diff --git a/AC701N.cbp b/AC701N.cbp
new file mode 100644
index 0000000..f2b466b
--- /dev/null
+++ b/AC701N.cbp
@@ -0,0 +1,1249 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/JBao_JL7016_SOC_SDK_README.md b/JBao_JL7016_SOC_SDK_README.md
new file mode 100644
index 0000000..f7d5594
--- /dev/null
+++ b/JBao_JL7016_SOC_SDK_README.md
@@ -0,0 +1,39 @@
+# AC701N Earphone SDK
+
+## 基本信息
+
+- 工程名称:AC701N Earphone SDK
+- 版本号:V1.0.1
+- 生成时间:2026-08-19 15:43:10
+- 适用芯片:AC7016C(BR28)
+
+## 目录说明
+
+```
+JBao_JL7016_SOC_SDK_V1.0.1/
+├── apps/
+│ ├── common/ # SDK 公共模块
+│ ├── earphone/ # 耳机应用
+│ ├── usr_jb_proto/ # 应用协议层
+│ ├── usr_periph/ # 板级外设(RTC 等,源码开放)
+│ └── usr_le_code/ # BLE 协议库(库文件 + 公开头文件)
+├── cpu/ # 芯片相关代码与工具
+├── include_lib/ # SDK 头文件
+├── tools/ # 工程工具
+├── Makefile
+├── AC701N.cbp
+└── JBao_JL7016_SOC_SDK_README.md
+```
+
+### 封装模块公开接口
+
+**apps/usr_le_code**
+
+- 静态库:`apps/usr_le_code/lib/`
+- 公开头文件:
+ - `apps/usr_le_code/usr_le_api.h`
+ - `apps/usr_le_code/usr_le_product.h`
+
+---
+
+*本文件由 tools/package_release.py 自动生成。*
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..c4761fe
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,866 @@
+
+# make 编译并下载
+# make VERBOSE=1 显示编译详细过程
+# make clean 清除编译临时文件
+#
+# 注意: Linux 下编译方式:
+# 1. 从 http://pkgman.jieliapp.com/doc/all 处找到下载链接
+# 2. 下载后,解压到 /opt/jieli 目录下,保证
+# /opt/jieli/common/bin/clang 存在(注意目录层次)
+# 3. 确认 ulimit -n 的结果足够大(建议大于8096),否则链接可能会因为打开文件太多而失败
+# 可以通过 ulimit -n 8096 来设置一个较大的值
+#
+
+# 工具路径设置
+ifeq ($(OS), Windows_NT)
+# Windows 下工具链位置
+TOOL_DIR := C:/JL/pi32/bin
+CC := clang.exe
+CXX := clang.exe
+LD := pi32v2-lto-wrapper.exe
+AR := llvm-ar.exe
+MKDIR := mkdir_win -p
+RM := rm -rf
+
+SYS_LIB_DIR := C:/JL/pi32/pi32v2-lib/r3-large
+SYS_INC_DIR := C:/JL/pi32/pi32v2-include
+EXT_CFLAGS := # Windows 下不需要 -D__SHELL__
+export PATH:=$(TOOL_DIR);$(PATH)
+
+## 后处理脚本
+FIXBAT := tools\utils\fixbat.exe # 用于处理 utf8->gbk 编码问题
+POST_SCRIPT := cpu/br28/tools/download.bat
+RUN_POST_SCRIPT := cpu\br28\tools\download.bat
+else
+# Linux 下工具链位置
+TOOL_DIR := /opt/jieli/pi32v2/bin
+CC := clang
+CXX := clang
+LD := lto-wrapper
+AR := lto-ar
+MKDIR := mkdir -p
+RM := rm -rf
+export OBJDUMP := $(TOOL_DIR)/objdump
+export OBJCOPY := $(TOOL_DIR)/objcopy
+export OBJSIZEDUMP := $(TOOL_DIR)/objsizedump
+
+SYS_LIB_DIR := $(TOOL_DIR)/../lib/r3-large
+SYS_INC_DIR := $(TOOL_DIR)/../include
+EXT_CFLAGS := -D__SHELL__ # Linux 下需要这个保证正确处理 download.c
+export PATH:=$(TOOL_DIR):$(PATH)
+
+## 后处理脚本
+FIXBAT := touch # Linux下不需要处理 bat 编码问题
+POST_SCRIPT := cpu/br28/tools/download.sh
+RUN_POST_SCRIPT := bash $(POST_SCRIPT)
+endif
+
+CC := $(TOOL_DIR)/$(CC)
+CXX := $(TOOL_DIR)/$(CXX)
+LD := $(TOOL_DIR)/$(LD)
+AR := $(TOOL_DIR)/$(AR)
+# 输出文件设置
+OUT_ELF := cpu/br28/tools/sdk.elf
+OBJ_FILE := $(OUT_ELF).objs.txt
+# 编译路径设置
+BUILD_DIR := objs
+
+# 编译参数设置
+CFLAGS := \
+ -target pi32v2 \
+ -mcpu=r3 \
+ -integrated-as \
+ -flto \
+ -Wuninitialized \
+ -Wno-invalid-noreturn \
+ -fno-common \
+ -integrated-as \
+ -Oz \
+ -g \
+ -flto \
+ -fallow-pointer-null \
+ -fprefer-gnu-section \
+ -Wno-shift-negative-value \
+ -Wundef \
+ -Wframe-larger-than=256 \
+ -Wincompatible-pointer-types \
+ -Wreturn-type \
+ -Wimplicit-function-declaration \
+ -mllvm -pi32v2-large-program=true \
+ -fms-extensions \
+ -fdiscrete-bitfield-abi \
+ -w \
+
+
+# C++额外的编译参数
+CXXFLAGS :=
+
+
+# 宏定义
+DEFINES := \
+ -DSUPPORT_MS_EXTENSIONS \
+ -DCONFIG_RELEASE_ENABLE \
+ -DCONFIG_CPU_BR28 \
+ -DCONFIG_USB_SUPPORT_MRX_TX \
+ -DCONFIG_PRINT_IN_MASK \
+ -DCONFIG_NEW_BREDR_ENABLE \
+ -DCONFIG_NEW_MODEM_ENABLE \
+ -DCONFIG_NEW_TWS_FORWARD_ENABLE \
+ -DCONFIG_UCOS_ENABLE \
+ -DCONFIG_EQ_SUPPORT_ASYNC \
+ -DEQ_CORE_V1 \
+ -DCONFIG_AAC_CODEC_FFT_USE_MUTEX \
+ -DCONFIG_DNS_ENABLE \
+ -DCONFIG_DMS_MALLOC \
+ -DCONFIG_MMU_ENABLE \
+ -DCONFIG_SBC_CODEC_HW \
+ -DCONFIG_MSBC_CODEC_HW \
+ -DCONFIG_AEC_M=128 \
+ -DCONFIG_SUPPORT_WIFI_DETECT \
+ -DCONFIG_AUDIO_ONCHIP \
+ -DCONFIG_MEDIA_NEW_ENABLE \
+ -DCONFIG_SUPPORT_EX_TWS_ADJUST \
+ -D__GCC_PI32V2__ \
+ -DCONFIG_MAC_ADDR_GET_USED_SFC \
+ -DTCFG_APP_BT_EN=1 \
+ -DEVENT_HANDLER_NUM_CONFIG=2 \
+ -DEVENT_TOUCH_ENABLE_CONFIG=0 \
+ -DEVENT_POOL_SIZE_CONFIG=256 \
+ -DCONFIG_EVENT_KEY_MAP_ENABLE=0 \
+ -DTIMER_POOL_NUM_CONFIG=15 \
+ -DAPP_ASYNC_POOL_NUM_CONFIG=0 \
+ -DUSE_SDFILE_NEW=1 \
+ -DSDFILE_STORAGE=0 \
+ -DVFS_FILE_POOL_NUM_CONFIG=1 \
+ -DFS_VERSION=0x020001 \
+ -DFATFS_VERSION=0x020101 \
+ -DSDFILE_VERSION=0x020000 \
+ -DVFS_ENABLE=1 \
+ -DVM_MAX_PAGE_ALIGN_SIZE_CONFIG=16*1024 \
+ -DVM_MAX_SECTOR_ALIGN_SIZE_CONFIG=16*1024 \
+ -DVM_ITEM_MAX_NUM=256 \
+ -DCONFIG_TWS_ENABLE \
+ -DCONFIG_EARPHONE_CASE_ENABLE \
+ -DCONFIG_OS_AFFINITY_ENABLE \
+ -DCONFIG_NEW_CFG_TOOL_ENABLE \
+ -DCONFIG_LITE_AEC_ENABLE=0 \
+ -DAUDIO_REC_LITE \
+ -DAUDIO_DEC_LITE \
+ -DAUDIO_REC_POOL_NUM=1 \
+ -DAUDIO_DEC_POOL_NUM=3 \
+ -DCONFIG_BTCTRLER_TASK_DEL_ENABLE \
+ -DCONFIG_LINK_DISTURB_SCAN_ENABLE=0 \
+ -DCONFIG_UPDATA_ENABLE \
+ -DCONFIG_OTA_UPDATA_ENABLE \
+ -DCONFIG_ITEM_FORMAT_VM \
+
+
+DEFINES += $(EXT_CFLAGS) # 额外的一些定义
+
+# 头文件搜索路径
+INCLUDES := \
+ -Iinclude_lib \
+ -Iinclude_lib/driver \
+ -Iinclude_lib/driver/device \
+ -Iinclude_lib/driver/cpu/br28 \
+ -Iinclude_lib/system \
+ -Iinclude_lib/system/generic \
+ -Iinclude_lib/system/device \
+ -Iinclude_lib/system/fs \
+ -Iinclude_lib/system/ui \
+ -Iinclude_lib/btctrler \
+ -Iinclude_lib/btctrler/port/br28 \
+ -Iinclude_lib/update \
+ -Iinclude_lib/agreement \
+ -Iinclude_lib/btstack/third_party/common \
+ -Iinclude_lib/btstack/third_party/rcsp \
+ -Iinclude_lib/media/media_new \
+ -Iinclude_lib/media/media_new/media \
+ -Iinclude_lib/media/media_new/media/cpu/br28 \
+ -Iinclude_lib/media/media_new/media/cpu/br28/asm \
+ -Iapps/common \
+ -Iapps/earphone/include \
+ -Iapps/earphone/include/wireless_mic \
+ -Iapps/common/icsd/anc \
+ -Iapps/common/icsd/adt \
+ -Iapps/common/power_manage \
+ -Iapps/common/device \
+ -Iapps/common/device/ntc \
+ -Iapps/common/device/imu_sensor \
+ -Iapps/common/audio \
+ -Iapps/common/music \
+ -Iapps/common/include \
+ -Iapps/common/config/include \
+ -Iapps/common/dev_manager \
+ -Iapps/common/third_party_profile/common \
+ -Iapps/common/third_party_profile/interface \
+ -Iapps/common/third_party_profile/jieli \
+ -Iapps/common/third_party_profile/jieli/trans_data_demo \
+ -Iapps/common/third_party_profile/jieli/online_db \
+ -Iapps/common/third_party_profile/jieli/JL_rcsp \
+ -Iapps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting \
+ -Iapps/common/third_party_profile/jieli/JL_rcsp/bt_trans_data \
+ -Iapps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol \
+ -Iapps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata \
+ -Iapps/earphone/board/br28 \
+ -Icpu/br28 \
+ -Icpu/br28/audio_dec \
+ -Icpu/br28/spatial_effect \
+ -Iapps/common/third_party_profile/Tecent_LL/include \
+ -Iapps/common/third_party_profile/Tecent_LL/tecent_ll_demo \
+ -Iapps/common/cJSON \
+ -Iinclude_lib/media \
+ -Iinclude_lib/btstack \
+ -Iinclude_lib/driver/cpu/br28/asm/power \
+ -Iapps/common/third_party_profile/tuya_protocol \
+ -Iapps/common/third_party_profile/tuya_protocol/app/demo \
+ -Iapps/common/third_party_profile/tuya_protocol/app/product_test \
+ -Iapps/common/third_party_profile/tuya_protocol/app/uart_common \
+ -Iapps/common/third_party_profile/tuya_protocol/extern_components/mbedtls \
+ -Iapps/common/third_party_profile/tuya_protocol/port \
+ -Iapps/common/third_party_profile/tuya_protocol/sdk/include \
+ -Iapps/common/third_party_profile/tuya_protocol/sdk/lib \
+ -Iapps/earphone/tuya \
+ -Iapps/common/device/usb \
+ -Iapps/common/device/usb/device \
+ -Iapps/common/device/usb/host \
+ -Iapps/earphone/wireless_mic/bt \
+ -Iapps/earphone/wireless_mic/idev \
+ -Iapps/earphone/wireless_mic/idev/idev_bt \
+ -Iapps/earphone/wireless_mic/idev/idev_bt/include \
+ -Iapps/earphone/wireless_mic/idev/idev_mic \
+ -Iapps/earphone/wireless_mic/odev \
+ -Iapps/earphone/wireless_mic/odev/odev_bt \
+ -Iapps/earphone/wireless_mic/odev/odev_bt/odev_edr \
+ -Iapps/earphone/wireless_mic/odev/odev_bt/odev_ble \
+ -Iapps/earphone/wireless_mic/odev/odev_bt/include \
+ -Iapps/earphone/wireless_mic/odev/odev_dac \
+ -Iapps/earphone/wireless_mic/process \
+ -Iapps/earphone/wireless_mic/audio \
+ -Iapps/earphone/wireless_mic/audio/wireless \
+ -Iapps/common/ezxml \
+ -Icpu/br28/audio_dec/audio_dec_file.h \
+ -Iinclude_lib/system/math/cpu/br28 \
+ -Iinclude_lib/media/aispeech/asr/include \
+ -Iinclude_lib/media/aispeech/enc/include \
+ -Icpu/br28/audio_hearing \
+ -Iinclude_lib/media/cvp \
+ -Iapps/usr_le_code \
+ -Iapps/usr_le_code/thirdpart \
+ -Iapps/usr_le_code/thirdpart/mjson \
+ -Iapps/usr_jb_proto/Protocol \
+ -Iapps/usr_jb_proto/Utils \
+ -Iapps/usr_periph \
+ -I$(SYS_INC_DIR) \
+
+
+# 需要编译的 .c 文件
+c_SRC_FILES := \
+ apps/common/audio/amplitude_statistic.c \
+ apps/common/audio/audio_dvol.c \
+ apps/common/audio/audio_export_demo.c \
+ apps/common/audio/audio_noise_gate.c \
+ apps/common/audio/audio_ns.c \
+ apps/common/audio/audio_plc.c \
+ apps/common/audio/audio_utils.c \
+ apps/common/audio/decode/audio_key_tone.c \
+ apps/common/audio/decode/decode.c \
+ apps/common/audio/demo/audio_demo.c \
+ apps/common/audio/online_debug/aud_data_export.c \
+ apps/common/audio/online_debug/aud_mic_dut.c \
+ apps/common/audio/online_debug/aud_spatial_effect_dut.c \
+ apps/common/audio/online_debug/audio_online_debug.c \
+ apps/common/audio/sine_make.c \
+ apps/common/audio/uartPcmSender.c \
+ apps/common/audio/wm8978/iic.c \
+ apps/common/audio/wm8978/wm8978.c \
+ apps/common/bt_common/bt_test_api.c \
+ apps/common/cJSON/cJSON.c \
+ apps/common/config/app_config.c \
+ apps/common/config/bt_profile_config.c \
+ apps/common/config/ci_transport_uart.c \
+ apps/common/config/new_cfg_tool.c \
+ apps/common/debug/debug.c \
+ apps/common/debug/debug_lite.c \
+ apps/common/dev_manager/dev_manager.c \
+ apps/common/dev_manager/dev_reg.c \
+ apps/common/dev_manager/dev_update.c \
+ apps/common/device/gSensor/SC7A20.c \
+ apps/common/device/gSensor/STK8321.c \
+ apps/common/device/gSensor/da230.c \
+ apps/common/device/gSensor/gSensor_manage.c \
+ apps/common/device/gSensor/mpu6050.c \
+ apps/common/device/gx8002_npu/gx8002_enc/gx8002_enc.c \
+ apps/common/device/gx8002_npu/gx8002_npu.c \
+ apps/common/device/gx8002_npu/gx8002_npu_event_deal.c \
+ apps/common/device/gx8002_npu/gx8002_upgrade/app_upgrade/gx_uart_upgrade_app.c \
+ apps/common/device/gx8002_npu/gx8002_upgrade/app_upgrade/gx_uart_upgrade_tws.c \
+ apps/common/device/gx8002_npu/gx8002_upgrade/gx_uart_upgrade.c \
+ apps/common/device/gx8002_npu/gx8002_upgrade/gx_uart_upgrade_porting.c \
+ apps/common/device/gx8002_npu/gx8002_upgrade/sdfile_upgrade/gx_uart_upgrade_sdfile.c \
+ apps/common/device/gx8002_npu/gx8002_upgrade/spp_upgrade/gx_fifo.c \
+ apps/common/device/gx8002_npu/gx8002_upgrade/spp_upgrade/gx_uart_upgrade_spp.c \
+ apps/common/device/imu_sensor/icm_42670p/icm_42670p.c \
+ apps/common/device/imu_sensor/icm_42670p/inv_imu_apex.c \
+ apps/common/device/imu_sensor/icm_42670p/inv_imu_driver.c \
+ apps/common/device/imu_sensor/icm_42670p/inv_imu_transport.c \
+ apps/common/device/imu_sensor/imuSensor_manage.c \
+ apps/common/device/imu_sensor/lsm6dsl/lsm6dsl.c \
+ apps/common/device/imu_sensor/mpu6887/mpu6887p.c \
+ apps/common/device/imu_sensor/mpu9250/mpu9250.c \
+ apps/common/device/imu_sensor/qmi8658/qmi8658c.c \
+ apps/common/device/imu_sensor/sh3001/sh3001.c \
+ apps/common/device/in_ear_detect/in_ear_detect.c \
+ apps/common/device/in_ear_detect/in_ear_manage.c \
+ apps/common/device/ir_sensor/ir_manage.c \
+ apps/common/device/ir_sensor/jsa1221.c \
+ apps/common/device/key/adkey.c \
+ apps/common/device/key/adkey_rtcvdd.c \
+ apps/common/device/key/ctmu_touch_key.c \
+ apps/common/device/key/iokey.c \
+ apps/common/device/key/irkey.c \
+ apps/common/device/key/key_driver.c \
+ apps/common/device/key/touch_key.c \
+ apps/common/device/key/uart_key.c \
+ apps/common/device/norflash/norflash_sfc.c \
+ apps/common/device/ntc/ntc_det.c \
+ apps/common/device/usb/device/cdc.c \
+ apps/common/device/usb/device/descriptor.c \
+ apps/common/device/usb/device/hid.c \
+ apps/common/device/usb/device/msd.c \
+ apps/common/device/usb/device/msd_upgrade.c \
+ apps/common/device/usb/device/task_pc.c \
+ apps/common/device/usb/device/uac1.c \
+ apps/common/device/usb/device/uac_stream.c \
+ apps/common/device/usb/device/usb_device.c \
+ apps/common/device/usb/device/user_setup.c \
+ apps/common/device/usb/host/adb.c \
+ apps/common/device/usb/host/aoa.c \
+ apps/common/device/usb/host/audio.c \
+ apps/common/device/usb/host/audio_demo.c \
+ apps/common/device/usb/host/hid.c \
+ apps/common/device/usb/host/usb_bulk_transfer.c \
+ apps/common/device/usb/host/usb_ctrl_transfer.c \
+ apps/common/device/usb/host/usb_host.c \
+ apps/common/device/usb/host/usb_storage.c \
+ apps/common/device/usb/usb_config.c \
+ apps/common/device/usb/usb_host_config.c \
+ apps/common/ezxml/ezxml.c \
+ apps/common/ezxml/ezxml_example.c \
+ apps/common/fat_nor/cfg_private.c \
+ apps/common/fat_nor/virfat_flash.c \
+ apps/common/file_operate/file_bs_deal.c \
+ apps/common/file_operate/file_manager.c \
+ apps/common/icsd/adt/icsd_adt.c \
+ apps/common/icsd/adt/icsd_adt_app.c \
+ apps/common/icsd/anc/icsd_anc_app.c \
+ apps/common/icsd/anc/icsd_anc_board.c \
+ apps/common/icsd/anc/icsd_anc_data.c \
+ apps/common/jl_kws/jl_kws_algo.c \
+ apps/common/jl_kws/jl_kws_audio.c \
+ apps/common/jl_kws/jl_kws_event.c \
+ apps/common/jl_kws/jl_kws_main.c \
+ apps/common/music/breakpoint.c \
+ apps/common/music/music_decrypt.c \
+ apps/common/music/music_id3.c \
+ apps/common/music/music_player.c \
+ apps/common/temp_trim/dtemp_pll_trim.c \
+ apps/common/test/fs_test.c \
+ apps/common/test/os_test.c \
+ apps/common/third_party_profile/Tecent_LL/tecent_ll_demo/ll_demo.c \
+ apps/common/third_party_profile/Tecent_LL/tecent_ll_demo/ll_task.c \
+ apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_import.c \
+ apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_data.c \
+ apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_device.c \
+ apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_event.c \
+ apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_ota.c \
+ apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_service.c \
+ apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_template.c \
+ apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_base64.c \
+ apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_crc.c \
+ apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_hmac.c \
+ apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_log.c \
+ apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_md5.c \
+ apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_sha1.c \
+ apps/common/third_party_profile/common/3th_profile_api.c \
+ apps/common/third_party_profile/common/custom_cfg.c \
+ apps/common/third_party_profile/common/mic_rec.c \
+ apps/common/third_party_profile/interface/app_protocol_api.c \
+ apps/common/third_party_profile/interface/app_protocol_common.c \
+ apps/common/third_party_profile/interface/app_protocol_dma.c \
+ apps/common/third_party_profile/interface/app_protocol_gfps.c \
+ apps/common/third_party_profile/interface/app_protocol_gma.c \
+ apps/common/third_party_profile/interface/app_protocol_mma.c \
+ apps/common/third_party_profile/interface/app_protocol_ota.c \
+ apps/common/third_party_profile/interface/app_protocol_tme.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_adaptive_noise_reduction.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_anc_voice.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_anc_voice_key.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_bt_name_setting.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_eq_setting.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_hearing_aid_setting.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_high_low_vol_setting.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_key_setting.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_led_setting.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_mic_setting.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_music_info_setting.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_time_stamp_setting.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_work_setting.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_bluetooth.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_customer_user.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_opt.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_tws_sync.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/bt_trans_data/le_rcsp_adv_module.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/bt_trans_data/rcsp_adv_spp_user.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_adv_user_update.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_ch_loader_download.c \
+ apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_user_update.c \
+ apps/common/third_party_profile/jieli/le_hogp.c \
+ apps/common/third_party_profile/jieli/online_db/online_db_deal.c \
+ apps/common/third_party_profile/jieli/online_db/spp_online_db.c \
+ apps/common/third_party_profile/jieli/trans_data_demo/le_trans_data.c \
+ apps/common/third_party_profile/jieli/trans_data_demo/spp_trans_data.c \
+ apps/common/third_party_profile/jieli/wireless_mic/le_wireless_mic_client.c \
+ apps/common/third_party_profile/jieli/wireless_mic/le_wireless_mic_server.c \
+ apps/common/third_party_profile/tuya_protocol/app/demo/tuya_ble_app_demo.c \
+ apps/common/third_party_profile/tuya_protocol/app/demo/tuya_ota.c \
+ apps/common/third_party_profile/tuya_protocol/app/product_test/tuya_ble_app_production_test.c \
+ apps/common/third_party_profile/tuya_protocol/app/uart_common/tuya_ble_app_uart_common_handler.c \
+ apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/aes.c \
+ apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/ccm.c \
+ apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/hmac.c \
+ apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/md5.c \
+ apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/sha1.c \
+ apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/sha256.c \
+ apps/common/third_party_profile/tuya_protocol/port/tuya_ble_port.c \
+ apps/common/third_party_profile/tuya_protocol/port/tuya_ble_port_JL.c \
+ apps/common/third_party_profile/tuya_protocol/port/tuya_ble_port_peripheral.c \
+ apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_api.c \
+ apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_bulk_data.c \
+ apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_data_handler.c \
+ apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_event.c \
+ apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_event_handler.c \
+ apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_event_handler_weak.c \
+ apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_feature_weather.c \
+ apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_gatt_send_queue.c \
+ apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_heap.c \
+ apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_main.c \
+ apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_mem.c \
+ apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_mutli_tsf_protocol.c \
+ apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_queue.c \
+ apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_storage.c \
+ apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_unix_time.c \
+ apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_utils.c \
+ apps/common/ui/lcd_simple/lcd_simple_api.c \
+ apps/common/ui/lcd_simple/ui.c \
+ apps/common/ui/lcd_simple/ui_mainmenu.c \
+ apps/common/update/testbox_update.c \
+ apps/common/update/update.c \
+ apps/common/update/update_tws.c \
+ apps/common/update/update_tws_new.c \
+ apps/earphone/aec/br28/audio_aec.c \
+ apps/earphone/aec/br28/audio_aec_demo.c \
+ apps/earphone/aec/br28/audio_aec_dms.c \
+ apps/earphone/aec/br28/audio_aec_online.c \
+ apps/earphone/aec/br28/audio_cvp_3mic.c \
+ apps/earphone/aec/br28/audio_cvp_ais_3mic.c \
+ apps/earphone/app_ancbox.c \
+ apps/earphone/app_anctool.c \
+ apps/earphone/app_main.c \
+ apps/earphone/app_protocol_deal.c \
+ apps/earphone/app_task_switch.c \
+ apps/earphone/app_testbox.c \
+ apps/earphone/audio_enc_mpt_cvp_ctr.c \
+ apps/earphone/audio_enc_mpt_self.c \
+ apps/earphone/ble_adv.c \
+ apps/earphone/board/br28/board_jl7016g_hybrid.c \
+ apps/earphone/board/br28/board_jl7018f_demo.c \
+ apps/earphone/board/br28/board_jl701n_anc.c \
+ apps/earphone/board/br28/board_jl701n_btemitter.c \
+ apps/earphone/board/br28/board_jl701n_demo.c \
+ apps/earphone/bt_auto_test.c \
+ apps/earphone/bt_background.c \
+ apps/earphone/bt_ble.c \
+ apps/earphone/bt_ble_hid.c \
+ apps/earphone/bt_emitter.c \
+ apps/earphone/bt_tws.c \
+ apps/earphone/default_event_handler.c \
+ apps/earphone/dual_update_demo.c \
+ apps/earphone/earphone.c \
+ apps/earphone/eartch_event_deal.c \
+ apps/earphone/font/fontinit.c \
+ apps/earphone/idle.c \
+ apps/earphone/key_event_deal.c \
+ apps/earphone/kws_voice_event_deal.c \
+ apps/earphone/linein/linein.c \
+ apps/earphone/ll_sync_demo/ll_sync_demo.c \
+ apps/earphone/log_config/app_config.c \
+ apps/earphone/log_config/lib_btctrler_config.c \
+ apps/earphone/log_config/lib_btstack_config.c \
+ apps/earphone/log_config/lib_driver_config.c \
+ apps/earphone/log_config/lib_media_config.c \
+ apps/earphone/log_config/lib_system_config.c \
+ apps/earphone/log_config/lib_update_config.c \
+ apps/earphone/music/sd_music.c \
+ apps/earphone/pbg_demo.c \
+ apps/earphone/pc/pc.c \
+ apps/earphone/power_manage/app_charge.c \
+ apps/earphone/power_manage/app_chargestore.c \
+ apps/earphone/power_manage/app_power_manage.c \
+ apps/earphone/power_manage/app_umidigi_chargestore.c \
+ apps/earphone/rcsp/jl_phone_app.c \
+ apps/earphone/rcsp/rcsp_adv.c \
+ apps/earphone/tone_table.c \
+ apps/earphone/trans_data_demo/trans_data_demo.c \
+ apps/earphone/tuya/tuya_app.c \
+ apps/earphone/tuya/tuya_demo.c \
+ apps/earphone/ui/lcd_simple/my_demo.c \
+ apps/earphone/ui_manage.c \
+ apps/earphone/user_cfg.c \
+ apps/earphone/version.c \
+ apps/earphone/vol_sync.c \
+ apps/earphone/wireless_mic/app_main_wireless_mic.c \
+ apps/earphone/wireless_mic/audio/adapter_adc.c \
+ apps/earphone/wireless_mic/audio/adapter_media.c \
+ apps/earphone/wireless_mic/audio/wireless/adapter_wireless_dec.c \
+ apps/earphone/wireless_mic/audio/wireless/adapter_wireless_enc.c \
+ apps/earphone/wireless_mic/bt/bt_edr_fun.c \
+ apps/earphone/wireless_mic/bt/bt_status_event.c \
+ apps/earphone/wireless_mic/idev/adapter_idev.c \
+ apps/earphone/wireless_mic/idev/idev_bt/adapter_idev_bt.c \
+ apps/earphone/wireless_mic/idev/idev_bt/idev_ble/adapter_idev_ble.c \
+ apps/earphone/wireless_mic/idev/idev_mic/adapter_idev_mic.c \
+ apps/earphone/wireless_mic/odev/adapter_odev.c \
+ apps/earphone/wireless_mic/odev/odev_bt/adapter_odev_bt.c \
+ apps/earphone/wireless_mic/odev/odev_bt/odev_ble/adapter_odev_ble.c \
+ apps/earphone/wireless_mic/odev/odev_bt/odev_ble/odev_ble_wireless.c \
+ apps/earphone/wireless_mic/odev/odev_bt/odev_edr/adapter_odev_edr.c \
+ apps/earphone/wireless_mic/odev/odev_dac/adapter_odev_dac.c \
+ apps/earphone/wireless_mic/process/adapter_process.c \
+ cpu/br28/adc_api.c \
+ cpu/br28/aec_tool.c \
+ cpu/br28/app_audio.c \
+ cpu/br28/audio_anc.c \
+ cpu/br28/audio_anc_fade_ctr.c \
+ cpu/br28/audio_anc_mult_scene.c \
+ cpu/br28/audio_capture.c \
+ cpu/br28/audio_codec_clock.c \
+ cpu/br28/audio_common/audio_mic_codec.c \
+ cpu/br28/audio_cvp_dut.c \
+ cpu/br28/audio_cvp_sync.c \
+ cpu/br28/audio_dec.c \
+ cpu/br28/audio_dec/audio_dec_file.c \
+ cpu/br28/audio_dec/audio_dec_iis.c \
+ cpu/br28/audio_dec/audio_dec_pc.c \
+ cpu/br28/audio_dec/audio_dec_pcm.c \
+ cpu/br28/audio_dec/audio_usb_mic.c \
+ cpu/br28/audio_dec_eff.c \
+ cpu/br28/audio_demo/audio_adc_demo.c \
+ cpu/br28/audio_demo/audio_dac_demo.c \
+ cpu/br28/audio_demo/audio_fft_demo.c \
+ cpu/br28/audio_demo/audio_matrix_demo.c \
+ cpu/br28/audio_demo/audio_wind_detect_demo.c \
+ cpu/br28/audio_effect_develop.c \
+ cpu/br28/audio_enc.c \
+ cpu/br28/audio_general.c \
+ cpu/br28/audio_hearing/audio_hearing_aid.c \
+ cpu/br28/audio_hearing/audio_hearing_aid_lp.c \
+ cpu/br28/audio_hearing/audio_sidetone.c \
+ cpu/br28/audio_link.c \
+ cpu/br28/audio_sync.c \
+ cpu/br28/charge.c \
+ cpu/br28/chargestore.c \
+ cpu/br28/clock_manager.c \
+ cpu/br28/eq_config.c \
+ cpu/br28/hw_fft.c \
+ cpu/br28/icsd_anc_user.c \
+ cpu/br28/iic_hw.c \
+ cpu/br28/iic_soft.c \
+ cpu/br28/irflt.c \
+ cpu/br28/lp_touch_key.c \
+ cpu/br28/lp_touch_key_alog.c \
+ cpu/br28/lp_touch_key_tool.c \
+ cpu/br28/lua_port_api.c \
+ cpu/br28/mcpwm.c \
+ cpu/br28/mic_dut_process.c \
+ cpu/br28/overlay_code.c \
+ cpu/br28/pdm_link.c \
+ cpu/br28/plcnt.c \
+ cpu/br28/power/power_app.c \
+ cpu/br28/power/power_check.c \
+ cpu/br28/power/power_port.c \
+ cpu/br28/power/power_trim.c \
+ cpu/br28/private_iis.c \
+ cpu/br28/pwm_led.c \
+ cpu/br28/rdec.c \
+ cpu/br28/setup.c \
+ cpu/br28/smart_voice/aispeech_asr.c \
+ cpu/br28/smart_voice/jl_kws_platform.c \
+ cpu/br28/smart_voice/kws_event.c \
+ cpu/br28/smart_voice/nn_vad.c \
+ cpu/br28/smart_voice/smart_voice_config.c \
+ cpu/br28/smart_voice/smart_voice_core.c \
+ cpu/br28/smart_voice/user_asr.c \
+ cpu/br28/smart_voice/vad_clock_trim.c \
+ cpu/br28/smart_voice/vad_mic.c \
+ cpu/br28/smart_voice/voice_mic_data.c \
+ cpu/br28/sound_device.c \
+ cpu/br28/spatial_effect/spatial_effect.c \
+ cpu/br28/spatial_effect/spatial_effect_imu.c \
+ cpu/br28/spatial_effect/spatial_effect_test.c \
+ cpu/br28/spatial_effect/spatial_effect_tws.c \
+ cpu/br28/spatial_effect/spatial_imu_trim.c \
+ cpu/br28/spi.c \
+ cpu/br28/tone_player.c \
+ cpu/br28/tws_audio.c \
+ cpu/br28/uart_dev.c \
+ cpu/br28/umidigi_chargestore.c \
+ apps/usr_jb_proto/Protocol/jb_product.c \
+ apps/usr_jb_proto/Protocol/jb_protocol.c \
+ apps/usr_jb_proto/Utils/jb_common.c \
+ apps/usr_jb_proto/Utils/jb_ringbuffer.c \
+ apps/usr_jb_proto/usr_jb_main.c \
+ apps/usr_periph/usr_rtc.c \
+
+
+# usr_le_code 预编译静态库(Release 不附带协议源码,禁止本地重建)
+USR_LE_LIB := apps/usr_le_code/lib/libusr_le_code.a
+
+
+
+# 需要编译的 .S 文件
+S_SRC_FILES := \
+ apps/earphone/sdk_version.z.S \
+
+
+# 需要编译的 .s 文件
+s_SRC_FILES :=
+
+
+# 需要编译的 .cpp 文件
+cpp_SRC_FILES :=
+
+
+# 需要编译的 .cc 文件
+cc_SRC_FILES :=
+
+
+# 需要编译的 .cxx 文件
+cxx_SRC_FILES :=
+
+
+# 链接参数
+LFLAGS := \
+ --plugin-opt=-pi32v2-always-use-itblock=false \
+ --plugin-opt=-enable-ipra=true \
+ --plugin-opt=-pi32v2-merge-max-offset=4096 \
+ --plugin-opt=-pi32v2-enable-simd=true \
+ --plugin-opt=mcpu=r3 \
+ --plugin-opt=-global-merge-on-const \
+ --plugin-opt=-inline-threshold=5 \
+ --plugin-opt=-inline-max-allocated-size=32 \
+ --plugin-opt=-inline-normal-into-special-section=true \
+ --plugin-opt=-dont-used-symbol-list=malloc,free,sprintf,printf,puts,putchar \
+ --plugin-opt=save-temps \
+ --plugin-opt=-pi32v2-enable-rep-memop \
+ --plugin-opt=-warn-stack-size=256 \
+ --sort-common \
+ --plugin-opt=-used-symbol-file=cpu/br28/sdk_used_list.used \
+ --plugin-opt=-pi32v2-large-program=true \
+ --gc-sections \
+ --start-group \
+ cpu/br28/liba/cpu.a \
+ cpu/br28/liba/system.a \
+ cpu/br28/liba/btstack.a \
+ cpu/br28/liba/rcsp_stack.a \
+ cpu/br28/liba/tme_stack.a \
+ cpu/br28/liba/google_fps.a \
+ cpu/br28/liba/btctrler.a \
+ cpu/br28/liba/aec.a \
+ cpu/br28/liba/lib_icsd_anc.a \
+ cpu/br28/liba/media.a \
+ cpu/br28/liba/libepmotion.a \
+ cpu/br28/liba/libAptFilt_pi32v2_OnChip.a \
+ cpu/br28/liba/libEchoSuppress_pi32v2_OnChip.a \
+ cpu/br28/liba/libNoiseSuppress_pi32v2_OnChip.a \
+ cpu/br28/liba/libSplittingFilter_pi32v2_OnChip.a \
+ cpu/br28/liba/libDelayEstimate_pi32v2_OnChip.a \
+ cpu/br28/liba/libDualMicSystem_pi32v2_OnChip.a \
+ cpu/br28/liba/libDualMicSystem_flexible_pi32v2_OnChip.a \
+ cpu/br28/liba/libAdaptiveEchoSuppress_pi32v2_OnChip.a \
+ cpu/br28/liba/libOpcore_maskrom_pi32v2_OnChip.a \
+ cpu/br28/liba/lib_esco_repair.a \
+ cpu/br28/liba/noisegate.a \
+ cpu/br28/liba/sbc_eng_lib.a \
+ cpu/br28/liba/mp3_dec_lib.a \
+ cpu/br28/liba/mp3_decstream_lib.a \
+ cpu/br28/liba/mp3tsy_dec_lib.a \
+ cpu/br28/liba/wav_dec_lib.a \
+ cpu/br28/liba/flac_dec_lib.a \
+ cpu/br28/liba/m4a_dec_lib.a \
+ cpu/br28/liba/ape_dec_lib.a \
+ cpu/br28/liba/wma_dec_lib.a \
+ cpu/br28/liba/amr_dec_lib.a \
+ cpu/br28/liba/dts_dec_lib.a \
+ cpu/br28/liba/agreement.a \
+ cpu/br28/liba/media_app.a \
+ cpu/br28/liba/lc3_codec_lib.a \
+ cpu/br28/liba/opus_dec_lib.a \
+ cpu/br28/liba/speex_enc_lib.a \
+ cpu/br28/liba/ldac_dec_lib.a \
+ cpu/br28/liba/opus_enc_lib.a \
+ cpu/br28/liba/bt_hash_enc.a \
+ cpu/br28/liba/libjlsp.a \
+ cpu/br28/liba/libjlsp_kws.a \
+ cpu/br28/liba/lfaudio_plc_lib.a \
+ cpu/br28/liba/drc.a \
+ cpu/br28/liba/crossover_coff_old.a \
+ cpu/br28/liba/lib_point360_td.a \
+ cpu/br28/liba/lib_resample_cal.a \
+ cpu/br28/liba/lib_resample_fast_cal.a \
+ cpu/br28/liba/SpatialAudio.a \
+ cpu/br28/liba/SensorCalib.a \
+ cpu/br28/liba/lib_pitchshifter.a \
+ cpu/br28/liba/VirtualBass.a \
+ cpu/br28/liba/lib_sur_cal.a \
+ cpu/br28/liba/limiter_noiseGate.a \
+ cpu/br28/liba/howling.a \
+ cpu/br28/liba/lib_howlings_phf.a \
+ cpu/br28/liba/libllns.a \
+ cpu/br28/liba/libkwscommon.a \
+ apps/common/third_party_profile/tuya_protocol/sdk/lib/libtuya_lib.a \
+ apps/usr_le_code/lib/libusr_le_code.a \
+ cpu/br28/liba/lib_icsd_adt.a \
+ cpu/br28/liba/lib_diafx.a \
+ cpu/br28/liba/libFFT_pi32v2_OnChip.a \
+ cpu/br28/liba/wtg_dec_lib.a \
+ cpu/br28/liba/bfilterfun_lib.a \
+ cpu/br28/liba/aac_dec_lib.a \
+ cpu/br28/liba/crypto_toolbox_Osize.a \
+ cpu/br28/liba/lib_dns.a \
+ cpu/br28/liba/update.a \
+ cpu/br28/liba/compressor.a \
+ cpu/br28/liba/limiter.a \
+ --end-group \
+ -Tcpu/br28/sdk.ld \
+ -M=cpu/br28/tools/sdk.map \
+ --plugin-opt=mcpu=r3 \
+ --plugin-opt=-mattr=+fprev1 \
+
+
+LIBPATHS := \
+ -L$(SYS_LIB_DIR) \
+
+
+LIBS := \
+ $(SYS_LIB_DIR)/libm.a \
+ $(SYS_LIB_DIR)/libc.a \
+ $(SYS_LIB_DIR)/libm.a \
+ $(SYS_LIB_DIR)/libcompiler-rt.a \
+
+
+
+c_OBJS := $(c_SRC_FILES:%.c=%.c.o)
+S_OBJS := $(S_SRC_FILES:%.S=%.S.o)
+s_OBJS := $(s_SRC_FILES:%.s=%.s.o)
+cpp_OBJS := $(cpp_SRC_FILES:%.cpp=%.cpp.o)
+cxx_OBJS := $(cxx_SRC_FILES:%.cxx=%.cxx.o)
+cc_OBJS := $(cc_SRC_FILES:%.cc=%.cc.o)
+
+OBJS := $(c_OBJS) $(S_OBJS) $(s_OBJS) $(cpp_OBJS) $(cxx_OBJS) $(cc_OBJS)
+DEP_FILES := $(OBJS:%.o=%.d)
+
+
+OBJS := $(addprefix $(BUILD_DIR)/, $(OBJS))
+DEP_FILES := $(addprefix $(BUILD_DIR)/, $(DEP_FILES))
+
+
+VERBOSE ?= 0
+ifeq ($(VERBOSE), 1)
+QUITE :=
+else
+QUITE := @
+endif
+
+# 一些旧的 make 不支持 file 函数,需要 make 的时候指定 LINK_AT=0 make
+LINK_AT ?= 1
+
+# 表示下面的不是一个文件的名字,无论是否存在 all, clean, pre_build 这样的文件
+# 还是要执行命令
+# see: https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
+.PHONY: all clean pre_build
+
+# 不要使用 make 预设置的规则
+# see: https://www.gnu.org/software/make/manual/html_node/Suffix-Rules.html
+.SUFFIXES:
+
+all: pre_build $(USR_LE_LIB) $(OUT_ELF)
+ $(info +POST-BUILD)
+ $(QUITE) $(RUN_POST_SCRIPT) sdk
+
+
+pre_build:
+ $(info +PRE-BUILD)
+ $(QUITE) $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -D__LD__ -E -P cpu/br28/sdk_used_list.c -o cpu/br28/sdk_used_list.used
+ $(QUITE) $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -D__LD__ -E -P cpu/br28/sdk_ld.c -o cpu/br28/sdk.ld
+ $(QUITE) $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -D__LD__ -E -P cpu/br28/tools/download.c -o $(POST_SCRIPT)
+ $(QUITE) $(FIXBAT) $(POST_SCRIPT)
+ $(QUITE) $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -D__LD__ -E -P cpu/br28/tools/isd_config_rule.c -o cpu/br28/tools/isd_config.ini
+
+clean:
+ $(QUITE) $(RM) $(OUT_ELF)
+ $(QUITE) $(RM) $(BUILD_DIR)
+
+
+
+ifeq ($(LINK_AT), 1)
+$(OUT_ELF): $(OBJS) $(USR_LE_LIB)
+ $(info +LINK $@)
+ $(shell $(MKDIR) $(@D))
+ $(file >$(OBJ_FILE), $(OBJS))
+ $(QUITE) $(LD) -o $(OUT_ELF) @$(OBJ_FILE) $(LFLAGS) $(LIBPATHS) $(LIBS)
+else
+$(OUT_ELF): $(OBJS) $(USR_LE_LIB)
+ $(info +LINK $@)
+ $(shell $(MKDIR) $(@D))
+ $(QUITE) $(LD) -o $(OUT_ELF) $(OBJS) $(LFLAGS) $(LIBPATHS) $(LIBS)
+endif
+
+
+$(BUILD_DIR)/%.c.o : %.c
+ $(info +CC $<)
+ $(QUITE) $(MKDIR) $(@D)
+ $(QUITE) $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -MM -MT $@ $< -o $(@:.o=.d)
+ $(QUITE) $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -c $< -o $@
+
+$(BUILD_DIR)/%.S.o : %.S
+ $(info +AS $<)
+ $(QUITE) $(MKDIR) $(@D)
+ $(QUITE) $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -MM -MT $@ $< -o $(@:.o=.d)
+ $(QUITE) $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -c $< -o $@
+
+$(BUILD_DIR)/%.s.o : %.s
+ $(info +AS $<)
+ $(QUITE) $(MKDIR) $(@D)
+ $(QUITE) $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -MM -MT $@ $< -o $(@:.o=.d)
+ $(QUITE) $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -c $< -o $@
+
+$(BUILD_DIR)/%.cpp.o : %.cpp
+ $(info +CXX $<)
+ $(QUITE) $(MKDIR) $(@D)
+ $(QUITE) $(CXX) $(CXXFLAGS) $(CFLAGS) $(DEFINES) $(INCLUDES) -MM -MT $@ $< -o $(@:.o=.d)
+ $(QUITE) $(CXX) $(CXXFLAGS) $(CFLAGS) $(DEFINES) $(INCLUDES) -c $< -o $@
+
+$(BUILD_DIR)/%.cxx.o : %.cxx
+ $(info +CXX $<)
+ $(QUITE) $(MKDIR) $(@D)
+ $(QUITE) $(CXX) $(CXXFLAGS) $(CFLAGS) $(DEFINES) $(INCLUDES) -MM -MT $@ $< -o $(@:.o=.d)
+ $(QUITE) $(CXX) $(CXXFLAGS) $(CFLAGS) $(DEFINES) $(INCLUDES) -c $< -o $@
+
+$(BUILD_DIR)/%.cc.o : %.cc
+ $(info +CXX $<)
+ $(QUITE) $(MKDIR) $(@D)
+ $(QUITE) $(CXX) $(CXXFLAGS) $(CFLAGS) $(DEFINES) $(INCLUDES) -MM -MT $@ $< -o $(@:.o=.d)
+ $(QUITE) $(CXX) $(CXXFLAGS) $(CFLAGS) $(DEFINES) $(INCLUDES) -c $< -o $@
+
+-include $(DEP_FILES)
diff --git a/README.md b/README.md
index 5bfda93..ed953b1 100644
--- a/README.md
+++ b/README.md
@@ -1,64 +1,88 @@
-# soc-codegen-template
+# JL7016 SOC 开发框架
-见宝科技 **SOC 代码生成模板仓库**。见宝工具箱生成/分发 SOC 工程时,从此仓库按分支拉取对应芯片模板。
+基于杰理 **JL7016 / AC7016C(BR28)** 的耳机 SOC 工程模板。应用层含 `jb_protocol`,BLE 能力由 `apps/usr_le_code` 静态库提供。
-**远程地址:** https://git.jianbao-tech.com/pets-device/soc-codegen-template.git
+适用芯片:AC7016C(BR28)
+SDK 名称:AC701N Earphone SDK
---
-## 分支说明
-
-本仓库 **`main` 分支仅作索引**,不含具体芯片工程。
-
-每个 SOC 模板对应一个独立分支,命名规则:**`厂商-型号`**。
-
-| 分支 | 说明 |
-|------|------|
-| **`main`** | 本页:分支索引与使用说明 |
-| **`JieLi-JL7016`** | 杰理 JL7016 / AC7016C(BR28)· 耳机 SDK + jb_protocol |
-
-完整分支表见 [`docs/branch-index.md`](docs/branch-index.md)。
-
----
-
-## 快速使用
-
-```bash
-# 克隆并切换到 JL7016 模板
-git clone https://git.jianbao-tech.com/pets-device/soc-codegen-template.git
-cd soc-codegen-template
-git checkout JieLi-JL7016
-```
-
-切换后阅读该分支根目录 **`README.md`** 了解构建、OTA 配置与打包方式。
-
----
-
-## 仓库结构(SOC 分支通用)
+## 目录结构
```text
-/
-├── apps/ 应用(earphone / usr_jb_proto / usr_periph / usr_le_code)
-├── cpu/ 芯片平台代码与下载工具
-├── include_lib/ SDK 头文件
-├── tools/ 构建与打包脚本
-├── Makefile 一键编译入口
-└── *.cbp Code::Blocks 工程
+JieLi-JL7016/
+├── apps/
+│ ├── common/ # SDK 公共模块
+│ ├── earphone/ # 耳机应用
+│ ├── usr_jb_proto/ # 应用协议层(jb_protocol / jb_product)
+│ ├── usr_periph/ # 板级外设(RTC 等,源码开放)
+│ └── usr_le_code/ # BLE 协议库(静态库 + 公开头文件)
+├── cpu/ # 芯片平台代码与下载工具(br28)
+├── include_lib/ # SDK 头文件
+├── tools/ # 工程工具与打包脚本
+├── Makefile # 一键编译入口
+├── AC701N.cbp # Code::Blocks 工程
+└── JBao_JL7016_SOC_SDK_README.md
```
-> 各芯片目录细节以对应分支 README 为准。
+### 封装模块公开接口
+
+**apps/usr_le_code**
+
+- 静态库:`apps/usr_le_code/lib/libusr_le_code.a`
+- 公开头文件:
+ - `apps/usr_le_code/usr_le_api.h`
+ - `apps/usr_le_code/usr_le_product.h`
---
-## 维护者
+## 快速开始
-- 新增 SOC:新建 `厂商-型号` 分支,更新 `docs/branch-index.md` 与本 README 表格
-- 模板发版:在对应 SOC 分支打 tag,如 `JieLi-JL7016/v1.0.0`
+### 环境要求
+
+- 杰理 AC701N 工具链(Windows 默认 `C:/JL/pi32/bin`)
+- Code::Blocks(打开 `AC701N.cbp`)或命令行 `make`
+
+### 1) 命令行编译
+
+```bash
+make
+```
+
+显示详细编译过程:
+
+```bash
+make VERBOSE=1
+```
+
+清除编译临时文件:
+
+```bash
+make clean
+```
+
+### 2) 协议与产品对接
+
+| 目的 | 文件 |
+|------|------|
+| 产品/版本定义 | `apps/usr_jb_proto/Protocol/jb_product.h` |
+| 用户层实现 | `apps/usr_jb_proto/Protocol/jb_product.c` |
+| 协议入口 | `apps/usr_jb_proto/usr_jb_main.c` |
+| BLE 公开接口 | `apps/usr_le_code/usr_le_api.h` |
+| 板级 RTC | `apps/usr_periph/usr_rtc.c` |
+
+---
+
+## 关键注意点
+
+- **厂商预置 blob 必须保留**:`cpu/br28/tools/` 下 `ota.bin`、`p11_code.bin`、`br28loader.bin`、`eq_*.bin` 等是打包/下载依赖,不要当编译产物删掉。
+- **编译产物不入库**:`objs/`、`sdk.elf`、`sdk.map`、`app.bin` 以及 `download/` 下生成的 `.fw` / `.ufw` 已由 `.gitignore` 忽略。
+- **rom.lst 必须入库**:链接脚本输入,不在忽略列表中。
+- 打包发版可使用 `tools/package_release.py`。
---
## 相关链接
-- [分支索引详情](docs/branch-index.md)
-- [Gitea 仓库](https://git.jianbao-tech.com/pets-device/soc-codegen-template)
+- [SOC 模板仓库 main 索引](https://git.jianbao-tech.com/pets-device/soc-codegen-template)
- [MCU 模板仓库](https://git.jianbao-tech.com/pets-device/mcu-codegen-template)
diff --git a/apps/common/audio/amplitude_statistic.c b/apps/common/audio/amplitude_statistic.c
new file mode 100644
index 0000000..43711b0
--- /dev/null
+++ b/apps/common/audio/amplitude_statistic.c
@@ -0,0 +1,180 @@
+/*
+ ****************************************************************
+ * Amplitude Statistics
+ * 幅值统计模块
+ * File : amplitude_statistic.c
+ * By :
+ * Notes :
+ ****************************************************************
+ */
+
+#include "amplitude_statistic.h"
+
+#if 0
+#define amplitude_log printf
+#else
+#define amplitude_log(...)
+#endif/*log_en*/
+
+static const unsigned short am_va_tab[] = {
+ 32768, 29205, 26029, 23198, 20675, 18427, 16423, 14637, 13045, 11627, 10362, 9235, 8231, 7336, 6538, 5827,
+ 5193, 4629, 4125, 3677, 3277, 2920, 2603, 2320, 2068, 1843, 1642, 1464, 1305, 1163, 1036, 0
+};
+
+static const int rms_va_tab[] = {
+ 134217728, 106612931, 84685661, 67268212, 53433040, 42443372, 33713969, 26779957, 21272076, 16897011,
+ 13421773, 10661293, 8468566, 6726821, 5343304, 4244337, 3371397, 2677996, 2127208, 1689701,
+ 1342177, 1066129, 846857, 672682, 534330, 424434, 337140, 267800, 212721, 168970,
+ 134218, 0
+};
+
+/*
+*********************************************************************
+* Loudness meter init
+* Description: 响度计算初始化
+* Arguments : loud_obj
+* sr
+* print_dest
+* index
+* Return : NULL
+* Note(s) : NULL
+*********************************************************************
+*/
+void loudness_meter_init(LOUDNESS_M_STRUCT *loud_obj, int sr, int print_dest, u8 index)
+{
+ memset(loud_obj, 0, sizeof(LOUDNESS_M_STRUCT));
+ loud_obj->countperiod = sr / 50;
+ loud_obj->inv_counterpreiod = 16777216 / loud_obj->countperiod;
+ loud_obj->print_dest = print_dest;
+ loud_obj->index = index;
+}
+
+/*
+*********************************************************************
+* Loudness meter short
+* Description: 响度计算函数
+* Arguments : loud_obj
+* data
+* len
+* Return : NULL
+* Note(s) : NULL
+*********************************************************************
+*/
+void loudness_meter_short(LOUDNESS_M_STRUCT *loud_obj, short *data, int len)
+{
+ int i;
+ int loudness_val = 0;
+
+ for (i = 0; i < len; i++) {
+ int tmp = data[i] * 256;
+ loud_obj->dclevel = (loud_obj->dclevel * 511 + tmp) >> 9;
+
+ int xabs = (data[i] > 0) ? data[i] : (-data[i]);
+ int xabs2 = (xabs * xabs) >> 10;
+ loud_obj->rms += xabs2;
+ loud_obj->maxval = (loud_obj->maxval > xabs) ? loud_obj->maxval : xabs;
+
+ if (xabs >= 32767) {
+ loud_obj->errprintfcount0++;
+ }
+
+ loud_obj->counti++;
+ if (loud_obj->counti > loud_obj->countperiod) {
+ if (loud_obj->maxval_print < loud_obj->maxval) {
+ loud_obj->maxval_print = loud_obj->maxval;
+ }
+
+ if (loud_obj->rms_print < loud_obj->rms) {
+ loud_obj->rms_print = loud_obj->rms;
+ }
+
+ loud_obj->counti = 0;
+ loud_obj->maxval = 0;
+ loud_obj->rms = 0;
+
+ if (loud_obj->errprintfcount0 > 2) {
+ loud_obj->errprintfcount0 = 0;
+ amplitude_log("[%d]overflow occur... \n", loud_obj->index);
+ }
+
+ loud_obj->print_cnt++;
+
+ if (loud_obj->print_cnt >= loud_obj->print_dest) {
+
+ int rmsval = ((__int64)loud_obj->rms_print * (__int64)loud_obj->inv_counterpreiod) >> (24 - (10 - 3));
+
+ if (rmsval > 25837266) {
+ amplitude_log("[%d]energy high... \n", loud_obj->index);
+ }
+
+ {
+ int compi = 0, found = 0;;
+ while (compi < 31) {
+ if (rmsval >= rms_va_tab[compi]) {
+// float upval = (0 - compi) * 0.5;
+// float dwonval = (0 - compi - 1) * 0.5;
+// amplitude_log("rms level: %f to %f dB\n", upval, dwonval);
+
+ int upval = (0 - compi);
+ int dwonval = (0 - compi - 1);
+
+ amplitude_log("[%d]rms level: %d to %d dB\n", loud_obj->index, upval, dwonval);
+
+ found = 1;
+ break;
+ }
+ compi++;
+ }
+
+ if (found == 0) {
+ amplitude_log("[%d]rms level < -30dB \n", loud_obj->index);
+ }
+ }
+
+ {
+ int compi = 0, found = 0;;
+ while (compi < 31) {
+ if (loud_obj->maxval_print >= am_va_tab[compi]) {
+// float upval = (0 - compi) * 0.5;
+// float dwonval = (0 - compi - 1) * 0.5;
+// amplitude_log("peak level: %f to %f dB\n", upval, dwonval);
+ int upval = (0 - compi);
+ int dwonval = (0 - compi - 1);
+ loud_obj->peak_val = dwonval;
+ amplitude_log("[%d]peak level: %d to %d dB\n", loud_obj->index, upval, dwonval);
+
+ found = 1;
+ break;
+ }
+
+ compi++;
+ }
+
+ if (found == 0) {
+ loud_obj->peak_val = -31;
+ amplitude_log("[%d]peak level < -30dB \n", loud_obj->index);
+ }
+ }
+
+ loud_obj->print_cnt = 0;
+ loud_obj->maxval_print = 0;
+ loud_obj->rms_print = 0;
+
+ if (loud_obj->dclevel > (255 * 256)) {
+ amplitude_log("[%d] why ??? dc level : %d \n", loud_obj->index, loud_obj->dclevel >> 8);
+ }
+ amplitude_log("\n\n");
+ }
+ }
+ }
+}
+
+#if 0
+void loudness_meter_demo(void)
+{
+ loudness_meter_init(&loudness_adc, 16000, 1);
+ loudness_meter_short(&loudness_adc, datain, points);
+}
+#endif
+
+
diff --git a/apps/common/audio/amplitude_statistic.h b/apps/common/audio/amplitude_statistic.h
new file mode 100644
index 0000000..01a08bf
--- /dev/null
+++ b/apps/common/audio/amplitude_statistic.h
@@ -0,0 +1,26 @@
+#ifndef _AMPLITUDE_STATISTIC_H_
+#define _AMPLITUDE_STATISTIC_H_
+
+#include "generic/typedef.h"
+
+typedef struct _LOUDNESS_M_STRUCT_ {
+ int mutecnt;
+ int rms;
+ int counti;
+ int maxval;
+ int countperiod;
+ int inv_counterpreiod;
+ int errprintfcount0;
+ short print_cnt;
+ short print_dest;
+ int dclevel;
+ int rms_print;
+ int maxval_print;
+ int peak_val;
+ u8 index;
+} LOUDNESS_M_STRUCT;
+
+void loudness_meter_init(LOUDNESS_M_STRUCT *loud_obj, int sr, int print_dest, u8 index);
+void loudness_meter_short(LOUDNESS_M_STRUCT *loud_obj, short *data, int len);
+
+#endif /*_AMPLITUDE_STATISTIC_H_*/
diff --git a/apps/common/audio/audio_NoiseGate.h b/apps/common/audio/audio_NoiseGate.h
new file mode 100644
index 0000000..2855598
--- /dev/null
+++ b/apps/common/audio/audio_NoiseGate.h
@@ -0,0 +1,13 @@
+#ifndef _AUDIO_NOISE_GATE_H_
+#define _AUDIO_NOISE_GATE_H_
+
+#include "generic/typedef.h"
+
+
+u8 *audio_noise_gate_open(int attack_time, int release_time, float thr, float gain, int sr, int ch);
+
+void audio_noise_gate_run(u8 *runbuf, void *in, void *out, u16 len);
+
+void audio_noise_gate_close(u8 *runbuf);
+
+#endif/*_AUDIO_NOISE_GATE_H_*/
diff --git a/apps/common/audio/audio_digital_vol.h b/apps/common/audio/audio_digital_vol.h
new file mode 100644
index 0000000..68bbb33
--- /dev/null
+++ b/apps/common/audio/audio_digital_vol.h
@@ -0,0 +1,79 @@
+#ifndef _AUDIO_DIGITAL_VOL_H_
+#define _AUDIO_DIGITAL_VOL_H_
+
+#include "generic/typedef.h"
+#include "os/os_type.h"
+#include "os/os_api.h"
+#include "generic/list.h"
+
+#define BG_DVOL_FADE_ENABLE 1 /*多路声音叠加,背景声音自动淡出小声*/
+
+typedef struct {
+ u8 toggle; /*数字音量开关*/
+ u8 fade; /*淡入淡出标志*/
+ u8 vol; /*淡入淡出当前音量(level)*/
+ u8 vol_max; /*淡入淡出最大音量(level)*/
+ s16 vol_fade; /*淡入淡出对应的起始音量*/
+#if BG_DVOL_FADE_ENABLE
+ s16 vol_bk; /*后台自动淡出前音量值*/
+ struct list_head entry;
+#endif
+ volatile s16 vol_target; /*淡入淡出对应的目标音量*/
+ volatile u16 fade_step; /*淡入淡出的步进*/
+} dvol_handle;
+
+
+int audio_digital_vol_init(void);
+void audio_digital_vol_bg_fade(u8 fade_out);
+dvol_handle *audio_digital_vol_open(u8 vol, u8 vol_max, u16 fade_step);
+void audio_digital_vol_close(dvol_handle *dvol);
+void audio_digital_vol_set(dvol_handle *dvol, u8 vol);
+u8 audio_digital_vol_get(void);
+int audio_digital_vol_run(dvol_handle *dvol, void *data, u32 len);
+void audio_digital_vol_reset_fade(dvol_handle *dvol);
+
+/*************************自定义支持重入的数字音量调节****************************/
+void *user_audio_digital_volume_open(u8 vol, u8 vol_max, u16 fade_step);
+int user_audio_digital_volume_close(void *_d_volume);
+u8 user_audio_digital_volume_get(void *_d_volume);
+int user_audio_digital_volume_set(void *_d_volume, u8 vol);
+int user_audio_digital_volume_reset_fade(void *_d_volume);
+int user_audio_digital_volume_run(void *_d_volume, void *data, u32 len, u8 ch_num);
+void user_audio_digital_handler_run(void *_d_volume, void *data, u32 len);
+void user_audio_digital_set_volume_tab(void *_d_volume, u16 *user_vol_tab, u8 user_vol_max);
+
+void *user_audio_process_open(void *parm, void *priv, void (*handler)(void *priv, void *data, int len, u8 ch_num));
+int user_audio_process_close(void *_uparm_hdl);
+void user_audio_process_handler_run(void *_uparm_hdl, void *data, u32 len, u8 ch_num);
+
+struct user_audio_digital_parm {
+ u8 en;
+ u8 vol;
+ u8 vol_max;
+ u16 fade_step;
+};
+
+struct digital_volume {
+ u8 toggle; /*数字音量开关*/
+ u8 fade; /*淡入淡出标志*/
+ u8 vol; /*淡入淡出当前音量*/
+ u8 vol_max; /*淡入淡出最大音量*/
+ s16 vol_fade; /*淡入淡出对应的起始音量*/
+ volatile s16 vol_target; /*淡入淡出对应的目标音量*/
+ volatile u16 fade_step; /*淡入淡出的步进*/
+
+ OS_MUTEX mutex;
+ u8 ch_num;
+ void *priv;
+ u8 user_vol_max; /*自定义音量表级数*/
+ volatile s16 *user_vol_tab; /*自定义音量表*/
+
+};
+
+struct user_audio_parm {
+ void *priv;
+ void (*handler)(void *priv, void *data, int len, u8 ch_num);/*用户自定义回调处理*/
+ struct digital_volume *dvol_hdl;
+};
+
+#endif
diff --git a/apps/common/audio/audio_dvol.c b/apps/common/audio/audio_dvol.c
new file mode 100644
index 0000000..dc32fd0
--- /dev/null
+++ b/apps/common/audio/audio_dvol.c
@@ -0,0 +1,450 @@
+/*
+ ****************************************************************
+ * AUDIO DIGITAL VOLUME
+ * File : audio_dvol.c
+ * By :
+ * Notes : 数字音量模块,支持多通道音量控制
+ ****************************************************************
+ */
+
+#include "audio_dvol.h"
+
+#if 0
+#define dvol_log y_printf
+#else
+#define dvol_log(...)
+#endif
+
+#define DIGITAL_FADE_EN 1
+#define DIGITAL_FADE_STEP 4
+
+#define BG_DVOL_MAX 14
+#define BG_DVOL_MID 10
+#define BG_DVOL_MIN 6
+#define BG_DVOL_MAX_FADE 13 /*>= BG_DVOL_MAX:自动淡出BG_DVOL_MAX_FADE*/
+#define BG_DVOL_MID_FADE 9 /*>= BG_DVOL_MID:自动淡出BG_DVOL_MID_FADE*/
+#define BG_DVOL_MIN_FADE 5 /*>= BG_DVOL_MIN:自动淡出BG_DVOL_MIN_FADE*/
+
+#define ASM_ENABLE 1
+#define L_sat(b,a) __asm__ volatile("%0=sat16(%1)(s)":"=&r"(b) : "r"(a));
+#define L_sat32(b,a,n) __asm__ volatile("%0=%1>>%2(s)":"=&r"(b) : "r"(a),"r"(n));
+
+typedef struct {
+ u8 bg_dvol_fade_out;
+ u8 start;
+ OS_MUTEX mutex;
+ struct list_head dvol_head;
+} dvol_t;
+static dvol_t dvol_attr;
+
+/*
+ *数字音量级数 DEFAULT_DIGITAL_VOL_MAX
+ *数组长度 DEFAULT_DIGITAL_VOL_MAX + 1
+ */
+#define DEFAULT_DIGITAL_VOL_MAX (31)
+const u16 default_dig_vol_table[DEFAULT_DIGITAL_VOL_MAX + 1] = {
+ 0 , //0
+ 93 , //1
+ 111 , //2
+ 132 , //3
+ 158 , //4
+ 189 , //5
+ 226 , //6
+ 270 , //7
+ 323 , //8
+ 386 , //9
+ 462 , //10
+ 552 , //11
+ 660 , //12
+ 789 , //13
+ 943 , //14
+ 1127, //15
+ 1347, //16
+ 1610, //17
+ 1925, //18
+ 2301, //19
+ 2751, //20
+ 3288, //21
+ 3930, //22
+ 4698, //23
+ 5616, //24
+ 6713, //25
+ 8025, //26
+ 9592, //27
+ 11466,//28
+ 15200,//29
+ 16000,//30
+ 16384 //31
+};
+
+static u16 digital_vol_max = DEFAULT_DIGITAL_VOL_MAX;
+static u16 *dig_vol_table = default_dig_vol_table;
+
+/*
+*********************************************************************
+* Audio Digital Volume Init
+* Description: 数字音量模块初始化
+* Arguments : None.
+* Return : 0 成功 其他 失败
+* Note(s) : None.
+*********************************************************************
+*/
+int audio_digital_vol_init(u16 *vol_table, u16 vol_max)
+{
+ memset(&dvol_attr, 0, sizeof(dvol_attr));
+ INIT_LIST_HEAD(&dvol_attr.dvol_head);
+ os_mutex_create(&dvol_attr.mutex);
+
+ if (vol_table != NULL) {
+ dig_vol_table = vol_table;
+ digital_vol_max = vol_max;
+ }
+
+ return 0;
+}
+
+/*背景音乐淡出使能*/
+void audio_digital_vol_bg_fade(u8 fade_out)
+{
+ dvol_log("audio_digital_vol_bg_fade:%d", fade_out);
+ dvol_attr.bg_dvol_fade_out = fade_out;
+}
+
+/*
+*********************************************************************
+* Audio Digital Volume Open
+* Description: 数字音量模块打开
+* Arguments : dvol_idx 数字音量通道索引,详见audio_dvol.h宏定义
+* vol 当前数字音量等级
+* vol_max 最大数字音量等级
+* fade_step 淡入淡出步进
+* vol_limit 数字音量限制,即可以给vol_max等分的最大音量
+* Return : 数字音量通道句柄
+* Note(s) : fade_step一般不超过两级数字音量的最小差值
+* (1)通话如果用数字音量,一般步进小一点,音量调节的时候不会有杂音
+* (2)淡出的时候可以快一点,尽快淡出到0
+*********************************************************************
+*/
+dvol_handle *audio_digital_vol_open(u8 dvol_idx, u8 vol, u8 vol_max, u16 fade_step, char vol_limit)
+{
+ dvol_log("dvol_open:%d-%d-%d-%d\n", vol, vol_max, fade_step, vol_limit);
+ dvol_handle *dvol = NULL;
+ dvol = zalloc(sizeof(dvol_handle));
+ if (dvol) {
+ u8 vol_level;
+ dvol->fade = DIGITAL_FADE_EN;
+ dvol->vol = (vol > vol_max) ? vol_max : vol;
+ if (vol > vol_max) {
+ printf("[warning]cur digital_vol(%d) > digital_vol_max(%d)!!", vol, vol_max);
+ }
+ dvol->vol_max = vol_max;
+ if (vol_limit == -1) {
+ dvol->vol_limit = digital_vol_max;
+ } else {
+ dvol->vol_limit = (vol_limit > digital_vol_max) ? digital_vol_max : vol_limit;
+ }
+ vol_level = dvol->vol * dvol->vol_limit / vol_max;
+ dvol->vol_target = dig_vol_table[vol_level];
+ dvol->vol_fade = dvol->vol_target;
+ dvol->fade_step = fade_step;
+ dvol->toggle = 1;
+ dvol->idx = dvol_idx;
+ local_irq_disable();
+ list_add(&dvol->entry, &dvol_attr.dvol_head);
+#if BG_DVOL_FADE_ENABLE
+ dvol->vol_bk = -1;
+ if (dvol_attr.bg_dvol_fade_out) {
+ dvol_handle *hdl;
+ list_for_each_entry(hdl, &dvol_attr.dvol_head, entry) {
+ if ((hdl != dvol) && (hdl->idx)) {
+ hdl->vol_bk = hdl->vol;
+ if (hdl->vol >= BG_DVOL_MAX) {
+ hdl->vol -= BG_DVOL_MAX_FADE;
+ } else if (hdl->vol >= BG_DVOL_MID) {
+ hdl->vol -= BG_DVOL_MID_FADE;
+ } else if (hdl->vol >= BG_DVOL_MIN) {
+ hdl->vol -= BG_DVOL_MIN_FADE;
+ } else {
+ hdl->vol_bk = -1;
+ continue;
+ }
+ u8 vol_level = hdl->vol * dvol->vol_limit / hdl->vol_max;
+ hdl->vol_target = dig_vol_table[vol_level];
+ //y_printf("bg_dvol fade_out:%x,vol_bk:%d,vol_set:%d,tartget:%d",hdl,hdl->vol_bk,hdl->vol,hdl->vol_target);
+ }
+ }
+ }
+#endif/*BG_DVOL_FADE_ENABLE*/
+ local_irq_enable();
+ dvol_log("dvol_open[%x]:%x-%d-%d-%d\n", dvol_idx, dvol, dvol->vol, dvol->vol_max, fade_step);
+ }
+ return dvol;
+}
+
+/*
+*********************************************************************
+* Audio Digital Volume Close
+* Description: 数字音量模块关闭
+* Arguments : dvol_idx 数字音量通道索引,详见audio_dvol.h宏定义
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+void audio_digital_vol_close(u8 dvol_idx)
+{
+ dvol_log("dvol_close[%x]\n", dvol_idx);
+ dvol_handle *dvol = NULL;
+ u8 dvol_valid = 0;
+ list_for_each_entry(dvol, &dvol_attr.dvol_head, entry) {
+ if (dvol && (dvol->idx == dvol_idx)) {
+ dvol_log("dvol_close[%x]:%x", dvol_idx, dvol);
+ dvol_valid = 1;
+ break;
+ }
+ }
+ if (dvol_valid == 0) {
+ return;
+ }
+
+ if (dvol) {
+ local_irq_disable();
+#if BG_DVOL_FADE_ENABLE
+ dvol_handle *hdl;
+ list_for_each_entry(hdl, &dvol_attr.dvol_head, entry) {
+ if ((hdl != dvol) && (hdl->vol_bk >= 0)) {
+ //y_printf("bg_dvol fade_in:%x,%d",hdl,hdl->vol_bk);
+ hdl->vol = hdl->vol_bk;
+ u8 vol_level = hdl->vol_bk * dvol->vol_limit / hdl->vol_max;
+ hdl->vol_target = dig_vol_table[vol_level];
+ hdl->vol_bk = -1;
+ }
+ }
+#endif
+ list_del(&dvol->entry);
+ free(dvol);
+ dvol = NULL;
+ local_irq_enable();
+ }
+}
+
+/*
+*********************************************************************
+* Audio Digital Volume Get
+* Description: 数字音量获取
+* Arguments : dvol_idx 数字音量通道索引,详见audio_dvol.h宏定义
+* Return : 对应的数字音量通道的当前音量等级.
+* Note(s) : None.
+*********************************************************************
+*/
+int audio_digital_vol_get(u8 dvol_idx)
+{
+ dvol_handle *dvol = NULL;
+ u8 dvol_valid = 0;
+ local_irq_disable();
+ list_for_each_entry(dvol, &dvol_attr.dvol_head, entry) {
+ if (dvol && (dvol->idx == dvol_idx)) {
+ dvol_valid = 1;
+ break;
+ }
+ }
+ local_irq_enable();
+ if (dvol && dvol_valid) {
+ return dvol->vol;
+ }
+ return 0;
+}
+
+/*
+*********************************************************************
+* Audio Digital Volume Set
+* Description: 数字音量设置
+* Arguments : dvol_idx 数字音量通道索引,详见audio_dvol.h宏定义
+* vol 目标音量等级
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+void audio_digital_vol_set(u8 dvol_idx, u8 vol)
+{
+ dvol_log("audio_digital_vol set:%d,%d\n", dvol_idx, vol);
+ dvol_handle *dvol = NULL;
+ u8 dvol_valid = 0;
+ local_irq_disable();
+ list_for_each_entry(dvol, &dvol_attr.dvol_head, entry) {
+ if (dvol && (dvol->idx == dvol_idx)) {
+ dvol_log("dvol_set[%x]:%x", dvol_idx, dvol);
+ dvol_valid = 1;
+ break;
+ }
+ }
+ local_irq_enable();
+ if ((dvol == NULL) || (dvol_valid == 0)) {
+ return;
+ }
+ if (dvol->toggle == 0) {
+ return;
+ }
+ dvol->vol = (vol > dvol->vol_max) ? dvol->vol_max : vol;
+#if BG_DVOL_FADE_ENABLE
+ if (dvol->vol_bk != -1) {
+ dvol->vol_bk = vol;
+ }
+#endif
+ dvol->fade = DIGITAL_FADE_EN;
+ u8 vol_level = dvol->vol * dvol->vol_limit / dvol->vol_max;
+ dvol->vol_target = dig_vol_table[vol_level];
+ dvol_log("digital_vol:%d-%d-%d-%d\n", vol, vol_level, dvol->vol_fade, dvol->vol_target);
+}
+/*********************************************************************
+* Audio Digital Volume Set
+* Description: 数字音量设置,设置数字音量的当前值,不用淡入淡出
+* Arguments : dvol_idx 数字音量通道索引,详见audio_dvol.h宏定义
+* vol 目标音量等级
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+
+void audio_digital_vol_set_no_fade(u8 dvol_idx, u8 vol)
+{
+ dvol_log("audio_digital_vol set:%d,%d\n", dvol_idx, vol);
+ dvol_handle *dvol = NULL;
+ u8 dvol_valid = 0;
+ local_irq_disable();
+ list_for_each_entry(dvol, &dvol_attr.dvol_head, entry) {
+ if (dvol && (dvol->idx == dvol_idx)) {
+ dvol_log("dvol_set[%x]:%x", dvol_idx, dvol);
+ dvol_valid = 1;
+ break;
+ }
+ }
+ local_irq_enable();
+ if ((dvol == NULL) || (dvol_valid == 0)) {
+ return;
+ }
+ if (dvol->toggle == 0) {
+ return;
+ }
+ dvol->vol = (vol > dvol->vol_max) ? dvol->vol_max : vol;
+#if BG_DVOL_FADE_ENABLE
+ if (dvol->vol_bk != -1) {
+ dvol->vol_bk = vol;
+ }
+#endif
+ dvol->fade = DIGITAL_FADE_EN;
+ u8 vol_level = dvol->vol * dvol->vol_limit / dvol->vol_max;
+ dvol->vol_fade = dig_vol_table[vol_level];
+ dvol_log("digital_vol:%d-%d-%d-%d\n", vol, vol_level, dvol->vol_fade, dvol->vol_target);
+}
+
+void audio_digital_vol_reset_fade(u8 dvol_idx)
+{
+ dvol_handle *dvol = NULL;
+ u8 dvol_valid = 0;
+ local_irq_disable();
+ list_for_each_entry(dvol, &dvol_attr.dvol_head, entry) {
+ if (dvol && (dvol->idx == dvol_idx)) {
+ dvol_valid = 1;
+ break;
+ }
+ }
+ local_irq_enable();
+ if (dvol && dvol_valid) {
+ dvol->vol_fade = 0;
+ }
+}
+
+/*
+*********************************************************************
+* Audio Digital Volume Process
+* Description: 数字音量运算核心
+* Arguments : dvol_idx 数字音量通道索引,详见audio_dvol.h宏定义
+* data 待运算数据
+* len 待运算数据长度
+* Return : 0 成功 其他 失败
+* Note(s) : None.
+*********************************************************************
+*/
+/*rounding处理*/
+#define MUL32_PSHIFT(x,y,s) (((x) * (y) + (1 << ((s)-1))) >> (s))
+
+int audio_digital_vol_run(u8 dvol_idx, void *data, u32 len)
+{
+ s32 valuetemp;
+ s16 *buf;
+
+ os_mutex_pend(&dvol_attr.mutex, 0);
+ dvol_handle *dvol = NULL;
+ u8 dvol_valid = 0;
+ local_irq_disable();
+ list_for_each_entry(dvol, &dvol_attr.dvol_head, entry) {
+ if (dvol && (dvol->idx == dvol_idx)) {
+ dvol_valid = 1;
+#if 0
+ static dvol_handle *last_dvol = NULL;
+ if (last_dvol != dvol) {
+ dvol_log("dvol_run[%x]:%x", dvol_idx, dvol);
+ last_dvol = dvol;
+ }
+#endif
+ break;
+ }
+ }
+ local_irq_enable();
+
+ if ((dvol->toggle == 0) || (dvol_valid == 0)) {
+ os_mutex_post(&dvol_attr.mutex);
+ return -1;
+ }
+
+ buf = data;
+ len >>= 1; //byte to point
+
+ for (u32 i = 0; i < len; i += 2) {
+ ///left channel
+ if (dvol->fade) {
+ if (dvol->vol_fade > dvol->vol_target) {
+ dvol->vol_fade -= dvol->fade_step;
+ if (dvol->vol_fade < dvol->vol_target) {
+ dvol->vol_fade = dvol->vol_target;
+ }
+ } else if (dvol->vol_fade < dvol->vol_target) {
+ dvol->vol_fade += dvol->fade_step;
+ if (dvol->vol_fade > dvol->vol_target) {
+ dvol->vol_fade = dvol->vol_target;
+ }
+ }
+ } else {
+ dvol->vol_fade = dvol->vol_target;
+ }
+
+ valuetemp = buf[i];
+ if (valuetemp < 0) {
+ /*负数先转换成正数,运算完再转换回去,是为了避免负数右移位引入1的误差,增加底噪*/
+ valuetemp = -valuetemp;
+ /*rounding处理(加入0.5),减少小信号时候的误差和谐波幅值*/
+ valuetemp = (valuetemp * dvol->vol_fade + (1 << 13)) >> 14 ;
+ valuetemp = -valuetemp;
+ } else {
+ valuetemp = (valuetemp * dvol->vol_fade + (1 << 13)) >> 14 ;
+ }
+ /*饱和处理*/
+ buf[i] = (s16)data_sat_s16(valuetemp);
+
+ ///right channel
+ valuetemp = buf[i + 1];
+ if (valuetemp < 0) {
+ /*负数先转换成正数,运算完再转换回去,是为了避免负数右移位引入1的误差,增加底噪*/
+ valuetemp = -valuetemp;
+ valuetemp = (valuetemp * dvol->vol_fade + (1 << 13)) >> 14 ;
+ valuetemp = -valuetemp;
+ } else {
+ valuetemp = (valuetemp * dvol->vol_fade + (1 << 13)) >> 14 ;
+ }
+ /*饱和处理*/
+ buf[i + 1] = (s16)data_sat_s16(valuetemp);
+ }
+ os_mutex_post(&dvol_attr.mutex);
+ return 0;
+}
+
diff --git a/apps/common/audio/audio_dvol.h b/apps/common/audio/audio_dvol.h
new file mode 100644
index 0000000..ec83f50
--- /dev/null
+++ b/apps/common/audio/audio_dvol.h
@@ -0,0 +1,55 @@
+#ifndef _AUDIO_DVOL_H_
+#define _AUDIO_DVOL_H_
+
+#include "generic/typedef.h"
+#include "os/os_type.h"
+#include "os/os_api.h"
+#include "generic/list.h"
+
+#define BG_DVOL_FADE_ENABLE 1 /*多路声音叠加,背景声音自动淡出小声*/
+
+/*Digital Volume Channel*/
+#define MUSIC_DVOL 0xA1
+#define CALL_DVOL 0xA2
+#define TONE_DVOL 0xA3
+#define HEARING_DVOL 0xA4
+
+/*Digital Volume Fade Step*/
+#define MUSIC_DVOL_FS 2
+#define CALL_DVOL_FS 4
+#define TONE_DVOL_FS 30
+#define HEARING_DVOL_FS 2
+
+/*Digital Volume Max Level*/
+#define MUSIC_DVOL_MAX 16
+#define CALL_DVOL_MAX 15
+#define TONE_DVOL_MAX 16
+#define HEARING_DVOL_MAX 16
+
+typedef struct {
+ u8 toggle; /*数字音量开关*/
+ u8 fade; /*淡入淡出标志*/
+ u8 vol; /*淡入淡出当前音量(level)*/
+ u8 vol_max; /*淡入淡出最大音量(level)*/
+ char vol_limit; /*最大数字音量限制*/
+ u8 idx; /*数字音量通道索引*/
+ s16 vol_fade; /*淡入淡出对应的起始音量*/
+#if BG_DVOL_FADE_ENABLE
+ s16 vol_bk; /*后台自动淡出前音量值*/
+#endif/*BG_DVOL_FADE_ENABLE*/
+ struct list_head entry;
+ volatile s16 vol_target; /*淡入淡出对应的目标音量*/
+ volatile u16 fade_step; /*淡入淡出的步进*/
+} dvol_handle;
+
+int audio_digital_vol_init(u16 *vol_table, u16 vol_max);
+void audio_digital_vol_bg_fade(u8 fade_out);
+dvol_handle *audio_digital_vol_open(u8 dvol_idx, u8 vol, u8 vol_max, u16 fade_step, char vol_limit);
+void audio_digital_vol_close(u8 dvol_idx);
+void audio_digital_vol_set(u8 dvol_idx, u8 vol);
+int audio_digital_vol_get(u8 dvol_idx);
+int audio_digital_vol_run(u8 dvol_idx, void *data, u32 len);
+void audio_digital_vol_reset_fade(u8 dvol_idx);
+void audio_digital_vol_set_no_fade(u8 dvol_idx, u8 vol);
+
+#endif/*_AUDIO_DVOL_H_*/
diff --git a/apps/common/audio/audio_export_demo.c b/apps/common/audio/audio_export_demo.c
new file mode 100644
index 0000000..1bf6970
--- /dev/null
+++ b/apps/common/audio/audio_export_demo.c
@@ -0,0 +1,140 @@
+#include "app_config.h"
+#ifdef AUDIO_PCM_DEBUG
+#include "uartPcmSender.h"
+
+extern int aec_uart_init();
+extern int aec_uart_fill(u8 ch, void *buf, u16 size);
+extern void aec_uart_write(void);
+extern int aec_uart_close(void);
+
+/*
+ 16k 正选波 pcm 数据
+*/
+static short const sin0_16k[16] = {
+ 0x0000, 0x30fd, 0x5a83, 0x7641, 0x7fff, 0x7642, 0x5a82, 0x30fc, 0x0000, 0xcf04, 0xa57d, 0x89be, 0x8000, 0x89be, 0xa57e, 0xcf05,
+};
+static u16 tx1_s_cnt = 0;
+static int get_sine0_data(u16 *s_cnt, s16 *data, u16 points, u8 ch)
+{
+ while (points--) {
+ if (*s_cnt >= 16) {
+ *s_cnt = 0;
+ }
+ *data++ = sin0_16k[*s_cnt] / 2;
+ if (ch == 2) {
+ *data++ = sin0_16k[*s_cnt] / 2;
+ }
+ (*s_cnt)++;
+ }
+ return 0;
+}
+
+/*
+*************************************************************
+* uart data export 接口使用说明
+* 1、每个通道一次只能固定发送512byte数据,数据不够会被丢弃
+* 2、aec_uart_write()一次会发送3个通道的数据,没有填数的通道会发送空白数据
+* 3、UART DMA发送一次数据需要约8ms时间,两次发数间隔需 > 8ms
+* 4、发送波特率、发送引脚在 uartPcmSender.h 配置
+* 5、该接口的接收端需使用JL的串口导出工具接收数据
+*
+*************************************************************
+*/
+void audio_export_demo_task(void *param)
+{
+ printf("audio_export_demo_task\n");
+ s16 data[256];
+ int len = 512;
+ /*生成256个点的16k的正选波数据*/
+ get_sine0_data(&tx1_s_cnt, data, len / 2, 1);
+
+ while (1) {
+ putchar('.');
+
+ {
+ /*run code*/
+ }
+
+ aec_uart_fill(0, data, 512); //往通道0填数据
+
+ {
+ /*run code*/
+ }
+
+ aec_uart_fill(1, data, 512); //往通道1填数据
+
+ {
+ /*run code*/
+ }
+
+ aec_uart_fill(2, data, 512); //往通道2填数据
+ aec_uart_write(); //一次把3路数据发送出去
+ os_time_dly(2); //等待发送完成,发送一次要8ms,发完才可以进行下一次发数
+ }
+}
+
+/*
+**********************************************************
+* uart data export 接口使用示例
+*********************************************************
+*/
+int audio_export_demo_init()
+{
+ printf("audio_export_demo_init\n");
+ /* uartSendInit(); //串口初始化,已经在开机时调用初始化,这里不需调用 */
+ aec_uart_init(); //uart export 初始化
+ os_task_create(audio_export_demo_task, NULL, 1, 1024, 128, "audio_export_task");
+
+ return 0;
+}
+
+
+/*
+*************************************************************
+* 通用 uart 发数接口(uartSendData())使用说明
+* 1、发数的数据长度可以根据需要修改
+* 2、一般发送512byte,DMA模式需要2.7ms
+* 3、发送波特率、发送引脚在 uartPcmSender.h 配置
+* 4、可以使用该接口自定义发数方式、协议等
+*
+*************************************************************
+*/
+void audio_uart_transmit_demo_task(void *param)
+{
+ printf("audio_uart_transmit_demo_task\n");
+ s16 data[256];
+ int len = 512;
+ /*生成256个点的16k的正选波数据*/
+ get_sine0_data(&tx1_s_cnt, data, len / 2, 1);
+
+ while (1) {
+ putchar('.');
+ uartSendData(data, len); //uart 发送数据接口
+ os_time_dly(1); //一般发送512byte,DMA模式需要2.7ms
+ }
+}
+/*
+**********************************************************
+* 通用uart发数使用示例
+*********************************************************
+*/
+int audio_uart_transmit_demo_init()
+{
+ printf("audio_uart_transmit_demo_init\n");
+ /* uartSendInit(); //串口初始化,已经在开机时调用初始化,这里不需调用 */
+ os_task_create(audio_uart_transmit_demo_task, NULL, 1, 1024, 128, "audio_uart_transmit_task");
+ return 0;
+}
+
+static u8 audio_export_demo_idle_query()
+{
+ return 0;
+}
+
+REGISTER_LP_TARGET(audio_export_demo_lp_target) = {
+ .name = "audio_export__demo",
+ .is_idle = audio_export_demo_idle_query,
+};
+
+#endif /*AUDIO_PCM_DEBUG*/
+
diff --git a/apps/common/audio/audio_noise_gate.c b/apps/common/audio/audio_noise_gate.c
new file mode 100644
index 0000000..f36ac4e
--- /dev/null
+++ b/apps/common/audio/audio_noise_gate.c
@@ -0,0 +1,126 @@
+/*
+ ******************************************************************
+ * Limiter_NoiseGate Module(限幅器/噪声门限模块)
+ *1. Limiter:限制最大幅度
+ *2. NoiseGate:
+ *(1)启动时间
+ *(2)释放时间
+ *(3)噪声阈值
+ *(4)噪声增益
+ *3. Usage:
+ *(1)LIMITER_THR:限幅器参数,限制信号的最大值
+ *(2)LIMITER_NOISE_GATE:噪声门限的阈值,配合LIMITER_NOISE_GAIN使用
+ *(3)LIMITER_NOISE_GAIN:当信号小于噪声门限LIMITER_NOISE_GATE的时候
+ *信号增益为LIMITER_NOISE_GAIN,范围是0到1,增益0为静音,增益1为直通
+ *效果。噪声门限用来优化声音的底噪
+ ******************************************************************
+ */
+
+#include "system/includes.h"
+#include "os/os_api.h"
+#include "limiter_noiseGate_api.h"
+#include "audio_noise_gate.h"
+
+
+//#define NG_LOG_ENABLE
+#ifdef NG_LOG_ENABLE
+#define NG_LOG y_printf
+#else
+#define NG_LOG(...)
+#endif/*NG_LOG_ENABLE*/
+
+/*限幅器上限*/
+#define LIMITER_THR -10000 /*-12000 = -12dB,放大1000倍,(-10000参考)*/
+/*小于CONST_NOISE_GATE的当成噪声处理,防止清0近端声音*/
+#define LIMITER_NOISE_GATE -40000 /*-12000 = -12dB,放大1000倍,(-40000参考)*/
+/*低于噪声门限阈值的增益 */
+#define LIMITER_NOISE_GAIN (0 << 30) /*(0~1)*2^30*/
+
+enum {
+ NG_STA_CLOSE = 0,
+ NG_STA_OPEN,
+ NG_STA_RUN,
+};
+
+typedef struct {
+ u8 state;
+ OS_MUTEX mutex;
+ u8 *run_buf;
+} audio_noise_gate_t;
+audio_noise_gate_t NoiseGate;
+
+int audio_noise_gate_open(u16 sample_rate, int limiter_thr, int noise_gate, int noise_gain)
+{
+ NG_LOG("audio_noise_gate_open");
+ NoiseGate.run_buf = malloc(need_limiter_noiseGate_buf(1));
+ NG_LOG("Limiter_noisegate_buf size:%d\n", need_limiter_noiseGate_buf(1));
+ if (NoiseGate.run_buf) {
+ //限幅器启动因子 int32(exp(-0.65/(16000 * 0.005))*2^30) 16000为采样率 0.005 为启动时间(s)
+ int limiter_attfactor = 1065053018;
+ //限幅器释放因子 int32(exp(-0.15/(16000 * 0.1))*2^30) 16000为采样率 0.1 为释放时间(s)
+ int limiter_relfactor = 1073641165;
+ //限幅器阈值(mdb)
+ //int limiter_threshold = CONST_LIMITER_THR;
+
+ //噪声门限启动因子 int32(exp(-1/(16000 * 0.1))*2^30) 16000为采样率 0.1 为启动时间(s)
+ /*
+ *import math
+ *int(math.exp(-1.0/(16000*0.1))*2**30)
+ */
+ int noiseGate_attfactor = 1073070945;
+ //噪声门限释放因子 int32(exp(-1/(16000 * 0.005))*2^30) 16000为采样率 0.005 为释放时间(s)
+ int noiseGate_relfactor = 1060403589;
+ //噪声门限(mdb)
+ //int noiseGate_threshold = -25000;
+ //低于噪声门限阈值的增益 (0~1)*2^30
+ //int noise
+ //Gate_low_thr_gain = 0 << 30;
+
+ if (sample_rate == 8000) {
+ limiter_attfactor = 1056434522;
+ limiter_relfactor = 1073540516;
+ noiseGate_attfactor = 1072400485;
+ noiseGate_relfactor = 1047231044;
+ }
+
+ limiter_noiseGate_init(NoiseGate.run_buf,
+ limiter_attfactor,
+ limiter_relfactor,
+ noiseGate_attfactor,
+ noiseGate_relfactor,
+ limiter_thr,
+ noise_gate,
+ noise_gain,
+ sample_rate, 1);
+ os_mutex_create(&NoiseGate.mutex);
+ NoiseGate.state = NG_STA_OPEN;
+ NG_LOG("audio_noise_gate_open succ");
+ return 0;
+ }
+ return -ENOMEM;
+}
+
+void audio_noise_gate_run(void *in, void *out, u16 len)
+{
+ if (NoiseGate.state == NG_STA_CLOSE) {
+ return;
+ }
+ os_mutex_pend(&NoiseGate.mutex, 0);
+ if (NoiseGate.run_buf) {
+ limiter_noiseGate_run(NoiseGate.run_buf, in, out, len / 2);
+ }
+ os_mutex_post(&NoiseGate.mutex);
+}
+
+void audio_noise_gate_close()
+{
+ NG_LOG("audio_noise_gate_close");
+ os_mutex_pend(&NoiseGate.mutex, 0);
+ NoiseGate.state = NG_STA_CLOSE;
+ if (NoiseGate.run_buf) {
+ free(NoiseGate.run_buf);
+ }
+ os_mutex_post(&NoiseGate.mutex);
+ NG_LOG("audio_noise_gate_close succ");
+}
+
diff --git a/apps/common/audio/audio_noise_gate.h b/apps/common/audio/audio_noise_gate.h
new file mode 100644
index 0000000..2dbee00
--- /dev/null
+++ b/apps/common/audio/audio_noise_gate.h
@@ -0,0 +1,11 @@
+#ifndef _AUDIO_LIMITER_NOISE_GATE_H_
+#define _AUDIO_LIMITER_NOISE_GATE_H_
+
+#include "generic/typedef.h"
+
+
+int audio_noise_gate_open(u16 sample_rate, int limiter_thr, int noise_gate, int noise_gain);
+void audio_noise_gate_run(void *in, void *out, u16 len);
+void audio_noise_gate_close();
+
+#endif/*_AUDIO_NOISE_GATE_H_*/
diff --git a/apps/common/audio/audio_ns.c b/apps/common/audio/audio_ns.c
new file mode 100644
index 0000000..6bf1f7d
--- /dev/null
+++ b/apps/common/audio/audio_ns.c
@@ -0,0 +1,112 @@
+/*
+ ******************************************************************
+ * Noise Suppress Module(降噪模块)
+ *Notes:
+ *(1)支持降噪的数据采样率:8k/16k
+ *(2)增加多5k左右代码
+ *(3)内存消耗跟数据采样率有关,具体可通过以下接口查询:
+ * int ns_mem_size = noise_suppress_mem_query(&ans->ns_para);
+ ******************************************************************
+ */
+
+#include "audio_ns.h"
+
+#ifdef CONFIG_MEDIA_NEW_ENABLE
+
+/*
+*********************************************************************
+* NoiseSuppress Process
+* Description: 降噪处理主函数
+* Arguments : ns 降噪句柄
+* in 输入数据
+* out 输出数据
+* len 输入数据长度
+* Return : 降噪输出长度
+* Note(s) : 由于降噪是固定处理帧长的,所以如果输入数据长度不是降噪
+* 帧长整数倍,则某一次会输出0长度,即没有输出
+*********************************************************************
+*/
+int audio_ns_run(audio_ns_t *ns, short *in, short *out, u16 len)
+{
+ if (ns == NULL) {
+ return len;
+ }
+#if 0
+ int wlen = cbuf_write(&ns->cbuf, in, len);
+ if (wlen != len) {
+ printf("ns_cbuf full\n");
+ }
+ if (ns->cbuf.data_len >= NS_FRAME_SIZE) {
+ cbuf_read(&ns->cbuf, out, NS_FRAME_SIZE);
+ putchar('.');
+ noise_suppress_run(out, out, NS_FRAME_POINTS);
+ return NS_FRAME_SIZE;
+ } else {
+ return 0;
+ }
+#else
+ //putchar('.');
+ int nOut = noise_suppress_run(in, out, (len / 2));
+ return (nOut << 1);
+#endif
+}
+
+/*
+*********************************************************************
+* Noise Suppress Open
+* Description: 初始化降噪模块
+* Arguments : sr 数据采样率
+* mode 降噪模式(0,1,2:越大越耗资源,效果越好)
+* NoiseLevel 初始噪声水平(评估初始噪声,加快收敛)
+* AggressFactor 降噪强度(越大越强:1~2)
+* MinSuppress 降噪最小压制(越小越强:0~1)
+* Return : 降噪模块句柄
+* Note(s) : (1)采样率只支持8k、16k
+* (2)如果内存不足,可以考虑wideband强制为0,即只做窄带降噪
+* ans-ns_para.wideband = 0;
+*********************************************************************
+*/
+audio_ns_t *audio_ns_open(u16 sr, u8 mode, float NoiseLevel, float AggressFactor, float MinSuppress)
+{
+ audio_ns_t *ans = zalloc(sizeof(audio_ns_t));
+ //cbuf_init(&ans->cbuf, ans->in, sizeof(ans->in));
+
+ ans->ns_para.wideband = (sr == 16000) ? 1 : 0;
+ ans->ns_para.mode = mode;
+ ans->ns_para.NoiseLevel = NoiseLevel;
+ ans->ns_para.AggressFactor = AggressFactor;
+ ans->ns_para.MinSuppress = MinSuppress;
+ printf("ns wideband:%d\n", ans->ns_para.wideband);
+ //int ns_mem_size = noise_suppress_mem_query(&ans->ns_para);
+ //printf("ns mem_size:%d\n", ns_mem_size);
+ noise_suppress_open(&ans->ns_para);
+ float lowcut = -60.f;
+ noise_suppress_config(NS_CMD_LOWCUTTHR, 0, &lowcut);
+ float noise_floor = -60.f;
+ noise_suppress_config(NS_CMD_NOISE_FLOOR, 0, &noise_floor);
+ printf("audio_ns_open ok\n");
+ return ans;
+}
+
+/*
+*********************************************************************
+* Noise Suppress Close
+* Description: 关闭降噪模块
+* Arguments : ns 降噪模块句柄
+* Return : 0 成功 其他 失败
+* Note(s) : None.
+*********************************************************************
+*/
+int audio_ns_close(audio_ns_t *ns)
+{
+ noise_suppress_close();
+ if (ns) {
+ free(ns);
+ ns = NULL;
+ }
+ printf("esco_ans_close ok\n");
+ return 0;
+}
+
+#endif /*CONFIG_MEDIA_NEW_ENABLE*/
+
diff --git a/apps/common/audio/audio_ns.h b/apps/common/audio/audio_ns.h
new file mode 100644
index 0000000..160f894
--- /dev/null
+++ b/apps/common/audio/audio_ns.h
@@ -0,0 +1,61 @@
+#ifndef _AUDIO_NOISE_SUPPRESS_H_
+#define _AUDIO_NOISE_SUPPRESS_H_
+
+#include "generic/typedef.h"
+#include "generic/circular_buf.h"
+#include "commproc_ns.h"
+
+/*降噪数据帧长(单位:点数)*/
+#define NS_FRAME_POINTS 160
+#define NS_FRAME_SIZE (NS_FRAME_POINTS << 1)
+/*降噪输出buf长度*/
+#define NS_OUT_POINTS_MAX (NS_FRAME_POINTS << 1)
+
+typedef struct {
+ //s16 in[512];
+ //cbuffer_t cbuf;
+ noise_suppress_param ns_para;
+} audio_ns_t;
+
+/*
+*********************************************************************
+* Noise Suppress Open
+* Description: 初始化降噪模块
+* Arguments : sr 数据采样率
+* mode 降噪模式(0,1,2:越大越耗资源,效果越好)
+* NoiseLevel 初始噪声水平(评估初始噪声,加快收敛)
+* AggressFactor 降噪强度(越大越强:1~2)
+* MinSuppress 降噪最小压制(越小越强:0~1)
+* Return : 降噪模块句柄
+* Note(s) : 采样率只支持8k、16k
+*********************************************************************
+*/
+audio_ns_t *audio_ns_open(u16 sr, u8 mode, float NoiseLevel, float AggressFactor, float MinSuppress);
+
+/*
+*********************************************************************
+* NoiseSuppress Process
+* Description: 降噪处理主函数
+* Arguments : ns 降噪句柄
+* in 输入数据
+* out 输出数据
+* len 输入数据长度
+* Return : 降噪输出长度
+* Note(s) : 由于降噪是固定处理帧长的,所以如果输入数据长度不是降噪
+* 帧长整数倍,则某一次会输出0长度,即没有输出
+*********************************************************************
+*/
+int audio_ns_run(audio_ns_t *ns, short *in, short *out, u16 len);
+
+/*
+*********************************************************************
+* Noise Suppress Close
+* Description: 关闭降噪模块
+* Arguments : ns 降噪模块句柄
+* Return : 0 成功 其他 失败
+* Note(s) : None.
+*********************************************************************
+*/
+int audio_ns_close(audio_ns_t *ns);
+
+#endif/*_AUDIO_NOISE_SUPPRESS_H_*/
diff --git a/apps/common/audio/audio_plc.c b/apps/common/audio/audio_plc.c
new file mode 100644
index 0000000..e820907
--- /dev/null
+++ b/apps/common/audio/audio_plc.c
@@ -0,0 +1,138 @@
+/*
+ ************************************************************
+ *
+ *
+ *
+ ************************************************************
+ */
+#include "system/includes.h"
+#include "PLC.h"
+#include "os/os_api.h"
+#include "app_config.h"
+#include "audio_config.h"
+
+#if TCFG_ESCO_PLC
+
+//#define AUDIO_PLC_LOG_ENABLE
+#ifdef AUDIO_PLC_LOG_ENABLE
+#define PLC_LOG y_printf
+#else
+#define PLC_LOG(...)
+#endif/*AUDIO_PLC_LOG_ENABLE*/
+
+enum {
+ PLC_STA_CLOSE = 0,
+ PLC_STA_OPEN,
+ PLC_STA_RUN,
+};
+
+
+#define PLC_FRAME_LEN 120
+typedef struct {
+ u8 state;
+ u8 repair;
+ u8 wideband;
+ OS_MUTEX mutex;
+ s16 *run_buf;
+} audio_plc_t;
+static audio_plc_t plc;
+
+int audio_plc_open(u16 sr)
+{
+ PLC_LOG("audio_plc_open:%d\n", sr);
+ memset((u8 *)&plc, 0, sizeof(audio_plc_t));
+ plc.run_buf = malloc(PLC_query()); /*buf_size:1040*/
+ PLC_LOG("PLC_buf:%x,size:%d\n", plc.run_buf, PLC_query());
+ if (plc.run_buf) {
+ s8 err = PLC_init(plc.run_buf);
+ if (err) {
+ PLC_LOG("PLC_init err:%d", err);
+ free(plc.run_buf);
+ return -EINVAL;
+ }
+ os_mutex_create(&plc.mutex);
+ if (sr == 16000) {
+ plc.wideband = 1;
+ }
+ plc.state = PLC_STA_OPEN;
+ }
+ PLC_LOG("audio_plc_open succ\n");
+ return 0;
+}
+
+void audio_plc_run(s16 *data, u16 len, u8 repair)
+{
+ u16 repair_point, tmp_point;
+ s16 *p_in, *p_out;
+ p_in = data;
+ p_out = data;
+ tmp_point = len / 2;
+ u8 repair_flag = 0;
+
+ os_mutex_pend(&plc.mutex, 0);
+ if (plc.state == PLC_STA_CLOSE) {
+ os_mutex_post(&plc.mutex);
+ return;
+ }
+
+#if 0 //debug
+ static u16 repair_cnt = 0;
+ if (repair) {
+ repair_cnt++;
+ y_printf("[E%d]", repair_cnt);
+ } else {
+ repair_cnt = 0;
+ }
+ //printf("[%d]",point);
+#endif/*debug*/
+
+ repair_flag = repair;
+ if (plc.wideband) {
+ /*
+ *msbc plc deal
+ *如果上一帧是错误,则当前帧也要修复
+ */
+ if (plc.repair) {
+ repair_flag = 1;
+ }
+ plc.repair = repair;
+ }
+
+ while (tmp_point) {
+ repair_point = (tmp_point > PLC_FRAME_LEN) ? PLC_FRAME_LEN : tmp_point;
+ tmp_point = tmp_point - repair_point;
+ PLC_run(p_in, p_out, repair_point, repair_flag);
+ p_in += repair_point;
+ p_out += repair_point;
+ }
+ os_mutex_post(&plc.mutex);
+}
+
+int audio_plc_close(void)
+{
+ PLC_LOG("audio_plc_close\n");
+ os_mutex_pend(&plc.mutex, 0);
+ plc.state = PLC_STA_CLOSE;
+ if (plc.run_buf) {
+ free(plc.run_buf);
+ plc.run_buf = NULL;
+ }
+ os_mutex_post(&plc.mutex);
+ PLC_LOG("audio_plc_close succ\n");
+ return 0;
+}
+#else
+int audio_plc_open(void)
+{
+ return 0;
+}
+
+void audio_plc_run(s16 *dat, u16 len, u8 repair_flag)
+{
+}
+
+int audio_plc_close()
+{
+ return 0;
+}
+#endif/*TCFG_ESCO_PLC*/
diff --git a/apps/common/audio/audio_plc.h b/apps/common/audio/audio_plc.h
new file mode 100644
index 0000000..297c4c1
--- /dev/null
+++ b/apps/common/audio/audio_plc.h
@@ -0,0 +1,10 @@
+#ifndef _AUDIO_PLC_H_
+#define _AUDIO_PLC_H_
+
+#include "generic/typedef.h"
+
+int audio_plc_open(u16 sr);
+void audio_plc_run(s16 *dat, u16 len, u8 repair_flag);
+int audio_plc_close(void);
+
+#endif/*_AUDIO_PLC_H_*/
diff --git a/apps/common/audio/audio_utils.c b/apps/common/audio/audio_utils.c
new file mode 100644
index 0000000..4149966
--- /dev/null
+++ b/apps/common/audio/audio_utils.c
@@ -0,0 +1,28 @@
+/*
+ ************************************************************
+ * Audio Utils
+ *Brief:数字信号处理常用模块合集
+ *Notes:
+ ************************************************************
+ */
+
+#include "audio_utils.h"
+
+/*
+*********************************************************************
+* Audio Digital Phase Inverter
+* Description: 数字反相器,用来反转数字音频信号的相位
+* Arguments : dat 数据buf地址
+* len 数据长度(unit:byte)
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+void digital_phase_inverter_s16(s16 *dat, int len)
+{
+ int data_size = len / 2;
+ for (int i = 0; i < data_size; i++) {
+ dat[i] = (dat[i] == -32768) ? 32767 : -dat[i];
+ }
+}
+
diff --git a/apps/common/audio/audio_utils.h b/apps/common/audio/audio_utils.h
new file mode 100644
index 0000000..e11465a
--- /dev/null
+++ b/apps/common/audio/audio_utils.h
@@ -0,0 +1,18 @@
+#ifndef _AUDIO_UTILS_H_
+#define _AUDIO_UTILS_H_
+
+#include "generic/typedef.h"
+
+/*
+*********************************************************************
+* Audio Digital Phase Inverter
+* Description: 数字反相器,用来反转数字音频信号的相位
+* Arguments : dat 数据buf地址
+* len 数据长度(unit:byte)
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+void digital_phase_inverter_s16(s16 *dat, int len);
+
+#endif/*_AUDIO_UTILS_H_*/
diff --git a/apps/common/audio/decode/audio_key_tone.c b/apps/common/audio/decode/audio_key_tone.c
new file mode 100644
index 0000000..8363cd4
--- /dev/null
+++ b/apps/common/audio/decode/audio_key_tone.c
@@ -0,0 +1,707 @@
+#include "asm/includes.h"
+#include "media/includes.h"
+#include "system/includes.h"
+#include "app_config.h"
+#include "audio_config.h"
+/* #include "audio_dec.h" */
+#include "application/audio_dec_app.h"
+#include "tone_player.h"
+#include "sine_make.h"
+
+#if TCFG_KEY_TONE_EN
+
+// 按键提示音任务名
+#define AUDIO_KEY_TONE_TASK_NAME "key_tone"
+
+// 按键提示音数字音量控制
+#if (SYS_DIGVOL_GROUP_EN && defined(CONFIG_MEDIA_DEVELOP_ENABLE))
+#define AUDIO_KEY_TONE_DIGVOL_EN 0
+#define AUDIO_KEY_TONE_DIGVOL_NAME "key_tone"
+#else
+#define AUDIO_KEY_TONE_DIGVOL_EN 0
+#endif
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+/*
+ * 使用audio_dec_app.h里面的接口,可以实现普通文件、正弦波文件、正弦波数组播放
+ */
+
+// 参数
+struct __key_tone_play_info {
+ const char *file_name; // 文件名
+ struct audio_sin_param *sin; // 正弦波数组
+ u8 sin_num; // 正弦波数组长度
+ u8 preemption; // 1-抢占,0-叠加
+ void (*evt_handler)(void *priv, int flag); // 事件回调
+ void *evt_priv; // 事件回调私有句柄
+};
+
+// 按键提示音
+struct __key_tone {
+ volatile u8 busy; // 任务工作中
+ volatile u8 start; // 运行标志
+ volatile u8 play;
+#if AUDIO_KEY_TONE_DIGVOL_EN
+ u8 volume; // 音量
+#endif
+ struct __key_tone_play_info play_info; // 输入参数
+ struct audio_dec_sine_app_hdl *dec_sin; // 文件播放句柄
+ struct audio_dec_file_app_hdl *dec_file; // sine播放句柄
+ void (*evt_handler)(void *priv, int flag); // 事件回调
+ void *evt_priv; // 事件回调私有句柄
+ const char *evt_owner; // 事件回调所在任务
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+extern struct audio_mixer mixer;
+
+static struct __key_tone *key_tone = NULL;
+
+//////////////////////////////////////////////////////////////////////////////
+
+/*
+*********************************************************************
+* Audio Key Tone Get File Ext Name
+* Description: 获取文件名后缀
+* Arguments : *name 文件名
+* Return : 后缀
+* Note(s) : None.
+*********************************************************************
+*/
+static char *get_file_ext_name(char *name)
+{
+ int len = strlen(name);
+ char *ext = (char *)name;
+
+ while (len--) {
+ if (*ext++ == '.') {
+ break;
+ }
+ }
+ if (len <= 0) {
+ ext = name + (strlen(name) - 3);
+ }
+
+ return ext;
+}
+
+/*
+*********************************************************************
+* Audio Key Tone Post Event
+* Description: 解码事件
+* Arguments : *ktone 按键提示音解码句柄
+* end_flag 结束标志
+* Return : true 成功
+* Note(s) : None.
+*********************************************************************
+*/
+static int key_tone_dec_event_handler(struct __key_tone *ktone, u8 end_flag)
+{
+ int argv[4];
+ if (!ktone->evt_handler) {
+ log_i("evt_handler null\n");
+ return false;
+ }
+ argv[0] = (int)ktone->evt_handler;
+ argv[1] = 2;
+ argv[2] = (int)ktone->evt_priv;
+ argv[3] = (int)end_flag; //0正常关闭,1被打断关闭
+
+ int ret = os_taskq_post_type(ktone->evt_owner, Q_CALLBACK, 4, argv);
+ if (ret) {
+ return false;
+ }
+ return true;
+}
+
+/*
+*********************************************************************
+* Audio Key Tone Reelease
+* Description: 提示音解码器释放
+* Arguments : *ktone 按键提示音解码句柄
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+static void key_tone_dec_hdl_release(struct __key_tone *ktone)
+{
+ if (ktone->dec_file) {
+ audio_dec_file_app_close(ktone->dec_file);
+ ktone->dec_file = NULL;
+ }
+ if (ktone->dec_sin) {
+ audio_dec_sine_app_close(ktone->dec_sin);
+ ktone->dec_sin = NULL;
+ }
+#if (!defined(CONFIG_MEDIA_DEVELOP_ENABLE))
+ app_audio_state_exit(APP_AUDIO_STATE_WTONE);
+#endif
+ /* clock_remove_set(DEC_TONE_CLK); */
+}
+
+/*
+*********************************************************************
+* Audio Key Tone Init OK
+* Description: 解码初始化完成
+* Arguments : *ktone 按键提示音解码句柄
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+static void key_tone_dec_hdl_init_ok(struct __key_tone *ktone)
+{
+#if (!defined(CONFIG_MEDIA_DEVELOP_ENABLE))
+ if (audio_mixer_get_ch_num(&mixer) <= 1) {
+#ifdef TCFG_WTONT_ONCE_VOL
+ extern u8 get_tone_once_vol(void);
+ app_audio_state_switch(APP_AUDIO_STATE_WTONE, get_tone_once_vol());
+#else
+ app_audio_state_switch(APP_AUDIO_STATE_WTONE, get_tone_vol());
+#endif
+ }
+#endif
+ /* clock_add_set(DEC_TONE_CLK); */
+}
+
+/*
+*********************************************************************
+* Audio Key Tone Close
+* Description: 关闭提示音解码
+* Arguments : *ktone 按键提示音解码句柄
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+static void key_tone_play_close(struct __key_tone *ktone)
+{
+ /* log_i("ktone:0x%x, sin:0x%x, file:0x%x \n", ktone, ktone->dec_file, ktone->dec_file); */
+ if (ktone->dec_file || ktone->dec_sin) {
+ key_tone_dec_hdl_release(ktone);
+ key_tone_dec_event_handler(ktone, 1);
+ }
+}
+
+/*
+*********************************************************************
+* Audio Key Tone Event Callback
+* Description: 解码回调处理
+* Arguments : *ktone 按键提示音解码句柄
+* event 事件
+* *param 事件参数
+* Return : 0 正常
+* Note(s) : None.
+*********************************************************************
+*/
+static int key_tone_dec_app_evt_cb(struct __key_tone *ktone, enum audio_dec_app_event event, int *param)
+{
+ switch (event) {
+ case AUDIO_DEC_APP_EVENT_START_INIT_OK:
+ log_i("key_tone start init ok\n");
+ key_tone_dec_hdl_init_ok(ktone);
+ break;
+ case AUDIO_DEC_APP_EVENT_PLAY_END:
+ log_i("key_tone play end\n");
+ key_tone_dec_hdl_release(ktone);
+ key_tone_dec_event_handler(ktone, 0);
+ break;
+
+#if defined(CONFIG_MEDIA_DEVELOP_ENABLE)
+ case AUDIO_DEC_APP_EVENT_STREAM_OPEN: {
+#if AUDIO_KEY_TONE_DIGVOL_EN
+ struct audio_dec_stream_entries_hdl *entries_hdl = (struct audio_dec_stream_entries_hdl *)param;
+ void *dvol_entry = NULL;
+ audio_dig_vol_param temp_digvol_param = {
+ .vol_start = ktone->volume,//get_max_sys_vol(),
+ .vol_max = get_max_sys_vol(),
+ .ch_total = audio_output_channel_num(),
+ .fade_en = 0,
+ .fade_points_step = 5,
+ .fade_gain_step = 10,
+ .vol_list = NULL,
+ };
+ dvol_entry = sys_digvol_group_ch_open(AUDIO_KEY_TONE_DIGVOL_NAME, -1, &temp_digvol_param);
+ (entries_hdl->entries_addr)[entries_hdl->entries_cnt++] = dvol_entry;
+#endif // SYS_DIGVOL_GROUP_EN
+ }
+ break;
+
+ case AUDIO_DEC_APP_EVENT_STREAM_CLOSE: {
+ }
+ break;
+
+#endif /*#if defined(CONFIG_MEDIA_DEVELOP_ENABLE)*/
+
+ case AUDIO_DEC_APP_EVENT_DEC_CLOSE:
+
+#if AUDIO_KEY_TONE_DIGVOL_EN
+ sys_digvol_group_ch_close(AUDIO_KEY_TONE_DIGVOL_NAME);
+#endif // SYS_DIGVOL_GROUP_EN
+
+ break;
+
+ default :
+ break;
+ }
+
+ return 0;
+}
+
+/*
+*********************************************************************
+* Audio Key Tone Sin Event Callback
+* Description: sine提示音解码回调
+* Arguments : *priv 私有句柄
+* event 事件
+* *param 事件参数
+* Return : 0 正常
+* Note(s) : None.
+*********************************************************************
+*/
+static int key_tone_dec_sine_app_evt_cb(void *priv, enum audio_dec_app_event event, int *param)
+{
+ struct audio_dec_sine_app_hdl *sine_dec = priv;
+ struct __key_tone *ktone = sine_dec->priv;
+ switch (event) {
+ case AUDIO_DEC_APP_EVENT_DEC_PROBE:
+ if (sine_dec->sin_maker) {
+ break;
+ }
+ audio_dec_sine_app_probe(sine_dec);
+ if (!sine_dec->sin_maker) {
+ return -ENOENT;
+ }
+ break;
+
+ default :
+ return key_tone_dec_app_evt_cb(ktone, event, param);
+ }
+
+ return 0;
+}
+
+/*
+*********************************************************************
+* Audio Key Tone File Event Callback
+* Description: file提示音解码回调
+* Arguments : *priv 私有句柄
+* event 事件
+* *param 事件参数
+* Return : 0 正常
+* Note(s) : None.
+*********************************************************************
+*/
+static int key_tone_dec_file_app_evt_cb(void *priv, enum audio_dec_app_event event, int *param)
+{
+ struct audio_dec_file_app_hdl *file_dec = priv;
+ struct __key_tone *ktone = file_dec->priv;
+ switch (event) {
+ case AUDIO_DEC_APP_EVENT_DEC_PROBE:
+ break;
+ default :
+ return key_tone_dec_app_evt_cb(ktone, event, param);
+ }
+
+ return 0;
+}
+
+/*
+*********************************************************************
+* Audio Key Tone Run
+* Description: 按键提示音运行
+* Arguments : *ktone 按键提示音解码句柄
+* Return : 0 正常
+* Note(s) : None.
+*********************************************************************
+*/
+static int key_tone_play_run(struct __key_tone *ktone)
+{
+ if (!ktone->start) {
+ return -1;
+ }
+
+ struct __key_tone_play_info info = {0};
+ local_irq_disable();
+ if (!ktone->play) {
+ local_irq_enable();
+ return 0;
+ }
+ // 保存播放参数
+ memcpy(&info, &ktone->play_info, sizeof(struct __key_tone_play_info));
+ ktone->play = 0;
+ local_irq_enable();
+
+ // 关闭现有play
+ key_tone_play_close(ktone);
+
+ // 设置参数
+ ktone->evt_handler = info.evt_handler;
+ ktone->evt_priv = info.evt_priv;
+ ktone->evt_owner = "app_core";
+
+ // 正弦波数组播放
+ if (info.sin && info.sin_num) {
+ ktone->dec_sin = audio_dec_sine_app_create_by_parm(info.sin, info.sin_num, !info.preemption);
+ if (ktone->dec_sin == NULL) {
+ return -1;
+ }
+ ktone->dec_sin->dec->evt_cb = key_tone_dec_sine_app_evt_cb;
+ ktone->dec_sin->priv = ktone;
+ /* audio_dec_sine_app_open(ktone->dec_sin); */
+ ktone->dec_sin->dec->wait.only_del = 1;
+ audio_dec_app_start(ktone->dec_sin->dec);
+ return 0;
+ }
+
+ // 判断文件名后缀
+ u8 file_name[16];
+ char *format = NULL;
+ FILE *file = fopen(info.file_name, "r");
+ if (!file) {
+ return -1;
+ }
+ fget_name(file, file_name, 16);
+ format = get_file_ext_name((char *)file_name);
+ fclose(file);
+
+ // 正弦波文件播放
+ if (ASCII_StrCmpNoCase(format, "sin", 3) == 0) {
+ ktone->dec_sin = audio_dec_sine_app_create(info.file_name, !info.preemption);
+ if (ktone->dec_sin == NULL) {
+ return -1;
+ }
+ ktone->dec_sin->dec->evt_cb = key_tone_dec_sine_app_evt_cb;
+ ktone->dec_sin->priv = ktone;
+ /* audio_dec_sine_app_open(ktone->dec_sin); */
+ ktone->dec_sin->dec->wait.only_del = 1;
+ audio_dec_app_start(ktone->dec_sin->dec);
+ return 0;
+ }
+
+ // 普通文件播放
+ ktone->dec_file = audio_dec_file_app_create(info.file_name, !info.preemption);
+ if (ktone->dec_file == NULL) {
+ return -1;
+ }
+ if (ktone->dec_file->dec->dec_type == AUDIO_CODING_SBC) {
+ audio_dec_app_set_frame_info(ktone->dec_file->dec, 0x4e, ktone->dec_file->dec->dec_type);
+ }
+ ktone->dec_file->dec->evt_cb = key_tone_dec_file_app_evt_cb;
+ ktone->dec_file->priv = ktone;
+ /* audio_dec_file_app_open(ktone->dec_file); */
+ ktone->dec_file->dec->wait.only_del = 1;
+ audio_dec_app_start(ktone->dec_file->dec);
+ return 0;
+}
+
+/*
+*********************************************************************
+* Audio Key Tone Task Run
+* Description: 按键提示音任务处理
+* Arguments : *p 按键提示音解码句柄
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+static void key_tone_task_deal(void *p)
+{
+ int res = 0;
+ int msg[16];
+ struct __key_tone *ktone = (struct __key_tone *)p;
+ ktone->start = 1;
+ ktone->busy = 1;
+ while (1) {
+ os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
+ res = key_tone_play_run(ktone);
+ if (res) {
+ ///等待删除线程
+ key_tone_play_close(ktone);
+ ktone->busy = 0;
+ while (1) {
+ os_time_dly(10000);
+ }
+ }
+ }
+}
+
+/*
+*********************************************************************
+* Audio Key Tone Destroy
+* Description: 注销按键提示音播放
+* Arguments : None.
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+void audio_key_tone_destroy(void)
+{
+ if (!key_tone) {
+ return ;
+ }
+
+ key_tone->start = 0;
+
+ while (key_tone->busy) {
+ os_taskq_post_msg(AUDIO_KEY_TONE_TASK_NAME, 1, 0);
+ os_time_dly(1);
+ }
+
+ task_kill(AUDIO_KEY_TONE_TASK_NAME);
+
+ local_irq_disable();
+ free(key_tone);
+ key_tone = NULL;
+ local_irq_enable();
+}
+
+/*
+*********************************************************************
+* Audio Key Tone Init
+* Description: 按键提示音初始化
+* Arguments : None.
+* Return : true 成功
+* Note(s) : None.
+*********************************************************************
+*/
+int audio_key_tone_init(void)
+{
+ int err = 0;
+ if (key_tone) {
+ return true;
+ }
+ struct __key_tone *ktone = zalloc(sizeof(struct __key_tone));
+ err = task_create(key_tone_task_deal, (void *)ktone, AUDIO_KEY_TONE_TASK_NAME);
+ if (err != OS_NO_ERR) {
+ log_e("%s creat fail %x\n", __FUNCTION__, err);
+ free(ktone);
+ return false;
+ }
+#if AUDIO_KEY_TONE_DIGVOL_EN
+ ktone->volume = get_max_sys_vol();
+#endif
+ key_tone = ktone;
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// 正弦波序号
+#define KTONE_SINE_NORAML 0
+
+// 按键提示音序号
+enum {
+ KTONE_IDEX_NORAML = 0,
+ KTONE_IDEX_NUM_0,
+ KTONE_IDEX_NUM_1,
+
+ KTONE_IDEX_MAX,
+};
+
+// 序号对应表
+static const char *const key_tone_index[] = {
+ [KTONE_IDEX_NORAML] = DEFAULT_SINE_TONE(KTONE_SINE_NORAML),
+ [KTONE_IDEX_NUM_0] = SDFILE_RES_ROOT_PATH"tone/0.*",
+ [KTONE_IDEX_NUM_1] = SDFILE_RES_ROOT_PATH"tone/1.*",
+};
+
+/*
+ * 正弦波参数配置:
+ * freq : 实际频率 * 512
+ * points : 正弦波点数
+ * win : 正弦窗
+ * decay : 衰减系数(百分比), 正弦窗模式下为频率设置:频率*512
+ */
+static const struct sin_param sine_16k_normal[] = {
+ /*{0, 1000, 0, 100},*/
+ {200 << 9, 4000, 0, 100},
+};
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+/*
+*********************************************************************
+* Audio Key Tone Get Sine Param Data
+* Description: 获取正弦波数组
+* Arguments : id 正弦波序号
+* *num 正弦波数组长度
+* Return : 正弦波数组
+* Note(s) : None.
+*********************************************************************
+*/
+static const struct sin_param *get_sine_param_data(u8 id, u8 *num)
+{
+ const struct sin_param *param_data = NULL;
+ switch (id) {
+ case KTONE_SINE_NORAML:
+ param_data = sine_16k_normal;
+ *num = ARRAY_SIZE(sine_16k_normal);
+ break;
+ default:
+ return NULL;
+ }
+ return param_data;
+};
+
+/*
+*********************************************************************
+* Audio Key Tone Open With Callback
+* Description: 打开文件播放
+* Arguments : *file_name 文件名
+* *sin 正弦波数组
+* sin_num 正弦波数组长度
+* preemption 1-抢断播放;0-叠加播放
+* evt_handler 事件回调
+* evt_priv 事件回调参数
+* Return : 0 正常
+* Note(s) : None.
+*********************************************************************
+*/
+static int ktone_play_open_with_callback_base(const char *file_name, struct audio_sin_param *sin, u8 sin_num, u8 preemption, void (*evt_handler)(void *priv, int flag), void *evt_priv)
+{
+ struct __key_tone *ktone = key_tone;
+ if ((!ktone) || (!ktone->start)) {
+ return -1;
+ }
+
+ struct __key_tone_play_info info = {0};
+ info.preemption = preemption;
+ info.evt_handler = evt_handler;
+ info.evt_priv = evt_priv;
+ if (sin && sin_num) {
+ info.sin = sin;
+ info.sin_num = sin_num;
+ } else {
+ info.file_name = file_name;
+ if (IS_DEFAULT_SINE(file_name)) {
+ info.sin = get_sine_param_data(DEFAULT_SINE_ID(file_name), &info.sin_num);
+ }
+ }
+
+ local_irq_disable();
+ memcpy(&ktone->play_info, &info, sizeof(struct __key_tone_play_info));
+ ktone->play = 1;
+ local_irq_enable();
+
+ os_taskq_post_msg(AUDIO_KEY_TONE_TASK_NAME, 1, 0);
+
+ return 0;
+}
+
+/*
+*********************************************************************
+* Audio Key Tone Play Sine
+* Description: 播放正弦波数组
+* Arguments : *sin 正弦波数组
+* sin_num 正弦波数组长度
+* preemption 1-抢断播放;0-叠加播放
+* Return : 0 正常
+* Note(s) : None.
+*********************************************************************
+*/
+int audio_key_tone_play_sin(struct audio_sin_param *sin, u8 sin_num, u8 preemption)
+{
+ /* y_printf("n:0x%x \n", name); */
+ return ktone_play_open_with_callback_base(NULL, sin, sin_num, preemption, NULL, NULL);
+}
+
+/*
+*********************************************************************
+* Audio Key Tone Play File
+* Description: 播放文件
+* Arguments : *name 文件名
+* preemption 1-抢断播放;0-叠加播放
+* Return : 0 正常
+* Note(s) : None.
+*********************************************************************
+*/
+int audio_key_tone_play_name(const char *name, u8 preemption)
+{
+ /* y_printf("n:0x%x \n", name); */
+ return ktone_play_open_with_callback_base(name, NULL, 0, preemption, NULL, NULL);
+}
+
+/*
+*********************************************************************
+* Audio Key Tone Play Index
+* Description: 按序号播放文件
+* Arguments : index 序号
+* preemption 1-抢断播放;0-叠加播放
+* Return : 0 正常
+* Note(s) : 使用key_tone_index[]数组
+*********************************************************************
+*/
+int audio_key_tone_play_index(u8 index, u8 preemption)
+{
+ if (index >= KTONE_IDEX_MAX) {
+ return -1;
+ }
+ return audio_key_tone_play_name(key_tone_index[index], preemption);
+}
+
+/*
+*********************************************************************
+* Audio Key Tone Play
+* Description: 按键提示音播放
+* Arguments : None.
+* Return : None.
+* Note(s) : 默认播放
+*********************************************************************
+*/
+void audio_key_tone_play(void)
+{
+ audio_key_tone_play_index(KTONE_IDEX_NORAML, 0);
+ /* audio_key_tone_play_index(KTONE_IDEX_NUM_0, 0); */
+ /* audio_key_tone_play_sin(sine_16k_normal, ARRAY_SIZE(sine_16k_normal), 0); */
+}
+
+/*
+*********************************************************************
+* Audio Key Tone Check Play
+* Description: 检测按键提示音是否在播放
+* Arguments : None.
+* Return : true 正在播放
+* Note(s) : None.
+*********************************************************************
+*/
+int audio_key_tone_is_play(void)
+{
+ if ((!key_tone) || (!key_tone->start)) {
+ return false;
+ }
+ if (key_tone->dec_file || key_tone->dec_sin) {
+ return true;
+ }
+ return false;
+}
+
+/*
+*********************************************************************
+* Audio Key Tone Set Digvol
+* Description: 设置按键提示音的音量
+* Arguments : volume 音量
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+void audio_key_tone_digvol_set(u8 volume)
+{
+#if AUDIO_KEY_TONE_DIGVOL_EN
+ log_i("vol:%d \n", volume);
+ if (!key_tone) {
+ return ;
+ }
+ key_tone->volume = volume;
+ void *vol_hdl = audio_dig_vol_group_hdl_get(sys_digvol_group, AUDIO_KEY_TONE_DIGVOL_NAME);
+ if (vol_hdl == NULL) {
+ return;
+ }
+ audio_dig_vol_set(vol_hdl, AUDIO_DIG_VOL_ALL_CH, volume);
+#endif
+}
+
+
+#endif
+
diff --git a/apps/common/audio/decode/decode.c b/apps/common/audio/decode/decode.c
new file mode 100644
index 0000000..0932cc9
--- /dev/null
+++ b/apps/common/audio/decode/decode.c
@@ -0,0 +1,325 @@
+
+#include "application/audio_dec_app.h"
+#include "app_config.h"
+#include "audio_config.h"
+#include "app_main.h"
+
+
+//////////////////////////////////////////////////////////////////////////////
+extern struct audio_decoder_task decode_task;
+extern struct audio_mixer mixer;
+extern struct audio_dac_hdl dac_hdl;
+#if AUDIO_DAC_MULTI_CHANNEL_ENABLE
+extern struct audio_dac_channel default_dac;
+#endif
+
+extern const int audio_dec_app_mix_en;
+
+extern u32 audio_output_channel_num(void);
+
+//////////////////////////////////////////////////////////////////////////////
+struct audio_dec_app_audio_state_hdl {
+ struct audio_mixer *p_mixer;
+ u32 dec_mix : 1; // 1:叠加模式
+ u32 flag;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+const struct audio_dec_format_hdl decode_format_list[] = {
+ {"wtg", AUDIO_CODING_G729},
+ {"msbc", AUDIO_CODING_MSBC},
+ {"msb", AUDIO_CODING_MSBC},
+ {"sbc", AUDIO_CODING_SBC},
+ {"mty", AUDIO_CODING_MTY},
+ {"aac", AUDIO_CODING_AAC},
+ {"mp3", AUDIO_CODING_MP3},
+ {"wma", AUDIO_CODING_WMA},
+ {"wav", AUDIO_CODING_WAV},
+#if (defined(TCFG_DEC_MIDI_ENABLE) && TCFG_DEC_MIDI_ENABLE)
+ //midi 文件播放,需要对应音色文件配合
+ {"midi", AUDIO_CODING_MIDI},
+ {"mid", AUDIO_CODING_MIDI},
+#endif //TCFG_DEC_MIDI_ENABLE
+
+#if TCFG_DEC_WTGV2_ENABLE
+ {"wts", AUDIO_CODING_WTGV2},
+#endif
+ {"speex", AUDIO_CODING_SPEEX},
+ {"opus", AUDIO_CODING_OPUS},
+ {0, 0},
+};
+
+#if defined(CONFIG_MEDIA_DEVELOP_ENABLE)
+static struct audio_stream_entry *audio_dec_app_entries[2] = {NULL};
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+
+/*----------------------------------------------------------------------------*/
+/**@brief 解码创建参数初始化
+ @param *dec: 解码句柄
+ @return 0-正常
+ @note 弱函数重定义
+*/
+/*----------------------------------------------------------------------------*/
+int audio_dec_app_create_param_init(struct audio_dec_app_hdl *dec)
+{
+ dec->p_decode_task = &decode_task;
+#if defined(CONFIG_MEDIA_DEVELOP_ENABLE)
+ if (!audio_dec_app_mix_en) {
+#if AUDIO_DAC_MULTI_CHANNEL_ENABLE
+ audio_dec_app_entries[0] = &default_dac.entry;
+#else
+ audio_dec_app_entries[0] = &dac_hdl.entry;
+#endif
+ dec->entries = audio_dec_app_entries;
+ } else
+#endif
+ {
+ dec->p_mixer = &mixer;
+ }
+#if defined(CONFIG_MEDIA_DEVELOP_ENABLE)
+ u8 dac_connect_mode = app_audio_output_mode_get();
+ if (dac_connect_mode == DAC_OUTPUT_FRONT_LR_REAR_LR) {
+ dec->out_ch_num = 4;
+ } else {
+ dec->out_ch_num = audio_output_channel_num();
+ }
+#else
+ u8 dac_connect_mode = audio_dac_get_channel(&dac_hdl);
+ switch (dac_connect_mode) {
+ /* case DAC_OUTPUT_DUAL_LR_DIFF: */
+ case DAC_OUTPUT_LR:
+ dec->out_ch_num = 2;
+ break;
+ /* case DAC_OUTPUT_FRONT_LR_REAR_LR: */
+ /* dec->out_ch_num = 4; */
+ /* break; */
+ default :
+ dec->out_ch_num = 1;
+ break;
+ }
+#endif
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 文件解码创建参数初始化
+ @param *file_dec: 文件解码句柄
+ @return 0-正常
+ @note 弱函数重定义
+*/
+/*----------------------------------------------------------------------------*/
+int audio_dec_file_app_create_param_init(struct audio_dec_file_app_hdl *file_dec)
+{
+ file_dec->format = (struct audio_dec_format_hdl *)decode_format_list;
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 解码输出状态设置
+ @param *dec: 解码句柄
+ @param flag: 解码标签
+ @return 0-正常
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+int audio_dec_app_audio_state_switch(struct audio_dec_app_hdl *dec, u32 flag)
+{
+ u8 need_set_audio = 1;
+ /* if ((dec->dec_mix) && (audio_mixer_get_ch_num(dec->p_mixer) > 1)) { */
+ /* need_set_audio = 0; */
+ /* } */
+ if (app_audio_get_state() == APP_AUDIO_STATE_IDLE) {
+ need_set_audio = 1;
+ }
+ if (need_set_audio) {
+ if (flag == AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MUSIC) {
+ app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
+ } else {
+#ifdef TCFG_WTONT_ONCE_VOL
+ extern u8 get_tone_once_vol(void);
+ app_audio_state_switch(APP_AUDIO_STATE_WTONE, get_tone_once_vol());
+#else
+ app_audio_state_switch(APP_AUDIO_STATE_WTONE, get_tone_vol());
+#endif
+ }
+ }
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 解码输出状态退出
+ @param *p_aud_state: 输出状态
+ @return 0-正常
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+int audio_dec_app_audio_state_exit(struct audio_dec_app_audio_state_hdl *p_aud_state)
+{
+ u8 need_set_audio = 1;
+ /* if ((p_aud_state->dec_mix) && (audio_mixer_get_ch_num(p_aud_state->p_mixer) > 1)) { */
+ /* need_set_audio = 0; */
+ /* } */
+ /* if (app_audio_get_state() == APP_AUDIO_STATE_IDLE) { */
+ /* need_set_audio = 1; */
+ /* } */
+ if (need_set_audio) {
+ if (p_aud_state->flag == AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MUSIC) {
+ app_audio_state_exit(APP_AUDIO_STATE_MUSIC);
+ } else {
+ app_audio_state_exit(APP_AUDIO_STATE_WTONE);
+ }
+ }
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 文件解码初始化完成
+ @param *file_dec: 文件解码句柄
+ @return 0-正常
+ @note 弱函数重定义
+*/
+/*----------------------------------------------------------------------------*/
+int audio_dec_file_app_init_ok(struct audio_dec_file_app_hdl *file_dec)
+{
+ audio_dec_app_audio_state_switch(file_dec->dec, file_dec->flag & AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MASK);
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 文件解码结束
+ @param *file_dec: 文件解码句柄
+ @return 0-正常
+ @note 弱函数重定义
+*/
+/*----------------------------------------------------------------------------*/
+int audio_dec_file_app_play_end(struct audio_dec_file_app_hdl *file_dec)
+{
+ struct audio_dec_app_audio_state_hdl aud_state = {0};
+ aud_state.p_mixer = file_dec->dec->p_mixer;
+ aud_state.dec_mix = file_dec->dec->dec_mix;
+ aud_state.flag = file_dec->flag & AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MASK;
+ audio_dec_file_app_close(file_dec);
+ audio_dec_app_audio_state_exit(&aud_state);
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 正弦波解码初始化完成
+ @param *sine_dec: 正弦波解码句柄
+ @return 0-正常
+ @note 弱函数重定义
+*/
+/*----------------------------------------------------------------------------*/
+int audio_dec_sine_app_init_ok(struct audio_dec_sine_app_hdl *sine_dec)
+{
+ audio_dec_app_audio_state_switch(sine_dec->dec, sine_dec->flag & AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MASK);
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+/**@brief 正弦波解码结束
+ @param *sine_dec: 正弦波解码句柄
+ @return 0-正常
+ @note 弱函数重定义
+*/
+/*----------------------------------------------------------------------------*/
+int audio_dec_sine_app_play_end(struct audio_dec_sine_app_hdl *sine_dec)
+{
+ struct audio_dec_app_audio_state_hdl aud_state = {0};
+ aud_state.p_mixer = sine_dec->dec->p_mixer;
+ aud_state.dec_mix = sine_dec->dec->dec_mix;
+ aud_state.flag = sine_dec->flag & AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MASK;
+ audio_dec_sine_app_close(sine_dec);
+ audio_dec_app_audio_state_exit(&aud_state);
+ return 0;
+}
+
+#if (!defined(CONFIG_MEDIA_DEVELOP_ENABLE))
+void audio_dec_app_output_sr_set(struct audio_dec_app_hdl *dec)
+{
+ /* #if defined(CONFIG_CPU_BR23) */
+ /* extern u32 audio_output_rate(int input_rate); */
+ /* dec->src_out_sr = audio_output_rate(dec->src_out_sr); */
+ /* #endif */
+ if (dec->src_out_sr == 0) {
+ dec->src_out_sr = audio_dac_get_sample_rate(&dac_hdl);
+ if (dec->src_out_sr == 0) {
+ dec->src_out_sr = 16000;
+ log_w("src out is zero \n");
+ }
+ }
+ if (dec->sample_rate == 0) {
+ dec->sample_rate = dec->src_out_sr;
+ }
+}
+#endif
+
+
+//////////////////////////////////////////////////////////////////////////////
+// test
+#if 0
+#include "tone_player.h"
+
+void audio_dec_file_test(void)
+{
+ struct audio_dec_file_app_hdl *hdl;
+ hdl = audio_dec_file_app_create(TONE_POWER_ON, 1);
+ if (hdl) {
+ audio_dec_file_app_open(hdl);
+ }
+ os_time_dly(2);
+ hdl = audio_dec_file_app_create(TONE_POWER_OFF, 1);
+ if (hdl) {
+ audio_dec_file_app_open(hdl);
+ }
+ os_time_dly(300);
+}
+
+static const struct audio_sin_param sine_test[] = {
+ /*{0, 1000, 0, 100},*/
+ {200 << 9, 4000, 0, 100},
+};
+static const struct audio_sin_param sine_test1[] = {
+ {450 << 9, 24960, 1, 16.667 * 512},
+ {0, 16000, 0, 100},
+};
+void audio_dec_sine_test(void)
+{
+ struct audio_dec_sine_app_hdl *hdl;
+ /* hdl = audio_dec_sine_app_create(SDFILE_RES_ROOT_PATH"tone/vol_max.sin", 1); */
+ hdl = audio_dec_sine_app_create_by_parm(sine_test1, ARRAY_SIZE(sine_test1), 1);
+ if (hdl) {
+ audio_dec_sine_app_open(hdl);
+ }
+ os_time_dly(2);
+ hdl = audio_dec_sine_app_create_by_parm(sine_test, ARRAY_SIZE(sine_test), 1);
+ if (hdl) {
+ audio_dec_sine_app_open(hdl);
+ }
+ /* os_time_dly(300); */
+}
+
+void audio_dec_usb_file_test(void)
+{
+ tone_play_stop();
+ clk_set("sys", 192 * 1000000L);
+
+ struct audio_dec_file_app_hdl *hdl;
+ /* hdl = audio_dec_file_app_create("storage/udisk/C/1.mp3", 1); */
+ hdl = audio_dec_file_app_create("storage/udisk/C/1.wav", 1);
+ if (hdl) {
+ audio_dec_file_app_open(hdl);
+ }
+ os_time_dly(2);
+ /* hdl = audio_dec_file_app_create("storage/udisk/C/2.mp3", 1); */
+ hdl = audio_dec_file_app_create("storage/udisk/C/2.wav", 1);
+ if (hdl) {
+ audio_dec_file_app_open(hdl);
+ }
+ os_time_dly(300);
+}
+
+#endif /*test*/
+
+
diff --git a/apps/common/audio/sine_make.c b/apps/common/audio/sine_make.c
new file mode 100644
index 0000000..5dc9efe
--- /dev/null
+++ b/apps/common/audio/sine_make.c
@@ -0,0 +1,410 @@
+/*****************************************************************
+>file name : apps/common/sine_make.c
+>author : lichao
+>create time : Sun 05 May 2019 08:37:35 PM CST
+*****************************************************************/
+#include "system/includes.h"
+#include "sine_make.h"
+
+#define SINE_USE_MALLOC 1
+
+struct audio_sin_maker {
+ u8 open;
+ u8 id;
+ u8 sin_num;
+ u8 channel;
+ u8 repeat;
+ u8 next_param;
+ u16 fade_points;
+ /*int sample_rate;*/
+ int volume;
+ int points;
+ int sin_index;
+ int win_sin_index;
+ const struct sin_param *sin;
+};
+
+#ifndef SINE_USE_MALLOC
+static struct audio_sin_maker sin_maker_handle;
+#endif
+
+void *sin_tone_open(const struct sin_param *param, int num, u8 channel, u8 repeat)
+{
+ if (!param || !num) {
+ return NULL;
+ }
+
+#ifdef SINE_USE_MALLOC
+ struct audio_sin_maker *sin = zalloc(sizeof(struct audio_sin_maker));
+#else
+ struct audio_sin_maker *sin = &sin_maker_handle;
+#endif
+
+ if (!sin) {
+ return NULL;
+ }
+ if (sin->open) {
+ return NULL;
+ }
+
+ sin->sin = param;
+ sin->sin_num = num;
+ sin->open = 1;
+ sin->points = param[0].points;
+ sin->id = 0;
+ sin->channel = channel;
+ sin->repeat = repeat;
+#if (defined CONFIG_CPU_BR18 || \
+ defined CONFIG_CPU_BR21)
+ /*这里如果加多fade points,会导致结束的时候有噪声,不是在淡出尾部*/
+ sin->fade_points = 0;
+#else
+ sin->fade_points = 480;
+#endif
+ sin->next_param = 1;
+
+ return (void *)sin;
+}
+#if !defined(SINE_MAKE_IN_MASK)
+const int sf_sin_tab1[513] = {
+ 0x00000000, 0x0000c910, 0x0001921f, 0x00025b2d, 0x0003243a, 0x0003ed45, 0x0004b64e, 0x00057f53,
+ 0x00064855, 0x00071154, 0x0007da4e, 0x0008a343, 0x00096c33, 0x000a351d, 0x000afe00, 0x000bc6dd,
+ 0x000c8fb3, 0x000d5881, 0x000e2147, 0x000eea03, 0x000fb2b7, 0x00107b61, 0x00114401, 0x00120c96,
+ 0x0012d521, 0x00139d9f, 0x00146611, 0x00152e77, 0x0015f6d0, 0x0016bf1b, 0x00178758, 0x00184f87,
+ 0x001917a7, 0x0019dfb7, 0x001aa7b7, 0x001b6fa7, 0x001c3786, 0x001cff53, 0x001dc70f, 0x001e8eb8,
+ 0x001f564e, 0x00201dd1, 0x0020e541, 0x0021ac9b, 0x002273e2, 0x00233b13, 0x0024022e, 0x0024c933,
+ 0x00259021, 0x002656f8, 0x00271db7, 0x0027e45f, 0x0028aaed, 0x00297163, 0x002a37bf, 0x002afe01,
+ 0x002bc429, 0x002c8a35, 0x002d5026, 0x002e15fb, 0x002edbb4, 0x002fa14f, 0x003066ce, 0x00312c2e,
+ 0x0031f170, 0x0032b694, 0x00337b98, 0x0034407c, 0x00350540, 0x0035c9e4, 0x00368e66, 0x003752c6,
+ 0x00381705, 0x0038db21, 0x00399f19, 0x003a62ef, 0x003b26a0, 0x003bea2c, 0x003cad94, 0x003d70d7,
+ 0x003e33f3, 0x003ef6e9, 0x003fb9b8, 0x00407c60, 0x00413ee0, 0x00420138, 0x0042c367, 0x0043856d,
+ 0x0044474a, 0x004508fc, 0x0045ca83, 0x00468be0, 0x00474d11, 0x00480e16, 0x0048ceef, 0x00498f9a,
+ 0x004a5019, 0x004b1069, 0x004bd08b, 0x004c907f, 0x004d5043, 0x004e0fd8, 0x004ecf3c, 0x004f8e70,
+ 0x00504d72, 0x00510c43, 0x0051cae3, 0x0052894f, 0x00534789, 0x0054058f, 0x0054c362, 0x00558100,
+ 0x00563e6a, 0x0056fb9e, 0x0057b89d, 0x00587565, 0x005931f7, 0x0059ee52, 0x005aaa76, 0x005b6662,
+ 0x005c2215, 0x005cdd8f, 0x005d98d0, 0x005e53d8, 0x005f0ea5, 0x005fc937, 0x0060838f, 0x00613dab,
+ 0x0061f78b, 0x0062b12e, 0x00636a95, 0x006423be, 0x0064dcaa, 0x00659557, 0x00664dc6, 0x006705f5,
+ 0x0067bde5, 0x00687595, 0x00692d05, 0x0069e433, 0x006a9b21, 0x006b51cc, 0x006c0836, 0x006cbe5c,
+ 0x006d7440, 0x006e29e0, 0x006edf3d, 0x006f9454, 0x00704927, 0x0070fdb5, 0x0071b1fd, 0x007265ff,
+ 0x007319ba, 0x0073cd2f, 0x0074805c, 0x00753341, 0x0075e5dd, 0x00769831, 0x00774a3c, 0x0077fbfe,
+ 0x0078ad75, 0x00795ea2, 0x007a0f84, 0x007ac01a, 0x007b7065, 0x007c2064, 0x007cd016, 0x007d7f7c,
+ 0x007e2e93, 0x007edd5d, 0x007f8bd9, 0x00803a06, 0x0080e7e4, 0x00819573, 0x008242b1, 0x0082ef9f,
+ 0x00839c3d, 0x00844889, 0x0084f484, 0x0085a02c, 0x00864b82, 0x0086f686, 0x0087a136, 0x00884b92,
+ 0x0088f59b, 0x00899f4e, 0x008a48ad, 0x008af1b7, 0x008b9a6b, 0x008c42c9, 0x008cead0, 0x008d9281,
+ 0x008e39da, 0x008ee0db, 0x008f8784, 0x00902dd5, 0x0090d3cd, 0x0091796b, 0x00921eb0, 0x0092c39a,
+ 0x0093682a, 0x00940c5f, 0x0094b039, 0x009553b7, 0x0095f6d9, 0x0096999f, 0x00973c07, 0x0097de12,
+ 0x00987fc0, 0x0099210f, 0x0099c200, 0x009a6293, 0x009b02c6, 0x009ba299, 0x009c420c, 0x009ce11f,
+ 0x009d7fd1, 0x009e1e22, 0x009ebc12, 0x009f599f, 0x009ff6cb, 0x00a09393, 0x00a12ff9, 0x00a1cbfb,
+ 0x00a26799, 0x00a302d3, 0x00a39da9, 0x00a4381a, 0x00a4d225, 0x00a56bcb, 0x00a6050a, 0x00a69de3,
+ 0x00a73656, 0x00a7ce61, 0x00a86605, 0x00a8fd41, 0x00a99415, 0x00aa2a80, 0x00aac082, 0x00ab561b,
+ 0x00abeb4a, 0x00ac800f, 0x00ad1469, 0x00ada859, 0x00ae3bde, 0x00aecef7, 0x00af61a5, 0x00aff3e6,
+ 0x00b085bb, 0x00b11722, 0x00b1a81d, 0x00b238aa, 0x00b2c8c9, 0x00b3587a, 0x00b3e7bc, 0x00b4768f,
+ 0x00b504f3, 0x00b592e7, 0x00b6206c, 0x00b6ad7f, 0x00b73a23, 0x00b7c655, 0x00b85216, 0x00b8dd65,
+ 0x00b96842, 0x00b9f2ac, 0x00ba7ca4, 0x00bb0629, 0x00bb8f3b, 0x00bc17d9, 0x00bca003, 0x00bd27b8,
+ 0x00bdaef9, 0x00be35c5, 0x00bebc1b, 0x00bf41fc, 0x00bfc767, 0x00c04c5c, 0x00c0d0da, 0x00c154e1,
+ 0x00c1d870, 0x00c25b89, 0x00c2de29, 0x00c36051, 0x00c3e200, 0x00c46337, 0x00c4e3f5, 0x00c56439,
+ 0x00c5e403, 0x00c66354, 0x00c6e22a, 0x00c76085, 0x00c7de65, 0x00c85bca, 0x00c8d8b3, 0x00c95521,
+ 0x00c9d112, 0x00ca4c87, 0x00cac77f, 0x00cb41fa, 0x00cbbbf8, 0x00cc3578, 0x00ccae79, 0x00cd26fd,
+ 0x00cd9f02, 0x00ce1689, 0x00ce8d90, 0x00cf0417, 0x00cf7a1f, 0x00cfefa8, 0x00d064af, 0x00d0d937,
+ 0x00d14d3d, 0x00d1c0c2, 0x00d233c6, 0x00d2a649, 0x00d31849, 0x00d389c7, 0x00d3fac3, 0x00d46b3b,
+ 0x00d4db31, 0x00d54aa4, 0x00d5b993, 0x00d627fe, 0x00d695e5, 0x00d70348, 0x00d77026, 0x00d7dc7f,
+ 0x00d84853, 0x00d8b3a1, 0x00d91e6a, 0x00d988ad, 0x00d9f26a, 0x00da5ba0, 0x00dac450, 0x00db2c79,
+ 0x00db941a, 0x00dbfb34, 0x00dc61c7, 0x00dcc7d1, 0x00dd2d53, 0x00dd924d, 0x00ddf6be, 0x00de5aa6,
+ 0x00debe05, 0x00df20db, 0x00df8327, 0x00dfe4e9, 0x00e04621, 0x00e0a6cf, 0x00e106f2, 0x00e1668a,
+ 0x00e1c598, 0x00e2241a, 0x00e28210, 0x00e2df7b, 0x00e33c5a, 0x00e398ac, 0x00e3f473, 0x00e44fac,
+ 0x00e4aa59, 0x00e50479, 0x00e55e0b, 0x00e5b710, 0x00e60f88, 0x00e66771, 0x00e6becc, 0x00e71599,
+ 0x00e76bd8, 0x00e7c187, 0x00e816a8, 0x00e86b39, 0x00e8bf3c, 0x00e912ae, 0x00e96591, 0x00e9b7e4,
+ 0x00ea09a7, 0x00ea5ad9, 0x00eaab7b, 0x00eafb8c, 0x00eb4b0c, 0x00eb99fb, 0x00ebe858, 0x00ec3624,
+ 0x00ec835e, 0x00ecd007, 0x00ed1c1d, 0x00ed67a1, 0x00edb293, 0x00edfcf2, 0x00ee46be, 0x00ee8ff8,
+ 0x00eed89e, 0x00ef20b0, 0x00ef6830, 0x00efaf1b, 0x00eff573, 0x00f03b37, 0x00f08066, 0x00f0c501,
+ 0x00f10908, 0x00f14c7a, 0x00f18f57, 0x00f1d19f, 0x00f21352, 0x00f25470, 0x00f294f8, 0x00f2d4eb,
+ 0x00f31447, 0x00f3530e, 0x00f3913f, 0x00f3ced9, 0x00f40bdd, 0x00f4484b, 0x00f48422, 0x00f4bf62,
+ 0x00f4fa0b, 0x00f5341d, 0x00f56d97, 0x00f5a67b, 0x00f5dec6, 0x00f6167a, 0x00f64d97, 0x00f6841b,
+ 0x00f6ba07, 0x00f6ef5b, 0x00f72417, 0x00f7583a, 0x00f78bc5, 0x00f7beb7, 0x00f7f110, 0x00f822d1,
+ 0x00f853f8, 0x00f88486, 0x00f8b47b, 0x00f8e3d6, 0x00f91298, 0x00f940c0, 0x00f96e4e, 0x00f99b43,
+ 0x00f9c79d, 0x00f9f35e, 0x00fa1e84, 0x00fa4910, 0x00fa7302, 0x00fa9c59, 0x00fac516, 0x00faed37,
+ 0x00fb14be, 0x00fb3bab, 0x00fb61fc, 0x00fb87b2, 0x00fbaccd, 0x00fbd14d, 0x00fbf531, 0x00fc187a,
+ 0x00fc3b28, 0x00fc5d3a, 0x00fc7eb0, 0x00fc9f8a, 0x00fcbfc9, 0x00fcdf6c, 0x00fcfe73, 0x00fd1cdd,
+ 0x00fd3aac, 0x00fd57de, 0x00fd7474, 0x00fd906e, 0x00fdabcc, 0x00fdc68c, 0x00fde0b1, 0x00fdfa38,
+ 0x00fe1324, 0x00fe2b72, 0x00fe4323, 0x00fe5a38, 0x00fe70b0, 0x00fe868b, 0x00fe9bc9, 0x00feb069,
+ 0x00fec46d, 0x00fed7d4, 0x00feea9d, 0x00fefcc9, 0x00ff0e58, 0x00ff1f49, 0x00ff2f9d, 0x00ff3f54,
+ 0x00ff4e6d, 0x00ff5ce9, 0x00ff6ac7, 0x00ff7808, 0x00ff84ab, 0x00ff90b1, 0x00ff9c18, 0x00ffa6e3,
+ 0x00ffb10f, 0x00ffba9e, 0x00ffc38f, 0x00ffcbe2, 0x00ffd397, 0x00ffdaaf, 0x00ffe129, 0x00ffe705,
+ 0x00ffec43, 0x00fff0e3, 0x00fff4e6, 0x00fff84a, 0x00fffb11, 0x00fffd39, 0x00fffec4, 0x00ffffb1,
+ 0x00ffffff,
+};
+#else
+extern const int sf_sin_tab1[513] ;
+#endif
+
+
+#define SINE_INT_ZOOM 16384
+#define SINE_INT_ZBIT 14
+#define __int64 long long
+/*软件索引实现sin生成*/
+static int get_sine_value(int mx_idx)
+{
+ int ret = 0;
+ int idx = 0;
+ int tm_idx = mx_idx & 0x1FFFFFF; //2^25
+ int phase = tm_idx & 0x3FFF;
+ int tp_idx0 = tm_idx >> 14;
+ int tp_idx1 = tp_idx0 + 1;
+ int sign = 1, dt0, dt1;
+
+ if (tp_idx0 > 1024) {
+ sign = -1;
+ tp_idx0 = 2048 - tp_idx0;
+ }
+ if (tp_idx0 < 513) {
+ dt0 = sf_sin_tab1[tp_idx0];
+ } else {
+ dt0 = sf_sin_tab1[1024 - tp_idx0];
+ }
+
+ if (tp_idx1 > 1024) {
+ sign = -1;
+ tp_idx1 = 2048 - tp_idx1;
+ }
+ if (tp_idx1 < 513) {
+ dt1 = sf_sin_tab1[tp_idx1];
+ } else {
+ dt1 = sf_sin_tab1[1024 - tp_idx1];
+ }
+
+ ret = ((__int64)dt0 * (SINE_INT_ZOOM - phase) + (__int64)dt1 * phase) >> SINE_INT_ZBIT;
+
+ ret *= sign;
+ return ret;
+}
+
+static void hw_sin_value(int a, int *sin_res, u8 precision)
+{
+ u64 s64 = a;
+
+ *sin_res = __asm_sine(s64, precision);
+}
+
+int sin_tone_make(void *_maker, void *data, int len)
+{
+ struct audio_sin_maker *maker = (struct audio_sin_maker *)_maker;
+ s16 *pcm = (s16 *)data;
+ int sin_value = 0;
+ int win_sin_value = 0;
+ int add_idx = 0, sub_vol = 0, win_add_idx = 0;
+ int offset = 0;
+ u8 id = maker->id;
+ u8 sin_num = maker->sin_num;
+ u8 repeat = maker->repeat;
+ u8 channel = maker->channel;
+ int sin_index;
+ int win_sin_index;
+ int volume;
+ u32 reamin_points = len / 2 / channel;
+
+ do {
+ if (maker->next_param) {
+ maker->volume = SINE_TOTAL_VOLUME;
+ maker->sin_index = 0;
+ maker->win_sin_index = 0;
+ maker->next_param = 0;
+ }
+
+ u8 win = maker->sin[id].win;
+ add_idx = ((u64)(1 << 25) * maker->sin[id].freq / DEFAULT_SINE_SAMPLE_RATE) >> 9;
+ if (win) {
+ win_add_idx = ((u64)(1 << 25) * maker->sin[id].decay / DEFAULT_SINE_SAMPLE_RATE) >> 9;
+ /*sub_vol = 0;*/
+ } else {
+ sub_vol = maker->sin[id].decay;
+ }
+
+ sin_index = maker->sin_index;
+ win_sin_index = maker->win_sin_index;
+ volume = maker->volume;
+ u32 points = 0;
+ if (maker->fade_points) {
+ points = maker->fade_points > reamin_points ? reamin_points : maker->fade_points;
+ sub_vol = 0;
+ maker->fade_points -= points;
+ } else {
+ points = maker->points > reamin_points ? reamin_points : maker->points;
+ maker->points -= points;
+ }
+ reamin_points -= points;
+ while (points--) {
+ /*hw_sin_value(sin_index, &sin_value, 0);*/
+ sin_value = __asm_sine((s64)sin_index, 2);
+ if (win) {
+ /*hw_sin_value(win_sin_index, &win_sin_value, 0);*/
+ win_sin_value = __asm_sine((s64)win_sin_index, 2);
+#if ((defined CONFIG_CPU_BR36) || (defined CONFIG_CPU_BR28))
+ sin_value = ((s64)sin_value * (s64)win_sin_value) >> 44;
+#else
+ sin_value = ((s64)sin_value * (s64)win_sin_value) >> 34;
+#endif
+ win_sin_index += win_add_idx;
+ win_sin_index &= 0x1ffffff;
+ } else {
+#if ((defined CONFIG_CPU_BR36) || (defined CONFIG_CPU_BR28))
+ sin_value = ((s64)volume * sin_value) >> 39;
+#else
+ sin_value = ((s64)volume * sin_value) >> 34;
+#endif
+ }
+ sin_index += add_idx;
+ sin_index &= 0x1ffffff;
+
+ volume -= sub_vol;
+ if (volume < 0) {
+ volume = 0;
+ }
+
+ *pcm++ = sin_value;
+ if (channel == 2) {
+ *pcm++ = sin_value;
+ } else if (channel == 4) {
+ *pcm++ = sin_value;
+ *pcm++ = sin_value;
+ *pcm++ = sin_value;
+ }
+ }
+
+ maker->volume = volume;
+ maker->sin_index = sin_index;
+ maker->win_sin_index = win_sin_index;
+ if (!maker->points) {
+ if (++id >= sin_num) {
+ if (!repeat) {
+ break;
+ }
+ id = 0;
+ }
+ maker->points = maker->sin[id].points;
+ maker->id = id;
+ maker->next_param = 1;
+ }
+
+ if (!reamin_points) {
+ break;
+ }
+ } while (1);
+
+ return len - (reamin_points * 2 * channel);
+}
+
+int sin_tone_points(void *_maker)
+{
+ struct audio_sin_maker *maker = (struct audio_sin_maker *)_maker;
+ int points = 0;
+ u8 i = 0;
+
+ for (i = 0; i < maker->sin_num; i++) {
+ points += maker->sin[i].points;
+ }
+
+ return points;
+}
+
+void sin_tone_close(void *_maker)
+{
+ struct audio_sin_maker *maker = (struct audio_sin_maker *)_maker;
+
+#ifdef SINE_USE_MALLOC
+ if (maker) {
+ free(maker);
+ }
+#else
+ if (sin_maker_handle.open) {
+ sin_maker_handle.open = 0;
+ }
+#endif
+
+}
+
+#include "asm/math_fast_function.h"
+
+#ifndef DATA16
+#define DATA16 32767
+#endif
+
+/*********************************
+ * fc : 正弦波中心频率
+ * fs : 采样频率
+ * FrameSize :每次计算输出点数
+ * idx :当前计算起始indix
+ * rst :结果存放地址
+ * *******************************/
+void SinWave_Generator(int fc, int fs, int FrameSize, int idx, short *rst)
+{
+ float tmp0, tmp1, tmp2;
+ tmp0 = (float)fc / fs;
+ for (int i = 0; i < FrameSize; i++) {
+ tmp1 = (i + idx) * tmp0 * 2;
+ tmp2 = sin_float(tmp1);
+ *rst = (short)(tmp2 * DATA16);
+ rst++;
+ }
+}
+/*********************************
+ * fs : 采样频率
+ * FrameSize :每次计算输出点数
+ * idx :当前计算起始indix
+ * ts :期望一次扫频所持续时间
+ * rst :结果存放地址
+ * *******************************/
+void SweepSin_Generator(int fs, int FrameSize, int idx, float ts, short *rst)
+{
+ float fp, fc, tmp1, tmp2;
+ int Ncnt, NPoint, DPoint;
+
+ NPoint = fs * ts;
+ // fp = (fs/2)/(fs*ts);
+ fp = 1 / (2 * 2 * ts);
+
+ for (int i = 0; i < FrameSize; i++) {
+ Ncnt = (i + idx) / NPoint;
+ DPoint = (i + idx) - Ncnt * NPoint;
+ //printf("idx:%d \n",DPoint);
+ tmp1 = ((DPoint * fp) / fs) * DPoint * 2;
+ tmp2 = sin_float(tmp1);
+ //printf("Sin[%d]:%d",i,(int)(tmp2*1000));
+ *rst = (short)(tmp2 * DATA16);
+ rst++;
+ }
+}
+
+/*
+*********************************************************************
+* Description: 正弦信号生成
+* Arguments : fc 信号中心频率
+* fs 信号采样率
+* buf 数据输出地址
+* len 数据生成长度,单位是bytes
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+int sin_idx = 0;
+void sin_pcm_fill(int fc, int fs, void *buf, u32 len)
+{
+ SinWave_Generator(fc, fs, len / 2, sin_idx, buf);
+ sin_idx += len / 2;
+}
+
+/*
+*********************************************************************
+* Description: 扫频信号生成
+* Arguments : fs 信号采样率
+* buf 数据输出地址
+* len 数据生成长度,单位是bytes
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+int sweep_sin_idx = 0;
+void sweepsin_pcm_fill(int fs, void *buf, u32 len)
+{
+ SweepSin_Generator(fs, len / 2, sweep_sin_idx, 25, buf);
+ sweep_sin_idx += len / 2;
+}
diff --git a/apps/common/audio/sine_make.h b/apps/common/audio/sine_make.h
new file mode 100644
index 0000000..f658c3e
--- /dev/null
+++ b/apps/common/audio/sine_make.h
@@ -0,0 +1,47 @@
+#ifndef __SINE_MAKE_H_
+#define __SINE_MAKE_H_
+
+#include "generic/typedef.h"
+
+#define DEFAULT_SINE_SAMPLE_RATE 16000
+#define SINE_TOTAL_VOLUME 26843546//16106128//20132660 //26843546
+
+struct sin_param {
+ //int idx_increment;
+ int freq;
+ int points;
+ int win;
+ int decay;
+};
+
+int sin_tone_make(void *_maker, void *data, int len);
+void *sin_tone_open(const struct sin_param *param, int num, u8 channel, u8 repeat);
+int sin_tone_points(void *_maker);
+void sin_tone_close(void *_maker);
+
+/*
+*********************************************************************
+* Description: 正弦信号生成
+* Arguments : fc 信号中心频率
+* fs 信号采样率
+* buf 数据输出地址
+* len 数据生成长度,单位是bytes
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+void sin_pcm_fill(int fc, int fs, void *buf, u32 len);
+
+/*
+*********************************************************************
+* Description: 扫频信号生成
+* Arguments : fs 信号采样率
+* buf 数据输出地址
+* len 数据生成长度,单位是bytes
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+void sweepsin_pcm_fill(int fs, void *buf, u32 len);
+
+#endif/*__SINE_MAKE_H_*/
diff --git a/apps/common/audio/stream/stream_entry.h b/apps/common/audio/stream/stream_entry.h
new file mode 100644
index 0000000..76b1f35
--- /dev/null
+++ b/apps/common/audio/stream/stream_entry.h
@@ -0,0 +1,20 @@
+#ifndef __STREAM_ENTRY_H__
+#define __STREAM_ENTRY_H__
+
+#include "system/includes.h"
+#include "media/includes.h"
+
+// struct __stream_entry;
+struct __stream_entry {
+ u8 is_end;
+ void *data_priv;
+ int (*data_callback)(void *priv, struct audio_data_frame *in);
+ struct audio_stream_entry entry;
+};
+
+struct __stream_entry *stream_entry_open(void *priv, int (*data_callback)(void *priv, struct audio_data_frame *in), u8 is_end);
+void stream_entry_close(struct __stream_entry **hdl);
+void stream_entry_resume(struct __stream_entry *hdl);
+
+#endif// __STREAM_ENTRY_H__
+
diff --git a/apps/common/audio/uartPcmSender.c b/apps/common/audio/uartPcmSender.c
new file mode 100644
index 0000000..564179e
--- /dev/null
+++ b/apps/common/audio/uartPcmSender.c
@@ -0,0 +1,129 @@
+#include "app_config.h"
+
+#ifdef AUDIO_PCM_DEBUG
+#include "system/includes.h"
+#include "asm/uart_dev.h"
+#include "uartPcmSender.h"
+
+static u8 uart_cbuf[32] __attribute__((aligned(4)));
+const uart_bus_t *uart_bus = NULL;
+
+//设备事件响应demo
+void uart_event_handler(struct sys_event *e)
+{
+ u8 uart_rxbuf[12] = {0};
+ u8 uart_txbuf[12] = {0};
+ const uart_bus_t *_uart_bus;
+ u32 uart_rxcnt = 0;
+ u8 i = 0;
+
+ if (0) {//!strcmp(e->arg, "uart_rx_overflow")) {
+ if (e->u.dev.event == DEVICE_EVENT_CHANGE) {
+ printf("uart event: %s\n", e->arg);
+ _uart_bus = (const uart_bus_t *)e->u.dev.value;
+ uart_rxcnt = _uart_bus->read(uart_rxbuf, sizeof(uart_rxbuf), 0);
+ if (uart_rxcnt) {
+ g_printf("rx:%s", uart_rxbuf);
+ }
+ }
+ }
+ if (0) { //(!strcmp(e->arg, "uart_rx_outtime")) {
+ if (e->u.dev.event == DEVICE_EVENT_CHANGE) {
+ printf("uart event: %s\n", e->arg);
+ _uart_bus = (const uart_bus_t *)e->u.dev.value;
+ uart_rxcnt = _uart_bus->read(uart_rxbuf, sizeof(uart_rxbuf), 0);
+ if (uart_rxcnt) {
+ printf("get_buffer:\n");
+ for (int i = 0; i < uart_rxcnt; i++) {
+ putbyte(uart_rxbuf[i]);
+ if (i % 16 == 15) {
+ putchar('\n');
+ }
+ }
+ if (uart_rxcnt % 16) {
+ putchar('\n');
+ }
+ _uart_bus->write(uart_rxbuf, uart_rxcnt);
+ }
+ printf("uart out\n");
+ }
+ }
+}
+SYS_EVENT_HANDLER(SYS_DEVICE_EVENT, uart_event_handler, 0);
+
+void gpio_change(void *priv);
+static void uart_isr_hook(void *arg, u32 status)
+{
+ const uart_bus_t *ubus = arg;
+ struct sys_event e;
+
+ //当CONFIG_UARTx_ENABLE_TX_DMA(x = 0, 1)为1时,不要在中断里面调用ubus->write(),因为中断不能pend信号量
+ if (status == UT_RX) {
+ printf("uart_rx_isr\n");
+#if 1//(UART_DEV_USAGE_TEST_SEL == 1)
+ e.type = SYS_DEVICE_EVENT;
+ e.arg = "uart_rx_overflow";
+ e.u.dev.event = DEVICE_EVENT_CHANGE;
+ e.u.dev.value = (int)ubus;
+ sys_event_notify(&e);
+#endif
+ }
+ if (status == UT_RX_OT) {
+ printf("uart_rx_ot_isr\n");
+#if 1//(UART_DEV_USAGE_TEST_SEL == 1)
+ e.type = SYS_DEVICE_EVENT;
+ e.arg = "uart_rx_outtime";
+ e.u.dev.event = DEVICE_EVENT_CHANGE;
+ e.u.dev.value = (int)ubus;
+ sys_event_notify(&e);
+#endif
+ }
+ if (status == UT_TX) {
+ /* putchar('T'); */
+ /* gpio_change(0); */
+ }
+}
+
+void uartSendData(void *buf, u16 len) //发送数据的接口。
+{
+ if (uart_bus) {
+ uart_bus->write(buf, len); //把数据写到DMA
+ }
+}
+
+/* char *TickPage = "uart online"; */
+/* void uartTickSend(void *priv){ */
+/* if(uartTickSendFlag){ */
+/* r_printf("sizeof:%d\n", sizeof(TickPage)); */
+/* uartSendData(TickPage, sizeof(TickPage)); */
+/* } */
+/* } */
+
+void uartSendInit()
+{
+ struct uart_platform_data_t u_arg = {0};
+ u_arg.tx_pin = PCM_UART1_TX_PORT;
+ u_arg.rx_pin = PCM_UART1_RX_PORT;
+ u_arg.rx_cbuf = uart_cbuf;
+ u_arg.rx_cbuf_size = 32;
+ u_arg.frame_length = 6;
+ u_arg.rx_timeout = 100;
+ u_arg.isr_cbfun = uart_isr_hook;
+ u_arg.baud = PCM_UART1_BAUDRATE;
+ u_arg.is_9bit = 0;
+
+
+ r_printf("uart_dev_open() ...\n");
+ uart_bus = uart_dev_open(&u_arg);
+ r_printf("comming %s,%d\n", __func__, __LINE__);
+ if (uart_bus != NULL) {
+ r_printf("success\n");
+ gpio_set_hd(PCM_UART1_TX_PORT, 1);
+ gpio_set_hd0(PCM_UART1_TX_PORT, 1);
+ //os_task_create(uart_u_task, (void *)uart_bus, 31, 512, 0, "uart_u_task");
+ } else {
+ r_printf("false\n");
+ }
+}
+
+#endif
diff --git a/apps/common/audio/uartPcmSender.h b/apps/common/audio/uartPcmSender.h
new file mode 100644
index 0000000..746544f
--- /dev/null
+++ b/apps/common/audio/uartPcmSender.h
@@ -0,0 +1,21 @@
+#ifndef _UARTPCMSENDER_H_
+#define _UARTPCMSENDER_H_
+#include "system/includes.h"
+#include "app_config.h"
+/*
+ *串口导出数据配置
+ *注意IO口设置不要和普通log输出uart冲突
+ */
+#define PCM_UART1_TX_PORT IO_PORT_DM /*数据导出发送IO*/
+#define PCM_UART1_RX_PORT -1
+#define PCM_UART1_BAUDRATE 2000000 /*数据导出波特率,不用修改,和接收端设置一直*/
+
+#if ((TCFG_UART0_ENABLE == ENABLE_THIS_MOUDLE) && (PCM_UART1_TX_PORT == TCFG_UART0_TX_PORT))
+//IO口配置冲突,请检查修改
+#error "PCM_UART1_TX_PORT conflict with TCFG_UART0_TX_PORT"
+#endif/*PCM_UART1_TX_PORT*/
+
+void uartSendInit(); //串口发数初始化
+void uartSendData(void *buf, u16 len); //发送数据的接口
+
+#endif /*_UARTPCMSENDER_H_*/
diff --git a/apps/common/bt_common/bt_test_api.c b/apps/common/bt_common/bt_test_api.c
new file mode 100644
index 0000000..2ee6fb9
--- /dev/null
+++ b/apps/common/bt_common/bt_test_api.c
@@ -0,0 +1,246 @@
+
+#include "typedef.h"
+#include "app_config.h"
+#include "task.h"
+#include "btctrler_task.h"
+#include "btcontroller_config.h"
+#include "system/includes.h"
+
+#define LOG_TAG "[BT_DUT]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+//bredr test api
+extern void ble_enter_dut_tx_mode(void *param);
+extern void bt_ble_adv_enable(u8 enable);
+extern void bredr_fcc_init(u8 mode, u8 fre);
+
+#if 0
+
+static void bt_dut_api(void)
+{
+ log_info("bt in dut \n");
+#if TCFG_AUTO_SHUT_DOWN_TIME
+ extern void sys_auto_shut_down_disable(void);
+ sys_auto_shut_down_disable();
+#endif
+
+#if TCFG_USER_TWS_ENABLE
+ extern void tws_cancle_all_noconn();
+ tws_cancle_all_noconn() ;
+#else
+ //sys_timer_del(app_var.auto_stop_page_scan_timer);
+ extern void bredr_close_all_scan();
+ bredr_close_all_scan();
+#endif
+
+#if TCFG_USER_BLE_ENABLE
+#if (CONFIG_BT_MODE == BT_NORMAL)
+ bt_ble_adv_enable(0);
+#endif
+#endif
+}
+
+void bit_clr_ie(unsigned char index);
+/* !!!Notice:when this api is called and sleep mode should be sure to exit; */
+void bt_fix_fre_api(u8 fre)
+{
+ bt_dut_api();
+
+ bit_clr_ie(IRQ_BREDR_IDX);
+ bit_clr_ie(IRQ_BT_CLKN_IDX);
+
+ bredr_fcc_init(BT_FRE, fre);
+}
+#endif
+
+//ble test api
+enum BLE_DUT_PAYLOAD_TYPE {
+ PAYLOAD_TYPE_PRBS9 = 0,
+ PAYLOAD_TYPE_11110000,
+ PAYLOAD_TYPE_10101010,
+ PAYLOAD_TYPE_PRBS15,
+ PAYLOAD_TYPE_11111111,
+ PAYLOAD_TYPE_00000000,
+ PAYLOAD_TYPE_00001111,
+ PAYLOAD_TYPE_01010101,
+
+ PAYLOAD_TYPE_SINGLE_CARRIER = 0xf0,
+};
+
+enum BLE_DUT_PHY_TYPE {
+ BLE_1M_UNCODED_PHY = 1,
+ BLE_2M_UNCODED_PHY,
+ BLE_1M_CODED_PHY_S8,
+ BLE_1M_CODED_PHY_S2,
+};
+
+struct ble_dut_param_set {
+ u8 ch_index; //tx ch index;(0~39 -> 2402~2480)
+ u8 payload_type; //tx payload type
+ u8 payload_len; //payload_len(0~0xff) when continuous_tx = 0;
+ u8 continuous_tx; //enable or disable continuous transmission mode(0/1)
+};
+
+/* !!!Notice:when this api is called and sleep mode should be sure to exit; */
+void ble_fix_fre_api()
+{
+#if TCFG_USER_BLE_ENABLE
+#if (CONFIG_BT_MODE == BT_NORMAL)
+ bt_ble_adv_enable(0);
+#endif
+ os_time_dly(10);
+
+ struct ble_dut_param_set dut_param = {
+ .ch_index = 0,
+ .payload_type = PAYLOAD_TYPE_10101010,
+ .payload_len = 0x20,
+ .continuous_tx = 1,
+ };
+ ble_enter_dut_tx_mode(&dut_param);
+#endif
+}
+
+static void *ble_dut_hdl = NULL;
+extern void ll_hci_destory(void);
+void ble_dut_mode_init(void)
+{
+ if (!ble_dut_hdl) {
+ ll_hci_destory();
+ ble_dut_hdl = __ble_dut_ops->init();
+ }
+}
+
+void ble_dut_mode_exit(void)
+{
+ if (ble_dut_hdl) {
+ __ble_dut_ops->exit(ble_dut_hdl);
+ ble_dut_hdl = NULL;
+ }
+}
+
+void ble_dut_tx_fre_api(u8 ch)
+{
+ ble_dut_mode_init();
+ struct ble_dut_tx_param_t tx_param = {
+ .ch_index = ch,
+ .payload_len = 0x20,
+ .payload_type = PAYLOAD_TYPE_PRBS9,
+ .phy_type = BLE_1M_UNCODED_PHY,
+ };
+
+ log_info("BLE_DUT_TX-ch:%x\n", ch);
+ __ble_dut_ops->ioctrl(BLE_DUT_SET_TX_MODE, &tx_param);
+
+}
+
+void ble_dut_rx_fre_api(u8 ch)
+{
+ ble_dut_mode_init();
+ struct ble_dut_rx_param_t rx_param = {
+ .ch_index = ch,
+ .phy_type = BLE_1M_UNCODED_PHY,
+ };
+
+ log_info("BLE_DUT_RX-ch:%x \n", ch);
+ __ble_dut_ops->ioctrl(BLE_DUT_SET_RX_MODE, &rx_param);
+
+}
+
+int ble_dut_test_end(void)
+{
+ int pkt_valid_cnt = 0;
+ int pkt_err_cnt = 0;
+ if (ble_dut_hdl) {
+ __ble_dut_ops->ioctrl(BLE_DUT_SET_TEST_END, &pkt_valid_cnt, NULL);
+
+ log_info("pkt_rx_cnt:%d pkt_err_cnt:%d\n", pkt_valid_cnt, pkt_err_cnt);
+ } else {
+ log_error("ble dut hdl not inited\n");
+ }
+
+ return pkt_valid_cnt;
+}
+
+static volatile u8 bt_test_status = 0;
+
+void ble_bqb_test_thread_init(void);
+static hci_transport_config_uart_t config = {
+ HCI_TRANSPORT_CONFIG_UART,
+ 115200,
+ 0, // main baudrate
+ 0, // flow control
+ NULL,
+};
+
+extern void dut_hci_controller_init(const hci_transport_t *transport, const void *config);
+void ble_standard_dut_test_init(void)
+{
+ log_info("%s\n", __FUNCTION__);
+ bt_test_status = 1;
+ ble_dut_mode_init();
+ //ble_bqb_test_thread_init();
+ dut_hci_controller_init((void *)hci_transport_uart_instance(), &config);
+}
+
+void ble_standard_dut_test_close(void)
+{
+ log_info("%s\n", __FUNCTION__);
+ ble_dut_test_end();
+ ble_dut_mode_exit();
+ hci_transport_t *p_uart_trans = hci_transport_uart_instance();
+ p_uart_trans->close();
+ bt_test_status = 0;
+
+}
+
+void ble_dut_mode_key_handle(u8 type, u8 key_val)
+{
+ static u8 rx_ch = 0;
+ static u8 tx_ch = 0;
+ switch (key_val) {
+ case 3:
+ ble_dut_tx_fre_api(tx_ch++);
+ if (tx_ch > 39) {
+ tx_ch = 0;
+ }
+ break;
+
+ case 1:
+ ble_dut_rx_fre_api(rx_ch++);
+ if (rx_ch > 39) {
+ rx_ch = 0;
+ }
+ break;
+
+ case 2:
+ ble_dut_test_end();
+ break;
+
+ case 0:
+ ble_standard_dut_test_init();
+ break;
+
+ case 4:
+ ble_standard_dut_test_close();
+ break;
+
+defualt:
+ break;
+ }
+}
+
+static u8 bt_test_idle_query(void)
+{
+ return !bt_test_status;
+}
+
+REGISTER_LP_TARGET(bt_test_lp_target) = {
+ .name = "bt_test",
+ .is_idle = bt_test_idle_query,
+};
+
diff --git a/apps/common/cJSON/cJSON.c b/apps/common/cJSON/cJSON.c
new file mode 100644
index 0000000..e5e2962
--- /dev/null
+++ b/apps/common/cJSON/cJSON.c
@@ -0,0 +1,1528 @@
+
+/*
+ Copyright (c) 2009 Dave Gamble
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+/* cJSON */
+/* JSON parser in C. */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "cJSON.h"
+
+static const char *ep;
+
+const char *cJSON_GetErrorPtr(void)
+{
+ return ep;
+}
+
+static int cJSON_strcasecmp(const char *s1, const char *s2)
+{
+ if (!s1) {
+ return (s1 == s2) ? 0 : 1;
+ }
+ if (!s2) {
+ return 1;
+ }
+ for (; tolower(*s1) == tolower(*s2); ++s1, ++s2) if (*s1 == 0) {
+ return 0;
+ }
+ return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
+}
+
+static void *(*cJSON_malloc)(size_t sz) = malloc;
+static void (*cJSON_free)(void *ptr) = free;
+
+static char *cJSON_strdup(const char *str)
+{
+ size_t len;
+ char *copy;
+
+ len = strlen(str) + 1;
+ if (!(copy = (char *)cJSON_malloc(len))) {
+ return 0;
+ }
+ memcpy(copy, str, len);
+ return copy;
+}
+
+void cJSON_InitHooks(cJSON_Hooks *hooks)
+{
+ if (!hooks) { /* Reset hooks */
+ cJSON_malloc = malloc;
+ cJSON_free = free;
+ return;
+ }
+
+ cJSON_malloc = (hooks->malloc_fn) ? hooks->malloc_fn : malloc;
+ cJSON_free = (hooks->free_fn) ? hooks->free_fn : free;
+}
+
+/* Internal constructor. */
+static cJSON *cJSON_New_Item(void)
+{
+ cJSON *node = (cJSON *)cJSON_malloc(sizeof(cJSON));
+ if (node) {
+ memset(node, 0, sizeof(cJSON));
+ }
+ return node;
+}
+
+/* Delete a cJSON structure. */
+void cJSON_Delete(cJSON *c)
+{
+ cJSON *next;
+ while (c) {
+ next = c->next;
+ if (!(c->type & cJSON_IsReference) && c->child) {
+ cJSON_Delete(c->child);
+ }
+ if (!(c->type & cJSON_IsReference) && c->valuestring) {
+ cJSON_free(c->valuestring);
+ }
+ if (!(c->type & cJSON_StringIsConst) && c->string) {
+ cJSON_free(c->string);
+ }
+ cJSON_free(c);
+ c = next;
+ }
+}
+
+/* Parse the input text to generate a number, and populate the result into item. */
+static const char *parse_number(cJSON *item, const char *num)
+{
+ double n = 0, sign = 1, scale = 0;
+ int subscale = 0, signsubscale = 1;
+
+ if (*num == '-') {
+ sign = -1, num++; /* Has sign? */
+ }
+ if (*num == '0') {
+ num++; /* is zero */
+ }
+ if (*num >= '1' && *num <= '9') do {
+ n = (n * 10.0) + (*num++ -'0');
+ } while (*num >= '0' && *num <= '9'); /* Number? */
+ if (*num == '.' && num[1] >= '0' && num[1] <= '9') {
+ num++; /* Fractional part? */
+ do {
+ n = (n * 10.0) + (*num++ -'0'), scale--;
+ } while (*num >= '0' && *num <= '9');
+ }
+ if (*num == 'e' || *num == 'E') { /* Exponent? */
+ num++;
+ if (*num == '+') {
+ num++;
+ } else if (*num == '-') {
+ signsubscale = -1, num++; /* With sign? */
+ }
+ while (*num >= '0' && *num <= '9') {
+ subscale = (subscale * 10) + (*num++ - '0'); /* Number? */
+ }
+ }
+
+ n = sign * n * pow(10.0, (scale + subscale * signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
+
+ item->valuedouble = n;
+ item->valueint = (int)n;
+ item->type = cJSON_Number;
+ return num;
+}
+
+static int pow2gt(int x)
+{
+ --x;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ return x + 1;
+}
+
+typedef struct {
+ char *buffer;
+ int length;
+ int offset;
+} printbuffer;
+
+static char *ensure(printbuffer *p, int needed)
+{
+ char *newbuffer;
+ int newsize;
+ if (!p || !p->buffer) {
+ return 0;
+ }
+ needed += p->offset;
+ if (needed <= p->length) {
+ return p->buffer + p->offset;
+ }
+
+ newsize = pow2gt(needed);
+ newbuffer = (char *)cJSON_malloc(newsize);
+ if (!newbuffer) {
+ cJSON_free(p->buffer);
+ p->length = 0, p->buffer = 0;
+ return 0;
+ }
+ if (newbuffer) {
+ memcpy(newbuffer, p->buffer, p->length);
+ }
+ cJSON_free(p->buffer);
+ p->length = newsize;
+ p->buffer = newbuffer;
+ return newbuffer + p->offset;
+}
+
+static int update(printbuffer *p)
+{
+ char *str;
+ if (!p || !p->buffer) {
+ return 0;
+ }
+ str = p->buffer + p->offset;
+ return p->offset + strlen(str);
+}
+
+/* Render the number nicely from the given item into a string. */
+static char *print_number(cJSON *item, printbuffer *p)
+{
+ char *str = 0;
+ double d = item->valuedouble;
+ if (d == 0) {
+ if (p) {
+ str = ensure(p, 2);
+ } else {
+ str = (char *)cJSON_malloc(2); /* special case for 0. */
+ }
+ if (str) {
+ strcpy(str, "0");
+ }
+ } else if (fabs(((double)item->valueint) - d) <= DBL_EPSILON && d <= INT_MAX && d >= INT_MIN) {
+ if (p) {
+ str = ensure(p, 21);
+ } else {
+ str = (char *)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
+ }
+ if (str) {
+ sprintf(str, "%d", item->valueint);
+ }
+ } else {
+ if (p) {
+ str = ensure(p, 64);
+ } else {
+ str = (char *)cJSON_malloc(64); /* This is a nice tradeoff. */
+ }
+ if (str) {
+ if (fabs(floor(d) - d) <= DBL_EPSILON && fabs(d) < 1.0e60) {
+ sprintf(str, "%.0f", d);
+ } else if (fabs(d) < 1.0e-6 || fabs(d) > 1.0e9) {
+ sprintf(str, "%e", d);
+ } else {
+ sprintf(str, "%f", d);
+ }
+ }
+ }
+ return str;
+}
+
+static unsigned parse_hex4(const char *str)
+{
+ unsigned h = 0;
+ if (*str >= '0' && *str <= '9') {
+ h += (*str) - '0';
+ } else if (*str >= 'A' && *str <= 'F') {
+ h += 10 + (*str) - 'A';
+ } else if (*str >= 'a' && *str <= 'f') {
+ h += 10 + (*str) - 'a';
+ } else {
+ return 0;
+ }
+ h = h << 4;
+ str++;
+ if (*str >= '0' && *str <= '9') {
+ h += (*str) - '0';
+ } else if (*str >= 'A' && *str <= 'F') {
+ h += 10 + (*str) - 'A';
+ } else if (*str >= 'a' && *str <= 'f') {
+ h += 10 + (*str) - 'a';
+ } else {
+ return 0;
+ }
+ h = h << 4;
+ str++;
+ if (*str >= '0' && *str <= '9') {
+ h += (*str) - '0';
+ } else if (*str >= 'A' && *str <= 'F') {
+ h += 10 + (*str) - 'A';
+ } else if (*str >= 'a' && *str <= 'f') {
+ h += 10 + (*str) - 'a';
+ } else {
+ return 0;
+ }
+ h = h << 4;
+ str++;
+ if (*str >= '0' && *str <= '9') {
+ h += (*str) - '0';
+ } else if (*str >= 'A' && *str <= 'F') {
+ h += 10 + (*str) - 'A';
+ } else if (*str >= 'a' && *str <= 'f') {
+ h += 10 + (*str) - 'a';
+ } else {
+ return 0;
+ }
+ return h;
+}
+
+/* Parse the input text into an unescaped cstring, and populate item. */
+static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+static const char *parse_string(cJSON *item, const char *str)
+{
+ const char *ptr = str + 1;
+ char *ptr2;
+ char *out;
+ int len = 0;
+ unsigned uc, uc2;
+ if (*str != '\"') {
+ ep = str; /* not a string! */
+ return 0;
+ }
+
+ while (*ptr != '\"' && *ptr && ++len) if (*ptr++ == '\\') {
+ ptr++; /* Skip escaped quotes. */
+ }
+
+ out = (char *)cJSON_malloc(len + 1); /* This is how long we need for the string, roughly. */
+ if (!out) {
+ return 0;
+ }
+
+ ptr = str + 1;
+ ptr2 = out;
+ while (*ptr != '\"' && *ptr) {
+ if (*ptr != '\\') {
+ *ptr2++ = *ptr++;
+ } else {
+ ptr++;
+ switch (*ptr) {
+ case 'b':
+ *ptr2++ = '\b';
+ break;
+ case 'f':
+ *ptr2++ = '\f';
+ break;
+ case 'n':
+ *ptr2++ = '\n';
+ break;
+ case 'r':
+ *ptr2++ = '\r';
+ break;
+ case 't':
+ *ptr2++ = '\t';
+ break;
+ case 'u': /* transcode utf16 to utf8. */
+ uc = parse_hex4(ptr + 1);
+ ptr += 4; /* get the unicode char. */
+
+ if ((uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0) {
+ break; /* check for invalid. */
+ }
+
+ if (uc >= 0xD800 && uc <= 0xDBFF) { /* UTF16 surrogate pairs. */
+ if (ptr[1] != '\\' || ptr[2] != 'u') {
+ break; /* missing second-half of surrogate. */
+ }
+ uc2 = parse_hex4(ptr + 3);
+ ptr += 6;
+ if (uc2 < 0xDC00 || uc2 > 0xDFFF) {
+ break; /* invalid second-half of surrogate. */
+ }
+ uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF));
+ }
+
+ len = 4;
+ if (uc < 0x80) {
+ len = 1;
+ } else if (uc < 0x800) {
+ len = 2;
+ } else if (uc < 0x10000) {
+ len = 3;
+ }
+ ptr2 += len;
+
+ switch (len) {
+ case 4:
+ *--ptr2 = ((uc | 0x80) & 0xBF);
+ uc >>= 6;
+ case 3:
+ *--ptr2 = ((uc | 0x80) & 0xBF);
+ uc >>= 6;
+ case 2:
+ *--ptr2 = ((uc | 0x80) & 0xBF);
+ uc >>= 6;
+ case 1:
+ *--ptr2 = (uc | firstByteMark[len]);
+ }
+ ptr2 += len;
+ break;
+ default:
+ *ptr2++ = *ptr;
+ break;
+ }
+ ptr++;
+ }
+ }
+ *ptr2 = 0;
+ if (*ptr == '\"') {
+ ptr++;
+ }
+ item->valuestring = out;
+ item->type = cJSON_String;
+ return ptr;
+}
+
+/* Render the cstring provided to an escaped version that can be printed. */
+static char *print_string_ptr(const char *str, printbuffer *p)
+{
+ const char *ptr;
+ char *ptr2, *out;
+ int len = 0, flag = 0;
+ unsigned char token;
+
+ for (ptr = str; *ptr; ptr++) {
+ flag |= ((*ptr > 0 && *ptr < 32) || (*ptr == '\"') || (*ptr == '\\')) ? 1 : 0;
+ }
+ if (!flag) {
+ len = ptr - str;
+ if (p) {
+ out = ensure(p, len + 3);
+ } else {
+ out = (char *)cJSON_malloc(len + 3);
+ }
+ if (!out) {
+ return 0;
+ }
+ ptr2 = out;
+ *ptr2++ = '\"';
+ strcpy(ptr2, str);
+ ptr2[len] = '\"';
+ ptr2[len + 1] = 0;
+ return out;
+ }
+
+ if (!str) {
+ if (p) {
+ out = ensure(p, 3);
+ } else {
+ out = (char *)cJSON_malloc(3);
+ }
+ if (!out) {
+ return 0;
+ }
+ strcpy(out, "\"\"");
+ return out;
+ }
+ ptr = str;
+ while ((token = *ptr) && ++len) {
+ if (strchr("\"\\\b\f\n\r\t", token)) {
+ len++;
+ } else if (token < 32) {
+ len += 5;
+ }
+ ptr++;
+ }
+
+ if (p) {
+ out = ensure(p, len + 3);
+ } else {
+ out = (char *)cJSON_malloc(len + 3);
+ }
+ if (!out) {
+ return 0;
+ }
+
+ ptr2 = out;
+ ptr = str;
+ *ptr2++ = '\"';
+ while (*ptr) {
+ if ((unsigned char)*ptr > 31 && *ptr != '\"' && *ptr != '\\') {
+ *ptr2++ = *ptr++;
+ } else {
+ *ptr2++ = '\\';
+ switch (token = *ptr++) {
+ case '\\':
+ *ptr2++ = '\\';
+ break;
+ case '\"':
+ *ptr2++ = '\"';
+ break;
+ case '\b':
+ *ptr2++ = 'b';
+ break;
+ case '\f':
+ *ptr2++ = 'f';
+ break;
+ case '\n':
+ *ptr2++ = 'n';
+ break;
+ case '\r':
+ *ptr2++ = 'r';
+ break;
+ case '\t':
+ *ptr2++ = 't';
+ break;
+ default:
+ sprintf(ptr2, "u%04x", token);
+ ptr2 += 5;
+ break; /* escape and print */
+ }
+ }
+ }
+ *ptr2++ = '\"';
+ *ptr2++ = 0;
+ return out;
+}
+/* Invote print_string_ptr (which is useful) on an item. */
+static char *print_string(cJSON *item, printbuffer *p)
+{
+ return print_string_ptr(item->valuestring, p);
+}
+
+/* Predeclare these prototypes. */
+static const char *parse_value(cJSON *item, const char *value);
+static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p);
+static const char *parse_array(cJSON *item, const char *value);
+static char *print_array(cJSON *item, int depth, int fmt, printbuffer *p);
+static const char *parse_object(cJSON *item, const char *value);
+static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p);
+
+/* Utility to jump whitespace and cr/lf */
+static const char *skip(const char *in)
+{
+ while (in && *in && (unsigned char)*in <= 32) {
+ in++;
+ }
+ return in;
+}
+
+/* Parse an object - create a new root, and populate. */
+cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated)
+{
+ const char *end = 0;
+ cJSON *c = cJSON_New_Item();
+ ep = 0;
+ if (!c) {
+ return 0; /* memory fail */
+ }
+
+ end = parse_value(c, skip(value));
+ if (!end) {
+ cJSON_Delete(c); /* parse failure. ep is set. */
+ return 0;
+ }
+
+ /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
+ if (require_null_terminated) {
+ end = skip(end);
+ if (*end) {
+ cJSON_Delete(c);
+ ep = end;
+ return 0;
+ }
+ }
+ if (return_parse_end) {
+ *return_parse_end = end;
+ }
+ return c;
+}
+/* Default options for cJSON_Parse */
+cJSON *cJSON_Parse(const char *value)
+{
+ return cJSON_ParseWithOpts(value, 0, 0);
+}
+
+/* Render a cJSON item/entity/structure to text. */
+char *cJSON_Print(cJSON *item)
+{
+ return print_value(item, 0, 1, 0);
+}
+char *cJSON_PrintUnformatted(cJSON *item)
+{
+ return print_value(item, 0, 0, 0);
+}
+
+char *cJSON_PrintBuffered(cJSON *item, int prebuffer, int fmt)
+{
+ printbuffer p;
+ p.buffer = (char *)cJSON_malloc(prebuffer);
+ p.length = prebuffer;
+ p.offset = 0;
+ return print_value(item, 0, fmt, &p);
+ return p.buffer;
+}
+
+
+/* Parser core - when encountering text, process appropriately. */
+static const char *parse_value(cJSON *item, const char *value)
+{
+ if (!value) {
+ return 0; /* Fail on null. */
+ }
+ if (!strncmp(value, "null", 4)) {
+ item->type = cJSON_NULL;
+ return value + 4;
+ }
+ if (!strncmp(value, "false", 5)) {
+ item->type = cJSON_False;
+ return value + 5;
+ }
+ if (!strncmp(value, "true", 4)) {
+ item->type = cJSON_True;
+ item->valueint = 1;
+ return value + 4;
+ }
+ if (*value == '\"') {
+ return parse_string(item, value);
+ }
+ if (*value == '-' || (*value >= '0' && *value <= '9')) {
+ return parse_number(item, value);
+ }
+ if (*value == '[') {
+ return parse_array(item, value);
+ }
+ if (*value == '{') {
+ return parse_object(item, value);
+ }
+
+ ep = value;
+ return 0; /* failure. */
+}
+
+/* Render a value to text. */
+static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p)
+{
+ char *out = 0;
+ if (!item) {
+ return 0;
+ }
+ if (p) {
+ switch ((item->type) & 255) {
+ case cJSON_NULL: {
+ out = ensure(p, 5);
+ if (out) {
+ strcpy(out, "null");
+ }
+ break;
+ }
+ case cJSON_False: {
+ out = ensure(p, 6);
+ if (out) {
+ strcpy(out, "false");
+ }
+ break;
+ }
+ case cJSON_True: {
+ out = ensure(p, 5);
+ if (out) {
+ strcpy(out, "true");
+ }
+ break;
+ }
+ case cJSON_Number:
+ out = print_number(item, p);
+ break;
+ case cJSON_String:
+ out = print_string(item, p);
+ break;
+ case cJSON_Array:
+ out = print_array(item, depth, fmt, p);
+ break;
+ case cJSON_Object:
+ out = print_object(item, depth, fmt, p);
+ break;
+ }
+ } else {
+ switch ((item->type) & 255) {
+ case cJSON_NULL:
+ out = cJSON_strdup("null");
+ break;
+ case cJSON_False:
+ out = cJSON_strdup("false");
+ break;
+ case cJSON_True:
+ out = cJSON_strdup("true");
+ break;
+ case cJSON_Number:
+ out = print_number(item, 0);
+ break;
+ case cJSON_String:
+ out = print_string(item, 0);
+ break;
+ case cJSON_Array:
+ out = print_array(item, depth, fmt, 0);
+ break;
+ case cJSON_Object:
+ out = print_object(item, depth, fmt, 0);
+ break;
+ }
+ }
+ return out;
+}
+
+/* Build an array from input text. */
+static const char *parse_array(cJSON *item, const char *value)
+{
+ cJSON *child;
+ if (*value != '[') {
+ ep = value; /* not an array! */
+ return 0;
+ }
+
+ item->type = cJSON_Array;
+ value = skip(value + 1);
+ if (*value == ']') {
+ return value + 1; /* empty array. */
+ }
+
+ item->child = child = cJSON_New_Item();
+ if (!item->child) {
+ return 0; /* memory fail */
+ }
+ value = skip(parse_value(child, skip(value))); /* skip any spacing, get the value. */
+ if (!value) {
+ return 0;
+ }
+
+ while (*value == ',') {
+ cJSON *new_item;
+ if (!(new_item = cJSON_New_Item())) {
+ return 0; /* memory fail */
+ }
+ child->next = new_item;
+ new_item->prev = child;
+ child = new_item;
+ value = skip(parse_value(child, skip(value + 1)));
+ if (!value) {
+ return 0; /* memory fail */
+ }
+ }
+
+ if (*value == ']') {
+ return value + 1; /* end of array */
+ }
+ ep = value;
+ return 0; /* malformed. */
+}
+
+/* Render an array to text */
+static char *print_array(cJSON *item, int depth, int fmt, printbuffer *p)
+{
+ char **entries;
+ char *out = 0, *ptr, *ret;
+ int len = 5;
+ cJSON *child = item->child;
+ int numentries = 0, i = 0, fail = 0;
+ size_t tmplen = 0;
+
+ /* How many entries in the array? */
+ while (child) {
+ numentries++, child = child->next;
+ }
+ /* Explicitly handle numentries==0 */
+ if (!numentries) {
+ if (p) {
+ out = ensure(p, 3);
+ } else {
+ out = (char *)cJSON_malloc(3);
+ }
+ if (out) {
+ strcpy(out, "[]");
+ }
+ return out;
+ }
+
+ if (p) {
+ /* Compose the output array. */
+ i = p->offset;
+ ptr = ensure(p, 1);
+ if (!ptr) {
+ return 0;
+ } *ptr = '[';
+ p->offset++;
+ child = item->child;
+ while (child && !fail) {
+ print_value(child, depth + 1, fmt, p);
+ p->offset = update(p);
+ if (child->next) {
+ len = fmt ? 2 : 1;
+ ptr = ensure(p, len + 1);
+ if (!ptr) {
+ return 0;
+ }*ptr++ = ',';
+ if (fmt) {
+ *ptr++ = ' ';
+ }*ptr = 0;
+ p->offset += len;
+ }
+ child = child->next;
+ }
+ ptr = ensure(p, 2);
+ if (!ptr) {
+ return 0;
+ } *ptr++ = ']';
+ *ptr = 0;
+ out = (p->buffer) + i;
+ } else {
+ /* Allocate an array to hold the values for each */
+ entries = (char **)cJSON_malloc(numentries * sizeof(char *));
+ if (!entries) {
+ return 0;
+ }
+ memset(entries, 0, numentries * sizeof(char *));
+ /* Retrieve all the results: */
+ child = item->child;
+ while (child && !fail) {
+ ret = print_value(child, depth + 1, fmt, 0);
+ entries[i++] = ret;
+ if (ret) {
+ len += strlen(ret) + 2 + (fmt ? 1 : 0);
+ } else {
+ fail = 1;
+ }
+ child = child->next;
+ }
+
+ /* If we didn't fail, try to malloc the output string */
+ if (!fail) {
+ out = (char *)cJSON_malloc(len);
+ }
+ /* If that fails, we fail. */
+ if (!out) {
+ fail = 1;
+ }
+
+ /* Handle failure. */
+ if (fail) {
+ for (i = 0; i < numentries; i++) if (entries[i]) {
+ cJSON_free(entries[i]);
+ }
+ cJSON_free(entries);
+ return 0;
+ }
+
+ /* Compose the output array. */
+ *out = '[';
+ ptr = out + 1;
+ *ptr = 0;
+ for (i = 0; i < numentries; i++) {
+ tmplen = strlen(entries[i]);
+ memcpy(ptr, entries[i], tmplen);
+ ptr += tmplen;
+ if (i != numentries - 1) {
+ *ptr++ = ',';
+ if (fmt) {
+ *ptr++ = ' ';
+ }*ptr = 0;
+ }
+ cJSON_free(entries[i]);
+ }
+ cJSON_free(entries);
+ *ptr++ = ']';
+ *ptr++ = 0;
+ }
+ return out;
+}
+
+/* Build an object from the text. */
+static const char *parse_object(cJSON *item, const char *value)
+{
+ cJSON *child;
+ if (*value != '{') {
+ ep = value; /* not an object! */
+ return 0;
+ }
+
+ item->type = cJSON_Object;
+ value = skip(value + 1);
+ if (*value == '}') {
+ return value + 1; /* empty array. */
+ }
+
+ item->child = child = cJSON_New_Item();
+ if (!item->child) {
+ return 0;
+ }
+ value = skip(parse_string(child, skip(value)));
+ if (!value) {
+ return 0;
+ }
+ child->string = child->valuestring;
+ child->valuestring = 0;
+ if (*value != ':') {
+ ep = value; /* fail! */
+ return 0;
+ }
+ value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */
+ if (!value) {
+ return 0;
+ }
+
+ while (*value == ',') {
+ cJSON *new_item;
+ if (!(new_item = cJSON_New_Item())) {
+ return 0; /* memory fail */
+ }
+ child->next = new_item;
+ new_item->prev = child;
+ child = new_item;
+ value = skip(parse_string(child, skip(value + 1)));
+ if (!value) {
+ return 0;
+ }
+ child->string = child->valuestring;
+ child->valuestring = 0;
+ if (*value != ':') {
+ ep = value; /* fail! */
+ return 0;
+ }
+ value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */
+ if (!value) {
+ return 0;
+ }
+ }
+
+ if (*value == '}') {
+ return value + 1; /* end of array */
+ }
+ ep = value;
+ return 0; /* malformed. */
+}
+
+/* Render an object to text. */
+static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p)
+{
+ char **entries = 0, **names = 0;
+ char *out = 0, *ptr, *ret, *str;
+ int len = 7, i = 0, j;
+ cJSON *child = item->child;
+ int numentries = 0, fail = 0;
+ size_t tmplen = 0;
+ /* Count the number of entries. */
+ while (child) {
+ numentries++, child = child->next;
+ }
+ /* Explicitly handle empty object case */
+ if (!numentries) {
+ if (p) {
+ out = ensure(p, fmt ? depth + 4 : 3);
+ } else {
+ out = (char *)cJSON_malloc(fmt ? depth + 4 : 3);
+ }
+ if (!out) {
+ return 0;
+ }
+ ptr = out;
+ *ptr++ = '{';
+ if (fmt) {
+ *ptr++ = '\n';
+ for (i = 0; i < depth - 1; i++) {
+ *ptr++ = '\t';
+ }
+ }
+ *ptr++ = '}';
+ *ptr++ = 0;
+ return out;
+ }
+ if (p) {
+ /* Compose the output: */
+ i = p->offset;
+ len = fmt ? 2 : 1;
+ ptr = ensure(p, len + 1);
+ if (!ptr) {
+ return 0;
+ }
+ *ptr++ = '{';
+ if (fmt) {
+ *ptr++ = '\n';
+ } *ptr = 0;
+ p->offset += len;
+ child = item->child;
+ depth++;
+ while (child) {
+ if (fmt) {
+ ptr = ensure(p, depth);
+ if (!ptr) {
+ return 0;
+ }
+ for (j = 0; j < depth; j++) {
+ *ptr++ = '\t';
+ }
+ p->offset += depth;
+ }
+ print_string_ptr(child->string, p);
+ p->offset = update(p);
+
+ len = fmt ? 2 : 1;
+ ptr = ensure(p, len);
+ if (!ptr) {
+ return 0;
+ }
+ *ptr++ = ':';
+ if (fmt) {
+ *ptr++ = '\t';
+ }
+ p->offset += len;
+
+ print_value(child, depth, fmt, p);
+ p->offset = update(p);
+
+ len = (fmt ? 1 : 0) + (child->next ? 1 : 0);
+ ptr = ensure(p, len + 1);
+ if (!ptr) {
+ return 0;
+ }
+ if (child->next) {
+ *ptr++ = ',';
+ }
+ if (fmt) {
+ *ptr++ = '\n';
+ }*ptr = 0;
+ p->offset += len;
+ child = child->next;
+ }
+ ptr = ensure(p, fmt ? (depth + 1) : 2);
+ if (!ptr) {
+ return 0;
+ }
+ if (fmt) for (i = 0; i < depth - 1; i++) {
+ *ptr++ = '\t';
+ }
+ *ptr++ = '}';
+ *ptr = 0;
+ out = (p->buffer) + i;
+ } else {
+ /* Allocate space for the names and the objects */
+ entries = (char **)cJSON_malloc(numentries * sizeof(char *));
+ if (!entries) {
+ return 0;
+ }
+ names = (char **)cJSON_malloc(numentries * sizeof(char *));
+ if (!names) {
+ cJSON_free(entries);
+ return 0;
+ }
+ memset(entries, 0, sizeof(char *)*numentries);
+ memset(names, 0, sizeof(char *)*numentries);
+
+ /* Collect all the results into our arrays: */
+ child = item->child;
+ depth++;
+ if (fmt) {
+ len += depth;
+ }
+ while (child) {
+ names[i] = str = print_string_ptr(child->string, 0);
+ entries[i++] = ret = print_value(child, depth, fmt, 0);
+ if (str && ret) {
+ len += strlen(ret) + strlen(str) + 2 + (fmt ? 2 + depth : 0);
+ } else {
+ fail = 1;
+ }
+ child = child->next;
+ }
+
+ /* Try to allocate the output string */
+ if (!fail) {
+ out = (char *)cJSON_malloc(len);
+ }
+ if (!out) {
+ fail = 1;
+ }
+
+ /* Handle failure */
+ if (fail) {
+ for (i = 0; i < numentries; i++) {
+ if (names[i]) {
+ cJSON_free(names[i]);
+ }
+ if (entries[i]) {
+ cJSON_free(entries[i]);
+ }
+ }
+ cJSON_free(names);
+ cJSON_free(entries);
+ return 0;
+ }
+
+ /* Compose the output: */
+ *out = '{';
+ ptr = out + 1;
+ if (fmt) {
+ *ptr++ = '\n';
+ }*ptr = 0;
+ for (i = 0; i < numentries; i++) {
+ if (fmt) for (j = 0; j < depth; j++) {
+ *ptr++ = '\t';
+ }
+ tmplen = strlen(names[i]);
+ memcpy(ptr, names[i], tmplen);
+ ptr += tmplen;
+ *ptr++ = ':';
+ if (fmt) {
+ *ptr++ = '\t';
+ }
+ strcpy(ptr, entries[i]);
+ ptr += strlen(entries[i]);
+ if (i != numentries - 1) {
+ *ptr++ = ',';
+ }
+ if (fmt) {
+ *ptr++ = '\n';
+ }*ptr = 0;
+ cJSON_free(names[i]);
+ cJSON_free(entries[i]);
+ }
+
+ cJSON_free(names);
+ cJSON_free(entries);
+ if (fmt) for (i = 0; i < depth - 1; i++) {
+ *ptr++ = '\t';
+ }
+ *ptr++ = '}';
+ *ptr++ = 0;
+ }
+ return out;
+}
+
+/* Get Array size/item / object item. */
+int cJSON_GetArraySize(cJSON *array)
+{
+ cJSON *c = array->child;
+ int i = 0;
+ while (c) {
+ i++, c = c->next;
+ }
+ return i;
+}
+cJSON *cJSON_GetArrayItem(cJSON *array, int item)
+{
+ cJSON *c = array->child;
+ while (c && item > 0) {
+ item--, c = c->next;
+ }
+ return c;
+}
+cJSON *cJSON_GetObjectItem(cJSON *object, const char *string)
+{
+ cJSON *c = object->child;
+ while (c && cJSON_strcasecmp(c->string, string)) {
+ c = c->next;
+ }
+ return c;
+}
+
+/* Utility for array list handling. */
+static void suffix_object(cJSON *prev, cJSON *item)
+{
+ prev->next = item;
+ item->prev = prev;
+}
+/* Utility for handling references. */
+static cJSON *create_reference(cJSON *item)
+{
+ cJSON *ref = cJSON_New_Item();
+ if (!ref) {
+ return 0;
+ }
+ memcpy(ref, item, sizeof(cJSON));
+ ref->string = 0;
+ ref->type |= cJSON_IsReference;
+ ref->next = ref->prev = 0;
+ return ref;
+}
+
+/* Add item to array/object. */
+void cJSON_AddItemToArray(cJSON *array, cJSON *item)
+{
+ cJSON *c = array->child;
+ if (!item) {
+ return;
+ }
+ if (!c) {
+ array->child = item;
+ } else {
+ while (c && c->next) {
+ c = c->next;
+ }
+ suffix_object(c, item);
+ }
+}
+void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
+{
+ if (!item) {
+ return;
+ }
+ if (item->string) {
+ cJSON_free(item->string);
+ }
+ item->string = cJSON_strdup(string);
+ cJSON_AddItemToArray(object, item);
+}
+void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
+{
+ if (!item) {
+ return;
+ }
+ if (!(item->type & cJSON_StringIsConst) && item->string) {
+ cJSON_free(item->string);
+ }
+ item->string = (char *)string;
+ item->type |= cJSON_StringIsConst;
+ cJSON_AddItemToArray(object, item);
+}
+void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
+{
+ cJSON_AddItemToArray(array, create_reference(item));
+}
+void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
+{
+ cJSON_AddItemToObject(object, string, create_reference(item));
+}
+
+cJSON *cJSON_DetachItemFromArray(cJSON *array, int which)
+{
+ cJSON *c = array->child;
+ while (c && which > 0) {
+ c = c->next, which--;
+ }
+ if (!c) {
+ return 0;
+ }
+ if (c->prev) {
+ c->prev->next = c->next;
+ }
+ if (c->next) {
+ c->next->prev = c->prev;
+ }
+ if (c == array->child) {
+ array->child = c->next;
+ }
+ c->prev = c->next = 0;
+ return c;
+}
+void cJSON_DeleteItemFromArray(cJSON *array, int which)
+{
+ cJSON_Delete(cJSON_DetachItemFromArray(array, which));
+}
+cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string)
+{
+ int i = 0;
+ cJSON *c = object->child;
+ while (c && cJSON_strcasecmp(c->string, string)) {
+ i++, c = c->next;
+ }
+ if (c) {
+ return cJSON_DetachItemFromArray(object, i);
+ }
+ return 0;
+}
+void cJSON_DeleteItemFromObject(cJSON *object, const char *string)
+{
+ cJSON_Delete(cJSON_DetachItemFromObject(object, string));
+}
+
+/* Replace array/object items with new ones. */
+void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
+{
+ cJSON *c = array->child;
+ while (c && which > 0) {
+ c = c->next, which--;
+ }
+ if (!c) {
+ cJSON_AddItemToArray(array, newitem);
+ return;
+ }
+ newitem->next = c;
+ newitem->prev = c->prev;
+ c->prev = newitem;
+ if (c == array->child) {
+ array->child = newitem;
+ } else {
+ newitem->prev->next = newitem;
+ }
+}
+void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
+{
+ cJSON *c = array->child;
+ while (c && which > 0) {
+ c = c->next, which--;
+ }
+ if (!c) {
+ return;
+ }
+ newitem->next = c->next;
+ newitem->prev = c->prev;
+ if (newitem->next) {
+ newitem->next->prev = newitem;
+ }
+ if (c == array->child) {
+ array->child = newitem;
+ } else {
+ newitem->prev->next = newitem;
+ }
+ c->next = c->prev = 0;
+ cJSON_Delete(c);
+}
+void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
+{
+ int i = 0;
+ cJSON *c = object->child;
+ while (c && cJSON_strcasecmp(c->string, string)) {
+ i++, c = c->next;
+ }
+ if (c) {
+ newitem->string = cJSON_strdup(string);
+ cJSON_ReplaceItemInArray(object, i, newitem);
+ }
+}
+
+/* Create basic types: */
+cJSON *cJSON_CreateNull(void)
+{
+ cJSON *item = cJSON_New_Item();
+ if (item) {
+ item->type = cJSON_NULL;
+ }
+ return item;
+}
+cJSON *cJSON_CreateTrue(void)
+{
+ cJSON *item = cJSON_New_Item();
+ if (item) {
+ item->type = cJSON_True;
+ }
+ return item;
+}
+cJSON *cJSON_CreateFalse(void)
+{
+ cJSON *item = cJSON_New_Item();
+ if (item) {
+ item->type = cJSON_False;
+ }
+ return item;
+}
+cJSON *cJSON_CreateBool(int b)
+{
+ cJSON *item = cJSON_New_Item();
+ if (item) {
+ item->type = b ? cJSON_True : cJSON_False;
+ }
+ return item;
+}
+cJSON *cJSON_CreateNumber(double num)
+{
+ cJSON *item = cJSON_New_Item();
+ if (item) {
+ item->type = cJSON_Number;
+ item->valuedouble = num;
+ item->valueint = (int)num;
+ }
+ return item;
+}
+cJSON *cJSON_CreateString(const char *string)
+{
+ cJSON *item = cJSON_New_Item();
+ if (item) {
+ item->type = cJSON_String;
+ item->valuestring = cJSON_strdup(string);
+ }
+ return item;
+}
+cJSON *cJSON_CreateArray(void)
+{
+ cJSON *item = cJSON_New_Item();
+ if (item) {
+ item->type = cJSON_Array;
+ }
+ return item;
+}
+cJSON *cJSON_CreateObject(void)
+{
+ cJSON *item = cJSON_New_Item();
+ if (item) {
+ item->type = cJSON_Object;
+ }
+ return item;
+}
+
+/* Create Arrays: */
+cJSON *cJSON_CreateIntArray(const int *numbers, int count)
+{
+ int i;
+ cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
+ for (i = 0; a && i < count; i++) {
+ n = cJSON_CreateNumber(numbers[i]);
+ if (!i) {
+ a->child = n;
+ } else {
+ suffix_object(p, n);
+ }
+ p = n;
+ }
+ return a;
+}
+cJSON *cJSON_CreateFloatArray(const float *numbers, int count)
+{
+ int i;
+ cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
+ for (i = 0; a && i < count; i++) {
+ n = cJSON_CreateNumber(numbers[i]);
+ if (!i) {
+ a->child = n;
+ } else {
+ suffix_object(p, n);
+ }
+ p = n;
+ }
+ return a;
+}
+cJSON *cJSON_CreateDoubleArray(const double *numbers, int count)
+{
+ int i;
+ cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
+ for (i = 0; a && i < count; i++) {
+ n = cJSON_CreateNumber(numbers[i]);
+ if (!i) {
+ a->child = n;
+ } else {
+ suffix_object(p, n);
+ }
+ p = n;
+ }
+ return a;
+}
+cJSON *cJSON_CreateStringArray(const char **strings, int count)
+{
+ int i;
+ cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
+ for (i = 0; a && i < count; i++) {
+ n = cJSON_CreateString(strings[i]);
+ if (!i) {
+ a->child = n;
+ } else {
+ suffix_object(p, n);
+ }
+ p = n;
+ }
+ return a;
+}
+
+/* Duplication */
+cJSON *cJSON_Duplicate(cJSON *item, int recurse)
+{
+ cJSON *newitem, *cptr, *nptr = 0, *newchild;
+ /* Bail on bad ptr */
+ if (!item) {
+ return 0;
+ }
+ /* Create new item */
+ newitem = cJSON_New_Item();
+ if (!newitem) {
+ return 0;
+ }
+ /* Copy over all vars */
+ newitem->type = item->type & (~cJSON_IsReference), newitem->valueint = item->valueint, newitem->valuedouble = item->valuedouble;
+ if (item->valuestring) {
+ newitem->valuestring = cJSON_strdup(item->valuestring);
+ if (!newitem->valuestring) {
+ cJSON_Delete(newitem);
+ return 0;
+ }
+ }
+ if (item->string) {
+ newitem->string = cJSON_strdup(item->string);
+ if (!newitem->string) {
+ cJSON_Delete(newitem);
+ return 0;
+ }
+ }
+ /* If non-recursive, then we're done! */
+ if (!recurse) {
+ return newitem;
+ }
+ /* Walk the ->next chain for the child. */
+ cptr = item->child;
+ while (cptr) {
+ newchild = cJSON_Duplicate(cptr, 1); /* Duplicate (with recurse) each item in the ->next chain */
+ if (!newchild) {
+ cJSON_Delete(newitem);
+ return 0;
+ }
+ if (nptr) {
+ nptr->next = newchild, newchild->prev = nptr; /* If newitem->child already set, then crosswire ->prev and ->next and move on */
+ nptr = newchild;
+ } else {
+ newitem->child = newchild; /* Set newitem->child and move to it */
+ nptr = newchild;
+ }
+ cptr = cptr->next;
+ }
+ return newitem;
+}
+
+void cJSON_Minify(char *json)
+{
+ char *into = json;
+ while (*json) {
+ if (*json == ' ') {
+ json++;
+ } else if (*json == '\t') {
+ json++; /* Whitespace characters. */
+ } else if (*json == '\r') {
+ json++;
+ } else if (*json == '\n') {
+ json++;
+ } else if (*json == '/' && json[1] == '/') while (*json && *json != '\n') {
+ json++; /* double-slash comments, to end of line. */
+ } else if (*json == '/' && json[1] == '*') {
+ while (*json && !(*json == '*' && json[1] == '/')) {
+ json++; /* multiline comments. */
+ }
+ json += 2;
+ } else if (*json == '\"') {
+ *into++ = *json++; /* string literals, which are \" sensitive. */
+ while (*json && *json != '\"') {
+ if (*json == '\\') {
+ *into++ = *json++;
+ }*into++ = *json++;
+ }*into++ = *json++;
+ } else {
+ *into++ = *json++; /* All other characters. */
+ }
+ }
+ *into = 0; /* and null-terminate. */
+}
diff --git a/apps/common/cJSON/cJSON.h b/apps/common/cJSON/cJSON.h
new file mode 100644
index 0000000..5daf5a2
--- /dev/null
+++ b/apps/common/cJSON/cJSON.h
@@ -0,0 +1,150 @@
+
+/*
+ Copyright (c) 2009 Dave Gamble
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef cJSON__h
+#define cJSON__h
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* cJSON Types: */
+#define cJSON_False 0
+#define cJSON_True 1
+#define cJSON_NULL 2
+#define cJSON_Number 3
+#define cJSON_String 4
+#define cJSON_Array 5
+#define cJSON_Object 6
+
+#define cJSON_IsReference 256
+#define cJSON_StringIsConst 512
+
+/* The cJSON structure: */
+typedef struct cJSON {
+ struct cJSON *next, *prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
+ struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
+
+ int type; /* The type of the item, as above. */
+
+ char *valuestring; /* The item's string, if type==cJSON_String */
+ int valueint; /* The item's number, if type==cJSON_Number */
+ double valuedouble; /* The item's number, if type==cJSON_Number */
+
+ char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
+} cJSON;
+
+typedef struct cJSON_Hooks {
+ void *(*malloc_fn)(size_t sz);
+ void (*free_fn)(void *ptr);
+} cJSON_Hooks;
+
+/* Supply malloc, realloc and free functions to cJSON */
+extern void cJSON_InitHooks(cJSON_Hooks *hooks);
+
+
+/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
+extern cJSON *cJSON_Parse(const char *value);
+/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
+extern char *cJSON_Print(cJSON *item);
+/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
+extern char *cJSON_PrintUnformatted(cJSON *item);
+/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
+extern char *cJSON_PrintBuffered(cJSON *item, int prebuffer, int fmt);
+/* Delete a cJSON entity and all subentities. */
+extern void cJSON_Delete(cJSON *c);
+
+/* Returns the number of items in an array (or object). */
+extern int cJSON_GetArraySize(cJSON *array);
+/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
+extern cJSON *cJSON_GetArrayItem(cJSON *array, int item);
+/* Get item "string" from object. Case insensitive. */
+extern cJSON *cJSON_GetObjectItem(cJSON *object, const char *string);
+
+/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
+extern const char *cJSON_GetErrorPtr(void);
+
+/* These calls create a cJSON item of the appropriate type. */
+extern cJSON *cJSON_CreateNull(void);
+extern cJSON *cJSON_CreateTrue(void);
+extern cJSON *cJSON_CreateFalse(void);
+extern cJSON *cJSON_CreateBool(int b);
+extern cJSON *cJSON_CreateNumber(double num);
+extern cJSON *cJSON_CreateString(const char *string);
+extern cJSON *cJSON_CreateArray(void);
+extern cJSON *cJSON_CreateObject(void);
+
+/* These utilities create an Array of count items. */
+extern cJSON *cJSON_CreateIntArray(const int *numbers, int count);
+extern cJSON *cJSON_CreateFloatArray(const float *numbers, int count);
+extern cJSON *cJSON_CreateDoubleArray(const double *numbers, int count);
+extern cJSON *cJSON_CreateStringArray(const char **strings, int count);
+
+/* Append item to the specified array/object. */
+extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
+extern void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
+extern void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
+/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
+extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+extern void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
+
+/* Remove/Detatch items from Arrays/Objects. */
+extern cJSON *cJSON_DetachItemFromArray(cJSON *array, int which);
+extern void cJSON_DeleteItemFromArray(cJSON *array, int which);
+extern cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string);
+extern void cJSON_DeleteItemFromObject(cJSON *object, const char *string);
+
+/* Update array items. */
+extern void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
+extern void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
+extern void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem);
+
+/* Duplicate a cJSON item */
+extern cJSON *cJSON_Duplicate(cJSON *item, int recurse);
+/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
+need to be released. With recurse!=0, it will duplicate any children connected to the item.
+The item->next and ->prev pointers are always zero on return from Duplicate. */
+
+/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
+extern cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated);
+
+extern void cJSON_Minify(char *json);
+
+/* Macros for creating things quickly. */
+#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
+#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
+#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
+#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
+#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
+#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
+
+/* When assigning an integer value, it needs to be propagated to valuedouble too. */
+#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
+#define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/apps/common/config/app_config.c b/apps/common/config/app_config.c
new file mode 100644
index 0000000..b2e447f
--- /dev/null
+++ b/apps/common/config/app_config.c
@@ -0,0 +1,121 @@
+#include "system/includes.h"
+#include "app_config.h"
+#include "config/config_interface.h"
+
+#define LOG_TAG "[APP-CONFIG]"
+#define LOG_ERROR_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#include "debug.h"
+
+
+extern void dec_eq_test();
+static int sdfile_test(const char *name);
+int jl_cfg_dec_test(void);
+
+ci_transport_config_uart_t config = {
+ CI_TRANSPORT_CONFIG_UART,
+ 115200,
+ 0,
+ 0,
+ NULL,
+};
+
+#if (TCFG_ONLINE_ENABLE || TCFG_CFG_TOOL_ENABLE)
+#if TCFG_COMM_TYPE == TCFG_UART_COMM
+void config_online_init()
+{
+ log_info("-------online Config Start-------");
+ config_layer_init(ci_transport_uart_instance(), &config);
+}
+__initcall(config_online_init);
+#endif
+#endif
+
+void config_test(void)
+{
+
+#if 1
+ log_info("-------EQ online Config Start-------");
+
+ sys_clk_set(SYS_48M);
+
+ //Setup dev input
+ config_layer_init(ci_transport_uart_instance(), &config);
+
+ dec_eq_test();
+ while (1) {
+ extern void clr_wdt();
+ clr_wdt();
+ }
+#endif
+
+#if 0
+ log_info("-------SDFile test Start------");
+
+#ifdef SDFILE_DEV
+
+#define SDFILE_NAME1 SDFILE_ROOT_PATH"xx.bin"
+
+ void *mnt = mount(SDFILE_DEV, SDFILE_MOUNT_PATH, "jlfs", 0, NULL);
+ if (mnt == NULL) {
+ log_error("mount jlfs failed");
+ }
+
+ sdfile_test(SDFILE_NAME1);
+
+#endif /*SDFILE_DEV*/
+
+#endif
+
+#if 0
+ log_info("--------JL CFG test Start------");
+
+ jl_cfg_dec_test();
+#endif
+ while (1);
+}
+
+static int sdfile_test(const char *name)
+{
+ log_d("SDFILE file path: %s", name);
+ FILE *fp = NULL;
+ u8 buf[16];
+ u8 len;
+
+ fp = fopen(name, "r");
+ if (!fp) {
+ log_d("sdfile open file ERR!");
+ return -1;
+ }
+
+ len = fread(fp, buf, sizeof(buf));
+
+ if (len != sizeof(buf)) {
+ log_d("0-read file ERR!");
+ goto _end;
+ }
+
+ put_buf(buf, sizeof(buf));
+
+ fseek(fp, 16, SEEK_SET);
+
+ len = fread(fp, buf, sizeof(buf));
+
+ if (len != sizeof(buf)) {
+ log_d("1-read file ERR!");
+ goto _end;
+ }
+
+ put_buf(buf, sizeof(buf));
+
+ log_d("SDFILE ok!");
+
+_end:
+ if (fp) {
+ fclose(fp);
+ }
+
+
+ return 0;
+}
diff --git a/apps/common/config/bt_profile_config.c b/apps/common/config/bt_profile_config.c
new file mode 100644
index 0000000..e937076
--- /dev/null
+++ b/apps/common/config/bt_profile_config.c
@@ -0,0 +1,216 @@
+#include "system/includes.h"
+#include "app_config.h"
+#include "btcontroller_config.h"
+#include "btstack/bt_profile_config.h"
+#include "bt_common.h"
+
+#define LOG_TAG "[BT-CFG]"
+#define LOG_ERROR_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#include "debug.h"
+
+
+#if TCFG_APP_BT_EN
+
+typedef struct {
+ // linked list - assert: first field
+ void *offset_item;
+
+ // data is contained in same memory
+ u32 service_record_handle;
+ u8 *service_record;
+} service_record_item_t;
+
+extern const u8 sdp_pnp_service_data[];
+extern const u8 sdp_a2dp_service_data[];
+extern const u8 sdp_avctp_ct_service_data[];
+extern const u8 sdp_avctp_ta_service_data[];
+extern const u8 sdp_hfp_service_data[];
+extern const u8 sdp_spp_service_data[];
+extern const u8 sdp_hid_service_data[];
+extern service_record_item_t sdp_record_item_begin[];
+extern service_record_item_t sdp_record_item_end[];
+
+#define SDP_RECORD_HANDLER_REGISTER(handler) \
+ const service_record_item_t handler \
+ sec(.sdp_record_item)
+
+#if TCFG_USER_BLE_ENABLE
+
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV)
+const int config_stack_modules = (BT_BTSTACK_CLASSIC | BT_BTSTACK_LE_ADV);
+#else
+const int config_stack_modules = BT_BTSTACK_CLASSIC | BT_BTSTACK_LE;
+#endif
+
+#else
+const int config_stack_modules = BT_BTSTACK_CLASSIC;
+#endif
+
+#if (USER_SUPPORT_PROFILE_PNP==1)
+SDP_RECORD_HANDLER_REGISTER(pnp_sdp_record_item) = {
+ .service_record = (u8 *)sdp_pnp_service_data,
+ .service_record_handle = 0x1000A,
+};
+#endif
+
+#if (USER_SUPPORT_PROFILE_A2DP==1)
+u8 a2dp_profile_support = 1;
+SDP_RECORD_HANDLER_REGISTER(a2dp_sdp_record_item) = {
+ .service_record = (u8 *)sdp_a2dp_service_data,
+ .service_record_handle = 0x00010001,
+};
+#endif
+#if (USER_SUPPORT_PROFILE_AVCTP==1)
+u8 acp_profile_support = 1;
+SDP_RECORD_HANDLER_REGISTER(arp_ct_sdp_record_item) = {
+ .service_record = (u8 *)sdp_avctp_ct_service_data,
+ .service_record_handle = 0x00010002,
+};
+#if BT_SUPPORT_MUSIC_VOL_SYNC
+SDP_RECORD_HANDLER_REGISTER(arp_ta_sdp_record_item) = {
+ .service_record = (u8 *)sdp_avctp_ta_service_data,
+ .service_record_handle = 0x00010005,
+};
+#endif
+#endif
+#if (USER_SUPPORT_PROFILE_HFP==1)
+u8 hfp_profile_support = 1;
+SDP_RECORD_HANDLER_REGISTER(hfp_sdp_record_item) = {
+ .service_record = (u8 *)sdp_hfp_service_data,
+ .service_record_handle = 0x00010003,
+};
+#endif
+#if (USER_SUPPORT_PROFILE_SPP==1)
+
+u8 spp_up_profile_support = 1;
+//FE010000-1234-5678-ABCD-00805F9B34FB
+const u8 sdp_user_spp_service_data[96] = {
+ 0x36, 0x00, 0x5B, 0x09, 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x11, 0x09, 0x00, 0x01, 0x36, 0x00,
+ 0x11, 0x1C, 0xfe, 0x01, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0xab, 0xcd, 0x00, 0x80, 0x5F, 0x9b,
+ 0x34, 0xfb, 0x09, 0x00, 0x04, 0x36, 0x00, 0x0E, 0x36, 0x00, 0x03, 0x19, 0x01, 0x00, 0x36, 0x00,
+ 0x05, 0x19, 0x00, 0x03, 0x08, 0x0a, 0x09, 0x00, 0x09, 0x36, 0x00, 0x17, 0x36, 0x00, 0x14, 0x1C,
+ 0xfe, 0x01, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0xab, 0xcd, 0x00, 0x80, 0x5F, 0x9b, 0x34, 0xfb,
+ 0x09, 0x01, 0x00, 0x09, 0x01, 0x00, 0x25, 0x06, 0x4A, 0x4C, 0x5F, 0x53, 0x50, 0x50, 0x00, 0x00,
+};
+SDP_RECORD_HANDLER_REGISTER(spp_user_sdp_record_item) = {
+ .service_record = (u8 *)sdp_user_spp_service_data,
+ .service_record_handle = 0x00010011,
+};
+
+u8 spp_profile_support = 1;
+SDP_RECORD_HANDLER_REGISTER(spp_sdp_record_item) = {
+ .service_record = (u8 *)sdp_spp_service_data,
+ .service_record_handle = 0x00010004,
+};
+
+#endif
+#if (USER_SUPPORT_PROFILE_HID==1)
+u8 hid_profile_support = 1;
+SDP_RECORD_HANDLER_REGISTER(hid_sdp_record_item) = {
+ .service_record = (u8 *)sdp_hid_service_data,
+ .service_record_handle = 0x00010006,
+};
+#endif
+#if (USER_SUPPORT_PROFILE_PBAP==1)
+extern const u8 sdp_pbap_service_data[];
+u8 pbap_profile_support = 1;
+SDP_RECORD_HANDLER_REGISTER(pbap_sdp_record_item) = {
+ .service_record = (u8 *)sdp_pbap_service_data,
+ .service_record_handle = 0x00010008,
+};
+#endif
+#if (USER_SUPPORT_PROFILE_MAP==1)
+extern const u8 sdp_map_mce_service_data[];
+u8 map_profile_support = 1;
+SDP_RECORD_HANDLER_REGISTER(map_sdp_record_item) = {
+ .service_record = (u8 *)sdp_map_mce_service_data,
+ .service_record_handle = 0x00010009,
+};
+#endif
+
+/*注意hid_conn_depend_on_dev_company置1之后,安卓手机会默认断开HID连接 */
+/*注意hid_conn_depend_on_dev_company置2之后,默认不断开HID连接 */
+const u8 hid_conn_depend_on_dev_company = 1;
+const u8 sdp_get_remote_pnp_info = 0;
+
+#ifdef CONFIG_256K_FLASH
+const u8 pbg_support_enable = 0;
+const u8 adt_profile_support = 0;
+const u8 more_hfp_cmd_support = 0;
+#else
+
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV)
+const u8 pbg_support_enable = 1;
+const u8 adt_profile_support = 1;
+#else
+const u8 pbg_support_enable = 0;
+const u8 adt_profile_support = 0;
+#endif
+
+const u8 more_hfp_cmd_support = 1;
+
+#endif
+
+#if (TCFG_BD_NUM == 2)
+const u8 a2dp_mutual_support = 1;
+const u8 more_addr_reconnect_support = 1;
+#if USER_SUPPORT_DUAL_A2DP_SOURCE
+const u8 more_avctp_cmd_support = 0;
+#else
+const u8 more_avctp_cmd_support = 1;
+#endif
+#else
+const u8 a2dp_mutual_support = 0;
+const u8 more_addr_reconnect_support = 0;
+#if ((RCSP_ADV_EN || SMART_BOX_EN) && JL_EARPHONE_APP_EN)
+const u8 more_avctp_cmd_support = 1;
+#else
+const u8 more_avctp_cmd_support = 0;
+#endif
+#endif
+#if TCFG_USER_EMITTER_ENABLE
+const u8 hci_inquiry_support = 1;
+const u8 btstack_emitter_support = 1; /*定义用于优化代码编译*/
+
+#if USER_SUPPORT_PROFILE_A2DP
+const u8 emitter_hfp_hf_support = 0; /*置1时做发射器连接手机时只支持hfp*/
+#else
+const u8 emitter_hfp_hf_support = 1; /*置1时做发射器连接手机时只支持hfp*/
+#endif
+
+extern const u8 sdp_a2dp_source_service_data[];
+
+#if (USER_SUPPORT_PROFILE_A2DP==0)
+u8 a2dp_profile_support = 2;
+#endif
+
+SDP_RECORD_HANDLER_REGISTER(a2dp_src_sdp_record_item) = {
+ .service_record = (u8 *)sdp_a2dp_source_service_data,
+ .service_record_handle = 0x0001000B,
+};
+#if (USER_SUPPORT_PROFILE_HFP_AG==1)
+extern const u8 sdp_hfp_ag_service_data[];
+u8 hfp_ag_profile_support = 1;
+SDP_RECORD_HANDLER_REGISTER(hfp_ag_sdp_record_item) = {
+ .service_record = (u8 *)sdp_hfp_ag_service_data,
+ .service_record_handle = 0x00010008,
+};
+#endif
+#else
+const u8 hci_inquiry_support = 0;
+const u8 btstack_emitter_support = 0; /*定义用于优化代码编译*/
+#endif
+/*u8 l2cap_debug_enable = 0xf0;
+u8 rfcomm_debug_enable = 0xf;
+u8 profile_debug_enable = 0xff;
+u8 ble_debug_enable = 0xff;
+u8 btstack_tws_debug_enable = 0xf;*/
+
+#else
+const u8 btstack_emitter_support = 1; /*定义用于优化代码编译*/
+const u8 a2dp_mutual_support = 1;
+const u8 adt_profile_support = 0;
+const u8 pbg_support_enable = 0;
+#endif
diff --git a/apps/common/config/ci_transport_uart.c b/apps/common/config/ci_transport_uart.c
new file mode 100644
index 0000000..e2352d9
--- /dev/null
+++ b/apps/common/config/ci_transport_uart.c
@@ -0,0 +1,370 @@
+#include "system/includes.h"
+#include "config/config_interface.h"
+#include "system/event.h"
+#include "app_online_cfg.h"
+#include "asm/uart_dev.h"
+#include "app_config.h"
+#include "asm/crc16.h"
+
+#define LOG_TAG "[CI-UART]"
+/* #define LOG_ERROR_ENABLE */
+/* #define LOG_INFO_ENABLE */
+/* #define LOG_DUMP_ENABLE */
+#include "debug.h"
+
+#if (TCFG_ONLINE_ENABLE || TCFG_CFG_TOOL_ENABLE)
+struct config_uart {
+ u32 baudrate;
+ int flowcontrol;
+ const char *dev_name;
+};
+
+struct uart_hdl {
+
+ struct config_uart config;
+
+ uart_bus_t *udev;
+ void *dbuf;
+
+ void *pRxBuffer;
+
+ u8 ucRxIndex;
+ u8 rx_type;
+
+ u16 data_length;
+
+ void *pTxBuffer;
+
+ void (*packet_handler)(const u8 *packet, int size);
+};
+
+
+typedef struct {
+ //head
+ u16 preamble;
+ u8 type;
+ u16 length;
+ u8 crc8;
+ u16 crc16;
+ u8 payload[0];
+} _GNU_PACKED_ uart_packet_t;
+
+#define UART_FORMAT_HEAD sizeof(uart_packet_t)
+
+typedef struct {
+ //head
+ u16 preamble0;
+ u8 preamble1;
+ u16 crc16;
+ u8 length;
+ u8 type;
+ u8 sq;
+ u8 payload[0];
+} _GNU_PACKED_ uart_tool_packet_t;
+
+#define UART_TOOL_FORMAT_HEAD sizeof(uart_tool_packet_t)
+
+static void dummy_handler(const u8 *packet, int size);
+
+#define UART_PREAMBLE 0xBED6
+#define UART_NEW_TOOL_PREAMBLE0 0xAA5A
+#define UART_NEW_TOOL_PREAMBLE1 0xA5
+
+#define UART_RX_SIZE 0x100
+#define UART_TX_SIZE 0x30
+#define UART_DB_SIZE 0x100
+#define UART_BAUD_RATE 115200
+
+#ifdef HAVE_MALLOC
+static struct uart_hdl *hdl;
+#define __this (hdl)
+#else
+static struct uart_hdl hdl;
+#define __this (&hdl)
+
+static u8 pRxBuffer_static[UART_RX_SIZE] __attribute__((aligned(4))); //rx memory
+static u8 pTxBuffer_static[UART_TX_SIZE] __attribute__((aligned(4))); //tx memory
+static u8 devBuffer_static[UART_DB_SIZE] __attribute__((aligned(4))); //dev DMA memory
+#endif
+
+s16 get_ci_tx_size()
+{
+ return UART_TX_SIZE;
+}
+static u8 procotol = 0;
+void ci_data_rx_handler(u8 type)
+{
+ u16 crc16;
+ uart_tool_packet_t *p_newtool;
+ uart_packet_t *p;
+
+ __this->rx_type = type;
+
+ if (type == CI_UART && __this->udev) {
+ __this->data_length += __this->udev->read(&__this->pRxBuffer[__this->data_length], (UART_RX_SIZE - __this->data_length), 0);//串口读取buf剩余空间的长度,实际长度比buf长,导致越界改写问题
+ }
+
+ /* log_info("Rx : %d", __this->data_length); */
+ /* log_info_hexdump(__this->pRxBuffer, __this->data_length); */
+ if (__this->data_length > UART_RX_SIZE) {
+ log_error("Wired");
+ }
+
+ u8 *tmp_buf = NULL;
+ tmp_buf = __this->pRxBuffer;
+ if (__this->data_length >= 2) {
+ unsigned i = 0;
+ for (i = 0; i < __this->data_length - 1; ++i) {
+ if ((tmp_buf[i] == 0x5A) && (tmp_buf[i + 1] == 0xAA) && (tmp_buf[i + 2] == 0xA5)) {
+ procotol = 1;
+ break;
+ } else if (tmp_buf[i] == 0xD6 && tmp_buf[i + 1] == 0xBE) {
+ procotol = 0;
+ break;
+ }
+ }
+ if (i != 0) {
+ __this->data_length -= i;
+ /* printf("__this->data_length %d i %d\n", __this->data_length, i); */
+ if (__this->data_length > 0) {
+ memmove(&__this->pRxBuffer[0], &tmp_buf[i], __this->data_length);
+ }
+ }
+ }
+
+ if (procotol) {
+ if (__this->data_length <= UART_TOOL_FORMAT_HEAD) {
+ return;
+ }
+ p_newtool = __this->pRxBuffer;
+
+ if ((p_newtool->preamble0 != UART_NEW_TOOL_PREAMBLE0) || (p_newtool->preamble1 != UART_NEW_TOOL_PREAMBLE1)) {
+ log_error("preamble err\n");
+ log_info_hexdump(__this->pRxBuffer, __this->data_length);
+ goto reset_buf;
+ }
+
+ if (__this->data_length >= p_newtool->length + 6) {
+ crc16 = crc_get_16bit(&p_newtool->length, p_newtool->length + 1);
+ /* log_info("CRC16 0x%x / 0x%x", crc16, p_newtool->crc16); */
+ if (p_newtool->crc16 != crc16) {
+ log_error("crc16 err\n");
+ goto reset_buf;
+ }
+ /* log_info_hexdump(p_newtool, p_newtool->length + 6); */
+ online_cfg_tool_data_deal(p_newtool, p_newtool->length + 6);
+ } else {
+ return;
+ }
+
+ } else {
+ if (__this->data_length <= UART_FORMAT_HEAD) {
+ return;
+ }
+ p = __this->pRxBuffer;
+
+ if (p->preamble != UART_PREAMBLE) {
+ log_info("preamble err\n");
+ log_info_hexdump(__this->pRxBuffer, __this->data_length);
+ goto reset_buf;
+ }
+
+ crc16 = crc_get_16bit(__this->pRxBuffer, UART_FORMAT_HEAD - 3);
+ /* log_info("CRC8 0x%x / 0x%x", crc16, p->crc8); */
+ if (p->crc8 != (crc16 & 0xff)) {
+ log_info("crc8 err\n");
+ goto reset_buf;
+ }
+ if (__this->data_length >= p->length + UART_FORMAT_HEAD) {
+ /* log_info("Total length : 0x%x / Rx length : 0x%x", __this->data_length, p->length + CI_FORMAT_HEAD); */
+ crc16 = crc_get_16bit(p->payload, p->length);
+ /* log_info("CRC16 0x%x / 0x%x", crc16, p->crc16); */
+ if (p->crc16 != crc16) {
+ log_info("crc16 err\n");
+ goto reset_buf;
+ }
+ __this->packet_handler(p->payload, p->length);
+ } else {
+ return;
+ }
+ }
+
+reset_buf:
+ __this->data_length = 0;
+}
+
+static void ci_uart_isr_cb(void *ut_bus, u32 status)
+{
+ if (status == UT_TX) {
+ return ;
+ }
+ struct sys_event e;
+ e.type = SYS_DEVICE_EVENT;
+ e.arg = (void *)DEVICE_EVENT_FROM_CI_UART;
+ e.u.dev.event = 0;
+ e.u.dev.value = 0;
+ sys_event_notify(&e);
+}
+
+static int ci_uart_init()
+{
+ struct uart_platform_data_t ut = {0};
+ ut.tx_pin = TCFG_ONLINE_TX_PORT;
+ ut.rx_pin = TCFG_ONLINE_RX_PORT;
+ ut.baud = __this->config.baudrate;
+ ut.rx_timeout = 1;
+ ut.isr_cbfun = ci_uart_isr_cb;
+ ut.rx_cbuf = devBuffer_static;
+ ut.rx_cbuf_size = UART_DB_SIZE;
+ ut.frame_length = UART_DB_SIZE;
+ /* JL_CLOCK->CLK_CON1 |= BIT(11); */
+ /* JL_CLOCK->CLK_CON1 &= ~BIT(10); */
+ __this->dbuf = devBuffer_static;
+ __this->data_length = 0;
+ __this->udev = (uart_bus_t *)uart_dev_open(&ut);
+ if (__this->udev == NULL) {
+ log_error("open uart dev err\n");
+ return -1;
+ }
+ return 0;
+}
+
+static void ci_uart_putbyte(char a)
+{
+ if (__this->udev) {
+ __this->udev->putbyte(a);
+ }
+}
+
+void ci_uart_write(char *buf, u16 len)
+{
+ if (__this->udev) {
+ __this->udev->write(buf, len);
+ }
+}
+
+static void dummy_handler(const u8 *packet, int size)
+{
+ log_error("Dummy");
+}
+
+static void clock_critical_enter(void)
+{
+
+}
+static void clock_critical_exit(void)
+{
+ if (__this->udev) {
+ __this->udev->set_baud(__this->config.baudrate);
+ }
+}
+CLOCK_CRITICAL_HANDLE_REG(ci, clock_critical_enter, clock_critical_exit)
+
+static void ci_dev_init(const void *config)
+{
+#ifdef HAVE_MALLOC
+ __this = malloc(sizeof(struct uart_hdl));
+ ASSERT(__this, "Fatal error");
+
+ memset(__this, 0x0, sizeof(struct uart_hdl));
+
+ __this->pRxBuffer = malloc(UART_RX_SIZE);
+ ASSERT(__this->pRxBuffer, "Fatal error");
+
+ __this->pTxBuffer = malloc(UART_TX_SIZE);
+ ASSERT(__this->pTxBuffer, "Fatal error");
+#else
+ log_info("Static");
+ __this->pRxBuffer = pRxBuffer_static;
+ __this->pTxBuffer = pTxBuffer_static;
+#endif
+
+ __this->packet_handler = dummy_handler;
+
+ ci_transport_config_uart_t *ci_config_uart = (ci_transport_config_uart_t *)config;
+
+ __this->config.baudrate = ci_config_uart->baudrate_init;
+ __this->config.flowcontrol = ci_config_uart->flowcontrol;
+ __this->config.dev_name = ci_config_uart->device_name;
+
+ log_info("baudrate : %d", __this->config.baudrate);
+ log_info("flowcontrol: %d", __this->config.flowcontrol);
+}
+
+static int ci_dev_open(void)
+{
+ ci_uart_init();
+ return 0;
+}
+
+static int ci_dev_close(void)
+{
+ return 0;
+}
+
+static void ci_dev_register_packet_handler(void (*handler)(const u8 *packet, int size))
+{
+ __this->packet_handler = handler;
+}
+
+static int ci_dev_send_packet(const u8 *packet, int size)
+{
+ /* dev_stream_out(); */
+ int i = 0;
+ uart_packet_t *p = (uart_packet_t *)__this->pTxBuffer;
+
+ p->preamble = UART_PREAMBLE;
+ p->type = 0;
+ p->length = size;
+ p->crc8 = CRC16(p, UART_FORMAT_HEAD - 3) & 0xff;
+ p->crc16 = CRC16(packet, size);
+
+ size += UART_FORMAT_HEAD;
+ /* ASSERT(size <= UART_TX_SIZE, "Fatal Error"); */
+ if (size > UART_TX_SIZE) {
+ log_e("Fatal Error");
+ return 0;
+ }
+
+ memcpy(p->payload, packet, size);
+
+ /* log_info("Tx : %d", size); */
+ /* log_info_hexdump(p, size); */
+ if (__this->rx_type == CI_UART) {
+#if 0
+ while (size--) {
+ ci_uart_putbyte(((char *)p)[i++]);
+ }
+#else
+ ci_uart_write(p, size);
+#endif
+ }
+
+ return 0;
+}
+
+static int ci_dev_can_send_packet_now(uint8_t packet_type)
+{
+ return 0;
+}
+
+// get dev api skeletons
+static const ci_transport_t ci_transport_uart = {
+ /* const char * name; */ "CI_UART",
+ /* void (*init) (const void *transport_config); */ &ci_dev_init,
+ /* int (*open)(void); */ &ci_dev_open,
+ /* int (*close)(void); */ &ci_dev_close,
+ /* void (*register_packet_handler)(void (*handler)(...); */ &ci_dev_register_packet_handler,
+ /* int (*can_send_packet_now)(uint8_t packet_type); */ &ci_dev_can_send_packet_now,
+ /* int (*send_packet)(...); */ &ci_dev_send_packet,
+};
+
+const ci_transport_t *ci_transport_uart_instance(void)
+{
+ return &ci_transport_uart;
+}
+
+
+
+#endif
+
diff --git a/apps/common/config/include/bt_profile_cfg.h b/apps/common/config/include/bt_profile_cfg.h
new file mode 100644
index 0000000..772dbca
--- /dev/null
+++ b/apps/common/config/include/bt_profile_cfg.h
@@ -0,0 +1,125 @@
+
+#ifndef _BT_PROFILE_CFG_H_
+#define _BT_PROFILE_CFG_H_
+
+#include "app_config.h"
+#include "btcontroller_modules.h"
+
+
+#if (TRANS_DATA_EN || RCSP_BTMATE_EN || RCSP_ADV_EN || SMART_BOX_EN || ANCS_CLIENT_EN || LL_SYNC_EN || TUYA_DEMO_EN)
+#ifndef BT_FOR_APP_EN
+#define BT_FOR_APP_EN 1
+#endif
+#else
+#ifndef BT_FOR_APP_EN
+#define BT_FOR_APP_EN 0
+#endif
+#ifndef AI_APP_PROTOCOL
+#define AI_APP_PROTOCOL 0
+#endif
+#endif
+
+
+///---sdp service record profile- 用户选择支持协议--///
+#if (BT_FOR_APP_EN || APP_ONLINE_DEBUG || AI_APP_PROTOCOL)
+#if (LL_SYNC_EN || TUYA_DEMO_EN)
+#undef USER_SUPPORT_PROFILE_SPP
+#define USER_SUPPORT_PROFILE_SPP 0
+#else
+#undef USER_SUPPORT_PROFILE_SPP
+#define USER_SUPPORT_PROFILE_SPP 1
+#endif
+#endif
+
+//ble demo的例子
+#define DEF_BLE_DEMO_NULL 0 //ble 没有使能
+#define DEF_BLE_DEMO_ADV 1 //only adv,can't connect
+#define DEF_BLE_DEMO_TRANS_DATA 2 //
+#define DEF_BLE_DEMO_RCSP_DEMO 4 //
+#define DEF_BLE_DEMO_ADV_RCSP 5
+#define DEF_BLE_DEMO_CLIENT 7 //
+#define DEF_BLE_ANCS_ADV 9
+#define DEF_BLE_DEMO_MULTI 11 //
+#define DEF_BLE_DEMO_LL_SYNC 13 //
+#define DEF_BLE_DEMO_WIRELESS_MIC_SERVER 14 //
+#define DEF_BLE_DEMO_WIRELESS_MIC_CLIENT 15 //
+#define DEF_BLE_DEMO_TUYA 16 //
+#define DEF_BLE_WL_MIC_1T1_TX 17
+#define DEF_BLE_WL_MIC_1T1_RX 18
+#define DEF_BLE_WL_MIC_1TN_TX 19
+#define DEF_BLE_WL_MIC_1TN_RX 20
+#define DEF_LE_AUDIO_CENTRAL 21
+#define DEF_LE_AUDIO_PERIPHERAL 22
+#define DEF_LE_AUDIO_BROADCASTER 23
+#define DEF_BLE_DEMO_HOGP 24
+
+#define LE_AUDIO_EN 0 //DEF_LE_AUDIO_CENTRAL
+
+//配置选择的demo
+#if TCFG_USER_BLE_ENABLE
+
+#if (SMART_BOX_EN | RCSP_BTMATE_EN)
+#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_RCSP_DEMO
+
+#elif TRANS_DATA_EN
+#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_TRANS_DATA
+
+#elif LL_SYNC_EN
+#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_LL_SYNC
+
+#elif TUYA_DEMO_EN
+#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_TUYA
+
+#elif RCSP_ADV_EN
+#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_ADV_RCSP
+
+#elif BLE_CLIENT_EN
+#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_CLIENT
+
+#elif TRANS_MULTI_BLE_EN
+#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_MULTI
+
+#elif ANCS_CLIENT_EN
+#define TCFG_BLE_DEMO_SELECT DEF_BLE_ANCS_ADV
+
+#elif AI_APP_PROTOCOL
+#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_NULL
+
+#elif (BLE_WIRELESS_CLIENT_EN)
+#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_WIRELESS_MIC_CLIENT
+
+#elif (BLE_WIRELESS_SERVER_EN)
+#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_WIRELESS_MIC_SERVER
+
+#elif (BLE_WIRELESS_1T1_TX_EN)
+#define TCFG_BLE_DEMO_SELECT DEF_BLE_WL_MIC_1T1_TX
+
+#elif (BLE_WIRELESS_1T1_RX_EN)
+#define TCFG_BLE_DEMO_SELECT DEF_BLE_WL_MIC_1T1_RX
+
+#elif (BLE_WIRELESS_1TN_TX_EN)
+#define TCFG_BLE_DEMO_SELECT DEF_BLE_WL_MIC_1TN_TX
+
+#elif (BLE_WIRELESS_1TN_RX_EN)
+#define TCFG_BLE_DEMO_SELECT DEF_BLE_WL_MIC_1TN_RX
+
+#elif (LE_AUDIO_EN)
+#define TCFG_BLE_DEMO_SELECT LE_AUDIO_EN
+
+#elif (BLE_HID_EN)
+#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_HOGP
+
+#else
+#define TCFG_BLE_DEMO_SELECT DEF_BLE5_DEMO
+#endif
+
+#else
+#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_NULL//ble is closed
+#endif
+
+//delete 2021-09-24;删除公共配置,放到各个profile自己配置
+// #define TCFG_BLE_SECURITY_EN 0 /*是否发请求加密命令*/
+
+
+
+#endif
diff --git a/apps/common/config/include/cfg_tool.h b/apps/common/config/include/cfg_tool.h
new file mode 100644
index 0000000..fefa338
--- /dev/null
+++ b/apps/common/config/include/cfg_tool.h
@@ -0,0 +1,242 @@
+#ifndef _APP_SOUND_BOX_
+#define _APP_SOUND_BOX_
+
+#include "typedef.h"
+#include "sdfile.h"
+#include "fs.h"
+#include "asm/sfc_norflash_api.h"
+#include "event.h"
+
+/*
+ * 波特率默认为 115200
+ * 对于物理串口,且是异步形式的协议,封包方式如下
+ *
+ * CRC是 CRC16(L + T + SQ + DATA)
+ * 其中,L是指(T+SQ+DATA)的长度
+ * DATA包含CMD与具体的数据流
+ *
+ * +----+----+----+--+--+---+---+----+---....---+
+ * | 5A | AA | A5 | CRC | L | T | SQ | DATA |
+ * +----+----+----+--+--+---+---+----+---....---+
+ *
+ * T 表示包的类型,其中
+ * 0x00 -- 表示回复,其中SQ是对应需要回应的包的序号
+ * 无论哪种模式下,回复包都用该种类型
+ * 0x12 -- 表示配置文件通道,是主动发送数据
+ * 例如,在配置工具中,PC往小机或者小机往PC主动发都用这个
+ */
+
+/*T 表示包的类型*/
+#define REPLY_STYLE 0x00 //无论哪种模式下,回复包都用该种类型
+#define INITIATIVE_STYLE 0x12 //主动发送数据的包用该类型
+#define SLAVE_ATIVE_SEND 0x01 //小机主动上发给PC
+#define EFF_CONFIG_ID 0x11 //调音
+/*
+ *0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | VERSION |AT| X| X| X| X| X| X| X| X| X| X| X|
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+#define PROTOCOL_VER_AT_NEW 0x0001 //使用新模式
+#define PROTOCOL_VER_AT_OLD 0x0011 //使用旧模式
+
+
+/*该文件所属文件ID为0*/
+#define CFG_TOOL_FILEID 0x00000000
+
+/*该文件所属文件ID为0*/
+#if ((defined CONFIG_NEW_CFG_TOOL_ENABLE) && ((defined CONFIG_SOUNDBOX) \
+ || (defined CONFIG_EARPHONE_CASE_ENABLE)))
+#define CFG_TOOL_FILE SDFILE_RES_ROOT_PATH"cfg_tool.bin"
+#else
+#define CFG_TOOL_FILE SDFILE_APP_ROOT_PATH"cfg_tool.bin"
+#endif
+
+/*旧调音工具eq文件所属文件ID为1*/
+#define CFG_OLD_EQ_FILEID 0x00000001
+#define CFG_OLD_EQ_FILE SDFILE_RES_ROOT_PATH"eq_cfg_hw.bin"
+
+/*旧调音工具混响文件所属文件ID为2*/
+#define CFG_OLD_EFFECT_FILEID 0x00000002
+#define CFG_OLD_EFFECT_FILE SDFILE_RES_ROOT_PATH"effects_cfg.bin"
+
+/*新调音工具eq文件所属文件ID为3*/
+#define CFG_EQ_FILEID 0x00000003
+#define CFG_EQ_FILE SDFILE_RES_ROOT_PATH"eq_cfg_hw.bin"
+
+/*****************************************************************/
+/****PC与小机使用到的CMD,CMD包含在DATA中,为DATA的第一个Byte*****/
+/*****************************************************************/
+
+#define ONLINE_SUB_OP_QUERY_BASIC_INFO 0x00000023 //查询固件的基本信息
+#define ONLINE_SUB_OP_QUERY_FILE_SIZE 0x0000000B //查询文件大小
+#define ONLINE_SUB_OP_QUERY_FILE_CONTENT 0x0000000C //读取文件内容
+#define ONLINE_SUB_OP_PREPARE_WRITE_FILE 0x00000022 //准备写入文件
+#define ONLINE_SUB_OP_READ_ADDR_RANGE 0x00000027 //读取地址范围内容
+#define ONLINE_SUB_OP_ERASE_ADDR_RANGE 0x00000024 //擦除地址范围内容
+#define ONLINE_SUB_OP_WRITE_ADDR_RANGE 0x00000025 //写入地址范围内容
+#define ONLINE_SUB_OP_ENTER_UPGRADE_MODE 0x00000026 //进入升级模式
+
+/*收到其他工具的数据*/
+#define DEFAULT_ACTION 0x000000FF //其他工具的数据
+
+/*****************************************************************/
+/*****小机接收PC的DATA,具体携带的数据,依据命令不同而不同**********/
+/*****************************************************************/
+
+//查询固件的基本信息
+typedef struct {
+ uint32_t cmd_id; //命令号,为0x23
+} R_QUERY_BASIC_INFO;
+
+//查询文件大小
+typedef struct {
+ uint32_t cmd_id; //命令号,为0x0B
+ uint32_t file_id; //查询的文件的ID,配置文件的ID为0
+} R_QUERY_FILE_SIZE;
+
+//读取文件内容
+typedef struct {
+ uint32_t cmd_id; //命令号,为0x0C
+ uint32_t file_id; //文件ID
+ uint32_t offset; //偏移
+ uint32_t size;
+} R_QUERY_FILE_CONTENT;
+
+//准备写入文件
+typedef struct {
+ uint32_t cmd_id; //命令号,为0x22
+ uint32_t file_id; //文件ID
+ uint32_t size; //文件大小
+} R_PREPARE_WRITE_FILE;
+
+//读取地址范围内容
+typedef struct {
+ uint32_t cmd_id; //命令号,为0x23
+ uint32_t addr; //flash的物理地址
+ uint32_t size; //读取的范围大小
+} R_READ_ADDR_RANGE;
+
+//擦除地址范围内容
+typedef struct {
+ uint32_t cmd_id; //命令号,为0x24
+ uint32_t addr; //起始地址
+ uint32_t size; //擦除大小
+} R_ERASE_ADDR_RANGE;
+
+//写入地址范围内容
+typedef struct {
+ uint32_t cmd_id; //命令号,为0x25
+ uint32_t addr; //物理地址
+ uint32_t size; //内容大小
+ /*uint8_t body[0];*/ //具体内容,大小为size
+} R_WRITE_ADDR_RANGE;
+
+//进入升级模式
+typedef struct {
+ uint32_t cmd_id; //命令号,为0x26
+} R_ENTER_UPGRADE_MODE;
+
+/*****************************************************************/
+/*******小机返回PC发送的DATA,具体的内容,依据命令不同而不同********/
+/*****************************************************************/
+
+//(1)查询固件的基本信息
+typedef struct {
+ uint16_t protocolVer; //协议版本,目前为1
+ char progCrc[32]; //固件的CRC,返回字符串,\0 结尾
+ char sdkName[32]; //SDK名字,\0 结尾
+ char pid[16]; //PID,\0 结尾(注意最长是16字节,16字节的时候,末尾不需要0)
+ char vid[16]; //VID,\0 结尾
+} S_QUERY_BASIC_INFO;
+
+//(2)查询文件大小
+typedef struct {
+ uint32_t file_size; //文件大小
+} S_QUERY_FILE_SIZE;
+
+//(3)读取文件内容
+/*
+ * 返回:具体的文件内容,长度为命令中的size参数
+ * 注:PC工具在获取配置文件的大小后,会自行决定拆分成几次命令读取
+ */
+
+//(4)准备写入文件
+/*
+ * 例如,cfg_tool.bin 本身的物理地址可能是 100,而擦除单元是 4K(4096),cfg_tool.bin 本身大小是 3999 字节,则
+ * file_addr = 100, file_size = 3999, earse_unit = 4096。
+ * 注意,接下来,PC 端会读取```[0, 8192)```这个范围的内容,修改掉```[100,4099]```的内容,然后再通过其他命令,
+ * 把```[0,8192)```这范围的内容写回去。
+ */
+typedef struct {
+ uint32_t file_addr; //配置文件真实物理地址
+ uint32_t file_size; //配置文件(cfg_tool.bin)本身的大小
+ uint32_t earse_unit; //flash 擦除单元(如 4K 的时候,填 4096)
+} S_PREPARE_WRITE_FILE;
+
+
+//(5)读取地址范围内容
+/*
+ * 返回:具体的文件内容,长度为命令中的size参数
+ * 注:PC工具在获取配置文件的大小后,会自行决定拆分成几次命令读取
+ */
+
+//(6)擦除地址范围内容
+/*
+ *返回两个字节的内容,"FA"或者"OK",表示失败或者成功
+ */
+
+//(7)写入地址范围内容
+/*
+ *返回两个字节的内容,"FA"或者"OK",表示失败或者成功
+ */
+
+//(8)进入升级模式
+/*
+ *小机收到命令后,进入升级模式
+ */
+
+/* --------------------------------------------------------------------------*/
+/**
+ * @brief usb或者串口收到的数据流通过这个接口传入进行数据解析
+ *
+ * @param buf 存储普通串口/USB收到的数据包
+ * @param len buf的长度(byte)
+ *
+ * @return
+ */
+/* --------------------------------------------------------------------------*/
+void online_cfg_tool_data_deal(void *buf, u32 len);
+
+/* --------------------------------------------------------------------------*/
+/**
+ * @brief 设备组装数据包并发送给PC工具,支持普通串口/USB串口/蓝牙SPP
+ *
+ * @param id 表示包的类型(不同的数据通道)
+ * @param sq 对应需要回应的包的序号
+ * @param buf 要发送的数据爆DATA部分
+ * @param len buf的长度(byte)
+ *
+ * @return
+ */
+/* --------------------------------------------------------------------------*/
+void all_assemble_package_send_to_pc(u8 id, u8 sq, u8 *buf, u32 len);
+
+int app_cfg_tool_event_handler(struct cfg_tool_event *cfg_tool_dev);
+
+struct tool_interface {
+ u8 id;//通道
+ void (*tool_message_deal)(u8 *buf, u32 len);//数据处理接口
+};
+
+#define REGISTER_DETECT_TARGET(interface) \
+ static struct tool_interface interface sec(.tool_interface)
+
+extern struct tool_interface tool_interface_begin[];
+extern struct tool_interface tool_interface_end[];
+
+#define list_for_each_tool_interface(p) \
+ for (p = tool_interface_begin; p < tool_interface_end; p++)
+
+#endif
+
diff --git a/apps/common/config/new_cfg_tool.c b/apps/common/config/new_cfg_tool.c
new file mode 100644
index 0000000..4802b9e
--- /dev/null
+++ b/apps/common/config/new_cfg_tool.c
@@ -0,0 +1,599 @@
+#include "cfg_tool.h"
+#include "event.h"
+#include "usb/device/cdc.h"
+#include "boot.h"
+#include "ioctl_cmds.h"
+#include "board_config.h"
+#include "app_online_cfg.h"
+#include "asm/crc16.h"
+#include "app_config.h"
+#include "config/config_target.h"
+#if APP_ONLINE_DEBUG
+#include "online_db_deal.h"
+#endif/*APP_ONLINE_DEBUG*/
+
+/*
+ *调音工具在线保存功能由协议接管,通道使用0x12,不分发给调音处理
+ *配置工具通道为0x12,调音工具在线保存功能相关数据包通道必须设置为0x12
+ *new_cfg_tool.c适用于新耳机/音箱配置工具和调音工具在线保存功能
+ *支持异步协议和蓝牙SPP协议的数据解析与通信
+ */
+
+#define LOG_TAG_CONST APP_CFG_TOOL
+#define LOG_TAG "[APP_CFG_TOOL]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+struct cfg_tool_info {
+ /*PC往小机发送的DATA*/
+ R_QUERY_BASIC_INFO r_basic_info;
+ R_QUERY_FILE_SIZE r_file_size;
+ R_QUERY_FILE_CONTENT r_file_content;
+ R_PREPARE_WRITE_FILE r_prepare_write_file;
+ R_READ_ADDR_RANGE r_read_addr_range;
+ R_ERASE_ADDR_RANGE r_erase_addr_range;
+ R_WRITE_ADDR_RANGE r_write_addr_range;
+ R_ENTER_UPGRADE_MODE r_enter_upgrade_mode;
+
+ /*小机返回PC发送的DATA*/
+ S_QUERY_BASIC_INFO s_basic_info;
+ S_QUERY_FILE_SIZE s_file_size;
+ S_PREPARE_WRITE_FILE s_prepare_write_file;
+};
+
+static struct cfg_tool_info info = {
+ .s_basic_info.protocolVer = PROTOCOL_VER_AT_OLD,
+};
+
+#define TEMP_BUF_SIZE 256
+
+extern const char *sdk_version_info_get(void);
+extern u8 *sdfile_get_burn_code(u8 *len);
+extern int norflash_erase(u32 cmd, u32 addr);
+
+static u8 local_packet[TEMP_BUF_SIZE];
+const char error_return[] = "FA"; //表示失败
+const char ok_return[] = "OK"; //表示成功
+const char er_return[] = "ER"; //表示不能识别的命令
+static u32 size_total_write = 0;
+
+extern void doe(u16 k, void *pBuf, u32 lenIn, u32 addr);
+extern int norflash_erase(u32 cmd, u32 addr);
+
+#ifdef ALIGN
+#undef ALIGN
+#endif
+#define ALIGN(a, b) \
+ ({ \
+ int m = (u32)(a) & ((b)-1); \
+ int ret = (u32)(a) + (m?((b)-m):0); \
+ ret;\
+ })
+
+static u32 cfg_tool_encode_data_by_user_key(u16 key, u8 *buff, u16 size, u32 dec_addr, u8 dec_len)
+{
+ u16 key_addr;
+ u16 r_len;
+
+ while (size) {
+ r_len = (size > dec_len) ? dec_len : size;
+ key_addr = (dec_addr >> 2)^key;
+ doe(key_addr, buff, r_len, 0);
+ buff += r_len;
+ dec_addr += r_len;
+ size -= r_len;
+ }
+
+ return dec_addr;
+}
+
+static u8 parse_seq = 0;
+static void ci_send_packet_new(u32 id, u8 *packet, int size)
+{
+#if APP_ONLINE_DEBUG
+ app_online_db_ack(parse_seq, packet, size);
+#endif/*APP_ONLINE_DEBUG*/
+}
+
+struct cfg_tool_event spp_packet;
+int cfg_tool_online_parse(u8 *buf, u32 len)
+{
+ parse_seq = buf[2];
+ u32 event = (buf[3] | (buf[4] << 8) | (buf[5] << 16) | (buf[6] << 24));
+ spp_packet.event = event;
+ spp_packet.packet = buf;
+ spp_packet.size = len;
+ return (app_cfg_tool_event_handler(&spp_packet));
+}
+
+void all_assemble_package_send_to_pc(u8 id, u8 sq, u8 *buf, u32 len)
+{
+ u8 *send_buf = NULL;
+ u16 crc16_data;
+
+ send_buf = (u8 *)malloc(TEMP_BUF_SIZE);
+ if (send_buf == NULL) {
+ log_error("send_buf malloc err!");
+ return;
+ }
+
+ send_buf[0] = 0x5A;
+ send_buf[1] = 0xAA;
+ send_buf[2] = 0xA5;
+ send_buf[5] = 2 + len;/*L*/
+ send_buf[6] = id;/*T*/
+ send_buf[7] = sq;/*SQ*/
+ memcpy(send_buf + 8, buf, len);
+ /*添加CRC16*/
+ crc16_data = CRC16(&send_buf[5], len + 3);
+ send_buf[3] = crc16_data & 0xff;
+ send_buf[4] = (crc16_data >> 8) & 0xff;
+
+ /* printf_buf(send_buf, len + 8); */
+
+#if (TCFG_CFG_TOOL_ENABLE || TCFG_ONLINE_ENABLE)
+#if (TCFG_COMM_TYPE == TCFG_SPP_COMM)
+ ci_send_packet_new(INITIATIVE_STYLE, buf, len);
+#elif (TCFG_COMM_TYPE == TCFG_USB_COMM)
+ cdc_write_data(0, send_buf, len + 8);
+#elif (TCFG_COMM_TYPE == TCFG_UART_COMM)
+ ci_uart_write(send_buf, len + 8);
+#endif
+#endif
+
+ free(send_buf);
+}
+
+/*6个byte的校验码数组转为字符串*/
+void hex2text(u8 *buf, u8 *out)
+{
+ sprintf(out, "%02x%02x-%02x%02x%02x%02x", buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]);
+}
+
+u32 packet_combined(u8 *packet, u8 num)
+{
+ u32 _packet = 0;
+ _packet = (packet[num] | (packet[num + 1] << 8) | (packet[num + 2] << 16) | (packet[num + 3] << 24));
+ return _packet;
+}
+
+FILE *cfg_open_file(u32 file_id)
+{
+ FILE *cfg_fp = NULL;
+ if (file_id <= CFG_EQ_FILEID) {
+ if ((file_id == CFG_TOOL_FILEID)) {
+ cfg_fp = fopen(CFG_TOOL_FILE, "r");
+ log_info("open cfg_tool.bin\n");
+ } else if ((file_id == CFG_OLD_EQ_FILEID)) {
+ cfg_fp = fopen(CFG_OLD_EQ_FILE, "r");
+ log_info("open old eq_cfg_hw.bin\n");
+ } else if ((file_id == CFG_OLD_EFFECT_FILEID)) {
+ cfg_fp = fopen(CFG_OLD_EFFECT_FILE, "r");
+ log_info("open effects_cfg.bin\n");
+ } else if ((file_id == CFG_EQ_FILEID)) {
+ cfg_fp = fopen(CFG_EQ_FILE, "r");
+ log_info("open eq_cfg_hw.bin\n");
+ }
+ }
+ return cfg_fp;
+}
+
+extern void nvram_set_boot_state(u32 state);
+extern void hw_mmu_disable(void);
+extern void ram_protect_close(void);
+AT(.volatile_ram_code)
+void cfg_tool_go_mask_usb_updata()
+{
+ local_irq_disable();
+ ram_protect_close();
+ hw_mmu_disable();
+ nvram_set_boot_state(2);
+
+ JL_CLOCK->PWR_CON |= (1 << 4);
+ /* chip_reset(); */
+ /* cpu_reset(); */
+ while (1);
+}
+
+/*延时复位防止工具升级进度条显示错误*/
+static void delay_cpu_reset(void *priv)
+{
+ extern void cpu_reset();
+ cpu_reset();
+}
+
+int app_cfg_tool_event_handler(struct cfg_tool_event *cfg_tool_dev)
+{
+ u8 *buf = NULL;
+ u8 *buf_temp = NULL;
+ u8 *buf_temp_0 = NULL;
+ u8 valid_cmd;
+ u32 erase_cmd;
+ int write_len;
+ int send_len;
+ u8 crc_temp_len, sdkname_temp_len;
+ char proCrc_fw[32] = {0};
+ char sdkName_fw[32] = {0};
+ const struct tool_interface *p;
+ struct vfs_attr attr;
+ FILE *cfg_fp = NULL;
+
+ /* printf_buf(cfg_tool_dev->packet, cfg_tool_dev->size); */
+
+ buf = (u8 *)malloc(TEMP_BUF_SIZE);
+ if (buf == NULL) {
+ log_error("buf malloc err!");
+ return 0;
+ }
+ buf_temp_0 = (u8 *)malloc(TEMP_BUF_SIZE);
+ if (buf_temp_0 == NULL) {
+ free(buf);
+ log_error("buf_temp_0 malloc err!");
+ return 0;
+ }
+ buf_temp_0 = (u8 *)ALIGN(buf_temp_0, 4);
+ memset(buf_temp_0, 0, TEMP_BUF_SIZE);
+ memcpy(buf_temp_0 + 1, cfg_tool_dev->packet, cfg_tool_dev->size);
+
+ /*数据进行处理*/
+ list_for_each_tool_interface(p) {
+ if (p->id == cfg_tool_dev->packet[1]) {
+ p->tool_message_deal(buf_temp_0 + 2, cfg_tool_dev->size - 1);
+ free(buf_temp_0);
+ free(buf);
+ return 1;
+ }
+ }
+
+ memset(buf, 0, TEMP_BUF_SIZE);
+
+ switch (cfg_tool_dev->event) {
+ case ONLINE_SUB_OP_QUERY_BASIC_INFO:
+ valid_cmd = 1;
+ /* log_info("event_ONLINE_SUB_OP_QUERY_BASIC_INFO\n"); */
+ /*获取校验码*/
+ u8 *p = sdfile_get_burn_code(&crc_temp_len);
+ memcpy(info.s_basic_info.progCrc, p + 8, 6);
+ /* printf_buf(info.s_basic_info.progCrc, 6); */
+ hex2text(info.s_basic_info.progCrc, proCrc_fw);
+ /* log_info("crc:%s\n", proCrc_fw); */
+
+ /*获取固件版本信息*/
+ sdkname_temp_len = strlen(sdk_version_info_get());
+ memcpy(info.s_basic_info.sdkName, sdk_version_info_get(), sdkname_temp_len);
+ memcpy(sdkName_fw, info.s_basic_info.sdkName, sdkname_temp_len);
+ /* log_info("version:%s\n", sdk_version_info_get()); */
+
+ struct flash_head flash_head_for_pid_vid;
+
+ for (u8 i = 0; i < 5; i++) {
+ norflash_read(NULL, (u8 *)&flash_head_for_pid_vid, 32, 0x1000 * i);
+ doe(0xffff, (u8 *)&flash_head_for_pid_vid, 32, 0);
+ if (flash_head_for_pid_vid.crc == 0xffff) {
+ continue;
+ } else {
+ log_info("flash head addr = 0x%x\n", 0x1000 * i);
+ break;
+ }
+ }
+
+ struct flash_head _head;
+ struct flash_head *temp_p = &_head;
+ memcpy(temp_p, &flash_head_for_pid_vid, 32);
+
+ memset(info.s_basic_info.pid, 0, sizeof(info.s_basic_info.pid));
+ memcpy(info.s_basic_info.pid, temp_p->pid, sizeof(info.s_basic_info.pid));
+ for (u8 i = 0; i < sizeof(info.s_basic_info.pid); i++) {
+ if (~info.s_basic_info.pid[i] == 0x00) {
+ info.s_basic_info.pid[i] = 0x00;
+ }
+ }
+ /* printf_buf(info.s_basic_info.pid, 16); */
+
+ memset(info.s_basic_info.vid, 0, sizeof(info.s_basic_info.vid));
+ memcpy(info.s_basic_info.vid, temp_p->vid, 4);
+ /* printf_buf(info.s_basic_info.vid, 16); */
+
+ send_len = sizeof(info.s_basic_info.protocolVer) + sizeof(proCrc_fw) + sizeof(sdkName_fw) + 32;
+ buf[0] = info.s_basic_info.protocolVer & 0xff;
+ buf[1] = (info.s_basic_info.protocolVer >> 8) & 0xff;
+ memcpy(buf + 2, proCrc_fw, sizeof(proCrc_fw));
+ memcpy(buf + 2 + sizeof(proCrc_fw), sdkName_fw, sizeof(sdkName_fw));
+ memcpy(buf + 2 + sizeof(proCrc_fw) + sizeof(sdkName_fw), info.s_basic_info.pid, 16);
+ memcpy(buf + 2 + sizeof(proCrc_fw) + sizeof(sdkName_fw) + 16, info.s_basic_info.vid, 16);
+ break;
+ case ONLINE_SUB_OP_QUERY_FILE_SIZE:
+ valid_cmd = 1;
+ /* log_info("event_ONLINE_SUB_OP_QUERY_FILE_SIZE\n"); */
+ info.r_file_size.file_id = packet_combined(cfg_tool_dev->packet, 7);
+ cfg_fp = cfg_open_file(info.r_file_size.file_id);
+
+ if (cfg_fp == NULL) {
+ log_error("file open error!\n");
+ goto _exit_;
+ }
+ fget_attrs(cfg_fp, &attr);
+
+ /* log_info("file addr:%x,file size:%d\n", attr.sclust, attr.fsize); */
+ info.s_file_size.file_size = attr.fsize;
+
+ send_len = sizeof(info.s_file_size.file_size);//长度
+
+ /*小端格式*/
+ buf[3] = (info.s_file_size.file_size >> 24) & 0xff;
+ buf[2] = (info.s_file_size.file_size >> 16) & 0xff;
+ buf[1] = (info.s_file_size.file_size >> 8) & 0xff;
+ buf[0] = info.s_file_size.file_size & 0xff;
+
+ fclose(cfg_fp);
+ break;
+ case ONLINE_SUB_OP_QUERY_FILE_CONTENT:
+ valid_cmd = 1;
+ /* log_info("event_ONLINE_SUB_OP_QUERY_FILE_CONTENT\n"); */
+ info.r_file_content.file_id = packet_combined(cfg_tool_dev->packet, 7);
+ info.r_file_content.offset = packet_combined(cfg_tool_dev->packet, 11);
+ info.r_file_content.size = packet_combined(cfg_tool_dev->packet, 15);
+
+ cfg_fp = cfg_open_file(info.r_file_content.file_id);
+
+ if (cfg_fp == NULL) {
+ log_error("file open error!\n");
+ goto _exit_;
+ }
+ fget_attrs(cfg_fp, &attr);
+
+ /* log_info("file addr:%x,file size:%d\n", attr.sclust, attr.fsize); */
+ if (info.r_file_content.size > attr.fsize) {
+ fclose(cfg_fp);
+ log_error("reading size more than actual size!\n");
+ break;
+ }
+
+ /*逻辑地址转换成flash物理地址*/
+ u32 flash_addr = sdfile_cpu_addr2flash_addr(attr.sclust);
+ /* log_info("flash_addr:0x%x", flash_addr); */
+ /*读取文件内容*/
+ buf_temp = (char *)malloc(info.r_file_content.size);
+ norflash_read(NULL, (void *)buf_temp, info.r_file_content.size, flash_addr + info.r_file_content.offset);
+ /* printf_buf(buf_temp, info.r_file_content.size); */
+ send_len = info.r_file_content.size;
+ memcpy(buf, buf_temp, info.r_file_content.size);
+
+ if (buf_temp) {
+ free(buf_temp);
+ }
+ fclose(cfg_fp);
+ break;
+ case ONLINE_SUB_OP_PREPARE_WRITE_FILE:
+ valid_cmd = 1;
+ /* log_info("event_ONLINE_SUB_OP_PREPARE_WRITE_FILE\n"); */
+ info.r_prepare_write_file.file_id = packet_combined(cfg_tool_dev->packet, 7);
+ info.r_prepare_write_file.size = packet_combined(cfg_tool_dev->packet, 11);
+
+ cfg_fp = cfg_open_file(info.r_prepare_write_file.file_id);
+ if (cfg_fp == NULL) {
+ log_error("file open error!\n");
+ break;
+ }
+ fget_attrs(cfg_fp, &attr);
+
+ /* log_info("file addr:%x,file size:%d\n", attr.sclust, attr.fsize); */
+ if (info.r_prepare_write_file.size > attr.fsize) {
+ //fclose(cfg_fp);
+ //log_error("preparing to write size more than actual size!\n");
+ //break;
+ }
+
+ info.s_prepare_write_file.file_size = attr.fsize;
+ info.s_prepare_write_file.file_addr = sdfile_cpu_addr2flash_addr(attr.sclust);
+ info.s_prepare_write_file.earse_unit = boot_info.vm.align * 256;
+
+ send_len = sizeof(info.s_prepare_write_file.file_size) * 3;
+
+ buf[3] = (info.s_prepare_write_file.file_addr >> 24) & 0xff;
+ buf[2] = (info.s_prepare_write_file.file_addr >> 16) & 0xff;
+ buf[1] = (info.s_prepare_write_file.file_addr >> 8) & 0xff;
+ buf[0] = info.s_prepare_write_file.file_addr & 0xff;
+
+ buf[7] = (info.s_prepare_write_file.file_size >> 24) & 0xff;
+ buf[6] = (info.s_prepare_write_file.file_size >> 16) & 0xff;
+ buf[5] = (info.s_prepare_write_file.file_size >> 8) & 0xff;
+ buf[4] = info.s_prepare_write_file.file_size & 0xff;
+
+ buf[11] = (info.s_prepare_write_file.earse_unit >> 24) & 0xff;
+ buf[10] = (info.s_prepare_write_file.earse_unit >> 16) & 0xff;
+ buf[9] = (info.s_prepare_write_file.earse_unit >> 8) & 0xff;
+ buf[8] = info.s_prepare_write_file.earse_unit & 0xff;
+
+ fclose(cfg_fp);
+ break;
+ case ONLINE_SUB_OP_READ_ADDR_RANGE:
+ valid_cmd = 1;
+ /* log_info("event_ONLINE_SUB_OP_READ_ADDR_RANGE\n"); */
+ info.r_read_addr_range.addr = packet_combined(cfg_tool_dev->packet, 7);
+ /* log_info("reading flash addr:0x%x\n", info.r_read_addr_range.addr); */
+ info.r_read_addr_range.size = packet_combined(cfg_tool_dev->packet, 11);
+ /* log_info("reading size = %d\n", info.r_read_addr_range.size); */
+ buf_temp = (char *)malloc(info.r_read_addr_range.size);
+ norflash_read(NULL, (void *)buf_temp, info.r_read_addr_range.size, info.r_read_addr_range.addr);
+ /* printf_buf(buf_temp, info.r_read_addr_range.size); */
+
+ send_len = info.r_read_addr_range.size;
+ memcpy(buf, buf_temp, info.r_read_addr_range.size);
+
+ if (buf_temp) {
+ free(buf_temp);
+ }
+ break;
+ case ONLINE_SUB_OP_ERASE_ADDR_RANGE:
+ valid_cmd = 1;
+ /* log_info("event_ONLINE_SUB_OP_ERASE_ADDR_RANGE\n"); */
+ info.r_erase_addr_range.addr = packet_combined(cfg_tool_dev->packet, 7);
+ /* log_info("erasing flash start addr:0x%x\n", info.r_erase_addr_range.addr); */
+ /*要擦除的大小,会保证按earse_unit对齐,即总是erase_unit的倍数*/
+ info.r_erase_addr_range.size = packet_combined(cfg_tool_dev->packet, 11);
+ /* log_info("erasing size = %d\n", info.r_erase_addr_range.size); */
+ /* log_info("earse_unit = %d\n", info.s_prepare_write_file.earse_unit); */
+ switch (info.s_prepare_write_file.earse_unit) {
+ case 256:
+ erase_cmd = IOCTL_ERASE_PAGE;
+ break;
+ case (4*1024):
+ erase_cmd = IOCTL_ERASE_SECTOR;
+ break;
+ case (64*1024):
+ erase_cmd = IOCTL_ERASE_BLOCK;
+ break;
+defualt:
+ memcpy(buf, error_return, sizeof(error_return));
+ log_error("erase error!");
+ break;
+ }
+
+ for (u8 i = 0; i < (info.r_erase_addr_range.size / info.s_prepare_write_file.earse_unit); i ++) {
+ u8 ret = norflash_erase(erase_cmd, info.r_erase_addr_range.addr + (i * info.s_prepare_write_file.earse_unit));
+ if (ret) {
+ memcpy(buf, error_return, sizeof(error_return));
+ log_error("erase error!");
+ } else {
+ memcpy(buf, ok_return, sizeof(ok_return));
+ log_info("erase success");
+ }
+ }
+
+ send_len = sizeof(error_return);
+ break;
+ case ONLINE_SUB_OP_WRITE_ADDR_RANGE:
+ valid_cmd = 1;
+ /* log_info("event_ONLINE_SUB_OP_WRITE_ADDR_RANGE\n"); */
+ info.r_write_addr_range.addr = packet_combined(cfg_tool_dev->packet, 7);
+ info.r_write_addr_range.size = packet_combined(cfg_tool_dev->packet, 11);
+ /* log_info("writing flash start addr:0x%x\n", info.r_write_addr_range.addr); */
+ /* log_info("writing size = %d\n", info.r_write_addr_range.size); */
+ buf_temp = (char *)malloc(info.r_write_addr_range.size);
+ memcpy(buf_temp, cfg_tool_dev->packet + 15, info.r_write_addr_range.size);
+ /* printf_buf(buf_temp, info.r_write_addr_range.size); */
+
+ cfg_tool_encode_data_by_user_key(boot_info.chip_id, buf_temp, info.r_write_addr_range.size, info.r_write_addr_range.addr - boot_info.sfc.sfc_base_addr, 0x20);
+
+ write_len = norflash_write(NULL, buf_temp, info.r_write_addr_range.size, info.r_write_addr_range.addr);
+
+ /* norflash_read(NULL, buf_temp, info.r_write_addr_range.size, info.r_write_addr_range.addr); */
+ /* printf_buf(buf_temp, info.r_write_addr_range.size); */
+
+ if (write_len != info.r_write_addr_range.size) {
+ memcpy(buf, error_return, sizeof(error_return));
+ log_error("write error!");
+ } else {
+ memcpy(buf, ok_return, sizeof(ok_return));
+ }
+ send_len = sizeof(error_return);
+
+ if (buf_temp) {
+ free(buf_temp);
+ }
+
+ if (info.r_prepare_write_file.file_id == CFG_TOOL_FILEID) {
+ size_total_write += info.r_write_addr_range.size;
+ /* log_info("size_total_write = %d\n", size_total_write); */
+ /* log_info("erasing size = %d\n", info.r_erase_addr_range.size); */
+ if (size_total_write >= info.r_erase_addr_range.size) {
+ size_total_write = 0;
+ log_info("cpu_reset\n");
+ extern u16 sys_timeout_add(void *priv, void (*func)(void *priv), u32 msec);
+ sys_timeout_add(NULL, delay_cpu_reset, 500);
+ }
+ }
+ break;
+ case ONLINE_SUB_OP_ENTER_UPGRADE_MODE:
+ valid_cmd = 1;
+ log_info("event_ONLINE_SUB_OP_ENTER_UPGRADE_MODE\n");
+ cfg_tool_go_mask_usb_updata();
+ break;
+ default:
+ valid_cmd = 0;
+ log_error("invalid data\n");
+ memcpy(buf, er_return, sizeof(er_return));//不认识的命令返回ER
+ send_len = sizeof(er_return);
+ break;
+_exit_:
+ memcpy(buf, error_return, sizeof(error_return));//文件打开失败返回FA
+ send_len = sizeof(error_return);
+ break;
+ }
+
+ all_assemble_package_send_to_pc(REPLY_STYLE, cfg_tool_dev->packet[2], buf, send_len);
+
+ free(buf_temp_0);
+ free(buf);
+ return (valid_cmd);
+}
+
+void cfg_tool_event_to_user(u8 *packet, u32 type, u8 event, u8 size)
+{
+ struct sys_event e;
+ e.type = SYS_DEVICE_EVENT;
+ if (packet != NULL) {
+ if (size > sizeof(local_packet)) {
+ return;
+ }
+ e.u.cfg_tool.packet = local_packet;
+ memcpy(e.u.cfg_tool.packet, packet, size);
+ }
+ e.arg = (void *)type;
+ e.u.cfg_tool.event = event;
+ e.u.cfg_tool.size = size;
+ sys_event_notify(&e);
+}
+
+void app_cfg_tool_message_deal(u8 *buf, u32 len)
+{
+ u8 cmd = buf[8];
+ switch (cmd) {
+ case ONLINE_SUB_OP_QUERY_BASIC_INFO:
+ case ONLINE_SUB_OP_QUERY_FILE_SIZE:
+ case ONLINE_SUB_OP_QUERY_FILE_CONTENT:
+ case ONLINE_SUB_OP_PREPARE_WRITE_FILE:
+ case ONLINE_SUB_OP_READ_ADDR_RANGE:
+ case ONLINE_SUB_OP_ERASE_ADDR_RANGE:
+ case ONLINE_SUB_OP_WRITE_ADDR_RANGE:
+ case ONLINE_SUB_OP_ENTER_UPGRADE_MODE:
+ cfg_tool_event_to_user(&buf[5], DEVICE_EVENT_FROM_CFG_TOOL, cmd, buf[5] + 1);
+ break;
+ default:
+ cfg_tool_event_to_user(&buf[5], DEVICE_EVENT_FROM_CFG_TOOL, DEFAULT_ACTION, buf[5] + 1);
+ break;
+ }
+}
+
+void online_cfg_tool_data_deal(void *buf, u32 len)
+{
+ u8 *data_buf = buf;
+ u16 crc16_data;
+
+ /* printf_buf(buf, len); */
+
+ /*DATA前的固定字节包括 (5A AA A5 CRC L T SQ)共8个字节 */
+ if (len < 8) {
+ log_error("Data length is too short, receive an invalid message!\n");
+ return;
+ }
+
+ if ((data_buf[0] != 0x5a) || (data_buf[1] != 0xaa) || (data_buf[2] != 0xa5)) {
+ log_error("Header check error, receive an invalid message!\n");
+ return;
+ }
+
+ /*CRC16校验,CRC16校验码位于数据包的buf[3]和buf[4]*/
+ crc16_data = (data_buf[4] << 8) | data_buf[3];
+ if (crc16_data != CRC16(data_buf + 5, len - 5)) {
+ log_error("CRC16 check error, receive an invalid message!\n");
+ return;
+ }
+
+ app_cfg_tool_message_deal(buf, len);
+}
diff --git a/apps/common/debug/debug.c b/apps/common/debug/debug.c
new file mode 100644
index 0000000..7bd1c91
--- /dev/null
+++ b/apps/common/debug/debug.c
@@ -0,0 +1,63 @@
+#include "app_config.h"
+#include "typedef.h"
+
+
+
+#ifndef CONFIG_DEBUG_ENABLE
+
+int putchar(int a)
+{
+ return a;
+}
+
+int puts(const char *out)
+{
+ return 0;
+}
+
+int printf(const char *format, ...)
+{
+ return 0;
+}
+
+
+void put_buf(const u8 *buf, int len)
+{
+
+}
+
+void put_u8hex(u8 dat)
+{
+
+}
+
+void put_u16hex(u16 dat)
+{
+
+}
+
+void put_u32hex(u32 dat)
+{
+
+}
+
+void log_print(int level, const char *tag, const char *format, ...)
+{
+
+}
+
+#ifndef CONFIG_DEBUG_LITE_ENABLE
+void log_putbyte(char c)
+{
+
+}
+#endif /* #ifndef CONFIG_DEBUG_LITE_ENABLE */
+
+int assert_printf(const char *format, ...)
+{
+ cpu_assert_debug();
+
+ return 0;
+}
+
+#endif
diff --git a/apps/common/debug/debug_lite.c b/apps/common/debug/debug_lite.c
new file mode 100644
index 0000000..b3d37d9
--- /dev/null
+++ b/apps/common/debug/debug_lite.c
@@ -0,0 +1,68 @@
+#include "app_config.h"
+#include "typedef.h"
+
+#ifdef CONFIG_DEBUG_LITE_ENABLE
+
+extern void putbyte(char a);
+
+#define putbyte_lite putbyte
+
+void log_putbyte(char c)
+{
+ putbyte_lite(c);
+}
+
+void puts_lite(const char *out)
+{
+ while (*out != '\0') {
+ putbyte_lite(*out);
+ out++;
+ }
+}
+
+int printf_lite(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+
+ return print(NULL, 0, format, args);
+}
+
+void put_buf_lite(void *_buf, u32 len)
+{
+ u8 *buf = (u8 *)_buf;
+ printf_lite("\n0x%x\n", buf);
+ for (int i = 0; i < len; i++) {
+ if (((i % 16) == 0) && (i != 0)) {
+ putbyte_lite('\n');
+ }
+ printf_lite("%x", buf[i]);
+ putbyte_lite(' ');
+ }
+ putbyte_lite('\n');
+}
+
+#else
+
+
+void puts_lite(const char *out)
+{
+
+}
+
+
+void put_buf_lite(void *_buf, u32 len)
+{
+
+}
+
+
+int printf_lite(const char *format, ...)
+{
+ return 0;
+}
+
+#endif /* #ifdef CONFIG_DEBUG_LITE_ENABLE */
+
+
diff --git a/apps/common/dev_manager/dev_manager.c b/apps/common/dev_manager/dev_manager.c
new file mode 100644
index 0000000..0d9a594
--- /dev/null
+++ b/apps/common/dev_manager/dev_manager.c
@@ -0,0 +1,1128 @@
+#include "dev_manager.h"
+#include "dev_reg.h"
+#include "app_config.h"
+#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
+#include "dev_multiplex_api.h"
+#endif
+#include "spi/nor_fs.h"
+#include "dev_update.h"
+
+// *INDENT-OFF*
+
+#if (TCFG_DEV_MANAGER_ENABLE)
+
+#define DEV_MANAGER_TASK_NAME "dev_mg"
+#define DEV_MANAGER_SCAN_DISK_MAX_DEEPTH 9
+
+///设备管理总控制句柄
+struct __dev_manager {
+ struct list_head list;
+ OS_MUTEX mutex;
+ OS_SEM sem;
+ u32 counter;
+};
+static struct __dev_manager dev_mg;
+#define __this (&dev_mg)
+
+
+///设备节点结构体
+struct __dev {
+ struct list_head entry;
+ struct __dev_reg *parm;//设备参数
+ struct imount *fmnt;
+ volatile u8 valid: 1;//有效设备标记, 这里有效是指是否有可播放文件
+ volatile u32 active_stamp;///活动设备时间戳,通过时间戳记录当前最后活动设备
+};
+
+
+static u32 __dev_manager_get_time_stamp(void)
+{
+ u32 counter = __this->counter;
+ __this->counter ++;
+ return counter;
+}
+
+int __dev_manager_add(char *logo, u8 need_mount)
+{
+ if (logo == NULL) {
+ return DEV_MANAGER_ADD_ERR_PARM;
+ }
+ int i;
+ printf("%s add start\n", logo);
+ struct __dev_reg *p = NULL;
+ struct __dev_reg *n;
+
+ for(n=(struct __dev_reg *)dev_reg; n->logo != NULL; n++){
+ if (!strcmp(n->logo, logo)) {
+ p = n;
+ break;
+ }
+ }
+
+ if (p) {
+ ///挂载文件系统
+ if (dev_manager_list_check_by_logo(logo)) {
+ printf("dev online aready, err!!!\n");
+ return DEV_MANAGER_ADD_IN_LIST_AREADY;
+ }
+ struct __dev *dev = (struct __dev *)zalloc(sizeof(struct __dev));
+ if(dev == NULL){
+ return DEV_MANAGER_ADD_ERR_NOMEM;
+ }
+ os_mutex_pend(&__this->mutex, 0);
+ if(need_mount){
+ dev->fmnt = mount(p->name, p->storage_path, p->fs_type, 3, NULL);
+ }
+ dev->parm = p;
+ dev->valid = (dev->fmnt ? 1 : 0);
+ dev->active_stamp = __dev_manager_get_time_stamp();//timer_get_ms();
+ list_add_tail(&dev->entry, &__this->list);
+ os_mutex_post(&__this->mutex);
+ printf("%s, %s add ok, dev->fmnt = %x, %d\n", __FUNCTION__, logo, (int)dev->fmnt, dev->active_stamp);
+ if(dev->fmnt == NULL){
+ return DEV_MANAGER_ADD_ERR_MOUNT_FAIL;
+ }
+ return DEV_MANAGER_ADD_OK;
+ }
+ printf("dev_manager_add can not find logo %s\n",logo);
+ return DEV_MANAGER_ADD_ERR_NOT_FOUND;
+}
+
+static int __dev_manager_del(char *logo)
+{
+ if (logo == NULL) {
+ return -1;
+ }
+ struct __dev *dev, *n;
+ os_mutex_pend(&__this->mutex, 0);
+ list_for_each_entry_safe(dev, n, &__this->list, entry) {
+ if (!strcmp(dev->parm->logo, logo)) {
+ ///卸载文件系统
+ if(dev->fmnt){
+ unmount(dev->parm->storage_path);
+ }
+ list_del(&dev->entry);
+ free(dev);
+ printf("%s, %s del ok\n", __FUNCTION__, logo);
+ break;
+ }
+ }
+ os_mutex_post(&__this->mutex);
+ return 0;
+}
+
+//*----------------------------------------------------------------------------*/
+/**@brief 设备增加接口
+ @param logo:逻辑盘符,如:sd0/sd1/udisk0等
+ @return 0:成功,非0是失败
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+int dev_manager_add(char *logo)
+{
+ if(logo == NULL){
+ return -1;
+ }
+ int ret = 0;
+#if TCFG_RECORD_FOLDER_DEV_ENABLE
+ char rec_dev_logo[16] = {0};
+ sprintf(rec_dev_logo, "%s%s", logo, "_rec");
+ ret = __dev_manager_add(rec_dev_logo, 1);
+ if(ret == DEV_MANAGER_ADD_OK){
+ ret = __dev_manager_add(logo, 1);
+ if(ret){
+ __dev_manager_del(logo);
+ __dev_manager_del(rec_dev_logo);
+ }
+ }else if(ret == DEV_MANAGER_ADD_ERR_NOT_FOUND){
+ ret = __dev_manager_add(logo, 1);
+ }
+ else{
+ ret = __dev_manager_add(logo, 0);
+ }
+#else
+ ret = __dev_manager_add(logo, 1);
+#endif//TCFG_RECORD_FOLDER_DEV_ENABLE
+
+ return ret;
+}
+
+//*----------------------------------------------------------------------------*/
+/**@brief 设备删除接口
+ @param logo:逻辑盘符,如:sd0/sd1/udisk0等
+ @return 0:成功,非0是失败
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+int dev_manager_del(char *logo)
+{
+ if(logo == NULL){
+ return -1;
+ }
+ __dev_manager_del(logo);
+#if TCFG_RECORD_FOLDER_DEV_ENABLE
+ char rec_dev_logo[16] = {0};
+ sprintf(rec_dev_logo, "%s%s", logo, "_rec");
+ __dev_manager_del(rec_dev_logo);
+#endif//TCFG_RECORD_FOLDER_DEV_ENABLE
+
+ return 0;
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 通过设备节点检查设备是否在线
+ @param dev:设备节点
+ @return 成功返回设备节点, 失败返回NULL
+ @note 通过设备节点检查设备是否在设备链表中
+*/
+/*----------------------------------------------------------------------------*/
+struct __dev *dev_manager_check(struct __dev *dev)
+{
+ if (dev == NULL) {
+ return NULL;
+ }
+ struct __dev *p;
+ list_for_each_entry(p, &__this->list, entry) {
+ if(!(p->fmnt)){
+ continue;
+ }
+ if (dev == p) {
+ return p;
+ }
+ }
+ return NULL;
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 通过盘符检查设备是否在线
+ @param logo:逻辑盘符,如:sd0/sd1/udisk0
+ @return 成功返回设备节点, 失败返回NULL
+ @note 通过设备节点检查设备是否在设备链表中
+*/
+/*----------------------------------------------------------------------------*/
+struct __dev *dev_manager_check_by_logo(char *logo)
+{
+ if (logo == NULL) {
+ return NULL;
+ }
+ struct __dev *dev;
+ list_for_each_entry(dev, &__this->list, entry) {
+ if(!(dev->fmnt)){
+ continue;
+ }
+ if (!strcmp(dev->parm->logo, logo)) {
+ return dev;
+ }
+ }
+ return NULL;
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 获取设备总数
+ @param valid:
+ 1:有效可播放设备, 0;所有设备,包括有可播放设备及无可播放设备
+ @return 设备总数
+ @note 根据使用情景决定接口参数
+*/
+/*----------------------------------------------------------------------------*/
+u32 dev_manager_get_total(u8 valid)
+{
+ u32 total_valid = 0;
+ u32 total = 0;
+ struct __dev *dev;
+ os_mutex_pend(&__this->mutex, 0);
+ list_for_each_entry(dev, &__this->list, entry) {
+ if(!(dev->fmnt)){
+ continue;
+ }
+ if (dev->valid) {
+ total_valid++;
+ }
+ total ++;
+ }
+ os_mutex_post(&__this->mutex);
+ return (valid ? total_valid : total);
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 获取设备列表第一个设备
+ @param valid:
+ 1:有效可播放设备, 0;所有设备,包括有可播放设备及无可播放设备
+ @return 成功返回设备设备节点,失败返回NULL
+ @note 根据使用情景决定接口参数
+*/
+/*----------------------------------------------------------------------------*/
+struct __dev *dev_manager_find_first(u8 valid)
+{
+ struct __dev *dev = NULL;
+ os_mutex_pend(&__this->mutex, 0);
+ list_for_each_entry(dev, &__this->list, entry) {
+ if(!(dev->fmnt)){
+ continue;
+ }
+ if(valid){
+ if (dev->valid) {
+ os_mutex_post(&__this->mutex);
+ return dev;
+ }
+ }else{
+ os_mutex_post(&__this->mutex);
+ return dev;
+ }
+ }
+ os_mutex_post(&__this->mutex);
+ return NULL;
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 获取设备列表最后一个设备
+ @param valid:
+ 1:有效可播放设备中查找
+ 0:所有设备,包括有可播放设备及无可播放设备中查找
+ @return 成功返回设备设备节点,失败返回NULL
+ @note 根据使用情景决定接口参数
+*/
+/*----------------------------------------------------------------------------*/
+struct __dev *dev_manager_find_last(u8 valid)
+{
+ struct __dev *dev = NULL;
+ os_mutex_pend(&__this->mutex, 0);
+ list_for_each_entry_reverse(dev, &__this->list, entry) {
+ if(!(dev->fmnt)){
+ continue;
+ }
+ if(valid){
+ if (dev->valid) {
+ os_mutex_post(&__this->mutex);
+ return dev;
+ }
+ }else{
+ os_mutex_post(&__this->mutex);
+ return dev;
+ }
+ }
+ os_mutex_post(&__this->mutex);
+ return NULL;
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 获取上一个设备节点
+ @param
+ dev:当前设备节点
+ valid:
+ 1:有效可播放设备中查找,
+ 0:所有设备,包括有可播放设备及无可播放设备中查找
+ @return 成功返回设备设备节点,失败返回NULL
+ @note 根据当前设置的参数设备节点,找链表中的上一个设备
+*/
+/*----------------------------------------------------------------------------*/
+struct __dev *dev_manager_find_prev(struct __dev *dev, u8 valid)
+{
+ if (dev == NULL) {
+ return NULL;
+ }
+ struct __dev *p = NULL;
+ os_mutex_pend(&__this->mutex, 0);
+ if (dev_manager_check(dev) == NULL) {
+ ///传入的参数无效, 返回活动设备
+ os_mutex_post(&__this->mutex);
+ return dev_manager_find_active(valid);
+ }
+ list_for_each_entry(p, &dev->entry, entry) {
+ if((void*)p == (void*)(&__this->list)){
+ continue;
+ }
+ if(!(p->fmnt)){
+ continue;
+ }
+ if(valid){
+ if (p->valid) {
+ os_mutex_post(&__this->mutex);
+ return p;
+ }
+ }else{
+ os_mutex_post(&__this->mutex);
+ return p;
+ }
+ }
+ os_mutex_post(&__this->mutex);
+ return NULL;
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 获取下一个设备节点
+ @param
+ dev:当前设备节点
+ valid:
+ 1:有效可播放设备中查找,
+ 0:所有设备,包括有可播放设备及无可播放设备中查找
+ @return 成功返回设备设备节点,失败返回NULL
+ @note 根据当前设置的参数设备节点,找链表中的下一个设备
+*/
+/*----------------------------------------------------------------------------*/
+struct __dev *dev_manager_find_next(struct __dev *dev, u8 valid)
+{
+ if (dev == NULL) {
+ return NULL;
+ }
+ struct __dev *p = NULL;
+ os_mutex_pend(&__this->mutex, 0);
+ if (dev_manager_check(dev) == NULL) {
+ ///传入的参数无效, 返回活动设备
+ os_mutex_post(&__this->mutex);
+ return dev_manager_find_active(valid);
+ }
+
+ list_for_each_entry_reverse(p, &dev->entry, entry) {
+ if((void*)p == (void*)(&__this->list)){
+ continue;
+ }
+ if(!(p->fmnt)){
+ continue;
+ }
+ if(valid){
+ if (p->valid) {
+ os_mutex_post(&__this->mutex);
+ return p;
+ }
+ }else{
+ os_mutex_post(&__this->mutex);
+ return p;
+ }
+ }
+ os_mutex_post(&__this->mutex);
+ return NULL;
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 获取当前活动设备节点
+ @param
+ valid:
+ 1:有效可播放设备中查找,
+ 0:所有设备,包括有可播放设备及无可播放设备中查找
+ @return 成功返回设备设备节点,失败返回NULL
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+struct __dev *dev_manager_find_active(u8 valid)
+{
+ struct __dev *dev = NULL;
+ struct __dev *active = NULL;
+ os_mutex_pend(&__this->mutex, 0);
+ list_for_each_entry(dev, &__this->list, entry) {
+ if(!(dev->fmnt)){
+ continue;
+ }
+ if(valid){
+ if (dev->valid) {
+ if (active) {
+ if (active->active_stamp < dev->active_stamp) {
+ active = dev;
+ }
+ } else {
+ active = dev;
+ }
+ }
+ }else{
+ if (active) {
+ if (active->active_stamp < dev->active_stamp) {
+ active = dev;
+ }
+ } else {
+ active = dev;
+ }
+
+ }
+ }
+ os_mutex_post(&__this->mutex);
+ return active;
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 获取指定设备节点
+ @param
+ logo:指定逻辑盘符,如:sd0/sd1/udisk0
+ valid:
+ 1:有效可播放设备中查找,
+ 0:所有设备,包括有可播放设备及无可播放设备中查找
+ @return 成功返回设备设备节点,失败返回NULL
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+struct __dev *dev_manager_find_spec(char *logo, u8 valid)
+{
+ if (logo == NULL) {
+ return NULL;
+ }
+ struct __dev *dev = NULL;
+ os_mutex_pend(&__this->mutex, 0);
+ list_for_each_entry(dev, &__this->list, entry) {
+ if(!(dev->fmnt)){
+ continue;
+ }
+ if (!strcmp(dev->parm->logo, logo)) {
+ if(valid){
+ if (dev->valid) {
+ os_mutex_post(&__this->mutex);
+ return dev;
+ }
+ }else{
+ os_mutex_post(&__this->mutex);
+ return dev;
+ }
+ }
+ }
+ os_mutex_post(&__this->mutex);
+ return NULL;
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 获取指定序号设备节点
+ @param
+ index:指定序号,指的是在设备链表中的顺序
+ valid:
+ 1:有效可播放设备中查找,
+ 0:所有设备,包括有可播放设备及无可播放设备中查找
+ @return 成功返回设备设备节点,失败返回NULL
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+struct __dev *dev_manager_find_by_index(u32 index, u8 valid)
+{
+ struct __dev *dev = NULL;
+ u32 i = 0;
+ os_mutex_pend(&__this->mutex, 0);
+ list_for_each_entry(dev, &__this->list, entry) {
+ if(!(dev->fmnt)){
+ continue;
+ }
+ if(valid){
+ if (dev->valid) {
+ if (i == index) {
+ os_mutex_post(&__this->mutex);
+ return dev;
+ }
+ i++;
+ }
+ }else{
+ if (i == index) {
+ os_mutex_post(&__this->mutex);
+ return dev;
+ }
+ i++;
+ }
+ }
+ os_mutex_post(&__this->mutex);
+ return NULL;
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 设备扫盘释放
+ @param
+ fsn:扫描句柄
+ @return 无
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+void dev_manager_scan_disk_release(struct vfscan *fsn)
+{
+ if (fsn) {
+ fscan_release(fsn);
+ }
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 设备扫盘
+ @param
+ dev:设备节点
+ path:指定扫描目录
+ parm:扫描参数,包括文件后缀等
+ cycle_mode:播放循环模式
+ callback:扫描打断回调
+ @return 成功返回扫描控制句柄,失败返回NULL
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+struct vfscan *dev_manager_scan_disk(struct __dev *dev, const char *path, const char *parm, u8 cycle_mode, struct __scan_callback *callback)
+{
+ if (dev_manager_check(dev) == NULL) {
+ return NULL;
+ }
+#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
+
+#if (TCFG_DM_MULTIPLEX_WITH_SD_PORT == 0) //0:sd0 1:sd1 //dm 参与复用的sd配置
+ if(!memcmp(dev->parm->logo ,"sd0",strlen("sd0"))){
+#else
+ if(!memcmp(dev->parm->logo ,"sd1",strlen("sd1"))){
+#endif
+ dev_usb_change_sd();
+ }
+
+ if(!memcmp(dev->parm->logo ,"udisk",strlen("udisk")))
+ dev_sd_change_usb();
+
+ if (dev_manager_online_check(dev, 1) == NULL) {
+ printf("mult remount fail !!!\n");
+ return NULL;
+ }
+#endif
+ char *fsn_path = NULL;
+ char *tmp_path = NULL;
+ if (path) {
+ if (*path == '/') {
+ path++;
+ }
+ tmp_path = zalloc(strlen(dev->parm->root_path) + strlen(path) + 1);
+ if (tmp_path == NULL) {
+ return NULL;
+ }
+ sprintf(tmp_path, "%s%s", dev->parm->root_path, path);
+ fsn_path = tmp_path;
+ } else {
+ fsn_path = dev->parm->root_path;
+ }
+ printf("fsn_path = %s, scan parm = %s\n", fsn_path, parm);
+ struct vfscan *fsn;
+ /* clock_add_set(SCAN_DISK_CLK); */
+ if(callback && callback->enter){
+ callback->enter(dev);//扫描前处理, 可以在注册的回调里提高系统时钟等处理
+ }
+ fsn = fscan_interrupt(
+ (const char *)fsn_path,
+ parm,
+ DEV_MANAGER_SCAN_DISK_MAX_DEEPTH,
+ ((callback) ? callback->scan_break : NULL));
+ /* clock_remove_set(SCAN_DISK_CLK); */
+ if(callback && callback->exit){
+ callback->exit(dev);//扫描后处理, 可以在注册的回调里还原到enter前的状态
+ }
+ if (fsn) {
+ if (fsn->file_number == 0) {
+ printf("dev nofile\n");
+#if (TCFG_DEV_UPDATE_IF_NOFILE_ENABLE)
+ ///没有文件找升级文件
+ dev_update_check(dev->parm->logo);
+#endif/*TCFG_DEV_UPDATE_IF_NOFILE_ENABLE*/
+ ///没有文件,释放fsn, 减少外面流程的处理
+ dev_manager_scan_disk_release(fsn);
+ fsn = NULL;
+ } else {
+ fsn->cycle_mode = cycle_mode;
+ }
+ }
+
+ if (tmp_path) {
+ free(tmp_path);
+ }
+ return fsn;
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 通过设备节点标记指定设备是否有效
+ @param
+ dev:设备节点
+ flag:
+ 1:设备有效,
+ 0:设备无效
+ @return
+ @note 这里有无效是指是否有可播放文件
+*/
+/*----------------------------------------------------------------------------*/
+void dev_manager_set_valid(struct __dev *dev, u8 flag)
+{
+ os_mutex_pend(&__this->mutex, 0);
+ if (dev_manager_check(dev)) {
+ dev->valid = flag;
+ }
+ os_mutex_post(&__this->mutex);
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 通过逻辑盘符标记指定设备是否有效
+ @param
+ logo:逻辑盘符,如:sd0/sd1/udisk0
+ flag:
+ 1:设备有效,
+ 0:设备无效
+ @return
+ @note 这里有无效是指是否有可播放文件
+*/
+/*----------------------------------------------------------------------------*/
+void dev_manager_set_valid_by_logo(char *logo, u8 flag)
+{
+ if (logo == NULL) {
+ return ;
+ }
+ struct __dev *dev = NULL;
+ os_mutex_pend(&__this->mutex, 0);
+ dev = dev_manager_check_by_logo(logo);
+ if (dev) {
+ dev->valid = flag;
+ }
+ os_mutex_post(&__this->mutex);
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 激活指定设备节点的设备
+ @param
+ dev:设备节点
+ @return
+ @note 该接口可以将设备变为最新活动设备
+*/
+/*----------------------------------------------------------------------------*/
+void dev_manager_set_active(struct __dev *dev)
+{
+ os_mutex_pend(&__this->mutex, 0);
+ if (dev_manager_check(dev)) {
+ dev->active_stamp = __dev_manager_get_time_stamp();//timer_get_ms();
+ }
+ os_mutex_post(&__this->mutex);
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 激活指定逻辑盘符的设备
+ @param
+ logo:逻辑盘符,如:sd0/sd1/udisk0
+ @return
+ @note 该接口可以将设备变为最新活动设备
+*/
+/*----------------------------------------------------------------------------*/
+void dev_manager_set_active_by_logo(char *logo)
+{
+ if (logo == NULL) {
+ return ;
+ }
+ struct __dev *dev = NULL;
+ os_mutex_pend(&__this->mutex, 0);
+ dev = dev_manager_check_by_logo(logo);
+ if (dev) {
+ dev->active_stamp = __dev_manager_get_time_stamp();//timer_get_ms();
+ }
+ os_mutex_post(&__this->mutex);
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 获取设备节点的逻辑盘符
+ @param
+ dev:设备节点
+ @return 成功返回逻辑盘符,如:sd0/sd1/udisk0,失败返回NULL
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+char *dev_manager_get_logo(struct __dev *dev)
+{
+ char *logo = NULL;
+ os_mutex_pend(&__this->mutex, 0);
+ if (dev_manager_check(dev) == NULL) {
+ os_mutex_post(&__this->mutex);
+ return NULL;
+ }
+ logo = dev->parm->logo;
+ os_mutex_post(&__this->mutex);
+ return logo;
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 获取物理设备节点的逻辑盘符(去掉_rec后缀)
+ @param
+ dev:设备节点
+ @return 成功返回逻辑盘符,如:sd0/sd1/udisk0,失败返回NULL
+ @note 物理逻辑盘符是指非录音文件夹设备盘符(录音文件夹设备如:sd0_rec)
+*/
+/*----------------------------------------------------------------------------*/
+char *dev_manager_get_phy_logo(struct __dev *dev)
+{
+ char *logo = dev_manager_get_logo(dev);
+ char phy_dev_logo[16] = {0};
+ if (logo) {
+ char *str = strstr(logo, "_rec");
+ if (str) {
+ strncpy(phy_dev_logo, logo, strlen(logo) - strlen(str));
+ struct __dev *phy_dev = dev_manager_find_spec(phy_dev_logo, 0);
+ return dev_manager_get_logo(phy_dev);
+ }
+ }
+ return logo;
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 获取录音文件夹设备节点的逻辑盘符(追加_rec后缀)
+ @param
+ dev:设备节点
+ @return 成功返回逻辑盘符,如:sd0_rec/sd1_rec/udisk0_rec,失败返回NULL
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+char *dev_manager_get_rec_logo(struct __dev *dev)
+{
+ char *logo = dev_manager_get_logo(dev);
+ char rec_dev_logo[16] = {0};
+ if (logo) {
+ char *str = strstr(logo, "_rec");
+ if (!str) {
+ sprintf(rec_dev_logo, "%s%s", logo, "_rec");
+ struct __dev *rec_dev = dev_manager_find_spec(rec_dev_logo, 0);
+ return dev_manager_get_logo(rec_dev);
+ }
+ }
+ return logo;
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 通过设备节点获取设备文件系统根目录
+ @param
+ dev:设备节点
+ @return 成功返回根目录,失败返回NULL
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+char *dev_manager_get_root_path(struct __dev *dev)
+{
+ char *path = NULL;
+ os_mutex_pend(&__this->mutex, 0);
+ if (dev_manager_check(dev) == NULL) {
+ os_mutex_post(&__this->mutex);
+ return NULL;
+ }
+ path = dev->parm->root_path;
+ os_mutex_post(&__this->mutex);
+ return path;
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 通过逻辑盘符获取设备文件系统根目录
+ @param
+ logo:逻辑盘符,如:sd0/sd1/udisk0
+ @return 成功返回根目录,失败返回NULL
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+char *dev_manager_get_root_path_by_logo(char *logo)
+{
+ char *path = NULL;
+ os_mutex_pend(&__this->mutex, 0);
+ struct __dev *dev = dev_manager_check_by_logo(logo);
+ if (dev == NULL) {
+ os_mutex_post(&__this->mutex);
+ return NULL;
+ }
+ path = dev->parm->root_path;
+ os_mutex_post(&__this->mutex);
+ return path;
+}
+
+//*----------------------------------------------------------------------------*/
+/**@brief 通过设备节点获取设备mount信息
+ @param
+ dev:设备节点
+ @return 成功返回对应指针,失败返回NULL
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+struct imount *dev_manager_get_mount_hdl(struct __dev *dev)
+{
+ if (dev == NULL) {
+ return NULL;
+ }else{
+ return dev->fmnt;
+ }
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 通过逻辑盘符判断设备是否在线
+ @param
+ logo:逻辑盘符,如:sd0/sd1/udisk0
+ valid:
+ 1:检查有效可播放设备
+ 0:检查所有设备
+ @return 1:在线 0:不在线
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+int dev_manager_online_check_by_logo(char *logo, u8 valid)
+{
+ struct __dev *dev = dev_manager_find_spec(logo, valid);
+ return (dev ? 1 : 0);
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 通过设备节点判断设备是否在线
+ @param
+ dev:设备节点
+ valid:
+ 1:检查有效可播放设备
+ 0:检查所有设备
+ @return 1:在线 0:不在线
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+int dev_manager_online_check(struct __dev *dev, u8 valid)
+{
+ if (dev_manager_check(dev) == NULL) {
+ return 0;
+ }else{
+ if(valid){
+ return (dev->valid ? 1 : 0);
+ }else{
+ return 1;
+ }
+ }
+}
+
+//*----------------------------------------------------------------------------*/
+/**@brief 通过逻辑盘符判断设备是否在设备链表中
+ @param
+ logo:逻辑盘符,如:sd0/sd1/udisk0
+ @return 1:在设备链表中, 0:不在设备链表中
+ @note 该接口会检查所有在设备链表中的设备,忽略mount,valid等状态
+*/
+/*----------------------------------------------------------------------------*/
+struct __dev *dev_manager_list_check_by_logo(char *logo)
+{
+ if (logo == NULL) {
+ return 0;
+ }
+ struct __dev *dev;
+ os_mutex_pend(&__this->mutex, 0);
+ list_for_each_entry(dev, &__this->list, entry) {
+ if (!strcmp(dev->parm->logo, logo)) {
+ os_mutex_post(&__this->mutex);
+ return dev;
+ }
+ }
+ os_mutex_post(&__this->mutex);
+ return NULL;
+}
+
+//*----------------------------------------------------------------------------*/
+/**@brief 检查链表中没有挂载的设备并重新挂载
+ @param
+ logo:逻辑盘符,如:sd0/sd1/udisk0
+ @return 1:在设备链表中, 0:不在设备链表中
+ @note 该接口会检查所有在设备链表中的设备,忽略mount,valid等状态
+*/
+/*----------------------------------------------------------------------------*/
+void dev_manager_list_check_mount(void)
+{
+ struct __dev *dev;
+ os_mutex_pend(&__this->mutex, 0);
+ list_for_each_entry(dev, &__this->list, entry) {
+
+ if(!strcmp(dev->parm->logo,"virfat_flash")){
+ continue;
+ }
+
+ if(dev->fmnt){
+ unmount(dev->parm->storage_path);
+ dev->fmnt = NULL;
+ }
+
+ if(dev->fmnt == NULL){
+ struct __dev_reg *p = dev->parm;
+ dev->fmnt = mount(p->name, p->storage_path, p->fs_type, 3, NULL);
+ dev->valid = (dev->fmnt ? 1 : 0);
+ }
+ }
+ os_mutex_post(&__this->mutex);
+}
+
+//*----------------------------------------------------------------------------*/
+/**@brief 设备挂载
+ @param
+ logo:逻辑盘符,如:sd0/sd1/udisk0
+ @return 0:成功, -1:失败
+ @note 需要主动mount设备可以调用改接口
+*/
+/*----------------------------------------------------------------------------*/
+static int __dev_manager_mount(char *logo)
+{
+ int ret = 0;
+ os_mutex_pend(&__this->mutex, 0);
+ struct __dev *dev = dev_manager_list_check_by_logo(logo);
+ if (dev == NULL) {
+ os_mutex_post(&__this->mutex);
+ return -1;
+ }
+ if(dev->fmnt == NULL){
+ struct __dev_reg *p = dev->parm;
+ dev->fmnt = mount(p->name, p->storage_path, p->fs_type, 3, NULL);
+ dev->valid = (dev->fmnt ? 1 : 0);
+ }
+ ret = (dev->valid ? 0 : -1);
+ os_mutex_post(&__this->mutex);
+ return ret;
+}
+//*----------------------------------------------------------------------------*/
+/**@brief 设备卸载
+ @param
+ logo:逻辑盘符,如:sd0/sd1/udisk0
+ @return 0:成功, -1:失败
+ @note 需要主动unmount设备可以调用改接口
+*/
+/*----------------------------------------------------------------------------*/
+static int __dev_manager_unmount(char *logo)
+{
+ os_mutex_pend(&__this->mutex, 0);
+ struct __dev *dev = dev_manager_check_by_logo(logo);
+ if (dev == NULL) {
+ os_mutex_post(&__this->mutex);
+ return -1;
+ }
+ if(dev->fmnt){
+ unmount(dev->parm->storage_path);
+ dev->fmnt = NULL;
+ }
+ dev->valid = 0;
+ os_mutex_post(&__this->mutex);
+ return 0;
+}
+
+//*----------------------------------------------------------------------------*/
+/**@brief 设备挂载
+ @param
+ logo:逻辑盘符,如:sd0/sd1/udisk0
+ @return 0:成功, -1:失败
+ @note 慎用
+*/
+/*----------------------------------------------------------------------------*/
+int dev_manager_mount(char *logo)
+{
+ int ret = __dev_manager_mount(logo);
+ if(ret == 0){
+#if TCFG_RECORD_FOLDER_DEV_ENABLE
+ char rec_dev_logo[16] = {0};
+ sprintf(rec_dev_logo, "%s%s", logo, "_rec");
+ ret = __dev_manager_mount(rec_dev_logo);
+ if(ret){
+ __dev_manager_unmount(logo);
+ }
+#endif
+ }
+ return ret;
+}
+
+//*----------------------------------------------------------------------------*/
+/**@brief 设备卸载
+ @param
+ logo:逻辑盘符,如:sd0/sd1/udisk0
+ @return 0:成功, -1:失败
+ @note 慎用
+*/
+/*----------------------------------------------------------------------------*/
+int dev_manager_unmount(char *logo)
+{
+ int err = 0;
+#if TCFG_RECORD_FOLDER_DEV_ENABLE
+ char rec_dev_logo[16] = {0};
+ sprintf(rec_dev_logo, "%s%s", logo, "_rec");
+ __dev_manager_unmount(rec_dev_logo);
+#endif
+ err = __dev_manager_unmount(logo);
+ return err;
+}
+
+
+//*----------------------------------------------------------------------------*/
+/**@brief 设备检测线程处理
+ @param
+ @return
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+extern void hidden_file(u8 flag);
+static void dev_manager_task(void *p)
+{
+ int res = 0;
+ int msg[8] = {0};
+ ///过滤隐藏 和 .开头名名的字文件
+ hidden_file(1);
+ ///设备初始化,
+ devices_init();
+
+#if TCFG_SD_ALWAY_ONLINE_ENABLE
+#if (defined(TCFG_SD0_ENABLE) && (TCFG_SD0_ENABLE))
+ extern void force_set_sd_online(char *sdx);
+ force_set_sd_online("sd0");
+ int err = dev_manager_add("sd0");
+#elif (defined(TCFG_SD1_ENABLE) && (TCFG_SD1_ENABLE))
+ extern void force_set_sd_online(char *sdx);
+ force_set_sd_online("sd1");
+ int err = dev_manager_add("sd1");
+#endif
+ if (err != 0) {
+ printf("sd add fail\n");
+ } else {
+#if (TCFG_SD_ALWAY_ONLINE_ENABLE && (TCFG_SD0_ENABLE || TCFG_SD1_ENABLE))
+ extern void sdx_dev_detect_timer_del();
+ sdx_dev_detect_timer_del();
+#endif
+ }
+#endif
+
+#if SDFILE_STORAGE && TCFG_CODE_FLASH_ENABLE
+ dev_manager_add(SDFILE_DEV);
+#endif
+
+#if TCFG_NOR_REC
+ dev_manager_add("rec_nor");
+#endif
+
+#if TCFG_NOR_FAT
+ dev_manager_add("fat_nor");
+ dev_manager_set_valid_by_logo("fat_nor", 0);///将设备设置为无效设备
+#endif
+
+#if TCFG_NOR_FS
+ dev_manager_add("res_nor");
+#endif
+
+#if TCFG_VIR_UDISK_ENABLE
+ dev_manager_add("vir_udisk0");
+#endif
+
+#if TCFG_VIRFAT_FLASH_ENABLE
+ dev_manager_add("virfat_flash");
+ dev_manager_set_valid_by_logo("virfat_flash", 0);///将设备设置为无效设备
+#endif
+
+#if TCFG_NANDFLASH_DEV_ENABLE
+ dev_manager_add("nandflash_ftl");
+ dev_manager_set_valid_by_logo("nandflash_ftl", 0);///将设备设置为无效设备
+#endif
+
+#if FLASH_INSIDE_REC_ENABLE
+ set_rec_capacity(512*1024);//需要先设置容量,注意要小于Ini文件设置大小.
+ _sdfile_rec_init();
+ dev_manager_add("rec_sdfile");
+#endif
+
+ os_sem_post(&__this->sem);
+
+ while (1) {
+ res = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
+ switch (res) {
+ case OS_TASKQ:
+ switch (msg[0]) {
+ case Q_EVENT:
+ break;
+ case Q_MSG:
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void dev_manager_var_init()
+{
+ memset(__this, 0, sizeof(struct __dev_manager));
+ INIT_LIST_HEAD(&__this->list);
+ os_mutex_create(&__this->mutex);
+}
+
+#endif/*TCFG_DEV_MANAGER_ENABLE*/
+//*----------------------------------------------------------------------------*/
+/**@brief 设备管理器初始化
+ @param
+ @return
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+void dev_manager_init(void)
+{
+#if (TCFG_DEV_MANAGER_ENABLE)
+ dev_manager_var_init();
+
+ os_sem_create(&__this->sem, 0);
+
+ int err = task_create(dev_manager_task, NULL, DEV_MANAGER_TASK_NAME);
+ if (err != OS_NO_ERR) {
+ ASSERT(0, "task_create fail!!! %x\n", err);
+ }
+ os_sem_pend(&__this->sem, 0);
+#else
+ devices_init();
+#endif
+}
+
diff --git a/apps/common/dev_manager/dev_manager.h b/apps/common/dev_manager/dev_manager.h
new file mode 100644
index 0000000..d7573c9
--- /dev/null
+++ b/apps/common/dev_manager/dev_manager.h
@@ -0,0 +1,93 @@
+#ifndef __DEV_MANAGER_H__
+#define __DEV_MANAGER_H__
+
+#include "system/includes.h"
+#include "typedef.h"
+#include "system/fs/fs.h"
+
+enum {
+ DEV_MANAGER_ADD_OK = 0x0,
+ DEV_MANAGER_ADD_IN_LIST_AREADY,
+ DEV_MANAGER_ADD_ERR_PARM,
+ DEV_MANAGER_ADD_ERR_NOMEM,
+ DEV_MANAGER_ADD_ERR_NOT_FOUND,
+ DEV_MANAGER_ADD_ERR_MOUNT_FAIL,
+};
+
+
+struct __dev;
+
+struct __scan_callback {
+ void (*enter)(struct __dev *dev);
+ void (*exit)(struct __dev *dev);
+ int (*scan_break)(void);
+};
+
+//dev_manager增加设备节点
+int dev_manager_add(char *logo);
+//dev_manager删除设备节点
+int dev_manager_del(char *logo);
+//dev_manager获取设备总数
+u32 dev_manager_get_total(u8 valid);
+//dev_manager通过设备节点检查设备是否在设备链表中
+struct __dev *dev_manager_check(struct __dev *dev);
+//dev_manager通过逻辑盘符检查设备是否在设备链表中
+struct __dev *dev_manager_check_by_logo(char *logo);
+//dev_manager查找第一个设备
+struct __dev *dev_manager_find_first(u8 valid);
+//dev_manager查找最后一个设备
+struct __dev *dev_manager_find_last(u8 valid);
+//dev_manager查找参数设备的前一个设备
+struct __dev *dev_manager_find_prev(struct __dev *dev, u8 valid);
+//dev_manager查找参数设备的后一个设备
+struct __dev *dev_manager_find_next(struct __dev *dev, u8 valid);
+//dev_manager查找最后活动设备
+struct __dev *dev_manager_find_active(u8 valid);
+//dev_manager查找指定逻辑盘符对应的设备
+struct __dev *dev_manager_find_spec(char *logo, u8 valid);
+//dev_manager查找指定序号设备
+struct __dev *dev_manager_find_by_index(u32 index, u8 valid);
+//dev_manager扫盘句柄释放
+void dev_manager_scan_disk_release(struct vfscan *fsn);
+//dev_manager扫盘
+struct vfscan *dev_manager_scan_disk(struct __dev *dev, const char *path, const char *parm, u8 cycle_mode, struct __scan_callback *callback);
+//dev_manager设定指定设备节点设备有效
+void dev_manager_set_valid(struct __dev *dev, u8 flag);
+//dev_manager设定指定设备节点设备为最后活动设备
+void dev_manager_set_active(struct __dev *dev);
+//dev_manager设定指定逻辑盘符的设备有效
+void dev_manager_set_valid_by_logo(char *logo, u8 flag);
+//dev_manager设定指定逻辑盘符的设备为最后活动设备
+void dev_manager_set_active_by_logo(char *logo);
+//dev_manager获取指定设备节点的逻辑盘符
+char *dev_manager_get_logo(struct __dev *dev);
+//获取物理设备节点的逻辑盘符(去掉_rec后缀)
+char *dev_manager_get_phy_logo(struct __dev *dev);
+//获取录音文件夹设备节点的逻辑盘符(追加_rec后缀)
+char *dev_manager_get_rec_logo(struct __dev *dev);
+//dev_manager获取指定设备节点的文件系统根目录
+char *dev_manager_get_root_path(struct __dev *dev);
+//dev_manager获取指定逻辑盘符的设备的文件系统根目录
+char *dev_manager_get_root_path_by_logo(char *logo);
+//dev_manager通过设备节点获取设备mount信息
+struct imount *dev_manager_get_mount_hdl(struct __dev *dev);
+//dev_manager通过设备节点检查设备是否在线
+int dev_manager_online_check(struct __dev *dev, u8 valid);
+//dev_manager通过逻辑盘符检查设备是否在线
+int dev_manager_online_check_by_logo(char *logo, u8 valid);
+//通过逻辑盘符判断设备是否在设备链表中
+struct __dev *dev_manager_list_check_by_logo(char *logo);
+//检查链表中没有挂载的设备并重新挂载
+void dev_manager_list_check_mount(void);
+//设备挂载
+int dev_manager_mount(char *logo);
+//设备卸载
+int dev_manager_unmount(char *logo);
+
+//dev_manager初始化
+void dev_manager_init(void);
+
+void dev_manager_var_init();
+
+#endif//__DEV_MANAGER_H__
+
diff --git a/apps/common/dev_manager/dev_reg.c b/apps/common/dev_manager/dev_reg.c
new file mode 100644
index 0000000..773d220
--- /dev/null
+++ b/apps/common/dev_manager/dev_reg.c
@@ -0,0 +1,173 @@
+#include "dev_reg.h"
+#include "app_config.h"
+
+//*----------------------------------------------------------------------------*/
+/**@brief 设备配置表
+ @param 具体配置项请看struct __dev_reg结构体描述
+ @return
+ @note 注意:
+ 例如logo逻辑盘符sd0_rec/sd1_rec/udisk_rec是做录音文件夹区分使用的,
+ 在定义新的设备逻辑盘发的时候, 注意避开"_rec"后缀作为设备逻辑盘符
+*/
+/*----------------------------------------------------------------------------*/
+
+
+const struct __dev_reg dev_reg[] = {
+#if SDFILE_STORAGE && TCFG_CODE_FLASH_ENABLE
+ //内置flash
+ {
+ /*logo*/ SDFILE_DEV,
+ /*name*/ NULL,
+ /*storage_path*/ SDFILE_MOUNT_PATH,
+ /*root_path*/ SDFILE_RES_ROOT_PATH,
+ /*fs_type*/ "sdfile",
+ },
+#endif
+#if FLASH_INSIDE_REC_ENABLE
+ //内置录音
+ {
+ /*logo*/ "rec_sdfile",
+ /*name*/ NULL,
+ /*storage_path*/ "mnt/rec_sdfile",
+ /*root_path*/ "mnt/rec_sdfile/C/",
+ /*fs_type*/ "rec_sdfile",
+ },
+#endif
+#if (TCFG_SD0_ENABLE)
+ //sd0
+ {
+ /*logo*/ "sd0",
+ /*name*/ "sd0",
+ /*storage_path*/ "storage/sd0",
+ /*root_path*/ "storage/sd0/C/",
+ /*fs_type*/ "fat",
+ },
+#endif
+#if (TCFG_SD1_ENABLE)
+ //sd1
+ {
+ /*logo*/ "sd1",
+ /*name*/ "sd1",
+ /*storage_path*/ "storage/sd1",
+ /*root_path*/ "storage/sd1/C/",
+ /*fs_type*/ "fat",
+ },
+#endif
+#if (TCFG_UDISK_ENABLE)
+ //u盘
+ {
+ /*logo*/ "udisk0",
+ /*name*/ "udisk0",
+ /*storage_path*/ "storage/udisk0",
+ /*root_path*/ "storage/udisk0/C/",
+ /*fs_type*/ "fat",
+ },
+#endif
+#if (TCFG_SD0_ENABLE && TCFG_RECORD_FOLDER_DEV_ENABLE)
+ //sd0录音文件夹分区
+ {
+ /*logo*/ "sd0_rec",
+ /*name*/ "sd0",
+ /*storage_path*/ "storage/sd0",
+ /*root_path*/ "storage/sd0/C/"REC_FOLDER_NAME,
+ /*fs_type*/ "fat",
+ },
+#endif
+#if (TCFG_SD1_ENABLE && TCFG_RECORD_FOLDER_DEV_ENABLE)
+ //sd1录音文件夹分区
+ {
+ /*logo*/ "sd1_rec",
+ /*name*/ "sd1",
+ /*storage_path*/ "storage/sd1",
+ /*root_path*/ "storage/sd1/C/"REC_FOLDER_NAME,
+ /*fs_type*/ "fat",
+ },
+#endif
+#if (TCFG_UDISK_ENABLE && TCFG_RECORD_FOLDER_DEV_ENABLE)
+ //u盘录音文件夹分区
+ {
+ /*logo*/ "udisk0_rec",
+ /*name*/ "udisk0",
+ /*storage_path*/ "storage/udisk0",
+ /*root_path*/ "storage/udisk0/C/"REC_FOLDER_NAME,
+ /*fs_type*/ "fat",
+ },
+#endif
+#if TCFG_NOR_FAT
+ //外挂fat分区
+ {
+ /*logo*/ "fat_nor",
+ /*name*/ "fat_nor",
+ /*storage_path*/ "storage/fat_nor",
+ /*root_path*/ "storage/fat_nor/C/",
+ /*fs_type*/ "fat",
+ },
+#endif
+#if TCFG_NOR_FS
+ //外挂flash资源分区
+ {
+ /*logo*/ "res_nor",
+ /*name*/ "res_nor",
+ /*storage_path*/ "storage/res_nor",
+ /*root_path*/ "storage/res_nor/C/",
+ /*fs_type*/ "nor_sdfile",
+ },
+#endif
+#if TCFG_NOR_REC
+ ///外挂录音分区
+ {
+ /*logo*/ "rec_nor",
+ /*name*/ "rec_nor",
+ /*storage_path*/ "storage/rec_nor",
+ /*root_path*/ "storage/rec_nor/C/",
+ /*fs_type*/ "rec_fs",
+ },
+#endif
+ {
+ /*logo*/ "nor_ui",
+ /*name*/ "nor_ui",
+ /*storage_path*/ "storage/nor_ui",
+ /*root_path*/ "storage/nor_ui/C/",
+ /*fs_type*/ "nor_sdfile",
+ },
+#if TCFG_VIR_UDISK_ENABLE
+ // 虚拟U盘
+ {
+ /*logo*/ "vir_udisk0",
+ /*name*/ "vir_udisk0",
+ /*storage_path*/ "storage/vir_udisk0",
+ /*root_path*/ "storage/vir_udisk0/C/",
+ /*fs_type*/ "fat",
+ },
+#endif
+#if TCFG_VIRFAT_FLASH_ENABLE
+ //flash 虚拟fat
+ {
+ /*logo*/ "virfat_flash",
+ /*name*/ "virfat_flash",
+ /*storage_path*/ "storage/virfat_flash",
+ /*root_path*/ "storage/virfat_flash/C/",
+ /*fs_type*/ "sdfile_fat",
+ },
+#endif
+#if TCFG_NANDFLASH_DEV_ENABLE
+ {
+ /*logo*/ "nandflash_ftl",
+ /*name*/ "nandflash_ftl",
+ /*storage_path*/ "storage/nandflash_ftl",
+ /*root_path*/ "storage/nandflash_ftl/C/",
+ /*fs_type*/ "fat",
+ },
+#endif
+ //<新加设备参数请在reg end前添加!!
+ //type == type) {
+ parm = (struct __update_dev_reg *)update_dev_list[i];
+ }
+ }
+
+ if (parm == NULL) {
+ return NULL;
+ }
+ return (void *)&parm->u.sd;
+}
+
+
+struct strg_update {
+ void *fd;
+ char *update_path;
+};
+static struct strg_update strg_update = {0};
+#define __this (&strg_update)
+
+static u16 strg_f_open(void)
+{
+ if (!__this->update_path) {
+ printf("file path err ");
+ return false;
+ }
+
+ if (__this->fd) {
+ return true;
+ /* fclose(__this->fd);
+ __this->fd = NULL; */
+ }
+ __this->fd = fopen(__this->update_path, "r");
+ if (!__this->fd) {
+ printf("file open err ");
+ return false;
+ }
+ return true;
+}
+
+static u16 strg_f_read(void *fp, u8 *buff, u16 len)
+{
+ if (!__this->fd) {
+ return (u16) - 1;
+ }
+
+ len = fread(__this->fd, buff, len);
+ return len;
+}
+
+static int strg_f_seek(void *fp, u8 type, u32 offset)
+{
+ if (!__this->fd) {
+ return (int) - 1;
+ }
+
+ int ret = fseek(__this->fd, offset, type);
+ /* return 0; // 0k */
+ return ret;
+}
+static u16 strg_f_stop(u8 err)
+{
+ if (__this->fd) {
+ fclose(__this->fd);
+ __this->fd = NULL;
+ }
+ return true;
+}
+
+static int strg_update_set_file_path_and_hdl(char *update_path, void *fd)
+{
+ __this->update_path = update_path;
+ __this->fd = fd;
+
+ return true;
+}
+
+static const update_op_api_t strg_dev_update_op = {
+ .f_open = strg_f_open,
+ .f_read = strg_f_read,
+ .f_seek = strg_f_seek,
+ .f_stop = strg_f_stop,
+};
+
+static void dev_update_param_private_handle(UPDATA_PARM *p)
+{
+ u16 up_type = p->parm_type;
+
+#ifdef CONFIG_SD_UPDATE_ENABLE
+ if ((up_type == SD0_UPDATA) || (up_type == SD1_UPDATA)) {
+ int sd_start = (u32)p->parm_priv;
+ void *sd = NULL;
+ sd = dev_update_get_parm(up_type);
+ if (sd) {
+ memcpy((void *)sd_start, sd, UPDATE_PRIV_PARAM_LEN);
+ } else {
+ memset((void *)sd_start, 0, UPDATE_PRIV_PARAM_LEN);
+ }
+ }
+#endif
+
+#ifdef CONFIG_USB_UPDATE_ENABLE
+ if (up_type == USB_UPDATA) {
+ printf("usb updata ");
+ int usb_start = (u32)p->parm_priv;
+ memset((void *)usb_start, 0, UPDATE_PRIV_PARAM_LEN);
+ }
+#endif
+ memcpy(p->file_patch, updata_file_name, strlen(updata_file_name));
+}
+
+
+static void dev_update_before_jump_handle(u16 up_type)
+{
+#if (defined DEV_UPDATE_SUPPORT_JUMP) || (CONFIG_UPDATE_JUMP_TO_MASK)
+#if TCFG_BLUETOOTH_BACK_MODE //后台模式需要把蓝牙关掉
+ if (BT_MODULES_IS_SUPPORT(BT_MODULE_LE)) {
+ ll_hci_destory();
+ }
+ hci_controller_destory();
+#endif
+#if CONFIG_UPDATE_JUMP_TO_MASK
+ y_printf(">>>[test]:latch reset update\n");
+ latch_reset();
+
+#if 0
+ update_close_hw("null");
+ ram_protect_close();
+ save_spi_port();
+
+ extern void __BT_UPDATA_JUMP();
+ y_printf("update jump to __BT_UPDATA ...\n");
+ y_printf(">>>[test]:JL_IOMC = 0x%x\n", (JL_IOMAP->CON0 >> 16) & 0x3);
+ /* clk_set("sys", 48 * 1000000L); */
+ //跳转到uboot加载完,30ms左右(200410_yzb)
+ __BT_UPDATA_JUMP();
+#endif
+#else
+ printf("update jump to mask...\n");
+ /* JL_UART0->CON0 = 0; */
+ /* JL_UART1->CON0 = 0; */
+ __JUMP_TO_MASKROM();
+#endif
+#else
+ cpu_reset();
+#endif //DEV_UPDATE_SUPPORT_JUMP
+}
+
+static void dev_update_state_cbk(int type, u32 state, void *priv)
+{
+ update_ret_code_t *ret_code = (update_ret_code_t *)priv;
+
+ switch (state) {
+ case UPDATE_CH_EXIT:
+ if ((0 == ret_code->stu) && (0 == ret_code->err_code)) {
+ update_mode_api_v2(type,
+ dev_update_param_private_handle,
+ dev_update_before_jump_handle);
+ } else {
+ printf("update fail, cpu reset!!!\n");
+ cpu_reset();
+ }
+ break;
+ }
+}
+u16 dev_update_check(char *logo)
+{
+ if (update_success_boot_check() == true) {
+ return UPDATA_NON;
+ }
+ struct __dev *dev = dev_manager_find_spec(logo, 0);
+ if (dev) {
+#if DEV_UPDATE_EN
+ //<查找设备升级配置
+ struct __update_dev_reg *parm = NULL;
+ for (int i = 0; i < ARRAY_SIZE(update_dev_list); i++) {
+ if (0 == strcmp(update_dev_list[i]->logo, logo)) {
+ parm = (struct __update_dev_reg *)update_dev_list[i];
+ }
+ }
+ if (parm == NULL) {
+ printf("dev update without parm err!!!\n");
+ return UPDATA_PARM_ERR;
+ }
+ //<尝试按照路径打开升级文件
+ char *updata_file = (char *)updata_file_name;
+ if (*updata_file == '/') {
+ updata_file ++;
+ }
+ memset(update_path, 0, sizeof(update_path));
+ sprintf(update_path, "%s%s", dev_manager_get_root_path(dev), updata_file);
+ printf("update_path: %s\n", update_path);
+ FILE *fd = fopen(update_path, "r");
+ if (!fd) {
+ ///没有升级文件, 继续跑其他解码相关的流程
+ printf("open update file err!!!\n");
+ return UPDATA_DEV_ERR;
+ }
+
+#if(USER_UART_UPDATE_ENABLE) && (UART_UPDATE_ROLE == UART_UPDATE_MASTER)
+ uart_update_send_update_ready(update_path);
+ while (get_uart_update_sta()) {
+ os_time_dly(10);
+ }
+#else
+ ///进行升级
+
+ strg_update_set_file_path_and_hdl(update_path, (void *)fd);
+
+ update_mode_info_t info = {
+ .type = parm->type,
+ .state_cbk = dev_update_state_cbk,
+ .p_op_api = &strg_dev_update_op,
+ .task_en = 0,
+ };
+ app_active_update_task_init(&info);
+
+#endif// USER_UART_UPDATE_ENABLE
+
+#endif//DEV_UPDATE_EN
+ }
+ return UPDATA_READY;
+}
+
+
+
diff --git a/apps/common/dev_manager/dev_update.h b/apps/common/dev_manager/dev_update.h
new file mode 100644
index 0000000..dc7a0e6
--- /dev/null
+++ b/apps/common/dev_manager/dev_update.h
@@ -0,0 +1,10 @@
+#ifndef __DEV_UPDATE_H__
+#define __DEV_UPDATE_H__
+
+#include "typedef.h"
+#include "system/includes.h"
+
+void *dev_update_get_parm(int type);
+u16 dev_update_check(char *logo);
+
+#endif//__DEV_UPDATE_H__
diff --git a/apps/common/device/key/adkey.c b/apps/common/device/key/adkey.c
new file mode 100644
index 0000000..a9c69ca
--- /dev/null
+++ b/apps/common/device/key/adkey.c
@@ -0,0 +1,157 @@
+#include "key_driver.h"
+#include "adkey.h"
+#include "gpio.h"
+#include "system/event.h"
+#include "app_config.h"
+
+
+#if TCFG_ADKEY_ENABLE
+
+static const struct adkey_platform_data *__this = NULL;
+
+u8 ad_get_key_value(void);
+//按键驱动扫描参数列表
+struct key_driver_para adkey_scan_para = {
+ .scan_time = 10, //按键扫描频率, 单位: ms
+ .last_key = NO_KEY, //上一次get_value按键值, 初始化为NO_KEY;
+ .filter_time = 2, //按键消抖延时;
+ .long_time = 75, //按键判定长按数量
+ .hold_time = (75 + 15), //按键判定HOLD数量
+ .click_delay_time = 20, //按键被抬起后等待连击延时数量
+ .key_type = KEY_DRIVER_TYPE_AD,
+ .get_value = ad_get_key_value,
+};
+u8 ad_get_key_value(void)
+{
+ u8 i;
+ u16 ad_data;
+
+ if (!__this->enable) {
+ return NO_KEY;
+ }
+
+ /* ad_data = adc_get_voltage(__this->ad_channel); */
+ ad_data = adc_get_value(__this->ad_channel);
+ /* printf("ad_value = %d \n", ad_data); */
+ for (i = 0; i < ADKEY_MAX_NUM; i++) {
+ if ((ad_data <= __this->ad_value[i]) && (__this->ad_value[i] < 0x3ffL)) {
+ return __this->key_value[i];
+ }
+ }
+ return NO_KEY;
+}
+
+int adkey_init(const struct adkey_platform_data *adkey_data)
+{
+ __this = adkey_data;
+ if (!__this) {
+ return -EINVAL;
+ }
+
+ if (!__this->enable) {
+ return KEY_NOT_SUPPORT;
+ }
+ adc_add_sample_ch(__this->ad_channel); //注意:初始化AD_KEY之前,先初始化ADC
+#if (TCFG_ADKEY_LED_IO_REUSE || TCFG_ADKEY_IR_IO_REUSE || TCFG_ADKEY_LED_SPI_IO_REUSE)
+#else
+ gpio_set_die(__this->adkey_pin, 0);
+ gpio_set_direction(__this->adkey_pin, 1);
+ gpio_set_pull_down(__this->adkey_pin, 0);
+ if (__this->extern_up_en) {
+ gpio_set_pull_up(__this->adkey_pin, 0);
+ } else {
+ gpio_set_pull_up(__this->adkey_pin, 1);
+ }
+#endif
+
+ return 0;
+}
+
+#if (TCFG_ADKEY_LED_IO_REUSE || TCFG_ADKEY_IR_IO_REUSE || TCFG_ADKEY_LED_SPI_IO_REUSE)
+
+#if TCFG_ADKEY_IR_IO_REUSE
+static u8 ir_io_sus = 0;
+extern u8 ir_io_suspend(void);
+extern u8 ir_io_resume(void);
+#endif
+#if TCFG_ADKEY_LED_IO_REUSE
+static u8 led_io_sus = 0;
+extern u8 led_io_suspend(void);
+extern u8 led_io_resume(void);
+#endif
+#if TCFG_ADKEY_LED_SPI_IO_REUSE
+static u8 led_spi_sus = 0;
+extern u8 led_spi_suspend(void);
+extern u8 led_spi_resume(void);
+#endif
+u8 adc_io_reuse_enter(u32 ch)
+{
+ if (ch == __this->ad_channel) {
+#if TCFG_ADKEY_IR_IO_REUSE
+ if (ir_io_suspend()) {
+ return 1;
+ } else {
+ ir_io_sus = 1;
+ }
+#endif
+#if TCFG_ADKEY_LED_IO_REUSE
+ if (led_io_suspend()) {
+ return 1;
+ } else {
+ led_io_sus = 1;
+ }
+#endif
+#if TCFG_ADKEY_LED_SPI_IO_REUSE
+ if (led_spi_suspend()) {
+ return 1;
+ } else {
+ led_spi_sus = 1;
+ }
+#endif
+ gpio_set_die(__this->adkey_pin, 0);
+ gpio_set_direction(__this->adkey_pin, 1);
+ gpio_set_pull_down(__this->adkey_pin, 0);
+ if (__this->extern_up_en) {
+ gpio_set_pull_up(__this->adkey_pin, 0);
+ } else {
+ gpio_set_pull_up(__this->adkey_pin, 1);
+ }
+ }
+ return 0;
+}
+
+u8 adc_io_reuse_exit(u32 ch)
+{
+ if (ch == __this->ad_channel) {
+#if TCFG_ADKEY_IR_IO_REUSE
+ if (ir_io_sus) {
+ ir_io_sus = 0;
+ ir_io_resume();
+ }
+#endif
+#if TCFG_ADKEY_LED_IO_REUSE
+ if (led_io_sus) {
+ led_io_sus = 0;
+ led_io_resume();
+ }
+#endif
+#if TCFG_ADKEY_LED_SPI_IO_REUSE
+ if (led_spi_sus) {
+ led_spi_sus = 0;
+ led_spi_resume();
+ }
+#endif
+ }
+ return 0;
+}
+
+#endif
+
+
+
+#endif /* #if TCFG_ADKEY_ENABLE */
+
+
+
+
+
diff --git a/apps/common/device/key/adkey_rtcvdd.c b/apps/common/device/key/adkey_rtcvdd.c
new file mode 100644
index 0000000..cff4872
--- /dev/null
+++ b/apps/common/device/key/adkey_rtcvdd.c
@@ -0,0 +1,253 @@
+#include "includes.h"
+#include "key_driver.h"
+#include "adkey.h"
+#include "gpio.h"
+#include "system/event.h"
+#include "app_config.h"
+#include "asm/power/p33.h"
+
+#if TCFG_ADKEY_RTCVDD_ENABLE
+
+#define ADKEY_RTCVDD_DEBUG 1
+#if ADKEY_RTCVDD_DEBUG
+#define adkey_rtcvdd_debug(fmt, ...) printf("[ADKEY_RTCVDD] "fmt, ##__VA_ARGS__)
+#else
+#define adkey_rtcvdd_debug(fmt, ...)
+#endif
+
+#define ADC_KEY_NUMBER 10
+
+#define FULL_ADC 0x3ffL
+
+#define ADC_FULL(x) (x)
+#define ADC_VOLTAGE(x,y,z) ((x*y) / (y + z)) //x当前满幅电压,y分压电阻,z上拉电阻
+#define ADC_ZERRO(x) (0)
+
+u16 ad_rtcvdd_key_table[ADC_KEY_NUMBER + 1] = {0};
+
+#define FULL_AD_VOLTAGE 0x3FFF
+
+volatile u8 adkey_lock_cnt = 0;
+static u8 rtcvdd_cnt = 10;
+static u8 rtcvdd_full_cnt = 0xff;
+u16 rtcvdd_full_value = FULL_AD_VOLTAGE;
+u16 max_value = 0;
+u16 min_value = 0xffff;
+u32 total_value = 0;
+static u8 check_rtcvdd_cnt = 0;
+
+static const struct adkey_rtcvdd_platform_data *__this = NULL;
+
+
+u8 adkey_rtcvdd_get_key_value(void);
+//按键驱动扫描参数列表
+struct key_driver_para adkey_rtcvdd_scan_para = {
+ .scan_time = 10, //按键扫描频率, 单位: ms
+ .last_key = NO_KEY, //上一次get_value按键值, 初始化为NO_KEY;
+ .filter_time = 2, //按键消抖延时;
+ .long_time = 75, //按键判定长按数量
+ .hold_time = (75 + 15), //按键判定HOLD数量
+ .click_delay_time = 20, //按键被抬起后等待连击延时数量
+ .key_type = KEY_DRIVER_TYPE_RTCVDD_AD,
+ .get_value = adkey_rtcvdd_get_key_value,
+};
+
+static void set_rtcvdd_table(u16 adc_rtcvdd)
+{
+ u8 i;
+ u32 extern_up_res_value = __this->extern_up_res_value;
+
+ if (extern_up_res_value == 0) { //使用内部上拉
+ extern_up_res_value = 100;
+ }
+
+ for (i = 0; i < __this->adkey_num; i++) {
+ if (i == (__this->adkey_num - 1)) {
+ ad_rtcvdd_key_table[i] = (ADC_VOLTAGE(adc_rtcvdd, __this->res_value[i], extern_up_res_value) + ADC_FULL(adc_rtcvdd)) / 2;
+ //adkey_rtcvdd_debug("recvdd = %d, res_value[%d] = %d", adc_rtcvdd, i, __this->res_value[i]);
+ } else {
+ ad_rtcvdd_key_table[i] = (ADC_VOLTAGE(adc_rtcvdd, __this->res_value[i], extern_up_res_value) + ADC_VOLTAGE(adc_rtcvdd, __this->res_value[i + 1], extern_up_res_value)) / 2;
+ //adkey_rtcvdd_debug("res_value[%d] = %d, res_value[%d] = %d", i, __this->res_value[i], i + 1, __this->res_value[i+1]);
+ }
+ }
+}
+
+static void SET_ADKEY_LOCK_CNT(u8 cnt)
+{
+ CPU_SR_ALLOC();
+ OS_ENTER_CRITICAL();
+
+ adkey_lock_cnt = cnt;
+
+ OS_EXIT_CRITICAL();
+}
+
+static u8 GET_ADKEY_LOCK_CNT(void)
+{
+ u8 val;
+ CPU_SR_ALLOC();
+ OS_ENTER_CRITICAL();
+
+ val = adkey_lock_cnt;
+
+ OS_EXIT_CRITICAL();
+ return val;
+}
+
+static void POST_ADKEY_LOCK_CNT(void)
+{
+ CPU_SR_ALLOC();
+ OS_ENTER_CRITICAL();
+
+ adkey_lock_cnt --;
+
+ OS_EXIT_CRITICAL();
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief ad按键初始化
+ @param void
+ @param void
+ @return void
+ @note void ad_key0_init(void)
+*/
+/*----------------------------------------------------------------------------*/
+int adkey_rtcvdd_init(const struct adkey_rtcvdd_platform_data *adkey_data)
+{
+ adkey_rtcvdd_debug("ad key init\n");
+
+ __this = adkey_data;
+ if (!__this) {
+ return -EINVAL;
+ }
+
+ if (__this->extern_up_res_value == 0) { //使用内部上拉
+ gpio_set_pull_up(__this->adkey_pin, 1);
+ } else {
+ gpio_set_pull_up(__this->adkey_pin, 0);
+ }
+ gpio_set_direction(__this->adkey_pin, 1);
+ gpio_set_pull_down(__this->adkey_pin, 0);
+ gpio_set_die(__this->adkey_pin, 0);
+
+ adc_add_sample_ch(__this->ad_channel); //注意:初始化AD_KEY之前,先初始化ADC
+ adc_add_sample_ch(AD_CH_RTCVDD);
+
+ set_rtcvdd_table(FULL_ADC);
+
+ return 0;
+}
+
+
+/*把cnt个值里的最大值和最小值去掉,求剩余cnt-2个数的平均值*/
+static u16 rtcvdd_full_vaule_update(u16 value)
+{
+ u16 full_value = FULL_ADC;
+ if (rtcvdd_full_cnt == 0xff) {
+ rtcvdd_full_cnt = 0;
+ SET_ADKEY_LOCK_CNT(50);
+ return value; //first time
+ } else {
+ rtcvdd_full_cnt ++;
+ if (value > max_value) {
+ max_value = value;
+ }
+ if (value < min_value) {
+ min_value = value;
+ }
+ total_value += value;
+
+ if (rtcvdd_full_cnt > 10 - 1) { //算10个数
+ full_value = (total_value - max_value - min_value) / (rtcvdd_full_cnt - 2);
+ rtcvdd_full_cnt = 0;
+ max_value = 0;
+ min_value = 0xffff;
+ total_value = 0;
+ } else {
+ return rtcvdd_full_value;
+ }
+ }
+ return full_value;
+}
+
+u8 get_rtcvdd_level(void)
+{
+ u8 level = GET_RTCVDD_VOL();
+ return level;
+}
+
+void set_rtcvdd_level(u8 level)
+{
+ if (level > 7 || level < 0) {
+ return;
+ }
+ RTCVDD_VOL_SEL(level);
+}
+/*检测到RTCVDD 比 VDDIO 高的时候自动把RTCVDD降一档*/
+static u8 rtcvdd_auto_match_vddio_lev(u32 rtcvdd_value)
+{
+ u8 rtcvdd_lev = 0;
+ if (rtcvdd_value >= FULL_ADC) { //trim rtcvdd < vddio
+ if (rtcvdd_cnt > 10) {
+ rtcvdd_cnt = 0;
+ rtcvdd_lev = get_rtcvdd_level();
+ if (rtcvdd_lev < 8) {
+ rtcvdd_lev++; //降一档
+ /* rtcvdd_lev--; //降一档 */
+ set_rtcvdd_level(rtcvdd_lev);
+ SET_ADKEY_LOCK_CNT(50);
+ return 1;
+ }
+ } else {
+ rtcvdd_cnt ++;
+ }
+ } else {
+ rtcvdd_cnt = 0;
+ rtcvdd_full_value = rtcvdd_full_vaule_update(rtcvdd_value);
+ }
+ return 0;
+}
+
+
+
+/*----------------------------------------------------------------------------*/
+/**@brief 获取ad按键值
+ @param void
+ @param void
+ @return key_number
+ @note tu8 adkey_rtcvdd_get_key_value(void)
+*/
+/*----------------------------------------------------------------------------*/
+u8 adkey_rtcvdd_get_key_value(void)
+{
+ u8 key_number, i;
+ u32 ad_value;
+ u16 rtcvdd_value = 0;
+
+ rtcvdd_value = 2 * adc_get_value(AD_CH_RTCVDD);
+ ad_value = adc_get_value(__this->ad_channel);
+
+ /* printf("rtcvdd_value = %d, ad_value = %d", rtcvdd_value, ad_value); */
+ if (rtcvdd_auto_match_vddio_lev(rtcvdd_value)) {
+ return NO_KEY;
+ }
+
+ if (GET_ADKEY_LOCK_CNT()) {
+ POST_ADKEY_LOCK_CNT();
+ return NO_KEY;
+ }
+
+ set_rtcvdd_table(rtcvdd_full_value);
+
+ for (i = 0; i < __this->adkey_num; i++) {
+ if (ad_value <= ad_rtcvdd_key_table[i] && (ad_rtcvdd_key_table[i] < 0x3FFL)) {
+ return __this->key_value[i];
+ }
+ }
+
+ return NO_KEY;
+}
+
+
+#endif /* #if TCFG_ADKEY_RTCVDD_ENABLE */
+
diff --git a/apps/common/device/key/ctmu_touch_key.c b/apps/common/device/key/ctmu_touch_key.c
new file mode 100644
index 0000000..80344d3
--- /dev/null
+++ b/apps/common/device/key/ctmu_touch_key.c
@@ -0,0 +1,61 @@
+#include "key_driver.h"
+#include "app_config.h"
+
+
+
+#if TCFG_CTMU_TOUCH_KEY_ENABLE
+#include "asm/ctmu.h"
+
+#define LOG_TAG_CONST CTMU
+#define LOG_TAG "[ctmu]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+/* =========== 触摸键使用说明 ============= */
+//1. 使用ctmu模块作计数;
+
+static const struct ctmu_touch_key_platform_data *__this = NULL;
+
+static u8 ctmu_touch_key_get_value(void);
+//按键驱动扫描参数列表
+struct key_driver_para ctmu_touch_key_scan_para = {
+ .scan_time = 10, //按键扫描频率, 单位: ms
+ .last_key = NO_KEY, //上一次get_value按键值, 初始化为NO_KEY;
+ .filter_time = 2, //按键消抖延时;
+ .long_time = 55, //按键判定长按数量
+ .hold_time = (55 + 15), //按键判定HOLD数量
+ .click_delay_time = 40, //按键被抬起后等待连击延时数量
+ .key_type = KEY_DRIVER_TYPE_CTMU_TOUCH,
+ .get_value = ctmu_touch_key_get_value,
+};
+
+
+
+static u8 ctmu_touch_key_get_value(void)
+{
+ u8 key = get_ctmu_value();
+
+ if (key != NO_KEY) {
+ log_debug("key = %d %x", key, __this->port_list[key].key_value);
+ return __this->port_list[key].key_value;
+ }
+
+ return NO_KEY;
+}
+
+
+int ctmu_touch_key_init(const struct ctmu_touch_key_platform_data *ctmu_touch_key_data)
+{
+ __this = ctmu_touch_key_data;
+ log_info("ctmu touch_key_init >>>> ");
+
+ return ctmu_init((void *)ctmu_touch_key_data);
+}
+
+
+#endif /* #if TCFG_CTMU_TOUCH_KEY_ENABLE */
+
diff --git a/apps/common/device/key/iokey.c b/apps/common/device/key/iokey.c
new file mode 100644
index 0000000..95d6b13
--- /dev/null
+++ b/apps/common/device/key/iokey.c
@@ -0,0 +1,355 @@
+#include "key_driver.h"
+#include "iokey.h"
+#include "gpio.h"
+#include "system/event.h"
+#include "app_config.h"
+#include "asm/clock.h"
+
+#if TCFG_IOKEY_ENABLE
+
+static const struct iokey_platform_data *__this = NULL;
+
+u8 io_get_key_value(void);
+
+#if MOUSE_KEY_SCAN_MODE
+struct key_driver_para iokey_scan_para = {
+ .scan_time = 5, //按键扫描频率, 单位: ms
+ .last_key = NO_KEY, //上一次get_value按键值, 初始化为NO_KEY;
+ .filter_time = 2, //按键消抖延时;
+ .long_time = 5, //按键判定长按数量
+ .hold_time = (5 + 0), //按键判定HOLD数量
+ .click_delay_time = 20, //按键被抬起后等待连击延时数量
+ .key_type = KEY_DRIVER_TYPE_IO,
+ .get_value = io_get_key_value,
+};
+#else
+//按键驱动扫描参数列表
+struct key_driver_para iokey_scan_para = {
+ .scan_time = 10, //按键扫描频率, 单位: ms
+ .last_key = NO_KEY, //上一次get_value按键值, 初始化为NO_KEY;
+ .filter_time = 4, //按键消抖延时;
+ .long_time = 75, //按键判定长按数量
+ .hold_time = (75 + 15), //按键判定HOLD数量
+ .click_delay_time = 20, //按键被抬起后等待连击延时数量
+ .key_type = KEY_DRIVER_TYPE_IO,
+ .get_value = io_get_key_value,
+};
+#endif
+
+#define MARK_BIT_VALUE(b, v) do {if ((v & (~BIT(7))) < 7) b |= BIT(v & (~BIT(7)));} while(0)
+
+static void key_io_pull_down_input(u8 key_io)
+{
+ gpio_direction_input(key_io);
+ gpio_set_pull_down(key_io, 1);
+ gpio_set_pull_up(key_io, 0);
+ gpio_set_die(key_io, 1);
+}
+
+
+static void key_io_pull_up_input(u8 key_io)
+{
+ gpio_direction_input(key_io);
+ gpio_set_pull_down(key_io, 0);
+ gpio_set_pull_up(key_io, 1);
+ gpio_set_die(key_io, 1);
+}
+
+static void key_io_output_high(u8 key_io)
+{
+ gpio_set_pull_down(key_io, 0);
+ gpio_set_pull_up(key_io, 0);
+ gpio_direction_output(key_io, 1);
+}
+
+static void key_io_output_low(u8 key_io)
+{
+ gpio_set_pull_down(key_io, 0);
+ gpio_set_pull_up(key_io, 0);
+ gpio_direction_output(key_io, 0);
+}
+
+static int get_io_key_value(u8 key_io)
+{
+ return gpio_read(key_io);
+}
+
+
+static void key_io_reset(void)
+{
+ int i;
+
+ for (i = 0; i < __this->num; i++) {
+ switch (__this->port[i].connect_way) {
+ case ONE_PORT_TO_HIGH:
+ key_io_pull_down_input(__this->port[i].key_type.one_io.port);
+ break;
+
+ case ONE_PORT_TO_LOW:
+#if (TCFG_IO_MULTIPLEX_WITH_SD == ENABLE)
+ if (TCFG_MULTIPLEX_PORT != __this->port[i].key_type.one_io.port) {
+ key_io_pull_up_input(__this->port[i].key_type.one_io.port);
+ }
+#else
+
+ key_io_pull_up_input(__this->port[i].key_type.one_io.port);
+#endif
+ break;
+
+ case DOUBLE_PORT_TO_IO:
+ break;
+
+ default:
+ ASSERT(0, "IO KEY CONNECT ERR!!!");
+ break;
+ }
+ }
+}
+
+
+#if MULT_KEY_ENABLE
+extern const struct key_remap_data iokey_remap_data;
+static u8 iokey_value_remap(u8 bit_mark)
+{
+ for (int i = 0; i < iokey_remap_data.remap_num; i++) {
+ if (iokey_remap_data.table[i].bit_value == bit_mark) {
+ return iokey_remap_data.table[i].remap_value;
+ }
+ }
+
+ return NO_KEY;
+}
+#endif
+
+
+#if TCFG_IO_MULTIPLEX_WITH_SD == ENABLE
+static u8 mult_key_value = 1;
+static void udelay(u32 usec)
+{
+ JL_TIMER0->CON = BIT(14);
+ JL_TIMER0->CNT = 0;
+ JL_TIMER0->PRD = clk_get("lsb") / 1000000L * usec;
+ JL_TIMER0->CON = BIT(0); //lsb clk
+ while ((JL_TIMER0->CON & BIT(15)) == 0);
+ JL_TIMER0->CON = BIT(14);
+}
+extern u8 sd_io_suspend(u8 sdx, u8 sd_io);
+extern u8 sd_io_resume(u8 sdx, u8 sd_io);
+void sd_mult_io_detect(void *arg)
+{
+ static u32 cnt = 0;
+ if (sd_io_suspend(1, 1) == 0) {
+ gpio_set_direction(TCFG_MULTIPLEX_PORT, 0);
+ gpio_write(TCFG_MULTIPLEX_PORT, 0);
+ udelay(10);
+ gpio_set_die(TCFG_MULTIPLEX_PORT, 1);
+ gpio_set_pull_down(TCFG_MULTIPLEX_PORT, 0);
+ gpio_set_pull_up(TCFG_MULTIPLEX_PORT, 1);
+ gpio_set_direction(TCFG_MULTIPLEX_PORT, 1);
+ udelay(10);
+ mult_key_value = gpio_read(TCFG_MULTIPLEX_PORT);
+ sd_io_resume(1, 1);
+ }
+}
+#endif
+
+__attribute__((weak)) u8 iokey_filter_hook(u8 io_state)
+{
+ return 0;
+}
+
+/* 开机锁键剩余确认次数;非 0 时扫描一律返回 NO_KEY */
+static u8 s_boot_lock_cnt;
+
+/**
+ * @brief 启动/关闭开机锁键
+ * @param release_cnt >0:松开后连续确认次数;0:关闭
+ */
+void iokey_boot_lock_start(u8 release_cnt)
+{
+#if TCFG_IOKEY_BOOT_LOCK_ENABLE
+ s_boot_lock_cnt = release_cnt;
+#else
+ (void)release_cnt;
+ s_boot_lock_cnt = 0;
+#endif
+}
+
+/**
+ * @brief 立即关闭开机锁键
+ */
+void iokey_boot_lock_stop(void)
+{
+ s_boot_lock_cnt = 0;
+}
+
+/**
+ * @brief 扫描路径更新锁键:监视 port[0],松开则递减计数
+ * @return 1=仍锁定(应返回 NO_KEY),0=已解锁可正常扫描
+ */
+static u8 iokey_boot_lock_update(void)
+{
+#if !TCFG_IOKEY_BOOT_LOCK_ENABLE
+ return 0;
+#else
+ u8 key_io;
+ u8 io_level;
+ u8 released;
+
+ if (!s_boot_lock_cnt)
+ {
+ return 0;
+ }
+ if (!__this || (__this->num == 0))
+ {
+ return 1;
+ }
+
+ key_io = __this->port[0].key_type.one_io.port;
+ io_level = gpio_read(key_io);
+ if (__this->port[0].connect_way == ONE_PORT_TO_LOW)
+ {
+ released = io_level; /* 上拉输入,松开为高 */
+ }
+ else
+ {
+ released = !io_level; /* 下拉输入,松开为低 */
+ }
+
+ if (released)
+ {
+ s_boot_lock_cnt--;
+ if (s_boot_lock_cnt == 0)
+ {
+ puts("iokey boot lock released\n");
+ }
+ }
+ return 1; /* 本拍仍屏蔽;计数到 0 后下一拍才开放 */
+#endif
+}
+
+u8 io_get_key_value(void)
+{
+ int i;
+
+ u8 press_value = 0;
+ u8 read_value = 0;
+ u8 read_io;
+ u8 write_io;
+ u8 connect_way;
+ u8 ret_value = NO_KEY;
+ u8 bit_mark = 0;
+
+ if (!__this->enable) {
+ return NO_KEY;
+ }
+ if (iokey_boot_lock_update()) {
+ return NO_KEY;
+ }
+ //先扫描单IO接按键方式
+ for (i = 0; i < __this->num; i++) {
+ connect_way = __this->port[i].connect_way;
+
+ if (connect_way == ONE_PORT_TO_HIGH) {
+ press_value = 1;
+ } else if (connect_way == ONE_PORT_TO_LOW) {
+ press_value = 0;
+ } else {
+ continue;
+ }
+
+ read_io = __this->port[i].key_type.one_io.port;
+
+#if (TCFG_IO_MULTIPLEX_WITH_SD == ENABLE)
+ if (read_io == TCFG_MULTIPLEX_PORT) {
+ read_value = mult_key_value;
+ } else {
+ read_value = get_io_key_value(read_io);
+ }
+#else
+ read_value = get_io_key_value(read_io);
+#endif
+ if (iokey_filter_hook(read_value)) {
+#ifdef TCFG_IOKEY_TIME_REDEFINE
+ extern struct key_driver_para iokey_scan_user_para;
+ iokey_scan_user_para.filter_cnt = 0;
+ iokey_scan_user_para.press_cnt = 0;
+ iokey_scan_user_para.click_cnt = 0;
+ iokey_scan_user_para.click_delay_cnt = 0;
+ iokey_scan_user_para.last_key = NO_KEY;
+#else
+ iokey_scan_para.filter_cnt = 0;
+ iokey_scan_para.press_cnt = 0;
+ iokey_scan_para.click_cnt = 0;
+ iokey_scan_para.click_delay_cnt = 0;
+ iokey_scan_para.last_key = NO_KEY;
+#endif
+ return NO_KEY;
+ }
+ if (read_value == press_value) {
+ ret_value = __this->port[i].key_value;
+#if MULT_KEY_ENABLE
+ MARK_BIT_VALUE(bit_mark, ret_value); //标记被按下的按键
+#else
+ goto _iokey_get_value_end;
+#endif
+ }
+ }
+
+ //再扫描两个IO接按键方式, in_port: 上拉输入, out_port: 输出低
+ for (i = 0; i < __this->num; i++) {
+ connect_way = __this->port[i].connect_way;
+ if (connect_way == DOUBLE_PORT_TO_IO) {//标准双io
+ press_value = 0;
+ read_io = __this->port[i].key_type.two_io.in_port;
+ key_io_output_low(__this->port[i].key_type.two_io.out_port); //输出低
+ key_io_pull_up_input(read_io); //上拉
+ read_value = get_io_key_value(read_io);
+ key_io_reset(); //按键初始化为单IO检测状态
+ if (read_value == press_value) {
+ ret_value = __this->port[i].key_value;
+#if MULT_KEY_ENABLE
+ MARK_BIT_VALUE(bit_mark, ret_value); //标记被按下的按键
+#else
+ goto _iokey_get_value_end;
+#endif
+ }
+ }
+ }
+
+#if MULT_KEY_ENABLE
+ bit_mark = iokey_value_remap(bit_mark); //组合按键重新映射按键值
+ ret_value = (bit_mark != NO_KEY) ? bit_mark : ret_value;
+#endif
+
+_iokey_get_value_end:
+ return ret_value;
+}
+
+
+
+int iokey_init(const struct iokey_platform_data *iokey_data)
+{
+ int i;
+
+ __this = iokey_data;
+ if (__this == NULL) {
+ return -EINVAL;
+ }
+ if (!__this->enable) {
+ return KEY_NOT_SUPPORT;
+ }
+
+ /* 长按开机场景:等电源键(port[0])松开后再开放按键扫描 */
+#if TCFG_IOKEY_BOOT_LOCK_ENABLE
+ iokey_boot_lock_start(IOKEY_BOOT_LOCK_DEFAULT_CNT);
+#else
+ iokey_boot_lock_stop();
+#endif
+ key_io_reset();
+
+ return 0;
+}
+
+#endif /* #if TCFG_IOKEY_ENABLE */
+
diff --git a/apps/common/device/key/irkey.c b/apps/common/device/key/irkey.c
new file mode 100644
index 0000000..887dcd1
--- /dev/null
+++ b/apps/common/device/key/irkey.c
@@ -0,0 +1,78 @@
+#include "key_driver.h"
+#include "irkey.h"
+#include "gpio.h"
+#include "asm/irflt.h"
+#include "app_config.h"
+
+#if TCFG_IRKEY_ENABLE
+
+u8 ir_get_key_value(void);
+//按键驱动扫描参数列表
+struct key_driver_para irkey_scan_para = {
+ .scan_time = 10, //按键扫描频率, 单位: ms
+ .last_key = NO_KEY, //上一次get_value按键值, 初始化为NO_KEY;
+ .filter_time = 2, //按键消抖延时;
+ .long_time = 75, //按键判定长按数量
+ .hold_time = (75 + 15), //按键判定HOLD数量
+ .click_delay_time = 20, //按键被抬起后等待连击延时数量
+ .key_type = KEY_DRIVER_TYPE_IR,
+ .get_value = ir_get_key_value,
+};
+
+
+
+const u8 IRTabFF00[] = {
+ NKEY_00, NKEY_01, NKEY_02, NKEY_03, NKEY_04, NKEY_05, NKEY_06, IR_06, IR_15, IR_08, NKEY_0A, NKEY_0B, IR_12, IR_11, NKEY_0E, NKEY_0F,
+ NKEY_10, NKEY_11, NKEY_12, NKEY_13, NKEY_14, IR_07, IR_09, NKEY_17, IR_13, IR_10, NKEY_1A, NKEY_1B, IR_16, NKEY_1D, NKEY_1E, NKEY_1F,
+ NKEY_20, NKEY_21, NKEY_22, NKEY_23, NKEY_24, NKEY_25, NKEY_26, NKEY_27, NKEY_28, NKEY_29, NKEY_2A, NKEY_2B, NKEY_2C, NKEY_2D, NKEY_2E, NKEY_2F,
+ NKEY_30, NKEY_31, NKEY_32, NKEY_33, NKEY_34, NKEY_35, NKEY_36, NKEY_37, NKEY_38, NKEY_39, NKEY_3A, NKEY_3B, NKEY_3C, NKEY_3D, NKEY_3E, NKEY_3F,
+ IR_04, NKEY_41, IR_18, IR_05, IR_03, IR_00, IR_01, IR_02, NKEY_48, NKEY_49, IR_20, NKEY_4B, NKEY_4C, NKEY_4D, NKEY_4E, NKEY_4F,
+ NKEY_50, NKEY_51, IR_19, NKEY_53, NKEY_54, NKEY_55, NKEY_56, NKEY_57, NKEY_58, NKEY_59, IR_17, NKEY_5B, NKEY_5C, NKEY_5D, IR_14, NKEY_5F,
+};
+
+
+/*----------------------------------------------------------------------------*/
+/**@brief 获取ir按键值
+ @param void
+ @param void
+ @return void
+ @note void get_irkey_value(void)
+*/
+/*----------------------------------------------------------------------------*/
+u8 ir_get_key_value(void)
+{
+ u8 tkey = 0xff;
+ tkey = get_irflt_value();
+ if (tkey == 0xff) {
+ return tkey;
+ }
+ tkey = IRTabFF00[tkey];
+ return tkey;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**@brief ir按键初始化
+ @param void
+ @param void
+ @return void
+ @note void ir_key_init(void)
+*/
+/*----------------------------------------------------------------------------*/
+int irkey_init(const struct irkey_platform_data *irkey_data)
+{
+ printf("irkey_init ");
+
+ ir_input_io_sel(irkey_data->port);
+
+ ir_output_timer_sel();
+
+ irflt_config();
+
+ ir_timeout_set();
+
+ return 0;
+}
+
+#endif
+
diff --git a/apps/common/device/key/key_driver.c b/apps/common/device/key/key_driver.c
new file mode 100644
index 0000000..e9574fd
--- /dev/null
+++ b/apps/common/device/key/key_driver.c
@@ -0,0 +1,380 @@
+#include "device/key_driver.h"
+#include "system/event.h"
+#include "system/init.h"
+#include "iokey.h"
+#include "adkey.h"
+#include "slidekey.h"
+#include "irkey.h"
+#include "touch_key.h"
+#include "system/timer.h"
+#include "asm/power_interface.h"
+#include "app_config.h"
+#include "rdec_key.h"
+#include "tent600_key.h"
+#if TCFG_KEY_TONE_EN
+#include "tone_player.h"
+#endif
+
+#if(TCFG_IRSENSOR_ENABLE == 1)
+#include "irSensor/ir_manage.h"
+#endif
+
+#define LOG_TAG_CONST KEY
+#define LOG_TAG "[KEY]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+//#define LOG_DUMP_ENABLE
+//#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#define KEY_EVENT_CLICK_ONLY_SUPPORT 1 //是否支持某些按键只响应单击事件
+
+
+#if TCFG_SPI_LCD_ENABLE
+#ifndef ALL_KEY_EVENT_CLICK_ONLY
+#define ALL_KEY_EVENT_CLICK_ONLY 1 //是否全部按键只响应单击事件
+#endif
+#else
+#ifndef ALL_KEY_EVENT_CLICK_ONLY
+#define ALL_KEY_EVENT_CLICK_ONLY 0 //是否全部按键只响应单击事件
+#endif
+#endif
+
+static volatile u8 is_key_active = 0;
+static volatile u8 key_poweron_flag = 0;
+
+extern u32 timer_get_ms(void);
+
+//=======================================================//
+// 按键值重新映射函数:
+// 用户可以实现该函数把一些按键值重新映射, 可用于组合键的键值重新映射
+//=======================================================//
+int __attribute__((weak)) key_event_remap(struct sys_event *e)
+{
+ return true;
+}
+
+//=======================================================//
+// 设置按键开机标志位
+//=======================================================//
+void set_key_poweron_flag(u8 flag)
+{
+ key_poweron_flag = flag;
+}
+
+//=======================================================//
+// 获取按键开机标志位
+//=======================================================//
+u8 get_key_poweron_flag(void)
+{
+ return key_poweron_flag;
+}
+
+//=======================================================//
+// 清除按键开机标志位
+//=======================================================//
+void clear_key_poweron_flag(void)
+{
+ key_poweron_flag = 0;
+}
+
+//=======================================================//
+// 按键扫描函数: 扫描所有注册的按键驱动
+//=======================================================//
+static void key_driver_scan(void *_scan_para)
+{
+ struct key_driver_para *scan_para = (struct key_driver_para *)_scan_para;
+
+ u8 key_event = 0;
+ u8 cur_key_value = NO_KEY;
+ u8 key_value = 0;
+ struct sys_event e;
+ static u8 poweron_cnt = 0;
+
+ //为了滤掉adkey与mic连在一起时电容充放电导致的开机按键误判,一般用于type-c耳机
+ /* if (poweron_cnt <= 250) { */
+ /* poweron_cnt++; */
+ /* return; */
+ /* } */
+
+ cur_key_value = scan_para->get_value();
+ /* if (cur_key_value != NO_KEY) { */
+ /* printf(">>>cur_key_value: %d\n", cur_key_value); */
+ /* } */
+
+ if (cur_key_value != NO_KEY) {
+ is_key_active = 35; //35*10Ms
+ } else if (is_key_active) {
+ is_key_active --;
+ }
+//===== 按键消抖处理
+ if (cur_key_value != scan_para->filter_value && scan_para->filter_time) { //当前按键值与上一次按键值如果不相等, 重新消抖处理, 注意filter_time != 0;
+ scan_para->filter_cnt = 0; //消抖次数清0, 重新开始消抖
+ scan_para->filter_value = cur_key_value; //记录上一次的按键值
+ return; //第一次检测, 返回不做处理
+ } //当前按键值与上一次按键值相等, filter_cnt开始累加;
+ if (scan_para->filter_cnt < scan_para->filter_time) {
+ scan_para->filter_cnt++;
+ return;
+ }
+ //为了滤掉adkey与mic连在一起时电容充放电导致的按键误判,一般用于type-c耳机
+ /* if ((cur_key_value != scan_para->last_key) && (scan_para->last_key != NO_KEY) && (cur_key_value != NO_KEY)) { */
+ /* return; */
+ /* } */
+//===== 按键消抖结束, 开始判断按键类型(单击, 双击, 长按, 多击, HOLD, (长按/HOLD)抬起)
+ if (cur_key_value != scan_para->last_key) {
+ if (cur_key_value == NO_KEY) { //cur_key = NO_KEY; last_key = valid_key -> 按键被抬起
+
+#if MOUSE_KEY_SCAN_MODE
+ /* if (scan_para->press_cnt >= scan_para->long_time) { //长按/HOLD状态之后被按键抬起; */
+ key_event = KEY_EVENT_UP;
+ key_value = scan_para->last_key;
+ goto _notify; //发送抬起消息
+ /* } */
+#else
+ if (scan_para->press_cnt >= scan_para->long_time) { //长按/HOLD状态之后被按键抬起;
+ key_event = KEY_EVENT_UP;
+ key_value = scan_para->last_key;
+ goto _notify; //发送抬起消息
+ }
+#endif
+
+ scan_para->click_delay_cnt = 1; //按键等待下次连击延时开始
+ } else { //cur_key = valid_key, last_key = NO_KEY -> 按键被按下
+ scan_para->press_cnt = 1; //用于判断long和hold事件的计数器重新开始计时;
+ if (cur_key_value != scan_para->notify_value) { //第一次单击/连击时按下的是不同按键, 单击次数重新开始计数
+ scan_para->click_cnt = 1;
+ scan_para->notify_value = cur_key_value;
+ } else {
+ scan_para->click_cnt++; //单击次数累加
+ }
+ }
+ goto _scan_end; //返回, 等待延时时间到
+ } else { //cur_key = last_key -> 没有按键按下/按键长按(HOLD)
+ if (cur_key_value == NO_KEY) { //last_key = NO_KEY; cur_key = NO_KEY -> 没有按键按下
+ if (scan_para->click_cnt > 0) { //有按键需要消息需要处理
+
+#if ALL_KEY_EVENT_CLICK_ONLY//彩屏方案支持单击
+ key_event = KEY_EVENT_CLICK; //单击
+ key_value = scan_para->notify_value;
+ goto _notify;
+
+#endif
+
+#if KEY_EVENT_CLICK_ONLY_SUPPORT //是否支持某些按键只响应单击事件
+ if (scan_para->notify_value & BIT(7)) { //BIT(7)按键特殊处理标志, 只发送单击事件, 也可以用于其它扩展
+ key_event = KEY_EVENT_CLICK; //单击
+ key_value = scan_para->notify_value;
+ goto _notify;
+ }
+#endif
+ if (scan_para->click_delay_cnt > scan_para->click_delay_time) { //按键被抬起后延时到
+ //TODO: 在此可以添加任意多击事件
+ if (scan_para->click_cnt >= 5) {
+ key_event = KEY_EVENT_FIRTH_CLICK; //五击
+ } else if (scan_para->click_cnt >= 4) {
+ key_event = KEY_EVENT_FOURTH_CLICK; //4击
+ } else if (scan_para->click_cnt >= 3) {
+ key_event = KEY_EVENT_TRIPLE_CLICK; //三击
+ } else if (scan_para->click_cnt >= 2) {
+ key_event = KEY_EVENT_DOUBLE_CLICK; //双击
+ } else {
+ key_event = KEY_EVENT_CLICK; //单击
+ }
+ key_value = scan_para->notify_value;
+ goto _notify;
+ } else { //按键抬起后等待下次延时时间未到
+ scan_para->click_delay_cnt++;
+ goto _scan_end; //按键抬起后延时时间未到, 返回
+ }
+ } else {
+ goto _scan_end; //没有按键需要处理
+ }
+ } else { //last_key = valid_key; cur_key = valid_key, press_cnt累加用于判断long和hold
+ scan_para->press_cnt++;
+ if (scan_para->press_cnt == scan_para->long_time) {
+ key_event = KEY_EVENT_LONG;
+ } else if (scan_para->press_cnt == scan_para->hold_time) {
+ key_event = KEY_EVENT_HOLD;
+ scan_para->press_cnt = scan_para->long_time;
+ } else {
+ goto _scan_end; //press_cnt没到长按和HOLD次数, 返回
+ }
+ //press_cnt没到长按和HOLD次数, 发消息
+ key_value = cur_key_value;
+ goto _notify;
+ }
+ }
+
+_notify:
+#if TCFG_IRSENSOR_ENABLE
+ if (get_irSensor_event() == IR_SENSOR_EVENT_FAR) { //未佩戴的耳机不响应按键
+ return;
+ }
+#endif
+ key_value &= ~BIT(7); //BIT(7) 用作按键特殊处理的标志
+ e.type = SYS_KEY_EVENT;
+ e.u.key.init = 1;
+ e.u.key.type = scan_para->key_type;//区分按键类型
+ e.u.key.event = key_event;
+ e.u.key.value = key_value;
+ e.u.key.tmr = timer_get_ms();
+
+
+ scan_para->click_cnt = 0; //单击次数清0
+ scan_para->notify_value = NO_KEY;
+
+ e.arg = (void *)DEVICE_EVENT_FROM_KEY;
+ /* printf("key_value: 0x%x, event: %d, key_poweron_flag: %d\n", key_value, key_event, key_poweron_flag); */
+ if (key_poweron_flag) {
+ if (key_event == KEY_EVENT_UP) {
+ clear_key_poweron_flag();
+ return;
+ }
+ return;
+ }
+ if (key_event_remap(&e)) {
+ sys_event_notify(&e);
+#if TCFG_KEY_TONE_EN
+ audio_key_tone_play();
+#endif
+ }
+_scan_end:
+ scan_para->last_key = cur_key_value;
+ return;
+}
+
+
+//wakeup callback
+void key_active_set(u8 port)
+{
+ is_key_active = 35; //35*10Ms
+}
+
+//=======================================================//
+// 按键初始化函数: 初始化所有注册的按键驱动
+//=======================================================//
+int key_driver_init(void)
+{
+ int err;
+
+#if TCFG_IOKEY_ENABLE
+ extern const struct iokey_platform_data iokey_data;
+ extern struct key_driver_para iokey_scan_para;
+ err = iokey_init(&iokey_data);
+#ifdef TCFG_IOKEY_TIME_REDEFINE
+ extern struct key_driver_para iokey_scan_user_para;
+ if (err == 0) {
+ sys_s_hi_timer_add((void *)&iokey_scan_user_para, key_driver_scan, iokey_scan_user_para.scan_time); //注册按键扫描定时器
+ }
+#else
+ if (err == 0) {
+ sys_s_hi_timer_add((void *)&iokey_scan_para, key_driver_scan, iokey_scan_para.scan_time); //注册按键扫描定时器
+ }
+#endif
+#endif
+
+#if TCFG_ADKEY_ENABLE
+#ifdef CONFIG_ICRECORDER_CASE_ENABLE
+ extern multi_adkey_init(const struct adkey_platform_data * multi_adkey_data);
+ extern const struct adkey_platform_data multi_adkey_data[];
+ extern struct key_driver_para multi_adkey_scan_para;
+ err = multi_adkey_init(multi_adkey_data);
+ if (err == 0) {
+ sys_s_hi_timer_add((void *)&multi_adkey_scan_para, key_driver_scan, multi_adkey_scan_para.scan_time); //注册按键扫描定时器
+ }
+#else
+ extern const struct adkey_platform_data adkey_data;
+ extern struct key_driver_para adkey_scan_para;
+ err = adkey_init(&adkey_data);
+ if (err == 0) {
+ sys_s_hi_timer_add((void *)&adkey_scan_para, key_driver_scan, adkey_scan_para.scan_time); //注册按键扫描定时器
+ }
+#endif
+#endif
+
+#if TCFG_IRKEY_ENABLE
+ extern const struct irkey_platform_data irkey_data;
+ extern struct key_driver_para irkey_scan_para;
+ err = irkey_init(&irkey_data);
+ if (err == 0) {
+ sys_s_hi_timer_add((void *)&irkey_scan_para, key_driver_scan, irkey_scan_para.scan_time); //注册按键扫描定时器
+ }
+#endif
+
+#if TCFG_TOUCH_KEY_ENABLE
+ extern const struct touch_key_platform_data touch_key_data;
+ extern struct key_driver_para touch_key_scan_para;
+ err = touch_key_init(&touch_key_data);
+ if (err == 0) {
+ sys_s_hi_timer_add((void *)&touch_key_scan_para, key_driver_scan, touch_key_scan_para.scan_time); //注册按键扫描定时器
+ }
+#endif
+
+#if TCFG_ADKEY_RTCVDD_ENABLE
+ extern const struct adkey_rtcvdd_platform_data adkey_rtcvdd_data;
+ extern struct key_driver_para adkey_rtcvdd_scan_para;
+ err = adkey_rtcvdd_init(&adkey_rtcvdd_data);
+ if (err == 0) {
+ sys_s_hi_timer_add((void *)&adkey_rtcvdd_scan_para, key_driver_scan, adkey_rtcvdd_scan_para.scan_time); //注册按键扫描定时器
+ }
+#endif
+
+#if TCFG_RDEC_KEY_ENABLE
+ extern const struct rdec_platform_data rdec_key_data;
+ extern struct key_driver_para rdec_key_scan_para;
+ err = rdec_key_init(&rdec_key_data);
+ if (err == 0) {
+ sys_s_hi_timer_add((void *)&rdec_key_scan_para, key_driver_scan, rdec_key_scan_para.scan_time); //注册按键扫描定时器
+ }
+#endif
+
+#if TCFG_CTMU_TOUCH_KEY_ENABLE
+#include "asm/ctmu.h"
+ extern const struct ctmu_touch_key_platform_data ctmu_touch_key_data;
+ extern struct key_driver_para ctmu_touch_key_scan_para;
+ extern int ctmu_touch_key_init(const struct ctmu_touch_key_platform_data * ctmu_touch_key_data);
+ err = ctmu_touch_key_init(&ctmu_touch_key_data);
+ if (err == 0) {
+ sys_s_hi_timer_add((void *)&ctmu_touch_key_scan_para, key_driver_scan, ctmu_touch_key_scan_para.scan_time); //注册按键扫描定时器
+ }
+#endif /* #if TCFG_CTMU_TOUCH_KEY_ENABLE */
+
+#if TCFG_SLIDE_KEY_ENABLE
+ extern const struct slidekey_platform_data slidekey_data;
+ extern int slidekey_init(const struct slidekey_platform_data * slidekey_data);
+ err = slidekey_init(&slidekey_data);
+ if (err == 0) {
+ }
+#endif//TCFG_SLIDE_KEY_ENABLE
+
+#if TCFG_6083_ADKEY_ENABLE
+ extern int adkey_init_6083();
+ err = adkey_init_6083();
+ if (err == 0) {
+ }
+#endif
+#if TCFG_TENT600_KEY_ENABLE
+ extern const struct tent600_key_platform_data key_data ;
+ extern struct key_driver_para tent600_key_scan_para;
+ err = tent600_key_init(&key_data);
+ if (err == 0) {
+ sys_s_hi_timer_add((void *)&tent600_key_scan_para, key_driver_scan, tent600_key_scan_para.scan_time); //注册按键扫描定时器
+ }
+#endif
+
+ return 0;
+}
+
+static u8 key_idle_query(void)
+{
+ return !is_key_active;
+}
+#if ((!TCFG_LP_TOUCH_KEY_ENABLE) && (TCFG_IOKEY_ENABLE || TCFG_ADKEY_ENABLE))
+REGISTER_LP_TARGET(key_lp_target) = {
+ .name = "key",
+ .is_idle = key_idle_query,
+};
+#endif /* #if !TCFG_LP_TOUCH_KEY_ENABLE */
+
diff --git a/apps/common/device/key/touch_key.c b/apps/common/device/key/touch_key.c
new file mode 100644
index 0000000..e71762e
--- /dev/null
+++ b/apps/common/device/key/touch_key.c
@@ -0,0 +1,62 @@
+#include "touch_key.h"
+#include "key_driver.h"
+#include "app_config.h"
+
+
+#if TCFG_TOUCH_KEY_ENABLE
+
+
+/* =========== 触摸键使用说明 ============= */
+//1. 使用plcnt模块作计数;
+//2. 配置参数时, 在配置好时钟后, 需要调试no_touch_cnt和touch_cnt的值;
+
+static const struct touch_key_platform_data *__this = NULL;
+
+//按键驱动扫描参数列表
+struct key_driver_para touch_key_scan_para = {
+ .scan_time = 10, //按键扫描频率, 单位: ms
+ .last_key = NO_KEY, //上一次get_value按键值, 初始化为NO_KEY;
+ .filter_time = 1, //按键消抖延时;
+ .long_time = 75, //按键判定长按数量
+ .hold_time = (75 + 15), //按键判定HOLD数量
+ .click_delay_time = 20, //按键被抬起后等待连击延时数量
+ .key_type = KEY_DRIVER_TYPE_TOUCH,
+ .get_value = touch_key_get_value,
+};
+
+#define TOUCH_KEY_DEBUG 0
+
+#if TOUCH_KEY_DEBUG
+#define touch_key_debug(fmt, ...) printf("[TOUCH] "fmt, ##__VA_ARGS__)
+#else
+#define touch_key_debug(fmt, ...)
+#endif
+
+
+u8 touch_key_get_value(void)
+{
+ u8 key = get_plcnt_value();
+
+ if (key != NO_KEY) {
+ touch_key_debug("key = %d", key);
+ return __this->port_list[key].key_value;
+ }
+
+ return NO_KEY;
+}
+
+
+int touch_key_init(const struct touch_key_platform_data *touch_key_data)
+{
+ __this = touch_key_data;
+ printf("touch_key_init >>>> ");
+
+ return plcnt_init((void *)touch_key_data);
+}
+
+
+#endif /* #if TCFG_TOUCH_KEY_ENABLE */
+
+
+
+
diff --git a/apps/common/device/key/uart_key.c b/apps/common/device/key/uart_key.c
new file mode 100644
index 0000000..34fa0e6
--- /dev/null
+++ b/apps/common/device/key/uart_key.c
@@ -0,0 +1,51 @@
+#include "key_driver.h"
+#include "system/event.h"
+#include "asm/uart.h"
+#include "app_config.h"
+
+extern int getbyte(char *c);
+
+#if TCFG_UART_KEY_ENABLE
+
+static int uart_key_init(void)
+{
+ return 0;
+}
+
+static u8 uart_get_key_value(void)
+{
+ char c;
+ u8 key_value;
+
+ if (getbyte(&c) == 0) {
+ return NO_KEY;
+ }
+
+ switch (c) {
+ case 'm':
+ key_value = KEY_MODE;
+ break;
+ case 'u':
+ key_value = KEY_UP;
+ break;
+ case 'd':
+ key_value = KEY_DOWN;
+ break;
+ case 'o':
+ key_value = KEY_OK;
+ break;
+ case 'e':
+ key_value = KEY_MENU;
+ break;
+ default:
+ key_value = NO_KEY;
+ break;
+ }
+
+ return key_value;
+}
+
+
+
+#endif /* #if TCFG_UART_KEY_ENABLE */
+
diff --git a/apps/common/device/norflash/norflash_sfc.c b/apps/common/device/norflash/norflash_sfc.c
new file mode 100644
index 0000000..9c4a455
--- /dev/null
+++ b/apps/common/device/norflash/norflash_sfc.c
@@ -0,0 +1,708 @@
+#include "includes.h"
+#include "app_config.h"
+#include "norflash_sfc.h"
+
+#if (defined(TCFG_NORFLASH_SFC_DEV_ENABLE) && TCFG_NORFLASH_SFC_DEV_ENABLE)
+
+#undef LOG_TAG_CONST
+#define LOG_TAG "[FLASH_SFC]"
+#define LOG_ERROR_ENABLE
+#define LOG_INFO_ENABLE
+#include "debug.h"
+
+
+#define MAX_NORFLASH_PART_NUM 4
+
+struct norflash_partition {
+ const char *name;
+ u32 start_addr;
+ u32 size;
+ struct device device;
+};
+
+static struct norflash_partition nor_part[MAX_NORFLASH_PART_NUM];
+
+struct norflash_info {
+ u32 flash_id;
+ u32 flash_capacity;
+ int spi_num;
+ int spi_err;
+ u8 spi_cs_io;
+ u8 spi_r_width;
+ u8 part_num;
+ u8 open_cnt;
+ struct norflash_partition *const part_list;
+ OS_MUTEX mutex;
+ u32 max_end_addr;
+};
+
+static struct norflash_info _norflash = {
+ .spi_num = (int) - 1,
+ .part_list = nor_part,
+};
+
+static int _norflash_read(u32 addr, u8 *buf, u32 len, u8 cache);
+static int _norflash_eraser(u8 eraser, u32 addr);
+static void _norflash_cache_sync_timer(void *priv);
+static int _norflash_write_pages(u32 addr, u8 *buf, u32 len);
+
+static struct norflash_partition *norflash_find_part(const char *name)
+{
+ struct norflash_partition *part = NULL;
+ u32 idx;
+ for (idx = 0; idx < MAX_NORFLASH_PART_NUM; idx++) {
+ part = &_norflash.part_list[idx];
+ if (part->name == NULL) {
+ continue;
+ }
+ if (!strcmp(part->name, name)) {
+ return part;
+ }
+ }
+ return NULL;
+}
+
+static struct norflash_partition *norflash_new_part(const char *name, u32 addr, u32 size)
+{
+ struct norflash_partition *part;
+ u32 idx;
+ for (idx = 0; idx < MAX_NORFLASH_PART_NUM; idx++) {
+ part = &_norflash.part_list[idx];
+ if (part->name == NULL) {
+ break;
+ }
+ }
+ if (part->name != NULL) {
+ log_error("create norflash part fail\n");
+ return NULL;
+ }
+ memset(part, 0, sizeof(*part));
+ part->name = name;
+ part->start_addr = addr;
+ part->size = size;
+ if (part->start_addr + part->size > _norflash.max_end_addr) {
+ _norflash.max_end_addr = part->start_addr + part->size;
+ }
+ _norflash.part_num++;
+ return part;
+}
+
+static void norflash_delete_part(const char *name)
+{
+ struct norflash_partition *part;
+ u32 idx;
+ for (idx = 0; idx < MAX_NORFLASH_PART_NUM; idx++) {
+ part = &_norflash.part_list[idx];
+ if (part->name == NULL) {
+ continue;
+ }
+ if (!strcmp(part->name, name)) {
+ part->name = NULL;
+ _norflash.part_num--;
+ }
+ }
+}
+
+static int norflash_verify_part(struct norflash_partition *p)
+{
+ struct norflash_partition *part = NULL;
+ u32 idx;
+ for (idx = 0; idx < MAX_NORFLASH_PART_NUM; idx++) {
+ part = &_norflash.part_list[idx];
+ if (part->name == NULL) {
+ continue;
+ }
+ if ((p->start_addr >= part->start_addr) && (p->start_addr < part->start_addr + part->size)) {
+ if (strcmp(p->name, part->name) != 0) {
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+#define FLASH_CACHE_ENABLE 1
+
+#if FLASH_CACHE_ENABLE
+static u32 flash_cache_addr;
+static u8 *flash_cache_buf = NULL; //缓存4K的数据,与flash里的数据一样。
+static u8 flash_cache_is_dirty;
+static u16 flash_cache_timer;
+
+#define FLASH_CACHE_SYNC_T_INTERVAL 60
+
+static int _check_0xff(u8 *buf, u32 len)
+{
+ for (u32 i = 0; i < len; i ++) {
+ if ((*(buf + i)) != 0xff) {
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif
+
+
+static u32 _pow(u32 num, int n)
+{
+ u32 powint = 1;
+ int i;
+ for (i = 1; i <= n; i++) {
+ powint *= num;
+ }
+ return powint;
+}
+
+static u32 _norflash_read_id()
+{
+ return sfc_spi_read_id();
+}
+
+static int _norflash_init(const char *name, struct norflash_sfc_dev_platform_data *pdata)
+{
+ log_info("norflash_sfc_init >>>>");
+
+ struct norflash_partition *part;
+ if (_norflash.spi_num == (int) - 1) {
+ //_norflash.spi_num = pdata->spi_hw_num;
+ _norflash.flash_id = 0;
+ _norflash.flash_capacity = 0;
+ os_mutex_create(&_norflash.mutex);
+ _norflash.max_end_addr = 0;
+ _norflash.part_num = 0;
+ sfc_spi_init(pdata->sfc_spi_pdata);
+ }
+
+ part = norflash_find_part(name);
+
+ if (!part) {
+ part = norflash_new_part(name, pdata->start_addr, pdata->size);
+ ASSERT(part, "not enough norflash partition memory in array\n");
+ ASSERT(norflash_verify_part(part) == 0, "norflash partition %s overlaps\n", name);
+ log_info("norflash new partition %s\n", part->name);
+ } else {
+ ASSERT(0, "norflash partition name already exists\n");
+ }
+ return 0;
+}
+
+static void clock_critical_enter()
+{
+
+}
+static void clock_critical_exit()
+{
+ /* if (!(_norflash.flash_id == 0 || _norflash.flash_id == 0xffff)) { */
+ /* spi_set_baud(_norflash.spi_num, spi_get_baud(_norflash.spi_num)); */
+ /* } */
+}
+CLOCK_CRITICAL_HANDLE_REG(spi_norflash, clock_critical_enter, clock_critical_exit);
+
+static int _norflash_open(void *arg)
+{
+ int reg = 0;
+ os_mutex_pend(&_norflash.mutex, 0);
+ log_info("norflash open\n");
+ if (!_norflash.open_cnt) {
+ _norflash.flash_id = _norflash_read_id();
+
+ log_info("norflash_read_id: 0x%x\n", _norflash.flash_id);
+ if ((_norflash.flash_id == 0) || (_norflash.flash_id == 0xffffff)) {
+ log_error("read norflash id error !\n");
+ reg = -ENODEV;
+ goto __exit;
+ }
+ _norflash.flash_capacity = 64 * _pow(2, (_norflash.flash_id & 0xff) - 0x10) * 1024;
+ log_info("norflash_capacity: 0x%x\n", _norflash.flash_capacity);
+
+#if FLASH_CACHE_ENABLE
+ flash_cache_buf = (u8 *)malloc(4096);
+ ASSERT(flash_cache_buf, "flash_cache_buf is not ok\n");
+ flash_cache_addr = 4096;//先给一个大于4096的数
+ _norflash_read(0, flash_cache_buf, 4096, 1);
+ flash_cache_addr = 0;
+#endif
+ log_info("norflash open success !\n");
+ }
+ if (_norflash.flash_id == 0 || _norflash.flash_id == 0xffffff) {
+ log_error("re-open norflash id error !\n");
+ reg = -EFAULT;
+ goto __exit;
+ }
+ ASSERT(_norflash.max_end_addr <= _norflash.flash_capacity, "max partition end address is greater than flash capacity\n");
+ _norflash.open_cnt++;
+
+__exit:
+ os_mutex_post(&_norflash.mutex);
+ return reg;
+}
+
+int _norflash_close(void)
+{
+ os_mutex_pend(&_norflash.mutex, 0);
+ log_info("norflash close\n");
+ if (_norflash.open_cnt) {
+ _norflash.open_cnt--;
+ }
+ if (!_norflash.open_cnt) {
+#if FLASH_CACHE_ENABLE
+ if (flash_cache_is_dirty) {
+ flash_cache_is_dirty = 0;
+ _norflash_eraser(IOCTL_ERASE_SECTOR, flash_cache_addr);
+ _norflash_write_pages(flash_cache_addr, flash_cache_buf, 4096);
+ }
+ free(flash_cache_buf);
+ flash_cache_buf = NULL;
+#endif
+ log_info("norflash close done\n");
+ }
+ os_mutex_post(&_norflash.mutex);
+ return 0;
+}
+
+static int _norflash_read(u32 addr, u8 *buf, u32 len, u8 cache)
+{
+ int ret = 0;
+
+ ret = sfc_spi_read(addr, buf, len);
+ if (ret != len) {
+ ret = -1;
+ } else {
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int _norflash_write_pages(u32 addr, u8 *buf, u32 len)
+{
+ /* y_printf("flash write addr = %d, num = %d\n", addr, len); */
+ int ret = 0;
+ ret = sfc_spi_write_pages(addr, buf, len);
+ if (ret != len) {
+ ret = -1;
+ } else {
+ ret = 0;
+ }
+
+ return ret;
+}
+
+#if FLASH_CACHE_ENABLE
+static void _norflash_cache_sync_timer(void *priv)
+{
+ int reg = 0;
+ os_mutex_pend(&_norflash.mutex, 0);
+ if (flash_cache_is_dirty) {
+ flash_cache_is_dirty = 0;
+ reg = _norflash_eraser(IOCTL_ERASE_SECTOR, flash_cache_addr);
+ if (reg) {
+ goto __exit;
+ }
+ reg = _norflash_write_pages(flash_cache_addr, flash_cache_buf, 4096);
+ }
+ if (flash_cache_timer) {
+ sys_timeout_del(flash_cache_timer);
+ flash_cache_timer = 0;
+ }
+__exit:
+ os_mutex_post(&_norflash.mutex);
+}
+#endif
+
+int _norflash_write(u32 addr, void *buf, u32 len, u8 cache)
+{
+ int reg = 0;
+ os_mutex_pend(&_norflash.mutex, 0);
+
+ u8 *w_buf = (u8 *)buf;
+ u32 w_len = len;
+
+ /* y_printf("flash write addr = %d, num = %d\n", addr, len); */
+#if FLASH_CACHE_ENABLE
+ if (!cache) {
+ reg = _norflash_write_pages(addr, w_buf, w_len);
+ goto __exit;
+ }
+ u32 align_addr = addr / 4096 * 4096;
+ u32 align_len = 4096 - (addr - align_addr);
+ align_len = w_len > align_len ? align_len : w_len;
+ if (align_addr != flash_cache_addr) {
+ if (flash_cache_is_dirty) {
+ flash_cache_is_dirty = 0;
+ reg = _norflash_eraser(IOCTL_ERASE_SECTOR, flash_cache_addr);
+ if (reg) {
+ line_inf;
+ goto __exit;
+ }
+ reg = _norflash_write_pages(flash_cache_addr, flash_cache_buf, 4096);
+ if (reg) {
+ line_inf;
+ goto __exit;
+ }
+ }
+ _norflash_read(align_addr, flash_cache_buf, 4096, 0);
+ flash_cache_addr = align_addr;
+ }
+ memcpy(flash_cache_buf + (addr - align_addr), w_buf, align_len);
+ if ((addr + align_len) % 4096) {
+ flash_cache_is_dirty = 1;
+ if (flash_cache_timer) {
+ sys_timer_re_run(flash_cache_timer);
+ } else {
+ flash_cache_timer = sys_timeout_add(0, _norflash_cache_sync_timer, FLASH_CACHE_SYNC_T_INTERVAL);
+ }
+ } else {
+ flash_cache_is_dirty = 0;
+ reg = _norflash_eraser(IOCTL_ERASE_SECTOR, align_addr);
+ if (reg) {
+ line_inf;
+ goto __exit;
+ }
+ reg = _norflash_write_pages(align_addr, flash_cache_buf, 4096);
+ if (reg) {
+ line_inf;
+ goto __exit;
+ }
+ }
+ addr += align_len;
+ w_buf += align_len;
+ w_len -= align_len;
+ while (w_len) {
+ u32 cnt = w_len > 4096 ? 4096 : w_len;
+ _norflash_read(addr, flash_cache_buf, 4096, 0);
+ flash_cache_addr = addr;
+ memcpy(flash_cache_buf, w_buf, cnt);
+ if ((addr + cnt) % 4096) {
+ flash_cache_is_dirty = 1;
+ if (flash_cache_timer) {
+ sys_timer_re_run(flash_cache_timer);
+ } else {
+ flash_cache_timer = sys_timeout_add(0, _norflash_cache_sync_timer, FLASH_CACHE_SYNC_T_INTERVAL);
+ }
+ } else {
+ flash_cache_is_dirty = 0;
+ reg = _norflash_eraser(IOCTL_ERASE_SECTOR, addr);
+ if (reg) {
+ line_inf;
+ goto __exit;
+ }
+ reg = _norflash_write_pages(addr, flash_cache_buf, 4096);
+ if (reg) {
+ line_inf;
+ goto __exit;
+ }
+ }
+ addr += cnt;
+ w_buf += cnt;
+ w_len -= cnt;
+ }
+#else
+ reg = _norflash_write_pages(addr, w_buf, w_len);
+#endif
+__exit:
+ os_mutex_post(&_norflash.mutex);
+ return reg;
+}
+
+static int _norflash_eraser(u8 eraser, u32 addr)
+{
+ int ret = 0;
+
+ ret = sfc_spi_eraser(eraser, addr);
+
+ return ret;
+}
+
+int _norflash_ioctl(u32 cmd, u32 arg, u32 unit, void *_part)
+{
+ int reg = 0;
+ struct norflash_partition *part = _part;
+ os_mutex_pend(&_norflash.mutex, 0);
+ switch (cmd) {
+ case IOCTL_GET_STATUS:
+ *(u32 *)arg = 1;
+ break;
+ case IOCTL_GET_ID:
+ *((u32 *)arg) = _norflash.flash_id;
+ break;
+ case IOCTL_GET_CAPACITY:
+ if (_norflash.flash_capacity == 0) {
+ *(u32 *)arg = 0;
+ } else if (_norflash.part_num == 1 && part->start_addr == 0) {
+ *(u32 *)arg = _norflash.flash_capacity / unit;
+ } else {
+ *(u32 *)arg = part->size / unit;
+ }
+ break;
+ case IOCTL_GET_BLOCK_SIZE:
+ *(u32 *)arg = 512;
+ break;
+ case IOCTL_ERASE_PAGE:
+ reg = _norflash_eraser(IOCTL_ERASE_PAGE, arg * unit + part->start_addr);
+ break;
+ case IOCTL_ERASE_SECTOR:
+ reg = _norflash_eraser(IOCTL_ERASE_SECTOR, arg * unit + part->start_addr);
+ break;
+ case IOCTL_ERASE_BLOCK:
+ reg = _norflash_eraser(IOCTL_ERASE_BLOCK, arg * unit + part->start_addr);
+ break;
+ case IOCTL_ERASE_CHIP:
+ reg = _norflash_eraser(IOCTL_ERASE_CHIP, 0);
+ break;
+ case IOCTL_FLUSH:
+ break;
+ case IOCTL_CMD_RESUME:
+ break;
+ case IOCTL_CMD_SUSPEND:
+ break;
+ case IOCTL_GET_PART_INFO:
+ u32 *info = (u32 *)arg;
+ u32 *start_addr = &info[0];
+ u32 *part_size = &info[1];
+ *start_addr = part->start_addr;
+ *part_size = part->size;
+ break;
+ default:
+ reg = -EINVAL;
+ break;
+ }
+__exit:
+ os_mutex_post(&_norflash.mutex);
+ return reg;
+}
+
+
+/*************************************************************************************
+ * 挂钩 device_api
+ ************************************************************************************/
+
+static int norflash_sfc_dev_init(const struct dev_node *node, void *arg)
+{
+ struct norflash_sfc_dev_platform_data *pdata = arg;
+
+ return _norflash_init(node->name, pdata);
+}
+
+static int norflash_sfc_dev_open(const char *name, struct device **device, void *arg)
+{
+ struct norflash_partition *part;
+ part = norflash_find_part(name);
+ if (!part) {
+ log_error("no norflash partition is found\n");
+ return -ENODEV;
+ }
+ *device = &part->device;
+ (*device)->private_data = part;
+ if (atomic_read(&part->device.ref)) {
+ return 0;
+ }
+ return _norflash_open(arg);
+}
+static int norflash_sfc_dev_close(struct device *device)
+{
+ return _norflash_close();
+}
+static int norflash_sfc_dev_read(struct device *device, void *buf, u32 len, u32 offset)
+{
+ int reg;
+ /* printf("flash read sector = %d, num = %d\n", offset, len); */
+ offset = offset * 512;
+ len = len * 512;
+ struct norflash_partition *part;
+ part = (struct norflash_partition *)device->private_data;
+ if (!part) {
+ log_error("norflash partition invalid\n");
+ return -EFAULT;
+ }
+ offset += part->start_addr;
+ reg = _norflash_read(offset, buf, len, 1);
+ if (reg) {
+ r_printf(">>>[r error]:\n");
+ len = 0;
+ }
+
+ len = len / 512;
+ return len;
+}
+static int norflash_sfc_dev_write(struct device *device, void *buf, u32 len, u32 offset)
+{
+ /* printf("flash write sector = %d, num = %d\n", offset, len); */
+ int reg = 0;
+ offset = offset * 512;
+ len = len * 512;
+ struct norflash_partition *part = device->private_data;
+ if (!part) {
+ log_error("norflash partition invalid\n");
+ return -EFAULT;
+ }
+ offset += part->start_addr;
+ reg = _norflash_write(offset, buf, len, 1);
+ if (reg) {
+ r_printf(">>>[w error]:\n");
+ len = 0;
+ }
+ len = len / 512;
+ return len;
+}
+static bool norflash_sfc_dev_online(const struct dev_node *node)
+{
+ return 1;
+}
+static int norflash_sfc_dev_ioctl(struct device *device, u32 cmd, u32 arg)
+{
+ struct norflash_partition *part = device->private_data;
+ if (!part) {
+ log_error("norflash partition invalid\n");
+ return -EFAULT;
+ }
+ return _norflash_ioctl(cmd, arg, 512, part);
+}
+
+/*
+ * 1. 外部调用时以512字节为单位的地址和长度,且需要驱动write自己处理擦除,
+ * 请使用norflash_sfc_dev_ops接口,否则使用本文件内的其他ops
+ *
+ * 2. 如果不需要驱动自己处理擦除,可以把宏FLASH_CACHE_ENABLE清零,或者把
+ * norflash_sfc_dev_read()里面调用的_norflash_read()的实参cache填0,
+ * norflash_sfc_dev_write()同理
+ *
+ * 3. norflash_sfc_dev_ops可以被多个设备名注册,每个设备名被认为是不同分区,所以
+ * 需要填不同的分区起始地址和大小,若分区地址有重叠或者最大分区结束地址大于
+ * flash容量,会触发ASSERT()
+ *
+ * 4. 关于IOCTL_GET_CAPACITY,有多个分区注册时返回分区的大小,如果只注册了1
+ * 个分区,分区起始地址 == 0时返回flash容量,起始地址 != 0时返回分区大小,
+ * norflash_sfc_dev_ops返回的长度以512字节为单位
+ *
+ * 5. 本文件内的各个ops可以同时使用
+ */
+//按512字节单位读写
+const struct device_operations norflash_sfc_dev_ops = {
+ .init = norflash_sfc_dev_init,
+ .online = norflash_sfc_dev_online,
+ .open = norflash_sfc_dev_open,
+ .read = norflash_sfc_dev_read,
+ .write = norflash_sfc_dev_write,
+ .ioctl = norflash_sfc_dev_ioctl,
+ .close = norflash_sfc_dev_close,
+};
+
+
+static int norflash_sfc_fs_dev_init(const struct dev_node *node, void *arg)
+{
+ struct norflash_sfc_dev_platform_data *pdata = arg;
+
+ return _norflash_init(node->name, pdata);
+}
+
+static int norflash_sfc_fs_dev_open(const char *name, struct device **device, void *arg)
+{
+ struct norflash_partition *part;
+ part = norflash_find_part(name);
+ if (!part) {
+ log_error("no norflash partition is found\n");
+ return -ENODEV;
+ }
+ *device = &part->device;
+ (*device)->private_data = part;
+ if (atomic_read(&part->device.ref)) {
+ return 0;
+ }
+ return _norflash_open(arg);
+}
+static int norflash_sfc_fs_dev_close(struct device *device)
+{
+ return _norflash_close();
+}
+static int norflash_sfc_fs_dev_read(struct device *device, void *buf, u32 len, u32 offset)
+{
+ int reg;
+ /* printf("flash read sector = %d, num = %d\n", offset, len); */
+ struct norflash_partition *part;
+ part = (struct norflash_partition *)device->private_data;
+ if (!part) {
+ log_error("norflash partition invalid\n");
+ return -EFAULT;
+ }
+ offset += part->start_addr;
+ reg = _norflash_read(offset, buf, len, 0);
+ if (reg) {
+ r_printf(">>>[r error]:\n");
+ len = 0;
+ }
+
+ return len;
+}
+
+static int norflash_sfc_fs_dev_write(struct device *device, void *buf, u32 len, u32 offset)
+{
+ //printf("flash write addr = 0x%x, len = 0x%x\n", offset, len);
+ int reg = 0;
+ struct norflash_partition *part = device->private_data;
+ if (!part) {
+ log_error("norflash partition invalid\n");
+ return -EFAULT;
+ }
+ offset += part->start_addr;
+ reg = _norflash_write(offset, buf, len, 0);
+ if (reg) {
+ r_printf(">>>[w error]:\n");
+ len = 0;
+ }
+ return len;
+}
+static bool norflash_sfc_fs_dev_online(const struct dev_node *node)
+{
+ return 1;
+}
+
+static int norflash_sfc_fs_dev_ioctl(struct device *device, u32 cmd, u32 arg)
+{
+ struct norflash_partition *part = device->private_data;
+ if (!part) {
+ log_error("norflash partition invalid\n");
+ return -EFAULT;
+ }
+ return _norflash_ioctl(cmd, arg, 1, part);
+}
+
+/*
+ * 1. 外部调用时以1字节为单位的地址和长度,且驱动write自己不处理擦除,
+ * 请使用norflash_sfc_fs_dev_ops接口,否则使用本文件内的其他ops。注意:有些文件系
+ * 统需要满足这个条件的驱动,如果期望修改成驱动内部处理擦除,需要测试所
+ * 有关联的文件系统是否支持,或者新建一个符合需求的ops
+ *
+ * 2. 如果需要驱动自己处理擦除,需要把宏FLASH_CACHE_ENABLE置1,且
+ * norflash_sfc_fs_dev_read()里面调用的_norflash_read()的实参cache填1,
+ * norflash_sfc_fs_dev_write()同理
+ *
+ * 3. norflash_sfc_fs_dev_ops可以被多个设备名注册,每个设备名被认为是不同分区,所以
+ * 需要填不同的分区起始地址和大小,若分区地址有重叠或者最大分区结束地址大于
+ * flash容量,会触发ASSERT()
+ *
+ * 4. 关于IOCTL_GET_CAPACITY,有多个分区注册时返回分区的大小,如果只注册了1
+ * 个分区,分区起始地址 == 0时返回flash容量,起始地址 != 0时返回分区大小
+ * norflash_sfc_fs_dev_ops返回的长度以1字节为单位
+ *
+ * 5. 本文件内的各个ops可以同时使用
+ */
+//按1字节单位读写
+const struct device_operations norflash_sfc_fs_dev_ops = {
+ .init = norflash_sfc_fs_dev_init,
+ .online = norflash_sfc_fs_dev_online,
+ .open = norflash_sfc_fs_dev_open,
+ .read = norflash_sfc_fs_dev_read,
+ .write = norflash_sfc_fs_dev_write,
+ .ioctl = norflash_sfc_fs_dev_ioctl,
+ .close = norflash_sfc_fs_dev_close,
+};
+
+/*
+ * 对ops的读写单位有另外需求,或者驱动内部是否支持擦除,可以参照上面的ops,
+ * 不同条件自由组合,建立新的ops
+ */
+
+#endif /* #if (defined(TCFG_NORFLASH_SFC_DEV_ENABLE) && TCFG_NORFLASH_SFC_DEV_ENABLE) */
diff --git a/apps/common/device/usb/device/cdc.c b/apps/common/device/usb/device/cdc.c
new file mode 100644
index 0000000..12428e5
--- /dev/null
+++ b/apps/common/device/usb/device/cdc.c
@@ -0,0 +1,490 @@
+#include "usb/device/usb_stack.h"
+#include "usb/usb_config.h"
+#include "usb/device/cdc.h"
+#include "app_config.h"
+#include "os/os_api.h"
+#include "cdc_defs.h" //need redefine __u8, __u16, __u32
+
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#if TCFG_USB_SLAVE_CDC_ENABLE
+
+
+struct usb_cdc_gadget {
+ u8 *cdc_buffer;
+ u8 *bulk_ep_out_buffer;
+ u8 *bulk_ep_in_buffer;
+ void *priv;
+ int (*output)(void *priv, u8 *obuf, u32 olen);
+ void (*wakeup_handler)(struct usb_device_t *usb_device);
+ OS_MUTEX mutex_data;
+#if CDC_INTR_EP_ENABLE
+ OS_MUTEX mutex_intr;
+ u8 *intr_ep_in_buffer;
+#endif
+ u8 bmTransceiver;
+ u8 subtype_data[8];
+};
+
+static struct usb_cdc_gadget *cdc_hdl;
+
+#if USB_MALLOC_ENABLE
+
+#else
+static u8 _cdc_buffer[MAXP_SIZE_CDC_BULKOUT] SEC(.cdc_var) __attribute__((aligned(4)));
+static struct usb_cdc_gadget _cdc_hdl SEC(.cdc_var);
+#endif
+
+static const u8 cdc_virtual_comport_desc[] = {
+ //IAD Descriptor
+ 0x08, //bLength
+ 0x0b, //bDescriptorType
+ 0x00, //bFirstInterface
+ 0x02, //bInterfaceCount
+ 0x02, //bFunctionClass, Comunication and CDC control
+ 0x02, //bFunctionSubClass
+ 0x01, //bFunctionProtocol
+ 0x00, //iFunction
+ //Interface 0, Alt 0
+ 0x09, //Length
+ 0x04, //DescriptorType:Interface
+ 0x00, //InterfaceNum
+ 0x00, //AlternateSetting
+ 0x01, //NumEndpoint
+ 0x02, //InterfaceClass, Communation and CDC control
+ 0x02, //InterfaceSubClass, Abstract Control Model
+ 0x01, //InterfaceProtocol, AT commands defined by ITU-T V.250 etc
+ 0x00, //Interface String
+ //CDC Interface Descriptor
+ 0x05, //bLength
+ 0x24, //bDescriptorType
+ 0x00, //bDescriptorSubType, Header Functional Desc
+ 0x10, 0x01, //bcdCDC, version 1.10
+ //CDC Interface Descriptor
+ 0x05, //bLength
+ 0x24, //bDescriptorType
+ 0x01, //bDescriptorSubType, Call Management Functional Descriptor
+ 0x03, //bmCapabilities, D7..D2 reversed
+ // D7..D2 reversed
+ // D1 sends/receives call management information only over a Data Class interface
+ // D0 handle call management itself
+ 0x01, //bDataInterface
+ //CDC Interface Descriptor
+ 0x04, //bLength
+ 0x24, //bDescriptorType
+ 0x02, //bDescriptorSubType, Abstract Control Management Functional Descriptor
+ 0x02, //bmCapabilities, D7..D2 reversed
+ // D7..D4 reversed
+ // D3 supports the notification Network_Connection
+ // D2 not supports the request Send_Break
+ // D1 supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State
+ // D0 supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature
+ //CDC Interface Descriptor
+ 0x05, //bLength
+ 0x24, //bDescriptorType
+ 0x06, //bDescriptorSubType, Union Functional Descriptor
+ 0x00, //bControlInterface
+ 0x01, //bSubordinateInterface[0]
+ //Endpoint In
+ 0x07, //bLength
+ 0x05, //bDescritorType
+ 0x82, //bEndpointAddr
+ 0x03, //bmAttributes, interrupt
+ 0x08, 0x00, //wMaxPacketSize
+ 0x01, //bInterval, 1ms
+ //Interface 1, Alt 0
+ 0x09, //Length
+ 0x04, //DescriptorType:Interface
+ 0x01, //InterfaceNum
+ 0x00, //AlternateSetting
+ 0x02, //NumEndpoint
+ 0x0a, //InterfaceClass, CDC Data
+ 0x00, //InterfaceSubClass
+ 0x00, //InterfaceProtocol
+ 0x00, //Interface String
+ //Endpoint Out
+ 0x07, //bLength
+ 0x05, //bDescriptor
+ 0x02, //bEndpointAddr
+ 0x02, //bmAttributes, bulk
+ 0x40, 0x00, //wMaxPacketSize
+ 0x00, //bInterval
+ //Endpoint In
+ 0x07, //bLength
+ 0x05, //bDescritorType
+ 0x83, //bEndpointAddr
+ 0x02, //bmAttributes, bulk
+ 0x40, 0x00, //wMaxPacketSize
+ 0x00, //bInterval
+};
+
+static void cdc_endpoint_init(struct usb_device_t *usb_device, u32 itf);
+static u32 cdc_setup_rx(struct usb_device_t *usb_device, struct usb_ctrlrequest *ctrl_req);
+
+static void usb_cdc_line_coding_init(struct usb_cdc_line_coding *lc)
+{
+ lc->dwDTERate = 460800;
+ lc->bCharFormat = USB_CDC_1_STOP_BITS;
+ lc->bParityType = USB_CDC_NO_PARITY;
+ lc->bDataBits = 8;
+}
+
+static void dump_line_coding(struct usb_cdc_line_coding *lc)
+{
+ log_debug("dtw rate : %d", lc->dwDTERate);
+ log_debug("stop bits : %d", lc->bCharFormat);
+ log_debug("verify bits : %d", lc->bParityType);
+ log_debug("data bits : %d", lc->bDataBits);
+}
+
+static u32 cdc_setup(struct usb_device_t *usb_device, struct usb_ctrlrequest *ctrl_req)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ int recip_type;
+ u32 len;
+
+ recip_type = ctrl_req->bRequestType & USB_TYPE_MASK;
+
+ switch (recip_type) {
+ case USB_TYPE_CLASS:
+ switch (ctrl_req->bRequest) {
+ case USB_CDC_REQ_SET_LINE_CODING:
+ log_debug("set line coding");
+ usb_set_setup_recv(usb_device, cdc_setup_rx);
+ break;
+ case USB_CDC_REQ_GET_LINE_CODING:
+ log_debug("get line codling");
+ len = ctrl_req->wLength < sizeof(struct usb_cdc_line_coding) ?
+ ctrl_req->wLength : sizeof(struct usb_cdc_line_coding);
+ if (cdc_hdl == NULL) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ break;
+ }
+ usb_set_data_payload(usb_device, ctrl_req, cdc_hdl->subtype_data, len);
+ dump_line_coding((struct usb_cdc_line_coding *)cdc_hdl->subtype_data);
+ break;
+ case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
+ log_debug("set control line state - %d", ctrl_req->wValue);
+ if (cdc_hdl) {
+ /* if (ctrl_req->wValue & BIT(0)) { //DTR */
+ cdc_hdl->bmTransceiver |= BIT(0);
+ /* } else { */
+ /* usb_slave->cdc->bmTransceiver &= ~BIT(0); */
+ /* } */
+ /* if (ctrl_req->wValue & BIT(1)) { //RTS */
+ cdc_hdl->bmTransceiver |= BIT(1);
+ /* } else { */
+ /* usb_slave->cdc->bmTransceiver &= ~BIT(1); */
+ /* } */
+ cdc_hdl->bmTransceiver |= BIT(4); //cfg done
+ }
+ usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
+ //cdc_endpoint_init(usb_device, (ctrl_req->wIndex & USB_RECIP_MASK));
+ break;
+ default:
+ log_error("unsupported class req");
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ break;
+ }
+ break;
+ default:
+ log_error("unsupported req type");
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ break;
+ }
+ return 0;
+}
+
+static u32 cdc_setup_rx(struct usb_device_t *usb_device, struct usb_ctrlrequest *ctrl_req)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ int recip_type;
+ struct usb_cdc_line_coding *lc = 0;
+ u32 len;
+ u8 read_ep[8];
+
+ len = ctrl_req->wLength;
+ usb_read_ep0(usb_id, read_ep, len);
+ recip_type = ctrl_req->bRequestType & USB_TYPE_MASK;
+ switch (recip_type) {
+ case USB_TYPE_CLASS:
+ switch (ctrl_req->bRequest) {
+ case USB_CDC_REQ_SET_LINE_CODING:
+ log_debug("USB_CDC_REQ_SET_LINE_CODING");
+ if (cdc_hdl == NULL) {
+ break;
+ }
+ if (len > sizeof(struct usb_cdc_line_coding)) {
+ len = sizeof(struct usb_cdc_line_coding);
+ }
+ memcpy(cdc_hdl->subtype_data, read_ep, len);
+ lc = (struct usb_cdc_line_coding *)cdc_hdl->subtype_data;
+ dump_line_coding(lc);
+ break;
+ }
+ break;
+ }
+ return USB_EP0_STAGE_SETUP;
+}
+
+static void cdc_reset(struct usb_device_t *usb_device, u32 itf)
+{
+ log_error("%s()", __func__);
+ const usb_dev usb_id = usb_device2id(usb_device);
+#if USB_ROOT2
+ usb_disable_ep(usb_id, CDC_DATA_EP_IN);
+#if CDC_INTR_EP_ENABLE
+ usb_disable_ep(usb_id, CDC_INTR_EP_IN);
+#endif
+#else
+ cdc_endpoint_init(usb_device, itf);
+#endif
+}
+
+u32 cdc_desc_config(const usb_dev usb_id, u8 *ptr, u32 *itf)
+{
+ u8 *tptr;
+
+ tptr = ptr;
+ memcpy(tptr, cdc_virtual_comport_desc, sizeof(cdc_virtual_comport_desc));
+ //iad interface number
+ tptr[2] = *itf;
+ //control interface number
+ tptr[8 + 2] = *itf;
+ tptr[8 + 9 + 5 + 4] = *itf + 1;
+ tptr[8 + 9 + 5 + 5 + 4 + 3] = *itf;
+ tptr[8 + 9 + 5 + 5 + 4 + 4] = *itf + 1;
+ //interrupt in ep
+ tptr[8 + 9 + 5 + 5 + 4 + 5 + 2] = USB_DIR_IN | CDC_INTR_EP_IN;
+ tptr[8 + 9 + 5 + 5 + 4 + 5 + 4] = MAXP_SIZE_CDC_INTRIN & 0xff;
+ tptr[8 + 9 + 5 + 5 + 4 + 5 + 5] = (MAXP_SIZE_CDC_INTRIN >> 8) & 0xff;
+#if defined(FUSB_MODE) && FUSB_MODE == 0
+ tptr[8 + 9 + 5 + 5 + 4 + 5 + 6] = 4; //high-speed mode, 125x2^(4-1)=1ms
+#endif
+ //data interface number
+ tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 2] = *itf + 1;
+ //bulk out ep
+ tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 2] = CDC_DATA_EP_OUT;
+ tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 4] = MAXP_SIZE_CDC_BULKOUT & 0xff;
+ tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 5] = (MAXP_SIZE_CDC_BULKOUT >> 8) & 0xff;
+ //bulk in ep
+ tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 2] = USB_DIR_IN | CDC_DATA_EP_IN;
+ tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 4] = MAXP_SIZE_CDC_BULKIN & 0xff;
+ tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 5] = (MAXP_SIZE_CDC_BULKIN >> 8) & 0xff;
+ tptr += sizeof(cdc_virtual_comport_desc);
+
+ if (usb_set_interface_hander(usb_id, *itf, cdc_setup) != *itf) {
+ ASSERT(0, "cdc set interface_hander fail");
+ }
+ if (usb_set_reset_hander(usb_id, *itf, cdc_reset) != *itf) {
+
+ }
+ *itf += 2;
+ return (u32)(tptr - ptr);
+}
+
+void cdc_set_wakeup_handler(void (*handle)(struct usb_device_t *usb_device))
+{
+ if (cdc_hdl) {
+ cdc_hdl->wakeup_handler = handle;
+ }
+}
+
+static void cdc_wakeup_handler(struct usb_device_t *usb_device, u32 ep)
+{
+ if (cdc_hdl && cdc_hdl->wakeup_handler) {
+ cdc_hdl->wakeup_handler(usb_device);
+ }
+}
+
+void cdc_set_output_handle(void *priv, int (*output_handler)(void *priv, u8 *buf, u32 len))
+{
+ if (cdc_hdl) {
+ cdc_hdl->output = output_handler;
+ cdc_hdl->priv = priv;
+ }
+}
+
+static void cdc_intrrx(struct usb_device_t *usb_device, u32 ep)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ if (cdc_hdl == NULL) {
+ return;
+ }
+ u8 *cdc_rx_buf = cdc_hdl->cdc_buffer;
+ //由于bulk传输使用双缓冲,无法用usb_get_ep_buffer()知道是哪一个buffer,需要外部buffer接收数据
+ u32 len = usb_g_bulk_read(usb_id, CDC_DATA_EP_OUT, cdc_rx_buf, MAXP_SIZE_CDC_BULKOUT, 0);
+ if (cdc_hdl->output) {
+ cdc_hdl->output(cdc_hdl->priv, cdc_rx_buf, len);
+ }
+}
+
+static void cdc_endpoint_init(struct usb_device_t *usb_device, u32 itf)
+{
+ ASSERT(cdc_hdl, "cdc not register");
+
+ const usb_dev usb_id = usb_device2id(usb_device);
+
+ usb_g_ep_config(usb_id, CDC_DATA_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_BULK,
+ 0, cdc_hdl->bulk_ep_in_buffer, MAXP_SIZE_CDC_BULKIN);
+
+ usb_g_ep_config(usb_id, CDC_DATA_EP_OUT | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK,
+ 1, cdc_hdl->bulk_ep_out_buffer, MAXP_SIZE_CDC_BULKOUT);
+ /* usb_g_set_intr_hander(usb_id, CDC_DATA_EP_OUT | USB_DIR_OUT, cdc_intrrx); */
+ usb_g_set_intr_hander(usb_id, CDC_DATA_EP_OUT | USB_DIR_OUT, cdc_wakeup_handler);
+ usb_enable_ep(usb_id, CDC_DATA_EP_IN);
+
+#if CDC_INTR_EP_ENABLE
+ usb_g_ep_config(usb_id, CDC_INTR_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_INT,
+ 0, cdc_hdl->intr_ep_in_buffer, MAXP_SIZE_CDC_INTRIN);
+ usb_enable_ep(usb_id, CDC_INTR_EP_IN);
+#endif
+}
+
+u32 cdc_read_data(const usb_dev usb_id, u8 *buf, u32 len)
+{
+ u32 rxlen;
+ if (cdc_hdl == NULL) {
+ return 0;
+ }
+ u8 *cdc_rx_buf = cdc_hdl->cdc_buffer;
+ os_mutex_pend(&cdc_hdl->mutex_data, 0);
+ //由于bulk传输使用双缓冲,无法用usb_get_ep_buffer()知道是哪一个buffer,需要外部buffer接收数据
+ rxlen = usb_g_bulk_read(usb_id, CDC_DATA_EP_OUT, cdc_rx_buf, MAXP_SIZE_CDC_BULKOUT, 0);
+ rxlen = rxlen > len ? len : rxlen;
+ if (rxlen > 0) {
+ memcpy(buf, cdc_rx_buf, rxlen);
+ }
+ os_mutex_post(&cdc_hdl->mutex_data);
+ return rxlen;
+}
+
+u32 cdc_write_data(const usb_dev usb_id, u8 *buf, u32 len)
+{
+ u32 txlen, offset;
+ if (cdc_hdl == NULL) {
+ return 0;
+ }
+ if ((cdc_hdl->bmTransceiver & (BIT(1) | BIT(4))) != (BIT(1) | BIT(4))) {
+ return 0;
+ }
+ offset = 0;
+ os_mutex_pend(&cdc_hdl->mutex_data, 0);
+ while (offset < len) {
+ txlen = len - offset > MAXP_SIZE_CDC_BULKIN ?
+ MAXP_SIZE_CDC_BULKIN : len - offset;
+ txlen = usb_g_bulk_write(usb_id, CDC_DATA_EP_IN, buf + offset, txlen);
+ if (txlen == 0) {
+ break;
+ }
+ if ((cdc_hdl->bmTransceiver & (BIT(1) | BIT(4))) != (BIT(1) | BIT(4))) {
+ break;
+ }
+ offset += txlen;
+ }
+ //当最后一包的包长等于maxpktsize,需要发一个0长包表示结束
+ if ((offset % MAXP_SIZE_CDC_BULKIN) == 0) {
+ usb_g_bulk_write(usb_id, CDC_DATA_EP_IN, NULL, 0);
+ }
+ os_mutex_post(&cdc_hdl->mutex_data);
+ return offset;
+}
+
+u32 cdc_write_inir(const usb_dev usb_id, u8 *buf, u32 len)
+{
+#if CDC_INTR_EP_ENABLE
+ u32 txlen, offset;
+ if (cdc_hdl == NULL) {
+ return 0;
+ }
+ if ((cdc_hdl->bmTransceiver & BIT(4)) == 0) {
+ return 0;
+ }
+ offset = 0;
+ os_mutex_pend(&cdc_hdl->mutex_intr, 0);
+ while (offset < len) {
+ txlen = len - offset > MAXP_SIZE_CDC_INTRIN ?
+ MAXP_SIZE_CDC_INTRIN : len - offset;
+ txlen = usb_g_intr_write(usb_id, CDC_INTR_EP_IN, buf + offset, txlen);
+ if (txlen == 0) {
+ break;
+ }
+ if ((cdc_hdl->bmTransceiver & BIT(4)) == 0) {
+ break;
+ }
+ offset += txlen;
+ }
+ os_mutex_post(&cdc_hdl->mutex_intr);
+ return offset;
+#else
+ return 0;
+#endif
+}
+
+void cdc_register(const usb_dev usb_id)
+{
+ struct usb_cdc_line_coding *lc;
+ /* log_info("%s() %d", __func__, __LINE__); */
+ if (!cdc_hdl) {
+#if USB_MALLOC_ENABLE
+ cdc_hdl = zalloc(sizeof(struct usb_cdc_gadget));
+ if (!cdc_hdl) {
+ log_error("cdc_register err 1");
+ return;
+ }
+ cdc_hdl->cdc_buffer = malloc(MAXP_SIZE_CDC_BULKOUT);
+ if (!cdc_hdl->cdc_buffer) {
+ log_error("cdc_register err 2");
+ goto __exit_err;
+ }
+#else
+ memset(&_cdc_hdl, 0, sizeof(struct usb_cdc_gadget));
+ cdc_hdl = &_cdc_hdl;
+ cdc_hdl->cdc_buffer = _cdc_buffer;
+#endif
+ lc = (struct usb_cdc_line_coding *)cdc_hdl->subtype_data;
+ usb_cdc_line_coding_init(lc);
+ os_mutex_create(&cdc_hdl->mutex_data);
+
+ cdc_hdl->bulk_ep_in_buffer = usb_alloc_ep_dmabuffer(usb_id, CDC_DATA_EP_IN | USB_DIR_IN, MAXP_SIZE_CDC_BULKIN + MAXP_SIZE_CDC_BULKOUT);
+ cdc_hdl->bulk_ep_out_buffer = cdc_hdl->bulk_ep_in_buffer + MAXP_SIZE_CDC_BULKIN;
+
+#if CDC_INTR_EP_ENABLE
+ os_mutex_create(&cdc_hdl->mutex_intr);
+ cdc_hdl->intr_ep_in_buffer = usb_alloc_ep_dmabuffer(usb_id, CDC_INTR_EP_IN | USB_DIR_IN, MAXP_SIZE_CDC_INTRIN);
+#endif
+
+ }
+ return;
+__exit_err:
+#if USB_MALLOC_ENABLE
+ if (cdc_hdl->cdc_buffer) {
+ free(cdc_hdl->cdc_buffer);
+ }
+ if (cdc_hdl) {
+ free(cdc_hdl);
+ }
+#endif
+ cdc_hdl = NULL;
+}
+
+void cdc_release(const usb_dev usb_id)
+{
+ /* log_info("%s() %d", __func__, __LINE__); */
+ if (cdc_hdl) {
+#if USB_MALLOC_ENABLE
+ free(cdc_hdl->cdc_buffer);
+ free(cdc_hdl);
+#endif
+ cdc_hdl = NULL;
+ }
+}
+
+#endif
diff --git a/apps/common/device/usb/device/cdc.h b/apps/common/device/usb/device/cdc.h
new file mode 100644
index 0000000..45a27f7
--- /dev/null
+++ b/apps/common/device/usb/device/cdc.h
@@ -0,0 +1,23 @@
+#ifndef __CDC_H__
+#define __CDC_H__
+
+#include "usb/device/usb_stack.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+u32 cdc_desc_config(const usb_dev usb_id, u8 *ptr, u32 *itf);
+void cdc_set_wakeup_handler(void (*handle)(struct usb_device_t *usb_device));
+void cdc_set_output_handle(void *priv, int (*output_handler)(void *priv, u8 *buf, u32 len));
+u32 cdc_read_data(const usb_dev usb_id, u8 *buf, u32 len);
+u32 cdc_write_data(const usb_dev usb_id, u8 *buf, u32 len);
+u32 cdc_write_inir(const usb_dev usb_id, u8 *buf, u32 len);
+void cdc_register(const usb_dev usb_id);
+void cdc_release(const usb_dev usb_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/apps/common/device/usb/device/cdc_defs.h b/apps/common/device/usb/device/cdc_defs.h
new file mode 100644
index 0000000..727d8fb
--- /dev/null
+++ b/apps/common/device/usb/device/cdc_defs.h
@@ -0,0 +1,457 @@
+
+/*
+ * USB Communications Device Class (CDC) definitions
+ *
+ * CDC says how to talk to lots of different types of network adapters,
+ * notably ethernet adapters and various modems. It's used mostly with
+ * firmware based USB peripherals.
+ */
+
+#ifndef __LINUX_USB_CDC_H
+#define __LINUX_USB_CDC_H
+
+#include "typedef.h" /* __u8 etc */
+
+#ifdef __le16
+#undef __le16
+#endif
+typedef unsigned short __le16;
+#ifdef __le32
+#undef __le32
+#endif
+typedef unsigned int __le32;
+#ifdef __u8
+#undef __u8
+#endif
+typedef unsigned char __u8;
+#ifdef __u16
+#undef __u16
+#endif
+typedef unsigned short __u16;
+#ifdef __u32
+#undef __u32
+#endif
+typedef unsigned int __u32;
+
+#define USB_CDC_SUBCLASS_ACM 0x02
+#define USB_CDC_SUBCLASS_ETHERNET 0x06
+#define USB_CDC_SUBCLASS_WHCM 0x08
+#define USB_CDC_SUBCLASS_DMM 0x09
+#define USB_CDC_SUBCLASS_MDLM 0x0a
+#define USB_CDC_SUBCLASS_OBEX 0x0b
+#define USB_CDC_SUBCLASS_EEM 0x0c
+#define USB_CDC_SUBCLASS_NCM 0x0d
+#define USB_CDC_SUBCLASS_MBIM 0x0e
+
+#define USB_CDC_PROTO_NONE 0
+
+#define USB_CDC_ACM_PROTO_AT_V25TER 1
+#define USB_CDC_ACM_PROTO_AT_PCCA101 2
+#define USB_CDC_ACM_PROTO_AT_PCCA101_WAKE 3
+#define USB_CDC_ACM_PROTO_AT_GSM 4
+#define USB_CDC_ACM_PROTO_AT_3G 5
+#define USB_CDC_ACM_PROTO_AT_CDMA 6
+#define USB_CDC_ACM_PROTO_VENDOR 0xff
+
+#define USB_CDC_PROTO_EEM 7
+
+#define USB_CDC_NCM_PROTO_NTB 1
+#define USB_CDC_MBIM_PROTO_NTB 2
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Class-Specific descriptors ... there are a couple dozen of them
+ */
+
+#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */
+#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */
+#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */
+#define USB_CDC_UNION_TYPE 0x06 /* union_desc */
+#define USB_CDC_COUNTRY_TYPE 0x07
+#define USB_CDC_NETWORK_TERMINAL_TYPE 0x0a /* network_terminal_desc */
+#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */
+#define USB_CDC_WHCM_TYPE 0x11
+#define USB_CDC_MDLM_TYPE 0x12 /* mdlm_desc */
+#define USB_CDC_MDLM_DETAIL_TYPE 0x13 /* mdlm_detail_desc */
+#define USB_CDC_DMM_TYPE 0x14
+#define USB_CDC_OBEX_TYPE 0x15
+#define USB_CDC_NCM_TYPE 0x1a
+#define USB_CDC_MBIM_TYPE 0x1b
+
+/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */
+struct usb_cdc_header_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __le16 bcdCDC;
+} __attribute__((packed));
+
+/* "Call Management Descriptor" from CDC spec 5.2.3.2 */
+struct usb_cdc_call_mgmt_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __u8 bmCapabilities;
+#define USB_CDC_CALL_MGMT_CAP_CALL_MGMT 0x01
+#define USB_CDC_CALL_MGMT_CAP_DATA_INTF 0x02
+
+ __u8 bDataInterface;
+} __attribute__((packed));
+
+/* "Abstract Control Management Descriptor" from CDC spec 5.2.3.3 */
+struct usb_cdc_acm_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __u8 bmCapabilities;
+} __attribute__((packed));
+
+/* capabilities from 5.2.3.3 */
+
+#define USB_CDC_COMM_FEATURE 0x01
+#define USB_CDC_CAP_LINE 0x02
+#define USB_CDC_CAP_BRK 0x04
+#define USB_CDC_CAP_NOTIFY 0x08
+
+/* "Union Functional Descriptor" from CDC spec 5.2.3.8 */
+struct usb_cdc_union_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __u8 bMasterInterface0;
+ __u8 bSlaveInterface0;
+ /* ... and there could be other slave interfaces */
+} __attribute__((packed));
+
+/* "Country Selection Functional Descriptor" from CDC spec 5.2.3.9 */
+struct usb_cdc_country_functional_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __u8 iCountryCodeRelDate;
+ __le16 wCountyCode0;
+ /* ... and there can be a lot of country codes */
+} __attribute__((packed));
+
+/* "Network Channel Terminal Functional Descriptor" from CDC spec 5.2.3.11 */
+struct usb_cdc_network_terminal_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __u8 bEntityId;
+ __u8 iName;
+ __u8 bChannelIndex;
+ __u8 bPhysicalInterface;
+} __attribute__((packed));
+
+/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */
+struct usb_cdc_ether_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __u8 iMACAddress;
+ __le32 bmEthernetStatistics;
+ __le16 wMaxSegmentSize;
+ __le16 wNumberMCFilters;
+ __u8 bNumberPowerFilters;
+} __attribute__((packed));
+
+/* "Telephone Control Model Functional Descriptor" from CDC WMC spec 6.3..3 */
+struct usb_cdc_dmm_desc {
+ __u8 bFunctionLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubtype;
+ __u16 bcdVersion;
+ __le16 wMaxCommand;
+} __attribute__((packed));
+
+/* "MDLM Functional Descriptor" from CDC WMC spec 6.7.2.3 */
+struct usb_cdc_mdlm_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __le16 bcdVersion;
+ __u8 bGUID[16];
+} __attribute__((packed));
+
+/* "MDLM Detail Functional Descriptor" from CDC WMC spec 6.7.2.4 */
+struct usb_cdc_mdlm_detail_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ /* type is associated with mdlm_desc.bGUID */
+ __u8 bGuidDescriptorType;
+ __u8 bDetailData[0];
+} __attribute__((packed));
+
+/* "OBEX Control Model Functional Descriptor" */
+struct usb_cdc_obex_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __le16 bcdVersion;
+} __attribute__((packed));
+
+/* "NCM Control Model Functional Descriptor" */
+struct usb_cdc_ncm_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __le16 bcdNcmVersion;
+ __u8 bmNetworkCapabilities;
+} __attribute__((packed));
+
+/* "MBIM Control Model Functional Descriptor" */
+struct usb_cdc_mbim_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __le16 bcdMBIMVersion;
+ __le16 wMaxControlMessage;
+ __u8 bNumberFilters;
+ __u8 bMaxFilterSize;
+ __le16 wMaxSegmentSize;
+ __u8 bmNetworkCapabilities;
+} __attribute__((packed));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Class-Specific Control Requests (6.2)
+ *
+ * section 3.6.2.1 table 4 has the ACM profile, for modems.
+ * section 3.8.2 table 10 has the ethernet profile.
+ *
+ * Microsoft's RNDIS stack for Ethernet is a vendor-specific CDC ACM variant,
+ * heavily dependent on the encapsulated (proprietary) command mechanism.
+ */
+
+#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00
+#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01
+#define USB_CDC_REQ_SET_LINE_CODING 0x20
+#define USB_CDC_REQ_GET_LINE_CODING 0x21
+#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
+#define USB_CDC_REQ_SEND_BREAK 0x23
+#define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40
+#define USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER 0x41
+#define USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER 0x42
+#define USB_CDC_SET_ETHERNET_PACKET_FILTER 0x43
+#define USB_CDC_GET_ETHERNET_STATISTIC 0x44
+#define USB_CDC_GET_NTB_PARAMETERS 0x80
+#define USB_CDC_GET_NET_ADDRESS 0x81
+#define USB_CDC_SET_NET_ADDRESS 0x82
+#define USB_CDC_GET_NTB_FORMAT 0x83
+#define USB_CDC_SET_NTB_FORMAT 0x84
+#define USB_CDC_GET_NTB_INPUT_SIZE 0x85
+#define USB_CDC_SET_NTB_INPUT_SIZE 0x86
+#define USB_CDC_GET_MAX_DATAGRAM_SIZE 0x87
+#define USB_CDC_SET_MAX_DATAGRAM_SIZE 0x88
+#define USB_CDC_GET_CRC_MODE 0x89
+#define USB_CDC_SET_CRC_MODE 0x8a
+
+/* Line Coding Structure from CDC spec 6.2.13 */
+struct usb_cdc_line_coding {
+ __le32 dwDTERate;
+ __u8 bCharFormat;
+#define USB_CDC_1_STOP_BITS 0
+#define USB_CDC_1_5_STOP_BITS 1
+#define USB_CDC_2_STOP_BITS 2
+
+ __u8 bParityType;
+#define USB_CDC_NO_PARITY 0
+#define USB_CDC_ODD_PARITY 1
+#define USB_CDC_EVEN_PARITY 2
+#define USB_CDC_MARK_PARITY 3
+#define USB_CDC_SPACE_PARITY 4
+
+ __u8 bDataBits;
+} __attribute__((packed));
+
+/* table 62; bits in multicast filter */
+#define USB_CDC_PACKET_TYPE_PROMISCUOUS (1 << 0)
+#define USB_CDC_PACKET_TYPE_ALL_MULTICAST (1 << 1) /* no filter */
+#define USB_CDC_PACKET_TYPE_DIRECTED (1 << 2)
+#define USB_CDC_PACKET_TYPE_BROADCAST (1 << 3)
+#define USB_CDC_PACKET_TYPE_MULTICAST (1 << 4) /* filtered */
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Class-Specific Notifications (6.3) sent by interrupt transfers
+ *
+ * section 3.8.2 table 11 of the CDC spec lists Ethernet notifications
+ * section 3.6.2.1 table 5 specifies ACM notifications, accepted by RNDIS
+ * RNDIS also defines its own bit-incompatible notifications
+ */
+
+#define USB_CDC_NOTIFY_NETWORK_CONNECTION 0x00
+#define USB_CDC_NOTIFY_RESPONSE_AVAILABLE 0x01
+#define USB_CDC_NOTIFY_SERIAL_STATE 0x20
+#define USB_CDC_NOTIFY_SPEED_CHANGE 0x2a
+
+struct usb_cdc_notification {
+ __u8 bmRequestType;
+ __u8 bNotificationType;
+ __le16 wValue;
+ __le16 wIndex;
+ __le16 wLength;
+} __attribute__((packed));
+
+struct usb_cdc_speed_change {
+ __le32 DLBitRRate; /* contains the downlink bit rate (IN pipe) */
+ __le32 ULBitRate; /* contains the uplink bit rate (OUT pipe) */
+} __attribute__((packed));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Class Specific structures and constants
+ *
+ * CDC NCM NTB parameters structure, CDC NCM subclass 6.2.1
+ *
+ */
+
+struct usb_cdc_ncm_ntb_parameters {
+ __le16 wLength;
+ __le16 bmNtbFormatsSupported;
+ __le32 dwNtbInMaxSize;
+ __le16 wNdpInDivisor;
+ __le16 wNdpInPayloadRemainder;
+ __le16 wNdpInAlignment;
+ __le16 wPadding1;
+ __le32 dwNtbOutMaxSize;
+ __le16 wNdpOutDivisor;
+ __le16 wNdpOutPayloadRemainder;
+ __le16 wNdpOutAlignment;
+ __le16 wNtbOutMaxDatagrams;
+} __attribute__((packed));
+
+/*
+ * CDC NCM transfer headers, CDC NCM subclass 3.2
+ */
+
+#define USB_CDC_NCM_NTH16_SIGN 0x484D434E /* NCMH */
+#define USB_CDC_NCM_NTH32_SIGN 0x686D636E /* ncmh */
+
+struct usb_cdc_ncm_nth16 {
+ __le32 dwSignature;
+ __le16 wHeaderLength;
+ __le16 wSequence;
+ __le16 wBlockLength;
+ __le16 wNdpIndex;
+} __attribute__((packed));
+
+struct usb_cdc_ncm_nth32 {
+ __le32 dwSignature;
+ __le16 wHeaderLength;
+ __le16 wSequence;
+ __le32 dwBlockLength;
+ __le32 dwNdpIndex;
+} __attribute__((packed));
+
+/*
+ * CDC NCM datagram pointers, CDC NCM subclass 3.3
+ */
+
+#define USB_CDC_NCM_NDP16_CRC_SIGN 0x314D434E /* NCM1 */
+#define USB_CDC_NCM_NDP16_NOCRC_SIGN 0x304D434E /* NCM0 */
+#define USB_CDC_NCM_NDP32_CRC_SIGN 0x316D636E /* ncm1 */
+#define USB_CDC_NCM_NDP32_NOCRC_SIGN 0x306D636E /* ncm0 */
+
+#define USB_CDC_MBIM_NDP16_IPS_SIGN 0x00535049 /* IPS : IPS0 for now */
+#define USB_CDC_MBIM_NDP32_IPS_SIGN 0x00737069 /* ips : ips0 for now */
+#define USB_CDC_MBIM_NDP16_DSS_SIGN 0x00535344 /* DSS */
+#define USB_CDC_MBIM_NDP32_DSS_SIGN 0x00737364 /* dss */
+
+/* 16-bit NCM Datagram Pointer Entry */
+struct usb_cdc_ncm_dpe16 {
+ __le16 wDatagramIndex;
+ __le16 wDatagramLength;
+} __attribute__((__packed__));
+
+/* 16-bit NCM Datagram Pointer Table */
+struct usb_cdc_ncm_ndp16 {
+ __le32 dwSignature;
+ __le16 wLength;
+ __le16 wNextNdpIndex;
+ struct usb_cdc_ncm_dpe16 dpe16[0];
+} __attribute__((packed));
+
+/* 32-bit NCM Datagram Pointer Entry */
+struct usb_cdc_ncm_dpe32 {
+ __le32 dwDatagramIndex;
+ __le32 dwDatagramLength;
+} __attribute__((__packed__));
+
+/* 32-bit NCM Datagram Pointer Table */
+struct usb_cdc_ncm_ndp32 {
+ __le32 dwSignature;
+ __le16 wLength;
+ __le16 wReserved6;
+ __le32 dwNextNdpIndex;
+ __le32 dwReserved12;
+ struct usb_cdc_ncm_dpe32 dpe32[0];
+} __attribute__((packed));
+
+/* CDC NCM subclass 3.2.1 and 3.2.2 */
+#define USB_CDC_NCM_NDP16_INDEX_MIN 0x000C
+#define USB_CDC_NCM_NDP32_INDEX_MIN 0x0010
+
+/* CDC NCM subclass 3.3.3 Datagram Formatting */
+#define USB_CDC_NCM_DATAGRAM_FORMAT_CRC 0x30
+#define USB_CDC_NCM_DATAGRAM_FORMAT_NOCRC 0X31
+
+/* CDC NCM subclass 4.2 NCM Communications Interface Protocol Code */
+#define USB_CDC_NCM_PROTO_CODE_NO_ENCAP_COMMANDS 0x00
+#define USB_CDC_NCM_PROTO_CODE_EXTERN_PROTO 0xFE
+
+/* CDC NCM subclass 5.2.1 NCM Functional Descriptor, bmNetworkCapabilities */
+#define USB_CDC_NCM_NCAP_ETH_FILTER (1 << 0)
+#define USB_CDC_NCM_NCAP_NET_ADDRESS (1 << 1)
+#define USB_CDC_NCM_NCAP_ENCAP_COMMAND (1 << 2)
+#define USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE (1 << 3)
+#define USB_CDC_NCM_NCAP_CRC_MODE (1 << 4)
+#define USB_CDC_NCM_NCAP_NTB_INPUT_SIZE (1 << 5)
+
+/* CDC NCM subclass Table 6-3: NTB Parameter Structure */
+#define USB_CDC_NCM_NTB16_SUPPORTED (1 << 0)
+#define USB_CDC_NCM_NTB32_SUPPORTED (1 << 1)
+
+/* CDC NCM subclass Table 6-3: NTB Parameter Structure */
+#define USB_CDC_NCM_NDP_ALIGN_MIN_SIZE 0x04
+#define USB_CDC_NCM_NTB_MAX_LENGTH 0x1C
+
+/* CDC NCM subclass 6.2.5 SetNtbFormat */
+#define USB_CDC_NCM_NTB16_FORMAT 0x00
+#define USB_CDC_NCM_NTB32_FORMAT 0x01
+
+/* CDC NCM subclass 6.2.7 SetNtbInputSize */
+#define USB_CDC_NCM_NTB_MIN_IN_SIZE 2048
+#define USB_CDC_NCM_NTB_MIN_OUT_SIZE 2048
+
+/* NTB Input Size Structure */
+struct usb_cdc_ncm_ndp_input_size {
+ __le32 dwNtbInMaxSize;
+ __le16 wNtbInMaxDatagrams;
+ __le16 wReserved;
+} __attribute__((packed));
+
+/* CDC NCM subclass 6.2.11 SetCrcMode */
+#define USB_CDC_NCM_CRC_NOT_APPENDED 0x00
+#define USB_CDC_NCM_CRC_APPENDED 0x01
+
+#endif /* __LINUX_USB_CDC_H */
diff --git a/apps/common/device/usb/device/descriptor.c b/apps/common/device/usb/device/descriptor.c
new file mode 100644
index 0000000..e93b233
--- /dev/null
+++ b/apps/common/device/usb/device/descriptor.c
@@ -0,0 +1,202 @@
+/**
+ * @file descriptor.c
+ * @brief overwrite usb device descriptor
+ * @version 1.00
+ * @date 2019-05-06
+ */
+
+#include "usb/device/usb_stack.h"
+#include "usb/device/descriptor.h"
+#include "usb/device/uac_audio.h"
+
+#include "app_config.h"
+
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#if TCFG_USB_SLAVE_ENABLE
+
+static const u8 sDeviceDescriptor[] = { // in Unicode
+ 0x02, // iProduct: Index to string descriptor that contains the string in Unicode
+ 0x03, // iSerialNumber: none
+ 0x01 // bNumConfigurations: 1
+};
+
+static const u8 LANGUAGE_STR[] = {
+ 0x04, 0x03, 0x09, 0x04
+};
+
+
+static const u8 product_string[] = {
+ 42,
+ 0x03,
+ 'U', 0x00,
+ 'S', 0x00,
+ 'B', 0x00,
+ ' ', 0x00,
+ 'C', 0x00,
+ 'o', 0x00,
+ 'm', 0x00,
+ 'p', 0x00,
+ 'o', 0x00,
+ 's', 0x00,
+ 'i', 0x00,
+ 't', 0x00,
+ 'e', 0x00,
+ ' ', 0x00,
+ 'D', 0x00,
+ 'e', 0x00,
+ 'v', 0x00,
+ 'i', 0x00,
+ 'c', 0x00,
+ 'e', 0x00,
+};
+
+static const u8 MANUFACTURE_STR[] = {
+ 34, //该描述符的长度为34字节
+ 0x03, //字符串描述符的类型编码为0x03
+ 0x4a, 0x00, //J
+ 0x69, 0x00, //i
+ 0x65, 0x00, //e
+ 0x6c, 0x00, //l
+ 0x69, 0x00, //i
+ 0x20, 0x00, //
+ 0x54, 0x00, //T
+ 0x65, 0x00, //e
+ 0x63, 0x00, //c
+ 0x68, 0x00, //h
+ 0x6e, 0x00, //n
+ 0x6f, 0x00, //o
+ 0x6c, 0x00, //l
+ 0x6f, 0x00, //o
+ 0x67, 0x00, //g
+ 0x79, 0x00, //y
+};
+
+static const u8 sConfigDescriptor[] = { //> 4;
+ if (bcd > 9) {
+ bcd = bcd - 0xa + 'A';
+ } else {
+ bcd = bcd + '0';
+ }
+ ptr[2 + i * 4] = bcd;
+ bcd = flash_id[i] & 0xf;
+ if (bcd > 9) {
+ bcd = bcd - 0xa + 'A';
+ } else {
+ bcd = bcd + '0';
+ }
+ ptr[2 + i * 4 + 2] = bcd;
+ }
+ } else {
+ memcpy(ptr, serial_string, serial_string[0]);
+ }
+#endif
+}
+
+#if USB_ROOT2
+static const u8 ee_string[] = {0x12, 0x03, 0x4D, 0x00, 0x53, 0x00, 0x46, 0x00, 0x54,
+ 0x00, 0x31, 0x00, 0x30, 0x00, 0x30, 0x00, 0x90, 0x00
+ };
+void get_string_ee(u8 *ptr)
+{
+ memcpy(ptr, ee_string, ee_string[0]);
+}
+#endif
+
+void get_product_str(u8 *ptr)
+{
+ memcpy(ptr, product_string, product_string[0]);
+}
+
+const u8 *usb_get_config_desc()
+{
+ return sConfigDescriptor;
+}
+
+const u8 *usb_get_string_desc(u32 id)
+{
+ const u8 *pstr = uac_get_string(id);
+ if (pstr != NULL) {
+ return pstr;
+ }
+ return NULL;
+}
+
+#endif
diff --git a/apps/common/device/usb/device/hid.c b/apps/common/device/usb/device/hid.c
new file mode 100644
index 0000000..eb85881
--- /dev/null
+++ b/apps/common/device/usb/device/hid.c
@@ -0,0 +1,332 @@
+#include "os/os_api.h"
+#include "usb/device/usb_stack.h"
+#include "usb/device/hid.h"
+#include "usb_config.h"
+
+#include "app_config.h"
+
+#if TCFG_USB_SLAVE_USER_HID
+#undef TCFG_USB_SLAVE_HID_ENABLE
+#define TCFG_USB_SLAVE_HID_ENABLE 0
+#endif
+
+#if TCFG_USB_SLAVE_HID_ENABLE
+
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+static const u8 sHIDDescriptor[] = {
+//HID
+ //InterfaceDeszcriptor:
+ USB_DT_INTERFACE_SIZE, // Length
+ USB_DT_INTERFACE, // DescriptorType
+ /* 0x04, // bInterface number */
+ 0x00, // bInterface number
+ 0x00, // AlternateSetting
+ 0x01, // NumEndpoint
+ /* 0x02, // NumEndpoint */
+ USB_CLASS_HID, // Class = Human Interface Device
+ 0x00, // Subclass, 0 No subclass, 1 Boot Interface subclass
+ 0x00, // Procotol, 0 None, 1 Keyboard, 2 Mouse
+ 0x00, // Interface Name
+
+ //HIDDescriptor:
+ 0x09, // bLength
+ USB_HID_DT_HID, // bDescriptorType, HID Descriptor
+ 0x00, 0x01, // bcdHID, HID Class Specification release NO.
+ 0x00, // bCuntryCode, Country localization (=none)
+ 0x01, // bNumDescriptors, Number of descriptors to follow
+ 0x22, // bDescriptorType, Report Desc. 0x22, Physical Desc. 0x23
+ 0,//LOW(ReportLength)
+ 0, //HIGH(ReportLength)
+
+ //EndpointDescriptor:
+ USB_DT_ENDPOINT_SIZE, // bLength
+ USB_DT_ENDPOINT, // bDescriptorType, Type
+ USB_DIR_IN | HID_EP_IN, // bEndpointAddress
+ USB_ENDPOINT_XFER_INT, // Interrupt
+ LOBYTE(MAXP_SIZE_HIDIN), HIBYTE(MAXP_SIZE_HIDIN),// Maximum packet size
+ HID_INTR_INTERVAL, // Poll every 10msec seconds
+
+//@Endpoint Descriptor:
+ /* USB_DT_ENDPOINT_SIZE, // bLength
+ USB_DT_ENDPOINT, // bDescriptorType, Type
+ USB_DIR_OUT | HID_EP_OUT, // bEndpointAddress
+ USB_ENDPOINT_XFER_INT, // Interrupt
+ LOBYTE(MAXP_SIZE_HIDOUT), HIBYTE(MAXP_SIZE_HIDOUT),// Maximum packet size
+ HID_INTR_INTERVAL, // bInterval, for high speed 2^(n-1) * 125us, for full/low speed n * 1ms */
+};
+
+static const u8 sHIDReportDesc[] = {
+ USAGE_PAGE(1, CONSUMER_PAGE),
+ USAGE(1, CONSUMER_CONTROL),
+ COLLECTION(1, APPLICATION),
+
+ LOGICAL_MIN(1, 0x00),
+ LOGICAL_MAX(1, 0x01),
+
+ USAGE(1, VOLUME_INC),
+ USAGE(1, VOLUME_DEC),
+ USAGE(1, MUTE),
+ USAGE(1, PLAY_PAUSE),
+ USAGE(1, SCAN_NEXT_TRACK),
+ USAGE(1, SCAN_PREV_TRACK),
+ USAGE(1, FAST_FORWARD),
+ USAGE(1, STOP),
+
+ USAGE(1, TRACKING_INC),
+ USAGE(1, TRACKING_DEC),
+ USAGE(1, STOP_EJECT),
+ USAGE(1, VOLUME),
+ USAGE(2, BALANCE_LEFT),
+ USAGE(2, BALANCE_RIGHT),
+ USAGE(1, PLAY),
+ USAGE(1, PAUSE),
+
+ REPORT_SIZE(1, 0x01),
+ REPORT_COUNT(1, 0x10),
+ INPUT(1, 0x42),
+ END_COLLECTION,
+
+};
+
+static u32 get_hid_report_desc_len(u32 index)
+{
+ u32 len = 0;
+ len = sizeof(sHIDReportDesc);
+ return len;
+}
+static void *get_hid_report_desc(u32 index)
+{
+ u8 *ptr = NULL;
+ ptr = (u8 *)sHIDReportDesc;
+ return ptr;
+}
+
+
+static u8 *hid_ep_in_dma;
+/* static u8 *hid_ep_out_dma; */
+
+static u32 hid_tx_data(struct usb_device_t *usb_device, const u8 *buffer, u32 len)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ return usb_g_intr_write(usb_id, HID_EP_IN, buffer, len);
+}
+static void hid_rx_data(struct usb_device_t *usb_device, u32 ep)
+{
+ /* const usb_dev usb_id = usb_device2id(usb_device); */
+ /* u32 rx_len = usb_g_intr_read(usb_id, ep, NULL, 64, 0); */
+ /* hid_tx_data(usb_device, hid_ep_out_dma, rx_len); */
+}
+
+static void hid_endpoint_init(struct usb_device_t *usb_device, u32 itf)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ usb_g_ep_config(usb_id, HID_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_INT, 0, hid_ep_in_dma, MAXP_SIZE_HIDIN);
+ usb_enable_ep(usb_id, HID_EP_IN);
+
+ /* usb_g_set_intr_hander(usb_id, HID_EP_OUT, hid_rx_data); */
+ /* usb_g_ep_config(usb_id, HID_EP_OUT, USB_ENDPOINT_XFER_INT, 1, ep_buffer, MAXP_SIZE_HIDOUT); */
+}
+u32 hid_register(const usb_dev usb_id)
+{
+ hid_ep_in_dma = usb_alloc_ep_dmabuffer(usb_id, HID_EP_IN | USB_DIR_IN, MAXP_SIZE_HIDIN);
+
+ /* hid_ep_out_dma = hid_ep_in_dma + MAXP_SIZE_HIDIN; */
+ return 0;
+}
+
+void hid_release(const usb_dev usb_id)
+{
+ return ;
+}
+
+static void hid_reset(struct usb_device_t *usb_device, u32 itf)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ log_debug("%s", __func__);
+#if USB_ROOT2
+ usb_disable_ep(usb_id, HID_EP_IN);
+#else
+ hid_endpoint_init(usb_device, itf);
+#endif
+}
+static u32 hid_recv_output_report(struct usb_device_t *usb_device, struct usb_ctrlrequest *setup)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ u32 ret = 0;
+ u8 read_ep[8];
+ u8 mute;
+ u16 volume = 0;
+ usb_read_ep0(usb_id, read_ep, MIN(sizeof(read_ep), setup->wLength));
+ ret = USB_EP0_STAGE_SETUP;
+ put_buf(read_ep, 8);
+
+
+ return ret;
+}
+
+static u32 hid_itf_hander(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ u32 tx_len;
+ u8 *tx_payload = usb_get_setup_buffer(usb_device);
+ u32 bRequestType = req->bRequestType & USB_TYPE_MASK;
+ switch (bRequestType) {
+ case USB_TYPE_STANDARD:
+ switch (req->bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ switch (HIBYTE(req->wValue)) {
+ case USB_HID_DT_HID:
+ tx_payload = (u8 *)sHIDDescriptor + USB_DT_INTERFACE_SIZE;
+ tx_len = 9;
+ tx_payload = usb_set_data_payload(usb_device, req, tx_payload, tx_len);
+ tx_payload[7] = LOBYTE(get_hid_report_desc_len(req->wIndex));
+ tx_payload[8] = HIBYTE(get_hid_report_desc_len(req->wIndex));
+ break;
+ case USB_HID_DT_REPORT:
+ hid_endpoint_init(usb_device, req->wIndex);
+ tx_len = get_hid_report_desc_len(req->wIndex);
+ tx_payload = get_hid_report_desc(req->wIndex);
+ usb_set_data_payload(usb_device, req, tx_payload, tx_len);
+ break;
+ }// USB_REQ_GET_DESCRIPTOR
+ break;
+ case USB_REQ_SET_DESCRIPTOR:
+ usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
+ break;
+ case USB_REQ_SET_INTERFACE:
+ if (usb_device->bDeviceStates == USB_DEFAULT) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_CONFIGURED) {
+ //只有一个interface 没有Alternate
+ if (req->wValue == 0) { //alt 0
+ usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
+ } else {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ }
+ }
+ break;
+ case USB_REQ_GET_INTERFACE:
+ if (req->wValue || (req->wLength != 1)) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_DEFAULT) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_CONFIGURED) {
+ tx_len = 1;
+ tx_payload[0] = 0x00;
+ usb_set_data_payload(usb_device, req, tx_payload, tx_len);
+ }
+ break;
+ case USB_REQ_GET_STATUS:
+ if (usb_device->bDeviceStates == USB_DEFAULT) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ }
+ break;
+ }//bRequest @ USB_TYPE_STANDARD
+ break;
+
+ case USB_TYPE_CLASS: {
+ switch (req->bRequest) {
+ case USB_REQ_SET_IDLE:
+ usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
+ break;
+ case USB_REQ_GET_IDLE:
+ tx_len = 1;
+ tx_payload[0] = 0;
+ usb_set_data_payload(usb_device, req, tx_payload, tx_len);
+ break;
+ case USB_REQ_SET_REPORT:
+ usb_set_setup_recv(usb_device, hid_recv_output_report);
+ break;
+ }//bRequest @ USB_TYPE_CLASS
+ }
+ break;
+ }
+ return 0;
+}
+
+u32 hid_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num)
+{
+ log_debug("hid interface num:%d\n", *cur_itf_num);
+ u8 *_ptr = ptr;
+ memcpy(ptr, sHIDDescriptor, sizeof(sHIDDescriptor));
+ ptr[2] = *cur_itf_num;
+ if (usb_set_interface_hander(usb_id, *cur_itf_num, hid_itf_hander) != *cur_itf_num) {
+ ASSERT(0, "hid set interface_hander fail");
+ }
+ if (usb_set_reset_hander(usb_id, *cur_itf_num, hid_reset) != *cur_itf_num) {
+ ASSERT(0, "hid set interface_reset_hander fail");
+ }
+
+ ptr[USB_DT_INTERFACE_SIZE + 7] = LOBYTE(get_hid_report_desc_len(0));
+ ptr[USB_DT_INTERFACE_SIZE + 8] = HIBYTE(get_hid_report_desc_len(0));
+ *cur_itf_num = *cur_itf_num + 1;
+ return sizeof(sHIDDescriptor) ;
+}
+
+void hid_key_handler(struct usb_device_t *usb_device, u32 hid_key)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ if (usb_get_ep_status(usb_id, HID_EP_IN)) {
+ return;
+ }
+
+ u16 key_buf = hid_key;
+ hid_tx_data(usb_device, (const u8 *)&key_buf, 2);
+ os_time_dly(2);
+ key_buf = 0;
+ hid_tx_data(usb_device, (const u8 *)&key_buf, 2);
+}
+
+void hid_key_handler_send_one_packet(struct usb_device_t *usb_device, u32 hid_key)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ u16 key_buf = hid_key;
+ hid_tx_data(usb_device, (const u8 *)&key_buf, 2);
+}
+
+struct hid_button {
+ u8 report_id;
+ u8 button1: 1;
+ u8 button2: 1;
+ u8 button3: 1;
+ u8 no_button: 5;
+ u8 X_axis;
+ u8 Y_axis;
+};
+struct hid_button hid_key;
+void hid_test(struct usb_device_t *usb_device)
+{
+ static u32 tx_count = 0;
+
+ hid_key_handler(usb_device, BIT(tx_count));
+ tx_count ++;
+ if (BIT(tx_count) > USB_AUDIO_PAUSE) {
+ tx_count = 0;
+ }
+}
+#else
+void hid_key_handler(struct usb_device_t *usb_device, u32 hid_key)
+{
+
+}
+
+void hid_key_handler_for_one_packet(struct usb_device_t *usb_device, u32 hid_key)
+{
+
+}
+#endif
diff --git a/apps/common/device/usb/device/msd.c b/apps/common/device/usb/device/msd.c
new file mode 100644
index 0000000..8dfca67
--- /dev/null
+++ b/apps/common/device/usb/device/msd.c
@@ -0,0 +1,1126 @@
+#include "system/includes.h"
+#include "usb/device/usb_stack.h"
+#include "usb/device/msd.h"
+#include "usb/scsi.h"
+#include "usb_config.h"
+#include "device/device.h"
+#include "app_config.h"
+
+#if TCFG_DEV_MANAGER_ENABLE
+#include "dev_manager.h"
+#endif
+
+#if TCFG_USB_APPLE_DOCK_EN
+#include "apple_dock/iAP.h"
+#endif
+
+#if TCFG_USB_SLAVE_MSD_ENABLE
+
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+ // *INDENT-OFF*
+#define USB_MSD_BULK_DEV_USE_ASYNC 1
+
+// Mass Storage Class
+ /*********************************************************/
+static const u8 sMassDescriptor[] = { //= MAX_MSD_DEV) {
+ cnt = MAX_MSD_DEV;
+ }
+ return cnt;
+}
+
+u32 msd_set_wakeup_handle(void (*handle)(struct usb_device_t *usb_device))
+{
+ if (msd_handle) {
+ msd_handle->info.msd_wakeup_handle = handle;
+ return 1;
+ }
+ return 0;
+}
+static void msd_wakeup(struct usb_device_t *usb_device, u32 ep)
+{
+ if ((msd_handle) && (msd_handle->info.msd_wakeup_handle)) {
+ msd_handle->info.msd_wakeup_handle(usb_device);
+ }
+}
+static u8 get_cardreader_popup(u32 lun)
+{
+ return msd_handle->info.bDisk_popup[lun];//弹出
+}
+static void set_cardreader_popup(u32 lun, u8 status)
+{
+ if (msd_handle->info.dev_handle[lun] != NULL) {
+ msd_handle->info.bDisk_popup[lun] = status;//弹出
+ }
+}
+static void recover_set_cardreader_popup(u32 lun)
+{
+ if (msd_handle->info.dev_handle[lun] != NULL) {
+ msd_handle->info.bDisk_popup[lun] = 0;//未弹出
+ }
+}
+static void msd_endpoint_init(struct usb_device_t *usb_device, u32 itf)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+
+ usb_g_ep_config(usb_id, MSD_BULK_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 0, msd_handle->ep_out_dmabuffer, MAXP_SIZE_BULKIN);
+
+ usb_g_ep_config(usb_id, MSD_BULK_EP_OUT, USB_ENDPOINT_XFER_BULK, 1, msd_handle->ep_out_dmabuffer, MAXP_SIZE_BULKOUT);
+ usb_g_set_intr_hander(usb_id, MSD_BULK_EP_OUT, msd_wakeup);
+
+ usb_enable_ep(usb_id, MSD_BULK_EP_IN);
+}
+static void msd_reset_wakeup(struct usb_device_t *usb_device, u32 itf_num)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ if (msd_handle && msd_handle->info.msd_reset_wakeup_handle) {
+ msd_handle->info.msd_reset_wakeup_handle(usb_device, itf_num);
+ }
+}
+void msd_set_reset_wakeup_handle(void (*handle)(struct usb_device_t *usb_device, u32 itf_num))
+{
+ if (msd_handle) {
+ msd_handle->info.msd_reset_wakeup_handle = handle;
+ }
+}
+void msd_reset(struct usb_device_t *usb_device, u32 itf_num)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ log_debug("%s", __func__);
+
+#if USB_ROOT2
+ usb_disable_ep(usb_id, MSD_BULK_EP_OUT);
+#else
+ msd_endpoint_init(usb_device, itf_num);
+#endif
+}
+static void *check_disk_status(u8 cur_lun)
+{
+ u32 ret;
+ u32 online_status;
+ void *dev_fd = msd_handle->info.dev_handle[cur_lun] ;
+ const char *dev_name = msd_handle->info.dev_name[cur_lun];
+
+#if TCFG_DEV_MANAGER_ENABLE
+ if (dev_manager_list_check_by_logo((char *)dev_name)) {
+ if (dev_fd == NULL) {
+ msd_handle->info.dev_handle[cur_lun] = dev_open(dev_name, NULL);
+ if (msd_handle->info.dev_handle[cur_lun]) {
+#ifdef CONFIG_EARPHONE_CASE_ENABLE
+ dev_ioctl(msd_handle->info.dev_handle[cur_lun], IOCTL_POWER_RESUME, (u32)dev_name);
+#endif
+ }
+ } else {
+ //FIXME:need add device state check??
+ u32 dev_online = 0;
+ ret = dev_ioctl(dev_fd, IOCTL_GET_STATUS, (u32)&dev_online);
+ if (ret || !dev_online) {
+ goto __dev_offline;
+ }
+ }
+
+ if (get_cardreader_popup(cur_lun)) {
+ return NULL;
+ }
+ } else {
+ if (dev_fd) {
+ goto __dev_offline;
+ }
+ }
+#else
+ if (dev_fd == NULL) {
+ msd_handle->info.dev_handle[cur_lun] = dev_open(dev_name, NULL);
+ } else {
+ u32 dev_online = 0;
+ ret = dev_ioctl(dev_fd, IOCTL_GET_STATUS, (u32)&dev_online);
+ if (ret || !dev_online) {
+ goto __dev_offline;
+ }
+ }
+#endif
+
+ return msd_handle->info.dev_handle[cur_lun];
+
+__dev_offline:
+ dev_close(dev_fd);
+ recover_set_cardreader_popup(cur_lun);
+ msd_handle->info.dev_handle[cur_lun] = NULL;
+ return NULL;
+}
+static u32 msd_itf_hander(struct usb_device_t *usb_device, struct usb_ctrlrequest *setup)
+{
+ u32 tx_len;
+ u8 *tx_payload = usb_get_setup_buffer(usb_device);
+ u32 bRequestType = setup->bRequestType & USB_TYPE_MASK;
+ switch (bRequestType) {
+ case USB_TYPE_STANDARD:
+ switch (setup->bRequest) {
+ case USB_REQ_GET_STATUS:
+ usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
+ break;
+ case USB_REQ_GET_INTERFACE:
+ tx_len = 1;
+ u8 i = 0;
+ usb_set_data_payload(usb_device, setup, &i, tx_len);
+ break;
+ case USB_REQ_SET_INTERFACE:
+ usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
+ break;
+ default:
+ break;
+ }
+ break;
+ case USB_TYPE_CLASS:
+ switch (setup->bRequest) {
+ case USB_MSD_MAX_LUN:
+ msd_endpoint_init(usb_device, -1);
+ tx_len = 1;
+ tx_payload[0] = __get_max_msd_dev() - 1;
+ usb_set_data_payload(usb_device, setup, tx_payload, tx_len);
+ break;
+ case USB_MSD_RESET :
+ usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+u32 msd_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num)
+{
+ log_debug("%s() %d", __func__, *cur_itf_num);
+ memcpy(ptr, sMassDescriptor, sizeof(sMassDescriptor));
+ ptr[2] = *cur_itf_num;
+#if TCFG_USB_APPLE_DOCK_EN
+ if (apple_mfi_chip_online_lib()) {
+ ptr[5] = 0xff; //bInterfaceClass:Vendor-Specific
+ ptr[6] = 0xf0; //bInterfaceSubClass:MFi Accessory
+ ptr[7] = 0x00; //bInterfaceProtocol */
+ ptr[8] = MSD_STR_INDEX; //bInterfaceString*/
+ }
+#endif
+ if (usb_set_interface_hander(usb_id, *cur_itf_num, msd_itf_hander) != *cur_itf_num) {
+
+ }
+ if (usb_set_reset_hander(usb_id, *cur_itf_num, msd_reset_wakeup) != *cur_itf_num) {
+
+ }
+ *cur_itf_num = *cur_itf_num + 1;
+ return sizeof(sMassDescriptor);
+}
+u32 msd_usb2mcu(const struct usb_device_t *usb_device, u8 *buffer, u32 len)
+{
+ usb_dev usb_id = usb_device2id(usb_device);
+ return usb_g_bulk_read(usb_id, MSD_BULK_EP_OUT, buffer, len, 1);
+}
+u32 msd_mcu2usb(const struct usb_device_t *usb_device, const u8 *buffer, u32 len)
+{
+ usb_dev usb_id = usb_device2id(usb_device);
+ return usb_g_bulk_write(usb_id, MSD_BULK_EP_IN, buffer, len);
+}
+static u32 msd_usb2mcu_64byte_fast(const struct usb_device_t *usb_device, u8 *buffer, u32 len)
+{
+ usb_dev usb_id = usb_device2id(usb_device);
+ return usb_g_bulk_read64byte_fast(usb_id, MSD_BULK_EP_OUT, buffer, len);
+}
+static u32 get_cbw(const struct usb_device_t *usb_device)
+{
+ msd_handle->cbw.dCBWSignature = 0;
+ memset((u8 *)(&(msd_handle->cbw)), 0, sizeof(struct usb_scsi_cbw));
+ u32 rx_len = msd_usb2mcu(usb_device, (u8 *)(&(msd_handle->cbw)), sizeof(struct usb_scsi_cbw));
+ if (rx_len == 0) {
+ return 1;
+ }
+ if (msd_handle->cbw.dCBWSignature ^ CBW_SIGNATURE) {
+ if ((msd_handle->cbw.dCBWSignature ^ CBW_SIGNATURE) != CBW_SIGNATURE) {
+ }
+ return 1;
+ }
+ msd_handle->csw.dCSWTag = msd_handle->cbw.dCBWTag;
+ msd_handle->csw.uCSWDataResidue = msd_handle->cbw.dCBWDataTransferLength;
+
+ return 0;
+}
+static void inquiry(const struct usb_device_t *usb_device)
+{
+ u32 err;
+ u32 len = min(msd_handle->csw.uCSWDataResidue, sizeof(SCSIInquiryData));
+ u32 scsiinquirydata[sizeof(SCSIInquiryData) / 4 + 4]; //usb dma 不能访问code区域
+ memcpy(scsiinquirydata, SCSIInquiryData, sizeof(SCSIInquiryData));
+ err = msd_mcu2usb(usb_device, (const u8 *)scsiinquirydata, len);
+ if (err == 0) {
+ log_error("write usb err %d", __LINE__);
+ }
+ msd_handle->csw.uCSWDataResidue -= len;
+ msd_handle->csw.bCSWStatus = 0;
+}
+static void send_csw(const struct usb_device_t *usb_device)
+{
+ u32 err;
+ msd_handle->csw.dCSWSignature = CSW_SIGNATURE;
+ err = msd_mcu2usb(usb_device, (u8 *) & (msd_handle->csw), sizeof(struct usb_scsi_csw));
+ if (err == 0) {
+ log_error("write usb err %d", __LINE__);
+ }
+}
+static void stall_inep(const struct usb_device_t *usb_device)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ usb_write_txcsr(usb_id, MSD_BULK_EP_IN, TXCSRP_SendStall);
+ u32 ot = 2000;
+
+ while (1) {
+ if (ot-- == 0) {
+ break;
+ }
+ if (usb_otg_online(usb_id) == DISCONN_MODE) {
+ break;
+ }
+ if ((usb_read_txcsr(usb_id, MSD_BULK_EP_IN) & TXCSRP_SendStall) == 0) {
+ break;
+ }
+ }
+}
+
+static void stall_outep(const struct usb_device_t *usb_device)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ usb_write_rxcsr(usb_id, MSD_BULK_EP_OUT, RXCSRP_SendStall);
+ u32 ot = 2000;
+ while (1) {
+ if (ot-- == 0) {
+ break;
+ }
+ if (usb_otg_online(usb_id) == DISCONN_MODE) {
+ break;
+ }
+ if ((usb_read_rxcsr(usb_id, MSD_BULK_EP_OUT) & RXCSRP_SendStall) == 0) {
+ break;
+ }
+ }
+}
+
+static void unknow(const struct usb_device_t *usb_device, u8 rw)
+{
+ if (rw) {
+ stall_outep(usb_device);
+ } else {
+ stall_inep(usb_device);
+ }
+
+ msd_handle->csw.uCSWDataResidue = 0;
+ msd_handle->csw.bCSWStatus = 0x01;
+ msd_handle->info.bError = 0x1;
+ /* msd_handle->info.bError = 0x2; */
+}
+static void stall_error(const struct usb_device_t *usb_device, u8 rw, u8 error)
+{
+ msd_handle->csw.bCSWStatus = 0x01;
+ unknow(usb_device, rw);
+ msd_handle->info.bError = error;
+}
+static void test_unit_ready(const struct usb_device_t *usb_device)
+{
+ int err;
+ u8 cur_lun = msd_handle->cbw.bCBWLUN;
+
+ if (NULL == check_disk_status(cur_lun)) {
+ msd_handle->csw.bCSWStatus = 0x1;
+ msd_handle->info.bError = 0x0f;
+ } else {
+ msd_handle->csw.uCSWDataResidue = 0;
+ msd_handle->csw.bCSWStatus = 0x0;
+ }
+}
+static void allow_medium_removal(const struct usb_device_t *usb_device)
+{
+ msd_handle->csw.bCSWStatus = 0x0;
+ if (msd_handle->cbw.lba[2]) {
+ msd_handle->info.bError = 0x02;
+ msd_handle->csw.bCSWStatus = 0x01;
+ }
+ msd_handle->csw.uCSWDataResidue = 0;
+}
+static void request_sense(const struct usb_device_t *usb_device)
+{
+ u32 err;
+ u32 len;
+ u8 sense_data[0x12];
+ len = min(msd_handle->csw.uCSWDataResidue, 0x12);
+ if (msd_handle->csw.uCSWDataResidue == 0) {
+ stall_inep(usb_device);
+ msd_handle->info.bError = NOT_READY;
+ msd_handle->csw.uCSWDataResidue = 0;
+ msd_handle->csw.bCSWStatus = 0x01;
+ return;
+ } else {
+ memset(sense_data, 0x0, sizeof(sense_data));
+ sense_data[2] = msd_handle->info.bSenseKey;
+ sense_data[12] = msd_handle->info.bAdditionalSenseCode;
+ sense_data[13] = msd_handle->info.bAddiSenseCodeQualifier;
+ sense_data[0] = 0x70;
+ sense_data[7] = 0x0a;
+ err = msd_mcu2usb(usb_device, sense_data, len);
+ if (err == 0) {
+ log_error("write usb err %d", __LINE__);
+ }
+ }
+ msd_handle->csw.uCSWDataResidue -= len;
+ msd_handle->csw.bCSWStatus = 0;
+}
+static u8 const scsi_mode_sense[4] = {
+ 0x03, 0x00, 0x00, 0x00
+};
+static void mode_sense(const struct usb_device_t *usb_device)
+{
+ u32 err;
+ u32 sense;
+ err = msd_mcu2usb(usb_device, (u8 *)scsi_mode_sense, sizeof(scsi_mode_sense));
+ if (err == 0) {
+ log_error("write usb err %d", __LINE__);
+ }
+ msd_handle->csw.uCSWDataResidue = 0;
+ msd_handle->csw.bCSWStatus = 0;
+}
+static void verify(const struct usb_device_t *usb_device)
+{
+ msd_handle->csw.uCSWDataResidue = 0;
+ msd_handle->csw.bCSWStatus = 0;
+}
+
+#if USB_MSD_BULK_DEV_USE_ASYNC
+static void msd_write_10_async(const struct usb_device_t *usb_device, u8 cur_lun, u32 lba, u16 lba_num)
+{
+ u32 err = 0;
+ u16 num = 0;
+ u8 buf_idx = 0;
+ u32 have_send_stall = FALSE;
+ void *dev_fd = NULL;
+ while (lba_num) {
+ wdt_clear();
+ num = lba_num > MSD_BLOCK_SIZE ? MSD_BLOCK_SIZE : lba_num;
+ if (msd_handle->csw.uCSWDataResidue == 0) {
+ msd_handle->csw.bCSWStatus = 1;
+ break;
+ }
+ if (msd_handle->csw.uCSWDataResidue >= num * 0x200) {
+ msd_handle->csw.uCSWDataResidue -= num * 0x200;
+ }
+ err = msd_usb2mcu_64byte_fast(usb_device, msd_handle->msd_buf + buf_idx * MSD_BUFFER_SIZE, num * 0x200);
+ if (err != num * 0x200) {
+ log_error("read usb_err %d, dev = %s",
+ __LINE__, msd_handle->info.dev_name[cur_lun]);
+ stall_error(usb_device, 1, MEDIUM_ERROR);
+ have_send_stall = TRUE;
+ break;
+ }
+ dev_fd = check_disk_status(cur_lun);
+ if (dev_fd) {
+ dev_ioctl(dev_fd, IOCTL_SET_ASYNC_MODE, 0);
+ err = dev_bulk_write(dev_fd, msd_handle->msd_buf + buf_idx * MSD_BUFFER_SIZE, lba, num);
+ if (err != num) {
+ log_error("write_10 write fail, %d, dev = %s",
+ err, msd_handle->info.dev_name[cur_lun]);
+ stall_error(usb_device, 1, MEDIUM_ERROR);
+ have_send_stall = TRUE;
+ break;
+ }
+ } else {
+ log_error("write_10 disk offline, dev = %s",
+ msd_handle->info.dev_name[cur_lun]);
+ stall_error(usb_device, 1, MEDIUM_ERROR);
+ have_send_stall = TRUE;
+ break;
+ }
+ buf_idx = !buf_idx;
+ lba_num -= num;
+ lba += num;
+ }
+ dev_fd = check_disk_status(cur_lun);
+ if (dev_fd) {
+ //async mode last block flush
+ dev_ioctl(dev_fd, IOCTL_FLUSH, 0);
+ } else {
+ if (have_send_stall == FALSE) {
+ log_error("write_10 disk offline while sync, dev = %s",
+ msd_handle->info.dev_name[cur_lun]);
+ stall_error(usb_device, 1, MEDIUM_ERROR);
+ }
+ }
+}
+
+static void msd_read_10_async(const struct usb_device_t *usb_device, u8 cur_lun, u32 lba, u16 lba_num)
+{
+ u32 err = 0;
+ u16 num = 0;
+ u8 buf_idx = 0;
+ u32 last_lba = 0, last_num = 0;
+ void *dev_fd = NULL;
+
+ if (lba_num == 0) {
+ log_error("lba_num == 0\n");
+ stall_error(usb_device, 0, 0x02);
+ return;
+ }
+ num = lba_num > MSD_BLOCK_SIZE ? MSD_BLOCK_SIZE : lba_num;
+ dev_fd = check_disk_status(cur_lun);
+ if (dev_fd) {
+ dev_ioctl(dev_fd, IOCTL_SET_ASYNC_MODE, 0);
+ err = dev_bulk_read(dev_fd, msd_handle->msd_buf + buf_idx * MSD_BUFFER_SIZE, lba, num);
+ if (err != num) {
+ log_error("read disk error0 = %d, dev = %s\n", err, msd_handle->info.dev_name[cur_lun]);
+ stall_error(usb_device, 0, MEDIUM_ERROR);
+ return;
+ }
+ } else {
+ log_error("read_10 disk offline, dev = %s\n", msd_handle->info.dev_name[cur_lun]);
+ stall_error(usb_device, 0, MEDIUM_ERROR);
+ return;
+ }
+
+ while (lba_num) {
+ wdt_clear();
+ last_num = num;
+ last_lba = lba;
+ buf_idx = !buf_idx;
+ lba += num;
+ lba_num -= num;
+ num = lba_num > MSD_BLOCK_SIZE ? MSD_BLOCK_SIZE : lba_num;
+ if (msd_handle->csw.uCSWDataResidue == 0) {
+ msd_handle->csw.bCSWStatus = 1;
+ break;
+ }
+ if (msd_handle->csw.uCSWDataResidue >= last_num * 0x200) {
+ msd_handle->csw.uCSWDataResidue -= last_num * 0x200;
+ }
+ dev_fd = check_disk_status(cur_lun);
+ if (dev_fd) {
+ if (num) {
+ dev_ioctl(dev_fd, IOCTL_SET_ASYNC_MODE, 0);
+ err = dev_bulk_read(dev_fd, msd_handle->msd_buf + buf_idx * MSD_BUFFER_SIZE, lba, num);
+ if (err != num) {
+ log_error("read disk error1 = %d, dev = %s",
+ err, msd_handle->info.dev_name[cur_lun]);
+ stall_error(usb_device, 0, MEDIUM_ERROR);
+ break;
+ }
+ } else {
+ //async mode last block flush
+ dev_ioctl(dev_fd, IOCTL_FLUSH, 0);
+ }
+ } else {
+ log_error("read_10 disk offline, dev = %s",
+ msd_handle->info.dev_name[cur_lun]);
+ stall_error(usb_device, 0, MEDIUM_ERROR);
+ break;
+ }
+
+ /* u8 *p = msd_handle->msd_buf + !buf_idx * MSD_BUFFER_SIZE; */
+ /* for (int i = 0; i < last_num * 512; i++) { */
+ /* p[i] = i; */
+ /* } */
+
+ err = msd_mcu2usb(usb_device, msd_handle->msd_buf + !buf_idx * MSD_BUFFER_SIZE, last_num * 0x200);
+
+ if (err != last_num * 0x200) {
+ log_error("read_10 data transfer err %d, dev = %s",
+ __LINE__, msd_handle->info.dev_name[cur_lun]);
+ stall_error(usb_device, 0, 0x05);
+ if (num) {
+ dev_ioctl(dev_fd, IOCTL_FLUSH, 0);
+ }
+ break;
+ }
+ }
+}
+#endif
+static u32 read_32(u8 *p)
+{
+ return ((u32)(p[0]) << 24) | ((u32)(p[1]) << 16) | ((u32)(p[2]) << 8) | (p[3]);
+}
+
+
+static void write_10(const struct usb_device_t *usb_device)
+{
+ u32 err = 0 ;
+ u32 lba;
+ u16 lba_num;
+ u16 num = 0;
+ lba = read_32(msd_handle->cbw.lba);
+ lba_num = ((u16)(msd_handle->cbw.LengthH) << 8) | (msd_handle->cbw.LengthL);
+ u8 cur_lun = msd_handle->cbw.bCBWLUN;
+ void *dev_fd = msd_handle->info.dev_handle[cur_lun];
+
+ /* app_status_handler(APP_STATUS_PC_COPY); */
+
+
+#if USB_MSD_BULK_DEV_USE_ASYNC
+ /* u32 old_speed; */
+ /* dev_fd = check_disk_status(cur_lun); */
+ /* if (dev_fd) { */
+ /* dev_ioctl(dev_fd, IOCTL_GET_SPEED, (u32)&old_speed); */
+ /* dev_ioctl(dev_fd, IOCTL_SET_SPEED, 48000000); */
+ /* } */
+ msd_write_10_async(usb_device, cur_lun, lba, lba_num);
+ /* if (dev_fd) { */
+ /* dev_ioctl(dev_fd, IOCTL_SET_SPEED, old_speed); */
+ /* } */
+#else
+
+ while (lba_num) {
+ wdt_clear();
+ num = lba_num > MSD_BLOCK_SIZE ? MSD_BLOCK_SIZE : lba_num;
+ if (msd_handle->csw.uCSWDataResidue == 0) {
+ msd_handle->csw.bCSWStatus = 0x1;
+ break;
+ }
+ if (msd_handle->csw.uCSWDataResidue >= (num * 0x200)) {
+ msd_handle->csw.uCSWDataResidue -= (num * 0x200);
+ }
+ err = msd_usb2mcu_64byte_fast(usb_device, msd_handle->msd_buf, num * 0x200);
+ if (err == 0) {
+ stall_error(usb_device, 1, MEDIUM_ERROR);
+ log_error("read usb, dev = %s", err, msd_handle->info.dev_name[cur_lun]);
+ break;
+ }
+ dev_fd = check_disk_status(cur_lun);
+ if (dev_fd) {
+ dev_ioctl(dev_fd, IOCTL_CMD_RESUME, 0);
+ err = dev_bulk_write(dev_fd, msd_handle->msd_buf, lba, num);
+ dev_ioctl(dev_fd, IOCTL_CMD_SUSPEND, 0);
+ if (err != num) {
+ stall_error(usb_device, 1, MEDIUM_ERROR);
+ log_error("write disk error =%d, dev = %s", err, msd_handle->info.dev_name[cur_lun]);
+ break;
+ } else {
+ break;
+ }
+ lba += num;
+ lba_num -= num;
+ } else {
+ log_error("write disk offline, dev = %s", msd_handle->info.dev_name[cur_lun]);
+ stall_error(usb_device, 1, MEDIUM_ERROR);
+ break;
+ }
+ }
+#endif
+}
+static void read_10(const struct usb_device_t *usb_device)
+{
+ u32 err = 0;
+ u32 lba;
+ u16 lba_num;
+ u16 num = 0;
+ lba = read_32(msd_handle->cbw.lba);
+ lba_num = ((u16)(msd_handle->cbw.LengthH) << 8) | (msd_handle->cbw.LengthL);
+ u8 cur_lun = msd_handle->cbw.bCBWLUN;
+ void *dev_fd = msd_handle->info.dev_handle[cur_lun];
+
+#if USB_MSD_BULK_DEV_USE_ASYNC
+ msd_read_10_async(usb_device, cur_lun, lba, lba_num);
+#else
+
+ while (lba_num) {
+ wdt_clear();
+ num = lba_num > MSD_BLOCK_SIZE ? MSD_BLOCK_SIZE : lba_num;
+ if (msd_handle->csw.uCSWDataResidue == 0) {
+ msd_handle->csw.bCSWStatus = 0x1;
+ break;
+ }
+ if (msd_handle->csw.uCSWDataResidue >= (num * 0x200)) {
+ msd_handle->csw.uCSWDataResidue -= (num * 0x200);
+ }
+ dev_fd = check_disk_status(cur_lun);
+ if (dev_fd) {
+ dev_ioctl(dev_fd, IOCTL_CMD_RESUME, 0);
+ err = dev_bulk_read(dev_fd, msd_handle->msd_buf, lba, num);
+ dev_ioctl(dev_fd, IOCTL_CMD_SUSPEND, 0);
+ if (err != num) {
+ log_error("read disk error =%d, dev = %s", err, msd_handle->info.dev_name[cur_lun]);
+ stall_error(usb_device, 0, MEDIUM_ERROR);
+ break;
+ }
+ } else {
+ log_error("read disk offline, dev = %s", err, msd_handle->info.dev_name[cur_lun]);
+ stall_error(usb_device, 0, MEDIUM_ERROR);
+ break;
+ }
+ err = msd_mcu2usb(usb_device, msd_handle->msd_buf, num * 0x200);
+ if (err == 0) {
+ log_error("write usb err %d, dev = %s", __LINE__, msd_handle->info.dev_name[cur_lun]);
+ stall_error(usb_device, 0, MEDIUM_ERROR);
+ break;
+ }
+ lba += num;
+ lba_num -= num;
+ }
+#endif
+}
+static void read_capacity(const struct usb_device_t *usb_device)
+{
+ u32 err;
+ u32 capacity_temp;
+ u8 capacity[8] = {0};
+ u8 cur_lun = msd_handle->cbw.bCBWLUN;
+ void *dev_fd = check_disk_status(cur_lun);
+ if (!dev_fd) {
+ stall_error(usb_device, 0, 0x0f);
+ return;
+ }
+ dev_ioctl(dev_fd, IOCTL_GET_CAPACITY, (u32)&capacity_temp);
+ capacity_temp = cpu_to_be32(capacity_temp - 1);
+ memcpy(capacity, &capacity_temp, 4);
+ dev_ioctl(dev_fd, IOCTL_GET_BLOCK_SIZE, (u32)&capacity_temp);
+ /* r_printf(">>>[test]:capacity_temp2 = %d\n", capacity_temp); */
+ capacity_temp = cpu_to_be32(capacity_temp);
+ memcpy(&capacity[4], &capacity_temp, 4);
+ err = msd_mcu2usb(usb_device, capacity, 8);
+ if (err == 0) {
+ log_error("write usb err %d", __LINE__);
+ }
+ msd_handle->csw.uCSWDataResidue = 0;
+ msd_handle->csw.bCSWStatus = 0;
+
+}
+
+static void read_format_capacity(const struct usb_device_t *usb_device)
+{
+ u32 err;
+ u8 capacity[12] = {0};
+ u32 capacity_temp;
+ u8 cur_lun = msd_handle->cbw.bCBWLUN;
+ void *dev_fd = check_disk_status(cur_lun);
+ if (!dev_fd) {
+ stall_error(usb_device, 0, 0x0f);
+ return;
+ }
+
+ dev_ioctl(dev_fd, IOCTL_GET_CAPACITY, (u32)&capacity_temp);
+
+ capacity_temp = cpu_to_be32(capacity_temp);
+ memcpy(&capacity[4], &capacity_temp, 4);
+ dev_ioctl(dev_fd, IOCTL_GET_BLOCK_SIZE, (u32)&capacity_temp);
+ capacity_temp = cpu_to_be32(capacity_temp);
+ memcpy(&capacity[8], &capacity_temp, 4);
+ capacity[3] = 0x08;
+ capacity[8] = 0x02;
+ err = msd_mcu2usb(usb_device, capacity, 12);
+ if (err == 0) {
+ log_error("write usb err %d", __LINE__);
+ }
+ msd_handle->csw.uCSWDataResidue -= 12;
+ msd_handle->csw.bCSWStatus = 0;
+}
+
+static void stop_start()
+{
+ int i;
+ u8 loej, start;
+ /* set_cardreader_popup(0, !(msd_handle->cbw.lba[2])); */
+ loej = msd_handle->cbw.lba[2] & BIT(1);
+ start = msd_handle->cbw.lba[2] & BIT(0);
+ for (i = 0; i < __get_max_msd_dev(); i++) {
+ if (loej && !start) {
+ set_cardreader_popup(i, 1);
+ } else if (loej && start) {
+ set_cardreader_popup(i, 0);
+ }
+ }
+
+ msd_handle->csw.uCSWDataResidue = 0;
+ msd_handle->csw.bCSWStatus = 0x0;
+}
+
+
+u32 private_scsi_cmd(const struct usb_device_t *usb_device, struct usb_scsi_cbw *cbw);
+
+void USB_MassStorage(const struct usb_device_t *usb_device)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+#ifdef USB_HW_20
+ //husb每次收到数据都有intrrx, 即使intrrxe没有打开,所以USB_MassStorage()退出
+ //前一打开intrrxe就会起来一次rx中断,但是ep的rxcsr == 0
+ if ((usb_read_rxcsr(usb_id, MSD_BULK_EP_OUT) & RXCSRP_RxPktRdy) == 0) {
+ return;
+ }
+#endif
+ usb_clr_intr_rxe(usb_id, MSD_BULK_EP_OUT);
+ if (get_cbw(usb_device)) {
+ usb_set_intr_rxe(usb_id, MSD_BULK_EP_OUT);
+ return;
+ }
+ /* log_debug("opcode %x", msd_handle->cbw.operationCode); */
+ if (private_scsi_cmd(usb_device, &(msd_handle->cbw))) {
+ msd_handle->info.bError = 0;
+ msd_handle->csw.uCSWDataResidue = 0;
+ msd_handle->csw.bCSWStatus = 0x0;
+ } else {
+ wdt_clear();
+ switch (msd_handle->cbw.operationCode) {
+ case INQUIRY://0x12
+ inquiry(usb_device);
+ break;
+ case TEST_UNIT_READY://0x00
+ test_unit_ready(usb_device);
+ break;
+ case VERIFY://0x2f
+ verify(usb_device);
+ break;
+ case ALLOW_MEDIUM_REMOVAL://0x1e
+ allow_medium_removal(usb_device);
+ break;
+ case REQUEST_SENSE://0x03
+ request_sense(usb_device);
+ break;
+ case MODE_SENSE://0x1a
+ mode_sense(usb_device);
+ break;
+ case READ_10://0x28
+ read_10(usb_device);
+ break;
+ case WRITE_10://0x2a
+ write_10(usb_device);
+ break;
+ case READ_CAPACITY://0x25
+ read_capacity(usb_device);
+ break;
+ case READ_FORMAT_CAPACITIES://0x23
+ read_format_capacity(usb_device);
+ break;
+ case START_STOP://0x1b
+ stop_start();
+ break;
+
+ default:
+ log_error("opcode %x", msd_handle->cbw.operationCode);
+ stall_error(usb_device, 0, !(msd_handle->cbw.bmCBWFlags & 0x80));
+ break;
+ }
+ }
+ switch (msd_handle->info.bError) {
+ case 0x00:
+ msd_handle->info.bSenseKey = NO_SENSE;
+ msd_handle->info.bAdditionalSenseCode = ASC_NO_ADDITIONAL_SENSE_INFORMATION;
+ msd_handle->info.bAddiSenseCodeQualifier = ASCQ_NO_ADDITIONAL_SENSE_INFORMATION;
+ break;
+
+ case 0x02:
+ msd_handle->info.bSenseKey = ILLEGAL_REQUEST;
+ msd_handle->info.bAdditionalSenseCode = ASC_INVALID_FIELD_IN_COMMAND_PACKET;
+ msd_handle->info.bAddiSenseCodeQualifier = ASCQ_INVALID_FIELD_IN_COMMAND_PACKET;
+ break;
+ case MEDIUM_ERROR:
+ msd_handle->info.bSenseKey = MEDIUM_ERROR;
+ msd_handle->info.bAdditionalSenseCode = ASC_WRITE_FAULT;
+ msd_handle->info.bAddiSenseCodeQualifier = ASCQ_WRITE_FAULT;
+ break;
+
+
+ case 0x0f:
+ case 0x05:
+ msd_handle->info.bSenseKey = NOT_READY;
+ msd_handle->info.bAdditionalSenseCode = ASC_MEDIUM_PRESENT;
+ msd_handle->info.bAddiSenseCodeQualifier = ASCQ_MEDIUM_PRESENT;
+ break;
+ case 0x06:
+ msd_handle->info.bSenseKey = ABORTED_COMMAND;
+ msd_handle->info.bAdditionalSenseCode = ASC_INVALID_COMMAND_OPERATION_CODE;
+ msd_handle->info.bAddiSenseCodeQualifier = ASCQ_INVALID_COMMAND_OPERATION_CODE;
+ break;
+ }
+ usb_set_intr_rxe(usb_id, MSD_BULK_EP_OUT);
+ send_csw(usb_device);
+}
+
+u32 msd_register_disk(const char *name, void *arg)
+{
+ int i;
+ u32 len, ret = -1;
+ if (msd_handle) {
+ for (i = 0; i < __get_max_msd_dev(); i++) {
+ if (msd_handle->info.dev_name[i][0] == 0) {
+ ASSERT(strlen(name) <= MSD_DEV_NAME_LEN, "MSD_DEV_NAME_LEN too small");
+ strcpy(msd_handle->info.dev_name[i], name);
+ msd_handle->info.dev_handle[i] = NULL;
+ break;
+ }
+ }
+ if (i == __get_max_msd_dev()) {
+ ret = -3;
+ }
+ }
+ return ret;
+}
+u32 msd_unregister_disk(const char *name)
+{
+ u32 err;
+ int i;
+ if (msd_handle) {
+ for (i = 0; i < __get_max_msd_dev(); i++) {
+ if (!strcmp(msd_handle->info.dev_name[i], name)) {
+ msd_handle->info.dev_name[i][0] = 0;
+ return 0;
+ }
+ }
+ }
+ return -1;
+}
+
+u32 msd_unregister_all()
+{
+ u32 err;
+ int i;
+ if (msd_handle) {
+ for (i = 0; i < __get_max_msd_dev(); i++) {
+ if (msd_handle->info.dev_handle[i]) {
+ err = dev_close(msd_handle->info.dev_handle[i]);
+ msd_handle->info.dev_handle[i] = NULL;
+ /* memset(msd_handle->info.dev_name[i], 0, MSD_DEV_NAME_LEN); */
+ }
+ }
+ }
+ return 0;
+}
+u32 msd_register(const usb_dev usb_id)
+{
+ if (msd_handle == NULL) {
+#if USB_MALLOC_ENABLE
+ msd_handle = (struct usb_msd_handle *)zalloc(sizeof(struct usb_msd_handle));
+ if (msd_handle == NULL) {
+ log_error("msd_register err");
+ return -1;
+ }
+#if USB_MSD_BULK_DEV_USE_ASYNC
+ msd_handle->msd_buf = (u8 *)malloc(MSD_BUFFER_SIZE * 2);
+#else
+ msd_handle->msd_buf = (u8 *)malloc(MSD_BUFFER_SIZE);
+#endif
+ if (msd_handle->msd_buf == NULL) {
+ log_error("msd_register err");
+ return -1;
+ }
+#else
+ memset(&_msd_handle, 0, sizeof(struct usb_msd_handle));
+ _msd_handle.msd_buf = msd_buf;
+ msd_handle = &_msd_handle;
+#endif
+ log_info("msd_handle = %x", msd_handle);
+
+ msd_handle->ep_out_dmabuffer = usb_alloc_ep_dmabuffer(usb_id, MSD_BULK_EP_OUT, MAXP_SIZE_BULKIN + MAXP_SIZE_BULKOUT);
+
+ }
+ return 0;
+}
+u32 msd_release()
+{
+ if (msd_handle) {
+ for (int i = 0; i < __get_max_msd_dev(); i++) {
+ void *dev_fd = msd_handle->info.dev_handle[i] ;
+ if (dev_fd) {
+#ifdef CONFIG_EARPHONE_CASE_ENABLE
+ dev_ioctl(dev_fd, IOCTL_POWER_SUSPEND, 0);
+#endif
+ dev_close(dev_fd);
+ msd_handle->info.dev_handle[i] = NULL;
+ }
+ }
+
+#if USB_MALLOC_ENABLE
+ if (msd_handle->msd_buf) {
+ free(msd_handle->msd_buf);
+ msd_handle->msd_buf = NULL;
+ }
+ free(msd_handle);
+#endif
+ msd_handle = NULL;
+ }
+ return 0;
+}
+
+#if TCFG_USB_APPLE_DOCK_EN
+int usb_g_ep_read_check(const usb_dev id, u32 ep, u32 rx_len)
+{
+ if (apple_mfi_chip_online_lib()) {
+ if (ep != MSD_BULK_EP_OUT) {
+ return 0;
+ }
+ u32 dma_size = usb_get_dma_size(id, ep);
+ /* printf("dma:%d, rl:%d, ep:%d \n", dma_size, rx_len, ep); */
+ if (rx_len < dma_size) {
+ return -1;
+ }
+ }
+ return 0;
+}
+void apple_usb_msd_wakeup(struct usb_device_t *usb_device)
+{
+ msd_wakeup(usb_device, MSD_BULK_EP_IN);
+}
+u8 MCU_SRAMToUSB_app(void *hdl, u8 *pBuf, u16 uCount)
+{
+ return msd_mcu2usb(hdl, pBuf, uCount);
+}
+u8 MCU_USBToSRAM_app(void *hdl, u8 *pBuf, u16 uCount)
+{
+ /* return msd_usb2mcu(hdl, pBuf, uCount); */
+ usb_dev usb_id = usb_device2id(hdl);
+ int ret;
+ int cnt = 10000;
+ while (cnt--) {
+ ret = usb_g_bulk_read(usb_id, MSD_BULK_EP_OUT, pBuf, uCount, 0);
+ if (ret) {
+ break;
+ }
+ }
+ // printf("%s,%d, ret:%d, cnt:%d \n", __func__, __LINE__, ret, cnt);
+ // put_buf(pBuf, ret);
+ return ret;
+}
+#endif
+#endif
diff --git a/apps/common/device/usb/device/msd_upgrade.c b/apps/common/device/usb/device/msd_upgrade.c
new file mode 100644
index 0000000..3eb124f
--- /dev/null
+++ b/apps/common/device/usb/device/msd_upgrade.c
@@ -0,0 +1,76 @@
+#include "system/includes.h"
+#include "usb/device/msd.h"
+#include "usb/scsi.h"
+#include "usb_config.h"
+#include "app_config.h"
+#include "cpu.h"
+#include "asm/debug.h"
+
+#define WRITE_FLASH 0xFB
+#define READ_FLASH 0xFD
+#define OTHER_CMD 0xFC
+typedef enum {
+ UPGRADE_NULL = 0,
+ UPGRADE_USB_HARD_KEY,
+ UPGRADE_USB_SOFT_KEY,
+ UPGRADE_UART_KEY,
+} UPGRADE_STATE;
+
+extern void nvram_set_boot_state(u32 state);
+extern void hw_mmu_disable(void);
+extern void ram_protect_close(void);
+
+AT(.volatile_ram_code)
+void go_mask_usb_updata()
+{
+#ifdef CONFIG_CPU_BR18
+ gpio_set_die(IO_PORTD_02, 0);
+ gpio_set_die(IO_PORTB_04, 0);
+ cpu_reset();
+
+#else
+ local_irq_disable();
+ ram_protect_close();
+ //FIXME
+ /* hw_mmu_disable(); */
+ nvram_set_boot_state(UPGRADE_USB_SOFT_KEY);
+ JL_CLOCK->PWR_CON |= (1 << 4);
+#endif
+
+ /* chip_reset(); */
+ /* cpu_reset(); */
+ while (1);
+}
+#if TCFG_PC_UPDATE
+
+u32 _usb_bulk_rw_test(const struct usb_device_t *usb_device, struct usb_scsi_cbw *cbw);
+
+u32 private_scsi_cmd(const struct usb_device_t *usb_device, struct usb_scsi_cbw *cbw)
+{
+ /* if (_usb_bulk_rw_test(usb_device, cbw)) { */
+ /* return TRUE; */
+ /* } */
+
+ switch (cbw->operationCode) {
+//////////////////////Boot Loader Custom CMD
+ case WRITE_FLASH:
+ case READ_FLASH:
+ case OTHER_CMD:
+ log_d("goto mask pc mode\n");
+ go_mask_usb_updata();
+ break;
+
+ default:
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+#else
+u32 private_scsi_cmd(const struct usb_device_t *usb_device, struct usb_scsi_cbw *cbw)
+{
+ return FALSE;
+}
+#endif
+
diff --git a/apps/common/device/usb/device/task_pc.c b/apps/common/device/usb/device/task_pc.c
new file mode 100644
index 0000000..7b129d4
--- /dev/null
+++ b/apps/common/device/usb/device/task_pc.c
@@ -0,0 +1,463 @@
+/**
+ * @file task_pc.c
+ * @brief 从机模式
+ * @author chenrixin@zh-jieli.com
+ * @version 1.0.0
+ * @date 2020-02-29
+ */
+
+#include "system/app_core.h"
+#include "system/includes.h"
+#include "server/server_core.h"
+#include "app_config.h"
+#include "app_action.h"
+#include "os/os_api.h"
+#include "device/sdmmc.h"
+
+#include "app_charge.h"
+#include "asm/charge.h"
+
+#if TCFG_USB_SLAVE_ENABLE
+#if USB_PC_NO_APP_MODE == 0
+#include "app_task.h"
+#endif
+#include "usb/usb_config.h"
+#include "usb/device/usb_stack.h"
+
+#if TCFG_USB_SLAVE_HID_ENABLE
+#include "usb/device/hid.h"
+#endif
+
+#if TCFG_USB_SLAVE_MSD_ENABLE
+#include "usb/device/msd.h"
+#endif
+
+#if TCFG_USB_SLAVE_CDC_ENABLE
+#include "usb/device/cdc.h"
+#endif
+
+#if (TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0)
+#include "dev_multiplex_api.h"
+#endif
+
+#if TCFG_USB_APPLE_DOCK_EN
+#include "apple_dock/iAP.h"
+#endif
+
+#if (TCFG_CFG_TOOL_ENABLE || TCFG_EFFECT_TOOL_ENABLE)
+#include "cfg_tool.h"
+#endif
+
+#if ((TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE) \
+ && TCFG_CHARGESTORE_PORT == IO_PORT_DP)
+#include "asm/chargestore.h"
+#endif
+
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[USB_TASK]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#define USB_TASK_NAME "usb_msd"
+
+#define USBSTACK_EVENT 0x80
+#define USBSTACK_MSD_RUN 0x81
+#define USBSTACK_MSD_RELASE 0x82
+#define USBSTACK_HID 0x83
+#define USBSTACK_MSD_RESET 0x84
+
+extern int usb_audio_demo_init(void);
+extern void usb_audio_demo_exit(void);
+
+static usb_dev usbfd = 0;//SEC(.usb_g_bss);
+static OS_MUTEX msd_mutex ;//SEC(.usb_g_bss);
+static u8 msd_in_task;
+static u8 msd_run_reset;
+
+
+static void usb_task(void *p)
+{
+ int ret = 0;
+ int msg[16];
+ while (1) {
+ ret = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
+ if (ret != OS_TASKQ) {
+ continue;
+ }
+ if (msg[0] != Q_MSG) {
+ continue;
+ }
+ switch (msg[1]) {
+#if TCFG_USB_SLAVE_MSD_ENABLE
+ case USBSTACK_MSD_RUN:
+ os_mutex_pend(&msd_mutex, 0);
+ msd_in_task = 1;
+#if TCFG_USB_APPLE_DOCK_EN
+ apple_mfi_link((void *)msg[2]);
+#else
+ USB_MassStorage((void *)msg[2]);
+#endif
+ if (msd_run_reset) {
+ msd_reset((struct usb_device_t *)msg[2], 0);
+ msd_run_reset = 0;
+ }
+ msd_in_task = 0;
+ os_mutex_post(&msd_mutex);
+ break;
+ case USBSTACK_MSD_RELASE:
+ os_sem_post((OS_SEM *)msg[2]);
+ while (1) {
+ os_time_dly(10000);
+ }
+ break;
+// case USBSTACK_MSD_RESET:
+// os_mutex_pend(&msd_mutex, 0);
+// msd_reset((struct usb_device_t *)msg[2], (u32)msg[3]);
+// os_mutex_post(&msd_mutex);
+// break;
+#endif
+ default:
+ break;
+ }
+ }
+}
+
+static void usb_msd_wakeup(struct usb_device_t *usb_device)
+{
+ os_taskq_post_msg(USB_TASK_NAME, 2, USBSTACK_MSD_RUN, usb_device);
+}
+static void usb_msd_reset_wakeup(struct usb_device_t *usb_device, u32 itf_num)
+{
+ /* os_taskq_post_msg(USB_TASK_NAME, 3, USBSTACK_MSD_RESET, usb_device, itf_num); */
+ if (msd_in_task) {
+ msd_run_reset = 1;
+ } else {
+#if TCFG_USB_SLAVE_MSD_ENABLE
+ msd_reset(usb_device, 0);
+#endif
+ }
+}
+static void usb_msd_init()
+{
+ r_printf("%s()", __func__);
+ int err;
+ os_mutex_create(&msd_mutex);
+ err = task_create(usb_task, NULL, USB_TASK_NAME);
+ if (err != OS_NO_ERR) {
+ r_printf("usb_msd task creat fail %x\n", err);
+ }
+}
+static void usb_msd_free()
+{
+ r_printf("%s()", __func__);
+
+ os_mutex_del(&msd_mutex, 0);
+
+ int err;
+ OS_SEM sem;
+ os_sem_create(&sem, 0);
+ os_taskq_post_msg(USB_TASK_NAME, 2, USBSTACK_MSD_RELASE, (int)&sem);
+ os_sem_pend(&sem, 0);
+
+
+ err = task_kill(USB_TASK_NAME);
+ if (!err) {
+ r_printf("usb_msd_uninit succ!!\n");
+ } else {
+ r_printf("usb_msd_uninit fail!!\n");
+ }
+}
+
+#if TCFG_USB_SLAVE_CDC_ENABLE
+static void usb_cdc_wakeup(struct usb_device_t *usb_device)
+{
+ //回调函数在中断里,正式使用不要在这里加太多东西阻塞中断,
+ //或者先post到任务,由任务调用cdc_read_data()读取再执行后续工作
+ const usb_dev usb_id = usb_device2id(usb_device);
+ u8 buf[64] = {0};
+ static u8 buf_rx[256] = {0};
+ static u8 rx_len_total = 0;
+ u32 rlen;
+
+ log_debug("cdc rx hook");
+ rlen = cdc_read_data(usb_id, buf, 64);
+
+ /* put_buf(buf, rlen);//固件三部测试使用 */
+ /* cdc_write_data(usb_id, buf, rlen);//固件三部测试使用 */
+
+ if ((buf[0] == 0x5A) && (buf[1] == 0xAA) && (buf[2] == 0xA5)) {
+ memset(buf_rx, 0, 256);
+ memcpy(buf_rx, buf, rlen);
+ /* log_info("need len = %d\n", buf_rx[5] + 6); */
+ /* log_info("rx len = %d\n", rlen); */
+ if ((buf_rx[5] + 6) == rlen) {
+ rx_len_total = 0;
+#if TCFG_CFG_TOOL_ENABLE || TCFG_EFFECT_TOOL_ENABLE
+#if (TCFG_COMM_TYPE == TCFG_USB_COMM)
+ /* put_buf(buf_rx, rlen); */
+ online_cfg_tool_data_deal(buf_rx, rlen);
+#else
+ put_buf(buf, rlen);
+ cdc_write_data(usb_id, buf, rlen);
+#endif
+#endif
+ } else {
+ rx_len_total += rlen;
+ }
+ } else {
+ if ((rx_len_total + rlen) > 256) {
+ memset(buf_rx, 0, 256);
+ rx_len_total = 0;
+ return;
+ }
+ memcpy(buf_rx + rx_len_total, buf, rlen);
+ /* log_info("need len = %d\n", buf_rx[5] + 6); */
+ /* log_info("rx len = %d\n", rx_len_total + rlen); */
+ if ((buf_rx[5] + 6) == (rx_len_total + rlen)) {
+#if TCFG_CFG_TOOL_ENABLE || TCFG_EFFECT_TOOL_ENABLE
+#if (TCFG_COMM_TYPE == TCFG_USB_COMM)
+ /* put_buf(buf_rx, rx_len_total + rlen); */
+ online_cfg_tool_data_deal(buf_rx, rx_len_total + rlen);
+#else
+ put_buf(buf, rlen);
+ cdc_write_data(usb_id, buf, rlen);
+#endif
+#endif
+ rx_len_total = 0;
+ } else {
+ rx_len_total += rlen;
+ }
+ }
+}
+#endif
+
+void usb_start()
+{
+
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+ usb_audio_demo_init();
+#endif
+
+#ifdef USB_DEVICE_CLASS_CONFIG
+ g_printf("USB_DEVICE_CLASS_CONFIG:%x", USB_DEVICE_CLASS_CONFIG);
+#if TCFG_USB_CDC_BACKGROUND_RUN
+ usb_device_mode(usbfd, USB_DEVICE_CLASS_CONFIG | CDC_CLASS);
+#else
+ usb_device_mode(usbfd, USB_DEVICE_CLASS_CONFIG);
+#endif
+
+#endif
+
+
+#if TCFG_USB_SLAVE_MSD_ENABLE
+ //没有复用时候判断 sd开关
+ //复用时候判断是否参与复用
+#if (!TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_SD0_ENABLE)\
+ ||(TCFG_SD0_ENABLE && TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_DM_MULTIPLEX_WITH_SD_PORT != 0)
+ msd_register_disk("sd0", NULL);
+#endif
+
+#if (!TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_SD1_ENABLE)\
+ ||(TCFG_SD1_ENABLE && TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_DM_MULTIPLEX_WITH_SD_PORT != 1)
+ msd_register_disk("sd1", NULL);
+#endif
+
+#if TCFG_NOR_FAT
+ msd_register_disk("fat_nor", NULL);
+#endif
+
+#if TCFG_VIR_UDISK_ENABLE
+ msd_register_disk("vir_udisk0", NULL);
+#endif
+
+ msd_set_wakeup_handle(usb_msd_wakeup);
+ msd_set_reset_wakeup_handle(usb_msd_reset_wakeup);
+ usb_msd_init();
+#endif
+
+#if TCFG_USB_SLAVE_CDC_ENABLE
+ cdc_set_wakeup_handler(usb_cdc_wakeup);
+#endif
+}
+static void usb_remove_disk()
+{
+#if TCFG_USB_SLAVE_MSD_ENABLE
+ os_mutex_pend(&msd_mutex, 0);
+ msd_unregister_all();
+ os_mutex_post(&msd_mutex);
+#endif
+}
+void usb_pause()
+{
+ log_info("usb pause");
+
+ usb_sie_disable(usbfd);
+
+#if TCFG_USB_SLAVE_MSD_ENABLE
+ if (msd_set_wakeup_handle(NULL)) {
+ usb_remove_disk();
+ usb_msd_free();
+ }
+#endif
+
+
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+ usb_audio_demo_exit();
+#endif
+
+ usb_device_mode(usbfd, 0);
+}
+
+void usb_stop()
+{
+ log_info("App Stop - usb");
+
+ usb_pause();
+
+ usb_sie_close(usbfd);
+}
+
+#if TCFG_USB_CDC_BACKGROUND_RUN
+void usb_cdc_background_run()
+{
+ g_printf("CDC is running in the background");
+ usb_device_mode(0, CDC_CLASS);
+ cdc_set_wakeup_handler(usb_cdc_wakeup);
+}
+#endif
+
+int pc_device_event_handler(struct sys_event *event)
+{
+ if ((int)event->arg != DEVICE_EVENT_FROM_OTG) {
+ return false;
+ }
+
+ int switch_app_case = false;
+ const char *usb_msg = (const char *)event->u.dev.value;
+ log_debug("usb event : %d DEVICE_EVENT_FROM_OTG %s", event->u.dev.event, usb_msg);
+
+ if (usb_msg[0] == 's') {
+ if (event->u.dev.event == DEVICE_EVENT_IN) {
+ log_info("usb %c online", usb_msg[2]);
+ usbfd = usb_msg[2] - '0';
+#if USB_PC_NO_APP_MODE
+ usb_start();
+#elif TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
+
+#if TCFG_USB_CDC_BACKGROUND_RUN
+ mult_sdio_suspend();
+ usb_cdc_background_run();
+ switch_app_case = 0;
+#else
+ usb_otg_suspend(0, OTG_KEEP_STATE);
+ mult_sdio_suspend();
+ usb_pause();
+ mult_sdio_resume();
+ switch_app_case = 0;
+#endif//TCFG_USB_CDC_BACKGROUND_RUN
+
+#else
+
+
+#if (TWFG_APP_POWERON_IGNORE_DEV && TCFG_USB_CDC_BACKGROUND_RUN && TCFG_PC_ENABLE)
+ if (jiffies_to_msecs(jiffies) < TWFG_APP_POWERON_IGNORE_DEV) {
+ usb_cdc_background_run();
+ switch_app_case = 0;
+ } else {
+ usb_pause();
+ switch_app_case = 1;
+ }
+#elif (TCFG_USB_CDC_BACKGROUND_RUN)
+ usb_cdc_background_run();
+ switch_app_case = 0;
+
+#elif (TWFG_APP_POWERON_IGNORE_DEV == 0)
+ usb_pause();
+ switch_app_case = 1;
+
+#else
+ usb_pause();
+ switch_app_case = 1;
+#endif
+
+#endif
+ } else if (event->u.dev.event == DEVICE_EVENT_OUT) {
+ log_info("usb %c offline", usb_msg[2]);
+#if USB_PC_NO_APP_MODE
+ usb_stop();
+#else
+
+#ifdef CONFIG_SOUNDBOX
+ if (true == app_check_curr_task(APP_PC_TASK)) {
+#else
+ if (app_get_curr_task() == APP_PC_TASK) {
+#endif
+ switch_app_case = 2;
+ } else {
+ /* 此处的模式限制会在USB已连接,蓝牙播歌切换到蓝牙模式后再拔出USB的情况下,
+ 无法检测到再次插入USB */
+#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
+ mult_sdio_suspend();
+#endif
+ usb_stop();
+#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
+ mult_sdio_resume();
+#endif
+ }
+
+#endif
+ }
+ }
+
+ return switch_app_case;
+}
+
+#if USB_PC_NO_APP_MODE
+void usbstack_init()
+{
+ register_sys_event_handler(SYS_DEVICE_EVENT, DEVICE_EVENT_FROM_OTG, 2,
+ (void (*)(struct sys_event *))pc_device_event_handler);
+}
+
+void usbstack_exit()
+{
+ unregister_sys_event_handler((void (*)(struct sys_event *))pc_device_event_handler);
+}
+#endif
+
+#if (TCFG_OTG_MODE & OTG_DET_DM_ONLY)
+static void otg_sof_check_before_hook()
+{
+ log_debug("sof_check_before");
+#if ((TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE) \
+ && TCFG_CHARGESTORE_PORT == IO_PORT_DP)
+ power_wakeup_index_enable(2, 0);
+ chargestore_api_stop();
+#endif
+}
+
+static void otg_sof_check_after_hook()
+{
+ log_debug("sof_check_after");
+#if ((TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE) \
+ && TCFG_CHARGESTORE_PORT == IO_PORT_DP)
+ chargestore_api_restart();
+ power_wakeup_index_enable(2, 1);
+#endif
+}
+
+static int otg_sof_check_hook_register()
+{
+ //需要在otg定时器启动之前(即devices_init()之前)注册钩子函数
+ usb_otg_sof_check_register_hooks(otg_sof_check_before_hook,
+ otg_sof_check_after_hook);
+ return 0;
+}
+early_initcall(otg_sof_check_hook_register);
+#endif
+
+#endif
diff --git a/apps/common/device/usb/device/uac1.c b/apps/common/device/usb/device/uac1.c
new file mode 100644
index 0000000..d70f6e8
--- /dev/null
+++ b/apps/common/device/usb/device/uac1.c
@@ -0,0 +1,1401 @@
+/* Copyright(C) JieLi Technology
+ * usb audio 1.0
+ * All right reserved
+ *
+ */
+
+#include "system/includes.h"
+#include "usb_config.h"
+#include "usb/device/usb_stack.h"
+#include "usb/device/uac_audio.h"
+#include "app_config.h"
+
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+static u32 mic_samplingfrequency;
+/*********************************************************/
+/*
+ Audio Class
+*/
+/*********************************************************/
+///Standard Interface Association Descriptor
+static const u8 uac_audio_interface_association[] = {
+ USB_DT_INTERFACE_ASSOCIATION_SIZE, //Size of this descriptor in bytes: 8
+ USB_DT_INTERFACE_ASSOCIATION,//INTERFACE ASSOCIATION Descriptor
+ 0,//Interface number of the first interface that is associated with this function
+ 0,//Number of contiguous interfaces that are associated with this function.
+ USB_CLASS_AUDIO,//AUDIO_FUNCTION Function Class code
+ USB_SUBCLASS_AUDIOSTREAMING,//FUNCTION_SUBCLASS_UNDEFINED
+ PC_PROTOCOL_UNDEFINED,//AF_VERSION_02_00 Function Protocol code.
+ SPEAKER_STR_INDEX,//Index of a string descriptor that describes this interface.
+};
+static const u8 uac_ac_standard_interface_desc[] = {
+///standard interface AC descriptor(Interface 0, Alternate Setting 0)
+ USB_DT_INTERFACE_SIZE, //Length
+ USB_DT_INTERFACE, //DescriptorType:Inerface
+ 0x00, //InterfaceNum
+ 0x00, //AlternateSetting
+ 0x00, //NumEndpoint
+ USB_CLASS_AUDIO, //InterfaceClass:audio
+ USB_SUBCLASS_AUDIOCONTROL, //InterfaceSubClass:audio ctl
+ PC_PROTOCOL_UNDEFINED, //InterfaceProtocol
+ SPEAKER_STR_INDEX, //Interface String
+};
+
+static const u8 uac_spk_ac_interface[] = {
+///class-specific AC interface descriptor
+ 0x09, //Length
+ USB_DT_CS_INTERFACE, //DescriptorType:audio interface descriptor
+ UAC_HEADER, //DescriptorSubType:audio control header
+ 0x00, 0x01, //bcdADC:audio Device Class v1.00
+ 0x28, 0x00, //TotalLength of class-specific AC interface descriptors
+ 0x01, //InCollection:1 AudioStreaming interface
+ 0x02, //InterfaceNr(1) - AS #2 id AudioStreaming interface 1 belongs to this AudioControl interface
+ /* 0x03, //InterfaceNr(1) - AS #2 id AudioStreaming interface 1 belongs to this AudioControl interface */
+};
+static const u8 uac_audio_ac_interface[] = {
+///class-specific AC interface descriptor
+ 0x0a, //Length
+ USB_DT_CS_INTERFACE, //DescriptorType:audio interface descriptor
+ UAC_HEADER, //DescriptorSubType:audio control header
+ 0x00, 0x01, //bcdADC:audio Device Class v1.00
+ 0x47, 0x00, //TotalLength of class-specific AC interface descriptors
+ 0x02, //InCollection:1 AudioStreaming interface
+ 0x01, //InterfaceNr(1) - AS #2 id AudioStreaming interface 1 belongs to this AudioControl interface
+ 0x02, //InterfaceNr(1) - AS #2 id AudioStreaming interface 1 belongs to this AudioControl interface
+};
+
+
+static const u8 uac_spk_input_terminal_desc[] = {
+
+///USB USB Streaming IT(Speaker)
+ 0x0c, //Length
+ USB_DT_CS_INTERFACE, //DescriptorType:audio interface descriptor
+ UAC_INPUT_TERMINAL, //DescriptorSubType:Input Terminal
+ SPK_INPUT_TERMINAL_ID, //TerminalID
+ LOBYTE(UAC_TERMINAL_STREAMING), HIBYTE(UAC_TERMINAL_STREAMING), //TerminalType:USB Streaming
+ 0x00, //AssocTerminal
+ SPK_CHANNEL, //NrChannels:2 channel
+#if SPK_CHANNEL == 1
+ 0x04, 0x00, //Mono center front channel
+#else
+ 0x03, 0x00, //ChannelConfig:Left Front,Right Front,
+#endif
+ 0x00, //ChannelName String
+ 0x00, //Terminal String
+};
+///Audio Feature Unit Descriptor(Speaker)
+static const u8 uac_spk_feature_desc[] = {
+ 0x07 + (SPK_CHANNEL + 1) * 1, //Length
+ USB_DT_CS_INTERFACE, //DescriptorType:audio interface descriptor
+ UAC_FEATURE_UNIT, //DescriptorSubType:Audio Feature Unit
+ SPK_FEATURE_UNIT_ID, //UnitID
+ SPK_INPUT_TERMINAL_ID, //SourceID:1 #USB Streaming IT
+ 0x01, //ControlSize:1 byte
+ 0x01, //Controls:BIT[0……7]:Mute,Volume Bass Mid Treble......
+ 0x02, //left ch
+#if SPK_CHANNEL == 2
+ 0x02, //right ch
+#endif
+ 0x00, //Feature String
+};
+//SELECTOR_UNIT
+static const u8 uac_spk_selector_uint_desc[] = {
+ 0x7, // bLength 7
+ USB_DT_CS_INTERFACE,// bDescriptorType CS_INTERFACE (0x24)
+ UAC_SELECTOR_UNIT,// bDescriptorSubtype SELECTOR_UNIT (0x05)
+ SPK_SELECTOR_UNIT_ID,//bUnitID 33
+ 1,//bNrInPins 1
+ SPK_FEATURE_UNIT_ID, //baSourceID(1) 50
+ 0,//iSelector None (0)
+};
+static const u8 uac_spk_output_terminal_desc[] = {
+///USB Speaker OT
+ 0x09, //Length
+ USB_DT_CS_INTERFACE, //DescriptorType:audio interface descriptor
+ UAC_OUTPUT_TERMINAL, //DescriptorSubTYpe:Output Terminal
+ SPK_OUTPUT_TERMINAL_ID, //TerminalID
+ LOBYTE(UAC_OUTPUT_TERMINAL_SPEAKER), HIBYTE(UAC_OUTPUT_TERMINAL_SPEAKER), //TerminalType:Speaker
+ 0, //AssocTerminal:
+ //SPK_FEATURE_UNIT_ID, //SourceID: Feature UNIT
+ SPK_SELECTOR_UNIT_ID, //SourceID: Selector UNIT
+ 0x00, //Terminal String
+};
+
+static const u8 uac_spk_as_interface_desc[] = {
+//-------------------Speaker interface---------------------//
+///standard interface AS descriptor(Interface 1, Alternate Setting 0)
+ USB_DT_INTERFACE_SIZE, //Length
+ USB_DT_INTERFACE, //DescriptorType:Interface
+ 0x00, //InterfaceNum:2
+ 0x00, //AlternateSetting:0
+ 0x00, //NumEndpoint:0
+ USB_CLASS_AUDIO, //InterfaceClass:audio
+ USB_SUBCLASS_AUDIOSTREAMING, //InterfaceSubClass:audio streaming
+ PC_PROTOCOL_UNDEFINED, //InterfaceProtocol
+ 0x00, //Interface String
+
+///standard interface AS descriptor(Interface 2, Alternate Setting 1)
+ USB_DT_INTERFACE_SIZE, //Length
+ USB_DT_INTERFACE, //DescriptorType:Interface
+ 0x00, //InterfaceNum
+ 0x01, //AlternateSetting
+ 0x01, //NumEndpoint
+ USB_CLASS_AUDIO, //InterfaceClass:audio
+ USB_SUBCLASS_AUDIOSTREAMING, //InterfaceSubClass:audio streaming
+ PC_PROTOCOL_UNDEFINED, //InterfaceProtocol
+ 0x00, //Interface String
+
+///Audio Streaming Interface Descriptor:AS_GENERAL(0x01),
+ 0x07, //Length
+ USB_DT_CS_INTERFACE, //DescriptorType:audio interface descriptor
+ UAC_AS_GENERAL, //DescriptorSubType:AS_GENERAL
+ SPK_INPUT_TERMINAL_ID, //TerminalLink:#1 USB Streaming IT
+ 0x01, //Delay:1
+ (SPK_AUDIO_TYPE & 0xFF), (SPK_AUDIO_TYPE >> 8), //FormatTag:PCM
+
+///Type 1 Format type descriptor
+ 0x0b, //Length
+ USB_DT_CS_INTERFACE, //DescriptorType:audio interface descriptor
+ UAC_FORMAT_TYPE, //DescriptorSubType:Format_type
+ UAC_FORMAT_TYPE_I, //FormatType:Format type 1
+ SPK_CHANNEL, //NumberOfChannel
+ 0x02, //SubframeSize:2byte
+ SPK_AUDIO_RES, //BitsResolution:16bit
+ 0x01, //SampleFreqType:One sampling frequency.
+ DW1BYTE(SPK_AUDIO_RATE), DW2BYTE(SPK_AUDIO_RATE), DW3BYTE(SPK_AUDIO_RATE),
+
+//Isochronous,Synchronization Type(Asynchronous)
+ 0x09, //Length
+ USB_DT_ENDPOINT, //DescriptorType:endpoint descriptor
+ USB_DIR_OUT | SPK_ISO_EP_OUT, //EndpointAddress:Output endpoint 1
+ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE, //0x09,
+ LOBYTE(SPK_FRAME_LEN), HIBYTE(SPK_FRAME_LEN), //MaxPacketSize
+ UAC_ISO_INTERVAL,//one packet per frame 0x00, //Interval //Asynchronous
+ 0x00,//unused
+ 0x00,//unused
+
+//Audio Endpoint descriptor,General
+ 0x07, //Length
+ USB_DT_CS_ENDPOINT, //DescriptorType:audio endpoint descriptor
+ UAC_AS_GENERAL, //DescriptorSubType:audio endpiont general
+// 0x01, // bmAttributes (Sampling Freq Control)
+ 0x00, //Attributes
+ 0x00, //LockDelayUnits
+ 0x00, 0x00, //LockDelay
+};
+
+const u8 speakerStringDescriptor[20] = {
+ 20, //该描述符的长度为20字节
+ 0x03, //字符串描述符的类型编码为0x03
+ 'U', 0x00, //U
+ 'S', 0x00, //S
+ 'B', 0x00, //B
+ ' ', 0x00, //
+ 'A', 0x00, //A
+ 'u', 0x00, //u
+ 'd', 0x00, //d
+ 'i', 0x00, //i
+ 'o', 0x00, //o
+};
+/*********************************************************/
+/*
+ Microphone Class
+*/
+/*********************************************************/
+
+///Standard Interface Association Descriptor
+static const u8 uac_mic_interface_association[] = {
+ USB_DT_INTERFACE_ASSOCIATION_SIZE,//Size of this descriptor in bytes
+ USB_DT_INTERFACE_ASSOCIATION,//INTERFACE ASSOCIATION Descriptor
+ 2,//Interface number of the first interface that is associated with this function ****
+ 1,//Number of contiguous interfaces that are associated with this function.
+ USB_CLASS_AUDIO,//AUDIO_FUNCTION Function Class code
+ USB_SUBCLASS_AUDIOSTREAMING,//FUNCTION_SUBCLASS_UNDEFINED
+ PC_PROTOCOL_UNDEFINED,//AF_VERSION_02_00 Function Protocol code.
+ MIC_STR_INDEX,//Index of a string descriptor that describes this interface
+};
+static const u8 uac_mic_ac_interface[] = {
+///class-specific AC interface descriptor
+ 0x09, //Length
+ USB_DT_CS_INTERFACE, //DescriptorType
+ UAC_HEADER, //DescriptorSubType
+ 0x00, 0x01, //bcdADC
+ 0x27, 0x00, /*TotalLength of class-specific AC interface descriptors */
+ /* Includes the combined length */
+ /* of this descriptor header and all Unit and */
+ /* Terminal descriptors. */
+ 0x01, //InCollection:1 AudioStreaming interface
+ 0x01, //InterfaceNr(1) ****
+};
+///USB USB Streaming IT(Microphone)
+static const u8 uac_mic_input_terminal_desc[] = {
+ 0x0c, //Length
+ USB_DT_CS_INTERFACE, //DescriptorType:audio interface descriptor
+ UAC_INPUT_TERMINAL, //DescriptorSubType:Input Terminal
+ MIC_INPUT_TERMINAL_ID, //TerminalID
+ LOBYTE(UAC_INPUT_TERMINAL_MICROPHONE), HIBYTE(UAC_INPUT_TERMINAL_MICROPHONE), //TerminalType:Microphone
+ 0, //AssocTerminal
+ MIC_CHANNEL, //NrChannels
+#if MIC_CHANNEL == 2
+ 0x03, 0x00, //wChannelConfig:Left Front right Front
+#else
+ 0x00, 0x00, //wChannelConfig:
+#endif
+ 0x00, //ChannelName String
+ 0x00, //Terminal String
+};
+//SELECTOR_UNIT
+static const u8 uac_mic_selector_uint_desc[] = {
+ 0x7, // bLength 7
+ USB_DT_CS_INTERFACE,// bDescriptorType CS_INTERFACE (0x24)
+ UAC_SELECTOR_UNIT,// bDescriptorSubtype SELECTOR_UNIT (0x05)
+ MIC_SELECTOR_UNIT_ID,//bUnitID 33
+ 1,//bNrInPins 1
+ MIC_FEATURE_UNIT_ID, //baSourceID(1) 50
+ 0,//iSelector None (0)
+};
+
+///Audio Feature Unit Descriptor(Microphone)
+static const u8 uac_mic_feature_desc[] = {
+ 7 + (MIC_CHANNEL + 1) * 1, //Length
+ USB_DT_CS_INTERFACE, //DescriptorType:audio interface descriptor
+ UAC_FEATURE_UNIT, //DescriptorSubType:Audio Feature Unit
+ MIC_FEATURE_UNIT_ID, //UnitID
+ MIC_INPUT_TERMINAL_ID, //SourceID: #Microphone
+ 0x01, //ControlSize:1 byte
+ 0x43, 0x00, // bmaControls[0] (Mute,Volume,Automatic)
+#if MIC_CHANNEL == 2
+ 0x00,
+#endif
+ 0x00, //Feature String
+};
+///USB Microphone OT
+static const u8 uac_mic_output_terminal_desc[] = {
+ 0x09, //Length
+ USB_DT_CS_INTERFACE, //DescriptorType:audio interface descriptor
+ UAC_OUTPUT_TERMINAL, //DescriptorSubTYpe:Output Terminal
+ MIC_OUTPUT_TERMINAL_ID, //TerminalID
+ LOBYTE(UAC_TERMINAL_STREAMING), HIBYTE(UAC_TERMINAL_STREAMING), //TerminalType:USB Sreaming
+ 2, //AssocTerminal:
+ MIC_SELECTOR_UNIT_ID, //SourceID:A #Feature UNIT
+ 0x00, //Terminal String
+};
+
+///standard interface AS descriptor(Interface 1, Alternate Setting 0)
+static const u8 uac_mic_as_interface_desc[] = {
+ USB_DT_INTERFACE_SIZE, //Length
+ USB_DT_INTERFACE, //DescriptorType:Interface
+ 0x03, //InterfaceNum ****
+ 0x00, //AlternateSetting
+ 0x00, //NumEndpoint
+ USB_CLASS_AUDIO, //InterfaceClass:audio
+ USB_SUBCLASS_AUDIOSTREAMING, //InterfaceSubClass:audio streaming
+ 0x00, //InterfaceProtocol
+ 0x00, //Interface String
+
+///standard interface AS descriptor(Interface 2, Alternate Setting 1)
+ USB_DT_INTERFACE_SIZE, //Length
+ USB_DT_INTERFACE, //DescriptorType:Interface
+ 0x02, //InterfaceNum ****
+ 0x01, //AlternateSetting
+ 0x01, //NumEndpoint
+ USB_CLASS_AUDIO, //InterfaceClass:audio
+ USB_SUBCLASS_AUDIOSTREAMING, //InterfaceSubClass:audio streaming
+ 0x00, //InterfaceProtocol
+ 0x00, //Interface String
+
+///Audio Streaming Interface Descriptor:AS_GENERAL
+ 0x07, //Length
+ USB_DT_CS_INTERFACE, //DescriptorType:audio interface descriptor
+ UAC_AS_GENERAL, //DescriptorSubType:AS_GENERAL
+ MIC_OUTPUT_TERMINAL_ID, //TerminalLink:#1 USB Streaming OT
+ 0x01, //Delay:1
+ (MIC_AUDIO_TYPE & 0xFF), (MIC_AUDIO_TYPE >> 8), //FormatTag:PCM
+
+///Type 1 Format type descriptor
+ 0x08 + 3 * (MIC_SamplingFrequency), //Length
+ USB_DT_CS_INTERFACE, //DescriptorType:audio interface descriptor
+ UAC_FORMAT_TYPE, //DescriptorSubType:Format_type
+ UAC_FORMAT_TYPE_I_PCM, //FormatType:Format type 1
+ MIC_CHANNEL, //NumberOfChannel:1
+ MIC_AUDIO_RES / 8, //SubframeSize:2byte
+ MIC_AUDIO_RES, //BitsResolution:16bit
+#if MIC_SamplingFrequency > 1
+ MIC_SamplingFrequency,
+ DW1BYTE(MIC_AUDIO_RATE_1), DW2BYTE(MIC_AUDIO_RATE_1), DW3BYTE(MIC_AUDIO_RATE_1),
+ DW1BYTE(MIC_AUDIO_RATE_2), DW2BYTE(MIC_AUDIO_RATE_2), DW3BYTE(MIC_AUDIO_RATE_2),
+ DW1BYTE(MIC_AUDIO_RATE), DW2BYTE(MIC_AUDIO_RATE), DW3BYTE(MIC_AUDIO_RATE),
+ DW1BYTE(MIC_AUDIO_RATE_4), DW2BYTE(MIC_AUDIO_RATE_4), DW3BYTE(MIC_AUDIO_RATE_4),
+#else
+ 0x01, //SampleFreqType:One sampling frequency.
+ DW1BYTE(MIC_AUDIO_RATE), DW2BYTE(MIC_AUDIO_RATE), DW3BYTE(MIC_AUDIO_RATE),
+#endif
+
+///Endpoint 1 - Standard Descriptor:Output Endpoint1
+//Isochronous,Synchronization Type(Asynchronous)
+ USB_DT_ENDPOINT_AUDIO_SIZE, //Length
+ USB_DT_ENDPOINT, //DescriptorType:endpoint descriptor
+ USB_DIR_IN | MIC_ISO_EP_IN, //EndpointAddress:Output endpoint
+ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ LOBYTE(MIC_FRAME_LEN), HIBYTE(MIC_FRAME_LEN), //MaxPacketSize
+ UAC_ISO_INTERVAL,//one packet per frame //Interval
+ 0x00,//unused
+ 0x00,//unused
+
+///Endpoint - Audio Streaming Descriptor
+//Audio Endpoint descriptor,General
+ 0x07, //Length
+ USB_DT_CS_ENDPOINT, //DescriptorType:audio endpoint descriptor
+ UAC_AS_GENERAL, //DescriptorSubType:audio endpiont general
+#if MIC_SamplingFrequency > 1
+ 0x01, // bmAttributes (Sampling Freq Control)
+#else
+ 0x00, //Attributes
+#endif
+
+ 0x00, //LockDelayUnits
+ 0x00, 0x00, //LockDelay
+};
+static const u8 micStringDescriptor[30] = {
+ 30, //该描述符的长度为30字节
+ 0x03, //字符串描述符的类型编码为0x03
+ 'U', 0x00, //U
+ 'S', 0x00, //S
+ 'B', 0x00, //B
+ ' ', 0x00, //
+ 'M', 0x00, //M
+ 'i', 0x00, //i
+ 'c', 0x00, //c
+ 'r', 0x00, //r
+ 'o', 0x00, //o
+ 'p', 0x00, //p
+ 'h', 0x00, //h
+ 'o', 0x00, //o
+ 'n', 0x00, //n
+ 'e', 0x00, //e
+};
+
+const u8 *uac_get_string(u32 id)
+{
+ if (id == SPEAKER_STR_INDEX) {
+ return speakerStringDescriptor;
+ } else if (id == MIC_STR_INDEX) {
+ return micStringDescriptor;
+ }
+ return NULL;
+}
+struct uac_info_t {
+ u16 spk_left_vol;
+ u16 spk_right_vol;
+ u16 spk_max_vol;
+ u16 spk_min_vol;
+ u16 spk_def_vol;
+ u16 spk_vol_res;
+ u8 *spk_dma_buffer;
+
+ u16 mic_max_vol;
+ u16 mic_min_vol;
+ u16 mic_def_vol;
+ u16 mic_vol_res;
+ u16 mic_vol;
+ u8 *mic_dma_buffer;
+
+ u8 spk_mute: 1;
+ u8 mic_mute: 1;
+ u8 bAGC: 1;
+ u8 ps4_mode: 1;
+ u8 res: 4;
+};
+
+
+struct uac_info_t *uac_info;
+#if USB_MALLOC_ENABLE
+#else
+struct uac_info_t _uac_info SEC(.uac_var);
+#endif
+
+static u32 vol_convert(u16 v)
+{
+ const u16 vol_table[] = {
+ 0xe3a0, 0xe461, 0xe519, 0xe5c8, 0xe670, 0xe711, 0xe7ac, 0xe840, 0xe8cf, 0xe959,
+ 0xe9df, 0xea60, 0xeadc, 0xeb55, 0xebca, 0xec3c, 0xecab, 0xed16, 0xed7f, 0xede5,
+ 0xee48, 0xeea9, 0xef08, 0xef64, 0xefbe, 0xf016, 0xf06c, 0xf0c0, 0xf113, 0xf164,
+ 0xf1b3, 0xf200, 0xf24c, 0xf297, 0xf2e0, 0xf328, 0xf36e, 0xf3b4, 0xf3f8, 0xf43a,
+ 0xf47c, 0xf4bd, 0xf4fc, 0xf53b, 0xf579, 0xf5b5, 0xf5f1, 0xf62c, 0xf666, 0xf69f,
+ 0xf6d7, 0xf70e, 0xf745, 0xf77b, 0xf7b0, 0xf7e5, 0xf818, 0xf84b, 0xf87e, 0xf8b0,
+ 0xf8e1, 0xf911, 0xf941, 0xf970, 0xf99f, 0xf9cd, 0xf9fb, 0xfa28, 0xfa55, 0xfa81,
+ 0xfaad, 0xfad8, 0xfb03, 0xfb2d, 0xfb56, 0xfb80, 0xfba9, 0xfbd1, 0xfbf9, 0xfc21,
+ 0xfc48, 0xfc6f, 0xfc95, 0xfcbb, 0xfce1, 0xfd06, 0xfd2b, 0xfd50, 0xfd74, 0xfd98,
+ 0xfdbc, 0xfddf, 0xfe02, 0xfe25, 0xfe47, 0xfe69, 0xfe8b, 0xfead, 0xfece, 0xfeef,
+ 0xff0f,
+ };
+
+ if (v <= 100) {
+ return vol_table[v];
+ }
+
+ for (int i = 0; i < sizeof(vol_table) / 2; i++) {
+ if (v <= vol_table[i]) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+void uac_get_cur_vol(const usb_dev usb_id, u16 *l_vol, u16 *r_vol)
+{
+ if (l_vol) {
+ *l_vol = 0;
+ }
+ if (r_vol) {
+ *r_vol = 0;
+ }
+ if (uac_info) {
+ if (!uac_info->spk_mute) {
+ if (l_vol) {
+ *l_vol = vol_convert(uac_info->spk_left_vol);
+ }
+ if (r_vol) {
+ *r_vol = vol_convert(uac_info->spk_right_vol);
+ }
+ }
+ }
+}
+u16 uac_get_mic_vol(const usb_dev usb_id)
+{
+ if (uac_info) {
+ if (!uac_info->mic_mute) {
+ return vol_convert(uac_info->mic_vol);
+ }
+ }
+ return 0;
+}
+
+u16 uac_get_mic_sameplerate(void *priv)
+{
+ u16 sample_rate = (u16)mic_samplingfrequency;
+ return sample_rate;
+}
+
+static u32 uac_vol_handler(struct usb_device_t *usb_device, struct usb_ctrlrequest *setup)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ u32 ret = 0;
+ u8 read_ep[8];
+ u8 mute;
+ u16 volume = 0;
+ usb_read_ep0(usb_id, read_ep, setup->wLength);
+ ret = USB_EP0_STAGE_SETUP;
+ switch (HIBYTE(setup->wValue)) {
+ case UAC_FU_MUTE:
+ if (HIBYTE(setup->wIndex) == SPK_FEATURE_UNIT_ID) {
+ memcpy((u8 *)&mute, read_ep, 1);
+ if (mute) {
+ uac_mute_volume(SPK_FEATURE_UNIT_ID, 0, 0);
+ uac_info->spk_mute = 1;
+ } else {
+ uac_mute_volume(SPK_FEATURE_UNIT_ID,
+ vol_convert(uac_info->spk_left_vol),
+ vol_convert(uac_info->spk_right_vol));
+ uac_info->spk_mute = 0;
+ }
+ } else if (HIBYTE(setup->wIndex) == MIC_FEATURE_UNIT_ID) {
+ memcpy((u8 *)&mute, read_ep, 1);
+ if (mute) {
+ uac_mute_volume(MIC_FEATURE_UNIT_ID, 0, 0);
+ uac_info->mic_mute = 1;
+ } else {
+ uac_mute_volume(MIC_FEATURE_UNIT_ID, vol_convert(uac_info->mic_vol), 0);
+ uac_info->mic_mute = 0;
+ }
+ }
+ break;
+ case UAC_FU_VOLUME:
+ if (HIBYTE(setup->wIndex) == SPK_FEATURE_UNIT_ID) {
+ memcpy((u8 *)&volume, read_ep, setup->wLength);
+ if (LOBYTE(setup->wValue) == 1) {
+ uac_info->spk_left_vol = volume;
+ } else if (LOBYTE(setup->wValue) == 2) {
+ uac_info->spk_right_vol = volume;
+ }
+ if (uac_info->ps4_mode) {
+ uac_info->spk_left_vol = vol_convert(100);
+ uac_info->spk_right_vol = vol_convert(100);
+ }
+ if (!uac_info->spk_mute && !uac_info->ps4_mode) {
+ uac_mute_volume(SPK_FEATURE_UNIT_ID,
+ vol_convert(uac_info->spk_left_vol),
+ vol_convert(uac_info->spk_right_vol));
+ }
+ } else if (HIBYTE(setup->wIndex) == MIC_FEATURE_UNIT_ID) {
+ memcpy((u8 *)&uac_info->mic_vol, read_ep, sizeof(uac_info->mic_vol));
+ /* if (uac_info->mic_vol == 0x8000) { */
+ /* uac_info->mic_vol = 0; */
+ /* } else if (uac_info->mic_vol >= 100) { */
+ /* uac_info->mic_vol = 99; */
+ /* } */
+ if (!uac_info->mic_mute) {
+ uac_mute_volume(MIC_FEATURE_UNIT_ID, vol_convert(uac_info->mic_vol), 0);
+ }
+ }
+ break;
+ case UAC_FU_AUTOMATIC_GAIN:
+ if (read_ep[0]) {
+ uac_info->bAGC = 1;
+ } else {
+ uac_info->bAGC = 0;
+ }
+ break;
+
+ case 0: //bSelectorUnitID
+ if (HIBYTE(setup->wIndex) == SPK_SELECTOR_UNIT_ID) {
+ uac_info->ps4_mode = read_ep[0];
+ if (read_ep[0]) {
+ printf("SPK_FEATURE_UNIT_ID");
+ uac_info->spk_left_vol = vol_convert(100);
+ uac_info->spk_right_vol = vol_convert(100);
+ uac_mute_volume(SPK_FEATURE_UNIT_ID, 100, 100);
+ }
+ }
+ break;
+
+ default :
+ ret = USB_EP0_SET_STALL;
+ break;
+ }
+
+ return ret;
+}
+#if USB_ROOT2
+static u8 SetInterface_0_Lock;
+#endif
+static u32 uac_endpoint_recv(struct usb_device_t *usb_device, struct usb_ctrlrequest *setup)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ u32 ret = 0;
+ u8 read_ep[8];
+
+ usb_read_ep0(usb_id, read_ep, setup->wLength);
+
+ ret = USB_EP0_STAGE_SETUP;
+ u32 ep = LOBYTE(setup->wIndex);
+ switch (ep) {
+ case MIC_ISO_EP_IN|USB_DIR_IN:
+ memcpy(&mic_samplingfrequency, read_ep, 3);
+ break;
+ case SPK_ISO_EP_OUT|USB_DIR_OUT:
+ /* memcpy(&spk_samplingfrequency,read_ep,3); */
+ break;
+ }
+ return ret;
+}
+u32 uac_setup_endpoint(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
+{
+ u32 ret = 0;
+ const usb_dev usb_id = usb_device2id(usb_device);
+ u8 type = req->bRequestType & USB_TYPE_MASK;
+ if (type != USB_TYPE_CLASS) {
+ return ret;
+ }
+ if (req->bRequest != 0x01) {
+ return ret;
+ }
+ if (req->wValue != 0x0100) {
+ return ret;
+ }
+ usb_set_setup_recv(usb_device, uac_endpoint_recv);
+ return 1;
+}
+static u32 audio_ac_itf_handler(struct usb_device_t *usb_device, struct usb_ctrlrequest *setup)
+{
+ u8 mute;
+
+ const usb_dev usb_id = usb_device2id(usb_device);
+ u32 tx_len;
+ u8 *tx_payload = usb_get_setup_buffer(usb_device);
+ u32 bRequestType = setup->bRequestType & USB_TYPE_MASK;
+ u32 ret = 0;
+ switch (setup->bRequest) {
+ case USB_REQ_SET_INTERFACE:
+#if USB_ROOT2
+ SetInterface_0_Lock = 1;
+ if (usb_device->bDeviceStates == USB_DEFAULT) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_CONFIGURED) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);//no alt setting
+ }
+#else
+ if (setup->wValue == 0) { //alt 0
+ usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
+ } else {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ }
+#endif
+ break;
+ case USB_REQ_GET_INTERFACE:
+#if USB_ROOT2
+ if (usb_root2_testing()) {
+ SetInterface_0_Lock = 0;
+ }
+#endif
+ if (setup->wValue || (setup->wLength != 1)) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_DEFAULT) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_CONFIGURED) {
+ tx_len = 1;
+ tx_payload[0] = 0x00;
+ usb_set_data_payload(usb_device, setup, tx_payload, tx_len);
+ }
+ break;
+ case UAC_SET_CUR:
+ /* USB_DEBUG_PRINTF("set vol && mute"); */
+ usb_set_setup_recv(usb_device, uac_vol_handler);
+ break;
+ case UAC_GET_CUR:
+ switch (HIBYTE(setup->wValue)) {
+ case UAC_FU_MUTE:
+ if (HIBYTE(setup->wIndex) == SPK_FEATURE_UNIT_ID) {
+ mute = uac_info->spk_mute ;
+ } else if (HIBYTE(setup->wIndex) == MIC_FEATURE_UNIT_ID) {
+ mute = uac_info->mic_mute ;
+ }
+ tx_payload = &mute;
+ tx_len = setup->wLength;
+ usb_set_data_payload(usb_device, setup, tx_payload, tx_len);
+ break;
+
+ case UAC_FU_VOLUME:
+ if (HIBYTE(setup->wIndex) == SPK_FEATURE_UNIT_ID) {
+ if (LOBYTE(setup->wValue) == 1) {
+ tx_payload = (u8 *)&uac_info->spk_left_vol;
+ } else if (LOBYTE(setup->wValue) == 2) {
+ tx_payload = (u8 *)&uac_info->spk_right_vol;
+ }
+ } else if (HIBYTE(setup->wIndex) == MIC_FEATURE_UNIT_ID) {
+ tx_payload = (u8 *)&uac_info->mic_vol;
+ }
+ tx_len = setup->wLength;
+ usb_set_data_payload(usb_device, setup, tx_payload, tx_len);
+ break;
+ case UAC_FU_AUTOMATIC_GAIN:
+ if (uac_info->bAGC) {
+ tx_payload[0] = 0x01;
+ } else {
+ tx_payload[0] = 0x00;
+ }
+ tx_len = setup->wLength;
+ usb_set_data_payload(usb_device, setup, tx_payload, tx_len);
+ break;
+ }
+ break;
+ case UAC_GET_DEF:
+ if (HIBYTE(setup->wIndex) == SPK_FEATURE_UNIT_ID) {
+ tx_payload = (u8 *)&uac_info->spk_def_vol;
+ } else if (HIBYTE(setup->wIndex) == MIC_FEATURE_UNIT_ID) {
+ tx_payload = (u8 *)&uac_info->mic_def_vol;
+ }
+ tx_len = setup->wLength;
+ usb_set_data_payload(usb_device, setup, tx_payload, tx_len);
+ break;
+ case UAC_GET_MAX:
+ if (HIBYTE(setup->wIndex) == SPK_FEATURE_UNIT_ID) {
+ tx_payload = (u8 *)&uac_info->spk_max_vol;
+ } else if (HIBYTE(setup->wIndex) == MIC_FEATURE_UNIT_ID) {
+ tx_payload = (u8 *)&uac_info->mic_max_vol;
+ }
+ tx_len = setup->wLength;
+ usb_set_data_payload(usb_device, setup, tx_payload, tx_len);
+ break;
+ case UAC_GET_MIN:
+ if (HIBYTE(setup->wIndex) == SPK_FEATURE_UNIT_ID) {
+ tx_payload = (u8 *)&uac_info->spk_min_vol;
+ } else if (HIBYTE(setup->wIndex) == MIC_FEATURE_UNIT_ID) {
+ tx_payload = (u8 *)&uac_info->mic_min_vol;
+ }
+ tx_len = setup->wLength;
+ usb_set_data_payload(usb_device, setup, tx_payload, tx_len);
+ break;
+ case UAC_GET_RES:
+ if (HIBYTE(setup->wIndex) == SPK_FEATURE_UNIT_ID) {
+ tx_payload = (u8 *)&uac_info->spk_vol_res;
+ } else if (HIBYTE(setup->wIndex) == MIC_FEATURE_UNIT_ID) {
+ tx_payload = (u8 *)&uac_info->mic_vol_res;
+ }
+ tx_len = setup->wLength;
+ usb_set_data_payload(usb_device, setup, tx_payload, tx_len);
+ break;
+ case UAC_GET_LEN:
+ break;
+ case UAC_GET_INFO:
+ break;
+ case USB_REQ_GET_STATUS:
+ if (usb_device->bDeviceStates == USB_DEFAULT) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ }
+ break;
+ default:
+ ret = 1 ;
+ break;
+ }
+ return ret;
+}
+#define UAC_PLC_EN 0
+#if UAC_PLC_EN
+typedef struct _USBAUDIO_PLC_API {
+ unsigned int (*need_buf)();
+ void (*open)(unsigned char *ptr, int sr, int nch);
+ int (*run)(unsigned char *ptr, short *inbuf, short *oubuf, short len, short err_flag);
+} USBAUDIO_PLC_API;
+
+extern USBAUDIO_PLC_API *get_USBplc_api();
+
+static USBAUDIO_PLC_API *uac_plc_api = 0;
+static u8 *uac_plc_buffer;
+
+void usb_audio_plc_open()
+{
+ uac_plc_api = get_USBplc_api();
+ u32 bufsize = uac_plc_api->need_buf();
+ uac_plc_buffer = malloc(bufsize);
+ uac_plc_api->open(uac_plc_buffer, SPK_AUDIO_RATE, SPK_CHANNEL);
+}
+void usb_audio_plc_close()
+{
+ if (uac_plc_api) {
+ uac_plc_api = NULL;
+ }
+ if (uac_plc_buffer) {
+ free(uac_plc_buffer);
+ uac_plc_buffer = NULL;
+ }
+}
+#endif
+
+static void spk_transfer(struct usb_device_t *usb_device, u32 ep)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ u8 *ep_buffer = uac_info->spk_dma_buffer;
+ u32 spk_frame_len = SPK_AUDIO_RATE * (SPK_AUDIO_RES / 8) * SPK_CHANNEL / 1000;
+ spk_frame_len += (SPK_AUDIO_RATE % 1000 ? (SPK_AUDIO_RES / 8) * SPK_CHANNEL : 0);
+ u32 rx_len = usb_g_iso_read(usb_id, SPK_ISO_EP_OUT, NULL, spk_frame_len, 0);
+
+#if UAC_PLC_EN
+ if (rx_len) {
+ uac_plc_api->run(uac_plc_buffer, ep_buffer, ep_buffer, rx_len, 0);
+ } else {
+ uac_plc_api->run(uac_plc_buffer, ep_buffer, ep_buffer, rx_len, 1);
+ }
+#endif
+
+ uac_speaker_stream_write(ep_buffer, rx_len);
+}
+static void open_spk(struct usb_device_t *usb_device)
+{
+ log_info("%s", __func__);
+ const usb_dev usb_id = usb_device2id(usb_device);
+ u32 spk_frame_len = SPK_AUDIO_RATE * (SPK_AUDIO_RES / 8) * SPK_CHANNEL / 1000;
+ spk_frame_len += (SPK_AUDIO_RATE % 1000 ? (SPK_AUDIO_RES / 8) * SPK_CHANNEL : 0);
+ u8 *ep_buffer = uac_info->spk_dma_buffer;
+ uac_speaker_stream_open(SPK_AUDIO_RATE, SPK_CHANNEL);
+
+#if UAC_PLC_EN
+ usb_audio_plc_open();
+#endif
+
+ usb_g_set_intr_hander(usb_id, SPK_ISO_EP_OUT | USB_DIR_OUT, spk_transfer);
+
+ usb_g_ep_config(usb_id, SPK_ISO_EP_OUT | USB_DIR_OUT, USB_ENDPOINT_XFER_ISOC, 1, ep_buffer, spk_frame_len);
+}
+static void close_spk(struct usb_device_t *usb_device)
+{
+ log_info("%s", __func__);
+ const usb_dev usb_id = usb_device2id(usb_device);
+ usb_clr_intr_rxe(usb_id, SPK_ISO_EP_OUT);
+ usb_g_set_intr_hander(usb_id, SPK_ISO_EP_OUT, NULL);
+
+#if UAC_PLC_EN
+ usb_audio_plc_close();
+#endif
+
+ uac_speaker_stream_close();
+
+}
+static u8 spk_itf_status;
+static u32 spk_as_itf_hander(struct usb_device_t *usb_device, struct usb_ctrlrequest *setup)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ u32 tx_len;
+ u8 *tx_payload = usb_get_setup_buffer(usb_device);
+ u32 bRequestType = setup->bRequestType & USB_TYPE_MASK;
+ u32 ret = 0;
+
+ switch (setup->bRequest) {
+ case USB_REQ_SET_INTERFACE:
+ if (usb_device->bDeviceStates == USB_DEFAULT) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_CONFIGURED) {
+#if USB_ROOT2
+ if (!usb_root2_testing()) {
+ SetInterface_0_Lock = 1;
+ }
+ if (SetInterface_0_Lock == 0) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else {
+ usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
+ if (setup->wValue == 1) { //alt 1
+ open_spk(usb_device);
+ } else if (setup->wValue == 0) { //alt 0
+ close_spk(usb_device);
+ } else {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ }
+ }
+#else
+ usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
+ if (setup->wValue == 1) { //alt 1
+ open_spk(usb_device);
+ spk_itf_status = 1;
+ } else if (setup->wValue == 0) { //alt 0
+ close_spk(usb_device);
+ spk_itf_status = 0;
+ } else {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ }
+#endif
+ }
+
+ break;
+ case USB_REQ_GET_INTERFACE:
+ if (usb_root2_testing()) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else {
+ if (setup->wValue || (setup->wLength != 1)) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_DEFAULT) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_CONFIGURED) {
+ tx_len = 1;
+ tx_payload[0] = spk_itf_status;
+ usb_set_data_payload(usb_device, setup, tx_payload, tx_len);
+ }
+ }
+ break;
+ case USB_REQ_GET_STATUS:
+ if (usb_device->bDeviceStates == USB_DEFAULT) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ }
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+static u8 mic_no_data;
+static void mic_transfer(struct usb_device_t *usb_device, u32 ep)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ u8 *ep_buffer = uac_info->mic_dma_buffer;
+
+ if (mic_samplingfrequency == 0) {
+ mic_samplingfrequency = MIC_AUDIO_RATE;
+ }
+
+ u32 mic_frame_len = ((mic_samplingfrequency * MIC_AUDIO_RES / 8 * MIC_CHANNEL) / 1000);
+ mic_frame_len += (mic_samplingfrequency % 1000 ? (MIC_AUDIO_RES / 8) * MIC_CHANNEL : 0);
+
+ int len = uac_mic_stream_read(ep_buffer, mic_frame_len);
+ if (len) {
+ mic_no_data = 0;
+ } else if (mic_no_data) {
+ len = mic_frame_len;
+ memset(ep_buffer, 0, len);
+ }
+
+ usb_g_iso_write(usb_id, MIC_ISO_EP_IN, NULL, len);
+
+}
+static void open_mic(struct usb_device_t *usb_device)
+{
+ log_info("%s", __func__);
+ mic_no_data = 1;
+ const usb_dev usb_id = usb_device2id(usb_device);
+
+ usb_enable_ep(usb_id, MIC_ISO_EP_IN);
+
+ u8 *ep_buffer = uac_info->mic_dma_buffer;
+
+ usb_g_set_intr_hander(usb_id, MIC_ISO_EP_IN | USB_DIR_IN, mic_transfer);
+
+ if (mic_samplingfrequency == 0) {
+ mic_samplingfrequency = MIC_AUDIO_RATE;
+ }
+ u32 mic_frame_len = ((mic_samplingfrequency * MIC_AUDIO_RES / 8 * MIC_CHANNEL) / 1000);
+ mic_frame_len += (mic_samplingfrequency % 1000 ? (MIC_AUDIO_RES / 8) * MIC_CHANNEL : 0);
+
+ uac_mic_stream_open(mic_samplingfrequency, mic_frame_len, MIC_CHANNEL);
+
+ usb_g_ep_config(usb_id,
+ MIC_ISO_EP_IN | USB_DIR_IN,
+ USB_ENDPOINT_XFER_ISOC,
+ 1, ep_buffer, mic_frame_len);
+
+ mic_transfer(usb_device, MIC_ISO_EP_IN);
+}
+static void close_mic(struct usb_device_t *usb_device)
+{
+ log_info("%s", __func__);
+ const usb_dev usb_id = usb_device2id(usb_device);
+ usb_clr_intr_txe(usb_id, MIC_ISO_EP_IN);
+ usb_g_set_intr_hander(usb_id, MIC_ISO_EP_IN | USB_DIR_IN, NULL);
+ uac_mic_stream_close();
+}
+static u8 mic_itf_status;
+static u32 mic_as_itf_hander(struct usb_device_t *usb_device, struct usb_ctrlrequest *setup)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ u8 *tx_payload = usb_get_setup_buffer(usb_device);
+ u32 tx_len;
+ u32 bRequestType = setup->bRequestType & USB_TYPE_MASK;
+ u32 ret = 0;
+
+ switch (setup->bRequest) {
+ case USB_REQ_SET_INTERFACE:
+ if (usb_device->bDeviceStates == USB_DEFAULT) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_CONFIGURED) {
+#if USB_ROOT2
+ if (!usb_root2_testing()) {
+ SetInterface_0_Lock = 1;
+ }
+ if (SetInterface_0_Lock == 0) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else {
+ usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
+ if (setup->wValue == 1) {//alt 1
+ open_mic(usb_device);
+ } else if (setup->wValue == 0) { //alt 0
+ close_mic(usb_device);
+ } else {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ }
+ }
+#else
+ usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
+ if (setup->wValue == 1) {//alt 1
+ open_mic(usb_device);
+ mic_itf_status = 1;
+ } else if (setup->wValue == 0) { //alt 0
+ close_mic(usb_device);
+ mic_itf_status = 0;
+ } else {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ }
+#endif
+ }
+ break;
+ case USB_REQ_GET_INTERFACE:
+ if (usb_root2_testing()) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else {
+ if (setup->wValue || (setup->wLength != 1)) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_DEFAULT) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_CONFIGURED) {
+ tx_len = 1;
+ tx_payload[0] = mic_itf_status;
+ usb_set_data_payload(usb_device, setup, tx_payload, tx_len);
+ }
+ }
+ break;
+ case USB_REQ_GET_STATUS:
+ if (usb_device->bDeviceStates == USB_DEFAULT) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ } else {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ }
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+void spk_reset(struct usb_device_t *usb_device, u32 ift_num)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ log_debug("%s", __func__);
+ u8 *ep_buffer = uac_info->spk_dma_buffer;
+ usb_g_ep_config(usb_id, SPK_ISO_EP_OUT | USB_DIR_OUT, USB_ENDPOINT_XFER_ISOC, 1, ep_buffer, SPK_FRAME_LEN);
+}
+u32 uac_spk_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num)
+{
+ int i = 0;
+ u8 *tptr = ptr;
+ u32 offset;
+ u32 frame_len;
+
+ log_debug("spkdc:%d\n", *cur_itf_num);
+ memcpy(tptr, (u8 *)uac_ac_standard_interface_desc, sizeof(uac_ac_standard_interface_desc));
+ tptr[2] = *cur_itf_num;
+ tptr += sizeof(uac_ac_standard_interface_desc);//0x09
+
+ memcpy(tptr, (u8 *)uac_spk_ac_interface, sizeof(uac_spk_ac_interface));
+ tptr[5] += 7; //spk selector unit
+#if SPK_CHANNEL == 1
+ tptr[5]--;
+#endif
+ tptr[8] = *cur_itf_num + 1;
+ tptr += sizeof(uac_spk_ac_interface);//0x09
+
+ memcpy(tptr, (u8 *)uac_spk_input_terminal_desc, sizeof(uac_spk_input_terminal_desc));
+ tptr += sizeof(uac_spk_input_terminal_desc);//0x0c
+
+ memcpy(tptr, (u8 *)uac_spk_feature_desc, sizeof(uac_spk_feature_desc));
+ tptr += sizeof(uac_spk_feature_desc);//0x0a
+
+ memcpy(tptr, (u8 *)uac_spk_selector_uint_desc, sizeof(uac_spk_selector_uint_desc));
+ tptr += sizeof(uac_spk_selector_uint_desc);
+
+ memcpy(tptr, (u8 *)uac_spk_output_terminal_desc, sizeof(uac_spk_output_terminal_desc));
+ tptr += sizeof(uac_spk_output_terminal_desc);//0x09
+
+ memcpy(tptr, (u8 *)uac_spk_as_interface_desc, sizeof(uac_spk_as_interface_desc));
+ tptr[2] = *cur_itf_num + 1;
+ tptr[9 + 2] = *cur_itf_num + 1;
+ frame_len = SPK_AUDIO_RATE * (SPK_AUDIO_RES / 8) * SPK_CHANNEL / 1000;
+ frame_len += (SPK_AUDIO_RATE % 1000 ? (SPK_AUDIO_RES / 8) * SPK_CHANNEL : 0);
+ offset = 9 + 9 + 7 + 11 + 4;
+ //MaxPacketSize of spk iso out
+ tptr[offset] = LOBYTE(frame_len);
+ tptr[offset + 1] = HIBYTE(frame_len);
+ tptr += sizeof(uac_spk_as_interface_desc);//0x09+0x09+0x07+0x0b+0x09+0x07
+
+ if (usb_set_interface_hander(usb_id, *cur_itf_num, audio_ac_itf_handler) != *cur_itf_num) {
+ ASSERT(0, "uac spk set interface_hander fail");
+ }
+ if (usb_set_reset_hander(usb_id, *cur_itf_num, spk_reset) != *cur_itf_num) {
+
+ }
+ (*cur_itf_num) ++;
+ if (usb_set_interface_hander(usb_id, *cur_itf_num, spk_as_itf_hander) != *cur_itf_num) {
+ ASSERT(0, "uac spk set interface_hander fail");
+ }
+
+ (*cur_itf_num) ++;
+
+ i = tptr - ptr;
+ return i;
+}
+void mic_reset(struct usb_device_t *usb_device, u32 ift_num)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ log_error("%s", __func__);
+#if USB_ROOT2
+ usb_disable_ep(usb_id, SPK_ISO_EP_OUT);
+ /* uac_release(usb_id); */
+#else
+ u8 *ep_buffer = uac_info->mic_dma_buffer;
+ usb_g_ep_config(usb_id, MIC_ISO_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_ISOC, 1, ep_buffer, MIC_FRAME_LEN);
+#endif
+}
+u32 uac_mic_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num)
+{
+ int i = 0;
+ u8 *tptr = ptr;
+ u32 offset;
+ u32 frame_len;
+
+ log_debug("micdc:%d\n", *cur_itf_num);
+
+ memcpy(tptr, (u8 *)uac_ac_standard_interface_desc, sizeof(uac_ac_standard_interface_desc));
+ tptr[2] = *cur_itf_num;
+ tptr[8] = MIC_STR_INDEX;
+ tptr += sizeof(uac_ac_standard_interface_desc);//0x09
+
+ memcpy(tptr, uac_mic_ac_interface, sizeof(uac_mic_ac_interface));
+#if MIC_CHANNEL == 2
+ tptr[5]++;
+#endif
+ tptr[8] = *cur_itf_num + 1;
+ tptr += sizeof(uac_mic_ac_interface);
+
+ memcpy(tptr, (u8 *)uac_mic_input_terminal_desc, sizeof(uac_mic_input_terminal_desc));
+ tptr += sizeof(uac_mic_input_terminal_desc);//0x09
+
+ memcpy(tptr, (u8 *)uac_mic_output_terminal_desc, sizeof(uac_mic_output_terminal_desc));
+ tptr += sizeof(uac_mic_output_terminal_desc);//0x09
+
+ memcpy(tptr, (u8 *)uac_mic_selector_uint_desc, sizeof(uac_mic_selector_uint_desc));
+ tptr += sizeof(uac_mic_selector_uint_desc);
+
+ memcpy(tptr, (u8 *)uac_mic_feature_desc, sizeof(uac_mic_feature_desc));
+ tptr += sizeof(uac_mic_feature_desc);//0x09
+
+
+
+ memcpy(tptr, (u8 *)uac_mic_as_interface_desc, sizeof(uac_mic_as_interface_desc));
+ tptr[2] = *cur_itf_num + 1;
+ tptr[9 + 2] = *cur_itf_num + 1;
+#if MIC_SamplingFrequency > 1
+ u32 sr = 0;
+ //find the max sample rate
+ if (sr < MIC_AUDIO_RATE_1) {
+ sr = MIC_AUDIO_RATE_1;
+ }
+ if (sr < MIC_AUDIO_RATE_2) {
+ sr = MIC_AUDIO_RATE_2;
+ }
+ if (sr < MIC_AUDIO_RATE) {
+ sr = MIC_AUDIO_RATE;
+ }
+ if (sr < MIC_AUDIO_RATE_4) {
+ sr = MIC_AUDIO_RATE_4;
+ }
+ frame_len = sr * (MIC_AUDIO_RES / 8) * MIC_CHANNEL / 1000;
+ frame_len += (sr % 1000 ? (MIC_AUDIO_RES / 8) * MIC_CHANNEL : 0);
+#else
+ frame_len = MIC_AUDIO_RATE * (MIC_AUDIO_RES / 8) * MIC_CHANNEL / 1000;
+ frame_len += (MIC_AUDIO_RATE % 1000 ? (MIC_AUDIO_RES / 8) * MIC_CHANNEL : 0);
+#endif
+ offset = 9 + 9 + 7 + (8 + 3 * MIC_SamplingFrequency) + 4;
+ //MaxPacketSize of mic iso in
+ tptr[offset] = LOBYTE(frame_len);
+ tptr[offset + 1] = HIBYTE(frame_len);
+ tptr += sizeof(uac_mic_as_interface_desc);//0x09
+
+ if (usb_set_interface_hander(usb_id, *cur_itf_num, audio_ac_itf_handler) != *cur_itf_num) {
+ ASSERT(0, "uac mic set interface_hander fail");
+ }
+ if (usb_set_reset_hander(usb_id, *cur_itf_num, mic_reset) != *cur_itf_num) {
+
+ }
+ (*cur_itf_num) ++;
+ if (usb_set_interface_hander(usb_id, *cur_itf_num, mic_as_itf_hander) != *cur_itf_num) {
+ ASSERT(0, "uac mic set interface_hander fail");
+ }
+
+ (*cur_itf_num) ++;
+ i = tptr - ptr;
+ return i;
+}
+void audio_reset(struct usb_device_t *usb_device, u32 ift_num)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ log_debug("%s", __func__);
+#if USB_ROOT2
+ usb_disable_ep(usb_id, SPK_ISO_EP_OUT);
+ /* uac_release(usb_id); */
+#else
+ u8 *ep_buffer;
+ ep_buffer = uac_info->spk_dma_buffer;
+ usb_g_ep_config(usb_id, SPK_ISO_EP_OUT | USB_DIR_OUT, USB_ENDPOINT_XFER_ISOC, 1, ep_buffer, SPK_FRAME_LEN);
+
+ ep_buffer = uac_info->mic_dma_buffer;
+ usb_g_ep_config(usb_id, MIC_ISO_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_ISOC, 1, ep_buffer, MIC_FRAME_LEN);
+#endif
+}
+u32 uac_audio_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num)
+{
+ int i = 0;
+ u8 *tptr = ptr;
+ u32 offset;
+ u32 frame_len;
+
+ memcpy(tptr, (u8 *)uac_audio_interface_association, sizeof(uac_audio_interface_association));
+ tptr[2] = *cur_itf_num;
+ tptr[3] = 3;
+ tptr += sizeof(uac_audio_interface_association);//0x09
+
+ memcpy(tptr, (u8 *)uac_ac_standard_interface_desc, sizeof(uac_ac_standard_interface_desc));
+ tptr[2] = *cur_itf_num;
+ tptr += sizeof(uac_ac_standard_interface_desc);//0x09
+
+ memcpy(tptr, (u8 *)uac_audio_ac_interface, sizeof(uac_audio_ac_interface));
+ tptr[5] += 7; //spk selector unit
+#if SPK_CHANNEL == 1
+ tptr[5]--;
+#endif
+#if MIC_CHANNEL == 2
+ tptr[5]++;
+#endif
+ tptr[8] = *cur_itf_num + 1;
+ tptr[9] = *cur_itf_num + 2;
+ tptr += sizeof(uac_audio_ac_interface);//0x09
+
+ memcpy(tptr, (u8 *)uac_spk_input_terminal_desc, sizeof(uac_spk_input_terminal_desc));
+ tptr += sizeof(uac_spk_input_terminal_desc);//0x09
+
+ memcpy(tptr, (u8 *)uac_mic_input_terminal_desc, sizeof(uac_mic_input_terminal_desc));
+ tptr += sizeof(uac_mic_input_terminal_desc);//0x09
+
+ memcpy(tptr, (u8 *)uac_spk_output_terminal_desc, sizeof(uac_spk_output_terminal_desc));
+ tptr += sizeof(uac_spk_output_terminal_desc);//0x09
+
+ memcpy(tptr, (u8 *)uac_mic_output_terminal_desc, sizeof(uac_mic_output_terminal_desc));
+ tptr += sizeof(uac_mic_output_terminal_desc);//0x09
+
+ memcpy(tptr, (u8 *)uac_spk_selector_uint_desc, sizeof(uac_spk_selector_uint_desc));
+ tptr += sizeof(uac_spk_selector_uint_desc);
+
+ memcpy(tptr, (u8 *)uac_mic_selector_uint_desc, sizeof(uac_mic_selector_uint_desc));
+ tptr += sizeof(uac_mic_selector_uint_desc);
+
+ memcpy(tptr, (u8 *)uac_spk_feature_desc, sizeof(uac_spk_feature_desc));
+ tptr += sizeof(uac_spk_feature_desc);//0x09
+
+ memcpy(tptr, (u8 *)uac_mic_feature_desc, sizeof(uac_mic_feature_desc));
+ tptr += sizeof(uac_mic_feature_desc);//0x09
+
+
+ memcpy(tptr, (u8 *)uac_spk_as_interface_desc, sizeof(uac_spk_as_interface_desc));
+ tptr[2] = *cur_itf_num + 1;
+ tptr[9 + 2] = *cur_itf_num + 1;
+ frame_len = SPK_AUDIO_RATE * (SPK_AUDIO_RES / 8) * SPK_CHANNEL / 1000;
+ frame_len += (SPK_AUDIO_RATE % 1000 ? (SPK_AUDIO_RES / 8) * SPK_CHANNEL : 0);
+ offset = 9 + 9 + 7 + 11 + 4;
+ //MaxPacketSize of spk iso out
+ tptr[offset] = LOBYTE(frame_len);
+ tptr[offset + 1] = HIBYTE(frame_len);
+ tptr += sizeof(uac_spk_as_interface_desc);//0x09
+
+ memcpy(tptr, (u8 *)uac_mic_as_interface_desc, sizeof(uac_mic_as_interface_desc));
+ tptr[2] = *cur_itf_num + 2;
+ tptr[9 + 2] = *cur_itf_num + 2;
+#if MIC_SamplingFrequency > 1
+ u32 sr = 0;
+ //find the max sample rate
+ if (sr < MIC_AUDIO_RATE_1) {
+ sr = MIC_AUDIO_RATE_1;
+ }
+ if (sr < MIC_AUDIO_RATE_2) {
+ sr = MIC_AUDIO_RATE_2;
+ }
+ if (sr < MIC_AUDIO_RATE) {
+ sr = MIC_AUDIO_RATE;
+ }
+ if (sr < MIC_AUDIO_RATE_4) {
+ sr = MIC_AUDIO_RATE_4;
+ }
+ frame_len = sr * (MIC_AUDIO_RES / 8) * MIC_CHANNEL / 1000;
+ frame_len += (sr % 1000 ? (MIC_AUDIO_RES / 8) * MIC_CHANNEL : 0);
+#else
+ frame_len = MIC_AUDIO_RATE * (MIC_AUDIO_RES / 8) * MIC_CHANNEL / 1000;
+ frame_len += (MIC_AUDIO_RATE % 1000 ? (MIC_AUDIO_RES / 8) * MIC_CHANNEL : 0);
+#endif
+ offset = 9 + 9 + 7 + (8 + 3 * MIC_SamplingFrequency) + 4;
+ //MaxPacketSize of mic iso in
+ tptr[offset] = LOBYTE(frame_len);
+ tptr[offset + 1] = HIBYTE(frame_len);
+ tptr += sizeof(uac_mic_as_interface_desc);//0x09
+
+ log_debug("audio control interface num:%d\n", *cur_itf_num);
+ if (usb_set_interface_hander(usb_id, *cur_itf_num, audio_ac_itf_handler) != *cur_itf_num) {
+ ASSERT(0, "uac spk set interface_hander fail");
+ }
+
+ if (usb_set_reset_hander(usb_id, *cur_itf_num, audio_reset) != *cur_itf_num) {
+
+ }
+ (*cur_itf_num) ++;
+ log_debug("speaker stream interface num:%d\n", *cur_itf_num);
+ if (usb_set_interface_hander(usb_id, *cur_itf_num, spk_as_itf_hander) != *cur_itf_num) {
+ ASSERT(0, "uac spk set interface_hander fail");
+ }
+
+ (*cur_itf_num) ++;
+ log_debug("mic stream interface num:%d\n", *cur_itf_num);
+ if (usb_set_interface_hander(usb_id, *cur_itf_num, mic_as_itf_hander) != *cur_itf_num) {
+ ASSERT(0, "uac mic set interface_hander fail");
+ }
+
+ (*cur_itf_num) ++;
+
+ i = tptr - ptr;
+ return i;
+}
+u32 uac_register(const usb_dev usb_id, const u32 class)
+{
+ if (uac_info == NULL) {
+#if USB_MALLOC_ENABLE
+ uac_info = (struct uac_info_t *)malloc(sizeof(struct uac_info_t));
+ if (uac_info == NULL) {
+ printf("uac_register err\n");
+ return -1;
+ }
+#else
+ memset(&_uac_info, 0, sizeof(struct uac_info_t));
+ uac_info = &_uac_info;
+#endif
+ if (class == AUDIO_CLASS) {
+ uac_info->spk_dma_buffer = usb_alloc_ep_dmabuffer(usb_id, SPK_ISO_EP_OUT, SPK_FRAME_LEN + MIC_FRAME_LEN);
+ uac_info->mic_dma_buffer = uac_info->spk_dma_buffer + SPK_FRAME_LEN;
+ } else if (class == SPEAKER_CLASS) {
+ uac_info->spk_dma_buffer = usb_alloc_ep_dmabuffer(usb_id, SPK_ISO_EP_OUT, SPK_FRAME_LEN);
+ } else if (class == MIC_CLASS) {
+ uac_info->mic_dma_buffer = usb_alloc_ep_dmabuffer(usb_id, MIC_ISO_EP_IN | USB_DIR_IN, MIC_FRAME_LEN);
+ }
+ }
+ uac_info->spk_def_vol = vol_convert(uac_get_spk_vol());
+ uac_info->spk_left_vol = uac_info->spk_def_vol;
+ uac_info->spk_right_vol = uac_info->spk_def_vol;
+ uac_info->spk_max_vol = vol_convert(100);
+ uac_info->spk_min_vol = vol_convert(0);
+ uac_info->spk_vol_res = 0x30;
+ uac_info->spk_mute = 0;
+
+ uac_info->mic_max_vol = vol_convert(100);
+ uac_info->mic_min_vol = vol_convert(0);
+ uac_info->mic_vol_res = 0x30;
+ uac_info->mic_def_vol = vol_convert(13 / 14.0 * 100);
+ uac_info->mic_vol = uac_info->mic_def_vol;
+ uac_info->mic_mute = 0;
+ uac_info->ps4_mode = 0;
+ return 0;
+}
+void uac_release(const usb_dev usb_id)
+{
+ struct usb_device_t *usb_device = usb_id2device(usb_id);
+
+ if (uac_info) {
+ close_spk(usb_device);
+ close_mic(usb_device);
+#if USB_MALLOC_ENABLE
+ free(uac_info);
+#endif
+ uac_info = NULL;
+ }
+}
+#endif
diff --git a/apps/common/device/usb/device/uac_stream.c b/apps/common/device/usb/device/uac_stream.c
new file mode 100644
index 0000000..8afdfff
--- /dev/null
+++ b/apps/common/device/usb/device/uac_stream.c
@@ -0,0 +1,514 @@
+#include "app_config.h"
+#include "system/includes.h"
+#include "printf.h"
+#include "usb/usb_config.h"
+#include "usb/device/usb_stack.h"
+
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+#include "usb/device/uac_audio.h"
+#include "uac_stream.h"
+#include "audio_config.h"
+
+/* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
+#include "audio_track.h"
+/* #endif */
+
+
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[UAC]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#define UAC_DEBUG_ECHO_MODE 0
+
+static volatile u8 speaker_stream_is_open = 0;
+struct uac_speaker_handle {
+ cbuffer_t cbuf;
+ volatile u8 need_resume;
+ u8 channel;
+ u8 alive;
+ void *buffer;
+ void *audio_track;
+ //void (*rx_handler)(int, void *, int);
+};
+
+static void (*uac_rx_handler)(int, void *, int) = NULL;
+
+#if (SOUNDCARD_ENABLE)
+#define UAC_BUFFER_SIZE (4 * 1024)
+#else
+#define UAC_BUFFER_SIZE (1 * 1024)
+#endif
+
+#define UAC_BUFFER_MAX (UAC_BUFFER_SIZE * 50 / 100)
+
+static struct uac_speaker_handle *uac_speaker = NULL;
+
+#if USB_MALLOC_ENABLE
+#else
+static struct uac_speaker_handle uac_speaker_handle SEC(.uac_var);
+static u8 uac_rx_buffer[UAC_BUFFER_SIZE] ALIGNED(4) SEC(.uac_rx);
+#endif
+u32 uac_speaker_stream_length()
+{
+ return UAC_BUFFER_SIZE;
+}
+u32 uac_speaker_stream_size()
+{
+ if (!speaker_stream_is_open) {
+ return 0;
+ }
+
+ if (uac_speaker) {
+ return cbuf_get_data_size(&uac_speaker->cbuf);
+ }
+
+ return 0;
+}
+
+u32 uac_speaker_get_alive()
+{
+ if (uac_speaker) {
+ return uac_speaker->alive;
+ }
+ return 0;
+}
+void uac_speaker_set_alive(u8 alive)
+{
+ local_irq_disable();
+ if (uac_speaker) {
+ uac_speaker->alive = alive;
+ }
+ local_irq_enable();
+}
+
+void uac_speaker_stream_buf_clear(void)
+{
+ if (speaker_stream_is_open) {
+ cbuf_clear(&uac_speaker->cbuf);
+ }
+}
+
+void set_uac_speaker_rx_handler(void *priv, void (*rx_handler)(int, void *, int))
+{
+ uac_rx_handler = rx_handler;
+ /* if (uac_speaker) { */
+ /* uac_speaker->rx_handler = rx_handler; */
+ /* } */
+}
+
+int uac_speaker_stream_sample_rate(void)
+{
+ /* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
+ if (uac_speaker && uac_speaker->audio_track) {
+ int sr = audio_local_sample_track_rate(uac_speaker->audio_track);
+ if ((sr < (SPK_AUDIO_RATE + 100)) && (sr > (SPK_AUDIO_RATE - 100))) {
+ return sr;
+ }
+ /* printf("uac audio_track reset \n"); */
+ /* local_irq_disable(); */
+ /* audio_local_sample_track_close(uac_speaker->audio_track); */
+ /* uac_speaker->audio_track = audio_local_sample_track_open(SPK_CHANNEL, SPK_AUDIO_RATE, 1000); */
+ /* local_irq_enable(); */
+ }
+ /* #endif */
+ return SPK_AUDIO_RATE;
+}
+
+void uac_speaker_stream_write(const u8 *obuf, u32 len)
+{
+ if (speaker_stream_is_open) {
+ //write dac
+ /* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
+ if (uac_speaker->audio_track) {
+ audio_local_sample_track_in_period(uac_speaker->audio_track, (len >> 1) / uac_speaker->channel);
+ }
+ /* #endif */
+ int wlen = cbuf_write(&uac_speaker->cbuf, (void *)obuf, len);
+ if (wlen != len) {
+ //putchar('W');
+ }
+ //if (uac_speaker->rx_handler) {
+ if (uac_rx_handler) {
+ /* if (uac_speaker->cbuf.data_len >= UAC_BUFFER_MAX) { */
+ // 马上就要满了,赶紧取走
+ uac_speaker->need_resume = 1; //2020-12-22注:无需唤醒
+ /* } */
+ if (uac_speaker->need_resume) {
+ uac_speaker->need_resume = 0;
+ uac_rx_handler(0, (void *)obuf, len);
+ //uac_speaker->rx_handler(0, (void *)obuf, len);
+ }
+ }
+ uac_speaker->alive = 0;
+ }
+}
+
+int uac_speaker_read(void *priv, void *data, u32 len)
+{
+ int r_len;
+ int err = 0;
+
+ local_irq_disable();
+ if (!speaker_stream_is_open) {
+ local_irq_enable();
+ return 0;
+ }
+
+ r_len = cbuf_get_data_size(&uac_speaker->cbuf);
+ if (r_len) {
+ r_len = r_len > len ? len : r_len;
+ r_len = cbuf_read(&uac_speaker->cbuf, data, r_len);
+ if (!r_len) {
+ putchar('U');
+ }
+ }
+
+ if (r_len == 0) {
+ uac_speaker->need_resume = 1;
+ }
+ local_irq_enable();
+ return r_len;
+}
+
+void uac_speaker_stream_open(u32 samplerate, u32 ch)
+{
+ if (speaker_stream_is_open) {
+ return;
+ }
+ log_info("%s", __func__);
+
+ if (!uac_speaker) {
+#if USB_MALLOC_ENABLE
+
+ uac_speaker = zalloc(sizeof(struct uac_speaker_handle));
+ if (!uac_speaker) {
+ return;
+ }
+
+ uac_speaker->buffer = malloc(UAC_BUFFER_SIZE);
+ if (!uac_speaker->buffer) {
+ free(uac_speaker);
+ uac_speaker = NULL;
+ goto __err;
+ }
+
+
+#else
+
+ uac_speaker = &uac_speaker_handle;
+
+ memset(uac_speaker, 0, sizeof(struct uac_speaker_handle));
+
+ uac_speaker->buffer = uac_rx_buffer;
+#endif
+ uac_speaker->channel = ch;
+ /* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
+ uac_speaker->audio_track = audio_local_sample_track_open(ch, samplerate, 1000);
+ /* #endif */
+ }
+
+
+ //uac_speaker->rx_handler = NULL;
+
+ cbuf_init(&uac_speaker->cbuf, uac_speaker->buffer, UAC_BUFFER_SIZE);
+ speaker_stream_is_open = 1;
+ struct sys_event event;
+ event.type = SYS_DEVICE_EVENT;
+ event.arg = (void *)DEVICE_EVENT_FROM_UAC;
+ event.u.dev.event = USB_AUDIO_PLAY_OPEN;
+ event.u.dev.value = (int)((ch << 24) | samplerate);
+
+#if !UAC_DEBUG_ECHO_MODE
+ sys_event_notify(&event);
+#endif
+
+ return;
+
+__err:
+ return;
+}
+
+void uac_speaker_stream_close()
+{
+ if (speaker_stream_is_open == 0) {
+ return;
+ }
+
+ log_info("%s", __func__);
+ speaker_stream_is_open = 0;
+
+ if (uac_speaker) {
+ /* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
+ audio_local_sample_track_close(uac_speaker->audio_track);
+ /* #endif */
+ uac_speaker->audio_track = NULL;
+#if USB_MALLOC_ENABLE
+ if (uac_speaker->buffer) {
+ free(uac_speaker->buffer);
+ }
+ free(uac_speaker);
+#endif
+ uac_speaker = NULL;
+ }
+ struct sys_event event;
+ event.type = SYS_DEVICE_EVENT;
+ event.arg = (void *)DEVICE_EVENT_FROM_UAC;
+ event.u.dev.event = USB_AUDIO_PLAY_CLOSE;
+ event.u.dev.value = (int)0;
+
+#if !UAC_DEBUG_ECHO_MODE
+ sys_event_notify(&event);
+#endif
+}
+
+int uac_get_spk_vol()
+{
+ int max_vol = get_max_sys_vol();
+ int vol = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
+ if (vol * 100 / max_vol < 100) {
+ return vol * 100 / max_vol;
+ } else {
+ return 99;
+ }
+ return 0;
+}
+static u8 flag_uac_event_enable = 1;
+void set_uac_event_flag(u8 en)
+{
+ flag_uac_event_enable = en;
+}
+u8 get_uac_event_flag(void)
+{
+ return flag_uac_event_enable;
+}
+static volatile u32 mic_stream_is_open;
+
+u8 uac_get_mic_stream_status(void)
+{
+ return mic_stream_is_open;
+}
+
+void uac_mute_volume(u32 type, u32 l_vol, u32 r_vol)
+{
+ struct sys_event event;
+ event.type = SYS_DEVICE_EVENT;
+ event.arg = (void *)DEVICE_EVENT_FROM_UAC;
+
+ static u32 last_spk_l_vol = (u32) - 1, last_spk_r_vol = (u32) - 1;
+ static u32 last_mic_vol = (u32) - 1;
+
+ if (!get_uac_event_flag()) {
+ return;
+ }
+ switch (type) {
+ case MIC_FEATURE_UNIT_ID: //MIC
+ if (mic_stream_is_open == 0) {
+ return ;
+ }
+ if (l_vol == last_mic_vol) {
+ return;
+ }
+ last_mic_vol = l_vol;
+ event.u.dev.event = USB_AUDIO_SET_MIC_VOL;
+ break;
+ case SPK_FEATURE_UNIT_ID: //SPK
+ if (speaker_stream_is_open == 0) {
+ return;
+ }
+ if (l_vol == last_spk_l_vol && r_vol == last_spk_r_vol) {
+ return;
+ }
+ last_spk_l_vol = l_vol;
+ last_spk_r_vol = r_vol;
+ event.u.dev.event = USB_AUDIO_SET_PLAY_VOL;
+ break;
+ default:
+ break;
+ }
+
+ event.u.dev.value = (int)(r_vol << 16 | l_vol);
+#if !UAC_DEBUG_ECHO_MODE
+ sys_event_notify(&event);
+#endif
+}
+
+
+static int (*mic_tx_handler)(int, void *, int) = NULL;
+int uac_mic_stream_read(u8 *buf, u32 len)
+{
+ if (mic_stream_is_open == 0) {
+ return 0;
+ }
+#if 0//48K 1ksin
+ const s16 sin_48k[] = {
+ 0, 2139, 4240, 6270, 8192, 9974, 11585, 12998,
+ 14189, 15137, 15826, 16244, 16384, 16244, 15826, 15137,
+ 14189, 12998, 11585, 9974, 8192, 6270, 4240, 2139,
+ 0, -2139, -4240, -6270, -8192, -9974, -11585, -12998,
+ -14189, -15137, -15826, -16244, -16384, -16244, -15826, -15137,
+ -14189, -12998, -11585, -9974, -8192, -6270, -4240, -2139
+ };
+ u16 *l_ch = (u16 *)buf;
+ u16 *r_ch = (u16 *)buf;
+ r_ch++;
+ for (int i = 0; i < len / 2; i++) {
+ *l_ch = sin_48k[i];
+ *r_ch = sin_48k[i];
+ l_ch += 1;
+ r_ch += 1;
+ }
+ return len;
+#elif UAC_DEBUG_ECHO_MODE
+#if MIC_CHANNEL == 2
+ uac_speaker_read(NULL, buf, len);
+ const s16 sin_48k[] = {
+ 0, 2139, 4240, 6270, 8192, 9974, 11585, 12998,
+ 14189, 15137, 15826, 16244, 16384, 16244, 15826, 15137,
+ 14189, 12998, 11585, 9974, 8192, 6270, 4240, 2139,
+ 0, -2139, -4240, -6270, -8192, -9974, -11585, -12998,
+ -14189, -15137, -15826, -16244, -16384, -16244, -15826, -15137,
+ -14189, -12998, -11585, -9974, -8192, -6270, -4240, -2139
+ };
+ u16 *r_ch = (u16 *)buf;
+ r_ch++;
+ for (int i = 0; i < len / 4; i++) {
+ *r_ch = sin_48k[i];
+ r_ch += 2;
+ }
+#else
+ uac_speaker_read(NULL, buf, len * 2);
+ u16 *r_ch = (u16 *)buf;
+ for (int i = 0; i < len / 2; i++) {
+ r_ch[i] = r_ch[i * 2];
+ }
+
+#endif
+ return len;
+#else
+ if (mic_tx_handler) {
+#if 1
+ return mic_tx_handler(0, buf, len);
+#else
+ //16bit ---> 24bit
+ int rlen = mic_tx_handler(0, tmp_buf, len / 3 * 2);
+ rlen /= 2; //sampe point
+ for (int i = 0 ; i < rlen ; i++) {
+ buf[i * 3] = 0;
+ buf[i * 3 + 1] = tmp_buf[i * 2];
+ buf[i * 3 + 2] = tmp_buf[i * 2 + 1];
+ }
+#endif
+ } else {
+ //putchar('N');
+ }
+ return 0;
+#endif
+ return 0;
+}
+
+void set_uac_mic_tx_handler(void *priv, int (*tx_handler)(int, void *, int))
+{
+ mic_tx_handler = tx_handler;
+}
+static u32 mic_close_tid = 0;
+static u8 mic_sw;
+u32 uac_mic_stream_open(u32 samplerate, u32 frame_len, u32 ch)
+{
+ mic_sw = 1;
+ if (mic_stream_is_open) {
+ return 0;
+ }
+
+ /* mic_tx_handler = NULL; */
+ log_info("%s", __func__);
+
+ struct sys_event event;
+ event.type = SYS_DEVICE_EVENT;
+ event.arg = (void *)DEVICE_EVENT_FROM_UAC;
+ event.u.dev.event = USB_AUDIO_MIC_OPEN;
+ event.u.dev.value = (int)((ch << 24) | samplerate);
+ mic_stream_is_open = 1;
+
+#if !UAC_DEBUG_ECHO_MODE
+ sys_event_notify(&event);
+#endif
+ return 0;
+}
+
+static void uac_mic_stream_close_delay()
+{
+ mic_close_tid = 0;
+ if (!mic_sw) {
+
+ } else {
+ return ;
+ }
+ log_info("%s", __func__);
+ struct sys_event event;
+ event.type = SYS_DEVICE_EVENT;
+ event.arg = (void *)DEVICE_EVENT_FROM_UAC;
+ event.u.dev.event = USB_AUDIO_MIC_CLOSE;
+ event.u.dev.value = (int)0;
+ mic_stream_is_open = 0;
+
+#if !UAC_DEBUG_ECHO_MODE
+ sys_event_notify(&event);
+#endif
+}
+void uac_mic_stream_close()
+{
+ mic_sw = 0;
+ if (mic_stream_is_open == 0) {
+ return ;
+ }
+ //FIXME:
+ //未知原因出现频繁开关mic,导致出现audio或者蓝牙工作异常,
+ //收到mic关闭命令后延时1s再发消息通知audio模块执行关闭动作
+ //如果在1s之内继续收到usb下发的关闭命令,则继续推迟1s。
+ if (mic_close_tid == 0) {
+ mic_close_tid = sys_hi_timeout_add(NULL, uac_mic_stream_close_delay, 1000);
+ } else {
+ sys_hi_timeout_modify(mic_close_tid, 1000);
+ }
+}
+
+_WEAK_
+s8 app_audio_get_volume(u8 state)
+{
+ return 88;
+}
+_WEAK_
+void usb_audio_demo_exit(void)
+{
+
+}
+_WEAK_
+int usb_audio_demo_init(void)
+{
+ return 0;
+}
+_WEAK_
+u8 get_max_sys_vol(void)
+{
+ return 100;
+}
+_WEAK_
+void *audio_local_sample_track_open(u8 channel, int sample_rate, int period)
+{
+ return NULL;
+}
+_WEAK_
+int audio_local_sample_track_in_period(void *c, int samples)
+{
+ return 0;
+}
+_WEAK_
+void audio_local_sample_track_close(void *c)
+{
+}
+#endif
diff --git a/apps/common/device/usb/device/uac_stream.h b/apps/common/device/usb/device/uac_stream.h
new file mode 100644
index 0000000..6b64adb
--- /dev/null
+++ b/apps/common/device/usb/device/uac_stream.h
@@ -0,0 +1,31 @@
+/*****************************************************************
+>file name : usb_audio.h
+>author : lichao
+>create time : Wed 22 May 2019 10:39:35 AM CST
+*****************************************************************/
+#ifndef _UAC_STREAM_H_
+#define _UAC_STREAM_H_
+#include "typedef.h"
+
+enum uac_event {
+ USB_AUDIO_PLAY_OPEN = 0x0,
+ USB_AUDIO_PLAY_CLOSE,
+ USB_AUDIO_MIC_OPEN,
+ USB_AUDIO_MIC_CLOSE,
+ // USB_AUDIO_MUTE,
+ USB_AUDIO_SET_PLAY_VOL,
+ USB_AUDIO_SET_MIC_VOL,
+};
+
+
+void uac_speaker_stream_buf_clear(void);
+u32 uac_speaker_stream_length();
+u32 uac_speaker_stream_size();
+void set_uac_speaker_rx_handler(void *priv, void (*rx_handler)(int, void *, int));
+void set_uac_mic_tx_handler(void *priv, int (*tx_handler)(int, void *, int));
+int uac_speaker_stream_sample_rate(void);
+
+int uac_speaker_read(void *priv, void *data, u32 len);
+u32 uac_speaker_get_alive();
+void uac_speaker_set_alive(u8 alive);
+#endif
diff --git a/apps/common/device/usb/device/usb_device.c b/apps/common/device/usb/device/usb_device.c
new file mode 100644
index 0000000..15223d8
--- /dev/null
+++ b/apps/common/device/usb/device/usb_device.c
@@ -0,0 +1,258 @@
+#include "usb/device/usb_stack.h"
+#include "usb_config.h"
+#include "usb/device/msd.h"
+#include "usb/scsi.h"
+#include "usb/device/hid.h"
+#include "usb/device/uac_audio.h"
+#include "usb/device/cdc.h"
+#include "irq.h"
+#include "init.h"
+#include "gpio.h"
+#include "app_config.h"
+
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+
+#include "debug.h"
+
+#if TCFG_USB_SLAVE_ENABLE
+
+static void usb_device_init(const usb_dev usb_id)
+{
+
+ usb_config(usb_id);
+ usb_g_sie_init(usb_id);
+#if defined(FUSB_MODE) && FUSB_MODE
+ usb_write_power(usb_id, 0x40);
+#elif defined(FUSB_MODE) && (FUSB_MODE == 0)
+ usb_write_power(usb_id, 0x60);
+#endif
+ usb_slave_init(usb_id);
+ u8 *ep0_dma_buffer = usb_alloc_ep_dmabuffer(usb_id, 0, 64);
+
+ usb_set_dma_raddr(usb_id, 0, ep0_dma_buffer);
+ usb_set_dma_raddr(usb_id, 1, ep0_dma_buffer);
+ usb_set_dma_raddr(usb_id, 2, ep0_dma_buffer);
+ usb_set_dma_raddr(usb_id, 3, ep0_dma_buffer);
+ usb_set_dma_raddr(usb_id, 4, ep0_dma_buffer);
+
+ usb_write_intr_usbe(usb_id, INTRUSB_RESET_BABBLE | INTRUSB_SUSPEND);
+ usb_clr_intr_txe(usb_id, -1);
+ usb_clr_intr_rxe(usb_id, -1);
+ usb_set_intr_txe(usb_id, 0);
+ usb_set_intr_rxe(usb_id, 0);
+ usb_g_isr_reg(usb_id, 3, 0);
+ /* usb_sof_isr_reg(usb_id,3,0); */
+ /* usb_sofie_enable(usb_id); */
+ /* USB_DEBUG_PRINTF("ep0 addr %x %x\n", usb_get_dma_taddr(0), ep0_dma_buffer); */
+}
+static void usb_device_hold(const usb_dev usb_id)
+{
+
+ usb_g_hold(usb_id);
+ usb_release(usb_id);
+}
+
+
+static int usb_ep_conflict_check(const usb_dev usb_id);
+int usb_device_mode(const usb_dev usb_id, const u32 class)
+{
+
+ /* usb_device_set_class(CLASS_CONFIG); */
+ u8 class_index = 0;
+ if (class == 0) {
+ gpio_direction_input(IO_PORT_DM + 2 * usb_id);
+ gpio_set_pull_up(IO_PORT_DM + 2 * usb_id, 0);
+ gpio_set_pull_down(IO_PORT_DM + 2 * usb_id, 0);
+ gpio_set_die(IO_PORT_DM + 2 * usb_id, 0);
+
+ gpio_direction_input(IO_PORT_DP + 2 * usb_id);
+ gpio_set_pull_up(IO_PORT_DP + 2 * usb_id, 0);
+ gpio_set_pull_down(IO_PORT_DP + 2 * usb_id, 0);
+ gpio_set_die(IO_PORT_DP + 2 * usb_id, 0);
+
+ os_time_dly(15);
+
+ gpio_set_die(IO_PORT_DM + 2 * usb_id, 1);
+ gpio_set_die(IO_PORT_DP + 2 * usb_id, 1);
+
+#if TCFG_USB_SLAVE_MSD_ENABLE
+ msd_release(usb_id);
+#endif
+
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+ uac_release(usb_id);
+#endif
+
+#if TCFG_USB_SLAVE_CDC_ENABLE
+ cdc_release(usb_id);
+#endif
+#if TCFG_USB_SLAVE_HID_ENABLE
+ hid_release(usb_id);
+#endif
+ usb_device_hold(usb_id);
+ return 0;
+ }
+
+ /* int ret = usb_ep_conflict_check(usb_id); */
+ /* if (ret) { */
+ /* return ret; */
+ /* } */
+
+ usb_memory_init();
+
+ usb_add_desc_config(usb_id, MAX_INTERFACE_NUM, NULL);
+
+#if TCFG_USB_SLAVE_MSD_ENABLE
+ if ((class & MASSSTORAGE_CLASS) == MASSSTORAGE_CLASS) {
+ log_info("add desc msd");
+ usb_add_desc_config(usb_id, class_index++, msd_desc_config);
+ msd_register(usb_id);
+ }
+#endif
+
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+ if ((class & AUDIO_CLASS) == AUDIO_CLASS) {
+ log_info("add audio desc");
+ usb_add_desc_config(usb_id, class_index++, uac_audio_desc_config);
+ uac_register(usb_id, AUDIO_CLASS);
+ } else if ((class & SPEAKER_CLASS) == SPEAKER_CLASS) {
+ log_info("add desc speaker");
+ usb_add_desc_config(usb_id, class_index++, uac_spk_desc_config);
+ uac_register(usb_id, SPEAKER_CLASS);
+ } else if ((class & MIC_CLASS) == MIC_CLASS) {
+ log_info("add desc mic");
+ usb_add_desc_config(usb_id, class_index++, uac_mic_desc_config);
+ uac_register(usb_id, MIC_CLASS);
+ }
+#endif
+
+#if TCFG_USB_SLAVE_HID_ENABLE
+ if ((class & HID_CLASS) == HID_CLASS) {
+ log_info("add desc std hid");
+ usb_add_desc_config(usb_id, class_index++, hid_desc_config);
+ hid_register(usb_id);
+ }
+#endif
+
+#if TCFG_USB_SLAVE_CDC_ENABLE
+ if ((class & CDC_CLASS) == CDC_CLASS) {
+ log_info("add desc cdc");
+ usb_add_desc_config(usb_id, class_index++, cdc_desc_config);
+ cdc_register(usb_id);
+ }
+#endif
+
+ usb_device_init(usb_id);
+ user_setup_filter_install(usb_id2device(usb_id));
+ return 0;
+}
+/* module_initcall(usb_device_mode); */
+
+static int usb_ep_conflict_check(const usb_dev usb_id)
+{
+ u8 usb_ep_tx_list[] = {
+#if TCFG_USB_SLAVE_MSD_ENABLE
+ MSD_BULK_EP_IN,
+#endif
+#if TCFG_USB_SLAVE_HID_ENABLE
+ HID_EP_IN,
+#endif
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+ MIC_ISO_EP_IN,
+#endif
+#if TCFG_USB_SLAVE_CDC_ENABLE
+ CDC_DATA_EP_IN,
+#if CDC_INTR_EP_ENABLE
+ CDC_INTR_EP_IN,
+#endif
+#endif
+ };
+ u8 usb_ep_rx_list[] = {
+#if TCFG_USB_SLAVE_MSD_ENABLE
+ MSD_BULK_EP_OUT,
+#endif
+#if TCFG_USB_SLAVE_HID_ENABLE
+ HID_EP_OUT,
+#endif
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+ SPK_ISO_EP_OUT,
+#endif
+#if TCFG_USB_SLAVE_CDC_ENABLE
+ CDC_DATA_EP_OUT,
+#endif
+ };
+ int ret = 0;
+ int i, j;
+
+ for (i = 0; i < sizeof(usb_ep_tx_list) - 1; i++) {
+ for (j = i + 1; j < sizeof(usb_ep_tx_list); j++) {
+ if (usb_ep_tx_list[i] == usb_ep_tx_list[j]) {
+ ret = -1;
+ ASSERT(0, "ep%d conflict, dir in\n", usb_ep_tx_list[i]);
+ goto __exit;
+ }
+ }
+ }
+ for (i = 0; i < sizeof(usb_ep_rx_list) - 1; i++) {
+ for (j = i + 1; j < sizeof(usb_ep_rx_list); j++) {
+ if (usb_ep_rx_list[i] == usb_ep_rx_list[j]) {
+ ret = -1;
+ ASSERT(0, "ep%d conflict, dir out\n", usb_ep_rx_list[i]);
+ goto __exit;
+ }
+ }
+ }
+__exit:
+ return ret;
+}
+
+#endif
+
+/*
+ * @brief otg检测中sof初始化,不要放在TCFG_USB_SLAVE_ENABLE里
+ * @parm id usb设备号
+ * @return 0 ,忽略sof检查,1 等待sof信号
+ */
+u32 usb_otg_sof_check_init(const usb_dev id)
+{
+ /* return 0;// */
+ u8 *ep0_dma_buffer = usb_alloc_ep_dmabuffer(id, 0, 64);
+
+ usb_g_sie_init(id);
+
+#ifdef USB_HW_20
+ //husb调用完usb_g_sie_init(),或者收到usb reset中断,intrusbe,intrtxe,
+ //intrrxe会复位成默认值,不手动清零以及关中断,会收到usb reset中断,由于
+ //空指针问题导致异常
+ usb_write_intr_usbe(id, 0);
+ usb_clr_intr_txe(id, -1);
+ usb_clr_intr_rxe(id, -1);
+ if (id == 0) {
+ unrequest_irq(IRQ_USB_CTRL_IDX);
+#if USB_MAX_HW_NUM > 1
+ } else {
+ unrequest_irq(IRQ_USB1_CTRL_IDX);
+#endif
+ }
+#endif
+
+#if defined(FUSB_MODE) && FUSB_MODE
+ usb_write_power(id, 0x40);
+#elif defined(FUSB_MODE) && (FUSB_MODE == 0)
+ usb_write_power(id, 0x60);
+#endif
+
+ usb_set_dma_raddr(id, 0, ep0_dma_buffer);
+
+ for (int ep = 1; ep < USB_MAX_HW_EPNUM; ep++) {
+ usb_disable_ep(id, ep);
+ }
+ usb_sof_clr_pnd(id);
+ return 1;
+}
diff --git a/apps/common/device/usb/device/user_setup.c b/apps/common/device/usb/device/user_setup.c
new file mode 100644
index 0000000..0c48aa0
--- /dev/null
+++ b/apps/common/device/usb/device/user_setup.c
@@ -0,0 +1,223 @@
+#include "usb/device/usb_stack.h"
+#include "usb_config.h"
+#include "usb/device/msd.h"
+#include "usb/scsi.h"
+#include "usb/device/hid.h"
+#include "usb/device/uac_audio.h"
+#include "irq.h"
+#include "init.h"
+#include "gpio.h"
+#include "app_config.h"
+
+#if TCFG_USB_APPLE_DOCK_EN
+#include "apple_dock/iAP.h"
+#endif
+
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#if TCFG_USB_SLAVE_ENABLE
+
+static const u8 user_stirng[] = {
+ 24,
+ 0x03,
+ 'U', 0x00,
+ 'S', 0x00,
+ 'B', 0x00,
+ 'A', 0x00,
+ 'u', 0x00,
+ 'd', 0x00,
+ 'i', 0x00,
+ 'o', 0x00,
+ '1', 0x00,
+ '.', 0x00,
+ '0', 0x00,
+};
+
+#if TCFG_USB_APPLE_DOCK_EN
+static const u8 IAP_interface_string[] = {
+ 0x1c, 0x03,
+ //iAP Interface
+ 0x69, 0x00, 0x41, 0x00, 0x50, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x74, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x66, 0x00, 0x61, 0x00, 0x63, 0x00, 0x65, 0x00
+};
+#endif
+
+static u8 root2_testing;
+u32 usb_root2_testing()
+{
+#if USB_ROOT2
+ return root2_testing;
+#else
+ return 0;
+#endif
+}
+u32 check_ep_vaild(u32 ep)
+{
+ u32 en = 0;
+ switch (ep) {
+ case 0:
+ en = 1;
+ break;
+#if TCFG_USB_SLAVE_MSD_ENABLE
+ case 1:
+ en = 1;
+ break;
+#endif
+#if TCFG_USB_SLAVE_HID_ENABLE
+ case 2:
+ en = 1;
+ break;
+#endif
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+ case 3:
+ en = 1;
+ break;
+#endif
+ case 4:
+ break;
+ }
+ return en;
+}
+static u32 setup_endpoint(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ u32 tx_len = 0;
+ u8 *tx_payload = usb_get_setup_buffer(usb_device);
+
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+ if (uac_setup_endpoint(usb_device, req)) {
+ return 1;
+ }
+#endif
+ u32 ep = LOBYTE(req->wIndex) & 0x0f;
+ if (check_ep_vaild(ep) == 0) {
+ usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+ return 1;// not zero user handle this request
+ }
+
+
+ return 0;
+}
+static u32 setup_device(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
+{
+ const usb_dev usb_id = usb_device2id(usb_device);
+ u32 ret = 0;
+ switch (req->bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ switch (HIBYTE(req->wValue)) {
+ case USB_DT_STRING:
+ switch (LOBYTE(req->wValue)) {
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+ case SPEAKER_STR_INDEX:
+ case MIC_STR_INDEX:
+ if (usb_device->bDeviceStates == USB_DEFAULT) {
+ ret = 0;
+ } else {
+ usb_set_data_payload(usb_device, req, user_stirng, sizeof(user_stirng));
+ ret = 1;
+ }
+ break;
+#endif
+#if TCFG_USB_APPLE_DOCK_EN
+ case MSD_STR_INDEX:
+ if (apple_mfi_chip_online_lib()) {
+ y_printf("MSD_STR_INDEX \n");
+ usb_set_data_payload(usb_device, req, IAP_interface_string, sizeof(IAP_interface_string));
+ apple_mfi_pass_ready_set_api();
+ extern void apple_usb_msd_wakeup(struct usb_device_t *usb_device);
+ apple_usb_msd_wakeup(usb_device);
+ ret = 1;
+ break;
+ }
+#endif
+ default:
+ break;
+ }
+ break;
+ case USB_DT_DEVICE:
+#if USB_ROOT2
+ if (req->wLength == 0xffff) {
+ root2_testing = 1;
+ }
+#endif
+ break;
+ }
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ break;
+ case USB_REQ_SET_ADDRESS:
+ /* if(req->wLength || req->wIndex){ */
+ /* ret = 1; */
+ /* usb_set_setup_phase(usb_device, USB_EP0_SET_STALL); */
+ /* dump_setup_request(req); */
+ /* log_debug_hexdump((u8 *)req, 8); */
+ /* } */
+ break;
+ }
+ return ret;
+}
+
+static u32 setup_other(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
+{
+ u32 ret = 0;
+ u32 tx_len;
+ u8 *tx_payload = usb_get_setup_buffer(usb_device);
+ switch (req->bRequest) {
+ case USB_REQ_GET_STATUS:
+#if TCFG_TYPEC_EARPHONE_TEST_FILTER
+ tx_len = 1;
+ tx_payload[0] = 0xfe;
+ usb_set_data_payload(usb_device, req, tx_payload, tx_len);
+#endif
+ break;
+ default:
+ ret = 1 ;
+ break;
+ }
+ return ret;
+}
+static u32 user_setup_filter(struct usb_device_t *usb_device, struct usb_ctrlrequest *request)
+{
+ // dump_setup_request(request);
+ // log_debug_hexdump((u8 *)request, 8);
+ u32 ret = 0;
+ u32 recip = request->bRequestType & USB_RECIP_MASK;
+ switch (recip) {
+ case USB_RECIP_DEVICE:
+ ret = setup_device(usb_device, request);
+ break;
+ case USB_RECIP_INTERFACE:
+ break;
+ case USB_RECIP_ENDPOINT:
+ ret = setup_endpoint(usb_device, request);
+ break;
+ case USB_RECIP_OTHER:
+ ret = setup_other(usb_device, request);
+ break;
+ }
+#if 0
+ const char *statas[] = {"USB_ATTACHED", "USB_POWERED", "USB_DEFAULT",
+ "USB_ADDRESS", "USB_CONFIGURED", "USB_SUSPENDED"
+ };
+
+ const char *phases[] = {"SETUP", "IN", "OUT",
+ "STALL",
+ };
+
+ printf("state:%s phase: %s", statas[usb_device->bDeviceStates],
+ phases[usb_device->bsetup_phase]);
+#endif
+ return ret;// not zero user handle this request
+}
+void user_setup_filter_install(struct usb_device_t *usb_device)
+{
+ usb_set_setup_hook(usb_device, user_setup_filter);
+}
+#endif
diff --git a/apps/common/device/usb/host/adb.c b/apps/common/device/usb/host/adb.c
new file mode 100644
index 0000000..973d9fe
--- /dev/null
+++ b/apps/common/device/usb/host/adb.c
@@ -0,0 +1,459 @@
+#include "includes.h"
+#include "asm/includes.h"
+#include "system/timer.h"
+#include "device/ioctl_cmds.h"
+#include "usb/host/usb_host.h"
+#include "usb_ctrl_transfer.h"
+#include "usb_bulk_transfer.h"
+#include "device_drive.h"
+#include "adb.h"
+#include "usb_config.h"
+#include "app_config.h"
+#if TCFG_ADB_ENABLE
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[adb]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+
+#include "adb_rsa_key.c"
+
+struct adb_device_t adb;
+
+struct device adb_device;
+void aoa_switch(struct usb_host_device *host_dev);
+
+static int set_adb_power(struct usb_host_device *host_dev, u32 value)
+{
+ return DEV_ERR_NONE;
+}
+
+static int get_adb_power(struct usb_host_device *host_dev, u32 value)
+{
+ return DEV_ERR_NONE;
+}
+
+static const struct interface_ctrl adb_ops = {
+ .interface_class = USB_CLASS_ADB,
+ .set_power = set_adb_power,
+ .get_power = get_adb_power,
+ .ioctl = NULL,
+};
+
+static const struct usb_interface_info adb_inf = {
+ .ctrl = (struct interface_ctrl *) &adb_ops,
+ .dev.adb = &adb,
+};
+
+u32 usb_adb_interface_ptp_mtp_parse(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+ struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
+ pBuf += sizeof(struct usb_interface_descriptor);
+ int len = 0;
+ const usb_dev usb_id = host_device2id(host_dev);
+
+ for (int i = 0; i < interface->bNumEndpoints; i++) {
+ struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)pBuf;
+ if (endpoint->bDescriptorType == USB_DT_ENDPOINT) {
+ if (endpoint->bmAttributes == USB_ENDPOINT_XFER_BULK) {
+ if (endpoint->bEndpointAddress & USB_DIR_IN) {
+ adb.extr_in = endpoint->bEndpointAddress & 0xf;
+ } else {
+ adb.extr_out = endpoint->bEndpointAddress;
+ }
+ }
+ pBuf += USB_DT_ENDPOINT_SIZE;
+ } else {
+ return 0;
+ }
+ }
+ printf("%s() %x %x\n", __func__, adb.extr_in, adb.extr_out);
+ return pBuf - (u8 *)interface ;
+}
+
+int usb_adb_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+ struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
+ pBuf += sizeof(struct usb_interface_descriptor);
+ int len = 0;
+ const usb_dev usb_id = host_device2id(host_dev);
+
+ adb_device.private_data = host_dev;
+
+ host_dev->interface_info[interface_num] = &adb_inf;
+
+ for (int endnum = 0; endnum < interface->bNumEndpoints; endnum++) {
+ struct usb_endpoint_descriptor *end_desc = (struct usb_endpoint_descriptor *)pBuf;
+
+ if (end_desc->bDescriptorType != USB_DT_ENDPOINT ||
+ end_desc->bLength != USB_DT_ENDPOINT_SIZE) {
+ log_error("ep bDescriptorType = %d bLength = %d", end_desc->bDescriptorType, end_desc->bLength);
+ return -USB_DT_ENDPOINT;
+ }
+
+ len += USB_DT_ENDPOINT_SIZE;
+ pBuf += USB_DT_ENDPOINT_SIZE;
+
+ if ((end_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+ if (end_desc->bEndpointAddress & USB_DIR_IN) {
+ adb.host_epin = usb_get_ep_num(usb_id, USB_DIR_IN, USB_ENDPOINT_XFER_BULK);
+ adb.target_epin = end_desc->bEndpointAddress & 0x0f;
+#if defined(FUSB_MODE) && FUSB_MODE == 0
+ adb.rxmaxp = end_desc->wMaxPacketSize;
+#endif
+ log_debug("D(%d)->H(%d)", adb.target_epin, adb.host_epin);
+ } else {
+ adb.host_epout = usb_get_ep_num(usb_id, USB_DIR_OUT, USB_ENDPOINT_XFER_BULK);
+ adb.target_epout = end_desc->bEndpointAddress & 0x0f;
+#if defined(FUSB_MODE) && FUSB_MODE == 0
+ adb.txmaxp = end_desc->wMaxPacketSize;
+#endif
+ log_debug("H(%d)->D(%d)", adb.host_epout, adb.target_epout);
+ }
+ }
+ }
+
+ u8 *ep_buffer = usb_h_get_ep_buffer(usb_id, adb.host_epin | USB_DIR_IN);
+ usb_h_ep_config(usb_id, adb.host_epin | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 0, 0, ep_buffer, 64);
+
+
+ ep_buffer = usb_h_get_ep_buffer(usb_id, adb.host_epout | USB_DIR_OUT);
+ usb_h_ep_config(usb_id, adb.host_epout | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK, 0, 0, ep_buffer, 64);
+
+ return len;
+}
+
+static int adb_send_packet(struct amessage *msg, const u8 *data_ptr)
+{
+ if (msg == NULL) {
+ return usb_bulk_only_send(&adb_device, adb.host_epout, 64, adb.target_epout, NULL, 0);
+ }
+ u32 cnt;
+ u32 count = msg->data_length;
+
+ msg->magic = msg->command ^ 0xffffffff;
+ const u8 *_data_ptr = data_ptr;
+ msg->data_check = 0;
+ while (count--) {
+ msg->data_check += *_data_ptr++;
+ }
+ int ret = usb_bulk_only_send(&adb_device, adb.host_epout, 64, adb.target_epout, (u8 *)msg, sizeof(*msg));
+ if (ret < 0) {
+ return ret;
+ }
+ if (data_ptr != NULL) {
+ return usb_bulk_only_send(&adb_device, adb.host_epout, 64, adb.target_epout, data_ptr, msg->data_length);
+ } else {
+ return 0;
+ }
+}
+static int adb_recv(u8 *buffer, u32 len, u32 timeout)
+{
+ return usb_bulk_only_receive(&adb_device, adb.host_epin, 64, adb.target_epin, buffer, len);
+}
+#define check_usb_status(ret) do{\
+ if(ret < 0){\
+ log_info("%s() @ %d %d\n", __func__, __LINE__, ret);\
+ return ret;\
+ }\
+ }while(0);
+
+static u8 adb_signatrue_data_index ;
+
+u32 adb_auth()
+{
+ log_info("%s() %d\n", __func__, __LINE__);
+ struct amessage msg;
+ int ret = 0;
+ u8 *cmd_string;
+ adb.local_id = 0x58525047;
+ adb.remote_id = 0;
+ msg.command = A_CNXN;
+ msg.arg0 = A_VERSION;
+ msg.arg1 = 0x00001000;
+ cmd_string = (u8 *)"host::";
+ msg.data_length = strlen((const char *)cmd_string) + 1;
+ ret = adb_send_packet(&msg, cmd_string);
+ check_usb_status(ret);
+ memset(&msg, 0, 24);
+ ret = adb_recv((u8 *)&msg, 24, 5);
+ check_usb_status(ret);
+
+ if (msg.command == A_CNXN) {
+ if (adb_recv(adb.buffer, msg.data_length, 1 * 100)) {
+ log_error("auth error 0\n");
+ return 0;
+ }
+ log_info("auth not send rsa pub key\n");
+ return 0;
+ } else if (msg.command == A_AUTH) {
+
+ } else {
+ log_error("auth error 1\n");
+ return 1;
+ }
+
+ ret = adb_recv(adb.buffer, msg.data_length, 1 * 100);
+ check_usb_status(ret);
+ msg.command = A_AUTH;
+ msg.arg0 = ADB_AUTH_SIGNATURE;
+ msg.data_length = sizeof(adb_signatrue_data[0]);
+ if (adb_signatrue_data_index > 2) {
+ adb_signatrue_data_index = 0;
+ }
+
+ adb_signatrue_data_index ++;
+ cmd_string = (u8 *)&adb_signatrue_data[adb_signatrue_data_index][0];
+ ret = adb_send_packet(&msg, cmd_string);
+ check_usb_status(ret);
+
+ ret = adb_send_packet(NULL, NULL);//zero packet
+ check_usb_status(ret);
+
+ memset(&msg, 0, 24);
+ ret = adb_recv((u8 *)&msg, 24, 1 * 100);
+ check_usb_status(ret);
+ if (msg.command != A_AUTH) {
+ log_error("auth error 2\n");
+ return 1;
+ }
+ ret = adb_recv(adb.buffer, msg.data_length, 1 * 100);
+ check_usb_status(ret);
+
+
+__RETRY:
+ msg.command = A_AUTH;
+ msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
+ msg.arg1 = 0;
+ msg.data_length = sizeof(adb_rsa_pub_key);
+ ret = adb_send_packet(&msg, (u8 *)adb_rsa_pub_key);
+ check_usb_status(ret);
+
+ ret = adb_recv((u8 *)&msg, 24, 30 * 100);
+
+ if (ret < 0) {
+ if (ret == -DEV_ERR_TIMEOUT) {
+ goto __RETRY;
+ }
+ check_usb_status(ret);
+ }
+
+ ret = adb_recv(adb.buffer, msg.data_length, 1 * 100);//最长等待30s,等手机点击确认授权adb
+ if (ret < 0) {
+ if (ret == -DEV_ERR_TIMEOUT) {
+ goto __RETRY;
+ }
+ check_usb_status(ret);
+ }
+
+ if (msg.command == A_AUTH) {
+ goto __RETRY;
+ }
+ return 0;
+}
+
+u32 adb_shell_login()
+{
+ log_info("%s() %d\n", __func__, __LINE__);
+ struct amessage msg;
+ u8 *cmd_string;
+ /* __AUTH_SUCCESS: */
+
+ cmd_string = (u8 *)"shell:";
+ msg.command = A_OPEN;
+ msg.arg0 = adb.local_id;
+ msg.arg1 = 0;
+ msg.data_length = strlen((char const *)cmd_string) + 1;
+ int ret = adb_send_packet(&msg, cmd_string);
+ check_usb_status(ret);
+
+ memset(&msg, 0, 24);
+ ret = adb_recv((u8 *)&msg, 24, 1 * 100);
+ check_usb_status(ret);
+
+ if (msg.command != A_OKAY) {
+ log_error("A_OKAY error\n");
+ return 4;
+ }
+
+ ret = adb_recv((u8 *)&msg, 24, 1 * 100);
+ check_usb_status(ret);
+ if (msg.command != A_WRTE) {
+ log_error("A_WRTE error\n");
+ return 5;
+ }
+ adb.remote_id = msg.arg0;
+
+ ret = adb_recv(adb.buffer, msg.data_length, 1 * 100);
+ check_usb_status(ret);
+
+ msg.command = A_OKAY;
+ msg.arg0 = adb.local_id;
+ msg.arg1 = adb.remote_id;
+ msg.data_length = 0;
+ ret = adb_send_packet(&msg, NULL);
+ check_usb_status(ret);
+ return 0;
+}
+
+static u32 adb_ex_cmd(const char *cmd_string, u8 *echo_buffer, u32 max_len)
+{
+ log_info("%s\n", cmd_string);
+ int ret;
+ struct amessage msg;
+ msg.command = A_WRTE;
+ msg.arg0 = adb.local_id;
+ msg.arg1 = adb.remote_id;
+ msg.data_length = strlen(cmd_string);
+ ret = adb_send_packet(&msg, (u8 *)cmd_string);
+ check_usb_status(ret);
+ memset(&msg, 0, 24);
+ memset(echo_buffer, 0, max_len);
+ ret = adb_recv((u8 *)&msg, sizeof(msg), 3 * 100);
+ check_usb_status(ret);
+
+ if (msg.command != A_OKAY) {
+ return true;
+ }
+ u32 offset = 0;
+ do {
+ ret = adb_recv((u8 *)&msg, sizeof(msg), 3 * 100);
+ check_usb_status(ret);
+ if (msg.command != A_WRTE) {
+ log_info("command %x\n", msg.command);
+ return true;
+ }
+ if ((offset + msg.data_length) > max_len) {
+ log_info("%s", echo_buffer);
+ echo_buffer[offset] = 0;
+ offset = 0;
+ }
+
+ ret = adb_recv(&echo_buffer[offset], msg.data_length, 3 * 100);
+ check_usb_status(ret);
+ offset += msg.data_length;
+
+ if (msg.data_length == 0) {
+ log_info("no data_length\n");
+ break;
+ }
+
+ if (offset >= max_len) {
+
+ }
+ /* echo_buffer[offset] = '\n'; */
+ echo_buffer[offset] = 0;
+
+ if (echo_buffer[offset - 2] == 0x24 && echo_buffer[offset - 1] == 0x20) {
+ /* puts("end\n"); */
+ break;
+ } else if (echo_buffer[offset - 2] == 0x23 && echo_buffer[offset - 1] == 0x20) {
+ /* puts("end 1\n"); */
+ break;
+ }
+ msg.command = A_OKAY;
+ msg.arg0 = adb.local_id;
+ msg.arg1 = adb.remote_id;
+ msg.data_length = 0;
+ ret = adb_send_packet(&msg, NULL);
+ check_usb_status(ret);
+
+ } while (1);
+
+ msg.command = A_OKAY;
+ msg.arg0 = adb.local_id;
+ msg.arg1 = adb.remote_id;
+ msg.data_length = 0;
+ /* puts("exit\n"); */
+ return adb_send_packet(&msg, NULL);
+
+}
+#define APP_ACTIVITY_PATH "com.zh-jieli.gmaeCenter/com.zh-jieli.gameCenter.activity.guide.SplashActivity\n"
+#define APP_WEBSITE "http://www.zh-jieli.com\n"
+#define APP_BASH_IN_PATH "/sdcard/jilei/active.bash"
+#define APP_BASH_OUT_PATH "/data/local/tmp/active.bash"
+
+u32 adb_game_active()
+{
+ log_info("%s() %d\n", __func__, __LINE__);
+ u32 max_len = adb.max_len;;
+ u8 *adb_buffer = adb.buffer;
+ //1,启动app
+ adb_ex_cmd("am start -n " APP_ACTIVITY_PATH, adb_buffer, max_len);
+ puts((char *)adb_buffer);
+ //查找Error字符串,如果找到跳转网页下载app,否则执行adb指令
+ if (strstr((const char *)adb_buffer, "Error") != NULL) {
+ adb_ex_cmd("am start -a android.intent.action.VIEW -d " APP_WEBSITE, adb_buffer, max_len);
+ puts((char *)adb_buffer);
+ } else {
+ adb_ex_cmd("dd if=" APP_BASH_IN_PATH " of=" APP_BASH_OUT_PATH "\n", adb_buffer, max_len);
+ puts((char *)adb_buffer);
+ adb_ex_cmd("chown shell " APP_BASH_OUT_PATH";chmod 777 "APP_BASH_OUT_PATH "\n", adb_buffer, max_len);
+ puts((char *)adb_buffer);
+ adb_ex_cmd("trap \"\" HUP;sh "APP_BASH_OUT_PATH "&\n", adb_buffer, max_len);
+ puts((char *)adb_buffer);
+ }
+
+ return 0;
+}
+static void mtp_ptp_open_session(u32 is_mtp)
+{
+ /* usbh_bulk_send_blocking(ADB_HOST_EP, adb_device.extr_out, (u8 *)_open_session, 16); */
+ /* usbh_request_bulk_blocking(ADB_HOST_EP, adb_device.extr_in, get_data_buffer(), 12, 3); */
+
+ /* usbh_bulk_send_blocking(ADB_HOST_EP, adb_device.extr_out, (u8 *)get_device_info, sizeof(get_device_info)); */
+ /* usbh_request_bulk_blocking(ADB_HOST_EP, adb_device.extr_in, get_data_buffer(), 512, 3); */
+
+ /* usbh_request_bulk_blocking(ADB_HOST_EP, adb_device.extr_in, get_data_buffer(), 12, 3); */
+}
+
+static void adb_open_session()
+{
+ struct usb_host_device *host_dev = adb_device.private_data;
+ if (adb.extr_in && adb.extr_out) {
+ get_ms_extended_compat_id(host_dev, adb.buffer);
+ get_device_status(host_dev);
+ get_config_descriptor(host_dev, adb.buffer, 0xff);
+ /* mtp_ptp_open_session(ac6921_data_buffer[0x12] == 0x4d); */
+ }
+}
+u32 adb_process()
+{
+ adb.max_len = 1024;
+ adb.buffer = malloc(adb.max_len);
+ os_time_dly(20);
+ do {
+
+ adb_open_session();
+
+ if (adb_auth()) {
+ break;
+ }
+
+ if (adb_shell_login()) {
+ break;
+ }
+
+ adb_game_active();
+ log_info("adb active succ");
+ return 0;
+
+ } while (0);
+
+ free(adb.buffer);
+
+
+ log_info("adb active error");
+ return 1;
+}
+void adb_switch_aoa(u32 id)
+{
+ struct usb_host_device *host_dev = adb_device.private_data;
+ aoa_switch(host_dev);
+ /* usb_host_remount(id, 3, 30, 50, 1); */
+}
+#endif //TCFG_ADB_ENABLE
diff --git a/apps/common/device/usb/host/adb.h b/apps/common/device/usb/host/adb.h
new file mode 100644
index 0000000..26240a4
--- /dev/null
+++ b/apps/common/device/usb/host/adb.h
@@ -0,0 +1,73 @@
+#ifndef __ADB_H__
+#define __ADB_H__
+
+#include "system/task.h"
+#include "device/device.h"
+#include "usb/scsi.h"
+#include "usb_bulk_transfer.h"
+#include "usb/host/usb_host.h"
+struct adb_device_t {
+ u32 local_id;
+ u32 remote_id;
+ void *buffer;
+ u32 max_len;
+
+ u8 target_epin;
+ u8 target_epout;
+ u8 host_epin;
+ u8 host_epout;
+
+ u8 extr_in;
+ u8 extr_out;
+};
+u32 usb_adb_interface_ptp_mtp_parse(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
+int usb_adb_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
+u32 adb_process();
+void adb_switch_aoa(u32 id);
+
+#if 1
+#define A_SYNC 0x434e5953
+#define A_CNXN 0x4e584e43
+#define A_OPEN 0x4e45504f
+#define A_OKAY 0x59414b4f
+#define A_CLSE 0x45534c43
+#define A_WRTE 0x45545257
+#define A_AUTH 0x48545541
+//#define S_ID_LOCAL 0x00003456
+/* AUTH packets first argument */
+/* Request */
+#define ADB_AUTH_TOKEN 1
+/* Response */
+#define ADB_AUTH_SIGNATURE 2
+#define ADB_AUTH_RSAPUBLICKEY 3
+
+#define A_VERSION 0x01000000 // ADB protocol version
+
+#define ADB_VERSION_MAJOR 1 // Used for help/version information
+#define ADB_VERSION_MINOR 0 // Used for help/version information
+
+#else
+#define A_SYNC 0x53594e43
+#define A_CNXN 0x434e584e
+#define A_OPEN 0x4f50454e
+#define A_OKAY 0x4f4b4159
+#define A_CLSE 0x434c5345
+#define A_WRTE 0x57525445
+
+#define A_VERSION 0x00000001 // ADB protocol version
+
+#define ADB_VERSION_MAJOR 1 // Used for help/version information
+#define ADB_VERSION_MINOR 0 // Used for help/version information
+
+#endif
+
+struct amessage {
+ unsigned long int command; /* command identifier constant */
+ unsigned long int arg0; /* first argument */
+ unsigned long int arg1; /* second argument */
+ unsigned long int data_length; /* length of payload (0 is allowed) */
+ unsigned long int data_check; /* checksum of data payload */
+ unsigned long int magic; /* command ^ 0xffffffff */
+};
+
+#endif /*ADB_H*/
diff --git a/apps/common/device/usb/host/adb_rsa_key.c b/apps/common/device/usb/host/adb_rsa_key.c
new file mode 100644
index 0000000..06c0170
--- /dev/null
+++ b/apps/common/device/usb/host/adb_rsa_key.c
@@ -0,0 +1,115 @@
+#include "typedef.h"
+#include "app_config.h"
+#if TCFG_ADB_ENABLE
+static const u8 _open_session[] = {
+ 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
+};
+static const u8 get_device_info[] = {
+ 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00,
+};
+
+
+static const u8 adb_signatrue_data[][256] = {
+ {
+ 0xFA, 0xA6, 0xE3, 0x50, 0x3C, 0xC4, 0x95, 0xFE, 0xBB, 0x46, 0xE0, 0x9F, 0xD9, 0x9A, 0x18, 0xC1,
+ 0x28, 0x67, 0xA9, 0x46, 0xF8, 0x20, 0xBF, 0xDB, 0xFE, 0x6B, 0xC8, 0xC4, 0x0A, 0x09, 0xFA, 0x9A,
+ 0xCD, 0x51, 0xE3, 0x67, 0xD1, 0xDF, 0xD2, 0x92, 0xD3, 0x9E, 0xFA, 0x17, 0x76, 0x01, 0xF5, 0xE2,
+ 0xBD, 0x64, 0x9C, 0x92, 0x82, 0x4B, 0xE4, 0x27, 0x21, 0x22, 0x1A, 0x70, 0x99, 0x8F, 0xC5, 0xD5,
+ 0xE2, 0x02, 0x2C, 0xA4, 0x13, 0x08, 0x1E, 0x42, 0x83, 0x5C, 0x7E, 0x3C, 0x1F, 0x97, 0x1B, 0xAF,
+ 0x6F, 0x7E, 0x4F, 0xAB, 0xDA, 0x6A, 0x61, 0x56, 0x03, 0x79, 0xB5, 0xF0, 0x97, 0xEE, 0xEC, 0x88,
+ 0x6F, 0x9E, 0x8D, 0x41, 0xE2, 0x13, 0x9B, 0x21, 0xEE, 0x6F, 0x09, 0x81, 0x62, 0xC1, 0xB5, 0xE7,
+ 0xC2, 0x5C, 0x4A, 0x8C, 0x39, 0xAA, 0x50, 0x08, 0x48, 0xB5, 0x1D, 0xF6, 0x7C, 0x67, 0xD6, 0x39,
+ 0x63, 0x7E, 0x5E, 0x49, 0x3D, 0x9B, 0x49, 0x4B, 0x67, 0x8E, 0x06, 0x31, 0x07, 0x4E, 0x56, 0x8A,
+ 0xC4, 0x9D, 0x84, 0xA9, 0xF4, 0xFC, 0xE3, 0x2D, 0x1D, 0x2A, 0x98, 0x52, 0x40, 0x49, 0x93, 0x71,
+ 0xA7, 0x43, 0x0D, 0x78, 0xEB, 0xFA, 0x49, 0x7A, 0x39, 0xBF, 0xE4, 0x06, 0x08, 0x1B, 0x20, 0x84,
+ 0xDC, 0x64, 0xBB, 0xDE, 0x1A, 0x5E, 0x4B, 0xF8, 0x57, 0xBF, 0x9C, 0x8C, 0xB9, 0x1D, 0xEE, 0xB3,
+ 0x90, 0x17, 0x03, 0x8B, 0x3E, 0x9F, 0x8A, 0x23, 0xEC, 0x30, 0xA7, 0x24, 0x5E, 0x5B, 0x58, 0xAA,
+ 0x5A, 0xAE, 0xE2, 0x14, 0xC1, 0xAE, 0xA3, 0xF9, 0xAF, 0x70, 0xE0, 0x14, 0x7D, 0x73, 0x3B, 0x6D,
+ 0x9B, 0x06, 0x2F, 0xAA, 0xFF, 0x7A, 0x2A, 0x56, 0x6F, 0x91, 0x70, 0x6D, 0x4A, 0x18, 0x35, 0x51,
+ 0xD5, 0x5D, 0xFB, 0xA1, 0x8B, 0x03, 0xF2, 0x0C, 0x56, 0xF0, 0x5A, 0x4A, 0x08, 0x89, 0xFE, 0x86
+ },
+ {
+ 0x60, 0xE6, 0x4A, 0x3D, 0x12, 0xD1, 0x48, 0x25, 0x7D, 0x6E, 0x8E, 0x03, 0xE2, 0xC8, 0xE7, 0x66,
+ 0x96, 0xD7, 0xD3, 0xBF, 0xE6, 0x97, 0x13, 0x3A, 0x2D, 0x2B, 0x85, 0xE7, 0xDA, 0x5C, 0x87, 0xD8,
+ 0xDC, 0x88, 0xAC, 0xF7, 0xC3, 0xF0, 0x5A, 0xE8, 0x95, 0x66, 0x19, 0xA1, 0xA8, 0x2A, 0xE1, 0x70,
+ 0x13, 0xF0, 0x05, 0x59, 0x3D, 0x89, 0x04, 0x65, 0x08, 0x03, 0x9C, 0xDC, 0x71, 0x24, 0xC5, 0x9E,
+ 0x4D, 0x82, 0xD8, 0x72, 0x07, 0xFD, 0x8F, 0xD3, 0x37, 0x56, 0x8C, 0xB6, 0x01, 0xDB, 0x08, 0x5B,
+ 0xA3, 0x42, 0x8F, 0xF0, 0xCA, 0xDC, 0x80, 0xEB, 0x32, 0xC4, 0x67, 0x1F, 0x73, 0xAF, 0xF0, 0x56,
+ 0xBC, 0x89, 0x72, 0xB1, 0x7D, 0xDA, 0xA4, 0x79, 0x7D, 0x02, 0x35, 0x38, 0xBA, 0xA0, 0x36, 0xFE,
+ 0x5A, 0x70, 0x93, 0xF5, 0x10, 0x7A, 0x92, 0xE9, 0xD4, 0xB0, 0xED, 0xF3, 0x00, 0xD0, 0x27, 0x79,
+ 0x51, 0x54, 0x38, 0x2D, 0x4C, 0xAA, 0x27, 0xEF, 0xA7, 0x8A, 0x34, 0x4E, 0x4B, 0x29, 0x90, 0xC4,
+ 0x3E, 0xA8, 0x8D, 0x3D, 0x00, 0xD6, 0x84, 0x11, 0x17, 0x32, 0xD6, 0xE9, 0x33, 0x02, 0xCD, 0x04,
+ 0x35, 0x3F, 0x1A, 0xC3, 0x05, 0xCF, 0x6F, 0xF4, 0x39, 0x65, 0xE5, 0x6B, 0x88, 0x1E, 0x25, 0xA1,
+ 0xD7, 0xC0, 0x30, 0xE4, 0x0B, 0x2A, 0x61, 0x6D, 0x61, 0xF1, 0x93, 0xAE, 0xC3, 0x42, 0xDC, 0x15,
+ 0x1D, 0x87, 0x60, 0x09, 0x92, 0x64, 0xC1, 0x63, 0xAD, 0xCA, 0x36, 0x63, 0x0E, 0x69, 0x51, 0x45,
+ 0xD0, 0x18, 0x5E, 0x10, 0x88, 0x7B, 0xD9, 0xDE, 0xA3, 0x12, 0x85, 0xF9, 0x30, 0x01, 0x0A, 0xE1,
+ 0x82, 0xD1, 0x49, 0x44, 0xD9, 0x97, 0xE4, 0xF1, 0x55, 0x2D, 0xE2, 0xF3, 0x32, 0xC8, 0xA0, 0xC8,
+ 0x81, 0xB9, 0x02, 0x87, 0x5C, 0x19, 0xB7, 0x21, 0x6A, 0xB9, 0xB0, 0x81, 0x61, 0x8C, 0x35, 0x78
+ },
+ {
+ 0x0C, 0x7E, 0xDC, 0x78, 0x60, 0x1A, 0xC8, 0x9B, 0x3A, 0x23, 0x0B, 0x1D, 0x6F, 0xAE, 0x71, 0x6D,
+ 0xD8, 0x3C, 0xE9, 0xA3, 0x51, 0x90, 0xAA, 0x7B, 0x7E, 0x2F, 0x2B, 0xBD, 0x34, 0xF4, 0x43, 0x3F,
+ 0x77, 0xC4, 0x0E, 0x41, 0x04, 0xD9, 0xD4, 0x9C, 0xB3, 0xD2, 0x6B, 0xE1, 0xC6, 0xA8, 0xEF, 0x50,
+ 0x00, 0x11, 0xE1, 0x08, 0x8B, 0xB4, 0xF1, 0xE3, 0x3D, 0x56, 0x83, 0x07, 0x7F, 0xB8, 0x47, 0xF2,
+ 0x84, 0xD2, 0xA1, 0x50, 0x64, 0x5A, 0x08, 0x42, 0x36, 0x23, 0x09, 0x31, 0x9A, 0x6B, 0x61, 0x6F,
+ 0x60, 0x2C, 0xF2, 0x75, 0x4E, 0x6B, 0xB9, 0x15, 0xEE, 0x3C, 0x5E, 0xA2, 0x7F, 0xA0, 0x41, 0xFE,
+ 0x00, 0x6A, 0x30, 0x49, 0x2C, 0xEC, 0x17, 0x8B, 0x04, 0x32, 0xE9, 0x7A, 0x68, 0xA0, 0xF4, 0xDF,
+ 0x34, 0xF7, 0x1E, 0x6F, 0x19, 0x09, 0x37, 0x87, 0x99, 0xAA, 0x81, 0x1A, 0xCD, 0xF3, 0x1F, 0x89,
+ 0x50, 0xB2, 0x17, 0x52, 0x6D, 0x8E, 0xA6, 0x02, 0xC4, 0x2A, 0xAB, 0x3E, 0x5B, 0x38, 0x0C, 0x3F,
+ 0x50, 0xAA, 0x5F, 0xFE, 0x47, 0x04, 0xED, 0xCD, 0xEE, 0x7C, 0xD5, 0xED, 0x5F, 0x0E, 0xC6, 0x9C,
+ 0x79, 0x10, 0x11, 0x6F, 0x65, 0x58, 0x37, 0x95, 0x54, 0x50, 0x59, 0x68, 0x4C, 0x8E, 0xE7, 0x35,
+ 0xF0, 0x96, 0x5A, 0x21, 0x48, 0xB4, 0x53, 0x52, 0xFC, 0xA4, 0x7C, 0x2B, 0xB1, 0xE1, 0x54, 0x2C,
+ 0x42, 0x3B, 0x68, 0xBF, 0xBB, 0x68, 0x0D, 0x62, 0x16, 0x2F, 0xF5, 0xC8, 0x5F, 0x95, 0x11, 0xF2,
+ 0xDF, 0x03, 0x1E, 0xCB, 0x7C, 0xD0, 0x9C, 0xE9, 0x89, 0x62, 0xEA, 0xC5, 0x4B, 0xA9, 0xD5, 0xCC,
+ 0xD2, 0x42, 0x33, 0xA8, 0x7B, 0x2C, 0x56, 0xCF, 0xCE, 0x0D, 0x09, 0x64, 0x62, 0x3F, 0x58, 0x41,
+ 0x71, 0x79, 0x5D, 0x1D, 0xDF, 0x08, 0x0B, 0x36, 0x97, 0x16, 0x24, 0x20, 0x76, 0x9C, 0x9E, 0xEA
+ }
+};
+static const u8 adb_rsa_pub_key[] = {
+ 0x51, 0x41, 0x41, 0x41, 0x41, 0x46, 0x4F, 0x56, 0x4F, 0x6E, 0x49, 0x6C, 0x69, 0x51, 0x58, 0x44,
+ 0x73, 0x42, 0x43, 0x42, 0x31, 0x75, 0x6F, 0x68, 0x70, 0x2B, 0x52, 0x71, 0x6E, 0x6E, 0x59, 0x48,
+ 0x2F, 0x75, 0x45, 0x58, 0x34, 0x59, 0x6A, 0x50, 0x71, 0x52, 0x4D, 0x35, 0x4B, 0x75, 0x62, 0x56,
+ 0x50, 0x71, 0x66, 0x57, 0x35, 0x64, 0x56, 0x46, 0x33, 0x2B, 0x76, 0x57, 0x6B, 0x53, 0x4B, 0x71,
+ 0x35, 0x4C, 0x31, 0x42, 0x4F, 0x4E, 0x4D, 0x36, 0x4B, 0x4F, 0x31, 0x69, 0x31, 0x73, 0x69, 0x4F,
+ 0x54, 0x69, 0x34, 0x6C, 0x45, 0x30, 0x6F, 0x54, 0x6F, 0x74, 0x30, 0x41, 0x4B, 0x6E, 0x4D, 0x67,
+ 0x4E, 0x6A, 0x6F, 0x33, 0x45, 0x4D, 0x65, 0x72, 0x30, 0x6C, 0x57, 0x56, 0x54, 0x54, 0x43, 0x39,
+ 0x68, 0x52, 0x66, 0x67, 0x46, 0x65, 0x56, 0x73, 0x43, 0x32, 0x44, 0x74, 0x71, 0x62, 0x61, 0x6D,
+ 0x4A, 0x48, 0x63, 0x41, 0x66, 0x59, 0x77, 0x36, 0x54, 0x62, 0x4C, 0x44, 0x6C, 0x4B, 0x70, 0x6A,
+ 0x38, 0x34, 0x33, 0x63, 0x31, 0x59, 0x5A, 0x65, 0x59, 0x6D, 0x52, 0x56, 0x4D, 0x7A, 0x4D, 0x34,
+ 0x6E, 0x74, 0x49, 0x78, 0x64, 0x56, 0x33, 0x33, 0x76, 0x4B, 0x75, 0x39, 0x38, 0x34, 0x6A, 0x72,
+ 0x43, 0x41, 0x47, 0x68, 0x77, 0x4A, 0x41, 0x67, 0x4A, 0x46, 0x53, 0x41, 0x4B, 0x56, 0x59, 0x51,
+ 0x55, 0x33, 0x6A, 0x4C, 0x76, 0x41, 0x76, 0x57, 0x45, 0x6C, 0x59, 0x47, 0x37, 0x2F, 0x4B, 0x59,
+ 0x6D, 0x55, 0x34, 0x54, 0x71, 0x73, 0x70, 0x64, 0x76, 0x4C, 0x42, 0x6F, 0x65, 0x36, 0x68, 0x64,
+ 0x46, 0x44, 0x65, 0x76, 0x4D, 0x4D, 0x43, 0x63, 0x72, 0x6C, 0x44, 0x49, 0x66, 0x65, 0x45, 0x53,
+ 0x57, 0x68, 0x42, 0x56, 0x35, 0x67, 0x78, 0x6A, 0x57, 0x41, 0x70, 0x4D, 0x47, 0x67, 0x53, 0x71,
+ 0x53, 0x45, 0x6A, 0x70, 0x36, 0x79, 0x62, 0x6A, 0x33, 0x38, 0x50, 0x4C, 0x72, 0x76, 0x49, 0x51,
+ 0x48, 0x77, 0x2B, 0x66, 0x70, 0x6F, 0x51, 0x74, 0x6F, 0x4F, 0x4E, 0x65, 0x37, 0x6F, 0x68, 0x66,
+ 0x42, 0x77, 0x45, 0x66, 0x47, 0x46, 0x4E, 0x63, 0x33, 0x61, 0x70, 0x48, 0x50, 0x6E, 0x59, 0x53,
+ 0x47, 0x4F, 0x67, 0x70, 0x54, 0x78, 0x70, 0x57, 0x57, 0x75, 0x49, 0x42, 0x79, 0x2F, 0x67, 0x38,
+ 0x35, 0x2B, 0x65, 0x54, 0x30, 0x44, 0x61, 0x36, 0x53, 0x65, 0x71, 0x33, 0x67, 0x62, 0x4A, 0x59,
+ 0x64, 0x75, 0x52, 0x44, 0x65, 0x36, 0x5A, 0x39, 0x63, 0x4A, 0x77, 0x48, 0x79, 0x38, 0x43, 0x34,
+ 0x59, 0x79, 0x6B, 0x44, 0x56, 0x45, 0x4B, 0x6A, 0x39, 0x75, 0x52, 0x41, 0x41, 0x45, 0x59, 0x70,
+ 0x52, 0x6B, 0x74, 0x39, 0x66, 0x34, 0x79, 0x51, 0x4A, 0x31, 0x73, 0x4D, 0x48, 0x31, 0x5A, 0x75,
+ 0x4F, 0x55, 0x46, 0x4A, 0x46, 0x65, 0x74, 0x6B, 0x72, 0x67, 0x32, 0x44, 0x46, 0x61, 0x35, 0x30,
+ 0x50, 0x39, 0x48, 0x61, 0x78, 0x6F, 0x4D, 0x59, 0x30, 0x41, 0x79, 0x78, 0x7A, 0x51, 0x72, 0x53,
+ 0x77, 0x4D, 0x44, 0x79, 0x6E, 0x36, 0x64, 0x49, 0x65, 0x38, 0x65, 0x58, 0x46, 0x78, 0x51, 0x62,
+ 0x56, 0x4D, 0x4F, 0x6C, 0x4B, 0x36, 0x79, 0x33, 0x70, 0x6F, 0x2B, 0x4A, 0x4D, 0x42, 0x34, 0x79,
+ 0x4D, 0x42, 0x36, 0x51, 0x77, 0x30, 0x7A, 0x31, 0x35, 0x62, 0x6F, 0x58, 0x4C, 0x78, 0x4D, 0x4B,
+ 0x76, 0x4E, 0x59, 0x6E, 0x4B, 0x4E, 0x70, 0x69, 0x6F, 0x33, 0x67, 0x45, 0x78, 0x5A, 0x2B, 0x48,
+ 0x68, 0x57, 0x62, 0x43, 0x47, 0x69, 0x37, 0x64, 0x4A, 0x6C, 0x56, 0x47, 0x50, 0x6F, 0x74, 0x34,
+ 0x4D, 0x42, 0x45, 0x4C, 0x7A, 0x43, 0x38, 0x66, 0x4C, 0x55, 0x44, 0x69, 0x41, 0x43, 0x49, 0x54,
+ 0x37, 0x75, 0x31, 0x58, 0x31, 0x62, 0x68, 0x65, 0x71, 0x6C, 0x35, 0x59, 0x7A, 0x43, 0x30, 0x6C,
+ 0x67, 0x2F, 0x4B, 0x48, 0x5A, 0x7A, 0x62, 0x36, 0x6D, 0x63, 0x74, 0x4E, 0x2B, 0x34, 0x62, 0x52,
+ 0x74, 0x79, 0x4B, 0x35, 0x75, 0x52, 0x52, 0x4A, 0x70, 0x48, 0x45, 0x56, 0x63, 0x4B, 0x58, 0x57,
+ 0x50, 0x34, 0x30, 0x73, 0x31, 0x79, 0x38, 0x37, 0x75, 0x30, 0x6D, 0x49, 0x50, 0x4A, 0x6E, 0x73,
+ 0x39, 0x6D, 0x4F, 0x2F, 0x2F, 0x44, 0x41, 0x35, 0x4C, 0x32, 0x6D, 0x64, 0x77, 0x56, 0x79, 0x73,
+ 0x72, 0x74, 0x4B, 0x51, 0x69, 0x51, 0x37, 0x36, 0x57, 0x6A, 0x74, 0x59, 0x51, 0x63, 0x41, 0x73,
+ 0x46, 0x2B, 0x42, 0x54, 0x4E, 0x56, 0x48, 0x62, 0x41, 0x6E, 0x7A, 0x7A, 0x52, 0x75, 0x6C, 0x52,
+ 0x61, 0x43, 0x45, 0x78, 0x2B, 0x6E, 0x30, 0x49, 0x6A, 0x35, 0x34, 0x49, 0x45, 0x41, 0x4F, 0x75,
+ 0x55, 0x4B, 0x70, 0x6F, 0x61, 0x48, 0x71, 0x6F, 0x56, 0x4F, 0x33, 0x51, 0x42, 0x36, 0x52, 0x41,
+ 0x51, 0x7A, 0x4D, 0x67, 0x70, 0x44, 0x73, 0x41, 0x30, 0x58, 0x34, 0x4C, 0x6A, 0x4F, 0x32, 0x52,
+ 0x2B, 0x4D, 0x4B, 0x6F, 0x6D, 0x6F, 0x6C, 0x52, 0x5A, 0x6F, 0x32, 0x34, 0x57, 0x32, 0x41, 0x35,
+ 0x57, 0x2B, 0x30, 0x56, 0x4A, 0x77, 0x45, 0x41, 0x41, 0x51, 0x41, 0x3D, 0x20, 0x75, 0x6E, 0x6B,
+ 0x6E, 0x6F, 0x77, 0x6E, 0x40, 0x75, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0x00
+};
+#endif
diff --git a/apps/common/device/usb/host/aoa.c b/apps/common/device/usb/host/aoa.c
new file mode 100644
index 0000000..22fe000
--- /dev/null
+++ b/apps/common/device/usb/host/aoa.c
@@ -0,0 +1,232 @@
+/**
+ * @file aoa.c
+ * @brief https://source.android.com/devices/accessories/aoa
+ * http://www.hackermi.com/2015-04/aoa-analyse/
+ * Android 开放配件协议 1.0
+ * @author chenrixin@zh-jieli.com
+ * @version 1
+ * @date 2020-03-25
+ */
+
+#include "includes.h"
+#include "app_config.h"
+
+#include "usb_config.h"
+#include "usb/host/usb_host.h"
+#include "usb/usb_phy.h"
+#include "device_drive.h"
+#include "usb_ctrl_transfer.h"
+#include "usb_bulk_transfer.h"
+#include "usb_storage.h"
+#include "adb.h"
+#include "aoa.h"
+#include "usb_hid_keys.h"
+#if TCFG_AOA_ENABLE
+#include "gamebox.h"
+
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[AOA]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+//0x2D00 有一个接口,该接口有两个批量端点,用于输入和输出通信。
+//0x2D01 有两个接口,每个接口有两个批量端点,用于输入和输出通信。
+//第一个接口处理标准通信,
+//第二个接口则处理 ADB 通信。
+//要使用接口,请找到第一个批量输入和输出端点,
+//使用 SET_CONFIGURATION (0x09) 设备请求将设备配置的值设为 1,然后使用端点进行通信
+//
+
+
+static void aoa_timer_handler(void *priv);
+static u32 aoa_timer_id;
+static struct aoa_device_t aoa;
+static struct device aoa_device;
+
+static int set_power(struct usb_host_device *host_dev, u32 value)
+{
+ if (aoa_timer_id) {
+ usr_timer_del(aoa_timer_id);
+ aoa_timer_id = 0;
+ }
+ return DEV_ERR_NONE;
+}
+
+static int get_power(struct usb_host_device *host_dev, u32 value)
+{
+ return DEV_ERR_NONE;
+}
+static const struct interface_ctrl aoa_ctrl = {
+ .interface_class = USB_CLASS_AOA,
+ .set_power = set_power,
+ .get_power = get_power,
+ .ioctl = NULL,
+};
+
+static const struct usb_interface_info aoa_inf = {
+ .ctrl = (struct interface_ctrl *) &aoa_ctrl,
+ .dev.aoa = &aoa,
+};
+
+static const char *credetials[] = {"JieLiTec",
+ "GameBox",
+ "Android accessories devcie !",
+ "1.0.0",
+ "http://www.zh-jieli.com",
+ "1234567890ABCDEF",
+ };
+
+void aoa_switch(struct usb_host_device *host_dev)
+{
+ u16 version;
+ log_info("aoa_switch");
+ usb_get_aoa_version(host_dev, &version);
+ log_info("AOA version: %x", version);
+ for (int i = 0; i < 5; i++) {
+ log_info("send string [%d] %s", i, credetials[i]);
+ int r = usb_set_credentials(host_dev, credetials[i], i);
+ if (r < 0) {
+ break;
+ }
+ }
+ usb_switch2aoa(host_dev);
+}
+
+int usb_aoa_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+ struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
+ pBuf += sizeof(struct usb_interface_descriptor);
+ int len = 0;
+ const usb_dev usb_id = host_device2id(host_dev);
+ aoa_device.private_data = host_dev;
+ host_dev->interface_info[interface_num] = &aoa_inf;
+
+ for (int endnum = 0; endnum < interface->bNumEndpoints; endnum++) {
+ struct usb_endpoint_descriptor *end_desc = (struct usb_endpoint_descriptor *)pBuf;
+
+ if (end_desc->bDescriptorType != USB_DT_ENDPOINT ||
+ end_desc->bLength != USB_DT_ENDPOINT_SIZE) {
+ log_error("ep bDescriptorType = %d bLength = %d", end_desc->bDescriptorType, end_desc->bLength);
+ return -USB_DT_ENDPOINT;
+ }
+
+ len += USB_DT_ENDPOINT_SIZE;
+ pBuf += USB_DT_ENDPOINT_SIZE;
+
+ if ((end_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+ if (end_desc->bEndpointAddress & USB_DIR_IN) {
+ aoa.target_epin = end_desc->bEndpointAddress & 0x0f;
+#if defined(FUSB_MODE) && FUSB_MODE == 0
+ aoa.rxmaxp = end_desc->wMaxPacketSize;
+#endif
+ } else {
+ aoa.target_epout = end_desc->bEndpointAddress & 0x0f;
+#if defined(FUSB_MODE) && FUSB_MODE == 0
+ aoa.txmaxp = end_desc->wMaxPacketSize;
+#endif
+ }
+ }
+ }
+
+
+ return len;
+}
+
+static int aoa_tx_data(const u8 *pbuf, u32 len)
+{
+ struct usb_host_device *host_dev = aoa_device.private_data;
+ usb_dev usb_id = host_device2id(host_dev);
+ g_printf("TX:");
+ printf_buf(pbuf, len);
+ return usb_h_ep_write_async(usb_id, aoa.host_epout, 64, aoa.target_epout, pbuf, len, USB_ENDPOINT_XFER_BULK, 1);
+}
+static void aoa_epin_isr(struct usb_host_device *host_dev, u32 ep)
+{
+ u8 buffer[64] = {0};
+ usb_dev usb_id = host_device2id(host_dev);
+ u32 rx_len = usb_h_ep_read_async(usb_id, ep, aoa.target_epin, buffer, sizeof(buffer), USB_ENDPOINT_XFER_BULK, 0);
+ g_printf("RX:");
+ printf_buf(buffer, rx_len);
+
+ usb_h_ep_read_async(usb_id, ep, aoa.target_epin, NULL, 0, USB_ENDPOINT_XFER_BULK, 1);
+}
+
+#define Accessory_assigned_ID 0x0001
+
+u32 aoa_process(u32 mode, u32 id)
+{
+ struct usb_host_device *host_dev = aoa_device.private_data;
+ struct usb_device_descriptor device_desc;
+ usb_get_device_descriptor(host_dev, &device_desc);
+
+ if ((device_desc.idVendor == 0x18d1) &&
+ ((device_desc.idProduct & 0x2d00) == 0x2d00)) {
+ log_info("aoa mode ready idVendor:%x idProduct: %x",
+ device_desc.idVendor, device_desc.idProduct);
+ } else {
+ log_info("aoa switch idVendor:%x idProduct: %x",
+ device_desc.idVendor, device_desc.idProduct);
+
+ aoa_switch(host_dev);
+
+ usb_host_remount(id, 3, 30, 50, 1);
+ return 0;
+ }
+
+
+ usb_aoa_register_hid(host_dev, Accessory_assigned_ID, sizeof(hid_report_desc));
+
+ u32 offset = 0;
+ while (offset < sizeof(hid_report_desc)) {
+ u32 cnt = min(sizeof(hid_report_desc) - offset, 63);
+ usb_aoa_set_hid_report_desc(host_dev, Accessory_assigned_ID, offset, &hid_report_desc[offset], cnt);
+ offset += cnt;
+ }
+
+ aoa.host_epout = usb_get_ep_num(id, USB_DIR_OUT, USB_ENDPOINT_XFER_BULK);
+ aoa.host_epin = usb_get_ep_num(id, USB_DIR_IN, USB_ENDPOINT_XFER_BULK);
+ log_debug("D(%d)->H(%d)", aoa.target_epin, aoa.host_epin);
+ log_debug("H(%d)->D(%d)", aoa.host_epout, aoa.target_epout);
+
+ usb_h_set_ep_isr(host_dev, aoa.host_epin | USB_DIR_IN, aoa_epin_isr, host_dev);
+ u8 *ep_buffer = usb_h_get_ep_buffer(id, aoa.host_epin | USB_DIR_IN);
+ usb_h_ep_config(id, aoa.host_epin | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 1, 0, ep_buffer, 64);
+ int r = usb_h_ep_read_async(id, aoa.host_epin, aoa.target_epin, NULL, 0, USB_ENDPOINT_XFER_BULK, 1);
+
+ ep_buffer = usb_h_get_ep_buffer(id, aoa.host_epout | USB_DIR_OUT);
+ usb_h_ep_config(id, aoa.host_epout | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK, 0, 0, ep_buffer, 64);
+
+ aoa_timer_id = usr_timer_add((void *)0, aoa_timer_handler, 4, 0);
+ g_printf("aoa succ");
+
+ return 1;
+}
+
+
+static void aoa_timer_handler(void *priv)
+{
+ struct usb_host_device *host_dev = aoa_device.private_data;
+
+ u8 tx_buffer[32];
+ if (mouse_data_send == 1) {
+ tx_buffer[0] = MOUSE_POINT_ID;
+ memcpy(&tx_buffer[1], &mouse_data, sizeof(mouse_data));
+ usb_aoa_send_hid_event(host_dev, Accessory_assigned_ID, tx_buffer, sizeof(mouse_data) + 1);
+ memset(&mouse_data, 0, sizeof(mouse_data)) ;
+ mouse_data_send = 0;
+ }
+
+ tx_buffer[0] = TOUCH_SCREEN_ID;
+ struct touch_screen_t t;
+ memset(&t, 0, sizeof(t));
+ if (point_list_pop(&t)) {
+ memcpy(&tx_buffer[1], &t, sizeof(t));
+ usb_aoa_send_hid_event(host_dev, Accessory_assigned_ID, tx_buffer, sizeof(t) + 1);
+ }
+
+}
+#endif
diff --git a/apps/common/device/usb/host/aoa.h b/apps/common/device/usb/host/aoa.h
new file mode 100644
index 0000000..73fa8ad
--- /dev/null
+++ b/apps/common/device/usb/host/aoa.h
@@ -0,0 +1,20 @@
+#ifndef __AOA_H__
+#define __AOA_H__
+
+struct aoa_device_t {
+ u16 version;
+
+ u8 target_epin;
+ u8 target_epout;
+
+ u8 host_epin;
+ u8 host_epout;
+
+ struct adb_device_t *adb;
+};
+u32 aoa_process(u32 mode, u32 id);
+int usb_aoa_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
+
+
+
+#endif /*AOA_H*/
diff --git a/apps/common/device/usb/host/apple_mfi.h b/apps/common/device/usb/host/apple_mfi.h
new file mode 100644
index 0000000..55a54ea
--- /dev/null
+++ b/apps/common/device/usb/host/apple_mfi.h
@@ -0,0 +1,8 @@
+#ifndef _APPLE_MFI_H_
+#define _APPLE_MFI_H_
+
+int usb_apple_mfi_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
+
+
+
+#endif
diff --git a/apps/common/device/usb/host/audio.c b/apps/common/device/usb/host/audio.c
new file mode 100644
index 0000000..d9150e6
--- /dev/null
+++ b/apps/common/device/usb/host/audio.c
@@ -0,0 +1,820 @@
+#include "includes.h"
+#include "asm/includes.h"
+#include "app_config.h"
+#include "system/timer.h"
+#include "device/ioctl_cmds.h"
+#include "device_drive.h"
+#if TCFG_HOST_AUDIO_ENABLE
+#include "usb/host/usb_host.h"
+#include "usb_ctrl_transfer.h"
+#include "usb_bulk_transfer.h"
+#include "audio.h"
+#include "usb_config.h"
+
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[AUDIO]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+
+/* #define USB_AUDIO_PLAY_TEST */
+
+struct usb_audio_play {
+ u32 sample_rate;
+ u8 Cur_AlternateSetting;
+ u8 src_channel;
+ u8 play_state;
+ u8 mute;
+ u8 *send_buf;
+ u8 *usb_audio_play_buf;
+ u8 *usb_audio_play_buf2;
+ cbuffer_t usb_audio_play_cbuf;
+ u32 usb_audio_remain_len;
+ OS_SEM sem;
+ int (*put_buf)(void *ptr, u32 len);
+};
+struct usb_audio_mic {
+ u8 Cur_AlternateSetting;
+ u32 sample_rate;
+ u8 record_state;
+ u8 *usb_audio_record_buf;
+ u8 *usb_audio_record_buf2;
+ cbuffer_t usb_audio_record_cbuf;
+ int *(*get_buf)(void *ptr, u32 len);
+};
+struct usb_audio_info {
+ usb_dev usb_id;
+ struct usb_audio_play player;
+ struct usb_audio_mic microphone;
+};
+
+enum {
+ AUDIO_PLAY_IDLE = 0,
+ AUDIO_PLAY_START,
+ AUDIO_PLAY_STOP,
+ AUDIO_PLAY_PAUSE,
+};
+enum {
+ AUDIO_RECORD_IDLE = 0,
+ AUDIO_RECORD_START,
+ AUDIO_RECORD_STOP,
+ AUDIO_RECORD_PAUSE,
+};
+
+#define EP_MAX_PACKET_SIZE (192)
+
+struct usb_audio_info _usb_audio_info = {0};
+#define __this (&_usb_audio_info)
+
+struct audio_device_t audio_device[USB_MAX_HW_NUM][MAX_HOST_INTERFACE];
+
+static u8 ep_in_dma_buf[256] __attribute__((aligned(4)));
+static u8 ep_out_dma_buf[256] __attribute__((aligned(4)));
+
+static int set_power(struct usb_host_device *host_dev, u32 value)
+{
+ const usb_dev usb_id = host_device2id(host_dev);
+ return DEV_ERR_NONE;
+}
+
+static int get_power(struct usb_host_device *host_dev, u32 value)
+{
+ return DEV_ERR_NONE;
+}
+
+static const struct interface_ctrl uac_ctrl = {
+ .interface_class = USB_CLASS_AUDIO,
+ .set_power = set_power,
+ .get_power = get_power,
+ .ioctl = NULL,
+};
+
+static const struct usb_interface_info _uac_if[USB_MAX_HW_NUM][MAX_HOST_INTERFACE] = {
+ {
+ {
+ .ctrl = (struct interface_ctrl *) &uac_ctrl,
+ .dev.audio = &audio_device[0][0],
+ },
+ {
+ .ctrl = (struct interface_ctrl *) &uac_ctrl,
+ .dev.audio = &audio_device[0][1],
+ },
+ {
+ .ctrl = (struct interface_ctrl *) &uac_ctrl,
+ .dev.audio = &audio_device[0][2],
+ },
+ {
+ .ctrl = (struct interface_ctrl *) &uac_ctrl,
+ .dev.audio = &audio_device[0][3],
+ },
+ },
+};
+
+int usb_audio_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+ struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
+ const usb_dev usb_id = host_device2id(host_dev);
+
+ const struct usb_interface_info *usb_if = &_uac_if[usb_id][interface_num];
+ struct audio_streaming_t *as_t = NULL;
+ memset(usb_if->dev.p, 0, sizeof(struct audio_device_t));
+ host_dev->interface_info[interface_num] = usb_if;
+ usb_if->dev.audio->parent = host_dev;
+
+ if (interface->bInterfaceSubClass == USB_SUBCLASS_AUDIOCONTROL) {
+ log_info("audio control interface : %d\n", interface_num);
+ pBuf += sizeof(struct usb_interface_descriptor);
+ usb_if->dev.audio->subclass = interface->bInterfaceSubClass;
+ usb_if->dev.audio->interface_num = interface_num;
+
+ return sizeof(struct usb_interface_descriptor);
+ }
+
+ if (interface->bInterfaceSubClass == USB_SUBCLASS_AUDIOSTREAMING) {
+ usb_if->dev.audio->subclass = interface->bInterfaceSubClass;
+ usb_if->dev.audio->interface_num = interface_num;
+ if (interface->bNumEndpoints == 0) {
+ pBuf += sizeof(struct usb_interface_descriptor);
+ do {
+ struct usb_interface_descriptor *as_interface = (struct usb_interface_descriptor *)pBuf;
+ if (as_interface->bNumEndpoints == 0 || as_interface->bInterfaceClass != USB_CLASS_AUDIO) {
+ break;
+ }
+ log_info("audio streaming interface : %d ep_num:%d Altersetting:%d", interface_num, as_interface->bNumEndpoints, as_interface->bAlternateSetting);
+ as_t = &usb_if->dev.audio->as[as_interface->bAlternateSetting - 1];
+ as_t->bNumEndpoints = as_interface->bNumEndpoints;
+ pBuf += (USB_DT_INTERFACE_SIZE + UAC_DT_AS_HEADER_SIZE);
+ //解析format
+ struct uac_format_type_i_discrete_descriptor *uac_format_desc = (struct uac_format_type_i_discrete_descriptor *)pBuf;
+ if (uac_format_desc->bDescriptorSubtype == UAC_FORMAT_TYPE) {
+ as_t->bFormatType = uac_format_desc->bFormatType;
+ as_t->bNrChannels = uac_format_desc->bNrChannels;
+ as_t->bSubframeSize = uac_format_desc->bSubframeSize;
+ as_t->bBitResolution = uac_format_desc->bBitResolution;
+ as_t->bSamFreqType = uac_format_desc->bSamFreqType;
+ for (u8 i = 0; i < as_t->bSamFreqType; i++) {
+ memcpy(&as_t->tSamFreq[i], &uac_format_desc->tSamFreq[i], 3);
+ log_info("as bNrChannels:%d bBitResolution:%d tSamFreq : %d", as_t->bNrChannels, as_t->bBitResolution, as_t->tSamFreq[i]);
+ }
+ //Endpointdescriptor
+ pBuf += uac_format_desc->bLength;
+ /* for (int i = 0; i < as_t->bNumEndpoints; i++) { */
+ struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)pBuf;
+ if (endpoint->bDescriptorType == USB_DT_ENDPOINT) {
+ as_t->ep_Interval = endpoint->bInterval;
+ as_t->ep_max_packet_size = endpoint->wMaxPacketSize;
+ if (endpoint->bEndpointAddress & USB_DIR_IN) {
+ as_t->ep = endpoint->bEndpointAddress & 0xf;
+ log_info("ep in : %x\n", as_t->ep);
+ usb_if->dev.audio->support = MICROPHONE_SUPPORTED;
+ } else {
+ as_t->ep = endpoint->bEndpointAddress;
+ log_info("ep out : %x\n", as_t->ep);
+ usb_if->dev.audio->support = HEADPHONE_SUPPORTED;
+ }
+ pBuf += (USB_DT_ENDPOINT_AUDIO_SIZE + UAC_ISO_ENDPOINT_DESC_SIZE);
+ }
+ /* } */
+ } else {
+ log_error("uac_format_desc->bDescriptorSubtype err!!\n");
+ goto __exit;
+ }
+
+ } while (1);
+ /* log_info("lennnn:%d\n",pBuf - (u8 *)interface); */
+ return pBuf - (u8 *)interface ;
+ } else {
+ log_info("audio streaming interface : %d ep_num:%d Altersetting:%d\n", interface_num, interface->bNumEndpoints, interface->bAlternateSetting);
+ }
+
+ }
+
+__exit:
+ return USB_DT_INTERFACE_SIZE;
+
+}
+
+static struct audio_device_t *__find_microphone_interface(const struct usb_host_device *host_dev)
+{
+ struct audio_device_t *audio = NULL;
+ for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
+ const struct usb_interface_info *usb_if = host_dev->interface_info[i];
+ if (usb_if &&
+ (usb_if->ctrl->interface_class == USB_CLASS_AUDIO)) {
+ audio = usb_if->dev.audio;
+ if (audio->subclass == USB_SUBCLASS_AUDIOSTREAMING &&
+ audio->support == MICROPHONE_SUPPORTED) {
+ // find microphone
+ return audio;
+ }
+ }
+ }
+
+ return NULL;
+}
+static struct audio_device_t *__find_headphone_interface(const struct usb_host_device *host_dev)
+{
+ struct audio_device_t *audio = NULL;
+ for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
+ const struct usb_interface_info *usb_if = host_dev->interface_info[i];
+ if (usb_if &&
+ (usb_if->ctrl->interface_class == USB_CLASS_AUDIO)) {
+ audio = usb_if->dev.audio;
+ if (audio->subclass == USB_SUBCLASS_AUDIOSTREAMING &&
+ audio->support == HEADPHONE_SUPPORTED) {
+ // find headphone
+ return audio;
+ }
+ }
+ }
+
+ return NULL;
+}
+static u32 play_vol_convert(u16 v)
+{
+ //固定音量表,更换声卡需要修改音量表
+ const u16 vol_table[] = {
+ //0-100
+ 0xd300, //0
+ 0xd58f, 0xd7bf, 0xd9a8, 0xdb5b, 0xdce1, 0xde45, 0xdf8a, 0xe0b6, 0xe1cd, 0xe2d1,
+ 0xe3c5, 0xe4ab, 0xe583, 0xe651, 0xe714, 0xe7cd, 0xe87f, 0xe928, 0xe9ca, 0xea66,
+ 0xeafc, 0xeb8d, 0xec18, 0xec9e, 0xed20, 0xed9e, 0xee18, 0xee8e, 0xef00, 0xef6f,
+ 0xefdc, 0xf045, 0xf0ab, 0xf10f, 0xf171, 0xf1d0, 0xf22c, 0xf287, 0xf2e0, 0xf336,
+ 0xf38b, 0xf3de, 0xf42f, 0xf47e, 0xf4cc, 0xf518, 0xf563, 0xf5ad, 0xf5f5, 0xf63c,
+ 0xf681, 0xf6c6, 0xf709, 0xf74b, 0xf78c, 0xf7cb, 0xf80a, 0xf848, 0xf885, 0xf8c1,
+ 0xf8fc, 0xf936, 0xf96f, 0xf9a8, 0xf9df, 0xfa16, 0xfa4c, 0xfa81, 0xfab6, 0xfaea,
+ 0xfb1d, 0xfb50, 0xfb82, 0xfbb3, 0xfbe4, 0xfc14, 0xfc43, 0xfc72, 0xfca0, 0xfcce,
+ 0xfcfc, 0xfd28, 0xfd55, 0xfd80, 0xfdab, 0xfdd6, 0xfe01, 0xfe2a, 0xfe54, 0xfe7d,
+ 0xfea5, 0xfece, 0xfef5, 0xff1d, 0xff43, 0xff6a, 0xff90, 0xffb6, 0xffdb, 0x0000,
+ };
+
+ if (v <= 100) {
+ return vol_table[v];
+ }
+
+ for (int i = 0; i < sizeof(vol_table) / 2; i++) {
+ if (v <= vol_table[i]) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+void set_usb_audio_play_volume(u16 vol)
+{
+ const struct usb_host_device *host_dev = host_id2device(__this->usb_id);
+ u8 featureUnitID = 6;
+ usb_audio_volume_control(host_dev, featureUnitID, 1, play_vol_convert(vol));
+ usb_audio_volume_control(host_dev, featureUnitID, 2, play_vol_convert(vol));
+ if (vol == 0) {
+ __this->player.mute = 1;
+ usb_audio_mute_control(host_dev, featureUnitID, __this->player.mute); //mute
+ } else {
+ if (__this->player.mute == 1) {
+ __this->player.mute = 0;
+ usb_audio_mute_control(host_dev, featureUnitID, __this->player.mute);
+ }
+ }
+}
+
+#ifdef USB_AUDIO_PLAY_TEST
+static const s16 sin_48k[] = {
+ 0, 2139, 4240, 6270, 8192, 9974, 11585, 12998,
+ 14189, 15137, 15826, 16244, 16384, 16244, 15826, 15137,
+ 14189, 12998, 11585, 9974, 8192, 6270, 4240, 2139,
+ 0, -2139, -4240, -6270, -8192, -9974, -11585, -12998,
+ -14189, -15137, -15826, -16244, -16384, -16244, -15826, -15137,
+ -14189, -12998, -11585, -9974, -8192, -6270, -4240, -2139
+};
+#endif
+static void usb_audio_tx_isr(struct usb_host_device *host_dev, u32 ep)
+{
+ const usb_dev usb_id = host_device2id(host_dev);
+ struct audio_device_t *audio = NULL;
+ struct audio_streaming_t *as_t = NULL;
+ u16 ep_max_packet_size = 0;
+ u8 channel = 0;
+ u32 rlen = 0;
+ static u32 usb_audio_tx_len = 0;
+
+ if (__this->player.play_state != AUDIO_PLAY_START) {
+ return;
+ }
+
+ audio = __find_headphone_interface(host_dev);
+ if (!audio) {
+ log_error("no find headphone interface!");
+ return;
+ }
+
+ as_t = &audio->as[__this->player.Cur_AlternateSetting - 1];
+ /* ep_max_packet_size = as_t->ep_max_packet_size; */
+ ep_max_packet_size = EP_MAX_PACKET_SIZE;
+ channel = as_t->bNrChannels;
+
+ //iso send
+#ifdef USB_AUDIO_PLAY_TEST
+ //For Test
+ int tx_len = 0;
+#if 1 // 单声道双声道输出
+ s16 buf[240 / 2];
+ for (u8 i = 0, j = 0; i < 240 / 2; i += 2) {
+ buf[i] = sin_48k[j];
+ buf[i + 1] = sin_48k[j];
+ j++;
+ if (j >= sizeof(sin_48k) / sizeof(sin_48k[0])) {
+ j = 0;
+ }
+ }
+#else
+ //单声道直接输出
+ u8 buf[248];
+ do {
+ memcpy(&buf[tx_len], sin_48k, sizeof(sin_48k));
+ tx_len += sizeof(sin_48k);
+ } while (tx_len < ep_max_packet_size);
+#endif
+ usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, buf, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 0);
+#else
+ if (__this->player.usb_audio_remain_len == 0) {
+ cbuf_read_alloc(&__this->player.usb_audio_play_cbuf, &__this->player.usb_audio_remain_len);
+ usb_audio_tx_len = 0;
+ }
+ if (__this->player.usb_audio_remain_len) {
+ if (usb_audio_tx_len == 0) {
+ rlen = cbuf_read(&__this->player.usb_audio_play_cbuf, __this->player.usb_audio_play_buf2, __this->player.usb_audio_remain_len);
+ if (!rlen) {
+ __this->player.usb_audio_remain_len = 0;
+ usb_audio_tx_len = 0;
+ putchar('C');
+ usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, NULL, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 1);
+ os_sem_post(&__this->player.sem);
+ return;
+ }
+ os_sem_post(&__this->player.sem);
+
+ }
+ u8 *send_buf = __this->player.send_buf;
+ u8 *play_buf = __this->player.usb_audio_play_buf2;
+ if (channel == 2) {
+ if (__this->player.src_channel == 1) {
+ //源数据是单声道数据,转双声道输出
+ int j = 0;
+ for (u8 i = 0; i < ep_max_packet_size; i += 4) {
+ //left
+ *(send_buf + i) = *(play_buf + (usb_audio_tx_len + j));
+ *(send_buf + i + 1) = *(play_buf + (usb_audio_tx_len + j + 1));
+ //right
+
+ *(send_buf + i + 2) = *(play_buf + (usb_audio_tx_len + j));
+ *(send_buf + i + 3) = *(play_buf + (usb_audio_tx_len + j + 1));
+ j += 2;
+ }
+ usb_audio_tx_len += j;
+ usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, send_buf, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 0);
+ } else if (__this->player.src_channel == 2) {
+ //源数据是双声道数据,直接双声道输出
+ usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, play_buf + usb_audio_tx_len, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 0);
+ usb_audio_tx_len += ep_max_packet_size;
+ }
+ } else if (channel == 1) {
+ }
+ if (usb_audio_tx_len >= __this->player.usb_audio_remain_len) {
+ __this->player.usb_audio_remain_len = 0;
+ usb_audio_tx_len = 0;
+ }
+ } else {
+ //audio buf null ,send null packet
+ putchar('E');
+ usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, NULL, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 1);
+ }
+
+#endif
+}
+void set_vol_test(void *p)
+{
+ struct usb_host_device *host_dev = (struct usb_host_device *)p;
+ static u16 vol = 100;
+ set_usb_audio_play_volume(vol);
+ /* static u8 f = 0; */
+ /* void usb_audio_pause_play(void); */
+ /* void usb_audio_resume_play(void); */
+ /* if (!f) { */
+ /* usb_audio_pause_play(); */
+ /* } else { */
+ /* usb_audio_resume_play(); */
+ /* } */
+ /* f = !f; */
+ vol -= 10;
+}
+void audio_play_task(void *p)
+{
+ log_info(">>> Enter usb audio play task");
+ struct usb_host_device *host_dev = (struct usb_host_device *)p;
+ const usb_dev usb_id = host_device2id(host_dev);
+ u8 *ptr = NULL;
+ u32 wlen = 0;
+ u32 ret = 0;
+ struct audio_device_t *audio = NULL;
+ audio = __find_headphone_interface(host_dev);
+ struct audio_streaming_t *as_t = &audio->as[__this->player.Cur_AlternateSetting - 1];
+ /* u32 ep_max_packet_size = as_t->ep_max_packet_size; */
+ u32 ep_max_packet_size = EP_MAX_PACKET_SIZE;
+ log_info("ep max packet : %d\n", ep_max_packet_size);
+ if (__this->player.send_buf) {
+ free(__this->player.send_buf);
+ __this->player.send_buf = NULL;
+ }
+ __this->player.send_buf = zalloc(ep_max_packet_size);
+ u32 usb_audio_buf_size = ep_max_packet_size * 5; //预留5个包的缓存
+
+ /* sys_timer_add(host_dev,set_vol_test,5000); */
+ os_sem_create(&__this->player.sem, 0);
+ u32 host_ep = as_t->host_ep;
+ __this->player.play_state = AUDIO_PLAY_START;
+ //分配双缓存
+ // 一个缓存保存读卡的数据,一个用于usb发送
+ if (!__this->player.usb_audio_play_buf) {
+ __this->player.usb_audio_play_buf = zalloc(usb_audio_buf_size);
+ cbuf_init(&__this->player.usb_audio_play_cbuf, __this->player.usb_audio_play_buf, usb_audio_buf_size);
+ usb_h_ep_write_async(usb_id, host_ep, ep_max_packet_size, as_t->ep, NULL, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 1); //启动iso传输
+ }
+ if (!__this->player.usb_audio_play_buf2) {
+ __this->player.usb_audio_play_buf2 = zalloc(usb_audio_buf_size);
+ }
+ while (1) {
+ if (__this->player.Cur_AlternateSetting == 0 || __this->player.play_state != AUDIO_PLAY_START) {
+ putchar('C');
+ os_time_dly(50);
+ continue;
+ }
+ ptr = cbuf_write_alloc(&__this->player.usb_audio_play_cbuf, &wlen);
+ if (wlen) {
+ putchar('R');
+ ret = __this->player.put_buf(ptr, wlen);
+ if (ret != wlen) {
+ __this->player.play_state = AUDIO_PLAY_STOP;
+ goto __task_exit;
+
+ }
+ cbuf_write_updata(&__this->player.usb_audio_play_cbuf, wlen);
+ } else {
+ log_w("usb audio play buf not enough!\n");
+ }
+__task_exit:
+ os_sem_pend(&__this->player.sem, 0);
+ }
+}
+
+void usb_audio_start_play(const usb_dev usb_id, u8 channel, u8 bit_reso, u32 sample_rate)
+{
+ log_info(" usb audio play\n");
+ const struct usb_host_device *host_dev = host_id2device(usb_id);
+ struct audio_device_t *audio = NULL;
+ struct audio_streaming_t *as_t = NULL;
+ u8 *ep_buffer = ep_out_dma_buf;
+ u8 find_alternatesetting = 0;
+ audio = __find_headphone_interface(host_dev);
+ if (!audio) {
+ log_error("no find headphone interface!");
+ return;
+ }
+ for (u8 i = 0; i < ARRAY_SIZE(audio->as); i++) {
+ as_t = &audio->as[i];
+ if (as_t->bBitResolution == bit_reso) {
+ for (u8 j = 0; j < as_t->bSamFreqType; j++) {
+ if (as_t->tSamFreq[j] == sample_rate) {
+ find_alternatesetting = i + 1;
+ break;
+ }
+ }
+ }
+ }
+ if (!find_alternatesetting) {
+ log_e("can not find Alternatesetting,please check bit_reso and sample_rate\n");
+ return;
+ }
+
+ __this->usb_id = usb_id;
+ //端点分配
+ u32 host_ep = usb_get_ep_num(usb_id, USB_DIR_OUT, USB_ENDPOINT_XFER_ISOC);
+ ASSERT(host_ep != -1, "ep not enough");
+
+ __this->player.Cur_AlternateSetting = find_alternatesetting; //选择Alternatesetting
+ __this->player.sample_rate = sample_rate; //选择采样率
+ __this->player.src_channel = channel;
+ as_t = &audio->as[find_alternatesetting - 1];
+ u8 target_ep = as_t->ep;
+ u8 ep_interval = as_t->ep_Interval;
+ as_t->host_ep = host_ep;
+
+ usb_set_interface(host_dev, audio->interface_num, find_alternatesetting); //interface Alternatesetting
+ usb_audio_sampling_frequency_control(host_dev, target_ep, sample_rate);//设置采样率
+ //设置音量
+ /* usb_audio_volume_control(host_dev, 6, 1, vol_convert(5)); */
+ /* usb_audio_volume_control(host_dev, 6, 2, vol_convert(5)); */
+
+ log_info("H2D ep: %x --> %x interval: %d", host_ep, target_ep, ep_interval);
+ usb_h_set_ep_isr(host_dev, host_ep, usb_audio_tx_isr, host_dev);
+ usb_h_ep_config(usb_id, host_ep, USB_ENDPOINT_XFER_ISOC, 1, ep_interval, ep_buffer, sizeof(ep_out_dma_buf));
+ task_create(audio_play_task, host_dev, "uac_play");
+}
+
+void usb_audio_stop_play(const usb_dev usb_id)
+{
+ const struct usb_host_device *host_dev = host_id2device(usb_id);
+ usb_h_set_ep_isr(NULL, 0, NULL, NULL);
+ __this->player.put_buf(NULL, 0);
+ __this->player.Cur_AlternateSetting = 0;
+ __this->player.sample_rate = 0;
+ __this->player.src_channel = 0;
+ if (__this->player.usb_audio_play_buf) {
+ free(__this->player.usb_audio_play_buf);
+ __this->player.usb_audio_play_buf = NULL;
+ }
+ if (__this->player.usb_audio_play_buf2) {
+ free(__this->player.usb_audio_play_buf2);
+ __this->player.usb_audio_play_buf2 = NULL;
+ }
+ if (__this->player.send_buf) {
+ free(__this->player.send_buf);
+ __this->player.send_buf = NULL;
+ }
+ printf("\n[ debug ]--func=%s line=%d\n", __func__, __LINE__);
+ task_kill("uac_play");
+ printf("\n[ debug ]--func=%s line=%d\n", __func__, __LINE__);
+}
+void usb_audio_pause_play(void)
+{
+ __this->player.play_state = AUDIO_PLAY_PAUSE;
+}
+void usb_audio_resume_play(void)
+{
+ const struct usb_host_device *host_dev = host_id2device(__this->usb_id);
+ struct audio_device_t *audio = __find_headphone_interface(host_dev);
+ struct audio_streaming_t *as_t = &audio->as[__this->player.Cur_AlternateSetting - 1];
+ __this->player.play_state = AUDIO_PLAY_START;
+ usb_h_ep_write_async(__this->usb_id, as_t->host_ep, as_t->ep_max_packet_size, as_t->ep, NULL, as_t->ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 1); //重新启动传输
+}
+
+
+static u32 record_vol_convert(u16 v)
+{
+ //固定音量表,更换声卡需要修改音量表
+ const u16 vol_table[] = {
+ //0-100
+ 0xf400,
+ 0xf479, 0xf4ee, 0xf560, 0xf5cf, 0xf63a, 0xf6a3, 0xf709, 0xf76c, 0xf7cd, 0xf82b,
+ 0xf887, 0xf8e1, 0xf939, 0xf98f, 0xf9e4, 0xfa36, 0xfa87, 0xfad6, 0xfb23, 0xfb6f,
+ 0xfbba, 0xfc03, 0xfc4b, 0xfc91, 0xfcd6, 0xfd1a, 0xfd5d, 0xfd9f, 0xfde0, 0xfe1f,
+ 0xfe5e, 0xfe9b, 0xfed8, 0xff14, 0xff4e, 0xff88, 0xffc1, 0xfff9, 0x0003, 0x0069,
+ 0x00a3, 0x00de, 0x0119, 0x0155, 0x0193, 0x01d1, 0x0210, 0x0251, 0x0292, 0x02d5,
+ 0x0318, 0x035d, 0x03a3, 0x03eb, 0x0434, 0x047e, 0x04c9, 0x0517, 0x0565, 0x05b5,
+ 0x0607, 0x065b, 0x06b1, 0x0708, 0x0762, 0x07bd, 0x081b, 0x087c, 0x08de, 0x0943,
+ 0x09ab, 0x0a16, 0x0a84, 0x0af4, 0x0b69, 0x0be1, 0x0c5c, 0x0cdc, 0x0d60, 0x0de9,
+ 0x0e77, 0x0f0a, 0x0fa2, 0x1041, 0x10e7, 0x1195, 0x124a, 0x1308, 0x13d0, 0x14a3,
+ 0x1582, 0x166e, 0x176a, 0x1877, 0x1998, 0x1ad0, 0x1c24, 0x1d98, 0x1f33, 0x2100,
+ };
+
+ if (v <= 100) {
+ return vol_table[v];
+ }
+
+ for (int i = 0; i < sizeof(vol_table) / 2; i++) {
+ if (v <= vol_table[i]) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+void set_usb_audio_record_volume(u16 vol)
+{
+ const struct usb_host_device *host_dev = host_id2device(__this->usb_id);
+ u8 featureUnitID = 5;
+ usb_audio_volume_control(host_dev, featureUnitID, 0, record_vol_convert(vol));
+}
+
+static u32 write_file_len = 0;
+static void usb_audio_rx_isr(struct usb_host_device *host_dev, u32 ep)
+{
+ u8 buffer[192] = {0};
+ u8 *ptr = NULL;
+ int rlen, wlen = 0;
+ usb_dev usb_id = host_device2id(host_dev);
+ struct audio_device_t *audio = NULL;
+ struct audio_streaming_t *as_t = NULL;
+ audio = __find_microphone_interface(host_dev);
+ if (!audio) {
+ log_error("no find microphone interface!");
+ return;
+ }
+ if (__this->microphone.record_state != AUDIO_RECORD_START) {
+ return;
+ }
+ as_t = &audio->as[__this->microphone.Cur_AlternateSetting - 1];
+ u8 channel = as_t->bNrChannels;
+
+ u32 rx_len = usb_h_ep_read_async(usb_id, ep, as_t->ep, buffer, sizeof(buffer), USB_ENDPOINT_XFER_ISOC, 0);
+ /* g_printf("RX:%d\n",rx_len); */
+ /* printf_buf(buffer, rx_len); */
+ cbuf_write(&__this->microphone.usb_audio_record_cbuf, buffer, rx_len);
+ cbuf_write_alloc(&__this->microphone.usb_audio_record_cbuf, &wlen);
+ if (wlen == 0) {
+ putchar('O');
+ if (write_file_len) {
+ log_w("write againnnnn\n");
+ }
+ /* [> printf("R:%d W:%d\n", rx_len,wlen); <] */
+ cbuf_read_alloc(&__this->microphone.usb_audio_record_cbuf, &rlen);
+ cbuf_read(&__this->microphone.usb_audio_record_cbuf, __this->microphone.usb_audio_record_buf2, rlen);
+ write_file_len = rlen;
+ os_taskq_post_msg("uac_record", 2, 0x01, rlen);
+ /* return; */
+ }
+
+ usb_h_ep_read_async(usb_id, ep, as_t->ep, NULL, 0, USB_ENDPOINT_XFER_ISOC, 1); //触发下一个接收中断
+}
+void audio_record_task(void *p)
+{
+ log_info(">>> Enter usb audio record task");
+ struct usb_host_device *host_dev = (struct usb_host_device *)p;
+ const usb_dev usb_id = host_device2id(host_dev);
+ u8 *ptr = NULL;
+ u32 rlen = 0;
+ u32 ret = 0;
+ int msg[16];
+ struct audio_device_t *audio = NULL;
+ audio = __find_microphone_interface(host_dev);
+ struct audio_streaming_t *as_t = &audio->as[__this->microphone.Cur_AlternateSetting - 1];
+ /* u32 ep_max_packet_size = as_t->ep_max_packet_size; */
+ u32 ep_max_packet_size = EP_MAX_PACKET_SIZE;
+ log_info("ep max packet : %d\n", ep_max_packet_size);
+ u32 usb_audio_buf_size = ep_max_packet_size * 50;
+
+ u32 host_ep = as_t->host_ep;
+ u8 target_ep = as_t->ep;
+ //分配双缓存
+ // 一个缓存写卡的数据,一个用于usb接收
+ if (!__this->microphone.usb_audio_record_buf) {
+ __this->microphone.usb_audio_record_buf = zalloc(usb_audio_buf_size);
+ cbuf_init(&__this->microphone.usb_audio_record_cbuf, __this->microphone.usb_audio_record_buf, usb_audio_buf_size);
+
+ }
+ if (!__this->microphone.usb_audio_record_buf2) {
+ __this->microphone.usb_audio_record_buf2 = zalloc(usb_audio_buf_size);
+ }
+
+ usb_h_ep_read_async(usb_id, host_ep, target_ep, NULL, 0, USB_ENDPOINT_XFER_ISOC, 1); //启动iso
+ while (1) {
+ ret = os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
+ if (ret == OS_TASKQ) {
+ switch (msg[1]) {
+ case 0x01:
+ ptr = __this->microphone.usb_audio_record_buf2;
+ rlen = msg[2];
+ putchar('W');
+ __this->microphone.get_buf(ptr, rlen);
+ write_file_len = 0;
+ break;
+ }
+ }
+ }
+}
+void usb_audio_start_record(const usb_dev usb_id, u8 bit_reso, u32 sample_rate)
+{
+ log_info(" usb audio record\n");
+ const struct usb_host_device *host_dev = host_id2device(usb_id);
+ struct audio_device_t *audio = NULL;
+ struct audio_streaming_t *as_t = NULL;
+ u8 *ep_buffer = ep_in_dma_buf;
+ u8 find_alternatesetting = 0;
+ audio = __find_microphone_interface(host_dev);
+ if (!audio) {
+ log_error("no find microphone interface!");
+ return;
+ }
+ for (u8 i = 0; i < ARRAY_SIZE(audio->as); i++) {
+ as_t = &audio->as[i];
+ if (as_t->bBitResolution == bit_reso) {
+ for (u8 j = 0; j < as_t->bSamFreqType; j++) {
+ if (as_t->tSamFreq[j] == sample_rate) {
+ find_alternatesetting = i + 1;
+ break;
+ }
+ }
+ }
+ }
+ if (!find_alternatesetting) {
+ log_e("can not find Alternatesetting,please check bit_reso and sample_rate\n");
+ return;
+ }
+ //端点分配
+ u32 host_ep = usb_get_ep_num(usb_id, USB_DIR_IN, USB_ENDPOINT_XFER_ISOC);
+ ASSERT(host_ep != -1, "ep not enough");
+ __this->usb_id = usb_id;
+ host_ep = host_ep | USB_DIR_IN;
+
+ __this->microphone.Cur_AlternateSetting = find_alternatesetting; //选择Alternatesetting
+ __this->microphone.sample_rate = sample_rate; //选择采样率
+ as_t = &audio->as[find_alternatesetting - 1];
+ u8 target_ep = as_t->ep;
+ u8 ep_interval = as_t->ep_Interval;
+ as_t->host_ep = host_ep;
+
+ usb_set_interface(host_dev, audio->interface_num, find_alternatesetting); //interface 1 Alternatesetting 1
+ usb_audio_sampling_frequency_control(host_dev, target_ep, sample_rate);//设置采样率
+ //设置音量
+ /* usb_audio_volume_control(host_dev, 6, 1, vol_convert(5)); */
+ /* usb_audio_volume_control(host_dev, 6, 2, vol_convert(5)); */
+ log_info("D2H ep: %x --> %x", target_ep, host_ep);
+ usb_h_set_ep_isr(host_dev, host_ep, usb_audio_rx_isr, host_dev);
+ usb_h_ep_config(usb_id, host_ep, USB_ENDPOINT_XFER_ISOC, 1, ep_interval, ep_buffer, sizeof(ep_in_dma_buf));
+ task_create(audio_record_task, host_dev, "uac_record");
+ __this->microphone.record_state = AUDIO_RECORD_START;
+}
+void usb_audio_stop_record(const usb_dev usb_id)
+{
+ const struct usb_host_device *host_dev = host_id2device(usb_id);
+ usb_h_set_ep_isr(NULL, 0, NULL, NULL);
+ __this->microphone.get_buf(NULL, 0);
+ __this->microphone.Cur_AlternateSetting = 0;
+ __this->microphone.sample_rate = 0;
+ if (__this->microphone.usb_audio_record_buf) {
+ free(__this->microphone.usb_audio_record_buf);
+ __this->microphone.usb_audio_record_buf = NULL;
+ }
+ if (__this->microphone.usb_audio_record_buf2) {
+ free(__this->microphone.usb_audio_record_buf2);
+ __this->microphone.usb_audio_record_buf2 = NULL;
+ }
+ printf("\n[ debug ]--func=%s line=%d\n", __func__, __LINE__);
+ task_kill("uac_record");
+ printf("\n[ debug ]--func=%s line=%d\n", __func__, __LINE__);
+}
+void usb_audio_pause_record(void)
+{
+ __this->microphone.record_state = AUDIO_RECORD_PAUSE;
+}
+void usb_audio_resume_record(void)
+{
+ const struct usb_host_device *host_dev = host_id2device(__this->usb_id);
+ struct audio_device_t *audio = __find_microphone_interface(host_dev);
+ struct audio_streaming_t *as_t = &audio->as[__this->microphone.Cur_AlternateSetting - 1];
+ __this->microphone.record_state = AUDIO_RECORD_START;
+ usb_h_ep_read_async(__this->usb_id, as_t->host_ep, as_t->ep, NULL, 0, USB_ENDPOINT_XFER_ISOC, 1); //重新启动接收
+}
+
+void usb_audio_start_process(u32 id)
+{
+ usb_audio_start_play(id, 1, 16, 48000); //开启headphone
+ usb_audio_start_record(id, 16, 48000); //开启microphone
+}
+void usb_audio_stop_process(u32 id)
+{
+ usb_audio_stop_play(id);
+ usb_audio_stop_record(id);
+}
+
+
+static void usb_audio_event_handler(struct sys_event *event, void *priv)
+{
+ const char *audio = NULL;
+ switch (event->type) {
+ case SYS_DEVICE_EVENT:
+ if ((u32)event->arg == DEVICE_EVENT_FROM_USB_HOST) {
+ if ((event->u.dev.event == DEVICE_EVENT_IN) ||
+ (event->u.dev.event == DEVICE_EVENT_CHANGE)) {
+ audio = (const char *)event->u.dev.value;
+ usb_audio_start_process(audio[5] - '0');
+
+ } else if (event->u.dev.event == DEVICE_EVENT_OUT) {
+ log_error("device out %x", event->u.dev.value);
+ usb_audio_stop_process(audio[5] - '0');
+ }
+ break;
+ }
+ }
+}
+void usb_host_audio_init(int (*put_buf)(void *ptr, u32 len), int *(*get_buf)(void *ptr, u32 len))
+{
+ memset(__this, 0, sizeof(struct usb_audio_info));
+ __this->player.put_buf = put_buf;
+ __this->microphone.get_buf = get_buf;
+ register_sys_event_handler(SYS_DEVICE_EVENT, DEVICE_EVENT_FROM_USB_HOST, 2,
+ usb_audio_event_handler);
+}
+void usb_host_audio_exit()
+{
+ unregister_sys_event_handler(usb_audio_event_handler);
+ __this->player.put_buf = NULL;
+ __this->microphone.get_buf = NULL;
+}
+
+#endif
diff --git a/apps/common/device/usb/host/audio.h b/apps/common/device/usb/host/audio.h
new file mode 100644
index 0000000..9787161
--- /dev/null
+++ b/apps/common/device/usb/host/audio.h
@@ -0,0 +1,56 @@
+#ifndef __AUDIO_H__
+#define __AUDIO_H__
+
+#include "system/task.h"
+#include "device/device.h"
+#include "usb_bulk_transfer.h"
+#include "usb/host/usb_host.h"
+#include "usb/device/uac_audio.h"
+
+
+#define HEADPHONE_SUPPORTED 0x01
+#define MICROPHONE_SUPPORTED 0x02
+#define HEADSET_SUPPORTED 0x03
+
+struct audio_streaming_t {
+ u8 bNumEndpoints;
+ u8 bFormatType; /** FORMAT_TYPE_1 */
+ u8 bNrChannels; /** physical channels in the stream */
+ u8 bSubframeSize;
+ u8 bBitResolution;
+ u8 bSamFreqType;
+ u32 tSamFreq[8];
+ u8 host_ep; //主机传输端点
+ u8 ep; //从机端点(由描述符中指定)
+ u8 ep_Interval;
+ u16 ep_max_packet_size;
+};
+
+struct audio_device_t {
+ u8 interface_num; //接口号
+ u8 subclass;
+ u8 support;
+ void *parent;
+ struct audio_streaming_t as[8];
+};
+
+int usb_audio_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
+
+// API
+int usb_audio_play_put_buf(void *ptr, u32 len);
+int usb_audio_record_get_buf(void *ptr, u32 len);
+
+//headphone api
+void set_usb_audio_play_volume(u16 vol);
+void usb_audio_start_play(const usb_dev usb_id, u8 channel, u8 bit_reso, u32 sample_rate); //指定播放数据的声道数,位数,采样率
+void usb_audio_stop_play(const usb_dev usb_id);
+void usb_audio_pause_play(void);
+void usb_audio_resume_play(void);
+
+//microphone api
+void set_usb_audio_record_volume(u16 vol);
+void usb_audio_start_record(const usb_dev usb_id, u8 bit_reso, u32 sample_rate); //指定录制数据的位数,采样率
+void usb_audio_stop_record(const usb_dev usb_id);
+void usb_audio_pause_record(void);
+void usb_audio_resume_record(void);
+#endif
diff --git a/apps/common/device/usb/host/audio_demo.c b/apps/common/device/usb/host/audio_demo.c
new file mode 100644
index 0000000..0e1b4ca
--- /dev/null
+++ b/apps/common/device/usb/host/audio_demo.c
@@ -0,0 +1,111 @@
+#include "includes.h"
+#include "asm/includes.h"
+#include "app_config.h"
+#include "system/timer.h"
+#include "device/ioctl_cmds.h"
+#include "device_drive.h"
+#if TCFG_HOST_AUDIO_ENABLE
+#include "usb/host/usb_host.h"
+#include "usb_ctrl_transfer.h"
+#include "usb_bulk_transfer.h"
+#include "audio.h"
+#include "usb_config.h"
+
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[AUDIO]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+
+#define TEST_FILE_ENABLE (0) //从sd卡读数据; 录制数据至sd卡
+#if (TEST_FILE_ENABLE)
+static FILE *play_file = NULL;
+int usb_audio_play_put_buf(void *ptr, u32 len)
+{
+ int ret = 0;
+ if (ptr == NULL && len == 0) {
+ //err
+ if (play_file) {
+ fclose(play_file);
+ play_file = NULL;
+ return 0;
+ }
+ }
+ if (!play_file) {
+ play_file = fopen("storage/sd0/C/raw.pcm", "r"); //单声道
+ /* play_file = fopen("storage/sd0/C/raw2.pcm", "r"); //双声道 */
+ if (!play_file) {
+ log_e("fopen play file faild!\n");
+ return -1;
+ }
+ }
+ //读sd卡数据到播放缓存中
+ ret = fread(play_file, ptr, len);
+ if (ret != len) {
+ log_e(" file read buf err %d\n", ret);
+ fclose(play_file);
+ play_file = NULL;
+ return -1;
+ }
+
+ return len;
+}
+static FILE *record_file = NULL;
+int usb_audio_record_get_buf(void *ptr, u32 len)
+{
+#if (TEST_FILE_ENABLE)
+ int ret = 0;
+ static u32 cnt = 0;
+ if (!record_file) {
+ record_file = fopen("storage/sd0/C/record01.pcm", "w+");
+ cnt = 0;
+ if (!record_file) {
+ log_e("fopen play file faild!\n");
+ return -1;
+ }
+ }
+ putchar('W');
+ ret = fwrite(record_file, ptr, len);
+ if (ret != len) {
+ log_e(" file write buf err %d\n", ret);
+ fclose(record_file);
+ record_file = NULL;
+ return -1;
+ }
+ //test
+ if (cnt++ >= 800) {
+ cnt = 0;
+ log_info("stop record....\n");
+ fclose(record_file);
+ record_file = NULL;
+ }
+#endif
+
+ return len;
+}
+#else
+
+//将数据传入usb
+//ptr:usb数据指针
+//len:需要传入的数据长度
+int usb_audio_play_put_buf(void *ptr, u32 len)
+{
+ return len;
+}
+
+//从usb读取数据
+//ptr:usb数据指针
+//len:读取的数据长度
+int usb_audio_record_get_buf(void *ptr, u32 len)
+{
+ return len;
+}
+
+
+#endif
+
+#endif
diff --git a/apps/common/device/usb/host/hid.c b/apps/common/device/usb/host/hid.c
new file mode 100644
index 0000000..49a9cc0
--- /dev/null
+++ b/apps/common/device/usb/host/hid.c
@@ -0,0 +1,657 @@
+#include "includes.h"
+#include "asm/includes.h"
+#include "app_config.h"
+#include "system/timer.h"
+#include "device/ioctl_cmds.h"
+#include "device_drive.h"
+#if TCFG_HID_HOST_ENABLE
+#include "usb/host/usb_host.h"
+#include "usb_ctrl_transfer.h"
+#include "usb_bulk_transfer.h"
+#include "hid.h"
+#include "usb_config.h"
+#include "usb_hid_keys.h"
+
+#define MAIN_ITEM 0
+#define GLOBAL_ITEM 1
+#define LOCAL_ITEM 2
+
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[HID]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+
+struct hid_device_t hid_device[USB_MAX_HW_NUM][MAX_HOST_INTERFACE];
+
+static int set_power(struct usb_host_device *host_dev, u32 value)
+{
+ const usb_dev usb_id = host_device2id(host_dev);
+ memset(hid_device[usb_id], 0, sizeof(hid_device[usb_id]));
+ return DEV_ERR_NONE;
+}
+
+static int get_power(struct usb_host_device *host_dev, u32 value)
+{
+ return DEV_ERR_NONE;
+}
+
+static const struct interface_ctrl hid_ctrl = {
+ .interface_class = USB_CLASS_HID,
+ .set_power = set_power,
+ .get_power = get_power,
+ .ioctl = NULL,
+};
+
+static const struct usb_interface_info _usb_if[USB_MAX_HW_NUM][MAX_HOST_INTERFACE] = {
+ {
+ {
+ .ctrl = (struct interface_ctrl *) &hid_ctrl,
+ .dev.hid = &hid_device[0][0],
+ },
+ {
+ .ctrl = (struct interface_ctrl *) &hid_ctrl,
+ .dev.hid = &hid_device[0][1],
+ },
+ {
+ .ctrl = (struct interface_ctrl *) &hid_ctrl,
+ .dev.hid = &hid_device[0][2],
+ },
+ {
+ .ctrl = (struct interface_ctrl *) &hid_ctrl,
+ .dev.hid = &hid_device[0][3],
+ },
+ },
+#if USB_MAX_HW_NUM > 1
+ {
+ {
+ .ctrl = (struct interface_ctrl *) &hid_ctrl,
+ .dev.hid = &hid_device[1][0],
+ },
+ {
+ .ctrl = (struct interface_ctrl *) &hid_ctrl,
+ .dev.hid = &hid_device[1][1],
+ },
+ {
+ .ctrl = (struct interface_ctrl *) &hid_ctrl,
+ .dev.hid = &hid_device[1][2],
+ },
+ {
+ .ctrl = (struct interface_ctrl *) &hid_ctrl,
+ .dev.hid = &hid_device[1][3],
+ },
+ },
+#endif
+};
+
+static u8 interval[USB_MAX_HW_NUM][16];
+
+int usb_hid_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+ struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
+ pBuf += sizeof(struct usb_interface_descriptor);
+ int len = 0;
+ const usb_dev usb_id = host_device2id(host_dev);
+
+ struct usb_endpoint_descriptor *endpoint;
+
+ pBuf += 9;//hid desc;
+
+ const struct usb_interface_info *usb_if = &_usb_if[usb_id][interface_num];
+
+ memset(usb_if->dev.p, 0, sizeof(struct hid_device_t));
+
+ host_dev->interface_info[interface_num] = usb_if;
+ usb_if->dev.hid->parent = host_dev;
+
+ log_info("hid eps %d %d %x %x", interface->bNumEndpoints, interface_num, usb_if, usb_if->dev.p);
+
+ log_info("parent %x hid @ interface %d usb_if %x hid %x",
+ host_dev, interface_num, usb_if, usb_if->dev.hid);
+
+ if ((interface->bInterfaceProtocol == 0x02) ||
+ (interface->bInterfaceProtocol == 0x01)) { //mouse & keyboard
+
+ usb_if->dev.hid->bNumEndpoints = interface->bNumEndpoints;
+ usb_if->dev.hid->report_list[0].usage = interface->bInterfaceProtocol;
+ for (int i = 0 ; i < interface->bNumEndpoints; i++) {
+ endpoint = (struct usb_endpoint_descriptor *)pBuf;
+ if (USB_DIR_IN & endpoint->bEndpointAddress) {
+ const u8 ep = endpoint->bEndpointAddress & 0x0f;
+ usb_if->dev.hid->ep_pair[i] = ep;
+ interval[usb_id][ep] = endpoint->bInterval;
+ log_info("interfacenum = %d,endpoint = %x interval = %x",
+ interface->bInterfaceNumber, endpoint->bEndpointAddress, endpoint->bInterval);
+ }
+ pBuf += endpoint->bLength;
+ }
+ } else {
+ log_info("vendor");
+ host_dev->interface_info[interface_num] = NULL; //???
+ for (int i = 0 ; i < interface->bNumEndpoints; i++) {
+ endpoint = (struct usb_endpoint_descriptor *)pBuf;
+ if (USB_DIR_IN & endpoint->bEndpointAddress) {
+ /* interface_endpoint[interface->bInterfaceNumber] = endpoint->bEndpointAddress & 0x0f; */
+ log_info("interfacenum = %d,endpoint = %x interval = %x",
+ interface->bInterfaceNumber, endpoint->bEndpointAddress, endpoint->bInterval);
+ }
+ pBuf += endpoint->bLength;
+ }
+ return sizeof(struct usb_interface_descriptor);
+ }
+
+ return pBuf - (u8 *)interface;
+}
+
+static u32 _hid_report_parse(struct hid_device_t *hid, const u8 *report, u32 len)
+{
+ hid->report_count = 0;
+ struct report_info_t null_rpt;
+ struct report_info_t *const rpt = &null_rpt;
+
+ memset(rpt, 0, sizeof(*rpt));
+
+ unsigned char ops;
+ int index = 0;
+ u8 report_size = 0;
+ u8 report_count = 0;
+ u8 cur_ops_is_report_size_count = 0;
+ u8 old_ops_is_report_size_count = 0;
+ s8 cur_section_bit = 0;
+ u8 input_bit_index = 0;
+ u8 total_bits = 0;
+ u8 output_bit_index = 0;
+ u8 cur_usage = 0;
+ u32 undef_type = 0;
+ u8 undef_usage = 0;
+ u8 collection_deep = 0;
+
+ while (index < len) {
+ ops = (char)report[index++];
+ char bSize = ops & 0x03;
+ bSize = bSize == 3 ? 4 : bSize; // size is 4 when bSize is 3
+ char bType = (ops >> 2) & 0x03;
+ char bTag = (ops >> 4) & 0x0F;
+
+ cur_ops_is_report_size_count = 0;
+ char bSizeActual = 0;
+ int itemVal = 0;
+ for (int j = 0; j < bSize; j++) {
+ if (index + j < len) {
+ itemVal += report[index + j] << (8 * j);
+ bSizeActual++;
+ }
+ }
+ if (undef_type) {
+ undef_type ++;
+ if (bTag == 0x0A) {
+ undef_usage ++;
+ } else if (bTag == 0x0C) {
+ undef_usage --;
+ }
+ if (undef_usage == 0 && undef_type > 2) {
+ undef_type = 0;
+ }
+ index += bSize;
+ continue;
+ }
+ if (undef_type) {
+ index += bSize;
+ continue;
+ }
+ if (itemVal == 0xffb5) {
+ undef_type = 1;
+ index += bSize;
+ continue;
+ } else {
+ undef_type = 0;
+ }
+ if (bType == MAIN_ITEM) {
+ if (old_ops_is_report_size_count) {
+ cur_section_bit += report_size * report_count;
+ }
+ if (bTag == 0x08) {
+ /* log_info("input %X", itemVal); */
+ /* log_info("\tusage %x", cur_usage); */
+ /* log_info("\t\tcur_section_bit %d", cur_section_bit); */
+ if (rpt->usage == 0x02) { //mouse
+ if (cur_usage == 1) {
+ if (rpt->btn_start_bit == 0) {
+ rpt->btn_start_bit = total_bits ;
+ }
+ rpt->btn_width += cur_section_bit ;
+ /* log_info("btn_width %d-%d", rpt->btn_start_bit, rpt->btn_width); */
+ } else if ((cur_usage == 0x30) || (cur_usage == 0x31)) {
+
+ if (rpt->xy_start_bit == 0) {
+ rpt->xy_start_bit = total_bits;
+ }
+ rpt->xy_width = cur_section_bit;
+ /* log_info("xy_width %d-%d", rpt->xy_start_bit, rpt->xy_width); */
+ } else if (cur_usage == 0x38) {
+ if (rpt->wheel_start_bit == 0) {
+ rpt->wheel_start_bit = total_bits;
+ }
+ if (rpt->xy_width || cur_section_bit < 24) {
+ rpt->wheel_width = cur_section_bit;
+ /* log_info("wheel_width %d-%d", rpt->wheel_start_bit, rpt->wheel_width); */
+ } else {
+ rpt->wheel_width = rpt->xy_width = cur_section_bit / 3;
+
+ rpt->xy_start_bit = total_bits;
+ rpt->wheel_start_bit = rpt->xy_start_bit + rpt->xy_width * 2;
+ /* log_info("wheel_width %d-%d", rpt->wheel_start_bit, rpt->wheel_width); */
+ /* log_info("xy_width %d-%d", rpt->xy_start_bit, rpt->xy_width); */
+ }
+ } else if (cur_usage == 0xb8) {
+ rpt->wheel_width = rpt->xy_width = cur_section_bit / 4;
+ rpt->xy_start_bit = total_bits;
+ rpt->wheel_start_bit = rpt->xy_start_bit + rpt->xy_width * 2;
+ }
+ }
+ total_bits += cur_section_bit;
+ /* input_bit[input_bit_index++] = cur_section_bit; */
+ cur_section_bit = -1;
+ } else if (bTag == 0x09) {
+ /* log_info("OUTPUT %X", itemVal); */
+ /* log_info("\tusage %x", cur_usage); */
+ /* log_info("\t\tcur_section_bit %d", cur_section_bit); */
+ /* output_bit[output_bit_index++] = cur_section_bit; */
+ cur_section_bit = -1;
+ } else if (bTag == 0x0B) {
+ /* log_info("Feature %X", itemVal); */
+ /* log_info("\tusage %x", cur_usage); */
+ /* log_info("\t\tcur_section_bit %d", cur_section_bit); */
+ /* output_bit[output_bit_index++] = cur_section_bit; */
+ cur_section_bit = -1;
+ } else if (bTag == 0x0A) {
+ collection_deep ++ ;
+ log_info("Collection %d %x", collection_deep, rpt->usage);
+ } else if (bTag == 0x0C) {
+ collection_deep --;
+ log_info("End Collection %d %x", collection_deep, rpt->usage);
+ if (collection_deep == 0) {
+ if (rpt->usage == 0x02 ||
+ rpt->usage == 0x06 ||
+ rpt->usage == 0x07) {
+
+ memcpy(&hid->report_list[hid->report_count], rpt, sizeof(*rpt));
+ memset(rpt, 0, sizeof(*rpt));
+
+ hid->report_count ++;
+ }
+ }
+ if (index < len) {
+ continue;
+ }
+ } else {
+ log_info("MAIN_ITEM Unknown btag :%x", bTag);
+ return 1;
+ }
+ } else if (bType == GLOBAL_ITEM) {
+ /* log_info("GLOBAL_ITEM"); */
+ if (bTag == 0x00) {
+ /* log_info("Usage Page %x", itemVal); */
+
+ if (rpt->usage == 0x06) {
+ if (itemVal == 0x07) {
+ rpt->usage = 0x07;
+ log_info("re set type %x", 0x07);
+ }
+ }
+ if (itemVal == 0x02) {
+ rpt->usage = 0x02;
+ log_info("re set type %x", 0x02);
+ }
+
+ } else if (bTag == 0x01) {
+ //log_info("Logical Minimum %x", itemVal);
+ } else if (bTag == 0x02) {
+ //log_info("Logical Maximum %x", itemVal);
+ } else if (bTag == 0x03) {
+ /* log_info("Physical Minimum %x", itemVal); */
+ } else if (bTag == 0x04) {
+ /* log_info("Physical Maximum %x", itemVal); */
+ } else if (bTag == 0x05) {
+ /* log_info("Unit Exponent %x", itemVal); */
+ } else if (bTag == 0x06) {
+ /* log_info("Unit %x", itemVal); */
+ } else if (bTag == 0x07) {
+ /* log_info("Report Size %x", itemVal); */
+ report_size = itemVal;
+ cur_ops_is_report_size_count = 1;
+ } else if (bTag == 0x08) {
+ log_info("Report ID %x", itemVal, rpt->usage);
+ rpt->report_id = itemVal;
+ } else if (bTag == 0x09) {
+ /* log_info("Report Count %x", itemVal); */
+ report_count = itemVal;
+ cur_ops_is_report_size_count = 1;
+ } else if (bTag == 0x0A) {
+ /* log_info("Push %x", bSizeActual); */
+ } else if (bTag == 0x0B) {
+ /* log_info("Pop %x", bSizeActual); */
+ } else {
+ log_info("GLOBAL_ITEM Unknown btag :%x", bTag);
+ return 2;
+ }
+ } else if (bType == LOCAL_ITEM) {
+ /* log_info("LOCAL_ITEM"); */
+ if (bTag == 0x00) {
+ if (rpt->usage == 0) {
+ rpt->usage = itemVal;
+ log_info("set type %x", rpt->usage);
+ }
+ if (itemVal == 0x30) { //X
+ } else if (itemVal == 0x31) { //y
+ } else if (itemVal == 0x38) { //wheel
+ } else {
+ }
+ /* log_info("\t change usage %x -> %x", cur_usage, itemVal); */
+ cur_usage = itemVal;
+ if (!collection_deep) {
+ if (itemVal == 0x06 || itemVal == 0x07 || itemVal == 0x02) {
+ //仅限键盘和鼠标
+ rpt->usage = itemVal;
+ log_info("set typee %x", rpt->usage);
+ }
+ }
+ /* type = itemVal; */
+ } else if (bTag == 0x01) {
+ // log_info("Usage Minimum %x", itemVal);
+ } else if (bTag == 0x02) {
+ // log_info("Usage Maximum %x", itemVal);
+ } else if (bTag == 0x03) {
+ /* log_info("Designator Index %x", itemVal); */
+ } else if (bTag == 0x04) {
+ /* log_info("Designator Minimum %x", itemVal); */
+ } else if (bTag == 0x05) {
+ /* log_info("Designator Maximum %x", itemVal); */
+ } else if (bTag == 0x07) {
+ /* log_info("String Index %x", itemVal); */
+ } else if (bTag == 0x08) {
+ /* log_info("String Minimum %x", itemVal); */
+ } else if (bTag == 0x09) {
+ /* log_info("String Maximum %x", itemVal); */
+ } else if (bTag == 0x0A) {
+ /* log_info("Delimiter %x", itemVal); */
+ } else {
+ log_info("LOCAL_ITEM Unknown btag :%x", bTag);
+ return 3;
+ }
+ } else {
+ log_info("OTHER Unknown btag :%x", bTag);
+ return 4;
+ }
+ if (!cur_ops_is_report_size_count && old_ops_is_report_size_count) {
+ if (cur_section_bit != -1) {
+ cur_section_bit += report_size * report_count;
+ } else {
+ cur_section_bit = 0;
+ }
+ }
+ if (cur_section_bit == -1) {
+ cur_section_bit = 0;
+ }
+ old_ops_is_report_size_count = cur_ops_is_report_size_count;
+ index += bSize;
+
+ }
+ return 0;
+}
+static u32 hid_report_parse(struct hid_device_t *hid, const u8 *report, u32 len)
+{
+ u8 type = _hid_report_parse(hid, report, len);
+ for (int i = 0; i < hid->report_count; i++) {
+ struct report_info_t *rpt = &hid->report_list[i];
+ if (rpt->usage == 0x02) {
+ if (rpt->report_id == 0) {
+ rpt->report_id = 0xff;
+ }
+ rpt->btn_start_bit /= 8;
+ rpt->btn_width /= 8;
+ rpt->xy_start_bit /= 8;
+ rpt->xy_width /= 8;
+ rpt->wheel_start_bit /= 8;
+ rpt->wheel_width /= 8;
+
+ log_info("mouse report_id %d",
+ rpt->report_id);
+
+ log_info("btn_width %d-%d",
+ rpt->btn_start_bit, rpt->btn_width);
+ log_info("xy_width %d-%d",
+ rpt->xy_start_bit, rpt->xy_width);
+ log_info("wheel_width %d-%d",
+ rpt->wheel_start_bit, rpt->wheel_width);
+
+ if (rpt->btn_width != 2) {
+ rpt->btn_width = 1;
+ }
+
+ log_info("btn_width %d-%d",
+ rpt->btn_start_bit, rpt->btn_width);
+
+ } else if (rpt->usage == 6 || rpt->usage == 7) {
+ if (rpt->report_id == 0) {
+ rpt->report_id = 0xff;
+ }
+ log_info("keyboard report_id %d", rpt->report_id);
+ } else {
+ log_info("unknown usage %d", rpt->usage);
+ }
+ }
+ return 0;
+}
+
+void mouse_route(const struct mouse_data_t *p);
+/* __attribute__((weak)) void mouse_route(const struct mouse_data_t *p) */
+/* { */
+/* log_info("btn: %x x-y %d %d wheel %d ac_pan %d", */
+/* p->btn, p->x, p->y, p->wheel, p->ac_pan); */
+/* } */
+static void hid_convert_mouse(const struct report_info_t *mouse, const u8 *buffer)
+{
+ struct mouse_data_t mouse_data;
+ memset(&mouse_data, 0, sizeof(mouse_data));
+ if (mouse->report_id != 0xff) {
+ if (mouse->report_id != buffer[0]) {
+ log_error("report_id = %x buffer[0] = %x", mouse->report_id, buffer[0]);
+ return;
+ }
+ buffer++;
+ }
+ const u8 *ptr;
+ ptr = &buffer[mouse->btn_start_bit];
+ if (mouse->btn_width == 2) {
+ mouse_data.btn = ptr[0] | (ptr[1] << 8);
+ } else {
+ mouse_data.btn = ptr[0] ;
+ }
+ s16 tmp;
+ ptr = &buffer[mouse->xy_start_bit];
+ if (mouse->xy_width == 1 || mouse->xy_width == 2) {
+ mouse_data.x = (char)ptr[0];
+ mouse_data.y = (char)ptr[1];
+ } else if (mouse->xy_width == 4) {
+ mouse_data.x = ptr[0] | (ptr[1] << 8);
+ ptr += 2;
+ mouse_data.y = ptr[0] | (ptr[1] << 8);
+ } else if (mouse->xy_width == 3) {
+ tmp = (ptr[1] & 0xf) << 12 | ptr[0] << 4;
+ tmp = tmp >> 4;
+ mouse_data.x = tmp;
+
+ tmp = (ptr[2] << 8) | ((ptr[1] >> 4) << 4);
+ tmp = tmp >> 4;
+ mouse_data.y = tmp;
+ } else {
+ log_error("error mouse xy_width %d", mouse->xy_width);
+ }
+
+ ptr = &buffer[mouse->wheel_start_bit];
+
+ if (mouse->wheel_width == 1) {
+ mouse_data.wheel = (char)ptr[0];
+ } else {
+ mouse_data.wheel = ptr[0] | (ptr[1] << 8);
+ }
+
+ mouse_route(&mouse_data);
+}
+__attribute__((weak)) void keyboard_route(const u8 *p)
+{
+ log_info("keyboard_buffer:");
+ printf_buf(p, 12);
+}
+void hid_convert_krbd(const struct report_info_t *kbd, u8 *buffer)
+{
+#if 0
+ u8 keyboard_buffer[12];
+ memset(keyboard_buffer, 0, sizeof(keyboard_buffer));
+ if (kbd->report_id != 0xff) {
+ if (kbd->report_id != buffer[0]) {
+ log_error("report_id = %x buffer[0] = %x", kbd->report_id, buffer[0]);
+ return;
+ }
+ buffer++;
+ }
+
+ u8 idx = 0;
+ u8 index = 0;
+ int i = 0;
+ for (i = 0; i < 8; i++) {
+ if (buffer[0] & BIT(i)) {
+ keyboard_buffer[idx++] = 0xe0 + i;
+ }
+ }
+
+ if (buffer[1] == 0) {
+ buffer += 2;
+ }
+ index = idx;
+ for (; idx < 12; idx++) {
+ if (*buffer) {
+ keyboard_buffer[index] = *buffer;
+ index++;
+ }
+ buffer ++;
+ }
+ keyboard_route(keyboard_buffer);
+#else
+ if (kbd->report_id != 0xff) {
+ if (kbd->report_id != buffer[0]) {
+ log_error("report_id = %x buffer[0] = %x", kbd->report_id, buffer[0]);
+ return;
+ }
+ buffer++;
+ }
+ u8 keyboard_buffer[8];
+ memset(keyboard_buffer, 0, sizeof(keyboard_buffer));
+
+ keyboard_buffer[0] = *buffer;
+ buffer ++;
+
+ if (*buffer == 0) {
+ buffer ++;
+ }
+ keyboard_buffer[1] = 0;
+
+ /* memcpy(&keyboard_buffer[2], buffer, 6); */
+ u8 pos = 2;
+ for (int i = pos; i < 8; i++) {
+ if (*buffer) {
+ keyboard_buffer[pos] = *buffer;
+ pos++;
+ }
+ buffer++;
+ }
+ keyboard_route(keyboard_buffer);
+#endif
+}
+
+static void hid_route(const struct hid_device_t *hid, const u8 *buffer)
+{
+ for (int i = 0; i < hid->report_count; i++) {
+ if (hid->report_list[i].usage == 0x02) {
+ hid_convert_mouse(&hid->report_list[i], buffer);
+ } else if ((hid->report_list[i].usage == 0x06) ||
+ (hid->report_list[i].usage == 0x07)) {
+ hid_convert_krbd(&hid->report_list[i], buffer);
+ } else {
+ r_printf("usage %x", hid->report_list[i].usage);
+ }
+ }
+}
+static void hid_isr(struct usb_interface_info *usb_if, u32 ep)
+{
+ u8 buffer[64] = {0};
+ struct usb_host_device *host_dev = usb_if->dev.hid->parent;
+ usb_dev usb_id = host_device2id(host_dev);
+ u32 target_ep = usb_if->dev.hid->ep_pair[ep];
+ u32 rx_len = usb_h_ep_read_async(usb_id, ep, target_ep, buffer, 64, USB_ENDPOINT_XFER_INT, 0);
+
+ if (rx_len) {
+ hid_route(usb_if->dev.hid, buffer);
+ }
+ /* printf_buf(buffer, rx_len); */
+
+ usb_h_ep_read_async(usb_id, ep, target_ep, buffer, 8, USB_ENDPOINT_XFER_INT, 1);
+}
+void hid_process(u32 id)
+{
+ struct usb_host_device *host_dev = host_id2device(id);
+ u8 report[256 + 2];
+ u8 ep_pair[4];
+
+ for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
+ struct usb_interface_info *usb_if = host_dev->interface_info[i];
+ log_info("parent %x hid @ interface %d usb_if %x hid %x",
+ host_dev, i, usb_if, usb_if ? usb_if->dev.hid : 0);
+ if (usb_if &&
+ (usb_if->ctrl->interface_class == USB_CLASS_HID)) {
+ hid_set_idle(host_dev, i);
+ memset(report, 0, sizeof(report));
+ hid_get_report(host_dev, report, i, 0xff);
+ printf_buf(report, 256);
+ hid_report_parse(usb_if->dev.hid, report, 256);
+ memcpy(ep_pair, usb_if->dev.hid->ep_pair, 4);
+
+ if (usb_if->dev.hid->report_count == 0) {
+ continue;
+ }
+
+ for (int i = 0; i < usb_if->dev.hid->bNumEndpoints; i++) {
+
+ u32 host_ep = usb_get_ep_num(id, USB_DIR_IN, USB_ENDPOINT_XFER_INT);
+
+ ASSERT(host_ep != -1, "ep not enough");
+
+ u32 target_ep = ep_pair[i];
+
+ usb_if->dev.hid->ep_pair[host_ep] = target_ep;
+
+ log_info("D2H ep: %x --> %x interval %d",
+ target_ep, host_ep, interval[id][target_ep]);
+
+ usb_h_set_ep_isr(host_dev, host_ep | USB_DIR_IN, hid_isr, usb_if);
+
+ u8 *ep_buffer = usb_h_get_ep_buffer(id, host_ep | USB_DIR_OUT);
+ usb_h_ep_config(id, host_ep | USB_DIR_IN, USB_ENDPOINT_XFER_INT, 1,
+ interval[id][target_ep], ep_buffer, 64);
+ int r = usb_h_ep_read_async(id, host_ep, target_ep, NULL, 0, USB_ENDPOINT_XFER_INT, 1);
+ }
+ } else {
+ if (usb_if) {
+ log_error("error hid class %x", usb_if->ctrl->interface_class);
+ }
+ }
+ }
+
+}
+
+#endif
diff --git a/apps/common/device/usb/host/hid.h b/apps/common/device/usb/host/hid.h
new file mode 100644
index 0000000..e4c148f
--- /dev/null
+++ b/apps/common/device/usb/host/hid.h
@@ -0,0 +1,83 @@
+/**@file hid.h
+ * @brief hid驱动头文件(做主机)
+ * @details 结构体声明,功能函数声明
+ * @author jieli
+ * @date 2021-9-1
+ * @version V1.0
+ * @copyright Copyright(c)2010-2021 珠海市杰理科技股份有限公司
+ *********************************************************
+ * @attention
+ * 硬件平台:AC632N
+ * SDK版本:AC632N_V1.0.0_SDK
+ * @修改日志:
+ *
+ * Date Version Author Description
+ * 2021-9-1 1.0 jieli 创建初始版本
+ *
+ *
+ *********************************************************
+ */
+#ifndef __HID_H__
+#define __HID_H__
+
+#include "system/task.h"
+#include "device/device.h"
+#include "usb/scsi.h"
+#include "usb_bulk_transfer.h"
+#include "usb/host/usb_host.h"
+
+/**@struct report_info_t
+ * @brief 报告描述符包含的信息结构体\n
+ * 自定义一些私有数据信息存储在该结构体中
+ */
+struct report_info_t {
+ u8 report_id; ///
+#include "jiffies.h"
+#include "usb_config.h"
+#include "usb_bulk_transfer.h"
+#include "usb_ctrl_transfer.h"
+#include "usb_storage.h"
+#include "usb/host/usb_host.h"
+#include "usb/usb_phy.h"
+#include "app_config.h"
+#include "device_drive.h"
+
+#if USB_HOST_ENABLE
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+struct usb_request_block {
+ void *ptr;
+ u32 len;
+ u32 target_ep;
+ u16 rxmap;
+ u16 txmap;
+ u32 msg;
+ u32 async_mode;
+};
+static struct usb_request_block urb;
+
+u8 get_async_mode(void)
+{
+ u8 mode = BULK_ASYNC_MODE_EXIT ;
+#if UDISK_READ_512_ASYNC_ENABLE
+ local_irq_disable();
+ mode = urb.async_mode;
+ local_irq_enable();
+#endif
+ return mode;
+
+}
+void set_async_mode(u8 mode)
+{
+#if UDISK_READ_512_ASYNC_ENABLE
+ local_irq_disable();
+ urb.async_mode = mode;
+ local_irq_enable();
+#endif
+}
+static void usb_bulk_rx_isr(struct usb_host_device *host_dev, u32 ep)
+{
+ usb_dev usb_id = host_device2id(host_dev);
+ int l = min(urb.len, urb.rxmap);
+
+ l = usb_h_ep_read_async(usb_id, ep, urb.target_ep, urb.ptr, l, USB_ENDPOINT_XFER_BULK, 0);
+ /* g_printf("%s() %d %d", __func__, l, urb.len); */
+ if (l > 0) {
+ urb.len -= l;
+ if (urb.ptr) {
+ urb.ptr += l;
+ }
+ urb.msg = 0;
+ } else {
+ urb.msg = l;
+ urb.len = 0;
+ }
+
+ if (urb.len == 0) {
+ u32 async_mode = get_async_mode();
+
+ if (async_mode == BULK_ASYNC_MODE_EXIT) {
+ usb_sem_post(host_dev);
+ } else if (async_mode == BULK_ASYNC_MODE_SEM_PEND) {
+ if (urb.msg == 0) {
+ usb_sem_post(host_dev);
+ } else {
+ r_printf("usb async error");
+ }
+ }
+ } else {
+ usb_h_ep_read_async(usb_id, ep, urb.target_ep, urb.ptr, urb.len, USB_ENDPOINT_XFER_BULK, 1);
+ }
+}
+s32 usb_bulk_only_receive_async(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len)
+{
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ const usb_dev usb_id = host_device2id(host_dev);
+ u8 devnum = host_dev->private_data.devnum;
+
+ urb.ptr = pBuf;
+ urb.len = len;
+ urb.target_ep = target_ep;
+
+#ifdef CONFIG_USB_SUPPORT_MRX_TX
+ urb.rxmap = 1 * 1024;
+#else
+#if defined(FUSB_MODE) && FUSB_MODE == 0
+ urb.rxmap = rxmaxp;
+#else
+ urb.rxmap = 0x40;
+#endif
+#endif
+
+ urb.msg = -DEV_ERR_OFFLINE;
+
+ usb_h_set_ep_isr(host_dev, host_ep | USB_DIR_IN, usb_bulk_rx_isr, host_dev);
+ usb_set_intr_rxe(usb_id, host_ep);
+#ifdef USB_HW_20
+ usb_write_rxfuncaddr(usb_id, host_ep, devnum);
+#endif
+
+ int ret = usb_h_ep_read_async(usb_id, host_ep, target_ep, urb.ptr, len, USB_ENDPOINT_XFER_BULK, 1);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = usb_sem_pend(host_dev, 300);
+
+ usb_clr_intr_rxe(usb_id, host_ep);
+ usb_h_set_ep_isr(host_dev, host_ep | USB_DIR_IN, NULL, host_dev);
+ if (ret) {
+ return -DEV_ERR_TIMEOUT;
+ }
+ return urb.msg ? urb.msg : len;
+}
+
+/**
+ * @brief usb_bulk_receive_async_no_wait 启动USB Bulk 异步预读
+ * 不用等信号量,启动传输后返回
+ * @param device 设备句柄
+ * @param pBuf 读buffer缓冲区,芯片所有memory都可以
+ * @param len 需要预读的长度
+ *
+ * @return 负数表示失败
+ */
+s32 usb_bulk_receive_async_no_wait(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len)
+{
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ const usb_dev usb_id = host_device2id(host_dev);
+ u8 devnum = host_dev->private_data.devnum;
+
+ set_async_mode(BULK_ASYNC_MODE_SEM_PEND);
+ urb.ptr = pBuf;
+ urb.len = len;
+ urb.target_ep = target_ep;
+
+#ifdef CONFIG_USB_SUPPORT_MRX_TX
+ urb.rxmap = 1 * 1024;
+#else
+#if defined(FUSB_MODE) && FUSB_MODE == 0
+ urb.rxmap = rxmaxp;
+#else
+ urb.rxmap = 0x40;
+#endif
+#endif
+
+ urb.msg = -DEV_ERR_OFFLINE;
+
+ usb_h_set_ep_isr(host_dev, host_ep | USB_DIR_IN, usb_bulk_rx_isr, host_dev);
+ usb_set_intr_rxe(usb_id, host_ep);
+#ifdef USB_HW_20
+ usb_write_rxfuncaddr(usb_id, host_ep, devnum);
+#endif
+
+ int ret = usb_h_ep_read_async(usb_id, host_ep, target_ep, urb.ptr, len, USB_ENDPOINT_XFER_BULK, 1);
+ if (ret < 0) {
+ if (ret == -DEV_ERR_RXSTALL) {
+ ret = usb_clear_feature(host_dev, target_ep | USB_DIR_IN);
+ if (ret == 0) {
+ return -DEV_ERR_RXSTALL;
+ }
+ }
+ return ret;
+ }
+ return len;
+}
+static s32 _usb_bulk_only_receive(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len)
+{
+#if 0
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ const usb_dev usb_id = host_device2id(host_dev);
+ return usb_h_bulk_read(usb_id, host_ep, rxmaxp, target_ep, pBuf, len);
+#else
+ return usb_bulk_only_receive_async(device, host_ep, rxmaxp, target_ep, pBuf, len);
+#endif
+}
+s32 usb_bulk_only_receive(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len)
+{
+
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ int ret = _usb_bulk_only_receive(device, host_ep, rxmaxp, target_ep, pBuf, len);
+ if (ret == -DEV_ERR_RXSTALL) {
+ ret = usb_clear_feature(host_dev, target_ep | USB_DIR_IN);
+ if (ret == 0) {
+ return -DEV_ERR_RXSTALL;
+ }
+ }
+ return ret;
+}
+static void usb_bulk_tx_isr(struct usb_host_device *host_dev, u32 ep)
+{
+ usb_dev usb_id = host_device2id(host_dev);
+ int l = min(urb.len, urb.txmap);
+ l = usb_h_ep_write_async(usb_id, ep, urb.txmap, urb.target_ep, urb.ptr, l, USB_ENDPOINT_XFER_BULK, 0);
+
+ if (l > 0) {
+ urb.len -= l;
+ urb.ptr += l;
+ urb.msg = 0;
+ } else {
+ urb.msg = l;
+ urb.len = 0;
+ }
+
+ if (urb.len == 0) {
+ if (urb.msg || l == 0) {
+ usb_sem_post(host_dev);
+ }
+ }
+}
+s32 usb_bulk_only_send_async(struct device *device, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *pBuf, u32 len)
+{
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ const usb_dev usb_id = host_device2id(host_dev);
+ u8 devnum = host_dev->private_data.devnum;
+
+ urb.target_ep = target_ep;
+#ifdef CONFIG_USB_SUPPORT_MRX_TX
+ urb.txmap = 8 * 1024;
+#else
+#if defined(FUSB_MODE) && FUSB_MODE == 0
+ urb.txmap = rxmaxp;
+#else
+ urb.txmap = 0x40;
+#endif
+#endif
+
+
+ urb.msg = -DEV_ERR_OFFLINE;
+ urb.len = len - min(len, urb.txmap);
+ urb.ptr = (u8 *)pBuf + min(len, urb.txmap);
+
+
+ usb_h_set_ep_isr(host_dev, host_ep, usb_bulk_tx_isr, host_dev);
+ usb_set_intr_txe(usb_id, host_ep);
+#ifdef USB_HW_20
+ usb_write_txfuncaddr(usb_id, host_ep, devnum);
+#endif
+
+ int ret = usb_h_ep_write_async(usb_id, host_ep, txmaxp, target_ep, pBuf, min(len, urb.txmap), USB_ENDPOINT_XFER_BULK, 1);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = usb_sem_pend(host_dev, 250);
+
+ usb_clr_intr_txe(usb_id, host_ep);
+ usb_h_set_ep_isr(host_dev, host_ep, NULL, host_dev);
+
+ if (ret) {
+ r_printf("ret %d", ret);
+ return -DEV_ERR_TIMEOUT;
+ }
+ /* g_printf("%s() %d %d", __func__, urb.len, urb.msg); */
+ return urb.msg ? urb.msg : len;
+}
+/**
+ * @brief usb_bulk_only_send
+ *
+ * @param device
+ * @param host_ep 主机的端点号
+ * @param target_ep 目标设备的端点号
+ * @param pBuf
+ * @param len
+ *
+ * @return 负数失败
+ * 正数发送的字节数
+ */
+static s32 _usb_bulk_only_send(struct device *device, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *pBuf, u32 len)
+{
+#if 0
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ const usb_dev usb_id = host_device2id(host_dev);
+ return usb_h_bulk_write(usb_id, host_ep, txmaxp, target_ep, pBuf, len);
+#elif 0
+ if (len < 512) {
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ const usb_dev usb_id = host_device2id(host_dev);
+ return usb_h_bulk_write(usb_id, host_ep, txmaxp, target_ep, pBuf, len);
+ } else {
+ return usb_bulk_only_send_async(device, host_ep, txmaxp, target_ep, pBuf, len);
+ }
+#else
+ return usb_bulk_only_send_async(device, host_ep, txmaxp, target_ep, pBuf, len);
+#endif
+}
+s32 usb_bulk_only_send(struct device *device, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *pBuf, u32 len)
+{
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ int ret = _usb_bulk_only_send(device, host_ep, txmaxp, target_ep, pBuf, len);
+
+ if (ret == -DEV_ERR_TXSTALL) {
+ ret = usb_clear_feature(host_dev, target_ep);
+ if (ret == 0) {
+ return -DEV_ERR_TXSTALL;
+ }
+ }
+ return ret;
+
+}
+#endif
diff --git a/apps/common/device/usb/host/usb_bulk_transfer.h b/apps/common/device/usb/host/usb_bulk_transfer.h
new file mode 100644
index 0000000..c3e2dd6
--- /dev/null
+++ b/apps/common/device/usb/host/usb_bulk_transfer.h
@@ -0,0 +1,120 @@
+/**@file usb_bulk_transfer.h
+ * @brief usb_bulk_transfer批量传输头文件
+ * @details 功能函数声明
+ * @author jieli
+ * @date 2021-8-1
+ * @version V1.0
+ * @copyright Copyright(c)2010-2021 珠海市杰理科技股份有限公司
+ *********************************************************
+ * @attention
+ * 硬件平台:AC695N
+ * SDK版本:AC695N_V1.0.0_SDK
+ * @修改日志:
+ *
+ * Date Version Author Description
+ * 2021-8-1 1.0 jieli 创建初始版本
+ *
+ *
+ *********************************************************
+ */
+#ifndef __USB_BULK_TRANSFER_H__
+#define __USB_BULK_TRANSFER_H__
+#include "typedef.h"
+#include "device/device.h"
+
+
+/**@brief 批量传输只读取(异步模式)
+ * @param[in] device定义的结构体指针
+ * @param[in] host_ep 主机端点号
+ * @param[in] rxmaxp 接收端点最大包长
+ * @param[in] target_ep 目标端点号
+ * @param[in] *pBuf BUFFER指针
+ * @param[in] len 数据长度
+ * @return
+ * @par 示例:
+ * @code
+ * usb_bulk_only_receive_async(device, host_ep, rxmaxp, target_ep, pBuf, len);
+ * @encode
+ */
+s32 usb_bulk_only_receive_async(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len);
+
+/**@brief 批量传输只读取(普通模式)
+ * @param[in] device定义的结构体指针
+ * @param[in] host_ep 主机端点号
+ * @param[in] rxmaxp 接收端点最大包长
+ * @param[in] ep 目标端点号
+ * @param[in] *pBuf BUFFER指针
+ * @param[in] len 数据长度
+ * @return
+ * @par 示例:
+ * @code
+ * usb_bulk_only_receive(device, host_ep, rxmaxp, ep, pBuf, len);
+ * @encode
+ */
+s32 usb_bulk_only_receive(struct device *device, u8 host_ep, u16 rxmaxp, u8 ep, u8 *pBuf, u32 len);
+
+/**@brief 批量传输只发送(异步模式)
+ * @param[in] device定义的结构体指针
+ * @param[in] host_ep 主机端点号
+ * @param[in] txmaxp 发送端点最大包长
+ * @param[in] target_ep 目标端点号
+ * @param[in] *pBuf BUFFER指针
+ * @param[in] len 数据长度
+ * @return
+ * @par 示例:
+ * @code
+ * usb_bulk_only_send_async(device, host_ep, txmaxp, target_ep, pBuf, len);
+ * @encode
+ */
+s32 usb_bulk_only_send_async(struct device *device, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *pBuf, u32 len);
+
+/**@brief 批量传输只发送(普通模式)
+ * @param[in] device定义的结构体指针
+ * @param[in] ep 主机端点号
+ * @param[in] txmaxp 发送端点最大包长
+ * @param[in] ep 目标端点号
+ * @param[in] *pBuf BUFFER指针
+ * @param[in] len 数据长度
+ * @return
+ * @par 示例:
+ * @code
+ * usb_bulk_only_send(device, host_ep, txmaxp, ep, pBuf, len);
+ * @encode
+ */
+s32 usb_bulk_only_send(struct device *device, u8 host_ep, u16 txmaxp, u8 ep, const u8 *pBuf, u32 len);
+
+/**@brief 获取异步模式当前状态
+ * @param[in] 空
+ * @return 当前状态
+ * @par 示例:
+ * @code
+ * get_async_mode();
+ * @encode
+ */
+u8 get_async_mode(void);
+
+/**@brief 设置异步模式
+ * @param[in] mode 需要设置的模式
+ * @return 空
+ * @par 示例:
+ * @code
+ * set_async_mode(BULK_ASYNC_MODE_EXIT);退出异步模式
+ * @encode
+ */
+void set_async_mode(u8 mode);
+
+/**@brief 批量传输异步模式读取并且不等待
+ * @param[in] device定义的结构体指针
+ * @param[in] ep 主机端点号
+ * @param[in] rxmaxp 发送端点最大包长
+ * @param[in] target_ep 目标端点号
+ * @param[in] *pBuf BUFFER指针
+ * @param[in] len 数据长度
+ * @return
+ * @par 示例:
+ * @code
+ * usb_bulk_only_send(device, host_ep, rxmaxp, ep, pBuf, len);
+ * @encode
+ */
+s32 usb_bulk_receive_async_no_wait(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len);
+#endif
diff --git a/apps/common/device/usb/host/usb_ctrl_transfer.c b/apps/common/device/usb/host/usb_ctrl_transfer.c
new file mode 100644
index 0000000..900ee5d
--- /dev/null
+++ b/apps/common/device/usb/host/usb_ctrl_transfer.c
@@ -0,0 +1,637 @@
+/**
+ * @file usb_ctrl_transfer.c
+ * @brief usb 控制传输接口
+ * @author chenrixin@zh-jieli.com
+ * @version 1.00
+ * @date 2017-02-09
+ */
+
+#include "usb/host/usb_host.h"
+#include "usb_ctrl_transfer.h"
+#include "app_config.h"
+#include "device_drive.h"
+#include "gpio.h"
+#include "usb/scsi.h"
+
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#if USB_HOST_ENABLE
+
+_WEAK_
+void usb_dis_ep0_txdly(const usb_dev id)
+{
+}
+static void ep0_h_isr(struct usb_host_device *host_dev, u32 ep)
+{
+ usb_dev usb_id = host_device2id(host_dev);
+ usb_sem_post(host_dev);
+}
+/**
+ * @brief usb_ctlXfer
+ *
+ * @param host_dev
+ * @param urb
+ *
+ * @return
+ */
+static int usb_ctlXfer(struct usb_host_device *host_dev, struct ctlXfer *urb)
+{
+ u32 ret = DEV_ERR_NONE;
+ u8 reg = 0;
+ u32 data_len;
+ usb_dev usb_id = host_device2id(host_dev);
+ u8 devnum = host_dev->private_data.devnum;
+ u32 max_packet_size = host_dev->private_data.ep0_max_packet_size;
+
+ usb_write_faddr(usb_id, devnum);
+#ifdef USB_HW_20
+ usb_write_txfuncaddr(usb_id, 0, devnum);
+#endif
+
+ switch (urb->stage) {
+ case USB_PID_SETUP :
+ usb_write_ep0(usb_id, (u8 *)&urb->setup, 8);
+ reg = CSR0H_SetupPkt | CSR0H_TxPktRdy;
+ break;
+ case USB_PID_IN :
+ if (urb->setup.wLength) {
+ reg = CSR0H_ReqPkt;
+ } else {
+ reg = CSR0H_StatusPkt | CSR0H_ReqPkt;
+ }
+ break;
+ case USB_PID_OUT:
+ if (urb->setup.wLength) {
+ data_len = min(urb->setup.wLength, max_packet_size);
+ reg = CSR0H_TxPktRdy;
+ usb_write_ep0(usb_id, urb->buffer, data_len);
+ urb->setup.wLength -= data_len;
+ urb->buffer += data_len;
+ } else {
+ reg = CSR0H_StatusPkt | CSR0H_TxPktRdy;
+ }
+ break;
+ default :
+ break;
+ }
+
+#if USB_HOST_ASYNC
+ //config ep0 callback fun
+ usb_h_set_ep_isr(host_dev, 0, ep0_h_isr, host_dev);
+ usb_set_intr_txe(usb_id, 0);
+#endif
+
+#ifdef USB_HW_20
+ usb_write_csr0(usb_id, reg | CSR0H_DISPING);
+#else
+ usb_write_csr0(usb_id, reg);
+#endif
+
+ u32 st = 0;
+ u32 ot = usb_get_jiffies() + 500;
+ while (1) {
+ if (usb_host_timeout(ot)) {
+ log_error("time out %x\n", reg);
+ ret = -DEV_ERR_TIMEOUT;
+ goto __exit;
+ }
+ if (usb_h_dev_status(usb_id)) {
+ st ++;
+ } else {
+ st = 0;
+ }
+ if (((usb_read_devctl(usb_id) & BIT(2)) == 0) || (st > 1000)) {
+ log_error("usb%d_offline\n", usb_id);
+ ret = -DEV_ERR_OFFLINE;
+ goto __exit;
+ }
+
+#if USB_HOST_ASYNC
+ ret = usb_sem_pend(host_dev, 250); //wait isr
+ if (ret) {
+ log_error("usb%d_offline\n", usb_id);
+ ret = -DEV_ERR_OFFLINE;
+ goto __exit;
+ }
+#endif
+
+ reg = usb_read_csr0(usb_id);
+ if (reg & CSR0H_RxStall) {
+ log_error(" rxStall CSR0:0x%x", reg);
+ ret = -DEV_ERR_CONTROL_STALL;
+ goto __exit;
+ }
+ if (reg & CSR0H_Error) {
+ log_error(" Error CSR0:0x%x", reg);
+ usb_write_csr0(usb_id, 0);
+ ret = -DEV_ERR_CONTROL;
+ goto __exit;
+ }
+ if (USB_PID_IN == urb->stage) {
+
+ if (reg & CSR0H_RxPktRdy) {
+ data_len = usb_read_count0(usb_id);
+ data_len = min(data_len, urb->setup.wLength);
+ usb_read_ep0(usb_id, urb->buffer, data_len);;
+ urb->buffer += data_len;
+ urb->setup.wLength -= data_len;
+ if (data_len < max_packet_size) {
+ urb->setup.wLength = 0;
+ }
+ if (urb->setup.wLength) {
+#ifdef USB_HW_20
+ usb_write_csr0(usb_id, CSR0H_ReqPkt | CSR0H_DISPING);
+#else
+ usb_write_csr0(usb_id, CSR0H_ReqPkt);
+#endif
+ } else {
+#ifdef USB_HW_20
+ usb_write_csr0(usb_id, CSR0H_DISPING);
+#else
+ usb_write_csr0(usb_id, 0);
+#endif
+ break;
+ }
+ }
+ } else {
+ if (!(reg & CSR0H_TxPktRdy)) {
+ break;
+ }
+ }
+ }
+__exit:
+ usb_clr_intr_txe(usb_id, 0);
+ usb_dis_ep0_txdly(usb_id);
+ return ret;
+}
+/**
+ * @brief usb_control_transfers
+ *
+ * @param struct host_dev
+ * @param urb
+ *
+ * @return
+ */
+static int usb_control_transfers(struct usb_host_device *host_dev, struct ctlXfer *urb)
+{
+ usb_dev usb_id = host_device2id(host_dev);
+
+ int res;
+ /*SETUP*/
+
+ urb->stage = USB_PID_SETUP; //SETUP transaction
+
+ res = usb_ctlXfer(host_dev, urb);
+
+ if (res) {
+ return res;
+ }
+
+ /*IN or OUT*/
+ urb->stage = USB_PID_IN;
+
+
+ while (urb->setup.wLength) {
+ if (urb->setup.bRequestType & USB_DIR_IN) { //Request Direction
+ urb->stage = USB_PID_IN; //IN transaction
+
+ res = usb_ctlXfer(host_dev, urb);
+
+ if (res) {
+ return res;
+ }
+
+ urb->stage = USB_PID_OUT;
+ } else {
+ urb->stage = USB_PID_OUT; //OUT transaction
+
+ res = usb_ctlXfer(host_dev, urb);
+
+ if (res) {
+ return res;
+ }
+
+ urb->stage = USB_PID_IN;
+ }
+ }
+
+ res = usb_ctlXfer(host_dev, urb);
+
+ if (res) {
+ return res;
+ }
+
+ return DEV_ERR_NONE;
+}
+
+/**
+ * @brief usb_control_msg
+ *
+ * @param host_dev
+ * @param request
+ * @param requesttype
+ * @param value
+ * @param index
+ * @param data
+ * @param size
+ *
+ * @return
+ */
+int usb_control_msg(struct usb_host_device *host_dev,
+ u8 request, u8 requesttype,
+ u16 value, u16 index,
+ void *data, u16 size)
+{
+ struct ctlXfer urb;
+ urb.setup.bRequestType = requesttype;
+ urb.setup.bRequest = request;
+ urb.setup.wValue = cpu_to_le16(value);
+ urb.setup.wIndex = cpu_to_le16(index);
+ urb.setup.wLength = cpu_to_le16(size);
+ urb.buffer = data;
+
+ return usb_control_transfers(host_dev, &urb);
+
+}
+
+/**
+ * @brief usb_clear_feature
+ *
+ * @param host_dev
+ * @param ep
+ *
+ * @return
+ */
+int usb_clear_feature(struct usb_host_device *host_dev, u32 ep)
+{
+ return usb_control_msg(host_dev, USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, ep, NULL, 0);
+}
+
+int set_address(struct usb_host_device *host_dev, u8 devnum)
+{
+ return usb_control_msg(host_dev, USB_REQ_SET_ADDRESS, 0, devnum, 0, NULL, 0);
+}
+
+int usb_get_device_descriptor(struct usb_host_device *host_dev, struct usb_device_descriptor *desc)
+{
+ return usb_control_msg(host_dev,
+ USB_REQ_GET_DESCRIPTOR,
+ USB_DIR_IN,
+ (USB_DT_DEVICE << 8),
+ 0,
+ desc,
+ USB_DT_DEVICE_SIZE
+ );
+}
+
+int usb_get_string_descriptor(struct usb_host_device *host_dev, struct usb_device_descriptor *desc)
+{
+ int ret = DEV_ERR_NONE;
+#if 0
+ struct usb_private_data *private_data = host_dev->private_data ;
+ /**********get string language*********/
+ u8 buf[16];
+ memset(buf, 0x0, sizeof(buf));
+ ret = usb_control_msg(host_dev,
+ USB_REQ_GET_DESCRIPTOR,
+ USB_DIR_IN,
+ (USB_DT_STRING << 8),
+ 0,
+ desc,
+ sizeof(buf)
+ );
+ if (ret) {
+ return ret;
+ }
+ memcpy(&private_data->language, buf + 2, sizeof(private_data->language));
+
+ /**********get manufacturer string**********/
+ memset(private_data->manufacturer, 0x0, sizeof(private_data->manufacturer));
+ if (desc->iManufacturer) {
+ ret = usb_control_msg(host_dev,
+ USB_REQ_GET_DESCRIPTOR,
+ USB_DIR_IN,
+ (USB_DT_STRING << 8) | desc->iManufacturer,
+ 0,
+ private_data->manufacturer,
+ sizeof(private_data->manufacturer)
+ );
+ if (ret) {
+ return ret;
+ }
+ }
+ /**********get product string**********/
+ memset(private_data->product, 0x0, sizeof(private_data->product));
+ if (desc->iProduct) {
+ ret = usb_control_msg(host_dev,
+ USB_REQ_GET_DESCRIPTOR,
+ USB_DIR_IN,
+ (USB_DT_STRING << 8) | desc->iProduct,
+ 0,
+ private_data->product,
+ sizeof(private_data->product)
+ );
+ if (ret) {
+ return ret;
+ }
+ }
+#endif
+ return ret;
+}
+
+int set_configuration(struct usb_host_device *host_dev)
+{
+ return usb_control_msg(host_dev, USB_REQ_SET_CONFIGURATION, 0, 1, 0, NULL, 0);
+}
+int set_configuration_add_value(struct usb_host_device *host_dev, u16 value)
+{
+ return usb_control_msg(host_dev, USB_REQ_SET_CONFIGURATION, 0, value, 0, NULL, 0);
+}
+int get_config_descriptor(struct usb_host_device *host_dev, void *cfg_desc, u32 len)
+{
+ return usb_control_msg(host_dev,
+ USB_REQ_GET_DESCRIPTOR,
+ USB_DIR_IN,
+ (USB_DT_CONFIG << 8),
+ 0,
+ cfg_desc,
+ len);
+}
+
+int get_config_descriptor_add_value_l(struct usb_host_device *host_dev, void *cfg_desc, u32 len, u8 value_l)
+{
+ return usb_control_msg(host_dev,
+ USB_REQ_GET_DESCRIPTOR,
+ USB_DIR_IN,
+ (USB_DT_CONFIG << 8) | value_l,
+ 0,
+ cfg_desc,
+ len);
+}
+
+
+int get_msd_max_lun(struct usb_host_device *host_dev, void *lun)
+{
+ return usb_control_msg(host_dev,
+ USB_MSD_MAX_LUN,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0,
+ 0,
+ lun,
+ 1);
+}
+int set_msd_reset(struct usb_host_device *host_dev)
+{
+ return usb_control_msg(host_dev,
+ 0xff,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0,
+ 0,
+ NULL,
+ 0);
+}
+
+int hid_set_idle(struct usb_host_device *host_dev, u32 id)
+{
+ return usb_control_msg(host_dev, 0x0a, 0x21, 0, id << 8, NULL, 0);
+}
+int hid_get_report(struct usb_host_device *host_dev, u8 *report, u8 report_id, u16 report_len)
+{
+ return usb_control_msg(host_dev,
+ USB_REQ_GET_DESCRIPTOR,
+ USB_DIR_IN | USB_RECIP_INTERFACE,
+ 0x2200,
+ report_id,
+ report,
+ report_len);
+}
+int hid_set_output_report(struct usb_host_device *host_dev, u8 *report, u8 report_id, u8 report_len)
+{
+ return usb_control_msg(host_dev,
+ 0x09,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0x0201,
+ report_id,
+ report,
+ report_len);
+}
+int usb_set_remote_wakeup(struct usb_host_device *host_dev)
+{
+ return usb_control_msg(host_dev, USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
+ USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0);
+}
+int get_device_status(struct usb_host_device *host_dev)
+{
+ u16 status;
+ return usb_control_msg(host_dev, USB_REQ_GET_STATUS, USB_DIR_IN, 0, 0, (u8 *)&status, 2);
+}
+int usb_get_device_qualifier(struct usb_host_device *host_dev, u8 *buffer)
+{
+ return usb_control_msg(host_dev,
+ USB_REQ_GET_DESCRIPTOR,
+ USB_DIR_IN,
+ (USB_DT_DEVICE_QUALIFIER << 8),
+ 0,
+ buffer,
+ 0x0a);
+
+}
+#define AOA_CMD51 0x33
+#define AOA_CMD52 0x34
+#define AOA_CMD53 0x35
+
+
+
+
+int usb_get_aoa_version(struct usb_host_device *host_dev, u16 *version)
+{
+ return usb_control_msg(host_dev,
+ AOA_CMD51,
+ USB_DIR_IN | USB_TYPE_VENDOR,
+ 0,
+ 0,
+ version,
+ 2);
+}
+int usb_set_credentials(struct usb_host_device *host_dev, const char *string, int index)
+{
+ return usb_control_msg(host_dev,
+ AOA_CMD52,
+ USB_DIR_OUT | USB_TYPE_VENDOR,
+ 0,
+ index,
+ (u8 *)string,
+ strlen(string));
+}
+int usb_switch2aoa(struct usb_host_device *host_dev)
+{
+ return usb_control_msg(host_dev,
+ AOA_CMD53,
+ USB_DIR_OUT | USB_TYPE_VENDOR,
+ 0,
+ 0,
+ NULL,
+ 0);
+}
+int usb_switch2slave(struct usb_host_device *host_dev)
+{
+ return usb_control_msg(host_dev,
+ 0x51,
+ USB_DIR_OUT | USB_TYPE_VENDOR,
+ 0,
+ 0,
+ NULL,
+ 0);
+}
+/* Control request for registering a HID device.
+ * Upon registering, a unique ID is sent by the accessory in the
+ * value parameter. This ID will be used for future commands for
+ * the device
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_REGISTER_HID_DEVICE
+ * value: Accessory assigned ID for the HID device
+ * index: total length of the HID report descriptor
+ * data none
+ */
+#define ACCESSORY_REGISTER_HID 54
+int usb_aoa_register_hid(struct usb_host_device *host_dev, u16 value, u16 index)
+{
+ return usb_control_msg(host_dev,
+ ACCESSORY_REGISTER_HID,
+ USB_DIR_OUT | USB_TYPE_VENDOR,
+ value,
+ index,
+ NULL,
+ 0);
+}
+/* Control request for unregistering a HID device.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_REGISTER_HID
+ * value: Accessory assigned ID for the HID device
+ * index: 0
+ * data none
+ */
+#define ACCESSORY_UNREGISTER_HID 55
+int usb_aoa_unregister_hid(struct usb_host_device *host_dev, u16 value)
+{
+ return usb_control_msg(host_dev,
+ ACCESSORY_UNREGISTER_HID,
+ USB_DIR_OUT | USB_TYPE_VENDOR,
+ value,
+ 0,
+ NULL,
+ 0);
+}
+
+/* Control request for sending the HID report descriptor.
+ * If the HID descriptor is longer than the endpoint zero max packet size,
+ * the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
+ * commands. The data for the descriptor must be sent sequentially
+ * if multiple packets are needed.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_SET_HID_REPORT_DESC
+ * value: Accessory assigned ID for the HID device
+ * index: offset of data in descriptor
+ * (needed when HID descriptor is too big for one packet)
+ * data the HID report descriptor
+ */
+#define ACCESSORY_SET_HID_REPORT_DESC 56
+int usb_aoa_set_hid_report_desc(struct usb_host_device *host_dev, u16 value, u16 offset, const char *pbuf, u32 len)
+{
+ return usb_control_msg(host_dev,
+ ACCESSORY_SET_HID_REPORT_DESC,
+ USB_DIR_OUT | USB_TYPE_VENDOR,
+ value,
+ offset,
+ (u8 *)pbuf,
+ len);
+}
+
+/* Control request for sending HID events.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_SEND_HID_EVENT
+ * value: Accessory assigned ID for the HID device
+ * index: 0
+ * data the HID report for the event
+ */
+#define ACCESSORY_SEND_HID_EVENT 57
+int usb_aoa_send_hid_event(struct usb_host_device *host_dev, u16 value, const u8 *pbuf, u32 len)
+{
+ return usb_control_msg(host_dev,
+ ACCESSORY_SEND_HID_EVENT,
+ USB_DIR_OUT | USB_TYPE_VENDOR,
+ value,
+ 0,
+ (u8 *)pbuf,
+ len);
+}
+int get_ms_extended_compat_id(struct usb_host_device *host_dev, u8 *buffer)
+{
+ return usb_control_msg(host_dev,
+ 0x01,
+ USB_DIR_IN | USB_RECIP_DEVICE | USB_TYPE_VENDOR,
+ 0x0000,
+ 4,
+ buffer,
+ 0x28);
+}
+
+
+int usb_set_interface(struct usb_host_device *host_dev, u8 interface, u8 alternateSetting)
+{
+ log_info("%s Set Interface:%d AlternateSetting:%d", __func__, interface, alternateSetting);
+ return usb_control_msg(host_dev,
+ USB_REQ_SET_INTERFACE,
+ USB_RECIP_INTERFACE,
+ alternateSetting,
+ interface,
+ NULL,
+ 0);
+
+}
+
+int usb_audio_sampling_frequency_control(struct usb_host_device *host_dev, u32 ep, u32 sampe_rate)
+{
+ log_info("%s ep:%d sampe_rate:%d", __func__, ep, sampe_rate);
+ return usb_control_msg(host_dev,
+ 1,
+ USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
+ 0x0100,
+ ep,
+ &sampe_rate,
+ 3);
+}
+int usb_audio_volume_control(struct usb_host_device *host_dev, u8 feature_id, u8 channel_num, u16 volume)
+{
+ log_info("%s featureID:%d vol:%x", __func__, feature_id, volume);
+ return usb_control_msg(host_dev,
+ 1,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ (0x02 << 8) | channel_num,
+ feature_id << 8,
+ &volume,
+ 2);
+}
+int usb_audio_mute_control(struct usb_host_device *host_dev, u8 feature_id, u8 mute)
+{
+ log_info("%s featureID:%d mute:%d", __func__, feature_id, mute);
+ return usb_control_msg(host_dev,
+ 1,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0x0100,
+ feature_id << 8,
+ &mute,
+ 1);
+}
+#endif
diff --git a/apps/common/device/usb/host/usb_ctrl_transfer.h b/apps/common/device/usb/host/usb_ctrl_transfer.h
new file mode 100644
index 0000000..5758ade
--- /dev/null
+++ b/apps/common/device/usb/host/usb_ctrl_transfer.h
@@ -0,0 +1,384 @@
+/**@file usb_ctrl_transfer.h
+ * @brief usb_ctrl_transfer控制传输头文件
+ * @details 功能函数声明
+ * @author jieli
+ * @date 2021-8-1
+ * @version V1.0
+ * @copyright Copyright(c)2010-2021 珠海市杰理科技股份有限公司
+ *********************************************************
+ * @attention
+ * 硬件平台:AC695N
+ * SDK版本:AC695N_V1.0.0_SDK
+ * @修改日志:
+ *
+ * Date Version Author Description
+ * 2021-8-1 1.0 jieli 创建初始版本
+ *
+ *
+ *********************************************************
+ */
+#ifndef __USB_CTRL_TRANSFER_H__
+#define __USB_CTRL_TRANSFER_H__
+
+#include "usb/ch9.h"
+#include "usb/usb_phy.h"
+#include "device/device.h"
+#include "usb_config.h"
+
+
+/*
+ * USB Packet IDs (PIDs)
+ */
+#define USB_PID_EXT 0xf0 /* USB 2.0 LPM ECN */
+#define USB_PID_OUT 0xe1
+#define USB_PID_ACK 0xd2
+#define USB_PID_DATA0 0xc3
+#define USB_PID_PING 0xb4 /* USB 2.0 */
+#define USB_PID_SOF 0xa5
+#define USB_PID_NYET 0x96 /* USB 2.0 */
+#define USB_PID_DATA2 0x87 /* USB 2.0 */
+#define USB_PID_SPLIT 0x78 /* USB 2.0 */
+#define USB_PID_IN 0x69
+#define USB_PID_NAK 0x5a
+#define USB_PID_DATA1 0x4b
+#define USB_PID_PREAMBLE 0x3c /* Token mode */
+#define USB_PID_ERR 0x3c /* USB 2.0: handshake mode */
+#define USB_PID_SETUP 0x2d
+#define USB_PID_STALL 0x1e
+#define USB_PID_MDATA 0x0f /* USB 2.0 */
+
+
+
+struct ctlXfer {
+ struct usb_ctrlrequest setup; ///<控制请求
+ void *buffer; ///<控制请求的data
+ u8 stage; ///<当前状态
+};
+
+int usb_control_msg(struct usb_host_device *host_dev,
+ u8 request, u8 requesttype,
+ u16 value, u16 index,
+ void *data, u16 size);
+
+/**@brief USB清除或禁用特定的特性
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] ep 端点号
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_clear_feature(host_dev , ep);
+ * @encode
+ */
+int usb_clear_feature(struct usb_host_device *usb_dev, u32 ep);
+
+/**@brief USB设置地址
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] devnum 设备编号
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * set_address(host_dev , ep);
+ * @encode
+ */
+int set_address(struct usb_host_device *usb_dev, u8 devnum);
+
+/**@brief USB获取设备描述符
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] usb_device_descriptor定义的结构体指针
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_get_device_descriptor(host_dev , device_desc);
+ * @encode
+ */
+int usb_get_device_descriptor(struct usb_host_device *usb_dev, struct usb_device_descriptor *desc);
+
+/**@brief USB获取字符串描述符
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] usb_device_descriptor定义的结构体指针
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_get_string_descriptor(host_dev , device_desc);
+ * @encode
+ */
+int usb_get_string_descriptor(struct usb_host_device *usb_dev, struct usb_device_descriptor *desc);
+
+/**@brief USB设置相关配置
+ * @param[in] usb_host_device定义的结构体指针
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * set_configuration(host_dev);
+ * @encode
+ */
+int set_configuration(struct usb_host_device *usb_dev);
+
+/**@brief USB设置相关配置,添加相关参数
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] value 当前请求的参数
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * set_configuration_add_value(host_dev , value);
+ * @encode
+ */
+int set_configuration_add_value(struct usb_host_device *host_dev, u16 value);
+
+/**@brief USB获取配置描述符
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] cfg_desc 自定义的配置描述符指针
+ * @param[in] len 长度
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * get_config_descriptor(host_dev , cfg_desc , len);
+ * @encode
+ */
+int get_config_descriptor(struct usb_host_device *usb_dev, void *cfg_desc, u32 len);
+
+/**@brief USB获取配置描述符,添加相关参数
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] cfg_desc 自定义的配置描述符指针
+ * @param[in] len 长度
+ * @param[in] value_l 请求的参数
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * get_config_descriptor_add_value_l(host_dev , cfg_desc , len , value_l);
+ * @encode
+ */
+int get_config_descriptor_add_value_l(struct usb_host_device *host_dev, void *cfg_desc, u32 len, u8 value_l);
+
+/**@brief USB获取大容量存储设备的最大逻辑单元号
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] lun 逻辑单元号
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * get_msd_max_lun(host_dev , lun);
+ * @encode
+ */
+int get_msd_max_lun(struct usb_host_device *usb_dev, void *lun);
+
+/**@brief USB设置大容量存储设备复位
+ * @param[in] usb_host_device定义的结构体指针
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * set_msd_reset(host_dev);
+ * @encode
+ */
+int set_msd_reset(struct usb_host_device *usb_dev);
+
+/**@brief hid设置为空闲模式
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] id 指定接口或端点号
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * hid_set_idle(host_dev , id);
+ * @encode
+ */
+int hid_set_idle(struct usb_host_device *usb_dev, u32 id);
+
+/**@brief hid获取报告描述符
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] report 自定义报告指针,指向报告内容
+ * @param[in] report_id 报告描述符id号
+ * @param[in] report_len 报告描述符长度
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * hid_get_report(host_dev , report , report_id , report_len);
+ * @encode
+ */
+int hid_get_report(struct usb_host_device *usb_dev, u8 *report, u8 report_id, u16 report_len);
+
+/**@brief hid设置输出报告描述符
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] report 自定义报告指针,指向报告内容
+ * @param[in] report_id
+ * @param[in] report_len
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * hid_set_output_report(host_dev , report , report_id , report_len);
+ * @encode
+ */
+int hid_set_output_report(struct usb_host_device *usb_dev, u8 *report, u8 report_id, u8 report_len);
+
+/**@brief USB设置远程唤醒
+ * @param[in] usb_host_device定义的结构体指针
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_set_remote_wakeup(host_dev);
+ * @encode
+ */
+int usb_set_remote_wakeup(struct usb_host_device *usb_dev);
+
+/**@brief USB获取设备状态
+ * @param[in] usb_host_device定义的结构体指针
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * get_device_status(host_dev);
+ * @encode
+ */
+int get_device_status(struct usb_host_device *usb_dev);
+
+/**@brief USB获取设备限定描述符
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] BUFFER 自定义的指针,指向限定描述符内容
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_get_device_qualifier(host_dev , buffer);
+ * @encode
+ */
+int usb_get_device_qualifier(struct usb_host_device *usb_dev, u8 *buffer);
+
+/**@brief USB获取安卓aoa协议版本
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] version 自定义的指针,指向版本内容
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_get_aoa_version(host_dev , version);
+ * @encode
+ */
+int usb_get_aoa_version(struct usb_host_device *host_dev, u16 *version);
+
+/**@brief USB设置证书信息
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] string 字符串指针,指向证书内容
+ * @param[in] index 传递的参数
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_set_credentials(host_dev , string , index);
+ * @encode
+ */
+int usb_set_credentials(struct usb_host_device *host_dev, const char *string, int index);
+
+/**@brief USB设置aoa开关
+ * @param[in] usb_host_device定义的结构体指针
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_switch2aoa(host_dev);
+ * @encode
+ */
+int usb_switch2aoa(struct usb_host_device *host_dev);
+
+/**@brief USB设置从机模式开关
+ * @param[in] usb_host_device定义的结构体指针
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_switch2slave(host_dev);
+ * @encode
+ */
+int usb_switch2slave(struct usb_host_device *host_dev);
+
+/**@brief USB hid设备注册
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] value 请求的参数
+ * @param[in] index 传递的参数
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_aoa_register_hid(host_dev , value , index);
+ * @encode
+ */
+int usb_aoa_register_hid(struct usb_host_device *host_dev, u16 value, u16 index);
+
+/**@brief USB设置hid报告描述符
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] value 请求的参数
+ * @param[in] offset 偏移量参数
+ * @param[in] pbuf 存放数据的BUFFER指针
+ * @param[in] len 长度
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_aoa_set_hid_report_desc(host_dev , value , offset , *pbuf , len);
+ * @encode
+ */
+int usb_aoa_set_hid_report_desc(struct usb_host_device *host_dev, u16 value, u16 offset, const char *pbuf, u32 len);
+
+/**@brief USB发送hid事件
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] value 请求的参数
+ * @param[in] pbuf 存放数据的BUFFER指针
+ * @param[in] len 长度
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_aoa_send_hid_event(host_dev , value , *pbuf , len);
+ * @encode
+ */
+int usb_aoa_send_hid_event(struct usb_host_device *host_dev, u16 value, const u8 *pbuf, u32 len);
+
+/**@brief 获取扩展的大容量存储设备(可兼容)id 号
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] BUFFER 存放数据的BUFFER
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * get_ms_extended_compat_id(host_dev , value , *pbuf , len);
+ * @encode
+ */
+int get_ms_extended_compat_id(struct usb_host_device *host_dev, u8 *buffer);
+
+/**@brief USB设置接口
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] interface 接口参数(请求的参数)
+ * @param[in] alternateSetting 交替设置(传递的参数)
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_set_interface(host_dev , interface , alternateSetting);
+ * @encode
+ */
+int usb_set_interface(struct usb_host_device *host_dev, u8 interface, u8 alternateSetting);
+
+/**@brief USB音频采样频率控制
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] ep 端点号
+ * @param[in] samp_rate 采样率
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_audio_sampling_frequency_control(host_dev , ep , sampe_rate);
+ * @encode
+ */
+int usb_audio_sampling_frequency_control(struct usb_host_device *host_dev, u32 ep, u32 sampe_rate);
+
+/**@brief USB音频音量控制
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] feature_id 特征值id号(端点或接口的id)(传递的参数)
+ * @param[in] channel_num 通道编号(请求的参数)
+ * @paeam[in] volume 音量
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_audio_volume_control(host_dev , feature_id , channel_num , volume);
+ * @encode
+ */
+int usb_audio_volume_control(struct usb_host_device *host_dev, u8 feature_id, u8 channel_num, u16 volume);
+
+/**@brief USB音频静音控制
+ * @param[in] usb_host_device定义的结构体指针
+ * @param[in] feature_id 特征值id号(端点或接口的id)(传递的参数)
+ * @param[in] mute 静音信号(静音标志)
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_audio_mute_control(host_dev , feature_id , channel_num , volume);
+ * @encode
+ */
+int usb_audio_mute_control(struct usb_host_device *host_dev, u8 feature_id, u8 mute);
+
+#endif
diff --git a/apps/common/device/usb/host/usb_hid_keys.h b/apps/common/device/usb/host/usb_hid_keys.h
new file mode 100644
index 0000000..4947e11
--- /dev/null
+++ b/apps/common/device/usb/host/usb_hid_keys.h
@@ -0,0 +1,353 @@
+/**
+ * USB HID Keyboard scan codes as per USB spec 1.11
+ * plus some additional codes
+ *
+ * Created by MightyPork, 2016
+ * Public domain
+ *
+ * Adapted from:
+ * https://source.android.com/devices/input/keyboard-devices.html
+ */
+
+#ifndef USB_HID_KEYS
+#define USB_HID_KEYS
+
+struct keyboard_data_t {
+ u8 fun_key;
+ u8 res;
+ u8 Keypad[6];
+} _GNU_PACKED_ ;
+
+struct mouse_data_t {
+ u8 btn;
+ s16 x;
+ s16 y;
+ s8 wheel;
+ s8 ac_pan;
+} _GNU_PACKED_ ;
+struct point_t {
+ u8 tip_switch: 2;
+ /* u8 in_range: 1; */
+ u8 res: 2;
+ u8 cid: 4;
+ s16 x;
+ s16 y;
+} _GNU_PACKED_ ;
+
+struct touch_screen_t {
+ struct point_t p[3];
+} _GNU_PACKED_;
+
+struct mouse_point_t {
+ u8 btn;
+ s8 x;
+ s8 y;
+ s8 wheel;
+} _GNU_PACKED_;
+/**
+ * Modifier masks - used for the first byte in the HID report.
+ * NOTE: The second byte in the report is reserved, 0x00
+ */
+#define _KEY_MOD_LCTRL 0x01
+#define _KEY_MOD_LSHIFT 0x02
+#define _KEY_MOD_LALT 0x04
+#define _KEY_MOD_LMETA 0x08
+#define _KEY_MOD_RCTRL 0x10
+#define _KEY_MOD_RSHIFT 0x20
+#define _KEY_MOD_RALT 0x40
+#define _KEY_MOD_RMETA 0x80
+
+/**
+ * Scan codes - last N slots in the HID report (usually 6).
+ * 0x00 if no key pressed.
+ *
+ * If more than N keys are pressed, the HID reports
+ * KEY_ERR_OVF in all slots to indicate this condition.
+ */
+
+#define _KEY_NONE 0x00 // No key pressed
+#define _KEY_ERR_OVF 0x01 // Keyboard Error Roll Over - used for all slots if too many keys are pressed ("Phantom key")
+// 0x02 // Keyboard POST Fail
+// 0x03 // Keyboard Error Undefined
+#define _KEY_A 0x04 // Keyboard a and A
+#define _KEY_B 0x05 // Keyboard b and B
+#define _KEY_C 0x06 // Keyboard c and C
+#define _KEY_D 0x07 // Keyboard d and D
+#define _KEY_E 0x08 // Keyboard e and E
+#define _KEY_F 0x09 // Keyboard f and F
+#define _KEY_G 0x0a // Keyboard g and G
+#define _KEY_H 0x0b // Keyboard h and H
+#define _KEY_I 0x0c // Keyboard i and I
+#define _KEY_J 0x0d // Keyboard j and J
+#define _KEY_K 0x0e // Keyboard k and K
+#define _KEY_L 0x0f // Keyboard l and L
+#define _KEY_M 0x10 // Keyboard m and M
+#define _KEY_N 0x11 // Keyboard n and N
+#define _KEY_O 0x12 // Keyboard o and O
+#define _KEY_P 0x13 // Keyboard p and P
+#define _KEY_Q 0x14 // Keyboard q and Q
+#define _KEY_R 0x15 // Keyboard r and R
+#define _KEY_S 0x16 // Keyboard s and S
+#define _KEY_T 0x17 // Keyboard t and T
+#define _KEY_U 0x18 // Keyboard u and U
+#define _KEY_V 0x19 // Keyboard v and V
+#define _KEY_W 0x1a // Keyboard w and W
+#define _KEY_X 0x1b // Keyboard x and X
+#define _KEY_Y 0x1c // Keyboard y and Y
+#define _KEY_Z 0x1d // Keyboard z and Z
+
+#define _KEY_1 0x1e // Keyboard 1 and !
+#define _KEY_2 0x1f // Keyboard 2 and @
+#define _KEY_3 0x20 // Keyboard 3 and #
+#define _KEY_4 0x21 // Keyboard 4 and $
+#define _KEY_5 0x22 // Keyboard 5 and %
+#define _KEY_6 0x23 // Keyboard 6 and ^
+#define _KEY_7 0x24 // Keyboard 7 and &
+#define _KEY_8 0x25 // Keyboard 8 and *
+#define _KEY_9 0x26 // Keyboard 9 and (
+#define _KEY_0 0x27 // Keyboard 0 and )
+
+#define _KEY_ENTER 0x28 // Keyboard Return (ENTER)
+#define _KEY_ESC 0x29 // Keyboard ESCAPE
+#define _KEY_BACKSPACE 0x2a // Keyboard DELETE (Backspace)
+#define _KEY_TAB 0x2b // Keyboard Tab
+#define _KEY_SPACE 0x2c // Keyboard Spacebar
+#define _KEY_MINUS 0x2d // Keyboard - and _
+#define _KEY_EQUAL 0x2e // Keyboard = and +
+#define _KEY_LEFTBRACE 0x2f // Keyboard [ and {
+#define _KEY_RIGHTBRACE 0x30 // Keyboard ] and }
+#define _KEY_BACKSLASH 0x31 // Keyboard \ and |
+#define _KEY_HASHTILDE 0x32 // Keyboard Non-US # and ~
+#define _KEY_SEMICOLON 0x33 // Keyboard ; and :
+#define _KEY_APOSTROPHE 0x34 // Keyboard ' and "
+#define _KEY_GRAVE 0x35 // Keyboard ` and ~
+#define _KEY_COMMA 0x36 // Keyboard , and <
+#define _KEY_DOT 0x37 // Keyboard . and >
+#define _KEY_SLASH 0x38 // Keyboard / and ?
+#define _KEY_CAPSLOCK 0x39 // Keyboard Caps Lock
+
+#define _KEY_F1 0x3a // Keyboard F1
+#define _KEY_F2 0x3b // Keyboard F2
+#define _KEY_F3 0x3c // Keyboard F3
+#define _KEY_F4 0x3d // Keyboard F4
+#define _KEY_F5 0x3e // Keyboard F5
+#define _KEY_F6 0x3f // Keyboard F6
+#define _KEY_F7 0x40 // Keyboard F7
+#define _KEY_F8 0x41 // Keyboard F8
+#define _KEY_F9 0x42 // Keyboard F9
+#define _KEY_F10 0x43 // Keyboard F10
+#define _KEY_F11 0x44 // Keyboard F11
+#define _KEY_F12 0x45 // Keyboard F12
+
+#define _KEY_SYSRQ 0x46 // Keyboard Print Screen
+#define _KEY_SCROLLLOCK 0x47 // Keyboard Scroll Lock
+#define _KEY_PAUSE 0x48 // Keyboard Pause
+#define _KEY_INSERT 0x49 // Keyboard Insert
+#define _KEY_HOME 0x4a // Keyboard Home
+#define _KEY_PAGEUP 0x4b // Keyboard Page Up
+#define _KEY_DELETE 0x4c // Keyboard Delete Forward
+#define _KEY_END 0x4d // Keyboard End
+#define _KEY_PAGEDOWN 0x4e // Keyboard Page Down
+#define _KEY_RIGHT 0x4f // Keyboard Right Arrow
+#define _KEY_LEFT 0x50 // Keyboard Left Arrow
+#define _KEY_DOWN 0x51 // Keyboard Down Arrow
+#define _KEY_UP 0x52 // Keyboard Up Arrow
+
+#define _KEY_NUMLOCK 0x53 // Keyboard Num Lock and Clear
+#define _KEY_KPSLASH 0x54 // Keypad /
+#define _KEY_KPASTERISK 0x55 // Keypad *
+#define _KEY_KPMINUS 0x56 // Keypad -
+#define _KEY_KPPLUS 0x57 // Keypad +
+#define _KEY_KPENTER 0x58 // Keypad ENTER
+#define _KEY_KP1 0x59 // Keypad 1 and End
+#define _KEY_KP2 0x5a // Keypad 2 and Down Arrow
+#define _KEY_KP3 0x5b // Keypad 3 and PageDn
+#define _KEY_KP4 0x5c // Keypad 4 and Left Arrow
+#define _KEY_KP5 0x5d // Keypad 5
+#define _KEY_KP6 0x5e // Keypad 6 and Right Arrow
+#define _KEY_KP7 0x5f // Keypad 7 and Home
+#define _KEY_KP8 0x60 // Keypad 8 and Up Arrow
+#define _KEY_KP9 0x61 // Keypad 9 and Page Up
+#define _KEY_KP0 0x62 // Keypad 0 and Insert
+#define _KEY_KPDOT 0x63 // Keypad . and Delete
+
+#define _KEY_102ND 0x64 // Keyboard Non-US \ and |
+#define _KEY_COMPOSE 0x65 // Keyboard Application
+#define _KEY_POWER 0x66 // Keyboard Power
+#define _KEY_KPEQUAL 0x67 // Keypad =
+
+#define _KEY_F13 0x68 // Keyboard F13
+#define _KEY_F14 0x69 // Keyboard F14
+#define _KEY_F15 0x6a // Keyboard F15
+#define _KEY_F16 0x6b // Keyboard F16
+#define _KEY_F17 0x6c // Keyboard F17
+#define _KEY_F18 0x6d // Keyboard F18
+#define _KEY_F19 0x6e // Keyboard F19
+#define _KEY_F20 0x6f // Keyboard F20
+#define _KEY_F21 0x70 // Keyboard F21
+#define _KEY_F22 0x71 // Keyboard F22
+#define _KEY_F23 0x72 // Keyboard F23
+#define _KEY_F24 0x73 // Keyboard F24
+
+#define _KEY_OPEN 0x74 // Keyboard Execute
+#define _KEY_HELP 0x75 // Keyboard Help
+#define _KEY_PROPS 0x76 // Keyboard Menu
+#define _KEY_FRONT 0x77 // Keyboard Select
+#define _KEY_STOP 0x78 // Keyboard Stop
+#define _KEY_AGAIN 0x79 // Keyboard Again
+#define _KEY_UNDO 0x7a // Keyboard Undo
+#define _KEY_CUT 0x7b // Keyboard Cut
+#define _KEY_COPY 0x7c // Keyboard Copy
+#define _KEY_PASTE 0x7d // Keyboard Paste
+#define _KEY_FIND 0x7e // Keyboard Find
+#define _KEY_MUTE 0x7f // Keyboard Mute
+#define _KEY_VOLUMEUP 0x80 // Keyboard Volume Up
+#define _KEY_VOLUMEDOWN 0x81 // Keyboard Volume Down
+// 0x82 Keyboard Locking Caps Lock
+// 0x83 Keyboard Locking Num Lock
+// 0x84 Keyboard Locking Scroll Lock
+#define _KEY_KPCOMMA 0x85 // Keypad Comma
+// 0x86 Keypad Equal Sign
+#define _KEY_RO 0x87 // Keyboard International1
+#define _KEY_KATAKANAHIRAGANA 0x88 // Keyboard International2
+#define _KEY_YEN 0x89 // Keyboard International3
+#define _KEY_HENKAN 0x8a // Keyboard International4
+#define _KEY_MUHENKAN 0x8b // Keyboard International5
+#define _KEY_KPJPCOMMA 0x8c // Keyboard International6
+// 0x8d Keyboard International7
+// 0x8e Keyboard International8
+// 0x8f Keyboard International9
+#define _KEY_HANGEUL 0x90 // Keyboard LANG1
+#define _KEY_HANJA 0x91 // Keyboard LANG2
+#define _KEY_KATAKANA 0x92 // Keyboard LANG3
+#define _KEY_HIRAGANA 0x93 // Keyboard LANG4
+#define _KEY_ZENKAKUHANKAKU 0x94 // Keyboard LANG5
+// 0x95 Keyboard LANG6
+// 0x96 Keyboard LANG7
+// 0x97 Keyboard LANG8
+// 0x98 Keyboard LANG9
+// 0x99 Keyboard Alternate Erase
+// 0x9a Keyboard SysReq/Attention
+// 0x9b Keyboard Cancel
+// 0x9c Keyboard Clear
+// 0x9d Keyboard Prior
+// 0x9e Keyboard Return
+// 0x9f Keyboard Separator
+// 0xa0 Keyboard Out
+// 0xa1 Keyboard Oper
+// 0xa2 Keyboard Clear/Again
+// 0xa3 Keyboard CrSel/Props
+// 0xa4 Keyboard ExSel
+
+// 0xb0 Keypad 00
+// 0xb1 Keypad 000
+// 0xb2 Thousands Separator
+// 0xb3 Decimal Separator
+// 0xb4 Currency Unit
+// 0xb5 Currency Sub-unit
+#define _KEY_KPLEFTPAREN 0xb6 // Keypad (
+#define _KEY_KPRIGHTPAREN 0xb7 // Keypad )
+// 0xb8 Keypad {
+// 0xb9 Keypad }
+// 0xba Keypad Tab
+// 0xbb Keypad Backspace
+// 0xbc Keypad A
+// 0xbd Keypad B
+// 0xbe Keypad C
+// 0xbf Keypad D
+// 0xc0 Keypad E
+// 0xc1 Keypad F
+// 0xc2 Keypad XOR
+// 0xc3 Keypad ^
+// 0xc4 Keypad %
+// 0xc5 Keypad <
+// 0xc6 Keypad >
+// 0xc7 Keypad &
+// 0xc8 Keypad &&
+// 0xc9 Keypad |
+// 0xca Keypad ||
+// 0xcb Keypad :
+// 0xcc Keypad #
+// 0xcd Keypad Space
+// 0xce Keypad @
+// 0xcf Keypad !
+// 0xd0 Keypad Memory Store
+// 0xd1 Keypad Memory Recall
+// 0xd2 Keypad Memory Clear
+// 0xd3 Keypad Memory Add
+// 0xd4 Keypad Memory Subtract
+// 0xd5 Keypad Memory Multiply
+// 0xd6 Keypad Memory Divide
+// 0xd7 Keypad +/-
+// 0xd8 Keypad Clear
+// 0xd9 Keypad Clear Entry
+// 0xda Keypad Binary
+// 0xdb Keypad Octal
+// 0xdc Keypad Decimal
+// 0xdd Keypad Hexadecimal
+
+#define _KEY_LEFTCTRL 0xe0 // Keyboard Left Control
+#define _KEY_LEFTSHIFT 0xe1 // Keyboard Left Shift
+#define _KEY_LEFTALT 0xe2 // Keyboard Left Alt
+#define _KEY_LEFTMETA 0xe3 // Keyboard Left GUI
+#define _KEY_RIGHTCTRL 0xe4 // Keyboard Right Control
+#define _KEY_RIGHTSHIFT 0xe5 // Keyboard Right Shift
+#define _KEY_RIGHTALT 0xe6 // Keyboard Right Alt
+#define _KEY_RIGHTMETA 0xe7 // Keyboard Right GUI
+
+#define _KEY_MEDIA_PLAYPAUSE 0xe8
+#define _KEY_MEDIA_STOPCD 0xe9
+#define _KEY_MEDIA_PREVIOUSSONG 0xea
+#define _KEY_MEDIA_NEXTSONG 0xeb
+#define _KEY_MEDIA_EJECTCD 0xec
+#define _KEY_MEDIA_VOLUMEUP 0xed
+#define _KEY_MEDIA_VOLUMEDOWN 0xee
+#define _KEY_MEDIA_MUTE 0xef
+#define _KEY_MEDIA_WWW 0xf0
+#define _KEY_MEDIA_BACK 0xf1
+#define _KEY_MEDIA_FORWARD 0xf2
+#define _KEY_MEDIA_STOP 0xf3
+#define _KEY_MEDIA_FIND 0xf4
+#define _KEY_MEDIA_SCROLLUP 0xf5
+#define _KEY_MEDIA_SCROLLDOWN 0xf6
+#define _KEY_MEDIA_EDIT 0xf7
+#define _KEY_MEDIA_SLEEP 0xf8
+#define _KEY_MEDIA_COFFEE 0xf9
+#define _KEY_MEDIA_REFRESH 0xfa
+#define _KEY_MEDIA_CALC 0xfb
+
+#define _KEY_CUSTOM_CTRL_VOL_UP 0x00e9
+#define _KEY_CUSTOM_CTRL_VOL_DOWN 0x00ea
+#define _KEY_CUSTOM_CTRL_MUTE 0x00e2
+#define _KEY_CUSTOM_CTRL_FORWARD 0x00b5
+#define _KEY_CUSTOM_CTRL_STOP 0x00cd
+#define _KEY_CUSTOM_CTRL_BACK 0x00b6
+#define _KEY_CUSTOM_CTRL_MUSIC 0x0183
+#define _KEY_CUSTOM_CTRL_CALCULATOR 0x0192
+#define _KEY_CUSTOM_CTRL_SEARCH 0x0221
+#define _KEY_CUSTOM_CTRL_EMAIL 0x018A
+#define _KEY_CUSTOM_CTRL_HOME 0x0223
+#define _KEY_BRIGHTNESS_INCREASE 0x006F
+#define _KEY_BRIGHTNESS_REDUCTION 0x0070
+#define _KEY_ZOOM_IN 0x022D
+#define _KEY_ZOOM_OUT 0x022E
+#define _KEY_CUSTOM_COPY 0x021B
+#define _KEY_CUSTOM_CUT 0x021C
+#define _KEY_CUSTOM_PASTE 0x021D
+#define _KEY_CUSTOM_SELECT_ALL 0x021E
+#define _KEY_CUSTOM_SPLIT_SCREEN 0x0196
+#define _KEY_CUSTOM_LOCK 0x0030
+#define _KEY_CUSTOM_ESC 0x0223
+#define _KEY_CUSTOM_CALENDAR 0x018e
+#define _KEY_CUSTOM_MESSAGE 0X018d
+
+#define _KEY_CUSTOM_BROWER 0x0231
+#define _KEY_CUSTOM_PROCESS 0x023a
+
+#define _KEY_CUSTOM_SET 0x029b
+
+#define LED_NUM_LOCK 0x01
+#define LED_CAPS_LOCK 0x02
+#define LED_SCROLL_CLOCK 0x04
+#endif
+
diff --git a/apps/common/device/usb/host/usb_host.c b/apps/common/device/usb/host/usb_host.c
new file mode 100644
index 0000000..8ce36d1
--- /dev/null
+++ b/apps/common/device/usb/host/usb_host.c
@@ -0,0 +1,834 @@
+#include "includes.h"
+#include "app_config.h"
+#include "device_drive.h"
+/* #include "os/os_compat.h" */
+#if USB_HOST_ENABLE
+#include "usb_config.h"
+#include "usb/host/usb_host.h"
+#include "usb/usb_phy.h"
+#include "usb_ctrl_transfer.h"
+#include "usb_storage.h"
+#include "adb.h"
+#include "aoa.h"
+#include "hid.h"
+#include "audio.h"
+
+#if TCFG_USB_APPLE_DOCK_EN
+#include "apple_dock/iAP.h"
+#include "apple_mfi.h"
+#endif
+
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[mount]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+
+static struct usb_host_device host_devices[USB_MAX_HW_NUM];// SEC(.usb_h_bss);
+
+#define device_to_usbdev(device) ((struct usb_host_device *)((device)->private_data))
+
+
+int host_dev_status(const struct usb_host_device *host_dev)
+{
+ return ((host_dev)->private_data.status);
+}
+
+u32 host_device2id(const struct usb_host_device *host_dev)
+{
+#if USB_MAX_HW_NUM > 1
+ return ((host_dev)->private_data.usb_id);
+#else
+ return 0;
+#endif
+}
+const struct usb_host_device *host_id2device(const usb_dev id)
+{
+#if USB_MAX_HW_NUM > 1
+ return &host_devices[id];
+#else
+ return &host_devices[0];
+#endif
+}
+int usb_sem_init(struct usb_host_device *host_dev)
+{
+ usb_dev usb_id = host_device2id(host_dev);
+
+ usb_host_config(usb_id);
+
+ OS_SEM *sem = zalloc(sizeof(OS_SEM));
+ ASSERT(sem, "usb alloc sem error");
+ host_dev->sem = sem;
+ g_printf("%s %x %x ", __func__, host_dev, sem);
+ os_sem_create(host_dev->sem, 0);
+ return 0;
+}
+int usb_sem_pend(struct usb_host_device *host_dev, u32 timeout)
+{
+ if (host_dev->sem == NULL) {
+ return 1;
+ }
+ int ret = os_sem_pend(host_dev->sem, timeout);
+ if (ret) {
+ r_printf("%s %d ", __func__, ret);
+ }
+ return ret;
+}
+int usb_sem_post(struct usb_host_device *host_dev)
+{
+ if (host_dev->sem == NULL) {
+ return 1;
+ }
+ int ret = os_sem_post(host_dev->sem);
+ if (ret) {
+ r_printf("%s %d ", __func__, ret);
+ }
+ return 0;
+}
+int usb_sem_del(struct usb_host_device *host_dev)
+{
+ usb_dev usb_id = host_device2id(host_dev);
+
+ r_printf("1");
+ if (host_dev->sem == NULL) {
+ return 0;
+ }
+ r_printf("2");
+ r_printf("3");
+#if USB_HUB
+ if (host_dev && host_dev->sem && host_dev->father == NULL) {
+ os_sem_del(host_dev->sem, 0);
+ }
+#else
+ if (host_dev && host_dev->sem) {
+ os_sem_del(host_dev->sem, 0);
+ }
+#endif
+ r_printf("4");
+ g_printf("%s %x %x ", __func__, host_dev, host_dev->sem);
+ free(host_dev->sem);
+ r_printf("5");
+ host_dev->sem = NULL;
+ r_printf("6");
+ usb_host_free(usb_id);
+ r_printf("7");
+ return 0;
+}
+
+static int _usb_msd_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+ log_info("find udisk @ interface %d", interface_num);
+#if TCFG_UDISK_ENABLE
+ return usb_msd_parser(host_dev, interface_num, pBuf);
+#else
+ return USB_DT_INTERFACE_SIZE;
+#endif
+}
+static int _usb_apple_mfi_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+ log_info("find udisk @ interface %d", interface_num);
+#if TCFG_USB_APPLE_DOCK_EN
+ return usb_apple_mfi_parser(host_dev, interface_num, pBuf);
+#else
+ return USB_DT_INTERFACE_SIZE;
+#endif
+}
+static int _usb_adb_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+ log_info("find adb @ interface %d", interface_num);
+#if TCFG_ADB_ENABLE
+ return usb_adb_parser(host_dev, interface_num, pBuf);
+#else
+ return USB_DT_INTERFACE_SIZE;
+#endif
+}
+static int _usb_aoa_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+ log_info("find aoa @ interface %d", interface_num);
+#if TCFG_AOA_ENABLE
+ return usb_aoa_parser(host_dev, interface_num, pBuf);
+#else
+ return USB_DT_INTERFACE_SIZE;
+#endif
+
+}
+static int _usb_hid_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+ log_info("find hid @ interface %d", interface_num);
+#if TCFG_HID_HOST_ENABLE
+ return usb_hid_parser(host_dev, interface_num, pBuf);
+#else
+ return USB_DT_INTERFACE_SIZE;
+#endif
+}
+static int _usb_audio_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+ log_info("find audio @ interface %d", interface_num);
+#if TCFG_HOST_AUDIO_ENABLE
+ return usb_audio_parser(host_dev, interface_num, pBuf);
+#else
+ return USB_DT_INTERFACE_SIZE;
+#endif
+}
+static int _usb_adb_interface_ptp_mtp_parse(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+ log_info("find adbmtp @ interface %d", interface_num);
+#if TCFG_ADB_ENABLE
+ return usb_adb_interface_ptp_mtp_parse(host_dev, interface_num, pBuf);
+#else
+ return USB_DT_INTERFACE_SIZE;
+#endif
+}
+/**
+ * @brief usb_descriptor_parser
+ *
+ * @param device
+ * @param pBuf
+ * @param total_len
+ *
+ * @return
+ */
+static int usb_descriptor_parser(struct usb_host_device *host_dev, const u8 *pBuf, u32 total_len, struct usb_device_descriptor *device_desc)
+{
+ int len = 0;
+ u8 interface_num = 0;
+ struct usb_private_data *private_data = &host_dev->private_data;
+
+ struct usb_config_descriptor *cfg_desc = (struct usb_config_descriptor *)pBuf;
+
+ if (cfg_desc->bDescriptorType != USB_DT_CONFIG ||
+ cfg_desc->bLength < USB_DT_CONFIG_SIZE) {
+ log_error("invalid descriptor for config bDescriptorType = %d bLength= %d",
+ cfg_desc->bDescriptorType, cfg_desc->bLength);
+ return -USB_DT_CONFIG;
+ }
+
+ log_info("idVendor %x idProduct %x", device_desc->idVendor, device_desc->idProduct);
+
+ len += USB_DT_CONFIG_SIZE;
+ pBuf += USB_DT_CONFIG_SIZE;
+ int i = 0;
+ u32 have_find_valid_class = 0;
+ while (len < total_len) {
+ if (interface_num > MAX_HOST_INTERFACE) {
+ log_error("interface_num too much");
+ break;
+ }
+
+ struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
+ if (interface->bDescriptorType == USB_DT_INTERFACE) {
+
+ printf("inf class %x subclass %x ep %d",
+ interface->bInterfaceClass, interface->bInterfaceSubClass, interface->bNumEndpoints);
+
+ if (interface->bInterfaceClass == USB_CLASS_MASS_STORAGE) {
+ i = _usb_msd_parser(host_dev, interface_num, pBuf);
+ if (i < 0) {
+ log_error("---%s %d---", __func__, __LINE__);
+ len = total_len;
+ } else {
+ interface_num++;
+ len += i;
+ pBuf += i;
+ have_find_valid_class = true;
+ }
+ } else if ((device_desc->idVendor == 0x05AC) &&
+ ((device_desc->idProduct & 0xff00) == 0x1200)) {
+ i = _usb_apple_mfi_parser(host_dev, interface_num, pBuf);
+ if (i < 0) {
+ log_error("---%s %d---", __func__, __LINE__);
+ len = total_len;
+ } else {
+ interface_num++;
+ len += i;
+ pBuf += i;
+ have_find_valid_class = true;
+ }
+ } else if (interface->bInterfaceClass == USB_CLASS_AUDIO) {
+ i = _usb_audio_parser(host_dev, interface_num, pBuf);
+ if (i < 0) {
+ log_error("---%s %d---", __func__, __LINE__);
+ len = total_len;
+ } else {
+ interface_num++;
+ len += i;
+ pBuf += i;
+ have_find_valid_class = true;
+ }
+ } else if ((interface->bInterfaceClass == 0xff) &&
+ (interface->bInterfaceSubClass == USB_CLASS_ADB)) {
+ i = _usb_adb_parser(host_dev, interface_num, pBuf);
+ if (i < 0) {
+ log_error("---%s %d---", __func__, __LINE__);
+ len = total_len;
+ } else {
+ interface_num++;
+ len += i;
+ pBuf += i;
+ have_find_valid_class = true;
+ }
+ } else if ((device_desc->idVendor == 0x18d1) &&
+ ((device_desc->idProduct & 0x2d00) == 0x2d00)) {
+ i = _usb_aoa_parser(host_dev, interface_num, pBuf);
+ if (i < 0) {
+ log_error("---%s %d---", __func__, __LINE__);
+ len = total_len;
+ } else {
+ interface_num++;
+ len += i;
+ pBuf += i;
+ have_find_valid_class = true;
+ }
+ } else if (interface->bInterfaceClass == USB_CLASS_HID) {
+ i = _usb_hid_parser(host_dev, interface_num, pBuf);
+ if (i < 0) {
+ log_error("---%s %d---", __func__, __LINE__);
+ len = total_len;
+ } else {
+ interface_num++;
+ len += i;
+ pBuf += i;
+ have_find_valid_class = true;
+ }
+ } else if ((interface->bNumEndpoints == 3) &&
+ (interface->bInterfaceClass == 0xff || interface->bInterfaceClass == 0x06)) {
+ i = _usb_adb_interface_ptp_mtp_parse(host_dev, interface_num, pBuf);
+ if (i < 0) {
+ log_error("---%s %d---", __func__, __LINE__);
+ len = total_len;
+ } else {
+ interface_num++;
+ len += i;
+ pBuf += i;
+ }
+ have_find_valid_class = true;
+ } else if ((interface->bInterfaceClass == 0xff) &&
+ (interface->bInterfaceSubClass == 0xff)) {
+ i = _usb_aoa_parser(host_dev, interface_num, pBuf);
+ if (i < 0) {
+ log_error("---%s %d---", __func__, __LINE__);
+ len = total_len;
+ } else {
+ interface_num++;
+ len += i;
+ pBuf += i;
+ }
+ have_find_valid_class = true;
+
+ } else {
+ log_info("find unsupport [class %x subClass %x] @ interface %d",
+ interface->bInterfaceClass,
+ interface->bInterfaceSubClass,
+ interface_num);
+
+ len += USB_DT_INTERFACE_SIZE;
+ pBuf += USB_DT_INTERFACE_SIZE;
+ }
+ } else {
+ /* log_error("unknown section %d %d", len, pBuf[0]); */
+ if (pBuf[0]) {
+ len += pBuf[0];
+ pBuf += pBuf[0];
+ } else {
+ len = total_len;
+ }
+ }
+ }
+
+
+ log_debug("len %d total_len %d", len, total_len);
+ return !have_find_valid_class;
+}
+
+
+/* --------------------------------------------------------------------------*/
+/**
+ * @brief usb_host_suspend
+ *
+ * @param usb
+ *
+ * @return
+ */
+/* --------------------------------------------------------------------------*/
+void usb_host_suspend(const usb_dev usb_id)
+{
+ usb_h_entry_suspend(usb_id);
+}
+
+void usb_host_resume(const usb_dev usb_id)
+{
+ usb_h_resume(usb_id);
+}
+
+static u32 _usb_host_mount(const usb_dev usb_id, u32 retry, u32 reset_delay, u32 mount_timeout)
+{
+ u32 ret = DEV_ERR_NONE;
+ struct usb_host_device *host_dev = &host_devices[usb_id];
+ struct usb_private_data *private_data = &host_dev->private_data;
+
+
+ for (int i = 0; i < retry; i++) {
+ usb_h_sie_init(usb_id);
+#if defined(FUSB_MODE) && FUSB_MODE
+ usb_write_power(usb_id, BIT(6)); //full-speed
+#elif defined(FUSB_MODE) && (FUSB_MODE == 0)
+ usb_write_power(usb_id, BIT(5) | BIT(6)); //high-speed
+#else
+#error "USB_SPEED_MODE not defined"
+#endif
+ ret = usb_host_init(usb_id, reset_delay, mount_timeout);
+ if (ret) {
+ reset_delay += 10;
+ continue;
+ }
+
+ void *const ep0_dma = usb_h_get_ep_buffer(usb_id, 0);
+ usb_set_dma_taddr(usb_id, 0, ep0_dma);
+
+ usb_sie_enable(usb_id);//enable sie intr
+ usb_mdelay(reset_delay);
+
+ /**********get device descriptor*********/
+ struct usb_device_descriptor device_desc;
+ private_data->usb_id = usb_id;
+ private_data->status = 0;
+ private_data->devnum = 0;
+ private_data->ep0_max_packet_size = 8;
+ ret = usb_get_device_descriptor(host_dev, &device_desc);
+
+ /**********set address*********/
+ usb_mdelay(20);
+ u8 devnum = rand32() % 16 + 1;
+ ret = set_address(host_dev, devnum);
+ check_usb_mount(ret);
+ private_data->devnum = devnum ;
+
+ /**********get device descriptor*********/
+ usb_mdelay(20);
+ ret = usb_get_device_descriptor(host_dev, &device_desc);
+ check_usb_mount(ret);
+ private_data->ep0_max_packet_size = device_desc.bMaxPacketSize0;
+
+ /**********get config descriptor*********/
+ struct usb_config_descriptor cfg_desc;
+ ret = get_config_descriptor(host_dev, &cfg_desc, USB_DT_CONFIG_SIZE);
+ check_usb_mount(ret);
+
+#if USB_H_MALLOC_ENABLE
+ u8 *desc_buf = zalloc(cfg_desc.wTotalLength + 16);
+ ASSERT(desc_buf, "desc_buf");
+#else
+ u8 desc_buf[128] = {0};
+ cfg_desc.wTotalLength = min(sizeof(desc_buf), cfg_desc.wTotalLength);
+#endif
+
+ ret = get_config_descriptor(host_dev, desc_buf, cfg_desc.wTotalLength);
+ check_usb_mount(ret);
+
+ /**********set configuration*********/
+ ret = set_configuration(host_dev);
+ /* printf_buf(desc_buf, cfg_desc.wTotalLength); */
+ ret |= usb_descriptor_parser(host_dev, desc_buf, cfg_desc.wTotalLength, &device_desc);
+#if USB_H_MALLOC_ENABLE
+ log_info("free:desc_buf= %x\n", desc_buf);
+ free(desc_buf);
+#endif
+ check_usb_mount(ret);
+
+ for (int itf = 0; itf < MAX_HOST_INTERFACE; itf++) {
+ if (host_dev->interface_info[itf]) {
+ host_dev->interface_info[itf]->ctrl->set_power(host_dev, 1);
+ }
+ }
+ break;//succ
+ }
+
+ if (ret) {
+ goto __exit_fail;
+ }
+ private_data->status = 1;
+ return DEV_ERR_NONE;
+
+__exit_fail:
+ printf("usb_probe fail");
+ private_data->status = 0;
+ usb_sie_close(usb_id);
+ return ret;
+}
+static int usb_event_notify(const struct usb_host_device *host_dev, u32 ev)
+{
+ const usb_dev id = host_device2id(host_dev);
+ struct sys_event event;
+ static u32 bmUsbEvent[USB_MAX_HW_NUM];
+ u8 have_post_event = 0;
+ u8 no_send_event = 0;
+ if (ev == 0) {
+ event.u.dev.event = DEVICE_EVENT_IN;
+ } else if (ev == 1) {
+ event.u.dev.event = DEVICE_EVENT_CHANGE;
+ } else {
+ event.u.dev.event = DEVICE_EVENT_OUT;
+ goto __usb_event_out;
+ }
+ for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
+ no_send_event = 0;
+ event.u.dev.value = 0;
+ if (host_dev->interface_info[i]) {
+ switch (host_dev->interface_info[i]->ctrl->interface_class) {
+#if TCFG_UDISK_ENABLE
+ case USB_CLASS_MASS_STORAGE:
+ if (have_post_event & BIT(0)) {
+ no_send_event = 1;
+ } else {
+ have_post_event |= BIT(0);
+ }
+ if (id == 0) {
+ event.u.dev.value = (int)"udisk0";
+ } else {
+ event.u.dev.value = (int)"udisk1";
+ }
+ bmUsbEvent[id] |= BIT(0);
+ break;
+#endif
+#if TCFG_ADB_ENABLE
+ case USB_CLASS_ADB:
+ if (have_post_event & BIT(1)) {
+ no_send_event = 1;
+ } else {
+ have_post_event |= BIT(1);
+ }
+ if (id == 0) {
+ event.u.dev.value = (int)"adb0";
+ } else {
+ event.u.dev.value = (int)"adb1";
+ }
+ bmUsbEvent[id] |= BIT(1);
+ break;
+#endif
+#if TCFG_AOA_ENABLE
+ case USB_CLASS_AOA:
+ if (have_post_event & BIT(2)) {
+ no_send_event = 1;
+ } else {
+ have_post_event |= BIT(2);
+ }
+ if (id == 0) {
+ event.u.dev.value = (int)"aoa0";
+ } else {
+ event.u.dev.value = (int)"aoa1";
+ }
+ bmUsbEvent[id] |= BIT(2);
+ break;
+#endif
+#if TCFG_HID_HOST_ENABLE
+ case USB_CLASS_HID:
+ if (have_post_event & BIT(3)) {
+ no_send_event = 1;
+ } else {
+ have_post_event |= BIT(3);
+ }
+ if (id == 0) {
+ event.u.dev.value = (int)"hid0";
+ } else {
+ event.u.dev.value = (int)"hid1";
+ }
+ bmUsbEvent[id] |= BIT(3);
+ break;
+#endif
+#if TCFG_HOST_AUDIO_ENABLE
+ case USB_CLASS_AUDIO:
+ if (have_post_event & BIT(4)) {
+ no_send_event = 1;
+ } else {
+ have_post_event |= BIT(4);
+ }
+ if (id == 0) {
+ event.u.dev.value = (int)"audio0";
+ } else {
+ event.u.dev.value = (int)"audio1";
+ }
+ bmUsbEvent[id] |= BIT(4);
+ break;
+#endif
+ }
+
+ if (!no_send_event && event.u.dev.value) {
+ log_info("event %x interface %x class %x %s",
+ event.u.dev.event, i,
+ host_dev->interface_info[i]->ctrl->interface_class,
+ (const char *)event.u.dev.value);
+
+ /* printf("usb_host_mount notify >>>>>>>>>>>\n"); */
+ event.arg = (void *)DEVICE_EVENT_FROM_USB_HOST;
+ event.type = SYS_DEVICE_EVENT;
+ sys_event_notify(&event);
+ }
+ }
+ }
+
+__usb_event_out:
+ if (event.u.dev.event == DEVICE_EVENT_OUT) {
+ for (int i = 0; i < 32; i++) {
+ if (bmUsbEvent[id] & BIT(i)) {
+ switch (i) {
+#if TCFG_UDISK_ENABLE
+ case 0:
+ if (id == 0) {
+ event.u.dev.value = (int)"udisk0";
+ } else {
+ event.u.dev.value = (int)"udisk1";
+ }
+ break;
+#endif
+#if TCFG_ADB_ENABLE
+ case 1:
+ if (id == 0) {
+ event.u.dev.value = (int)"adb0";
+ } else {
+ event.u.dev.value = (int)"adb1";
+ }
+ break;
+#endif
+#if TCFG_AOA_ENABLE
+ case 2:
+ if (id == 0) {
+ event.u.dev.value = (int)"aoa0";
+ } else {
+ event.u.dev.value = (int)"aoa1";
+ }
+ break;
+#endif
+#if TCFG_HID_HOST_ENABLE
+ case 3:
+ if (id == 0) {
+ event.u.dev.value = (int)"hid0";
+ } else {
+ event.u.dev.value = (int)"hid1";
+ }
+ break;
+#endif
+#if TCFG_HOST_AUDIO_ENABLE
+ case 4:
+ if (id == 0) {
+ event.u.dev.value = (int)"audio0";
+ } else {
+ event.u.dev.value = (int)"audio1";
+ }
+ break;
+#endif
+ default:
+ event.u.dev.value = 0;
+ break;
+ }
+ bmUsbEvent[id] &= ~BIT(i);
+ if (event.u.dev.value) {
+ event.type = SYS_DEVICE_EVENT;
+ event.arg = (void *)DEVICE_EVENT_FROM_USB_HOST;
+ have_post_event = 1;
+ sys_event_notify(&event);
+ }
+ }
+ }
+ }
+
+ if (have_post_event) {
+ return DEV_ERR_NONE;
+ } else {
+ return DEV_ERR_UNKNOW_CLASS;
+ }
+
+}
+
+const char *usb_host_valid_class_to_dev(const usb_dev id, u32 usbclass)
+{
+#if USB_MAX_HW_NUM > 1
+ const usb_dev usb_id = id;
+#else
+ const usb_dev usb_id = 0;
+#endif
+ struct usb_host_device *host_dev = &host_devices[usb_id];
+ u32 itf_class;
+
+ for (int i = 0; i < MAX_HOST_INTERFACE; i++) {
+ if (host_dev->interface_info[i] &&
+ host_dev->interface_info[i]->ctrl) {
+ itf_class = host_dev->interface_info[i]->ctrl->interface_class;
+ if (itf_class == usbclass) {
+ switch (itf_class) {
+ case USB_CLASS_MASS_STORAGE:
+ if (usb_id == 0) {
+ return "udisk0";
+ } else if (usb_id == 1) {
+ return "udisk1";
+ }
+ break;
+ case USB_CLASS_ADB:
+ if (usb_id == 0) {
+ return "adb0";
+ } else if (usb_id == 1) {
+ return "adb1";
+ }
+ break;
+ case USB_CLASS_AOA:
+ if (usb_id == 0) {
+ return "aoa0";
+ } else if (usb_id == 1) {
+ return "aoa1";
+ }
+ break;
+ case USB_CLASS_HID:
+ if (usb_id == 0) {
+ return "hid0";
+ } else if (usb_id == 1) {
+ return "hid1";
+ }
+ break;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+/* --------------------------------------------------------------------------*/
+/**
+ * @brief usb_host_mount
+ *
+ * @param usb
+ *
+ * @return
+ */
+/* --------------------------------------------------------------------------*/
+u32 usb_host_mount(const usb_dev id, u32 retry, u32 reset_delay, u32 mount_timeout)
+{
+#if USB_MAX_HW_NUM > 1
+ const usb_dev usb_id = id;
+#else
+ const usb_dev usb_id = 0;
+#endif
+
+ u32 ret;
+ struct usb_host_device *host_dev = &host_devices[usb_id];
+ memset(host_dev, 0, sizeof(*host_dev));
+
+ host_dev->private_data.usb_id = id;
+
+ usb_sem_init(host_dev);
+ usb_h_isr_reg(usb_id, 1, 0);
+
+
+ ret = _usb_host_mount(usb_id, retry, reset_delay, mount_timeout);
+ usb_otg_resume(usb_id); //打开usb host之后恢复otg检测
+ if (ret) {
+ goto __exit_fail;
+ }
+ return usb_event_notify(host_dev, 0);
+
+__exit_fail:
+ usb_sie_disable(usb_id);
+ usb_sem_del(host_dev);
+ return ret;
+}
+
+static u32 _usb_host_unmount(const usb_dev usb_id)
+{
+ struct usb_host_device *host_dev = &host_devices[usb_id];
+
+ struct usb_private_data *private_data = &host_dev->private_data;
+ private_data->status = 0;
+
+ usb_sem_post(host_dev);//拔掉设备时,让读写线程快速释放
+
+ for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
+ if (host_dev->interface_info[i] && host_dev->interface_info[i]->ctrl->set_power) {
+ host_dev->interface_info[i]->ctrl->set_power(host_dev, 0);
+ host_dev->interface_info[i] = NULL;
+ }
+ }
+
+ usb_sie_close(usb_id);
+ return DEV_ERR_NONE;
+}
+
+/* --------------------------------------------------------------------------*/
+/**
+ * @brief usb_host_unmount
+ *
+ * @param usb
+ *
+ * @return
+ */
+/* --------------------------------------------------------------------------*/
+/* u32 usb_host_unmount(const usb_dev usb_id, char *device_name) */
+u32 usb_host_unmount(const usb_dev id)
+{
+#if USB_MAX_HW_NUM > 1
+ const usb_dev usb_id = id;
+#else
+ const usb_dev usb_id = 0;
+#endif
+ u32 ret;
+ struct usb_host_device *host_dev = &host_devices[usb_id];
+ struct sys_event event;
+
+#if (TCFG_UDISK_ENABLE && UDISK_READ_512_ASYNC_ENABLE)
+ _usb_stor_async_wait_sem(host_dev);
+#endif
+ ret = _usb_host_unmount(usb_id);
+ if (ret) {
+ goto __exit_fail;
+ }
+ usb_sem_del(host_dev);
+
+ /* printf("usb_host_unmount notify >>>>>>>>>>>\n"); */
+ usb_event_notify(host_dev, 2);
+ return DEV_ERR_NONE;
+
+__exit_fail:
+ return ret;
+}
+
+u32 usb_host_remount(const usb_dev id, u32 retry, u32 delay, u32 ot, u8 notify)
+{
+#if USB_MAX_HW_NUM > 1
+ const usb_dev usb_id = id;
+#else
+ const usb_dev usb_id = 0;
+#endif
+ u32 ret;
+ struct sys_event event;
+
+ ret = _usb_host_unmount(usb_id);
+ if (ret) {
+ goto __exit_fail;
+ }
+
+ struct usb_host_device *host_dev = &host_devices[usb_id];
+ os_sem_set(host_dev->sem, 0);
+
+ ret = _usb_host_mount(usb_id, retry, delay, ot);
+ if (ret) {
+ goto __exit_fail;
+ }
+
+ if (notify) {
+ struct usb_host_device *host_dev = &host_devices[usb_id];
+ usb_event_notify(host_dev, 1);
+ }
+ return DEV_ERR_NONE;
+
+__exit_fail:
+ return ret;
+}
+
+int usb_host_force_reset(const usb_dev usb_id)
+{
+ //预留以后加上hub的处理
+ usb_h_force_reset(usb_id);
+ return 0;
+}
+#endif
diff --git a/apps/common/device/usb/host/usb_storage.c b/apps/common/device/usb/host/usb_storage.c
new file mode 100644
index 0000000..176fdcb
--- /dev/null
+++ b/apps/common/device/usb/host/usb_storage.c
@@ -0,0 +1,2150 @@
+/** * @file usb_storage.c
+ * @brief
+ * @author chenrixin@zh-jieli.com
+ * @version 1.00
+ * @date 2017-02-09
+ */
+
+#include "asm/includes.h"
+#include "system/timer.h"
+#include "device/ioctl_cmds.h"
+#include "usb/host/usb_host.h"
+#include "usb_ctrl_transfer.h"
+#include "usb_bulk_transfer.h"
+#include "device_drive.h"
+#include "usb_storage.h"
+#include "usb_config.h"
+#include "app_config.h"
+
+#if TCFG_UDISK_ENABLE
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+static int set_stor_power(struct usb_host_device *host_dev, u32 value);
+static int get_stor_power(struct usb_host_device *host_dev, u32 value);
+
+const struct interface_ctrl udisk_ops = {
+ .interface_class = USB_CLASS_MASS_STORAGE,
+ .set_power = set_stor_power,
+ .get_power = get_stor_power,
+ .ioctl = NULL,
+};
+
+
+static struct mass_storage mass_stor = {0};//SEC(.usb_h_udisk);
+
+static const struct usb_interface_info udisk_inf = {
+ .ctrl = (struct interface_ctrl *) &udisk_ops,
+ .dev.disk = &mass_stor,
+};
+
+static struct device udisk_device ;//SEC(.usb_h_udisk);
+static struct udisk_end_desc udisk_ep ;//SEC(.usb_h_udisk);
+
+#define host_device2disk(host_dev) (udisk_inf.dev.disk)
+
+/**
+ * @brief usb_stor_force_reset
+ *
+ * @param device
+ *
+ * @return
+ */
+static int usb_stor_force_reset(const usb_dev usb_id)
+{
+ /* struct usb_host_device *host_dev = device_to_usbdev(device);
+ const usb_dev usb_id = host_device2id(host_dev); */
+ log_error("============usb_stor_force_reset===============\n");
+ return usb_host_force_reset(usb_id);
+}
+static void usb_stor_set_curlun(struct mass_storage *disk, u32 i)
+{
+ disk->curlun = i;
+}
+static int usb_stor_get_curlun(struct mass_storage *disk)
+{
+ return disk->curlun;
+}
+static int usb_stor_txmaxp(struct mass_storage *disk)
+{
+#if defined(FUSB_MODE) && FUSB_MODE == 0
+ return udisk_ep.txmaxp;
+#else
+ return 0x40;
+#endif
+}
+static int usb_stor_rxmaxp(struct mass_storage *disk)
+{
+#if defined(FUSB_MODE) && FUSB_MODE == 0
+ return udisk_ep.rxmaxp;
+#else
+ return 0x40;
+#endif
+}
+#define UDISK_MUTEX_TIMEOUT 5000/10 //5s
+static int usb_h_mutex_pend(struct usb_host_device *host_dev)
+{
+ struct mass_storage *disk = host_device2disk(host_dev);
+ /* putchar('{'); */
+ /* putchar('^'); */
+ /* putchar('['); */
+
+ int r = os_mutex_pend(&disk->mutex, UDISK_MUTEX_TIMEOUT);
+ if (r) {
+ log_error("-----------------%d -------------------", r);
+ }
+ if (r == OS_TIMEOUT) {
+ return OS_TIMEOUT;
+ }
+ return r;
+}
+static int usb_h_mutex_post(struct usb_host_device *host_dev)
+{
+ struct mass_storage *disk = host_device2disk(host_dev);
+ /* putchar(']'); */
+ /* putchar('^'); */
+ /* putchar('}'); */
+
+ int r = os_mutex_post(&disk->mutex);
+ return r;
+}
+static int set_stor_power(struct usb_host_device *host_dev, u32 value)
+{
+ struct mass_storage *disk = host_device2disk(host_dev);
+ log_debug("%s() %d ", __func__, disk->dev_status);
+ if (disk == NULL || disk->dev_status == DEV_IDLE) {
+ return 0;
+ }
+ if (value != 0) {
+ return 0;
+ }
+ int r = usb_h_mutex_pend(host_dev);
+ if (disk->dev_status == DEV_READ || disk->dev_status == DEV_WRITE) {
+ if (value == 0) {
+ log_error("%s disk busy", __func__);
+ }
+ }
+
+ disk->dev_status = DEV_CLOSE;
+
+ log_debug("%s() %d ", __func__, disk->dev_status);
+
+ if (r == OS_TIMEOUT) {
+ return OS_TIMEOUT;
+ }
+ usb_h_mutex_post(host_dev);
+ return DEV_ERR_NONE;
+}
+
+static int get_stor_power(struct usb_host_device *host_dev, u32 value)
+{
+ return DEV_ERR_NONE;
+}
+
+/**
+ * @brief usb_init_cbw
+ *
+ * @param device
+ */
+static void usb_init_cbw(struct device *device, u32 dir, u32 opcode, u32 length)
+{
+ struct mass_storage *disk = host_device2disk(host_dev);
+
+ memset(&disk->cbw, 0x00, sizeof(struct usb_scsi_cbw));
+ u32 curlun = usb_stor_get_curlun(disk);
+ disk->cbw.dCBWSignature = CBW_SIGNATURE;
+ disk->cbw.dCBWTag = rand32();
+ disk->cbw.bCBWLUN = curlun;
+ disk->cbw.lun = curlun << 5;
+ disk->cbw.bmCBWFlags = dir;
+ disk->cbw.operationCode = opcode;
+ disk->cbw.dCBWDataTransferLength = cpu_to_le32(length);
+}
+
+static int usb_stor_check_status(struct usb_host_device *host_dev)
+{
+ struct mass_storage *disk = host_device2disk(host_dev);
+
+ if (!host_dev) {
+ return -DEV_ERR_NOT_MOUNT;
+ }
+ if (!disk) {
+ return -DEV_ERR_NOT_MOUNT;
+ }
+ if (disk->dev_status == DEV_IDLE) {
+ return -DEV_ERR_NOT_MOUNT;
+ } else if (disk->dev_status == DEV_CLOSE) {
+ return -DEV_ERR_NOT_MOUNT;
+ }
+ return 0;
+}
+
+static int usb_stor_reset(struct device *device)
+{
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ int ret = DEV_ERR_NONE;
+
+ if (disk == NULL) {
+ return -DEV_ERR_NOT_MOUNT;
+ }
+ //mass storage reset request
+ ret = set_msd_reset(host_dev);
+ return ret;
+}
+
+static int usb_stor_resume(struct device *device)
+{
+ struct usb_device_descriptor device_desc;
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ const usb_dev usb_id = host_device2id(host_dev);
+ u8 devnum = host_dev->private_data.devnum;
+ int ret = DEV_ERR_NONE;
+ ret = usb_stor_check_status(host_dev);
+ if (ret) {
+ return ret;
+ }
+
+ usb_h_resume(usb_id);
+
+ ret = usb_get_device_descriptor(host_dev, &device_desc);
+ if (ret == 0) {
+ return ret;
+ }
+ usb_host_force_reset(usb_id);
+ ret = set_address(host_dev, devnum);
+ if (ret) {
+ log_error("%s() @ %d %x\n", __func__, __LINE__, ret);
+ usb_sie_close(usb_id);
+ return -ret;
+ }
+ ret = usb_get_device_descriptor(host_dev, &device_desc);
+ if (ret) {
+ log_error("%s() @ %d %x\n", __func__, __LINE__, ret);
+ usb_sie_close(usb_id);
+ return -ret;
+ }
+ return ret;
+}
+/**
+ * @brief usb_stor_inquiry
+ *
+ * @param device
+ *
+ * @return
+ */
+static int _usb_stor_inquiry(struct device *device)
+{
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ const usb_dev usb_id = host_device2id(host_dev);
+
+ const u32 txmaxp = usb_stor_txmaxp(disk);
+ const u32 rxmaxp = usb_stor_rxmaxp(disk);
+
+ int ret = DEV_ERR_NONE;
+ struct inquiry_data inquiry;
+
+ log_info("usb_stor_inquiry disk =%x", (u32)disk);
+
+ u32 total_lun = disk->lun;
+ u32 init_lun = 0;
+
+ for (int i = 0; i <= total_lun; i ++) {
+ usb_stor_set_curlun(disk, i);
+ usb_init_cbw(device, USB_DIR_IN, INQUIRY, sizeof(struct inquiry_data));
+ disk->cbw.bCBWLength = 0x06;
+ disk->cbw.lba[2] = sizeof(struct inquiry_data);
+
+ //cbw
+ ret = usb_bulk_only_send(device,
+ udisk_ep.host_epout,
+ txmaxp,
+ udisk_ep.target_epout,
+ (u8 *)&disk->cbw,
+ sizeof(struct usb_scsi_cbw));
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ //data
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ (u8 *)&inquiry,
+ sizeof(struct inquiry_data));
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ } else if (ret != sizeof(struct inquiry_data)) {
+ ret = -DEV_ERR_UNKNOW;
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ /* printf_buf(&inquiry, sizeof(struct inquiry_data)); */
+ //csw
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ (u8 *)&disk->csw,
+ sizeof(struct usb_scsi_csw));
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ } else if (ret != sizeof(struct usb_scsi_csw)) {
+ ret = -DEV_ERR_UNKNOW;
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+ if (inquiry.PeripheralDeviceType) {
+ if (init_lun == i) {
+ if (init_lun < total_lun) {
+ init_lun++;
+ } else {
+ init_lun = 0;
+ }
+ }
+ }
+ }
+ usb_stor_set_curlun(disk, init_lun);
+
+ return DEV_ERR_NONE;
+__exit:
+ log_error("%s---%d\n", __func__, __LINE__);
+ return ret;
+}
+
+static int usb_stor_inquiry(struct device *device)
+{
+ int ret;
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ ret = usb_stor_check_status(host_dev);
+ if (ret) {
+ return ret;
+ }
+ ret = usb_h_mutex_pend(host_dev);
+ if (ret == OS_TIMEOUT) {
+ return -OS_TIMEOUT;
+ }
+
+ ret = _usb_stor_inquiry(device);
+ usb_h_mutex_post(host_dev);
+ return ret;
+}
+/**
+ * @brief usb_stor_test_unit_ready
+ *
+ * @param device
+ *
+ * @return
+ */
+static int _usb_stor_test_unit_ready(struct device *device)
+{
+ int ret = DEV_ERR_NONE;
+
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ const usb_dev usb_id = host_device2id(host_dev);
+
+ const u32 txmaxp = usb_stor_txmaxp(disk);
+ const u32 rxmaxp = usb_stor_rxmaxp(disk);
+
+ usb_init_cbw(device, 0, TEST_UNIT_READY, 0);
+ disk->cbw.bCBWLength = 6;
+ //cbw
+ ret = usb_bulk_only_send(device,
+ udisk_ep.host_epout,
+ txmaxp,
+ udisk_ep.target_epout,
+ (u8 *)&disk->cbw,
+ sizeof(struct usb_scsi_cbw));
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ //csw
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ (u8 *)&disk->csw,
+ sizeof(struct usb_scsi_csw));
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ } else if (ret != sizeof(struct usb_scsi_csw)) {
+ ret = -DEV_ERR_UNKNOW;
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ return DEV_ERR_NONE;
+__exit:
+ log_error("%s---%d\n", __func__, __LINE__);
+ return ret;
+}
+static int usb_stor_test_unit_ready(struct device *device)
+{
+ int ret;
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ ret = usb_stor_check_status(host_dev);
+ if (ret) {
+ return ret;
+ }
+ ret = usb_h_mutex_pend(host_dev);
+ if (ret == OS_TIMEOUT) {
+ return -OS_TIMEOUT;
+ }
+ ret = _usb_stor_test_unit_ready(device);
+ usb_h_mutex_post(host_dev);
+ return ret;
+}
+
+/**
+ * @brief usb_stor_mode_sense6
+ *
+ * @param device
+ *
+ * @return
+ *
+ * @brief disk write protect inquiry
+ */
+static int _usb_stor_mode_sense6(struct device *device)
+{
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ const usb_dev usb_id = host_device2id(host_dev);
+ u8 *cdb;
+ int ret = DEV_ERR_NONE;
+ u8 data_buf[4];
+
+ const u32 txmaxp = usb_stor_txmaxp(disk);
+ const u32 rxmaxp = usb_stor_rxmaxp(disk);
+
+ usb_init_cbw(device, USB_DIR_IN, MODE_SENSE, 4);
+ disk->cbw.bCBWLUN = 6;
+ cdb = (u8 *)&disk->cbw.operationCode;
+ cdb[1] = 0; // PC | DBD
+ cdb[2] = 0x1c; //page code
+ cdb[3] = 0; //subpage code
+ cdb[4] = 192; //allocation length
+ cdb[5] = 0; //control;
+ //cbw
+ ret = usb_bulk_only_send(device,
+ udisk_ep.host_epout,
+ txmaxp,
+ udisk_ep.target_epout,
+ (u8 *)&disk->cbw,
+ sizeof(struct usb_scsi_cbw));
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ //data
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp, udisk_ep.target_epin,
+ data_buf,
+ sizeof(data_buf));
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+ disk->read_only = data_buf[2] == 0x80 ? 1 : 0; //write protect
+
+ //csw
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ (u8 *)&disk->csw,
+ sizeof(struct usb_scsi_csw));
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ } else if (ret != sizeof(struct usb_scsi_csw)) {
+ ret = -DEV_ERR_NONE;
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ return DEV_ERR_NONE;
+__exit:
+ log_error("%s---%d\n", __func__, __LINE__);
+ return ret;
+}
+static int usb_stor_mode_sense6(struct device *device)
+{
+ int ret;
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ ret = usb_stor_check_status(host_dev);
+ if (ret) {
+ return ret;
+ }
+ ret = usb_h_mutex_pend(host_dev);
+ if (ret == OS_TIMEOUT) {
+ return -OS_TIMEOUT;
+ }
+ ret = _usb_stor_mode_sense6(device);
+ usb_h_mutex_post(host_dev);
+ return ret;
+}
+/**
+ * @brief usb_stor_request_sense
+ *
+ * @param device
+ *
+ * @return
+ */
+static int _usb_stor_request_sense(struct device *device)
+{
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ const usb_dev usb_id = host_device2id(host_dev);
+ int ret = DEV_ERR_NONE;
+
+ const u32 txmaxp = usb_stor_txmaxp(disk);
+ const u32 rxmaxp = usb_stor_rxmaxp(disk);
+
+ usb_init_cbw(device, USB_DIR_IN, REQUEST_SENSE, sizeof(struct request_sense_data));
+ disk->cbw.bCBWLength = 0xC;
+ disk->cbw.lba[2] = sizeof(struct request_sense_data);
+ //cbw
+ ret = usb_bulk_only_send(device,
+ udisk_ep.host_epout,
+ txmaxp,
+ udisk_ep.target_epout,
+ (u8 *)&disk->cbw,
+ sizeof(struct usb_scsi_cbw));
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ //data
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ (u8 *)&disk->sense,
+ sizeof(struct request_sense_data));
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ } else if (ret != sizeof(struct request_sense_data)) {
+ ret = -DEV_ERR_NONE;
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ /* printf_buf(&private_data->dev.disk->sense, sizeof(struct REQUEST_SENSE_DATA)); */
+ //csw
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ (u8 *)&disk->csw,
+ sizeof(struct usb_scsi_csw));
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ } else if (ret != sizeof(struct usb_scsi_csw)) {
+ ret = -DEV_ERR_UNKNOW;
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ return DEV_ERR_NONE;
+__exit:
+ log_error("%s---%d\n", __func__, __LINE__);
+ return ret;
+}
+static int usb_stor_request_sense(struct device *device)
+{
+ int ret;
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ ret = usb_stor_check_status(host_dev);
+ if (ret) {
+ return ret;
+ }
+ ret = usb_h_mutex_pend(host_dev);
+ if (ret == OS_TIMEOUT) {
+ return -OS_TIMEOUT;
+ }
+ ret = _usb_stor_request_sense(device);
+ usb_h_mutex_post(host_dev);
+ return ret;
+}
+
+/**
+ * @brief usb_stor_read_capacity
+ *
+ * @param device
+ *
+ * @return
+ */
+static int _usb_stor_read_capacity(struct device *device)
+{
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ const usb_dev usb_id = host_device2id(host_dev);
+ int ret = DEV_ERR_NONE;
+
+ if (disk == NULL) {
+ return -DEV_ERR_NOT_MOUNT;
+ }
+
+ const u32 txmaxp = usb_stor_txmaxp(disk);
+ const u32 rxmaxp = usb_stor_rxmaxp(disk);
+
+ u32 curlun = usb_stor_get_curlun(disk);
+
+ usb_init_cbw(device, USB_DIR_IN, READ_CAPACITY, 8);
+ disk->cbw.bCBWLength = 0xA;
+ disk->cbw.bmCBWFlags = USB_DIR_IN;
+ disk->cbw.operationCode = READ_CAPACITY;
+ disk->capacity[curlun].block_size = 0;
+ disk->capacity[curlun].block_num = 0;
+
+ //cbw
+ ret = usb_bulk_only_send(device,
+ udisk_ep.host_epout,
+ txmaxp,
+ udisk_ep.target_epout,
+ (u8 *)&disk->cbw,
+ sizeof(struct usb_scsi_cbw));
+
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ //data
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ (u8 *)&disk->capacity[curlun],
+ sizeof(struct read_capacity_data));
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ } else if (ret != sizeof(struct read_capacity_data)) {
+ ret = -DEV_ERR_UNKNOW;
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ disk->capacity[curlun].block_size = be32_to_cpu(disk->capacity[curlun].block_size);
+ disk->capacity[curlun].block_num = be32_to_cpu(disk->capacity[curlun].block_num) + 1;
+ log_info("block_size=%d", disk->capacity[curlun].block_size);
+ log_info("block_num=%d", disk->capacity[curlun].block_num);
+ //csw
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ (u8 *)&disk->csw,
+ sizeof(struct usb_scsi_csw));
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ } else if (ret != sizeof(struct usb_scsi_csw)) {
+ ret = -DEV_ERR_UNKNOW;
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ return DEV_ERR_NONE;
+__exit:
+ log_error("%s---%d\n", __func__, __LINE__);
+ return ret;
+}
+static int usb_stor_read_capacity(struct device *device)
+{
+ int ret;
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ ret = usb_stor_check_status(host_dev);
+ if (ret) {
+ return ret;
+ }
+ ret = usb_h_mutex_pend(host_dev);
+ if (ret == OS_TIMEOUT) {
+ return -OS_TIMEOUT;
+ }
+ ret = _usb_stor_read_capacity(device);
+ usb_h_mutex_post(host_dev);
+ return ret;
+}
+
+static int _usb_stro_read_cbw_request(struct device *device, u32 num_lba, u32 lba)
+{
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+
+ const u32 txmaxp = usb_stor_txmaxp(disk);
+ u32 rx_len = num_lba * 512; //filesystem uses the fixed BLOCK_SIZE
+ u32 cur_lba = lba;
+ int ret = 0;
+
+ disk->dev_status = DEV_READ;
+ disk->suspend_cnt = 0;
+ usb_init_cbw(device, USB_DIR_IN, READ_10, rx_len);
+ disk->cbw.bCBWLength = 0xA;
+
+ cur_lba = cpu_to_be32(cur_lba);
+ memcpy(disk->cbw.lba, &cur_lba, sizeof(cur_lba));
+
+ disk->cbw.LengthH = HIBYTE(num_lba);
+ disk->cbw.LengthL = LOBYTE(num_lba);
+
+ //cbw
+ ret = usb_bulk_only_send(device,
+ udisk_ep.host_epout,
+ txmaxp,
+ udisk_ep.target_epout,
+ (u8 *)&disk->cbw,
+ sizeof(struct usb_scsi_cbw));
+
+ if (ret < DEV_ERR_NONE) {
+ if (disk->dev_status != DEV_CLOSE) {
+ disk->dev_status = DEV_OPEN;
+ }
+ log_error("%s---%d", __func__, __LINE__);
+ return ret;
+ }
+ return num_lba;
+}
+static int _usb_stro_read_csw(struct device *device)
+{
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ const u32 rxmaxp = usb_stor_rxmaxp(disk);
+ int ret = 0;
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ (u8 *)&disk->csw,
+ sizeof(struct usb_scsi_csw));
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d ret:%d\n", __func__, __LINE__, ret);
+ } else if (ret != sizeof(struct usb_scsi_csw)) {
+ ret = -DEV_ERR_UNKNOW;
+ log_error("%s:%d\n", __func__, __LINE__);
+ }
+ return ret;
+}
+
+static int _usb_stor_read_block_finish(struct device *device, u32 remain_len, u8 num_lba, void *pBuf)
+{
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ const u32 txmaxp = usb_stor_txmaxp(disk);
+ const u32 rxmaxp = usb_stor_rxmaxp(disk);
+ int ret = 0;
+ int len = num_lba * 512;
+ while (remain_len) {
+ //读完剩余的包,再开始下一次请求
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ pBuf,
+ len);
+ remain_len -= len;
+ if (remain_len == 0) {
+ //csw
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ (u8 *)&disk->csw,
+ sizeof(struct usb_scsi_csw));
+ }
+ }
+
+ return 0;
+}
+static int _usb_stor_read_big_block(struct device *device, u32 disk_block_size, void *pBuf, u8 num_lba, u32 lba)
+{
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ const u32 txmaxp = usb_stor_txmaxp(disk);
+ const u32 rxmaxp = usb_stor_rxmaxp(disk);
+ int ret = 0;
+ u32 rx_len = num_lba * 512; //filesystem uses the fixed BLOCK_SIZE
+ u8 num_block = disk_block_size / 512; //8
+ u8 req_offset = lba % num_block; //计算block数据偏移量
+ u8 send_cbw = 0;
+ if ((req_offset == 0) || (lba <= disk->prev_lba) || ((lba - disk->prev_lba) > num_block) || (disk->remain_len == 0)) {
+ //sector 4k地址;或地址不连续时(地址小于上一次地址; 地址和上一次地址不属于同一个sector)
+ send_cbw = 1;
+ } else {
+ //地址连续
+ send_cbw = 0;
+ }
+ /* y_printf("lba===%d prev_lba=%d req_offset===%d cbw:%d %d %d\n", */
+ /* lba, disk->prev_lba, req_offset, send_cbw, disk_block_size,disk->remain_len); */
+ disk->prev_lba = lba;
+ lba = lba / num_block;
+
+ if (send_cbw) {
+ _usb_stor_read_block_finish(device, disk->remain_len, num_lba, pBuf); //确保读完剩余包 */
+ disk->remain_len = 0;
+ disk->dev_status = DEV_READ;
+ disk->suspend_cnt = 0;
+ usb_init_cbw(device, USB_DIR_IN, READ_10, disk_block_size / 512 * 512);
+ disk->cbw.bCBWLength = 0xA;
+
+ lba = cpu_to_be32(lba);
+ memcpy(disk->cbw.lba, &lba, sizeof(lba));
+
+ disk->cbw.LengthH = HIBYTE(num_lba);
+ disk->cbw.LengthL = LOBYTE(num_lba);
+ //cbw
+ //请求disk_block_size 大小数据
+ ret = usb_bulk_only_send(device,
+ udisk_ep.host_epout,
+ txmaxp,
+ udisk_ep.target_epout,
+ (u8 *)&disk->cbw,
+ sizeof(struct usb_scsi_cbw));
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ disk->remain_len = disk_block_size;
+ } else {
+ req_offset = 0; //地址连续时,读一次data
+ }
+ //data
+ do {
+ //循环读取,直到读取到偏移量所在的数据为止
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ pBuf,
+ rx_len);
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+ disk->remain_len -= rx_len;
+
+ } while (req_offset--);
+
+ if (!disk->remain_len) { //读完data,需要读csw
+ //csw
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ (u8 *)&disk->csw,
+ sizeof(struct usb_scsi_csw));
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ } else if (ret != sizeof(struct usb_scsi_csw)) {
+ ret = -DEV_ERR_UNKNOW;
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+ }
+
+ disk->dev_status = DEV_OPEN;
+ return num_lba;
+__exit:
+ if (disk->dev_status != DEV_CLOSE) {
+ disk->dev_status = DEV_OPEN;
+ }
+ log_error("%s---%d", __func__, __LINE__);
+ return 0;
+}
+
+int _usb_stor_async_wait_sem(struct usb_host_device *host_dev)
+{
+ int ret = 0;
+#if UDISK_READ_512_ASYNC_ENABLE
+ if (get_async_mode() == BULK_ASYNC_MODE_SEM_PEND) {
+ set_async_mode(BULK_ASYNC_MODE_EXIT);
+ ret = usb_sem_pend(host_dev, 100);
+ if (ret) {
+ r_printf("usb async ret timeout %d", ret);
+ return -DEV_ERR_TIMEOUT;
+ }
+ }
+#endif
+ return ret;
+}
+#if UDISK_READ_BIGBLOCK_ASYNC_ENABLE
+static int _usb_stro_read_async(struct device *device, void *pBuf, u32 num_lba, u32 lba)
+{
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ const usb_dev usb_id = host_device2id(host_dev);
+
+ const u32 txmaxp = usb_stor_txmaxp(disk);
+ const u32 rxmaxp = usb_stor_rxmaxp(disk);
+ int ret = 0;
+ u8 read_block_num = UDISK_READ_ASYNC_BLOCK_NUM;
+ u32 rx_len = num_lba * 512; //filesystem uses the fixed BLOCK_SIZE
+ /* r_printf("read lba : %d %d\n",lba,disk->remain_len); */
+ if ((lba != disk->async_prev_lba + 1) || disk->remain_len == 0) {
+ //这里要确保上次cbw 请求的数据读取完毕
+ //data
+ while (disk->remain_len) {
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ NULL,
+ rx_len);
+ disk->remain_len -= rx_len;
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ disk->remain_len = 0; //data 接收错误直接发csw
+ }
+ if (disk->remain_len == 0) {
+ //csw
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ (u8 *)&disk->csw,
+ sizeof(struct usb_scsi_csw));
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ } else if (ret != sizeof(struct usb_scsi_csw)) {
+ ret = -DEV_ERR_UNKNOW;
+ log_error("%s:%d\n", __func__, __LINE__);
+ }
+ break;
+ }
+ }
+ _usb_stro_read_cbw_request(device, read_block_num, lba); //cbw
+ disk->remain_len = read_block_num * 512;
+ //data
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ pBuf,
+ rx_len);
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+ disk->remain_len -= rx_len;
+ } else {
+ //地址连续,直接读取预读的数据
+ //data
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ pBuf,
+ rx_len);
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+ disk->remain_len -= rx_len;
+ if (disk->remain_len == 0) {
+ //预读数据读完,发csw
+ //csw
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ (u8 *)&disk->csw,
+ sizeof(struct usb_scsi_csw));
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ } else if (ret != sizeof(struct usb_scsi_csw)) {
+ ret = -DEV_ERR_UNKNOW;
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+ }
+ }
+ disk->async_prev_lba = lba;
+
+ disk->dev_status = DEV_OPEN;
+ return num_lba;
+__exit:
+ if (disk->dev_status != DEV_CLOSE) {
+ disk->dev_status = DEV_OPEN;
+ }
+ log_error("%s---%d", __func__, __LINE__);
+ return 0;
+}
+#endif
+#if UDISK_READ_512_ASYNC_ENABLE
+static int _usb_stro_read_async(struct device *device, void *pBuf, u32 num_lba, u32 lba)
+{
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ const usb_dev usb_id = host_device2id(host_dev);
+
+ const u32 txmaxp = usb_stor_txmaxp(disk);
+ const u32 rxmaxp = usb_stor_rxmaxp(disk);
+ int ret = 0;
+ u32 rx_len = num_lba * 512; //filesystem uses the fixed BLOCK_SIZE
+ u8 read_block_num = UDISK_READ_ASYNC_BLOCK_NUM;
+ /* r_printf("lba : %d %d\n",lba,disk->remain_len); */
+ if (_usb_stor_async_wait_sem(host_dev)) {
+ goto __exit;
+ }
+
+ if ((lba != disk->async_prev_lba + 1)) {
+ if (disk->remain_len == 0) {
+ if (disk->need_send_csw) {
+ //已取完data,需要发csw
+ ret = _usb_stro_read_csw(device);
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d %d\n", __func__, __LINE__, ret);
+ goto __exit;
+ }
+ disk->need_send_csw = 0;
+ }
+ }
+ //这里要确保上次cbw 请求的数据读取完毕
+ //data
+ while (disk->remain_len) {
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ NULL,
+ rx_len);
+ disk->remain_len -= rx_len;
+ if (ret != rx_len) {
+ log_error("%s:%d %d\n", __func__, __LINE__, ret);
+ disk->remain_len = 0; //data 接收错误直接发csw
+ goto __exit;
+ }
+ if (disk->remain_len == 0) {
+ //csw
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ (u8 *)&disk->csw,
+ sizeof(struct usb_scsi_csw));
+ if (ret != sizeof(struct usb_scsi_csw)) {
+ ret = -DEV_ERR_UNKNOW;
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+ break;
+ }
+ }
+ ret = _usb_stro_read_cbw_request(device, read_block_num, lba); //cbw
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+ disk->remain_len = read_block_num * 512;
+ //data
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ pBuf,
+ rx_len);
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+ disk->remain_len -= rx_len;
+ if (disk->remain_len == 0) {
+ ret = _usb_stro_read_csw(device);
+ if (ret != sizeof(struct usb_scsi_csw)) {
+ ret = -DEV_ERR_UNKNOW;
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+ }
+ } else {
+ memcpy(pBuf, disk->udisk_512_buf, rx_len);
+ if (disk->remain_len == 0) {
+ ret = _usb_stro_read_csw(device);
+ if (ret != sizeof(struct usb_scsi_csw)) {
+ ret = -DEV_ERR_UNKNOW;
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+ }
+ }
+ disk->async_prev_lba = lba;
+ //异步预读
+ if (disk->remain_len == 0) {
+ ret = _usb_stro_read_cbw_request(device, read_block_num, lba + 1); //cbw
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+ disk->remain_len = read_block_num * 512;
+ }
+ //data
+ ret = usb_bulk_receive_async_no_wait(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ disk->udisk_512_buf,
+ rx_len);
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+ disk->remain_len -= rx_len;
+ if (disk->remain_len == 0) {
+ //data请求完,等待发送csw
+ disk->need_send_csw = 1;
+ }
+
+ disk->dev_status = DEV_OPEN;
+ return num_lba;
+__exit:
+ if (disk->dev_status != DEV_CLOSE) {
+ disk->dev_status = DEV_OPEN;
+ }
+ log_error("%s---%d", __func__, __LINE__);
+ return 0;
+}
+#endif
+
+//****************************youning***********************************----->
+#if UDISK_READ_AHEAD_ENABLE
+
+static int _usb_stor_read_ahead_cbw(struct device *device, void *pBuf, u32 num_lba, u32 lba)
+{
+ //log_info("func:%s,line:%d\n", __func__, __LINE__);
+
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ const u32 curlun = usb_stor_get_curlun(disk);
+ u8 read_block_num = UDISK_READ_AHEAD_BLOCK_NUM; //需要预读扇区数量
+ if (lba + read_block_num - 1 >= disk->capacity[curlun].block_num) {
+ read_block_num = disk->capacity[curlun].block_num - lba;
+ log_info("usb_read_ahead over capacity!!!%d,%d,%d\n", read_block_num, disk->capacity[curlun].block_num - 1, lba);
+ }
+ disk->remain_len = read_block_num * 512;
+ int ret = 0;
+ ret = _usb_stro_read_cbw_request(device, read_block_num, lba); //cbw
+ check_usb_read_ahead(ret);
+
+ return 0;
+
+__exit:
+ return ret;
+}
+
+static int _usb_stor_read_ahead_data(struct device *device, void *pBuf, u32 num_lba, u32 lba)
+{
+ //log_info("func:%s,line:%d\n", __func__, __LINE__);
+
+ if (num_lba == 0) {
+ return 0;
+ }
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ const u32 rxmaxp = usb_stor_rxmaxp(disk);
+
+ u32 rx_len = num_lba * 512;
+ int ret;
+
+ if (disk->remain_len != 0) {
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ pBuf,
+ rx_len);
+ check_usb_read_ahead(ret);
+
+ disk->remain_len -= rx_len;
+ disk->udisk_read_ahead_lba_last = lba + num_lba - 1;
+ }
+
+ if (disk->remain_len == 0) {
+ ret = _usb_stro_read_csw(device);
+ check_usb_read_ahead(ret);
+ }
+
+ return 0;
+
+__exit:
+ return ret;
+}
+
+static int _usb_stor_read_ahead(struct device *device, void *pBuf, u32 num_lba, u32 lba)
+{
+ //log_info("func:%s,line:%d\n", __func__, __LINE__);
+
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+
+ int ret = 0;
+ if ((lba != disk->udisk_read_ahead_lba_last + 1) || disk->remain_len == 0) {
+ ret = _usb_stor_read_ahead_data(device, NULL, disk->remain_len / 512, lba); //预读中止,把上一次的剩下的读完
+ check_usb_read_ahead(ret);
+
+ ret = _usb_stor_read_ahead_cbw(device, pBuf, num_lba, lba);
+ check_usb_read_ahead(ret);
+
+ ret = _usb_stor_read_ahead_data(device, pBuf, num_lba, lba);
+ check_usb_read_ahead(ret);
+ } else {
+ ret = _usb_stor_read_ahead_data(device, pBuf, num_lba, lba);
+ check_usb_read_ahead(ret);
+ }
+
+ return num_lba; //read success
+__exit:
+ return 0; //read error
+}
+
+#endif
+//****************************youning***********************************<-----
+
+/**
+ * @brief usb_stor_read 从U盘的lba扇区读取num_lba个扇区
+ *
+ * @param device 设备句柄
+ * @param pBuf 读buffer缓冲区,芯片所有memory都可以
+ * @param lba 需要读取的扇区地址
+ * @param num_lba 需要读取的扇区数量
+ *
+ * @return 负数表示失败
+ * 大于0的表示读取的字节数(Byte)
+ */
+static int _usb_stor_read(struct device *device, void *pBuf, u32 num_lba, u32 lba)
+{
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ const usb_dev usb_id = host_device2id(host_dev);
+
+ const u32 txmaxp = usb_stor_txmaxp(disk);
+ const u32 rxmaxp = usb_stor_rxmaxp(disk);
+ const u32 curlun = usb_stor_get_curlun(disk);
+
+ u8 read_retry = 0;
+ int ret;
+ u32 rx_cnt;
+ /* u32 rx_len = num_lba * disk->capacity[curlun].block_size; */
+ u32 rx_len = num_lba * 512; //filesystem uses the fixed BLOCK_SIZE
+
+ if (disk->capacity[curlun].block_size > 512) {
+ // 扇区大于512Byte
+ return _usb_stor_read_big_block(device, disk->capacity[curlun].block_size, pBuf, num_lba, lba);
+ }
+
+ if (lba + num_lba - 1 >= disk->capacity[curlun].block_num) {
+ return -DEV_ERR_OVER_CAPACITY;
+ }
+#if (UDISK_READ_BIGBLOCK_ASYNC_ENABLE || UDISK_READ_512_ASYNC_ENABLE)
+ if (disk->async_en) {
+ return _usb_stro_read_async(device, pBuf, num_lba, lba);
+ }
+#endif
+
+#if UDISK_READ_AHEAD_ENABLE
+
+ return _usb_stor_read_ahead(device, pBuf, num_lba, lba);
+#endif
+
+ ret = _usb_stro_read_cbw_request(device, num_lba, lba);
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ //data
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ pBuf,
+ rx_len);
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ //csw
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ (u8 *)&disk->csw,
+ sizeof(struct usb_scsi_csw));
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ } else if (ret != sizeof(struct usb_scsi_csw)) {
+ ret = -DEV_ERR_UNKNOW;
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ disk->dev_status = DEV_OPEN;
+ return num_lba;
+
+__exit:
+ if (disk->dev_status != DEV_CLOSE) {
+ disk->dev_status = DEV_OPEN;
+ }
+ log_error("%s---%d", __func__, __LINE__);
+ return 0;
+}
+static int usb_stor_read(struct device *device, void *pBuf, u32 num_lba, u32 lba)
+{
+ int ret;
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ ret = usb_stor_check_status(host_dev);
+ if (ret) {
+ return ret;
+ }
+ ret = usb_h_mutex_pend(host_dev);
+ if (ret == OS_TIMEOUT) {
+ return -OS_TIMEOUT;
+ }
+ ret = _usb_stor_read(device, pBuf, num_lba, lba);
+ usb_h_mutex_post(host_dev);
+ return ret;
+}
+
+/**
+ * @brief usb_stor_write 写数据到U盘
+ *
+ * @param device
+ * @param pBuf 数据buffer
+ * @param lba 需要写入的扇区地址
+ * @param num_lba 需要写入的扇区数量
+ *
+ * @return 负数表示写入失败
+ * 正数为写入的字节数 (Byte)
+ */
+static int _usb_stor_write(struct device *device, void *pBuf, u32 num_lba, u32 lba)
+{
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ const usb_dev usb_id = host_device2id(host_dev);
+ u32 ret;
+
+ const u32 txmaxp = usb_stor_txmaxp(disk);
+ const u32 rxmaxp = usb_stor_rxmaxp(disk);
+ const u32 curlun = usb_stor_get_curlun(disk);
+
+ if (lba + num_lba - 1 >= disk->capacity[curlun].block_num) {
+ log_error("%s %d", __func__, __LINE__);
+ return -DEV_ERR_OVER_CAPACITY;
+ }
+
+ if (disk->capacity[curlun].block_size > 512) {
+ log_error(" %s disk bolock size %d not support write", __func__, disk->capacity[curlun].block_size);
+ return -DEV_ERR_NO_WRITE;
+ }
+
+ if (disk->read_only) {
+ log_error("%s %d", __func__, __LINE__);
+ return -DEV_ERR_NO_WRITE;
+ }
+
+ /* u32 tx_len = num_lba * disk->capacity[curlun].block_size; */
+ u32 tx_len = num_lba * 512; //filesystem uses the fixed BLOCK_SIZE
+
+#if (UDISK_READ_BIGBLOCK_ASYNC_ENABLE || UDISK_READ_512_ASYNC_ENABLE)
+ /* r_printf("write lba : %d %d txlen:%d\n",lba,disk->remain_len,tx_len); */
+ /* 确保预读read剩余的包读完,才开始写 */
+ _usb_stor_async_wait_sem(host_dev);
+ while (disk->remain_len) {
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ NULL,
+ tx_len);
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+ disk->remain_len -= tx_len;
+ disk->need_send_csw = 1;
+ }
+ if (disk->remain_len == 0) {
+ //csw
+ if (disk->need_send_csw) {
+ ret = _usb_stro_read_csw(device);
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ } else if (ret != sizeof(struct usb_scsi_csw)) {
+ ret = -DEV_ERR_UNKNOW;
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+ }
+ disk->need_send_csw = 0;
+ disk->async_prev_lba = 0;
+ }
+#endif
+
+#if UDISK_READ_AHEAD_ENABLE
+
+ //_usb_stor_read_ahead_data(device, NULL, disk->remain_len / 512, disk->udisk_read_ahead_lba_last); //预读中止,把上一次的剩下的读完
+
+#endif
+
+ disk->dev_status = DEV_WRITE;
+ disk->suspend_cnt = 0;
+ usb_init_cbw(device, USB_DIR_OUT, WRITE_10, tx_len);
+
+ disk->cbw.bCBWLength = 0xA;
+
+ lba = cpu_to_be32(lba);
+ memcpy(disk->cbw.lba, &lba, sizeof(lba));
+
+ disk->cbw.LengthH = HIBYTE(num_lba);
+ disk->cbw.LengthL = LOBYTE(num_lba);
+
+ //cbw
+ ret = usb_bulk_only_send(device,
+ udisk_ep.host_epout,
+ txmaxp,
+ udisk_ep.target_epout,
+ (u8 *)&disk->cbw,
+ sizeof(struct usb_scsi_cbw));
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ //data
+ ret = usb_bulk_only_send(device,
+ udisk_ep.host_epout,
+ txmaxp,
+ udisk_ep.target_epout,
+ pBuf,
+ tx_len);
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+
+ //csw
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ (u8 *)&disk->csw,
+ sizeof(struct usb_scsi_csw));
+
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ } else if (ret != sizeof(struct usb_scsi_csw)) {
+ ret = -DEV_ERR_UNKNOW;
+ goto __exit;
+ }
+
+ if (disk->csw.bCSWStatus) {
+ ret = usb_stor_request_sense(device);
+ if (ret) {
+ ret = -DEV_ERR_OFFLINE;
+ }
+
+ if (ret == -DEV_ERR_OFFLINE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ goto __exit;
+ }
+ log_info("usb_stor_sense =%x", disk->sense.SenseKey);
+ return 0;
+ }
+
+ disk->dev_status = DEV_OPEN;
+ return num_lba;//DEV_ERR_NONE;
+
+__exit:
+ if (disk->dev_status != DEV_CLOSE) {
+ disk->dev_status = DEV_OPEN;
+ }
+ log_error("%s---%d\n", __func__, __LINE__);
+ /* usb_stor_force_reset(usb_id); */
+ return 0;
+}
+static int usb_stor_write(struct device *device, void *pBuf, u32 num_lba, u32 lba)
+{
+ int ret;
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ ret = usb_stor_check_status(host_dev);
+ if (ret) {
+ return ret;
+ }
+ ret = usb_h_mutex_pend(host_dev);
+ if (ret == OS_TIMEOUT) {
+ return -OS_TIMEOUT;
+ }
+ ret = _usb_stor_write(device, pBuf, num_lba, lba);
+ usb_h_mutex_post(host_dev);
+ return ret;
+}
+#if ENABLE_DISK_HOTPLUG
+static void usb_stor_tick_handle(void *arg)
+{
+ struct device *device = (struct device *)arg;
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);//(device);
+ const usb_dev usb_id = host_device2id(host_dev);
+
+ int ret;
+
+ r_printf("A");
+ if (disk == NULL) {
+ return;
+ }
+ r_printf("B");
+ if (disk->dev_status == DEV_OPEN) {
+ r_printf("C");
+ ret = usb_stor_read_capacity(device);
+ r_printf("D");
+ }
+
+#if 0
+#if 1
+ disk->suspend_cnt++;
+ if ((disk->suspend_cnt > 6) && (disk->dev_status == DEV_OPEN)) {
+ usb_h_entry_suspend(usb_id);
+ disk->suspend_cnt = 0;
+ disk->dev_status = DEV_SUSPEND;
+ }
+#else
+ ret = usb_stor_test_unit_ready(device);
+ if (ret < DEV_ERR_NONE) {
+ return ;
+ }
+ if (disk->csw.bCSWStatus) {
+ usb_stor_request_sense(device);
+ /* puts("request sense\n"); */
+ /* put_buf((u8 *)&disk->sense, sizeof(disk->sense)); */
+ if ((disk->sense.SenseKey & 0x0f) == NOT_READY) {
+ if (disk->sense.ASC == 0x3a && disk->sense.ASCQ == 0x00) {
+ disk->media_sta_cur = 0;
+ }
+ } else if ((disk->sense.SenseKey & 0x0f) == UNIT_ATTENTION) {
+ if (disk->sense.ASC == 0x28 && disk->sense.ASCQ == 0x00) {
+ disk->media_sta_cur = 1;
+ }
+ }
+ } else {
+ disk->media_sta_cur = 1;
+ }
+
+ if (disk->media_sta_cur != disk->media_sta_prev) {
+ if (disk->media_sta_cur) {
+ log_info("udisk media insert");
+ usb_stor_read_capacity(device);
+ usb_stor_mode_sense6(device);
+ } else {
+ log_info("udisk media eject");
+ }
+ }
+ disk->media_sta_prev = disk->media_sta_cur;
+#endif
+#endif
+}
+#endif
+
+/**
+ * @brief usb_stor_init
+ *
+ * @param device
+ *
+ * @return
+ */
+int usb_stor_init(struct device *device)
+{
+ log_debug("%s---%d\n", __func__, __LINE__);
+ int ret = DEV_ERR_NONE;
+ u32 state = 0;
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+#if UDISK_READ_AHEAD_ENABLE
+ disk->udisk_read_ahead_lba_last = -1;
+ disk->remain_len = 0;
+#endif
+ log_error("%s() disk = %x", __func__, disk);
+
+ if (!host_dev_status(host_dev)) {
+ return -DEV_ERR_OFFLINE;
+ }
+
+ const usb_dev usb_id = host_device2id(host_dev);
+ if (host_dev->private_data.status == 0) {
+ return -ENODEV;
+ }
+
+ if (!disk) {
+ log_error("%s not enough memory");
+ return -DEV_ERR_OUTOFMEMORY;
+ }
+
+ disk->dev_status = DEV_INIT;
+
+ const u32 txmaxp = usb_stor_txmaxp(disk);
+ const u32 rxmaxp = usb_stor_rxmaxp(disk);
+
+ u8 lun = 0;
+ ret = get_msd_max_lun(host_dev, &lun);
+ if (ret != DEV_ERR_NONE) {
+ /* disk->dev_status = DEV_IDLE; */
+ /* usb_stor_force_reset(usb_id); */
+ log_error("ret = %d\n", ret);
+ /* return ret; */
+ }
+ /* os_time_dly(10); */
+
+ disk->lun = lun;
+
+ int retry = 5;
+ while (retry) {
+ retry --;
+ if (ret == -DEV_ERR_OFFLINE) {
+ log_error("disk offline");
+ break;
+ }
+ switch (state) {
+ case 0:
+ log_info("--- inquery ---");
+ ret = usb_stor_inquiry(device);
+ if (ret < DEV_ERR_NONE) {
+ os_time_dly(15);
+ if (retry == 2) {
+ ret = -DEV_ERR_OFFLINE;
+ } else {
+ ret = DEV_ERR_NONE;
+ }
+ } else {
+ state++;
+ }
+ break;
+
+ case 1:
+ log_info("--- test unit ready ---");
+ ret = usb_stor_test_unit_ready(device);
+ if (ret < DEV_ERR_NONE) {
+ os_time_dly(50);
+ } else if (disk->csw.bCSWStatus) {
+ os_time_dly(50);
+ ret = usb_stor_request_sense(device);
+ if ((disk->sense.SenseKey & 0x0f) != NO_SENSE) {
+ if (disk->sense.SenseKey == NOT_READY) {
+ os_time_dly(30);
+ disk->curlun++;
+ if (disk->curlun > disk->lun) {
+ disk->curlun = 0;
+ }
+ }
+ }
+ } else {
+ state++;
+ }
+ break;
+
+ case 2:
+ log_info("--- read capacity ---");
+ ret = usb_stor_read_capacity(device);
+ if (ret < DEV_ERR_NONE) {
+ os_time_dly(50);
+ } else if (disk->csw.bCSWStatus) {
+ os_time_dly(50);
+ ret = usb_stor_request_sense(device);
+ if ((disk->sense.SenseKey & 0x0f) != NO_SENSE) {
+ os_time_dly(30);
+ }
+ } else {
+ log_info("udisk mount succ");
+ state = 0xff;
+ }
+ break;
+
+ default:
+ retry = 0;
+ break;
+ }
+ }
+ state = 0;
+
+ if (ret != DEV_ERR_NONE) {
+ disk->dev_status = DEV_IDLE;
+ /* usb_stor_force_reset(usb_id); */
+ log_error("ret = %d\n", ret);
+ } else {
+ /* disk->test_unit_ready_tick = sys_timer_add(device,usb_stor_tick_handle,200); */
+#if ENABLE_DISK_HOTPLUG
+ disk->media_sta_cur = 1;
+ disk->media_sta_prev = 1;
+#endif
+ }
+ disk->suspend_cnt = 0;
+ return ret;
+}
+
+/**
+ * @brief usb_stor_ioctrl
+ *
+ * @param device
+ * @param cmd 支持下面的命令
+ * |命令|功能|
+ * |---|---|
+ * |IOCTL_GET_ID|U盘位于总线的地址0表示不在线|
+ * |IOCTL_GET_BLOCK_SIZE|获取扇区大小|
+ * |IOCTL_GET_CAPACITY|获取磁盘容量|
+ * |IOCTL_GET_MAX_LUN|获取最大磁盘数量<最大支持两个磁盘>|
+ * |IOCTL_GET_CUR_LUN|获取当前的磁盘号|
+ * |IOCTL_SET_CUR_LUN|设置当前的磁盘号|
+ * @param arg
+ *
+ * @return 0----成功
+ * 其他值---失败-
+ */
+static int usb_stor_ioctrl(struct device *device, u32 cmd, u32 arg)
+{
+ int ret = DEV_ERR_NONE;
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ const usb_dev usb_id = host_device2id(host_dev);
+ u32 devnum = host_dev->private_data.devnum;
+ u32 curlun = usb_stor_get_curlun(disk);
+ const u32 rxmaxp = usb_stor_rxmaxp(disk);
+
+ if (disk == NULL) {
+ return -ENOTTY;
+ }
+
+ switch (cmd) {
+ case IOCTL_GET_ID:
+ *(u32 *)arg = devnum;
+ break;
+
+ case IOCTL_GET_BLOCK_SIZE:
+ *(u32 *)arg = disk->capacity[curlun].block_size;
+ break;
+
+ case IOCTL_GET_BLOCK_NUMBER:
+ *(u32 *)arg = disk->capacity[curlun].block_num;
+ break;
+
+ case IOCTL_GET_CAPACITY:
+ *(u32 *)arg = disk->capacity[curlun].block_num;
+ break;
+
+ case IOCTL_GET_MAX_LUN:
+ *(u32 *)arg = disk->lun;
+ break;
+
+ case IOCTL_GET_CUR_LUN:
+ *(u32 *)arg = curlun;
+ break;
+
+ case IOCTL_SET_CUR_LUN:
+ if (arg > disk->lun) {
+ return -EINVAL;
+ }
+ usb_stor_set_curlun(disk, arg);
+ ret = usb_stor_read_capacity(device);
+ if (ret < 0) {
+ log_error("usb disk unit%d is not ready", curlun);
+ return -EFAULT;
+ } else if (disk->csw.bCSWStatus) {
+ usb_stor_request_sense(device);
+ if (disk->sense.SenseKey != NO_SENSE) {
+ log_error("usb disk unit%d is not ready", curlun);
+ }
+ return -EFAULT;
+ }
+ /* usb_stor_mode_sense6(device); */
+ break;
+
+ case IOCTL_CHECK_WRITE_PROTECT:
+ if (disk->read_only) {
+ *(u32 *)arg = 1;
+ } else {
+ *(u32 *)arg = 0;
+ }
+ break;
+
+ case IOCTL_GET_STATUS:
+#if ENABLE_DISK_HOTPLUG
+ if (disk->media_sta_cur) {
+#else
+ if (1) {
+#endif
+ log_info("usb disk unit%d is online", curlun);
+ *(u32 *)arg = 1;
+ } else {
+ log_info("usb disk unit%d is offline", curlun);
+ *(u32 *)arg = 0;
+ }
+ break;
+
+ case IOCTL_SET_FORCE_RESET:
+ ret = usb_stor_force_reset(usb_id);
+ break;
+ case IOCTL_SET_ASYNC_MODE:
+ g_printf(">> UDISK IOCTL_SET_ASYNC_MODE %d\n", arg);
+#if (UDISK_READ_BIGBLOCK_ASYNC_ENABLE || UDISK_READ_512_ASYNC_ENABLE)
+ usb_h_mutex_pend(host_dev);
+ _usb_stor_async_wait_sem(host_dev);
+ if (arg == 0) {
+ if (disk->remain_len == 0) {
+ if (disk->need_send_csw) {
+ //已取完data,需要发csw
+ ret = _usb_stro_read_csw(device);
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d ret:%d\n", __func__, __LINE__, ret);
+ } else if (ret != sizeof(struct usb_scsi_csw)) {
+ ret = -DEV_ERR_UNKNOW;
+ log_error("%s:%d\n", __func__, __LINE__);
+ }
+ disk->need_send_csw = 0;
+ }
+ }
+ //这里要确保上次cbw 请求的数据读取完毕
+ //data
+ while (disk->remain_len) {
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ NULL,
+ 512);
+ disk->remain_len -= 512;
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ disk->remain_len = 0; //data 接收错误直接发csw
+ }
+ if (disk->remain_len == 0) {
+ //csw
+ ret = usb_bulk_only_receive(device,
+ udisk_ep.host_epin,
+ rxmaxp,
+ udisk_ep.target_epin,
+ (u8 *)&disk->csw,
+ sizeof(struct usb_scsi_csw));
+ if (ret < DEV_ERR_NONE) {
+ log_error("%s:%d\n", __func__, __LINE__);
+ } else if (ret != sizeof(struct usb_scsi_csw)) {
+ ret = -DEV_ERR_UNKNOW;
+ log_error("%s:%d\n", __func__, __LINE__);
+ }
+ break;
+ }
+ }
+ }
+ disk->async_en = arg;
+ disk->async_prev_lba = MASS_LBA_INIT;
+ disk->need_send_csw = 0;
+ set_async_mode(BULK_ASYNC_MODE_EXIT);
+ usb_h_mutex_post(host_dev);
+#endif
+ break;
+
+ default:
+ return -ENOTTY;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief usb_msd_parser
+ *
+ * @param device
+ * @param pBuf
+ *
+ * @return
+ */
+int usb_msd_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+ struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
+ pBuf += sizeof(struct usb_interface_descriptor);
+ int len = 0;
+ const usb_dev usb_id = host_device2id(host_dev);
+
+ udisk_device.private_data = host_dev;
+
+ host_dev->interface_info[interface_num] = &udisk_inf;
+
+ for (int endnum = 0; endnum < interface->bNumEndpoints; endnum++) {
+ struct usb_endpoint_descriptor *end_desc = (struct usb_endpoint_descriptor *)pBuf;
+
+ if (end_desc->bDescriptorType != USB_DT_ENDPOINT ||
+ end_desc->bLength != USB_DT_ENDPOINT_SIZE) {
+ log_error("ep bDescriptorType = %d bLength = %d", end_desc->bDescriptorType, end_desc->bLength);
+ return -USB_DT_ENDPOINT;
+ }
+
+ len += USB_DT_ENDPOINT_SIZE;
+ pBuf += USB_DT_ENDPOINT_SIZE;
+
+ if ((end_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+ if (end_desc->bEndpointAddress & USB_DIR_IN) {
+ udisk_ep.host_epin = usb_get_ep_num(usb_id, USB_DIR_IN, USB_ENDPOINT_XFER_BULK);
+ udisk_ep.target_epin = end_desc->bEndpointAddress & 0x0f;
+#if defined(FUSB_MODE) && FUSB_MODE == 0
+ udisk_ep.rxmaxp = end_desc->wMaxPacketSize;
+#endif
+ log_debug("D(%d)->H(%d)", udisk_ep.target_epin, udisk_ep.host_epin);
+ } else {
+ udisk_ep.host_epout = usb_get_ep_num(usb_id, USB_DIR_OUT, USB_ENDPOINT_XFER_BULK);
+ udisk_ep.target_epout = end_desc->bEndpointAddress & 0x0f;
+#if defined(FUSB_MODE) && FUSB_MODE == 0
+ udisk_ep.txmaxp = end_desc->wMaxPacketSize;
+#endif
+ log_debug("H(%d)->D(%d)", udisk_ep.host_epout, udisk_ep.target_epout);
+ }
+ }
+ }
+ u8 *ep_buffer = usb_h_get_ep_buffer(usb_id, udisk_ep.host_epin | USB_DIR_IN);
+#ifdef USB_HW_20
+ usb_write_rxfuncaddr(usb_id, udisk_ep.host_epin, host_dev->private_data.devnum);
+#endif
+ usb_h_ep_config(usb_id, udisk_ep.host_epin | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 0, 0, ep_buffer, usb_stor_rxmaxp(udisk_inf.dev.disk));
+
+
+ ep_buffer = usb_h_get_ep_buffer(usb_id, udisk_ep.host_epout | USB_DIR_OUT);
+#ifdef USB_HW_20
+ usb_write_txfuncaddr(usb_id, udisk_ep.host_epout, host_dev->private_data.devnum);
+#endif
+ usb_h_ep_config(usb_id, udisk_ep.host_epout | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK, 0, 0, ep_buffer, usb_stor_txmaxp(udisk_inf.dev.disk));
+ return len;
+}
+/**
+ * @brief usb_stor_open
+ *
+ * @param node
+ * @param device
+ * @param arg
+ *
+ * @return
+ */
+static int usb_stor_open(const char *name, struct device **device, void *arg)
+{
+ int ret;
+ *device = &udisk_device;
+ struct usb_host_device *host_dev = device_to_usbdev(*device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ const u32 curlun = usb_stor_get_curlun(disk);
+ log_debug("=====================usb_stor_open===================== %d", disk->dev_status);
+ if (disk->dev_status != DEV_IDLE) {
+ if (disk->dev_status == DEV_CLOSE) {
+ log_error("%s() fail, disconnect\n", __func__);
+ return -DEV_ERR_NOT_MOUNT;
+ } else {
+ return DEV_ERR_NONE;
+ }
+ }
+ memset(&disk->mutex, 0, sizeof(disk->mutex));
+ os_mutex_create(&disk->mutex);
+ disk->remain_len = 0;
+ disk->prev_lba = 0;
+#if (UDISK_READ_BIGBLOCK_ASYNC_ENABLE || UDISK_READ_512_ASYNC_ENABLE)
+ disk->async_prev_lba = MASS_LBA_INIT;
+ disk->need_send_csw = 0;
+ disk->async_en = 0; //默认关闭预读模式
+ set_async_mode(BULK_ASYNC_MODE_EXIT);
+#if UDISK_READ_512_ASYNC_ENABLE
+ if (!disk->udisk_512_buf) {
+ disk->udisk_512_buf = zalloc(512);
+ }
+#endif
+#endif
+ ret = usb_stor_init(*device);
+ if (ret) {
+ log_error("usb_stor_init err %d\n", ret);
+ return -ENODEV;
+ }
+ log_debug("device %x", (u32)*device);
+
+
+ usb_h_mutex_pend(host_dev);
+ if (*device) {
+ log_error("mass storage dev name %s", name);
+ disk->dev_status = DEV_OPEN;
+ usb_h_mutex_post(host_dev);
+ return DEV_ERR_NONE;
+ } else {
+ usb_h_mutex_post(host_dev);
+ return -ENODEV;
+ }
+}
+
+/**
+ * @brief usb_stor_close
+ *
+ * @param device
+ *
+ * @return
+ */
+static int usb_stor_close(struct device *device)
+{
+ log_debug("%s---%d\n", __func__, __LINE__);
+ struct usb_host_device *host_dev = device_to_usbdev(device);
+ struct mass_storage *disk = host_device2disk(host_dev);
+ int ret;
+ if (disk->dev_status == DEV_IDLE) {
+ return 0;
+ }
+ log_info("=====================usb_stor_close=====================");
+ if (disk) {
+ log_info("=====================usb_stor_close===================== 333");
+ ret = usb_h_mutex_pend(host_dev);
+
+ const usb_dev usb_id = host_device2id(host_dev);
+ usb_clr_intr_rxe(usb_id, udisk_ep.host_epin);
+
+ disk->dev_status = DEV_IDLE;
+
+ if (ret != OS_ERR_NONE) {
+ log_error("disk close pend timeout!!!\n");
+ } else {
+ usb_h_mutex_post(host_dev);
+ }
+ log_info("=====================usb_stor_close===================== 1222 ");
+
+ os_mutex_del(&disk->mutex, 0);
+ memset(&disk->mutex, 0, sizeof(disk->mutex));
+#if UDISK_READ_512_ASYNC_ENABLE
+ if (disk->udisk_512_buf) {
+ free(disk->udisk_512_buf);
+ disk->udisk_512_buf = NULL;
+ }
+#endif
+ }
+ return DEV_ERR_NONE;
+}
+
+static bool usb_stor_online(const struct dev_node *node)
+{
+ struct device *device = &udisk_device;
+ struct mass_storage *disk = udisk_inf.dev.disk;;
+ if (disk) {
+ return true;//disk->media_sta_cur ? true : false;
+ }
+ return false;
+}
+
+const struct device_operations mass_storage_ops = {
+ .init = NULL,
+ .online = usb_stor_online,
+ .open = usb_stor_open,
+ .read = usb_stor_read,
+ .write = usb_stor_write,
+ .ioctl = usb_stor_ioctrl,
+ .close = usb_stor_close,
+};
+
+static u8 usb_stor_idle_query(void)
+{
+ struct device *device = &udisk_device;
+ struct mass_storage *disk = host_device2disk(host_dev);
+ if (disk) {
+ return (disk->dev_status == DEV_IDLE) ? true : false;
+ }
+ return true;
+}
+
+REGISTER_LP_TARGET(usb_stor_lp_target) = {
+ .name = "udisk",
+ .is_idle = usb_stor_idle_query,
+};
+
+#if 0
+u32 usb_host_mount(const usb_dev id, u32 retry, u32 reset_delay, u32 mount_timeout);
+extern u8 msd_test_buf[32 * 1024];
+void dump_usb_buf();
+void usb_host_test()
+{
+___usb_test:
+ usb_host_mount(0, 3, 20, 200);
+ struct device *device;
+ usb_stor_open("udisk0", &device, NULL);
+ log_info("%s---%d\n", __func__, __LINE__);
+ u32 lba = 0;
+ while (1) {
+
+ u32 *p = (u32 *)msd_test_buf;
+ u32 numOflba = sizeof(msd_test_buf) / 512;
+
+ if ((usb_stor_read(device, p, numOflba, lba)) != numOflba) {
+ printf("read error %d", lba);
+ while (1);
+ }
+#if 1
+ if (usb_stor_write(device, p, numOflba, lba) != numOflba) {
+
+ printf("write error %d", lba);
+ while (1);
+ }
+
+ if ((usb_stor_read(device, p, numOflba, lba)) != numOflba) {
+ printf("read error %d", lba);
+ while (1);
+ }
+#endif
+ for (int i = 0; i < numOflba * 512 / 4; i++) {
+ if (p[i] != (i + lba * 0x80)) {
+ printf("@lba:%x offset %x %x != %x ", lba, i, p[i], i + lba * 0x80);
+ /* put_buf(p, numOflba * 512); */
+ /* while (1); */
+ }
+ }
+ wdt_clear();
+
+ lba += numOflba;
+ }
+}
+#endif
+#endif
diff --git a/apps/common/device/usb/host/usb_storage.h b/apps/common/device/usb/host/usb_storage.h
new file mode 100644
index 0000000..c0558fd
--- /dev/null
+++ b/apps/common/device/usb/host/usb_storage.h
@@ -0,0 +1,145 @@
+/**@file usb_storage.h
+ * @brief usb_storage驱动头文件(做主机)
+ * @details 结构体声明,功能函数声明
+ * @author jieli
+ * @date 2021-8-1
+ * @version V1.0
+ * @copyright Copyright(c)2010-2021 珠海市杰理科技股份有限公司
+ *********************************************************
+ * @attention
+ * 硬件平台:AC695N
+ * SDK版本:AC695N_V1.0.0_SDK
+ * @修改日志:
+ *
+ * Date Version Author Description
+ * 2021-8-1 1.0 jieli 创建初始版本
+ *
+ *
+ *********************************************************
+ */
+#ifndef __USB_STORAGE_H__
+#define __USB_STORAGE_H__
+
+#include "system/task.h"
+#include "device/device.h"
+#include "usb/scsi.h"
+#include "usb_bulk_transfer.h"
+#include "usb/host/usb_host.h"
+
+/* u盘预读功能配置, 二选一
+ * 当两种方式都不使能,则表示不开启预读 */
+#define UDISK_READ_BIGBLOCK_ASYNC_ENABLE 0 //使能大扇区预读方式(不需要额外buf,速度比512预读慢10%)
+#define UDISK_READ_512_ASYNC_ENABLE 0 //使能512Byte预读方式(需要额外的512byte buffer,速度比大扇区预读快10%)
+/****************************/
+
+#define UDISK_READ_ASYNC_BLOCK_NUM (16) //预读扇区数
+
+//****************************youning***********************************----->
+#define UDISK_READ_AHEAD_ENABLE 0 //使能U盘预读功能
+#define UDISK_READ_AHEAD_BLOCK_NUM 16 //U盘预读扇区数量
+#define check_usb_read_ahead(ret) \
+ if(ret < 0) {\
+ log_error("func:%s,line:%d,lba:%d,ret:%d\n", __func__, __LINE__, lba, ret);\
+ goto __exit;\
+ } //检查函数返回值,0:正确 非0:错误
+//****************************youning***********************************<-----
+
+/**@enum usb_sta
+ * @brief USB设备当前状态
+ */
+typedef enum usb_sta {
+ DEV_IDLE = 0, ///<空闲状态
+ DEV_INIT, ///<初始化
+ DEV_OPEN, ///<开启
+ DEV_READ, ///<读操作
+ DEV_WRITE, ///<写操作
+ DEV_CLOSE, ///<关闭
+ DEV_SUSPEND, ///<挂起
+} USB_STA ;
+
+/**@struct udisk_end_desc
+ * @brief U盘端点描述结构体
+ *
+ */
+struct udisk_end_desc {
+ u8 host_epout; ///<主机端点输出
+ u8 target_epout; ///<目标端点输出
+ u8 host_epin; ///<主机端点输入
+ u8 target_epin; ///<目标端点输入
+#if defined(FUSB_MODE) && FUSB_MODE == 0
+ u16 rxmaxp; ///<接收最大端点号
+ u16 txmaxp; ///<发送最大端点号
+#endif
+};
+
+#define ENABLE_DISK_HOTPLUG 0
+
+/**@struct mass_storage
+ * @brief mass_storage协议所使用的相关变量
+ */
+struct mass_storage {
+ OS_MUTEX mutex; ///<互斥量
+
+ struct usb_scsi_cbw cbw; ///bRemoteWakup) {
+ sys_timeout_add(usb_device, usb_resume_sign, 1);
+ }
+}
+void usb_phy_resume(const usb_dev usb_id)
+{
+ usb_iomode(0);
+
+ struct usb_device_t *usb_device = usb_id2device(usb_id);
+ usb_write_faddr(usb_id, usb_device->baddr);
+
+ if (usb_device->baddr == 0) {
+ usb_device->bDeviceStates = USB_DEFAULT;
+ } else {
+ usb_device->bDeviceStates = USB_CONFIGURED;
+ }
+
+ usb_otg_resume(usb_id);
+}
+
+void usb_phy_suspend(const usb_dev usb_id)
+{
+ gpio_set_pull_up(IO_PORT_DP, 1);
+ gpio_set_pull_down(IO_PORT_DP, 0);
+ gpio_set_direction(IO_PORT_DP, 1);
+
+ usb_iomode(1);
+ /* musb_read_usb(0, MUSB_INTRUSB); */
+
+ usb_otg_suspend(usb_id, OTG_KEEP_STATE);
+}
+void usb_isr(const usb_dev usb_id)
+{
+ u32 intr_usb, intr_usbe;
+ u32 intr_tx, intr_txe;
+ u32 intr_rx, intr_rxe;
+
+ __asm__ volatile("ssync");
+ usb_read_intr(usb_id, &intr_usb, &intr_tx, &intr_rx);
+ usb_read_intre(usb_id, &intr_usbe, &intr_txe, &intr_rxe);
+ struct usb_device_t *usb_device = usb_id2device(usb_id);
+
+ intr_usb &= intr_usbe;
+ intr_tx &= intr_txe;
+ intr_rx &= intr_rxe;
+
+ if (intr_usb & INTRUSB_SUSPEND) {
+ log_error("usb suspend");
+ set_sleep_flag(1);
+#if USB_SUSPEND_RESUME
+ usb_phy_suspend(usb_id);
+#endif
+
+#if USB_SUSPEND_RESUME_SYSTEM_NO_SLEEP
+ printf("\n NULL \n");
+#endif
+ }
+ if (intr_usb & INTRUSB_RESET_BABBLE) {
+ log_error("usb reset");
+ usb_reset_interface(usb_device);
+
+#if USB_SUSPEND_RESUME || USB_SUSPEND_RESUME_SYSTEM_NO_SLEEP
+ u32 reg = usb_read_power(usb_id);
+ usb_write_power(usb_id, (reg | INTRUSB_SUSPEND | INTRUSB_RESUME));//enable suspend resume
+#endif
+ }
+
+ if (intr_usb & INTRUSB_RESUME) {
+ log_error("usb resume");
+#if USB_SUSPEND_RESUME
+ usb_phy_resume(usb_id);
+#endif
+ }
+
+ if (intr_tx & BIT(0)) {
+ if (usb_interrupt_rx[usb_id][0]) {
+ usb_interrupt_rx[usb_id][0](usb_device, 0);
+ } else {
+ usb_control_transfer(usb_device);
+ }
+ }
+
+ for (int i = 1; i < MAX_EP_TX; i++) {
+ if (intr_tx & BIT(i)) {
+ if (usb_interrupt_tx[usb_id][i]) {
+ usb_interrupt_tx[usb_id][i](usb_device, i);
+ }
+ }
+ }
+
+ for (int i = 1; i < MAX_EP_RX; i++) {
+ if (intr_rx & BIT(i)) {
+ if (usb_interrupt_rx[usb_id][i]) {
+ usb_interrupt_rx[usb_id][i](usb_device, i);
+ }
+ }
+ }
+ __asm__ volatile("csync");
+}
+
+void usb_sof_isr(const usb_dev usb_id)
+{
+ usb_sof_clr_pnd(usb_id);
+ static u32 sof_count = 0;
+ if ((sof_count++ % 1000) == 0) {
+ log_d("sof 1s isr frame:%d", usb_read_sofframe(usb_id));
+ }
+}
+void usb_suspend_check(void *p)
+{
+ usb_dev usb_id = (usb_dev)p;
+
+ static u16 sof_frame = 0;
+ u16 frame = usb_read_sofframe(usb_id);// sof frame 不更新,则usb进入断开或者suspend状态
+ if (frame == sof_frame) {
+ usb_phy_suspend(usb_id);
+ }
+ sof_frame = frame;
+}
+
+SET_INTERRUPT
+void usb0_g_isr()
+{
+ usb_isr(0);
+}
+SET_INTERRUPT
+void usb0_sof_isr()
+{
+ usb_sof_isr(0);
+}
+
+#if USB_MAX_HW_NUM == 2
+SET_INTERRUPT
+void usb1_g_isr()
+{
+ usb_isr(1);
+}
+SET_INTERRUPT
+void usb1_sof_isr()
+{
+ usb_sof_isr(1);
+}
+#endif
+__attribute__((always_inline_when_const_args))
+u32 usb_g_set_intr_hander(const usb_dev usb_id, u32 ep, usb_interrupt hander)
+{
+ if (ep & USB_DIR_IN) {
+ usb_interrupt_tx[usb_id][ep & 0xf] = hander;
+ } else {
+ usb_interrupt_rx[usb_id][ep] = hander;
+ }
+ return 0;
+}
+void usb_g_isr_reg(const usb_dev usb_id, u8 priority, u8 cpu_id)
+{
+ if (usb_id == 0) {
+ request_irq(IRQ_USB_CTRL_IDX, priority, usb0_g_isr, cpu_id);
+ } else {
+#if USB_MAX_HW_NUM == 2
+ request_irq(IRQ_USB1_CTRL_IDX, priority, usb1_g_isr, cpu_id);
+#endif
+ }
+}
+void usb_sof_isr_reg(const usb_dev usb_id, u8 priority, u8 cpu_id)
+{
+ if (usb_id == 0) {
+ request_irq(IRQ_USB_SOF_IDX, priority, usb0_sof_isr, cpu_id);
+ } else {
+#if USB_MAX_HW_NUM == 2
+ request_irq(IRQ_USB1_SOF_IDX, priority, usb1_sof_isr, cpu_id);
+#endif
+ }
+}
+u32 usb_config(const usb_dev usb_id)
+{
+ memset(usb_interrupt_rx[usb_id], 0, sizeof(usb_interrupt_rx[usb_id]));
+ memset(usb_interrupt_tx[usb_id], 0, sizeof(usb_interrupt_tx[usb_id]));
+
+ if (!usb_config_var) {
+#if USB_MALLOC_ENABLE
+ usb_config_var = (struct usb_config_var_t *)zalloc(sizeof(struct usb_config_var_t));
+ if (!usb_config_var) {
+ return -1;
+ }
+#else
+ memset(&_usb_config_var, 0, sizeof(_usb_config_var));
+ usb_config_var = &_usb_config_var;
+#endif
+ }
+ log_debug("zalloc: usb_config_var = %x\n", usb_config_var);
+
+ usb_var_init(usb_id, &(usb_config_var->usb_ep_addr));
+ usb_setup_init(usb_id, &(usb_config_var->usb_setup), usb_config_var->usb_setup_buffer);
+ return 0;
+}
+
+u32 usb_release(const usb_dev usb_id)
+{
+ log_debug("free zalloc: usb_config_var = %x\n", usb_id, usb_config_var);
+ usb_var_init(usb_id, NULL);
+ usb_setup_init(usb_id, NULL, NULL);
+#if USB_MALLOC_ENABLE
+ if (usb_config_var) {
+ log_debug("free: usb_config_var = %x\n", usb_config_var);
+ free(usb_config_var);
+ }
+#endif
+
+ usb_config_var = NULL;
+
+ return 0;
+}
diff --git a/apps/common/device/usb/usb_config.h b/apps/common/device/usb/usb_config.h
new file mode 100644
index 0000000..116ba63
--- /dev/null
+++ b/apps/common/device/usb/usb_config.h
@@ -0,0 +1,139 @@
+/**@file usb_config.h
+ * @brief usb_config配置头文件
+ * @details 功能函数声明
+ * @author jieli
+ * @date 2021-8-1
+ * @version V1.0
+ * @copyright Copyright(c)2010-2021 珠海市杰理科技股份有限公司
+ *********************************************************
+ * @attention
+ * 硬件平台:AC695N
+ * SDK版本:AC695N_V1.0.0_SDK
+ * @修改日志:
+ *
+ * Date Version Author Description
+ * 2021-8-1 1.0 jieli 创建初始版本
+ *
+ *
+ *********************************************************
+ */
+#ifndef __USB_CONFIG_H__
+#define __USB_CONFIG_H__
+
+#include "typedef.h"
+#include "asm/usb.h"
+#include "usb/device/usb_stack.h"
+#include "usb/host/usb_host.h"
+
+/**@brief USB主机模式配置
+ * @param[in] usb_id USB的id号
+ * @return 无
+ * @par 示例:
+ * @code
+ * usb_host_config(usb_id);
+ * @encode
+ */
+void usb_host_config(usb_dev usb_id);
+
+/**@brief USB主机模式释放
+ * @param[in] usb_id USB的id号
+ * @return 无
+ * @par 示例:
+ * @code
+ * usb_host_free(usb_id);
+ * @encode
+ */
+void usb_host_free(usb_dev usb_id);
+
+/**@brief USB主机模式获取端点的BUFFER的地址
+ * @param[in] usb_id USB的id号
+ * @param[in] ep 端点号
+ * @return 无
+ * @par 示例:
+ * @code
+ * usb_h_get_ep_bufeeer(usb_id , ep);
+ * @encode
+ */
+void *usb_h_get_ep_buffer(const usb_dev usb_id, u32 ep);
+
+/**@brief USB主机模式中断注册
+ * @param[in] usb_id USB的id号
+ * @param[in] priority 优先级
+ * @param[in] cpu_id cpu的id号
+ * @return 无
+ * @par 示例:
+ * @code
+ * usb_h_isr_reg(usb_id , ep);
+ * @encode
+ */
+void usb_h_isr_reg(const usb_dev usb_id, u8 priority, u8 cpu_id);
+
+/**@brief USB从机模式中断注册
+ * @param[in] usb_id USB的id号
+ * @param[in] priority 优先级
+ * @param[in] cpu_id cpu的id号
+ * @return 无
+ * @par 示例:
+ * @code
+ * usb_g_isr_reg(usb_id , ep);
+ * @encode
+ */
+void usb_g_isr_reg(const usb_dev usb_id, u8 priority, u8 cpu_id);
+
+
+
+/**@brief USB SOF中断注册
+ * @param[in] usb_id USB的id号
+ * @param[in] priority 优先级
+ * @param[in] cpu_id cpu的id号
+ * @return 无
+ * @par 示例:
+ * @code
+ * usb_sof_isr_reg(usb_id , ep);
+ * @encode
+ */
+void usb_sof_isr_reg(const usb_dev usb_id, u8 priority, u8 cpu_id);
+
+/**@brief 分配端点BUFFER的dma地址
+ * @param[in] usb_id USB的id号
+ * @param[in] ep 端点号
+ * @param[in] dma_size 数据长度
+ * @return 无
+ * @par 示例:
+ * @code
+ * usb_alloc_ep_dmabuffer(usb_id , ep , size);
+ * @encode
+ */
+void *usb_alloc_ep_dmabuffer(const usb_dev usb_id, u32 ep, u32 dma_size);
+
+/**@brief USB从机初始化配置
+ * @param[in] usb_id USB的id号
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_config(usb_id);
+ * @encode
+ */
+u32 usb_config(const usb_dev usb_id);
+
+/**@brief USB从机释放
+ * @param[in] usb_id USB的id号
+ * @return 0:成功
+ * @par 示例:
+ * @code
+ * usb_release(usb_id);
+ * @encode
+ */
+u32 usb_release(const usb_dev usb_id);
+
+/**@brief USB内存空间初始化
+ * @param[in] 无
+ * @return 无
+ * @par 示例:
+ * @code
+ * usb_memory_init(usb_id);
+ * @encode
+ */
+void usb_memory_init();
+
+#endif /*USB_CONFIG_H*/
diff --git a/apps/common/device/usb/usb_host_config.c b/apps/common/device/usb/usb_host_config.c
new file mode 100644
index 0000000..e4b2128
--- /dev/null
+++ b/apps/common/device/usb/usb_host_config.c
@@ -0,0 +1,194 @@
+#include "usb_config.h"
+#include "usb/scsi.h"
+#include "irq.h"
+#include "init.h"
+#include "gpio.h"
+#include "app_config.h"
+#define LOG_TAG_CONST USB
+#define LOG_TAG "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#define SET_INTERRUPT ___interrupt
+
+#if TCFG_UDISK_ENABLE || TCFG_ADB_ENABLE ||TCFG_AOA_ENABLE || TCFG_HID_HOST_ENABLE || TCFG_HOST_AUDIO_ENABLE
+
+#if TCFG_HID_HOST_ENABLE
+#define MAX_HOST_EP_RX 4
+#define MAX_HOST_EP_TX 4
+#else
+#define MAX_HOST_EP_RX 2
+#define MAX_HOST_EP_TX 2 //ep0 & ep1(msd)
+#endif
+
+struct host_var_t {
+ struct usb_ep_addr_t host_ep_addr ;
+ usb_h_interrupt usb_h_interrupt_rx[MAX_HOST_EP_RX] ;
+ usb_h_interrupt usb_h_interrupt_tx[MAX_HOST_EP_TX] ;
+ struct usb_host_device *dev_at_ep[MAX_HOST_EP_RX];
+};
+static struct host_var_t *host_var[USB_MAX_HW_NUM];// SEC(.usb_h_bss);
+static struct host_var_t __host_var[USB_MAX_HW_NUM];
+#if TCFG_ADB_ENABLE && TCFG_AOA_ENABLE && TCFG_HID_HOST_ENABLE
+static u8 ep0_dma[USB_MAX_HW_NUM][64 + 4] __attribute__((aligned(4)));
+static u8 ep1_dma[USB_MAX_HW_NUM][64 * 2 + 4] __attribute__((aligned(4)));
+static u8 ep2_dma[USB_MAX_HW_NUM][64 * 2 + 4] __attribute__((aligned(4)));
+static u8 ep3_dma[USB_MAX_HW_NUM][64 * 2 + 4] __attribute__((aligned(4)));
+static u8 ep4_dma[USB_MAX_HW_NUM][64 * 2 + 4] __attribute__((aligned(4)));
+#else
+#if defined(FUSB_MODE) && FUSB_MODE
+static u8 msd_h_dma_buffer[2][64 + 4] __attribute__((aligned(4))) SEC(.usb_h_dma);
+#elif defined(FUSB_MODE) && (FUSB_MODE == 0)
+static u8 msd_h_dma_buffer[2][512] __attribute__((aligned(4))) SEC(.usb_h_dma);
+#else
+#error "USB_SPEED_MODE not defined"
+#endif
+#endif
+
+void usb_h_isr(const usb_dev usb_id)
+{
+ u32 intr_usb, intr_usbe;
+ u32 intr_tx, intr_txe;
+ u32 intr_rx, intr_rxe;
+
+ __asm__ volatile("ssync");
+
+ usb_read_intr(usb_id, &intr_usb, &intr_tx, &intr_rx);
+ usb_read_intre(usb_id, &intr_usbe, &intr_txe, &intr_rxe);
+ struct usb_host_device *host_dev = NULL;
+
+ /* r_printf("usb_h_isr %x %x %x %x",host_dev,intr_usb,intr_tx,intr_rx); */
+ intr_usb &= intr_usbe;
+ intr_tx &= intr_txe;
+ intr_rx &= intr_rxe;
+
+ if (intr_usb & INTRUSB_SUSPEND) {
+ log_error("usb suspend");
+ }
+ if (intr_usb & INTRUSB_RESET_BABBLE) {
+ log_error("usb reset");
+ }
+ if (intr_usb & INTRUSB_RESUME) {
+ log_error("usb resume");
+ }
+
+ if (intr_tx & BIT(0)) {
+ if (host_var[usb_id]->usb_h_interrupt_tx[0]) {
+ host_dev = host_var[usb_id]->dev_at_ep[0];
+ host_var[usb_id]->usb_h_interrupt_tx[0](host_dev, 0);
+ }
+ }
+
+ for (int i = 1; i < MAX_HOST_EP_TX; i++) {
+ if (intr_tx & BIT(i)) {
+ if (host_var[usb_id]->usb_h_interrupt_tx[i]) {
+ host_dev = host_var[usb_id]->dev_at_ep[i];
+ host_var[usb_id]->usb_h_interrupt_tx[i](host_dev, i);
+ }
+ }
+ }
+
+ for (int i = 1; i < MAX_HOST_EP_RX; i++) {
+ if (intr_rx & BIT(i)) {
+ if (host_var[usb_id]->usb_h_interrupt_rx[i]) {
+ host_dev = host_var[usb_id]->dev_at_ep[i];
+ host_var[usb_id]->usb_h_interrupt_rx[i](host_dev, i);
+ }
+ }
+ }
+ __asm__ volatile("csync");
+}
+SET_INTERRUPT
+void usb0_h_isr()
+{
+ usb_h_isr(0);
+}
+SET_INTERRUPT
+void usb1_h_isr()
+{
+ usb_h_isr(1);
+}
+__attribute__((always_inline_when_const_args))
+u32 usb_h_set_intr_hander(const usb_dev usb_id, u32 ep, usb_h_interrupt hander)
+{
+ if (ep & USB_DIR_IN) {
+ host_var[usb_id]->usb_h_interrupt_rx[ep & 0xf] = hander;
+ } else {
+ host_var[usb_id]->usb_h_interrupt_tx[ep] = hander;
+ }
+ return 0;
+}
+void usb_h_isr_reg(const usb_dev usb_id, u8 priority, u8 cpu_id)
+{
+ if (usb_id == 0) {
+ request_irq(IRQ_USB_CTRL_IDX, priority, usb0_h_isr, cpu_id);
+#if USB_MAX_HW_NUM > 1
+ } else if (usb_id == 1) {
+ request_irq(IRQ_USB1_CTRL_IDX, priority, usb1_h_isr, cpu_id);
+#endif
+ }
+}
+
+__attribute__((always_inline_when_const_args))
+void *usb_h_get_ep_buffer(const usb_dev usb_id, u32 ep)
+{
+#if TCFG_ADB_ENABLE && TCFG_AOA_ENABLE && TCFG_HID_HOST_ENABLE
+ u8 dir = !!(ep & USB_DIR_IN);
+ u8 *p = NULL;
+ switch (ep & 0xf) {
+ case 0:
+ p = &ep0_dma[usb_id][0];
+ break;
+ case 1:
+ p = &ep1_dma[usb_id][dir * 64];
+ break;
+ case 2:
+ p = &ep2_dma[usb_id][dir * 64];
+ break;
+ case 3:
+ p = &ep3_dma[usb_id][dir * 64];
+ break;
+ case 4:
+ p = &ep4_dma[usb_id][dir * 64];
+ break;
+ }
+ return p;
+#else
+ return msd_h_dma_buffer;
+#endif
+}
+void usb_h_set_ep_isr(struct usb_host_device *host_dev, u32 ep, usb_h_interrupt hander, void *p)
+{
+ if (host_dev) {
+ usb_dev usb_id = host_device2id(host_dev);
+ host_var[usb_id]->dev_at_ep[ep & 0xf] = p;
+ usb_h_set_intr_hander(usb_id, ep, hander);
+ }
+}
+void usb_host_config(usb_dev usb_id)
+{
+ /* host_var[usb_id] = zalloc(sizeof(struct host_var_t)); */
+ host_var[usb_id] = &__host_var[usb_id];
+
+ ASSERT(host_var[usb_id], "host_var_t");
+
+ g_printf("%s() %x %x", __func__, host_var[usb_id], &(host_var[usb_id]->host_ep_addr));
+ usb_var_init(usb_id, &(host_var[usb_id]->host_ep_addr));
+}
+void usb_host_free(usb_dev usb_id)
+{
+ g_printf("%s() %x", __func__, host_var[usb_id]);
+ OS_ENTER_CRITICAL();
+ /* free(host_var[usb_id]); */
+ /* host_var[usb_id] = NULL; */
+ if (host_var[usb_id]) {
+ memset(host_var[usb_id]->usb_h_interrupt_rx, 0, sizeof(usb_h_interrupt) * MAX_HOST_EP_RX);
+ memset(host_var[usb_id]->usb_h_interrupt_tx, 0, sizeof(usb_h_interrupt) * MAX_HOST_EP_TX);
+ }
+ OS_EXIT_CRITICAL();
+}
+#endif
diff --git a/apps/common/device/usb/usb_std_class_def.h b/apps/common/device/usb/usb_std_class_def.h
new file mode 100644
index 0000000..cdef1af
--- /dev/null
+++ b/apps/common/device/usb/usb_std_class_def.h
@@ -0,0 +1,190 @@
+#ifndef __USB_STD_CLASS_DEF_H__
+#define __USB_STD_CLASS_DEF_H__
+
+#ifndef USB_MALLOC_ENABLE
+#define USB_MALLOC_ENABLE 0
+#endif
+#ifndef USB_HOST_ASYNC
+#define USB_HOST_ASYNC 1
+#endif
+#ifndef USB_H_MALLOC_ENABLE
+#define USB_H_MALLOC_ENABLE 1
+#endif
+#ifndef USB_DEVICE_CLASS_CONFIG
+#define USB_DEVICE_CLASS_CONFIG (SPEAKER_CLASS|MIC_CLASS|HID_CLASS|MASSSTORAGE_CLASS)
+#endif
+
+///////////MassStorage Class
+#ifndef MSD_BULK_EP_OUT
+#define MSD_BULK_EP_OUT 1
+#endif
+#ifndef MSD_BULK_EP_IN
+#define MSD_BULK_EP_IN 1
+#endif
+#ifndef MAXP_SIZE_BULKOUT
+#if defined(FUSB_MODE) && FUSB_MODE
+#define MAXP_SIZE_BULKOUT 64
+#elif defined(FUSB_MODE) && FUSB_MODE == 0
+#define MAXP_SIZE_BULKOUT 512
+#endif
+#endif
+#ifndef MAXP_SIZE_BULKIN
+#if defined(FUSB_MODE) && FUSB_MODE
+#define MAXP_SIZE_BULKIN 64
+#elif defined(FUSB_MODE) && FUSB_MODE == 0
+#define MAXP_SIZE_BULKIN 512
+#endif
+#endif
+#ifndef MSD_STR_INDEX
+#define MSD_STR_INDEX 7
+#endif
+
+///////////HID class
+#ifndef HID_EP_IN
+#define HID_EP_IN 2
+#endif
+#ifndef HID_EP_OUT
+#define HID_EP_OUT 2
+#endif
+#ifndef HID_EP_IN_2
+#define HID_EP_IN_2 3
+#endif
+#ifndef HID_EP_OUT_2
+#define HID_EP_OUT_2 3
+#endif
+#ifndef MAXP_SIZE_HIDOUT
+#define MAXP_SIZE_HIDOUT 16
+#endif
+#ifndef MAXP_SIZE_HIDIN
+#define MAXP_SIZE_HIDIN 16
+#endif
+#ifndef HID_INTR_INTERVAL
+#if defined(FUSB_MODE) && FUSB_MODE
+#define HID_INTR_INTERVAL 1
+#elif defined(FUSB_MODE) && FUSB_MODE == 0
+#define HID_INTR_INTERVAL 4
+#endif
+#endif
+
+/////////////Audio Class
+#ifndef UAC_ISO_INTERVAL
+#if defined(FUSB_MODE) && FUSB_MODE
+#define UAC_ISO_INTERVAL 1
+#elif defined(FUSB_MODE) && FUSB_MODE == 0
+#define UAC_ISO_INTERVAL 4
+#endif
+#endif
+//speaker class
+#ifndef SPK_AUDIO_RATE
+#define SPK_AUDIO_RATE 48000
+#endif
+#ifndef SPK_AUDIO_RES
+#define SPK_AUDIO_RES 16
+#endif
+#ifndef SPK_CHANNEL
+#define SPK_CHANNEL 2
+#endif
+#ifndef SPK_FRAME_LEN
+#define SPK_FRAME_LEN (((SPK_AUDIO_RATE) * SPK_AUDIO_RES / 8 * SPK_CHANNEL)/1000+4)
+#endif
+#ifndef SPK_PCM_Type
+#define SPK_PCM_Type (SPK_AUDIO_RES >> 4) // 0=8 ,1=16
+#endif
+#ifndef SPK_AUDIO_TYPE
+#define SPK_AUDIO_TYPE (0x02 - SPK_PCM_Type) // TYPE1_PCM16
+#endif
+#ifndef SPK_ISO_EP_OUT
+#ifdef CONFIG_CPU_BR18
+#define SPK_ISO_EP_OUT 2
+#else
+#define SPK_ISO_EP_OUT 3
+#endif
+#endif
+#ifndef SPEAKER_STR_INDEX
+#define SPEAKER_STR_INDEX 5
+#endif
+#ifndef SPK_INPUT_TERMINAL_ID
+#define SPK_INPUT_TERMINAL_ID 1
+#endif
+#ifndef SPK_FEATURE_UNIT_ID
+#define SPK_FEATURE_UNIT_ID 2
+#endif
+#ifndef SPK_OUTPUT_TERMINAL_ID
+#define SPK_OUTPUT_TERMINAL_ID 3
+#endif
+#ifndef SPK_SELECTOR_UNIT_ID
+#define SPK_SELECTOR_UNIT_ID 8
+#endif
+
+/////////////Microphone Class
+#ifndef MIC_SamplingFrequency
+#define MIC_SamplingFrequency 1
+#endif
+
+#if MIC_SamplingFrequency == 1
+#define MIC_AUDIO_RATE 48000
+#else
+#define MIC_AUDIO_RATE 192000
+#define MIC_AUDIO_RATE_1 44100
+#define MIC_AUDIO_RATE_2 48000
+#define MIC_AUDIO_RATE_4 96000
+#endif
+
+#ifndef MIC_AUDIO_RES
+#define MIC_AUDIO_RES 16
+#endif
+#ifndef MIC_CHANNEL
+#define MIC_CHANNEL 1
+#endif
+#ifndef MIC_FRAME_LEN
+#define MIC_FRAME_LEN ((MIC_AUDIO_RATE * MIC_AUDIO_RES / 8 * MIC_CHANNEL)/1000)
+#endif
+#ifndef MIC_PCM_TYPE
+#define MIC_PCM_TYPE (MIC_AUDIO_RES >> 4) // 0=8 ,1=16
+#endif
+#ifndef MIC_AUDIO_TYPE
+#define MIC_AUDIO_TYPE (0x02 - MIC_PCM_TYPE)
+#endif
+#ifndef MIC_ISO_EP_IN
+#define MIC_ISO_EP_IN 3
+#endif
+#ifndef MIC_STR_INDEX
+#define MIC_STR_INDEX 6
+#endif
+#ifndef MIC_INPUT_TERMINAL_ID
+#define MIC_INPUT_TERMINAL_ID 4
+#endif
+#ifndef MIC_FEATURE_UNIT_ID
+#define MIC_FEATURE_UNIT_ID 5
+#endif
+#ifndef MIC_OUTPUT_TERMINAL_ID
+#define MIC_OUTPUT_TERMINAL_ID 6
+#endif
+#ifndef MIC_SELECTOR_UNIT_ID
+#define MIC_SELECTOR_UNIT_ID 7
+#endif
+
+////////////CDC Class
+#ifndef CDC_DATA_EP_IN
+#define CDC_DATA_EP_IN 4
+#endif
+#ifndef CDC_DATA_EP_OUT
+#define CDC_DATA_EP_OUT 4
+#endif
+#ifndef CDC_INTR_EP_IN
+#define CDC_INTR_EP_IN 5
+#endif
+#ifndef MAXP_SIZE_CDC_BULKIN
+#define MAXP_SIZE_CDC_BULKIN 64
+#endif
+#ifndef MAXP_SIZE_CDC_BULKOUT
+#define MAXP_SIZE_CDC_BULKOUT 64
+#endif
+#ifndef MAXP_SIZE_CDC_INTRIN
+#define MAXP_SIZE_CDC_INTRIN 8
+#endif
+#ifndef CDC_INTR_EP_ENABLE
+#define CDC_INTR_EP_ENABLE 0
+#endif
+
+#endif
diff --git a/apps/common/fat_nor/cfg_private.c b/apps/common/fat_nor/cfg_private.c
new file mode 100644
index 0000000..fb96120
--- /dev/null
+++ b/apps/common/fat_nor/cfg_private.c
@@ -0,0 +1,327 @@
+#include "includes.h"
+#include "boot.h"
+#include "asm/sfc_norflash_api.h"
+#include "cfg_private.h"
+/* #include "sdfile.h" */
+
+#define CFG_PRIVATE_FILE_NUM 5
+SDFILE_FILE_HEAD head = {0};
+static u8 cfg_private_create_flag = 0;
+static u32 cfg_private_create_sclust = 0;
+
+
+static FILE *cfg_private_create(const char *path, const char *mode)
+{
+ int i = 0;
+ char *str = NULL;
+ char *part_path = NULL;
+ char *buf_temp = NULL;
+ int file_head_len = 0;
+ int align_size = 4096;
+ if (boot_info.vm.align == 1) {
+ align_size = 256;
+ }
+
+ str = strrchr(path, '/');
+ /* r_printf(">>>[test]:file name str = %s\n", str + 1); */
+ part_path = (char *)zalloc(strlen(path));
+ memcpy(part_path, path, strlen(path) - strlen(str));
+ /* r_printf(">>>[test]:part_path = %s\n", part_path); */
+ FILE *file = fopen(part_path, "r");
+ if (!file) {
+ r_printf(">>>[test]:no apply part!!!!!!!\n");
+ goto __exit;
+ }
+ struct vfs_attr attrs = {0};
+ fget_attrs(file, &attrs);
+ attrs.sclust = sdfile_cpu_addr2flash_addr(attrs.sclust);
+ if (attrs.sclust % align_size) {
+ fclose(file);
+ file = NULL;
+ r_printf(">>>[test]:part start addr is not alignment, sclust = %d, align_size = %d\n", attrs.sclust, align_size);
+ goto __exit;
+ }
+ cfg_private_create_sclust = attrs.sclust;
+ buf_temp = (char *)malloc(align_size);
+ norflash_read(NULL, (void *)buf_temp, align_size, attrs.sclust);
+ for (; i < CFG_PRIVATE_FILE_NUM; i++) {
+ int addr = attrs.sclust + i * sizeof(SDFILE_FILE_HEAD);
+ norflash_read(NULL, (void *)&head, sizeof(SDFILE_FILE_HEAD), addr);
+ if (CRC16((u8 *)&head + 2, sizeof(SDFILE_FILE_HEAD) - 2) == head.head_crc) {
+ file_head_len += head.len;
+ continue;
+ }
+ memset(&head, 0, sizeof(SDFILE_FILE_HEAD));
+ head.len = attrs.fsize - CFG_PRIVATE_FILE_NUM * sizeof(SDFILE_FILE_HEAD) - file_head_len;
+ /* y_printf(">>>[test]:file len = %d\n", head.len); */
+ head.addr = attrs.sclust + CFG_PRIVATE_FILE_NUM * sizeof(SDFILE_FILE_HEAD) + file_head_len;
+ head.addr = sdfile_flash_addr2cpu_addr(head.addr);
+ /* y_printf(">>>[test]:file addr = %d\n", head.addr); */
+ memcpy(head.name, (char *)(str + 1), strlen(str + 1));
+ head.attr = 0x02;
+ head.head_crc = CRC16((u8 *)&head + 2, sizeof(SDFILE_FILE_HEAD) - 2);
+ break;
+ }
+ if (i >= CFG_PRIVATE_FILE_NUM) {
+ fclose(file);
+ file = NULL;
+ r_printf(">>>[test]:file head is over\n");
+ goto __exit;
+ }
+ cfg_private_erase(attrs.sclust, align_size);
+ memcpy(buf_temp + i * sizeof(SDFILE_FILE_HEAD), &head, sizeof(SDFILE_FILE_HEAD));
+ norflash_write(NULL, (void *)buf_temp, align_size, attrs.sclust);
+ /* put_buf(buf_temp, align_size); */
+ fclose(file);
+ file = NULL;
+ file = fopen(path, mode);
+
+__exit:
+ if (part_path) {
+ free(part_path);
+ }
+ if (buf_temp) {
+ free(buf_temp);
+ }
+ return file;
+}
+
+FILE *cfg_private_open(const char *path, const char *mode)
+{
+ int res;
+ FILE *file = fopen(path, mode);
+ if (!file) {
+ if (mode[0] == 'w' && mode[1] == '+') {
+ file = cfg_private_create(path, mode);
+ if (file) {
+ cfg_private_create_flag = 1;
+ }
+ }
+ }
+ return file;
+}
+
+int cfg_private_read(FILE *file, void *buf, u32 len)
+{
+ return fread(file, buf, len);
+}
+
+void cfg_private_erase(u32 addr, u32 len)
+{
+ /* r_printf(">>>[test]:addr = 0x%x, len = %d\n", addr, len); */
+ u32 erase_total_size = len;
+ u32 erase_addr = addr;
+ u32 erase_size = 4096;
+ u32 erase_cmd = IOCTL_ERASE_SECTOR;
+ //flash不同支持的最小擦除单位不同(page/sector)
+ //boot_info.vm.align == 1: 最小擦除单位page;
+ //boot_info.vm.align != 1: 最小擦除单位sector;
+ if (boot_info.vm.align == 1) {
+ erase_size = 256;
+ erase_cmd = IOCTL_ERASE_PAGE;
+ }
+ while (erase_total_size) {
+ //擦除区域操作
+ norflash_ioctl(NULL, erase_cmd, erase_addr);
+ erase_addr += erase_size;
+ erase_total_size -= erase_size;
+ }
+}
+
+int cfg_private_check(char *buf, int len)
+{
+ for (int i = 0; i < len; i++) {
+ if (buf[i] != 0xff) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int cfg_private_write(FILE *file, void *buf, u32 len)
+{
+ int align_size = 4096;
+ if (boot_info.vm.align == 1) {
+ align_size = 256;
+ }
+ struct vfs_attr attrs = {0};
+ fget_attrs(file, &attrs);
+ /* r_printf(">>>[test]:attrs.sclust = 0x%x\n", attrs.sclust); */
+ attrs.sclust = sdfile_cpu_addr2flash_addr(attrs.sclust);
+ u32 fptr = fpos(file);
+ /* r_printf(">>>[test]:addr = %d, fsize = %d, fptr = %d, w_len = %d\n", attrs.sclust, attrs.fsize, fptr, len); */
+ if (len + fptr > attrs.fsize) {
+ r_printf(">>>[test]:error, write over!!!!!!!!\n");
+ return -1;
+ }
+ char *buf_temp = (char *)malloc(align_size);
+ int res = len;
+
+ for (int wlen = 0; len > 0;) {
+ u32 align_addr = (attrs.sclust + fptr) / align_size * align_size;
+ u32 w_pos = attrs.sclust + fptr - align_addr;
+ wlen = align_size - w_pos;
+ /* y_printf(">>>[test]:wpos = %d, wlen = %d\n", w_pos, wlen); */
+ if (wlen > len) {
+ wlen = len;
+ }
+ norflash_read(NULL, (void *)buf_temp, align_size, align_addr);
+ if (0 == cfg_private_check(buf_temp, align_size)) {
+ cfg_private_erase(align_addr, align_size);
+ }
+ memcpy(buf_temp + w_pos, buf, wlen);
+ /* put_buf(buf_temp, align_size); */
+ norflash_write(NULL, (void *)buf_temp, align_size, align_addr);
+ fptr += wlen;
+ len -= wlen;
+ }
+__exit:
+ free(buf_temp);
+ fseek(file, fptr, SEEK_SET);
+ return res;
+}
+
+int cfg_private_delete_file(FILE *file)
+{
+ int align_size = 4096;
+ if (boot_info.vm.align == 1) {
+ align_size = 256;
+ }
+ struct vfs_attr attrs = {0};
+ fget_attrs(file, &attrs);
+ attrs.sclust = sdfile_cpu_addr2flash_addr(attrs.sclust);
+ int len = attrs.fsize;
+ char *buf_temp = (char *)malloc(align_size);
+ u32 fptr = 0;
+
+ for (int wlen = 0; len > 0;) {
+ u32 align_addr = (attrs.sclust + fptr) / align_size * align_size;
+ u32 w_pos = attrs.sclust + fptr - align_addr;
+ wlen = align_size - w_pos;
+ if (wlen > len) {
+ wlen = len;
+ }
+ norflash_read(NULL, (void *)buf_temp, align_size, align_addr);
+ if (0 == cfg_private_check(buf_temp, align_size)) {
+ cfg_private_erase(align_addr, align_size);
+ }
+ memset(buf_temp + w_pos, 0xff, wlen);
+ norflash_write(NULL, (void *)buf_temp, align_size, align_addr);
+ fptr += wlen;
+ len -= wlen;
+ }
+ free(buf_temp);
+ fclose(file);
+ return 0;
+}
+
+int cfg_private_close(FILE *file)
+{
+ if (cfg_private_create_flag) {
+ int i = 0;
+ int align_size = 4096;
+ if (boot_info.vm.align == 1) {
+ align_size = 256;
+ }
+ char name[SDFILE_NAME_LEN];
+ fget_name(file, name, SDFILE_NAME_LEN);
+ char *buf_temp = (char *)malloc(align_size);
+ norflash_read(NULL, (void *)buf_temp, align_size, cfg_private_create_sclust);
+ for (; i < CFG_PRIVATE_FILE_NUM; i++) {
+ int addr = cfg_private_create_sclust + i * sizeof(SDFILE_FILE_HEAD);
+ norflash_read(NULL, (void *)&head, sizeof(SDFILE_FILE_HEAD), addr);
+ if (CRC16((u8 *)&head + 2, sizeof(SDFILE_FILE_HEAD) - 2) != head.head_crc) {
+ continue;
+ }
+ if (0 == memcmp(head.name, name, SDFILE_NAME_LEN)) {
+ head.len = fpos(file);
+ y_printf(">>>[test]:real file len = %d\n", head.len);
+ head.head_crc = CRC16((u8 *)&head + 2, sizeof(SDFILE_FILE_HEAD) - 2);
+ break;
+ }
+ }
+ cfg_private_create_flag = 0;
+ if (i < CFG_PRIVATE_FILE_NUM) {
+ cfg_private_erase(cfg_private_create_sclust, align_size);
+ memcpy(buf_temp + i * sizeof(SDFILE_FILE_HEAD), &head, sizeof(SDFILE_FILE_HEAD));
+ norflash_write(NULL, (void *)buf_temp, align_size, cfg_private_create_sclust);
+ }
+ if (buf_temp) {
+ free(buf_temp);
+ }
+ }
+ return fclose(file);
+}
+
+int cfg_private_seek(FILE *file, int offset, int fromwhere)
+{
+ return fseek(file, offset, fromwhere);
+}
+
+void cfg_private_test_demo(void)
+{
+#if 0
+#define N 256
+ char test_buf[N] = {0};
+ char r_buf[512] = {0};
+ for (int i = 0; i < N; i++) {
+ test_buf[i] = i & 0xff;
+ }
+
+ char path[64] = "mnt/sdfile/app/FATFSI/eq_cfg_hw.bin";
+ char path2[64] = "mnt/sdfile/app/FATFSI/cfg_tool.bin";
+ y_printf("\n >>>[test]:func = %s,line= %d\n", __FUNCTION__, __LINE__);
+ FILE *fp = cfg_private_open(path, "w+");
+ if (!fp) {
+ r_printf(">>>[test]:open fail!!!!!\n");
+ while (1);
+ }
+ /* cfg_private_delete_file(fp); */
+ /* fp = cfg_private_open(path, "w+"); */
+ /* cfg_private_read(fp, r_buf, 512); */
+ /* put_buf(r_buf, 512); */
+ /* cfg_private_seek(fp, 0, SEEK_SET); */
+
+ cfg_private_write(fp, test_buf, N);
+
+ cfg_private_close(fp);
+ fp = cfg_private_open(path, "r");
+ cfg_private_read(fp, r_buf, 512);
+ put_buf(r_buf, 512);
+ fclose(fp);
+ y_printf("\n >>>[test]:func = %s,line= %d\n", __FUNCTION__, __LINE__);
+
+ fp = cfg_private_open(path2, "w+");
+ if (!fp) {
+ r_printf(">>>[test]:open fail!!!!!\n");
+ while (1);
+ }
+ for (int i = 0; i < N; i++) {
+ test_buf[i] = (N - 1 - i) & 0xff;
+ }
+ cfg_private_write(fp, test_buf, N);
+ cfg_private_close(fp);
+ fp = cfg_private_open(path2, "r");
+ cfg_private_read(fp, r_buf, 512);
+ put_buf(r_buf, 512);
+ fclose(fp);
+
+#if 0
+ FILE *file = cfg_private_open("mnt/sdfile/app/FATFSI", "w+");
+ if (!file) {
+ r_printf(">>>[test]:open fail!!!!!\n");
+ while (1);
+ }
+ struct vfs_attr attrs = {0};
+ fget_attrs(file, &attrs);
+ y_printf(">>>[test]:in part addr = %d, fsize = %d\n", attrs.sclust, attrs.fsize);
+ char *part = zalloc(attrs.fsize);
+ cfg_private_delete_file(file);
+ file = cfg_private_open("mnt/sdfile/app/FATFSI", "w+");
+ cfg_private_read(file, part, attrs.fsize);
+ put_buf(part, attrs.fsize);
+ free(part);
+#endif
+ while (1);
+#endif
+}
diff --git a/apps/common/fat_nor/virfat_flash.c b/apps/common/fat_nor/virfat_flash.c
new file mode 100644
index 0000000..4e1bf8d
--- /dev/null
+++ b/apps/common/fat_nor/virfat_flash.c
@@ -0,0 +1,932 @@
+#include "system/includes.h"
+#include "app_config.h"
+#include "fs/virfat_flash.h"
+#include "res/resfile.h"
+
+#include "asm/sfc_norflash_api.h"
+#include "boot.h"
+#include "sdfile.h"
+
+
+#define OUTFLASH_FAT16_ENABLE 0 // 如果需要使用16M以上的flash需要修改download.bat文件与之对应
+
+typedef struct _flash_private_info {
+ char part_name[16];
+ u32 flash_private_addr;
+ u32 private_len;
+} FLASH_PRIVATE_INFO;
+
+static virfat_flash_t virfat_flash;
+static u8 curr_file = 0xff;
+volatile char vir_file_type = 0;
+u32 change_flag = 0;
+static void *fd;
+
+static OS_MUTEX virfat_flash_mutex;
+#define virfat_mutex_init() os_mutex_create(&virfat_flash_mutex)
+#define virfat_mutex_pend() os_mutex_pend(&virfat_flash_mutex, portMAX_DELAY)
+#define virfat_mutex_post() os_mutex_post(&virfat_flash_mutex)
+
+#define FATFS_IN_FLASH_NAME "FATFSI"
+
+static u32 virfat_flash_addr2cpu_addr(u32 offset)
+{
+ return offset - boot_info.sfc.sfc_base_addr + boot_info.sfc.app_addr;
+}
+
+static u32 virfat_cpu_addr2flash_addr(u32 offset)
+{
+ return offset - boot_info.sfc.app_addr + boot_info.sfc.sfc_base_addr;
+}
+
+static void virfat_get_cpu_fatfs_addr(char *name, u32 *addr, u32 *len)
+{
+ u32 start_addr = boot_info.sfc.app_addr;
+ /* y_printf(">>>[test]:base_addr = %d, app_addr = %d\n", boot_info.sfc.sfc_base_addr, boot_info.sfc.app_addr); */
+ u32 offset = 0;
+ struct sdfile_file_head head = {0};
+ /* u16 local_flash_key = get_chip_id_in_phonefs(); */
+ while (1) {
+ /* extern int norflash_origin_read(u8 * buf, u32 offset, u32 len); */
+ /* norflash_origin_read((u8 *)&head, start_addr, sizeof(head)); */
+ memcpy(&head, (u8 *)start_addr, sizeof(head));
+ /* put_buf(&head, 32); */
+ /* decode_data_by_user_key_in_sdfile(local_flash_key, (u8 *)&head, sizeof(head), offset, sizeof(head)); */
+ if (head.head_crc != CRC16((u8 *)&head.data_crc, sizeof(head) - sizeof(head.head_crc))) {
+ y_printf("\n >>>[test]:func = %s,line= %d\n", __FUNCTION__, __LINE__);
+ return;
+ }
+ /* r_printf(">>>[test]:head.name = %s, name = %s\n", head.name, name); */
+ if (0 == memcmp(head.name, name, strlen(name))) {
+ break;
+ }
+ offset += sizeof(head);
+ start_addr += sizeof(head);
+ }
+ *addr = head.addr;
+ *len = head.len;
+ r_printf(">>>[test]:######### start_addr = 0x%x, len = 0x%x\n", head.addr, head.len);
+}
+
+#if TCFG_VIRFAT_FLASH_ENABLE
+void fat_copy(void *pDest, void *pSrc, u32 copyLen)
+{
+ while (copyLen--) {
+ ((u8 *)pDest)[copyLen] = ((u8 *)pSrc)[copyLen];
+ }
+}
+
+static u16 ld_word(u8 *p)
+{
+ return (u16)p[1] << 8 | p[0];
+}
+
+static u32 ld_dword(u8 *p)
+{
+ return (u32)p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
+}
+
+//fat 备份4Kfat_table和4K目录项,保留扇区扩大8K ,8M
+#if 1
+/* static const unsigned char bpb_data[512] = { */
+static char bpb_data[512] = {
+ 0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x08, 0x18, 0x00,
+ 0x01, 0x80, 0x00, 0x00, 0x40, 0xF8, 0x08, 0x00, 0x3F, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0xEE, 0x8D, 0xF2, 0x2C, 0x4E, 0x4F, 0x20, 0x4E, 0x41,
+ 0x4D, 0x45, 0x20, 0x20, 0x20, 0x20, 0x46, 0x41, 0x54, 0x31, 0x36, 0x20, 0x20, 0x20, 0x33, 0xC9,
+ 0x8E, 0xD1, 0xBC, 0xF0, 0x7B, 0x8E, 0xD9, 0xB8, 0x00, 0x20, 0x8E, 0xC0, 0xFC, 0xBD, 0x00, 0x7C,
+ 0x38, 0x4E, 0x24, 0x7D, 0x24, 0x8B, 0xC1, 0x99, 0xE8, 0x3C, 0x01, 0x72, 0x1C, 0x83, 0xEB, 0x3A,
+ 0x66, 0xA1, 0x1C, 0x7C, 0x26, 0x66, 0x3B, 0x07, 0x26, 0x8A, 0x57, 0xFC, 0x75, 0x06, 0x80, 0xCA,
+ 0x02, 0x88, 0x56, 0x02, 0x80, 0xC3, 0x10, 0x73, 0xEB, 0x33, 0xC9, 0x8A, 0x46, 0x10, 0x98, 0xF7,
+ 0x66, 0x16, 0x03, 0x46, 0x1C, 0x13, 0x56, 0x1E, 0x03, 0x46, 0x0E, 0x13, 0xD1, 0x8B, 0x76, 0x11,
+ 0x60, 0x89, 0x46, 0xFC, 0x89, 0x56, 0xFE, 0xB8, 0x20, 0x00, 0xF7, 0xE6, 0x8B, 0x5E, 0x0B, 0x03,
+ 0xC3, 0x48, 0xF7, 0xF3, 0x01, 0x46, 0xFC, 0x11, 0x4E, 0xFE, 0x61, 0xBF, 0x00, 0x00, 0xE8, 0xE6,
+ 0x00, 0x72, 0x39, 0x26, 0x38, 0x2D, 0x74, 0x17, 0x60, 0xB1, 0x0B, 0xBE, 0xA1, 0x7D, 0xF3, 0xA6,
+ 0x61, 0x74, 0x32, 0x4E, 0x74, 0x09, 0x83, 0xC7, 0x20, 0x3B, 0xFB, 0x72, 0xE6, 0xEB, 0xDC, 0xA0,
+ 0xFB, 0x7D, 0xB4, 0x7D, 0x8B, 0xF0, 0xAC, 0x98, 0x40, 0x74, 0x0C, 0x48, 0x74, 0x13, 0xB4, 0x0E,
+ 0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB, 0xEF, 0xA0, 0xFD, 0x7D, 0xEB, 0xE6, 0xA0, 0xFC, 0x7D, 0xEB,
+ 0xE1, 0xCD, 0x16, 0xCD, 0x19, 0x26, 0x8B, 0x55, 0x1A, 0x52, 0xB0, 0x01, 0xBB, 0x00, 0x00, 0xE8,
+ 0x3B, 0x00, 0x72, 0xE8, 0x5B, 0x8A, 0x56, 0x24, 0xBE, 0x0B, 0x7C, 0x8B, 0xFC, 0xC7, 0x46, 0xF0,
+ 0x3D, 0x7D, 0xC7, 0x46, 0xF4, 0x29, 0x7D, 0x8C, 0xD9, 0x89, 0x4E, 0xF2, 0x89, 0x4E, 0xF6, 0xC6,
+ 0x06, 0x96, 0x7D, 0xCB, 0xEA, 0x03, 0x00, 0x00, 0x20, 0x0F, 0xB6, 0xC8, 0x66, 0x8B, 0x46, 0xF8,
+ 0x66, 0x03, 0x46, 0x1C, 0x66, 0x8B, 0xD0, 0x66, 0xC1, 0xEA, 0x10, 0xEB, 0x5E, 0x0F, 0xB6, 0xC8,
+ 0x4A, 0x4A, 0x8A, 0x46, 0x0D, 0x32, 0xE4, 0xF7, 0xE2, 0x03, 0x46, 0xFC, 0x13, 0x56, 0xFE, 0xEB,
+ 0x4A, 0x52, 0x50, 0x06, 0x53, 0x6A, 0x01, 0x6A, 0x10, 0x91, 0x8B, 0x46, 0x18, 0x96, 0x92, 0x33,
+ 0xD2, 0xF7, 0xF6, 0x91, 0xF7, 0xF6, 0x42, 0x87, 0xCA, 0xF7, 0x76, 0x1A, 0x8A, 0xF2, 0x8A, 0xE8,
+ 0xC0, 0xCC, 0x02, 0x0A, 0xCC, 0xB8, 0x01, 0x02, 0x80, 0x7E, 0x02, 0x0E, 0x75, 0x04, 0xB4, 0x42,
+ 0x8B, 0xF4, 0x8A, 0x56, 0x24, 0xCD, 0x13, 0x61, 0x61, 0x72, 0x0B, 0x40, 0x75, 0x01, 0x42, 0x03,
+ 0x5E, 0x0B, 0x49, 0x75, 0x06, 0xF8, 0xC3, 0x41, 0xBB, 0x00, 0x00, 0x60, 0x66, 0x6A, 0x00, 0xEB,
+ 0xB0, 0x42, 0x4F, 0x4F, 0x54, 0x4D, 0x47, 0x52, 0x20, 0x20, 0x20, 0x20, 0x0D, 0x0A, 0x52, 0x65,
+ 0x6D, 0x6F, 0x76, 0x65, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x73, 0x20, 0x6F, 0x72, 0x20, 0x6F, 0x74,
+ 0x68, 0x65, 0x72, 0x20, 0x6D, 0x65, 0x64, 0x69, 0x61, 0x2E, 0xFF, 0x0D, 0x0A, 0x44, 0x69, 0x73,
+ 0x6B, 0x20, 0x65, 0x72, 0x72, 0x6F, 0x72, 0xFF, 0x0D, 0x0A, 0x50, 0x72, 0x65, 0x73, 0x73, 0x20,
+ 0x61, 0x6E, 0x79, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x72, 0x65, 0x73, 0x74, 0x61,
+ 0x72, 0x74, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, 0xCB, 0xD8, 0x55, 0xAA
+};
+#else
+//fat 备份12Kfat_table和4K目录项,保留扇区扩大16K ,32M
+/* static const unsigned char bpb_data[512] = { */
+static char bpb_data[512] = {
+ 0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x08, 0x30, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x00, 0xF8, 0x18, 0x00, 0x3F, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x80, 0x00, 0x29, 0xEE, 0x8D, 0xF2, 0x2C, 0x4E, 0x4F, 0x20, 0x4E, 0x41,
+ 0x4D, 0x45, 0x20, 0x20, 0x20, 0x20, 0x46, 0x41, 0x54, 0x31, 0x36, 0x20, 0x20, 0x20, 0x33, 0xC9,
+ 0x8E, 0xD1, 0xBC, 0xF0, 0x7B, 0x8E, 0xD9, 0xB8, 0x00, 0x20, 0x8E, 0xC0, 0xFC, 0xBD, 0x00, 0x7C,
+ 0x38, 0x4E, 0x24, 0x7D, 0x24, 0x8B, 0xC1, 0x99, 0xE8, 0x3C, 0x01, 0x72, 0x1C, 0x83, 0xEB, 0x3A,
+ 0x66, 0xA1, 0x1C, 0x7C, 0x26, 0x66, 0x3B, 0x07, 0x26, 0x8A, 0x57, 0xFC, 0x75, 0x06, 0x80, 0xCA,
+ 0x02, 0x88, 0x56, 0x02, 0x80, 0xC3, 0x10, 0x73, 0xEB, 0x33, 0xC9, 0x8A, 0x46, 0x10, 0x98, 0xF7,
+ 0x66, 0x16, 0x03, 0x46, 0x1C, 0x13, 0x56, 0x1E, 0x03, 0x46, 0x0E, 0x13, 0xD1, 0x8B, 0x76, 0x11,
+ 0x60, 0x89, 0x46, 0xFC, 0x89, 0x56, 0xFE, 0xB8, 0x20, 0x00, 0xF7, 0xE6, 0x8B, 0x5E, 0x0B, 0x03,
+ 0xC3, 0x48, 0xF7, 0xF3, 0x01, 0x46, 0xFC, 0x11, 0x4E, 0xFE, 0x61, 0xBF, 0x00, 0x00, 0xE8, 0xE6,
+ 0x00, 0x72, 0x39, 0x26, 0x38, 0x2D, 0x74, 0x17, 0x60, 0xB1, 0x0B, 0xBE, 0xA1, 0x7D, 0xF3, 0xA6,
+ 0x61, 0x74, 0x32, 0x4E, 0x74, 0x09, 0x83, 0xC7, 0x20, 0x3B, 0xFB, 0x72, 0xE6, 0xEB, 0xDC, 0xA0,
+ 0xFB, 0x7D, 0xB4, 0x7D, 0x8B, 0xF0, 0xAC, 0x98, 0x40, 0x74, 0x0C, 0x48, 0x74, 0x13, 0xB4, 0x0E,
+ 0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB, 0xEF, 0xA0, 0xFD, 0x7D, 0xEB, 0xE6, 0xA0, 0xFC, 0x7D, 0xEB,
+ 0xE1, 0xCD, 0x16, 0xCD, 0x19, 0x26, 0x8B, 0x55, 0x1A, 0x52, 0xB0, 0x01, 0xBB, 0x00, 0x00, 0xE8,
+ 0x3B, 0x00, 0x72, 0xE8, 0x5B, 0x8A, 0x56, 0x24, 0xBE, 0x0B, 0x7C, 0x8B, 0xFC, 0xC7, 0x46, 0xF0,
+ 0x3D, 0x7D, 0xC7, 0x46, 0xF4, 0x29, 0x7D, 0x8C, 0xD9, 0x89, 0x4E, 0xF2, 0x89, 0x4E, 0xF6, 0xC6,
+ 0x06, 0x96, 0x7D, 0xCB, 0xEA, 0x03, 0x00, 0x00, 0x20, 0x0F, 0xB6, 0xC8, 0x66, 0x8B, 0x46, 0xF8,
+ 0x66, 0x03, 0x46, 0x1C, 0x66, 0x8B, 0xD0, 0x66, 0xC1, 0xEA, 0x10, 0xEB, 0x5E, 0x0F, 0xB6, 0xC8,
+ 0x4A, 0x4A, 0x8A, 0x46, 0x0D, 0x32, 0xE4, 0xF7, 0xE2, 0x03, 0x46, 0xFC, 0x13, 0x56, 0xFE, 0xEB,
+ 0x4A, 0x52, 0x50, 0x06, 0x53, 0x6A, 0x01, 0x6A, 0x10, 0x91, 0x8B, 0x46, 0x18, 0x96, 0x92, 0x33,
+ 0xD2, 0xF7, 0xF6, 0x91, 0xF7, 0xF6, 0x42, 0x87, 0xCA, 0xF7, 0x76, 0x1A, 0x8A, 0xF2, 0x8A, 0xE8,
+ 0xC0, 0xCC, 0x02, 0x0A, 0xCC, 0xB8, 0x01, 0x02, 0x80, 0x7E, 0x02, 0x0E, 0x75, 0x04, 0xB4, 0x42,
+ 0x8B, 0xF4, 0x8A, 0x56, 0x24, 0xCD, 0x13, 0x61, 0x61, 0x72, 0x0B, 0x40, 0x75, 0x01, 0x42, 0x03,
+ 0x5E, 0x0B, 0x49, 0x75, 0x06, 0xF8, 0xC3, 0x41, 0xBB, 0x00, 0x00, 0x60, 0x66, 0x6A, 0x00, 0xEB,
+ 0xB0, 0x42, 0x4F, 0x4F, 0x54, 0x4D, 0x47, 0x52, 0x20, 0x20, 0x20, 0x20, 0x0D, 0x0A, 0x52, 0x65,
+ 0x6D, 0x6F, 0x76, 0x65, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x73, 0x20, 0x6F, 0x72, 0x20, 0x6F, 0x74,
+ 0x68, 0x65, 0x72, 0x20, 0x6D, 0x65, 0x64, 0x69, 0x61, 0x2E, 0xFF, 0x0D, 0x0A, 0x44, 0x69, 0x73,
+ 0x6B, 0x20, 0x65, 0x72, 0x72, 0x6F, 0x72, 0xFF, 0x0D, 0x0A, 0x50, 0x72, 0x65, 0x73, 0x73, 0x20,
+ 0x61, 0x6E, 0x79, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x72, 0x65, 0x73, 0x74, 0x61,
+ 0x72, 0x74, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, 0xCB, 0xD8, 0x55, 0xAA
+};
+#endif
+
+static u32 get_first_one(u32 n)
+{
+ u32 pos = 0;
+ for (pos = 0; pos < 32; pos++) {
+ if (n & BIT(pos)) {
+ return pos;
+ }
+ }
+ return 0xff;
+
+}
+
+static bool virfat_flash_mount(virfat_flash_t *disk_handler, u8 *buf)
+{
+ u32 fatsize;
+ u32 maxclust;
+ u32 sects_fat;
+ u32 n_rootdir;
+
+ /*计算FAT表大小*/
+ fatsize = ld_word(&buf[BPB_FATSz16]); /* Number of sectors per FAT */
+ if (!fatsize) {
+ fatsize = ld_dword(&buf[BPB_FATSz32]);
+ }
+
+ disk_handler->fatsize = fatsize * 512; //fat表大小 byte.
+ disk_handler->fatbase = ld_word(&buf[BPB_RsvdSecCnt]); /* FAT start sector (lba) */
+ /* disk_handler->fatbase2 = disk_handler->fatbase + fatsize; */
+
+ fatsize *= buf[BPB_NumFATs];
+
+ disk_handler->csize = get_first_one(buf[BPB_SecPerClus]); /* Number of sectors per cluster */
+
+ n_rootdir = ld_word(&buf[BPB_RootEntCnt]); /* Nmuber of root directory entries */
+
+ disk_handler->database = (disk_handler->fatbase + fatsize + n_rootdir / 16); /* Data start sector (lba) */
+
+
+ /*计算总容量*/
+ disk_handler->capacity = ld_word(&buf[BPB_TotSec16]); /* Number of sectors on the file system */
+ if (!disk_handler->capacity) {
+ disk_handler->capacity = ld_dword(&buf[BPB_TotSec32]);
+ }
+ /* r_printf(">>>[test]:cap = 0x%x, csize = %d\n",disk_handler->capacity, disk_handler->csize); */
+ maxclust = (disk_handler->capacity - ld_word(&buf[BPB_RsvdSecCnt]) - fatsize -
+ n_rootdir / 16) >> disk_handler->csize;
+ disk_handler->max_clust = maxclust + 2;
+ /* r_printf(">>>[test]:maxclust = %d\n", maxclust); */
+
+ disk_handler->fs_type = (maxclust >= MIN_FAT32) ? FS_FAT32 : ((maxclust >= MIN_FAT16) ? FS_FAT16 : FS_FAT12);
+ /* r_printf(">>>[test]:fs_type = 0x%x\n", disk_handler->fs_type); */
+
+ /* Root directory start cluster */
+ if (disk_handler->fs_type == FS_FAT32) {
+ disk_handler->dirbase = disk_handler->database;
+ disk_handler->database += 1 << disk_handler->csize;
+ } else {
+ disk_handler->dirbase = disk_handler->fatbase + fatsize;
+ }
+
+ disk_handler->clustSize = disk_handler->csize + 9;
+
+ return TRUE;
+}
+
+static void vir_read_reserved_area(u8 *buf, u32 len)
+{
+ memset(buf, 0, len);
+}
+
+
+static void vir_read_BPB(u8 *buf, u32 offset, u32 len)
+{
+ /* u8 bpb_jl_head[] = "JLBT_DISK"; */
+
+ /* memset(buf, 0, 512); */
+ memcpy(buf, bpb_data + offset, len);
+
+ /* memcpy(buf + sizeof(bpb_data), bpb_jl_head, sizeof(bpb_jl_head)); */
+
+ /* buf[510] = 0x55; */
+ /* buf[511] = 0xAA; */
+}
+
+static int virfat_read(void *fd, void *buf, u32 addr, u32 len)
+{
+ int rlen = -1;
+#if TCFG_VIRFAT_INSERT_FLASH_ENABLE
+ u32 cpu_addr = virfat_flash_addr2cpu_addr(virfat_flash.flash_fatfs_addr + addr);
+ /* r_printf(">>>[test]:cpu_addr = %d, addr = %d\n", cpu_addr, addr); */
+ memcpy((u8 *)buf, (u8 *)cpu_addr, len);
+ rlen = len;
+#else
+ rlen = dev_bulk_read(fd, buf, addr, len);
+#endif
+ return rlen;
+}
+
+static int virfat_write(void *fd, void *buf, u32 addr, u32 len)
+{
+ int wlen = -1;
+#if TCFG_VIRFAT_INSERT_FLASH_ENABLE
+ addr += virfat_flash.flash_fatfs_addr;
+ wlen = norflash_write(NULL, buf, len, addr);
+#else
+ wlen = dev_bulk_write(fd, buf, addr, len);
+#endif
+ return wlen;
+}
+
+static int virfat_ioctl(void *fd, u32 cmd, u32 arg)
+{
+ int res = -1;
+#if TCFG_VIRFAT_INSERT_FLASH_ENABLE
+ if ((cmd == IOCTL_ERASE_SECTOR) || (cmd == IOCTL_ERASE_PAGE) || (cmd == IOCTL_ERASE_BLOCK)) {
+ arg += virfat_flash.flash_fatfs_addr;
+ }
+ res = norflash_ioctl(NULL, cmd, arg);
+#else
+ res = dev_ioctl(fd, cmd, arg);
+#endif
+ return res;
+}
+
+AT_VOLATILE_RAM_CODE
+static u32 virfat_flash_read(void *buf, u32 addr_sec, u32 len)
+{
+ /* y_printf("11111111111[r:%d],,", addr_sec); */
+ u32 real_addrsec = 0;
+ u32 rlen;
+ if (addr_sec == 0) {
+ vir_read_BPB(buf, 0, 512);
+ y_printf("fatbase:%d \n", virfat_flash.fatbase);
+ y_printf("dirbase:%d \n", virfat_flash.dirbase);
+ y_printf("database:%d \n", virfat_flash.database);
+ return len;
+ } else if (addr_sec < 4096 / 512) {
+ vir_read_reserved_area(buf, len);
+ return len;
+ } else {
+ real_addrsec = addr_sec - 4096 / 512;
+ }
+ /* r_printf(">>>[test]111111:real-add= %d\n",real_addrsec); */
+
+#if TCFG_VIRFAT_INSERT_FLASH_ENABLE
+ rlen = virfat_read(fd, buf, real_addrsec * 512, len);
+#else
+ rlen = _norflash_read_watch(buf, real_addrsec * 512, len, 1);
+ if (rlen == 0) {
+ return len;
+ }
+#endif
+ return rlen;
+}
+
+
+static u32 virfat_flash_write(void *buf, u32 addr_sec, u32 len)
+{
+ /* r_printf("[w:%d],,", addr_sec); */
+ u8 *buf_temp = (u8 *)malloc(4096);
+ u32 wlen = 0;
+ u32 real_addrsec = 0;
+ if (addr_sec == 0) {
+ return len;
+ } else if (addr_sec < 4096 / 512) {
+ return len;
+ } else if (addr_sec < virfat_flash.fatbase) { //备份区不写
+ real_addrsec = addr_sec - 4096 / 512 + 0; // 0为flash里面保留区域(备份fat表和目录项)实际位置。
+ return len;
+ } else if (addr_sec < virfat_flash.dirbase) {
+ real_addrsec = addr_sec - 4096 / 512;
+ /* real_addrsec = addr_sec - virfat_flash.fatbase + 8 * 1024 * UNIT / 512; // 8KxUNIT为flash里面fat表实际位置。 */
+ int real_fatbase = virfat_flash.fatbase * 512 - 4096;
+ if (virfat_flash.fatsize > 4096) {
+ int a = (addr_sec - virfat_flash.fatbase) * 512 / 4096;
+ real_fatbase += a * 4096;
+ addr_sec -= a * 4096 / 512;
+ }
+ virfat_read(fd, buf_temp, real_fatbase, 4096);
+ virfat_ioctl(fd, IOCTL_ERASE_SECTOR, real_fatbase);
+ memcpy(buf_temp + (addr_sec - virfat_flash.fatbase) * 512, buf, len);
+ wlen = virfat_write(fd, buf_temp, real_fatbase, 4096);
+ if (wlen == 4096) {
+ wlen = len;
+ }
+ } else if (addr_sec < virfat_flash.database) {
+ real_addrsec = addr_sec - 4096 / 512;
+ int real_dirbase = virfat_flash.dirbase * 512 - 4096;
+ /* real_addrsec = addr_sec - virfat_flash.dirbase + 12 * 1024 * UNIT / 512; // 12KxUNIT为flash里面目录项实际位置。 */
+ virfat_read(fd, buf_temp, real_dirbase, 4096);
+ virfat_ioctl(fd, IOCTL_ERASE_SECTOR, real_dirbase);
+ memcpy(buf_temp + (addr_sec - virfat_flash.dirbase) * 512, buf, len);
+ wlen = virfat_write(fd, buf_temp, real_dirbase, 4096);
+ if (wlen == 4096) {
+ wlen = len;
+ }
+ } else {
+ real_addrsec = addr_sec - 4096 / 512;
+ /* real_addrsec = addr_sec - virfat_flash.database + 16 * 1024 * UNIT / 512; // 16KxUNIT为flash里面数据区实际位置。 */
+ int align_addr = real_addrsec * 512 / 4096 * 4096;
+ int offset = real_addrsec * 512 % 4096;
+ virfat_read(fd, buf_temp, align_addr, 4096);
+ virfat_ioctl(fd, IOCTL_ERASE_SECTOR, align_addr);
+ memcpy(buf_temp + offset, buf, len);
+ wlen = virfat_write(fd, buf_temp, align_addr, 4096);
+ if (wlen == 4096) {
+ wlen = len;
+ }
+
+ /* wlen = virfat_write(fd, buf, real_addrsec * 512, len); */
+ }
+ free(buf_temp);
+ buf_temp = NULL;
+ if (wlen != len) {
+ r_printf(">>>[test]:wlen = %d, len = %d\n", wlen, len);
+ log_e("write error!!!!!!!!!!!!!");
+ }
+ return wlen;
+}
+
+AT_VOLATILE_RAM_CODE
+u32 virfat_flash_read_watch(void *buf, u32 addr_sec, u32 len)
+{
+ /* y_printf("[r:%d],,", addr_sec); */
+ u32 real_addrsec = 0;
+ u32 rlen;
+ /* if (addr_sec == 0) { */
+ if (addr_sec < 512) {
+ vir_read_BPB(buf, addr_sec, len);
+ y_printf("fatbase:%d \n", virfat_flash.fatbase);
+ y_printf("dirbase:%d \n", virfat_flash.dirbase);
+ y_printf("database:%d \n", virfat_flash.database);
+ return len;
+ } else if (addr_sec < 4096) {
+ vir_read_reserved_area(buf, len);
+ return len;
+ } else {
+ real_addrsec = addr_sec - 4096 ;
+ }
+ /* r_printf(">>>[test]:real-add= %d\n",real_addrsec); */
+
+#if TCFG_VIRFAT_INSERT_FLASH_ENABLE
+ rlen = virfat_read(fd, buf, real_addrsec, len);
+#else
+ rlen = _norflash_read_watch(buf, real_addrsec, len, 1);
+ if (rlen == 0) {
+ return len;
+ }
+#endif
+ return rlen;
+}
+
+u32 virfat_flash_write_watch(void *buf, u32 addr_sec, u32 len)
+{
+ u32 wlen;
+ u32 real_addrsec = 0;
+ if (addr_sec == 0) {
+ return len;
+ } else if (addr_sec < 4096) {
+ return len;
+ } else {
+ real_addrsec = addr_sec - 4096;
+ }
+ wlen = virfat_write(fd, buf, real_addrsec, len);
+ if (wlen != len) {
+ r_printf(">>>[test]:wlen = %d, len = %d\n", wlen, len);
+ log_e("write error!!!!!!!!!!!!!");
+ }
+ return wlen;
+}
+
+u32 virfat_flash_erase_watch(int cmd, u32 arg)
+{
+ if (arg == 0) {
+ return 0;
+ } else if (arg < 4096) {
+ return 0;
+ } else {
+ arg = arg - 4096;
+ }
+ return virfat_ioctl(fd, cmd, arg);
+}
+u32 virfat_flash_erase(int cmd, u32 arg)
+{
+ return virfat_ioctl(fd, cmd, arg);
+}
+
+u32 virfat_flash_capacity() //fat上容量
+{
+ return virfat_flash.capacity * 512;
+}
+
+u32 virfat_flash_get_real_capacity() //获取实际flash容量
+{
+ static u32 jlfat_capacity = 0;
+ if (jlfat_capacity == 0) {
+ virfat_ioctl(fd, IOCTL_GET_CAPACITY, (u32)&jlfat_capacity);
+#if (OUTFLASH_FAT16_ENABLE == 0)
+ int min_fat16_size = 10 * 1024 * 1024;
+ if (jlfat_capacity > min_fat16_size) {
+ return min_fat16_size;
+ }
+#endif
+ }
+#if TCFG_VIRFAT_INSERT_FLASH_ENABLE
+ jlfat_capacity = virfat_flash.fatfs_len;
+#endif
+ return jlfat_capacity;
+}
+
+#define BACKUPS_SPACE 8192
+void virfat_flash_backups_fat_dir_data()
+{
+ u8 *buf = malloc(4096);
+ ASSERT(buf);
+ for (int offset = 0; offset < BACKUPS_SPACE; offset += 4096) {
+ virfat_flash_read_watch(buf, 4096 + BACKUPS_SPACE + offset, 4096);
+ virfat_flash_erase_watch(IOCTL_ERASE_SECTOR, 4096 + offset);
+ virfat_flash_write_watch(buf, 4096 + offset, 4096);
+ }
+ if (buf) {
+ free(buf);
+ }
+}
+
+void virfat_flash_resume_fat_dir_data()
+{
+ u8 *buf = malloc(4096);
+ ASSERT(buf);
+ for (int offset = 0; offset < BACKUPS_SPACE; offset += 4096) {
+ virfat_flash_read_watch(buf, 4096 + offset, 4096);
+ virfat_flash_erase_watch(IOCTL_ERASE_SECTOR, 4096 + BACKUPS_SPACE + offset);
+ virfat_flash_write_watch(buf, 4096 + BACKUPS_SPACE + offset, 4096);
+ }
+ if (buf) {
+ free(buf);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/** @brief:
+@param:
+@return:
+@author:phewlee.
+@note: 外置flash jlaft文件系统,获取文件名。
+@date: 2021-05-19
+*/
+/*----------------------------------------------------------------------------*/
+#define BUF_LEN 512
+void virfat_flash_get_dirinfo(void *file_buf, u32 *file_num)
+{
+ u32 cnt = 0;
+ u8 *buf = malloc(BUF_LEN);
+ u8 name_buf[12] = {0};
+ u32 dir_len = (virfat_flash.database - virfat_flash.dirbase) * 512;
+ for (int k = 0; k < dir_len; k += BUF_LEN) {
+ virfat_flash_read_watch(buf, virfat_flash.dirbase * 512 + k, BUF_LEN);
+ for (int i = 0; i < BUF_LEN; i += 32) {
+ memset(name_buf, 0, 12);
+ memcpy(name_buf, buf + i, 12);
+ /* put_buf(buf, 32); */
+ if (name_buf[0] == 0xE5) {
+ continue;
+ }
+ if ((name_buf[0] != 0) && (name_buf[1] != 0)) {
+ if (file_buf) {
+ memcpy(file_buf + cnt * 12, name_buf, 12);
+ }
+ cnt++;
+ /* r_printf(">>>[test]:name = %s\n", name_buf); */
+ } else {
+ /* y_printf("\n >>>[test]:func = %s,line= %d\n",__FUNCTION__, __LINE__); */
+ break;
+ }
+ }
+ }
+ *file_num = cnt;
+ free(buf);
+
+}
+
+
+/*----------------------------------------------------------------------------*/
+/** @brief:
+@param:
+@return:
+@author:phewlee.
+@note: 外置flash jlaft文件系统,获取文件信息。
+@date: 2021-05-19
+*/
+/*----------------------------------------------------------------------------*/
+#if JLFAT_DIRINFO_ENABLE
+void virfat_flash_get_alldirinfo(JLFAT_DIRINFO *dir_info, u32 *file_num)
+{
+ u32 cnt = 0;
+ u8 *buf = malloc(BUF_LEN);
+ u8 dir[32] = {0};
+ u32 dir_len = (virfat_flash.database - virfat_flash.dirbase) * 512;
+ for (int k = 0; k < dir_len; k += BUF_LEN) {
+ virfat_flash_read_watch(buf, virfat_flash.dirbase * 512 + k, BUF_LEN);
+ for (int i = 0; i < BUF_LEN; i += 32) {
+ memset(dir, 0, 32);
+ memcpy(dir, buf + i, 32);
+ if (dir[0] == 0xE5) {
+ continue;
+ }
+ if ((dir[0] != 0) && (dir[1] != 0)) {
+ if (dir_info) {
+ memcpy(dir_info[cnt].name, dir, 11);
+ dir_info[cnt].name[11] = 0;
+ dir_info[cnt].attr = buf[DIR_Attr] & (~AM_FCH);
+ dir_info[cnt].fsize = ld_dword((u8 *)(&dir[DIR_FileSize]));
+ dir_info[cnt].sclust = ((u32)ld_word(&dir[DIR_FstClusHI]) << 16) | ld_word(&dir[DIR_FstClusLO]);
+ dir_info[cnt].fix_date = ld_word((u8 *)(&dir[DIR_WrtDate]));
+ dir_info[cnt].fix_time = ld_word((u8 *)(&dir[DIR_WrtTime]));
+ }
+ cnt++;
+ /* r_printf(">>>[test]:name = %s\n", dir_info[cnt].name); */
+ } else {
+ /* y_printf("\n >>>[test]:func = %s,line= %d\n",__FUNCTION__, __LINE__); */
+ break;
+ }
+ }
+ }
+ *file_num = cnt;
+ free(buf);
+}
+#endif
+
+static u32 virfat_flash_available()
+{
+ return 1;
+}
+
+
+u8 virfat_flash_init(void)
+{
+#if TCFG_VIRFAT_INSERT_FLASH_ENABLE
+ ASSERT(boot_info.vm.align >= 8, "virfat_flash erase sector < 4K is not support!!!!!!!!!");
+ virfat_get_cpu_fatfs_addr(FATFS_IN_FLASH_NAME, &virfat_flash.flash_fatfs_addr, &virfat_flash.fatfs_len);
+#endif
+ u32 a = 0;
+ virfat_flash_mount(&virfat_flash, bpb_data);
+ int real_capacity = virfat_flash_get_real_capacity();
+ int min_fat32_size = ((MIN_FAT32 - 2) << (virfat_flash.csize + 9));
+ ASSERT(real_capacity < min_fat32_size, "capacity > min_fat32_size, not surport fat32 flash");
+ /* #if (OUTFLASH_FAT16_ENABLE == 0) */
+ /* #<{(| int min_fat16_size = ((MIN_FAT16 - 2) << (virfat_flash.csize + 9)); |)}># */
+ /* #<{(| r_printf(">>>[test]:min fat16 = %d\n", min_fat16_size); |)}># */
+ /* int min_fat16_size = 10 * 1024 * 1024; */
+ /* if (real_capacity > min_fat16_size) { */
+ /* real_capacity = min_fat16_size; */
+ /* } */
+ /* #endif */
+ r_printf(">>>[test]:real_capacity = 0x%x\n", real_capacity);
+ real_capacity = real_capacity / 512;
+ if (virfat_flash.capacity != real_capacity) {
+ if (real_capacity >= 32 * 1024 * 1024 / 512) {
+ fat_copy(&bpb_data[BPB_TotSec16], &a, 2);
+ fat_copy(&bpb_data[BPB_TotSec32], &real_capacity, 4);
+ } else {
+ fat_copy(&bpb_data[BPB_TotSec16], &real_capacity, 2);
+ }
+ if (real_capacity >= 16 * 1024 * 1024 / 512) {
+ int fatsize = (real_capacity * 512 / 4096 * 2 + 4097) / 4096 * 4096; //计算fat表大小,按fat16来,注意fat表前面占有F8FFFFFF.
+ int fat_sector = fatsize / 512;
+ int rsvdsec = fat_sector + 4096 / 512 + 4096 / 512; //目录项128 * 32 = 4096 不变,工具配置规则目录项没有扩大
+ r_printf(">>>[test]:fat_sector = 0x%x, rsvdsec = 0x%x\n", fat_sector, rsvdsec);
+ fat_copy(&bpb_data[BPB_FATSz16], &fat_sector, 2);
+ fat_copy(&bpb_data[BPB_RsvdSecCnt], &rsvdsec, 2);
+ }
+ put_buf(bpb_data, 96);
+ virfat_flash_mount(&virfat_flash, bpb_data);
+ }
+
+
+ /* y_printf("fatbase:%d \n", virfat_flash.fatbase); */
+ /* y_printf("dirbase:%d \n", virfat_flash.dirbase); */
+ /* y_printf("database:%d \n", virfat_flash.database); */
+ /* y_printf("clustSize:%d \n", virfat_flash.clustSize); */
+
+ return 0;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////device api//////////////////////////////////////////////////////////
+
+static struct device virfat_flash_dev;
+static int flash_virfat_init(const struct dev_node *node, void *arg)
+{
+ /* r_printf(">>>[test]:init name = %s\n", virfat_flash.re_devname); */
+ if (arg) {
+ memcpy(&virfat_flash.re_devname, arg, strlen(arg));
+ }
+ return 0;
+}
+
+static int flash_virfat_open(const char *name, struct device **device, void *arg)
+{
+ /* y_printf(">>>[test]:dev_name = %s\n", virfat_flash.re_devname); */
+ r_printf(">>>[test]:virfat_flash open!!!!!!\n");
+ *device = &virfat_flash_dev;
+#if TCFG_VIRFAT_INSERT_FLASH_ENABLE
+ virfat_flash_init();
+ return 0;
+#endif
+ fd = dev_open((const char *)&virfat_flash.re_devname, arg);
+ virfat_flash_init();
+ return 0;
+}
+#if 0
+AT_VOLATILE_RAM_CODE
+int flash_virfat_read(struct device *device, void *buf, u32 len, u32 addr)
+{
+ /* y_printf(">>>[test]:r;addr = %d ,len = %d\n", addr, len); */
+ virfat_flash_read_watch(buf, addr, len);
+ return len;
+}
+#else
+AT_VOLATILE_RAM_CODE
+int flash_virfat_read(struct device *device, void *buf, u32 len, u32 addr)
+{
+ /* y_printf(">>>[test]:r;addr = %d ,len = %d\n", addr, len); */
+ void *_buf = buf;
+ u32 _len = len;
+ u32 _lba = addr;
+ while (_len) {
+ virfat_flash_read(_buf, _lba, 512);
+ //printf_buf(_buf, 512);
+ _len -= 1;
+ _lba += 1;
+ _buf += 512;
+ }
+ return len;
+
+ /* return virfat_flash_read(buf, addr, len); */
+}
+#endif
+
+static int flash_virfat_write(struct device *device, void *buf, u32 len, u32 addr)
+{
+
+ /* r_printf(">>>[test]:w;addr = %d ,len = %d\n", addr, len); */
+ /* return virfat_flash_write(buf, addr, len); */
+ void *_buf = buf;
+ u32 _len = len;
+ u32 _lba = addr;
+ while (_len) {
+ virfat_flash_write(_buf, _lba, 512);
+ //printf_buf(_buf, 512);
+ _len -= 1;
+ _lba += 1;
+ _buf += 512;
+ }
+ return len;
+
+}
+
+static bool flash_virfat_online(const struct dev_node *node)
+{
+ return 1;
+}
+
+static int flash_virfat_close(struct device *device)
+{
+ dev_close(device);
+ return 0;
+}
+static int flash_virfat_ioctrl(struct device *device, u32 cmd, u32 arg)
+{
+ int err = 0;
+ switch (cmd) {
+ case IOCTL_GET_STATUS:
+ *(u32 *)arg = 1;
+ break;
+ case IOCTL_GET_ID:
+ virfat_ioctl(device, IOCTL_GET_ID, arg);
+ /* *((u32 *)arg) = 0x12345678; */
+ break;
+ case IOCTL_GET_CAPACITY:
+ *((u32 *)arg) = virfat_flash_capacity();
+ break;
+ case IOCTL_GET_BLOCK_SIZE:
+ *((u32 *)arg) = 512;
+ break;
+ case IOCTL_ERASE_PAGE:
+ case IOCTL_ERASE_SECTOR:
+ case IOCTL_ERASE_BLOCK:
+ /* y_printf(">>>[test]:in flash_vir eraser addr = %d\n", arg); */
+ err = virfat_flash_erase(cmd, arg);
+ break;
+ case IOCTL_FLUSH:
+ break;
+ case IOCTL_CMD_RESUME:
+ break;
+ case IOCTL_CMD_SUSPEND:
+ break;
+ case IOCTL_SET_ASYNC_MODE:
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ return err;
+}
+
+const struct device_operations virfat_flash_dev_ops = {
+ .init = flash_virfat_init,
+ .online = flash_virfat_online,
+ .open = flash_virfat_open,
+ .read = flash_virfat_read,
+ .write = flash_virfat_write,
+ .ioctl = flash_virfat_ioctrl,
+ .close = flash_virfat_close,
+};
+
+static int _private_sfc_read(void *fd, void *buf, u32 addr, u32 len)
+{
+ struct device *device = (struct device *)fd;
+ FLASH_PRIVATE_INFO *flash_private_info = (FLASH_PRIVATE_INFO *)device->private_data;
+ if (flash_private_info->private_len < (addr + len)) {
+ return -1;
+ }
+ u32 cpu_addr = virfat_flash_addr2cpu_addr(flash_private_info->flash_private_addr + addr);
+ /* r_printf(">>>[test]:cpu_addr = %d, addr = %d\n", cpu_addr, addr); */
+ memcpy((u8 *)buf, (u8 *)cpu_addr, len);
+ /* put_buf(buf, len); */
+ return len;
+}
+
+static int _private_sfc_write(void *fd, void *buf, u32 addr, u32 len)
+{
+ struct device *device = (struct device *)fd;
+ FLASH_PRIVATE_INFO *flash_private_info = (FLASH_PRIVATE_INFO *)device->private_data;
+ if (flash_private_info->private_len < (addr + len)) {
+ return -1;
+ }
+ u32 wlen = -1;
+ addr += flash_private_info->flash_private_addr;
+ /* r_printf(">>>[test]:addr = %d\n", addr); */
+ /* put_buf(buf, len); */
+ wlen = norflash_write(NULL, buf, len, addr);
+ return wlen;
+}
+
+static int _private_sfc_ioctl(void *fd, u32 cmd, u32 arg)
+{
+ int res = -1;
+ struct device *device = (struct device *)fd;
+ FLASH_PRIVATE_INFO *flash_private_info = (FLASH_PRIVATE_INFO *)device->private_data;
+ if ((cmd == IOCTL_ERASE_SECTOR) || (cmd == IOCTL_ERASE_PAGE) || (cmd == IOCTL_ERASE_BLOCK)) {
+ if (flash_private_info->private_len <= arg) {
+ return -1;
+ }
+ arg += flash_private_info->flash_private_addr;
+ }
+ res = norflash_ioctl(NULL, cmd, arg);
+ return res;
+}
+
+static int private_sfc_init(const struct dev_node *node, void *arg)
+{
+ virfat_mutex_init();
+ return 0;
+}
+
+static int private_sfc_open(const char *name, struct device **device, void *arg)
+{
+ r_printf(">>>[test]:private_sfc open!!!!!!\n");
+ virfat_mutex_pend();
+ struct device *private_sfc_dev = (struct device *)zalloc(sizeof(struct device));
+ FLASH_PRIVATE_INFO *flash_private_info = (FLASH_PRIVATE_INFO *)zalloc(sizeof(FLASH_PRIVATE_INFO));
+ if (arg) {
+ memcpy(flash_private_info->part_name, arg, strlen(arg));
+ }
+ ASSERT(boot_info.vm.align >= 8, "virfat_flash erase sector < 4K is not support!!!!!!!!!");
+ virfat_get_cpu_fatfs_addr(flash_private_info->part_name, &flash_private_info->flash_private_addr, &flash_private_info->private_len);
+ private_sfc_dev->private_data = flash_private_info;
+ *device = private_sfc_dev;
+ virfat_mutex_post();
+ return 0;
+}
+
+int private_sfc_read(struct device *device, void *buf, u32 len, u32 addr)
+{
+ /* y_printf(">>>[test]:r;addr = %d ,len = %d\n", addr, len); */
+ virfat_mutex_pend();
+ int rlen = _private_sfc_read(device, buf, addr, len);
+ virfat_mutex_post();
+ return rlen;
+}
+
+static int private_sfc_write(struct device *device, void *buf, u32 len, u32 addr)
+{
+
+ /* r_printf(">>>[test]:w;addr = %d ,len = %d\n", addr, len); */
+ virfat_mutex_pend();
+ int wlen = _private_sfc_write(device, buf, addr, len);
+ virfat_mutex_post();
+ return wlen;
+}
+
+static bool private_sfc_online(const struct dev_node *node)
+{
+ return 1;
+}
+
+static int private_sfc_close(struct device *device)
+{
+ virfat_mutex_pend();
+ dev_close(device);
+ if (device->private_data) {
+ free(device->private_data);
+ }
+ free(device);
+ virfat_mutex_post();
+ return 0;
+}
+static int private_sfc_ioctrl(struct device *device, u32 cmd, u32 arg)
+{
+ virfat_mutex_pend();
+ int err = 0;
+ FLASH_PRIVATE_INFO *flash_private_info = (FLASH_PRIVATE_INFO *)device->private_data;
+ switch (cmd) {
+ case IOCTL_GET_STATUS:
+ *(u32 *)arg = 1;
+ break;
+ case IOCTL_GET_ID:
+ /* virfat_ioctl(device, IOCTL_GET_ID, arg); */
+ /* *((u32 *)arg) = 0x12345678; */
+ break;
+ case IOCTL_GET_CAPACITY:
+ *((u32 *)arg) = flash_private_info->private_len;
+ break;
+ case IOCTL_GET_BLOCK_SIZE:
+ *((u32 *)arg) = 512;
+ break;
+ case IOCTL_ERASE_PAGE:
+ case IOCTL_ERASE_SECTOR:
+ case IOCTL_ERASE_BLOCK:
+ /* y_printf(">>>[test]:in flash_vir eraser addr = %d\n", arg); */
+ err = _private_sfc_ioctl(device, cmd, arg);
+ break;
+ case IOCTL_FLUSH:
+ break;
+ case IOCTL_CMD_RESUME:
+ break;
+ case IOCTL_CMD_SUSPEND:
+ break;
+ case IOCTL_SET_ASYNC_MODE:
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ virfat_mutex_post();
+ return err;
+}
+
+const struct device_operations private_sfc_dev_ops = {
+ .init = private_sfc_init,
+ .online = private_sfc_online,
+ .open = private_sfc_open,
+ .read = private_sfc_read,
+ .write = private_sfc_write,
+ .ioctl = private_sfc_ioctrl,
+ .close = private_sfc_close,
+};
+#endif
diff --git a/apps/common/file_operate/file_bs_deal.c b/apps/common/file_operate/file_bs_deal.c
new file mode 100644
index 0000000..f3bdf1a
--- /dev/null
+++ b/apps/common/file_operate/file_bs_deal.c
@@ -0,0 +1,488 @@
+/*
+ *********************************************************************************************************
+ * AC51
+ * fs browser select
+ * CODE
+ *
+ * (c) Copyright 2015-2016, ZHUHAI JIELI
+ * All Rights Reserved
+ *
+ * File : *
+ * By : jamin.li
+ * DATE : 2015-10-15 build this file
+ *********************************************************************************************************
+ */
+
+#include "file_bs_deal.h"
+#include "uart.h"
+#include "dev_manager.h"
+
+#define FILE_BS_OPT_DBG
+#ifdef FILE_BS_OPT_DBG
+
+#define file_bs_puts puts
+#define file_bs_printf printf
+
+#else
+#define file_bs_puts(...)
+#define file_bs_printf(...)
+
+#endif
+
+/*
+ *********************************************************************************************************
+ *
+ * Description: 在指定数据中,搜索key(byte)的位置
+ *
+ * Arguments : buf - 指定数据起始地址, buf_len-长度, key-搜索的key,
+ * find_type -搜索方向:0-从前往后搜索,1-从后往前搜索
+ *
+ * Returns : key的位置
+ *
+ * Note:
+ *********************************************************************************************************
+ */
+//查找byte的位置
+static int find_byte_pos(u8 *buf, u16 buf_len, u8 key, u8 find_type)
+{
+ u8 *data = buf;
+
+ if (0 == find_type) {
+ //从前往后找
+ while (buf_len > 0) {
+ if (*data == key) {
+ return (int)(data - buf);
+ }
+ data++;
+ buf_len--;
+ }
+ } else {
+ //从后往前找
+ data += (buf_len - 1);
+ while (buf_len > 0) {
+ if (*data == key) {
+ return (int)(data - buf);
+ }
+ data--;
+ buf_len--;
+ }
+ }
+ return -1;
+}
+
+
+/*
+ *********************************************************************************************************
+ *
+ * Description: 转化路径格式
+ *
+ * Arguments :
+ *
+ * Returns : 0-为成功,其他值 失败
+ *
+ * Note:
+ *********************************************************************************************************
+ */
+int file_comm_change_file_path(char *dest, char *src)
+{
+ u8 start_flag = 0, space_flag, val;
+
+ while (1) {
+ val = *src;
+ if (val == '\0') {
+ *dest = '\0';
+ break;
+ }
+ switch (val) {
+ case '/':
+ if (start_flag != 0) {
+ space_flag = 0;
+ }
+ start_flag++;
+ *dest = val;
+ break;
+
+ case ' ':
+ space_flag = 1;
+ break;
+
+ default:
+ if (space_flag != 0) {
+ *dest = '.';
+ dest++;
+ space_flag = 0;
+ }
+ *dest = val;
+ break;
+ }
+
+ dest++;
+ src++;
+ }
+
+ return 0;
+}
+
+/*
+ *********************************************************************************************************
+ *
+ * Description: 修正从fs取等的长名
+ *
+ * Arguments : str,len
+ *
+ * Returns : 字节长度(不包含结束符)
+ *
+ * Note: 过滤0xffff值,自动填入结束符
+ *********************************************************************************************************
+ */
+int file_comm_long_name_fix(u8 *str, u16 len)
+{
+ u8 *src = str;
+ while (len > 1) {
+ if ((*str == 0xff) && (*(str + 1) == 0xff)) {
+ break;
+ }
+
+ if ((*str == 0x0) && (*(str + 1) == 0x0)) {
+ break;
+ }
+
+ str += 2;
+ len -= 2;
+ }
+ *str = 0x00;
+ *(str + 1) = 0x00;
+ return (int)(str - src);
+}
+
+/*
+ *********************************************************************************************************
+ *
+ * Description: 转换8+3名字显示
+ *
+ * Arguments : dest,src
+ *
+ * Returns : 转换后名字的长度(不包含结束符)
+ *
+ * Note: 转换后自动填入结束符
+ *********************************************************************************************************
+ */
+int file_comm_display_83name(u8 *dest, u8 *src)
+{
+ u8 offset;
+
+ for (offset = 8; offset > 0; offset--) {
+ if (src[offset - 1] != 0x20) {
+ break;
+ }
+ }
+
+ memcpy(dest, src, offset);
+
+ if (src[8] != 0x20) {
+ dest[offset++] = '.';
+ memcpy(dest + offset, src + 8, 3);
+ offset += 3;
+ }
+
+ dest[offset++] = '\0';
+
+ return offset; //name 's len
+}
+
+/*
+ *********************************************************************************************************
+ *
+ * Description: 获取显示的文件夹或文件名字
+ *
+ * Arguments :tpath,disp_file_name,disp_dir_name
+ *
+ * Returns :
+ *
+ * Note: 转换后 lfn_cnt 为0为短名,lfn_cnt不为0 则是长名
+ *********************************************************************************************************
+ */
+void file_comm_change_display_name(char *tpath, LONG_FILE_NAME *disp_file_name, LONG_FILE_NAME *disp_dir_name)
+{
+ u16 len;
+ int pos;
+
+ //取文件名字显示
+
+ if (disp_file_name != NULL) {
+ if (disp_file_name->lfn_cnt != 0) {
+ //long name
+ file_bs_puts("file long name \n");
+ //printf_buf(disp_file_name->lfn, 16);
+ disp_file_name->lfn_cnt = file_comm_long_name_fix((void *)disp_file_name->lfn, disp_file_name->lfn_cnt); //增加结束符
+ } else {
+ //short name
+ file_bs_puts("file short name\n");
+ len = strlen((void *)tpath); //增加结束符
+ pos = find_byte_pos((void *)tpath, len, 0x2f, 1); //
+ if (pos == -1) {
+ strcpy(disp_file_name->lfn, "----");
+ } else {
+ memcpy((void *)&disp_file_name->lfn[32], tpath + pos + 1, 11);
+ file_comm_display_83name((void *)disp_file_name->lfn, (void *)&disp_file_name->lfn[32]);
+ }
+
+ disp_file_name->lfn_cnt = 0;
+ }
+
+ //printf_buf(disp_file_name->lfn, 32);
+
+ }
+
+
+ //取文件夹名字显示
+ if (disp_dir_name != NULL) {
+ if (disp_dir_name->lfn_cnt != 0) {
+ //long name
+ file_bs_puts("folder long name \n");
+ //printf_buf(disp_dir_name->lfn, 16);
+ disp_dir_name->lfn_cnt = file_comm_long_name_fix((void *)&disp_dir_name->lfn, disp_dir_name->lfn_cnt); //增加结束符
+ } else {
+ //short name
+ file_bs_puts("folder short name \n");
+ len = strlen((void *)tpath); //增加结束符
+ pos = find_byte_pos((void *)tpath, len, 0x2f, 1); //
+
+ if (pos != -1) {
+ pos = find_byte_pos((void *)tpath, pos, 0x2f, 1); //
+ }
+
+ if (pos == -1) {
+ strcpy(disp_dir_name->lfn, "ROOT");
+ } else {
+ memcpy(&disp_dir_name->lfn[32], tpath + pos + 1, 11);
+ file_comm_display_83name((void *)disp_dir_name->lfn, (void *)&disp_dir_name->lfn[32]);
+ }
+ disp_dir_name->lfn_cnt = 0;
+ }
+
+ //printf_buf(disp_dir_name->lfn, 32);
+ }
+}
+/*
+ *********************************************************************************************************
+ *
+ * Description: 打开文件浏览器
+ *
+ * Arguments : fil_bs
+ *
+ * Returns : dir的总数
+ *
+ * Note:
+ *********************************************************************************************************
+ */
+//返回根目录dir总数
+u32 file_bs_open_handle(FILE_BS_DEAL *fil_bs, u8 *ext_name)
+{
+ u32 total_dir;
+
+ if (fil_bs == NULL) {
+ puts("*open hdl is null\n");
+ return 0;
+ }
+
+ file_bs_puts("open bs hdl\n");
+ file_bs_printf("bs_mapi:0x%x\n", (int)fil_bs);
+
+ if (ext_name == NULL) {
+ ext_name = "MP3";//"WAVWMAMP3FLA";
+ }
+
+ printf("fil_bs->dev = %x\n", fil_bs->dev);
+ printf("%s, %s, %s, %d\n]", dev_manager_get_root_path(fil_bs->dev), dev_manager_get_logo(fil_bs->dev), __FUNCTION__, __LINE__);
+ fset_ext_type(dev_manager_get_root_path(fil_bs->dev), ext_name);
+ printf("%s, %d\n]", __FUNCTION__, __LINE__);
+
+ total_dir = fopen_dir_info(dev_manager_get_root_path(fil_bs->dev), &fil_bs->file, 0);
+ printf("%s, %d\n]", __FUNCTION__, __LINE__);
+ if (fil_bs->file == 0) {
+ file_bs_puts("open bs fail\n");
+ return 0;
+ }
+ file_bs_printf("open bs hdl_out,root_dir = 0x%x\n", total_dir);
+ return total_dir;
+}
+
+/*
+ *********************************************************************************************************
+ *
+ * Description: 关闭文件浏览器
+ *
+ * Arguments : fil_bs
+ *
+ * Returns :
+ *
+ * Note:
+ *********************************************************************************************************
+ */
+void file_bs_close_handle(FILE_BS_DEAL *fil_bs)
+{
+ file_bs_puts("close bs hdl\n");
+ if (fil_bs->file) {
+ fclose(fil_bs->file);
+ fil_bs->file = NULL;
+ }
+ file_bs_puts("close bs hdl_out\n");
+}
+
+/*
+ *********************************************************************************************************
+ *
+ * Description: 进入文件夹目录
+ *
+ * Arguments : fil_bs,dir_info
+ *
+ * Returns : dir的总数
+ *
+ * Note:
+ *********************************************************************************************************
+ */
+u32 file_bs_entern_dir(FILE_BS_DEAL *fil_bs, FS_DIR_INFO *dir_info)
+{
+ u32 total_dir;
+ file_bs_printf("bs_enter dir\n");
+ total_dir = fenter_dir_info(fil_bs->file, dir_info); //使用open获得的file,无需重新申请。
+ file_bs_printf("bs_enter_out,t = 0x%x\n", total_dir);
+ return total_dir;
+}
+
+/*
+ *********************************************************************************************************
+ *
+ * Description: 返回上传目录
+ *
+ * Arguments : fil_bs
+ *
+ * Returns : dir的总数
+ *
+ * Note:
+ *********************************************************************************************************
+ */
+u32 file_bs_exit_dir(FILE_BS_DEAL *fil_bs)
+{
+ u32 total_dir;
+ file_bs_printf("bs_exit dir\n");
+ total_dir = fexit_dir_info(fil_bs->file);//
+ file_bs_printf("bs_exit_out,total = 0x%x\n", total_dir);
+ return total_dir;
+}
+
+/*
+ *********************************************************************************************************
+ *
+ * Description: 获取指定位置的dir信息
+ *
+ * Arguments : fil_bs,buf--被填入的buf,start_sn -获取的其实位置(从1开始),get_cnt--获取dir的个数
+ *
+ * Returns : 真正获取到的dir总数
+ *
+ * Note:
+ *********************************************************************************************************
+ */
+u32 file_bs_get_dir_info(FILE_BS_DEAL *fil_bs, FS_DIR_INFO *buf, u16 start_sn, u16 get_cnt)
+{
+ u32 real_dir;
+ /* file_bs_printf("bs_get dir_info\n"); */
+ real_dir = fget_dir_info(fil_bs->file, start_sn, get_cnt, buf);
+ /* file_bs_printf("bs_get_out,t = 0x%x\n", real_dir); */
+ return real_dir;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// test
+
+#if 0
+
+#define BS_GET_DIR_NUM 3
+void file_bs_test(void)
+{
+ printf("\n\n\n\n %s,%d, ", __func__, __LINE__);
+ FS_DIR_INFO *dir_buf = zalloc(sizeof(FS_DIR_INFO) * BS_GET_DIR_NUM);
+ FILE_BS_DEAL *fil_bs = zalloc(sizeof(FILE_BS_DEAL));
+ if (!fil_bs || !dir_buf) {
+ printf("%s,%d, ", __func__, __LINE__);
+ printf("malloc err");
+ while (1);
+ }
+ fil_bs->dev = storage_dev_last();
+ if (!fil_bs->dev) {
+ printf("%s,%d, ", __func__, __LINE__);
+ printf("have no dev");
+ while (1);
+ }
+
+ /* void *fmnt = mount(fil_bs->dev->dev_name, fil_bs->dev->storage_path, fil_bs->dev->fs_type, 3, NULL); */
+ /* if (!fmnt) { */
+ /* printf("%s,%d, ", __func__, __LINE__); */
+ /* printf("mount err"); */
+ /* while(1); */
+ /* } */
+
+ int i, j, cnt, total;
+ file_bs_open_handle(fil_bs, "MP3");//open完后需要close
+ /* printf("\n root dir num: %d ", total); */
+ /* if (!total) { */
+ /* printf("%s,%d, ", __func__, __LINE__); */
+ /* printf("total dir is zero"); */
+ /* goto __exit; */
+ /* } */
+
+ total = file_bs_entern_dir(fil_bs, dir_buf);
+ /* printf("\n %s,%d, ", __func__, __LINE__); */
+ /* printf("dir num: %d ", total); */
+ if (!total) {
+ printf("%s,%d, ", __func__, __LINE__);
+ printf("total dir is zero");
+ goto __exit;
+ }
+
+ u8 flag = 0;
+ for (i = 1; i <= total; i += BS_GET_DIR_NUM) {
+__again:
+ cnt = file_bs_get_dir_info(fil_bs, dir_buf, i, BS_GET_DIR_NUM);
+ /* printf("\n cnt:%d ", cnt); */
+ for (j = 0; j < cnt; j++) {
+ /* printf("j:%d, dirtype:%d, fntype:%d, sclust:0x%x ", i + j, dir_buf[j].dir_type, dir_buf[j].fn_type, dir_buf[j].sclust); */
+ if (dir_buf[j].dir_type == BS_DIR_TYPE_FORLDER) {
+ if (flag < 2) {
+ flag ++;
+ if (flag == 2) {
+ int sub_i, sub_j, sub_cnt, sub_total;
+ sub_total = file_bs_entern_dir(fil_bs, &dir_buf[j]);
+ /* printf("\n %s,%d, ", __func__, __LINE__); */
+ /* printf("dir num: %d ", sub_total); */
+ if (sub_total) {
+ for (sub_i = 1; sub_i <= sub_total; sub_i += BS_GET_DIR_NUM) {
+ sub_cnt = file_bs_get_dir_info(fil_bs, dir_buf, sub_i, BS_GET_DIR_NUM);
+ /* printf("sub_cnt:%d ", sub_cnt); */
+ for (sub_j = 0; sub_j < sub_cnt; sub_j++) {
+ /* printf("sub_j:%d, dirtype:%d, fntype:%d, sclust:0x%x ", sub_i + sub_j, dir_buf[sub_j].dir_type, dir_buf[sub_j].fn_type, dir_buf[sub_j].sclust); */
+ }
+ }
+ }
+ file_bs_exit_dir(fil_bs);
+ goto __again;
+ }
+ }
+ }
+ }
+ }
+
+__exit:
+ /* printf("\n %s,%d, \n ", __func__, __LINE__); */
+
+ file_bs_close_handle(fil_bs);
+
+ /* unmount(fil_bs->dev->storage_path); */
+
+ free(dir_buf);
+ free(fil_bs);
+}
+#endif
+
diff --git a/apps/common/file_operate/file_bs_deal.h b/apps/common/file_operate/file_bs_deal.h
new file mode 100644
index 0000000..373e703
--- /dev/null
+++ b/apps/common/file_operate/file_bs_deal.h
@@ -0,0 +1,47 @@
+/*
+ *********************************************************************************************************
+ * AC46
+ * fs browser select
+ * CODE
+ *
+ * (c) Copyright 2015-2016, ZHUHAI JIELI
+ * All Rights Reserved
+ *
+ * File : *
+ * By : jamin.li
+ * DATE : 2015-10-15 build this file
+ *********************************************************************************************************
+ */
+
+#ifndef _FILE_BS_DEAL_H_
+#define _FILE_BS_DEAL_H_
+
+#include "fs/fs.h"
+#include "storage_dev/storage_dev.h"
+
+#define BS_DIR_TYPE_FORLDER 0
+#define BS_DIR_TYPE_FILE 1
+
+#define BS_FNAME_TYPE_SHORT 0
+#define BS_FNAME_TYPE_LONG 1
+
+typedef struct _FILE_BS_DEAL_ {
+ struct __dev *dev;
+ FILE *file;
+} FILE_BS_DEAL;
+
+
+extern int file_comm_change_file_path(char *dest, char *src);
+extern int file_comm_long_name_fix(u8 *str, u16 len);
+extern int file_comm_display_83name(u8 *dest, u8 *src);
+
+extern u32 file_bs_open_handle(FILE_BS_DEAL *fil_bs, u8 *ext_name);
+extern void file_bs_close_handle(FILE_BS_DEAL *fil_bs);
+extern u32 file_bs_entern_dir(FILE_BS_DEAL *fil_bs, FS_DIR_INFO *dir_info);
+extern u32 file_bs_exit_dir(FILE_BS_DEAL *fil_bs);
+extern u32 file_bs_get_dir_info(FILE_BS_DEAL *fil_bs, FS_DIR_INFO *buf, u16 start_sn, u16 get_cnt);
+
+extern void file_comm_change_display_name(char *tpath, LONG_FILE_NAME *disp_file_name, LONG_FILE_NAME *disp_dir_name);
+
+#endif/*_FILE_BS_DEAL_H_*/
+
diff --git a/apps/common/file_operate/file_manager.c b/apps/common/file_operate/file_manager.c
new file mode 100644
index 0000000..6d774dc
--- /dev/null
+++ b/apps/common/file_operate/file_manager.c
@@ -0,0 +1,371 @@
+#include "file_manager.h"
+#include "app_config.h"
+
+#define MODE_FIX 0
+#if MODE_FIX
+static int file_manager_mode_deal(struct vfscan *fs, int sel_mode, int *arg)
+{
+
+ int err;
+ int fnum = 0;
+ int file_start = 1;
+ int file_end = fs->file_number;
+
+ if (file_end == 0) {
+ return -ENOENT;
+ }
+ struct ffolder folder = {0};
+ fget_folder(fs, &folder);
+ /* if ((scan->cycle_mode == FCYCLE_FOLDER) && (scan->ff_api.fileTotalInDir) */
+ /* && ((scan->ff_api.fileTotalOutDir + scan->ff_api.fileTotalInDir) <= scan->ff_api.totalFileNumber) */
+ /* ) { */
+
+ if ((fs->cycle_mode == FCYCLE_FOLDER) && (folder.fileTotal)
+ && ((folder.fileStart + folder.fileTotal - 1) <= file_end)
+ ) {
+ file_start = folder.fileStart;
+ file_end = folder.fileStart + folder.fileTotal - 1;
+ }
+ switch (sel_mode) {
+ case FSEL_LAST_FILE:
+ fnum = fs->file_number;
+ break;
+ case FSEL_FIRST_FILE:
+ fnum = 1;
+ break;
+ case FSEL_AUTO_FILE:
+ /* if (scan->ff_api.fileNumber == 0) { */
+ /* return -EINVAL; */
+ /* } */
+ if (fs->cycle_mode == FCYCLE_ONE) {
+ /* fnum = scan->ff_api.fileNumber; */
+ fnum = fs->file_counter;
+ break;
+ }
+ case FSEL_NEXT_FILE:
+ /* if (scan->ff_api.fileNumber == 0) { */
+ /* return -EINVAL; */
+ /* } */
+ if (fs->cycle_mode == FCYCLE_RANDOM) {
+ fnum = rand32() % (file_end - file_start + 1) + file_start;
+ if (fnum == fs->file_counter) {
+ fnum = fs->file_counter + 1;
+ }
+ } else {
+ fnum = fs->file_counter + 1;
+ }
+ /* if (fnum > scan->last_file_number) { */
+ if (fnum > fs->file_number) {
+ if (fs->cycle_mode == FCYCLE_LIST) {
+ return -ENOENT;
+ } else if (fs->cycle_mode == FCYCLE_FOLDER) {
+ fnum = file_start;
+ } else {
+ fnum = 1;
+ }
+ }
+ if (fnum > file_end) {
+ fnum = file_start;
+ } else if (fnum < file_start) {
+ fnum = file_end;
+ }
+ break;
+ case FSEL_PREV_FILE:
+ /* if (scan->ff_api.fileNumber == 0) { */
+ /* return -EINVAL; */
+ /* } */
+ if (fs->cycle_mode == FCYCLE_RANDOM) {
+ fnum = rand32() % (file_end - file_start + 1) + file_start;
+ if (fnum == fs->file_counter) {
+ fnum = fs->file_counter + 1;
+ }
+ } else {
+ fnum = fs->file_counter - 1;
+ }
+ /* if ((scan->ff_api.fileNumber | BIT(15)) != scan->cur_file_number) { */
+ /* fnum -= scan->last_file_number - scan->ff_api.totalFileNumber; */
+ /* } */
+ /* scan->last_file_number = scan->ff_api.totalFileNumber; */
+ if (fs->cycle_mode == FCYCLE_LIST) {
+ break;
+ }
+ if (fnum > file_end) {
+ fnum = file_start;
+ } else if (fnum < file_start) {
+ fnum = file_end;
+ }
+ break;
+
+ case FSEL_NEXT_FOLDER_FILE:
+ /* fnum = scan->ff_api.fileTotalOutDir + scan->ff_api.fileTotalInDir + 1; */
+ fnum = folder.fileStart + folder.fileTotal;
+ if (fnum > fs->file_number) {
+ fnum = 1;
+ }
+ break;
+ case FSEL_PREV_FOLDER_FILE:
+ /* if ((scan->ff_api.fileTotalOutDir + 1) > 1) { */
+ if (folder.fileStart > 1) {
+ fnum = folder.fileStart - 1;
+ } else {
+ fnum = fs->file_number;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if ((sel_mode != FSEL_NEXT_FOLDER_FILE) && (sel_mode != FSEL_PREV_FOLDER_FILE)) {
+ if (fnum < file_start) {
+ fnum = file_start;
+ } else if (fnum > file_end) {
+ fnum = file_end;
+ }
+ }
+ *arg = fnum;
+ return 0;
+}
+#endif
+
+FILE *file_manager_select(struct __dev *dev, struct vfscan *fs, int sel_mode, int arg, struct __scan_callback *callback)
+{
+ FILE *_file = NULL;
+ //clock_add_set(SCAN_DISK_CLK);
+ if (callback && callback->enter) {
+ callback->enter(dev);//扫描前处理, 可以在注册的回调里提高系统时钟等处理
+ }
+#if MODE_FIX
+ if ((sel_mode != FSEL_BY_SCLUST) && (sel_mode != FSEL_BY_PATH)) {
+ if (file_manager_mode_deal(fs, sel_mode, &arg)) {
+ return NULL;
+ }
+ sel_mode = FSEL_BY_NUMBER;
+ }
+#endif
+ _file = fselect(fs, sel_mode, arg);
+ //clock_remove_set(SCAN_DISK_CLK);
+ if (callback && callback->exit) {
+ callback->exit(dev);//扫描后处理, 可以在注册的回调里还原到enter前的状态
+ }
+ return _file;
+}
+
+/* --------------------------------------------------------------------------*/
+/**
+ * @brief 文件删除统一处理
+ *
+ * @param path 扫描路径名
+ * @param param 配置参数
+ * @param dir_flag 是否删除文件夹标志
+ * @note 加速处理:(删除文件的时候使用)从前往后依次删除. 文件夹必须从后往前删。
+ *
+ * @return 0成功, 其他失败
+ */
+/* ----------------------------------------------------------------------------*/
+int file_manager_delete_deal(char *path, char *param, u8 dir_flag)
+{
+ u16 folder_total_file = 0;
+ int d_err = 0;
+ struct vfscan *fsn = NULL;
+ FILE *d_f = NULL;
+
+ fsn = fscan(path, param, 9);
+ if (fsn == NULL) {
+ r_printf(">>>[test]:err!!!!!! fsacn fsn fail\n");
+ return 1;
+ }
+ folder_total_file = fsn->file_number;
+ y_printf(">>>[test]:total = %d\n", folder_total_file);
+ for (int i = folder_total_file; i >= 1; i--) {
+ if (!dir_flag) {
+ d_f = fselect(fsn, FSEL_BY_NUMBER, folder_total_file - i + 1); //加速处理,不用找到最后一个文件。
+ } else {
+ d_f = fselect(fsn, FSEL_BY_NUMBER, i);
+ }
+ if (d_f == NULL) {
+ r_printf(">>>[test]:err!! select file err\n");
+ return 1;
+ }
+ putchar('D');
+ d_err = fdelete(d_f);
+ if (d_err) {
+ r_printf(">>>[test]:err!! delete file err\n");
+ return 1;
+ }
+ d_f = NULL;
+ }
+ return 0;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/** @brief:文件夹删除处理
+ @param:dev_logo :设备logo folder:文件夹路径(短名) folder_len:文件夹路径长度
+ @return:
+ @author:phewlee
+ @note:
+ @date: 2021-05-21,10:16
+*/
+/*----------------------------------------------------------------------------*/
+int file_manager_delete_dir(char *dev_logo, char *folder, u16 folder_len)
+{
+ int err = 0;
+ struct __dev *dev;
+ char path[128] = {0};
+
+ static const u8 delete_file_param[] = "-t"
+ "ALL"
+ " -sn -r";
+
+ static const u8 delete_folder_param[] = "-t"
+ "ALL"
+ " -sn -d -r";
+
+ dev = dev_manager_find_spec(dev_logo, 0);
+ if (dev == NULL) {
+ r_printf(">>>[test]:errr!!!!!!!!! not find dev\n");
+ return 1;
+ }
+ char *root_path = dev_manager_get_root_path(dev);
+ memcpy(path, root_path, strlen(root_path));
+ memcpy(path + strlen(root_path), folder, folder_len);
+ r_printf(">>>[test]:path = %s\n", path);
+ err = file_manager_delete_deal(path, delete_file_param, 0);
+ if (err) {
+ r_printf(">>>[test]:errr!!!!!!!!! delete file deal fail\n");
+ return 1;
+ }
+ err = file_manager_delete_deal(path, delete_folder_param, 1);
+ if (err) {
+ r_printf(">>>[test]:errr!!!!!!!!! delete folder deal fail\n");
+ return 1;
+ }
+ FILE *folder_f = fopen(path, "r");
+ if (folder_f == NULL) {
+ r_printf(">>>[test]:err open folder\n");
+ return 1;
+ }
+ err = fdelete(folder_f);
+ return err;
+}
+
+/*----------------------------------------------------------------------------*/
+/** @brief:文件插入处理
+ @param:d_f: 源文件句柄, i_f:插入文件句柄,fptr:偏移量
+ @return:
+ @author:phewlee
+ @note:
+ @date: 2021-05-25,10:16
+*/
+/*----------------------------------------------------------------------------*/
+int file_manager_insert_file(FILE *d_f, FILE *i_f, u32 fptr)
+{
+ int err = finsert_file(d_f, i_f, fptr);
+ return err;
+}
+
+/*----------------------------------------------------------------------------*/
+/** @brief:文件分割处理
+ @param:f: 源文件句柄, dev_logo:设备logo , file_name : 文件名, name_len: 文件长度, fptr:偏移量, buf:头文件数据, buf_len:头文件数据长度, folder : 需要指定的路径,绝对路径,例如:/RECORD或者/1/2/3/4, 暂时只支持短名文件夹形式, folder 传NULL默认根目录。
+ @return:
+ @author:phewlee
+ @note:
+ @date: 2021-05-25,10:16
+*/
+/*----------------------------------------------------------------------------*/
+int file_manager_division_file(FILE *f, char *dev_logo, char *file_name, u32 name_len, u32 fptr, char *buf, u32 buf_len, char *folder)
+{
+ struct __dev *dev;
+ char path[128] = {0};
+ char tmp_name[64] = {0};
+ if ((dev_logo == NULL) || (file_name == NULL) || (buf == NULL)) {
+ return -1;
+ }
+
+ ///////////////////////////////////////////////////
+ dev = dev_manager_find_spec(dev_logo, 0);
+ if (dev == NULL) {
+ r_printf(">>>[test]:errr!!!!!!!!! not find dev\n");
+ return -1;
+ }
+ char *root_path = dev_manager_get_root_path(dev);
+
+ /****************分割文件*********************/
+ if (folder) {
+ memcpy(tmp_name, folder, strlen(folder));
+ }
+ strcat(tmp_name, "/");
+ strcat(tmp_name, "jl_test.tmp");
+ if (fdicvision_file(f, tmp_name, fptr)) {
+ r_printf(">>>[test]:file division fail\n");
+ goto __exit;
+ }
+
+ /****************打开分割出去的文件*********************/
+ memcpy(path, root_path, strlen(root_path) - 1);
+ memcpy(path + strlen(root_path) - 1, tmp_name, strlen(tmp_name));
+ r_printf(">>>[test]:path1 = %s\n", path);
+ FILE *i_f = fopen(path, "r");
+ if (i_f == NULL) {
+ r_printf(">>>[test]:open i_f fail\n");
+ return -1;
+ }
+ ///////////////////////////////////////////////////
+
+ /****************创建新文件,写入头数据*********************/
+ memset(path, 0, sizeof(path));
+ memcpy(path, root_path, strlen(root_path));
+ if (folder) {
+ memcpy(path + strlen(path) - 1, folder, strlen(folder));
+ strcat(path, "/");
+ }
+ memcpy(path + strlen(path), file_name, name_len);
+ r_printf(">>>[test]:path1 = %s\n", path);
+ FILE *d_f = fopen(path, "w+");
+ if (d_f == NULL) {
+ r_printf(">>>[test]:open d_f fail\n");
+ fclose(i_f);
+ i_f = NULL;
+ goto __exit;
+ }
+ int wlen = fwrite(d_f, buf, buf_len);
+ if (wlen != buf_len) {
+ r_printf(">>>[test]:err write!!!!!!!!wlen = %d, buf_len = %d\n", wlen, buf_len);
+ fclose(i_f);
+ i_f = NULL;
+ fclose(d_f);
+ d_f = NULL;
+ goto __exit;
+ }
+ fclose(d_f);
+ d_f = NULL;
+ d_f = fopen(path, "r");
+ if (d_f == NULL) {
+ r_printf(">>>[test]:open d_f fail\n");
+ fclose(i_f);
+ i_f = NULL;
+ goto __exit;
+ }
+ //////////////////////////////////////////////////////////
+
+ int fsize = flen(d_f);
+ int err = finsert_file(d_f, i_f, fsize);
+ fclose(i_f);
+ i_f = NULL;
+ fclose(d_f);
+ d_f = NULL;
+ return err;
+
+__exit:
+ memset(path, 0, sizeof(path));
+ memcpy(path, root_path, strlen(root_path) - 1);
+ memcpy(path + strlen(root_path) - 1, tmp_name, strlen(tmp_name));
+ r_printf(">>>[test]:error process: path1 = %s\n", path);
+ FILE *f_tmp = fopen(path, "r");
+ if (f_tmp) {
+ fdelete(f_tmp);
+ f_tmp = NULL;
+ }
+ return -1;
+}
+
diff --git a/apps/common/file_operate/file_manager.h b/apps/common/file_operate/file_manager.h
new file mode 100644
index 0000000..0f6a3c6
--- /dev/null
+++ b/apps/common/file_operate/file_manager.h
@@ -0,0 +1,11 @@
+#ifndef __FILE_MANAGER_H__
+#define __FILE_MANAGER_H__
+
+#include "system/includes.h"
+#include "typedef.h"
+#include "system/fs/fs.h"
+#include "dev_manager.h"
+
+FILE *file_manager_select(struct __dev *dev, struct vfscan *fs, int sel_mode, int arg, struct __scan_callback *callback);
+
+#endif// __FILE_MANAGER_H__
diff --git a/apps/common/icsd/adt/icsd_adt.c b/apps/common/icsd/adt/icsd_adt.c
new file mode 100644
index 0000000..01d17f0
--- /dev/null
+++ b/apps/common/icsd/adt/icsd_adt.c
@@ -0,0 +1,503 @@
+#include "app_config.h"
+#if ((defined TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN) && TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN && \
+ TCFG_AUDIO_ANC_ENABLE)
+#include "system/task.h"
+#include "icsd_adt.h"
+#include "icsd_adt_app.h"
+#include "classic/tws_api.h"
+#include "icsd_anc.h"
+#include "tone_player.h"
+#include "icsd_anc_user.h"
+
+#define ICSD_ADT_TASK_NAME "icsd_adt"
+
+const u8 VDT_TRAIN_EN = 0;
+
+u8 adt_task = 0;
+u8 src_task = 0;
+int (*adt_printf)(const char *format, ...);
+int (*wat_printf)(const char *format, ...);
+int (*ein_printf)(const char *format, ...);
+int printf_off(const char *format, ...)
+{
+ return 0;
+}
+
+#define ADT_DATA_DEBUG 0
+void icsd_adt_run_output(__adt_result *adt_result)
+{
+ u8 voice_state = adt_result->voice_state;
+ u8 wind_lvl = adt_result->wind_lvl;
+ u8 wat_result = adt_result->wat_result;
+ u8 ein_state = adt_result->ein_state;
+
+#if ADT_DATA_DEBUG
+ extern void icsd_adt_output_demo(__adt_result * adt_result);
+ icsd_adt_output_demo(adt_result);
+#else
+ void audio_acoustic_detector_output_hdl(u8 voice_state, u8 wind_lvl, u8 wat_result);
+ audio_acoustic_detector_output_hdl(voice_state, wind_lvl, wat_result);
+#endif
+}
+
+#define AUDIO_ADC_CH0 BIT(0)
+#define AUDIO_ADC_CH1 BIT(1)
+#define AUDIO_ADC_CH2 BIT(2)
+#define AUDIO_ADC_CH3 BIT(3)
+void icsd_adt_mic_ch_analog_open(u32 ch)
+{
+ if (ch & AUDIO_ADC_CH0) {
+ /*close mic0 analog config*/
+ SFR(JL_ADDA->ADA_CON4, 15, 1, 0); // AUDADC_MICA_BUFP_EN_10v
+ SFR(JL_ADDA->ADA_CON4, 14, 1, 0); // AUDADC_MICA_BUFN_EN_10v
+ SFR(JL_ADDA->ADA_CON4, 4, 1, 1); // AUDADC_MICA_AMP_EN_10v
+ SFR(JL_ADDA->ADA_CON1, 8, 1, 1); // AUDADC_CHA_S2_RSTB_10v
+ SFR(JL_ADDA->ADA_CON1, 7, 1, 1); // AUDADC_CHA_EN_10v
+ SFR(JL_ADDA->ADA_CON1, 6, 1, 1); // AUDADC_CHA_BIAS_EN_10v
+ }
+ if (ch & AUDIO_ADC_CH1) {
+ /*close mic1 analog config*/
+ SFR(JL_ADDA->ADA_CON5, 15, 1, 0); // AUDADC_MICB_BUFP_EN_10v
+ SFR(JL_ADDA->ADA_CON5, 14, 1, 0); // AUDADC_MICB_BUFN_EN_10v
+ SFR(JL_ADDA->ADA_CON5, 4, 1, 1); // AUDADC_MICB_AMP_EN_10v
+ SFR(JL_ADDA->ADA_CON1, 11, 1, 1); // AUDADC_CHB_S2_RSTB_10v
+ SFR(JL_ADDA->ADA_CON1, 10, 1, 1); // AUDADC_CHB_EN_10v
+ SFR(JL_ADDA->ADA_CON1, 9, 1, 1); // AUDADC_CHB_BIAS_EN_10v
+ }
+ if (ch & AUDIO_ADC_CH2) {
+ /*close mic2 analog config*/
+ SFR(JL_ADDA->ADA_CON6, 15, 1, 0); // AUDADC_MICC_BUFP_EN_10v
+ SFR(JL_ADDA->ADA_CON6, 14, 1, 0); // AUDADC_MICC_BUFN_EN_10v
+ SFR(JL_ADDA->ADA_CON6, 4, 1, 1); // AUDADC_MICC_AMP_EN_10v
+ SFR(JL_ADDA->ADA_CON1, 14, 1, 1); // AUDADC_CHC_S2_RSTB_10v
+ SFR(JL_ADDA->ADA_CON1, 13, 1, 1); // AUDADC_CHC_EN_10v
+ SFR(JL_ADDA->ADA_CON1, 12, 1, 1); // AUDADC_CHC_BIAS_EN_10v
+ }
+ if (ch & AUDIO_ADC_CH3) {
+ /*close mic3 analog config*/
+ SFR(JL_ADDA->ADA_CON7, 15, 1, 0); // AUDADC_MICD_BUFP_EN_10v
+ SFR(JL_ADDA->ADA_CON7, 14, 1, 0); // AUDADC_MICD_BUFN_EN_10v
+ SFR(JL_ADDA->ADA_CON7, 4, 1, 1); // AUDADC_MICD_AMP_EN_10v
+ SFR(JL_ADDA->ADA_CON1, 17, 1, 1); // AUDADC_CHD_S2_RSTB_10v
+ SFR(JL_ADDA->ADA_CON1, 16, 1, 1); // AUDADC_CHD_EN_10v
+ SFR(JL_ADDA->ADA_CON1, 15, 1, 1); // AUDADC_CHD_BIAS_EN_10v
+ }
+}
+
+void icsd_adt_mic_ch_analog_close(u32 ch)
+{
+ if (ch & AUDIO_ADC_CH0) {
+ /*close mic0 analog config*/
+ SFR(JL_ADDA->ADA_CON4, 15, 1, 0); // AUDADC_MICA_BUFP_EN_10v
+ SFR(JL_ADDA->ADA_CON4, 14, 1, 0); // AUDADC_MICA_BUFN_EN_10v
+ SFR(JL_ADDA->ADA_CON4, 4, 1, 0); // AUDADC_MICA_AMP_EN_10v
+ SFR(JL_ADDA->ADA_CON1, 8, 1, 0); // AUDADC_CHA_S2_RSTB_10v
+ SFR(JL_ADDA->ADA_CON1, 7, 1, 0); // AUDADC_CHA_EN_10v
+ SFR(JL_ADDA->ADA_CON1, 6, 1, 0); // AUDADC_CHA_BIAS_EN_10v
+ }
+ if (ch & AUDIO_ADC_CH1) {
+ /*close mic1 analog config*/
+ SFR(JL_ADDA->ADA_CON5, 15, 1, 0); // AUDADC_MICB_BUFP_EN_10v
+ SFR(JL_ADDA->ADA_CON5, 14, 1, 0); // AUDADC_MICB_BUFN_EN_10v
+ SFR(JL_ADDA->ADA_CON5, 4, 1, 0); // AUDADC_MICB_AMP_EN_10v
+ SFR(JL_ADDA->ADA_CON1, 11, 1, 0); // AUDADC_CHB_S2_RSTB_10v
+ SFR(JL_ADDA->ADA_CON1, 10, 1, 0); // AUDADC_CHB_EN_10v
+ SFR(JL_ADDA->ADA_CON1, 9, 1, 0); // AUDADC_CHB_BIAS_EN_10v
+ }
+ if (ch & AUDIO_ADC_CH2) {
+ /*close mic2 analog config*/
+ SFR(JL_ADDA->ADA_CON6, 15, 1, 0); // AUDADC_MICC_BUFP_EN_10v
+ SFR(JL_ADDA->ADA_CON6, 14, 1, 0); // AUDADC_MICC_BUFN_EN_10v
+ SFR(JL_ADDA->ADA_CON6, 4, 1, 0); // AUDADC_MICC_AMP_EN_10v
+ SFR(JL_ADDA->ADA_CON1, 14, 1, 0); // AUDADC_CHC_S2_RSTB_10v
+ SFR(JL_ADDA->ADA_CON1, 13, 1, 0); // AUDADC_CHC_EN_10v
+ SFR(JL_ADDA->ADA_CON1, 12, 1, 0); // AUDADC_CHC_BIAS_EN_10v
+ }
+ if (ch & AUDIO_ADC_CH3) {
+ /*close mic3 analog config*/
+ SFR(JL_ADDA->ADA_CON7, 15, 1, 0); // AUDADC_MICD_BUFP_EN_10v
+ SFR(JL_ADDA->ADA_CON7, 14, 1, 0); // AUDADC_MICD_BUFN_EN_10v
+ SFR(JL_ADDA->ADA_CON7, 4, 1, 0); // AUDADC_MICD_AMP_EN_10v
+ SFR(JL_ADDA->ADA_CON1, 17, 1, 0); // AUDADC_CHD_S2_RSTB_10v
+ SFR(JL_ADDA->ADA_CON1, 16, 1, 0); // AUDADC_CHD_EN_10v
+ SFR(JL_ADDA->ADA_CON1, 15, 1, 0); // AUDADC_CHD_BIAS_EN_10v
+ }
+}
+
+u8 talk_mic_analog_close = 0;
+u8 audio_adt_talk_mic_analog_close()
+{
+ if (talk_mic_analog_close == 0) {
+ printf("-----------audio_adt_talk_mic_analog_close\n");
+ u8 talk_mic_ch = icsd_get_talk_mic_ch();
+ icsd_adt_mic_ch_analog_close(talk_mic_ch);
+ talk_mic_analog_close = 1;
+ return 1;
+ }
+ return 0;
+}
+
+u8 audio_adt_talk_mic_analog_open()
+{
+ if (talk_mic_analog_close) {
+ printf("-----------audio_adt_talk_mic_analog_open\n");
+ u8 talk_mic_ch = icsd_get_talk_mic_ch();
+ icsd_adt_mic_ch_analog_open(talk_mic_ch);
+ talk_mic_analog_close = 0;
+ return 1;
+ }
+ return 0;
+}
+
+float adt_pow10(float n)
+{
+ float pow10n = exp_float((float)n / log10_float(exp_float((float)1.0)));
+ return pow10n;
+}
+
+u32 icsd_adt_get_role()
+{
+ return tws_api_get_role();
+}
+
+u32 icsd_adt_get_tws_state()
+{
+ return tws_api_get_tws_state();
+}
+
+#define TWS_FUNC_ID_SDADT_M2S TWS_FUNC_ID('A', 'D', 'T', 'M')
+REGISTER_TWS_FUNC_STUB(icsd_adt_m2s) = {
+ .func_id = TWS_FUNC_ID_SDADT_M2S,
+ .func = icsd_adt_m2s_cb,
+};
+#define TWS_FUNC_ID_SDADT_S2M TWS_FUNC_ID('A', 'D', 'T', 'S')
+REGISTER_TWS_FUNC_STUB(icsd_adt_s2m) = {
+ .func_id = TWS_FUNC_ID_SDADT_S2M,
+ .func = icsd_adt_s2m_cb,
+};
+
+void icsd_adt_tws_m2s(u8 cmd)
+{
+ local_irq_disable();
+ s8 data[8];
+ icsd_adt_m2s_packet(data, cmd);
+ int ret = tws_api_send_data_to_sibling(data, 8, TWS_FUNC_ID_SDADT_M2S);
+ local_irq_enable();
+}
+
+void icsd_adt_tws_s2m(u8 cmd)
+{
+ local_irq_disable();
+ s8 data[8];
+ icsd_adt_s2m_packet(data, cmd);
+ int ret = tws_api_send_data_to_sibling(data, 8, TWS_FUNC_ID_SDADT_S2M);
+ local_irq_enable();
+}
+
+void icsd_adt_anc_dma_on(u8 out_sel, int *buf, int len)
+{
+ anc_dma_on_double(out_sel, buf, len);
+}
+
+void icsd_adt_dma_done()
+{
+ icsd_acoustic_detector_ancdma_done();
+}
+
+void icsd_adt_hw_suspend()
+{
+ anc_core_dma_ie(0);
+ anc_core_dma_stop();
+}
+
+void icsd_adt_hw_resume()
+{
+ audio_acoustic_detector_updata();
+ icsd_adt_szout_init();
+}
+
+void icsd_adt_FFT_radix256(int *in_cur, int *out)
+{
+ u32 fft_config;
+ fft_config = hw_fft_config(256, 8, 1, 0, 1);
+ hw_fft_run(fft_config, in_cur, out);
+}
+
+void icsd_adt_FFT_radix128(int *in_cur, int *out)
+{
+ u32 fft_config;
+ fft_config = hw_fft_config(128, 7, 1, 0, 1);
+ hw_fft_run(fft_config, in_cur, out);
+}
+
+void icsd_adt_FFT_radix64(int *in_cur, int *out)
+{
+ u32 fft_config;
+ fft_config = hw_fft_config(64, 6, 1, 0, 1);
+ hw_fft_run(fft_config, in_cur, out);
+}
+
+void icsd_post_anctask_msg(u8 cmd)
+{
+ audio_anc_post_msg_adt(cmd);
+}
+
+void icsd_post_adttask_msg(u8 cmd)
+{
+ if (adt_task == 1) {
+ os_taskq_post_msg("icsd_adt", 1, cmd);
+ }
+}
+
+void icsd_post_srctask_msg(u8 cmd)
+{
+ if (src_task == 1) {
+ os_taskq_post_msg("icsd_src", 1, cmd);
+ }
+}
+
+void icsd_adt_task(void *priv)
+{
+ int res = 0;
+ int msg[30];
+ while (1) {
+ res = os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
+ if (res == OS_TASKQ) {
+ icsd_adt_task_handler(msg[1]);
+ }
+ }
+}
+
+void icsd_adt_task_create()
+{
+ if (adt_task == 0) {
+ task_create(icsd_adt_task, NULL, ICSD_ADT_TASK_NAME);
+ adt_task = 1;
+ }
+}
+
+void icsd_adt_task_kill()
+{
+ if (adt_task == 1) {
+ task_kill(ICSD_ADT_TASK_NAME);
+ adt_task = 0;
+ }
+}
+
+void icsd_src_task(void *priv)
+{
+ int res = 0;
+ int msg[30];
+ while (1) {
+ res = os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
+ if (res == OS_TASKQ) {
+ icsd_src_task_handler(msg[1]);
+ }
+ }
+}
+
+void icsd_src_task_create()
+{
+ if (src_task == 0) {
+ task_create(icsd_src_task, NULL, "icsd_src");
+ src_task = 1;
+ }
+}
+
+void icsd_src_task_kill()
+{
+ if (src_task == 1) {
+ task_kill("icsd_src");
+ src_task = 0;
+ }
+}
+
+void icsd_adt_start()
+{
+ adt_printf = _adt_printf;
+ wat_printf = _wat_printf;
+ ein_printf = _ein_printf;
+ printf("icsd_adt_start====================================\n");
+}
+
+void icsd_adt_szout_init()
+{
+#if ADT_USE_ADAPTIVE_SZ
+ extern float icsd_anc_sz_data[120 + 40];
+ extern float icsd_anc_pz_data[120 + 40];
+ extern u8 sz_out_exist;//需要打开自适应ANC库中的 自适应SZ输出使能:ANC_SZ_OUT_EN
+ icsd_adt_szout_set(icsd_anc_sz_data, icsd_anc_pz_data, sz_out_exist);
+#else
+ icsd_adt_szout_set(0, 0, 0);
+#endif
+}
+const u16 ADT_DEBUG_INF = 0;//ADT_INF_1;//state
+//state = 1, pwr = 7, dov = 8, angle_err = 7, angle_tlk = 3
+const u8 adt_errpxx_dB_thr = 80;//60;
+const u8 adt_err_zcv_thr = 10;//12;
+const u8 pwr_inside_even_flag0_thr = 5; //pwr
+const u8 angle_err_even_flag0_thr = 3;//4; //angle_err
+const u8 angle_talk_even_flag0_thr = 2; //angle_tlk
+const u16 f1f2_angsum_thr = 200;
+#ifndef ADT_CLIENT_BOARD
+const u8 final_speech_even_thr = 4; //dov
+
+
+const u8 ADT_TWS_MODE = 1;
+const u8 ADT_DET_VER = 6;
+const u8 ADT_PATH_CONFIG = ADT_PATH_DAC_SRC_EN | ADT_PATH_3M_EN;
+const u8 ADT_EIN_VER = ADT_EIN_TWS_V0;
+const float ref_gain_sel = 3;
+const float err_gain_sel = 3;
+u8 pnc_ref_pwr_thr = 160;
+u8 pnc_err_pwr_thr = 100;
+u8 tpc_ref_pwr_thr = 120;
+u8 tpc_err_pwr_thr = 100;
+u8 anc_ref_pwr_thr = 120;
+u8 anc_err_pwr_thr = 100;
+
+const float wat_pn_gain = 0.22;
+const float wat_bypass_gain = 16;
+const float wat_anc_gain = 0.22;
+
+const float wdac_senc = 0.7; //越小播音乐时灵敏度越高
+const float wdac[8] = { 0.35, 0.54, 0.57, 0.48, 0.37, 0.22, 0.38, 0.37};//播放音乐/100
+const float wref[8] = {1.62, 0.90, 0.71, 0.60, 0.54, 0.50, 0.47, 0.46};//播放外部噪声
+const float wref_tran[8] = {1.82, 1.80, 1.58, 1.30, 1.16, 1.12, 1.11, 1.12};
+const float wref_ancs[8] = {1.92, 0.48, 0.07, 0.03, 0.05, 0.06, 0.06, 0.04 };
+const float fdac[8] = {0.18, 0.051, 0.02, 0.02, 0.02, 0.02, 0.02, 0.05};//播放音乐/1000
+u8 icsd_get_ang_flag(float *_target_angle)
+{
+ u8 af1 = _target_angle[1] > 15 || _target_angle[1] < -130;
+ u8 af2 = _target_angle[2] > 15 || _target_angle[2] < -130;
+ u8 af3 = _target_angle[3] > 15 || _target_angle[3] < -130;
+ u8 ang_flag = af1 && af2 && af3;
+ /* printf("get ang flag:%d\n", ang_flag); */
+ return ang_flag;
+}
+
+void icsd_adt_ein_parm_HT03(__icsd_adt_parm *_ADT_PARM)
+{
+ _ADT_PARM->anc_in_pz_sum = -80;
+ _ADT_PARM->anc_out_pz_sum = 0;
+ _ADT_PARM->anc_in_sz_mean = 1;
+ _ADT_PARM->anc_out_sz_mean = -12;
+ _ADT_PARM->anc_in_fb_sum = 60;
+ _ADT_PARM->anc_out_fb_sum = 30;
+
+ _ADT_PARM->pnc_in_pz_sum = -80;
+ _ADT_PARM->pnc_out_pz_sum = 0;
+ _ADT_PARM->pnc_in_sz_mean = 1;
+ _ADT_PARM->pnc_out_sz_mean = -12;
+ _ADT_PARM->pnc_in_fb_sum = 60;
+ _ADT_PARM->pnc_out_fb_sum = 30;
+
+ _ADT_PARM->trans_in_pz_sum = 2;
+ _ADT_PARM->trans_out_pz_sum = 26;
+ _ADT_PARM->trans_in_sz_mean = 2;
+ _ADT_PARM->trans_out_sz_mean = -7;
+ _ADT_PARM->trans_in_fb_sum = 20;
+ _ADT_PARM->trans_out_fb_sum = -20;
+}
+
+void icsd_adt_voice_board_data()
+{
+ __icsd_adt_parm *ADT_PARM;
+ ADT_PARM = zalloc(sizeof(__icsd_adt_parm));
+
+ extern const float HT03_ADT_FLOAT_DATA[];
+ extern const float HT03_sz_out_data[28];
+ extern const float HT03_pz_out_data[28];
+ ADT_PARM->adt_float_data = (void *)HT03_ADT_FLOAT_DATA;
+ ADT_PARM->sz_inptr = (float *)HT03_sz_out_data;
+ ADT_PARM->pz_inptr = (float *)HT03_pz_out_data;
+ icsd_adt_ein_parm_HT03(ADT_PARM);
+
+ icsd_adt_parm_set(ADT_PARM);
+ free(ADT_PARM);
+
+ icsd_adt_szout_init();
+}
+#else
+
+#include "icsd_adt_client_board.c"
+
+#endif/*ADC_CLIENT_BOARD*/
+
+
+//=======================================================================================================
+
+#if ADT_DATA_DEBUG
+
+void icsd_play_num0()
+{
+ icsd_adt_tone_play(ICSD_ADT_TONE_NUM0);
+}
+void icsd_play_num1()
+{
+ icsd_adt_tone_play(ICSD_ADT_TONE_NUM1);
+}
+void icsd_play_num2()
+{
+ icsd_adt_tone_play(ICSD_ADT_TONE_NUM2);
+}
+void icsd_play_num3()
+{
+ icsd_adt_tone_play(ICSD_ADT_TONE_NUM3);
+}
+void icsd_play_normal()
+{
+ icsd_adt_tone_play(ICSD_ADT_TONE_NORMAL);
+}
+
+void icsd_adt_output_demo(__adt_result *adt_result)
+{
+#if ADT_EAR_IN_EN
+ static u8 hold = 0;
+ static u8 hold_flg = 0;
+ static int hold_time = 0;
+ if (adt_result->ein_state == 0) {
+ hold = 1;
+ hold_flg = 1;
+ hold_time = 0;
+ printf("------------------------------------------------------------------ein state:0\n");
+ } else {
+ if (hold_flg) {
+ hold_flg = 0;
+ hold_time = jiffies;
+ printf("set hold time:%d\n", hold_time);
+ }
+ if ((hold_time > 0) && (hold)) {
+ if (jiffies > (hold_time + 100)) {
+ printf("hold time out:%d\n", jiffies);
+ hold = 0;
+ }
+ }
+ printf("--------------------------------ein state:1\n");
+ }
+ if (hold) {
+ //return;
+ }
+#endif
+
+ if (adt_result->wind_lvl) {
+ printf("------wind lvl:%d\n", adt_result->wind_lvl);
+ }
+ if (adt_result->voice_state) {
+ icsd_play_normal();
+ }
+ switch (adt_result->wat_result) {
+ case 2:
+ icsd_play_num2();
+ break;
+ case 3:
+ icsd_play_num3();
+ break;
+ default:
+ break;
+ }
+}
+#endif /*ADT_DATA_DEBUG*/
+
+#endif /*(defined TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN) && TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
+
diff --git a/apps/common/icsd/adt/icsd_adt.h b/apps/common/icsd/adt/icsd_adt.h
new file mode 100644
index 0000000..1111e38
--- /dev/null
+++ b/apps/common/icsd/adt/icsd_adt.h
@@ -0,0 +1,306 @@
+#ifndef _ICSD_ADT_H
+#define _ICSD_ADT_H
+
+#include "generic/typedef.h"
+#include "os/os_type.h"
+#include "os/os_api.h"
+#include "classic/tws_api.h"
+#include "math.h"
+
+#if 0
+#define _adt_printf printf //打开智能免摘库打印信息
+#else
+extern int printf_off(const char *format, ...);
+#define _adt_printf printf_off
+#endif/*log_en*/
+
+#if 0
+#define _wat_printf printf //打开广域点击库打印信息
+#else
+extern int printf_off(const char *format, ...);
+#define _wat_printf printf_off
+#endif/*log_en*/
+
+#if 0
+#define _wind_printf printf //打开风噪检测库打印信息
+#else
+extern int printf_off(const char *format, ...);
+#define _wind_printf printf_off
+#endif/*log_en*/
+
+#if 0
+#define _ein_printf printf //打开入耳检测库打印信息
+#else
+extern int printf_off(const char *format, ...);
+#define _ein_printf printf_off
+#endif/*log_en*/
+
+#define ADT_CALIBRATION_EN 0
+#define ADT_USE_ADAPTIVE_SZ 0//使用自适应SZ
+#define ADT_EAR_IN_EN 0
+
+#define ADT_VDT_EN BIT(0) //智能免摘
+#define ADT_WDT_EN BIT(1) //风噪检测
+#define ADT_WAT_EN BIT(2) //广域点击
+#define ADT_EIN_EN BIT(3) //入耳检测
+
+#define ADT_PATH_VDT_ANCL_ON BIT(0) //智能免摘使用ancl通路数据
+#define ADT_PATH_WAT_EMIC_ON BIT(1) //广域点击使用errmic数据通路
+#define ADT_PATH_VAD_ON BIT(2) //通过VAD检测降低功耗
+#define ADT_PATH_DAC_SRC_EN BIT(3)
+#define ADT_PATH_3M_EN BIT(4)
+
+
+#define ADT_INF_1 BIT(0)
+#define ADT_INF_2 BIT(1)
+#define ADT_INF_3 BIT(2)
+
+extern const u8 ADT_PATH_CONFIG;
+#define ICSD_TWS_STA_SIBLING_CONNECTED TWS_STA_SIBLING_CONNECTED//tws已连接
+
+typedef struct {
+ u8 voice_state;
+ u8 wind_lvl;
+ u8 wat_result;
+ u8 ein_state;
+} __adt_result;
+
+struct icsd_acoustic_detector_infmt {
+ u16 sample_rate; //当前播放采样率
+ u8 ff_gain;
+ u8 fb_gain;
+ u8 adt_mode; // TWS: 0 HEADSET: 1
+ u8 dac_mode; //低压0 高压1
+ u8 mic0_type; // MIC0 类型
+ u8 mic1_type; // MIC1 类型
+ u8 mic2_type; // MIC2 类型
+ u8 mic3_type; // MIC3 类型
+ u8 sensitivity; //智能免摘灵敏度设置
+ void *lfb_coeff;
+ void *lff_coeff;
+ void *ltrans_coeff;
+ void *ltransfb_coeff;
+ float gains_l_fbgain;
+ float gains_l_ffgain;
+ float gains_l_transgain;
+ float gains_l_transfbgain;
+ u8 gain_sign;
+ u8 lfb_yorder;
+ u8 lff_yorder;
+ u8 ltrans_yorder;
+ u8 ltransfb_yorder;
+ u32 trans_alogm;
+ u32 alogm;
+
+ void *alloc_ptr; //外部申请的ram地址
+ /*
+ 算法结果输出
+ voice_state: 0 无讲话; 1 有讲话
+ wind_lvl: 0-70 风噪等级
+ */
+ void (*output_hdl)(u8 voice_state, u8 wind_lvl); //算法结果输出
+ void (*anc_dma_post_msg)(void); //ANC task dma 抄数回调接口
+ void (*anc_dma_output_callback); //ANC DMA下采样数据输出回调,用于写卡分析
+};
+
+struct icsd_acoustic_detector_libfmt {
+ int adc_isr_len; //ADC中断长度
+ int adc_sr; //ADC 采样率
+ int lib_alloc_size; //算法ram需求大小
+ u8 mic_num; //需要打开的mic个数
+};
+
+enum {
+ ICSD_ANC_LFF_MIC = 0,
+ ICSD_ANC_LFB_MIC = 1,
+ ICSD_ANC_RFF_MIC = 2,
+ ICSD_ANC_RFB_MIC = 3,
+ ICSD_ANC_TALK_MIC = 4,
+ ICSD_ANC_MIC_NULL = 0XFF, //对应的MIC没有数值,则表示这个MIC没有开启
+};
+
+typedef struct {
+ void *adt_float_data;
+ float *sz_inptr;
+ float *pz_inptr;
+ s16 anc_in_pz_sum;
+ s16 anc_in_sz_mean;
+ s16 anc_in_fb_sum;
+ s16 anc_out_pz_sum;
+ s16 anc_out_sz_mean;
+ s16 anc_out_fb_sum;
+
+ s16 pnc_in_pz_sum;
+ s16 pnc_in_sz_mean;
+ s16 pnc_in_fb_sum;
+ s16 pnc_out_pz_sum;
+ s16 pnc_out_sz_mean;
+ s16 pnc_out_fb_sum;
+
+ s16 trans_in_pz_sum;
+ s16 trans_in_sz_mean;
+ s16 trans_in_fb_sum;
+ s16 trans_out_pz_sum;
+ s16 trans_out_sz_mean;
+ s16 trans_out_fb_sum;
+} __icsd_adt_parm;
+
+enum {
+ RESUME_ANCMODE = 0,
+ RESUME_BYPASSMODE,
+};
+enum {
+ ADT_DACMODE_LOW = 0,
+ ADT_DACMODE_HIGH,
+};
+enum {
+ ADT_TWS = 0,
+ ADT_HEADSET,
+};
+enum {
+ ADT_ANC_ON = 0,
+ ADT_ANC_OFF,
+};
+enum {
+ ADT_VOICE_WIND_MODE = 0, //智能免摘 + 风噪
+ ADT_WAT_MODE, //广域点击
+ ADT_VW_WAT_MODE, //智能免摘 + 风噪检测 + 广域点击
+};
+enum {
+ ADT_EIN_UNSUPPORT = 0,
+ ADT_EIN_TWS_V0,
+ ADT_EIN_HEADSET_V0,
+};
+
+extern const float wat_pn_gain;
+extern const float wat_anc_gain;
+extern const float wat_bypass_gain;
+extern const u8 final_speech_even_thr;
+extern const u8 VDT_TRAIN_EN;
+extern const float ref_gain_sel;
+extern const float err_gain_sel;
+extern u8 pnc_ref_pwr_thr;
+extern u8 pnc_err_pwr_thr;
+extern u8 tpc_ref_pwr_thr;
+extern u8 tpc_err_pwr_thr;
+extern u8 anc_ref_pwr_thr;
+extern u8 anc_err_pwr_thr;
+extern const float wref[8];
+extern const float wref_tran[8];
+extern const float wref_ancs[8];
+extern const float wdac_senc;
+extern const float wdac[8];
+extern const float fdac[8];
+extern const u8 ADT_DET_VER;
+extern const u8 ADT_TWS_MODE;
+extern const u8 ADT_EIN_VER;
+extern float anc_trans_lfb_gain;
+extern float anc_trans_rfb_gain;
+extern const double anc_trans_lfb_coeff[];
+extern const double anc_trans_rfb_coeff[];
+
+extern int (*adt_printf)(const char *format, ...);
+extern int (*wat_printf)(const char *format, ...);
+extern int (*ein_printf)(const char *format, ...);
+
+extern void icsd_adt_tws_m2s(u8 cmd);
+extern void icsd_adt_tws_s2m(u8 cmd);
+//LIB调用的算术函数
+extern float sin_float(float x);
+extern float cos_float(float x);
+extern float cos_hq(float x);
+extern float sin_hq(float x);
+extern float log10_float(float x);
+extern float exp_float(float x);
+extern float root_float(float x);
+//extern float pow10(float n);
+extern float adt_pow10(float n);
+extern float angle_float(float x, float y);
+//ADT调用的APP函数
+
+extern int audio_dac_read_anc_reset(void);
+extern int audio_acoustic_detector_updata();
+extern void tws_tx_unsniff_req(void);
+extern int tws_api_get_role(void);
+extern int tws_api_get_tws_state();
+extern u8 anc_dma_done_ppflag();
+extern void anc_core_dma_ie(u8 en);
+extern void anc_core_dma_stop(void);
+extern int os_task_create(void (*task_func)(void *p_arg), void *p_arg, u8 prio, u32 stksize, int qsize, const char *name);
+extern int os_task_del(const char *name);
+extern int os_taskq_post_msg(const char *name, int argc, ...);
+extern int os_taskq_pend(const char *fmt, int *argv, int argc);
+extern void anc_dma_on_double(u8 out_sel, int *buf, int len);
+extern int audio_resample_hw_push_data_out(void *resample);
+extern void audio_resample_hw_close(void *resample);
+extern void *audio_resample_hw_open(u8 channel, int in_rate, int out_rate, u8 type);
+extern int audio_resample_hw_set_output_handler(void *resample, void *priv, int (*handler)(void *, void *, int));
+extern int audio_resample_hw_write(void *resample, void *data, int len);
+extern void audio_anc_post_msg_adt(u8 cmd);
+extern void hw_fft_run(unsigned int fft_config, const int *in, int *out);
+extern unsigned int hw_fft_config(int N, int log2N, int is_same_addr, int is_ifft, int is_real);
+//APP调用的ADT函数
+extern void icsd_adt_start();
+extern void icsd_adt_anctask_handle(u8 cmd);
+//APP调用的LIB函数
+extern void icsd_acoustic_detector_get_libfmt(struct icsd_acoustic_detector_libfmt *libfmt, u8 function);
+extern void icsd_acoustic_detector_set_infmt(struct icsd_acoustic_detector_infmt *fmt);
+extern void icsd_acoustic_detector_infmt_updata(struct icsd_acoustic_detector_infmt *fmt);
+extern void icsd_acoustic_detector_open(void);
+extern void icsd_acoustic_detector_close();
+extern void icsd_acoustic_detector_resume(u8 mode, u8 anc_onoff);
+extern void icsd_acoustic_detector_suspend();
+extern void icsd_acoustic_detector_ancdma_done();//ancdma done回调
+extern void icsd_acoustic_detector_mic_input_hdl(void *priv, s16 *buf, int len);
+extern void icsd_adt_set_audio_sample_rate(u16 sample_rate);
+//LIB调用的ADT函数
+extern void icsd_adt_FFT_radix256(int *in_cur, int *out);
+extern void icsd_adt_FFT_radix128(int *in_cur, int *out);
+extern void icsd_adt_FFT_radix64(int *in_cur, int *out);
+extern void icsd_adt_anc_dma_on(u8 out_sel, int *buf, int len);
+extern void icsd_adt_hw_suspend();
+extern void icsd_adt_hw_resume();
+extern void icsd_post_adttask_msg(u8 cmd);
+extern void icsd_post_srctask_msg(u8 cmd);
+extern void icsd_adt_src_close(void *resample);
+extern void *icsd_adt_src_init(int in_rate, int out_rate, int (*handler)(void *, void *, int));
+extern void icsd_adt_src_push(void *resample);
+extern void icsd_adt_src_write(void *data, int len, void *resample);
+extern void icsd_adt_run_output(__adt_result *adt_result);
+extern void icsd_post_anctask_msg(u8 cmd);
+extern void icsd_adt_voice_board_data();
+extern void icsd_adt_tx_unsniff_req();
+extern u32 icsd_adt_get_tws_state();
+extern u32 icsd_adt_get_role();
+extern u8 icsd_get_ang_flag(float *_target_angle);
+//ADT调用的LIB函数
+extern void icsd_adt_version();
+extern void icsd_adt_parm_set(__icsd_adt_parm *_ADT_PARM);
+extern void icsd_adt_szout_set(float *anc_sz_data, float *anc_pz_data, u8 sz_out_exist);
+extern void icsd_adt_task_handler(int msg);
+extern void icsd_src_task_handler(int msg);
+extern void icsd_adt_s2m_packet(s8 *data, u8 cmd);
+extern void icsd_adt_m2s_packet(s8 *data, u8 cmd);
+
+extern void icsd_adt_szout_init();
+extern void icsd_adt_dma_done();
+extern void icsd_adt_task_create();
+extern void icsd_adt_task_kill();
+extern void icsd_src_task_create();
+extern void icsd_src_task_kill();
+extern void icsd_adt_m2s_cb(void *_data, u16 len, bool rx);
+extern void icsd_adt_s2m_cb(void *_data, u16 len, bool rx);
+
+extern u8 audio_adt_talk_mic_analog_close();
+extern u8 audio_adt_talk_mic_analog_open();
+extern u8 talk_mic_analog_close;
+
+extern u8 oral_function;
+extern const u8 adt_errpxx_dB_thr;
+extern const u8 adt_err_zcv_thr;
+extern const u8 pwr_inside_even_flag0_thr;
+extern const u8 angle_err_even_flag0_thr;
+extern const u8 angle_talk_even_flag0_thr;
+extern const u16 f1f2_angsum_thr;
+extern const u16 ADT_DEBUG_INF;
+#endif
diff --git a/apps/common/icsd/adt/icsd_adt_app.c b/apps/common/icsd/adt/icsd_adt_app.c
new file mode 100644
index 0000000..707c106
--- /dev/null
+++ b/apps/common/icsd/adt/icsd_adt_app.c
@@ -0,0 +1,1955 @@
+/*
+ ****************************************************************************
+ * ICSD ADT APP API
+ *
+ *Description : 智能免摘和anc风噪检测相关接口
+ *Notes :
+ ****************************************************************************
+ */
+#include "app_config.h"
+#if ((defined TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN) && TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN && \
+ TCFG_AUDIO_ANC_ENABLE)
+#include "system/includes.h"
+#include "icsd_adt_app.h"
+#include "icsd_adt.h"
+#include "system/task.h"
+#include "asm/audio_adc.h"
+#include "audio_anc.h"
+#include "timer.h"
+#include "icsd_anc.h"
+#include "btstack/avctp_user.h"
+#include "bt_tws.h"
+#include "tone_player.h"
+#include "asm/anc.h"
+#include "app_anctool.h"
+#include "audio_config.h"
+#include "icsd_anc_user.h"
+
+#if ICSD_ADT_WIND_INFO_SPP_DEBUG_EN
+#include "spp_user.h"
+#endif
+
+extern struct audio_dac_hdl dac_hdl;
+
+struct speak_to_chat_t {
+ volatile u8 busy;
+ volatile u8 state;
+ struct icsd_acoustic_detector_libfmt libfmt;//回去需要的资源
+ struct icsd_acoustic_detector_infmt infmt;//转递资源
+ void *lib_alloc_ptr;//adt申请的内存指针
+ u32 timer;//免摘结束定时齐
+ u8 sensitivity;
+ u8 voice_state;//免摘检测到声音的状态
+ u8 adt_resume;//resume的状态
+ u8 adt_suspend;//suspend的状态
+ u8 adt_resume_timer;//resume定时器
+ u8 wind_lvl;//记录风强信息
+ u8 a2dp_state;//触发免摘时是否播歌的状态
+ u8 speak_to_chat_state;//智能免摘的状态
+ u8 last_anc_state;//记录触发免摘前的anc模式
+ u8 anc_switch_flag;//是否是内部免摘触发的anc模式切换
+ u8 tws_sync_state;//是否已经接收到同步的信息
+ u8 adt_wind_lvl;//风噪等级
+ u8 adt_tmp_wind_lvl;//风噪等级
+ u8 adt_wat_result;//广域点击次数
+ u8 adt_param_updata;//是否在resume前更新参数
+ u8 adt_wat_ignore_flag;//是否忽略广域点击的响应
+#if ICSD_ADT_WIND_INFO_SPP_DEBUG_EN
+ struct spp_operation_t *spp_opt;
+ u8 spp_connected_state;
+#endif
+ u32 wind_cnt;
+ int sample_rate;
+};
+struct speak_to_chat_t *speak_to_chat_hdl = NULL;
+
+typedef struct {
+ u8 speak_to_chat_state;
+ u8 adt_mode;
+ u16 speak_to_chat_end_time; //免摘定时结束的时间,单位ms
+} adt_info_t;
+static adt_info_t adt_info = {
+ .speak_to_chat_state = AUDIO_ADT_CLOSE,
+ .adt_mode = ADT_MODE_CLOSE,
+ .speak_to_chat_end_time = 5000,
+};
+
+/*tws同步char状态使用*/
+static u8 globle_speak_to_chat_state = 0;
+/*用于判断先开anc off再开免摘*/
+static u8 adt_open_in_anc = 0;
+
+void audio_icsd_adt_info_sync(u8 *data, int len);
+void audio_icsd_adt_info_sync_cb(void *_data, u16 len, bool rx)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ u8 tmp_data[4];
+ int mode = ((u8 *)_data)[0];
+ int voice_state = 0;
+ int wind_lvl = 0;
+ int wat_result = 0;
+ int val = 0;
+ int err = 0;
+ int adt_mode = 0;
+ int anc_fade_gain = 0;
+ // printf("audio_icsd_adt_info_sync_cb rx:%d, mode:%d ", rx, mode);
+ switch (mode) {
+ case SYNC_ICSD_ADT_WIND_LVL_RESULT:
+ if (!hdl || !hdl->state) {
+ break;
+ }
+ hdl->busy = 1;
+ voice_state = ((u8 *)_data)[1];
+ wind_lvl = ((u8 *)_data)[2];
+ wat_result = ((u8 *)_data)[3];
+
+ err = os_taskq_post_msg(SPEAK_TO_CHAT_TASK_NAME, 2, ICSD_ADT_WIND_LVL, wind_lvl);
+
+#if TCFG_AUDIO_SPEAK_TO_CHAT_ENABLE
+ if ((adt_info.adt_mode & ADT_SPEAK_TO_CHAT_MODE) && voice_state) {
+ /* err = os_taskq_post_msg(SPEAK_TO_CHAT_TASK_NAME, 2, ICSD_ADT_VOICE_STATE, voice_state); */
+ set_speak_to_chat_voice_state(1);
+ }
+#endif /*TCFG_AUDIO_SPEAK_TO_CHAT_ENABLE*/
+
+#if TCFG_AUDIO_WIDE_AREA_TAP_ENABLE
+#if (TCFG_USER_TWS_ENABLE && !AUDIO_ANC_WIDE_AREA_TAP_EVENT_SYNC)
+ /*广域点击:是否响应另一只耳机的点击*/
+ if (!rx)
+#endif /*AUDIO_ANC_WIDE_AREA_TAP_EVENT_SYNC*/
+ {
+ if ((adt_info.adt_mode & ADT_WIDE_AREA_TAP_MODE) && wat_result && !hdl->adt_wat_ignore_flag) {
+ err = os_taskq_post_msg(SPEAK_TO_CHAT_TASK_NAME, 2, ICSD_ADT_WAT_RESULT, wat_result);
+ }
+ }
+#endif /*TCFG_AUDIO_WIDE_AREA_TAP_ENABLE*/
+ hdl->busy = 0;
+ break;
+ case SYNC_ICSD_ADT_VOICE_STATE:
+ case SYNC_ICSD_ADT_WIND_LVL_CMP:
+ case SYNC_ICSD_ADT_WAT_RESULT:
+ if (!hdl || !hdl->state) {
+ break;
+ }
+ hdl->busy = 1;
+ voice_state = ((u8 *)_data)[1];
+ wind_lvl = ((u8 *)_data)[2];
+ wat_result = ((u8 *)_data)[3];
+
+#if TCFG_AUDIO_ANC_WIND_NOISE_DET_ENABLE
+ if (adt_info.adt_mode & ADT_WIND_NOISE_DET_MODE) {
+ /*从机本地的风噪和接收到的主机风噪比较,取最大值*/
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ if (hdl->adt_tmp_wind_lvl < ((u8)wind_lvl)) {
+ hdl->adt_tmp_wind_lvl = (u8)wind_lvl;
+ }
+ /*比较完后从机同步最终的风噪信息*/
+ tmp_data[0] = SYNC_ICSD_ADT_WIND_LVL_RESULT;
+ tmp_data[1] = 0;
+ tmp_data[2] = hdl->adt_tmp_wind_lvl;
+ tmp_data[3] = 0;
+ audio_icsd_adt_info_sync(tmp_data, 4);
+ }
+ }
+#endif /*TCFG_AUDIO_ANC_WIND_NOISE_DET_ENABLE*/
+
+#if TCFG_AUDIO_SPEAK_TO_CHAT_ENABLE
+ if ((adt_info.adt_mode & ADT_SPEAK_TO_CHAT_MODE) && voice_state) {
+ /* err = os_taskq_post_msg(SPEAK_TO_CHAT_TASK_NAME, 2, ICSD_ADT_VOICE_STATE, voice_state); */
+ set_speak_to_chat_voice_state(1);
+ }
+#endif /*TCFG_AUDIO_SPEAK_TO_CHAT_ENABLE*/
+
+#if TCFG_AUDIO_WIDE_AREA_TAP_ENABLE
+#if (TCFG_USER_TWS_ENABLE && !AUDIO_ANC_WIDE_AREA_TAP_EVENT_SYNC)
+ /*广域点击:是否响应另一只耳机的点击*/
+ if (!rx)
+#endif /*AUDIO_ANC_WIDE_AREA_TAP_EVENT_SYNC*/
+ {
+ if ((adt_info.adt_mode & ADT_WIDE_AREA_TAP_MODE) && wat_result && !hdl->adt_wat_ignore_flag) {
+ err = os_taskq_post_msg(SPEAK_TO_CHAT_TASK_NAME, 2, ICSD_ADT_WAT_RESULT, wat_result);
+ }
+ }
+#endif /*TCFG_AUDIO_WIDE_AREA_TAP_ENABLE*/
+
+ hdl->busy = 0;
+ break;
+ case SYNC_ICSD_ADT_SUSPEND:
+ audio_speak_to_char_suspend();
+ break;
+ case SYNC_ICSD_ADT_OPEN:
+ case SYNC_ICSD_ADT_CLOSE:
+ adt_mode = ((u8 *)_data)[1];
+ err = os_taskq_post_msg(SPEAK_TO_CHAT_TASK_NAME, 2, mode, adt_mode);
+ break;
+ case SYNC_ICSD_ADT_SET_ANC_FADE_GAIN:
+ anc_fade_gain = (((u8 *)_data)[2] << 8) | ((u8 *)_data)[1];
+ err = os_taskq_post_msg(SPEAK_TO_CHAT_TASK_NAME, 2, mode, anc_fade_gain);
+ break;
+ default:
+ break;
+ }
+}
+
+#define TWS_FUNC_ID_ICSD_ADT_M2S TWS_FUNC_ID('I', 'A', 'M', 'S')
+REGISTER_TWS_FUNC_STUB(audio_icsd_adt_m2s) = {
+ .func_id = TWS_FUNC_ID_ICSD_ADT_M2S,
+ .func = audio_icsd_adt_info_sync_cb,
+};
+
+void audio_icsd_adt_info_sync(u8 *data, int len)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ /* printf("audio_icsd_adt_info_sync , %d, %d", data[0], data[1]); */
+#if TCFG_USER_TWS_ENABLE
+ if (get_tws_sibling_connect_state()) {
+ int ret = tws_api_send_data_to_sibling(data, len, TWS_FUNC_ID_ICSD_ADT_M2S);
+ } else
+#endif
+ {
+ audio_icsd_adt_info_sync_cb(data, len, 0);
+ }
+}
+
+static void audio_mic_output_handle(void *priv, s16 *data, int len)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl && hdl->state) {
+ u8 esco_mic_num = audio_adc_file_get_esco_mic_num();
+ u8 adt_mic_num = get_icsd_adt_mic_num();
+ u8 mic_ch_num = esco_mic_num > adt_mic_num ? esco_mic_num : adt_mic_num;
+ /*adt使用3mic模式 或者 通话使用3mic时(adc固定开3个),如果免摘使用2mic,需要重新排列数据顺序*/
+ if (mic_ch_num > hdl->libfmt.mic_num) {
+ for (int i = 0; i < len / 2; i++) {
+ memcpy(&data[2 * i], &data[3 * i], 4);
+ }
+ }
+ icsd_acoustic_detector_mic_input_hdl(priv, data, len);
+ }
+}
+
+/*算法结果输出*
+ * voice_state : 是否有说话,0 无讲话,1 有讲话
+ * wind_lvl : 风噪等级,0 - 10
+ * wat_result : 连击次数,2 双击, 3 三击
+ */
+extern int tws_in_sniff_state();
+void audio_acoustic_detector_output_hdl(u8 voice_state, u8 wind_lvl, u8 wat_result)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ u8 data[4] = {SYNC_ICSD_ADT_WIND_LVL_CMP, voice_state, wind_lvl, wat_result};
+ static u8 cnt = 0;
+ u8 wind_lvl_target_cnt = 0;;
+
+ if (hdl && hdl->state) {
+ hdl->busy = 1;
+ /*限制少的判断放前面*/
+ if ((adt_info.adt_mode & ADT_WIDE_AREA_TAP_MODE) && wat_result && !hdl->adt_wat_ignore_flag) {
+#if TCFG_USER_TWS_ENABLE
+ if (tws_in_sniff_state()) {
+ /*如果在蓝牙siniff下需要退出蓝牙sniff再发送*/
+ icsd_adt_tx_unsniff_req();
+ }
+#endif
+ /*没有tws时直接更新状态*/
+ data[0] = SYNC_ICSD_ADT_WAT_RESULT;
+ audio_icsd_adt_info_sync(data, 4);
+ } else if ((adt_info.adt_mode & ADT_SPEAK_TO_CHAT_MODE) && voice_state) {
+#if TCFG_USER_TWS_ENABLE
+ if (tws_in_sniff_state() && (tws_api_get_role() == TWS_ROLE_MASTER)) {
+ /*如果在蓝牙siniff下需要退出蓝牙sniff再发送*/
+ icsd_adt_tx_unsniff_req();
+ }
+ if (get_tws_sibling_connect_state()) {
+ if ((tws_api_get_role() == TWS_ROLE_MASTER)) {
+ /*连接tws时,同步主机状态*/
+ data[0] = SYNC_ICSD_ADT_VOICE_STATE;
+ audio_icsd_adt_info_sync(data, 4);
+ }
+ } else
+#endif
+ {
+ /*没有tws时直接更新状态*/
+ data[0] = SYNC_ICSD_ADT_VOICE_STATE;
+ audio_icsd_adt_info_sync(data, 4);
+ }
+
+ } else if (adt_info.adt_mode & ADT_WIND_NOISE_DET_MODE) {
+ /*如果开了风噪检测,需要实时与对耳交流风噪信息*/
+#if TCFG_USER_TWS_ENABLE
+ if (tws_in_sniff_state()) {
+ /*蓝牙sniff下,间隔 发送一次*/
+ wind_lvl_target_cnt = 20;
+ } else
+#endif
+ {
+ /*非蓝牙sniff下,间隔 发送一次*/
+ wind_lvl_target_cnt = 2;
+ }
+ cnt ++;
+#if TCFG_USER_TWS_ENABLE
+ if (get_tws_sibling_connect_state()) {
+ /*记录本地的风噪强度*/
+ hdl->adt_tmp_wind_lvl = wind_lvl;
+ /*同步主机风噪和从机风噪比较*/
+ if ((tws_api_get_role() == TWS_ROLE_MASTER)) {
+ if (cnt > wind_lvl_target_cnt) {
+ /*间隔wind_lvl_target_cnt次发送一次*/
+ data[0] = SYNC_ICSD_ADT_WIND_LVL_CMP;
+ audio_icsd_adt_info_sync(data, 4);
+
+ cnt = 0;
+ }
+ }
+ } else
+#endif
+ {
+ /*没有tws时直接更新状态*/
+ hdl->adt_wind_lvl = wind_lvl;
+ if (cnt > wind_lvl_target_cnt) {
+ /*间隔wind_lvl_target_cnt次发送一次*/
+ data[0] = SYNC_ICSD_ADT_WIND_LVL_RESULT;
+ audio_icsd_adt_info_sync(data, 4);
+ cnt = 0;
+ }
+ }
+ }
+
+ hdl->busy = 0;
+ }
+}
+
+//ANC task dma 抄数回调接口
+void audio_acoustic_detector_anc_dma_post_msg(void)
+{
+
+}
+//ANC DMA下采样数据输出回调,用于写卡分析
+void audio_acoustic_detector_anc_dma_output_callback(void)
+{
+
+}
+
+void audio_icsd_adt_start()
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl->last_anc_state == ANC_ON) {
+ icsd_acoustic_detector_resume(RESUME_ANCMODE, ADT_ANC_ON);
+ } else if (hdl->last_anc_state == ANC_TRANSPARENCY) {
+ icsd_acoustic_detector_resume(RESUME_BYPASSMODE, ADT_ANC_OFF);
+ } else { /*if (hdl->last_anc_state == ANC_OFF)*/
+ icsd_acoustic_detector_resume(RESUME_ANCMODE, ADT_ANC_OFF);
+ }
+}
+
+void icsd_mic_ch_sel(struct icsd_acoustic_detector_infmt *infmt)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+
+ infmt->mic0_type = ICSD_ANC_MIC_NULL;
+ infmt->mic1_type = ICSD_ANC_MIC_NULL;
+ infmt->mic2_type = ICSD_ANC_MIC_NULL;
+ infmt->mic3_type = ICSD_ANC_MIC_NULL;
+ u8 talk_mic_ch = icsd_get_talk_mic_ch();
+ u8 ff_mic_ch = icsd_get_ref_mic_ch();
+ u8 fb_mic_ch = icsd_get_fb_mic_ch();
+
+ /*免摘使用3mic时,talk mic ch读取通话的配置,ff和fb使用anc的配置*/
+ if (hdl->libfmt.mic_num == 3) {
+ /*判断talk mic*/
+ switch (talk_mic_ch) {
+ case AUDIO_ADC_MIC_0:
+ infmt->mic0_type = ICSD_ANC_TALK_MIC;
+ break;
+ case AUDIO_ADC_MIC_1:
+ infmt->mic1_type = ICSD_ANC_TALK_MIC;
+ break;
+ case AUDIO_ADC_MIC_2:
+ infmt->mic2_type = ICSD_ANC_TALK_MIC;
+ break;
+ case AUDIO_ADC_MIC_3:
+ infmt->mic3_type = ICSD_ANC_TALK_MIC;
+ break;
+ }
+ }
+
+ /*无论tws还是头戴式立体声都是用左通道*/
+ /*判断ff mic*/
+ switch (ff_mic_ch) {
+ case AUDIO_ADC_MIC_0:
+ infmt->mic0_type = ICSD_ANC_LFF_MIC;
+ break;
+ case AUDIO_ADC_MIC_1:
+ infmt->mic1_type = ICSD_ANC_LFF_MIC;
+ break;
+ case AUDIO_ADC_MIC_2:
+ infmt->mic2_type = ICSD_ANC_LFF_MIC;
+ break;
+ case AUDIO_ADC_MIC_3:
+ infmt->mic3_type = ICSD_ANC_LFF_MIC;
+ break;
+ }
+
+ /*判断fb mic*/
+ switch (fb_mic_ch) {
+ case AUDIO_ADC_MIC_0:
+ infmt->mic0_type = ICSD_ANC_LFB_MIC;
+ break;
+ case AUDIO_ADC_MIC_1:
+ infmt->mic1_type = ICSD_ANC_LFB_MIC;
+ break;
+ case AUDIO_ADC_MIC_2:
+ infmt->mic2_type = ICSD_ANC_LFB_MIC;
+ break;
+ case AUDIO_ADC_MIC_3:
+ infmt->mic3_type = ICSD_ANC_LFB_MIC;
+ break;
+ }
+
+}
+
+void set_icsd_adt_param_updata()
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl && hdl->state) {
+ hdl->adt_param_updata = 1;
+ }
+}
+
+int audio_acoustic_detector_updata()
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl && hdl->state) {
+ hdl->busy = 1;
+ if (hdl->infmt.lfb_coeff) {
+ free(hdl->infmt.lfb_coeff);
+ hdl->infmt.lfb_coeff = NULL;
+ }
+ if (hdl->infmt.lff_coeff) {
+ free(hdl->infmt.lff_coeff);
+ hdl->infmt.lff_coeff = NULL;
+ }
+ if (hdl->infmt.ltrans_coeff) {
+ free(hdl->infmt.ltrans_coeff);
+ hdl->infmt.ltrans_coeff = NULL;
+ }
+ if (hdl->infmt.ltransfb_coeff) {
+ free(hdl->infmt.ltransfb_coeff);
+ hdl->infmt.ltransfb_coeff = NULL;
+ }
+ /*获取anc参数和增益*/
+ /*获取anc参数和增益*/
+ hdl->infmt.gains_l_fbgain = get_anc_gains_l_fbgain();
+ hdl->infmt.gains_l_ffgain = get_anc_gains_l_ffgain();
+ hdl->infmt.gains_l_transgain = get_anc_gains_l_transgain();
+ hdl->infmt.gains_l_transfbgain = get_anc_gains_lfb_transgain();
+ hdl->infmt.lfb_yorder = get_anc_l_fbyorder();
+ hdl->infmt.lff_yorder = get_anc_l_ffyorder();
+ hdl->infmt.ltrans_yorder = get_anc_l_transyorder();
+ hdl->infmt.ltransfb_yorder = get_anc_lfb_transyorder();
+ hdl->infmt.trans_alogm = get_anc_gains_trans_alogm();
+ hdl->infmt.alogm = get_anc_gains_alogm();
+
+ hdl->infmt.lfb_coeff = zalloc(hdl->infmt.lfb_yorder * 40);
+ hdl->infmt.lff_coeff = zalloc(hdl->infmt.lff_yorder * 40);;
+ hdl->infmt.ltrans_coeff = zalloc(hdl->infmt.ltrans_yorder * 40);;
+ hdl->infmt.ltransfb_coeff = zalloc(hdl->infmt.ltransfb_yorder * 40);;
+
+ memcpy(hdl->infmt.lfb_coeff, get_anc_lfb_coeff(), hdl->infmt.lfb_yorder * 40);
+ memcpy(hdl->infmt.lff_coeff, get_anc_lff_coeff(), hdl->infmt.lff_yorder * 40);
+ memcpy(hdl->infmt.ltrans_coeff, get_anc_ltrans_coeff(), hdl->infmt.ltrans_yorder * 40);
+ memcpy(hdl->infmt.ltransfb_coeff, get_anc_ltrans_fb_coeff(), hdl->infmt.ltransfb_yorder * 40);
+
+ extern u32 get_anc_gains_sign();
+ hdl->infmt.gain_sign = get_anc_gains_sign();
+
+ icsd_acoustic_detector_infmt_updata(&hdl->infmt);
+ hdl->busy = 0;
+ }
+
+ return 0;
+}
+
+#if ICSD_ADT_WIND_INFO_SPP_DEBUG_EN
+/*记录spp连接状态*/
+void icsd_adt_wind_spp_connect_state_cbk(u8 state)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl && hdl->state) {
+ hdl->spp_connected_state = state;
+ }
+}
+#endif
+
+/*设置talk mic gain和ff mic gain一样*/
+void audio_icsd_adt_set_talk_mic_gain(audio_mic_param_t *mic_param)
+{
+ u8 talk_mic_ch = icsd_get_talk_mic_ch();
+ u16 talk_mic_gain = audio_anc_ffmic_gain_get();
+ printf("talk_mic_ch %d, gain %d", talk_mic_ch, talk_mic_gain);
+ switch (talk_mic_ch) {
+ case AUDIO_ADC_MIC_0:
+ mic_param->mic0_gain = talk_mic_gain;
+ break;
+ case AUDIO_ADC_MIC_1:
+ mic_param->mic1_gain = talk_mic_gain;
+ break;
+ case AUDIO_ADC_MIC_2:
+ mic_param->mic2_gain = talk_mic_gain;
+ break;
+ case AUDIO_ADC_MIC_3:
+ mic_param->mic3_gain = talk_mic_gain;
+ break;
+ }
+}
+
+void audio_icsd_adt_set_sample(int sample_rate)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl) {
+ printf("%s:%d", __func__, __LINE__);
+ if (hdl->sample_rate != sample_rate) {
+ icsd_adt_set_audio_sample_rate(sample_rate);
+ }
+ hdl->sample_rate = sample_rate;
+ }
+}
+
+/*获取免摘需要多少个mic*/
+u8 get_icsd_adt_mic_num()
+{
+ u8 mic_num = 2;
+ extern const u8 ADT_PATH_CONFIG;
+ if (ADT_PATH_CONFIG & ADT_PATH_3M_EN) {
+ mic_num = 3;
+ }
+ return mic_num;
+}
+
+/*打开智能免摘检测*/
+int audio_acoustic_detector_open()
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl == NULL) {
+ return -1;
+ }
+
+ /*修改了sniff的唤醒间隔*/
+ icsd_set_tws_t_sniff(160);
+ icsd_adt_version();
+ u8 adt_function = 0;
+ if (adt_info.adt_mode == ADT_WIDE_AREA_TAP_MODE) {
+ /*只开广域点击*/
+ //adt_function = ADT_WAT_MODE;
+ adt_function |= ADT_WAT_EN;
+ } else if (adt_info.adt_mode & ADT_WIDE_AREA_TAP_MODE) {
+ /*同时开了广域点击 和 智能免摘/风噪检测*/
+ //adt_function = ADT_VW_WAT_MODE;
+ adt_function |= ADT_WAT_EN;
+ adt_function |= ADT_VDT_EN;
+ adt_function |= ADT_WDT_EN;
+ } else {
+ /*只开了智能免摘/风噪检测*/
+ //adt_function = ADT_VOICE_WIND_MODE;
+ adt_function |= ADT_VDT_EN;
+ adt_function |= ADT_WDT_EN;
+ }
+ if (ADT_EAR_IN_EN) {
+ adt_function |= ADT_EIN_EN;
+ }
+
+ audio_dac_set_samplerate_callback_add(&dac_hdl, audio_icsd_adt_set_sample);
+
+ icsd_acoustic_detector_get_libfmt(&hdl->libfmt, adt_function);
+
+#if ICSD_ADT_WIND_INFO_SPP_DEBUG_EN
+ /*获取spp发送句柄*/
+ if (adt_info.adt_mode & ADT_WIND_NOISE_DET_MODE) {
+ spp_get_operation_table(&hdl->spp_opt);
+ if (hdl->spp_opt) {
+ /*设置记录spp连接状态回调*/
+ hdl->spp_opt->regist_state_cbk(hdl, icsd_adt_wind_spp_connect_state_cbk);
+ }
+ }
+#endif
+
+ printf("mode : %x, adc_len : %d, sr : %d, size : %d", adt_function, hdl->libfmt.adc_isr_len, hdl->libfmt.adc_sr, hdl->libfmt.lib_alloc_size);
+ if (hdl->libfmt.lib_alloc_size) {
+ hdl->lib_alloc_ptr = zalloc(hdl->libfmt.lib_alloc_size);
+ } else {
+ return -1;;
+ }
+ if (hdl->lib_alloc_ptr == NULL) {
+ printf("hdl->lib_alloc_ptr malloc fail !!!");
+ return -1;
+ }
+
+ /*配置TWS还是头戴式耳机*/
+#if TCFG_USER_TWS_ENABLE
+ hdl->infmt.adt_mode = ADT_TWS;
+#else
+ hdl->infmt.adt_mode = ADT_HEADSET;
+#endif /*TCFG_USER_TWS_ENABLE*/
+
+ /*配置mic通道*/
+ icsd_mic_ch_sel(&hdl->infmt);
+ /* hdl->infmt.mic0_type = ICSD_ANC_MIC_NULL; */
+ /* hdl->infmt.mic1_type = ICSD_ANC_LFF_MIC; */
+ /* hdl->infmt.mic2_type = ICSD_ANC_LFB_MIC; */
+ /* hdl->infmt.mic3_type = ICSD_ANC_MIC_NULL; */
+ printf("mic0_type: %d, mic1_type: %d, mic2_type: %d, mic3_type: %d", hdl->infmt.mic0_type, hdl->infmt.mic1_type, hdl->infmt.mic2_type, hdl->infmt.mic3_type);
+ /*检测灵敏度
+ * 0 : 正常灵敏度
+ * 1 : 智能灵敏度*/
+ hdl->infmt.sensitivity = 0;
+ /*配置低压/高压DAC*/
+#if ((TCFG_AUDIO_DAC_MODE == DAC_MODE_L_DIFF) || (TCFG_AUDIO_DAC_MODE == DAC_MODE_L_SINGLE))
+ hdl->infmt.dac_mode = ADT_DACMODE_LOW;
+#else
+ hdl->infmt.dac_mode = ADT_DACMODE_HIGH;
+#endif /*TCFG_AUDIO_DAC_MODE*/
+ /*获取anc参数和增益*/
+ hdl->infmt.gains_l_fbgain = get_anc_gains_l_fbgain();
+ hdl->infmt.gains_l_ffgain = get_anc_gains_l_ffgain();
+ hdl->infmt.gains_l_transgain = get_anc_gains_l_transgain();
+ hdl->infmt.gains_l_transfbgain = get_anc_gains_lfb_transgain();
+ hdl->infmt.lfb_yorder = get_anc_l_fbyorder();
+ hdl->infmt.lff_yorder = get_anc_l_ffyorder();
+ hdl->infmt.ltrans_yorder = get_anc_l_transyorder();
+ hdl->infmt.ltransfb_yorder = get_anc_lfb_transyorder();
+ hdl->infmt.trans_alogm = get_anc_gains_trans_alogm();
+ hdl->infmt.alogm = get_anc_gains_alogm();
+
+ hdl->infmt.lfb_coeff = zalloc(hdl->infmt.lfb_yorder * 40);
+ hdl->infmt.lff_coeff = zalloc(hdl->infmt.lff_yorder * 40);;
+ hdl->infmt.ltrans_coeff = zalloc(hdl->infmt.ltrans_yorder * 40);;
+ hdl->infmt.ltransfb_coeff = zalloc(hdl->infmt.ltransfb_yorder * 40);;
+
+ memcpy(hdl->infmt.lfb_coeff, get_anc_lfb_coeff(), hdl->infmt.lfb_yorder * 40);
+ memcpy(hdl->infmt.lff_coeff, get_anc_lff_coeff(), hdl->infmt.lff_yorder * 40);
+ memcpy(hdl->infmt.ltrans_coeff, get_anc_ltrans_coeff(), hdl->infmt.ltrans_yorder * 40);
+ memcpy(hdl->infmt.ltransfb_coeff, get_anc_ltrans_fb_coeff(), hdl->infmt.ltransfb_yorder * 40);
+
+ extern u32 get_anc_gains_sign();
+ hdl->infmt.gain_sign = get_anc_gains_sign();
+
+ hdl->infmt.alloc_ptr = hdl->lib_alloc_ptr;
+ /*数据输出回调*/
+ /* hdl->infmt.output_hdl = audio_acoustic_detector_output_hdl; */
+ hdl->infmt.anc_dma_post_msg = audio_acoustic_detector_anc_dma_post_msg;
+ hdl->infmt.anc_dma_output_callback = audio_acoustic_detector_anc_dma_output_callback;
+ hdl->infmt.ff_gain = audio_anc_ffmic_gain_get();
+ hdl->infmt.fb_gain = audio_anc_fbmic_gain_get();
+ /* hdl->infmt.sample_rate = 16000;//Raymond debug */
+ hdl->infmt.sample_rate = 44100;//Raymond debug
+ printf("ff_gain %d, fb_gain %d", hdl->infmt.ff_gain, hdl->infmt.fb_gain);
+ icsd_acoustic_detector_set_infmt(&hdl->infmt);
+ icsd_adt_task_create();
+ icsd_src_task_create();
+ icsd_acoustic_detector_open();
+
+ u16 mic_ch = 0;
+ /*根据anc使用的mic配置adt的mic*/
+ if (TCFG_AUDIO_ANCL_FF_MIC != MIC_NULL) {
+ mic_ch |= BIT(TCFG_AUDIO_ANCL_FF_MIC);
+ }
+ if (TCFG_AUDIO_ANCL_FB_MIC != MIC_NULL) {
+ mic_ch |= BIT(TCFG_AUDIO_ANCL_FB_MIC);
+ }
+ /*头戴式使用左耳*/
+ if (hdl->infmt.adt_mode != ADT_HEADSET) {
+ if (TCFG_AUDIO_ANCR_FF_MIC != MIC_NULL) {
+ mic_ch |= BIT(TCFG_AUDIO_ANCR_FF_MIC);
+ }
+ if (TCFG_AUDIO_ANCR_FB_MIC != MIC_NULL) {
+ mic_ch |= BIT(TCFG_AUDIO_ANCR_FB_MIC);
+ }
+ }
+
+ if (hdl->libfmt.mic_num == 3) {
+ mic_ch |= icsd_get_talk_mic_ch();
+ }
+
+ audio_mic_param_t mic_param = {
+ .mic_ch_sel = mic_ch,
+ .sample_rate = hdl->libfmt.adc_sr,//采样率
+ .adc_irq_points = hdl->libfmt.adc_isr_len,//一次处理数据的数据单元, 单位点 4对齐(要配合mic起中断点数修改)
+ .adc_buf_num = 3,
+ .mic0_gain = audio_anc_mic_gain_get(0),
+ .mic1_gain = audio_anc_mic_gain_get(1),
+ .mic2_gain = audio_anc_mic_gain_get(2),
+ .mic3_gain = audio_anc_mic_gain_get(3),
+ };
+ if (hdl->libfmt.mic_num == 3) {
+ /*免摘使用3mic时,设置talk mic gain和ff mic gain一样*/
+ audio_icsd_adt_set_talk_mic_gain(&mic_param);
+ }
+ int err = audio_mic_en(1, &mic_param, audio_mic_output_handle);
+ if (err != 0) {
+ printf("open mic fail !!!");
+ goto err0;
+ }
+ icsd_adt_start();
+ audio_icsd_adt_start();
+
+ /*用于TWS同步adt状态*/
+ if (adt_info.speak_to_chat_state == AUDIO_ADT_CHAT) {
+ audio_speak_to_chat_voice_state_sync();
+ hdl->adt_resume = 0;
+ }
+ adt_info.speak_to_chat_state = AUDIO_ADT_OPEN;
+ hdl->speak_to_chat_state = AUDIO_ADT_OPEN;
+ return 0;
+err0:
+ audio_acoustic_detector_close();
+ return -1;
+}
+
+/*关闭智能免摘检测*/
+int audio_acoustic_detector_close()
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl) {
+ audio_dac_set_samplerate_callback_del(&dac_hdl, audio_icsd_adt_set_sample);
+ audio_mic_en(0, NULL, NULL);
+ if (hdl->lib_alloc_ptr) {
+ /*需要先挂起再关闭*/
+ icsd_acoustic_detector_suspend();
+ icsd_acoustic_detector_close();
+ icsd_adt_task_kill();
+ icsd_src_task_kill();
+
+ if (hdl->infmt.lfb_coeff) {
+ free(hdl->infmt.lfb_coeff);
+ hdl->infmt.lfb_coeff = NULL;
+ }
+ if (hdl->infmt.lff_coeff) {
+ free(hdl->infmt.lff_coeff);
+ hdl->infmt.lff_coeff = NULL;
+ }
+ if (hdl->infmt.ltrans_coeff) {
+ free(hdl->infmt.ltrans_coeff);
+ hdl->infmt.ltrans_coeff = NULL;
+ }
+ if (hdl->infmt.ltransfb_coeff) {
+ free(hdl->infmt.ltransfb_coeff);
+ hdl->infmt.ltransfb_coeff = NULL;
+ }
+
+ free(hdl->lib_alloc_ptr);
+ hdl->lib_alloc_ptr = NULL;
+ }
+ }
+ return 0;
+}
+
+/*dac数据清零 mute*/
+void audio_adt_dac_check_slience_cb(void *buf, int len)
+{
+ /* memset((u8 *)buf, 0x0, len); */
+}
+void audio_adt_dac_mute_start(void *priv)
+{
+ audio_dac_write_callback_add(&dac_hdl, audio_adt_dac_check_slience_cb);
+}
+void audio_adt_dac_mute_stop(void)
+{
+ audio_dac_write_callback_del(&dac_hdl, audio_adt_dac_check_slience_cb);
+}
+
+
+void adt_anc_mode_switch(u8 mode, u8 tone_play)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl) {
+ anc_mode_switch(ANC_ON, 0);
+ }
+}
+
+
+void audio_icsd_adt_suspend()
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl && hdl->state) {
+ printf("%s : %d", __func__, __LINE__);
+ icsd_acoustic_detector_suspend();
+ hdl->adt_suspend = 0;
+ /*删除定时器*/
+ if (hdl->timer) {
+ sys_s_hi_timeout_del(hdl->timer);
+ hdl->timer = 0;
+ }
+ }
+}
+
+/*char 定时结束后从通透同步恢复anc on /anc off*/
+void audio_speak_to_char_suspend(void)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ int err = 0;
+ if (hdl && hdl->state) {
+ printf("%s : %d", __func__, __LINE__);
+ /*tws同步suspend时,防止二次调用*/
+ if (hdl->adt_suspend) {
+ return;
+ }
+ hdl->busy = 1;
+ hdl->adt_suspend = 1;
+ printf("%s : %d", __func__, hdl->last_anc_state);
+ /*tws同步后,删除定时器*/
+ if (hdl->timer) {
+ sys_s_hi_timeout_del(hdl->timer);
+ hdl->timer = 0;
+ }
+ hdl->speak_to_chat_state = AUDIO_ADT_OPEN;
+ adt_info.speak_to_chat_state = AUDIO_ADT_OPEN;
+ icsd_acoustic_detector_suspend();
+ /*播放结束提示音的标志*/
+ hdl->anc_switch_flag = 1;
+ if (hdl->last_anc_state == ANC_ON) {
+ if (anc_mode_get() == ANC_ON) {
+ icsd_acoustic_detector_resume(RESUME_ANCMODE, ADT_ANC_ON);
+#if SPEAK_TO_CHAT_PLAY_TONE_EN
+ /*免摘结束退出通透提示音*/
+ err = os_taskq_post_msg(SPEAK_TO_CHAT_TASK_NAME, 2, ICSD_ADT_TONE_PLAY, (int)ICSD_ADT_TONE_NUM0);
+#else
+ hdl->adt_suspend = 0;
+#endif /*SPEAK_TO_CHAT_PLAY_TONE_EN*/
+ hdl->anc_switch_flag = 0;
+ } else {
+ /* anc_mode_switch(ANC_ON, 0); */
+ err = os_taskq_post_msg(SPEAK_TO_CHAT_TASK_NAME, 3, ICSD_ANC_MODE_SWITCH, ANC_ON, 0);
+ }
+ } else if (hdl->last_anc_state == ANC_TRANSPARENCY) {
+ if (anc_mode_get() == ANC_TRANSPARENCY) {
+ icsd_acoustic_detector_resume(RESUME_BYPASSMODE, ADT_ANC_OFF);
+#if SPEAK_TO_CHAT_PLAY_TONE_EN
+ /*免摘结束退出通透提示音*/
+ err = os_taskq_post_msg(SPEAK_TO_CHAT_TASK_NAME, 2, ICSD_ADT_TONE_PLAY, (int)ICSD_ADT_TONE_NUM0);
+#else
+ hdl->adt_suspend = 0;
+#endif /*SPEAK_TO_CHAT_PLAY_TONE_EN*/
+ hdl->anc_switch_flag = 0;
+ } else {
+ /* anc_mode_switch(ANC_TRANSPARENCY, 0); */
+ err = os_taskq_post_msg(SPEAK_TO_CHAT_TASK_NAME, 3, ICSD_ANC_MODE_SWITCH, ANC_TRANSPARENCY, 0);
+ }
+ } else { /*if (hdl->last_anc_state == ANC_OFF*/
+ if (anc_mode_get() == ANC_OFF) {
+ icsd_acoustic_detector_resume(RESUME_ANCMODE, ADT_ANC_OFF);
+#if SPEAK_TO_CHAT_PLAY_TONE_EN
+ /*免摘结束退出通透提示音*/
+ err = os_taskq_post_msg(SPEAK_TO_CHAT_TASK_NAME, 2, ICSD_ADT_TONE_PLAY, (int)ICSD_ADT_TONE_NUM0);
+#else
+ hdl->adt_suspend = 0;
+#endif /*SPEAK_TO_CHAT_PLAY_TONE_EN*/
+ hdl->anc_switch_flag = 0;
+ } else {
+ adt_open_in_anc = 1;
+ /* anc_mode_switch(ANC_OFF, 0); */
+ err = os_taskq_post_msg(SPEAK_TO_CHAT_TASK_NAME, 3, ICSD_ANC_MODE_SWITCH, ANC_OFF, 0);
+ }
+ }
+
+ audio_adt_dac_mute_stop();
+ if (hdl->a2dp_state && (bt_a2dp_get_status() != BT_MUSIC_STATUS_STARTING)) {
+ printf("send PLAY cmd");
+ bt_cmd_prepare(USER_CTRL_AVCTP_OPID_PLAY, 0, NULL);
+ }
+ hdl->a2dp_state = 0;
+ hdl->busy = 0;
+ }
+}
+
+void audio_speak_to_char_sync_suspend(void)
+{
+ printf("%s", __func__);
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ u8 data[4];
+ if (hdl && hdl->state) {
+ hdl->adt_suspend = 0;
+#if TCFG_USER_TWS_ENABLE
+ if (get_tws_sibling_connect_state()) {
+ data[0] = SYNC_ICSD_ADT_SUSPEND;
+ audio_icsd_adt_info_sync(data, 4);
+ } else {
+ audio_speak_to_char_suspend();
+ }
+#else
+ audio_speak_to_char_suspend();
+#endif/*TCFG_USER_TWS_ENABLE*/
+ }
+}
+
+void audio_anc_mode_switch_in_adt(u8 anc_mode)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl && hdl->state) {
+ icsd_acoustic_detector_suspend();
+ if (anc_mode == ANC_TRANSPARENCY && hdl->adt_resume) {
+ /*说话触发的通透不记录*/
+ return;
+ }
+ hdl->busy = 1;
+ printf("%s : %d", __func__, __LINE__);
+ /*每次切anc模式都在resume前更新参数*/
+ set_icsd_adt_param_updata();
+ /*进入免摘后,如果切换anc模式主动退出免摘*/
+ if (hdl->speak_to_chat_state == AUDIO_ADT_CHAT) {
+ /* hdl->adt_suspend = 0; */
+ /*删除定时器*/
+ if (hdl->timer) {
+ sys_s_hi_timeout_del(hdl->timer);
+ hdl->timer = 0;
+ }
+ }
+ if ((anc_mode == ANC_OFF) && (hdl->speak_to_chat_state != AUDIO_ADT_CLOSE)) {
+ adt_open_in_anc = 1;
+ }
+ /*记录外部切换的anc模式*/
+ hdl->last_anc_state = anc_mode;
+ hdl->busy = 0;
+ }
+}
+
+void audio_speak_to_chat_timer(void *p)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl && hdl->state) {
+ printf("%s", __func__);
+ if (hdl->timer) {
+ sys_s_hi_timeout_del(hdl->timer);
+ }
+ hdl->timer = 0;
+ audio_speak_to_char_sync_suspend();
+ }
+}
+
+/*切换anc 或者通透完成后,恢复免摘*/
+void audio_icsd_adt_resume_timer(void *p)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl && hdl->state) {
+ hdl->busy = 1;
+ printf("%s : %d", __func__, __LINE__);
+ /*更新参数*/
+ if (hdl->adt_param_updata) {
+ hdl->adt_param_updata = 0;
+ audio_acoustic_detector_updata();
+ }
+ /*adt挂起完成,准备退出挂起*/
+ hdl->adt_suspend = 0;
+ if (hdl->adt_resume) {
+ /*智能免摘切换通透挂起恢复*/
+ if (anc_mode_get() == ANC_TRANSPARENCY) {
+ icsd_acoustic_detector_resume(RESUME_BYPASSMODE, ADT_ANC_OFF);
+ }
+ hdl->adt_resume = 0;
+ } else {
+ /*智能免摘定时结束触发的挂起恢复*/
+ if (anc_mode_get() == ANC_ON) {
+ icsd_acoustic_detector_resume(RESUME_ANCMODE, ADT_ANC_ON);
+ } else if (anc_mode_get() == ANC_TRANSPARENCY) {
+ icsd_acoustic_detector_resume(RESUME_BYPASSMODE, ADT_ANC_OFF);
+ } else { /*if (anc_mode_get() == ANC_OFF*/
+ icsd_acoustic_detector_resume(RESUME_ANCMODE, ADT_ANC_OFF);
+ }
+ hdl->speak_to_chat_state = AUDIO_ADT_OPEN;
+ adt_info.speak_to_chat_state = AUDIO_ADT_OPEN;
+ }
+ hdl->adt_resume_timer = 0;
+ hdl->busy = 0;
+ }
+}
+void audio_icsd_adt_resume()
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl && hdl->state) {
+ hdl->busy = 1;
+ printf("%s : %d", __func__, __LINE__);
+ adt_open_in_anc = 0;
+ /*延时1s,等待数据稳定在恢复*/
+ if (hdl->adt_resume_timer == 0) {
+ hdl->adt_resume_timer = sys_s_hi_timerout_add(NULL, audio_icsd_adt_resume_timer, 500);
+ }
+ if (hdl->adt_resume) {
+ /*智能免摘定时结束触发的挂起恢复*/
+ if (anc_mode_get() == ANC_TRANSPARENCY) {
+ }
+ } else {
+ if (hdl->anc_switch_flag) {
+#if SPEAK_TO_CHAT_PLAY_TONE_EN
+ /*免摘结束退出通透提示音*/
+ icsd_adt_tone_play(ICSD_ADT_TONE_NUM0);
+#endif /*SPEAK_TO_CHAT_PLAY_TONE_EN*/
+ hdl->anc_switch_flag = 0;
+ }
+ }
+ hdl->busy = 0;
+ }
+}
+
+u8 audio_speak_to_chat_is_running()
+{
+ return (speak_to_chat_hdl != NULL);
+}
+
+/*adt是否在跑*/
+u8 audio_icsd_adt_is_running()
+{
+ return (speak_to_chat_hdl != NULL);
+}
+
+/*获取智能免摘的状态*/
+u8 get_speak_to_chat_state()
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl) {
+ return hdl->speak_to_chat_state;
+ } else {
+ return 0;
+ }
+}
+
+/*获取adt的模式*/
+u8 get_icsd_adt_mode()
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ return adt_info.adt_mode;
+}
+
+void audio_icsd_adt_state_sync_done(u8 adt_mode, u8 speak_to_chat_state)
+{
+
+ int close_adt = ADT_SPEAK_TO_CHAT_MODE | ADT_WIDE_AREA_TAP_MODE | ADT_WIND_NOISE_DET_MODE;
+ audio_icsd_adt_res_close(close_adt);
+
+ printf("%s, adt %d, chat %d", __func__, adt_mode, speak_to_chat_state);
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ adt_info.speak_to_chat_state = speak_to_chat_state;
+ if (hdl && hdl->state) {
+ /*tws同步时重置记录的anc模式*/
+ hdl->last_anc_state = anc_mode_get();
+ }
+ adt_info.adt_mode = adt_mode;
+ /*同步动作前已经关闭adt了,这里只需要判断打开,避免没有开adt在anc off里面开了anc*/
+ if (adt_info.adt_mode) {
+ /*在anc跑完后面执行同步adt状态*/
+ adt_open_in_anc = 1;
+ }
+}
+
+/*同步tws配对时,同步adt的状态*/
+static u8 sync_data[5];
+void audio_anc_icsd_adt_state_sync(u8 *data)
+{
+ printf("audio_anc_icsd_adt_state_sync");
+ memcpy(sync_data, data, sizeof(sync_data));
+ os_taskq_post_msg(SPEAK_TO_CHAT_TASK_NAME, 2, ICSD_ADT_STATE_SYNC, (int)sync_data);
+}
+
+/*检测到讲话状态同步*/
+void set_speak_to_chat_voice_state(u8 state)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ int err = 0;
+ if (hdl && hdl->state) {
+ hdl->voice_state = state;
+ hdl->tws_sync_state = 0;
+ printf("%s", __func__);
+ err = os_taskq_post_msg(SPEAK_TO_CHAT_TASK_NAME, 2, ICSD_ADT_VOICE_STATE, (int)hdl);
+ }
+}
+
+void audio_speak_to_chat_voice_state_sync(void)
+{
+ printf("%s", __func__);
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ u8 data[4] = {0};
+ if ((hdl->adt_resume == 0) && (hdl->adt_suspend == 0)) {
+#if TCFG_USER_TWS_ENABLE
+ if (get_tws_sibling_connect_state()) {
+ /*hdl->tws_sync_state == 0 : 保证上一次消息还没接收到,不发下一个消息*/
+ if (hdl->tws_sync_state == 0) {
+ hdl->tws_sync_state = 1;
+ data[0] = SYNC_ICSD_ADT_VOICE_STATE;
+ audio_icsd_adt_info_sync(data, 4);
+ }
+ } else {
+ set_speak_to_chat_voice_state(1);
+ }
+#else
+ set_speak_to_chat_voice_state(1);
+#endif/*TCFG_USER_TWS_ENABLE*/
+ }
+}
+
+
+void icsd_adt_task_play_tone_cb(void *priv)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ /*播放完提示音*/
+ if (hdl && hdl->state) {
+ hdl->adt_suspend = 0;
+ }
+}
+
+static void audio_icsd_adt_task(void *p)
+{
+ printf("%s", __func__);
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ int msg[16];
+ int res;
+
+ while (1) {
+ res = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
+ if (res == OS_TASKQ) {
+ switch (msg[1]) {
+#if TCFG_AUDIO_SPEAK_TO_CHAT_ENABLE
+ case ICSD_ADT_VOICE_STATE:
+ hdl = speak_to_chat_hdl;
+ if (hdl && hdl->state) {
+ hdl->busy = 1;
+ /* hdl->adt_resume == 0 :上一次检测到语音,挂起切换通透还没完成恢复的时候,不能做下一次动作
+ * hdl->adt_suspend == 0 : 结束定时挂起切换anc模式的时候,还没完成模式切换,不能做检测作动*/
+ if (hdl->voice_state && (hdl->adt_resume == 0) && (hdl->adt_suspend == 0)) {
+ if (hdl->speak_to_chat_state == AUDIO_ADT_CHAT) {
+ printf("hdl->speak_to_chat_state == AUDIO_ADT_CHAT)");
+ } else {
+ printf("%s", __func__);
+ /*检测到语音切换到通透*/
+ if (anc_mode_get() != ANC_TRANSPARENCY) {
+ hdl->adt_resume = 1;/*调用顺序不可改*/
+ hdl->speak_to_chat_state = AUDIO_ADT_OPEN;
+ adt_info.speak_to_chat_state = AUDIO_ADT_OPEN;
+ icsd_acoustic_detector_suspend();
+ set_anc_adt_state(1);
+ anc_mode_switch(ANC_TRANSPARENCY, 0);
+ }
+
+ /*如果在播歌暂停播歌*/
+ if (bt_a2dp_get_status() == BT_MUSIC_STATUS_STARTING) {
+ printf("send PAUSE cmd");
+ hdl->a2dp_state = 1;
+ bt_cmd_prepare(USER_CTRL_AVCTP_OPID_PAUSE, 0, NULL);
+ }
+#if SPEAK_TO_CHAT_PLAY_TONE_EN
+ /*结束免摘后检测播放提示音*/
+ icsd_adt_tone_play(ICSD_ADT_TONE_NORMAL);
+#endif /*SPEAK_TO_CHAT_PLAY_TONE_EN*/
+ /* tone_play_index_with_callback(IDEX_TONE_NORMAL, 1, audio_adt_dac_mute_start, NULL); */
+ }
+#if SPEAK_TO_CHAT_TEST_TONE_EN
+ /*每次检测到说话都播放提示音*/
+ icsd_adt_tone_play(ICSD_ADT_TONE_NORMAL);
+#endif /*SPEAK_TO_CHAT_TEST_TONE_EN*/
+
+ /*重新定时*/
+ if (hdl->timer) {
+ sys_s_hi_timeout_del(hdl->timer);
+ hdl->timer = 0;
+ }
+ hdl->timer = sys_s_hi_timerout_add(NULL, audio_speak_to_chat_timer, adt_info.speak_to_chat_end_time);
+ hdl->speak_to_chat_state = AUDIO_ADT_CHAT;
+ adt_info.speak_to_chat_state = AUDIO_ADT_CHAT;
+ hdl->voice_state = 0;
+ }
+ hdl->busy = 0;
+ }
+ break;
+#endif /*TCFG_AUDIO_SPEAK_TO_CHAT_ENABLE*/
+#if TCFG_AUDIO_ANC_WIND_NOISE_DET_ENABLE
+ case ICSD_ADT_WIND_LVL:
+ hdl = speak_to_chat_hdl;
+ if (hdl && hdl->state) {
+ hdl->busy = 1;
+ u8 wind_lvl = (u8)msg[2];
+ /* printf("[task]wind_lvl : %d", wind_lvl); */
+ hdl->adt_wind_lvl = wind_lvl;
+
+#if ICSD_ADT_WIND_INFO_SPP_DEBUG_EN
+ /*蓝牙spp发送风噪值*/
+ static u8 cnt = 0;
+ /*spp是否连接 && spp是否初始化 && spp发送是否初始化 && 每隔5次发送一次数据*/
+ if ((hdl->spp_connected_state == SPP_USER_ST_CONNECT) && hdl->spp_opt && hdl->spp_opt->send_data && (cnt++ > 5)) {
+ cnt = 0;
+ char tmpbuf[25];
+ memset(tmpbuf, 0x20, sizeof(tmpbuf));//填充空格
+ sprintf(tmpbuf, "wind lvl:%d", hdl->adt_wind_lvl);
+
+#if TCFG_USER_TWS_ENABLE
+ if (get_tws_sibling_connect_state() && (tws_api_get_role() == TWS_ROLE_MASTER)) {
+ /*主机发送*/
+ hdl->spp_opt->send_data(NULL, tmpbuf, sizeof(tmpbuf));
+ } else
+#endif /*TCFG_USER_TWS_ENABLE*/
+ {
+ hdl->spp_opt->send_data(NULL, tmpbuf, sizeof(tmpbuf));
+
+ }
+ }
+#endif /*ICSD_ADT_WIND_INFO_SPP_DEBUG_EN*/
+ /*风噪处理*/
+ audio_anc_wind_noise_process(hdl->adt_wind_lvl);
+ hdl->busy = 0;
+ }
+ break;
+#endif /*TCFG_AUDIO_ANC_WIND_NOISE_DET_ENABLE*/
+#if TCFG_AUDIO_WIDE_AREA_TAP_ENABLE
+ case ICSD_ADT_WAT_RESULT:
+ hdl = speak_to_chat_hdl;
+ if (hdl && hdl->state) {
+ hdl->busy = 1;
+ u8 wat_result = (u8)msg[2];
+ printf("[task]wat_result : %d", wat_result);
+ hdl->adt_wat_result = wat_result;
+ audio_wat_area_tap_event_handle(hdl->adt_wat_result);
+ hdl->busy = 0;
+ }
+ break;
+#endif /*TCFG_AUDIO_WIDE_AREA_TAP_ENABLE*/
+ case ICSD_ADT_TONE_PLAY:
+ /*播放提示音,定时器里面需要播放提示音时,可发消息到这里播放*/
+ u8 index = (u8)msg[2];
+ int err = icsd_adt_tone_play_callback(index, icsd_adt_task_play_tone_cb, NULL);
+ if (hdl && (err != 0)) {
+ /*如果播放提示音失败,suspend提前置0*/
+ hdl->adt_suspend = 0;
+ }
+ break;
+ case SPEAK_TO_CHAT_TASK_KILL:
+ /*清掉队列消息*/
+ os_taskq_flush();
+ os_sem_post((OS_SEM *)msg[2]);
+ break;
+ case ICSD_ANC_MODE_SWITCH:
+ anc_mode_switch((u8)msg[2], (u8)msg[3]);
+ break;
+ case SYNC_ICSD_ADT_OPEN:
+ audio_icsd_adt_open((u8)msg[2]);
+ break;
+ case SYNC_ICSD_ADT_CLOSE:
+ audio_icsd_adt_res_close((u8)msg[2]);
+ break;
+ case SYNC_ICSD_ADT_SET_ANC_FADE_GAIN:
+ printf("set anc fade gain : %d", msg[2]);
+ icsd_anc_fade_set(msg[2]);
+ break;
+ case ICSD_ADT_STATE_SYNC:
+ printf("ICSD_ADT_STATE_SYNC");
+ u8 *s_data = (u8 *)msg[2];
+ /*先关闭adt,同步adt状态,然后同步anc,在anc里面做判断开adt*/
+ audio_icsd_adt_state_sync_done(s_data[3], s_data[4]);
+ anc_mode_sync(s_data);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+/*return
+ * 0 : 不允许打开
+ * 1 : 允许打开*/
+static int audio_icsd_adt_open_permit()
+{
+ /*通话的时候不允许打开*/
+ if (esco_player_runing()) {
+ printf("esco open !!!");
+ return 0;
+ }
+#if TCFG_ANC_TOOL_DEBUG_ONLINE
+ /*连接anc spp 工具的时候不允许打开*/
+ if (get_app_anctool_spp_connected_flag()) {
+ printf("anctool spp connected !!!");
+ return 0;
+ }
+#endif
+ return 1;
+}
+
+int anc_adt_init()
+{
+ /*先创建任务,开关adt的操作在任务里面处理*/
+ task_create(audio_icsd_adt_task, NULL, SPEAK_TO_CHAT_TASK_NAME);
+ return 0;
+}
+
+int audio_icsd_adt_init()
+{
+ printf("%s", __func__);
+ struct speak_to_chat_t *hdl = NULL;
+
+ if (speak_to_chat_hdl) {
+ printf("speak_to_chat_hdl is areadly open !!");
+ return 0;
+ }
+ speak_to_chat_hdl = zalloc(sizeof(struct speak_to_chat_t));
+ if (speak_to_chat_hdl == NULL) {
+ printf("speak_to_chat_hdl malloc fail !!!");
+ adt_info.adt_mode = ADT_MODE_CLOSE;
+ return -1;
+ }
+ hdl = speak_to_chat_hdl;
+
+ hdl->last_anc_state = anc_mode_get();
+ printf("last_anc_state %d", hdl->last_anc_state);
+
+ /*设置anc使用的adt状态*/
+ set_anc_adt_state(1);
+ /* task_create(audio_icsd_adt_task, hdl, SPEAK_TO_CHAT_TASK_NAME); */
+ audio_acoustic_detector_open();
+ icsd_adt_clock_add();
+ /*关闭蓝牙sniff*/
+#if TCFG_USER_TWS_ENABLE
+ icsd_bt_sniff_set_enable(0);
+#endif
+ hdl->state = 1;
+ return 0;
+}
+
+int audio_icsd_adt_open(u8 adt_mode)
+{
+ printf("%s", __func__);
+ if (!(~adt_info.adt_mode & adt_mode) && adt_mode) {
+ /*判断传进来的模式中有哪些没有打开的*/
+ return 0;
+ }
+ if (adt_info.adt_mode && adt_mode) {
+ /*如果当前有其他模块已经打开时,需要关闭在重新打开*/
+ adt_info.adt_mode |= adt_mode;
+ audio_icsd_adt_res_close(0);
+ return 0;
+ }
+ adt_info.adt_mode |= adt_mode;
+
+ if (anc_mode_get() == ANC_ON) {
+ adt_open_in_anc = 0;
+ audio_icsd_adt_init();
+ } else if (anc_mode_get() == ANC_OFF) {
+ adt_open_in_anc = 1;
+ anc_mode_switch_in_anctask(ANC_OFF, 0);
+ } else if (anc_mode_get() == ANC_TRANSPARENCY) {
+ adt_open_in_anc = 0;
+ audio_icsd_adt_init();
+ }
+ return 0;
+}
+
+/*同步打开,
+ *ag: audio_icsd_adt_sync_open(ADT_SPEAK_TO_CHAT_MODE | ADT_WIDE_AREA_TAP_MODE | ADT_WIND_NOISE_DET_MODE) */
+int audio_icsd_adt_sync_open(u8 adt_mode)
+{
+ printf("%s", __func__);
+ u8 data[4] = {0};
+ data[0] = SYNC_ICSD_ADT_OPEN;
+ data[1] = adt_mode;
+
+ if (audio_icsd_adt_open_permit() == 0) {
+ return -1;
+ }
+#if TCFG_USER_TWS_ENABLE
+ if (get_tws_sibling_connect_state()) {
+ if ((tws_api_get_role() == TWS_ROLE_MASTER)) {
+ /*同步主机状态打开*/
+ audio_icsd_adt_info_sync(data, 4);
+ }
+ } else
+#endif
+ {
+ audio_icsd_adt_info_sync(data, 4);
+ }
+ return 0;
+}
+
+/*同步关闭,
+ *ag: audio_icsd_adt_sync_close(ADT_SPEAK_TO_CHAT_MODE | ADT_WIDE_AREA_TAP_MODE | ADT_WIND_NOISE_DET_MODE) */
+int audio_icsd_adt_sync_close(u8 adt_mode)
+{
+ u8 data[4] = {0};
+ data[0] = SYNC_ICSD_ADT_CLOSE;
+ data[1] = adt_mode;
+#if TCFG_USER_TWS_ENABLE
+ if (get_tws_sibling_connect_state()) {
+ if ((tws_api_get_role() == TWS_ROLE_MASTER)) {
+ /*同步主机状态打开*/
+ audio_icsd_adt_info_sync(data, 4);
+ }
+ } else
+#endif
+ {
+ audio_icsd_adt_info_sync(data, 4);
+ }
+ return 0;
+}
+
+/*获取是否需要先开anc再开免摘的状态*/
+u8 get_adt_open_in_anc_state()
+{
+ return adt_open_in_anc;
+}
+
+int audio_speak_to_chat_open_in_anc_done()
+{
+ if (adt_open_in_anc) {
+ adt_open_in_anc = 0;
+ if (adt_info.adt_mode) {
+ audio_icsd_adt_init();
+ } else {
+ audio_icsd_adt_res_close(0);
+ }
+ }
+ return 0;
+}
+
+int audio_icsd_adt_close(u8 adt_mode)
+{
+ int err = 0;
+ err = os_taskq_post_msg(SPEAK_TO_CHAT_TASK_NAME, 2, SYNC_ICSD_ADT_CLOSE, adt_mode);
+ return err;
+}
+
+int audio_icsd_adt_res_close(u8 adt_mode)
+{
+ printf("%s", __func__);
+ adt_info.adt_mode &= ~adt_mode;
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl && hdl->state) {
+ hdl->state = 0;
+ while (hdl->busy) {
+ putchar('w');
+ os_time_dly(1);
+ }
+ audio_acoustic_detector_close();
+ if (hdl->timer) {
+ sys_s_hi_timeout_del(hdl->timer);
+ hdl->timer = 0;
+ }
+ set_anc_adt_state(0);
+ hdl->speak_to_chat_state = AUDIO_ADT_CLOSE;
+ adt_info.speak_to_chat_state = AUDIO_ADT_CLOSE;
+
+ /*恢复ANC状态*/
+ if (hdl->last_anc_state == ANC_ON) {
+ anc_mode_switch(ANC_ON, 0);
+ } else if (hdl->last_anc_state == ANC_TRANSPARENCY) {
+ anc_mode_switch(ANC_TRANSPARENCY, 0);
+ } else {
+ adt_open_in_anc = 0;
+ //如果全部模式都关闭的时候,需要anc忽略相同模式的切换,关闭假anc off
+ anc_mode_switch(ANC_OFF, 0);
+ }
+
+ /*关闭dac mute*/
+ audio_adt_dac_mute_stop();
+
+ /*恢复播歌状态*/
+ if (hdl->a2dp_state && (bt_a2dp_get_status() != BT_MUSIC_STATUS_STARTING)) {
+ printf("send PLAY cmd");
+ bt_cmd_prepare(USER_CTRL_AVCTP_OPID_PLAY, 0, NULL);
+ }
+ /*打开蓝牙sniff*/
+#if TCFG_USER_TWS_ENABLE
+ icsd_bt_sniff_set_enable(1);
+#endif
+
+ free(hdl);
+ speak_to_chat_hdl = NULL;
+ icsd_adt_clock_del();
+
+ }
+ /*如果adt没有全部关闭,需要重新打开
+ *如果是通话时关闭的,直接关闭adt*/
+ if (adt_info.adt_mode && !esco_player_runing()) {
+ audio_icsd_adt_open(0);
+ }
+ return 0;
+}
+
+/*关闭所有模块*/
+int audio_icsd_adt_close_all()
+{
+ u8 adt_mode = ADT_SPEAK_TO_CHAT_MODE | ADT_WIDE_AREA_TAP_MODE | ADT_WIND_NOISE_DET_MODE;
+ audio_icsd_adt_close(adt_mode);
+ return 0;
+}
+
+/*打开所有模块*/
+int audio_icsd_adt_open_all()
+{
+ u8 adt_mode = ADT_SPEAK_TO_CHAT_MODE | ADT_WIDE_AREA_TAP_MODE | ADT_WIND_NOISE_DET_MODE;
+ audio_icsd_adt_sync_open(adt_mode);
+ return 0;
+}
+
+/*打开智能免摘*/
+int audio_speak_to_chat_open()
+{
+ if (anc_mode_get() == ANC_ON) {
+#if !(SPEAK_TO_CHAT_ANC_MODE_ENABLE & ANC_ON_BIT)
+ /*不支持anc on下打开免摘*/
+ return 0;
+#endif
+ } else if (anc_mode_get() == ANC_OFF) {
+#if !(SPEAK_TO_CHAT_ANC_MODE_ENABLE & ANC_OFF_BIT)
+ /*不支持anc off下打开免摘*/
+ return 0;
+#endif
+ } else if (anc_mode_get() == ANC_TRANSPARENCY) {
+ /*不支持通透下开免摘*/
+#if !(SPEAK_TO_CHAT_ANC_MODE_ENABLE & ANC_TRANS_BIT)
+ return 0;
+#endif
+ }
+ printf("%s", __func__);
+ u8 adt_mode = ADT_SPEAK_TO_CHAT_MODE;
+ return audio_icsd_adt_sync_open(adt_mode);
+}
+
+/*关闭智能免摘*/
+int audio_speak_to_chat_close()
+{
+ printf("%s", __func__);
+ u8 adt_mode = ADT_SPEAK_TO_CHAT_MODE;
+ return audio_icsd_adt_sync_close(adt_mode);
+}
+
+/*设置免摘定时结束的时间,单位ms*/
+int audio_speak_to_char_end_time_set(u16 time)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl && (adt_info.adt_mode & ADT_SPEAK_TO_CHAT_MODE)) {
+ adt_info.speak_to_chat_end_time = time;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+/*设置智能免摘检测的灵敏度*/
+int audio_speak_to_chat_sensitivity_set(u8 sensitivity)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl && (adt_info.adt_mode & ADT_SPEAK_TO_CHAT_MODE)) {
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+void audio_speak_to_chat_demo()
+{
+ printf("%s", __func__);
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (audio_icsd_adt_open_permit() == 0) {
+ return;
+ }
+
+ /*判断智能免摘是否已经打开*/
+ if ((adt_info.adt_mode & ADT_SPEAK_TO_CHAT_MODE) == 0) {
+ if (anc_mode_get() == ANC_ON) {
+#if !(SPEAK_TO_CHAT_ANC_MODE_ENABLE & ANC_ON_BIT)
+ /*不支持anc on下打开免摘*/
+ return;
+#endif
+ } else if (anc_mode_get() == ANC_OFF) {
+#if !(SPEAK_TO_CHAT_ANC_MODE_ENABLE & ANC_OFF_BIT)
+ /*不支持anc off下打开免摘*/
+ return;
+#endif
+ } else if (anc_mode_get() == ANC_TRANSPARENCY) {
+ /*暂不支持通透下开免摘*/
+#if !(SPEAK_TO_CHAT_ANC_MODE_ENABLE & ANC_TRANS_BIT)
+ return;
+#endif
+ }
+ /*打开提示音*/
+ icsd_adt_tone_play(ICSD_ADT_TONE_SPKCHAT_ON);
+ audio_speak_to_chat_open();
+ } else {
+ /*关闭提示音*/
+ icsd_adt_tone_play(ICSD_ADT_TONE_SPKCHAT_OFF);
+ audio_speak_to_chat_close();
+ }
+}
+
+/*打开广域点击*/
+int audio_wat_click_open()
+{
+ printf("%s", __func__);
+ u8 adt_mode = ADT_WIDE_AREA_TAP_MODE;
+ return audio_icsd_adt_sync_open(adt_mode);
+}
+
+/*关闭广域点击*/
+int audio_wat_click_close()
+{
+ printf("%s", __func__);
+ u8 adt_mode = ADT_WIDE_AREA_TAP_MODE;
+ return audio_icsd_adt_sync_close(adt_mode);
+}
+
+void audio_wide_area_tap_ingre_flag_timer(void *p)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl && (adt_info.adt_mode & ADT_WIDE_AREA_TAP_MODE)) {
+ /*恢复响应*/
+ printf("wat ingore end");
+ hdl->adt_wat_ignore_flag = 0;
+ }
+}
+
+/*设置是否忽略广域点击
+ * ignore: 1 忽略点击,0 响应点击
+ * 忽略点击的时间,单位ms*/
+int audio_wide_area_tap_ignore_flag_set(u8 ignore, u16 time)
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl && (adt_info.adt_mode & ADT_WIDE_AREA_TAP_MODE)) {
+ hdl->adt_wat_ignore_flag = ignore;
+ if (hdl->adt_wat_ignore_flag) {
+ /*如果忽略点击,定时恢复响应*/
+ printf("wat ingore start");
+ sys_s_hi_timerout_add(NULL, audio_wide_area_tap_ingre_flag_timer, time);
+ }
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+/*广域点击使用demo*/
+void audio_wat_click_demo()
+{
+ printf("%s", __func__);
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (audio_icsd_adt_open_permit() == 0) {
+ return;
+ }
+
+ if ((adt_info.adt_mode & ADT_WIDE_AREA_TAP_MODE) == 0) {
+ /*打开提示音*/
+ icsd_adt_tone_play(ICSD_ADT_TONE_WCLICK_ON);
+ audio_wat_click_open();
+ } else {
+ /*关闭提示音*/
+ icsd_adt_tone_play(ICSD_ADT_TONE_WCLICK_OFF);
+ audio_wat_click_close();
+ }
+}
+
+/*广域点击事件处理*/
+void audio_wat_area_tap_event_handle(u8 wat_result)
+{
+ switch (wat_result) {
+ case WIND_AREA_TAP_DOUBLE_CLICK:
+ /*音乐暂停播放*/
+ if ((bt_get_call_status() == BT_CALL_OUTGOING) ||
+ (bt_get_call_status() == BT_CALL_ALERT)) {
+ bt_cmd_prepare(USER_CTRL_HFP_CALL_HANGUP, 0, NULL);
+ } else if (bt_get_call_status() == BT_CALL_INCOMING) {
+ bt_cmd_prepare(USER_CTRL_HFP_CALL_ANSWER, 0, NULL);
+ } else if (bt_get_call_status() == BT_CALL_ACTIVE) {
+ bt_cmd_prepare(USER_CTRL_HFP_CALL_HANGUP, 0, NULL);
+ } else {
+ bt_cmd_prepare(USER_CTRL_AVCTP_OPID_PLAY, 0, NULL);
+ }
+ break;
+ case WIND_AREA_TAP_THIRD_CLICK:
+ /*anc切模式*/
+ anc_mode_next();
+ break;
+ case WIND_AREA_TAP_MULTIPLE_CLICK:
+ /* tone_play_index(IDEX_TONE_NUM_4, 0); */
+ break;
+ }
+}
+
+
+/*打开风噪检测*/
+int audio_icsd_wind_detect_open()
+{
+ printf("%s", __func__);
+ u8 adt_mode = ADT_WIND_NOISE_DET_MODE;
+ return audio_icsd_adt_sync_open(adt_mode);
+}
+
+/*关闭风噪检测*/
+int audio_icsd_wind_detect_close()
+{
+ printf("%s", __func__);
+ u8 adt_mode = ADT_WIND_NOISE_DET_MODE;
+ return audio_icsd_adt_sync_close(adt_mode);
+}
+
+/*获取风噪等级*/
+u8 get_audio_icsd_wind_lvl()
+{
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (hdl) {
+ return hdl->adt_wind_lvl;
+ } else {
+ return 0;
+ }
+}
+
+/*风噪检测使用demo*/
+void audio_icsd_wind_detect_demo()
+{
+ printf("%s", __func__);
+ struct speak_to_chat_t *hdl = speak_to_chat_hdl;
+ if (audio_icsd_adt_open_permit() == 0) {
+ return;
+ }
+
+ if ((adt_info.adt_mode & ADT_WIND_NOISE_DET_MODE) == 0) {
+ /*打开提示音*/
+ icsd_adt_tone_play(ICSD_ADT_TONE_WINDDET_ON);
+ audio_icsd_wind_detect_open();
+ } else {
+ /*关闭提示音*/
+ icsd_adt_tone_play(ICSD_ADT_TONE_WINDDET_OFF);
+ audio_icsd_wind_detect_close();
+ }
+}
+
+/*风噪输出等级:0~255*/
+typedef struct {
+ const u16 lvl1_thr; //阈值1
+ const u16 lvl2_thr; //阈值2
+ const u16 lvl3_thr; //阈值3
+ const u16 lvl4_thr; //阈值4
+ const u16 lvl5_thr; //阈值5
+ const u16 dithering_step; //消抖风噪等级间距
+ u8 last_lvl;
+ u8 cur_lvl;
+} wind_lvl_det_t;
+wind_lvl_det_t wind_lvl_det_anc = {
+ .lvl1_thr = 30,
+ .lvl2_thr = 60,
+ .lvl3_thr = 90,
+ .lvl4_thr = 120,
+ .lvl5_thr = 150,
+ .dithering_step = 10,
+ .last_lvl = 0,
+ .cur_lvl = 0,
+};
+/*划分风噪等级为 6三个等级*/
+static u8 get_icsd_anc_wind_noise_lvl(wind_lvl_det_t *wind_lvl_det, u8 wind_lvl)
+{
+
+ if ((wind_lvl >= 0) && (wind_lvl <= (wind_lvl_det->lvl1_thr - wind_lvl_det->dithering_step))) {
+ /*判断LVL0*/
+ wind_lvl_det->cur_lvl = ANC_WIND_NOISE_LVL0;
+ wind_lvl_det->last_lvl = ANC_WIND_NOISE_LVL0;
+ } else if ((wind_lvl > (wind_lvl_det->lvl1_thr - wind_lvl_det->dithering_step)) && (wind_lvl <= wind_lvl_det->lvl1_thr)) {
+ /*LVL0和LVL1阈值处的消抖处理*/
+ if (wind_lvl_det->last_lvl > ANC_WIND_NOISE_LVL0) {
+ wind_lvl_det->cur_lvl = ANC_WIND_NOISE_LVL1;
+ } else {
+ wind_lvl_det->cur_lvl = ANC_WIND_NOISE_LVL0;
+ }
+
+ } else if ((wind_lvl > wind_lvl_det->lvl1_thr) && (wind_lvl <= (wind_lvl_det->lvl2_thr - wind_lvl_det->dithering_step))) {
+ /*判断LVL1*/
+ wind_lvl_det->cur_lvl = ANC_WIND_NOISE_LVL1;
+ wind_lvl_det->last_lvl = ANC_WIND_NOISE_LVL1;
+ } else if ((wind_lvl > (wind_lvl_det->lvl2_thr - wind_lvl_det->dithering_step)) && (wind_lvl <= wind_lvl_det->lvl2_thr)) {
+ /*LVL1和LVL2阈值处的消抖处理*/
+ if (wind_lvl_det->last_lvl > ANC_WIND_NOISE_LVL1) {
+ wind_lvl_det->cur_lvl = ANC_WIND_NOISE_LVL2;
+ } else {
+ wind_lvl_det->cur_lvl = ANC_WIND_NOISE_LVL1;
+ }
+
+ } else if ((wind_lvl > wind_lvl_det->lvl2_thr) && (wind_lvl <= (wind_lvl_det->lvl3_thr - wind_lvl_det->dithering_step))) {
+ /*判断LVL2*/
+ wind_lvl_det->cur_lvl = ANC_WIND_NOISE_LVL2;
+ wind_lvl_det->last_lvl = ANC_WIND_NOISE_LVL2;
+ } else if ((wind_lvl > (wind_lvl_det->lvl3_thr - wind_lvl_det->dithering_step)) && (wind_lvl <= wind_lvl_det->lvl3_thr)) {
+ /*LVL2和LVL3阈值处的消抖处理*/
+ if (wind_lvl_det->last_lvl > ANC_WIND_NOISE_LVL2) {
+ wind_lvl_det->cur_lvl = ANC_WIND_NOISE_LVL3;
+ } else {
+ wind_lvl_det->cur_lvl = ANC_WIND_NOISE_LVL2;
+ }
+
+ } else if ((wind_lvl > wind_lvl_det->lvl3_thr) && (wind_lvl <= (wind_lvl_det->lvl4_thr - wind_lvl_det->dithering_step))) {
+ /*判断LVL3*/
+ wind_lvl_det->cur_lvl = ANC_WIND_NOISE_LVL3;
+ wind_lvl_det->last_lvl = ANC_WIND_NOISE_LVL3;
+ } else if ((wind_lvl > (wind_lvl_det->lvl4_thr - wind_lvl_det->dithering_step)) && (wind_lvl <= wind_lvl_det->lvl4_thr)) {
+ /*LVL3和LVL4阈值处的消抖处理*/
+ if (wind_lvl_det->last_lvl > ANC_WIND_NOISE_LVL3) {
+ wind_lvl_det->cur_lvl = ANC_WIND_NOISE_LVL4;
+ } else {
+ wind_lvl_det->cur_lvl = ANC_WIND_NOISE_LVL3;
+ }
+
+ } else if ((wind_lvl > wind_lvl_det->lvl4_thr) && (wind_lvl <= (wind_lvl_det->lvl5_thr - wind_lvl_det->dithering_step))) {
+ /*判断LVL4*/
+ wind_lvl_det->cur_lvl = ANC_WIND_NOISE_LVL4;
+ wind_lvl_det->last_lvl = ANC_WIND_NOISE_LVL4;
+ } else if ((wind_lvl > (wind_lvl_det->lvl5_thr - wind_lvl_det->dithering_step)) && (wind_lvl <= wind_lvl_det->lvl5_thr)) {
+ /*LVL4和LVL5阈值处的消抖处理*/
+ if (wind_lvl_det->last_lvl > ANC_WIND_NOISE_LVL4) {
+ wind_lvl_det->cur_lvl = ANC_WIND_NOISE_LVL5;
+ } else {
+ wind_lvl_det->cur_lvl = ANC_WIND_NOISE_LVL4;
+ }
+
+ } else {//if ((wind_lvl > MIDDLE_STRONG_WIND_LVL_THR) && (wind_lvl <= 300)) {
+ /*判断LVL5*/
+ wind_lvl_det->cur_lvl = ANC_WIND_NOISE_LVL5;
+ wind_lvl_det->last_lvl = ANC_WIND_NOISE_LVL5;
+ }
+ return wind_lvl_det->cur_lvl;
+}
+
+typedef struct {
+ u16 time;//定时器定时计算时间, ms
+ u32 fade_timer;//计算定时器
+ u32 wind_cnt;//记录单次定时器的风噪帧数
+ u32 wind_eng;//记录风噪等级累加数字
+ u8 last_lvl;//记录上一次风噪等级
+ u8 preset_lvl;//记录当前检测到的风噪等级
+ u8 fade_in_cnt;//记录风噪变大的次数
+ u8 fade_out_cnt;//记录风噪变小的次数
+ u8 wind_process_flag;//是否条件anc增益
+
+ u8 fade_in_time;//设置淡入时间,单位s,误差1s
+ u8 fade_out_time;//设置淡出时间,单位s,误差1s
+ float ratio_thr;//设置判断阈值百分比,范围:0~1
+} wind_info_t;
+static wind_info_t wind_info_anc = {
+ .time = 1000, //ms
+ .fade_timer = 0,
+ .wind_cnt = 0,
+ .wind_eng = 0,
+ .last_lvl = 0,
+ .preset_lvl = 0,
+ .fade_in_cnt = 0,
+ .fade_out_cnt = 0,
+ .wind_process_flag = 0,
+ .fade_in_time = 4, //s
+ .fade_out_time = 10, //s
+ .ratio_thr = 0.8f,
+};
+
+void audio_adt_wn_process_fade_timer(void *p)
+{
+ wind_info_t *wind_info = (wind_info_t *)p;
+
+ wind_info->fade_timer = 0;
+
+ /*计算当前计算帧的风噪等级:求当前计算帧内的平均值*/
+ wind_info->preset_lvl = (float)((float)wind_info->wind_eng / wind_info->wind_cnt) * (1.0 / wind_info->ratio_thr);
+ printf("=========================cnt %d, eng %d, avg %d", wind_info->wind_cnt, wind_info->wind_eng, wind_info->preset_lvl);
+ wind_info->wind_cnt = 0;
+ wind_info->wind_eng = 0;
+ if (wind_info->preset_lvl > wind_info->last_lvl) {
+ /*与上一次比较,风噪变大*/
+ wind_info->fade_in_cnt ++;
+ wind_info->fade_out_cnt = 0;
+ } else if (wind_info->preset_lvl < wind_info->last_lvl) {
+ /*与上一次比较,风噪变小*/
+ wind_info->fade_in_cnt = 0;
+ wind_info->fade_out_cnt ++;;
+ } else {
+ /*与上一次比较,风噪可能是变大,也可能是变小*/
+ wind_info->fade_in_cnt ++;
+ wind_info->fade_out_cnt ++;;
+ }
+
+ /*判断是否到达淡入淡出的时间*/
+ if (wind_info->fade_in_cnt >= (wind_info->fade_in_time * 1000 / wind_info->time)) {
+ wind_info->fade_in_cnt = 0;
+ wind_info->fade_out_cnt = 0;
+ wind_info->wind_process_flag = 1;
+ } else if (wind_info->fade_out_cnt >= (wind_info->fade_out_time * 1000 / wind_info->time)) {
+ wind_info->fade_in_cnt = 0;
+ wind_info->fade_out_cnt = 0;
+ wind_info->wind_process_flag = 1;
+ }
+
+}
+
+int audio_anc_wind_noise_process_fade(wind_info_t *wind_info, u8 anc_wind_noise_lvl)
+{
+ if (wind_info->fade_timer == 0) {
+ wind_info->fade_timer = sys_s_hi_timerout_add(wind_info, audio_adt_wn_process_fade_timer, wind_info->time);
+ }
+
+ wind_info->wind_cnt ++;
+ wind_info->wind_eng += anc_wind_noise_lvl;
+ if (wind_info->wind_process_flag) {
+ wind_info->wind_process_flag = 0;
+ printf("anc_wind_noise_lvl %x : %d", (int)wind_info, wind_info->preset_lvl);
+ wind_info->last_lvl = wind_info->preset_lvl;
+ return wind_info->preset_lvl;
+ }
+ return 0;
+}
+
+/*anc风噪检测的处理*/
+void audio_anc_wind_noise_process(u8 wind_lvl)
+{
+ u8 anc_wind_noise_lvl = 0;
+
+ /*anc模式下才改anc增益*/
+ if (anc_mode_get() == ANC_ON) {
+ /*划分风噪等级*/
+ anc_wind_noise_lvl = get_icsd_anc_wind_noise_lvl(&wind_lvl_det_anc, wind_lvl);
+ /* printf(" ========== anc_wind_noise_lvl %d", anc_wind_noise_lvl); */
+
+ /*做淡入淡出时间处理,返回0表示不做处理维持原来的增益不变*/
+ anc_wind_noise_lvl = audio_anc_wind_noise_process_fade(&wind_info_anc, anc_wind_noise_lvl);
+ if (anc_wind_noise_lvl == 0) {
+ return;
+ }
+ } else {
+ return;
+ }
+
+ u16 anc_fade_gain = 16384;
+ /*根据风噪等级改变anc增益*/
+ switch (anc_wind_noise_lvl) {
+ case ANC_WIND_NOISE_LVL0:
+ anc_fade_gain = 16384;
+ break;
+ case ANC_WIND_NOISE_LVL1:
+ anc_fade_gain = 10000;
+ break;
+ case ANC_WIND_NOISE_LVL2:
+ anc_fade_gain = 8000;
+ break;
+ case ANC_WIND_NOISE_LVL3:
+ anc_fade_gain = 6000;
+ break;
+ case ANC_WIND_NOISE_LVL4:
+ anc_fade_gain = 3000;
+ break;
+ case ANC_WIND_NOISE_LVL5:
+ anc_fade_gain = 0;
+ break;
+ }
+
+ u8 data[4] = {0};
+ data[0] = SYNC_ICSD_ADT_SET_ANC_FADE_GAIN;
+ data[1] = anc_fade_gain & 0xff;
+ data[2] = (anc_fade_gain >> 8) & 0xff;
+ audio_icsd_adt_info_sync(data, 4);
+}
+
+static u8 audio_speak_to_chat_idle_query()
+{
+ return speak_to_chat_hdl ? 0 : 1;
+}
+
+REGISTER_LP_TARGET(speak_to_chat_lp_target) = {
+ .name = "speak_to_chat",
+ .is_idle = audio_speak_to_chat_idle_query,
+};
+
+#endif /*(defined TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN) && TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
diff --git a/apps/common/icsd/adt/icsd_adt_app.h b/apps/common/icsd/adt/icsd_adt_app.h
new file mode 100644
index 0000000..4648de9
--- /dev/null
+++ b/apps/common/icsd/adt/icsd_adt_app.h
@@ -0,0 +1,189 @@
+#ifndef __ICSD_ADT_APP_H_
+#define __ICSD_ADT_APP_H_
+
+#include "typedef.h"
+#include "icsd_anc_user.h"
+// #include "icsd_adt_client_board.h"
+
+#define SPEAK_TO_CHAT_TASK_NAME "speak_to_chat"
+
+/*智能免摘检测到声音和退出通透是否播放提示音*/
+#define SPEAK_TO_CHAT_PLAY_TONE_EN 1
+
+/*智能免摘每次检测到声音的测试提示音*/
+#define SPEAK_TO_CHAT_TEST_TONE_EN 0
+
+/* 通过蓝牙spp发送风噪信息
+ * 需要同时打开USER_SUPPORT_PROFILE_SPP和APP_ONLINE_DEBUG*/
+#define ICSD_ADT_WIND_INFO_SPP_DEBUG_EN 0
+
+enum {
+ AUDIO_ADT_CLOSE = 0, //关闭关闭
+ AUDIO_ADT_OPEN, //打开状态
+ AUDIO_ADT_CHAT, //免摘状态
+};
+
+enum {
+ ANC_WIND_NOISE_LVL0 = 1,
+ ANC_WIND_NOISE_LVL1,
+ ANC_WIND_NOISE_LVL2,
+ ANC_WIND_NOISE_LVL3,
+ ANC_WIND_NOISE_LVL4,
+ ANC_WIND_NOISE_LVL5,
+};
+
+enum {
+ WIND_AREA_TAP_DOUBLE_CLICK = 2, //双击
+ WIND_AREA_TAP_THIRD_CLICK, //三击
+ WIND_AREA_TAP_MULTIPLE_CLICK, //大于3次多次连击
+};
+
+enum {
+ ADT_MODE_CLOSE = 0,
+ ADT_SPEAK_TO_CHAT_MODE = BIT(0), //智能免摘
+ ADT_WIND_NOISE_DET_MODE = BIT(1),//风噪检测
+ ADT_WIDE_AREA_TAP_MODE = BIT(2), //广域点击
+};
+
+enum {
+ /*任务消息*/
+ ICSD_ADT_VOICE_STATE = 1,
+ ICSD_ADT_WIND_LVL,
+ ICSD_ADT_WAT_RESULT,
+ ICSD_ADT_TONE_PLAY,
+ SPEAK_TO_CHAT_TASK_KILL,
+ ICSD_ANC_MODE_SWITCH,
+ ICSD_ADT_STATE_SYNC,
+
+ /*对耳信息同步*/
+ SYNC_ICSD_ADT_VOICE_STATE,
+ SYNC_ICSD_ADT_WIND_LVL_CMP,
+ SYNC_ICSD_ADT_WAT_RESULT,
+ SYNC_ICSD_ADT_WIND_LVL_RESULT,
+ SYNC_ICSD_ADT_SUSPEND,
+ SYNC_ICSD_ADT_OPEN,
+ SYNC_ICSD_ADT_CLOSE,
+ SYNC_ICSD_ADT_SET_ANC_FADE_GAIN,
+};
+
+/*打开智能免摘*/
+int audio_speak_to_chat_open();
+
+/*关闭智能免摘*/
+int audio_speak_to_chat_close();
+
+void audio_speak_to_chat_demo();
+
+/*设置免摘定时结束的时间,单位ms*/
+int audio_speak_to_char_end_time_set(u16 time);
+
+/*设置智能免摘检测的灵敏度*/
+int audio_speak_to_chat_sensitivity_set(u8 sensitivity);
+
+/*获取是否需要先开anc再开免摘的状态*/
+u8 get_adt_open_in_anc_state();
+
+void audio_anc_mode_switch_in_adt(u8 anc_mode);
+
+/*打开声音检测*/
+int audio_acoustic_detector_open();
+
+/*关闭声音检测*/
+int audio_acoustic_detector_close();
+
+int audio_speak_to_chat_open_in_anc_done();
+
+void audio_icsd_adt_resume();
+void audio_icsd_adt_suspend();
+/*char 定时结束后从通透同步恢复anc on /anc off*/
+void audio_speak_to_char_suspend(void);
+void audio_speak_to_char_sync_suspend(void);
+
+/*获取智能免摘是否打开*/
+u8 audio_speak_to_chat_is_running();
+
+/*获取智能免摘状态*/
+u8 get_speak_to_chat_state();
+
+/*获取adt的模式*/
+u8 get_icsd_adt_mode();
+
+/*同步tws配对时,同步adt的状态*/
+void audio_anc_icsd_adt_state_sync(u8 *data);
+void audio_icsd_adt_state_sync_done(u8 adt_mode, u8 speak_to_chat_state);
+
+/*检测到讲话状态同步*/
+void set_speak_to_chat_voice_state(u8 state);
+void audio_speak_to_chat_voice_state_sync(void);
+
+int anc_adt_init();
+
+int audio_icsd_adt_open(u8 adt_mode);
+int audio_icsd_adt_sync_open(u8 adt_mode);
+/*打开所有模块*/
+int audio_icsd_adt_open_all();
+
+int audio_icsd_adt_sync_close(u8 adt_mode);
+int audio_icsd_adt_close(u8 adt_mode);
+int audio_icsd_adt_res_close(u8 adt_mode);
+/*关闭所有模块*/
+int audio_icsd_adt_close_all();
+
+u8 audio_icsd_adt_is_running();
+
+/*打开广域点击*/
+int audio_wat_click_open();
+
+/*关闭广域点击*/
+int audio_wat_click_close();
+
+/*设置是否忽略广域点击
+ * ingore: 1 忽略点击,0 响应点击
+ * 忽略点击的时间,单位ms*/
+int audio_wide_area_tap_ignore_flag_set(u8 ignore, u16 time);
+
+/*广域点击开关demo*/
+void audio_wat_click_demo();
+
+/*广域点击事件处理*/
+void audio_wat_area_tap_event_handle(u8 wat_result);
+
+/*打开风噪检测*/
+int audio_icsd_wind_detect_open();
+
+/*关闭风噪检测*/
+int audio_icsd_wind_detect_close();
+
+/*获取风噪等级*/
+u8 get_audio_icsd_wind_lvl();
+
+/*风噪检测开关demo*/
+void audio_icsd_wind_detect_demo();
+
+/*风噪检测处理*/
+void audio_anc_wind_noise_process(u8 wind_lvl);
+
+/*参数更新接口*/
+int audio_acoustic_detector_updata();
+void set_icsd_adt_param_updata();
+
+/*获取免摘需要多少个mic*/
+u8 get_icsd_adt_mic_num();
+
+extern void set_anc_adt_state(u8 state);
+extern void *get_anc_lfb_coeff();
+extern void *get_anc_lff_coeff();
+extern void *get_anc_ltrans_coeff();
+extern void *get_anc_ltrans_fb_coeff();
+extern float get_anc_gains_l_fbgain();
+extern float get_anc_gains_l_ffgain();
+extern float get_anc_gains_l_transgain();
+extern float get_anc_gains_lfb_transgain();
+extern u8 get_anc_l_fbyorder();
+extern u8 get_anc_l_ffyorder();
+extern u8 get_anc_l_transyorder();
+extern u8 get_anc_lfb_transyorder();
+extern u32 get_anc_gains_alogm();
+extern u32 get_anc_gains_trans_alogm();
+
+#endif
diff --git a/apps/common/icsd/adt/icsd_adt_client_board.c b/apps/common/icsd/adt/icsd_adt_client_board.c
new file mode 100644
index 0000000..d27d7b8
--- /dev/null
+++ b/apps/common/icsd/adt/icsd_adt_client_board.c
@@ -0,0 +1,296 @@
+#if ADT_CLIENT_BOARD == HT03_HYBRID_6G
+const u8 ADT_TWS_MODE = 1;
+//const u8 ADT_DET_VER = 2;
+//const u8 ADT_PATH_CONFIG = 0;
+const u8 ADT_DET_VER = 4;
+const u8 ADT_PATH_CONFIG = ADT_PATH_DAC_SRC_EN;
+const u8 ADT_EIN_VER = ADT_EIN_TWS_V0;
+const float ref_gain_sel = 3;
+const float err_gain_sel = 3;
+u8 pnc_ref_pwr_thr = 160;
+u8 pnc_err_pwr_thr = 100;
+u8 tpc_ref_pwr_thr = 120;
+u8 tpc_err_pwr_thr = 100;
+u8 anc_ref_pwr_thr = 120;
+u8 anc_err_pwr_thr = 100;
+const float wat_pn_gain = 1;
+const float wat_bypass_gain = 16;
+const float wat_anc_gain = 1;
+const u8 final_speech_even_thr = 4;
+const float wdac_senc = 1;
+const float wdac[8] = {1, 1, 0.92, 0.80, 0.67, 0.62, 0.7, 0.7};//播放一笑江湖DJ /100
+const float wref[8] = {6.78, 3.66, 0.58, 0.37, 0.31, 0.29, 0.28, 0.27};//播放外部噪声
+const float wref_tran[8] = {1.26, 1.06, 1.06, 1.00, 1.00, 1.18, 1.16, 1.03 };
+const float wref_ancs[8] = {2.06, 2.00, 0.011, 0.006, 0.009, 0.012, 0.014, 0.018 };
+const float fdac[8] = {0.18, 0.051, 0.02, 0.02, 0.02, 0.02, 0.02, 0.05};//播放一笑江湖DJ /1000
+u8 icsd_get_ang_flag(float *_target_angle)
+{
+ u8 af1 = _target_angle[1] > 15 || _target_angle[1] < -130;
+ u8 af2 = _target_angle[2] > 15 || _target_angle[2] < -130;
+ u8 af3 = _target_angle[3] > 15 || _target_angle[3] < -130;
+ u8 ang_flag = af1 && af2 && af3;
+ return ang_flag;
+}
+
+#elif ADT_CLIENT_BOARD == G96_HYBRID
+const u8 ADT_TWS_MODE = 1;
+//const u8 ADT_DET_VER = 5;
+//const u8 ADT_PATH_CONFIG = 0;
+const u8 ADT_DET_VER = 4;
+const u8 ADT_PATH_CONFIG = ADT_PATH_DAC_SRC_EN;
+const u8 ADT_EIN_VER = ADT_EIN_TWS_V0;
+const float ref_gain_sel = 4;
+const float err_gain_sel = 1;
+u8 pnc_ref_pwr_thr = 160;
+u8 pnc_err_pwr_thr = 100;
+u8 tpc_ref_pwr_thr = 120;
+u8 tpc_err_pwr_thr = 100;
+u8 anc_ref_pwr_thr = 120;
+u8 anc_err_pwr_thr = 135;
+const float wat_pn_gain = 2.4;
+const float wat_bypass_gain = 16;
+const float wat_anc_gain = 2.5;
+const u8 final_speech_even_thr = 4;
+const float wdac_senc = 1;
+const float wdac[8] = {2.98, 2.29, 1.94, 1.95, 1.76, 1.54, 1.44, 1.29};
+const float wref[8] = {6.76, 1.98, 1.57, 1.50, 1.41, 1.32, 1.16, 1.02};
+const float wref_tran[8] = {4.26, 2.36, 2.36, 2.79, 3.00, 3.18, 3.16, 3.03 };
+const float wref_ancs[8] = {2.06, 2.00, 0.11, 0.06, 0.09, 0.12, 0.14, 0.18 };
+const float fdac[8] = {0.008, 0.008, 0.008, 0.008, 0.01, 0.01, 0.01, 0.01};
+u8 icsd_get_ang_flag(float *_target_angle)
+{
+ u8 af1 = _target_angle[4] < 15 && _target_angle[4] > -150;
+ u8 af2 = _target_angle[2] < 15 && _target_angle[2] > -150;
+ u8 af3 = _target_angle[3] < 15 && _target_angle[3] > -150;
+ u8 ang_flag = af1 && af2 && af3;
+ return ang_flag;
+}
+
+#elif ADT_CLIENT_BOARD == G97_HYBRID
+const u8 ADT_TWS_MODE = 1;
+const u8 ADT_DET_VER = 3;
+const u8 ADT_PATH_CONFIG = 0;
+//const u8 ADT_DET_VER = 4;
+//const u8 ADT_PATH_CONFIG = ADT_PATH_DAC_SRC_EN;
+const u8 ADT_EIN_VER = ADT_EIN_UNSUPPORT;
+const float ref_gain_sel = 2;
+const float err_gain_sel = 1;
+u8 pnc_ref_pwr_thr = 160;
+u8 pnc_err_pwr_thr = 100;
+u8 tpc_ref_pwr_thr = 120;
+u8 tpc_err_pwr_thr = 100;
+u8 anc_ref_pwr_thr = 120;
+u8 anc_err_pwr_thr = 135;
+const float wat_pn_gain = 2.88;
+const float wat_bypass_gain = 19.2;
+const float wat_anc_gain = 3;
+const u8 final_speech_even_thr = 4;
+const float wdac_senc = 1;
+const float wdac[8] = {10.43, 4.85, 1.36, 1.09, 0.87, 0.71, 0.63, 0.59};
+const float wref[8] = {7.31, 1.90, 0.43, 0.33, 0.28, 0.25, 0.22, 0.20};
+const float wref_tran[8] = {8.23, 3.33, 1.72, 1.64, 1.48, 1.30, 1.12, 1.04};
+const float wref_ancs[8] = {4.62, 1.32, 0.09, 0.06, 0.07, 0.10, 0.13, 0.15 };
+const float fdac[8] = {0.18, 0.051, 0.02, 0.02, 0.02, 0.02, 0.02, 0.05};
+u8 icsd_get_ang_flag(float *_target_angle)
+{
+ u8 af1 = _target_angle[1] < -120 || _target_angle[1] > 20;
+ u8 af2 = _target_angle[2] < -120 || _target_angle[2] > 20;
+ u8 af3 = _target_angle[3] < -120 || _target_angle[3] > 20;
+ u8 ang_flag = af1 && af2 && af3;
+
+ printf("ang:%d %d %d af:%d %d %d\n", (int)_target_angle[1], (int)_target_angle[2], (int)_target_angle[3], af1, af2, af3);
+ return ang_flag;
+}
+
+#elif ADT_CLIENT_BOARD == H3_HYBRID
+const u8 ADT_TWS_MODE = 0;
+const u8 ADT_DET_VER = 1;
+const u8 ADT_PATH_CONFIG = 0;
+const u8 ADT_EIN_VER = ADT_EIN_HEADSET_V0;
+const float ref_gain_sel = 3;
+const float err_gain_sel = 3;
+u8 pnc_ref_pwr_thr = 160;
+u8 pnc_err_pwr_thr = 100;
+u8 tpc_ref_pwr_thr = 120;
+u8 tpc_err_pwr_thr = 100;
+u8 anc_ref_pwr_thr = 120;
+u8 anc_err_pwr_thr = 135;
+const float wat_pn_gain = 1;
+const float wat_bypass_gain = 16;
+const float wat_anc_gain = 1;
+const u8 final_speech_even_thr = 4;
+const float wdac_senc = 1;
+const float wref[8] = {6.78, 3.66, 0.58, 0.37, 0.31, 0.29, 0.28, 0.27};
+const float wdac[8] = {1, 1, 0.92, 0.80, 0.67, 0.62, 0.7, 0.7};
+const float wref_tran[8] = {4.26, 2.36, 2.36, 2.79, 3.00, 3.18, 3.16, 3.03 };
+const float wref_ancs[8] = {2.06, 2.00, 0.011, 0.006, 0.009, 0.012, 0.014, 0.018 };
+const float fdac[8] = {0.18, 0.051, 0.02, 0.02, 0.02, 0.02, 0.02, 0.05};
+
+#elif ADT_CLIENT_BOARD == ANC05_HYBRID
+const u8 ADT_TWS_MODE = 0;
+const u8 ADT_DET_VER = 1;
+const u8 ADT_PATH_CONFIG = 0;
+const u8 ADT_EIN_VER = ADT_EIN_UNSUPPORT;
+const float ref_gain_sel = 3;
+const float err_gain_sel = 3;
+u8 pnc_ref_pwr_thr = 160;
+u8 pnc_err_pwr_thr = 100;
+u8 tpc_ref_pwr_thr = 120;
+u8 tpc_err_pwr_thr = 100;
+u8 anc_ref_pwr_thr = 120;
+u8 anc_err_pwr_thr = 135;
+const float wat_pn_gain = 1;
+const float wat_bypass_gain = 16;
+const float wat_anc_gain = 1;
+const u8 final_speech_even_thr = 4;
+const float wdac_senc = 1;
+const float wref[8] = {6.78, 3.66, 0.58, 0.37, 0.31, 0.29, 0.28, 0.27};
+const float wdac[8] = {1, 1, 0.92, 0.80, 0.67, 0.62, 0.7, 0.7};
+const float wref_tran[8] = {4.26, 2.36, 2.36, 2.79, 3.00, 3.18, 3.16, 3.03 };
+const float wref_ancs[8] = {2.06, 2.00, 0.011, 0.006, 0.009, 0.012, 0.014, 0.018 };
+const float fdac[8] = {0.18, 0.051, 0.02, 0.02, 0.02, 0.02, 0.02, 0.05};
+
+#else
+const float wdac_senc = 1;
+const u8 ADT_TWS_MODE = 1;
+const u8 ADT_DET_VER = 0;
+const u8 ADT_PATH_CONFIG = 0;
+const u8 ADT_EIN_VER = ADT_EIN_UNSUPPORT;
+const float ref_gain_sel = 3;
+const float err_gain_sel = 3;
+u8 pnc_ref_pwr_thr = 160;
+u8 pnc_err_pwr_thr = 100;
+u8 tpc_ref_pwr_thr = 120;
+u8 tpc_err_pwr_thr = 100;
+u8 anc_ref_pwr_thr = 120;
+u8 anc_err_pwr_thr = 135;
+const float wat_pn_gain = 1;
+const float wat_bypass_gain = 16;
+const float wat_anc_gain = 1;
+const u8 final_speech_even_thr = 4;
+const float wref[8] = {6.78, 3.66, 0.58, 0.37, 0.31, 0.29, 0.28, 0.27};
+const float wdac[8] = {1, 1, 0.92, 0.80, 0.67, 0.62, 0.7, 0.7};
+const float wref_tran[8] = {4.26, 2.36, 2.36, 2.79, 3.00, 3.18, 3.16, 3.03 };
+const float wref_ancs[8] = {2.06, 2.00, 0.011, 0.006, 0.009, 0.012, 0.014, 0.018 };
+const float fdac[8] = {0.18, 0.051, 0.02, 0.02, 0.02, 0.02, 0.02, 0.05};
+
+#endif
+
+void icsd_adt_ein_parm_HT03(__icsd_adt_parm *_ADT_PARM)
+{
+ _ADT_PARM->anc_in_pz_sum = -80;
+ _ADT_PARM->anc_out_pz_sum = 0;
+ _ADT_PARM->anc_in_sz_mean = 1;
+ _ADT_PARM->anc_out_sz_mean = -12;
+ _ADT_PARM->anc_in_fb_sum = 60;
+ _ADT_PARM->anc_out_fb_sum = 30;
+
+ _ADT_PARM->pnc_in_pz_sum = -80;
+ _ADT_PARM->pnc_out_pz_sum = 0;
+ _ADT_PARM->pnc_in_sz_mean = 1;
+ _ADT_PARM->pnc_out_sz_mean = -12;
+ _ADT_PARM->pnc_in_fb_sum = 60;
+ _ADT_PARM->pnc_out_fb_sum = 30;
+
+ _ADT_PARM->trans_in_pz_sum = 2;
+ _ADT_PARM->trans_out_pz_sum = 26;
+ _ADT_PARM->trans_in_sz_mean = 2;
+ _ADT_PARM->trans_out_sz_mean = -7;
+ _ADT_PARM->trans_in_fb_sum = 20;
+ _ADT_PARM->trans_out_fb_sum = -20;
+}
+
+void icsd_adt_ein_parm(__icsd_adt_parm *_ADT_PARM)
+{
+ _ADT_PARM->anc_in_pz_sum = -80;
+ _ADT_PARM->anc_out_pz_sum = 0;
+ _ADT_PARM->anc_in_sz_mean = 1;
+ _ADT_PARM->anc_out_sz_mean = -12;
+ _ADT_PARM->anc_in_fb_sum = 60;
+ _ADT_PARM->anc_out_fb_sum = 30;
+
+ _ADT_PARM->pnc_in_pz_sum = -80;
+ _ADT_PARM->pnc_out_pz_sum = 0;
+ _ADT_PARM->pnc_in_sz_mean = 1;
+ _ADT_PARM->pnc_out_sz_mean = -12;
+ _ADT_PARM->pnc_in_fb_sum = 60;
+ _ADT_PARM->pnc_out_fb_sum = 30;
+
+ _ADT_PARM->trans_in_pz_sum = 2;
+ _ADT_PARM->trans_out_pz_sum = 26;
+ _ADT_PARM->trans_in_sz_mean = 2;
+ _ADT_PARM->trans_out_sz_mean = -7;
+ _ADT_PARM->trans_in_fb_sum = 20;
+ _ADT_PARM->trans_out_fb_sum = -20;
+}
+
+void icsd_adt_voice_board_data()
+{
+ __icsd_adt_parm *ADT_PARM;
+
+ ADT_PARM = zalloc(sizeof(__icsd_adt_parm));
+#if ADT_CLIENT_BOARD == HT03_HYBRID_6G
+ adt_printf("ADT HT03\n");
+ extern const float HT03_ADT_FLOAT_DATA[];
+ extern const float HT03_sz_out_data[28];
+ extern const float HT03_pz_out_data[28];
+ ADT_PARM->adt_float_data = (void *)HT03_ADT_FLOAT_DATA;
+ ADT_PARM->sz_inptr = (float *)HT03_sz_out_data;
+ ADT_PARM->pz_inptr = (float *)HT03_pz_out_data;
+ icsd_adt_ein_parm_HT03(ADT_PARM);
+
+#elif ADT_CLIENT_BOARD == G96_HYBRID
+ adt_printf("ADT G96\n");
+ extern const float G96_ADT_FLOAT_DATA[];
+ extern const float G96_sz_out_data[28];
+ extern const float G96_pz_out_data[28];
+ ADT_PARM->adt_float_data = (void *)G96_ADT_FLOAT_DATA;
+ ADT_PARM->sz_inptr = (float *)G96_sz_out_data;
+ ADT_PARM->pz_inptr = (float *)G96_pz_out_data;
+ icsd_adt_ein_parm(ADT_PARM);
+
+#elif ADT_CLIENT_BOARD == G97_HYBRID
+ adt_printf("ADT G97\n");
+ extern const float G97_ADT_FLOAT_DATA[];
+ extern const float G97_sz_out_data[28];
+ extern const float G97_pz_out_data[28];
+ ADT_PARM->adt_float_data = (void *)G97_ADT_FLOAT_DATA;
+ ADT_PARM->sz_inptr = (float *)G97_sz_out_data;
+ ADT_PARM->pz_inptr = (float *)G97_pz_out_data;
+ icsd_adt_ein_parm(ADT_PARM);
+
+#elif ADT_CLIENT_BOARD == H3_HYBRID
+ adt_printf("ADT H3\n");
+ extern const float H3_ADT_FLOAT_DATA[];
+ extern const float H3_sz_out_data[28];
+ extern const float H3_pz_out_data[28];
+ ADT_PARM->adt_float_data = (void *)H3_ADT_FLOAT_DATA;
+ ADT_PARM->sz_inptr = (float *)H3_sz_out_data;
+ ADT_PARM->pz_inptr = (float *)H3_pz_out_data;
+ icsd_adt_ein_parm(ADT_PARM);
+
+#elif ADT_CLIENT_BOARD == ANC05_HYBRID
+ adt_printf("ADT ANC05\n");
+ extern const float ANC05_ADT_FLOAT_DATA[];
+ extern const float ANC05_sz_out_data[28];
+ extern const float ANC05_pz_out_data[28];
+ ADT_PARM->adt_float_data = (void *)ANC05_ADT_FLOAT_DATA;
+ ADT_PARM->sz_inptr = (float *)ANC05_sz_out_data;
+ ADT_PARM->pz_inptr = (float *)ANC05_pz_out_data;
+ icsd_adt_ein_parm(ADT_PARM);
+
+#else
+ adt_printf("ADT XXX\n");
+#endif
+
+ icsd_adt_parm_set(ADT_PARM);
+ free(ADT_PARM);
+
+ icsd_adt_szout_init();
+}
+
+
+
+
+
+
diff --git a/apps/common/icsd/anc/icsd_anc.h b/apps/common/icsd/anc/icsd_anc.h
new file mode 100644
index 0000000..db11ae4
--- /dev/null
+++ b/apps/common/icsd/anc/icsd_anc.h
@@ -0,0 +1,457 @@
+#ifndef _SD_ANC_LIB_H
+#define _SD_ANC_LIB_H
+
+#include "asm/anc.h"
+#include "timer.h"
+#include "math.h"
+
+#if 0
+#define _anc_printf printf //打开自适应ANC参数调试信息
+#else
+extern int anc_printf_off(const char *format, ...);
+#define _anc_printf anc_printf_off
+#endif
+
+#if 0
+#define icsd_printf printf
+#else
+#define icsd_printf(...)
+#endif
+
+#define ANC_TRAIN_TIMEOUT_S 5//10//秒
+#define TWS_STA_SIBLING_CONNECTED 0x00000002//tws已连接
+
+#define ANC_USER_TRAIN_DMA_LEN 16384
+
+#define TEST_JT_OFF 0
+
+#define ANC_DEBUG_OFF 0
+#define ANC_DEBUG_TONEL_SZ_DATA 1
+#define ANC_DEBUG_TONER_SZ_DATA 2
+#define ANC_DEBUG_PZ_DATA 3
+#define ANC_DEBUG_BYPASS_SIGN 4
+extern const u8 ICSD_ANC_DEBUG;
+
+#define ANC_FUN_TARGET_SYNC BIT(0)
+extern const u16 ICSD_ANC_FUN;
+
+//FF_FB_EN
+#define ICSD_DFF_AFB_EN BIT(7)
+#define ICSD_AFF_DFB_EN BIT(6)
+#define ICSD_FB_TRAIN_OFF BIT(5)
+#define ICSD_FB_TRAIN_NEW BIT(4)
+//TEST_ANC_COMBINATION
+#define TEST_ANC_COMBINATION_OFF 0x00
+#define TEST_TFF_TFB_TONE 0x01 // bypassl强制失败
+#define TEST_TFF_TFB_BYPASS 0x02 // tonel强制失败
+#define TEST_TFF_DFB 0x03 // FB训练强制失败
+#define TEST_DFF_TFB 0x04 // PZ强制失败
+#define TEST_DFF_DFB 0x05 // tonel,bypassl,PZ强制失败
+#define TEST_DFF_DFB_2 0x06 // tonel,PZ强制失败
+//TEST_ANC_TRAIN
+#define TEST_ANC_TRAIN_OFF 0x01
+#define TEST_FF_TRAIN_PASS 0x02 // 强制每次训练都成功
+#define TEST_TRAIN_FAIL 0x03 // 强制每次训练都失败
+
+#define TWS_TONE_BYPASS_MODE 1
+#define TWS_BYPASS_MODE 2
+#define HEADSET_TONE_BYPASS_MODE 3
+#define HEADSET_BYPASS_MODE 4
+#define HEADSET_TONES_MODE 5
+#define TWS_TONE_MODE 6
+//user_train_state------------------------
+#define ANC_USER_TRAIN_DMA_READY BIT(0)
+#define ANC_USER_TRAIN_TOOL_DATA BIT(1)
+#define ANC_DAC_MODE_H1_DIFF BIT(2)
+#define ANC_USER_TRAIN_DMA_EN BIT(3)
+#define ANC_USER_TRAIN_TONEMODE BIT(4)
+#define ANC_TRAIN_TONE_PLAY BIT(5)
+#define ANC_TRAIN_TONE_END BIT(6)
+#define ANC_TRAIN_TONE_FIRST BIT(7)
+#define ANC_TRAIN_IIR_READY BIT(8)
+#define ANC_MASTER_RX_PZSYNC BIT(9)
+#define ANC_FB_IIR_AB_DONE BIT(10)
+#define ANC_FF_IIR_AB_DONE BIT(11)
+#define ANC_PZOUT_INITED BIT(12)
+#define ANC_SZOUT_INITED BIT(13)
+#define ANC_USER_TRAIN_RUN BIT(14)
+#define ANC_TRAIN_TIMEOUT BIT(15)
+#define ANC_TRAIN_DMA_ON BIT(16)
+#define ANC_TONE_DAC_ON BIT(17)
+#define ANC_TONE_ANC_READY BIT(18)
+#define ANC_TONESMODE_BYPASS_OFF BIT(19)
+#define ANC_RX_TARGET BIT(20)
+#define ANC_TARGET_DONE BIT(21)
+//icsd_anc_contral
+#define ICSD_ANC_FORCED_EXIT BIT(0)
+#define ICSD_ANC_SUSPENDED BIT(1)
+#define ICSD_ANC_FADE_GAIN_RESUME BIT(2)
+#define ICSD_ANC_TONE_END BIT(3)
+#define ICSD_ANC_INITED BIT(4)
+#define ICSD_ANC_FORCED_BEFORE_INIT BIT(5)
+//anctask cmd
+enum {
+ ANC_CMD_FORCED_EXIT = 0,
+ ANC_CMD_TONE_MODE_START,
+ ANC_CMD_TONEL_START,
+ ANC_CMD_TONER_START,
+ ANC_CMD_PZL_START,
+ ANC_CMD_PZR_START,
+ ANC_CMD_TONE_DACON,
+ ANC_CMD_TRAIN_AFTER_TONE,
+ ANC_CMD_TARGET_END,
+ ANC_CMD_TARGET_HANDLE,
+};
+//SZPZ->anc_err---------------------------
+#define ANC_ERR_LR_BALANCE BIT(0)//左右耳不平衡
+#define ANC_ERR_SOUND_PRESSURE BIT(1)//低声压
+#define ANC_ERR_SHAKE BIT(2)//抖动
+//icsd_anc_function-----------------------
+#define ANC_ADAPTIVE_CMP BIT(0)
+#define ANC_EARPHONE_CHECK BIT(1)
+
+#define TARLEN 120
+#define TARLEN_L 40
+#define DRPPNT 10
+#define ANC_FBANC_OUT_SEL_L 13
+#define ANC_FFANC_OUT_SEL_L 12
+
+
+
+struct icsd_anc_tws_packet {
+ s8 *data;
+ u16 len;
+};
+
+struct icsd_anc_board_param {
+ u8 iir_mode;
+ void *anc_db;
+ void *anc_data_l;
+ void *anc_data_r;
+ void *anc_double_data_l;
+ void *anc_double_data_r;
+ u8 default_ff_gain;
+ u8 default_fb_gain;
+ s8 tool_ffgain_sign;
+ s8 tool_fbgain_sign;
+ s8 tool_target_sign;
+ s8 tfb_sign;
+ s8 tff_sign;
+ s8 bfb_sign;
+ s8 bff_sign;
+ s8 bypass_sign;
+ float m_value_l; //80 ~ 200 //135 最深点位置中心值
+ float sen_l; //12 ~ 22 //18 最深点深度
+ float in_q_l; //0.4 ~ 1.2 //0.6 最深点降噪宽度
+ float m_value_r; //80 ~ 200 //135 最深点位置中心值
+ float sen_r; //12 ~ 22 //18 最深点深度
+ float in_q_r; //0.4 ~ 1.2 //0.6 最深点降噪宽度
+ float *mse_tar;
+ int gold_curve_en;
+ float gain_a_param;
+ u8 gain_a_en;
+ u8 cmp_abs_en;
+ u8 jt_en;
+ int idx_begin;
+ int idx_end;
+ u8 FB_NFIX;
+ u16 fb_w2r;
+ float sen_offset_l;
+ float sen_offset_r;
+ u8 gain_min_offset;
+ u8 gain_max_offset;
+ u8 ff_target_fix_num_l;
+ u8 ff_target_fix_num_r;
+ u8 pz_max_times;
+ u8 bypass_max_times;
+ u8 ff_yorder;
+ u8 fb_yorder;
+ u8 cmp_yorder;
+ int cmp_type[8];
+ float cmp_thd_low;
+ float cmp_thd_high;
+ float bypass_volume;
+ float minvld;
+ //ctl
+ u8 mode;
+ u8 FF_FB_EN;
+ u8 dma_belong_to;
+ u32 tone_jiff;
+ int IIR_NUM;// 4 3
+ int IIR_NUM_FIX;// 4 8-IIR_NUM
+ int IIR_COEF; //(IIR_NUM * 3+1)
+ u8 JT_MODE;
+ float *anc_szl_out;
+ float *anc_szr_out;
+ float sz_priority_thr;
+};
+extern struct icsd_anc_board_param *ANC_BOARD_PARAM;
+
+struct icsd_anc_backup {
+ int gains_alogm;
+ u8 gains_l_ffmic_gain;
+ u8 gains_l_fbmic_gain;
+ u8 gains_r_ffmic_gain;
+ u8 gains_r_fbmic_gain;
+ float gains_l_ffgain;
+ float gains_l_fbgain;
+ float gains_r_ffgain;
+ float gains_r_fbgain;
+ double *lff_coeff;
+ double *lfb_coeff;
+ double *rff_coeff;
+ double *rfb_coeff;
+ u8 lff_yorder;
+ u8 lfb_yorder;
+ u8 rff_yorder;
+ u8 rfb_yorder;
+ u8 ff_1st_dcc;
+ u8 fb_1st_dcc;
+ u8 ff_2nd_dcc;
+ u8 fb_2nd_dcc;
+ u8 gains_drc_en;
+};
+extern volatile struct icsd_anc_backup *CFG_BACKUP;
+
+struct icsd_anc {
+ audio_anc_t *param;
+ u16 *anc_fade_gain;
+ u8 mode;
+ u8 train_index;
+ u8 adaptive_run_busy; //自适应训练中
+ int *gains_alogm;
+ u8 *gains_l_ffmic_gain;
+ u8 *gains_l_fbmic_gain;
+ u8 *gains_r_ffmic_gain;
+ u8 *gains_r_fbmic_gain;
+ float *gains_l_ffgain;
+ float *gains_l_fbgain;
+ float *gains_l_cmpgain;
+ float *gains_r_ffgain;
+ float *gains_r_fbgain;
+ float *gains_r_cmpgain;
+ double **lff_coeff;
+ double **lfb_coeff;
+ double **lcmp_coeff;
+ double **rff_coeff;
+ double **rfb_coeff;
+ double **rcmp_coeff;
+ u8 *lff_yorder;
+ u8 *lfb_yorder;
+ u8 *lcmp_yorder;
+ u8 *rff_yorder;
+ u8 *rfb_yorder;
+ u8 *rcmp_yorder;
+ u8 *ff_1st_dcc;
+ u8 *fb_1st_dcc;
+ u8 *ff_2nd_dcc;
+ u8 *fb_2nd_dcc;
+ u8 *gains_drc_en;
+ void *src_hdl;
+ u32 dac_on_jiff;
+ u32 dac_on_slience;
+ int tone_delay;
+};
+extern volatile struct icsd_anc ICSD_ANC;
+
+struct icsd_anc_tool_data {
+ int h_len;
+ int yorderb;//int fb_yorder;
+ int yorderf;//int ff_yorder;
+ int yorderc;//int cmp_yorder;
+ float *h_freq;
+ float *data_out1;//float *hszpz_out_l;
+ float *data_out2;//float *hpz_out_l;
+ float *data_out3;//float *htarget_out_l;
+ float *data_out4;//float *fb_fgq_l;
+ float *data_out5;//float *ff_fgq_l;
+ float *data_out6;//float *hszpz_out_r;
+ float *data_out7;//float *hpz_out_r;
+ float *data_out8;//float *htarget_out_r;
+ float *data_out9;//float *fb_fgq_r;,
+ float *data_out10;//float *ff_fgq_r;
+ float *data_out11;//float *cmp_fgq_l;
+ float *data_out12;//float *cmp_fgq_r;
+ float *data_out13;//float *tool_target_out_l;
+ float *data_out14;//float *tool_target_out_r;
+ float *wz_temp;
+ u8 result;
+ u8 anc_err;
+ u8 save_idx;
+ u8 use_idx;
+ u8 tws_use_idx;
+ u8 anc_combination;
+ u8 cmp_result;
+};
+extern volatile struct icsd_anc_tool_data *TOOL_DATA;
+
+enum {
+ TFF_TFB = 0,
+ TFF_DFB,
+ DFF_TFB,
+ DFF_DFB,
+};
+
+enum {
+ ICSD_FULL_INEAR = 0,
+ ICSD_HALF_INEAR,
+ ICSD_HEADSET,
+};
+extern const u8 ICSD_EP_TYPE;
+
+extern int (*anc_printf)(const char *format, ...);
+extern int icsd_anc_id;
+extern volatile u8 icsd_anc_function;
+extern volatile u8 icsd_anc_contral;
+extern volatile int user_train_state;
+extern u32 train_time;
+extern u16 icsd_time_out_hdl;
+extern u8 icsd_anc_combination_test;
+extern u8 icsd_anc_train_test;
+extern const u8 TWS_MODE;
+extern const u8 HEADSET_MODE;
+extern const u8 NEW_PRE_TREAT;
+extern const u8 icsd_dcc[4];
+extern const u8 FF_VERSION;
+extern const u8 cmp_iir_type[];
+extern const u8 ff_iir_type[];
+extern const u8 fb_iir_type[];
+//LIB调用的算术函数
+extern float complex_abs_float(float x, float y);
+extern float sin_float(float x);
+extern float cos_float(float x);
+extern float cos_hq(float x);
+extern float sin_hq(float x);
+extern float log10_float(float x);
+extern float exp_float(float x);
+extern float root_float(float x);
+extern float anc_pow10(float n);
+extern float angle_float(float x, float y);
+extern void icsd_anc_save_with_idx(u8 save_idx);
+extern void audio_adc_mic_demo_close(void);
+extern void icsd_anc_board_config();
+//SDK调用的SDANC APP函数
+
+extern void icsd_anc_dma_done();
+extern void icsd_anc_end(audio_anc_t *param);
+extern void icsd_anc_run();
+extern void icsd_anc_setparam();
+extern void icsd_anc_timeout_handler();
+extern void icsd_anc_init(audio_anc_t *param, u8 mode, u8 seq, int tone_delay, u8 tws_balance_en);
+extern u16 sys_timeout_add(void *priv, void (*func)(void *priv), u32 msec);
+extern void icsd_anc_tone_play_start();
+extern void icsd_anctone_dacon(u32 slience_frames, u16 sample_rate);
+extern u8 icsd_anc_train_result_get(struct icsd_anc_tool_data *TOOL_DATA);
+
+//SDANC APP调用的库函数
+extern void icsd_anc_cmd_packet(s8 *data, u8 cmd);
+extern void icsd_anc_tws_sync_cmd(void *_data, u16 len, bool rx);
+extern void icsd_anc_version();
+extern void icsd_anc_lib_init();
+extern void icsd_anc_htarget_data_send_end();
+extern void icsd_anc_mode_init(int tone_delay);
+extern void icsd_anc_train_after_tone();
+extern void icsd_anc_m2s_packet(s8 *data, u8 cmd);
+extern void icsd_anc_s2m_packet(s8 *data, u8 cmd);
+extern void icsd_anc_msync_packet(struct icsd_anc_tws_packet *packet, u8 cmd);
+extern void icsd_anc_ssync_packet(struct icsd_anc_tws_packet *packet, u8 cmd);
+extern void icsd_anc_m2s_cb(void *_data, u16 len, bool rx);
+extern void icsd_anc_s2m_cb(void *_data, u16 len, bool rx);
+extern void icsd_anc_msync_cb(void *_data, u16 len, bool rx);
+extern void icsd_anc_ssync_cb(void *_data, u16 len, bool rx);
+extern void cal_wz(double *ab, float gain, int tap, float *freq, float fs, float *wz, int len);
+extern void ff_fgq_2_aabb(double *iir_ab, float *ff_fgq);
+extern float icsd_anc_vmdata_match(float *_vmdata, float gain);
+extern void icsd_anc_tonemode_start();
+extern float icsd_anc_default_match();
+extern void icsd_anc_anctask_cmd_handle(u8 cmd);
+extern void icsd_anc_board_param_init();
+extern void icsd_anc_tool_data_init();
+//SDANC APP调用的SDK函数
+
+extern void icsd_biquad2ab_out(float gain, float f, float fs, float q, double *a0, double *a1, double *a2, double *b0, double *b1, double *b2, int type);
+extern void biquad2ab_double(float gain, float f, float q, double *a0, double *a1, double *a2, double *b0, double *b1, double *b2, int type);
+extern int tws_api_get_role(void);
+extern int tws_api_get_tws_state();
+extern void anc_dma_on(u8 out_sel, int *buf, int len);
+extern void audio_anc_fade2(int gain, u8 en, u8 step, u8 slow);
+extern void anc_user_train_process(audio_anc_t *param);
+extern void audio_anc_post_msg_user_train_run(void);
+extern void audio_anc_post_msg_user_train_setparam(void);
+extern void audio_anc_post_msg_user_train_timeout(void);
+extern unsigned int hw_fft_config(int N, int log2N, int is_same_addr, int is_ifft, int is_real);
+extern void hw_fft_run(unsigned int fft_config, const int *in, int *out);
+extern void anc_user_train_cb(u8 mode, u8 result, u8 forced_exit);
+//库调用的SDANC APP函数
+extern void icsd_anc_set_alogm(void *_param, int alogm);
+extern void icsd_anc_set_micgain(void *_param, int lff_gain, int lfb_gain);
+extern void icsd_anc_fade(void *_param);
+extern void icsd_anc_long_fade(void *_param);
+extern void icsd_anc_user_train_dma_on(u8 out_sel, u32 len, int *buf);
+extern void icsd_anc_htarget_data_send();
+extern void icsd_anc_fft(int *in, int *out);
+extern u32 icsd_anc_get_role();
+extern u32 icsd_anc_get_tws_state();
+extern void icsd_anc_tws_m2s(u8 cmd);
+extern void icsd_anc_tws_s2m(u8 cmd);
+extern void icsd_anc_tws_msync(u8 cmd);
+extern void icsd_anc_tws_ssync(u8 cmd);
+extern void icsd_anc_train_timeout();
+extern void icsd_anc_src_init(int in_rate, int out_rate, int (*handler)(void *, void *, int));
+extern void icsd_anc_src_write(void *data, int len);
+extern u8 icsd_anc_get_save_idx();
+extern void icsd_anc_vmdata_num_reset();
+extern u8 icsd_anc_get_vmdata_num();
+extern u8 icsd_anc_min_diff_idx();
+extern void icsd_anc_fgq_printf(float *ptr);
+extern void icsd_anc_aabb_printf(double *iir_ab);
+extern void icsd_anc_vmdata_by_idx(double *ff_ab, float *ff_gain, u8 idx);
+extern void icsd_anc_vmdatar_by_idx(double *ff_ab, float *ff_gain, u8 idx);
+extern void icsd_anc_config_inf();
+extern void icsd_anc_ear_record_printf();
+extern u8 icsd_anc_tooldata_select_vmdata(float *ff_fgq);
+extern u8 icsd_anc_tooldata_select_vmdata_headset(float *ff_fgq_l, float *ff_fgq_r);
+extern void icsd_audio_adc_mic_open(u8 mic_idx, u8 gain, u16 sr, u8 mic_2_dac);
+extern void icsd_audio_adc_mic_close();
+extern void sd_anc_exit();
+
+extern void icsd_anc_tonel_start(void *priv);
+extern void icsd_anc_toner_start(void *priv);
+extern void icsd_anc_pzl_start(void *priv);
+extern void icsd_anc_pzr_start(void *priv);
+extern void anc_dmadata_debug();
+extern void icsd_anc_fft256(int *in, int *out);
+extern void icsd_anc_src_push();
+extern void anc_core_dma_stop(void);
+extern void anc_core_dma_ie(u8 en);
+extern void icsd_anc_forced_exit();
+extern void audio_anc_post_msg_icsd_anc_cmd(u8 cmd);
+extern void icsd_anctone_dacon_handler();
+extern void icsd_anc_forced_exit_end();
+extern float anc_pow10(float n);
+
+
+enum {
+ SD_ANC_TWS = 0,
+ SD_ANC_HEADSET,
+};
+
+struct icsd_anc_libfmt {
+ int lib_alloc_size; //算法ram需求大小
+};
+
+struct icsd_anc_infmt {
+ void *alloc_ptr; //外部申请的ram地址
+};
+
+extern void icsd_anc_set_infmt(struct icsd_anc_infmt *fmt);
+extern void icsd_anc_get_libfmt(struct icsd_anc_libfmt *libfmt, u8 type);
+
+extern const float THD_JT;
+extern const float THD_JT_SAVE;
+extern const float THD_JT2;
+extern const float spl_tb [21];
+extern const float spl_freq_tb [21];
+extern const float target_cmp_dat[];
+
+#endif
diff --git a/apps/common/icsd/anc/icsd_anc_app.c b/apps/common/icsd/anc/icsd_anc_app.c
new file mode 100644
index 0000000..10aff97
--- /dev/null
+++ b/apps/common/icsd/anc/icsd_anc_app.c
@@ -0,0 +1,756 @@
+#include "icsd_anc_app.h"
+#include "classic/tws_api.h"
+#include "board_config.h"
+#include "tone_player.h"
+#include "adv_adaptive_noise_reduction.h"
+#include "audio_anc.h"
+#include "asm/audio_src.h"
+#include "icsd_anc_user.h"
+
+#if 1
+#define icsd_anc_log printf
+#else
+#define icsd_anc_log(...)
+#endif/*log_en*/
+
+#if TCFG_AUDIO_ANC_EAR_ADAPTIVE_EN
+
+#if (ICSD_ANC_MODE == TWS_TONE_BYPASS_MODE) || \
+ (ICSD_ANC_MODE == TWS_TONE_MODE) || \
+ (ICSD_ANC_MODE == TWS_BYPASS_MODE)
+const u8 TWS_MODE = 1;
+#else
+const u8 TWS_MODE = 0;
+#endif/**/
+#if (ICSD_ANC_MODE == HEADSET_TONE_BYPASS_MODE) || \
+ (ICSD_ANC_MODE == HEADSET_BYPASS_MODE) || \
+ (ICSD_ANC_MODE == HEADSET_TONES_MODE)
+const u8 HEADSET_MODE = 1;
+#else
+const u8 HEADSET_MODE = 0;
+#endif/**/
+
+const u8 ICSD_ANC_DEBUG = ICSD_ANC_DEBUG_TYPE;
+u32 train_time;
+struct icsd_anc_board_param *ANC_BOARD_PARAM = NULL;
+volatile struct icsd_anc_tool_data *TOOL_DATA = NULL;
+volatile struct icsd_anc_backup *CFG_BACKUP = NULL;
+volatile struct icsd_anc ICSD_ANC;
+volatile u8 icsd_anc_contral = 0;
+volatile u8 icsd_anc_function = 0;
+int *user_train_buf = 0;
+volatile int user_train_state = 0;
+u16 icsd_time_out_hdl = 0;
+u8 icsd_anc_combination_test;
+u8 icsd_anc_train_test;
+int icsd_anc_id = 0;
+u8 icsd_anc_tws_balance_en = 0;
+
+
+int (*anc_printf)(const char *format, ...);
+int anc_printf_off(const char *format, ...)
+{
+ return 0;
+}
+
+#define TWS_FUNC_ID_SDANC_M2S TWS_FUNC_ID('I', 'C', 'M', 'S')
+REGISTER_TWS_FUNC_STUB(icsd_anc_m2s) = {
+ .func_id = TWS_FUNC_ID_SDANC_M2S,
+ .func = icsd_anc_m2s_cb,
+};
+
+#define TWS_FUNC_ID_SDANC_S2M TWS_FUNC_ID('I', 'C', 'S', 'M')
+REGISTER_TWS_FUNC_STUB(icsd_anc_s2m) = {
+ .func_id = TWS_FUNC_ID_SDANC_S2M,
+ .func = icsd_anc_s2m_cb,
+};
+
+#define TWS_FUNC_ID_SDANC_MSYNC TWS_FUNC_ID('I', 'C', 'M', 'N')
+REGISTER_TWS_FUNC_STUB(icsd_anc_msync) = {
+ .func_id = TWS_FUNC_ID_SDANC_MSYNC,
+ .func = icsd_anc_msync_cb,
+};
+
+#define TWS_FUNC_ID_SDANC_SSYNC TWS_FUNC_ID('I', 'C', 'S', 'N')
+REGISTER_TWS_FUNC_STUB(icsd_anc_ssync) = {
+ .func_id = TWS_FUNC_ID_SDANC_SSYNC,
+ .func = icsd_anc_ssync_cb,
+};
+
+void icsd_anc_tws_msync(u8 cmd)
+{
+ struct icsd_anc_tws_packet packet;
+ icsd_anc_msync_packet(&packet, cmd);
+ anc_printf("msync:%d %d\n", packet.len, packet.data[0]);
+ int ret = tws_api_send_data_to_sibling(packet.data, packet.len, TWS_FUNC_ID_SDANC_MSYNC);
+}
+
+void icsd_anc_tws_ssync(u8 cmd)
+{
+ struct icsd_anc_tws_packet packet;
+ icsd_anc_ssync_packet(&packet, cmd);
+ anc_printf("ssync:%d %d\n", packet.len, packet.data[0]);
+ int ret = tws_api_send_data_to_sibling(packet.data, packet.len, TWS_FUNC_ID_SDANC_SSYNC);
+}
+
+void icsd_anc_tws_m2s(u8 cmd)
+{
+ s8 data[16];
+ icsd_anc_m2s_packet(data, cmd);
+ int ret = tws_api_send_data_to_sibling(data, 16, TWS_FUNC_ID_SDANC_M2S);
+}
+
+void icsd_anc_tws_s2m(u8 cmd)
+{
+ s8 data[16];
+ icsd_anc_s2m_packet(data, cmd);
+ int ret = tws_api_send_data_to_sibling(data, 16, TWS_FUNC_ID_SDANC_S2M);
+}
+
+float anc_pow10(float n)
+{
+ float pow10n = exp_float((float)n / log10_float(exp_float((float)1.0)));
+ return pow10n;
+}
+
+void icsd_anc_fgq_printf(float *ptr)
+{
+ icsd_anc_log("icsd_anc_fgq\n");
+ for (int i = 0; i < ANC_VMDATA_FF_RECORD_SIZE; i++) {
+ icsd_anc_log("%d\n", (int)((*ptr++) * 1000));
+ }
+}
+
+void icsd_anc_aabb_printf(double *iir_ab)
+{
+ icsd_anc_log("icsd_anc_aabb\n");
+ for (int i = 0; i < ANC_BOARD_PARAM->fb_yorder; i++) {
+ icsd_anc_log("AB:%d %d %d %d %d\n", (int)(iir_ab[i * 5] * 100000000),
+ (int)(iir_ab[i * 5 + 1] * 100000000),
+ (int)(iir_ab[i * 5 + 2] * 100000000),
+ (int)(iir_ab[i * 5 + 3] * 100000000),
+ (int)(iir_ab[i * 5 + 4] * 100000000));
+ }
+ //put_buf(iir_ab, 8 * 40);
+}
+
+void icsd_anc_forced_exit()
+{
+ if (!(icsd_anc_contral & ICSD_ANC_FORCED_EXIT)) {
+ icsd_printf("icsd_anc_forced_exit----------------------------\n");
+ if (icsd_anc_contral & ICSD_ANC_INITED) {
+ icsd_anc_contral |= ICSD_ANC_FORCED_EXIT;
+ audio_anc_post_msg_icsd_anc_cmd(ANC_CMD_FORCED_EXIT);
+ } else {
+ icsd_anc_contral |= ICSD_ANC_FORCED_BEFORE_INIT;
+ }
+ }
+}
+
+void icsd_anc_train_timeout()
+{
+ icsd_anc_log("icsd_anc_train_timeout\n");
+ user_train_state &= ~ANC_USER_TRAIN_RUN;
+ user_train_state |= ANC_TRAIN_TIMEOUT;
+ audio_anc_post_msg_user_train_timeout();
+}
+
+u32 icsd_anc_get_role()
+{
+ return tws_api_get_role();
+}
+
+u32 icsd_anc_get_tws_state()
+{
+ if (icsd_anc_tws_balance_en) {
+ return tws_api_get_tws_state();
+ }
+ return 0;
+}
+
+void icsd_anc_set_alogm(void *_param, int alogm)
+{
+ audio_anc_t *param = _param;
+ param->gains.alogm = alogm;
+}
+
+void icsd_anc_set_micgain(void *_param, int lff_gain, int lfb_gain)
+{
+ //0 ~ 15
+ audio_anc_t *param = _param;
+ icsd_anc_log("mic gain set:%d %d-->%d %d\n", param->gains.l_ffmic_gain, param->gains.l_fbmic_gain, lff_gain, lfb_gain);
+ param->gains.l_ffmic_gain = lff_gain;
+ param->gains.l_fbmic_gain = lfb_gain;
+ audio_anc_mic_management(param);
+ audio_anc_mic_gain(param->mic_param, 0);
+}
+
+void icsd_anc_fft(int *in, int *out)
+{
+ u32 fft_config;
+ fft_config = hw_fft_config(1024, 10, 1, 0, 1);
+ hw_fft_run(fft_config, in, out);
+}
+void icsd_anc_fft256(int *in, int *out)
+{
+ u32 fft_config;
+ fft_config = hw_fft_config(256, 8, 1, 0, 1);
+ hw_fft_run(fft_config, in, out);
+}
+void icsd_anc_fade(void *_param)
+{
+ audio_anc_t *param = _param;
+ audio_anc_fade2(param->anc_fade_gain, param->anc_fade_en, 1, 0);
+}
+
+void icsd_anc_long_fade(void *_param)
+{
+ audio_anc_t *param = _param;
+ audio_anc_fade2(0, param->anc_fade_en, 4, 0); //增益先淡出到0
+ os_time_dly(10);//10
+}
+
+void icsd_anc_user_train_dma_on(u8 out_sel, u32 len, int *buf)
+{
+ user_train_state |= ANC_TRAIN_DMA_ON;
+ anc_dma_on(out_sel, buf, len);
+}
+
+void icsd_anc_dma_done()
+{
+ if (ICSD_ANC.adaptive_run_busy) {
+ if (user_train_state & ANC_USER_TRAIN_DMA_EN) {
+ if (user_train_state & ANC_USER_TRAIN_DMA_READY) {
+ user_train_state &= ~ANC_USER_TRAIN_DMA_READY;
+ anc_core_dma_stop();
+ audio_anc_post_msg_user_train_run();
+ } else {
+ user_train_state |= ANC_USER_TRAIN_DMA_READY;
+ }
+ }
+ }
+}
+
+
+void *anc_ram_addr = 0;
+void sd_anc_exit()
+{
+ if (anc_ram_addr) {
+ free(anc_ram_addr);
+ anc_ram_addr = 0;
+ }
+ printf("sd_anc_exit");
+ mem_stats();
+}
+void sd_anc_init()
+{
+ anc_printf = _anc_printf;
+ printf("sd anc init\n");
+ mem_stats();
+ struct icsd_anc_libfmt libfmt;
+ icsd_anc_get_libfmt(&libfmt, SD_ANC_TWS);
+ if (anc_ram_addr == 0) {
+ anc_ram_addr = zalloc(libfmt.lib_alloc_size);
+ }
+ struct icsd_anc_infmt infmt;
+ infmt.alloc_ptr = anc_ram_addr;
+ icsd_anc_set_infmt(&infmt);
+ printf("ram init:%d\n", libfmt.lib_alloc_size);
+}
+
+void icsd_anc_init(audio_anc_t *param, u8 mode, u8 seq, int tone_delay, u8 tws_balance_en)
+{
+ sd_anc_init();
+ anc_printf = _anc_printf;
+ icsd_anc_contral |= ICSD_ANC_INITED;
+ if (icsd_anc_contral & ICSD_ANC_FORCED_BEFORE_INIT) {
+ icsd_anc_contral &= ~ICSD_ANC_FORCED_BEFORE_INIT;
+ icsd_anc_forced_exit();
+ }
+ if (icsd_anc_contral & ICSD_ANC_FORCED_EXIT) {
+ icsd_printf("icsd_anc_init FORCED EXIT\n");
+ return;
+ }
+ icsd_anc_id = seq;
+ icsd_anc_tws_balance_en = tws_balance_en;
+ icsd_anc_log("sd anc init:%d, seq %d, tone_delay %d, tws_balance %d ======================================\n", seq, tone_delay, icsd_anc_id, tws_balance_en);
+ mem_stats();
+ user_train_state = 0;
+ icsd_anc_function = 0;
+ if (mode == 1) {
+ user_train_state |= ANC_USER_TRAIN_TOOL_DATA;
+ icsd_anc_tool_data_init();
+ }
+ user_train_state |= ANC_TRAIN_TONE_PLAY;
+ icsd_anc_combination_test = TEST_ANC_COMBINATION;
+ icsd_anc_train_test = TEST_ANC_TRAIN;
+#if ANC_USER_TRAIN_TONE_MODE
+ user_train_state |= ANC_USER_TRAIN_TONEMODE;
+#endif
+#if HEADSET_TONES_MODE_BYPASS_OFF
+ user_train_state |= ANC_TONESMODE_BYPASS_OFF;
+#endif
+#if ANC_ADAPTIVE_CMP_EN
+ icsd_anc_function |= ANC_ADAPTIVE_CMP;
+#endif
+#if ANC_EARPHONE_CHECK_EN
+ icsd_anc_function |= ANC_EARPHONE_CHECK;
+#endif
+
+ ICSD_ANC.param = param;
+ ICSD_ANC.adaptive_run_busy = 1;
+ ICSD_ANC.anc_fade_gain = ¶m->anc_fade_gain;
+ ICSD_ANC.gains_l_ffgain = ¶m->gains.l_ffgain;
+ ICSD_ANC.gains_l_fbgain = ¶m->gains.l_fbgain;
+ ICSD_ANC.gains_l_cmpgain = ¶m->gains.l_cmpgain;
+ ICSD_ANC.gains_r_ffgain = ¶m->gains.r_ffgain;
+ ICSD_ANC.gains_r_fbgain = ¶m->gains.r_fbgain;
+ ICSD_ANC.gains_r_cmpgain = ¶m->gains.r_cmpgain;
+ ICSD_ANC.lff_yorder = ¶m->lff_yorder;
+ ICSD_ANC.lfb_yorder = ¶m->lfb_yorder;
+ ICSD_ANC.lcmp_yorder = ¶m->lcmp_yorder;
+ ICSD_ANC.rff_yorder = ¶m->rff_yorder;
+ ICSD_ANC.rfb_yorder = ¶m->rfb_yorder;
+ ICSD_ANC.rcmp_yorder = ¶m->rcmp_yorder;
+ ICSD_ANC.lff_coeff = ¶m->lff_coeff;
+ ICSD_ANC.lfb_coeff = ¶m->lfb_coeff;
+ ICSD_ANC.lcmp_coeff = ¶m->lcmp_coeff;
+ ICSD_ANC.rff_coeff = ¶m->rff_coeff;
+ ICSD_ANC.rfb_coeff = ¶m->rfb_coeff;
+ ICSD_ANC.rcmp_coeff = ¶m->rcmp_coeff;
+ ICSD_ANC.gains_l_ffmic_gain = ¶m->gains.l_ffmic_gain;
+ ICSD_ANC.gains_l_fbmic_gain = ¶m->gains.l_fbmic_gain;
+ ICSD_ANC.gains_r_ffmic_gain = ¶m->gains.r_ffmic_gain;
+ ICSD_ANC.gains_r_fbmic_gain = ¶m->gains.r_fbmic_gain;
+ ICSD_ANC.gains_alogm = (int *)(¶m->gains.alogm);
+ ICSD_ANC.ff_1st_dcc = ¶m->gains.ff_1st_dcc;
+ ICSD_ANC.fb_1st_dcc = ¶m->gains.fb_1st_dcc;
+ ICSD_ANC.ff_2nd_dcc = ¶m->gains.ff_2nd_dcc;
+ ICSD_ANC.fb_2nd_dcc = ¶m->gains.fb_2nd_dcc;
+ ICSD_ANC.gains_drc_en = ¶m->gains.drc_en;
+
+ ICSD_ANC.mode = ANC_USER_TRAIN_MODE;
+ ICSD_ANC.train_index = 0;
+ ICSD_ANC.adaptive_run_busy = 1;
+
+ icsd_anc_board_config();
+ user_train_state |= ANC_USER_TRAIN_DMA_EN;
+ TOOL_DATA->save_idx = 0xff;
+ ANC_BOARD_PARAM->iir_mode = ANC_USER_TRAIN_MODE;
+ ANC_BOARD_PARAM->tool_ffgain_sign = 1;
+ ANC_BOARD_PARAM->tool_fbgain_sign = 1;
+ if (param->gains.gain_sign & ANCL_FF_SIGN) {
+ ANC_BOARD_PARAM->tool_ffgain_sign = -1;
+ }
+ if (param->gains.gain_sign & ANCL_FB_SIGN) {
+ ANC_BOARD_PARAM->tool_fbgain_sign = -1;
+ }
+
+ //金机曲线功能==================================
+#if 1
+ icsd_anc_log("ref en:%d----------------------\n", param->gains.adaptive_ref_en);
+ struct icsd_fb_ref *fb_parm = NULL;
+ struct icsd_ff_ref *ff_parm = NULL;
+ if (param->gains.adaptive_ref_en) {
+ icsd_anc_log("get ref data\n");
+ anc_adaptive_fb_ref_data_get((u8 **)(&fb_parm));
+ anc_adaptive_ff_ref_data_get((u8 **)(&ff_parm));
+ ANC_BOARD_PARAM->m_value_l = fb_parm->m_value;
+ ANC_BOARD_PARAM->sen_l = fb_parm->sen;
+ ANC_BOARD_PARAM->in_q_l = fb_parm->in_q;
+ icsd_anc_log("fb_parm:%d %d %d\n", (int)(fb_parm->m_value * 1000), (int)(fb_parm->sen * 1000), (int)(fb_parm->in_q * 1000));
+ }
+ if (ff_parm) {
+ icsd_anc_log("use gold curve==========================================================\n");
+ ANC_BOARD_PARAM->gold_curve_en = param->gains.adaptive_ref_en;
+ ANC_BOARD_PARAM->mse_tar = ff_parm->db;
+ }
+#endif
+ //==============================================
+ icsd_anc_config_inf();
+ icsd_anc_lib_init();
+ icsd_anc_set_alogm(param, ANC_USER_TRAIN_SR_SEL);
+ ICSD_ANC.tone_delay = tone_delay;
+ icsd_anc_mode_init(tone_delay);
+
+}
+
+void icsd_anc_init_cmd()
+{
+ icsd_anc_log("icsd_anc_init_cmd\n");
+ extern void audio_anc_post_msg_user_train_init(u8 mode);
+ audio_anc_post_msg_user_train_init(ANC_ON);
+}
+
+
+u32 icsd_slience_frames;
+u16 icsd_sample_rate;
+void icsd_anctone_dacon_handler()
+{
+ u32 slience_frames = icsd_slience_frames;
+ u16 sample_rate = icsd_sample_rate;
+ if (icsd_anc_contral & ICSD_ANC_FORCED_EXIT) {
+ icsd_printf("icsd_anctone_dacon FORCED EXIT\n");
+ return;
+ }
+ if (user_train_state & ANC_TRAIN_TONE_PLAY) {
+ icsd_anc_board_param_init();
+ ANC_BOARD_PARAM->mode = ICSD_ANC_MODE;
+ icsd_anc_log("icsd_anctone_dacon 1:%d %d %d\n", (int)jiffies, slience_frames, sample_rate);
+ user_train_state |= ANC_TONE_DAC_ON;
+ user_train_state &= ~ANC_TRAIN_TONE_PLAY;
+ u32 slience_ms = 0;
+ if ((slience_frames != 0) && (sample_rate != 0)) {
+ slience_ms = (slience_frames * 1000 / sample_rate) + 1;
+ icsd_anc_log("icsd_anctone_dacon 2:%d %d %d\n", slience_frames, sample_rate, slience_ms);
+ }
+ ANC_BOARD_PARAM->tone_jiff = jiffies + (slience_ms / 10) + 1;
+ ICSD_ANC.dac_on_jiff = jiffies;
+ ICSD_ANC.dac_on_slience = slience_ms;
+ if (user_train_state & ANC_TONE_ANC_READY) {
+ icsd_anc_log("dac on set tonemode start timeout:%d %d\n", slience_ms, ANC_BOARD_PARAM->tone_jiff);
+ switch (ANC_BOARD_PARAM->mode) {
+ case HEADSET_TONES_MODE:
+ sys_hi_timeout_add((void *)icsd_anc_id, icsd_anc_tonel_start, slience_ms + TONEL_DELAY);
+ sys_hi_timeout_add((void *)icsd_anc_id, icsd_anc_toner_start, slience_ms + TONER_DELAY);
+ sys_hi_timeout_add((void *)icsd_anc_id, icsd_anc_pzl_start, slience_ms + PZL_DELAY);
+ sys_hi_timeout_add((void *)icsd_anc_id, icsd_anc_pzr_start, slience_ms + PZR_DELAY);
+ break;
+ default:
+ sys_hi_timeout_add((void *)icsd_anc_id, icsd_anc_tonemode_start, slience_ms + ICSD_ANC.tone_delay);
+ break;
+ }
+ } else {
+ icsd_anc_log("dac on wait anc ready\n");
+ }
+ }
+}
+
+void icsd_anctone_dacon(u32 slience_frames, u16 sample_rate)
+{
+ icsd_slience_frames = slience_frames;
+ icsd_sample_rate = sample_rate;
+ audio_anc_post_msg_icsd_anc_cmd(ANC_CMD_TONE_DACON);
+}
+
+void icsd_anc_tone_play_start()
+{
+#if ANC_USER_TRAIN_TONE_MODE
+ icsd_anc_log("icsd_anc_tone_play_start\n");
+ user_train_state |= ANC_TRAIN_TONE_PLAY;
+ icsd_anc_init_cmd();
+ os_time_dly(20);
+#endif
+}
+
+u8 icsd_anc_adaptive_busy_flag_get(void)
+{
+ return ICSD_ANC.adaptive_run_busy;
+}
+
+#if ANC_EAR_RECORD_EN
+/* float vmdata_FL[EAR_RECORD_MAX][25]; */
+/* float vmdata_FR[EAR_RECORD_MAX][25]; */
+float (*vmdata_FL)[ANC_VMDATA_FF_RECORD_SIZE] = NULL;
+float (*vmdata_FR)[ANC_VMDATA_FF_RECORD_SIZE] = NULL;
+int *vmdata_num;
+
+void icsd_anc_vmdata_init(float (*FL)[ANC_VMDATA_FF_RECORD_SIZE], float (*FR)[ANC_VMDATA_FF_RECORD_SIZE], int *num)
+{
+ //读取耳道记忆 VM数据地址
+ vmdata_FL = FL;
+ vmdata_FR = FR;
+ vmdata_num = num;
+ /* icsd_anc_log("vmdata_num %d\n", *vmdata_num); */
+ /* put_buf((u8*)vmdata_FL, EAR_RECORD_MAX*ANC_VMDATA_FF_RECORD_SIZE*4); */
+ /* put_buf((u8*)vmdata_FR, EAR_RECORD_MAX*ANC_VMDATA_FF_RECORD_SIZE*4); */
+}
+
+void icsd_anc_vmdata_num_reset()
+{
+ if ((!vmdata_FL) || (!vmdata_FR)) {
+ return;
+ }
+ *vmdata_num = 0;
+ memset(vmdata_FL, 0, EAR_RECORD_MAX * 4 * ANC_VMDATA_FF_RECORD_SIZE);
+}
+
+u8 icsd_anc_get_vmdata_num()
+{
+ return *vmdata_num;
+}
+
+void icsd_anc_ear_record_printf()
+{
+ int i;
+ if ((!vmdata_FL) || (!vmdata_FR)) {
+ return;
+ }
+ icsd_anc_log("vmdata_num:%d\n", *vmdata_num);
+ for (i = 0; i < EAR_RECORD_MAX; i++) {
+ icsd_anc_log("vmdata_FL[%d]\n", i);
+ icsd_anc_fgq_printf(&vmdata_FL[i][0]);
+ }
+ for (i = 0; i < EAR_RECORD_MAX; i++) {
+ icsd_anc_log("vmdata_FR[%d]\n", i);
+ icsd_anc_fgq_printf(&vmdata_FR[i][0]);
+ }
+}
+
+u8 icsd_anc_max_diff_idx()
+{
+ u8 max_diff_idx = 0;
+ if ((!vmdata_FL) || (!vmdata_FR)) {
+ return max_diff_idx;
+ }
+ if (*vmdata_num > 0) {
+ float diff;
+ float max_diff = icsd_anc_vmdata_match(&vmdata_FL[0][0], vmdata_FL[0][0]);
+ max_diff_idx = 0;
+ for (int i = 1; i < *vmdata_num; i++) {
+ diff = icsd_anc_vmdata_match(&vmdata_FL[i][0], vmdata_FL[i][0]);
+ if (diff > max_diff) {
+ max_diff = diff;
+ max_diff_idx = i;
+ }
+ }
+ }
+ icsd_anc_log("max diff idx:%d\n", max_diff_idx);
+ return max_diff_idx;
+}
+
+u8 icsd_anc_min_diff_idx()
+{
+ float diff;
+ float min_diff;
+ u8 min_diff_idx = 0xff;
+
+ if ((!vmdata_FL) || (!vmdata_FR)) {
+ return min_diff_idx;
+ }
+ if (*vmdata_num > 0) {
+ min_diff = icsd_anc_vmdata_match(&vmdata_FL[0][0], vmdata_FL[0][0]);
+ min_diff_idx = 0;
+ icsd_anc_log("DIFF[0]:%d\n", (int)(min_diff * 1000));
+ for (int i = 1; i < *vmdata_num; i++) {
+ diff = icsd_anc_vmdata_match(&vmdata_FL[i][0], vmdata_FL[i][0]);
+ if (diff < min_diff) {
+ min_diff = diff;
+ min_diff_idx = i;
+ }
+ icsd_anc_log("DIFF[%d]:%d %d %d\n", i, (int)(diff * 1000), min_diff_idx, (int)(min_diff * 1000));
+ }
+ diff = icsd_anc_default_match();
+ icsd_anc_log("default diff:%d vmmin diff:%d\n", (int)(diff * 100), (int)(min_diff * 100));
+ if (diff < min_diff) {
+ icsd_anc_log("use default\n");
+ min_diff_idx = 0xff;
+ } else {
+ icsd_anc_log("select vmdata_FL[%d]\n", min_diff_idx);
+ }
+ }
+ return min_diff_idx;
+}
+
+u8 icsd_anc_get_save_idx()
+{
+ u8 save_idx = 0;
+ if (*vmdata_num < EAR_RECORD_MAX) {
+ save_idx = *vmdata_num;
+ } else {
+ save_idx = icsd_anc_max_diff_idx();
+ }
+ icsd_anc_log("icsd_anc_get_save_idx:%d\n", save_idx);
+ return save_idx;
+}
+
+void icsd_anc_save_with_idx(u8 save_idx)
+{
+ anc_printf("save try:%d %d\n", save_idx, *vmdata_num);
+ if ((!vmdata_FL) || (!vmdata_FR)) {
+ return;
+ }
+ if (save_idx > *vmdata_num) {
+ return;
+ }
+ if ((save_idx >= 0) && (save_idx < EAR_RECORD_MAX)) {
+ if (*vmdata_num < EAR_RECORD_MAX) {
+ (*vmdata_num)++;
+ }
+ anc_printf("icsd_anc_save_with_idx:%d %d====================================================\n", save_idx, *vmdata_num);
+ switch (ANC_BOARD_PARAM->mode) {
+ case HEADSET_TONE_BYPASS_MODE:
+ case HEADSET_TONES_MODE:
+ case HEADSET_BYPASS_MODE:
+ memcpy(&vmdata_FL[save_idx][0], TOOL_DATA->data_out5, 4 * ANC_VMDATA_FF_RECORD_SIZE);
+ memcpy(&vmdata_FR[save_idx][0], TOOL_DATA->data_out10, 4 * ANC_VMDATA_FF_RECORD_SIZE);
+ break;
+ default:
+ memcpy(&vmdata_FL[save_idx][0], TOOL_DATA->data_out5, 4 * ANC_VMDATA_FF_RECORD_SIZE);
+ break;
+ }
+#if TEST_EAR_RECORD_EN
+ icsd_anc_log("EAR RECORD SAVE:%d\n", save_idx);
+ icsd_anc_ear_record_printf();
+#endif
+ }
+}
+
+void icsd_anc_vmdata_by_idx(double *ff_ab, float *ff_gain, u8 idx)
+{
+ u8 num = icsd_anc_get_vmdata_num();
+ if ((!vmdata_FL) || (!vmdata_FR)) {
+ return;
+ }
+ if ((num == 0) || (idx == 0xff) || ((num - 1) < idx)) {
+ return;
+ }
+#if TEST_EAR_RECORD_EN
+ icsd_anc_log("EAR RECORD USED RECORD L\n");
+ icsd_anc_fgq_printf(&vmdata_FL[idx][0]);
+#endif
+ ff_fgq_2_aabb(ff_ab, &vmdata_FL[idx][0]);
+ *ff_gain = vmdata_FL[idx][0];
+}
+
+void icsd_anc_vmdatar_by_idx(double *ff_ab, float *ff_gain, u8 idx)
+{
+ u8 num = icsd_anc_get_vmdata_num();
+ if ((!vmdata_FL) || (!vmdata_FR)) {
+ return;
+ }
+ if ((num == 0) || (idx == 0xff) || ((num - 1) < idx)) {
+ return;
+ }
+#if TEST_EAR_RECORD_EN
+ icsd_anc_log("EAR RECORD USED RECORD R\n");
+ icsd_anc_fgq_printf(&vmdata_FR[idx][0]);
+#endif
+ ff_fgq_2_aabb(ff_ab, &vmdata_FR[idx][0]);
+ *ff_gain = vmdata_FR[idx][0];
+}
+
+u8 icsd_anc_tooldata_select_vmdata_headset(float *ff_fgq_l, float *ff_fgq_r)
+{
+ icsd_anc_log("headset train time vm select start:%d\n", (int)((jiffies - train_time) * 10));
+ u8 min_idx = icsd_anc_min_diff_idx();
+ extern void icsd_set_min_idx(u8 minidx);
+ icsd_set_min_idx(min_idx);
+ u8 num = icsd_anc_get_vmdata_num();
+ if ((!vmdata_FL) || (!vmdata_FR)) {
+ return 0;
+ }
+ //icsd_anc_log("icsd_anc_tooldata_select_vmdata:%d %d\n", num, min_idx);
+ if ((num == 0) || (min_idx == 0xff) || ((num - 1) < min_idx)) {
+ icsd_anc_log("use default\n");
+ return 0;
+ }
+ memcpy(ff_fgq_l, &vmdata_FL[min_idx][0], 4 * ANC_VMDATA_FF_RECORD_SIZE);
+ memcpy(ff_fgq_r, &vmdata_FR[min_idx][0], 4 * ANC_VMDATA_FF_RECORD_SIZE);
+
+#if TEST_EAR_RECORD_EN
+ icsd_anc_log("EAR RECORD TOOL_DATA RECORD\n");
+ icsd_anc_fgq_printf(ff_fgq_l);
+ icsd_anc_fgq_printf(ff_fgq_r);
+#endif
+
+ icsd_anc_log("train time vm select end:%d\n", (int)((jiffies - train_time) * 10));
+ icsd_anc_log("headset use record:%d\n", min_idx);
+ return 1;
+}
+
+u8 icsd_anc_tooldata_select_vmdata(float *ff_fgq)
+{
+
+ icsd_anc_log("train time vm select start:%d\n", (int)((jiffies - train_time) * 10));
+ //u8 min_idx = icsd_anc_min_diff_idx();
+ u8 min_idx = TOOL_DATA->use_idx;
+ icsd_printf("use record idx:%d\n", TOOL_DATA->use_idx);
+ extern void icsd_set_min_idx(u8 minidx);
+ icsd_set_min_idx(min_idx);
+ u8 num = icsd_anc_get_vmdata_num();
+ if ((!vmdata_FL) || (!vmdata_FR)) {
+ return 0;
+ }
+ //icsd_anc_log("icsd_anc_tooldata_select_vmdata:%d %d\n", num, min_idx);
+ if ((num == 0) || (min_idx == 0xff) || ((num - 1) < min_idx)) {
+ icsd_anc_log("use default\n");
+ return 0;
+ }
+ memcpy(ff_fgq, &vmdata_FL[min_idx][0], 4 * ANC_VMDATA_FF_RECORD_SIZE);
+
+#if TEST_EAR_RECORD_EN
+ icsd_anc_log("EAR RECORD TOOL_DATA RECORD\n");
+ icsd_anc_fgq_printf(ff_fgq);
+#endif
+
+ icsd_anc_log("train time vm select end:%d\n", (int)((jiffies - train_time) * 10));
+ icsd_anc_log("use record:%d\n", min_idx);
+ return 1;
+}
+#else
+u8 icsd_anc_min_diff_idx()
+{
+ return 0xff;
+}
+u8 icsd_anc_get_save_idx()
+{
+ return 0xff;
+}
+u8 icsd_anc_get_vmdata_num()
+{
+ return 0;
+}
+void icsd_anc_vmdata_num_reset()
+{}
+void icsd_anc_save_with_idx(u8 save_idx)
+{}
+void icsd_anc_vmdata_by_idx(double *ff_ab, float *ff_gain, u8 idx)
+{}
+void icsd_anc_vmdatar_by_idx(double *ff_ab, float *ff_gain, u8 idx)
+{}
+void icsd_anc_ear_record_printf()
+{}
+u8 icsd_anc_tooldata_select_vmdata(float *ff_fgq)
+{
+ return 0;
+}
+u8 icsd_anc_tooldata_select_vmdata_headset(float *ff_fgq_l, float *ff_fgq_r)
+{
+ return 0;
+}
+#endif
+
+
+#if ANC_SZ_OUT_EN
+
+float icsd_anc_sz_data[TARLEN + TARLEN_L];
+float icsd_anc_pz_data[TARLEN + TARLEN_L];
+u8 sz_out_exist = 0;
+
+void icsd_anc_sz_out(float *hz_in)
+{
+ printf("icsd_anc_sz_out\n");
+ memcpy(icsd_anc_sz_data, hz_in, 4 * (TARLEN + TARLEN_L));
+ sz_out_exist = 1;
+ extern void icsd_aeq_demo();
+ icsd_aeq_demo();
+ icsd_printf("train time aeq end:%dms\n", (int)((jiffies - train_time) * 10));
+}
+
+void icsd_anc_pz_out(float *hz_in)
+{
+ printf("icsd_anc_pz_out\n");
+ memcpy(icsd_anc_pz_data, hz_in, 4 * (TARLEN + TARLEN_L));
+ sz_out_exist = 1;
+}
+
+#endif
+
+
+#endif/*TCFG_AUDIO_ANC_EAR_ADAPTIVE_EN*/
+
+
+
+
+
diff --git a/apps/common/icsd/anc/icsd_anc_app.h b/apps/common/icsd/anc/icsd_anc_app.h
new file mode 100644
index 0000000..3f1b5f8
--- /dev/null
+++ b/apps/common/icsd/anc/icsd_anc_app.h
@@ -0,0 +1,151 @@
+#ifndef _ICSD_ANC_APP_H
+#define _ICSD_ANC_APP_H
+
+/*===========接口说明=============================================
+一. void sd_anc_init(audio_anc_t *param,u8 mode)
+ 1.调用该函数启动sd anc训练
+ 2.param为ANC ON模式下的audio_anc_t参数指针
+ 3.mode:0. 普通模式 1. htarget 数据上传模式
+
+二. void sd_anc_htarget_data_send(float *h_freq,float *hszpz_out,float *hpz_out, float *htarget_out,int len)
+ 1.htarget数据上传模式下,当数据准备好后会自动调用该函数
+
+三. void sd_anc_htarget_data_end()
+ 1.htarget数据上传模式下,当数据上传完成后需要调用该函数进入训练后的ANC ON模式
+
+四. void anc_user_train_tone_play_cb()
+ 1.当前ANC ON提示音结束时回调该函数进入 SD ANC 训练
+ 2.SD ANC训练结束后会切换到ANC ON模式
+
+ 1:rdout + lout 2:rdout + rerrmic
+ 3:rdout + rrefmic 4:ldout + lerrmic
+ 5:ldout + lrefmic 6:rerrmic + rrefmic
+ 7:lerrmic + lrefmic
+
+ anc_sr, 0: 11.7k 1: 23.4k 2: 46.9k 3: 93.8k 4: 187.5k 5: 375k 6: 750k 7: 1.5M
+
+================================================================*/
+
+#include "asm/anc.h"
+#include "asm/dac.h"
+#include "app_config.h"
+#include "icsd_anc.h"
+#include "icsd_anc_client_board.h"
+
+#ifndef ADAPTIVE_CLIENT_BOARD
+
+#define ICSD_ANC_MODE TWS_TONE_BYPASS_MODE
+#define ANC_ADAPTIVE_FF_ORDER 8 /*ANC自适应FF滤波器阶数, 原厂指定*/
+#define ANC_ADAPTIVE_FB_ORDER 5 /*ANC自适应FB滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_CMP_ORDER 8 /*ANC自适应CMP滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_RECORD_FF_ORDER 8 /*ANC自适应耳道记忆FF滤波器阶数,原厂指定*/
+#define ANC_FB_TRAIN_OFF 1
+#define ANC_FB_TRAIN_NEW 0
+#define ANC_EARPHONE_CHECK_EN 0
+#define ANC_ADAPTIVE_CMP_EN 1 //自适应CMP补偿
+#define ANC_ADAPTIVE_TONE_DELAY 1570
+
+#endif/*ADAPTIVE_CLIENT_BOARD*/
+
+#define ANC_HEADSET_TONE_00 0
+#define ANC_HEADSET_TONE_01 1
+#define ANC_HEADSET_TONE ANC_HEADSET_TONE_00
+
+#if ANC_HEADSET_TONE == ANC_HEADSET_TONE_00
+#define TONEL_DELAY 50
+#define TONER_DELAY 2400
+#define PZL_DELAY 900
+#define PZR_DELAY 3300
+#else
+#define TONEL_DELAY 50
+#define TONER_DELAY 1000
+#define PZL_DELAY 1900
+#define PZR_DELAY 3200
+#endif
+
+#define TEST_EAR_RECORD_EN 0
+#define TEST_ANC_COMBINATION TEST_ANC_COMBINATION_OFF
+#define TEST_ANC_TRAIN TEST_ANC_TRAIN_OFF
+#define ICSD_ANC_DEBUG_TYPE ANC_DEBUG_OFF
+
+#define ANC_USER_TRAIN_EN 1
+
+#if ICSD_ANC_MODE == HEADSET_BYPASS_MODE
+#define ANC_USER_TRAIN_TONE_MODE 0
+#define BYPASS_MAXTIME 4
+#define PZ_MAXTIME 4
+
+#elif ICSD_ANC_MODE == HEADSET_TONES_MODE
+#define ANC_USER_TRAIN_TONE_MODE 1
+#define BYPASS_MAXTIME 2
+#define PZ_MAXTIME 3
+
+#elif ICSD_ANC_MODE == TWS_BYPASS_MODE
+#define ANC_USER_TRAIN_TONE_MODE 0
+#define BYPASS_MAXTIME 4
+#define PZ_MAXTIME 4
+
+#elif ICSD_ANC_MODE == TWS_TONE_BYPASS_MODE
+#define ANC_USER_TRAIN_TONE_MODE 1
+#define BYPASS_MAXTIME 2
+#define PZ_MAXTIME 3
+
+#elif ICSD_ANC_MODE == TWS_TONE_MODE
+#define ANC_USER_TRAIN_TONE_MODE 1
+#define BYPASS_MAXTIME 2
+#define PZ_MAXTIME 3
+
+#elif ICSD_ANC_MODE == HEADSET_TONE_BYPASS_MODE
+#define ANC_USER_TRAIN_TONE_MODE 1
+#define BYPASS_MAXTIME 2
+#define PZ_MAXTIME 3
+
+#else
+#define ANC_USER_TRAIN_TONE_MODE 0
+#define BYPASS_MAXTIME 4
+#define PZ_MAXTIME 4
+#endif
+
+#define ANC_USER_TRAIN_MODE 2//0:FF 1:FB 2:HY
+#define ANC_USER_TRAIN_SR_SEL 2//46.9k
+#define ANC_EAR_RECORD_EN 1 //耳道记忆
+#define EAR_RECORD_MAX 5
+#define ANC_DFF_AFB_EN 1//默认FF + 自适应FB 1:判断为自适应成功 0:判断为自适应失败
+#define ANC_AFF_DFB_EN 1//默认FB + 自适应FF 1:判断为自适应成功 0:判断为自适应失败
+#define ANC_SZ_OUT_EN 0//自适应SZ输出使能
+#define HEADSET_TONES_MODE_BYPASS_OFF 0
+
+//耳道记忆滤波器保存大小,滤波器组 * 3 + 总增益
+#define ANC_VMDATA_FF_RECORD_SIZE (ANC_ADAPTIVE_RECORD_FF_ORDER * 3) + 1
+
+extern float (*vmdata_FL)[ANC_VMDATA_FF_RECORD_SIZE];//ff fgq
+extern float (*vmdata_FR)[ANC_VMDATA_FF_RECORD_SIZE];//ff fgq
+extern int *vmdata_num;
+
+#define ANC_USE_RECORD 1 //ANC自适应失败使用耳道记忆参数
+#define ANC_SUCCESS 2 //ANC自适应成功
+#define ANC_USE_DEFAULT 3 //ANC自适应使用ICSD内部默认参数,目前不用;
+
+//自适应训练结果 u8
+#define ANC_ADAPTIVE_RESULT_LFF BIT(0) //使用LFF自适应or记忆参数
+#define ANC_ADAPTIVE_RESULT_LFB BIT(1) //使用LFB自适应参数
+#define ANC_ADAPTIVE_RESULT_LCMP BIT(2) //使用LCMP自适应参数
+#define ANC_ADAPTIVE_RESULT_RFF BIT(3) //使用RFF自适应or记忆参数
+#define ANC_ADAPTIVE_RESULT_RFB BIT(4) //使用RFB自适应参数
+#define ANC_ADAPTIVE_RESULT_RCMP BIT(5) //使用RCMP自适应参数
+
+struct icsd_fb_ref {
+ float m_value;
+ float sen;
+ float in_q;
+};
+
+struct icsd_ff_ref {
+ float fre[75];
+ float db[75];
+};
+
+
+extern void icsd_anc_vmdata_init(float (*FL)[ANC_VMDATA_FF_RECORD_SIZE], float (*FR)[ANC_VMDATA_FF_RECORD_SIZE], int *num);
+
+#endif/*_ICSD_ANC_APP_H*/
diff --git a/apps/common/icsd/anc/icsd_anc_board.c b/apps/common/icsd/anc/icsd_anc_board.c
new file mode 100644
index 0000000..806624d
--- /dev/null
+++ b/apps/common/icsd/anc/icsd_anc_board.c
@@ -0,0 +1,422 @@
+#include "board_config.h"
+#include "icsd_anc_app.h"
+#include "tone_player.h"
+#include "audio_anc.h"
+#include "icsd_anc_user.h"
+
+#if 1
+#define icsd_board_log printf
+#else
+#define icsd_board_log(...)
+#endif/*log_en*/
+
+#if TCFG_AUDIO_ANC_EAR_ADAPTIVE_EN
+
+u8 anc_train_result = 0; //ANC自适应训练结果返回值
+u8 IIR_NUM;// 4 3
+u8 IIR_NUM_FIX;// 4 8-IIR_NUM
+u8 IIR_COEF; //(IIR_NUM * 3+1)
+
+/*
+typedef enum {
+ ANC_IIR_HIGH_PASS = 0,
+ ANC_IIR_LOW_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_LOW_SHELF,
+} ANC_iir_type;
+*/
+
+#ifndef ADAPTIVE_CLIENT_BOARD
+const u8 cmp_iir_type[] = {
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 ff_iir_type[] = {
+ ANC_IIR_LOW_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 fb_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 FF_VERSION = 1;
+const u8 NEW_PRE_TREAT = 0;
+const u8 ICSD_EP_TYPE = ICSD_FULL_INEAR;
+const u8 icsd_dcc[4] = {1, 4, 1, 1}; //ff1st,ff2nd,fb12t,fb2nd
+const u16 ICSD_ANC_FUN = 0;
+
+void icsd_xtmp_handler(float *xtmp, float gain_min, float gain_max)
+{
+ if (xtmp[1] < gain_min) {
+ xtmp[1] = (float)gain_min;
+ }
+ if (xtmp[1] > gain_max) {
+ xtmp[1] = (float)gain_max;
+ }
+}
+
+void icsd_anc_board_config()
+{
+ icsd_anc_board_param_init();
+ ANC_BOARD_PARAM->ff_yorder = ANC_ADAPTIVE_FF_ORDER;
+ ANC_BOARD_PARAM->fb_yorder = ANC_ADAPTIVE_FB_ORDER;
+ ANC_BOARD_PARAM->cmp_yorder = ANC_ADAPTIVE_CMP_ORDER;
+
+#define DEFAULT_FF_GAIN 3
+#define DEFAULT_FB_GAIN 3
+ extern const float E108D_DATA[];
+ extern const s8 E108D_s8_DATA[];
+ extern const float E108D_DOUBLE_DATA[];
+ ANC_BOARD_PARAM->anc_data_l = (void *)E108D_DATA;
+ ANC_BOARD_PARAM->anc_data_r = (void *)E108D_DATA;
+ ANC_BOARD_PARAM->anc_db = (void *)E108D_s8_DATA;
+ ANC_BOARD_PARAM->anc_double_data_l = (void *)E108D_DOUBLE_DATA;
+ ANC_BOARD_PARAM->anc_double_data_r = (void *)E108D_DOUBLE_DATA;
+ ANC_BOARD_PARAM->m_value_l = 120.0; //80 ~ 200 最深点位置中心值
+ ANC_BOARD_PARAM->sen_l = 15.0; //12 ~ 22 最深点深度
+ ANC_BOARD_PARAM->in_q_l = 0.4; //0.4 ~ 1.2 最深点降噪宽度
+ ANC_BOARD_PARAM->m_value_r = 120.0; //80 ~ 200 最深点位置中心值
+ ANC_BOARD_PARAM->sen_r = 15.0; //12 ~ 22 最深点深度
+ ANC_BOARD_PARAM->in_q_r = 0.4; //0.4 ~ 1.2 最深点降噪宽度
+ ANC_BOARD_PARAM->sen_offset_l = 11.0 - 18.0;
+ ANC_BOARD_PARAM->sen_offset_r = 11.0 - 18.0;
+ ANC_BOARD_PARAM->ff_target_fix_num_l = 18;
+ ANC_BOARD_PARAM->ff_target_fix_num_r = 18;
+ ANC_BOARD_PARAM->gain_a_param = 25.0;
+ ANC_BOARD_PARAM->gain_a_en = 0;
+ ANC_BOARD_PARAM->cmp_abs_en = 0;
+ ANC_BOARD_PARAM->idx_begin = 18;
+ ANC_BOARD_PARAM->idx_end = 60;
+ ANC_BOARD_PARAM->fb_w2r = 1000;
+ ANC_BOARD_PARAM->FB_NFIX = 3;
+ ANC_BOARD_PARAM->gain_min_offset = 11;
+ ANC_BOARD_PARAM->gain_max_offset = 18;
+ ANC_BOARD_PARAM->minvld = -10.0;
+
+ ANC_BOARD_PARAM->bypass_max_times = BYPASS_MAXTIME;
+ ANC_BOARD_PARAM->pz_max_times = PZ_MAXTIME;
+ ANC_BOARD_PARAM->jt_en = 2;
+ ANC_BOARD_PARAM->tff_sign = 1;
+ ANC_BOARD_PARAM->tfb_sign = -1;
+ ANC_BOARD_PARAM->bff_sign = 1;
+ ANC_BOARD_PARAM->bfb_sign = 1;
+ ANC_BOARD_PARAM->bypass_sign = -1;
+ ANC_BOARD_PARAM->bypass_volume = 0.6; //0.6
+
+ ANC_BOARD_PARAM->tool_target_sign = -1;
+ ANC_BOARD_PARAM->cmp_type[0] = 1;
+ ANC_BOARD_PARAM->cmp_type[1] = 1;
+ ANC_BOARD_PARAM->cmp_type[2] = 0;
+ ANC_BOARD_PARAM->cmp_type[3] = 1;
+ ANC_BOARD_PARAM->cmp_type[4] = 1;
+ ANC_BOARD_PARAM->cmp_type[5] = 1;
+ ANC_BOARD_PARAM->cmp_type[6] = 1;
+ ANC_BOARD_PARAM->cmp_type[7] = 1;
+ ANC_BOARD_PARAM->cmp_thd_low = -40.0;
+ ANC_BOARD_PARAM->cmp_thd_high = 40.0;
+
+ ANC_BOARD_PARAM->IIR_NUM = 3;
+ ANC_BOARD_PARAM->IIR_NUM_FIX = 8 - ANC_BOARD_PARAM->IIR_NUM;
+ ANC_BOARD_PARAM->IIR_COEF = ANC_BOARD_PARAM->IIR_NUM * 3 + 1;
+
+ ANC_BOARD_PARAM->sz_priority_thr = 60;
+ ANC_BOARD_PARAM->JT_MODE = 0;
+
+ if (ANC_BOARD_PARAM->pz_max_times < 3) {
+ ANC_BOARD_PARAM->pz_max_times = 3;
+ }
+
+ if (ANC_BOARD_PARAM->bypass_max_times < 2) {
+ ANC_BOARD_PARAM->pz_max_times = 2;
+ }
+
+ ANC_BOARD_PARAM->mode = ICSD_ANC_MODE;
+ if (ANC_DFF_AFB_EN) {
+ icsd_board_log("ANC_DFF_AFB_EN ON\n");
+ ANC_BOARD_PARAM->FF_FB_EN |= ICSD_DFF_AFB_EN;//BIT(7);
+ }
+ if (ANC_AFF_DFB_EN) {
+ icsd_board_log("ANC_AFF_DFB_EN ON\n");
+ ANC_BOARD_PARAM->FF_FB_EN |= ICSD_AFF_DFB_EN;//BIT(6);
+ }
+ if (ANC_FB_TRAIN_OFF) {
+ ANC_BOARD_PARAM->FF_FB_EN |= ICSD_FB_TRAIN_OFF;//BIT(5);
+ }
+ if (ANC_FB_TRAIN_NEW) {
+ ANC_BOARD_PARAM->FF_FB_EN |= ICSD_FB_TRAIN_NEW;//BIT(4);
+ }
+ ANC_BOARD_PARAM->default_ff_gain = DEFAULT_FF_GAIN;
+ ANC_BOARD_PARAM->default_fb_gain = DEFAULT_FB_GAIN;
+
+ if (TCFG_AUDIO_DAC_MODE == DAC_MODE_H1_DIFF) {
+ user_train_state |= ANC_DAC_MODE_H1_DIFF;
+ } else {
+ user_train_state &= ~ANC_DAC_MODE_H1_DIFF;
+ }
+}
+#else
+
+#include "icsd_anc_client_board.c"
+
+#endif/*ADAPTIVE_CLIENT_BOARD*/
+
+void icsd_anc_config_inf()
+{
+ icsd_board_log("\n=============ANC COMFIG INF================\n");
+
+ icsd_anc_version();
+ switch (ICSD_ANC_MODE) {
+ case TWS_TONE_BYPASS_MODE:
+ icsd_board_log("TWS_TONE_BYPASS_MODE\n");
+ break;
+ case TWS_TONE_MODE:
+ icsd_board_log("TWS_TONE_MODE\n");
+ break;
+ case TWS_BYPASS_MODE:
+ icsd_board_log("TWS_BYPASS_MODE\n");
+ break;
+ case HEADSET_TONE_BYPASS_MODE:
+ icsd_board_log("HEADSET_TONE_BYPASS_MODE\n");
+ break;
+ case HEADSET_TONES_MODE:
+ icsd_board_log("HEADSET_TONES_MODE\n");
+ break;
+ case HEADSET_BYPASS_MODE:
+ icsd_board_log("HEADSET_BYPASS_MODE\n");
+ break;
+ default:
+ icsd_board_log("NEW MODE\n");
+ break;
+ }
+ icsd_board_log("TEST_ANC_COMBINATION:%d\n", TEST_ANC_COMBINATION);
+ icsd_board_log("ANC_ADAPTIVE_CMP_EN:%d\n", ANC_ADAPTIVE_CMP_EN);
+ icsd_board_log("ANC_EAR_RECORD_EN:%d\n", ANC_EAR_RECORD_EN);
+ icsd_board_log("TEST_EAR_RECORD_EN:%d\n", TEST_EAR_RECORD_EN);
+ icsd_board_log("BYPASS_TIMES MIN:2 MAX:%d\n", BYPASS_MAXTIME);
+ icsd_board_log("PZ_TIMES MIN:3 MAX:%d\n", PZ_MAXTIME);
+ icsd_board_log("\n");
+
+#if TEST_EAR_RECORD_EN
+ icsd_board_log("EAR RECORD CURRENT RECORD\n");
+ //icsd_anc_ear_record_icsd_board_log();
+#endif
+}
+
+//训练结果获取API,用于通知应用层当前使用自适应参数还是默认参数
+u8 icsd_anc_train_result_get(struct icsd_anc_tool_data *TOOL_DATA)
+{
+ u8 result = 0;
+ if (TOOL_DATA) {
+ switch (TOOL_DATA->anc_combination) {
+ case TFF_TFB://使用自适应FF,自适应FB
+ result = ANC_ADAPTIVE_RESULT_LFF | ANC_ADAPTIVE_RESULT_LFB | ANC_ADAPTIVE_RESULT_RFF | ANC_ADAPTIVE_RESULT_RFB;
+ break;
+ case TFF_DFB://使用自适应FF,默认FB
+ result = ANC_ADAPTIVE_RESULT_LFF | ANC_ADAPTIVE_RESULT_RFF;
+ break;
+ case DFF_TFB://result:1 使用记忆FF,自适应FB :3 使用默认FF,自适应FB
+ result = ANC_ADAPTIVE_RESULT_LFB | ANC_ADAPTIVE_RESULT_RFB;
+ break;
+ case DFF_DFB://result:1 使用记忆FF,默认FB :3 使用默认FF,默认FB
+ default:
+ break;
+ }
+ //使用耳道记忆的FF参数
+ if (TOOL_DATA->result == ANC_USE_RECORD) {
+ result |= (ANC_ADAPTIVE_RESULT_LFF | ANC_ADAPTIVE_RESULT_RFF);
+ }
+ //CMP成功,使用自适应CMP参数
+ if (TOOL_DATA->cmp_result) {
+ result |= (ANC_ADAPTIVE_RESULT_LCMP | ANC_ADAPTIVE_RESULT_RCMP);
+ }
+ }
+ return result;
+}
+
+extern int tone_play_index(u8 index, u8 preemption);
+void icsd_anc_htarget_data_end(u8 result)
+{
+ user_train_state &= ~ANC_USER_TRAIN_TOOL_DATA;
+ ICSD_ANC.adaptive_run_busy = 0;
+ /*
+ 训练结果播放提示音
+ result = 1 训练成功
+ result = 0 训练失败
+ */
+ anc_train_result = result;
+ printf("ICSD ANC RESULT:%d================\n", result);
+
+ switch (result) {
+ case 1:
+ anc_printf("FF USE RECORD\n");
+ break;
+ case 2:
+ anc_printf("FF USE TRAIN\n");
+ break;
+ case 3:
+ anc_printf("FF USE DEFAULT\n");
+ break;
+ default:
+ break;
+ }
+ switch (TOOL_DATA->anc_combination) {
+ case TFF_TFB://使用自适应FF,自适应FB
+ anc_printf("TFF_TFB\n");
+ break;
+ case TFF_DFB://使用自适应FF,默认FB
+ anc_printf("TFF_DFB\n");
+#if ANC_DEVELOPER_MODE_EN
+ icsd_adt_tone_play(ICSD_ADT_TONE_NUM2);
+#endif/*ANC_DEVELOPER_MODE_EN*/
+ break;
+ case DFF_TFB://result:1 使用记忆FF,自适应FB :3 使用默认FF,自适应FB
+ anc_printf("DFF_TFB\n");
+#if ANC_DEVELOPER_MODE_EN
+ icsd_adt_tone_play(ICSD_ADT_TONE_NUM1);
+#endif/*ANC_DEVELOPER_MODE_EN*/
+ break;
+ case DFF_DFB://result:1 使用记忆FF,默认FB :3 使用默认FF,默认FB
+ anc_printf("DFF_DFB\n");
+#if ANC_DEVELOPER_MODE_EN
+ icsd_adt_tone_play(ICSD_ADT_TONE_NUM0);
+#endif/*ANC_DEVELOPER_MODE_EN*/
+ break;
+ default:
+ break;
+ }
+ audio_anc_adaptive_fail_callback(TOOL_DATA->anc_err);
+ icsd_board_log("train time tool data end:%d\n", (int)((jiffies - train_time) * 10));
+ icsd_anc_htarget_data_send_end();
+}
+
+extern void audio_anc_adaptive_data_packet(struct icsd_anc_tool_data *TOOL_DATA);
+void icsd_anc_htarget_data_send()
+{
+
+#if ANC_SZ_OUT_EN
+ extern void icsd_anc_sz_out(float * hz_in);
+ extern void icsd_anc_pz_out(float * hz_in);
+ if (HEADSET_MODE) {
+ if ((TOOL_DATA->result == 2) || (TOOL_DATA->anc_combination == TFF_DFB)) {
+ icsd_anc_sz_out(TOOL_DATA->data_out1);
+ icsd_anc_pz_out(TOOL_DATA->data_out2);
+ }
+ } else {
+ if (TOOL_DATA->result == 2) {
+ icsd_anc_sz_out(TOOL_DATA->data_out1);
+ icsd_anc_pz_out(TOOL_DATA->data_out2);
+ }
+ }
+#endif
+
+ if (TOOL_DATA->cmp_result) {
+ anc_printf("CMP RESULT:success\n");
+ } else {
+ anc_printf("CMP RESULT:fail\n");
+ }
+
+ icsd_board_log("train time tool data start:%d\n", (int)((jiffies - train_time) * 10));
+ //TOOL_DATA->result 0:失败使用默认参数 1:耳道记忆参数 2:成功
+ printf("save check:%d %d----------------\n", TOOL_DATA->result, HEADSET_MODE);
+ if (HEADSET_MODE) {
+ if ((TOOL_DATA->result == 2) || (TOOL_DATA->anc_combination == TFF_DFB)) {
+ //成功时进行耳道记忆
+ icsd_anc_save_with_idx(TOOL_DATA->save_idx);
+ }
+ } else {
+ if (TOOL_DATA->result == 2) {
+ //成功时进行耳道记忆
+ icsd_anc_save_with_idx(TOOL_DATA->save_idx);
+ }
+ }
+ audio_anc_adaptive_data_packet((struct icsd_anc_tool_data *)TOOL_DATA);
+ icsd_anc_htarget_data_end(TOOL_DATA->result);
+}
+
+void icsd_anc_end(audio_anc_t *param)
+{
+ icsd_board_log("train time finish:%dms\n", (int)((jiffies - train_time) * 10));
+ user_train_state &= ~ANC_USER_TRAIN_DMA_EN;
+ if (icsd_time_out_hdl) {
+ sys_timeout_del(icsd_time_out_hdl);
+ icsd_time_out_hdl = 0;
+ }
+ icsd_anc_contral = 0;
+ anc_user_train_cb(ANC_ON, anc_train_result, 0);
+}
+
+void icsd_anc_forced_exit_end()
+{
+ if (icsd_anc_contral & ICSD_ANC_TONE_END) {
+ printf("icsd_anc_forced_exit_end cb-----------------------------\n");
+ icsd_anc_contral &= ~ICSD_ANC_FORCED_EXIT;
+ icsd_anc_contral &= ~ICSD_ANC_SUSPENDED;
+ icsd_anc_contral &= ~ICSD_ANC_TONE_END;
+ icsd_anc_contral &= ~ICSD_ANC_INITED;
+ icsd_anc_contral &= ~ICSD_ANC_FORCED_BEFORE_INIT;
+ if (icsd_time_out_hdl) {
+ sys_timeout_del(icsd_time_out_hdl);
+ icsd_time_out_hdl = 0;
+ }
+ anc_user_train_cb(ANC_ON, 0, 1);
+ }
+}
+
+void anc_user_train_tone_play_cb()
+{
+ icsd_board_log("anc_user_train_tone_play_cb:%d========================================\n", (int)jiffies);
+ train_time = jiffies;
+#if ANC_USER_TRAIN_EN
+ icsd_anc_contral |= ICSD_ANC_TONE_END;
+ if (icsd_anc_contral & ICSD_ANC_SUSPENDED) {
+ printf("FORCED EXIT END================================\n");
+ user_train_state |= ANC_TRAIN_TONE_END;
+ icsd_anc_forced_exit_end();
+ return;
+ }
+#if ANC_USER_TRAIN_TONE_MODE
+ icsd_board_log("TONE MODE tone play cb~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
+ if (user_train_state & ANC_TRAIN_TONE_FIRST) {
+ user_train_state |= ANC_TRAIN_TONE_END;
+ } else {
+ icsd_board_log("second train at cb~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
+ user_train_state |= ANC_TRAIN_TONE_END;
+ audio_anc_post_msg_icsd_anc_cmd(ANC_CMD_TRAIN_AFTER_TONE);
+ }
+#else
+ extern void audio_anc_post_msg_user_train_init(u8 mode);
+ audio_anc_post_msg_user_train_init(ANC_ON);
+#endif/*ANC_USER_TRAIN_TONE_MODE*/
+
+#else
+ anc_user_train_cb(ANC_ON, anc_train_result, 0);
+#endif/*ANC_USER_TRAIN_EN*/
+}
+
+#endif/*TCFG_AUDIO_ANC_EAR_ADAPTIVE_EN*/
diff --git a/apps/common/icsd/anc/icsd_anc_client_board.c b/apps/common/icsd/anc/icsd_anc_client_board.c
new file mode 100644
index 0000000..d42dc05
--- /dev/null
+++ b/apps/common/icsd/anc/icsd_anc_client_board.c
@@ -0,0 +1,1024 @@
+
+/*********************************************************************
+
+ ANC 耳道自适应配置文件
+
+*********************************************************************/
+
+
+#if ADAPTIVE_CLIENT_BOARD == HT03_HYBRID_6G
+const u8 cmp_iir_type[] = {
+ ANC_IIR_LOW_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 ff_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 fb_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+const u8 FF_VERSION = 1;
+const u8 NEW_PRE_TREAT = 0;
+const u8 ICSD_EP_TYPE = ICSD_FULL_INEAR;
+const u8 icsd_dcc[4] = {8, 4, 8, 1}; //ff1st,ff2nd,fb12t,fb2nd
+const u16 ICSD_ANC_FUN = 0;
+
+#elif ADAPTIVE_CLIENT_BOARD == G96_HYBRID
+const u8 cmp_iir_type[] = {
+ ANC_IIR_LOW_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 ff_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 fb_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+const u8 FF_VERSION = 1;
+const u8 NEW_PRE_TREAT = 0;
+const u8 ICSD_EP_TYPE = ICSD_FULL_INEAR;
+const u8 icsd_dcc[4] = {8, 4, 8, 1}; //ff1st,ff2nd,fb12t,fb2nd
+const u16 ICSD_ANC_FUN = 0;//ANC_FUN_TARGET_SYNC;
+
+#elif ADAPTIVE_CLIENT_BOARD == P90_HYBRID
+const u8 cmp_iir_type[] = {
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_LOW_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 ff_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 fb_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+const u8 FF_VERSION = 1;
+const u8 NEW_PRE_TREAT = 0;
+const u8 ICSD_EP_TYPE = ICSD_HALF_INEAR;
+const u8 icsd_dcc[4] = {8, 4, 8, 1}; //ff1st,ff2nd,fb12t,fb2nd
+const u16 ICSD_ANC_FUN = 0;
+
+#elif ADAPTIVE_CLIENT_BOARD == D28_HYBRID
+const u8 cmp_iir_type[] = {
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_LOW_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 ff_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 fb_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+const u8 FF_VERSION = 2;
+const u8 NEW_PRE_TREAT = 0;
+const u8 ICSD_EP_TYPE = ICSD_HALF_INEAR;
+const u8 icsd_dcc[4] = {8, 4, 8, 1}; //ff1st,ff2nd,fb12t,fb2nd
+const u16 ICSD_ANC_FUN = ANC_FUN_TARGET_SYNC;
+
+#elif ADAPTIVE_CLIENT_BOARD == ANC05_HYBRID
+const u8 cmp_iir_type[] = {
+ ANC_IIR_LOW_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 ff_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 fb_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+const u8 FF_VERSION = 1;
+const u8 NEW_PRE_TREAT = 0;
+const u8 ICSD_EP_TYPE = ICSD_HEADSET;
+const u8 icsd_dcc[4] = {8, 4, 8, 1}; //ff1st,ff2nd,fb12t,fb2nd
+const u16 ICSD_ANC_FUN = 0;
+
+#elif ADAPTIVE_CLIENT_BOARD == H3_HYBRID
+const u8 cmp_iir_type[] = {
+ ANC_IIR_LOW_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_HIGH_SHELF,
+};
+
+const u8 ff_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 fb_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+const u8 FF_VERSION = 1;
+const u8 NEW_PRE_TREAT = 1;
+const u8 ICSD_EP_TYPE = ICSD_HEADSET;
+const u8 icsd_dcc[4] = {8, 4, 8, 1}; //ff1st,ff2nd,fb12t,fb2nd
+const u16 ICSD_ANC_FUN = 0;
+
+
+#elif ADAPTIVE_CLIENT_BOARD == H3_TOZO_HYBIRD
+const u8 cmp_iir_type[] = {
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_HIGH_SHELF,
+};
+
+const u8 ff_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 fb_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+const u8 FF_VERSION = 1;
+const u8 NEW_PRE_TREAT = 1;
+const u8 ICSD_EP_TYPE = ICSD_HEADSET;
+const u8 icsd_dcc[4] = {8, 4, 8, 1}; //ff1st,ff2nd,fb12t,fb2nd
+const u16 ICSD_ANC_FUN = 0;
+
+#elif ADAPTIVE_CLIENT_BOARD == JH4006_HYBRID
+const u8 cmp_iir_type[] = {
+ ANC_IIR_LOW_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_HIGH_SHELF,
+};
+
+const u8 ff_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 fb_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+const u8 FF_VERSION = 1;
+const u8 NEW_PRE_TREAT = 1;
+const u8 ICSD_EP_TYPE = ICSD_HEADSET;
+const u8 icsd_dcc[4] = {8, 4, 8, 1}; //ff1st,ff2nd,fb12t,fb2nd
+const u16 ICSD_ANC_FUN = 0;
+
+#else
+const u8 cmp_iir_type[] = {
+ ANC_IIR_LOW_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 ff_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+
+const u8 fb_iir_type[] = {
+ ANC_IIR_HIGH_SHELF,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+ ANC_IIR_BAND_PASS,
+};
+const u8 FF_VERSION = 1;
+const u8 NEW_PRE_TREAT = 0;
+const u8 ICSD_EP_TYPE = ICSD_FULL_INEAR;
+const u8 icsd_dcc[4] = {8, 4, 8, 1}; //ff1st,ff2nd,fb12t,fb2nd
+const u16 ICSD_ANC_FUN = 0;
+
+#endif
+
+void icsd_xtmp_handler(float *xtmp, float gain_min, float gain_max)
+{
+#if ADAPTIVE_CLIENT_BOARD == H3_HYBRID
+ if (xtmp[1] < 2.0) {
+ xtmp[1] = (float)2.0;
+ }
+ if (xtmp[1] > 11.0) {
+ xtmp[1] = (float)11.0;
+ }
+ if (xtmp[4] < 3.0) {
+ xtmp[4] = (float)3.0;
+ }
+ if (xtmp[4] > 13.0) {
+ xtmp[4] = (float)13.0;
+ }
+
+#elif ADAPTIVE_CLIENT_BOARD == H3_TOZO_HYBIRD
+ if (xtmp[1] < 2.0) {
+ xtmp[1] = (float)2.0;
+ }
+ if (xtmp[1] > 11.0) {
+ xtmp[1] = (float)11.0;
+ }
+ if (xtmp[4] < 3.0) {
+ xtmp[4] = (float)3.0;
+ }
+ if (xtmp[4] > 13.0) {
+ xtmp[4] = (float)13.0;
+ }
+
+#else
+ if (xtmp[1] < gain_min) {
+ xtmp[1] = (float)gain_min;
+ }
+ if (xtmp[1] > gain_max) {
+ xtmp[1] = (float)gain_max;
+ }
+#endif
+}
+
+
+void icsd_anc_board_config()
+{
+ icsd_anc_board_param_init();
+ ANC_BOARD_PARAM->ff_yorder = ANC_ADAPTIVE_FF_ORDER;
+ ANC_BOARD_PARAM->fb_yorder = ANC_ADAPTIVE_FB_ORDER;
+ ANC_BOARD_PARAM->cmp_yorder = ANC_ADAPTIVE_CMP_ORDER;
+ ANC_BOARD_PARAM->tool_target_sign = 1;
+
+#if ADAPTIVE_CLIENT_BOARD == HT03_HYBRID_6G
+#define PROJECT_098 0
+#define PROJECT_HT03 1
+#define BOARD_PROJECT PROJECT_HT03
+#if BOARD_PROJECT == PROJECT_HT03
+ icsd_board_log("------------HT03_HYBRID_6G---------------\n");
+#define DEFAULT_FF_GAIN 3
+#define DEFAULT_FB_GAIN 3
+ extern const float HT03_DATA[];
+ extern const s8 HT03_s8_DATA[];
+ extern const float HT03_DOUBLE_DATA[];
+ ANC_BOARD_PARAM->anc_data_l = (void *)HT03_DATA;
+ ANC_BOARD_PARAM->anc_db = (void *)HT03_s8_DATA;
+ ANC_BOARD_PARAM->anc_double_data_l = (void *)HT03_DOUBLE_DATA;
+ ANC_BOARD_PARAM->m_value_l = 120.0; //80 ~ 200 最深点位置中心值
+ ANC_BOARD_PARAM->sen_l = 15.0; //12 ~ 22 最深点深度
+ ANC_BOARD_PARAM->in_q_l = 0.4; //0.4 ~ 1.2 最深点降噪宽度
+ ANC_BOARD_PARAM->sen_offset_l = 11.0 - 18.0;
+ ANC_BOARD_PARAM->ff_target_fix_num_l = 18;
+ ANC_BOARD_PARAM->gain_a_param = 25.0;
+ ANC_BOARD_PARAM->gain_a_en = 1;
+ ANC_BOARD_PARAM->cmp_abs_en = 0;
+ ANC_BOARD_PARAM->idx_begin = 18;
+ ANC_BOARD_PARAM->idx_end = 60;
+ ANC_BOARD_PARAM->fb_w2r = 1000;
+ ANC_BOARD_PARAM->FB_NFIX = 3;
+ ANC_BOARD_PARAM->gain_min_offset = 11;
+ ANC_BOARD_PARAM->gain_max_offset = 18;
+ ANC_BOARD_PARAM->minvld = -10.0;
+
+ ANC_BOARD_PARAM->bypass_max_times = BYPASS_MAXTIME;
+ ANC_BOARD_PARAM->pz_max_times = PZ_MAXTIME;
+ ANC_BOARD_PARAM->jt_en = 2;
+ ANC_BOARD_PARAM->tff_sign = 1;
+ ANC_BOARD_PARAM->tfb_sign = -1;
+ ANC_BOARD_PARAM->bff_sign = 1;
+ ANC_BOARD_PARAM->bfb_sign = 1;
+ ANC_BOARD_PARAM->bypass_sign = -1;
+ ANC_BOARD_PARAM->bypass_volume = 0.6; //0.6
+
+ ANC_BOARD_PARAM->tool_target_sign = -1;
+ ANC_BOARD_PARAM->cmp_type[0] = 10;
+ ANC_BOARD_PARAM->cmp_type[1] = 1;
+ ANC_BOARD_PARAM->cmp_type[2] = 1;
+ ANC_BOARD_PARAM->cmp_type[3] = 1;
+ ANC_BOARD_PARAM->cmp_type[4] = 1;
+ ANC_BOARD_PARAM->cmp_type[5] = 1;
+ ANC_BOARD_PARAM->cmp_type[6] = 1;
+ ANC_BOARD_PARAM->cmp_type[7] = 1;
+ ANC_BOARD_PARAM->cmp_thd_low = 3.0;
+ ANC_BOARD_PARAM->cmp_thd_high = 10.0;
+
+ ANC_BOARD_PARAM->IIR_NUM = 3;
+ ANC_BOARD_PARAM->IIR_NUM_FIX = 8 - ANC_BOARD_PARAM->IIR_NUM;
+ ANC_BOARD_PARAM->IIR_COEF = ANC_BOARD_PARAM->IIR_NUM * 3 + 1;
+
+ ANC_BOARD_PARAM->sz_priority_thr = 60;
+ ANC_BOARD_PARAM->JT_MODE = 0;
+
+#else
+ icsd_board_log("------------ 098 -----------------\n");
+#define DEFAULT_FF_GAIN 3
+#define DEFAULT_FB_GAIN 3
+
+#endif
+
+#elif ADAPTIVE_CLIENT_BOARD == G96_HYBRID
+
+ icsd_board_log("------------G96_HYBRID---------------\n");
+#define DEFAULT_FF_GAIN 4
+#define DEFAULT_FB_GAIN 1
+ extern const float G96_DATA[];
+ extern const s8 G96_s8_DATA[];
+ extern const float G96_DOUBLE_DATA[];
+ ANC_BOARD_PARAM->anc_data_l = (void *)G96_DATA;
+ ANC_BOARD_PARAM->anc_db = (void *)G96_s8_DATA;
+ ANC_BOARD_PARAM->anc_double_data_l = (void *)G96_DOUBLE_DATA;
+ ANC_BOARD_PARAM->m_value_l = 120.0; //80 ~ 200 最深点位置中心值
+ ANC_BOARD_PARAM->sen_l = 18.0; //12 ~ 22 最深点深度
+ ANC_BOARD_PARAM->in_q_l = 0.4; //0.4 ~ 1.2 最深点降噪宽度
+ ANC_BOARD_PARAM->sen_offset_l = 15.0 - 12.5;
+ ANC_BOARD_PARAM->ff_target_fix_num_l = 10;
+ ANC_BOARD_PARAM->gain_a_param = 25.0;
+ ANC_BOARD_PARAM->gain_a_en = 0;
+ ANC_BOARD_PARAM->cmp_abs_en = 2;
+ ANC_BOARD_PARAM->idx_begin = 27;
+ ANC_BOARD_PARAM->idx_end = 60;
+ ANC_BOARD_PARAM->fb_w2r = 1000;
+ ANC_BOARD_PARAM->FB_NFIX = 3;
+ ANC_BOARD_PARAM->gain_min_offset = 10;
+ ANC_BOARD_PARAM->gain_max_offset = 18;
+ ANC_BOARD_PARAM->minvld = -10.0;
+
+ ANC_BOARD_PARAM->bypass_max_times = BYPASS_MAXTIME;
+ ANC_BOARD_PARAM->pz_max_times = PZ_MAXTIME;
+ ANC_BOARD_PARAM->jt_en = 1;
+ ANC_BOARD_PARAM->tff_sign = -1;
+ ANC_BOARD_PARAM->tfb_sign = -1;
+ ANC_BOARD_PARAM->bff_sign = 1;
+ ANC_BOARD_PARAM->bfb_sign = -1;
+ ANC_BOARD_PARAM->bypass_sign = -1;
+ ANC_BOARD_PARAM->bypass_volume = 0.7; //0.6
+
+ ANC_BOARD_PARAM->tool_target_sign = 1;
+ ANC_BOARD_PARAM->cmp_type[0] = 10;
+ ANC_BOARD_PARAM->cmp_type[1] = 1;
+ ANC_BOARD_PARAM->cmp_type[2] = 1;
+ ANC_BOARD_PARAM->cmp_type[3] = 1;
+ ANC_BOARD_PARAM->cmp_type[4] = 1;
+ ANC_BOARD_PARAM->cmp_type[5] = 1;
+ ANC_BOARD_PARAM->cmp_type[6] = 1;
+ ANC_BOARD_PARAM->cmp_type[7] = 1;
+ ANC_BOARD_PARAM->cmp_thd_low = 3.0;
+ ANC_BOARD_PARAM->cmp_thd_high = 10.0;
+
+ ANC_BOARD_PARAM->IIR_NUM = 3;
+ ANC_BOARD_PARAM->IIR_NUM_FIX = 8 - ANC_BOARD_PARAM->IIR_NUM;
+ ANC_BOARD_PARAM->IIR_COEF = ANC_BOARD_PARAM->IIR_NUM * 3 + 1;
+
+ ANC_BOARD_PARAM->sz_priority_thr = 45;
+ ANC_BOARD_PARAM->JT_MODE = 1;
+
+#elif ADAPTIVE_CLIENT_BOARD == G02_HYBRID_6G
+ icsd_board_log("------------ G02 -----------------\n");
+#define DEFAULT_FF_GAIN 4
+#define DEFAULT_FB_GAIN 1
+ extern const float G02_DATA[];
+ extern const s8 G02_s8_DATA[];
+ extern const float G02_DOUBLE_DATA[];
+ ANC_BOARD_PARAM->anc_data_l = (void *)G02_DATA;
+ ANC_BOARD_PARAM->anc_db = (void *)G02_s8_DATA;
+ ANC_BOARD_PARAM->anc_double_data_l = (void *)G02_DOUBLE_DATA;
+ ANC_BOARD_PARAM->m_value_l = 130.0; //80 ~ 200 最深点位置中心值
+ ANC_BOARD_PARAM->sen_l = 14.0; //12 ~ 22 最深点深度
+ ANC_BOARD_PARAM->in_q_l = 0.5; //0.4 ~ 1.2 最深点降噪宽度
+ ANC_BOARD_PARAM->sen_offset_l = 22.0 - 18.0;
+ ANC_BOARD_PARAM->ff_target_fix_num_l = 10;
+ ANC_BOARD_PARAM->gain_a_param = 12.0;
+ ANC_BOARD_PARAM->gain_a_en = 0;
+ ANC_BOARD_PARAM->cmp_abs_en = 1;
+ ANC_BOARD_PARAM->idx_begin = 25;
+ ANC_BOARD_PARAM->idx_end = 60;
+ ANC_BOARD_PARAM->fb_w2r = 1200;
+ ANC_BOARD_PARAM->FB_NFIX = 4;
+ ANC_BOARD_PARAM->gain_min_offset = 22;
+ ANC_BOARD_PARAM->gain_max_offset = 32;
+ ANC_BOARD_PARAM->minvld = -30.0;
+
+ ANC_BOARD_PARAM->bypass_max_times = BYPASS_MAXTIME;
+ ANC_BOARD_PARAM->pz_max_times = PZ_MAXTIME;
+ ANC_BOARD_PARAM->jt_en = 1;
+ ANC_BOARD_PARAM->tff_sign = -1;
+ ANC_BOARD_PARAM->tfb_sign = -1;
+ ANC_BOARD_PARAM->bff_sign = 1;
+ ANC_BOARD_PARAM->bfb_sign = -1;
+ ANC_BOARD_PARAM->bypass_sign = -1;
+ ANC_BOARD_PARAM->bypass_volume = 0.6;//1.6;
+
+ ANC_BOARD_PARAM->tool_target_sign = 1;
+ ANC_BOARD_PARAM->cmp_type[0] = 10;
+ ANC_BOARD_PARAM->cmp_type[1] = 1;
+ ANC_BOARD_PARAM->cmp_type[2] = 1;
+ ANC_BOARD_PARAM->cmp_type[3] = 1;
+ ANC_BOARD_PARAM->cmp_type[4] = 1;
+ ANC_BOARD_PARAM->cmp_type[5] = 1;
+ ANC_BOARD_PARAM->cmp_type[6] = 1;
+ ANC_BOARD_PARAM->cmp_type[7] = 1;
+ ANC_BOARD_PARAM->cmp_thd_low = 3.0;
+ ANC_BOARD_PARAM->cmp_thd_high = 10.0;
+
+ ANC_BOARD_PARAM->IIR_NUM = 3;
+ ANC_BOARD_PARAM->IIR_NUM_FIX = 8 - ANC_BOARD_PARAM->IIR_NUM;
+ ANC_BOARD_PARAM->IIR_COEF = ANC_BOARD_PARAM->IIR_NUM * 3 + 1;
+
+ ANC_BOARD_PARAM->sz_priority_thr = 60;
+ ANC_BOARD_PARAM->JT_MODE = 0;
+
+#elif ADAPTIVE_CLIENT_BOARD == ANC05_HYBRID
+ icsd_board_log("------------ ANC05_HYBRID -----------------\n");
+#define DEFAULT_FF_GAIN 3
+#define DEFAULT_FB_GAIN 3
+ extern const float ANC05_L_DATA[];
+ extern const float ANC05_R_DATA[];
+ extern const s8 ANC05_s8_DATA[];
+ extern const double ANC05_L_DOUBLE_DATA[];
+ extern const double ANC05_R_DOUBLE_DATA[];
+ ANC_BOARD_PARAM->anc_data_l = (void *)ANC05_L_DATA;
+ ANC_BOARD_PARAM->anc_data_r = (void *)ANC05_R_DATA;
+ ANC_BOARD_PARAM->anc_db = (void *)ANC05_s8_DATA;
+ ANC_BOARD_PARAM->anc_double_data_l = (void *)ANC05_L_DOUBLE_DATA;
+ ANC_BOARD_PARAM->anc_double_data_r = (void *)ANC05_R_DOUBLE_DATA;
+ ANC_BOARD_PARAM->m_value_l = 220.0; //80 ~ 200 最深点位置中心值
+ ANC_BOARD_PARAM->sen_l = 12.0; //12 ~ 22 最深点深度
+ ANC_BOARD_PARAM->in_q_l = 0.3; //0.4 ~ 1.2 最深点降噪宽度
+ ANC_BOARD_PARAM->m_value_r = 220.0; //80 ~ 200 最深点位置中心值
+ ANC_BOARD_PARAM->sen_r = 12.0; //12 ~ 22 最深点深度
+ ANC_BOARD_PARAM->in_q_r = 0.3; //0.4 ~ 1.2 最深点降噪宽度
+ ANC_BOARD_PARAM->sen_offset_l = 13.0 - 18.0;
+ ANC_BOARD_PARAM->sen_offset_r = 13.0 - 18.0;
+ ANC_BOARD_PARAM->ff_target_fix_num_l = 18;
+ ANC_BOARD_PARAM->ff_target_fix_num_r = 18;
+ ANC_BOARD_PARAM->gain_a_param = 25.0;
+ ANC_BOARD_PARAM->gain_a_en = 0;
+ ANC_BOARD_PARAM->cmp_abs_en = 0;
+ ANC_BOARD_PARAM->idx_begin = 18;
+ ANC_BOARD_PARAM->idx_end = 60;
+ ANC_BOARD_PARAM->fb_w2r = 1000;
+ ANC_BOARD_PARAM->FB_NFIX = 3;
+ ANC_BOARD_PARAM->gain_min_offset = 11;
+ ANC_BOARD_PARAM->gain_max_offset = 18;
+ ANC_BOARD_PARAM->minvld = -10.0;
+
+ ANC_BOARD_PARAM->bypass_max_times = BYPASS_MAXTIME;
+ ANC_BOARD_PARAM->pz_max_times = PZ_MAXTIME;
+ ANC_BOARD_PARAM->jt_en = 1;
+ ANC_BOARD_PARAM->tff_sign = -1;
+ ANC_BOARD_PARAM->tfb_sign = 1;
+ ANC_BOARD_PARAM->bff_sign = 1;
+ ANC_BOARD_PARAM->bfb_sign = 1;
+ ANC_BOARD_PARAM->bypass_sign = -1;
+ ANC_BOARD_PARAM->bypass_volume = 2.0;
+ ANC_BOARD_PARAM->tool_target_sign = -1;//工具性能线反时需要调整该标志位
+
+ ANC_BOARD_PARAM->cmp_type[0] = 10;
+ ANC_BOARD_PARAM->cmp_type[1] = 1;
+ ANC_BOARD_PARAM->cmp_type[2] = 0;
+ ANC_BOARD_PARAM->cmp_type[3] = 1;
+ ANC_BOARD_PARAM->cmp_type[4] = 1;
+ ANC_BOARD_PARAM->cmp_type[5] = 1;
+ ANC_BOARD_PARAM->cmp_type[6] = 1;
+ ANC_BOARD_PARAM->cmp_type[7] = 1;
+ ANC_BOARD_PARAM->cmp_thd_low = -40.0;
+ ANC_BOARD_PARAM->cmp_thd_high = 40.0;
+
+ ANC_BOARD_PARAM->IIR_NUM = 4;
+ ANC_BOARD_PARAM->IIR_NUM_FIX = 8 - ANC_BOARD_PARAM->IIR_NUM;
+ ANC_BOARD_PARAM->IIR_COEF = ANC_BOARD_PARAM->IIR_NUM * 3 + 1;
+
+ ANC_BOARD_PARAM->sz_priority_thr = 60;
+ ANC_BOARD_PARAM->JT_MODE = 0;
+
+#elif ADAPTIVE_CLIENT_BOARD == H3_HYBRID
+ icsd_board_log("------------ H3_HYBRID -----------------\n");
+#define DEFAULT_FF_GAIN 4
+#define DEFAULT_FB_GAIN 1
+ extern const float H3_L_DATA[];
+ extern const float H3_R_DATA[];
+ extern const s8 H3_s8_DATA[];
+ extern const double H3_L_DOUBLE_DATA[];
+ extern const double H3_R_DOUBLE_DATA[];
+
+ ANC_BOARD_PARAM->anc_data_l = (void *)H3_L_DATA;
+ ANC_BOARD_PARAM->anc_data_r = (void *)H3_L_DATA;
+ ANC_BOARD_PARAM->anc_db = (void *)H3_s8_DATA;
+ ANC_BOARD_PARAM->anc_double_data_l = (void *)H3_L_DOUBLE_DATA;
+ ANC_BOARD_PARAM->anc_double_data_r = (void *)H3_L_DOUBLE_DATA;
+ ANC_BOARD_PARAM->m_value_l = 220.0; //80 ~ 200 最深点位置中心值
+ ANC_BOARD_PARAM->sen_l = 15.0; //12 ~ 22 最深点深度
+ ANC_BOARD_PARAM->in_q_l = 0.3; //0.4 ~ 1.2 最深点降噪宽度
+ ANC_BOARD_PARAM->m_value_r = 220.0; //80 ~ 200 最深点位置中心值
+ ANC_BOARD_PARAM->sen_r = 15.0; //12 ~ 22 最深点深度
+ ANC_BOARD_PARAM->in_q_r = 0.3; //0.4 ~ 1.2 最深点降噪宽度
+ ANC_BOARD_PARAM->sen_offset_l = 13.0 - 18.0;
+ ANC_BOARD_PARAM->sen_offset_r = 13.0 - 18.0;
+ ANC_BOARD_PARAM->ff_target_fix_num_l = 8;
+ ANC_BOARD_PARAM->ff_target_fix_num_r = 8;
+ ANC_BOARD_PARAM->gain_a_param = 25.0;
+ ANC_BOARD_PARAM->gain_a_en = 0;
+ ANC_BOARD_PARAM->cmp_abs_en = 2;
+ ANC_BOARD_PARAM->idx_begin = 23;
+ ANC_BOARD_PARAM->idx_end = 60;
+ ANC_BOARD_PARAM->fb_w2r = 1000;
+ ANC_BOARD_PARAM->FB_NFIX = 4;
+ ANC_BOARD_PARAM->gain_min_offset = 11;
+ ANC_BOARD_PARAM->gain_max_offset = 18;
+ ANC_BOARD_PARAM->minvld = -10.0;
+
+ ANC_BOARD_PARAM->bypass_max_times = BYPASS_MAXTIME;
+ ANC_BOARD_PARAM->pz_max_times = PZ_MAXTIME;
+ ANC_BOARD_PARAM->jt_en = 1;
+ ANC_BOARD_PARAM->tff_sign = -1;
+ ANC_BOARD_PARAM->tfb_sign = 1;
+ ANC_BOARD_PARAM->bff_sign = 1;
+ ANC_BOARD_PARAM->bfb_sign = 1;
+ ANC_BOARD_PARAM->bypass_sign = -1;
+ ANC_BOARD_PARAM->bypass_volume = 2.0;
+
+ ANC_BOARD_PARAM->tool_target_sign = -1;
+ ANC_BOARD_PARAM->cmp_type[0] = 10;
+ ANC_BOARD_PARAM->cmp_type[1] = 1;
+ ANC_BOARD_PARAM->cmp_type[2] = 1;
+ ANC_BOARD_PARAM->cmp_type[3] = 1;
+ ANC_BOARD_PARAM->cmp_type[4] = 1;
+ ANC_BOARD_PARAM->cmp_type[5] = 1;
+ ANC_BOARD_PARAM->cmp_type[6] = 1;
+ ANC_BOARD_PARAM->cmp_type[7] = 0;
+ ANC_BOARD_PARAM->cmp_thd_low = -40.0;
+ ANC_BOARD_PARAM->cmp_thd_high = 40.0;
+
+ ANC_BOARD_PARAM->IIR_NUM = 4;
+ ANC_BOARD_PARAM->IIR_NUM_FIX = 8 - ANC_BOARD_PARAM->IIR_NUM;
+ ANC_BOARD_PARAM->IIR_COEF = ANC_BOARD_PARAM->IIR_NUM * 3 + 1;
+
+ ANC_BOARD_PARAM->sz_priority_thr = 50;//高声压SZ优先级
+ ANC_BOARD_PARAM->JT_MODE = 0;
+
+#elif ADAPTIVE_CLIENT_BOARD == H3_TOZO_HYBIRD
+ icsd_board_log("------------ H3_TOZO_HYBIRD -----------------\n");
+#define DEFAULT_FF_GAIN 3
+#define DEFAULT_FB_GAIN 1
+ extern const float H3_TOZO_L_DATA[];
+ extern const float H3_TOZO_R_DATA[];
+ extern const s8 H3_TOZO_s8_DATA[];
+ extern const double H3_TOZO_L_DOUBLE_DATA[];
+ extern const double H3_TOZO_R_DOUBLE_DATA[];
+
+ ANC_BOARD_PARAM->anc_data_l = (void *)H3_TOZO_L_DATA;
+ ANC_BOARD_PARAM->anc_data_r = (void *)H3_TOZO_L_DATA;
+ ANC_BOARD_PARAM->anc_db = (void *)H3_TOZO_s8_DATA;
+ ANC_BOARD_PARAM->anc_double_data_l = (void *)H3_TOZO_L_DOUBLE_DATA;
+ ANC_BOARD_PARAM->anc_double_data_r = (void *)H3_TOZO_L_DOUBLE_DATA;
+ ANC_BOARD_PARAM->m_value_l = 220.0; //80 ~ 200 最深点位置中心值
+ ANC_BOARD_PARAM->sen_l = 15.0; //12 ~ 22 最深点深度
+ ANC_BOARD_PARAM->in_q_l = 0.3; //0.4 ~ 1.2 最深点降噪宽度
+ ANC_BOARD_PARAM->m_value_r = 220.0; //80 ~ 200 最深点位置中心值
+ ANC_BOARD_PARAM->sen_r = 15.0; //12 ~ 22 最深点深度
+ ANC_BOARD_PARAM->in_q_r = 0.3; //0.4 ~ 1.2 最深点降噪宽度
+ ANC_BOARD_PARAM->sen_offset_l = 13.0 - 18.0;
+ ANC_BOARD_PARAM->sen_offset_r = 13.0 - 18.0;
+ ANC_BOARD_PARAM->ff_target_fix_num_l = 8;
+ ANC_BOARD_PARAM->ff_target_fix_num_r = 8;
+ ANC_BOARD_PARAM->gain_a_param = 25.0;
+ ANC_BOARD_PARAM->gain_a_en = 0;
+ ANC_BOARD_PARAM->cmp_abs_en = 2;
+ ANC_BOARD_PARAM->idx_begin = 23;
+ ANC_BOARD_PARAM->idx_end = 60;
+ ANC_BOARD_PARAM->fb_w2r = 1000;
+ ANC_BOARD_PARAM->FB_NFIX = 4;
+ ANC_BOARD_PARAM->gain_min_offset = 11;
+ ANC_BOARD_PARAM->gain_max_offset = 18;
+ ANC_BOARD_PARAM->minvld = -10.0;
+
+ ANC_BOARD_PARAM->bypass_max_times = BYPASS_MAXTIME;
+ ANC_BOARD_PARAM->pz_max_times = PZ_MAXTIME;
+ ANC_BOARD_PARAM->jt_en = 1;
+ ANC_BOARD_PARAM->tff_sign = -1;
+ ANC_BOARD_PARAM->tfb_sign = 1;
+ ANC_BOARD_PARAM->bff_sign = 1;
+ ANC_BOARD_PARAM->bfb_sign = 1;
+ ANC_BOARD_PARAM->bypass_sign = -1;
+ ANC_BOARD_PARAM->bypass_volume = 2.0;
+
+ ANC_BOARD_PARAM->tool_target_sign = -1;
+ ANC_BOARD_PARAM->cmp_type[0] = 1;
+ ANC_BOARD_PARAM->cmp_type[1] = 1;
+ ANC_BOARD_PARAM->cmp_type[2] = 1;
+ ANC_BOARD_PARAM->cmp_type[3] = 1;
+ ANC_BOARD_PARAM->cmp_type[4] = 1;
+ ANC_BOARD_PARAM->cmp_type[5] = 1;
+ ANC_BOARD_PARAM->cmp_type[6] = 1;
+ ANC_BOARD_PARAM->cmp_type[7] = 0;
+ ANC_BOARD_PARAM->cmp_thd_low = -40.0;
+ ANC_BOARD_PARAM->cmp_thd_high = 40.0;
+
+ ANC_BOARD_PARAM->IIR_NUM = 4;
+ ANC_BOARD_PARAM->IIR_NUM_FIX = 8 - ANC_BOARD_PARAM->IIR_NUM;
+ ANC_BOARD_PARAM->IIR_COEF = ANC_BOARD_PARAM->IIR_NUM * 3 + 1;
+
+ ANC_BOARD_PARAM->sz_priority_thr = 50;//高声压SZ优先级
+ ANC_BOARD_PARAM->JT_MODE = 0;
+
+#elif ADAPTIVE_CLIENT_BOARD == P90_HYBRID
+
+ icsd_board_log("------------P90_HYBRID---------------\n");
+#define DEFAULT_FF_GAIN 4
+#define DEFAULT_FB_GAIN 1
+ extern const float P90_DATA[];
+ extern const s8 P90_s8_DATA[];
+ extern const float P90_DOUBLE_DATA[];
+ ANC_BOARD_PARAM->anc_data_l = (void *)P90_DATA;
+ ANC_BOARD_PARAM->anc_db = (void *)P90_s8_DATA;
+ ANC_BOARD_PARAM->anc_double_data_l = (void *)P90_DOUBLE_DATA;
+ ANC_BOARD_PARAM->m_value_l = 120.0; //80 ~ 200 最深点位置中心值
+ ANC_BOARD_PARAM->sen_l = 18.0; //12 ~ 22 最深点深度
+ ANC_BOARD_PARAM->in_q_l = 0.4; //0.4 ~ 1.2 最深点降噪宽度
+ ANC_BOARD_PARAM->sen_offset_l = 15.0 - 12.5;
+ ANC_BOARD_PARAM->ff_target_fix_num_l = 10;
+ ANC_BOARD_PARAM->gain_a_param = 25.0;
+ ANC_BOARD_PARAM->gain_a_en = 0;
+ ANC_BOARD_PARAM->cmp_abs_en = 3;
+ ANC_BOARD_PARAM->idx_begin = 0;
+ ANC_BOARD_PARAM->idx_end = 60;
+ ANC_BOARD_PARAM->fb_w2r = 1000;
+ ANC_BOARD_PARAM->FB_NFIX = 3;
+ ANC_BOARD_PARAM->gain_min_offset = 10;
+ ANC_BOARD_PARAM->gain_max_offset = 18;
+ ANC_BOARD_PARAM->minvld = -10.0;
+
+ ANC_BOARD_PARAM->bypass_max_times = 1;
+ ANC_BOARD_PARAM->pz_max_times = 1;//PZ_MAXTIME;
+ ANC_BOARD_PARAM->jt_en = 1;
+ ANC_BOARD_PARAM->tff_sign = -1;
+ ANC_BOARD_PARAM->tfb_sign = 1;//-1
+ ANC_BOARD_PARAM->bff_sign = 1;
+ ANC_BOARD_PARAM->bfb_sign = 1;//-1;
+ ANC_BOARD_PARAM->bypass_sign = -1;
+ ANC_BOARD_PARAM->bypass_volume = 0.7; //0.6
+
+ ANC_BOARD_PARAM->tool_target_sign = 1;
+ ANC_BOARD_PARAM->cmp_type[0] = 1;
+ ANC_BOARD_PARAM->cmp_type[1] = 1;
+ ANC_BOARD_PARAM->cmp_type[2] = 10;
+ ANC_BOARD_PARAM->cmp_type[3] = 1;
+ ANC_BOARD_PARAM->cmp_type[4] = 0;
+ ANC_BOARD_PARAM->cmp_type[5] = 1;
+ ANC_BOARD_PARAM->cmp_type[6] = 1;
+ ANC_BOARD_PARAM->cmp_type[7] = 1;
+ ANC_BOARD_PARAM->cmp_thd_low = -40.0;
+ ANC_BOARD_PARAM->cmp_thd_high = 40.0;
+
+ ANC_BOARD_PARAM->IIR_NUM = 4;
+ ANC_BOARD_PARAM->IIR_NUM_FIX = 8 - ANC_BOARD_PARAM->IIR_NUM;
+ ANC_BOARD_PARAM->IIR_COEF = ANC_BOARD_PARAM->IIR_NUM * 3 + 1;
+
+ ANC_BOARD_PARAM->sz_priority_thr = 40;
+ ANC_BOARD_PARAM->JT_MODE = 1;
+
+#elif ADAPTIVE_CLIENT_BOARD == D28_HYBRID
+
+ icsd_board_log("------------D28_HYBRID---------------\n");
+#define DEFAULT_FF_GAIN 4
+#define DEFAULT_FB_GAIN 1
+ extern const float D28_DATA[];
+ extern const s8 D28_s8_DATA[];
+ extern const float D28_DOUBLE_DATA[];
+ ANC_BOARD_PARAM->anc_data_l = (void *)D28_DATA;
+ ANC_BOARD_PARAM->anc_db = (void *)D28_s8_DATA;
+ ANC_BOARD_PARAM->anc_double_data_l = (void *)D28_DOUBLE_DATA;
+ ANC_BOARD_PARAM->m_value_l = 120.0; //80 ~ 200 最深点位置中心值
+ ANC_BOARD_PARAM->sen_l = 18.0; //12 ~ 22 最深点深度
+ ANC_BOARD_PARAM->in_q_l = 0.4; //0.4 ~ 1.2 最深点降噪宽度
+ ANC_BOARD_PARAM->sen_offset_l = 15.0 - 12.5;
+ ANC_BOARD_PARAM->ff_target_fix_num_l = 0;
+ ANC_BOARD_PARAM->gain_a_param = 25.0;
+ ANC_BOARD_PARAM->gain_a_en = 0;
+ ANC_BOARD_PARAM->cmp_abs_en = 4;
+ ANC_BOARD_PARAM->idx_begin = 0;
+ ANC_BOARD_PARAM->idx_end = 60;
+ ANC_BOARD_PARAM->fb_w2r = 1000;
+ ANC_BOARD_PARAM->FB_NFIX = 3;
+ ANC_BOARD_PARAM->gain_min_offset = 10;
+ ANC_BOARD_PARAM->gain_max_offset = 18;
+ ANC_BOARD_PARAM->minvld = -10.0;
+
+ ANC_BOARD_PARAM->bypass_max_times = 1;
+ ANC_BOARD_PARAM->pz_max_times = 1;//PZ_MAXTIME;
+ ANC_BOARD_PARAM->jt_en = 1;
+ ANC_BOARD_PARAM->tff_sign = -1;
+ ANC_BOARD_PARAM->tfb_sign = 1;//-1
+ ANC_BOARD_PARAM->bff_sign = 1;
+ ANC_BOARD_PARAM->bfb_sign = 1;//-1;
+ ANC_BOARD_PARAM->bypass_sign = -1;
+ ANC_BOARD_PARAM->bypass_volume = 0.7; //0.6
+
+ ANC_BOARD_PARAM->tool_target_sign = 1;
+ ANC_BOARD_PARAM->cmp_type[0] = 1;
+ ANC_BOARD_PARAM->cmp_type[1] = 1;
+ ANC_BOARD_PARAM->cmp_type[2] = 10;
+ ANC_BOARD_PARAM->cmp_type[3] = 1;
+ ANC_BOARD_PARAM->cmp_type[4] = 0;
+ ANC_BOARD_PARAM->cmp_type[5] = 1;
+ ANC_BOARD_PARAM->cmp_type[6] = 1;
+ ANC_BOARD_PARAM->cmp_type[7] = 1;
+ ANC_BOARD_PARAM->cmp_thd_low = -40.0;
+ ANC_BOARD_PARAM->cmp_thd_high = 40.0;
+
+ ANC_BOARD_PARAM->IIR_NUM = 7;
+ ANC_BOARD_PARAM->IIR_NUM_FIX = ANC_ADAPTIVE_FF_ORDER - ANC_BOARD_PARAM->IIR_NUM;
+ ANC_BOARD_PARAM->IIR_COEF = ANC_BOARD_PARAM->IIR_NUM * 3 + 1;
+
+ ANC_BOARD_PARAM->sz_priority_thr = 40;
+ ANC_BOARD_PARAM->JT_MODE = 1;
+
+
+#elif ADAPTIVE_CLIENT_BOARD == JH4006_HYBRID
+ icsd_board_log("------------ JH4006_HYBRID -----------------\n");
+#define DEFAULT_FF_GAIN 4
+#define DEFAULT_FB_GAIN 1
+ extern const float JH4006_L_DATA[];
+ //extern const float JH4006_R_DATA[];
+ extern const s8 JH4006_s8_DATA[];
+ extern const double JH4006_L_DOUBLE_DATA[];
+ extern const double JH4006_R_DOUBLE_DATA[];
+
+ ANC_BOARD_PARAM->anc_data_l = (void *)JH4006_L_DATA;
+ ANC_BOARD_PARAM->anc_data_r = (void *)JH4006_L_DATA;
+ ANC_BOARD_PARAM->anc_db = (void *)JH4006_s8_DATA;
+ ANC_BOARD_PARAM->anc_double_data_l = (void *)JH4006_L_DOUBLE_DATA;
+ ANC_BOARD_PARAM->anc_double_data_r = (void *)JH4006_L_DOUBLE_DATA;
+ ANC_BOARD_PARAM->m_value_l = 220.0; //80 ~ 200 最深点位置中心值
+ ANC_BOARD_PARAM->sen_l = 15.0; //12 ~ 22 最深点深度
+ ANC_BOARD_PARAM->in_q_l = 0.3; //0.4 ~ 1.2 最深点降噪宽度
+ ANC_BOARD_PARAM->m_value_r = 220.0; //80 ~ 200 最深点位置中心值
+ ANC_BOARD_PARAM->sen_r = 15.0; //12 ~ 22 最深点深度
+ ANC_BOARD_PARAM->in_q_r = 0.3; //0.4 ~ 1.2 最深点降噪宽度
+ ANC_BOARD_PARAM->sen_offset_l = 13.0 - 18.0;
+ ANC_BOARD_PARAM->sen_offset_r = 13.0 - 18.0;
+ ANC_BOARD_PARAM->ff_target_fix_num_l = 8;
+ ANC_BOARD_PARAM->ff_target_fix_num_r = 8;
+ ANC_BOARD_PARAM->gain_a_param = 25.0;
+ ANC_BOARD_PARAM->gain_a_en = 0;
+ ANC_BOARD_PARAM->cmp_abs_en = 2;
+ ANC_BOARD_PARAM->idx_begin = 23;
+ ANC_BOARD_PARAM->idx_end = 60;
+ ANC_BOARD_PARAM->fb_w2r = 1000;
+ ANC_BOARD_PARAM->FB_NFIX = 4;
+ ANC_BOARD_PARAM->gain_min_offset = 11;
+ ANC_BOARD_PARAM->gain_max_offset = 18;
+ ANC_BOARD_PARAM->minvld = -10.0;
+
+ ANC_BOARD_PARAM->bypass_max_times = BYPASS_MAXTIME;
+ ANC_BOARD_PARAM->pz_max_times = PZ_MAXTIME;
+ ANC_BOARD_PARAM->jt_en = 1;
+ ANC_BOARD_PARAM->tff_sign = -1;
+ ANC_BOARD_PARAM->tfb_sign = 1;
+ ANC_BOARD_PARAM->bff_sign = 1;
+ ANC_BOARD_PARAM->bfb_sign = 1;
+ ANC_BOARD_PARAM->bypass_sign = -1;
+ ANC_BOARD_PARAM->bypass_volume = 2.0;
+
+ ANC_BOARD_PARAM->tool_target_sign = -1;
+ ANC_BOARD_PARAM->cmp_type[0] = 10;
+ ANC_BOARD_PARAM->cmp_type[1] = 1;
+ ANC_BOARD_PARAM->cmp_type[2] = 1;
+ ANC_BOARD_PARAM->cmp_type[3] = 1;
+ ANC_BOARD_PARAM->cmp_type[4] = 1;
+ ANC_BOARD_PARAM->cmp_type[5] = 1;
+ ANC_BOARD_PARAM->cmp_type[6] = 1;
+ ANC_BOARD_PARAM->cmp_type[7] = 0;
+ ANC_BOARD_PARAM->cmp_thd_low = -40.0;
+ ANC_BOARD_PARAM->cmp_thd_high = 40.0;
+
+ ANC_BOARD_PARAM->IIR_NUM = 4;
+ ANC_BOARD_PARAM->IIR_NUM_FIX = 8 - ANC_BOARD_PARAM->IIR_NUM;
+ ANC_BOARD_PARAM->IIR_COEF = ANC_BOARD_PARAM->IIR_NUM * 3 + 1;
+
+ ANC_BOARD_PARAM->sz_priority_thr = 50;//高声压SZ优先级
+ ANC_BOARD_PARAM->JT_MODE = 0;
+
+#else
+
+#endif
+ ANC_BOARD_PARAM->mode = ICSD_ANC_MODE;
+ if (ANC_DFF_AFB_EN) {
+ icsd_board_log("ANC_DFF_AFB_EN ON\n");
+ ANC_BOARD_PARAM->FF_FB_EN |= ICSD_DFF_AFB_EN;//BIT(7);
+ }
+ if (ANC_AFF_DFB_EN) {
+ icsd_board_log("ANC_AFF_DFB_EN ON\n");
+ ANC_BOARD_PARAM->FF_FB_EN |= ICSD_AFF_DFB_EN;//BIT(6);
+ }
+ if (ANC_FB_TRAIN_OFF) {
+ ANC_BOARD_PARAM->FF_FB_EN |= ICSD_FB_TRAIN_OFF;//BIT(5);
+ }
+ if (ANC_FB_TRAIN_NEW) {
+ ANC_BOARD_PARAM->FF_FB_EN |= ICSD_FB_TRAIN_NEW;//BIT(4);
+ }
+ ANC_BOARD_PARAM->default_ff_gain = DEFAULT_FF_GAIN;
+ ANC_BOARD_PARAM->default_fb_gain = DEFAULT_FB_GAIN;
+
+ if (TCFG_AUDIO_DAC_MODE == DAC_MODE_H1_DIFF) {
+ user_train_state |= ANC_DAC_MODE_H1_DIFF;
+ } else {
+ user_train_state &= ~ANC_DAC_MODE_H1_DIFF;
+ }
+}
+
diff --git a/apps/common/icsd/anc/icsd_anc_client_board.h b/apps/common/icsd/anc/icsd_anc_client_board.h
new file mode 100644
index 0000000..93378db
--- /dev/null
+++ b/apps/common/icsd/anc/icsd_anc_client_board.h
@@ -0,0 +1,158 @@
+
+/*********************************************************************
+
+ ANC 耳道自适应配置文件
+
+*********************************************************************/
+
+#include "icsd_anc.h"
+
+#define DEVE_BOARD 0x00 //开发板
+#define HT03_HYBRID_6F 0x01 //CUSTOM1_CFG
+#define HT03_HYBRID_6G 0x02 //CUSTOM2_CFG
+#define A896_HYBRID_6G 0x03 //CUSTOM3_CFG
+#define HT05_6G 0x04 //CUSTOM4_CFG
+#define ANC05_HYBRID 0x05 //CUSTOM5_CFG
+#define G02_HYBRID_6G 0x06 //CUSTOM6_CFG
+#define AC098_HYBRID_6G 0x07 //CUSTOM7_CFG
+#define G96_HYBRID 0x08 //CUSTOM8_CFG
+#define H3_HYBRID 0x09 //CUSTOM9_CFG
+#define P90_HYBRID 0x0a //CUSTOM10_CFG
+#define JH4006_HYBRID 0x0d //CUSTOM10_CFG
+
+#define D28_HYBRID 0x80
+#define H3_TOZO_HYBIRD 0x81
+
+//自适应板级配置,适配不同样机
+//#define ADAPTIVE_CLIENT_BOARD HT03_HYBRID_6G
+//#define ADAPTIVE_CLIENT_BOARD G96_HYBRID
+//#define ADAPTIVE_CLIENT_BOARD P90_HYBRID
+//#define ADAPTIVE_CLIENT_BOARD G02_HYBRID_6G
+//#define ADAPTIVE_CLIENT_BOARD JH4006_HYBRID
+#define ADAPTIVE_CLIENT_BOARD D28_HYBRID
+//#define ADAPTIVE_CLIENT_BOARD H3_TOZO_HYBIRD
+//#define ADAPTIVE_CLIENT_BOARD H3_HYBIRD
+
+#if ADAPTIVE_CLIENT_BOARD == HT03_HYBRID_6G
+#define ICSD_ANC_MODE TWS_TONE_BYPASS_MODE
+#define ANC_ADAPTIVE_FF_ORDER 8 /*ANC自适应FF滤波器阶数, 原厂指定*/
+#define ANC_ADAPTIVE_FB_ORDER 5 /*ANC自适应FB滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_CMP_ORDER 8 /*ANC自适应CMP滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_RECORD_FF_ORDER 8 /*ANC自适应耳道记忆FF滤波器阶数,原厂指定*/
+#define ANC_FB_TRAIN_OFF 0
+#define ANC_FB_TRAIN_NEW 0
+#define ANC_EARPHONE_CHECK_EN 1
+#define ANC_ADAPTIVE_CMP_EN 1 //自适应CMP补偿
+#define ANC_ADAPTIVE_TONE_DELAY 700
+
+#elif ADAPTIVE_CLIENT_BOARD == G02_HYBRID_6G
+#define ICSD_ANC_MODE TWS_TONE_BYPASS_MODE
+#define ANC_ADAPTIVE_FF_ORDER 8 /*ANC自适应FF滤波器阶数, 原厂指定*/
+#define ANC_ADAPTIVE_FB_ORDER 6 /*ANC自适应FB滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_CMP_ORDER 4 /*ANC自适应CMP滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_RECORD_FF_ORDER 8 /*ANC自适应耳道记忆FF滤波器阶数,原厂指定*/
+#define ANC_FB_TRAIN_OFF 0
+#define ANC_FB_TRAIN_NEW 0
+#define ANC_EARPHONE_CHECK_EN 0
+#define ANC_ADAPTIVE_CMP_EN 0 //自适应CMP补偿
+#define ANC_ADAPTIVE_TONE_DELAY 700
+
+#elif ADAPTIVE_CLIENT_BOARD == ANC05_HYBRID
+#define ICSD_ANC_MODE HEADSET_TONES_MODE //HEADSET_TONE_BYPASS_MODE
+#define ANC_ADAPTIVE_FF_ORDER 8 /*ANC自适应FF滤波器阶数, 原厂指定*/
+#define ANC_ADAPTIVE_FB_ORDER 5 /*ANC自适应FB滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_CMP_ORDER 8 /*ANC自适应CMP滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_RECORD_FF_ORDER 8 /*ANC自适应耳道记忆FF滤波器阶数,原厂指定*/
+#define ANC_FB_TRAIN_OFF 0
+#define ANC_FB_TRAIN_NEW 0
+#define ANC_EARPHONE_CHECK_EN 0
+#define ANC_ADAPTIVE_CMP_EN 1 //自适应CMP补偿
+#define ANC_ADAPTIVE_TONE_DELAY 700
+
+#elif ADAPTIVE_CLIENT_BOARD == H3_HYBRID
+#define ICSD_ANC_MODE HEADSET_TONES_MODE //HEADSET_TONE_BYPASS_MODE
+#define ANC_ADAPTIVE_FF_ORDER 8 /*ANC自适应FF滤波器阶数, 原厂指定*/
+#define ANC_ADAPTIVE_FB_ORDER 6 /*ANC自适应FB滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_CMP_ORDER 8 /*ANC自适应CMP滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_RECORD_FF_ORDER 8 /*ANC自适应耳道记忆FF滤波器阶数,原厂指定*/
+#define ANC_FB_TRAIN_OFF 0
+#define ANC_FB_TRAIN_NEW 0
+#define ANC_EARPHONE_CHECK_EN 1
+#define ANC_ADAPTIVE_CMP_EN 1 //自适应CMP补偿
+#define ANC_ADAPTIVE_TONE_DELAY 700
+
+#elif ADAPTIVE_CLIENT_BOARD == H3_TOZO_HYBIRD
+#define ICSD_ANC_MODE HEADSET_TONES_MODE //HEADSET_TONE_BYPASS_MODE
+#define ANC_ADAPTIVE_FF_ORDER 8 /*ANC自适应FF滤波器阶数, 原厂指定*/
+#define ANC_ADAPTIVE_FB_ORDER 6 /*ANC自适应FB滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_CMP_ORDER 8 /*ANC自适应CMP滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_RECORD_FF_ORDER 8 /*ANC自适应耳道记忆FF滤波器阶数,原厂指定*/
+#define ANC_FB_TRAIN_OFF 0
+#define ANC_FB_TRAIN_NEW 0
+#define ANC_EARPHONE_CHECK_EN 1
+#define ANC_ADAPTIVE_CMP_EN 1 //自适应CMP补偿
+#define ANC_ADAPTIVE_TONE_DELAY 700
+
+#elif ADAPTIVE_CLIENT_BOARD == G96_HYBRID
+#define ICSD_ANC_MODE TWS_TONE_BYPASS_MODE //HEADSET_TONE_BYPASS_MODE
+#define ANC_ADAPTIVE_FF_ORDER 8 /*ANC自适应FF滤波器阶数, 原厂指定*/
+#define ANC_ADAPTIVE_FB_ORDER 5 /*ANC自适应FB滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_CMP_ORDER 8 /*ANC自适应CMP滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_RECORD_FF_ORDER 8 /*ANC自适应耳道记忆FF滤波器阶数,原厂指定*/
+#define ANC_FB_TRAIN_OFF 0
+#define ANC_FB_TRAIN_NEW 1
+#define ANC_EARPHONE_CHECK_EN 1
+#define ANC_ADAPTIVE_CMP_EN 0 //自适应CMP补偿
+#define ANC_ADAPTIVE_TONE_DELAY 700
+
+#elif ADAPTIVE_CLIENT_BOARD == P90_HYBRID
+//#define ICSD_ANC_MODE TWS_TONE_BYPASS_MODE
+#define ICSD_ANC_MODE TWS_TONE_MODE
+#define ANC_ADAPTIVE_FF_ORDER 8 /*ANC自适应FF滤波器阶数, 原厂指定*/
+#define ANC_ADAPTIVE_FB_ORDER 5 /*ANC自适应FB滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_CMP_ORDER 8 /*ANC自适应CMP滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_RECORD_FF_ORDER 8 /*ANC自适应耳道记忆FF滤波器阶数,原厂指定*/
+#define ANC_FB_TRAIN_OFF 1
+#define ANC_FB_TRAIN_NEW 0
+#define ANC_EARPHONE_CHECK_EN 0
+#define ANC_ADAPTIVE_CMP_EN 1 //自适应CMP补偿
+#define ANC_ADAPTIVE_TONE_DELAY 1600//700
+
+#elif ADAPTIVE_CLIENT_BOARD == D28_HYBRID
+#define ICSD_ANC_MODE TWS_TONE_MODE
+#define ANC_ADAPTIVE_FF_ORDER 10 /*ANC自适应FF滤波器阶数, 原厂指定*/
+#define ANC_ADAPTIVE_FB_ORDER 5 /*ANC自适应FB滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_CMP_ORDER 8 /*ANC自适应CMP滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_RECORD_FF_ORDER 10 /*ANC自适应耳道记忆FF滤波器阶数,原厂指定*/
+#define ANC_FB_TRAIN_OFF 1
+#define ANC_FB_TRAIN_NEW 0
+#define ANC_EARPHONE_CHECK_EN 0
+#define ANC_ADAPTIVE_CMP_EN 1 //自适应CMP补偿
+#define ANC_ADAPTIVE_TONE_DELAY 1600//700
+
+#elif ADAPTIVE_CLIENT_BOARD == JH4006_HYBRID
+#define ICSD_ANC_MODE HEADSET_TONES_MODE //HEADSET_TONE_BYPASS_MODE
+#define ANC_ADAPTIVE_FF_ORDER 8 /*ANC自适应FF滤波器阶数, 原厂指定*/
+#define ANC_ADAPTIVE_FB_ORDER 6 /*ANC自适应FB滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_CMP_ORDER 8 /*ANC自适应CMP滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_RECORD_FF_ORDER 8 /*ANC自适应耳道记忆FF滤波器阶数,原厂指定*/
+#define ANC_FB_TRAIN_OFF 0
+#define ANC_FB_TRAIN_NEW 0
+#define ANC_EARPHONE_CHECK_EN 0
+#define ANC_ADAPTIVE_CMP_EN 0 //自适应CMP补偿
+#define ANC_ADAPTIVE_TONE_DELAY 700
+
+#else
+#define ICSD_ANC_MODE TWS_TONE_BYPASS_MODE
+#define ANC_ADAPTIVE_FF_ORDER 8 /*ANC自适应FF滤波器阶数, 原厂指定*/
+#define ANC_ADAPTIVE_FB_ORDER 5 /*ANC自适应FB滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_CMP_ORDER 4 /*ANC自适应CMP滤波器阶数,原厂指定*/
+#define ANC_ADAPTIVE_RECORD_FF_ORDER 8 /*ANC自适应耳道记忆FF滤波器阶数,原厂指定*/
+#define ANC_FB_TRAIN_OFF 1
+#define ANC_FB_TRAIN_NEW 0
+#define ANC_EARPHONE_CHECK_EN 0
+#define ANC_ADAPTIVE_CMP_EN 0 //自适应CMP补偿
+#define ANC_ADAPTIVE_TONE_DELAY 700
+#endif/*ADAPTIVE_CLIENT_BOARD*/
+
+
diff --git a/apps/common/icsd/anc/icsd_anc_data.c b/apps/common/icsd/anc/icsd_anc_data.c
new file mode 100644
index 0000000..13bb0b9
--- /dev/null
+++ b/apps/common/icsd/anc/icsd_anc_data.c
@@ -0,0 +1,266 @@
+#include "audio_anc.h"
+
+const float THD_JT = 6;
+const float THD_JT_SAVE = 4;
+const float THD_JT2 = 7;
+
+const s8 ANC_s8_DATA[] = {
+ 6,//P_PARAM_01
+ -12,//P_PARAM_02
+ 4,//SP_PARAM_01
+ -12,//SP_PARAM_01
+ 28,//ANC_ERRMIC_SPL_DB
+ 12,//ANC_SZ_DB
+ -10,//EAR_CHECK_VLD1
+ -9,//EAR_CHECK_VLD2
+ 40,//FSTOP_IDX
+ 58,//FSTOP_IDX2
+ 41,//_ANC_REFMIC_SPL_DB
+ -4,//B_PARM1_THR_L
+ 4,//B_PARM1_THR_H
+ -6,//B_PARM2_THR_L
+ 6,//B_PARM2_THR_H
+ -4,//B_PARM3_THR_L
+ 4,//B_PARM3_THR_H
+};
+
+const double ICSD_ANC_DOUBLE_DATA[] = {
+//double cmp_iir_ab[10] //
+ 1.000496069900691509246826171875, -1.998426330275833606719970703125, 0.997930623590946197509765625, -1.998426330275833606719970703125, 0.9984266944229602813720703125,
+ 0.9998088735155761241912841796875, -1.999607323668897151947021484375, 0.9997985516674816608428955078125, -1.999607323668897151947021484375, 0.9996074251830577850341796875,
+};
+
+const float spl_tb [21] = {
+ 17, //134.765625000000
+ 19, //179.687500000000
+ 21, //224.609375000000
+ 22, //269.531250000000
+ 23, //314.453125000000
+ 23, //359.375000000000
+ 24, //404.296875000000
+ 26, //449.218750000000
+ 23, //494.140625000000
+ 24, //539.062500000000
+ 25, //583.984375000000
+ 25, //628.906250000000
+ 24, //673.828125000000
+ 22, //718.750000000000
+ 22, //763.671875000000
+ 23, //808.593750000000
+ 24, //853.515625000000
+ 25, //898.437500000000
+ 25, //943.359375000000
+ 24, //988.281250000000
+ 24, //1033.20312500000
+};
+
+const float spl_freq_tb [21] = {
+ 134.765625000000,
+ 179.687500000000,
+ 224.609375000000,
+ 269.531250000000,
+ 314.453125000000,
+ 359.375000000000,
+ 404.296875000000,
+ 449.218750000000,
+ 494.140625000000,
+ 539.062500000000,
+ 583.984375000000,
+ 628.906250000000,
+ 673.828125000000,
+ 718.750000000000,
+ 763.671875000000,
+ 808.593750000000,
+ 853.515625000000,
+ 898.437500000000,
+ 943.359375000000,
+ 988.281250000000,
+ 1033.20312500000
+};
+
+const float ICSD_ANC_DATA[] = {
+//float ff_fgq[25]
+ 1,//gain
+ 10000, 20.000, 1.000, //F G Q
+ 1200, -3.500, 1.000,
+ 2000, -4.000, 1.000,
+ 6500, -6.000, 1.000,
+ 10000, -30.000, 1.500,
+ 75, 2.000, 2.000,
+ 385, -4.260, 0.505,
+ 620, 1.600, 1.500,
+//float fb_fgq[25]
+ 0.707945,//gain
+ 3500.0, -6.000, 0.900, //F G Q
+ 1510.0, -2, 0.800,
+ 5289.0, -11, 0.800,
+ 120.0, 18.000, 0.600,
+ 45.0, 3.000, 1.000,
+ 20.0, 0.0, 1.000,
+ 20.0, 0.0, 1.000,
+ 20.0, 0.0, 1.000,
+//float ff_weight_HT03[75]
+ 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 10.00, 10.00, 10.00,
+ 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00,
+ 5.100, 5.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100,
+ 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100,
+ 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100, 0.100,
+//float best_param_fix[13]
+ -3.00,
+ 0.900, -6.000, 3500.0, // Q G F
+ 0.800, -2, 1510.0,
+ 0.800, -11, 5289.0,
+ 1.000, 0.0, 20.0,
+//float best_param_flex[6]
+ 0.600, 18.000, 120.0,
+ 1.000, 3.000, 45.0,
+//float biquad_init_lcl[10]
+ -1, 150, 0.5,
+ -3, 500, 1,
+ -7, 1200, 0.8,
+ -1,
+//float biquad_fix[15]
+ 8, 60, 1.8,
+ -10, 15, 1.5,
+ 4.5, 4500, 0.8,
+ -8, 7500, 2,
+ -25, 14000, 1.2,
+//float Vrange[26]
+ -5.0, 5.0, 130, 400, 0.3, 1,
+ -5.0, 5.0, 400, 900, 0.3, 1,
+ -10.0, -5.0, 900, 1400, 0.7, 0.9,
+ -1.1, -0.9,
+ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, //没有使用
+//float biquad_init_data[7]
+ 1.0,//highshlef_N
+ 4.0,//peak_N
+ 5.0,//N
+ 1.0,//h_fix
+ 2.0,//p_fix
+ 3.0,//n_fix
+ 2.0,//n_flex
+//float fb_std[3]
+ 1.414,
+ 0.707,
+ 20.0,
+//float k_cmp[75*2]
+ 0.355735, 0.000000,
+ 0.406650, 0.009267,
+ 0.540936, 0.013891,
+ 0.677297, 0.006987,
+ 0.661146, -0.122581,
+ 0.762457, -0.082076,
+ 0.845315, -0.032340,
+ 0.922015, 0.001376,
+ 0.983304, 0.017571,
+ 1.003132, 0.021645,
+ 1.013473, 0.016530,
+ 1.014149, 0.007091,
+ 1.005985, -0.001269,
+ 0.992157, -0.002376,
+ 0.982547, 0.008197,
+ 0.987876, 0.019249,
+ 0.993822, 0.015540,
+ 0.984279, 0.010513,
+ 0.969368, 0.020658,
+ 0.970804, 0.034582,
+ 0.996935, 0.025907,
+ 0.985948, 0.031042,
+ 0.935211, 0.022464,
+ 0.953423, 0.025235,
+ 0.961401, 0.012630,
+ 0.929649, 0.025147,
+ 0.916033, 0.070842,
+ 0.908546, 0.113489,
+ 0.890224, 0.146915,
+ 0.880289, 0.170188,
+ 0.897130, 0.177176,
+ 0.899322, 0.215329,
+ 0.902587, 0.219978,
+ 0.901702, 0.301843,
+ 0.930309, 0.364164,
+ 0.958195, 0.421897,
+ 1.015677, 0.431439,
+ 1.046609, 0.453263,
+ 1.089167, 0.435698,
+ 1.112152, 0.445592,
+ 1.149376, 0.458663,
+ 1.143086, 0.467994,
+ 1.178618, 0.494142,
+ 1.178230, 0.490062,
+ 1.202727, 0.519448,
+ 1.264703, 0.538896,
+ 1.300802, 0.571430,
+ 1.309515, 0.629530,
+ 1.383454, 0.672111,
+ 1.433505, 0.684519,
+ 1.510080, 0.676279,
+ 1.680950, 0.720572,
+ 1.649127, 0.726221,
+ 1.787352, 0.769206,
+ 1.911621, 0.671973,
+ 1.936819, 0.780815,
+ 2.111839, 0.570215,
+ 2.236738, 0.596179,
+ 2.329324, 0.556353,
+ 2.423803, 0.479938,
+ 2.548114, 0.379554,
+ 2.495549, 0.279278,
+ 2.675386, -0.007060,
+ 2.512869, -0.084337,
+ 2.723908, -0.190948,
+ 2.353746, -0.626941,
+ 2.550212, -0.385014,
+ 2.369031, -0.435515,
+ 2.333464, -0.795883,
+ 1.912714, -0.841469,
+ 1.844244, -1.095402,
+ 1.741950, -1.333718,
+ 1.919448, -1.361989,
+ 1.672145, -1.309203,
+ 1.559095, -0.326499,
+//cmp_fix_biquad
+ -31.603, 19, 5,
+ 4.247, 36, 0.3,
+ -12.149, 9046, 0.9,
+ 11.905, 6464, 1.2,
+//cmp_flex_vrange
+ -8, 8, 100, 300, 0.6, 1,
+ -8, 8, 400, 800, 0.5, 1,
+ -8, 8, 800, 1000, 0.5, 1,
+ -5, 5, 1000, 1500, 0.8, 1.5,
+ 0.35481, 0.35481,
+//cmp_flex_init
+ 4.985, 193, 0.8,
+ 0, 500, 1,
+ 6.1, 900, 0.57,
+ 0, 1200, 0.5,
+//cmp_weight
+ 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 10.00, 10.00, 10.00, 10.00,
+ 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00,
+ 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 3.000, 3.000, 3.000,
+ 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000,
+ 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000,
+//cmp_iir_ab_idx
+ 2,
+//nmss_config
+ 1,//flex_seq[0]
+ 2,//flex_seq[1]
+ 0,//flex_seq[2]
+ 0,//flex_seq[3]
+ 0,//flex_seq[4]
+ 0,//flex_seq[5]
+ 2,//n
+ 1.0,//rho
+ 2.0,//chi
+ 0.5,//psi
+ 0.5,//sigma
+ 250,//maxnum
+ 0.10,//usual_delta
+ 5.0,//zero_term_delta
+//lowshelf_config
+ 0, //en
+ 26, //f
+ -8.0,//g
+ 1.0, //q
+};
diff --git a/apps/common/include/bt_common.h b/apps/common/include/bt_common.h
new file mode 100644
index 0000000..06e4b98
--- /dev/null
+++ b/apps/common/include/bt_common.h
@@ -0,0 +1,232 @@
+// binary representation
+// attribute size in bytes (16), flags(16), handle (16), uuid (16/128), value(...)
+
+#ifndef _BT_COMMON_H
+#define _BT_COMMON_H
+#include
+#include "app_config.h"
+
+#define UART_FIFIO_BUF_LEN 1024
+
+#ifdef APP_PRIVATE_PROFILE_CFG
+#include "lib_profile_cfg.h"
+#else
+#include "bt_profile_cfg.h"
+#endif
+
+#define SYNC_TIMEOUT_MS(x) {(x / 10) & 0xff, (x / 10) >> 8}
+
+#define ALIGN_2BYTE(size) (((size)+1)&0xfffffffe)
+#define BYTE_LEN(x...) sizeof((u8 []) {x})
+#define MS_TO_SLOT(x) (x * 8 / 5)
+#define UINT24_TO_BYTE(x) \
+{ \
+ (x), \
+ (x) >> 8, \
+ (x) >> 16 \
+}
+
+enum {
+ ST_BIT_INQUIRY = 0,
+ ST_BIT_PAGE_SCAN,
+ ST_BIT_BLE_ADV,
+ ST_BIT_SPP_CONN,
+ ST_BIT_BLE_CONN,
+ ST_BIT_WEIXIN_CONN,
+};
+
+enum {
+ BLE_PRIV_MSG_PAIR_CONFIRM = 0xF0,
+ BLE_PRIV_PAIR_ENCRYPTION_CHANGE,
+};//ble_state_e
+
+
+// #define SYS_BT_EVENT_FORM_COMMON (('C' << 24) | ('M' << 16) | ('M' << 8) | '\0')
+enum {
+ COMMON_EVENT_EDR_REMOTE_TYPE = 1,
+ COMMON_EVENT_BLE_REMOTE_TYPE,
+ COMMON_EVENT_SHUTDOWN_ENABLE,
+ COMMON_EVENT_SHUTDOWN_DISABLE,
+ COMMON_EVENT_MODE_DETECT,
+};
+
+// LE Controller Commands
+struct __ext_adv_report_event {
+ u8 Subevent_Code;
+ u8 Num_Reports;
+ u16 Event_Type;
+ u8 Address_Type;
+ u8 Address[6];
+ u8 Primary_PHY;
+ u8 Secondary_PHY;
+ u8 Advertising_SID;
+ u8 Tx_Power;
+ u8 RSSI;
+ u16 Periodic_Advertising_Interval;
+ u8 Direct_Address_Type;
+ u8 Direct_Address[6];
+ u8 Data_Length;
+ u8 Data[0];
+} _GNU_PACKED_;
+
+struct __periodic_adv_report_event {
+ u8 Subevent_Code;
+ u16 Sync_Handle;
+ u8 Tx_Power;
+ u8 RSSI;
+ u8 Unused;
+ u8 Data_Status;
+ u8 Data_Length;
+ u8 Data[0];
+} _GNU_PACKED_ ;
+
+struct __periodic_creat_sync {
+ u8 Filter_Policy;
+ u8 Advertising_SID;
+ u8 Advertising_Address_Type;
+ u8 Advertiser_Address[6];
+ u8 Skip[2];
+ u8 Sync_Timeout[2];
+ u8 Unused;
+} _GNU_PACKED_;
+
+struct __ext_scan_param {
+ u8 Own_Address_Type;
+ u8 Scanning_Filter_Policy;
+ u8 Scanning_PHYs;
+ u8 Scan_Type;
+ u16 Scan_Interval;
+ u16 Scan_Window;
+} _GNU_PACKED_;
+
+struct __ext_scan_enable {
+ u8 Enable;
+ u8 Filter_Duplicates;
+ u16 Duration;
+ u16 Period;
+} _GNU_PACKED_;
+
+struct ext_advertising_param {
+ u8 Advertising_Handle;
+ u16 Advertising_Event_Properties;
+ u8 Primary_Advertising_Interval_Min[3];
+ u8 Primary_Advertising_Interval_Max[3];
+ u8 Primary_Advertising_Channel_Map;
+ u8 Own_Address_Type;
+ u8 Peer_Address_Type;
+ u8 Peer_Address[6];
+ u8 Advertising_Filter_Policy;
+ u8 Advertising_Tx_Power;
+ u8 Primary_Advertising_PHY;
+ u8 Secondary_Advertising_Max_Skip;
+ u8 Secondary_Advertising_PHY;
+ u8 Advertising_SID;
+ u8 Scan_Request_Notification_Enable;
+} _GNU_PACKED_;
+
+struct ext_advertising_data {
+ u8 Advertising_Handle;
+ u8 Operation;
+ u8 Fragment_Preference;
+ u8 Advertising_Data_Length;
+ u8 Advertising_Data[31];
+} _GNU_PACKED_;
+
+struct ext_advertising_enable {
+ u8 Enable;
+ u8 Number_of_Sets;
+ u8 Advertising_Handle;
+ u16 Duration;
+ u8 Max_Extended_Advertising_Events;
+} _GNU_PACKED_;
+
+struct periodic_advertising_param {
+ u8 Advertising_Handle;
+ u16 Periodic_Advertising_Interval_Min;
+ u16 Periodic_Advertising_Interval_Max;
+ u16 Periodic_Advertising_Properties;
+} _GNU_PACKED_;
+
+struct periodic_advertising_data {
+ u8 Advertising_Handle;
+ u8 Operation;
+ u8 Advertising_Data_Length;
+ u8 Advertising_Data[31];
+} _GNU_PACKED_;
+
+struct periodic_advertising_enable {
+ u8 Enable;
+ u8 Advertising_Handle;
+} _GNU_PACKED_;
+
+typedef struct {
+ uint16_t Sync_Handle;
+} _GNU_PACKED_ periodic_adv_terminate_sync;
+
+extern const int config_le_hci_connection_num;//支持同时连接个数
+extern const int config_le_sm_support_enable; //是否支持加密配对
+extern const int config_le_gatt_server_num; //支持server角色个数
+extern const int config_le_gatt_client_num; //支持client角色个数
+
+extern uint16_t little_endian_read_16(const uint8_t *buffer, int pos);
+extern uint32_t little_endian_read_24(const uint8_t *buffer, int pos);
+extern uint32_t little_endian_read_32(const uint8_t *buffer, int pos);
+extern void swapX(const uint8_t *src, uint8_t *dst, int len);
+
+extern void little_endian_store_16(uint8_t *buffer, uint16_t pos, uint16_t value);
+extern void little_endian_store_32(uint8_t *buffer, uint16_t pos, uint32_t value);
+extern void big_endian_store_16(uint8_t *buffer, uint16_t pos, uint16_t value);
+extern void big_endian_store_32(uint8_t *buffer, uint16_t pos, uint32_t value);
+
+//common api
+extern void bt_ble_init(void);
+extern void bt_ble_exit(void);
+extern void bt_ble_adv_enable(u8 enable);
+extern void ble_app_disconnect(void);
+extern void ble_module_enable(u8 en);
+extern const u8 *bt_get_mac_addr();
+extern void lib_make_ble_address(u8 *ble_address, u8 *edr_address);
+extern void user_spp_data_handler(u8 packet_type, u16 ch, u8 *packet, u16 size);
+extern void bt_get_vm_mac_addr(u8 *addr);
+extern void set_remote_test_flag(u8 own_remote_test);
+extern void bredr_power_get(void);
+extern void bredr_power_put(void);
+extern void radio_set_eninv(int v);
+extern void transport_spp_init(void);
+extern const char *bt_get_local_name();
+extern void wdt_clear(void);
+extern u8 ble_update_get_ready_jump_flag(void);
+extern void reset_PK_cb_register(void (*reset_pk)(u32 *));
+extern void reset_PK_cb_register_ext(void (*reset_pk)(u32 *, u16));
+extern void att_server_flow_enable(u8 enable);
+extern void le_device_db_init(void);
+extern bool get_remote_test_flag();
+extern void transport_spp_disconnect(void);
+extern int transport_spp_flow_enable(u8 en);
+extern void transport_spp_flow_cfg(void);
+
+void att_set_conn_handle(u16 conn_handle, u8 handle_type);
+void at_send_rx_cid_data(u8 cid, u8 *packet, u16 size);
+void at_send_conn_result(u8 cid, u8 is_sucess);
+void at_send_disconnect(u8 cid);
+void at_send_connected(u8 cid);
+void at_send_string(u8 *str);
+void at_respond_send_err(u32 err_id);
+
+int le_att_server_send_data(u8 cid, u8 *packet, u16 size);
+int le_att_server_send_ctrl(u8 cid, u8 *packet, u16 size);
+int le_att_client_send_data(u8 cid, u8 *packet, u16 size);
+int le_at_client_creat_connection(u8 *conn_addr, u8 addr_type);
+void black_list_check(u8 sta, u8 *peer_addr);
+
+
+//errid
+enum {
+ ERR_AT_CMD = 1,
+ //add here
+};
+
+//初始化配置蓝牙发射功率最大值范围,解析详见 btcontroller_modules.h
+void bt_max_pwr_set(u8 pwr, u8 pg_pwr, u8 iq_pwr, u8 ble_pwr);
+
+#endif
diff --git a/apps/common/include/cfg_private.h b/apps/common/include/cfg_private.h
new file mode 100644
index 0000000..282034f
--- /dev/null
+++ b/apps/common/include/cfg_private.h
@@ -0,0 +1,12 @@
+#ifndef _CFG_PRIVATE_H
+#define _CFG_PRIVATE_H
+
+int cfg_private_delete_file(FILE *file);
+int cfg_private_write(FILE *file, void *buf, u32 len);
+FILE *cfg_private_open(const char *path, const char *mode);
+int cfg_private_read(FILE *file, void *buf, u32 len);
+int cfg_private_close(FILE *file);
+int cfg_private_seek(FILE *file, int offset, int fromwhere);
+void cfg_private_erase(u32 addr, u32 len);
+
+#endif
diff --git a/apps/common/include/norflash_sfc.h b/apps/common/include/norflash_sfc.h
new file mode 100644
index 0000000..0637eec
--- /dev/null
+++ b/apps/common/include/norflash_sfc.h
@@ -0,0 +1,56 @@
+#ifndef _NORFLASH_H
+#define _NORFLASH_H
+
+#include "device/device.h"
+#include "ioctl_cmds.h"
+#include "asm/spi.h"
+#include "printf.h"
+#include "gpio.h"
+#include "device_drive.h"
+#include "malloc.h"
+#include "asm/sfc_spi.h"
+
+/*************************************************/
+/*
+ COMMAND LIST - WinBond FLASH WX25X
+*/
+/***************************************************************/
+#define WINBOND_WRITE_ENABLE 0x06
+#define WINBOND_READ_SR1 0x05
+#define WINBOND_READ_SR2 0x35
+#define WINBOND_WRITE_SR1 0x01
+#define WINBOND_WRITE_SR2 0x31
+#define WINBOND_READ_DATA 0x03
+#define WINBOND_FAST_READ_DATA 0x0b
+#define WINBOND_FAST_READ_DUAL_OUTPUT 0x3b
+#define WINBOND_PAGE_PROGRAM 0x02
+#define WINBOND_PAGE_ERASE 0x81
+#define WINBOND_SECTOR_ERASE 0x20
+#define WINBOND_BLOCK_ERASE 0xD8
+#define WINBOND_CHIP_ERASE 0xC7
+#define WINBOND_JEDEC_ID 0x9F
+
+enum {
+ FLASH_PAGE_ERASER,
+ FLASH_SECTOR_ERASER,
+ FLASH_BLOCK_ERASER,
+ FLASH_CHIP_ERASER,
+};
+
+struct norflash_sfc_dev_platform_data {
+ const struct sfc_spi_platform_data *sfc_spi_pdata;
+ u32 start_addr; //分区起始地址
+ u32 size; //分区大小,若只有1个分区,则这个参数可以忽略
+};
+
+#define NORFLASH_SFC_DEV_PLATFORM_DATA_BEGIN(data) \
+ const struct norflash_sfc_dev_platform_data data = {
+
+#define NORFLASH_SFC_DEV_PLATFORM_DATA_END() \
+};
+
+extern const struct device_operations norflash_sfc_dev_ops;
+extern const struct device_operations norflash_sfc_fs_dev_ops;
+
+#endif
+
diff --git a/apps/common/include/standard_hid.h b/apps/common/include/standard_hid.h
new file mode 100644
index 0000000..10eb17a
--- /dev/null
+++ b/apps/common/include/standard_hid.h
@@ -0,0 +1,18 @@
+#ifndef __STANDARD_HID_H__
+#define __STANDARD_HID_H__
+
+#include "typedef.h"
+#include "usb/device/hid.h"
+/*******************************************************************/
+/*
+ *-------------------hid for ble
+ */
+#define HID_UUID_16 0x1812
+#define HID_INFORMATION_UUID_16 0x2A4A
+#define HID_REPORT_MAP_UUID_16 0x2A4B
+#define HID_CONTROL_POINT_UUID_16 0x2A4C
+#define HID_REPORT_UUID_16 0x2A4D
+#define PROTOCOL_MODE_UUID_16 0x2A4E
+#define HID_REPORT_REFERENCE_UUID_16 0x2908
+
+#endif // #define __STANDARD_HID_H__
diff --git a/apps/common/include/update_tws.h b/apps/common/include/update_tws.h
new file mode 100644
index 0000000..71d014c
--- /dev/null
+++ b/apps/common/include/update_tws.h
@@ -0,0 +1,92 @@
+#ifndef _RCSP_ADV_TWS_OTA_H
+#define _RCSP_ADV_TWS_OTA_H
+
+#include "app_config.h"
+
+#if (OTA_TWS_SAME_TIME_ENABLE && (RCSP_ADV_EN || AI_APP_PROTOCOL) && !OTA_TWS_SAME_TIME_NEW)
+
+#define SYS_BT_OTA_EVENT_TYPE_STATUS (('O' << 24) | ('T' << 16) | ('A' << 8) | '\0')
+
+#include "system/event.h"
+#include "update_loader_download.h"
+
+typedef int sint32_t;
+
+enum {
+ OTA_OVER = 0,
+ OTA_INIT,
+ OTA_START,
+ OTA_VERIFY_ING,
+ OTA_VERIFY_END,
+ OTA_SUCC,
+};
+
+enum {
+ OTA_SINGLE_EARPHONE,
+ OTA_TWS,
+};
+
+enum {
+ OTA_START_UPDATE = 0,
+ OTA_START_UPDATE_READY,
+ OTA_START_VERIFY,
+ OTA_UPDATE_OVER,
+ OTA_UPDATE_ERR,
+ OTA_UPDATE_SUCC,
+};
+
+enum {
+ OTA_TYPE_SET = 0,
+ OTA_TYPE_GET,
+ OTA_STATUS_SET,
+ OTA_STATUS_GET,
+ OTA_REMOTE_STATUS_SET,
+ OTA_REMOTE_STATUS_GET,
+ OTA_RESULT_SET,
+ OTA_RESULT_GET,
+};
+
+
+enum {
+ OTA_STOP_APP_DISCONNECT,
+ OTA_STOP_LINK_DISCONNECT,
+ OTA_STOP_UPDATE_OVER_SUCC,
+ OTA_STOP_UPDATE_OVER_ERR,
+ OTA_STOP_PHONE,
+};
+
+enum {
+ SYNC_CMD_START_UPDATE,
+ SYNC_CMD_START_VERIFY,
+ SYNC_CMD_UPDATE_OVER,
+ SYNC_CMD_UPDATE_ERR,
+};
+
+int tws_ota_init(void);
+int tws_ota_close(void);
+
+int tws_ota_open(struct __tws_ota_para *para);
+void tws_ota_stop(u8 reason);
+
+u16 tws_ota_enter_verify(void *priv);
+u16 tws_ota_exit_verify(u8 *res, u8 *up_flg);
+u16 tws_ota_updata_boot_info_over(void *priv);
+
+int tws_ota_err_callback(u8 reason);
+
+int tws_ota_data_send_m_to_s(u8 *buf, u16 len);
+int tws_ota_sync_cmd(int reason);
+void tws_ota_app_event_deal(u8 evevt);
+u8 dual_bank_update_burn_boot_info_callback(u8 ret);
+int bt_ota_event_handler(struct bt_event *bt);
+void tws_ota_event_post(u32 type, u8 event);
+
+u8 tws_ota_control(int type, ...);
+
+void tws_ota_send_data_to_sibling(u8 opcode, u8 *data, u8 len);
+int tws_ota_get_data_from_sibling(u8 opcode, u8 *data, u8 len);
+
+#endif //(OTA_TWS_SAME_TIME_ENABLE && RCSP_ADV_EN)
+
+#endif //_RCSP_ADV_TWS_OTA_H
+
diff --git a/apps/common/include/update_tws_new.h b/apps/common/include/update_tws_new.h
new file mode 100644
index 0000000..920a8f0
--- /dev/null
+++ b/apps/common/include/update_tws_new.h
@@ -0,0 +1,123 @@
+#ifndef _UPRATE_TWS_NEW_H
+#define _UPRATE_TWS_NEW_H
+
+#include "app_config.h"
+#define SYS_BT_OTA_EVENT_TYPE_STATUS (('O' << 24) | ('T' << 16) | ('A' << 8) | '\0')
+#if (OTA_TWS_SAME_TIME_ENABLE && OTA_TWS_SAME_TIME_NEW)//(RCSP_ADV_EN || AI_APP_PROTOCOL))
+
+
+#define TWS_FUNC_ID_OTA_TRANS (('O' << (3 * 8)) | ('T' << (2 * 8)) | ('A' << (1 * 8)) | ('\0'))
+
+#include "system/event.h"
+#include "update_loader_download.h"
+
+typedef int sint32_t;
+
+enum {
+ OTA_OVER = 0,
+ OTA_INIT,
+ OTA_START,
+ OTA_VERIFY_ING,
+ OTA_VERIFY_END,
+ OTA_SUCC,
+};
+
+enum {
+ OTA_SINGLE_EARPHONE,
+ OTA_TWS,
+};
+
+enum {
+ OTA_START_UPDATE = 0,
+ OTA_START_UPDATE_READY,
+ OTA_START_VERIFY,
+ OTA_UPDATE_OVER,
+ OTA_UPDATE_ERR,
+ OTA_UPDATE_SUCC,
+};
+
+enum {
+ OTA_TYPE_SET = 0,
+ OTA_TYPE_GET,
+ OTA_STATUS_SET,
+ OTA_STATUS_GET,
+ OTA_REMOTE_STATUS_SET,
+ OTA_REMOTE_STATUS_GET,
+ OTA_RESULT_SET,
+ OTA_RESULT_GET,
+};
+
+
+enum {
+ OTA_STOP_APP_DISCONNECT,
+ OTA_STOP_LINK_DISCONNECT,
+ OTA_STOP_UPDATE_OVER_SUCC,
+ OTA_STOP_UPDATE_OVER_ERR,
+ OTA_STOP_PHONE,
+};
+
+enum {
+ SYNC_CMD_START_UPDATE,
+ SYNC_CMD_START_VERIFY,
+ SYNC_CMD_UPDATE_OVER,
+ SYNC_CMD_UPDATE_ERR,
+};
+
+//TWS OTA CMD
+enum {
+ OTA_TWS_INIT,
+ OTA_TWS_START_UPDATE = 0x1,
+ OTA_TWS_START_UPDATE_RSP,
+ OTA_TWS_TRANS_UPDATE_DATA,
+ OTA_TWS_TRANS_UPDATE_DATA_RSP,
+ OTA_TWS_VERIFY,
+ OTA_TWS_VERIFY_RSP,
+ OTA_TWS_UPDATE_RESULT,
+ OTA_TWS_WRITE_BOOT_INFO,
+ OTA_TWS_WRITE_BOOT_INFO_RSP,
+ OTA_TWS_USER_CHIP_UPDATE,
+};
+
+enum {
+ OTA_TWS_CMD_SUCC = 0x1,
+ OTA_TWS_CMD_ERR,
+};
+
+#define MSG_OTA_TWS_START_UPDATE 0x1
+#define MSG_OTA_TWS_START_UPDATE_RSP 0x2
+#define MSG_OTA_TWS_TRANS_UPDATE_DATA 0x3
+#define MSG_OTA_TWS_TRANS_UPDATE_DATA_RSP 0x4
+#define MSG_OTA_TWS_VERIFY 0x5
+#define MSG_OTA_TWS_VERIFY_RSP 0x6
+
+
+int tws_ota_init(void);
+int tws_ota_close(void);
+
+int tws_ota_open(struct __tws_ota_para *para);
+void tws_ota_stop(u8 reason);
+
+u16 tws_ota_enter_verify(void *priv);
+u16 tws_ota_exit_verify(u8 *res, u8 *up_flg);
+u16 tws_ota_updata_boot_info_over(void *priv);
+
+int tws_ota_err_callback(u8 reason);
+
+int tws_ota_data_send_m_to_s(u8 *buf, u16 len);
+int tws_ota_sync_cmd(int reason);
+void tws_ota_app_event_deal(u8 evevt);
+u8 dual_bank_update_burn_boot_info_callback(u8 ret);
+int bt_ota_event_handler(struct bt_event *bt);
+void tws_ota_event_post(u32 type, u8 event);
+
+u8 tws_ota_control(int type, ...);
+
+void tws_ota_send_data_to_sibling(u8 opcode, u8 *data, u8 len);
+int tws_ota_get_data_from_sibling(u8 opcode, u8 *data, u8 len);
+
+int tws_ota_result(u8 err);
+int tws_ota_data_send_pend(void);
+#endif //(OTA_TWS_SAME_TIME_ENABLE && RCSP_ADV_EN)
+
+#endif //_RCSP_ADV_TWS_OTA_H
+
diff --git a/apps/common/phone_message/phone_message.h b/apps/common/phone_message/phone_message.h
new file mode 100644
index 0000000..6fa5785
--- /dev/null
+++ b/apps/common/phone_message/phone_message.h
@@ -0,0 +1,206 @@
+#ifndef _PHONE_MESSAGE_
+#define _PHONE_MESSAGE_
+
+#include "application/audio_dec_app.h"
+#include "btstack/avctp_user.h"
+#include "classic/tws_api.h"
+#include "app_config.h"
+#include "app_main.h"
+
+#define PHONE_MESSAGE_TWS_ENABLE 0
+
+#if (TCFG_PHONE_MESSAGE_ENABLE)
+//////////////////////////////////////////////////////////////////////////////
+
+#if TCFG_USER_TWS_ENABLE
+#undef PHONE_MESSAGE_TWS_ENABLE
+#define PHONE_MESSAGE_TWS_ENABLE 1 // 通话留言TWS使能
+#endif
+
+#define PHONE_MESSAGE_ENC_USE_TASK (1) // 使用单独线程存储录音数据
+
+#define PHONE_MESSAGE_DEC_GET_INFO_ONLY_ENC 0 // 仅在播录音过程中可以获取信息
+#define PHONE_MESSAGE_DEC_GET_INFO_LIMIT_TIME (10*1000) // 在限制时间内获取有效
+
+#define PHONE_MESSAGE_TWS_BUF_LEN (4*1024) // tws转发buf
+#define PHONE_MESSAGE_TWS_PKT_LEN (512) // 每一包最大长度
+
+#define PHONE_MESSAGE_USE_BUF_LEN (1*1024) // 留言推提示音和录音buf
+
+// 通话留言按键响应类型
+#define CONFIG_PHONE_MESSAGE_KEY_ALL 1 // 都可以响应
+#define CONFIG_PHONE_MESSAGE_KEY_LEFT 2 // 仅左耳可以响应
+#define CONFIG_PHONE_MESSAGE_KEY_RIGHT 3 // 仅右耳可以响应
+#define CONFIG_PHONE_MESSAGE_ENC_KEY_TYPE CONFIG_PHONE_MESSAGE_KEY_ALL//CONFIG_PHONE_MESSAGE_KEY_RIGHT
+#define CONFIG_PHONE_MESSAGE_PLAY_KEY_TYPE CONFIG_PHONE_MESSAGE_KEY_ALL
+
+
+#define PHONE_MESSAGE_ENC_HEAD SDFILE_RES_ROOT_PATH"tone/msg_head.*"
+#define PHONE_MESSAGE_ENC_TAIL SDFILE_RES_ROOT_PATH"tone/msg_tail.*"
+
+#define PHONE_MESSAGE_DEC_HAVE SDFILE_RES_ROOT_PATH"tone/msg_have.*"
+#define PHONE_MESSAGE_DEC_NONE SDFILE_RES_ROOT_PATH"tone/msg_none.*"
+
+enum {
+ PHONE_MESSAGE_EVENT_NULL = 0,
+ PHONE_MESSAGE_EVENT_HEAD_TONE_END, // head提示音播放结束
+ PHONE_MESSAGE_EVENT_TIMEOUT, // 超时
+ PHONE_MESSAGE_EVENT_ENERGY, // 能量检测结束
+ PHONE_MESSAGE_EVENT_WRITE_FILE_ERROR, // 写文件失败
+ PHONE_MESSAGE_EVENT_STOP, // 留言已结束
+};
+
+enum {
+ PHONE_MESSAGE_STATUS_IDLE = 0,
+ PHONE_MESSAGE_STATUS_PLAY_HEAD, // 正在推送起始提示音
+ PHONE_MESSAGE_STATUS_ENC, // 正在录音
+ PHONE_MESSAGE_STATUS_PLAY_TAIL, // 正在推送结束提示音
+ PHONE_MESSAGE_STATUS_WAIT_STOP, // 等待结束
+};
+
+enum {
+ PHONE_MESSAGE_USE_BUF_TYPE_NULL = 0,
+ PHONE_MESSAGE_USE_BUF_TYPE_OUT, // buf用于推送提示音
+ PHONE_MESSAGE_USE_BUF_TYPE_ENC, // buf用于录音
+};
+
+enum {
+ PHONE_MESSAGE_DEC_STATUS_IDLE = 0,
+ PHONE_MESSAGE_DEC_STATUS_PLAY_HAVE, // 播放 有留言 提示音
+ PHONE_MESSAGE_DEC_STATUS_PLAY_NONE, // 播放 没有留言 提示音
+ PHONE_MESSAGE_DEC_STATUS_PLAY_ENC, // 播放留言内容
+ PHONE_MESSAGE_DEC_STATUS_WAIT_STOP, // 等待结束
+};
+
+struct phone_message_hdl {
+ u32 status : 4; // 留言状态
+ volatile u32 init_ok : 1; // 已经初始化
+ u32 time_check : 1; // 留言超时使能
+ u32 energy_check : 1; // 留言能量检测使能
+ u32 energy_flag : 1; // 标记全程是否有能量检测达标
+ u32 min_time_check : 1; // 时间太短,删除
+ u32 enc_limit_energy : 1; // 整个过程中能量都不达标,删除
+ u32 esco_dec_mute : 1; // 近端静音
+ u32 tws : 1; // 1:tws模式;0:普通模式,本地播放
+ void *head_file_hdl; // 留言起始提示音
+ void *tail_file_hdl; // 留言结束提示音
+ struct audio_dec_app_hdl *dec; // 解码句柄
+ u16 mic_sr; // mic采样率
+ u8 mic_ch; // mic通道数
+ u8 pkt_len; // 帧长
+ u8 phone_num[12]; // 电话号码
+ u16 sample_rate; // 留言数据采样率
+ u32 coding_type; // 留言数据类型
+ u32 out_need_points; // mic输出点数统计
+ u32 out_cur_points; // 当前输出点数
+ u32 out_mute_points; // 静音点数
+ cbuffer_t out_cbuf; // 输出循环buf
+#if PHONE_MESSAGE_ENC_USE_TASK
+ volatile u8 enc_task_stop; // 留言任务stop
+ u8 enc_task_init_ok : 1; // 留言任务初始化完成
+ u8 enc_write_err : 1; // 留言任务写出错
+ u16 enc_lost; // 留言写数据丢失统计
+ OS_SEM enc_task_sem; // 留言任务信号量
+ cbuffer_t enc_cbuf; // 留言写数循环buf
+#endif
+ u8 *use_buf; // 使用buf
+ u8 use_buf_type; // 使用buf类型
+ u32 energy_limit; // 能量阀值
+ u16 energy_max; // 连续最大能量不达标次数
+ u16 energy_cnt; // 能量不达标计数
+ unsigned long max_time; // 留言最大时间限制
+ unsigned long min_time; // 留言最小时间限制
+ unsigned long pause_time; // 临时停了多长时间
+ unsigned long start_limit_time; // 起始提示音启动限制时间
+ void *evt_priv; // 事件回调私有句柄
+ int (*evt_cb)(void *priv, int event, int *param); // 事件回调
+ };
+
+ struct phone_message_dec_hdl {
+ u32 status : 4; // 播放状态
+ u32 del_enc : 1; // 是否删除文件
+ u32 limit_time_check : 1; // 获取留言信息时间限制使能
+ u32 tws : 1; // 1:tws模式;0:普通模式,本地播放
+ u32 tws_master : 1; // 主机。留言所在的机器
+ u32 tws_file_end : 1; // 留言文件已经读完。并不意味着tws已经发送完
+ u32 tws_no_put_close : 1; // 不推送close消息
+ void *file_hdl; // 文件句柄
+ struct audio_dec_app_hdl *dec; // 解码句柄
+ char *name_mic_have; // 有留言 提示音
+ char *name_mic_none; // 没有留言 提示音
+ u8 pkt_len; // 留言数据帧长
+ u8 phone_num[12]; // 留言电话号码
+ u16 sample_rate; // 留言数据采样率
+ u32 coding_type; // 留言数据类型
+ unsigned long limit_time; // 获取留言信息时间限制
+ u32 create_time; // 当前解码创建时的时间
+
+#if PHONE_MESSAGE_TWS_ENABLE
+ void *tws_buf; // tws buf
+ u8 *tws_pkt_data; // tws数据起始位置
+ int tws_pkt_len; // tws数据总长
+ int tws_pkt_ptr; // tws数据已经使用长度
+#endif
+};
+
+//////////////////////////////////////////////////////////////////////////////
+extern u8 phone_message_have;
+extern u8 phone_message_idx;
+extern struct phone_message_hdl *phone_message;
+extern struct phone_message_dec_hdl *phone_message_dec;
+
+//////////////////////////////////////////////////////////////////////////////
+// call
+int phone_message_call_open(void);
+void phone_message_close(void);
+struct phone_message_hdl *phone_message_create(void);
+int phone_message_mic_write(s16 *data, int len); // 负数:非电话留言
+int phone_message_output_read(s16 *data, int len); // 负数:非电话留言
+int phone_message_enc_write(u8 *data, int len); // 负数:非电话留言
+void phone_message_enc_file_del(void);
+
+//////////////////////////////////////////////////////////////////////////////
+// play
+void phone_message_dec_close(void);
+struct phone_message_dec_hdl *phone_massage_dec_create(void);
+int phone_massage_dec(struct phone_message_dec_hdl *dec, u8 have);
+int phone_message_dec_open(u8 del_enc);
+
+//////////////////////////////////////////////////////////////////////////////
+// api
+void phone_message_call_api_close(void);
+int phone_message_call_api_open(void);
+int phone_message_call_api_start(void);
+int phone_message_call_api_stop(void);
+int phone_message_call_api_set_info(u32 coding_type, u16 sr, u8 *num);
+int phone_message_call_api_get_info(u32 *p_coding_type, u16 *p_sr, u8 *num, u8 num_len);
+int phone_message_call_api_is_work(void);
+int phone_message_call_api_esco_out_data(s16 *data, int len);
+
+void phone_message_play_api_close(void);
+int phone_message_play_api_open(u8 del_enc);
+int phone_message_play_api_get_info(u32 *p_coding_type, u16 *p_sr, u8 *num, u8 num_len, u8 always);
+int phone_message_play_api_is_work(void);
+
+//////////////////////////////////////////////////////////////////////////////
+// tws
+int phone_message_tws_call_open(void);
+
+int phone_message_tws_play_open(u8 have, u8 del_enc);
+void phone_message_tws_play_close(void);
+
+void phone_message_tws_enc_del(void);
+
+int phone_message_tws_event_deal(struct bt_event *evt);
+
+// tws dec
+int phone_message_tws_dec_init(struct phone_message_dec_hdl *play);
+void phone_message_tws_dec_release(struct phone_message_dec_hdl *play);
+int phone_message_tws_dec_trans_read(struct phone_message_dec_hdl *play, void *buf, u32 len);
+int phone_message_tws_dec_probe(struct phone_message_dec_hdl *play);
+void phone_message_tws_dec_output_data(struct phone_message_dec_hdl *play, void *data, int len);
+
+#endif /*(TCFG_PHONE_MESSAGE_ENABLE)*/
+
+#endif /*_PHONE_MESSAGE_*/
+
diff --git a/apps/common/storage_dev/storage_dev.h b/apps/common/storage_dev/storage_dev.h
new file mode 100644
index 0000000..98564f2
--- /dev/null
+++ b/apps/common/storage_dev/storage_dev.h
@@ -0,0 +1,64 @@
+#ifndef _STORAGE_DEV_H_
+#define _STORAGE_DEV_H_
+
+#include "typedef.h"
+
+struct storage_dev {
+ char *logo;
+ char *dev_name;
+ char *storage_path;
+ char *root_path;
+ char *fs_type;
+ void *priv;
+ u32 *counter;
+};
+
+enum {
+ STORAGE_DEV_OK = 0,
+ STORAGE_DEV_ALREADY = (('S' << 24) | ('G' << 16) | ('\0' << 8) | '\0'),
+ STORAGE_DEV_IS_NOT_STORAGE,
+ STORAGE_DEV_NO_FIND,
+ STORAGE_DEV_EMPTY,
+ STORAGE_DEV_FULL,
+ STORAGE_DEV_CALLBACK,
+ STORAGE_DEV_FAT_MOUNT_FAIL,
+};
+
+int storage_dev_add(void *logo);
+int storage_dev_del(void *logo);
+int storage_dev_total(void);
+
+struct storage_dev *storage_dev_check(void *logo);
+struct storage_dev *storage_dev_frist(void);
+struct storage_dev *storage_dev_last(void);
+struct storage_dev *storage_dev_last_active(void);
+struct storage_dev *storage_dev_next(struct storage_dev *cur);
+struct storage_dev *storage_dev_prev(struct storage_dev *cur);
+struct storage_dev *storage_dev_last_active(void);
+struct storage_dev *storage_dev_find_by_index(u16 index);//根据号码获取设备
+void storage_dev_active_mark(void *logo);
+
+
+// return 0-ok
+typedef int (* storage_callback)(struct storage_dev *);
+
+int storage_dev_add_ex(void *logo, storage_callback cb);
+int storage_dev_del_ex(void *logo, storage_callback cb);
+int storage_dev_total_ex(storage_callback cb);
+
+struct storage_dev *storage_dev_check_ex(void *logo, storage_callback cb);
+struct storage_dev *storage_dev_frist_ex(storage_callback cb);
+struct storage_dev *storage_dev_last_ex(storage_callback cb);
+struct storage_dev *storage_dev_next_ex(struct storage_dev *cur, storage_callback cb);
+struct storage_dev *storage_dev_prev_ex(struct storage_dev *cur, storage_callback cb);
+struct storage_dev *storage_dev_last_active_ex(storage_callback cb);
+
+
+#define REGISTER_STORAGE_DEVICE(node) \
+ const struct storage_dev node sec(.storage_device)
+
+#define REGISTER_STORAGE_DEVICES(node) \
+ const struct storage_dev node[] sec(.storage_device)
+
+#endif
+
diff --git a/apps/common/temp_trim/dtemp_pll_trim.c b/apps/common/temp_trim/dtemp_pll_trim.c
new file mode 100644
index 0000000..8cbb38d
--- /dev/null
+++ b/apps/common/temp_trim/dtemp_pll_trim.c
@@ -0,0 +1,92 @@
+#include "typedef.h"
+#include "asm/clock.h"
+#include "timer.h"
+#include "asm/efuse.h"
+#include "irq.h"
+#include "asm/power_interface.h"
+#include "jiffies.h"
+#include "app_config.h"
+#include "syscfg_id.h"
+#include "system/includes.h"
+
+
+//*******************************************
+// ****************dtemp pll trim************
+//*******************************************
+
+
+#define APP_IO_DEBUG_0(i,x) //{JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT &= ~BIT(x);}
+#define APP_IO_DEBUG_1(i,x) //{JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT |= BIT(x);}
+
+
+extern void get_bta_pll_midbank_temp(void); //ok
+extern const int config_bt_temperature_pll_trim;
+static u16 trim_timer_handle = 0;
+static u8 is_pll_trim_active = 0;
+#define CHECK_TEMPERATURE_CYCLE_INIT (1000 * 8) //检测周期
+/* #define CHECK_TEMPERATURE_CYCLE_CONNECTED (1000 * 5 ) //连接蓝牙检测周期 */
+
+extern u8 btpll_status_det();
+
+extern u8 le_hw_check_all_instant_will_be_valid();
+
+
+static void btpll_trim_main()
+{
+ printf("midbank_trim>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\r\n");
+ local_irq_disable();
+ is_pll_trim_active = 1;
+ local_irq_enable();
+ /* APP_IO_DEBUG_1(B,0); */
+
+ get_bta_pll_midbank_temp();
+
+ /* APP_IO_DEBUG_0(B,0); */
+ local_irq_disable();
+ is_pll_trim_active = 0;
+ local_irq_enable();
+
+}
+
+void temperature_plltrim_handle()
+{
+ int msg[3] = {0};
+ msg[0] = (int)btpll_trim_main;
+ msg[1] = 1;
+ msg[2] = 0;
+ int ret = os_taskq_post_type("app_core", Q_CALLBACK, 3, msg);
+
+}
+
+void trim_process()
+{
+ if (!le_hw_check_all_instant_will_be_valid()) {
+ if (btpll_status_det()) {
+ temperature_plltrim_handle();
+ }
+ }
+}
+
+
+void trim_timer_add()
+{
+ if (config_bt_temperature_pll_trim) {
+ if (!trim_timer_handle) {
+ trim_timer_handle = sys_s_hi_timer_add(NULL, trim_process, CHECK_TEMPERATURE_CYCLE_INIT);
+ }
+ }
+}
+
+
+static u8 pll_trim_idle_query(void)
+{
+ return (!is_pll_trim_active);
+}
+
+REGISTER_LP_TARGET(plll_trim_lp_target) = {
+ .name = "pll_trim",
+ .is_idle = pll_trim_idle_query,
+};
+
+
+__initcall(trim_timer_add);
diff --git a/apps/common/test/fs_test.c b/apps/common/test/fs_test.c
new file mode 100644
index 0000000..b2331f3
--- /dev/null
+++ b/apps/common/test/fs_test.c
@@ -0,0 +1,234 @@
+#include "system/includes.h"
+#include "app_config.h"
+
+#define SD_DEV "sd0"
+#define SD_MOUNT_PATH "storage/sd0"
+#define SD_ROOT_PATH "storage/sd0/C/"
+/**********************ac697n 添加SD卡写 配置*******************************
+ 1.配置板级xxx.h, 对比ad697n_demo.h文件,添加TCFG_SD0_ENABLE宏包住的内容。
+ 2.配置板级xxx.c, 对比ad697n_demo.c文件,添加TCFG_SD0_ENABLE宏包住的内容。注:sd_set_power 接口里面内容,如有需要自己配置。
+ 3.配置earphone/music.c ,避免编译不过。注:key_table内容如有需要自己配置。
+ 4.SD卡检测上线和挂载接口在default_event_handler.c文件中.dev_manager_mount("sd0")接口挂载SD卡。如果已经挂载了,可以不用测试demo中的mount接口。
+ 5.如下面测试demo,调用接口读写即可。
+ ***********************************************************************/
+
+
+struct imount *mount(const char *dev_name, const char *path,
+ const char *fs_type, int cache_num, void *dev_arg);
+#if 1
+int SD_test(void)
+{
+#define FILE_NAME SD_ROOT_PATH"abc.txt"
+ log_d("SD driver test >>>> path: %s", FILE_NAME);
+ void *mnt = mount(SD_DEV, SD_MOUNT_PATH, "fat", 3, NULL);
+ if (mnt) {
+ log_d("sd mount fat succ");
+ } else {
+ log_d("sd mount fat failed");
+ return -1;
+ }
+
+ FILE *fp = NULL;
+ u8 str[] = "This is a test string.";
+ u8 buf[100];
+ u8 len;
+
+ fp = fopen(FILE_NAME, "w+");
+ if (!fp) {
+ log_d("open file ERR!");
+ return -1;
+ }
+
+ len = fwrite(fp, str, sizeof(str));
+
+ if (len != sizeof(str)) {
+ log_d("write file ERR!");
+ goto _end;
+ }
+#if 1
+ fseek(fp, 0, SEEK_SET);
+
+ len = fread(fp, buf, sizeof(str));
+
+ if (len != sizeof(str)) {
+ log_d("read file ERR!");
+ goto _end;
+ }
+
+ put_buf(buf, sizeof(str));
+#endif
+ log_d("SD ok!");
+
+_end:
+ if (fp) {
+ fclose(fp);
+ }
+
+ return 0;
+}
+#endif
+
+
+#if 0
+#define SDFILE_NEW_FILE1 SDFILE_RES_ROOT_PATH"tone/bt.wtg"
+#define SDFILE_NEW_FILE2 SDFILE_RES_ROOT_PATH"cfg_tool.bin"
+#if (USE_SDFILE_NEW == 1)
+#define SDFILE_NEW_FILE3 SDFILE_RES_ROOT_PATH"btif"
+#else
+#define SDFILE_NEW_FILE3 SDFILE_RES_ROOT_PATH"RESERVED_CONFIG/btif"
+#endif
+#define SDFILE_NEW_FILE4 SDFILE_RES_ROOT_PATH"cfg_tool.bin"
+#define SDFILE_READ_LEN 0x20
+
+void sdfile_test(void)
+{
+ FILE *fp = NULL;
+ u8 buf[SDFILE_READ_LEN];
+ u32 len;
+ int ret;
+
+ printf("sdfile test >>>>>>>>");
+ fp = fopen(SDFILE_NEW_FILE1, "r");
+
+ if (!fp) {
+ printf("file open fail");
+ }
+
+ printf("file open succ");
+
+ ret = fread(fp, buf, SDFILE_READ_LEN);
+ if (ret == SDFILE_READ_LEN) {
+ printf("file read succ");
+ put_buf(buf, SDFILE_READ_LEN);
+ }
+
+ fclose(fp);
+
+ fp = fopen(SDFILE_NEW_FILE4, "r");
+
+ if (!fp) {
+ printf("file open fail");
+ }
+
+ printf("file open succ4444");
+
+ ret = fread(fp, buf, SDFILE_READ_LEN);
+ if (ret == SDFILE_READ_LEN) {
+ printf("file read succ444");
+ put_buf(buf, SDFILE_READ_LEN);
+ }
+
+ fclose(fp);
+
+//////////////////////////////////
+ fp = fopen(SDFILE_NEW_FILE2, "r");
+
+ if (!fp) {
+ printf("file open fail2");
+ }
+
+ ret = fread(fp, buf, SDFILE_READ_LEN);
+ if (ret == SDFILE_READ_LEN) {
+ printf("file read succ2");
+ put_buf(buf, SDFILE_READ_LEN);
+ }
+
+
+ ret = fread(fp, buf, SDFILE_READ_LEN);
+ if (ret == SDFILE_READ_LEN) {
+ printf("file read succ2");
+ put_buf(buf, SDFILE_READ_LEN);
+ }
+
+ fseek(fp, 0x200, SEEK_SET);
+
+ ret = fread(fp, buf, SDFILE_READ_LEN);
+ if (ret == SDFILE_READ_LEN) {
+ printf("file read succ3");
+ put_buf(buf, SDFILE_READ_LEN);
+ }
+
+ printf("file open succ2");
+ fclose(fp);
+
+//////////////////////////////////
+ fp = fopen(SDFILE_NEW_FILE3, "r");
+
+ if (!fp) {
+ printf("file open fail3");
+ }
+ printf("file open succ3");
+
+ ret = fread(fp, buf, SDFILE_READ_LEN);
+ if (ret == SDFILE_READ_LEN) {
+ printf("file read succ4");
+ put_buf(buf, SDFILE_READ_LEN);
+ }
+
+ char str_buf[] = "test btif write";
+
+ fseek(fp, 0, SEEK_SET);
+ ret = fwrite(fp, str_buf, sizeof(str_buf));
+ if (ret == sizeof(str_buf)) {
+ printf("file write succ");
+ }
+
+ fseek(fp, 0, SEEK_SET);
+ printf("file will read");
+ ret = fread(fp, buf, sizeof(str_buf));
+ if (ret == sizeof(str_buf)) {
+ printf("file read succ5");
+ put_buf(buf, sizeof(str_buf));
+ }
+
+ fclose(fp);
+}
+
+#endif
+
+
+#if 0
+void m_1() ;
+void m_2() ;
+
+void movefun_test()
+{
+ extern u32 moveable_addr ;
+ extern u32 m_code_addr ;
+ extern u32 m_code_size ;
+ extern u32 moveable_slot_addr ;
+ extern u32 moveable_slot_begin ;
+ extern u32 moveable_slot_size ;
+ u32 *a = &moveable_slot_addr ;
+ u32 *b = &moveable_slot_begin ;
+ for (int i = 0 ; i < (u32) &moveable_slot_size ; i += 4) {
+ *a = *b - (u32)&m_code_addr + (u32) &moveable_addr ;
+ printf("index %d = %x %x \r\n", i, *a, *b) ;
+ a++ ;
+ b++ ;
+ }
+ printf("sdram addr= %x flash addr=%x size =%x \r\n", (u32)&moveable_addr, (u32)&m_code_addr, (u32)&m_code_size);
+ memcpy(&moveable_addr, &m_code_addr, (u32)&m_code_size) ;
+ m_1() ;
+
+
+}
+void fun_test()
+{
+ m_1() ;
+ m_2() ;
+}
+__attribute__((movable_region(2)))
+void m_1() AT(.m.code)
+{
+ printf("movable_regin fun test 1") ;
+ m_2() ;
+}
+
+__attribute__((movable_region(2)))
+void m_2()AT(.m.code)
+{
+ printf("movable_regin fun test 2") ;
+
+}
+#endif
diff --git a/apps/common/test/os_test.c b/apps/common/test/os_test.c
new file mode 100644
index 0000000..64e7a19
--- /dev/null
+++ b/apps/common/test/os_test.c
@@ -0,0 +1,58 @@
+#include "system/includes.h"
+
+/* --------------------------------------------------------------------------*/
+/**
+ * @brief A 任务
+ *
+ * @param p
+ */
+/* ----------------------------------------------------------------------------*/
+static void os_demo_A(void *p)
+{
+ while (1) {
+ printf("os_demo_A runnning");
+ os_time_dly(100);
+ }
+}
+
+
+/* --------------------------------------------------------------------------*/
+/**
+ * @brief B 任务
+ *
+ * @param p
+ */
+/* ----------------------------------------------------------------------------*/
+static void os_demo_B(void *p)
+{
+ while (1) {
+ printf("os_demo_B runnning");
+ os_time_dly(100);
+ }
+}
+
+
+/* --------------------------------------------------------------------------*/
+/**
+ * @brief 任务创建实例,禁止在关闭中断或中断中调用此函数
+ */
+/* ----------------------------------------------------------------------------*/
+void os_test(void)
+{
+ int ret;
+
+ ret = os_task_create(os_demo_A, NULL, 31, 512, 0, "demo_A");
+ if (ret != OS_NO_ERR) {
+ printf("os_demo_A create err : %d", ret);
+ }
+
+ ret = os_task_create(os_demo_B, NULL, 31, 512, 0, "demo_B");
+ if (ret != OS_NO_ERR) {
+ printf("os_demo_B create err : %d", ret);
+ }
+
+ while (1) {
+ os_time_dly(1);
+ }
+}
+
diff --git a/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_common.h b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_common.h
new file mode 100644
index 0000000..b752878
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_common.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_QIOT_COMMON_H
+#define QCLOUD_BLE_QIOT_COMMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BLE_QIOT_PRODUCT_ID_LEN (10) // fixed length of product id
+#define BLE_QIOT_DEVICE_NAME_LEN (48) // max length of device name
+#define BLE_QIOT_PSK_LEN (24) // fixed length of secret key
+#define BLE_QIOT_MAC_LEN (6) // fixed length of mac
+
+#define SWAP_32(x) \
+ ((((x)&0xFF000000) >> 24) | (((x)&0x00FF0000) >> 8) | (((x)&0x0000FF00) << 8) | (((x)&0x000000FF) << 24))
+#define SWAP_16(x) ((((x)&0xFF00) >> 8) | (((x)&0x00FF) << 8))
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define HTONL(x) SWAP_32(x)
+#define HTONS(x) SWAP_16(x)
+#define NTOHL(x) SWAP_32(x)
+#define NTOHS(x) SWAP_16(x)
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define HTONL(x) (x)
+#define HTONS(x) (x)
+#define NTOHL(x) (x)
+#define NTOHS(x) (x)
+#else
+#error "undefined byte order"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // QCLOUD_BLE_QIOT_COMMON_H
diff --git a/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_config.h b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_config.h
new file mode 100644
index 0000000..abbb97c
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_config.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef QCLOUD_BLE_QIOT_CONFIG_H
+#define QCLOUD_BLE_QIOT_CONFIG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+
+#define BLE_QIOT_SDK_VERSION "1.5.0" // sdk version
+#define BLE_QIOT_SDK_DEBUG 0 // sdk debug
+
+// the device broadcast is controlled by the user, but we provide a mechanism to help the device save more power.
+// if you want broadcast is triggered by something like press a button instead of all the time, and the broadcast
+// stopped automatically in a few minutes if the device is not bind, define BLE_QIOT_BUTTON_BROADCAST is 1 and
+// BLE_QIOT_BIND_TIMEOUT is the period that broadcast stopped.
+// if the device in the bound state, broadcast dose not stop automatically.
+#define BLE_QIOT_BUTTON_BROADCAST 0
+#if BLE_QIOT_BUTTON_BROADCAST
+#define BLE_QIOT_BIND_TIMEOUT (2 * 60 * 1000) // unit: ms
+#endif //BLE_QIOT_BUTTON_BROADCAST
+
+// in some BLE stack the default ATT_MTU is 23, set BLE_QIOT_REMOTE_SET_MTU is 1 if you want to reset the mtu by the
+// Tencent Lianlian. Tencent Lianlian will set the mtu get from function ble_get_user_data_mtu_size()
+#define BLE_QIOT_REMOTE_SET_MTU (1)
+
+// the following definition will affect the stack that LLSync used,the minimum value tested is 2048 bytes
+// the max length of llsync event data, depends on the length of user data reported to Tencent Lianlian at a time
+#define BLE_QIOT_EVENT_MAX_SIZE (128)
+// the minimum between BLE_QIOT_EVENT_MAX_SIZE and mtu
+#define BLE_QIOT_EVENT_BUF_SIZE (23)
+
+// some data like integer need to be transmitted in a certain byte order, defined it according to your device
+#define __ORDER_LITTLE_ENDIAN__ 1234
+#define __ORDER_BIG_ENDIAN__ 4321
+#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
+
+// in some BLE stack ble_qiot_log_hex() maybe not work, user can use there own hexdump function
+#define BLE_QIOT_USER_DEFINE_HEXDUMP 0
+#if BLE_QIOT_USER_DEFINE_HEXDUMP
+// add your code here like this
+// #define ble_qiot_log_hex(level, hex_name, data, data_len) \
+// do { \
+// MY_RAW_LOG("\r\nble qiot dump: %s, length: %d\r\n", hex_name, data_len); \
+// MY_RAW_HEXDUMP_(data, data_len); \
+// } while(0)
+
+// or use your own hexdump function with same definition
+// void ble_qiot_log_hex(e_ble_qiot_log_level level, const char *hex_name, const char *data, uint32_t data_len);
+#endif // BLE_QIOT_USER_DEFINE_HEXDUMP
+
+// Macro for logging a formatted string, the function must printf raw string without any color, prefix, newline or
+// timestamp
+#define BLE_QIOT_LOG_PRINT(...) printf(__VA_ARGS__)
+
+#define BLE_QIOT_LLSYNC_STANDARD 1 // support llsync standard
+#if BLE_QIOT_LLSYNC_STANDARD
+// some users hope to confirm on the device before the binding, set BLE_QIOT_SECURE_BIND is 1 to enable the secure
+// binding and enable secure bind in iot-explorer console. When the server is bound, the device callback ble_secure_bind_user_cb()
+// will be triggered, the user agree or refuse connect by ble_secure_bind_user_confirm(). If the device does not respond
+// and the connection timeout, or the user cancel the connection in Tencent Lianlian, a notify will received in function
+// ble_secure_bind_user_notify().
+#define BLE_QIOT_SECURE_BIND 0
+#if BLE_QIOT_SECURE_BIND
+#define BLE_QIOT_BIND_WAIT_TIME 60
+#endif //BLE_QIOT_SECURE_BIND
+
+// some sdk info needs to stored on the device and the address is up to you
+#define BLE_QIOT_RECORD_FLASH_ADDR 5
+
+// define user develop version, pick from "a-zA-Z0-9.-_" and length limits 1~32 bytes.
+// must be consistent with the firmware version that user write in the iot-explorer console
+// refer https://cloud.tencent.com/document/product/1081/40296
+#define BLE_QIOT_USER_DEVELOPER_VERSION "0.0.1"
+
+#define BLE_QIOT_SUPPORT_OTA 1 // 1 is support ota, others not
+#if BLE_QIOT_SUPPORT_OTA
+#define BLE_QIOT_SUPPORT_RESUMING 0 // 1 is support resuming, others not
+#if BLE_QIOT_SUPPORT_RESUMING
+// storage ota info in the flash if support resuming ota file
+#define BLE_QIOT_OTA_INFO_FLASH_ADDR 10
+#endif //BLE_QIOT_SUPPORT_RESUMING
+
+#define BLE_QIOT_TOTAL_PACKAGES 0x12 // the total package numbers in a loop
+#define BLE_QIOT_PACKAGE_LENGTH 0xb0 // the user data length in package, ble_get_user_data_mtu_size() - 3 is the max
+#define BLE_QIOT_RETRY_TIMEOUT 0x20 // the max interval between two packages, unit: second
+// the time spent for device reboot, the server waiting the device version reported after upgrade. unit: second
+#define BLE_QIOT_REBOOT_TIME 20
+#define BLE_QIOT_PACKAGE_INTERVAL 0xa // the interval between two packages send by the server
+// the package from the server will storage in the buffer, write the buffer to the flash at one time when the buffer
+// overflow. reduce the flash write can speed up file download, we suggest the BLE_QIOT_OTA_BUF_SIZE is multiples
+// of BLE_QIOT_PACKAGE_LENGTH and equal flash page size
+#define BLE_QIOT_OTA_BUF_SIZE (512 * 4)
+#endif //BLE_QIOT_SUPPORT_OTA
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+#define BLE_QIOT_LLSYNC_CONFIG_NET (!BLE_QIOT_LLSYNC_STANDARD) // support llsync configure network
+
+#if (1 == BLE_QIOT_LLSYNC_STANDARD) && (1 == BLE_QIOT_LLSYNC_CONFIG_NET)
+#error "llsync standard and llsync configure network is incompatible"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // QCLOUD_BLE_QIOT_CONFIG_H
diff --git a/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_crc.h b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_crc.h
new file mode 100644
index 0000000..1097409
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_crc.h
@@ -0,0 +1,32 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef QCLOUD_BLE_QIOT_CRC_H
+#define QCLOUD_BLE_QIOT_CRC_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include
+#include
+
+void ble_qiot_crc32_init();
+uint32_t ble_qiot_crc32(uint32_t crc, const uint8_t *buf, int len);
+
+#if defined(__cplusplus)
+}
+#endif
+#endif // QCLOUD_BLE_QIOT_HMAC_H
diff --git a/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_export.h b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_export.h
new file mode 100644
index 0000000..b521d4e
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_export.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_QIOT_EXPORT_H
+#define QCLOUD_BLE_QIOT_EXPORT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_config.h"
+
+#define TENCENT_COMPANY_IDENTIFIER 0xFEE7 // Tencent Company ID, another is 0xFEBA
+
+#define IOT_BLE_UUID_BASE \
+ { \
+ 0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0x00, 0x00, 0x00, 0x00 \
+ }
+
+// llsync services uuid
+#if BLE_QIOT_LLSYNC_STANDARD
+#define IOT_BLE_UUID_SERVICE 0xFFE0
+#endif //BLE_QIOT_LLSYNC_STANDARD
+#if BLE_QIOT_LLSYNC_CONFIG_NET
+#define IOT_BLE_UUID_SERVICE 0xFFF0
+#endif //BLE_QIOT_LLSYNC_CONFIG_NET
+
+// characteristics uuid
+#define IOT_BLE_UUID_DEVICE_INFO 0xFFE1 // used to connection and identity authentication
+#define IOT_BLE_UUID_EVENT 0xFFE3 // used to send data to the server from device
+
+#if BLE_QIOT_LLSYNC_STANDARD
+#define IOT_BLE_UUID_DATA 0xFFE2 // used to send data to the device from server
+#define IOT_BLE_UUID_OTA 0xFFE4 // used to send ota data to the device from server
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+typedef enum {
+ GATT_CHAR_BROADCAST = (1 << 0), // Broadcasting of the value permitted.
+ GATT_CHAR_READ = (1 << 1), // Reading the value permitted.
+ GATT_CHAR_WRITE_WO_RESP = (1 << 2), // Writing the value with Write Command permitted.
+ GATT_CHAR_WRITE = (1 << 3), // Writing the value with Write Request permitted.
+ GATT_CHAR_NOTIFY = (1 << 4), // Notification of the value permitted.
+ GATT_CHAR_INDICATE = (1 << 5), // Indications of the value permitted.
+ GATT_CHAR_AUTH_SIGNED_WR = (1 << 6), // Writing the value with Signed Write Command permitted.
+} char_props_s;
+
+// the callback function prototype definition for the characteristics
+typedef void (*ble_on_write_cb)(const uint8_t *buf, uint16_t len);
+
+// the characteristics attributes
+typedef struct {
+ uint16_t uuid16;
+ uint8_t gatt_char_props;
+ ble_on_write_cb on_write;
+} qiot_char_s;
+
+// the service attributes
+typedef struct {
+ uint16_t service_uuid16;
+ uint8_t service_uuid128[16];
+ uint16_t gatt_max_mtu;
+
+ qiot_char_s device_info;
+ qiot_char_s data;
+ qiot_char_s event;
+ qiot_char_s ota;
+} qiot_service_init_s;
+
+typedef enum {
+ BLE_QIOT_RS_OK = 0, // success
+ BLE_QIOT_RS_ERR = -1, // normal error
+ BLE_QIOT_RS_ERR_FLASH = -2, // flash error
+ BLE_QIOT_RS_ERR_PARA = -3, // parameters error
+ BLE_QIOT_RS_VALID_SIGN_ERR = -4,
+} ble_qiot_ret_status_t;
+
+/**
+ * @brief get llsync services context
+ *
+ * @return llsync services struct
+ */
+const qiot_service_init_s *ble_get_qiot_services(void);
+
+/**
+ * @brief llsync sdck initialize
+ * @note you should called it before any other sdk api
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_qiot_explorer_init(void);
+
+/**
+ * @brief report mtu of the device to the server
+ * @note report mtu to the server to set the mtu
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_report_device_info(void);
+
+/**
+ * @brief sync the device mtu to The Tencent Lianlian.
+ * @note if BLE_QIOT_REMOTE_SET_MTU is 1, The Tencent Lianlian will set the mtu get from function
+ * ble_get_user_data_mtu_size(), but The Tencent Lianlian can not know the effective value even if the setting is
+ * successful, so llsync need sync the mtu again. The user call this function in the BLE mtu callback.
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_sync_mtu(uint16_t llsync_mtu);
+
+/**
+ * @brief start llsync advertising
+ * @note broadcast data according to the device bind state, reference to llsync protocol
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_qiot_advertising_start(void);
+
+/**
+ * @brief stop advertising
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_qiot_advertising_stop(void);
+
+/**
+ * @brief device info write callbcak, call the function when characteristic IOT_BLE_UUID_DEVICE_INFO received data
+ * @param buf a pointer point to the data
+ * @param len data length
+ * @return none
+ */
+void ble_device_info_write_cb(const uint8_t *buf, uint16_t len);
+
+/**
+ * @brief gap event connect call-back, when gap get ble connect event, use this function
+ * tell qiot ble sdk
+ * @return none
+ */
+void ble_gap_connect_cb(void);
+
+/**
+ * @brief gap event disconnect call-back, when gap get ble disconnect event, use this function
+ * tell qiot ble sdk
+ * @return none
+ */
+void ble_gap_disconnect_cb(void);
+
+#ifdef BLE_QIOT_LLSYNC_STANDARD
+/**
+ * @brief get property of the device from the server
+ * @note the property will be received from IOT_BLE_UUID_DATA if success
+ * @return BLE_QIOT_RS_OK is success, other is error. if success, the data from server will come to
+ */
+ble_qiot_ret_status_t ble_event_get_status(void);
+
+/**
+ * @brief report property of the device to the server
+ * @note the reply will be received from IOT_BLE_UUID_DATA if success
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_report_property(void);
+
+/**
+ * @brief post event to the server
+ * @param event_id id of the event
+ * @note the reply will be received from IOT_BLE_UUID_DATA if success
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_post(uint8_t event_id);
+
+/**
+ * @brief data write callback, call the function when characteristic IOT_BLE_UUID_DATA received data
+ * @param buf a pointer point to the data
+ * @param len data length
+ * @return none
+ */
+void ble_lldata_write_cb(const uint8_t *buf, uint16_t len);
+
+/**
+ * @brief ota data write callback, call the function when characteristic IOT_BLE_UUID_OTA received data
+ * @param buf a pointer point to the data
+ * @param len data length
+ * @return none
+ */
+void ble_ota_write_cb(const uint8_t *buf, uint16_t len);
+
+typedef enum {
+ BLE_QIOT_SECURE_BIND_CONFIRM = 0,
+ BLE_QIOT_SECURE_BIND_REJECT = 1,
+} ble_qiot_secure_bind_t;
+
+/**
+ * @brief user choose whether to connect
+ * @note call the function when the user choose connect or not
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_secure_bind_user_confirm(ble_qiot_secure_bind_t choose);
+
+// inform user the ota start
+typedef void (*ble_ota_start_callback)(void);
+
+enum {
+ BLE_QIOT_OTA_SUCCESS = 0, // ota success
+ BLE_QIOT_OTA_ERR_CRC = 1, // ota failed because crc error
+ BLE_QIOT_OTA_ERR_TIMEOUT = 2, // ota failed because download timeout
+ BLE_QIOT_OTA_DISCONNECT = 3, // ota failed because ble disconnect
+ BLE_QIOT_OTA_ERR_FILE = 4, // ota failed because the file mismatch the device
+};
+// inform user the ota stop and the result
+typedef void (*ble_ota_stop_callback)(uint8_t result);
+
+// llsync only valid the file crc, also allow the user valid the file by their way
+typedef ble_qiot_ret_status_t (*ble_ota_valid_file_callback)(uint32_t file_size, char *file_version);
+/**
+ * @brief register ota callback
+ * @param start_cb called before ota start, set null if not used
+ * @param stop_cb called after ota stop, set null if not used
+ * @param valid_file_cb called after the crc valid, set null if not used
+ * @return none
+ */
+void ble_ota_callback_reg(ble_ota_start_callback start_cb, ble_ota_stop_callback stop_cb,
+ ble_ota_valid_file_callback valid_file_cb);
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+#if BLE_QIOT_LLSYNC_CONFIG_NET
+
+typedef enum {
+ BLE_WIFI_MODE_NULL = 0, // invalid mode
+ BLE_WIFI_MODE_STA = 1, // station
+ BLE_WIFI_MODE_AP = 2, // ap
+} BLE_WIFI_MODE;
+
+typedef enum {
+ BLE_WIFI_STATE_CONNECT = 0, // wifi connect
+ BLE_WIFI_STATE_OTHER = 1, // other state
+} BLE_WIFI_STATE;
+
+/**
+ * @brief report wifi-mode setting result
+ * @param result setting result, 0 is success, other failed
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_report_wifi_mode(uint8_t result);
+
+/**
+ * @brief report wifi-info setting result
+ * @param result setting result, 0 is success, other failed
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_report_wifi_info(uint8_t result);
+
+/**
+ * @brief report wifi connection status
+ * @param mode current wifi mode, reference BLE_WIFI_MODE
+ * @param state current wifi state, reference BLE_WIFI_STATE
+ * @param ssid_len length of ssid
+ * @param ssid the ssid currently connected
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_report_wifi_connect(BLE_WIFI_MODE mode, BLE_WIFI_STATE state, uint8_t ssid_len,
+ const char *ssid);
+
+/**
+ * @brief report wifi-token setting result
+ * @param result setting result, 0 is success, other failed
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_report_wifi_token(uint8_t result);
+
+/**
+ * @brief report wifi-log
+ * @param log log message
+ * @param log_size length of log
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_report_wifi_log(const uint8_t *log, uint16_t log_size);
+
+#endif //BLE_QIOT_LLSYNC_CONFIG_NET
+
+#ifdef __cplusplus
+}
+#endif
+#endif // QCLOUD_BLE_QIOT_EXPORT_H
diff --git a/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_hmac.h b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_hmac.h
new file mode 100644
index 0000000..383e8d9
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_hmac.h
@@ -0,0 +1,32 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef QCLOUD_BLE_QIOT_HMAC_H
+#define QCLOUD_BLE_QIOT_HMAC_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include
+
+#define SHA1_DIGEST_SIZE 20
+
+void utils_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len);
+
+#if defined(__cplusplus)
+}
+#endif
+#endif // QCLOUD_BLE_QIOT_HMAC_H
diff --git a/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_import.h b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_import.h
new file mode 100644
index 0000000..11eb3c3
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_import.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_QIOT_IMPORT_H
+#define QCLOUD_BLE_QIOT_IMPORT_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include "ble_qiot_export.h"
+
+// 16 bits service UUIDs list, use advertising type 0x02 or 0x03
+typedef struct {
+ uint8_t uuid_num;
+ uint16_t *uuids;
+} uuid_list_s;
+
+// advertise manufacture specific data, use advertising type 0xFF
+typedef struct {
+ uint16_t company_identifier;
+ uint8_t *adv_data;
+ uint8_t adv_data_len;
+} manufacturer_data_s;
+
+typedef struct {
+ uuid_list_s uuid_info;
+ manufacturer_data_s manufacturer_info;
+} adv_info_s;
+
+/**
+ * @brief get mac address
+ * @param mac the buf storage mac, 6 bytes permanent
+ * @return 0 is success, other is error
+ */
+int ble_get_mac(char *mac);
+
+/**
+ * @brief add llsync services to ble stack
+ * @param qiot_service_init_s llsync service
+ * @return none
+ */
+void ble_services_add(const qiot_service_init_s *p_service);
+
+/**
+ * @brief start llsync advertising
+ * @param adv a pointer point to advertising data
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_advertising_start(adv_info_s *adv);
+
+/**
+ * @brief stop advertising
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_advertising_stop(void);
+
+/**
+ * @brief get the ATT_MTU user want to used
+ * @return the value
+ */
+uint16_t ble_get_user_data_mtu_size(void);
+
+/**
+ * @brief send a notification to host, use characteristic IOT_BLE_UUID_EVENT
+ * @param buf a pointer point to indication information
+ * @param len indication information length
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_send_notify(uint8_t *buf, uint8_t len);
+
+// timer type
+enum {
+ BLE_TIMER_ONE_SHOT_TYPE = 0,
+ BLE_TIMER_PERIOD_TYPE,
+ BLE_TIMER_BUTT,
+};
+typedef void *ble_timer_t;
+
+// timer callback prototype
+typedef void (*ble_timer_cb)(void *param);
+
+/**
+ * @brief create a timer
+ * @param type timer type
+ * @param timeout_handle timer callback
+ * @return timer identifier is return, NULL is error
+ */
+ble_timer_t ble_timer_create(uint8_t type, ble_timer_cb timeout_handle);
+
+/**
+ * @brief start a timer
+ * @param timer_id Timer identifier
+ * @param period timer period(unit: ms)
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_timer_start(ble_timer_t timer_id, uint32_t period);
+
+/**
+ * @brief stop a timer
+ * @param timer_id Timer identifier
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_timer_stop(ble_timer_t timer_id);
+
+/**
+ * @brief delete a timer
+ * @param timer_id Timer identifier
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_timer_delete(ble_timer_t timer_id);
+
+#ifdef BLE_QIOT_LLSYNC_STANDARD
+/**
+ * @brief get device product id
+ * @param product_id the buf storage product id, 10 bytes permanent
+ * @return 0 is success, other is error
+ */
+int ble_get_product_id(char *product_id);
+
+/**
+ * @brief get device name
+ * @param device_name the buf storage device name, the max length of the device name is 48 bytes
+ * @return length of device name, 0 is error
+ */
+int ble_get_device_name(char *device_name);
+
+/**
+ * @brief get device secret
+ * @param psk the buf storage secret, 24 bytes permanent
+ * @return 0 is success, other is error
+ */
+int ble_get_psk(char *psk);
+
+/**
+ * @brief write data to flash
+ * @param flash_addr write address in flash
+ * @param write_buf point to write buf
+ * @param write_len length of data to write
+ * @return write_len is success, other is error
+ */
+int ble_write_flash(uint32_t flash_addr, const char *write_buf, uint16_t write_len);
+
+/**
+ * @brief read data from flash
+ * @param flash_addr read address from flash
+ * @param read_buf point to read buf
+ * @param read_len length of data to read
+ * @return read_len is success, other is error
+ */
+int ble_read_flash(uint32_t flash_addr, char *read_buf, uint16_t read_len);
+
+/**
+ * @brief secure binding user callback
+ * @note when the secure binding is activated, the function notify user the connecting is coming, the function is
+ * no-block
+ * @return None
+ */
+void ble_secure_bind_user_cb(void);
+
+enum {
+ BLE_SECURE_BIND_CANCEL = 0, // user cancel in Tencent Lianlian
+ BLE_SECURE_BIND_TIMEOUT = 1, // the binding timeout
+};
+/**
+ * @brief secure binding user notify
+ * @note notify user when the secure bind timeout or cancel
+ * @return None
+ */
+void ble_secure_bind_user_notify(uint8_t result);
+
+enum {
+ BLE_OTA_ENABLE = 1, // ota enable
+ BLE_OTA_DISABLE_LOW_POWER = 2, // the device low power can not upgrade
+ BLE_OTA_DISABLE_LOW_VERSION = 3, // disable upgrade low version
+};
+/**
+ * @brief get ota is enable
+ * @param version the ota file version
+ * @return BLE_OTA_ENABLE is enable, others disable
+ * @note can not be blocking, the reason defined by users
+ */
+uint8_t ble_ota_is_enable(const char *version, u32 file_size, u32 file_crc);
+
+/**
+ * @brief get the address the ota file will be saved
+ * @return the flash address
+ */
+uint32_t ble_ota_get_download_addr(void);
+
+/**
+ * @brief write data to flash
+ * @param flash_addr write address in flash
+ * @param write_buf point to write buf
+ * @param write_len length of data to write
+ * @return write_len is success, other is error
+ */
+int ble_ota_write_flash(uint32_t flash_addr, const char *write_buf, uint16_t write_len);
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+#if BLE_QIOT_LLSYNC_CONFIG_NET
+/**
+ * @brief set wifi mode
+ * @param mode the target mode
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_combo_wifi_mode_set(BLE_WIFI_MODE mode);
+
+/**
+ * @brief set wifi info
+ * @param ssid wifi ssid
+ * @param ssid_len the length of ssid
+ * @param passwd wifi password
+ * @param passwd_len the length of password
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_combo_wifi_info_set(const char *ssid, uint8_t ssid_len, const char *passwd, uint8_t passwd_len);
+
+/**
+ * @brief connect wifi
+ * @param none
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_combo_wifi_connect();
+
+/**
+ * @brief set wifi token
+ * @param token token message
+ * @param token_len length of token
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_combo_wifi_token_set(const char *token, uint16_t token_len);
+
+/**
+ * @brief get wifi log
+ * @param none
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_combo_wifi_log_get(void);
+#endif //BLE_QIOT_LLSYNC_CONFIG_NET
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // QCLOUD_BLE_QIOT_IMPORT_H
diff --git a/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_llsync_data.h b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_llsync_data.h
new file mode 100644
index 0000000..48a4760
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_llsync_data.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_QIOT_LLSYNC_DATA_H
+#define QCLOUD_BLE_QIOT_LLSYNC_DATA_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+
+#define BLE_QIOT_CONTROL_DATA_TYPE (0x00)
+#define BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE (0x22)
+
+#define BLE_QIOT_GET_STATUS_REPLY_HEADER_LEN (4)
+#define BLE_QIOT_DATA_FIXED_HEADER_LEN (3)
+
+// handle property request
+ble_qiot_ret_status_t ble_lldata_property_request_handle(const char *in_buf, int buf_len);
+
+// handle property reply
+ble_qiot_ret_status_t ble_lldata_property_reply_handle(uint8_t type, const char *in_buf, int buf_len);
+
+// handle event data
+ble_qiot_ret_status_t ble_lldata_event_handle(uint8_t id, const char *in_buf, int len);
+
+// handle action data
+ble_qiot_ret_status_t ble_lldata_action_handle(uint8_t id, const char *in_buf, int len);
+
+// get report data
+ble_qiot_ret_status_t ble_user_property_get_report_data(void);
+#ifdef __cplusplus
+}
+#endif
+#endif // QCLOUD_BLE_QIOT_LLSYNC_DATA_H
diff --git a/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_llsync_device.h b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_llsync_device.h
new file mode 100644
index 0000000..e045d74
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_llsync_device.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_QIOT_LLSYNC_DEVICE_H
+#define QCLOUD_BLE_QIOT_LLSYNC_DEVICE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+//#include
+#include "ble_qiot_common.h"
+#include "ble_qiot_export.h"
+#include "ble_qiot_hmac.h"
+#include "ble_qiot_llsync_event.h"
+
+#define LLSYNC_BIND_STATE_MASK 0x03
+#define LLSYNC_PROTO_VER_BIT 0x04
+#define LLSYNC_PROTOCOL_VERSION_MASK 0xF0
+#define LLSYNC_MTU_SET_MASK 0x8000
+
+#define LLSYNC_MTU_SET_RESULT_ERR 0xFFFF // some error when setting mtu
+
+#define BLE_QIOT_LLSYNC_PROTOCOL_VERSION (2) // llsync protocol version, equal or less than 15
+
+#define ATT_DEFAULT_MTU 23 // default att mtu
+#define ATT_MTU_TO_LLSYNC_MTU(_att_mtu) ((_att_mtu)-3)
+
+#define BLE_LOCAL_PSK_LEN 4
+#define BLE_BIND_IDENTIFY_STR_LEN 8
+#define BLE_EXPIRATION_TIME 60 // timestamp expiration value
+#define BLE_UNBIND_REQUEST_STR "UnbindRequest"
+#define BLE_UNBIND_REQUEST_STR_LEN (sizeof("UnbindRequest") - 1)
+#define BLE_UNBIND_RESPONSE "UnbindResponse"
+#define BLE_UNBIND_RESPONSE_STR_LEN (sizeof("UnbindResponse") - 1)
+
+typedef enum {
+ E_DEV_MSG_SYNC_TIME = 0, // sync info before bind
+ E_DEV_MSG_CONN_VALID, // connect request
+ E_DEV_MSG_BIND_SUCC, // inform bind success
+ E_DEV_MSG_BIND_FAIL, // inform bind failed
+ E_DEV_MSG_UNBIND, // unbind request
+ E_DEV_MSG_CONN_SUCC, // inform connect result
+ E_DEV_MSG_CONN_FAIL,
+ E_DEV_MSG_UNBIND_SUCC, // inform unbind result
+ E_DEV_MSG_UNBIND_FAIL,
+ E_DEV_MSG_SET_MTU_RESULT, // inform set mtu result
+ E_DEV_MSG_BIND_TIMEOUT, // inform bind timeout
+ E_DEV_MSG_GET_DEV_INFO = 0xE0, // configure network start
+ E_DEV_MSG_SET_WIFI_MODE,
+ E_DEV_MSG_SET_WIFI_INFO,
+ E_DEV_MSG_SET_WIFI_CONNECT,
+ E_DEV_MSG_SET_WIFI_TOKEN,
+ E_DEV_MSG_GET_DEV_LOG,
+ E_DEV_MSG_MSG_BUTT,
+} e_dev_info_msg_type;
+
+typedef enum {
+ E_LLSYNC_BIND_IDLE = 0, // no bind
+ E_LLSYNC_BIND_WAIT, // wait bind, return idle state if no bind in the period
+ E_LLSYNC_BIND_SUCC, // bound
+} e_llsync_bind_state;
+
+typedef enum {
+ E_LLSYNC_DISCONNECTED = 0,
+ E_LLSYNC_CONNECTED,
+} e_llsync_connection_state;
+
+typedef enum {
+ E_BLE_DISCONNECTED = 0,
+ E_BLE_CONNECTED,
+} e_ble_connection_state;
+
+typedef struct ble_device_info_t_ {
+ char product_id[BLE_QIOT_PRODUCT_ID_LEN];
+ char device_name[BLE_QIOT_DEVICE_NAME_LEN + 1];
+ char psk[BLE_QIOT_PSK_LEN];
+ char mac[BLE_QIOT_MAC_LEN];
+} ble_device_info;
+
+typedef struct ble_core_data_ {
+ uint8_t bind_state;
+ char local_psk[BLE_LOCAL_PSK_LEN];
+ char identify_str[BLE_BIND_IDENTIFY_STR_LEN];
+} ble_core_data;
+
+// write to uuid FEE1 before bind
+typedef struct ble_bind_data_t_ {
+ int nonce;
+ int timestamp;
+} ble_bind_data;
+
+// connect data struct
+typedef struct ble_conn_data_t_ {
+ int timestamp;
+ char sign_info[SHA1_DIGEST_SIZE];
+} ble_conn_data;
+
+// unbind data struct
+typedef struct ble_unbind_data_t_ {
+ char sign_info[SHA1_DIGEST_SIZE];
+} ble_unbind_data;
+
+typedef struct {
+ bool have_data; // start received package
+ uint8_t type; // event type
+ uint16_t buf_len; // the length of data
+ char buf[BLE_QIOT_EVENT_MAX_SIZE];
+} ble_event_slice_t;
+
+// read sdk data from flash
+ble_qiot_ret_status_t ble_init_flash_data(void);
+
+// set llsync bind state
+void llsync_bind_state_set(e_llsync_bind_state new_state);
+
+// get llsync bind state
+e_llsync_bind_state llsync_bind_state_get(void);
+
+// set llsync connection state
+void llsync_connection_state_set(e_llsync_connection_state new_state);
+
+// set ble connection state
+void ble_connection_state_set(e_ble_connection_state new_state);
+
+// get llsync connection state
+bool llsync_is_connected(void);
+
+// get ble connection state
+bool ble_is_connected(void);
+
+// get broadcast data
+int ble_get_my_broadcast_data(char *out_buf, int buf_len);
+
+// get bind authcode, return authcode length;
+// out_buf length must greater than SHA1_DIGEST_SIZE + BLE_QIOT_DEVICE_NAME_LEN
+int ble_bind_get_authcode(const char *bind_data, uint16_t data_len, char *out_buf, uint16_t buf_len);
+
+// write bind result to flash, return 0 is success
+ble_qiot_ret_status_t ble_bind_write_result(const char *result, uint16_t len);
+
+// write unbind result to flash, return 0 is success
+ble_qiot_ret_status_t ble_unbind_write_result(void);
+
+// get connect authcode, return authcode length;
+// out_buf length must greater than SHA1_DIGEST_SIZE + BLE_QIOT_DEVICE_NAME_LEN
+int ble_conn_get_authcode(const char *conn_data, uint16_t data_len, char *out_buf, uint16_t buf_len);
+
+// get connect authcode, return authcode length;
+// out_buf length must greater than SHA1_DIGEST_SIZE + BLE_UNBIND_RESPONSE_STR_LEN
+int ble_unbind_get_authcode(const char *unbind_data, uint16_t data_len, char *out_buf, uint16_t buf_len);
+
+// inform device the result of mtu setting
+int ble_inform_mtu_result(const char *result, uint16_t data_len);
+
+// get llsync mtu
+uint16_t llsync_mtu_get(void);
+
+// update llsync mtu
+void llsync_mtu_update(uint16_t sync_mtu);
+
+#ifdef __cplusplus
+}
+#endif
+#endif // QCLOUD_BLE_QIOT_LLSYNC_DEVICE_H
diff --git a/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_llsync_event.h b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_llsync_event.h
new file mode 100644
index 0000000..d3703ff
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_llsync_event.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_QIOT_LLSYNC_EVENT_H
+#define QCLOUD_BLE_QIOT_LLSYNC_EVENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+
+#include "ble_qiot_config.h"
+#include "ble_qiot_export.h"
+
+enum {
+ BLE_QIOT_EVENT_NO_SLICE = 0,
+ BLE_QIOT_EVENT_SLICE_HEAD = 1,
+ BLE_QIOT_EVENT_SLICE_BODY = 2,
+ BLE_QIOT_EVENT_SLICE_FOOT = 3,
+};
+
+// 1 byte type + 2 bytes payload-length
+#define BLE_QIOT_EVENT_FIXED_HEADER_LEN (3)
+
+// the bit 15 - 14 is slice flag, bit 13 - 0 is tlv length
+#define BLE_QIOT_IS_SLICE_PACKAGE(_C) ((_C)&0XC0)
+#define BLE_QIOT_IS_SLICE_HEADER(_C) (((_C)&0XC0) == 0X40)
+#define BLE_QIOT_IS_SLICE_BODY(_C) (((_C)&0XC0) == 0X80)
+#define BLE_QIOT_IS_SLICE_TAIL(_C) (((_C)&0XC0) == 0XC0)
+
+#define BLE_QIOT_STRING_TYPE_LEN 2 // string/struct type length
+#define BLE_QIOT_MIN_STRING_TYPE_LEN (BLE_QIOT_STRING_TYPE_LEN + 1) // at least 2 bytes length and 1 byte payload
+#define BLE_QIOT_NOT_SUPPORT_WARN " not support, please check the data template"
+
+ble_qiot_ret_status_t ble_event_notify(uint8_t type, uint8_t *header, uint8_t header_len, const char *buf,
+ uint16_t buf_len);
+
+ble_qiot_ret_status_t ble_event_notify2(uint8_t type, uint8_t length_flag, uint8_t *header, uint8_t header_len,
+ const char *buf, uint16_t buf_len);
+
+ble_qiot_ret_status_t ble_event_sync_wait_time(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // QCLOUD_BLE_QIOT_LLSYNC_EVENT_H
diff --git a/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_llsync_ota.h b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_llsync_ota.h
new file mode 100644
index 0000000..1b3054e
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_llsync_ota.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_QIOT_LLSYNC_OTA_H
+#define QCLOUD_BLE_QIOT_LLSYNC_OTA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+
+#include "ble_qiot_config.h"
+#include "ble_qiot_export.h"
+
+#define BLE_QIOT_GET_OTA_REQUEST_HEADER_LEN 3 // the ota request header len
+#define BLE_QIOT_OTA_DATA_HEADER_LEN 3 // the ota data header len
+
+// ota feature
+#define BLE_QIOT_OTA_ENABLE (1 << 0)
+#define BLE_QIOT_OTA_RESUME_ENABLE (1 << 1)
+
+// ota file valid result
+#define BLE_QIOT_OTA_VALID_SUCCESS (1 << 7)
+#define BLE_QIOT_OTA_VALID_FAIL (0 << 7)
+
+#define BLE_QIOT_OTA_MAX_VERSION_STR (32) // max ota version length
+#define BLE_QIOT_OTA_PAGE_VALID_VAL 0x5A // ota info valid flag
+
+#define BLE_QIOT_OTA_FIRST_TIMEOUT (1)
+#define BLE_QIOT_OTA_MAX_RETRY_COUNT 5 // disconnect if retry times more than BLE_QIOT_OTA_MAX_RETRY_COUNT
+
+// ota control bits
+#define BLE_QIOT_OTA_REQUEST_BIT (1 << 0)
+#define BLE_QIOT_OTA_RECV_END_BIT (1 << 1)
+#define BLE_QIOT_OTA_RECV_DATA_BIT (1 << 2)
+#define BLE_QIOT_OTA_FIRST_RETRY_BIT (1 << 3)
+#define BLE_QIOT_OTA_DO_VALID_BIT (1 << 4)
+#define BLE_QIOT_OTA_HAVE_DATA_BIT (1 << 5)
+
+// the reason of ota file error
+enum {
+ BLE_QIOT_OTA_CRC_ERROR = 0,
+ BLE_QIOT_OTA_READ_FLASH_ERROR = 1,
+ BLE_QIOT_OTA_FILE_ERROR = 2,
+};
+
+// ota data type
+enum {
+ BLE_QIOT_OTA_MSG_REQUEST = 0,
+ BLE_QIOT_OTA_MSG_DATA = 1,
+ BLE_QIOT_OTA_MSG_END = 2,
+ BLE_QIOT_OTA_MSG_BUTT,
+};
+
+// ota request reply
+typedef struct ble_ota_reply_info_ {
+ uint8_t package_nums; // package numbers in a loop
+ uint8_t package_size; // each package size
+ uint8_t retry_timeout; // data retry
+ uint8_t reboot_timeout; // max time of device reboot
+ uint32_t last_file_size; // the file already received
+ uint8_t package_interval; // package send interval on the server
+ uint8_t rsv[3];
+} ble_ota_reply_info;
+
+typedef struct ble_ota_file_info_ {
+ uint32_t file_size;
+ uint32_t file_crc;
+ uint8_t file_version[BLE_QIOT_OTA_MAX_VERSION_STR];
+} ble_ota_file_info;
+
+// ota info saved in flash if support resuming
+typedef struct ble_ota_info_record_ {
+ uint8_t valid_flag;
+ uint8_t rsv[3];
+ uint32_t last_file_size; // the file size already write in flash
+ uint32_t last_address; // the address file saved
+ ble_ota_file_info download_file_info;
+} ble_ota_info_record;
+
+// ota user callback
+typedef struct ble_ota_user_callback_ {
+ ble_ota_start_callback start_cb;
+ ble_ota_stop_callback stop_cb;
+ ble_ota_valid_file_callback valid_file_cb;
+} ble_ota_user_callback;
+
+// ota request package: 1 byte type + 2 bytes length + 4 bytes size + 4 bytes crc + 1 byte version length + 1 ~ 32 bytes
+// version
+typedef struct {
+ bool have_data; // start received package
+ uint8_t type; // event type
+ uint16_t buf_len; // the length of data
+ char buf[BLE_QIOT_GET_OTA_REQUEST_HEADER_LEN + 4 + 4 + 1 + BLE_QIOT_OTA_MAX_VERSION_STR];
+} ble_ota_request_slice_t;
+
+// ota reply info
+typedef struct ble_ota_reply_t_ {
+ uint32_t file_size;
+ uint8_t req;
+} ble_ota_reply_t;
+
+ble_qiot_ret_status_t ble_ota_request_handle(const char *in_buf, int buf_len);
+
+ble_qiot_ret_status_t ble_ota_data_handle(const char *in_buf, int buf_len);
+
+ble_qiot_ret_status_t ble_ota_file_end_handle(void);
+
+void ble_ota_stop(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // QCLOUD_BLE_QIOT_LLSYNC_OTA_H
diff --git a/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_log.h b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_log.h
new file mode 100644
index 0000000..b8fef93
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_log.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_QIOT_LOG_H
+#define QCLOUD_BLE_QIOT_LOG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_config.h"
+
+typedef enum {
+ BLE_QIOT_LOG_LEVEL_NONE = 0,
+ BLE_QIOT_LOG_LEVEL_ERR,
+ BLE_QIOT_LOG_LEVEL_WARN,
+ BLE_QIOT_LOG_LEVEL_INFO,
+ BLE_QIOT_LOG_LEVEL_DEBUG,
+ BLE_QIOT_LOG_LEVEL_ALL,
+} e_ble_qiot_log_level;
+
+// log new line feed type
+#define LINE_NONE
+#define LINE_LF "\n"
+#define LINE_CR "\r"
+#define LINE_CRLF "\r\n"
+
+// log new line feed type config
+#define LOG_LINE_FEED_TYPE LINE_CRLF
+
+extern e_ble_qiot_log_level g_log_level;
+
+#ifndef ble_qiot_log_d
+#define ble_qiot_log_d(fmt, args...) \
+ do { \
+ if (g_log_level < BLE_QIOT_LOG_LEVEL_DEBUG) \
+ break; \
+ BLE_QIOT_LOG_PRINT("qiot debug: " fmt LOG_LINE_FEED_TYPE, ##args); \
+ } while (0)
+#endif
+
+#ifndef ble_qiot_log_i
+#define ble_qiot_log_i(fmt, args...) \
+ do { \
+ if (g_log_level < BLE_QIOT_LOG_LEVEL_INFO) \
+ break; \
+ BLE_QIOT_LOG_PRINT("qiot info: " fmt LOG_LINE_FEED_TYPE, ##args); \
+ } while (0)
+#endif
+
+#ifndef ble_qiot_log_w
+#define ble_qiot_log_w(fmt, args...) \
+ do { \
+ if (g_log_level < BLE_QIOT_LOG_LEVEL_WARN) \
+ break; \
+ BLE_QIOT_LOG_PRINT("qiot warn(%s|%d): " fmt LOG_LINE_FEED_TYPE, __FILE__, __LINE__, ##args); \
+ } while (0)
+#endif
+
+#ifndef ble_qiot_log_e
+#define ble_qiot_log_e(fmt, args...) \
+ do { \
+ if (g_log_level < BLE_QIOT_LOG_LEVEL_ERR) \
+ break; \
+ BLE_QIOT_LOG_PRINT("qiot err(%s|%d): " fmt LOG_LINE_FEED_TYPE, __FILE__, __LINE__, ##args); \
+ } while (0)
+#endif
+
+#ifndef ble_qiot_log
+#define ble_qiot_log(level, fmt, args...) \
+ do { \
+ if (g_log_level < level) \
+ break; \
+ BLE_QIOT_LOG_PRINT("qiot log(%s|%d): " fmt LOG_LINE_FEED_TYPE, __FILE__, __LINE__, ##args); \
+ } while (0)
+#endif
+
+// this function only use for ble_qiot_log_hex
+#ifndef ble_qiot_log_raw
+#define ble_qiot_log_raw(fmt, args...) \
+ do { \
+ BLE_QIOT_LOG_PRINT(fmt, ##args); \
+ } while (0)
+#endif
+
+void ble_qiot_set_log_level(e_ble_qiot_log_level level);
+
+#if !BLE_QIOT_USER_DEFINE_HEXDUMP
+void ble_qiot_log_hex(e_ble_qiot_log_level level, const char *hex_name, const char *data, uint32_t data_len);
+#endif // BLE_QIOT_USER_DEFINE_HEXDUMP
+
+#ifdef __cplusplus
+}
+#endif
+#endif // QCLOUD_BLE_QIOT_LOG_H
diff --git a/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_md5.h b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_md5.h
new file mode 100644
index 0000000..2d670e0
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_md5.h
@@ -0,0 +1,94 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef QCLOUD_BLE_QIOT_MD5_H
+#define QCLOUD_BLE_QIOT_MD5_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MD5_DIGEST_SIZE 16
+
+typedef struct {
+ unsigned int total[2]; /*!< number of bytes processed */
+ unsigned int state[4]; /*!< intermediate digest state */
+ unsigned char buffer[64]; /*!< data block being processed */
+} iot_md5_context;
+
+/**
+ * @brief init MD5 context
+ *
+ * @param ctx MD5 context
+ */
+void utils_md5_init(iot_md5_context *ctx);
+
+/**
+ * @brief free MD5 context
+ *
+ * @param ctx MD5 context
+ */
+void utils_md5_free(iot_md5_context *ctx);
+
+/**
+ * @brief clone MD5 context
+ *
+ * @param dst destination MD5 context
+ * @param src source MD5 context
+ */
+void utils_md5_clone(iot_md5_context *dst, const iot_md5_context *src);
+
+/**
+ * @brief start MD5 calculation
+ *
+ * @param ctx MD5 context
+ */
+void utils_md5_starts(iot_md5_context *ctx);
+
+/**
+ * @brief MD5 update
+ *
+ * @param ctx MD5 context
+ * @param input input data
+ * @param ilen data length
+ */
+void utils_md5_update(iot_md5_context *ctx, const unsigned char *input, unsigned int ilen);
+
+/**
+ * @brief finish MD5 calculation
+ *
+ * @param ctx MD5 context
+ * @param output MD5 result
+ */
+void utils_md5_finish(iot_md5_context *ctx, unsigned char output[16]);
+
+/* MD5 internal process */
+void utils_md5_process(iot_md5_context *ctx, const unsigned char data[64]);
+
+/**
+ * @brief Output = MD5( input buffer )
+ *
+ * @param input data input
+ * @param ilen data lenght
+ * @param output MD5 result
+ */
+void utils_md5(const unsigned char *input, unsigned int ilen, unsigned char output[16]);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_param_check.h b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_param_check.h
new file mode 100644
index 0000000..ba51bcd
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_param_check.h
@@ -0,0 +1,93 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef QCLOUD_BLE_IOT_PARAM_CHECK_H_
+#define QCLOUD_BLE_IOT_PARAM_CHECK_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include "ble_qiot_log.h"
+
+#define NUMBERIC_SANITY_CHECK(num, err) \
+ do { \
+ if (0 == (num)) { \
+ ble_qiot_log_e("Invalid argument, numeric 0"); \
+ return (err); \
+ } \
+ } while (0)
+
+#define NUMBERIC_SANITY_CHECK_RTN(num) \
+ do { \
+ if (0 == (num)) { \
+ ble_qiot_log_e("Invalid argument, numeric 0"); \
+ return; \
+ } \
+ } while (0)
+
+#define BUFF_LEN_SANITY_CHECK(num, min, err) \
+ do { \
+ if ((min) > (num)) { \
+ ble_qiot_log_e("Invalid argument, %d <= %d", min, num); \
+ return (err); \
+ } \
+ } while (0)
+
+#define POINTER_SANITY_CHECK(ptr, err) \
+ do { \
+ if (NULL == (ptr)) { \
+ ble_qiot_log_e("Invalid argument, %s = %p", #ptr, ptr); \
+ return (err); \
+ } \
+ } while (0)
+
+#define POINTER_SANITY_CHECK_RTN(ptr) \
+ do { \
+ if (NULL == (ptr)) { \
+ ble_qiot_log_e("Invalid argument, %s = %p", #ptr, ptr); \
+ return; \
+ } \
+ } while (0)
+
+#define STRING_PTR_SANITY_CHECK(ptr, err) \
+ do { \
+ if (NULL == (ptr)) { \
+ ble_qiot_log_e("Invalid argument, %s = %p", #ptr, (ptr)); \
+ return (err); \
+ } \
+ if (0 == strlen((ptr))) { \
+ ble_qiot_log_e("Invalid argument, %s = '%s'", #ptr, (ptr)); \
+ return (err); \
+ } \
+ } while (0)
+
+#define STRING_PTR_SANITY_CHECK_RTN(ptr) \
+ do { \
+ if (NULL == (ptr)) { \
+ ble_qiot_log_e("Invalid argument, %s = %p", #ptr, (ptr)); \
+ return; \
+ } \
+ if (0 == strlen((ptr))) { \
+ ble_qiot_log_e("Invalid argument, %s = '%s'", #ptr, (ptr)); \
+ return; \
+ } \
+ } while (0)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* QCLOUD_BLE_IOT_PARAM_CHECK_H_ */
diff --git a/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_service.h b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_service.h
new file mode 100644
index 0000000..bbccbf3
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_service.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_IOT_SERVICE_H_
+#define QCLOUD_BLE_IOT_SERVICE_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+
+#include "ble_qiot_export.h"
+#include "ble_qiot_llsync_data.h"
+#include "ble_qiot_template.h"
+
+// message type, reference data template
+enum {
+ BLE_QIOT_MSG_TYPE_PROPERTY = 0,
+ BLE_QIOT_MSG_TYPE_EVENT,
+ BLE_QIOT_MSG_TYPE_ACTION,
+ BLE_QIOT_MSG_TYPE_BUTT,
+};
+
+// define reply result
+enum {
+ BLE_QIOT_REPLY_SUCCESS = 0,
+ BLE_QIOT_REPLY_FAIL,
+ BLE_QIOT_REPLY_DATA_ERR,
+ BLE_QIOT_REPLY_BUTT,
+};
+
+// define message type that from server to device
+enum {
+ BLE_QIOT_DATA_DOWN_REPORT_REPLY = 0,
+ BLE_QIOT_DATA_DOWN_CONTROL,
+ BLE_QIOT_DATA_DOWN_GET_STATUS_REPLY,
+ BLE_QIOT_DATA_DOWN_ACTION,
+ BLE_QIOT_DATA_DOWN_EVENT_REPLY,
+};
+
+// define message type that from device to server
+enum {
+ BLE_QIOT_EVENT_UP_PROPERTY_REPORT = 0,
+ BLE_QIOT_EVENT_UP_CONTROL_REPLY,
+ BLE_QIOT_EVENT_UP_GET_STATUS,
+ BLE_QIOT_EVENT_UP_EVENT_POST,
+ BLE_QIOT_EVENT_UP_ACTION_REPLY,
+ BLE_QIOT_EVENT_UP_BIND_SIGN_RET,
+ BLE_QIOT_EVENT_UP_CONN_SIGN_RET,
+ BLE_QIOT_EVENT_UP_UNBIND_SIGN_RET,
+ BLE_QIOT_EVENT_UP_REPORT_MTU,
+ BLE_QIOT_EVENT_UP_REPLY_OTA_REPORT,
+ BLE_QIOT_EVENT_UP_REPLY_OTA_DATA,
+ BLE_QIOT_EVENT_UP_REPORT_CHECK_RESULT,
+ BLE_QIOT_EVENT_UP_SYNC_MTU,
+ BLE_QIOT_EVENT_UP_SYNC_WAIT_TIME,
+ BLE_QIOT_EVENT_UP_WIFI_MODE = 0xE0,
+ BLE_QIOT_EVENT_UP_WIFI_INFO,
+ BLE_QIOT_EVENT_UP_WIFI_CONNECT,
+ BLE_QIOT_EVENT_UP_WIFI_TOKEN,
+ BLE_QIOT_EVENT_UP_WIFI_LOG,
+ BLE_QIOT_EVENT_UP_BUTT,
+};
+
+// msg header define, bit 7-6 is msg type, bit 5 means request or reply, bit 4 - 0 is id
+#define BLE_QIOT_PARSE_MSG_HEAD_TYPE(_C) (((_C) & 0XFF) >> 6)
+#define BLE_QIOT_PARSE_MSG_HEAD_EFFECT(_C) ((((_C) & 0XFF) & 0X20) ? BLE_QIOT_EFFECT_REPLY : BLE_QIOT_EFFECT_REQUEST)
+#define BLE_QIOT_PARSE_MSG_HEAD_ID(_C) ((_C) & 0X1F)
+
+// tlv header define, bit 7 - 5 is type, bit 4 - 0 depends on type of data template
+#define BLE_QIOT_PARSE_TLV_HEAD_TYPE(_C) (((_C) & 0XFF) >> 5)
+#define BLE_QIOT_PARSE_TLV_HEAD_ID(_C) ((_C) & 0X1F)
+
+// handle llsync device info
+// return 0 is success, other is error
+int ble_device_info_msg_handle(const char *in_buf, int in_len);
+
+// lldata message from remote
+// return 0 is success, other is error
+int ble_lldata_msg_handle(const char *in_buf, int in_len);
+
+// ota message from remote
+// return 0 is success, other is error
+int ble_ota_msg_handle(const char *buf, uint16_t len);
+
+#ifdef __cplusplus
+}
+#endif
+#endif // QCLOUD_BLE_IOT_SERVICE_H_
diff --git a/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_sha1.h b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_sha1.h
new file mode 100644
index 0000000..89fca2a
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_sha1.h
@@ -0,0 +1,93 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef QCLOUD_BLE_LLSYNC_BLE_QIOT_SHA1_H
+#define QCLOUD_BLE_LLSYNC_BLE_QIOT_SHA1_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+
+/**
+ * \brief SHA-1 context structure
+ */
+typedef struct {
+ uint32_t total[2]; /*!< number of bytes processed */
+ uint32_t state[5]; /*!< intermediate digest state */
+ unsigned char buffer[64]; /*!< data block being processed */
+} iot_sha1_context;
+
+/**
+ * \brief Initialize SHA-1 context
+ *
+ * \param ctx SHA-1 context to be initialized
+ */
+void utils_sha1_init(iot_sha1_context *ctx);
+
+/**
+ * \brief Clear SHA-1 context
+ *
+ * \param ctx SHA-1 context to be cleared
+ */
+void utils_sha1_free(iot_sha1_context *ctx);
+
+/**
+ * \brief Clone (the state of) a SHA-1 context
+ *
+ * \param dst The destination context
+ * \param src The context to be cloned
+ */
+void utils_sha1_clone(iot_sha1_context *dst, const iot_sha1_context *src);
+
+/**
+ * \brief SHA-1 context setup
+ *
+ * \param ctx context to be initialized
+ */
+void utils_sha1_starts(iot_sha1_context *ctx);
+
+/**
+ * \brief SHA-1 process buffer
+ *
+ * \param ctx SHA-1 context
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ */
+void utils_sha1_update(iot_sha1_context *ctx, const unsigned char *input, size_t ilen);
+
+/**
+ * \brief SHA-1 final digest
+ *
+ * \param ctx SHA-1 context
+ * \param output SHA-1 checksum result
+ */
+void utils_sha1_finish(iot_sha1_context *ctx, unsigned char output[20]);
+
+/* Internal use */
+void utils_sha1_process(iot_sha1_context *ctx, const unsigned char data[64]);
+
+/**
+ * \brief Output = SHA-1( input buffer )
+ *
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ * \param output SHA-1 checksum result
+ */
+void utils_sha1(const unsigned char *input, size_t ilen, unsigned char output[20]);
+
+#endif // QCLOUD_BLE_LLSYNC_BLE_QIOT_SHA1_H
diff --git a/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_template.h b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_template.h
new file mode 100644
index 0000000..262ed36
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_template.h
@@ -0,0 +1,119 @@
+/*
+* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+* Licensed under the MIT License (the "License"); you may not use this file except in
+* compliance with the License. You may obtain a copy of the License at
+* http://opensource.org/licenses/MIT
+* Unless required by applicable law or agreed to in writing, software distributed under the License is
+* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+* either express or implied. See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+#ifndef BLE_QIOT_TEMPLATE_H_
+#define BLE_QIOT_TEMPLATE_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+//#include
+
+
+// data type in template, corresponding to type in json file
+enum {
+ BLE_QIOT_DATA_TYPE_BOOL = 0,
+ BLE_QIOT_DATA_TYPE_INT,
+ BLE_QIOT_DATA_TYPE_STRING,
+ BLE_QIOT_DATA_TYPE_FLOAT,
+ BLE_QIOT_DATA_TYPE_ENUM,
+ BLE_QIOT_DATA_TYPE_TIME,
+ BLE_QIOT_DATA_TYPE_STRUCT,
+ BLE_QIOT_DATA_TYPE_BUTT,
+};
+
+// message type, reference data template
+enum {
+ BLE_QIOT_PROPERTY_AUTH_RW = 0,
+ BLE_QIOT_PROPERTY_AUTH_READ,
+ BLE_QIOT_PROPERTY_AUTH_BUTT,
+};
+
+// define message flow direction
+enum {
+ BLE_QIOT_EFFECT_REQUEST = 0,
+ BLE_QIOT_EFFECT_REPLY,
+ BLE_QIOT_EFFECT_BUTT,
+};
+#define BLE_QIOT_PACKAGE_MSG_HEAD(_TYPE, _REPLY, _ID) (((_TYPE) << 6) | (((_REPLY) == BLE_QIOT_EFFECT_REPLY) << 5) | ((_ID) & 0X1F))
+#define BLE_QIOT_PACKAGE_TLV_HEAD(_TYPE, _ID) (((_TYPE) << 5) | ((_ID) & 0X1F))
+
+
+// define tlv struct
+typedef struct {
+ uint8_t type;
+ uint8_t id;
+ uint16_t len;
+ char *val;
+} e_ble_tlv;
+#define BLE_QIOT_INCLUDE_PROPERTY
+
+// define property id
+enum {
+ BLE_QIOT_PROPERTY_ID_POWER_SWITCH = 0,
+ BLE_QIOT_PROPERTY_ID_BUTT,
+};
+
+// define property set handle return 0 if success, other is error
+// sdk call the function that inform the server data to the device
+typedef int (*property_set_cb)(const char *data, uint16_t len);
+
+// define property get handle. return the data length obtained, -1 is error, 0 is no data
+// sdk call the function fetch user data and send to the server, the data should wrapped by user adn skd just transmit
+typedef int (*property_get_cb)(char *buf, uint16_t buf_len);
+
+// each property have a struct ble_property_t, make up a array named sg_ble_property_array
+typedef struct {
+ property_set_cb set_cb; //set callback
+ property_get_cb get_cb; //get callback
+ uint8_t authority; //property authority
+ uint8_t type; //data type
+} ble_property_t;
+// property module
+#ifdef BLE_QIOT_INCLUDE_PROPERTY
+uint8_t ble_get_property_type_by_id(uint8_t id);
+
+int ble_user_property_set_data(const e_ble_tlv *tlv);
+int ble_user_property_get_data_by_id(uint8_t id, char *buf, uint16_t buf_len);
+int ble_user_property_report_reply_handle(uint8_t result);
+int ble_lldata_parse_tlv(const char *buf, int buf_len, e_ble_tlv *tlv);
+int ble_user_property_struct_handle(const char *in_buf, uint16_t buf_len, ble_property_t *struct_arr, uint8_t arr_size);
+int ble_user_property_struct_get_data(char *in_buf, uint16_t buf_len, ble_property_t *struct_arr, uint8_t arr_size);
+void ll_sync_led_switch(void);
+void ll_sync_unbind(void);
+void llsync_device_state_sync(void);
+#endif
+
+// event module
+#ifdef BLE_QIOT_INCLUDE_EVENT
+int ble_event_get_id_array_size(uint8_t event_id);
+uint8_t ble_event_get_param_id_type(uint8_t event_id, uint8_t param_id);
+int ble_event_get_data_by_id(uint8_t event_id, uint8_t param_id, char *out_buf, uint16_t buf_len);
+int ble_user_event_reply_handle(uint8_t event_id, uint8_t result);
+#endif
+
+// action module
+#ifdef BLE_QIOT_INCLUDE_ACTION
+uint8_t ble_action_get_intput_type_by_id(uint8_t action_id, uint8_t input_id);
+uint8_t ble_action_get_output_type_by_id(uint8_t action_id, uint8_t output_id);
+int ble_action_get_input_id_size(uint8_t action_id);
+int ble_action_get_output_id_size(uint8_t action_id);
+int ble_action_user_handle_input_param(uint8_t action_id, e_ble_tlv *input_param_array, uint8_t input_array_size,
+ uint8_t *output_id_array);
+int ble_action_user_handle_output_param(uint8_t action_id, uint8_t output_id, char *buf, uint16_t buf_len);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif //BLE_QIOT_TEMPLATE_H_
diff --git a/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_utils_base64.h b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_utils_base64.h
new file mode 100644
index 0000000..c2a839d
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/include/ble_qiot_utils_base64.h
@@ -0,0 +1,36 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef QCLOUD_BLE_IOT_UTILS_BASE64_H_
+#define QCLOUD_BLE_IOT_UTILS_BASE64_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+#include "ble_qiot_export.h"
+
+ble_qiot_ret_status_t qcloud_iot_utils_base64encode(unsigned char *dst, size_t dlen, size_t *olen,
+ const unsigned char *src, size_t slen);
+
+ble_qiot_ret_status_t qcloud_iot_utils_base64decode(unsigned char *dst, size_t dlen, size_t *olen,
+ const unsigned char *src, size_t slen);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* QCLOUD_BLE_IOT_UTILS_BASE64_H_ */
diff --git a/apps/common/third_party_profile/Tecent_LL/tecent_ll_demo/ll_demo.c b/apps/common/third_party_profile/Tecent_LL/tecent_ll_demo/ll_demo.c
new file mode 100644
index 0000000..fcd4837
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/tecent_ll_demo/ll_demo.c
@@ -0,0 +1,1341 @@
+/*********************************************************************************************
+ * Filename : le_server_module.c
+
+ * Description :
+
+ * Author :
+
+ * Email : zh-jieli.com
+
+ * Last modifiled : 2017-01-17 11:14
+
+ * Copyright:(c)JIELI 2011-2016 @ , All Rights Reserved.
+*********************************************************************************************/
+
+// *****************************************************************************
+/* EXAMPLE_START(le_counter): LE Peripheral - Heartbeat Counter over GATT
+ *
+ * @text All newer operating systems provide GATT Client functionality.
+ * The LE Counter examples demonstrates how to specify a minimal GATT Database
+ * with a custom GATT Service and a custom Characteristic that sends periodic
+ * notifications.
+ */
+// *****************************************************************************
+#include "system/app_core.h"
+#include "system/includes.h"
+
+#include "app_config.h"
+#include "app_action.h"
+
+#include "btstack/btstack_task.h"
+#include "btstack/bluetooth.h"
+#include "user_cfg.h"
+#include "vm.h"
+#include "btcontroller_modules.h"
+#include "bt_common.h"
+#include "3th_profile_api.h"
+
+#include "ll_demo.h"
+#include "le_common.h"
+
+#include "rcsp_bluetooth.h"
+#include "JL_rcsp_api.h"
+#include "custom_cfg.h"
+#include "ble_qiot_export.h"
+#include "ble_qiot_service.h"
+#include "ll_task.h"
+
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_LL_SYNC)
+
+//TRANS ANCS
+#define TRANS_ANCS_EN 0
+#if TRANS_ANCS_EN
+#include "btstack/btstack_event.h"
+#endif
+
+#define TEST_SEND_DATA_RATE 0 //测试上行发送数据
+#define TEST_SEND_HANDLE_VAL ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE
+/* #define TEST_SEND_HANDLE_VAL ATT_CHARACTERISTIC_ae05_01_VALUE_HANDLE */
+#define EXT_ADV_MODE_EN 0
+
+#define TEST_AUDIO_DATA_UPLOAD 0 //测试文件上传
+
+#define LL_TECENT_SUPPORT_TASK 1
+
+#if LE_DEBUG_PRINT_EN
+extern void printf_buf(u8 *buf, u32 len);
+/* #define log_info printf */
+#define log_info(x, ...) printf("[ll_demo]" x " ", ## __VA_ARGS__)
+#define log_info_hexdump printf_buf
+#else
+#define log_info(...)
+#define log_info_hexdump(...)
+#endif
+
+
+/* #define LOG_TAG_CONST BT_BLE */
+/* #define LOG_TAG "[LE_S_DEMO]" */
+/* #define LOG_ERROR_ENABLE */
+/* #define LOG_DEBUG_ENABLE */
+/* #define LOG_INFO_ENABLE */
+/* #define LOG_DUMP_ENABLE */
+/* #define LOG_CLI_ENABLE */
+/* #include "debug.h" */
+
+//------
+//ATT发送的包长, note: 20 <=need >= MTU
+#define ATT_LOCAL_MTU_SIZE (200) //
+//ATT缓存的buffer大小, note: need >= 20,可修改
+#define ATT_SEND_CBUF_SIZE (512) //
+
+//共配置的RAM
+#define ATT_RAM_BUFSIZE (ATT_CTRL_BLOCK_SIZE + ATT_LOCAL_MTU_SIZE + ATT_SEND_CBUF_SIZE) //note:
+static u8 att_ram_buffer[ATT_RAM_BUFSIZE] __attribute__((aligned(4)));
+//---------------
+
+#if TEST_SEND_DATA_RATE
+static u32 test_data_count;
+static u32 server_timer_handle = 0;
+static u8 test_data_start;
+#endif
+
+/*
+ 打开流控使能后,确定使能接口 att_server_flow_enable 被调用
+ 然后使用过程 通过接口 att_server_flow_hold 来控制流控开关
+ 注意:流控只能控制对方使用带响应READ/WRITE等命令方式
+ 例如:ATT_WRITE_REQUEST = 0x12
+ */
+#define ATT_DATA_RECIEVT_FLOW 0//流控功能使能
+
+//---------------
+// 广播周期 (unit:0.625ms)
+#define ADV_INTERVAL_MIN (160*5)
+
+#define HOLD_LATENCY_CNT_MIN (3) //(0~0xffff)
+#define HOLD_LATENCY_CNT_MAX (15) //(0~0xffff)
+#define HOLD_LATENCY_CNT_ALL (0xffff)
+
+static volatile hci_con_handle_t con_handle;
+
+//加密设置
+/* static const uint8_t sm_min_key_size = 7; */
+
+//连接参数更新请求设置
+//是否使能参数请求更新,0--disable, 1--enable
+static const uint8_t connection_update_enable = 1; ///0--disable, 1--enable
+//当前请求的参数表index
+static uint8_t connection_update_cnt = 0; //
+
+//参数表
+static const struct conn_update_param_t connection_param_table[] = {
+ {16, 24, 10, 600},//11
+ {12, 28, 10, 600},//3.7
+ {8, 20, 10, 600},
+ /* {12, 28, 4, 600},//3.7 */
+ /* {12, 24, 30, 600},//3.05 */
+};
+
+//共可用的参数组数
+#define CONN_PARAM_TABLE_CNT (sizeof(connection_param_table)/sizeof(struct conn_update_param_t))
+
+#if (ATT_RAM_BUFSIZE < 64)
+#error "adv_data & rsp_data buffer error!!!!!!!!!!!!"
+#endif
+
+//用户可配对的,这是样机跟客户开发的app配对的秘钥
+/* const u8 link_key_data[16] = {0x06, 0x77, 0x5f, 0x87, 0x91, 0x8d, 0xd4, 0x23, 0x00, 0x5d, 0xf1, 0xd8, 0xcf, 0x0c, 0x14, 0x2b}; */
+#define EIR_TAG_STRING 0xd6, 0x05, 0x08, 0x00, 'J', 'L', 'A', 'I', 'S', 'D','K'
+static const char user_tag_string[] = {EIR_TAG_STRING};
+
+static u8 adv_data_len;
+static u8 adv_data[ADV_RSP_PACKET_MAX];//max is 31
+static u8 scan_rsp_data_len;
+static u8 scan_rsp_data[ADV_RSP_PACKET_MAX];//max is 31
+
+/* #define adv_data &att_ram_buffer[0] */
+/* #define scan_rsp_data &att_ram_buffer[32] */
+
+static char gap_device_name[BT_NAME_LEN_MAX] = "jl_ble_test";
+static u8 gap_device_name_len = 0; //名字长度,不包含结束符
+static u8 ble_work_state = 0; //ble 状态变化
+static u8 adv_ctrl_en; //广播控制
+
+static u8 test_read_write_buf[4];
+
+static void (*app_recieve_callback)(void *priv, void *buf, u16 len) = NULL;
+static void (*app_ble_state_callback)(void *priv, ble_state_e state) = NULL;
+static void (*ble_resume_send_wakeup)(void) = NULL;
+static u32 channel_priv;
+
+static int app_send_user_data_check(u16 len);
+int llsync_app_send_user_data_do(void *priv, u8 *data, u16 len);
+static int app_send_user_data(u16 handle, u8 *data, u16 len, u8 handle_type);
+
+// Complete Local Name 默认的蓝牙名字
+
+//------------------------------------------------------
+//广播参数设置
+static void advertisements_setup_init();
+static int set_adv_enable(void *priv, u32 en);
+static int get_buffer_vaild_len(void *priv);
+extern const char *bt_get_local_name();
+extern void clr_wdt(void);
+extern void sys_auto_shut_down_disable(void);
+extern void sys_auto_shut_down_enable(void);
+extern u8 get_total_connect_dev(void);
+
+//------------------------------------------------------
+//NACS
+#if TRANS_ANCS_EN
+#define ANCS_SUBEVENT_CLIENT_NOTIFICATION 0xF1
+void ancs_client_init(void);
+void ancs_client_register_callback(btstack_packet_handler_t callback);
+const char *ancs_client_attribute_name_for_id(int id);
+void ancs_set_notification_buffer(u8 *buffer, u16 buffer_size);
+
+//ancs info buffer
+#define ANCS_INFO_BUFFER_SIZE (1024)
+static u8 ancs_info_buffer[ANCS_INFO_BUFFER_SIZE];
+#endif
+
+//------------------------------------------------------
+#if TEST_AUDIO_DATA_UPLOAD
+static const u8 test_audio_data_file[1024] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9
+};
+
+#define AUDIO_ONE_PACKET_LEN 128
+static void test_send_audio_data(int init_flag)
+{
+ static u32 send_pt = 0;
+ static u32 start_flag = 0;
+
+ if (!con_handle) {
+ return;
+ }
+
+ if (init_flag) {
+ log_info("audio send init\n");
+ send_pt = 0;
+ start_flag = 1;
+ }
+
+ if (!start_flag) {
+ return;
+ }
+
+ u32 file_size = sizeof(test_audio_data_file);
+ u8 *file_ptr = test_audio_data_file;
+
+ if (send_pt >= file_size) {
+ log_info("audio send Complete\n");
+ start_flag = 0;
+ return;
+ }
+
+ u32 send_len = file_size - send_pt;
+ if (send_len > AUDIO_ONE_PACKET_LEN) {
+ send_len = AUDIO_ONE_PACKET_LEN;
+ }
+
+ while (1) {
+ if (app_send_user_data_check(send_len)) {
+ log_info("audio send %08x\n", send_pt);
+ if (app_send_user_data(ATT_CHARACTERISTIC_ae3c_01_VALUE_HANDLE, &file_ptr[send_pt], send_len, ATT_OP_AUTO_READ_CCC)) {
+ log_info("audio send fail!\n");
+ break;
+ } else {
+ send_pt += send_len;
+ }
+ } else {
+ break;
+ }
+ }
+}
+
+#endif
+
+
+static void send_request_connect_parameter(u8 table_index)
+{
+ struct conn_update_param_t *param = (void *)&connection_param_table[table_index];//static ram
+
+ log_info("update_request:-%d-%d-%d-%d-\n", param->interval_min, param->interval_max, param->latency, param->timeout);
+ if (con_handle) {
+ ble_op_conn_param_request(con_handle, param);
+ }
+}
+
+static void check_connetion_updata_deal(void)
+{
+ if (connection_update_enable) {
+ if (connection_update_cnt < CONN_PARAM_TABLE_CNT) {
+ send_request_connect_parameter(connection_update_cnt);
+ }
+ }
+}
+
+static void connection_update_complete_success(u8 *packet)
+{
+ int con_handle, conn_interval, conn_latency, conn_timeout;
+
+ con_handle = hci_subevent_le_connection_update_complete_get_connection_handle(packet);
+ conn_interval = hci_subevent_le_connection_update_complete_get_conn_interval(packet);
+ conn_latency = hci_subevent_le_connection_update_complete_get_conn_latency(packet);
+ conn_timeout = hci_subevent_le_connection_update_complete_get_supervision_timeout(packet);
+
+ log_info("conn_interval = %d\n", conn_interval);
+ log_info("conn_latency = %d\n", conn_latency);
+ log_info("conn_timeout = %d\n", conn_timeout);
+}
+
+
+static void set_ble_work_state(ble_state_e state)
+{
+ if (state != ble_work_state) {
+ log_info("ble_work_st:%x->%x\n", ble_work_state, state);
+ ble_work_state = state;
+ if (app_ble_state_callback) {
+ app_ble_state_callback((void *)channel_priv, state);
+ }
+ }
+}
+
+static ble_state_e get_ble_work_state(void)
+{
+ return ble_work_state;
+}
+
+static void cbk_sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
+{
+ sm_just_event_t *event = (void *)packet;
+ u32 tmp32;
+ switch (packet_type) {
+ case HCI_EVENT_PACKET:
+ switch (hci_event_packet_get_type(packet)) {
+ case SM_EVENT_JUST_WORKS_REQUEST:
+ sm_just_works_confirm(sm_event_just_works_request_get_handle(packet));
+ log_info("Just Works Confirmed.\n");
+ break;
+ case SM_EVENT_PASSKEY_DISPLAY_NUMBER:
+ log_info_hexdump(packet, size);
+ memcpy(&tmp32, event->data, 4);
+ log_info("Passkey display: %06u.\n", tmp32);
+ break;
+ }
+ break;
+ }
+}
+
+
+#if TEST_SEND_DATA_RATE
+static void server_timer_handler(void)
+{
+ if (!con_handle) {
+ test_data_count = 0;
+ test_data_start = 0;
+ return;
+ }
+
+ log_info("peer_rssi = %d\n", ble_vendor_get_peer_rssi(con_handle));
+
+ if (test_data_count) {
+ log_info("\n%d bytes send: %d.%02d KB/s \n", test_data_count, test_data_count / 1000, test_data_count % 1000);
+ test_data_count = 0;
+ }
+}
+
+static void server_timer_start(void)
+{
+ if (server_timer_handle) {
+ return;
+ }
+
+ server_timer_handle = sys_timer_add(NULL, server_timer_handler, 1000);
+}
+
+static void server_timer_stop(void)
+{
+ if (server_timer_handle) {
+ sys_timeout_del(server_timer_handle);
+ server_timer_handle = 0;
+ }
+}
+
+void test_data_send_packet(void)
+{
+ u32 vaild_len = get_buffer_vaild_len(0);//获取发送buffer可写入的数据
+ if (!test_data_start) {
+ return;
+ }
+
+ if (vaild_len) {
+ if (!app_send_user_data(TEST_SEND_HANDLE_VAL, (void *)&test_data_count, vaild_len, ATT_OP_AUTO_READ_CCC)) {
+ test_data_count += vaild_len;
+ }
+ }
+ clr_wdt();
+}
+#endif
+
+
+static void can_send_now_wakeup(void)
+{
+ /* putchar('E'); */
+ if (ble_resume_send_wakeup) {
+ ble_resume_send_wakeup();
+ }
+
+#if TEST_SEND_DATA_RATE
+ test_data_send_packet();
+#endif
+
+#if TEST_AUDIO_DATA_UPLOAD
+ test_send_audio_data(0);
+#endif
+
+}
+
+static void ble_auto_shut_down_enable(u8 enable)
+{
+#if TCFG_AUTO_SHUT_DOWN_TIME
+ if (enable) {
+ if (get_total_connect_dev() == 0) { //已经没有设备连接
+ sys_auto_shut_down_enable();
+ }
+ } else {
+ sys_auto_shut_down_disable();
+ }
+#endif
+}
+
+const char *const phy_result[] = {
+ "None",
+ "1M",
+ "2M",
+ "Coded",
+};
+
+static void set_connection_data_length(u16 tx_octets, u16 tx_time)
+{
+ if (con_handle) {
+ ble_op_set_data_length(con_handle, tx_octets, tx_time);
+ }
+}
+
+static void set_connection_data_phy(u8 tx_phy, u8 rx_phy)
+{
+ if (0 == con_handle) {
+ return;
+ }
+
+ u8 all_phys = 0;
+ u16 phy_options = CONN_SET_PHY_OPTIONS_S8;
+
+ ble_op_set_ext_phy(con_handle, all_phys, tx_phy, rx_phy, phy_options);
+}
+
+static void server_profile_start(u16 con_handle)
+{
+#if BT_FOR_APP_EN
+ set_app_connect_type(TYPE_BLE);
+#endif
+ ble_op_att_send_init(con_handle, att_ram_buffer, ATT_RAM_BUFSIZE, ATT_LOCAL_MTU_SIZE);
+ set_ble_work_state(BLE_ST_CONNECT);
+ ble_auto_shut_down_enable(0);
+
+ /* set_connection_data_phy(CONN_SET_CODED_PHY, CONN_SET_CODED_PHY); */
+}
+
+_WEAK_
+u8 ble_update_get_ready_jump_flag(void)
+{
+ return 0;
+}
+/*
+ * @section Packet Handler
+ *
+ * @text The packet handler is used to:
+ * - stop the counter after a disconnect
+ * - send a notification when the requested ATT_EVENT_CAN_SEND_NOW is received
+ */
+
+/* LISTING_START(packetHandler): Packet Handler */
+static void cbk_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
+{
+ int mtu;
+ u32 tmp;
+ u8 status;
+ const char *attribute_name;
+
+ switch (packet_type) {
+ case HCI_EVENT_PACKET:
+ switch (hci_event_packet_get_type(packet)) {
+
+ /* case DAEMON_EVENT_HCI_PACKET_SENT: */
+ /* break; */
+ case ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE:
+ log_info("ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE\n");
+ case ATT_EVENT_CAN_SEND_NOW:
+ can_send_now_wakeup();
+ break;
+
+ case HCI_EVENT_LE_META:
+ switch (hci_event_le_meta_get_subevent_code(packet)) {
+ case HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE:
+ status = hci_subevent_le_enhanced_connection_complete_get_status(packet);
+ if (status) {
+ log_info("LE_SLAVE CONNECTION FAIL!!! %0x\n", status);
+ set_ble_work_state(BLE_ST_DISCONN);
+ break;
+ }
+ con_handle = hci_subevent_le_enhanced_connection_complete_get_connection_handle(packet);
+ log_info("HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE : %0x\n", con_handle);
+ log_info("conn_interval = %d\n", hci_subevent_le_enhanced_connection_complete_get_conn_interval(packet));
+ log_info("conn_latency = %d\n", hci_subevent_le_enhanced_connection_complete_get_conn_latency(packet));
+ log_info("conn_timeout = %d\n", hci_subevent_le_enhanced_connection_complete_get_supervision_timeout(packet));
+ server_profile_start(con_handle);
+ break;
+
+ case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
+ con_handle = hci_subevent_le_connection_complete_get_connection_handle(packet);
+ log_info("HCI_SUBEVENT_LE_CONNECTION_COMPLETE: %0x\n", con_handle);
+ connection_update_complete_success(packet + 8);
+ server_profile_start(con_handle);
+#if RCSP_BTMATE_EN
+#if (defined(BT_CONNECTION_VERIFY) && (0 == BT_CONNECTION_VERIFY))
+ JL_rcsp_auth_reset();
+#endif
+ //rcsp_dev_select(RCSP_BLE);
+ rcsp_init();
+#endif
+ log_info("ble remote rssi= %d\n", ble_vendor_get_peer_rssi(con_handle));
+ break;
+
+ case HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE:
+ connection_update_complete_success(packet);
+ break;
+
+ case HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE:
+ log_info("APP HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE\n");
+ /* set_connection_data_phy(CONN_SET_CODED_PHY, CONN_SET_CODED_PHY); */
+ break;
+
+ case HCI_SUBEVENT_LE_PHY_UPDATE_COMPLETE:
+ log_info("APP HCI_SUBEVENT_LE_PHY_UPDATE %s\n", hci_event_le_meta_get_phy_update_complete_status(packet) ? "Fail" : "Succ");
+ log_info("Tx PHY: %s\n", phy_result[hci_event_le_meta_get_phy_update_complete_tx_phy(packet)]);
+ log_info("Rx PHY: %s\n", phy_result[hci_event_le_meta_get_phy_update_complete_rx_phy(packet)]);
+ break;
+ }
+ break;
+
+ case HCI_EVENT_DISCONNECTION_COMPLETE:
+ log_info("HCI_EVENT_DISCONNECTION_COMPLETE: %0x\n", packet[5]);
+#if RCSP_BTMATE_EN
+ rcsp_exit();
+#endif
+ con_handle = 0;
+ ble_op_att_send_init(con_handle, 0, 0, 0);
+ set_ble_work_state(BLE_ST_DISCONN);
+
+ if (!ble_update_get_ready_jump_flag()) {
+ ble_qiot_advertising_start();
+ }
+ connection_update_cnt = 0;
+#if BT_FOR_APP_EN
+ set_app_connect_type(TYPE_NULL);
+#endif
+ ble_auto_shut_down_enable(1);
+ break;
+
+ case ATT_EVENT_MTU_EXCHANGE_COMPLETE:
+ mtu = att_event_mtu_exchange_complete_get_MTU(packet) - 3;
+ log_info("ATT MTU = %u\n", mtu);
+ ble_op_att_set_send_mtu(mtu);
+ /* set_connection_data_length(251, 2120); */
+ break;
+
+ case HCI_EVENT_VENDOR_REMOTE_TEST:
+ log_info("--- HCI_EVENT_VENDOR_REMOTE_TEST\n");
+ break;
+
+ case L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE:
+ tmp = little_endian_read_16(packet, 4);
+ log_info("-update_rsp: %02x\n", tmp);
+ if (tmp) {
+ connection_update_cnt++;
+ log_info("remoter reject!!!\n");
+ check_connetion_updata_deal();
+ } else {
+ connection_update_cnt = CONN_PARAM_TABLE_CNT;
+ }
+ break;
+
+ case HCI_EVENT_ENCRYPTION_CHANGE:
+ log_info("HCI_EVENT_ENCRYPTION_CHANGE= %d\n", packet[2]);
+ break;
+
+#if TRANS_ANCS_EN
+ case HCI_EVENT_ANCS_META:
+ switch (hci_event_ancs_meta_get_subevent_code(packet)) {
+ case ANCS_SUBEVENT_CLIENT_NOTIFICATION:
+ printf("ANCS_SUBEVENT_CLIENT_NOTIFICATION \n");
+ attribute_name = ancs_client_attribute_name_for_id(ancs_subevent_client_notification_get_attribute_id(packet));
+ if (!attribute_name) {
+ printf("ancs unknow attribute_id :%d \n", ancs_subevent_client_notification_get_attribute_id(packet));
+ break;
+ } else {
+ u16 attribute_strlen = little_endian_read_16(packet, 7);
+ u8 *attribute_str = (void *)little_endian_read_32(packet, 9);
+ printf("Notification: %s - %s \n", attribute_name, attribute_str);
+ }
+ break;
+ default:
+ break;
+ }
+
+ break;
+#endif
+
+ }
+ break;
+ }
+}
+
+
+/* LISTING_END */
+
+/*
+ * @section ATT Read
+ *
+ * @text The ATT Server handles all reads to constant data. For dynamic data like the custom characteristic, the registered
+ * att_read_callback is called. To handle long characteristics and long reads, the att_read_callback is first called
+ * with buffer == NULL, to request the total value length. Then it will be called again requesting a chunk of the value.
+ * See Listing attRead.
+ */
+
+#if 0
+/* LISTING_START(attRead): ATT Read */
+
+// ATT Client Read Callback for Dynamic Data
+// - if buffer == NULL, don't copy data, just return size of value
+// - if buffer != NULL, copy data and return number bytes copied
+// @param offset defines start of attribute value
+static uint16_t att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset, uint8_t *buffer, uint16_t buffer_size)
+{
+
+ uint16_t att_value_len = 0;
+ uint16_t handle = att_handle;
+
+ log_info("read_callback, handle= 0x%04x,buffer= %08x\n", handle, (u32)buffer);
+
+ switch (handle) {
+ case ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE:
+ att_value_len = gap_device_name_len;
+
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+
+ if (buffer) {
+ memcpy(buffer, &gap_device_name[offset], buffer_size);
+ att_value_len = buffer_size;
+ log_info("\n------read gap_name: %s \n", gap_device_name);
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_ae10_01_VALUE_HANDLE:
+ att_value_len = sizeof(test_read_write_buf);
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+
+ if (buffer) {
+ memcpy(buffer, &test_read_write_buf[offset], buffer_size);
+ att_value_len = buffer_size;
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_ae04_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_ae02_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_ae05_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_ae3c_01_CLIENT_CONFIGURATION_HANDLE:
+ if (buffer) {
+ buffer[0] = att_get_ccc_config(handle);
+ buffer[1] = 0;
+ }
+ att_value_len = 2;
+ break;
+
+ default:
+ break;
+ }
+
+ log_info("att_value_len= %d\n", att_value_len);
+ return att_value_len;
+
+}
+#endif
+
+
+/* LISTING_END */
+/*
+ * @section ATT Write
+ *
+ * @text The only valid ATT write in this example is to the Client Characteristic Configuration, which configures notification
+ * and indication. If the ATT handle matches the client configuration handle, the new configuration value is stored and used
+ * in the heartbeat handler to decide if a new value should be sent. See Listing attWrite.
+ */
+
+/* LISTING_START(attWrite): ATT Write */
+static int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size)
+{
+ int result = 0;
+ u16 tmp16;
+ u8 *tmp_buf = NULL;
+ u16 handle = att_handle;
+
+ log_info("write_callback, handle= 0x%04x,size = %d\n", handle, buffer_size);
+
+ switch (handle) {
+ case ATT_CHARACTERISTIC_0000FFE3_65D0_4E20_B56A_E493541BA4E2_01_CLIENT_CONFIGURATION_HANDLE:
+ set_ble_work_state(BLE_ST_NOTIFY_IDICATE);
+ check_connetion_updata_deal();
+ log_info("\n------write ccc:%04x,%02x\n", handle, buffer[0]);
+ att_set_ccc_config(handle, buffer[0]);
+ break;
+
+ case ATT_CHARACTERISTIC_0000FFE1_65D0_4E20_B56A_E493541BA4E2_01_VALUE_HANDLE:
+ log_info("llsync device info handler\n");
+#if LL_TECENT_SUPPORT_TASK
+ tmp_buf = malloc(buffer_size + LL_PACKET_HEAD_LEN);
+ memcpy(tmp_buf + LL_PACKET_HEAD_LEN, buffer, buffer_size);
+ ((LL_PACKET_HEAD_T *)tmp_buf)->packet_channel = LL_DEVICE_INFO_MSG_CH;
+ ((LL_PACKET_HEAD_T *)tmp_buf)->len = buffer_size;
+ tecent_ll_packet_recieve(tmp_buf, buffer_size + LL_PACKET_HEAD_LEN);
+ free(tmp_buf);
+#else
+ result = ble_device_info_msg_handle(buffer, buffer_size);
+ if (result) {
+ log_info("llsync device info handler error:%d\n", result);
+ }
+#endif
+ break;
+
+ case ATT_CHARACTERISTIC_0000FFE2_65D0_4E20_B56A_E493541BA4E2_01_VALUE_HANDLE:
+ log_info("llsync data msg handler\n");
+#if LL_TECENT_SUPPORT_TASK
+ tmp_buf = malloc(buffer_size + LL_PACKET_HEAD_LEN);
+ memcpy(tmp_buf + LL_PACKET_HEAD_LEN, buffer, buffer_size);
+ ((LL_PACKET_HEAD_T *)tmp_buf)->packet_channel = LL_DATA_MSG_CH;
+ ((LL_PACKET_HEAD_T *)tmp_buf)->len = buffer_size;
+ tecent_ll_packet_recieve(tmp_buf, buffer_size + LL_PACKET_HEAD_LEN);
+ free(tmp_buf);
+#else
+ result = ble_lldata_msg_handle(buffer, buffer_size);
+ if (result) {
+ log_info("llsync data msg handler error:%d\n", result);
+ }
+#endif
+ break;
+
+ case ATT_CHARACTERISTIC_0000FFE3_65D0_4E20_B56A_E493541BA4E2_01_VALUE_HANDLE:
+ log_info("llsync notify msg \n");
+ break;
+
+ case ATT_CHARACTERISTIC_0000FFE4_65D0_4E20_B56A_E493541BA4E2_01_VALUE_HANDLE:
+ log_info("llsync ota msg handler");
+#if LL_TECENT_SUPPORT_TASK
+ tmp_buf = malloc(buffer_size + LL_PACKET_HEAD_LEN);
+ memcpy(tmp_buf + LL_PACKET_HEAD_LEN, buffer, buffer_size);
+ ((LL_PACKET_HEAD_T *)tmp_buf)->packet_channel = LL_OTA_MSG_CH;
+ ((LL_PACKET_HEAD_T *)tmp_buf)->len = buffer_size;
+ tecent_ll_packet_recieve(tmp_buf, buffer_size + LL_PACKET_HEAD_LEN);
+ free(tmp_buf);
+#else
+ result = ble_ota_msg_handle(buffer, buffer_size);
+ if (result) {
+ log_info("llsync ota msg handler error:%d\n", result);
+ }
+#endif
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int app_send_user_data(u16 handle, u8 *data, u16 len, u8 handle_type)
+{
+ u32 ret = APP_BLE_NO_ERROR;
+
+ if (!con_handle) {
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+ if (!att_get_ccc_config(handle + 1)) {
+ log_info("fail,no write ccc!!!,%04x\n", handle + 1);
+ return APP_BLE_NO_WRITE_CCC;
+ }
+
+ ret = ble_op_att_send_data(handle, data, len, handle_type);
+ if (ret == BLE_BUFFER_FULL) {
+ ret = APP_BLE_BUFF_FULL;
+ }
+
+ if (ret) {
+ log_info("app_send_fail:%d !!!!!!\n", ret);
+ }
+ return ret;
+}
+
+//------------------------------------------------------
+#if RCSP_BTMATE_EN
+static u8 tag_in_adv;
+#endif
+
+static int make_set_adv_data(void)
+{
+ u8 offset = 0;
+ u8 *buf = adv_data;
+
+
+#if DOUBLE_BT_SAME_MAC
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x0A, 1);
+#else
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x06, 1);
+#endif
+
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_16BIT_SERVICE_UUIDS, 0xAF30, 2);
+
+#if RCSP_BTMATE_EN
+ u8 tag_len = sizeof(user_tag_string);
+ if (tag_len > ADV_RSP_PACKET_MAX - (offset + 2)) {
+ tag_in_adv = 0;
+ } else {
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_MANUFACTURER_SPECIFIC_DATA, (void *)user_tag_string, tag_len);
+ tag_in_adv = 1;
+ }
+#endif
+
+ if (offset > ADV_RSP_PACKET_MAX) {
+ puts("***adv_data overflow!!!!!!\n");
+ return -1;
+ }
+ log_info("adv_data(%d):", offset);
+ log_info_hexdump(buf, offset);
+ adv_data_len = offset;
+ ble_op_set_adv_data(offset, buf);
+ return 0;
+}
+
+static int make_set_rsp_data(void)
+{
+ printf("make_set_rsp_data\n");
+ u8 offset = 0;
+ u8 *buf = scan_rsp_data;
+
+#if RCSP_BTMATE_EN
+ if (!tag_in_adv) {
+ u8 tag_len = sizeof(user_tag_string);
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_MANUFACTURER_SPECIFIC_DATA, (void *)user_tag_string, tag_len);
+ }
+#endif
+
+ u8 name_len = gap_device_name_len;
+ u8 vaild_len = ADV_RSP_PACKET_MAX - (offset + 2);
+ if (name_len > vaild_len) {
+ name_len = vaild_len;
+ }
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, (void *)gap_device_name, name_len);
+
+ if (offset > ADV_RSP_PACKET_MAX) {
+ puts("***rsp_data overflow!!!!!!\n");
+ return -1;
+ }
+
+ printf("rsp_data(%d):", offset);
+ printf_buf(buf, offset);
+ scan_rsp_data_len = offset;
+ ble_op_set_rsp_data(offset, buf);
+ return 0;
+}
+
+//广播参数设置
+static void advertisements_setup_init()
+{
+ uint8_t adv_type = ADV_IND;
+ uint8_t adv_channel = ADV_CHANNEL_ALL;
+ int ret = 0;
+
+ ble_op_set_adv_param(ADV_INTERVAL_MIN, adv_type, adv_channel);
+
+ ret |= make_set_adv_data();
+ ret |= make_set_rsp_data();
+
+ if (ret) {
+ puts("advertisements_setup_init fail !!!!!!\n");
+ return;
+ }
+
+}
+
+#define PASSKEY_ENTER_ENABLE 0 //输入passkey使能,可修改passkey
+//重设passkey回调函数,在这里可以重新设置passkey
+//passkey为6个数字组成,十万位、万位。。。。个位 各表示一个数字 高位不够为0
+static void reset_passkey_cb(u32 *key)
+{
+#if 1
+ u32 newkey = rand32();//获取随机数
+
+ newkey &= 0xfffff;
+ if (newkey > 999999) {
+ newkey = newkey - 999999; //不能大于999999
+ }
+ *key = newkey; //小于或等于六位数
+ printf("set new_key= %06u\n", *key);
+#else
+ *key = 123456; //for debug
+#endif
+}
+
+void ble_sm_setup_init(io_capability_t io_type, u8 auth_req, uint8_t min_key_size, u8 security_en)
+{
+ //setup SM: Display only
+ sm_init();
+ sm_set_io_capabilities(io_type);
+ sm_set_authentication_requirements(auth_req);
+ sm_set_encryption_key_size_range(min_key_size, 16);
+ sm_set_request_security(security_en);
+ sm_event_callback_set(&cbk_sm_packet_handler);
+
+ if (io_type == IO_CAPABILITY_DISPLAY_ONLY) {
+ reset_PK_cb_register(reset_passkey_cb);
+ }
+}
+
+#define LL_TCFG_BLE_SECURITY_EN 0 /*是否发请求加密命令*/
+void ble_profile_init(void)
+{
+ printf("LL sync ble profile init\n");
+ le_device_db_init();
+
+#if PASSKEY_ENTER_ENABLE
+ ble_sm_setup_init(IO_CAPABILITY_DISPLAY_ONLY, SM_AUTHREQ_MITM_PROTECTION | SM_AUTHREQ_BONDING, 7, LL_TCFG_BLE_SECURITY_EN);
+#else
+ /* ble_sm_setup_init(IO_CAPABILITY_NO_INPUT_NO_OUTPUT, SM_AUTHREQ_MITM_PROTECTION | SM_AUTHREQ_BONDING, 7, LL_TCFG_BLE_SECURITY_EN); */
+ ble_sm_setup_init(IO_CAPABILITY_NO_INPUT_NO_OUTPUT, SM_AUTHREQ_MITM_PROTECTION | SM_AUTHREQ_BONDING, 7, LL_TCFG_BLE_SECURITY_EN);
+#endif
+
+ /* setup ATT server */
+ att_server_init(profile_data, NULL, att_write_callback);
+ att_server_register_packet_handler(cbk_packet_handler);
+ /* gatt_client_register_packet_handler(packet_cbk); */
+
+ // register for HCI events
+ hci_event_callback_set(&cbk_packet_handler);
+ /* ble_l2cap_register_packet_handler(packet_cbk); */
+ /* sm_event_packet_handler_register(packet_cbk); */
+ le_l2cap_register_packet_handler(&cbk_packet_handler);
+
+#if TRANS_ANCS_EN
+ //setup GATT client
+ gatt_client_init();
+
+ //setup ANCS clent
+ ancs_client_init();
+ ancs_set_notification_buffer(ancs_info_buffer, sizeof(ancs_info_buffer));
+ ancs_client_register_callback(&cbk_packet_handler);
+#endif
+
+ ble_vendor_set_default_att_mtu(ATT_LOCAL_MTU_SIZE);
+}
+
+#if EXT_ADV_MODE_EN
+
+
+#define EXT_ADV_NAME 'J', 'L', '_', 'E', 'X', 'T', '_', 'A', 'D', 'V'
+/* #define EXT_ADV_NAME "JL_EXT_ADV" */
+#define EXT_ADV_DATA \
+ 0x02, 0x01, 0x06, \
+ 0x03, 0x02, 0xF0, 0xFF, \
+ BYTE_LEN(EXT_ADV_NAME) + 1, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, EXT_ADV_NAME
+
+const struct ext_advertising_param ext_adv_param = {
+ .Advertising_Handle = 0,
+ .Advertising_Event_Properties = 1,
+ .Primary_Advertising_Interval_Min = {30, 0, 0},
+ .Primary_Advertising_Interval_Max = {30, 0, 0},
+ .Primary_Advertising_Channel_Map = 7,
+ .Primary_Advertising_PHY = ADV_SET_1M_PHY,
+ .Secondary_Advertising_PHY = ADV_SET_1M_PHY,
+};
+
+const struct ext_advertising_data ext_adv_data = {
+ .Advertising_Handle = 0,
+ .Operation = 3,
+ .Fragment_Preference = 0,
+ .Advertising_Data_Length = BYTE_LEN(EXT_ADV_DATA),
+ .Advertising_Data = EXT_ADV_DATA,
+};
+
+const struct ext_advertising_enable ext_adv_enable = {
+ .Enable = 1,
+ .Number_of_Sets = 1,
+ .Advertising_Handle = 0,
+ .Duration = 0,
+ .Max_Extended_Advertising_Events = 0,
+};
+
+const struct ext_advertising_enable ext_adv_disable = {
+ .Enable = 0,
+ .Number_of_Sets = 1,
+ .Advertising_Handle = 0,
+ .Duration = 0,
+ .Max_Extended_Advertising_Events = 0,
+};
+
+#endif /* EXT_ADV_MODE_EN */
+
+static int set_adv_enable(void *priv, u32 en)
+{
+ ble_state_e next_state, cur_state;
+
+ if (!adv_ctrl_en && en) {
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+ if (con_handle) {
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+ if (en) {
+ next_state = BLE_ST_ADV;
+ } else {
+ next_state = BLE_ST_IDLE;
+ }
+
+ cur_state = get_ble_work_state();
+ switch (cur_state) {
+ case BLE_ST_ADV:
+ case BLE_ST_IDLE:
+ case BLE_ST_INIT_OK:
+ case BLE_ST_NULL:
+ case BLE_ST_DISCONN:
+ break;
+ default:
+ return APP_BLE_OPERATION_ERROR;
+ break;
+ }
+
+ if (cur_state == next_state) {
+ return APP_BLE_NO_ERROR;
+ }
+ log_info("adv_en:%d\n", en);
+ set_ble_work_state(next_state);
+
+#if EXT_ADV_MODE_EN
+ if (en) {
+ ble_op_set_ext_adv_param(&ext_adv_param, sizeof(ext_adv_param));
+
+ log_info_hexdump(&ext_adv_data, sizeof(ext_adv_data));
+ ble_op_set_ext_adv_data(&ext_adv_data, sizeof(ext_adv_data));
+
+ ble_op_set_ext_adv_enable(&ext_adv_enable, sizeof(ext_adv_enable));
+ } else {
+ ble_op_set_ext_adv_enable(&ext_adv_disable, sizeof(ext_adv_disable));
+ }
+#else
+ if (en) {
+ advertisements_setup_init();
+ }
+ ble_op_adv_enable(en);
+#endif /* EXT_ADV_MODE_EN */
+
+ return APP_BLE_NO_ERROR;
+}
+
+static int ble_disconnect(void *priv)
+{
+ if (con_handle) {
+ if (BLE_ST_SEND_DISCONN != get_ble_work_state()) {
+ log_info(">>>ble send disconnect\n");
+ set_ble_work_state(BLE_ST_SEND_DISCONN);
+ ble_op_disconnect(con_handle);
+ } else {
+ log_info(">>>ble wait disconnect...\n");
+ }
+ return APP_BLE_NO_ERROR;
+ } else {
+ return APP_BLE_OPERATION_ERROR;
+ }
+}
+
+
+static int get_buffer_vaild_len(void *priv)
+{
+ u32 vaild_len = 0;
+ ble_op_att_get_remain(&vaild_len);
+ return vaild_len;
+}
+
+int llsync_app_send_user_data_do(void *priv, u8 *data, u16 len)
+{
+#if PRINT_DMA_DATA_EN
+ if (len < 128) {
+ log_info("-le_tx(%d):");
+ log_info_hexdump(data, len);
+ } else {
+ putchar('L');
+ }
+#endif
+ return app_send_user_data(ATT_CHARACTERISTIC_0000FFE3_65D0_4E20_B56A_E493541BA4E2_01_VALUE_HANDLE, data, len, ATT_OP_AUTO_READ_CCC);
+}
+
+static int app_send_user_data_check(u16 len)
+{
+ u32 buf_space = get_buffer_vaild_len(0);
+ if (len <= buf_space) {
+ return 1;
+ }
+ return 0;
+}
+
+
+static int regiest_wakeup_send(void *priv, void *cbk)
+{
+ ble_resume_send_wakeup = cbk;
+ return APP_BLE_NO_ERROR;
+}
+
+static int regiest_recieve_cbk(void *priv, void *cbk)
+{
+ channel_priv = (u32)priv;
+ app_recieve_callback = cbk;
+ return APP_BLE_NO_ERROR;
+}
+
+static int regiest_state_cbk(void *priv, void *cbk)
+{
+ channel_priv = (u32)priv;
+ app_ble_state_callback = cbk;
+ return APP_BLE_NO_ERROR;
+}
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+
+
+u8 *ble_get_scan_rsp_ptr(u16 *len)
+{
+ if (len) {
+ *len = scan_rsp_data_len;
+ }
+ return scan_rsp_data;
+}
+
+u8 *ble_get_adv_data_ptr(u16 *len)
+{
+ if (len) {
+ *len = adv_data_len;
+ }
+ return adv_data;
+}
+
+u8 *ble_get_gatt_profile_data(u16 *len)
+{
+ *len = sizeof(profile_data);
+ return (u8 *)profile_data;
+}
+
+
+void bt_ble_adv_enable(u8 enable)
+{
+ set_adv_enable(0, enable);
+}
+
+u16 bt_ble_is_connected(void)
+{
+ return con_handle;
+}
+
+void ble_module_enable(u8 en)
+{
+ log_info("mode_en:%d\n", en);
+ if (en) {
+ adv_ctrl_en = 1;
+ bt_ble_adv_enable(1);
+ } else {
+ if (con_handle) {
+ adv_ctrl_en = 0;
+ ble_disconnect(NULL);
+ } else {
+ bt_ble_adv_enable(0);
+ adv_ctrl_en = 0;
+ }
+ }
+}
+
+
+//流控使能 EN: 1-停止收数 or 0-继续收数
+int ble_trans_flow_enable(u8 en)
+{
+ int ret = -1;
+#if ATT_DATA_RECIEVT_FLOW
+ if (con_handle) {
+ att_server_flow_hold(con_handle, en);
+ ret = 0;
+ }
+#endif
+ log_info("ble_trans_flow_enable:%d,%d\n", en, ret);
+ return ret;
+}
+
+//for test
+static void timer_trans_flow_test(void)
+{
+ static u8 sw = 0;
+ if (con_handle) {
+ sw = !sw;
+ ble_trans_flow_enable(sw);
+ }
+}
+
+static const char ble_ext_name[] = "(BLE)";
+
+extern void ll_sync_init();
+void tecent_ll_init()
+{
+#if LL_TECENT_SUPPORT_TASK
+ tecent_ll_task_init();
+#endif
+ ll_sync_init();
+}
+
+void ble_set_llsync_param()
+{
+ uint8_t adv_type = ADV_IND;
+ uint8_t adv_channel = ADV_CHANNEL_ALL;
+ ble_op_set_adv_param(ADV_INTERVAL_MIN, adv_type, adv_channel);
+}
+
+void bt_ble_init(void)
+{
+ log_info("***** ble_init******\n");
+ char *name_p;
+
+#if DOUBLE_BT_SAME_NAME
+ u8 ext_name_len = 0;
+#else
+ u8 ext_name_len = sizeof(ble_ext_name) - 1;
+#endif
+
+ name_p = bt_get_local_name();
+ gap_device_name_len = strlen(name_p);
+ if (gap_device_name_len > BT_NAME_LEN_MAX - ext_name_len) {
+ gap_device_name_len = BT_NAME_LEN_MAX - ext_name_len;
+ }
+
+ memcpy(gap_device_name, name_p, gap_device_name_len);
+
+#if DOUBLE_BT_SAME_NAME == 0
+ //增加后缀,区分名字
+ memcpy(&gap_device_name[gap_device_name_len], "(BLE)", ext_name_len);
+ gap_device_name_len += ext_name_len;
+#endif
+
+ log_info("ble name(%d): %s \n", gap_device_name_len, gap_device_name);
+
+#if ATT_DATA_RECIEVT_FLOW
+ log_info("att_server_flow_enable\n");
+ att_server_flow_enable(1);
+ /* sys_timer_add(0, timer_trans_flow_test, 3000); */
+#endif
+
+ set_ble_work_state(BLE_ST_INIT_OK);
+ tecent_ll_init();
+#if 0
+ ble_module_enable(1);
+#else
+ /* ble_profile_init(); */
+ ble_set_llsync_param();
+ ble_qiot_advertising_start();
+#endif
+
+#if TEST_SEND_DATA_RATE
+ server_timer_start();
+#endif
+}
+
+void bt_ble_exit(void)
+{
+ log_info("***** ble_exit******\n");
+
+ ble_qiot_advertising_stop();
+
+#if TEST_SEND_DATA_RATE
+ server_timer_stop();
+#endif
+
+}
+
+
+void ble_app_disconnect(void)
+{
+ ble_disconnect(NULL);
+}
+
+#if RCSP_BTMATE_EN
+static int rcsp_send_user_data_do(void *priv, u8 *data, u16 len)
+{
+ log_info("rcsp_tx:%x\n", len);
+#if PRINT_DMA_DATA_EN
+ if (len < 128) {
+ log_info("-dma_tx(%d):");
+ log_info_hexdump(data, len);
+ } else {
+ putchar('L');
+ }
+#endif
+ return app_send_user_data(ATT_CHARACTERISTIC_ae02_02_VALUE_HANDLE, data, len, ATT_OP_AUTO_READ_CCC);
+}
+#endif
+
+#if RCSP_BTMATE_EN
+static const struct ble_server_operation_t mi_ble_operation = {
+ .adv_enable = set_adv_enable,
+ .disconnect = ble_disconnect,
+ .get_buffer_vaild = get_buffer_vaild_len,
+ .send_data = (void *)rcsp_send_user_data_do,
+ .regist_wakeup_send = regiest_wakeup_send,
+ .regist_recieve_cbk = regiest_recieve_cbk,
+ .regist_state_cbk = regiest_state_cbk,
+};
+#else
+static const struct ble_server_operation_t mi_ble_operation = {
+ .adv_enable = set_adv_enable,
+ .disconnect = ble_disconnect,
+ .get_buffer_vaild = get_buffer_vaild_len,
+ .send_data = (void *)llsync_app_send_user_data_do,
+ .regist_wakeup_send = regiest_wakeup_send,
+ .regist_recieve_cbk = regiest_recieve_cbk,
+ .regist_state_cbk = regiest_state_cbk,
+};
+#endif
+
+void ble_get_server_operation_table(struct ble_server_operation_t **interface_pt)
+{
+ *interface_pt = (void *)&mi_ble_operation;
+}
+
+void ble_server_send_test_key_num(u8 key_num)
+{
+ ;
+}
+
+#endif
+
+
diff --git a/apps/common/third_party_profile/Tecent_LL/tecent_ll_demo/ll_demo.h b/apps/common/third_party_profile/Tecent_LL/tecent_ll_demo/ll_demo.h
new file mode 100644
index 0000000..b81ace1
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/tecent_ll_demo/ll_demo.h
@@ -0,0 +1,76 @@
+// binary representation
+// attribute size in bytes (16), flags(16), handle (16), uuid (16/128), value(...)
+
+#ifndef _LL_DEMO_H
+#define _LL_DEMO_H
+
+#include
+#include "app_config.h"
+
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_LL_SYNC)
+//
+// gatt profile include file, generated by jieli gatt_inc_generator.exe
+//
+
+const uint8_t profile_data[] = {
+ //////////////////////////////////////////////////////
+ //
+ // 0x0001 PRIMARY_SERVICE 1800
+ //
+ //////////////////////////////////////////////////////
+ 0x0a, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x28, 0x00, 0x18,
+
+ /* CHARACTERISTIC, 2a00, READ | DYNAMIC, */
+ // 0x0002 CHARACTERISTIC 2a00 READ | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x28, 0x02, 0x03, 0x00, 0x00, 0x2a,
+ // 0x0003 VALUE 2a00 READ | DYNAMIC
+ 0x08, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00, 0x2a,
+
+ //////////////////////////////////////////////////////
+ //
+ // 0x0004 PRIMARY_SERVICE 0000FFE0-65D0-4E20-B56A-E493541BA4E2
+ //
+ //////////////////////////////////////////////////////
+ 0x18, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x28, 0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe0, 0xff, 0x00, 0x00,
+
+ /* CHARACTERISTIC, 0000FFE1-65D0-4E20-B56A-E493541BA4E2, WRITE | DYNAMIC, */
+ // 0x0005 CHARACTERISTIC 0000FFE1-65D0-4E20-B56A-E493541BA4E2 WRITE | DYNAMIC
+ 0x1b, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x28, 0x08, 0x06, 0x00, 0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe1, 0xff, 0x00, 0x00,
+ // 0x0006 VALUE 0000FFE1-65D0-4E20-B56A-E493541BA4E2 WRITE | DYNAMIC
+ 0x16, 0x00, 0x08, 0x03, 0x06, 0x00, 0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe1, 0xff, 0x00, 0x00,
+
+ /* CHARACTERISTIC, 0000FFE2-65D0-4E20-B56A-E493541BA4E2, WRITE | DYNAMIC, */
+ // 0x0007 CHARACTERISTIC 0000FFE2-65D0-4E20-B56A-E493541BA4E2 WRITE | DYNAMIC
+ 0x1b, 0x00, 0x02, 0x00, 0x07, 0x00, 0x03, 0x28, 0x08, 0x08, 0x00, 0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe2, 0xff, 0x00, 0x00,
+ // 0x0008 VALUE 0000FFE2-65D0-4E20-B56A-E493541BA4E2 WRITE | DYNAMIC
+ 0x16, 0x00, 0x08, 0x03, 0x08, 0x00, 0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe2, 0xff, 0x00, 0x00,
+
+ /* CHARACTERISTIC, 0000FFE3-65D0-4E20-B56A-E493541BA4E2, NOTIFY, */
+ // 0x0009 CHARACTERISTIC 0000FFE3-65D0-4E20-B56A-E493541BA4E2 NOTIFY
+ 0x1b, 0x00, 0x02, 0x00, 0x09, 0x00, 0x03, 0x28, 0x10, 0x0a, 0x00, 0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe3, 0xff, 0x00, 0x00,
+ // 0x000a VALUE 0000FFE3-65D0-4E20-B56A-E493541BA4E2 NOTIFY
+ 0x16, 0x00, 0x10, 0x02, 0x0a, 0x00, 0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe3, 0xff, 0x00, 0x00,
+ // 0x000b CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x0b, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+ /* CHARACTERISTIC, 0000FFE4-65D0-4E20-B56A-E493541BA4E2, WRITE_WITHOUT_RESPONSE | DYNAMIC, */
+ // 0x000c CHARACTERISTIC 0000FFE4-65D0-4E20-B56A-E493541BA4E2 WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x1b, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x03, 0x28, 0x04, 0x0d, 0x00, 0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe4, 0xff, 0x00, 0x00,
+ // 0x000d VALUE 0000FFE4-65D0-4E20-B56A-E493541BA4E2 WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x16, 0x00, 0x04, 0x03, 0x0d, 0x00, 0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe4, 0xff, 0x00, 0x00,
+
+ // END
+ 0x00, 0x00,
+};
+//
+// characteristics <--> handles
+//
+#define ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE 0x0003
+#define ATT_CHARACTERISTIC_0000FFE1_65D0_4E20_B56A_E493541BA4E2_01_VALUE_HANDLE 0x0006
+#define ATT_CHARACTERISTIC_0000FFE2_65D0_4E20_B56A_E493541BA4E2_01_VALUE_HANDLE 0x0008
+#define ATT_CHARACTERISTIC_0000FFE3_65D0_4E20_B56A_E493541BA4E2_01_VALUE_HANDLE 0x000a
+#define ATT_CHARACTERISTIC_0000FFE3_65D0_4E20_B56A_E493541BA4E2_01_CLIENT_CONFIGURATION_HANDLE 0x000b
+#define ATT_CHARACTERISTIC_0000FFE4_65D0_4E20_B56A_E493541BA4E2_01_VALUE_HANDLE 0x000d
+
+#endif
+#endif
diff --git a/apps/common/third_party_profile/Tecent_LL/tecent_ll_demo/ll_task.c b/apps/common/third_party_profile/Tecent_LL/tecent_ll_demo/ll_task.c
new file mode 100644
index 0000000..ac64d16
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/tecent_ll_demo/ll_task.c
@@ -0,0 +1,61 @@
+#include "ll_task.h"
+#include "os/os_api.h"
+#include "ble_qiot_config.h"
+#include "ble_qiot_service.h"
+#include "ble_qiot_import.h"
+
+LL_PACKET_CONTROL LL_packet_c;
+
+#define __this (&LL_packet_c)
+
+static void tecent_ll_task(void *arg)
+{
+ LL_PACKET_HEAD_T ll_packet_head;
+ u8 *buffer = NULL;
+ u8 result = 0;
+ while (1) {
+ os_sem_pend(&(__this->ll_sem), 0);
+ if (cbuf_get_data_len(&(__this->cbuf)) > LL_PACKET_HEAD_LEN) {
+ cbuf_read(&(__this->cbuf), &ll_packet_head, LL_PACKET_HEAD_LEN);
+ buffer = malloc(ll_packet_head.len);
+ if (buffer == NULL) {
+ printf("buf malloc err\n");
+ break;
+ }
+ cbuf_read(&(__this->cbuf), buffer, ll_packet_head.len);
+ switch (ll_packet_head.packet_channel) {
+ case LL_DEVICE_INFO_MSG_CH:
+ result = ble_device_info_msg_handle(buffer, ll_packet_head.len);
+ break;
+ case LL_DATA_MSG_CH:
+ result = ble_lldata_msg_handle(buffer, ll_packet_head.len);
+ break;
+ case LL_OTA_MSG_CH:
+ result = ble_ota_msg_handle(buffer, ll_packet_head.len);
+ break;
+ }
+ free(buffer);
+ }
+ }
+}
+
+int tecent_ll_task_init(void)
+{
+ os_sem_create(&(__this->ll_sem), 0);
+ u32 malloc_size = (ble_get_user_data_mtu_size() + LL_PACKET_HEAD_LEN) * BLE_QIOT_TOTAL_PACKAGES;
+ __this->tecent_ll_buf = malloc(malloc_size);
+ memset(__this->tecent_ll_buf, 0x0, malloc_size);
+ cbuf_init(&(__this->cbuf), __this->tecent_ll_buf, malloc_size);
+ os_task_create(tecent_ll_task, NULL, 31, 512, 0, "tecent_ll_task");
+ return 0;
+}
+
+void tecent_ll_packet_recieve(void *buf, u16 len)
+{
+ if (cbuf_is_write_able(&(__this->cbuf), len) >= len) {
+ cbuf_write(&(__this->cbuf), buf, len);
+ } else {
+ printf("[L]\n");
+ }
+ os_sem_post(&(__this->ll_sem));
+}
diff --git a/apps/common/third_party_profile/Tecent_LL/tecent_ll_demo/ll_task.h b/apps/common/third_party_profile/Tecent_LL/tecent_ll_demo/ll_task.h
new file mode 100644
index 0000000..85c590f
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/tecent_ll_demo/ll_task.h
@@ -0,0 +1,31 @@
+#ifndef __LL_TASK_H__
+#define __LL_TASK_H__
+
+#include "typedef.h"
+#include "os/os_api.h"
+#include "circular_buf.h"
+
+typedef struct __LL_PACKET_HEAD {
+ u8 packet_channel;
+ u16 len;
+} LL_PACKET_HEAD_T;
+
+typedef struct __LL_PACKET_CONTROL {
+ OS_SEM ll_sem;
+ cbuffer_t cbuf;
+ volatile u8 wait;
+ u8 *tecent_ll_buf;
+} LL_PACKET_CONTROL;
+
+#define LL_PACKET_HEAD_LEN (sizeof(LL_PACKET_HEAD_T))
+
+enum {
+ LL_DEVICE_INFO_MSG_CH = 0,
+ LL_DATA_MSG_CH,
+ LL_OTA_MSG_CH,
+};
+
+int tecent_ll_task_init(void);
+void tecent_ll_packet_recieve(void *buf, u16 len);
+
+#endif //__LL_TASK_H__
diff --git a/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_import.c b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_import.c
new file mode 100644
index 0000000..18a09d4
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_import.c
@@ -0,0 +1,224 @@
+#include "ble_qiot_import.h"
+/* #include "le/ble_api.h" */
+#include "vm.h"
+#include "le_common.h"
+#include "dual_bank_updata_api.h"
+
+#define PRODUCT_ID "YSUM4IEDOH"
+#define DEVICE_NAME "dev001"
+#define SECRET_KEY "6WNLgmVK4fThhVIgdOBmKQ=="
+
+#define LOG_TAG "[ble_qiot_import]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#define ADV_INTERVAL_MIN (160)
+
+static u8 scan_rsp_data[ADV_RSP_PACKET_MAX];//max is 31
+static char d_name[7] = "LLMAIN";
+static u8 d_name_len = 6; //名字长度,不包含结束符
+static u8 ble_work_state = 0; //ble 状态变化
+static u8 adv_ctrl_en; //广播控制
+static u16 protocol_MTU; //广播控制
+
+static u8 adv_data_len;
+static u8 adv_data[ADV_RSP_PACKET_MAX];//max is 31
+static u8 scan_rsp_data_len;
+static u8 scan_rsp_data[ADV_RSP_PACKET_MAX];//max is 31
+
+int ble_get_product_id(char *product_id)
+{
+ log_info("ble_get_product_id");
+ memcpy(product_id, PRODUCT_ID, strlen(PRODUCT_ID));
+ put_buf(product_id, strlen(product_id));
+ return 0;
+}
+
+int ble_get_device_name(char *device_name)
+{
+ log_info("ble_get_device_name");
+ memcpy(device_name, DEVICE_NAME, strlen(DEVICE_NAME));
+ put_buf(device_name, strlen(device_name));
+ return strlen(device_name);
+}
+
+int ble_get_psk(char *psk)
+{
+ log_info("ble_get_psk");
+ memcpy(psk, SECRET_KEY, strlen(SECRET_KEY));
+ put_buf(psk, strlen(psk));
+ return 0;
+}
+
+extern const u8 *ble_get_mac_addr(void);
+int ble_get_mac(char *mac)
+{
+ log_info("ble_get_mac");
+ le_controller_get_mac(mac);
+ put_buf(mac, 6);
+ return 0;
+}
+
+static void (*app_set_adv_data)(u8 *adv_data, u8 adv_len) = NULL;
+static void (*app_set_rsp_data)(u8 *rsp_data, u8 rsp_len) = NULL;
+void app_set_adv_data_register(void (*handler)(u8 *adv_data, u8 adv_len))
+{
+ app_set_adv_data = handler;
+}
+void app_set_rsp_data_register(void (*handler)(u8 *rsp_data, u8 rsp_len))
+{
+ app_set_rsp_data = handler;
+}
+
+static int llsync_set_rsp_data(void)
+{
+ u8 offset = 0;
+ u8 *buf = scan_rsp_data;
+
+ u8 name_len = sizeof(d_name);
+ u8 vaild_len = ADV_RSP_PACKET_MAX - (offset + 2);
+ if (name_len > vaild_len) {
+ name_len = vaild_len;
+ }
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, (void *)d_name, d_name_len);
+
+ if (offset > ADV_RSP_PACKET_MAX) {
+ printf("***rsp_data overflow!!!!!!\n");
+ return -1;
+ }
+
+ //printf("rsp_data(%d):", offset);
+ //printf_buf(buf, offset);
+ scan_rsp_data_len = offset;
+ if (app_set_rsp_data) {
+ app_set_rsp_data(scan_rsp_data, scan_rsp_data_len);
+ }
+ ble_op_set_rsp_data(offset, buf);
+ return 0;
+}
+
+static int llsync_set_adv_data(adv_info_s *adv)
+{
+ u8 offset = 0;
+ u8 *buf = adv_data;
+ u8 manufacturer_buf[20];
+
+ memcpy(&manufacturer_buf[0], &adv->manufacturer_info.company_identifier, 2);
+ memcpy(&manufacturer_buf[2], adv->manufacturer_info.adv_data, adv->manufacturer_info.adv_data_len);
+ printf("manufacturer_buf\n");
+ put_buf(manufacturer_buf, adv->manufacturer_info.adv_data_len + 2);
+
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x06, 1);
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_16BIT_SERVICE_UUIDS, IOT_BLE_UUID_SERVICE, 2);
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_MANUFACTURER_SPECIFIC_DATA, manufacturer_buf, adv->manufacturer_info.adv_data_len + 2);
+
+ if (offset > ADV_RSP_PACKET_MAX) {
+ puts("***adv_data overflow!!!!!!\n");
+ printf("offset = %d, limite is %d\n", offset, ADV_RSP_PACKET_MAX);
+ return -1;
+ }
+
+ //log_info("adv_data(%d):", offset);
+ //log_info_hexdump(buf, offset);
+ adv_data_len = offset;
+ if (app_set_adv_data) {
+ app_set_adv_data(adv_data, adv_data_len);
+ }
+ ble_op_set_adv_data(offset, buf);
+ return 0;
+}
+
+static void (*llsync_ble_module_enable)(u8 en) = NULL;
+ble_qiot_ret_status_t ble_advertising_start(adv_info_s *adv)
+{
+ log_info("ble_advertising_start\n");
+ //log_info_hexdump(adv->manufacturer_info.adv_data, adv->manufacturer_info.adv_data_len);
+
+ llsync_set_adv_data(adv);
+ llsync_set_rsp_data();
+
+ if (llsync_ble_module_enable) {
+ llsync_ble_module_enable(1);
+ }
+ return 0;
+}
+
+void llsync_ble_module_enable_register(void (*handler)(u8 en))
+{
+ llsync_ble_module_enable = handler;
+}
+
+ble_qiot_ret_status_t ble_advertising_stop(void)
+{
+ log_info("ble_advertising_stop\n");
+ if (llsync_ble_module_enable) {
+ llsync_ble_module_enable(0);
+ }
+ return 0;
+}
+
+static int (*llsync_send_data)(void *priv, u8 *data, u16 len) = NULL;
+void llsync_send_data_register(int (*handler)(void *priv, void *buf, u16 len))
+{
+ llsync_send_data = handler;
+}
+
+ble_qiot_ret_status_t ble_send_notify(uint8_t *buf, uint8_t len)
+{
+ if (llsync_send_data) {
+ llsync_send_data(NULL, buf, len);
+ } else {
+ log_info("llsync_send_data no register");
+ }
+ return 0;
+}
+
+uint16_t ble_get_user_data_mtu_size(void)
+{
+ return BLE_QIOT_PACKAGE_LENGTH + 6;
+}
+
+uint8_t ble_ota_is_enable(const char *version, u32 file_size, u32 file_crc)
+{
+ log_info("ota version: %s, enable ota", version);
+ if (dual_bank_passive_update_init(file_crc, file_size, BLE_QIOT_OTA_BUF_SIZE, NULL) == 0) {
+ if (dual_bank_update_allow_check(file_size) == 0) {
+ return BLE_OTA_ENABLE;
+ }
+ }
+ dual_bank_passive_update_exit(NULL);
+ return 0;
+}
+
+extern s32 vm_open(u16 index);
+extern s32 vm_read(vm_hdl hdl, u8 *data_buf, u16 len);
+extern s32 vm_write(vm_hdl hdl, u8 *data_buf, u16 len);
+
+int ble_read_flash(uint32_t flash_addr, char *read_buf, uint16_t read_len)
+{
+ int ret;
+ s32 hdl = vm_open(flash_addr);
+
+ ret = vm_read(hdl, read_buf, read_len);
+ if (ret < 0) {
+ log_info("\n\nread flash error:%d", ret);
+ }
+ return read_len;
+}
+
+int ble_write_flash(uint32_t flash_addr, const char *write_buf, uint16_t write_len)
+{
+ int ret;
+ s32 hdl = vm_open(flash_addr);
+
+ ret = vm_write(hdl, write_buf, write_len);
+ if (ret < 0) {
+ log_info("\n\nwrite flash error:%d", ret);
+ }
+ return write_len;
+}
+
diff --git a/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_data.c b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_data.c
new file mode 100644
index 0000000..5bbe50d
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_data.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//#include
+#include
+#include
+
+#include "ble_qiot_config.h"
+
+#if BLE_QIOT_LLSYNC_STANDARD
+
+#include "ble_qiot_export.h"
+#include "ble_qiot_import.h"
+#include "ble_qiot_common.h"
+#include "ble_qiot_llsync_event.h"
+#include "ble_qiot_utils_base64.h"
+#include "ble_qiot_log.h"
+#include "ble_qiot_param_check.h"
+#include "ble_qiot_service.h"
+#include "ble_qiot_template.h"
+#include "ble_qiot_llsync_data.h"
+
+// parse tlv data and return the length parsed
+int ble_lldata_parse_tlv(const char *buf, int buf_len, e_ble_tlv *tlv)
+{
+ int ret_len = 0;
+ uint16_t type_len = 0;
+
+ tlv->type = BLE_QIOT_PARSE_TLV_HEAD_TYPE(buf[0]);
+ if (tlv->type >= BLE_QIOT_DATA_TYPE_BUTT) {
+ ble_qiot_log_e("lldata parse invalid type: %d", tlv->type);
+ return -1;
+ }
+ tlv->id = BLE_QIOT_PARSE_TLV_HEAD_ID(buf[0]);
+ ret_len++;
+
+ switch (tlv->type) {
+ case BLE_QIOT_DATA_TYPE_BOOL:
+ tlv->len = sizeof(uint8_t);
+ tlv->val = (char *)buf + ret_len;
+ ret_len += sizeof(uint8_t);
+ break;
+ case BLE_QIOT_DATA_TYPE_ENUM:
+ tlv->len = sizeof(uint16_t);
+ tlv->val = (char *)buf + ret_len;
+ ret_len += sizeof(uint16_t);
+ break;
+ case BLE_QIOT_DATA_TYPE_INT:
+ case BLE_QIOT_DATA_TYPE_FLOAT:
+ case BLE_QIOT_DATA_TYPE_TIME:
+ tlv->len = sizeof(uint32_t);
+ tlv->val = (char *)buf + ret_len;
+ ret_len += sizeof(uint32_t);
+ break;
+ case BLE_QIOT_DATA_TYPE_STRUCT:
+ case BLE_QIOT_DATA_TYPE_STRING:
+ if (buf_len < BLE_QIOT_MIN_STRING_TYPE_LEN) {
+ ble_qiot_log_e("lldata len invalid, type: %d, len: %d", tlv->type, buf_len);
+ return -1;
+ }
+ memcpy(&type_len, &buf[ret_len], sizeof(uint16_t));
+ tlv->len = NTOHS(type_len);
+ ret_len += sizeof(uint16_t);
+ tlv->val = (char *)buf + ret_len;
+ ret_len += tlv->len;
+ break;
+ default:
+ break;
+ }
+ ble_qiot_log_d("tlv parsed, type: %d, id: %d, len: %d", tlv->type, tlv->id, tlv->len);
+
+ return ret_len;
+}
+
+// handle property data, method is control or get status
+static ble_qiot_ret_status_t ble_lldata_property_data_handle(bool is_request, const char *in_buf, int buf_len)
+{
+#ifdef BLE_QIOT_INCLUDE_PROPERTY
+ uint16_t parse_len = 0;
+ int ret_len = 0;
+ e_ble_tlv tlv;
+ int8_t ret = BLE_QIOT_REPLY_SUCCESS;
+
+ ble_qiot_ret_status_t inform_ret = BLE_QIOT_RS_OK;
+
+ ble_qiot_log_d("handle property data");
+ while (parse_len < buf_len) {
+ memset(&tlv, 0, sizeof(e_ble_tlv));
+ ret_len = ble_lldata_parse_tlv(in_buf + parse_len, buf_len - parse_len, &tlv);
+ if (ret_len < 0) {
+ return BLE_QIOT_RS_ERR;
+ }
+
+ parse_len += ret_len;
+ if (parse_len > buf_len) {
+ ble_qiot_log_e("invalid peroperty data, %d(property len) > %d(buf len)", parse_len, buf_len);
+ ret = BLE_QIOT_REPLY_DATA_ERR;
+ break;
+ }
+
+ if (BLE_QIOT_RS_OK != ble_user_property_set_data(&tlv)) {
+ ret = BLE_QIOT_REPLY_FAIL;
+ break;
+ }
+ }
+ if (is_request) {
+ return ble_event_notify(BLE_QIOT_EVENT_UP_CONTROL_REPLY, NULL, 0, (const char *)&ret, sizeof(int8_t));
+ } else {
+ return (BLE_QIOT_REPLY_SUCCESS == ret) ? BLE_QIOT_RS_OK : BLE_QIOT_RS_ERR;
+ }
+#else
+ ble_qiot_log_e("property" BLE_QIOT_NOT_SUPPORT_WARN);
+ return BLE_QIOT_RS_OK;
+#endif //BLE_QIOT_INCLUDE_PROPERTY
+}
+
+#ifdef BLE_QIOT_INCLUDE_PROPERTY
+// post property
+ble_qiot_ret_status_t ble_user_property_get_report_data(void)
+{
+ uint8_t property_id = 0;
+ uint8_t property_type = 0;
+ int property_len = 0;
+ uint16_t type_len = 0;
+ uint16_t data_len = 0;
+ uint16_t data_buf_off = 0;
+
+ uint8_t data_buf[BLE_QIOT_EVENT_MAX_SIZE] = {0};
+
+ ble_qiot_log_d("report property");
+ for (property_id = 0; property_id < BLE_QIOT_PROPERTY_ID_BUTT; property_id++) {
+ property_type = ble_get_property_type_by_id(property_id);
+ if (property_type >= BLE_QIOT_DATA_TYPE_BUTT) {
+ ble_qiot_log_e("property(%d) type(%d) invalid", property_id, property_type);
+ return BLE_QIOT_RS_ERR;
+ }
+
+ data_buf[data_len++] = BLE_QIOT_PACKAGE_TLV_HEAD(property_type, property_id);
+ data_buf_off = data_len;
+ if ((BLE_QIOT_DATA_TYPE_STRING == property_type) || (BLE_QIOT_DATA_TYPE_STRUCT == property_type)) {
+ // reserved 2 bytes for string/struct length
+ data_buf_off += BLE_QIOT_STRING_TYPE_LEN;
+ }
+ property_len = ble_user_property_get_data_by_id(property_id, (char *)&data_buf[data_buf_off],
+ sizeof(data_buf) - data_buf_off);
+ if (property_len < 0) {
+ return BLE_QIOT_RS_ERR;
+ } else if (property_len == 0) {
+ // clean the property head cause no data to post
+ data_len--;
+ data_buf[data_len] = '0';
+ ble_qiot_log_d("property: %d no data to post", property_id);
+ } else {
+ if ((BLE_QIOT_DATA_TYPE_STRING == property_type) || (BLE_QIOT_DATA_TYPE_STRUCT == property_type)) {
+ // filling the payload length
+ type_len = HTONS(property_len);
+ memcpy(data_buf + data_len, &type_len, sizeof(uint16_t));
+ data_len += sizeof(uint16_t);
+ }
+ data_len += property_len;
+ }
+ }
+ // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "user data", data_buf, data_len);
+
+ return ble_event_notify(BLE_QIOT_EVENT_UP_PROPERTY_REPORT, NULL, 0, (const char *)data_buf, data_len);
+}
+#endif //BLE_QIOT_INCLUDE_PROPERTY
+
+// handle control
+ble_qiot_ret_status_t ble_lldata_property_request_handle(const char *in_buf, int buf_len)
+{
+ return ble_lldata_property_data_handle(true, in_buf, buf_len);
+}
+
+// handle report_reply
+static ble_qiot_ret_status_t ble_lldata_property_report_reply(const char *in_buf, int buf_len)
+{
+#ifdef BLE_QIOT_INCLUDE_PROPERTY
+ (void)ble_user_property_report_reply_handle(in_buf[0]);
+#else
+ ble_qiot_log_e("property" BLE_QIOT_NOT_SUPPORT_WARN);
+#endif //BLE_QIOT_INCLUDE_PROPERTY
+ return BLE_QIOT_RS_OK;
+}
+
+// handle get_status_reply
+static ble_qiot_ret_status_t ble_lldata_property_get_status_reply(const char *in_buf, int buf_len)
+{
+#ifdef BLE_QIOT_INCLUDE_PROPERTY
+ uint8_t result = 0;
+ uint16_t reply_len = 0;
+
+ result = in_buf[0];
+ ble_qiot_log_d("get status reply result: %d", result);
+ if (BLE_QIOT_REPLY_SUCCESS == result) {
+ memcpy(&reply_len, &in_buf[1], sizeof(uint16_t));
+ return ble_lldata_property_data_handle(false, in_buf + sizeof(uint8_t) + sizeof(uint16_t), NTOHS(reply_len));
+ } else {
+ return BLE_QIOT_RS_ERR;
+ }
+#else
+ ble_qiot_log_e("property" BLE_QIOT_NOT_SUPPORT_WARN);
+ return BLE_QIOT_RS_OK;
+#endif //BLE_QIOT_INCLUDE_PROPERTY
+}
+
+// handle reply from remote
+ble_qiot_ret_status_t ble_lldata_property_reply_handle(uint8_t type, const char *in_buf, int buf_len)
+{
+ switch (type) {
+ case BLE_QIOT_DATA_DOWN_REPORT_REPLY:
+ return ble_lldata_property_report_reply(in_buf, buf_len);
+ case BLE_QIOT_DATA_DOWN_GET_STATUS_REPLY:
+ return ble_lldata_property_get_status_reply(in_buf, buf_len);
+ default:
+ ble_qiot_log_e("invalid property reply type");
+ return BLE_QIOT_RS_ERR;
+ }
+}
+
+// handle event_post_reply
+ble_qiot_ret_status_t ble_lldata_event_handle(uint8_t id, const char *in_buf, int len)
+{
+#ifdef BLE_QIOT_INCLUDE_EVENT
+ (void)ble_user_event_reply_handle(id, in_buf[0]);
+#else
+ ble_qiot_log_e("event" BLE_QIOT_NOT_SUPPORT_WARN);
+#endif //BLE_QIOT_INCLUDE_PROPERTY
+ return BLE_QIOT_RS_OK;
+}
+
+// handle action
+ble_qiot_ret_status_t ble_lldata_action_handle(uint8_t action_id, const char *in_buf, int len)
+{
+#ifdef BLE_QIOT_INCLUDE_ACTION
+ POINTER_SANITY_CHECK(in_buf, BLE_QIOT_RS_ERR_PARA);
+
+ uint16_t parse_len = 0;
+ uint8_t tlv_index = 0;
+ int ret_len = 0;
+ int handle_ret = BLE_QIOT_REPLY_SUCCESS;
+ uint8_t output_id = 0;
+ uint8_t output_type = 0;
+ uint16_t data_len = 0;
+ uint16_t data_buf_off = 0;
+ int output_param_len = 0;
+ uint16_t string_len = 0;
+ uint8_t header_buf[2] = {0};
+
+ e_ble_tlv tlv[BLE_QIOT_ACTION_INPUT_ID_BUTT] = {0};
+ uint8_t output_flag_array[BLE_QIOT_ACTION_OUTPUT_ID_BUTT] = {0}; // set true if the id have output
+ uint8_t data_buf[BLE_QIOT_EVENT_MAX_SIZE] = {0};
+
+ header_buf[0] = BLE_QIOT_REPLY_SUCCESS;
+ header_buf[1] = action_id;
+
+ ble_qiot_log_d("input action: %d", action_id);
+ while (parse_len < len) {
+ if (tlv_index >= BLE_QIOT_ACTION_INPUT_ID_BUTT) {
+ ble_qiot_log_e("invalid action(id: %d) data", action_id);
+ handle_ret = BLE_QIOT_REPLY_DATA_ERR;
+ goto end;
+ }
+ ret_len = ble_lldata_parse_tlv(in_buf + parse_len, len - parse_len, &tlv[tlv_index]);
+ if (ret_len < 0) {
+ handle_ret = BLE_QIOT_REPLY_DATA_ERR;
+ goto end;
+ }
+ parse_len += ret_len;
+ tlv_index++;
+ if (parse_len > len) {
+ ble_qiot_log_e("action data parse failed, parse len: %d > data len: %d", parse_len, len);
+ handle_ret = BLE_QIOT_REPLY_DATA_ERR;
+ goto end;
+ }
+ }
+ if (0 != ble_action_user_handle_input_param(action_id, tlv, tlv_index, output_flag_array)) {
+ handle_ret = BLE_QIOT_REPLY_FAIL;
+ goto end;
+ }
+
+ for (output_id = 0; output_id < BLE_QIOT_ACTION_OUTPUT_ID_BUTT; output_id++) {
+ if (output_flag_array[output_id]) {
+ output_type = ble_action_get_output_type_by_id(action_id, output_id);
+ if (output_type >= BLE_QIOT_DATA_TYPE_BUTT) {
+ ble_qiot_log_e("action id(%d:%d) type invalid", action_id, output_id);
+ handle_ret = BLE_QIOT_REPLY_FAIL;
+ goto end;
+ }
+ data_buf[data_len++] = BLE_QIOT_PACKAGE_TLV_HEAD(output_type, output_id);
+ data_buf_off = data_len;
+ if (BLE_QIOT_DATA_TYPE_STRING == output_type) {
+ data_buf_off += BLE_QIOT_STRING_TYPE_LEN;
+ }
+ output_param_len = ble_action_user_handle_output_param(
+ action_id, output_id, (char *)data_buf + data_buf_off, sizeof(data_buf) - data_buf_off);
+ if (output_param_len < 0) {
+ handle_ret = BLE_QIOT_REPLY_FAIL;
+ goto end;
+ } else if (output_param_len == 0) {
+ // clean the head cause no data to post
+ data_len--;
+ data_buf[data_len] = '0';
+ ble_qiot_log_d("action id(%d: %d) no data to post", action_id, output_id);
+ } else {
+ if (BLE_QIOT_DATA_TYPE_STRING == output_type) {
+ string_len = HTONS(output_param_len);
+ memcpy(data_buf + data_len, &string_len, sizeof(uint16_t));
+ data_len += sizeof(uint16_t);
+ }
+ data_len += output_param_len;
+ }
+ }
+ }
+ // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "user data", data_buf, data_len);
+ return ble_event_notify(BLE_QIOT_EVENT_UP_ACTION_REPLY, header_buf, sizeof(header_buf), (const char *)data_buf,
+ data_len);
+
+end:
+ header_buf[0] = BLE_QIOT_REPLY_FAIL;
+ ble_event_notify(BLE_QIOT_EVENT_UP_ACTION_REPLY, header_buf, sizeof(header_buf), (const char *)&handle_ret,
+ sizeof(uint8_t));
+ return BLE_QIOT_RS_ERR;
+#else
+ ble_qiot_log_e("action" BLE_QIOT_NOT_SUPPORT_WARN);
+ return BLE_QIOT_RS_OK;
+#endif //BLE_QIOT_INCLUDE_PROPERTY
+}
+
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_device.c b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_device.c
new file mode 100644
index 0000000..6ceddb4
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_device.c
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_config.h"
+
+#include
+#include
+#include
+
+#include "ble_qiot_common.h"
+#include "ble_qiot_config.h"
+#include "ble_qiot_export.h"
+#include "ble_qiot_hmac.h"
+#include "ble_qiot_import.h"
+#include "ble_qiot_log.h"
+#include "ble_qiot_param_check.h"
+#include "ble_qiot_utils_base64.h"
+#include "ble_qiot_md5.h"
+#include "ble_qiot_llsync_device.h"
+
+#define BLE_GET_EXPIRATION_TIME(_cur_time) ((_cur_time) + BLE_EXPIRATION_TIME)
+
+static ble_core_data sg_core_data; // ble data storage in flash
+static ble_device_info sg_device_info; // device info storage in flash
+static e_llsync_bind_state sg_llsync_bind_state; // llsync bind state in used
+static e_llsync_connection_state sg_llsync_connection_state; // llsync connection state in used
+static e_ble_connection_state sg_ble_connection_state; // ble connection state in used
+static uint16_t sg_llsync_mtu; // the mtu for llsync slice data
+
+uint16_t llsync_mtu_get(void)
+{
+ // return default mtu if llsync mtu not set
+ if (0 == sg_llsync_mtu) {
+ sg_llsync_mtu = ATT_MTU_TO_LLSYNC_MTU(ATT_DEFAULT_MTU);
+ }
+ return sg_llsync_mtu;
+}
+
+void llsync_mtu_update(uint16_t llsync_mtu)
+{
+ sg_llsync_mtu = llsync_mtu;
+}
+
+void llsync_bind_state_set(e_llsync_bind_state new_state)
+{
+ ble_qiot_log_d("bind state: %d ---> %d", sg_llsync_bind_state, new_state);
+ sg_llsync_bind_state = new_state;
+}
+
+e_llsync_bind_state llsync_bind_state_get(void)
+{
+ return sg_llsync_bind_state;
+}
+
+void llsync_connection_state_set(e_llsync_connection_state new_state)
+{
+ ble_qiot_log_d("llsync state: %d ---> %d", sg_llsync_connection_state, new_state);
+ sg_llsync_connection_state = new_state;
+}
+
+bool llsync_is_connected(void)
+{
+ return sg_llsync_connection_state == E_LLSYNC_CONNECTED;
+}
+
+void ble_connection_state_set(e_ble_connection_state new_state)
+{
+ ble_qiot_log_d("ble state: %d ---> %d", sg_llsync_connection_state, new_state);
+ sg_ble_connection_state = new_state;
+}
+
+bool ble_is_connected(void)
+{
+ return sg_ble_connection_state == E_BLE_CONNECTED;
+}
+
+// [1byte bind state] + [6 bytes mac] + [8bytes identify string]/[10 bytes product id]
+int ble_get_my_broadcast_data(char *out_buf, int buf_len)
+{
+ POINTER_SANITY_CHECK(out_buf, BLE_QIOT_RS_ERR_PARA);
+ BUFF_LEN_SANITY_CHECK(buf_len, BLE_BIND_IDENTIFY_STR_LEN + BLE_QIOT_MAC_LEN + 1, BLE_QIOT_RS_ERR_PARA);
+ int ret_len = 0;
+#if BLE_QIOT_LLSYNC_STANDARD
+ int i = 0;
+ uint8_t md5_in_buf[128] = {0};
+ uint8_t md5_in_len = 0;
+ uint8_t md5_out_buf[MD5_DIGEST_SIZE] = {0};
+
+ out_buf[ret_len++] = llsync_bind_state_get() | (BLE_QIOT_LLSYNC_PROTOCOL_VERSION << LLSYNC_PROTO_VER_BIT);
+ if (E_LLSYNC_BIND_SUCC == llsync_bind_state_get()) {
+ // 1 bytes state + 8 bytes device identify_str + 8 bytes identify_str
+ memcpy((char *)md5_in_buf, sg_device_info.product_id, sizeof(sg_device_info.product_id));
+ md5_in_len += sizeof(sg_device_info.product_id);
+ memcpy((char *)md5_in_buf + md5_in_len, sg_device_info.device_name, strlen(sg_device_info.device_name));
+ md5_in_len += strlen(sg_device_info.device_name);
+ utils_md5(md5_in_buf, md5_in_len, md5_out_buf);
+ for (i = 0; i < MD5_DIGEST_SIZE / 2; i++) {
+ out_buf[i + ret_len] = md5_out_buf[i] ^ md5_out_buf[i + MD5_DIGEST_SIZE / 2];
+ }
+ ret_len += MD5_DIGEST_SIZE / 2;
+ memcpy(out_buf + ret_len, sg_core_data.identify_str, sizeof(sg_core_data.identify_str));
+ ret_len += sizeof(sg_core_data.identify_str);
+ } else
+#endif //BLE_QIOT_LLSYNC_STANDARD
+ {
+#if BLE_QIOT_LLSYNC_CONFIG_NET
+ out_buf[ret_len++] = BLE_QIOT_LLSYNC_PROTOCOL_VERSION;
+#endif // BLE_QIOT_LLSYNC_CONFIG_NET
+ // 1 bytes state + 6 bytes mac + 10 bytes product id
+ memcpy(out_buf + ret_len, sg_device_info.mac, BLE_QIOT_MAC_LEN);
+ ret_len += BLE_QIOT_MAC_LEN;
+ memcpy(out_buf + ret_len, sg_device_info.product_id, sizeof(sg_device_info.product_id));
+ ret_len += sizeof(sg_device_info.product_id);
+ }
+ ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "broadcast", out_buf, ret_len);
+
+ return ret_len;
+}
+
+int ble_inform_mtu_result(const char *result, uint16_t data_len)
+{
+ uint16_t ret = 0;
+
+ memcpy(&ret, result, sizeof(uint16_t));
+ ret = NTOHS(ret);
+ ble_qiot_log_i("mtu setting result: %02x", ret);
+
+ if (LLSYNC_MTU_SET_RESULT_ERR == ret) {
+ return ble_event_sync_mtu(ATT_DEFAULT_MTU);
+ } else if (0 == ret) {
+ return BLE_QIOT_RS_OK;
+ } else {
+ llsync_mtu_update(ATT_MTU_TO_LLSYNC_MTU(ret));
+ return BLE_QIOT_RS_OK;
+ }
+}
+
+#if BLE_QIOT_LLSYNC_STANDARD
+static int memchk(const uint8_t *buf, int len)
+{
+ int i = 0;
+
+ for (i = 0; i < len; i++) {
+ if (buf[i] != 0xFF) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+extern void bt_tws_sync_ll_sync_state();
+static ble_qiot_ret_status_t ble_write_core_data(ble_core_data *core_data)
+{
+ memcpy(&sg_core_data, core_data, sizeof(ble_core_data));
+ if (sizeof(ble_core_data) !=
+ ble_write_flash(BLE_QIOT_RECORD_FLASH_ADDR, (char *)&sg_core_data, sizeof(ble_core_data))) {
+ ble_qiot_log_e("llsync write core failed");
+ return BLE_QIOT_RS_ERR_FLASH;
+ }
+
+#if TCFG_USER_TWS_ENABLE
+ bt_tws_sync_ll_sync_state();
+#endif
+
+ return BLE_QIOT_RS_OK;
+}
+
+int ble_bind_get_authcode(const char *bind_data, uint16_t data_len, char *out_buf, uint16_t buf_len)
+{
+ POINTER_SANITY_CHECK(bind_data, BLE_QIOT_RS_ERR_PARA);
+ BUFF_LEN_SANITY_CHECK(data_len, (int32_t)sizeof(ble_bind_data), BLE_QIOT_RS_ERR_PARA);
+ POINTER_SANITY_CHECK(out_buf, BLE_QIOT_RS_ERR_PARA);
+ BUFF_LEN_SANITY_CHECK(buf_len, SHA1_DIGEST_SIZE + BLE_QIOT_DEVICE_NAME_LEN, BLE_QIOT_RS_ERR_PARA);
+
+ char out_sign[SHA1_DIGEST_SIZE] = {0};
+ char sign_info[80] = {0};
+ int sign_info_len = 0;
+ int time_expiration = 0;
+ int nonce = 0;
+ int ret_len = 0;
+ uint8_t secret[BLE_QIOT_PSK_LEN / 4 * 3] = {0};
+ int secret_len = 0;
+
+ // if the pointer "char *bind_data" is not aligned with 4 byte, in some cpu convert it to
+ // pointer "ble_bind_data *" work correctly, but some cpu will get wrong value, or cause
+ // other "Unexpected Error". Here copy it to a local variable make sure aligned with 4 byte.
+ ble_bind_data bind_data_aligned;
+ memcpy(&bind_data_aligned, bind_data, sizeof(ble_bind_data));
+
+ nonce = NTOHL(bind_data_aligned.nonce);
+ time_expiration = BLE_GET_EXPIRATION_TIME(NTOHL(bind_data_aligned.timestamp));
+
+ // [10 bytes product_id] + [x bytes device name] + ';' + [4 bytes nonce] + ';' + [4 bytes timestamp]
+ memcpy(sign_info, sg_device_info.product_id, sizeof(sg_device_info.product_id));
+ sign_info_len += sizeof(sg_device_info.product_id);
+ memcpy(sign_info + sign_info_len, sg_device_info.device_name, strlen(sg_device_info.device_name));
+ sign_info_len += strlen(sg_device_info.device_name);
+ snprintf(sign_info + sign_info_len, sizeof(sign_info) - sign_info_len, ";%u", nonce);
+ sign_info_len += strlen(sign_info + sign_info_len);
+ snprintf(sign_info + sign_info_len, sizeof(sign_info) - sign_info_len, ";%u", time_expiration);
+ sign_info_len += strlen(sign_info + sign_info_len);
+
+ qcloud_iot_utils_base64decode(secret, sizeof(secret), (size_t *)&secret_len,
+ (const unsigned char *)sg_device_info.psk, sizeof(sg_device_info.psk));
+ ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "bind sign in", sign_info, sign_info_len);
+ utils_hmac_sha1((const char *)sign_info, sign_info_len, out_sign, (const char *)secret, secret_len);
+ ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "bind sign out", out_sign, sizeof(out_sign));
+
+ // return [20 bytes sign] + [x bytes device_name]
+ memset(out_buf, 0, buf_len);
+ memcpy(out_buf, out_sign, SHA1_DIGEST_SIZE);
+ ret_len = SHA1_DIGEST_SIZE;
+
+ memcpy(out_buf + ret_len, sg_device_info.device_name, strlen(sg_device_info.device_name));
+ ret_len += strlen(sg_device_info.device_name);
+ ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "bind auth code", out_buf, ret_len);
+
+ return ret_len;
+}
+
+ble_qiot_ret_status_t ble_bind_write_result(const char *result, uint16_t len)
+{
+ POINTER_SANITY_CHECK(result, BLE_QIOT_RS_ERR_PARA);
+ BUFF_LEN_SANITY_CHECK(len, (int32_t)sizeof(ble_core_data), BLE_QIOT_RS_ERR_PARA);
+
+ ble_core_data *bind_result = (ble_core_data *)result;
+
+ llsync_bind_state_set((e_llsync_bind_state)bind_result->bind_state);
+ return ble_write_core_data(bind_result);
+}
+
+ble_qiot_ret_status_t ble_unbind_write_result(void)
+{
+ ble_core_data bind_result;
+
+ llsync_connection_state_set(E_LLSYNC_DISCONNECTED);
+ llsync_bind_state_set(E_LLSYNC_BIND_IDLE);
+ memset(&bind_result, 0, sizeof(bind_result));
+ return ble_write_core_data(&bind_result);
+}
+
+int ble_conn_get_authcode(const char *conn_data, uint16_t data_len, char *out_buf, uint16_t buf_len)
+{
+ POINTER_SANITY_CHECK(conn_data, BLE_QIOT_RS_ERR_PARA);
+ BUFF_LEN_SANITY_CHECK(data_len, (int32_t)sizeof(ble_conn_data), BLE_QIOT_RS_ERR_PARA);
+ POINTER_SANITY_CHECK(out_buf, BLE_QIOT_RS_ERR_PARA);
+ BUFF_LEN_SANITY_CHECK(buf_len, SHA1_DIGEST_SIZE + BLE_QIOT_DEVICE_NAME_LEN, BLE_QIOT_RS_ERR_PARA);
+
+ char sign_info[64] = {0};
+ char out_sign[SHA1_DIGEST_SIZE] = {0};
+ int sign_info_len = 0;
+ int timestamp = 0;
+ int ret_len = 0;
+
+ // if the pointer "char *bind_data" is not aligned with 4 byte, in some cpu convert it to
+ // pointer "ble_bind_data *" work correctly, but some cpu will get wrong value, or cause
+ // other "Unexpected Error". Here copy it to a local variable make sure aligned with 4 byte.
+ ble_conn_data conn_data_aligned;
+ memcpy(&conn_data_aligned, conn_data, sizeof(ble_conn_data));
+
+ // valid sign
+ timestamp = NTOHL(conn_data_aligned.timestamp);
+ snprintf(sign_info + sign_info_len, sizeof(sign_info) - sign_info_len, "%d", timestamp);
+ sign_info_len = strlen(sign_info + sign_info_len);
+ ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "valid sign in", sign_info, sign_info_len);
+ utils_hmac_sha1(sign_info, sign_info_len, out_sign, sg_core_data.local_psk, sizeof(sg_core_data.local_psk));
+ ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "valid sign out", out_sign, SHA1_DIGEST_SIZE);
+ if (0 != memcmp(&conn_data_aligned.sign_info, out_sign, SHA1_DIGEST_SIZE)) {
+ ble_qiot_log_e("llsync invalid connect sign");
+ return BLE_QIOT_RS_VALID_SIGN_ERR;
+ }
+
+ // calc sign
+ memset(sign_info, 0, sizeof(sign_info));
+ sign_info_len = 0;
+
+ // expiration time + product id + device name
+ timestamp = BLE_GET_EXPIRATION_TIME(NTOHL(conn_data_aligned.timestamp));
+ snprintf(sign_info + sign_info_len, sizeof(sign_info) - sign_info_len, "%d", timestamp);
+ sign_info_len += strlen(sign_info + sign_info_len);
+ memcpy(sign_info + sign_info_len, sg_device_info.product_id, sizeof(sg_device_info.product_id));
+ sign_info_len += sizeof(sg_device_info.product_id);
+ memcpy(sign_info + sign_info_len, sg_device_info.device_name, strlen(sg_device_info.device_name));
+ sign_info_len += strlen(sg_device_info.device_name);
+
+ ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "conn sign in", sign_info, sign_info_len);
+ utils_hmac_sha1(sign_info, sign_info_len, out_sign, sg_core_data.local_psk, sizeof(sg_core_data.local_psk));
+ ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "conn sign out", out_sign, sizeof(out_sign));
+
+ // return authcode
+ memset(out_buf, 0, buf_len);
+ memcpy(out_buf, out_sign, SHA1_DIGEST_SIZE);
+ ret_len += SHA1_DIGEST_SIZE;
+ memcpy(out_buf + ret_len, sg_device_info.device_name, strlen(sg_device_info.device_name));
+ ret_len += strlen(sg_device_info.device_name);
+ ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "conn auth code", out_buf, ret_len);
+
+ return ret_len;
+}
+
+int ble_unbind_get_authcode(const char *unbind_data, uint16_t data_len, char *out_buf, uint16_t buf_len)
+{
+ POINTER_SANITY_CHECK(unbind_data, BLE_QIOT_RS_ERR_PARA);
+ BUFF_LEN_SANITY_CHECK(data_len, (int32_t)sizeof(ble_unbind_data), BLE_QIOT_RS_ERR_PARA);
+ POINTER_SANITY_CHECK(out_buf, BLE_QIOT_RS_ERR_PARA);
+ BUFF_LEN_SANITY_CHECK(buf_len, SHA1_DIGEST_SIZE, BLE_QIOT_RS_ERR_PARA);
+
+ char sign_info[32] = {0};
+ char out_sign[SHA1_DIGEST_SIZE] = {0};
+ int sign_info_len = 0;
+ int ret_len = 0;
+
+ // valid sign
+ memcpy(sign_info, BLE_UNBIND_REQUEST_STR, BLE_UNBIND_REQUEST_STR_LEN);
+ sign_info_len = BLE_UNBIND_REQUEST_STR_LEN;
+ utils_hmac_sha1(sign_info, sign_info_len, out_sign, sg_core_data.local_psk, sizeof(sg_core_data.local_psk));
+ ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "valid sign out", out_sign, SHA1_DIGEST_SIZE);
+
+ if (0 != memcmp(((ble_unbind_data *)unbind_data)->sign_info, out_sign, SHA1_DIGEST_SIZE)) {
+ ble_qiot_log_e("llsync invalid unbind sign");
+ return BLE_QIOT_RS_VALID_SIGN_ERR;
+ }
+
+ // calc sign
+ memset(sign_info, 0, sizeof(sign_info));
+ sign_info_len = 0;
+
+ memcpy(sign_info, BLE_UNBIND_RESPONSE, strlen(BLE_UNBIND_RESPONSE));
+ sign_info_len += BLE_UNBIND_RESPONSE_STR_LEN;
+ utils_hmac_sha1(sign_info, sign_info_len, out_sign, sg_core_data.local_psk, sizeof(sg_core_data.local_psk));
+ ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "unbind auth code", out_sign, SHA1_DIGEST_SIZE);
+
+ memset(out_buf, 0, buf_len);
+ memcpy(out_buf, out_sign, sizeof(out_sign));
+ ret_len += sizeof(out_sign);
+
+ return ret_len;
+}
+
+#endif
+
+ble_qiot_ret_status_t ble_init_flash_data(void)
+{
+#if BLE_QIOT_LLSYNC_STANDARD
+ if (sizeof(sg_core_data) !=
+ ble_read_flash(BLE_QIOT_RECORD_FLASH_ADDR, (char *)&sg_core_data, sizeof(sg_core_data))) {
+ ble_qiot_log_e("llsync read flash failed");
+ return BLE_QIOT_RS_ERR_FLASH;
+ }
+ if (0 == memchk((const uint8_t *)&sg_core_data, sizeof(sg_core_data))) {
+ memset(&sg_core_data, 0, sizeof(sg_core_data));
+ }
+
+ if (0 != ble_get_psk(sg_device_info.psk)) {
+ ble_qiot_log_e("llsync get secret key failed");
+ return BLE_QIOT_RS_ERR_FLASH;
+ }
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+ if (0 != ble_get_mac(sg_device_info.mac)) {
+ ble_qiot_log_e("llsync get mac failed");
+ return BLE_QIOT_RS_ERR_FLASH;
+ }
+ if (0 != ble_get_product_id(sg_device_info.product_id)) {
+ ble_qiot_log_e("llsync get product id failed");
+ return BLE_QIOT_RS_ERR_FLASH;
+ }
+ if (0 == ble_get_device_name(sg_device_info.device_name)) {
+ ble_qiot_log_e("llsync get device name failed");
+ return BLE_QIOT_RS_ERR_FLASH;
+ }
+
+#if BLE_QIOT_LLSYNC_STANDARD
+ llsync_bind_state_set((e_llsync_bind_state)sg_core_data.bind_state);
+ // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "core_data", (char *)&sg_core_data, sizeof(sg_core_data));
+ // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "device_info", (char *)&sg_device_info, sizeof(sg_device_info));
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+ return BLE_QIOT_RS_OK;
+}
+
+
+
+void ll_sync_state_deal(void *_data, u16 len)
+{
+ ble_core_data data;
+
+ memcpy(&data, _data, len);
+
+ if (data.bind_state == E_LLSYNC_BIND_SUCC) {
+ //g_printf("bind ok\n");
+ ble_bind_write_result((u8 *)&data, len);
+ } else if (data.bind_state == E_LLSYNC_BIND_WAIT) {
+ //g_printf("bind wait\n");
+ llsync_bind_state_set(E_LLSYNC_BIND_IDLE);
+ } else {
+ //g_printf("no bind \n");
+ ble_unbind_write_result();
+ }
+}
+
+u16 ll_sync_get_core_data(u8 *data)
+{
+ if (sizeof(ble_core_data) > 20) {
+ ASSERT(0, "DATA ERROR\n");
+ }
+ memcpy(data, &sg_core_data, sizeof(ble_core_data));
+ return sizeof(ble_core_data);
+}
+
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_event.c b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_event.c
new file mode 100644
index 0000000..5163a1e
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_event.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_config.h"
+
+//#include
+#include
+
+#include "ble_qiot_import.h"
+#include "ble_qiot_common.h"
+#include "ble_qiot_param_check.h"
+#include "ble_qiot_service.h"
+#include "ble_qiot_template.h"
+#include "ble_qiot_llsync_device.h"
+#include "ble_qiot_llsync_event.h"
+
+// report device info
+ble_qiot_ret_status_t ble_event_report_device_info(void)
+{
+ char device_info[56] = {0}; // 1 byte llsync proto version + 2 bytes mtu size + 1 byte length of develop version
+ uint16_t mtu_size = 0;
+
+#if BLE_QIOT_REMOTE_SET_MTU
+ mtu_size = LLSYNC_MTU_SET_MASK;
+#endif //BLE_QIOT_REMOTE_SET_MTU
+ mtu_size |= ble_get_user_data_mtu_size();
+ mtu_size = HTONS(mtu_size);
+ device_info[0] = BLE_QIOT_LLSYNC_PROTOCOL_VERSION;
+ memcpy(&device_info[1], &mtu_size, sizeof(mtu_size));
+#if BLE_QIOT_LLSYNC_CONFIG_NET
+ device_info[3] = (char)ble_get_device_name(&device_info[4]);
+#else
+ device_info[3] = (char)strlen(BLE_QIOT_USER_DEVELOPER_VERSION);
+ memcpy(&device_info[4], BLE_QIOT_USER_DEVELOPER_VERSION, device_info[3]);
+#endif //BLE_QIOT_LLSYNC_CONFIG_NET
+ return ble_event_notify(BLE_QIOT_EVENT_UP_REPORT_MTU, NULL, 0, device_info, 4 + device_info[3]);
+}
+
+// sync mtu
+ble_qiot_ret_status_t ble_event_sync_mtu(uint16_t att_mtu)
+{
+ uint16_t mtu_size = 0;
+
+ mtu_size = ATT_MTU_TO_LLSYNC_MTU(att_mtu);
+ llsync_mtu_update(mtu_size);
+ mtu_size = HTONS(mtu_size);
+ return ble_event_notify(BLE_QIOT_EVENT_UP_SYNC_MTU, NULL, 0, (const char *)&mtu_size, sizeof(uint16_t));
+}
+
+ble_qiot_ret_status_t ble_event_notify2(uint8_t type, uint8_t length_flag, uint8_t *header, uint8_t header_len,
+ const char *buf, uint16_t buf_len)
+{
+ char *p = (char *)buf;
+ uint16_t left_len = buf_len;
+ uint16_t send_len = 0;
+ uint16_t mtu_size = 0;
+ uint8_t slice_state = BLE_QIOT_EVENT_NO_SLICE;
+ uint16_t send_buf_index = 0;
+ uint16_t tmp_len = 0;
+
+ uint8_t send_buf[BLE_QIOT_EVENT_BUF_SIZE] = {0};
+
+ if (!llsync_is_connected() && type != BLE_QIOT_EVENT_UP_BIND_SIGN_RET && type != BLE_QIOT_EVENT_UP_CONN_SIGN_RET &&
+ type != BLE_QIOT_EVENT_UP_UNBIND_SIGN_RET && type != BLE_QIOT_EVENT_UP_SYNC_WAIT_TIME) {
+ ble_qiot_log_e("upload msg negate, device not connected");
+ return BLE_QIOT_RS_ERR;
+ }
+
+ // reserve event header length, 3 bytes fixed length + n bytes header
+ mtu_size = llsync_mtu_get();
+ mtu_size = mtu_size > sizeof(send_buf) ? sizeof(send_buf) : mtu_size;
+ mtu_size -= (BLE_QIOT_EVENT_FIXED_HEADER_LEN + header_len);
+ // ble_qiot_log_d("mtu size %d", mtu_size);
+
+ do {
+ memset(send_buf, 0, sizeof(send_buf));
+ send_buf_index = 0;
+ send_len = left_len > mtu_size ? mtu_size : left_len;
+
+ send_buf[send_buf_index++] = type;
+ if (NULL != buf) {
+ tmp_len = HTONS(send_len + header_len);
+ memcpy(send_buf + send_buf_index, &tmp_len, sizeof(uint16_t));
+ send_buf_index += sizeof(uint16_t);
+ if (NULL != header) {
+ memcpy(send_buf + send_buf_index, header, header_len);
+ send_buf_index += header_len;
+ }
+ memcpy(send_buf + send_buf_index, p, send_len);
+ send_buf_index += send_len;
+
+ p += send_len;
+ left_len -= send_len;
+ send_len += (BLE_QIOT_EVENT_FIXED_HEADER_LEN + header_len);
+
+ if (0 == left_len) {
+ slice_state =
+ (BLE_QIOT_EVENT_NO_SLICE == slice_state) ? BLE_QIOT_EVENT_NO_SLICE : BLE_QIOT_EVENT_SLICE_FOOT;
+ } else {
+ slice_state =
+ (BLE_QIOT_EVENT_NO_SLICE == slice_state) ? BLE_QIOT_EVENT_SLICE_HEAD : BLE_QIOT_EVENT_SLICE_BODY;
+ }
+ // the high 2 bits means slice state, and the left 14 bits is data length
+ send_buf[1] |= slice_state << 6;
+ send_buf[1] |= length_flag;
+ } else {
+ send_len = send_buf_index;
+ }
+
+ ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "post data", (char *)send_buf, send_len);
+ if (0 != ble_send_notify(send_buf, send_len)) {
+ ble_qiot_log_e("event(type: %d) post failed, len: %d", type, send_len);
+ return BLE_QIOT_RS_ERR;
+ }
+ } while (left_len != 0);
+
+ return BLE_QIOT_RS_OK;
+}
+
+ble_qiot_ret_status_t ble_event_notify(uint8_t type, uint8_t *header, uint8_t header_len, const char *buf,
+ uint16_t buf_len)
+{
+ return ble_event_notify2(type, 0, header, header_len, buf, buf_len);
+}
+
+#if BLE_QIOT_LLSYNC_CONFIG_NET
+ble_qiot_ret_status_t ble_event_report_wifi_mode(uint8_t result)
+{
+ return ble_event_notify(BLE_QIOT_EVENT_UP_WIFI_MODE, NULL, 0, (const char *)&result, sizeof(uint8_t));
+}
+
+ble_qiot_ret_status_t ble_event_report_wifi_info(uint8_t result)
+{
+ return ble_event_notify(BLE_QIOT_EVENT_UP_WIFI_INFO, NULL, 0, (const char *)&result, sizeof(uint8_t));
+}
+
+ble_qiot_ret_status_t ble_event_report_wifi_connect(BLE_WIFI_MODE mode, BLE_WIFI_STATE state, uint8_t ssid_len,
+ const char *ssid)
+{
+ char buf[40] = {0};
+ uint8_t pos = 0;
+
+ buf[pos++] = mode;
+ buf[pos++] = state;
+ buf[pos++] = 0;
+ buf[pos++] = ssid_len;
+ memcpy(buf + pos, ssid, ssid_len);
+
+ return ble_event_notify(BLE_QIOT_EVENT_UP_WIFI_CONNECT, NULL, 0, (const char *)buf, pos + ssid_len);
+}
+
+ble_qiot_ret_status_t ble_event_report_wifi_token(uint8_t result)
+{
+ return ble_event_notify(BLE_QIOT_EVENT_UP_WIFI_TOKEN, NULL, 0, (const char *)&result, sizeof(uint8_t));
+}
+
+ble_qiot_ret_status_t ble_event_report_wifi_log(const uint8_t *log, uint16_t log_size)
+{
+ return ble_event_notify(BLE_QIOT_EVENT_UP_WIFI_LOG, NULL, 0, (const char *)log, log_size);
+}
+#endif //BLE_QIOT_LLSYNC_CONFIG_NET
+
+#if BLE_QIOT_LLSYNC_STANDARD
+// get_status
+ble_qiot_ret_status_t ble_event_get_status(void)
+{
+#ifdef BLE_QIOT_INCLUDE_PROPERTY
+ return ble_event_notify(BLE_QIOT_EVENT_UP_GET_STATUS, NULL, 0, NULL, 0);
+#else
+ ble_qiot_log_e("property" BLE_QIOT_NOT_SUPPORT_WARN);
+ return BLE_QIOT_RS_OK;
+#endif
+}
+
+// report
+ble_qiot_ret_status_t ble_event_report_property(void)
+{
+#ifdef BLE_QIOT_INCLUDE_PROPERTY
+ return ble_user_property_get_report_data();
+#else
+ ble_qiot_log_e("property" BLE_QIOT_NOT_SUPPORT_WARN);
+ return BLE_QIOT_RS_OK;
+#endif
+}
+
+#if BLE_QIOT_SECURE_BIND
+ble_qiot_ret_status_t ble_event_sync_wait_time(void)
+{
+ uint16_t time = BLE_QIOT_BIND_WAIT_TIME;
+
+ time = HTONS(time);
+ return ble_event_notify(BLE_QIOT_EVENT_UP_SYNC_WAIT_TIME, NULL, 0, (const char *)&time, sizeof(uint16_t));
+}
+#endif //BLE_QIOT_SECURE_BIND
+
+ble_qiot_ret_status_t ble_event_post(uint8_t event_id)
+{
+#ifdef BLE_QIOT_INCLUDE_EVENT
+ uint8_t param_id = 0;
+ uint8_t param_id_size = 0;
+ uint8_t param_type = 0;
+ int param_len = 0;
+ uint16_t data_len = 0;
+ uint16_t data_buf_off = 0;
+ uint16_t string_len = 0;
+ uint8_t header_buf = {0};
+
+ uint8_t data_buf[BLE_QIOT_EVENT_MAX_SIZE] = {0};
+
+ ble_qiot_log_d("post event: %d", event_id);
+ param_id_size = ble_event_get_id_array_size(event_id);
+ // get all data
+ for (param_id = 0; param_id < param_id_size; param_id++) {
+ param_type = ble_event_get_param_id_type(event_id, param_id);
+ if (param_type >= BLE_QIOT_DATA_TYPE_BUTT) {
+ ble_qiot_log_e("invalid event(%d:%d) type", event_id, param_id);
+ return BLE_QIOT_RS_ERR;
+ }
+
+ data_buf[data_len++] = BLE_QIOT_PACKAGE_TLV_HEAD(param_type, param_id);
+ data_buf_off = data_len;
+ if (BLE_QIOT_DATA_TYPE_STRING == param_type) {
+ // reserved 2 bytes for string type, other type have fixed length
+ data_buf_off += BLE_QIOT_STRING_TYPE_LEN;
+ }
+ param_len = ble_event_get_data_by_id(event_id, param_id, (char *)data_buf + data_buf_off,
+ sizeof(data_buf) - data_buf_off);
+ if (param_len < 0) {
+ return BLE_QIOT_RS_ERR;
+ } else if (param_len == 0) {
+ // clean the header cause no data to post
+ data_len--;
+ data_buf[data_len] = '0';
+ ble_qiot_log_d("event(%d: %d) no data to post", event_id, param_id);
+ } else {
+ if (BLE_QIOT_DATA_TYPE_STRING == param_type) {
+ string_len = HTONS(param_len);
+ memcpy(data_buf + data_len, &string_len, sizeof(uint16_t));
+ data_len += sizeof(uint16_t);
+ }
+ data_len += param_len;
+ }
+ }
+ header_buf = event_id;
+
+ return ble_event_notify(BLE_QIOT_EVENT_UP_EVENT_POST, &header_buf, sizeof(header_buf), (const char *)data_buf,
+ data_len);
+#else
+ ble_qiot_log_e("event" BLE_QIOT_NOT_SUPPORT_WARN);
+ return BLE_QIOT_RS_OK;
+#endif //BLE_QIOT_INCLUDE_EVENT
+}
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_ota.c b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_ota.c
new file mode 100644
index 0000000..767b7d8
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_ota.c
@@ -0,0 +1,621 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_config.h"
+
+#if BLE_QIOT_LLSYNC_STANDARD
+//#include
+#include
+#include
+
+#include "ble_qiot_export.h"
+#include "ble_qiot_import.h"
+#include "ble_qiot_common.h"
+#include "ble_qiot_llsync_data.h"
+#include "ble_qiot_llsync_event.h"
+#include "ble_qiot_utils_base64.h"
+#include "ble_qiot_crc.h"
+#include "ble_qiot_log.h"
+#include "ble_qiot_param_check.h"
+#include "ble_qiot_service.h"
+#include "ble_qiot_template.h"
+#include "ble_qiot_llsync_ota.h"
+#include "dual_bank_updata_api.h"
+#include "timer.h"
+#include "os/os_api.h"
+#include "update_loader_download.h"
+#include "app_config.h"
+
+#if BLE_QIOT_SUPPORT_OTA
+static ble_ota_user_callback sg_ota_user_cb; // user callback
+// 1. monitor the data and request from the server if data lost; 2. call the user function if no data for a long time
+static int sg_ota_timer = 0;
+static uint8_t sg_ota_timeout_cnt = 0; // count the number of no data times
+static uint8_t sg_ota_data_buf[BLE_QIOT_OTA_BUF_SIZE] = {0}; // storage ota data and write to the flash at once
+static uint16_t sg_ota_data_buf_size = 0; // the data size in the buffer
+static uint32_t sg_ota_download_file_size = 0; // the data size download from the server
+static uint8_t sg_ota_next_seq = 0; // the next expect seq
+static uint32_t sg_ota_download_address = 0; // the address saved ota file
+static uint8_t sg_ota_download_percent = 0; // the percent of file had download
+static uint8_t sg_ota_flag = 0; // ota control info
+static ble_ota_info_record sg_ota_info; // the ota info storage in flash if support resuming
+static ble_ota_reply_t sg_ota_reply_info; // record the last reply info
+
+static OS_SEM sg_ota_sem;
+
+static update_op_tws_api_t *sg_ota_tws_same_api = NULL;
+static u8 pkt_flag = PKT_FLAG_FIRST;
+
+#define BLE_QIOT_OTA_FLAG_SET(_BIT) (sg_ota_flag |= (_BIT));
+#define BLE_QIOT_OTA_FLAG_CLR(_BIT) (sg_ota_flag &= ~(_BIT));
+#define BLE_QIOT_OTA_FLAG_IS_SET(_BIT) ((sg_ota_flag & (_BIT)) == (_BIT))
+
+uint32_t ble_ota_get_download_addr(void)
+{
+ return 0;
+}
+
+static inline bool ble_qiot_ota_info_valid(void)
+{
+ return sg_ota_info.valid_flag == BLE_QIOT_OTA_PAGE_VALID_VAL;
+}
+static inline uint8_t ble_ota_next_seq_get(void)
+{
+ return sg_ota_next_seq;
+}
+static inline void ble_ota_next_seq_inc(void)
+{
+ sg_ota_next_seq++;
+}
+static inline uint32_t ble_ota_download_address_get(void)
+{
+ return sg_ota_download_address;
+}
+static inline void ble_ota_download_address_set(void)
+{
+ sg_ota_download_address = ble_ota_get_download_addr();
+ return;
+}
+static inline uint32_t ble_ota_download_size_get(void)
+{
+ return sg_ota_download_file_size;
+}
+static inline void ble_ota_download_size_inc(uint32_t size)
+{
+ sg_ota_download_file_size += size;
+}
+static inline uint8_t ble_ota_file_percent_get(void)
+{
+ return sg_ota_download_percent;
+}
+static inline void ble_ota_file_percent_set(uint8_t percent)
+{
+ sg_ota_download_percent = percent;
+}
+
+int ble_ota_write_flash(uint32_t flash_addr, const char *write_buf, uint16_t write_len)
+{
+ return sg_ota_data_buf_size;
+}
+
+void ble_ota_callback_reg(ble_ota_start_callback start_cb, ble_ota_stop_callback stop_cb,
+ ble_ota_valid_file_callback valid_file_cb)
+{
+ sg_ota_user_cb.start_cb = start_cb;
+ sg_ota_user_cb.stop_cb = stop_cb;
+ sg_ota_user_cb.valid_file_cb = valid_file_cb;
+}
+static inline void ble_ota_user_start_cb(void)
+{
+ if (NULL != sg_ota_user_cb.start_cb) {
+ ble_qiot_log_i("start callback begin");
+ sg_ota_user_cb.start_cb();
+ ble_qiot_log_i("start callback end");
+ }
+}
+static inline void ble_ota_user_stop_cb(uint8_t result)
+{
+ if (NULL != sg_ota_user_cb.stop_cb) {
+ ble_qiot_log_i("stop callback begin");
+ sg_ota_user_cb.stop_cb(result);
+ ble_qiot_log_i("stop callback end");
+ }
+}
+static inline ble_qiot_ret_status_t ble_ota_user_valid_cb(void)
+{
+ if (NULL != sg_ota_user_cb.valid_file_cb) {
+ ble_qiot_log_i("valid callback begin");
+ return sg_ota_user_cb.valid_file_cb(sg_ota_info.download_file_info.file_size,
+ (char *)sg_ota_info.download_file_info.file_version);
+ }
+ return BLE_QIOT_RS_OK;
+}
+static inline ble_qiot_ret_status_t ble_ota_write_info(void)
+{
+#if BLE_QIOT_SUPPORT_RESUMING
+ sg_ota_info.valid_flag = BLE_QIOT_OTA_PAGE_VALID_VAL;
+ sg_ota_info.last_file_size = ble_ota_download_size_get();
+ sg_ota_info.last_address = ble_ota_download_address_get();
+ if (sizeof(ble_ota_info_record) !=
+ ble_write_flash(BLE_QIOT_OTA_INFO_FLASH_ADDR, (const char *)&sg_ota_info, sizeof(ble_ota_info_record))) {
+ ble_qiot_log_e("write ota info failed");
+ return BLE_QIOT_RS_ERR;
+ }
+#endif //BLE_QIOT_SUPPORT_RESUMING
+ return BLE_QIOT_RS_OK;
+}
+static inline void ble_ota_clear_info(void)
+{
+#if BLE_QIOT_SUPPORT_RESUMING
+ sg_ota_info.valid_flag = ~BLE_QIOT_OTA_PAGE_VALID_VAL;
+ if (sizeof(ble_ota_info_record) !=
+ ble_write_flash(BLE_QIOT_OTA_INFO_FLASH_ADDR, (const char *)&sg_ota_info, sizeof(ble_ota_info_record))) {
+ ble_qiot_log_e("clear ota info failed");
+ }
+#endif //BLE_QIOT_SUPPORT_RESUMING
+ return;
+}
+static inline ble_qiot_ret_status_t ble_ota_reply_ota_data(void)
+{
+ uint8_t req = ble_ota_next_seq_get();
+ uint32_t file_size = ble_ota_download_size_get();
+
+ printf("used old file size %x, req %d", file_size, req);
+ if (sg_ota_reply_info.file_size != file_size) {
+ sg_ota_reply_info.file_size = file_size;
+ sg_ota_reply_info.req = req;
+ } else {
+ // in the case that the device reply info missed, the timer reply info again but the seq increased, so we need
+ // saved the last reply info and used in the time
+ req = sg_ota_reply_info.req;
+ }
+
+ file_size = HTONL(file_size);
+ return ble_event_notify(BLE_QIOT_EVENT_UP_REPLY_OTA_DATA, &req, sizeof(uint8_t), (const char *)&file_size,
+ sizeof(uint32_t));
+}
+static inline ble_qiot_ret_status_t ble_ota_report_check_result(uint8_t firmware_valid, uint8_t error_code)
+{
+ uint8_t result = firmware_valid | error_code;
+ return ble_event_notify(BLE_QIOT_EVENT_UP_REPORT_CHECK_RESULT, NULL, 0, (const char *)&result, sizeof(uint8_t));
+}
+static inline void ble_ota_timer_delete(void)
+{
+ if (NULL == sg_ota_timer) {
+ ble_qiot_log_e("ble ota timer invalid, delete failed");
+ return;
+ }
+
+ sys_timer_del(sg_ota_timer);
+ /* if (BLE_QIOT_RS_OK != ble_timer_delete(sg_ota_timer)) { */
+ /* ble_qiot_log_e("ble ota timer delete failed"); */
+ /* } */
+ sg_ota_timer = 0;
+ return;
+}
+
+static int ble_ota_write_end_callback(void *priv)
+{
+ os_sem_post(&sg_ota_sem);
+ return 0;
+}
+
+static ble_qiot_ret_status_t ble_ota_write_data_to_flash(void)
+{
+ int ret = 0;
+ int write_addr = 0;
+
+ // the download size include the data size, so the write address exclude the data size
+ //os_time_dly(10);
+ /* g_printf("%s\n", __func__); */
+ dual_bank_update_write((const char *)sg_ota_data_buf, sg_ota_data_buf_size, ble_ota_write_end_callback);
+ os_sem_pend(&sg_ota_sem, 0);
+
+#if OTA_TWS_SAME_TIME_ENABLE
+ if (pkt_flag != PKT_FLAG_FIRST) {
+ if (sg_ota_tws_same_api && sg_ota_tws_same_api->tws_ota_data_send_pend) {
+ if (sg_ota_tws_same_api->tws_ota_data_send_pend()) {
+ printf("pend timeout\n");
+ return BLE_QIOT_RS_ERR;
+ }
+ }
+ }
+ if (sg_ota_tws_same_api && sg_ota_tws_same_api->tws_ota_data_send) {
+ sg_ota_tws_same_api->tws_ota_data_send(sg_ota_data_buf, sg_ota_data_buf_size);
+ }
+
+ pkt_flag = PKT_FLAG_MIDDLE;
+#endif
+
+#if 0
+ write_addr = ble_ota_download_address_get() + ble_ota_download_size_get() - sg_ota_data_buf_size;
+ ret = ble_ota_write_flash(write_addr, (const char *)sg_ota_data_buf, sg_ota_data_buf_size);
+ if (ret != sg_ota_data_buf_size) {
+ ble_qiot_log_e("ota data write flash failed");
+ return BLE_QIOT_RS_ERR;
+ }
+#endif
+ return BLE_QIOT_RS_OK;
+}
+static void ble_ota_timer_callback(void *param)
+{
+ if (BLE_QIOT_OTA_FLAG_IS_SET(BLE_QIOT_OTA_RECV_DATA_BIT)) {
+ BLE_QIOT_OTA_FLAG_CLR(BLE_QIOT_OTA_RECV_DATA_BIT);
+ return;
+ }
+ sg_ota_timeout_cnt++;
+
+ ble_qiot_log_w("reply in the timer, count: %d", sg_ota_timeout_cnt);
+ ble_ota_reply_ota_data();
+
+ if (sg_ota_timeout_cnt >= BLE_QIOT_OTA_MAX_RETRY_COUNT) {
+ sg_ota_flag = 0;
+ ble_ota_timer_delete();
+ // inform the user ota failed because timeout
+#if BLE_QIOT_SUPPORT_OTA
+ ble_ota_stop();
+#endif //BLE_QIOT_SUPPORT_OTA
+ ble_ota_user_stop_cb(BLE_QIOT_OTA_ERR_TIMEOUT);
+ }
+}
+static inline void ble_ota_timer_start(void)
+{
+ if (NULL == sg_ota_timer) {
+ sg_ota_timer = sys_timer_add(NULL, ble_ota_timer_callback, BLE_QIOT_RETRY_TIMEOUT * 1000);
+ /* sg_ota_timer = ble_timer_create(BLE_TIMER_PERIOD_TYPE, ble_ota_timer_callback); */
+ /* if (NULL == sg_ota_timer) { */
+ /* ble_qiot_log_e("ble ota timer create failed"); */
+ /* return; */
+ /* } */
+ }
+ /* if (BLE_QIOT_RS_OK != ble_timer_start(sg_ota_timer, BLE_QIOT_RETRY_TIMEOUT * 1000)) { */
+ /* ble_qiot_log_e("ble ota timer start failed"); */
+ /* } */
+ return;
+}
+static ble_qiot_ret_status_t ble_ota_init(void)
+{
+ uint32_t size_align = 0;
+ uint8_t file_percent = 0;
+
+ // init the ota env
+ memset(sg_ota_data_buf, 0, sizeof(sg_ota_data_buf));
+ sg_ota_data_buf_size = 0;
+ sg_ota_timeout_cnt = 0;
+ memset(&sg_ota_info, 0, sizeof(ble_ota_info_record));
+ sg_ota_download_file_size = 0;
+ sg_ota_next_seq = 0;
+ sg_ota_download_percent = 0;
+ sg_ota_flag = 0;
+ ble_ota_download_address_set();
+ memset(&sg_ota_reply_info, 0, sizeof(sg_ota_reply_info));
+
+#if BLE_QIOT_SUPPORT_RESUMING
+ // start from 0 if read flash fail, but ota will continue so ignored the return code
+ ble_read_flash(BLE_QIOT_OTA_INFO_FLASH_ADDR, (char *)&sg_ota_info, sizeof(sg_ota_info));
+ ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "ota info", &sg_ota_info, sizeof(sg_ota_info));
+ // check if the valid flag legalled
+ if (ble_qiot_ota_info_valid()) {
+ // the ota info write to flash may be mismatch the file write to flash, we should download file from the byte
+ // align the flash page
+ if (ble_ota_download_address_get() == sg_ota_info.last_address) {
+ size_align = sg_ota_info.last_file_size / BLE_QIOT_RECORD_FLASH_PAGESIZE * BLE_QIOT_RECORD_FLASH_PAGESIZE;
+ ble_ota_download_size_inc(size_align);
+ file_percent = size_align * 100 / sg_ota_info.download_file_info.file_size;
+ ble_ota_file_percent_set(file_percent);
+ ble_qiot_log_i("align file size: %x, the percent: %d", size_align, file_percent);
+ } else {
+ memset(&sg_ota_info, 0, sizeof(ble_ota_info_record));
+ }
+ } else {
+ memset(&sg_ota_info, 0, sizeof(ble_ota_info_record));
+ }
+#endif //BLE_QIOT_SUPPORT_RESUMING
+ return BLE_QIOT_RS_OK;
+}
+// stop ota if ble disconnect
+void ble_ota_stop(void)
+{
+ if (!BLE_QIOT_OTA_FLAG_IS_SET(BLE_QIOT_OTA_REQUEST_BIT)) {
+ ble_qiot_log_w("ota not start");
+ return;
+ }
+ sg_ota_flag = 0;
+ set_ota_status(0);
+ ble_ota_timer_delete();
+ // write data to flash if the ota stop
+ ble_ota_write_data_to_flash();
+ ble_ota_write_info();
+ dual_bank_passive_update_exit(NULL);
+#if OTA_TWS_SAME_TIME_ENABLE
+ if (sg_ota_tws_same_api && sg_ota_tws_same_api->tws_ota_err) {
+ sg_ota_tws_same_api->tws_ota_err(0);
+ }
+#endif
+ // inform user ota failed because ble disconnect
+ ble_ota_user_stop_cb(BLE_QIOT_OTA_DISCONNECT);
+}
+
+ble_qiot_ret_status_t ble_ota_request_handle(const char *in_buf, int buf_len)
+{
+ BUFF_LEN_SANITY_CHECK(buf_len, sizeof(ble_ota_file_info) - BLE_QIOT_OTA_MAX_VERSION_STR, BLE_QIOT_RS_ERR_PARA);
+
+ uint8_t ret = 0;
+ uint8_t reply_flag = 0;
+ uint32_t file_size = 0;
+ uint32_t file_crc = 0;
+ uint8_t version_len = 0;
+ char *p = (char *)in_buf;
+ char *notify_data = NULL;
+ uint16_t notify_len = 0;
+ ble_ota_reply_info ota_reply_info;
+
+ ble_ota_init();
+
+ memcpy(&file_size, p, sizeof(file_size));
+ p += sizeof(file_size);
+ memcpy(&file_crc, p, sizeof(file_crc));
+ p += sizeof(file_crc);
+ version_len = *p++;
+ file_size = NTOHL(file_size);
+ file_crc = NTOHL(file_crc);
+ ble_qiot_log_i("request ota, size: %x, crc: %x, version: %s", file_size, file_crc, p);
+
+ // check if the ota is allowed
+ ret = ble_ota_is_enable((const char *)p, file_size, file_crc);
+ if (ret == BLE_OTA_ENABLE) {
+#if OTA_TWS_SAME_TIME_ENABLE
+ sg_ota_tws_same_api = get_tws_update_api();
+ if (sg_ota_tws_same_api == NULL) {
+ ret = 0;
+ } else {
+ if (sg_ota_tws_same_api && sg_ota_tws_same_api->tws_ota_start) {
+ struct __tws_ota_para tws_update_para;
+ tws_update_para.fm_size = file_size;
+ tws_update_para.fm_crc = file_crc;
+ tws_update_para.max_pkt_len = BLE_QIOT_OTA_BUF_SIZE;
+ if (sg_ota_tws_same_api->tws_ota_start(&tws_update_para) != 0) { //tws same time err
+ ret = 0;
+ }
+ }
+ }
+#endif
+ }
+
+ if (BLE_OTA_ENABLE == ret) {
+ reply_flag = BLE_QIOT_OTA_ENABLE;
+ ota_reply_info.package_nums = BLE_QIOT_TOTAL_PACKAGES;
+ ota_reply_info.package_size = BLE_QIOT_PACKAGE_LENGTH + BLE_QIOT_OTA_DATA_HEADER_LEN;
+ ota_reply_info.retry_timeout = BLE_QIOT_RETRY_TIMEOUT;
+ ota_reply_info.reboot_timeout = BLE_QIOT_REBOOT_TIME;
+ ota_reply_info.last_file_size = 0;
+ ota_reply_info.package_interval = BLE_QIOT_PACKAGE_INTERVAL;
+#if BLE_QIOT_SUPPORT_RESUMING
+ reply_flag |= BLE_QIOT_OTA_RESUME_ENABLE;
+ // check file crc to determine its the same file, download the new file if its different
+ if (ble_qiot_ota_info_valid() && (file_crc == sg_ota_info.download_file_info.file_crc) &&
+ (file_size == sg_ota_info.download_file_info.file_size)) {
+ ota_reply_info.last_file_size = HTONL(ble_ota_download_size_get());
+ }
+#endif //BLE_QIOT_SUPPORT_RESUMING
+
+ sg_ota_info.download_file_info.file_size = file_size;
+ sg_ota_info.download_file_info.file_crc = file_crc;
+ memcpy(sg_ota_info.download_file_info.file_version, p, version_len);
+
+ ble_ota_user_start_cb();
+ ble_ota_timer_start();
+ // handler the ota data after ota request
+ BLE_QIOT_OTA_FLAG_SET(BLE_QIOT_OTA_REQUEST_BIT);
+ notify_data = (char *)&ota_reply_info;
+ notify_len = sizeof(ble_ota_reply_info) - sizeof(ota_reply_info.rsv);
+
+ os_sem_create(&sg_ota_sem, 0);
+ } else {
+ reply_flag &= ~BLE_QIOT_OTA_ENABLE;
+ notify_data = (char *)&ret;
+ notify_len = sizeof(uint8_t);
+ }
+ return ble_event_notify(BLE_QIOT_EVENT_UP_REPLY_OTA_REPORT, &reply_flag, sizeof(uint8_t), (const char *)notify_data,
+ notify_len);
+}
+
+/* static int ble_ota_verify_result_hdl(int calc_crc){ */
+/* os_sem_post(&sg_ota_sem); */
+/* return 0; */
+/* } */
+// call the function after the server inform or the device receive the last package
+static void ble_ota_reboot_timer(void *priv)
+{
+ cpu_reset();
+}
+
+static int ble_ota_write_boot_info_callback(int err)
+{
+#if OTA_TWS_SAME_TIME_ENABLE
+ if (sg_ota_tws_same_api && sg_ota_tws_same_api->tws_ota_result_hdl) {
+ sg_ota_tws_same_api->tws_ota_result_hdl(err);
+ }
+#else
+ if (err == 0) {
+ sys_timeout_add(NULL, ble_ota_reboot_timer, 500);
+ }
+#endif
+ return 0;
+}
+
+ble_qiot_ret_status_t ble_ota_file_end_handle(void)
+{
+ int crc_buf_len = 0;
+ uint32_t crc_file_len = 0;
+ uint32_t crc = 0;
+ int slave_boot_info_state = 0;
+ // the function called only once in the same ota process
+ sg_ota_flag = 0;
+ ble_ota_timer_delete();
+
+ ble_qiot_log_i("calc crc start");
+
+ /* u32 dual_bank_update_read_data(u32 offset, u8 *read_buf, u32 read_len); */
+ while (crc_file_len < sg_ota_info.download_file_info.file_size) {
+ crc_buf_len = sizeof(sg_ota_data_buf) > (sg_ota_info.download_file_info.file_size - crc_file_len)
+ ? (sg_ota_info.download_file_info.file_size - crc_file_len)
+ : sizeof(sg_ota_data_buf);
+ memset(sg_ota_data_buf, 0, sizeof(sg_ota_data_buf));
+ dual_bank_update_read_data(ble_ota_download_address_get() + crc_file_len, (char *)sg_ota_data_buf, crc_buf_len);
+ crc_file_len += crc_buf_len;
+ crc = ble_qiot_crc32(crc, (const uint8_t *)sg_ota_data_buf, crc_buf_len);
+ // maybe need task delay
+ }
+
+ ble_qiot_log_i("calc crc %x, file crc %x", crc, sg_ota_info.download_file_info.file_crc);
+
+#if OTA_TWS_SAME_TIME_ENABLE
+ if (sg_ota_tws_same_api && sg_ota_tws_same_api->enter_verfiy_hdl) {
+ if (sg_ota_tws_same_api->enter_verfiy_hdl(NULL)) { //slave verify err
+ crc = 0;
+ }
+ }
+#endif
+
+ if (crc == sg_ota_info.download_file_info.file_crc) {
+#if OTA_TWS_SAME_TIME_ENABLE
+ if (sg_ota_tws_same_api && sg_ota_tws_same_api->exit_verify_hdl) {
+ u8 update_boot_info_flag, verify_err;
+ if (sg_ota_tws_same_api->exit_verify_hdl(&verify_err, &update_boot_info_flag) == 0) { //slave write boot_info err
+ slave_boot_info_state = 1;
+ }
+ }
+#endif
+ if (BLE_QIOT_RS_OK == ble_ota_user_valid_cb() && !slave_boot_info_state) {
+ dual_bank_update_burn_boot_info(ble_ota_write_boot_info_callback);
+ int ret = ble_ota_report_check_result(BLE_QIOT_OTA_VALID_SUCCESS, 0);
+ ble_ota_user_stop_cb(BLE_QIOT_OTA_SUCCESS);
+ } else {
+ ble_ota_report_check_result(BLE_QIOT_OTA_VALID_FAIL, BLE_QIOT_OTA_FILE_ERROR);
+ ble_ota_user_stop_cb(BLE_QIOT_OTA_ERR_FILE);
+ }
+ } else {
+ ble_ota_report_check_result(BLE_QIOT_OTA_VALID_FAIL, BLE_QIOT_OTA_CRC_ERROR);
+ ble_ota_user_stop_cb(BLE_QIOT_OTA_ERR_CRC);
+ }
+ ble_ota_clear_info();
+ return BLE_QIOT_RS_OK;
+}
+
+static ble_qiot_ret_status_t ble_qiot_ota_data_saved(char *data, uint16_t data_len)
+{
+ int ret = 0;
+ uint8_t percent = 0;
+
+ // write data to flash if the buffer overflow
+ if ((data_len + sg_ota_data_buf_size) > sizeof(sg_ota_data_buf)) {
+ // ble_qiot_log_e("data buf overflow, write data");
+ if (BLE_QIOT_RS_OK != ble_ota_write_data_to_flash()) {
+ return BLE_QIOT_RS_ERR;
+ }
+ // update the ota info if support resuming
+ percent = (ble_ota_download_size_get() + sg_ota_data_buf_size) * 100 / sg_ota_info.download_file_info.file_size;
+ if (percent > ble_ota_file_percent_get()) {
+ ble_ota_file_percent_set(percent);
+ ret = ble_ota_write_info();
+ if (ret != BLE_QIOT_RS_OK) {
+ ble_qiot_log_e("update ota info failed");
+ return BLE_QIOT_RS_ERR;
+ }
+ }
+ memset(sg_ota_data_buf, 0, sizeof(sg_ota_data_buf));
+ sg_ota_data_buf_size = 0;
+ }
+
+ memcpy(sg_ota_data_buf + sg_ota_data_buf_size, data, data_len);
+ sg_ota_data_buf_size += data_len;
+ ble_ota_download_size_inc(data_len);
+
+ // if the last package, write to flash and reply the server
+ if (ble_ota_download_size_get() == sg_ota_info.download_file_info.file_size) {
+ ble_qiot_log_i("receive the last package");
+ if (BLE_QIOT_RS_OK != ble_ota_write_data_to_flash()) {
+ return BLE_QIOT_RS_ERR;
+ }
+ ble_ota_reply_ota_data();
+ // set the file receive end bit
+ BLE_QIOT_OTA_FLAG_SET(BLE_QIOT_OTA_RECV_END_BIT);
+ memset(sg_ota_data_buf, 0, sizeof(sg_ota_data_buf));
+ sg_ota_data_buf_size = 0;
+ }
+
+ return BLE_QIOT_RS_OK;
+}
+
+ble_qiot_ret_status_t ble_ota_data_handle(const char *in_buf, int buf_len)
+{
+ POINTER_SANITY_CHECK(in_buf, BLE_QIOT_RS_ERR_PARA);
+
+ uint8_t seq = 0;
+ char *data = NULL;
+ uint16_t data_len = 0;
+
+ if (!BLE_QIOT_OTA_FLAG_IS_SET(BLE_QIOT_OTA_REQUEST_BIT)) {
+ ble_qiot_log_w("ota request is need first");
+ return BLE_QIOT_RS_ERR;
+ }
+
+ seq = in_buf[0];
+ data = (char *)in_buf + 1;
+ data_len = (uint16_t)buf_len - 1;
+
+ // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_ERR, "data", in_buf, buf_len);
+ if (seq == ble_ota_next_seq_get()) {
+ BLE_QIOT_OTA_FLAG_SET(BLE_QIOT_OTA_RECV_DATA_BIT);
+ BLE_QIOT_OTA_FLAG_SET(BLE_QIOT_OTA_FIRST_RETRY_BIT);
+ sg_ota_timeout_cnt = 0;
+ ble_ota_next_seq_inc();
+
+ if (BLE_QIOT_RS_OK != ble_qiot_ota_data_saved(data, data_len)) {
+ // stop ota and inform the server
+ ble_qiot_log_e("stop ota because save data failed");
+ return BLE_QIOT_RS_ERR;
+ }
+ if (BLE_QIOT_OTA_FLAG_IS_SET(BLE_QIOT_OTA_RECV_END_BIT)) {
+ return BLE_QIOT_RS_OK;
+ }
+ // reply the server if received the last package in the loop
+ if (BLE_QIOT_TOTAL_PACKAGES == ble_ota_next_seq_get()) {
+ ble_qiot_log_e("reply loop");
+ ble_ota_reply_ota_data();
+ sg_ota_next_seq = 0;
+ }
+ BLE_QIOT_OTA_FLAG_SET(BLE_QIOT_OTA_RECV_DATA_BIT);
+ } else {
+ // request data only once in the loop, controlled by the flag
+ ble_qiot_log_w("unexpect seq %d, expect seq %d", seq, ble_ota_next_seq_get());
+ if (BLE_QIOT_OTA_FLAG_IS_SET(BLE_QIOT_OTA_FIRST_RETRY_BIT)) {
+ BLE_QIOT_OTA_FLAG_CLR(BLE_QIOT_OTA_FIRST_RETRY_BIT);
+ BLE_QIOT_OTA_FLAG_CLR(BLE_QIOT_OTA_RECV_DATA_BIT);
+ ble_ota_reply_ota_data();
+ // refresh the timer
+ ble_ota_timer_start();
+ }
+ }
+ return BLE_QIOT_RS_OK;
+}
+#endif //BLE_QIOT_SUPPORT_OTA
+
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_service.c b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_service.c
new file mode 100644
index 0000000..e475c5c
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_service.c
@@ -0,0 +1,664 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+
+#include "ble_qiot_config.h"
+
+#include "ble_qiot_export.h"
+#include "ble_qiot_import.h"
+#include "ble_qiot_llsync_data.h"
+#include "ble_qiot_llsync_device.h"
+#include "ble_qiot_llsync_event.h"
+#include "ble_qiot_log.h"
+#include "ble_qiot_llsync_ota.h"
+#include "ble_qiot_param_check.h"
+#include "ble_qiot_service.h"
+#include "ble_qiot_template.h"
+#include "ble_qiot_service.h"
+#include "ble_qiot_crc.h"
+#include "asm/clock.h"
+#include "app_config.h"
+#include "update_loader_download.h"
+#include "os/os_api.h"
+
+#define BLE_QIOT_OTA_HZ (120 * 1000000L)
+
+// llsync support data fragment, so we need to package all the data before parsing if the data is slice
+static ble_event_slice_t sg_ble_slice_data;
+
+#if BLE_QIOT_BUTTON_BROADCAST
+static ble_timer_t sg_bind_timer = NULL;
+#endif //BLE_QIOT_BUTTON_BROADCAST
+
+#if BLE_QIOT_SECURE_BIND
+static ble_bind_data sg_bind_auth_data;
+#endif //BLE_QIOT_SECURE_BIND
+
+static qiot_service_init_s service_info = {
+ .service_uuid16 = IOT_BLE_UUID_SERVICE,
+ .service_uuid128 = IOT_BLE_UUID_BASE,
+ .device_info =
+ {
+ .uuid16 = IOT_BLE_UUID_DEVICE_INFO,
+ .gatt_char_props = GATT_CHAR_WRITE,
+ .on_write = ble_device_info_write_cb,
+ },
+ .event =
+ {
+ .uuid16 = IOT_BLE_UUID_EVENT,
+ .gatt_char_props = GATT_CHAR_NOTIFY,
+ .on_write = NULL,
+ },
+#if BLE_QIOT_LLSYNC_STANDARD
+ .data =
+ {
+ .uuid16 = IOT_BLE_UUID_DATA,
+ .gatt_char_props = GATT_CHAR_WRITE,
+ .on_write = ble_lldata_write_cb,
+ },
+ .ota =
+ {
+ .uuid16 = IOT_BLE_UUID_OTA,
+ .gatt_char_props = GATT_CHAR_WRITE_WO_RESP,
+ .on_write = ble_ota_write_cb,
+ },
+#endif //BLE_QIOT_LLSYNC_STANDARD
+};
+
+const qiot_service_init_s *ble_get_qiot_services(void)
+{
+ return &service_info;
+}
+
+#if BLE_QIOT_LLSYNC_STANDARD
+
+#if BLE_QIOT_SECURE_BIND
+static ble_qiot_ret_status_t ble_secure_bind_handle(const char *data, uint16_t len)
+{
+ memset(&sg_bind_auth_data, 0, sizeof(ble_bind_data));
+ memcpy(&sg_bind_auth_data, data, sizeof(ble_bind_data));
+ ble_event_sync_wait_time();
+ ble_secure_bind_user_cb();
+
+ return BLE_QIOT_RS_OK;
+}
+
+ble_qiot_ret_status_t ble_secure_bind_user_confirm(ble_qiot_secure_bind_t choose)
+{
+ char out_buf[80] = {0};
+ int ret_len = 0;
+ uint8_t flag = 0;
+
+ ble_qiot_log_i("user choose: %d", choose);
+ ret_len = ble_bind_get_authcode(&sg_bind_auth_data, sizeof(ble_bind_data), out_buf, sizeof(out_buf));
+ if (ret_len <= 0) {
+ ble_qiot_log_e("get bind authcode failed");
+ return BLE_QIOT_RS_ERR;
+ }
+ flag = choose << 5;
+ return ble_event_notify2((uint8_t)BLE_QIOT_EVENT_UP_BIND_SIGN_RET, flag, NULL, 0, out_buf, ret_len);
+}
+#endif //BLE_QIOT_SECURE_BIND
+
+void ble_lldata_write_cb(const uint8_t *buf, uint16_t len)
+{
+ (void)ble_lldata_msg_handle((const char *)buf, len);
+}
+
+void ble_ota_write_cb(const uint8_t *buf, uint16_t len)
+{
+ (void)ble_ota_msg_handle((const char *)buf, len);
+}
+
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+#if BLE_QIOT_BUTTON_BROADCAST
+static void ble_bind_timer_callback(void *param)
+{
+ ble_qiot_log_i("timer timeout");
+ if (E_LLSYNC_BIND_WAIT == llsync_bind_state_get()) {
+ ble_advertising_stop();
+ llsync_bind_state_set(E_LLSYNC_BIND_IDLE);
+ ble_qiot_log_i("stop advertising");
+ }
+}
+#endif //BLE_QIOT_BUTTON_BROADCAST
+
+ble_qiot_ret_status_t ble_qiot_advertising_start(void)
+{
+ printf("ble_qiot_advertising_start\n");
+ adv_info_s my_adv_info;
+ uint16_t uuids[1];
+ uint8_t adv_data[32] = {0};
+ uint8_t adv_data_len = 0;
+
+ uuids[0] = IOT_BLE_UUID_SERVICE;
+ my_adv_info.uuid_info.uuid_num = 1;
+ my_adv_info.uuid_info.uuids = uuids;
+
+ if (E_LLSYNC_BIND_IDLE == llsync_bind_state_get()) {
+#if BLE_QIOT_BUTTON_BROADCAST
+ if (NULL == sg_bind_timer) {
+ sg_bind_timer = ble_timer_create(BLE_TIMER_ONE_SHOT_TYPE, ble_bind_timer_callback);
+ if (NULL == sg_bind_timer) {
+ ble_qiot_log_e("create bind timer failed");
+ return BLE_QIOT_RS_ERR;
+ }
+ }
+#endif //BLE_QIOT_BUTTON_BROADCAST
+
+ ble_advertising_stop();
+
+ llsync_bind_state_set(E_LLSYNC_BIND_WAIT);
+ adv_data_len = ble_get_my_broadcast_data((char *)adv_data, sizeof(adv_data));
+ my_adv_info.manufacturer_info.company_identifier = TENCENT_COMPANY_IDENTIFIER;
+ my_adv_info.manufacturer_info.adv_data = adv_data;
+ my_adv_info.manufacturer_info.adv_data_len = adv_data_len;
+ printf("adv_data:");
+ put_buf(adv_data, adv_data_len);
+ ble_advertising_start(&my_adv_info);
+ ble_qiot_log_i("start wait advertising");
+
+#if BLE_QIOT_BUTTON_BROADCAST
+ ble_timer_start(sg_bind_timer, BLE_QIOT_BIND_TIMEOUT);
+#endif //BLE_QIOT_BUTTON_BROADCAST
+ } else if (E_LLSYNC_BIND_WAIT == llsync_bind_state_get()) {
+ ble_advertising_stop();
+ adv_data_len = ble_get_my_broadcast_data((char *)adv_data, sizeof(adv_data));
+ my_adv_info.manufacturer_info.company_identifier = TENCENT_COMPANY_IDENTIFIER;
+ my_adv_info.manufacturer_info.adv_data = adv_data;
+ my_adv_info.manufacturer_info.adv_data_len = adv_data_len;
+ ble_advertising_start(&my_adv_info);
+ ble_qiot_log_i("restart wait advertising");
+
+#if BLE_QIOT_BUTTON_BROADCAST
+ ble_timer_stop(sg_bind_timer);
+ ble_timer_start(sg_bind_timer, BLE_QIOT_BIND_TIMEOUT);
+#endif //BLE_QIOT_BUTTON_BROADCAST
+ } else if (E_LLSYNC_BIND_SUCC == llsync_bind_state_get()) {
+ ble_advertising_stop();
+ adv_data_len = ble_get_my_broadcast_data((char *)adv_data, sizeof(adv_data));
+ my_adv_info.manufacturer_info.company_identifier = TENCENT_COMPANY_IDENTIFIER;
+ my_adv_info.manufacturer_info.adv_data = adv_data;
+ my_adv_info.manufacturer_info.adv_data_len = adv_data_len;
+ ble_advertising_start(&my_adv_info);
+ ble_qiot_log_i("start bind advertising");
+ } else {
+ // do nothing
+ }
+
+ return BLE_QIOT_RS_OK;
+}
+
+ble_qiot_ret_status_t ble_qiot_advertising_stop(void)
+{
+ return 0 == ble_advertising_stop() ? BLE_QIOT_RS_OK : BLE_QIOT_RS_ERR;
+}
+
+ble_qiot_ret_status_t ble_qiot_explorer_init(void)
+{
+ printf("ble_qiot_explorer_init\n");
+ ble_qiot_ret_status_t ret_code = BLE_QIOT_RS_OK;
+ const qiot_service_init_s *service_info = NULL;
+
+ ble_qiot_set_log_level(BLE_QIOT_LOG_LEVEL_INFO);
+
+ service_info = ble_get_qiot_services();
+ //ble_services_add(service_info);
+
+ ret_code = ble_init_flash_data();
+ if (ret_code != BLE_QIOT_RS_OK) {
+ ble_qiot_log_e("flash init failed, ret code %d", ret_code);
+ return ret_code;
+ }
+
+ return ret_code;
+}
+
+void ll_sync_init()
+{
+ ble_qiot_explorer_init();
+#if BLE_QIOT_SUPPORT_OTA && OTA_TWS_SAME_TIME_ENABLE
+ tws_sync_update_crc_handler_register(ble_qiot_crc32_init, ble_qiot_crc32);
+#endif
+}
+
+void ble_device_info_write_cb(const uint8_t *buf, uint16_t len)
+{
+ (void)ble_device_info_msg_handle((const char *)buf, len);
+}
+
+// when gap get ble connect event, use this function
+void ble_gap_connect_cb(void)
+{
+ ble_connection_state_set(E_BLE_CONNECTED);
+}
+
+// when gap get ble disconnect event, use this function
+void ble_gap_disconnect_cb(void)
+{
+ llsync_mtu_update(0);
+ llsync_connection_state_set(E_LLSYNC_DISCONNECTED);
+ ble_connection_state_set(E_BLE_DISCONNECTED);
+#if BLE_QIOT_SUPPORT_OTA
+ ble_ota_stop();
+#endif //BLE_QIOT_SUPPORT_OTA
+}
+
+static uint8_t ble_msg_type_header_len(uint8_t type)
+{
+ if (type == BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE) {
+ return BLE_QIOT_GET_STATUS_REPLY_HEADER_LEN;
+ } else {
+ return BLE_QIOT_DATA_FIXED_HEADER_LEN;
+ }
+}
+
+static int8_t ble_package_slice_data(uint8_t data_type, uint8_t flag, uint8_t header_len, const char *in_buf,
+ int in_len)
+{
+ if (!BLE_QIOT_IS_SLICE_HEADER(flag)) {
+ if (!sg_ble_slice_data.have_data) {
+ ble_qiot_log_e("slice no header");
+ return -1;
+ }
+ if (data_type != sg_ble_slice_data.type) {
+ ble_qiot_log_e("msg type: %d != %d", data_type, sg_ble_slice_data.type);
+ return -1;
+ }
+ if (sg_ble_slice_data.buf_len + (in_len - header_len) > sizeof(sg_ble_slice_data.buf)) {
+ ble_qiot_log_e("too long data: %d > %d", sg_ble_slice_data.buf_len + (in_len - header_len),
+ sizeof(sg_ble_slice_data.buf));
+ return -1;
+ }
+ }
+
+ if (BLE_QIOT_IS_SLICE_HEADER(flag)) {
+ if (sg_ble_slice_data.have_data) {
+ ble_qiot_log_i("new data coming, clean the package buffer");
+ memset(&sg_ble_slice_data, 0, sizeof(sg_ble_slice_data));
+ }
+ sg_ble_slice_data.have_data = true;
+ sg_ble_slice_data.type = data_type;
+ // reserved space for payload length field
+ sg_ble_slice_data.buf_len += header_len;
+ sg_ble_slice_data.buf[0] = in_buf[0];
+ memcpy(sg_ble_slice_data.buf + sg_ble_slice_data.buf_len, in_buf + header_len, in_len - header_len);
+ sg_ble_slice_data.buf_len += (in_len - header_len);
+
+ return 1;
+ } else if (BLE_QIOT_IS_SLICE_BODY(flag)) {
+ memcpy(sg_ble_slice_data.buf + sg_ble_slice_data.buf_len, in_buf + header_len, in_len - header_len);
+ sg_ble_slice_data.buf_len += (in_len - header_len);
+ return 1;
+ } else {
+ memcpy(sg_ble_slice_data.buf + sg_ble_slice_data.buf_len, in_buf + header_len, in_len - header_len);
+ sg_ble_slice_data.buf_len += (in_len - header_len);
+
+ return 0;
+ }
+}
+
+int ble_device_info_msg_handle(const char *in_buf, int in_len)
+{
+ POINTER_SANITY_CHECK(in_buf, BLE_QIOT_RS_ERR_PARA);
+ uint8_t ch;
+ char out_buf[80] = {0};
+ char *p_data = NULL;
+ int p_data_len = 0;
+ int ret_len = 0;
+ uint16_t tmp_len = 0;
+ uint8_t header_len = 0;
+ int ret = BLE_QIOT_RS_OK;
+ char *p_ssid = NULL;
+ char *p_passwd = NULL;
+ // This flag is use to avoid attacker jump "ble_conn_get_authcode()" step, then
+ // send 'E_DEV_MSG_CONN_SUCC' msg, and device straightly set 'E_LLSYNC_CONNECTED' flag.
+ // This behavior make signature check useless lead to risk.
+ static bool conn_flag = false;
+
+ p_data = (char *)in_buf;
+ p_data_len = in_len;
+
+ // E_DEV_MSG_SYNC_TIME, E_DEV_MSG_CONN_VALID, E_DEV_MSG_BIND_SUCC, E_DEV_MSG_UNBIND this 4 type
+ // of message has more than one bytes data, it may cut to several slices, here need to merge them
+ // together, other type message only has 1 byte data, not need merge.
+ if ((in_len > 3) && BLE_QIOT_IS_SLICE_PACKAGE(in_buf[1])) {
+ // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "slice", p_data, p_data_len);
+ header_len = ble_msg_type_header_len(in_buf[0]);
+ ret = ble_package_slice_data(in_buf[0], in_buf[1], header_len, in_buf, in_len);
+ if (ret < 0) {
+ return BLE_QIOT_RS_ERR;
+ } else if (ret == 0) {
+ tmp_len = HTONS(sg_ble_slice_data.buf_len - header_len);
+ memcpy(&sg_ble_slice_data.buf[1], &tmp_len, sizeof(tmp_len));
+ p_data = sg_ble_slice_data.buf;
+ p_data_len = sg_ble_slice_data.buf_len;
+ } else if (ret > 0) {
+ return BLE_QIOT_RS_OK;
+ }
+ }
+ // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "tlv", p_data, p_data_len);
+
+ ch = p_data[0];
+ printf("msg ch = %d\n", ch);
+ switch (ch) {
+#if BLE_QIOT_LLSYNC_STANDARD
+ case E_DEV_MSG_SYNC_TIME:
+#if BLE_QIOT_SECURE_BIND
+ ret = ble_secure_bind_handle(p_data + 3, p_data_len - 3);
+#else
+ ret_len = ble_bind_get_authcode(p_data + 3, p_data_len - 3, out_buf, sizeof(out_buf));
+ if (ret_len <= 0) {
+ ble_qiot_log_e("get bind authcode failed");
+ ret = BLE_QIOT_RS_ERR;
+ break;
+ }
+ ret = ble_event_notify((uint8_t)BLE_QIOT_EVENT_UP_BIND_SIGN_RET, NULL, 0, out_buf, ret_len);
+#endif //BLE_QIOT_SECURE_BIND
+ break;
+ case E_DEV_MSG_CONN_VALID:
+ ret_len = ble_conn_get_authcode(p_data + 3, p_data_len - 3, out_buf, sizeof(out_buf));
+ if (ret_len <= 0) {
+ ble_qiot_log_e("get connect authcode failed");
+ ret = BLE_QIOT_RS_ERR;
+ break;
+ }
+ ret = ble_event_notify((uint8_t)BLE_QIOT_EVENT_UP_CONN_SIGN_RET, NULL, 0, out_buf, ret_len);
+ conn_flag = true;
+ break;
+ case E_DEV_MSG_BIND_SUCC:
+ if (BLE_QIOT_RS_OK != ble_bind_write_result(p_data + 3, p_data_len - 3)) {
+ ble_qiot_log_e("write bind result failed");
+ ret = BLE_QIOT_RS_ERR;
+ }
+ break;
+ case E_DEV_MSG_BIND_FAIL:
+ ble_qiot_log_i("get msg bind fail");
+ break;
+ case E_DEV_MSG_UNBIND:
+ ret_len = ble_unbind_get_authcode(p_data + 3, p_data_len - 3, out_buf, sizeof(out_buf));
+ if (ret_len <= 0) {
+ ble_qiot_log_e("get unbind authcode failed");
+ ret = BLE_QIOT_RS_ERR;
+ break;
+ }
+ ret = ble_event_notify((uint8_t)BLE_QIOT_EVENT_UP_UNBIND_SIGN_RET, NULL, 0, out_buf, ret_len);
+ break;
+ case E_DEV_MSG_CONN_SUCC:
+ if (!conn_flag) {
+ break;
+ }
+ conn_flag = false;
+ ble_qiot_log_i("get msg connect success");
+ llsync_connection_state_set(E_LLSYNC_CONNECTED);
+ ret = ble_event_report_device_info();
+ //llsync_device_state_sync();
+ break;
+ case E_DEV_MSG_CONN_FAIL:
+ ble_qiot_log_i("get msg connect fail");
+ break;
+ case E_DEV_MSG_UNBIND_SUCC:
+ ble_qiot_log_i("get msg unbind success");
+ if (BLE_QIOT_RS_OK != ble_unbind_write_result()) {
+ ble_qiot_log_e("write unbind result failed");
+ ret = BLE_QIOT_RS_ERR;
+ }
+ break;
+ case E_DEV_MSG_UNBIND_FAIL:
+ ble_qiot_log_i("get msg unbind fail");
+ break;
+ case E_DEV_MSG_BIND_TIMEOUT:
+ ble_qiot_log_i("get msg bind result: %d", p_data[1]);
+#if (1 == BLE_QIOT_SECURE_BIND)
+ ble_secure_bind_user_notify(p_data[1]);
+#endif
+ break;
+#endif //BLE_QIOT_LLSYNC_STANDARD
+#if BLE_QIOT_LLSYNC_CONFIG_NET
+ case E_DEV_MSG_GET_DEV_INFO:
+ llsync_connection_state_set(E_LLSYNC_CONNECTED);
+ ret = ble_event_report_device_info();
+ break;
+ case E_DEV_MSG_SET_WIFI_MODE:
+ ret = ble_combo_wifi_mode_set(p_data[1]);
+ break;
+ case E_DEV_MSG_SET_WIFI_INFO:
+ // 1 byte ssid len + N bytes ssid + 1 byte pwd len + N bytes pwd
+ p_ssid = &p_data[3];
+ p_passwd = &p_ssid[p_ssid[0] + 1];
+ ret = ble_combo_wifi_info_set((const char *)&p_ssid[1], p_ssid[0], (const char *)&p_passwd[1], p_passwd[0]);
+ break;
+ case E_DEV_MSG_SET_WIFI_CONNECT:
+ ret = ble_combo_wifi_connect();
+ break;
+ case E_DEV_MSG_SET_WIFI_TOKEN:
+ ret = ble_combo_wifi_token_set(p_data + 3, p_data_len - 3);
+ break;
+ case E_DEV_MSG_GET_DEV_LOG:
+ ret = ble_combo_wifi_log_get();
+ break;
+#endif
+ case E_DEV_MSG_SET_MTU_RESULT:
+ ble_inform_mtu_result(p_data + 1, p_data_len - 1);
+ llsync_device_state_sync();
+ break;
+ default:
+ ble_qiot_log_e("unknow type %d", ch);
+ break;
+ }
+ memset(&sg_ble_slice_data, 0, sizeof(sg_ble_slice_data));
+
+ return ret;
+}
+
+#if BLE_QIOT_LLSYNC_STANDARD
+// lldata message from remote
+int ble_lldata_msg_handle(const char *in_buf, int in_len)
+{
+ POINTER_SANITY_CHECK(in_buf, BLE_QIOT_RS_ERR_PARA);
+
+ uint8_t data_type = 0;
+ uint8_t data_effect = 0;
+ uint8_t id = 0;
+ uint8_t slice_flag = 0;
+ uint8_t header_len = 0;
+ uint8_t slice_type = 0;
+ uint16_t tmp_len = 0;
+ char *p_data = NULL;
+ int p_data_len = 0;
+ int ret = 0;
+
+ if (!llsync_is_connected()) {
+ ble_qiot_log_e("operation negate, device not connected");
+ return BLE_QIOT_RS_ERR;
+ }
+
+ p_data = (char *)in_buf;
+ p_data_len = in_len;
+
+ data_type = BLE_QIOT_PARSE_MSG_HEAD_TYPE(in_buf[0]);
+ if (data_type >= BLE_QIOT_DATA_TYPE_BUTT) {
+ ble_qiot_log_e("invalid data type: %d", data_type);
+ return BLE_QIOT_RS_ERR;
+ }
+ data_effect = BLE_QIOT_PARSE_MSG_HEAD_EFFECT(in_buf[0]);
+ if (data_effect >= BLE_QIOT_EFFECT_BUTT) {
+ ble_qiot_log_e("invalid data eff: ect");
+ return BLE_QIOT_RS_ERR;
+ }
+ id = BLE_QIOT_PARSE_MSG_HEAD_ID(in_buf[0]);
+ ble_qiot_log_d("data type: %d, effect: %d, id: %d", data_type, data_effect, id);
+
+ // if data is action_reply, control or get_status_reply, the data maybe need package
+ if ((data_type == BLE_QIOT_MSG_TYPE_ACTION) || (in_buf[0] == BLE_QIOT_CONTROL_DATA_TYPE) ||
+ (in_buf[0] == BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE)) {
+ slice_flag = (in_buf[0] == BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE) ? in_buf[2] : in_buf[1];
+ slice_type = (in_buf[0] == BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE) ? in_buf[0] : data_type;
+
+ // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "slice", p_data, p_data_len);
+ if (BLE_QIOT_IS_SLICE_PACKAGE(slice_flag)) {
+ header_len = ble_msg_type_header_len(slice_type);
+ ret = ble_package_slice_data(slice_type, slice_flag, header_len, in_buf, in_len);
+ if (ret < 0) {
+ return BLE_QIOT_RS_ERR;
+ } else if (ret == 0) {
+ tmp_len = HTONS(sg_ble_slice_data.buf_len - header_len);
+ if (BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE == slice_type) {
+ sg_ble_slice_data.buf[1] = in_buf[1];
+ memcpy(&sg_ble_slice_data.buf[2], &tmp_len, sizeof(tmp_len));
+ } else {
+ memcpy(&sg_ble_slice_data.buf[1], &tmp_len, sizeof(tmp_len));
+ }
+ p_data = sg_ble_slice_data.buf;
+ p_data_len = sg_ble_slice_data.buf_len;
+ } else if (ret > 0) {
+ return BLE_QIOT_RS_OK;
+ }
+ }
+ }
+ // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "tlv", p_data, p_data_len);
+
+ switch (data_type) {
+ case BLE_QIOT_MSG_TYPE_PROPERTY:
+ if (BLE_QIOT_EFFECT_REQUEST == data_effect) {
+ // default E_BLE_DATA_DOWN_TYPE_CONTROL
+ ret = ble_lldata_property_request_handle(p_data + 3, p_data_len - 3);
+ } else if (BLE_QIOT_EFFECT_REPLY == data_effect) {
+ // id means BLE_QIOT_DATA_DOWN_GET_STATUS_REPLY or BLE_QIOT_DATA_DOWN_REPORT_REPLY
+ ret = ble_lldata_property_reply_handle(id, p_data + 1, p_data_len - 1);
+ } else {
+ ret = BLE_QIOT_RS_ERR;
+ }
+ break;
+ case BLE_QIOT_MSG_TYPE_EVENT:
+ if (BLE_QIOT_EFFECT_REPLY == data_effect) {
+ ret = ble_lldata_event_handle(id, p_data + 1, p_data_len - 1);
+ } else {
+ ble_qiot_log_e("invalid event data effect");
+ ret = BLE_QIOT_RS_ERR;
+ }
+ break;
+ case BLE_QIOT_MSG_TYPE_ACTION:
+ if (BLE_QIOT_EFFECT_REQUEST == data_effect) {
+ ret = ble_lldata_action_handle(id, p_data + 3, p_data_len - 3);
+ } else {
+ ble_qiot_log_e("invalid action data effect");
+ ret = BLE_QIOT_RS_ERR;
+ }
+ break;
+ default:
+ break;
+ }
+ memset(&sg_ble_slice_data, 0, sizeof(sg_ble_slice_data));
+
+ return ret;
+}
+
+#if BLE_QIOT_SUPPORT_OTA
+static uint8_t ble_ota_type_header_len(uint8_t type)
+{
+ return BLE_QIOT_GET_OTA_REQUEST_HEADER_LEN;
+}
+
+int ble_ota_msg_handle(const char *buf, uint16_t len)
+{
+ POINTER_SANITY_CHECK(buf, BLE_QIOT_RS_ERR_PARA);
+
+ uint8_t data_type = 0;
+ int ret = BLE_QIOT_RS_OK;
+ uint8_t header_len = 0;
+ uint8_t slice_flag = 0;
+ char *p_data = NULL;
+ int p_data_len = 0;
+ uint16_t tmp_len = 0;
+
+ if (!llsync_is_connected()) {
+ ble_qiot_log_e("upgrade forbidden, device not connected");
+ return BLE_QIOT_RS_ERR;
+ }
+
+ data_type = (buf[0] == BLE_QIOT_OTA_MSG_REQUEST) ? BLE_QIOT_OTA_MSG_REQUEST : buf[0];
+ slice_flag = (buf[0] == BLE_QIOT_OTA_MSG_REQUEST) ? buf[1] : buf[0];
+ if (data_type >= BLE_QIOT_OTA_MSG_BUTT) {
+ ble_qiot_log_e("invalid data type %d", data_type);
+ return BLE_QIOT_RS_ERR;
+ }
+ p_data = (char *)buf;
+ p_data_len = len;
+
+ // ble_qiot_log_i("ota data type %d, flag %d", data_type, slice_flag);
+ if (BLE_QIOT_IS_SLICE_PACKAGE(slice_flag)) {
+ ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "tlv", p_data, p_data_len);
+ header_len = ble_ota_type_header_len(data_type);
+ ret = ble_package_slice_data(data_type, slice_flag, header_len, buf, len);
+ if (ret < 0) {
+ return BLE_QIOT_RS_ERR;
+ } else if (ret == 0) {
+ if (data_type == BLE_QIOT_OTA_MSG_REQUEST) {
+ tmp_len = HTONS(sg_ble_slice_data.buf_len - header_len);
+ memcpy(&sg_ble_slice_data.buf[1], &tmp_len, sizeof(tmp_len));
+ } else {
+ sg_ble_slice_data.buf[1] = sg_ble_slice_data.buf_len - header_len;
+ }
+ if (data_type == BLE_QIOT_OTA_MSG_DATA) {
+ sg_ble_slice_data.buf[2] = buf[2];
+ }
+ p_data = sg_ble_slice_data.buf;
+ p_data_len = sg_ble_slice_data.buf_len;
+ } else if (ret > 0) {
+ return BLE_QIOT_RS_OK;
+ }
+ }
+
+ // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "tlv", p_data, p_data_len);
+ switch (data_type) {
+ case BLE_QIOT_OTA_MSG_REQUEST:
+ clk_set("sys", BLE_QIOT_OTA_HZ);
+
+#if (!defined CONFIG_TRANSFER_ENABLE)
+ update_start_exit_sniff();
+#endif
+ set_ota_status(1);
+ ret = ble_ota_request_handle(p_data + 3, p_data_len);
+ break;
+ case BLE_QIOT_OTA_MSG_DATA:
+ ret = ble_ota_data_handle(p_data + 2, p_data_len - 2);
+ break;
+ case BLE_QIOT_OTA_MSG_END:
+ clk_set("sys", BT_NORMAL_HZ);
+ set_ota_status(0);
+ ret = ble_ota_file_end_handle();
+ break;
+ default:
+ break;
+ }
+ memset(&sg_ble_slice_data, 0, sizeof(sg_ble_slice_data));
+
+ return ret;
+}
+#else
+int ble_ota_msg_handle(const char *buf, uint16_t len)
+{
+ return BLE_QIOT_RS_OK;
+}
+#endif //BLE_QIOT_SUPPORT_OTA
+
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_template.c b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_template.c
new file mode 100644
index 0000000..26eb83e
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_template.c
@@ -0,0 +1,264 @@
+/*
+* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+* Licensed under the MIT License (the "License"); you may not use this file except in
+* compliance with the License. You may obtain a copy of the License at
+* http://opensource.org/licenses/MIT
+* Unless required by applicable law or agreed to in writing, software distributed under the License is
+* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+* either express or implied. See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_template.h"
+
+#include
+//#include
+#include
+
+#include "ble_qiot_export.h"
+#include "ble_qiot_common.h"
+#include "ble_qiot_param_check.h"
+#include "ble_qiot_llsync_event.h"
+#include "ble_qiot_service.h"
+#include "ble_qiot_llsync_device.h"
+#include "gpio.h"
+
+static uint8_t LL_led = 0;
+#define LLSYNC_SWITCH_PIN IO_PORTA_01
+static int ble_property_power_switch_set(const char *data, uint16_t len)
+{
+ printf("ble_property_power_switch_set led to %d\n", data[0]);
+ LL_led = data[0];
+ gpio_write(LLSYNC_SWITCH_PIN, LL_led);
+ return 0;
+}
+
+static int ble_property_power_switch_get(char *data, uint16_t buf_len)
+{
+ printf("ble_property_power_switch_get, led state is %d\n", LL_led);
+ data[0] = LL_led;
+ return sizeof(uint8_t);
+}
+
+static ble_property_t sg_ble_property_array[BLE_QIOT_PROPERTY_ID_BUTT] = {
+ {ble_property_power_switch_set, ble_property_power_switch_get, BLE_QIOT_PROPERTY_AUTH_RW, BLE_QIOT_DATA_TYPE_BOOL},
+};
+
+ble_qiot_ret_status_t ble_event_report_device_switch_state(u8 led_state)
+{
+ char device_info[2] = {0};
+
+ device_info[0] = BLE_QIOT_PROPERTY_ID_POWER_SWITCH;
+ device_info[1] = led_state;
+
+ return ble_event_notify(BLE_QIOT_EVENT_UP_PROPERTY_REPORT, NULL, 0, device_info, sizeof(device_info));
+}
+
+void ll_sync_led_switch(void)
+{
+ LL_led = !LL_led;
+
+ printf("ll_sync set led to %d\n", LL_led);
+ gpio_write(LLSYNC_SWITCH_PIN, LL_led);
+ ble_event_report_device_switch_state(LL_led);
+}
+
+void ll_sync_unbind(void)
+{
+ printf("ll_sync factory data reset\n");
+ ble_unbind_write_result();
+}
+
+void llsync_device_state_sync(void)
+{
+ printf("llsync_device_state_sync, led = %d\n", LL_led);
+ ble_event_report_device_switch_state(LL_led);
+}
+
+static bool ble_check_space_enough_by_type(uint8_t type, uint16_t left_size)
+{
+ switch (type) {
+ case BLE_QIOT_DATA_TYPE_BOOL:
+ return left_size >= sizeof(uint8_t);
+ case BLE_QIOT_DATA_TYPE_INT:
+ case BLE_QIOT_DATA_TYPE_FLOAT:
+ case BLE_QIOT_DATA_TYPE_TIME:
+ return left_size >= sizeof(uint32_t);
+ case BLE_QIOT_DATA_TYPE_ENUM:
+ return left_size >= sizeof(uint16_t);
+ default:
+ // string length is unknow, default true
+ return true;
+ }
+}
+
+static uint16_t ble_check_ret_value_by_type(uint8_t type, uint16_t buf_len, uint16_t ret_val)
+{
+ switch (type) {
+ case BLE_QIOT_DATA_TYPE_BOOL:
+ return ret_val <= sizeof(uint8_t);
+ case BLE_QIOT_DATA_TYPE_INT:
+ case BLE_QIOT_DATA_TYPE_FLOAT:
+ case BLE_QIOT_DATA_TYPE_TIME:
+ return ret_val <= sizeof(uint32_t);
+ case BLE_QIOT_DATA_TYPE_ENUM:
+ return ret_val <= sizeof(uint16_t);
+ default:
+ // string length is unknow, default true
+ return ret_val <= buf_len;
+ }
+}
+
+uint8_t ble_get_property_type_by_id(uint8_t id)
+{
+ if (id >= BLE_QIOT_PROPERTY_ID_BUTT) {
+ ble_qiot_log_e("invalid property id %d", id);
+ return BLE_QIOT_DATA_TYPE_BUTT;
+ }
+ return sg_ble_property_array[id].type;
+}
+
+int ble_user_property_set_data(const e_ble_tlv *tlv)
+{
+ POINTER_SANITY_CHECK(tlv, BLE_QIOT_RS_ERR_PARA);
+ if (tlv->id >= BLE_QIOT_PROPERTY_ID_BUTT) {
+ ble_qiot_log_e("invalid property id %d", tlv->id);
+ return BLE_QIOT_RS_ERR;
+ }
+
+ if (NULL != sg_ble_property_array[tlv->id].set_cb) {
+ if (0 != sg_ble_property_array[tlv->id].set_cb(tlv->val, tlv->len)) {
+ ble_qiot_log_e("set property id %d failed", tlv->id);
+ return BLE_QIOT_RS_ERR;
+ } else {
+ return BLE_QIOT_RS_OK;
+ }
+ }
+ ble_qiot_log_e("invalid set callback, id %d", tlv->id);
+
+ return BLE_QIOT_RS_ERR;
+}
+
+int ble_user_property_get_data_by_id(uint8_t id, char *buf, uint16_t buf_len)
+{
+ int ret_len = 0;
+
+ POINTER_SANITY_CHECK(buf, BLE_QIOT_RS_ERR_PARA);
+ if (id >= BLE_QIOT_PROPERTY_ID_BUTT) {
+ ble_qiot_log_e("invalid property id %d", id);
+ return -1;
+ }
+
+ if (NULL != sg_ble_property_array[id].get_cb) {
+ if (!ble_check_space_enough_by_type(sg_ble_property_array[id].type, buf_len)) {
+ ble_qiot_log_e("not enough space get property id %d data", id);
+ return -1;
+ }
+ ret_len = sg_ble_property_array[id].get_cb(buf, buf_len);
+ if (ret_len < 0) {
+ ble_qiot_log_e("get property id %d data failed", id);
+ return -1;
+ } else {
+ if (ble_check_ret_value_by_type(sg_ble_property_array[id].type, buf_len, ret_len)) {
+ return ret_len;
+ } else {
+ ble_qiot_log_e("property id %d length invalid", id);
+ return -1;
+ }
+ }
+ }
+ ble_qiot_log_e("invalid callback, property id %d", id);
+
+ return 0;
+}
+
+int ble_user_property_report_reply_handle(uint8_t result)
+{
+ ble_qiot_log_d("report reply result %d", result);
+
+ return BLE_QIOT_RS_OK;
+}
+
+int ble_user_property_struct_handle(const char *in_buf, uint16_t buf_len, ble_property_t struct_arr[], uint8_t arr_size)
+{
+ uint16_t parse_len = 0;
+ uint16_t ret_len = 0;
+ e_ble_tlv tlv;
+
+ while (parse_len < buf_len) {
+ memset(&tlv, 0, sizeof(e_ble_tlv));
+ ret_len = ble_lldata_parse_tlv(in_buf + parse_len, buf_len - parse_len, &tlv);
+ parse_len += ret_len;
+ if (parse_len > buf_len) {
+ ble_qiot_log_e("parse struct failed");
+ return parse_len;
+ }
+
+ if (tlv.id >= arr_size) {
+ ble_qiot_log_e("invalid array index %d", tlv.id);
+ return parse_len;
+ }
+ if (NULL == struct_arr[tlv.id].set_cb) {
+ ble_qiot_log_e("invalid member id %d", tlv.id);
+ return parse_len;
+ }
+ if (BLE_QIOT_RS_OK != struct_arr[tlv.id].set_cb(tlv.val, tlv.len)) {
+ ble_qiot_log_e("user handle property error, member id %d, type %d, len %d", tlv.id, tlv.type, tlv.len);
+ return parse_len;
+ }
+ }
+
+ return 0;
+}
+
+int ble_user_property_struct_get_data(char *in_buf, uint16_t buf_len, ble_property_t struct_arr[], uint8_t arr_size)
+{
+ uint8_t property_id = 0;
+ uint8_t property_type = 0;
+ int property_len = 0;
+ char *data_buf = in_buf;
+ uint16_t data_len = 0;
+ uint16_t string_len = 0;
+
+ for (property_id = 0; property_id < arr_size; property_id++) {
+ property_type = struct_arr[property_id].type;
+ if (property_type >= BLE_QIOT_DATA_TYPE_BUTT) {
+ ble_qiot_log_e("member id %d type %d invalid", property_id, property_type);
+ return BLE_QIOT_RS_ERR;
+ }
+ data_buf[data_len++] = BLE_QIOT_PACKAGE_TLV_HEAD(property_type, property_id);
+ if (BLE_QIOT_DATA_TYPE_STRING == property_type) {
+ // reserved 2 bytes for string length
+ property_len = struct_arr[property_id].get_cb((char *)data_buf + data_len + 2, buf_len - data_len - 2);
+ } else {
+ property_len = struct_arr[property_id].get_cb((char *)data_buf + data_len, buf_len - data_len);
+ }
+ if (property_len < 0) {
+ ble_qiot_log_e("too long data, member id %d, data length %d", property_id, data_len);
+ return BLE_QIOT_RS_ERR;
+ } else if (property_len == 0) {
+ // no data to post
+ data_len--;
+ data_buf[data_len] = '0';
+ ble_qiot_log_d("member id %d no data to post", property_id);
+ } else {
+ if (BLE_QIOT_DATA_TYPE_STRING == property_type) {
+ string_len = HTONS(property_len);
+ memcpy(data_buf + data_len, &string_len, sizeof(uint16_t));
+ data_len += sizeof(uint16_t);
+ }
+ data_len += property_len;
+ }
+ }
+
+ return data_len;
+}
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_base64.c b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_base64.c
new file mode 100644
index 0000000..62eb061
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_base64.c
@@ -0,0 +1,194 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_utils_base64.h"
+#include "ble_qiot_export.h"
+#include
+#include
+
+static const unsigned char base64_enc_map[64] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
+ 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
+ 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+};
+
+static const unsigned char base64_dec_map[128] = {
+ 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+ 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 62,
+ 127, 127, 127, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, 127, 64, 127, 127, 127, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 127, 127, 127, 127, 127
+};
+
+#define BASE64_SIZE_T_MAX ((size_t)-1) /* SIZE_T_MAX is not standard */
+
+ble_qiot_ret_status_t qcloud_iot_utils_base64encode(unsigned char *dst, size_t dlen, size_t *olen,
+ const unsigned char *src, size_t slen)
+{
+ size_t i, n;
+ unsigned char *p;
+
+ if (slen == 0) {
+ *olen = 0;
+ return (BLE_QIOT_RS_OK);
+ }
+
+ n = slen / 3 + (slen % 3 != 0);
+
+ if (n > (BASE64_SIZE_T_MAX - 1) / 4) {
+ *olen = BASE64_SIZE_T_MAX;
+ return (BLE_QIOT_RS_ERR);
+ }
+
+ n *= 4;
+
+ if ((dlen < n + 1) || (NULL == dst)) {
+ *olen = n + 1;
+ return (BLE_QIOT_RS_ERR);
+ }
+
+ n = (slen / 3) * 3;
+
+ int C1, C2, C3;
+ for (i = 0, p = dst; i < n; i += 3) {
+ C1 = *src++;
+ C2 = *src++;
+ C3 = *src++;
+
+ *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
+ *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+ *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
+ *p++ = base64_enc_map[C3 & 0x3F];
+ }
+
+ if (i < slen) {
+ C1 = *src++;
+ C2 = ((i + 1) < slen) ? *src++ : 0;
+
+ *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
+ *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+
+ if ((i + 1) < slen) {
+ *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
+ } else {
+ *p++ = '=';
+ }
+
+ *p++ = '=';
+ }
+
+ *olen = p - dst;
+ *p = 0;
+
+ return (BLE_QIOT_RS_OK);
+}
+
+ble_qiot_ret_status_t qcloud_iot_utils_base64decode(unsigned char *dst, size_t dlen, size_t *olen,
+ const unsigned char *src, size_t slen)
+{
+ size_t i, n;
+ uint32_t j, x;
+ unsigned char *p;
+
+ /* First pass: check for validity and get output length */
+ for (i = n = j = 0; i < slen; i++) {
+ /* Skip spaces before checking for EOL */
+ x = 0;
+ while (i < slen && src[i] == ' ') {
+ ++i;
+ ++x;
+ }
+
+ /* Spaces at end of buffer are OK */
+ if (i == slen) {
+ break;
+ }
+
+ if ((slen - i) >= 2 && src[i] == '\r' && src[i + 1] == '\n') {
+ continue;
+ }
+
+ if (src[i] == '\n') {
+ continue;
+ }
+
+ /* Space inside a line is an error */
+ if (x != 0) {
+ return (BLE_QIOT_RS_ERR);
+ }
+
+ if (src[i] == '=' && ++j > 2) {
+ return (BLE_QIOT_RS_ERR);
+ }
+
+ if (src[i] > 127 || base64_dec_map[src[i]] == 127) {
+ return (BLE_QIOT_RS_ERR);
+ }
+
+ if (base64_dec_map[src[i]] < 64 && j != 0) {
+ return (BLE_QIOT_RS_ERR);
+ }
+
+ n++;
+ }
+
+ if (n == 0) {
+ *olen = 0;
+ return (BLE_QIOT_RS_OK);
+ }
+
+ n = ((n * 6) + 7) >> 3;
+ n -= j;
+
+ if (dst == NULL || dlen < n) {
+ *olen = n;
+ return (BLE_QIOT_RS_ERR);
+ }
+
+ for (j = 3, n = x = 0, p = dst; i > 0; i--, src++) {
+ if (*src == '\r' || *src == '\n' || *src == ' ') {
+ continue;
+ }
+
+ j -= (base64_dec_map[*src] == 64);
+ x = (x << 6) | (base64_dec_map[*src] & 0x3F);
+
+ if (++n == 4) {
+ n = 0;
+ if (j > 0) {
+ *p++ = (unsigned char)(x >> 16);
+ }
+ if (j > 1) {
+ *p++ = (unsigned char)(x >> 8);
+ }
+ if (j > 2) {
+ *p++ = (unsigned char)(x);
+ }
+ }
+ }
+
+ *olen = p - dst;
+
+ return (BLE_QIOT_RS_OK);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_crc.c b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_crc.c
new file mode 100644
index 0000000..2428314
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_crc.c
@@ -0,0 +1,76 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_crc.h"
+
+#include
+
+const uint32_t crc32_tab[] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832,
+ 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a,
+ 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,
+ 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4,
+ 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074,
+ 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525,
+ 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76,
+ 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6,
+ 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,
+ 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7,
+ 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330,
+ 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+void ble_qiot_crc32_init(void)
+{
+
+}
+
+uint32_t ble_qiot_crc32(uint32_t crc, const uint8_t *buf, int len)
+{
+ const uint8_t *p;
+
+ p = buf;
+ crc = crc ^ ~0U;
+
+ while (len--) {
+ crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+ }
+
+ return crc ^ ~0U;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_hmac.c b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_hmac.c
new file mode 100644
index 0000000..562dc11
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_hmac.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+
+#include "ble_qiot_log.h"
+#include "ble_qiot_sha1.h"
+#include "ble_qiot_hmac.h"
+
+#define KEY_IOPAD_SIZE 64
+
+int8_t utils_hb2hex(uint8_t hb)
+{
+ hb = hb & 0xF;
+ return (int8_t)(hb < 10 ? '0' + hb : hb - 10 + 'a');
+}
+
+void utils_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len)
+{
+ if ((NULL == msg) || (NULL == digest) || (NULL == key)) {
+ ble_qiot_log_e("parameter is Null,failed!");
+ return;
+ }
+
+ if (key_len > KEY_IOPAD_SIZE) {
+ ble_qiot_log_e("key_len > size(%d) of array", KEY_IOPAD_SIZE);
+ return;
+ }
+
+ iot_sha1_context context;
+ unsigned char k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */
+ unsigned char k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */
+ unsigned char out[SHA1_DIGEST_SIZE];
+ int i;
+
+ /* start out by storing key in pads */
+ memset(k_ipad, 0, sizeof(k_ipad));
+ memset(k_opad, 0, sizeof(k_opad));
+ memcpy(k_ipad, key, key_len);
+ memcpy(k_opad, key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i = 0; i < KEY_IOPAD_SIZE; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ /* perform inner SHA */
+ utils_sha1_init(&context); /* init context for 1st pass */
+ utils_sha1_starts(&context); /* setup context for 1st pass */
+ utils_sha1_update(&context, k_ipad, KEY_IOPAD_SIZE); /* start with inner pad */
+ utils_sha1_update(&context, (unsigned char *)msg, msg_len); /* then text of datagram */
+ utils_sha1_finish(&context, out); /* finish up 1st pass */
+
+ /* perform outer SHA */
+ utils_sha1_init(&context); /* init context for 2nd pass */
+ utils_sha1_starts(&context); /* setup context for 2nd pass */
+ utils_sha1_update(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */
+ utils_sha1_update(&context, out, SHA1_DIGEST_SIZE); /* then results of 1st hash */
+ utils_sha1_finish(&context, out); /* finish up 2nd pass */
+
+ memcpy(digest, out, SHA1_DIGEST_SIZE);
+ /* for (i = 0; i < SHA1_DIGEST_SIZE; ++i) {
+ digest[i * 2] = utils_hb2hex(out[i] >> 4);
+ digest[i * 2 + 1] = utils_hb2hex(out[i]);
+ }*/
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_log.c b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_log.c
new file mode 100644
index 0000000..30c8792
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_log.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_log.h"
+
+#include
+#include
+#include
+
+#define HEX_DUMP_BYTE_PER_LINE 16
+
+e_ble_qiot_log_level g_log_level = BLE_QIOT_LOG_LEVEL_INFO;
+
+void ble_qiot_set_log_level(e_ble_qiot_log_level level)
+{
+ g_log_level = level;
+ return;
+}
+
+#if !BLE_QIOT_USER_DEFINE_HEXDUMP
+void ble_qiot_log_hex(e_ble_qiot_log_level level, const char *hex_name, const char *data, uint32_t data_len)
+{
+ char buf[HEX_DUMP_BYTE_PER_LINE * 5] = {0};
+ int line_count = 0, line = 0, byte = 0, rest = 0, start_byte = 0;
+
+ if (g_log_level < level) {
+ return;
+ }
+
+ line_count = data_len / HEX_DUMP_BYTE_PER_LINE;
+ if (data_len % HEX_DUMP_BYTE_PER_LINE) {
+ line_count += 1;
+ }
+
+ ble_qiot_log_raw("\r\nble qiot dump: %s, length: %d\r\n", hex_name, data_len);
+ ble_qiot_log_raw(" 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15\r\n");
+ ble_qiot_log_raw("===============================================\r\n");
+ for (line = 0; line < line_count; line++) {
+ start_byte = line * HEX_DUMP_BYTE_PER_LINE;
+ if (data_len - start_byte < HEX_DUMP_BYTE_PER_LINE) {
+ rest = data_len % HEX_DUMP_BYTE_PER_LINE;
+ } else {
+ rest = HEX_DUMP_BYTE_PER_LINE;
+ }
+
+ for (byte = 0; byte < HEX_DUMP_BYTE_PER_LINE; byte++) {
+ if (byte < rest) {
+ sprintf(&buf[byte * 3], "%02X ", data[start_byte + byte]);
+ } else {
+ sprintf(&buf[byte * 3], " ");
+ }
+ }
+
+ sprintf(&buf[HEX_DUMP_BYTE_PER_LINE * 3], "| ");
+ for (byte = 0; byte < rest; byte++) {
+ if (data[start_byte + byte] >= ' ' && data[start_byte + byte] <= '~') {
+ buf[HEX_DUMP_BYTE_PER_LINE * 3 + 2 + byte] = data[start_byte + byte];
+ } else {
+ buf[HEX_DUMP_BYTE_PER_LINE * 3 + 2 + byte] = '.';
+ }
+ }
+ sprintf(&buf[HEX_DUMP_BYTE_PER_LINE * 3 + 2 + rest], "\r\n");
+
+ ble_qiot_log_raw("%s", buf); // do not use printf(buf), that cause '%' transfer next character
+ }
+ ble_qiot_log_raw("\r\n");
+}
+#endif // BLE_QIOT_USER_DEFINE_HEXDUMP
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_md5.c b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_md5.c
new file mode 100644
index 0000000..149b431
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_md5.c
@@ -0,0 +1,302 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_md5.h"
+
+#include
+#include
+#include
+
+/* Implementation that should never be optimized out by the compiler */
+static void _utils_md5_zeroize(void *v, size_t n)
+{
+ volatile unsigned char *p = v;
+ while (n--) {
+ *p++ = 0;
+ }
+}
+
+/*
+ * 32-bit integer manipulation macros (little endian)
+ */
+#ifndef IOT_MD5_GET_UINT32_LE
+#define IOT_MD5_GET_UINT32_LE(n, b, i) \
+ { \
+ (n) = ((uint32_t)(b)[(i)]) | ((uint32_t)(b)[(i) + 1] << 8) | ((uint32_t)(b)[(i) + 2] << 16) | \
+ ((uint32_t)(b)[(i) + 3] << 24); \
+ }
+#endif
+
+#ifndef IOT_MD5_PUT_UINT32_LE
+#define IOT_MD5_PUT_UINT32_LE(n, b, i) \
+ { \
+ (b)[(i)] = (unsigned char)(((n)) & 0xFF); \
+ (b)[(i) + 1] = (unsigned char)(((n) >> 8) & 0xFF); \
+ (b)[(i) + 2] = (unsigned char)(((n) >> 16) & 0xFF); \
+ (b)[(i) + 3] = (unsigned char)(((n) >> 24) & 0xFF); \
+ }
+#endif
+
+void utils_md5_init(iot_md5_context *ctx)
+{
+ memset(ctx, 0, sizeof(iot_md5_context));
+}
+
+void utils_md5_free(iot_md5_context *ctx)
+{
+ if (ctx == NULL) {
+ return;
+ }
+
+ _utils_md5_zeroize(ctx, sizeof(iot_md5_context));
+}
+
+void utils_md5_clone(iot_md5_context *dst, const iot_md5_context *src)
+{
+ *dst = *src;
+}
+
+/*
+ * MD5 context setup
+ */
+void utils_md5_starts(iot_md5_context *ctx)
+{
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+}
+
+void utils_md5_process(iot_md5_context *ctx, const unsigned char data[64])
+{
+ uint32_t X[16], A, B, C, D;
+
+ IOT_MD5_GET_UINT32_LE(X[0], data, 0);
+ IOT_MD5_GET_UINT32_LE(X[1], data, 4);
+ IOT_MD5_GET_UINT32_LE(X[2], data, 8);
+ IOT_MD5_GET_UINT32_LE(X[3], data, 12);
+ IOT_MD5_GET_UINT32_LE(X[4], data, 16);
+ IOT_MD5_GET_UINT32_LE(X[5], data, 20);
+ IOT_MD5_GET_UINT32_LE(X[6], data, 24);
+ IOT_MD5_GET_UINT32_LE(X[7], data, 28);
+ IOT_MD5_GET_UINT32_LE(X[8], data, 32);
+ IOT_MD5_GET_UINT32_LE(X[9], data, 36);
+ IOT_MD5_GET_UINT32_LE(X[10], data, 40);
+ IOT_MD5_GET_UINT32_LE(X[11], data, 44);
+ IOT_MD5_GET_UINT32_LE(X[12], data, 48);
+ IOT_MD5_GET_UINT32_LE(X[13], data, 52);
+ IOT_MD5_GET_UINT32_LE(X[14], data, 56);
+ IOT_MD5_GET_UINT32_LE(X[15], data, 60);
+
+#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define P(a, b, c, d, k, s, t) \
+ { \
+ a += F(b, c, d) + X[k] + t; \
+ a = S(a, s) + b; \
+ }
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+
+#define F(x, y, z) (z ^ (x & (y ^ z)))
+
+ P(A, B, C, D, 0, 7, 0xD76AA478);
+ P(D, A, B, C, 1, 12, 0xE8C7B756);
+ P(C, D, A, B, 2, 17, 0x242070DB);
+ P(B, C, D, A, 3, 22, 0xC1BDCEEE);
+ P(A, B, C, D, 4, 7, 0xF57C0FAF);
+ P(D, A, B, C, 5, 12, 0x4787C62A);
+ P(C, D, A, B, 6, 17, 0xA8304613);
+ P(B, C, D, A, 7, 22, 0xFD469501);
+ P(A, B, C, D, 8, 7, 0x698098D8);
+ P(D, A, B, C, 9, 12, 0x8B44F7AF);
+ P(C, D, A, B, 10, 17, 0xFFFF5BB1);
+ P(B, C, D, A, 11, 22, 0x895CD7BE);
+ P(A, B, C, D, 12, 7, 0x6B901122);
+ P(D, A, B, C, 13, 12, 0xFD987193);
+ P(C, D, A, B, 14, 17, 0xA679438E);
+ P(B, C, D, A, 15, 22, 0x49B40821);
+
+#undef F
+
+#define F(x, y, z) (y ^ (z & (x ^ y)))
+
+ P(A, B, C, D, 1, 5, 0xF61E2562);
+ P(D, A, B, C, 6, 9, 0xC040B340);
+ P(C, D, A, B, 11, 14, 0x265E5A51);
+ P(B, C, D, A, 0, 20, 0xE9B6C7AA);
+ P(A, B, C, D, 5, 5, 0xD62F105D);
+ P(D, A, B, C, 10, 9, 0x02441453);
+ P(C, D, A, B, 15, 14, 0xD8A1E681);
+ P(B, C, D, A, 4, 20, 0xE7D3FBC8);
+ P(A, B, C, D, 9, 5, 0x21E1CDE6);
+ P(D, A, B, C, 14, 9, 0xC33707D6);
+ P(C, D, A, B, 3, 14, 0xF4D50D87);
+ P(B, C, D, A, 8, 20, 0x455A14ED);
+ P(A, B, C, D, 13, 5, 0xA9E3E905);
+ P(D, A, B, C, 2, 9, 0xFCEFA3F8);
+ P(C, D, A, B, 7, 14, 0x676F02D9);
+ P(B, C, D, A, 12, 20, 0x8D2A4C8A);
+
+#undef F
+
+#define F(x, y, z) (x ^ y ^ z)
+
+ P(A, B, C, D, 5, 4, 0xFFFA3942);
+ P(D, A, B, C, 8, 11, 0x8771F681);
+ P(C, D, A, B, 11, 16, 0x6D9D6122);
+ P(B, C, D, A, 14, 23, 0xFDE5380C);
+ P(A, B, C, D, 1, 4, 0xA4BEEA44);
+ P(D, A, B, C, 4, 11, 0x4BDECFA9);
+ P(C, D, A, B, 7, 16, 0xF6BB4B60);
+ P(B, C, D, A, 10, 23, 0xBEBFBC70);
+ P(A, B, C, D, 13, 4, 0x289B7EC6);
+ P(D, A, B, C, 0, 11, 0xEAA127FA);
+ P(C, D, A, B, 3, 16, 0xD4EF3085);
+ P(B, C, D, A, 6, 23, 0x04881D05);
+ P(A, B, C, D, 9, 4, 0xD9D4D039);
+ P(D, A, B, C, 12, 11, 0xE6DB99E5);
+ P(C, D, A, B, 15, 16, 0x1FA27CF8);
+ P(B, C, D, A, 2, 23, 0xC4AC5665);
+
+#undef F
+
+#define F(x, y, z) (y ^ (x | ~z))
+
+ P(A, B, C, D, 0, 6, 0xF4292244);
+ P(D, A, B, C, 7, 10, 0x432AFF97);
+ P(C, D, A, B, 14, 15, 0xAB9423A7);
+ P(B, C, D, A, 5, 21, 0xFC93A039);
+ P(A, B, C, D, 12, 6, 0x655B59C3);
+ P(D, A, B, C, 3, 10, 0x8F0CCC92);
+ P(C, D, A, B, 10, 15, 0xFFEFF47D);
+ P(B, C, D, A, 1, 21, 0x85845DD1);
+ P(A, B, C, D, 8, 6, 0x6FA87E4F);
+ P(D, A, B, C, 15, 10, 0xFE2CE6E0);
+ P(C, D, A, B, 6, 15, 0xA3014314);
+ P(B, C, D, A, 13, 21, 0x4E0811A1);
+ P(A, B, C, D, 4, 6, 0xF7537E82);
+ P(D, A, B, C, 11, 10, 0xBD3AF235);
+ P(C, D, A, B, 2, 15, 0x2AD7D2BB);
+ P(B, C, D, A, 9, 21, 0xEB86D391);
+
+#undef F
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+}
+
+/*
+ * MD5 process buffer
+ */
+void utils_md5_update(iot_md5_context *ctx, const unsigned char *input, unsigned int ilen)
+{
+ uint32_t fill;
+ uint32_t left;
+
+ if (ilen == 0) {
+ return;
+ }
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += (uint32_t)ilen;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if (ctx->total[0] < (uint32_t)ilen) {
+ ctx->total[1]++;
+ }
+
+ if (left && ilen >= fill) {
+ memcpy((void *)(ctx->buffer + left), input, fill);
+ utils_md5_process(ctx, ctx->buffer);
+ input += fill;
+ ilen -= fill;
+ left = 0;
+ }
+
+ while (ilen >= 64) {
+ utils_md5_process(ctx, input);
+ input += 64;
+ ilen -= 64;
+ }
+
+ if (ilen > 0) {
+ memcpy((void *)(ctx->buffer + left), input, ilen);
+ }
+}
+
+static const unsigned char iot_md5_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+/*
+ * MD5 final digest
+ */
+void utils_md5_finish(iot_md5_context *ctx, unsigned char output[16])
+{
+ uint32_t last, padn;
+ uint32_t high, low;
+ unsigned char msglen[8];
+
+ high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
+ low = (ctx->total[0] << 3);
+
+ IOT_MD5_PUT_UINT32_LE(low, msglen, 0);
+ IOT_MD5_PUT_UINT32_LE(high, msglen, 4);
+
+ last = ctx->total[0] & 0x3F;
+ padn = (last < 56) ? (56 - last) : (120 - last);
+
+ utils_md5_update(ctx, iot_md5_padding, padn);
+ utils_md5_update(ctx, msglen, 8);
+
+ IOT_MD5_PUT_UINT32_LE(ctx->state[0], output, 0);
+ IOT_MD5_PUT_UINT32_LE(ctx->state[1], output, 4);
+ IOT_MD5_PUT_UINT32_LE(ctx->state[2], output, 8);
+ IOT_MD5_PUT_UINT32_LE(ctx->state[3], output, 12);
+}
+
+/*
+ * output = MD5( input buffer )
+ */
+void utils_md5(const unsigned char *input, unsigned int ilen, unsigned char output[16])
+{
+ iot_md5_context ctx;
+
+ utils_md5_init(&ctx);
+ utils_md5_starts(&ctx);
+ utils_md5_update(&ctx, input, ilen);
+ utils_md5_finish(&ctx, output);
+ utils_md5_free(&ctx);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_sha1.c b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_sha1.c
new file mode 100644
index 0000000..c385960
--- /dev/null
+++ b/apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_utils_sha1.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_sha1.h"
+
+#include
+#include
+
+/* Implementation that should never be optimized out by the compiler */
+static void utils_sha1_zeroize(void *v, size_t n)
+{
+ volatile unsigned char *p = v;
+ while (n--) {
+ *p++ = 0;
+ }
+}
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef IOT_SHA1_GET_UINT32_BE
+#define IOT_SHA1_GET_UINT32_BE(n, b, i) \
+ { \
+ (n) = ((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | ((uint32_t)(b)[(i) + 2] << 8) | \
+ ((uint32_t)(b)[(i) + 3]); \
+ }
+#endif
+
+#ifndef IOT_SHA1_PUT_UINT32_BE
+#define IOT_SHA1_PUT_UINT32_BE(n, b, i) \
+ { \
+ (b)[(i)] = (unsigned char)((n) >> 24); \
+ (b)[(i) + 1] = (unsigned char)((n) >> 16); \
+ (b)[(i) + 2] = (unsigned char)((n) >> 8); \
+ (b)[(i) + 3] = (unsigned char)((n)); \
+ }
+#endif
+
+void utils_sha1_init(iot_sha1_context *ctx)
+{
+ memset(ctx, 0, sizeof(iot_sha1_context));
+}
+
+void utils_sha1_free(iot_sha1_context *ctx)
+{
+ if (ctx == NULL) {
+ return;
+ }
+
+ utils_sha1_zeroize(ctx, sizeof(iot_sha1_context));
+}
+
+void utils_sha1_clone(iot_sha1_context *dst, const iot_sha1_context *src)
+{
+ *dst = *src;
+}
+
+/*
+ * SHA-1 context setup
+ */
+void utils_sha1_starts(iot_sha1_context *ctx)
+{
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+ ctx->state[4] = 0xC3D2E1F0;
+}
+
+void utils_sha1_process(iot_sha1_context *ctx, const unsigned char data[64])
+{
+ uint32_t temp, W[16], A, B, C, D, E;
+
+ IOT_SHA1_GET_UINT32_BE(W[0], data, 0);
+ IOT_SHA1_GET_UINT32_BE(W[1], data, 4);
+ IOT_SHA1_GET_UINT32_BE(W[2], data, 8);
+ IOT_SHA1_GET_UINT32_BE(W[3], data, 12);
+ IOT_SHA1_GET_UINT32_BE(W[4], data, 16);
+ IOT_SHA1_GET_UINT32_BE(W[5], data, 20);
+ IOT_SHA1_GET_UINT32_BE(W[6], data, 24);
+ IOT_SHA1_GET_UINT32_BE(W[7], data, 28);
+ IOT_SHA1_GET_UINT32_BE(W[8], data, 32);
+ IOT_SHA1_GET_UINT32_BE(W[9], data, 36);
+ IOT_SHA1_GET_UINT32_BE(W[10], data, 40);
+ IOT_SHA1_GET_UINT32_BE(W[11], data, 44);
+ IOT_SHA1_GET_UINT32_BE(W[12], data, 48);
+ IOT_SHA1_GET_UINT32_BE(W[13], data, 52);
+ IOT_SHA1_GET_UINT32_BE(W[14], data, 56);
+ IOT_SHA1_GET_UINT32_BE(W[15], data, 60);
+
+#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define R(t) \
+ (temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ W[(t - 14) & 0x0F] ^ W[t & 0x0F], (W[t & 0x0F] = S(temp, 1)))
+
+#define P(a, b, c, d, e, x) \
+ { \
+ e += S(a, 5) + F(b, c, d) + K + x; \
+ b = S(b, 30); \
+ }
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+ E = ctx->state[4];
+
+#define F(x, y, z) (z ^ (x & (y ^ z)))
+#define K 0x5A827999
+
+ P(A, B, C, D, E, W[0]);
+ P(E, A, B, C, D, W[1]);
+ P(D, E, A, B, C, W[2]);
+ P(C, D, E, A, B, W[3]);
+ P(B, C, D, E, A, W[4]);
+ P(A, B, C, D, E, W[5]);
+ P(E, A, B, C, D, W[6]);
+ P(D, E, A, B, C, W[7]);
+ P(C, D, E, A, B, W[8]);
+ P(B, C, D, E, A, W[9]);
+ P(A, B, C, D, E, W[10]);
+ P(E, A, B, C, D, W[11]);
+ P(D, E, A, B, C, W[12]);
+ P(C, D, E, A, B, W[13]);
+ P(B, C, D, E, A, W[14]);
+ P(A, B, C, D, E, W[15]);
+ P(E, A, B, C, D, R(16));
+ P(D, E, A, B, C, R(17));
+ P(C, D, E, A, B, R(18));
+ P(B, C, D, E, A, R(19));
+
+#undef K
+#undef F
+
+#define F(x, y, z) (x ^ y ^ z)
+#define K 0x6ED9EBA1
+
+ P(A, B, C, D, E, R(20));
+ P(E, A, B, C, D, R(21));
+ P(D, E, A, B, C, R(22));
+ P(C, D, E, A, B, R(23));
+ P(B, C, D, E, A, R(24));
+ P(A, B, C, D, E, R(25));
+ P(E, A, B, C, D, R(26));
+ P(D, E, A, B, C, R(27));
+ P(C, D, E, A, B, R(28));
+ P(B, C, D, E, A, R(29));
+ P(A, B, C, D, E, R(30));
+ P(E, A, B, C, D, R(31));
+ P(D, E, A, B, C, R(32));
+ P(C, D, E, A, B, R(33));
+ P(B, C, D, E, A, R(34));
+ P(A, B, C, D, E, R(35));
+ P(E, A, B, C, D, R(36));
+ P(D, E, A, B, C, R(37));
+ P(C, D, E, A, B, R(38));
+ P(B, C, D, E, A, R(39));
+
+#undef K
+#undef F
+
+#define F(x, y, z) ((x & y) | (z & (x | y)))
+#define K 0x8F1BBCDC
+
+ P(A, B, C, D, E, R(40));
+ P(E, A, B, C, D, R(41));
+ P(D, E, A, B, C, R(42));
+ P(C, D, E, A, B, R(43));
+ P(B, C, D, E, A, R(44));
+ P(A, B, C, D, E, R(45));
+ P(E, A, B, C, D, R(46));
+ P(D, E, A, B, C, R(47));
+ P(C, D, E, A, B, R(48));
+ P(B, C, D, E, A, R(49));
+ P(A, B, C, D, E, R(50));
+ P(E, A, B, C, D, R(51));
+ P(D, E, A, B, C, R(52));
+ P(C, D, E, A, B, R(53));
+ P(B, C, D, E, A, R(54));
+ P(A, B, C, D, E, R(55));
+ P(E, A, B, C, D, R(56));
+ P(D, E, A, B, C, R(57));
+ P(C, D, E, A, B, R(58));
+ P(B, C, D, E, A, R(59));
+
+#undef K
+#undef F
+
+#define F(x, y, z) (x ^ y ^ z)
+#define K 0xCA62C1D6
+
+ P(A, B, C, D, E, R(60));
+ P(E, A, B, C, D, R(61));
+ P(D, E, A, B, C, R(62));
+ P(C, D, E, A, B, R(63));
+ P(B, C, D, E, A, R(64));
+ P(A, B, C, D, E, R(65));
+ P(E, A, B, C, D, R(66));
+ P(D, E, A, B, C, R(67));
+ P(C, D, E, A, B, R(68));
+ P(B, C, D, E, A, R(69));
+ P(A, B, C, D, E, R(70));
+ P(E, A, B, C, D, R(71));
+ P(D, E, A, B, C, R(72));
+ P(C, D, E, A, B, R(73));
+ P(B, C, D, E, A, R(74));
+ P(A, B, C, D, E, R(75));
+ P(E, A, B, C, D, R(76));
+ P(D, E, A, B, C, R(77));
+ P(C, D, E, A, B, R(78));
+ P(B, C, D, E, A, R(79));
+
+#undef K
+#undef F
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+ ctx->state[4] += E;
+}
+
+/*
+ * SHA-1 process buffer
+ */
+void utils_sha1_update(iot_sha1_context *ctx, const unsigned char *input, size_t ilen)
+{
+ size_t fill;
+ uint32_t left;
+
+ if (ilen == 0) {
+ return;
+ }
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += (uint32_t)ilen;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if (ctx->total[0] < (uint32_t)ilen) {
+ ctx->total[1]++;
+ }
+
+ if (left && ilen >= fill) {
+ memcpy((void *)(ctx->buffer + left), input, fill);
+ utils_sha1_process(ctx, ctx->buffer);
+ input += fill;
+ ilen -= fill;
+ left = 0;
+ }
+
+ while (ilen >= 64) {
+ utils_sha1_process(ctx, input);
+ input += 64;
+ ilen -= 64;
+ }
+
+ if (ilen > 0) {
+ memcpy((void *)(ctx->buffer + left), input, ilen);
+ }
+}
+
+static const unsigned char iot_sha1_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+/*
+ * SHA-1 final digest
+ */
+void utils_sha1_finish(iot_sha1_context *ctx, unsigned char output[20])
+{
+ uint32_t last, padn;
+ uint32_t high, low;
+ unsigned char msglen[8];
+
+ high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
+ low = (ctx->total[0] << 3);
+
+ IOT_SHA1_PUT_UINT32_BE(high, msglen, 0);
+ IOT_SHA1_PUT_UINT32_BE(low, msglen, 4);
+
+ last = ctx->total[0] & 0x3F;
+ padn = (last < 56) ? (56 - last) : (120 - last);
+
+ utils_sha1_update(ctx, iot_sha1_padding, padn);
+ utils_sha1_update(ctx, msglen, 8);
+
+ IOT_SHA1_PUT_UINT32_BE(ctx->state[0], output, 0);
+ IOT_SHA1_PUT_UINT32_BE(ctx->state[1], output, 4);
+ IOT_SHA1_PUT_UINT32_BE(ctx->state[2], output, 8);
+ IOT_SHA1_PUT_UINT32_BE(ctx->state[3], output, 12);
+ IOT_SHA1_PUT_UINT32_BE(ctx->state[4], output, 16);
+}
+
+/*
+ * output = SHA-1( input buffer )
+ */
+void utils_sha1(const unsigned char *input, size_t ilen, unsigned char output[20])
+{
+ iot_sha1_context ctx;
+
+ utils_sha1_init(&ctx);
+ utils_sha1_starts(&ctx);
+ utils_sha1_update(&ctx, input, ilen);
+ utils_sha1_finish(&ctx, output);
+ utils_sha1_free(&ctx);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/apps/common/third_party_profile/common/3th_profile_api.c b/apps/common/third_party_profile/common/3th_profile_api.c
new file mode 100644
index 0000000..fa55e93
--- /dev/null
+++ b/apps/common/third_party_profile/common/3th_profile_api.c
@@ -0,0 +1,115 @@
+#include
+#include
+#include
+
+#include "typedef.h"
+#include "3th_profile_api.h"
+#include "bt_tws.h"
+#include "key_event_deal.h"
+#include "system/timer.h"
+#include "bt_common.h"
+#include "btstack/avctp_user.h"
+#include "os/os_api.h"
+
+#if BT_FOR_APP_EN
+
+#if (OTA_TWS_SAME_TIME_ENABLE && RCSP_ADV_EN && USER_APP_EN)
+#include "rcsp_adv_tws_ota.h"
+#endif
+
+#if (OTA_TWS_SAME_TIME_ENABLE && SMART_BOX_EN)
+#include "smartbox_update_tws.h"
+#else
+#include "update_tws.h"
+#endif
+
+static u8 mic_data_type = SOURCE_TYPE;
+static u8 connect_type = TYPE_NULL;
+static u8 tws_ble_type = TYPE_NULL;
+
+void mic_set_data_source(u8 data_type)
+{
+ mic_data_type = data_type;
+}
+
+u8 mic_get_data_source(void)
+{
+ return mic_data_type;
+}
+
+u8 get_ble_connect_type(void)
+{
+ return tws_ble_type;
+}
+
+void set_ble_connect_type(u8 type)
+{
+ tws_ble_type = type;
+}
+
+u8 get_app_connect_type(void)
+{
+ return connect_type;
+}
+
+void set_app_connect_type(u8 type)
+{
+ connect_type = type;
+}
+
+
+#if TCFG_USER_TWS_ENABLE
+
+int tws_data_to_sibling_send(u8 opcode, u8 *data, u8 len)
+{
+ u8 send_data[len + 2];
+ printf(">>>>>>>>>>send data to sibling \n");
+ send_data[0] = opcode;
+ send_data[1] = len;
+ memcpy(send_data + 2, data, len);
+
+ return tws_api_send_data_to_sibling(send_data, sizeof(send_data), TWS_FUNC_ID_AI_SYNC);
+}
+
+static void __ai_tws_rx_from_sibling(u8 *data)
+{
+ u8 opcode = data[0];
+ u8 len = data[1];
+ u8 *rx_data = data + 2;
+
+#if (OTA_TWS_SAME_TIME_ENABLE && (RCSP_BTMATE_EN || RCSP_ADV_EN || SMART_BOX_EN))
+ tws_ota_get_data_from_sibling(opcode, rx_data, len);
+#endif
+
+ free(data);
+}
+
+static void ai_tws_rx_from_sibling(void *_data, u16 len, bool rx)
+{
+ int err = 0;
+ if (rx) {
+ printf(">>>%s \n", __func__);
+ printf("len :%d\n", len);
+ put_buf(_data, len);
+ u8 *rx_data = malloc(len);
+ memcpy(rx_data, _data, len);
+
+ int msg[4];
+ msg[0] = (int)__ai_tws_rx_from_sibling;
+ msg[1] = 1;
+ msg[2] = (int)rx_data;
+ err = os_taskq_post_type("app_core", Q_CALLBACK, 3, msg);
+ if (err) {
+ printf("tws rx post fail\n");
+ }
+ }
+}
+
+//发送给对耳
+REGISTER_TWS_FUNC_STUB(app_vol_sync_stub) = {
+ .func_id = TWS_FUNC_ID_AI_SYNC,
+ .func = ai_tws_rx_from_sibling,
+};
+
+#endif
+#endif
diff --git a/apps/common/third_party_profile/common/3th_profile_api.h b/apps/common/third_party_profile/common/3th_profile_api.h
new file mode 100644
index 0000000..be54a51
--- /dev/null
+++ b/apps/common/third_party_profile/common/3th_profile_api.h
@@ -0,0 +1,34 @@
+
+
+#ifndef _3TH_PROFILE_API_H
+#define _3TH_PROFILE_API_H
+
+#include
+#include
+#include "le_common.h"
+
+
+#define TYPE_NULL 0
+#define TYPE_BLE 1
+#define TYPE_SPP 2
+
+#define TYPE_MASTER_BLE 3
+#define TYPE_SLAVE_BLE 4
+
+#define TYPE_MASTER_SPP 5
+#define TYPE_SLAVE_SPP 6
+
+#define SOURCE_TYPE 0
+#define SINK_TYPE_MASTER 1
+#define SINK_TYPE_SLAVE 2
+
+void set_app_connect_type(u8 type);
+u8 get_app_connect_type(void);
+u8 get_ble_connect_type(void);
+void set_ble_connect_type(u8 type);
+void mic_set_data_source(u8 data_type);
+u8 mic_get_data_source(void);
+
+int tws_data_to_sibling_send(u8 opcode, u8 *data, u8 len); //发送数据给对耳
+
+#endif
diff --git a/apps/common/third_party_profile/common/custom_cfg.c b/apps/common/third_party_profile/common/custom_cfg.c
new file mode 100644
index 0000000..36f9be0
--- /dev/null
+++ b/apps/common/third_party_profile/common/custom_cfg.c
@@ -0,0 +1,1485 @@
+#include "custom_cfg.h"
+#include "app_config.h"
+
+#if RCSP_BTMATE_EN
+#include "rcsp_user_update.h"
+#include "rcsp_bluetooth.h"
+#elif RCSP_ADV_EN
+#include "rcsp_adv_user_update.h"
+#include "rcsp_adv_bluetooth.h"
+#elif SMART_BOX_EN
+#include "smartbox_adv_bluetooth.h"
+#endif
+
+#if AI_APP_PROTOCOL
+#include "app_protocol_api.h"
+#endif
+
+#if RCSP_ADV_EN || RCSP_BTMATE_EN || SMART_BOX_EN || APP_PROTOCOL_READ_CFG_EN
+#include "app_config.h"
+#include "fs.h"
+//#include "crc_api.h"
+//#include "syd_file.h"
+#include "uart.h"
+#include
+
+#if 0
+#pragma code_seg(".custom_cfg_code")
+#pragma bss_seg(".custom_cfg_bss")
+#pragma const_seg(".custom_cfg_const")
+#endif
+
+#define CFG_DEBUG_TAG "-[CFG]:"
+//#define RES_CUSTOM_CFG_FILE "/config.***"
+#define RES_CUSTOM_CFG_FILE SDFILE_RES_ROOT_PATH"config.dat"
+
+//配置:VM的接口采用692X还是693X
+#define VM_API_AC692X 0
+#define VM_API_AC693X 1
+#define USE_VM_API_SEL VM_API_AC693X
+
+//配置:是否在总是擦除EXIF区域然后重写,还是只有在EXIF信息有变化时才擦除
+#define ALWAYS_ERASE_EXIF_AREA 0
+#define ONLY_DIFF_ERASE_EXIF_AREA 1
+#define EXIF_ERASE_CONFIG ALWAYS_ERASE_EXIF_AREA
+
+//配置:文件操作接口是用692X还是693X
+#define SDFILE_API_AC692X 0
+#define SDFILE_API_AC693X 1
+#define USE_FS_API_SEL SDFILE_API_AC693X
+
+
+#define CUSTOM_CFG_DEBUG_EN 1
+#if CUSTOM_CFG_DEBUG_EN
+#define cfg_puts puts
+#define cfg_printf printf
+#define cfg_printf_buf put_buf
+#else
+#define cfg_puts(...)
+#define cfg_printf(...)
+#define cfg_printf_buf(...)
+#endif
+
+typedef struct _exif_info_t {
+ u32 addr;
+ u32 len;
+} exif_info_t;
+
+static exif_info_t exif_info;
+
+#define MEMBER_OFFSET_OF_STRUCT(type, member) ((u32)&(((type *)0)->member))
+#define MEMBER_SIZE_OF_STRUCT(type,member) ((u16)sizeof(((type *)0)->member))
+
+typedef struct _adv_data_t {
+ u16 crc;
+ u16 len;
+ u8 data[31];
+} adv_data_cfg_t;
+
+typedef struct _ble_name_t {
+ u16 crc;
+ u16 len;
+ u8 data[31 - 2];
+} ble_name_t;
+
+typedef struct _bt_name_t {
+ u16 crc;
+ u16 len;
+ u8 data[31];
+} bt_name_t;
+
+typedef struct _bt_pin_code_t {
+ u16 crc;
+ u16 len;
+ char data[4];
+} bt_pin_code_t;
+
+typedef struct _ver_info_cfg_t {
+ u16 crc;
+ u16 len;
+ update_file_id_t data;
+} ver_info_cfg_t;
+
+typedef struct _reset_io_info_cfg_t {
+ u16 crc;
+ u16 len;
+ u8 data;
+} reset_io_info_cfg_t;
+
+typedef struct _polit_lamp_io_info_cfg_t {
+ u16 crc;
+ u16 len;
+ u8 data[4];
+} pilot_lamp_io_info_cfg_t;
+
+typedef struct _link_key_info_cfg_t {
+ u16 crc;
+ u16 len;
+ update_file_link_key_t data;
+} link_key_info_cfg_t;
+
+typedef struct _last_device_connect_linkkey_cfg_t {
+ u16 crc;
+ u16 len;
+ u8 data[16];
+} last_device_connect_linkkey_cfg_t;
+
+typedef struct LOW_POWER_VOLTAGE {
+ u16 crc;
+ u16 len;
+ u8 data[2];
+} low_power_voltage_t;
+
+typedef struct _bt_addr_cfg_t {
+ u16 crc;
+ u16 len;
+ u8 data[6];
+} bt_addr_cfg_t;
+
+typedef struct _gatt_profile_cfg_t {
+ u16 crc;
+ u16 len;
+ u8 data[512 + 256];
+} gatt_profile_cfg_t;
+
+typedef struct _power_io_on_off_cfg_t {
+ u16 crc;
+ u16 len;
+ u8 data[6];
+} power_io_on_off_cfg_t;
+
+#if VER_INFO_EXT_COUNT
+typedef struct _ver_info_ext_cfg_t {
+ u16 crc;
+ u16 len;
+ u8 data[VER_INFO_EXT_MAX_LEN];
+} ver_info_ext_cfg_t;
+#endif
+
+typedef struct _read_write_uuid_cfg_t {
+ u16 crc;
+ u16 len;
+ u8 data[4];
+} read_write_uuid_cfg_t;
+
+typedef struct _common_cfg_t {
+ u16 crc;
+ u16 len;
+ u8 data[0];
+} common_cfg_t;
+
+typedef struct _pid_vid_cfg_t {
+ u16 crc;
+ u16 len;
+ u8 data[4];
+} pid_vid_cfg_t;
+
+typedef struct _authkey_cfg_t {
+ u16 crc;
+ u16 len;
+ u8 data[32];
+} authkey_cfg_t;
+
+typedef struct _project_code_cfg_t {
+ u16 crc;
+ u16 len;
+ u8 data[32];
+} project_code_cfg_t;
+
+typedef struct _md5_cfg_t {
+ u16 crc;
+ u16 len;
+ u8 data[32];
+} md5_cfg_t;
+
+typedef struct _sdk_type_cfg_t {
+ u16 crc;
+ u16 len;
+ u8 data;
+} sdk_type_cfg_t;
+
+typedef struct _ex_cfg_t {
+ adv_data_cfg_t adv_data_cfg;
+ adv_data_cfg_t scan_rsp_cfg;
+ ble_name_t ble_name_cfg;
+ bt_name_t bt_name_cfg;
+ bt_pin_code_t pin_code_cfg;
+ ver_info_cfg_t ver_info_cfg;
+ low_power_voltage_t low_power_voltage_cfg;
+ bt_addr_cfg_t edr_addr_cfg;
+ bt_addr_cfg_t ble_addr_cfg;
+ gatt_profile_cfg_t gatt_profile_cfg;
+ reset_io_info_cfg_t reset_io_info_cfg;
+ pilot_lamp_io_info_cfg_t pilot_lamp_io_info_cfg;
+ link_key_info_cfg_t link_key_info_cfg;
+ power_io_on_off_cfg_t power_io_on_off_cfg;
+ last_device_connect_linkkey_cfg_t last_device_connect_linkkey_cfg;
+ read_write_uuid_cfg_t ble_read_write_uuid_cfg;
+#if VER_INFO_EXT_COUNT
+ ver_info_ext_cfg_t ver_info_authkey_cfg;
+ ver_info_ext_cfg_t ver_info_procode_cfg;
+#endif
+ pid_vid_cfg_t pid_vid_cfg;
+ md5_cfg_t md5_cfg;
+ sdk_type_cfg_t sdk_type_cfg;
+} ex_cfg_t;
+
+typedef union _ex_cfg_item_u {
+ adv_data_cfg_t adv_data_cfg;
+ adv_data_cfg_t scan_rsp_cfg;
+ ble_name_t ble_name_cfg;
+ bt_name_t bt_name_cfg;
+ bt_pin_code_t pin_code_cfg;
+ ver_info_cfg_t ver_info_cfg;
+ low_power_voltage_t low_power_voltage_cfg;
+ bt_addr_cfg_t edr_addr_cfg;
+ bt_addr_cfg_t ble_addr_cfg;
+ gatt_profile_cfg_t gatt_profile_cfg;
+ reset_io_info_cfg_t reset_io_info_cfg;
+ pilot_lamp_io_info_cfg_t pilot_lamp_io_info_cfg;
+ link_key_info_cfg_t link_key_info_cfg;
+ power_io_on_off_cfg_t power_io_on_off_cfg;
+ last_device_connect_linkkey_cfg_t last_device_connect_linkkey_cfg;
+ read_write_uuid_cfg_t ble_read_write_uuid_cfg;
+#if VER_INFO_EXT_COUNT
+ ver_info_ext_cfg_t ver_info_authkey_cfg;
+ ver_info_ext_cfg_t ver_info_procode_cfg;
+#endif
+ common_cfg_t common_cfg;
+ pid_vid_cfg_t pid_vid_cfg;
+ md5_cfg_t md5_cfg;
+ sdk_type_cfg_t sdk_type_cfg;
+} ex_cfg_item_u;
+
+typedef struct _cfg_item_head_t {
+ u16 index;
+ u16 type;
+ u32 addr;
+ u32 len;
+ u16 crc;
+ u16 rfu;
+ u8 name[16];
+} cfg_item_head_t;
+
+typedef struct _cfg_head_t {
+ u8 flag[4];
+ u16 self_crc;
+ u16 item_head_crc;
+ u32 len;
+ u16 item_count;
+ u16 rfu;
+ u8 name[16];
+} cfg_head_t;
+
+typedef enum _cfg_err_type_t {
+ CFG_ERR_NONE = 0,
+ CFG_ERR_FILE_INDEX_ERR,
+ CFG_ERR_FILE_SEEK_ERR,
+ CFG_ERR_FILE_READ_ERR,
+ CFG_ERR_ITEM_LEN_OVER,
+ CFG_ERR_ITEM_NO_FOUND,
+} cfg_err_type_t;
+
+typedef struct _cfg_item_description {
+ u8 *item_name;
+ u8 *item_data;
+ u16 item_len;
+ u16 *real_len;
+} cfg_item_description_t;
+
+typedef struct _update_file_id_cfg {
+ u16 len;
+ update_file_id_t data;
+} update_file_id_cfg_t;
+
+static update_file_id_cfg_t update_id_cfg = {
+ .len = 0,
+};
+
+typedef struct _update_file_reset_io_cfg {
+ u16 len;
+ update_file_reset_io_t data;
+} update_file_reset_io_cfg_t;
+
+static update_file_reset_io_cfg_t update_reset_io_cfg = {
+ .len = 0,
+};
+
+typedef struct _update_file_pilot_lamp_io_cfg {
+ u16 len;
+ update_file_pilot_lamp_io_t data;
+} update_file_pilot_lamp_io_cfg_t;
+
+static update_file_pilot_lamp_io_cfg_t update_pilot_lamp_io_cfg = {
+ .len = 0,
+};
+
+typedef struct _update_file_link_key_cfg {
+ u16 len;
+ update_file_link_key_t data;
+} update_file_link_key_cfg_t;
+
+static update_file_link_key_cfg_t update_link_cfg = {
+ .len = 0,
+};
+
+typedef struct _update_file_power_io_on_off_cfg {
+ u16 len;
+ u8 data[16];
+} update_file_power_io_on_off_cfg_t;
+
+static update_file_power_io_on_off_cfg_t update_power_io_on_off_cfg = {
+ .len = 0,
+};
+
+#if VER_INFO_EXT_COUNT
+typedef struct _update_file_ver_info_ext_cfg {
+ u16 len;
+ u8 data[VER_INFO_EXT_COUNT * (VER_INFO_EXT_MAX_LEN + 1)]; // authkey + , + procode + '\0'
+} update_file_ver_info_ext_cfg_t;
+
+static update_file_ver_info_ext_cfg_t update_file_ver_info_ext_cfg = {
+ .len = 0,
+};
+#endif
+
+static const cfg_item_description_t cfg_item_description[] = {
+ [0] = {
+ (u8 *)"ver_info", (u8 *) &update_id_cfg.data, sizeof(update_id_cfg.data), &update_id_cfg.len
+ },
+ [1] = {
+ (u8 *)"reset_io", (u8 *) &update_reset_io_cfg.data, sizeof(update_reset_io_cfg.data), &update_reset_io_cfg.len
+ },
+ [2] = {
+ (u8 *)"pilot_lamp_io", (u8 *) &update_pilot_lamp_io_cfg.data, sizeof(update_pilot_lamp_io_cfg.data), &update_pilot_lamp_io_cfg.len
+ },
+ [3] = {
+ (u8 *)"link_key", (u8 *) &update_link_cfg.data, sizeof(update_link_cfg.data), &update_link_cfg.len
+ },
+ [4] = {
+ (u8 *)"power_io", (u8 *) &update_power_io_on_off_cfg.data, sizeof(update_power_io_on_off_cfg.data), &update_power_io_on_off_cfg.len
+ },
+#if VER_INFO_EXT_COUNT
+ [5] = {
+ (u8 *)"ver_info_ext", (u8 *) &update_file_ver_info_ext_cfg.data, sizeof(update_file_ver_info_ext_cfg.data), &update_file_ver_info_ext_cfg.len
+ },
+#endif
+};
+
+typedef enum _FLASH_ERASER {
+ CHIP_ERASER,
+ BLOCK_ERASER,
+ SECTOR_ERASER,
+} FLASH_ERASER;
+#if (USE_VM_API_SEL == VM_API_AC692X)
+#include "flash_api.h"
+#elif (USE_VM_API_SEL == VM_API_AC693X)
+extern bool sfc_erase(FLASH_ERASER cmd, u32 addr);
+extern u32 sfc_write(const u8 *buf, u32 addr, u32 len);
+extern u32 sfc_read(u8 *buf, u32 addr, u32 len);
+static void vm_read_by_addr(u8 *buf, u32 addr, u32 len)
+{
+ sfc_read(buf, addr, len);
+}
+
+static u32 vm_write_by_addr(u8 *buf, u32 addr, u32 len)
+{
+ return sfc_write(buf, addr, len);
+}
+
+#endif
+
+
+
+extern u32 fs_open_file_bypath_offest(void *dev_hdl, void *buf, u16 len, char *path, u32 offset);
+
+u32 get_cfg_data_connect_by_name(u8 *name, u8 *data, u16 len, u16 *real_len)
+{
+ cfg_item_head_t cfg_item_head;
+ cfg_head_t cfg_head;
+ u32 err = CFG_ERR_NONE;
+ u32 r_len;
+ u16 i;
+ *real_len = 0;
+ u32 offset = 0;
+
+#if (USE_FS_API_SEL == SDFILE_API_AC692X)
+ DEV_HANDLE dev = cache;
+ u32 file_err;
+ file_err = fs_open_file_bypath_offest(dev, &cfg_head, sizeof(cfg_head_t), RES_CUSTOM_CFG_FILE, offset);
+ if (0 == file_err) {
+ err = CFG_ERR_FILE_READ_ERR;
+ goto _ERR_RET;
+ }
+#elif (USE_FS_API_SEL == SDFILE_API_AC693X)
+ FILE *fp = NULL;
+ fp = fopen(RES_CUSTOM_CFG_FILE, "r");
+ if (!fp) {
+ cfg_puts("file open fail");
+ err = CFG_ERR_FILE_READ_ERR;
+ goto _ERR_RET;
+ }
+ r_len = fread(fp, (void *)&cfg_head, sizeof(cfg_head_t));
+ if (r_len != sizeof(cfg_head_t)) {
+ cfg_puts("file read cfg head fail\n");
+ err = CFG_ERR_FILE_READ_ERR;
+ goto _ERR_RET;
+ }
+#endif
+
+ offset += sizeof(cfg_head_t);
+ cfg_printf("read file req_len:%x ret_len:%x\n", sizeof(cfg_head_t), cfg_head.len);
+ cfg_puts("cfg_head:\n");
+ cfg_printf_buf((u8 *)&cfg_head, sizeof(cfg_head_t));
+
+ for (i = 0; i < cfg_head.item_count; i++) {
+#if (USE_FS_API_SEL == SDFILE_API_AC692X)
+ file_err = fs_open_file_bypath_offest(dev, &cfg_item_head, sizeof(cfg_item_head_t), RES_CUSTOM_CFG_FILE, offset);
+#elif (USE_FS_API_SEL == SDFILE_API_AC693X)
+ fseek(fp, SEEK_SET, offset);
+ r_len = fread(fp, (void *)&cfg_item_head, sizeof(cfg_item_head_t));
+ if (r_len != sizeof(cfg_item_head_t)) {
+ cfg_puts("file read cfg item head fail\n");
+ err = CFG_ERR_FILE_READ_ERR;
+ goto _ERR_RET;
+ }
+#endif
+ offset += sizeof(cfg_item_head_t);
+ if (0 == memcmp(cfg_item_head.name, name, strlen((const char *)name))) {
+ cfg_printf("find item %d name:%s\n", i, cfg_item_head.name);
+ cfg_printf_buf((u8 *)&cfg_item_head, sizeof(cfg_item_head_t));
+ offset = cfg_item_head.addr;
+ if (len < cfg_item_head.len) {
+ err = CFG_ERR_ITEM_LEN_OVER;
+ break;
+ }
+ *real_len = cfg_item_head.len;
+#if (USE_FS_API_SEL == SDFILE_API_AC692X)
+ fs_open_file_bypath_offest(dev, data, cfg_item_head.len, RES_CUSTOM_CFG_FILE, offset);
+#elif (USE_FS_API_SEL == SDFILE_API_AC693X)
+ fseek(fp, offset, SEEK_SET);
+ r_len = fread(fp, data, cfg_item_head.len);
+ if (r_len != cfg_item_head.len) {
+ cfg_puts("read cfg item content fail\n");
+ err = CFG_ERR_FILE_READ_ERR;
+ goto _ERR_RET;
+ }
+#endif
+ break;
+ }
+ }
+
+ if (i == cfg_head.item_count) {
+ err = CFG_ERR_ITEM_NO_FOUND;
+ }
+
+_ERR_RET:
+ return err;
+}
+
+void ex_cfg_read_flash_by_addr(u8 *buf, u32 addr, u32 len)
+{
+ vm_read_by_addr(buf, exif_info.addr + addr, len);
+}
+
+extern u16 CRC16(const void *ptr, u32 len);
+static u16 crc16(u8 *buf, u16 len)
+{
+ return CRC16(buf, len);
+}
+
+typedef struct _cfg_item_attr_t {
+ u16 item_len;
+ u16 data_len;
+ u16 member_offset;
+} cfg_item_attr_t;
+
+static const cfg_item_attr_t cfg_item_attr_tab[] = {
+ [CFG_ITEM_ADV_IND] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, adv_data_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, adv_data_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, adv_data_cfg),
+ },
+ [CFG_ITEM_SCAN_RSP] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, scan_rsp_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, scan_rsp_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, scan_rsp_cfg),
+ },
+ [CFG_ITEM_BLE_NAME] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, ble_name_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, ble_name_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, ble_name_cfg),
+ },
+ [CFG_ITEM_BT_NAME] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, bt_name_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, bt_name_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, bt_name_cfg),
+ },
+ [CFG_ITEM_PIN_CODE] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, pin_code_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, pin_code_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, pin_code_cfg),
+ },
+ [CFG_ITEM_VER_INFO] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, ver_info_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, ver_info_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, ver_info_cfg),
+ },
+ [CFG_ITEM_LOW_POWER_VOLTAGE] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, low_power_voltage_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, low_power_voltage_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, low_power_voltage_cfg),
+ },
+ [CFG_ITEM_EDR_ADDR] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, edr_addr_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, edr_addr_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, edr_addr_cfg),
+ },
+ [CFG_ITEM_BLE_ADDR] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, ble_addr_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, ble_addr_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, ble_addr_cfg),
+ },
+ [CFG_ITEM_GATT_PROFILE] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, gatt_profile_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, gatt_profile_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, gatt_profile_cfg),
+ },
+ [CFG_ITEM_RESET_IO_INFO] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, reset_io_info_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, reset_io_info_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, reset_io_info_cfg),
+ },
+ [CFG_ITEM_PILOT_LAMP_IO_INFO] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, pilot_lamp_io_info_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, pilot_lamp_io_info_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, pilot_lamp_io_info_cfg),
+ },
+ [CFG_ITEM_LINK_KEY_INFO] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, link_key_info_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, link_key_info_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, link_key_info_cfg),
+ },
+ [CFG_ITEM_POWER_IO_ON_OFF] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, power_io_on_off_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, power_io_on_off_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, power_io_on_off_cfg),
+ },
+ [CFG_ITEM_LAST_DEVICE_LINK_KEY_INFO] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, last_device_connect_linkkey_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, last_device_connect_linkkey_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, last_device_connect_linkkey_cfg),
+ },
+ [CFG_ITEM_BLE_READ_WRITE_UUID_INFO] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, ble_read_write_uuid_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, ble_read_write_uuid_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, ble_read_write_uuid_cfg),
+ },
+#if VER_INFO_EXT_COUNT
+ [CFG_ITEM_VER_INFO_AUTHKEY] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, ver_info_authkey_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, ver_info_authkey_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, ver_info_authkey_cfg),
+ },
+ [CFG_ITEM_VER_INFO_PROCODE] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, ver_info_procode_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, ver_info_procode_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, ver_info_procode_cfg),
+ },
+#endif
+ [CFG_ITEM_PVID] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, pid_vid_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, pid_vid_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, pid_vid_cfg),
+ },
+ [CFG_ITEM_MD5] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, md5_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, md5_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, md5_cfg),
+ },
+ [CFG_ITEM_SDK_TYPE] = {
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, sdk_type_cfg),
+ MEMBER_SIZE_OF_STRUCT(ex_cfg_t, sdk_type_cfg.data),
+ MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, sdk_type_cfg),
+ }
+};
+
+static u32 custom_cfg_item_change_check(u8 type, u8 *new_data, u16 new_data_len, u8 *write_flag)
+{
+ ex_cfg_item_u item_u;
+ u16 item_len = 0;
+ ex_cfg_t *p_ex_cfg = NULL;
+ u32 item_offset = 0;
+ u32 exif_addr = exif_info.addr;
+
+ u32 err = 0;
+
+ if (type > sizeof(cfg_item_attr_tab) / sizeof(cfg_item_attr_tab[0])) {
+ err = -2;
+ goto _ERR_RET;
+ }
+
+ u32 data_len = cfg_item_attr_tab[type].data_len;
+
+ if (item_len < new_data_len) {
+ err = -1;
+ goto _ERR_RET;
+ }
+
+ item_len = cfg_item_attr_tab[type].item_len;
+ item_offset = cfg_item_attr_tab[type].member_offset;
+
+ vm_read_by_addr((u8 *)&item_u.common_cfg, exif_addr + item_offset, item_len);
+
+ if ((item_u.common_cfg.len == new_data_len) && \
+ (0 == memcmp((u8 *)&item_u.common_cfg.data, new_data, new_data_len))) {
+ *write_flag = 0;
+ } else {
+ *write_flag = 1;
+ }
+
+#if 0
+ switch (type) {
+ case CFG_ITEM_ADV_IND:
+ item_len = sizeof(p_ex_cfg->adv_data_cfg.data);
+ if (item_len < new_data_len) {
+ err = -1;
+ goto _ERR_RET;
+ }
+ item_offset = MEMBER_OFFSET_OF_STRUCT(ex_cfg_t, adv_data_cfg);
+ vm_read_by_addr((u8 *)&item_u.adv_data_cfg, exif_addr + item_offset, sizeof(adv_data_cfg_t));
+ if ((item_u.adv_data_cfg.len == new_data_len) && \
+ (0 == memcmp((u8 *)&item_u.adv_data_cfg.data, new_data, new_data_len))) {
+ *write_flag = 0;
+ } else {
+ *write_flag = 1;
+ }
+ break;
+ case CFG
+ }
+#endif
+ _ERR_RET:
+ return err;
+}
+static u32 custom_cfg_item_write(u8 type, u8 *data, u16 data_len)
+{
+ ex_cfg_item_u item_u;
+ u16 item_len = 0;
+ ex_cfg_t *p_ex_cfg = NULL;
+ u32 item_offset = 0;
+ u32 exif_addr = exif_info.addr;
+
+ u32 err = 0;
+
+ if (type > sizeof(cfg_item_attr_tab) / sizeof(cfg_item_attr_tab[0])) {
+ err = -2;
+ goto _ERR_RET;
+ }
+
+ u32 item_data_len = cfg_item_attr_tab[type].data_len;
+
+ if (item_data_len < data_len) {
+ err = -1;
+ goto _ERR_RET;
+ }
+
+ item_len = cfg_item_attr_tab[type].item_len;
+ item_offset = cfg_item_attr_tab[type].member_offset;
+
+ vm_read_by_addr((u8 *)&item_u.common_cfg, exif_addr + item_offset, item_len);
+ if ((0xffff != item_u.common_cfg.crc) && \
+ (0xffff != item_u.common_cfg.len)) {
+ err = -3;
+ goto _ERR_RET;
+ }
+#if 0
+ vm_read_by_addr((u8 *)&item_u.common_cfg, exif_addr + item_offset, item_len);
+
+ if ((item_u.common_cfg.len == new_data_len) && \
+ (0 == memcmp((u8 *)&item_u.common_cfg.data, new_data, new_data_len))) {
+ *write_flag = 0;
+ } else {
+ *write_flag = 1;
+ }
+#else
+ memset((u8 *)&item_u.common_cfg.data, 0x00, item_data_len);
+ memcpy((u8 *)&item_u.common_cfg.data, data, data_len);
+ item_u.common_cfg.len = data_len;
+ item_u.common_cfg.crc = crc16((u8 *)&item_u.common_cfg.data, data_len);
+
+ vm_write_by_addr((u8 *)&item_u.common_cfg, exif_addr + item_offset, item_len);
+#endif
+
+_ERR_RET:
+ cfg_printf(">>>write item:%x err:%x\n", type, err);
+ return err;
+}
+
+static u32 custom_cfg_fill(ex_cfg_t *user_ex_cfg, u8 *data, u16 data_len, u8 type, u8 *write_flag)
+{
+ u16 len = 0;
+ switch (type) {
+ case CFG_ITEM_ADV_IND:
+ len = sizeof(user_ex_cfg->adv_data_cfg.data);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp(user_ex_cfg->adv_data_cfg.data, data, len)) {
+ *write_flag = 1;
+ memcpy(user_ex_cfg->adv_data_cfg.data, data, len);
+ user_ex_cfg->adv_data_cfg.len = len;
+ user_ex_cfg->adv_data_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy(user_ex_cfg->adv_data_cfg.data, data, len);
+ user_ex_cfg->adv_data_cfg.len = len;
+ user_ex_cfg->adv_data_cfg.crc = crc16(data, len);
+ }
+ break;
+ case CFG_ITEM_SCAN_RSP:
+ len = sizeof(user_ex_cfg->scan_rsp_cfg.data);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp(user_ex_cfg->scan_rsp_cfg.data, data, len)) {
+ *write_flag = 1;
+ memcpy(user_ex_cfg->scan_rsp_cfg.data, data, len);
+ user_ex_cfg->scan_rsp_cfg.len = len;
+ user_ex_cfg->scan_rsp_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy(user_ex_cfg->scan_rsp_cfg.data, data, len);
+ user_ex_cfg->scan_rsp_cfg.len = len;
+ user_ex_cfg->scan_rsp_cfg.crc = crc16(data, len);
+ }
+ break;
+ case CFG_ITEM_BLE_NAME:
+ len = sizeof(user_ex_cfg->ble_name_cfg.data);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp(user_ex_cfg->ble_name_cfg.data, data, len)) {
+ *write_flag = 1;
+ memcpy(user_ex_cfg->ble_name_cfg.data, data, len);
+ user_ex_cfg->ble_name_cfg.len = len;
+ user_ex_cfg->ble_name_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy(user_ex_cfg->ble_name_cfg.data, data, len);
+ user_ex_cfg->ble_name_cfg.len = len;
+ user_ex_cfg->ble_name_cfg.crc = crc16(data, len);
+ }
+ break;
+ case CFG_ITEM_BT_NAME:
+ len = sizeof(user_ex_cfg->bt_name_cfg.data);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp(user_ex_cfg->bt_name_cfg.data, data, len)) {
+ *write_flag = 1;
+ memcpy(user_ex_cfg->bt_name_cfg.data, data, len);
+ user_ex_cfg->bt_name_cfg.len = len;
+ user_ex_cfg->bt_name_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy(user_ex_cfg->bt_name_cfg.data, data, len);
+ user_ex_cfg->bt_name_cfg.len = len;
+ user_ex_cfg->bt_name_cfg.crc = crc16(data, len);
+ }
+ break;
+ case CFG_ITEM_PIN_CODE:
+ len = sizeof(user_ex_cfg->pin_code_cfg.data);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp(user_ex_cfg->pin_code_cfg.data, data, len)) {
+ *write_flag = 1;
+ memcpy(user_ex_cfg->pin_code_cfg.data, data, len);
+ user_ex_cfg->pin_code_cfg.len = len;
+ user_ex_cfg->pin_code_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy(user_ex_cfg->pin_code_cfg.data, data, len);
+ user_ex_cfg->pin_code_cfg.len = len;
+ user_ex_cfg->pin_code_cfg.crc = crc16(data, len);
+ }
+ break;
+ case CFG_ITEM_VER_INFO:
+ len = sizeof(user_ex_cfg->ver_info_cfg.data);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp((u8 *)&user_ex_cfg->ver_info_cfg.data, data, len)) {
+ *write_flag = 1;
+ memcpy((u8 *)&user_ex_cfg->ver_info_cfg.data, data, len);
+ user_ex_cfg->ver_info_cfg.len = len;
+ user_ex_cfg->ver_info_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy((u8 *)&user_ex_cfg->ver_info_cfg.data, data, len);
+ user_ex_cfg->ver_info_cfg.len = len;
+ user_ex_cfg->ver_info_cfg.crc = crc16(data, len);
+ }
+ break;
+ case CFG_ITEM_RESET_IO_INFO:
+ len = sizeof(user_ex_cfg->reset_io_info_cfg.data);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp((u8 *)&user_ex_cfg->reset_io_info_cfg.data, data, len)) {
+ *write_flag = 1;
+ memcpy((u8 *)&user_ex_cfg->reset_io_info_cfg.data, data, len);
+ user_ex_cfg->reset_io_info_cfg.len = len;
+ user_ex_cfg->reset_io_info_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy((u8 *)&user_ex_cfg->reset_io_info_cfg.data, data, len);
+ user_ex_cfg->reset_io_info_cfg.len = len;
+ user_ex_cfg->reset_io_info_cfg.crc = crc16(data, len);
+ }
+ break;
+ case CFG_ITEM_PILOT_LAMP_IO_INFO:
+ len = sizeof(user_ex_cfg->pilot_lamp_io_info_cfg.data);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp(user_ex_cfg->pilot_lamp_io_info_cfg.data, data, len)) {
+ *write_flag = 1;
+ memcpy(user_ex_cfg->pilot_lamp_io_info_cfg.data, data, len);
+ user_ex_cfg->pilot_lamp_io_info_cfg.len = len;
+ user_ex_cfg->pilot_lamp_io_info_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy(user_ex_cfg->pilot_lamp_io_info_cfg.data, data, len);
+ user_ex_cfg->pilot_lamp_io_info_cfg.len = len;
+ user_ex_cfg->pilot_lamp_io_info_cfg.crc = crc16(data, len);
+ }
+ break;
+ case CFG_ITEM_POWER_IO_ON_OFF:
+ len = sizeof(user_ex_cfg->power_io_on_off_cfg.data);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp(user_ex_cfg->power_io_on_off_cfg.data, data, len)) {
+ *write_flag = 1;
+ memcpy(user_ex_cfg->power_io_on_off_cfg.data, data, len);
+ user_ex_cfg->power_io_on_off_cfg.len = len;
+ user_ex_cfg->power_io_on_off_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy(user_ex_cfg->power_io_on_off_cfg.data, data, len);
+ user_ex_cfg->power_io_on_off_cfg.len = len;
+ user_ex_cfg->power_io_on_off_cfg.crc = crc16(data, len);
+ }
+ break;
+ case CFG_ITEM_LINK_KEY_INFO:
+ len = sizeof(user_ex_cfg->link_key_info_cfg.data.link_key);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp(user_ex_cfg->link_key_info_cfg.data.link_key, data, len)) {
+ *write_flag = 1;
+ memcpy(user_ex_cfg->link_key_info_cfg.data.link_key, data, len);
+ user_ex_cfg->link_key_info_cfg.len = len;
+ user_ex_cfg->link_key_info_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy(user_ex_cfg->link_key_info_cfg.data.link_key, data, len);
+ user_ex_cfg->link_key_info_cfg.len = len;
+ user_ex_cfg->link_key_info_cfg.crc = crc16(data, len);
+ }
+ break;
+ case CFG_ITEM_LAST_DEVICE_LINK_KEY_INFO:
+ len = sizeof(user_ex_cfg->last_device_connect_linkkey_cfg.data);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp(user_ex_cfg->last_device_connect_linkkey_cfg.data, data, len)) {
+ *write_flag = 1;
+ memcpy(user_ex_cfg->last_device_connect_linkkey_cfg.data, data, len);
+ user_ex_cfg->last_device_connect_linkkey_cfg.len = len;
+ user_ex_cfg->last_device_connect_linkkey_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy(user_ex_cfg->last_device_connect_linkkey_cfg.data, data, len);
+ user_ex_cfg->last_device_connect_linkkey_cfg.len = len;
+ user_ex_cfg->last_device_connect_linkkey_cfg.crc = crc16(data, len);
+ }
+ break;
+ case CFG_ITEM_LOW_POWER_VOLTAGE:
+ len = sizeof(user_ex_cfg->low_power_voltage_cfg.data);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp(user_ex_cfg->low_power_voltage_cfg.data, data, len)) {
+ *write_flag = 1;
+ memcpy(user_ex_cfg->low_power_voltage_cfg.data, data, len);
+ user_ex_cfg->low_power_voltage_cfg.len = len;
+ user_ex_cfg->low_power_voltage_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy(user_ex_cfg->low_power_voltage_cfg.data, data, len);
+ user_ex_cfg->low_power_voltage_cfg.len = len;
+ user_ex_cfg->low_power_voltage_cfg.crc = crc16(data, len);
+ }
+ break;
+ case CFG_ITEM_EDR_ADDR:
+ len = sizeof(user_ex_cfg->edr_addr_cfg.data);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp(user_ex_cfg->edr_addr_cfg.data, data, len)) {
+ *write_flag = 1;
+ memcpy(user_ex_cfg->edr_addr_cfg.data, data, len);
+ user_ex_cfg->edr_addr_cfg.len = len;
+ user_ex_cfg->edr_addr_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy(user_ex_cfg->edr_addr_cfg.data, data, len);
+ user_ex_cfg->edr_addr_cfg.len = len;
+ user_ex_cfg->edr_addr_cfg.crc = crc16(data, len);
+ }
+ break;
+ case CFG_ITEM_BLE_ADDR:
+ len = sizeof(user_ex_cfg->ble_addr_cfg.data);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp(user_ex_cfg->ble_addr_cfg.data, data, len)) {
+ *write_flag = 1;
+ memcpy(user_ex_cfg->ble_addr_cfg.data, data, len);
+ user_ex_cfg->ble_addr_cfg.len = len;
+ user_ex_cfg->ble_addr_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy(user_ex_cfg->ble_addr_cfg.data, data, len);
+ user_ex_cfg->ble_addr_cfg.len = len;
+ user_ex_cfg->ble_addr_cfg.crc = crc16(data, len);
+ }
+ break;
+ case CFG_ITEM_GATT_PROFILE:
+ len = sizeof(user_ex_cfg->gatt_profile_cfg.data);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp(user_ex_cfg->gatt_profile_cfg.data, data, len)) {
+ *write_flag = 1;
+ memcpy(user_ex_cfg->gatt_profile_cfg.data, data, len);
+ user_ex_cfg->gatt_profile_cfg.len = len;
+ user_ex_cfg->gatt_profile_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy(user_ex_cfg->gatt_profile_cfg.data, data, len);
+ user_ex_cfg->gatt_profile_cfg.len = len;
+ user_ex_cfg->gatt_profile_cfg.crc = crc16(data, len);
+ }
+ break;
+#if VER_INFO_EXT_COUNT
+ case CFG_ITEM_VER_INFO_AUTHKEY:
+ len = sizeof(user_ex_cfg->ver_info_authkey_cfg.data);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp(user_ex_cfg->ver_info_authkey_cfg.data, data, len)) {
+ *write_flag = 1;
+ memcpy(user_ex_cfg->ver_info_authkey_cfg.data, data, len);
+ user_ex_cfg->ver_info_authkey_cfg.len = len;
+ user_ex_cfg->ver_info_authkey_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy(user_ex_cfg->ver_info_authkey_cfg.data, data, len);
+ user_ex_cfg->ver_info_authkey_cfg.len = len;
+ user_ex_cfg->ver_info_authkey_cfg.crc = crc16(data, len);
+ }
+ break;
+ case CFG_ITEM_VER_INFO_PROCODE:
+ len = sizeof(user_ex_cfg->ver_info_procode_cfg.data);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp(user_ex_cfg->ver_info_procode_cfg.data, data, len)) {
+ *write_flag = 1;
+ memcpy(user_ex_cfg->ver_info_procode_cfg.data, data, len);
+ user_ex_cfg->ver_info_procode_cfg.len = len;
+ user_ex_cfg->ver_info_procode_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy(user_ex_cfg->ver_info_procode_cfg.data, data, len);
+ user_ex_cfg->ver_info_procode_cfg.len = len;
+ user_ex_cfg->ver_info_procode_cfg.crc = crc16(data, len);
+ }
+ break;
+#endif
+ case CFG_ITEM_BLE_READ_WRITE_UUID_INFO:
+ len = sizeof(user_ex_cfg->ble_read_write_uuid_cfg.data);
+ len = len > data_len ? data_len : len;
+ if (!(*write_flag)) {
+ if (memcmp(user_ex_cfg->ble_read_write_uuid_cfg.data, data, len)) {
+ *write_flag = 1;
+ memcpy(user_ex_cfg->ble_read_write_uuid_cfg.data, data, len);
+ user_ex_cfg->ble_read_write_uuid_cfg.len = len;
+ user_ex_cfg->ble_read_write_uuid_cfg.crc = crc16(data, len);
+ }
+ } else {
+ memcpy(user_ex_cfg->ble_read_write_uuid_cfg.data, data, len);
+ user_ex_cfg->ble_read_write_uuid_cfg.len = len;
+ user_ex_cfg->ble_read_write_uuid_cfg.crc = crc16(data, len);
+ }
+ break;
+ }
+ return 0;
+}
+#if VER_INFO_EXT_COUNT
+static u32 fill_authkey_procode(ex_cfg_t *user_ex_cfg, u8 *item_data, u16 item_len, u8 *write_flag)
+{
+ if (!item_len) {
+ return 0;
+ }
+ u16 i = 0;
+ u16 index = 0;
+ u8 type = CFG_ITEM_VER_INFO_AUTHKEY;
+ u8 separator = ',';
+ for (; i < item_len && type < CFG_ITEM_VER_INFO_AUTHKEY + VER_INFO_EXT_COUNT; i++) {
+ if (separator == item_data[i]) {
+ custom_cfg_item_write(type, item_data + index, i - index);
+ index = i + 1;
+ type++;
+ } else if (i == item_len - 1) {
+ custom_cfg_item_write(type, item_data + index, item_len - index);
+ }
+ }
+ return 0;
+}
+#endif
+
+static u32 custom_cfg_file_fill(ex_cfg_t *user_ex_cfg, u8 *write_flag)
+{
+ u32 err;
+ u16 i;
+ u8 *item_data;
+ u8 *item_name;
+ u16 item_len;
+ for (i = 0 ; i < sizeof(cfg_item_description) / sizeof(cfg_item_description[0]); i++) {
+ err = get_cfg_data_connect_by_name(cfg_item_description[i].item_name, \
+ cfg_item_description[i].item_data, \
+ cfg_item_description[i].item_len, \
+ cfg_item_description[i].real_len);
+ if (CFG_ERR_NONE != err) {
+ cfg_printf("cfg_item:%d read error:%x\n", i, err);
+ } else {
+ cfg_printf("cfg_name %s\n cfg_len%x\n", cfg_item_description[i].item_name, *(cfg_item_description[i].real_len));
+ cfg_printf_buf((u8 *)cfg_item_description[i].item_data, *(cfg_item_description[i].real_len));
+ }
+ if (cfg_item_description[i].real_len != 0) {
+ item_name = cfg_item_description[i].item_name;
+ item_data = cfg_item_description[i].item_data;
+ item_len = *cfg_item_description[i].real_len;
+ if (0 == strcmp((const char *)item_name, "ver_info")) {
+ custom_cfg_item_write(CFG_ITEM_VER_INFO, item_data, item_len);
+ } else if (0 == strcmp((const char *)item_name, "reset_io")) {
+ custom_cfg_item_write(CFG_ITEM_RESET_IO_INFO, item_data, item_len);
+ } else if (0 == strcmp((const char *)item_name, "pilot_lamp_io")) {
+ custom_cfg_item_write(CFG_ITEM_PILOT_LAMP_IO_INFO, item_data, item_len);
+ } else if (0 == strcmp((const char *)item_name, "link_key")) {
+ custom_cfg_item_write(CFG_ITEM_LINK_KEY_INFO, item_data, item_len);
+ } else if (0 == strcmp((const char *)item_name, "power_io")) {
+ custom_cfg_item_write(CFG_ITEM_POWER_IO_ON_OFF, item_data, item_len);
+ } else if (0 == strcmp((const char *)item_name, "ver_info_ext")) {
+#if VER_INFO_EXT_COUNT
+ custom_cfg_item_write(CFG_ITEM_VER_INFO, item_data, item_len);
+#endif
+ }
+ }
+ }
+ return err;
+}
+
+
+
+extern int ble_at_get_address(u8 *addr);
+//extern char *hook_get_host_name(void);
+extern const char *bt_get_local_name();
+extern const u8 *bt_get_mac_addr();
+//extern char *hook_get_pin_code(void);
+extern const char *bt_get_pin_code();
+//extern void hook_get_mac_addr(u8 *btaddr);
+extern u8 *ble_get_scan_rsp_ptr(u8 *len);
+extern u8 *ble_get_adv_data_ptr(u8 *len);
+extern int le_controller_get_mac(void *addr);
+extern u8 *ble_get_gatt_profile_data(u16 *len);
+extern const char *bt_get_local_name();
+extern u8 *get_last_device_connect_linkkey(u16 *len);
+
+static u32 ex_cfg_fill_content(ex_cfg_t *user_ex_cfg, u8 *write_flag)
+{
+ custom_cfg_file_fill(NULL, write_flag);
+
+ //CFG_ITEM_BT_NAME
+ u8 *host_name = (u8 *)bt_get_local_name();
+ u16 host_name_len = strlen(bt_get_local_name());
+ custom_cfg_item_write(CFG_ITEM_BT_NAME, host_name, host_name_len);
+
+ //CFG_ITEM_EDR_ADDR
+ u8 addr[6];
+ //hook_get_mac_addr(addr);
+ custom_cfg_item_write(CFG_ITEM_EDR_ADDR, bt_get_mac_addr(), sizeof(addr));
+
+ //CFG_ITEM_PIN_CODE
+#if (0 == BT_CONNECTION_VERIFY)
+ u8 pin_code[] = {BT_CONNECTION_VERIFY, VER_INFO_EXT_COUNT, 0, 0};
+ u16 pin_code_len = sizeof(pin_code);
+#else
+ u8 *pin_code = (u8 *)bt_get_pin_code();
+ u16 pin_code_len = strlen(bt_get_pin_code());
+#endif
+ custom_cfg_item_write(CFG_ITEM_PIN_CODE, pin_code, pin_code_len);
+
+
+ //CFG_ITEM_BLE_NAME
+ host_name = bt_get_local_name();
+ host_name_len = strlen(bt_get_local_name());
+ custom_cfg_item_write(CFG_ITEM_BLE_NAME, host_name, host_name_len);
+
+ //CFG_ITEM_BLE_ADDR
+ le_controller_get_mac(addr);
+ //CFG_ITEM_SCAN_RSP
+ u16 len;
+ u8 *item_data = ble_get_scan_rsp_ptr(&len);
+ cfg_printf("get item_data\n");
+ cfg_printf_buf(item_data, len);
+ struct excfg_rsp_payload rsp_payload;
+
+ //New Scan_rsp
+ /*
+ * | len(1 Byte) | type(1 Byte) | data(name_len) |
+ * bt_name_len | 0x9 | name_str |
+ * jl_payloader_len(14) | 0xff | jl_payloader |
+ */
+#if RCSP_ADV_EN || RCSP_BTMATE_EN
+ if (get_rcsp_support_new_reconn_flag()) {
+#else
+ if (0) {
+#endif
+ u8 *rsp_data = malloc(31);
+ u8 i, rsp_len = 0;
+ if (rsp_data) {
+ cfg_printf("[make new rsp data]\n");
+ rsp_payload.vid = 0x05D6;
+ memcpy(rsp_payload.logo, "JLOTA", sizeof("JLOTA"));
+ for (i = 0; i < sizeof(rsp_payload.logo) / 2; i++) {
+ rsp_payload.logo[i] ^= rsp_payload.logo[sizeof(rsp_payload.logo) - i - 1];
+ rsp_payload.logo[sizeof(rsp_payload.logo) - i - 1] ^= rsp_payload.logo[i];
+ rsp_payload.logo[i] ^= rsp_payload.logo[sizeof(rsp_payload.logo) - i - 1];
+ }
+ rsp_payload.version = 0;
+ memcpy(rsp_payload.addr, addr, 6);
+
+ while (i < len) { //如果rsp_data里有名字要把名字也拷贝出来
+ if (*(item_data + 1) == 0x09) { //find HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME:0x09
+ memcpy(rsp_data, item_data, *item_data + 1);
+ rsp_len = *item_data + 1;
+ break;
+ }
+ i += (1 + *item_data);
+ item_data += (1 + *item_data);
+ }
+
+ if (rsp_len + sizeof(struct excfg_rsp_payload) + 2 > 31) {
+ cfg_printf("rsp data overflow!!!\n");
+ } else {
+ *(rsp_data + rsp_len) = sizeof(struct excfg_rsp_payload) + 1; //fill jlpayload
+ *(rsp_data + rsp_len + 1) = 0xff; // HCI_EIR_DATATYPE_MANUFACTURER_SPECIFIC_DATA
+ memcpy(rsp_data + rsp_len + 2, &rsp_payload, sizeof(struct excfg_rsp_payload));
+ rsp_len += (2 + sizeof(struct excfg_rsp_payload));
+ addr[0] += 1; //修改地址,让手机重新发现服务, 这里地址的修改规则可以用户自行设置
+ cfg_printf("new rsp_data:\n");
+ cfg_printf_buf(rsp_data, rsp_len);
+ custom_cfg_item_write(CFG_ITEM_SCAN_RSP, rsp_data, rsp_len);
+ }
+
+ //广播包里有0xff字段也要找出来去掉,小程序判断到adv和rsp有重复字段是会出错
+ u8 new_adv_len = 0;
+ i = 0;
+ item_data = ble_get_adv_data_ptr(&len);
+ while (i < len) { //找出不等于0xff的信息,拷贝到new_adv_data
+ if (*(item_data + 1) != 0xff) {
+ //memcpy(rsp_data, item_data, *item_data + 1);
+ memcpy(rsp_data, item_data, *item_data + 1);
+ new_adv_len += *item_data + 1;
+ }
+ i += (1 + *item_data);
+ item_data += (1 + *item_data);
+ }
+ cfg_printf("new adv_data:\n");
+ cfg_printf_buf(rsp_data, new_adv_len);
+ custom_cfg_item_write(CFG_ITEM_ADV_IND, rsp_data, new_adv_len);
+
+ free(rsp_data);
+ }
+
+ } else {
+ custom_cfg_item_write(CFG_ITEM_SCAN_RSP, item_data, len);
+ }
+ custom_cfg_item_write(CFG_ITEM_BLE_ADDR, addr, sizeof(addr));
+
+ //CFG_ITEM_ADV_IND
+ item_data = ble_get_adv_data_ptr(&len);
+ custom_cfg_item_write(CFG_ITEM_ADV_IND, item_data, len);
+
+ //CFG_ITEM_GATT_PROFILE
+ item_data = ble_get_gatt_profile_data(&len);
+ custom_cfg_item_write(CFG_ITEM_GATT_PROFILE, item_data, len);
+
+
+ //CFG_ITEM_LAST_DEVICE_LINK_KEY_INFO
+ item_data = get_last_device_connect_linkkey(&len);
+ put_buf(item_data, len);
+ custom_cfg_item_write(CFG_ITEM_LAST_DEVICE_LINK_KEY_INFO, item_data, len);
+
+#if VER_INFO_EXT_COUNT
+ u8 authkey_len = 0;
+ u8 *local_authkey_data = NULL;
+ get_authkey_procode_from_cfg_file(&local_authkey_data, &authkey_len, GET_AUTH_KEY_FROM_EX_CFG);
+ custom_cfg_item_write(CFG_ITEM_VER_INFO_AUTHKEY, local_authkey_data, authkey_len);
+
+ u8 procode_len = 0;
+ u8 *local_procode_data = NULL;
+ get_authkey_procode_from_cfg_file(&local_procode_data, &procode_len, GET_PRO_CODE_FROM_EX_CFG);
+
+ custom_cfg_item_write(CFG_ITEM_VER_INFO_PROCODE, local_procode_data, procode_len);
+#endif
+
+ u16 pvid[2] = {0};
+ pvid[0] = get_vid_pid_ver_from_cfg_file(GET_VID_FROM_EX_CFG);
+ pvid[1] = get_vid_pid_ver_from_cfg_file(GET_PID_FROM_EX_CFG);
+
+ custom_cfg_item_write(CFG_ITEM_PVID, pvid, sizeof(pvid));
+
+ u8 md5[32] = {0};
+ FILE *fp = NULL;
+#define RES_MD5_FILE SDFILE_RES_ROOT_PATH"md5.bin"
+ fp = fopen(RES_MD5_FILE, "r");
+ if (fp) {
+ fread(fp, (void *)md5, 32);
+ fclose(fp);
+ }
+ custom_cfg_item_write(CFG_ITEM_MD5, md5, sizeof(md5));
+ u8 sdk_type = 0;
+#if RCSP_ADV_EN || RCSP_BTMATE_EN
+ sdk_type = RCSP_SDK_TYPE;
+#endif
+ custom_cfg_item_write(CFG_ITEM_SDK_TYPE, &sdk_type, sizeof(sdk_type));
+ return 0;
+}
+
+#define TEMP_BUF_LEN 0x20
+static void ex_cfg_write_to_flash(ex_cfg_t *user_ex_cfg)
+{
+ u32 exif_addr = exif_info.addr;
+ u32 exif_len = exif_info.len;
+ u8 empty_flag = 1;
+ u8 temp_buf[TEMP_BUF_LEN];
+ u16 i;
+
+ cfg_printf("exif_addr : 0x%x, exif_len : %d\n", exif_addr, exif_len);
+
+ if (sizeof(ex_cfg_t) > exif_len) {
+ cfg_printf("-EX_CFG_TOO_LONG:%x\n", sizeof(ex_cfg_t));
+ return ;
+ }
+
+ u16 total_len = sizeof(ex_cfg_t);
+ u16 read_len = sizeof(temp_buf);
+
+ while (total_len) {
+ u16 len = total_len > read_len ? read_len : total_len;
+ vm_read_by_addr(temp_buf, exif_addr, len);
+
+ for (i = 0; i < sizeof(temp_buf); i++) {
+ if (temp_buf[i] != 0xff) {
+ empty_flag = 0;
+ }
+ }
+ total_len -= len;
+ exif_addr += len;
+ }
+
+ if (empty_flag) {
+ cfg_puts("EX_CFG_AREA EMPTY\n");
+ } else {
+ cfg_puts("EX_CFG_HAD_DATA\n");
+ return;
+ }
+ vm_write_by_addr((u8 *)user_ex_cfg, exif_addr, sizeof(ex_cfg_t));
+}
+
+#define PRINT_EX_CFG_INFO 0
+static void print_user_ex_cfg_info(ex_cfg_t *user_ex_cfg);
+#define EXIF_CFG_PATH SDFILE_APP_ROOT_PATH"exif"
+__attribute__((noinline))
+static void ex_cfg_get_addr_and_len(u32 *addr, u32 *len)
+{
+ FILE *fp = fopen(EXIF_CFG_PATH, "r");
+ if (fp) {
+ cfg_printf("open %s succ", EXIF_CFG_PATH);
+ struct vfs_attr attr = {0};
+ fget_attrs(fp, &attr);
+
+ extern u32 sdfile_cpu_addr2flash_addr(u32 offset);
+ *addr = sdfile_cpu_addr2flash_addr(attr.sclust);
+ *len = attr.fsize;
+ } else {
+
+ cfg_printf("open %s fail", EXIF_CFG_PATH);
+ *addr = 0;
+ *len = 0;
+ }
+
+ cfg_printf(">>>exif addr:%x len:%x\n", *addr, *len);
+}
+
+u32 ex_cfg_get_start_addr(void)
+{
+ u32 start_addr;
+ FILE *fp = fopen(EXIF_CFG_PATH, "r");
+ if (fp) {
+ cfg_printf("open %s succ", EXIF_CFG_PATH);
+ struct vfs_attr attr = {0};
+ fget_attrs(fp, &attr);
+
+ extern u32 sdfile_cpu_addr2flash_addr(u32 offset);
+ start_addr = sdfile_cpu_addr2flash_addr(attr.sclust);
+ } else {
+
+ cfg_printf("open %s fail", EXIF_CFG_PATH);
+ start_addr = 0;
+ }
+
+ return start_addr;
+}
+
+#define SECOTR_SIZE (4*1024L)
+u32 ex_cfg_fill_content_api(void)
+{
+ ex_cfg_get_addr_and_len(&exif_info.addr, &exif_info.len);
+
+ if (exif_info.addr) {
+ //ex_cfg_read_flash_by_addr((u8 *)&user_ex_cfg, 0, sizeof(ex_cfg_t));
+#if (EXIF_ERASE_CONFIG == ALWAYS_ERASE_EXIF_AREA)
+ if (exif_info.len < SECOTR_SIZE) {
+ puts("exif len less SECOTR_SiZE\n");
+ while (1);
+ }
+
+ sfc_erase(SECTOR_ERASER, exif_info.addr);
+#else
+#error "To do ..."
+#endif
+
+ ex_cfg_fill_content(NULL, NULL);
+ }
+
+ return exif_info.addr;
+}
+u32 ex_cfg_fill_content_api_test(void)
+{
+ return 0;
+}
+
+
+static void print_user_ex_cfg_info(ex_cfg_t *user_ex_cfg)
+{
+#if PRINT_EX_CFG_INFO
+ puts("adv_data_cfg:\n");
+ printf_buf(user_ex_cfg->adv_data_cfg.data, user_ex_cfg->adv_data_cfg.len);
+ puts("scan_rsp_cfg:\n");
+ printf_buf(user_ex_cfg->scan_rsp_cfg.data, user_ex_cfg->scan_rsp_cfg.len);
+ puts("ble_name_cfg:\n");
+ printf_buf(user_ex_cfg->ble_name_cfg.data, user_ex_cfg->ble_name_cfg.len);
+ puts("ble_addr_cfg:\n");
+ printf_buf(user_ex_cfg->ble_addr_cfg.data, user_ex_cfg->ble_addr_cfg.len);
+ puts("bt_name_cfg:\n");
+ printf_buf(user_ex_cfg->bt_name_cfg.data, user_ex_cfg->bt_name_cfg.len);
+ puts("pin_code_cfg:\n");
+ printf_buf((u8 *)user_ex_cfg->pin_code_cfg.data, user_ex_cfg->pin_code_cfg.len);
+ puts("ver_info_cfg:\n");
+ printf_buf((u8 *)&user_ex_cfg->ver_info_cfg.data, user_ex_cfg->ver_info_cfg.len);
+ puts("reset_io_info_cfg:\n");
+ printf_buf((u8 *)&user_ex_cfg->reset_io_info_cfg.data, user_ex_cfg->reset_io_info_cfg.len);
+ puts("pilot_lamp_io_info_cfg:\n");
+ printf_buf(user_ex_cfg->pilot_lamp_io_info_cfg.data, user_ex_cfg->pilot_lamp_io_info_cfg.len);
+ puts("power_io_on_off_cfg:\n");
+ printf_buf(user_ex_cfg->power_io_on_off_cfg.data, user_ex_cfg->power_io_on_off_cfg.len);
+ puts("link_key_info_cfg:\n");
+ printf_buf(user_ex_cfg->link_key_info_cfg.data.link_key, user_ex_cfg->link_key_info_cfg.len);
+ puts("last_device_connect_linkkey_cfg:\n");
+ printf_buf(user_ex_cfg->last_device_connect_linkkey_cfg.data, user_ex_cfg->last_device_connect_linkkey_cfg.len);
+ puts("ver_info_authkey_cfg:\n");
+ printf("len is %x\n", user_ex_cfg->ver_info_authkey_cfg.len);
+ if (0xffff != user_ex_cfg->ver_info_authkey_cfg.len) {
+ printf_buf(user_ex_cfg->ver_info_authkey_cfg.data, user_ex_cfg->ver_info_authkey_cfg.len);
+ }
+ puts("ver_info_procode_cfg:\n");
+ printf("len is %x\n", user_ex_cfg->ver_info_procode_cfg.len);
+ if (0xffff != user_ex_cfg->ver_info_procode_cfg.len) {
+ printf_buf(user_ex_cfg->ver_info_procode_cfg.data, user_ex_cfg->ver_info_procode_cfg.len);
+ }
+ puts("ble_read_write_uuid_cfg:\n");
+ printf("len is %x\n", user_ex_cfg->ble_read_write_uuid_cfg.len);
+ if (0xffff != user_ex_cfg->ble_read_write_uuid_cfg.len) {
+ printf_buf(user_ex_cfg->ble_read_write_uuid_cfg.data, user_ex_cfg->ble_read_write_uuid_cfg.len);
+ }
+ puts("-------------------------\n");
+ puts("new_ex_cfg_info:\n");
+ printf_buf((u8 *)user_ex_cfg, sizeof(ex_cfg_t));
+#endif
+}
+
+void ex_cfg_data_load(void)
+{
+ ex_cfg_t user_ex_cfg;
+ u32 exif_addr = exif_info.addr;
+ vm_read_by_addr((u8 *)&user_ex_cfg, exif_addr, sizeof(ex_cfg_t));
+ cfg_puts("user_ex_cfg:\n");
+ cfg_printf_buf((u8 *)&user_ex_cfg, sizeof(ex_cfg_t));
+}
+
+u16 get_vid_pid_ver_from_cfg_file(u8 type)
+{
+ u8 *item_name = cfg_item_description[0].item_name;
+ u8 *item_data = cfg_item_description[0].item_data;
+ u16 item_len = cfg_item_description[0].item_len;
+ u16 *real_len = cfg_item_description[0].real_len;
+ if (!(*real_len)) {
+ get_cfg_data_connect_by_name(item_name, item_data, item_len, real_len);
+ }
+ switch (type) {
+ case GET_VID_FROM_EX_CFG:
+ return ((u16)item_data[0] << 8 | (u16)item_data[1]);
+ case GET_PID_FROM_EX_CFG:
+ return ((u16)item_data[2] << 8 | (u16)item_data[3]);
+ case GET_VER_FROM_EX_CFG:
+ return ((u16)item_data[4] << 8 | (u16)item_data[5]);
+ }
+
+ return ((u16) - 1);
+}
+
+#if VER_INFO_EXT_COUNT
+u32 get_authkey_procode_from_cfg_file(u8 *data[], u8 *len, u8 type)
+{
+ u8 *item_name = cfg_item_description[5].item_name;
+ u8 *item_data = cfg_item_description[5].item_data;
+ u16 item_len = cfg_item_description[5].item_len;
+ u16 *real_len = cfg_item_description[5].real_len;
+ if (!(*real_len)) {
+ get_cfg_data_connect_by_name(item_name, item_data, item_len, real_len);
+ }
+ u8 offset = (u8) - 1;
+ u8 index = 0;
+ u8 separator = ',';
+ while (item_data[++offset]) {
+ if (separator == item_data[offset]) {
+ if (type - GET_AUTH_KEY_FROM_EX_CFG) {
+ index = offset;
+ type --;
+ } else {
+ break;
+ }
+ }
+ }
+ if (!item_data[offset]) {
+ index ++;
+ }
+ *data = item_data + index;
+ *len = offset - index;
+ return 0;
+}
+#endif
+
+#endif
+
+
diff --git a/apps/common/third_party_profile/common/custom_cfg.h b/apps/common/third_party_profile/common/custom_cfg.h
new file mode 100644
index 0000000..8508d3e
--- /dev/null
+++ b/apps/common/third_party_profile/common/custom_cfg.h
@@ -0,0 +1,114 @@
+#ifndef _CUSTOM_CFG_H_
+#define _CUSTOM_CFG_H_
+
+#include "typedef.h"
+//#include "hw_cpu.h"
+#include
+#include "app_config.h"
+
+#define BT_CONNECTION_VERIFY 0 // 0是校验,1是不校验
+
+#if (JL_EARPHONE_APP_EN && RCSP_UPDATE_EN)
+#define VER_INFO_EXT_COUNT 2 //2
+#else
+#define VER_INFO_EXT_COUNT 0 //2
+#endif
+#define VER_INFO_EXT_MAX_LEN 24
+
+enum {
+ CFG_ITEM_ADV_IND = 0,
+ CFG_ITEM_SCAN_RSP,
+ CFG_ITEM_BLE_NAME,
+ CFG_ITEM_BT_ADDR,
+
+ CFG_ITEM_BT_NAME = 4,
+ CFG_ITEM_PIN_CODE,
+ CFG_ITEM_VER_INFO,
+ CFG_ITEM_LOW_POWER_VOLTAGE,
+
+ CFG_ITEM_EDR_ADDR = 8,
+ CFG_ITEM_BLE_ADDR,
+ CFG_ITEM_GATT_PROFILE,
+ CFG_ITEM_RESET_IO_INFO,
+
+ CFG_ITEM_PILOT_LAMP_IO_INFO = 12,
+ CFG_ITEM_LINK_KEY_INFO,
+ CFG_ITEM_POWER_IO_ON_OFF,
+ CFG_ITEM_LAST_DEVICE_LINK_KEY_INFO,
+
+ CFG_ITEM_BLE_READ_WRITE_UUID_INFO = 16,
+#if VER_INFO_EXT_COUNT
+ CFG_ITEM_VER_INFO_AUTHKEY,
+ CFG_ITEM_VER_INFO_PROCODE,
+#endif
+ CFG_ITEM_PVID, //供loader使用
+ CFG_ITEM_MD5,
+ CFG_ITEM_SDK_TYPE,
+};
+
+enum {
+ EX_CFG_ERR_NONE = 0,
+ EX_CFG_INDEX_ERR,
+ EX_CFG_LEN_ERR,
+};
+
+enum {
+ GET_VID_FROM_EX_CFG = 0,
+ GET_PID_FROM_EX_CFG,
+ GET_VER_FROM_EX_CFG,
+#if VER_INFO_EXT_COUNT
+ GET_AUTH_KEY_FROM_EX_CFG,
+ GET_PRO_CODE_FROM_EX_CFG,
+#endif
+};
+
+typedef struct _update_file_id {
+ u8 vid[2];
+ u8 pid[2];
+ u8 ver[2];
+ u8 len[4];
+ u8 reserve[4];
+ u8 crc[2];
+} update_file_id_t;
+
+typedef struct _update_file_ext_id {
+ update_file_id_t update_file_id_info;
+#if VER_INFO_EXT_COUNT
+ u8 ext[VER_INFO_EXT_COUNT * (VER_INFO_EXT_MAX_LEN * 2)];
+#endif
+} update_file_ext_id_t;
+
+typedef struct _update_file_reset_io {
+ u8 io_num;
+ u8 resever[15];
+} update_file_reset_io_t;
+
+typedef struct _update_file_pilot_lamp_io {
+ u8 pilot_lamp_io[16];
+} update_file_pilot_lamp_io_t;
+
+typedef struct _update_file_link_key {
+ u8 link_key[16];
+} update_file_link_key_t;
+
+struct excfg_rsp_payload {
+ u16 vid;
+ u8 logo[5];
+ u8 version;
+ u8 addr[6];
+};
+//u32 custom_cfg_file_init(void);
+//void ex_cfg_write_to_flash(void);
+//u32 ex_cfg_fill_content_api(u8 cfg_index, u8 *data, u16 len);
+u32 ex_cfg_fill_content_api(void);
+u16 get_vid_pid_ver_from_cfg_file(u8 type);
+#if VER_INFO_EXT_COUNT
+u32 get_authkey_procode_from_cfg_file(u8 *data[], u8 *len, u8 type);
+#endif
+
+#if RCSP_UPDATE_EN
+extern int rcsp_update_msg[10];
+#endif
+
+#endif
+
diff --git a/apps/common/third_party_profile/common/mic_rec.c b/apps/common/third_party_profile/common/mic_rec.c
new file mode 100644
index 0000000..8d8d8e0
--- /dev/null
+++ b/apps/common/third_party_profile/common/mic_rec.c
@@ -0,0 +1,391 @@
+/*****************************************************************
+>file name : mic_rec.c
+>author : lichao
+>create time : Wed 26 Jun 2019 04:31:50 PM CST
+*****************************************************************/
+#include "system/includes.h"
+#include "media/includes.h"
+#include "app_config.h"
+#include "audio_config.h"
+#include "classic/tws_local_media_sync.h"
+#include "3th_profile_api.h"
+#include "classic/tws_api.h"
+#include "btstack/avctp_user.h"
+#include "bt_tws.h"
+
+#if (BT_MIC_EN)
+
+#define LOG_TAG "[MIC_REC]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+enum {
+ STANDARD_OPUS = 0 << 6,
+ KUGOU_OPUS = 1 << 6,
+};
+
+enum {
+ ENC_OPUS_16KBPS = 0,
+ ENC_OPUS_32KBPS = 1,
+ ENC_OPUS_64KBPS = 2,
+};
+
+typedef struct __ai_encode_info {
+ const u8 *info;
+ u32 enc_type;
+ u8 opus_type;
+ u16(*sender)(u8 *buf, u16 len);
+} _ai_encode_info;
+
+struct __speech_buf_ctl {
+ cbuffer_t cbuffer;
+ volatile u8 speech_init_flg;
+ u16 cbuf_size;
+ u8 *speech_cbuf;
+};
+
+struct __mic_rec_t {
+ struct __speech_buf_ctl buf_ctl;
+ struct __ai_encode_info ai_enc_info;
+ u8 ai_mic_busy_flg;
+ u8 init_ok;
+ u16 frame_num;
+ u16 frame_size;
+ OS_MUTEX mutex_ai_mic;
+};
+static struct __mic_rec_t mic_rec;
+#define __this (&mic_rec)
+
+extern void bt_sniff_ready_clean(void);
+bool get_tws_sibling_connect_state(void);
+int a2dp_tws_dec_suspend(void *p);
+void a2dp_tws_dec_resume(void);
+int audio_mic_enc_open(int (*mic_output)(void *priv, void *buf, int len), u32 code_type, u8 ai_type);
+int audio_mic_enc_close();
+static void ai_mic_tws_stop_opus();
+
+static void speech_cbuf_init(void)
+{
+ __this->buf_ctl.speech_init_flg = 1;
+
+ ASSERT(__this->buf_ctl.speech_cbuf == NULL, "speech_cbuf is err\n");
+ __this->buf_ctl.speech_cbuf = malloc(__this->buf_ctl.cbuf_size);
+ ASSERT(__this->buf_ctl.speech_cbuf, "speech_cbuf is not ok\n");
+
+ cbuf_init(&(__this->buf_ctl.cbuffer), __this->buf_ctl.speech_cbuf, __this->buf_ctl.cbuf_size);
+}
+
+static void speech_cbuf_exit(void)
+{
+ __this->buf_ctl.speech_init_flg = 0;
+ cbuf_clear(&(__this->buf_ctl.cbuffer));
+
+ free(__this->buf_ctl.speech_cbuf);
+ __this->buf_ctl.speech_cbuf = NULL;
+}
+
+static u16 speech_data_send(u8 *buf, u16 len, u16(*send_data)(u8 *buf, u16 len))
+{
+ u16 res = 0;
+ u16 send_len = __this->frame_num * len;
+ u8 temp_buf[send_len];
+
+ if (__this->buf_ctl.speech_init_flg == 0) {
+ return 0;
+ }
+
+ if (cbuf_write(&(__this->buf_ctl.cbuffer), buf, len) != len) {
+ res = (u16)(-1);
+ }
+
+ /* printf("cl %d\n",cbuf_get_data_size(&(__this->buf_ctl.cbuffer))); */
+
+ while (cbuf_get_data_size(&(__this->buf_ctl.cbuffer)) >= send_len) {
+ cbuf_read_alloc_len(&(__this->buf_ctl.cbuffer), temp_buf, send_len);
+ if (send_data) {
+ if (!send_data(temp_buf, send_len)) {
+ putchar('S');
+ cbuf_read_alloc_len_updata(&(__this->buf_ctl.cbuffer), send_len);
+ } else {
+ putchar('E');
+ break;
+ }
+ }
+ }
+
+ return res;
+}
+
+#if TCFG_USER_TWS_ENABLE
+#if 0
+void tws_api_local_media_sync_rx_handler_notify()
+{
+ u8 *tws_buf = NULL;
+ int len = 0;
+
+ if (mic_get_data_source() == SINK_TYPE_SLAVE) {
+ if (dma_tws_mic_pool) {
+ tws_buf = tws_api_local_media_trans_pop(&len);
+ /* log_info("sf %d %0x\n",len, tws_buf); */
+ if (tws_buf) {
+ tws_api_local_media_trans_free(tws_buf);
+ }
+ }
+ }
+}
+
+static u16 tws_data_send_slave_to_master(u8 *buf, u16 len)
+{
+ u8 *tws_buf = NULL;
+
+ if (dma_tws_mic_pool == 0) {
+ return -1;
+ }
+
+ tws_buf = tws_api_local_media_trans_alloc(len);
+ if (tws_buf == NULL) {
+ return -1;
+ }
+ /* log_info("sd %0x %d\n",tws_buf,len); */
+ memcpy(tws_buf, buf, len);
+ /* printf("tdlen\n"); */
+ /* put_buf(tws_buf,len); */
+ tws_api_local_media_trans_push(tws_buf, len);
+ return 0;
+
+}
+#endif
+
+enum {
+ //send to sibling
+ TWS_AI_A2DP_DROP_FRAME_CTL_V2 = 0,
+
+ //tws sync deal
+ TWS_AI_MIC_RESUME_A2DP = 0x80,
+};
+
+static int mic_rec_tws_send_cmd(u8 cmd)
+{
+ return tws_api_send_data_to_sibling(&cmd, sizeof(cmd), 0x3890AB12);
+}
+
+static void __mic_rec_tws_rx_cb_deal(int cmd)
+{
+ switch (cmd) { //tws sync deal
+ case TWS_AI_A2DP_DROP_FRAME_CTL_V2:
+ a2dp_tws_dec_suspend(NULL);
+ break;
+ case TWS_AI_MIC_RESUME_A2DP:
+ ai_mic_tws_stop_opus();
+ break;
+ }
+}
+
+static void mic_rec_tws_rx_data(void *_data, u16 len, bool rx)
+{
+ int msg[4];
+ int err = 0;
+ u8 *data = (u8 *)_data;
+
+ printf(">>>%s \n", __func__);
+ printf("len :%d\n", len);
+ put_buf(_data, len);
+
+ if (!rx && data[0] < TWS_AI_MIC_RESUME_A2DP) { //not need deal
+ return;
+ }
+
+ msg[0] = (int)__mic_rec_tws_rx_cb_deal;
+ msg[1] = 1;
+ msg[2] = *data;
+ err = os_taskq_post_type("app_core", Q_CALLBACK, 3, msg);
+ if (err) {
+ printf("tws rx post fail\n");
+ }
+}
+
+REGISTER_TWS_FUNC_STUB(mic_rec_sync_stub) = {
+ .func_id = 0x3890AB12,
+ .func = mic_rec_tws_rx_data,
+};
+#endif
+
+u16 ai_mic_get_frame_size()
+{
+ return __this->frame_size;
+}
+
+static int rec_enc_output(void *priv, void *buf, int len)
+{
+ bt_sniff_ready_clean();
+
+ u8 *send_buf = (u8 *)buf;
+ int send_len = len;
+
+ //printf("len:%d\n", len);
+ __this->frame_size = len;
+ if (speech_data_send(send_buf, send_len, __this->ai_enc_info.sender) == (u16)(-1)) {
+ log_info("opus data miss !!! line:%d \n", __LINE__);
+ }
+
+ return 0;
+}
+
+
+_WEAK_ int a2dp_tws_dec_suspend(void *p)
+{
+ return 0;
+}
+
+
+_WEAK_ void a2dp_tws_dec_resume(void)
+{
+}
+
+_WEAK_ void bt_sniff_ready_clean(void)
+{
+}
+
+_WEAK_ void mic_rec_clock_set(void)
+{
+}
+
+_WEAK_ void mic_rec_clock_recover(void)
+{
+}
+
+int ai_mic_rec_start(void)
+{
+ if (0 == __this->init_ok) {
+ printf("init err\n");
+ return -1;
+ }
+ os_mutex_pend(&__this->mutex_ai_mic, 0);
+
+ if (__this->ai_mic_busy_flg) {
+ os_mutex_post(&__this->mutex_ai_mic);
+ return -1;
+ }
+
+ user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL);
+
+#if TCFG_USER_TWS_ENABLE
+ if (get_tws_sibling_connect_state() && (tws_api_get_role() == TWS_ROLE_MASTER)) {
+ mic_rec_tws_send_cmd(TWS_AI_A2DP_DROP_FRAME_CTL_V2);
+ }
+#endif
+
+ int err = a2dp_tws_dec_suspend(NULL);
+ if (err == 0) {
+ printf("opus init \n");
+
+ mic_rec_clock_set();
+
+ speech_cbuf_init();
+
+ printf("%s \n", __this->ai_enc_info.info);
+ audio_mic_enc_open(rec_enc_output, __this->ai_enc_info.enc_type, __this->ai_enc_info.opus_type);
+ __this->ai_mic_busy_flg = 1;
+ }
+
+ os_mutex_post(&__this->mutex_ai_mic);
+
+ return 0;
+}
+
+int ai_mic_is_busy(void)
+{
+ return __this->ai_mic_busy_flg;
+}
+
+static void ai_mic_tws_stop_opus()
+{
+ if (__this->ai_mic_busy_flg == 0) {
+ a2dp_tws_dec_resume();
+ }
+}
+
+static int ai_mic_resume_a2dp(void)
+{
+ int err = 0;
+ int msg[8];
+ msg[0] = (int)ai_mic_tws_stop_opus;
+ msg[1] = 1;
+ msg[2] = 0;
+
+ while (1) {
+ err = os_taskq_post_type("app_core", Q_CALLBACK, 3, msg);
+ if (err != OS_Q_FULL) {
+ break;
+ }
+ os_time_dly(2);
+ }
+
+ return err;
+}
+
+int ai_mic_rec_close(void)
+{
+ os_mutex_pend(&__this->mutex_ai_mic, 0);
+
+ if (__this->ai_mic_busy_flg) {
+ printf(">>>>opus close: %d, %s\n", cpu_in_irq(), os_current_task());
+ audio_mic_enc_close();
+
+ speech_cbuf_exit();
+
+ mic_rec_clock_recover();
+
+ __this->ai_mic_busy_flg = 0;
+ }
+
+ os_mutex_post(&__this->mutex_ai_mic);
+
+#if TCFG_USER_TWS_ENABLE
+ if ((tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED)) {
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ mic_rec_tws_send_cmd(TWS_AI_MIC_RESUME_A2DP);
+ }
+ } else {
+ /*a2dp_tws_dec_resume();*/
+ ai_mic_resume_a2dp();
+ }
+#else
+ ai_mic_resume_a2dp();
+ /*a2dp_tws_dec_resume();*/
+#endif
+
+ return 0;
+}
+
+static int ai_mic_mutex_init(void)
+{
+ os_mutex_create(&__this->mutex_ai_mic);
+ return 0;
+}
+late_initcall(ai_mic_mutex_init);
+
+int mic_rec_pram_init(/* const char **name, */u32 enc_type, u8 opus_type, u16(*speech_send)(u8 *buf, u16 len), u16 frame_num, u16 cbuf_size)
+{
+ /* __this->ai_enc_info.info = name; */
+ __this->init_ok = 0;
+ if (enc_type == AUDIO_CODING_OPUS && !TCFG_ENC_OPUS_ENABLE) {
+ printf("please enable opus deceder");
+ return -1;
+ } else if (enc_type == AUDIO_CODING_SPEEX && !TCFG_ENC_SPEEX_ENABLE) {
+ printf("please enable speex deceder");
+ return -1;
+ }
+ __this->ai_enc_info.enc_type = enc_type;
+ __this->ai_enc_info.opus_type = opus_type;
+ __this->ai_enc_info.sender = speech_send;
+ __this->frame_num = frame_num;
+ __this->buf_ctl.cbuf_size = cbuf_size;
+ __this->init_ok = 1;
+ return 0;
+}
+#endif
+
diff --git a/apps/common/third_party_profile/interface/app_protocol_api.c b/apps/common/third_party_profile/interface/app_protocol_api.c
new file mode 100644
index 0000000..1f9f401
--- /dev/null
+++ b/apps/common/third_party_profile/interface/app_protocol_api.c
@@ -0,0 +1,1294 @@
+#include
+#include
+#include
+
+#include "system/timer.h"
+#include "system/task.h"
+#include "app_protocol_api.h"
+#include "btstack/avctp_user.h"
+#include "syscfg_id.h"
+#include "system/includes.h"
+#include "bt_tws.h"
+#include "app_protocol_ota.h"
+#include "btstack/third_party/app_protocol_libs_api.h"
+#include "audio_config.h"
+
+#if AI_APP_PROTOCOL
+static int app_protocol_demo_init(int match_id);
+static int app_protocol_ama_init(int match_id);
+static int app_protocol_gma_init(int match_id);
+static int app_protocol_dma_init(int match_id);
+static int app_protocol_tme_init(int match_id);
+static int app_protocol_mma_init(int match_id);
+static int app_protocol_gfps_init(int match_id);
+
+#if 1
+#define APP_PROTOCOL_LOG printf
+#define APP_PROTOCOL_DUMP put_buf
+#else
+#define APP_PROTOCOL_LOG(...)
+#define APP_PROTOCOL_DUMP(...)
+#endif
+
+typedef struct {
+ // linked list - assert: first field
+ void *offset_item;
+ // data is contained in same memory
+ u32 service_record_handle;
+ u8 *service_record;
+} app_protocal_item_t;
+#define AI_RECORD_REGISTER(handler) \
+ const app_protocal_item_t handler sec(.sdp_record_item)
+
+struct app_protocol_info_t {
+ /*配置类接口*/
+ void (*set_product_id)(u32 pid);
+ void (*set_vendor_id)(u32 vid);
+ void (*set_local_version)(u32 vid);
+ void (*set_special_info_group)(void *addr);
+ void (*set_tws_sibling_mac)(void *mac);
+};
+
+struct app_ctrl_operation_t {
+ int(*protocol_init)();
+ int(*protocol_exit)();
+ int(*adv_enable)(int enable);
+ int(*ibeacon_adv)(int sw);
+ int(*regist_wakeup_send)(void *priv, void *cbk);
+ int(*regist_recieve_cbk)(void *priv, void *cbk);
+ int(*latency_enable)(void *priv, u32 enable);
+ int(*send_data)(void *priv, void *buf, u16 len);
+ int(*send_voice_data)(void *buf, u16 len);
+ int(*disconnect)(void *addr);
+ int(*tws_receive_sync_data)(u8 *data, int len);
+ int(*get_auth_state)(void);
+ int(*start_voice_recognition)(int st);
+ int(*update_tws_state_to_lib)(int sta);
+};
+struct callback_register_t {
+ void(*message_handler_regedit)(int (*handler)(int id, int opcode, u8 *data, u32 len));
+ void(*check_some_status_register)(int (*handler)(int state_flag));
+ void(*check_tws_role_is_master_register)(bool (*handler)(void));
+ void(*tx_resume)(void (*handler)(void));
+ void(*rx_resume)(void (*handler)(void));
+ void(*get_battery)(bool (*handler)(u8 battery_type, u8 *value));
+};
+typedef struct app_protocol {
+ int handler_id;
+ int (*loop)(void);
+ int (*tx_loop)(void);
+ int (*special_message)(int id, int opcode, u8 *data, u32 len);
+ struct app_protocol_info_t *settings;
+ struct app_ctrl_operation_t *app_ctrl;
+ struct callback_register_t *callback;
+} app_protocol_interface_t;
+
+#define MAX_NUMBER_RUN 2
+struct app_protocol_task {
+ app_protocol_interface_t app_p[MAX_NUMBER_RUN];
+ u16 tick_timer;
+ u8 running_protocol_number: 3;
+ u8 run_flag: 1;
+ u8 first_init_flag: 1;
+ u8 reserve: 3;
+};
+struct app_protocol_task g_app;
+#define __this (&g_app)
+static app_protocol_interface_t *current_run_app = NULL;
+
+#define list_for_each_app_protocol(p) \
+ for (p = __this->app_p; p < __this->app_p + MAX_NUMBER_RUN; p++)
+
+
+static app_protocol_interface_t *get_interface_for_id(u32 id)
+{
+ app_protocol_interface_t *app;
+ list_for_each_app_protocol(app) {
+ if (id == app->handler_id) {
+ return app;
+ }
+ }
+ return NULL;
+}
+static int free_interface_for_id(u32 id)
+{
+ app_protocol_interface_t *app;
+ list_for_each_app_protocol(app) {
+ if (id == app->handler_id) {
+ app->handler_id = 0;
+ app->loop = NULL;
+ app->tx_loop = NULL;
+ app->settings = NULL;
+ app->app_ctrl = NULL;
+ app->callback = NULL;
+ return 1;
+ }
+ }
+ return 0;
+}
+static app_protocol_interface_t *get_empty_interface()
+{
+ app_protocol_interface_t *app;
+ list_for_each_app_protocol(app) {
+ if (0 == app->handler_id) {
+ return app;
+ }
+ }
+ return NULL;
+}
+
+/**获取当前协议*/
+u32 app_protocol_get_cur_handle_id()
+{
+ if (current_run_app) {
+ return current_run_app->handler_id;
+ }
+ return 0;
+}
+
+/*设置产品的PID*/
+void app_protocol_set_product_id(u32 handler_id, u32 pid)
+{
+ app_protocol_interface_t *app = get_interface_for_id(handler_id);
+ if (app && app->settings) {
+ if (app->settings->set_product_id) {
+ app->settings->set_product_id(pid);
+ }
+ }
+}
+/*设置产品的VID*/
+void app_protocol_set_vendor_id(u32 handler_id, u32 vid)
+{
+ app_protocol_interface_t *app = get_interface_for_id(handler_id);
+ if (app && app->settings) {
+ if (app->settings->set_vendor_id) {
+ app->settings->set_vendor_id(vid);
+ }
+ }
+}
+
+/*设置产品的version*/
+void app_protocol_set_local_version(u32 handler_id, u32 version)
+{
+ app_protocol_interface_t *app = get_interface_for_id(handler_id);
+ if (app && app->settings) {
+ if (app->settings->set_local_version) {
+ app->settings->set_local_version(version);
+ }
+ }
+}
+
+/*配置协议更多信息,例如GMA的三元组地址*/
+void app_protocol_set_info_group(u32 handler_id, void *addr)
+{
+ app_protocol_interface_t *app = get_interface_for_id(handler_id);
+ if (app && app->settings) {
+ if (app->settings->set_special_info_group) {
+ app->settings->set_special_info_group(addr);
+ }
+ }
+}
+/*配置TWS的地址,app协议用于配置广播包或者命令告知app*/
+void app_protocol_set_tws_sibling_mac(u8 *mac)
+{
+ app_protocol_interface_t *app;
+ list_for_each_app_protocol(app) {
+ if (app->settings) {
+ if (app->settings->set_tws_sibling_mac) {
+ app->settings->set_tws_sibling_mac(mac);
+ }
+ }
+ }
+}
+
+void app_protocol_ibeacon_switch(int sw)
+{
+ app_protocol_interface_t *app;
+ list_for_each_app_protocol(app) {
+ if (app->app_ctrl) {
+ if (app->app_ctrl->ibeacon_adv) {
+ app->app_ctrl->ibeacon_adv(sw);
+ }
+ }
+ }
+}
+void app_protocol_ble_adv_switch(int sw)
+{
+ app_protocol_interface_t *app;
+ list_for_each_app_protocol(app) {
+ if (app->app_ctrl) {
+ if (app->app_ctrl->adv_enable) {
+ app->app_ctrl->adv_enable(sw);
+ }
+ }
+ }
+}
+void app_protocol_disconnect(void *addr)
+{
+ app_protocol_interface_t *app;
+ list_for_each_app_protocol(app) {
+ if (app->app_ctrl) {
+ if (app->app_ctrl->disconnect) {
+ app->app_ctrl->disconnect(addr);
+ }
+ }
+ }
+}
+void app_protocol_get_tws_data_for_lib(u8 *data, u32 len)
+{
+ app_protocol_interface_t *app;
+ list_for_each_app_protocol(app) {
+ if (app->app_ctrl) {
+ if (app->app_ctrl->tws_receive_sync_data) {
+ app->app_ctrl->tws_receive_sync_data(data, len);
+ }
+ }
+ }
+}
+void app_protocal_update_tws_state_to_lib(int state)
+{
+ app_protocol_interface_t *app;
+ list_for_each_app_protocol(app) {
+ if (app->app_ctrl) {
+ if (app->app_ctrl->update_tws_state_to_lib) {
+ app->app_ctrl->update_tws_state_to_lib(state);
+ }
+ }
+ }
+}
+__attribute__((weak))
+bool is_tws_master_role()
+{
+#if TCFG_USER_TWS_ENABLE
+ return (tws_api_get_role() == TWS_ROLE_MASTER);
+#endif
+ return 1;
+}
+
+static int app_get_tws_side()
+{
+ // CHECK_STATUS_TWS_SIDE: /*0是单耳,1是左耳,2是右耳*/
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_local_channel() == 'R') {
+ return 2;
+ } else if (tws_api_get_local_channel() == 'L') {
+ return 1;
+ }
+#endif
+ return 0;
+}
+int app_protocol_check_status(int status_flag)
+{
+ switch (status_flag) {
+ case CHECK_STATUS_TWS_MASTER:
+ return is_tws_master_role();
+ case CHECK_STATUS_TWS_SLAVE:
+ return !is_tws_master_role();
+ case CHECK_STATUS_TWS_PAIR_STA: /*1是tws已经配对了,0是未配对*/
+ if (get_bt_tws_connect_status()) {
+ return true;
+ } else {
+ return false;
+ }
+ case CHECK_STATUS_TWS_SIDE: /*0是单耳,1是左耳,2是右耳*/
+ return app_get_tws_side();
+ }
+ return 0;
+}
+__attribute__((weak))
+bool app_protocol_get_battery(u8 type, u8 *value)
+{
+ for (int i = 0; i < APP_PROTOCOL_BAT_T_MAX; i++) {
+ if (type & BIT(i)) {
+ value[i] = app_protocal_get_bat_by_type(i);
+ }
+ }
+ return 0;
+}
+static void set_mic_rec_param(int id)
+{
+ switch (id) {
+ case TME_HANDLER_ID:
+ mic_rec_pram_init(AUDIO_CODING_OPUS, 1 << 6, app_protocol_send_voice_data, 4, 1024); //TME每4帧加一个头,每帧长度46
+ break;
+ case GMA_HANDLER_ID:
+ mic_rec_pram_init(AUDIO_CODING_OPUS, 0, app_protocol_send_voice_data, 4, 1024);
+ break;
+ case MMA_HANDLER_ID:
+ mic_rec_pram_init(AUDIO_CODING_SPEEX, 0, app_protocol_send_voice_data, 5, 1024); //小米每5帧加一个头,每帧长度42
+ break;
+ default:
+ mic_rec_pram_init(AUDIO_CODING_OPUS, 0, app_protocol_send_voice_data, 4, 1024);
+ break;
+
+ }
+}
+static int app_protocol_message_handler(int id, int opcode, u8 *data, u32 len)
+{
+ static app_protocol_interface_t *message_app = NULL;
+ APP_PROTOCOL_LOG("\napp_protocol_message_handler opcode = %d\n", opcode);
+ int ret = 0;
+ switch (opcode) {
+ case APP_PROTOCOL_CONNECTED_SPP:
+ case APP_PROTOCOL_CONNECTED_BLE:
+ //连接上断开消息的
+ app_protocol_post_bt_event(AI_EVENT_APP_CONNECT, NULL);
+ /* void bt_check_exit_sniff(); */
+ /* bt_check_exit_sniff(); */
+ user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL);
+ current_run_app = get_interface_for_id(id);
+#if APP_PROTOCOL_SPEECH_EN
+ set_mic_rec_param(id);
+#endif
+ printf("APP_PROTOCOL_CONNECT\n");
+ break;
+ case APP_PROTOCOL_DISCONNECT:
+ app_protocol_post_bt_event(AI_EVENT_APP_DISCONNECT, NULL);
+ app_protocol_ota_interrupt_by_disconnect(id);
+ current_run_app = NULL;
+ printf("APP_PROTOCOL_disconnect\n");
+ if (app_protocol_update_success_flag()) {
+ cpu_reset();
+ }
+ break;
+ case APP_PROTOCOL_AUTH_PASS:
+ break;
+ case APP_PROTOCOL_SPEECH_ENCODER_TYPE:
+ break;
+#if APP_PROTOCOL_SPEECH_EN
+ case APP_PROTOCOL_SPEECH_START:
+ APP_PROTOCOL_LOG("app_protocol_speech_start by app\n");
+ ret = app_protocol_start_speech_by_app(1);
+ break;
+ case APP_PROTOCOL_SPEECH_STOP:
+ ret = app_protocol_stop_speech_by_app();
+ break;
+#endif
+ case APP_PROTOCOL_SET_VOLUME:
+ app_protocol_set_volume(data[0]);
+ break;
+ case APP_PROTOCOL_GET_VOLUME:
+ data[0] = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
+ break;
+ case APP_PROTOCOL_LIB_TWS_DATA_SYNC:
+ app_protocol_tws_send_to_sibling(APP_PROTOCOL_TWS_FOR_LIB, data, len);
+ break;
+ default:
+ ret = app_protocol_ota_message_handler(id, opcode, data, len);
+ break;
+ }
+ message_app = get_interface_for_id(id);
+
+ if (message_app) {
+ if (message_app->special_message) {
+ message_app->special_message(id, opcode, data, len);
+ }
+ }
+ return ret;
+}
+
+static void app_protocol_resume(void)
+{
+ if (__this->run_flag == 0) {
+ return ;
+ }
+ os_taskq_post_type(APP_PROTOCOL_TASK_NAME, APP_PROTOCOL_RX_DATA_EVENT, 0, NULL);
+}
+static void app_protocol_send_resume(void)
+{
+ if (__this->run_flag == 0) {
+ return ;
+ }
+ os_taskq_post_type(APP_PROTOCOL_TASK_NAME, APP_PROTOCOL_TX_DATA_EVENT, 0, NULL);
+}
+static void app_protocol_tick_resume(void)
+{
+ app_protocol_resume();///500ms resume for send retry
+}
+static void app_protocol_loop_process(void *parm)
+{
+ int msg[8];
+ int ret;
+ app_protocol_interface_t *app = NULL;
+ __this->tick_timer = sys_timer_add(NULL, app_protocol_tick_resume, 1000);
+ __this->run_flag = 1;
+ APP_PROTOCOL_LOG("app_protocol_loop_process\n");
+ while (1) {
+ ret = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
+ if (ret != OS_TASKQ) {
+ continue;
+ }
+ switch (msg[0]) {
+ case APP_PROTOCOL_RX_DATA_EVENT:
+ list_for_each_app_protocol(app) {
+ if (app->handler_id) {
+ if (app->loop) {
+ app->loop();
+ }
+ }
+ }
+ break;
+ case APP_PROTOCOL_TX_DATA_EVENT:
+ list_for_each_app_protocol(app) {
+ if (app->handler_id) {
+ if (app->tx_loop) {
+ app->tx_loop();
+ }
+ }
+ }
+ break;
+ case APP_PROTOCOL_TASK_EXIT:
+ os_sem_post((OS_SEM *)msg[1]);
+ os_time_dly(10000);
+ break;
+ default:
+ APP_PROTOCOL_LOG("err app protocal msg\n");
+ break;
+ }
+ }
+}
+//可以动态加载选择某个APP协议
+void app_protocol_init(int handler_id)
+{
+ APP_PROTOCOL_LOG("app_protocol_init\n");
+ //如果是第二次调用这个函数,就只起注册协议的作用,不需要重新建立任务
+ if (__this->running_protocol_number < MAX_NUMBER_RUN) {
+#if APP_PROTOCOL_DEMO_CODE
+ if (app_protocol_demo_init(handler_id)) {
+ __this->running_protocol_number++;
+ }
+#endif
+#if APP_PROTOCOL_AMA_CODE
+ if (app_protocol_ama_init(handler_id)) {
+ __this->running_protocol_number++;
+ }
+#endif
+#if APP_PROTOCOL_GMA_CODE
+ if (app_protocol_gma_init(handler_id)) {
+ __this->running_protocol_number++;
+ }
+#endif
+#if APP_PROTOCOL_DMA_CODE
+ if (app_protocol_dma_init(handler_id)) {
+ __this->running_protocol_number++;
+ }
+#endif
+#if APP_PROTOCOL_MMA_CODE
+ if (app_protocol_mma_init(handler_id)) {
+ __this->running_protocol_number++;
+ }
+#endif
+
+#if APP_PROTOCOL_TME_CODE
+ if (app_protocol_tme_init(handler_id)) {
+ __this->running_protocol_number++;
+ }
+#endif
+#if APP_PROTOCOL_GFPS_CODE
+ if (app_protocol_gfps_init(handler_id)) {
+ __this->running_protocol_number++;
+ }
+#endif
+ }
+ if ((__this->running_protocol_number > 0) && __this->first_init_flag == 0) {
+ APP_PROTOCOL_LOG("app_protocol_task create\n");
+ __this->first_init_flag = 1;
+ task_create(app_protocol_loop_process, NULL, APP_PROTOCOL_TASK_NAME);
+ }
+}
+void app_protocol_all_init()
+{
+ app_protocol_init(DEMO_HANDLER_ID);
+ app_protocol_init(DMA_HANDLER_ID);
+ app_protocol_init(MMA_HANDLER_ID);
+ app_protocol_init(GMA_HANDLER_ID);
+ app_protocol_init(TME_HANDLER_ID);
+ app_protocol_init(GFPS_HANDLER_ID);
+}
+/*为了适应以前的参数格式,自定义了一个函数发消息*/
+int app_protocol_post_msg(const char *name, int argc, ...)
+{
+ int ret = 0;
+ int argv[8];
+ APP_PROTOCOL_LOG("mm_task_post_msg\n");
+ va_list argptr;
+ ASSERT(argc < 8);
+ va_start(argptr, argc);
+ for (int i = 0; i < argc; i++) {
+ argv[i] = va_arg(argptr, int);
+ }
+ va_end(argptr);
+ if (argc == 1) {
+ ret = os_taskq_post_type(name, argv[0], 0, NULL);
+ } else {
+ ret = os_taskq_post_type(name, argv[0], argc - 1, &argv[1]);
+ }
+ return ret;
+}
+void app_protocol_exit(int handler_id)
+{
+ //handler_id为0时退出所有,有具体handler值是退出一个
+ OS_SEM sem;
+ app_protocol_interface_t *app;
+ if (handler_id == 0) {
+ list_for_each_app_protocol(app) {
+ if (app->handler_id) {
+ if (app->app_ctrl) {
+ if (app->app_ctrl->protocol_exit) {
+ app->app_ctrl->protocol_exit();
+ }
+ }
+ if (free_interface_for_id(app->handler_id)) {
+ __this->running_protocol_number--;
+ }
+ }
+ }
+ } else {
+ app = get_interface_for_id(handler_id);
+ if (app) {
+ if (app->app_ctrl) {
+ if (app->app_ctrl->protocol_exit) {
+ app->app_ctrl->protocol_exit();
+ }
+ }
+ if (free_interface_for_id(handler_id)) {
+ __this->running_protocol_number--;
+ }
+ }
+ }
+ APP_PROTOCOL_LOG("app_protocol_exit\n");
+ if (__this->run_flag && (!__this->running_protocol_number)) {
+ __this->run_flag = 0;
+ if (__this->tick_timer) {
+ sys_timer_del(__this->tick_timer);
+ __this->tick_timer = 0;
+ }
+ os_sem_create(&sem, 0);
+ os_taskq_post_type(APP_PROTOCOL_TASK_NAME, APP_PROTOCOL_TASK_EXIT, 1, (int *)&sem);
+ os_sem_pend(&sem, 0);
+
+ task_kill(APP_PROTOCOL_TASK_NAME);
+ __this->first_init_flag = 0;
+
+ APP_PROTOCOL_LOG("app_protocol_delete task\n");
+ }
+}
+
+int app_protocol_send_voice_data(uint8_t *voice_buf, uint16_t voice_len)
+{
+ int error = 0;
+ app_protocol_interface_t *app = current_run_app;
+ if (app) {
+ if (app->app_ctrl) {
+ if (app->app_ctrl->send_voice_data) {
+ error = app->app_ctrl->send_voice_data(voice_buf, voice_len);
+ }
+ }
+ return error;
+ }
+ return -1;
+}
+int app_protocol_check_connect_success()
+{
+ int flag = 0;
+ app_protocol_interface_t *app = current_run_app;
+ if (app) {
+ if (app->app_ctrl) {
+ //一般认为只有真正加密完才能说连接完成
+ if (app->app_ctrl->get_auth_state) {
+ flag = app->app_ctrl->get_auth_state();
+ }
+ }
+ }
+ return flag;
+}
+static int app_protocol_start_voice_recognition(int state)
+{
+ int flag = 0;
+ app_protocol_interface_t *app = current_run_app;
+ if (!app) {
+ //做案子的时候百度有时候没连接也有状态更新到蓝牙库
+ app = get_interface_for_id(DMA_HANDLER_ID);
+ }
+ if (app) {
+ if (app->app_ctrl) {
+ //一般认为只有真正加密完才能说连接完成
+ if (app->app_ctrl->start_voice_recognition) {
+ flag = app->app_ctrl->start_voice_recognition(state);
+ }
+ }
+ }
+ return flag;
+}
+int app_protocol_start_speech_cmd()
+{
+ return app_protocol_start_voice_recognition(1);
+}
+int app_protocol_stop_speech_cmd()
+{
+ return app_protocol_start_voice_recognition(0);
+}
+int app_protocol_left_start_speech_cmd()
+{
+ printf("left click");
+ return app_protocol_start_voice_recognition(2);
+}
+int app_protocol_right_start_speech_cmd()
+{
+ printf("right click");
+ return app_protocol_start_voice_recognition(3);
+}
+
+void app_protocol_common_init(app_protocol_interface_t *app)
+{
+#if USER_SUPPORT_PROFILE_SPP
+ extern void user_spp_data_handler(u8 packet_type, u16 ch, u8 * packet, u16 size);
+ spp_data_deal_handle_register(user_spp_data_handler);
+#endif
+#if TCFG_USER_TWS_ENABLE
+ tws_api_auto_role_switch_disable();
+#endif
+ if (app->callback) {
+ if (app->callback->message_handler_regedit) {
+ app->callback->message_handler_regedit(app_protocol_message_handler);
+ }
+ if (app->callback->check_tws_role_is_master_register) {
+ app->callback->check_tws_role_is_master_register(is_tws_master_role);
+ }
+ if (app->callback->check_some_status_register) {
+ app->callback->check_some_status_register(app_protocol_check_status);
+ }
+
+ if (app->callback->tx_resume) {
+ app->callback->tx_resume(app_protocol_send_resume);
+ }
+ if (app->callback->rx_resume) {
+ app->callback->rx_resume(app_protocol_resume);
+ }
+ if (app->callback->get_battery) {
+ app->callback->get_battery(app_protocol_get_battery);
+ }
+ }
+ if (app->app_ctrl) {
+ if (app->app_ctrl->protocol_init) {
+ app->app_ctrl->protocol_init();
+ }
+ }
+
+}
+//**对接具体协议的接口**//
+#if APP_PROTOCOL_DEMO_CODE
+extern int demo_process();
+extern int demo_all_init(void);
+extern int demo_all_exit(void);
+static const struct app_ctrl_operation_t demo_ctrl = {
+ .protocol_init = demo_all_init,
+ .protocol_exit = demo_all_exit,
+};
+static int app_protocol_demo_init(int match_id)
+{
+ if (DEMO_HANDLER_ID != match_id) {
+ return 0;
+ }
+ APP_PROTOCOL_LOG("app_protocol_demo_init\n");
+ app_protocol_interface_t *app = get_interface_for_id(DEMO_HANDLER_ID);
+ if (app) {
+ APP_PROTOCOL_LOG("DEMO_HANDLER_ID init again\n");
+ } else {
+ app = get_empty_interface();
+ if (app) {
+ app->handler_id = DEMO_HANDLER_ID;
+ app->loop = demo_process;
+ app->settings = NULL;
+ app->app_ctrl = &demo_ctrl;
+ app->callback = NULL;
+ app_protocol_common_init(app);
+ APP_PROTOCOL_LOG("DEMO_HANDLER_ID init OK\n");
+ return 1;
+ } else {
+ APP_PROTOCOL_LOG("not support more app protocal\n");
+ }
+ }
+ return 0;
+}
+#endif
+#if APP_PROTOCOL_AMA_CODE
+static int ama_run_loop(void)
+{
+ APP_PROTOCOL_LOG("ama_run_loop\n");
+ return 0;
+}
+static int app_protocol_ama_init(int match_id)
+{
+ if (AMA_HANDLER_ID != match_id) {
+ return 0;
+ }
+ APP_PROTOCOL_LOG("app_protocol_ama_init\n");
+ app_protocol_interface_t *app = get_interface_for_id(AMA_HANDLER_ID);
+ if (app) {
+ APP_PROTOCOL_LOG("AMA_HANDLER_ID init again\n");
+ } else {
+ app = get_empty_interface();
+ if (app) {
+ app->handler_id = AMA_HANDLER_ID;
+ app->loop = ama_run_loop;
+ app->settings = NULL;
+ app->app_ctrl = NULL;
+ app->callback = NULL;
+ APP_PROTOCOL_LOG("AMA_HANDLER_ID init OK\n");
+ return 1;
+ } else {
+ APP_PROTOCOL_LOG("not support more app protocal\n");
+ }
+ }
+ return 0;
+}
+#endif
+#if APP_PROTOCOL_GMA_CODE
+#if TCFG_USER_TWS_ENABLE//GMA_TWS_SUPPORTED
+u8 gma_tws_support = 1;
+#endif
+extern const char *gma_tone_tab[];
+extern struct app_protocol_private_handle_t gma_private_handle;
+extern const u8 sdp_gma_spp_service_data[];
+AI_RECORD_REGISTER(gma_record_item) = {
+ .service_record = (u8 *)sdp_gma_spp_service_data,
+ .service_record_handle = 0x00010035,
+};
+static const struct callback_register_t gma_callback = {
+ .message_handler_regedit = gma_message_callback_register,
+ .check_tws_role_is_master_register = gma_is_tws_master_callback_register,
+ .tx_resume = gma_tx_resume_register,
+ .rx_resume = gma_rx_resume_register,
+ .get_battery = gma_get_battery_callback_register,
+};
+static const struct app_ctrl_operation_t gma_ctrl = {
+ .protocol_init = gma_all_init,
+ .protocol_exit = gma_all_exit,
+ .send_voice_data = gma_opus_voice_mic_send,
+ .get_auth_state = gma_connect_success,
+ .start_voice_recognition = gma_start_voice_recognition,
+ .adv_enable = gma_ble_adv_enable,
+ .ibeacon_adv = gma_ble_ibeacon_adv,
+ .disconnect = gma_disconnect,
+};
+static const struct app_protocol_info_t gma_settings = {
+ .set_special_info_group = gma_set_active_ali_para,
+ .set_tws_sibling_mac = gma_set_sibling_mac_para,
+};
+
+#define GMA_MAIN_NUMBER 0X00
+#define GMA_SECONDARY_NUMBER 0X00
+#define GMA_REVISION_NUMBER 0X01
+
+int app_protocol_gma_get_version(void)
+{
+ return (GMA_MAIN_NUMBER << 16 | GMA_SECONDARY_NUMBER << 8 | GMA_REVISION_NUMBER);
+}
+
+/*
+ *code crc16
+ * */
+static unsigned short wCRCin = 0xFFFF;
+static unsigned short wCPoly = 0x1021;
+
+static unsigned short CRC16_CCITT_FALSE(u16 init_crc, unsigned char *data, unsigned int datalen)
+{
+
+ while (datalen--) {
+ wCRCin ^= *(data++) << 8;
+ for (int i = 0; i < 8; i++) {
+ if (wCRCin & 0x8000) {
+ wCRCin = (wCRCin << 1) ^ wCPoly;
+ } else {
+ wCRCin = wCRCin << 1;
+ }
+ }
+ }
+ return (wCRCin);
+
+}
+
+static void CRC16_CCITT_FALSE_INIT(void)
+{
+ wCRCin = 0xFFFF;
+ wCPoly = 0x1021;
+}
+
+static int CRC16_CODE_RESULT(int calc_crc)
+{
+ return 0;
+}
+
+static int app_protocol_gma_init(int match_id)
+{
+ if (GMA_HANDLER_ID != match_id) {
+ return 0;
+ }
+ APP_PROTOCOL_LOG("app_protocol_gma_init\n");
+ app_protocol_interface_t *app = get_interface_for_id(GMA_HANDLER_ID);
+ if (app) {
+ APP_PROTOCOL_LOG("GMA_HANDLER_ID init again\n");
+ } else {
+ app = get_empty_interface();
+ if (app) {
+ app->handler_id = GMA_HANDLER_ID;
+ app->loop = gma_rx_loop;
+ app->tx_loop = tm_data_send_process_thread;
+ app->settings = &gma_settings;
+ app->app_ctrl = &gma_ctrl;
+ app->callback = &gma_callback;
+ gma_prev_init();
+ app_protocol_tone_register(gma_tone_tab);
+ app_protocol_handle_register(&gma_private_handle);
+ app_protocol_common_init(app);
+ app_protocol_ota_api api = {
+ .ota_request_data = gma_ota_requset_next_packet,
+ .ota_report_result = gma_replay_ota_result,
+ .ota_crc_init_hdl = CRC16_CCITT_FALSE_INIT,
+ .ota_crc_calc_hdl = CRC16_CCITT_FALSE,
+ };
+ app_protocol_ota_init(&api, 0);
+ /* app_protocol_data_api_register(gma_ota_requset_next_packet, gma_replay_ota_result); */
+ /* app_protocol_ota_crc_handler_register( CRC16_CCITT_FALSE_INIT, CRC16_CCITT_FALSE); */
+ APP_PROTOCOL_LOG("GMA_HANDLER_ID init OK\n");
+ return 1;
+ } else {
+ APP_PROTOCOL_LOG("not support more app protocal\n");
+ }
+ }
+ return 0;
+}
+#endif
+
+#if APP_PROTOCOL_DMA_CODE
+//u8 dma_tws_support = 1;
+extern const char *dma_notice_tab[];
+extern const u8 sdp_dueros_spp_service_data[];
+extern const u8 sdp_dueros_ota_service_data[];
+AI_RECORD_REGISTER(dma_record_item) = {
+ .service_record = (u8 *)sdp_dueros_spp_service_data,
+ .service_record_handle = 0x00010036,
+};
+AI_RECORD_REGISTER(dma_ota_record_item) = {
+ .service_record = (u8 *)sdp_dueros_ota_service_data,
+ .service_record_handle = 0x00010037,
+};
+
+static const struct callback_register_t dma_callback = {
+ .message_handler_regedit = dma_message_callback_register,
+ .check_some_status_register = dma_check_status_callback_register,
+ .tx_resume = dma_tx_resume_register,
+ .rx_resume = dma_rx_resume_register,
+ .get_battery = dma_get_battery_callback_register,
+};
+
+static const struct app_ctrl_operation_t dma_ctrl = {
+ .protocol_init = dma_all_init,
+ .protocol_exit = dma_all_exit,
+ .adv_enable = dma_ble_adv_enable,
+ .send_voice_data = dma_speech_data_send,
+ .get_auth_state = dma_pair_state,
+ .start_voice_recognition = dma_start_voice_recognition,
+ .disconnect = dma_disconnect,
+ .update_tws_state_to_lib = dma_update_tws_state_to_lib,
+ .tws_receive_sync_data = dma_tws_data_deal,
+ /*.send_voice_data = dma_opus_voice_mic_send,
+ .adv_enable = dma_ble_adv_enable,*/
+};
+static const struct app_protocol_info_t dma_settings = {
+ .set_product_id = dma_set_pid,
+ .set_special_info_group = dma_set_product_id_key,
+
+};
+static int dueros_special_message(int id, int opcode, u8 *data, u32 len)
+{
+ int ret = 0;
+ switch (opcode) {
+ case APP_PROTOCOL_DMA_SAVE_RAND:
+ APP_PROTOCOL_LOG("APP_PROTOCOL_DMA_SAVE_RAND");
+ //APP_PROTOCOL_DUMP(data, len);
+ ret = syscfg_write(VM_DMA_RAND, data, len);
+ //app_protocol_tws_send_to_sibling(DMA_TWS_ALL_INFO_SYNC, data, len);
+ break;
+ case APP_PROTOCOL_DMA_READ_RAND:
+ APP_PROTOCOL_LOG("APP_PROTOCOL_DMA_READ_RAND");
+ ret = syscfg_read(VM_DMA_RAND, data, len);
+ //APP_PROTOCOL_DUMP(data, len);
+ break;
+ case APP_PROTOCOL_DMA_SAVE_OTA_INFO:
+ APP_PROTOCOL_LOG("APP_PROTOCOL_DMA_SAVE_OTA_INFO");
+ APP_PROTOCOL_DUMP(data, len);
+ //不支持断点续传
+ //ret = syscfg_write(VM_TME_AUTH_COOKIE, data, len);
+ //app_protocol_tws_send_to_sibling(DMA_TWS_OTA_INFO_SYNC, data, len);
+ break;
+ case APP_PROTOCOL_DMA_READ_OTA_INFO:
+ APP_PROTOCOL_LOG("APP_PROTOCOL_DMA_READ_OTA_INFO");
+ //ret = syscfg_read(VM_TME_AUTH_COOKIE, data, len);
+ //不支持断点续传
+ memset(data, 0, len);
+ APP_PROTOCOL_DUMP(data, len);
+ break;
+ case APP_PROTOCOL_DMA_TTS_TYPE:
+ printf("app_protocol_dma_tone_play %d\n", data[0]);
+ //app_protocol_dma_tone_play(data[0], 1);
+ break;
+ }
+ return ret;
+}
+static int app_protocol_dma_init(int match_id)
+{
+ if (DMA_HANDLER_ID != match_id) {
+ return 0;
+ }
+ APP_PROTOCOL_LOG("app_protocol_dma_init\n");
+ app_protocol_interface_t *app = get_interface_for_id(DMA_HANDLER_ID);
+ if (app) {
+ APP_PROTOCOL_LOG("DMA_HANDLER_ID init again\n");
+ } else {
+ app = get_empty_interface();
+ if (app) {
+ app->handler_id = DMA_HANDLER_ID;
+ app->loop = dueros_process;
+ app->tx_loop = dueros_send_process;
+ app->special_message = dueros_special_message;
+ app->settings = &dma_settings;
+ app->app_ctrl = &dma_ctrl;
+ app->callback = &dma_callback;
+ app_protocol_tone_register(dma_notice_tab);
+ dueros_dma_manufacturer_info_init();
+ app_protocol_common_init(app);
+ APP_PROTOCOL_LOG("DMA_HANDLER_ID init OK\n");
+ return 1;
+ } else {
+ APP_PROTOCOL_LOG("not support more app protocal\n");
+ }
+ }
+ return 0;
+}
+#endif
+
+#if APP_PROTOCOL_TME_CODE
+extern const char *tme_notice_tab[APP_RROTOCOL_TONE_MAX];
+extern const u8 sdp_tme_service_data[];
+extern struct app_protocol_private_handle_t tme_private_handle;
+AI_RECORD_REGISTER(tme_record_item) = {
+ .service_record = (u8 *)sdp_tme_service_data,
+ .service_record_handle = 0x00010037,
+};
+
+static const struct callback_register_t tme_callback = {
+ .message_handler_regedit = tme_message_callback_register,
+ .check_tws_role_is_master_register = tme_is_tws_master_callback_register,
+ .tx_resume = tme_tx_resume_register,
+ .rx_resume = tme_rx_resume_register,
+ .get_battery = tme_get_battery_callback_register,
+};
+static const struct app_ctrl_operation_t tme_ctrl = {
+ .protocol_init = tme_all_init,
+ .protocol_exit = tme_all_exit,
+ .adv_enable = tme_ble_adv_enable,
+ .send_voice_data = tme_send_voice_data,
+ .get_auth_state = tme_connect_success,
+ .start_voice_recognition = tme_start_voice_recognition,
+ .disconnect = tme_protocol_disconnect,
+// .ibeacon_adv = gma_ble_ibeacon_adv,
+// int(*regist_wakeup_send)(void *priv, void *cbk);
+// int(*regist_recieve_cbk)(void *priv, void *cbk);
+// int(*latency_enable)(void *priv, u32 enable);
+// int(*send_data)(void *priv, void *buf, u16 len);
+};
+static const struct app_protocol_info_t tme_settings = {
+ .set_special_info_group = tme_set_configuration_info,
+ .set_product_id = tme_set_pid,
+ .set_vendor_id = tme_set_bid,
+ //.set_tws_sibling_mac = gma_set_sibling_mac_para,
+ //void (*set_left_battery)(u8 bat);
+};
+
+#define TME_VERSION {0x00,0x10}//版本号
+static const char version[] = TME_VERSION;
+
+int app_protocol_tme_get_version(void)
+{
+ return (version[0] << 8) | version[1];
+}
+
+
+static int app_protocol_tme_init(int match_id)
+{
+ if (TME_HANDLER_ID != match_id) {
+ return 0;
+ }
+ APP_PROTOCOL_LOG("app_protocol_tme_init\n");
+ app_protocol_interface_t *app = get_interface_for_id(TME_HANDLER_ID);
+ if (app) {
+ APP_PROTOCOL_LOG("TME_HANDLER_ID init again\n");
+ } else {
+ app = get_empty_interface();
+ if (app) {
+ app->handler_id = TME_HANDLER_ID;
+ app->loop = TME_protocol_process;
+ app->tx_loop = TME_send_packet_process;
+ app->settings = &tme_settings;
+ app->app_ctrl = &tme_ctrl;
+ app->callback = &tme_callback;
+ app_protocol_tone_register(tme_notice_tab);
+ app_protocol_handle_register(&tme_private_handle);
+
+ app_protocol_ota_api api = {
+ .ota_request_data = TME_request_ota_data,
+ .ota_report_result = NULL,
+ .ota_crc_init_hdl = NULL,
+ .ota_crc_calc_hdl = NULL,
+ .ota_notify_file_size = TME_notify_file_size,
+ };
+ app_protocol_ota_init(&api, 0);
+
+ app_protocol_common_init(app);
+ APP_PROTOCOL_LOG("TME_HANDLER_ID init OK\n");
+ return 1;
+ } else {
+ APP_PROTOCOL_LOG("not support more app protocal\n");
+ }
+ }
+ return 0;
+}
+#endif
+
+#if APP_PROTOCOL_MMA_CODE
+extern void mma_prev_init();
+extern const char *mma_notice_tab[APP_RROTOCOL_TONE_MAX];
+extern struct app_protocol_private_handle_t mma_private_handle;
+
+static const struct callback_register_t mma_callback = {
+ .message_handler_regedit = mma_message_callback_register,
+ .check_tws_role_is_master_register = mma_is_tws_master_callback_register,
+ .tx_resume = mma_tx_resume_register,
+ .rx_resume = mma_rx_resume_register,
+ .get_battery = mma_get_battery_callback_register,
+};
+
+static const struct app_ctrl_operation_t mma_ctrl = {
+
+ .protocol_init = mma_all_init,
+ .protocol_exit = mma_all_exit,
+ .adv_enable = mma_ble_adv_enable,
+ .send_voice_data = XM_speech_data_send,
+ .get_auth_state = XM_protocal_auth_pass,
+ .start_voice_recognition = mma_start_voice_recognition,
+ .disconnect = mma_disconnect,
+ .tws_receive_sync_data = mma_tws_data_deal,
+};
+static const struct app_protocol_info_t mma_settings = {
+ .set_product_id = mma_set_product_id,
+ .set_vendor_id = mma_set_verdor_id,
+ .set_local_version = mma_set_local_version,
+};
+int mma_special_message(int id, int opcode, u8 *data, u32 len)
+{
+ int ret = 0;
+ switch (opcode) {
+ case APP_PROTOCOL_MMA_SAVE_INFO:
+ APP_PROTOCOL_LOG("APP_PROTOCOL_MMA_SAVE_");
+ APP_PROTOCOL_DUMP(data, len);
+ ret = syscfg_write(VM_DMA_RAND, data, len);
+ break;
+ case APP_PROTOCOL_MMA_READ_INFO:
+ APP_PROTOCOL_LOG("APP_PROTOCOL_mMA_READ_");
+ ret = syscfg_read(VM_DMA_RAND, data, len);
+ APP_PROTOCOL_DUMP(data, len);
+ break;
+ case APP_PROTOCOL_MMA_SAVE_ADV_COUNTER:
+ syscfg_write(VM_TME_AUTH_COOKIE, data, len);
+ break;
+ case APP_PROTOCOL_MMA_READ_ADV_COUNTER:
+ syscfg_read(VM_TME_AUTH_COOKIE, data, len);
+ break;
+ }
+ return ret;
+}
+static int app_protocol_mma_init(int match_id)
+{
+ if (MMA_HANDLER_ID != match_id) {
+ return 0;
+ }
+ APP_PROTOCOL_LOG("app_protocol_mma_init\n");
+ app_protocol_interface_t *app = get_interface_for_id(MMA_HANDLER_ID);
+ if (app) {
+ APP_PROTOCOL_LOG("MMA_HANDLER_ID init again\n");
+ } else {
+ app = get_empty_interface();
+ if (app) {
+ app->handler_id = MMA_HANDLER_ID;
+ app->loop = mma_protocol_loop_process;
+ /*app->tx_loop = ;*/
+ app->special_message = mma_special_message;
+ app->settings = &mma_settings;
+ app->app_ctrl = &mma_ctrl;
+ app->callback = &mma_callback;
+ app_protocol_tone_register(mma_notice_tab);
+
+ app_protocol_ota_api api = {
+ .ota_request_data = mma_request_ota_data,
+ .ota_report_result = mma_report_ota_status,
+ .ota_crc_init_hdl = NULL,
+ .ota_crc_calc_hdl = NULL,
+ .ota_notify_file_size = mma_notify_file_size,
+ };
+ app_protocol_ota_init(&api, 1); //mma需要等待APP来进行复位
+ mma_prev_init();
+ app_protocol_handle_register(&mma_private_handle);
+ app_protocol_common_init(app);
+ APP_PROTOCOL_LOG("mMA_HANDLER_ID init OK\n");
+ return 1;
+ } else {
+ APP_PROTOCOL_LOG("not support more app protocal\n");
+ }
+ }
+ return 0;
+}
+#endif
+#if APP_PROTOCOL_GFPS_CODE
+
+u8 gfp_debug_enable = 0x03; // 打印开关,BIT(0):printf BIT(1):put_buf
+
+#define GFPS_ANC_TRANSPARENT_MODE 0x80
+#define GFPS_OFF_MODE 0x20
+#define GFPS_ANC_MODE 0x08
+#define GFPS_ANC_ALL_MODE (GFPS_ANC_TRANSPARENT_MODE | GFPS_OFF_MODE | GFPS_ANC_MODE)
+extern void gfps_hearable_controls_enable(u8 enable);
+extern void gfps_hearable_controls_update(u8 display_flag, u8 settable_flag, u8 current_state);
+
+extern struct app_protocol_private_handle_t gfps_private_handle;
+extern const u8 sdp_gfp_spp_service_data[];
+AI_RECORD_REGISTER(gfps_record_item) = {
+ .service_record = (u8 *)sdp_gfp_spp_service_data,
+ .service_record_handle = 0x00010039,
+};
+static const struct callback_register_t gfps_callback = {
+ .message_handler_regedit = gfps_message_callback_register,
+ .check_tws_role_is_master_register = gfps_is_tws_master_callback_register,
+ .tx_resume = NULL,
+ .rx_resume = NULL,
+ .get_battery = NULL,
+};
+static const struct app_ctrl_operation_t gfps_ctrl = {
+ .protocol_init = gfps_all_init,
+ .protocol_exit = gfps_all_exit,
+ .adv_enable = gfps_ble_adv_enable,
+ .send_voice_data = NULL,
+ .get_auth_state = NULL,
+ .start_voice_recognition = NULL,
+ .disconnect = gfps_disconnect,
+ .update_tws_state_to_lib = NULL,
+ .tws_receive_sync_data = gfps_tws_data_deal,
+ /*.send_voice_data = gfps_opus_voice_mic_send,
+ .adv_enable = gfps_ble_adv_enable,*/
+};
+static const struct app_protocol_info_t gfps_settings = {
+ .set_product_id = NULL,
+ .set_special_info_group = NULL,
+};
+
+static uint8_t google_model_id_used[3] = {0xF2, 0x63, 0x8D};
+static char google_public_key_used[64] = {
+ 0x5f, 0x17, 0xf0, 0x5a, 0x22, 0x03, 0xe2, 0xdc, 0x93, 0x1d, 0x5c, 0x00, 0xe8, 0xa4, 0x06, 0x7c,
+ 0x3c, 0x09, 0xa0, 0xad, 0x91, 0x82, 0x3e, 0x45, 0xda, 0xe7, 0xe5, 0x2f, 0x5e, 0xe9, 0x80, 0x1b,
+ 0xa6, 0xe2, 0x21, 0x9f, 0x65, 0x85, 0xa8, 0xab, 0x65, 0xf1, 0x47, 0x7e, 0x46, 0x7a, 0xdb, 0xb2,
+ 0x4b, 0x46, 0x72, 0xb8, 0x35, 0x89, 0x0b, 0x99, 0x57, 0xb7, 0x0e, 0xa9, 0x45, 0xe1, 0x7a, 0xbb
+
+};
+static char google_private_key_used[32] = {
+ 0x86, 0x89, 0x57, 0x30, 0xFB, 0x95, 0x8A, 0x9E, 0x42, 0x57, 0x56, 0x97,
+ 0x39, 0x54, 0x77, 0xE7, 0x62, 0x44, 0x7A, 0xA1, 0x2B, 0xDF, 0x35, 0xFE,
+ 0xE9, 0xC5, 0x82, 0x28, 0x1B, 0xD7, 0xF5, 0xBE
+};
+
+static u8 gfps_special_name[2] = "JL";
+
+//lib收到控制消息后,会传消息上来处理
+extern int gfps_message_deal_handler(int id, int opcode, u8 *data, u32 len);
+
+static int app_protocol_gfps_init(int match_id)
+{
+ if (GFPS_HANDLER_ID != match_id) {
+ return 0;
+ }
+ APP_PROTOCOL_LOG("app_protocol_gfps_init\n");
+ app_protocol_interface_t *app = get_interface_for_id(GFPS_HANDLER_ID);
+ if (app) {
+ APP_PROTOCOL_LOG("GFPS_HANDLER_ID init again\n");
+ } else {
+ app = get_empty_interface();
+ if (app) {
+ app->handler_id = GFPS_HANDLER_ID;
+ app->loop = NULL;
+ app->tx_loop = NULL;
+ app->special_message = gfps_message_deal_handler;
+ app->settings = &gfps_settings;
+ app->app_ctrl = &gfps_ctrl;
+ app->callback = &gfps_callback;
+ //update_channel_map_do_in_irq_flag_set(1);
+ gfps_set_anti_spoofing_public_key(google_public_key_used);
+ gfps_set_anti_spoofing_private_key(google_private_key_used);
+ gfps_set_model_id(google_model_id_used);
+#if CONFIG_ANC_ENABLE
+ gfps_hearable_controls_enable(1);
+ gfps_hearable_controls_update(GFPS_ANC_ALL_MODE, GFPS_ANC_ALL_MODE, GFPS_OFF_MODE);
+#endif
+ app_protocol_handle_register(&gfps_private_handle);
+ app_protocol_common_init(app);
+ APP_PROTOCOL_LOG("GFPS_HANDLER_ID init OK\n");
+ return 1;
+ } else {
+ APP_PROTOCOL_LOG("not support more app protocal\n");
+ }
+ }
+ return 0;
+}
+#endif
+
+int app_protocol_get_version_by_id(int id)
+{
+#if APP_PROTOCOL_GMA_CODE
+ if (id == GMA_HANDLER_ID) {
+ return app_protocol_gma_get_version();
+ }
+#endif
+#if APP_PROTOCOL_TME_CODE
+ if (id == TME_HANDLER_ID) {
+ return app_protocol_tme_get_version();
+ }
+#endif
+ return 0;
+}
+
+/* int app_protocol_reply_frame_check_result(int result){ */
+/* if( app_protocol_get_cur_handle_id() == GMA_HANDLER_ID){ */
+/* gma_replay_ota_result(result); */
+/* } */
+/* return 0; */
+/* } */
+
+//编译问题加几个空的
+_WEAK_ void bt_ble_init(void)
+{
+}
+_WEAK_ void bt_ble_exit(void)
+{
+}
+_WEAK_ void bt_ble_adv_enable(void)
+{
+}
+
+#else
+void app_protocol_init(int handler_id)
+{
+}
+void app_protocol_exit(int handler_id)
+{
+}
+#endif
+
diff --git a/apps/common/third_party_profile/interface/app_protocol_api.h b/apps/common/third_party_profile/interface/app_protocol_api.h
new file mode 100644
index 0000000..e830866
--- /dev/null
+++ b/apps/common/third_party_profile/interface/app_protocol_api.h
@@ -0,0 +1,84 @@
+
+
+#ifndef _3TH_PROTOCOL_API_H
+#define _3TH_PROTOCOL_API_H
+
+#include
+#include
+#include "typedef.h"
+#include "os/os_api.h"
+#include "btstack/third_party/app_protocol_event.h"
+#include "app_protocol_common.h"
+
+#define APP_PROTOCOL_TASK_NAME "app_proto"
+
+//定义这几个宏仅仅用于编译优化代码量。需要那个选哪个,flash够大,可以全部都打开的。
+//不要在板级头文件重复定义。
+#define APP_PROTOCOL_DEMO_CODE 0
+#define APP_PROTOCOL_GMA_CODE 0
+#define APP_PROTOCOL_AMA_CODE 0
+#define APP_PROTOCOL_DMA_CODE 0
+#define APP_PROTOCOL_TME_CODE 0
+#define APP_PROTOCOL_MMA_CODE 0
+#define APP_PROTOCOL_GFPS_CODE 1
+
+//#define APP_PROTOCOL_SPEECH_EN 0 //语音助手功能,若无此功能则关掉
+#define APP_PROTOCOL_READ_CFG_EN 0 //从custom.dat中读取配置信息,若无此功能则关掉
+
+#define DEMO_HANDLER_ID 0x300 /*作为一个使用的例子,同时也可作为客户自己添加协议的ID*/
+#define GMA_HANDLER_ID 0x400 /*阿里天猫协议接口ID*/
+#define MMA_HANDLER_ID 0x500 /*小米MMA协议接口ID*/
+#define DMA_HANDLER_ID 0x600 /*百度DMA协议接口ID*/
+#define TME_HANDLER_ID 0x700 /*腾讯酷狗TME协议接口ID*/
+#define AMA_HANDLER_ID 0x800 /*亚马逊的AMA协议接口ID*/
+#define GFPS_HANDLER_ID 0x900 /*谷歌快对的协议接口ID*/
+
+//app os task message
+enum {
+ //Q_USER =0x400000
+ APP_PROTOCOL_RX_DATA_EVENT = (Q_USER + 100),
+ APP_PROTOCOL_TX_DATA_EVENT,
+ APP_PROTOCOL_TASK_EXIT,
+};
+
+//参数配置类接口(在库外面的文件common区)
+//配置在init之前的参数接口
+void app_protocol_set_product_id(u32 handler_id, u32 pid);
+void app_protocol_set_vendor_id(u32 handler_id, u32 vid);
+void app_protocol_set_local_version(u32 handler_id, u32 version);
+void app_protocol_set_info_group(u32 handler_id, void *addr); //如配置三元组
+void app_protocol_tws_role_check_register(u8(*handler)(void)); /*注册获取tws状态的函数接口*/
+void app_protocol_set_tws_sibling_mac(u8 *mac);
+
+
+//公共类函数接口
+/*这个接口主要是建立一个线程,注册一些协议需要用的公共接口,比如resume,message_handler等函数。建立了线程之后,初始化*/
+void app_protocol_all_init();
+void app_protocol_init(int handler_id);
+/*主要是删除线程操作,在删除完之后再释放APP协议栈的资源*/
+void app_protocol_exit(int handler_id);
+/*开始语音识别功能*/
+int app_protocol_start_speech_cmd();
+/*手动停止语音识别功能*/
+int app_protocol_stop_speech_cmd();
+int app_protocol_left_start_speech_cmd();
+int app_protocol_right_start_speech_cmd();
+void app_protocol_update_battery(u8 main, u8 left, u8 right, u8 box);
+void app_protocol_ble_adv_switch(int sw);
+void app_protocol_ibeacon_switch(int sw);
+void app_protocol_disconnect(void *addr);
+void app_protocol_get_tws_data_for_lib(u8 *data, u32 len);
+/*发送mic相应编码后的数据*/
+int app_protocol_send_voice_data(uint8_t *voice_buf, uint16_t voice_len);
+/*获取有没有链路连接完成状态*/
+int app_protocol_check_connect_success();
+bool is_tws_master_role();
+
+u32 app_protocol_get_cur_handle_id();
+
+int app_protocol_get_version_by_id(int id);
+
+int app_protocol_reply_frame_check_result(int result);
+void app_protocal_update_tws_state_to_lib(int state);
+
+#endif
diff --git a/apps/common/third_party_profile/interface/app_protocol_common.c b/apps/common/third_party_profile/interface/app_protocol_common.c
new file mode 100644
index 0000000..ba29300
--- /dev/null
+++ b/apps/common/third_party_profile/interface/app_protocol_common.c
@@ -0,0 +1,774 @@
+#include "app_protocol_api.h"
+#include "app_protocol_common.h"
+#include "system/includes.h"
+#include "app_config.h"
+#include "audio_config.h"
+//#include "app_chargestore.h"
+#include "app_power_manage.h"
+#include "asm/charge.h"
+#include "bt_tws.h"
+#include "btstack/avctp_user.h"
+#include "3th_profile_api.h"
+#include "bt_common.h"
+#include "tone_player.h"
+#include "app_main.h"
+#include "key_event_deal.h"
+
+#if AI_APP_PROTOCOL
+
+#if 1
+#define APP_PROTOCOL_LOG printf
+#define APP_PROTOCOL_DUMP put_buf
+#else
+#define APP_PROTOCOL_LOG(...)
+#define APP_PROTOCOL_DUMP(...)
+#endif
+
+__attribute__((weak))
+void app_protocol_tone_play(int index, int tws_sync)
+{
+
+}
+static const char **app_tone_table = NULL;
+static struct app_protocol_private_handle_t *private_handle;
+
+extern u8 get_remote_dev_company(void);
+#define REMOTE_DEV_ANDROID 1
+#define REMOTE_DEV_IOS 2
+bool is_ios_system(void)
+{
+ APP_PROTOCOL_LOG("remote_dev_company :%d \n", get_remote_dev_company());
+ return (get_remote_dev_company() == REMOTE_DEV_IOS);
+}
+
+void app_protocol_tone_register(const char **tone_table)
+{
+ app_tone_table = tone_table;
+}
+
+const char *app_protocol_get_tone(int index)
+{
+ if (app_tone_table) {
+ return app_tone_table[index];
+ }
+ return NULL;
+}
+
+void app_protocol_handle_register(struct app_protocol_private_handle_t *hd)
+{
+ private_handle = hd;
+}
+
+struct app_protocol_private_handle_t *app_protocol_get_handle()
+{
+ return private_handle;
+}
+
+//协议私有同步消息处理函数
+void app_protocol_tws_sync_private_deal(int cmd, int value)
+{
+ if (private_handle && private_handle->tws_sync_func) {
+ private_handle->tws_sync_func(cmd, value);
+ }
+}
+
+//协议私有收到对耳数据处理函数
+void app_protocol_tws_rx_data_private_deal(u16 opcode, u8 *data, u16 len)
+{
+ if (private_handle && private_handle->tws_rx_from_siblling) {
+ private_handle->tws_rx_from_siblling(opcode, data, len);
+ }
+}
+
+int app_protocol_sys_event_private_deal(struct sys_event *event)
+{
+ if (private_handle && private_handle->sys_event_handler) {
+ return private_handle->sys_event_handler(event);
+ }
+ return 0;
+}
+
+#if APP_PROTOCOL_SPEECH_EN
+#define APP_PROTOCOL_MIC_TIMEOUT 8000 //mic使用超时时间,0不限时
+
+static u16 mic_timer = 0;
+static u16 tone_after_exit_sniff_timer = 0;
+static u8 exit_sniff_cnt = 0;
+void __app_protocol_speech_stop(void)
+{
+ if (ai_mic_is_busy()) {
+ if (mic_timer) {
+ sys_timeout_del(mic_timer);
+ mic_timer = 0;
+ }
+ APP_PROTOCOL_LOG("app_protocol_speech_stop\n");
+
+ ai_mic_rec_close();
+ app_protocol_stop_speech_cmd();
+ }
+}
+
+static void app_protocol_speech_timeout(void *priv)
+{
+ APP_PROTOCOL_LOG(" speech timeout !!! \n");
+ __app_protocol_speech_stop();
+}
+
+static int app_protocol_speech_start_check()
+{
+ if (BT_STATUS_TAKEING_PHONE == get_bt_connect_status()) {
+ APP_PROTOCOL_LOG("phone ing...\n");
+ return -1;
+ }
+ if (ai_mic_is_busy()) {
+ APP_PROTOCOL_LOG("mic activing...\n");
+ return -1;
+ }
+ return 0;
+}
+
+int __app_protocol_speech_start(void)
+{
+ if (!app_protocol_speech_start_check() && ai_mic_rec_start() == 0) {
+#if APP_PROTOCOL_MIC_TIMEOUT
+ mic_timer = sys_timeout_add(NULL, app_protocol_speech_timeout, APP_PROTOCOL_MIC_TIMEOUT);
+#endif
+ return 0;
+ }
+ APP_PROTOCOL_LOG("speech start fail\n");
+ return -1;
+}
+
+int app_protocol_start_speech_by_app(u8 tone_en)
+{
+ if (app_protocol_speech_start_check()) {
+ return -1;
+ }
+ if (app_var.siri_stu) {
+ APP_PROTOCOL_LOG("siri activing...\n");
+ return -1;
+ }
+ if (tone_en) {
+ app_protocol_tone_play(APP_RROTOCOL_TONE_SPEECH_APP_START, 1);
+ } else {
+ app_protocol_post_bt_event(AI_EVENT_SPEECH_START, NULL);
+ }
+ return 0;
+}
+
+int app_protocol_stop_speech_by_app()
+{
+ app_protocol_post_bt_event(AI_EVENT_SPEECH_STOP, NULL);
+ return 0;
+}
+
+static void speech_tone_play_after_exit_sniff()
+{
+ tone_after_exit_sniff_timer = 0;
+ if (bt_is_sniff_close() && exit_sniff_cnt < 13) {
+ exit_sniff_cnt++;
+ tone_after_exit_sniff_timer = sys_timeout_add(NULL, speech_tone_play_after_exit_sniff, 100);
+ return;
+ }
+ exit_sniff_cnt = 0;
+ if (!app_protocol_speech_start_check()) {
+ app_protocol_tone_play(APP_RROTOCOL_TONE_SPEECH_KEY_START, 1);
+ }
+}
+
+int app_protocol_start_speech_by_key(struct sys_event *event)
+{
+#if TCFG_USER_TWS_ENABLE
+ if (get_bt_tws_connect_status() && !is_tws_master_role()) {
+ APP_PROTOCOL_LOG("tws slave, return\n");
+ return 0;
+ }
+#endif
+
+ user_send_cmd_prepare(USER_CTRL_HFP_GET_SIRI_STATUS, 0, NULL);
+ if (app_protocol_speech_start_check()) {
+ return -1;
+ }
+
+ if (app_protocol_check_connect_success() && (get_curr_channel_state()&A2DP_CH)) {
+ printf("no connect\n");
+ } else {
+ if (get_curr_channel_state()&A2DP_CH) {
+ //<协议未连接, 但是A2DP已连接, 点击唤醒键, 提示TTS【请打开小度APP】
+ if (is_ios_system()) {
+ APP_PROTOCOL_LOG("ble adv ibeaconn");
+ app_protocol_ibeacon_switch(1);
+ } else {
+ user_send_cmd_prepare(USER_CTRL_HFP_GET_SIRI_OPEN, 0, NULL);
+ }
+ app_protocol_tone_play(APP_PROTOCOL_TONE_DISCONNECTED_ALL, 1);
+ } else {
+ //<蓝牙完全关闭状态, 用户按唤醒键, 提示TTS【蓝牙未连接, 请用手机蓝牙和我连接吧】
+ app_protocol_tone_play(APP_RROTOCOL_TONE_OPEN_APP, 1);
+ }
+ APP_PROTOCOL_LOG("A2dp or protocol no connect err!!!\n");
+ return -1;
+ }
+
+
+#if 1//等退出sniff后再播提示音
+ if (bt_is_sniff_close()) {
+ user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL);
+ if (tone_after_exit_sniff_timer == 0) {
+ tone_after_exit_sniff_timer = sys_timeout_add(NULL, speech_tone_play_after_exit_sniff, 100);
+ }
+ return 0;
+ }
+ exit_sniff_cnt = 0;
+#endif
+
+ app_protocol_tone_play(APP_RROTOCOL_TONE_SPEECH_KEY_START, 1);
+ return 0;
+}
+
+int app_protocol_stop_speech_by_key(void)
+{
+ return 0;
+}
+#else
+void __app_protocol_speech_stop(void)
+{
+}
+#endif
+
+void app_speech_tone_play_end_callback(void *priv, int flag)
+{
+ u32 index = (u32)priv;
+ switch (index) {
+#if APP_PROTOCOL_SPEECH_EN
+ case APP_RROTOCOL_TONE_SPEECH_KEY_START:
+ APP_PROTOCOL_LOG("APP_RROTOCOL_TONE_SPEECH_KEY_START\n");
+ if (app_protocol_speech_start_check()) {
+ break;
+ }
+ if (app_var.siri_stu) {
+ APP_PROTOCOL_LOG("siri activing...\n");
+ break;
+ }
+ ///按键启动需要report, app启动, 直接启动语音即可
+ if (is_tws_master_role() && !app_protocol_start_speech_cmd()) {//从转发mic数据给主机或主机上报完成开启mic
+ APP_PROTOCOL_LOG("app_protocol_mic_status_report success\n");
+ app_protocol_post_bt_event(AI_EVENT_SPEECH_START, NULL);
+ }
+ break;
+ case APP_RROTOCOL_TONE_SPEECH_APP_START:
+ APP_PROTOCOL_LOG("APP_RROTOCOL_TONE_SPEECH_APP_START\n");
+ if (app_protocol_speech_start_check()) {
+ break;
+ }
+ if (app_var.siri_stu) {
+ APP_PROTOCOL_LOG("siri activing...\n");
+ break;
+ }
+ if (is_tws_master_role()) {
+ app_protocol_post_bt_event(AI_EVENT_SPEECH_START, NULL);
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+int app_protocol_set_volume(u8 vol)
+{
+ u8 vol_l = (vol * get_max_sys_vol()) / 0x64;
+ u8 vol_r = (vol * get_max_sys_vol()) / 0x64;
+
+ app_audio_set_volume(APP_AUDIO_STATE_MUSIC, APP_AUDIO_STATE_MUSIC, vol_r);
+ return 0;
+}
+__attribute__((weak))
+bool vbat_is_low_power(void)
+{
+ return 0;
+}
+u8 app_protocal_get_bat_by_type(u8 type)
+{
+ u8 value = 0;
+ extern u8 get_tws_sibling_bat_persent(void);
+ u8 sibling_val = get_tws_sibling_bat_persent();
+#if TCFG_CHARGESTORE_ENABLE
+ if (sibling_val == 0xff) {
+ sibling_val = chargestore_get_sibling_power_level();
+ }
+#endif
+ switch (type) {
+ case APP_PROTOCOL_BAT_T_CHARGE_FLAG:
+ value = get_charge_online_flag();
+ break;
+ case APP_PROTOCOL_BAT_T_MAIN:
+ value = get_vbat_percent();
+ break;
+#if TCFG_CHARGESTORE_ENABLE
+ case APP_PROTOCOL_BAT_T_BOX:
+ value = chargestore_get_power_level();
+ break;
+#endif
+ case APP_PROTOCOL_BAT_T_TWS_LEFT:
+ value = (tws_api_get_local_channel() == 'L') ? get_vbat_percent() : sibling_val;
+ break;
+ case APP_PROTOCOL_BAT_T_TWS_RIGHT:
+ value = (tws_api_get_local_channel() == 'R') ? get_vbat_percent() : sibling_val;
+ break;
+ case APP_PROTOCOL_BAT_T_TWS_SIBLING:
+ value = sibling_val;
+ break;
+ case APP_PROTOCOL_BAT_T_LOW_POWER:
+ value = vbat_is_low_power();
+ break;
+ default:
+ break;
+ }
+ if (value == 0xff) { //获取不到电量返回0
+ value = 0;
+ }
+ return value;
+}
+
+u32 read_cfg_file(void *buf, u16 len, char *path)
+{
+ FILE *fp = fopen(path, "r");
+ int rlen;
+
+ if (!fp) {
+ //printf("read_cfg_file:fopen err!\n");
+ return FALSE;
+ }
+
+ rlen = fread(fp, buf, len);
+ if (rlen <= 0) {
+ //printf("read_cfg_file:fread err!\n");
+ return FALSE;
+ }
+
+ fclose(fp);
+
+ return TRUE;
+}
+
+#define LIC_PAGE_OFFSET 80
+#define FORCE_TO_ERASE 1
+
+typedef enum _FLASH_ERASER {
+ CHIP_ERASER = 0,
+ BLOCK_ERASER,
+ SECTOR_ERASER,
+ PAGE_ERASER,
+} FLASH_ERASER;
+
+typedef struct __flash_of_lic_para_head {
+ s16 crc;
+ u16 string_len;
+ const u8 para_string[];
+} __attribute__((packed)) _flash_of_lic_para_head;
+
+static bool license_para_head_check(u8 *para)
+{
+ _flash_of_lic_para_head *head;
+
+ //fill head
+ head = (_flash_of_lic_para_head *)para;
+
+ ///crc check
+ u8 *crc_data = (u8 *)(para + sizeof(((_flash_of_lic_para_head *)0)->crc));
+ u32 crc_len = sizeof(_flash_of_lic_para_head) - sizeof(((_flash_of_lic_para_head *)0)->crc)/*head crc*/ + (head->string_len)/*content crc,include end character '\0'*/;
+ s16 crc_sum = 0;
+
+ crc_sum = CRC16(crc_data, crc_len);
+
+ if (crc_sum != head->crc) {
+ printf("license crc error !!! %x %x \n", (u32)crc_sum, (u32)head->crc);
+ return false;
+ }
+
+ return true;
+}
+
+//获取三元组信息的头指针
+const u8 *app_protocal_get_license_ptr(void)
+{
+ u32 flash_capacity = sdfile_get_disk_capacity();
+ u32 flash_addr = flash_capacity - 256 + LIC_PAGE_OFFSET;
+ u8 *lic_ptr = NULL;
+ _flash_of_lic_para_head *head;
+
+ printf("flash capacity:%x \n", flash_capacity);
+ lic_ptr = (u8 *)sdfile_flash_addr2cpu_addr(flash_addr);
+
+ //head length check
+ head = (_flash_of_lic_para_head *)lic_ptr;
+ if (head->string_len >= 0xff) {
+ printf("license length error !!! \n");
+ return NULL;
+ }
+
+ ////crc check
+ if (license_para_head_check(lic_ptr) == (false)) {
+ printf("license head check fail\n");
+ return NULL;
+ }
+
+ //put_buf(lic_ptr, 128);
+
+ lic_ptr += sizeof(_flash_of_lic_para_head);
+ return lic_ptr;
+}
+
+extern bool sfc_erase(int cmd, u32 addr);
+extern u32 sfc_write(const u8 *buf, u32 addr, u32 len);
+//将三元组信息保存到flash里面
+int app_protocol_license2flash(const u8 *data, u16 len)
+{
+ _flash_of_lic_para_head header;
+ u8 buffer[256];
+ u32 flash_capacity = sdfile_get_disk_capacity();
+ u32 sector = flash_capacity - 4 * 1024;
+ u32 page_addr = flash_capacity - 256;
+ u8 *auif_ptr = (u8 *)sdfile_flash_addr2cpu_addr(page_addr);
+
+#if (!FORCE_TO_ERASE)
+ APP_PROTOCOL_LOG("not supported flash erase !!! \n");
+ return (-1);
+#endif
+
+ ///save last 256 byte
+ /* memset(buffer, 0xff, sizeof(buffer)); */
+ memcpy(buffer, auif_ptr, sizeof(buffer));
+ auif_ptr += LIC_PAGE_OFFSET;
+
+ header.string_len = len;
+ ///length
+ memcpy(&buffer[LIC_PAGE_OFFSET + sizeof(header.crc)], &(header.string_len), sizeof(header.string_len));
+ ///context
+ memcpy(&buffer[LIC_PAGE_OFFSET + sizeof(header)], data, len);
+ ///crc
+ header.crc = CRC16(&buffer[LIC_PAGE_OFFSET + sizeof(header.crc)], sizeof(header.string_len) + header.string_len);
+ memcpy(&buffer[LIC_PAGE_OFFSET], &(header.crc), sizeof(header.crc));
+
+ ///check if need update data to flash,erease license erea if there are some informations in license erea
+ if (!memcmp(auif_ptr, buffer + LIC_PAGE_OFFSET, len + sizeof(_flash_of_lic_para_head))) {
+ APP_PROTOCOL_LOG("flash information the same with license\n");
+ return 0;
+ }
+
+ APP_PROTOCOL_LOG("erase license sector \n");
+ sfc_erase(SECTOR_ERASER, sector);
+
+ APP_PROTOCOL_LOG("write license to flash \n");
+ sfc_write(buffer, page_addr, 256);
+
+ return 0;
+}
+
+int app_protocol_tws_send_to_sibling(u16 opcode, u8 *data, u16 len)
+{
+ u8 send_data[len + 4];
+ printf("app protocol send data to sibling \n");
+ send_data[0] = opcode & 0xff;
+ send_data[1] = opcode >> 8;
+ send_data[2] = len & 0xff;
+ send_data[3] = len >> 8;
+ memcpy(send_data + 4, data, len);
+
+ return tws_api_send_data_to_sibling(send_data, sizeof(send_data), APP_PROTOCOL_TWS_SEND_ID);
+}
+
+static void __tws_rx_from_sibling(u8 *data)
+{
+ u16 opcode = (data[1] << 8) | data[0];
+ u16 len = (data[3] << 8) | data[2];
+ u8 *rx_data = data + 4;
+
+ switch (opcode) {
+ case APP_PROTOCOL_TWS_FOR_LIB:
+ APP_PROTOCOL_LOG("APP_PROTOCOL_TWS_FOR_LIB");
+ app_protocol_get_tws_data_for_lib(rx_data, len);
+ break;
+ }
+ app_protocol_tws_rx_data_private_deal(opcode, rx_data, len);
+
+ free(data);
+}
+
+static void app_protocol_rx_from_sibling(void *_data, u16 len, bool rx)
+{
+ int err = 0;
+ if (rx) {
+ printf(">>>%s \n", __func__);
+ printf("len :%d\n", len);
+ put_buf(_data, len);
+ u8 *rx_data = malloc(len);
+ memcpy(rx_data, _data, len);
+
+ int msg[4];
+ msg[0] = (int)__tws_rx_from_sibling;
+ msg[1] = 1;
+ msg[2] = (int)rx_data;
+ err = os_taskq_post_type("app_core", Q_CALLBACK, 3, msg);
+ if (err) {
+ printf("tws rx post fail\n");
+ }
+ }
+}
+
+
+//发送给对耳
+REGISTER_TWS_FUNC_STUB(app_vol_sync_stub) = {
+ .func_id = APP_PROTOCOL_TWS_SEND_ID,
+ .func = app_protocol_rx_from_sibling,
+};
+
+//对耳同步执行
+int app_protocol_tws_sync_send(int cmd, int value)
+{
+ int data[2];
+ data[0] = cmd;
+ data[1] = value;
+ return tws_api_send_data_to_slave(data, sizeof(data), APP_PROTOCOL_TWS_SYNC_ID);
+}
+
+void app_protocol_tws_sync_deal(int cmd, int value)
+{
+ switch (cmd) {
+ case APP_PROTOCOL_SYNC_TONE:
+ printf("APP_PROTOCOL_SYNC_TONE:%d\n", value);
+ app_protocol_tone_play(value, 0);
+ break;
+ }
+ app_protocol_tws_sync_private_deal(cmd, value);
+}
+
+static void app_protocol_tws_sync_rx(void *data, u16 len, bool rx)
+{
+ int err = 0;
+ int *arg = (int *)data;
+ int msg[8];
+
+ msg[0] = (int)app_protocol_tws_sync_deal;
+ msg[1] = len / sizeof(int);
+ msg[2] = arg[0]; //cmd
+ msg[3] = arg[1]; //value
+
+ err = os_taskq_post_type("app_core", Q_CALLBACK, 2 + len / sizeof(int), msg);
+ if (err) {
+ printf("tws sync post fail\n");
+ }
+}
+
+REGISTER_TWS_FUNC_STUB(app_protocol_sync) = {
+ .func_id = APP_PROTOCOL_TWS_SYNC_ID,
+ .func = app_protocol_tws_sync_rx,
+};
+
+//在app_core任务里面进行处理
+int app_protocol_post_app_core_callback(int callback, void *priv)
+{
+ int msg[8];
+ msg[0] = callback;
+ msg[1] = 1;
+ msg[2] = (int)priv;
+ return os_taskq_post_type("app_core", Q_CALLBACK, 3, msg);
+}
+
+void app_protocol_post_bt_event(u8 event, void *priv)
+{
+ struct sys_event e;
+
+ memset(&e, 0, sizeof(e));
+ e.type = SYS_BT_EVENT;
+ e.arg = (void *)SYS_BT_AI_EVENT_TYPE_STATUS;
+ e.u.bt.event = event;
+ e.u.bt.value = (int)priv;
+ sys_event_notify(&e);
+}
+
+
+static int app_protocol_bt_status_event_handler(struct bt_event *bt)
+{
+ switch (bt->event) {
+ case BT_STATUS_INIT_OK:
+ app_protocol_all_init();
+ break;
+ case BT_STATUS_SECOND_CONNECTED:
+ case BT_STATUS_FIRST_CONNECTED:
+ if (app_protocol_check_connect_success()) {
+ app_protocol_tone_play(APP_PROTOCOL_TONE_CONNECTED_ALL_FINISH, 1);
+ } else {
+ app_protocol_tone_play(APP_PROTOCOL_TONE_CONNECTED_NEED_OPEN_APP, 1);
+ }
+ break;
+ case BT_STATUS_FIRST_DISCONNECT:
+ case BT_STATUS_SECOND_DISCONNECT:
+ app_protocol_tone_play(APP_PROTOCOL_TONE_DISCONNECTED, 1);
+ app_protocal_update_tws_state_to_lib(USER_NOTIFY_STATE_MOBILE_DISCONNECTED);
+ break;
+ case BT_STATUS_PHONE_INCOME:
+ case BT_STATUS_PHONE_OUT:
+ case BT_STATUS_PHONE_ACTIVE:
+ __app_protocol_speech_stop();
+ app_protocol_ble_adv_switch(0);
+ break;
+ case BT_STATUS_PHONE_HANGUP:
+ app_protocol_ble_adv_switch(1);
+ break;
+
+ case BT_STATUS_PHONE_MANUFACTURER:
+ if (!app_protocol_check_connect_success()) {
+ if (is_ios_system()) {
+ app_protocol_ibeacon_switch(1);
+ }
+
+ if (get_call_status() != BT_CALL_HANGUP) {
+ app_protocol_ble_adv_switch(0);
+ }
+ }
+ break;
+ case BT_STATUS_VOICE_RECOGNITION:
+ if ((app_var.siri_stu == 1) || (app_var.siri_stu == 2)) {
+ __app_protocol_speech_stop();
+ app_protocol_ble_adv_switch(0);
+ } else if (app_var.siri_stu == 0) {
+ app_protocol_ble_adv_switch(1);
+ }
+ break;
+ case BT_STATUS_CONN_A2DP_CH:
+ app_protocal_update_tws_state_to_lib(USER_NOTIFY_STATE_MOBILE_CONNECTED);
+ break;
+ }
+ return 0;
+}
+
+static void app_protocol_bt_tws_event_handler(struct bt_event *bt)
+{
+ int role = bt->args[0];
+ int phone_link_connection = bt->args[1];
+ int reason = bt->args[2];
+
+ switch (bt->event) {
+ case TWS_EVENT_CONNECTED:
+ if (!is_tws_master_role()) {
+ app_protocol_disconnect(NULL);
+ app_protocol_ble_adv_switch(0);
+ } else {
+#if APP_PROTOCOL_SPEECH_EN
+ if (ai_mic_is_busy()) { //mic在解码过程中,从机连接成功,挂起音频
+ ai_mic_tws_sync_suspend();
+ }
+#endif
+ }
+ app_protocal_update_tws_state_to_lib(USER_NOTIFY_STATE_TWS_CONNECT);
+ break;
+ case TWS_EVENT_CONNECTION_DETACH:
+ if (!app_protocol_check_connect_success()) { //APP未连接,开启广播
+ if (0 == get_esco_coder_busy_flag()) {
+ //esco在用的时候开广播会影响质量
+ app_protocol_ble_adv_switch(1);
+ }
+ }
+#if APP_PROTOCOL_SPEECH_EN
+ if (!ai_mic_is_busy()) {
+ __app_protocol_speech_stop(); //对耳断开时没启动mic,停止语音
+ }
+#endif
+ app_protocal_update_tws_state_to_lib(USER_NOTIFY_STATE_BATTERY_LEVEL_UPDATE); //主动上报电量
+ app_protocal_update_tws_state_to_lib(USER_NOTIFY_STATE_TWS_DISCONNECT);
+ break;
+ case TWS_EVENT_ROLE_SWITCH:
+ app_protocal_update_tws_state_to_lib(USER_NOTIFY_STATE_ROLE_SWITCH_FINISH);
+ app_protocol_disconnect(NULL);
+ if (role == TWS_ROLE_MASTER && (0 == get_esco_coder_busy_flag())) {
+ app_protocol_ble_adv_switch(1);
+ } else {
+ app_protocol_ble_adv_switch(0);
+ }
+ break;
+ }
+}
+
+static int app_protocol_bt_ai_event_handler(struct bt_event *bt)
+{
+ switch (bt->event) {
+#if APP_PROTOCOL_SPEECH_EN
+ case AI_EVENT_SPEECH_START:
+ APP_PROTOCOL_LOG("AI_EVENT_SPEECH_START");
+ __app_protocol_speech_start();
+ break;
+ case AI_EVENT_SPEECH_STOP:
+ APP_PROTOCOL_LOG("AI_EVENT_SPEECH_STOP");
+ __app_protocol_speech_stop();
+ break;
+#endif
+ case AI_EVENT_APP_CONNECT:
+ APP_PROTOCOL_LOG("AI_EVENT_APP_CONNECT");
+ if (get_curr_channel_state()&A2DP_CH) {
+ app_protocol_tone_play(APP_PROTOCOL_TONE_CONNECTED_ALL_FINISH, 1);
+ } else {
+ app_protocol_tone_play(APP_PROTOCOL_TONE_PROTOCOL_CONNECTED, 1);
+ }
+ break;
+ case AI_EVENT_APP_DISCONNECT:
+ APP_PROTOCOL_LOG("AI_EVENT_APP_DISCONNECT");
+ __app_protocol_speech_stop();
+ break;
+ }
+ return 0;
+}
+
+int app_protocol_sys_event_handler(struct sys_event *event)
+{
+#if TCFG_USER_GFPS_PROCESS_CTL
+ if (app_user_protocol_sys_event_remap_hdl(event) == true) {
+ return 0;
+ }
+#endif
+ switch (event->type) {
+ case SYS_BT_EVENT:
+ if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) {
+ app_protocol_bt_status_event_handler(&event->u.bt);
+ }
+#if TCFG_USER_TWS_ENABLE
+ else if (((u32)event->arg == SYS_BT_EVENT_FROM_TWS)) {
+ app_protocol_bt_tws_event_handler(&event->u.bt);
+ }
+#endif
+ else if (((u32)event->arg == SYS_BT_AI_EVENT_TYPE_STATUS)) {
+ app_protocol_bt_ai_event_handler(&event->u.bt);
+ }
+ break;
+
+ case SYS_KEY_EVENT:
+ app_protocol_key_event_handler(event);
+ break;
+ }
+ app_protocol_sys_event_private_deal(event);
+
+ return 0;
+}
+void tell_lib_start_role_switch()
+{
+ app_protocol_ble_adv_switch(0);
+ if (is_tws_master_role()) {
+ printf("master dev will role switch\n");
+ app_protocal_update_tws_state_to_lib(USER_NOTIFY_STATE_ROLE_SWITCH_START);
+ /* os_time_dly(10); */
+ }
+}
+#else
+int app_protocol_sys_event_handler(struct sys_event *event)
+{
+ return 0;
+}
+void tell_lib_start_role_switch()
+{
+
+}
+
+#endif
+
+
diff --git a/apps/common/third_party_profile/interface/app_protocol_common.h b/apps/common/third_party_profile/interface/app_protocol_common.h
new file mode 100644
index 0000000..1618bac
--- /dev/null
+++ b/apps/common/third_party_profile/interface/app_protocol_common.h
@@ -0,0 +1,108 @@
+
+
+#ifndef _3TH_PROTOCOL_COMMON_H
+#define _3TH_PROTOCOL_COMMON_H
+
+#include
+#include
+#include "typedef.h"
+#include "tone_player.h"
+#include "audio_base.h"
+#include "system/event.h"
+
+#ifndef TONE_RES_ROOT_PATH
+#if TCFG_NOR_FS && (TCFG_VIRFAT_FLASH_ENABLE == 0)
+#define NOR_FLASH_RES_ROOT_PATH "storage/res_nor/C/"
+#define TONE_RES_ROOT_PATH NOR_FLASH_RES_ROOT_PATH //内置flash提示音根路径
+#else
+#define TONE_RES_ROOT_PATH SDFILE_RES_ROOT_PATH //内置flash提示音根路径
+#endif//TCFG_NOR_FS
+#endif
+
+#define APP_PROTOCOL_TWS_SYNC_ID 0xFFFF321A
+#define APP_PROTOCOL_TWS_SEND_ID 0xFFFF321B
+
+enum {
+ APP_PROTOCOL_TONE_CONNECTED_ALL_FINISH = 0,//所有连接完成【已连接,你可以按AI键来和我进行对话】 ok
+ APP_PROTOCOL_TONE_PROTOCOL_CONNECTED,//APP已连接,经典蓝牙未连接【请在手机上完成蓝牙配对】 con
+ APP_PROTOCOL_TONE_CONNECTED_NEED_OPEN_APP,//经典蓝牙已连接,app未连接【已配对,请打开app进行连接】 btcon
+ APP_PROTOCOL_TONE_DISCONNECTED,//经典蓝牙已断开【蓝牙已断开,请在手机上完成蓝牙配对】 dis
+ APP_PROTOCOL_TONE_DISCONNECTED_ALL,//经典蓝牙和【蓝牙未连接,请用手机蓝牙和我连接吧】alldis
+ APP_RROTOCOL_TONE_OPEN_APP,//经典蓝牙已连接,APP未连接【请打开APP】 app
+ APP_RROTOCOL_TONE_SPEECH_APP_START,//手机APP启动语音助手
+ APP_RROTOCOL_TONE_SPEECH_KEY_START,//按键启动语音助手
+ APP_RROTOCOL_TONE_MAX,//提示音最大数量
+};
+
+//发送给对耳的消息,格式为:opcode len data
+enum {
+ APP_PROTOCOL_TWS_FOR_LIB = 0,
+
+ GMA_TWS_CMD_SYNC_LIC,
+};
+
+//对耳同步的命令,格式为cmd value
+enum {
+ APP_PROTOCOL_SYNC_TONE = 0,
+};
+
+//发送到系统事件处理的事件
+enum {
+ AI_EVENT_SPEECH_START = 0,
+ AI_EVENT_SPEECH_STOP,
+ AI_EVENT_APP_CONNECT,
+ AI_EVENT_APP_DISCONNECT,
+};
+
+struct app_protocol_private_handle_t {
+ void (*tws_rx_from_siblling)(u16 opcode, u8 *data, u16 len); //收到对耳数据的处理接口
+ void (*tws_sync_func)(int cmd, int value); //对耳同步执行的接口
+ int (*sys_event_handler)(struct sys_event *event); //系统事件
+};
+
+//提示音注册和播放
+void app_protocol_tone_register(const char **tone_table);
+const char *app_protocol_get_tone(int index);
+void app_protocol_tone_play(int index, int tws_sync);
+void app_speech_tone_play_end_callback(void *priv, int flag); //提示音播放完毕回调函数
+
+
+extern int ai_mic_is_busy(void); //mic正在被使用
+extern int ai_mic_rec_start(void); //启动mic和编码模块
+extern int ai_mic_rec_close(void); //停止mic和编码模块
+extern bool bt_is_sniff_close(void);
+
+//语音识别接口
+int mic_rec_pram_init(/* const char **name, */u32 enc_type, u8 opus_type, u16(*speech_send)(u8 *buf, u16 len), u16 frame_num, u16 cbuf_size);
+int __app_protocol_speech_start(void);
+void __app_protocol_speech_stop(void);
+int app_protocol_start_speech_by_app(u8 tone_en); //APP启动
+int app_protocol_stop_speech_by_app(); //APP停止
+int app_protocol_start_speech_by_key(struct sys_event *event); //按键启动
+int app_protocol_stop_speech_by_key(void); //按键停止
+
+
+//协议获取和设置一些设备信息接口
+int app_protocol_set_volume(u8 vol);
+u8 app_protocal_get_bat_by_type(u8 type);
+u32 read_cfg_file(void *buf, u16 len, char *path);
+const u8 *app_protocal_get_license_ptr(void); //获取三元组信息的头指针
+int app_protocol_license2flash(const u8 *data, u16 len); //将三元组信息保存到flash里面
+
+//事件处理函数指针列表注册和接口
+void app_protocol_handle_register(struct app_protocol_private_handle_t *hd);
+struct app_protocol_private_handle_t *app_protocol_get_handle();
+void app_protocol_tws_sync_private_deal(int cmd, int value); //对耳同步事件私有协议处理函数
+void app_protocol_tws_rx_data_private_deal(u16 opcode, u8 *data, u16 len); //私有协议处理来自对耳的数据函数
+int app_protocol_sys_event_private_deal(struct sys_event *event); //私有协议处理系统事件函数
+
+void app_protocol_post_bt_event(u8 event, void *priv); //发送到系统事件处理
+int app_protocol_post_app_core_callback(int callback, void *priv); //放到app_core中处理
+int app_protocol_tws_send_to_sibling(u16 opcode, u8 *data, u16 len); //发送命令数据给对耳
+int app_protocol_tws_sync_send(int cmd, int value); //对耳同步执行命令
+
+int app_protocol_key_event_handler(struct sys_event *event); //按键事件处理函数
+int app_protocol_sys_event_handler(struct sys_event *event); //系统事件处理函数
+
+#endif
+
diff --git a/apps/common/third_party_profile/interface/app_protocol_dma.c b/apps/common/third_party_profile/interface/app_protocol_dma.c
new file mode 100644
index 0000000..d7ace73
--- /dev/null
+++ b/apps/common/third_party_profile/interface/app_protocol_dma.c
@@ -0,0 +1,147 @@
+#include
+#include
+#include
+
+#include "app_protocol_api.h"
+#include "system/includes.h"
+#include "vm.h"
+#include "audio_config.h"
+#include "app_power_manage.h"
+#include "user_cfg.h"
+#if APP_PROTOCOL_DMA_CODE
+
+#if 1
+#define APP_DMA_LOG printf
+#define APP_DMA_DUMP put_buf
+#else
+#define APP_DMA_LOG(...)
+#define APP_DMA_DUMP(...)
+#endif
+
+//*********************************************************************************//
+// DMA认证信息 //
+//*********************************************************************************//
+#define DMA_PRODUCT_INFO_TEST 0
+
+#if DMA_PRODUCT_INFO_TEST
+static const char *dma_product_id = "abcdeYghv0fy6HFexl6bTIZU123Z4n6H";
+static const char *dma_triad_id = "A254BcBb000E00D200A0C0E3";
+static const char *dma_secret = "bab8d7e0dc616630";
+#endif
+static const char *dma_product_key = "rcPXDpFbBOxXaDL9GZ8qLTWq7Yz8rWFm";
+
+#define DMA_PRODUCT_ID_LEN 65
+#define DMA_PRODUCT_KEY_LEN 65
+#define DMA_TRIAD_ID_LEN 32
+#define DMA_SECRET_LEN 32
+
+#define DMA_LEGAL_CHAR(c) ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
+
+static u16 dma_get_one_info(const u8 *in, u8 *out)
+{
+ int read_len = 0;
+ const u8 *p = in;
+
+ while (DMA_LEGAL_CHAR(*p) && *p != ',') { //read Product ID
+ *out++ = *p++;
+ read_len++;
+ }
+ return read_len;
+}
+
+u8 read_dma_product_info_from_flash(u8 *read_buf, u16 buflen)
+{
+ u8 *rp = read_buf;
+ const u8 *dma_ptr = (u8 *)app_protocal_get_license_ptr();
+
+ if (dma_ptr == NULL) {
+ return FALSE;
+ }
+
+ if (dma_get_one_info(dma_ptr, rp) != 32) {
+ return FALSE;
+ }
+ dma_ptr += 33;
+
+ rp = read_buf + DMA_PRODUCT_ID_LEN;
+ memcpy(rp, dma_product_key, strlen(dma_product_key));
+
+ rp = read_buf + DMA_PRODUCT_ID_LEN + DMA_PRODUCT_KEY_LEN;
+ if (dma_get_one_info(dma_ptr, rp) != 24) {
+ return FALSE;
+ }
+ dma_ptr += 25;
+
+ rp = read_buf + DMA_PRODUCT_ID_LEN + DMA_PRODUCT_KEY_LEN + DMA_TRIAD_ID_LEN;
+ if (dma_get_one_info(dma_ptr, rp) != 16) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+__attribute__((weak))
+void bt_update_testbox_addr(u8 *addr)
+{
+
+}
+void dueros_dma_manufacturer_info_init()
+{
+ u8 read_buf[DMA_PRODUCT_ID_LEN + DMA_PRODUCT_KEY_LEN + DMA_TRIAD_ID_LEN + DMA_SECRET_LEN + 1] = {0};
+ bool ret = FALSE;
+
+ APP_DMA_LOG("dueros_dma_manufacturer_info_init\n");
+
+#if DMA_PRODUCT_INFO_TEST
+ memcpy(read_buf, dma_product_id, strlen(dma_product_id));
+ memcpy(read_buf + DMA_PRODUCT_ID_LEN, dma_product_key, strlen(dma_product_key));
+ memcpy(read_buf + DMA_PRODUCT_ID_LEN + DMA_PRODUCT_KEY_LEN, dma_triad_id, strlen(dma_triad_id));
+ memcpy(read_buf + DMA_PRODUCT_ID_LEN + DMA_PRODUCT_KEY_LEN + DMA_TRIAD_ID_LEN, dma_secret, strlen(dma_secret));
+ ret = TRUE;
+#else
+ // ret = read_dma_product_info_from_flash(read_buf, sizeof(read_buf));
+#endif
+
+ if (ret == TRUE) {
+ APP_DMA_LOG("read license success\n");
+ APP_DMA_LOG("product id: %s\n", read_buf);
+ APP_DMA_LOG("product key: %s\n", read_buf + DMA_PRODUCT_ID_LEN);
+ APP_DMA_LOG("triad id: %s\n", read_buf + DMA_PRODUCT_ID_LEN + DMA_PRODUCT_KEY_LEN);
+ APP_DMA_LOG("secret: %s\n", read_buf + DMA_PRODUCT_ID_LEN + DMA_PRODUCT_KEY_LEN + DMA_TRIAD_ID_LEN);
+ app_protocol_set_info_group(DMA_HANDLER_ID, read_buf);
+ } else {
+ app_protocol_set_info_group(DMA_HANDLER_ID, NULL);
+ }
+
+#if 1
+ u8 mac[] = {0xF4, 0x43, 0x8D, 0x29, 0x17, 0x02};
+ u8 ble_mac[6];
+ void bt_update_mac_addr(u8 * addr);
+ void lmp_hci_write_local_address(const u8 * addr);
+ void bt_update_testbox_addr(u8 * addr);
+ extern int le_controller_set_mac(void *addr);
+ //extern void lib_make_ble_address(u8 * ble_address, u8 * edr_address);
+ bt_update_mac_addr(mac);
+ lmp_hci_write_local_address(mac);
+ bt_update_testbox_addr(mac);
+ //lib_make_ble_address(ble_mac, mac);
+ le_controller_set_mac(mac); //修改BLE地址
+ APP_DMA_DUMP(mac, 6);
+ APP_DMA_DUMP(ble_mac, 6);
+#endif
+}
+
+//*********************************************************************************//
+// DMA提示音 //
+//*********************************************************************************//
+const char *dma_notice_tab[APP_RROTOCOL_TONE_MAX] = {
+ [APP_PROTOCOL_TONE_CONNECTED_ALL_FINISH] = TONE_RES_ROOT_PATH"tone/xd_ok.*",//所有连接完成【已连接,你可以按AI键来和我进行对话】
+ [APP_PROTOCOL_TONE_PROTOCOL_CONNECTED] = TONE_RES_ROOT_PATH"tone/xd_con.*",//小度APP已连接,经典蓝牙未连接【请在手机上完成蓝牙配对】
+ [APP_PROTOCOL_TONE_CONNECTED_NEED_OPEN_APP] = TONE_RES_ROOT_PATH"tone/xd_btcon.*",//经典蓝牙已连接,小度app未连接【已配对,请打开小度app进行连接】
+ [APP_PROTOCOL_TONE_DISCONNECTED] = TONE_RES_ROOT_PATH"tone/xd_dis.*",//经典蓝牙已断开【蓝牙已断开,请在手机上完成蓝牙配对】
+ [APP_PROTOCOL_TONE_DISCONNECTED_ALL] = TONE_RES_ROOT_PATH"tone/xd_alldis.*",//经典蓝牙和小度都断开了【蓝牙未连接,请用手机蓝牙和我连接吧】
+ [APP_RROTOCOL_TONE_SPEECH_APP_START] = TONE_NORMAL,
+ [APP_RROTOCOL_TONE_SPEECH_KEY_START] = TONE_NORMAL,
+};
+
+#endif
+
diff --git a/apps/common/third_party_profile/interface/app_protocol_gfps.c b/apps/common/third_party_profile/interface/app_protocol_gfps.c
new file mode 100644
index 0000000..ee49abd
--- /dev/null
+++ b/apps/common/third_party_profile/interface/app_protocol_gfps.c
@@ -0,0 +1,424 @@
+#include
+#include
+#include
+
+#include "app_protocol_api.h"
+#include "system/includes.h"
+#include "vm.h"
+#include "audio_config.h"
+#include "app_power_manage.h"
+#include "user_cfg.h"
+#include "earphone.h"
+#include "btstack/avctp_user.h"
+#include "btstack/bluetooth.h"
+#include "bt_tws.h"
+
+#if AI_APP_PROTOCOL
+#if APP_PROTOCOL_GFPS_CODE
+
+extern void *gfps_app_ble_hdl;
+/* extern u32 unactice_device_cmd_prepare(USER_CMD_TYPE cmd, u16 param_len, u8 *param); */
+extern void tws_dual_conn_close();
+extern int gfps_tws_data_deal(u8 *data, int len);
+extern void audio_app_volume_set(u8 state, s16 volume, u8 fade);
+extern bool get_gfps_pair_state(void);
+extern void set_gfps_pair_state(u8 state);
+extern void gfps_set_battery_ui_enable(uint8_t enable);
+extern void gfps_set_pair_mode(void *priv);
+extern void gfps_all_info_recover(u8 name_reset);
+extern void gfps_sibling_sync_info();
+extern int gfps_disconnect(void *addr);
+extern void gfps_bt_ble_adv_enable(u8 enable);
+extern void gfps_adv_interval_set(u16 value);
+extern void gfps_sibling_data_send(u8 type, u8 *data, u16 len);
+extern int gfps_ble_adv_enable(u8 enable);
+extern void gfps_battery_update(void);
+extern void bt_set_need_keep_scan(u8 en);
+extern int audio_digital_vol_update_parm(u8 dvol_idx, s32 param);
+extern void set_wait_poweroff_time(u16 time);
+
+/**
+ 弹窗的逻辑:
+ 1、没有任何手机配对记录情况,广播初始配对广播。
+ 2、开机有配对记录广播后续配对广播,回连超时进入配对状态时,广播初始配对广播。
+ 3、回连手机发现linkkey_missing,且没有任何手机配对记录了,广播初始配对广播。
+ 4、连上任意一台手机后, 广播后续配对广播,断开进入配对状态也是广播后续配对广播。(客户要求断开后也广播初始配对广播)
+ 5、恢复出厂设置时,需要调用一下gfps_all_info_recover(1)清除一下GFP的账号信息和修改的蓝牙名字
+ 6、认证的时候,需要有一个UI来触发初始配对广播(调用gfps_set_pair_mode(NULL)),可以为长按左右耳5秒之类的
+ 7、耳机关机要关电量显示
+ */
+
+#define TONE_GOOGLE "tone_en/google.*"
+#define GFPS_SIBLING_SYNC_TYPE_ADV_MAC_STATE 0x04
+
+#define ADV_INIT_PAIR_IN_PAIR_MODE 0 //进入配对状态广播初始配对广播
+
+struct gfps_protocol_t {
+ u8 poweron_reconn;
+ u8 close_icon;
+};
+static struct gfps_protocol_t gfps_protocol = {0};
+
+#define __this (&gfps_protocol)
+
+#define INIT_PAIR_ADV_INTERVAL 150
+#define SUBS_PAIR_ADV_INTERVAL 352
+
+void gfps_set_pair_mode_by_user(u8 disconn_ble)
+{
+ if (disconn_ble) {
+ gfps_disconnect(NULL);
+ }
+ gfps_adv_interval_set(INIT_PAIR_ADV_INTERVAL);
+ set_gfps_pair_state(0);
+ gfps_bt_ble_adv_enable(0);
+ gfps_bt_ble_adv_enable(1);
+}
+
+//重写弱函数,获取电量
+extern u8 get_charge_online_flag(void);
+extern u8 get_tws_sibling_bat_persent(void);
+void generate_rfcomm_battery_data(u8 *data)
+{
+ u8 self_val = get_charge_online_flag() << 7 | get_vbat_percent();
+#if TCFG_USER_TWS_ENABLE
+ u8 sibling_val = get_tws_sibling_bat_persent();
+
+ data[2] = 0xFF; //充电仓电量
+
+#if TCFG_CHARGESTORE_ENABLE
+ if (self_val >> 7 || sibling_val >> 7) { //有任意一直耳机充电时才显示充电仓电量
+ data[2] = chargestore_get_power_level(); //充电仓电量
+ }
+#endif
+
+ data[0] = (tws_api_get_local_channel() == 'L') ? self_val : sibling_val; //左耳电量
+ data[1] = (tws_api_get_local_channel() == 'R') ? self_val : sibling_val; //右耳电量
+#else
+ data[0] = self_val;
+ data[1] = 0xFF;
+ data[2] = 0xFF;
+#endif
+ printf("%s, l:%x, r:%x, bat:%x", __func__, data[0], data[1], data[2]);
+}
+
+extern int lmp_hci_write_scan_enable(u8 enable);
+static void gfps_ctl_bt_enter_pair_mode()
+{
+ printf("%s", __func__);
+ tws_dual_conn_close();
+ lmp_hci_write_scan_enable((1 << 1) | 1);
+ bt_set_need_keep_scan(1);
+}
+
+//重写弱函数,GFP-BLE配对认证成功后,需要先断开一个设备或者开可连接,等手机连接经典蓝牙
+extern u8 *get_cur_connect_phone_mac_addr(void);
+void gfps_before_pair_new_device(u8 *seeker_addr)
+{
+#if TCFG_USER_GFPS_PROCESS_CTL
+ app_user_gfps_before_pair_new_device(seeker_addr);
+#else
+ u8 remote_edr_addr[6];
+ u8 *tmp_addr = NULL;
+
+ for (int i = 0; i < 6; i ++) {
+ remote_edr_addr[i] = seeker_addr[5 - i];
+ }
+
+ if (get_curr_channel_state()) {
+ tmp_addr = get_cur_connect_phone_mac_addr();
+ if (memcmp(tmp_addr, remote_edr_addr, 6) != 0) {
+ printf("Subsequent pair\n");
+ printf("USER_CTRL_DISCONNECTION_HCI send\n");
+ user_send_cmd_prepare(USER_CTRL_DISCONNECTION_HCI, 0, NULL);
+ } else {
+ printf("Retroactive Pair\n");
+ }
+ }
+ printf("func:%s, line:%d", __FUNCTION__, __LINE__);
+#endif
+}
+
+struct google_tone_ctl_t {
+ u8 l_en;
+ u8 r_en;
+ u8 l_mute;
+ u8 r_mute;
+};
+static struct google_tone_ctl_t google_tone_ctl = {0};
+
+static void google_tone_set_volume()
+{
+ printf("google_tone_set_volume");
+ /* printf("func:%s:%d", __FUNCTION__, app_audio_volume_max_query(SysVol_TONE)); */
+ /* u32 param = VOLUME_NODE_CMD_SET_VOL | app_audio_volume_max_query(SysVol_TONE); */
+ /* jlstream_set_node_param(NODE_UUID_VOLUME_CTRLER, "Vol_BtcRing", ¶m, sizeof(param)); */
+}
+
+/* #if TCFG_USER_TWS_ENABLE */
+/* static void tws_google_tone_callback(int priv, enum stream_event event) */
+/* { */
+/* printf("func:%s, event:%d", __FUNCTION__, event); */
+/* if (event == STREAM_EVENT_START) { */
+/* int msg[] = {(int)google_tone_set_volume, 0}; */
+/* os_taskq_post_type("app_core", Q_CALLBACK, ARRAY_SIZE(msg), msg); */
+/* } */
+/* } */
+/* REGISTER_TWS_TONE_CALLBACK(tws_google_tone_stub) = { */
+/* .func_uuid = 0x2EC850AE, */
+/* .callback = tws_google_tone_callback, */
+/* }; */
+/* #endif */
+
+/* static int google_tone_play_callback(void *priv, enum stream_event event) */
+/* { */
+/* printf("func:%s, event:%d", __FUNCTION__, event); */
+/* if (event == STREAM_EVENT_START) { */
+/* int msg[] = {(int)google_tone_set_volume, 0}; */
+/* os_taskq_post_type("app_core", Q_CALLBACK, ARRAY_SIZE(msg), msg); */
+/* } */
+/* return 0; */
+/* } */
+
+void google_tone_play_deal()
+{
+ if (strcmp(os_current_task(), "app_core")) {
+ printf("%s, task:%s", __func__, os_current_task());
+ int msg[] = {(int)google_tone_play_deal, 0};
+ os_taskq_post_type("app_core", Q_CALLBACK, ARRAY_SIZE(msg), msg);
+ return;
+ }
+
+ /* tone_player_stop(); */
+ /* tone_player_play(); */
+}
+
+void google_tone_mute_ctl(u8 self, u8 charge_flag)
+{
+ u8 *mute = &google_tone_ctl.l_mute;
+
+ if ((tws_api_get_local_channel() == 'L' && !self) ||
+ (tws_api_get_local_channel() == 'R' && self)) {
+ mute = &google_tone_ctl.r_mute;
+ printf("%s, r_mute:%d, charge_flag:%d", __func__, *mute, charge_flag);
+ } else {
+ printf("%s, l_mute:%d, charge_flag:%d", __func__, *mute, charge_flag);
+ }
+
+ if (*mute != charge_flag) {
+ *mute = charge_flag;
+ google_tone_play_deal();
+ }
+}
+
+int gfps_protocol_tws_send_to_sibling(u16 opcode, u8 *data, u16 len)
+{
+ return tws_api_send_data_to_sibling(data, len, 0x23080315);
+}
+
+static void __tws_rx_from_sibling(u8 *data, int len)
+{
+ gfps_tws_data_deal(data, len);
+
+ switch (data[0]) {
+ case GFPS_SIBLING_SYNC_TYPE_ADV_MAC_STATE:
+ gfps_adv_interval_set(data[1] ? SUBS_PAIR_ADV_INTERVAL : INIT_PAIR_ADV_INTERVAL);
+ set_gfps_pair_state(data[1]);
+ le_controller_set_mac((void *)&data[2]);
+ gfps_bt_ble_adv_enable(0);
+ gfps_bt_ble_adv_enable(1);
+ break;
+ }
+ free(data);
+}
+
+static void gfps_protocol_rx_from_sibling(void *_data, u16 len, bool rx)
+{
+ int err = 0;
+ if (rx) {
+ printf(">>>%s \n", __func__);
+ printf("len :%d\n", len);
+ put_buf(_data, len);
+
+ u8 *rx_data = malloc(len);
+ if (!rx_data) {
+ return;
+ }
+
+ memcpy(rx_data, _data, len);
+
+ int msg[4];
+ msg[0] = (int)__tws_rx_from_sibling;
+ msg[1] = 2;
+ msg[2] = (int)rx_data;
+ msg[3] = (int)len;
+ err = os_taskq_post_type("app_core", Q_CALLBACK, ARRAY_SIZE(msg), msg);
+ if (err) {
+ printf("tws rx post fail\n");
+ }
+ }
+}
+
+//发送给对耳
+REGISTER_TWS_FUNC_STUB(app_vol_sync_stub) = {
+ .func_id = 0x23080315,
+ .func = gfps_protocol_rx_from_sibling,
+};
+
+int gfps_message_deal_handler(int id, int opcode, u8 *data, u32 len)
+{
+ switch (opcode) {
+ case APP_PROTOCOL_LIB_TWS_DATA_SYNC:
+ gfps_protocol_tws_send_to_sibling(opcode, data, len);
+ break;
+ case APP_PROTOCOL_GFPS_RING_STOP_ALL:
+ printf("GFPS_RING_STOP_ALL");
+ google_tone_ctl.l_en = 0;
+ google_tone_ctl.r_en = 0;
+ google_tone_play_deal();
+ break;
+ case APP_PROTOCOL_GFPS_RING_RIGHT:
+ printf("GFPS_RING_RIGHT");
+ google_tone_ctl.l_en = 0;
+ google_tone_ctl.r_en = 1;
+ google_tone_play_deal();
+ break;
+ case APP_PROTOCOL_GFPS_RING_LEFT:
+ printf("GFPS_RING_LEFT");
+ google_tone_ctl.l_en = 1;
+ google_tone_ctl.r_en = 0;
+ google_tone_play_deal();
+ break;
+ case APP_PROTOCOL_GFPS_RING_ALL:
+ printf("GFPS_RING_ALL");
+ google_tone_ctl.l_en = 1;
+ google_tone_ctl.r_en = 1;
+ google_tone_play_deal();
+ break;
+ case APP_PROTOCOL_GFPS_HEARABLE_CONTROLS:
+ printf("APP_PROTOCOL_GFPS_HEARABLE_CONTROLS display:%x settable:%x current:%x\n", data[0], data[1], data[2]);
+ break;
+ }
+ return 0;
+}
+
+//关机广播收仓
+void gfps_need_adv_close_icon_set(u8 en)
+{
+ printf("func:%s, en:%d", __FUNCTION__, en);
+ __this->close_icon = en;
+}
+
+void gfps_poweroff_adv_close_icon()
+{
+ printf("func:%s, line:%d", __FUNCTION__, __LINE__);
+ if (__this->close_icon) {
+ void set_wait_poweroff_time(u16 time);
+ set_wait_poweroff_time(2000); //广播800ms
+ gfps_adv_interval_set(48); //连接上手机间隔改为30ms
+ gfps_set_battery_ui_enable(0); //关闭电量显示,会重新开关广播
+ }
+}
+
+int gfps_hci_event_handler(struct bt_event *bt)
+{
+ switch (bt->event) {
+ case HCI_EVENT_DISCONNECTION_COMPLETE:
+ switch (bt->value) {
+ case ERROR_CODE_PIN_OR_KEY_MISSING:
+ printf("GFP linkkey missing");
+ if (!btstack_get_num_of_remote_device_recorded()) { //没有配对记录的时候,广播初始配对广播
+ gfps_all_info_recover(0);
+ gfps_adv_interval_set(INIT_PAIR_ADV_INTERVAL); //连接上手机间隔改为93.75ms
+ gfps_set_pair_mode_by_user(0);
+ }
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
+int gfps_bt_status_event_handler(struct bt_event *bt)
+{
+ u8 ret = 0;
+ switch (bt->event) {
+ // 需要切换蓝牙的命令
+ case BT_STATUS_A2DP_MEDIA_START:
+ break;
+ case BT_STATUS_INIT_OK:
+ if (btstack_get_num_of_remote_device_recorded()) {
+ __this->poweron_reconn = 1;
+ }
+ break;
+ case BT_STATUS_SECOND_CONNECTED:
+ case BT_STATUS_FIRST_CONNECTED:
+ __this->poweron_reconn = 0;
+ gfps_adv_interval_set(SUBS_PAIR_ADV_INTERVAL); //连接上手机间隔改为220ms,防止fast pair validator测试fail
+ set_gfps_pair_state(1);
+ gfps_bt_ble_adv_enable(0);
+ gfps_bt_ble_adv_enable(1);
+ break;
+ case BT_STATUS_PHONE_INCOME:
+ case BT_STATUS_PHONE_OUT:
+ case BT_STATUS_PHONE_ACTIVE:
+ gfps_ble_adv_enable(0);
+ break;
+ case BT_STATUS_PHONE_HANGUP:
+ gfps_ble_adv_enable(1);
+ break;
+ }
+ return 0;
+}
+
+
+static int gfps_app_power_event_handler(struct device_event *dev)
+{
+ switch (dev->event) {
+#if TCFG_USER_TWS_ENABLE
+ case POWER_EVENT_SYNC_TWS_VBAT_LEVEL:
+ printf("update gfps bat");
+ if (get_tws_sibling_bat_persent() != 0xFF) {
+ google_tone_mute_ctl(0, get_tws_sibling_bat_persent() >> 7);
+ }
+ gfps_battery_update();
+ break;
+#endif
+ case POWER_EVENT_POWER_CHANGE:
+ printf("update gfps bat");
+ google_tone_mute_ctl(1, get_charge_online_flag());
+ gfps_battery_update();
+ break;
+ }
+ return 0;
+}
+
+int gfps_sys_event_handler_specific(struct sys_event *event)
+{
+ switch (event->type) {
+ case SYS_DEVICE_EVENT:
+ if ((u32)event->arg == DEVICE_EVENT_FROM_POWER) {
+ gfps_app_power_event_handler(&event->u.dev);
+ }
+ break;
+ case SYS_BT_EVENT:
+ if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) {
+ gfps_bt_status_event_handler(&event->u.bt);
+ } else if ((u32)event->arg == SYS_BT_EVENT_TYPE_HCI_STATUS) {
+ gfps_hci_event_handler(&event->u.bt);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+struct app_protocol_private_handle_t gfps_private_handle = {
+ .sys_event_handler = gfps_sys_event_handler_specific,
+};
+
+#endif
+#endif
+
+
+
diff --git a/apps/common/third_party_profile/interface/app_protocol_gma.c b/apps/common/third_party_profile/interface/app_protocol_gma.c
new file mode 100644
index 0000000..93704b9
--- /dev/null
+++ b/apps/common/third_party_profile/interface/app_protocol_gma.c
@@ -0,0 +1,557 @@
+#include
+#include
+#include
+
+#include "app_protocol_api.h"
+#include "system/includes.h"
+#include "vm.h"
+#include "audio_config.h"
+#include "app_power_manage.h"
+#include "user_cfg.h"
+
+#if APP_PROTOCOL_GMA_CODE
+
+#if 1
+#define APP_GMA_LOG printf
+#define APP_GMA_DUMP put_buf
+#else
+#define APP_GMA_LOG(...)
+#define APP_GMA_DUMP(...)
+#endif
+
+//*********************************************************************************//
+// GMA认证信息 //
+//*********************************************************************************//
+
+#define GMA_GMA_FROM_FLASH 0
+#define GMA_GMA_FROM_FILE 1
+
+#define GMA_GMA_SOURCH GMA_GMA_FROM_FLASH
+
+
+extern int le_controller_set_mac(void *addr);
+extern void lmp_hci_write_local_address(const u8 *addr);
+extern void lmp_hci_read_local_address(u8 *addr);
+extern void bt_update_testbox_addr(u8 *addr);
+
+typedef struct {
+ uint8_t mac[6];
+ uint32_t pid;
+ uint8_t secret[16];
+} ali_para_s;
+
+static ali_para_s ali_para;
+static ali_para_s *active_ali_para = NULL;
+
+///mac reverse
+void gma_mac_addr_reverse_get(uint8_t *buf)
+{
+ memcpy(buf, (const void *)active_ali_para->mac, 6);
+}
+
+#define LEGAL_PID_NUM(cha) (cha>='0' && cha<='9')
+#define LEGAL_MAC_NUM(cha) ((cha>='0'&&cha<='9') || (cha>='a'&&cha<='f') || (cha>='A'&&cha<='F') || (cha==':'))
+#define LEGAL_SECRET_NUM(cha) ((cha>='0'&&cha<='9') || (cha>='a'&&cha<='f') || (cha>='A'&&cha<='F'))
+
+#define USELESS_CHAR ':'
+#define GMA_ALI_PARA_END_CHAR ','
+#define GMA_ALI_PARA_MAC_CHAR_NUMS (sizeof(((ali_para_s *)0)->mac))
+#define GMA_ALI_PARA_PID_CHAR_NUMS 4//(sizeof(((ali_para_s *)0)->pid))
+#define GMA_ALI_PARA_SECRET_CHAR_NUMS (sizeof(((ali_para_s *)0)->secret))
+
+static u8 gma_ali_para_char2num(u8 cha)
+{
+ u8 num = 0;
+
+ if (cha >= '0' && cha <= '9') {
+ num = cha - '0';
+ } else if (cha >= 'a' && cha <= 'f') {
+ num = cha - 'a' + 10;
+ } else if (cha >= 'A' && cha <= 'F') {
+ num = cha - 'A' + 10;
+ }
+
+ return num;
+}
+
+static int gma_license_set(ali_para_s *ali_para)
+{
+ const u8 *gma_ptr = (u8 *)app_protocal_get_license_ptr();
+
+ if (gma_ptr == NULL) {
+ return -1;
+ }
+
+ ///license fill
+ //pid
+ memcpy((u8 *) & (ali_para->pid), gma_ptr, sizeof(ali_para->pid));
+ gma_ptr += sizeof(ali_para->pid);
+ APP_GMA_LOG("gma pid:%d \n", ali_para->pid);
+ //secret
+ memcpy((u8 *)(ali_para->secret), gma_ptr, sizeof(ali_para->secret));
+ gma_ptr += sizeof(ali_para->secret);
+ APP_GMA_LOG("gma secret:");
+ APP_GMA_DUMP(ali_para->secret, sizeof(ali_para->secret));
+ //mac
+ memcpy((u8 *)(ali_para->mac), gma_ptr, sizeof(ali_para->mac));
+ gma_ptr += sizeof(ali_para->mac);
+ {
+ //mac reverse
+ u8 mac_backup_buf[6];
+ memcpy(mac_backup_buf, ali_para->mac, 6);
+ int i;
+ for (i = 0; i < 6; i++) {
+ ali_para->mac[i] = (mac_backup_buf)[5 - i];
+ }
+ }
+ APP_GMA_LOG("gma mac:");
+ APP_GMA_DUMP(ali_para->mac, sizeof(ali_para->mac));
+
+ return 0;
+}
+
+#if GMA_GMA_SOURCH == GMA_GMA_FROM_FILE
+
+#define ALI_PARA_ACTIVE_NUM 1
+
+static const char *ali_para_string[] = {
+ "jl_auif",
+ //Product ID,Device Secret,Mac,Md5
+ //此处可以用户自行填写从阿里申请的三元组信息
+ " ",
+};
+
+static bool gma_ali_para_info_fill(const u8 *para, ali_para_s *ali_para)
+{
+ const u8 *para_string = para;
+ u8 highbit_en = 0;
+ uint32_t pid = 0;
+ uint32_t char_nums = 0;
+ uint8_t *secret = ali_para->secret;
+ uint8_t *mac = ali_para->mac;
+
+ while (*para_string && *para_string != GMA_ALI_PARA_END_CHAR) {
+ if (!LEGAL_PID_NUM(*para_string)) {
+ /* APP_GMA_LOG("pid illegal character !!! \n"); */
+ para_string++;
+ continue;
+ }
+
+ ///check pid character numbers legal scope
+ char_nums++;
+ if (char_nums > GMA_ALI_PARA_PID_CHAR_NUMS) {
+ APP_GMA_LOG("pid character numbers overflow !!! \n");
+ return false;
+ }
+
+ pid *= 10;
+ pid += gma_ali_para_char2num(*para_string);
+ para_string++;
+ }
+
+ ///check pid character numbers legal scope
+ if (char_nums != GMA_ALI_PARA_PID_CHAR_NUMS) {
+ APP_GMA_LOG("pid character numbers error:%d !!! \n", char_nums);
+ return false;
+ }
+
+ APP_GMA_LOG(">>pid:%d \n", pid);
+ ali_para->pid = pid;
+
+ para_string++;
+ char_nums = 0;
+ memset(ali_para->secret, 0x00, sizeof(ali_para->secret));
+ while (*para_string != GMA_ALI_PARA_END_CHAR) {
+ if (!LEGAL_SECRET_NUM(*para_string)) {
+ APP_GMA_LOG("secret illegal character !!! \n");
+ para_string++;
+ continue;
+ }
+
+ ///assignment secret
+ if (!highbit_en) {
+ *secret += gma_ali_para_char2num(*para_string);
+ highbit_en ^= 1;
+ } else {
+ ///check secret character numbers legal scope
+ char_nums++;
+ if (char_nums > GMA_ALI_PARA_SECRET_CHAR_NUMS) {
+ APP_GMA_LOG("secret character number overflow !!! \n");
+ return false;
+ }
+
+ *secret <<= 4;
+ *secret++ += gma_ali_para_char2num(*para_string);
+ highbit_en ^= 1;
+ }
+
+ para_string++;
+ }
+
+ ///check secret character numbers legal scope
+ if (char_nums != GMA_ALI_PARA_SECRET_CHAR_NUMS) {
+ APP_GMA_LOG("secret character number error !!! :%d \n", char_nums);
+ return false;
+ }
+
+ ///print secret
+ APP_GMA_LOG(">>ali_para secret: ");
+ for (int i = 0; i < sizeof(ali_para->secret) / sizeof(ali_para->secret[0]); i++) {
+ APP_GMA_LOG("%x ", ali_para->secret[i]);
+ }
+
+ memset(ali_para->mac, 0x00, sizeof(ali_para->mac));
+ para_string++;
+ highbit_en = 0;
+ char_nums = 0;
+ while (*para_string != GMA_ALI_PARA_END_CHAR) {
+ //if legal character
+ if (!LEGAL_MAC_NUM(*para_string)) {
+ APP_GMA_LOG("mac illegal character !!! \n");
+ para_string++;
+ continue;
+// return false;
+ }
+
+ if (*para_string == USELESS_CHAR) {
+ para_string++;
+ continue;
+ }
+
+ ///assignment mac
+ if (!highbit_en) {
+ *mac += gma_ali_para_char2num(*para_string);
+ highbit_en ^= 1;
+ } else {
+ //check mac character numbers legal scope
+ char_nums++;
+ if (char_nums > GMA_ALI_PARA_MAC_CHAR_NUMS) {
+ APP_GMA_LOG("mac character numbers overflow !!! \n");
+ return false;
+ }
+
+ *mac <<= 4;
+ *mac++ += gma_ali_para_char2num(*para_string);
+ highbit_en ^= 1;
+ }
+
+ para_string++;
+ }
+
+ //check mac character numbers legal scope
+ if (char_nums != GMA_ALI_PARA_MAC_CHAR_NUMS) {
+ APP_GMA_LOG("mac character numbers error !!! \n");
+ return false;
+ }
+
+ ///mac reverse
+ for (int i = 0, tmp_mac = 0, array_size = (sizeof(ali_para->mac) / sizeof(ali_para->mac[0])); \
+ i < (sizeof(ali_para->mac) / sizeof(ali_para->mac[0]) / 2); i++) {
+ tmp_mac = ali_para->mac[i];
+ ali_para->mac[i] = ali_para->mac[array_size - 1 - i];
+ ali_para->mac[array_size - 1 - i] = tmp_mac;
+ }
+
+ ///print secret
+ APP_GMA_LOG(">>ali_para mac: ");
+ for (int i = 0; i < sizeof(ali_para->mac) / sizeof(ali_para->mac[0]); i++) {
+ APP_GMA_LOG("%x ", ali_para->mac[i]);
+ }
+ return true;
+}
+
+static int gma_license2flash(const ali_para_s *ali_para)
+{
+ int i;
+ u8 mac[6];
+ u8 rdata[sizeof(ali_para_s)];
+
+ for (i = 0; i < sizeof(mac); i++) {
+ mac[i] = ali_para->mac[5 - i];
+ }
+ memcpy(rdata, &ali_para->pid, sizeof(ali_para->pid));
+ memcpy(rdata + sizeof(ali_para->pid), ali_para->secret, sizeof(ali_para->secret));
+ memcpy(rdata + sizeof(ali_para->pid) + sizeof(ali_para->secret), mac, sizeof(mac));
+
+ return app_protocol_license2flash(rdata, sizeof(rdata));
+}
+
+#endif
+
+
+#if TCFG_USER_TWS_ENABLE
+#include "bt_tws.h"
+static ali_para_s ali_para_remote; //对耳的三元组
+
+//VM_GMA_MAC 对耳的地址
+//VM_GMA_ALI_PARA 对耳的三元组
+
+static int gma_strcmp(const u8 *ptr1, const u8 *ptr2, u8 len)
+{
+ while (len--) {
+ if (*ptr1 != *ptr2) {
+ return (*ptr1 - *ptr2);
+ }
+
+ ptr1++;
+ ptr2++;
+ }
+
+ return 0;
+}
+
+///mac reverse
+u8 *gma_sibling_mac_get() //获取地址较小的那个
+{
+ ali_para_s *sibling_ali_para = NULL;//&ali_para;
+ if (active_ali_para == &ali_para) {
+ printf("ali_para active \n");
+ sibling_ali_para = &ali_para_remote;
+ }
+
+ if (active_ali_para == &ali_para_remote) {
+ printf("ali_para active \n");
+ sibling_ali_para = &ali_para;
+ }
+
+ return (sibling_ali_para ? sibling_ali_para->mac : NULL);
+}
+
+int gma_select_ali_para_by_common_mac()
+{
+ u8 ret = 0;
+ u8 mac[6];
+ u8 mac_buf_tmp[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+ ret = syscfg_read(CFG_TWS_COMMON_ADDR, mac, 6);
+ if (ret != 6 || !memcmp(mac, mac_buf_tmp, 6)) {
+ printf("tws no conn\n");
+ return -1;
+ }
+ APP_GMA_LOG("active mac:");
+ APP_GMA_DUMP(mac, 6);
+ ///select para
+ ali_para_s ali_para_temp;
+ syscfg_read(VM_GMA_ALI_PARA, (u8 *) &ali_para_temp, sizeof(ali_para_s));
+ if (ali_para_temp.pid == ali_para.pid) {
+ memcpy(&ali_para_remote, &ali_para_temp, sizeof(ali_para_s));
+ APP_GMA_LOG("remote mac:");
+ APP_GMA_DUMP(ali_para_remote.mac, 6);
+ APP_GMA_LOG("remote pid:%d \n", ali_para_remote.pid);
+ APP_GMA_LOG("remote secret:");
+ APP_GMA_DUMP(ali_para_remote.secret, sizeof(ali_para_remote.secret));
+ if (gma_strcmp(mac, ali_para_remote.mac, 6) == 0) {
+ APP_GMA_LOG("used remote para \n");
+ active_ali_para = &ali_para_remote;
+ return 0;
+ } else if (gma_strcmp(mac, ali_para.mac, 6) == 0) {
+ APP_GMA_LOG("used local para \n");
+ active_ali_para = &ali_para;
+ return 0;
+ } else {
+ APP_GMA_LOG("MAC ERROR !!!!!!!!!!!!!!!!\n");
+ return -1;
+ }
+ } else {
+ APP_GMA_LOG("no remote mac \n");
+ }
+ return -1;
+}
+
+void gma_slave_sync_remote_addr(u8 *buf)
+{
+ u8 common_addr[6];
+ ///remote ali_para fill
+ memcpy(&ali_para_remote, buf, sizeof(ali_para_remote));
+ syscfg_write(VM_GMA_MAC, ali_para_remote.mac, 6);
+
+ ///write ali para to vm
+ syscfg_write(VM_GMA_ALI_PARA, (u8 *)&ali_para_remote, sizeof(ali_para_remote));
+
+ tws_api_get_local_addr(common_addr);
+ if (memcmp(active_ali_para->mac, common_addr, 6)) { //common地址发生变化
+ APP_GMA_LOG("gma addr change");
+ ///used slave address
+ active_ali_para = &ali_para_remote;
+ app_protocol_set_tws_sibling_mac(ali_para.mac);
+ app_protocol_set_info_group(GMA_HANDLER_ID, active_ali_para); //设置三元组
+ //断开APP接口
+ if (is_tws_master_role()) {
+ APP_GMA_LOG("gma need reconn app");
+ app_protocol_disconnect(NULL);
+ app_protocol_ble_adv_switch(0);
+ le_controller_set_mac(active_ali_para->mac);
+ app_protocol_ble_adv_switch(1);
+ }
+ }
+}
+
+#ifdef CONFIG_NEW_BREDR_ENABLE
+void tws_host_get_common_addr(u8 *remote_addr, u8 *common_addr, char channel)
+#else
+void tws_host_get_common_addr(u8 *local_addr, u8 *remote_addr, u8 *common_addr, char channel)
+#endif
+{
+ APP_GMA_LOG(">>>>>>>>>tws_host_get_common_addr ch:%c \n", channel);
+
+ u8 mac_buf[6];
+ gma_mac_addr_reverse_get(mac_buf);
+ APP_GMA_LOG(">>>local mac: ");
+ APP_GMA_DUMP(mac_buf, 6);
+ ///used the bigger one as host bt mac
+ if (gma_strcmp(mac_buf, (const u8 *)remote_addr, 6) < 0) {
+ ///used slave mac addr;remote_addr from slave addr reverse
+ memcpy(common_addr, remote_addr, 6);
+ } else {
+ ///used master mac addr
+ gma_mac_addr_reverse_get(common_addr);
+ }
+ APP_GMA_LOG("common_addr: ");
+ APP_GMA_DUMP((const u8 *)common_addr, 6);
+ APP_GMA_LOG("remote_addr: ");
+ APP_GMA_DUMP((const u8 *)remote_addr, 6);
+}
+
+void gma_kick_license_to_sibling(void)
+{
+ APP_GMA_LOG("send license info to sibling\n");
+ app_protocol_tws_send_to_sibling(GMA_TWS_CMD_SYNC_LIC, (u8 *) & (ali_para), sizeof(ali_para));;
+}
+
+void gma_tws_remove_paired(void)
+{
+ ali_para_s ali_para_temp;
+ memset(&ali_para_temp, 0xff, sizeof(ali_para_s));
+ syscfg_write(VM_GMA_ALI_PARA, (u8 *)&ali_para_temp, sizeof(ali_para_s));
+
+ active_ali_para = &ali_para;
+ app_protocol_set_tws_sibling_mac(ali_para_temp.mac);
+ app_protocol_set_info_group(GMA_HANDLER_ID, active_ali_para); //设置三元组
+
+ app_protocol_disconnect(NULL);
+ app_protocol_ble_adv_switch(0);
+ le_controller_set_mac(active_ali_para->mac);
+ app_protocol_ble_adv_switch(1);
+}
+
+#endif
+
+__attribute__((weak))
+void bt_update_testbox_addr(u8 *addr)
+{
+
+}
+int gma_prev_init(void)
+{
+ int err = 0;
+ /* ali_para_s ali_para; */
+#if GMA_GMA_SOURCH == GMA_GMA_FROM_FLASH
+ err = gma_license_set(&ali_para);
+#elif GMA_GMA_SOURCH == GMA_GMA_FROM_FILE
+ u8 *ali_str = ali_para_string[ALI_PARA_ACTIVE_NUM];
+ u8 ali_license[128] = {0};
+
+ //check if exist flash file
+ if (read_cfg_file(ali_license, sizeof(ali_license), SDFILE_RES_ROOT_PATH"license.txt") == TRUE) {
+ ali_str = ali_license;
+ }
+ APP_GMA_LOG("ali_str:%s\n", ali_str);
+ if (gma_ali_para_info_fill((const u8 *)ali_str, &ali_para) == false) {
+ APP_GMA_LOG("array context not good \n");
+///read license from flash
+ err = gma_license_set(&ali_para);
+ }
+///write license to flash
+ if (!err) {
+ gma_license2flash(&ali_para);
+ }
+#endif
+ if (!err) {
+ active_ali_para = &ali_para;
+#if TCFG_USER_TWS_ENABLE
+ if (!gma_select_ali_para_by_common_mac()) {
+ app_protocol_set_tws_sibling_mac(gma_sibling_mac_get());
+ }
+#endif
+ app_protocol_set_info_group(GMA_HANDLER_ID, active_ali_para); //设置三元组
+ bt_update_mac_addr(active_ali_para->mac);
+ lmp_hci_write_local_address(active_ali_para->mac);
+ app_protocol_ble_adv_switch(0);
+ le_controller_set_mac(active_ali_para->mac); //修改BLE地址
+ bt_update_testbox_addr(ali_para.mac);
+ }
+ return err;
+}
+
+
+//*********************************************************************************//
+// GMA 提示音 //
+//*********************************************************************************//
+const char *gma_tone_tab[APP_RROTOCOL_TONE_MAX] = {
+ [APP_RROTOCOL_TONE_SPEECH_KEY_START] = TONE_NORMAL,
+};
+
+//*********************************************************************************//
+// DMA私有消息处理 //
+//*********************************************************************************//
+#if TCFG_USER_TWS_ENABLE
+void gma_rx_tws_data_deal(u16 opcode, u8 *data, u16 len)
+{
+ switch (opcode) {
+ case GMA_TWS_CMD_SYNC_LIC:
+ printf(">>> TWS_AI_GMA_START_SYNC_LIC \n");
+ gma_slave_sync_remote_addr(data);
+ break;
+ }
+}
+
+static void gma_bt_tws_event_handler(struct bt_event *bt)
+{
+ int role = bt->args[0];
+ int phone_link_connection = bt->args[1];
+ int reason = bt->args[2];
+
+ switch (bt->event) {
+ case TWS_EVENT_CONNECTED:
+ gma_kick_license_to_sibling();
+ break;
+ case TWS_EVENT_REMOVE_PAIRS:
+ gma_tws_remove_paired();
+ break;
+ }
+}
+#endif
+
+static int gma_bt_status_event_handler(struct bt_event *bt)
+{
+ return 0;
+}
+
+int gma_sys_event_deal(struct sys_event *event)
+{
+ switch (event->type) {
+ case SYS_BT_EVENT:
+ if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) {
+ gma_bt_status_event_handler(&event->u.bt);
+ }
+#if TCFG_USER_TWS_ENABLE
+ else if (((u32)event->arg == SYS_BT_EVENT_FROM_TWS)) {
+ gma_bt_tws_event_handler(&event->u.bt);
+ }
+#endif
+ break;
+
+ }
+
+ return 0;
+
+}
+
+struct app_protocol_private_handle_t gma_private_handle = {
+#if TCFG_USER_TWS_ENABLE
+ .tws_rx_from_siblling = gma_rx_tws_data_deal,
+#endif
+ /* .tws_sync_func = ; */
+ .sys_event_handler = gma_sys_event_deal,
+};
+#endif
+
diff --git a/apps/common/third_party_profile/interface/app_protocol_mma.c b/apps/common/third_party_profile/interface/app_protocol_mma.c
new file mode 100644
index 0000000..8b9cc99
--- /dev/null
+++ b/apps/common/third_party_profile/interface/app_protocol_mma.c
@@ -0,0 +1,146 @@
+#include
+#include
+#include
+
+#include "app_protocol_api.h"
+#include "system/includes.h"
+#include "audio_config.h"
+#include "app_power_manage.h"
+#include "user_cfg.h"
+#include "bt_tws.h"
+#include "custom_cfg.h"
+
+#if APP_PROTOCOL_MMA_CODE
+
+#if 1
+#define APP_MMA_LOG printf
+#define APP_MMA_DUMP put_buf
+#else
+#define APP_MMA_LOG(...)
+#define APP_MMA_DUMP(...)
+#endif
+//*********************************************************************************//
+// MMA初始化 //
+//*********************************************************************************//
+
+void mma_prev_init()
+{
+ u16 pid = 0x210c;
+ u16 vid = 0x05d6;
+ u16 ver = 0x1100;
+#if APP_PROTOCOL_READ_CFG_EN
+ vid = get_vid_pid_ver_from_cfg_file(GET_VID_FROM_EX_CFG);
+ pid = get_vid_pid_ver_from_cfg_file(GET_PID_FROM_EX_CFG);
+ ver = get_vid_pid_ver_from_cfg_file(GET_VER_FROM_EX_CFG);
+#endif
+ APP_MMA_LOG("mma pid:%x, vid:%x, ver:%x\n", pid, vid, ver);
+ app_protocol_set_vendor_id(MMA_HANDLER_ID, vid);
+ app_protocol_set_product_id(MMA_HANDLER_ID, pid);
+ app_protocol_set_local_version(MMA_HANDLER_ID, ver);
+}
+
+//*********************************************************************************//
+// MMA提示音 //
+//*********************************************************************************//
+const char *mma_notice_tab[APP_RROTOCOL_TONE_MAX] = {
+ [APP_RROTOCOL_TONE_SPEECH_KEY_START] = TONE_NORMAL,
+};
+
+//*********************************************************************************//
+// MMA私有消息处理 //
+//*********************************************************************************//
+
+#if 1
+extern int le_controller_get_mac(void *addr);
+
+#ifdef CONFIG_NEW_BREDR_ENABLE
+void tws_host_get_common_addr(u8 *remote_addr, u8 *common_addr, char channel)
+#else
+void tws_host_get_common_addr(u8 *local_addr, u8 *remote_addr, u8 *common_addr, char channel)
+#endif
+{
+ APP_MMA_LOG(">>>>>>>>>tws_host_get_common_addr ch:%c \n", channel);
+
+ if (channel == 'L') {
+ memcpy(common_addr, bt_get_mac_addr(), 6);
+ } else {
+ memcpy(common_addr, remote_addr, 6);
+ }
+ APP_MMA_LOG(">>>local mac: ");
+ APP_MMA_DUMP(bt_get_mac_addr(), 6);
+ APP_MMA_LOG("remote_addr: ");
+ APP_MMA_DUMP((const u8 *)remote_addr, 6);
+ APP_MMA_LOG("common_addr: ");
+ APP_MMA_DUMP((const u8 *)common_addr, 6);
+}
+
+static void mma_tws_get_data_analysis(u16 cmd, u8 *data, u16 len)
+{
+}
+
+static void mma_update_ble_addr()
+{
+ u8 ble_old_addr[6];
+ u8 ble_new_addr[6];
+ u8 comm_addr[6];
+ tws_api_get_local_addr(comm_addr);
+ le_controller_get_mac(ble_old_addr);
+ void ble_update_address_tws_paired(u8 * comm_addr);
+ ble_update_address_tws_paired(comm_addr);
+ le_controller_get_mac(ble_new_addr);
+ if (is_tws_master_role() && memcmp(ble_old_addr, ble_new_addr, 6)) {
+ app_protocol_disconnect(NULL);
+ app_protocol_ble_adv_switch(0);
+ app_protocol_ble_adv_switch(1);
+ }
+}
+
+static void mma_bt_tws_event_handler(struct bt_event *bt)
+{
+ int role = bt->args[0];
+ int phone_link_connection = bt->args[1];
+ int reason = bt->args[2];
+
+ switch (bt->event) {
+ case TWS_EVENT_CONNECTED:
+ mma_update_ble_addr();
+ break;
+ case TWS_EVENT_REMOVE_PAIRS:
+ mma_update_ble_addr();
+ break;
+ }
+}
+
+
+static int mma_bt_status_event_handler(struct bt_event *bt)
+{
+ return 0;
+}
+
+int mma_sys_event_deal(struct sys_event *event)
+{
+ switch (event->type) {
+ case SYS_BT_EVENT:
+ if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) {
+ mma_bt_status_event_handler(&event->u.bt);
+ }
+#if TCFG_USER_TWS_ENABLE
+ else if (((u32)event->arg == SYS_BT_EVENT_FROM_TWS)) {
+ mma_bt_tws_event_handler(&event->u.bt);
+ }
+#endif
+ break;
+
+ }
+
+ return 0;
+
+}
+
+struct app_protocol_private_handle_t mma_private_handle = {
+ /* .tws_rx_from_siblling = mma_tws_get_data_analysis, */
+ .sys_event_handler = mma_sys_event_deal,
+};
+#endif
+#endif
+
diff --git a/apps/common/third_party_profile/interface/app_protocol_ota.c b/apps/common/third_party_profile/interface/app_protocol_ota.c
new file mode 100644
index 0000000..f4c76be
--- /dev/null
+++ b/apps/common/third_party_profile/interface/app_protocol_ota.c
@@ -0,0 +1,527 @@
+#include "app_config.h"
+
+#if AI_APP_PROTOCOL
+#include "app_protocol_ota.h"
+#include "app_protocol_api.h"
+#include "fs.h"
+#include "os/os_error.h"
+#include "update_loader_download.h"
+#include "dual_bank_updata_api.h"
+#include "update.h"
+#include "timer.h"
+#include "debug.h"
+
+#define LOG_TAG_CONST APP_OTA
+#define LOG_TAG "[APP_OTA]"
+
+
+int clk_set(const char *name, int clk);
+update_op_tws_api_t *get_tws_update_api(void);
+void tws_sync_update_crc_handler_register(void (*crc_init_hdl)(void), u32(*crc_calc_hdl)(u32 init_crc, u8 *data, u32 len));
+
+#define APP_UPDATE_FAILED 0
+#define APP_UPDATE_SUCC 1
+
+#define APP_CHECK_CRC_SUCC 0
+#define APP_CHECK_CRC_FAILED 1
+
+typedef struct _app_protocol_ota_param_t {
+ u32 state;
+ u32 read_len;
+ u32 need_rx_len;
+ u8 *read_buf;
+ void (*resume_hdl)(void *priv);
+ int (*sleep_hdl)(void *priv);
+ app_protocol_ota_api ota_api;
+ u32 file_offset;
+ u8 seek_type;
+ u8 update_result;
+ u8 sync_update_first_packet;
+ u8 ota_cancle_flag;
+ u8 wait_app_reboot;
+ OS_SEM ota_sem;
+} app_protocol_ota_param_t;
+
+static app_protocol_ota_param_t app_protocol_ota_param;
+static update_op_tws_api_t *app_protocol_update_tws_api = NULL;
+
+#define __this (&app_protocol_ota_param)
+
+enum {
+ BT_SEEK_SET = 0x01,
+ BT_SEEK_CUR = 0x02,
+ BT_SEEK_TYPE_UPDATE_LEN = 0x10,
+};
+
+typedef enum {
+ UPDATA_START = 0x00,
+ UPDATA_REV_DATA,
+ UPDATA_STOP,
+} UPDATA_BIT_FLAG;
+
+#define RETRY_TIMES 3
+
+const app_protocol_ota_type_map ota_type_map[] = {
+ {.protocol_id = GMA_HANDLER_ID, .ota_type = PASSIVE_OTA},
+ {.protocol_id = MMA_HANDLER_ID, .ota_type = INITIATIVE_OTA},
+ {.protocol_id = DMA_HANDLER_ID, .ota_type = NO_SUPPORT_OTA},
+ {.protocol_id = TME_HANDLER_ID, .ota_type = INITIATIVE_OTA},
+ {.protocol_id = AMA_HANDLER_ID, .ota_type = NO_SUPPORT_OTA},
+};
+
+//根据protocol_id获取协议升级类型
+u8 check_ota_type_by_protocol_id(int id)
+{
+ u8 i = 0;
+ for (; i < sizeof(ota_type_map) / sizeof(app_protocol_ota_type_map); i++) {
+ if (id == ota_type_map[i].protocol_id) {
+ return ota_type_map[i].ota_type;
+ }
+ }
+ return NO_SUPPORT_OTA;
+}
+
+static void initiative_ota_resume_hdl_register(void (*resume_hdl)(void *priv), int (*sleep_hdl)(void *priv))
+{
+ __this->resume_hdl = resume_hdl;
+ __this->sleep_hdl = sleep_hdl;
+}
+
+void app_protocol_ota_init(app_protocol_ota_api *api, u8 need_wait_app_reboot)
+{
+ memcpy(&(__this->ota_api), api, sizeof(app_protocol_ota_api));
+ __this->wait_app_reboot = need_wait_app_reboot;
+#if OTA_TWS_SAME_TIME_ENABLE
+ tws_sync_update_crc_handler_register(__this->ota_api.ota_crc_init_hdl, __this->ota_api.ota_crc_calc_hdl);
+ g_printf("crc_init_hdl:0x%x crc_calc_hdl:0x%x\n", __this->ota_api.ota_crc_init_hdl, __this->ota_api.ota_crc_calc_hdl);
+#endif
+}
+
+
+void initiative_ota_init(void (*resume_hdl)(void *priv), int (*sleep_hdl)(void *priv))
+{
+ os_sem_create(&(__this->ota_sem), 0);
+ initiative_ota_resume_hdl_register(resume_hdl, sleep_hdl);
+}
+
+u16 initiative_ota_f_open(void)
+{
+ log_info(">>>initiative_ota_f_open\n");
+ __this->file_offset = 0;
+ __this->seek_type = BT_SEEK_SET;
+ return 1;
+}
+
+void initiative_ota_handle(u8 state, void *buf, int len)
+{
+ /* log_info("R"); */
+ if (state != __this->state) {
+ log_info(">>>initiative state err\n");
+ return;
+ }
+
+ switch (state) {
+ case UPDATA_REV_DATA:
+ if (__this->read_buf) {
+ memcpy(__this->read_buf, buf, len);
+ __this->read_len = len;
+ __this->state = 0;
+ }
+ break;
+
+ case UPDATA_STOP:
+ __this->state = 0;
+ break;
+ }
+
+ if (__this->resume_hdl) {
+ __this->resume_hdl(NULL);
+ }
+}
+
+u16 initiative_ota_f_read(void *fp, u8 *buff, u16 len)
+{
+ u8 retry_cnt = 0;
+
+ __this->need_rx_len = len;
+ __this->state = UPDATA_REV_DATA;
+ __this->read_len = 0;
+ __this->read_buf = buff;
+
+__RETRY:
+ if (app_protocol_get_cur_handle_id() == 0) { //如果已经断开连接直接返回-1 */
+ return -1;
+ }
+
+ if (__this->ota_cancle_flag) {
+ return -1;
+ }
+
+ if (__this->ota_api.ota_request_data == NULL) {
+ return -1;
+ }
+
+ printf("initiative_ota_read\n");
+ __this->ota_api.ota_request_data(fp, __this->file_offset, len);
+
+ while (!((0 == __this->state) && (__this->read_len == len))) {
+ if (__this->sleep_hdl && app_protocol_get_cur_handle_id()) {
+ __this->sleep_hdl(NULL);
+ } else {
+ len = -1;
+ break;
+ }
+
+ if (!((0 == __this->state) && (__this->read_len == len))) {
+ if (retry_cnt++ > RETRY_TIMES) {
+ len = (u16) - 1;
+ break;
+ } else {
+ goto __RETRY;
+ }
+ }
+ }
+
+ if ((u16) - 1 != len) {
+ __this->file_offset += len;
+ }
+
+ return len;
+}
+
+int initiative_ota_f_seek(void *fp, u8 type, u32 offset)
+{
+ if (type == SEEK_SET) {
+ __this->file_offset = offset;
+ __this->seek_type = BT_SEEK_SET;
+ } else if (type == SEEK_CUR) {
+ __this->file_offset += offset;
+ __this->seek_type = BT_SEEK_CUR;
+ }
+
+ return 0;//FR_OK;
+}
+
+static u16 initiative_ota_f_stop(u8 err)
+{
+ //err = update_result_handle(err);
+ __this->state = UPDATA_STOP;
+ log_info(">>>initiative_ota_stop:%x err:0x%x\n", __this->state, err);
+
+ if (__this->ota_cancle_flag) {
+ return -1;
+ }
+
+ if (__this->ota_api.ota_request_data) {
+ __this->ota_api.ota_request_data(NULL, 0, 0);
+ }
+
+ while (!(0 == __this->state)) {
+ if (__this->sleep_hdl) { // && get_rcsp_connect_status()) {
+ if (__this->sleep_hdl(NULL) == OS_TIMEOUT) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ if (__this->ota_api.ota_report_result) {
+ __this->ota_api.ota_report_result(err);
+ }
+
+ return 1;
+}
+
+static int initiative_ota_notify_update_content_size(void *priv, u32 size)
+{
+ int err;
+ u8 data[4];
+ /* WRITE_BIG_U32(data, size); */
+ /* user_change_ble_conn_param(0); */
+ log_info("send content_size:%x\n", size);
+ if (__this->ota_api.ota_notify_file_size) {
+ __this->ota_api.ota_notify_file_size(size);
+ }
+ /* err = JL_CMD_send(JL_OPCODE_NOTIFY_UPDATE_CONENT_SIZE, data, sizeof(data), JL_NEED_RESPOND); */
+
+ return err;
+}
+
+const update_op_api_t initiative_update_op = {
+ .ch_init = initiative_ota_init,
+ .f_open = initiative_ota_f_open,
+ .f_read = initiative_ota_f_read,
+ .f_seek = initiative_ota_f_seek,
+ .f_stop = initiative_ota_f_stop,
+ .notify_update_content_size = initiative_ota_notify_update_content_size,
+};
+
+void app_protocol_ota_update_success_reset(void *priv)
+{
+ cpu_reset();
+}
+
+static void initiative_ota_state_cbk(int type, u32 state, void *priv)
+{
+ update_ret_code_t *ret_code = (update_ret_code_t *)priv;
+ if (ret_code) {
+ log_info("state:%x err:%x\n", ret_code->stu, ret_code->err_code);
+ }
+ switch (state) {
+ case UPDATE_CH_EXIT:
+ if (UPDATE_DUAL_BANK_IS_SUPPORT()) {
+ if ((0 == ret_code->stu) && (0 == ret_code->err_code)) {
+ /* set_jl_update_flag(1); */
+ log_info(">>>initiative update succ\n");
+ update_result_set(UPDATA_SUCC);
+ __this->update_result = APP_UPDATE_SUCC;
+#if !OTA_TWS_SAME_TIME_ENABLE
+ sys_timeout_add(NULL, app_protocol_ota_update_success_reset, 2000); //延时一段时间再reset保证命令已经发送
+#endif
+ } else {
+ log_info(">>>initiative update failed\n");
+ update_result_set(UPDATA_DEV_ERR);
+ __this->update_result = APP_UPDATE_FAILED;
+ }
+ } else {
+ if ((0 == ret_code->stu) && (0 == ret_code->err_code)) {
+ __this->update_result = APP_UPDATE_SUCC;
+ /* set_jl_update_flag(1); */
+ }
+ }
+ os_sem_post(&(__this->ota_sem));
+ break;
+ }
+}
+
+//被动升级请求下一帧数据
+int passive_ota_write_callback(void *priv)
+{
+ if (__this->ota_api.ota_request_data) {
+ __this->ota_api.ota_request_data(NULL, 0, 0);
+ }
+ return 0;
+}
+
+
+int passive_ota_set_boot_info_callback(int ret)
+{
+ if (__this->ota_api.ota_report_result) {
+ __this->ota_api.ota_report_result(ret);
+ }
+
+ if (ret == 0) { //0表示boot info写成功
+#if OTA_TWS_SAME_TIME_ENABLE
+ if (app_protocol_update_tws_api && app_protocol_update_tws_api->tws_ota_result_hdl && !__this->wait_app_reboot) {
+ app_protocol_update_tws_api->tws_ota_result_hdl(0);
+ }
+#else
+ sys_timeout_add(NULL, app_protocol_ota_update_success_reset, 2000); //延时一段时间再reset保证命令已经发送
+#endif
+ __this->update_result = APP_UPDATE_SUCC;
+ } else {
+ dual_bank_passive_update_exit(NULL);
+#if OTA_TWS_SAME_TIME_ENABLE
+ if (app_protocol_update_tws_api && app_protocol_update_tws_api->tws_ota_err) {
+ app_protocol_update_tws_api->tws_ota_err(0);
+ }
+ __this->update_result = APP_UPDATE_FAILED;
+#endif
+ }
+ return 0;
+}
+
+int passive_ota_crc_result_call_back(int crc_res)
+{
+ if (crc_res) { //校验成功
+ log_info("crc check succ, write boot_info\n");
+ u8 update_boot_info_flag, verify_err;
+#if OTA_TWS_SAME_TIME_ENABLE
+ if (app_protocol_update_tws_api && app_protocol_update_tws_api->exit_verify_hdl) {
+ if (app_protocol_update_tws_api->exit_verify_hdl(&verify_err, &update_boot_info_flag)) {
+ dual_bank_update_burn_boot_info((int (*)(int))passive_ota_set_boot_info_callback);
+ } else { //从机写boot_info失败
+ if (__this->ota_api.ota_report_result) {
+ __this->ota_api.ota_report_result(APP_CHECK_CRC_FAILED);
+ }
+ if (app_protocol_update_tws_api && app_protocol_update_tws_api->tws_ota_err) { //通知从机升级失败
+ app_protocol_update_tws_api->tws_ota_err(0);
+ }
+ __this->update_result = APP_UPDATE_FAILED;
+ }
+ } else
+#endif
+ {
+ dual_bank_update_burn_boot_info((int (*)(int))passive_ota_set_boot_info_callback);
+ }
+ } else { //校验失败
+ if (__this->ota_api.ota_report_result) {
+ __this->ota_api.ota_report_result(APP_CHECK_CRC_FAILED);
+ }
+#if OTA_TWS_SAME_TIME_ENABLE
+ if (app_protocol_update_tws_api && app_protocol_update_tws_api->tws_ota_err) { //通知从机升级失败
+ app_protocol_update_tws_api->tws_ota_err(0);
+ }
+#endif
+ __this->update_result = APP_UPDATE_FAILED;
+ //app_protocol_reply_frame_check_result(crc_res);
+ dual_bank_passive_update_exit(NULL);
+ }
+ return 0;
+}
+
+int app_protocol_ota_interrupt_by_disconnect(int id)
+{
+ if (check_ota_type_by_protocol_id(id) == INITIATIVE_OTA) {
+
+ } else {
+#if OTA_TWS_SAME_TIME_ENABLE
+ if (app_protocol_update_tws_api && app_protocol_update_tws_api->tws_ota_err) {
+ app_protocol_update_tws_api->tws_ota_err(0);
+ }
+#endif
+ dual_bank_passive_update_exit(NULL);
+ }
+ return 0;
+}
+
+int app_protocol_update_success_flag(void)
+{
+ return __this->update_result;
+}
+
+int app_protocol_ota_message_handler(int id, int opcode, u8 *data, u32 len)
+{
+ int err_code = UPDATE_RESULT_ERR_NONE;
+ int ret = 0;
+ switch (opcode) {
+ case APP_PROTOCOL_OTA_CHECK:
+ log_info("APP_PROTOCOL_OTA_CHECK\n");
+ ota_frame_info *frame_info = data;
+ dual_bank_passive_update_init(frame_info->frame_crc, frame_info->frame_size, frame_info->max_pkt_len, NULL);
+ ret = dual_bank_update_allow_check(frame_info->frame_size);
+ if (ret) {
+ err_code = UPDATE_RESULT_RESOURCE_LIMIT;
+ dual_bank_passive_update_exit(NULL);
+ } else { //for tws sync update init
+#if OTA_TWS_SAME_TIME_ENABLE
+ app_protocol_update_tws_api = get_tws_update_api();
+ struct __tws_ota_para tws_update_para;
+ tws_update_para.fm_size = frame_info->frame_size;
+ tws_update_para.fm_crc16 = frame_info->frame_crc;
+ tws_update_para.max_pkt_len = frame_info->max_pkt_len;
+ if (app_protocol_update_tws_api && app_protocol_update_tws_api->tws_ota_start) {
+ if (app_protocol_update_tws_api->tws_ota_start(&tws_update_para)) {
+ err_code = UPDATE_RESULT_OTA_TWS_START_ERR;
+ dual_bank_passive_update_exit(NULL);
+ }
+ }
+ __this->sync_update_first_packet = 1;
+#endif
+ }
+ break;
+
+ case APP_PROTOCOL_OTA_BEGIN:
+ update_mode_info_t info = {
+ .type = BLE_APP_UPDATA,
+ .state_cbk = initiative_ota_state_cbk,
+ .p_op_api = &initiative_update_op,
+ .task_en = 1,
+ };
+ __this->ota_cancle_flag = 0;
+ app_active_update_task_init(&info);
+ break;
+
+ case APP_PROTOCOL_OTA_TRANS_DATA:
+ log_info("APP_PROTOCOL_OTA_TRANS_DATA\n");
+ if (check_ota_type_by_protocol_id(id) == INITIATIVE_OTA) {
+ initiative_ota_handle(UPDATA_REV_DATA, data, len);
+ } else {
+#if OTA_TWS_SAME_TIME_ENABLE
+ if (!__this->sync_update_first_packet) { //第一次传输不需要pend
+ if (app_protocol_update_tws_api && app_protocol_update_tws_api->tws_ota_data_send_pend) {
+ if (app_protocol_update_tws_api->tws_ota_data_send_pend()) {
+ log_info(" UPDATE_ERR_WAIT_TWS_RESPONSE_TIMEOUT\n");
+ err_code = UPDATE_RESULT_OTA_TWS_NO_RSP;
+ break;
+ }
+ }
+ }
+ __this->sync_update_first_packet = 0;
+#endif
+ dual_bank_update_write(data, len, passive_ota_write_callback);
+#if OTA_TWS_SAME_TIME_ENABLE
+ if (app_protocol_update_tws_api && app_protocol_update_tws_api->tws_ota_data_send) {
+ app_protocol_update_tws_api->tws_ota_data_send(data, len);
+ }
+#endif
+ }
+ break;
+
+ case APP_PROTOCOL_OTA_GET_APP_VERSION:
+ u32 fm_version = app_protocol_get_version_by_id(id);
+ break;
+
+ case APP_PROTOCOL_OTA_CHECK_CRC:
+ if (check_ota_type_by_protocol_id(id) == INITIATIVE_OTA) {
+ os_sem_pend(&(__this->ota_sem), 0);
+ err_code = __this->update_result;
+ } else {
+ clk_set("sys", 160 * 1000000L); //提升主频加快CRC校验速度
+#if OTA_TWS_SAME_TIME_ENABLE
+ if (app_protocol_update_tws_api && app_protocol_update_tws_api->tws_ota_data_send_pend) { //pend 最后一包数据
+ if (app_protocol_update_tws_api->tws_ota_data_send_pend()) {
+ log_info(" UPDATE_ERR_WAIT_TWS_RESPONSE_TIMEOUT\n");
+ err_code = UPDATE_RESULT_OTA_TWS_NO_RSP;
+ break;
+ }
+ }
+
+ if (app_protocol_update_tws_api && app_protocol_update_tws_api->enter_verfiy_hdl) {
+ if (app_protocol_update_tws_api->enter_verfiy_hdl(NULL)) { //从机校验CRC
+ log_info("update enter verify err\n");
+ if (__this->ota_api.ota_report_result) {
+ __this->ota_api.ota_report_result(APP_CHECK_CRC_FAILED);
+ }
+ } else {
+ log_info("update enter verify succ\n");
+ dual_bank_update_verify(__this->ota_api.ota_crc_init_hdl, __this->ota_api.ota_crc_calc_hdl, passive_ota_crc_result_call_back);
+ }
+ } else
+#endif
+ {
+ dual_bank_update_verify(__this->ota_api.ota_crc_init_hdl, __this->ota_api.ota_crc_calc_hdl, passive_ota_crc_result_call_back);
+ }
+ }
+ break;
+
+ case APP_PROTOCOL_OTA_CANCLE:
+ __this->ota_cancle_flag = 1;
+ break;
+
+ case APP_PROTOCOL_OTA_REBOOT:
+ __this->state = 0;
+ /* #if OTA_TWS_SAME_TIME_ENABLE //同步升级在update lib里进行重启 */
+ /* g_printf("APP_PROTOCOL_OTA_REBOOT!!!\n"); */
+ /* #else */
+ /* cpu_reset(); */
+ /* #endif */
+ break;
+
+ case APP_PROTOCOL_OTA_PERCENT:
+
+ break;
+ case APP_PROTOCOL_OTA_END:
+
+ break;
+ case APP_PROTOCOL_OTA_SUCCESS:
+
+ break;
+ case APP_PROTOCOL_OTA_FAIL:
+
+ break;
+ }
+ return err_code;
+}
+#endif
diff --git a/apps/common/third_party_profile/interface/app_protocol_ota.h b/apps/common/third_party_profile/interface/app_protocol_ota.h
new file mode 100644
index 0000000..83ac38b
--- /dev/null
+++ b/apps/common/third_party_profile/interface/app_protocol_ota.h
@@ -0,0 +1,28 @@
+#ifndef __APP_PROTOCOL_OTA_H__
+#define __APP_PROTOCOL_OTA_H__
+
+#include "typedef.h"
+
+#define NO_SUPPORT_OTA 0xff
+#define INITIATIVE_OTA 0x01
+#define PASSIVE_OTA 0x02
+
+typedef struct app_protocol_ota_type_map_t {
+ u32 protocol_id;
+ u8 ota_type;
+} app_protocol_ota_type_map;
+
+typedef struct app_protocol_ota_api_t {
+ u32(*ota_request_data)(void *priv, u32 offset, u16 len);
+ u32(*ota_report_result)(u8 result);
+ void (*ota_notify_file_size)(u32 file_size);
+ void (*ota_crc_init_hdl)(void);
+ u16(*ota_crc_calc_hdl)(u16 init_crc, u8 *data, u32 len);
+} app_protocol_ota_api;
+
+int app_protocol_ota_message_handler(int id, int opcode, u8 *data, u32 len);
+void app_protocol_ota_init(app_protocol_ota_api *api, u8 need_wait_app_reboot);
+int app_protocol_ota_interrupt_by_disconnect(int id);
+int app_protocol_update_success_flag(void);
+
+#endif //__APP_PROTOCOL_OTA_H__
diff --git a/apps/common/third_party_profile/interface/app_protocol_tme.c b/apps/common/third_party_profile/interface/app_protocol_tme.c
new file mode 100644
index 0000000..7b83e0d
--- /dev/null
+++ b/apps/common/third_party_profile/interface/app_protocol_tme.c
@@ -0,0 +1,126 @@
+#include
+#include
+#include
+
+#include "app_protocol_api.h"
+#include "system/includes.h"
+#include "audio_config.h"
+#include "app_power_manage.h"
+#include "user_cfg.h"
+#include "btstack/avctp_user.h"
+#include "bt_tws.h"
+
+#if APP_PROTOCOL_TME_CODE
+
+extern void TME_set_edr_connected(u8 flag);
+
+//*********************************************************************************//
+// TME认证信息 //
+//*********************************************************************************//
+
+//*********************************************************************************//
+// TME提示音 //
+//*********************************************************************************//
+const char *tme_notice_tab[APP_RROTOCOL_TONE_MAX] = {
+ [APP_RROTOCOL_TONE_SPEECH_KEY_START] = TONE_NORMAL,
+};
+
+//*********************************************************************************//
+// TME弱函数实现 //
+//*********************************************************************************//
+
+//*********************************************************************************//
+// TME私有消息处理 //
+//*********************************************************************************//
+#if 1
+extern int le_controller_set_mac(void *addr);
+extern int le_controller_get_mac(void *addr);
+
+#if TCFG_USER_TWS_ENABLE
+static void tme_tws_rx_from_sibling(u16 cmd, u8 *data, u16 len)
+{
+#if TCFG_USER_TWS_ENABLE
+ switch (cmd) {
+ }
+#endif
+}
+
+static void tme_update_ble_addr()
+{
+ u8 ble_old_addr[6];
+ u8 ble_new_addr[6];
+ u8 comm_addr[6];
+
+ printf("%s\n", __func__);
+
+ tws_api_get_local_addr(comm_addr);
+ le_controller_get_mac(ble_old_addr);
+ lib_make_ble_address(ble_new_addr, comm_addr);
+ le_controller_set_mac(ble_new_addr); //地址发生变化,更新地址
+ if (is_tws_master_role() && memcmp(ble_old_addr, ble_new_addr, 6)) {
+ app_protocol_disconnect(NULL);
+ app_protocol_ble_adv_switch(0);
+ app_protocol_ble_adv_switch(1);
+ }
+}
+
+static void tme_bt_tws_event_handler(struct bt_event *bt)
+{
+ int role = bt->args[0];
+ int phone_link_connection = bt->args[1];
+ int reason = bt->args[2];
+
+ switch (bt->event) {
+ case TWS_EVENT_CONNECTED:
+ tme_update_ble_addr();
+ if (BT_STATUS_WAITINT_CONN != get_bt_connect_status()) {
+ TME_set_edr_connected(1);
+ }
+ break;
+ case TWS_EVENT_REMOVE_PAIRS:
+ tme_update_ble_addr();
+ break;
+ }
+
+}
+#endif
+
+static int tme_bt_status_event_handler(struct bt_event *bt)
+{
+ switch (bt->event) {
+ case BT_STATUS_SECOND_CONNECTED:
+ case BT_STATUS_FIRST_CONNECTED:
+ TME_set_edr_connected(1); //连接过经典蓝牙标志
+ break;
+ }
+ return 0;
+}
+
+int tme_sys_event_deal(struct sys_event *event)
+{
+ switch (event->type) {
+ case SYS_BT_EVENT:
+ if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) {
+ tme_bt_status_event_handler(&event->u.bt);
+ }
+#if TCFG_USER_TWS_ENABLE
+ else if (((u32)event->arg == SYS_BT_EVENT_FROM_TWS)) {
+ tme_bt_tws_event_handler(&event->u.bt);
+ }
+#endif
+ break;
+
+ }
+
+ return 0;
+
+}
+
+struct app_protocol_private_handle_t tme_private_handle = {
+ /* .tws_rx_from_siblling = tme_tws_rx_from_sibling, */
+ .sys_event_handler = tme_sys_event_deal,
+};
+#endif
+
+#endif
+
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_adaptive_noise_reduction.c b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_adaptive_noise_reduction.c
new file mode 100644
index 0000000..0519cf9
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_adaptive_noise_reduction.c
@@ -0,0 +1,89 @@
+#include "adv_adaptive_noise_reduction.h"
+#include "syscfg_id.h"
+#include "user_cfg_id.h"
+#include "rcsp_adv_bluetooth.h"
+
+#if (RCSP_ADV_EN && RCSP_ADV_ANC_VOICE && RCSP_ADV_ADAPTIVE_NOISE_REDUCTION)
+
+#include "audio_anc.h"
+
+
+/**
+ * @brief 获取自适应降噪信息开关
+ *
+ * @result 1:自适应降噪开 0:自适应降噪关
+ */
+int get_adaptive_noise_reduction_switch()
+{
+ int sw_result = audio_anc_coeff_mode_get();
+ return sw_result;
+}
+
+/**
+ * @brief 开启自适应降噪
+ */
+void set_adaptive_noise_reduction_on()
+{
+ audio_anc_coeff_adaptive_set(1, 1, 1);
+}
+
+/**
+ * @brief 关闭自适应降噪
+ */
+void set_adaptive_noise_reduction_off()
+{
+ audio_anc_coeff_adaptive_set(0, 1, 1);
+}
+
+static u8 adaptive_noise_reduction_reseting = 0; // 重新检测状态,1:进行中 0:结束
+static u8 adaptive_noise_reduction_reset_result = 0; // 重新检测结果,1:失败 0:成功
+/**
+ * @brief 自适应降噪重新检测
+ */
+void set_adaptive_noise_reduction_reset()
+{
+ audio_anc_mode_ear_adaptive();
+ adaptive_noise_reduction_reseting = 1;
+}
+
+/**
+ * @brief 获取自适应降噪重新检测状态
+ *
+ * @result 1:进行中 0:结束
+ */
+u8 get_adaptive_noise_reduction_reset_status()
+{
+ return adaptive_noise_reduction_reseting;
+}
+
+/**
+ * @brief 获取自适应降噪重新检测结果
+ *
+ * @result 1:失败 0:成功
+ */
+u8 get_adaptive_noise_reduction_reset_result()
+{
+ return adaptive_noise_reduction_reset_result;
+}
+
+/**
+ * @brief 自适应降噪重新检测结果回调
+ */
+void set_adaptive_noise_reduction_reset_callback(u8 result)
+{
+ adaptive_noise_reduction_reseting = 0;
+ if (result != 0) {
+ // 成功
+ adaptive_noise_reduction_reset_result = 0;
+ } else {
+ // 失败
+ adaptive_noise_reduction_reset_result = 1;
+ }
+ // 通知手机APP
+ /* JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_UPDATE_ANC_VOICE, NULL, 0); */
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_UPDATE_ADAPTIVE_NOISE_REDUCTION, NULL, 0);
+}
+
+#endif
+
+
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_adaptive_noise_reduction.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_adaptive_noise_reduction.h
new file mode 100644
index 0000000..ab0f862
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_adaptive_noise_reduction.h
@@ -0,0 +1,48 @@
+#ifndef __ADV_ADAPTIVE_NOISE_REDUCTION_H__
+#define __ADV_ADAPTIVE_NOISE_REDUCTION_H__
+
+#include "le_rcsp_adv_module.h"
+
+/**
+ * @brief 获取自适应降噪信息开关
+ *
+ * @result 1:自适应降噪开 0:自适应降噪关
+ */
+int get_adaptive_noise_reduction_switch();
+
+/**
+ * @brief 开启自适应降噪
+ */
+void set_adaptive_noise_reduction_on();
+
+/**
+ * @brief 关闭自适应降噪
+ */
+void set_adaptive_noise_reduction_off();
+
+/**
+ * @brief 自适应降噪重新检测
+ */
+void set_adaptive_noise_reduction_reset();
+
+/**
+ * @brief 获取自适应降噪重新检测状态
+ *
+ * @result 1:进行中 0:结束
+ */
+u8 get_adaptive_noise_reduction_reset_status();
+
+/**
+ * @brief 获取自适应降噪重新检测结果
+ *
+ * @result 1:失败 0:成功
+ */
+u8 get_adaptive_noise_reduction_reset_result();
+
+/**
+ * @brief 自适应降噪重新检测结果回调
+ */
+void set_adaptive_noise_reduction_reset_callback(u8 result);
+
+#endif
+
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_ai_no_pick.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_ai_no_pick.h
new file mode 100644
index 0000000..c3b5572
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_ai_no_pick.h
@@ -0,0 +1,54 @@
+#ifndef __ADV_AI_NO_PICK_H__
+#define __ADV_AI_NO_PICK_H__
+
+#include "system/includes.h"
+
+typedef enum {
+ RCSP_AI_NO_PICK_SENSITIVITY_HIGH = 0x00,
+ RCSP_AI_NO_PICK_SENSITIVITY_LOW = 0x01,
+} RCSP_AI_NO_PICK_SENSITIVITY;
+
+typedef enum {
+ RCSP_AI_NO_PICK_AUTO_CLOSE_TIME_NONE = 0x00, // 不自动关闭
+ RCSP_AI_NO_PICK_AUTO_CLOSE_TIME_5s = 0x01,
+ RCSP_AI_NO_PICK_AUTO_CLOSE_TIME_15s = 0x02,
+ RCSP_AI_NO_PICK_AUTO_CLOSE_TIME_30s = 0x03,
+} RCSP_AI_NO_PICK_AUTO_CLOSE_TIME;
+
+/**
+ * @brief 获取智能免摘开关
+ *
+ * @result bool
+ */
+bool get_ai_no_pick_switch();
+
+/**
+ * @brief 开启智能免摘
+ */
+void set_ai_no_pick_switch(bool p_switch);
+
+/**
+ * @brief 获取智能免摘敏感度
+ *
+ * @result RCSP_AI_NO_PICK_SENSITIVITY
+ */
+RCSP_AI_NO_PICK_SENSITIVITY get_ai_no_pick_sensitivity();
+
+/**
+ * @brief 设置智能免摘敏感度
+ */
+void set_ai_no_pick_sensitivity(RCSP_AI_NO_PICK_SENSITIVITY sensitivity);
+
+/**
+ * @brief 获取智能免摘自动关闭时间
+ *
+ * @result RCSP_AI_NO_PICK_AUTO_CLOSE_TIME
+ */
+RCSP_AI_NO_PICK_AUTO_CLOSE_TIME get_ai_no_pick_auto_close_time();
+
+/**
+ * @brief 设置智能免摘自动关闭时间
+ */
+void set_ai_no_pick_auto_close_time(RCSP_AI_NO_PICK_AUTO_CLOSE_TIME time_type);
+
+#endif // __ADV_AI_NO_PICK_H__
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_anc_voice.c b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_anc_voice.c
new file mode 100644
index 0000000..b6031a2
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_anc_voice.c
@@ -0,0 +1,335 @@
+#include "app_config.h"
+#include "syscfg_id.h"
+#include "user_cfg_id.h"
+#include "le_rcsp_adv_module.h"
+
+#include "adv_anc_voice.h"
+#include "adv_setting_common.h"
+#include "rcsp_adv_tws_sync.h"
+#include "rcsp_adv_opt.h"
+
+#include "rcsp_adv_bluetooth.h"
+
+#if (RCSP_ADV_EN && RCSP_ADV_ANC_VOICE)
+
+#include "audio_anc.h"
+
+// anc信息:mode(1byte/0/1/2) + ( left_max(2byte) + right_max(2byte) + left_cur_val(2byte) + right_cur_val(2byte) ) * 3
+static u8 g_anc_info[25] = {0};
+
+extern int get_bt_tws_connect_status();
+extern u8 JL_get_cur_bt_channel_sel(void);
+
+static bool check_pos_neg(u8 mode)
+{
+ bool ret = false;
+ u8 offset = 1 + mode * 8;
+#if TCFG_USER_TWS_ENABLE
+ if ('R' == tws_api_get_local_channel()) {
+ offset += 2;
+ }
+#endif
+ s16 val = g_anc_info[offset] << 8 | g_anc_info[offset + 1];
+ if (val < 0) {
+ ret = true;
+ }
+ return ret;
+}
+
+void get_anc_voice_info(u8 *anc_info)
+{
+ memcpy(anc_info, g_anc_info, sizeof(g_anc_info));
+}
+
+void set_anc_voice_info(u8 *anc_info)
+{
+ memcpy(g_anc_info, anc_info, sizeof(g_anc_info));
+}
+
+static void update_anc_voice_vm_value(u8 *anc_info)
+{
+ u8 anc_vm_info[25] = {-1};
+ int ret = syscfg_read(CFG_RCSP_ADV_ANC_VOICE_MODE, anc_vm_info, 1);
+ if (0 != memcmp(anc_vm_info, anc_info, 1)) {
+ ret = syscfg_write(CFG_RCSP_ADV_ANC_VOICE_MODE, anc_info, 1);
+ }
+
+ ret = syscfg_read(CFG_RCSP_ADV_ANC_VOICE, anc_vm_info + 1, sizeof(anc_vm_info) - 1);
+ if (0 != memcmp(anc_vm_info + 1, anc_info + 1, sizeof(anc_vm_info) - 1)) {
+ ret = syscfg_write(CFG_RCSP_ADV_ANC_VOICE, anc_info + 1, sizeof(anc_vm_info) - 1);
+ }
+}
+
+static void anc_voice_sync(u8 *anc_info)
+{
+#if TCFG_USER_TWS_ENABLE
+ if (get_bt_tws_connect_status()) {
+ update_adv_setting(BIT(ATTR_TYPE_ANC_VOICE));
+ }
+#endif
+}
+
+static void anc_voice_effect_set(u8 mode, s16 value)
+{
+ static s16 value_old = -1;
+#if TCFG_AUDIO_ANC_ENABLE
+ extern void anc_gain_app_value_set(int app_value);
+ if (value != value_old) {
+ /* audio_anc_gain(value, value); */
+ anc_gain_app_value_set(value);
+ }
+ anc_mode_switch(mode + 1, 1);
+#endif
+ value_old = value;
+}
+
+static void anc_voice_state_update(void)
+{
+ u8 offset = 0;
+ u8 mode = g_anc_info[offset++];
+ offset += mode * 8;
+ s16 left_max = g_anc_info[offset++] << 8 | g_anc_info[offset++];
+ s16 right_max = g_anc_info[offset++] << 8 | g_anc_info[offset++];
+ s16 left_val = g_anc_info[offset++] << 8 | g_anc_info[offset++];
+ s16 right_val = g_anc_info[offset++] << 8 | g_anc_info[offset++];
+
+#if TCFG_USER_TWS_ENABLE
+ if ('R' == tws_api_get_local_channel()) {
+ if (check_pos_neg(mode) && right_val >= right_max) {
+ anc_voice_effect_set(mode, right_val);
+ } else if (right_max >= right_val) {
+ anc_voice_effect_set(mode, right_val);
+ }
+ return;
+ }
+#endif
+
+ if (check_pos_neg(mode) && left_val >= left_max) {
+ anc_voice_effect_set(mode, left_val);
+ } else if (left_max >= left_val) {
+ anc_voice_effect_set(mode, left_val);
+ }
+}
+
+void deal_anc_voice(u8 *anc_setting, u8 write_vm, u8 tws_sync)
+{
+ u8 anc_info[25] = {0};
+ if (!anc_setting) {
+ get_anc_voice_info(anc_info);
+ } else {
+ u8 mode = anc_setting[0];
+ g_anc_info[0] = mode;
+ memcpy(g_anc_info + 1 + mode * 8, anc_setting + 1, 8);
+ memcpy(anc_info, g_anc_info, sizeof(anc_info));
+ }
+ if (write_vm) {
+ update_anc_voice_vm_value(anc_info);
+ }
+
+ if (tws_sync) {
+ anc_voice_sync(anc_info);
+ }
+
+ anc_voice_state_update();
+}
+
+#if TCFG_USER_TWS_ENABLE
+#define TWS_FUNC_ID_ANC_VOICE_SYNC \
+ (((u8)('R' + 'C' + 'S' + 'P') << (3 * 8)) | \
+ ((u8)('A' + 'N' + 'C' + 'S') << (2 * 8)) | \
+ ((u8)('V' + 'O' + 'I' + 'C' + 'E') << (1 * 8)) | \
+ ((u8)('S' + 'Y' + 'N' + 'C') << (0 * 8)))
+
+void anc_voice_max_val_swap_sync(u8 *data, u16 len)
+{
+ update_anc_voice_vm_value(g_anc_info);
+}
+
+static void anc_voice_state_sync(u8 *data, u16 len)
+{
+ if (NULL == data || 0 == len) {
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_UPDATE_ANC_VOICE, NULL, 0);
+ return;
+ }
+ u8 offset = 9;
+ // 假如当前是右耳,应该填写左值
+ // 假如当前是左耳,应该填写右值
+ if ('L' == tws_api_get_local_channel()) {
+ offset += 2;
+ }
+ // 根据左右耳填充对应的最大值信息
+ // 降噪(2byte) + 通透(2byte)
+ memcpy(g_anc_info + offset, data, 2);
+ memcpy(g_anc_info + offset + 4, data + 4, 2);
+ offset += 8;
+ memcpy(g_anc_info + offset, data + 2, 2);
+ memcpy(g_anc_info + offset + 4, data + 6, 2);
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_UPDATE_ANC_VOICE_MAX_SYNC, NULL, 0);
+}
+
+static void adv_anc_voice_tws_func_t(void *data, u16 len, bool rx)
+{
+ if (rx) {
+ anc_voice_state_sync((u8 *)data, len);
+ }
+}
+
+REGISTER_TWS_FUNC_STUB(adv_tws_sync) = {
+ .func_id = TWS_FUNC_ID_ANC_VOICE_SYNC,
+ .func = adv_anc_voice_tws_func_t,
+};
+
+#endif
+
+void rcsp_adv_voice_mode_update(u8 mode)
+{
+ u8 anc_info[25] = {0};
+ get_anc_voice_info(anc_info);
+ anc_info[0] = mode;
+ if (mode) {
+ memcpy(anc_info + 1, anc_info + 1 + mode * 8, 8);
+ }
+ deal_anc_voice(anc_info, 1, 0);
+#if TCFG_USER_TWS_ENABLE
+ if (get_bt_tws_connect_status() && TWS_ROLE_SLAVE == tws_api_get_role()) {
+ tws_api_send_data_to_sibling(NULL, 0, TWS_FUNC_ID_ANC_VOICE_SYNC);
+ return;
+ }
+#endif
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_UPDATE_ANC_VOICE, NULL, 0);
+}
+
+int anc_voice_setting_sync()
+{
+ int ret = 0;
+ u8 anc_info[8] = {0};
+#if (TCFG_AUDIO_ANC_ENABLE)
+ /* extern int anc_gain_tab[3]; */
+ /* u16 noise_reduction = (u16)(16384 & (u16) - 1); // 调用接口获取降噪最大值 */
+ /* u16 transparent = (u16)(16384 & (u16) - 1); // 调用接口获取通透最大值 */
+
+ u16 noise_reduction = 16384; // 调用接口获取降噪最大值
+ u16 transparent = 16384; // 调用接口获取通透最大值
+#else
+ u16 noise_reduction = 0;
+ u16 transparent = 0;
+#endif
+
+ anc_info[0] = ((u8 *)&noise_reduction)[1];
+ anc_info[1] = ((u8 *)&noise_reduction)[0];
+ anc_info[2] = ((u8 *)&transparent)[1];
+ anc_info[3] = ((u8 *)&transparent)[0];
+
+ u8 offset = 9;
+#if TCFG_USER_TWS_ENABLE
+ if ('R' == tws_api_get_local_channel()) {
+ offset += 2;
+ }
+#endif
+
+ // 初始值最大和当前值都是同一个值
+ // 默认是左值
+ u8 tmp_value = -1;
+ int result = 0;
+ if ((result = syscfg_read(CFG_RCSP_ADV_ANC_VOICE_MODE, &tmp_value, sizeof(tmp_value))) != sizeof(tmp_value)) {
+ tmp_value = offset;
+ memcpy(g_anc_info + tmp_value, anc_info, 2);
+ tmp_value += 4;
+ memcpy(g_anc_info + tmp_value, anc_info, 2);
+ tmp_value += 4;
+ memcpy(g_anc_info + tmp_value, anc_info + 2, 2);
+ tmp_value += 4;
+ memcpy(g_anc_info + tmp_value, anc_info + 2, 2);
+ }
+
+#if TCFG_USER_TWS_ENABLE
+ // 填写当前降噪/通透当前值
+ memcpy(anc_info + 4, g_anc_info + offset + 4, 2);
+ memcpy(anc_info + 6, g_anc_info + offset + 8 + 4, 2);
+ // 把自己的最大值发送给对端
+ if (get_bt_tws_connect_status()) {
+ tws_api_send_data_to_sibling(anc_info, sizeof(anc_info), TWS_FUNC_ID_ANC_VOICE_SYNC);
+ }
+#endif
+ return ret;
+}
+
+int anc_voice_setting_init(void)
+{
+ int ret = 1;
+ u8 anc_mode = -1;
+ if (syscfg_read(CFG_RCSP_ADV_ANC_VOICE_MODE, &anc_mode, sizeof(anc_mode)) != sizeof(anc_mode)) {
+ anc_voice_setting_sync();
+ ret = 0;
+ }
+ return ret;
+}
+
+// ====================================================
+enum {
+ anc_VOICE_GET_PREP_MSG,
+ anc_VOICE_SET_CUR_MODE,
+ anc_VOICE_NOTICE_MSG,
+ anc_VOICE_GET_CUR_MODE,
+};
+
+static void s16_pos_neg_conversion(u8 *data)
+{
+ s16 tmp_val = data[0] << 8 | data[1];
+ tmp_val = -tmp_val;
+ data[1] = ((u8 *)&tmp_val)[0];
+ data[0] = ((u8 *)&tmp_val)[1];
+}
+
+u8 anc_voice_info_get(u8 *data, u16 len)
+{
+ u8 offset = 0;
+ u8 anc_info[25] = {0};
+ get_anc_voice_info(anc_info);
+ u8 mode = anc_info[0];
+ data[offset++] = mode;
+ memcpy(data + offset, anc_info + 1 + mode * 8, 8);
+ if (check_pos_neg(mode)) {
+ for (u8 i = 0; i < 8; i += 2) {
+ s16_pos_neg_conversion(data + 1 + i);
+ }
+ }
+ offset += 8;
+ return offset;
+}
+
+u8 anc_voice_info_fetch_all_get(u8 *data, u16 len)
+{
+ u8 mode = 0;
+ u8 offset = 1;
+ u8 anc_info[25] = {0};
+ get_anc_voice_info(anc_info);
+ for (u8 resp_offset = 1; offset < sizeof(anc_info); offset += 8) {
+ data[resp_offset++] = mode;
+ memcpy(data + resp_offset, anc_info + offset, 8);
+ if (check_pos_neg(mode)) {
+ for (u8 i = 0; i < 8; i += 2) {
+ s16_pos_neg_conversion(data + 2 + mode * 9 + i);
+ }
+ }
+ resp_offset += 8;
+ mode++;
+ }
+ data[0] = mode;
+ return len;
+}
+
+int anc_voice_info_set(u8 *data, u16 len)
+{
+ int ret = 0;
+ if (check_pos_neg(data[0])) {
+ for (u8 i = 0; i < 8; i += 2) {
+ s16_pos_neg_conversion(data + 1 + i);
+ }
+ }
+ deal_anc_voice(data, 1, 1);
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_UPDATE_ANC_VOICE, NULL, 0);
+ return ret;
+}
+
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_anc_voice.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_anc_voice.h
new file mode 100644
index 0000000..d289728
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_anc_voice.h
@@ -0,0 +1,19 @@
+#ifndef __ADV_ANS_VOICE_H__
+#define __ADV_ANS_VOICE_H__
+
+#include "le_rcsp_adv_module.h"
+
+int anc_voice_setting_init(void);
+int anc_voice_setting_sync(void);
+
+void deal_anc_voice(u8 *anc_setting, u8 write_vm, u8 tws_sync);
+void set_anc_voice_info(u8 *anc_info);
+void get_anc_voice_info(u8 *anc_info);
+
+u8 anc_voice_info_get(u8 *data, u16 len);
+u8 anc_voice_info_fetch_all_get(u8 *data, u16 len);
+int anc_voice_info_set(u8 *data, u16 len);
+int update_anc_voice_key_opt(void);
+void rcsp_adv_voice_mode_update(u8 mode);
+
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_anc_voice_key.c b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_anc_voice_key.c
new file mode 100644
index 0000000..55a283b
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_anc_voice_key.c
@@ -0,0 +1,94 @@
+#include "app_config.h"
+#include "syscfg_id.h"
+#include "user_cfg_id.h"
+#include "key_event_deal.h"
+#include "le_rcsp_adv_module.h"
+
+#include "adv_anc_voice_key.h"
+#include "adv_setting_common.h"
+#include "rcsp_adv_tws_sync.h"
+#include "rcsp_adv_opt.h"
+
+#include "adv_anc_voice.h"
+
+#if (RCSP_ADV_EN)
+/* #if (RCSP_ADV_KEY_SET_ENABLE && TCFG_AUDIO_ANC_ENABLE) */
+#if (RCSP_ADV_KEY_SET_ENABLE)
+
+//#include "audio_anc.h"
+
+#define COMMON_FUNCTION 0xFF
+#define ANC_VOICE_TYPE_MAX 3
+
+static u8 g_anc_voice_key_mode[4] = {0, 0, 0, BIT(ANC_VOICE_TYPE_MAX) - 1};
+
+extern int get_bt_tws_connect_status();
+
+void set_anc_voice_key_mode(u8 *anc_voice_mode)
+{
+ memcpy(g_anc_voice_key_mode, anc_voice_mode, sizeof(g_anc_voice_key_mode));
+}
+
+void get_anc_voice_key_mode(u8 *anc_voice_mode)
+{
+ memcpy(anc_voice_mode, g_anc_voice_key_mode, sizeof(g_anc_voice_key_mode));
+}
+
+static void update_anc_voice_key_vm_value(u8 *anc_voice_mode)
+{
+ syscfg_write(CFG_RCSP_ADV_ANC_VOICE_KEY, anc_voice_mode, 4);
+}
+
+static void anc_voice_key_sync(u8 *key_setting_info)
+{
+#if TCFG_USER_TWS_ENABLE
+ if (get_bt_tws_connect_status()) {
+ update_adv_setting(BIT(ATTR_TYPE_ANC_VOICE_KEY));
+ }
+#endif
+}
+
+void deal_anc_voice_key_setting(u8 *anc_key_setting, u8 write_vm, u8 tws_sync)
+{
+ u8 anc_voice_key_mode[4] = {0};
+ if (!anc_key_setting) {
+ get_anc_voice_key_mode(anc_voice_key_mode);
+ } else {
+ set_anc_voice_key_mode(anc_key_setting);
+ memcpy(anc_voice_key_mode, g_anc_voice_key_mode, sizeof(g_anc_voice_key_mode));
+ }
+ if (write_vm) {
+ update_anc_voice_key_vm_value(anc_voice_key_mode);
+ }
+ if (tws_sync) {
+ anc_voice_key_sync(anc_voice_key_mode);
+ }
+}
+
+int update_anc_voice_key_opt(void)
+{
+ int ret = 0;
+#if (RCSP_ADV_ANC_VOICE)
+ u32 mask = g_anc_voice_key_mode[0] << 24 | g_anc_voice_key_mode[1] << 16 | g_anc_voice_key_mode[2] << 8 | g_anc_voice_key_mode[3];
+ // 获取当前处于什么模式
+#if TCFG_AUDIO_ANC_ENABLE
+ u8 cur_mode = anc_mode_get();
+#else
+ u8 cur_mode = ANC_OFF;
+#endif
+ u8 next_mode = cur_mode % ANC_VOICE_TYPE_MAX;
+ for (; next_mode < ANC_VOICE_TYPE_MAX; next_mode++) {
+ if (mask & BIT(next_mode)) {
+ rcsp_adv_voice_mode_update(next_mode % ANC_VOICE_TYPE_MAX);
+ return ret;
+ }
+ }
+ if (mask & BIT(next_mode % ANC_VOICE_TYPE_MAX)) {
+ rcsp_adv_voice_mode_update(next_mode % ANC_VOICE_TYPE_MAX);
+ }
+#endif
+ return ret;
+}
+
+#endif
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_anc_voice_key.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_anc_voice_key.h
new file mode 100644
index 0000000..b34ed8a
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_anc_voice_key.h
@@ -0,0 +1,12 @@
+#ifndef __ADV_ANC_VOICE_KEY_H__
+#define __ADV_ANC_VOICE_KEY_H__
+
+#include "le_rcsp_adv_module.h"
+
+void deal_anc_voice_key_setting(u8 *anc_key_setting, u8 write_vm, u8 tws_sync);
+void get_anc_voice_key_mode(u8 *anc_voice_mode);
+void set_anc_voice_key_mode(u8 *anc_voice_mode);
+
+int update_anc_voice_key_opt(void);
+
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_bt_name_setting.c b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_bt_name_setting.c
new file mode 100644
index 0000000..59278ba
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_bt_name_setting.c
@@ -0,0 +1,67 @@
+#include "app_config.h"
+#include "user_cfg.h"
+#include "syscfg_id.h"
+#include "user_cfg_id.h"
+#include "le_rcsp_adv_module.h"
+
+#include "adv_bt_name_setting.h"
+#include "adv_setting_common.h"
+#include "rcsp_adv_tws_sync.h"
+#include "rcsp_adv_opt.h"
+
+#if (RCSP_ADV_EN)
+#if RCSP_ADV_NAME_SET_ENABLE
+extern int get_bt_tws_connect_status();
+
+void adv_edr_name_change_now(void)
+{
+ extern BT_CONFIG bt_cfg;
+ extern const char *bt_get_local_name();
+ extern void lmp_hci_write_local_name(const char *name);
+ memcpy(bt_cfg.edr_name, _s_info.edr_name, LOCAL_NAME_LEN);
+ lmp_hci_write_local_name(bt_get_local_name());
+}
+
+void set_bt_name_setting(u8 *bt_name_setting)
+{
+ memcpy(_s_info.edr_name, bt_name_setting, 32);
+}
+
+void get_bt_name_setting(u8 *bt_name_setting)
+{
+ memcpy(bt_name_setting, _s_info.edr_name, 32);
+}
+
+// 1、写入VM
+static void update_bt_name_vm_value(u8 *bt_name_setting)
+{
+ syscfg_write(CFG_BT_NAME, bt_name_setting, 32);
+}
+// 2、同步对端
+static void bt_name_sync(u8 *bt_name_setting)
+{
+#if TCFG_USER_TWS_ENABLE
+ if (get_bt_tws_connect_status()) {
+ update_adv_setting(BIT(ATTR_TYPE_EDR_NAME));
+ }
+#endif
+}
+
+void deal_bt_name_setting(u8 *bt_name_setting, u8 write_vm, u8 tws_sync)
+{
+ u8 bt_name[32] = {0};
+ if (!bt_name_setting) {
+ get_bt_name_setting(bt_name);
+ } else {
+ memcpy(bt_name, bt_name_setting, 32);
+ }
+ if (write_vm) {
+ update_bt_name_vm_value(bt_name);
+ }
+ if (tws_sync) {
+ bt_name_sync(bt_name);
+ }
+}
+#endif
+
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_bt_name_setting.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_bt_name_setting.h
new file mode 100644
index 0000000..00318f7
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_bt_name_setting.h
@@ -0,0 +1,12 @@
+#ifndef __ADV_BT_NAME_SETTING_H__
+#define __ADV_BT_NAME_SETTING_H__
+
+#include "le_rcsp_adv_module.h"
+
+#if RCSP_ADV_NAME_SET_ENABLE
+
+void set_bt_name_setting(u8 *bt_name_setting);
+void get_bt_name_setting(u8 *bt_name_setting);
+
+#endif
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_eq_setting.c b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_eq_setting.c
new file mode 100644
index 0000000..f140aba
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_eq_setting.c
@@ -0,0 +1,218 @@
+#include "app_config.h"
+#include "syscfg_id.h"
+#include "user_cfg_id.h"
+#include "le_rcsp_adv_module.h"
+
+#include "adv_eq_setting.h"
+#include "adv_setting_common.h"
+#include "rcsp_adv_tws_sync.h"
+#include "rcsp_adv_opt.h"
+#include "application/audio_eq.h"
+
+#if (RCSP_ADV_EN)
+#if RCSP_ADV_EQ_SET_ENABLE
+extern int get_bt_tws_connect_status();
+extern int eq_mode_get_freq(u8 mode, u16 index);
+extern s8 eq_mode_get_gain(u8 mode, u16 index);
+extern int eq_mode_set_custom_param(u16 index, int gain);
+extern int eq_mode_set(u8 mode);
+extern int eq_mode_get_cur(void);
+
+static void eq_setting_info_deal(u8 *eq_info_data)
+{
+ u8 data;
+ u8 status;
+ u8 mode;
+ if (eq_info_data[0] >> 7) {
+ status = eq_info_data[2];
+ } else {
+ status = *(((u8 *)eq_info_data) + 1);
+ }
+ mode = eq_info_data[0] & 0x7F;
+ if (mode < EQ_MODE_CUSTOM) {
+ eq_mode_set(mode);
+ } else {
+ // 自定义修改EQ参数
+ if (EQ_MODE_CUSTOM == mode) {
+ if (status != 0x7F) {
+ u8 i;
+ for (i = 0; i < EQ_SECTION_MAX; i++) {
+ if (eq_info_data[0] >> 7) {
+ data = eq_info_data[i + 2];
+ } else {
+ data = eq_info_data[i + 1];
+ }
+ eq_mode_set_custom_param(i, (s8)data);
+ }
+ }
+ eq_mode_set(mode);
+ }
+ }
+}
+
+void set_eq_setting(u8 *eq_setting)
+{
+ u8 i;
+ u8 eq_setting_mode = eq_setting[0];
+ if (eq_setting_mode >> 7) {
+ // 多段eq
+ for (i = 2; i < eq_setting[1] + 2; i++) {
+ if ((eq_setting[i] > 12) && (eq_setting[i] < -12)) {
+ eq_setting[i] = 0;
+ }
+ }
+ } else {
+ // 10段eq
+ for (i = 1; i < 11; i++) {
+ if ((eq_setting[i] > 12) && (eq_setting[i] < -12)) {
+ eq_setting[i] = 0;
+ }
+ }
+ }
+ memcpy(_s_info.eq_mode_info, eq_setting, 11);
+}
+
+void get_eq_setting(u8 *eq_setting)
+{
+ memcpy(eq_setting, _s_info.eq_mode_info, 11);
+}
+
+// 1、写入VM
+static void update_eq_vm_value(u8 *eq_setting)
+{
+ u8 status = *(((u8 *)eq_setting) + 1);
+
+ syscfg_write(CFG_RCSP_ADV_EQ_MODE_SETTING, eq_setting, 1);
+
+ /*自定义修改EQ参数*/
+ if (EQ_MODE_CUSTOM == (eq_setting[0] & 0x7F)) {
+ if (eq_setting[0] >> 7) {
+ // 多段eq
+ status = eq_setting[2];
+ }
+ if (status != 0x7F) {
+ syscfg_write(CFG_RCSP_ADV_EQ_DATA_SETTING, &eq_setting[1], 10);
+ }
+ }
+
+}
+// 2、同步对端
+static void eq_sync(u8 *eq_setting)
+{
+#if TCFG_USER_TWS_ENABLE
+ if (get_bt_tws_connect_status()) {
+ update_adv_setting(BIT(ATTR_TYPE_EQ_SETTING));
+ }
+#endif
+}
+
+void deal_eq_setting(u8 *eq_setting, u8 write_vm, u8 tws_sync)
+{
+ u8 eq_info[11] = {0};
+ if (!eq_setting) {
+ get_eq_setting(eq_info);
+ } else {
+ u8 status = *(((u8 *)eq_setting) + 1);
+
+ /*自定义修改EQ参数*/
+ if (EQ_MODE_CUSTOM == (eq_setting[0] & 0x7F)) {
+ if (eq_setting[0] >> 7) {
+ status = eq_setting[2];
+ }
+
+ if (status != 0x7F) {
+ memcpy(eq_info, eq_setting, 11);
+ set_eq_setting(eq_info);
+ } else {
+ _s_info.eq_mode_info[0] = eq_setting[0];
+ get_eq_setting(eq_info);
+ }
+ } else {
+ memcpy(eq_info, eq_setting, 11);
+ _s_info.eq_mode_info[0] = eq_setting[0];
+ }
+
+ }
+ if (write_vm) {
+ update_eq_vm_value(eq_info);
+ }
+ if (tws_sync) {
+ eq_sync(eq_info);
+ }
+ eq_setting_info_deal(eq_info);
+}
+
+
+u8 app_get_eq_info(u8 *get_eq_info)
+{
+ u16 i;
+ get_eq_info[0] = eq_mode_get_cur();
+ u8 data_len = 1;
+
+ if (10 == EQ_SECTION_MAX) {
+ // 10段eq : mode + gain[10byte]
+ for (i = 0; i < 10; i++) {
+ get_eq_info[data_len] = eq_mode_get_gain(get_eq_info[0], i);
+ data_len++;
+ }
+ } else {
+ // 多段eq : mode + num + value(freq[2byte] + gain[1byte])
+ get_eq_info[1] = EQ_SECTION_MAX;
+ data_len++;
+ for (i = 0; i < EQ_SECTION_MAX; i++) {
+ get_eq_info[data_len] = eq_mode_get_gain(get_eq_info[0], i);
+ data_len++;
+ }
+ get_eq_info[0] |= (1 << 7);
+ }
+ return data_len;
+}
+
+u8 app_get_eq_all_info(u8 *get_eq_info)
+{
+ u16 i;
+ u8 mode = EQ_MODE_NORMAL;
+ get_eq_info[0] = EQ_SECTION_MAX;
+ u8 data_len = 1;
+ // get freq
+ for (i = 0; i < EQ_SECTION_MAX; i++) {
+ u16 eq_freq = (u16)(eq_mode_get_freq(mode, i) & ((u16) - 1));
+ eq_freq = ((((u8 *)&eq_freq)[0] << 8) + ((u8 *)&eq_freq)[1]);
+ memcpy(get_eq_info + data_len, &eq_freq, sizeof(eq_freq));
+ data_len += 2;
+ }
+ // get gain
+ for (; mode < EQ_MODE_CUSTOM; mode++) {
+ get_eq_info[data_len] = mode;
+ if (10 != EQ_SECTION_MAX) {
+ get_eq_info[data_len] |= (1 << 7);
+ }
+ data_len++;
+ for (i = 0; i < EQ_SECTION_MAX; i++) {
+ u8 eq_gain = eq_mode_get_gain(mode, i);
+ get_eq_info[data_len] = eq_gain;
+ data_len++;
+ }
+ }
+ // get custom
+ get_eq_info[data_len] = EQ_MODE_CUSTOM;
+ if (10 != EQ_SECTION_MAX) {
+ get_eq_info[data_len] |= (1 << 7);
+ }
+ data_len++;
+ for (i = 0; i < EQ_SECTION_MAX; i++) {
+ if (10 == EQ_SECTION_MAX) {
+ get_eq_info[data_len] = _s_info.eq_mode_info[i + 1];
+ } else {
+ get_eq_info[data_len] = _s_info.eq_mode_info[i + 2];
+ }
+ data_len++;
+ }
+
+ return data_len;
+}
+
+
+#endif
+
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_eq_setting.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_eq_setting.h
new file mode 100644
index 0000000..5e350d6
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_eq_setting.h
@@ -0,0 +1,20 @@
+#ifndef __ADV_EQ_SETTING_H__
+#define __ADV_EQ_SETTING_H__
+
+#include "le_rcsp_adv_module.h"
+
+#if defined(RCSP_ADV_EQ_SET_ENABLE) && RCSP_ADV_EQ_SET_ENABLE
+
+struct _EQ_INFO {
+ u8 mode;
+ s8 gain_val[10];
+};
+
+void set_eq_setting(u8 *eq_setting);
+void get_eq_setting(u8 *eq_setting);
+void deal_eq_setting(u8 *eq_setting, u8 write_vm, u8 tws_sync);
+u8 app_get_eq_info(u8 *get_eq_info);
+u8 app_get_eq_all_info(u8 *get_eq_info);
+
+#endif
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_high_low_vol.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_high_low_vol.h
new file mode 100644
index 0000000..58a0329
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_high_low_vol.h
@@ -0,0 +1,18 @@
+#ifndef __ADV_HIGH_LOW_VOL__
+#define __ADV_HIGH_LOW_VOL__
+
+#include "le_rcsp_adv_module.h"
+
+#if RCSP_ADV_HIGH_LOW_SET
+
+struct _HIGL_LOW_VOL {
+ int low_vol;
+ int high_vol;
+};
+
+void get_high_low_vol_info(u8 *vol_gain_param);
+void set_high_low_vol_info(u8 *vol_gain_param);
+void deal_high_low_vol(u8 *vol_gain_data, u8 write_vm, u8 tws_sync);
+
+#endif
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_high_low_vol_setting.c b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_high_low_vol_setting.c
new file mode 100644
index 0000000..f7060c0
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_high_low_vol_setting.c
@@ -0,0 +1,81 @@
+#include "app_config.h"
+#include "syscfg_id.h"
+#include "user_cfg_id.h"
+#include "adv_high_low_vol.h"
+
+#include "adv_setting_common.h"
+#include "rcsp_adv_tws_sync.h"
+#include "rcsp_adv_opt.h"
+
+#if (RCSP_ADV_EN)
+#if RCSP_ADV_HIGH_LOW_SET
+
+static struct _HIGL_LOW_VOL high_low_vol = {
+ .low_vol = 12,
+ .high_vol = 12,
+};
+
+extern int get_bt_tws_connect_status();
+extern int audio_out_eq_spec_set_gain(u8 idx, int gain);
+
+void get_high_low_vol_info(u8 *vol_gain_param)
+{
+ memcpy(vol_gain_param, &high_low_vol, sizeof(struct _HIGL_LOW_VOL));
+}
+
+void set_high_low_vol_info(u8 *vol_gain_param)
+{
+ memcpy(&high_low_vol, vol_gain_param, sizeof(struct _HIGL_LOW_VOL));
+}
+
+static void update_high_low_vol_vm_value(u8 *vol_gain_param)
+{
+ syscfg_write(CFG_RCSP_ADV_HIGH_LOW_VOL, vol_gain_param, sizeof(struct _HIGL_LOW_VOL));
+}
+
+static void high_low_vol_setting_sync(u8 *vol_gain_param)
+{
+#if TCFG_USER_TWS_ENABLE
+ if (get_bt_tws_connect_status()) {
+ update_adv_setting(BIT(ATTR_TYPE_HIGH_LOW_VOL));
+ }
+#endif
+}
+
+static void high_low_vol_state_update(void)
+{
+#if (TCFG_AUDIO_OUT_EQ_ENABLE != 0)
+ static int low_vol = 0;
+ static int high_vol = 0;
+ if (low_vol != high_low_vol.low_vol) {
+ audio_out_eq_spec_set_gain(0, high_low_vol.low_vol - 12);
+ low_vol = high_low_vol.low_vol;
+ }
+ if (high_vol != high_low_vol.high_vol) {
+ audio_out_eq_spec_set_gain(1, high_low_vol.high_vol - 12);
+ high_vol = high_low_vol.high_vol;
+ }
+#endif
+}
+
+void deal_high_low_vol(u8 *vol_gain_data, u8 write_vm, u8 tws_sync)
+{
+ int vol_gain_param[2] = {0};
+ if (!vol_gain_data) {
+ get_high_low_vol_info((u8 *)vol_gain_param);
+ } else {
+ memcpy((u8 *)&vol_gain_param, vol_gain_data, sizeof(vol_gain_param));
+ set_high_low_vol_info(vol_gain_data);
+ printf("low %d, high %d\n", vol_gain_param[0], vol_gain_param[1]);
+ }
+ if (write_vm) {
+ update_high_low_vol_vm_value((u8 *)vol_gain_param);
+ }
+ if (tws_sync) {
+ high_low_vol_setting_sync((u8 *)vol_gain_param);
+ }
+ high_low_vol_state_update();
+}
+
+#endif
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_key_setting.c b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_key_setting.c
new file mode 100644
index 0000000..7f4cf7f
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_key_setting.c
@@ -0,0 +1,219 @@
+#include "app_config.h"
+#include "syscfg_id.h"
+#include "user_cfg_id.h"
+#include "key_event_deal.h"
+#include "le_rcsp_adv_module.h"
+
+#include "adv_key_setting.h"
+#include "adv_setting_common.h"
+#include "rcsp_adv_tws_sync.h"
+#include "rcsp_adv_opt.h"
+
+#include "adv_anc_voice_key.h"
+
+#if (RCSP_ADV_EN)
+#if RCSP_ADV_KEY_SET_ENABLE
+
+extern int get_bt_tws_connect_status();
+static u8 rcsp_adv_key_event_flag = 0x0;
+static void enable_adv_key_event(void)
+{
+ rcsp_adv_key_event_flag = 1;
+}
+
+static u8 get_adv_key_event_status(void)
+{
+ return rcsp_adv_key_event_flag;
+}
+
+static void disable_adv_key_event(void)
+{
+ rcsp_adv_key_event_flag = 0;
+}
+
+void set_key_setting(u8 *key_setting_info)
+{
+ _s_info.key_setting[3 * 0 + 2] = key_setting_info[0];
+ _s_info.key_setting[3 * 2 + 2] = key_setting_info[1];
+ _s_info.key_setting[3 * 1 + 2] = key_setting_info[2];
+ _s_info.key_setting[3 * 3 + 2] = key_setting_info[3];
+}
+
+void get_key_setting(u8 *key_setting_info)
+{
+ key_setting_info[0] = _s_info.key_setting[3 * 0 + 2];
+ key_setting_info[1] = _s_info.key_setting[3 * 2 + 2];
+ key_setting_info[2] = _s_info.key_setting[3 * 1 + 2];
+ key_setting_info[3] = _s_info.key_setting[3 * 3 + 2];
+}
+
+static void update_key_setting_vm_value(u8 *key_setting_info)
+{
+ syscfg_write(CFG_RCSP_ADV_KEY_SETTING, key_setting_info, 4);
+}
+
+static void key_setting_sync(u8 *key_setting_info)
+{
+#if TCFG_USER_TWS_ENABLE
+ if (get_bt_tws_connect_status()) {
+ update_adv_setting(BIT(ATTR_TYPE_KEY_SETTING));
+ }
+#endif
+}
+
+void deal_key_setting(u8 *key_setting_info, u8 write_vm, u8 tws_sync)
+{
+ u8 key_setting[4];
+ if (!key_setting_info) {
+ get_key_setting(key_setting);
+ } else {
+ memcpy(key_setting, key_setting_info, 4);
+ }
+ // 1、写入VM
+ if (write_vm) {
+ update_key_setting_vm_value(key_setting);
+ }
+ // 2、同步对端
+ if (tws_sync) {
+ key_setting_sync(key_setting);
+ }
+ // 3、更新状态
+ enable_adv_key_event();
+}
+
+#define ADV_POWER_ON_OFF 0
+enum ADV_KEY_TYPE {
+ ADV_KEY_TYPE_NULL = 0x0,
+#if ADV_POWER_ON_OFF
+ ADV_KEY_TYPE_POWER_ON,
+ ADV_KEY_TYPE_POWER_OFF,
+#endif
+ ADV_KEY_TYPE_PREV = 0x3,
+ ADV_KEY_TYPE_NEXT,
+ ADV_KEY_TYPE_PP,
+ ADV_KEY_TYPE_ANSWER_CALL,
+ ADV_KEY_TYPE_HANG_UP,
+ ADV_KEY_TYPE_CALL_BACK,
+ ADV_KEY_TYPE_INC_VOICE,
+ ADV_KEY_TYPE_DESC_VOICE,
+ ADV_KEY_TYPE_TAKE_PHOTO,
+ ADV_KEY_TYPE_ANC_VOICE = 0xFF,
+};
+
+static u8 get_adv_key_opt(u8 key_action, u8 channel)
+{
+ u8 opt;
+ for (opt = 0; opt < sizeof(_s_info.key_setting); opt += 3) {
+ if (_s_info.key_setting[opt] == channel &&
+ _s_info.key_setting[opt + 1] == key_action) {
+ break;
+ }
+ }
+ if (sizeof(_s_info.key_setting) == opt) {
+ return -1;
+ }
+ switch (_s_info.key_setting[opt + 2]) {
+ case ADV_KEY_TYPE_NULL:
+ //opt = KEY_NULL;
+ opt = ADV_KEY_TYPE_NULL;
+ break;
+#if ADV_POWER_ON_OFF
+ case ADV_KEY_TYPE_POWER_ON:
+ opt = KEY_POWER_ON;
+ break;
+ case ADV_KEY_TYPE_POWER_OFF:
+ opt = KEY_RCSP_POWEROFF;
+ break;
+#endif
+ case ADV_KEY_TYPE_PREV:
+ opt = KEY_MUSIC_PREV;
+ break;
+ case ADV_KEY_TYPE_NEXT:
+ opt = KEY_MUSIC_NEXT;
+ break;
+ case ADV_KEY_TYPE_PP:
+ opt = KEY_MUSIC_PP;
+ break;
+ case ADV_KEY_TYPE_ANSWER_CALL:
+ opt = KEY_CALL_ANSWER;
+ break;
+ case ADV_KEY_TYPE_HANG_UP:
+ opt = KEY_CALL_HANG_UP;
+ break;
+ case ADV_KEY_TYPE_CALL_BACK:
+ opt = KEY_CALL_LAST_NO;
+ break;
+ case ADV_KEY_TYPE_INC_VOICE:
+ opt = KEY_VOL_UP;
+ break;
+ case ADV_KEY_TYPE_DESC_VOICE:
+ opt = KEY_VOL_DOWN;
+ break;
+ case ADV_KEY_TYPE_TAKE_PHOTO:
+ opt = KEY_HID_CONTROL;
+ break;
+ case ADV_KEY_TYPE_ANC_VOICE:
+ update_anc_voice_key_opt();
+ opt = KEY_NULL;
+ break;
+ }
+ return opt;
+}
+
+void set_key_event_by_rcsp_info(struct sys_event *event, u8 *key_event)
+{
+ if (0 == get_adv_key_event_status()) {
+ return;
+ }
+ u8 key_action = 0;
+ struct key_event *key = &event->u.key;
+ switch (key->event) {
+ case 0:
+ // 单击
+ key_action = 0x1;
+ break;
+ case 4:
+ // 双击
+ key_action = 0x2;
+ break;
+ default:
+ return;
+ }
+
+#if (TCFG_CHARGESTORE_ENABLE && TCFG_USER_TWS_ENABLE)
+ u8 channel = tws_api_get_local_channel();
+
+ if (get_bt_tws_connect_status()) {
+ channel = tws_api_get_local_channel();
+ }
+#else
+ u8 channel = 'U';
+#endif
+
+ switch (channel) {
+ case 'U':
+ case 'L':
+ channel = (u32) event->arg == KEY_EVENT_FROM_TWS ? 2 : 1;
+ break;
+ case 'R':
+ channel = (u32) event->arg == KEY_EVENT_FROM_TWS ? 1 : 2;
+ break;
+ default:
+ return;
+ }
+
+ key_action = get_adv_key_opt(key_action, channel);
+ if ((u8) - 1 != key_action) {
+ *key_event = key_action ? key_action : KEY_NULL;
+ }
+}
+#else
+
+
+void set_key_event_by_rcsp_info(struct sys_event *event, u8 *key_event)
+{
+ return;
+}
+
+#endif
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_key_setting.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_key_setting.h
new file mode 100644
index 0000000..9be79b3
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_key_setting.h
@@ -0,0 +1,13 @@
+#ifndef __ADV_KEY_SETTING_H__
+#define __ADV_KEY_SETTING_H__
+
+
+#include "le_rcsp_adv_module.h"
+
+#if RCSP_ADV_KEY_SET_ENABLE
+
+void set_key_setting(u8 *key_setting_info);
+void get_key_setting(u8 *key_setting_info);
+
+#endif
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_led_setting.c b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_led_setting.c
new file mode 100644
index 0000000..34e8969
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_led_setting.c
@@ -0,0 +1,145 @@
+#include "app_config.h"
+#include "syscfg_id.h"
+#include "user_cfg_id.h"
+#include "asm/pwm_led.h"
+#include "user_cfg.h"
+#include "ui_manage.h"
+#include "le_rcsp_adv_module.h"
+
+#include "adv_led_setting.h"
+#include "adv_setting_common.h"
+#include "rcsp_adv_tws_sync.h"
+#include "rcsp_adv_opt.h"
+
+#if (RCSP_ADV_EN)
+#if RCSP_ADV_LED_SET_ENABLE
+
+enum ADV_LED_TYPE {
+ ADV_LED_TYPE_ALL_OFF = 0x0,
+ ADV_LED_TYPE_RED_ON,
+ ADV_LED_TYPE_BLUE_ON,
+ ADV_LED_TYPE_RAD_BREATHE,
+ ADV_LED_TYPE_BLUE_BREATHE,
+ ADV_LED_TYPE_FAST_FLASH,
+ ADV_LED_TYPE_SLOW_FLASH,
+};
+
+extern STATUS *get_led_config(void);
+extern int get_bt_tws_connect_status();
+
+
+__attribute__((weak))
+u8 adv_get_led_status(void)
+{
+ return 1;
+}
+
+static u8 adv_led_value_conversion(u8 adv_led_opt)
+{
+ u8 conversion_value = adv_led_opt;
+ switch (adv_led_opt) {
+ case ADV_LED_TYPE_ALL_OFF:
+ conversion_value = PWM_LED_ALL_OFF;
+ break;
+ case ADV_LED_TYPE_RED_ON:
+ conversion_value = PWM_LED1_ON;
+ break;
+ case ADV_LED_TYPE_BLUE_ON:
+ conversion_value = PWM_LED0_ON;
+ break;
+ case ADV_LED_TYPE_RAD_BREATHE:
+ conversion_value = PWM_LED1_BREATHE;
+ break;
+ case ADV_LED_TYPE_BLUE_BREATHE:
+ conversion_value = PWM_LED0_BREATHE;
+ break;
+ case ADV_LED_TYPE_FAST_FLASH:
+ conversion_value = PWM_LED0_LED1_FAST_FLASH;
+ break;
+ case ADV_LED_TYPE_SLOW_FLASH:
+ conversion_value = PWM_LED0_LED1_SLOW_FLASH;
+ break;
+ }
+ return conversion_value;
+}
+
+void set_led_setting(u8 *led_setting_info)
+{
+ _s_info.led_status[2 * 0 + 1] = led_setting_info[0];
+ _s_info.led_status[2 * 1 + 1] = led_setting_info[1];
+ _s_info.led_status[2 * 2 + 1] = led_setting_info[2];
+}
+
+void get_led_setting(u8 *led_setting_info)
+{
+ led_setting_info[0] = _s_info.led_status[2 * 0 + 1];
+ led_setting_info[1] = _s_info.led_status[2 * 1 + 1];
+ led_setting_info[2] = _s_info.led_status[2 * 2 + 1];
+}
+
+// 1、写入VM
+static void update_led_setting_vm_value(u8 *led_setting_info)
+{
+ syscfg_write(CFG_RCSP_ADV_LED_SETTING, led_setting_info, 3);
+}
+// 2、同步对端
+static void led_setting_sync(u8 *led_setting_info)
+{
+#if TCFG_USER_TWS_ENABLE
+ if (get_bt_tws_connect_status()) {
+ update_adv_setting(BIT(ATTR_TYPE_LED_SETTING));
+ }
+#endif
+}
+// 3、更新状态
+void update_led_setting_state(void)
+{
+ u8 led_setting_info[3];
+ get_led_setting(led_setting_info);
+
+ // 直接修改led表
+ STATUS *p_led = get_led_config();
+ // 未配对
+ p_led->bt_init_ok = adv_led_value_conversion(led_setting_info[0]);
+ p_led->bt_disconnect = adv_led_value_conversion(led_setting_info[0]);
+ // 未连接
+ p_led->tws_connect_ok = adv_led_value_conversion(led_setting_info[1]);
+ // 连接
+ p_led->bt_connect_ok = adv_led_value_conversion(led_setting_info[2]);
+
+ switch (adv_get_led_status()) {
+ case STATUS_BT_INIT_OK:
+ case STATUS_BT_DISCONN:
+ ui_update_status(STATUS_BT_INIT_OK);
+ break;
+ case STATUS_BT_TWS_CONN:
+ ui_update_status(STATUS_BT_TWS_CONN);
+ break;
+ case STATUS_PHONE_ACTIV:
+ case STATUS_PHONE_OUT:
+ case STATUS_PHONE_INCOME:
+ case STATUS_BT_CONN:
+ ui_update_status(STATUS_BT_CONN);
+ break;
+ }
+}
+
+void deal_led_setting(u8 *led_setting_info, u8 write_vm, u8 tws_sync)
+{
+ u8 led_setting[3];
+ if (!led_setting_info) {
+ get_led_setting(led_setting);
+ } else {
+ memcpy(led_setting, led_setting_info, 3);
+ }
+ if (write_vm) {
+ update_led_setting_vm_value(led_setting);
+ }
+ if (tws_sync) {
+ led_setting_sync(led_setting);
+ }
+ update_led_setting_state();
+}
+
+#endif
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_led_setting.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_led_setting.h
new file mode 100644
index 0000000..9b9b7bf
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_led_setting.h
@@ -0,0 +1,13 @@
+#ifndef __ADV_LED_SETTING_H__
+#define __ADV_LED_SETTING_H__
+
+
+#include "le_rcsp_adv_module.h"
+
+#if RCSP_ADV_LED_SET_ENABLE
+
+void set_led_setting(u8 *led_setting_info);
+void get_led_setting(u8 *led_setting_info);
+
+#endif
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_mic_setting.c b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_mic_setting.c
new file mode 100644
index 0000000..7d13cef
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_mic_setting.c
@@ -0,0 +1,155 @@
+#include "app_config.h"
+#include "syscfg_id.h"
+#include "user_cfg_id.h"
+#include "le_rcsp_adv_module.h"
+
+#include "adv_mic_setting.h"
+#include "adv_setting_common.h"
+#include "rcsp_adv_tws_sync.h"
+#include "rcsp_adv_opt.h"
+
+#if (RCSP_ADV_EN)
+#if RCSP_ADV_MIC_SET_ENABLE
+
+extern void test_esco_role_switch(u8 flag);
+extern void tws_conn_switch_role();
+extern int get_bt_tws_connect_status();
+static void mic_setting_info_deal(u8 mic_info_data)
+{
+#if TCFG_USER_TWS_ENABLE
+ u8 channel = tws_api_get_local_channel();
+ printf("%s, %d\n", __FUNCTION__, channel);
+
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ printf("-----master-----\n");
+ } else {
+ printf("-----role-----\n");
+ }
+ switch (mic_info_data) {
+ case 0x01:
+ if (get_bt_tws_connect_status()) {
+ printf("-------auto--------\n");
+ tws_api_auto_role_switch_enable();
+ }
+ break;
+ case 0x02:
+ if (get_bt_tws_connect_status()) {
+ if (channel != 'L') {
+ printf("-------!L--------\n");
+ tws_api_auto_role_switch_disable();
+ tws_conn_switch_role();
+ }
+ }
+ break;
+ case 0x03:
+ if (get_bt_tws_connect_status()) {
+ if (channel != 'R') {
+ printf("-------!R--------\n");
+ tws_api_auto_role_switch_disable();
+ tws_conn_switch_role();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+#endif
+}
+
+void set_mic_setting(u8 mic_setting_info)
+{
+ _s_info.mic_mode = mic_setting_info;
+}
+
+u8 get_mic_setting(void)
+{
+ return _s_info.mic_mode;
+}
+
+static void update_mic_setting_vm_value(u8 mic_setting_info)
+{
+ syscfg_write(CFG_RCSP_ADV_MIC_SETTING, &mic_setting_info, 1);
+}
+
+static void adv_mic_setting_sync(u8 mic_setting_info)
+{
+#if TCFG_USER_TWS_ENABLE
+ if (get_bt_tws_connect_status()) {
+ update_adv_setting(BIT(ATTR_TYPE_MIC_SETTING));
+ }
+#endif
+}
+
+void deal_mic_setting(u8 mic_setting_info, u8 write_vm, u8 tws_sync)
+{
+ if (!mic_setting_info) {
+ mic_setting_info = get_mic_setting();
+ } else {
+ set_mic_setting(mic_setting_info);
+ }
+ if (write_vm) {
+ update_mic_setting_vm_value(mic_setting_info);
+ }
+ if (tws_sync) {
+ adv_mic_setting_sync(mic_setting_info);
+ }
+ mic_setting_info_deal(mic_setting_info);
+}
+
+
+//通话时,固定mic的位置,mode--esco state
+void rcsp_user_mic_fixed_deal(u8 mode)
+{
+ u8 channel = tws_api_get_local_channel();
+
+ if (!get_bt_tws_connect_status()) {
+ return;
+ }
+
+ if (mode == 0) {
+ test_esco_role_switch(0);
+ return;
+ }
+
+ if ((tws_api_get_role() == TWS_ROLE_MASTER)
+ && (tws_api_get_tws_state() | TWS_STA_ESCO_OPEN)) {
+
+ switch (get_mic_setting()) {
+ case 0x02:
+ if (get_bt_tws_connect_status()) {
+ if (channel != 'L') {
+ printf("mic_sw_l\n");
+ test_esco_role_switch(1);
+ }
+ }
+ break;
+
+ case 0x03:
+ if (get_bt_tws_connect_status()) {
+ if (channel != 'R') {
+ printf("mic_sw_r\n");
+ test_esco_role_switch(1);
+
+ }
+ }
+
+ break;
+
+ default:
+ printf("mic_sw_auto\n");
+ test_esco_role_switch(0);
+ break;
+ }
+ }
+}
+
+#else
+
+void rcsp_user_mic_fixed_deal(u8 mode)
+{
+ return;
+}
+
+#endif
+
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_mic_setting.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_mic_setting.h
new file mode 100644
index 0000000..6cef962
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_mic_setting.h
@@ -0,0 +1,15 @@
+#ifndef __ADV_MIC_SETTING_H__
+#define __ADV_MIC_SETTING_H__
+
+
+#include "le_rcsp_adv_module.h"
+
+#if RCSP_ADV_MIC_SET_ENABLE
+
+void set_mic_setting(u8 mic_setting_info);
+u8 get_mic_setting(void);
+#endif
+
+void rcsp_user_mic_fixed_deal(u8 mode);
+
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_music_info_setting.c b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_music_info_setting.c
new file mode 100644
index 0000000..2a28923
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_music_info_setting.c
@@ -0,0 +1,447 @@
+#include "app_config.h"
+#include "syscfg_id.h"
+#include "user_cfg_id.h"
+#include "le_rcsp_adv_module.h"
+
+#include "adv_setting_common.h"
+#include "rcsp_adv_tws_sync.h"
+#include "rcsp_adv_opt.h"
+#include "adv_music_info_setting.h"
+#include "btstack/avctp_user.h"
+#include "rcsp_adv_bluetooth.h"
+#include "bt_tws.h"
+
+#if (RCSP_ADV_EN)
+#if RCSP_ADV_MUSIC_INFO_ENABLE
+
+
+struct music_info_t {
+ u8 title_len;
+ char title[64];
+ u8 artist_len;
+ char artist[64];
+ u8 album_len;
+ char album[64];
+ u8 num_len;
+ char number;
+ u8 total_len;
+ char total[2];
+ u8 genre_len;
+ char genre[16];
+ char time[8];
+ u8 player_state;
+ u8 player_time_min;
+ u8 player_time_sec;
+ u32 curr_player_time;
+ u8 player_time_en;
+ u32 total_time;
+ volatile int get_music_player_timer;
+};
+
+struct music_info_t music_info;
+void JL_rcsp_event_to_user(u32 type, u8 event, u8 *msg, u8 size);
+
+
+u8 get_player_time_en(void)
+{
+ return music_info.player_time_en;
+}
+
+void set_player_time_en(u8 en)
+{
+ music_info.player_time_en = en;
+}
+
+void reset_player_time_en(void)
+{
+ music_player_time_timer_deal(music_info.player_time_en);
+}
+
+void music_player_time_deal(void *priv)
+{
+ if (BT_STATUS_PLAYING_MUSIC == get_bt_connect_status()) {
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_GET_PLAY_TIME, 0, NULL);
+ }
+}
+
+void get_music_info(void)
+{
+ //printf("\nsend music info\n");
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_GET_MUSIC_INFO, 0, NULL);
+}
+
+void btstack_avrcp_ch_creat_ok(void)
+{
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ //printf("\n\n\n\nrcsp ge music info\n");
+ tws_api_sync_call_by_uuid('T', SYNC_CMD_MUSIC_INFO, 300);
+ } else {
+ if ((tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) == 0) {
+ //printf("\n\n\nno tws rcsp ge music info\n\n");
+ get_music_info();
+ }
+ }
+}
+
+char *get_music_title(void)
+{
+ return music_info.title;
+}
+
+u8 get_music_title_len(void)
+{
+ return music_info.title_len;
+}
+
+char *get_music_artist(void)
+{
+ return music_info.artist;
+}
+
+u8 get_music_artist_len(void)
+{
+ return music_info.artist_len;
+}
+
+char *get_music_album(void)
+{
+ return music_info.album;
+}
+
+u8 get_music_album_len(void)
+{
+ return music_info.album_len;
+}
+
+char *get_music_number(void)
+{
+ return &music_info.number;
+}
+
+u8 get_music_number_len(void)
+{
+ return music_info.num_len;
+}
+
+char *get_music_total(void)
+{
+ return music_info.total;
+}
+
+u8 get_music_total_len(void)
+{
+ return music_info.total_len;
+}
+
+char *get_music_genre(void)
+{
+ return music_info.genre;
+}
+
+u8 get_music_genre_len(void)
+{
+ return music_info.genre_len;
+}
+
+u16 get_music_total_time(void)
+{
+ return (music_info.total_time / 1000);
+}
+
+u32 get_music_curr_time(void)
+{
+ return music_info.curr_player_time;
+ /* return (music_info.player_time_min * 60 + music_info.player_time_sec); */
+}
+
+u8 bt_music_total_time(u32 time)
+{
+ music_info.total_time = time;
+ /* printf("get music time %d\n", music_info.total_time); */
+ return 0;
+}
+
+u8 get_music_player_state(void)
+{
+ return music_info.player_state;
+}
+
+void rcsp_update_player_state(void)
+{
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_UPDATE_PLAYER_STATE, NULL, 0);
+}
+
+
+void bt_status_change(u8 state)
+{
+ if (BT_STATUS_PLAYING_MUSIC == state) {
+ music_info.player_state = 1;
+ } else {
+ music_info.player_state = 0;
+ }
+
+ if ((tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) == 0) {
+ rcsp_update_player_state();
+ } else {
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ tws_api_sync_call_by_uuid('T', SYNC_CMD_MUSIC_PLAYER_STATE, 300);
+ } else {
+ tws_api_sync_call_by_uuid('T', SYNC_CMD_MUSIC_PLAYER_TIEM_EN, 300);
+ }
+ }
+}
+
+void stop_get_music_timer(u8 en)
+{
+ if (en) {
+ music_info.player_time_en = 0;
+ }
+
+ if (music_info.get_music_player_timer) {
+ sys_timeout_del(music_info.get_music_player_timer);
+ music_info.get_music_player_timer = 0;
+ }
+}
+
+
+void music_player_time_timer_deal(u8 en)
+{
+ if (en) {
+ if (music_info.get_music_player_timer == 0) {
+ music_info.get_music_player_timer = sys_timer_add(NULL, music_player_time_deal, 800);
+ }
+ } else {
+ if (music_info.get_music_player_timer) {
+ sys_timer_del(music_info.get_music_player_timer);
+ music_info.get_music_player_timer = 0;
+ }
+ }
+
+
+}
+
+
+void music_info_cmd_handle(u8 *p, u16 len)
+{
+ u8 cmd = *p;
+ u8 *data = p + 1;
+
+ switch (cmd) {
+ case 0x01:
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PLAY, 0, NULL);
+ break;
+
+ case 0x02:
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PREV, 0, NULL);
+ break;
+
+ case 0x03:
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_NEXT, 0, NULL);
+ break;
+
+ case 0x04:
+
+ music_info.player_time_en = *data;
+
+ if (*data) {
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_UPDATE_MUSIC_PLAYER_TIME_TEMER, data, 1);
+ } else {
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_UPDATE_MUSIC_PLAYER_TIME_TEMER, data, 1);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+u32 char_to_hex(char num, u8 ten_num)
+{
+ u32 char_num;
+ switch (num) {
+ case '0':
+ char_num = 0;
+ break;
+ case '1':
+ char_num = 1;
+ break;
+ case '2':
+ char_num = 2;
+ break;
+ case '3':
+ char_num = 3;
+ break;
+ case '4':
+ char_num = 4;
+ break;
+ case '5':
+ char_num = 5;
+ break;
+
+ case '6':
+ char_num = 6;
+ break;
+
+ case '7':
+ char_num = 7;
+ break;
+
+ case '8':
+ char_num = 8;
+ break;
+ case '9':
+ char_num = 9;
+ break;
+ default:
+ char_num = 0;
+
+ }
+
+ switch (ten_num) {
+ case 0:
+ char_num = char_num;
+ break;
+ case 1:
+ char_num = char_num * 10;
+ break;
+ case 2:
+ char_num = char_num * 100;
+ break;
+ case 3:
+ char_num = char_num * 1000;
+ break;
+ case 4:
+ char_num = char_num * 10000;
+ break;
+ case 5:
+ char_num = char_num * 100000;
+ break;
+
+ case 6:
+ char_num = char_num * 1000000;
+ break;
+
+ case 7:
+ char_num = char_num * 10000000;
+ break;
+
+ default:
+ char_num = char_num;
+ }
+
+ return char_num;
+}
+
+u32 num_char_to_hex(char *c, len)
+{
+ u32 total_num = 0;
+ u8 i;
+ for (i = 0; i < len; i++) {
+ total_num += char_to_hex(*(c + i), len - i - 1);
+ }
+ return total_num;
+
+}
+
+
+void rcsp_adv_music_info_deal(u8 type, u32 time, u8 *info, u16 len)
+{
+
+ //printf("info len \n");
+ //put_buf(info,len);
+#if RCSP_ADV_FIND_DEVICE_ENABLE
+ extern u8 find_device_key_flag_get(void);
+ if (find_device_key_flag_get()) {
+ return;
+ }
+#endif
+ switch (type) {
+ case 0:
+ if (time != music_info.total_time) {
+ /* if(music_info.player_time_en) */
+ {
+ music_info.curr_player_time = time;
+ music_info.player_time_min = time / 1000 / 60;
+ music_info.player_time_sec = time / 1000 - (music_info.player_time_min * 60);
+
+ /* printf("total time %d %d->", music_info.total_time, time); */
+ /* printf("muisc time %d %d->", music_info.player_time_min, music_info.player_time_sec); */
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_UPDATE_PLAYER_TIME, NULL, 0);
+ }
+ }
+ return;
+ case 1:
+ if ((info) && (len)) {
+ if (len > 64) {
+ len = 64;
+ }
+ music_info.title_len = len;
+ memcpy(music_info.title, info, len);
+ }
+ break;
+ case 2:
+ if ((info) && (len)) {
+ if (len > 64) {
+ len = 64;
+ }
+ music_info.artist_len = len;
+ memcpy(music_info.artist, info, len);
+ }
+ break;
+ case 3:
+ if ((info) && (len)) {
+ if (len > 64) {
+ len = 64;
+ }
+ music_info.album_len = len;
+ memcpy(music_info.album, info, len);
+ }
+ break;
+ case 4:
+ if ((info) && (len)) {
+ len = 1;
+ music_info.num_len = len;
+ memcpy(&music_info.number, info, len);
+ }
+ break;
+ case 5:
+ if ((info) && (len)) {
+ len = 2;
+ music_info.total_len = len;
+ memcpy(music_info.total, info, len);
+ }
+ break;
+ case 6:
+ if ((info) && (len)) {
+ if (len > 16) {
+ len = 16;
+ }
+ music_info.genre_len = len;
+ memcpy(music_info.genre, info, len);
+ }
+ break;
+ case 7:
+ if ((info) && (len)) {
+ if (len > 8) {
+ len = 8;
+ }
+ memcpy(music_info.time, info, len);
+
+ /* printf("get time %s\n", info); */
+ /* put_buf(music_info.time, len); */
+ music_info.total_time = num_char_to_hex(music_info.time, len);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (music_info.player_time_en) {
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_UPDATE_MUSIC_INFO, &type, 1);
+ }
+ /* os_time_dly(2); */
+}
+
+
+#endif
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_music_info_setting.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_music_info_setting.h
new file mode 100644
index 0000000..7b406c8
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_music_info_setting.h
@@ -0,0 +1,31 @@
+#ifndef __ADV_MUSIC_INFO_SETTING_H__
+#define __ADV_MUSIC_INFO_SETTING_H__
+
+
+#include "le_rcsp_adv_module.h"
+
+#if RCSP_ADV_MUSIC_INFO_ENABLE
+
+char *get_music_title(void);
+u8 get_music_title_len(void);
+char *get_music_artist(void);
+u8 get_music_artist_len(void);
+char *get_music_album(void);
+u8 get_music_album_len(void);
+char *get_music_number(void);
+u8 get_music_number_len(void);
+char *get_music_total(void);
+u8 get_music_total_len(void);
+char *get_music_genre(void);
+u8 get_music_genre_len(void);
+u16 get_music_total_time(void);
+u32 get_music_curr_time(void);
+u8 get_music_player_state(void);
+void music_info_cmd_handle(u8 *p, u16 len);
+void stop_get_music_timer(u8 en);
+extern void music_player_time_timer_deal(u8 en);
+u8 get_player_time_en(void);
+void set_player_time_en(u8 en);
+void rcsp_adv_music_info_deal(u8 type, u32 time, u8 *info, u16 len);
+#endif
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_scene_noise_reduction.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_scene_noise_reduction.h
new file mode 100644
index 0000000..ae84086
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_scene_noise_reduction.h
@@ -0,0 +1,27 @@
+#ifndef __ADV_SCENE_NOISE_REDUCTION_H__
+#define __ADV_SCENE_NOISE_REDUCTION_H__
+
+#include "system/includes.h"
+
+typedef enum {
+ RCSP_SCENE_NOISE_REDUCTION_TYPE_INTELLIGENT = 0x00,
+ RCSP_SCENE_NOISE_REDUCTION_TYPE_MILD = 0x01,
+ RCSP_SCENE_NOISE_REDUCTION_TYPE_BALANCE = 0x02,
+ RCSP_SCENE_NOISE_REDUCTION_TYPE_DEEPNESS = 0x03,
+} RCSP_SCENE_NOISE_REDUCTION_TYPE;
+
+/**
+ * @brief 获取场景降噪类型
+ *
+ * @result RCSP_SCENE_NOISE_REDUCTION_TYPE
+ */
+RCSP_SCENE_NOISE_REDUCTION_TYPE get_scene_noise_reduction_type();
+
+/**
+ * @brief 设置场景降噪类型
+ */
+void set_scene_noise_reduction_type(RCSP_SCENE_NOISE_REDUCTION_TYPE type);
+
+
+
+#endif // __ADV_SCENE_NOISE_REDUCTION_H__
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_setting_common.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_setting_common.h
new file mode 100644
index 0000000..17cd313
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_setting_common.h
@@ -0,0 +1,31 @@
+#ifndef __ADV_SETTING_COMMON_H__
+#define __ADV_SETTING_COMMON_H__
+
+#include "typedef.h"
+#include "event.h"
+
+#if RCSP_ADV_EN
+struct t_s_info {
+ u8 edr_name[32];
+ u8 key_setting[12];
+ u8 key_extra_setting[4];
+ u8 led_status[6];
+ u8 mic_mode;
+ u8 work_mode;
+ u8 eq_mode_info[11];
+};
+extern struct t_s_info _s_info;
+
+void deal_time_stamp_setting(u32 time_stamp, u8 write_vm, u8 tws_sync);
+void deal_bt_name_setting(u8 *bt_name_setting, u8 write_vm, u8 tws_sync);
+void deal_key_setting(u8 *key_setting_info, u8 write_vm, u8 tws_sync);
+void deal_led_setting(u8 *led_setting_info, u8 write_vm, u8 tws_sync);
+void deal_mic_setting(u8 mic_setting_info, u8 write_vm, u8 tws_sync);
+void deal_work_setting(u8 work_setting_info, u8 write_vm, u8 tws_sync, u8 poweron);
+
+void adv_setting_init(void);
+void update_adv_setting(u16 type);
+void update_info_from_adv_vm_info(void);
+void modify_bt_name_and_reset(u32 msec);
+#endif
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_time_stamp_setting.c b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_time_stamp_setting.c
new file mode 100644
index 0000000..ea62253
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_time_stamp_setting.c
@@ -0,0 +1,87 @@
+#include "app_config.h"
+#include "syscfg_id.h"
+#include "user_cfg_id.h"
+#include "rcsp_adv_bluetooth.h"
+#include "JL_rcsp_protocol.h"
+#include "le_rcsp_adv_module.h"
+
+#include "adv_time_stamp_setting.h"
+#include "adv_setting_common.h"
+#include "rcsp_adv_tws_sync.h"
+#include "rcsp_adv_opt.h"
+
+#if (RCSP_ADV_EN)
+extern int get_bt_tws_connect_status();
+static u32 adv_time_stamp = 0;
+u32 get_adv_time_stamp(void)
+{
+ return adv_time_stamp;
+}
+
+void set_adv_time_stamp(u32 time_stamp)
+{
+ adv_time_stamp = time_stamp;
+}
+
+void sync_setting_by_time_stamp(void)
+{
+ tws_api_send_data_to_sibling((u8 *)&adv_time_stamp, sizeof(adv_time_stamp), TWS_FUNC_ID_TIME_STAMP_SYNC);
+}
+
+void deal_sibling_time_stamp_setting_switch(void *data, u16 len)
+{
+ u32 time_stamp = *((u32 *)data);
+ if (adv_time_stamp > time_stamp) {
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_ADV_SETTING_SYNC, NULL, 0);
+ }
+}
+
+void deal_adv_setting_gain_time_stamp(void)
+{
+#if TCFG_USER_TWS_ENABLE
+ extern u8 adv_info_device_request(u8 * buf, u16 len);
+ static u8 tws_pair = 0;
+ u8 buf = 2;
+ u8 ret = 0;
+ if (get_bt_tws_connect_status()) {
+ tws_pair = 1;
+ } else {
+ if (tws_pair) {
+ tws_pair = 0;
+ ret = adv_info_device_request(&buf, sizeof(buf));
+ }
+ }
+#endif
+}
+
+// 1、写入VM
+static void update_time_stamp_vm_value(u32 time_stamp)
+{
+ syscfg_write(CFG_RCSP_ADV_TIME_STAMP, (u8 *)&time_stamp, 4);
+}
+// 2、同步对端
+static void adv_time_stamp_sync(u32 time_stamp)
+{
+#if TCFG_USER_TWS_ENABLE
+ if (get_bt_tws_connect_status()) {
+ update_adv_setting(BIT(ATTR_TYPE_TIME_STAMP));
+ }
+#endif
+}
+
+void deal_time_stamp_setting(u32 time_stamp, u8 write_vm, u8 tws_sync)
+{
+ if (!time_stamp) {
+ time_stamp = get_adv_time_stamp();
+ } else {
+ set_adv_time_stamp(time_stamp);
+ }
+ if (write_vm) {
+ update_time_stamp_vm_value(time_stamp);
+ }
+ if (tws_sync) {
+ adv_time_stamp_sync(time_stamp);
+ }
+}
+
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_time_stamp_setting.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_time_stamp_setting.h
new file mode 100644
index 0000000..9a04ba2
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_time_stamp_setting.h
@@ -0,0 +1,10 @@
+#ifndef __ADV_TIME_STAMP_SETTING_H__
+#define __ADV_TIME_STAMP_SETTING_H__
+
+void set_adv_time_stamp(u32 time_stamp);
+u32 get_adv_time_stamp(void);
+void deal_sibling_time_stamp_setting_switch(void *data, u16 len);
+extern void sync_setting_by_time_stamp(void);
+void deal_adv_setting_gain_time_stamp(void);
+
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_voice_enhancement_mode.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_voice_enhancement_mode.h
new file mode 100644
index 0000000..27e20bc
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_voice_enhancement_mode.h
@@ -0,0 +1,18 @@
+#ifndef __ADV_VOICE_ENHANCEMENT_MODE_H__
+#define __ADV_VOICE_ENHANCEMENT_MODE_H__
+
+#include "system/includes.h"
+
+/**
+ * @brief 获取人声增强模式开关
+ *
+ * @result bool
+ */
+bool get_voice_enhancement_mode_switch();
+
+/**
+ * @brief 设置人声增强模式开关
+ */
+void set_voice_enhancement_mode_switch(bool mode_switch);
+
+#endif // __ADV_VOICE_ENHANCEMENT_MODE_H__
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_wind_noise_detection.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_wind_noise_detection.h
new file mode 100644
index 0000000..29aca5f
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_wind_noise_detection.h
@@ -0,0 +1,18 @@
+#ifndef __ADV_WIND_NOISE_DETECTION_H__
+#define __ADV_WIND_NOISE_DETECTION_H__
+
+#include "system/includes.h"
+
+/**
+ * @brief 获取风噪检测开关
+ *
+ * @result bool
+ */
+bool get_wind_noise_detection_switch();
+
+/**
+ * @brief 设置风噪检测开关
+ */
+void set_wind_noise_detection_switch(bool detection_switch);
+
+#endif // __ADV_WIND_NOISE_DETECTION_H__
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_work_setting.c b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_work_setting.c
new file mode 100644
index 0000000..eee300c
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_work_setting.c
@@ -0,0 +1,104 @@
+#include "app_config.h"
+#include "syscfg_id.h"
+#include "user_cfg_id.h"
+#include "le_rcsp_adv_module.h"
+
+#include "adv_work_setting.h"
+#include "adv_setting_common.h"
+#include "rcsp_adv_tws_sync.h"
+#include "rcsp_adv_opt.h"
+#include "os/os_api.h"
+#include "btstack/avctp_user.h"
+
+#if (RCSP_ADV_EN)
+#if RCSP_ADV_WORK_SET_ENABLE
+
+extern int get_bt_tws_connect_status();
+extern void bt_set_low_latency_mode(int enable);
+void set_work_setting(u8 work_setting_info)
+{
+ _s_info.work_mode = work_setting_info;
+}
+
+u8 get_work_setting(void)
+{
+ return _s_info.work_mode;
+}
+
+static void adv_work_setting_vm_value(u8 work_setting_info)
+{
+ /* syscfg_write(CFG_RCSP_ADV_WORK_SETTING, &work_setting_info, 1); */
+}
+
+static void adv_work_setting_sync(u8 work_setting_info)
+{
+#if TCFG_USER_TWS_ENABLE
+ if (get_bt_tws_connect_status()) {
+ update_adv_setting(BIT(ATTR_TYPE_WORK_MODE));
+ }
+#endif
+}
+
+static void __rcsp_work_set_call(void)
+{
+ //r_f_printf("__rcsp_work_set_call\n");
+ if (1 == _s_info.work_mode) {
+ bt_set_low_latency_mode(0);
+ } else if (2 == _s_info.work_mode) {
+ bt_set_low_latency_mode(1);
+ }
+}
+
+static void rcsp_work_set_deal(void)
+{
+ int err;
+ int msg[3];
+ msg[0] = (int) __rcsp_work_set_call;
+ msg[1] = 1;
+ msg[2] = 0;
+
+ err = os_taskq_post_type("app_core", Q_CALLBACK, 3, msg);
+ //r_printf("err %x\n",err);
+
+
+}
+
+static void update_work_setting_state(void)
+{
+ //r_f_printf("set deal\n");
+ rcsp_work_set_deal();
+}
+
+void deal_work_setting(u8 work_setting_info, u8 write_vm, u8 tws_sync, u8 poweron)
+{
+ if (poweron) {
+ __rcsp_work_set_call();
+ } else {
+ if (0 == work_setting_info) {
+ work_setting_info = get_work_setting();
+ } else {
+ set_work_setting(work_setting_info);
+ }
+ if (write_vm) {
+ adv_work_setting_vm_value(work_setting_info);
+ }
+ if (tws_sync) {
+ adv_work_setting_sync(work_setting_info);
+ }
+ update_work_setting_state();
+ }
+}
+
+
+int ble_vendor_is_slow_state(void)
+{
+ if ((BT_STATUS_PLAYING_MUSIC == get_bt_connect_status()) && (2 == _s_info.work_mode)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+#endif
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_work_setting.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_work_setting.h
new file mode 100644
index 0000000..3054d8c
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_app_setting/adv_work_setting.h
@@ -0,0 +1,13 @@
+#ifndef __ADV_WORK_SETTING_H__
+#define __ADV_WORK_SETTING_H__
+
+
+#include "le_rcsp_adv_module.h"
+
+#if RCSP_ADV_WORK_SET_ENABLE
+
+void set_work_setting(u8 work_setting_info);
+u8 get_work_setting(void);
+
+#endif
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_bluetooth.c b/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_bluetooth.c
new file mode 100644
index 0000000..869ddad
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_bluetooth.c
@@ -0,0 +1,2194 @@
+#include
+#include
+#include
+#include "string.h"
+#include "attr.h"
+#include "JL_rcsp_api.h"
+#include "JL_rcsp_protocol.h"
+#include "JL_rcsp_packet.h"
+#include "spp_user.h"
+#include "btstack/avctp_user.h"
+#include "system/timer.h"
+#include "app_core.h"
+#include "user_cfg.h"
+#include "asm/pwm_led.h"
+#include "ui_manage.h"
+#include "key_event_deal.h"
+#include "syscfg_id.h"
+#include "classic/tws_api.h"
+#include "event.h"
+#include "bt_tws.h"
+#include "custom_cfg.h"
+#include "app_config.h"
+
+#include "rcsp_adv_user_update.h"
+#include "le_rcsp_adv_module.h"
+#include "rcsp_adv_bluetooth.h"
+#include "adv_setting_common.h"
+#include "adv_eq_setting.h"
+#include "adv_music_info_setting.h"
+#include "adv_high_low_vol.h"
+#include "adv_work_setting.h"
+#include "rcsp_adv_customer_user.h"
+#include "vm.h"
+
+#include "tone_player.h"
+#include "audio_config.h"
+
+#include "adv_anc_voice.h"
+#include "adv_adaptive_noise_reduction.h"
+#include "adv_anc_voice_key.h"
+//#include "audio_anc.h"
+#include "adv_ai_no_pick.h"
+#include "adv_scene_noise_reduction.h"
+#include "adv_wind_noise_detection.h"
+#include "adv_voice_enhancement_mode.h"
+
+
+#if (RCSP_ADV_EN)
+#define JL_RCSP_LOW_VERSION 0x01
+#define JL_RCSP_HIGH_VERSION 0x01
+
+/* #define RCSP_DEBUG_EN */
+#ifdef RCSP_DEBUG_EN
+#define rcsp_putchar(x) putchar(x)
+#define rcsp_printf printf
+#define rcsp_printf_buf(x,len) put_buf(x,len)
+#else
+#define rcsp_putchar(...)
+#define rcsp_printf(...)
+#define rcsp_printf_buf(...)
+#endif
+
+struct JL_AI_VAR jl_ai_var = {
+ .rcsp_run_flag = 0,
+};
+
+#define __this (&jl_ai_var)
+
+#define RCSP_USE_BLE 0
+#define RCSP_USE_SPP 1
+#define RCSP_CHANNEL_SEL RCSP_USE_SPP
+
+#define COMMON_FUNCTION 0xFF
+#define BT_FUNCTION 0x0
+
+
+#pragma pack(1)
+
+struct _SYS_info {
+ u8 bat_lev;
+ u8 sys_vol;
+ u8 max_vol;
+ u8 reserve;
+};
+
+struct _EDR_info {
+ u8 addr_buf[6];
+ u8 profile;
+ u8 state;
+};
+
+struct _DEV_info {
+ u8 status;
+ u32 usb_handle;
+ u32 sd0_handle;
+ u32 sd1_handle;
+ u32 flash_handle;
+};
+
+
+struct _MUSIC_STATUS_info {
+ u8 status;
+ u32 cur_time;
+ u32 total_time;
+ u8 cur_dev;
+};
+
+struct _dev_version {
+ u16 _sw_ver2: 4; //software l version
+ u16 _sw_ver1: 4; //software m version
+ u16 _sw_ver0: 4; //software h version
+ u16 _hw_ver: 4; //hardware version
+};
+
+
+#pragma pack()
+
+/* #pragma pack(1) */
+/* #pragma pack() */
+
+#define RES_MD5_FILE SDFILE_RES_ROOT_PATH"md5.bin"
+
+#if 1//RCSP_UPDATE_EN
+static volatile u8 JL_bt_chl = 0;
+u8 JL_get_cur_bt_channel_sel(void);
+void JL_ble_disconnect(void);
+void rcsp_reboot_dev(void);
+u8 rcsp_get_update_flag(void);
+#endif
+
+u8 get_rcsp_support_new_reconn_flag(void)
+{
+ return __this->new_reconn_flag;
+}
+
+u8 get_rcsp_connect_status(void)
+{
+#if 1//RCSP_UPDATE_EN
+ if (RCSP_BLE == JL_get_cur_bt_channel_sel()) {
+ if (__this->JL_ble_status == BLE_ST_CONNECT || __this->JL_ble_status == BLE_ST_NOTIFY_IDICATE) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } else {
+ return __this->JL_spp_status;
+ }
+#else
+ return 0;
+#endif
+}
+
+extern void rcsp_update_data_api_unregister(void);
+static u16 common_function_info(u32 mask, u8 *buf, u16 len);
+static u16 bt_function_info(u32 mask, u8 *buf, u16 len);
+#if RCSP_ADV_FIND_DEVICE_ENABLE
+static void earphone_mute_handler(u8 *other_opt, u32 msec);
+static void find_device_timeout_handle(u32 sec);
+void find_decice_tws_connect_handle(u8 flag, u8 *param);
+#endif
+
+void JL_rcsp_event_to_user(u32 type, u8 event, u8 *msg, u8 size)
+{
+ struct sys_event e;
+ e.type = SYS_DEVICE_EVENT;
+
+ if (size > sizeof(e.u.rcsp.args)) {
+ rcsp_printf("rcsp event size overflow:%x %x\n", size, sizeof(e.u.rcsp.args));
+ }
+
+ e.arg = (void *)type;
+ e.u.rcsp.event = event;
+
+ if (size) {
+ memcpy(e.u.rcsp.args, msg, size);
+ }
+
+ e.u.rcsp.size = size;
+
+ sys_event_notify(&e);
+}
+///Jim
+static u32 JL_auto_update_sys_info(u8 fun_type, u32 mask)
+{
+ u8 buf[512];
+ u8 offset = 0;
+ u32 ret = 0;
+
+ rcsp_printf("JL_auto_update_sys_info\n");
+
+ buf[0] = fun_type;
+
+ u8 *p = buf + 1;
+ u16 size = sizeof(buf) - 1;
+
+ switch (fun_type) {
+ case COMMON_FUNCTION:
+ rcsp_printf("COMMON_FUNCTION\n");
+ offset = common_function_info(mask, p, size);
+ break;
+ case BT_FUNCTION:
+ rcsp_printf("BT_FUNCTION\n");
+ offset = bt_function_info(mask, p, size);
+ break;
+ default:
+ break;
+ }
+
+ rcsp_printf_buf(buf, offset + 1);
+
+ ret = JL_CMD_send(JL_OPCODE_SYS_INFO_AUTO_UPDATE, buf, offset + 1, JL_NOT_NEED_RESPOND);
+ return ret;
+}
+
+void JL_bt_phone_state_update(void)
+{
+ JL_auto_update_sys_info(COMMON_FUNCTION, BIT(COMMON_INFO_ATTR_PHONE_SCO_STATE_INFO));
+}
+
+int JL_rcsp_event_handler(struct rcsp_event *rcsp)
+{
+ int ret = 0;
+
+ switch (rcsp->event) {
+ case MSG_JL_ADV_SETTING_SYNC:
+ update_adv_setting((u16) - 1);
+ break;
+ case MSG_JL_ADV_SETTING_UPDATE:
+ update_info_from_adv_vm_info();
+ break;
+ case MSG_JL_UPDATE_EQ:
+ JL_auto_update_sys_info(COMMON_FUNCTION, BIT(COMMON_INFO_ATTR_EQ));
+ break;
+ case MSG_JL_UPDATE_SEQ:
+ printf("MSG_JL_UPDATE_SEQ\n");
+ extern void adv_seq_vaule_sync(void);
+ adv_seq_vaule_sync();
+ break;
+ case MSG_JL_SWITCH_DEVICE:
+ if (RCSP_BLE == JL_get_cur_bt_channel_sel() && RCSP_SPP == rcsp->args[0]) {
+ JL_ble_disconnect();
+ }
+ break;
+#if RCSP_ADV_MUSIC_INFO_ENABLE
+ case MSG_JL_UPDATE_PLAYER_TIME:
+ if (JL_rcsp_get_auth_flag()) {
+ JL_auto_update_sys_info(BT_FUNCTION, 0x100);
+ }
+ break;
+ case MSG_JL_UPDATE_PLAYER_STATE:
+ if (JL_rcsp_get_auth_flag()) {
+ JL_auto_update_sys_info(BT_FUNCTION, 0x80);
+ }
+ break;
+ case MSG_JL_UPDATE_MUSIC_INFO:
+ if (JL_rcsp_get_auth_flag()) {
+ /* printf("rcsp type %x\n",rcsp->args[0]); */
+ JL_auto_update_sys_info(BT_FUNCTION, BIT(rcsp->args[0] - 1));
+ }
+ break;
+ case MSG_JL_UPDATE_MUSIC_PLAYER_TIME_TEMER:
+ if (JL_rcsp_get_auth_flag()) {
+ music_player_time_timer_deal(rcsp->args[0]);
+ }
+ break;
+#endif
+#if (RCSP_ADV_ANC_VOICE)
+ case MSG_JL_UPDATE_ANC_VOICE:
+ printf("MSG_JL_UPDATE_ANC_VOICE\n");
+#if RCSP_ADV_ADAPTIVE_NOISE_REDUCTION
+ JL_auto_update_sys_info(COMMON_FUNCTION, (BIT(COMMON_INFO_ATTR_ANC_VOICE) | BIT(COMMON_INFO_ATTR_ADAPTIVE_NOISE_REDUCTION)));
+#else
+ JL_auto_update_sys_info(COMMON_FUNCTION, BIT(COMMON_INFO_ATTR_ANC_VOICE));
+#endif
+ break;
+ case MSG_JL_UPDATE_ANC_VOICE_MAX_SYNC:
+ printf("MSG_JL_UPDATE_ANC_VOICE_MAX_SYNC\n");
+#if TCFG_USER_TWS_ENABLE
+ extern void anc_voice_max_val_swap_sync(void);
+ anc_voice_max_val_swap_sync();
+#endif
+ break;
+#endif
+#if RCSP_ADV_ADAPTIVE_NOISE_REDUCTION
+ case MSG_JL_UPDATE_ADAPTIVE_NOISE_REDUCTION:
+ printf("MSG_JL_UPDATE_ADAPTIVE_NOISE_REDUCTION\n");
+ JL_auto_update_sys_info(COMMON_FUNCTION, BIT(COMMON_INFO_ATTR_ADAPTIVE_NOISE_REDUCTION));
+ break;
+#endif
+#if RCSP_ADV_AI_NO_PICK
+ case MSG_JL_UPDATE_AI_NO_PICK:
+ printf("MSG_JL_UPDATE_AI_NO_PICK\n");
+ JL_auto_update_sys_info(COMMON_FUNCTION, BIT(COMMON_INFO_ATTR_AI_NO_PICK));
+ break;
+#endif
+#if RCSP_ADV_SCENE_NOISE_REDUCTION
+ case MSG_JL_UPDATE_SCENE_NOISE_REDUCTION:
+ printf("MSG_JL_UPDATE_SCENE_NOISE_REDUCTION\n");
+ JL_auto_update_sys_info(COMMON_FUNCTION, BIT(COMMON_INFO_ATTR_SCENE_NOISE_REDUCTION));
+ break;
+#endif
+#if RCSP_ADV_WIND_NOISE_DETECTION
+ case MSG_JL_UPDATE_WIND_NOISE_DETECTION:
+ printf("MSG_JL_UPDATE_WIND_NOISE_DETECTION\n");
+ JL_auto_update_sys_info(COMMON_FUNCTION, BIT(COMMON_INFO_ATTR_WIND_NOISE_DETECTION));
+ break;
+#endif
+#if RCSP_ADV_VOICE_ENHANCEMENT_MODE
+ case MSG_JL_UPDATE_VOICE_ENHANCEMENT_MODE:
+ printf("MSG_JL_UPDATE_VOICE_ENHANCEMENT_MODE\n");
+ JL_auto_update_sys_info(COMMON_FUNCTION, BIT(COMMON_INFO_ATTR_VOICE_ENHANCEMENT_MODE));
+ break;
+#endif
+ case MSG_JL_UPDAET_ADV_STATE_INFO:
+ if (get_rcsp_connect_status()) {
+ JL_rcsp_set_auth_flag(rcsp->args[0]);
+ bt_ble_adv_ioctl(BT_ADV_SET_NOTIFY_EN, rcsp->args[1], 1);
+ }
+ break;
+
+
+ case MSG_JL_REBOOT_DEV:
+ rcsp_reboot_dev();
+ break;
+
+#if RCSP_ADV_FIND_DEVICE_ENABLE
+ case MSG_JL_FIND_DEVICE_RESUME:
+ printf("MSG_JL_FIND_DEVICE_RESUME\n");
+#if TCFG_USER_TWS_ENABLE
+ find_decice_tws_connect_handle(2, rcsp->args);
+#endif
+ earphone_mute_handler(rcsp->args, 300);
+ break;
+ case MSG_JL_FIND_DEVICE_STOP:
+ printf("MSG_JL_FIND_DEVICE_STOP\n");
+ u16 sec = *((u16 *)rcsp->args);
+#if TCFG_USER_TWS_ENABLE
+ find_decice_tws_connect_handle(1, rcsp->args);
+#endif
+ find_device_timeout_handle(sec);
+ break;
+#endif
+ case MSG_JL_TWS_NEED_UPDATE:
+ printf("MSG_JL_TWS_NEED_UPDATE\n");
+ syscfg_write(VM_UPDATE_FLAG, rcsp->args, 1);
+ break;
+
+ default:
+#if RCSP_UPDATE_EN
+ JL_rcsp_msg_deal(NULL, rcsp->event, rcsp->args);
+#endif
+ break;
+ }
+
+ return ret;
+}
+
+u8 adv_info_notify(u8 *buf, u16 len)
+{
+ return JL_CMD_send(JL_OPCODE_ADV_DEVICE_NOTIFY, buf, len, JL_NOT_NEED_RESPOND);
+}
+
+u8 adv_info_device_request(u8 *buf, u16 len)
+{
+ printf("JL_OPCODE_ADV_DEVICE_REQUEST\n");
+ return JL_CMD_send(JL_OPCODE_ADV_DEVICE_REQUEST, buf, len, JL_NEED_RESPOND);
+}
+
+struct t_s_info _s_info = {
+ .key_setting = {
+ 0x01, 0x01, 0x05, \
+ 0x02, 0x01, 0x05, \
+ 0x01, 0x02, 0x08, \
+ 0x02, 0x02, 0x08
+ },
+ .key_extra_setting = {
+ 0
+ },
+ .led_status = {
+ 0x01, 0x06, \
+ 0x02, 0x05, \
+ 0x03, 0x04
+ },
+ .mic_mode = 1,
+ .work_mode = 1,
+ .eq_mode_info = {0x00},
+};
+
+extern const char *bt_get_local_name();
+extern void bt_adv_get_bat(u8 *buf);
+static u32 JL_opcode_get_adv_info(void *priv, u8 OpCode, u8 OpCode_SN, u8 *data, u16 len)
+{
+ u8 buf[256];
+ u8 offset = 0;
+
+ u32 ret = 0;
+ u32 mask = READ_BIG_U32(data);
+ rcsp_printf("FEATURE MASK : %x\n", mask);
+ /* #define ATTR_TYPE_BAT_VALUE (0) */
+ /* #define ATTR_TYPE_EDR_NAME (1) */
+ //get version
+ if (mask & BIT(ATTR_TYPE_BAT_VALUE)) {
+ rcsp_printf("ATTR_TYPE_BAT_VALUE\n");
+ u8 bat[3];
+ bt_adv_get_bat(bat);
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_BAT_VALUE, bat, 3);
+ }
+#if RCSP_ADV_NAME_SET_ENABLE
+ if (mask & BIT(ATTR_TYPE_EDR_NAME)) {
+ rcsp_printf("ATTR_TYPE_EDR_NAME\n");
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_EDR_NAME, (void *)_s_info.edr_name, strlen(_s_info.edr_name));
+ }
+#endif
+
+#if RCSP_ADV_KEY_SET_ENABLE
+ if (mask & BIT(ATTR_TYPE_KEY_SETTING)) {
+ rcsp_printf("ATTR_TYPE_KEY_SETTING\n");
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_KEY_SETTING, (void *)_s_info.key_setting, sizeof(_s_info.key_setting));
+ }
+
+ if (mask & BIT(ATTR_TYPE_ANC_VOICE_KEY)) {
+ rcsp_printf("ATTR_TYPE_ANC_VOICE_KEY\n");
+ u8 anc_voice_key_mode[4] = {0};
+ get_anc_voice_key_mode(anc_voice_key_mode);
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_ANC_VOICE_KEY, anc_voice_key_mode, sizeof(anc_voice_key_mode));
+ }
+#endif
+
+#if RCSP_ADV_LED_SET_ENABLE
+ if (mask & BIT(ATTR_TYPE_LED_SETTING)) {
+ rcsp_printf("ATTR_TYPE_LED_SETTING\n");
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_LED_SETTING, (void *)_s_info.led_status, sizeof(_s_info.led_status));
+ }
+#endif
+
+
+#if RCSP_ADV_MIC_SET_ENABLE
+ if (mask & BIT(ATTR_TYPE_MIC_SETTING)) {
+ rcsp_printf("ATTR_TYPE_MIC_SETTING\n");
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_MIC_SETTING, (void *)&_s_info.mic_mode, 1);
+ }
+#endif
+
+#if RCSP_ADV_WORK_SET_ENABLE
+ if (mask & BIT(ATTR_TYPE_WORK_MODE)) {
+ rcsp_printf("ATTR_TYPE_WORK_MODE\n");
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_WORK_MODE, (void *)&_s_info.work_mode, 1);
+ }
+#endif
+
+#if RCSP_ADV_PRODUCT_MSG_ENABLE
+ if (mask & BIT(ATTR_TYPE_PRODUCT_MESSAGE)) {
+ rcsp_printf("ATTR_TYPE_PRODUCT_MESSAGE\n");
+ u16 vid = get_vid_pid_ver_from_cfg_file(GET_VID_FROM_EX_CFG);
+ u16 pid = get_vid_pid_ver_from_cfg_file(GET_PID_FROM_EX_CFG);
+ u8 tversion[6];
+ tversion[0] = 0x05;
+ tversion[1] = 0xD6;
+ tversion[3] = vid & 0xFF;
+ tversion[2] = vid >> 8;
+ tversion[5] = pid & 0xFF;
+ tversion[4] = pid >> 8;
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_PRODUCT_MESSAGE, (void *)tversion, 6);
+
+ }
+#endif
+ rcsp_printf_buf(buf, offset);
+
+ ret = JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, buf, offset);
+
+ return ret;
+}
+
+// ----------------------------reboot----------------------//
+/* extern void tws_sync_modify_bt_name_reset(void); */
+/* void modify_bt_name_and_reset(u32 msec) */
+/* { */
+/* sys_timer_add(NULL, cpu_reset, msec); */
+/* } */
+// ----------------------------end----------------------//
+
+static u8 adv_setting_result = 0;
+static u8 adv_set_deal_one_attr(u8 *buf, u8 size, u8 offset)
+{
+ u8 rlen = buf[offset];
+ if ((offset + rlen + 1) > (size - offset)) {
+ rcsp_printf("\n\ndeal attr end!\n\n");
+ return rlen;
+ }
+ u8 type = buf[offset + 1];
+ u8 *pbuf = &buf[offset + 2];
+ u8 dlen = rlen - 1;
+ u8 bt_name[32];
+ adv_setting_result = 0;
+
+ switch (type) {
+#if RCSP_ADV_NAME_SET_ENABLE
+ case ATTR_TYPE_EDR_NAME:
+ if (dlen > 20) {
+ adv_setting_result = -1;
+ } else {
+ memcpy(bt_name, pbuf, dlen);
+ bt_name[dlen] = '\0';
+ memcpy(_s_info.edr_name, bt_name, 32);
+ rcsp_printf("ATTR_TYPE_EDR_NAME %s\n", bt_name);
+ rcsp_printf_buf(pbuf, dlen);
+ deal_bt_name_setting(NULL, 1, 1);
+ }
+ break;
+#endif
+#if RCSP_ADV_KEY_SET_ENABLE
+ case ATTR_TYPE_KEY_SETTING:
+ rcsp_printf("ATTR_TYPE_KEY_SETTING\n");
+ rcsp_printf_buf(pbuf, dlen);
+ while (dlen >= 3) {
+ if (pbuf[0] == 0x01) {
+ if (pbuf[1] == 0x01) {
+ _s_info.key_setting[2] = pbuf[2];
+ } else if (pbuf[1] == 0x02) {
+ _s_info.key_setting[8] = pbuf[2];
+ }
+ } else if (pbuf[0] == 0x02) {
+ if (pbuf[1] == 0x01) {
+ _s_info.key_setting[5] = pbuf[2];
+ } else if (pbuf[1] == 0x02) {
+ _s_info.key_setting[11] = pbuf[2];
+ }
+ }
+ dlen -= 3;
+ pbuf += 3;
+ }
+ deal_key_setting(NULL, 1, 1);
+ break;
+ case ATTR_TYPE_ANC_VOICE_KEY:
+ rcsp_printf("ATTR_TYPE_ANC_VOICE_KEY\n");
+ rcsp_printf_buf(pbuf, dlen);
+ deal_anc_voice_key_setting(pbuf, 1, 1);
+ break;
+#endif
+#if RCSP_ADV_LED_SET_ENABLE
+ case ATTR_TYPE_LED_SETTING:
+ rcsp_printf("ATTR_TYPE_LED_SETTING\n");
+ rcsp_printf_buf(pbuf, dlen);
+ while (dlen >= 2) {
+ if (pbuf[0] == 0 || pbuf[0] > 3) {
+ break;
+ } else {
+ _s_info.led_status[2 * (pbuf[0] - 1) + 1] = pbuf[1];
+ }
+ dlen -= 2;
+ pbuf += 2;
+ }
+ deal_led_setting(NULL, 1, 1);
+ break;
+#endif
+#if RCSP_ADV_MIC_SET_ENABLE
+ case ATTR_TYPE_MIC_SETTING:
+ rcsp_printf("ATTR_TYPE_MIC_SETTING\n");
+ rcsp_printf_buf(pbuf, dlen);
+ if (2 == _s_info.work_mode) {
+ adv_setting_result = -1;
+ } else {
+ deal_mic_setting(pbuf[0], 1, 1);
+ }
+ break;
+#endif
+#if RCSP_ADV_WORK_SET_ENABLE
+ case ATTR_TYPE_WORK_MODE:
+ rcsp_printf("ATTR_TYPE_WORK_MODE\n");
+ rcsp_printf_buf(pbuf, dlen);
+ deal_work_setting(pbuf[0], 1, 1, 0);
+ break;
+#endif
+ case ATTR_TYPE_TIME_STAMP:
+ rcsp_printf("ATTR_TYPE_TIME_STAMP\n");
+ rcsp_printf_buf(pbuf, dlen);
+ //adv_time_stamp = (((pbuf[0] << 8) | pbuf[1]) << 8 | pbuf[2]) << 8 | pbuf[3];
+ syscfg_read(CFG_BT_NAME, _s_info.edr_name, sizeof(_s_info.edr_name));
+ //deal_time_stamp_setting();
+ //set_adv_time_stamp((((pbuf[0] << 8) | pbuf[1]) << 8 | pbuf[2]) << 8 | pbuf[3]);
+ deal_time_stamp_setting((((pbuf[0] << 8) | pbuf[1]) << 8 | pbuf[2]) << 8 | pbuf[3], 1, 1);
+ break;
+ default:
+ rcsp_printf("ATTR UNKNOW\n");
+ rcsp_printf_buf(pbuf, dlen);
+ break;
+ }
+
+ return rlen + 1;
+}
+
+static u32 JL_opcode_set_adv_info(void *priv, u8 OpCode, u8 OpCode_SN, u8 *data, u16 len)
+{
+ rcsp_printf("JL_opcode_set_adv_info:\n");
+ rcsp_printf_buf(data, len);
+ u8 offset = 0;
+ while (offset < len) {
+ offset += adv_set_deal_one_attr(data, len, offset);
+ }
+ u8 ret = 0;
+ if (adv_setting_result) {
+ /* JL_CMD_response_send(OpCode, JL_PRO_STATUS_FAIL, OpCode_SN, &ret, 1); */
+ ret = 1;
+ JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, &ret, 1);
+ } else {
+ JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, &ret, 1);
+ }
+ return 0;
+}
+
+extern const int support_dual_bank_update_en;
+static u32 JL_opcode_get_target_info(void *priv, u8 OpCode, u8 OpCode_SN, u8 *data, u16 len)
+{
+ u8 buf[256];
+ u8 offset = 0;
+
+ __this->phone_platform = data[4];
+ if (__this->phone_platform == ANDROID) {
+ rcsp_printf("phone_platform == ANDROID\n");
+ } else if (__this->phone_platform == APPLE_IOS) {
+ rcsp_printf("phone_platform == APPLE_IOS\n");
+ } else {
+ rcsp_printf("phone_platform ERR\n");
+ }
+
+ u32 mask = READ_BIG_U32(data);
+ rcsp_printf("FEATURE MASK : %x\n", mask);
+
+ u32 ret = 0;
+
+ //get version
+ if (mask & BIT(ATTR_TYPE_PROTOCOL_VERSION)) {
+ rcsp_printf("ATTR_TYPE_PROTOCOL_VERSION\n");
+ u8 ver = get_rcsp_version();
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_PROTOCOL_VERSION, &ver, 1);
+ }
+
+ //get powerup sys info
+ if (mask & BIT(ATTR_TYPE_SYS_INFO)) {
+ rcsp_printf("ATTR_TYPE_SYS_INFO\n");
+
+ struct _SYS_info sys_info;
+ //extern u16 get_battery_level(void);
+ sys_info.bat_lev = 0; //get_battery_level() / 10;
+ sys_info.sys_vol = 0; //sound.vol.sys_vol_l;
+ sys_info.max_vol = 0; //MAX_SYS_VOL_L;
+
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_SYS_INFO, \
+ (u8 *)&sys_info, sizeof(sys_info));
+ }
+
+ //get EDR info
+ if (mask & BIT(ATTR_TYPE_EDR_ADDR)) {
+ rcsp_printf("ATTR_TYPE_EDR_ADDR\n");
+ struct _EDR_info edr_info;
+ /* extern void hook_get_mac_addr(u8 * btaddr); */
+ /* hook_get_mac_addr(edr_info.addr_buf); */
+
+ extern const u8 *bt_get_mac_addr();
+ u8 taddr_buf[6];
+ memcpy(taddr_buf, bt_get_mac_addr(), 6);
+ edr_info.addr_buf[0] = taddr_buf[5];
+ edr_info.addr_buf[1] = taddr_buf[4];
+ edr_info.addr_buf[2] = taddr_buf[3];
+ edr_info.addr_buf[3] = taddr_buf[2];
+ edr_info.addr_buf[4] = taddr_buf[1];
+ edr_info.addr_buf[5] = taddr_buf[0];
+ /* extern u8 get_edr_suppor_profile(void); */
+ /* edr_info.profile = get_edr_suppor_profile(); */
+ edr_info.profile = 0x0E;
+#if (RCSP_CHANNEL_SEL == RCSP_USE_BLE)
+ edr_info.profile &= ~BIT(7);
+#else
+ edr_info.profile |= BIT(7);
+#endif
+ extern u8 get_bt_connect_status(void);
+ if (get_bt_connect_status() == BT_STATUS_WAITINT_CONN) {
+ edr_info.state = 0;
+ } else {
+ edr_info.state = 1;
+ }
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_EDR_ADDR, (u8 *)&edr_info, sizeof(struct _EDR_info));
+ }
+
+ //get platform info
+ if (mask & BIT(ATTR_TYPE_PLATFORM)) {
+ rcsp_printf("ATTR_TYPE_PLATFORM\n");
+
+ u8 lic_val = 0;
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_PLATFORM, &lic_val, 1);
+ }
+
+ //get function info
+ if (mask & BIT(ATTR_TYPE_FUNCTION_INFO)) {
+ rcsp_printf("ATTR_TYPE_FUNCTION_INFO\n");
+
+ u8 tmp_buf[6] = {0};
+ u8 function_info = 0x16;
+ u32 func_mask = 1;
+ func_mask = app_htonl(func_mask);
+ memcpy(tmp_buf, &func_mask, 4);
+ memcpy(tmp_buf + 4, &function_info, 1);
+
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_FUNCTION_INFO, tmp_buf, sizeof(tmp_buf));
+ }
+
+ //get dev info
+ if (mask & BIT(ATTR_TYPE_DEV_VERSION)) {
+ rcsp_printf("ATTR_TYPE_DEV_VERSION\n");
+ u16 ver = 0;
+ ver = get_vid_pid_ver_from_cfg_file(GET_VER_FROM_EX_CFG);
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_DEV_VERSION, &ver, 2);
+ }
+
+ if (mask & BIT(ATTR_TYPE_UBOOT_VERSION)) {
+ rcsp_printf("ATTR_TYPE_UBOOT_VERSION\n");
+ u8 *uboot_ver_flag = (u8 *)(0x1C000 - 0x8);
+ u8 uboot_version[2] = {uboot_ver_flag[0], uboot_ver_flag[1]};
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_UBOOT_VERSION, uboot_version, sizeof(uboot_version));
+ }
+
+ if (mask & BIT(ATTR_TYPE_DOUBLE_PARITION)) {
+ rcsp_printf("ATTR_TYPE_DOUBLE_PARITION:%x\n", support_dual_bank_update_en);
+ u8 double_partition_value;
+ u8 ota_loader_need_download_flag;
+ u8 update_channel_sel = 0;
+ if (support_dual_bank_update_en) {
+ double_partition_value = 0x1;
+ ota_loader_need_download_flag = 0x00;
+ } else {
+ double_partition_value = 0x0;
+ ota_loader_need_download_flag = 0x01;
+ //update_channel_sel |= (BIT(7) | 0x0); //最低位为升级通道选择、0选择BLE升级、1选择SPP升级
+ }
+ update_channel_sel = 0x1;
+ u8 update_param[3] = {
+ double_partition_value,
+ ota_loader_need_download_flag,
+ update_channel_sel,
+ };
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_DOUBLE_PARITION, (u8 *)update_param, sizeof(update_param));
+ }
+
+ if (mask & BIT(ATTR_TYPE_UPDATE_STATUS)) {
+ rcsp_printf("ATTR_TYPE_UPDATE_STATUS\n");
+ u8 update_status_value[2] = {0};
+ /* syscfg_read(VM_UPDATE_FLAG, &update_status_value[1], 1); //读出vm强制升级标志 */
+ /* g_printf("get taget info:%d\n", update_status_value[1]); */
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_UPDATE_STATUS, (u8 *)&update_status_value, sizeof(update_status_value));
+ }
+
+ if (mask & BIT(ATTR_TYPE_DEV_VID_PID)) {
+ rcsp_printf("ATTR_TYPE_DEV_VID_PID\n");
+ u16 pvid[2] = {0};
+ pvid[0] = get_vid_pid_ver_from_cfg_file(GET_VID_FROM_EX_CFG);
+ pvid[1] = get_vid_pid_ver_from_cfg_file(GET_PID_FROM_EX_CFG);
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_DEV_VID_PID, (u8 *)pvid, sizeof(pvid));
+ }
+
+ if (mask & BIT(ATTR_TYPE_SDK_TYPE)) {
+ rcsp_printf("ATTR_TYPE_SDK_TYPE\n");
+ u8 sdk_type = RCSP_SDK_TYPE;
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_SDK_TYPE, &sdk_type, 1);
+ }
+
+#if VER_INFO_EXT_COUNT
+ // get AuthKey
+ if (mask & BIT(ATTR_TYPE_DEV_AUTHKEY)) {
+ rcsp_printf("ATTR_TYPE_DEV_AUTHKEY\n");
+ u8 authkey_len = 0;
+ u8 *local_authkey_data = NULL;
+ get_authkey_procode_from_cfg_file(&local_authkey_data, &authkey_len, GET_AUTH_KEY_FROM_EX_CFG);
+ if (local_authkey_data && authkey_len) {
+ put_buf(local_authkey_data, authkey_len);
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_DEV_AUTHKEY, local_authkey_data, authkey_len);
+ }
+ }
+
+ if (mask & BIT(ATTR_TYPE_DEV_PROCODE)) {
+ rcsp_printf("ATTR_TYPE_DEV_PROCODE\n");
+ u8 procode_len = 0;
+ u8 *local_procode_data = NULL;
+ get_authkey_procode_from_cfg_file(&local_procode_data, &procode_len, GET_PRO_CODE_FROM_EX_CFG);
+ if (local_procode_data && procode_len) {
+ put_buf(local_procode_data, procode_len);
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_DEV_PROCODE, local_procode_data, procode_len);
+ }
+ }
+#endif
+
+ if (mask & BIT(ATTR_TYPE_DEV_MAX_MTU)) {
+ rcsp_printf(" ATTR_TYPE_DEV_MTU_SIZE\n");
+ /* u16 JL_packet_get_rx_mtu(void); */
+ /* u16 JL_packet_get_rx_max_mtu(void); */
+ /* u16 JL_packet_get_tx_max_mtu(void); */
+ u16 rx_max_mtu = JL_packet_get_rx_max_mtu();
+ u16 tx_max_mtu = JL_packet_get_tx_max_mtu();
+ u8 t_buf[4];
+ t_buf[0] = (tx_max_mtu >> 8) & 0xFF;
+ t_buf[1] = tx_max_mtu & 0xFF;
+ t_buf[2] = (rx_max_mtu >> 8) & 0xFF;
+ t_buf[3] = rx_max_mtu & 0xFF;
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_DEV_MAX_MTU, t_buf, 4);
+ }
+
+ if (mask & BIT(ATTR_TEYP_BLE_ADDR)) {
+ rcsp_printf(" ATTR_TEYP_BLE_ADDR\n");
+ extern void lib_make_ble_address(u8 * ble_address, u8 * edr_address);
+ extern const u8 *bt_get_mac_addr();
+ u8 taddr_buf[7];
+ taddr_buf[0] = 0;
+ lib_make_ble_address(taddr_buf + 1, (void *)bt_get_mac_addr());
+ for (u8 i = 0; i < (6 / 2); i++) {
+ taddr_buf[i + 1] ^= taddr_buf[7 - i - 1];
+ taddr_buf[7 - i - 1] ^= taddr_buf[i + 1];
+ taddr_buf[i + 1] ^= taddr_buf[7 - i - 1];
+ }
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TEYP_BLE_ADDR, taddr_buf, sizeof(taddr_buf));
+ }
+
+ if (mask & BIT(ATTR_TYPE_MD5_GAME_SUPPORT)) {
+ rcsp_printf("ATTR_TYPE_MD5_GAME_SUPPORT\n");
+ u8 ext_function_flag[2] = {0};
+ u8 md5_support = UPDATE_MD5_ENABLE;
+
+ /* if(get_work_setting() == 2) */
+ {
+ md5_support |= BIT(1);
+ }
+
+#if (RCSP_ADV_FIND_DEVICE_ENABLE)
+ md5_support |= BIT(2);
+#endif
+#if (RCSP_ADV_ANC_VOICE)
+ md5_support |= BIT(6);
+#endif
+ ext_function_flag[0] = md5_support;
+ u8 ext_function_flag_byte1 = 0;
+#if (RCSP_ADV_ASSISTED_HEARING)
+ ext_function_flag_byte1 |= BIT(0);
+#endif
+#if RCSP_ADV_ADAPTIVE_NOISE_REDUCTION
+ ext_function_flag_byte1 |= BIT(1);
+#endif
+#if RCSP_ADV_AI_NO_PICK
+ ext_function_flag_byte1 |= BIT(3);
+#endif
+#if RCSP_ADV_SCENE_NOISE_REDUCTION
+ ext_function_flag_byte1 |= BIT(4);
+#endif
+#if RCSP_ADV_WIND_NOISE_DETECTION
+ ext_function_flag_byte1 |= BIT(5);
+#endif
+#if RCSP_ADV_VOICE_ENHANCEMENT_MODE
+ ext_function_flag_byte1 |= BIT(6);
+#endif
+ ext_function_flag[1] = ext_function_flag_byte1;
+ offset += add_one_attr(buf, sizeof(buf), offset, ATTR_TYPE_MD5_GAME_SUPPORT, ext_function_flag, 2);
+ }
+ rcsp_printf_buf(buf, offset);
+
+ ret = JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, buf, offset);
+
+ return ret;
+}
+
+static u16 common_function_info(u32 mask, u8 *buf, u16 len)
+{
+ u16 offset = 0;
+
+#if RCSP_ADV_EQ_SET_ENABLE
+ if (mask & BIT(COMMON_INFO_ATTR_EQ)) {
+ u8 eq_info[11] = {0};
+ u8 eq_info_size = app_get_eq_info(eq_info);
+ offset += add_one_attr(buf, len, offset, COMMON_INFO_ATTR_EQ, eq_info, eq_info_size);
+ }
+ if (mask & BIT(COMMON_INFO_ATTR_PRE_FETCH_ALL_EQ_INFO)) {
+ u8 eq_pre_fetch_info[1 + 20 + (1 + 10) * 10] = {0}; // num + freq + all_gain_of_eq [max]
+ u8 eq_per_fetch_size = app_get_eq_all_info(eq_pre_fetch_info);
+ offset += add_one_attr(buf, len, offset, COMMON_INFO_ATTR_PRE_FETCH_ALL_EQ_INFO, eq_pre_fetch_info, eq_per_fetch_size);
+ }
+#endif
+ if (mask & BIT(COMMON_INFO_ATTR_PHONE_SCO_STATE_INFO)) {
+ u8 phone_state = 0;
+ if (BT_CALL_HANGUP != get_call_status()) {
+ phone_state = 1;
+ }
+ offset += add_one_attr(buf, len, offset, COMMON_INFO_ATTR_PHONE_SCO_STATE_INFO, &phone_state, sizeof(phone_state));
+ }
+
+#if RCSP_ADV_HIGH_LOW_SET
+ if (mask & BIT(COMMON_INFO_ATTR_HIGH_LOW_SET)) {
+ struct _HIGL_LOW_VOL gain_param = {0};
+ get_high_low_vol_info(&gain_param);
+ gain_param.low_vol = gain_param.low_vol < 0 ? 0 : gain_param.low_vol;
+ gain_param.low_vol = gain_param.low_vol > 24 ? 24 : gain_param.low_vol;
+ gain_param.high_vol = gain_param.high_vol < 0 ? 0 : gain_param.high_vol;
+ gain_param.high_vol = gain_param.high_vol > 24 ? 24 : gain_param.high_vol;
+ gain_param.low_vol -= 12;
+ gain_param.high_vol -= 12;
+ gain_param.low_vol = READ_BIG_U32((u8 *)&gain_param.low_vol);
+ gain_param.high_vol = READ_BIG_U32((u8 *)&gain_param.high_vol);
+ offset += add_one_attr(buf, len, offset, COMMON_INFO_ATTR_HIGH_LOW_SET, (u8 *)(&gain_param), sizeof(gain_param));
+ }
+#endif
+
+#if (RCSP_ADV_ANC_VOICE)
+ if (mask & BIT(COMMON_INFO_ATTR_ANC_VOICE)) {
+ u8 anc_info[9] = {0};
+ anc_voice_info_get(anc_info, sizeof(anc_info));
+ offset += add_one_attr(buf, len, offset, COMMON_INFO_ATTR_ANC_VOICE, anc_info, sizeof(anc_info));
+ }
+
+ if (mask & BIT(COMMON_INFO_ATTR_FETCH_ALL_ANC_VOICE)) {
+ u8 anc_fetch_all_info[28] = {0};
+ anc_voice_info_fetch_all_get(anc_fetch_all_info, sizeof(anc_fetch_all_info));
+ offset += add_one_attr(buf, len, offset, COMMON_INFO_ATTR_FETCH_ALL_ANC_VOICE, anc_fetch_all_info, sizeof(anc_fetch_all_info));
+ }
+#endif
+
+// 添加辅听的get函数
+#if (RCSP_ADV_ASSISTED_HEARING)
+ if (mask & BIT(COMMON_INFO_ATTR_ASSISTED_HEARING)) {
+ u8 dha_fitting_data[3 + 2 + 2 * DHA_FITTING_CHANNEL_MAX] = {0};
+ get_dha_fitting_info(dha_fitting_data);
+ offset += add_one_attr(buf, len, offset, COMMON_INFO_ATTR_ASSISTED_HEARING, dha_fitting_data, sizeof(dha_fitting_data));
+ }
+#endif
+
+#if RCSP_ADV_ADAPTIVE_NOISE_REDUCTION
+ if (mask & BIT(COMMON_INFO_ATTR_ADAPTIVE_NOISE_REDUCTION)) {
+ u8 adaptive_noise_reduction_info[3] = {0};
+ // 获取自适应降噪开关
+ if (get_adaptive_noise_reduction_switch() != 0) {
+ // 开启
+ adaptive_noise_reduction_info[0] = 0x01;
+ }
+ // 获取设置自适应降噪状态
+ if (get_adaptive_noise_reduction_reset_status() != 0) {
+ // 设置中
+ adaptive_noise_reduction_info[1] = 0x01;
+ }
+ // 获取设置自适应降噪结果
+ if (get_adaptive_noise_reduction_reset_result() != 0) {
+ // 设置中
+ adaptive_noise_reduction_info[2] = 0x01;
+ }
+ offset += add_one_attr(buf, len, offset, COMMON_INFO_ATTR_ADAPTIVE_NOISE_REDUCTION, adaptive_noise_reduction_info, sizeof(adaptive_noise_reduction_info));
+ }
+#endif
+
+#if RCSP_ADV_AI_NO_PICK
+ if (mask & BIT(COMMON_INFO_ATTR_AI_NO_PICK)) {
+ u8 ai_no_pick_info[5] = {0};
+ ai_no_pick_info[1] = 0xff; // 获取智能免摘全部数据
+ ai_no_pick_info[2] = get_ai_no_pick_switch() ? 0x01 : 0x00;
+ ai_no_pick_info[3] = get_ai_no_pick_sensitivity();
+ ai_no_pick_info[4] = get_ai_no_pick_auto_close_time();
+ offset += add_one_attr(buf, len, offset, COMMON_INFO_ATTR_AI_NO_PICK, ai_no_pick_info, sizeof(ai_no_pick_info));
+ }
+#endif
+
+#if RCSP_ADV_SCENE_NOISE_REDUCTION
+ if (mask & BIT(COMMON_INFO_ATTR_SCENE_NOISE_REDUCTION)) {
+ u8 scene_noise_reduction_info[2] = {0};
+ scene_noise_reduction_info[1] = get_scene_noise_reduction_type();
+ offset += add_one_attr(buf, len, offset, COMMON_INFO_ATTR_SCENE_NOISE_REDUCTION, scene_noise_reduction_info, sizeof(scene_noise_reduction_info));
+ }
+#endif
+
+#if RCSP_ADV_WIND_NOISE_DETECTION
+ if (mask & BIT(COMMON_INFO_ATTR_WIND_NOISE_DETECTION)) {
+ u8 wind_noise_detection_info[2] = {0};
+ wind_noise_detection_info[1] = get_wind_noise_detection_switch() ? 0x01 : 0x00;
+ offset += add_one_attr(buf, len, offset, COMMON_INFO_ATTR_WIND_NOISE_DETECTION, wind_noise_detection_info, sizeof(wind_noise_detection_info));
+ }
+#endif
+
+#if RCSP_ADV_VOICE_ENHANCEMENT_MODE
+ if (mask & BIT(COMMON_INFO_ATTR_VOICE_ENHANCEMENT_MODE)) {
+ u8 voice_enhancement_mode_info[2] = {0};
+ voice_enhancement_mode_info[1] = get_voice_enhancement_mode_switch() ? 0x01 : 0x00;
+ offset += add_one_attr(buf, len, offset, COMMON_INFO_ATTR_VOICE_ENHANCEMENT_MODE, voice_enhancement_mode_info, sizeof(voice_enhancement_mode_info));
+ }
+#endif
+
+ return offset;
+}
+
+static u16 bt_function_info(u32 mask, u8 *buf, u16 len)
+{
+ u16 offset = 0;
+ u16 music_sec = 0;
+ u32 curr_music_sec = 0;
+ u8 music_state = 0;
+ u8 player_time[4];
+
+
+
+#if RCSP_ADV_MUSIC_INFO_ENABLE
+ if (mask & BIT(BT_INFO_ATTR_MUSIC_TITLE)) {
+ offset += add_one_attr(buf, len, offset, BT_INFO_ATTR_MUSIC_TITLE, get_music_title(), get_music_title_len());
+ }
+ if (mask & BIT(BT_INFO_ATTR_MUSIC_ARTIST)) {
+ offset += add_one_attr(buf, len, offset, BT_INFO_ATTR_MUSIC_ARTIST, get_music_artist(), get_music_artist_len());
+ }
+ if (mask & BIT(BT_INFO_ATTR_MUSIC_ALBUM)) {
+ offset += add_one_attr(buf, len, offset, BT_INFO_ATTR_MUSIC_ALBUM, get_music_album(), get_music_album_len());
+ }
+ if (mask & BIT(BT_INFO_ATTR_MUSIC_NUMBER)) {
+ offset += add_one_attr(buf, len, offset, BT_INFO_ATTR_MUSIC_NUMBER, get_music_number(), get_music_number_len());
+ }
+ if (mask & BIT(BT_INFO_ATTR_MUSIC_TOTAL)) {
+ offset += add_one_attr(buf, len, offset, BT_INFO_ATTR_MUSIC_TOTAL, get_music_total(), get_music_total_len());
+ }
+ if (mask & BIT(BT_INFO_ATTR_MUSIC_GENRE)) {
+ offset += add_one_attr(buf, len, offset, BT_INFO_ATTR_MUSIC_GENRE, get_music_genre(), get_music_genre_len());
+ }
+ if (mask & BIT(BT_INFO_ATTR_MUSIC_TIME)) {
+ music_sec = get_music_total_time();
+ player_time[0] = music_sec >> 8;
+ player_time[1] = music_sec;
+ offset += add_one_attr(buf, len, offset, BT_INFO_ATTR_MUSIC_TIME, player_time, 2);
+ }
+ if (mask & BIT(BT_INFO_ATTR_MUSIC_STATE)) {
+ //printf("\n music state\n");
+ music_state = get_music_player_state();
+ offset += add_one_attr(buf, len, offset, BT_INFO_ATTR_MUSIC_STATE, &music_state, 1);
+ }
+ if (mask & BIT(BT_INFO_ATTR_MUSIC_CURR_TIME)) {
+ //printf("\nmusic curr time\n");
+ curr_music_sec = get_music_curr_time();
+ player_time[0] = curr_music_sec >> 24;
+ player_time[1] = curr_music_sec >> 16;
+ player_time[2] = curr_music_sec >> 8;
+ player_time[3] = curr_music_sec;
+ offset += add_one_attr(buf, len, offset, BT_INFO_ATTR_MUSIC_CURR_TIME, player_time, 4);
+ }
+#endif
+ return offset;
+}
+
+static u32 JL_opcode_get_sys_info(void *priv, u8 OpCode, u8 OpCode_SN, u8 *data, u16 len)
+{
+ u8 buf[512];
+ u32 ret = 0;
+ u8 offset = 0;
+ u8 fun_type = data[0];
+ u32 mask = READ_BIG_U32(data + 1);
+ rcsp_printf("SYS MASK : %x\n", mask);
+
+ /* printf_buf(data, len); */
+
+ buf[0] = fun_type;
+
+ u8 *p = buf + 1;
+ u16 size = sizeof(buf) - 1;
+
+ switch (fun_type) {
+ case COMMON_FUNCTION:
+ rcsp_printf("COMMON_FUNCTION\n");
+ offset = common_function_info(mask, p, size);
+ break;
+
+ case BT_FUNCTION:
+ rcsp_printf("BT_FUNCTION\n");
+ offset = bt_function_info(mask, p, size);
+ break;
+ default:
+ break;
+
+ }
+
+ rcsp_printf_buf(buf, offset + 1);
+
+ ret = JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, buf, offset + 1);
+
+ return ret;
+}
+
+static void set_common_function_info(u8 OpCode, u8 OpCode_SN, u8 *data, u16 len)
+{
+ u8 offset = 0;
+ //analysis sys info
+ while (offset < len) {
+ u8 len_tmp = data[offset];
+ u8 type = data[offset + 1];
+ rcsp_printf("common info:\n");
+ rcsp_printf_buf(&data[offset], len_tmp + 1);
+
+ switch (type) {
+#if RCSP_ADV_EQ_SET_ENABLE
+ case COMMON_INFO_ATTR_EQ :
+ r_printf("COMMON_INFO_ATTR_EQ\n");
+
+ deal_eq_setting(&data[offset + 2], 1, 1);
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_UPDATE_EQ, NULL, 0);
+
+ break;
+#endif
+
+#if RCSP_ADV_HIGH_LOW_SET
+ case COMMON_INFO_ATTR_HIGH_LOW_SET:
+ r_printf("COMMON_INFO_ATTR_HIGH_LOW_SET");
+ struct _HIGL_LOW_VOL gain_param = {0};
+ gain_param.low_vol = READ_BIG_U32(data + 2) + 12;
+ gain_param.high_vol = READ_BIG_U32(data + 2 + 4) + 12;
+ gain_param.low_vol = gain_param.low_vol > 24 ? 24 : gain_param.low_vol;
+ gain_param.low_vol = gain_param.low_vol < 0 ? 0 : gain_param.low_vol;
+ gain_param.high_vol = gain_param.high_vol > 24 ? 24 : gain_param.high_vol;
+ gain_param.high_vol = gain_param.high_vol < 0 ? 0 : gain_param.high_vol;
+ deal_high_low_vol((u8 *)&gain_param, 1, 1);
+ break;
+#endif
+
+#if RCSP_ADV_ANC_VOICE
+ case COMMON_INFO_ATTR_ANC_VOICE:
+ printf("SET COMMON_INFO_ATTR_ANC_VOICE\n");
+ anc_voice_info_set(data + 2, len_tmp - 1);
+ break;
+#endif
+
+// 添加辅听的set函数
+#if (RCSP_ADV_ASSISTED_HEARING)
+ case COMMON_INFO_ATTR_ASSISTED_HEARING:
+ printf("SET COMMON_INFO_ATTR_ASSISTED_HEARING");
+ deal_hearing_aid_setting(OpCode, OpCode_SN, data + 2, 0, 1);
+ break;
+#endif
+
+#if RCSP_ADV_ADAPTIVE_NOISE_REDUCTION
+ case COMMON_INFO_ATTR_ADAPTIVE_NOISE_REDUCTION:
+ printf("SET COMMON_INFO_ATTR_ADAPTIVE_NOISE_REDUCTION\n");
+ u8 *switch_adaptive_noise_reduction = data + 2;
+ if (*switch_adaptive_noise_reduction) {
+ u8 *is_adaptive_noise_reduction_check = data + 3;
+ if (*is_adaptive_noise_reduction_check) {
+ // 重新检测
+ set_adaptive_noise_reduction_reset();
+ } else {
+ // 开启自适应
+ set_adaptive_noise_reduction_on();
+ }
+ } else {
+ // 关闭自适应
+ set_adaptive_noise_reduction_off();
+ }
+ break;
+#endif
+
+#if RCSP_ADV_AI_NO_PICK
+ case COMMON_INFO_ATTR_AI_NO_PICK:
+ printf("SET COMMON_INFO_ATTR_AI_NO_PICK\n");
+ u8 *ai_no_pick_func = data + 3;
+ u8 *ai_no_pick_val = data + 4;
+ if ((*ai_no_pick_func) == 0x00) { // 开关智能免摘
+ set_ai_no_pick_switch((*ai_no_pick_val) ? true : false);
+ } else if ((*ai_no_pick_func) == 0x01) { // 设置智能免摘敏感度
+ set_ai_no_pick_sensitivity((*ai_no_pick_val));
+ } else if ((*ai_no_pick_func) == 0x02) { // 设置智能免摘启动后自动关闭时间
+ set_ai_no_pick_auto_close_time((*ai_no_pick_val));
+ }
+ break;
+#endif
+
+#if RCSP_ADV_SCENE_NOISE_REDUCTION
+ case COMMON_INFO_ATTR_SCENE_NOISE_REDUCTION:
+ printf("SET COMMON_INFO_ATTR_SCENE_NOISE_REDUCTION\n");
+ u8 *scene_noise_reduction_type = data + 3;
+ set_scene_noise_reduction_type((RCSP_SCENE_NOISE_REDUCTION_TYPE)(*scene_noise_reduction_type));
+ break;
+#endif
+
+#if RCSP_ADV_WIND_NOISE_DETECTION
+ case COMMON_INFO_ATTR_WIND_NOISE_DETECTION:
+ printf("SET COMMON_INFO_ATTR_WIND_NOISE_DETECTION\n");
+ u8 *wind_noise_detection_switch = data + 3;
+ set_wind_noise_detection_switch((*wind_noise_detection_switch) ? true : false);
+ break;
+#endif
+
+#if RCSP_ADV_VOICE_ENHANCEMENT_MODE
+ case COMMON_INFO_ATTR_VOICE_ENHANCEMENT_MODE:
+ printf("SET COMMON_INFO_ATTR_VOICE_ENHANCEMENT_MODE\n");
+ u8 *voice_enhancement_mode_switch = data + 3;
+ set_voice_enhancement_mode_switch((*voice_enhancement_mode_switch) ? true : false);
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ offset += len_tmp + 1;
+ }
+}
+
+#if (RCSP_ADV_ASSISTED_HEARING)
+static u8 _hearing_aid_operating_flag = 0;
+void set_hearing_aid_operating_flag()
+{
+ _hearing_aid_operating_flag = 1;
+}
+#endif
+
+static u32 JL_opcode_set_sys_info(void *priv, u8 OpCode, u8 OpCode_SN, u8 *data, u16 len)
+{
+ u32 ret = 0;
+ u8 fun_type = data[0];
+ u8 *p = data + 1;
+
+ len = len - 1;
+
+ switch (fun_type) {
+ case COMMON_FUNCTION:
+ rcsp_printf("COMMON_FUNCTION\n");
+ set_common_function_info(OpCode, OpCode_SN, p, len);
+ break;
+ default:
+ break;
+ }
+
+#if (RCSP_ADV_ASSISTED_HEARING)
+ if (_hearing_aid_operating_flag) {
+ _hearing_aid_operating_flag = 0;
+ return JL_ERR_NONE;
+ }
+#endif
+
+ if (ret) {
+ ret = JL_CMD_response_send(OpCode, JL_PRO_STATUS_FAIL, OpCode_SN, NULL, 0);
+ } else {
+ ret = JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, NULL, 0);
+ }
+
+ return ret;
+}
+
+
+u32 bt_function_cmd_set(u8 *p, u16 len)
+{
+#if RCSP_ADV_MUSIC_INFO_ENABLE
+ music_info_cmd_handle(p, len);
+#endif
+ return true;
+}
+
+void wait_reboot_dev(void *priv)
+{
+ cpu_reset();
+}
+
+void rcsp_reboot_dev(void)
+{
+ user_send_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
+
+ extern void ble_module_enable(u8 en);
+#if RCSP_ADV_NAME_SET_ENABLE
+ extern void adv_edr_name_change_now(void);
+ adv_edr_name_change_now();
+#endif
+ ble_module_enable(0);
+#if TCFG_USER_TWS_ENABLE
+ if (get_bt_tws_connect_status()) {
+ //tws_sync_modify_bt_name_reset();
+ modify_bt_name_and_reset(500);
+ } else {
+ if (sys_timer_add(NULL, wait_reboot_dev, 500) == 0) {
+ cpu_reset();
+ }
+ }
+#else
+ if (sys_timer_add(NULL, wait_reboot_dev, 500) == 0) {
+ cpu_reset();
+ }
+#endif
+
+}
+
+static void function_cmd_handle(void *priv, u8 OpCode, u8 OpCode_SN, u8 *data, u16 len)
+{
+ u32 ret = 0;
+ u8 fun_type = data[0];
+ u8 *p = data + 1;
+
+ len = len - 1;
+
+ switch (fun_type) {
+ case BT_FUNCTION:
+ rcsp_printf("BT_FUNCTION\n");
+ ret = bt_function_cmd_set(p, len);
+ break;
+ default:
+ break;
+ }
+
+ if (ret == true) {
+ JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, NULL, 0);
+ } else {
+ JL_CMD_response_send(OpCode, JL_PRO_STATUS_FAIL, OpCode_SN, NULL, 0);
+ }
+}
+
+#if RCSP_ADV_FIND_DEVICE_ENABLE
+
+static u8 find_device_key_flag = 0;
+static u16 find_device_timer = 0;
+
+u8 find_device_key_flag_get(void)
+{
+ return find_device_key_flag;
+}
+
+void send_find_device_stop(void)
+{
+ if (0 == JL_rcsp_get_auth_flag()) {
+ return;
+ }
+ // 查找手机 关闭铃声 超时时间(不限制)
+ u8 send_buf[4] = {0x00, 0x00, 0x00, 0x00};
+ JL_CMD_send(JL_OPCODE_SYS_FIND_DEVICE, send_buf, sizeof(send_buf), JL_NOT_NEED_RESPOND);
+}
+
+void find_device_reset(void)
+{
+ find_device_key_flag = 0;
+ if (find_device_timer) {
+ sys_timeout_del(find_device_timer);
+ find_device_timer = 0;
+ }
+}
+
+static void find_device_stop(void *priv)
+{
+ find_device_reset();
+ send_find_device_stop();
+
+ // 0 - way, 1 - player, 2 - find_device_key_flag
+ u8 other_opt[3] = {0};
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
+ other_opt[2] = 2;
+ extern void find_device_sync(u8 * param, u32 msec);
+ find_device_sync(other_opt, 300);
+ return;
+ }
+#endif
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_FIND_DEVICE_RESUME, other_opt, sizeof(other_opt));
+}
+
+static void find_device_timeout_handle(u32 sec)
+{
+ find_device_key_flag = 1;
+ if (sec && (0 == find_device_timer)) {
+ find_device_timer = sys_timeout_add(NULL, find_device_stop, sec * 1000);
+ }
+}
+
+// channel : L - 左耳,R - 右耳
+// state : 0 - 静音,1 - 有声音
+static void earphone_mute(u8 channel, u8 state)
+{
+ if ('L' == channel) {
+ channel = 1;
+ } else if ('R' == channel) {
+ channel = 2;
+ } else {
+ return;
+ }
+ extern void audio_dac_ch_mute(struct audio_dac_hdl * dac, u8 ch, u8 mute);
+ audio_dac_ch_mute(NULL, channel, !state);
+}
+
+static void earphone_mute_timer_func(void *param)
+{
+ u8 way = ((u8 *)param)[0];
+ u8 player = ((u8 *)param)[1];
+ earphone_mute('L', 1);
+ earphone_mute('R', 1);
+
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
+
+ switch (way) {
+ case 1:
+ if ('R' == tws_api_get_local_channel()) {
+ earphone_mute('R', 0);
+ }
+ break;
+ case 2:
+ if ('L' == tws_api_get_local_channel()) {
+ earphone_mute('L', 0);
+ }
+ break;
+ }
+ }
+#endif
+ switch (player) {
+ case 0:
+ // app端播放/还原
+ tone_play_stop();
+ break;
+ case 1:
+ // 设备端播放
+ tone_play(TONE_NORMAL, 1);
+ earphone_mute_handler(param, 300);
+ break;
+ }
+}
+
+static void earphone_mute_handler(u8 *other_opt, u32 msec)
+{
+ static u16 earphone_mute_timer = 0;
+ static u8 tmp_param[3] = {0};
+ memcpy(tmp_param, other_opt, sizeof(other_opt));
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED && TWS_ROLE_SLAVE == tws_api_get_role() && 2 == tmp_param[2]) {
+ find_device_reset();
+ earphone_mute_timer_func(tmp_param);
+ }
+#endif
+ if (earphone_mute_timer) {
+ sys_timeout_del(earphone_mute_timer);
+ earphone_mute_timer = 0;
+ }
+
+ if (find_device_key_flag) {
+ earphone_mute_timer = sys_timeout_add(tmp_param, earphone_mute_timer_func, msec);
+ }
+}
+
+#if TCFG_USER_TWS_ENABLE
+void find_decice_tws_connect_handle(u8 flag, u8 *param)
+{
+ static u8 sync_param[4] = {0};
+ u8 other_opt[3] = {0};
+ switch (flag) {
+ case 0:
+ if (find_device_key_flag) {
+ memcpy(other_opt, sync_param, 2);
+ extern void find_devic_stop_timer(u8 * param, u32 msec);
+ find_devic_stop_timer(other_opt, 300);
+ memcpy(other_opt, sync_param + 2, 2);
+ extern void find_device_sync(u8 * param, u32 msec);
+ find_device_sync(other_opt, 300);
+ }
+ break;
+ case 1:
+ memcpy(sync_param, param, 2);
+ break;
+ case 2:
+ memcpy(sync_param + 2, param, 2);
+ break;
+ }
+}
+#endif
+
+static void find_device_handle(u8 OpCode, u8 OpCode_SN, u8 *data, u16 len)
+{
+ if (BT_CALL_HANGUP != get_call_status()) {
+ return;
+ }
+ u8 type = data[0];
+ u8 opt = data[1];
+ // 0 - way, 1 - player, 2 - find_device_key_flag
+ u8 other_opt[3] = {0};
+
+ if (opt) {
+ u16 timeout = READ_BIG_U16(data + 2);
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
+ memcpy(other_opt, &timeout, sizeof(timeout));
+ extern void find_devic_stop_timer(u8 * param, u32 msec);
+ find_devic_stop_timer(other_opt, 300);
+ } else
+#endif
+ {
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_FIND_DEVICE_STOP, &timeout, sizeof(timeout));
+ }
+ } else {
+ find_device_stop(NULL);
+ }
+
+ JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, NULL, 0);
+
+ // len为4时没有way和player两种设置
+ if (4 == len) {
+ return;
+ }
+
+ // 铃声播放时才给way和player赋值
+ if (6 == len && opt) {
+ other_opt[0] = data[4]; // way
+ other_opt[1] = data[5]; // player
+ }
+
+ // 300ms超时,发送对端同步执行
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
+ extern void find_device_sync(u8 * param, u32 msec);
+ find_device_sync(other_opt, 300);
+ return;
+ }
+#endif
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_FIND_DEVICE_RESUME, other_opt, sizeof(other_opt));
+}
+
+// 按键触发设备查找手机
+void JL_rcsp_find_device(void)
+{
+ if (0 == get_rcsp_connect_status()) {
+ return;
+ }
+ if (find_device_key_flag) {
+ find_device_stop(NULL);
+ } else {
+ find_device_key_flag = 1;
+ if ((__this->phone_platform == APPLE_IOS) && (0 != get_curr_channel_state())) {
+ // IOS平台
+ user_send_cmd_prepare(USER_CTRL_DISCONNECTION_HCI, 0, NULL);
+ }
+ // 查找手机 播放铃声 超时时间(默认10s)
+ u8 send_buf[4] = {0x00, 0x01, 0x00, 0x0A};
+ JL_CMD_send(JL_OPCODE_SYS_FIND_DEVICE, send_buf, sizeof(send_buf), JL_NOT_NEED_RESPOND);
+ }
+}
+
+#else
+u8 find_device_key_flag_get(void)
+{
+ return 0;
+}
+#endif
+
+//phone send cmd to firmware need respond
+static void JL_rcsp_cmd_resp(void *priv, u8 OpCode, u8 OpCode_SN, u8 *data, u16 len)
+{
+ FILE *fp = NULL;
+ u32 r_len;
+ u8 md5[32] = {0};
+ u8 low_latency_param[6];
+ rcsp_printf("JL_ble_cmd_resp\n");
+ switch (OpCode) {
+ case JL_OPCODE_GET_TARGET_FEATURE:
+ rcsp_printf("JL_OPCODE_GET_TARGET_INFO\n");
+ JL_opcode_get_target_info(priv, OpCode, OpCode_SN, data, len);
+ break;
+ case JL_OPCODE_SWITCH_DEVICE:
+ __this->device_type = data[0];
+ if (len > 1) { //新增一个Byte用于标识是否支持新的回连方式, 新版本APP会发多一个BYTE用于标识是否支持新的回连方式
+ __this->new_reconn_flag = data[1];
+ JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, &__this->new_reconn_flag, 1);
+ } else {
+ JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, NULL, 0);
+ }
+#if RCSP_UPDATE_EN
+ if (get_jl_update_flag()) {
+ if (RCSP_BLE == JL_get_cur_bt_channel_sel()) {
+ rcsp_printf("BLE_ CON START DISCON\n");
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_DEV_DISCONNECT, NULL, 0);
+ } else {
+ rcsp_printf("WAIT_FOR_SPP_DISCON\n");
+ }
+ }
+#endif
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_SWITCH_DEVICE, &data[0], 1);
+
+ break;
+
+ case JL_OPCODE_SYS_INFO_GET:
+ r_printf("JL_OPCODE_SYS_INFO_GET\n");
+ JL_opcode_get_sys_info(priv, OpCode, OpCode_SN, data, len);
+ break;
+
+ case JL_OPCODE_SYS_INFO_SET:
+ r_printf("JL_OPCODE_SYS_INFO_SET\n");
+ JL_opcode_set_sys_info(priv, OpCode, OpCode_SN, data, len);
+ break;
+
+ case JL_OPCODE_SET_ADV:
+ rcsp_printf(" JL_OPCODE_SET_ADV\n");
+ JL_opcode_set_adv_info(priv, OpCode, OpCode_SN, data, len);
+ break;
+ case JL_OPCODE_GET_ADV:
+ rcsp_printf(" JL_OPCODE_GET_ADV\n");
+ JL_opcode_get_adv_info(priv, OpCode, OpCode_SN, data, len);
+ break;
+ case JL_OPCODE_ADV_NOTIFY_SETTING:
+ rcsp_printf(" JL_OPCODE_ADV_NOTIFY_SETTING\n");
+ bt_ble_adv_ioctl(BT_ADV_SET_NOTIFY_EN, *((u8 *)data), 1);
+ JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, NULL, 0);
+ break;
+ case JL_OPCODE_ADV_DEVICE_REQUEST:
+ rcsp_printf("JL_OPCODE_ADV_DEVICE_REQUEST\n");
+ break;
+
+#if RCSP_ADV_FIND_DEVICE_ENABLE
+ case JL_OPCODE_SYS_FIND_DEVICE:
+ rcsp_printf("JL_OPCODE_SYS_FIND_DEVICE\n");
+ find_device_handle(OpCode, OpCode_SN, data, len);
+ break;
+#endif
+
+ case JL_OPCODE_FUNCTION_CMD:
+ function_cmd_handle(priv, OpCode, OpCode_SN, data, len);
+ break;
+
+ case JL_OPCODE_GET_MD5:
+ rcsp_printf("JL_OPCODE_GET_MD5\n");
+ fp = fopen(RES_MD5_FILE, "r");
+ if (!fp) {
+ JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, NULL, 0);
+ break;
+ }
+ r_len = fread(fp, (void *)md5, 32);
+ if (r_len != 32) {
+ JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, NULL, 0);
+ break;
+ }
+
+ printf("get [md5] succ:");
+ put_buf(md5, 32);
+ JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, md5, 32);
+
+ fclose(fp);
+ break;
+
+ case JL_OPCODE_LOW_LATENCY_PARAM:
+ low_latency_param[0] = 0;
+ low_latency_param[1] = 20;
+ low_latency_param[2] = 100 >> 24;
+ low_latency_param[3] = 100 >> 16;
+ low_latency_param[4] = 100 >> 8;
+ low_latency_param[5] = 100;
+ JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, low_latency_param, 6);
+ break;
+
+ case JL_OPCODE_SET_DEVICE_REBOOT:
+ rcsp_printf("JL_OPCODE_SET_DEVICE_REBOOT\n");
+
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_REBOOT_DEV, NULL, 0);
+
+ break;
+
+ case JL_OPCODE_CUSTOMER_USER:
+ rcsp_user_recv_cmd_resp(data, len);
+ JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, NULL, 0);
+ break;
+
+ default:
+#if RCSP_UPDATE_EN
+ if ((OpCode >= JL_OPCODE_GET_DEVICE_UPDATE_FILE_INFO_OFFSET) && \
+ (OpCode <= JL_OPCODE_SET_DEVICE_REBOOT)) {
+ JL_rcsp_update_cmd_resp(priv, OpCode, OpCode_SN, data, len);
+ } else
+#endif
+ {
+ JL_CMD_response_send(OpCode, JL_ERR_NONE, OpCode_SN, data, len);
+ }
+ break;
+ }
+
+// JL_ERR JL_CMD_response_send(u8 OpCode, u8 status, u8 sn, u8 *data, u16 len)
+}
+
+//phone send cmd to firmware not need respond
+static void JL_rcsp_cmd_no_resp(void *priv, u8 OpCode, u8 *data, u16 len)
+{
+ rcsp_printf("JL_ble_cmd_no_resp\n");
+ switch (OpCode) {
+
+ default:
+ break;
+ }
+}
+
+//phone send data to firmware need respond
+static void JL_rcsp_data_resp(void *priv, u8 OpCode_SN, u8 CMD_OpCode, u8 *data, u16 len)
+{
+ rcsp_printf("JL_ble_data_resp\n");
+ switch (CMD_OpCode) {
+ case 0:
+ break;
+
+ default:
+ break;
+ }
+
+}
+//phone send data to firmware not need respond
+static void JL_rcsp_data_no_resp(void *priv, u8 CMD_OpCode, u8 *data, u16 len)
+{
+ rcsp_printf("JL_ble_data_no_resp\n");
+ switch (CMD_OpCode) {
+ case 0:
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+//phone respone firmware cmd
+static void JL_rcsp_cmd_recieve_resp(void *priv, u8 OpCode, u8 status, u8 *data, u16 len)
+{
+ rcsp_printf("rec resp:%x\n", OpCode);
+
+ switch (OpCode) {
+
+ case JL_OPCODE_CUSTOMER_USER:
+ rcsp_user_recv_resp(data, len);
+ break;
+
+ default:
+#if RCSP_UPDATE_EN
+ if ((OpCode >= JL_OPCODE_GET_DEVICE_UPDATE_FILE_INFO_OFFSET) && \
+ (OpCode <= JL_OPCODE_SET_DEVICE_REBOOT)) {
+ JL_rcsp_update_cmd_receive_resp(priv, OpCode, status, data, len);
+ }
+#endif
+ break;
+ }
+}
+//phone respone firmware data
+static void JL_rcsp_data_recieve_resp(void *priv, u8 status, u8 CMD_OpCode, u8 *data, u16 len)
+{
+ rcsp_printf("JL_ble_data_recieve_resp\n");
+ switch (CMD_OpCode) {
+
+ case 0:
+ break;
+
+ default:
+ break;
+ }
+
+}
+//wait resp timout
+static u8 JL_rcsp_wait_resp_timeout(void *priv, u8 OpCode, u8 counter)
+{
+ rcsp_printf("JL_rcsp_wait_resp_timeout\n");
+
+ return 0;
+}
+
+
+///**************************************************************************************///
+///************ rcsp ble **********///
+///**************************************************************************************///
+static void JL_ble_status_callback(void *priv, ble_state_e status)
+{
+ rcsp_printf("JL_ble_status_callback==================== %d\n", status);
+ __this->JL_ble_status = status;
+ switch (status) {
+ case BLE_ST_IDLE:
+#if RCSP_UPDATE_EN
+ if (get_jl_update_flag()) {
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_UPDATE_START, NULL, 0);
+ }
+#endif
+ break;
+ case BLE_ST_ADV:
+ break;
+ case BLE_ST_CONNECT:
+#if (RCSP_ADV_FIND_DEVICE_ENABLE)
+ printf("smartbox_find_device_reset\n");
+ find_device_reset();
+#endif
+ break;
+ case BLE_ST_SEND_DISCONN:
+ break;
+ case BLE_ST_DISCONN:
+#if defined(TCFG_AUDIO_HEARING_AID_ENABLE) && (TCFG_AUDIO_HEARING_AID_ENABLE == 1)
+ /*与APP断连时,需要关闭辅听验配单频声音*/
+ extern void audio_dha_fitting_sync_close(void);
+ audio_dha_fitting_sync_close();
+#endif /*defined(TCFG_AUDIO_HEARING_AID_ENABLE) && (TCFG_AUDIO_HEARING_AID_ENABLE == 1)*/
+#if RCSP_UPDATE_EN
+ if (get_jl_update_flag()) {
+ bt_ble_adv_enable(0);
+ }
+#endif
+ break;
+ case BLE_ST_NOTIFY_IDICATE:
+ break;
+ default:
+ break;
+ }
+}
+
+static bool JL_ble_fw_ready(void *priv)
+{
+ return ((__this->JL_ble_status == BLE_ST_NOTIFY_IDICATE) ? true : false);
+}
+
+static s32 JL_ble_send(void *priv, void *data, u16 len)
+{
+ if ((__this->rcsp_ble != NULL) && (__this->JL_ble_status == BLE_ST_NOTIFY_IDICATE)) {
+ int err = __this->rcsp_ble->send_data(NULL, (u8 *)data, len);
+ /* rcsp_printf("send :%d\n", len); */
+ if (len < 128) {
+ /* rcsp_printf_buf(data, len); */
+ } else {
+ /* rcsp_printf_buf(data, 128); */
+ }
+
+ if (err == 0) {
+ return 0;
+ } else if (err == APP_BLE_BUFF_FULL) {
+ return 1;
+ }
+ } else {
+ rcsp_printf("send err -1 !!\n");
+ }
+
+ return -1;
+}
+
+static const JL_PRO_CB JL_pro_BLE_callback = {
+ .priv = NULL,
+ .fw_ready = JL_ble_fw_ready,
+ .fw_send = JL_ble_send,
+ .CMD_resp = JL_rcsp_cmd_resp,
+ .CMD_no_resp = JL_rcsp_cmd_no_resp,
+ .DATA_resp = JL_rcsp_data_resp,
+ .DATA_no_resp = JL_rcsp_data_no_resp,
+ .CMD_recieve_resp = JL_rcsp_cmd_recieve_resp,
+ .DATA_recieve_resp = JL_rcsp_data_recieve_resp,
+ .wait_resp_timeout = JL_rcsp_wait_resp_timeout,
+};
+
+static void rcsp_ble_callback_set(void (*resume)(void), void (*recieve)(void *, void *, u16), void (*status)(void *, ble_state_e))
+{
+ __this->rcsp_ble->regist_wakeup_send(NULL, resume);
+ __this->rcsp_ble->regist_recieve_cbk(NULL, recieve);
+ __this->rcsp_ble->regist_state_cbk(NULL, status);
+}
+#if 1//RCSP_UPDATE_EN
+u8 JL_get_cur_bt_channel_sel(void)
+{
+ return JL_bt_chl;
+}
+
+void JL_ble_disconnect(void)
+{
+ __this->rcsp_ble->disconnect(NULL);
+}
+
+u8 get_curr_device_type(void)
+{
+ return __this->device_type;
+}
+
+void set_curr_update_type(u8 type)
+{
+ __this->device_type = type;
+}
+
+u8 get_defalut_bt_channel_sel(void)
+{
+ return RCSP_CHANNEL_SEL;
+}
+#endif
+
+///**************************************************************************************///
+///************ rcsp spp **********///
+///**************************************************************************************///
+static void JL_spp_status_callback(u8 status)
+{
+ switch (status) {
+ case 0:
+ __this->JL_spp_status = 0;
+ break;
+ case 1:
+ __this->JL_spp_status = 1;
+#if (JL_EARPHONE_APP_EN && RCSP_ADV_FIND_DEVICE_ENABLE)
+ printf("smartbox_find_device_reset\n");
+ find_device_reset();
+#endif
+ break;
+#if defined(TCFG_AUDIO_HEARING_AID_ENABLE) && (TCFG_AUDIO_HEARING_AID_ENABLE == 1)
+ case 2:
+ /*与APP断连时,需要关闭辅听验配单频声音*/
+ extern int hearing_aid_fitting_start(u8 en);
+ extern u8 set_hearing_aid_fitting_state(u8 state);
+ hearing_aid_fitting_start(0);
+ set_hearing_aid_fitting_state(0);
+ break;
+#endif /*defined(TCFG_AUDIO_HEARING_AID_ENABLE) && (TCFG_AUDIO_HEARING_AID_ENABLE == 1)*/
+ default:
+#if (JL_EARPHONE_APP_EN)
+#if RCSP_ADV_MUSIC_INFO_ENABLE
+ stop_get_music_timer(1);
+#endif
+#if (0 == BT_CONNECTION_VERIFY)
+ JL_rcsp_auth_reset();
+#endif
+#if RCSP_UPDATE_EN
+ if (get_jl_update_flag()) {
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_UPDATE_START, NULL, 0);
+ }
+#endif //rcsp_update_en
+#endif
+ __this->JL_spp_status = 0;
+ break;
+ }
+}
+
+static bool JL_spp_fw_ready(void *priv)
+{
+ return (__this->JL_spp_status ? true : false);
+}
+
+static s32 JL_spp_send(void *priv, void *data, u16 len)
+{
+ if (len < 128) {
+ rcsp_printf("send: \n");
+ rcsp_printf_buf(data, (u32)len);
+ }
+ if ((__this->rcsp_spp != NULL) && (__this->JL_spp_status == 1)) {
+ u32 err = __this->rcsp_spp->send_data(NULL, (u8 *)data, len);
+ if (err == 0) {
+ return 0;
+ } else if (err == SPP_USER_ERR_SEND_BUFF_BUSY) {
+ return 1;
+ }
+ } else {
+ rcsp_printf("send err -1 !!\n");
+ }
+
+ return -1;
+}
+
+static const JL_PRO_CB JL_pro_SPP_callback = {
+ .priv = NULL,
+ .fw_ready = JL_spp_fw_ready,
+ .fw_send = JL_spp_send,
+ .CMD_resp = JL_rcsp_cmd_resp,
+ .DATA_resp = JL_rcsp_data_resp,
+ .CMD_no_resp = JL_rcsp_cmd_no_resp,
+ .DATA_no_resp = JL_rcsp_data_no_resp,
+ .CMD_recieve_resp = JL_rcsp_cmd_recieve_resp,
+ .DATA_recieve_resp = JL_rcsp_data_recieve_resp,
+ .wait_resp_timeout = JL_rcsp_wait_resp_timeout,
+};
+
+static void rcsp_spp_callback_set(void (*resume)(void), void (*recieve)(void *, void *, u16), void (*status)(u8))
+{
+ __this->rcsp_spp->regist_wakeup_send(NULL, resume);
+ __this->rcsp_spp->regist_recieve_cbk(NULL, recieve);
+ __this->rcsp_spp->regist_state_cbk(NULL, status);
+}
+
+static int rcsp_spp_data_send(void *priv, u8 *buf, u16 len)
+{
+ int err = 0;
+ if (__this->rcsp_spp != NULL) {
+ err = __this->rcsp_spp->send_data(NULL, (u8 *)buf, len);
+ }
+
+ return err;
+
+}
+
+static int rcsp_ble_data_send(void *priv, u8 *buf, u16 len)
+{
+ rcsp_printf("### rcsp_ble_data_send %d\n", len);
+ int err = 0;
+ if (__this->rcsp_ble != NULL) {
+ err = __this->rcsp_ble->send_data(NULL, (u8 *)buf, len);
+ }
+
+ return err;
+
+}
+
+static void rcsp_spp_protocol_data_recieve(void *priv, void *buf, u16 len)
+{
+#if TCFG_USER_TWS_ENABLE
+ if (get_jl_update_flag() && (tws_api_get_role() == TWS_ROLE_SLAVE)) {
+ return;
+ }
+#endif
+ JL_protocol_data_recieve(priv, buf, len);
+}
+
+static const u8 link_key_data[16] = {0x06, 0x77, 0x5f, 0x87, 0x91, 0x8d, 0xd4, 0x23, 0x00, 0x5d, 0xf1, 0xd8, 0xcf, 0x0c, 0x14, 0x2b};
+void rcsp_dev_select(u8 type)
+{
+#if RCSP_UPDATE_EN
+ set_jl_update_flag(0);
+#endif
+ if (type == RCSP_BLE) {
+#if 1//RCSP_UPDATE_EN
+ JL_bt_chl = RCSP_BLE;
+#endif
+ rcsp_printf("------RCSP_BLE-----\n");
+ rcsp_spp_callback_set(NULL, NULL, NULL);
+ rcsp_ble_callback_set(JL_protocol_resume, JL_protocol_data_recieve, JL_ble_status_callback);
+ JL_protocol_dev_switch(&JL_pro_BLE_callback);
+ JL_rcsp_auth_init(rcsp_ble_data_send, (u8 *)link_key_data, NULL);
+ } else {
+#if 1//RCSP_UPDATE_EN
+ JL_bt_chl = RCSP_SPP;
+#endif
+ rcsp_printf("------RCSP_SPP-----\n");
+ rcsp_spp_callback_set(JL_protocol_resume, rcsp_spp_protocol_data_recieve, JL_spp_status_callback);
+ rcsp_ble_callback_set(NULL, NULL, NULL);
+ JL_protocol_dev_switch(&JL_pro_SPP_callback);
+ JL_rcsp_auth_init(rcsp_spp_data_send, (u8 *)link_key_data, NULL);
+ }
+}
+
+void set_rcsp_dev_type_spp(void)
+{
+ rcsp_dev_select(RCSP_SPP);
+}
+
+////////////////////// RCSP process ///////////////////////////////
+
+static OS_SEM rcsp_sem;
+
+void JL_rcsp_resume_do(void)
+{
+ os_sem_post(&rcsp_sem);
+}
+
+static u32 rcsp_protocol_tick = 0;
+static void rcsp_process_timer()
+{
+ JL_set_cur_tick(rcsp_protocol_tick++);
+ os_sem_post(&rcsp_sem);
+}
+u8 usr_rsp_inited=0;
+void usr_rcsp_process_timer()
+{
+ if(usr_rsp_inited)rcsp_process_timer();
+}
+
+static void rcsp_process_task(void *p)
+{
+ while (1) {
+ os_sem_pend(&rcsp_sem, 0);
+ JL_protocol_process();
+ }
+}
+
+/////////////////////////////////////////////////////
+
+static u8 *rcsp_buffer = NULL;
+void rcsp_init()
+{
+ memcpy(_s_info.edr_name, bt_get_local_name(), 32);
+
+ if (__this->rcsp_run_flag) {
+ return;
+ }
+
+ memset((u8 *)__this, 0, sizeof(struct JL_AI_VAR));
+
+ /* __this->start_speech = start_speech; */
+ /* __this->stop_speech = stop_speech; */
+ //__this->rcsp_user = (struct __rcsp_user_var *)get_user_rcsp_opt();
+
+ ble_get_server_operation_table(&__this->rcsp_ble);
+ spp_get_operation_table(&__this->rcsp_spp);
+
+ set_jl_mtu_send(256);
+
+ u32 size = rcsp_protocol_need_buf_size();
+ rcsp_printf("rcsp need buf size:%x\n", size);
+
+ rcsp_buffer = zalloc(size);
+ ASSERT(rcsp_buffer, "no, memory for rcsp_init\n");
+ JL_protocol_init(rcsp_buffer, size);
+
+ os_sem_create(&rcsp_sem, 0);
+ // sys_timer_add(NULL, rcsp_process_timer, 500);
+ usr_rsp_inited=1;
+ int err = task_create(rcsp_process_task, NULL, "rcsp_task");
+
+ //default use ble , can switch spp anytime
+ rcsp_dev_select(RCSP_BLE);
+
+#if (!MUTIl_CHARGING_BOX_EN)
+ adv_setting_init();
+#endif
+
+ __this->rcsp_run_flag = 1;
+#if (0 != BT_CONNECTION_VERIFY)
+ JL_rcsp_set_auth_flag(1);
+#endif
+}
+
+
+void rcsp_exit(void)
+{
+#if ((AI_SOUNDBOX_EN==1) && (RCSP_ADV_EN==1))
+ if (speech_status() == true) {
+ rcsp_cancel_speech();
+ speech_stop();
+ }
+ __set_a2dp_sound_detect_counter(50, 250); /*第一个参数是后台检测返回蓝牙的包数目,第二个参数是退出回到原来模式静音的包数目*/
+ __this->wait_asr_end = 0;
+#endif
+
+ if (rcsp_buffer) {
+ free(rcsp_buffer);
+ rcsp_buffer = 0;
+ }
+
+ rcsp_update_data_api_unregister();
+ rcsp_printf("#### rcsp_exit_cb\n");
+ task_kill("rcsp_task");
+ return;
+}
+
+int app_core_data_for_send(u8 *packet, u16 size)
+{
+ //printf("for app send size %d\n", size);
+
+ if (JL_rcsp_get_auth_flag()) {
+ *packet = 1;
+ } else {
+ *packet = 0;
+ }
+
+ if (RCSP_SPP == JL_get_cur_bt_channel_sel()) {
+ if (get_ble_adv_notify()) {
+ *(packet + 1) = 1;
+ } else {
+ *(packet + 1) = 0;
+ }
+
+#if RCSP_ADV_MUSIC_INFO_ENABLE
+ if (get_player_time_en()) {
+ *(packet + 2) = 1;
+ } else {
+ *(packet + 2) = 0;
+ }
+#else
+ *(packet + 2) = 0;
+#endif
+
+ *(packet + 3) = get_connect_flag();
+ }
+
+ return 4;
+}
+
+void app_core_data_for_set(u8 *packet, u16 size)
+{
+ u8 rcsp_auth_flag = *packet;
+ u8 ble_adv_notify = *(packet + 1);
+ u8 player_time_en = *(packet + 2);
+ u8 connect_flag = *(packet + 3);
+
+ if (RCSP_SPP == JL_get_cur_bt_channel_sel()) {
+ JL_rcsp_set_auth_flag(rcsp_auth_flag);
+ set_ble_adv_notify(ble_adv_notify);
+#if RCSP_ADV_MUSIC_INFO_ENABLE
+ set_player_time_en(player_time_en);
+#endif
+ set_connect_flag(connect_flag);
+ }
+
+ return;
+}
+
+u8 smart_auth_res_deal(void)
+{
+
+ if ((tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED)) {
+ if (RCSP_SPP == JL_get_cur_bt_channel_sel()) {
+ tws_api_sync_call_by_uuid('T', SYNC_CMD_RCSP_AUTH_RES, 300);
+ return 0;
+ } else {
+ return 1;
+ }
+ } else {
+ return 1;
+ }
+}
+
+
+void rcsp_tws_auth_sync_deal(void)
+{
+ smart_auth_res_pass();
+}
+
+
+
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_bluetooth.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_bluetooth.h
new file mode 100644
index 0000000..701790f
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_bluetooth.h
@@ -0,0 +1,131 @@
+#ifndef __JL_BLUETOOTH_ADV_H__
+#define __JL_BLUETOOTH_ADV_H__
+
+#include "app_config.h"
+#include "typedef.h"
+#include "system/event.h"
+
+#include "le_common.h"
+#include "ble_user.h"
+#include "spp_user.h"
+#if (RCSP_ADV_EN)
+void rcsp_init();
+void rcsp_dev_select(u8 type);
+void function_change_inform(void);
+
+bool common_msg_deal(u32 param, void *priv);
+bool ble_msg_deal(u32 param);
+bool music_msg_deal(u32 param, void *priv);
+bool linein_msg_deal(u32 param);
+bool rtc_msg_deal(u32 param);
+
+#if (RCSP_ADV_ASSISTED_HEARING)
+void set_hearing_aid_operating_flag();
+#endif
+
+void rcsp_exit(void);
+u8 rcsp_get_asr_status(void);
+u8 get_rcsp_support_new_reconn_flag(void);
+
+enum {
+ RCSP_BLE,
+ RCSP_SPP,
+};
+
+
+enum {
+ ANDROID,
+ APPLE_IOS,
+};
+
+struct JL_AI_VAR {
+ ble_state_e JL_ble_status;
+ struct ble_server_operation_t *rcsp_ble;
+ u8 JL_spp_status;
+ struct spp_operation_t *rcsp_spp;
+ volatile u8 speech_state;
+ u32 feature_mask;
+ u8 device_type;
+ u8 phone_platform;
+ void (*start_speech)(void);
+ void (*stop_speech)(void);
+ u8 err_report;
+ volatile u8 file_browse_lock_flag;
+ u32 return_msg;
+ u8 spec_mode;
+ struct __rcsp_user_var *rcsp_user;
+ volatile u8 rcsp_run_flag;
+ u8 ffr_mode;
+ u16 ffr_time;
+ volatile u8 wait_asr_end;
+ u8 new_reconn_flag; //是否支持新的回连方式(进行地址修改)
+};
+
+struct _SPEECH_OVER_DEAL {
+ u8 last_task;
+ u8 status;
+};
+
+extern struct JL_AI_VAR jl_ai_var;
+extern struct _SPEECH_OVER_DEAL speech_deal_val;
+
+
+#define DEVICE_EVENT_FROM_RCSP (('R' << 24) | ('C' << 16) | ('S' << 8) | 'P')
+
+enum RCSP_MSG_T {
+ MSG_JL_GET_DEV_UPDATE_FILE_INFO_OFFSET,
+ MSG_JL_INQUIRE_DEVEICE_IF_CAN_UPDATE,
+ MSG_JL_LOADER_DOWNLOAD_START,
+ MSG_JL_UPDATE_START,
+ MSG_JL_ENTER_UPDATE_MODE,
+ MSG_JL_DEV_DISCONNECT,
+ MSG_JL_BLE_UPDATE_START,
+ MSG_JL_SPP_UPDATE_START,
+ MSG_JL_ADV_SETTING_SYNC,
+ MSG_JL_ADV_SETTING_UPDATE,
+ MSG_JL_UPDATE_EQ,
+ MSG_JL_UPDATE_SEQ,
+ MSG_JL_SWITCH_DEVICE,
+ MSG_JL_UPDATE_PLAYER_TIME,
+ MSG_JL_UPDATE_PLAYER_STATE,
+ MSG_JL_UPDATE_MUSIC_INFO,
+ MSG_JL_UPDATE_MUSIC_PLAYER_TIME_TEMER,
+ MSG_JL_UPDAET_ADV_STATE_INFO,
+ MSG_JL_REBOOT_DEV,
+ MSG_JL_FIND_DEVICE_RESUME,
+ MSG_JL_FIND_DEVICE_STOP,
+ MSG_JL_UPDATE_ANC_VOICE,
+ MSG_JL_UPDATE_ANC_VOICE_MAX_SYNC,
+ MSG_JL_UPDATE_ADAPTIVE_NOISE_REDUCTION,
+ MSG_JL_UPDATE_AI_NO_PICK,
+ MSG_JL_UPDATE_SCENE_NOISE_REDUCTION,
+ MSG_JL_UPDATE_WIND_NOISE_DETECTION,
+ MSG_JL_UPDATE_VOICE_ENHANCEMENT_MODE,
+ MSG_JL_TWS_NEED_UPDATE,
+};
+
+void JL_rcsp_event_to_user(u32 type, u8 event, u8 *msg, u8 size);
+int JL_rcsp_event_handler(struct rcsp_event *rcsp);
+void rcsp_tws_auth_sync_deal(void);
+extern u8 JL_get_cur_bt_channel_sel(void);
+
+#define SDK_TYPE_AC690X 0x0
+#define SDK_TYPE_AC692X 0x1
+#define SDK_TYPE_AC693X 0x2
+#define SDK_TYPE_AC695X 0x3
+#define SDK_TYPE_AC697X 0x4
+
+#if (defined CONFIG_CPU_BR21)
+#define RCSP_SDK_TYPE SDK_TYPE_AC692X
+#elif (defined CONFIG_CPU_BR22)
+#define RCSP_SDK_TYPE SDK_TYPE_AC693X
+#elif (defined CONFIG_CPU_BR23)
+#define RCSP_SDK_TYPE SDK_TYPE_AC695X
+#elif (defined CONFIG_CPU_BR30)
+#define RCSP_SDK_TYPE SDK_TYPE_AC697X
+#else
+#define RCSP_SDK_TYPE SDK_TYPE_AC693X
+#endif
+
+#endif
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_customer_user.c b/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_customer_user.c
new file mode 100644
index 0000000..5cc7f05
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_customer_user.c
@@ -0,0 +1,70 @@
+#include
+#include
+#include
+#include "string.h"
+#include "JL_rcsp_api.h"
+#include "JL_rcsp_protocol.h"
+#include "JL_rcsp_packet.h"
+#include "spp_user.h"
+#include "btstack/avctp_user.h"
+#include "system/timer.h"
+#include "app_core.h"
+#include "user_cfg.h"
+#include "asm/pwm_led.h"
+#include "ui_manage.h"
+#include "key_event_deal.h"
+#include "syscfg_id.h"
+#include "user_cfg_id.h"
+#include "classic/tws_api.h"
+#include "event.h"
+#include "bt_tws.h"
+#include "custom_cfg.h"
+#include "app_config.h"
+
+
+#if (RCSP_ADV_EN)
+
+/* #define RCSP_USER_DEBUG_EN */
+#ifdef RCSP_USER_DEBUG_EN
+#define rcsp_user_putchar(x) putchar(x)
+#define rcsp_user_printf printf
+#define rcsp_user_printf_buf(x,len) put_buf(x,len)
+#else
+#define rcsp_user_putchar(...)
+#define rcsp_user_printf(...)
+#define rcsp_user_printf_buf(...)
+#endif
+
+/// 发送需要回复的自定义命令
+u32 rcsp_user_send_resp_cmd(u8 *data, u16 len)
+{
+ u32 ret = 0;
+ rcsp_user_printf("send resp cmd\n");
+ rcsp_user_printf_buf(data, len);
+ ret = JL_CMD_send(JL_OPCODE_CUSTOMER_USER, data, len, 1);
+ return ret;
+}
+
+void rcsp_user_recv_resp(u8 *data, u16 len)
+{
+ ///收到固件发出去,APP的回复
+ rcsp_user_printf("resp resp\n");
+ rcsp_user_printf_buf(data, len);
+}
+
+
+void rcsp_user_recv_cmd_resp(u8 *data, u16 len)
+{
+ ///收到app主动发过来的需要回复的自定义命令
+ ///回复在其他地方已完成,开发不需要单独回复
+ rcsp_user_printf("user recv cmd:\n");
+ rcsp_user_printf_buf(data, len);
+ /* rcsp_user_send_resp_cmd(data, len); */
+}
+
+
+
+
+
+
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_customer_user.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_customer_user.h
new file mode 100644
index 0000000..faf4007
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_customer_user.h
@@ -0,0 +1,17 @@
+#ifndef __JL_ADV_CUSTOMER_USER_H__
+#define __JL_ADV_CUSTOMER_USER_H__
+
+#include "app_config.h"
+#include "typedef.h"
+#include "system/event.h"
+
+#include "le_common.h"
+#include "spp_user.h"
+#if (RCSP_ADV_EN)
+
+void rcsp_user_recv_cmd_resp(u8 *data, u16 len);
+void rcsp_user_recv_resp(u8 *data, u16 len);
+u32 rcsp_user_send_resp_cmd(u8 *data, u16 len);
+
+#endif
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_opt.c b/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_opt.c
new file mode 100644
index 0000000..3e760a3
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_opt.c
@@ -0,0 +1,494 @@
+#include "app_config.h"
+#include "syscfg_id.h"
+#include "user_cfg_id.h"
+#include "le_rcsp_adv_module.h"
+#include "rcsp_adv_bluetooth.h"
+
+#include "rcsp_adv_opt.h"
+#include "adv_setting_common.h"
+#include "rcsp_adv_tws_sync.h"
+#include "adv_time_stamp_setting.h"
+#include "adv_bt_name_setting.h"
+#include "adv_key_setting.h"
+#include "adv_led_setting.h"
+#include "adv_mic_setting.h"
+#include "adv_work_setting.h"
+#include "adv_eq_setting.h"
+#include "adv_high_low_vol.h"
+#include "adv_anc_voice_key.h"
+#include "bt_tws.h"
+#include "btstack/avctp_user.h"
+
+#include "adv_anc_voice.h"
+
+#if (RCSP_ADV_EN)
+static u16 adv_setting_event_flag = (u16) - 1;
+static void set_adv_setting_event_flag(u16 flag)
+{
+ adv_setting_event_flag = flag;
+}
+
+static u16 get_adv_setting_event_flag(void)
+{
+ return adv_setting_event_flag;
+}
+
+static u8 deal_adv_setting_string_item(u8 *des, u8 *src, u8 src_len, u8 type)
+{
+ des[0] = type;
+ memcpy(des + 1, src, src_len);
+ return src_len + sizeof(type);
+}
+
+void update_info_from_adv_vm_info(void)
+{
+ if (get_adv_setting_event_flag() & BIT(ATTR_TYPE_TIME_STAMP)) {
+ deal_time_stamp_setting(0, 1, 0);
+ }
+
+#if RCSP_ADV_NAME_SET_ENABLE
+ if (get_adv_setting_event_flag() & BIT(ATTR_TYPE_EDR_NAME)) {
+ deal_bt_name_setting(NULL, 1, 0);
+ }
+#endif
+
+#if RCSP_ADV_KEY_SET_ENABLE
+ if (get_adv_setting_event_flag() & BIT(ATTR_TYPE_KEY_SETTING)) {
+ deal_key_setting(NULL, 1, 0);
+ }
+
+ if (get_adv_setting_event_flag() & BIT(ATTR_TYPE_ANC_VOICE_KEY)) {
+ deal_anc_voice_key_setting(NULL, 1, 0);
+ }
+#endif
+
+#if RCSP_ADV_LED_SET_ENABLE
+ if (get_adv_setting_event_flag() & BIT(ATTR_TYPE_LED_SETTING)) {
+ deal_led_setting(NULL, 1, 0);
+ }
+#endif
+
+#if RCSP_ADV_MIC_SET_ENABLE
+ if (get_adv_setting_event_flag() & BIT(ATTR_TYPE_MIC_SETTING)) {
+ deal_mic_setting(0, 1, 0);
+ }
+#endif
+
+#if RCSP_ADV_WORK_SET_ENABLE
+ if (get_adv_setting_event_flag() & BIT(ATTR_TYPE_WORK_MODE)) {
+ deal_work_setting(0, 1, 0, 0);
+ }
+#endif
+
+#if RCSP_ADV_EQ_SET_ENABLE
+ if (get_adv_setting_event_flag() & BIT(ATTR_TYPE_EQ_SETTING)) {
+ deal_eq_setting(0, 1, 0);
+ }
+#endif
+
+#if RCSP_ADV_HIGH_LOW_SET
+ if (get_adv_setting_event_flag() & BIT(ATTR_TYPE_HIGH_LOW_VOL)) {
+ deal_high_low_vol(NULL, 1, 0);
+ }
+#endif
+
+#if (RCSP_ADV_ANC_VOICE)
+ if (get_adv_setting_event_flag() & BIT(ATTR_TYPE_ANC_VOICE)) {
+ deal_anc_voice(NULL, 1, 0);
+ }
+#endif
+
+#if (RCSP_ADV_ASSISTED_HEARING)
+ if (get_adv_setting_event_flag() & BIT(ATTR_TYPE_ASSISTED_HEARING)) {
+ deal_hearing_aid_setting(-1, -1, NULL, 1, 0);
+ }
+#endif
+
+ set_adv_setting_event_flag(0);
+}
+
+static u8 adv_read_data_from_vm(u8 syscfg_id, u8 *buf, u8 buf_len)
+{
+ int len = 0;
+ u8 i = 0;
+
+
+ len = syscfg_read(syscfg_id, buf, buf_len);
+
+ if (len > 0) {
+ for (i = 0; i < buf_len; i++) {
+ if (buf[i] != 0xff) {
+ return (buf_len == len);
+ }
+ }
+ }
+
+ return 0;
+}
+
+void adv_setting_init(void)
+{
+ u32 time_stamp = 0;
+ if (adv_read_data_from_vm(CFG_RCSP_ADV_TIME_STAMP, (u8 *)&time_stamp, sizeof(time_stamp))) {
+ set_adv_time_stamp(time_stamp);
+ //deal_time_stamp_setting(0, 0, 0);
+ }
+
+#if RCSP_ADV_NAME_SET_ENABLE
+ u8 bt_name_info[32] = {0};
+ if (adv_read_data_from_vm(CFG_BT_NAME, bt_name_info, sizeof(bt_name_info))) {
+ set_bt_name_setting(bt_name_info);
+ //deal_bt_name_setting(NULL, 0, 0);
+ }
+#endif
+
+#if RCSP_ADV_KEY_SET_ENABLE
+ u8 key_setting_info[4] = {0};
+ if (adv_read_data_from_vm(CFG_RCSP_ADV_KEY_SETTING, key_setting_info, sizeof(key_setting_info))) {
+ set_key_setting(key_setting_info);
+ deal_key_setting(NULL, 0, 0);
+ }
+
+ u8 key_anc_voice_mode[4] = {0};
+ if (adv_read_data_from_vm(CFG_RCSP_ADV_ANC_VOICE_KEY, key_anc_voice_mode, sizeof(key_anc_voice_mode))) {
+ set_anc_voice_key_mode(key_anc_voice_mode);
+ deal_anc_voice_key_setting(NULL, 0, 0);
+ }
+#endif
+
+#if RCSP_ADV_LED_SET_ENABLE
+ u8 led_setting_info[3] = {0};
+ if (adv_read_data_from_vm(CFG_RCSP_ADV_LED_SETTING, led_setting_info, sizeof(led_setting_info))) {
+ set_led_setting(led_setting_info);
+ deal_led_setting(NULL, 0, 0);
+ }
+#endif
+
+#if RCSP_ADV_MIC_SET_ENABLE
+ u8 mic_setting_info = 0;
+ if (adv_read_data_from_vm(CFG_RCSP_ADV_MIC_SETTING, &mic_setting_info, sizeof(mic_setting_info))) {
+ set_mic_setting(mic_setting_info);
+ deal_mic_setting(0, 0, 0);
+ }
+#endif
+
+#if RCSP_ADV_WORK_SET_ENABLE
+ u8 work_setting_info = 0;
+ if (adv_read_data_from_vm(CFG_RCSP_ADV_WORK_SETTING, &work_setting_info, sizeof(work_setting_info))) {
+ set_work_setting(work_setting_info);
+ deal_work_setting(0, 0, 0, 1);
+ }
+#endif
+
+#if RCSP_ADV_EQ_SET_ENABLE
+ u8 eq_setting_vm_info[11] = {0};
+ u8 eq_setting_info[10] = {0};
+ u8 eq_setting_mode = 0;
+ u8 i;
+ if (adv_read_data_from_vm(CFG_RCSP_ADV_EQ_DATA_SETTING, eq_setting_info, sizeof(eq_setting_info))) {
+ if (adv_read_data_from_vm(CFG_RCSP_ADV_EQ_MODE_SETTING, &eq_setting_mode, sizeof(eq_setting_mode))) {
+ eq_setting_vm_info[0] = eq_setting_mode;
+ memcpy(eq_setting_vm_info + 1, eq_setting_info, sizeof(eq_setting_info));
+ set_eq_setting(eq_setting_vm_info);
+ deal_eq_setting(NULL, 0, 0);
+ }
+ }
+#endif
+
+#if RCSP_ADV_HIGH_LOW_SET
+ u8 high_low_vol_setting[8] = {0};
+ if (adv_read_data_from_vm(CFG_RCSP_ADV_HIGH_LOW_VOL, high_low_vol_setting, sizeof(high_low_vol_setting))) {
+ set_high_low_vol_info(high_low_vol_setting);
+ deal_high_low_vol(NULL, 0, 0);
+ }
+#endif
+
+#if (RCSP_ADV_ANC_VOICE)
+ u8 anc_voice_setting[25] = {0};
+ if (anc_voice_setting_init()) {
+ if (adv_read_data_from_vm(CFG_RCSP_ADV_ANC_VOICE_MODE, anc_voice_setting, 1)) {
+ if (adv_read_data_from_vm(CFG_RCSP_ADV_ANC_VOICE, anc_voice_setting + 1, sizeof(anc_voice_setting) - 1)) {
+ set_anc_voice_info(anc_voice_setting);
+ deal_anc_voice(NULL, 0, 0);
+ }
+ }
+ }
+#endif
+}
+
+// type : 0 ~ 8
+// mode : 0 - 从vm读出并更新全局变量数据 // 1 - 同步
+void update_adv_setting(u16 type)
+{
+ u8 offset = 1;
+ // total_len time name key led mic work eq vol anc anc_voice
+ u8 adv_setting_to_sync[1 + (4 + 1) + (32 + 1) + (4 + 1) + (3 + 1) + (1 + 1) + (1 + 1) + (11 + 1) + (8 + 1) + (25 + 1) + (4 + 1)] = {0};
+ memset(adv_setting_to_sync, 0, sizeof(adv_setting_to_sync));
+
+ if (type & BIT(ATTR_TYPE_TIME_STAMP)) {
+ u32 time_stamp = get_adv_time_stamp();
+ offset += deal_adv_setting_string_item(adv_setting_to_sync + offset, (u8 *)&time_stamp, sizeof(time_stamp), ATTR_TYPE_TIME_STAMP);
+ }
+
+#if RCSP_ADV_NAME_SET_ENABLE
+ if (type & BIT(ATTR_TYPE_EDR_NAME)) {
+ u8 bt_name_info[32] = {0};
+ get_bt_name_setting(bt_name_info);
+ offset += deal_adv_setting_string_item(adv_setting_to_sync + offset, bt_name_info, sizeof(bt_name_info), ATTR_TYPE_EDR_NAME);
+ }
+#endif
+
+#if RCSP_ADV_KEY_SET_ENABLE
+ if (type & BIT(ATTR_TYPE_KEY_SETTING)) {
+ u8 key_setting_info[4] = {0};
+ get_key_setting(key_setting_info);
+ offset += deal_adv_setting_string_item(adv_setting_to_sync + offset, key_setting_info, sizeof(key_setting_info), ATTR_TYPE_KEY_SETTING);
+ }
+
+ if (type & BIT(ATTR_TYPE_ANC_VOICE_KEY)) {
+ u8 key_anc_voice_mode[4] = {0};
+ get_anc_voice_key_mode(key_anc_voice_mode);
+ offset += deal_adv_setting_string_item(adv_setting_to_sync + offset, key_anc_voice_mode, sizeof(key_anc_voice_mode), ATTR_TYPE_ANC_VOICE_KEY);
+ }
+#endif
+
+#if RCSP_ADV_LED_SET_ENABLE
+ if (type & BIT(ATTR_TYPE_LED_SETTING)) {
+ u8 led_setting_info[3] = {0};
+ get_led_setting(led_setting_info);
+ offset += deal_adv_setting_string_item(adv_setting_to_sync + offset, led_setting_info, sizeof(led_setting_info), ATTR_TYPE_LED_SETTING);
+ }
+#endif
+
+#if RCSP_ADV_MIC_SET_ENABLE
+ if (type & BIT(ATTR_TYPE_MIC_SETTING)) {
+ u8 mic_setting_info = get_mic_setting();
+ offset += deal_adv_setting_string_item(adv_setting_to_sync + offset, &mic_setting_info, sizeof(mic_setting_info), ATTR_TYPE_MIC_SETTING);
+ }
+#endif
+
+#if RCSP_ADV_WORK_SET_ENABLE
+ if (type & BIT(ATTR_TYPE_WORK_MODE)) {
+ u8 work_setting_info = get_work_setting();
+ offset += deal_adv_setting_string_item(adv_setting_to_sync + offset, &work_setting_info, sizeof(work_setting_info), ATTR_TYPE_WORK_MODE);
+ }
+#endif
+
+#if RCSP_ADV_EQ_SET_ENABLE
+ if (type & BIT(ATTR_TYPE_EQ_SETTING)) {
+ u8 eq_setting_info[11];
+ get_eq_setting(eq_setting_info);
+ offset += deal_adv_setting_string_item(adv_setting_to_sync + offset, eq_setting_info, sizeof(eq_setting_info), ATTR_TYPE_EQ_SETTING);
+ }
+#endif
+
+#if RCSP_ADV_HIGH_LOW_SET
+ if (type & BIT(ATTR_TYPE_HIGH_LOW_VOL)) {
+ u8 high_low_vol[8];
+ get_high_low_vol_info(high_low_vol);
+ offset += deal_adv_setting_string_item(adv_setting_to_sync + offset, high_low_vol, sizeof(high_low_vol), ATTR_TYPE_HIGH_LOW_VOL);
+ }
+#endif
+
+#if (RCSP_ADV_ANC_VOICE)
+ if (type & BIT(ATTR_TYPE_ANC_VOICE)) {
+ u8 anc_voice_info[25];
+ get_anc_voice_info(anc_voice_info);
+ offset += deal_adv_setting_string_item(adv_setting_to_sync + offset, anc_voice_info, sizeof(anc_voice_info), ATTR_TYPE_ANC_VOICE);
+ }
+#endif
+
+#if RCSP_ADV_ASSISTED_HEARING
+ if (((u16) - 1) != type && type & BIT(ATTR_TYPE_ASSISTED_HEARING)) {
+ u8 dha_fitting_data[3 + 2 * 4 * DHA_FITTING_CHANNEL_MAX];
+ get_hearing_aid_setting(dha_fitting_data);
+ offset += deal_adv_setting_string_item(adv_setting_to_sync + offset, dha_fitting_data, sizeof(dha_fitting_data), ATTR_TYPE_ASSISTED_HEARING);
+ }
+#endif
+
+ if (offset > 1) {
+ adv_setting_to_sync[0] = offset;
+ if (type == ((u16) - 1)) {
+ tws_api_send_data_to_sibling(adv_setting_to_sync, sizeof(adv_setting_to_sync), TWS_FUNC_ID_ADV_SETTING_SYNC);
+#if RCSP_ADV_LED_SET_ENABLE
+ tws_api_sync_call_by_uuid('T', SYNC_CMD_APP_RESET_LED_UI, 300);
+#endif
+ } else {
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ tws_api_send_data_to_sibling(adv_setting_to_sync, sizeof(adv_setting_to_sync), TWS_FUNC_ID_ADV_SETTING_SYNC);
+#if RCSP_ADV_LED_SET_ENABLE
+ tws_api_sync_call_by_uuid('T', SYNC_CMD_APP_RESET_LED_UI, 300);
+#endif
+ }
+ }
+ }
+}
+
+void deal_sibling_setting(u8 *buf)
+{
+ u8 type;
+ u8 len = buf[0];
+ u8 offset = 1;
+ u8 *data;
+ u32 time_stamp = 0;
+ set_adv_setting_event_flag(0);
+ while (offset < len) {
+ type = buf[offset++];
+ data = buf + offset;
+ switch (type) {
+#if RCSP_ADV_NAME_SET_ENABLE
+ case ATTR_TYPE_EDR_NAME:
+ set_bt_name_setting(data);
+ offset += 32;
+ break;
+#endif
+#if RCSP_ADV_KEY_SET_ENABLE
+ case ATTR_TYPE_KEY_SETTING :
+ set_key_setting(data);
+ offset += 4;
+ break;
+ case ATTR_TYPE_ANC_VOICE_KEY:
+ set_anc_voice_key_mode(data);
+ offset += 4;
+ break;
+#endif
+#if RCSP_ADV_LED_SET_ENABLE
+ case ATTR_TYPE_LED_SETTING :
+ set_led_setting(data);
+ offset += 3;
+ break;
+#endif
+#if RCSP_ADV_MIC_SET_ENABLE
+ case ATTR_TYPE_MIC_SETTING :
+ set_mic_setting(*data);
+ offset += 1;
+ break;
+#endif
+#if RCSP_ADV_WORK_SET_ENABLE
+ case ATTR_TYPE_WORK_MODE :
+ set_work_setting(*data);
+ offset += 1;
+ break;
+#endif
+#if RCSP_ADV_EQ_SET_ENABLE
+ case ATTR_TYPE_EQ_SETTING :
+ /* g_printf("tws eq setting\n"); */
+ set_eq_setting(data);
+ offset += 11;
+ break;
+#endif
+#if RCSP_ADV_HIGH_LOW_SET
+ case ATTR_TYPE_HIGH_LOW_VOL:
+ set_high_low_vol_info(data);
+ offset += 8;
+ break;
+#endif
+#if (RCSP_ADV_ANC_VOICE)
+ case ATTR_TYPE_ANC_VOICE:
+ set_anc_voice_info(data);
+ offset += 25;
+ break;
+#endif
+#if (RCSP_ADV_ASSISTED_HEARING)
+ case ATTR_TYPE_ASSISTED_HEARING:
+ set_hearing_aid_setting(data);
+ offset += 3 + 2 * 4 * DHA_FITTING_CHANNEL_MAX;
+ break;
+#endif
+ case ATTR_TYPE_TIME_STAMP:
+ time_stamp = (data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24));//*((u32 *)data);
+
+ set_adv_time_stamp(time_stamp);
+ offset += 4;
+ break;
+ default:
+ return;
+ }
+ set_adv_setting_event_flag(get_adv_setting_event_flag() | BIT(type));
+ }
+ // 发送事件
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_ADV_SETTING_UPDATE, NULL, 0);
+}
+
+#if (0)
+static void adv_reset_data_to_vm(u8 syscfg_id, u8 *buf, u8 buf_len)
+{
+ u8 res = 0;
+ res = syscfg_write(syscfg_id, buf, buf_len);
+}
+
+u8 rcsp_setting_info_reset() //恢复默认的APP设置
+{
+ printf("%s", __func__);
+
+ u32 time_stamp = 0xffffffff;
+ adv_reset_data_to_vm(CFG_RCSP_ADV_TIME_STAMP, (u8 *)&time_stamp, sizeof(time_stamp));
+
+ /* #if RCSP_ADV_NAME_SET_ENABLE */
+ /* u8 bt_name_info[32] = {0}; */
+ /* memset(bt_name_info,0xff,32); */
+ /* adv_reset_data_to_vm(CFG_BT_NAME, bt_name_info, sizeof(bt_name_info)); */
+ /* #endif */
+
+#if RCSP_ADV_KEY_SET_ENABLE
+ u8 key_setting_info[4] = {0};
+ memset(key_setting_info, 0xff, 4);
+ adv_reset_data_to_vm(CFG_RCSP_ADV_KEY_SETTING, key_setting_info, sizeof(key_setting_info));
+#endif
+
+#if RCSP_ADV_LED_SET_ENABLE
+ u8 led_setting_info[3] = {0};
+ memset(led_setting_info, 0xff, 3);
+ adv_reset_data_to_vm(CFG_RCSP_ADV_LED_SETTING, led_setting_info, sizeof(led_setting_info));
+#endif
+
+#if RCSP_ADV_MIC_SET_ENABLE
+ u8 mic_setting_info = 0xff;
+ adv_reset_data_to_vm(CFG_RCSP_ADV_MIC_SETTING, &mic_setting_info, sizeof(mic_setting_info));
+#endif
+
+#if RCSP_ADV_WORK_SET_ENABLE
+ u8 work_setting_info = 0xff;
+ adv_reset_data_to_vm(CFG_RCSP_ADV_WORK_SETTING, &work_setting_info, sizeof(work_setting_info));
+#endif
+
+#if RCSP_ADV_EQ_SET_ENABLE
+ u8 eq_setting_info[10] = {0};
+ u8 eq_setting_mode = 0xff;
+ memset(eq_setting_info, 0xff, 10);
+ adv_reset_data_to_vm(CFG_RCSP_ADV_EQ_DATA_SETTING, &eq_setting_info, sizeof(eq_setting_info));
+ adv_reset_data_to_vm(CFG_RCSP_ADV_EQ_MODE_SETTING, &eq_setting_mode, sizeof(eq_setting_mode));
+#endif
+ return 0;
+}
+
+u8 remap_app_chargestore_data_deal(u8 *buf, u8 len)
+{
+ u8 send_buf[30];
+ u8 ret = 0;
+ send_buf[0] = buf[0];
+//#define CMD_GET_NAME 0xc1
+ switch (buf[0]) {
+ case 0x08:
+ //printf("\n\n\n\n\n\n---------------reset store sys\n");
+ ret = 1 ;
+
+ void bt_tws_remove_pairs();
+ bt_tws_remove_pairs();
+ extern u8 rcsp_setting_info_reset();
+ rcsp_setting_info_reset();
+ user_send_cmd_prepare(USER_CTRL_DEL_ALL_REMOTE_INFO, 0, NULL);
+ os_time_dly(60);
+ cpu_reset();
+
+ break;
+
+ default:
+ break;
+ }
+ return ret;
+}
+#endif
+
+
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_opt.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_opt.h
new file mode 100644
index 0000000..f8a9a72
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_opt.h
@@ -0,0 +1,6 @@
+#ifndef __RCSP_ADV_OPT_H__
+#define __RCSP_ADV_OPT_H__
+
+void deal_sibling_setting(u8 *buf);
+
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_tws_sync.c b/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_tws_sync.c
new file mode 100644
index 0000000..3ec2dff
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_tws_sync.c
@@ -0,0 +1,105 @@
+#include "app_config.h"
+#include "rcsp_adv_tws_sync.h"
+#include "adv_setting_common.h"
+#include "rcsp_adv_opt.h"
+#include "adv_time_stamp_setting.h"
+#include "rcsp_adv_bluetooth.h"
+#include "bt_tws.h"
+
+#if (RCSP_ADV_EN && TCFG_USER_TWS_ENABLE)
+static void adv_sync_tws_func_t(void *data, u16 len, bool rx)
+{
+ if (rx) {
+ deal_sibling_setting((u8 *)data);
+ }
+}
+
+REGISTER_TWS_FUNC_STUB(adv_tws_sync) = {
+ .func_id = TWS_FUNC_ID_ADV_SETTING_SYNC,
+ .func = adv_sync_tws_func_t,
+};
+
+static void adv_sync_time_stamp_func_t(void *data, u16 len, bool rx)
+{
+ if (rx) {
+ deal_sibling_time_stamp_setting_switch(data, len);
+ }
+}
+
+REGISTER_TWS_FUNC_STUB(adv_time_stamp_sync) = {
+ .func_id = TWS_FUNC_ID_TIME_STAMP_SYNC,
+ .func = adv_sync_time_stamp_func_t,
+};
+
+#define TWS_FUNC_ID_ADV_RESET_SYNC \
+ (((u8)('R' + 'C' + 'S' + 'P') << (3 * 8)) | \
+ ((u8)('A' + 'D' + 'V') << (2 * 8)) | \
+ ((u8)('R' + 'E' + 'S' + 'E' + 'T') << (1 * 8)) | \
+ ((u8)('S' + 'Y' + 'N' + 'C') << (0 * 8)))
+
+static void adv_sync_reset_sync_func_t(int args)
+{
+ extern void cpu_reset();
+ cpu_reset();
+}
+
+TWS_SYNC_CALL_REGISTER(adv_reset_sync) = {
+ .uuid = TWS_FUNC_ID_ADV_RESET_SYNC,
+ .func = adv_sync_reset_sync_func_t,
+};
+
+void modify_bt_name_and_reset(u32 msec)
+{
+ tws_api_sync_call_by_uuid(TWS_FUNC_ID_ADV_RESET_SYNC, 0, msec);
+}
+
+#define TWS_FUNC_ID_ADV_FIND_DEV_SYNC \
+ (((u8)('A' + 'D' + 'V') << (3 * 8)) | \
+ ((u8)('F' + 'I' + 'N' + 'D') << (2 * 8)) | \
+ ((u8)('D' + 'E' + 'V') << (1 * 8)) | \
+ ((u8)('S' + 'Y' + 'N' + 'C') << (0 * 8)))
+
+static void adv_find_dev_sync_func_t(int args)
+{
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_FIND_DEVICE_RESUME, &args, sizeof(args));
+}
+
+TWS_SYNC_CALL_REGISTER(adv_find_dev_sync) = {
+ .uuid = TWS_FUNC_ID_ADV_FIND_DEV_SYNC,
+ .func = adv_find_dev_sync_func_t,
+};
+
+void find_device_sync(u8 *param, u32 msec)
+{
+ int priv = 0;
+ if (TWS_ROLE_MASTER == tws_api_get_role()) {
+ memcpy(&priv, param, 3);
+ tws_api_sync_call_by_uuid(TWS_FUNC_ID_ADV_FIND_DEV_SYNC, priv, msec);
+ }
+}
+
+#define TWS_FUNC_ID_ADV_FIND_DEV_STOP_TIMER_SYNC \
+ (((u8)('F' + 'I' + 'N' + 'D') << (3 * 8)) | \
+ ((u8)('D' + 'E' + 'V') << (2 * 8)) | \
+ ((u8)('S' + 'T' + 'O' + 'P') << (1 * 8)) | \
+ ((u8)('S' + 'Y' + 'N' + 'C') << (0 * 8)))
+
+static void adv_find_dev_stop_sync_timer_func_t(int args)
+{
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_FIND_DEVICE_STOP, &args, sizeof(args));
+}
+
+TWS_SYNC_CALL_REGISTER(adv_find_dev_stop_sync) = {
+ .uuid = TWS_FUNC_ID_ADV_FIND_DEV_STOP_TIMER_SYNC,
+ .func = adv_find_dev_stop_sync_timer_func_t,
+};
+
+void find_devic_stop_timer(u8 *param, u32 msec)
+{
+ int priv = 0;
+ if (TWS_ROLE_MASTER == tws_api_get_role()) {
+ memcpy(&priv, param, 3);
+ tws_api_sync_call_by_uuid(TWS_FUNC_ID_ADV_FIND_DEV_STOP_TIMER_SYNC, priv, msec);
+ }
+}
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_tws_sync.h b/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_tws_sync.h
new file mode 100644
index 0000000..4b2e1a9
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/adv_rcsp_protocol/rcsp_adv_tws_sync.h
@@ -0,0 +1,13 @@
+#ifndef __RCSP_ADV_TWS_SYNC_H__
+#define __RCSP_ADV_TWS_SYNC_H__
+
+#include "classic/tws_api.h"
+
+#define TWS_FUNC_ID_ADV_SETTING_SYNC \
+ TWS_FUNC_ID('R', 'C', 'S', 'P')
+#define TWS_FUNC_ID_TIME_STAMP_SYNC \
+ TWS_FUNC_ID('R' + 'C' + 'S' + 'P', \
+ 'A' + 'D' + 'V', \
+ 'T' + 'I' + 'M' + 'E', \
+ 'S' + 'T' + 'A' + 'M' + 'P')
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/bt_trans_data/le_rcsp_adv_module.c b/apps/common/third_party_profile/jieli/JL_rcsp/bt_trans_data/le_rcsp_adv_module.c
new file mode 100644
index 0000000..0edd9c6
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/bt_trans_data/le_rcsp_adv_module.c
@@ -0,0 +1,1126 @@
+/*********************************************************************************************
+ * Filename : le_server_module.c
+
+ * Description :
+
+ * Author :
+
+ * Email : zh-jieli.com
+
+ * Last modifiled : 2017-01-17 11:14
+
+ * Copyright:(c)JIELI 2011-2016 @ , All Rights Reserved.
+*********************************************************************************************/
+
+// *****************************************************************************
+/* EXAMPLE_START(le_counter): LE Peripheral - Heartbeat Counter over GATT
+ *
+ * @text All newer operating systems provide GATT Client functionality.
+ * The LE Counter examples demonstrates how to specify a minimal GATT Database
+ * with a custom GATT Service and a custom Characteristic that sends periodic
+ * notifications.
+ */
+// *****************************************************************************
+#include "system/app_core.h"
+#include "system/includes.h"
+
+#include "app_config.h"
+#include "app_action.h"
+#include "app_main.h"
+
+#include "btstack/btstack_task.h"
+#include "btstack/bluetooth.h"
+#include "user_cfg.h"
+#include "vm.h"
+#include "app_power_manage.h"
+#include "btcontroller_modules.h"
+#include "JL_rcsp_api.h"
+#include "rcsp_adv_bluetooth.h"
+#include "bt_common.h"
+/* #include "bt_tws.h" */
+#include "3th_profile_api.h"
+#include "btstack/avctp_user.h"
+//#include "app_chargestore.h"
+
+#include "le_common.h"
+#include "le_rcsp_adv_module.h"
+#include "btcrypt.h"
+#include "custom_cfg.h"
+#include "adv_music_info_setting.h"
+#include "classic/tws_api.h"
+#include "rcsp_adv_user_update.h"
+#include "bt_tws.h"
+
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV_RCSP)
+
+#if TCFG_CHARGE_BOX_ENABLE
+#include "chgbox_box.h"
+#endif
+
+/* usr_le_code 库钩子:由静态库导出,供 RCSP BLE 栈回调,非应用层公开 API */
+extern void usr_le_data_recieve(u8* data,u16 len);
+extern void usr_ble_adv_init();
+#if 1
+extern void printf_buf(u8 *buf, u32 len);
+#define log_info printf
+#define log_info_hexdump printf_buf
+#else
+#define log_info(...)
+#define log_info_hexdump(...)
+#endif
+
+#define EIR_TAG_STRING 0xd6, 0x05, 0x08, 0x00, 'J', 'L', 'A', 'I', 'S', 'D','K'
+static const char user_tag_string[] = {EIR_TAG_STRING};
+
+//用户可配对的,这是样机跟客户开发的app配对的秘钥
+/* const u8 link_key_data[16] = {0x06, 0x77, 0x5f, 0x87, 0x91, 0x8d, 0xd4, 0x23, 0x00, 0x5d, 0xf1, 0xd8, 0xcf, 0x0c, 0x14, 0x2b}; */
+
+
+/* #define LOG_TAG_CONST BT_BLE */
+/* #define LOG_TAG "[LE_S_DEMO]" */
+/* #define LOG_ERROR_ENABLE */
+/* #define LOG_DEBUG_ENABLE */
+/* #define LOG_INFO_ENABLE */
+/* #define LOG_DUMP_ENABLE */
+/* #define LOG_CLI_ENABLE */
+/* #include "debug.h" */
+
+//------
+#define ADV_INTERVAL_MIN (480)
+#define ATT_LOCAL_PAYLOAD_SIZE (247) //note: need >= 20
+#define ATT_SEND_CBUF_SIZE (1024+384)//(768) //note: need >= 20,缓存大小,可修改
+#define ATT_RAM_BUFSIZE (ATT_CTRL_BLOCK_SIZE + ATT_LOCAL_PAYLOAD_SIZE + ATT_SEND_CBUF_SIZE) //note:
+static u8 att_ram_buffer[ATT_RAM_BUFSIZE] __attribute__((aligned(4)));
+static hci_con_handle_t con_handle=0;
+
+//加密设置
+static const uint8_t sm_min_key_size = 7;
+
+//连接参数设置
+static const uint8_t connection_update_enable = 1; ///0--disable, 1--enable
+static uint8_t connection_update_cnt = 0; //
+static const struct conn_update_param_t connection_param_table[] = {
+ {16, 24, 10, 600},
+ {12, 28, 10, 600},//11
+ {8, 20, 10, 600},//3.7
+ /* {12, 28, 4, 600},//3.7 */
+ /* {12, 24, 30, 600},//3.05 */
+};
+static const struct conn_update_param_t connection_param_table_ota[] = {
+ {16, 24, 0, 600},
+ {12, 28, 0, 600},//11
+ {8, 20, 0, 600},//3.7
+ /* {12, 28, 4, 600},//3.7 */
+ /* {12, 24, 30, 600},//3.05 */
+};
+#define CONN_PARAM_TABLE_CNT (sizeof(connection_param_table)/sizeof(struct conn_update_param_t))
+
+#if (ATT_RAM_BUFSIZE < 64)
+#error "adv_data & rsp_data buffer error!!!!!!!!!!!!"
+#endif
+
+u8 muti_adv_data_len;
+u8 muti_adv_data[31];//max is 31
+static u8 scan_rsp_data_len;
+static u8 scan_rsp_data[ADV_RSP_PACKET_MAX];//max is 31
+
+
+/* #define adv_data &att_ram_buffer[0] */
+/* #define scan_rsp_data &att_ram_buffer[32] */
+
+static u32 ble_timer_handle = 0;
+static char *gap_device_name = "br22_ble_test";
+static u8 gap_device_name_len = 0;
+volatile static u8 ble_work_state = 0;
+static u8 test_read_write_buf[4];
+static u8 adv_ctrl_en;
+
+extern const char *bt_get_local_name();
+extern const u8 *bt_get_mac_addr();
+extern const u8 *ble_get_mac_addr(void);
+extern void swapX(const uint8_t *src, uint8_t *dst, int len);
+extern int get_bt_tws_connect_status();
+void rcsp_set_update_flag(u8 flag);
+void rcsp_update_set_role_switch(u8 sw);
+void sys_auto_shut_down_disable(void);
+
+//#define BLE_TIMER_SET (500)
+
+static void (*app_recieve_callback)(void *priv, void *buf, u16 len) = NULL;
+static void (*app_ble_state_callback)(void *priv, ble_state_e state) = NULL;
+static void (*ble_resume_send_wakeup)(void) = NULL;
+static u32 channel_priv;
+u16 sibling_ver_info = 0;
+//------------------------------------------------------
+
+static int app_send_user_data_check(u16 len);
+static int app_send_user_data_do(void *priv, u8 *data, u16 len);
+static int app_send_user_data(u16 handle, u8 *data, u16 len, u8 handle_type);
+//------------------------------------------------------
+//广播参数设置
+static void advertisements_setup_init();
+extern const char *bt_get_local_name();
+static int set_adv_enable(void *priv, u32 en);
+static int get_buffer_vaild_len(void *priv);
+//------------------------------------------------------
+static void send_request_connect_parameter(u8 table_index)
+{
+ struct conn_update_param_t *param = (void *)&connection_param_table[table_index];//static ram
+
+ log_info("update_request:-%d-%d-%d-%d-\n", param->interval_min, param->interval_max, param->latency, param->timeout);
+ if (con_handle) {
+ ble_user_cmd_prepare(BLE_CMD_REQ_CONN_PARAM_UPDATE, 2, con_handle, param);
+ }
+}
+
+static void check_connetion_updata_deal(void)
+{
+ if (connection_update_enable) {
+ if (connection_update_cnt < CONN_PARAM_TABLE_CNT) {
+ send_request_connect_parameter(connection_update_cnt);
+ }
+ }
+}
+
+
+static void send_request_connect_parameter_ota(u8 table_index)
+{
+ struct conn_update_param_t *param = (void *)&connection_param_table_ota[table_index];//static ram
+
+ log_info("update_request:-%d-%d-%d-%d-\n", param->interval_min, param->interval_max, param->latency, param->timeout);
+ if (con_handle) {
+ ble_user_cmd_prepare(BLE_CMD_REQ_CONN_PARAM_UPDATE, 2, con_handle, param);
+ }
+}
+
+static void check_connetion_updata_deal_ota(void)
+{
+ if (connection_update_enable) {
+ if (connection_update_cnt < CONN_PARAM_TABLE_CNT) {
+ send_request_connect_parameter_ota(connection_update_cnt);
+ }
+ }
+}
+
+
+static void connection_update_complete_success(u8 *packet)
+{
+ int con_handle, conn_interval, conn_latency, conn_timeout;
+
+ con_handle = hci_subevent_le_connection_update_complete_get_connection_handle(packet);
+ conn_interval = hci_subevent_le_connection_update_complete_get_conn_interval(packet);
+ conn_latency = hci_subevent_le_connection_update_complete_get_conn_latency(packet);
+ conn_timeout = hci_subevent_le_connection_update_complete_get_supervision_timeout(packet);
+
+ log_info("conn_interval = %d\n", conn_interval);
+ log_info("conn_latency = %d\n", conn_latency);
+ log_info("conn_timeout = %d\n", conn_timeout);
+}
+
+
+static void set_ble_work_state(ble_state_e state)
+{
+ if (state != ble_work_state) {
+ log_info("ble_work_st:%x->%x\n", ble_work_state, state);
+ ble_work_state = state;
+ if (app_ble_state_callback) {
+ app_ble_state_callback((void *)channel_priv, state);
+ }
+ }
+}
+
+static ble_state_e get_ble_work_state(void)
+{
+ return ble_work_state;
+}
+
+static void cbk_sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
+{
+ sm_just_event_t *event = (void *)packet;
+ u32 tmp32;
+ switch (packet_type) {
+ case HCI_EVENT_PACKET:
+ switch (hci_event_packet_get_type(packet)) {
+ case SM_EVENT_JUST_WORKS_REQUEST:
+ sm_just_works_confirm(sm_event_just_works_request_get_handle(packet));
+ log_info("Just Works Confirmed.\n");
+ break;
+ case SM_EVENT_PASSKEY_DISPLAY_NUMBER:
+ log_info_hexdump(packet, size);
+ memcpy(&tmp32, event->data, 4);
+ log_info("Passkey display: %06u.\n", tmp32);
+ break;
+ }
+ break;
+ }
+}
+
+static void can_send_now_wakeup(void)
+{
+ putchar('E');
+ if (ble_resume_send_wakeup) {
+ ble_resume_send_wakeup();
+ }
+}
+
+_WEAK_
+u8 ble_update_get_ready_jump_flag(void)
+{
+ return 0;
+}
+
+/*
+ * @section Packet Handler
+ *
+ * @text The packet handler is used to:
+ * - stop the counter after a disconnect
+ * - send a notification when the requested ATT_EVENT_CAN_SEND_NOW is received
+ */
+
+
+static int ble_disconnect(void *priv);
+/* LISTING_START(packetHandler): Packet Handler */
+static void cbk_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
+{
+ int mtu;
+ u32 tmp;
+
+ switch (packet_type) {
+ case HCI_EVENT_PACKET:
+ switch (hci_event_packet_get_type(packet)) {
+
+ /* case DAEMON_EVENT_HCI_PACKET_SENT: */
+ /* break; */
+ case ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE:
+ log_info("ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE\n");
+ case ATT_EVENT_CAN_SEND_NOW:
+ can_send_now_wakeup();
+ break;
+
+ case HCI_EVENT_LE_META:
+ switch (hci_event_le_meta_get_subevent_code(packet)) {
+ case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: {
+// set_app_connect_type(TYPE_BLE);
+ con_handle = little_endian_read_16(packet, 4);
+ log_info("HCI_SUBEVENT_LE_CONNECTION_COMPLETE: %0x\n", con_handle);
+ connection_update_complete_success(packet + 8);
+ ble_user_cmd_prepare(BLE_CMD_ATT_SEND_INIT, 4, con_handle, att_ram_buffer, ATT_RAM_BUFSIZE, ATT_LOCAL_PAYLOAD_SIZE);
+ set_ble_work_state(BLE_ST_CONNECT);
+#if (0 == BT_CONNECTION_VERIFY)
+ JL_rcsp_auth_reset();
+#endif
+
+ rcsp_dev_select(RCSP_BLE);
+ //__this->ble_adv_notify = 1;
+ //att_server_set_exchange_mtu(con_handle);///Jim
+ }
+ break;
+
+ case HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE:
+ connection_update_complete_success(packet);
+ break;
+ }
+ break;
+
+ case HCI_EVENT_DISCONNECTION_COMPLETE:
+ log_info("HCI_EVENT_DISCONNECTION_COMPLETE: %0x\n", packet[5]);
+ con_handle = 0;
+ ble_user_cmd_prepare(BLE_CMD_ATT_SEND_INIT, 4, con_handle, 0, 0, 0);
+ set_ble_work_state(BLE_ST_DISCONN);
+// set_app_connect_type(TYPE_NULL);
+ if (!ble_update_get_ready_jump_flag()) {
+ //extern u8 usr_get_pair_flag();
+ //extern void usr_reconn_adv();
+ if(usr_var.usr_goto_updata==0)
+ {
+ /*if(usr_get_pair_flag())
+ {
+ usr_reconn_adv();
+ }
+ else
+ {
+ bt_ble_adv_enable(1);
+ }*/
+ //extern void usr_ble_adv_init();
+ usr_ble_adv_init();
+ }
+ }
+ connection_update_cnt = 0;
+ break;
+
+ case ATT_EVENT_MTU_EXCHANGE_COMPLETE:
+ mtu = att_event_mtu_exchange_complete_get_MTU(packet) - 3;
+ log_info("ATT MTU = %u\n", mtu);
+ ble_user_cmd_prepare(BLE_CMD_ATT_MTU_SIZE, 1, mtu);
+ break;
+
+ case HCI_EVENT_VENDOR_REMOTE_TEST:
+ log_info("--- HCI_EVENT_VENDOR_REMOTE_TEST\n");
+ break;
+
+ case L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE:
+ tmp = little_endian_read_16(packet, 4);
+ log_info("-update_rsp: %02x\n", tmp);
+ if (tmp) {
+ connection_update_cnt++;
+ log_info("remoter reject!!!\n");
+ check_connetion_updata_deal();
+ } else {
+ connection_update_cnt = CONN_PARAM_TABLE_CNT;
+ }
+ break;
+
+ case HCI_EVENT_ENCRYPTION_CHANGE:
+ log_info("HCI_EVENT_ENCRYPTION_CHANGE= %d\n", packet[2]);
+ break;
+ }
+ break;
+ }
+}
+
+
+/* LISTING_END */
+
+/*
+ * @section ATT Read
+ *
+ * @text The ATT Server handles all reads to constant data. For dynamic data like the custom characteristic, the registered
+ * att_read_callback is called. To handle long characteristics and long reads, the att_read_callback is first called
+ * with buffer == NULL, to request the total value length. Then it will be called again requesting a chunk of the value.
+ * See Listing attRead.
+ */
+
+
+static uint16_t att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset, uint8_t *buffer, uint16_t buffer_size)
+{
+
+ uint16_t att_value_len = 0;
+ uint16_t handle = att_handle;
+
+ /* printf("READ Callback, handle %04x, offset %u, buffer size %u\n", handle, offset, buffer_size); */
+
+ log_info("read_callback, handle= 0x%04x,buffer= %08x\n", handle, (u32)buffer);
+
+ switch (handle) {
+ case ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE:
+ att_value_len = strlen(gap_device_name);
+
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+
+ if (buffer) {
+ memcpy(buffer, &gap_device_name[offset], buffer_size);
+ att_value_len = buffer_size;
+ log_info("\n------read gap_name: %s \n", gap_device_name);
+ }
+ break;
+#if 1//RCSP_BTMATE_EN
+ case ATT_CHARACTERISTIC_ae02_02_CLIENT_CONFIGURATION_HANDLE:
+#endif // RCSP_BTMATE_EN
+ case ATT_CHARACTERISTIC_15f1e601_a277_43fc_a484_dd39ef8a9100_01_CLIENT_CONFIGURATION_HANDLE:
+ if (buffer) {
+ buffer[0] = att_get_ccc_config(handle);
+ buffer[1] = 0;
+
+ }
+ att_value_len = 2;
+ break;
+ case ATT_CHARACTERISTIC_15f1e601_a277_43fc_a484_dd39ef8a9100_01_VALUE_HANDLE:
+ log_info("ATT_CHARACTERISTIC_15f1e601_a277_43fc_a484_dd39ef8a9100_01_VALUE_HANDLE\n");
+ att_value_len = gap_device_name_len;
+
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+
+ if (buffer) {
+ memcpy(buffer, &gap_device_name[offset], buffer_size);
+ att_value_len = buffer_size;
+ log_info("\n------read gap_name: %s \n", gap_device_name);
+ }
+ break;
+ default:
+ break;
+ }
+
+ log_info("att_value_len= %d\n", att_value_len);
+ return att_value_len;
+
+}
+
+/* LISTING_END */
+/*
+ * @section ATT Write
+ *
+ * @text The only valid ATT write in this example is to the Client Characteristic Configuration, which configures notification
+ * and indication. If the ATT handle matches the client configuration handle, the new configuration value is stored and used
+ * in the heartbeat handler to decide if a new value should be sent. See Listing attWrite.
+ */
+
+/* LISTING_START(attWrite): ATT Write */
+static int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size)
+{
+ int result = 0;
+ u16 tmp16;
+
+ u16 handle = att_handle;
+
+ /* log_info("write_callback, handle= 0x%04x\n", handle); */
+
+ switch (handle) {
+
+ case ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE:
+ tmp16 = BT_NAME_LEN_MAX;
+ if ((offset >= tmp16) || (offset + buffer_size) > tmp16) {
+ break;
+ }
+
+ if (offset == 0) {
+ memset(gap_device_name, 0x00, BT_NAME_LEN_MAX);
+ }
+ memcpy(&gap_device_name[offset], buffer, buffer_size);
+ log_info("\n------write gap_name:");
+ break;
+
+#if 1//RCSP_BTMATE_EN
+ case ATT_CHARACTERISTIC_ae02_02_CLIENT_CONFIGURATION_HANDLE:
+ set_ble_work_state(BLE_ST_NOTIFY_IDICATE);
+ check_connetion_updata_deal_ota();
+ //sys_timeout_add(NULL,check_connetion_updata_deal,1500);
+ log_info("\n------write ccc:%04x, %02x\n", handle, buffer[0]);
+ att_set_ccc_config(handle, buffer[0]);
+ can_send_now_wakeup();
+ break;
+#endif // RCSP_BTMATE_EN
+ case ATT_CHARACTERISTIC_15f1e601_a277_43fc_a484_dd39ef8a9100_01_CLIENT_CONFIGURATION_HANDLE:
+ set_ble_work_state(BLE_ST_NOTIFY_IDICATE);
+ // check_connetion_updata_deal();
+ sys_timeout_add(NULL,check_connetion_updata_deal,1500);
+ log_info("\n------write ccc:%04x, %02x\n", handle, buffer[0]);
+ att_set_ccc_config(handle, buffer[0]);
+ can_send_now_wakeup();
+ break;
+ case ATT_CHARACTERISTIC_15f1e602_a277_43fc_a484_dd39ef8a9100_01_VALUE_HANDLE:
+// log_info("rec data len :%d",buffer_size);
+ //printf_buf(buffer,buffer_size);
+ usr_le_data_recieve(buffer,buffer_size);
+ break;
+
+
+#if 1//RCSP_BTMATE_EN
+ case ATT_CHARACTERISTIC_ae01_02_VALUE_HANDLE:
+ printf("rcsp_read:%x\n", buffer_size);
+ if (app_recieve_callback) {
+ app_recieve_callback(0, buffer, buffer_size);
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+
+void usr_ble_send_data(u8* data,u16 len)
+{
+ /* CCC 未写时 ATT 发数会失败(常见 app_send_fail:-93),等主机使能通知再发 */
+ if (get_ble_work_state() != BLE_ST_NOTIFY_IDICATE) {
+ log_info("ble send skip, wait CCC");
+ return;
+ }
+ if (app_send_user_data_check(len))
+ {
+ app_send_user_data(ATT_CHARACTERISTIC_15f1e601_a277_43fc_a484_dd39ef8a9100_01_VALUE_HANDLE, data, len, ATT_OP_AUTO_READ_CCC);
+ }
+}
+static int app_send_user_data(u16 handle, u8 *data, u16 len, u8 handle_type)
+{
+ u32 ret = APP_BLE_NO_ERROR;
+
+ if (!con_handle) {
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+ ret = ble_user_cmd_prepare(BLE_CMD_ATT_SEND_DATA, 4, handle, data, len, handle_type);
+ if (ret == BLE_BUFFER_FULL) {
+ ret = APP_BLE_BUFF_FULL;
+ }
+
+ if (ret) {
+ log_info("app_send_fail:%d !!!!!!\n", ret);
+ }
+ return ret;
+}
+
+
+//------------------------------------------------------
+extern void swapX(const uint8_t *src, uint8_t *dst, int len);
+extern const u8 *bt_get_mac_addr();
+
+//------------------------------------------------------
+
+static void rcsp_adv_fill_mac_addr(u8 *mac_addr_buf)
+{
+ swapX(bt_get_mac_addr(), mac_addr_buf, 6);
+}
+
+extern u8 get_defalut_bt_channel_sel(void);
+extern JL_AES_BASE_BT;
+JL_AES_BASE_BT = JL_AES; // add for btcon_hash, by lingxuanfeng, 20220517
+static int make_set_adv_data(void)
+{
+ u8 offset = 0;
+ u8 *buf = muti_adv_data;
+
+
+
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x06, 1);
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_16BIT_SERVICE_UUIDS, 0xAF30, 2);
+
+#if 1//RCSP_BTMATE_EN
+ u8 tag_len = sizeof(user_tag_string);
+ if (tag_len > ADV_RSP_PACKET_MAX - (offset + 2)) {
+ //tag_in_adv = 0;
+ } else {
+ //offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_MANUFACTURER_SPECIFIC_DATA, (void *)user_tag_string, tag_len);
+ //tag_in_adv = 1;
+ }
+#endif
+
+ if (offset > ADV_RSP_PACKET_MAX) {
+ puts("***muti_adv_data overflow!!!!!!\n");
+ return -1;
+ }
+ log_info("muti_adv_data(%d):", offset);
+ log_info_hexdump(buf, offset);
+ muti_adv_data_len = offset;
+ ble_op_set_adv_data(offset, buf);
+ return 0;
+}
+
+static int make_set_rsp_data(void)
+{
+ u8 offset = 0;
+ u8 *buf = scan_rsp_data;
+
+#if 1//RCSP_BTMATE_EN
+ if (1) {
+ u8 tag_len = sizeof(user_tag_string);
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_MANUFACTURER_SPECIFIC_DATA, (void *)user_tag_string, tag_len);
+ }
+#endif
+
+ u8 name_len = gap_device_name_len;
+ u8 vaild_len = ADV_RSP_PACKET_MAX - (offset + 2);
+ if (name_len > vaild_len) {
+ name_len = vaild_len;
+ }
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, (void *)gap_device_name, name_len);
+
+ if (offset > ADV_RSP_PACKET_MAX) {
+ puts("***rsp_data overflow!!!!!!\n");
+ return -1;
+ }
+
+ log_info("rsp_data(%d):", offset);
+ log_info_hexdump(buf, offset);
+ scan_rsp_data_len = offset;
+ ble_op_set_rsp_data(offset, buf);
+ return 0;
+}
+
+int muti_make_set_adv_data(u8* data,u8 data_len)
+{
+#if 0
+ u8 offset = 0;
+ u8 *buf = muti_adv_data;
+
+ u8 name_len = gap_device_name_len;
+ u8 vaild_len = ADV_RSP_PACKET_MAX - (offset + 2);
+ if (name_len > vaild_len) {
+ name_len = vaild_len;
+ }
+ /* offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x18, 1); */
+ /* offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x1A, 1); */
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x06, 1);
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_16BIT_SERVICE_UUIDS, 0xAF30, 2);
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, (void *)gap_device_name, name_len);
+
+ if (offset > ADV_RSP_PACKET_MAX) {
+ puts("***muti_adv_data overflow!!!!!!\n");
+ return -1;
+ }
+ log_info("muti_adv_data(%d):", offset);
+ log_info_hexdump(buf, offset);
+ muti_adv_data_len = offset;
+ ble_op_set_adv_data(offset, buf);
+#endif // 0
+
+
+
+ ble_op_set_adv_data(data_len, data);
+
+
+ return 0;
+}
+//------------------------------------------------------
+int muti_make_set_adv_data_updata()
+{
+#if 1
+ u8 offset = 0;
+ u8 *buf = muti_adv_data;
+
+ u8 name_len = gap_device_name_len;
+ u8 vaild_len = ADV_RSP_PACKET_MAX - (offset + 2);
+ if (name_len > vaild_len) {
+ name_len = vaild_len;
+ }
+ /* offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x18, 1); */
+ /* offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x1A, 1); */
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x06, 1);
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_16BIT_SERVICE_UUIDS, 0xAE00, 2);
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, (void *)gap_device_name, name_len);
+
+ if (offset > ADV_RSP_PACKET_MAX) {
+ puts("***muti_adv_data overflow!!!!!!\n");
+ return -1;
+ }
+ log_info("muti_adv_data(%d):", offset);
+ log_info_hexdump(buf, offset);
+ muti_adv_data_len = offset;
+ ble_op_set_adv_data(offset, buf);
+#endif // 0
+
+
+ return 0;
+}
+static int update_adv_data(u8 *buf)
+{
+
+ return 0;
+}
+
+u8 *ble_get_scan_rsp_ptr(u16 *len)
+{
+ if (len) {
+ *len = scan_rsp_data_len;
+ }
+ return scan_rsp_data;
+}
+
+u8 *ble_get_adv_data_ptr(u16 *len)
+{
+ if (len) {
+ *len = muti_adv_data_len;
+ }
+ return muti_adv_data;
+}
+
+u8 *ble_get_gatt_profile_data(u16 *len)
+{
+ *len = sizeof(profile_data);
+ return (u8 *)profile_data;
+}
+
+//广播参数设置
+
+void usr_set_adv_interval(u16 val)
+{
+ usr_var.usr_adv_interval=val;
+}
+u16 usr_get_adv_interval()
+{
+ return usr_var.usr_adv_interval;
+}
+static void advertisements_setup_init()///Jim
+{
+ uint8_t adv_type = 0;
+ uint8_t adv_channel = 7;
+ int ret = 0;
+ u16 adv_interval = usr_var.usr_adv_interval;//ADV_INTERVAL_MIN;
+
+ ble_user_cmd_prepare(BLE_CMD_ADV_PARAM, 3, adv_interval, adv_type, adv_channel);
+
+ //ret |= make_set_adv_data();
+ //ret |= make_set_rsp_data();
+
+ if (ret) {
+ puts("advertisements_setup_init fail !!!!!!\n");
+ return;
+ }
+
+}
+
+
+void ble_sm_setup_init(io_capability_t io_type, u8 auth_req, uint8_t min_key_size, u8 security_en)
+{
+ //setup SM: Display only
+ sm_init();
+ sm_set_io_capabilities(io_type);
+ sm_set_authentication_requirements(auth_req);
+ sm_set_encryption_key_size_range(min_key_size, 16);
+ sm_set_request_security(0);
+ sm_event_callback_set(&cbk_sm_packet_handler);
+}
+
+
+#define RCSP_ADV_TCFG_BLE_SECURITY_EN 0/*是否发请求加密命令*/
+extern void le_device_db_init(void);
+void ble_profile_init(void)
+{
+ printf("ble profile init\n");
+ le_device_db_init();
+ ble_sm_setup_init(IO_CAPABILITY_NO_INPUT_NO_OUTPUT, SM_AUTHREQ_MITM_PROTECTION | SM_AUTHREQ_BONDING, 7, RCSP_ADV_TCFG_BLE_SECURITY_EN);
+ /* setup ATT server */
+ att_server_init(profile_data, att_read_callback, att_write_callback);
+ att_server_register_packet_handler(cbk_packet_handler);
+ /* gatt_client_register_packet_handler(packet_cbk); */
+
+ // register for HCI events
+ hci_event_callback_set(&cbk_packet_handler);
+ /* ble_l2cap_register_packet_handler(packet_cbk); */
+ /* sm_event_packet_handler_register(packet_cbk); */
+ le_l2cap_register_packet_handler(&cbk_packet_handler);
+}
+
+
+static int set_adv_enable(void *priv, u32 en)
+{
+ ble_state_e next_state, cur_state;
+
+ if (!adv_ctrl_en && en) {
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+ printf("con_handle %d\n", con_handle);
+ if (con_handle) {
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+ if (en) {
+ next_state = BLE_ST_ADV;
+ } else {
+ next_state = BLE_ST_IDLE;
+ }
+
+ cur_state = get_ble_work_state();
+ printf("get_ble_work_state %d\n", cur_state);
+ switch (cur_state) {
+ case BLE_ST_ADV:
+ case BLE_ST_IDLE:
+ case BLE_ST_INIT_OK:
+ case BLE_ST_NULL:
+ case BLE_ST_DISCONN:
+ break;
+ default:
+ return APP_BLE_OPERATION_ERROR;
+ break;
+ }
+
+ if (cur_state == next_state) {
+ printf("cur_state == next_state \n");
+ return APP_BLE_NO_ERROR;
+ }
+ log_info("adv_en:%d\n", en);
+ set_ble_work_state(next_state);
+ if (en) {
+ advertisements_setup_init();
+ }
+ ble_user_cmd_prepare(BLE_CMD_ADV_ENABLE, 1, en);
+ printf("> set_adv_enable %d\n", en);
+ return APP_BLE_NO_ERROR;
+}
+
+static int ble_disconnect(void *priv)
+{
+ if (con_handle) {
+ if (BLE_ST_SEND_DISCONN != get_ble_work_state()) {
+ log_info(">>>ble send disconnect\n");
+ set_ble_work_state(BLE_ST_SEND_DISCONN);
+ ble_user_cmd_prepare(BLE_CMD_DISCONNECT, 1, con_handle);
+ } else {
+ log_info(">>>ble wait disconnect...\n");
+ }
+ return APP_BLE_NO_ERROR;
+ } else {
+ return APP_BLE_OPERATION_ERROR;
+ }
+}
+
+
+static int get_buffer_vaild_len(void *priv)
+{
+ u32 vaild_len = 0;
+ ble_user_cmd_prepare(BLE_CMD_ATT_VAILD_LEN, 1, &vaild_len);
+ return vaild_len;
+}
+
+static int app_send_user_data_do(void *priv, u8 *data, u16 len)
+{
+ return app_send_user_data(ATT_CHARACTERISTIC_ae02_02_VALUE_HANDLE, data, len, ATT_OP_AUTO_READ_CCC);
+}
+
+static int app_send_user_data_check(u16 len)
+{
+ u32 buf_space = get_buffer_vaild_len(0);
+ if (len <= buf_space) {
+ return 1;
+ }
+ return 0;
+}
+
+static int regiest_wakeup_send(void *priv, void *cbk)
+{
+ ble_resume_send_wakeup = cbk;
+ return APP_BLE_NO_ERROR;
+}
+
+static int regiest_recieve_cbk(void *priv, void *cbk)
+{
+ channel_priv = (u32)priv;
+ app_recieve_callback = cbk;
+ return APP_BLE_NO_ERROR;
+}
+
+static int regiest_state_cbk(void *priv, void *cbk)
+{
+ channel_priv = (u32)priv;
+ app_ble_state_callback = cbk;
+ return APP_BLE_NO_ERROR;
+}
+
+void bt_ble_adv_enable(u8 enable)
+{
+ set_adv_enable(0, enable);
+}
+
+
+void bt_ble_rcsp_adv_disable(void)
+{
+ ble_app_disconnect();
+ set_adv_enable(0, 0);
+}
+
+
+void ble_module_enable(u8 en)
+{
+ log_info("mode_en:%d\n", en);
+ if (en) {
+ adv_ctrl_en = 1;
+ bt_ble_adv_enable(1);
+
+ } else {
+ if (con_handle) {
+ adv_ctrl_en = 0;
+ ble_disconnect(NULL);
+ } else {
+ bt_ble_adv_enable(0);
+ adv_ctrl_en = 0;
+ }
+ }
+}
+void ble_trans_module_enable(u8 flag)
+{
+ ble_module_enable(flag);
+}
+
+void bt_ble_init(void)
+{
+ log_info("***** ble_init******\n");
+
+ gap_device_name = bt_get_local_name();
+ gap_device_name_len = strlen(gap_device_name);
+ if (gap_device_name_len > BT_NAME_LEN_MAX) {
+ gap_device_name_len = BT_NAME_LEN_MAX;
+ }
+
+ log_info("ble name(%d): %s \n", gap_device_name_len, gap_device_name);
+
+ set_ble_work_state(BLE_ST_INIT_OK);
+ //bt_ble_init_do();
+
+ //bt_ble_rcsp_adv_enable();
+ ble_module_enable(0);
+ usr_ble_adv_init();
+}
+
+void bt_ble_exit(void)
+{
+ log_info("***** ble_exit******\n");
+ ble_module_enable(0);
+}
+
+u16 usr_get_conn_service()
+{
+ return con_handle;
+}
+
+/**
+ * @brief 主机是否已写 CCC,允许 GATT notify/indicate
+ * @return 1=可发数(BLE_ST_NOTIFY_IDICATE),0=还不行
+ */
+u8 usr_ble_is_notify_ready(void)
+{
+ return (get_ble_work_state() == BLE_ST_NOTIFY_IDICATE) ? 1 : 0;
+}
+
+void ble_app_disconnect(void)
+{
+ ble_disconnect(NULL);
+}
+
+void ble_multi_trans_disconnect()
+{
+ ble_app_disconnect();
+}
+
+static const struct ble_server_operation_t mi_ble_operation = {
+ .adv_enable = set_adv_enable,
+ .disconnect = ble_disconnect,
+ .get_buffer_vaild = get_buffer_vaild_len,
+ .send_data = (void *)app_send_user_data_do,
+ .regist_wakeup_send = regiest_wakeup_send,
+ .regist_recieve_cbk = regiest_recieve_cbk,
+ .regist_state_cbk = regiest_state_cbk,
+};
+
+
+void ble_get_server_operation_table(struct ble_server_operation_t **interface_pt)
+{
+ *interface_pt = (void *)&mi_ble_operation;
+}
+
+
+
+
+
+
+
+
+void ble_server_send_test_key_num(u8 key_num)
+{
+
+}
+
+bool ble_msg_deal(u32 param)
+{
+ return FALSE;
+}
+
+void input_key_handler(u8 key_status, u8 key_number)
+{
+
+}
+
+void bt_adv_get_bat(u8 *buf)
+{
+
+}
+
+
+static void deal_sibling_adv_state_info_sync(void *data, u16 len, bool rx)
+{
+
+}
+
+static void adv_state_info_sync(void)
+{
+
+}
+
+// type : 0 - 正常关机检查 // 1 - 低电关机检测
+u8 adv_tws_both_in_charge_box(u8 type)
+{
+ return 0;
+}
+
+static void adv_master_to_salve_disconn_ble(void *priv)
+{
+
+}
+
+// 切换后触发
+void adv_role_switch_handle(void)
+{
+ u8 adv_cmd = 0;
+}
+
+void send_version_to_sibling(void)
+{
+
+}
+
+
+// 同步seq到对端
+static void deal_sibling_seq_rand_sync(void *data, u16 len, bool rx)
+{
+
+}
+
+void adv_seq_vaule_sync(void)
+{
+
+}
+void bt_adv_seq_change(void)
+{
+
+}
+
+u8 get_ble_adv_modify(void)
+{
+ return 0;
+}
+
+u8 get_ble_adv_notify(void)
+{
+ return 0;
+}
+
+void set_ble_adv_notify(u8 en)
+{
+
+}
+
+u8 get_connect_flag(void)
+{
+ return 0;
+}
+
+void set_connect_flag(u8 value)
+{
+
+}
+static u8 update_dev_battery_level(void)
+{
+ return 0;
+}
+
+
+static u8 update_dev_connect_flag(void)
+{
+ return 0;
+ /*printf("adv modify!!!!!!\n");
+ bt_ble_adv_enable(0);
+ make_set_adv_data();
+ make_set_rsp_data();
+ bt_ble_adv_enable(1);*/
+}
+
+void bt_ble_rcsp_adv_enable(void)
+{
+ //ble_timer_handle = sys_timer_add(NULL, bt_ble_rcsp_adv_enable_do, BLE_TIMER_SET);
+}
+
+
+int bt_ble_adv_ioctl(u32 cmd, u32 priv, u8 mode)
+{
+ return 0;
+}
+
+
+#endif
+
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/bt_trans_data/le_rcsp_adv_module.h b/apps/common/third_party_profile/jieli/JL_rcsp/bt_trans_data/le_rcsp_adv_module.h
new file mode 100644
index 0000000..0a3c1e0
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/bt_trans_data/le_rcsp_adv_module.h
@@ -0,0 +1,204 @@
+// binary representation
+// attribute size in bytes (16), flags(16), handle (16), uuid (16/128), value(...)
+
+#ifndef _LE_SERVER_MODULE_H
+#define _LE_SERVER_MODULE_H
+
+#include
+#include "bt_common.h"
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV_RCSP)
+//
+// gatt profile include file, generated by jieli gatt_inc_generator.exe
+//
+///Jim
+static const uint8_t profile_data[] = {
+ //////////////////////////////////////////////////////
+ //
+ // 0x0001 PRIMARY_SERVICE 1800
+ //
+ //////////////////////////////////////////////////////
+ 0x0a, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x28, 0x00, 0x18,
+
+ /* CHARACTERISTIC, 2a00, READ | WRITE | DYNAMIC, */
+ // 0x0002 CHARACTERISTIC 2a00 READ | WRITE | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x28, 0x0a, 0x03, 0x00, 0x00, 0x2a,
+ // 0x0003 VALUE 2a00 READ | WRITE | DYNAMIC
+ 0x08, 0x00, 0x0a, 0x01, 0x03, 0x00, 0x00, 0x2a,
+
+ //////////////////////////////////////////////////////
+ //
+ // 0x0004 PRIMARY_SERVICE 15f1e600-a277-43fc-a484-dd39ef8a9100
+ //
+ //////////////////////////////////////////////////////
+ 0x18, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x28, 0x00, 0x91, 0x8a, 0xef, 0x39, 0xdd, 0x84, 0xa4, 0xfc, 0x43, 0x77, 0xa2, 0x00, 0xe6, 0xf1, 0x15,
+
+ /* CHARACTERISTIC, 15f1e601-a277-43fc-a484-dd39ef8a9100, READ |INDICATE| DYNAMIC, */
+ // 0x0005 CHARACTERISTIC 15f1e601-a277-43fc-a484-dd39ef8a9100 READ |INDICATE| DYNAMIC
+ 0x1b, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x28, 0x22, 0x06, 0x00, 0x00, 0x91, 0x8a, 0xef, 0x39, 0xdd, 0x84, 0xa4, 0xfc, 0x43, 0x77, 0xa2, 0x01, 0xe6, 0xf1, 0x15,
+ // 0x0006 VALUE 15f1e601-a277-43fc-a484-dd39ef8a9100 READ |INDICATE| DYNAMIC
+ 0x16, 0x00, 0x22, 0x03, 0x06, 0x00, 0x00, 0x91, 0x8a, 0xef, 0x39, 0xdd, 0x84, 0xa4, 0xfc, 0x43, 0x77, 0xa2, 0x01, 0xe6, 0xf1, 0x15,
+ // 0x0007 CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x07, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+ /* CHARACTERISTIC, 15f1e602-a277-43fc-a484-dd39ef8a9100, WRITE|WRITE_WITHOUT_RESPONSE|DYNAMIC, */
+ // 0x0008 CHARACTERISTIC 15f1e602-a277-43fc-a484-dd39ef8a9100 WRITE|WRITE_WITHOUT_RESPONSE|DYNAMIC
+ 0x1b, 0x00, 0x02, 0x00, 0x08, 0x00, 0x03, 0x28, 0x0c, 0x09, 0x00, 0x00, 0x91, 0x8a, 0xef, 0x39, 0xdd, 0x84, 0xa4, 0xfc, 0x43, 0x77, 0xa2, 0x02, 0xe6, 0xf1, 0x15,
+ // 0x0009 VALUE 15f1e602-a277-43fc-a484-dd39ef8a9100 WRITE|WRITE_WITHOUT_RESPONSE|DYNAMIC
+ 0x16, 0x00, 0x0c, 0x03, 0x09, 0x00, 0x00, 0x91, 0x8a, 0xef, 0x39, 0xdd, 0x84, 0xa4, 0xfc, 0x43, 0x77, 0xa2, 0x02, 0xe6, 0xf1, 0x15,
+
+#if 1//RCSP_BTMATE_EN
+ //////////////////////////////////////////////////////
+ //
+ // 0x0080 PRIMARY_SERVICE ae00
+ //
+ //////////////////////////////////////////////////////
+ 0x0a, 0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x28, 0x00, 0xae,
+
+ /* CHARACTERISTIC, ae01, WRITE_WITHOUT_RESPONSE | DYNAMIC, */
+ // 0x0081 CHARACTERISTIC ae01 WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x81, 0x00, 0x03, 0x28, 0x04, 0x82, 0x00, 0x01, 0xae,
+ // 0x0082 VALUE ae01 WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x08, 0x00, 0x04, 0x01, 0x82, 0x00, 0x01, 0xae,
+
+ /* CHARACTERISTIC, ae02, NOTIFY, */
+ // 0x0083 CHARACTERISTIC ae02 NOTIFY
+ 0x0d, 0x00, 0x02, 0x00, 0x83, 0x00, 0x03, 0x28, 0x10, 0x84, 0x00, 0x02, 0xae,
+ // 0x0084 VALUE ae02 NOTIFY
+ 0x08, 0x00, 0x10, 0x00, 0x84, 0x00, 0x02, 0xae,
+ // 0x0085 CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x85, 0x00, 0x02, 0x29, 0x00, 0x00,
+#endif // RCSP_BTMATE_EN
+ // END
+ 0x00, 0x00,
+
+
+};
+//
+// characteristics <--> handles
+//
+#if 1//RCSP_BTMATE_EN
+#define ATT_CHARACTERISTIC_ae01_02_VALUE_HANDLE 0x0082
+#define ATT_CHARACTERISTIC_ae02_02_VALUE_HANDLE 0x0084
+#define ATT_CHARACTERISTIC_ae02_02_CLIENT_CONFIGURATION_HANDLE 0x0085
+#endif
+
+#define ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE 0x0003
+#define ATT_CHARACTERISTIC_15f1e601_a277_43fc_a484_dd39ef8a9100_01_VALUE_HANDLE 0x0006
+#define ATT_CHARACTERISTIC_15f1e601_a277_43fc_a484_dd39ef8a9100_01_CLIENT_CONFIGURATION_HANDLE 0x0007
+#define ATT_CHARACTERISTIC_15f1e602_a277_43fc_a484_dd39ef8a9100_01_VALUE_HANDLE 0x0009
+
+
+
+
+#define JL_OPCODE_SET_ADV 0xC0
+#define JL_OPCODE_GET_ADV 0xC1
+#define JL_OPCODE_ADV_DEVICE_NOTIFY 0xC2
+#define JL_OPCODE_ADV_NOTIFY_SETTING 0xC3
+#define JL_OPCODE_ADV_DEVICE_REQUEST 0xC4
+
+#define ATTR_TYPE_BAT_VALUE (0)
+#define ATTR_TYPE_EDR_NAME (1)
+#define ATTR_TYPE_KEY_SETTING (2)
+#define ATTR_TYPE_LED_SETTING (3)
+#define ATTR_TYPE_MIC_SETTING (4)
+#define ATTR_TYPE_WORK_MODE (5)
+#define ATTR_TYPE_PRODUCT_MESSAGE (6)
+#define ATTR_TYPE_TIME_STAMP (7)
+#define ATTR_TYPE_EQ_SETTING (8)
+#define ATTR_TYPE_HIGH_LOW_VOL (9)
+#define ATTR_TYPE_ANC_VOICE_KEY (10)
+#define ATTR_TYPE_ANC_VOICE (11)
+#define ATTR_TYPE_ASSISTED_HEARING (12)
+
+//rcsp功能模块使能
+#define RCSP_ADV_NAME_SET_ENABLE 1
+#define RCSP_ADV_KEY_SET_ENABLE 1
+#define RCSP_ADV_LED_SET_ENABLE 1
+#define RCSP_ADV_MIC_SET_ENABLE 1
+#define RCSP_ADV_WORK_SET_ENABLE 1
+
+#if (JL_EARPHONE_APP_EN)
+#define RCSP_ADV_EQ_SET_ENABLE 1
+#define RCSP_ADV_MUSIC_INFO_ENABLE 1
+#define RCSP_ADV_HIGH_LOW_SET 1
+#define RCSP_ADV_FIND_DEVICE_ENABLE 1
+#define RCSP_ADV_AI_NO_PICK 0 // 智能免摘
+#define RCSP_ADV_ASSISTED_HEARING 0 // 辅听,注意开启辅听后,需要关闭ANC相关功能
+
+#if !RCSP_ADV_ASSISTED_HEARING
+#define RCSP_ADV_ANC_VOICE 0 // 主动降噪
+
+#if RCSP_ADV_ANC_VOICE
+#define RCSP_ADV_ADAPTIVE_NOISE_REDUCTION 1 // 自适应降噪
+#define RCSP_ADV_SCENE_NOISE_REDUCTION 1 // 场景降噪
+#define RCSP_ADV_WIND_NOISE_DETECTION 1 // 风噪检测
+#define RCSP_ADV_VOICE_ENHANCEMENT_MODE 1 // 人声增强模式
+#endif
+
+#endif
+
+#else
+#define RCSP_ADV_EQ_SET_ENABLE 0
+#define RCSP_ADV_MUSIC_INFO_ENABLE 0
+#define RCSP_ADV_HIGH_LOW_SET 0
+#define RCSP_ADV_FIND_DEVICE_ENABLE 0
+#define RCSP_ADV_ASSISTED_HEARING 0 // 辅听,注意开启辅听后,需要关闭ANC相关功能
+#define RCSP_ADV_ANC_VOICE 0 // 主动降噪
+#define RCSP_ADV_ADAPTIVE_NOISE_REDUCTION 0 // 自适应降噪
+#define RCSP_ADV_AI_NO_PICK 0 // 智能免摘
+#define RCSP_ADV_SCENE_NOISE_REDUCTION 0 // 场景降噪
+#define RCSP_ADV_WIND_NOISE_DETECTION 0 // 风噪检测
+#define RCSP_ADV_VOICE_ENHANCEMENT_MODE 0 // 人声增强模式
+#endif
+#define RCSP_ADV_PRODUCT_MSG_ENABLE 1
+
+#if !TCFG_EQ_ENABLE
+#undef RCSP_ADV_EQ_SET_ENABLE
+#define RCSP_ADV_EQ_SET_ENABLE 0
+#endif
+#if !ANC_EAR_ADAPTIVE_EN && JL_EARPHONE_APP_EN
+#undef RCSP_ADV_ADAPTIVE_NOISE_REDUCTION
+#define RCSP_ADV_ADAPTIVE_NOISE_REDUCTION 0 //自适应降噪
+#endif
+
+enum {
+ BT_ADV_ENABLE,
+ BT_ADV_DISABLE,
+ BT_ADV_SET_EDR_CON_FLAG,
+ BT_ADV_SET_BAT_CHARGE_L,
+ BT_ADV_SET_BAT_CHARGE_R,
+ BT_ADV_SET_BAT_CHARGE_C,
+ BT_ADV_SET_BAT_PERCENT_L,
+ BT_ADV_SET_BAT_PERCENT_R,
+ BT_ADV_SET_BAT_PERCENT_C,
+ BT_ADV_SET_NOTIFY_EN,
+};
+
+// BT_ADV_SET_EDR_CON_FLAG
+#define SECNE_DISMISS (0x00)
+#define SECNE_UNCONNECTED (0x01)
+#define SECNE_CONNECTED (0x02)
+#define SECNE_CONNECTING (0x03)
+#define SECNE_CONNECTINLESS (0x04)
+
+#define TWS_FUNC_ID_SEQ_RAND_SYNC (('S' << (3 * 8)) | ('E' << (2 * 8)) | ('Q' << (1 * 8)) | ('\0'))
+
+enum {
+ TWS_ADV_SEQ_CHANGE = 0,
+ TWS_VERSON_INFO,
+ TWS_UPDATE_INFO,
+};
+
+//extern int bt_ble_adv_ioctl(u32 cmd, u32 priv, u8 mode);
+extern void bt_adv_seq_change(void);
+void ble_app_disconnect(void);
+void bt_ble_rcsp_adv_enable(void);
+void bt_ble_rcsp_adv_disable(void);
+u8 get_ble_adv_notify(void);
+void set_ble_adv_notify(u8 en);
+u8 get_connect_flag(void);
+void set_connect_flag(u8 value);
+void ble_module_enable(u8 en);
+
+#endif
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/bt_trans_data/rcsp_adv_spp_user.c b/apps/common/third_party_profile/jieli/JL_rcsp/bt_trans_data/rcsp_adv_spp_user.c
new file mode 100644
index 0000000..2dfcef8
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/bt_trans_data/rcsp_adv_spp_user.c
@@ -0,0 +1,91 @@
+
+#include "app_config.h"
+#include "app_action.h"
+
+#include "system/includes.h"
+#include "spp_user.h"
+#include "string.h"
+#include "circular_buf.h"
+#include "3th_profile_api.h"
+#include "bt_common.h"
+
+
+#if 1
+extern void printf_buf(u8 *buf, u32 len);
+#define log_info printf
+#define log_info_hexdump printf_buf
+#else
+#define log_info(...)
+#define log_info_hexdump(...)
+#endif
+
+/* #define DEBUG_ENABLE */
+/* #include "debug_log.h" */
+
+/* #include "rcsp_spp_user.h" */
+#if 0//(RCSP_ADV_EN)
+
+static struct spp_operation_t *spp_api = NULL;
+static u8 spp_state;
+
+int rcsp_spp_send_data(u8 *data, u16 len)
+{
+ if (spp_api) {
+ return spp_api->send_data(NULL, data, len);
+ }
+ return SPP_USER_ERR_SEND_FAIL;
+}
+
+int rcsp_spp_send_data_check(u16 len)
+{
+ if (spp_api) {
+ if (spp_api->busy_state()) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void rcsp_spp_state_cbk(u8 state)
+{
+ spp_state = state;
+ switch (state) {
+ case SPP_USER_ST_CONNECT:
+ log_info("SPP_USER_ST_CONNECT ~~~\n");
+// set_app_connect_type(TYPE_SPP);
+ break;
+
+ case SPP_USER_ST_DISCONN:
+ log_info("SPP_USER_ST_DISCONN ~~~\n");
+// set_app_connect_type(TYPE_NULL);
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+static void rcsp_spp_send_wakeup(void)
+{
+ putchar('W');
+}
+
+static void rcsp_spp_recieve_cbk(void *priv, u8 *buf, u16 len)
+{
+ log_info("spp_api_rx ~~~\n");
+ log_info_hexdump(buf, len);
+}
+
+void rcsp_spp_init(void)
+{
+ spp_state = 0;
+ spp_get_operation_table(&spp_api);
+ spp_api->regist_recieve_cbk(0, rcsp_spp_recieve_cbk);
+ spp_api->regist_state_cbk(0, rcsp_spp_state_cbk);
+ spp_api->regist_wakeup_send(NULL, rcsp_spp_send_wakeup);
+}
+
+#endif
+
+
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/btcrypt.h b/apps/common/third_party_profile/jieli/JL_rcsp/btcrypt.h
new file mode 100644
index 0000000..33b62f5
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/btcrypt.h
@@ -0,0 +1,42 @@
+#ifndef TOMCRYPT_H_
+#define TOMCRYPT_H_
+// #include
+#include
+
+
+#define HARDWARE_METHOD 0
+
+#ifndef WIN32
+// #include "hw_cpu.h"
+#undef HARDWARE_METHOD
+#define HARDWARE_METHOD 1
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+@param [in] pt[*1] The plaintext
+@param ptlen The length of the plaintext(octets) range: 1~32
+@param [in] key[*1] The key for encrypt
+@param keylen[*1] The length of the key(octets) range: 1~32
+@param [out] mac[*1] output : The Message Authentication Code 16 bytes.
+*/
+extern void btcon_hash(unsigned char *pt, int ptlen, unsigned char *key, int keylen, unsigned char *mac);
+
+#if HARDWARE_METHOD
+extern int yf_aes_start_enc(unsigned char key[16], unsigned char plaintext[16], unsigned char encrypt[16]);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TOMCRYPT_H_ */
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_bluetooth.h b/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_bluetooth.h
new file mode 100644
index 0000000..9b792e4
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_bluetooth.h
@@ -0,0 +1,100 @@
+#ifndef __JL_BLUETOOTH_H__
+#define __JL_BLUETOOTH_H__
+
+#include "typedef.h"
+#include "le_common.h"
+#include "spp_user.h"
+#include "system/event.h"
+#include "rcsp_msg.h"
+#include "ble_user.h"
+#if RCSP_BTMATE_EN
+void rcsp_init();
+void rcsp_dev_select(u8 type);
+void function_change_inform(void);
+
+bool common_msg_deal(u32 param, void *priv);
+bool ble_msg_deal(u32 param);
+bool music_msg_deal(u32 param, void *priv);
+bool linein_msg_deal(u32 param);
+bool rtc_msg_deal(u32 param);
+
+void rcsp_exit(void);
+u8 rcsp_get_asr_status(void);
+u8 get_rcsp_support_new_reconn_flag(void);
+
+// enum {
+// RCSP_BLE,
+// RCSP_SPP,
+// };
+
+
+enum {
+ ANDROID,
+ APPLE_IOS,
+};
+
+struct JL_AI_VAR {
+ ble_state_e JL_ble_status;
+ struct ble_server_operation_t *rcsp_ble;
+ u8 JL_spp_status;
+ struct spp_operation_t *rcsp_spp;
+ volatile u8 speech_state;
+ u32 feature_mask;
+ u8 device_type;
+ u8 phone_platform;
+ void (*start_speech)(void);
+ void (*stop_speech)(void);
+ u8 err_report;
+ volatile u8 file_browse_lock_flag;
+ u32 return_msg;
+ u8 spec_mode;
+ struct __rcsp_user_var *rcsp_user;
+ volatile u8 rcsp_run_flag;
+ u8 ffr_mode;
+ u16 ffr_time;
+ u16 rcsp_timer_hdl;
+ volatile u8 wait_asr_end;
+ u8 new_reconn_flag; //是否支持新的回连方式(进行地址修改)
+};
+
+struct _SPEECH_OVER_DEAL {
+ u8 last_task;
+ u8 status;
+};
+
+extern struct JL_AI_VAR jl_ai_var;
+extern struct _SPEECH_OVER_DEAL speech_deal_val;
+
+enum RCSP_MSG_T {
+ MSG_JL_GET_DEV_UPDATE_FILE_INFO_OFFSET = RCSP_MSG_END,
+ MSG_JL_INQUIRE_DEVEICE_IF_CAN_UPDATE,
+ MSG_JL_LOADER_DOWNLOAD_START,
+ MSG_JL_UPDATE_START,
+ MSG_JL_ENTER_UPDATE_MODE,
+ MSG_JL_DEV_DISCONNECT,
+ MSG_JL_BLE_UPDATE_START,
+ MSG_JL_SPP_UPDATE_START,
+};
+
+bool rcsp_msg_post(RCSP_MSG msg, int argc, ...);
+
+#define SDK_TYPE_AC690X 0x0
+#define SDK_TYPE_AC692X 0x1
+#define SDK_TYPE_AC693X 0x2
+#define SDK_TYPE_AC695X 0x3
+#define SDK_TYPE_AC697X 0x4
+
+#if (defined CONFIG_CPU_BR21)
+#define RCSP_SDK_TYPE SDK_TYPE_AC692X
+#elif (defined CONFIG_CPU_BR22)
+#define RCSP_SDK_TYPE SDK_TYPE_AC693X
+#elif (defined CONFIG_CPU_BR23)
+#define RCSP_SDK_TYPE SDK_TYPE_AC695X
+#elif (defined CONFIG_CPU_BR30)
+#define RCSP_SDK_TYPE SDK_TYPE_AC697X
+#else
+#define RCSP_SDK_TYPE SDK_TYPE_AC693X
+#endif
+#endif
+
+#endif
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_msg.h b/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_msg.h
new file mode 100644
index 0000000..59e1012
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_msg.h
@@ -0,0 +1,13 @@
+#ifndef __RCSP_MSG_H__
+#define __RCSP_MSG_H__
+
+typedef enum __RCSP_MSG {
+ RCSP_MSG_UPDATE_EQ = 0,
+ RCSP_MSG_SET_FMTX_POINT,
+ RCSP_MSG_BS_END,
+ RCSP_MSG_BT_SCAN,
+ RCSP_MSG_END,
+} RCSP_MSG;
+
+#endif//__RCSP_MSG_H__
+
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_adv_user_update.c b/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_adv_user_update.c
new file mode 100644
index 0000000..d0762b7
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_adv_user_update.c
@@ -0,0 +1,574 @@
+#include "app_config.h"
+#include "rcsp_adv_user_update.h"
+#if RCSP_UPDATE_EN
+#include "uart.h"
+#include "system/timer.h"
+#include "update.h"
+#include "custom_cfg.h"
+#include "btstack/avctp_user.h"
+#include "JL_rcsp_packet.h"
+#include "JL_rcsp_protocol.h"
+#include "rcsp_adv_bluetooth.h"
+#include "le_rcsp_adv_module.h"
+#include "update_loader_download.h"
+#include "classic/tws_api.h"
+#include "syscfg_id.h"
+
+#if (RCSP_ADV_EN)
+
+#define RCSP_DEBUG_EN
+
+#ifdef RCSP_DEBUG_EN
+#define rcsp_putchar(x) putchar(x)
+#define rcsp_printf printf
+#define rcsp_printf_buf(x,len) printf_buf(x,len)
+#else
+#define rcsp_putchar(...)
+#define rcsp_printf(...)
+#define rcsp_printf_buf(...)
+#endif
+
+#define DEV_UPDATE_FILE_INFO_OFFEST 0x00//0x40
+#define DEV_UPDATE_FILE_INFO_LEN 0x00//(0x10 + VER_INFO_EXT_COUNT * (VER_INFO_EXT_MAX_LEN + 1))
+
+typedef enum {
+ UPDATA_START = 0x00,
+ UPDATA_REV_DATA,
+ UPDATA_STOP,
+} UPDATA_BIT_FLAG;
+
+#if 0
+static update_file_id_t update_file_id_info = {
+ .ver[0] = 0xff,
+ .ver[1] = 0xff,
+};
+#else
+static update_file_ext_id_t update_file_id_info = {
+ .update_file_id_info.ver[0] = 0xff,
+ .update_file_id_info.ver[1] = 0xff,
+};
+#endif
+
+extern const int support_dual_bank_update_en;
+extern void JL_ble_disconnect(void);
+extern u8 check_le_pakcet_sent_finish_flag(void);
+
+static u8 update_flag = 0;
+static u8 tws_need_update = 0; //标志耳机是否需要强制升级
+static u8 tws_need_role_switch = 0; //用于tws连接之后版本号不匹配进行role_switch,低版本号的作为主机进行强制升级
+static u8 disconnect_flag = 0;
+u8 get_jl_update_flag(void)
+{
+ printf("get_update_flag:%x\n", update_flag);
+ return update_flag;
+}
+
+void set_jl_update_flag(u8 flag)
+{
+ update_flag = flag;
+ printf("update_flag:%x\n", update_flag);
+}
+
+typedef struct _update_mode_t {
+ u8 opcode;
+ u8 opcode_sn;
+
+} update_mode_t;
+
+static update_mode_t update_record_info;
+
+void JL_controller_save_curr_cmd_para(u8 OpCode, u8 OpCode_SN)
+{
+ update_record_info.opcode = OpCode;
+ update_record_info.opcode_sn = OpCode_SN;
+}
+
+void JL_controller_get_curr_cmd_para(u8 *OpCode, u8 *OpCode_SN)
+{
+ *OpCode = update_record_info.opcode;
+ *OpCode_SN = update_record_info.opcode_sn;
+}
+
+static void (*fw_update_block_handle)(u8 state, u8 *buf, u16 len) = NULL;
+void register_receive_fw_update_block_handle(void (*handle)(u8 state, u8 *buf, u16 len))
+{
+ fw_update_block_handle = handle;
+}
+
+static u16 ble_discon_timeout;
+static void ble_discon_timeout_handle(void *priv)
+{
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_UPDATE_START, NULL, 0);
+}
+
+void JL_rcsp_update_cmd_resp(void *priv, u8 OpCode, u8 OpCode_SN, u8 *data, u16 len)
+{
+ u8 msg[4];
+ rcsp_printf("%s\n", __FUNCTION__);
+ switch (OpCode) {
+ case JL_OPCODE_GET_DEVICE_UPDATE_FILE_INFO_OFFSET:
+ if (0 == len) {
+ msg[0] = OpCode;
+ msg[1] = OpCode_SN;
+ rcsp_printf("JL_OPCODE_GET_DEVICE_UPDATE_FILE_INFO_OFFSET\n");
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP,
+ MSG_JL_GET_DEV_UPDATE_FILE_INFO_OFFSET,
+ msg,
+ 2);
+ } else {
+ rcsp_printf("JL_OPCODE_GET_DEVICE_UPDATE_FILE_INFO_OFFSET ERR\n");
+ }
+ break;
+ case JL_OPCODE_INQUIRE_DEVICE_IF_CAN_UPDATE:
+ rcsp_printf("JL_OPCODE_INQUIRE_DEVICE_IF_CAN_UPDATE:%x %x\n", len, data[0]);
+ if (len) {
+ extern void set_curr_update_type(u8 type);
+ set_curr_update_type(data[0]);
+ msg[0] = OpCode;
+ msg[1] = OpCode_SN;
+ msg[2] = 0x00;
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP,
+ MSG_JL_INQUIRE_DEVEICE_IF_CAN_UPDATE,
+ msg,
+ 3);
+ }
+ break;
+ case JL_OPCODE_EXIT_UPDATE_MODE:
+ rcsp_printf("JL_OPCODE_EXIT_UPDATE_MODE\n");
+ break;
+ case JL_OPCODE_ENTER_UPDATE_MODE:
+ rcsp_printf("JL_OPCODE_ENTER_UPDATE_MODE\n");
+ msg[0] = OpCode;
+ msg[1] = OpCode_SN;
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP,
+ MSG_JL_ENTER_UPDATE_MODE,
+ msg,
+ 2);
+ break;
+ case JL_OPCODE_SEND_FW_UPDATE_BLOCK:
+ rcsp_printf("JL_OPCODE_SEND_FW_UPDATE_BLOCK\n");
+ break;
+ case JL_OPCODE_GET_DEVICE_REFRESH_FW_STATUS:
+ rcsp_printf("JL_OPCODE_GET_DEVICE_REFRESH_FW_STATUS\n");
+ JL_controller_save_curr_cmd_para(OpCode, OpCode_SN);
+ if (fw_update_block_handle) {
+ fw_update_block_handle(UPDATA_STOP, NULL, 0);
+ }
+ break;
+ /* case JL_OPCODE_SET_DEVICE_REBOOT: */
+ /* rcsp_printf("JL_OPCODE_SET_DEVICE_REBOOT\n"); */
+ /* if (support_dual_bank_update_en) { */
+ /* cpu_reset(); */
+ /* } */
+ /* break; */
+ default:
+ break;
+ }
+}
+
+static void JL_rcsp_resp_dev_update_file_info_offest(u8 OpCode, u8 OpCode_SN)
+{
+ u8 data[4 + 2];
+ u16 update_file_info_offset = DEV_UPDATE_FILE_INFO_OFFEST;
+ u16 update_file_info_len = DEV_UPDATE_FILE_INFO_LEN;
+ WRITE_BIG_U32(data + 0, update_file_info_offset);
+ WRITE_BIG_U16(data + 4, update_file_info_len);
+ JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, data, sizeof(data));
+}
+
+static void JL_resp_inquire_device_if_can_update(u8 OpCode, u8 OpCode_SN, u8 update_sta)
+{
+ u8 data[1];
+ data[0] = update_sta;
+ JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, data, sizeof(data));
+}
+
+enum {
+ UPDATE_FLAG_OK,
+ UPDATE_FLAG_LOW_POWER,
+ UPDATE_FLAG_FW_INFO_ERR,
+ UPDATE_FLAG_FW_INFO_CONSISTENT,
+ UPDATE_FLAG_TWS_DISCONNECT,
+};
+
+static u8 judge_remote_version_can_update(void)
+{
+ //extern u16 ex_cfg_get_local_version_info(void);
+ u16 remote_file_ver = READ_BIG_U16(update_file_id_info.update_file_id_info.ver);
+ //u16 local_ver = ex_cfg_get_local_version_info();
+ u16 local_ver = get_vid_pid_ver_from_cfg_file(GET_VID_FROM_EX_CFG);
+
+#if (0 == VER_INFO_EXT_COUNT)
+ //extern u16 ex_cfg_get_local_pid_info(void);
+ //extern u16 ex_cfg_get_local_vid_info(void);
+
+ //u16 local_pid = ex_cfg_get_local_pid_info();
+ //u16 local_vid = ex_cfg_get_local_vid_info();
+ u16 local_pid = get_vid_pid_ver_from_cfg_file(GET_PID_FROM_EX_CFG);
+ u16 local_vid = get_vid_pid_ver_from_cfg_file(GET_VID_FROM_EX_CFG);
+
+ u16 remote_file_pid = READ_BIG_U16(update_file_id_info.update_file_id_info.pid);
+ u16 remote_file_vid = READ_BIG_U16(update_file_id_info.update_file_id_info.vid);
+
+ if (remote_file_ver > local_ver || remote_file_pid != local_pid || remote_file_vid != local_vid) {
+ return UPDATE_FLAG_FW_INFO_ERR;
+ }
+#else
+ //extern u32 ex_cfg_get_local_authkey_info(u8 * authkey_data[], u8 * authkey_len);
+ //extern u32 ex_cfg_get_local_procode_info(u8 * procode_data[], u8 * procode_len);
+
+ u8 authkey_len = 0;
+ u8 *local_authkey_data = NULL;
+ get_authkey_procode_from_cfg_file(&local_authkey_data, &authkey_len, GET_AUTH_KEY_FROM_EX_CFG);
+
+ u8 procode_len = 0;
+ u8 *local_procode_data = NULL;
+ get_authkey_procode_from_cfg_file(&local_procode_data, &procode_len, GET_PRO_CODE_FROM_EX_CFG);
+
+ //ex_cfg_get_local_authkey_info(&local_authkey_data, &authkey_len);
+ //ex_cfg_get_local_procode_info(&local_procode_data, &procode_len);
+
+ u8 *remote_authkey_data = update_file_id_info.ext;
+ u8 *remote_procode_data = update_file_id_info.ext + authkey_len + 1;
+
+ if (remote_file_ver < local_ver
+ || 0 != memcmp(remote_authkey_data, local_authkey_data, authkey_len)
+ || 0 != memcmp(remote_procode_data, local_procode_data, procode_len)) {
+ return UPDATE_FLAG_FW_INFO_ERR;
+ }
+#endif
+
+ if (remote_file_ver == local_ver) {
+ rcsp_printf("remote_file_ver is %x, local_ver is %x, remote_file_ver is similar to local_ver\n", remote_file_ver, local_ver);
+ return UPDATE_FLAG_FW_INFO_CONSISTENT;
+ }
+
+ return UPDATE_FLAG_OK;
+}
+
+static bool check_edr_is_disconnct(void)
+{
+ if (get_curr_channel_state()) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+static bool check_ble_all_packet_sent(void)
+{
+ if (check_le_pakcet_sent_finish_flag()) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+static u32 rcsp_update_data_read(void *priv, u32 offset_addr, u16 len)
+{
+ u32 err;
+ u8 data[4 + 2];
+ WRITE_BIG_U32(data, offset_addr);
+ WRITE_BIG_U16(data + 4, len);
+ err = JL_CMD_send(JL_OPCODE_SEND_FW_UPDATE_BLOCK, data, sizeof(data), JL_NEED_RESPOND);
+
+ return err;
+}
+
+static JL_ERR JL_controller_resp_get_dev_refresh_fw_status(u8 OpCode, u8 OpCode_SN, u8 result)
+{
+ JL_ERR send_err = JL_ERR_NONE;
+ u8 data[1];
+
+ data[0] = result; //0:sucess 1:fail;
+
+ send_err = JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, data, sizeof(data));
+
+ return send_err;
+}
+
+u32 rcsp_update_status_response(void *priv, u8 status)
+{
+ u8 OpCode;
+ u8 OpCode_SN;
+
+ JL_ERR send_err = JL_ERR_NONE;
+
+ JL_controller_get_curr_cmd_para(&OpCode, &OpCode_SN);
+
+ //log_info("get cmd para:%x %x\n", OpCode, OpCode_SN);
+
+ if (JL_OPCODE_GET_DEVICE_REFRESH_FW_STATUS == OpCode) {
+ send_err = JL_controller_resp_get_dev_refresh_fw_status(OpCode, OpCode_SN, status);
+ }
+
+ return send_err;
+}
+
+
+
+void JL_rcsp_update_cmd_receive_resp(void *priv, u8 OpCode, u8 status, u8 *data, u16 len)
+{
+ switch (OpCode) {
+ case JL_OPCODE_SEND_FW_UPDATE_BLOCK:
+ if (fw_update_block_handle) {
+ fw_update_block_handle(UPDATA_REV_DATA, data, len);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void rcsp_loader_download_result_handle(void *priv, u8 type, u8 cmd)
+{
+ if (UPDATE_LOADER_OK == cmd) {
+ //JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP,MSG_JL_UPDATE_START,NULL,0);
+ set_jl_update_flag(1);
+ if (support_dual_bank_update_en) {
+ rcsp_printf("1111>>>rcsp update succ\n");
+ update_result_set(UPDATA_SUCC);
+ }
+ } else {
+ rcsp_printf(">>>update loader err\n");
+ /* #if OTA_TWS_SAME_TIME_ENABLE */
+ /* if((tws_ota_control(OTA_TYPE_GET) == OTA_TWS)) { */
+ /* tws_ota_stop(OTA_STOP_UPDATE_OVER_ERR); */
+ /* } */
+ /* #endif */
+ //rcsp_db_update_fail_deal();
+ }
+}
+
+extern void register_receive_fw_update_block_handle(void (*handle)(u8 state, u8 *buf, u16 len));
+extern void rcsp_update_data_api_register(u32(*data_send_hdl)(void *priv, u32 offset, u16 len), u32(*send_update_handl)(void *priv, u8 state));
+extern void rcsp_update_handle(void *buf, int len);
+extern void bt_set_low_latency_mode(int enable);
+extern void bt_adv_seq_change(void);
+extern int bt_tws_poweroff();
+extern void bt_wait_phone_connect_control(u8 enable);
+extern int tws_api_get_role(void);
+extern void tws_cancle_all_noconn();
+extern void bt_ble_rcsp_adv_disable(void);
+extern void ble_module_enable(u8 en);
+extern void bt_ble_rcsp_adv_enable(void);
+extern u32 ex_cfg_fill_content_api(void);
+extern void update_param_priv_fill(UPDATA_PARM *p, void *priv, u16 priv_len);
+
+u8 rcsp_get_update_flag(void)
+{
+ return tws_need_update;
+}
+
+void rcsp_set_update_flag(u8 flag)
+{
+ tws_need_update = flag;
+}
+
+u8 rcsp_update_get_role_switch(void)
+{
+ return tws_need_role_switch;
+}
+
+void rcsp_update_set_role_switch(u8 sw)
+{
+ tws_need_role_switch = sw;
+}
+
+void update_slave_adv_reopen(void)
+{
+ r_printf("slave reopen adv...\n");
+ ble_module_enable(1);
+ bt_ble_rcsp_adv_enable();
+}
+
+static void rcsp_update_private_param_fill(UPDATA_PARM *p)
+{
+ u32 exif_addr = ex_cfg_fill_content_api();
+ update_param_priv_fill(p, (void *)&exif_addr, sizeof(exif_addr));
+}
+
+static void rcsp_update_before_jump_handle(int type)
+{
+#if CONFIG_UPDATE_JUMP_TO_MASK
+ y_printf(">>>[test]:latch reset update\n");
+ latch_reset();
+#if 0
+ update_close_hw("null");
+ ram_protect_close();
+ /* save_spi_port(); */
+ extern void __BT_UPDATA_JUMP();
+ y_printf("update jump to __BT_UPDATA ...\n");
+ /* clk_set("sys", 48 * 1000000L); */
+ //跳转到uboot加载完,30ms左右(200410_yzb)
+ __BT_UPDATA_JUMP();
+#endif
+#else
+ cpu_reset();
+#endif
+}
+
+void JL_rcsp_msg_deal(void *hdl, u8 event, u8 *msg)
+{
+ u16 remote_file_version;
+ u8 can_update_flag = UPDATE_FLAG_FW_INFO_ERR;
+
+ switch (event) {
+ case MSG_JL_GET_DEV_UPDATE_FILE_INFO_OFFSET:
+ rcsp_printf("MSG_JL_GET_DEV_UPDATE_FILE_INFO_OFFSET\n");
+
+ /* extern void linein_mutex_stop(void *priv); */
+ /* linein_mutex_stop(NULL); */
+ /* extern void linein_mute(u8 mute); */
+ /* linein_mute(1); */
+
+ JL_rcsp_resp_dev_update_file_info_offest((u8)msg[0], (u8)msg[1]);
+ break;
+
+ case MSG_JL_INQUIRE_DEVEICE_IF_CAN_UPDATE:
+ rcsp_printf("MSG_JL_INQUIRE_DEVEICE_IF_CAN_UPDATE\n");
+#if 0
+ remote_file_version = READ_BIG_U16(update_file_id_info.update_file_id_info.ver);
+ rcsp_printf("remote_file_ver:V%d.%d.%d.%d\n",
+ (remote_file_version & 0xf000) >> 12,
+ (remote_file_version & 0x0f00) >> 8,
+ (remote_file_version & 0x00f0) >> 4,
+ (remote_file_version & 0x000f));
+
+ if (0 == remote_file_version) {
+ can_update_flag = UPDATE_FLAG_OK;
+ } else {
+ can_update_flag = judge_remote_version_can_update();
+ }
+
+ if (UPDATE_FLAG_OK == can_update_flag) {
+ set_jl_update_flag(1);
+ }
+#else
+#if OTA_TWS_SAME_TIME_ENABLE
+ int get_bt_tws_connect_status();
+ if (get_bt_tws_connect_status() || (!support_dual_bank_update_en)) { //单备份返回成功
+ can_update_flag = UPDATE_FLAG_OK;
+ } else {
+ can_update_flag = UPDATE_FLAG_TWS_DISCONNECT;
+ }
+#else
+ can_update_flag = UPDATE_FLAG_OK;
+#endif //endif OTA_TWS_SAME_TIME_ENABLE
+#endif
+ //todo;judge voltage
+ JL_resp_inquire_device_if_can_update((u8)msg[0], (u8)msg[1], can_update_flag);
+
+ if (0 == support_dual_bank_update_en) {
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ g_printf("tws master start update...\n");
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_LOADER_DOWNLOAD_START, NULL, 0);
+ //需要通知从机进入了升级
+ u8 data = TWS_UPDATE_INFO;
+ tws_api_send_data_to_sibling(&data, sizeof(data), TWS_FUNC_ID_SEQ_RAND_SYNC);
+ } else {
+ bt_ble_rcsp_adv_disable();
+ ble_module_enable(0); //关闭广播防止从机被手机误回连
+ r_printf("slave close adv...\n");
+ sys_timeout_add(NULL, update_slave_adv_reopen, 1000 * 60); //延迟一分钟再开广播
+ }
+ if (RCSP_SPP == JL_get_cur_bt_channel_sel()) {
+#if TCFG_USER_TWS_ENABLE
+ tws_api_detach(TWS_DETACH_BY_LOCAL); //单备份升级断开tws
+ tws_cancle_all_noconn();
+#endif
+ }
+ }
+
+ break;
+
+ case MSG_JL_DEV_DISCONNECT:
+ if (check_ble_all_packet_sent()) {
+ rcsp_printf("MSG_JL_DEV_DISCONNECT\n");
+ JL_ble_disconnect();
+ if (check_edr_is_disconnct()) {
+ puts("-need discon edr\n");
+ user_send_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
+ }
+ ble_discon_timeout = sys_timeout_add(NULL, ble_discon_timeout_handle, 1000);
+ } else {
+ rcsp_printf("W");
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_DEV_DISCONNECT, NULL, 0);
+ }
+ break;
+
+ case MSG_JL_LOADER_DOWNLOAD_START:
+ rcsp_update_data_api_register(rcsp_update_data_read, rcsp_update_status_response);
+ register_receive_fw_update_block_handle(rcsp_update_handle);
+ if (RCSP_BLE == get_curr_device_type()) {
+ rcsp_update_loader_download_init(BLE_APP_UPDATA, rcsp_loader_download_result_handle);
+ } else if (RCSP_SPP == get_curr_device_type()) {
+ rcsp_update_loader_download_init(SPP_APP_UPDATA, rcsp_loader_download_result_handle);
+ }
+ break;
+
+ case MSG_JL_UPDATE_START:
+ if (check_edr_is_disconnct()) {
+ rcsp_printf("b");
+ JL_rcsp_event_to_user(DEVICE_EVENT_FROM_RCSP, MSG_JL_UPDATE_START, NULL, 0);
+ break;
+ }
+
+ if (RCSP_BLE == get_curr_device_type()) {
+ rcsp_printf("BLE_APP_UPDATE\n");
+ update_mode_api_v2(BLE_APP_UPDATA,
+ rcsp_update_private_param_fill,
+ rcsp_update_before_jump_handle);
+ } else {
+ rcsp_printf("SPP_APP_UPDATA\n");
+ update_mode_api_v2(SPP_APP_UPDATA,
+ rcsp_update_private_param_fill,
+ rcsp_update_before_jump_handle);
+ }
+ break;
+
+ case MSG_JL_ENTER_UPDATE_MODE:
+ rcsp_printf("MSG_JL_ENTER_UPDATE_MODE:%x %x\n", msg[0], msg[1]);
+ bt_set_low_latency_mode(0);
+ if (support_dual_bank_update_en && !tws_api_get_role()) {
+ u8 status = 0;
+ JL_CMD_response_send(msg[0], JL_PRO_STATUS_SUCCESS, msg[1], &status, 1);
+ rcsp_update_data_api_register(rcsp_update_data_read, rcsp_update_status_response);
+ register_receive_fw_update_block_handle(rcsp_update_handle);
+ rcsp_update_loader_download_init(DUAL_BANK_UPDATA, rcsp_loader_download_result_handle);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+#endif
+
+#else
+//以下函数是为了编译通过
+void update_slave_adv_reopen(void)
+{
+ printf("%s:NULL", __func__);
+}
+void rcsp_set_update_flag(u8 flag)
+{
+ printf("%s:NULL", __func__);
+}
+void rcsp_update_set_role_switch(u8 sw)
+{
+ printf("%s:NULL", __func__);
+}
+u8 get_jl_update_flag(void)
+{
+ printf("%s:NULL", __func__);
+ return 0;
+}
+u8 rcsp_get_update_flag(void)
+{
+ printf("%s:NULL", __func__);
+ return 0;
+}
+#endif
+
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_adv_user_update.h b/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_adv_user_update.h
new file mode 100644
index 0000000..79a53fc
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_adv_user_update.h
@@ -0,0 +1,27 @@
+#ifndef _RCSP_ADV_USER_UPDATE_H_
+#define _RCSP_ADV_USER_UPDATE_H_
+
+//#include "rcsp_protocol.h"
+//#include "rcsp_packet.h"
+#include "typedef.h"
+
+#define JL_OPCODE_GET_DEVICE_UPDATE_FILE_INFO_OFFSET 0xe1
+#define JL_OPCODE_INQUIRE_DEVICE_IF_CAN_UPDATE 0xe2
+#define JL_OPCODE_ENTER_UPDATE_MODE 0xe3
+#define JL_OPCODE_EXIT_UPDATE_MODE 0xe4
+#define JL_OPCODE_SEND_FW_UPDATE_BLOCK 0xe5
+#define JL_OPCODE_GET_DEVICE_REFRESH_FW_STATUS 0xe6
+#define JL_OPCODE_SET_DEVICE_REBOOT 0xe7
+#define JL_OPCODE_NOTIFY_UPDATE_CONENT_SIZE 0xe8
+
+
+void JL_rcsp_update_cmd_resp(void *priv, u8 OpCode, u8 OpCode_SN, u8 *data, u16 len);
+void JL_rcsp_update_cmd_receive_resp(void *priv, u8 OpCode, u8 status, u8 *data, u16 len);
+void JL_rcsp_msg_deal(void *hdl, u8 event, u8 *msg);
+u8 get_jl_update_flag(void);
+void set_jl_update_flag(u8 flag);
+u8 get_curr_device_type(void);
+void update_slave_adv_reopen(void);
+
+#endif
+
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_ch_loader_download.c b/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_ch_loader_download.c
new file mode 100644
index 0000000..c5098c8
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_ch_loader_download.c
@@ -0,0 +1,377 @@
+//#include "update_lib.h"
+#include "update.h"
+#include "uart.h"
+#include "update_loader_download.h"
+#include "system/fs/fs.h"
+#include "rcsp_user_update.h"
+#include "JL_rcsp_protocol.h"
+#include "os/os_error.h"
+
+#include
+
+#if OTA_TWS_SAME_TIME_NEW
+#include "update_tws_new.h"
+#else
+#include "update_tws.h"
+#endif
+
+#if TCFG_USER_TWS_ENABLE
+#include "bt_tws.h"
+#endif
+
+#if ((RCSP_ADV_EN || RCSP_BTMATE_EN))
+
+#define LMP_CH_UPDATE_DEBUG_EN 1
+#if LMP_CH_UPDATE_DEBUG_EN
+#define deg_puts puts
+#define deg_printf printf
+#else
+#define deg_puts(...)
+#define deg_printf(...)
+#endif
+
+typedef enum __DEVICE_REFRESH_FW_STATUS {
+ DEVICE_UPDATE_STA_SUCCESS = 0, //升级成功(default)
+ DEVICE_UPDATE_STA_VERIFY_ERR, //升级完校验代码出错(default)
+ DEVICE_UPDATE_STA_FAIL, //升级失败(default)
+ DEVICE_UPDATE_STA_KEY_ERR, //加密key不匹配
+ DEVICE_UPDATE_STA_FILE_ERR, //升级文件出错
+ DEVICE_UPDATE_STA_TYPE_ERR, //升级类型出错,仅code_type;
+ //DEVICE_UPDATE_STA_MAX_ERR,
+ DEVICE_UPDATE_STA_LOADER_DOWNLOAD_SUCC = 0x80,
+} DEVICE_UPDATE_STA;
+
+enum {
+ BT_UPDATE_OVER = 0,
+ BT_UPDATE_KEY_ERR,
+ BT_UPDATE_CONNECT_ERR,
+};
+
+typedef enum {
+ UPDATA_START = 0x00,
+ UPDATA_REV_DATA,
+ UPDATA_STOP,
+} UPDATA_BIT_FLAG;
+
+
+typedef struct _rcsp_update_param_t {
+ u32 state;
+ u32 read_len;
+ u32 need_rx_len;
+ u8 *read_buf;
+ void (*resume_hdl)(void *priv);
+ int (*sleep_hdl)(void *priv);
+ u32(*data_send_hdl)(void *priv, u32 offset, u16 len);
+ u32(*send_update_status_hdl)(void *priv, u8 state);
+ u32 file_offset;
+ u8 seek_type;
+} rcsp_update_param_t;
+
+extern void set_jl_update_flag(u8 flag);
+
+extern const int support_dual_bank_update_en;
+
+static rcsp_update_param_t rcsp_update_param;
+#define __this (&rcsp_update_param)
+
+static u8 *bt_read_buf = NULL;
+static u16 g_bt_read_len = 0;
+static u32 rcsp_file_offset = 0;
+static u8 rcsp_seek_type = 0;
+
+//NOTE:测试盒的定义和本sdk文件系统的seek_type定义不一样;
+enum {
+ BT_SEEK_SET = 0x01,
+ BT_SEEK_CUR = 0x02,
+
+ BT_SEEK_TYPE_UPDATE_LEN = 0x10,
+};
+
+void tws_api_auto_role_switch_disable();
+void tws_api_auto_role_switch_enable();
+
+int rcsp_f_seek(void *fp, u8 type, u32 offset)
+{
+ if (type == SEEK_SET) {
+ __this->file_offset = offset;
+ __this->seek_type = BT_SEEK_SET;
+ } else if (type == SEEK_CUR) {
+ __this->file_offset += offset;
+ __this->seek_type = BT_SEEK_CUR;
+ }
+
+ /* lib_printf("---------UPDATA_seek type %d, offsize %d----------\n", bt_seek_type, bt_file_offset); */
+ return 0;//FR_OK;
+}
+
+static u16 rcsp_f_stop(u8 err);
+
+#define RETRY_TIMES 3
+u8 get_rcsp_connect_status();
+u16 rcsp_f_read(void *fp, u8 *buff, u16 len)
+{
+ //printf("===rcsp_read:%x %x\n", __this->file_offset, len);
+ u8 retry_cnt = 0;
+
+ __this->need_rx_len = len;
+ __this->state = UPDATA_REV_DATA;
+ __this->read_len = 0;
+ __this->read_buf = buff;
+
+__RETRY:
+ if (!get_rcsp_connect_status()) { //如果已经断开连接直接返回-1
+ return -1;
+ }
+ __this->data_send_hdl(fp, __this->file_offset, len);
+
+ while (!((0 == __this->state) && (__this->read_len == len))) {
+ if (__this->sleep_hdl && get_rcsp_connect_status()) {
+ __this->sleep_hdl(NULL);
+ } else {
+ len = -1;
+ break;
+ }
+
+ if (!((0 == __this->state) && (__this->read_len == len))) {
+ if (retry_cnt++ > RETRY_TIMES) {
+ len = (u16) - 1;
+ break;
+ } else {
+ goto __RETRY;
+ }
+ }
+ }
+
+ if ((u16) - 1 != len) {
+ __this->file_offset += len;
+ }
+
+
+ return len;
+}
+
+u16 rcsp_f_open(void)
+{
+ deg_puts(">>>rcsp_f_open\n");
+ __this->file_offset = 0;
+ __this->seek_type = BT_SEEK_SET;
+ return 1;
+}
+
+u16 rcsp_send_update_len(u32 update_len)
+{
+ /* while (0 == (bit(updata_start) & bt_updata_get_flag())); */
+ /* bt_updata_clr_flag(updata_start); //clr flag */
+ return 1;
+}
+
+
+static u8 update_result_handle(u8 err)
+{
+ u8 res = DEVICE_UPDATE_STA_LOADER_DOWNLOAD_SUCC;
+
+ /* #if OTA_TWS_SAME_TIME_ENABLE */
+ /* tws_api_auto_role_switch_enable(); */
+ /* #endif */
+
+ if (err & UPDATE_RESULT_FLAG_BITMAP) {
+ switch (err & 0x7f) {
+ //升级文件错误
+ case UPDATE_RESULT_FILE_SIZE_ERR:
+ case UPDATE_RESULT_LOADER_SIZE_ERR:
+ case UPDATE_RESULT_REMOTE_FILE_HEAD_ERR:
+ case UPDATE_RESULT_LOCAL_FILE_HEAD_ERR:
+ case UPDATE_RESULT_FILE_OPERATION_ERR:
+ case UPDATE_RESULT_NOT_FIND_TARGET_FILE_ERR:
+ case UPDATE_RESULT_PRODUCT_INFO_NOT_MATCH:
+ res = DEVICE_UPDATE_STA_FILE_ERR;
+ break;
+ //文件内容校验失败
+ case UPDATE_RESULT_LOADER_VERIFY_ERR:
+ case UPDATE_RESULT_FLASH_DATA_VERIFY_ERR:
+ res = DEVICE_UPDATE_STA_VERIFY_ERR;
+ break;
+
+ }
+ } else if (BT_UPDATE_OVER == err) {
+ if (support_dual_bank_update_en) {
+ res = DEVICE_UPDATE_STA_SUCCESS;
+ } else {
+ res = DEVICE_UPDATE_STA_LOADER_DOWNLOAD_SUCC;
+ }
+ } else if (BT_UPDATE_KEY_ERR == err) {
+ res = DEVICE_UPDATE_STA_KEY_ERR;
+ } else {
+ res = DEVICE_UPDATE_STA_FAIL;
+ }
+
+ return res;
+}
+
+static u16 rcsp_f_stop(u8 err)
+{
+ /* while (0 == (bit(updata_start) & bt_updata_get_flag())); */
+ /* bt_updata_clr_flag(updata_start); //clr flag */
+
+ err = update_result_handle(err);
+ __this->state = UPDATA_STOP;
+ printf(">>>rcsp_stop:%x\n", __this->state);
+
+ if (__this->data_send_hdl) {
+ __this->data_send_hdl(NULL, 0, 0);
+ }
+
+ while (!(0 == __this->state)) {
+ if (__this->sleep_hdl && get_rcsp_connect_status()) {
+ if (__this->sleep_hdl(NULL) == OS_TIMEOUT) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ if (__this->send_update_status_hdl) {
+ __this->send_update_status_hdl(NULL, err);
+ }
+
+ return 1;
+}
+
+void db_update_notify_fail_to_phone()
+{
+ if (get_rcsp_connect_status()) {
+ rcsp_f_stop(DEVICE_UPDATE_STA_FAIL);
+ }
+}
+
+__attribute__((weak))
+void user_change_ble_conn_param(u8 param_index)
+{
+
+}
+
+static int rcsp_notify_update_content_size(void *priv, u32 size)
+{
+ int err;
+
+ u8 data[4];
+
+ WRITE_BIG_U32(data, size);
+
+ user_change_ble_conn_param(0);
+
+ deg_printf("send content_size:%x\n", size);
+ err = JL_CMD_send(JL_OPCODE_NOTIFY_UPDATE_CONENT_SIZE, data, sizeof(data), JL_NEED_RESPOND);
+
+ return err;
+}
+
+void rcsp_update_handle(u8 state, void *buf, int len)
+{
+ /* deg_puts("R"); */
+ if (state != __this->state) {
+ deg_puts(">>>rcsp state err\n");
+ return;
+ }
+
+ switch (state) {
+ case UPDATA_REV_DATA:
+ if (__this->read_buf) {
+ memcpy(__this->read_buf, buf, len);
+ __this->read_len = len;
+ __this->state = 0;
+ }
+ break;
+
+ case UPDATA_STOP:
+ __this->state = 0;
+ break;
+ }
+
+ if (__this->resume_hdl) {
+ __this->resume_hdl(NULL);
+ }
+}
+
+void rcsp_resume(void)
+{
+ if (__this->resume_hdl) {
+ __this->resume_hdl(NULL);
+ }
+}
+
+static void rcsp_update_resume_hdl_register(void (*resume_hdl)(void *priv), int (*sleep_hdl)(void *priv))
+{
+ __this->resume_hdl = resume_hdl;
+ __this->sleep_hdl = sleep_hdl;
+}
+
+void rcsp_update_data_api_register(u32(*data_send_hdl)(void *priv, u32 offset, u16 len), u32(*send_update_status_hdl)(void *priv, u8 state))
+{
+ __this->data_send_hdl = data_send_hdl;
+ __this->send_update_status_hdl = send_update_status_hdl;
+}
+
+void rcsp_update_data_api_unregister(void)
+{
+ __this->data_send_hdl = NULL;
+ __this->send_update_status_hdl = NULL;
+}
+
+void rcsp_ch_update_init(void (*resume_hdl)(void *priv), int (*sleep_hdl)(void *priv))
+{
+ deg_puts("------------rcsp_ch_update_init\n");
+
+ rcsp_update_resume_hdl_register(resume_hdl, sleep_hdl);
+ //register_receive_fw_update_block_handle(rcsp_updata_handle);
+}
+
+const update_op_api_t rcsp_update_op = {
+ .ch_init = rcsp_ch_update_init,
+ .f_open = rcsp_f_open,
+ .f_read = rcsp_f_read,
+ .f_seek = rcsp_f_seek,
+ .f_stop = rcsp_f_stop,
+ .notify_update_content_size = rcsp_notify_update_content_size,
+};
+
+static void rcsp_update_state_cbk(int type, u32 state, void *priv)
+{
+ update_ret_code_t *ret_code = (update_ret_code_t *)priv;
+ if (ret_code) {
+ printf("state:%x err:%x\n", ret_code->stu, ret_code->err_code);
+ }
+ switch (state) {
+ case UPDATE_CH_EXIT:
+ if (UPDATE_DUAL_BANK_IS_SUPPORT()) {
+ if ((0 == ret_code->stu) && (0 == ret_code->err_code)) {
+ set_jl_update_flag(1);
+ printf("2222>>>rcsp update succ\n");
+ update_result_set(UPDATA_SUCC);
+
+ } else {
+ update_result_set(UPDATA_DEV_ERR);
+ printf("3333>>>rcsp update succ\n");
+ }
+ } else {
+ if ((0 == ret_code->stu) && (0 == ret_code->err_code)) {
+ set_jl_update_flag(1);
+ }
+ }
+ break;
+ }
+}
+
+void rcsp_update_loader_download_init(int update_type, void (*result_cbk)(void *priv, u8 type, u8 cmd))
+{
+ update_mode_info_t info = {
+ .type = update_type,
+ .state_cbk = rcsp_update_state_cbk,
+ .p_op_api = &rcsp_update_op,
+ .task_en = 1,
+ };
+ app_active_update_task_init(&info);
+}
+
+#endif //(OTA_TWS_SAME_TIME_ENABLE && (RCSP_ADV_EN || RCSP_BTMATE_EN))
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_user_update.c b/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_user_update.c
new file mode 100644
index 0000000..49bf648
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_user_update.c
@@ -0,0 +1,564 @@
+#include "rcsp_user_update.h"
+#include "app_config.h"
+#if RCSP_UPDATE_EN
+#include "uart.h"
+#include "system/timer.h"
+#include "update.h"
+#include "custom_cfg.h"
+#include "btstack/avctp_user.h"
+#include "JL_rcsp_packet.h"
+#include "JL_rcsp_protocol.h"
+#include "rcsp_bluetooth.h"
+#include "update_loader_download.h"
+#if(TCFG_USER_TWS_ENABLE == 1)
+#include "classic/tws_api.h"
+#endif
+#include "btstack_3th_protocol_user.h"
+
+#if (RCSP_BTMATE_EN)
+
+#define RCSP_DEBUG_EN
+
+#ifdef RCSP_BTMATE_EN
+#define rcsp_putchar(x) putchar(x)
+#define rcsp_printf printf
+#define rcsp_printf_buf(x,len) printf_buf(x,len)
+#else
+#define rcsp_putchar(...)
+#define rcsp_printf(...)
+#define rcsp_printf_buf(...)
+#endif
+
+#define DEV_UPDATE_FILE_INFO_OFFEST 0x00//0x40
+#define DEV_UPDATE_FILE_INFO_LEN 0x00//(0x10 + VER_INFO_EXT_COUNT * (VER_INFO_EXT_MAX_LEN + 1))
+
+typedef enum {
+ UPDATA_START = 0x00,
+ UPDATA_REV_DATA,
+ UPDATA_STOP,
+} UPDATA_BIT_FLAG;
+
+typedef struct _update_mode_t {
+ u8 opcode;
+ u8 opcode_sn;
+
+} update_mode_t;
+
+
+extern const int support_dual_bank_update_en;
+extern void JL_ble_disconnect(void);
+extern void set_curr_update_type(u8 type);
+extern u8 check_le_pakcet_sent_finish_flag(void);
+extern void register_receive_fw_update_block_handle(void (*handle)(u8 state, u8 *buf, u16 len));
+extern void rcsp_update_data_api_register(u32(*data_send_hdl)(void *priv, u32 offset, u16 len), u32(*send_update_handl)(void *priv, u8 state));
+extern void rcsp_update_handle(void *buf, int len);
+extern u32 ex_cfg_fill_content_api(void);
+extern void update_result_set(u16 result);
+
+static u8 rcsp_update_status;
+static u8 update_flag = 0;
+static u16 ble_discon_timeout;
+static void (*fw_update_block_handle)(u8 state, u8 *buf, u16 len) = NULL;
+
+static update_file_ext_id_t update_file_id_info = {
+ .update_file_id_info.ver[0] = 0xff,
+ .update_file_id_info.ver[1] = 0xff,
+};
+
+static update_mode_t update_record_info;
+
+u8 get_jl_update_flag(void)
+{
+ printf("get_update_flag:%x\n", update_flag);
+ return update_flag;
+}
+
+void set_jl_update_flag(u8 flag)
+{
+ update_flag = flag;
+ printf("update_flag:%x\n", update_flag);
+}
+
+void JL_controller_save_curr_cmd_para(u8 OpCode, u8 OpCode_SN)
+{
+ update_record_info.opcode = OpCode;
+ update_record_info.opcode_sn = OpCode_SN;
+}
+
+void JL_controller_get_curr_cmd_para(u8 *OpCode, u8 *OpCode_SN)
+{
+ *OpCode = update_record_info.opcode;
+ *OpCode_SN = update_record_info.opcode_sn;
+}
+
+void register_receive_fw_update_block_handle(void (*handle)(u8 state, u8 *buf, u16 len))
+{
+ fw_update_block_handle = handle;
+}
+
+static void ble_discon_timeout_handle(void *priv)
+{
+ rcsp_msg_post(MSG_JL_UPDATE_START, 0);
+}
+
+void JL_rcsp_update_cmd_resp(void *priv, u8 OpCode, u8 OpCode_SN, u8 *data, u16 len)
+{
+ u8 msg[4];
+ rcsp_printf("%s\n", __FUNCTION__);
+ switch (OpCode) {
+ case JL_OPCODE_GET_DEVICE_UPDATE_FILE_INFO_OFFSET:
+ if (0 == len) {
+ rcsp_printf("JL_OPCODE_GET_DEVICE_UPDATE_FILE_INFO_OFFSET\n");
+ rcsp_msg_post(MSG_JL_GET_DEV_UPDATE_FILE_INFO_OFFSET, 2, OpCode, OpCode_SN);
+ } else {
+ rcsp_printf("JL_OPCODE_GET_DEVICE_UPDATE_FILE_INFO_OFFSET ERR\n");
+ }
+ break;
+ case JL_OPCODE_INQUIRE_DEVICE_IF_CAN_UPDATE:
+ rcsp_printf("JL_OPCODE_INQUIRE_DEVICE_IF_CAN_UPDATE:%x %x\n", len, data[0]);
+ //if (DEV_UPDATE_FILE_INFO_LEN == len) {
+ if (len) {
+ //memcpy((u8 *)&update_file_id_info, data, DEV_UPDATE_FILE_INFO_LEN);
+ set_curr_update_type(data[0]);
+ rcsp_msg_post(MSG_JL_INQUIRE_DEVEICE_IF_CAN_UPDATE, 3, OpCode, OpCode_SN, 0x00);
+ }
+ break;
+ case JL_OPCODE_EXIT_UPDATE_MODE:
+ rcsp_printf("JL_OPCODE_EXIT_UPDATE_MODE\n");
+ break;
+ case JL_OPCODE_ENTER_UPDATE_MODE:
+ rcsp_printf("JL_OPCODE_ENTER_UPDATE_MODE\n");
+ rcsp_msg_post(MSG_JL_ENTER_UPDATE_MODE, 2, OpCode, OpCode_SN);
+ break;
+ case JL_OPCODE_SEND_FW_UPDATE_BLOCK:
+ rcsp_printf("JL_OPCODE_SEND_FW_UPDATE_BLOCK\n");
+ break;
+ case JL_OPCODE_GET_DEVICE_REFRESH_FW_STATUS:
+ rcsp_printf("JL_OPCODE_GET_DEVICE_REFRESH_FW_STATUS\n");
+ JL_controller_save_curr_cmd_para(OpCode, OpCode_SN);
+ if (fw_update_block_handle) {
+ fw_update_block_handle(UPDATA_STOP, NULL, 0);
+ }
+ break;
+ case JL_OPCODE_SET_DEVICE_REBOOT:
+ rcsp_printf("JL_OPCODE_SET_DEVICE_REBOOT\n");
+ if (support_dual_bank_update_en) {
+ cpu_reset();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void JL_rcsp_resp_dev_update_file_info_offest(u8 OpCode, u8 OpCode_SN)
+{
+ u8 data[4 + 2];
+ u16 update_file_info_offset = DEV_UPDATE_FILE_INFO_OFFEST;
+ u16 update_file_info_len = DEV_UPDATE_FILE_INFO_LEN;
+ WRITE_BIG_U32(data + 0, update_file_info_offset);
+ WRITE_BIG_U16(data + 4, update_file_info_len);
+
+ JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, data, sizeof(data));
+}
+
+static void JL_resp_inquire_device_if_can_update(u8 OpCode, u8 OpCode_SN, u8 update_sta)
+{
+ u8 data[1];
+ data[0] = update_sta;
+ JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, data, sizeof(data));
+}
+
+enum {
+ UPDATE_FLAG_OK,
+ UPDATE_FLAG_LOW_POWER,
+ UPDATE_FLAG_FW_INFO_ERR,
+ UPDATE_FLAG_FW_INFO_CONSISTENT,
+};
+
+static u8 judge_remote_version_can_update(void)
+{
+ //extern u16 ex_cfg_get_local_version_info(void);
+ u16 remote_file_ver = READ_BIG_U16(update_file_id_info.update_file_id_info.ver);
+ //u16 local_ver = ex_cfg_get_local_version_info();
+ u16 local_ver = get_vid_pid_ver_from_cfg_file(GET_VID_FROM_EX_CFG);
+
+#if (0 == VER_INFO_EXT_COUNT)
+ //extern u16 ex_cfg_get_local_pid_info(void);
+ //extern u16 ex_cfg_get_local_vid_info(void);
+
+ //u16 local_pid = ex_cfg_get_local_pid_info();
+ //u16 local_vid = ex_cfg_get_local_vid_info();
+ u16 local_pid = get_vid_pid_ver_from_cfg_file(GET_PID_FROM_EX_CFG);
+ u16 local_vid = get_vid_pid_ver_from_cfg_file(GET_VID_FROM_EX_CFG);
+
+ u16 remote_file_pid = READ_BIG_U16(update_file_id_info.update_file_id_info.pid);
+ u16 remote_file_vid = READ_BIG_U16(update_file_id_info.update_file_id_info.vid);
+
+ if (remote_file_ver > local_ver || remote_file_pid != local_pid || remote_file_vid != local_vid) {
+ return UPDATE_FLAG_FW_INFO_ERR;
+ }
+#else
+ //extern u32 ex_cfg_get_local_authkey_info(u8 * authkey_data[], u8 * authkey_len);
+ //extern u32 ex_cfg_get_local_procode_info(u8 * procode_data[], u8 * procode_len);
+
+ u8 authkey_len = 0;
+ u8 *local_authkey_data = NULL;
+ get_authkey_procode_from_cfg_file(&local_authkey_data, &authkey_len, GET_AUTH_KEY_FROM_EX_CFG);
+
+ u8 procode_len = 0;
+ u8 *local_procode_data = NULL;
+ get_authkey_procode_from_cfg_file(&local_procode_data, &procode_len, GET_PRO_CODE_FROM_EX_CFG);
+
+ //ex_cfg_get_local_authkey_info(&local_authkey_data, &authkey_len);
+ //ex_cfg_get_local_procode_info(&local_procode_data, &procode_len);
+
+ u8 *remote_authkey_data = update_file_id_info.ext;
+ u8 *remote_procode_data = update_file_id_info.ext + authkey_len + 1;
+
+ if (remote_file_ver < local_ver
+ || 0 != memcmp(remote_authkey_data, local_authkey_data, authkey_len)
+ || 0 != memcmp(remote_procode_data, local_procode_data, procode_len)) {
+ return UPDATE_FLAG_FW_INFO_ERR;
+ }
+#endif
+
+ if (remote_file_ver == local_ver) {
+ rcsp_printf("remote_file_ver is %x, local_ver is %x, remote_file_ver is similar to local_ver\n", remote_file_ver, local_ver);
+ return UPDATE_FLAG_FW_INFO_CONSISTENT;
+ }
+
+ return UPDATE_FLAG_OK;
+}
+
+static bool check_edr_is_disconnct(void)
+{
+ if (get_curr_channel_state()) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+static bool check_ble_all_packet_sent(void)
+{
+ if (check_le_pakcet_sent_finish_flag()) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+static u32 rcsp_update_data_read(void *priv, u32 offset_addr, u16 len)
+{
+ u32 err;
+ u8 data[4 + 2];
+ WRITE_BIG_U32(data, offset_addr);
+ WRITE_BIG_U16(data + 4, len);
+ err = JL_CMD_send(JL_OPCODE_SEND_FW_UPDATE_BLOCK, data, sizeof(data), JL_NEED_RESPOND);
+
+ return err;
+}
+
+static JL_ERR JL_controller_resp_get_dev_refresh_fw_status(u8 OpCode, u8 OpCode_SN, u8 result)
+{
+ JL_ERR send_err = JL_ERR_NONE;
+ u8 data[1];
+
+ data[0] = result; //0:sucess 1:fail;
+
+ send_err = JL_CMD_response_send(OpCode, JL_PRO_STATUS_SUCCESS, OpCode_SN, data, sizeof(data));
+
+ return send_err;
+}
+
+u32 rcsp_update_status_response(void *priv, u8 status)
+{
+ u8 OpCode;
+ u8 OpCode_SN;
+
+ JL_ERR send_err = JL_ERR_NONE;
+
+ JL_controller_get_curr_cmd_para(&OpCode, &OpCode_SN);
+
+ //log_info("get cmd para:%x %x\n", OpCode, OpCode_SN);
+
+ if (JL_OPCODE_GET_DEVICE_REFRESH_FW_STATUS == OpCode) {
+ send_err = JL_controller_resp_get_dev_refresh_fw_status(OpCode, OpCode_SN, status);
+ }
+
+ return send_err;
+}
+
+
+
+void JL_rcsp_update_cmd_receive_resp(void *priv, u8 OpCode, u8 status, u8 *data, u16 len)
+{
+ switch (OpCode) {
+ case JL_OPCODE_SEND_FW_UPDATE_BLOCK:
+ if (fw_update_block_handle) {
+ fw_update_block_handle(UPDATA_REV_DATA, data, len);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void rcsp_loader_download_result_handle(void *priv, u8 type, u8 cmd)
+{
+ if (UPDATE_LOADER_OK == cmd) {
+ //rcsp_msg(MSG_JL_UPDATE_START, 0);
+ set_jl_update_flag(1);
+ if (support_dual_bank_update_en) {
+ rcsp_printf("4444>>>rcsp update succ\n");
+ update_result_set(UPDATA_SUCC);
+ }
+ } else {
+ rcsp_printf(">>>update loader err\n");
+#if OTA_TWS_SAME_TIME_ENABLE
+ if ((tws_ota_control(OTA_TYPE_GET) == OTA_TWS)) {
+ tws_ota_stop(OTA_STOP_UPDATE_OVER_ERR);
+ }
+#endif
+ }
+}
+
+
+u32 get_jl_rcsp_update_status()
+{
+ return rcsp_update_status;
+}
+
+static void rcsp_update_private_param_fill(UPDATA_PARM *p)
+{
+ u32 exif_addr;
+
+ exif_addr = ex_cfg_fill_content_api();
+ update_param_priv_fill(p, (void *)&exif_addr, sizeof(exif_addr));
+}
+
+static void rcsp_update_before_jump_handle(int type)
+{
+#if CONFIG_UPDATE_JUMP_TO_MASK
+ y_printf(">>>[test]:latch reset update\n");
+ latch_reset();
+
+#if 0
+ update_close_hw("null");
+ ram_protect_close();
+ /* save_spi_port(); */
+ extern void __BT_UPDATA_JUMP();
+ y_printf("update jump to __BT_UPDATA ...\n");
+ //跳转到uboot加载完,30ms左右(200410_yzb)
+ /* clk_set("sys", 48 * 1000000L); */
+ __BT_UPDATA_JUMP();
+#endif
+#else
+ cpu_reset();
+#endif
+}
+
+
+void JL_rcsp_msg_deal(RCSP_MSG msg, int argc, int *argv)
+{
+ u16 remote_file_version;
+ u8 can_update_flag = UPDATE_FLAG_FW_INFO_ERR;
+
+ switch (msg) {
+ case MSG_JL_GET_DEV_UPDATE_FILE_INFO_OFFSET:
+ rcsp_printf("MSG_JL_GET_DEV_UPDATE_FILE_INFO_OFFSET\n");
+ rcsp_update_status = 1;
+ /* extern void linein_mutex_stop(void *priv); */
+ /* linein_mutex_stop(NULL); */
+ /* extern void linein_mute(u8 mute); */
+ /* linein_mute(1); */
+ if (argc < 2) {
+ rcsp_printf("err: MSG_JL_GET_DEV_UPDATE_FILE_INFO_OFFSET too few argument, argc is %d\n", argc);
+ return;
+ }
+
+ JL_rcsp_resp_dev_update_file_info_offest((u8)argv[0], (u8)argv[1]);
+ break;
+
+ case MSG_JL_INQUIRE_DEVEICE_IF_CAN_UPDATE:
+ rcsp_printf("MSG_JL_INQUIRE_DEVEICE_IF_CAN_UPDATE\n");
+ if (argc < 2) {
+ rcsp_printf("err: MSG_JL_INQUIRE_DEVEICE_IF_CAN_UPDATE too few argument, argc is %d\n", argc);
+ return;
+ }
+#if 0
+ remote_file_version = READ_BIG_U16(update_file_id_info.update_file_id_info.ver);
+ rcsp_printf("remote_file_ver:V%d.%d.%d.%d\n",
+ (remote_file_version & 0xf000) >> 12,
+ (remote_file_version & 0x0f00) >> 8,
+ (remote_file_version & 0x00f0) >> 4,
+ (remote_file_version & 0x000f));
+
+ if (0 == remote_file_version) {
+ can_update_flag = UPDATE_FLAG_OK;
+ } else {
+ can_update_flag = judge_remote_version_can_update();
+ }
+
+ if (UPDATE_FLAG_OK == can_update_flag) {
+ set_jl_update_flag(1);
+ }
+#else
+ can_update_flag = UPDATE_FLAG_OK;
+#endif
+ //todo;judge voltage
+ JL_resp_inquire_device_if_can_update((u8)argv[0], (u8)argv[1], can_update_flag);
+
+ if (0 == support_dual_bank_update_en) {
+ rcsp_msg_post(MSG_JL_LOADER_DOWNLOAD_START, 0);
+ }
+ break;
+
+ case MSG_JL_DEV_DISCONNECT:
+ if (check_ble_all_packet_sent()) {
+ rcsp_printf("MSG_JL_DEV_DISCONNECT\n");
+ JL_ble_disconnect();
+ if (check_edr_is_disconnct()) {
+ puts("-need discon edr\n");
+ user_send_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
+ }
+ ble_discon_timeout = sys_timeout_add(NULL, ble_discon_timeout_handle, 1000);
+ } else {
+ rcsp_printf("W");
+ rcsp_msg_post(MSG_JL_DEV_DISCONNECT, 0);
+ }
+ break;
+
+ case MSG_JL_LOADER_DOWNLOAD_START:
+ rcsp_update_data_api_register(rcsp_update_data_read, rcsp_update_status_response);
+ register_receive_fw_update_block_handle(rcsp_update_handle);
+ if (RCSP_BLE == get_curr_device_type()) {
+ rcsp_update_loader_download_init(BLE_APP_UPDATA, rcsp_loader_download_result_handle);
+ } else if (RCSP_SPP == get_curr_device_type()) {
+ rcsp_update_loader_download_init(SPP_APP_UPDATA, rcsp_loader_download_result_handle);
+ }
+ break;
+
+ case MSG_JL_UPDATE_START:
+ if (check_edr_is_disconnct()) {
+ rcsp_printf("b");
+ rcsp_msg_post(MSG_JL_UPDATE_START, 0);
+ break;
+ }
+
+ if (RCSP_BLE == get_curr_device_type()) {
+ rcsp_printf("BLE_APP_UPDATE\n");
+ update_mode_api_v2(BLE_APP_UPDATA,
+ rcsp_update_private_param_fill,
+ rcsp_update_before_jump_handle);
+ } else {
+ rcsp_printf("SPP_APP_UPDATA\n");
+ update_mode_api_v2(SPP_APP_UPDATA,
+ rcsp_update_private_param_fill,
+ rcsp_update_before_jump_handle);
+ }
+ /* if (RCSP_BLE == get_curr_device_type()) { */
+ /* rcsp_printf("BLE_APP_UPDATE\n"); */
+ /* update_mode_api(BLE_APP_UPDATA); */
+ /* } else { */
+ /* rcsp_printf("SPP_APP_UPDATA\n"); */
+ /* update_mode_api(SPP_APP_UPDATA); */
+ /* } */
+ break;
+
+ case MSG_JL_ENTER_UPDATE_MODE:
+ if (argc < 2) {
+ rcsp_printf("err: MSG_JL_ENTER_UPDATE_MODE too few argument, argc is %d\n", argc);
+ return;
+ }
+ rcsp_printf("MSG_JL_ENTER_UPDATE_MODE:%x %x\n", (u8)argv[0], (u8)argv[1]);
+#if(TCFG_USER_TWS_ENABLE == 1)
+ void tws_cancle_all_noconn();
+ tws_cancle_all_noconn();
+#endif
+ user_send_cmd_prepare(USER_CTRL_WRITE_CONN_DISABLE, 0, NULL);
+ user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_DISABLE, 0, NULL);
+ if (support_dual_bank_update_en) {
+ u8 status = 0;
+ JL_CMD_response_send((u8)argv[0], JL_PRO_STATUS_SUCCESS, (u8)argv[1], &status, 1);
+ rcsp_update_data_api_register(rcsp_update_data_read, rcsp_update_status_response);
+ register_receive_fw_update_block_handle(rcsp_update_handle);
+ rcsp_update_loader_download_init(DUAL_BANK_UPDATA, rcsp_loader_download_result_handle);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void rcsp_update_jump_for_hid_device()
+{
+ if (RCSP_BLE == get_curr_device_type()) {
+ rcsp_printf("BLE_APP_UPDATE\n");
+ update_mode_api_v2(BLE_APP_UPDATA,
+ rcsp_update_private_param_fill,
+ rcsp_update_before_jump_handle);
+ } else {
+ rcsp_printf("SPP_APP_UPDATA\n");
+ update_mode_api_v2(SPP_APP_UPDATA,
+ rcsp_update_private_param_fill,
+ rcsp_update_before_jump_handle);
+ }
+}
+#endif
+
+static u8 rcsp_update_flag = 0;
+void set_rcsp_db_update_status(u8 value)
+{
+ rcsp_update_flag = value;
+}
+
+u8 get_rcsp_db_update_status()
+{
+ return rcsp_update_flag;
+}
+
+void rcsp_before_enter_db_update_mode() //进入双备份升级前
+{
+ r_printf("%s", __func__);
+ rcsp_update_flag = 1;
+ void sys_auto_shut_down_disable(void);
+ if (get_total_connect_dev() == 0) {
+ sys_auto_shut_down_disable();
+ }
+#if TCFG_USER_TWS_ENABLE
+ int tws_api_get_role(void);
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ return;
+ }
+#endif
+ if (get_total_connect_dev()) { //断开蓝牙连接,断开之后不能让他重新开
+ /* user_send_cmd_prepare(USER_CTRL_DISCONNECTION_HCI, 0, NULL); */
+ }
+#if TCFG_USER_TWS_ENABLE
+ extern void tws_cancle_all_noconn();
+ /* tws_cancle_all_noconn() ; */
+#else
+ user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_DISABLE, 0, NULL);
+ user_send_cmd_prepare(USER_CTRL_WRITE_CONN_DISABLE, 0, NULL);
+#endif
+}
+
+extern void sys_auto_shut_down_enable(void);
+void rcsp_db_update_fail_deal() //双备份升级失败处理
+{
+ r_printf("%s", __func__);
+ if (rcsp_update_flag) {
+ rcsp_update_flag = 0;
+ if (get_total_connect_dev() == 0) {
+ sys_auto_shut_down_enable();
+ }
+ }
+ /* cpu_reset(); //升级失败直接复位 */
+}
+
+#endif
+
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_user_update.h b/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_user_update.h
new file mode 100644
index 0000000..fd4eabc
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/rcsp_updata/rcsp_user_update.h
@@ -0,0 +1,25 @@
+#ifndef _RCSP_USER_UPDATE_H_
+#define _RCSP_USER_UPDATE_H_
+
+//#include "rcsp_protocol.h"
+//#include "rcsp_packet.h"
+#include "typedef.h"
+
+
+#define JL_OPCODE_GET_DEVICE_UPDATE_FILE_INFO_OFFSET 0xe1
+#define JL_OPCODE_INQUIRE_DEVICE_IF_CAN_UPDATE 0xe2
+#define JL_OPCODE_ENTER_UPDATE_MODE 0xe3
+#define JL_OPCODE_EXIT_UPDATE_MODE 0xe4
+#define JL_OPCODE_SEND_FW_UPDATE_BLOCK 0xe5
+#define JL_OPCODE_GET_DEVICE_REFRESH_FW_STATUS 0xe6
+#define JL_OPCODE_SET_DEVICE_REBOOT 0xe7
+#define JL_OPCODE_NOTIFY_UPDATE_CONENT_SIZE 0xe8
+
+void JL_rcsp_update_cmd_resp(void *priv, u8 OpCode, u8 OpCode_SN, u8 *data, u16 len);
+void JL_rcsp_update_cmd_receive_resp(void *priv, u8 OpCode, u8 status, u8 *data, u16 len);
+u8 get_jl_update_flag(void);
+void set_jl_update_flag(u8 flag);
+u8 get_curr_device_type(void);
+
+#endif
+
diff --git a/apps/common/third_party_profile/jieli/le_client_demo.h b/apps/common/third_party_profile/jieli/le_client_demo.h
new file mode 100644
index 0000000..bd3ffc0
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/le_client_demo.h
@@ -0,0 +1,84 @@
+// binary representation
+// attribute size in bytes (16), flags(16), handle (16), uuid (16/128), value(...)
+#ifndef _LE_CLIENT_DEMO_H
+#define _LE_CLIENT_DEMO_H
+
+#include
+#include "btstack/le/att.h"
+
+//搜索匹配连接方式
+typedef enum {
+ CLI_CREAT_BY_ADDRESS = 0,//指定地址创建连接
+ CLI_CREAT_BY_NAME,//指定设备名称创建连接
+ CLI_CREAT_BY_TAG,//匹配厂家标识创建连接
+} cli_creat_mode_e;
+
+//主机事件
+typedef enum {
+ CLI_EVENT_MATCH_DEV = 1,//搜索到匹配的设备
+ CLI_EVENT_CONNECTED, //设备连接成功
+ CLI_EVENT_DISCONNECT,//设备连接断开
+ CLI_EVENT_MATCH_UUID,//搜索到匹配的UUID
+ CLI_EVENT_SEARCH_PROFILE_COMPLETE, //搜索profile服务结束
+ CLI_EVENT_CONNECTION_UPDATE,//设备连接参数更新成功
+} le_client_event_e;
+
+
+typedef struct {
+ //服务16bit uuid,非0 代表uuid16格式,0--代表是uuid128格式,services_uuid128
+ u16 services_uuid16;
+ //服务16bit uuid,非0 代表uuid16格式,0--代表是uuid128格式,characteristic_uuid128
+ u16 characteristic_uuid16;
+ u8 services_uuid128[16];
+ u8 characteristic_uuid128[16];
+ u16 opt_type; //属性
+ u8 read_long_enable: 1; //en
+ u8 read_report_reference: 1; //en
+ u8 res_bits: 6; //
+} target_uuid_t;
+
+//搜索操作记录的 handle
+#define OPT_HANDLE_MAX 16
+typedef struct {
+ //匹配的UUID
+ target_uuid_t *search_uuid;
+ //可操作的handle
+ u16 value_handle;
+} opt_handle_t;
+
+//最大匹配的设备个数
+#define CLIENT_MATCH_CONN_MAX 3
+
+typedef struct {
+ u8 create_conn_mode; //cli_creat_mode_e
+ u8 bonding_flag; //连接过后会绑定,默认快连,不搜索设备
+ u8 compare_data_len; //匹配信息长度
+ const u8 *compare_data;//匹配信息,若是地址内容,由高到低位
+ u8 filter_pdu_bitmap; /*过滤指定的pdu包,不做匹配操作; bit map,event type*/
+} client_match_cfg_t;
+
+
+typedef struct {
+ //搜索匹配信息
+ const client_match_cfg_t *match_dev_cfg[CLIENT_MATCH_CONN_MAX];
+ //加密保定配置 0 or 1
+ u8 security_en;
+ //搜索服务的个数
+ u8 search_uuid_cnt; // <= OPT_HANDLE_MAX
+ //搜索服务
+ const target_uuid_t *search_uuid_table;
+ //回调处理接收到的 notify or indicate 数据
+ void (*report_data_callback)(att_data_report_t *data_report, target_uuid_t *search_uuid);
+ //主机一些事件回调处理
+ void (*event_callback)(le_client_event_e event, u8 *packet, int size);
+} client_conn_cfg_t;
+
+//清除绑定配对信息
+void client_clear_bonding_info(void);
+void client_send_conn_param_update(void);
+void ble_module_enable(u8 en);
+struct ble_client_operation_t *ble_get_client_operation_table(void);
+void bt_ble_init(void);
+void bt_ble_adv_enable(u8 enable);
+
+#endif
diff --git a/apps/common/third_party_profile/jieli/le_common.h b/apps/common/third_party_profile/jieli/le_common.h
new file mode 100644
index 0000000..81feeb8
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/le_common.h
@@ -0,0 +1,43 @@
+/*********************************************************************************************
+ * Filename : le_counter.h
+
+ * Description :
+
+ * Author : Bingquan
+
+ * Email : bingquan_cai@zh-jieli.com
+
+ * Last modifiled : 2017-01-17 15:17
+
+ * Copyright:(c)JIELI 2011-2016 @ , All Rights Reserved.
+*********************************************************************************************/
+
+#ifndef __LE_COMMON_H_
+#define __LE_COMMON_H_
+
+#include "typedef.h"
+#include
+#include "btstack/bluetooth.h"
+#include "app_config.h"
+#include "btstack/le/le_common_define.h"
+
+//--------------------------------------------
+#ifdef CONFIG_DEBUG_ENABLE
+#define LE_DEBUG_PRINT_EN 1 // log switch
+#else
+#define LE_DEBUG_PRINT_EN 0 // log switch
+#endif
+//--------------------------------------------
+
+/*毫秒 转换到 0.625ms 单位*/
+#define ADV_SCAN_MS(_ms) ((_ms) * 8 / 5)
+
+extern void bt_ble_init(void);
+extern void bt_ble_exit(void);
+extern void le_hogp_set_icon(u16 class_type);
+extern void le_hogp_set_ReportMap(u8 *map, u16 size);
+extern void ble_module_enable(u8 en);
+
+#endif
+
+
diff --git a/apps/common/third_party_profile/jieli/le_hogp.c b/apps/common/third_party_profile/jieli/le_hogp.c
new file mode 100644
index 0000000..e35045a
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/le_hogp.c
@@ -0,0 +1,1490 @@
+/*********************************************************************************************
+ * Filename : le_hogp.c
+
+ * Description :
+
+ * Author :
+
+ * Email : zh-jieli.com
+
+ * Last modifiled : 2020-09-01 11:14
+
+ * Copyright:(c)JIELI 2011-2020 @ , All Rights Reserved.
+*********************************************************************************************/
+
+// *****************************************************************************
+/* EXAMPLE_START
+ *
+ * @text All newer operating systems provide GATT Client functionality.
+ * The LE Counter examples demonstrates how to specify a minimal GATT Database
+ * with a custom GATT Service and a custom Characteristic that sends periodic
+ * notifications.
+ */
+// *****************************************************************************
+#include "system/app_core.h"
+#include "system/includes.h"
+
+#include "app_config.h"
+#include "app_action.h"
+
+#include "btstack/btstack_task.h"
+#include "btstack/bluetooth.h"
+#include "user_cfg.h"
+#include "vm.h"
+#include "btcontroller_modules.h"
+#include "bt_common.h"
+
+#include "le_common.h"
+#include "le_hogp.h"
+#include "standard_hid.h"
+
+#include "rcsp_bluetooth.h"
+#include "JL_rcsp_api.h"
+#include "update_loader_download.h"
+#include "custom_cfg.h"
+
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_HOGP)
+/* #if RCSP_BTMATE_EN */
+/* #include "btstack/JL_rcsp_api.h" */
+/* #include "rcsp_bluetooth.h" */
+/* #endif */
+
+
+#if 1
+extern void printf_buf(u8 *buf, u32 len);
+#define log_info printf
+#define log_info_hexdump printf_buf
+#else
+#define log_info(...)
+#define log_info_hexdump(...)
+#endif
+
+static void hid_timer_mouse_handler(void);
+
+#define EIR_TAG_STRING 0xd6, 0x05, 0x08, 0x00, 'J', 'L', 'A', 'I', 'S', 'D','K'
+static const char user_tag_string[] = {EIR_TAG_STRING};
+//用户可配对的,这是样机跟客户开发的app配对的秘钥
+//const u8 link_key_data[16] = {0x06, 0x77, 0x5f, 0x87, 0x91, 0x8d, 0xd4, 0x23, 0x00, 0x5d, 0xf1, 0xd8, 0xcf, 0x0c, 0x14, 0x2b};
+/* #define LOG_TAG_CONST BT_BLE */
+/* #define LOG_TAG "[LE_S_DEMO]" */
+/* #define LOG_ERROR_ENABLE */
+/* #define LOG_DEBUG_ENABLE */
+/* #define LOG_INFO_ENABLE */
+/* #define LOG_DUMP_ENABLE */
+/* #define LOG_CLI_ENABLE */
+/* #include "debug.h" */
+
+//------
+//ATT发送的包长, note: 20 <=need >= MTU
+#define ATT_LOCAL_MTU_SIZE (64)
+//ATT缓存的buffer大小, note: need >= 20,可修改
+#define ATT_SEND_CBUF_SIZE (256)
+
+//共配置的RAM
+#define ATT_RAM_BUFSIZE (ATT_CTRL_BLOCK_SIZE + ATT_LOCAL_MTU_SIZE + ATT_SEND_CBUF_SIZE) //note:
+static u8 att_ram_buffer[ATT_RAM_BUFSIZE] __attribute__((aligned(4)));
+//---------------
+int ble_hid_timer_handle = 0;
+//---------------
+// 广播周期 (unit:0.625ms)
+#define ADV_INTERVAL_MIN (160 * 1)//
+
+static volatile hci_con_handle_t con_handle;
+static u16 cur_conn_latency; //
+
+//加密设置
+/* static const uint8_t sm_min_key_size = 7; */
+
+//连接参数更新请求设置
+//是否使能参数请求更新,0--disable, 1--enable
+static uint8_t connection_update_enable = 1;
+static uint8_t connection_update_cnt = 0; //当前请求的参数表index
+static uint8_t connection_update_waiting = 0; //请求已被接收,等待主机更新参数
+
+//参数表
+static const struct conn_update_param_t Peripheral_Preferred_Connection_Parameters[] = {
+ {6, 9, 100, 600}, //android
+ {12, 12, 30, 400}, //ios
+};
+
+//共可用的参数组数
+#define CONN_PARAM_TABLE_CNT (sizeof(Peripheral_Preferred_Connection_Parameters)/sizeof(struct conn_update_param_t))
+
+#if (ATT_RAM_BUFSIZE < 64)
+#error "adv_data & rsp_data buffer error!!!!!!!!!!!!"
+#endif
+
+/* #define adv_data &att_ram_buffer[0] */
+/* #define scan_rsp_data &att_ram_buffer[32] */
+
+static u8 adv_data_len;
+static u8 adv_data[ADV_RSP_PACKET_MAX];//max is 31
+static u8 scan_rsp_data_len;
+static u8 scan_rsp_data[ADV_RSP_PACKET_MAX];//max is 31
+
+static char gap_device_name[BT_NAME_LEN_MAX] = "jl_ble_test";
+static u8 gap_device_name_len = 0; //名字长度,不包含结束符
+static u8 ble_work_state = 0; //ble 状态变化
+static u8 first_pair_flag = 0; //第一次配对标记
+static u8 is_hogp_active = 0; //不可进入sleep状态
+static u8 adv_ctrl_en; //广播控制
+static u16 adv_interval_val; //广播周期 (unit:0.625ms)
+
+//--------------------------------------------
+//配置有配对绑定时,先定向广播快连,再普通广播;否则只作普通广播
+#define PAIR_DIREDT_ADV_EN 1
+
+#define BLE_VM_HEAD_TAG (0xB35C)
+#define BLE_VM_TAIL_TAG (0x5CB3)
+struct pair_info_t {
+ u16 head_tag; //头标识
+ u8 pair_flag: 2; //配对信息是否有效
+ u8 direct_adv_flag: 1; //是否需要定向广播
+ u8 direct_adv_cnt: 5; //定向广播次数
+ u8 peer_address_info[7]; //绑定的对方地址信息
+ u16 tail_tag;//尾标识
+};
+
+//配对信息表
+static struct pair_info_t conn_pair_info;
+static u8 cur_peer_addr_info[7];//当前连接对方地址信息
+
+#define REPEAT_DIRECT_ADV_COUNT (2)// *1.28s
+#define REPEAT_DIRECT_ADV_TIMER (100)//
+
+//为了及时响应手机数据包,某些流程会忽略进入latency的控制
+//如下是定义忽略进入的interval个数
+#define LATENCY_SKIP_INTERVAL_MIN (3)
+#define LATENCY_SKIP_INTERVAL_KEEP (15)
+#define LATENCY_SKIP_INTERVAL_LONG (0xffff)
+
+//hid device infomation
+static u8 Appearance[] = {BLE_APPEARANCE_GENERIC_HID & 0xff, BLE_APPEARANCE_GENERIC_HID >> 8}; //
+static const char Manufacturer_Name_String[] = "zhuhai_jieli";
+static const char Model_Number_String[] = "hid_mouse";
+static const char Serial_Number_String[] = "000000";
+static const char Hardware_Revision_String[] = "0.0.1";
+static const char Firmware_Revision_String[] = "0.0.1";
+static const char Software_Revision_String[] = "0.0.1";
+static const u8 System_ID[] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+//定义的产品信息,for test
+#define PNP_VID_SOURCE 0x02
+#define PNP_VID 0x05ac //0x05d6
+#define PNP_PID 0x022C //
+#define PNP_PID_VERSION 0x011b //1.1.11
+
+static const u8 PnP_ID[] = {PNP_VID_SOURCE, PNP_VID & 0xFF, PNP_VID >> 8, PNP_PID & 0xFF, PNP_PID >> 8, PNP_PID_VERSION & 0xFF, PNP_PID_VERSION >> 8};
+/* static const u8 PnP_ID[] = {0x02, 0x17, 0x27, 0x40, 0x00, 0x23, 0x00}; */
+/* static const u8 PnP_ID[] = {0x02, 0xac, 0x05, 0x2c, 0x02, 0x1b, 0x01}; */
+
+/* static const u8 hid_information[] = {0x11, 0x01, 0x00, 0x01}; */
+static const u8 hid_information[] = {0x01, 0x01, 0x00, 0x03};
+
+static u8 *report_map; //描述符
+static u16 report_map_size;//描述符大小
+#define HID_REPORT_MAP_DATA report_map
+#define HID_REPORT_MAP_SIZE report_map_size
+
+//report 发生变化,通过service change 通知主机重新获取
+static u8 hid_report_change = 0;
+static u8 hid_battery_level = 88;
+
+static u8(*get_vbat_percent_call)(void) = NULL;
+//------------------------------------------------------
+static void (*app_recieve_callback)(void *priv, void *buf, u16 len) = NULL;
+static void (*app_ble_state_callback)(void *priv, ble_state_e state) = NULL;
+static void (*ble_resume_send_wakeup)(void) = NULL;
+static void (*le_hogp_output_callback)(u8 *buffer, u16 size) = NULL;
+static u32 channel_priv;//保留未用
+
+static int app_send_user_data_check(u16 len);
+static int app_send_user_data_do(void *priv, u8 *data, u16 len);
+static int app_send_user_data(u16 handle, u8 *data, u16 len, att_op_type_e handle_type);
+static void resume_all_ccc_enable(u8 update_request);
+static void check_report_map_change(void);
+
+// Complete Local Name 默认的蓝牙名字
+
+//------------------------------------------------------
+//广播参数设置
+static void advertisements_setup_init();
+static int set_adv_enable(void *priv, u32 en);
+static int get_buffer_remain_len(void *priv);
+static void ble_check_need_pair_adv(void);
+void ble_hid_transfer_channel_recieve(u8 *packet, u16 size);
+//------------------------------------------------------
+//------------------------------------------------------
+static void ble_bt_evnet_post(u32 arg_type, u8 priv_event, u8 *args, u32 value)
+{
+ struct sys_event e;
+ e.type = SYS_BT_EVENT;
+ e.arg = (void *)arg_type;
+ e.u.bt.event = priv_event;
+ if (args) {
+ memcpy(e.u.bt.args, args, 7);
+ }
+ e.u.bt.value = value;
+ sys_event_notify(&e);
+}
+
+static void ble_state_to_user(u8 state, u8 reason)
+{
+ ble_bt_evnet_post(SYS_BT_EVENT_BLE_STATUS, state, NULL, reason);
+}
+
+//@function 检测连接参数是否需要更新
+static void check_connetion_updata_deal(void)
+{
+ static struct conn_update_param_t param;
+ if (connection_update_enable) {
+ if (connection_update_cnt < CONN_PARAM_TABLE_CNT) {
+ memcpy(¶m, &Peripheral_Preferred_Connection_Parameters[connection_update_cnt], sizeof(struct conn_update_param_t)); //static ram
+ log_info("update_request:-%d-%d-%d-%d-\n", param.interval_min, param.interval_max, param.latency, param.timeout);
+ if (con_handle) {
+ ble_op_conn_param_request(con_handle, (u32)¶m);
+ }
+ }
+ }
+}
+
+//@function 接参数更新信息
+static void connection_update_complete_success(u8 *packet, u8 connected_init)
+{
+ int conn_interval, conn_latency, conn_timeout;
+
+ conn_interval = hci_subevent_le_connection_update_complete_get_conn_interval(packet);
+ conn_latency = hci_subevent_le_connection_update_complete_get_conn_latency(packet);
+ conn_timeout = hci_subevent_le_connection_update_complete_get_supervision_timeout(packet);
+
+ log_info("conn_interval = %d\n", conn_interval);
+ log_info("conn_latency = %d\n", conn_latency);
+ log_info("conn_timeout = %d\n", conn_timeout);
+
+ if (connected_init) {
+ if (conn_pair_info.pair_flag
+ && (conn_latency && (0 == memcmp(conn_pair_info.peer_address_info, packet - 1, 7)))) { //
+ //有配对信息,带latency连接,快速enable ccc 发数
+ log_info("reconnect ok\n");
+ resume_all_ccc_enable(0);
+ }
+ } else {
+ //not creat connection,judge
+ if ((conn_interval == 12) && (conn_latency == 4)) {
+ log_info("do update_again\n");
+ connection_update_cnt = 1;
+ check_connetion_updata_deal();
+ } else if ((conn_latency == 0)
+ && (connection_update_cnt == CONN_PARAM_TABLE_CNT)
+ && (Peripheral_Preferred_Connection_Parameters[0].latency != 0)) {
+ log_info("latency is 0,update_again\n");
+ connection_update_cnt = 0;
+ check_connetion_updata_deal();
+ }
+ }
+
+ cur_conn_latency = conn_latency;
+
+ if (ble_hid_timer_handle) {
+ sys_s_hi_timer_modify(ble_hid_timer_handle, (u32)(conn_interval * 1.25));
+ }
+}
+
+static void set_ble_work_state(ble_state_e state, u8 reason)
+{
+ if (state != ble_work_state) {
+ log_info("ble_work_st:%x->%x\n", ble_work_state, state);
+ ble_work_state = state;
+ if (app_ble_state_callback) {
+ app_ble_state_callback((void *)channel_priv, state);
+ }
+ ble_state_to_user(state, reason);
+ }
+}
+
+static ble_state_e get_ble_work_state(void)
+{
+ return ble_work_state;
+}
+
+static void conn_pair_vm_do(struct pair_info_t *info, u8 rw_flag)
+{
+#if PAIR_DIREDT_ADV_EN
+ int ret;
+ int vm_len = sizeof(struct pair_info_t);
+
+ log_info("-conn_pair_info vm_do:%d\n", rw_flag);
+ if (rw_flag == 0) {
+ ret = syscfg_read(CFG_BLE_MODE_INFO, (u8 *)info, vm_len);
+ if (!ret) {
+ log_info("-null--\n");
+ }
+
+ if ((BLE_VM_HEAD_TAG == info->head_tag) && (BLE_VM_TAIL_TAG == info->tail_tag)) {
+ log_info("-exist--\n");
+ log_info_hexdump((u8 *)info, vm_len);
+ info->direct_adv_flag = 1;
+ } else {
+ memset(info, 0, vm_len);
+ info->head_tag = BLE_VM_HEAD_TAG;
+ info->tail_tag = BLE_VM_TAIL_TAG;
+ }
+ } else {
+ info->direct_adv_flag = 1;
+ syscfg_write(CFG_BLE_MODE_INFO, (u8 *)info, vm_len);
+ }
+#endif
+}
+
+//检测是否需要定向广播
+static void ble_check_need_pair_adv(void)
+{
+#if PAIR_DIREDT_ADV_EN
+ log_info("%s\n", __FUNCTION__);
+ if (conn_pair_info.pair_flag && conn_pair_info.direct_adv_flag) {
+ conn_pair_info.direct_adv_cnt = REPEAT_DIRECT_ADV_COUNT;
+ }
+#endif
+}
+
+
+//协议栈sm 消息回调处理
+static void cbk_sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
+{
+ sm_just_event_t *event = (void *)packet;
+ u32 tmp32;
+ switch (packet_type) {
+ case HCI_EVENT_PACKET:
+ switch (hci_event_packet_get_type(packet)) {
+ case SM_EVENT_JUST_WORKS_REQUEST:
+ sm_just_works_confirm(sm_event_just_works_request_get_handle(packet));
+ log_info("Just Works Confirmed.\n");
+ first_pair_flag = 1;
+ memcpy(conn_pair_info.peer_address_info, &packet[4], 7);
+ conn_pair_info.pair_flag = 0;
+ ble_op_latency_skip(con_handle, LATENCY_SKIP_INTERVAL_KEEP); //
+ ble_state_to_user(BLE_PRIV_MSG_PAIR_CONFIRM, 0);
+ break;
+ case SM_EVENT_PASSKEY_DISPLAY_NUMBER:
+ log_info_hexdump(packet, size);
+ memcpy(&tmp32, event->data, 4);
+ log_info("Passkey display: %06u.\n", tmp32);
+ ble_state_to_user(BLE_PRIV_MSG_PAIR_CONFIRM, 1);
+ break;
+ }
+ break;
+ }
+}
+
+static const u16 change_handle_table[2] = {ATT_CHARACTERISTIC_2a4b_01_VALUE_HANDLE, ATT_CHARACTERISTIC_2a4b_01_VALUE_HANDLE};
+static void check_report_map_change(void)
+{
+#if 0 //部分手机不支持
+ if (hid_report_change && first_pair_flag && att_get_ccc_config(ATT_CHARACTERISTIC_2a05_01_CLIENT_CONFIGURATION_HANDLE)) {
+ log_info("###send services changed\n");
+ app_send_user_data(ATT_CHARACTERISTIC_2a05_01_VALUE_HANDLE, change_handle_table, 4, ATT_OP_INDICATE);
+ hid_report_change = 0;
+ }
+#endif
+}
+
+//回连状态,主动使能通知
+static void resume_all_ccc_enable(u8 update_request)
+{
+ log_info("resume_all_ccc_enable\n");
+ att_set_ccc_config(ATT_CHARACTERISTIC_2a4d_01_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY);
+ att_set_ccc_config(ATT_CHARACTERISTIC_2a4d_02_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY);
+ att_set_ccc_config(ATT_CHARACTERISTIC_2a4d_04_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY);
+ att_set_ccc_config(ATT_CHARACTERISTIC_2a4d_05_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY);
+ att_set_ccc_config(ATT_CHARACTERISTIC_2a4d_06_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY);
+ att_set_ccc_config(ATT_CHARACTERISTIC_2a4d_07_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY);
+ att_set_ccc_config(ATT_CHARACTERISTIC_ae42_01_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY);
+
+ set_ble_work_state(BLE_ST_NOTIFY_IDICATE, 0);
+ if (update_request) {
+ check_connetion_updata_deal();
+ ble_op_latency_skip(con_handle, LATENCY_SKIP_INTERVAL_MIN); //
+ }
+}
+
+//协议栈回调唤醒数据发送
+static void can_send_now_wakeup(void)
+{
+ /* putchar('E'); */
+ if (ble_resume_send_wakeup) {
+ ble_resume_send_wakeup();
+ }
+}
+
+
+//参考识别手机系统
+static void att_check_remote_result(u16 con_handle, remote_type_e remote_type)
+{
+ log_info("le_hogp %02x:remote_type= %02x\n", con_handle, remote_type);
+ ble_bt_evnet_post(SYS_BT_EVENT_FORM_COMMON, COMMON_EVENT_BLE_REMOTE_TYPE, NULL, remote_type);
+ //to do
+}
+/*
+ * @section Packet Handler
+ *
+ * @text The packet handler is used to:
+ * - stop the counter after a disconnect
+ * - send a notification when the requested ATT_EVENT_CAN_SEND_NOW is received
+ */
+
+/* LISTING_START(packetHandler): Packet Handler */
+//协议栈事件消息处理
+static void cbk_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
+{
+ int mtu;
+ u32 tmp;
+
+ switch (packet_type) {
+ case HCI_EVENT_PACKET:
+ switch (hci_event_packet_get_type(packet)) {
+
+ /* case DAEMON_EVENT_HCI_PACKET_SENT: */
+ /* break; */
+ case ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE:
+ log_info("ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE\n");
+ case ATT_EVENT_CAN_SEND_NOW:
+ can_send_now_wakeup();
+ break;
+
+ case HCI_EVENT_LE_META:
+ switch (hci_event_le_meta_get_subevent_code(packet)) {
+ case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: {
+ switch (packet[3]) {
+ case BT_OP_SUCCESS:
+ //init
+ first_pair_flag = 0;
+ connection_update_cnt = 0;
+ connection_update_waiting = 0;
+ cur_conn_latency = 0;
+ connection_update_enable = 1;
+
+ con_handle = little_endian_read_16(packet, 4);
+ log_info("HCI_SUBEVENT_LE_CONNECTION_COMPLETE: %0x\n", con_handle);
+ ble_op_att_send_init(con_handle, att_ram_buffer, ATT_RAM_BUFSIZE, ATT_LOCAL_MTU_SIZE);
+
+ log_info_hexdump(packet + 7, 7);
+ memcpy(cur_peer_addr_info, packet + 7, 7);
+ ble_op_latency_skip(con_handle, LATENCY_SKIP_INTERVAL_KEEP); //
+
+ set_ble_work_state(BLE_ST_CONNECT, 0);
+ connection_update_complete_success(packet + 8, 1);
+
+ //清除PC端历史键值
+ /* extern void clear_mouse_packet_data(void); */
+ /* sys_timeout_add(NULL, clear_mouse_packet_data, 50); */
+#if RCSP_BTMATE_EN
+#if (0 == BT_CONNECTION_VERIFY)
+ JL_rcsp_auth_reset();
+#endif
+ /* rcsp_dev_select(RCSP_BLE); */
+ rcsp_init();
+#endif
+ /* att_server_set_exchange_mtu(con_handle); //主动请求交换MTU */
+ /* ble_vendor_interval_event_enable(con_handle, 1); //enable interval事件-->HCI_SUBEVENT_LE_VENDOR_INTERVAL_COMPLETE */
+ break;
+
+ case BT_ERR_ADVERTISING_TIMEOUT:
+ //定向广播超时结束
+ log_info("BT_ERR_ADVERTISING_TIMEOUT\n");
+ set_ble_work_state(BLE_ST_IDLE, 0);
+
+ bt_ble_adv_enable(1);
+
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE:
+ connection_update_waiting = 0;
+ connection_update_complete_success(packet, 0);
+ break;
+
+ case HCI_SUBEVENT_LE_VENDOR_INTERVAL_COMPLETE:
+ log_info("INTERVAL_EVENT:%04x,%04x\n", little_endian_read_16(packet, 4), little_endian_read_16(packet, 6));
+ /* put_buf(packet, size + 1); */
+ break;
+
+ }
+ break;
+
+ case HCI_EVENT_DISCONNECTION_COMPLETE:
+ log_info("HCI_EVENT_DISCONNECTION_COMPLETE: %0x\n", packet[5]);
+#if RCSP_BTMATE_EN
+ rcsp_exit();
+#endif
+ con_handle = 0;
+
+ ble_op_att_send_init(con_handle, 0, 0, 0);
+ /* bt_ble_adv_enable(1); */
+ set_ble_work_state(BLE_ST_DISCONN, packet[5]);
+ if (UPDATE_MODULE_IS_SUPPORT(UPDATE_BLE_TEST_EN)) {
+ if (!ble_update_get_ready_jump_flag()) {
+ if (packet[5] == 0x08) {
+ //超时断开,检测是否配对广播
+ ble_check_need_pair_adv();
+ }
+ bt_ble_adv_enable(1);
+ } else {
+ log_info("no open adv\n");
+ }
+ }
+ break;
+
+ case ATT_EVENT_MTU_EXCHANGE_COMPLETE:
+ mtu = att_event_mtu_exchange_complete_get_MTU(packet) - 3;
+ log_info("ATT MTU = %u\n", mtu);
+ ble_op_att_set_send_mtu(mtu);
+ break;
+
+ case HCI_EVENT_VENDOR_REMOTE_TEST:
+ log_info("--- HCI_EVENT_VENDOR_REMOTE_TEST\n");
+ break;
+
+ case L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE:
+ tmp = little_endian_read_16(packet, 4);
+ log_info("-update_rsp: %02x\n", tmp);
+ if (tmp) {
+ connection_update_cnt++;
+ log_info("remoter reject!!!\n");
+ check_connetion_updata_deal();
+ } else {
+ connection_update_waiting = 1;
+ connection_update_cnt = CONN_PARAM_TABLE_CNT;
+ }
+ break;
+
+ case HCI_EVENT_ENCRYPTION_CHANGE:
+ log_info("HCI_EVENT_ENCRYPTION_CHANGE= %d\n", packet[2]);
+ if (!packet[2]) {
+ if (first_pair_flag) {
+ //只在配对时启动检查
+ att_server_set_check_remote(con_handle, att_check_remote_result);
+#if PAIR_DIREDT_ADV_EN
+ conn_pair_info.pair_flag = 1;
+ conn_pair_vm_do(&conn_pair_info, 1);
+#endif
+ } else {
+ if ((!conn_pair_info.pair_flag) || memcmp(cur_peer_addr_info, conn_pair_info.peer_address_info, 7)) {
+ log_info("record reconnect peer\n");
+ put_buf(cur_peer_addr_info, 7);
+ put_buf(conn_pair_info.peer_address_info, 7);
+ memcpy(conn_pair_info.peer_address_info, cur_peer_addr_info, 7);
+ conn_pair_info.pair_flag = 1;
+ conn_pair_vm_do(&conn_pair_info, 1);
+ }
+ resume_all_ccc_enable(1);
+
+ //回连时,从配对表中获取
+ u8 tmp_buf[6];
+ u8 remote_type = 0;
+ swapX(&cur_peer_addr_info[1], tmp_buf, 6);
+ ble_list_get_remote_type(tmp_buf, cur_peer_addr_info[0], &remote_type);
+ log_info("list's remote_type:%d\n", remote_type);
+ att_check_remote_result(con_handle, remote_type);
+ }
+ check_report_map_change();
+ ble_state_to_user(BLE_PRIV_PAIR_ENCRYPTION_CHANGE, first_pair_flag);
+ }
+ break;
+ }
+ break;
+ }
+}
+
+
+/* LISTING_END */
+
+/*
+ * @section ATT Read
+ *
+ * @text The ATT Server handles all reads to constant data. For dynamic data like the custom characteristic, the registered
+ * att_read_callback is called. To handle long characteristics and long reads, the att_read_callback is first called
+ * with buffer == NULL, to request the total value length. Then it will be called again requesting a chunk of the value.
+ * See Listing attRead.
+ */
+
+/* LISTING_START(attRead): ATT Read */
+
+// ATT Client Read Callback for Dynamic Data
+// - if buffer == NULL, don't copy data, just return size of value
+// - if buffer != NULL, copy data and return number bytes copied
+// @param offset defines start of attribute value
+
+//主机操作ATT read,协议栈回调处理
+static uint16_t att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset, uint8_t *buffer, uint16_t buffer_size)
+{
+
+ uint16_t att_value_len = 0;
+ uint16_t handle = att_handle;
+
+ log_info("read_callback, handle= 0x%04x,buffer= %08x\n", handle, (u32)buffer);
+
+ switch (handle) {
+ case ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE:
+ att_value_len = gap_device_name_len;
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+
+ if (buffer) {
+ memcpy(buffer, &gap_device_name[offset], buffer_size);
+ att_value_len = buffer_size;
+ log_info("\n------read gap_name: %s \n", gap_device_name);
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_2a01_01_VALUE_HANDLE:
+ att_value_len = sizeof(Appearance);
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+ if (buffer) {
+ memcpy(buffer, &Appearance[offset], buffer_size);
+ att_value_len = buffer_size;
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_2a04_01_VALUE_HANDLE:
+ att_value_len = 8;//fixed
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+ if (buffer) {
+ log_info("\n------get Peripheral_Preferred_Connection_Parameters\n");
+ memcpy(buffer, &Peripheral_Preferred_Connection_Parameters[0], buffer_size);
+ att_value_len = buffer_size;
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_2a29_01_VALUE_HANDLE:
+ att_value_len = strlen(Manufacturer_Name_String);
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+ if (buffer) {
+ memcpy(buffer, &Manufacturer_Name_String[offset], buffer_size);
+ att_value_len = buffer_size;
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_2a24_01_VALUE_HANDLE:
+ att_value_len = strlen(Model_Number_String);
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+ if (buffer) {
+ memcpy(buffer, &Model_Number_String[offset], buffer_size);
+ att_value_len = buffer_size;
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_2a25_01_VALUE_HANDLE:
+ att_value_len = strlen(Serial_Number_String);
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+ if (buffer) {
+ memcpy(buffer, &Serial_Number_String[offset], buffer_size);
+ att_value_len = buffer_size;
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_2a27_01_VALUE_HANDLE:
+ att_value_len = strlen(Hardware_Revision_String);
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+ if (buffer) {
+ memcpy(buffer, &Hardware_Revision_String[offset], buffer_size);
+ att_value_len = buffer_size;
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_2a26_01_VALUE_HANDLE:
+ att_value_len = strlen(Firmware_Revision_String);
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+ if (buffer) {
+ memcpy(buffer, &Firmware_Revision_String[offset], buffer_size);
+ att_value_len = buffer_size;
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_2a28_01_VALUE_HANDLE:
+ att_value_len = strlen(Software_Revision_String);
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+ if (buffer) {
+ memcpy(buffer, &Software_Revision_String[offset], buffer_size);
+ att_value_len = buffer_size;
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_2a23_01_VALUE_HANDLE:
+ att_value_len = sizeof(System_ID);
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+ if (buffer) {
+ memcpy(buffer, &System_ID[offset], buffer_size);
+ att_value_len = buffer_size;
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_2a50_01_VALUE_HANDLE:
+ log_info("read PnP_ID\n");
+ att_value_len = sizeof(PnP_ID);
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+ if (buffer) {
+ memcpy(buffer, &PnP_ID[offset], buffer_size);
+ att_value_len = buffer_size;
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_2a19_01_VALUE_HANDLE:
+ att_value_len = 1;
+ if (buffer) {
+ if (get_vbat_percent_call) {
+ hid_battery_level = get_vbat_percent_call();
+ }
+ buffer[0] = hid_battery_level;
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_2a4b_01_VALUE_HANDLE:
+ att_value_len = HID_REPORT_MAP_SIZE;
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+ if (buffer) {
+ memcpy(buffer, &HID_REPORT_MAP_DATA[offset], buffer_size);
+ att_value_len = buffer_size;
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_2a4a_01_VALUE_HANDLE:
+ att_value_len = sizeof(hid_information);
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+ if (buffer) {
+ memcpy(buffer, &hid_information[offset], buffer_size);
+ att_value_len = buffer_size;
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_2a05_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_2a19_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_2a4d_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_2a4d_02_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_2a4d_04_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_2a4d_05_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_2a4d_06_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_2a4d_07_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_ae42_01_CLIENT_CONFIGURATION_HANDLE:
+ if (buffer) {
+ buffer[0] = att_get_ccc_config(handle);
+ buffer[1] = 0;
+ }
+ att_value_len = 2;
+ break;
+
+ default:
+ break;
+ }
+
+ log_info("att_value_len= %d\n", att_value_len);
+ return att_value_len;
+
+}
+
+
+/* LISTING_END */
+/*
+ * @section ATT Write
+ *
+ * @text The only valid ATT write in this example is to the Client Characteristic Configuration, which configures notification
+ * and indication. If the ATT handle matches the client configuration handle, the new configuration value is stored and used
+ * in the heartbeat handler to decide if a new value should be sent. See Listing attWrite.
+ */
+
+/* LISTING_START(attWrite): ATT Write */
+//主机操作ATT write,协议栈回调处理
+static int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size)
+{
+ int result = 0;
+ u16 tmp16;
+
+ u16 handle = att_handle;
+
+ log_info("write_callback, handle= 0x%04x,size = %d\n", handle, buffer_size);
+
+ switch (handle) {
+
+ case ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE:
+ break;
+
+ case ATT_CHARACTERISTIC_2a4d_03_VALUE_HANDLE:
+ put_buf(buffer, buffer_size); //键盘led灯状态
+ if (le_hogp_output_callback) {
+ le_hogp_output_callback(buffer, buffer_size);
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_2a05_01_CLIENT_CONFIGURATION_HANDLE:
+ att_set_ccc_config(handle, buffer[0]);
+ if (buffer[0]) {
+ check_report_map_change();
+ }
+ break;
+
+#if RCSP_BTMATE_EN
+ case ATT_CHARACTERISTIC_ae02_01_CLIENT_CONFIGURATION_HANDLE:
+#if (0 == BT_CONNECTION_VERIFY)
+ JL_rcsp_auth_reset(); //hid设备试能nofity的时候reset auth保证APP可以重新连接
+#endif
+
+#if (TCFG_HID_AUTO_SHUTDOWN_TIME)
+ ble_bt_evnet_post(SYS_BT_EVENT_FORM_COMMON, COMMON_EVENT_SHUTDOWN_DISABLE, NULL, 0);
+ /* auto_shutdown_disable(); */
+#endif
+#endif
+
+ case ATT_CHARACTERISTIC_ae42_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_2a4d_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_2a4d_02_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_2a4d_04_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_2a4d_05_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_2a4d_06_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_2a4d_07_CLIENT_CONFIGURATION_HANDLE:
+ set_ble_work_state(BLE_ST_NOTIFY_IDICATE, 0);
+ ble_op_latency_skip(con_handle, LATENCY_SKIP_INTERVAL_MIN); //
+ case ATT_CHARACTERISTIC_2a19_01_CLIENT_CONFIGURATION_HANDLE:
+ if ((cur_conn_latency == 0)
+ && (connection_update_waiting == 0)
+ && (connection_update_cnt == CONN_PARAM_TABLE_CNT)
+ && (Peripheral_Preferred_Connection_Parameters[0].latency != 0)) {
+ connection_update_cnt = 0;//update again
+ }
+ check_connetion_updata_deal();
+ log_info("\n------write ccc:%04x,%02x\n", handle, buffer[0]);
+ att_set_ccc_config(handle, buffer[0]);
+ break;
+
+#if RCSP_BTMATE_EN
+ case ATT_CHARACTERISTIC_ae01_01_VALUE_HANDLE:
+ log_info("rcsp_read:%x 0x%x\n", buffer_size, app_recieve_callback);
+ connection_update_enable = 0;
+ ble_op_latency_skip(con_handle, LATENCY_SKIP_INTERVAL_LONG); //
+ if (app_recieve_callback) {
+ app_recieve_callback(0, buffer, buffer_size);
+ }
+ break;
+#endif
+
+ case ATT_CHARACTERISTIC_ae41_01_VALUE_HANDLE:
+ ble_hid_transfer_channel_recieve(buffer, buffer_size);
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+//att handle操作,notify or indicate
+static int app_send_user_data(u16 handle, u8 *data, u16 len, att_op_type_e handle_type)
+{
+ u32 ret = APP_BLE_NO_ERROR;
+
+ if (!con_handle) {
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+ putchar('@');
+ /* put_buf(data, len); */
+
+ ret = ble_op_att_send_data(handle, data, len, handle_type);
+ if (ret == BLE_BUFFER_FULL) {
+ ret = APP_BLE_BUFF_FULL;
+ }
+
+ if (ret) {
+ log_info("app_send_fail:%d !!!\n", ret);
+ }
+ return ret;
+}
+
+//------------------------------------------------------
+static u8 adv_name_ok = 0; //名字优先放入adv包
+static int make_set_adv_data(void)
+{
+ u8 offset = 0;
+ u8 *buf = adv_data;
+
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x06, 1);
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_16BIT_SERVICE_UUIDS, HID_UUID_16, 2);
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_APPEARANCE_DATA, Appearance, 2);
+
+ //check set name is ok?
+ u8 name_len = gap_device_name_len;
+ u8 vaild_len = ADV_RSP_PACKET_MAX - (offset + 2);
+
+ if (name_len <= vaild_len) {
+ adv_name_ok = 1;
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, (void *)gap_device_name, name_len);
+ log_info("name in adv_data\n");
+ } else {
+ adv_name_ok = 0;
+ }
+
+ if (offset > ADV_RSP_PACKET_MAX) {
+ puts("***adv_data overflow!!!!!!\n");
+ return -1;
+ }
+ log_info("adv_data(%d):", offset);
+ log_info_hexdump(buf, offset);
+ adv_data_len = offset;
+ ble_op_set_adv_data(offset, buf);
+ return 0;
+}
+
+static int make_set_rsp_data(void)
+{
+ u8 offset = 0;
+ u8 *buf = scan_rsp_data;
+
+#if RCSP_BTMATE_EN
+ u8 tag_len = sizeof(user_tag_string);
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_MANUFACTURER_SPECIFIC_DATA, (void *)user_tag_string, tag_len);
+#endif
+
+ if (!adv_name_ok) {
+ u8 name_len = gap_device_name_len;
+ u8 vaild_len = ADV_RSP_PACKET_MAX - (offset + 2);
+ if (name_len > vaild_len) {
+ name_len = vaild_len;
+ }
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, (void *)gap_device_name, name_len);
+ log_info("name in rsp_data\n");
+ }
+
+ if (offset > ADV_RSP_PACKET_MAX) {
+ puts("***rsp_data overflow!!!!!!\n");
+ return -1;
+ }
+
+ log_info("rsp_data(%d):", offset);
+ log_info_hexdump(buf, offset);
+ scan_rsp_data_len = offset;
+ ble_op_set_rsp_data(offset, buf);
+ return 0;
+}
+
+
+//广播参数设置
+static void advertisements_setup_init()
+{
+ uint8_t adv_type = ADV_IND;
+ uint8_t adv_channel = ADV_CHANNEL_ALL;
+ int ret = 0;
+
+ ret |= make_set_adv_data();
+ ret |= make_set_rsp_data();
+
+ if (ret) {
+ puts("adv_setup_init fail !!!!!!\n");
+ ASSERT(0);
+ }
+
+ if (conn_pair_info.pair_flag && conn_pair_info.direct_adv_flag && conn_pair_info.direct_adv_cnt) {
+ log_info(">>>direct_adv......\n");
+ adv_type = ADV_DIRECT_IND;
+ conn_pair_info.direct_adv_cnt--;
+ ble_op_set_adv_param_ext(adv_interval_val, adv_type, adv_channel, conn_pair_info.peer_address_info);
+ } else {
+ ble_op_set_adv_param(adv_interval_val, adv_type, adv_channel);
+ }
+
+}
+
+#define PASSKEY_ENTER_ENABLE 0 //输入passkey使能,可修改passkey
+//重设passkey回调函数,在这里可以重新设置passkey
+//passkey为6个数字组成,十万位、万位。。。。个位 各表示一个数字 高位不够为0
+static void reset_passkey_cb(u32 *key)
+{
+#if 1
+ u32 newkey = rand32();//获取随机数
+
+ newkey &= 0xfffff;
+ if (newkey > 999999) {
+ newkey = newkey - 999999; //不能大于999999
+ }
+ *key = newkey; //小于或等于六位数
+ log_info("set new_key= %06u\n", *key);
+#else
+ *key = 123456; //for debug
+#endif
+}
+
+void ble_sm_setup_init(io_capability_t io_type, u8 auth_req, uint8_t min_key_size, u8 security_en)
+{
+ //setup SM: Display only
+ sm_init();
+ sm_set_io_capabilities(io_type);
+ sm_set_authentication_requirements(auth_req);
+ sm_set_encryption_key_size_range(min_key_size, 16);
+ /* sm_set_request_security(security_en); */
+ sm_event_callback_set(&cbk_sm_packet_handler);
+
+ if (io_type == IO_CAPABILITY_DISPLAY_ONLY) {
+ reset_PK_cb_register(reset_passkey_cb);
+ }
+}
+
+static int set_adv_enable(void *priv, u32 en)
+{
+ ble_state_e next_state, cur_state;
+
+ if (!adv_ctrl_en && en) {
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+ if (con_handle) {
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+ if (en) {
+ next_state = BLE_ST_ADV;
+ } else {
+ next_state = BLE_ST_IDLE;
+ }
+
+ cur_state = get_ble_work_state();
+ switch (cur_state) {
+ case BLE_ST_ADV:
+ case BLE_ST_IDLE:
+ case BLE_ST_INIT_OK:
+ case BLE_ST_NULL:
+ case BLE_ST_DISCONN:
+ break;
+ default:
+ return APP_BLE_OPERATION_ERROR;
+ break;
+ }
+
+ if (cur_state == next_state) {
+ return APP_BLE_NO_ERROR;
+ }
+ log_info("adv_en:%d\n", en);
+ set_ble_work_state(next_state, 0);
+ if (en) {
+ advertisements_setup_init();//need to do before adv_en
+ }
+ ble_op_adv_enable(en);
+ return APP_BLE_NO_ERROR;
+}
+
+
+
+#define HOGP_TCFG_BLE_SECURITY_EN 0/*是否发请求加密命令*/
+void ble_profile_init(void)
+{
+ log_info("ble profile init\n");
+ le_device_db_init();
+
+#if PASSKEY_ENTER_ENABLE
+ ble_sm_setup_init(IO_CAPABILITY_DISPLAY_ONLY, SM_AUTHREQ_BONDING | SM_AUTHREQ_MITM_PROTECTION, 7, HOGP_TCFG_BLE_SECURITY_EN);
+#else
+ ble_sm_setup_init(IO_CAPABILITY_NO_INPUT_NO_OUTPUT, SM_AUTHREQ_BONDING | SM_AUTHREQ_MITM_PROTECTION, 7, HOGP_TCFG_BLE_SECURITY_EN);
+#endif
+
+ /* setup ATT server */
+ att_server_init(profile_data, att_read_callback, att_write_callback);
+ att_server_register_packet_handler(cbk_packet_handler);
+ /* gatt_client_register_packet_handler(packet_cbk); */
+
+ // register for HCI events
+ hci_event_callback_set(&cbk_packet_handler);
+ /* ble_l2cap_register_packet_handler(packet_cbk); */
+ /* sm_event_packet_handler_register(packet_cbk); */
+ le_l2cap_register_packet_handler(&cbk_packet_handler);
+ /* att_server_flow_enable(1); */
+
+ ble_vendor_set_default_att_mtu(ATT_LOCAL_MTU_SIZE);
+}
+
+
+
+static int ble_disconnect(void *priv)
+{
+ if (con_handle) {
+ if (BLE_ST_SEND_DISCONN != get_ble_work_state()) {
+ log_info(">>>ble send disconnect\n");
+ set_ble_work_state(BLE_ST_SEND_DISCONN, 0);
+ ble_op_disconnect(con_handle);
+ } else {
+ log_info(">>>ble wait disconnect...\n");
+ }
+ return APP_BLE_NO_ERROR;
+ } else {
+ return APP_BLE_OPERATION_ERROR;
+ }
+}
+
+static int get_buffer_remain_len(void *priv)
+{
+ u32 vaild_len = 0;
+ ble_op_att_get_remain(&vaild_len);
+ return vaild_len;
+}
+
+static int app_send_user_data_do(void *priv, u8 *data, u16 len)
+{
+ return app_send_user_data(HID_REPORT_ID_01_SEND_HANDLE, data, len, ATT_OP_AUTO_READ_CCC);
+}
+
+#if RCSP_BTMATE_EN
+static int rcsp_send_user_data_do(void *priv, u8 *data, u16 len)
+{
+ log_info("rcsp_tx:%x\n", len);
+ return app_send_user_data(ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE, data, len, ATT_OP_AUTO_READ_CCC);
+}
+#endif
+
+static int app_send_user_data_check(u16 len)
+{
+ u32 buf_space = get_buffer_remain_len(0);
+ if (len <= buf_space) {
+ return 1;
+ }
+ return 0;
+}
+
+
+static int regiest_wakeup_send(void *priv, void *cbk)
+{
+ ble_resume_send_wakeup = cbk;
+ return APP_BLE_NO_ERROR;
+}
+
+static int regiest_recieve_cbk(void *priv, void *cbk)
+{
+ channel_priv = (u32)priv;
+ app_recieve_callback = cbk;
+ return APP_BLE_NO_ERROR;
+}
+
+static int regiest_state_cbk(void *priv, void *cbk)
+{
+ channel_priv = (u32)priv;
+ app_ble_state_callback = cbk;
+ return APP_BLE_NO_ERROR;
+}
+
+
+static u8 hogp_idle_query(void)
+{
+ return !is_hogp_active;
+}
+
+REGISTER_LP_TARGET(le_hogp_target) = {
+ .name = "le_hogp",
+ .is_idle = hogp_idle_query,
+};
+
+void modify_ble_name(const char *name)
+{
+ if (strlen(name) <= BT_NAME_LEN_MAX) {
+ memset(gap_device_name, 0x0, BT_NAME_LEN_MAX);
+ memcpy(gap_device_name, name, strlen(name));
+ gap_device_name_len = strlen(gap_device_name);
+ log_info(">>>modify_ble_name:%s\n", gap_device_name);
+ }
+}
+
+static const char ble_ext_name[] = "(BLE)";
+void bt_ble_init(void)
+{
+ log_info("***** ble_init******\n");
+ log_info("ble_file: %s", __FILE__);
+ adv_ctrl_en = 0;
+ con_handle = 0;
+ adv_interval_val = ADV_INTERVAL_MIN;
+
+#if 1
+ char name_p[LOCAL_NAME_LEN] = "JL_HID(BLE)";
+ u8 ext_name_len = sizeof(ble_ext_name) - 1;
+
+ int ret = syscfg_read(CFG_BT_NAME, name_p, 32);
+ if (ret < 0) {
+ log_info("read bt name err\n");
+ } else {
+
+ }
+ gap_device_name_len = strlen(name_p);
+ if (gap_device_name_len > (BT_NAME_LEN_MAX - ext_name_len)) {
+ gap_device_name_len = BT_NAME_LEN_MAX - ext_name_len;
+ }
+
+ //增加后缀,区分名字
+ memcpy(gap_device_name, name_p, gap_device_name_len);
+ memcpy(&gap_device_name[gap_device_name_len], ble_ext_name, ext_name_len);
+ gap_device_name_len += ext_name_len;
+#else
+
+ const char name_p[] = "std_mouse";
+ u8 ext_name_len = sizeof(ble_ext_name);
+
+ gap_device_name_len = sizeof(name_p) - 1;
+ memcpy(gap_device_name, name_p, gap_device_name_len);
+ memcpy(&gap_device_name[gap_device_name_len], ble_ext_name, ext_name_len);
+ gap_device_name_len += ext_name_len;
+#endif
+
+ log_info("ble name(%d): %s \n", gap_device_name_len, gap_device_name);
+
+ memset(&conn_pair_info, 0, sizeof(struct pair_info_t));
+ conn_pair_vm_do(&conn_pair_info, 0);
+ adv_interval_val = ADV_INTERVAL_MIN;
+ set_ble_work_state(BLE_ST_INIT_OK, 0);
+
+}
+
+
+void bt_ble_exit(void)
+{
+ log_info("***** ble_exit******\n");
+ if (ble_hid_timer_handle) {
+ sys_s_hi_timer_del(ble_hid_timer_handle);
+ ble_hid_timer_handle = 0;
+ }
+ ble_module_enable(0);
+}
+
+void bt_ble_adv_enable(u8 enable)
+{
+ set_adv_enable(0, enable);
+}
+
+u8 *ble_get_scan_rsp_ptr(u16 *len)
+{
+ if (len) {
+ *len = scan_rsp_data_len;
+ }
+ return scan_rsp_data;
+}
+
+u8 *ble_get_adv_data_ptr(u16 *len)
+{
+ if (len) {
+ *len = adv_data_len;
+ }
+ return adv_data;
+}
+
+u8 *ble_get_gatt_profile_data(u16 *len)
+{
+ *len = sizeof(profile_data);
+ return (u8 *)profile_data;
+}
+
+
+void ble_app_disconnect(void)
+{
+ ble_disconnect(NULL);
+}
+
+void ble_module_enable(u8 en)
+{
+ log_info("mode_en:%d\n", en);
+ if (en) {
+ adv_ctrl_en = 1;
+ ble_check_need_pair_adv();
+ bt_ble_adv_enable(1);
+ } else {
+ if (con_handle) {
+ adv_ctrl_en = 0;
+ ble_op_latency_skip(con_handle, LATENCY_SKIP_INTERVAL_KEEP); //
+ ble_app_disconnect();
+ } else {
+ bt_ble_adv_enable(0);
+ adv_ctrl_en = 0;
+ }
+ }
+}
+
+
+#if RCSP_BTMATE_EN
+static const struct ble_server_operation_t mi_ble_operation = {
+ .adv_enable = set_adv_enable,
+ .disconnect = ble_disconnect,
+ .get_buffer_vaild = get_buffer_remain_len,
+ .send_data = (void *)rcsp_send_user_data_do,
+ .regist_wakeup_send = regiest_wakeup_send,
+ .regist_recieve_cbk = regiest_recieve_cbk,
+ .regist_state_cbk = regiest_state_cbk,
+};
+#else
+static const struct ble_server_operation_t mi_ble_operation = {
+ .adv_enable = set_adv_enable,
+ .disconnect = ble_disconnect,
+ .get_buffer_vaild = get_buffer_remain_len,
+ .send_data = (void *)app_send_user_data_do,
+ .regist_wakeup_send = regiest_wakeup_send,
+ .regist_recieve_cbk = regiest_recieve_cbk,
+ .regist_state_cbk = regiest_state_cbk,
+};
+#endif
+
+void ble_get_server_operation_table(struct ble_server_operation_t **interface_pt)
+{
+ *interface_pt = (void *)&mi_ble_operation;
+}
+
+void ble_server_send_test_key_num(u8 key_num)
+{
+ if (con_handle) {
+ if (get_remote_test_flag()) {
+ ble_op_test_key_num(con_handle, key_num);
+ } else {
+ log_info("-not conn testbox\n");
+ }
+ }
+}
+
+void le_hogp_set_icon(u16 class_type)
+{
+ memcpy(Appearance, &class_type, 2);
+}
+
+void le_hogp_set_ReportMap(u8 *map, u16 size)
+{
+ report_map = map;
+ report_map_size = size;
+ hid_report_change = 1;
+}
+
+void le_hogp_set_output_callback(void *cb)
+{
+ le_hogp_output_callback = cb;
+}
+
+//配对绑定配置
+void le_hogp_set_pair_config(u8 pair_max, u8 is_allow_cover)
+{
+ ble_list_config_reset(pair_max, is_allow_cover); //开1对1配对绑定
+}
+//开可配对绑定允许
+void le_hogp_set_pair_allow(void)
+{
+ conn_pair_info.pair_flag = 0;
+ conn_pair_vm_do(&conn_pair_info, 1);
+ ble_list_clear_all();
+}
+
+void le_hogp_regiest_get_battery(u8(*get_battery_cbk)(void))
+{
+ get_vbat_percent_call = get_battery_cbk;
+}
+
+int ble_hid_is_connected(void)
+{
+ return con_handle;
+}
+
+u8 *ble_cur_connect_addrinfo(void)
+{
+ return cur_peer_addr_info;
+}
+
+static const u16 report_id_handle_table[] = {
+ 0,
+ HID_REPORT_ID_01_SEND_HANDLE,
+ HID_REPORT_ID_02_SEND_HANDLE,
+ HID_REPORT_ID_03_SEND_HANDLE,
+ HID_REPORT_ID_04_SEND_HANDLE,
+ HID_REPORT_ID_05_SEND_HANDLE,
+ HID_REPORT_ID_06_SEND_HANDLE,
+};
+
+int ble_hid_data_send(u8 report_id, u8 *data, u16 len)
+{
+ if (report_id == 0 || report_id > 6) {
+ log_info("report_id %d,err!!!\n", report_id);
+ return -1;
+ }
+ return app_send_user_data(report_id_handle_table[report_id], data, len, ATT_OP_AUTO_READ_CCC);
+}
+
+void ble_hid_key_deal_test(u16 key_msg)
+{
+ if (key_msg) {
+ ble_hid_data_send(1, &key_msg, 2);
+ key_msg = 0;//key release
+ ble_hid_data_send(1, &key_msg, 2);
+ }
+}
+
+int ble_hid_transfer_channel_send(u8 *packet, u16 size)
+{
+ /* log_info("transfer_tx(%d):", size); */
+ /* log_info_hexdump(packet, size); */
+ return app_send_user_data(ATT_CHARACTERISTIC_ae42_01_VALUE_HANDLE, packet, size, ATT_OP_AUTO_READ_CCC);
+}
+
+void __attribute__((weak)) ble_hid_transfer_channel_recieve(u8 *packet, u16 size)
+{
+ log_info("transfer_rx(%d):", size);
+ log_info_hexdump(packet, size);
+ //ble_hid_transfer_channel_send(packet,size);//for test
+}
+
+//控制配对模式
+void ble_set_pair_list_control(u8 mode)
+{
+ bool ret = 0;
+ u8 connect_address[6];
+ switch (mode) {
+ case 0:
+ //close pair,关配对
+ ret = ble_list_pair_accept(0);
+ break;
+
+ case 1:
+ //open pair,开配对
+ ret = ble_list_pair_accept(1);
+ break;
+
+ case 2:
+ //绑定已配对设备,不再接受新的配对
+ swapX(&cur_peer_addr_info[1], connect_address, 6);
+ //bond current's device
+ ret = ble_list_bonding_remote(connect_address, cur_peer_addr_info[0]);
+ //close pair
+ ble_list_pair_accept(0);
+ break;
+
+ default:
+ break;
+ }
+ log_info("%s: %02x,ret=%02x\n", __FUNCTION__, mode, ret);
+}
+
+
+#endif
+
+
diff --git a/apps/common/third_party_profile/jieli/le_hogp.h b/apps/common/third_party_profile/jieli/le_hogp.h
new file mode 100644
index 0000000..25ca60c
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/le_hogp.h
@@ -0,0 +1,352 @@
+// binary representation
+// attribute size in bytes (16), flags(16), handle (16), uuid (16/128), value(...)
+
+#ifndef _LE_HOGP_H
+#define _LE_HOGP_H
+
+#include
+#include "app_config.h"
+
+//
+// gatt profile include file, generated by jieli gatt_inc_generator.exe
+//
+
+static const uint8_t profile_data[] = {
+ //////////////////////////////////////////////////////
+ //
+ // 0x0001 PRIMARY_SERVICE 1800
+ //
+ //////////////////////////////////////////////////////
+ 0x0a, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x28, 0x00, 0x18,
+
+ /* CHARACTERISTIC, 2a00, READ | DYNAMIC, */
+ // 0x0002 CHARACTERISTIC 2a00 READ | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x28, 0x02, 0x03, 0x00, 0x00, 0x2a,
+ // 0x0003 VALUE 2a00 READ | DYNAMIC
+ 0x08, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00, 0x2a,
+
+ /* CHARACTERISTIC, 2a01, READ | DYNAMIC, */
+ // 0x0004 CHARACTERISTIC 2a01 READ | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x04, 0x00, 0x03, 0x28, 0x02, 0x05, 0x00, 0x01, 0x2a,
+ // 0x0005 VALUE 2a01 READ | DYNAMIC
+ 0x08, 0x00, 0x02, 0x01, 0x05, 0x00, 0x01, 0x2a,
+
+ /* CHARACTERISTIC, 2a04, READ | DYNAMIC, */
+ // 0x0006 CHARACTERISTIC 2a04 READ | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x06, 0x00, 0x03, 0x28, 0x02, 0x07, 0x00, 0x04, 0x2a,
+ // 0x0007 VALUE 2a04 READ | DYNAMIC
+ 0x08, 0x00, 0x02, 0x01, 0x07, 0x00, 0x04, 0x2a,
+
+ //////////////////////////////////////////////////////
+ //
+ // 0x0008 PRIMARY_SERVICE 1801
+ //
+ //////////////////////////////////////////////////////
+ 0x0a, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x28, 0x01, 0x18,
+
+ /* CHARACTERISTIC, 2a05, INDICATE, */
+ // 0x0009 CHARACTERISTIC 2a05 INDICATE
+ 0x0d, 0x00, 0x02, 0x00, 0x09, 0x00, 0x03, 0x28, 0x20, 0x0a, 0x00, 0x05, 0x2a,
+ // 0x000a VALUE 2a05 INDICATE
+ 0x08, 0x00, 0x20, 0x00, 0x0a, 0x00, 0x05, 0x2a,
+ // 0x000b CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x0b, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+ //////////////////////////////////////////////////////
+ //
+ // 0x000c PRIMARY_SERVICE 180a
+ //
+ //////////////////////////////////////////////////////
+ 0x0a, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x00, 0x28, 0x0a, 0x18,
+
+ /* CHARACTERISTIC, 2a29, READ | DYNAMIC, */
+ // 0x000d CHARACTERISTIC 2a29 READ | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x03, 0x28, 0x02, 0x0e, 0x00, 0x29, 0x2a,
+ // 0x000e VALUE 2a29 READ | DYNAMIC
+ 0x08, 0x00, 0x02, 0x01, 0x0e, 0x00, 0x29, 0x2a,
+
+ /* CHARACTERISTIC, 2a24, READ | DYNAMIC, */
+ // 0x000f CHARACTERISTIC 2a24 READ | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x03, 0x28, 0x02, 0x10, 0x00, 0x24, 0x2a,
+ // 0x0010 VALUE 2a24 READ | DYNAMIC
+ 0x08, 0x00, 0x02, 0x01, 0x10, 0x00, 0x24, 0x2a,
+
+ /* CHARACTERISTIC, 2a25, READ | DYNAMIC, */
+ // 0x0011 CHARACTERISTIC 2a25 READ | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x11, 0x00, 0x03, 0x28, 0x02, 0x12, 0x00, 0x25, 0x2a,
+ // 0x0012 VALUE 2a25 READ | DYNAMIC
+ 0x08, 0x00, 0x02, 0x01, 0x12, 0x00, 0x25, 0x2a,
+
+ /* CHARACTERISTIC, 2a27, READ | DYNAMIC, */
+ // 0x0013 CHARACTERISTIC 2a27 READ | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x13, 0x00, 0x03, 0x28, 0x02, 0x14, 0x00, 0x27, 0x2a,
+ // 0x0014 VALUE 2a27 READ | DYNAMIC
+ 0x08, 0x00, 0x02, 0x01, 0x14, 0x00, 0x27, 0x2a,
+
+ /* CHARACTERISTIC, 2a26, READ | DYNAMIC, */
+ // 0x0015 CHARACTERISTIC 2a26 READ | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x15, 0x00, 0x03, 0x28, 0x02, 0x16, 0x00, 0x26, 0x2a,
+ // 0x0016 VALUE 2a26 READ | DYNAMIC
+ 0x08, 0x00, 0x02, 0x01, 0x16, 0x00, 0x26, 0x2a,
+
+ /* CHARACTERISTIC, 2a28, READ | DYNAMIC, */
+ // 0x0017 CHARACTERISTIC 2a28 READ | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x17, 0x00, 0x03, 0x28, 0x02, 0x18, 0x00, 0x28, 0x2a,
+ // 0x0018 VALUE 2a28 READ | DYNAMIC
+ 0x08, 0x00, 0x02, 0x01, 0x18, 0x00, 0x28, 0x2a,
+
+ /* CHARACTERISTIC, 2a23, READ | DYNAMIC, */
+ // 0x0019 CHARACTERISTIC 2a23 READ | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x19, 0x00, 0x03, 0x28, 0x02, 0x1a, 0x00, 0x23, 0x2a,
+ // 0x001a VALUE 2a23 READ | DYNAMIC
+ 0x08, 0x00, 0x02, 0x01, 0x1a, 0x00, 0x23, 0x2a,
+
+ /* CHARACTERISTIC, 2a2a, READ | DYNAMIC, */
+ // 0x001b CHARACTERISTIC 2a2a READ | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x1b, 0x00, 0x03, 0x28, 0x02, 0x1c, 0x00, 0x2a, 0x2a,
+ // 0x001c VALUE 2a2a READ | DYNAMIC
+ 0x08, 0x00, 0x02, 0x01, 0x1c, 0x00, 0x2a, 0x2a,
+
+ /* CHARACTERISTIC, 2a50, READ | AUTHENTICATION_REQUIRED | DYNAMIC, */
+ // 0x001d CHARACTERISTIC 2a50 READ | AUTHENTICATION_REQUIRED | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x1d, 0x00, 0x03, 0x28, 0x02, 0x1e, 0x00, 0x50, 0x2a,
+ // 0x001e VALUE 2a50 READ | AUTHENTICATION_REQUIRED | DYNAMIC
+ 0x08, 0x00, 0x02, 0x05, 0x1e, 0x00, 0x50, 0x2a,
+
+ //////////////////////////////////////////////////////
+ //
+ // 0x001f PRIMARY_SERVICE 180f
+ //
+ //////////////////////////////////////////////////////
+ 0x0a, 0x00, 0x02, 0x00, 0x1f, 0x00, 0x00, 0x28, 0x0f, 0x18,
+
+ /* CHARACTERISTIC, 2a19, READ | DYNAMIC | NOTIFY, */
+ // 0x0020 CHARACTERISTIC 2a19 READ | DYNAMIC | NOTIFY
+ 0x0d, 0x00, 0x02, 0x00, 0x20, 0x00, 0x03, 0x28, 0x12, 0x21, 0x00, 0x19, 0x2a,
+ // 0x0021 VALUE 2a19 READ | DYNAMIC | NOTIFY
+ 0x08, 0x00, 0x12, 0x01, 0x21, 0x00, 0x19, 0x2a,
+ // 0x0022 CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x22, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+ //////////////////////////////////////////////////////
+ //
+ // 0x0023 PRIMARY_SERVICE 1812
+ //
+ //////////////////////////////////////////////////////
+ 0x0a, 0x00, 0x02, 0x00, 0x23, 0x00, 0x00, 0x28, 0x12, 0x18,
+
+ /* CHARACTERISTIC, 2a4e, READ | WRITE_WITHOUT_RESPONSE,01 */
+ // 0x0024 CHARACTERISTIC 2a4e READ | WRITE_WITHOUT_RESPONSE
+ 0x0d, 0x00, 0x02, 0x00, 0x24, 0x00, 0x03, 0x28, 0x06, 0x25, 0x00, 0x4e, 0x2a,
+ // 0x0025 VALUE 2a4e READ | WRITE_WITHOUT_RESPONSE 01
+ 0x09, 0x00, 0x06, 0x00, 0x25, 0x00, 0x4e, 0x2a, 0x01,
+
+ /* CHARACTERISTIC, 2a4d, READ | WRITE | NOTIFY | DYNAMIC, */
+ // 0x0026 CHARACTERISTIC 2a4d READ | WRITE | NOTIFY | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x26, 0x00, 0x03, 0x28, 0x1a, 0x27, 0x00, 0x4d, 0x2a,
+ // 0x0027 VALUE 2a4d READ | WRITE | NOTIFY | DYNAMIC
+ 0x08, 0x00, 0x1a, 0x01, 0x27, 0x00, 0x4d, 0x2a,
+ // 0x0028 CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x28, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+ /* 0x0029 REPORT_REFERENCE,01,01 */
+ 0x0a, 0x00, 0x02, 0x00, 0x29, 0x00, 0x08, 0x29, 0x01, 0x01,
+
+ /* CHARACTERISTIC, 2a4d, READ | WRITE | NOTIFY | DYNAMIC, */
+ // 0x002a CHARACTERISTIC 2a4d READ | WRITE | NOTIFY | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x2a, 0x00, 0x03, 0x28, 0x1a, 0x2b, 0x00, 0x4d, 0x2a,
+ // 0x002b VALUE 2a4d READ | WRITE | NOTIFY | DYNAMIC
+ 0x08, 0x00, 0x1a, 0x01, 0x2b, 0x00, 0x4d, 0x2a,
+ // 0x002c CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x2c, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+ /* 0x002d REPORT_REFERENCE,02,01 */
+ 0x0a, 0x00, 0x02, 0x00, 0x2d, 0x00, 0x08, 0x29, 0x02, 0x01,
+
+ /* CHARACTERISTIC, 2a4d, READ | WRITE | WRITE_WITHOUT_RESPONSE | DYNAMIC, */
+ // 0x002e CHARACTERISTIC 2a4d READ | WRITE | WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x2e, 0x00, 0x03, 0x28, 0x0e, 0x2f, 0x00, 0x4d, 0x2a,
+ // 0x002f VALUE 2a4d READ | WRITE | WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x08, 0x00, 0x0e, 0x01, 0x2f, 0x00, 0x4d, 0x2a,
+
+ /* 0x0030 REPORT_REFERENCE,01,02 */
+ 0x0a, 0x00, 0x02, 0x00, 0x30, 0x00, 0x08, 0x29, 0x01, 0x02,
+
+ /* CHARACTERISTIC, 2a4d, READ | WRITE | NOTIFY | DYNAMIC, */
+ // 0x0031 CHARACTERISTIC 2a4d READ | WRITE | NOTIFY | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x31, 0x00, 0x03, 0x28, 0x1a, 0x32, 0x00, 0x4d, 0x2a,
+ // 0x0032 VALUE 2a4d READ | WRITE | NOTIFY | DYNAMIC
+ 0x08, 0x00, 0x1a, 0x01, 0x32, 0x00, 0x4d, 0x2a,
+ // 0x0033 CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x33, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+ /* 0x0034 REPORT_REFERENCE,03,01 */
+ 0x0a, 0x00, 0x02, 0x00, 0x34, 0x00, 0x08, 0x29, 0x03, 0x01,
+
+ /* CHARACTERISTIC, 2a4d, READ | WRITE | NOTIFY | DYNAMIC, */
+ // 0x0035 CHARACTERISTIC 2a4d READ | WRITE | NOTIFY | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x35, 0x00, 0x03, 0x28, 0x1a, 0x36, 0x00, 0x4d, 0x2a,
+ // 0x0036 VALUE 2a4d READ | WRITE | NOTIFY | DYNAMIC
+ 0x08, 0x00, 0x1a, 0x01, 0x36, 0x00, 0x4d, 0x2a,
+ // 0x0037 CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x37, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+ /* 0x0038 REPORT_REFERENCE,04,01 */
+ 0x0a, 0x00, 0x02, 0x00, 0x38, 0x00, 0x08, 0x29, 0x04, 0x01,
+
+ /* CHARACTERISTIC, 2a4d, READ | WRITE | NOTIFY | DYNAMIC, */
+ // 0x0039 CHARACTERISTIC 2a4d READ | WRITE | NOTIFY | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x39, 0x00, 0x03, 0x28, 0x1a, 0x3a, 0x00, 0x4d, 0x2a,
+ // 0x003a VALUE 2a4d READ | WRITE | NOTIFY | DYNAMIC
+ 0x08, 0x00, 0x1a, 0x01, 0x3a, 0x00, 0x4d, 0x2a,
+ // 0x003b CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x3b, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+ /* 0x003c REPORT_REFERENCE,05,01 */
+ 0x0a, 0x00, 0x02, 0x00, 0x3c, 0x00, 0x08, 0x29, 0x05, 0x01,
+
+ /* CHARACTERISTIC, 2a4d, READ | WRITE | NOTIFY | DYNAMIC, */
+ // 0x003d CHARACTERISTIC 2a4d READ | WRITE | NOTIFY | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x3d, 0x00, 0x03, 0x28, 0x1a, 0x3e, 0x00, 0x4d, 0x2a,
+ // 0x003e VALUE 2a4d READ | WRITE | NOTIFY | DYNAMIC
+ 0x08, 0x00, 0x1a, 0x01, 0x3e, 0x00, 0x4d, 0x2a,
+ // 0x003f CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x3f, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+ /* 0x0040 REPORT_REFERENCE,06,01 */
+ 0x0a, 0x00, 0x02, 0x00, 0x40, 0x00, 0x08, 0x29, 0x06, 0x01,
+
+ /* CHARACTERISTIC, 2a4b, READ | DYNAMIC, */
+ // 0x0041 CHARACTERISTIC 2a4b READ | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x41, 0x00, 0x03, 0x28, 0x02, 0x42, 0x00, 0x4b, 0x2a,
+ // 0x0042 VALUE 2a4b READ | DYNAMIC
+ 0x08, 0x00, 0x02, 0x01, 0x42, 0x00, 0x4b, 0x2a,
+
+ /* CHARACTERISTIC, 2a33, READ | WRITE | NOTIFY, */
+ // 0x0043 CHARACTERISTIC 2a33 READ | WRITE | NOTIFY
+ 0x0d, 0x00, 0x02, 0x00, 0x43, 0x00, 0x03, 0x28, 0x1a, 0x44, 0x00, 0x33, 0x2a,
+ // 0x0044 VALUE 2a33 READ | WRITE | NOTIFY
+ 0x08, 0x00, 0x1a, 0x00, 0x44, 0x00, 0x33, 0x2a,
+ // 0x0045 CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x45, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+ /* CHARACTERISTIC, 2a4a, READ | DYNAMIC, */
+ // 0x0046 CHARACTERISTIC 2a4a READ | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x46, 0x00, 0x03, 0x28, 0x02, 0x47, 0x00, 0x4a, 0x2a,
+ // 0x0047 VALUE 2a4a READ | DYNAMIC
+ 0x08, 0x00, 0x02, 0x01, 0x47, 0x00, 0x4a, 0x2a,
+
+ /* CHARACTERISTIC, 2a4c, WRITE_WITHOUT_RESPONSE | DYNAMIC, */
+ // 0x0048 CHARACTERISTIC 2a4c WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x48, 0x00, 0x03, 0x28, 0x04, 0x49, 0x00, 0x4c, 0x2a,
+ // 0x0049 VALUE 2a4c WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x08, 0x00, 0x04, 0x01, 0x49, 0x00, 0x4c, 0x2a,
+
+ //////////////////////////////////////////////////////
+ //
+ // 0x004a PRIMARY_SERVICE ae40
+ //
+ //////////////////////////////////////////////////////
+ 0x0a, 0x00, 0x02, 0x00, 0x4a, 0x00, 0x00, 0x28, 0x40, 0xae,
+
+ /* CHARACTERISTIC, ae41, WRITE_WITHOUT_RESPONSE | DYNAMIC, */
+ // 0x004b CHARACTERISTIC ae41 WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x4b, 0x00, 0x03, 0x28, 0x04, 0x4c, 0x00, 0x41, 0xae,
+ // 0x004c VALUE ae41 WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x08, 0x00, 0x04, 0x01, 0x4c, 0x00, 0x41, 0xae,
+
+ /* CHARACTERISTIC, ae42, NOTIFY, */
+ // 0x004d CHARACTERISTIC ae42 NOTIFY
+ 0x0d, 0x00, 0x02, 0x00, 0x4d, 0x00, 0x03, 0x28, 0x10, 0x4e, 0x00, 0x42, 0xae,
+ // 0x004e VALUE ae42 NOTIFY
+ 0x08, 0x00, 0x10, 0x00, 0x4e, 0x00, 0x42, 0xae,
+ // 0x004f CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x4f, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+#if RCSP_BTMATE_EN
+ //////////////////////////////////////////////////////
+ //
+ // 0x0080 PRIMARY_SERVICE ae00
+ //
+ //////////////////////////////////////////////////////
+ 0x0a, 0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x28, 0x00, 0xae,
+
+ /* CHARACTERISTIC, ae01, WRITE_WITHOUT_RESPONSE | DYNAMIC, */
+ // 0x0081 CHARACTERISTIC ae01 WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x81, 0x00, 0x03, 0x28, 0x04, 0x82, 0x00, 0x01, 0xae,
+ // 0x0082 VALUE ae01 WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x08, 0x00, 0x04, 0x01, 0x82, 0x00, 0x01, 0xae,
+
+ /* CHARACTERISTIC, ae02, NOTIFY, */
+ // 0x0083 CHARACTERISTIC ae02 NOTIFY
+ 0x0d, 0x00, 0x02, 0x00, 0x83, 0x00, 0x03, 0x28, 0x10, 0x84, 0x00, 0x02, 0xae,
+ // 0x0084 VALUE ae02 NOTIFY
+ 0x08, 0x00, 0x10, 0x00, 0x84, 0x00, 0x02, 0xae,
+ // 0x0085 CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x85, 0x00, 0x02, 0x29, 0x00, 0x00,
+#endif
+ // END
+ 0x00, 0x00,
+};
+//
+// characteristics <--> handles
+//
+#define ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE 0x0003
+#define ATT_CHARACTERISTIC_2a01_01_VALUE_HANDLE 0x0005
+#define ATT_CHARACTERISTIC_2a04_01_VALUE_HANDLE 0x0007
+#define ATT_CHARACTERISTIC_2a05_01_VALUE_HANDLE 0x000a
+#define ATT_CHARACTERISTIC_2a05_01_CLIENT_CONFIGURATION_HANDLE 0x000b
+#define ATT_CHARACTERISTIC_2a29_01_VALUE_HANDLE 0x000e
+#define ATT_CHARACTERISTIC_2a24_01_VALUE_HANDLE 0x0010
+#define ATT_CHARACTERISTIC_2a25_01_VALUE_HANDLE 0x0012
+#define ATT_CHARACTERISTIC_2a27_01_VALUE_HANDLE 0x0014
+#define ATT_CHARACTERISTIC_2a26_01_VALUE_HANDLE 0x0016
+#define ATT_CHARACTERISTIC_2a28_01_VALUE_HANDLE 0x0018
+#define ATT_CHARACTERISTIC_2a23_01_VALUE_HANDLE 0x001a
+#define ATT_CHARACTERISTIC_2a2a_01_VALUE_HANDLE 0x001c
+#define ATT_CHARACTERISTIC_2a50_01_VALUE_HANDLE 0x001e
+#define ATT_CHARACTERISTIC_2a19_01_VALUE_HANDLE 0x0021
+#define ATT_CHARACTERISTIC_2a19_01_CLIENT_CONFIGURATION_HANDLE 0x0022
+#define ATT_CHARACTERISTIC_2a4e_01_VALUE_HANDLE 0x0025
+#define ATT_CHARACTERISTIC_2a4d_01_VALUE_HANDLE 0x0027
+#define ATT_CHARACTERISTIC_2a4d_01_CLIENT_CONFIGURATION_HANDLE 0x0028
+#define ATT_CHARACTERISTIC_2a4d_02_VALUE_HANDLE 0x002b
+#define ATT_CHARACTERISTIC_2a4d_02_CLIENT_CONFIGURATION_HANDLE 0x002c
+#define ATT_CHARACTERISTIC_2a4d_03_VALUE_HANDLE 0x002f
+#define ATT_CHARACTERISTIC_2a4d_04_VALUE_HANDLE 0x0032
+#define ATT_CHARACTERISTIC_2a4d_04_CLIENT_CONFIGURATION_HANDLE 0x0033
+#define ATT_CHARACTERISTIC_2a4d_05_VALUE_HANDLE 0x0036
+#define ATT_CHARACTERISTIC_2a4d_05_CLIENT_CONFIGURATION_HANDLE 0x0037
+#define ATT_CHARACTERISTIC_2a4d_06_VALUE_HANDLE 0x003a
+#define ATT_CHARACTERISTIC_2a4d_06_CLIENT_CONFIGURATION_HANDLE 0x003b
+#define ATT_CHARACTERISTIC_2a4d_07_VALUE_HANDLE 0x003e
+#define ATT_CHARACTERISTIC_2a4d_07_CLIENT_CONFIGURATION_HANDLE 0x003f
+#define ATT_CHARACTERISTIC_2a4b_01_VALUE_HANDLE 0x0042
+#define ATT_CHARACTERISTIC_2a33_01_VALUE_HANDLE 0x0044
+#define ATT_CHARACTERISTIC_2a33_01_CLIENT_CONFIGURATION_HANDLE 0x0045
+#define ATT_CHARACTERISTIC_2a4a_01_VALUE_HANDLE 0x0047
+#define ATT_CHARACTERISTIC_2a4c_01_VALUE_HANDLE 0x0049
+#define ATT_CHARACTERISTIC_ae41_01_VALUE_HANDLE 0x004c
+#define ATT_CHARACTERISTIC_ae42_01_VALUE_HANDLE 0x004e
+#define ATT_CHARACTERISTIC_ae42_01_CLIENT_CONFIGURATION_HANDLE 0x004f
+
+#if RCSP_BTMATE_EN
+#define ATT_CHARACTERISTIC_ae01_01_VALUE_HANDLE 0x0082
+#define ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE 0x0084
+#define ATT_CHARACTERISTIC_ae02_01_CLIENT_CONFIGURATION_HANDLE 0x0085
+#endif
+
+//INPUT
+#define HID_REPORT_ID_01_SEND_HANDLE ATT_CHARACTERISTIC_2a4d_01_VALUE_HANDLE
+#define HID_REPORT_ID_02_SEND_HANDLE ATT_CHARACTERISTIC_2a4d_02_VALUE_HANDLE
+#define HID_REPORT_ID_03_SEND_HANDLE ATT_CHARACTERISTIC_2a4d_04_VALUE_HANDLE
+#define HID_REPORT_ID_04_SEND_HANDLE ATT_CHARACTERISTIC_2a4d_05_VALUE_HANDLE
+#define HID_REPORT_ID_05_SEND_HANDLE ATT_CHARACTERISTIC_2a4d_06_VALUE_HANDLE
+#define HID_REPORT_ID_06_SEND_HANDLE ATT_CHARACTERISTIC_2a4d_07_VALUE_HANDLE
+
+//OUTPUT
+#define HID_REPORT_ID_01_RECIEVE_HANDLE ATT_CHARACTERISTIC_2a4d_03_VALUE_HANDLE
+
+
+#endif
+
diff --git a/apps/common/third_party_profile/jieli/online_db/online_db_deal.c b/apps/common/third_party_profile/jieli/online_db/online_db_deal.c
new file mode 100644
index 0000000..684c522
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/online_db/online_db_deal.c
@@ -0,0 +1,760 @@
+#include "app_config.h"
+#include "app_action.h"
+#include "system/includes.h"
+#include "string.h"
+#include "online_db_deal.h"
+#include "circular_buf.h"
+#include "bt_common.h"
+
+#if APP_ONLINE_DEBUG
+
+#define LOG_TAG_CONST ONLINE_DB
+#define LOG_TAG "[ONLINE_DB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#if (TCFG_AUDIO_DATA_EXPORT_ENABLE && (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SPP))
+#define DB_MEM_BUF_LEN (768 * 15)
+#else
+#define DB_MEM_BUF_LEN (768)
+#endif
+#define DB_ONE_PACKET_LEN (256)
+
+
+#define DB_PRINT_DATA_EN 0//是否上报串口打印数据
+#define DB_PRINT_DELAY_TYPE 0//0-timeout check,1-time check
+#define DB_PRINT_NOT_SEND_HEAD 0//
+
+#define DB_TIMER_SET (200) //unit:ms
+#define DB_PAYLOAD_MAXSIZE (253)
+#define DB_TMP_PACKET_LEN (660)
+
+#if DB_PRINT_DATA_EN
+#define DB_PRINT_BUFF_LEN (128)
+#endif
+
+#define cbuf_get_space(a) (a)->total_len
+
+enum {
+ DB_EVT_MSG_NULL = 0,
+ DB_EVT_MSG_SEND,
+};
+
+enum {
+ DB_TO_TYPE_PRINT = 0,
+};
+
+struct db_head_t {
+ u8 length;
+ u8 type;
+ u8 seq;
+ u8 data[0];
+} _GNU_PACKED_;
+
+struct db_online_info_t {
+ u16 db_timer;
+ u8 res_byte;
+ u8 seq;
+ int (*send_api)(u8 *packet, u16 size);
+ cbuffer_t send_cbuf;
+ u8 db_mem_buffer[DB_MEM_BUF_LEN];
+ u8 tmp_send_buf[DB_TMP_PACKET_LEN];
+ u16 tmp_data_len;
+ u8 tmp_recieve_buf[DB_ONE_PACKET_LEN];
+ u16 tmp_recieve_len;
+
+#if DB_PRINT_DATA_EN
+ u8 print_buffer[DB_PRINT_BUFF_LEN * 2];
+ volatile u8 *print_buf_prt;
+ volatile u16 print_count;
+#endif
+};
+
+static volatile u8 db_send_busy = 0;
+static volatile u8 db_timeout_type = 0;
+static volatile u16 print_record_count = 0;
+
+static struct db_online_info_t *online_global_info;
+#define __this (online_global_info)
+
+static int db_cb_api_table[DB_PKT_TYPE_MAX];
+static volatile u8 db_active = DB_COM_TYPE_NULL;
+
+#define JUST_THIS_IS_NULL() (__this == NULL)
+//-----------------------------------------------------
+extern void register_putbyte_hook(int (*hook_call)(char a));
+static void db_data_try_send(void);
+static void db_data_send_msg(int evt_msg);
+static void db_print_test_function(void);
+static void db_timeout_handle(int type);
+//-----------------------------------------------------
+//获取cbuff 数据
+static u16 db_data_read_sub(u8 *buf, u16 buf_size)
+{
+ u16 ret_len;
+ if (0 == cbuf_get_data_size(&__this->send_cbuf)) {
+ return 0;
+ }
+
+ OS_ENTER_CRITICAL();
+ if (cbuf_get_data_size(&__this->send_cbuf)) {//check again
+ cbuf_read(&__this->send_cbuf, &ret_len, 2);
+ if (ret_len && ret_len <= buf_size) {
+ cbuf_read(&__this->send_cbuf, buf, ret_len);
+ }
+ }
+ OS_EXIT_CRITICAL();
+
+ return ret_len;
+}
+
+//尝试发送cbuff 数据
+static void db_data_try_send(void)
+{
+ u16 send_len;
+
+ if (db_send_busy) {
+ return;
+ }
+ db_send_busy = 1;//hold
+
+ if (__this->tmp_data_len) {
+ /* log_info("send_tmp_data = %d",__this->tmp_data_len); */
+ if (__this->send_api) {
+ if (__this->send_api(__this->tmp_send_buf, __this->tmp_data_len)) {
+ db_send_busy = 0;//fail
+ return;
+ }
+ __this->tmp_data_len = 0;
+ }
+ }
+
+ send_len = db_data_read_sub(__this->tmp_send_buf, DB_TMP_PACKET_LEN);
+
+ if (send_len > DB_TMP_PACKET_LEN) {
+ printf("err:send_len= %d\n", send_len);
+ ASSERT(0);
+ }
+
+ if (send_len) {
+ /* log_info("send_buf_data = %d",send_len); */
+ if (__this->send_api(__this->tmp_send_buf, send_len)) {
+ __this->tmp_data_len = send_len;
+ db_send_busy = 0;//fail
+ }
+ } else {
+ //not send
+ db_send_busy = 0;
+ }
+}
+
+//写入数据到cbuff
+static u32 db_data_write_sub(u8 *head, u8 head_size, u8 *data, u16 len)
+{
+ u16 wlen = 0;
+ u16 total_len = 0;
+
+ if (!db_active) {
+ /* log_error("not active!"); */
+ return 0;
+ }
+
+ if (len > DB_ONE_PACKET_LEN) {
+ ASSERT(0);
+ }
+
+ total_len = head_size + len;
+
+ OS_ENTER_CRITICAL();
+ u16 buf_space = cbuf_get_space(&__this->send_cbuf) - cbuf_get_data_size(&__this->send_cbuf);
+ if (total_len + 2 > buf_space) {
+ /* log_error("cbuf full!"); */
+ OS_EXIT_CRITICAL();
+ return 0;
+ }
+
+ wlen = cbuf_write(&__this->send_cbuf, &total_len, 2);
+ if (head_size) {
+ wlen += cbuf_write(&__this->send_cbuf, head, head_size);
+ }
+ if (len) {
+ wlen += cbuf_write(&__this->send_cbuf, data, len);
+ }
+ OS_EXIT_CRITICAL();
+
+ /* db_data_try_send(); */
+ if (!db_send_busy) {
+ db_data_send_msg(DB_EVT_MSG_SEND);
+ }
+ return wlen;
+}
+
+//处理协议栈来数,分发到已注册模块解析处理
+static void db_packet_handle(u8 *packet, u8 size)
+{
+ if (!db_active) {
+ return;
+ }
+
+ struct db_head_t *db_ptr = (void *)packet;
+ int ret = -1;
+
+ if (db_ptr->length == 0) {
+ log_error("len=0");
+ return;
+ }
+
+
+ //判读是否需要缓存组包
+ if (__this->tmp_recieve_len) {
+ if (__this->tmp_recieve_len + size > DB_ONE_PACKET_LEN) {
+ log_error("rx_len_err:%d", __this->tmp_recieve_len + size);
+ __this->tmp_recieve_len = 0;
+ return;
+ }
+
+ memcpy(&__this->tmp_recieve_buf[__this->tmp_recieve_len], packet, size);
+ __this->tmp_recieve_len += size;
+ if (__this->tmp_recieve_len < db_ptr->length) {
+ /* putchar('<'); */
+ return;
+ }
+
+ db_ptr = (void *)&__this->tmp_recieve_buf;
+ packet = (void *)&__this->tmp_recieve_buf;
+ size = __this->tmp_recieve_len;
+ __this->tmp_recieve_len = 0;
+ /* putchar('>'); */
+ } else {
+ if (size < db_ptr->length) {
+ __this->tmp_recieve_len = size;
+ memcpy(&__this->tmp_recieve_buf, packet, size);
+ /* putchar('<'); */
+ return;
+ }
+ }
+
+ if (db_ptr->type == 0 || db_ptr->type >= DB_PKT_TYPE_MAX) {
+ log_error("type_err");
+ return;
+ }
+
+
+ /* int (*db_parse_data)(u8 *packet,u8 size,u8 *ext_data,ext_size); */
+ int (*db_parse_data)(u8 * packet, u8 size, u8 * ext_data, u16 ext_size) = (void *)(db_cb_api_table[db_ptr->type]);
+
+ if (db_parse_data) {
+ /* log_info("db_parse_data,%08x",db_parse_data); */
+
+ log_info("rx_data(%d):", size);
+ log_info_hexdump((void *)db_ptr, size);
+
+ u8 *tmp_buf_pt = malloc(DB_ONE_PACKET_LEN);
+ if (!tmp_buf_pt) {
+ log_error("malloc faill,drop data!!!");
+ return;
+ }
+
+ size -= 3;
+ //整理对齐
+ memcpy(tmp_buf_pt, db_ptr->data, size);
+ db_parse_data(tmp_buf_pt, size, &db_ptr->type, 2);
+ free(tmp_buf_pt);
+ }
+}
+
+
+//打印数据推送处理,需要临界保护
+static void db_print_send_deal(void)
+{
+#if DB_PRINT_DATA_EN
+ static volatile u8 send_flag = 0;
+ u16 tmp_len = 0;
+ u8 *tmp_buf;
+
+ if (send_flag) {
+ __this->print_count = 0;//drop data
+ return;
+ }
+
+ //乒乓buffer
+ OS_ENTER_CRITICAL();
+ send_flag = 1;
+ if (__this->print_count) { //check again
+ tmp_len = __this->print_count;
+ tmp_buf = __this->print_buf_prt;
+ if (__this->print_buf_prt == __this->print_buffer) {
+ __this->print_buf_prt = &__this->print_buffer[DB_PRINT_BUFF_LEN];
+ } else {
+ __this->print_buf_prt = __this->print_buffer;
+ }
+ __this->print_count = 0;
+ }
+ OS_EXIT_CRITICAL();
+ if (tmp_len) {
+ app_online_db_send(DB_PKT_TYPE_PRINT, tmp_buf, tmp_len);
+ }
+ send_flag = 0;
+#endif
+}
+
+//截取串口打印数据处理
+static int db_hook_put_byte(char a)
+{
+ int ret = 0; //0--keep uart,1--not uart
+
+#if DB_PRINT_DATA_EN
+ static volatile repeat_cnt = 0;
+
+ if (!db_active) {
+ return ret;
+ }
+
+ if (repeat_cnt) {
+ return ret;
+ }
+ repeat_cnt = 1;
+
+ if (__this->print_count > (DB_PRINT_BUFF_LEN - 4)) {
+ db_print_send_deal();
+ }
+ __this->print_buf_prt[__this->print_count++] = (u8)a;
+ repeat_cnt = 0;
+
+#if(0 == DB_PRINT_DELAY_TYPE)
+ if (0 == (db_timeout_type & BIT(DB_TO_TYPE_PRINT))) {
+ db_timeout_type |= BIT(DB_TO_TYPE_PRINT);
+ print_record_count = __this->print_count;
+ sys_timeout_add(DB_TO_TYPE_PRINT, db_timeout_handle, DB_TIMER_SET);
+ }
+#endif
+
+#endif
+ return ret;
+}
+
+#if(1 == DB_PRINT_DELAY_TYPE)
+//定义检测打印数据是否需要超时推送到上位机
+static void db_print_timer_handle(void)
+{
+#if DB_PRINT_DATA_EN
+ if (__this->print_count) {
+ if (print_record_count == __this->print_count) { //第二次检查相同才输出打印
+ db_print_send_deal();
+ } else {
+ print_record_count = __this->print_count;
+ }
+ }
+#endif
+}
+#endif
+
+//检测打印数据是否需要超时推送到上位机
+static void db_timeout_handle(int type)
+{
+#if DB_PRINT_DATA_EN
+#if(0 == DB_PRINT_DELAY_TYPE)
+ if (!db_active) {
+ return;
+ }
+
+ /* putchar('&'); */
+ if (type == DB_TO_TYPE_PRINT) {
+ if (__this->print_count) { //第二次检查相同才输出打印
+ if (print_record_count == __this->print_count) { //第二次检查相同才输出打印
+ db_timeout_type &= (~BIT(DB_TO_TYPE_PRINT));
+ db_print_send_deal();
+ } else {
+ print_record_count = __this->print_count;
+ sys_timeout_add(DB_TO_TYPE_PRINT, db_timeout_handle, DB_TIMER_SET);
+ }
+ } else {
+ db_timeout_type &= (~BIT(DB_TO_TYPE_PRINT));
+ }
+ }
+#endif
+#endif
+}
+
+/* static u8 test_buffer_data22[512]; */
+/* static void db_test_send_data(void) */
+/* { */
+/* app_online_db_send_more(0, test_buffer_data22, 512); */
+/* } */
+
+//上位机连上初始化
+static void db_init(db_com_e conn_type)
+{
+ if (db_active) {
+ return;
+ }
+
+ log_info("db_init");
+ if (JUST_THIS_IS_NULL()) {
+ __this = malloc(sizeof(struct db_online_info_t));
+ if (JUST_THIS_IS_NULL()) {
+ log_error("malloc faill!!!");
+ return;
+ }
+ log_info("malloc ok");
+ }
+
+ cbuf_init(&__this->send_cbuf, __this->db_mem_buffer, DB_MEM_BUF_LEN);
+
+#if(1 == DB_PRINT_DELAY_TYPE)
+ __this->db_timer = sys_timer_add(NULL, db_print_timer_handle, DB_TIMER_SET);
+#endif
+
+ __this->tmp_data_len = 0;
+ __this->tmp_recieve_len = 0;
+ db_send_busy = 0;
+
+#if DB_PRINT_DATA_EN
+ __this->print_count = 0;
+ __this->print_buf_prt = __this->print_buffer;
+ /* register_putbyte_hook(db_hook_put_byte); */
+#endif
+
+ db_active = conn_type;
+ //db_print_test_function();
+
+ /* for (int i = 0; i < 512; i++) { */
+ /* test_buffer_data22[i] = i; */
+ /* } */
+ /* sys_timer_add(0, db_test_send_data, 200); */
+ /* printf_buf(test_buffer_data22, 512); */
+}
+
+//上位断开,退出
+void db_exit(void)
+{
+ if (!db_active) {
+ return;
+ }
+
+ log_info("db_exit");
+ db_active = DB_COM_TYPE_NULL;
+
+#if(1 == DB_PRINT_DELAY_TYPE)
+ if (__this->db_timer) {
+ sys_timer_del(__this->db_timer);
+ __this->db_timer = 0;
+ }
+#endif
+
+#if DB_PRINT_DATA_EN
+ /* register_putbyte_hook(NULL); */
+#endif
+
+ OS_ENTER_CRITICAL();
+ cbuf_clear(&__this->send_cbuf);
+ free(__this);
+ __this = NULL;
+ OS_EXIT_CRITICAL();
+}
+
+
+//注册协议栈发送接口
+static void db_register_send_data(void *send_api_call)
+{
+ if (!db_active) {
+ return;
+ }
+ __this->send_api = send_api_call;
+}
+
+//协议栈发送完成,唤醒
+static void db_wakeup_send_data(void *send_api_call)
+{
+ if (!db_active) {
+ return;
+ }
+
+ db_send_busy = 0;//
+ db_data_try_send();
+}
+
+static void db_data_send_msg(int evt_msg)
+{
+ struct sys_event e;
+ e.type = SYS_DEVICE_EVENT;
+ e.arg = (void *)DEVICE_EVENT_ONLINE_DATA;
+ e.u.dev.event = 0;
+ e.u.dev.value = evt_msg;
+ sys_event_notify(&e);
+}
+
+struct db_online_api_t de_online_api_table = {
+ .init = db_init,
+ .exit = db_exit,
+ .packet_handle = db_packet_handle,
+ .register_send_data = db_register_send_data,
+ .send_wake_up = db_wakeup_send_data,
+};
+
+//获取接口列表
+struct db_online_api_t *app_online_get_api_table(void)
+{
+ return &de_online_api_table;
+}
+
+//注册模块解析函数
+void app_online_db_register_handle(db_pkt_e type, int (*db_parse_data)(u8 *packet, u8 size, u8 *ext_data, u16 ext_size))
+{
+ if (type == 0 || type >= DB_PKT_TYPE_MAX) {
+ log_error("reg_type_err");
+ return;
+ }
+ log_info("register_handle %d,%08x", type, db_parse_data);
+ db_cb_api_table[type] = (int)db_parse_data;
+}
+
+//获取可发送数据的长度
+int app_online_get_buf_remain(db_pkt_e type)
+{
+
+ if (!db_active) {
+ return 0;
+ }
+
+ int w_len = 0;
+ int head_size = 3;
+ int buf_space = cbuf_get_space(&__this->send_cbuf) - cbuf_get_data_size(&__this->send_cbuf);
+ int pack_size = head_size + DB_PAYLOAD_MAXSIZE;
+
+ if (buf_space <= head_size) {
+ w_len = 0;
+ } else if (buf_space < pack_size) {
+ w_len = buf_space - head_size;
+ } else {
+ w_len = (buf_space / pack_size) * DB_PAYLOAD_MAXSIZE;
+ buf_space = buf_space % pack_size;
+ if (buf_space > head_size) {
+ w_len += (buf_space - head_size);
+ }
+ }
+ return w_len;
+}
+
+//发送包,发送
+int app_online_db_send(db_pkt_e type, u8 *packet, u8 size)
+{
+ if (!db_active) {
+ return -1;
+ }
+
+ struct db_head_t db_ptr;
+ db_ptr.length = size + 2;
+ db_ptr.type = type;
+ db_ptr.seq = __this->seq++;
+ u8 head_size = 3;
+
+ if (!size) {
+ log_error("size err!!!");
+ return -2;
+ }
+
+#if (DB_PRINT_DATA_EN && DB_PRINT_NOT_SEND_HEAD)
+ if (DB_PKT_TYPE_PRINT == type) {
+ head_size = 0;//不发送头
+ }
+#endif
+
+ log_info("tx_data(%d):,type=%d", size, type);
+ log_info_hexdump(packet, size);
+
+ if (!db_data_write_sub(&db_ptr, head_size, packet, size)) {
+ log_error("full fail,%d,%d", type, size);
+ return -3;
+ }
+ return 0;
+}
+
+//发送包,发送
+int app_online_db_send_more(db_pkt_e type, u8 *packet, u16 size)
+{
+ if (!db_active) {
+ return -1;
+ }
+
+ struct db_head_t db_ptr;
+ u8 head_size = 3;
+
+ if (!size || size > 650) {
+ log_error("overflow!!!%d,%d", type, size);
+ return -2;
+ }
+
+ log_info("tx_more_data(%d):,type=%d", size, type);
+ log_info_hexdump(packet, size);
+
+ u16 need_buff_size = ((size / DB_PAYLOAD_MAXSIZE) * (DB_PAYLOAD_MAXSIZE + head_size));
+ u16 remain_size = size % DB_PAYLOAD_MAXSIZE;
+
+ if (remain_size) {
+ need_buff_size += (remain_size + head_size);
+ }
+
+ OS_ENTER_CRITICAL();
+ if (need_buff_size + 2 > app_online_get_buf_remain(type)) {
+ OS_EXIT_CRITICAL();
+ log_error("more full!!!");
+ return -3;
+ }
+
+ u16 payload_size;
+ db_ptr.type = type;
+ cbuf_write(&__this->send_cbuf, &need_buff_size, 2);
+
+ while (size) {
+ if (size > DB_PAYLOAD_MAXSIZE) {
+ payload_size = DB_PAYLOAD_MAXSIZE;
+ } else {
+ payload_size = size;
+ }
+ size -= payload_size;
+ db_ptr.length = payload_size + 2;
+ db_ptr.seq = __this->seq++;
+ cbuf_write(&__this->send_cbuf, &db_ptr, head_size);
+ cbuf_write(&__this->send_cbuf, packet, payload_size);
+ packet += payload_size;
+ }
+ OS_EXIT_CRITICAL();
+
+ db_data_try_send();
+ /* if (!db_send_busy) { */
+ /* db_data_send_msg(DB_EVT_MSG_SEND); */
+ /* } */
+ return 0;
+}
+
+
+//应答包,发送
+int app_online_db_ack(u8 seq, u8 *packet, u8 size)
+{
+ if (!db_active) {
+ return -1;
+ }
+
+ struct db_head_t db_ptr;
+ db_ptr.length = size + 2;
+ db_ptr.type = DB_PKT_TYPE_ACK;
+ db_ptr.seq = seq;
+
+ log_info("tx_ack(%d):,seq=%d", size, seq);
+ log_info_hexdump(packet, size);
+
+ if (!db_data_write_sub(&db_ptr, 3, packet, size)) {
+ log_error("send fail2,%d,%d", seq, size);
+ return -1;
+ }
+ return 0;
+}
+
+
+
+void app_online_event_handle(int evt_value)
+{
+ if (!db_active) {
+ return;
+ }
+
+ if (evt_value == DB_EVT_MSG_SEND) {
+ /* putchar('@'); */
+ db_data_try_send();
+ }
+}
+
+void app_online_putchar(char a)
+{
+ db_hook_put_byte(a);
+}
+
+void app_online_puts(char *str)
+{
+ while (*str != 0) {
+ db_hook_put_byte(*str++);
+ }
+}
+
+static void app_online_put_u4hex(unsigned char dat)
+{
+ dat = 0xf & dat;
+ if (dat > 9) {
+ app_online_putchar(dat - 10 + 'A');
+ } else {
+ app_online_putchar(dat + '0');
+ }
+}
+
+
+void app_online_put_u16hex(u16 dat)
+{
+ app_online_putchar('0');
+ app_online_putchar('x');
+
+ app_online_put_u4hex(dat >> 12);
+ app_online_put_u4hex(dat >> 8);
+ app_online_put_u4hex(dat >> 4);
+ app_online_put_u4hex(dat);
+
+ app_online_putchar(' ');
+}
+
+void app_online_put_u8hex(u8 dat)
+{
+ app_online_put_u4hex(dat >> 4);
+ app_online_put_u4hex(dat);
+ app_online_putchar(' ');
+}
+
+void app_online_put_u32hex(u32 dat)
+{
+ app_online_putchar('0');
+ app_online_putchar('x');
+
+ app_online_put_u4hex(dat >> 28);
+ app_online_put_u4hex(dat >> 24);
+ app_online_put_u4hex(dat >> 20);
+ app_online_put_u4hex(dat >> 16);
+ app_online_put_u4hex(dat >> 12);
+ app_online_put_u4hex(dat >> 8);
+ app_online_put_u4hex(dat >> 4);
+ app_online_put_u4hex(dat);
+
+ app_online_putchar(' ');
+}
+
+void app_online_put_buf(u8 *buf, u16 len)
+{
+ for (int i = 0; i < len; i++) {
+ if ((i % 16) == 0) {
+ app_online_putchar('\n') ;
+ }
+ app_online_put_u8hex(buf[i]) ;
+ }
+ app_online_putchar('\n') ;
+}
+
+static const u8 test_buffer_data[8] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+static void db_print_test_function(void)
+{
+ app_online_puts("print test start\n");
+ app_online_putchar('@');
+ app_online_put_u8hex(0x78);
+ app_online_put_u16hex(0x1234);
+ app_online_put_u32hex(0x33445566);
+ app_online_put_buf(test_buffer_data, 32);
+ app_online_puts("print test end\n");
+}
+
+
+
+#endif
+
+
+
diff --git a/apps/common/third_party_profile/jieli/online_db/online_db_deal.h b/apps/common/third_party_profile/jieli/online_db/online_db_deal.h
new file mode 100644
index 0000000..3c3124e
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/online_db/online_db_deal.h
@@ -0,0 +1,102 @@
+#ifndef __ONLINE_DB_DEAL_H__
+#define __ONLINE_DB_DEAL_H__
+#include "typedef.h"
+
+typedef enum {
+ DB_PKT_TYPE_ACK = 0,
+ DB_PKT_TYPE_PRINT,
+ DB_PKT_TYPE_EQ = 5,
+ DB_PKT_TYPE_ANC = 7,
+ DB_PKT_TYPE_AEC = 8,
+ DB_PKT_TYPE_EXPORT = 0x9,
+ DB_PKT_TYPE_TOUCH = 0xA,
+ DB_PKT_TYPE_DMS = 0xB,
+ DB_PKT_TYPE_SPK_EQ = 0xC,
+ DB_PKT_TYPE_DAT_CH0 = 0x10,
+ DB_PKT_TYPE_DAT_CH1,
+ DB_PKT_TYPE_DAT_CH2,
+ DB_PKT_TYPE_MIC_DUT = 0x20,/*麦克风测试功能*/
+ DB_PKT_TYPE_SPATIAL_EFFECT = 0x21, /*空间音效调试功能*/
+ DB_PKT_TYPE_MAX,
+} db_pkt_e;
+
+typedef enum {
+ DB_COM_TYPE_NULL = 0,
+ DB_COM_TYPE_SPP,
+ DB_COM_TYPE_BLE,
+} db_com_e;
+
+struct db_online_api_t {
+ void (*init)(db_com_e conn_type);
+ void (*exit)(void);
+ void (*register_send_data)(void *send_api);
+ void (*send_wake_up)(void);
+ int (*packet_handle)(u8 *packet, u16 size);
+};
+
+/*
+ @funtion 获取可写入缓存的数据长度
+ @param [in] type
+ @return 可写入的长度
+ */
+int app_online_get_buf_remain(db_pkt_e type);
+
+/*
+ @funtion 大数据包发送,超过253,会拆包,蓝牙一次发多包
+ @param [in] type
+ @param [in] packet 数据地址
+ @param [in] size 数据长度, range:1~512
+ @return 0 sucess,others fail
+ */
+int app_online_db_send_more(db_pkt_e type, u8 *packet, u16 size);
+
+
+/*
+ @funtion 数据包发送
+ @param [in] type
+ @param [in] packet 数据地址
+ @param [in] size 数据长度, range:1~253
+ @return 0 sucess,others fail
+ */
+int app_online_db_send(db_pkt_e type, u8 *packet, u8 size);
+
+/*
+ @funtion 应答包发送
+ @param [in] seq 应答对应接收包数据的seq值
+ @param [in] packet 数据地址
+ @param [in] size 数据长度, range:1~253
+ @return 0 sucess,others fail
+ */
+int app_online_db_ack(u8 seq, u8 *packet, u8 size);
+
+/*
+ @funtion 注册接收数据包类型的处理函数
+ @param [in] type
+ @param [in] db_parse_datap, funtion to callback
+
+ int (*db_parse_data)(u8 *packet, u8 size, u8 *ext_data, u16 ext_size)
+ @param [in] packet 数据地址
+ @param [in] size 数据长度, range:1~253
+ @param [in] ext_data ,协议层head的起始地址,db_head_t
+ @param [in] ext_size ,数据 0~2
+ @return 0 sucess,others fail
+
+ */
+void app_online_db_register_handle(db_pkt_e type, int (*db_parse_data)(u8 *packet, u8 size, u8 *ext_data, u16 ext_size));
+
+/*
+ @funtion get api funtion
+ @return api_funtion point.
+ */
+struct db_online_api_t *app_online_get_api_table(void);
+
+
+//debug printf,提供简单打印接口
+void app_online_putchar(char a);
+void app_online_puts(char *str);
+void app_online_put_u8hex(u8 dat);
+void app_online_put_u16hex(u16 dat);
+void app_online_put_u32hex(u32 dat);
+void app_online_put_buf(u8 *buf, u16 len);
+
+#endif//
diff --git a/apps/common/third_party_profile/jieli/online_db/spp_online_db.c b/apps/common/third_party_profile/jieli/online_db/spp_online_db.c
new file mode 100644
index 0000000..b827c67
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/online_db/spp_online_db.c
@@ -0,0 +1,133 @@
+
+#include "app_config.h"
+#include "app_action.h"
+
+#include "system/includes.h"
+#include "spp_user.h"
+#include "string.h"
+#include "circular_buf.h"
+#include "bt_common.h"
+#include "online_db_deal.h"
+#include "spp_online_db.h"
+
+#if (TCFG_ANC_TOOL_DEBUG_ONLINE && TCFG_AUDIO_ANC_ENABLE)
+#include "app_anctool.h"
+#endif
+
+
+#if 1
+extern void printf_buf(u8 *buf, u32 len);
+#define log_info printf
+#define log_info_hexdump printf_buf
+#else
+#define log_info(...)
+#define log_info_hexdump(...)
+#endif
+
+#if APP_ONLINE_DEBUG
+
+static struct db_online_api_t *db_api;
+static struct spp_operation_t *spp_api = NULL;
+static u8 spp_state;
+
+int online_spp_send_data(u8 *data, u16 len)
+{
+ if (spp_api) {
+ /* log_info("spp_api_tx(%d) \n", len); */
+ /* log_info_hexdump(data, len); */
+ return spp_api->send_data(NULL, data, len);
+ }
+ return SPP_USER_ERR_SEND_FAIL;
+}
+
+int online_spp_send_data_check(u16 len)
+{
+ if (spp_api) {
+ if (spp_api->busy_state()) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void online_spp_state_cbk(u8 state)
+{
+ spp_state = state;
+ switch (state) {
+ case SPP_USER_ST_CONNECT:
+ log_info("SPP_USER_ST_CONNECT ~~~\n");
+ db_api->init(DB_COM_TYPE_SPP);
+ db_api->register_send_data(online_spp_send_data);
+#if (TCFG_ANC_TOOL_DEBUG_ONLINE && TCFG_AUDIO_ANC_ENABLE)
+ app_anctool_spp_connect();
+#endif
+ break;
+
+ case SPP_USER_ST_DISCONN:
+ log_info("SPP_USER_ST_DISCONN ~~~\n");
+ db_api->exit();
+#if (TCFG_ANC_TOOL_DEBUG_ONLINE && TCFG_AUDIO_ANC_ENABLE)
+ app_anctool_spp_disconnect();
+#endif
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+static void online_spp_send_wakeup(void)
+{
+ /* putchar('W'); */
+ db_api->send_wake_up();
+}
+
+static void online_spp_recieve_cbk(void *priv, u8 *buf, u16 len)
+{
+ log_info("spp_api_rx(%d) \n", len);
+ /* log_info_hexdump(buf, len); */
+
+#if (TCFG_ANC_TOOL_DEBUG_ONLINE && TCFG_AUDIO_ANC_ENABLE)
+ if (app_anctool_spp_rx_data(buf, len)) {
+ return;
+ }
+#endif
+#if (TCFG_CFG_TOOL_ENABLE || TCFG_ONLINE_ENABLE)
+#if (TCFG_COMM_TYPE == TCFG_SPP_COMM)
+ extern int cfg_tool_online_parse(u8 * buf, u32 len);
+ if ((buf[1] == 0x12) || (buf[1] == 0x05) || (buf[1] == 0x11)) {
+ if (cfg_tool_online_parse(buf, len)) {
+ return;
+ }
+ }
+#endif
+#endif
+ /* log_info("spp_rx_channel_handle"); */
+ db_api->packet_handle(buf, len);
+
+ //loop send data for test
+ /* if (online_spp_send_data_check(len)) { */
+ /* online_spp_send_data(buf, len); */
+ /* } */
+}
+
+void online_spp_init(void)
+{
+ log_info("spp_file: %s", __FILE__);
+ spp_state = 0;
+ spp_get_operation_table(&spp_api);
+ spp_api->regist_recieve_cbk(0, online_spp_recieve_cbk);
+ spp_api->regist_state_cbk(0, online_spp_state_cbk);
+ spp_api->regist_wakeup_send(NULL, online_spp_send_wakeup);
+ db_api = app_online_get_api_table();
+}
+
+#else
+
+void online_spp_init(void)
+{
+}
+
+#endif
+
diff --git a/apps/common/third_party_profile/jieli/online_db/spp_online_db.h b/apps/common/third_party_profile/jieli/online_db/spp_online_db.h
new file mode 100644
index 0000000..42bde6d
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/online_db/spp_online_db.h
@@ -0,0 +1,8 @@
+#ifndef __SPP_ONLINE_DB_H__
+#define __SPP_ONLINE_DB_H__
+
+#include "typedef.h"
+#include "bt_common.h"
+
+
+#endif//
diff --git a/apps/common/third_party_profile/jieli/trans_data_demo/le_trans_data.c b/apps/common/third_party_profile/jieli/trans_data_demo/le_trans_data.c
new file mode 100644
index 0000000..fd39028
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/trans_data_demo/le_trans_data.c
@@ -0,0 +1,1393 @@
+/*********************************************************************************************
+ * Filename : le_server_module.c
+
+ * Description :
+
+ * Author :
+
+ * Email : zh-jieli.com
+
+ * Last modifiled : 2017-01-17 11:14
+
+ * Copyright:(c)JIELI 2011-2016 @ , All Rights Reserved.
+*********************************************************************************************/
+
+// *****************************************************************************
+/* EXAMPLE_START(le_counter): LE Peripheral - Heartbeat Counter over GATT
+ *
+ * @text All newer operating systems provide GATT Client functionality.
+ * The LE Counter examples demonstrates how to specify a minimal GATT Database
+ * with a custom GATT Service and a custom Characteristic that sends periodic
+ * notifications.
+ */
+// *****************************************************************************
+#include "system/app_core.h"
+#include "system/includes.h"
+
+#include "app_config.h"
+#include "app_action.h"
+
+#include "btstack/btstack_task.h"
+#include "btstack/bluetooth.h"
+#include "user_cfg.h"
+#include "vm.h"
+#include "btcontroller_modules.h"
+#include "bt_common.h"
+#include "3th_profile_api.h"
+
+#include "le_trans_data.h"
+#include "le_common.h"
+
+#include "rcsp_bluetooth.h"
+#include "JL_rcsp_api.h"
+#include "custom_cfg.h"
+
+
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_TRANS_DATA)
+
+//TRANS ANCS
+#define TRANS_ANCS_EN 1
+#if TRANS_ANCS_EN
+#include "btstack/btstack_event.h"
+#endif
+
+#define TEST_SEND_DATA_RATE 0 //测试上行发送数据
+#define TEST_SEND_HANDLE_VAL ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE
+/* #define TEST_SEND_HANDLE_VAL ATT_CHARACTERISTIC_ae05_01_VALUE_HANDLE */
+#define EXT_ADV_MODE_EN 0
+
+#define TEST_AUDIO_DATA_UPLOAD 0 //测试文件上传
+
+
+#if LE_DEBUG_PRINT_EN
+extern void printf_buf(u8 *buf, u32 len);
+/* #define log_info printf */
+#define log_info(x, ...) printf("[LE_TRANS]" x " ", ## __VA_ARGS__)
+#define log_info_hexdump printf_buf
+#else
+#define log_info(...)
+#define log_info_hexdump(...)
+#endif
+
+
+/* #define LOG_TAG_CONST BT_BLE */
+/* #define LOG_TAG "[LE_S_DEMO]" */
+/* #define LOG_ERROR_ENABLE */
+/* #define LOG_DEBUG_ENABLE */
+/* #define LOG_INFO_ENABLE */
+/* #define LOG_DUMP_ENABLE */
+/* #define LOG_CLI_ENABLE */
+/* #include "debug.h" */
+
+//------
+//ATT发送的包长, note: 20 <=need >= MTU
+#define ATT_LOCAL_MTU_SIZE (200) //
+//ATT缓存的buffer大小, note: need >= 20,可修改
+#define ATT_SEND_CBUF_SIZE (512) //
+
+//共配置的RAM
+#define ATT_RAM_BUFSIZE (ATT_CTRL_BLOCK_SIZE + ATT_LOCAL_MTU_SIZE + ATT_SEND_CBUF_SIZE) //note:
+static u8 att_ram_buffer[ATT_RAM_BUFSIZE] __attribute__((aligned(4)));
+//---------------
+
+#if TEST_SEND_DATA_RATE
+static u32 test_data_count;
+static u32 server_timer_handle = 0;
+static u8 test_data_start;
+#endif
+
+/*
+ 打开流控使能后,确定使能接口 att_server_flow_enable 被调用
+ 然后使用过程 通过接口 att_server_flow_hold 来控制流控开关
+ 注意:流控只能控制对方使用带响应READ/WRITE等命令方式
+ 例如:ATT_WRITE_REQUEST = 0x12
+ */
+#define ATT_DATA_RECIEVT_FLOW 0//流控功能使能
+
+//---------------
+// 广播周期 (unit:0.625ms)
+#define ADV_INTERVAL_MIN (160*5)
+
+#define HOLD_LATENCY_CNT_MIN (3) //(0~0xffff)
+#define HOLD_LATENCY_CNT_MAX (15) //(0~0xffff)
+#define HOLD_LATENCY_CNT_ALL (0xffff)
+
+static volatile hci_con_handle_t con_handle;
+
+//加密设置
+/* static const uint8_t sm_min_key_size = 7; */
+
+//连接参数更新请求设置
+//是否使能参数请求更新,0--disable, 1--enable
+static const uint8_t connection_update_enable = 1; ///0--disable, 1--enable
+//当前请求的参数表index
+static uint8_t connection_update_cnt = 0; //
+
+//参数表
+static const struct conn_update_param_t connection_param_table[] = {
+ {16, 24, 10, 600},//11
+ {12, 28, 10, 600},//3.7
+ {8, 20, 10, 600},
+ /* {12, 28, 4, 600},//3.7 */
+ /* {12, 24, 30, 600},//3.05 */
+};
+
+//共可用的参数组数
+#define CONN_PARAM_TABLE_CNT (sizeof(connection_param_table)/sizeof(struct conn_update_param_t))
+
+#if (ATT_RAM_BUFSIZE < 64)
+#error "adv_data & rsp_data buffer error!!!!!!!!!!!!"
+#endif
+
+//用户可配对的,这是样机跟客户开发的app配对的秘钥
+/* const u8 link_key_data[16] = {0x06, 0x77, 0x5f, 0x87, 0x91, 0x8d, 0xd4, 0x23, 0x00, 0x5d, 0xf1, 0xd8, 0xcf, 0x0c, 0x14, 0x2b}; */
+#define EIR_TAG_STRING 0xd6, 0x05, 0x08, 0x00, 'J', 'L', 'A', 'I', 'S', 'D','K'
+static const char user_tag_string[] = {EIR_TAG_STRING};
+
+static u8 adv_data_len;
+static u8 adv_data[ADV_RSP_PACKET_MAX];//max is 31
+static u8 scan_rsp_data_len;
+static u8 scan_rsp_data[ADV_RSP_PACKET_MAX];//max is 31
+
+/* #define adv_data &att_ram_buffer[0] */
+/* #define scan_rsp_data &att_ram_buffer[32] */
+
+static char gap_device_name[BT_NAME_LEN_MAX] = "jl_ble_test";
+static u8 gap_device_name_len = 0; //名字长度,不包含结束符
+static u8 ble_work_state = 0; //ble 状态变化
+static u8 adv_ctrl_en; //广播控制
+
+static u8 test_read_write_buf[4];
+
+static void (*app_recieve_callback)(void *priv, void *buf, u16 len) = NULL;
+static void (*app_ble_state_callback)(void *priv, ble_state_e state) = NULL;
+static void (*ble_resume_send_wakeup)(void) = NULL;
+static u32 channel_priv;
+
+static int app_send_user_data_check(u16 len);
+static int app_send_user_data_do(void *priv, u8 *data, u16 len);
+static int app_send_user_data(u16 handle, u8 *data, u16 len, u8 handle_type);
+static void reset_passkey_cb(u32 *key);
+
+// Complete Local Name 默认的蓝牙名字
+
+//------------------------------------------------------
+//广播参数设置
+static void advertisements_setup_init();
+static int set_adv_enable(void *priv, u32 en);
+static int get_buffer_vaild_len(void *priv);
+extern const char *bt_get_local_name();
+extern void clr_wdt(void);
+extern void sys_auto_shut_down_disable(void);
+extern void sys_auto_shut_down_enable(void);
+extern u8 get_total_connect_dev(void);
+
+//------------------------------------------------------
+//NACS
+#if TRANS_ANCS_EN
+#define ANCS_SUBEVENT_CLIENT_NOTIFICATION 0xF1
+void ancs_client_init(void);
+void ancs_client_register_callback(btstack_packet_handler_t callback);
+const char *ancs_client_attribute_name_for_id(int id);
+void ancs_set_notification_buffer(u8 *buffer, u16 buffer_size);
+
+//ancs info buffer
+#define ANCS_INFO_BUFFER_SIZE (1024)
+static u8 ancs_info_buffer[ANCS_INFO_BUFFER_SIZE];
+#endif
+
+//------------------------------------------------------
+#if TEST_AUDIO_DATA_UPLOAD
+static const u8 test_audio_data_file[1024] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9
+};
+
+#define AUDIO_ONE_PACKET_LEN 128
+static void test_send_audio_data(int init_flag)
+{
+ static u32 send_pt = 0;
+ static u32 start_flag = 0;
+
+ if (!con_handle) {
+ return;
+ }
+
+ if (init_flag) {
+ log_info("audio send init\n");
+ send_pt = 0;
+ start_flag = 1;
+ }
+
+ if (!start_flag) {
+ return;
+ }
+
+ u32 file_size = sizeof(test_audio_data_file);
+ u8 *file_ptr = test_audio_data_file;
+
+ if (send_pt >= file_size) {
+ log_info("audio send Complete\n");
+ start_flag = 0;
+ return;
+ }
+
+ u32 send_len = file_size - send_pt;
+ if (send_len > AUDIO_ONE_PACKET_LEN) {
+ send_len = AUDIO_ONE_PACKET_LEN;
+ }
+
+ while (1) {
+ if (app_send_user_data_check(send_len)) {
+ log_info("audio send %08x\n", send_pt);
+ if (app_send_user_data(ATT_CHARACTERISTIC_ae3c_01_VALUE_HANDLE, &file_ptr[send_pt], send_len, ATT_OP_AUTO_READ_CCC)) {
+ log_info("audio send fail!\n");
+ break;
+ } else {
+ send_pt += send_len;
+ }
+ } else {
+ break;
+ }
+ }
+}
+
+#endif
+
+
+static void send_request_connect_parameter(u8 table_index)
+{
+ struct conn_update_param_t *param = (void *)&connection_param_table[table_index];//static ram
+
+ log_info("update_request:-%d-%d-%d-%d-\n", param->interval_min, param->interval_max, param->latency, param->timeout);
+ if (con_handle) {
+ ble_op_conn_param_request(con_handle, param);
+ }
+}
+
+static void check_connetion_updata_deal(void)
+{
+ if (connection_update_enable) {
+ if (connection_update_cnt < CONN_PARAM_TABLE_CNT) {
+ send_request_connect_parameter(connection_update_cnt);
+ }
+ }
+}
+
+static void connection_update_complete_success(u8 *packet)
+{
+ int con_handle, conn_interval, conn_latency, conn_timeout;
+
+ con_handle = hci_subevent_le_connection_update_complete_get_connection_handle(packet);
+ conn_interval = hci_subevent_le_connection_update_complete_get_conn_interval(packet);
+ conn_latency = hci_subevent_le_connection_update_complete_get_conn_latency(packet);
+ conn_timeout = hci_subevent_le_connection_update_complete_get_supervision_timeout(packet);
+
+ log_info("conn_interval = %d\n", conn_interval);
+ log_info("conn_latency = %d\n", conn_latency);
+ log_info("conn_timeout = %d\n", conn_timeout);
+}
+
+
+static void set_ble_work_state(ble_state_e state)
+{
+ if (state != ble_work_state) {
+ log_info("ble_work_st:%x->%x\n", ble_work_state, state);
+ ble_work_state = state;
+ if (app_ble_state_callback) {
+ app_ble_state_callback((void *)channel_priv, state);
+ }
+ }
+}
+
+static ble_state_e get_ble_work_state(void)
+{
+ return ble_work_state;
+}
+
+static void cbk_sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
+{
+ sm_just_event_t *event = (void *)packet;
+ u32 tmp32;
+ switch (packet_type) {
+ case HCI_EVENT_PACKET:
+ switch (hci_event_packet_get_type(packet)) {
+ case SM_EVENT_JUST_WORKS_REQUEST:
+ sm_just_works_confirm(sm_event_just_works_request_get_handle(packet));
+ log_info("Just Works Confirmed.\n");
+ break;
+
+ case SM_EVENT_PASSKEY_DISPLAY_NUMBER:
+ log_info_hexdump(packet, size);
+ memcpy(&tmp32, event->data, 4);
+ log_info("Passkey display: %06u.\n", tmp32);
+ break;
+
+ case SM_EVENT_PASSKEY_INPUT_NUMBER:
+ /*IO_CAPABILITY_KEYBOARD_ONLY 方式*/
+ reset_passkey_cb(&tmp32);
+ log_info("%04x->Passkey input: %06u.\n", event->con_handle, tmp32);
+ sm_passkey_input(event->con_handle, tmp32); /*update passkey*/
+ break;
+
+ case SM_EVENT_PAIR_PROCESS:
+ log_info("======PAIR_PROCESS: %02x\n", event->data[0]);
+ put_buf(event->data, 4);
+
+ }
+ break;
+ }
+}
+
+
+#if TEST_SEND_DATA_RATE
+static void server_timer_handler(void)
+{
+ if (!con_handle) {
+ test_data_count = 0;
+ test_data_start = 0;
+ return;
+ }
+
+ log_info("peer_rssi = %d\n", ble_vendor_get_peer_rssi(con_handle));
+
+ if (test_data_count) {
+ log_info("\n%d bytes send: %d.%02d KB/s \n", test_data_count, test_data_count / 1000, test_data_count % 1000);
+ test_data_count = 0;
+ }
+}
+
+static void server_timer_start(void)
+{
+ if (server_timer_handle) {
+ return;
+ }
+
+ server_timer_handle = sys_timer_add(NULL, server_timer_handler, 1000);
+}
+
+static void server_timer_stop(void)
+{
+ if (server_timer_handle) {
+ sys_timeout_del(server_timer_handle);
+ server_timer_handle = 0;
+ }
+}
+
+void test_data_send_packet(void)
+{
+ u32 vaild_len = get_buffer_vaild_len(0);//获取发送buffer可写入的数据
+ if (!test_data_start) {
+ return;
+ }
+
+ if (vaild_len) {
+ if (!app_send_user_data(TEST_SEND_HANDLE_VAL, (void *)&test_data_count, vaild_len, ATT_OP_AUTO_READ_CCC)) {
+ test_data_count += vaild_len;
+ }
+ }
+ clr_wdt();
+}
+#endif
+
+
+static void can_send_now_wakeup(void)
+{
+ /* putchar('E'); */
+ if (ble_resume_send_wakeup) {
+ ble_resume_send_wakeup();
+ }
+
+#if TEST_SEND_DATA_RATE
+ test_data_send_packet();
+#endif
+
+#if TEST_AUDIO_DATA_UPLOAD
+ test_send_audio_data(0);
+#endif
+
+}
+
+static void ble_auto_shut_down_enable(u8 enable)
+{
+#if TCFG_AUTO_SHUT_DOWN_TIME
+ if (enable) {
+ if (get_total_connect_dev() == 0) { //已经没有设备连接
+ sys_auto_shut_down_enable();
+ }
+ } else {
+ sys_auto_shut_down_disable();
+ }
+#endif
+}
+
+const char *const phy_result[] = {
+ "None",
+ "1M",
+ "2M",
+ "Coded",
+};
+
+static void set_connection_data_length(u16 tx_octets, u16 tx_time)
+{
+ if (con_handle) {
+ ble_op_set_data_length(con_handle, tx_octets, tx_time);
+ }
+}
+
+static void set_connection_data_phy(u8 tx_phy, u8 rx_phy)
+{
+ if (0 == con_handle) {
+ return;
+ }
+
+ u8 all_phys = 0;
+ u16 phy_options = CONN_SET_PHY_OPTIONS_S8;
+
+ ble_op_set_ext_phy(con_handle, all_phys, tx_phy, rx_phy, phy_options);
+}
+
+static void server_profile_start(u16 con_handle)
+{
+#if BT_FOR_APP_EN
+ set_app_connect_type(TYPE_BLE);
+#endif
+ ble_op_att_send_init(con_handle, att_ram_buffer, ATT_RAM_BUFSIZE, ATT_LOCAL_MTU_SIZE);
+ set_ble_work_state(BLE_ST_CONNECT);
+ ble_auto_shut_down_enable(0);
+
+ /* set_connection_data_phy(CONN_SET_CODED_PHY, CONN_SET_CODED_PHY); */
+}
+
+_WEAK_
+u8 ble_update_get_ready_jump_flag(void)
+{
+ return 0;
+}
+/*
+ * @section Packet Handler
+ *
+ * @text The packet handler is used to:
+ * - stop the counter after a disconnect
+ * - send a notification when the requested ATT_EVENT_CAN_SEND_NOW is received
+ */
+
+/* LISTING_START(packetHandler): Packet Handler */
+static void cbk_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
+{
+ int mtu;
+ u32 tmp;
+ u8 status;
+ const char *attribute_name;
+
+ switch (packet_type) {
+ case HCI_EVENT_PACKET:
+ switch (hci_event_packet_get_type(packet)) {
+
+ /* case DAEMON_EVENT_HCI_PACKET_SENT: */
+ /* break; */
+ case ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE:
+ log_info("ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE\n");
+ case ATT_EVENT_CAN_SEND_NOW:
+ can_send_now_wakeup();
+ break;
+
+ case HCI_EVENT_LE_META:
+ switch (hci_event_le_meta_get_subevent_code(packet)) {
+ case HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE:
+ status = hci_subevent_le_enhanced_connection_complete_get_status(packet);
+ if (status) {
+ log_info("LE_SLAVE CONNECTION FAIL!!! %0x\n", status);
+ set_ble_work_state(BLE_ST_DISCONN);
+ break;
+ }
+ con_handle = hci_subevent_le_enhanced_connection_complete_get_connection_handle(packet);
+ log_info("HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE : %0x\n", con_handle);
+ log_info("conn_interval = %d\n", hci_subevent_le_enhanced_connection_complete_get_conn_interval(packet));
+ log_info("conn_latency = %d\n", hci_subevent_le_enhanced_connection_complete_get_conn_latency(packet));
+ log_info("conn_timeout = %d\n", hci_subevent_le_enhanced_connection_complete_get_supervision_timeout(packet));
+ server_profile_start(con_handle);
+ break;
+
+ case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
+ con_handle = hci_subevent_le_connection_complete_get_connection_handle(packet);
+ log_info("HCI_SUBEVENT_LE_CONNECTION_COMPLETE: %0x\n", con_handle);
+ connection_update_complete_success(packet + 8);
+ server_profile_start(con_handle);
+#if RCSP_BTMATE_EN
+#if (defined(BT_CONNECTION_VERIFY) && (0 == BT_CONNECTION_VERIFY))
+ JL_rcsp_auth_reset();
+#endif
+ //rcsp_dev_select(RCSP_BLE);
+ rcsp_init();
+#endif
+ log_info("ble remote rssi= %d\n", ble_vendor_get_peer_rssi(con_handle));
+ break;
+
+ case HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE:
+ connection_update_complete_success(packet);
+ break;
+
+ case HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE:
+ log_info("APP HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE\n");
+ /* set_connection_data_phy(CONN_SET_CODED_PHY, CONN_SET_CODED_PHY); */
+ break;
+
+ case HCI_SUBEVENT_LE_PHY_UPDATE_COMPLETE:
+ log_info("APP HCI_SUBEVENT_LE_PHY_UPDATE %s\n", hci_event_le_meta_get_phy_update_complete_status(packet) ? "Fail" : "Succ");
+ log_info("Tx PHY: %s\n", phy_result[hci_event_le_meta_get_phy_update_complete_tx_phy(packet)]);
+ log_info("Rx PHY: %s\n", phy_result[hci_event_le_meta_get_phy_update_complete_rx_phy(packet)]);
+ break;
+ }
+ break;
+
+ case HCI_EVENT_DISCONNECTION_COMPLETE:
+ log_info("HCI_EVENT_DISCONNECTION_COMPLETE: %0x\n", packet[5]);
+#if RCSP_BTMATE_EN
+ rcsp_exit();
+#endif
+ con_handle = 0;
+ ble_op_att_send_init(con_handle, 0, 0, 0);
+ set_ble_work_state(BLE_ST_DISCONN);
+
+ if (!ble_update_get_ready_jump_flag()) {
+ bt_ble_adv_enable(1);
+ }
+ connection_update_cnt = 0;
+#if BT_FOR_APP_EN
+ set_app_connect_type(TYPE_NULL);
+#endif
+ ble_auto_shut_down_enable(1);
+ break;
+
+ case ATT_EVENT_MTU_EXCHANGE_COMPLETE:
+ mtu = att_event_mtu_exchange_complete_get_MTU(packet) - 3;
+ log_info("ATT MTU = %u\n", mtu);
+ ble_op_att_set_send_mtu(mtu);
+ /* set_connection_data_length(251, 2120); */
+ break;
+
+ case HCI_EVENT_VENDOR_REMOTE_TEST:
+ log_info("--- HCI_EVENT_VENDOR_REMOTE_TEST\n");
+ break;
+
+ case L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE:
+ tmp = little_endian_read_16(packet, 4);
+ log_info("-update_rsp: %02x\n", tmp);
+ if (tmp) {
+ connection_update_cnt++;
+ log_info("remoter reject!!!\n");
+ check_connetion_updata_deal();
+ } else {
+ connection_update_cnt = CONN_PARAM_TABLE_CNT;
+ }
+ break;
+
+ case HCI_EVENT_ENCRYPTION_CHANGE:
+ log_info("HCI_EVENT_ENCRYPTION_CHANGE= %d\n", packet[2]);
+ break;
+
+#if TRANS_ANCS_EN
+ case HCI_EVENT_ANCS_META:
+ switch (hci_event_ancs_meta_get_subevent_code(packet)) {
+ case ANCS_SUBEVENT_CLIENT_NOTIFICATION:
+ printf("ANCS_SUBEVENT_CLIENT_NOTIFICATION \n");
+ attribute_name = ancs_client_attribute_name_for_id(ancs_subevent_client_notification_get_attribute_id(packet));
+ if (!attribute_name) {
+ printf("ancs unknow attribute_id :%d \n", ancs_subevent_client_notification_get_attribute_id(packet));
+ break;
+ } else {
+ u16 attribute_strlen = little_endian_read_16(packet, 7);
+ u8 *attribute_str = (void *)little_endian_read_32(packet, 9);
+ printf("Notification: %s - %s \n", attribute_name, attribute_str);
+ }
+ break;
+ default:
+ break;
+ }
+
+ break;
+#endif
+
+ }
+ break;
+ }
+}
+
+
+/* LISTING_END */
+
+/*
+ * @section ATT Read
+ *
+ * @text The ATT Server handles all reads to constant data. For dynamic data like the custom characteristic, the registered
+ * att_read_callback is called. To handle long characteristics and long reads, the att_read_callback is first called
+ * with buffer == NULL, to request the total value length. Then it will be called again requesting a chunk of the value.
+ * See Listing attRead.
+ */
+
+/* LISTING_START(attRead): ATT Read */
+
+// ATT Client Read Callback for Dynamic Data
+// - if buffer == NULL, don't copy data, just return size of value
+// - if buffer != NULL, copy data and return number bytes copied
+// @param offset defines start of attribute value
+static uint16_t att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset, uint8_t *buffer, uint16_t buffer_size)
+{
+
+ uint16_t att_value_len = 0;
+ uint16_t handle = att_handle;
+
+ log_info("read_callback, handle= 0x%04x,buffer= %08x\n", handle, (u32)buffer);
+
+ switch (handle) {
+ case ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE:
+ att_value_len = gap_device_name_len;
+
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+
+ if (buffer) {
+ memcpy(buffer, &gap_device_name[offset], buffer_size);
+ att_value_len = buffer_size;
+ log_info("\n------read gap_name: %s \n", gap_device_name);
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_ae10_01_VALUE_HANDLE:
+ att_value_len = sizeof(test_read_write_buf);
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+
+ if (buffer) {
+ memcpy(buffer, &test_read_write_buf[offset], buffer_size);
+ att_value_len = buffer_size;
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_2a05_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_ae04_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_ae02_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_ae05_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_ae3c_01_CLIENT_CONFIGURATION_HANDLE:
+ if (buffer) {
+ buffer[0] = att_get_ccc_config(handle);
+ buffer[1] = 0;
+ }
+ att_value_len = 2;
+ break;
+
+ default:
+ break;
+ }
+
+ log_info("att_value_len= %d\n", att_value_len);
+ return att_value_len;
+
+}
+
+
+/* LISTING_END */
+/*
+ * @section ATT Write
+ *
+ * @text The only valid ATT write in this example is to the Client Characteristic Configuration, which configures notification
+ * and indication. If the ATT handle matches the client configuration handle, the new configuration value is stored and used
+ * in the heartbeat handler to decide if a new value should be sent. See Listing attWrite.
+ */
+
+/* LISTING_START(attWrite): ATT Write */
+static int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size)
+{
+ int result = 0;
+ u16 tmp16;
+
+ u16 handle = att_handle;
+
+ log_info("write_callback, handle= 0x%04x,size = %d\n", handle, buffer_size);
+
+ switch (handle) {
+
+ case ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE:
+ break;
+
+ case ATT_CHARACTERISTIC_ae02_01_CLIENT_CONFIGURATION_HANDLE:
+#if TEST_SEND_DATA_RATE
+ if (buffer[0]) {
+ server_timer_start();
+ } else {
+ server_timer_stop();
+ test_data_start = 0;
+ }
+#endif
+
+ case ATT_CHARACTERISTIC_2a05_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_ae04_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_ae05_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_ae3c_01_CLIENT_CONFIGURATION_HANDLE:
+ set_ble_work_state(BLE_ST_NOTIFY_IDICATE);
+ check_connetion_updata_deal();
+ log_info("\n------write ccc:%04x,%02x\n", handle, buffer[0]);
+ att_set_ccc_config(handle, buffer[0]);
+
+#if TEST_SEND_DATA_RATE
+ test_data_start = 1;//start
+ if (buffer[0]) {
+ test_data_send_packet();
+ }
+#endif
+ break;
+
+ case ATT_CHARACTERISTIC_ae10_01_VALUE_HANDLE:
+ tmp16 = sizeof(test_read_write_buf);
+ if ((offset >= tmp16) || (offset + buffer_size) > tmp16) {
+ break;
+ }
+ memcpy(&test_read_write_buf[offset], buffer, buffer_size);
+ break;
+
+ case ATT_CHARACTERISTIC_ae01_01_VALUE_HANDLE:
+ printf("\n-ae01_rx(%d):", buffer_size);
+ printf_buf(buffer, buffer_size);
+
+ if (app_recieve_callback) {
+ app_recieve_callback(0, buffer, buffer_size);
+ }
+ //收发测试,自动发送收到的数据;for test
+ if (app_send_user_data_check(buffer_size)) {
+ app_send_user_data(ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE, buffer, buffer_size, ATT_OP_AUTO_READ_CCC);
+ }
+
+#if TEST_SEND_DATA_RATE
+ if ((buffer[0] == 'A') && (buffer[1] == 'F')) {
+ test_data_start = 1;//start
+ } else if ((buffer[0] == 'A') && (buffer[1] == 'A')) {
+ test_data_start = 0;//stop
+ }
+#endif
+ break;
+
+ case ATT_CHARACTERISTIC_ae03_01_VALUE_HANDLE:
+ printf("\n-ae_rx(%d):", buffer_size);
+ printf_buf(buffer, buffer_size);
+
+ //收发测试,自动发送收到的数据;for test
+ if (app_send_user_data_check(buffer_size)) {
+ app_send_user_data(ATT_CHARACTERISTIC_ae05_01_VALUE_HANDLE, buffer, buffer_size, ATT_OP_AUTO_READ_CCC);
+ }
+ break;
+
+#if RCSP_BTMATE_EN
+ case ATT_CHARACTERISTIC_ae02_02_CLIENT_CONFIGURATION_HANDLE:
+#if (defined(BT_CONNECTION_VERIFY) && (0 == BT_CONNECTION_VERIFY))
+ JL_rcsp_auth_reset(); //处理APP断开后台还连接的情况
+#endif
+ ble_op_latency_skip(con_handle, HOLD_LATENCY_CNT_ALL); //
+ set_ble_work_state(BLE_ST_NOTIFY_IDICATE);
+#endif
+ /* if ((cur_conn_latency == 0) */
+ /* && (connection_update_cnt == CONN_PARAM_TABLE_CNT) */
+ /* && (Peripheral_Preferred_Connection_Parameters[0].latency != 0)) { */
+ /* connection_update_cnt = 0; */
+ /* } */
+ check_connetion_updata_deal();
+ log_info("\n------write ccc:%04x,%02x\n", handle, buffer[0]);
+ att_set_ccc_config(handle, buffer[0]);
+ break;
+#if RCSP_BTMATE_EN
+ case ATT_CHARACTERISTIC_ae01_02_VALUE_HANDLE:
+ printf("rcsp_read:%x\n", buffer_size);
+ if (app_recieve_callback) {
+ app_recieve_callback(0, buffer, buffer_size);
+ }
+ break;
+#endif
+
+ case ATT_CHARACTERISTIC_ae3b_01_VALUE_HANDLE:
+ printf("\n-ae3b_rx(%d):", buffer_size);
+ printf_buf(buffer, buffer_size);
+
+#if TEST_AUDIO_DATA_UPLOAD
+ if (0 == memcmp(buffer, "start", 5)) {
+ test_send_audio_data(1);
+ }
+#endif
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int app_send_user_data(u16 handle, u8 *data, u16 len, u8 handle_type)
+{
+ u32 ret = APP_BLE_NO_ERROR;
+
+ if (!con_handle) {
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+ if (!att_get_ccc_config(handle + 1)) {
+ log_info("fail,no write ccc!!!,%04x\n", handle + 1);
+ return APP_BLE_NO_WRITE_CCC;
+ }
+
+ ret = ble_op_att_send_data(handle, data, len, handle_type);
+ if (ret == BLE_BUFFER_FULL) {
+ ret = APP_BLE_BUFF_FULL;
+ }
+
+ if (ret) {
+ log_info("app_send_fail:%d !!!!!!\n", ret);
+ }
+ return ret;
+}
+
+//------------------------------------------------------
+#if RCSP_BTMATE_EN
+static u8 tag_in_adv;
+#endif
+
+static int make_set_adv_data(void)
+{
+ u8 offset = 0;
+ u8 *buf = adv_data;
+
+
+#if DOUBLE_BT_SAME_MAC
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x0A, 1);
+#else
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x06, 1);
+#endif
+
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_16BIT_SERVICE_UUIDS, 0xAF30, 2);
+
+#if RCSP_BTMATE_EN
+ u8 tag_len = sizeof(user_tag_string);
+ if (tag_len > ADV_RSP_PACKET_MAX - (offset + 2)) {
+ tag_in_adv = 0;
+ } else {
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_MANUFACTURER_SPECIFIC_DATA, (void *)user_tag_string, tag_len);
+ tag_in_adv = 1;
+ }
+#endif
+
+ if (offset > ADV_RSP_PACKET_MAX) {
+ puts("***adv_data overflow!!!!!!\n");
+ return -1;
+ }
+ log_info("adv_data(%d):", offset);
+ log_info_hexdump(buf, offset);
+ adv_data_len = offset;
+ ble_op_set_adv_data(offset, buf);
+ return 0;
+}
+
+static int make_set_rsp_data(void)
+{
+ u8 offset = 0;
+ u8 *buf = scan_rsp_data;
+
+#if RCSP_BTMATE_EN
+ if (!tag_in_adv) {
+ u8 tag_len = sizeof(user_tag_string);
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_MANUFACTURER_SPECIFIC_DATA, (void *)user_tag_string, tag_len);
+ }
+#endif
+
+ u8 name_len = gap_device_name_len;
+ u8 vaild_len = ADV_RSP_PACKET_MAX - (offset + 2);
+ if (name_len > vaild_len) {
+ name_len = vaild_len;
+ }
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, (void *)gap_device_name, name_len);
+
+ if (offset > ADV_RSP_PACKET_MAX) {
+ puts("***rsp_data overflow!!!!!!\n");
+ return -1;
+ }
+
+ log_info("rsp_data(%d):", offset);
+ log_info_hexdump(buf, offset);
+ scan_rsp_data_len = offset;
+ ble_op_set_rsp_data(offset, buf);
+ return 0;
+}
+
+//广播参数设置
+static void advertisements_setup_init()
+{
+ uint8_t adv_type = ADV_IND;
+ uint8_t adv_channel = ADV_CHANNEL_ALL;
+ int ret = 0;
+
+ ble_op_set_adv_param(ADV_INTERVAL_MIN, adv_type, adv_channel);
+
+ ret |= make_set_adv_data();
+ ret |= make_set_rsp_data();
+
+ if (ret) {
+ puts("advertisements_setup_init fail !!!!!!\n");
+ return;
+ }
+
+}
+
+#define PASSKEY_ENTER_ENABLE 0 //输入passkey使能,可修改passkey
+//重设passkey回调函数,在这里可以重新设置passkey
+//passkey为6个数字组成,十万位、万位。。。。个位 各表示一个数字 高位不够为0
+static void reset_passkey_cb(u32 *key)
+{
+#if 1
+ u32 newkey = rand32();//获取随机数
+
+ newkey &= 0xfffff;
+ if (newkey > 999999) {
+ newkey = newkey - 999999; //不能大于999999
+ }
+ *key = newkey; //小于或等于六位数
+ printf("set new_key= %06u\n", *key);
+#else
+ *key = 123456; //for debug
+#endif
+}
+
+void ble_sm_setup_init(io_capability_t io_type, u8 auth_req, uint8_t min_key_size, u8 security_en)
+{
+ //setup SM: Display only
+ sm_init();
+ sm_set_io_capabilities(io_type);
+ sm_set_authentication_requirements(auth_req);
+ sm_set_encryption_key_size_range(min_key_size, 16);
+ sm_set_request_security(security_en);
+ sm_event_callback_set(&cbk_sm_packet_handler);
+
+ if (io_type == IO_CAPABILITY_DISPLAY_ONLY) {
+ reset_PK_cb_register(reset_passkey_cb);
+ }
+}
+
+
+#define TRANS_TCFG_BLE_SECURITY_EN 0/*是否发请求加密命令*/
+void ble_profile_init(void)
+{
+ printf("ble profile init\n");
+ le_device_db_init();
+
+#if PASSKEY_ENTER_ENABLE
+ ble_sm_setup_init(IO_CAPABILITY_DISPLAY_ONLY, SM_AUTHREQ_MITM_PROTECTION | SM_AUTHREQ_BONDING, 7, TRANS_TCFG_BLE_SECURITY_EN);
+#else
+ ble_sm_setup_init(IO_CAPABILITY_NO_INPUT_NO_OUTPUT, SM_AUTHREQ_MITM_PROTECTION | SM_AUTHREQ_BONDING, 7, TRANS_TCFG_BLE_SECURITY_EN);
+#endif
+
+ /* setup ATT server */
+ att_server_init(profile_data, att_read_callback, att_write_callback);
+ att_server_register_packet_handler(cbk_packet_handler);
+ /* gatt_client_register_packet_handler(packet_cbk); */
+
+ // register for HCI events
+ hci_event_callback_set(&cbk_packet_handler);
+ /* ble_l2cap_register_packet_handler(packet_cbk); */
+ /* sm_event_packet_handler_register(packet_cbk); */
+ le_l2cap_register_packet_handler(&cbk_packet_handler);
+
+#if TRANS_ANCS_EN
+ //setup GATT client
+ gatt_client_init();
+
+ //setup ANCS clent
+ ancs_client_init();
+ ancs_set_notification_buffer(ancs_info_buffer, sizeof(ancs_info_buffer));
+ ancs_client_register_callback(&cbk_packet_handler);
+#endif
+
+ ble_vendor_set_default_att_mtu(ATT_LOCAL_MTU_SIZE);
+}
+
+#if EXT_ADV_MODE_EN
+
+
+#define EXT_ADV_NAME 'J', 'L', '_', 'E', 'X', 'T', '_', 'A', 'D', 'V'
+/* #define EXT_ADV_NAME "JL_EXT_ADV" */
+#define EXT_ADV_DATA \
+ 0x02, 0x01, 0x06, \
+ 0x03, 0x02, 0xF0, 0xFF, \
+ BYTE_LEN(EXT_ADV_NAME) + 1, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, EXT_ADV_NAME
+
+const struct ext_advertising_param ext_adv_param = {
+ .Advertising_Handle = 0,
+ .Advertising_Event_Properties = 1,
+ .Primary_Advertising_Interval_Min = {30, 0, 0},
+ .Primary_Advertising_Interval_Max = {30, 0, 0},
+ .Primary_Advertising_Channel_Map = 7,
+ .Primary_Advertising_PHY = ADV_SET_1M_PHY,
+ .Secondary_Advertising_PHY = ADV_SET_1M_PHY,
+};
+
+const struct ext_advertising_data ext_adv_data = {
+ .Advertising_Handle = 0,
+ .Operation = 3,
+ .Fragment_Preference = 0,
+ .Advertising_Data_Length = BYTE_LEN(EXT_ADV_DATA),
+ .Advertising_Data = EXT_ADV_DATA,
+};
+
+const struct ext_advertising_enable ext_adv_enable = {
+ .Enable = 1,
+ .Number_of_Sets = 1,
+ .Advertising_Handle = 0,
+ .Duration = 0,
+ .Max_Extended_Advertising_Events = 0,
+};
+
+const struct ext_advertising_enable ext_adv_disable = {
+ .Enable = 0,
+ .Number_of_Sets = 1,
+ .Advertising_Handle = 0,
+ .Duration = 0,
+ .Max_Extended_Advertising_Events = 0,
+};
+
+#endif /* EXT_ADV_MODE_EN */
+
+static int set_adv_enable(void *priv, u32 en)
+{
+ ble_state_e next_state, cur_state;
+
+ if (!adv_ctrl_en && en) {
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+ if (con_handle) {
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+ if (en) {
+ next_state = BLE_ST_ADV;
+ } else {
+ next_state = BLE_ST_IDLE;
+ }
+
+ cur_state = get_ble_work_state();
+ switch (cur_state) {
+ case BLE_ST_ADV:
+ case BLE_ST_IDLE:
+ case BLE_ST_INIT_OK:
+ case BLE_ST_NULL:
+ case BLE_ST_DISCONN:
+ break;
+ default:
+ return APP_BLE_OPERATION_ERROR;
+ break;
+ }
+
+ if (cur_state == next_state) {
+ return APP_BLE_NO_ERROR;
+ }
+ log_info("adv_en:%d\n", en);
+ set_ble_work_state(next_state);
+
+#if EXT_ADV_MODE_EN
+ if (en) {
+ ble_op_set_ext_adv_param(&ext_adv_param, sizeof(ext_adv_param));
+
+ log_info_hexdump(&ext_adv_data, sizeof(ext_adv_data));
+ ble_op_set_ext_adv_data(&ext_adv_data, sizeof(ext_adv_data));
+
+ ble_op_set_ext_adv_enable(&ext_adv_enable, sizeof(ext_adv_enable));
+ } else {
+ ble_op_set_ext_adv_enable(&ext_adv_disable, sizeof(ext_adv_disable));
+ }
+#else
+ if (en) {
+ advertisements_setup_init();
+ }
+ ble_op_adv_enable(en);
+#endif /* EXT_ADV_MODE_EN */
+
+ return APP_BLE_NO_ERROR;
+}
+
+static int ble_disconnect(void *priv)
+{
+ if (con_handle) {
+ if (BLE_ST_SEND_DISCONN != get_ble_work_state()) {
+ log_info(">>>ble send disconnect\n");
+ set_ble_work_state(BLE_ST_SEND_DISCONN);
+ ble_op_disconnect(con_handle);
+ } else {
+ log_info(">>>ble wait disconnect...\n");
+ }
+ return APP_BLE_NO_ERROR;
+ } else {
+ return APP_BLE_OPERATION_ERROR;
+ }
+}
+
+
+static int get_buffer_vaild_len(void *priv)
+{
+ u32 vaild_len = 0;
+ ble_op_att_get_remain(&vaild_len);
+ return vaild_len;
+}
+
+static int app_send_user_data_do(void *priv, u8 *data, u16 len)
+{
+#if PRINT_DMA_DATA_EN
+ if (len < 128) {
+ log_info("-le_tx(%d):");
+ log_info_hexdump(data, len);
+ } else {
+ putchar('L');
+ }
+#endif
+ return app_send_user_data(ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE, data, len, ATT_OP_AUTO_READ_CCC);
+}
+
+static int app_send_user_data_check(u16 len)
+{
+ u32 buf_space = get_buffer_vaild_len(0);
+ if (len <= buf_space) {
+ return 1;
+ }
+ return 0;
+}
+
+
+static int regiest_wakeup_send(void *priv, void *cbk)
+{
+ ble_resume_send_wakeup = cbk;
+ return APP_BLE_NO_ERROR;
+}
+
+static int regiest_recieve_cbk(void *priv, void *cbk)
+{
+ channel_priv = (u32)priv;
+ app_recieve_callback = cbk;
+ return APP_BLE_NO_ERROR;
+}
+
+static int regiest_state_cbk(void *priv, void *cbk)
+{
+ channel_priv = (u32)priv;
+ app_ble_state_callback = cbk;
+ return APP_BLE_NO_ERROR;
+}
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+
+
+u8 *ble_get_scan_rsp_ptr(u16 *len)
+{
+ if (len) {
+ *len = scan_rsp_data_len;
+ }
+ return scan_rsp_data;
+}
+
+u8 *ble_get_adv_data_ptr(u16 *len)
+{
+ if (len) {
+ *len = adv_data_len;
+ }
+ return adv_data;
+}
+
+u8 *ble_get_gatt_profile_data(u16 *len)
+{
+ *len = sizeof(profile_data);
+ return (u8 *)profile_data;
+}
+
+
+void bt_ble_adv_enable(u8 enable)
+{
+ set_adv_enable(0, enable);
+}
+
+u16 bt_ble_is_connected(void)
+{
+ return con_handle;
+}
+
+void ble_module_enable(u8 en)
+{
+ log_info("mode_en:%d\n", en);
+ if (en) {
+ adv_ctrl_en = 1;
+ bt_ble_adv_enable(1);
+ } else {
+ if (con_handle) {
+ adv_ctrl_en = 0;
+ ble_disconnect(NULL);
+ } else {
+ bt_ble_adv_enable(0);
+ adv_ctrl_en = 0;
+ }
+ }
+}
+
+
+//流控使能 EN: 1-停止收数 or 0-继续收数
+int ble_trans_flow_enable(u8 en)
+{
+ int ret = -1;
+#if ATT_DATA_RECIEVT_FLOW
+ if (con_handle) {
+ att_server_flow_hold(con_handle, en);
+ ret = 0;
+ }
+#endif
+ log_info("ble_trans_flow_enable:%d,%d\n", en, ret);
+ return ret;
+}
+
+//for test
+static void timer_trans_flow_test(void)
+{
+ static u8 sw = 0;
+ if (con_handle) {
+ sw = !sw;
+ ble_trans_flow_enable(sw);
+ }
+}
+
+static const char ble_ext_name[] = "(BLE)";
+
+void bt_ble_init(void)
+{
+ log_info("***** ble_init******\n");
+ log_info("ble_file: %s", __FILE__);
+ char *name_p;
+
+#if DOUBLE_BT_SAME_NAME
+ u8 ext_name_len = 0;
+#else
+ u8 ext_name_len = sizeof(ble_ext_name) - 1;
+#endif
+
+ name_p = bt_get_local_name();
+ gap_device_name_len = strlen(name_p);
+ if (gap_device_name_len > BT_NAME_LEN_MAX - ext_name_len) {
+ gap_device_name_len = BT_NAME_LEN_MAX - ext_name_len;
+ }
+
+ memcpy(gap_device_name, name_p, gap_device_name_len);
+
+#if DOUBLE_BT_SAME_NAME == 0
+ //增加后缀,区分名字
+ memcpy(&gap_device_name[gap_device_name_len], "(BLE)", ext_name_len);
+ gap_device_name_len += ext_name_len;
+#endif
+ gap_device_name[gap_device_name_len] = 0;//结束符
+ log_info("ble name(%d): %s \n", gap_device_name_len, gap_device_name);
+
+#if ATT_DATA_RECIEVT_FLOW
+ log_info("att_server_flow_enable\n");
+ att_server_flow_enable(1);
+ /* sys_timer_add(0, timer_trans_flow_test, 3000); */
+#endif
+
+ set_ble_work_state(BLE_ST_INIT_OK);
+ ble_module_enable(1);
+
+#if TEST_SEND_DATA_RATE
+ server_timer_start();
+#endif
+}
+
+void bt_ble_exit(void)
+{
+ log_info("***** ble_exit******\n");
+
+ ble_module_enable(0);
+
+#if TEST_SEND_DATA_RATE
+ server_timer_stop();
+#endif
+
+}
+
+
+void ble_app_disconnect(void)
+{
+ ble_disconnect(NULL);
+}
+
+#if RCSP_BTMATE_EN
+static int rcsp_send_user_data_do(void *priv, u8 *data, u16 len)
+{
+ log_info("rcsp_tx:%x\n", len);
+#if PRINT_DMA_DATA_EN
+ if (len < 128) {
+ log_info("-dma_tx(%d):");
+ log_info_hexdump(data, len);
+ } else {
+ putchar('L');
+ }
+#endif
+ return app_send_user_data(ATT_CHARACTERISTIC_ae02_02_VALUE_HANDLE, data, len, ATT_OP_AUTO_READ_CCC);
+}
+#endif
+
+#if RCSP_BTMATE_EN
+static const struct ble_server_operation_t mi_ble_operation = {
+ .adv_enable = set_adv_enable,
+ .disconnect = ble_disconnect,
+ .get_buffer_vaild = get_buffer_vaild_len,
+ .send_data = (void *)rcsp_send_user_data_do,
+ .regist_wakeup_send = regiest_wakeup_send,
+ .regist_recieve_cbk = regiest_recieve_cbk,
+ .regist_state_cbk = regiest_state_cbk,
+};
+#else
+static const struct ble_server_operation_t mi_ble_operation = {
+ .adv_enable = set_adv_enable,
+ .disconnect = ble_disconnect,
+ .get_buffer_vaild = get_buffer_vaild_len,
+ .send_data = (void *)app_send_user_data_do,
+ .regist_wakeup_send = regiest_wakeup_send,
+ .regist_recieve_cbk = regiest_recieve_cbk,
+ .regist_state_cbk = regiest_state_cbk,
+};
+#endif
+
+void ble_get_server_operation_table(struct ble_server_operation_t **interface_pt)
+{
+ *interface_pt = (void *)&mi_ble_operation;
+}
+
+void ble_server_send_test_key_num(u8 key_num)
+{
+ ;
+}
+#if TRANS_ANCS_EN
+extern u32 get_notification_uid(void);
+extern u16 get_controlpoint_handle(void);
+void hangup_ans_call_handle(u8 en)
+{
+
+ u32 notification_id;
+ u16 control_point_handle;
+
+ r_printf("hang_up or answer\n");
+ notification_id = get_notification_uid();
+ control_point_handle = get_controlpoint_handle();
+ u8 ble_hangup[] = {0x02, 0, 0, 0, 0, en};
+ memcpy(&ble_hangup[1], ¬ification_id, 4);
+ put_buf(ble_hangup, 6);
+ u8 ble_hangup_size = 6;
+ ble_op_att_send_data(control_point_handle, (void *)&ble_hangup, ble_hangup_size, ATT_OP_WRITE);
+
+}
+#endif
+#endif
+
+
diff --git a/apps/common/third_party_profile/jieli/trans_data_demo/le_trans_data.h b/apps/common/third_party_profile/jieli/trans_data_demo/le_trans_data.h
new file mode 100644
index 0000000..e6c7ec2
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/trans_data_demo/le_trans_data.h
@@ -0,0 +1,206 @@
+// binary representation
+// attribute size in bytes (16), flags(16), handle (16), uuid (16/128), value(...)
+
+#ifndef _LE_TRANS_DATA_H
+#define _LE_TRANS_DATA_H
+
+#include
+#include "app_config.h"
+//
+// gatt profile include file, generated by jieli gatt_inc_generator.exe
+//
+
+static const uint8_t profile_data[] = {
+ //////////////////////////////////////////////////////
+ //
+ // 0x0001 PRIMARY_SERVICE 1800
+ //
+ //////////////////////////////////////////////////////
+ 0x0a, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x28, 0x00, 0x18,
+
+ /* CHARACTERISTIC, 2a00, READ | WRITE | DYNAMIC, */
+ // 0x0002 CHARACTERISTIC 2a00 READ | WRITE | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x28, 0x0a, 0x03, 0x00, 0x00, 0x2a,
+ // 0x0003 VALUE 2a00 READ | WRITE | DYNAMIC
+ 0x08, 0x00, 0x0a, 0x01, 0x03, 0x00, 0x00, 0x2a,
+
+ //////////////////////////////////////////////////////
+ //
+ // 0x0004 PRIMARY_SERVICE ae30
+ //
+ //////////////////////////////////////////////////////
+ 0x0a, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x28, 0x30, 0xae,
+
+ /* CHARACTERISTIC, ae01, WRITE_WITHOUT_RESPONSE | DYNAMIC, */
+ // 0x0005 CHARACTERISTIC ae01 WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x28, 0x04, 0x06, 0x00, 0x01, 0xae,
+ // 0x0006 VALUE ae01 WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x08, 0x00, 0x04, 0x01, 0x06, 0x00, 0x01, 0xae,
+
+ /* CHARACTERISTIC, ae02, NOTIFY, */
+ // 0x0007 CHARACTERISTIC ae02 NOTIFY
+ 0x0d, 0x00, 0x02, 0x00, 0x07, 0x00, 0x03, 0x28, 0x10, 0x08, 0x00, 0x02, 0xae,
+ // 0x0008 VALUE ae02 NOTIFY
+ 0x08, 0x00, 0x10, 0x00, 0x08, 0x00, 0x02, 0xae,
+ // 0x0009 CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x09, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+ /* CHARACTERISTIC, ae03, WRITE_WITHOUT_RESPONSE | DYNAMIC, */
+ // 0x000a CHARACTERISTIC ae03 WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x03, 0x28, 0x04, 0x0b, 0x00, 0x03, 0xae,
+ // 0x000b VALUE ae03 WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x08, 0x00, 0x04, 0x01, 0x0b, 0x00, 0x03, 0xae,
+
+ /* CHARACTERISTIC, ae04, NOTIFY, */
+ // 0x000c CHARACTERISTIC ae04 NOTIFY
+ 0x0d, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x03, 0x28, 0x10, 0x0d, 0x00, 0x04, 0xae,
+ // 0x000d VALUE ae04 NOTIFY
+ 0x08, 0x00, 0x10, 0x00, 0x0d, 0x00, 0x04, 0xae,
+ // 0x000e CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x0e, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+ /* CHARACTERISTIC, ae05, INDICATE, */
+ // 0x000f CHARACTERISTIC ae05 INDICATE
+ 0x0d, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x03, 0x28, 0x20, 0x10, 0x00, 0x05, 0xae,
+ // 0x0010 VALUE ae05 INDICATE
+ 0x08, 0x00, 0x20, 0x00, 0x10, 0x00, 0x05, 0xae,
+ // 0x0011 CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x11, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+ /* CHARACTERISTIC, ae10, READ | WRITE | DYNAMIC, */
+ // 0x0012 CHARACTERISTIC ae10 READ | WRITE | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x12, 0x00, 0x03, 0x28, 0x0a, 0x13, 0x00, 0x10, 0xae,
+ // 0x0013 VALUE ae10 READ | WRITE | DYNAMIC
+ 0x08, 0x00, 0x0a, 0x01, 0x13, 0x00, 0x10, 0xae,
+
+
+#if 0
+ //for uuid128,sample
+ // PRIMARY_SERVICE, 0000F530-1212-EFDE-1523-785FEABCD123
+ // CHARACTERISTIC, 0000F531-1212-EFDE-1523-785FEABCD123, NOTIFY,
+ // CHARACTERISTIC, 0000F532-1212-EFDE-1523-785FEABCD123, WRITE_WITHOUT_RESPONSE | DYNAMIC,
+
+ //////////////////////////////////////////////////////
+ //
+ // 0x0014 PRIMARY_SERVICE 0000F530-1212-EFDE-1523-785FEABCD123
+ //
+ //////////////////////////////////////////////////////
+ 0x18, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x28, 0x23, 0xd1, 0xbc, 0xea, 0x5f, 0x78, 0x23, 0x15, 0xde, 0xef, 0x12, 0x12, 0x30, 0xf5, 0x00, 0x00,
+
+ /* CHARACTERISTIC, 0000F531-1212-EFDE-1523-785FEABCD123, NOTIFY, */
+ // 0x0015 CHARACTERISTIC 0000F531-1212-EFDE-1523-785FEABCD123 NOTIFY
+ 0x1b, 0x00, 0x02, 0x00, 0x15, 0x00, 0x03, 0x28, 0x10, 0x16, 0x00, 0x23, 0xd1, 0xbc, 0xea, 0x5f, 0x78, 0x23, 0x15, 0xde, 0xef, 0x12, 0x12, 0x31, 0xf5, 0x00, 0x00,
+ // 0x0016 VALUE 0000F531-1212-EFDE-1523-785FEABCD123 NOTIFY
+ 0x16, 0x00, 0x10, 0x02, 0x16, 0x00, 0x23, 0xd1, 0xbc, 0xea, 0x5f, 0x78, 0x23, 0x15, 0xde, 0xef, 0x12, 0x12, 0x31, 0xf5, 0x00, 0x00,
+ // 0x0017 CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x17, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+ /* CHARACTERISTIC, 0000F532-1212-EFDE-1523-785FEABCD123, WRITE_WITHOUT_RESPONSE | DYNAMIC, */
+ // 0x0018 CHARACTERISTIC 0000F532-1212-EFDE-1523-785FEABCD123 WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x1b, 0x00, 0x02, 0x00, 0x18, 0x00, 0x03, 0x28, 0x04, 0x19, 0x00, 0x23, 0xd1, 0xbc, 0xea, 0x5f, 0x78, 0x23, 0x15, 0xde, 0xef, 0x12, 0x12, 0x32, 0xf5, 0x00, 0x00,
+ // 0x0019 VALUE 0000F532-1212-EFDE-1523-785FEABCD123 WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x16, 0x00, 0x04, 0x03, 0x19, 0x00, 0x23, 0xd1, 0xbc, 0xea, 0x5f, 0x78, 0x23, 0x15, 0xde, 0xef, 0x12, 0x12, 0x32, 0xf5, 0x00, 0x00,
+#endif
+
+ //////////////////////////////////////////////////////
+ //
+ // 0x0014 PRIMARY_SERVICE 1812
+ //
+ //////////////////////////////////////////////////////
+ // 0x0a, 0x00, 0x02, 0x00, 0x34, 0x00, 0x00, 0x28, 0x12, 0x18,//ios app can't disconn
+
+#if 0// authentication
+ //
+ 10, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x28, 0x0A, 0x18, //primary service declaration
+ 13, 0x00, 0x02, 0x00, 0x1B, 0x00, 0x03, 0x28, 0x02, 0x1C, 0x00, 0x50, 0x2A, //characteristic declaration
+ 15, 0x00, 0x02, 0x04, 0x1C, 0x00, 0x50, 0x2A, 0x02, 0x8A, 0x24, 0x66, 0x82, 0x34, 0x36, //PnP ID
+#endif
+
+ //////////////////////////////////////////////////////
+ //
+ // 0x0040 PRIMARY_SERVICE ae3a
+ //
+ //////////////////////////////////////////////////////
+ 0x0a, 0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x28, 0x3a, 0xae,
+
+ /* CHARACTERISTIC, ae3b, WRITE_WITHOUT_RESPONSE | DYNAMIC, */
+ // 0x0041 CHARACTERISTIC ae3b WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x41, 0x00, 0x03, 0x28, 0x04, 0x42, 0x00, 0x3b, 0xae,
+ // 0x0042 VALUE ae3b WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x08, 0x00, 0x04, 0x01, 0x42, 0x00, 0x3b, 0xae,
+
+ /* CHARACTERISTIC, ae3c, NOTIFY, */
+ // 0x0043 CHARACTERISTIC ae3c NOTIFY
+ 0x0d, 0x00, 0x02, 0x00, 0x43, 0x00, 0x03, 0x28, 0x10, 0x44, 0x00, 0x3c, 0xae,
+ // 0x0044 VALUE ae3c NOTIFY
+ 0x08, 0x00, 0x10, 0x00, 0x44, 0x00, 0x3c, 0xae,
+ // 0x0045 CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x45, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+ //////////////////////////////////////////////////////
+ //
+ // 0x0046 PRIMARY_SERVICE 1801
+ //
+ //////////////////////////////////////////////////////
+ 0x0a, 0x00, 0x02, 0x00, 0x46, 0x00, 0x00, 0x28, 0x01, 0x18,
+
+ /* CHARACTERISTIC, 2a05, INDICATE, */
+ // 0x0047 CHARACTERISTIC 2a05 INDICATE
+ 0x0d, 0x00, 0x02, 0x00, 0x47, 0x00, 0x03, 0x28, 0x20, 0x48, 0x00, 0x05, 0x2a,
+ // 0x0048 VALUE 2a05 INDICATE
+ 0x08, 0x00, 0x20, 0x00, 0x48, 0x00, 0x05, 0x2a,
+ // 0x0049 CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x49, 0x00, 0x02, 0x29, 0x00, 0x00,
+
+#if RCSP_BTMATE_EN
+ //////////////////////////////////////////////////////
+ //
+ // 0x0004 PRIMARY_SERVICE ae00
+ //
+ //////////////////////////////////////////////////////
+ 0x0a, 0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x28, 0x00, 0xae,
+
+ /* CHARACTERISTIC, ae01, WRITE_WITHOUT_RESPONSE | DYNAMIC, */
+ // 0x0040 CHARACTERISTIC ae01 WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x0d, 0x00, 0x02, 0x00, 0x81, 0x00, 0x03, 0x28, 0x04, 0x82, 0x00, 0x01, 0xae,
+ // 0x0041 VALUE ae01 WRITE_WITHOUT_RESPONSE | DYNAMIC
+ 0x08, 0x00, 0x04, 0x01, 0x82, 0x00, 0x01, 0xae,
+
+ /* CHARACTERISTIC, ae02, NOTIFY, */
+ // 0x0042 CHARACTERISTIC ae02 NOTIFY
+ 0x0d, 0x00, 0x02, 0x00, 0x83, 0x00, 0x03, 0x28, 0x10, 0x84, 0x00, 0x02, 0xae,
+ // 0x0043 VALUE ae02 NOTIFY
+ 0x08, 0x00, 0x10, 0x00, 0x84, 0x00, 0x02, 0xae,
+ // 0x0044 CLIENT_CHARACTERISTIC_CONFIGURATION
+ 0x0a, 0x00, 0x0a, 0x01, 0x85, 0x00, 0x02, 0x29, 0x00, 0x00,
+#endif
+ // END
+ 0x00, 0x00,
+};
+//
+// characteristics <--> handles
+//
+#if RCSP_BTMATE_EN
+#define ATT_CHARACTERISTIC_ae01_02_VALUE_HANDLE 0x0082
+#define ATT_CHARACTERISTIC_ae02_02_VALUE_HANDLE 0x0084
+#define ATT_CHARACTERISTIC_ae02_02_CLIENT_CONFIGURATION_HANDLE 0x0085
+#endif
+
+#define ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE 0x0003
+#define ATT_CHARACTERISTIC_ae01_01_VALUE_HANDLE 0x0006
+#define ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE 0x0008
+#define ATT_CHARACTERISTIC_ae02_01_CLIENT_CONFIGURATION_HANDLE 0x0009
+#define ATT_CHARACTERISTIC_ae03_01_VALUE_HANDLE 0x000b
+#define ATT_CHARACTERISTIC_ae04_01_VALUE_HANDLE 0x000d
+#define ATT_CHARACTERISTIC_ae04_01_CLIENT_CONFIGURATION_HANDLE 0x000e
+#define ATT_CHARACTERISTIC_ae05_01_VALUE_HANDLE 0x0010
+#define ATT_CHARACTERISTIC_ae05_01_CLIENT_CONFIGURATION_HANDLE 0x0011
+#define ATT_CHARACTERISTIC_ae10_01_VALUE_HANDLE 0x0013
+
+#define ATT_CHARACTERISTIC_ae3b_01_VALUE_HANDLE 0x0042
+#define ATT_CHARACTERISTIC_ae3c_01_VALUE_HANDLE 0x0044
+#define ATT_CHARACTERISTIC_ae3c_01_CLIENT_CONFIGURATION_HANDLE 0x0045
+#define ATT_CHARACTERISTIC_2a05_01_VALUE_HANDLE 0x0048
+#define ATT_CHARACTERISTIC_2a05_01_CLIENT_CONFIGURATION_HANDLE 0x0049
+
+#endif
diff --git a/apps/common/third_party_profile/jieli/trans_data_demo/spp_trans_data.c b/apps/common/third_party_profile/jieli/trans_data_demo/spp_trans_data.c
new file mode 100644
index 0000000..b5f6469
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/trans_data_demo/spp_trans_data.c
@@ -0,0 +1,227 @@
+
+#include "app_config.h"
+#include "app_action.h"
+
+#include "system/includes.h"
+#include "spp_user.h"
+#include "string.h"
+#include "circular_buf.h"
+#include "spp_trans_data.h"
+#include "bt_common.h"
+#include "btstack/avctp_user.h"
+
+#if 0
+extern void printf_buf(u8 *buf, u32 len);
+#define log_info printf
+#define log_info_hexdump printf_buf
+#else
+#define log_info(...)
+#define log_info_hexdump(...)
+#endif
+
+#define TEST_SPP_DATA_RATE 0
+
+/* #define DEBUG_ENABLE */
+/* #include "debug_log.h" */
+#include "spp_trans_data.h"
+#if TRANS_DATA_EN || TRANS_MULTI_SPP_EN || TUYA_TRANS_EN || TUYA_DEMO_EN
+
+#if TEST_SPP_DATA_RATE
+#define SPP_TIMER_MS (100)
+static u32 test_data_count;
+static u32 spp_timer_handle = 0;
+static u32 spp_test_start;
+#endif
+
+/*
+ 打开流控使能后,确定配置接口 transport_spp_flow_cfg 被调用初始化配置
+ 然后使用过程 通过接口 transport_spp_flow_enable 来控制流控开关
+ */
+#define SPP_DATA_RECIEVT_FLOW 0//流控功能使能
+
+//流控速度控制,可以不用更改
+#define FLOW_SEND_CREDITS_NUM 1 //控制命令中 控制可接收的数据包个数,发送给对方的,range(1~32)
+#define FLOW_SEND_CREDITS_TRIGGER_NUM 1 //触发更新控制命令的阈值,range(1 to <= FLOW_SEND_CREDITS_NUM)
+
+
+void rfcomm_change_credits_setting(u16 init_credits, u8 base);
+int rfcomm_send_cretits_by_profile(u16 rfcomm_cid, u16 credit, u8 auto_flag);
+
+static struct spp_operation_t *spp_api = NULL;
+static u8 spp_state;
+static u16 spp_channel;
+
+int transport_spp_send_data(u8 *data, u16 len)
+{
+ if (spp_api) {
+ log_info("spp_api_tx(%d) \n", len);
+ /* log_info_hexdump(data, len); */
+ clear_sniff_cnt();
+ return spp_api->send_data(NULL, data, len);
+ }
+ return SPP_USER_ERR_SEND_FAIL;
+}
+
+int transport_spp_send_data_check(u16 len)
+{
+ if (spp_api) {
+ if (spp_api->busy_state()) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void transport_spp_state_cbk(u8 state)
+{
+ spp_state = state;
+ switch (state) {
+ case SPP_USER_ST_CONNECT:
+ log_info("SPP_USER_ST_CONNECT ~~~\n");
+
+ break;
+
+ case SPP_USER_ST_DISCONN:
+ log_info("SPP_USER_ST_DISCONN ~~~\n");
+ spp_channel = 0;
+
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+static void transport_spp_send_wakeup(void)
+{
+ putchar('W');
+}
+
+static void transport_spp_recieve_cbk(void *priv, u8 *buf, u16 len)
+{
+ spp_channel = (u16)priv;
+ log_info("spp_api_rx(%d) \n", len);
+ log_info_hexdump(buf, len);
+ clear_sniff_cnt();
+
+#if TEST_SPP_DATA_RATE
+ if ((buf[0] == 'A') && (buf[1] == 'F')) {
+ spp_test_start = 1;//start
+ } else if ((buf[0] == 'A') && (buf[1] == 'A')) {
+ spp_test_start = 0;//stop
+ }
+#endif
+
+ //loop send data for test
+ if (transport_spp_send_data_check(len)) {
+ transport_spp_send_data(buf, len);
+ }
+}
+
+
+#if TEST_SPP_DATA_RATE
+
+static void test_spp_send_data(void)
+{
+ u16 send_len = 250;
+ if (transport_spp_send_data_check(send_len)) {
+ test_data_count += send_len;
+ transport_spp_send_data(&test_data_count, send_len);
+ }
+}
+
+static void test_timer_handler(void)
+{
+ static u32 t_count = 0;
+
+ if (SPP_USER_ST_CONNECT != spp_state) {
+ test_data_count = 0;
+ spp_test_start = 0;
+ return;
+ }
+
+ if (spp_test_start) {
+ test_spp_send_data();
+ }
+
+ if (++t_count < (1000 / SPP_TIMER_MS)) {
+ return;
+ }
+ t_count = 0;
+
+ if (test_data_count) {
+ log_info("\n-spp_data_rate: %d bps-\n", test_data_count * 8);
+ test_data_count = 0;
+ }
+}
+#endif
+
+
+void transport_spp_init(void)
+{
+ log_info("transport_spp_init\n");
+ log_info("spp_file: %s", __FILE__);
+#if (USER_SUPPORT_PROFILE_SPP==1)
+ spp_state = 0;
+ spp_get_operation_table(&spp_api);
+ spp_api->regist_recieve_cbk(0, transport_spp_recieve_cbk);
+ spp_api->regist_state_cbk(0, transport_spp_state_cbk);
+ spp_api->regist_wakeup_send(NULL, transport_spp_send_wakeup);
+#endif
+
+#if TEST_SPP_DATA_RATE
+ spp_timer_handle = sys_timer_add(NULL, test_timer_handler, SPP_TIMER_MS);
+#endif
+
+}
+
+void transport_spp_disconnect(void)
+{
+ if (SPP_USER_ST_CONNECT == spp_state) {
+ log_info("transport_spp_disconnect\n");
+ user_send_cmd_prepare(USER_CTRL_SPP_DISCONNECT, 0, NULL);
+ }
+}
+
+static void timer_spp_flow_test(void)
+{
+ static u8 sw = 0;
+ if (spp_channel) {
+ sw = !sw;
+ transport_spp_flow_enable(sw);
+ }
+}
+
+//配置流控制的参数,蓝牙协议栈初始化前调用配置
+void transport_spp_flow_cfg(void)
+{
+#if SPP_DATA_RECIEVT_FLOW
+ rfcomm_change_credits_setting(FLOW_SEND_CREDITS_NUM, FLOW_SEND_CREDITS_TRIGGER_NUM);
+
+ //for test
+ /* sys_timer_add(0,timer_spp_flow_test,2000); */
+#endif
+}
+
+//流控使能 EN: 1-停止收数 or 0-继续收数
+int transport_spp_flow_enable(u8 en)
+{
+ int ret = -1;
+ u16 credits = FLOW_SEND_CREDITS_NUM;
+
+#if SPP_DATA_RECIEVT_FLOW
+ if (spp_channel) {
+ if (en) {
+ credits = 0;
+ }
+ ret = rfcomm_send_cretits_by_profile(spp_channel, credits, !en);
+ }
+#endif
+
+ log_info("transport_spp_flow_enable:%02x,%d,%d\n", spp_channel, en, ret);
+ return ret;
+}
+
+#endif
+
diff --git a/apps/common/third_party_profile/jieli/trans_data_demo/spp_trans_data.h b/apps/common/third_party_profile/jieli/trans_data_demo/spp_trans_data.h
new file mode 100644
index 0000000..a27dc9d
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/trans_data_demo/spp_trans_data.h
@@ -0,0 +1,9 @@
+#ifndef __SPP_TRANS_DATA_H__
+#define __SPP_TRANS_DATA_H__
+
+#include "typedef.h"
+#include "bt_common.h"
+
+void transport_spp_init(void);
+
+#endif//__RCSP_SPP_USER_H__
diff --git a/apps/common/third_party_profile/jieli/wireless_mic/le_wireless_mic_client.c b/apps/common/third_party_profile/jieli/wireless_mic/le_wireless_mic_client.c
new file mode 100644
index 0000000..3f7494f
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/wireless_mic/le_wireless_mic_client.c
@@ -0,0 +1,1566 @@
+// *****************************************************************************
+/* EXAMPLE_START(le_counter): LE Peripheral - Heartbeat Counter over GATT
+ *
+ * @text All newer operating systems provide GATT Client functionality.
+ * The LE Counter examples demonstrates how to specify a minimal GATT Database
+ * with a custom GATT Service and a custom Characteristic that sends periodic
+ * notifications.
+ */
+// *****************************************************************************
+
+#include "system/app_core.h"
+#include "system/includes.h"
+
+#include "app_config.h"
+#include "app_action.h"
+
+#include "btstack/btstack_task.h"
+#include "btstack/bluetooth.h"
+#include "user_cfg.h"
+#include "vm.h"
+#include "btcontroller_modules.h"
+#include "bt_common.h"
+
+#include "le_client_demo.h"
+#include "le_common.h"
+#include "ble_user.h"
+
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_WIRELESS_MIC_CLIENT)
+
+#define SUPPORT_TEST_BOX_BLE_MASTER_TEST_EN 1
+#define SHOW_RX_DATA_RATE 1
+#define SHOW_TX_DATA_RATE 1
+
+#if LE_DEBUG_PRINT_EN
+/* #define log_info printf */
+#define log_info(x, ...) printf("[LE_CLIENT]" x " ", ## __VA_ARGS__)
+#define log_info_hexdump put_buf
+#else
+#define log_info(...)
+#define log_info_hexdump(...)
+#endif
+
+
+//------
+#define ATT_LOCAL_MTU_SIZE (517) //note: need >= 20
+#define ATT_SEND_CBUF_SIZE (200)//(256)//(512*10) //note: need >= 20,缓存大小,可修改
+#define ATT_RAM_BUFSIZE (ATT_CTRL_BLOCK_SIZE + ATT_LOCAL_MTU_SIZE + ATT_SEND_CBUF_SIZE) //note:
+static u8 att_ram_buffer[ATT_RAM_BUFSIZE] __attribute__((aligned(4)));
+
+#define SEARCH_PROFILE_BUFSIZE (512) //note:
+static u8 search_ram_buffer[SEARCH_PROFILE_BUFSIZE] __attribute__((aligned(4)));
+#define scan_buffer search_ram_buffer
+//---------------
+//搜索类型
+#define SET_SCAN_TYPE SCAN_ACTIVE
+//搜索 周期大小, 参数一:320 参数二:320 参数三:168
+#define SET_SCAN_INTERVAL 320//48//256//48 //(unit:0.625ms), 96没有干扰的情况下, 连接速度为60ms, 如需要降低功耗, 可以在+16的倍数
+//搜索 窗口大小 参数一:102 参数二:70 参数三:30
+#define SET_SCAN_WINDOW 70//48//24//48 //(unit:0.625ms)
+
+//连接周期
+#define SET_CONN_INTERVAL 3 //(unit:1.25ms)
+//连接latency
+#define SET_CONN_LATENCY 0 //(unit:conn_interval)
+//连接超时
+#define SET_CONN_TIMEOUT 400 //(unit:10ms)
+#if WIRELESS_TOOL_BLE_NAME_EN
+#define TEST_BOX_BLE_NAME "W_MIC_01"
+#define TEST_BOX_BLE_NAME_LEN (sizeof(TEST_BOX_BLE_NAME)-1)
+static u8 *match_name;
+#endif
+//----------------------------------------------------------------------------
+static u8 scan_ctrl_en;
+static u8 ble_work_state = 0;
+static void (*app_recieve_callback)(void *priv, void *buf, u16 len) = NULL;
+static void (*app_ble_state_callback)(void *priv, ble_state_e state) = NULL;
+static void (*ble_resume_send_wakeup)(void) = NULL;
+static u32 channel_priv;
+
+static hci_con_handle_t con_handle;
+
+#define BLE_VM_HEAD_TAG (0xB95C)
+#define BLE_VM_TAIL_TAG (0x5CB9)
+struct pair_info_t {
+ u16 head_tag;
+ u8 pair_flag;
+ u8 peer_address_info[7];
+ u16 tail_tag;
+};
+static struct pair_info_t conn_pair_info;
+static u8 pair_bond_enable = 0;
+
+//-------------------------------------------------------------------------------
+typedef struct {
+ uint16_t read_handle;
+ uint16_t read_long_handle;
+ uint16_t write_handle;
+ uint16_t write_no_respond;
+ uint16_t notify_handle;
+ uint16_t indicate_handle;
+} target_hdl_t;
+
+//记录handle 使用
+static target_hdl_t target_handle;
+static opt_handle_t opt_handle_table[OPT_HANDLE_MAX];
+static u8 opt_handle_used_cnt;
+static u8 force_seach_onoff = 0;
+static s8 force_seach_rssi = -127;
+static u8 cur_peer_address_info[7];
+static u8 flag_specific_adv_name = 0;
+static u8 flag_need_judge_rssi = 0;
+static u8 flag_specific_sacn = 0;
+
+static void bt_ble_create_connection(u8 *conn_addr, u8 addr_type);
+static int bt_ble_scan_enable(void *priv, u32 en);
+static int client_write_send(void *priv, u8 *data, u16 len);
+static int client_operation_send(u16 handle, u8 *data, u16 len, u8 att_op_type);
+#if WIRELESS_TOOL_BLE_NAME_EN
+static ble_state_e get_ble_work_state(void);
+#else
+static void set_ble_work_state(ble_state_e state);
+#endif
+static void client_create_connection_cannel(void);
+//---------------------------------------------------------------------------
+#if 1//default
+//指定搜索uuid
+//指定搜索uuid
+static const target_uuid_t default_search_uuid_table[] = {
+
+ // for uuid16
+ // PRIMARY_SERVICE, ae30
+ // CHARACTERISTIC, ae01, WRITE_WITHOUT_RESPONSE | DYNAMIC,
+ // CHARACTERISTIC, ae02, NOTIFY,
+
+ {
+ .services_uuid16 = 0xae30,
+ .characteristic_uuid16 = 0xae01,
+ .opt_type = ATT_PROPERTY_WRITE_WITHOUT_RESPONSE,
+ },
+
+ {
+ .services_uuid16 = 0xae30,
+ .characteristic_uuid16 = 0xae02,
+ .opt_type = ATT_PROPERTY_NOTIFY,
+ },
+
+ //for uuid128,sample
+ // PRIMARY_SERVICE, 0000F530-1212-EFDE-1523-785FEABCD123
+ // CHARACTERISTIC, 0000F531-1212-EFDE-1523-785FEABCD123, NOTIFY,
+ // CHARACTERISTIC, 0000F532-1212-EFDE-1523-785FEABCD123, WRITE_WITHOUT_RESPONSE | DYNAMIC,
+ /*
+ {
+ .services_uuid16 = 0,
+ .services_uuid128 = {0x00,0x00,0xF5,0x30 ,0x12,0x12 ,0xEF, 0xDE ,0x15,0x23 ,0x78,0x5F,0xEA ,0xBC,0xD1,0x23} ,
+ .characteristic_uuid16 = 0,
+ .characteristic_uuid128 = {0x00,0x00,0xF5,0x31 ,0x12,0x12 ,0xEF, 0xDE ,0x15,0x23 ,0x78,0x5F,0xEA ,0xBC,0xD1,0x23},
+ .opt_type = ATT_PROPERTY_NOTIFY,
+ },
+
+ {
+ .services_uuid16 = 0,
+ .services_uuid128 = {0x00,0x00,0xF5,0x30 ,0x12,0x12 ,0xEF, 0xDE ,0x15,0x23 ,0x78,0x5F,0xEA ,0xBC,0xD1,0x23} ,
+ .characteristic_uuid16 = 0,
+ .characteristic_uuid128 = {0x00,0x00,0xF5,0x32 ,0x12,0x12 ,0xEF, 0xDE ,0x15,0x23 ,0x78,0x5F,0xEA ,0xBC,0xD1,0x23},
+ .opt_type = ATT_PROPERTY_WRITE_WITHOUT_RESPONSE,
+ },
+ */
+
+};
+
+
+static void default_report_data_deal(att_data_report_t *report_data, target_uuid_t *search_uuid)
+{
+ log_info("report_data:%02x,%02x,%d,len(%d)", report_data->packet_type,
+ report_data->value_handle, report_data->value_offset, report_data->blob_length);
+
+ log_info_hexdump(report_data->blob, report_data->blob_length);
+
+ switch (report_data->packet_type) {
+ case GATT_EVENT_NOTIFICATION: //notify
+ break;
+ case GATT_EVENT_INDICATION://indicate
+ case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT://read
+ break;
+ case GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT://read long
+ break;
+
+ default:
+ break;
+ }
+}
+
+static const u8 test_remoter_name1[] = "AC637N_MX(BLE)";//
+/* static const u8 test_remoter_name2[] = "AC630N_HID567(BLE)";// */
+static u16 default_client_write_handle;
+static u16 test_client_timer = 0;
+
+static const client_match_cfg_t match_dev01 = {
+ .create_conn_mode = BIT(CLI_CREAT_BY_NAME),
+ .compare_data_len = sizeof(test_remoter_name1) - 1, //去结束符
+ .compare_data = test_remoter_name1,
+ .bonding_flag = 0,
+};
+
+/* static const client_match_cfg_t match_dev02 = { */
+/* .create_conn_mode = BIT(CLI_CREAT_BY_NAME), */
+/* .compare_data_len = sizeof(test_remoter_name2) - 1, //去结束符 */
+/* .compare_data = test_remoter_name2, */
+/* .bonding_flag = 1, */
+/* }; */
+
+static void default_test_write(void)
+{
+ static u32 count = 0;
+ count++;
+ int ret = client_operation_send(default_client_write_handle, &count, 16, ATT_OP_WRITE_WITHOUT_RESPOND);
+ log_info("test_write:%x", ret);
+}
+
+static void default_event_callback(le_client_event_e event, u8 *packet, int size)
+{
+ switch (event) {
+ case CLI_EVENT_MATCH_DEV: {
+ client_match_cfg_t *match_dev = packet;
+ log_info("match_name:%s\n", match_dev->compare_data);
+ }
+ break;
+
+ case CLI_EVENT_MATCH_UUID: {
+ opt_handle_t *opt_hdl = packet;
+ if (opt_hdl->search_uuid == &default_search_uuid_table[0]) {
+ default_client_write_handle = opt_hdl->value_handle;
+ log_info("match_uuid22\n");
+ }
+ }
+ break;
+
+ case CLI_EVENT_SEARCH_PROFILE_COMPLETE:
+ log_info("CLI_EVENT_SEARCH_PROFILE_COMPLETE\n");
+ if ((!test_client_timer) && default_client_write_handle) {
+ log_info("test timer_add\n");
+ test_client_timer = sys_hi_timer_add(0, default_test_write, 500);
+ }
+ break;
+
+ case CLI_EVENT_CONNECTED:
+ break;
+
+ case CLI_EVENT_DISCONNECT:
+ if (test_client_timer) {
+ sys_timeout_del(test_client_timer);
+ test_client_timer = 0;
+ }
+ default_client_write_handle = 0;
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+static const client_conn_cfg_t client_conn_config_default = {
+ .match_dev_cfg[0] = &match_dev01,
+ .match_dev_cfg[1] = NULL,
+ .match_dev_cfg[2] = NULL,
+ /* .match_dev_cfg[1] = &match_dev02, */
+ .report_data_callback = default_report_data_deal,
+ .search_uuid_cnt = (sizeof(default_search_uuid_table) / sizeof(target_uuid_t)),
+ .search_uuid_table = default_search_uuid_table,
+ .security_en = 0,
+ .event_callback = default_event_callback,
+};
+
+#endif
+
+//---------------------------------------------------------------------------
+static client_conn_cfg_t *client_config = NULL; //(void *) &client_conn_config_default ;
+//----------------------------------------------------------------------------
+
+
+static const struct conn_update_param_t connection_param_table[] = {
+ {16, 24, 0, 600},//11
+ {12, 28, 0, 600},//3.7
+ {8, 20, 0, 600},
+ {50, 60, 0, 600},
+};
+
+static u8 send_param_index = 3;
+
+static int client_create_connect_api(u8 *addr, u8 addr_type, u8 mode);
+static int client_create_cannel_api(void);
+//----------------------------------------------------------------------------
+
+static void client_event_report(le_client_event_e event, u8 *packet, int size)
+{
+ if (client_config->event_callback) {
+ client_config->event_callback(event, packet, size);
+ }
+}
+
+static bool check_device_is_match(u8 info_type, u8 *data, int size)
+{
+ int i;
+ u8 conn_mode = BIT(info_type);
+ client_match_cfg_t *cfg;
+
+ /* log_info_hexdump(data,size); */
+
+ for (i = 0; i < CLIENT_MATCH_CONN_MAX; i++) {
+ cfg = client_config->match_dev_cfg[i];
+ if (cfg == NULL) {
+ continue;
+ }
+ /* log_info("cfg = %08x\n",cfg); */
+ /* log_info_hexdump(cfg,sizeof(client_match_cfg_t)); */
+ if (cfg->create_conn_mode == conn_mode && size == cfg->compare_data_len) {
+ log_info("match check\n");
+ /* log_info_hexdump(data, size); */
+ /* log_info_hexdump(cfg->compare_data, size); */
+ if (0 == memcmp(data, cfg->compare_data, cfg->compare_data_len)) {
+ log_info("match ok\n");
+ pair_bond_enable = cfg->bonding_flag;
+ client_event_report(CLI_EVENT_MATCH_DEV, cfg, sizeof(client_match_cfg_t));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static void conn_pair_vm_do(struct pair_info_t *info, u8 rw_flag)
+{
+ /* return; */
+
+ int ret;
+ int vm_len = sizeof(struct pair_info_t);
+
+ log_info("-conn_pair_info vm_do:%d\n", rw_flag);
+ if (rw_flag == 0) {
+ ret = syscfg_read(CFG_BLE_MODE_INFO, (u8 *)info, vm_len);
+ if (!ret) {
+ log_info("-null--\n");
+ }
+ if ((BLE_VM_HEAD_TAG == info->head_tag) && (BLE_VM_TAIL_TAG == info->tail_tag)) {
+ log_info("-exist--\n");
+ log_info_hexdump((u8 *)info, vm_len);
+ } else {
+ memset(info, 0, vm_len);
+ info->head_tag = BLE_VM_HEAD_TAG;
+ info->tail_tag = BLE_VM_TAIL_TAG;
+ }
+ } else {
+ syscfg_write(CFG_BLE_MODE_INFO, (u8 *)info, vm_len);
+ }
+}
+//------------------------------------------------------------
+static ble_state_e get_ble_work_state(void)
+{
+ return ble_work_state;
+}
+
+void clear_bonding_info(void)
+{
+ log_info("client_clear_bonding_info\n");
+ conn_pair_vm_do(&conn_pair_info, 0);
+ if (conn_pair_info.pair_flag) {
+ //del pair bond
+ memset(&conn_pair_info, 0, sizeof(struct pair_info_t));
+ conn_pair_vm_do(&conn_pair_info, 1);
+
+#if WIRELESS_PAIR_BONDING
+ if (get_ble_work_state() == BLE_ST_CREATE_CONN) {
+ client_create_connection_cannel();
+ bt_ble_scan_enable(0, 1);
+ } else if (con_handle) {
+ ble_disconnect();
+ }
+#endif
+ }
+}
+
+//------------------------------------------------------------
+static void set_ble_work_state(ble_state_e state)
+{
+ if (state != ble_work_state) {
+ log_info("ble_client_work_st:%x->%x\n", ble_work_state, state);
+ ble_work_state = state;
+ if (app_ble_state_callback) {
+ app_ble_state_callback((void *)channel_priv, state);
+ }
+ }
+}
+
+
+//-------------------------------------------------------------------------------
+static void check_target_uuid_match(search_result_t *result_info)
+{
+ u32 i;
+ target_uuid_t *t_uuid;
+
+ for (i = 0; i < client_config->search_uuid_cnt; i++) {
+ t_uuid = &client_config->search_uuid_table[i];
+ if (result_info->services.uuid16) {
+ if (result_info->services.uuid16 != t_uuid->services_uuid16) {
+ /* log_info("b1"); */
+ continue;
+ }
+ } else {
+ if (memcmp(result_info->services.uuid128, t_uuid->services_uuid128, 16)) {
+ /* log_info("b2"); */
+ continue;
+ }
+ }
+
+ if (result_info->characteristic.uuid16) {
+ if (result_info->characteristic.uuid16 != t_uuid->characteristic_uuid16) {
+ /* log_info("b3"); */
+ /* log_info("%d: %04x--%04x",result_info->characteristic.uuid16,t_uuid->characteristic_uuid16); */
+ continue;
+ }
+ } else {
+ if (memcmp(result_info->characteristic.uuid128, t_uuid->characteristic_uuid128, 16)) {
+ /* log_info("b4"); */
+ continue;
+ }
+ }
+
+ break;//match one
+ }
+
+ if (i >= client_config->search_uuid_cnt) {
+ return;
+ }
+
+ if (opt_handle_used_cnt >= OPT_HANDLE_MAX) {
+ log_info("opt_handle is full!!!\n");
+ return;
+ }
+
+ if ((t_uuid->opt_type & result_info->characteristic.properties) != t_uuid->opt_type) {
+ log_info("properties not match!!!\n");
+ return;
+ }
+
+ log_info("match one uuid\n");
+
+ opt_handle_t *opt_get = &opt_handle_table[opt_handle_used_cnt++];
+ opt_get->value_handle = result_info->characteristic.value_handle;
+ opt_get->search_uuid = t_uuid;
+
+ switch (t_uuid->opt_type) {
+ case ATT_PROPERTY_READ:
+ target_handle.read_handle = result_info->characteristic.value_handle;
+ break;
+
+ case ATT_PROPERTY_WRITE_WITHOUT_RESPONSE:
+ target_handle.write_no_respond = result_info->characteristic.value_handle;
+ break;
+
+ case ATT_PROPERTY_WRITE:
+ target_handle.write_handle = result_info->characteristic.value_handle;
+ break;
+
+ case ATT_PROPERTY_NOTIFY:
+ target_handle.notify_handle = result_info->characteristic.value_handle;
+ break;
+
+ case ATT_PROPERTY_INDICATE:
+ target_handle.indicate_handle = result_info->characteristic.value_handle;
+ break;
+
+ default:
+ break;
+ }
+
+ client_event_report(CLI_EVENT_MATCH_UUID, opt_get, sizeof(opt_handle_t));
+
+}
+
+//操作handle,完成 write ccc
+static void do_operate_search_handle(void)
+{
+ u16 tmp_16;
+ u16 i, cur_opt_type;
+ opt_handle_t *opt_hdl_pt;
+
+ log_info("opt_handle_used_cnt= %d\n", opt_handle_used_cnt);
+
+ log_info("find target_handle:");
+ log_info_hexdump(&target_handle, sizeof(target_hdl_t));
+
+ if (0 == opt_handle_used_cnt) {
+ goto opt_end;
+ }
+
+ /* test_send_conn_update();//for test */
+
+ for (i = 0; i < opt_handle_used_cnt; i++) {
+ opt_hdl_pt = &opt_handle_table[i];
+ cur_opt_type = opt_hdl_pt->search_uuid->opt_type;
+ switch ((u8)cur_opt_type) {
+ case ATT_PROPERTY_READ:
+ if (1) {
+ tmp_16 = 0x55A2;//fixed
+ log_info("read_long:%04x\n", opt_hdl_pt->value_handle);
+ client_operation_send(opt_hdl_pt->value_handle, (u8 *)&tmp_16, 2, ATT_OP_READ_LONG);
+ } else {
+ tmp_16 = 0x55A1;//fixed
+ log_info("read:%04x\n", opt_hdl_pt->value_handle);
+ client_operation_send(opt_hdl_pt->value_handle, (u8 *)&tmp_16, 2, ATT_OP_READ);
+ }
+ break;
+
+ case ATT_PROPERTY_NOTIFY:
+ tmp_16 = 0x01;//fixed
+ log_info("write_ntf_ccc:%04x\n", opt_hdl_pt->value_handle);
+ client_operation_send(opt_hdl_pt->value_handle + 1, &tmp_16, 2, ATT_OP_WRITE);
+ break;
+
+ case ATT_PROPERTY_INDICATE:
+ tmp_16 = 0x02;//fixed
+ log_info("write_ind_ccc:%04x\n", opt_hdl_pt->value_handle);
+ client_operation_send(opt_hdl_pt->value_handle + 1, &tmp_16, 2, ATT_OP_WRITE);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+opt_end:
+ set_ble_work_state(BLE_ST_SEARCH_COMPLETE);
+
+}
+
+//协议栈内部调用
+//return: 0--accept,1--reject
+int l2cap_connection_update_request_just(u8 *packet, hci_con_handle_t handle)
+{
+ log_info("slave request conn_update:\n-interval_min= %d,\n-interval_max= %d,\n-latency= %d,\n-timeout= %d\n",
+ little_endian_read_16(packet, 0), little_endian_read_16(packet, 2),
+ little_endian_read_16(packet, 4), little_endian_read_16(packet, 6));
+ return 0;
+ /* return 1; */
+}
+
+//协议栈内部调用
+void user_client_report_search_result(search_result_t *result_info)
+{
+ if (result_info == (void *) - 1) {
+ log_info("client_report_search_result finish!!!\n");
+ do_operate_search_handle();
+ client_event_report(CLI_EVENT_SEARCH_PROFILE_COMPLETE, 0, 0);
+ return;
+ }
+
+ log_info("\n*** services, uuid16:%04x,index=%d ***\n", result_info->services.uuid16, result_info->service_index);
+ log_info("{charactc, uuid16:%04x,index=%d,handle:%04x~%04x,value_handle=%04x}\n",
+ result_info->characteristic.uuid16, result_info->characteristic_index,
+ result_info->characteristic.start_handle, result_info->characteristic.end_handle,
+ result_info->characteristic.value_handle
+ );
+
+ if (!result_info->services.uuid16) {
+ log_info("######services_uuid128:");
+ log_info_hexdump(result_info->services.uuid128, 16);
+ }
+
+ if (!result_info->characteristic.uuid16) {
+ log_info("######charact_uuid128:");
+ log_info_hexdump(result_info->characteristic.uuid128, 16);
+ }
+
+ check_target_uuid_match(result_info);
+}
+
+#if (SHOW_RX_DATA_RATE | SHOW_TX_DATA_RATE)
+
+static u32 client_timer_handle = 0;
+static u32 test_rx_data_count;
+static u32 test_tx_data_count;
+
+static void client_timer_handler(void)
+{
+ if (!con_handle) {
+ test_rx_data_count = 0;
+
+ test_tx_data_count = 0;
+
+ return;
+ }
+
+ if (test_rx_data_count) {
+ log_info("peer_rssi = %d\n", ble_vendor_get_peer_rssi(con_handle));
+ /* log_info("\n-ble_data_rate: %d bps-\n", test_rx_data_count * 8); */
+ log_info("%d bytes receive: %d.%02d KB/s \n", test_rx_data_count, test_rx_data_count / 1000, test_rx_data_count % 1000);
+
+ test_rx_data_count = 0;
+ }
+
+ if (test_tx_data_count) {
+ log_info("peer_rssi = %d\n", ble_vendor_get_peer_rssi(con_handle));
+ log_info("%d bytes send: %d.%02d KB/s \n", test_tx_data_count, test_tx_data_count / 1000, test_tx_data_count % 1000);
+
+ test_tx_data_count = 0;
+ }
+}
+
+static void client_timer_start(void)
+{
+ client_timer_handle = sys_timer_add(NULL, client_timer_handler, 1000);
+}
+
+#endif /* SHOW_RX_DATA_RATE | SHOW_TX_DATA_RATE */
+
+static target_uuid_t *get_match_handle_target(u16 handle)
+{
+ for (int i = 0; i < opt_handle_used_cnt; i++) {
+ if (opt_handle_table[i].value_handle == handle) {
+ return opt_handle_table[i].search_uuid;
+ }
+ }
+ return NULL;
+}
+
+//协议栈内部调用
+void user_client_report_data_callback(att_data_report_t *report_data)
+{
+ /* log_info("\n-report_data:type %02x,handle %04x,offset %d,len %d:",report_data->packet_type, */
+ /* report_data->value_handle,report_data->value_offset,report_data->blob_length); */
+ /* log_info_hexdump(report_data->blob,report_data->blob_length); */
+
+#if SHOW_RX_DATA_RATE
+ test_rx_data_count += report_data->blob_length;
+#endif /* SHOW_RX_DATA_RATE */
+
+ target_uuid_t *search_uuid = get_match_handle_target(report_data->value_handle);
+
+ if (client_config->report_data_callback) {
+ client_config->report_data_callback(report_data, search_uuid);
+ return;
+ }
+
+ switch (report_data->packet_type) {
+ case GATT_EVENT_NOTIFICATION://notify
+// log_info("\n-notify_rx(%d):",report_data->blob_length);
+ case GATT_EVENT_INDICATION://indicate
+ case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT://read
+ case GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT://read long
+ break;
+ default:
+ break;
+ }
+}
+
+// PRIMARY_SERVICE,AE30
+/* static const u16 test_services_uuid16 = 0xae30; */
+
+// PRIMARY_SERVICE, 0000F530-1212-EFDE-1523-785FEABCD123
+/* static const u8 test_services_uuid128[16] = {0x00,0x00,0xF5,0x30 ,0x12,0x12 ,0xEF, 0xDE ,0x15,0x23 ,0x78,0x5F,0xEA ,0xBC,0xD1,0x23}; */
+
+static void client_search_profile_start(void)
+{
+ opt_handle_used_cnt = 0;
+ memset(&target_handle, 0, sizeof(target_hdl_t));
+ user_client_init(con_handle, search_ram_buffer, SEARCH_PROFILE_BUFSIZE);
+ if (client_config->search_uuid_cnt) {
+ printf("[debug] %s, %d\n", __FUNCTION__, __LINE__);
+ ble_op_search_profile_all();
+ } else {
+ printf("[debug] %s, %d\n", __FUNCTION__, __LINE__);
+ user_client_set_search_complete();
+ }
+}
+
+//------------------------------------------------------------
+static bool resolve_adv_report(u8 *adv_address, u8 data_length, u8 *data, s8 rssi)
+{
+ u8 i, lenght, ad_type;
+ u8 *adv_data_pt;
+ u8 find_remoter = 0;
+ /* u8 tmp_addr[6]; */
+ u32 tmp32;
+
+ if (check_device_is_match(CLI_CREAT_BY_ADDRESS, adv_address, 6)) {
+ find_remoter = 1;
+ }
+
+ adv_data_pt = data;
+ for (i = 0; i < data_length;) {
+ if (*adv_data_pt == 0) {
+ /* log_info("analyze end\n"); */
+ break;
+ }
+
+ lenght = *adv_data_pt++;
+
+ if (lenght >= data_length || (lenght + i) >= data_length) {
+ /*过滤非标准包格式*/
+ printf("!!!error_adv_packet:");
+ put_buf(data, data_length);
+ break;
+ }
+
+ ad_type = *adv_data_pt++;
+ i += (lenght + 1);
+
+ switch (ad_type) {
+ case HCI_EIR_DATATYPE_FLAGS:
+ /* log_info("flags:%02x\n",adv_data_pt[0]); */
+ break;
+
+ case HCI_EIR_DATATYPE_MORE_16BIT_SERVICE_UUIDS:
+ case HCI_EIR_DATATYPE_COMPLETE_16BIT_SERVICE_UUIDS:
+ case HCI_EIR_DATATYPE_MORE_32BIT_SERVICE_UUIDS:
+ case HCI_EIR_DATATYPE_COMPLETE_32BIT_SERVICE_UUIDS:
+ case HCI_EIR_DATATYPE_MORE_128BIT_SERVICE_UUIDS:
+ case HCI_EIR_DATATYPE_COMPLETE_128BIT_SERVICE_UUIDS:
+ /* log_info("service uuid:"); */
+ /* log_info_hexdump(adv_data_pt, lenght - 1); */
+ break;
+
+ case HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME:
+ case HCI_EIR_DATATYPE_SHORTENED_LOCAL_NAME:
+ tmp32 = adv_data_pt[lenght - 1];
+ adv_data_pt[lenght - 1] = 0;;
+ log_info("remoter_name: %s,rssi:%d\n", adv_data_pt, rssi);
+ log_info_hexdump(adv_address, 6);
+ adv_data_pt[lenght - 1] = tmp32;
+ //-------
+#if 1 //无线麦产线通过识别特殊字符串进行近距离连接测试
+ if (0 == memcmp(adv_data_pt, SPECIFIC_STRING, strlen(SPECIFIC_STRING))) {
+ flag_specific_adv_name = 1;
+ flag_need_judge_rssi = 1;
+ }
+ if (flag_specific_sacn) {
+ flag_need_judge_rssi = 1;
+ }
+ if (flag_need_judge_rssi) {
+ flag_need_judge_rssi = 0;
+ if (rssi + TCFG_WIRELESS_RSSI < 0) {
+ printf("rssi no satisfy,break");
+ break;
+ } else {
+ printf("rssi satisfy,RSSI = %d", rssi);
+ if (flag_specific_adv_name) {
+ find_remoter = 1;
+ break;
+ }
+ }
+ }
+
+ flag_specific_adv_name = 0;
+#endif
+
+#if SUPPORT_TEST_BOX_BLE_MASTER_TEST_EN
+#if !WIRELESS_TOOL_BLE_NAME_EN
+#define TEST_BOX_BLE_NAME "W_MIC_01"
+#define TEST_BOX_BLE_NAME_LEN sizeof(TEST_BOX_BLE_NAME)
+ printf("TEST_BOX_BLE_NAME_LEN=%d", TEST_BOX_BLE_NAME_LEN);
+ if (0 == memcmp(adv_data_pt, TEST_BOX_BLE_NAME, TEST_BOX_BLE_NAME_LEN)) {
+ find_remoter = 1;
+ break;
+ }
+#else
+ put_buf(match_name, strlen(match_name));
+ if (lenght == strlen(match_name) + 1) {
+ printf("TEST_BOX_BLE_NAME_LEN=%d", TEST_BOX_BLE_NAME_LEN);
+ if (0 == memcmp(adv_data_pt, match_name, lenght - 1)) {
+ find_remoter = 1;
+ break;
+ }
+ }
+#endif
+#endif
+ /* log_info("target name:%s", client_config->compare_data); */
+ if (check_device_is_match(CLI_CREAT_BY_NAME, adv_data_pt, lenght - 1)) {
+ find_remoter = 1;
+ log_info("catch name ok\n");
+ }
+ break;
+
+ case HCI_EIR_DATATYPE_MANUFACTURER_SPECIFIC_DATA:
+ if (check_device_is_match(CLI_CREAT_BY_TAG, adv_data_pt, lenght - 1)) {
+ log_info("get_tag_string!\n");
+ find_remoter = 1;
+ }
+ break;
+
+ case HCI_EIR_DATATYPE_APPEARANCE_DATA:
+ /* log_info("get_class_type:%04x\n",little_endian_read_16(adv_data_pt,0)); */
+ break;
+
+ default:
+ /* log_info("unknow ad_type:"); */
+ break;
+ }
+
+ if (find_remoter) {
+ log_info_hexdump(adv_data_pt, lenght - 1);
+ }
+ adv_data_pt += (lenght - 1);
+ }
+
+ return find_remoter;
+}
+
+static void client_report_adv_data(adv_report_t *report_pt, u16 len)
+{
+ bool find_remoter;
+
+ /* log_info("event_type,addr_type: %x,%x; ",report_pt->event_type,report_pt->address_type); */
+ /* log_info_hexdump(report_pt->address,6); */
+
+ /* log_info("adv_data_display:"); */
+ /* log_info_hexdump(report_pt->data,report_pt->length); */
+
+// log_info("rssi:%d\n",report_pt->rssi);
+#if WIRELESS_PAIR_BONDING
+
+ if (conn_pair_info.pair_flag) {
+ if (report_pt->event_type != 1) {
+ return;
+ }
+ printf("report_add_type == %x", report_pt->address_type);
+ printf("conn_add_type == %x", conn_pair_info.peer_address_info[0]);
+ put_buf(report_pt->address, 6);
+ put_buf(&conn_pair_info.peer_address_info[1], 6);
+ if (report_pt->address_type == conn_pair_info.peer_address_info[0]
+ && 0 == memcmp(&conn_pair_info.peer_address_info[1], report_pt->address, 6)) {
+ log_info("match bond_dev\n");
+ find_remoter = 1;
+ goto just_creat;
+ } else {
+ return;
+ }
+ }
+ find_remoter = resolve_adv_report(report_pt->address, report_pt->length, report_pt->data, report_pt->rssi);
+
+just_creat:
+
+#else
+ find_remoter = resolve_adv_report(report_pt->address, report_pt->length, report_pt->data, report_pt->rssi);
+#endif
+
+ if (find_remoter) {
+ if (force_seach_onoff && force_seach_rssi > report_pt->rssi) {
+ log_info("match but rssi fail!!!:%d,%d\n", force_seach_rssi, report_pt->rssi);
+ return;
+ }
+
+ log_info("rssi:%d\n", report_pt->rssi);
+ log_info("\n*********create_connection***********\n");
+ log_info("***remote type %d,addr:", report_pt->address_type);
+ log_info_hexdump(report_pt->address, 6);
+ bt_ble_scan_enable(0, 0);
+ client_create_connect_api(report_pt->address, report_pt->address_type, 0);
+ log_info("*create_finish\n");
+ }
+}
+
+
+static void client_create_connection(u8 *conn_addr, u8 addr_type)
+{
+ struct create_conn_param_t *create_conn_par = scan_buffer;
+ if (get_ble_work_state() == BLE_ST_CREATE_CONN) {
+ log_info("already create conn!!!\n");
+ return;
+ }
+ create_conn_par->conn_interval = SET_CONN_INTERVAL;
+ create_conn_par->conn_latency = SET_CONN_LATENCY;
+ create_conn_par->supervision_timeout = SET_CONN_TIMEOUT;
+ memcpy(create_conn_par->peer_address, conn_addr, 6);
+ create_conn_par->peer_address_type = addr_type;
+
+ set_ble_work_state(BLE_ST_CREATE_CONN);
+ log_info_hexdump(create_conn_par, sizeof(struct create_conn_param_t));
+ ble_op_create_connection(create_conn_par);
+}
+
+static void bt_ble_create_connection(u8 *conn_addr, u8 addr_type)
+{
+ client_create_connection(conn_addr, addr_type);
+}
+
+static void client_create_connection_cannel(void)
+{
+ if (get_ble_work_state() == BLE_ST_CREATE_CONN) {
+ set_ble_work_state(BLE_ST_SEND_CREATE_CONN_CANNEL);
+ ble_op_create_connection_cancel();
+ }
+}
+
+static int ble_disconnect(void *priv)
+{
+ if (con_handle) {
+ if (BLE_ST_SEND_DISCONN != get_ble_work_state()) {
+ log_info(">>>ble send disconnect\n");
+ set_ble_work_state(BLE_ST_SEND_DISCONN);
+ ble_op_disconnect(con_handle);
+ } else {
+ log_info(">>>ble wait disconnect...\n");
+ }
+ return APP_BLE_NO_ERROR;
+ } else {
+ return APP_BLE_OPERATION_ERROR;
+ }
+}
+
+static void connection_update_complete_success(u8 *packet)
+{
+ int con_handle, conn_interval, conn_latency, conn_timeout;
+
+ conn_interval = hci_subevent_le_connection_update_complete_get_conn_interval(packet);
+ conn_latency = hci_subevent_le_connection_update_complete_get_conn_latency(packet);
+ conn_timeout = hci_subevent_le_connection_update_complete_get_supervision_timeout(packet);
+
+ log_info("conn_interval = %d\n", conn_interval);
+ log_info("conn_latency = %d\n", conn_latency);
+ log_info("conn_timeout = %d\n", conn_timeout);
+}
+
+
+static void cbk_sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
+{
+ sm_just_event_t *event = (void *)packet;
+ u32 tmp32;
+ switch (packet_type) {
+ case HCI_EVENT_PACKET:
+ switch (hci_event_packet_get_type(packet)) {
+ case SM_EVENT_JUST_WORKS_REQUEST:
+ sm_just_works_confirm(sm_event_just_works_request_get_handle(packet));
+ log_info("Just Works Confirmed.\n");
+ break;
+ case SM_EVENT_PASSKEY_DISPLAY_NUMBER:
+ log_info_hexdump(packet, size);
+ memcpy(&tmp32, event->data, 4);
+ log_info("Passkey display: %06u.\n", tmp32);
+ break;
+ }
+ break;
+ }
+}
+
+static void can_send_now_wakeup(void)
+{
+ /* putchar('E'); */
+ if (ble_resume_send_wakeup) {
+ ble_resume_send_wakeup();
+ }
+}
+
+const char *const phy_result[] = {
+ "None",
+ "1M",
+ "2M",
+ "Coded",
+};
+
+static void set_connection_data_length(u16 tx_octets, u16 tx_time)
+{
+ if (con_handle) {
+ ble_op_set_data_length(con_handle, tx_octets, tx_time);
+ }
+}
+
+static void set_connection_data_phy(u8 tx_phy, u8 rx_phy)
+{
+ if (0 == con_handle) {
+ return;
+ }
+
+ u8 all_phys = 0;
+ u16 phy_options = 0;
+
+ ble_op_set_ext_phy(con_handle, all_phys, tx_phy, rx_phy, phy_options);
+}
+
+static void client_profile_start(u16 con_handle)
+{
+ ble_op_att_send_init(con_handle, att_ram_buffer, ATT_RAM_BUFSIZE, ATT_LOCAL_MTU_SIZE);
+ set_ble_work_state(BLE_ST_CONNECT);
+ printf("[debug] %s, %d\n", __FUNCTION__, __LINE__);
+ if (0 == client_config->security_en) {
+ printf("[debug] %s, %d\n", __FUNCTION__, __LINE__);
+ client_search_profile_start();
+ }
+}
+
+/* LISTING_START(packetHandler): Packet Handler */
+static void cbk_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
+{
+ int mtu;
+ u32 tmp;
+ u8 status;
+
+ switch (packet_type) {
+ case HCI_EVENT_PACKET:
+ switch (hci_event_packet_get_type(packet)) {
+
+ /* case DAEMON_EVENT_HCI_PACKET_SENT: */
+ /* break; */
+ case ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE:
+ log_info("ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE\n");
+ case ATT_EVENT_CAN_SEND_NOW:
+ can_send_now_wakeup();
+ break;
+
+ case HCI_EVENT_LE_META:
+ switch (hci_event_le_meta_get_subevent_code(packet)) {
+
+ case HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE:
+ status = hci_subevent_le_enhanced_connection_complete_get_status(packet);
+ if (status) {
+ log_info("LE_MASTER CREATE CONNECTION FAIL!!! %0x\n", status);
+ set_ble_work_state(BLE_ST_DISCONN);
+ break;
+ }
+ con_handle = hci_subevent_le_enhanced_connection_complete_get_connection_handle(packet);
+ log_info("HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE : 0x%0x\n", con_handle);
+ log_info("conn_interval = %d\n", hci_subevent_le_enhanced_connection_complete_get_conn_interval(packet));
+ log_info("conn_latency = %d\n", hci_subevent_le_enhanced_connection_complete_get_conn_latency(packet));
+ log_info("conn_timeout = %d\n", hci_subevent_le_enhanced_connection_complete_get_supervision_timeout(packet));
+ client_profile_start(con_handle);
+ break;
+
+ case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
+ if (packet[3]) {
+ log_info("LE_MASTER CREATE CONNECTION FAIL!!! %0x\n", packet[3]);
+ set_ble_work_state(BLE_ST_DISCONN);
+ break;
+ }
+ con_handle = hci_subevent_le_connection_complete_get_connection_handle(packet);
+ log_info("HCI_SUBEVENT_LE_CONNECTION_COMPLETE : %0x\n", con_handle);
+ connection_update_complete_success(packet + 8);
+ client_profile_start(con_handle);
+ client_event_report(CLI_EVENT_CONNECTED, packet, size);
+#if WIRELESS_PAIR_BONDING
+ memcpy(cur_peer_address_info, &packet[7], 7);
+ conn_pair_info.pair_flag = 1;
+ printf("pair_flag == %d", conn_pair_info.pair_flag);
+ put_buf(cur_peer_address_info, 7);
+ memcpy(&conn_pair_info.peer_address_info, cur_peer_address_info, 7);
+ conn_pair_info.head_tag = BLE_VM_HEAD_TAG;
+ conn_pair_info.tail_tag = BLE_VM_TAIL_TAG;
+ conn_pair_vm_do(&conn_pair_info, 1);
+#else
+ if (pair_bond_enable) {
+ conn_pair_info.pair_flag = 1;
+ memcpy(&conn_pair_info.peer_address_info, &packet[7], 7);
+ conn_pair_vm_do(&conn_pair_info, 1);
+ pair_bond_enable = 0;
+ }
+#endif
+ break;
+
+ case HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE:
+ log_info("APP HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE\n");
+ connection_update_complete_success(packet);
+
+ client_event_report(CLI_EVENT_CONNECTION_UPDATE, packet, size);
+
+ break;
+
+ case HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE:
+ log_info("APP HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE");
+ break;
+
+ case HCI_SUBEVENT_LE_PHY_UPDATE_COMPLETE:
+ log_info("APP HCI_SUBEVENT_LE_PHY_UPDATE %s\n", hci_event_le_meta_get_phy_update_complete_status(packet) ? "Fail" : "Succ");
+ log_info("Tx PHY: %s\n", phy_result[hci_event_le_meta_get_phy_update_complete_tx_phy(packet)]);
+ log_info("Rx PHY: %s\n", phy_result[hci_event_le_meta_get_phy_update_complete_rx_phy(packet)]);
+ break;
+
+ }
+ break;
+
+ case HCI_EVENT_DISCONNECTION_COMPLETE:
+ log_info("HCI_EVENT_DISCONNECTION_COMPLETE: %0x\n", packet[5]);
+ con_handle = 0;
+ ble_op_att_send_init(con_handle, 0, 0, 0);
+ set_ble_work_state(BLE_ST_DISCONN);
+ client_event_report(CLI_EVENT_DISCONNECT, packet, size);
+
+ //auto to do
+#if !WIRELESS_PAIR_BONDING
+ if (conn_pair_info.pair_flag) {
+ client_create_connect_api(0, 0, 1);
+ } else
+#endif
+ {
+ bt_ble_scan_enable(0, 1);
+ }
+ break;
+
+ case ATT_EVENT_MTU_EXCHANGE_COMPLETE:
+ mtu = att_event_mtu_exchange_complete_get_MTU(packet) - 3;
+ log_info("ATT MTU = %u\n", mtu);
+ ble_op_att_set_send_mtu(mtu);
+ break;
+
+ case HCI_EVENT_VENDOR_REMOTE_TEST:
+ log_info("--- HCI_EVENT_VENDOR_REMOTE_TEST\n");
+ break;
+
+ case L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE:
+ tmp = little_endian_read_16(packet, 4);
+ log_info("-update_rsp: %02x\n", tmp);
+ break;
+
+ case GAP_EVENT_ADVERTISING_REPORT:
+ /* putchar('@'); */
+ client_report_adv_data((void *)&packet[2], packet[1]);
+ break;
+
+ case HCI_EVENT_ENCRYPTION_CHANGE:
+ log_info("HCI_EVENT_ENCRYPTION_CHANGE= %d\n", packet[2]);
+ if (client_config->security_en) {
+ client_search_profile_start();
+ }
+ break;
+ }
+ break;
+ }
+}
+
+
+static int get_buffer_vaild_len(void *priv)
+{
+ u32 vaild_len = 0;
+ ble_op_att_get_remain(&vaild_len);
+ return vaild_len;
+}
+
+static int client_operation_send(u16 handle, u8 *data, u16 len, u8 att_op_type)
+{
+ int ret = APP_BLE_NO_ERROR;
+ if (!con_handle) {
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+ if (!handle) {
+ log_info("handle is null\n");
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+
+ if (get_buffer_vaild_len(0) < len) {
+ /* log_info("opt_buff_full!!!\n"); */
+ return APP_BLE_BUFF_FULL;
+ }
+
+ ret = ble_op_att_send_data(handle, data, len, att_op_type);
+ if (ret == BLE_BUFFER_FULL) {
+ ret = APP_BLE_BUFF_FULL;
+ } else {
+#if SHOW_TX_DATA_RATE
+ test_tx_data_count += len;
+#endif /* SHOW_TX_DATA_RATE */
+ }
+
+ return ret;
+}
+
+
+//-----------------------------------------------
+static int client_write_send(void *priv, u8 *data, u16 len)
+{
+ return client_operation_send(target_handle.write_handle, data, len, ATT_OP_WRITE);
+}
+
+static int client_write_without_respond_send(void *priv, u8 *data, u16 len)
+{
+ return client_operation_send(target_handle.write_no_respond, data, len, ATT_OP_WRITE_WITHOUT_RESPOND);
+}
+
+static int client_read_value_send(void *priv)
+{
+ u16 tmp_flag = 0x55A1;
+ return client_operation_send(target_handle.read_handle, (u8 *)&tmp_flag, 2, ATT_OP_READ);
+}
+
+static int client_read_long_value_send(void *priv)
+{
+ u16 tmp_flag = 0x55A2;
+ return client_operation_send(target_handle.read_handle, (u8 *)&tmp_flag, 2, ATT_OP_READ_LONG);
+}
+
+
+//扫描数设置
+static void scanning_setup_init(void)
+{
+ ble_op_set_scan_param(SET_SCAN_TYPE, SET_SCAN_INTERVAL, SET_SCAN_WINDOW);
+}
+
+static int bt_ble_scan_enable(void *priv, u32 en)
+{
+ ble_state_e next_state, cur_state;
+
+ if (!scan_ctrl_en && en) {
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+ if (en) {
+ next_state = BLE_ST_SCAN;
+ } else {
+ next_state = BLE_ST_IDLE;
+ }
+
+ cur_state = get_ble_work_state();
+ switch (cur_state) {
+ case BLE_ST_SCAN:
+ case BLE_ST_IDLE:
+ case BLE_ST_INIT_OK:
+ case BLE_ST_NULL:
+ case BLE_ST_DISCONN:
+ case BLE_ST_CONNECT_FAIL:
+ case BLE_ST_SEND_CREATE_CONN_CANNEL:
+ break;
+ default:
+ return APP_BLE_OPERATION_ERROR;
+ break;
+ }
+
+ if (cur_state == next_state) {
+ return APP_BLE_NO_ERROR;
+ }
+
+
+ log_info("scan_en:%d\n", en);
+ set_ble_work_state(next_state);
+
+ if (en) {
+ scanning_setup_init();
+ }
+ ble_op_scan_enable2(en, 0);
+
+ return APP_BLE_NO_ERROR;
+}
+
+static int client_regiest_wakeup_send(void *priv, void *cbk)
+{
+ /* att_regist_wakeup_send(cbk); */
+ return APP_BLE_NO_ERROR;
+}
+
+static int client_regiest_recieve_cbk(void *priv, void *cbk)
+{
+ channel_priv = (u32)priv;
+ app_recieve_callback = cbk;
+ return APP_BLE_NO_ERROR;
+}
+
+static int client_regiest_state_cbk(void *priv, void *cbk)
+{
+ channel_priv = (u32)priv;
+ app_ble_state_callback = cbk;
+ return APP_BLE_NO_ERROR;
+}
+
+//该接口重新配置搜索的配置项
+static int client_init_config(void *priv, const client_conn_cfg_t *cfg)
+{
+ log_info("client_init_config\n");
+ client_config = cfg;//reset config
+ return APP_BLE_NO_ERROR;
+}
+
+//可配置进入强制搜索方式连接,更加信号强度过滤设备
+static int client_force_search(u8 onoff, s8 rssi)
+{
+ force_seach_rssi = rssi;
+ if (force_seach_onoff != onoff) {
+
+ force_seach_onoff = onoff;
+ //强制搜索前后,关创建监听
+ if (get_ble_work_state() == BLE_ST_CREATE_CONN) {
+ client_create_connection_cannel();
+ }
+ }
+ return 0;
+}
+
+static int client_create_connect_api(u8 *addr, u8 addr_type, u8 mode)
+{
+ u8 cur_state = get_ble_work_state();
+
+ switch (cur_state) {
+ case BLE_ST_SCAN:
+ case BLE_ST_IDLE:
+ case BLE_ST_INIT_OK:
+ case BLE_ST_NULL:
+ case BLE_ST_DISCONN:
+ case BLE_ST_CONNECT_FAIL:
+ case BLE_ST_SEND_CREATE_CONN_CANNEL:
+ break;
+ default:
+ return APP_BLE_OPERATION_ERROR;
+ break;
+ }
+
+ if (cur_state == BLE_ST_SCAN) {
+ log_info("stop scan\n");
+ bt_ble_scan_enable(0, 0);
+ }
+
+ //pair mode
+ if (mode == 1) {
+ if (conn_pair_info.pair_flag) {
+ if (conn_pair_info.pair_flag) {
+ //有配对,跳过搜索,直接创建init_creat
+ log_info("pair to creat!\n");
+ log_info_hexdump(conn_pair_info.peer_address_info, 7);
+ bt_ble_create_connection(&conn_pair_info.peer_address_info[1], conn_pair_info.peer_address_info[0]);
+ return 0;
+ }
+
+ } else {
+ log_info("no pair to creat!\n");
+ return APP_BLE_OPERATION_ERROR;
+ }
+ } else {
+ log_info("addr to creat!\n");
+ log_info_hexdump(addr, 7);
+ bt_ble_create_connection(addr, addr_type);
+ }
+ return 0;
+}
+
+static int client_create_cannel_api(void)
+{
+ if (get_ble_work_state() == BLE_ST_CREATE_CONN) {
+ client_create_connection_cannel();
+ return 0;
+ }
+ return 1;
+}
+
+static const struct ble_client_operation_t client_operation = {
+ .scan_enable = bt_ble_scan_enable,
+ .disconnect = ble_disconnect,
+ .get_buffer_vaild = get_buffer_vaild_len,
+ .write_data = (void *)client_write_without_respond_send,
+ .read_do = (void *)client_read_value_send,
+ .regist_wakeup_send = client_regiest_wakeup_send,
+ .regist_recieve_cbk = client_regiest_recieve_cbk,
+ .regist_state_cbk = client_regiest_state_cbk,
+ .init_config = client_init_config,
+ .opt_comm_send = client_operation_send,
+ .set_force_search = client_force_search,
+ .create_connect = client_create_connect_api,
+ .create_connect_cannel = client_create_cannel_api,
+ .get_work_state = get_ble_work_state,
+};
+
+struct ble_client_operation_t *ble_get_client_operation_table(void)
+{
+ return &client_operation;
+}
+
+#define PASSKEY_ENTER_ENABLE 0 //输入passkey使能,可修改passkey
+//重设passkey回调函数,在这里可以重新设置passkey
+//passkey为6个数字组成,十万位、万位。。。。个位 各表示一个数字 高位不够为0
+static void reset_passkey_cb(u32 *key)
+{
+#if 1
+ u32 newkey = rand32();//获取随机数
+
+ newkey &= 0xfffff;
+ if (newkey > 999999) {
+ newkey = newkey - 999999; //不能大于999999
+ }
+ *key = newkey; //小于或等于六位数
+ log_info("set new_key= %06u\n", *key);
+#else
+ *key = 123456; //for debug
+#endif
+}
+
+#if 0
+//协议栈内部调用
+extern void sm_set_master_request_pair(int enable);
+static void ble_sm_setup_init(io_capability_t io_type, u8 auth_req, uint8_t min_key_size, u8 security_en)
+{
+ //setup SM: Display only
+ sm_init();
+ sm_set_io_capabilities(io_type);
+ sm_set_authentication_requirements(auth_req);
+ sm_set_encryption_key_size_range(min_key_size, 16);
+ sm_set_master_request_pair(security_en);
+ sm_event_callback_set(&cbk_sm_packet_handler);
+
+ if (io_type == IO_CAPABILITY_DISPLAY_ONLY) {
+ reset_PK_cb_register(reset_passkey_cb);
+ }
+}
+#endif
+
+
+//协议栈内部调用
+void ble_profile_init(void)
+{
+ log_info("ble profile init\n");
+ le_device_db_init();
+ ble_stack_gatt_role(1);
+
+//#if PASSKEY_ENTER_ENABLE
+// ble_sm_setup_init(IO_CAPABILITY_DISPLAY_ONLY, SM_AUTHREQ_MITM_PROTECTION | SM_AUTHREQ_BONDING, 7, client_config->security_en);
+//#else
+// ble_sm_setup_init(IO_CAPABILITY_NO_INPUT_NO_OUTPUT, SM_AUTHREQ_MITM_PROTECTION | SM_AUTHREQ_BONDING, 7, client_config->security_en);
+//#endif
+
+ /* setup ATT client */
+ gatt_client_init();
+ gatt_client_register_packet_handler(cbk_packet_handler);
+
+ // register for HCI events
+ hci_event_callback_set(&cbk_packet_handler);
+ le_l2cap_register_packet_handler(&cbk_packet_handler);
+
+ ble_vendor_set_default_att_mtu(ATT_LOCAL_MTU_SIZE);
+}
+
+
+static void device_bonding_init(void)
+{
+ int i;
+ int cfg_bonding = 0;
+ client_match_cfg_t *cfg;
+ for (i = 0; i < CLIENT_MATCH_CONN_MAX; i++) {
+ cfg = client_config->match_dev_cfg[i];
+ if (cfg == NULL) {
+ continue;
+ }
+ if (cfg->bonding_flag) {
+ cfg_bonding = 1;
+ }
+ }
+ if (!cfg_bonding) {
+ clear_bonding_info();
+ }
+}
+
+static u8 client_idle_query(void)
+{
+ return 0;
+}
+
+REGISTER_LP_TARGET(client_user_target) = {
+ .name = "client_user_demo",
+ .is_idle = client_idle_query,
+};
+
+
+
+
+void bt_ble_init(void)
+{
+ log_info("***** ble_init******\n");
+#if WIRELESS_TOOL_BLE_NAME_EN
+ u8 *config_name;
+ u8 config_name_len;
+#endif
+
+#if (WIRELESS_24G_ENABLE)
+ rf_set_24g_hackable_coded(WIRELESS_24G_CODE_ID);
+#endif
+#if WIRELESS_TOOL_BLE_NAME_EN
+#if 1 //使用配置工具的蓝牙名
+ extern const char *bt_get_local_name();
+ config_name = (u8 *)(bt_get_local_name());
+ config_name_len = strlen(config_name) + 1;
+ put_buf(config_name, config_name_len);
+ printf("len = %d", config_name_len);
+#else
+ config_name = TEST_BOX_BLE_NAME;
+ config_name_len = sizeof(TEST_BOX_BLE_NAME);
+#endif
+ match_name = (u8 *)zalloc(config_name_len);
+ memcpy(match_name, config_name, config_name_len);
+ printf("match_name");
+ put_buf(match_name, config_name_len);
+ printf("%s", match_name);
+#endif
+ if (0 == memcmp(match_name, SPECIFIC_STRING, strlen(SPECIFIC_STRING))) {
+ match_name = &match_name[strlen(SPECIFIC_STRING)];
+ printf("specific scan%s", match_name);
+ flag_specific_sacn = 1;
+
+ }
+
+ set_ble_work_state(BLE_ST_INIT_OK);
+ conn_pair_vm_do(&conn_pair_info, 0);
+
+#if !WIRELESS_PAIR_BONDING
+ device_bonding_init();
+#endif
+ ble_module_enable(1);
+ extern void wifi_detect_set_master_first(u8 first);
+#if TCFG_WIFI_DETECT_ENABLE
+#if TCFG_WIFI_DETCET_PRIOR
+ wifi_detect_set_master_first(0);
+#else
+ wifi_detect_set_master_first(1);
+#endif
+#endif
+
+#if (SHOW_RX_DATA_RATE | SHOW_TX_DATA_RATE)
+ client_timer_start();
+#endif /* SHOW_RX_DATA_RATE | SHOW_TX_DATA_RATE */
+}
+
+void bt_ble_exit(void)
+{
+ log_info("***** ble_exit******\n");
+}
+
+void ble_app_disconnect(void)
+{
+ ble_disconnect(NULL);
+}
+//统一接口,关闭模块
+void bt_ble_adv_enable(u8 enable)
+{
+ ble_module_enable(enable);
+}
+
+//模块开关
+void ble_module_enable(u8 en)
+{
+ log_info("mode_en:%d\n", en);
+ if (en) {
+ scan_ctrl_en = 1;
+ bt_ble_scan_enable(0, 1);
+ } else {
+ if (con_handle) {
+ scan_ctrl_en = 0;
+ ble_disconnect(NULL);
+ } else {
+ bt_ble_scan_enable(0, 0);
+ scan_ctrl_en = 0;
+ }
+ }
+
+}
+
+void client_send_conn_param_update(void)
+{
+ struct conn_update_param_t *param = (void *)&connection_param_table[send_param_index];//for test
+ log_info("client update param:-%d-%d-%d-%d-\n", param->interval_min, param->interval_max, param->latency, param->timeout);
+ if (con_handle) {
+ ble_op_conn_param_update(con_handle, param);
+ }
+}
+
+
+
+//----------------------------------------------------------------------------------
+
+
+
+#endif
+
+
+
diff --git a/apps/common/third_party_profile/jieli/wireless_mic/le_wireless_mic_server.c b/apps/common/third_party_profile/jieli/wireless_mic/le_wireless_mic_server.c
new file mode 100644
index 0000000..80f3c0a
--- /dev/null
+++ b/apps/common/third_party_profile/jieli/wireless_mic/le_wireless_mic_server.c
@@ -0,0 +1,1073 @@
+#include "system/app_core.h"
+#include "system/includes.h"
+
+#include "app_config.h"
+#include "app_action.h"
+
+#include "btstack/btstack_task.h"
+#include "btstack/bluetooth.h"
+#include "user_cfg.h"
+#include "vm.h"
+#include "btcontroller_modules.h"
+#include "bt_common.h"
+#include "3th_profile_api.h"
+
+#include "le_trans_data.h"
+#include "le_common.h"
+
+#include "rcsp_bluetooth.h"
+#include "JL_rcsp_api.h"
+#include "custom_cfg.h"
+
+
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_WIRELESS_MIC_SERVER)
+
+#if LE_DEBUG_PRINT_EN
+extern void printf_buf(u8 *buf, u32 len);
+/* #define log_info printf */
+#define log_info(x, ...) printf("[LE_TRANS]" x " ", ## __VA_ARGS__)
+#define log_info_hexdump printf_buf
+#else
+#define log_info(...)
+#define log_info_hexdump(...)
+#endif
+
+
+
+//------
+//ATT发送的包长, note: 20 <=need >= MTU
+#define ATT_LOCAL_MTU_SIZE (517) //
+//ATT缓存的buffer大小, note: need >= 20,可修改
+#if(APP_MAIN == APP_WIRELESS_MIC_2T1)
+#define ATT_SEND_CBUF_SIZE (90)
+#else
+#define ATT_SEND_CBUF_SIZE (200)
+#endif
+
+//共配置的RAM
+#define ATT_RAM_BUFSIZE (ATT_CTRL_BLOCK_SIZE + ATT_LOCAL_MTU_SIZE + ATT_SEND_CBUF_SIZE) //note:
+static u8 att_ram_buffer[ATT_RAM_BUFSIZE] __attribute__((aligned(4)));
+//---------------
+
+
+//---------------
+// 广播周期 (unit:0.625ms)
+//参数一: 96 参数二: 64 参数三: 48
+#define ADV_INTERVAL_MIN (64)
+
+#define HOLD_LATENCY_CNT_MIN (3) //(0~0xffff)
+#define HOLD_LATENCY_CNT_MAX (15) //(0~0xffff)
+#define HOLD_LATENCY_CNT_ALL (0xffff)
+
+
+static volatile hci_con_handle_t con_handle;
+#if WIRELESS_PAIR_BONDING
+
+#define PAIR_DIREDT_ADV_EN 1
+#define BLE_VM_HEAD_TAG (0xB95C)
+#define BLE_VM_TAIL_TAG (0x5CB9)
+static u16 adv_interval_val; //广播周期 (unit:0.625ms)
+#define REPEAT_DIRECT_ADV_COUNT (2)// *1.28s
+struct pair_info_t {
+ u16 head_tag; //头标识
+ u8 pair_flag: 2; //配对信息是否有效
+ u8 direct_adv_flag: 1; //是否需要定向广播
+ u8 direct_adv_cnt: 5; //定向广播次数
+ u8 peer_address_info[7]; //绑定的对方地址信息
+ u16 tail_tag;//尾标识
+};
+static struct pair_info_t conn_pair_info;
+static u8 cur_peer_address_info[7];
+
+#endif
+
+//加密设置
+/* static const uint8_t sm_min_key_size = 7; */
+
+//连接参数更新请求设置
+//是否使能参数请求更新,0--disable, 1--enable
+static const uint8_t connection_update_enable = 1; ///0--disable, 1--enable
+//当前请求的参数表index
+static uint8_t connection_update_cnt = 0; //
+
+//参数表
+static const struct conn_update_param_t connection_param_table[] = {
+ {WIRELESS_BLE_CONNECT_INTERVAL, WIRELESS_BLE_CONNECT_INTERVAL, 0, 100},//11
+};
+
+//共可用的参数组数
+#define CONN_PARAM_TABLE_CNT (sizeof(connection_param_table)/sizeof(struct conn_update_param_t))
+
+#if (ATT_RAM_BUFSIZE < 64)
+#error "adv_data & rsp_data buffer error!!!!!!!!!!!!"
+#endif
+
+//用户可配对的,这是样机跟客户开发的app配对的秘钥
+/* const u8 link_key_data[16] = {0x06, 0x77, 0x5f, 0x87, 0x91, 0x8d, 0xd4, 0x23, 0x00, 0x5d, 0xf1, 0xd8, 0xcf, 0x0c, 0x14, 0x2b}; */
+#define EIR_TAG_STRING 0xd6, 0x05, 0x08, 0x00, 'J', 'L', 'A', 'I', 'S', 'D','K'
+static const char user_tag_string[] = {EIR_TAG_STRING};
+
+static u8 adv_data_len;
+static u8 adv_data[ADV_RSP_PACKET_MAX];//max is 31
+static u8 scan_rsp_data_len;
+static u8 scan_rsp_data[ADV_RSP_PACKET_MAX];//max is 31
+
+/* #define adv_data &att_ram_buffer[0] */
+/* #define scan_rsp_data &att_ram_buffer[32] */
+#if WIRELESS_TOOL_BLE_NAME_EN
+#define MATCH_NAME "W_MIC_01"
+static u8 *gap_device_name;
+static u8 gap_device_name_len; //名字长度,不包含结束符
+#else
+static char gap_device_name[] = "W_MIC_01";
+static u8 gap_device_name_len = sizeof(gap_device_name) - 1; //名字长度,不包含结束符
+#endif
+static u8 ble_work_state = 0; //ble 状态变化
+static u8 adv_ctrl_en; //广播控制
+
+static u8 test_read_write_buf[4];
+
+static void (*app_recieve_callback)(void *priv, void *buf, u16 len) = NULL;
+static void (*app_ble_state_callback)(void *priv, ble_state_e state) = NULL;
+static void (*ble_resume_send_wakeup)(void) = NULL;
+static u32 channel_priv;
+
+static int app_send_user_data_check(u16 len);
+static int app_send_user_data_do(void *priv, u8 *data, u16 len);
+static int app_send_user_data(u16 handle, u8 *data, u16 len, u8 handle_type);
+
+// Complete Local Name 默认的蓝牙名字
+
+//------------------------------------------------------
+//广播参数设置
+static void advertisements_setup_init();
+static int set_adv_enable(void *priv, u32 en);
+static int get_buffer_vaild_len(void *priv);
+extern const char *bt_get_local_name();
+extern void clr_wdt(void);
+extern void sys_auto_shut_down_disable(void);
+extern void sys_auto_shut_down_enable(void);
+extern u8 get_total_connect_dev(void);
+
+static ble_state_e get_ble_work_state(void)
+{
+ return ble_work_state;
+}
+
+#if WIRELESS_PAIR_BONDING
+static void conn_pair_vm_do(struct pair_info_t *info, u8 rw_flag)
+{
+#if PAIR_DIREDT_ADV_EN
+ int ret;
+ int vm_len = sizeof(struct pair_info_t);
+
+ log_info("-conn_pair_info vm_do:%d\n", rw_flag);
+ if (rw_flag == 0) {
+ ret = syscfg_read(CFG_BLE_MODE_INFO, (u8 *)info, vm_len);
+ if (!ret) {
+ log_info("-null--\n");
+ }
+
+ if ((BLE_VM_HEAD_TAG == info->head_tag) && (BLE_VM_TAIL_TAG == info->tail_tag)) {
+ log_info("-exist--\n");
+ log_info_hexdump((u8 *)info, vm_len);
+ info->direct_adv_flag = 1;
+ } else {
+ memset(info, 0, vm_len);
+ info->head_tag = BLE_VM_HEAD_TAG;
+ info->tail_tag = BLE_VM_TAIL_TAG;
+ }
+ } else {
+ info->direct_adv_flag = 1;
+ syscfg_write(CFG_BLE_MODE_INFO, (u8 *)info, vm_len);
+ }
+#endif
+}
+
+//检测是否需要定向广播
+static void ble_check_need_pair_adv(void)
+{
+#if PAIR_DIREDT_ADV_EN
+ log_info("%s\n", __FUNCTION__);
+ if (conn_pair_info.pair_flag && conn_pair_info.direct_adv_flag) {
+ conn_pair_info.direct_adv_cnt = REPEAT_DIRECT_ADV_COUNT;
+ }
+#endif
+}
+void clear_bonding_info(void)
+{
+ log_info("server_clear_bonding_info\n");
+ conn_pair_vm_do(&conn_pair_info, 0);
+ printf("pair_flag == %d", conn_pair_info.pair_flag);
+ put_buf(cur_peer_address_info, 7);
+ if (conn_pair_info.pair_flag) {
+ printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
+ //del pair bond
+ memset(&conn_pair_info, 0, sizeof(struct pair_info_t));
+ conn_pair_vm_do(&conn_pair_info, 1);
+ //printf("ble_work_st == %x", get_ble_work_state());
+ if (BLE_ST_ADV == get_ble_work_state()) {
+ //开个一下切换广播类型,新配对连接
+ bt_ble_adv_enable(0);
+ bt_ble_adv_enable(1);
+ } else if (con_handle) {
+ ble_disconnect();
+ }
+ }
+}
+#endif
+
+static void send_request_connect_parameter(u8 table_index)
+{
+ struct conn_update_param_t *param = (void *)&connection_param_table[table_index];//static ram
+
+ log_info("update_request:-%d-%d-%d-%d-\n", param->interval_min, param->interval_max, param->latency, param->timeout);
+ if (con_handle) {
+ ble_op_conn_param_request(con_handle, param);
+ }
+}
+
+static void check_connetion_updata_deal(void)
+{
+ if (connection_update_enable) {
+ if (connection_update_cnt < CONN_PARAM_TABLE_CNT) {
+ send_request_connect_parameter(connection_update_cnt);
+ }
+ }
+}
+
+static void connection_update_complete_success(u8 *packet)
+{
+ int con_handle, conn_interval, conn_latency, conn_timeout;
+
+ con_handle = hci_subevent_le_connection_update_complete_get_connection_handle(packet);
+ conn_interval = hci_subevent_le_connection_update_complete_get_conn_interval(packet);
+ conn_latency = hci_subevent_le_connection_update_complete_get_conn_latency(packet);
+ conn_timeout = hci_subevent_le_connection_update_complete_get_supervision_timeout(packet);
+
+ log_info("conn_interval = %d\n", conn_interval);
+ log_info("conn_latency = %d\n", conn_latency);
+ log_info("conn_timeout = %d\n", conn_timeout);
+}
+
+
+static void set_ble_work_state(ble_state_e state)
+{
+ if (state != ble_work_state) {
+ log_info("ble_work_st:%x->%x\n", ble_work_state, state);
+ ble_work_state = state;
+ if (app_ble_state_callback) {
+ app_ble_state_callback((void *)channel_priv, state);
+ }
+ }
+}
+
+
+
+static void cbk_sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
+{
+ sm_just_event_t *event = (void *)packet;
+ u32 tmp32;
+ switch (packet_type) {
+ case HCI_EVENT_PACKET:
+ switch (hci_event_packet_get_type(packet)) {
+ case SM_EVENT_JUST_WORKS_REQUEST:
+ sm_just_works_confirm(sm_event_just_works_request_get_handle(packet));
+ log_info("Just Works Confirmed.\n");
+ break;
+ case SM_EVENT_PASSKEY_DISPLAY_NUMBER:
+ log_info_hexdump(packet, size);
+ memcpy(&tmp32, event->data, 4);
+ log_info("Passkey display: %06u.\n", tmp32);
+ break;
+ }
+ break;
+ }
+}
+
+static void can_send_now_wakeup(void)
+{
+ /* putchar('E'); */
+ if (ble_resume_send_wakeup) {
+ ble_resume_send_wakeup();
+ }
+}
+
+static void ble_auto_shut_down_enable(u8 enable)
+{
+#if TCFG_AUTO_SHUT_DOWN_TIME
+ if (enable) {
+ if (get_total_connect_dev() == 0) { //已经没有设备连接
+#if !TCFG_WIRELESS_MIC_ENABLE
+ sys_auto_shut_down_enable();
+#endif
+ }
+ } else {
+#if !TCFG_WIRELESS_MIC_ENABLE
+ sys_auto_shut_down_disable();
+#endif
+ }
+#endif
+}
+
+const char *const phy_result[] = {
+ "None",
+ "1M",
+ "2M",
+ "Coded",
+};
+
+static void set_connection_data_length(u16 tx_octets, u16 tx_time)
+{
+ if (con_handle) {
+ ble_op_set_data_length(con_handle, tx_octets, tx_time);
+ }
+}
+
+static void set_connection_data_phy(u8 tx_phy, u8 rx_phy)
+{
+ if (0 == con_handle) {
+ return;
+ }
+
+ u8 all_phys = 0;
+ u16 phy_options = CONN_SET_PHY_OPTIONS_S8;
+
+ ble_op_set_ext_phy(con_handle, all_phys, tx_phy, rx_phy, phy_options);
+}
+
+static void server_profile_start(u16 con_handle)
+{
+ ble_op_att_send_init(con_handle, att_ram_buffer, ATT_RAM_BUFSIZE, ATT_LOCAL_MTU_SIZE);
+ set_ble_work_state(BLE_ST_CONNECT);
+ ble_auto_shut_down_enable(0);
+
+ /* set_connection_data_phy(CONN_SET_CODED_PHY, CONN_SET_CODED_PHY); */
+}
+
+_WEAK_
+u8 ble_update_get_ready_jump_flag(void)
+{
+ return 0;
+}
+/*
+ * @section Packet Handler
+ *
+ * @text The packet handler is used to:
+ * - stop the counter after a disconnect
+ * - send a notification when the requested ATT_EVENT_CAN_SEND_NOW is received
+ */
+
+/* LISTING_START(packetHandler): Packet Handler */
+static void cbk_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
+{
+ int mtu;
+ u32 tmp;
+ u8 status;
+ const char *attribute_name;
+
+ switch (packet_type) {
+ case HCI_EVENT_PACKET:
+ switch (hci_event_packet_get_type(packet)) {
+
+ /* case DAEMON_EVENT_HCI_PACKET_SENT: */
+ /* break; */
+ case ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE:
+ log_info("ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE\n");
+ case ATT_EVENT_CAN_SEND_NOW:
+ can_send_now_wakeup();
+ break;
+
+ case HCI_EVENT_LE_META:
+ switch (hci_event_le_meta_get_subevent_code(packet)) {
+ case HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE:
+ status = hci_subevent_le_enhanced_connection_complete_get_status(packet);
+ if (status) {
+ log_info("LE_SLAVE CONNECTION FAIL!!! %0x\n", status);
+ set_ble_work_state(BLE_ST_DISCONN);
+ break;
+ }
+ con_handle = hci_subevent_le_enhanced_connection_complete_get_connection_handle(packet);
+ log_info("HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE : %0x\n", con_handle);
+ log_info("conn_interval = %d\n", hci_subevent_le_enhanced_connection_complete_get_conn_interval(packet));
+ log_info("conn_latency = %d\n", hci_subevent_le_enhanced_connection_complete_get_conn_latency(packet));
+ log_info("conn_timeout = %d\n", hci_subevent_le_enhanced_connection_complete_get_supervision_timeout(packet));
+ server_profile_start(con_handle);
+ break;
+
+ case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
+ con_handle = hci_subevent_le_connection_complete_get_connection_handle(packet);
+ log_info("HCI_SUBEVENT_LE_CONNECTION_COMPLETE: %0x\n", con_handle);
+ connection_update_complete_success(packet + 8);
+ server_profile_start(con_handle);
+#if WIRELESS_PAIR_BONDING
+ memcpy(cur_peer_address_info, packet + 7, 7);
+ put_buf(cur_peer_address_info, 7);
+ conn_pair_info.pair_flag = 1;
+ put_buf(cur_peer_address_info, 7);
+ memcpy(conn_pair_info.peer_address_info, cur_peer_address_info, 7);
+ conn_pair_info.head_tag = BLE_VM_HEAD_TAG;
+ conn_pair_info.tail_tag = BLE_VM_TAIL_TAG;
+ conn_pair_vm_do(&conn_pair_info, 1);
+#endif
+ log_info("ble remote rssi= %d\n", ble_vendor_get_peer_rssi(con_handle));
+ break;
+
+ case HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE:
+ log_info("APP HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE\n");
+ connection_update_complete_success(packet);
+ set_ble_work_state(BLE_ST_CONNECTION_UPDATE_OK);
+ break;
+
+ case HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE:
+ log_info("APP HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE\n");
+ set_connection_data_phy(CONN_SET_2M_PHY, CONN_SET_2M_PHY);
+ break;
+
+ case HCI_SUBEVENT_LE_PHY_UPDATE_COMPLETE:
+ log_info("APP HCI_SUBEVENT_LE_PHY_UPDATE %s\n", hci_event_le_meta_get_phy_update_complete_status(packet) ? "Fail" : "Succ");
+ log_info("Tx PHY: %s\n", phy_result[hci_event_le_meta_get_phy_update_complete_tx_phy(packet)]);
+ log_info("Rx PHY: %s\n", phy_result[hci_event_le_meta_get_phy_update_complete_rx_phy(packet)]);
+ check_connetion_updata_deal();
+ break;
+ }
+ break;
+
+ case HCI_EVENT_DISCONNECTION_COMPLETE:
+ log_info("HCI_EVENT_DISCONNECTION_COMPLETE: %0x\n", packet[5]);
+ con_handle = 0;
+ ble_op_att_send_init(con_handle, 0, 0, 0);
+ set_ble_work_state(BLE_ST_DISCONN);
+
+ if (!ble_update_get_ready_jump_flag()) {
+#if WIRELESS_PAIR_BONDING
+ ble_check_need_pair_adv();
+#endif
+ bt_ble_adv_enable(1);
+ }
+ connection_update_cnt = 0;
+ ble_auto_shut_down_enable(1);
+ break;
+
+ case ATT_EVENT_MTU_EXCHANGE_COMPLETE:
+ mtu = att_event_mtu_exchange_complete_get_MTU(packet) - 3;
+ log_info("ATT MTU = %u\n", mtu);
+ ble_op_att_set_send_mtu(mtu);
+ set_connection_data_length(251, 2120);
+ break;
+
+ case HCI_EVENT_VENDOR_REMOTE_TEST:
+ log_info("--- HCI_EVENT_VENDOR_REMOTE_TEST\n");
+ break;
+
+ case L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE:
+ tmp = little_endian_read_16(packet, 4);
+ log_info("-update_rsp: %02x\n", tmp);
+ if (tmp) {
+ connection_update_cnt++;
+ log_info("remoter reject!!!\n");
+ check_connetion_updata_deal();
+ } else {
+ connection_update_cnt = CONN_PARAM_TABLE_CNT;
+ }
+ break;
+
+ case HCI_EVENT_ENCRYPTION_CHANGE:
+ log_info("HCI_EVENT_ENCRYPTION_CHANGE= %d\n", packet[2]);
+ break;
+ }
+ break;
+ }
+}
+
+
+/* LISTING_END */
+
+/*
+ * @section ATT Read
+ *
+ * @text The ATT Server handles all reads to constant data. For dynamic data like the custom characteristic, the registered
+ * att_read_callback is called. To handle long characteristics and long reads, the att_read_callback is first called
+ * with buffer == NULL, to request the total value length. Then it will be called again requesting a chunk of the value.
+ * See Listing attRead.
+ */
+
+/* LISTING_START(attRead): ATT Read */
+
+// ATT Client Read Callback for Dynamic Data
+// - if buffer == NULL, don't copy data, just return size of value
+// - if buffer != NULL, copy data and return number bytes copied
+// @param offset defines start of attribute value
+static uint16_t att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset, uint8_t *buffer, uint16_t buffer_size)
+{
+
+ uint16_t att_value_len = 0;
+ uint16_t handle = att_handle;
+
+ log_info("read_callback, handle= 0x%04x,buffer= %08x\n", handle, (u32)buffer);
+
+ switch (handle) {
+ case ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE:
+ att_value_len = gap_device_name_len;
+
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+
+ if (buffer) {
+ memcpy(buffer, &gap_device_name[offset], buffer_size);
+ att_value_len = buffer_size;
+ log_info("\n------read gap_name: %s \n", gap_device_name);
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_ae10_01_VALUE_HANDLE:
+ att_value_len = sizeof(test_read_write_buf);
+ if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
+ break;
+ }
+
+ if (buffer) {
+ memcpy(buffer, &test_read_write_buf[offset], buffer_size);
+ att_value_len = buffer_size;
+ }
+ break;
+
+ case ATT_CHARACTERISTIC_ae04_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_ae02_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_ae05_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_ae3c_01_CLIENT_CONFIGURATION_HANDLE:
+ if (buffer) {
+ buffer[0] = att_get_ccc_config(handle);
+ buffer[1] = 0;
+ }
+ att_value_len = 2;
+ break;
+
+ default:
+ break;
+ }
+
+ log_info("att_value_len= %d\n", att_value_len);
+ return att_value_len;
+
+}
+
+
+/* LISTING_END */
+/*
+ * @section ATT Write
+ *
+ * @text The only valid ATT write in this example is to the Client Characteristic Configuration, which configures notification
+ * and indication. If the ATT handle matches the client configuration handle, the new configuration value is stored and used
+ * in the heartbeat handler to decide if a new value should be sent. See Listing attWrite.
+ */
+
+/* LISTING_START(attWrite): ATT Write */
+static int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size)
+{
+ int result = 0;
+ u16 tmp16;
+
+ u16 handle = att_handle;
+
+ //log_info("write_callback, handle= 0x%04x,size = %d\n", handle, buffer_size);
+
+ switch (handle) {
+
+ case ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE:
+ break;
+
+ case ATT_CHARACTERISTIC_ae02_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_ae04_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_ae05_01_CLIENT_CONFIGURATION_HANDLE:
+ case ATT_CHARACTERISTIC_ae3c_01_CLIENT_CONFIGURATION_HANDLE:
+ set_ble_work_state(BLE_ST_NOTIFY_IDICATE);
+ /* check_connetion_updata_deal(); */
+ log_info("\n------write ccc:%04x,%02x\n", handle, buffer[0]);
+ att_set_ccc_config(handle, buffer[0]);
+
+ /* set_connection_data_length(251, 2120); */
+ break;
+
+ case ATT_CHARACTERISTIC_ae10_01_VALUE_HANDLE:
+ tmp16 = sizeof(test_read_write_buf);
+ if ((offset >= tmp16) || (offset + buffer_size) > tmp16) {
+ break;
+ }
+ memcpy(&test_read_write_buf[offset], buffer, buffer_size);
+ break;
+
+ case ATT_CHARACTERISTIC_ae01_01_VALUE_HANDLE:
+ /* printf("\n-ae01_rx(%d):", buffer_size); */
+ /* printf_buf(buffer, buffer_size); */
+
+ if (app_recieve_callback) {
+ app_recieve_callback(0, buffer, buffer_size);
+ }
+ //收发测试,自动发送收到的数据;for test
+ if (app_send_user_data_check(buffer_size)) {
+ /* app_send_user_data(ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE, buffer, buffer_size, ATT_OP_AUTO_READ_CCC); */
+ }
+
+ break;
+
+ case ATT_CHARACTERISTIC_ae03_01_VALUE_HANDLE:
+ //printf("\n-ae_rx(%d):", buffer_size);
+ //put_buf(buffer, buffer_size);
+
+ //收发测试,自动发送收到的数据;for test
+ if (app_send_user_data_check(buffer_size)) {
+ app_send_user_data(ATT_CHARACTERISTIC_ae05_01_VALUE_HANDLE, buffer, buffer_size, ATT_OP_AUTO_READ_CCC);
+ }
+ break;
+
+
+ case ATT_CHARACTERISTIC_ae3b_01_VALUE_HANDLE:
+ printf("\n-ae3b_rx(%d):", buffer_size);
+ put_buf(buffer, buffer_size);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int app_send_user_data(u16 handle, u8 *data, u16 len, u8 handle_type)
+{
+ u32 ret = APP_BLE_NO_ERROR;
+
+ if (!con_handle) {
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+ if (!att_get_ccc_config(handle + 1)) {
+ log_info("fail,no write ccc!!!,%04x\n", handle + 1);
+ return APP_BLE_NO_WRITE_CCC;
+ }
+
+ ret = ble_op_att_send_data(handle, data, len, handle_type);
+ if (ret == BLE_BUFFER_FULL) {
+ ret = APP_BLE_BUFF_FULL;
+ }
+
+ if (ret) {
+ log_info("app_send_fail:%d !!!!!!\n", ret);
+ }
+ return ret;
+}
+
+//------------------------------------------------------
+
+static int make_set_adv_data(void)
+{
+ u8 offset = 0;
+ u8 *buf = adv_data;
+
+
+#if DOUBLE_BT_SAME_MAC
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x0A, 1);
+#else
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x06, 1);
+#endif
+
+#if(APP_MAIN == APP_WIRELESS_MIC_2T1)
+ u8 name_len = gap_device_name_len;
+
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, (void *)gap_device_name, name_len);
+#else
+ offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_16BIT_SERVICE_UUIDS, 0xAF30, 2);
+
+#endif
+ if (offset > ADV_RSP_PACKET_MAX) {
+ puts("***adv_data overflow!!!!!!\n");
+ return -1;
+ }
+ log_info("adv_data(%d):", offset);
+ log_info_hexdump(buf, offset);
+ adv_data_len = offset;
+ ble_op_set_adv_data(offset, buf);
+ return 0;
+}
+
+static int make_set_rsp_data(void)
+{
+ u8 offset = 0;
+ u8 *buf = scan_rsp_data;
+
+ u8 name_len = gap_device_name_len;
+ u8 vaild_len = ADV_RSP_PACKET_MAX - (offset + 2);
+ if (name_len > vaild_len) {
+ name_len = vaild_len;
+ }
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, (void *)gap_device_name, name_len);
+
+ if (offset > ADV_RSP_PACKET_MAX) {
+ puts("***rsp_data overflow!!!!!!\n");
+ return -1;
+ }
+
+ log_info("rsp_data(%d):", offset);
+ log_info_hexdump(buf, offset);
+ scan_rsp_data_len = offset;
+ ble_op_set_rsp_data(offset, buf);
+ return 0;
+}
+
+//广播参数设置
+static void advertisements_setup_init()
+{
+ uint8_t adv_type = ADV_IND;
+ uint8_t adv_channel = ADV_CHANNEL_ALL;
+ int ret = 0;
+
+ ble_op_set_adv_param(ADV_INTERVAL_MIN, adv_type, adv_channel);
+
+ ret |= make_set_adv_data();
+ ret |= make_set_rsp_data();
+
+ if (ret) {
+ puts("advertisements_setup_init fail !!!!!!\n");
+ return;
+ }
+#if WIRELESS_PAIR_BONDING
+ printf("'pair_flag == %d,adv_flag == %d, adv_cnt == %d", conn_pair_info.pair_flag, conn_pair_info.direct_adv_flag, conn_pair_info.direct_adv_cnt);
+ if (conn_pair_info.pair_flag && conn_pair_info.direct_adv_flag && conn_pair_info.direct_adv_cnt) {
+ log_info(">>>direct_adv......\n");
+ put_buf(conn_pair_info.peer_address_info, 7);
+ adv_type = 4;
+ /* conn_pair_info.direct_adv_cnt--; */
+ ble_op_set_adv_param_ext(adv_interval_val, adv_type, adv_channel, conn_pair_info.peer_address_info);
+ } else {
+ ble_op_set_adv_param(adv_interval_val, adv_type, adv_channel);
+ }
+#endif
+
+}
+
+#define PASSKEY_ENTER_ENABLE 0 //输入passkey使能,可修改passkey
+//重设passkey回调函数,在这里可以重新设置passkey
+//passkey为6个数字组成,十万位、万位。。。。个位 各表示一个数字 高位不够为0
+static void reset_passkey_cb(u32 *key)
+{
+#if 1
+ u32 newkey = rand32();//获取随机数
+
+ newkey &= 0xfffff;
+ if (newkey > 999999) {
+ newkey = newkey - 999999; //不能大于999999
+ }
+ *key = newkey; //小于或等于六位数
+ printf("set new_key= %06u\n", *key);
+#else
+ *key = 123456; //for debug
+#endif
+}
+
+void ble_sm_setup_init(io_capability_t io_type, u8 auth_req, uint8_t min_key_size, u8 security_en)
+{
+ //setup SM: Display only
+ sm_init();
+ sm_set_io_capabilities(io_type);
+ sm_set_authentication_requirements(auth_req);
+ sm_set_encryption_key_size_range(min_key_size, 16);
+ sm_set_request_security(security_en);
+ sm_event_callback_set(&cbk_sm_packet_handler);
+
+ if (io_type == IO_CAPABILITY_DISPLAY_ONLY) {
+ reset_PK_cb_register(reset_passkey_cb);
+ }
+}
+
+
+#define MIC_TCFG_BLE_SECURITY_EN 0/*是否发请求加密命令*/
+void ble_profile_init(void)
+{
+ printf("ble profile init\n");
+ le_device_db_init();
+
+#if PASSKEY_ENTER_ENABLE
+ ble_sm_setup_init(IO_CAPABILITY_DISPLAY_ONLY, SM_AUTHREQ_MITM_PROTECTION | SM_AUTHREQ_BONDING, 7, MIC_TCFG_BLE_SECURITY_EN);
+#else
+ ble_sm_setup_init(IO_CAPABILITY_NO_INPUT_NO_OUTPUT, SM_AUTHREQ_MITM_PROTECTION | SM_AUTHREQ_BONDING, 7, MIC_TCFG_BLE_SECURITY_EN);
+#endif
+
+ /* setup ATT server */
+ att_server_init(profile_data, att_read_callback, att_write_callback);
+ att_server_register_packet_handler(cbk_packet_handler);
+ /* gatt_client_register_packet_handler(packet_cbk); */
+
+ // register for HCI events
+ hci_event_callback_set(&cbk_packet_handler);
+ /* ble_l2cap_register_packet_handler(packet_cbk); */
+ /* sm_event_packet_handler_register(packet_cbk); */
+ le_l2cap_register_packet_handler(&cbk_packet_handler);
+
+ ble_vendor_set_default_att_mtu(ATT_LOCAL_MTU_SIZE);
+}
+
+
+static int set_adv_enable(void *priv, u32 en)
+{
+ ble_state_e next_state, cur_state;
+
+ if (!adv_ctrl_en && en) {
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+ if (con_handle) {
+ return APP_BLE_OPERATION_ERROR;
+ }
+
+ if (en) {
+ next_state = BLE_ST_ADV;
+ } else {
+ next_state = BLE_ST_IDLE;
+ }
+
+ cur_state = get_ble_work_state();
+ switch (cur_state) {
+ case BLE_ST_ADV:
+ case BLE_ST_IDLE:
+ case BLE_ST_INIT_OK:
+ case BLE_ST_NULL:
+ case BLE_ST_DISCONN:
+ break;
+ default:
+ return APP_BLE_OPERATION_ERROR;
+ break;
+ }
+
+ if (cur_state == next_state) {
+ return APP_BLE_NO_ERROR;
+ }
+ log_info("adv_en:%d\n", en);
+ set_ble_work_state(next_state);
+
+ if (en) {
+ advertisements_setup_init();
+ }
+ ble_op_adv_enable(en);
+
+ return APP_BLE_NO_ERROR;
+}
+
+static int ble_disconnect(void *priv)
+{
+ if (con_handle) {
+ if (BLE_ST_SEND_DISCONN != get_ble_work_state()) {
+ log_info(">>>ble send disconnect\n");
+ set_ble_work_state(BLE_ST_SEND_DISCONN);
+ ble_op_disconnect(con_handle);
+ } else {
+ log_info(">>>ble wait disconnect...\n");
+ }
+ return APP_BLE_NO_ERROR;
+ } else {
+ return APP_BLE_OPERATION_ERROR;
+ }
+}
+
+
+static int get_buffer_vaild_len(void *priv)
+{
+ u32 vaild_len = 0;
+ ble_op_att_get_remain(&vaild_len);
+ return vaild_len;
+}
+
+static int app_send_user_data_do(void *priv, u8 *data, u16 len)
+{
+ return app_send_user_data(ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE, data, len, ATT_OP_AUTO_READ_CCC);
+}
+
+static int app_send_user_data_check(u16 len)
+{
+ u32 buf_space = get_buffer_vaild_len(0);
+ if (len <= buf_space) {
+ return 1;
+ }
+ return 0;
+}
+
+
+static int regiest_wakeup_send(void *priv, void *cbk)
+{
+ ble_resume_send_wakeup = cbk;
+ return APP_BLE_NO_ERROR;
+}
+
+static int regiest_recieve_cbk(void *priv, void *cbk)
+{
+ channel_priv = (u32)priv;
+ app_recieve_callback = cbk;
+ return APP_BLE_NO_ERROR;
+}
+
+static int regiest_state_cbk(void *priv, void *cbk)
+{
+ channel_priv = (u32)priv;
+ app_ble_state_callback = cbk;
+ return APP_BLE_NO_ERROR;
+}
+
+u8 *ble_get_scan_rsp_ptr(u16 *len)
+{
+ if (len) {
+ *len = scan_rsp_data_len;
+ }
+ return scan_rsp_data;
+}
+
+u8 *ble_get_adv_data_ptr(u16 *len)
+{
+ if (len) {
+ *len = adv_data_len;
+ }
+ return adv_data;
+}
+
+u8 *ble_get_gatt_profile_data(u16 *len)
+{
+ *len = sizeof(profile_data);
+ return (u8 *)profile_data;
+}
+
+
+void bt_ble_adv_enable(u8 enable)
+{
+ set_adv_enable(0, enable);
+}
+
+u16 bt_ble_is_connected(void)
+{
+ return con_handle;
+}
+
+void ble_module_enable(u8 en)
+{
+ log_info("mode_en:%d\n", en);
+ if (en) {
+ adv_ctrl_en = 1;
+ bt_ble_adv_enable(1);
+ } else {
+ if (con_handle) {
+ adv_ctrl_en = 0;
+ ble_disconnect(NULL);
+ } else {
+ bt_ble_adv_enable(0);
+ adv_ctrl_en = 0;
+ }
+ }
+}
+
+
+//流控使能 EN: 1-停止收数 or 0-继续收数
+int ble_trans_flow_enable(u8 en)
+{
+ int ret = -1;
+ log_info("ble_trans_flow_enable:%d,%d\n", en, ret);
+ return ret;
+}
+
+//for test
+static void timer_trans_flow_test(void)
+{
+ static u8 sw = 0;
+ if (con_handle) {
+ sw = !sw;
+ ble_trans_flow_enable(sw);
+ }
+}
+
+static const char ble_ext_name[] = "(BLE)";
+
+void bt_ble_init(void)
+{
+ log_info("***** ble_init******\n");
+ char *name_p;
+#if WIRELESS_TOOL_BLE_NAME_EN
+ u8 *config_name;
+ u8 config_name_len;
+#endif
+ u8 ext_name_len = sizeof(ble_ext_name) - 1;
+ log_info("ble name(%d): %s \n", gap_device_name_len, gap_device_name);
+#if WIRELESS_TOOL_BLE_NAME_EN
+#if 1 //使用配置工具的蓝牙名
+ config_name = (u8 *)(bt_get_local_name());
+ config_name_len = strlen(config_name);
+ put_buf(config_name, strlen(config_name));
+#else
+ config_name = MATCH_NAME;
+ config_name_len = strlen(MATCH_NAME);
+#endif
+ gap_device_name_len = config_name_len;
+ gap_device_name = (u8 *)zalloc(config_name_len + 1);
+ memcpy(gap_device_name, config_name, config_name_len + 1);
+ log_info("ble name");
+ put_buf(gap_device_name, gap_device_name_len + 1);
+ printf("%s", gap_device_name);
+#endif
+#if WIRELESS_PAIR_BONDING
+ conn_pair_vm_do(&conn_pair_info, 0);
+ ble_check_need_pair_adv();
+ printf("pair_flag = %d", conn_pair_info.pair_flag);
+#endif
+
+ extern void wifi_detect_set_master_first(u8 first);
+#if TCFG_WIFI_DETECT_ENABLE
+#if TCFG_WIFI_DETCET_PRIOR
+ wifi_detect_set_master_first(0);
+#else
+ wifi_detect_set_master_first(1);
+#endif
+#endif
+
+#if (WIRELESS_24G_ENABLE)
+ rf_set_24g_hackable_coded(WIRELESS_24G_CODE_ID);
+#endif
+
+ set_ble_work_state(BLE_ST_INIT_OK);
+ ble_module_enable(1);
+
+}
+
+void bt_ble_exit(void)
+{
+ log_info("***** ble_exit******\n");
+ ble_module_enable(0);
+}
+
+
+void ble_app_disconnect(void)
+{
+ ble_disconnect(NULL);
+}
+
+
+static const struct ble_server_operation_t mi_ble_operation = {
+ .adv_enable = set_adv_enable,
+ .disconnect = ble_disconnect,
+ .get_buffer_vaild = get_buffer_vaild_len,
+ .send_data = (void *)app_send_user_data_do,
+ .regist_wakeup_send = regiest_wakeup_send,
+ .regist_recieve_cbk = regiest_recieve_cbk,
+ .regist_state_cbk = regiest_state_cbk,
+};
+
+void ble_get_server_operation_table(struct ble_server_operation_t **interface_pt)
+{
+ *interface_pt = (void *)&mi_ble_operation;
+}
+
+void ble_server_send_test_key_num(u8 key_num)
+{
+ ;
+}
+
+#endif
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/app/demo/tuya_ble_app_demo.c b/apps/common/third_party_profile/tuya_protocol/app/demo/tuya_ble_app_demo.c
new file mode 100644
index 0000000..d718b31
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/app/demo/tuya_ble_app_demo.c
@@ -0,0 +1,422 @@
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_heap.h"
+#include "tuya_ble_mem.h"
+#include "tuya_ble_api.h"
+#include "tuya_ble_port.h"
+#include "tuya_ble_main.h"
+#include "tuya_ble_secure.h"
+#include "tuya_ble_data_handler.h"
+#include "tuya_ble_storage.h"
+#include "tuya_ble_sdk_version.h"
+#include "tuya_ble_utils.h"
+#include "tuya_ble_event.h"
+#include "tuya_ble_app_demo.h"
+//#include "tuya_ble_demo_version.h"
+#include "tuya_ble_log.h"
+#include "tuya_ota.h"
+#include "system/generic/printf.h"
+
+#include "log.h"
+#include "system/includes.h"
+//#include "ota.h"
+
+tuya_ble_device_param_t device_param = {0};
+
+#define LED_PIN IO_PORTA_01
+static bool tuya_led_state = 0;
+
+//烧写器烧写三元组时这里置零
+#define TUYA_INFO_TEST 0
+
+#if TUYA_INFO_TEST
+static const char device_id_test[] = "tuya58253f7c8ed1";
+static const char auth_key_test[] = "I9ikbTKVMhfvEDgARBCtFbAWUpZIRdyv";
+static const uint8_t mac_test[6] = {0xDC, 0x23, 0x4D, 0x65, 0xB0, 0x66}; //The actual MAC address is : 66:55:44:33:22:11
+#endif /* TUYA_INFO_TEST */
+
+#define APP_CUSTOM_EVENT_1 1
+#define APP_CUSTOM_EVENT_2 2
+#define APP_CUSTOM_EVENT_3 3
+#define APP_CUSTOM_EVENT_4 4
+#define APP_CUSTOM_EVENT_5 5
+
+static uint8_t dp_data_array[255 + 3];
+static uint16_t dp_data_len = 0;
+
+typedef struct {
+ uint8_t data[50];
+} custom_data_type_t;
+
+void custom_data_process(int32_t evt_id, void *data)
+{
+ custom_data_type_t *event_1_data;
+ TUYA_APP_LOG_DEBUG("custom event id = %d", evt_id);
+ switch (evt_id) {
+ case APP_CUSTOM_EVENT_1:
+ event_1_data = (custom_data_type_t *)data;
+ TUYA_APP_LOG_HEXDUMP_DEBUG("received APP_CUSTOM_EVENT_1 data:", event_1_data->data, 50);
+ break;
+ case APP_CUSTOM_EVENT_2:
+ break;
+ case APP_CUSTOM_EVENT_3:
+ break;
+ case APP_CUSTOM_EVENT_4:
+ break;
+ case APP_CUSTOM_EVENT_5:
+ break;
+ default:
+ break;
+
+ }
+}
+
+custom_data_type_t custom_data;
+
+void custom_evt_1_send_test(uint8_t data)
+{
+ tuya_ble_custom_evt_t event;
+
+ for (uint8_t i = 0; i < 50; i++) {
+ custom_data.data[i] = data;
+ }
+ event.evt_id = APP_CUSTOM_EVENT_1;
+ event.custom_event_handler = (void *)custom_data_process;
+ event.data = &custom_data;
+ tuya_ble_custom_event_send(event);
+}
+
+static uint16_t sn = 0;
+static uint32_t time_stamp = 1587795793;
+
+void tuya_data_init()
+{
+ struct {
+ uint8_t id;
+ uint8_t type;
+ uint16_t len;
+ uint8_t data;
+ } p_dp_data;
+
+ p_dp_data.id = 1;
+ p_dp_data.type = 1;
+ p_dp_data.len = 0x0100;
+ p_dp_data.data = tuya_led_state;
+
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN == 0x03)
+ tuya_ble_dp_data_report(&p_dp_data, 5); //1
+#endif
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN == 0x04)
+ tuya_ble_dp_data_send(sn, DP_SEND_TYPE_ACTIVE, DP_SEND_FOR_CLOUD_PANEL, DP_SEND_WITH_RESPONSE, &p_dp_data, 5);
+#endif
+}
+
+void tuya_data_parse(tuya_ble_cb_evt_param_t *event)
+{
+ uint8_t *buf = event->dp_received_data.p_data;
+ uint32_t sn = event->dp_received_data.sn;
+ put_buf(buf, event->dp_received_data.data_len);
+ struct {
+ uint8_t id;
+ uint8_t type;
+ uint16_t len;
+ uint8_t data;
+ } p_dp_data;
+
+ p_dp_data.id = buf[0];
+ p_dp_data.type = buf[1];
+ p_dp_data.len = 0x0100;
+ p_dp_data.data = buf[4];
+
+ printf("\n\n<-------------- tuya_data_parse -------------->");
+ printf("sn = %d, id = %d, type = %d, len = %d, data = %d", sn, p_dp_data.id, p_dp_data.type, p_dp_data.len, p_dp_data.data);
+
+
+ switch (buf[0]) {
+ case 1:
+ printf("tuya switch control, onoff set to: %d\n", p_dp_data.data);
+ tuya_led_state = p_dp_data.data;
+ gpio_direction_output(LED_PIN, tuya_led_state);
+ break;
+ //case 2:
+ //printf("tuya mode control, mode set to: %d\n", buf[3]);
+ //break;
+ default:
+ printf("unknow control msg len = %d, data:", buf[2]);
+ break;
+ }
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN == 0x03)
+ tuya_ble_dp_data_report(&p_dp_data, 5); //1
+#endif
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN == 0x04)
+ tuya_ble_dp_data_send(sn, DP_SEND_TYPE_ACTIVE, DP_SEND_FOR_CLOUD_PANEL, DP_SEND_WITH_RESPONSE, &p_dp_data, 5);
+#endif
+
+}
+
+static void tuya_cb_handler(tuya_ble_cb_evt_param_t *event)
+{
+ int16_t result = 0;
+ printf("tuya cb_handler event->evt=0x%x\n", event->evt);
+ switch (event->evt) {
+ case TUYA_BLE_CB_EVT_CONNECTE_STATUS:
+ TUYA_APP_LOG_INFO("received tuya ble conncet status update event,current connect status = %d", event->connect_status);
+ break;
+ case TUYA_BLE_CB_EVT_DP_DATA_RECEIVED:
+ tuya_data_parse(event);
+ break;
+ case TUYA_BLE_CB_EVT_DP_DATA_REPORT_RESPONSE:
+ TUYA_APP_LOG_INFO("received dp data report response result code =%d", event->dp_response_data.status);
+
+ break;
+ case TUYA_BLE_CB_EVT_DP_DATA_WTTH_TIME_REPORT_RESPONSE:
+ TUYA_APP_LOG_INFO("received dp data report response result code =%d", event->dp_response_data.status);
+ break;
+ case TUYA_BLE_CB_EVT_DP_DATA_WITH_FLAG_REPORT_RESPONSE:
+ TUYA_APP_LOG_INFO("received dp data with flag report response sn = %d , flag = %d , result code =%d", event->dp_with_flag_response_data.sn, event->dp_with_flag_response_data.mode
+ , event->dp_with_flag_response_data.status);
+
+ break;
+ case TUYA_BLE_CB_EVT_DP_DATA_WITH_FLAG_AND_TIME_REPORT_RESPONSE:
+ TUYA_APP_LOG_INFO("received dp data with flag and time report response sn = %d , flag = %d , result code =%d", event->dp_with_flag_and_time_response_data.sn,
+ event->dp_with_flag_and_time_response_data.mode, event->dp_with_flag_and_time_response_data.status);
+
+ break;
+ case TUYA_BLE_CB_EVT_UNBOUND:
+
+ TUYA_APP_LOG_INFO("received unbound req");
+
+ break;
+ case TUYA_BLE_CB_EVT_ANOMALY_UNBOUND:
+
+ TUYA_APP_LOG_INFO("received anomaly unbound req");
+
+ break;
+ case TUYA_BLE_CB_EVT_DEVICE_RESET:
+
+ TUYA_APP_LOG_INFO("received device reset req");
+
+ break;
+ case TUYA_BLE_CB_EVT_DP_QUERY:
+ TUYA_APP_LOG_INFO("received TUYA_BLE_CB_EVT_DP_QUERY event");
+ if (dp_data_len > 0) {
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN == 0x03)
+ tuya_ble_dp_data_report(dp_data_array, dp_data_len);
+#endif
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN == 0x04)
+ tuya_ble_dp_data_send(sn, DP_SEND_TYPE_ACTIVE, DP_SEND_FOR_CLOUD_PANEL, DP_SEND_WITH_RESPONSE, dp_data_array, dp_data_len);
+#endif
+ }
+ break;
+ case TUYA_BLE_CB_EVT_OTA_DATA:
+ tuya_ota_proc(event->ota_data.type, event->ota_data.p_data, event->ota_data.data_len);
+ break;
+ case TUYA_BLE_CB_EVT_NETWORK_INFO:
+ TUYA_APP_LOG_INFO("received net info : %s", event->network_data.p_data);
+ tuya_ble_net_config_response(result);
+ break;
+ case TUYA_BLE_CB_EVT_WIFI_SSID:
+
+ break;
+ case TUYA_BLE_CB_EVT_TIME_STAMP:
+ TUYA_APP_LOG_INFO("received unix timestamp : %s ,time_zone : %d", event->timestamp_data.timestamp_string, event->timestamp_data.time_zone);
+ tuya_data_init();
+ break;
+ case TUYA_BLE_CB_EVT_TIME_NORMAL:
+
+ break;
+ case TUYA_BLE_CB_EVT_DATA_PASSTHROUGH:
+ TUYA_APP_LOG_HEXDUMP_DEBUG("received ble passthrough data :", event->ble_passthrough_data.p_data, event->ble_passthrough_data.data_len);
+ tuya_ble_data_passthrough(event->ble_passthrough_data.p_data, event->ble_passthrough_data.data_len);
+ break;
+ default:
+ TUYA_APP_LOG_WARNING("app_tuya_cb_queue msg: unknown event type 0x%04x", event->evt);
+ break;
+ }
+ tuya_ble_inter_event_response(event);
+}
+
+
+#define TUYA_LEGAL_CHAR(c) ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
+
+static u16 tuya_get_one_info(const u8 *in, u8 *out)
+{
+ int read_len = 0;
+ const u8 *p = in;
+
+ while (TUYA_LEGAL_CHAR(*p) && *p != ',') { //read product_uuid
+ *out++ = *p++;
+ read_len++;
+ }
+ return read_len;
+}
+
+typedef struct __flash_of_lic_para_head {
+ s16 crc;
+ u16 string_len;
+ const u8 para_string[];
+} __attribute__((packed)) _flash_of_lic_para_head;
+
+#define LIC_PAGE_OFFSET 80
+
+static bool license_para_head_check(u8 *para)
+{
+ _flash_of_lic_para_head *head;
+
+ //fill head
+ head = (_flash_of_lic_para_head *)para;
+
+ ///crc check
+ u8 *crc_data = (u8 *)(para + sizeof(((_flash_of_lic_para_head *)0)->crc));
+ u32 crc_len = sizeof(_flash_of_lic_para_head) - sizeof(((_flash_of_lic_para_head *)0)->crc)/*head crc*/ + (head->string_len)/*content crc,include end character '\0'*/;
+ s16 crc_sum = 0;
+
+ crc_sum = CRC16(crc_data, crc_len);
+
+ if (crc_sum != head->crc) {
+ printf("license crc error !!! %x %x \n", (u32)crc_sum, (u32)head->crc);
+ return false;
+ }
+
+ return true;
+}
+
+const u8 *tuya_get_license_ptr(void)
+{
+ u32 flash_capacity = sdfile_get_disk_capacity();
+ u32 flash_addr = flash_capacity - 256 + LIC_PAGE_OFFSET;
+ u8 *lic_ptr = NULL;
+ _flash_of_lic_para_head *head;
+
+ printf("flash capacity:%x \n", flash_capacity);
+ lic_ptr = (u8 *)sdfile_flash_addr2cpu_addr(flash_addr);
+
+ //head length check
+ head = (_flash_of_lic_para_head *)lic_ptr;
+ if (head->string_len >= 0xff) {
+ printf("license length error !!! \n");
+ return NULL;
+ }
+
+ ////crc check
+ if (license_para_head_check(lic_ptr) == (false)) {
+ printf("license head check fail\n");
+ return NULL;
+ }
+
+ //put_buf(lic_ptr, 128);
+
+ lic_ptr += sizeof(_flash_of_lic_para_head);
+ return lic_ptr;
+}
+
+static uint8_t read_tuya_product_info_from_flash(uint8_t *read_buf, u16 buflen)
+{
+ uint8_t *rp = read_buf;
+ const uint8_t *tuya_ptr = (uint8_t *)tuya_get_license_ptr();
+ //printf("tuya_ptr:");
+ //put_buf(tuya_ptr, 69);
+
+ if (tuya_ptr == NULL) {
+ return FALSE;
+ }
+ int data_len = 0;
+ data_len = tuya_get_one_info(tuya_ptr, rp);
+ //put_buf(rp, data_len);
+ if (data_len != 16) {
+ printf("read uuid err, data_len:%d", data_len);
+ put_buf(rp, data_len);
+ return FALSE;
+ }
+ tuya_ptr += 17;
+
+ rp = read_buf + 16;
+
+ data_len = tuya_get_one_info(tuya_ptr, rp);
+ //put_buf(rp, data_len);
+ if (data_len != 32) {
+ printf("read key err, data_len:%d", data_len);
+ put_buf(rp, data_len);
+ return FALSE;
+ }
+ tuya_ptr += 33;
+
+ rp = read_buf + 16 + 32;
+ data_len = tuya_get_one_info(tuya_ptr, rp);
+ //put_buf(rp, data_len);
+ if (data_len != 12) {
+ printf("read mac err, data_len:%d", data_len);
+ put_buf(rp, data_len);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static u8 ascii_to_hex(u8 in)
+{
+ if (in >= '0' && in <= '9') {
+ return in - '0';
+ } else if (in >= 'a' && in <= 'f') {
+ return in - 'a' + 0x0a;
+ } else if (in >= 'A' && in <= 'F') {
+ return in - 'A' + 0x0a;
+ } else {
+ printf("tuya ascii to hex error, data:0x%x", in);
+ return 0;
+ }
+}
+
+static void parse_mac_data(u8 *in, u8 *out)
+{
+ for (int i = 0; i < 6; i++) {
+ out[i] = (ascii_to_hex(in[2 * i]) << 4) + ascii_to_hex(in[2 * i + 1]);
+ }
+}
+
+void tuya_ble_app_init(void)
+{
+ device_param.device_id_len = 16; //If use the license stored by the SDK,initialized to 0, Otherwise 16 or 20.
+ uint8_t read_buf[16 + 32 + 6 + 1] = {0};
+
+ int ret = 0;
+ device_param.use_ext_license_key = 1;
+ if (device_param.device_id_len == 16) {
+#if TUYA_INFO_TEST
+ memcpy(device_param.auth_key, (void *)auth_key_test, AUTH_KEY_LEN);
+ memcpy(device_param.device_id, (void *)device_id_test, DEVICE_ID_LEN);
+ memcpy(device_param.mac_addr.addr, mac_test, 6);
+#else
+ ret = read_tuya_product_info_from_flash(read_buf, sizeof(read_buf));
+ if (ret == TRUE) {
+ uint8_t mac_data[6];
+ memcpy(device_param.device_id, read_buf, 16);
+ memcpy(device_param.auth_key, read_buf + 16, 32);
+ parse_mac_data(read_buf + 16 + 32, mac_data);
+ memcpy(device_param.mac_addr.addr, mac_data, 6);
+ }
+#endif
+ device_param.mac_addr.addr_type = TUYA_BLE_ADDRESS_TYPE_RANDOM;
+ }
+ printf("device_id:");
+ put_buf(device_param.device_id, 16);
+ printf("auth_key:");
+ put_buf(device_param.auth_key, 32);
+ printf("mac:");
+ put_buf(device_param.mac_addr.addr, 6);
+
+ device_param.p_type = TUYA_BLE_PRODUCT_ID_TYPE_PID;
+ device_param.product_id_len = 8;
+ memcpy(device_param.product_id, APP_PRODUCT_ID, 8);
+ device_param.firmware_version = TY_APP_VER_NUM;
+ device_param.hardware_version = TY_HARD_VER_NUM;
+ printf("HJY:12345\n");
+ tuya_ble_sdk_init(&device_param);
+ ret = tuya_ble_callback_queue_register(tuya_cb_handler);
+ y_printf("tuya_ble_callback_queue_register,ret=%d\n", ret);
+
+ //tuya_ota_init();
+
+ //TUYA_APP_LOG_INFO("demo project version : "TUYA_BLE_DEMO_VERSION_STR);
+ TUYA_APP_LOG_INFO("app version : "TY_APP_VER_STR);
+
+}
diff --git a/apps/common/third_party_profile/tuya_protocol/app/demo/tuya_ble_app_demo.h b/apps/common/third_party_profile/tuya_protocol/app/demo/tuya_ble_app_demo.h
new file mode 100644
index 0000000..2eef02c
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/app/demo/tuya_ble_app_demo.h
@@ -0,0 +1,48 @@
+#ifndef TUYA_BLE_APP_DEMO_H_
+#define TUYA_BLE_APP_DEMO_H_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#define APP_PRODUCT_ID "xqhyt364"
+
+#define APP_BUILD_FIRMNAME "tuya_ble_sdk_app_demo_nrf52832"
+
+//固件版本
+#define TY_APP_VER_NUM 0x0100
+#define TY_APP_VER_STR "1.0"
+
+//硬件版本
+#define TY_HARD_VER_NUM 0x0100
+#define TY_HARD_VER_STR "1.0"
+
+
+/*
+typedef enum {
+ white,
+ colour,
+ scene,
+ music,
+} tuya_light_mode;
+*/
+
+
+void tuya_ble_app_init(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //
+
+
+
+
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/app/demo/tuya_ota.c b/apps/common/third_party_profile/tuya_protocol/app/demo/tuya_ota.c
new file mode 100644
index 0000000..d0c3d3c
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/app/demo/tuya_ota.c
@@ -0,0 +1,207 @@
+#include "tuya_ota.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_app_demo.h"
+#include "dual_bank_updata_api.h"
+#include "timer.h"
+#include "asm/clock.h"
+
+extern u8 dual_bank_update_verify_without_crc(void);
+tuya_ble_status_t tuya_ble_ota_response(tuya_ble_ota_response_t *p_data);
+
+#define OTA_WRITE_FLASH_SIZE (2048)
+
+typedef struct {
+ u32 file_size;
+ u32 recv_len;
+ u32 file_crc;
+ u16 tuya_ota_packet_num;
+ u8 buff[OTA_WRITE_FLASH_SIZE];
+ u32 buff_size;
+} tuya_ota_t;
+
+tuya_ota_t tuya_ota;
+
+__attribute__((weak))
+u8 tuya_start_ota_check(void)
+{
+ return 0;
+}
+
+void tuya_ota_reset(void *priv)
+{
+ cpu_reset();
+}
+
+int tuya_ota_boot_info_cb(int err)
+{
+ sys_timeout_add(NULL, tuya_ota_reset, 2000);
+ return 0;
+}
+
+int tuya_ota_file_end_response(void *priv)
+{
+ tuya_ble_ota_response_t response;
+ tuya_ota_end_response_t ota_end_response;
+ ota_end_response.reserve = 0;
+
+ int old_sys_clk = clk_get("sys");
+
+ clk_set("sys", 120 * 1000000L); //提升系统时钟提高校验速度
+ if (dual_bank_update_verify_without_crc() == 0) {
+ printf("UPDATE SUCCESS");
+ ota_end_response.state = 0;
+ dual_bank_update_burn_boot_info(tuya_ota_boot_info_cb);
+ } else {
+ printf("UPDATE FAILURE");
+ ota_end_response.state = 2;
+ }
+ clk_set("sys", old_sys_clk); //恢复时钟
+ response.type = TUYA_BLE_OTA_END;
+ response.p_data = &ota_end_response;
+ response.data_len = 2;
+ return tuya_ble_ota_response(&response);
+}
+
+int tuya_ota_data_response()
+{
+ tuya_ble_ota_response_t response;
+ tuya_ota_data_response_t ota_data_response;
+ response.type = TUYA_BLE_OTA_DATA;
+ ota_data_response.reserve = 0;
+ ota_data_response.state = TUYA_OTA_DATA_SUCC;
+ response.p_data = &ota_data_response;
+ response.data_len = 2;
+ tuya_ble_ota_response(&response);
+ return 0;
+}
+
+int tuya_update_write_cb(void *priv)
+{
+ tuya_ota_data_response();
+ return 0;
+}
+
+void tuya_ota_proc(u16 type, u8 *recv_data, u32 recv_len)
+{
+ tuya_ble_ota_response_t response;
+ static bool first_packet_come = 0;
+ static u32 current_file_size = 0;
+
+ switch (type) {
+ case TUYA_BLE_OTA_REQ:
+ printf("TUYA_BLE_OTA_REQ\n");
+ dual_bank_passive_update_exit(NULL); //tuya APP退到后台会中断发数,重新开始REQ要退出上一次的任务
+ tuya_ota_req_response_t ota_req_response;
+ ota_req_response.flag = tuya_start_ota_check();
+ ota_req_response.ota_version = 3;
+ ota_req_response.reserve = 0;
+ ota_req_response.frame_version = TY_APP_VER_NUM;
+ ota_req_response.max_pkt_len = OTA_MAX_DATA_LEN;
+ first_packet_come = 0;
+ current_file_size = 0;
+ response.p_data = &ota_req_response;
+ response.data_len = 9;
+ memset(&tuya_ota, 0, sizeof(tuya_ota));
+ break;
+ case TUYA_BLE_OTA_FILE_INFO:
+ printf("TUYA_BLE_OTA_FILE_INFO\n");
+ tuya_ota_file_info_response_t ota_file_info_response;
+ ota_file_info_response.reserve = 0;
+ tuya_ota.file_size = READ_BIG_U32(recv_data + 29);
+ uint32_t file_version = READ_BIG_U32(recv_data + 9);
+ printf("TUYA_BLE_OTA_FILE_INFO file_size%d file_version%d", tuya_ota.file_size, file_version);
+ dual_bank_passive_update_init(0, tuya_ota.file_size, OTA_WRITE_FLASH_SIZE, NULL);
+ if (dual_bank_update_allow_check(tuya_ota.file_size) != 0) {
+ dual_bank_passive_update_exit(NULL);
+ ota_file_info_response.state = TUYA_OTA_STATE_FILE_SIZE_TOO_LARGE;
+ } else if (file_version <= TY_APP_VER_NUM) {
+ dual_bank_passive_update_exit(NULL);
+ ota_file_info_response.state = TUYA_OTA_STATE_VER_LOW;
+ } else {
+ ota_file_info_response.state = TUYA_OTA_STATE_NORMAL;
+ }
+ response.p_data = &ota_file_info_response;
+ response.data_len = 26;
+ break;
+ case TUYA_BLE_OTA_FILE_OFFSET_REQ:
+ printf("TUYA_BLE_OTA_FILE_OFFSET_REQ\n");
+ uint8_t data[5] = {0};
+ response.type = TUYA_BLE_OTA_FILE_OFFSET_REQ;
+ u32 offset_addr = READ_BIG_U32(recv_data + 1);
+ data[1] = (u8)(offset_addr >> 24);
+ data[2] = (u8)(offset_addr >> 16);
+ data[3] = (u8)(offset_addr >> 8);
+ data[4] = (u8)(offset_addr >> 0);
+ printf("offset_addr = 0x%x", offset_addr);
+ response.data_len = 5;
+ response.p_data = data;
+ tuya_ble_ota_response(&response);
+ return;
+ /* tuya_ota_file_offset_response_t ota_file_offset_response; */
+ /* ota_file_offset_response.reserve = 0; */
+ /* ota_file_offset_response.offset = recv_data[1] << 24 | recv_data[2] << 16 | recv_data[3] << 8 | recv_data[4]; */
+ /* printf("offset:%d\n", ota_file_offset_response.offset); */
+ /* response.p_data = &ota_file_offset_response; */
+ /* response.data_len = 2; */
+ break;
+ case TUYA_BLE_OTA_DATA:
+ printf("TUYA_BLE_OTA_DATA\n");
+ tuya_ota_data_response_t ota_data_response;
+ ota_data_response.reserve = 0;
+ u16 remote_packet_num = (recv_data[1] << 8) + recv_data[2];
+ u32 cur_frame_size = (recv_data[3] << 8) + recv_data[4];
+
+ if (remote_packet_num == 0 && first_packet_come == 1) {
+ printf("OTA ERROR packet num error, num = %d", remote_packet_num);
+ ota_data_response.state = TUYA_OTA_DATA_PKT_NUM_ERR;
+ response.p_data = &ota_data_response;
+ response.data_len = 2;
+ response.type = TUYA_BLE_OTA_DATA;
+ tuya_ble_ota_response(&response);
+
+ return;
+ }
+
+ current_file_size += cur_frame_size;
+ printf("OTA DATA info:");
+ put_buf(recv_data, 7);
+ printf("file_size:%d remote_packet_num:%d, last_packet_num = %d, frame_size:%d\n", current_file_size, remote_packet_num, tuya_ota.tuya_ota_packet_num, recv_len - 7);
+
+ first_packet_come = 1;
+
+ if (remote_packet_num && remote_packet_num != tuya_ota.tuya_ota_packet_num + 1) {
+ printf("OTA ERROR packet num error");
+ ota_data_response.state = TUYA_OTA_DATA_PKT_NUM_ERR;
+ response.p_data = &ota_data_response;
+ response.data_len = 2;
+ tuya_ble_ota_response(&response);
+ //dual_bank_passive_update_exit(NULL);
+ return;
+ } else {
+ tuya_ota.recv_len += recv_len - 7;
+ memcpy(tuya_ota.buff + tuya_ota.buff_size, recv_data + 7, recv_len - 7);
+ tuya_ota.buff_size += recv_len - 7;
+ if (tuya_ota.buff_size >= OTA_WRITE_FLASH_SIZE) {
+ dual_bank_update_write(tuya_ota.buff, OTA_WRITE_FLASH_SIZE, tuya_update_write_cb);
+ tuya_ota.buff_size -= OTA_WRITE_FLASH_SIZE;
+ } else {
+ tuya_ota_data_response();
+ tuya_ota.tuya_ota_packet_num = remote_packet_num;
+ return;
+ }
+ }
+ tuya_ota.tuya_ota_packet_num = remote_packet_num;
+ break;
+ case TUYA_BLE_OTA_END:
+ printf("TUYA_BLE_OTA_END\n");
+ if (tuya_ota.buff_size != 0) { //把剩余的数据写入flash
+ dual_bank_update_write(tuya_ota.buff, tuya_ota.buff_size, tuya_ota_file_end_response);
+ } else {
+ tuya_ota_file_end_response(NULL);
+ }
+ break;
+ }
+ response.type = type;
+ tuya_ble_ota_response(&response);
+}
+
diff --git a/apps/common/third_party_profile/tuya_protocol/app/demo/tuya_ota.h b/apps/common/third_party_profile/tuya_protocol/app/demo/tuya_ota.h
new file mode 100644
index 0000000..7247570
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/app/demo/tuya_ota.h
@@ -0,0 +1,58 @@
+#ifndef __TUYA_OTA_H__
+#define __TUYA_OTA_H__
+
+#include "typedef.h"
+
+#define OTA_MAX_DATA_LEN 128
+
+enum {
+ TUYA_OTA_STATE_NORMAL = 0,
+ TUYA_OTA_STATE_PID_NO_MATCH,
+ TUYA_OTA_STATE_VER_LOW,
+ TUYA_OTA_STATE_FILE_SIZE_TOO_LARGE,
+};
+
+enum {
+ TUYA_OTA_DATA_SUCC = 0,
+ TUYA_OTA_DATA_PKT_NUM_ERR,
+ TUYA_OTA_DATA_LEN_ERR,
+ TUYA_OTA_DATA_CRC_FAILED,
+ TUYA_OTA_DATA_OTHER_ERR,
+};
+
+#define READ_BIG_U32(a) ((*((u8*)(a)) <<24) + (*((u8*)(a)+1)<<16) + (*((u8*)(a)+2)<<8) + *((u8*)(a)+3))
+
+typedef struct tuya_ota_req_response {
+ u8 flag;
+ u8 ota_version;
+ u8 reserve;
+ u32 frame_version;
+ u16 max_pkt_len;
+} tuya_ota_req_response_t;
+
+typedef struct tuya_ota_file_info_response {
+ u8 reserve;
+ u8 state;
+ u32 store_file_len; //用于断点续传,目前不支持
+ u32 store_crc;
+ u8 md5[16]; //目前不使用
+} tuya_ota_file_info_response_t;
+
+typedef struct tuya_ota_file_offset_response {
+ u8 reserve;
+ u32 offset;
+} tuya_ota_file_offset_response_t;
+
+typedef struct tuya_ota_data_response {
+ u8 reserve;
+ u8 state;
+} tuya_ota_data_response_t;
+
+typedef struct tuya_ota_end_response {
+ u8 reserve;
+ u8 state;
+} tuya_ota_end_response_t;
+
+void tuya_ota_proc(u16 type, u8 *recv_data, u32 recv_len);
+
+#endif
diff --git a/apps/common/third_party_profile/tuya_protocol/app/product_test/tuya_ble_app_production_test.c b/apps/common/third_party_profile/tuya_protocol/app/product_test/tuya_ble_app_production_test.c
new file mode 100644
index 0000000..657b5b0
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/app/product_test/tuya_ble_app_production_test.c
@@ -0,0 +1,1386 @@
+/**
+ * \file tuya_ble_app_production_test.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_heap.h"
+#include "tuya_ble_mem.h"
+#include "tuya_ble_api.h"
+#include "tuya_ble_port.h"
+#include "tuya_ble_main.h"
+#include "tuya_ble_internal_config.h"
+#include "tuya_ble_data_handler.h"
+#include "tuya_ble_mutli_tsf_protocol.h"
+#include "tuya_ble_utils.h"
+#include "tuya_ble_secure.h"
+#include "tuya_ble_main.h"
+#include "tuya_ble_storage.h"
+#include "tuya_ble_app_production_test.h"
+#include "tuya_ble_log.h"
+#include "tuya_ble_api.h"
+#include "tuya_ble_utils.h"
+
+
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE == TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION)
+#include "tuya_ecc.h"
+#if (TUYA_BLE_INCLUDE_CJSON_COMPONENTS != 0)
+#include "cJSON.h"
+#endif
+#endif
+
+#if defined(CUSTOMIZED_TUYA_BLE_APP_PRODUCT_TEST_HEADER_FILE)
+#include CUSTOMIZED_TUYA_BLE_APP_PRODUCT_TEST_HEADER_FILE
+#endif
+
+
+#if (TUYA_BLE_DEVICE_REGISTER_FROM_BLE&&TUYA_BLE_DEVICE_AUTH_DATA_STORE)
+
+static uint8_t tuya_ble_production_test_flag = 0;
+
+static uint8_t tuya_ble_production_test_with_ble_flag = 0;
+
+#define tuya_ble_prod_monitor_timeout_ms 60000 //60s
+
+tuya_ble_timer_t tuya_ble_xTimer_prod_monitor;
+
+
+void tuya_ble_internal_production_test_with_ble_flag_clear(void)
+{
+ tuya_ble_production_test_with_ble_flag = 0;
+}
+
+
+uint8_t tuya_ble_internal_production_test_with_ble_flag_get(void)
+{
+ return tuya_ble_production_test_with_ble_flag;
+}
+
+
+static void tuya_ble_vtimer_prod_monitor_callback(tuya_ble_timer_t pxTimer)
+{
+ tuya_ble_device_delay_ms(1000);
+ tuya_ble_device_reset();
+
+}
+
+static void tuya_ble_prod_monitor_timer_init(void)
+{
+ if (tuya_ble_timer_create(&tuya_ble_xTimer_prod_monitor, tuya_ble_prod_monitor_timeout_ms, TUYA_BLE_TIMER_SINGLE_SHOT, tuya_ble_vtimer_prod_monitor_callback) != TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_xTimer_prod_monitor creat failed");
+ }
+
+}
+
+
+static void tuya_ble_prod_monitor_timer_start(void)
+{
+ if (tuya_ble_timer_start(tuya_ble_xTimer_prod_monitor) != TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_xTimer_prod_monitor start failed");
+ }
+
+}
+
+static void tuya_ble_prod_monitor_timer_stop(void)
+{
+
+ if (tuya_ble_timer_stop(tuya_ble_xTimer_prod_monitor) != TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_xTimer_prod_monitor stop failed");
+ }
+
+}
+
+
+static uint32_t tuya_ble_uart_prod_send(uint8_t type, uint8_t *pdata, uint8_t len)
+{
+ uint8_t uart_send_len = 7 + len;
+ uint8_t *uart_send_buffer = NULL;
+
+ uart_send_buffer = (uint8_t *)tuya_ble_malloc(uart_send_len);
+ if (uart_send_buffer != NULL) {
+ uart_send_buffer[0] = 0x66;
+ uart_send_buffer[1] = 0xAA;
+ uart_send_buffer[2] = 0x00;
+ uart_send_buffer[3] = type;
+ uart_send_buffer[4] = 0;
+ uart_send_buffer[5] = len;
+ memcpy(uart_send_buffer + 6, pdata, len);
+ uart_send_buffer[6 + len] = tuya_ble_check_sum(uart_send_buffer, 6 + len);
+ tuya_ble_common_uart_send_data(uart_send_buffer, 7 + len);
+ tuya_ble_free(uart_send_buffer);
+ } else {
+ TUYA_BLE_LOG_ERROR("uart prod send buffer malloc failed.");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_prod_updata_mac(uint8_t *mac)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_prod_beacon_scan_start(void)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_prod_beacon_scan_stop(void)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_prod_beacon_get_rssi_avg(int8_t *rssi)
+{
+ *rssi = -20;
+ return TUYA_BLE_SUCCESS;
+}
+
+
+static void tuya_ble_auc_enter(uint8_t *para, uint16_t len)
+{
+ uint8_t buf[1];
+
+ /* if dev is binding, can't entry ftm mode */
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) {
+ TUYA_BLE_LOG_DEBUG("AUC ENTER, BUT DEV IS BINDING");
+
+ tuya_ble_device_delay_ms(200);
+ tuya_ble_device_reset();
+ return;
+ }
+
+ TUYA_BLE_LOG_DEBUG("AUC ENTER!");
+
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE == TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION)
+ buf[0] = (TUYA_BLE_AUC_FINGERPRINT_VER << TUYA_BLE_AUC_FW_FINGERPRINT_POS) | \
+ (TUYA_BLE_AUC_WRITE_PID << TUYA_BLE_AUC_WRITE_PID_POS) |
+ (TUYA_BLE_AUC_WRITE_DEV_CERT << TUYA_BLE_AUC_WRITE_DEV_CERT_POS);
+#else
+ buf[0] = (TUYA_BLE_AUC_FINGERPRINT_VER << TUYA_BLE_AUC_FW_FINGERPRINT_POS) | \
+ (TUYA_BLE_AUC_WRITE_PID << TUYA_BLE_AUC_WRITE_PID_POS);
+#endif
+
+ if (tuya_ble_production_test_flag == 1) {
+ //tuya_ble_stop_scan();
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_ENTER, buf, 1);
+ return;
+ }
+ tuya_ble_prod_monitor_timer_init();
+
+ tuya_ble_prod_monitor_timer_start();
+
+ tuya_ble_prod_beacon_scan_start();
+
+ tuya_ble_production_test_flag = 1;
+
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_ENTER, buf, 1);
+}
+
+
+static void tuya_ble_auc_query_hid(uint8_t *para, uint16_t len)
+{
+ if (tuya_ble_production_test_flag != 1) {
+ return;
+ }
+
+ TUYA_BLE_LOG_DEBUG("AUC QUERY HID!");
+ char buf[70] = "{\"ret\":true,\"hid\":\"\"}";
+
+
+ if (tuya_ble_buffer_value_is_all_x(tuya_ble_current_para.auth_settings.h_id, H_ID_LEN, 0xFF)) {
+ buf[19] = '\"';
+ buf[20] = '}';
+ } else if (tuya_ble_buffer_value_is_all_x(tuya_ble_current_para.auth_settings.h_id, H_ID_LEN, 0)) {
+ buf[19] = '\"';
+ buf[20] = '}';
+ } else {
+ memcpy(&buf[19], tuya_ble_current_para.auth_settings.h_id, H_ID_LEN);
+ buf[38] = '\"';
+ buf[39] = '}';
+ }
+
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_QUERY_HID, (uint8_t *)buf, strlen(buf));
+
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("AUC QUERY HID response data : ", (uint8_t *)buf, strlen(buf));
+}
+
+
+
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_prod_gpio_test(void)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+
+static void tuya_ble_auc_gpio_test(uint8_t *para, uint16_t len)
+{
+ char ture_buf[] = "{\"ret\":true}";
+ char false_buf[] = "{\"ret\":false}";
+ if (tuya_ble_production_test_flag != 1) {
+ return;
+ }
+
+ TUYA_BLE_LOG_DEBUG("AUC GPIO TEST!");
+
+ if (tuya_ble_prod_gpio_test() == TUYA_BLE_SUCCESS) {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_GPIO_TEST, (uint8_t *)ture_buf, strlen(ture_buf));
+ TUYA_BLE_LOG_DEBUG("AUC GPIO TEST successed!");
+ } else {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_GPIO_TEST, (uint8_t *)false_buf, strlen(false_buf));
+ TUYA_BLE_LOG_ERROR("AUC GPIO TEST failed!");
+ }
+
+}
+
+
+static void tuya_ble_prod_asciitohex(uint8_t *ascbuf, uint8_t len, uint8_t *hexbuf)
+{
+ uint8_t i = 0, j = 0;
+
+ for (j = 0; j < (len / 2); j++) {
+ if ((ascbuf[i] >= 0x30) && (ascbuf[i] <= 0x39)) {
+ hexbuf[j] = ((ascbuf[i] - 0x30) << 4);
+ } else if ((ascbuf[i] >= 65) && (ascbuf[i] <= 70)) {
+ hexbuf[j] = ((ascbuf[i] - 55) << 4);
+ } else if ((ascbuf[i] >= 97) && (ascbuf[i] <= 102)) {
+ hexbuf[j] = ((ascbuf[i] - 87) << 4);
+ }
+ i++;
+ if ((ascbuf[i] >= 0x30) && (ascbuf[i] <= 0x39)) {
+ hexbuf[j] |= (ascbuf[i] - 0x30);
+ } else if ((ascbuf[i] >= 65) && (ascbuf[i] <= 70)) {
+ hexbuf[j] |= (ascbuf[i] - 55);
+ } else if ((ascbuf[i] >= 97) && (ascbuf[i] <= 102)) {
+ hexbuf[j] |= (ascbuf[i] - 87);
+ }
+ i++;
+
+ }
+
+}
+
+static void tuya_ble_auc_write_auth_info(uint8_t *para, uint16_t len)
+{
+ uint8_t mac_temp[6];
+ uint8_t mac_char[13];
+ uint8_t pid_len = 0, i = 0, pid_pos = 0;
+ char true_buf[] = "{\"ret\":true}";
+ char false_buf[] = "{\"ret\":false}";
+
+ if (tuya_ble_production_test_flag != 1) {
+ return;
+ }
+
+ TUYA_BLE_LOG_DEBUG("AUC WRITE AUTH INFO!");
+
+ /*
+ {
+ "auzkey":"xxxx", //"6":"32", 7 + 6+4
+ "uuid":"xxxx", //"4":"16", 7 +6+32+6 + 4+4
+ "mac":"xxxxxx", //"3":"12",
+ "prod_test":"xxxx" //"9":"4/5"
+ "pid":"abcdefgh" //if any
+ }
+ */
+
+ if (len < 100) {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_AUTH_INFO, (uint8_t *)false_buf, strlen(false_buf));
+ TUYA_BLE_LOG_ERROR("AUC_CMD_WRITE_AUTH_INFO error ,since Invalid length!");
+ return;
+ }
+
+#if ( TUYA_BLE_PROD_SUPPORT_OEM_TYPE == TUYA_BLE_PROD_OEM_TYPE_0_5 )
+ if ((memcmp(¶[2], "auzkey", 6) != 0) || (memcmp(¶[46], "uuid", 4) != 0) || (memcmp(¶[72], "mac", 3) != 0) || ((memcmp(¶[110], "pid\":\"", 6) != 0) && (memcmp(¶[111], "pid\":\"", 6) != 0))) {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_AUTH_INFO, (uint8_t *)false_buf, strlen(false_buf));
+ TUYA_BLE_LOG_ERROR("AUC_CMD_WRITE_AUTH_INFO error ,since Invalid paras");
+ return;
+ }
+
+ i = para[115] == '\"' ? 116 : 117;
+ pid_pos = i;
+ pid_len = 0;
+ while ((para[i] != '\"') && (pid_len <= 20)) {
+ i++;
+ pid_len++;
+ }
+ if (pid_len > 20) {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_AUTH_INFO, (uint8_t *)false_buf, strlen(false_buf));
+ TUYA_BLE_LOG_ERROR("AUC_CMD_WRITE_AUTH_INFO error ,because pid len > 20 .");
+ return;
+ }
+
+ memcpy(mac_char, ¶[78], 12);
+ tuya_ble_prod_asciitohex(mac_char, 12, mac_temp);
+
+ if (tuya_ble_storage_write_auth_key_device_id_mac(¶[11], AUTH_KEY_LEN, ¶[53], DEVICE_ID_LEN, mac_temp, MAC_LEN, mac_char, MAC_LEN * 2, ¶[pid_pos], pid_len) == TUYA_BLE_SUCCESS) {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_AUTH_INFO, (uint8_t *)true_buf, strlen(true_buf));
+ TUYA_BLE_LOG_DEBUG("AUC WRITE AUTH INFO successed!");
+ } else {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_AUTH_INFO, (uint8_t *)false_buf, strlen(false_buf));
+ TUYA_BLE_LOG_ERROR("AUC_CMD_WRITE_AUTH_INFO failed!");
+ }
+#else
+ if ((memcmp(¶[2], "auzkey", 6) != 0) || (memcmp(¶[46], "uuid", 4) != 0) || (memcmp(¶[72], "mac", 3) != 0)) {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_AUTH_INFO, (uint8_t *)false_buf, strlen(false_buf));
+ TUYA_BLE_LOG_ERROR("AUC_CMD_WRITE_AUTH_INFO error ,since Invalid paras");
+ return;
+ }
+
+ memcpy(mac_char, ¶[78], 12);
+ tuya_ble_prod_asciitohex(mac_char, 12, mac_temp);
+
+ if (tuya_ble_storage_write_auth_key_device_id_mac(¶[11], AUTH_KEY_LEN, ¶[53], DEVICE_ID_LEN, mac_temp, MAC_LEN, mac_char, MAC_LEN * 2, NULL, 0) == TUYA_BLE_SUCCESS) {
+ tuya_ble_prod_updata_mac(mac_temp);
+
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_AUTH_INFO, (uint8_t *)true_buf, strlen(true_buf));
+ TUYA_BLE_LOG_DEBUG("AUC WRITE AUTH INFO successed!");
+ } else {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_AUTH_INFO, (uint8_t *)false_buf, strlen(false_buf));
+ TUYA_BLE_LOG_ERROR("AUC_CMD_WRITE_AUTH_INFO failed!");
+ }
+#endif
+}
+
+
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE == TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION)
+volatile uint32_t comm_cfg_total_len = 0;
+volatile uint32_t comm_cfg_cur_rcv_len = 0;
+uint8_t *p_comm_cfg = NULL;
+
+
+#if ( TUYA_BLE_INCLUDE_CJSON_COMPONENTS != 0 )
+static void tuya_ble_auc_write_comm_cfg(uint8_t *para, uint16_t len)
+{
+ char reply_buf[64] = {0};
+ uint16_t reply_buf_len = 0;
+ bool reply_ret = false;
+
+ if (tuya_ble_production_test_flag != 1) {
+ return;
+ }
+
+ TUYA_BLE_LOG_DEBUG("AUC WRITE COMM CFG INFO!");
+
+ cJSON *root = NULL, *item = NULL;
+ int type;
+ char *key = NULL;
+ char *value = NULL;
+ uint32_t offset, crc32, calc_crc32;
+
+ unsigned char pstr[len + 1];
+ memset(pstr, 0x00, len + 1);
+ memcpy(pstr, para, len);
+
+ root = cJSON_Parse((char *)pstr);
+ if (!root) {
+ TUYA_BLE_LOG_ERROR("cJSON error : [%s]\n", cJSON_GetErrorPtr());
+ goto EXIT_ERR;
+ }
+
+ // type
+ item = cJSON_GetObjectItem(root, "type");
+ if (NULL == item) {
+ goto EXIT_ERR;
+ }
+ type = item->valueint;
+
+ // key
+ item = cJSON_GetObjectItem(root, "key");
+ if (NULL == item) {
+ goto EXIT_ERR;
+ }
+ key = item->valuestring;
+
+ if ((memcmp(key, "deviceCertificate", strlen("deviceCertificate")) != 0) && \
+ (memcmp(key, "privateKey", strlen("privateKey")) != 0)) {
+ TUYA_BLE_LOG_ERROR("WRITE COMM CFG, but key unknow.");
+ goto EXIT_ERR;
+ }
+
+ /* process different types, 1->size 2->value 3->crc32 */
+ if (type == 1) {
+ // size
+ item = cJSON_GetObjectItem(root, "size");
+ if (NULL == item) {
+ goto EXIT_ERR;
+ }
+
+ comm_cfg_total_len = item->valueint;
+ comm_cfg_cur_rcv_len = 0;
+
+ p_comm_cfg = (uint8_t *)tuya_ble_malloc(comm_cfg_total_len + 16);
+ if (p_comm_cfg == NULL) {
+ TUYA_BLE_LOG_ERROR("WRITE COMM CFG, malloc failed.");
+ } else {
+ reply_ret = true;
+ }
+ } else if (type == 2) {
+ // value + offset
+ item = cJSON_GetObjectItem(root, "value");
+ if (NULL == item) {
+ goto EXIT_ERR;
+ }
+ value = item->valuestring;
+
+ item = cJSON_GetObjectItem(root, "offset");
+ if (NULL == item) {
+ goto EXIT_ERR;
+ }
+ offset = item->valueint;
+
+ memcpy(&p_comm_cfg[offset], value, strlen(value));
+ TUYA_BLE_LOG_DEBUG("WRITE COMM CFG offset=[%d] value_size=[%d]", offset, strlen(value));
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("value", (uint8_t *)value, strlen(value));
+
+ comm_cfg_cur_rcv_len += strlen(value);
+ reply_ret = true;
+ } else if (type == 3) {
+ // crc32
+ if (comm_cfg_cur_rcv_len != comm_cfg_total_len) {
+ TUYA_BLE_LOG_DEBUG("WRITE COMM CFG size err, recv=[%d] total=[%d]", comm_cfg_cur_rcv_len, comm_cfg_total_len);
+ goto EXIT_ERR;
+ }
+
+ item = cJSON_GetObjectItem(root, "crc32");
+ if (NULL == item) {
+ goto EXIT_ERR;
+ }
+ crc32 = (uint32_t)item->valueint;
+
+ calc_crc32 = tuya_ble_crc32_compute(p_comm_cfg, comm_cfg_total_len, NULL);
+ if (crc32 != calc_crc32) {
+ TUYA_BLE_LOG_DEBUG("WRITE COMM CFG crc32 err, calc=[%d] crc32=[%d]", calc_crc32, crc32);
+ } else {
+ TUYA_BLE_LOG_DEBUG("---------WRITE COMM CFG write context success---------");
+ TUYA_BLE_LOG_DEBUG("context size = [%d]", comm_cfg_total_len);
+ TUYA_BLE_LOG_DEBUG("context crc32 = [%d]", crc32);
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("context ", p_comm_cfg, comm_cfg_total_len);
+ reply_ret = true;
+
+ /* write to security chip */
+ if (memcmp(key, "deviceCertificate", strlen("deviceCertificate")) == 0) {
+ if (tuya_ble_storage_private_data(PRIVATE_DATA_DEV_CERT, p_comm_cfg, comm_cfg_total_len) != TUYA_BLE_SUCCESS) {
+ reply_ret = false;
+ }
+ } else if (memcmp(key, "privateKey", strlen("privateKey")) == 0) {
+ uint8_t private_key[64] = {0};
+ uint16_t private_key_len;
+
+ if (tuya_ble_ecc_key_pem2hex((char *)p_comm_cfg, private_key, &private_key_len) == 0) {
+ TUYA_BLE_LOG_DEBUG("tuya ble ecc key pem2hex failed");
+ reply_ret = false;
+ } else {
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("private key raw", private_key, private_key_len);
+
+ if (tuya_ble_storage_private_data(PRIVATE_DATA_ECC_KEY, private_key, private_key_len) != TUYA_BLE_SUCCESS) {
+ reply_ret = false;
+ }
+ }
+ }
+
+ if (p_comm_cfg != NULL) {
+ tuya_ble_free(p_comm_cfg);
+ }
+ }
+ } else {
+ TUYA_BLE_LOG_ERROR("WRITE COMM CFG type err. [%d]", type);
+ }
+
+EXIT_ERR:
+ if (reply_ret) {
+ reply_buf_len = sprintf((char *)reply_buf, "{\"ret\":true,\"key\":\"%s\"}", key);
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_COMM_CFG, (uint8_t *)reply_buf, reply_buf_len);
+
+ TUYA_BLE_LOG_DEBUG("AUC WRITE COMM CFG responsed successed.");
+ } else {
+ reply_buf_len = sprintf((char *)reply_buf, "{\"ret\":false,\"key\":\"%s\"}", key);
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_COMM_CFG, (uint8_t *)reply_buf, reply_buf_len);
+
+ TUYA_BLE_LOG_DEBUG("AUC WRITE COMM CFG failed!");
+
+ if (p_comm_cfg != NULL) {
+ tuya_ble_free(p_comm_cfg);
+ }
+ }
+
+ if (NULL != root) {
+ cJSON_Delete(root);
+ }
+}
+#else
+static void tuya_ble_auc_write_comm_cfg(uint8_t *para, uint16_t len)
+{
+ char reply_buf[64] = {0};
+ uint16_t reply_buf_len = 0;
+ bool reply_ret = false;
+
+ if (tuya_ble_production_test_flag != 1) {
+ return;
+ }
+
+ TUYA_BLE_LOG_DEBUG("AUC WRITE COMM CFG INFO!");
+
+ int i;
+ int type, size, offset, crc32;
+ char key[64] = {0};
+ uint8_t symbol_colon_index[32] = {0};
+ uint8_t symbol_comma_index[32] = {0};
+ uint8_t symbol_colon_cnt, symbol_comma_cnt;
+ uint16_t start_pos, end_pos, cut_len;
+ uint32_t calc_crc32;
+
+ symbol_colon_cnt = tuya_ble_search_symbol_index((char *)para, len, ':', symbol_colon_index);
+ symbol_comma_cnt = tuya_ble_search_symbol_index((char *)para, len, ',', symbol_comma_index);
+ if (symbol_colon_cnt == 0 || symbol_comma_cnt == 0) {
+ goto EXIT_ERR;
+ }
+
+ TUYA_BLE_LOG_DEBUG("symbol->: cnt=[%d]", symbol_colon_cnt);
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("symbol : list index", symbol_colon_index, symbol_colon_cnt);
+
+ TUYA_BLE_LOG_DEBUG("symbol->, cnt=[%d]", symbol_comma_cnt);
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("symbol , list index", symbol_comma_index, symbol_comma_cnt);
+
+ // type
+ start_pos = symbol_colon_index[0] + 1;
+ type = para[start_pos] - '0';
+ TUYA_BLE_LOG_DEBUG("parse type ->[%d]", type);
+
+ // key
+ start_pos = symbol_colon_index[1] + 2;
+ end_pos = symbol_comma_index[1] - 2;
+ cut_len = (end_pos - start_pos + 1);
+ memcpy(key, ¶[start_pos], cut_len);
+ key[cut_len] = '\0';
+ TUYA_BLE_LOG_DEBUG("parse key ->[%s]", key);
+
+ if ((memcmp(key, "deviceCertificate", strlen("deviceCertificate")) != 0) && \
+ (memcmp(key, "privateKey", strlen("privateKey")) != 0)) {
+ TUYA_BLE_LOG_ERROR("WRITE COMM CFG, but key unknow.");
+ goto EXIT_ERR;
+ }
+
+ /* process different types, 1->size 2->value 3->crc32 */
+ if (type == 1) {
+ /*
+ {
+ "type":1,
+ "key":"xxxx",
+ "size":xxx
+ }
+ */
+
+ // size
+ start_pos = symbol_colon_index[2] + 1;
+ end_pos = len - 2;
+ cut_len = (end_pos - start_pos + 1);
+ size = tuya_ble_ascii_to_int((char *)¶[start_pos], cut_len);
+ TUYA_BLE_LOG_DEBUG("parse size ->[%d]", size);
+
+ comm_cfg_total_len = size;
+ comm_cfg_cur_rcv_len = 0;
+
+ p_comm_cfg = (uint8_t *)tuya_ble_malloc(comm_cfg_total_len + 16);
+ if (p_comm_cfg == NULL) {
+ TUYA_BLE_LOG_ERROR("WRITE COMM CFG, malloc failed.");
+ } else {
+ reply_ret = true;
+ }
+ } else if (type == 2) {
+ /*
+ {
+ "type":2,
+ "key":"xxxx",
+ "value":"xxxx",
+ "offset":xxxx
+ }
+ */
+
+ // offset
+ start_pos = symbol_colon_index[3] + 1;
+ end_pos = len - 2;
+ cut_len = (end_pos - start_pos + 1);
+ offset = tuya_ble_ascii_to_int((char *)¶[start_pos], cut_len);
+ TUYA_BLE_LOG_DEBUG("parse offset ->[%d]", offset);
+
+ // value
+ start_pos = symbol_colon_index[2] + 2;
+ end_pos = symbol_comma_index[2] - 2;
+ cut_len = (end_pos - start_pos + 1);
+
+ // replace tab character "\r"->'\r' "\n"->'\n'
+ uint8_t *p_value = NULL;
+ uint16_t buf_i = 0;
+ p_value = (uint8_t *)tuya_ble_malloc(cut_len);
+
+ for (i = start_pos; i <= end_pos; i++) {
+ if ((para[i] == '\\') && (para[i + 1] == 'r')) {
+ p_value[buf_i++] = '\r';
+
+ i += 1;
+ cut_len -= 1;
+ TUYA_BLE_LOG_DEBUG("find r ");
+ } else if ((para[i] == '\\') && (para[i + 1] == 'n')) {
+ p_value[buf_i++] = '\n';
+
+ i += 1;
+ cut_len -= 1;
+ TUYA_BLE_LOG_DEBUG("find n ");
+ } else {
+ p_value[buf_i++] = para[i];
+ }
+ }
+
+ memcpy(&p_comm_cfg[offset], p_value, cut_len);
+ tuya_ble_free(p_value);
+ TUYA_BLE_LOG_DEBUG("WRITE COMM CFG offset=[%d] value_size=[%d]", offset, cut_len);
+
+ comm_cfg_cur_rcv_len += cut_len;
+ reply_ret = true;
+ } else if (type == 3) {
+ /*
+ {
+ "type":3,
+ "key":"xxxx",
+ "crc32":xxxx
+ }
+ */
+
+ if (comm_cfg_cur_rcv_len != comm_cfg_total_len) {
+ TUYA_BLE_LOG_DEBUG("WRITE COMM CFG size err, recv=[%d] total=[%d]", comm_cfg_cur_rcv_len, comm_cfg_total_len);
+ goto EXIT_ERR;
+ }
+
+ // crc32
+ start_pos = symbol_colon_index[2] + 1;
+ end_pos = len - 2;
+ cut_len = (end_pos - start_pos + 1);
+ crc32 = tuya_ble_ascii_to_int((char *)¶[start_pos], cut_len);
+ TUYA_BLE_LOG_DEBUG("parse crc32 ->[%d]", crc32);
+
+ calc_crc32 = tuya_ble_crc32_compute(p_comm_cfg, comm_cfg_total_len, NULL);
+ if (crc32 != calc_crc32) {
+ TUYA_BLE_LOG_DEBUG("WRITE COMM CFG crc32 err, calc=[%d] crc32=[%d]", calc_crc32, crc32);
+ } else {
+ TUYA_BLE_LOG_DEBUG("---------WRITE COMM CFG write context success---------");
+ TUYA_BLE_LOG_DEBUG("context size = [%d]", comm_cfg_total_len);
+ TUYA_BLE_LOG_DEBUG("context crc32 = [%d]", crc32);
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("context ", p_comm_cfg, comm_cfg_total_len);
+ reply_ret = true;
+
+ /* write to security chip */
+ if (memcmp(key, "deviceCertificate", strlen("deviceCertificate")) == 0) {
+ if (tuya_ble_storage_private_data(PRIVATE_DATA_DEV_CERT, p_comm_cfg, comm_cfg_total_len) != TUYA_BLE_SUCCESS) {
+ reply_ret = false;
+ }
+ } else if (memcmp(key, "privateKey", strlen("privateKey")) == 0) {
+ uint8_t private_key[64] = {0};
+ uint16_t private_key_len;
+
+ if (tuya_ble_ecc_key_pem2hex((char *)p_comm_cfg, private_key, &private_key_len) == 0) {
+ TUYA_BLE_LOG_DEBUG("tuya ble ecc key pem2hex failed");
+ reply_ret = false;
+ } else {
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("private key raw", private_key, private_key_len);
+
+ if (tuya_ble_storage_private_data(PRIVATE_DATA_ECC_KEY, private_key, private_key_len) != TUYA_BLE_SUCCESS) {
+ reply_ret = false;
+ }
+ }
+ }
+
+ if (p_comm_cfg != NULL) {
+ tuya_ble_free(p_comm_cfg);
+ }
+ }
+ } else {
+ TUYA_BLE_LOG_ERROR("WRITE COMM CFG type err. [%d]", type);
+ }
+
+EXIT_ERR:
+ if (reply_ret) {
+ reply_buf_len = sprintf((char *)reply_buf, "{\"ret\":true,\"key\":\"%s\"}", key);
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_COMM_CFG, (uint8_t *)reply_buf, reply_buf_len);
+
+ TUYA_BLE_LOG_DEBUG("AUC WRITE COMM CFG responsed successed.");
+ } else {
+ reply_buf_len = sprintf((char *)reply_buf, "{\"ret\":false,\"key\":\"%s\"}", key);
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_COMM_CFG, (uint8_t *)reply_buf, reply_buf_len);
+
+ TUYA_BLE_LOG_DEBUG("AUC WRITE COMM CFG failed!");
+
+ if (p_comm_cfg != NULL) {
+ tuya_ble_free(p_comm_cfg);
+ }
+ }
+}
+#endif // ( TUYA_BLE_INCLUDE_CJSON_COMPONENTS != 0 )
+#endif // ( TUYA_BLE_SECURE_CONNECTION_TYPE == TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION )
+
+
+static void tuya_ble_auc_query_info(uint8_t *para, uint16_t len)
+{
+
+ uint8_t i = 0;
+ uint8_t mac_temp[13];
+ uint8_t *alloc_buf = NULL;
+
+ if (tuya_ble_production_test_flag != 1) {
+ return;
+ }
+
+ TUYA_BLE_LOG_DEBUG("AUC QUERY INFO!");
+
+ alloc_buf = (uint8_t *)tuya_ble_malloc(256);
+
+ if (alloc_buf) {
+ memset(alloc_buf, 0, 256);
+ } else {
+ TUYA_BLE_LOG_ERROR("AUC QUERY INFO alloc buf malloc failed.");
+ return;
+ }
+
+ alloc_buf[i++] = '{';
+ alloc_buf[i++] = '\"';
+ memcpy(&alloc_buf[i], "ret", 3);
+ i += 3;
+ alloc_buf[i++] = '\"';
+
+ alloc_buf[i++] = ':';
+ memcpy(&alloc_buf[i], "true", 4);
+ i += 4;
+
+ alloc_buf[i++] = ',';
+ alloc_buf[i++] = '\"';
+ memcpy(&alloc_buf[i], "auzKey", 6);
+ i += 6;
+ alloc_buf[i++] = '\"';
+ alloc_buf[i++] = ':';
+ alloc_buf[i++] = '\"';
+ memcpy(&alloc_buf[i], tuya_ble_current_para.auth_settings.auth_key, AUTH_KEY_LEN);
+ i += AUTH_KEY_LEN;
+
+ alloc_buf[i++] = '\"';
+
+ alloc_buf[i++] = ',';
+ alloc_buf[i++] = '\"';
+ memcpy(&alloc_buf[i], "hid", 3);
+ i += 3;
+ alloc_buf[i++] = '\"';
+ alloc_buf[i++] = ':';
+ alloc_buf[i++] = '\"';
+ memcpy(&alloc_buf[i], tuya_ble_current_para.auth_settings.h_id, H_ID_LEN);
+ i += 19;
+ alloc_buf[i++] = '\"';
+
+ alloc_buf[i++] = ',';
+ alloc_buf[i++] = '\"';
+ memcpy(&alloc_buf[i], "uuid", 4);
+ i += 4;
+ alloc_buf[i++] = '\"';
+ alloc_buf[i++] = ':';
+ alloc_buf[i++] = '\"';
+ memcpy(&alloc_buf[i], tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN);
+ i += DEVICE_ID_LEN;
+ alloc_buf[i++] = '\"';
+
+ alloc_buf[i++] = ',';
+ alloc_buf[i++] = '\"';
+ memcpy(&alloc_buf[i], "mac", 3);
+ i += 3;
+ alloc_buf[i++] = '\"';
+ alloc_buf[i++] = ':';
+ alloc_buf[i++] = '\"';
+
+ memcpy(&alloc_buf[i], tuya_ble_current_para.auth_settings.mac_string, MAC_LEN * 2);
+ i += MAC_LEN * 2;
+ alloc_buf[i++] = '\"';
+
+ alloc_buf[i++] = ',';
+ alloc_buf[i++] = '\"';
+ memcpy(&alloc_buf[i], "firmName", 8);
+ i += 8;
+ alloc_buf[i++] = '\"';
+ alloc_buf[i++] = ':';
+ alloc_buf[i++] = '\"';
+ memcpy(&alloc_buf[i], TUYA_BLE_APP_BUILD_FIRMNAME_STRING, strlen(TUYA_BLE_APP_BUILD_FIRMNAME_STRING));
+ i += strlen(TUYA_BLE_APP_BUILD_FIRMNAME_STRING);
+ alloc_buf[i++] = '\"';
+
+ alloc_buf[i++] = ',';
+ alloc_buf[i++] = '\"';
+ memcpy(&alloc_buf[i], "firmVer", 7);
+ i += 7;
+ alloc_buf[i++] = '\"';
+ alloc_buf[i++] = ':';
+ alloc_buf[i++] = '\"';
+ memcpy(&alloc_buf[i], TUYA_BLE_APP_VERSION_STRING, strlen(TUYA_BLE_APP_VERSION_STRING));
+ i += strlen(TUYA_BLE_APP_VERSION_STRING);
+ alloc_buf[i++] = '\"';
+
+ alloc_buf[i++] = ',';
+ alloc_buf[i++] = '\"';
+ memcpy(&alloc_buf[i], "prod_test", 9);
+ i += 9;
+ alloc_buf[i++] = '\"';
+ alloc_buf[i++] = ':';
+
+ memcpy(&alloc_buf[i], "false", 5);
+ i += 5;
+
+ alloc_buf[i++] = '}';
+
+ alloc_buf[i++] = 0;
+
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_QUERY_INFO, (uint8_t *)alloc_buf, i - 1);
+
+ TUYA_BLE_LOG_DEBUG("AUC_CMD_QUERY_INFO RESPONSE!");
+
+ tuya_ble_free(alloc_buf);
+}
+
+
+static void tuya_ble_auc_reset(uint8_t *para, uint16_t len)
+{
+ uint8_t buf[1] = {0x00};
+
+ if (tuya_ble_production_test_flag != 1) {
+ return;
+ }
+ TUYA_BLE_LOG_DEBUG("auc RESET!");
+
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_RESET, buf, sizeof(buf));
+
+ tuya_ble_device_delay_ms(1000);
+
+ tuya_ble_device_reset();
+
+}
+
+
+static void tuya_ble_auc_write_hid(uint8_t *para, uint16_t len)
+{
+ uint8_t hid[19];
+ char true_buf[] = "{\"ret\":true}";
+ char false_buf[] = "{\"ret\":false}";
+
+ if (tuya_ble_production_test_flag != 1) {
+ return;
+ }
+
+ TUYA_BLE_LOG_DEBUG("AUC WRITE AUTH HID!");
+
+ if (len < 27) {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_HID, (uint8_t *)false_buf, strlen(false_buf));
+ TUYA_BLE_LOG_ERROR("WRITE AUTH HID para length error!");
+ return;
+ }
+
+ if (memcmp(¶[2], "hid", 3) != 0) {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_HID, (uint8_t *)false_buf, strlen(false_buf));
+ TUYA_BLE_LOG_ERROR("WRITE AUTH HID para error!");
+ return;
+ }
+
+ memcpy(hid, ¶[8], H_ID_LEN);
+
+ if (tuya_ble_storage_write_hid(hid, H_ID_LEN) == TUYA_BLE_SUCCESS) {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_HID, (uint8_t *)true_buf, strlen(true_buf));
+ TUYA_BLE_LOG_DEBUG("WRITE AUTH HID successed.");
+ } else {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_HID, (uint8_t *)false_buf, strlen(false_buf));
+ TUYA_BLE_LOG_ERROR("WRITE AUTH HID failed.");
+ }
+
+
+
+}
+
+
+static void tuya_ble_auc_query_fingerprint(uint8_t *para, uint16_t len)
+{
+ int32_t length = 0;
+ uint8_t *alloc_buf = NULL;
+
+ if (tuya_ble_production_test_flag != 1) {
+ return;
+ }
+
+ TUYA_BLE_LOG_DEBUG("AUC QUERY FINGERPRINT!");
+
+ alloc_buf = (uint8_t *)tuya_ble_malloc(256);
+
+ if (alloc_buf) {
+ memset(alloc_buf, 0, 256);
+ } else {
+ TUYA_BLE_LOG_ERROR("AUC QUERY INFO alloc buf malloc failed.");
+ return;
+ }
+
+ length = sprintf((char *)alloc_buf, "{\"ret\":true,\"firmName\":\"%s\",\"firmVer\":\"%s\"}", TUYA_BLE_APP_BUILD_FIRMNAME_STRING, TUYA_BLE_APP_VERSION_STRING);
+
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_QUERY_FINGERPRINT, alloc_buf, length);
+
+ tuya_ble_free(alloc_buf);
+
+ TUYA_BLE_LOG_DEBUG("AUC_CMD_QUERY_FINGERPRINT responsed.");
+
+}
+
+
+
+
+static void tuya_ble_auc_rssi_test(uint8_t *para, uint16_t len)
+{
+ uint8_t length = 0;
+ int8_t rssi = 0;
+ static const char false_buf[] = "{\"ret\":false}";
+ char true_buf[30];
+
+ if (tuya_ble_production_test_flag != 1) {
+ return;
+ }
+
+ TUYA_BLE_LOG_DEBUG("AUC RSSI TEST!");
+
+ memset(true_buf, 0, sizeof(true_buf));
+
+ tuya_ble_prod_beacon_scan_stop();
+
+ if (tuya_ble_prod_beacon_get_rssi_avg(&rssi) != TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_ERROR("auc get rssi failed.");
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_RSSI_TEST, (uint8_t *)false_buf, strlen(false_buf));
+ } else {
+ length = sprintf((char *)true_buf, "{\"ret\":true,\"rssi\":\"%d\"}", rssi);
+ TUYA_BLE_LOG_DEBUG("auc get rssi = %d", rssi);
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_RSSI_TEST, (uint8_t *)true_buf, length);
+ }
+}
+
+
+static void tuya_ble_auc_read_mac(uint8_t *para, uint16_t len)
+{
+ (void)(para);
+ (void)(len);
+
+ int32_t length = 0;
+ uint8_t buf[64];
+ uint8_t mac_addr_str[12 + 1];
+
+ if (tuya_ble_production_test_flag != 1) {
+ return;
+ }
+
+ TUYA_BLE_LOG_DEBUG("AUC READ MAC ADDR!");
+
+ // MAC string format: DC 23 xx xx xx xx
+ memcpy(mac_addr_str, tuya_ble_current_para.auth_settings.mac_string, MAC_LEN * 2);
+ mac_addr_str[12] = '\0';
+
+ int swap_len = MAC_LEN * 2;
+ char temp[2];
+
+ for (int i = 0; i < swap_len / 2; i += 2) {
+ temp[0] = mac_addr_str[i];
+ temp[1] = mac_addr_str[i + 1];
+
+ mac_addr_str[i] = mac_addr_str[swap_len - 2 - i];
+ mac_addr_str[i + 1] = mac_addr_str[swap_len - 1 - i];
+
+ mac_addr_str[swap_len - 2 - i] = temp[0];
+ mac_addr_str[swap_len - 1 - i] = temp[1];
+ }
+
+ length = sprintf((void *)buf, "{\"ret\":true,\"mac\":\"%s\"}", mac_addr_str);
+
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_READ_MAC, buf, length);
+
+ TUYA_BLE_LOG_DEBUG("AUC_CMD_READ_MAC responsed.");
+}
+
+
+static void tuya_ble_auc_exit(uint8_t *para, uint16_t len)
+{
+ (void)(para);
+ (void)(len);
+
+ if (tuya_ble_production_test_flag != 1) {
+ return;
+ }
+
+ TUYA_BLE_LOG_DEBUG("AUC EXIT!");
+
+ char buf[] = "{\"ret\":true}";
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_EXIT, (uint8_t *)buf, strlen(buf));
+
+ tuya_ble_device_delay_ms(1000);
+ tuya_ble_device_reset();
+}
+
+
+#if ( TUYA_BLE_PROD_SUPPORT_OEM_TYPE == TUYA_BLE_PROD_OEM_TYPE_0_5 )
+
+typedef struct {
+ bool need_subpkg; /**< whether need subpkg received. */
+
+ uint8_t file_type; /**< file type. 0x09-OEM file 0x10-homekit atoken. */
+ uint32_t total_nums; /**< subpkg total numbers. */
+ uint32_t file_crc32; /**< file crc32 value. */
+ uint32_t rcv_file_len; /**< currently received file length. */
+ uint8_t *p_file_data; /**< the point of received file data. */
+} write_subpkg_info_t;
+
+static write_subpkg_info_t write_subpkg_info = {
+ .need_subpkg = false,
+
+ .file_type = 0,
+ .total_nums = 0,
+ .file_crc32 = 0,
+ .rcv_file_len = 0,
+ .p_file_data = NULL,
+};
+
+
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_prod_storage_oem_info(uint8_t *para, uint16_t len)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+
+static void tuya_ble_auc_write_oem_info(uint8_t *para, uint16_t len)
+{
+ char true_buf[] = "{\"ret\":true}";
+ char false_buf[] = "{\"ret\":false}";
+
+ if (tuya_ble_production_test_flag != 1) {
+ return;
+ }
+
+ TUYA_BLE_LOG_DEBUG("AUC WRITE OEM INFO!");
+
+ if (len == 0) {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_OEM_INFO, (uint8_t *)false_buf, strlen(false_buf));
+ TUYA_BLE_LOG_ERROR("WRITE OEM INFO para length error!");
+ return;
+ }
+
+ if ((write_subpkg_info.need_subpkg == false) && (write_subpkg_info.total_nums == 0)) { // need not subpkg
+ if (para[0] != '{' || para[len - 1] != '}') {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_OEM_INFO, (uint8_t *)false_buf, strlen(false_buf));
+ TUYA_BLE_LOG_ERROR("WRITE OEM INFO failed.");
+ return;
+ }
+
+ if (tuya_ble_prod_storage_oem_info(para, len) == TUYA_BLE_SUCCESS) {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_OEM_INFO, (uint8_t *)true_buf, strlen(true_buf));
+ TUYA_BLE_LOG_DEBUG("WRITE OEM INFO successed.");
+ } else {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_OEM_INFO, (uint8_t *)false_buf, strlen(false_buf));
+ TUYA_BLE_LOG_ERROR("WRITE OEM INFO failed.");
+ }
+ } else {
+ uint16_t cur_subpkg = (para[0] << 8) + para[1];
+ if (cur_subpkg < write_subpkg_info.total_nums) {
+ memcpy(write_subpkg_info.p_file_data + write_subpkg_info.rcv_file_len, para + 2, len - 2);
+ write_subpkg_info.rcv_file_len += len - 2;
+
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_OEM_INFO, (uint8_t *)true_buf, strlen(true_buf));
+ TUYA_BLE_LOG_DEBUG("WRITE OEM INFO subpkg successed.");
+ } else {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_OEM_INFO, (uint8_t *)false_buf, strlen(false_buf));
+ TUYA_BLE_LOG_ERROR("WRITE OEM INFO subpkg failed.");
+ }
+ }
+}
+
+
+static void tuya_ble_auc_write_subpkg_start(uint8_t *para, uint16_t len)
+{
+ char true_buf[] = "{\"ret\":true}";
+ char false_buf[] = "{\"ret\":false}";
+
+ uint8_t cmd;
+ int packageNum, crc32;
+ uint8_t symbol_colon_index[8] = {0};
+ uint8_t symbol_comma_index[8] = {0};
+ uint8_t symbol_colon_cnt, symbol_comma_cnt;
+ uint16_t start_pos, end_pos, cut_len;
+
+ symbol_colon_cnt = tuya_ble_search_symbol_index((char *)para, len, ':', symbol_colon_index);
+ symbol_comma_cnt = tuya_ble_search_symbol_index((char *)para, len, ',', symbol_comma_index);
+
+ /* check json filed */
+ if ((symbol_colon_cnt == 0 || symbol_comma_cnt == 0) || \
+ (memcmp(¶[2], "cmd", strlen("cmd")) != 0) || \
+ (memcmp(¶[symbol_comma_index[0] + 2], "packageNum", strlen("packageNum")) != 0) || \
+ (memcmp(¶[symbol_comma_index[1] + 2], "crc32", strlen("crc32")) != 0)) {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_SUBPKG_START, (uint8_t *)false_buf, strlen(false_buf));
+ TUYA_BLE_LOG_ERROR("AUC WRITE SUBPKG START format err failed.");
+ return;
+ }
+
+ /* cmd */
+ start_pos = symbol_colon_index[0] + 2;
+ end_pos = symbol_comma_index[0] - 2;
+ cut_len = (end_pos - start_pos + 1);
+ tuya_ble_hexstr2hex((uint8_t *)¶[start_pos], cut_len, &cmd);
+ TUYA_BLE_LOG_DEBUG("parse cmd ->[0x%02x]", cmd);
+
+ /* packageNum */
+ start_pos = symbol_colon_index[1] + 1;
+ end_pos = symbol_comma_index[1] - 1;
+ cut_len = (end_pos - start_pos + 1);
+ packageNum = tuya_ble_ascii_to_int((char *)¶[start_pos], cut_len);
+ TUYA_BLE_LOG_DEBUG("parse packageNum ->[%d]", packageNum);
+
+ /* crc32 */
+ start_pos = symbol_colon_index[2] + 1;
+ end_pos = len - 2;
+ cut_len = (end_pos - start_pos + 1);
+ crc32 = tuya_ble_ascii_to_int((char *)¶[start_pos], cut_len);
+ TUYA_BLE_LOG_DEBUG("parse crc32 ->[%d]", crc32);
+
+ write_subpkg_info.need_subpkg = true;
+ write_subpkg_info.file_type = cmd; //!< "09"-oem ocnfig data "10"-homekit atoken data. format: hexstring
+ write_subpkg_info.total_nums = packageNum;
+ write_subpkg_info.file_crc32 = crc32;
+
+ write_subpkg_info.p_file_data = (uint8_t *)tuya_ble_malloc(240 * write_subpkg_info.total_nums);
+ if (write_subpkg_info.p_file_data == NULL) {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_SUBPKG_START, (uint8_t *)false_buf, strlen(false_buf));
+ TUYA_BLE_LOG_ERROR("AUC WRITE SUBPKG START alloc buf malloc failed.");
+ return;
+ }
+
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_SUBPKG_START, (uint8_t *)true_buf, strlen(true_buf));
+ TUYA_BLE_LOG_DEBUG("AUC WRITE SUBPKG START successed.");
+}
+
+
+static void tuya_ble_auc_write_subpkg_end(uint8_t *para, uint16_t len)
+{
+ char true_buf[] = "{\"ret\":true}";
+ char false_buf[] = "{\"ret\":false}";
+ uint32_t calc_crc32;
+
+ /* check received file whether correct */
+ calc_crc32 = tuya_ble_crc32_compute(write_subpkg_info.p_file_data, write_subpkg_info.rcv_file_len, NULL);
+ if (calc_crc32 != write_subpkg_info.file_crc32) {
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_SUBPKG_END, (uint8_t *)false_buf, strlen(false_buf));
+ TUYA_BLE_LOG_DEBUG("AUC WRITE SUBPKG END crc32 check failed.");
+ } else {
+ if (write_subpkg_info.file_type == 0x09) {
+ /* oem config data */
+ tuya_ble_prod_storage_oem_info(write_subpkg_info.p_file_data, write_subpkg_info.rcv_file_len);
+ } else if (write_subpkg_info.file_type == 0x10) {
+ /* homekit atoken data */
+ // TODO ..
+ }
+
+ tuya_ble_uart_prod_send(TUYA_BLE_AUC_CMD_WRITE_SUBPKG_END, (uint8_t *)true_buf, strlen(true_buf));
+ TUYA_BLE_LOG_DEBUG("AUC WRITE SUBPKG END successed.");
+ }
+
+ /* Clear progress vars, and free p_file_data*/
+ write_subpkg_info.need_subpkg = false;
+ write_subpkg_info.file_crc32 = 0;
+ write_subpkg_info.total_nums = 0;
+ write_subpkg_info.file_type = 0;
+ write_subpkg_info.rcv_file_len = 0;
+
+ tuya_ble_free(write_subpkg_info.p_file_data);
+}
+#endif
+
+
+
+__TUYA_BLE_WEAK void tuya_ble_custom_app_production_test_process(uint8_t channel, uint8_t *p_in_data, uint16_t in_len)
+{
+ uint16_t sub_cmd = 0;
+ uint8_t *data_buffer = NULL;
+ uint16_t data_len = ((p_in_data[4] << 8) + p_in_data[5]);
+
+ if ((p_in_data[6] != 3) || (data_len < 3)) {
+ return;
+ }
+
+ sub_cmd = (p_in_data[7] << 8) + p_in_data[8];
+ data_len -= 3;
+ if (data_len > 0) {
+ data_buffer = p_in_data + 9;
+ }
+
+ switch (sub_cmd) {
+
+
+ default:
+ break;
+ };
+
+
+}
+
+
+__TUYA_BLE_WEAK void tuya_ble_app_sdk_test_process(uint8_t channel, uint8_t *p_in_data, uint16_t in_len)
+{
+ uint16_t sub_cmd = 0;
+ uint8_t *data_buffer = NULL;
+ uint16_t data_len = ((p_in_data[4] << 8) + p_in_data[5]);
+
+ if ((p_in_data[6] != 3) || (data_len < 3)) {
+ return;
+ }
+
+ sub_cmd = (p_in_data[7] << 8) + p_in_data[8];
+ data_len -= 3;
+ if (data_len > 0) {
+ data_buffer = p_in_data + 9;
+ }
+
+ switch (sub_cmd) {
+
+
+ default:
+ break;
+ };
+
+
+}
+
+
+
+extern void tuya_ble_connect_monitor_timer_stop(void);
+void tuya_ble_app_production_test_process(uint8_t channel, uint8_t *p_in_data, uint16_t in_len)
+{
+ uint8_t cmd = p_in_data[3];
+ uint16_t data_len = (p_in_data[4] << 8) + p_in_data[5];
+ uint8_t *data_buffer = p_in_data + 6;
+ /*
+ if(tuya_ble_current_para.sys_settings.factory_test_flag==0) //
+ {
+ TUYA_BLE_LOG_WARNING("The production interface is closed!");
+ return;
+ }
+ */
+ if ((channel != 0) && (cmd != TUYA_BLE_AUC_CMD_EXTEND)) {
+ TUYA_BLE_LOG_ERROR("The authorization instructions are not supported in non-serial channels!");
+ return;
+ }
+ if ((channel == 1) && (cmd == TUYA_BLE_AUC_CMD_EXTEND)) {
+ if (tuya_ble_production_test_with_ble_flag == 0) {
+ tuya_ble_production_test_with_ble_flag = 1;
+ if (tuya_ble_connect_status_get() != BONDING_CONN) {
+ tuya_ble_connect_monitor_timer_stop();
+ }
+ }
+
+ }
+ switch (cmd) {
+ case TUYA_BLE_AUC_CMD_EXTEND:
+ tuya_ble_custom_app_production_test_process(channel, p_in_data, in_len);
+ break;
+ case TUYA_BLE_SDK_TEST_CMD_EXTEND:
+ tuya_ble_app_sdk_test_process(channel, p_in_data, in_len);
+ break;
+ case TUYA_BLE_AUC_CMD_ENTER:
+ tuya_ble_auc_enter(data_buffer, data_len);
+ break;
+ case TUYA_BLE_AUC_CMD_QUERY_HID:
+ tuya_ble_auc_query_hid(data_buffer, data_len);
+ break;
+ case TUYA_BLE_AUC_CMD_GPIO_TEST:
+ tuya_ble_auc_gpio_test(data_buffer, data_len);
+ break;
+ case TUYA_BLE_AUC_CMD_WRITE_AUTH_INFO:
+ tuya_ble_auc_write_auth_info(data_buffer, data_len);
+ break;
+ case TUYA_BLE_AUC_CMD_QUERY_INFO:
+ tuya_ble_auc_query_info(data_buffer, data_len);
+ break;
+ case TUYA_BLE_AUC_CMD_RESET:
+ tuya_ble_auc_reset(data_buffer, data_len);
+ break;
+ case TUYA_BLE_AUC_CMD_QUERY_FINGERPRINT:
+ tuya_ble_auc_query_fingerprint(data_buffer, data_len);
+ break;
+ case TUYA_BLE_AUC_CMD_WRITE_HID:
+ tuya_ble_auc_write_hid(data_buffer, data_len);
+ break;
+ case TUYA_BLE_AUC_CMD_RSSI_TEST:
+ tuya_ble_auc_rssi_test(data_buffer, data_len);
+ break;
+ case TUYA_BLE_AUC_CMD_READ_MAC:
+ tuya_ble_auc_read_mac(data_buffer, data_len);
+ break;
+
+ case TUYA_BLE_AUC_CMD_EXIT:
+ tuya_ble_auc_exit(data_buffer, data_len);
+ break;
+
+#if ( TUYA_BLE_PROD_SUPPORT_OEM_TYPE == TUYA_BLE_PROD_OEM_TYPE_0_5 )
+ case TUYA_BLE_AUC_CMD_WRITE_OEM_INFO:
+ tuya_ble_auc_write_oem_info(data_buffer, data_len);
+ break;
+ case TUYA_BLE_AUC_CMD_WRITE_SUBPKG_START:
+ tuya_ble_auc_write_subpkg_start(data_buffer, data_len);
+ break;
+ case TUYA_BLE_AUC_CMD_WRITE_SUBPKG_END:
+ tuya_ble_auc_write_subpkg_end(data_buffer, data_len);
+ break;
+#endif
+
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE == TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION)
+ case TUYA_BLE_AUC_CMD_WRITE_COMM_CFG:
+ tuya_ble_auc_write_comm_cfg(data_buffer, data_len);
+ break;
+#endif
+
+ default:
+ break;
+ };
+
+
+}
+
+#else
+
+void tuya_ble_app_production_test_process(uint8_t channel, uint8_t *p_in_data, uint16_t in_len)
+{
+ uint8_t cmd = p_in_data[3];
+ uint16_t data_len = (p_in_data[4] << 8) + p_in_data[5];
+ uint8_t *data_buffer = p_in_data + 6;
+ switch (cmd) {
+ default:
+ break;
+ };
+
+
+}
+
+#endif
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/app/product_test/tuya_ble_app_production_test.h b/apps/common/third_party_profile/tuya_protocol/app/product_test/tuya_ble_app_production_test.h
new file mode 100644
index 0000000..98ff56e
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/app/product_test/tuya_ble_app_production_test.h
@@ -0,0 +1,100 @@
+/**
+ * \file tuya_ble_app_production_test.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#ifndef _TUYA_BLE_APP_PRODUCTION_TEST_H_
+#define _TUYA_BLE_APP_PRODUCTION_TEST_H_
+
+#include
+#include "tuya_ble_internal_config.h"
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TUYA_BLE_AUC_CMD_ENTER 0x00
+#define TUYA_BLE_AUC_CMD_QUERY_HID 0x01
+#define TUYA_BLE_AUC_CMD_GPIO_TEST 0x02
+#define TUYA_BLE_AUC_CMD_WRITE_AUTH_INFO 0x03
+#define TUYA_BLE_AUC_CMD_QUERY_INFO 0x04
+#define TUYA_BLE_AUC_CMD_RESET 0x05
+#define TUYA_BLE_AUC_CMD_QUERY_FINGERPRINT 0x06
+#define TUYA_BLE_AUC_CMD_WRITE_HID 0x07
+#define TUYA_BLE_AUC_CMD_RSSI_TEST 0x08
+#define TUYA_BLE_AUC_CMD_WRITE_OEM_INFO 0x09
+#define TUYA_BLE_AUC_CMD_WRITE_SUBPKG_START 0x0C
+#define TUYA_BLE_AUC_CMD_WRITE_SUBPKG_END 0x0D
+#define TUYA_BLE_AUC_CMD_WRITE_COMM_CFG 0x12 // ADD
+#define TUYA_BLE_AUC_CMD_READ_MAC 0x13
+#define TUYA_BLE_AUC_CMD_EXIT 0x14
+
+#define TUYA_BLE_AUC_CMD_EXTEND 0xF0
+#define TUYA_BLE_SDK_TEST_CMD_EXTEND 0xF2
+
+
+#define TUYA_BLE_AUC_FINGERPRINT_VER 1
+
+#if ( TUYA_BLE_PROD_SUPPORT_OEM_TYPE == TUYA_BLE_PROD_OEM_TYPE_0_5 )
+#define TUYA_BLE_AUC_WRITE_PID 1
+#else
+#define TUYA_BLE_AUC_WRITE_PID 0
+#endif
+
+#define TUYA_BLE_AUC_WRITE_DEV_CERT 1
+
+enum {
+ TUYA_BLE_AUC_FW_FINGERPRINT_POS = 0,
+ TUYA_BLE_AUC_WRITE_PID_POS = 1,
+ TUYA_BLE_AUC_WRITE_DEV_CERT_POS = 5,
+};
+
+
+/*channel: 0-uart ,1 - ble.*/
+void tuya_ble_app_production_test_process(uint8_t channel, uint8_t *p_in_data, uint16_t in_len);
+
+
+#if (TUYA_BLE_DEVICE_REGISTER_FROM_BLE&&TUYA_BLE_DEVICE_AUTH_DATA_STORE)
+
+tuya_ble_status_t tuya_ble_prod_beacon_scan_start(void);
+
+tuya_ble_status_t tuya_ble_prod_beacon_scan_stop(void);
+
+tuya_ble_status_t tuya_ble_prod_beacon_get_rssi_avg(int8_t *rssi);
+
+tuya_ble_status_t tuya_ble_prod_gpio_test(void);
+
+void tuya_ble_internal_production_test_with_ble_flag_clear(void);
+
+uint8_t tuya_ble_internal_production_test_with_ble_flag_get(void);
+
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _TUYA_BLE_APP_PRODUCTION_TEST_H_
+
diff --git a/apps/common/third_party_profile/tuya_protocol/app/uart_common/tuya_ble_app_uart_common_handler.c b/apps/common/third_party_profile/tuya_protocol/app/uart_common/tuya_ble_app_uart_common_handler.c
new file mode 100644
index 0000000..08d1925
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/app/uart_common/tuya_ble_app_uart_common_handler.c
@@ -0,0 +1,813 @@
+/**
+ * \file tuya_ble_app_uart_common_handler.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_heap.h"
+#include "tuya_ble_mem.h"
+#include "tuya_ble_api.h"
+#include "tuya_ble_port.h"
+#include "tuya_ble_main.h"
+#include "tuya_ble_internal_config.h"
+#include "tuya_ble_data_handler.h"
+#include "tuya_ble_mutli_tsf_protocol.h"
+#include "tuya_ble_utils.h"
+#include "tuya_ble_secure.h"
+#include "tuya_ble_main.h"
+#include "tuya_ble_storage.h"
+#include "tuya_ble_app_uart_common_handler.h"
+#include "tuya_ble_log.h"
+
+
+#define TUYA_BLE_OTA_MCU_TEST 0
+
+#define TUYA_BLE_UART_COMMON_MCU_OTA_DATA_LENGTH_MAX 200
+
+#define TUYA_BLE_OTA_MCU_TYPE 1
+
+
+#define TUYA_BLE_UART_COMMON_MCU_OTA_REQUEST 0xEA
+#define TUYA_BLE_UART_COMMON_MCU_OTA_FILE_INFO 0xEB
+#define TUYA_BLE_UART_COMMON_MCU_OTA_FILE_OFFSET 0xEC
+#define TUYA_BLE_UART_COMMON_MCU_OTA_DATA 0xED
+#define TUYA_BLE_UART_COMMON_MCU_OTA_END 0xEE
+
+
+#if (!TUYA_BLE_OTA_MCU_TEST)
+
+
+void tuya_ble_uart_common_mcu_ota_data_from_ble_handler(uint16_t cmd, uint8_t *recv_data, uint32_t recv_len)
+{
+ static uint8_t uart_data_temp[42];
+ uint8_t *uart_data_buffer = NULL;
+ uint8_t uart_data_len = 0;
+
+ if (cmd == FRM_OTA_DATA_REQ) {
+ uart_data_buffer = (uint8_t *)tuya_ble_malloc(recv_len + 7);
+ if (uart_data_buffer == NULL) {
+ TUYA_BLE_LOG_ERROR("uart_data_buffer malloc failed.");
+ return;
+ }
+
+ } else {
+ uart_data_buffer = uart_data_temp;
+ }
+
+ uart_data_buffer[0] = 0x55;
+ uart_data_buffer[1] = 0xAA;
+ uart_data_buffer[2] = 0x00;
+ switch (cmd) {
+ case FRM_OTA_START_REQ:
+ uart_data_buffer[3] = TUYA_BLE_UART_COMMON_MCU_OTA_REQUEST;
+ uart_data_buffer[4] = 0;
+ uart_data_buffer[5] = 2;
+ uart_data_buffer[6] = TUYA_BLE_UART_COMMON_MCU_OTA_DATA_LENGTH_MAX >> 8;
+ uart_data_buffer[7] = (uint8_t)TUYA_BLE_UART_COMMON_MCU_OTA_DATA_LENGTH_MAX;
+ uart_data_len = 8;
+ break;
+ case FRM_OTA_FILE_INFOR_REQ:
+ uart_data_buffer[3] = TUYA_BLE_UART_COMMON_MCU_OTA_FILE_INFO;
+ uart_data_buffer[4] = 0;
+ uart_data_buffer[5] = 35;
+ memcpy(uart_data_buffer + 6, recv_data, 8);
+ uart_data_buffer[14] = recv_data[9];
+ uart_data_buffer[15] = recv_data[10];
+ uart_data_buffer[16] = recv_data[11];
+ memcpy(&uart_data_buffer[17], recv_data + 12, 24);
+ uart_data_len = 41;
+ break;
+ case FRM_OTA_FILE_OFFSET_REQ:
+ uart_data_buffer[3] = TUYA_BLE_UART_COMMON_MCU_OTA_FILE_OFFSET;
+ uart_data_buffer[4] = 0;
+ uart_data_buffer[5] = 4;
+ memcpy(uart_data_buffer + 6, recv_data, 4);
+ uart_data_len = 10;
+ break;
+ case FRM_OTA_DATA_REQ:
+ uart_data_buffer[3] = TUYA_BLE_UART_COMMON_MCU_OTA_DATA;
+ uart_data_buffer[4] = 0;
+ uart_data_buffer[5] = recv_len;
+ memcpy(uart_data_buffer + 6, recv_data, recv_len);
+ uart_data_len = 6 + recv_len;
+ break;
+ case FRM_OTA_END_REQ:
+ uart_data_buffer[3] = TUYA_BLE_UART_COMMON_MCU_OTA_END;
+ uart_data_buffer[4] = 0;
+ uart_data_buffer[5] = 0;
+ uart_data_len = 6;
+ break;
+ default:
+ break;
+ }
+
+ uart_data_buffer[uart_data_len] = tuya_ble_check_sum(uart_data_buffer, uart_data_len);
+
+ tuya_ble_common_uart_send_data(uart_data_buffer, uart_data_len + 1);
+
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("mcu ota uart send data : ", uart_data_buffer, uart_data_len + 1);
+
+ if (cmd == FRM_OTA_DATA_REQ) {
+ tuya_ble_free(uart_data_buffer);
+ }
+
+}
+
+
+
+static void tuya_ble_uart_common_mcu_ota_data_from_uart_handler(uint8_t cmd, uint8_t *data_buffer, uint16_t data_len)
+{
+ static uint8_t ble_data_buffer[30];
+ static uint8_t ble_data_len = 0;
+ uint16_t ble_cmd = 0;
+ tuya_ble_connect_status_t currnet_connect_status;
+
+ memset(ble_data_buffer, 0, sizeof(ble_data_buffer));
+ ble_data_len = 0;
+ switch (cmd) {
+ case TUYA_BLE_UART_COMMON_MCU_OTA_REQUEST:
+ ble_data_buffer[0] = data_buffer[0];
+ ble_data_buffer[1] = 3;
+ ble_data_buffer[2] = TUYA_BLE_OTA_MCU_TYPE;
+ ble_data_buffer[3] = 0;
+ memcpy(&ble_data_buffer[4], data_buffer + 1, 5);
+ ble_data_len = 9;
+ ble_cmd = FRM_OTA_START_RESP;
+ break;
+ case TUYA_BLE_UART_COMMON_MCU_OTA_FILE_INFO:
+ ble_data_buffer[0] = TUYA_BLE_OTA_MCU_TYPE;
+ memcpy(&ble_data_buffer[1], data_buffer, 25);
+ ble_data_len = 26;
+ ble_cmd = FRM_OTA_FILE_INFOR_RESP;
+ break;
+ case TUYA_BLE_UART_COMMON_MCU_OTA_FILE_OFFSET:
+ ble_data_buffer[0] = TUYA_BLE_OTA_MCU_TYPE;
+ memcpy(&ble_data_buffer[1], data_buffer, 4);
+ ble_data_len = 5;
+ ble_cmd = FRM_OTA_FILE_OFFSET_RESP;
+ break;
+ case TUYA_BLE_UART_COMMON_MCU_OTA_DATA:
+ ble_data_buffer[0] = TUYA_BLE_OTA_MCU_TYPE;
+ ble_data_buffer[1] = data_buffer[0];
+ ble_data_len = 2;
+ ble_cmd = FRM_OTA_DATA_RESP;
+ break;
+ case TUYA_BLE_UART_COMMON_MCU_OTA_END:
+ ble_data_buffer[0] = TUYA_BLE_OTA_MCU_TYPE;
+ ble_data_buffer[1] = data_buffer[0];
+ ble_data_len = 2;
+ ble_cmd = FRM_OTA_END_RESP;
+ break;
+ default:
+ break;
+ };
+
+ currnet_connect_status = tuya_ble_connect_status_get();
+
+ if (currnet_connect_status != BONDING_CONN) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_uart_common_mcu_ota_process FAILED.");
+ return;
+ }
+
+ if (ble_data_len > 0) {
+ tuya_ble_commData_send(ble_cmd, 0, ble_data_buffer, ble_data_len, ENCRYPTION_MODE_SESSION_KEY);
+ }
+
+}
+
+
+__TUYA_BLE_WEAK void tuya_ble_custom_app_uart_common_process(uint8_t *p_in_data, uint16_t in_len)
+{
+ uint8_t cmd = p_in_data[3];
+ uint16_t data_len = (p_in_data[4] << 8) + p_in_data[5];
+ uint8_t *data_buffer = p_in_data + 6;
+
+ switch (cmd) {
+
+ default:
+ break;
+ };
+
+}
+
+
+
+void tuya_ble_uart_common_process(uint8_t *p_in_data, uint16_t in_len)
+{
+ uint8_t cmd = p_in_data[3];
+ uint16_t data_len = (p_in_data[4] << 8) + p_in_data[5];
+ uint8_t *data_buffer = p_in_data + 6;
+
+ switch (cmd) {
+ case TUYA_BLE_UART_COMMON_MCU_OTA_REQUEST:
+ case TUYA_BLE_UART_COMMON_MCU_OTA_FILE_INFO:
+ case TUYA_BLE_UART_COMMON_MCU_OTA_FILE_OFFSET:
+ case TUYA_BLE_UART_COMMON_MCU_OTA_DATA:
+ case TUYA_BLE_UART_COMMON_MCU_OTA_END:
+ tuya_ble_uart_common_mcu_ota_data_from_uart_handler(cmd, data_buffer, data_len);
+ break;
+ default:
+ tuya_ble_custom_app_uart_common_process(p_in_data, in_len);
+ break;
+ };
+
+}
+
+
+#else
+
+
+tuya_ble_timer_t tuya_ble_xtimer_heartbeat ;
+
+static uint32_t tuya_ble_heartbeat_timeout_ms = 1000;
+
+static uint8_t heartbeat_uart_buffer[10];
+
+static uint8_t mcu_info_get = 0;
+
+
+static void tuya_ble_common_uart_protocol_send(uint8_t cmd, uint8_t *pdata, uint8_t len)
+{
+ static uint8_t alloc_buf[256];
+
+ uint8_t i = 0;
+ alloc_buf[0 + 1] = 0x55;
+ alloc_buf[1 + 1] = 0xaa;
+ alloc_buf[2 + 1] = 0x00;
+ alloc_buf[3 + 1] = cmd;
+ alloc_buf[4 + 1] = 0;
+ alloc_buf[5 + 1] = len;
+
+ memcpy(alloc_buf + 6 + 1, pdata, len);
+ alloc_buf[7 + len] = tuya_ble_check_sum(alloc_buf + 1, 6 + len);
+
+ tuya_ble_common_uart_send_data(alloc_buf + 1, 7 + len);
+}
+
+
+static void tuya_ble_vtimer_heartbeat_callback(tuya_ble_timer_t timer)
+{
+ heartbeat_uart_buffer[0] = 0x55;
+ heartbeat_uart_buffer[1] = 0xAA;
+ heartbeat_uart_buffer[2] = 0x00;
+ heartbeat_uart_buffer[3] = 0x00;
+ heartbeat_uart_buffer[4] = 0x00;
+ heartbeat_uart_buffer[5] = 0x00;
+ heartbeat_uart_buffer[6] = 0xFF;
+
+ tuya_ble_common_uart_send_data(heartbeat_uart_buffer, 7);
+
+}
+
+
+static void tuya_ble_heartbeat_timer_create(void)
+{
+ if (tuya_ble_timer_create(&tuya_ble_xtimer_heartbeat, tuya_ble_heartbeat_timeout_ms, TUYA_BLE_TIMER_REPEATED, tuya_ble_vtimer_heartbeat_callback) != TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_xtimer_heartbeat creat failed");
+ }
+
+}
+
+
+static void tuya_ble_heartbeat_timer_start(void)
+{
+ if (tuya_ble_timer_start(tuya_ble_xtimer_heartbeat) != TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_xtimer_heartbeat start failed");
+ }
+
+}
+
+static void tuya_ble_heartbeat_timer_restart(uint32_t ms)
+{
+ if (tuya_ble_timer_restart(tuya_ble_xtimer_heartbeat, ms) != TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_xtimer_heartbeat restart failed");
+ }
+
+}
+
+
+static void tuya_ble_heartbeat_timer_stop(void)
+{
+
+ if (tuya_ble_timer_stop(tuya_ble_xtimer_heartbeat) != TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_xtimer_heartbeat stop failed");
+ }
+
+}
+
+
+static void tuya_ble_heartbeat_timer_delete(void)
+{
+
+ if (tuya_ble_timer_delete(tuya_ble_xtimer_heartbeat) != TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_xtimer_heartbeat delete failed");
+ }
+
+}
+
+
+
+
+static void tuya_ble_ota_data_process_test(uint8_t *p_data, uint16_t p_data_len);
+
+void tuya_ble_uart_common_mcu_ota_data_from_ble_handler(uint16_t cmd, uint8_t *recv_data, uint32_t recv_len)
+{
+ static uint8_t uart_data_temp[42];
+ uint8_t uart_cmd = 0xFF;
+ uint8_t *uart_data_buffer = NULL;
+ uint8_t uart_data_len = 0;
+
+ if (cmd == FRM_OTA_DATA_REQ) {
+ uart_data_buffer = (uint8_t *)tuya_ble_malloc(recv_len + 7);
+ if (uart_data_buffer == NULL) {
+ TUYA_BLE_LOG_ERROR("uart_data_buffer malloc failed.\n");
+ return;
+ }
+
+ } else {
+ uart_data_buffer = uart_data_temp;
+ }
+
+ uart_data_buffer[0] = 0x55;
+ uart_data_buffer[1] = 0xAA;
+ uart_data_buffer[2] = 0x00;
+ switch (cmd) {
+ case FRM_OTA_START_REQ:
+ uart_data_buffer[3] = TUYA_BLE_UART_COMMON_MCU_OTA_REQUEST;
+ uart_data_buffer[4] = 0;
+ uart_data_buffer[5] = 2;
+ uart_data_buffer[6] = TUYA_BLE_UART_COMMON_MCU_OTA_DATA_LENGTH_MAX >> 8;
+ uart_data_buffer[7] = (uint8_t)TUYA_BLE_UART_COMMON_MCU_OTA_DATA_LENGTH_MAX;
+ uart_data_len = 8;
+ break;
+ case FRM_OTA_FILE_INFOR_REQ:
+ uart_data_buffer[3] = TUYA_BLE_UART_COMMON_MCU_OTA_FILE_INFO;
+ uart_data_buffer[4] = 0;
+ uart_data_buffer[5] = 35;
+ memcpy(uart_data_buffer + 6, recv_data, 8);
+ uart_data_buffer[14] = recv_data[9];
+ uart_data_buffer[15] = recv_data[10];
+ uart_data_buffer[16] = recv_data[11];
+ memcpy(&uart_data_buffer[17], recv_data + 12, 24);
+ uart_data_len = 41;
+ break;
+ case FRM_OTA_FILE_OFFSET_REQ:
+ uart_data_buffer[3] = TUYA_BLE_UART_COMMON_MCU_OTA_FILE_OFFSET;
+ uart_data_buffer[4] = 0;
+ uart_data_buffer[5] = 4;
+ memcpy(uart_data_buffer + 6, recv_data, 4);
+ uart_data_len = 10;
+ break;
+ case FRM_OTA_DATA_REQ:
+ uart_data_buffer[3] = TUYA_BLE_UART_COMMON_MCU_OTA_DATA;
+ uart_data_buffer[4] = 0;
+ uart_data_buffer[5] = recv_len;
+ memcpy(uart_data_buffer + 6, recv_data, recv_len);
+ uart_data_len = 6 + recv_len;
+ break;
+ case FRM_OTA_END_REQ:
+ uart_data_buffer[3] = TUYA_BLE_UART_COMMON_MCU_OTA_END;
+ uart_data_buffer[4] = 0;
+ uart_data_buffer[5] = 0;
+ uart_data_len = 6;
+ break;
+ default:
+ break;
+ }
+
+ uart_data_buffer[uart_data_len] = tuya_ble_check_sum(uart_data_buffer, uart_data_len);
+
+ tuya_ble_common_uart_send_data(uart_data_buffer, uart_data_len + 1);
+
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("mcu ota uart send data : ", uart_data_buffer, uart_data_len + 1);
+
+ if (cmd == FRM_OTA_DATA_REQ) {
+ tuya_ble_free(uart_data_buffer);
+ }
+
+}
+
+
+
+static void tuya_ble_uart_common_mcu_ota_data_from_uart_handler(uint8_t cmd, uint8_t *data_buffer, uint16_t data_len)
+{
+ static uint8_t ble_data_buffer[30];
+ static uint8_t ble_data_len = 0;
+ uint16_t ble_cmd = 0;
+ tuya_ble_connect_status_t currnet_connect_status;
+
+ memset(ble_data_buffer, 0, sizeof(ble_data_buffer));
+ ble_data_len = 0;
+ switch (cmd) {
+ case TUYA_BLE_UART_COMMON_MCU_OTA_REQUEST:
+ ble_data_buffer[0] = data_buffer[0];
+ ble_data_buffer[1] = 3;
+ ble_data_buffer[2] = TUYA_BLE_OTA_MCU_TYPE;
+ ble_data_buffer[3] = 0;
+ memcpy(&ble_data_buffer[4], data_buffer + 1, 5);
+ ble_data_len = 9;
+ ble_cmd = FRM_OTA_START_RESP;
+ break;
+ case TUYA_BLE_UART_COMMON_MCU_OTA_FILE_INFO:
+ ble_data_buffer[0] = TUYA_BLE_OTA_MCU_TYPE;
+ memcpy(&ble_data_buffer[1], data_buffer, 25);
+ ble_data_len = 26;
+ ble_cmd = FRM_OTA_FILE_INFOR_RESP;
+ break;
+ case TUYA_BLE_UART_COMMON_MCU_OTA_FILE_OFFSET:
+ ble_data_buffer[0] = TUYA_BLE_OTA_MCU_TYPE;
+ memcpy(&ble_data_buffer[1], data_buffer, 4);
+ ble_data_len = 5;
+ ble_cmd = FRM_OTA_FILE_OFFSET_RESP;
+ break;
+ case TUYA_BLE_UART_COMMON_MCU_OTA_DATA:
+ ble_data_buffer[0] = TUYA_BLE_OTA_MCU_TYPE;
+ ble_data_buffer[1] = data_buffer[0];
+ ble_data_len = 2;
+ ble_cmd = FRM_OTA_DATA_RESP;
+ break;
+ case TUYA_BLE_UART_COMMON_MCU_OTA_END:
+ ble_data_buffer[0] = TUYA_BLE_OTA_MCU_TYPE;
+ ble_data_buffer[1] = data_buffer[0];
+ ble_data_len = 2;
+ ble_cmd = FRM_OTA_END_RESP;
+ break;
+ default:
+ break;
+ };
+
+ currnet_connect_status = tuya_ble_connect_status_get();
+
+ if (currnet_connect_status != BONDING_CONN) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_uart_common_mcu_ota_process FAILED.");
+ return;
+ }
+
+ if (ble_data_len > 0) {
+ tuya_ble_commData_send(ble_cmd, 0, ble_data_buffer, ble_data_len, ENCRYPTION_MODE_SESSION_KEY);
+ }
+
+}
+
+
+void tuya_ble_uart_common_send_current_ble_state(void)
+{
+ uint8_t ble_work_state = 0;
+ tuya_ble_connect_status_t ble_state;
+
+ ble_state = tuya_ble_connect_status_get();
+
+ if ((ble_state == UNBONDING_UNCONN) || (ble_state == UNBONDING_UNCONN) || (ble_state == UNBONDING_UNCONN)) {
+ ble_work_state = 1;
+ } else if ((ble_state == BONDING_UNCONN) || (ble_state == BONDING_UNAUTH_CONN)) {
+ ble_work_state = 2;
+ } else if (ble_state == BONDING_CONN) {
+ ble_work_state = 3;
+ } else {
+ ble_work_state = 0;
+ }
+
+ tuya_ble_common_uart_protocol_send(TUYA_BLE_UART_COMMON_REPORT_WORK_STATE_TYPE, (uint8_t *)&ble_work_state, 1);
+
+}
+
+
+void tuya_ble_uart_common_process(uint8_t *p_in_data, uint16_t in_len)
+{
+ uint8_t cmd = p_in_data[3];
+ uint16_t data_len = (p_in_data[4] << 8) + p_in_data[5];
+ uint8_t *data_buffer = p_in_data + 6;
+ uint32_t mcu_firmware_version = 0, mcu_hardware_version = 0;
+ switch (cmd) {
+ case TUYA_BLE_UART_COMMON_HEART_MSG_TYPE:
+ if ((mcu_info_get == 0) || (data_buffer[0] == 0)) {
+ mcu_info_get = 1;
+ tuya_ble_common_uart_protocol_send(TUYA_BLE_UART_COMMON_SEARCH_PID_TYPE, NULL, 0);
+ }
+
+ break;
+
+ case TUYA_BLE_UART_COMMON_SEARCH_PID_TYPE:
+ if (memcmp(tuya_ble_current_para.pid, data_buffer, 8) != 0) {
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("PID change to : ", data_buffer, 16);
+ tuya_ble_device_update_product_id(TUYA_BLE_PRODUCT_ID_TYPE_PID, 8, data_buffer);
+
+ }
+
+ tuya_ble_heartbeat_timer_restart(10000);
+ tuya_ble_common_uart_protocol_send(TUYA_BLE_UART_COMMON_CK_MCU_TYPE, NULL, 0);
+ tuya_ble_common_uart_protocol_send(TUYA_BLE_UART_COMMON_QUERY_MCU_VERSION, NULL, 0);
+
+ break;
+
+ case TUYA_BLE_UART_COMMON_CK_MCU_TYPE:
+
+ tuya_ble_uart_common_send_current_ble_state();
+
+ break;
+
+ case TUYA_BLE_UART_COMMON_QUERY_MCU_VERSION:
+ mcu_firmware_version = (data_buffer[0] << 16) | (data_buffer[1] << 8) | (data_buffer[2]);
+ mcu_hardware_version = (data_buffer[3] << 16) | (data_buffer[4] << 8) | (data_buffer[5]);
+ TUYA_BLE_LOG_DEBUG("reveived mcu_firmware_version : 0x%04x mcu_hardware_version : 0x%04x", mcu_firmware_version, mcu_hardware_version);
+ tuya_ble_device_update_mcu_version(mcu_firmware_version, mcu_hardware_version);
+
+ break;
+
+ case TUYA_BLE_UART_COMMON_MCU_SEND_VERSION:
+ mcu_firmware_version = (data_buffer[0] << 16) | (data_buffer[1] << 8) | (data_buffer[2]);
+ mcu_hardware_version = (data_buffer[3] << 16) | (data_buffer[4] << 8) | (data_buffer[5]);
+ TUYA_BLE_LOG_DEBUG("reveived mcu_firmware_version : 0x%04x mcu_hardware_version : 0x%04x", mcu_firmware_version, mcu_hardware_version);
+ tuya_ble_device_update_mcu_version(mcu_firmware_version, mcu_hardware_version);
+ break;
+
+ case TUYA_BLE_UART_COMMON_REPORT_WORK_STATE_TYPE:
+
+ break;
+ case TUYA_BLE_UART_COMMON_RESET_TYPE:
+
+ break;
+ case TUYA_BLE_UART_COMMON_SEND_CMD_TYPE:
+
+ break;
+ case TUYA_BLE_UART_COMMON_SEND_STATUS_TYPE:
+
+ break;
+ case TUYA_BLE_UART_COMMON_QUERY_STATUS:
+
+ break;
+ case TUYA_BLE_UART_COMMON_SEND_STORAGE_TYPE:
+
+ break;
+ case TUYA_BLE_UART_COMMON_SEND_TIME_SYNC_TYPE:
+
+ break;
+ case TUYA_BLE_UART_COMMON_MODIFY_ADV_INTERVAL:
+
+ break;
+ case TUYA_BLE_UART_COMMON_TURNOFF_SYSTEM_TIME:
+
+ break;
+ case TUYA_BLE_UART_COMMON_ENANBLE_LOWER_POWER:
+
+ break;
+ case TUYA_BLE_UART_COMMON_SEND_ONE_TIME_PASSWORD_TOKEN:
+
+ break;
+ case TUYA_BLE_UART_COMMON_ACTIVE_DISCONNECT:
+
+ break;
+ case TUYA_BLE_UART_COMMON_BLE_OTA_STATUS:
+
+ break;
+
+ case TUYA_BLE_UART_COMMON_MCU_OTA_REQUEST:
+ case TUYA_BLE_UART_COMMON_MCU_OTA_FILE_INFO:
+ case TUYA_BLE_UART_COMMON_MCU_OTA_FILE_OFFSET:
+ case TUYA_BLE_UART_COMMON_MCU_OTA_DATA:
+ case TUYA_BLE_UART_COMMON_MCU_OTA_END:
+ tuya_ble_uart_common_mcu_ota_data_from_uart_handler(cmd, data_buffer, data_len);
+ break;
+ default:
+ break;
+ };
+
+}
+
+static uint8_t mcu_ota_flag = 0;
+
+#define MCU_OTA_MAX_DATA_SIZE 200
+
+#define CURRENT_MCU_FIRMWARE_VERSION 0x010000
+
+#define SUPPORT_MCU_OTA_FILE_MAX_LENGTH 102400
+
+typedef struct {
+ uint32_t file_version;
+ uint8_t file_md5[16];
+ uint32_t file_length;
+ uint32_t file_crc32;
+} mcu_ota_file_info_data_t;
+
+static mcu_ota_file_info_data_t mcu_ota_file_data = {0};
+
+static uint16_t current_package = 0;
+static uint16_t last_package = 0;
+
+static uint32_t current_image_crc_last;
+static uint32_t current_image_write_offset;
+
+static void mcu_ota_current_para_init(void)
+{
+ current_package = 0;
+ last_package = 0;
+ mcu_ota_flag = 0;
+ current_image_crc_last = 0;
+ current_image_write_offset = 0;
+}
+
+void mcu_ota_test_init(void)
+{
+ mcu_ota_current_para_init();
+ tuya_ble_heartbeat_timer_create();
+ tuya_ble_heartbeat_timer_start();
+}
+
+void mcu_ota_test_para_init_connect(void)
+{
+ mcu_ota_current_para_init();
+}
+
+
+static void tuya_ble_ota_data_process_test(uint8_t *p_data, uint16_t p_data_len)
+{
+ uint16_t len = 0;
+ uint16_t crc16_rev, crc16_temp;
+ static uint8_t ota_data_response_buffer[40];
+ uint8_t ota_data_response_len;
+ uint8_t cmd = p_data[3];
+ uint16_t ota_data_len = (p_data[4] << 8) + p_data[5];
+ uint8_t *ota_data_buffer = p_data + 6;
+ memset(ota_data_response_buffer, 0, sizeof(ota_data_response_buffer));
+ ota_data_response_buffer[0] = 0x55;
+ ota_data_response_buffer[1] = 0xaa;
+ ota_data_response_buffer[2] = 0x00;
+ switch (cmd) {
+ case TUYA_BLE_UART_COMMON_MCU_OTA_REQUEST:
+ ota_data_response_buffer[3] = TUYA_BLE_UART_COMMON_MCU_OTA_REQUEST;
+ ota_data_response_buffer[4] = 0;
+ ota_data_response_buffer[5] = 6;
+ if (mcu_ota_flag == 0) {
+ mcu_ota_current_para_init();
+ ota_data_response_buffer[6] = 0;
+ ota_data_response_buffer[7] = ((uint32_t)CURRENT_MCU_FIRMWARE_VERSION >> 16);
+ ota_data_response_buffer[8] = ((uint32_t)CURRENT_MCU_FIRMWARE_VERSION >> 8);
+ ota_data_response_buffer[9] = ((uint32_t)CURRENT_MCU_FIRMWARE_VERSION);
+ ota_data_response_buffer[10] = ((uint16_t)MCU_OTA_MAX_DATA_SIZE >> 8);
+ ota_data_response_buffer[11] = ((uint16_t)MCU_OTA_MAX_DATA_SIZE);
+ mcu_ota_flag = 1;
+ memset(&mcu_ota_file_data, 0, sizeof(mcu_ota_file_data));
+ } else {
+ ota_data_response_buffer[6] = 1;
+ mcu_ota_flag = 0;
+ }
+ ota_data_response_len = 12;
+
+ break;
+
+ case TUYA_BLE_UART_COMMON_MCU_OTA_FILE_INFO:
+ ota_data_response_buffer[3] = TUYA_BLE_UART_COMMON_MCU_OTA_FILE_INFO;
+ ota_data_response_buffer[4] = 0;
+ ota_data_response_buffer[5] = 25;
+ if (mcu_ota_flag != 1) {
+ ota_data_response_buffer[6] = 4;
+ mcu_ota_flag = 0;
+ } else {
+ if (memcmp(ota_data_buffer, tuya_ble_current_para.pid, 8)) {
+ ota_data_response_buffer[6] = 1;
+ mcu_ota_flag = 0;
+ } else {
+ mcu_ota_file_data.file_version = (ota_data_buffer[8] << 16) + (ota_data_buffer[9] << 8) + ota_data_buffer[10];
+ memcpy(mcu_ota_file_data.file_md5, ota_data_buffer + 11, 16);
+ mcu_ota_file_data.file_length = (ota_data_buffer[27] << 24) + (ota_data_buffer[28] << 16) + (ota_data_buffer[29] << 8) + ota_data_buffer[30];
+ mcu_ota_file_data.file_crc32 = (ota_data_buffer[31] << 24) + (ota_data_buffer[32] << 16) + (ota_data_buffer[33] << 8) + ota_data_buffer[34];
+
+ if (mcu_ota_file_data.file_version <= CURRENT_MCU_FIRMWARE_VERSION) {
+ ota_data_response_buffer[6] = 2;
+ mcu_ota_flag = 0;
+ } else if (mcu_ota_file_data.file_length > SUPPORT_MCU_OTA_FILE_MAX_LENGTH) {
+ ota_data_response_buffer[6] = 3;
+ mcu_ota_flag = 0;
+ } else {
+ ota_data_response_buffer[6] = 0;
+ mcu_ota_flag = 2;
+
+ }
+
+
+ }
+ }
+ ota_data_response_len = 31;
+
+ break;
+ case TUYA_BLE_UART_COMMON_MCU_OTA_FILE_OFFSET:
+ ota_data_response_buffer[3] = TUYA_BLE_UART_COMMON_MCU_OTA_FILE_OFFSET;
+ ota_data_response_buffer[4] = 0;
+ ota_data_response_buffer[5] = 4;
+ if (mcu_ota_flag == 2) {
+ memset(&ota_data_response_buffer[6], 0, 4);
+ mcu_ota_flag = 3;
+ ota_data_response_len = 10;
+ } else {
+ mcu_ota_flag = 0;
+ ota_data_response_len = 0;
+ }
+
+ break;
+
+ case TUYA_BLE_UART_COMMON_MCU_OTA_DATA:
+ ota_data_response_buffer[3] = TUYA_BLE_UART_COMMON_MCU_OTA_DATA;
+ ota_data_response_buffer[4] = 0;
+ ota_data_response_buffer[5] = 1;
+
+ if ((mcu_ota_flag == 3) || (mcu_ota_flag == 4)) {
+ current_package = (ota_data_buffer[0] << 8) | ota_data_buffer[1];
+ len = (ota_data_buffer[2] << 8) | ota_data_buffer[3];
+
+ if ((current_package != (last_package + 1)) && (current_package != 0)) {
+ TUYA_BLE_LOG_ERROR("mcu ota received package number error.received package number : %d", current_package);
+ ota_data_response_buffer[6] = 1;
+ } else if ((len > MCU_OTA_MAX_DATA_SIZE) || ((len + 6) != (p_data_len - 7))) {
+ TUYA_BLE_LOG_ERROR("mcu ota received package data length error : len = %d,p_data_len = %d", len, p_data_len);
+ ota_data_response_buffer[6] = 2;
+ } else {
+ crc16_temp = (ota_data_buffer[4] << 8) | ota_data_buffer[5];
+ crc16_rev = tuya_ble_crc16_compute(&ota_data_buffer[6], len, NULL);
+ if (crc16_temp != crc16_rev) {
+ TUYA_BLE_LOG_ERROR("mcu ota received package data crc16 error,crc_16_cal = 0x%04x ; crc16_rev = 0x%04x", crc16_temp, crc16_rev);
+ ota_data_response_buffer[6] = 3;
+ }
+
+ }
+
+
+ if (ota_data_response_buffer[6] == 0) {
+ current_image_crc_last = tuya_ble_crc32_compute(&ota_data_buffer[6], len, ¤t_image_crc_last);
+ current_image_write_offset += len;
+ mcu_ota_flag = 4;
+ last_package = current_package;
+ } else {
+ mcu_ota_flag = 0;
+ mcu_ota_current_para_init();
+ }
+ ota_data_response_len = 7;
+
+ } else {
+ mcu_ota_flag = 0;
+ ota_data_response_len = 0;
+ }
+
+ break;
+
+ case TUYA_BLE_UART_COMMON_MCU_OTA_END:
+ ota_data_response_buffer[3] = TUYA_BLE_UART_COMMON_MCU_OTA_END;
+ ota_data_response_buffer[4] = 0;
+ ota_data_response_buffer[5] = 1;
+ if (mcu_ota_flag != 0) {
+ if (mcu_ota_file_data.file_length != current_image_write_offset) {
+ ota_data_response_buffer[6] = 1;
+ } else if (mcu_ota_file_data.file_crc32 != current_image_crc_last) {
+ ota_data_response_buffer[6] = 2;
+ } else {
+ ota_data_response_buffer[6] = 0;
+ mcu_ota_flag = 0;
+ TUYA_BLE_LOG_DEBUG("mcu ota test succeed.");
+ }
+ ota_data_response_len = 7;
+ } else {
+ mcu_ota_flag = 0;
+ ota_data_response_len = 0;
+ }
+
+
+ break;
+
+ default:
+
+ break;
+ };
+
+ if (ota_data_response_len > 0) {
+ ota_data_response_buffer[ota_data_response_len] = tuya_ble_check_sum(ota_data_response_buffer, ota_data_response_len);
+ ota_data_response_len++;
+ tuya_ble_common_uart_send_full_instruction_received(ota_data_response_buffer, ota_data_response_len);
+ }
+
+}
+
+#endif
+
+
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/app/uart_common/tuya_ble_app_uart_common_handler.h b/apps/common/third_party_profile/tuya_protocol/app/uart_common/tuya_ble_app_uart_common_handler.h
new file mode 100644
index 0000000..c26846e
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/app/uart_common/tuya_ble_app_uart_common_handler.h
@@ -0,0 +1,53 @@
+/**
+ * \file tuya_ble_app_uart_common_handler.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#ifndef _TUYA_BLE_APP_UART_COMMON_HANDLER_H_
+#define _TUYA_BLE_APP_UART_COMMON_HANDLER_H_
+
+#include
+#include "tuya_ble_internal_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @brief Function for transmit ble data from peer devices to tuya sdk.
+ *
+ * @note This function must be called from where the ble data is received.
+ *.
+ * */
+
+void tuya_ble_uart_common_process(uint8_t *p_in_data, uint16_t in_len);
+
+void tuya_ble_uart_common_mcu_ota_data_from_ble_handler(uint16_t cmd, uint8_t *recv_data, uint32_t recv_len);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _TUYA_BLE_APP_UART_COMMON_HANDLER_H_
+
diff --git a/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/aes.c b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/aes.c
new file mode 100644
index 0000000..be039a8
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/aes.c
@@ -0,0 +1,2285 @@
+/*
+ * FIPS-197 compliant AES implementation
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+/*
+ * The AES block cipher was designed by Vincent Rijmen and Joan Daemen.
+ *
+ * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf
+ * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+ */
+
+#include "aes.h"
+
+
+#if defined(MBEDTLS_AES_C)
+
+#include
+
+
+//#include "mbedtls/platform.h"
+//#include "mbedtls/platform_util.h"
+#if defined(MBEDTLS_PADLOCK_C)
+#include "mbedtls/padlock.h"
+#endif
+#if defined(MBEDTLS_AESNI_C)
+#include "mbedtls/aesni.h"
+#endif
+
+#if defined(MBEDTLS_SELF_TEST)
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#define mbedtls_printf //printf
+#endif /* MBEDTLS_PLATFORM_C */
+#endif /* MBEDTLS_SELF_TEST */
+
+#if !defined(MBEDTLS_AES_ALT)
+
+
+/* Internal macros meant to be called only from within the library. */
+#define MBEDTLS_INTERNAL_VALIDATE_RET( cond, ret ) do { } while( 0 )
+#define MBEDTLS_INTERNAL_VALIDATE( cond ) do { } while( 0 )
+
+/* Parameter validation macros based on platform_util.h */
+#define AES_VALIDATE_RET( cond ) \
+ MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_AES_BAD_INPUT_DATA )
+#define AES_VALIDATE( cond ) \
+ MBEDTLS_INTERNAL_VALIDATE( cond )
+
+/*
+ * 32-bit integer manipulation macros (little endian)
+ */
+#ifndef GET_UINT32_LE
+#define GET_UINT32_LE(n,b,i) \
+{ \
+ (n) = ( (uint32_t) (b)[(i) ] ) \
+ | ( (uint32_t) (b)[(i) + 1] << 8 ) \
+ | ( (uint32_t) (b)[(i) + 2] << 16 ) \
+ | ( (uint32_t) (b)[(i) + 3] << 24 ); \
+}
+#endif
+
+#ifndef PUT_UINT32_LE
+#define PUT_UINT32_LE(n,b,i) \
+{ \
+ (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \
+ (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \
+ (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \
+ (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \
+}
+#endif
+
+#if defined(MBEDTLS_PADLOCK_C) && \
+ ( defined(MBEDTLS_HAVE_X86) || defined(MBEDTLS_PADLOCK_ALIGN16) )
+static int aes_padlock_ace = -1;
+#endif
+
+#if defined(MBEDTLS_AES_ROM_TABLES)
+/*
+ * Forward S-box
+ */
+static const unsigned char FSb[256] = {
+ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5,
+ 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
+ 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
+ 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
+ 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
+ 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
+ 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A,
+ 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
+ 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
+ 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
+ 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B,
+ 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
+ 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85,
+ 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
+ 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
+ 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
+ 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17,
+ 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
+ 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88,
+ 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
+ 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
+ 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
+ 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9,
+ 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
+ 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
+ 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
+ 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
+ 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
+ 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94,
+ 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
+ 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68,
+ 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
+};
+
+/*
+ * Forward tables
+ */
+#define FT \
+\
+ V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \
+ V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \
+ V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \
+ V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \
+ V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \
+ V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \
+ V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \
+ V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \
+ V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \
+ V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \
+ V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \
+ V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \
+ V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \
+ V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \
+ V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \
+ V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \
+ V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \
+ V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \
+ V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \
+ V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \
+ V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \
+ V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \
+ V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \
+ V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \
+ V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \
+ V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \
+ V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \
+ V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \
+ V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \
+ V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \
+ V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \
+ V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \
+ V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \
+ V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \
+ V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \
+ V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \
+ V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \
+ V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \
+ V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \
+ V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \
+ V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \
+ V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \
+ V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \
+ V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \
+ V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \
+ V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \
+ V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \
+ V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \
+ V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \
+ V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \
+ V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \
+ V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \
+ V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \
+ V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \
+ V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \
+ V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \
+ V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \
+ V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \
+ V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \
+ V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \
+ V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \
+ V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \
+ V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \
+ V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C)
+
+#define V(a,b,c,d) 0x##a##b##c##d
+static const uint32_t FT0[256] = { FT };
+#undef V
+
+#if !defined(MBEDTLS_AES_FEWER_TABLES)
+
+#define V(a,b,c,d) 0x##b##c##d##a
+static const uint32_t FT1[256] = { FT };
+#undef V
+
+#define V(a,b,c,d) 0x##c##d##a##b
+static const uint32_t FT2[256] = { FT };
+#undef V
+
+#define V(a,b,c,d) 0x##d##a##b##c
+static const uint32_t FT3[256] = { FT };
+#undef V
+
+#endif /* !MBEDTLS_AES_FEWER_TABLES */
+
+#undef FT
+
+/*
+ * Reverse S-box
+ */
+static const unsigned char RSb[256] = {
+ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38,
+ 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
+ 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,
+ 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
+ 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D,
+ 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
+ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2,
+ 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
+ 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,
+ 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
+ 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA,
+ 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
+ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A,
+ 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
+ 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,
+ 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
+ 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA,
+ 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
+ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85,
+ 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
+ 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,
+ 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
+ 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20,
+ 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
+ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31,
+ 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
+ 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,
+ 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
+ 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0,
+ 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26,
+ 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
+};
+
+/*
+ * Reverse tables
+ */
+#define RT \
+\
+ V(50,A7,F4,51), V(53,65,41,7E), V(C3,A4,17,1A), V(96,5E,27,3A), \
+ V(CB,6B,AB,3B), V(F1,45,9D,1F), V(AB,58,FA,AC), V(93,03,E3,4B), \
+ V(55,FA,30,20), V(F6,6D,76,AD), V(91,76,CC,88), V(25,4C,02,F5), \
+ V(FC,D7,E5,4F), V(D7,CB,2A,C5), V(80,44,35,26), V(8F,A3,62,B5), \
+ V(49,5A,B1,DE), V(67,1B,BA,25), V(98,0E,EA,45), V(E1,C0,FE,5D), \
+ V(02,75,2F,C3), V(12,F0,4C,81), V(A3,97,46,8D), V(C6,F9,D3,6B), \
+ V(E7,5F,8F,03), V(95,9C,92,15), V(EB,7A,6D,BF), V(DA,59,52,95), \
+ V(2D,83,BE,D4), V(D3,21,74,58), V(29,69,E0,49), V(44,C8,C9,8E), \
+ V(6A,89,C2,75), V(78,79,8E,F4), V(6B,3E,58,99), V(DD,71,B9,27), \
+ V(B6,4F,E1,BE), V(17,AD,88,F0), V(66,AC,20,C9), V(B4,3A,CE,7D), \
+ V(18,4A,DF,63), V(82,31,1A,E5), V(60,33,51,97), V(45,7F,53,62), \
+ V(E0,77,64,B1), V(84,AE,6B,BB), V(1C,A0,81,FE), V(94,2B,08,F9), \
+ V(58,68,48,70), V(19,FD,45,8F), V(87,6C,DE,94), V(B7,F8,7B,52), \
+ V(23,D3,73,AB), V(E2,02,4B,72), V(57,8F,1F,E3), V(2A,AB,55,66), \
+ V(07,28,EB,B2), V(03,C2,B5,2F), V(9A,7B,C5,86), V(A5,08,37,D3), \
+ V(F2,87,28,30), V(B2,A5,BF,23), V(BA,6A,03,02), V(5C,82,16,ED), \
+ V(2B,1C,CF,8A), V(92,B4,79,A7), V(F0,F2,07,F3), V(A1,E2,69,4E), \
+ V(CD,F4,DA,65), V(D5,BE,05,06), V(1F,62,34,D1), V(8A,FE,A6,C4), \
+ V(9D,53,2E,34), V(A0,55,F3,A2), V(32,E1,8A,05), V(75,EB,F6,A4), \
+ V(39,EC,83,0B), V(AA,EF,60,40), V(06,9F,71,5E), V(51,10,6E,BD), \
+ V(F9,8A,21,3E), V(3D,06,DD,96), V(AE,05,3E,DD), V(46,BD,E6,4D), \
+ V(B5,8D,54,91), V(05,5D,C4,71), V(6F,D4,06,04), V(FF,15,50,60), \
+ V(24,FB,98,19), V(97,E9,BD,D6), V(CC,43,40,89), V(77,9E,D9,67), \
+ V(BD,42,E8,B0), V(88,8B,89,07), V(38,5B,19,E7), V(DB,EE,C8,79), \
+ V(47,0A,7C,A1), V(E9,0F,42,7C), V(C9,1E,84,F8), V(00,00,00,00), \
+ V(83,86,80,09), V(48,ED,2B,32), V(AC,70,11,1E), V(4E,72,5A,6C), \
+ V(FB,FF,0E,FD), V(56,38,85,0F), V(1E,D5,AE,3D), V(27,39,2D,36), \
+ V(64,D9,0F,0A), V(21,A6,5C,68), V(D1,54,5B,9B), V(3A,2E,36,24), \
+ V(B1,67,0A,0C), V(0F,E7,57,93), V(D2,96,EE,B4), V(9E,91,9B,1B), \
+ V(4F,C5,C0,80), V(A2,20,DC,61), V(69,4B,77,5A), V(16,1A,12,1C), \
+ V(0A,BA,93,E2), V(E5,2A,A0,C0), V(43,E0,22,3C), V(1D,17,1B,12), \
+ V(0B,0D,09,0E), V(AD,C7,8B,F2), V(B9,A8,B6,2D), V(C8,A9,1E,14), \
+ V(85,19,F1,57), V(4C,07,75,AF), V(BB,DD,99,EE), V(FD,60,7F,A3), \
+ V(9F,26,01,F7), V(BC,F5,72,5C), V(C5,3B,66,44), V(34,7E,FB,5B), \
+ V(76,29,43,8B), V(DC,C6,23,CB), V(68,FC,ED,B6), V(63,F1,E4,B8), \
+ V(CA,DC,31,D7), V(10,85,63,42), V(40,22,97,13), V(20,11,C6,84), \
+ V(7D,24,4A,85), V(F8,3D,BB,D2), V(11,32,F9,AE), V(6D,A1,29,C7), \
+ V(4B,2F,9E,1D), V(F3,30,B2,DC), V(EC,52,86,0D), V(D0,E3,C1,77), \
+ V(6C,16,B3,2B), V(99,B9,70,A9), V(FA,48,94,11), V(22,64,E9,47), \
+ V(C4,8C,FC,A8), V(1A,3F,F0,A0), V(D8,2C,7D,56), V(EF,90,33,22), \
+ V(C7,4E,49,87), V(C1,D1,38,D9), V(FE,A2,CA,8C), V(36,0B,D4,98), \
+ V(CF,81,F5,A6), V(28,DE,7A,A5), V(26,8E,B7,DA), V(A4,BF,AD,3F), \
+ V(E4,9D,3A,2C), V(0D,92,78,50), V(9B,CC,5F,6A), V(62,46,7E,54), \
+ V(C2,13,8D,F6), V(E8,B8,D8,90), V(5E,F7,39,2E), V(F5,AF,C3,82), \
+ V(BE,80,5D,9F), V(7C,93,D0,69), V(A9,2D,D5,6F), V(B3,12,25,CF), \
+ V(3B,99,AC,C8), V(A7,7D,18,10), V(6E,63,9C,E8), V(7B,BB,3B,DB), \
+ V(09,78,26,CD), V(F4,18,59,6E), V(01,B7,9A,EC), V(A8,9A,4F,83), \
+ V(65,6E,95,E6), V(7E,E6,FF,AA), V(08,CF,BC,21), V(E6,E8,15,EF), \
+ V(D9,9B,E7,BA), V(CE,36,6F,4A), V(D4,09,9F,EA), V(D6,7C,B0,29), \
+ V(AF,B2,A4,31), V(31,23,3F,2A), V(30,94,A5,C6), V(C0,66,A2,35), \
+ V(37,BC,4E,74), V(A6,CA,82,FC), V(B0,D0,90,E0), V(15,D8,A7,33), \
+ V(4A,98,04,F1), V(F7,DA,EC,41), V(0E,50,CD,7F), V(2F,F6,91,17), \
+ V(8D,D6,4D,76), V(4D,B0,EF,43), V(54,4D,AA,CC), V(DF,04,96,E4), \
+ V(E3,B5,D1,9E), V(1B,88,6A,4C), V(B8,1F,2C,C1), V(7F,51,65,46), \
+ V(04,EA,5E,9D), V(5D,35,8C,01), V(73,74,87,FA), V(2E,41,0B,FB), \
+ V(5A,1D,67,B3), V(52,D2,DB,92), V(33,56,10,E9), V(13,47,D6,6D), \
+ V(8C,61,D7,9A), V(7A,0C,A1,37), V(8E,14,F8,59), V(89,3C,13,EB), \
+ V(EE,27,A9,CE), V(35,C9,61,B7), V(ED,E5,1C,E1), V(3C,B1,47,7A), \
+ V(59,DF,D2,9C), V(3F,73,F2,55), V(79,CE,14,18), V(BF,37,C7,73), \
+ V(EA,CD,F7,53), V(5B,AA,FD,5F), V(14,6F,3D,DF), V(86,DB,44,78), \
+ V(81,F3,AF,CA), V(3E,C4,68,B9), V(2C,34,24,38), V(5F,40,A3,C2), \
+ V(72,C3,1D,16), V(0C,25,E2,BC), V(8B,49,3C,28), V(41,95,0D,FF), \
+ V(71,01,A8,39), V(DE,B3,0C,08), V(9C,E4,B4,D8), V(90,C1,56,64), \
+ V(61,84,CB,7B), V(70,B6,32,D5), V(74,5C,6C,48), V(42,57,B8,D0)
+
+#define V(a,b,c,d) 0x##a##b##c##d
+static const uint32_t RT0[256] = { RT };
+#undef V
+
+#if !defined(MBEDTLS_AES_FEWER_TABLES)
+
+#define V(a,b,c,d) 0x##b##c##d##a
+static const uint32_t RT1[256] = { RT };
+#undef V
+
+#define V(a,b,c,d) 0x##c##d##a##b
+static const uint32_t RT2[256] = { RT };
+#undef V
+
+#define V(a,b,c,d) 0x##d##a##b##c
+static const uint32_t RT3[256] = { RT };
+#undef V
+
+#endif /* !MBEDTLS_AES_FEWER_TABLES */
+
+#undef RT
+
+/*
+ * Round constants
+ */
+static const uint32_t RCON[10] = {
+ 0x00000001, 0x00000002, 0x00000004, 0x00000008,
+ 0x00000010, 0x00000020, 0x00000040, 0x00000080,
+ 0x0000001B, 0x00000036
+};
+
+#else /* MBEDTLS_AES_ROM_TABLES */
+
+/*
+ * Forward S-box & tables
+ */
+static unsigned char FSb[256];
+static uint32_t FT0[256];
+#if !defined(MBEDTLS_AES_FEWER_TABLES)
+static uint32_t FT1[256];
+static uint32_t FT2[256];
+static uint32_t FT3[256];
+#endif /* !MBEDTLS_AES_FEWER_TABLES */
+
+/*
+ * Reverse S-box & tables
+ */
+static unsigned char RSb[256];
+static uint32_t RT0[256];
+#if !defined(MBEDTLS_AES_FEWER_TABLES)
+static uint32_t RT1[256];
+static uint32_t RT2[256];
+static uint32_t RT3[256];
+#endif /* !MBEDTLS_AES_FEWER_TABLES */
+
+/*
+ * Round constants
+ */
+static uint32_t RCON[10];
+
+/*
+ * Tables generation code
+ */
+#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 )
+#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) )
+#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 )
+
+static int aes_init_done = 0;
+
+static void aes_gen_tables(void)
+{
+ int i, x, y, z;
+ int pow[256];
+ int log[256];
+
+ /*
+ * compute pow and log tables over GF(2^8)
+ */
+ for (i = 0, x = 1; i < 256; i++) {
+ pow[i] = x;
+ log[x] = i;
+ x = (x ^ XTIME(x)) & 0xFF;
+ }
+
+ /*
+ * calculate the round constants
+ */
+ for (i = 0, x = 1; i < 10; i++) {
+ RCON[i] = (uint32_t) x;
+ x = XTIME(x) & 0xFF;
+ }
+
+ /*
+ * generate the forward and reverse S-boxes
+ */
+ FSb[0x00] = 0x63;
+ RSb[0x63] = 0x00;
+
+ for (i = 1; i < 256; i++) {
+ x = pow[255 - log[i]];
+
+ y = x;
+ y = ((y << 1) | (y >> 7)) & 0xFF;
+ x ^= y;
+ y = ((y << 1) | (y >> 7)) & 0xFF;
+ x ^= y;
+ y = ((y << 1) | (y >> 7)) & 0xFF;
+ x ^= y;
+ y = ((y << 1) | (y >> 7)) & 0xFF;
+ x ^= y ^ 0x63;
+
+ FSb[i] = (unsigned char) x;
+ RSb[x] = (unsigned char) i;
+ }
+
+ /*
+ * generate the forward and reverse tables
+ */
+ for (i = 0; i < 256; i++) {
+ x = FSb[i];
+ y = XTIME(x) & 0xFF;
+ z = (y ^ x) & 0xFF;
+
+ FT0[i] = ((uint32_t) y) ^
+ ((uint32_t) x << 8) ^
+ ((uint32_t) x << 16) ^
+ ((uint32_t) z << 24);
+
+#if !defined(MBEDTLS_AES_FEWER_TABLES)
+ FT1[i] = ROTL8(FT0[i]);
+ FT2[i] = ROTL8(FT1[i]);
+ FT3[i] = ROTL8(FT2[i]);
+#endif /* !MBEDTLS_AES_FEWER_TABLES */
+
+ x = RSb[i];
+
+ RT0[i] = ((uint32_t) MUL(0x0E, x)) ^
+ ((uint32_t) MUL(0x09, x) << 8) ^
+ ((uint32_t) MUL(0x0D, x) << 16) ^
+ ((uint32_t) MUL(0x0B, x) << 24);
+
+#if !defined(MBEDTLS_AES_FEWER_TABLES)
+ RT1[i] = ROTL8(RT0[i]);
+ RT2[i] = ROTL8(RT1[i]);
+ RT3[i] = ROTL8(RT2[i]);
+#endif /* !MBEDTLS_AES_FEWER_TABLES */
+ }
+}
+
+#undef ROTL8
+
+#endif /* MBEDTLS_AES_ROM_TABLES */
+
+#if defined(MBEDTLS_AES_FEWER_TABLES)
+
+#define ROTL8(x) ( (uint32_t)( ( x ) << 8 ) + (uint32_t)( ( x ) >> 24 ) )
+#define ROTL16(x) ( (uint32_t)( ( x ) << 16 ) + (uint32_t)( ( x ) >> 16 ) )
+#define ROTL24(x) ( (uint32_t)( ( x ) << 24 ) + (uint32_t)( ( x ) >> 8 ) )
+
+#define AES_RT0(idx) RT0[idx]
+#define AES_RT1(idx) ROTL8( RT0[idx] )
+#define AES_RT2(idx) ROTL16( RT0[idx] )
+#define AES_RT3(idx) ROTL24( RT0[idx] )
+
+#define AES_FT0(idx) FT0[idx]
+#define AES_FT1(idx) ROTL8( FT0[idx] )
+#define AES_FT2(idx) ROTL16( FT0[idx] )
+#define AES_FT3(idx) ROTL24( FT0[idx] )
+
+#else /* MBEDTLS_AES_FEWER_TABLES */
+
+#define AES_RT0(idx) RT0[idx]
+#define AES_RT1(idx) RT1[idx]
+#define AES_RT2(idx) RT2[idx]
+#define AES_RT3(idx) RT3[idx]
+
+#define AES_FT0(idx) FT0[idx]
+#define AES_FT1(idx) FT1[idx]
+#define AES_FT2(idx) FT2[idx]
+#define AES_FT3(idx) FT3[idx]
+
+#endif /* MBEDTLS_AES_FEWER_TABLES */
+
+static void *(* const volatile memset_func)(void *, int, size_t) = memset;
+
+static void mbedtls_platform_zeroize(void *buf, size_t len)
+{
+ memset_func(buf, 0, len);
+}
+
+void mbedtls_aes_init(mbedtls_aes_context *ctx)
+{
+ AES_VALIDATE(ctx != NULL);
+
+ memset(ctx, 0, sizeof(mbedtls_aes_context));
+}
+
+void mbedtls_aes_free(mbedtls_aes_context *ctx)
+{
+ if (ctx == NULL) {
+ return;
+ }
+
+ mbedtls_platform_zeroize(ctx, sizeof(mbedtls_aes_context));
+}
+
+#if defined(MBEDTLS_CIPHER_MODE_XTS)
+void mbedtls_aes_xts_init(mbedtls_aes_xts_context *ctx)
+{
+ AES_VALIDATE(ctx != NULL);
+
+ mbedtls_aes_init(&ctx->crypt);
+ mbedtls_aes_init(&ctx->tweak);
+}
+
+void mbedtls_aes_xts_free(mbedtls_aes_xts_context *ctx)
+{
+ if (ctx == NULL) {
+ return;
+ }
+
+ mbedtls_aes_free(&ctx->crypt);
+ mbedtls_aes_free(&ctx->tweak);
+}
+#endif /* MBEDTLS_CIPHER_MODE_XTS */
+
+/*
+ * AES key schedule (encryption)
+ */
+#if !defined(MBEDTLS_AES_SETKEY_ENC_ALT)
+int mbedtls_aes_setkey_enc(mbedtls_aes_context *ctx, const unsigned char *key,
+ unsigned int keybits)
+{
+ unsigned int i;
+ uint32_t *RK;
+
+ AES_VALIDATE_RET(ctx != NULL);
+ AES_VALIDATE_RET(key != NULL);
+
+ switch (keybits) {
+ case 128:
+ ctx->nr = 10;
+ break;
+ case 192:
+ ctx->nr = 12;
+ break;
+ case 256:
+ ctx->nr = 14;
+ break;
+ default :
+ return (MBEDTLS_ERR_AES_INVALID_KEY_LENGTH);
+ }
+
+#if !defined(MBEDTLS_AES_ROM_TABLES)
+ if (aes_init_done == 0) {
+ aes_gen_tables();
+ aes_init_done = 1;
+ }
+#endif
+
+#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16)
+ if (aes_padlock_ace == -1) {
+ aes_padlock_ace = mbedtls_padlock_has_support(MBEDTLS_PADLOCK_ACE);
+ }
+
+ if (aes_padlock_ace) {
+ ctx->rk = RK = MBEDTLS_PADLOCK_ALIGN16(ctx->buf);
+ } else
+#endif
+ ctx->rk = RK = ctx->buf;
+
+#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
+ if (mbedtls_aesni_has_support(MBEDTLS_AESNI_AES)) {
+ return (mbedtls_aesni_setkey_enc((unsigned char *) ctx->rk, key, keybits));
+ }
+#endif
+
+ for (i = 0; i < (keybits >> 5); i++) {
+ GET_UINT32_LE(RK[i], key, i << 2);
+ }
+
+ switch (ctx->nr) {
+ case 10:
+
+ for (i = 0; i < 10; i++, RK += 4) {
+ RK[4] = RK[0] ^ RCON[i] ^
+ ((uint32_t) FSb[(RK[3] >> 8) & 0xFF ]) ^
+ ((uint32_t) FSb[(RK[3] >> 16) & 0xFF ] << 8) ^
+ ((uint32_t) FSb[(RK[3] >> 24) & 0xFF ] << 16) ^
+ ((uint32_t) FSb[(RK[3]) & 0xFF ] << 24);
+
+ RK[5] = RK[1] ^ RK[4];
+ RK[6] = RK[2] ^ RK[5];
+ RK[7] = RK[3] ^ RK[6];
+ }
+ break;
+
+ case 12:
+
+ for (i = 0; i < 8; i++, RK += 6) {
+ RK[6] = RK[0] ^ RCON[i] ^
+ ((uint32_t) FSb[(RK[5] >> 8) & 0xFF ]) ^
+ ((uint32_t) FSb[(RK[5] >> 16) & 0xFF ] << 8) ^
+ ((uint32_t) FSb[(RK[5] >> 24) & 0xFF ] << 16) ^
+ ((uint32_t) FSb[(RK[5]) & 0xFF ] << 24);
+
+ RK[7] = RK[1] ^ RK[6];
+ RK[8] = RK[2] ^ RK[7];
+ RK[9] = RK[3] ^ RK[8];
+ RK[10] = RK[4] ^ RK[9];
+ RK[11] = RK[5] ^ RK[10];
+ }
+ break;
+
+ case 14:
+
+ for (i = 0; i < 7; i++, RK += 8) {
+ RK[8] = RK[0] ^ RCON[i] ^
+ ((uint32_t) FSb[(RK[7] >> 8) & 0xFF ]) ^
+ ((uint32_t) FSb[(RK[7] >> 16) & 0xFF ] << 8) ^
+ ((uint32_t) FSb[(RK[7] >> 24) & 0xFF ] << 16) ^
+ ((uint32_t) FSb[(RK[7]) & 0xFF ] << 24);
+
+ RK[9] = RK[1] ^ RK[8];
+ RK[10] = RK[2] ^ RK[9];
+ RK[11] = RK[3] ^ RK[10];
+
+ RK[12] = RK[4] ^
+ ((uint32_t) FSb[(RK[11]) & 0xFF ]) ^
+ ((uint32_t) FSb[(RK[11] >> 8) & 0xFF ] << 8) ^
+ ((uint32_t) FSb[(RK[11] >> 16) & 0xFF ] << 16) ^
+ ((uint32_t) FSb[(RK[11] >> 24) & 0xFF ] << 24);
+
+ RK[13] = RK[5] ^ RK[12];
+ RK[14] = RK[6] ^ RK[13];
+ RK[15] = RK[7] ^ RK[14];
+ }
+ break;
+ }
+
+ return (0);
+}
+#endif /* !MBEDTLS_AES_SETKEY_ENC_ALT */
+
+/*
+ * AES key schedule (decryption)
+ */
+#if !defined(MBEDTLS_AES_SETKEY_DEC_ALT)
+int mbedtls_aes_setkey_dec(mbedtls_aes_context *ctx, const unsigned char *key,
+ unsigned int keybits)
+{
+ int i, j, ret;
+ mbedtls_aes_context cty;
+ uint32_t *RK;
+ uint32_t *SK;
+
+ AES_VALIDATE_RET(ctx != NULL);
+ AES_VALIDATE_RET(key != NULL);
+
+ mbedtls_aes_init(&cty);
+
+#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16)
+ if (aes_padlock_ace == -1) {
+ aes_padlock_ace = mbedtls_padlock_has_support(MBEDTLS_PADLOCK_ACE);
+ }
+
+ if (aes_padlock_ace) {
+ ctx->rk = RK = MBEDTLS_PADLOCK_ALIGN16(ctx->buf);
+ } else
+#endif
+ ctx->rk = RK = ctx->buf;
+
+ /* Also checks keybits */
+ if ((ret = mbedtls_aes_setkey_enc(&cty, key, keybits)) != 0) {
+ goto exit;
+ }
+
+ ctx->nr = cty.nr;
+
+#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
+ if (mbedtls_aesni_has_support(MBEDTLS_AESNI_AES)) {
+ mbedtls_aesni_inverse_key((unsigned char *) ctx->rk,
+ (const unsigned char *) cty.rk, ctx->nr);
+ goto exit;
+ }
+#endif
+
+ SK = cty.rk + cty.nr * 4;
+
+ *RK++ = *SK++;
+ *RK++ = *SK++;
+ *RK++ = *SK++;
+ *RK++ = *SK++;
+
+ for (i = ctx->nr - 1, SK -= 8; i > 0; i--, SK -= 8) {
+ for (j = 0; j < 4; j++, SK++) {
+ *RK++ = AES_RT0(FSb[(*SK) & 0xFF ]) ^
+ AES_RT1(FSb[(*SK >> 8) & 0xFF ]) ^
+ AES_RT2(FSb[(*SK >> 16) & 0xFF ]) ^
+ AES_RT3(FSb[(*SK >> 24) & 0xFF ]);
+ }
+ }
+
+ *RK++ = *SK++;
+ *RK++ = *SK++;
+ *RK++ = *SK++;
+ *RK++ = *SK++;
+
+exit:
+ mbedtls_aes_free(&cty);
+
+ return (ret);
+}
+
+#if defined(MBEDTLS_CIPHER_MODE_XTS)
+static int mbedtls_aes_xts_decode_keys(const unsigned char *key,
+ unsigned int keybits,
+ const unsigned char **key1,
+ unsigned int *key1bits,
+ const unsigned char **key2,
+ unsigned int *key2bits)
+{
+ const unsigned int half_keybits = keybits / 2;
+ const unsigned int half_keybytes = half_keybits / 8;
+
+ switch (keybits) {
+ case 256:
+ break;
+ case 512:
+ break;
+ default :
+ return (MBEDTLS_ERR_AES_INVALID_KEY_LENGTH);
+ }
+
+ *key1bits = half_keybits;
+ *key2bits = half_keybits;
+ *key1 = &key[0];
+ *key2 = &key[half_keybytes];
+
+ return 0;
+}
+
+int mbedtls_aes_xts_setkey_enc(mbedtls_aes_xts_context *ctx,
+ const unsigned char *key,
+ unsigned int keybits)
+{
+ int ret;
+ const unsigned char *key1, *key2;
+ unsigned int key1bits, key2bits;
+
+ AES_VALIDATE_RET(ctx != NULL);
+ AES_VALIDATE_RET(key != NULL);
+
+ ret = mbedtls_aes_xts_decode_keys(key, keybits, &key1, &key1bits,
+ &key2, &key2bits);
+ if (ret != 0) {
+ return (ret);
+ }
+
+ /* Set the tweak key. Always set tweak key for the encryption mode. */
+ ret = mbedtls_aes_setkey_enc(&ctx->tweak, key2, key2bits);
+ if (ret != 0) {
+ return (ret);
+ }
+
+ /* Set crypt key for encryption. */
+ return mbedtls_aes_setkey_enc(&ctx->crypt, key1, key1bits);
+}
+
+int mbedtls_aes_xts_setkey_dec(mbedtls_aes_xts_context *ctx,
+ const unsigned char *key,
+ unsigned int keybits)
+{
+ int ret;
+ const unsigned char *key1, *key2;
+ unsigned int key1bits, key2bits;
+
+ AES_VALIDATE_RET(ctx != NULL);
+ AES_VALIDATE_RET(key != NULL);
+
+ ret = mbedtls_aes_xts_decode_keys(key, keybits, &key1, &key1bits,
+ &key2, &key2bits);
+ if (ret != 0) {
+ return (ret);
+ }
+
+ /* Set the tweak key. Always set tweak key for encryption. */
+ ret = mbedtls_aes_setkey_enc(&ctx->tweak, key2, key2bits);
+ if (ret != 0) {
+ return (ret);
+ }
+
+ /* Set crypt key for decryption. */
+ return mbedtls_aes_setkey_dec(&ctx->crypt, key1, key1bits);
+}
+#endif /* MBEDTLS_CIPHER_MODE_XTS */
+
+#endif /* !MBEDTLS_AES_SETKEY_DEC_ALT */
+
+#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \
+{ \
+ X0 = *RK++ ^ AES_FT0( ( Y0 ) & 0xFF ) ^ \
+ AES_FT1( ( Y1 >> 8 ) & 0xFF ) ^ \
+ AES_FT2( ( Y2 >> 16 ) & 0xFF ) ^ \
+ AES_FT3( ( Y3 >> 24 ) & 0xFF ); \
+ \
+ X1 = *RK++ ^ AES_FT0( ( Y1 ) & 0xFF ) ^ \
+ AES_FT1( ( Y2 >> 8 ) & 0xFF ) ^ \
+ AES_FT2( ( Y3 >> 16 ) & 0xFF ) ^ \
+ AES_FT3( ( Y0 >> 24 ) & 0xFF ); \
+ \
+ X2 = *RK++ ^ AES_FT0( ( Y2 ) & 0xFF ) ^ \
+ AES_FT1( ( Y3 >> 8 ) & 0xFF ) ^ \
+ AES_FT2( ( Y0 >> 16 ) & 0xFF ) ^ \
+ AES_FT3( ( Y1 >> 24 ) & 0xFF ); \
+ \
+ X3 = *RK++ ^ AES_FT0( ( Y3 ) & 0xFF ) ^ \
+ AES_FT1( ( Y0 >> 8 ) & 0xFF ) ^ \
+ AES_FT2( ( Y1 >> 16 ) & 0xFF ) ^ \
+ AES_FT3( ( Y2 >> 24 ) & 0xFF ); \
+}
+
+#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \
+{ \
+ X0 = *RK++ ^ AES_RT0( ( Y0 ) & 0xFF ) ^ \
+ AES_RT1( ( Y3 >> 8 ) & 0xFF ) ^ \
+ AES_RT2( ( Y2 >> 16 ) & 0xFF ) ^ \
+ AES_RT3( ( Y1 >> 24 ) & 0xFF ); \
+ \
+ X1 = *RK++ ^ AES_RT0( ( Y1 ) & 0xFF ) ^ \
+ AES_RT1( ( Y0 >> 8 ) & 0xFF ) ^ \
+ AES_RT2( ( Y3 >> 16 ) & 0xFF ) ^ \
+ AES_RT3( ( Y2 >> 24 ) & 0xFF ); \
+ \
+ X2 = *RK++ ^ AES_RT0( ( Y2 ) & 0xFF ) ^ \
+ AES_RT1( ( Y1 >> 8 ) & 0xFF ) ^ \
+ AES_RT2( ( Y0 >> 16 ) & 0xFF ) ^ \
+ AES_RT3( ( Y3 >> 24 ) & 0xFF ); \
+ \
+ X3 = *RK++ ^ AES_RT0( ( Y3 ) & 0xFF ) ^ \
+ AES_RT1( ( Y2 >> 8 ) & 0xFF ) ^ \
+ AES_RT2( ( Y1 >> 16 ) & 0xFF ) ^ \
+ AES_RT3( ( Y0 >> 24 ) & 0xFF ); \
+}
+
+/*
+ * AES-ECB block encryption
+ */
+#if !defined(MBEDTLS_AES_ENCRYPT_ALT)
+int mbedtls_internal_aes_encrypt(mbedtls_aes_context *ctx,
+ const unsigned char input[16],
+ unsigned char output[16])
+{
+ int i;
+ uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3;
+
+ RK = ctx->rk;
+
+ GET_UINT32_LE(X0, input, 0);
+ X0 ^= *RK++;
+ GET_UINT32_LE(X1, input, 4);
+ X1 ^= *RK++;
+ GET_UINT32_LE(X2, input, 8);
+ X2 ^= *RK++;
+ GET_UINT32_LE(X3, input, 12);
+ X3 ^= *RK++;
+
+ for (i = (ctx->nr >> 1) - 1; i > 0; i--) {
+ AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
+ AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3);
+ }
+
+ AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
+
+ X0 = *RK++ ^ \
+ ((uint32_t) FSb[(Y0) & 0xFF ]) ^
+ ((uint32_t) FSb[(Y1 >> 8) & 0xFF ] << 8) ^
+ ((uint32_t) FSb[(Y2 >> 16) & 0xFF ] << 16) ^
+ ((uint32_t) FSb[(Y3 >> 24) & 0xFF ] << 24);
+
+ X1 = *RK++ ^ \
+ ((uint32_t) FSb[(Y1) & 0xFF ]) ^
+ ((uint32_t) FSb[(Y2 >> 8) & 0xFF ] << 8) ^
+ ((uint32_t) FSb[(Y3 >> 16) & 0xFF ] << 16) ^
+ ((uint32_t) FSb[(Y0 >> 24) & 0xFF ] << 24);
+
+ X2 = *RK++ ^ \
+ ((uint32_t) FSb[(Y2) & 0xFF ]) ^
+ ((uint32_t) FSb[(Y3 >> 8) & 0xFF ] << 8) ^
+ ((uint32_t) FSb[(Y0 >> 16) & 0xFF ] << 16) ^
+ ((uint32_t) FSb[(Y1 >> 24) & 0xFF ] << 24);
+
+ X3 = *RK++ ^ \
+ ((uint32_t) FSb[(Y3) & 0xFF ]) ^
+ ((uint32_t) FSb[(Y0 >> 8) & 0xFF ] << 8) ^
+ ((uint32_t) FSb[(Y1 >> 16) & 0xFF ] << 16) ^
+ ((uint32_t) FSb[(Y2 >> 24) & 0xFF ] << 24);
+
+ PUT_UINT32_LE(X0, output, 0);
+ PUT_UINT32_LE(X1, output, 4);
+ PUT_UINT32_LE(X2, output, 8);
+ PUT_UINT32_LE(X3, output, 12);
+
+ return (0);
+}
+#endif /* !MBEDTLS_AES_ENCRYPT_ALT */
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+void mbedtls_aes_encrypt(mbedtls_aes_context *ctx,
+ const unsigned char input[16],
+ unsigned char output[16])
+{
+ mbedtls_internal_aes_encrypt(ctx, input, output);
+}
+#endif /* !MBEDTLS_DEPRECATED_REMOVED */
+
+/*
+ * AES-ECB block decryption
+ */
+#if !defined(MBEDTLS_AES_DECRYPT_ALT)
+int mbedtls_internal_aes_decrypt(mbedtls_aes_context *ctx,
+ const unsigned char input[16],
+ unsigned char output[16])
+{
+ int i;
+ uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3;
+
+ RK = ctx->rk;
+
+ GET_UINT32_LE(X0, input, 0);
+ X0 ^= *RK++;
+ GET_UINT32_LE(X1, input, 4);
+ X1 ^= *RK++;
+ GET_UINT32_LE(X2, input, 8);
+ X2 ^= *RK++;
+ GET_UINT32_LE(X3, input, 12);
+ X3 ^= *RK++;
+
+ for (i = (ctx->nr >> 1) - 1; i > 0; i--) {
+ AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
+ AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3);
+ }
+
+ AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
+
+ X0 = *RK++ ^ \
+ ((uint32_t) RSb[(Y0) & 0xFF ]) ^
+ ((uint32_t) RSb[(Y3 >> 8) & 0xFF ] << 8) ^
+ ((uint32_t) RSb[(Y2 >> 16) & 0xFF ] << 16) ^
+ ((uint32_t) RSb[(Y1 >> 24) & 0xFF ] << 24);
+
+ X1 = *RK++ ^ \
+ ((uint32_t) RSb[(Y1) & 0xFF ]) ^
+ ((uint32_t) RSb[(Y0 >> 8) & 0xFF ] << 8) ^
+ ((uint32_t) RSb[(Y3 >> 16) & 0xFF ] << 16) ^
+ ((uint32_t) RSb[(Y2 >> 24) & 0xFF ] << 24);
+
+ X2 = *RK++ ^ \
+ ((uint32_t) RSb[(Y2) & 0xFF ]) ^
+ ((uint32_t) RSb[(Y1 >> 8) & 0xFF ] << 8) ^
+ ((uint32_t) RSb[(Y0 >> 16) & 0xFF ] << 16) ^
+ ((uint32_t) RSb[(Y3 >> 24) & 0xFF ] << 24);
+
+ X3 = *RK++ ^ \
+ ((uint32_t) RSb[(Y3) & 0xFF ]) ^
+ ((uint32_t) RSb[(Y2 >> 8) & 0xFF ] << 8) ^
+ ((uint32_t) RSb[(Y1 >> 16) & 0xFF ] << 16) ^
+ ((uint32_t) RSb[(Y0 >> 24) & 0xFF ] << 24);
+
+ PUT_UINT32_LE(X0, output, 0);
+ PUT_UINT32_LE(X1, output, 4);
+ PUT_UINT32_LE(X2, output, 8);
+ PUT_UINT32_LE(X3, output, 12);
+
+ return (0);
+}
+#endif /* !MBEDTLS_AES_DECRYPT_ALT */
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+void mbedtls_aes_decrypt(mbedtls_aes_context *ctx,
+ const unsigned char input[16],
+ unsigned char output[16])
+{
+ mbedtls_internal_aes_decrypt(ctx, input, output);
+}
+#endif /* !MBEDTLS_DEPRECATED_REMOVED */
+
+/*
+ * AES-ECB block encryption/decryption
+ */
+int mbedtls_aes_crypt_ecb(mbedtls_aes_context *ctx,
+ int mode,
+ const unsigned char input[16],
+ unsigned char output[16])
+{
+ AES_VALIDATE_RET(ctx != NULL);
+ AES_VALIDATE_RET(input != NULL);
+ AES_VALIDATE_RET(output != NULL);
+ AES_VALIDATE_RET(mode == MBEDTLS_AES_ENCRYPT ||
+ mode == MBEDTLS_AES_DECRYPT);
+
+#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
+ if (mbedtls_aesni_has_support(MBEDTLS_AESNI_AES)) {
+ return (mbedtls_aesni_crypt_ecb(ctx, mode, input, output));
+ }
+#endif
+
+#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86)
+ if (aes_padlock_ace) {
+ if (mbedtls_padlock_xcryptecb(ctx, mode, input, output) == 0) {
+ return (0);
+ }
+
+ // If padlock data misaligned, we just fall back to
+ // unaccelerated mode
+ //
+ }
+#endif
+
+ if (mode == MBEDTLS_AES_ENCRYPT) {
+ return (mbedtls_internal_aes_encrypt(ctx, input, output));
+ } else {
+ return (mbedtls_internal_aes_decrypt(ctx, input, output));
+ }
+}
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+/*
+ * AES-CBC buffer encryption/decryption
+ */
+int mbedtls_aes_crypt_cbc(mbedtls_aes_context *ctx,
+ int mode,
+ size_t length,
+ unsigned char iv[16],
+ const unsigned char *input,
+ unsigned char *output)
+{
+ int i;
+ unsigned char temp[16];
+
+ AES_VALIDATE_RET(ctx != NULL);
+ AES_VALIDATE_RET(mode == MBEDTLS_AES_ENCRYPT ||
+ mode == MBEDTLS_AES_DECRYPT);
+ AES_VALIDATE_RET(iv != NULL);
+ AES_VALIDATE_RET(input != NULL);
+ AES_VALIDATE_RET(output != NULL);
+
+ if (length % 16) {
+ return (MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH);
+ }
+
+#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86)
+ if (aes_padlock_ace) {
+ if (mbedtls_padlock_xcryptcbc(ctx, mode, length, iv, input, output) == 0) {
+ return (0);
+ }
+
+ // If padlock data misaligned, we just fall back to
+ // unaccelerated mode
+ //
+ }
+#endif
+
+ if (mode == MBEDTLS_AES_DECRYPT) {
+ while (length > 0) {
+ memcpy(temp, input, 16);
+ mbedtls_aes_crypt_ecb(ctx, mode, input, output);
+
+ for (i = 0; i < 16; i++) {
+ output[i] = (unsigned char)(output[i] ^ iv[i]);
+ }
+
+ memcpy(iv, temp, 16);
+
+ input += 16;
+ output += 16;
+ length -= 16;
+ }
+ } else {
+ while (length > 0) {
+ for (i = 0; i < 16; i++) {
+ output[i] = (unsigned char)(input[i] ^ iv[i]);
+ }
+
+ mbedtls_aes_crypt_ecb(ctx, mode, output, output);
+ memcpy(iv, output, 16);
+
+ input += 16;
+ output += 16;
+ length -= 16;
+ }
+ }
+
+ return (0);
+}
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#if defined(MBEDTLS_CIPHER_MODE_XTS)
+
+/* Endianess with 64 bits values */
+#ifndef GET_UINT64_LE
+#define GET_UINT64_LE(n,b,i) \
+{ \
+ (n) = ( (uint64_t) (b)[(i) + 7] << 56 ) \
+ | ( (uint64_t) (b)[(i) + 6] << 48 ) \
+ | ( (uint64_t) (b)[(i) + 5] << 40 ) \
+ | ( (uint64_t) (b)[(i) + 4] << 32 ) \
+ | ( (uint64_t) (b)[(i) + 3] << 24 ) \
+ | ( (uint64_t) (b)[(i) + 2] << 16 ) \
+ | ( (uint64_t) (b)[(i) + 1] << 8 ) \
+ | ( (uint64_t) (b)[(i) ] ); \
+}
+#endif
+
+#ifndef PUT_UINT64_LE
+#define PUT_UINT64_LE(n,b,i) \
+{ \
+ (b)[(i) + 7] = (unsigned char) ( (n) >> 56 ); \
+ (b)[(i) + 6] = (unsigned char) ( (n) >> 48 ); \
+ (b)[(i) + 5] = (unsigned char) ( (n) >> 40 ); \
+ (b)[(i) + 4] = (unsigned char) ( (n) >> 32 ); \
+ (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \
+ (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \
+ (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \
+ (b)[(i) ] = (unsigned char) ( (n) ); \
+}
+#endif
+
+typedef unsigned char mbedtls_be128[16];
+
+/*
+ * GF(2^128) multiplication function
+ *
+ * This function multiplies a field element by x in the polynomial field
+ * representation. It uses 64-bit word operations to gain speed but compensates
+ * for machine endianess and hence works correctly on both big and little
+ * endian machines.
+ */
+static void mbedtls_gf128mul_x_ble(unsigned char r[16],
+ const unsigned char x[16])
+{
+ uint64_t a, b, ra, rb;
+
+ GET_UINT64_LE(a, x, 0);
+ GET_UINT64_LE(b, x, 8);
+
+ ra = (a << 1) ^ 0x0087 >> (8 - ((b >> 63) << 3));
+ rb = (a >> 63) | (b << 1);
+
+ PUT_UINT64_LE(ra, r, 0);
+ PUT_UINT64_LE(rb, r, 8);
+}
+
+/*
+ * AES-XTS buffer encryption/decryption
+ */
+int mbedtls_aes_crypt_xts(mbedtls_aes_xts_context *ctx,
+ int mode,
+ size_t length,
+ const unsigned char data_unit[16],
+ const unsigned char *input,
+ unsigned char *output)
+{
+ int ret;
+ size_t blocks = length / 16;
+ size_t leftover = length % 16;
+ unsigned char tweak[16];
+ unsigned char prev_tweak[16];
+ unsigned char tmp[16];
+
+ AES_VALIDATE_RET(ctx != NULL);
+ AES_VALIDATE_RET(mode == MBEDTLS_AES_ENCRYPT ||
+ mode == MBEDTLS_AES_DECRYPT);
+ AES_VALIDATE_RET(data_unit != NULL);
+ AES_VALIDATE_RET(input != NULL);
+ AES_VALIDATE_RET(output != NULL);
+
+ /* Data units must be at least 16 bytes long. */
+ if (length < 16) {
+ return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH;
+ }
+
+ /* NIST SP 800-38E disallows data units larger than 2**20 blocks. */
+ if (length > (1 << 20) * 16) {
+ return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH;
+ }
+
+ /* Compute the tweak. */
+ ret = mbedtls_aes_crypt_ecb(&ctx->tweak, MBEDTLS_AES_ENCRYPT,
+ data_unit, tweak);
+ if (ret != 0) {
+ return (ret);
+ }
+
+ while (blocks--) {
+ size_t i;
+
+ if (leftover && (mode == MBEDTLS_AES_DECRYPT) && blocks == 0) {
+ /* We are on the last block in a decrypt operation that has
+ * leftover bytes, so we need to use the next tweak for this block,
+ * and this tweak for the lefover bytes. Save the current tweak for
+ * the leftovers and then update the current tweak for use on this,
+ * the last full block. */
+ memcpy(prev_tweak, tweak, sizeof(tweak));
+ mbedtls_gf128mul_x_ble(tweak, tweak);
+ }
+
+ for (i = 0; i < 16; i++) {
+ tmp[i] = input[i] ^ tweak[i];
+ }
+
+ ret = mbedtls_aes_crypt_ecb(&ctx->crypt, mode, tmp, tmp);
+ if (ret != 0) {
+ return (ret);
+ }
+
+ for (i = 0; i < 16; i++) {
+ output[i] = tmp[i] ^ tweak[i];
+ }
+
+ /* Update the tweak for the next block. */
+ mbedtls_gf128mul_x_ble(tweak, tweak);
+
+ output += 16;
+ input += 16;
+ }
+
+ if (leftover) {
+ /* If we are on the leftover bytes in a decrypt operation, we need to
+ * use the previous tweak for these bytes (as saved in prev_tweak). */
+ unsigned char *t = mode == MBEDTLS_AES_DECRYPT ? prev_tweak : tweak;
+
+ /* We are now on the final part of the data unit, which doesn't divide
+ * evenly by 16. It's time for ciphertext stealing. */
+ size_t i;
+ unsigned char *prev_output = output - 16;
+
+ /* Copy ciphertext bytes from the previous block to our output for each
+ * byte of cyphertext we won't steal. At the same time, copy the
+ * remainder of the input for this final round (since the loop bounds
+ * are the same). */
+ for (i = 0; i < leftover; i++) {
+ output[i] = prev_output[i];
+ tmp[i] = input[i] ^ t[i];
+ }
+
+ /* Copy ciphertext bytes from the previous block for input in this
+ * round. */
+ for (; i < 16; i++) {
+ tmp[i] = prev_output[i] ^ t[i];
+ }
+
+ ret = mbedtls_aes_crypt_ecb(&ctx->crypt, mode, tmp, tmp);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Write the result back to the previous block, overriding the previous
+ * output we copied. */
+ for (i = 0; i < 16; i++) {
+ prev_output[i] = tmp[i] ^ t[i];
+ }
+ }
+
+ return (0);
+}
+#endif /* MBEDTLS_CIPHER_MODE_XTS */
+
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+/*
+ * AES-CFB128 buffer encryption/decryption
+ */
+int mbedtls_aes_crypt_cfb128(mbedtls_aes_context *ctx,
+ int mode,
+ size_t length,
+ size_t *iv_off,
+ unsigned char iv[16],
+ const unsigned char *input,
+ unsigned char *output)
+{
+ int c;
+ size_t n;
+
+ AES_VALIDATE_RET(ctx != NULL);
+ AES_VALIDATE_RET(mode == MBEDTLS_AES_ENCRYPT ||
+ mode == MBEDTLS_AES_DECRYPT);
+ AES_VALIDATE_RET(iv_off != NULL);
+ AES_VALIDATE_RET(iv != NULL);
+ AES_VALIDATE_RET(input != NULL);
+ AES_VALIDATE_RET(output != NULL);
+
+ n = *iv_off;
+
+ if (n > 15) {
+ return (MBEDTLS_ERR_AES_BAD_INPUT_DATA);
+ }
+
+ if (mode == MBEDTLS_AES_DECRYPT) {
+ while (length--) {
+ if (n == 0) {
+ mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, iv, iv);
+ }
+
+ c = *input++;
+ *output++ = (unsigned char)(c ^ iv[n]);
+ iv[n] = (unsigned char) c;
+
+ n = (n + 1) & 0x0F;
+ }
+ } else {
+ while (length--) {
+ if (n == 0) {
+ mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, iv, iv);
+ }
+
+ iv[n] = *output++ = (unsigned char)(iv[n] ^ *input++);
+
+ n = (n + 1) & 0x0F;
+ }
+ }
+
+ *iv_off = n;
+
+ return (0);
+}
+
+/*
+ * AES-CFB8 buffer encryption/decryption
+ */
+int mbedtls_aes_crypt_cfb8(mbedtls_aes_context *ctx,
+ int mode,
+ size_t length,
+ unsigned char iv[16],
+ const unsigned char *input,
+ unsigned char *output)
+{
+ unsigned char c;
+ unsigned char ov[17];
+
+ AES_VALIDATE_RET(ctx != NULL);
+ AES_VALIDATE_RET(mode == MBEDTLS_AES_ENCRYPT ||
+ mode == MBEDTLS_AES_DECRYPT);
+ AES_VALIDATE_RET(iv != NULL);
+ AES_VALIDATE_RET(input != NULL);
+ AES_VALIDATE_RET(output != NULL);
+ while (length--) {
+ memcpy(ov, iv, 16);
+ mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, iv, iv);
+
+ if (mode == MBEDTLS_AES_DECRYPT) {
+ ov[16] = *input;
+ }
+
+ c = *output++ = (unsigned char)(iv[0] ^ *input++);
+
+ if (mode == MBEDTLS_AES_ENCRYPT) {
+ ov[16] = c;
+ }
+
+ memcpy(iv, ov + 1, 16);
+ }
+
+ return (0);
+}
+#endif /* MBEDTLS_CIPHER_MODE_CFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_OFB)
+/*
+ * AES-OFB (Output Feedback Mode) buffer encryption/decryption
+ */
+int mbedtls_aes_crypt_ofb(mbedtls_aes_context *ctx,
+ size_t length,
+ size_t *iv_off,
+ unsigned char iv[16],
+ const unsigned char *input,
+ unsigned char *output)
+{
+ int ret = 0;
+ size_t n;
+
+ AES_VALIDATE_RET(ctx != NULL);
+ AES_VALIDATE_RET(iv_off != NULL);
+ AES_VALIDATE_RET(iv != NULL);
+ AES_VALIDATE_RET(input != NULL);
+ AES_VALIDATE_RET(output != NULL);
+
+ n = *iv_off;
+
+ if (n > 15) {
+ return (MBEDTLS_ERR_AES_BAD_INPUT_DATA);
+ }
+
+ while (length--) {
+ if (n == 0) {
+ ret = mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, iv, iv);
+ if (ret != 0) {
+ goto exit;
+ }
+ }
+ *output++ = *input++ ^ iv[n];
+
+ n = (n + 1) & 0x0F;
+ }
+
+ *iv_off = n;
+
+exit:
+ return (ret);
+}
+#endif /* MBEDTLS_CIPHER_MODE_OFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+/*
+ * AES-CTR buffer encryption/decryption
+ */
+int mbedtls_aes_crypt_ctr(mbedtls_aes_context *ctx,
+ size_t length,
+ size_t *nc_off,
+ unsigned char nonce_counter[16],
+ unsigned char stream_block[16],
+ const unsigned char *input,
+ unsigned char *output)
+{
+ int c, i;
+ size_t n;
+
+ AES_VALIDATE_RET(ctx != NULL);
+ AES_VALIDATE_RET(nc_off != NULL);
+ AES_VALIDATE_RET(nonce_counter != NULL);
+ AES_VALIDATE_RET(stream_block != NULL);
+ AES_VALIDATE_RET(input != NULL);
+ AES_VALIDATE_RET(output != NULL);
+
+ n = *nc_off;
+
+ if (n > 0x0F) {
+ return (MBEDTLS_ERR_AES_BAD_INPUT_DATA);
+ }
+
+ while (length--) {
+ if (n == 0) {
+ mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, nonce_counter, stream_block);
+
+ for (i = 16; i > 0; i--)
+ if (++nonce_counter[i - 1] != 0) {
+ break;
+ }
+ }
+ c = *input++;
+ *output++ = (unsigned char)(c ^ stream_block[n]);
+
+ n = (n + 1) & 0x0F;
+ }
+
+ *nc_off = n;
+
+ return (0);
+}
+#endif /* MBEDTLS_CIPHER_MODE_CTR */
+
+#endif /* !MBEDTLS_AES_ALT */
+
+#if (MBEDTLS_AES_SELF_TEST==1)
+/*
+ * AES test vectors from:
+ *
+ * http://csrc.nist.gov/archive/aes/rijndael/rijndael-vals.zip
+ */
+static const unsigned char aes_test_ecb_dec[3][16] = {
+ {
+ 0x44, 0x41, 0x6A, 0xC2, 0xD1, 0xF5, 0x3C, 0x58,
+ 0x33, 0x03, 0x91, 0x7E, 0x6B, 0xE9, 0xEB, 0xE0
+ },
+ {
+ 0x48, 0xE3, 0x1E, 0x9E, 0x25, 0x67, 0x18, 0xF2,
+ 0x92, 0x29, 0x31, 0x9C, 0x19, 0xF1, 0x5B, 0xA4
+ },
+ {
+ 0x05, 0x8C, 0xCF, 0xFD, 0xBB, 0xCB, 0x38, 0x2D,
+ 0x1F, 0x6F, 0x56, 0x58, 0x5D, 0x8A, 0x4A, 0xDE
+ }
+};
+
+static const unsigned char aes_test_ecb_enc[3][16] = {
+ {
+ 0xC3, 0x4C, 0x05, 0x2C, 0xC0, 0xDA, 0x8D, 0x73,
+ 0x45, 0x1A, 0xFE, 0x5F, 0x03, 0xBE, 0x29, 0x7F
+ },
+ {
+ 0xF3, 0xF6, 0x75, 0x2A, 0xE8, 0xD7, 0x83, 0x11,
+ 0x38, 0xF0, 0x41, 0x56, 0x06, 0x31, 0xB1, 0x14
+ },
+ {
+ 0x8B, 0x79, 0xEE, 0xCC, 0x93, 0xA0, 0xEE, 0x5D,
+ 0xFF, 0x30, 0xB4, 0xEA, 0x21, 0x63, 0x6D, 0xA4
+ }
+};
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+static const unsigned char aes_test_cbc_dec[3][16] = {
+ {
+ 0xFA, 0xCA, 0x37, 0xE0, 0xB0, 0xC8, 0x53, 0x73,
+ 0xDF, 0x70, 0x6E, 0x73, 0xF7, 0xC9, 0xAF, 0x86
+ },
+ {
+ 0x5D, 0xF6, 0x78, 0xDD, 0x17, 0xBA, 0x4E, 0x75,
+ 0xB6, 0x17, 0x68, 0xC6, 0xAD, 0xEF, 0x7C, 0x7B
+ },
+ {
+ 0x48, 0x04, 0xE1, 0x81, 0x8F, 0xE6, 0x29, 0x75,
+ 0x19, 0xA3, 0xE8, 0x8C, 0x57, 0x31, 0x04, 0x13
+ }
+};
+
+static const unsigned char aes_test_cbc_enc[3][16] = {
+ {
+ 0x8A, 0x05, 0xFC, 0x5E, 0x09, 0x5A, 0xF4, 0x84,
+ 0x8A, 0x08, 0xD3, 0x28, 0xD3, 0x68, 0x8E, 0x3D
+ },
+ {
+ 0x7B, 0xD9, 0x66, 0xD5, 0x3A, 0xD8, 0xC1, 0xBB,
+ 0x85, 0xD2, 0xAD, 0xFA, 0xE8, 0x7B, 0xB1, 0x04
+ },
+ {
+ 0xFE, 0x3C, 0x53, 0x65, 0x3E, 0x2F, 0x45, 0xB5,
+ 0x6F, 0xCD, 0x88, 0xB2, 0xCC, 0x89, 0x8F, 0xF0
+ }
+};
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+/*
+ * AES-CFB128 test vectors from:
+ *
+ * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
+ */
+static const unsigned char aes_test_cfb128_key[3][32] = {
+ {
+ 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
+ 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
+ },
+ {
+ 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52,
+ 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5,
+ 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B
+ },
+ {
+ 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE,
+ 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81,
+ 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7,
+ 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4
+ }
+};
+
+static const unsigned char aes_test_cfb128_iv[16] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
+};
+
+static const unsigned char aes_test_cfb128_pt[64] = {
+ 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96,
+ 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A,
+ 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C,
+ 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51,
+ 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11,
+ 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF,
+ 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17,
+ 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10
+};
+
+static const unsigned char aes_test_cfb128_ct[3][64] = {
+ {
+ 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20,
+ 0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A,
+ 0xC8, 0xA6, 0x45, 0x37, 0xA0, 0xB3, 0xA9, 0x3F,
+ 0xCD, 0xE3, 0xCD, 0xAD, 0x9F, 0x1C, 0xE5, 0x8B,
+ 0x26, 0x75, 0x1F, 0x67, 0xA3, 0xCB, 0xB1, 0x40,
+ 0xB1, 0x80, 0x8C, 0xF1, 0x87, 0xA4, 0xF4, 0xDF,
+ 0xC0, 0x4B, 0x05, 0x35, 0x7C, 0x5D, 0x1C, 0x0E,
+ 0xEA, 0xC4, 0xC6, 0x6F, 0x9F, 0xF7, 0xF2, 0xE6
+ },
+ {
+ 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB,
+ 0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74,
+ 0x67, 0xCE, 0x7F, 0x7F, 0x81, 0x17, 0x36, 0x21,
+ 0x96, 0x1A, 0x2B, 0x70, 0x17, 0x1D, 0x3D, 0x7A,
+ 0x2E, 0x1E, 0x8A, 0x1D, 0xD5, 0x9B, 0x88, 0xB1,
+ 0xC8, 0xE6, 0x0F, 0xED, 0x1E, 0xFA, 0xC4, 0xC9,
+ 0xC0, 0x5F, 0x9F, 0x9C, 0xA9, 0x83, 0x4F, 0xA0,
+ 0x42, 0xAE, 0x8F, 0xBA, 0x58, 0x4B, 0x09, 0xFF
+ },
+ {
+ 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B,
+ 0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60,
+ 0x39, 0xFF, 0xED, 0x14, 0x3B, 0x28, 0xB1, 0xC8,
+ 0x32, 0x11, 0x3C, 0x63, 0x31, 0xE5, 0x40, 0x7B,
+ 0xDF, 0x10, 0x13, 0x24, 0x15, 0xE5, 0x4B, 0x92,
+ 0xA1, 0x3E, 0xD0, 0xA8, 0x26, 0x7A, 0xE2, 0xF9,
+ 0x75, 0xA3, 0x85, 0x74, 0x1A, 0xB9, 0xCE, 0xF8,
+ 0x20, 0x31, 0x62, 0x3D, 0x55, 0xB1, 0xE4, 0x71
+ }
+};
+#endif /* MBEDTLS_CIPHER_MODE_CFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_OFB)
+/*
+ * AES-OFB test vectors from:
+ *
+ * https://csrc.nist.gov/publications/detail/sp/800-38a/final
+ */
+static const unsigned char aes_test_ofb_key[3][32] = {
+ {
+ 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
+ 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
+ },
+ {
+ 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52,
+ 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5,
+ 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B
+ },
+ {
+ 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE,
+ 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81,
+ 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7,
+ 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4
+ }
+};
+
+static const unsigned char aes_test_ofb_iv[16] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
+};
+
+static const unsigned char aes_test_ofb_pt[64] = {
+ 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96,
+ 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A,
+ 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C,
+ 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51,
+ 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11,
+ 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF,
+ 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17,
+ 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10
+};
+
+static const unsigned char aes_test_ofb_ct[3][64] = {
+ {
+ 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20,
+ 0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A,
+ 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03,
+ 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25,
+ 0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6,
+ 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc,
+ 0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78,
+ 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e
+ },
+ {
+ 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB,
+ 0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74,
+ 0xfc, 0xc2, 0x8b, 0x8d, 0x4c, 0x63, 0x83, 0x7c,
+ 0x09, 0xe8, 0x17, 0x00, 0xc1, 0x10, 0x04, 0x01,
+ 0x8d, 0x9a, 0x9a, 0xea, 0xc0, 0xf6, 0x59, 0x6f,
+ 0x55, 0x9c, 0x6d, 0x4d, 0xaf, 0x59, 0xa5, 0xf2,
+ 0x6d, 0x9f, 0x20, 0x08, 0x57, 0xca, 0x6c, 0x3e,
+ 0x9c, 0xac, 0x52, 0x4b, 0xd9, 0xac, 0xc9, 0x2a
+ },
+ {
+ 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B,
+ 0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60,
+ 0x4f, 0xeb, 0xdc, 0x67, 0x40, 0xd2, 0x0b, 0x3a,
+ 0xc8, 0x8f, 0x6a, 0xd8, 0x2a, 0x4f, 0xb0, 0x8d,
+ 0x71, 0xab, 0x47, 0xa0, 0x86, 0xe8, 0x6e, 0xed,
+ 0xf3, 0x9d, 0x1c, 0x5b, 0xba, 0x97, 0xc4, 0x08,
+ 0x01, 0x26, 0x14, 0x1d, 0x67, 0xf3, 0x7b, 0xe8,
+ 0x53, 0x8f, 0x5a, 0x8b, 0xe7, 0x40, 0xe4, 0x84
+ }
+};
+#endif /* MBEDTLS_CIPHER_MODE_OFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+/*
+ * AES-CTR test vectors from:
+ *
+ * http://www.faqs.org/rfcs/rfc3686.html
+ */
+
+static const unsigned char aes_test_ctr_key[3][16] = {
+ {
+ 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC,
+ 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E
+ },
+ {
+ 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7,
+ 0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63
+ },
+ {
+ 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8,
+ 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC
+ }
+};
+
+static const unsigned char aes_test_ctr_nonce_counter[3][16] = {
+ {
+ 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
+ },
+ {
+ 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59,
+ 0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01
+ },
+ {
+ 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F,
+ 0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01
+ }
+};
+
+static const unsigned char aes_test_ctr_pt[3][48] = {
+ {
+ 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62,
+ 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67
+ },
+
+ {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
+ },
+
+ {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x20, 0x21, 0x22, 0x23
+ }
+};
+
+static const unsigned char aes_test_ctr_ct[3][48] = {
+ {
+ 0xE4, 0x09, 0x5D, 0x4F, 0xB7, 0xA7, 0xB3, 0x79,
+ 0x2D, 0x61, 0x75, 0xA3, 0x26, 0x13, 0x11, 0xB8
+ },
+ {
+ 0x51, 0x04, 0xA1, 0x06, 0x16, 0x8A, 0x72, 0xD9,
+ 0x79, 0x0D, 0x41, 0xEE, 0x8E, 0xDA, 0xD3, 0x88,
+ 0xEB, 0x2E, 0x1E, 0xFC, 0x46, 0xDA, 0x57, 0xC8,
+ 0xFC, 0xE6, 0x30, 0xDF, 0x91, 0x41, 0xBE, 0x28
+ },
+ {
+ 0xC1, 0xCF, 0x48, 0xA8, 0x9F, 0x2F, 0xFD, 0xD9,
+ 0xCF, 0x46, 0x52, 0xE9, 0xEF, 0xDB, 0x72, 0xD7,
+ 0x45, 0x40, 0xA4, 0x2B, 0xDE, 0x6D, 0x78, 0x36,
+ 0xD5, 0x9A, 0x5C, 0xEA, 0xAE, 0xF3, 0x10, 0x53,
+ 0x25, 0xB2, 0x07, 0x2F
+ }
+};
+
+static const int aes_test_ctr_len[3] =
+{ 16, 32, 36 };
+#endif /* MBEDTLS_CIPHER_MODE_CTR */
+
+#if defined(MBEDTLS_CIPHER_MODE_XTS)
+/*
+ * AES-XTS test vectors from:
+ *
+ * IEEE P1619/D16 Annex B
+ * https://web.archive.org/web/20150629024421/http://grouper.ieee.org/groups/1619/email/pdf00086.pdf
+ * (Archived from original at http://grouper.ieee.org/groups/1619/email/pdf00086.pdf)
+ */
+static const unsigned char aes_test_xts_key[][32] = {
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ },
+ {
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22
+ },
+ {
+ 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+ 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22
+ },
+};
+
+static const unsigned char aes_test_xts_pt32[][32] = {
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ },
+ {
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44
+ },
+ {
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44
+ },
+};
+
+static const unsigned char aes_test_xts_ct32[][32] = {
+ {
+ 0x91, 0x7c, 0xf6, 0x9e, 0xbd, 0x68, 0xb2, 0xec,
+ 0x9b, 0x9f, 0xe9, 0xa3, 0xea, 0xdd, 0xa6, 0x92,
+ 0xcd, 0x43, 0xd2, 0xf5, 0x95, 0x98, 0xed, 0x85,
+ 0x8c, 0x02, 0xc2, 0x65, 0x2f, 0xbf, 0x92, 0x2e
+ },
+ {
+ 0xc4, 0x54, 0x18, 0x5e, 0x6a, 0x16, 0x93, 0x6e,
+ 0x39, 0x33, 0x40, 0x38, 0xac, 0xef, 0x83, 0x8b,
+ 0xfb, 0x18, 0x6f, 0xff, 0x74, 0x80, 0xad, 0xc4,
+ 0x28, 0x93, 0x82, 0xec, 0xd6, 0xd3, 0x94, 0xf0
+ },
+ {
+ 0xaf, 0x85, 0x33, 0x6b, 0x59, 0x7a, 0xfc, 0x1a,
+ 0x90, 0x0b, 0x2e, 0xb2, 0x1e, 0xc9, 0x49, 0xd2,
+ 0x92, 0xdf, 0x4c, 0x04, 0x7e, 0x0b, 0x21, 0x53,
+ 0x21, 0x86, 0xa5, 0x97, 0x1a, 0x22, 0x7a, 0x89
+ },
+};
+
+static const unsigned char aes_test_xts_data_unit[][16] = {
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ },
+ {
+ 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ },
+ {
+ 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ },
+};
+
+#endif /* MBEDTLS_CIPHER_MODE_XTS */
+
+/*
+ * Checkup routine
+ */
+int mbedtls_aes_self_test(int verbose)
+{
+ int ret = 0, i, j, u, mode;
+ unsigned int keybits;
+ unsigned char key[32];
+ unsigned char buf[64];
+ const unsigned char *aes_tests;
+#if defined(MBEDTLS_CIPHER_MODE_CBC) || defined(MBEDTLS_CIPHER_MODE_CFB)
+ unsigned char iv[16];
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ unsigned char prv[16];
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR) || defined(MBEDTLS_CIPHER_MODE_CFB) || \
+ defined(MBEDTLS_CIPHER_MODE_OFB)
+ size_t offset;
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR) || defined(MBEDTLS_CIPHER_MODE_XTS)
+ int len;
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ unsigned char nonce_counter[16];
+ unsigned char stream_block[16];
+#endif
+ mbedtls_aes_context ctx;
+
+ memset(key, 0, 32);
+ mbedtls_aes_init(&ctx);
+
+ /*
+ * ECB mode
+ */
+ for (i = 0; i < 6; i++) {
+ u = i >> 1;
+ keybits = 128 + u * 64;
+ mode = i & 1;
+
+ if (verbose != 0)
+ mbedtls_printf(" AES-ECB-%3d (%s): ", keybits,
+ (mode == MBEDTLS_AES_DECRYPT) ? "dec" : "enc");
+
+ memset(buf, 0, 16);
+
+ if (mode == MBEDTLS_AES_DECRYPT) {
+ ret = mbedtls_aes_setkey_dec(&ctx, key, keybits);
+ aes_tests = aes_test_ecb_dec[u];
+ } else {
+ ret = mbedtls_aes_setkey_enc(&ctx, key, keybits);
+ aes_tests = aes_test_ecb_enc[u];
+ }
+
+ /*
+ * AES-192 is an optional feature that may be unavailable when
+ * there is an alternative underlying implementation i.e. when
+ * MBEDTLS_AES_ALT is defined.
+ */
+ if (ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192) {
+ mbedtls_printf("skipped\n");
+ continue;
+ } else if (ret != 0) {
+ goto exit;
+ }
+
+ for (j = 0; j < 10000; j++) {
+ ret = mbedtls_aes_crypt_ecb(&ctx, mode, buf, buf);
+ if (ret != 0) {
+ goto exit;
+ }
+ }
+
+ if (memcmp(buf, aes_tests, 16) != 0) {
+ ret = 1;
+ goto exit;
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("passed\n");
+ }
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("\n");
+ }
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ /*
+ * CBC mode
+ */
+ for (i = 0; i < 6; i++) {
+ u = i >> 1;
+ keybits = 128 + u * 64;
+ mode = i & 1;
+
+ if (verbose != 0)
+ mbedtls_printf(" AES-CBC-%3d (%s): ", keybits,
+ (mode == MBEDTLS_AES_DECRYPT) ? "dec" : "enc");
+
+ memset(iv, 0, 16);
+ memset(prv, 0, 16);
+ memset(buf, 0, 16);
+
+ if (mode == MBEDTLS_AES_DECRYPT) {
+ ret = mbedtls_aes_setkey_dec(&ctx, key, keybits);
+ aes_tests = aes_test_cbc_dec[u];
+ } else {
+ ret = mbedtls_aes_setkey_enc(&ctx, key, keybits);
+ aes_tests = aes_test_cbc_enc[u];
+ }
+
+ /*
+ * AES-192 is an optional feature that may be unavailable when
+ * there is an alternative underlying implementation i.e. when
+ * MBEDTLS_AES_ALT is defined.
+ */
+ if (ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192) {
+ mbedtls_printf("skipped\n");
+ continue;
+ } else if (ret != 0) {
+ goto exit;
+ }
+
+ for (j = 0; j < 10000; j++) {
+ if (mode == MBEDTLS_AES_ENCRYPT) {
+ unsigned char tmp[16];
+
+ memcpy(tmp, prv, 16);
+ memcpy(prv, buf, 16);
+ memcpy(buf, tmp, 16);
+ }
+
+ ret = mbedtls_aes_crypt_cbc(&ctx, mode, 16, iv, buf, buf);
+ if (ret != 0) {
+ goto exit;
+ }
+
+ }
+
+ if (memcmp(buf, aes_tests, 16) != 0) {
+ ret = 1;
+ goto exit;
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("passed\n");
+ }
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("\n");
+ }
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ /*
+ * CFB128 mode
+ */
+ for (i = 0; i < 6; i++) {
+ u = i >> 1;
+ keybits = 128 + u * 64;
+ mode = i & 1;
+
+ if (verbose != 0)
+ mbedtls_printf(" AES-CFB128-%3d (%s): ", keybits,
+ (mode == MBEDTLS_AES_DECRYPT) ? "dec" : "enc");
+
+ memcpy(iv, aes_test_cfb128_iv, 16);
+ memcpy(key, aes_test_cfb128_key[u], keybits / 8);
+
+ offset = 0;
+ ret = mbedtls_aes_setkey_enc(&ctx, key, keybits);
+ /*
+ * AES-192 is an optional feature that may be unavailable when
+ * there is an alternative underlying implementation i.e. when
+ * MBEDTLS_AES_ALT is defined.
+ */
+ if (ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192) {
+ mbedtls_printf("skipped\n");
+ continue;
+ } else if (ret != 0) {
+ goto exit;
+ }
+
+ if (mode == MBEDTLS_AES_DECRYPT) {
+ memcpy(buf, aes_test_cfb128_ct[u], 64);
+ aes_tests = aes_test_cfb128_pt;
+ } else {
+ memcpy(buf, aes_test_cfb128_pt, 64);
+ aes_tests = aes_test_cfb128_ct[u];
+ }
+
+ ret = mbedtls_aes_crypt_cfb128(&ctx, mode, 64, &offset, iv, buf, buf);
+ if (ret != 0) {
+ goto exit;
+ }
+
+ if (memcmp(buf, aes_tests, 64) != 0) {
+ ret = 1;
+ goto exit;
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("passed\n");
+ }
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("\n");
+ }
+#endif /* MBEDTLS_CIPHER_MODE_CFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_OFB)
+ /*
+ * OFB mode
+ */
+ for (i = 0; i < 6; i++) {
+ u = i >> 1;
+ keybits = 128 + u * 64;
+ mode = i & 1;
+
+ if (verbose != 0)
+ mbedtls_printf(" AES-OFB-%3d (%s): ", keybits,
+ (mode == MBEDTLS_AES_DECRYPT) ? "dec" : "enc");
+
+ memcpy(iv, aes_test_ofb_iv, 16);
+ memcpy(key, aes_test_ofb_key[u], keybits / 8);
+
+ offset = 0;
+ ret = mbedtls_aes_setkey_enc(&ctx, key, keybits);
+ /*
+ * AES-192 is an optional feature that may be unavailable when
+ * there is an alternative underlying implementation i.e. when
+ * MBEDTLS_AES_ALT is defined.
+ */
+ if (ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192) {
+ mbedtls_printf("skipped\n");
+ continue;
+ } else if (ret != 0) {
+ goto exit;
+ }
+
+ if (mode == MBEDTLS_AES_DECRYPT) {
+ memcpy(buf, aes_test_ofb_ct[u], 64);
+ aes_tests = aes_test_ofb_pt;
+ } else {
+ memcpy(buf, aes_test_ofb_pt, 64);
+ aes_tests = aes_test_ofb_ct[u];
+ }
+
+ ret = mbedtls_aes_crypt_ofb(&ctx, 64, &offset, iv, buf, buf);
+ if (ret != 0) {
+ goto exit;
+ }
+
+ if (memcmp(buf, aes_tests, 64) != 0) {
+ ret = 1;
+ goto exit;
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("passed\n");
+ }
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("\n");
+ }
+#endif /* MBEDTLS_CIPHER_MODE_OFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ /*
+ * CTR mode
+ */
+ for (i = 0; i < 6; i++) {
+ u = i >> 1;
+ mode = i & 1;
+
+ if (verbose != 0)
+ mbedtls_printf(" AES-CTR-128 (%s): ",
+ (mode == MBEDTLS_AES_DECRYPT) ? "dec" : "enc");
+
+ memcpy(nonce_counter, aes_test_ctr_nonce_counter[u], 16);
+ memcpy(key, aes_test_ctr_key[u], 16);
+
+ offset = 0;
+ if ((ret = mbedtls_aes_setkey_enc(&ctx, key, 128)) != 0) {
+ goto exit;
+ }
+
+ len = aes_test_ctr_len[u];
+
+ if (mode == MBEDTLS_AES_DECRYPT) {
+ memcpy(buf, aes_test_ctr_ct[u], len);
+ aes_tests = aes_test_ctr_pt[u];
+ } else {
+ memcpy(buf, aes_test_ctr_pt[u], len);
+ aes_tests = aes_test_ctr_ct[u];
+ }
+
+ ret = mbedtls_aes_crypt_ctr(&ctx, len, &offset, nonce_counter,
+ stream_block, buf, buf);
+ if (ret != 0) {
+ goto exit;
+ }
+
+ if (memcmp(buf, aes_tests, len) != 0) {
+ ret = 1;
+ goto exit;
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("passed\n");
+ }
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("\n");
+ }
+#endif /* MBEDTLS_CIPHER_MODE_CTR */
+
+#if defined(MBEDTLS_CIPHER_MODE_XTS)
+ {
+ static const int num_tests =
+ sizeof(aes_test_xts_key) / sizeof(*aes_test_xts_key);
+ mbedtls_aes_xts_context ctx_xts;
+
+ /*
+ * XTS mode
+ */
+ mbedtls_aes_xts_init(&ctx_xts);
+
+ for (i = 0; i < num_tests << 1; i++) {
+ const unsigned char *data_unit;
+ u = i >> 1;
+ mode = i & 1;
+
+ if (verbose != 0)
+ mbedtls_printf(" AES-XTS-128 (%s): ",
+ (mode == MBEDTLS_AES_DECRYPT) ? "dec" : "enc");
+
+ memset(key, 0, sizeof(key));
+ memcpy(key, aes_test_xts_key[u], 32);
+ data_unit = aes_test_xts_data_unit[u];
+
+ len = sizeof(*aes_test_xts_ct32);
+
+ if (mode == MBEDTLS_AES_DECRYPT) {
+ ret = mbedtls_aes_xts_setkey_dec(&ctx_xts, key, 256);
+ if (ret != 0) {
+ goto exit;
+ }
+ memcpy(buf, aes_test_xts_ct32[u], len);
+ aes_tests = aes_test_xts_pt32[u];
+ } else {
+ ret = mbedtls_aes_xts_setkey_enc(&ctx_xts, key, 256);
+ if (ret != 0) {
+ goto exit;
+ }
+ memcpy(buf, aes_test_xts_pt32[u], len);
+ aes_tests = aes_test_xts_ct32[u];
+ }
+
+
+ ret = mbedtls_aes_crypt_xts(&ctx_xts, mode, len, data_unit,
+ buf, buf);
+ if (ret != 0) {
+ goto exit;
+ }
+
+ if (memcmp(buf, aes_tests, len) != 0) {
+ ret = 1;
+ goto exit;
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("passed\n");
+ }
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("\n");
+ }
+
+ mbedtls_aes_xts_free(&ctx_xts);
+ }
+#endif /* MBEDTLS_CIPHER_MODE_XTS */
+
+ ret = 0;
+
+exit:
+ if (ret != 0 && verbose != 0) {
+ mbedtls_printf("failed\n");
+ }
+
+ mbedtls_aes_free(&ctx);
+
+ return (ret);
+}
+
+#endif /* MBEDTLS_AES_SELF_TEST */
+
+#endif /* MBEDTLS_AES_C */
diff --git a/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/aes.h b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/aes.h
new file mode 100644
index 0000000..50d6d35
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/aes.h
@@ -0,0 +1,678 @@
+/**
+ * \file aes.h
+ *
+ * \brief This file contains AES definitions and functions.
+ *
+ * The Advanced Encryption Standard (AES) specifies a FIPS-approved
+ * cryptographic algorithm that can be used to protect electronic
+ * data.
+ *
+ * The AES algorithm is a symmetric block cipher that can
+ * encrypt and decrypt information. For more information, see
+ * FIPS Publication 197: Advanced Encryption Standard and
+ * ISO/IEC 18033-2:2006: Information technology -- Security
+ * techniques -- Encryption algorithms -- Part 2: Asymmetric
+ * ciphers .
+ *
+ * The AES-XTS block mode is standardized by NIST SP 800-38E
+ *
+ * and described in detail by IEEE P1619
+ * .
+ */
+
+/* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of Mbed TLS (https://tls.mbed.org)
+ */
+
+#ifndef MBEDTLS_AES_H
+#define MBEDTLS_AES_H
+
+#define MBEDTLS_AES_ROM_TABLES
+//#define MBEDTLS_AES_FEWER_TABLES
+#define MBEDTLS_CIPHER_MODE_CBC
+//#define MBEDTLS_CIPHER_MODE_CFB
+//#define MBEDTLS_PKCS1_V15
+//#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
+//#define MBEDTLS_SSL_PROTO_TLS1_1
+
+/* mbed TLS modules */
+#define MBEDTLS_AES_C
+
+
+#include
+#include
+
+/* padlock.c and aesni.c rely on these values! */
+#define MBEDTLS_AES_ENCRYPT 1 /**< AES encryption. */
+#define MBEDTLS_AES_DECRYPT 0 /**< AES decryption. */
+
+/* Error codes in range 0x0020-0x0022 */
+#define MBEDTLS_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */
+#define MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */
+
+/* Error codes in range 0x0021-0x0025 */
+#define MBEDTLS_ERR_AES_BAD_INPUT_DATA -0x0021 /**< Invalid input data. */
+
+/* MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE is deprecated and should not be used. */
+#define MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE -0x0023 /**< Feature not available. For example, an unsupported AES key size. */
+
+/* MBEDTLS_ERR_AES_HW_ACCEL_FAILED is deprecated and should not be used. */
+#define MBEDTLS_ERR_AES_HW_ACCEL_FAILED -0x0025 /**< AES hardware accelerator failed. */
+
+#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
+ !defined(inline) && !defined(__cplusplus)
+#define inline __inline
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(MBEDTLS_AES_ALT)
+// Regular implementation
+//
+
+/**
+ * \brief The AES context-type definition.
+ */
+typedef struct mbedtls_aes_context {
+ int nr; /*!< The number of rounds. */
+ uint32_t *rk; /*!< AES round keys. */
+ uint32_t buf[68]; /*!< Unaligned data buffer. This buffer can
+ hold 32 extra Bytes, which can be used for
+ one of the following purposes:
+ Alignment if VIA padlock is
+ used.
+ Simplifying key expansion in the 256-bit
+ case by generating an extra round key.
+ */
+}
+mbedtls_aes_context;
+
+#if defined(MBEDTLS_CIPHER_MODE_XTS)
+/**
+ * \brief The AES XTS context-type definition.
+ */
+typedef struct mbedtls_aes_xts_context {
+ mbedtls_aes_context crypt; /*!< The AES context to use for AES block
+ encryption or decryption. */
+ mbedtls_aes_context tweak; /*!< The AES context used for tweak
+ computation. */
+} mbedtls_aes_xts_context;
+#endif /* MBEDTLS_CIPHER_MODE_XTS */
+
+#else /* MBEDTLS_AES_ALT */
+#include "aes_alt.h"
+#endif /* MBEDTLS_AES_ALT */
+
+/**
+ * \brief This function initializes the specified AES context.
+ *
+ * It must be the first API called before using
+ * the context.
+ *
+ * \param ctx The AES context to initialize. This must not be \c NULL.
+ */
+void mbedtls_aes_init(mbedtls_aes_context *ctx);
+
+/**
+ * \brief This function releases and clears the specified AES context.
+ *
+ * \param ctx The AES context to clear.
+ * If this is \c NULL, this function does nothing.
+ * Otherwise, the context must have been at least initialized.
+ */
+void mbedtls_aes_free(mbedtls_aes_context *ctx);
+
+#if defined(MBEDTLS_CIPHER_MODE_XTS)
+/**
+ * \brief This function initializes the specified AES XTS context.
+ *
+ * It must be the first API called before using
+ * the context.
+ *
+ * \param ctx The AES XTS context to initialize. This must not be \c NULL.
+ */
+void mbedtls_aes_xts_init(mbedtls_aes_xts_context *ctx);
+
+/**
+ * \brief This function releases and clears the specified AES XTS context.
+ *
+ * \param ctx The AES XTS context to clear.
+ * If this is \c NULL, this function does nothing.
+ * Otherwise, the context must have been at least initialized.
+ */
+void mbedtls_aes_xts_free(mbedtls_aes_xts_context *ctx);
+#endif /* MBEDTLS_CIPHER_MODE_XTS */
+
+/**
+ * \brief This function sets the encryption key.
+ *
+ * \param ctx The AES context to which the key should be bound.
+ * It must be initialized.
+ * \param key The encryption key.
+ * This must be a readable buffer of size \p keybits bits.
+ * \param keybits The size of data passed in bits. Valid options are:
+ * 128 bits
+ * 192 bits
+ * 256 bits
+ *
+ * \return \c 0 on success.
+ * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure.
+ */
+int mbedtls_aes_setkey_enc(mbedtls_aes_context *ctx, const unsigned char *key,
+ unsigned int keybits);
+
+/**
+ * \brief This function sets the decryption key.
+ *
+ * \param ctx The AES context to which the key should be bound.
+ * It must be initialized.
+ * \param key The decryption key.
+ * This must be a readable buffer of size \p keybits bits.
+ * \param keybits The size of data passed. Valid options are:
+ * 128 bits
+ * 192 bits
+ * 256 bits
+ *
+ * \return \c 0 on success.
+ * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure.
+ */
+int mbedtls_aes_setkey_dec(mbedtls_aes_context *ctx, const unsigned char *key,
+ unsigned int keybits);
+
+#if defined(MBEDTLS_CIPHER_MODE_XTS)
+/**
+ * \brief This function prepares an XTS context for encryption and
+ * sets the encryption key.
+ *
+ * \param ctx The AES XTS context to which the key should be bound.
+ * It must be initialized.
+ * \param key The encryption key. This is comprised of the XTS key1
+ * concatenated with the XTS key2.
+ * This must be a readable buffer of size \p keybits bits.
+ * \param keybits The size of \p key passed in bits. Valid options are:
+ * 256 bits (each of key1 and key2 is a 128-bit key)
+ * 512 bits (each of key1 and key2 is a 256-bit key)
+ *
+ * \return \c 0 on success.
+ * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure.
+ */
+int mbedtls_aes_xts_setkey_enc(mbedtls_aes_xts_context *ctx,
+ const unsigned char *key,
+ unsigned int keybits);
+
+/**
+ * \brief This function prepares an XTS context for decryption and
+ * sets the decryption key.
+ *
+ * \param ctx The AES XTS context to which the key should be bound.
+ * It must be initialized.
+ * \param key The decryption key. This is comprised of the XTS key1
+ * concatenated with the XTS key2.
+ * This must be a readable buffer of size \p keybits bits.
+ * \param keybits The size of \p key passed in bits. Valid options are:
+ * 256 bits (each of key1 and key2 is a 128-bit key)
+ * 512 bits (each of key1 and key2 is a 256-bit key)
+ *
+ * \return \c 0 on success.
+ * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure.
+ */
+int mbedtls_aes_xts_setkey_dec(mbedtls_aes_xts_context *ctx,
+ const unsigned char *key,
+ unsigned int keybits);
+#endif /* MBEDTLS_CIPHER_MODE_XTS */
+
+/**
+ * \brief This function performs an AES single-block encryption or
+ * decryption operation.
+ *
+ * It performs the operation defined in the \p mode parameter
+ * (encrypt or decrypt), on the input data buffer defined in
+ * the \p input parameter.
+ *
+ * mbedtls_aes_init(), and either mbedtls_aes_setkey_enc() or
+ * mbedtls_aes_setkey_dec() must be called before the first
+ * call to this API with the same context.
+ *
+ * \param ctx The AES context to use for encryption or decryption.
+ * It must be initialized and bound to a key.
+ * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or
+ * #MBEDTLS_AES_DECRYPT.
+ * \param input The buffer holding the input data.
+ * It must be readable and at least \c 16 Bytes long.
+ * \param output The buffer where the output data will be written.
+ * It must be writeable and at least \c 16 Bytes long.
+
+ * \return \c 0 on success.
+ */
+int mbedtls_aes_crypt_ecb(mbedtls_aes_context *ctx,
+ int mode,
+ const unsigned char input[16],
+ unsigned char output[16]);
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+/**
+ * \brief This function performs an AES-CBC encryption or decryption operation
+ * on full blocks.
+ *
+ * It performs the operation defined in the \p mode
+ * parameter (encrypt/decrypt), on the input data buffer defined in
+ * the \p input parameter.
+ *
+ * It can be called as many times as needed, until all the input
+ * data is processed. mbedtls_aes_init(), and either
+ * mbedtls_aes_setkey_enc() or mbedtls_aes_setkey_dec() must be called
+ * before the first call to this API with the same context.
+ *
+ * \note This function operates on full blocks, that is, the input size
+ * must be a multiple of the AES block size of \c 16 Bytes.
+ *
+ * \note Upon exit, the content of the IV is updated so that you can
+ * call the same function again on the next
+ * block(s) of data and get the same result as if it was
+ * encrypted in one call. This allows a "streaming" usage.
+ * If you need to retain the contents of the IV, you should
+ * either save it manually or use the cipher module instead.
+ *
+ *
+ * \param ctx The AES context to use for encryption or decryption.
+ * It must be initialized and bound to a key.
+ * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or
+ * #MBEDTLS_AES_DECRYPT.
+ * \param length The length of the input data in Bytes. This must be a
+ * multiple of the block size (\c 16 Bytes).
+ * \param iv Initialization vector (updated after use).
+ * It must be a readable and writeable buffer of \c 16 Bytes.
+ * \param input The buffer holding the input data.
+ * It must be readable and of size \p length Bytes.
+ * \param output The buffer holding the output data.
+ * It must be writeable and of size \p length Bytes.
+ *
+ * \return \c 0 on success.
+ * \return #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH
+ * on failure.
+ */
+int mbedtls_aes_crypt_cbc(mbedtls_aes_context *ctx,
+ int mode,
+ size_t length,
+ unsigned char iv[16],
+ const unsigned char *input,
+ unsigned char *output);
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#if defined(MBEDTLS_CIPHER_MODE_XTS)
+/**
+ * \brief This function performs an AES-XTS encryption or decryption
+ * operation for an entire XTS data unit.
+ *
+ * AES-XTS encrypts or decrypts blocks based on their location as
+ * defined by a data unit number. The data unit number must be
+ * provided by \p data_unit.
+ *
+ * NIST SP 800-38E limits the maximum size of a data unit to 2^20
+ * AES blocks. If the data unit is larger than this, this function
+ * returns #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH.
+ *
+ * \param ctx The AES XTS context to use for AES XTS operations.
+ * It must be initialized and bound to a key.
+ * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or
+ * #MBEDTLS_AES_DECRYPT.
+ * \param length The length of a data unit in Bytes. This can be any
+ * length between 16 bytes and 2^24 bytes inclusive
+ * (between 1 and 2^20 block cipher blocks).
+ * \param data_unit The address of the data unit encoded as an array of 16
+ * bytes in little-endian format. For disk encryption, this
+ * is typically the index of the block device sector that
+ * contains the data.
+ * \param input The buffer holding the input data (which is an entire
+ * data unit). This function reads \p length Bytes from \p
+ * input.
+ * \param output The buffer holding the output data (which is an entire
+ * data unit). This function writes \p length Bytes to \p
+ * output.
+ *
+ * \return \c 0 on success.
+ * \return #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH if \p length is
+ * smaller than an AES block in size (16 Bytes) or if \p
+ * length is larger than 2^20 blocks (16 MiB).
+ */
+int mbedtls_aes_crypt_xts(mbedtls_aes_xts_context *ctx,
+ int mode,
+ size_t length,
+ const unsigned char data_unit[16],
+ const unsigned char *input,
+ unsigned char *output);
+#endif /* MBEDTLS_CIPHER_MODE_XTS */
+
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+/**
+ * \brief This function performs an AES-CFB128 encryption or decryption
+ * operation.
+ *
+ * It performs the operation defined in the \p mode
+ * parameter (encrypt or decrypt), on the input data buffer
+ * defined in the \p input parameter.
+ *
+ * For CFB, you must set up the context with mbedtls_aes_setkey_enc(),
+ * regardless of whether you are performing an encryption or decryption
+ * operation, that is, regardless of the \p mode parameter. This is
+ * because CFB mode uses the same key schedule for encryption and
+ * decryption.
+ *
+ * \note Upon exit, the content of the IV is updated so that you can
+ * call the same function again on the next
+ * block(s) of data and get the same result as if it was
+ * encrypted in one call. This allows a "streaming" usage.
+ * If you need to retain the contents of the
+ * IV, you must either save it manually or use the cipher
+ * module instead.
+ *
+ *
+ * \param ctx The AES context to use for encryption or decryption.
+ * It must be initialized and bound to a key.
+ * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or
+ * #MBEDTLS_AES_DECRYPT.
+ * \param length The length of the input data in Bytes.
+ * \param iv_off The offset in IV (updated after use).
+ * It must point to a valid \c size_t.
+ * \param iv The initialization vector (updated after use).
+ * It must be a readable and writeable buffer of \c 16 Bytes.
+ * \param input The buffer holding the input data.
+ * It must be readable and of size \p length Bytes.
+ * \param output The buffer holding the output data.
+ * It must be writeable and of size \p length Bytes.
+ *
+ * \return \c 0 on success.
+ */
+int mbedtls_aes_crypt_cfb128(mbedtls_aes_context *ctx,
+ int mode,
+ size_t length,
+ size_t *iv_off,
+ unsigned char iv[16],
+ const unsigned char *input,
+ unsigned char *output);
+
+/**
+ * \brief This function performs an AES-CFB8 encryption or decryption
+ * operation.
+ *
+ * It performs the operation defined in the \p mode
+ * parameter (encrypt/decrypt), on the input data buffer defined
+ * in the \p input parameter.
+ *
+ * Due to the nature of CFB, you must use the same key schedule for
+ * both encryption and decryption operations. Therefore, you must
+ * use the context initialized with mbedtls_aes_setkey_enc() for
+ * both #MBEDTLS_AES_ENCRYPT and #MBEDTLS_AES_DECRYPT.
+ *
+ * \note Upon exit, the content of the IV is updated so that you can
+ * call the same function again on the next
+ * block(s) of data and get the same result as if it was
+ * encrypted in one call. This allows a "streaming" usage.
+ * If you need to retain the contents of the
+ * IV, you should either save it manually or use the cipher
+ * module instead.
+ *
+ *
+ * \param ctx The AES context to use for encryption or decryption.
+ * It must be initialized and bound to a key.
+ * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or
+ * #MBEDTLS_AES_DECRYPT
+ * \param length The length of the input data.
+ * \param iv The initialization vector (updated after use).
+ * It must be a readable and writeable buffer of \c 16 Bytes.
+ * \param input The buffer holding the input data.
+ * It must be readable and of size \p length Bytes.
+ * \param output The buffer holding the output data.
+ * It must be writeable and of size \p length Bytes.
+ *
+ * \return \c 0 on success.
+ */
+int mbedtls_aes_crypt_cfb8(mbedtls_aes_context *ctx,
+ int mode,
+ size_t length,
+ unsigned char iv[16],
+ const unsigned char *input,
+ unsigned char *output);
+#endif /*MBEDTLS_CIPHER_MODE_CFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_OFB)
+/**
+ * \brief This function performs an AES-OFB (Output Feedback Mode)
+ * encryption or decryption operation.
+ *
+ * For OFB, you must set up the context with
+ * mbedtls_aes_setkey_enc(), regardless of whether you are
+ * performing an encryption or decryption operation. This is
+ * because OFB mode uses the same key schedule for encryption and
+ * decryption.
+ *
+ * The OFB operation is identical for encryption or decryption,
+ * therefore no operation mode needs to be specified.
+ *
+ * \note Upon exit, the content of iv, the Initialisation Vector, is
+ * updated so that you can call the same function again on the next
+ * block(s) of data and get the same result as if it was encrypted
+ * in one call. This allows a "streaming" usage, by initialising
+ * iv_off to 0 before the first call, and preserving its value
+ * between calls.
+ *
+ * For non-streaming use, the iv should be initialised on each call
+ * to a unique value, and iv_off set to 0 on each call.
+ *
+ * If you need to retain the contents of the initialisation vector,
+ * you must either save it manually or use the cipher module
+ * instead.
+ *
+ * \warning For the OFB mode, the initialisation vector must be unique
+ * every encryption operation. Reuse of an initialisation vector
+ * will compromise security.
+ *
+ * \param ctx The AES context to use for encryption or decryption.
+ * It must be initialized and bound to a key.
+ * \param length The length of the input data.
+ * \param iv_off The offset in IV (updated after use).
+ * It must point to a valid \c size_t.
+ * \param iv The initialization vector (updated after use).
+ * It must be a readable and writeable buffer of \c 16 Bytes.
+ * \param input The buffer holding the input data.
+ * It must be readable and of size \p length Bytes.
+ * \param output The buffer holding the output data.
+ * It must be writeable and of size \p length Bytes.
+ *
+ * \return \c 0 on success.
+ */
+int mbedtls_aes_crypt_ofb(mbedtls_aes_context *ctx,
+ size_t length,
+ size_t *iv_off,
+ unsigned char iv[16],
+ const unsigned char *input,
+ unsigned char *output);
+
+#endif /* MBEDTLS_CIPHER_MODE_OFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+/**
+ * \brief This function performs an AES-CTR encryption or decryption
+ * operation.
+ *
+ * This function performs the operation defined in the \p mode
+ * parameter (encrypt/decrypt), on the input data buffer
+ * defined in the \p input parameter.
+ *
+ * Due to the nature of CTR, you must use the same key schedule
+ * for both encryption and decryption operations. Therefore, you
+ * must use the context initialized with mbedtls_aes_setkey_enc()
+ * for both #MBEDTLS_AES_ENCRYPT and #MBEDTLS_AES_DECRYPT.
+ *
+ * \warning You must never reuse a nonce value with the same key. Doing so
+ * would void the encryption for the two messages encrypted with
+ * the same nonce and key.
+ *
+ * There are two common strategies for managing nonces with CTR:
+ *
+ * 1. You can handle everything as a single message processed over
+ * successive calls to this function. In that case, you want to
+ * set \p nonce_counter and \p nc_off to 0 for the first call, and
+ * then preserve the values of \p nonce_counter, \p nc_off and \p
+ * stream_block across calls to this function as they will be
+ * updated by this function.
+ *
+ * With this strategy, you must not encrypt more than 2**128
+ * blocks of data with the same key.
+ *
+ * 2. You can encrypt separate messages by dividing the \p
+ * nonce_counter buffer in two areas: the first one used for a
+ * per-message nonce, handled by yourself, and the second one
+ * updated by this function internally.
+ *
+ * For example, you might reserve the first 12 bytes for the
+ * per-message nonce, and the last 4 bytes for internal use. In that
+ * case, before calling this function on a new message you need to
+ * set the first 12 bytes of \p nonce_counter to your chosen nonce
+ * value, the last 4 to 0, and \p nc_off to 0 (which will cause \p
+ * stream_block to be ignored). That way, you can encrypt at most
+ * 2**96 messages of up to 2**32 blocks each with the same key.
+ *
+ * The per-message nonce (or information sufficient to reconstruct
+ * it) needs to be communicated with the ciphertext and must be unique.
+ * The recommended way to ensure uniqueness is to use a message
+ * counter. An alternative is to generate random nonces, but this
+ * limits the number of messages that can be securely encrypted:
+ * for example, with 96-bit random nonces, you should not encrypt
+ * more than 2**32 messages with the same key.
+ *
+ * Note that for both stategies, sizes are measured in blocks and
+ * that an AES block is 16 bytes.
+ *
+ * \warning Upon return, \p stream_block contains sensitive data. Its
+ * content must not be written to insecure storage and should be
+ * securely discarded as soon as it's no longer needed.
+ *
+ * \param ctx The AES context to use for encryption or decryption.
+ * It must be initialized and bound to a key.
+ * \param length The length of the input data.
+ * \param nc_off The offset in the current \p stream_block, for
+ * resuming within the current cipher stream. The
+ * offset pointer should be 0 at the start of a stream.
+ * It must point to a valid \c size_t.
+ * \param nonce_counter The 128-bit nonce and counter.
+ * It must be a readable-writeable buffer of \c 16 Bytes.
+ * \param stream_block The saved stream block for resuming. This is
+ * overwritten by the function.
+ * It must be a readable-writeable buffer of \c 16 Bytes.
+ * \param input The buffer holding the input data.
+ * It must be readable and of size \p length Bytes.
+ * \param output The buffer holding the output data.
+ * It must be writeable and of size \p length Bytes.
+ *
+ * \return \c 0 on success.
+ */
+int mbedtls_aes_crypt_ctr(mbedtls_aes_context *ctx,
+ size_t length,
+ size_t *nc_off,
+ unsigned char nonce_counter[16],
+ unsigned char stream_block[16],
+ const unsigned char *input,
+ unsigned char *output);
+#endif /* MBEDTLS_CIPHER_MODE_CTR */
+
+/**
+ * \brief Internal AES block encryption function. This is only
+ * exposed to allow overriding it using
+ * \c MBEDTLS_AES_ENCRYPT_ALT.
+ *
+ * \param ctx The AES context to use for encryption.
+ * \param input The plaintext block.
+ * \param output The output (ciphertext) block.
+ *
+ * \return \c 0 on success.
+ */
+int mbedtls_internal_aes_encrypt(mbedtls_aes_context *ctx,
+ const unsigned char input[16],
+ unsigned char output[16]);
+
+/**
+ * \brief Internal AES block decryption function. This is only
+ * exposed to allow overriding it using see
+ * \c MBEDTLS_AES_DECRYPT_ALT.
+ *
+ * \param ctx The AES context to use for decryption.
+ * \param input The ciphertext block.
+ * \param output The output (plaintext) block.
+ *
+ * \return \c 0 on success.
+ */
+int mbedtls_internal_aes_decrypt(mbedtls_aes_context *ctx,
+ const unsigned char input[16],
+ unsigned char output[16]);
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+#if defined(MBEDTLS_DEPRECATED_WARNING)
+#define MBEDTLS_DEPRECATED __attribute__((deprecated))
+#else
+#define MBEDTLS_DEPRECATED
+#endif
+/**
+ * \brief Deprecated internal AES block encryption function
+ * without return value.
+ *
+ * \deprecated Superseded by mbedtls_internal_aes_encrypt()
+ *
+ * \param ctx The AES context to use for encryption.
+ * \param input Plaintext block.
+ * \param output Output (ciphertext) block.
+ */
+MBEDTLS_DEPRECATED void mbedtls_aes_encrypt(mbedtls_aes_context *ctx,
+ const unsigned char input[16],
+ unsigned char output[16]);
+
+/**
+ * \brief Deprecated internal AES block decryption function
+ * without return value.
+ *
+ * \deprecated Superseded by mbedtls_internal_aes_decrypt()
+ *
+ * \param ctx The AES context to use for decryption.
+ * \param input Ciphertext block.
+ * \param output Output (plaintext) block.
+ */
+MBEDTLS_DEPRECATED void mbedtls_aes_decrypt(mbedtls_aes_context *ctx,
+ const unsigned char input[16],
+ unsigned char output[16]);
+
+#undef MBEDTLS_DEPRECATED
+#endif /* !MBEDTLS_DEPRECATED_REMOVED */
+
+
+#if (MBEDTLS_SELF_TEST==1)
+/**
+ * \brief Checkup routine.
+ *
+ * \return \c 0 on success.
+ * \return \c 1 on failure.
+ */
+int mbedtls_aes_self_test(int verbose);
+
+#endif /* MBEDTLS_SELF_TEST */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* aes.h */
diff --git a/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/ccm.c b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/ccm.c
new file mode 100644
index 0000000..8e3220b
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/ccm.c
@@ -0,0 +1,391 @@
+/*
+ * NIST SP800-38C compliant CCM implementation
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+/*
+ * Definition of CCM:
+ * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
+ * RFC 3610 "Counter with CBC-MAC (CCM)"
+ *
+ * Related:
+ * RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
+ */
+
+
+#include
+#include "aes.h"
+#include "ccm.h"
+#include "cpu.h"
+
+#define CCM_ENCRYPT 0
+#define CCM_DECRYPT 1
+
+
+static bool aes128_ecb_encrypt(const uint8_t *key, uint8_t *input, uint16_t input_len, uint8_t *output)
+{
+ uint16_t length;
+ mbedtls_aes_context aes_ctx;
+ //
+ if (input_len % 16) {
+ return false;
+ }
+
+ length = input_len;
+
+ mbedtls_aes_init(&aes_ctx);
+
+ mbedtls_aes_setkey_enc(&aes_ctx, key, 128);
+
+ while (length > 0) {
+ mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, input, output);
+ input += 16;
+ output += 16;
+ length -= 16;
+ }
+
+ mbedtls_aes_free(&aes_ctx);
+
+ return true;
+}
+
+static int aes_ecb_encrypt(const uint8_t *pKey, uint8_t *input, uint8_t *output)
+{
+ // return (int)aes128_ecb_encrypt(pKey, input, 16, output);
+ // AES128_ECB_encrypt(input,pKey, output);
+ // return 0;
+ // return aes128_encrypt(pKey, input, 16, output);
+ uint16_t length;
+ mbedtls_aes_context aes_ctx;
+
+ length = 16;
+
+ mbedtls_aes_init(&aes_ctx);
+
+ mbedtls_aes_setkey_enc(&aes_ctx, pKey, 128);
+
+ while (length > 0) {
+ mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, input, output);
+ input += 16;
+ output += 16;
+ length -= 16;
+ }
+
+ mbedtls_aes_free(&aes_ctx);
+
+ return 0;
+}
+
+/* Implementation that should never be optimized out by the compiler */
+static void mbedtls_zeroize(void *v, size_t n)
+{
+ volatile unsigned char *p = v;
+ while (n--) {
+ *p++ = 0;
+ }
+}
+
+/*
+ * Macros for common operations.
+ * Results in smaller compiled code than static inline functions.
+ */
+
+/*
+ * Update the CBC-MAC state in y using a block in b
+ * (Always using b as the source helps the compiler optimise a bit better.)
+ */
+#define UPDATE_CBC_MAC \
+ for( i = 0; i < 16; i++ ) \
+ y[i] ^= b[i]; \
+ \
+ if( ( ret = aes_ecb_encrypt( key, y, y) ) != 0 ) \
+ return( ret );
+
+/*
+ * Encrypt or decrypt a partial block with CTR
+ * Warning: using b for temporary storage! src and dst must not be b!
+ * This avoids allocating one more 16 bytes buffer while allowing src == dst.
+ */
+#define CTR_CRYPT( dst, src, len ) \
+ if( ( ret = aes_ecb_encrypt( key, ctr, b) ) != 0 ) \
+ return( ret ); \
+ \
+ for( i = 0; i < len; i++ ) \
+ dst[i] = src[i] ^ b[i];
+
+/*
+ * Authenticated encryption or decryption
+ */
+static int ccm_auth_crypt(int mode, const unsigned char *key,
+ const unsigned char *iv, size_t iv_len,
+ const unsigned char *add, size_t add_len,
+ const unsigned char *input, size_t length,
+ unsigned char *output,
+ unsigned char *tag, size_t tag_len)
+{
+ int ret;
+ unsigned char i;
+ unsigned char q;
+ size_t len_left;
+ unsigned char b[16];
+ unsigned char y[16];
+ unsigned char ctr[16];
+ const unsigned char *src;
+ unsigned char *dst;
+
+ /*
+ * Check length requirements: SP800-38C A.1
+ * Additional requirement: a < 2^16 - 2^8 to simplify the code.
+ * 'length' checked later (when writing it to the first block)
+ */
+ if (tag_len < 4 || tag_len > 16 || tag_len % 2 != 0) {
+ return (MBEDTLS_ERR_CCM_BAD_INPUT);
+ }
+
+ /* Also implies q is within bounds */
+ if (iv_len < 7 || iv_len > 13) {
+ return (MBEDTLS_ERR_CCM_BAD_INPUT);
+ }
+
+ if (add_len > 0xFF00) {
+ return (MBEDTLS_ERR_CCM_BAD_INPUT);
+ }
+
+ q = 16 - 1 - (unsigned char) iv_len;
+
+ /*
+ * First block B_0:
+ * 0 .. 0 flags
+ * 1 .. iv_len nonce (aka iv)
+ * iv_len+1 .. 15 length
+ *
+ * With flags as (bits):
+ * 7 0
+ * 6 add present?
+ * 5 .. 3 (t - 2) / 2
+ * 2 .. 0 q - 1
+ */
+ b[0] = 0;
+ b[0] |= (add_len > 0) << 6;
+ b[0] |= ((tag_len - 2) / 2) << 3;
+ b[0] |= q - 1;
+
+ memcpy(b + 1, iv, iv_len);
+
+ for (i = 0, len_left = length; i < q; i++, len_left >>= 8) {
+ b[15 - i] = (unsigned char)(len_left & 0xFF);
+ }
+
+ if (len_left > 0) {
+ return (MBEDTLS_ERR_CCM_BAD_INPUT);
+ }
+
+
+ /* Start CBC-MAC with first block */
+ memset(y, 0, 16);
+ UPDATE_CBC_MAC;
+
+ /*
+ * If there is additional data, update CBC-MAC with
+ * add_len, add, 0 (padding to a block boundary)
+ */
+ if (add_len > 0) {
+ size_t use_len;
+ len_left = add_len;
+ src = add;
+
+ memset(b, 0, 16);
+ b[0] = (unsigned char)((add_len >> 8) & 0xFF);
+ b[1] = (unsigned char)((add_len) & 0xFF);
+
+ use_len = len_left < 16 - 2 ? len_left : 16 - 2;
+ memcpy(b + 2, src, use_len);
+ len_left -= use_len;
+ src += use_len;
+
+ UPDATE_CBC_MAC;
+
+ while (len_left > 0) {
+ use_len = len_left > 16 ? 16 : len_left;
+
+ memset(b, 0, 16);
+ memcpy(b, src, use_len);
+ UPDATE_CBC_MAC;
+
+ len_left -= use_len;
+ src += use_len;
+ }
+ }
+
+ /*
+ * Prepare counter block for encryption:
+ * 0 .. 0 flags
+ * 1 .. iv_len nonce (aka iv)
+ * iv_len+1 .. 15 counter (initially 1)
+ *
+ * With flags as (bits):
+ * 7 .. 3 0
+ * 2 .. 0 q - 1
+ */
+ ctr[0] = q - 1;
+ memcpy(ctr + 1, iv, iv_len);
+ memset(ctr + 1 + iv_len, 0, q);
+ ctr[15] = 1;
+
+ /*
+ * Authenticate and {en,de}crypt the message.
+ *
+ * The only difference between encryption and decryption is
+ * the respective order of authentication and {en,de}cryption.
+ */
+ len_left = length;
+ src = input;
+ dst = output;
+
+ while (len_left > 0) {
+ size_t use_len = len_left > 16 ? 16 : len_left;
+
+ if (mode == CCM_ENCRYPT) {
+ memset(b, 0, 16);
+ memcpy(b, src, use_len);
+ UPDATE_CBC_MAC;
+ }
+
+ CTR_CRYPT(dst, src, use_len);
+
+ if (mode == CCM_DECRYPT) {
+ memset(b, 0, 16);
+ memcpy(b, dst, use_len);
+ UPDATE_CBC_MAC;
+ }
+
+ dst += use_len;
+ src += use_len;
+ len_left -= use_len;
+
+ /*
+ * Increment counter.
+ * No need to check for overflow thanks to the length check above.
+ */
+ for (i = 0; i < q; i++)
+ if (++ctr[15 - i] != 0) {
+ break;
+ }
+ }
+
+ /*
+ * Authentication: reset counter and crypt/mask internal tag
+ */
+ for (i = 0; i < q; i++) {
+ ctr[15 - i] = 0;
+ }
+
+ CTR_CRYPT(y, y, 16);
+ memcpy(tag, y, tag_len);
+
+ return (0);
+}
+
+/*
+ * Authenticated encryption
+ */
+int aes_ccm_encrypt_and_tag(const unsigned char *key,
+ const unsigned char *iv, size_t iv_len,
+ const unsigned char *add, size_t add_len,
+ const unsigned char *input, size_t length,
+ unsigned char *output,
+ unsigned char *tag, size_t tag_len)
+{
+ return (ccm_auth_crypt(CCM_ENCRYPT, key, iv, iv_len,
+ add, add_len, input, length, output, tag, tag_len));
+}
+
+/*
+ * Authenticated decryption
+ */
+int aes_ccm_auth_decrypt(const unsigned char *key,
+ const unsigned char *iv, size_t iv_len,
+ const unsigned char *add, size_t add_len,
+ const unsigned char *input, size_t length,
+ unsigned char *output,
+ const unsigned char *tag, size_t tag_len)
+{
+ int ret;
+ unsigned char check_tag[16];
+ unsigned char i;
+ int diff;
+
+ if ((ret = ccm_auth_crypt(CCM_DECRYPT, key,
+ iv, iv_len, add, add_len,
+ input, length, output, check_tag, tag_len)) != 0) {
+ return (ret);
+ }
+
+ /* Check tag in "constant-time" */
+ for (diff = 0, i = 0; i < tag_len; i++) {
+ diff |= tag[i] ^ check_tag[i];
+ }
+
+ if (diff != 0) {
+ mbedtls_zeroize(output, length);
+ return (MBEDTLS_ERR_CCM_AUTH_FAILED);
+ }
+
+ return (0);
+}
+
+//#define MI_AUTOTEST
+
+#ifdef MI_AUTOTEST
+static uint8_t k[16] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
+ };
+static uint8_t nonce[13] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c
+ };
+static uint8_t p[64] = "HELLOWORLD!@#$%^helloworld123456";
+static uint8_t c[64] = {0};
+static uint8_t d[64] = {0};
+static uint8_t mic[4] = {0};
+static uint8_t astr[4] = {1, 2, 3, 4};
+
+
+#define LEN 32
+void aes_ccm_test2(void)
+{
+
+ aes_ccm_encrypt_and_tag(k, nonce, 12, astr, sizeof(astr), p, LEN, c, mic, 4);
+ aes_ccm_auth_decrypt(k, nonce, 12, astr, sizeof(astr), c, LEN, d, mic, 4);
+
+ //MI_LOG_INFO("Cipher : \n");
+ //MI_LOG_HEXDUMP(c, LEN);
+ // MI_LOG_INFO("MIC : \n");
+ // MI_LOG_HEXDUMP(mic, sizeof(mic));
+
+ // MI_LOG_DEBUG("AES128-CCM TEST: ");
+ if (memcmp(d, p, LEN) == 0) {
+ // MI_LOG_PRINTF(" PASS \n");
+ } else {
+ // MI_LOG_PRINTF(" FAIL \n");
+ }
+
+}
+#endif
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/ccm.h b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/ccm.h
new file mode 100644
index 0000000..0f04529
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/ccm.h
@@ -0,0 +1,93 @@
+/**
+ * \file ccm.h
+ *
+ * \brief Counter with CBC-MAC (CCM) for 128-bit block ciphers
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_CCM_H
+#define MBEDTLS_CCM_H
+
+#define MBEDTLS_ERR_CCM_BAD_INPUT -0x000D /**< Bad input parameters to function. */
+#define MBEDTLS_ERR_CCM_AUTH_FAILED -0x000F /**< Authenticated decryption failed. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief CCM buffer encryption
+ *
+ * \param key key must be 16 bytes
+ * \param length length of the input data in bytes
+ * \param iv nonce (initialization vector)
+ * \param iv_len length of IV in bytes
+ * must be 2, 3, 4, 5, 6, 7 or 8
+ * \param add additional data
+ * \param add_len length of additional data in bytes
+ * must be less than 2^16 - 2^8
+ * \param input buffer holding the input data
+ * \param output buffer for holding the output data
+ * must be at least 'length' bytes wide
+ * \param tag buffer for holding the tag
+ * \param tag_len length of the tag to generate in bytes
+ * must be 4, 6, 8, 10, 14 or 16
+ *
+ * \note The tag is written to a separate buffer. To get the tag
+ * concatenated with the output as in the CCM spec, use
+ * tag = output + length and make sure the output buffer is
+ * at least length + tag_len wide.
+ *
+ * \return 0 if successful
+ */
+int aes_ccm_encrypt_and_tag(const unsigned char *key,
+ const unsigned char *iv, size_t iv_len,
+ const unsigned char *add, size_t add_len,
+ const unsigned char *input, size_t length,
+ unsigned char *output,
+ unsigned char *tag, size_t tag_len);
+
+/**
+ * \brief CCM buffer authenticated decryption
+ *
+ * \param key key must be 16 bytes
+ * \param length length of the input data
+ * \param iv initialization vector
+ * \param iv_len length of IV
+ * \param add additional data
+ * \param add_len length of additional data
+ * \param input buffer holding the input data
+ * \param output buffer for holding the output data
+ * \param tag buffer holding the tag
+ * \param tag_len length of the tag
+ *
+ * \return 0 if successful and authenticated,
+ * MBEDTLS_ERR_CCM_AUTH_FAILED if tag does not match
+ */
+int aes_ccm_auth_decrypt(const unsigned char *key,
+ const unsigned char *iv, size_t iv_len,
+ const unsigned char *add, size_t add_len,
+ const unsigned char *input, size_t length,
+ unsigned char *output,
+ const unsigned char *tag, size_t tag_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MBEDTLS_CCM_H */
diff --git a/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/hmac.c b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/hmac.c
new file mode 100644
index 0000000..11d3b0b
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/hmac.c
@@ -0,0 +1,366 @@
+#include "sha1.h"
+#include "sha256.h"
+#include "hmac.h"
+
+
+#define hmac_printf
+
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef CEIL_DIV
+#define CEIL_DIV(a, b) (((a) + (b) - 1) / (b))
+#endif
+
+
+#define SHA1_DIGEST_SIZE 20
+#define SHA1_BLOCK_SIZE 64
+
+#define SHA256_DIGEST_SIZE 32
+#define SHA256_BLOCK_SIZE 64
+
+
+typedef struct {
+ /** Digest-specific context */
+ mbedtls_sha1_context *md_ctx;
+
+ /** HMAC part of the context */
+ uint8_t ipad[64];
+ uint8_t opad[64];
+} hmac_sha1_context_t;
+
+typedef struct {
+ /** Digest-specific context */
+ mbedtls_sha256_context *md_ctx;
+
+ /** HMAC part of the context */
+ uint8_t ipad[64];
+ uint8_t opad[64];
+} hmac_sha256_context_t;
+
+
+
+void hmac_sha1_init(hmac_sha1_context_t *ctx)
+{
+ memset(ctx, 0, sizeof(hmac_sha1_context_t));
+}
+
+void hmac_sha1_free(hmac_sha1_context_t *ctx)
+{
+ mbedtls_sha1_free((mbedtls_sha1_context *)ctx->md_ctx);
+}
+
+
+int32_t hmac_sha1_setup(hmac_sha1_context_t *ctx, int32_t hmac)
+{
+ return 0;
+}
+
+int hmac_sha1_starts(hmac_sha1_context_t *ctx, const uint8_t *key, uint32_t keylen)
+{
+
+ uint8_t sum[SHA1_DIGEST_SIZE];
+ uint32_t i;
+
+ if (keylen > (uint32_t) SHA1_BLOCK_SIZE) {
+ mbedtls_sha1_starts((mbedtls_sha1_context *) ctx->md_ctx);
+ mbedtls_sha1_update((mbedtls_sha1_context *) ctx->md_ctx, key, keylen);
+ mbedtls_sha1_finish((mbedtls_sha1_context *) ctx->md_ctx, sum);
+
+ keylen = SHA1_DIGEST_SIZE;
+ key = sum;
+ }
+
+
+ memset(ctx->ipad, 0x36, SHA1_BLOCK_SIZE);
+ memset(ctx->opad, 0x5C, SHA1_BLOCK_SIZE);
+
+ for (i = 0; i < keylen; i++) {
+ ctx->ipad[i] = (uint8_t)(ctx->ipad[i] ^ key[i]);
+ ctx->opad[i] = (uint8_t)(ctx->opad[i] ^ key[i]);
+ }
+
+ memset(sum, 0, sizeof(sum));
+
+ mbedtls_sha1_starts((mbedtls_sha1_context *) ctx->md_ctx);
+ mbedtls_sha1_update((mbedtls_sha1_context *) ctx->md_ctx, ctx->ipad, SHA1_BLOCK_SIZE);
+
+ return 0;
+
+}
+
+int32_t hmac_sha1_update(hmac_sha1_context_t *ctx, const uint8_t *input, uint32_t ilen)
+{
+ mbedtls_sha1_update((mbedtls_sha1_context *) ctx->md_ctx, input, ilen);
+ return 0;
+}
+
+int32_t hmac_sha1_finish(hmac_sha1_context_t *ctx, uint8_t *output)
+{
+ uint8_t tmp[SHA1_DIGEST_SIZE];
+
+ mbedtls_sha1_finish((mbedtls_sha1_context *) ctx->md_ctx, tmp);
+ mbedtls_sha1_starts((mbedtls_sha1_context *) ctx->md_ctx);
+ mbedtls_sha1_update((mbedtls_sha1_context *) ctx->md_ctx, ctx->opad, SHA1_BLOCK_SIZE);
+ mbedtls_sha1_update((mbedtls_sha1_context *) ctx->md_ctx, tmp, SHA1_DIGEST_SIZE);
+ mbedtls_sha1_finish((mbedtls_sha1_context *) ctx->md_ctx, output);
+
+ return 0;
+}
+
+int32_t hmac_sha1_reset(hmac_sha1_context_t *ctx)
+{
+
+ mbedtls_sha1_starts((mbedtls_sha1_context *) ctx->md_ctx);
+ mbedtls_sha1_update((mbedtls_sha1_context *) ctx->md_ctx, ctx->ipad, SHA1_BLOCK_SIZE);
+
+ return 0 ;
+}
+
+int32_t hmac_sha1_crypt(const uint8_t *key, uint32_t keylen, const uint8_t *input, uint32_t ilen, uint8_t *output)
+{
+ hmac_sha1_context_t ctx;
+ mbedtls_sha1_context sha_ctx;
+ int32_t ret;
+
+ hmac_sha1_init(&ctx);
+ memset(&sha_ctx, 0, sizeof(sha_ctx));
+ ctx.md_ctx = &sha_ctx;
+ if ((ret = hmac_sha1_setup(&ctx, 1)) != 0) {
+ return (ret);
+ }
+
+ hmac_sha1_starts(&ctx, key, keylen);
+ hmac_sha1_update(&ctx, input, ilen);
+ hmac_sha1_finish(&ctx, output);
+
+ return (0);
+}
+
+//
+
+void hmac_sha256_init(hmac_sha256_context_t *ctx)
+{
+ memset(ctx, 0, sizeof(hmac_sha256_context_t));
+}
+
+void hmac_sha256_free(hmac_sha256_context_t *ctx)
+{
+ mbedtls_sha256_free((mbedtls_sha256_context *)ctx->md_ctx);
+}
+
+
+int32_t hmac_sha256_setup(hmac_sha256_context_t *ctx, int32_t hmac)
+{
+ return 0;
+}
+
+int hmac_sha256_starts(hmac_sha256_context_t *ctx, const uint8_t *key, uint32_t keylen)
+{
+
+ uint8_t sum[SHA256_DIGEST_SIZE];
+ uint32_t i;
+
+ if (keylen > (uint32_t) SHA256_BLOCK_SIZE) {
+ mbedtls_sha256_starts((mbedtls_sha256_context *) ctx->md_ctx, 0);
+ mbedtls_sha256_update((mbedtls_sha256_context *) ctx->md_ctx, key, keylen);
+ mbedtls_sha256_finish((mbedtls_sha256_context *) ctx->md_ctx, sum);
+
+ keylen = SHA256_DIGEST_SIZE;
+ key = sum;
+ }
+
+
+ memset(ctx->ipad, 0x36, SHA256_BLOCK_SIZE);
+ memset(ctx->opad, 0x5C, SHA256_BLOCK_SIZE);
+
+ for (i = 0; i < keylen; i++) {
+ ctx->ipad[i] = (uint8_t)(ctx->ipad[i] ^ key[i]);
+ ctx->opad[i] = (uint8_t)(ctx->opad[i] ^ key[i]);
+ }
+
+ memset(sum, 0, sizeof(sum));
+
+ mbedtls_sha256_starts((mbedtls_sha256_context *) ctx->md_ctx, 0);
+ mbedtls_sha256_update((mbedtls_sha256_context *) ctx->md_ctx, ctx->ipad, SHA256_BLOCK_SIZE);
+
+ return 0;
+
+}
+
+int32_t hmac_sha256_update(hmac_sha256_context_t *ctx, const uint8_t *input, uint32_t ilen)
+{
+ mbedtls_sha256_update((mbedtls_sha256_context *) ctx->md_ctx, input, ilen);
+ return 0;
+}
+
+int32_t hmac_sha256_finish(hmac_sha256_context_t *ctx, uint8_t *output)
+{
+ uint8_t tmp[SHA256_DIGEST_SIZE];
+
+ mbedtls_sha256_finish((mbedtls_sha256_context *) ctx->md_ctx, tmp);
+ mbedtls_sha256_starts((mbedtls_sha256_context *) ctx->md_ctx, 0);
+ mbedtls_sha256_update((mbedtls_sha256_context *) ctx->md_ctx, ctx->opad, SHA256_BLOCK_SIZE);
+ mbedtls_sha256_update((mbedtls_sha256_context *) ctx->md_ctx, tmp, SHA256_DIGEST_SIZE);
+ mbedtls_sha256_finish((mbedtls_sha256_context *) ctx->md_ctx, output);
+
+ return 0;
+}
+
+int32_t hmac_sha256_reset(hmac_sha256_context_t *ctx)
+{
+
+ mbedtls_sha256_starts((mbedtls_sha256_context *) ctx->md_ctx, 0);
+ mbedtls_sha256_update((mbedtls_sha256_context *) ctx->md_ctx, ctx->ipad, SHA256_BLOCK_SIZE);
+
+ return 0 ;
+}
+
+int32_t hmac_sha256_crypt(const uint8_t *key, uint32_t keylen, const uint8_t *input, uint32_t ilen, uint8_t *output)
+{
+ hmac_sha256_context_t ctx;
+ mbedtls_sha256_context sha_ctx;
+ int32_t ret;
+
+ hmac_sha256_init(&ctx);
+ memset(&sha_ctx, 0, sizeof(sha_ctx));
+ ctx.md_ctx = &sha_ctx;
+ if ((ret = hmac_sha256_setup(&ctx, 1)) != 0) {
+ return (ret);
+ }
+
+ hmac_sha256_starts(&ctx, key, keylen);
+ hmac_sha256_update(&ctx, input, ilen);
+ hmac_sha256_finish(&ctx, output);
+
+ return (0);
+}
+
+uint32_t sha256_hkdf(const uint8_t *key, uint32_t key_len,
+ const uint8_t *salt, uint32_t salt_len,
+ const uint8_t *info, uint32_t info_len,
+ uint8_t *out, uint32_t out_len)
+{
+ const uint8_t null_salt[32] = {0};
+ uint8_t PRK[32];
+ uint8_t T_n[32];
+ uint32_t loop;
+ uint32_t temp_len;
+
+ // Step 1: HKDF-Extract(salt, IKM) -> PRK
+ if (salt == NULL) {
+ hmac_sha256_crypt(null_salt, 32, key, key_len, PRK);
+ } else {
+ hmac_sha256_crypt(salt, salt_len, key, key_len, PRK);
+ }
+
+ // Step 2: HKDF-Expand(PRK, info, L) -> OKM
+ //T(0) = empty string (zero length)
+ //T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)
+ //T(2) = HMAC-Hash(PRK, T(1) | info | 0x02)
+ //T(3) = HMAC-Hash(PRK, T(2) | info | 0x03)
+
+ uint8_t temp[32 + info_len + 1];
+ memset(temp, 0, 32 + info_len + 1);
+ loop = CEIL_DIV(out_len, 32);
+
+ for (int32_t i = 0; i < loop ; i++) {
+ if (i == 0) {
+ temp_len = 0;
+ } else {
+ memcpy(temp, T_n, 32);
+ temp_len = 32;
+ }
+
+ memcpy(temp + temp_len, info, info_len);
+ temp_len += info_len;
+
+ temp[temp_len] = i + 1;
+ temp_len += 1;
+
+ hmac_sha256_crypt(PRK, 32, temp, temp_len, T_n);
+
+ memcpy(out + 32 * i, T_n, MIN(32, out_len));
+ out_len -= 32;
+ }
+
+ return 0;
+}
+
+
+
+/***************************************************this is for test************************************************/
+#if (HMAC_SELF_TEST == 1)
+
+///////////////////////////////////////////
+//Hash = SHA-256
+//IKM = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b (22 octets)
+//salt = 0x000102030405060708090a0b0c (13 octets)
+//info = 0xf0f1f2f3f4f5f6f7f8f9 (10 octets)
+//L = 42
+//
+//PRK = 0x077709362c2e32df0ddc3f0dc47bba63
+// 90b6c73bb50f9c3122ec844ad7c2b3e5 (32 octets)
+//OKM = 0x3cb25f25faacd57a90434f64d0362f2a
+// 2d2d0a90cf1a5a4c5db02d56ecc4c5bf
+// 34007208d5b887185865 (42 octets)
+
+#if 0
+uint8_t salt[13] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c};
+uint8_t info[10] = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9};
+uint8_t key_material[22] = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b};
+#endif
+
+
+void hkdf_test(void)
+{
+ uint8_t key_material[80] = {0x00,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
+ };
+
+ uint8_t salt[80] = {0x60,
+ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
+ 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80,
+ 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90,
+ 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0,
+ 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf
+ };
+
+ uint8_t info[80] = {0xb0,
+ 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0,
+ 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
+ 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0,
+ 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+
+ uint8_t expect[82] = {
+ 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34,
+ 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8, 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c,
+ 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09,
+ 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8, 0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71,
+ 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87, 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f,
+ 0x1d, 0x87
+ };
+ uint8_t out_key[82];
+
+ sha256_hkdf(key_material, sizeof(key_material), salt, sizeof(salt), info, sizeof(info), out_key, 82);
+
+ hmac_printf("SHA256-HKDF TEST: ");
+ if (memcmp(expect, out_key, 82) == 0) {
+ hmac_printf(" PASS\n");
+ } else {
+ hmac_printf(" FAIL\n");
+ }
+
+}
+
+
+#endif
+
diff --git a/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/hmac.h b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/hmac.h
new file mode 100644
index 0000000..0c483c3
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/hmac.h
@@ -0,0 +1,49 @@
+#ifndef HMAC_H
+#define HMAC_H
+
+#include
+#include
+#include
+
+
+#define HMAC_SELF_TEST 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * \brief Output = Generic_HMAC( hmac key, input buffer )
+ *
+ * \param md_info message digest info
+ * \param key HMAC secret key
+ * \param keylen length of the HMAC key in bytes
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ * \param output Generic HMAC-result
+ *
+ * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter
+ * verification fails.
+ */
+int32_t hmac_sha1_crypt(const uint8_t *key, uint32_t keylen, const uint8_t *input, uint32_t ilen, uint8_t *output);
+
+
+int32_t hmac_sha256_crypt(const uint8_t *key, uint32_t keylen, const uint8_t *input, uint32_t ilen, uint8_t *output);
+
+
+uint32_t sha256_hkdf(const uint8_t *key, uint32_t key_len, const uint8_t *salt, uint32_t salt_len, const uint8_t *info, uint32_t info_len,
+ uint8_t *out, uint32_t out_len);
+
+#if (HMAC_SELF_TEST == 1)
+
+void hkdf_test(void);
+
+#endif /* HMAC_SELF_TEST */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* hmac.h */
diff --git a/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/md5.c b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/md5.c
new file mode 100644
index 0000000..6e1b8de
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/md5.c
@@ -0,0 +1,504 @@
+/*
+ * RFC 1321 compliant MD5 implementation
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+/*
+ * The MD5 algorithm was designed by Ron Rivest in 1991.
+ *
+ * http://www.ietf.org/rfc/rfc1321.txt
+ */
+
+#define MBEDTLS_MD5_C
+
+#if defined(MBEDTLS_MD5_C)
+
+#include "md5.h"
+#include
+
+#define mbedtls_printf //printf
+
+
+#if !defined(MBEDTLS_MD5_ALT)
+
+/*
+ * 32-bit integer manipulation macros (little endian)
+ */
+#ifndef GET_UINT32_LE
+#define GET_UINT32_LE(n,b,i) \
+{ \
+ (n) = ( (uint32_t) (b)[(i) ] ) \
+ | ( (uint32_t) (b)[(i) + 1] << 8 ) \
+ | ( (uint32_t) (b)[(i) + 2] << 16 ) \
+ | ( (uint32_t) (b)[(i) + 3] << 24 ); \
+}
+#endif
+
+#ifndef PUT_UINT32_LE
+#define PUT_UINT32_LE(n,b,i) \
+{ \
+ (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \
+ (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \
+ (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \
+ (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \
+}
+#endif
+
+void mbedtls_md5_init(mbedtls_md5_context *ctx)
+{
+ memset(ctx, 0, sizeof(mbedtls_md5_context));
+}
+
+void mbedtls_md5_free(mbedtls_md5_context *ctx)
+{
+ if (ctx == NULL) {
+ return;
+ }
+
+ //mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md5_context ) );
+ memset(ctx, 0, sizeof(mbedtls_md5_context));
+}
+
+void mbedtls_md5_clone(mbedtls_md5_context *dst,
+ const mbedtls_md5_context *src)
+{
+ *dst = *src;
+}
+
+/*
+ * MD5 context setup
+ */
+int mbedtls_md5_starts_ret(mbedtls_md5_context *ctx)
+{
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+
+ return (0);
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+void mbedtls_md5_starts(mbedtls_md5_context *ctx)
+{
+ mbedtls_md5_starts_ret(ctx);
+}
+#endif
+
+#if !defined(MBEDTLS_MD5_PROCESS_ALT)
+int mbedtls_internal_md5_process(mbedtls_md5_context *ctx,
+ const unsigned char data[64])
+{
+ uint32_t X[16], A, B, C, D;
+
+ GET_UINT32_LE(X[ 0], data, 0);
+ GET_UINT32_LE(X[ 1], data, 4);
+ GET_UINT32_LE(X[ 2], data, 8);
+ GET_UINT32_LE(X[ 3], data, 12);
+ GET_UINT32_LE(X[ 4], data, 16);
+ GET_UINT32_LE(X[ 5], data, 20);
+ GET_UINT32_LE(X[ 6], data, 24);
+ GET_UINT32_LE(X[ 7], data, 28);
+ GET_UINT32_LE(X[ 8], data, 32);
+ GET_UINT32_LE(X[ 9], data, 36);
+ GET_UINT32_LE(X[10], data, 40);
+ GET_UINT32_LE(X[11], data, 44);
+ GET_UINT32_LE(X[12], data, 48);
+ GET_UINT32_LE(X[13], data, 52);
+ GET_UINT32_LE(X[14], data, 56);
+ GET_UINT32_LE(X[15], data, 60);
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define P(a,b,c,d,k,s,t) \
+{ \
+ a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
+}
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+
+ P(A, B, C, D, 0, 7, 0xD76AA478);
+ P(D, A, B, C, 1, 12, 0xE8C7B756);
+ P(C, D, A, B, 2, 17, 0x242070DB);
+ P(B, C, D, A, 3, 22, 0xC1BDCEEE);
+ P(A, B, C, D, 4, 7, 0xF57C0FAF);
+ P(D, A, B, C, 5, 12, 0x4787C62A);
+ P(C, D, A, B, 6, 17, 0xA8304613);
+ P(B, C, D, A, 7, 22, 0xFD469501);
+ P(A, B, C, D, 8, 7, 0x698098D8);
+ P(D, A, B, C, 9, 12, 0x8B44F7AF);
+ P(C, D, A, B, 10, 17, 0xFFFF5BB1);
+ P(B, C, D, A, 11, 22, 0x895CD7BE);
+ P(A, B, C, D, 12, 7, 0x6B901122);
+ P(D, A, B, C, 13, 12, 0xFD987193);
+ P(C, D, A, B, 14, 17, 0xA679438E);
+ P(B, C, D, A, 15, 22, 0x49B40821);
+
+#undef F
+
+#define F(x,y,z) (y ^ (z & (x ^ y)))
+
+ P(A, B, C, D, 1, 5, 0xF61E2562);
+ P(D, A, B, C, 6, 9, 0xC040B340);
+ P(C, D, A, B, 11, 14, 0x265E5A51);
+ P(B, C, D, A, 0, 20, 0xE9B6C7AA);
+ P(A, B, C, D, 5, 5, 0xD62F105D);
+ P(D, A, B, C, 10, 9, 0x02441453);
+ P(C, D, A, B, 15, 14, 0xD8A1E681);
+ P(B, C, D, A, 4, 20, 0xE7D3FBC8);
+ P(A, B, C, D, 9, 5, 0x21E1CDE6);
+ P(D, A, B, C, 14, 9, 0xC33707D6);
+ P(C, D, A, B, 3, 14, 0xF4D50D87);
+ P(B, C, D, A, 8, 20, 0x455A14ED);
+ P(A, B, C, D, 13, 5, 0xA9E3E905);
+ P(D, A, B, C, 2, 9, 0xFCEFA3F8);
+ P(C, D, A, B, 7, 14, 0x676F02D9);
+ P(B, C, D, A, 12, 20, 0x8D2A4C8A);
+
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+
+ P(A, B, C, D, 5, 4, 0xFFFA3942);
+ P(D, A, B, C, 8, 11, 0x8771F681);
+ P(C, D, A, B, 11, 16, 0x6D9D6122);
+ P(B, C, D, A, 14, 23, 0xFDE5380C);
+ P(A, B, C, D, 1, 4, 0xA4BEEA44);
+ P(D, A, B, C, 4, 11, 0x4BDECFA9);
+ P(C, D, A, B, 7, 16, 0xF6BB4B60);
+ P(B, C, D, A, 10, 23, 0xBEBFBC70);
+ P(A, B, C, D, 13, 4, 0x289B7EC6);
+ P(D, A, B, C, 0, 11, 0xEAA127FA);
+ P(C, D, A, B, 3, 16, 0xD4EF3085);
+ P(B, C, D, A, 6, 23, 0x04881D05);
+ P(A, B, C, D, 9, 4, 0xD9D4D039);
+ P(D, A, B, C, 12, 11, 0xE6DB99E5);
+ P(C, D, A, B, 15, 16, 0x1FA27CF8);
+ P(B, C, D, A, 2, 23, 0xC4AC5665);
+
+#undef F
+
+#define F(x,y,z) (y ^ (x | ~z))
+
+ P(A, B, C, D, 0, 6, 0xF4292244);
+ P(D, A, B, C, 7, 10, 0x432AFF97);
+ P(C, D, A, B, 14, 15, 0xAB9423A7);
+ P(B, C, D, A, 5, 21, 0xFC93A039);
+ P(A, B, C, D, 12, 6, 0x655B59C3);
+ P(D, A, B, C, 3, 10, 0x8F0CCC92);
+ P(C, D, A, B, 10, 15, 0xFFEFF47D);
+ P(B, C, D, A, 1, 21, 0x85845DD1);
+ P(A, B, C, D, 8, 6, 0x6FA87E4F);
+ P(D, A, B, C, 15, 10, 0xFE2CE6E0);
+ P(C, D, A, B, 6, 15, 0xA3014314);
+ P(B, C, D, A, 13, 21, 0x4E0811A1);
+ P(A, B, C, D, 4, 6, 0xF7537E82);
+ P(D, A, B, C, 11, 10, 0xBD3AF235);
+ P(C, D, A, B, 2, 15, 0x2AD7D2BB);
+ P(B, C, D, A, 9, 21, 0xEB86D391);
+
+#undef F
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+
+ return (0);
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+void mbedtls_md5_process(mbedtls_md5_context *ctx,
+ const unsigned char data[64])
+{
+ mbedtls_internal_md5_process(ctx, data);
+}
+#endif
+#endif /* !MBEDTLS_MD5_PROCESS_ALT */
+
+/*
+ * MD5 process buffer
+ */
+int mbedtls_md5_update_ret(mbedtls_md5_context *ctx,
+ const unsigned char *input,
+ size_t ilen)
+{
+ int ret;
+ size_t fill;
+ uint32_t left;
+
+ if (ilen == 0) {
+ return (0);
+ }
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += (uint32_t) ilen;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if (ctx->total[0] < (uint32_t) ilen) {
+ ctx->total[1]++;
+ }
+
+ if (left && ilen >= fill) {
+ memcpy((void *)(ctx->buffer + left), input, fill);
+ if ((ret = mbedtls_internal_md5_process(ctx, ctx->buffer)) != 0) {
+ return (ret);
+ }
+
+ input += fill;
+ ilen -= fill;
+ left = 0;
+ }
+
+ while (ilen >= 64) {
+ if ((ret = mbedtls_internal_md5_process(ctx, input)) != 0) {
+ return (ret);
+ }
+
+ input += 64;
+ ilen -= 64;
+ }
+
+ if (ilen > 0) {
+ memcpy((void *)(ctx->buffer + left), input, ilen);
+ }
+
+ return (0);
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+void mbedtls_md5_update(mbedtls_md5_context *ctx,
+ const unsigned char *input,
+ size_t ilen)
+{
+ mbedtls_md5_update_ret(ctx, input, ilen);
+}
+#endif
+
+/*
+ * MD5 final digest
+ */
+int mbedtls_md5_finish_ret(mbedtls_md5_context *ctx,
+ unsigned char output[16])
+{
+ int ret;
+ uint32_t used;
+ uint32_t high, low;
+
+ /*
+ * Add padding: 0x80 then 0x00 until 8 bytes remain for the length
+ */
+ used = ctx->total[0] & 0x3F;
+
+ ctx->buffer[used++] = 0x80;
+
+ if (used <= 56) {
+ /* Enough room for padding + length in current block */
+ memset(ctx->buffer + used, 0, 56 - used);
+ } else {
+ /* We'll need an extra block */
+ memset(ctx->buffer + used, 0, 64 - used);
+
+ if ((ret = mbedtls_internal_md5_process(ctx, ctx->buffer)) != 0) {
+ return (ret);
+ }
+
+ memset(ctx->buffer, 0, 56);
+ }
+
+ /*
+ * Add message length
+ */
+ high = (ctx->total[0] >> 29)
+ | (ctx->total[1] << 3);
+ low = (ctx->total[0] << 3);
+
+ PUT_UINT32_LE(low, ctx->buffer, 56);
+ PUT_UINT32_LE(high, ctx->buffer, 60);
+
+ if ((ret = mbedtls_internal_md5_process(ctx, ctx->buffer)) != 0) {
+ return (ret);
+ }
+
+ /*
+ * Output final state
+ */
+ PUT_UINT32_LE(ctx->state[0], output, 0);
+ PUT_UINT32_LE(ctx->state[1], output, 4);
+ PUT_UINT32_LE(ctx->state[2], output, 8);
+ PUT_UINT32_LE(ctx->state[3], output, 12);
+
+ return (0);
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+void mbedtls_md5_finish(mbedtls_md5_context *ctx,
+ unsigned char output[16])
+{
+ mbedtls_md5_finish_ret(ctx, output);
+}
+#endif
+
+#endif /* !MBEDTLS_MD5_ALT */
+
+/*
+ * output = MD5( input buffer )
+ */
+int mbedtls_md5_ret(const unsigned char *input,
+ size_t ilen,
+ unsigned char output[16])
+{
+ int ret;
+ mbedtls_md5_context ctx;
+
+ mbedtls_md5_init(&ctx);
+
+ if ((ret = mbedtls_md5_starts_ret(&ctx)) != 0) {
+ goto exit;
+ }
+
+ if ((ret = mbedtls_md5_update_ret(&ctx, input, ilen)) != 0) {
+ goto exit;
+ }
+
+ if ((ret = mbedtls_md5_finish_ret(&ctx, output)) != 0) {
+ goto exit;
+ }
+
+exit:
+ mbedtls_md5_free(&ctx);
+
+ return (ret);
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+void mbedtls_md5(const unsigned char *input,
+ size_t ilen,
+ unsigned char output[16])
+{
+ mbedtls_md5_ret(input, ilen, output);
+}
+#endif
+
+#if defined(MBEDTLS_SELF_TEST)
+/*
+ * RFC 1321 test vectors
+ */
+static const unsigned char md5_test_buf[7][81] = {
+ { "" },
+ { "a" },
+ { "abc" },
+ { "message digest" },
+ { "abcdefghijklmnopqrstuvwxyz" },
+ { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
+ {
+ "12345678901234567890123456789012345678901234567890123456789012"
+ "345678901234567890"
+ }
+};
+
+static const size_t md5_test_buflen[7] = {
+ 0, 1, 3, 14, 26, 62, 80
+};
+
+static const unsigned char md5_test_sum[7][16] = {
+ {
+ 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04,
+ 0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E
+ },
+ {
+ 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8,
+ 0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61
+ },
+ {
+ 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0,
+ 0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72
+ },
+ {
+ 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D,
+ 0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0
+ },
+ {
+ 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00,
+ 0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B
+ },
+ {
+ 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5,
+ 0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F
+ },
+ {
+ 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55,
+ 0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A
+ }
+};
+
+/*
+ * Checkup routine
+ */
+int mbedtls_md5_self_test(int verbose)
+{
+ int i, ret = 0;
+ unsigned char md5sum[16];
+
+ for (i = 0; i < 7; i++) {
+ if (verbose != 0) {
+ mbedtls_printf(" MD5 test #%d: ", i + 1);
+ }
+
+ ret = mbedtls_md5_ret(md5_test_buf[i], md5_test_buflen[i], md5sum);
+ if (ret != 0) {
+ goto fail;
+ }
+
+ if (memcmp(md5sum, md5_test_sum[i], 16) != 0) {
+ ret = 1;
+ goto fail;
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("passed\n");
+ }
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("\n");
+ }
+
+ return (0);
+
+fail:
+ if (verbose != 0) {
+ mbedtls_printf("failed\n");
+ }
+
+ return (ret);
+}
+
+#endif /* MBEDTLS_SELF_TEST */
+
+#endif /* MBEDTLS_MD5_C */
diff --git a/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/md5.h b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/md5.h
new file mode 100644
index 0000000..6e66999
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/md5.h
@@ -0,0 +1,309 @@
+/**
+ * \file md5.h
+ *
+ * \brief MD5 message digest algorithm (hash function)
+ *
+ * \warning MD5 is considered a weak message digest and its use constitutes a
+ * security risk. We recommend considering stronger message
+ * digests instead.
+ */
+/*
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_MD5_H
+#define MBEDTLS_MD5_H
+
+
+#include
+#include
+
+
+//#define MBEDTLS_MD5_SELF_TEST
+
+
+/* MBEDTLS_ERR_MD5_HW_ACCEL_FAILED is deprecated and should not be used. */
+#define MBEDTLS_ERR_MD5_HW_ACCEL_FAILED -0x002F /**< MD5 hardware accelerator failed */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(MBEDTLS_MD5_ALT)
+// Regular implementation
+//
+
+/**
+ * \brief MD5 context structure
+ *
+ * \warning MD5 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ */
+typedef struct mbedtls_md5_context {
+ uint32_t total[2]; /*!< number of bytes processed */
+ uint32_t state[4]; /*!< intermediate digest state */
+ unsigned char buffer[64]; /*!< data block being processed */
+}
+mbedtls_md5_context;
+
+#else /* MBEDTLS_MD5_ALT */
+#include "md5_alt.h"
+#endif /* MBEDTLS_MD5_ALT */
+
+/**
+ * \brief Initialize MD5 context
+ *
+ * \param ctx MD5 context to be initialized
+ *
+ * \warning MD5 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ */
+void mbedtls_md5_init(mbedtls_md5_context *ctx);
+
+/**
+ * \brief Clear MD5 context
+ *
+ * \param ctx MD5 context to be cleared
+ *
+ * \warning MD5 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ */
+void mbedtls_md5_free(mbedtls_md5_context *ctx);
+
+/**
+ * \brief Clone (the state of) an MD5 context
+ *
+ * \param dst The destination context
+ * \param src The context to be cloned
+ *
+ * \warning MD5 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ */
+void mbedtls_md5_clone(mbedtls_md5_context *dst,
+ const mbedtls_md5_context *src);
+
+/**
+ * \brief MD5 context setup
+ *
+ * \param ctx context to be initialized
+ *
+ * \return 0 if successful
+ *
+ * \warning MD5 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ */
+int mbedtls_md5_starts_ret(mbedtls_md5_context *ctx);
+
+/**
+ * \brief MD5 process buffer
+ *
+ * \param ctx MD5 context
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ *
+ * \return 0 if successful
+ *
+ * \warning MD5 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ */
+int mbedtls_md5_update_ret(mbedtls_md5_context *ctx,
+ const unsigned char *input,
+ size_t ilen);
+
+/**
+ * \brief MD5 final digest
+ *
+ * \param ctx MD5 context
+ * \param output MD5 checksum result
+ *
+ * \return 0 if successful
+ *
+ * \warning MD5 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ */
+int mbedtls_md5_finish_ret(mbedtls_md5_context *ctx,
+ unsigned char output[16]);
+
+/**
+ * \brief MD5 process data block (internal use only)
+ *
+ * \param ctx MD5 context
+ * \param data buffer holding one block of data
+ *
+ * \return 0 if successful
+ *
+ * \warning MD5 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ */
+int mbedtls_internal_md5_process(mbedtls_md5_context *ctx,
+ const unsigned char data[64]);
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+#if defined(MBEDTLS_DEPRECATED_WARNING)
+#define MBEDTLS_DEPRECATED __attribute__((deprecated))
+#else
+#define MBEDTLS_DEPRECATED
+#endif
+/**
+ * \brief MD5 context setup
+ *
+ * \deprecated Superseded by mbedtls_md5_starts_ret() in 2.7.0
+ *
+ * \param ctx context to be initialized
+ *
+ * \warning MD5 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ */
+MBEDTLS_DEPRECATED void mbedtls_md5_starts(mbedtls_md5_context *ctx);
+
+/**
+ * \brief MD5 process buffer
+ *
+ * \deprecated Superseded by mbedtls_md5_update_ret() in 2.7.0
+ *
+ * \param ctx MD5 context
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ *
+ * \warning MD5 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ */
+MBEDTLS_DEPRECATED void mbedtls_md5_update(mbedtls_md5_context *ctx,
+ const unsigned char *input,
+ size_t ilen);
+
+/**
+ * \brief MD5 final digest
+ *
+ * \deprecated Superseded by mbedtls_md5_finish_ret() in 2.7.0
+ *
+ * \param ctx MD5 context
+ * \param output MD5 checksum result
+ *
+ * \warning MD5 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ */
+MBEDTLS_DEPRECATED void mbedtls_md5_finish(mbedtls_md5_context *ctx,
+ unsigned char output[16]);
+
+/**
+ * \brief MD5 process data block (internal use only)
+ *
+ * \deprecated Superseded by mbedtls_internal_md5_process() in 2.7.0
+ *
+ * \param ctx MD5 context
+ * \param data buffer holding one block of data
+ *
+ * \warning MD5 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ */
+MBEDTLS_DEPRECATED void mbedtls_md5_process(mbedtls_md5_context *ctx,
+ const unsigned char data[64]);
+
+#undef MBEDTLS_DEPRECATED
+#endif /* !MBEDTLS_DEPRECATED_REMOVED */
+
+/**
+ * \brief Output = MD5( input buffer )
+ *
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ * \param output MD5 checksum result
+ *
+ * \return 0 if successful
+ *
+ * \warning MD5 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ */
+int mbedtls_md5_ret(const unsigned char *input,
+ size_t ilen,
+ unsigned char output[16]);
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+#if defined(MBEDTLS_DEPRECATED_WARNING)
+#define MBEDTLS_DEPRECATED __attribute__((deprecated))
+#else
+#define MBEDTLS_DEPRECATED
+#endif
+/**
+ * \brief Output = MD5( input buffer )
+ *
+ * \deprecated Superseded by mbedtls_md5_ret() in 2.7.0
+ *
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ * \param output MD5 checksum result
+ *
+ * \warning MD5 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ */
+MBEDTLS_DEPRECATED void mbedtls_md5(const unsigned char *input,
+ size_t ilen,
+ unsigned char output[16]);
+
+#undef MBEDTLS_DEPRECATED
+#endif /* !MBEDTLS_DEPRECATED_REMOVED */
+
+#if defined(MBEDTLS_SELF_TEST)
+
+/**
+ * \brief Checkup routine
+ *
+ * \return 0 if successful, or 1 if the test failed
+ *
+ * \warning MD5 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ */
+int mbedtls_md5_self_test(int verbose);
+
+#endif /* MBEDTLS_SELF_TEST */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* mbedtls_md5.h */
diff --git a/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/sha1.c b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/sha1.c
new file mode 100644
index 0000000..c3cde4a
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/sha1.c
@@ -0,0 +1,575 @@
+/*
+ * FIPS-180-1 compliant SHA-1 implementation
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+/*
+ * The SHA-1 standard was published by NIST in 1993.
+ *
+ * http://www.itl.nist.gov/fipspubs/fip180-1.htm
+ */
+
+#define MBEDTLS_SHA1_C
+
+#if defined(MBEDTLS_SHA1_C)
+
+#include "sha1.h"
+
+#include
+
+#define mbedtls_printf printf
+
+/* Internal macros meant to be called only from within the library. */
+#define MBEDTLS_INTERNAL_VALIDATE_RET( cond, ret ) do { } while( 0 )
+#define MBEDTLS_INTERNAL_VALIDATE( cond ) do { } while( 0 )
+
+#define SHA1_VALIDATE_RET(cond) \
+ MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA1_BAD_INPUT_DATA )
+
+#define SHA1_VALIDATE(cond) MBEDTLS_INTERNAL_VALIDATE( cond )
+
+#if !defined(MBEDTLS_SHA1_ALT)
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n,b,i) \
+{ \
+ (n) = ( (uint32_t) (b)[(i) ] << 24 ) \
+ | ( (uint32_t) (b)[(i) + 1] << 16 ) \
+ | ( (uint32_t) (b)[(i) + 2] << 8 ) \
+ | ( (uint32_t) (b)[(i) + 3] ); \
+}
+#endif
+
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n,b,i) \
+{ \
+ (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
+ (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
+ (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
+ (b)[(i) + 3] = (unsigned char) ( (n) ); \
+}
+#endif
+
+void mbedtls_sha1_init(mbedtls_sha1_context *ctx)
+{
+ SHA1_VALIDATE(ctx != NULL);
+
+ memset(ctx, 0, sizeof(mbedtls_sha1_context));
+}
+
+void mbedtls_sha1_free(mbedtls_sha1_context *ctx)
+{
+ if (ctx == NULL) {
+ return;
+ }
+
+ //mbedtls_platform_zeroize( ctx, sizeof( mbedtls_sha1_context ) );
+ memset(ctx, 0, sizeof(mbedtls_sha1_context));
+}
+
+void mbedtls_sha1_clone(mbedtls_sha1_context *dst,
+ const mbedtls_sha1_context *src)
+{
+ SHA1_VALIDATE(dst != NULL);
+ SHA1_VALIDATE(src != NULL);
+
+ *dst = *src;
+}
+
+/*
+ * SHA-1 context setup
+ */
+int mbedtls_sha1_starts_ret(mbedtls_sha1_context *ctx)
+{
+ SHA1_VALIDATE_RET(ctx != NULL);
+
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+ ctx->state[4] = 0xC3D2E1F0;
+
+ return (0);
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+void mbedtls_sha1_starts(mbedtls_sha1_context *ctx)
+{
+ mbedtls_sha1_starts_ret(ctx);
+}
+#endif
+
+#if !defined(MBEDTLS_SHA1_PROCESS_ALT)
+int mbedtls_internal_sha1_process(mbedtls_sha1_context *ctx,
+ const unsigned char data[64])
+{
+ uint32_t temp, W[16], A, B, C, D, E;
+
+ SHA1_VALIDATE_RET(ctx != NULL);
+ SHA1_VALIDATE_RET((const unsigned char *)data != NULL);
+
+ GET_UINT32_BE(W[ 0], data, 0);
+ GET_UINT32_BE(W[ 1], data, 4);
+ GET_UINT32_BE(W[ 2], data, 8);
+ GET_UINT32_BE(W[ 3], data, 12);
+ GET_UINT32_BE(W[ 4], data, 16);
+ GET_UINT32_BE(W[ 5], data, 20);
+ GET_UINT32_BE(W[ 6], data, 24);
+ GET_UINT32_BE(W[ 7], data, 28);
+ GET_UINT32_BE(W[ 8], data, 32);
+ GET_UINT32_BE(W[ 9], data, 36);
+ GET_UINT32_BE(W[10], data, 40);
+ GET_UINT32_BE(W[11], data, 44);
+ GET_UINT32_BE(W[12], data, 48);
+ GET_UINT32_BE(W[13], data, 52);
+ GET_UINT32_BE(W[14], data, 56);
+ GET_UINT32_BE(W[15], data, 60);
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define R(t) \
+( \
+ temp = W[( t - 3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \
+ W[( t - 14 ) & 0x0F] ^ W[ t & 0x0F], \
+ ( W[t & 0x0F] = S(temp,1) ) \
+)
+
+#define P(a,b,c,d,e,x) \
+{ \
+ e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \
+}
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+ E = ctx->state[4];
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+#define K 0x5A827999
+
+ P(A, B, C, D, E, W[0]);
+ P(E, A, B, C, D, W[1]);
+ P(D, E, A, B, C, W[2]);
+ P(C, D, E, A, B, W[3]);
+ P(B, C, D, E, A, W[4]);
+ P(A, B, C, D, E, W[5]);
+ P(E, A, B, C, D, W[6]);
+ P(D, E, A, B, C, W[7]);
+ P(C, D, E, A, B, W[8]);
+ P(B, C, D, E, A, W[9]);
+ P(A, B, C, D, E, W[10]);
+ P(E, A, B, C, D, W[11]);
+ P(D, E, A, B, C, W[12]);
+ P(C, D, E, A, B, W[13]);
+ P(B, C, D, E, A, W[14]);
+ P(A, B, C, D, E, W[15]);
+ P(E, A, B, C, D, R(16));
+ P(D, E, A, B, C, R(17));
+ P(C, D, E, A, B, R(18));
+ P(B, C, D, E, A, R(19));
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0x6ED9EBA1
+
+ P(A, B, C, D, E, R(20));
+ P(E, A, B, C, D, R(21));
+ P(D, E, A, B, C, R(22));
+ P(C, D, E, A, B, R(23));
+ P(B, C, D, E, A, R(24));
+ P(A, B, C, D, E, R(25));
+ P(E, A, B, C, D, R(26));
+ P(D, E, A, B, C, R(27));
+ P(C, D, E, A, B, R(28));
+ P(B, C, D, E, A, R(29));
+ P(A, B, C, D, E, R(30));
+ P(E, A, B, C, D, R(31));
+ P(D, E, A, B, C, R(32));
+ P(C, D, E, A, B, R(33));
+ P(B, C, D, E, A, R(34));
+ P(A, B, C, D, E, R(35));
+ P(E, A, B, C, D, R(36));
+ P(D, E, A, B, C, R(37));
+ P(C, D, E, A, B, R(38));
+ P(B, C, D, E, A, R(39));
+
+#undef K
+#undef F
+
+#define F(x,y,z) ((x & y) | (z & (x | y)))
+#define K 0x8F1BBCDC
+
+ P(A, B, C, D, E, R(40));
+ P(E, A, B, C, D, R(41));
+ P(D, E, A, B, C, R(42));
+ P(C, D, E, A, B, R(43));
+ P(B, C, D, E, A, R(44));
+ P(A, B, C, D, E, R(45));
+ P(E, A, B, C, D, R(46));
+ P(D, E, A, B, C, R(47));
+ P(C, D, E, A, B, R(48));
+ P(B, C, D, E, A, R(49));
+ P(A, B, C, D, E, R(50));
+ P(E, A, B, C, D, R(51));
+ P(D, E, A, B, C, R(52));
+ P(C, D, E, A, B, R(53));
+ P(B, C, D, E, A, R(54));
+ P(A, B, C, D, E, R(55));
+ P(E, A, B, C, D, R(56));
+ P(D, E, A, B, C, R(57));
+ P(C, D, E, A, B, R(58));
+ P(B, C, D, E, A, R(59));
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0xCA62C1D6
+
+ P(A, B, C, D, E, R(60));
+ P(E, A, B, C, D, R(61));
+ P(D, E, A, B, C, R(62));
+ P(C, D, E, A, B, R(63));
+ P(B, C, D, E, A, R(64));
+ P(A, B, C, D, E, R(65));
+ P(E, A, B, C, D, R(66));
+ P(D, E, A, B, C, R(67));
+ P(C, D, E, A, B, R(68));
+ P(B, C, D, E, A, R(69));
+ P(A, B, C, D, E, R(70));
+ P(E, A, B, C, D, R(71));
+ P(D, E, A, B, C, R(72));
+ P(C, D, E, A, B, R(73));
+ P(B, C, D, E, A, R(74));
+ P(A, B, C, D, E, R(75));
+ P(E, A, B, C, D, R(76));
+ P(D, E, A, B, C, R(77));
+ P(C, D, E, A, B, R(78));
+ P(B, C, D, E, A, R(79));
+
+#undef K
+#undef F
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+ ctx->state[4] += E;
+
+ return (0);
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+void mbedtls_sha1_process(mbedtls_sha1_context *ctx,
+ const unsigned char data[64])
+{
+ mbedtls_internal_sha1_process(ctx, data);
+}
+#endif
+#endif /* !MBEDTLS_SHA1_PROCESS_ALT */
+
+/*
+ * SHA-1 process buffer
+ */
+int mbedtls_sha1_update_ret(mbedtls_sha1_context *ctx,
+ const unsigned char *input,
+ size_t ilen)
+{
+ int ret;
+ size_t fill;
+ uint32_t left;
+
+ SHA1_VALIDATE_RET(ctx != NULL);
+ SHA1_VALIDATE_RET(ilen == 0 || input != NULL);
+
+ if (ilen == 0) {
+ return (0);
+ }
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += (uint32_t) ilen;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if (ctx->total[0] < (uint32_t) ilen) {
+ ctx->total[1]++;
+ }
+
+ if (left && ilen >= fill) {
+ memcpy((void *)(ctx->buffer + left), input, fill);
+
+ if ((ret = mbedtls_internal_sha1_process(ctx, ctx->buffer)) != 0) {
+ return (ret);
+ }
+
+ input += fill;
+ ilen -= fill;
+ left = 0;
+ }
+
+ while (ilen >= 64) {
+ if ((ret = mbedtls_internal_sha1_process(ctx, input)) != 0) {
+ return (ret);
+ }
+
+ input += 64;
+ ilen -= 64;
+ }
+
+ if (ilen > 0) {
+ memcpy((void *)(ctx->buffer + left), input, ilen);
+ }
+
+ return (0);
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+void mbedtls_sha1_update(mbedtls_sha1_context *ctx,
+ const unsigned char *input,
+ size_t ilen)
+{
+ mbedtls_sha1_update_ret(ctx, input, ilen);
+}
+#endif
+
+/*
+ * SHA-1 final digest
+ */
+int mbedtls_sha1_finish_ret(mbedtls_sha1_context *ctx,
+ unsigned char output[20])
+{
+ int ret;
+ uint32_t used;
+ uint32_t high, low;
+
+ SHA1_VALIDATE_RET(ctx != NULL);
+ SHA1_VALIDATE_RET((unsigned char *)output != NULL);
+
+ /*
+ * Add padding: 0x80 then 0x00 until 8 bytes remain for the length
+ */
+ used = ctx->total[0] & 0x3F;
+
+ ctx->buffer[used++] = 0x80;
+
+ if (used <= 56) {
+ /* Enough room for padding + length in current block */
+ memset(ctx->buffer + used, 0, 56 - used);
+ } else {
+ /* We'll need an extra block */
+ memset(ctx->buffer + used, 0, 64 - used);
+
+ if ((ret = mbedtls_internal_sha1_process(ctx, ctx->buffer)) != 0) {
+ return (ret);
+ }
+
+ memset(ctx->buffer, 0, 56);
+ }
+
+ /*
+ * Add message length
+ */
+ high = (ctx->total[0] >> 29)
+ | (ctx->total[1] << 3);
+ low = (ctx->total[0] << 3);
+
+ PUT_UINT32_BE(high, ctx->buffer, 56);
+ PUT_UINT32_BE(low, ctx->buffer, 60);
+
+ if ((ret = mbedtls_internal_sha1_process(ctx, ctx->buffer)) != 0) {
+ return (ret);
+ }
+
+ /*
+ * Output final state
+ */
+ PUT_UINT32_BE(ctx->state[0], output, 0);
+ PUT_UINT32_BE(ctx->state[1], output, 4);
+ PUT_UINT32_BE(ctx->state[2], output, 8);
+ PUT_UINT32_BE(ctx->state[3], output, 12);
+ PUT_UINT32_BE(ctx->state[4], output, 16);
+
+ return (0);
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+void mbedtls_sha1_finish(mbedtls_sha1_context *ctx,
+ unsigned char output[20])
+{
+ mbedtls_sha1_finish_ret(ctx, output);
+}
+#endif
+
+#endif /* !MBEDTLS_SHA1_ALT */
+
+/*
+ * output = SHA-1( input buffer )
+ */
+int mbedtls_sha1_ret(const unsigned char *input,
+ size_t ilen,
+ unsigned char output[20])
+{
+ int ret;
+ mbedtls_sha1_context ctx;
+
+ SHA1_VALIDATE_RET(ilen == 0 || input != NULL);
+ SHA1_VALIDATE_RET((unsigned char *)output != NULL);
+
+ mbedtls_sha1_init(&ctx);
+
+ if ((ret = mbedtls_sha1_starts_ret(&ctx)) != 0) {
+ goto exit;
+ }
+
+ if ((ret = mbedtls_sha1_update_ret(&ctx, input, ilen)) != 0) {
+ goto exit;
+ }
+
+ if ((ret = mbedtls_sha1_finish_ret(&ctx, output)) != 0) {
+ goto exit;
+ }
+
+exit:
+ mbedtls_sha1_free(&ctx);
+
+ return (ret);
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+void mbedtls_sha1(const unsigned char *input,
+ size_t ilen,
+ unsigned char output[20])
+{
+ mbedtls_sha1_ret(input, ilen, output);
+}
+#endif
+
+#if defined(MBEDTLS_SHA1_SELF_TEST)
+/*
+ * FIPS-180-1 test vectors
+ */
+static const unsigned char sha1_test_buf[3][57] = {
+ { "abc" },
+ { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
+ { "" }
+};
+
+static const size_t sha1_test_buflen[3] = {
+ 3, 56, 1000
+};
+
+static const unsigned char sha1_test_sum[3][20] = {
+ {
+ 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,
+ 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D
+ },
+ {
+ 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE,
+ 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1
+ },
+ {
+ 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E,
+ 0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F
+ }
+};
+
+/*
+ * Checkup routine
+ */
+int mbedtls_sha1_self_test(int verbose)
+{
+ int i, j, buflen, ret = 0;
+ unsigned char buf[1024];
+ unsigned char sha1sum[20];
+ mbedtls_sha1_context ctx;
+
+ mbedtls_sha1_init(&ctx);
+
+ /*
+ * SHA-1
+ */
+ for (i = 0; i < 3; i++) {
+ if (verbose != 0) {
+ mbedtls_printf(" SHA-1 test #%d: ", i + 1);
+ }
+
+ if ((ret = mbedtls_sha1_starts_ret(&ctx)) != 0) {
+ goto fail;
+ }
+
+ if (i == 2) {
+ memset(buf, 'a', buflen = 1000);
+
+ for (j = 0; j < 1000; j++) {
+ ret = mbedtls_sha1_update_ret(&ctx, buf, buflen);
+ if (ret != 0) {
+ goto fail;
+ }
+ }
+ } else {
+ ret = mbedtls_sha1_update_ret(&ctx, sha1_test_buf[i],
+ sha1_test_buflen[i]);
+ if (ret != 0) {
+ goto fail;
+ }
+ }
+
+ if ((ret = mbedtls_sha1_finish_ret(&ctx, sha1sum)) != 0) {
+ goto fail;
+ }
+
+ if (memcmp(sha1sum, sha1_test_sum[i], 20) != 0) {
+ ret = 1;
+ goto fail;
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("passed\n");
+ }
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("\n");
+ }
+
+ goto exit;
+
+fail:
+ if (verbose != 0) {
+ mbedtls_printf("failed\n");
+ }
+
+exit:
+ mbedtls_sha1_free(&ctx);
+
+ return (ret);
+}
+
+#endif /* MBEDTLS_SHA1_SELF_TEST */
+
+#endif /* MBEDTLS_SHA1_C */
diff --git a/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/sha1.h b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/sha1.h
new file mode 100644
index 0000000..097d6bb
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/sha1.h
@@ -0,0 +1,347 @@
+/**
+ * \file sha1.h
+ *
+ * \brief This file contains SHA-1 definitions and functions.
+ *
+ * The Secure Hash Algorithm 1 (SHA-1) cryptographic hash function is defined in
+ * FIPS 180-4: Secure Hash Standard (SHS) .
+ *
+ * \warning SHA-1 is considered a weak message digest and its use constitutes
+ * a security risk. We recommend considering stronger message
+ * digests instead.
+ */
+/*
+ * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of Mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_SHA1_H
+#define MBEDTLS_SHA1_H
+
+//#define MBEDTLS_SHA1_SELF_TEST
+
+#include
+#include
+
+/* MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED is deprecated and should not be used. */
+#define MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED -0x0035 /**< SHA-1 hardware accelerator failed */
+#define MBEDTLS_ERR_SHA1_BAD_INPUT_DATA -0x0073 /**< SHA-1 input data was malformed. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(MBEDTLS_SHA1_ALT)
+// Regular implementation
+//
+
+/**
+ * \brief The SHA-1 context structure.
+ *
+ * \warning SHA-1 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ */
+typedef struct mbedtls_sha1_context {
+ uint32_t total[2]; /*!< The number of Bytes processed. */
+ uint32_t state[5]; /*!< The intermediate digest state. */
+ unsigned char buffer[64]; /*!< The data block being processed. */
+}
+mbedtls_sha1_context;
+
+#else /* MBEDTLS_SHA1_ALT */
+#include "sha1_alt.h"
+#endif /* MBEDTLS_SHA1_ALT */
+
+/**
+ * \brief This function initializes a SHA-1 context.
+ *
+ * \warning SHA-1 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ * \param ctx The SHA-1 context to initialize.
+ * This must not be \c NULL.
+ *
+ */
+void mbedtls_sha1_init(mbedtls_sha1_context *ctx);
+
+/**
+ * \brief This function clears a SHA-1 context.
+ *
+ * \warning SHA-1 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ * \param ctx The SHA-1 context to clear. This may be \c NULL,
+ * in which case this function does nothing. If it is
+ * not \c NULL, it must point to an initialized
+ * SHA-1 context.
+ *
+ */
+void mbedtls_sha1_free(mbedtls_sha1_context *ctx);
+
+/**
+ * \brief This function clones the state of a SHA-1 context.
+ *
+ * \warning SHA-1 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ * \param dst The SHA-1 context to clone to. This must be initialized.
+ * \param src The SHA-1 context to clone from. This must be initialized.
+ *
+ */
+void mbedtls_sha1_clone(mbedtls_sha1_context *dst,
+ const mbedtls_sha1_context *src);
+
+/**
+ * \brief This function starts a SHA-1 checksum calculation.
+ *
+ * \warning SHA-1 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ * \param ctx The SHA-1 context to initialize. This must be initialized.
+ *
+ * \return \c 0 on success.
+ * \return A negative error code on failure.
+ *
+ */
+int mbedtls_sha1_starts_ret(mbedtls_sha1_context *ctx);
+
+/**
+ * \brief This function feeds an input buffer into an ongoing SHA-1
+ * checksum calculation.
+ *
+ * \warning SHA-1 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ * \param ctx The SHA-1 context. This must be initialized
+ * and have a hash operation started.
+ * \param input The buffer holding the input data.
+ * This must be a readable buffer of length \p ilen Bytes.
+ * \param ilen The length of the input data \p input in Bytes.
+ *
+ * \return \c 0 on success.
+ * \return A negative error code on failure.
+ */
+int mbedtls_sha1_update_ret(mbedtls_sha1_context *ctx,
+ const unsigned char *input,
+ size_t ilen);
+
+/**
+ * \brief This function finishes the SHA-1 operation, and writes
+ * the result to the output buffer.
+ *
+ * \warning SHA-1 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ * \param ctx The SHA-1 context to use. This must be initialized and
+ * have a hash operation started.
+ * \param output The SHA-1 checksum result. This must be a writable
+ * buffer of length \c 20 Bytes.
+ *
+ * \return \c 0 on success.
+ * \return A negative error code on failure.
+ */
+int mbedtls_sha1_finish_ret(mbedtls_sha1_context *ctx,
+ unsigned char output[20]);
+
+/**
+ * \brief SHA-1 process data block (internal use only).
+ *
+ * \warning SHA-1 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ * \param ctx The SHA-1 context to use. This must be initialized.
+ * \param data The data block being processed. This must be a
+ * readable buffer of length \c 64 Bytes.
+ *
+ * \return \c 0 on success.
+ * \return A negative error code on failure.
+ *
+ */
+int mbedtls_internal_sha1_process(mbedtls_sha1_context *ctx,
+ const unsigned char data[64]);
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+#if defined(MBEDTLS_DEPRECATED_WARNING)
+#define MBEDTLS_DEPRECATED __attribute__((deprecated))
+#else
+#define MBEDTLS_DEPRECATED
+#endif
+/**
+ * \brief This function starts a SHA-1 checksum calculation.
+ *
+ * \warning SHA-1 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ * \deprecated Superseded by mbedtls_sha1_starts_ret() in 2.7.0.
+ *
+ * \param ctx The SHA-1 context to initialize. This must be initialized.
+ *
+ */
+MBEDTLS_DEPRECATED void mbedtls_sha1_starts(mbedtls_sha1_context *ctx);
+
+/**
+ * \brief This function feeds an input buffer into an ongoing SHA-1
+ * checksum calculation.
+ *
+ * \warning SHA-1 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ * \deprecated Superseded by mbedtls_sha1_update_ret() in 2.7.0.
+ *
+ * \param ctx The SHA-1 context. This must be initialized and
+ * have a hash operation started.
+ * \param input The buffer holding the input data.
+ * This must be a readable buffer of length \p ilen Bytes.
+ * \param ilen The length of the input data \p input in Bytes.
+ *
+ */
+MBEDTLS_DEPRECATED void mbedtls_sha1_update(mbedtls_sha1_context *ctx,
+ const unsigned char *input,
+ size_t ilen);
+
+/**
+ * \brief This function finishes the SHA-1 operation, and writes
+ * the result to the output buffer.
+ *
+ * \warning SHA-1 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ * \deprecated Superseded by mbedtls_sha1_finish_ret() in 2.7.0.
+ *
+ * \param ctx The SHA-1 context. This must be initialized and
+ * have a hash operation started.
+ * \param output The SHA-1 checksum result.
+ * This must be a writable buffer of length \c 20 Bytes.
+ */
+MBEDTLS_DEPRECATED void mbedtls_sha1_finish(mbedtls_sha1_context *ctx,
+ unsigned char output[20]);
+
+/**
+ * \brief SHA-1 process data block (internal use only).
+ *
+ * \warning SHA-1 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ * \deprecated Superseded by mbedtls_internal_sha1_process() in 2.7.0.
+ *
+ * \param ctx The SHA-1 context. This must be initialized.
+ * \param data The data block being processed.
+ * This must be a readable buffer of length \c 64 bytes.
+ *
+ */
+MBEDTLS_DEPRECATED void mbedtls_sha1_process(mbedtls_sha1_context *ctx,
+ const unsigned char data[64]);
+
+#undef MBEDTLS_DEPRECATED
+#endif /* !MBEDTLS_DEPRECATED_REMOVED */
+
+/**
+ * \brief This function calculates the SHA-1 checksum of a buffer.
+ *
+ * The function allocates the context, performs the
+ * calculation, and frees the context.
+ *
+ * The SHA-1 result is calculated as
+ * output = SHA-1(input buffer).
+ *
+ * \warning SHA-1 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ * \param input The buffer holding the input data.
+ * This must be a readable buffer of length \p ilen Bytes.
+ * \param ilen The length of the input data \p input in Bytes.
+ * \param output The SHA-1 checksum result.
+ * This must be a writable buffer of length \c 20 Bytes.
+ *
+ * \return \c 0 on success.
+ * \return A negative error code on failure.
+ *
+ */
+int mbedtls_sha1_ret(const unsigned char *input,
+ size_t ilen,
+ unsigned char output[20]);
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+#if defined(MBEDTLS_DEPRECATED_WARNING)
+#define MBEDTLS_DEPRECATED __attribute__((deprecated))
+#else
+#define MBEDTLS_DEPRECATED
+#endif
+/**
+ * \brief This function calculates the SHA-1 checksum of a buffer.
+ *
+ * The function allocates the context, performs the
+ * calculation, and frees the context.
+ *
+ * The SHA-1 result is calculated as
+ * output = SHA-1(input buffer).
+ *
+ * \warning SHA-1 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ * \deprecated Superseded by mbedtls_sha1_ret() in 2.7.0
+ *
+ * \param input The buffer holding the input data.
+ * This must be a readable buffer of length \p ilen Bytes.
+ * \param ilen The length of the input data \p input in Bytes.
+ * \param output The SHA-1 checksum result. This must be a writable
+ * buffer of size \c 20 Bytes.
+ *
+ */
+MBEDTLS_DEPRECATED void mbedtls_sha1(const unsigned char *input,
+ size_t ilen,
+ unsigned char output[20]);
+
+#undef MBEDTLS_DEPRECATED
+#endif /* !MBEDTLS_DEPRECATED_REMOVED */
+
+#if defined(MBEDTLS_SHA1_SELF_TEST)
+
+/**
+ * \brief The SHA-1 checkup routine.
+ *
+ * \warning SHA-1 is considered a weak message digest and its use
+ * constitutes a security risk. We recommend considering
+ * stronger message digests instead.
+ *
+ * \return \c 0 on success.
+ * \return \c 1 on failure.
+ *
+ */
+int mbedtls_sha1_self_test(int verbose);
+
+#endif /* MBEDTLS_SHA1_SELF_TEST */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* mbedtls_sha1.h */
diff --git a/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/sha256.c b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/sha256.c
new file mode 100644
index 0000000..8b39ad4
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/sha256.c
@@ -0,0 +1,600 @@
+/*
+ * FIPS-180-2 compliant SHA-256 implementation
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+/*
+ * The SHA-256 Secure Hash Standard was published by NIST in 2002.
+ *
+ * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
+ */
+
+#define MBEDTLS_SHA256_C
+
+#if defined(MBEDTLS_SHA256_C)
+
+#include "sha256.h"
+#include
+#include
+
+#define mbedtls_printf //printf
+
+/* Internal macros meant to be called only from within the library. */
+#define MBEDTLS_INTERNAL_VALIDATE_RET( cond, ret ) do { } while( 0 )
+#define MBEDTLS_INTERNAL_VALIDATE( cond ) do { } while( 0 )
+
+#define SHA256_VALIDATE_RET(cond) \
+ MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA256_BAD_INPUT_DATA )
+#define SHA256_VALIDATE(cond) MBEDTLS_INTERNAL_VALIDATE( cond )
+
+#if !defined(MBEDTLS_SHA256_ALT)
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n,b,i) \
+do { \
+ (n) = ( (uint32_t) (b)[(i) ] << 24 ) \
+ | ( (uint32_t) (b)[(i) + 1] << 16 ) \
+ | ( (uint32_t) (b)[(i) + 2] << 8 ) \
+ | ( (uint32_t) (b)[(i) + 3] ); \
+} while( 0 )
+#endif
+
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n,b,i) \
+do { \
+ (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
+ (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
+ (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
+ (b)[(i) + 3] = (unsigned char) ( (n) ); \
+} while( 0 )
+#endif
+
+void mbedtls_sha256_init(mbedtls_sha256_context *ctx)
+{
+ SHA256_VALIDATE(ctx != NULL);
+
+ memset(ctx, 0, sizeof(mbedtls_sha256_context));
+}
+
+void mbedtls_sha256_free(mbedtls_sha256_context *ctx)
+{
+ if (ctx == NULL) {
+ return;
+ }
+
+ //mbedtls_platform_zeroize( ctx, sizeof( mbedtls_sha256_context ) );
+ memset(ctx, 0, sizeof(mbedtls_sha256_context));
+}
+
+void mbedtls_sha256_clone(mbedtls_sha256_context *dst,
+ const mbedtls_sha256_context *src)
+{
+ SHA256_VALIDATE(dst != NULL);
+ SHA256_VALIDATE(src != NULL);
+
+ *dst = *src;
+}
+
+/*
+ * SHA-256 context setup
+ */
+int mbedtls_sha256_starts_ret(mbedtls_sha256_context *ctx, int is224)
+{
+ SHA256_VALIDATE_RET(ctx != NULL);
+ SHA256_VALIDATE_RET(is224 == 0 || is224 == 1);
+
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ if (is224 == 0) {
+ /* SHA-256 */
+ ctx->state[0] = 0x6A09E667;
+ ctx->state[1] = 0xBB67AE85;
+ ctx->state[2] = 0x3C6EF372;
+ ctx->state[3] = 0xA54FF53A;
+ ctx->state[4] = 0x510E527F;
+ ctx->state[5] = 0x9B05688C;
+ ctx->state[6] = 0x1F83D9AB;
+ ctx->state[7] = 0x5BE0CD19;
+ } else {
+ /* SHA-224 */
+ ctx->state[0] = 0xC1059ED8;
+ ctx->state[1] = 0x367CD507;
+ ctx->state[2] = 0x3070DD17;
+ ctx->state[3] = 0xF70E5939;
+ ctx->state[4] = 0xFFC00B31;
+ ctx->state[5] = 0x68581511;
+ ctx->state[6] = 0x64F98FA7;
+ ctx->state[7] = 0xBEFA4FA4;
+ }
+
+ ctx->is224 = is224;
+
+ return (0);
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+void mbedtls_sha256_starts(mbedtls_sha256_context *ctx,
+ int is224)
+{
+ mbedtls_sha256_starts_ret(ctx, is224);
+}
+#endif
+
+#if !defined(MBEDTLS_SHA256_PROCESS_ALT)
+static const uint32_t K[] = {
+ 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
+ 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
+ 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
+ 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
+ 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
+ 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
+ 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
+ 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
+ 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
+ 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
+ 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
+ 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
+ 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
+ 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
+ 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
+ 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
+};
+
+#define SHR(x,n) ((x & 0xFFFFFFFF) >> n)
+#define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
+
+#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3))
+#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10))
+
+#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
+#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
+
+#define F0(x,y,z) ((x & y) | (z & (x | y)))
+#define F1(x,y,z) (z ^ (x & (y ^ z)))
+
+#define R(t) \
+( \
+ W[t] = S1(W[t - 2]) + W[t - 7] + \
+ S0(W[t - 15]) + W[t - 16] \
+)
+
+#define P(a,b,c,d,e,f,g,h,x,K) \
+{ \
+ temp1 = h + S3(e) + F1(e,f,g) + K + x; \
+ temp2 = S2(a) + F0(a,b,c); \
+ d += temp1; h = temp1 + temp2; \
+}
+
+int mbedtls_internal_sha256_process(mbedtls_sha256_context *ctx,
+ const unsigned char data[64])
+{
+ uint32_t temp1, temp2, W[64];
+ uint32_t A[8];
+ unsigned int i;
+
+ SHA256_VALIDATE_RET(ctx != NULL);
+ SHA256_VALIDATE_RET((const unsigned char *)data != NULL);
+
+ for (i = 0; i < 8; i++) {
+ A[i] = ctx->state[i];
+ }
+
+#if defined(MBEDTLS_SHA256_SMALLER)
+ for (i = 0; i < 64; i++) {
+ if (i < 16) {
+ GET_UINT32_BE(W[i], data, 4 * i);
+ } else {
+ R(i);
+ }
+
+ P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i]);
+
+ temp1 = A[7];
+ A[7] = A[6];
+ A[6] = A[5];
+ A[5] = A[4];
+ A[4] = A[3];
+ A[3] = A[2];
+ A[2] = A[1];
+ A[1] = A[0];
+ A[0] = temp1;
+ }
+#else /* MBEDTLS_SHA256_SMALLER */
+ for (i = 0; i < 16; i++) {
+ GET_UINT32_BE(W[i], data, 4 * i);
+ }
+
+ for (i = 0; i < 16; i += 8) {
+ P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i + 0], K[i + 0]);
+ P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i + 1], K[i + 1]);
+ P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i + 2], K[i + 2]);
+ P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i + 3], K[i + 3]);
+ P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i + 4], K[i + 4]);
+ P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i + 5], K[i + 5]);
+ P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i + 6], K[i + 6]);
+ P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i + 7], K[i + 7]);
+ }
+
+ for (i = 16; i < 64; i += 8) {
+ P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i + 0), K[i + 0]);
+ P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i + 1), K[i + 1]);
+ P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i + 2), K[i + 2]);
+ P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i + 3), K[i + 3]);
+ P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i + 4), K[i + 4]);
+ P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i + 5), K[i + 5]);
+ P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i + 6), K[i + 6]);
+ P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i + 7), K[i + 7]);
+ }
+#endif /* MBEDTLS_SHA256_SMALLER */
+
+ for (i = 0; i < 8; i++) {
+ ctx->state[i] += A[i];
+ }
+
+ return (0);
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+void mbedtls_sha256_process(mbedtls_sha256_context *ctx,
+ const unsigned char data[64])
+{
+ mbedtls_internal_sha256_process(ctx, data);
+}
+#endif
+#endif /* !MBEDTLS_SHA256_PROCESS_ALT */
+
+/*
+ * SHA-256 process buffer
+ */
+int mbedtls_sha256_update_ret(mbedtls_sha256_context *ctx,
+ const unsigned char *input,
+ size_t ilen)
+{
+ int ret;
+ size_t fill;
+ uint32_t left;
+
+ SHA256_VALIDATE_RET(ctx != NULL);
+ SHA256_VALIDATE_RET(ilen == 0 || input != NULL);
+
+ if (ilen == 0) {
+ return (0);
+ }
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += (uint32_t) ilen;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if (ctx->total[0] < (uint32_t) ilen) {
+ ctx->total[1]++;
+ }
+
+ if (left && ilen >= fill) {
+ memcpy((void *)(ctx->buffer + left), input, fill);
+
+ if ((ret = mbedtls_internal_sha256_process(ctx, ctx->buffer)) != 0) {
+ return (ret);
+ }
+
+ input += fill;
+ ilen -= fill;
+ left = 0;
+ }
+
+ while (ilen >= 64) {
+ if ((ret = mbedtls_internal_sha256_process(ctx, input)) != 0) {
+ return (ret);
+ }
+
+ input += 64;
+ ilen -= 64;
+ }
+
+ if (ilen > 0) {
+ memcpy((void *)(ctx->buffer + left), input, ilen);
+ }
+
+ return (0);
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+void mbedtls_sha256_update(mbedtls_sha256_context *ctx,
+ const unsigned char *input,
+ size_t ilen)
+{
+ mbedtls_sha256_update_ret(ctx, input, ilen);
+}
+#endif
+
+/*
+ * SHA-256 final digest
+ */
+int mbedtls_sha256_finish_ret(mbedtls_sha256_context *ctx,
+ unsigned char output[32])
+{
+ int ret;
+ uint32_t used;
+ uint32_t high, low;
+
+ SHA256_VALIDATE_RET(ctx != NULL);
+ SHA256_VALIDATE_RET((unsigned char *)output != NULL);
+
+ /*
+ * Add padding: 0x80 then 0x00 until 8 bytes remain for the length
+ */
+ used = ctx->total[0] & 0x3F;
+
+ ctx->buffer[used++] = 0x80;
+
+ if (used <= 56) {
+ /* Enough room for padding + length in current block */
+ memset(ctx->buffer + used, 0, 56 - used);
+ } else {
+ /* We'll need an extra block */
+ memset(ctx->buffer + used, 0, 64 - used);
+
+ if ((ret = mbedtls_internal_sha256_process(ctx, ctx->buffer)) != 0) {
+ return (ret);
+ }
+
+ memset(ctx->buffer, 0, 56);
+ }
+
+ /*
+ * Add message length
+ */
+ high = (ctx->total[0] >> 29)
+ | (ctx->total[1] << 3);
+ low = (ctx->total[0] << 3);
+
+ PUT_UINT32_BE(high, ctx->buffer, 56);
+ PUT_UINT32_BE(low, ctx->buffer, 60);
+
+ if ((ret = mbedtls_internal_sha256_process(ctx, ctx->buffer)) != 0) {
+ return (ret);
+ }
+
+ /*
+ * Output final state
+ */
+ PUT_UINT32_BE(ctx->state[0], output, 0);
+ PUT_UINT32_BE(ctx->state[1], output, 4);
+ PUT_UINT32_BE(ctx->state[2], output, 8);
+ PUT_UINT32_BE(ctx->state[3], output, 12);
+ PUT_UINT32_BE(ctx->state[4], output, 16);
+ PUT_UINT32_BE(ctx->state[5], output, 20);
+ PUT_UINT32_BE(ctx->state[6], output, 24);
+
+ if (ctx->is224 == 0) {
+ PUT_UINT32_BE(ctx->state[7], output, 28);
+ }
+
+ return (0);
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+void mbedtls_sha256_finish(mbedtls_sha256_context *ctx,
+ unsigned char output[32])
+{
+ mbedtls_sha256_finish_ret(ctx, output);
+}
+#endif
+
+#endif /* !MBEDTLS_SHA256_ALT */
+
+/*
+ * output = SHA-256( input buffer )
+ */
+int mbedtls_sha256_ret(const unsigned char *input,
+ size_t ilen,
+ unsigned char output[32],
+ int is224)
+{
+ int ret;
+ mbedtls_sha256_context ctx;
+
+ SHA256_VALIDATE_RET(is224 == 0 || is224 == 1);
+ SHA256_VALIDATE_RET(ilen == 0 || input != NULL);
+ SHA256_VALIDATE_RET((unsigned char *)output != NULL);
+
+ mbedtls_sha256_init(&ctx);
+
+ if ((ret = mbedtls_sha256_starts_ret(&ctx, is224)) != 0) {
+ goto exit;
+ }
+
+ if ((ret = mbedtls_sha256_update_ret(&ctx, input, ilen)) != 0) {
+ goto exit;
+ }
+
+ if ((ret = mbedtls_sha256_finish_ret(&ctx, output)) != 0) {
+ goto exit;
+ }
+
+exit:
+ mbedtls_sha256_free(&ctx);
+
+ return (ret);
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+void mbedtls_sha256(const unsigned char *input,
+ size_t ilen,
+ unsigned char output[32],
+ int is224)
+{
+ mbedtls_sha256_ret(input, ilen, output, is224);
+}
+#endif
+
+#if defined(MBEDTLS_SHA256_SELF_TEST)
+
+#define mbedtls_calloc calloc
+#define mbedtls_free free
+/*
+ * FIPS-180-2 test vectors
+ */
+static const unsigned char sha256_test_buf[3][57] = {
+ { "abc" },
+ { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
+ { "" }
+};
+
+static const size_t sha256_test_buflen[3] = {
+ 3, 56, 1000
+};
+
+static const unsigned char sha256_test_sum[6][32] = {
+ /*
+ * SHA-224 test vectors
+ */
+ {
+ 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22,
+ 0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3,
+ 0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7,
+ 0xE3, 0x6C, 0x9D, 0xA7
+ },
+ {
+ 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC,
+ 0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50,
+ 0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19,
+ 0x52, 0x52, 0x25, 0x25
+ },
+ {
+ 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8,
+ 0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B,
+ 0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE,
+ 0x4E, 0xE7, 0xAD, 0x67
+ },
+
+ /*
+ * SHA-256 test vectors
+ */
+ {
+ 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
+ 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
+ 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
+ 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD
+ },
+ {
+ 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
+ 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
+ 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
+ 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1
+ },
+ {
+ 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92,
+ 0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67,
+ 0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E,
+ 0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0
+ }
+};
+
+/*
+ * Checkup routine
+ */
+int mbedtls_sha256_self_test(int verbose)
+{
+ int i, j, k, buflen, ret = 0;
+ unsigned char *buf;
+ unsigned char sha256sum[32];
+ mbedtls_sha256_context ctx;
+
+ buf = mbedtls_calloc(1024, sizeof(unsigned char));
+ if (NULL == buf) {
+ if (verbose != 0) {
+ mbedtls_printf("Buffer allocation failed\n");
+ }
+
+ return (1);
+ }
+
+ mbedtls_sha256_init(&ctx);
+
+ for (i = 0; i < 6; i++) {
+ j = i % 3;
+ k = i < 3;
+
+ if (verbose != 0) {
+ mbedtls_printf(" SHA-%d test #%d: ", 256 - k * 32, j + 1);
+ }
+
+ if ((ret = mbedtls_sha256_starts_ret(&ctx, k)) != 0) {
+ goto fail;
+ }
+
+ if (j == 2) {
+ memset(buf, 'a', buflen = 1000);
+
+ for (j = 0; j < 1000; j++) {
+ ret = mbedtls_sha256_update_ret(&ctx, buf, buflen);
+ if (ret != 0) {
+ goto fail;
+ }
+ }
+
+ } else {
+ ret = mbedtls_sha256_update_ret(&ctx, sha256_test_buf[j],
+ sha256_test_buflen[j]);
+ if (ret != 0) {
+ goto fail;
+ }
+ }
+
+ if ((ret = mbedtls_sha256_finish_ret(&ctx, sha256sum)) != 0) {
+ goto fail;
+ }
+
+
+ if (memcmp(sha256sum, sha256_test_sum[i], 32 - k * 4) != 0) {
+ ret = 1;
+ goto fail;
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("passed\n");
+ }
+ }
+
+ if (verbose != 0) {
+ mbedtls_printf("\n");
+ }
+
+ goto exit;
+
+fail:
+ if (verbose != 0) {
+ mbedtls_printf("failed\n");
+ }
+
+exit:
+ mbedtls_sha256_free(&ctx);
+ mbedtls_free(buf);
+
+ return (ret);
+}
+
+#endif /* MBEDTLS_SHA256_SELF_TEST */
+
+#endif /* MBEDTLS_SHA256_C */
diff --git a/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/sha256.h b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/sha256.h
new file mode 100644
index 0000000..a71850d
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/extern_components/mbedtls/sha256.h
@@ -0,0 +1,292 @@
+/**
+ * \file sha256.h
+ *
+ * \brief This file contains SHA-224 and SHA-256 definitions and functions.
+ *
+ * The Secure Hash Algorithms 224 and 256 (SHA-224 and SHA-256) cryptographic
+ * hash functions are defined in FIPS 180-4: Secure Hash Standard (SHS) .
+ */
+/*
+ * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of Mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_SHA256_H
+#define MBEDTLS_SHA256_H
+
+#include
+#include
+
+//#define MBEDTLS_SHA256_SELF_TEST
+
+/* MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED is deprecated and should not be used. */
+#define MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED -0x0037 /**< SHA-256 hardware accelerator failed */
+#define MBEDTLS_ERR_SHA256_BAD_INPUT_DATA -0x0074 /**< SHA-256 input data was malformed. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(MBEDTLS_SHA256_ALT)
+// Regular implementation
+//
+
+/**
+ * \brief The SHA-256 context structure.
+ *
+ * The structure is used both for SHA-256 and for SHA-224
+ * checksum calculations. The choice between these two is
+ * made in the call to mbedtls_sha256_starts_ret().
+ */
+typedef struct mbedtls_sha256_context {
+ uint32_t total[2]; /*!< The number of Bytes processed. */
+ uint32_t state[8]; /*!< The intermediate digest state. */
+ unsigned char buffer[64]; /*!< The data block being processed. */
+ int is224; /*!< Determines which function to use:
+ 0: Use SHA-256, or 1: Use SHA-224. */
+}
+mbedtls_sha256_context;
+
+#else /* MBEDTLS_SHA256_ALT */
+#include "sha256_alt.h"
+#endif /* MBEDTLS_SHA256_ALT */
+
+/**
+ * \brief This function initializes a SHA-256 context.
+ *
+ * \param ctx The SHA-256 context to initialize. This must not be \c NULL.
+ */
+void mbedtls_sha256_init(mbedtls_sha256_context *ctx);
+
+/**
+ * \brief This function clears a SHA-256 context.
+ *
+ * \param ctx The SHA-256 context to clear. This may be \c NULL, in which
+ * case this function returns immediately. If it is not \c NULL,
+ * it must point to an initialized SHA-256 context.
+ */
+void mbedtls_sha256_free(mbedtls_sha256_context *ctx);
+
+/**
+ * \brief This function clones the state of a SHA-256 context.
+ *
+ * \param dst The destination context. This must be initialized.
+ * \param src The context to clone. This must be initialized.
+ */
+void mbedtls_sha256_clone(mbedtls_sha256_context *dst,
+ const mbedtls_sha256_context *src);
+
+/**
+ * \brief This function starts a SHA-224 or SHA-256 checksum
+ * calculation.
+ *
+ * \param ctx The context to use. This must be initialized.
+ * \param is224 This determines which function to use. This must be
+ * either \c 0 for SHA-256, or \c 1 for SHA-224.
+ *
+ * \return \c 0 on success.
+ * \return A negative error code on failure.
+ */
+int mbedtls_sha256_starts_ret(mbedtls_sha256_context *ctx, int is224);
+
+/**
+ * \brief This function feeds an input buffer into an ongoing
+ * SHA-256 checksum calculation.
+ *
+ * \param ctx The SHA-256 context. This must be initialized
+ * and have a hash operation started.
+ * \param input The buffer holding the data. This must be a readable
+ * buffer of length \p ilen Bytes.
+ * \param ilen The length of the input data in Bytes.
+ *
+ * \return \c 0 on success.
+ * \return A negative error code on failure.
+ */
+int mbedtls_sha256_update_ret(mbedtls_sha256_context *ctx,
+ const unsigned char *input,
+ size_t ilen);
+
+/**
+ * \brief This function finishes the SHA-256 operation, and writes
+ * the result to the output buffer.
+ *
+ * \param ctx The SHA-256 context. This must be initialized
+ * and have a hash operation started.
+ * \param output The SHA-224 or SHA-256 checksum result.
+ * This must be a writable buffer of length \c 32 Bytes.
+ *
+ * \return \c 0 on success.
+ * \return A negative error code on failure.
+ */
+int mbedtls_sha256_finish_ret(mbedtls_sha256_context *ctx,
+ unsigned char output[32]);
+
+/**
+ * \brief This function processes a single data block within
+ * the ongoing SHA-256 computation. This function is for
+ * internal use only.
+ *
+ * \param ctx The SHA-256 context. This must be initialized.
+ * \param data The buffer holding one block of data. This must
+ * be a readable buffer of length \c 64 Bytes.
+ *
+ * \return \c 0 on success.
+ * \return A negative error code on failure.
+ */
+int mbedtls_internal_sha256_process(mbedtls_sha256_context *ctx,
+ const unsigned char data[64]);
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+#if defined(MBEDTLS_DEPRECATED_WARNING)
+#define MBEDTLS_DEPRECATED __attribute__((deprecated))
+#else
+#define MBEDTLS_DEPRECATED
+#endif
+/**
+ * \brief This function starts a SHA-224 or SHA-256 checksum
+ * calculation.
+ *
+ * \deprecated Superseded by mbedtls_sha256_starts_ret() in 2.7.0.
+ *
+ * \param ctx The context to use. This must be initialized.
+ * \param is224 Determines which function to use. This must be
+ * either \c 0 for SHA-256, or \c 1 for SHA-224.
+ */
+MBEDTLS_DEPRECATED void mbedtls_sha256_starts(mbedtls_sha256_context *ctx,
+ int is224);
+
+/**
+ * \brief This function feeds an input buffer into an ongoing
+ * SHA-256 checksum calculation.
+ *
+ * \deprecated Superseded by mbedtls_sha256_update_ret() in 2.7.0.
+ *
+ * \param ctx The SHA-256 context to use. This must be
+ * initialized and have a hash operation started.
+ * \param input The buffer holding the data. This must be a readable
+ * buffer of length \p ilen Bytes.
+ * \param ilen The length of the input data in Bytes.
+ */
+MBEDTLS_DEPRECATED void mbedtls_sha256_update(mbedtls_sha256_context *ctx,
+ const unsigned char *input,
+ size_t ilen);
+
+/**
+ * \brief This function finishes the SHA-256 operation, and writes
+ * the result to the output buffer.
+ *
+ * \deprecated Superseded by mbedtls_sha256_finish_ret() in 2.7.0.
+ *
+ * \param ctx The SHA-256 context. This must be initialized and
+ * have a hash operation started.
+ * \param output The SHA-224 or SHA-256 checksum result. This must be
+ * a writable buffer of length \c 32 Bytes.
+ */
+MBEDTLS_DEPRECATED void mbedtls_sha256_finish(mbedtls_sha256_context *ctx,
+ unsigned char output[32]);
+
+/**
+ * \brief This function processes a single data block within
+ * the ongoing SHA-256 computation. This function is for
+ * internal use only.
+ *
+ * \deprecated Superseded by mbedtls_internal_sha256_process() in 2.7.0.
+ *
+ * \param ctx The SHA-256 context. This must be initialized.
+ * \param data The buffer holding one block of data. This must be
+ * a readable buffer of size \c 64 Bytes.
+ */
+MBEDTLS_DEPRECATED void mbedtls_sha256_process(mbedtls_sha256_context *ctx,
+ const unsigned char data[64]);
+
+#undef MBEDTLS_DEPRECATED
+#endif /* !MBEDTLS_DEPRECATED_REMOVED */
+
+/**
+ * \brief This function calculates the SHA-224 or SHA-256
+ * checksum of a buffer.
+ *
+ * The function allocates the context, performs the
+ * calculation, and frees the context.
+ *
+ * The SHA-256 result is calculated as
+ * output = SHA-256(input buffer).
+ *
+ * \param input The buffer holding the data. This must be a readable
+ * buffer of length \p ilen Bytes.
+ * \param ilen The length of the input data in Bytes.
+ * \param output The SHA-224 or SHA-256 checksum result. This must
+ * be a writable buffer of length \c 32 Bytes.
+ * \param is224 Determines which function to use. This must be
+ * either \c 0 for SHA-256, or \c 1 for SHA-224.
+ */
+int mbedtls_sha256_ret(const unsigned char *input,
+ size_t ilen,
+ unsigned char output[32],
+ int is224);
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+#if defined(MBEDTLS_DEPRECATED_WARNING)
+#define MBEDTLS_DEPRECATED __attribute__((deprecated))
+#else
+#define MBEDTLS_DEPRECATED
+#endif
+
+/**
+ * \brief This function calculates the SHA-224 or SHA-256 checksum
+ * of a buffer.
+ *
+ * The function allocates the context, performs the
+ * calculation, and frees the context.
+ *
+ * The SHA-256 result is calculated as
+ * output = SHA-256(input buffer).
+ *
+ * \deprecated Superseded by mbedtls_sha256_ret() in 2.7.0.
+ *
+ * \param input The buffer holding the data. This must be a readable
+ * buffer of length \p ilen Bytes.
+ * \param ilen The length of the input data in Bytes.
+ * \param output The SHA-224 or SHA-256 checksum result. This must be
+ * a writable buffer of length \c 32 Bytes.
+ * \param is224 Determines which function to use. This must be either
+ * \c 0 for SHA-256, or \c 1 for SHA-224.
+ */
+MBEDTLS_DEPRECATED void mbedtls_sha256(const unsigned char *input,
+ size_t ilen,
+ unsigned char output[32],
+ int is224);
+
+#undef MBEDTLS_DEPRECATED
+#endif /* !MBEDTLS_DEPRECATED_REMOVED */
+
+#if defined(MBEDTLS_SHA256_SELF_TEST)
+
+/**
+ * \brief The SHA-224 and SHA-256 checkup routine.
+ *
+ * \return \c 0 on success.
+ * \return \c 1 on failure.
+ */
+int mbedtls_sha256_self_test(int verbose);
+
+#endif /* MBEDTLS_SHA256_SELF_TEST */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* mbedtls_sha256.h */
diff --git a/apps/common/third_party_profile/tuya_protocol/port/tuya_ble_port.c b/apps/common/third_party_profile/tuya_protocol/port/tuya_ble_port.c
new file mode 100644
index 0000000..10c69f5
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/port/tuya_ble_port.c
@@ -0,0 +1,667 @@
+/**
+ * \file tuya_ble_port.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#include "tuya_ble_port.h"
+#include "tuya_ble_type.h"
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_gap_advertising_adv_data_update(uint8_t const *p_ad_data, uint8_t ad_len)
+{
+ return TUYA_BLE_SUCCESS;
+}
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_gap_advertising_scan_rsp_data_update(uint8_t const *p_sr_data, uint8_t sr_len)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+/**
+ *@brief Function for update the device information characteristic value.
+ *@param[in] p_data The pointer to the data to be updated.
+ *@param[in] data_len The length of the data to be updated.
+ *
+ *@note The device information characteristic uuid : 00000003-0000-1001-8001-00805F9B07D0
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_device_info_characteristic_value_update(uint8_t const *p_data, uint8_t data_len)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_gap_disconnect(void)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_gatt_send_data(const uint8_t *p_data, uint16_t len)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_timer_create(void **p_timer_id, uint32_t timeout_value_ms, tuya_ble_timer_mode mode, tuya_ble_timer_handler_t timeout_handler)
+{
+ return TUYA_BLE_SUCCESS;
+}
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_timer_delete(void *timer_id)
+{
+ return TUYA_BLE_SUCCESS;
+}
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_timer_start(void *timer_id)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_timer_restart(void *timer_id, uint32_t timeout_value_ms)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_timer_stop(void *timer_id)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK void tuya_ble_device_delay_ms(uint32_t ms)
+{
+
+}
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK void tuya_ble_device_delay_us(uint32_t us)
+{
+
+}
+
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_rand_generator(uint8_t *p_buf, uint8_t len)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_device_reset(void)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_gap_addr_get(tuya_ble_gap_addr_t *p_addr)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_gap_addr_set(tuya_ble_gap_addr_t *p_addr)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+/**
+*@brief
+*@param
+*
+*@note
+*
+* */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_rtc_get_timestamp(uint32_t *timestamp, int32_t *timezone)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_rtc_set_timestamp(uint32_t timestamp, int32_t timezone)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_nv_init(void)
+{
+ return TUYA_BLE_SUCCESS;
+}
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_nv_erase(uint32_t addr, uint32_t size)
+{
+ return TUYA_BLE_SUCCESS;
+}
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_nv_write(uint32_t addr, const uint8_t *p_data, uint32_t size)
+{
+ return TUYA_BLE_SUCCESS;
+}
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_nv_read(uint32_t addr, uint8_t *p_data, uint32_t size)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_common_uart_init(void)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_common_uart_send_data(const uint8_t *p_data, uint16_t len)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_task_create(void **pp_handle, const char *p_name, void (*p_routine)(void *), void *p_param, uint16_t stack_size, uint16_t priority)
+{
+ return true;
+}
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_task_delete(void *p_handle)
+{
+ return true;
+}
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_task_suspend(void *p_handle)
+{
+ return true;
+}
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_task_resume(void *p_handle)
+{
+ return true;
+}
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_msg_queue_create(void **pp_handle, uint32_t msg_num, uint32_t msg_size)
+{
+ return true;
+}
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_msg_queue_delete(void *p_handle)
+{
+ return true;
+}
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_msg_queue_peek(void *p_handle, uint32_t *p_msg_num)
+{
+ return true;
+}
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_msg_queue_send(void *p_handle, void *p_msg, uint32_t wait_ms)
+{
+ return true;
+}
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_msg_queue_recv(void *p_handle, void *p_msg, uint32_t wait_ms)
+{
+ return true;
+}
+
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_event_queue_send_port(tuya_ble_evt_param_t *evt, uint32_t wait_ms)
+{
+ return true;
+}
+
+
+
+/**
+ * @brief 128 bit AES ECB encryption on speicified plaintext and keys
+ * @param input specifed plain text to be encypted
+ * @param input_len byte length of the data to be descrypted, must be multiples of 16
+ * @param key keys to encrypt the plaintext
+ * @param output output buffer to store encrypted data
+ * @return encryption results
+ * @retval true successful
+ * @retval false fail
+ * @note least significant octet of encrypted data corresponds to encypted[0]
+ */
+__TUYA_BLE_WEAK bool tuya_ble_aes128_ecb_encrypt(uint8_t *key, uint8_t *input, uint16_t input_len, uint8_t *output)
+{
+ return true;
+}
+
+/**
+ * @brief 128 bit AES ECB decryption on speicified encrypted data and keys
+ * @param input specifed encypted data to be decypted
+ * @param input_len byte length of the data to be descrypted, must be multiples of 16
+ * @param key keys to decrypt the data
+ * @param output output buffer to store plain data
+ * @return decryption results
+ * @retval true successful
+ * @retval false fail
+ * @note least significant octet of encrypted data corresponds to encypted[0]
+*/
+__TUYA_BLE_WEAK bool tuya_ble_aes128_ecb_decrypt(uint8_t *key, uint8_t *input, uint16_t input_len, uint8_t *output)
+{
+ return true;
+}
+/**
+ * @brief 128 bit AES CBC encryption on speicified plaintext and keys
+ * @param input specifed plain text to be encypted
+ * @param key keys to encrypt the plaintext
+ * @param output output buffer to store encrypted data
+ * @param iv initialization vector (IV) for CBC mode
+ * @param input_len byte length of the data to be descrypted, must be multiples of 16
+ * @return encryption results
+ * @retval true successful
+ * @retval false fail
+ * @note least significant octet of encrypted data corresponds to encypted[0]
+ */
+__TUYA_BLE_WEAK bool tuya_ble_aes128_cbc_encrypt(uint8_t *key, uint8_t *iv, uint8_t *input, uint16_t input_len, uint8_t *output)
+{
+ return true;
+}
+/**
+ * @brief 128 bit AES CBC descryption on speicified plaintext and keys
+ * @param input specifed encypted data to be decypted
+ * @param key keys to decrypt the data
+ * @param output output buffer to store plain data
+ * @param iv initialization vector (IV) for CBC mode
+ * @param input_len byte length of the data to be descrypted, must be multiples of 16
+ * @return encryption results
+ * @retval true successful
+ * @retval false fail
+ * @note least significant octet of encrypted data corresponds to encypted[0]
+ */
+__TUYA_BLE_WEAK bool tuya_ble_aes128_cbc_decrypt(uint8_t *key, uint8_t *iv, uint8_t *input, uint16_t input_len, uint8_t *output)
+{
+ return true;
+}
+/**
+ * @brief MD5 checksum
+ * @param input specifed plain text to be encypted
+ * @param output output buffer to store md5 result data,output data len is always 16
+ * @param input_len byte length of the data to be encypted
+ * @return encryption results
+ * @retval true successful
+ * @retval false fail
+ * @note
+ */
+__TUYA_BLE_WEAK bool tuya_ble_md5_crypt(uint8_t *input, uint16_t input_len, uint8_t *output)
+{
+ return true;
+}
+
+/**
+ * @brief SHA256 checksum
+ * @param input specifed plain text to be encypted
+ * @param output output buffer to store sha256 result data,output data len is always 32
+ * @param input_len byte length of the data to be encypted
+ * @return encryption results
+ * @retval true successful
+ * @retval false fail
+ * @note
+ */
+__TUYA_BLE_WEAK bool tuya_ble_sha256_crypt(const uint8_t *input, uint16_t input_len, uint8_t *output)
+{
+ return true;
+}
+
+/**
+ *@brief storage private data, for example: token/dev cert/keys
+ *@param private_data_type describe private data type, see the tuay_ble_private_data_type enum define
+ *@param p_data storage data point
+ *@param data_size p_data size
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_storage_private_data(tuya_ble_private_data_type private_data_type, uint8_t *p_data, uint32_t data_size)
+{
+ return 0;
+}
+
+/**
+ *@brief Get device certificate length
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK uint32_t tuya_ble_get_dev_crt_len(void)
+{
+ return 0;
+}
+
+/**
+ *@brief Get device certificate data
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_get_dev_crt_der(uint8_t *p_der, uint32_t der_len)
+{
+ return TUYA_BLE_ERR_NOT_FOUND;
+}
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_ecc_keypair_gen_secp256r1(uint8_t *public_key, uint8_t *private_key)
+{
+ return TUYA_BLE_ERR_INVALID_STATE;
+}
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_ecc_shared_secret_compute_secp256r1(uint8_t *public_key, uint8_t *private_key, uint8_t *secret_key)
+{
+ return TUYA_BLE_ERR_INVALID_STATE;
+}
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_ecc_sign_secp256r1(const uint8_t *p_sk, const uint8_t *p_data, uint32_t data_size, uint8_t *p_sig)
+{
+ return TUYA_BLE_ERR_INVALID_STATE;
+}
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_ecc_verify_secp256r1(const uint8_t *p_pk, const uint8_t *p_data, uint32_t data_size, const uint8_t *p_sig)
+{
+ return TUYA_BLE_ERR_RESOURCES;
+}
+
+/**
+ * @brief This function calculates the full generic HMAC
+ * on the input buffer with the provided key.
+ * @param key The HMAC secret key.
+ * @param key_len The length of the HMAC secret key in Bytes.
+ * @param input specifed plain text to be encypted
+ * @param output output buffer to store the result data
+ * @param input_len byte length of the data to be encypted
+ * @return encryption results
+ * @retval true successful
+ * @retval false fail
+ * @note
+ */
+__TUYA_BLE_WEAK bool tuya_ble_hmac_sha1_crypt(const uint8_t *key, uint32_t key_len, const uint8_t *input, uint32_t input_len, uint8_t *output)
+{
+ return true;
+}
+
+/**
+ * @brief This function calculates the full generic HMAC
+ * on the input buffer with the provided key.
+ * @param key The HMAC secret key.
+ * @param key_len The length of the HMAC secret key in Bytes.
+ * @param input specifed plain text to be encypted
+ * @param output output buffer to store the result data
+ * @param input_len byte length of the data to be encypted
+ * @return encryption results
+ * @retval true successful
+ * @retval false fail
+ * @note
+ */
+__TUYA_BLE_WEAK bool tuya_ble_hmac_sha256_crypt(const uint8_t *key, uint32_t key_len, const uint8_t *input, uint32_t input_len, uint8_t *output)
+{
+ return true;
+}
+
+
+/**
+ * @brief Allocate a memory block with required size.
+ *
+ *
+ * @param[in] size Required memory size.
+ *
+ * @return The address of the allocated memory block. If the address is NULL, the
+ * memory allocation failed.
+ */
+__TUYA_BLE_WEAK void *tuya_ble_port_malloc(uint32_t size);
+
+/**
+ *
+ * @brief Free a memory block that had been allocated.
+ *
+ * @param[in] pv The address of memory block being freed.
+ *
+ * @return None.
+ */
+__TUYA_BLE_WEAK void tuya_ble_port_free(void *pv);
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/port/tuya_ble_port.h b/apps/common/third_party_profile/tuya_protocol/port/tuya_ble_port.h
new file mode 100644
index 0000000..8a770c2
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/port/tuya_ble_port.h
@@ -0,0 +1,710 @@
+/**
+ * \file tuya_ble_port.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+
+#ifndef TUYA_BLE_PORT_H__
+#define TUYA_BLE_PORT_H__
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_config.h"
+#include "tuya_ble_port_peripheral.h"
+
+void tuya_ble_device_enter_critical(void);
+void tuya_ble_device_exit_critical(void);
+
+#if defined(TUYA_BLE_PORT_PLATFORM_HEADER_FILE)
+/**
+ * @file TUYA_BLE_PORT_PLATFORM_HEADER_FILE
+ *
+ * @brief Platform header file
+
+ * @note
+ * Must declare or define 'tuya_ble_device_enter_critical' and 'tuya_ble_device_exit_critical' in the platform header file.
+
+ * An example on the nrf52832 platform is as follows
+
+ * @example
+
+ * @code
+ #define TUYA_BLE_PORT_PLATFORM_HEADER_FILE "tuya_ble_port_nrf52832.h" ///disconnect) {
+ ble_operation->disconnect(NULL);
+ return TUYA_BLE_SUCCESS;
+ }
+
+ return TUYA_BLE_ERR_INVALID_STATE;
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_gatt_send_data(const uint8_t *p_data, uint16_t len)
+{
+ int ret = 0;
+ /* struct ble_server_operation_t *ble_operation = NULL; */
+ /* TUYA_BLE_LOG_DEBUG("%s\n", __func__); */
+ /* tuya_ble_get_server_operation_table(&ble_operation); */
+ if (ble_operation && ble_operation->send_data) {
+ ret = ble_operation->send_data(NULL, p_data, len);
+ TUYA_BLE_LOG_DEBUG("%d\n", ret);
+ return ret ? TUYA_BLE_ERR_UNKNOWN : TUYA_BLE_SUCCESS;
+ }
+ return TUYA_BLE_ERR_INVALID_STATE;
+}
+
+struct timer_param {
+ tuya_ble_timer_mode mode;
+ tuya_ble_timer_handler_t timeout_handler;
+ uint32_t timeout_value_ms;
+};
+
+static struct timer_param ble_timer;
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_timer_create(void **p_timer_id, uint32_t timeout_value_ms, tuya_ble_timer_mode mode, tuya_ble_timer_handler_t timeout_handler)
+{
+ *p_timer_id = malloc(2);
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ if (*p_timer_id) {
+ //我们的timer不需要create,所以这里只需要保存一下信息
+ *(u16 *)(*p_timer_id) = 0;
+ ble_timer.mode = mode;
+ ble_timer.timeout_handler = timeout_handler;
+ ble_timer.timeout_value_ms = timeout_value_ms;
+ return TUYA_BLE_SUCCESS;
+ }
+
+ return TUYA_BLE_ERR_NO_MEM;
+}
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_timer_delete(void *timer_id)
+{
+ u16 id = *(u16 *)timer_id;
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ if (id) {
+ if (ble_timer.mode == TUYA_BLE_TIMER_SINGLE_SHOT) {
+ sys_timeout_del(id);
+ } else {
+ sys_timer_del(id);
+ }
+ }
+ free(timer_id);
+ return TUYA_BLE_SUCCESS;
+}
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_timer_start(void *timer_id)
+{
+ u16 id = *(u16 *)timer_id;
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ if (id) {
+ if (ble_timer.mode == TUYA_BLE_TIMER_SINGLE_SHOT) {
+ sys_timeout_del(id);
+ } else {
+ sys_timer_del(id);
+ }
+ }
+ u16(*sys_timer_create)(void *priv, void (*func)(void *priv), u32 msec);
+ sys_timer_create = (ble_timer.mode == TUYA_BLE_TIMER_SINGLE_SHOT) ? sys_timeout_add : sys_timer_add;
+ *(u16 *)timer_id = sys_timer_create(NULL, ble_timer.timeout_handler, ble_timer.timeout_value_ms);
+ return TUYA_BLE_SUCCESS;
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_timer_restart(void *timer_id, uint32_t timeout_value_ms)
+{
+ u16 id = *(u16 *)timer_id;
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ sys_timer_modify(id, timeout_value_ms);
+ sys_timer_re_run(id);
+ return TUYA_BLE_SUCCESS;
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_timer_stop(void *timer_id)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK void tuya_ble_device_delay_ms(uint32_t ms)
+{
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ if (ms < 10) {
+ ms = 10;
+ }
+ os_time_dly(ms / 10);
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK void tuya_ble_device_delay_us(uint32_t us)
+{
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ delay_us(us);
+}
+
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_rand_generator(uint8_t *p_buf, uint8_t len)
+{
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ get_random_number(p_buf, len);
+ return TUYA_BLE_SUCCESS;
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_device_reset(void)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_gap_addr_get(tuya_ble_gap_addr_t *p_addr)
+{
+ u8 ret;
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ if (p_addr->addr_type == TUYA_BLE_ADDRESS_TYPE_PUBLIC) {
+ ret = le_controller_get_mac(p_addr->addr);
+ } else if (p_addr->addr_type == TUYA_BLE_ADDRESS_TYPE_RANDOM) {
+ ret = le_controller_get_random_mac(p_addr->addr);
+ }
+ return ret ? TUYA_BLE_ERR_NOT_FOUND : TUYA_BLE_SUCCESS;
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_gap_addr_set(tuya_ble_gap_addr_t *p_addr)
+{
+ u8 ret;
+ ble_op_adv_enable(0);
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ TUYA_BLE_LOG_DEBUG("tuya_ble_gap_addr_set=%d\n", p_addr->addr_type);
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("addr", p_addr->addr, 6);
+ ble_op_set_own_address_type(p_addr->addr_type);
+ if (p_addr->addr_type == TUYA_BLE_ADDRESS_TYPE_PUBLIC) {
+ ret = le_controller_set_mac(p_addr->addr);
+ } else if (p_addr->addr_type == TUYA_BLE_ADDRESS_TYPE_RANDOM) {
+ ret = le_controller_set_random_mac(p_addr->addr);
+ }
+ ble_op_adv_enable(1);
+ return ret ? TUYA_BLE_ERR_INVALID_ADDR : TUYA_BLE_SUCCESS;
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK void tuya_ble_device_enter_critical(void)
+{
+ OS_ENTER_CRITICAL();
+}
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK void tuya_ble_device_exit_critical(void)
+{
+ OS_EXIT_CRITICAL();
+}
+
+/*
+*@brief
+*@param
+*
+*@note
+*
+* */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_rtc_get_timestamp(uint32_t *timestamp, int32_t *timezone)
+{
+ //目前用不到
+ *timestamp = 0;
+ *timezone = 0;
+ return TUYA_BLE_SUCCESS;
+}
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_rtc_set_timestamp(uint32_t timestamp, int32_t timezone)
+{
+ return TUYA_BLE_SUCCESS;
+}
+
+typedef enum _FLASH_ERASER {
+ CHIP_ERASER,
+ BLOCK_ERASER,//4k
+ SECTOR_ERASER,//64k
+} FLASH_ERASER;
+
+
+//
+extern bool sfc_erase(FLASH_ERASER cmd, u32 addr);
+extern u32 sdfile_cpu_addr2flash_addr(u32 offset);
+
+#define USER_FILE_NAME SDFILE_APP_ROOT_PATH"USERIF"
+#define NV_MODE_FILE 0 //固定放在一个指定的区域,一般情况下不会被意外擦除,flash比较大的方案建议用这个
+#define NV_MODE_VM 1 //用VM存,被意外擦除的概率比较高,比如升级的时候,flash空间不够的时候用这个
+#define TUYA_BLE_NV_MODE NV_MODE_FILE
+//使用文件的的方式保存数据,需要在ini文件添加下面的配置
+/*
+USERIF_ADR=AUTO;
+USERIF_LEN=0x4000;
+USERIF_OPT=1;
+*/
+
+FILE *code_fp = NULL;
+
+struct vfs_attr code_attr = {0};
+struct vfs_attr attr;
+
+typedef struct __tuya_addr_to_vfs {
+ u32 tuya_start_addr;//0
+ u32 vfs_satrt_addr;//1
+} tuya_addr_to_vfs;
+
+static tuya_addr_to_vfs addr_sw;
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_nv_init(void)
+{
+#if (TUYA_BLE_NV_MODE == NV_MODE_FILE)
+ if (code_fp) {
+ return TUYA_BLE_SUCCESS;
+ }
+ code_fp = fopen(USER_FILE_NAME, "r+w");
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ if (code_fp == NULL) {
+ TUYA_BLE_LOG_DEBUG("file open err!!!");
+ return TUYA_BLE_ERR_RESOURCES;
+ }
+
+ fget_attrs(code_fp, &attr);
+ if (attr.fsize < 2048) {
+ TUYA_BLE_LOG_DEBUG("file size err!!!");
+ }
+ addr_sw.tuya_start_addr = 0;
+ addr_sw.vfs_satrt_addr = attr.sclust;
+ TUYA_BLE_LOG_DEBUG("addr %x,%x\n", attr.sclust, addr_sw.tuya_start_addr);
+ TUYA_BLE_LOG_DEBUG("tuya_ble_nv_initok\n");
+#endif
+
+ return TUYA_BLE_SUCCESS;
+}
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_nv_erase(uint32_t addr, uint32_t size)
+{
+#if (TUYA_BLE_NV_MODE == NV_MODE_FILE)
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ if (code_fp == NULL) {
+ TUYA_BLE_LOG_DEBUG("file ptr err!!!");
+ return TUYA_BLE_ERR_RESOURCES;
+ }
+ u32 flash_addr = sdfile_cpu_addr2flash_addr(addr_sw.vfs_satrt_addr + addr);
+ sfc_erase(SECTOR_ERASER, flash_addr);// 4k
+#endif
+ return TUYA_BLE_SUCCESS;
+}
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_nv_write(uint32_t addr, const uint8_t *p_data, uint32_t size)
+{
+#if (TUYA_BLE_NV_MODE == NV_MODE_FILE)
+ FILE *write_fp = code_fp;
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ if (code_fp == NULL) {
+ TUYA_BLE_LOG_DEBUG("file ptr err!!!");
+ return TUYA_BLE_ERR_RESOURCES;
+ }
+ int ret = 0;
+ ret = fseek(write_fp, addr, SEEK_SET);
+ TUYA_BLE_LOG_DEBUG("fseek=%x,addr_star=%d,size=%d\n", addr, ret, size);
+ int r = fwrite(write_fp, p_data, size);//更新数据到自定义区,写数据前需要擦除,确保处于FF状态才能成功写入
+ if (r != size) {
+ TUYA_BLE_LOG_DEBUG("write file error code %x", r);
+ }
+#else
+ u8 index;
+ switch (addr) {
+ case TUYA_BLE_AUTH_FLASH_ADDR:
+ index = CFG_USER_TUYA_INFO_AUTH;
+ break;
+ case TUYA_BLE_AUTH_FLASH_BACKUP_ADDR:
+ index = CFG_USER_TUYA_INFO_AUTH_BK;
+ break;
+ case TUYA_BLE_SYS_FLASH_ADDR:
+ index = CFG_USER_TUYA_INFO_SYS;
+ break;
+ case TUYA_BLE_SYS_FLASH_BACKUP_ADDR:
+ index = CFG_USER_TUYA_INFO_SYS_BK;
+ break;
+
+ default:
+ return TUYA_BLE_ERR_INVALID_ADDR;
+ }
+ if (syscfg_write(index, p_data, size) != size) {
+ return TUYA_BLE_ERR_INVALID_ADDR;
+ }
+#endif
+ //发消息,用来给TWS同步app配对数据
+ if (addr == TUYA_BLE_AUTH_FLASH_ADDR) {
+ if (ble_task.ble_task_name) {
+ os_taskq_post_msg(ble_task.ble_task_name, 1, BLE_TASK_MSG_INFO_SYNC_AUTH);
+ }
+ } else if (addr == TUYA_BLE_SYS_FLASH_ADDR) {
+ if (ble_task.ble_task_name) {
+ os_taskq_post_msg(ble_task.ble_task_name, 1, BLE_TASK_MSG_INFO_SYNC_SYS);
+ }
+ }
+ return TUYA_BLE_SUCCESS;
+}
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_nv_read(uint32_t addr, uint8_t *p_data, uint32_t size)
+{
+#if (TUYA_BLE_NV_MODE == NV_MODE_FILE)
+ FILE *read_fp = code_fp;
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ if (code_fp == NULL) {
+ TUYA_BLE_LOG_DEBUG("file ptr err!!!");
+ return TUYA_BLE_ERR_RESOURCES;
+ }
+ fseek(read_fp, addr, SEEK_SET);
+ fread(read_fp, p_data, size);//文件模式读取自定义数据区
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("file read:", p_data, size);
+#else
+ u8 index;
+ switch (addr) {
+ case TUYA_BLE_AUTH_FLASH_ADDR:
+ index = CFG_USER_TUYA_INFO_AUTH;
+ break;
+ case TUYA_BLE_AUTH_FLASH_BACKUP_ADDR:
+ index = CFG_USER_TUYA_INFO_AUTH_BK;
+ break;
+ case TUYA_BLE_SYS_FLASH_ADDR:
+ index = CFG_USER_TUYA_INFO_SYS;
+ break;
+ case TUYA_BLE_SYS_FLASH_BACKUP_ADDR:
+ index = CFG_USER_TUYA_INFO_SYS_BK;
+ break;
+
+ default:
+ return TUYA_BLE_ERR_INVALID_ADDR;
+ }
+ syscfg_read(index, p_data, size);
+#endif
+ return TUYA_BLE_SUCCESS;
+}
+
+bool uart_dev_test_init_api(void);
+u16 uart_dev_test_send_api(void *data, u16 len);
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_common_uart_init(void)
+{
+ /* bool ret = uart_dev_test_init_api(); */
+ /* return ret ? TUYA_BLE_SUCCESS : TUYA_BLE_ERR_BUSY; */
+ return TUYA_BLE_SUCCESS;
+}
+
+extern tuya_ble_status_t tuya_ble_gatt_receive_data(uint8_t *p_data, uint16_t len);
+u8 JL_tuya_ble_gatt_receive_data(u8 *p_data, u16 len)
+{
+ return tuya_ble_gatt_receive_data(p_data, len);
+}
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK tuya_ble_status_t tuya_ble_common_uart_send_data(const uint8_t *p_data, uint16_t len)
+{
+ /* u16 wlen = uart_dev_test_send_api(p_data, len); */
+ /* return wlen == len ? TUYA_BLE_SUCCESS : TUYA_BLE_ERR_BUSY; */
+ return TUYA_BLE_SUCCESS;
+}
+
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_task_create(void **pp_handle, const char *p_name, void (*p_routine)(void *), void *p_param, uint16_t stack_size, uint16_t priority)
+{
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ int ret = os_task_create(p_routine, p_param, priority, stack_size, 256, p_name);
+ if (ret == 0) {
+ ble_task.ble_task_name = p_name;
+ os_sem_create(&ble_task.ble_sem, 0);
+ TUYA_BLE_LOG_DEBUG("%s succ\n", __func__);
+ }
+ return ret ? false : true;
+}
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_task_delete(void *p_handle)
+{
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ if (ble_task.ble_task_name) {
+ os_task_del(ble_task.ble_task_name);
+ os_sem_del(&ble_task.ble_sem, 0);
+ ble_task.ble_task_name = NULL;
+ }
+ return true;
+}
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_task_suspend(void *p_handle)
+{
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ if (ble_task.ble_task_name) {
+ os_sem_pend(&ble_task.ble_sem, 0);
+ }
+ return true;
+}
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_task_resume(void *p_handle)
+{
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ if (ble_task.ble_task_name) {
+ os_sem_set(&ble_task.ble_sem, 1);
+ os_sem_post(&ble_task.ble_sem);
+ }
+ return true;
+}
+
+struct ble_msg_queue {
+ cbuffer_t queue_hdl;
+ u8 *queue;
+ u8 enable;
+ u32 msg_size;
+};
+
+struct ble_msg_queue ble_queue;
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_msg_queue_create(void **pp_handle, uint32_t msg_num, uint32_t msg_size)
+{
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ memset(&ble_queue, 0x00, sizeof(ble_queue));
+ ble_queue.queue = malloc(msg_size * msg_num);
+ if (ble_queue.queue) {
+ *pp_handle = (void *)ble_queue.queue;
+ ble_queue.msg_size = msg_size;
+ cbuf_init(&ble_queue.queue_hdl, ble_queue.queue, msg_size * msg_num);
+ ble_queue.enable = 1;
+ return true;
+ }
+ return false;
+}
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_msg_queue_delete(void *p_handle)
+{
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ if (ble_queue.enable) {
+ ble_queue.enable = 0;
+ free(ble_queue.queue);
+ ble_queue.queue = NULL;
+ }
+ return true;
+}
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_msg_queue_peek(void *p_handle, uint32_t *p_msg_num)
+{
+ return true;
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_msg_queue_send(void *p_handle, void *p_msg, uint32_t wait_ms)
+{
+ if (ble_queue.enable) {
+ //TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ int wlen = cbuf_write(&ble_queue.queue_hdl, p_msg, ble_queue.msg_size);
+ os_taskq_post_msg(ble_task.ble_task_name, 2, BLE_TASK_MSG_MSG_COMES, (u32)p_handle);
+ }
+ return true;
+}
+
+static bool tuya_ble_os_msg_queue_recv_sub_deal(void *p_msg)
+{
+ tuya_ble_evt_param_t *evt = (tuya_ble_evt_param_t *)p_msg;
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ bool ret = false;
+ switch (evt->hdr.event) {
+ case TUYA_BLE_EVT_DATA_PASSTHROUGH:
+ break;
+
+ default:
+ return true;
+ }
+
+ return ret;
+}
+
+void (*tuya_cb_handler)(tuya_ble_cb_evt_param_t *event) = NULL;
+void tuya_event_to_earphone(u8 msg, u8 sub_msg, u32 value);
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_os_msg_queue_recv(void *p_handle, void *p_msg, uint32_t wait_ms)
+{
+ int ret;
+ int msg[16];
+ ret = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
+ if (ret != OS_TASKQ) {
+ return false;
+ }
+ if (msg[0] != Q_MSG) {
+ return false;
+ }
+
+ //TUYA_BLE_LOG_DEBUG("tuya_ble_os_msg_queue_recv\n");
+
+ bool b_ret = false;
+
+ switch (msg[1]) {
+ case BLE_TASK_MSG_MSG_COMES:
+ cbuf_read(&ble_queue.queue_hdl, p_msg, ble_queue.msg_size);
+ if ((u32)msg[2] == (u32)ble_queue.queue) {
+ b_ret = tuya_ble_os_msg_queue_recv_sub_deal(p_msg);
+ } else {
+ tuya_cb_handler = (void(*)(tuya_ble_cb_evt_param_t *))msg[2];
+ tuya_cb_handler((tuya_ble_cb_evt_param_t *)p_msg);
+ }
+ break;
+
+ case BLE_TASK_MSG_INFO_SYNC_AUTH:
+ //设备信息变更(比如mac变更,但是正常使用不会跑这里)要同步tws
+ // tuya_event_to_earphone(TUYA_BLE_TO_EARPHONE_SYNC_AUTH_MSG, 0, 0);
+ break;
+
+ case BLE_TASK_MSG_INFO_SYNC_SYS:
+ //app配对信息变更要同步tws
+ //tuya_event_to_earphone(TUYA_BLE_TO_EARPHONE_SYNC_SYS_MSG, 0, 0);
+ break;
+
+ default:
+ break;
+ }
+
+ //TUYA_BLE_LOG_DEBUG("deal ret %d\n", b_ret);
+
+ return b_ret;
+}
+
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+__TUYA_BLE_WEAK bool tuya_ble_event_queue_send_port(tuya_ble_evt_param_t *evt, uint32_t wait_ms)
+{
+ TUYA_BLE_LOG_DEBUG("%s\n", __func__);
+ return tuya_ble_os_msg_queue_send((void *)ble_queue.queue, evt, wait_ms);
+}
+
+
+
+/**
+ * @brief 128 bit AES ECB encryption on speicified plaintext and keys
+ * @param input specifed plain text to be encypted
+ * @param input_len byte length of the data to be descrypted, must be multiples of 16
+ * @param key keys to encrypt the plaintext
+ * @param output output buffer to store encrypted data
+ * @return encryption results
+ * @retval true successful
+ * @retval false fail
+ * @note least significant octet of encrypted data corresponds to encypted[0]
+ */
+__TUYA_BLE_WEAK bool tuya_ble_aes128_ecb_encrypt(uint8_t *key, uint8_t *input, uint16_t input_len, uint8_t *output)
+{
+ uint16_t length;
+ mbedtls_aes_context aes_ctx;
+ //
+ if (input_len % 16) {
+ return false;
+ }
+
+ length = input_len;
+
+ mbedtls_aes_init(&aes_ctx);
+
+ mbedtls_aes_setkey_enc(&aes_ctx, key, 128);
+
+ while (length > 0) {
+ mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, input, output);
+ input += 16;
+ output += 16;
+ length -= 16;
+ }
+
+ mbedtls_aes_free(&aes_ctx);
+
+ return true;
+}
+
+/**
+ * @brief 128 bit AES ECB decryption on speicified encrypted data and keys
+ * @param input specifed encypted data to be decypted
+ * @param input_len byte length of the data to be descrypted, must be multiples of 16
+ * @param key keys to decrypt the data
+ * @param output output buffer to store plain data
+ * @return decryption results
+ * @retval true successful
+ * @retval false fail
+ * @note least significant octet of encrypted data corresponds to encypted[0]
+*/
+__TUYA_BLE_WEAK bool tuya_ble_aes128_ecb_decrypt(uint8_t *key, uint8_t *input, uint16_t input_len, uint8_t *output)
+{
+ uint16_t length;
+ mbedtls_aes_context aes_ctx;
+ //
+ if (input_len % 16) {
+ return false;
+ }
+
+ length = input_len;
+
+ mbedtls_aes_init(&aes_ctx);
+
+ mbedtls_aes_setkey_dec(&aes_ctx, key, 128);
+
+ while (length > 0) {
+ mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_DECRYPT, input, output);
+ input += 16;
+ output += 16;
+ length -= 16;
+ }
+
+ mbedtls_aes_free(&aes_ctx);
+ return true;
+}
+/**
+ * @brief 128 bit AES CBC encryption on speicified plaintext and keys
+ * @param input specifed plain text to be encypted
+ * @param key keys to encrypt the plaintext
+ * @param output output buffer to store encrypted data
+ * @param iv initialization vector (IV) for CBC mode
+ * @param input_len byte length of the data to be descrypted, must be multiples of 16
+ * @return encryption results
+ * @retval true successful
+ * @retval false fail
+ * @note least significant octet of encrypted data corresponds to encypted[0]
+ */
+__TUYA_BLE_WEAK bool tuya_ble_aes128_cbc_encrypt(uint8_t *key, uint8_t *iv, uint8_t *input, uint16_t input_len, uint8_t *output)
+{
+ mbedtls_aes_context aes_ctx;
+
+ if (input_len % 16) {
+ return false;
+ }
+
+ mbedtls_aes_init(&aes_ctx);
+
+ mbedtls_aes_setkey_enc(&aes_ctx, key, 128);
+
+ mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, input_len, iv, input, output);
+
+ mbedtls_aes_free(&aes_ctx);
+
+ return true;
+}
+/**
+ * @brief 128 bit AES CBC descryption on speicified plaintext and keys
+ * @param input specifed encypted data to be decypted
+ * @param key keys to decrypt the data
+ * @param output output buffer to store plain data
+ * @param iv initialization vector (IV) for CBC mode
+ * @param input_len byte length of the data to be descrypted, must be multiples of 16
+ * @return encryption results
+ * @retval true successful
+ * @retval false fail
+ * @note least significant octet of encrypted data corresponds to encypted[0]
+ */
+__TUYA_BLE_WEAK bool tuya_ble_aes128_cbc_decrypt(uint8_t *key, uint8_t *iv, uint8_t *input, uint16_t input_len, uint8_t *output)
+{
+ mbedtls_aes_context aes_ctx;
+
+ if (input_len % 16) {
+ return false;
+ }
+
+ mbedtls_aes_init(&aes_ctx);
+
+ mbedtls_aes_setkey_dec(&aes_ctx, key, 128);
+
+ mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, input_len, iv, input, output);
+
+ mbedtls_aes_free(&aes_ctx);
+
+ return true;
+}
+/**
+ * @brief MD5 checksum
+ * @param input specifed plain text to be encypted
+ * @param output output buffer to store md5 result data,output data len is always 16
+ * @param input_len byte length of the data to be encypted
+ * @return encryption results
+ * @retval true successful
+ * @retval false fail
+ * @note
+ */
+__TUYA_BLE_WEAK bool tuya_ble_md5_crypt(uint8_t *input, uint16_t input_len, uint8_t *output)
+{
+ mbedtls_md5_context md5_ctx;
+ mbedtls_md5_init(&md5_ctx);
+ mbedtls_md5_starts(&md5_ctx);
+ mbedtls_md5_update(&md5_ctx, input, input_len);
+ mbedtls_md5_finish(&md5_ctx, output);
+ mbedtls_md5_free(&md5_ctx);
+ return true;
+}
+
+/**
+ * @brief This function calculates the full generic HMAC
+ * on the input buffer with the provided key.
+ * @param key The HMAC secret key.
+ * @param key_len The length of the HMAC secret key in Bytes.
+ * @param input specifed plain text to be encypted
+ * @param output output buffer to store the result data
+ * @param input_len byte length of the data to be encypted
+ * @return encryption results
+ * @retval true successful
+ * @retval false fail
+ * @note
+ */
+__TUYA_BLE_WEAK bool tuya_ble_hmac_sha1_crypt(const uint8_t *key, uint32_t key_len, const uint8_t *input, uint32_t input_len, uint8_t *output)
+{
+ return true;
+}
+
+/**
+ * @brief This function calculates the full generic HMAC
+ * on the input buffer with the provided key.
+ * @param key The HMAC secret key.
+ * @param key_len The length of the HMAC secret key in Bytes.
+ * @param input specifed plain text to be encypted
+ * @param output output buffer to store the result data
+ * @param input_len byte length of the data to be encypted
+ * @return encryption results
+ * @retval true successful
+ * @retval false fail
+ * @note
+ */
+__TUYA_BLE_WEAK bool tuya_ble_hmac_sha256_crypt(const uint8_t *key, uint32_t key_len, const uint8_t *input, uint32_t input_len, uint8_t *output)
+{
+ return true;
+}
+
+
+/**
+ * \brief Allocate a memory block with required size.
+ *
+ *
+ * \param[in] size Required memory size.
+ *
+ * \return The address of the allocated memory block. If the address is NULL, the
+ * memory allocation failed.
+ */
+__TUYA_BLE_WEAK void *tuya_ble_port_malloc(uint32_t size)
+{
+ return malloc(size);
+}
+
+
+
+/**
+ *
+ * \brief Free a memory block that had been allocated.
+ *
+ * \param[in] pv The address of memory block being freed.
+ *
+ * \return None.
+ */
+__TUYA_BLE_WEAK void tuya_ble_port_free(void *pv)
+{
+ return free(pv);
+}
+
+
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/port/tuya_ble_port_peripheral.c b/apps/common/third_party_profile/tuya_protocol/port/tuya_ble_port_peripheral.c
new file mode 100644
index 0000000..a9507b6
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/port/tuya_ble_port_peripheral.c
@@ -0,0 +1,32 @@
+/**
+ * \file tuya_ble_port_peripheral.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#include "tuya_ble_port.h"
+#include "tuya_ble_type.h"
+
+
+
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/port/tuya_ble_port_peripheral.h b/apps/common/third_party_profile/tuya_protocol/port/tuya_ble_port_peripheral.h
new file mode 100644
index 0000000..067e943
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/port/tuya_ble_port_peripheral.h
@@ -0,0 +1,43 @@
+/**
+ * \file tuya_ble_port_peripheral.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+
+#ifndef TUYA_BLE_PORT_PERIPHERAL_H__
+#define TUYA_BLE_PORT_PERIPHERAL_H__
+
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+
+
+
+
+
+
+#endif
+
+
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/port/tuya_ble_stdlib.h b/apps/common/third_party_profile/tuya_protocol/port/tuya_ble_stdlib.h
new file mode 100644
index 0000000..722aabd
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/port/tuya_ble_stdlib.h
@@ -0,0 +1,86 @@
+/**
+ * \file tuya_ble_stdlib.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+
+#ifndef TUYA_BLE_STDLIB_H__
+#define TUYA_BLE_STDLIB_H__
+
+/*
+ * If not using the standard library,please set to 0 . Then implement the library functions required by the TUYA BLE SDK in other files and declare in this file.
+ */
+
+#define TUYA_BLE_USE_STDLIB 1
+
+#if TUYA_BLE_USE_STDLIB
+
+#include "cpu.h"
+#include
+#include
+#include
+#include
+
+#else
+
+//
+typedef unsigned char uint8_t ;
+typedef signed char int8_t;
+
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+
+typedef int int32_t;
+typedef unsigned int uint32_t;
+
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+
+#define true 1
+#define false 0
+
+..........
+
+void *memset(void *str, int32_t c, uint32_t n);
+void *memcpy(void *str1, const void *str2, uint32_t n);
+int32_t memcmp(const void *str1, const void *str2, uint32_t n);
+uint32_t strlen(const char *str);
+int32_t rand(void);
+int64_t atoll(const char *str);
+
+.............
+
+
+
+#endif
+
+
+
+
+
+
+#endif
+
+
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_api.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_api.h
new file mode 100644
index 0000000..03bcbc6
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_api.h
@@ -0,0 +1,405 @@
+/**
+ * \file tuya_ble_api.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+
+#ifndef TUYA_BLE_API_H__
+#define TUYA_BLE_API_H__
+
+#include "tuya_ble_type.h"
+#include "tuya_ble_internal_config.h"
+#include "tuya_ble_port.h"
+
+#if (TUYA_BLE_USE_OS==0)
+/**
+ * @brief Function for executing all enqueued tasks.
+ *
+ * @note This function must be called from within the main loop. It will
+ * execute all events scheduled since the last time it was called.
+ * */
+void tuya_ble_main_tasks_exec(void);
+#endif
+
+/**
+ * @brief Function for transmit ble data from peer devices to tuya sdk.
+ *
+ * @note This function must be called from where the ble data is received.
+ *.
+ * */
+tuya_ble_status_t tuya_ble_gatt_receive_data(uint8_t *p_data, uint16_t len);
+
+/**
+ * @brief Function for transmit uart data to tuya sdk.
+ *
+ * @note This function must be called from where the uart data is received.
+ *.
+ * */
+tuya_ble_status_t tuya_ble_common_uart_receive_data(uint8_t *p_data, uint16_t len);
+
+/**
+ * @brief Function for send the full instruction received from uart to the sdk.
+ *
+ * @param
+ * [in]p_data : pointer to full instruction data(Complete instruction,include0x55 or 0x66 0xaa and checksum.)
+ * [in]len : Number of bytes of pdata.
+ *
+ * @note If the application uses a custom uart parsing algorithm to obtain the full uart instruction,then call this function to send the full instruction.
+ *
+ * */
+tuya_ble_status_t tuya_ble_common_uart_send_full_instruction_received(uint8_t *p_data, uint16_t len);
+
+
+/**
+ * @brief Function for update the device id to tuya sdk.
+ *
+ * @note the following id of the device must be update immediately when changed.
+ *.
+ * */
+
+tuya_ble_status_t tuya_ble_device_update_product_id(tuya_ble_product_id_type_t type, uint8_t len, uint8_t *p_buf);
+
+tuya_ble_status_t tuya_ble_device_update_login_key(uint8_t *p_buf, uint8_t len);
+
+#if ((TUYA_BLE_PROTOCOL_VERSION_HIGN==4) && (TUYA_BLE_BEACON_KEY_ENABLE))
+tuya_ble_status_t tuya_ble_device_update_beacon_key(uint8_t *p_buf, uint8_t len);
+#endif
+
+tuya_ble_status_t tuya_ble_device_update_bound_state(uint8_t state);
+
+tuya_ble_status_t tuya_ble_device_update_mcu_version(uint32_t mcu_firmware_version, uint32_t mcu_hardware_version);
+
+/**
+ * @brief Function for initialize the tuya sdk.
+ *
+ * @note appliction should call this after all platform init complete.
+ *.
+ * */
+
+tuya_ble_status_t tuya_ble_sdk_init(tuya_ble_device_param_t *param_data);
+
+
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN==4)
+
+/**
+ * @brief Function for send the dp point data.
+ *
+ * @param [in]sn: The sending sequence number of the application definition management.
+ * [in]type : DP_SEND_TYPE_ACTIVE- The device actively sends dp data;DP_SEND_TYPE_PASSIVE- The device passively sends dp data. For example, in order to answer the dp query command of the mobile app. Currently only applicable to WIFI+BLE combo devices.
+ * [in]mode : See the description in the 'tuya_ble_type.h' file for details.
+ * [in]ack : See the description in the 'tuya_ble_type.h' file for details.
+ * [in]p_dp_data : The pointer of dp data .
+ * [in]dp_data_len : The length of dp data .
+ * @note new api, The length of each dp data sent through this function must be 2 bytes. DTLD->'L' must be 2 bytes.
+ *.
+ * */
+tuya_ble_status_t tuya_ble_dp_data_send(uint32_t sn, tuya_ble_dp_data_send_type_t type, tuya_ble_dp_data_send_mode_t mode, tuya_ble_dp_data_send_ack_t ack, uint8_t *p_dp_data, uint32_t dp_data_len);
+
+/**
+ * @brief Function for send the dp data with time.
+ *
+ * @param [in]sn: The sending sequence number of the application definition management.
+ * [in]mode : See the description in the 'tuya_ble_type.h' file for details.
+ * [in]time_type : DP_TIME_TYPE_MS_STRING - Indicates that the following 'p_time_data' is a string of milliseconds that must be 13 bytes in length.
+ * E.g, 'p_time_data' points to the string "1600777955000";
+ * DP_TIME_TYPE_UNIX_TIMESTAMP - Indicates that the following 'p_time_data' points to the four-byte unix timestamp data.
+ * E.g, unix timestamp is 1600777955 = 0x5F69EEE3, then 'p_time_data' is {0x5F,0x69,0xEE,0xE3} ;
+ * [in]p_time_data : time data pointer.
+ * [in]p_dp_data : The pointer of dp data .
+ * [in]dp_data_len : The length of dp data .
+ * @note new api, The length of each dp data sent through this function must be 2 bytes. DTLD->'L' must be 2 bytes.
+ *. The default type of this function is 'DP_SEND_TYPE_ACTIVE', and the default ack is 'DP_SEND_WITH_RESPONSE', which cannot be changed.
+ * */
+tuya_ble_status_t tuya_ble_dp_data_with_time_send(uint32_t sn, tuya_ble_dp_data_send_mode_t mode, tuya_ble_dp_data_send_time_type_t time_type, uint8_t *p_time_data, uint8_t *p_dp_data, uint32_t dp_data_len);
+
+#else
+
+/**
+ * @brief Function for report the dp point data.
+ *
+ * @note
+ *.
+ * */
+
+tuya_ble_status_t tuya_ble_dp_data_report(uint8_t *p_data, uint32_t len);
+
+/**
+ * @brief Function for report the dp point data with time.
+ *
+ * @note
+ *.
+ * */
+
+tuya_ble_status_t tuya_ble_dp_data_with_time_report(uint32_t timestamp, uint8_t *p_data, uint32_t len);
+
+/**
+ * @brief Function for report the dp point data with time.
+ *
+ * @note time_string: 13-byte millisecond string ,for example ,"0000000123456";
+ *.
+ * */
+
+tuya_ble_status_t tuya_ble_dp_data_with_time_ms_string_report(uint8_t *time_string, uint8_t *p_data, uint32_t len);
+
+/**
+ * @brief Function for report the dp point data with flag.
+ *
+ * @note
+ *.
+ * */
+
+tuya_ble_status_t tuya_ble_dp_data_with_flag_report(uint16_t sn, tuya_ble_dp_data_send_mode_t mode, uint8_t *p_data, uint32_t len);
+
+/**
+ * @brief Function for report the dp point data with flag and time.
+ *
+ * @note
+ *.
+ * */
+
+tuya_ble_status_t tuya_ble_dp_data_with_flag_and_time_report(uint16_t sn, tuya_ble_dp_data_send_mode_t mode, uint32_t timestamp, uint8_t *p_data, uint32_t len);
+
+/**
+ * @brief Function for report the dp point data with flag and time.
+ *
+ * @note time_string: 13-byte millisecond string ,for example ,"0000000123456";
+ *.
+ * */
+tuya_ble_status_t tuya_ble_dp_data_with_flag_and_time_ms_string_report(uint16_t sn, tuya_ble_dp_data_send_mode_t mode, uint8_t *time_string, uint8_t *p_data, uint32_t len);
+
+#endif
+
+/**
+ * @brief Function for process the internal state of tuya sdk, application should call this in connect handler.
+ *
+ * @note
+ *.
+ * */
+void tuya_ble_connected_handler(void);
+
+
+/**
+ * @brief Function for process the internal state of tuya sdk, application should call this in disconnect handler.
+ *
+ * @note
+ *.
+ * */
+void tuya_ble_disconnected_handler(void);
+
+#if TUYA_BLE_LINK_LAYER_ENCRYPTION_SUPPORT_ENABLE
+
+/**
+ *@brief Function for update the link encrypted status to sdk, application should call this function when the link layer encryption is successful.
+ *@note
+ *
+ * */
+void tuya_ble_link_encrypted_handler(void);
+
+#endif
+
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN >= 3)
+/**
+ * @brief Function for process the internal state of tuya sdk, application should call this in disconnect handler.
+ * @param [in]on_off: 0-off ,1 - on.
+ * @note
+ *.
+ * */
+tuya_ble_status_t tuya_ble_adv_data_connecting_request_set(uint8_t on_off);
+#endif
+
+/**
+ * @brief Function for data passthrough.
+ *
+ * @note The tuya sdk will forwards the data to the app.
+ *.
+ * */
+tuya_ble_status_t tuya_ble_data_passthrough(uint8_t *p_data, uint32_t len);
+
+
+/**
+ * @brief Function for response the production test instruction asynchronous.
+ *
+ * @param [in]channel: 0-uart ,1 - ble.
+ * [in]pdata : pointer to production test cmd data(Complete instruction,include0x66 0xaa and checksum.)
+ * [in]len : Number of bytes of pdata.
+ * @note The tuya sdk will forwards the data to the app.
+ *.
+ * */
+tuya_ble_status_t tuya_ble_production_test_asynchronous_response(uint8_t channel, uint8_t *p_data, uint32_t len);
+
+/**
+ * @brief Function for response for the net config req.
+ *
+ * @note
+ *.
+ * */
+tuya_ble_status_t tuya_ble_net_config_response(int16_t result_code);
+
+
+#if (!TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+/**
+ * @brief Function for response for ubound req.
+ *
+ * @note
+ *.
+ * */
+tuya_ble_status_t tuya_ble_ubound_response(uint8_t result_code);
+
+
+/**
+ * @brief Function for response for anomaly ubound req.
+ *
+ * @note
+ *.
+ * */
+tuya_ble_status_t tuya_ble_anomaly_ubound_response(uint8_t result_code);
+
+/**
+ * @brief Function for response for device reset req.
+ *
+ * @note
+ *.
+ * */
+tuya_ble_status_t tuya_ble_device_reset_response(uint8_t result_code);
+
+#endif
+
+/**
+ * @brief Function for get the ble connet status.
+ *
+ * @note
+ *.
+ * */
+
+tuya_ble_connect_status_t tuya_ble_connect_status_get(void);
+
+/**
+ * @brief Function for notify the sdk the device has unbind.
+ *
+ * @note
+ *.
+ * */
+tuya_ble_status_t tuya_ble_device_unbind(void);
+
+/**
+ * @brief Function for notify the sdk the device has resumes factory Settings.
+ *
+ * @note When the device resumes factory Settings,shoule notify the sdk.
+ *.
+ * */
+
+tuya_ble_status_t tuya_ble_device_factory_reset(void);
+
+
+/**
+ * @brief Function for Request update time.
+ *
+ * @param time_type: 0-13-byte millisecond string [from cloud],1 - normal time format [from cloud] , 2 - normal time format[from app local]
+ * @note
+ *.
+ * */
+tuya_ble_status_t tuya_ble_time_req(uint8_t time_type);
+
+/**
+ * @brief Function for response the ota req.
+ *
+ * @note response the ota data req from call back event.
+ *.
+ * */
+
+tuya_ble_status_t tuya_ble_ota_response(tuya_ble_ota_response_t *p_data);
+
+
+
+/**
+ * @brief Function for send custom event to main process of ble sdk.
+ *
+ * @note
+ *.
+ * */
+uint8_t tuya_ble_custom_event_send(tuya_ble_custom_evt_t evt);
+
+
+
+#if TUYA_BLE_USE_OS
+
+/**
+ * @brief Function for registe queue to receive call back evt when use os
+ *
+ * @note
+ *
+ * */
+tuya_ble_status_t tuya_ble_callback_queue_register(void *cb_queue);
+
+/**
+ * @brief Function for response the event.
+ *
+ * @note if use os,must be sure to call this function after process one event in queue.
+ *
+ * */
+tuya_ble_status_t tuya_ble_event_response(tuya_ble_cb_evt_param_t *param);
+
+#else
+
+/**
+ * @brief Function for registe call back functions.
+ *
+ * @note appliction should receive the message from the call back registed by this function.
+ *
+ * */
+tuya_ble_status_t tuya_ble_callback_queue_register(tuya_ble_callback_t cb);
+
+/**
+ * @brief Function for get scheduler queue size.
+ *
+ * @note If it returns 0, it means that the queue has not been initialized.
+ *
+ * */
+uint16_t tuya_ble_scheduler_queue_size_get(void);
+/**
+ * @brief Function for get queue free space.
+ *
+ * @note
+ *
+ * */
+uint16_t tuya_ble_scheduler_queue_space_get(void);
+/**
+ * @brief Function for get the number of current events in the queue.
+ *
+ * @note
+ *
+ * */
+uint16_t tuya_ble_scheduler_queue_events_get(void);
+
+#endif
+
+/**
+ * @brief Function for check if sleep is allowed.
+ *
+ * @note If it returns true, it means that sleep is allowed.
+ *
+ * */
+bool tuya_ble_sleep_allowed_check(void);
+
+
+#endif
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_bulk_data.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_bulk_data.h
new file mode 100644
index 0000000..d49a845
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_bulk_data.h
@@ -0,0 +1,92 @@
+/**
+ * \file tuya_ble_bulkdata.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#ifndef TUYA_BLE_BULK_DATA_H_
+#define TUYA_BLE_BULK_DATA_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*********************************************************************
+ * INCLUDE
+ */
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+
+
+
+/**@brief Macro for defining bulk data transfer protocol. */
+
+#define FRM_BULK_DATA_READ_INFO_REQ 0x0007 //APP->BLE
+#define FRM_BULK_DATA_READ_INFO_RESP 0x0007 //BLE->APP
+#define FRM_BULK_DATA_READ_DATA_REQ 0x0008 //APP->BLE
+#define FRM_BULK_DATA_READ_DATA_RESP 0x0008 //BLE->APP
+#define FRM_BULK_DATA_SEND_DATA 0x0009 //BLE->APP
+#define FRM_BULK_DATA_ERASE_DATA_REQ 0x000A //APP->BLE
+#define FRM_BULK_DATA_ERASE_DATA_RESP 0x000A //BLE->APP
+
+
+
+/**@brief Function for get the block size used for bulk data reading.
+ *
+ *
+ * @param[out] block size used for bulk data reading.
+ * @note The block size depends on the mtu value negotiated after the BLE connection is established.
+ * If the return value is 0, stop the current bulk data transmission.
+ */
+uint32_t tuya_ble_bulk_data_read_block_size_get(void);
+
+/**@brief Function for handling the bulk data request.
+ *
+ *
+ * @param[in] cmd Request command.
+ * @param[in] p_recv_data Pointer to the buffer with received data.
+ * @param[in] recv_data_len Length of received data.
+ */
+void tuya_ble_handle_bulk_data_req(uint16_t cmd, uint8_t *p_recv_data, uint32_t recv_data_len);
+
+/**@brief Function for respond to app requests.
+ *
+ *
+ * @param[in] p_data The pointer to the response data.
+ */
+tuya_ble_status_t tuya_ble_bulk_data_response(tuya_ble_bulk_data_response_t *p_data);
+
+/**@brief Function for handling the bulk data events.
+ *
+ *
+ * @param[in] p_evt Event received from the application.
+ */
+void tuya_ble_handle_bulk_data_evt(tuya_ble_evt_param_t *p_evt);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //TUYA_BLE_BULKDATA_H_
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_data_handler.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_data_handler.h
new file mode 100644
index 0000000..1d4bc80
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_data_handler.h
@@ -0,0 +1,194 @@
+/**
+ * \file tuya_ble_data_handler.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#ifndef TUYA_BLE_DATA_HANDLER_H_
+#define TUYA_BLE_DATA_HANDLER_H_
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_internal_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define FRM_QRY_DEV_INFO_REQ 0x0000 //APP->BLE
+#define FRM_QRY_DEV_INFO_RESP 0x0000 //BLE->APP
+#define PAIR_REQ 0x0001 //APP->BLE
+#define PAIR_RESP 0x0001 //BLE->APP
+#define FRM_CMD_SEND 0x0002 //APP->BLE
+#define FRM_CMD_RESP 0x0002 //BLE->APP
+#define FRM_STATE_QUERY 0x0003 //APP->BLE
+#define FRM_STATE_QUERY_RESP 0x0003 //BLE->APP
+#define FRM_LOGIN_KEY_REQ 0x0004 //APP->BLE
+#define FRM_LOGIN_KEY_RESP 0x0004 //BLE->APP
+#define FRM_UNBONDING_REQ 0x0005 //APP->BLE
+#define FRM_UNBONDING_RESP 0x0005 //BLE->APP
+#define FRM_DEVICE_RESET 0x0006 //APP->BLE
+#define FRM_DEVICE_RESET_RESP 0x0006 //BLE->APP
+
+#define FRM_OTA_START_REQ 0x000C //APP->BLE
+#define FRM_OTA_START_RESP 0x000C //BLE->APP
+#define FRM_OTA_FILE_INFOR_REQ 0x000D //APP->BLE
+#define FRM_OTA_FILE_INFOR_RESP 0x000D //BLE->APP
+#define FRM_OTA_FILE_OFFSET_REQ 0x000E //APP->BLE
+#define FRM_OTA_FILE_OFFSET_RESP 0x000E //BLE->APP
+#define FRM_OTA_DATA_REQ 0x000F //APP->BLE
+#define FRM_OTA_DATA_RESP 0x000F //BLE->APP
+#define FRM_OTA_END_REQ 0x0010 //APP->BLE
+#define FRM_OTA_END_RESP 0x0010 //BLE->APP
+
+#define FRM_FACTORY_TEST_CMD 0x0012 //APP->BLE
+#define FRM_FACTORY_TEST_RESP 0x0012 //BLE->APP
+
+#define FRM_ANOMALY_UNBONDING_REQ 0x0014 //APP->BLE
+#define FRM_ANOMALY_UNBONDING_RESP 0x0014 //BLE->APP
+
+#define FRM_AUTHENTICATE_PHASE_1_REQ 0x0015 //APP->BLE
+#define FRM_AUTHENTICATE_PHASE_1_RESP 0x0015 //BLE->APP
+
+#define FRM_AUTHENTICATE_PHASE_2_REQ 0x0016 //APP->BLE
+#define FRM_AUTHENTICATE_PHASE_2_RESP 0x0016 //BLE->APP
+
+#define FRM_AUTHENTICATE_PHASE_3_REQ 0x0017 //APP->BLE
+#define FRM_AUTHENTICATE_PHASE_3_RESP 0x0017 //BLE->APP
+
+#define FRM_ANOMALY_UNBONDING_REQ 0x0014 //APP->BLE
+#define FRM_ANOMALY_UNBONDING_RESP 0x0014 //BLE->APP
+
+
+#define FRM_NET_CONFIG_INFO_REQ 0x0021 //APP->BLE
+#define FRM_NET_CONFIG_INFO_RESP 0x0021 //BLE->APP
+
+#define FRM_NET_CONFIG_RESPONSE_REPORT_REQ 0x0022 //APP->BLE
+#define FRM_NET_CONFIG_RESPONSE_REPORT_RESP 0x0022 //BLE->APP
+
+
+#define FRM_DATA_PASSTHROUGH_REQ 0x0023 //APP<->BLE
+
+#define FRM_DP_DATA_WRITE_REQ 0x0027 //APP->BLE
+#define FRM_DP_DATA_WRITE_RESP 0x0027 //BLE->APP
+
+#define FRM_STAT_REPORT 0x8001 //BLE->APP
+#define FRM_STAT_REPORT_RESP 0x8001 //APP->BLE
+
+#define FRM_STAT_WITH_TIME_REPORT 0x8003 //BLE->APP
+#define FRM_STAT_WITH_TIME_REPORT_RESP 0x8003 //APP->BLE
+
+#define FRM_DATA_WITH_FLAG_REPORT 0x8004 //BLE->APP
+#define FRM_DATA_WITH_FLAG_REPORT_RESP 0x8004 //APP->BLE
+
+#define FRM_DATA_WITH_FLAG_AND_TIME_REPORT 0x8005 //BLE->APP
+#define FRM_DATA_WITH_FLAG_AND_TIME_REPORT_RESP 0x8005 //APP->BLE
+
+#define FRM_DP_DATA_SEND_REQ 0x8006 //BLE->APP
+#define FRM_DP_DATA_SEND_RESP 0x8006 //APP->BLE
+
+#define FRM_DP_DATA_WITH_TIME_SEND_REQ 0x8007 //BLE->APP
+#define FRM_DP_DATA_WITH_TIME_SEND_RESP 0x8007 //APP->BLE
+
+#define FRM_WEATHER_DATA_REQUEST 0x8017 //BLE->APP
+#define FRM_WEATHER_DATA_REQUEST_RESP 0x8017 //APP->BLE
+
+#define FRM_WEATHER_DATA_RECEIVED 0x8018 //APP->BLE
+#define FRM_WEATHER_DATA_RECEIVED_RESP 0x8018 //BLE->APP
+
+#define FRM_GET_UNIX_TIME_MS_REQ 0x8010 //BLE->APP
+#define FRM_GET_UNIX_TIME_MS_RESP 0x8010 //APP->BLE
+#define FRM_GET_UNIX_TIME_CHAR_MS_REQ 0x8011 //BLE->APP
+#define FRM_GET_UNIX_TIME_CHAR_MS_RESP 0x8011 //APP->BLE
+#define FRM_GET_UNIX_TIME_CHAR_DATE_REQ 0x8012 //BLE->APP
+#define FRM_GET_UNIX_TIME_CHAR_DATE_RESP 0x8012 //APP->BLE
+
+#define FRM_GET_APP_LOCAL_TIME_REQ 0x8013 //BLE->APP
+#define FRM_GET_APP_LOCAL_TIME_RESP 0x8013 //APP->BLE
+#define FRM_GET_UNIX_TIME_WITH_DST_REQ 0x8014 //BLE->APP [timestamp + timezone + daylight saving time]
+#define FRM_GET_UNIX_TIME_WITH_DST_RESP 0x8014 //APP->BLE [timestamp + timezone + daylight saving time]
+
+typedef enum {
+ TUYA_BLE_OTA_STATUS_NONE,
+ TUYA_BLE_OTA_STATUS_START,
+ TUYA_BLE_OTA_STATUS_FILE_INFO,
+ TUYA_BLE_OTA_STATUS_FILE_OFFSET,
+ TUYA_BLE_OTA_STATUS_FILE_DATA,
+ TUYA_BLE_OTA_STATUS_FILE_END,
+ TUYA_BLE_OTA_STATUS_MAX,
+} tuya_ble_ota_status_t;
+
+
+typedef struct {
+ uint32_t send_len;
+ uint8_t *send_data;
+ uint32_t encrypt_data_buf_len;
+ uint8_t *encrypt_data_buf;
+} tuya_ble_r_air_send_packet;
+
+
+typedef struct {
+ uint32_t recv_len;
+ uint32_t recv_len_max;
+ uint8_t *recv_data;
+ uint32_t decrypt_buf_len;
+ uint8_t *de_encrypt_buf;
+} tuya_ble_r_air_recv_packet;
+
+void tuya_ble_air_recv_packet_free(void);
+
+void tuya_ble_set_device_version(uint32_t firmware_version, uint32_t hardware_version);
+
+void tuya_ble_set_external_mcu_version(uint32_t firmware_version, uint32_t hardware_version);
+
+uint8_t tuya_ble_commData_send(uint16_t cmd, uint32_t ack_sn, uint8_t *data, uint16_t len, uint8_t encryption_mode);
+
+uint8_t tuya_ble_send(uint16_t cmd, uint32_t ack_sn, uint8_t *data, uint16_t len);
+
+void tuya_ble_evt_process(uint16_t cmd, uint8_t *recv_data, uint32_t recv_len);
+
+void tuya_ble_reset_ble_sn(void);
+
+void tuya_ble_commonData_rx_proc(uint8_t *buf, uint16_t len);
+
+void tuya_ble_pair_rand_clear(void);
+
+uint8_t tuya_ble_pair_rand_valid_get(void);
+
+uint32_t tuya_ble_send_packet_data_length_get(void);
+
+void tuya_ble_device_unbond(void);
+
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE==TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION)
+
+void tuya_ble_auth_data_reset(void);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // TUYA_BLE_COMMDATA_HANDLER_H_
+
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_event.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_event.h
new file mode 100644
index 0000000..4ab4b95
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_event.h
@@ -0,0 +1,159 @@
+/**
+ * \file tuya_ble_event.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#ifndef TUYA_BLE_EVENT_H_
+#define TUYA_BLE_EVENT_H_
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#if (!TUYA_BLE_USE_OS)
+
+
+#define TUYA_BLE_EVT_MAX_NUM MAX_NUMBER_OF_TUYA_MESSAGE
+#define TUYA_BLE_EVT_SIZE 52 //64
+
+enum {
+ TUYA_BLE_EVT_SEND_SUCCESS = 0,
+ TUYA_BLE_EVT_SEND_NO_MEMORY = 1,
+ TUYA_BLE_EVT_SEND_FAIL = 2,
+};
+
+#define TUYA_BLE_ERROR_HANDLER(ERR_CODE)
+
+#define TUYA_BLE_ERROR_CHECK(ERR_CODE)
+
+#define TUYA_BLE_ERROR_CHECK_BOOL(BOOLEAN_VALUE)
+
+
+#define CEIL_DIV(A, B) \
+ (((A) + (B) - 1) / (B))
+
+/**@brief Compute number of bytes required to hold the scheduler buffer.
+ *
+ * @param[in] EVENT_SIZE Maximum size of events to be passed through the scheduler.
+ * @param[in] QUEUE_SIZE Number of entries in scheduler queue (i.e. the maximum number of events
+ * that can be scheduled for execution).
+ *
+ * @return Required scheduler buffer size (in bytes).
+ */
+#define TUYA_BLE_SCHED_BUF_SIZE(EVENT_SIZE, QUEUE_SIZE) \
+ ((EVENT_SIZE) * ((QUEUE_SIZE) + 1))
+
+
+/**@brief Macro for initializing the event scheduler.
+ *
+ * @details It will also handle dimensioning and allocation of the memory buffer required by the
+ * scheduler, making sure the buffer is correctly aligned.
+ *
+ * @param[in] EVENT_SIZE Maximum size of events to be passed through the scheduler.
+ * @param[in] QUEUE_SIZE Number of entries in scheduler queue (i.e. the maximum number of events
+ * that can be scheduled for execution).
+ *
+ * @note Since this macro allocates a buffer, it must only be called once (it is OK to call it
+ * several times as long as it is from the same location, e.g. to do a reinitialization).
+ */
+#define TUYA_BLE_SCHED_INIT(EVENT_SIZE, QUEUE_SIZE) \
+ do \
+ { \
+ static uint32_t TUYA_BLE_SCHED_BUF[CEIL_DIV(TUYA_BLE_SCHED_BUF_SIZE((EVENT_SIZE), (QUEUE_SIZE)), \
+ sizeof(uint32_t))]; \
+ uint32_t ERR_CODE = tuya_ble_sched_init((EVENT_SIZE), (QUEUE_SIZE), TUYA_BLE_SCHED_BUF); \
+ TUYA_BLE_ERROR_CHECK(ERR_CODE); \
+ } while (0)
+
+/**@brief Function for initializing the Scheduler.
+ *
+ * @details It must be called before entering the main loop.
+ *
+ * @param[in] max_event_size Maximum size of events to be passed through the scheduler.
+ * @param[in] queue_size Number of entries in scheduler queue (i.e. the maximum number of
+ * events that can be scheduled for execution).
+ * @param[in] p_evt_buffer Pointer to memory buffer for holding the scheduler queue. It must
+ * be dimensioned using the APP_SCHED_BUFFER_SIZE() macro. The buffer
+ * must be aligned to a 4 byte boundary.
+ *
+ * @note Normally initialization should be done using the TUYA_SCHED_INIT() macro, as that will both
+ * allocate the scheduler buffer, and also align the buffer correctly.
+ *
+ * @retval NRF_SUCCESS Successful initialization.
+ * @retval NRF_ERROR_INVALID_PARAM Invalid parameter (buffer not aligned to a 4 byte
+ * boundary).
+ */
+//uint32_t tuya_ble_sched_init(uint16_t max_event_size, uint16_t queue_size, void * p_evt_buffer);
+
+/**@brief Function for executing all scheduled events.
+ *
+ * @details This function must be called from within the main loop. It will execute all events
+ * scheduled since the last time it was called.
+ */
+void tuya_sched_execute(void);
+
+/**@brief Function for scheduling an event.
+ *
+ * @details Puts an event into the event queue.
+ *
+ * @param[in] p_event_data Pointer to event data to be scheduled.
+ * @param[in] event_size Size of event data to be scheduled.
+ * @param[in] handler Event handler to receive the event.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+//tuya_ble_status_t tuya_ble_sched_event_put(void const * p_event_data, uint16_t event_data_size);
+
+
+/**@brief Function for getting the current amount of free space in the queue.
+ *
+ * @details The real amount of free space may be less if entries are being added from an interrupt.
+ * To get the sxact value, this function should be called from the critical section.
+ *
+ * @return Amount of free space in the queue.
+ */
+uint16_t tuya_ble_sched_queue_size_get(void);
+
+uint16_t tuya_ble_sched_queue_space_get(void);
+
+uint16_t tuya_ble_sched_queue_events_get(void);
+
+void tuya_ble_event_queue_init(void);
+
+tuya_ble_status_t tuya_ble_message_send(tuya_ble_evt_param_t *evt);
+
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //
+
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_feature_weather.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_feature_weather.h
new file mode 100644
index 0000000..bc789f5
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_feature_weather.h
@@ -0,0 +1,221 @@
+/**
+ * \file tuya_ble_feature_weather.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#ifndef TUYA_BLE_FEATURE_WEATHER_H_
+#define TUYA_BLE_FEATURE_WEATHER_H_
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+
+
+/**@brief Total number of weather parameters currently supported. */
+#define SUPPORT_WEATHER_KEY_TYPE_MAX_NUMS ( 25 )
+
+
+/**@brief Weather key type. */
+typedef enum {
+ WKT_TEMP = (1 << 0), /**< temperature. */
+ WKT_THIHG = (1 << 1), /**< high temperature. */
+ WKT_TLOW = (1 << 2), /**< low temperature. */
+ WKT_HUMIDITY = (1 << 3), /**< humidity. */
+ WKT_CONDITION = (1 << 4), /**< weather condition. */
+ WKT_PRESSURE = (1 << 5), /**< pressure. */
+ WKT_REALFEEL = (1 << 6), /**< sendible temperature. */
+ WKT_UVI = (1 << 7), /**< uvi. */
+ WKT_SUNRISE = (1 << 8), /**< sunrise. */
+ WKT_SUNSET = (1 << 9), /**< sunset. */
+ WKT_UNIX = (1 << 10), /**< unix time, Use with sunrise and sunset. */
+ WKT_LOCAL = (1 << 11), /**< local time, Use with sunrise and sunset. */
+ WKT_WINDSPEED = (1 << 12), /**< wind speed. */
+ WKT_WINDDIR = (1 << 13), /**< wind direction. */
+ WKT_WINDLEVEL = (1 << 14), /**< wind speed scale/level. */
+ WKT_AQI = (1 << 15), /**< aqi. */
+ WKT_TIPS = (1 << 16), /**< tips. */
+ WKT_RANK = (1 << 17), /**< Detailed AQI status and national ranking. */
+ WKT_PM10 = (1 << 18), /**< pm10. */
+ WKT_PM25 = (1 << 19), /**< pm2.5. */
+ WKT_O3 = (1 << 20), /**< o3. */
+ WKT_NO2 = (1 << 21), /**< no2. */
+ WKT_CO = (1 << 22), /**< co. */
+ WKT_SO2 = (1 << 23), /**< so2. */
+ WKT_CONDITIONNUM = (1 << 24), /**< weather condition mapping id. */
+
+ WKT_COMBINE_BITMAP_MAXVAL = (1 << SUPPORT_WEATHER_KEY_TYPE_MAX_NUMS),
+} tuya_ble_weather_key_type_t;
+
+
+/**@brief Weather value type. */
+typedef enum {
+ WVT_INTEGER = 0,
+ WVT_STRING,
+} tuya_ble_weather_value_type_t;
+
+
+/**@brief Weather location type. */
+typedef enum {
+ WLT_PAIR_NETWORK_LOCATION = 1, /**< Pair network location. */
+ WLT_APP_CURRENT_LOCATION, /**< Mobile phone current location. */
+ WLT_CUSTOM_LOCATION, /**< The current sdk version unsupport. */
+
+ WLT_MAX,
+} tuya_ble_weather_location_type_t;
+
+
+/**@brief Weather data object structure.
+ *
+ */
+typedef struct {
+ uint8_t n_day; /**< which day. */
+ tuya_ble_weather_key_type_t key_type; /**< weather key type. */
+ tuya_ble_weather_value_type_t val_type; /**< weather value type. */
+ uint8_t value_len; /**< weather value length. */
+ char vaule[]; /**< weather values. */
+} tuya_ble_wd_object_t;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @brief Function for request weather data. Default request current location of mobile phone
+ *
+ * @note Example1: request temperatur & humidity and two days, called: tuya_ble_feature_weather_data_request((WKT_TEMP | WKT_HUMIDITY), 2);
+ * Example2: request sunrise data&time and ont day, called: tuya_ble_feature_weather_data_request((WKT_SUNRISE | WKT_LOCAL), 1);
+ * Example3: request highest temperature and seven days, called: tuya_ble_feature_weather_data_request((WKT_THIHG), 7);
+ * In addition, request sunrise/sunset must be matched with WKT_UNIX/WKT_LOCAL, otherwise the received data is unix time
+ *
+ * @param[in] combine_type Request combine types. For details, see the enum of tuya_ble_weather_key_type_t
+ * @param[in] n_days Request forecast days, rang from [1-7]; 1-means only today, 2-means today+tomorrow ...
+ *
+ * @retval TUYA_BLE_ERR_INVALID_PARAM The provided Parameters are not valid.
+ * @retval TUYA_BLE_ERR_NO_MEM If no memory is available to accept the operation.
+ * @retval TUYA_BLE_ERR_INTERNAL If weather request message send failed.
+ * @retval TUYA_BLE_SUCCESS Successful.
+ *
+ * */
+extern tuya_ble_status_t tuya_ble_feature_weather_data_request(uint32_t combine_type, uint8_t n_days);
+
+
+/**
+ * @brief Function for request weather data with appoint location.
+ *
+ * @param[in] location_type Request location types. For details, see the enum of tuya_ble_weather_location_type_t.
+ * @param[in] combine_type Request combine types. For details, see the enum of tuya_ble_weather_key_type_t
+ * @param[in] n_days Request forecast days, rang from [1-7]; 1-means only today, 2-means today+tomorrow ...
+ *
+ * @retval TUYA_BLE_ERR_INVALID_PARAM The provided Parameters are not valid.
+ * @retval TUYA_BLE_ERR_NO_MEM If no memory is available to accept the operation.
+ * @retval TUYA_BLE_ERR_INTERNAL If weather request message send failed.
+ * @retval TUYA_BLE_SUCCESS Successful.
+ *
+ * */
+extern tuya_ble_status_t tuya_ble_feature_weather_data_request_with_location(tuya_ble_weather_location_type_t location_type, uint32_t combine_type, uint8_t n_days);
+
+/**
+ * @brief Function for application parse received weather datas, In tuya_cb_handler() function
+ * add TUYA_BLE_CB_EVT_WEATHER_DATA_REQ_RESPONSE and TUYA_BLE_CB_EVT_WEATHER_DATA_RECEIVED callback
+ * event and process it. For example:
+ *
+ case TUYA_BLE_CB_EVT_WEATHER_DATA_REQ_RESPONSE:
+ TUYA_APP_LOG_INFO("received weather data request response result code =%d",event->weather_req_response_data.status);
+ break;
+
+ case TUYA_BLE_CB_EVT_WEATHER_DATA_RECEIVED:
+ tuya_ble_wd_object_t *object;
+ uint16_t object_len = 0;
+ for (;;) {
+ object = (tuya_ble_wd_object_t *)(event->weather_received_data.p_data + object_len);
+
+ TUYA_APP_LOG_DEBUG("recvived weather data, n_days=[%d] key=[0x%08x] val_type=[%d] val_len=[%d]", \
+ object->n_day, object->key_type, object->val_type, object->value_len);
+ TUYA_APP_LOG_HEXDUMP_DEBUG("vaule :", (uint8_t *)object->vaule, object->value_len);
+
+ // TODO .. YOUR JOBS
+
+ object_len += (sizeof(tuya_ble_wd_object_t) + object->value_len);
+ if (object_len >= event->weather_received_data.data_len)
+ break;
+ }
+ break;
+ * */
+
+
+/**
+ * @brief Function for convert weather enum type to string
+ *
+ * @note For example input convert type=WKT_TEMP, output key "w.temp"
+ *
+ * @param[in] type Convert type
+ * @param[out] key The ponit of weather key string
+ *
+ * @retval TUYA_BLE_ERR_INVALID_PARAM The provided Parameters are not valid.
+ * @retval TUYA_BLE_ERR_NOT_FOUND No corresponding type was found.
+ * @retval TUYA_BLE_SUCCESS Successful.
+ *
+ * */
+extern tuya_ble_status_t tuya_ble_feature_weather_key_enum_type_to_string(tuya_ble_weather_key_type_t type, char *key);
+
+
+/**
+ * @brief Function for handler weather data request event
+ *
+ * @details Internal use of tuya ble sdk
+ *
+ * @param[in] evt For details, see the struct of tuya_ble_evt_param_t
+ *
+ * */
+extern void tuya_ble_handle_weather_data_request_evt(tuya_ble_evt_param_t *evt);
+
+
+/**
+ * @brief Function for handler weather data request response/ack
+ *
+ * @details Internal use of tuya ble sdk
+ *
+ * @param[in] recv_data The point of recvived response data
+ * @param[in] recv_len The numbers of data
+ *
+ * */
+extern void tuya_ble_handle_weather_data_request_response(uint8_t *recv_data, uint16_t recv_len);
+
+
+/**
+ * @brief Function for handler weather data received
+ *
+ * @details Internal use of tuya ble sdk
+ *
+ * @param[in] recv_data The point of recvived weather data
+ * @param[in] recv_len The numbers of data
+ *
+ * */
+extern void tuya_ble_handle_weather_data_received(uint8_t *recv_data, uint16_t recv_len);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TUYA_BLE_FEATURE_WEATHER_H_ */
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_gatt_send_queue.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_gatt_send_queue.h
new file mode 100644
index 0000000..6f6b4d2
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_gatt_send_queue.h
@@ -0,0 +1,49 @@
+/**
+ * \file tuya_ble_gatt_send_queue.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#ifndef TUYA_BLE_GATT_SEND_QUEUE_H_
+#define TUYA_BLE_GATT_SEND_QUEUE_H_
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ uint8_t *buf;
+ uint8_t size;
+} tuya_ble_gatt_send_data_t;
+
+void tuya_ble_gatt_send_queue_init(void);
+void tuya_ble_gatt_send_data_handle(void *evt);
+tuya_ble_status_t tuya_ble_gatt_send_data_enqueue(uint8_t *p_data, uint8_t data_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //TUYA_BLE_GATT_SEND_QUEUE_H_
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_heap.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_heap.h
new file mode 100644
index 0000000..7745a55
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_heap.h
@@ -0,0 +1,114 @@
+/*
+ * FreeRTOS Kernel V10.0.0
+ * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. If you wish to use our Amazon
+ * FreeRTOS name, please do so in a fair use way that does not cause confusion.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * http://www.FreeRTOS.org
+ * http://aws.amazon.com/freertos
+ *
+ * 1 tab == 4 spaces!
+ */
+
+
+#ifndef TUYA_HEAP_H__
+#define TUYA_HEAP_H__
+
+#include "tuya_ble_stdlib.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if (TUYA_BLE_USE_PLATFORM_MEMORY_HEAP==0)
+
+#define portBYTE_ALIGNMENT 4
+
+
+
+#if portBYTE_ALIGNMENT == 32
+#define portBYTE_ALIGNMENT_MASK ( 0x001f )
+#endif
+
+#if portBYTE_ALIGNMENT == 16
+#define portBYTE_ALIGNMENT_MASK ( 0x000f )
+#endif
+
+#if portBYTE_ALIGNMENT == 8
+#define portBYTE_ALIGNMENT_MASK ( 0x0007 )
+#endif
+
+#if portBYTE_ALIGNMENT == 4
+#define portBYTE_ALIGNMENT_MASK ( 0x0003 )
+#endif
+
+#if portBYTE_ALIGNMENT == 2
+#define portBYTE_ALIGNMENT_MASK ( 0x0001 )
+#endif
+
+#if portBYTE_ALIGNMENT == 1
+#define portBYTE_ALIGNMENT_MASK ( 0x0000 )
+#endif
+
+#ifndef portBYTE_ALIGNMENT_MASK
+#error "Invalid portBYTE_ALIGNMENT definition"
+#endif
+
+
+#ifndef tuyaASSERT
+#define tuyaASSERT( x )
+#define tuyaASSERT_DEFINED 0
+#else
+#define tuyaASSERT_DEFINED 1
+#endif
+
+
+#ifndef tuyaCOVERAGE_TEST_MARKER
+#define tuyaCOVERAGE_TEST_MARKER()
+#endif
+
+
+#ifndef tuya_traceMALLOC
+#define tuya_traceMALLOC( pvAddress, uiSize )
+#endif
+
+#ifndef tuya_traceFREE
+#define tuya_traceFREE( pvAddress, uiSize )
+#endif
+
+
+
+void *pvTuyaPortMalloc(uint32_t xWantedSize);
+
+void vTuyaPortFree(void *pv);
+
+uint32_t xTuyaPortGetFreeHeapSize(void);
+
+uint32_t xTuyaPortGetMinimumEverFreeHeapSize(void);
+
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //TUYA_HEAP_H__
+
+/** @} */
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_internal_config.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_internal_config.h
new file mode 100644
index 0000000..4d800ca
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_internal_config.h
@@ -0,0 +1,150 @@
+/**
+ * \file tuya_ble_internal_config.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+
+#ifndef TUYA_BLE_INTERNAL_CONFIG_H__
+#define TUYA_BLE_INTERNAL_CONFIG_H__
+
+
+#include "tuya_ble_config.h"
+#include "tuya_ble_port.h"
+
+
+#define MAX_NUMBER_OF_TUYA_MESSAGE 16 //!< tuya ble message queue size
+
+
+//BLE Communication protocol version v4.2
+#define TUYA_BLE_PROTOCOL_VERSION_HIGN 0x04
+#define TUYA_BLE_PROTOCOL_VERSION_LOW 0x02
+
+#define TUYA_BLE_DP_WRITE_CURRENT_VERSION 0
+
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN>=4)
+
+#define TUYA_BLE_AIR_FRAME_MAX 1536
+
+#define TUYA_UART_RECEIVE_MAX_DP_DATA_LEN (512+4)
+
+#define TUYA_UART_RECEIVE_MAX_DP_BUFFER_DATA_LEN (512+4)
+
+#define TUYA_BLE_RECEIVE_MAX_DP_DATA_LEN (512+4)
+
+#define TUYA_BLE_SEND_MAX_DP_DATA_LEN TUYA_BLE_RECEIVE_MAX_DP_DATA_LEN
+
+#define TUYA_BLE_SEND_MAX_DATA_LEN (((TUYA_BLE_AIR_FRAME_MAX-17)/16)*16-14)
+
+#define TUYA_BLE_RECEIVE_MAX_DATA_LEN TUYA_BLE_SEND_MAX_DATA_LEN
+
+#else
+
+#define TUYA_BLE_ADVANCED_ENCRYPTION_DEVICE 0
+
+#define TUYA_BLE_AIR_FRAME_MAX 1024
+
+#define TUYA_UART_RECEIVE_MAX_DP_DATA_LEN (255+4)
+#define TUYA_UART_RECEIVE_MAX_DP_BUFFER_DATA_LEN (255+4)
+
+#define TUYA_BLE_RECEIVE_MAX_DP_DATA_LEN (255+3)
+
+#define TUYA_BLE_SEND_MAX_DP_DATA_LEN TUYA_BLE_RECEIVE_MAX_DP_DATA_LEN
+
+#define TUYA_BLE_REPORT_MAX_DP_DATA_LEN TUYA_BLE_RECEIVE_MAX_DP_DATA_LEN
+
+#define TUYA_BLE_TRANSMISSION_MAX_DATA_LEN (TUYA_BLE_AIR_FRAME_MAX-29)
+
+#define TUYA_BLE_SEND_MAX_DATA_LEN TUYA_BLE_TRANSMISSION_MAX_DATA_LEN
+
+#define TUYA_BLE_RECEIVE_MAX_DATA_LEN TUYA_BLE_SEND_MAX_DATA_LEN
+
+#endif
+
+
+#define TUYA_BLE_GATT_SEND_DATA_QUEUE_SIZE (MAX_NUMBER_OF_TUYA_MESSAGE*3)
+
+
+#if (TUYA_BLE_USE_PLATFORM_MEMORY_HEAP==0)
+/**
+ * MACRO for memory management
+ */
+#define TUYA_BLE_TOTAL_HEAP_SIZE 5120
+
+#if (TUYA_BLE_TOTAL_HEAP_SIZE<5120)
+#define TUYA_BLE_BULK_DATA_MAX_READ_BLOCK_SIZE 512
+#else
+#define TUYA_BLE_BULK_DATA_MAX_READ_BLOCK_SIZE 1024
+#endif
+
+#else
+#define TUYA_BLE_BULK_DATA_MAX_READ_BLOCK_SIZE 512
+#endif
+
+
+#ifndef TUYA_BLE_MAX_CALLBACKS
+#define TUYA_BLE_MAX_CALLBACKS 1
+#endif
+
+
+#define TUYA_BLE_AUTH_FLASH_ADDR (TUYA_NV_START_ADDR)
+#define TUYA_BLE_AUTH_FLASH_BACKUP_ADDR (TUYA_NV_START_ADDR+TUYA_NV_ERASE_MIN_SIZE)
+
+#define TUYA_BLE_SYS_FLASH_ADDR (TUYA_NV_START_ADDR+TUYA_NV_ERASE_MIN_SIZE*2)
+#define TUYA_BLE_SYS_FLASH_BACKUP_ADDR (TUYA_NV_START_ADDR+TUYA_NV_ERASE_MIN_SIZE*3)
+
+
+/**
+ * 1 - device register from ble 0 - from others
+ * @note:
+ */
+#define TUYA_BLE_DEVICE_REGISTER_FROM_BLE (TUYA_BLE_DEVICE_COMMUNICATION_ABILITY&TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_REGISTER_FROM_BLE)
+
+
+#define TUYA_BLE_DEVICE_AUTH_DATA_STORE TUYA_BLE_DEVICE_AUTH_SELF_MANAGEMENT
+
+/**
+ * if 1 ,tuya ble sdk authorization storage into extern medium, For example security chip
+ */
+#define TUYA_BLE_DEVICE_AUTH_DATA_STORE_EXT_MEDIUM 0
+
+
+/**
+ * if 1 ,used ble dongle for product test, the transmit datas will encryption
+ */
+#define TUYA_BLE_PROD_TEST_SUPPORT_ENCRYPTION 0
+
+
+/**
+ * if >=1, the product support oem, when execute prod test will write in pid and json config file
+ *
+ * Noticed!!! if enable the macro, need to realization 'tuya_ble_status_t tuya_ble_prod_storage_oem_info(uint8_t *para,uint16_t len)'
+ * function yourself at the custom_app_product_test.c
+ */
+#define TUYA_BLE_PROD_SUPPORT_OEM_TYPE TUYA_BLE_PROD_OEM_TYPE_NONE
+
+
+#if (TUYA_BLE_SYS_FLASH_BACKUP_ADDR>=(TUYA_NV_AREA_SIZE+TUYA_NV_START_ADDR))
+#error "Storage Memory overflow!"
+#endif
+
+
+#endif
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_log.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_log.h
new file mode 100644
index 0000000..61a80ec
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_log.h
@@ -0,0 +1,142 @@
+/**
+ * \file tuya_ble_log.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#ifndef TUYA_BLE_LOG_H__
+#define TUYA_BLE_LOG_H__
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_internal_config.h"
+#include "tuya_ble_log_internal.h"
+
+#if TUYA_BLE_LOG_ENABLE
+
+
+#ifndef TUYA_BLE_LOG_LEVEL
+#define TUYA_BLE_LOG_LEVEL TUYA_BLE_LOG_LEVEL_DEBUG
+#endif
+
+#ifndef TUYA_BLE_LOG_COLORS_ENABLE
+#define TUYA_BLE_LOG_COLORS_ENABLE 0
+#endif
+
+
+#define TUYA_BLE_LOG_ERROR(...) TUYA_BLE_LOG_INTERNAL_ERROR(__VA_ARGS__)
+#define TUYA_BLE_LOG_WARNING(...) TUYA_BLE_LOG_INTERNAL_WARNING( __VA_ARGS__)
+#define TUYA_BLE_LOG_INFO(...) TUYA_BLE_LOG_INTERNAL_INFO( __VA_ARGS__)
+#define TUYA_BLE_LOG_DEBUG(...) TUYA_BLE_LOG_INTERNAL_DEBUG( __VA_ARGS__)
+
+#define TUYA_BLE_LOG_HEXDUMP_ERROR(...) TUYA_BLE_LOG_INTERNAL_HEXDUMP_ERROR(__VA_ARGS__)
+#define TUYA_BLE_LOG_HEXDUMP_WARNING(...) TUYA_BLE_LOG_INTERNAL_HEXDUMP_WARNING( __VA_ARGS__)
+#define TUYA_BLE_LOG_HEXDUMP_INFO(...) TUYA_BLE_LOG_INTERNAL_HEXDUMP_INFO( __VA_ARGS__)
+#define TUYA_BLE_LOG_HEXDUMP_DEBUG(...) TUYA_BLE_LOG_INTERNAL_HEXDUMP_DEBUG( __VA_ARGS__)
+
+#else
+
+#define TUYA_BLE_LOG_ERROR(...)
+#define TUYA_BLE_LOG_WARNING(...)
+#define TUYA_BLE_LOG_INFO(...)
+#define TUYA_BLE_LOG_DEBUG(...)
+
+#define TUYA_BLE_LOG_HEXDUMP_ERROR(...)
+#define TUYA_BLE_LOG_HEXDUMP_WARNING(...)
+#define TUYA_BLE_LOG_HEXDUMP_INFO(...)
+#define TUYA_BLE_LOG_HEXDUMP_DEBUG(...)
+
+#endif //
+
+
+#if TUYA_APP_LOG_ENABLE
+
+#ifndef TUYA_APP_LOG_LEVEL
+#define TUYA_APP_LOG_LEVEL TUYA_APP_LOG_LEVEL_DEBUG
+#endif
+
+#ifndef TUYA_APP_LOG_COLORS_ENABLE
+#define TUYA_APP_LOG_COLORS_ENABLE 0
+#endif
+
+
+#define TUYA_APP_LOG_ERROR(...) TUYA_APP_LOG_INTERNAL_ERROR(__VA_ARGS__)
+#define TUYA_APP_LOG_WARNING(...) TUYA_APP_LOG_INTERNAL_WARNING( __VA_ARGS__)
+#define TUYA_APP_LOG_INFO(...) TUYA_APP_LOG_INTERNAL_INFO( __VA_ARGS__)
+#define TUYA_APP_LOG_DEBUG(...) TUYA_APP_LOG_INTERNAL_DEBUG( __VA_ARGS__)
+
+#define TUYA_APP_LOG_HEXDUMP_ERROR(...) TUYA_APP_LOG_INTERNAL_HEXDUMP_ERROR(__VA_ARGS__)
+#define TUYA_APP_LOG_HEXDUMP_WARNING(...) TUYA_APP_LOG_INTERNAL_HEXDUMP_WARNING( __VA_ARGS__)
+#define TUYA_APP_LOG_HEXDUMP_INFO(...) TUYA_APP_LOG_INTERNAL_HEXDUMP_INFO( __VA_ARGS__)
+#define TUYA_APP_LOG_HEXDUMP_DEBUG(...) TUYA_APP_LOG_INTERNAL_HEXDUMP_DEBUG( __VA_ARGS__)
+
+#else
+
+#define TUYA_APP_LOG_ERROR(...)
+#define TUYA_APP_LOG_WARNING(...)
+#define TUYA_APP_LOG_INFO(...)
+#define TUYA_APP_LOG_DEBUG(...)
+
+#define TUYA_APP_LOG_HEXDUMP_ERROR(...)
+#define TUYA_APP_LOG_HEXDUMP_WARNING(...)
+#define TUYA_APP_LOG_HEXDUMP_INFO(...)
+#define TUYA_APP_LOG_HEXDUMP_DEBUG(...)
+
+#endif //
+
+
+#ifdef TUYA_BLE_ASSERT
+
+#define TUYA_BLE_ERR_HANDLER(ERR_CODE) \
+ do \
+ { \
+ TUYA_BLE_LOG_ERROR("Error code 0x%04X <%d>. %s:%d\n", ERR_CODE, ERR_CODE, (uint32_t)__FILE__, __LINE__); \
+ } while (0)
+
+#define TUYA_BLE_ERR_CHECK(ERR_CODE) \
+ do \
+ { \
+ const uint32_t LOCAL_ERR_CODE = (ERR_CODE); \
+ if (LOCAL_ERR_CODE != 0) \
+ { \
+ TUYA_BLE_ERR_HANDLER(LOCAL_ERR_CODE); \
+ } \
+ } while (0)
+
+#define TUYA_BLE_ERR_TEST(ERR_CODE, EXPECT) \
+ do \
+ { \
+ const uint32_t LOCAL_ERR_CODE = (ERR_CODE); \
+ if (LOCAL_ERR_CODE != (EXPECT)) \
+ { \
+ TUYA_BLE_ERR_HANDLER(LOCAL_ERR_CODE); \
+ } \
+ } while (0)
+#else //
+
+#define TUYA_BLE_ERR_CHECK(ERR_CODE)
+
+#define TUYA_BLE_ERR_TEST(ERR_CODE, EXPECT)
+
+#endif //
+
+
+
+#endif // TUYA_BLE_LOG_H__
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_log_internal.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_log_internal.h
new file mode 100644
index 0000000..750d634
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_log_internal.h
@@ -0,0 +1,288 @@
+/**
+ * \file tuya_ble_log_internal.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#ifndef TUYA_BLE_LOG_INTERNAL__H__
+#define TUYA_BLE_LOG_INTERNAL__H__
+
+#include "tuya_ble_port.h"
+#include "tuya_ble_internal_config.h"
+
+
+#if !defined(TUYA_BLE_PRINTF)
+#error "Not defined printf function."
+#elif !defined(TUYA_BLE_HEXDUMP)
+#error "Not defined hexdump function."
+#endif
+
+
+#ifndef TUYA_BLE_LOG_COLORS_ENABLE
+#define TUYA_BLE_LOG_COLORS_ENABLE 0
+#endif
+
+#ifndef TUYA_BLE_LOG_MODULE_NAME
+#define TUYA_BLE_LOG_MODULE_NAME "TUYA_BLE"
+#endif
+
+
+
+#if TUYA_BLE_LOG_COLORS_ENABLE
+#define TUYA_BLE_LOG_COLOR_DEFAULT "\x1B[0m"
+#define TUYA_BLE_LOG_COLOR_BLACK "\x1B[1;30m"
+#define TUYA_BLE_LOG_COLOR_RED "\x1B[1;31m"
+#define TUYA_BLE_LOG_COLOR_GREEN "\x1B[1;32m"
+#define TUYA_BLE_LOG_COLOR_YELLOW "\x1B[1;33m"
+#define TUYA_BLE_LOG_COLOR_BLUE "\x1B[1;34m"
+#define TUYA_BLE_LOG_COLOR_MAGENTA "\x1B[1;35m"
+#define TUYA_BLE_LOG_COLOR_CYAN "\x1B[1;36m"
+#define TUYA_BLE_LOG_COLOR_WHITE "\x1B[1;37m"
+#else
+#define TUYA_BLE_LOG_COLOR_DEFAULT
+#define TUYA_BLE_LOG_COLOR_BLACK
+#define TUYA_BLE_LOG_COLOR_RED
+#define TUYA_BLE_LOG_COLOR_GREEN
+#define TUYA_BLE_LOG_COLOR_YELLOW
+#define TUYA_BLE_LOG_COLOR_BLUE
+#define TUYA_BLE_LOG_COLOR_MAGENTA
+#define TUYA_BLE_LOG_COLOR_CYAN
+#define TUYA_BLE_LOG_COLOR_WHITE
+#endif
+
+#define TUYA_BLE_LOG_ERROR_COLOR TUYA_BLE_LOG_COLOR_RED
+#define TUYA_BLE_LOG_WARNING_COLOR TUYA_BLE_LOG_COLOR_YELLOW
+#define TUYA_BLE_LOG_INFO_COLOR TUYA_BLE_LOG_COLOR_DEFAULT
+#define TUYA_BLE_LOG_DEBUG_COLOR TUYA_BLE_LOG_COLOR_GREEN
+#define TUYA_BLE_LOG_DEFAULT_COLOR TUYA_BLE_LOG_COLOR_DEFAULT
+
+#define TUYA_BLE_LOG_BREAK ": "
+
+//#define TUYA_BLE_LOG_CRLF "\r\n"
+#define TUYA_BLE_LOG_CRLF ""
+
+#define TUYA_BLE_ERROR_PREFIX TUYA_BLE_LOG_ERROR_COLOR "[E] " TUYA_BLE_LOG_MODULE_NAME TUYA_BLE_LOG_BREAK
+#define TUYA_BLE_WARNING_PREFIX TUYA_BLE_LOG_WARNING_COLOR "[W] " TUYA_BLE_LOG_MODULE_NAME TUYA_BLE_LOG_BREAK
+#define TUYA_BLE_INFO_PREFIX TUYA_BLE_LOG_INFO_COLOR "[I] " TUYA_BLE_LOG_MODULE_NAME TUYA_BLE_LOG_BREAK
+#define TUYA_BLE_DEBUG_PREFIX TUYA_BLE_LOG_DEBUG_COLOR "[D] " TUYA_BLE_LOG_MODULE_NAME TUYA_BLE_LOG_BREAK
+
+
+#define TUYA_BLE_LOG_INTERNAL_ERROR(_fmt_, ...) \
+do { \
+ if (TUYA_BLE_LOG_LEVEL >= TUYA_BLE_LOG_LEVEL_ERROR) \
+ { \
+ TUYA_BLE_PRINTF(TUYA_BLE_ERROR_PREFIX _fmt_ TUYA_BLE_LOG_DEFAULT_COLOR TUYA_BLE_LOG_CRLF, ##__VA_ARGS__); \
+ } \
+} while(0)
+
+#define TUYA_BLE_LOG_INTERNAL_WARNING(_fmt_, ...) \
+do { \
+ if (TUYA_BLE_LOG_LEVEL >= TUYA_BLE_LOG_LEVEL_WARNING) \
+ { \
+ TUYA_BLE_PRINTF(TUYA_BLE_WARNING_PREFIX _fmt_ TUYA_BLE_LOG_DEFAULT_COLOR TUYA_BLE_LOG_CRLF, ##__VA_ARGS__); \
+ } \
+} while(0)
+
+#define TUYA_BLE_LOG_INTERNAL_INFO(_fmt_, ...) \
+do { \
+ if (TUYA_BLE_LOG_LEVEL >= TUYA_BLE_LOG_LEVEL_INFO) \
+ { \
+ TUYA_BLE_PRINTF(TUYA_BLE_INFO_PREFIX _fmt_ TUYA_BLE_LOG_DEFAULT_COLOR TUYA_BLE_LOG_CRLF, ##__VA_ARGS__); \
+ } \
+} while(0)
+
+#define TUYA_BLE_LOG_INTERNAL_DEBUG(_fmt_, ...) \
+do { \
+ if (TUYA_BLE_LOG_LEVEL >= TUYA_BLE_LOG_LEVEL_DEBUG) \
+ { \
+ TUYA_BLE_PRINTF(TUYA_BLE_DEBUG_PREFIX _fmt_ TUYA_BLE_LOG_DEFAULT_COLOR TUYA_BLE_LOG_CRLF, ##__VA_ARGS__); \
+ } \
+} while(0)
+
+#define TUYA_BLE_LOG_INTERNAL_HEXDUMP_ERROR(_fmt_, p_data, len) \
+do { \
+ if (TUYA_BLE_LOG_LEVEL >= TUYA_BLE_LOG_LEVEL_ERROR) \
+ { \
+ TUYA_BLE_PRINTF(TUYA_BLE_ERROR_PREFIX _fmt_ TUYA_BLE_LOG_DEFAULT_COLOR " [len=%d] :" TUYA_BLE_LOG_CRLF,len ); \
+ TUYA_BLE_HEXDUMP(p_data, len); \
+ TUYA_BLE_PRINTF(TUYA_BLE_LOG_CRLF); \
+ } \
+} while(0)
+
+#define TUYA_BLE_LOG_INTERNAL_HEXDUMP_WARNING(_fmt_, p_data, len) \
+do { \
+ if (TUYA_BLE_LOG_LEVEL >= TUYA_BLE_LOG_LEVEL_WARNING) \
+ { \
+ TUYA_BLE_PRINTF(TUYA_BLE_WARNING_PREFIX _fmt_ TUYA_BLE_LOG_DEFAULT_COLOR " [len=%d] :" TUYA_BLE_LOG_CRLF,len); \
+ TUYA_BLE_HEXDUMP(p_data, len); \
+ TUYA_BLE_PRINTF(TUYA_BLE_LOG_CRLF); \
+ } \
+} while(0)
+
+#define TUYA_BLE_LOG_INTERNAL_HEXDUMP_INFO(_fmt_, p_data, len) \
+do { \
+ if (TUYA_BLE_LOG_LEVEL >= TUYA_BLE_LOG_LEVEL_INFO) \
+ { \
+ TUYA_BLE_PRINTF(TUYA_BLE_INFO_PREFIX _fmt_ TUYA_BLE_LOG_DEFAULT_COLOR " [len=%d] :" TUYA_BLE_LOG_CRLF,len); \
+ TUYA_BLE_HEXDUMP(p_data, len); \
+ TUYA_BLE_PRINTF(TUYA_BLE_LOG_CRLF); \
+ } \
+} while(0)
+
+#define TUYA_BLE_LOG_INTERNAL_HEXDUMP_DEBUG(_fmt_, p_data, len) \
+do { \
+ if (TUYA_BLE_LOG_LEVEL >= TUYA_BLE_LOG_LEVEL_DEBUG) \
+ { \
+ TUYA_BLE_PRINTF(TUYA_BLE_DEBUG_PREFIX _fmt_ TUYA_BLE_LOG_DEFAULT_COLOR " [len=%d] :" TUYA_BLE_LOG_CRLF,len); \
+ TUYA_BLE_HEXDUMP(p_data, len); \
+ TUYA_BLE_PRINTF(TUYA_BLE_LOG_CRLF); \
+ } \
+} while(0)
+
+
+
+/* TUYA APP LOG */
+
+#ifndef TUYA_APP_LOG_COLORS_ENABLE
+#define TUYA_APP_LOG_COLORS_ENABLE 0
+#endif
+
+#ifndef TUYA_APP_LOG_MODULE_NAME
+#define TUYA_APP_LOG_MODULE_NAME "TUYA_APP"
+#endif
+
+
+
+#if TUYA_APP_LOG_COLORS_ENABLE
+#define TUYA_APP_LOG_COLOR_DEFAULT "\x1B[0m"
+#define TUYA_APP_LOG_COLOR_BLACK "\x1B[1;30m"
+#define TUYA_APP_LOG_COLOR_RED "\x1B[1;31m"
+#define TUYA_APP_LOG_COLOR_GREEN "\x1B[1;32m"
+#define TUYA_APP_LOG_COLOR_YELLOW "\x1B[1;33m"
+#define TUYA_APP_LOG_COLOR_BLUE "\x1B[1;34m"
+#define TUYA_APP_LOG_COLOR_MAGENTA "\x1B[1;35m"
+#define TUYA_APP_LOG_COLOR_CYAN "\x1B[1;36m"
+#define TUYA_APP_LOG_COLOR_WHITE "\x1B[1;37m"
+#else
+#define TUYA_APP_LOG_COLOR_DEFAULT
+#define TUYA_APP_LOG_COLOR_BLACK
+#define TUYA_APP_LOG_COLOR_RED
+#define TUYA_APP_LOG_COLOR_GREEN
+#define TUYA_APP_LOG_COLOR_YELLOW
+#define TUYA_APP_LOG_COLOR_BLUE
+#define TUYA_APP_LOG_COLOR_MAGENTA
+#define TUYA_APP_LOG_COLOR_CYAN
+#define TUYA_APP_LOG_COLOR_WHITE
+#endif
+
+#define TUYA_APP_LOG_ERROR_COLOR TUYA_APP_LOG_COLOR_RED
+#define TUYA_APP_LOG_WARNING_COLOR TUYA_APP_LOG_COLOR_YELLOW
+#define TUYA_APP_LOG_INFO_COLOR TUYA_APP_LOG_COLOR_DEFAULT
+#define TUYA_APP_LOG_DEBUG_COLOR TUYA_APP_LOG_COLOR_GREEN
+#define TUYA_APP_LOG_DEFAULT_COLOR TUYA_APP_LOG_COLOR_DEFAULT
+
+#define TUYA_APP_LOG_BREAK ": "
+
+//#define TUYA_APP_LOG_CRLF "\r\n"
+#define TUYA_APP_LOG_CRLF ""
+
+#define TUYA_APP_ERROR_PREFIX TUYA_APP_LOG_ERROR_COLOR "[E] " TUYA_APP_LOG_MODULE_NAME TUYA_APP_LOG_BREAK
+#define TUYA_APP_WARNING_PREFIX TUYA_APP_LOG_WARNING_COLOR "[W] " TUYA_APP_LOG_MODULE_NAME TUYA_APP_LOG_BREAK
+#define TUYA_APP_INFO_PREFIX TUYA_APP_LOG_INFO_COLOR "[I] " TUYA_APP_LOG_MODULE_NAME TUYA_APP_LOG_BREAK
+#define TUYA_APP_DEBUG_PREFIX TUYA_APP_LOG_DEBUG_COLOR "[D] " TUYA_APP_LOG_MODULE_NAME TUYA_APP_LOG_BREAK
+
+
+#define TUYA_APP_LOG_INTERNAL_ERROR(_fmt_, ...) \
+do { \
+ if (TUYA_APP_LOG_LEVEL >= TUYA_APP_LOG_LEVEL_ERROR) \
+ { \
+ TUYA_BLE_PRINTF(TUYA_APP_ERROR_PREFIX _fmt_ TUYA_APP_LOG_DEFAULT_COLOR TUYA_APP_LOG_CRLF, ##__VA_ARGS__); \
+ } \
+} while(0)
+
+#define TUYA_APP_LOG_INTERNAL_WARNING(_fmt_, ...) \
+do { \
+ if (TUYA_APP_LOG_LEVEL >= TUYA_APP_LOG_LEVEL_WARNING) \
+ { \
+ TUYA_BLE_PRINTF(TUYA_APP_WARNING_PREFIX _fmt_ TUYA_APP_LOG_DEFAULT_COLOR TUYA_APP_LOG_CRLF, ##__VA_ARGS__); \
+ } \
+} while(0)
+
+#define TUYA_APP_LOG_INTERNAL_INFO(_fmt_, ...) \
+do { \
+ if (TUYA_APP_LOG_LEVEL >= TUYA_APP_LOG_LEVEL_INFO) \
+ { \
+ TUYA_BLE_PRINTF(TUYA_APP_INFO_PREFIX _fmt_ TUYA_APP_LOG_DEFAULT_COLOR TUYA_APP_LOG_CRLF, ##__VA_ARGS__); \
+ } \
+} while(0)
+
+#define TUYA_APP_LOG_INTERNAL_DEBUG(_fmt_, ...) \
+do { \
+ if (TUYA_APP_LOG_LEVEL >= TUYA_APP_LOG_LEVEL_DEBUG) \
+ { \
+ TUYA_BLE_PRINTF(TUYA_APP_DEBUG_PREFIX _fmt_ TUYA_APP_LOG_DEFAULT_COLOR TUYA_APP_LOG_CRLF, ##__VA_ARGS__); \
+ } \
+} while(0)
+
+#define TUYA_APP_LOG_INTERNAL_HEXDUMP_ERROR(_fmt_, p_data, len) \
+do { \
+ if (TUYA_APP_LOG_LEVEL >= TUYA_APP_LOG_LEVEL_ERROR) \
+ { \
+ TUYA_BLE_PRINTF(TUYA_APP_ERROR_PREFIX _fmt_ TUYA_APP_LOG_DEFAULT_COLOR " [len=%d] :" TUYA_APP_LOG_CRLF,len ); \
+ TUYA_BLE_HEXDUMP(p_data, len); \
+ TUYA_BLE_PRINTF(TUYA_APP_LOG_CRLF); \
+ } \
+} while(0)
+
+#define TUYA_APP_LOG_INTERNAL_HEXDUMP_WARNING(_fmt_, p_data, len) \
+do { \
+ if (TUYA_APP_LOG_LEVEL >= TUYA_APP_LOG_LEVEL_WARNING) \
+ { \
+ TUYA_BLE_PRINTF(TUYA_APP_WARNING_PREFIX _fmt_ TUYA_APP_LOG_DEFAULT_COLOR " [len=%d] :" TUYA_APP_LOG_CRLF,len); \
+ TUYA_BLE_HEXDUMP(p_data, len); \
+ TUYA_BLE_PRINTF(TUYA_APP_LOG_CRLF); \
+ } \
+} while(0)
+
+#define TUYA_APP_LOG_INTERNAL_HEXDUMP_INFO(_fmt_, p_data, len) \
+do { \
+ if (TUYA_APP_LOG_LEVEL >= TUYA_APP_LOG_LEVEL_INFO) \
+ { \
+ TUYA_BLE_PRINTF(TUYA_APP_INFO_PREFIX _fmt_ TUYA_APP_LOG_DEFAULT_COLOR " [len=%d] :" TUYA_APP_LOG_CRLF,len); \
+ TUYA_BLE_HEXDUMP(p_data, len); \
+ TUYA_BLE_PRINTF(TUYA_APP_LOG_CRLF); \
+ } \
+} while(0)
+
+#define TUYA_APP_LOG_INTERNAL_HEXDUMP_DEBUG(_fmt_, p_data, len) \
+do { \
+ if (TUYA_APP_LOG_LEVEL >= TUYA_APP_LOG_LEVEL_DEBUG) \
+ { \
+ TUYA_BLE_PRINTF(TUYA_APP_DEBUG_PREFIX _fmt_ TUYA_APP_LOG_DEFAULT_COLOR " [len=%d] :" TUYA_APP_LOG_CRLF,len); \
+ TUYA_BLE_HEXDUMP(p_data, len); \
+ TUYA_BLE_PRINTF(TUYA_APP_LOG_CRLF); \
+ } \
+} while(0)
+
+
+#endif // TUYA_BLE_LOG_INTERNAL__H__
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_main.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_main.h
new file mode 100644
index 0000000..7d33775
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_main.h
@@ -0,0 +1,78 @@
+/**
+ * \file tuya_ble_main.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+
+#ifndef TUYA_BLE_MAIN_H__
+#define TUYA_BLE_MAIN_H__
+
+#include "tuya_ble_type.h"
+#include "tuya_ble_internal_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern tuya_ble_parameters_settings_t tuya_ble_current_para;
+
+void tuya_ble_connect_status_set(tuya_ble_connect_status_t status);
+
+tuya_ble_connect_status_t tuya_ble_connect_status_get(void);
+
+#if TUYA_BLE_LINK_LAYER_ENCRYPTION_SUPPORT_ENABLE
+
+void tuya_ble_link_status_set(tuya_ble_link_status_t status);
+
+tuya_ble_link_status_t tuya_ble_link_status_get(void);
+
+#endif
+
+void tuya_ble_event_init(void);
+
+uint8_t tuya_ble_event_send(tuya_ble_evt_param_t *evt);
+
+uint8_t tuya_ble_cb_event_send(tuya_ble_cb_evt_param_t *evt);
+
+uint8_t tuya_ble_get_adv_connect_request_bit_status(void);
+
+void tuya_ble_adv_change(void);
+
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN >= 3)
+void tuya_ble_adv_change_with_connecting_request(void);
+#endif
+
+tuya_ble_status_t tuya_ble_inter_event_response(tuya_ble_cb_evt_param_t *param);
+
+void tuya_ble_connect_monitor_timer_init(void);
+
+void tuya_ble_connect_monitor_timer_start(void);
+
+void tuya_ble_connect_monitor_timer_stop(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_mem.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_mem.h
new file mode 100644
index 0000000..b19c0a9
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_mem.h
@@ -0,0 +1,54 @@
+/**
+ * \file tuya_ble_mem.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+
+#ifndef TUYA_BLE_MEM_H__
+#define TUYA_BLE_MEM_H__
+
+#include "tuya_ble_type.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void *tuya_ble_malloc(uint16_t size);
+
+tuya_ble_status_t tuya_ble_free(uint8_t *ptr);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
+
+
+
+
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_mutli_tsf_protocol.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_mutli_tsf_protocol.h
new file mode 100644
index 0000000..8cbc0d7
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_mutli_tsf_protocol.h
@@ -0,0 +1,316 @@
+/**
+ * \file tuya_ble_mutli_tsf_protocol.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+#ifndef _TUYA_BLE_MUTLI_TSF_PROTOCOL_H
+#define _TUYA_BLE_MUTLI_TSF_PROTOCOL_H
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __MUTLI_TSF_PROTOCOL_GLOBALS
+#define __MUTLI_TSF_PROTOCOL_EXT
+#else
+#define __MUTLI_TSF_PROTOCOL_EXT extern
+#endif
+
+/***********************************************************
+*************************micro define***********************
+***********************************************************/
+#define SNGL_PKG_TRSFR_LMT TUYA_BLE_DATA_MTU_MAX // single package transfer limit
+
+//#define FRM_TYPE_OFFSET (0x0f << 4)
+#define FRM_VERSION_OFFSET (0x0f << 4)
+#define FRM_SEQ_OFFSET (0x0f << 0)
+
+// frame total len
+typedef uint32_t frame_total_t;
+
+// frame subpackage num
+typedef uint32_t frame_subpkg_num_t;
+
+
+// frame sequence
+typedef uint8_t frame_seq_t;
+
+#define FRAME_SEQ_LMT 16
+
+// frame subpackage len
+typedef uint16_t frame_subpkg_len_t;
+
+// frame package description
+typedef uint8_t frm_pkg_desc_t;
+#define FRM_PKG_INIT 0 // frame package init
+#define FRM_PKG_FIRST 1 // frame package first
+#define FRM_PKG_MIDDLE 2 // frame package middle
+#define FRM_PKG_END 3 // frame package end
+
+// mutil tsf ret code
+typedef int32_t mtp_ret;
+#define MTP_OK 0
+#define MTP_INVALID_PARAM 1
+#define MTP_COM_ERROR 2
+#define MTP_TRSMITR_CONTINUE 3
+#define MTP_TRSMITR_ERROR 4
+#define MTP_MALLOC_ERR 5
+
+// frame transmitter process
+typedef struct {
+ frame_total_t total; //4 bytes, total length of data, not including header
+ uint8_t version; //1 byte, protocol major version number
+ frame_seq_t seq; //1 byte
+ frm_pkg_desc_t pkg_desc; //1 byte, Current packet frame type (init/first/middle/end)
+ frame_subpkg_num_t subpkg_num;//4 bytes, current sub-packet number
+ uint32_t pkg_trsmitr_cnt; // package process count ,Number of bytes sent
+ frame_subpkg_len_t subpkg_len;//1 byte, the data length in the current sub-packet
+ uint8_t subpkg[SNGL_PKG_TRSFR_LMT];
+} frm_trsmitr_proc_s;
+
+
+// dp type description,please refer to the relevant help documents of Tuya iot platform for the usage of various types of dp points.
+typedef uint8_t dp_type;
+#define DT_RAW 0
+#define DT_BOOL 1
+#define DT_VALUE 2
+#define DT_INT DT_VALUE
+#define DT_STRING 3
+#define DT_ENUM 4
+#define DT_BITMAP 5
+#define DT_CHAR 7 //Not currently supported
+#define DT_UCHAR 8 //Not currently supported
+#define DT_SHORT 9 //Not currently supported
+#define DT_USHORT 10 //Not currently supported
+#define DT_LMT DT_USHORT
+
+#define DT_VALUE_LEN 4 // int
+#define DT_BOOL_LEN 1
+#define DT_ENUM_LEN 1
+#define DT_BITMAP_MAX 4 // 1/2/4
+#define DT_STR_MAX 255
+#define DT_RAW_MAX 255
+#define DT_INT_LEN DT_VALUE_LEN
+
+typedef struct s_klv_node {
+ struct s_klv_node *next;
+ uint8_t id;
+ dp_type type;
+ uint16_t len;
+ uint8_t *data;
+} klv_node_s;
+
+
+/***********************************************************
+*************************variable define********************
+***********************************************************/
+
+
+/***********************************************************
+*************************function define********************
+***********************************************************/
+/***********************************************************
+* Function: make_klv_list
+* description:
+* Input:
+* Output:
+* Return:
+***********************************************************/
+__MUTLI_TSF_PROTOCOL_EXT \
+klv_node_s *make_klv_list(klv_node_s *list, uint8_t id, dp_type type, \
+ void *data, uint16_t len);
+
+/***********************************************************
+* Function: free_klv_list
+* description:
+* Input: list
+* Output:
+* Return:
+***********************************************************/
+__MUTLI_TSF_PROTOCOL_EXT \
+void free_klv_list(klv_node_s *list);
+
+/***********************************************************
+* Function: klvlist_2_data
+* description:
+* Input: list
+* Output: data len
+* Return:
+* Note:data need free.
+***********************************************************/
+__MUTLI_TSF_PROTOCOL_EXT \
+mtp_ret klvlist_2_data(klv_node_s *list, uint8_t **data, uint32_t *len, uint8_t type);
+
+/***********************************************************
+* Function: data_2_klvlist
+* description:
+* Input: data len
+* Output: list
+* Return:
+* Note: list need to call free_klv_list to free.
+***********************************************************/
+__MUTLI_TSF_PROTOCOL_EXT \
+mtp_ret data_2_klvlist(uint8_t *data, uint32_t len, klv_node_s **list, uint8_t type);
+
+/***********************************************************
+* Function: create_trsmitr_init
+* description: create a transmitter and initialize
+* Input: none
+* Output:
+* Return: transmitter handle
+***********************************************************/
+__MUTLI_TSF_PROTOCOL_EXT \
+frm_trsmitr_proc_s *create_trsmitr_init(void);
+
+/***********************************************************
+* Function: trsmitr_init
+* description: init a transmitter
+* Input: transmitter handle
+* Output:
+* Return:
+***********************************************************/
+__MUTLI_TSF_PROTOCOL_EXT \
+void trsmitr_init(frm_trsmitr_proc_s *frm_trsmitr);
+
+/***********************************************************
+* Function: delete_trsmitr
+* description: delete transmitter
+* Input: transmitter handle
+* Output:
+* Return:
+***********************************************************/
+__MUTLI_TSF_PROTOCOL_EXT \
+void delete_trsmitr(frm_trsmitr_proc_s *frm_trsmitr);
+
+/***********************************************************
+* Function: get_trsmitr_frame_total_len
+* description: get a transmitter total data len
+* Input: transmitter handle
+* Output:
+* Return: frame_total_t
+***********************************************************/
+__MUTLI_TSF_PROTOCOL_EXT \
+frame_total_t get_trsmitr_frame_total_len(frm_trsmitr_proc_s *frm_trsmitr);
+
+/***********************************************************
+* Function: get_trsmitr_frame_type
+* description:
+* Input: transmitter handle
+* Output:
+* Return: frame_type_t
+***********************************************************/
+__MUTLI_TSF_PROTOCOL_EXT \
+uint8_t get_trsmitr_frame_version(frm_trsmitr_proc_s *frm_trsmitr);
+
+/***********************************************************
+* Function: get_trsmitr_frame_seq
+* description:
+* Input: transmitter handle
+* Output:
+* Return: frame_seq_t
+***********************************************************/
+__MUTLI_TSF_PROTOCOL_EXT \
+frame_seq_t get_trsmitr_frame_seq(frm_trsmitr_proc_s *frm_trsmitr);
+
+/***********************************************************
+* Function: get_trsmitr_subpkg_len
+* description:
+* Input: transmitter handle
+* Output:
+* Return: frame_subpkg_len_t
+***********************************************************/
+__MUTLI_TSF_PROTOCOL_EXT \
+frame_subpkg_len_t get_trsmitr_subpkg_len(frm_trsmitr_proc_s *frm_trsmitr);
+
+/***********************************************************
+* Function: get_trsmitr_subpkg
+* description:
+* Input: transmitter handle
+* Output:
+* Return: subpackage buf
+***********************************************************/
+__MUTLI_TSF_PROTOCOL_EXT \
+uint8_t *get_trsmitr_subpkg(frm_trsmitr_proc_s *frm_trsmitr);
+
+/***********************************************************
+* Function: trsmitr_send_pkg_encode
+* description: frm_trsmitr->transmitter handle
+* type->frame type
+* buf->data buf
+* len->data len
+* Input:
+* Output:
+* Return: MTP_OK->buf send up
+* MTP_TRSMITR_CONTINUE->need call again to be continue
+* other->error
+* Note: could get from encode data len and encode data by calling method
+ get_trsmitr_subpkg_len() and get_trsmitr_subpkg()
+***********************************************************/
+__MUTLI_TSF_PROTOCOL_EXT \
+mtp_ret trsmitr_send_pkg_encode(frm_trsmitr_proc_s *frm_trsmitr, uint8_t version, uint8_t *buf, uint32_t len);
+
+/***********************************************************
+* Function: trsmitr_send_pkg_encode_with_packet_length
+* description: Encoding function for specifying sub-packet length
+*
+*
+*
+* Input:
+* Output:
+* Return: MTP_OK->buf send up
+* MTP_TRSMITR_CONTINUE->need call again to be continue
+* other->error
+* Note: could get from encode data len and encode data by calling method
+ get_trsmitr_subpkg_len() and get_trsmitr_subpkg()
+***********************************************************/
+__MUTLI_TSF_PROTOCOL_EXT \
+mtp_ret trsmitr_send_pkg_encode_with_packet_length(frm_trsmitr_proc_s *frm_trsmitr, uint32_t pkg_len_max, uint8_t version, uint8_t *buf, uint32_t len);
+
+/***********************************************************
+* Function: trsmitr_recv_pkg_decode
+* description: frm_trsmitr->transmitter handle
+* raw_data->raw encode data
+* raw_data_len->raw encode data len
+* Input:
+* Output:
+* Return: MTP_OK->buf receive up
+* MTP_TRSMITR_CONTINUE->need call again to be continue
+* other->error
+* Note: could get from decode data len and decode data by calling method
+ get_trsmitr_subpkg_len() and get_trsmitr_subpkg()
+***********************************************************/
+__MUTLI_TSF_PROTOCOL_EXT \
+mtp_ret trsmitr_recv_pkg_decode(frm_trsmitr_proc_s *frm_trsmitr, uint8_t *raw_data, uint16_t raw_data_len);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_queue.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_queue.h
new file mode 100644
index 0000000..e1679d8
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_queue.h
@@ -0,0 +1,56 @@
+/**
+ * \file tuya_ble_queue.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#ifndef TUYA_BLE_QUEUE_H_
+#define TUYA_BLE_QUEUE_H_
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ void *buf;
+ volatile uint8_t size;
+ volatile uint8_t offset;
+ volatile uint8_t rd_ptr;
+ volatile uint8_t wr_ptr;
+ volatile uint8_t used;
+} tuya_ble_queue_t;
+
+tuya_ble_status_t tuya_ble_queue_init(tuya_ble_queue_t *q, void *buf, uint8_t size, uint8_t elem_size);
+tuya_ble_status_t tuya_ble_enqueue(tuya_ble_queue_t *q, void *in);
+tuya_ble_status_t tuya_ble_queue_get(tuya_ble_queue_t *q, void *out);
+tuya_ble_status_t tuya_ble_dequeue(tuya_ble_queue_t *q, void *out);
+void tuya_ble_queue_decrease(tuya_ble_queue_t *q);
+void tuya_ble_queue_flush(tuya_ble_queue_t *q);
+uint8_t tuya_ble_get_queue_used(tuya_ble_queue_t *q);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //TUYA_BLE_QUEUE_H_
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_storage.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_storage.h
new file mode 100644
index 0000000..a8f1278
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_storage.h
@@ -0,0 +1,53 @@
+/**
+ * \file tuya_ble_storage.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#ifndef TUYA_BLE_STORAGE_H_
+#define TUYA_BLE_STORAGE_H_
+
+#include "tuya_ble_type.h"
+#include "tuya_ble_internal_config.h"
+
+uint32_t tuya_ble_storage_save_sys_settings(void);
+
+uint32_t tuya_ble_storage_save_auth_settings(void);
+
+uint32_t tuya_ble_storage_init(void);
+
+
+#if (TUYA_BLE_DEVICE_AUTH_DATA_STORE)
+
+tuya_ble_status_t tuya_ble_storage_write_pid(tuya_ble_product_id_type_t pid_type, uint8_t pid_len, uint8_t *pid);
+
+tuya_ble_status_t tuya_ble_storage_write_hid(uint8_t *hid, uint8_t len);
+
+tuya_ble_status_t tuya_ble_storage_read_id_info(tuya_ble_factory_id_data_t *id);
+
+tuya_ble_status_t tuya_ble_storage_write_auth_key_device_id_mac(uint8_t *auth_key, uint8_t auth_key_len, uint8_t *device_id, uint8_t device_id_len,
+ uint8_t *mac, uint8_t mac_len, uint8_t *mac_string, uint8_t mac_string_len, uint8_t *pid, uint8_t pid_len);
+
+#endif
+
+#endif
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_type.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_type.h
new file mode 100644
index 0000000..b7845b3
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_type.h
@@ -0,0 +1,1057 @@
+/**
+ * \file tuya_ble_type.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+
+#ifndef TUYA_BLE_TYPE_H__
+#define TUYA_BLE_TYPE_H__
+
+#include "tuya_ble_stdlib.h"
+
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#if defined(__CC_ARM)
+#pragma anon_unions
+#elif defined(__ICCARM__)
+#pragma language = extended
+#elif defined(__GNUC__)
+/* anonymous unions are enabled by default */
+#endif
+
+
+#if defined ( __CC_ARM )
+
+#ifndef __TUYA_BLE_ASM
+#define __TUYA_BLE_ASM __asm
+#endif
+
+#ifndef __TUYA_BLE_INLINE
+#define __TUYA_BLE_INLINE __inline
+#endif
+
+#ifndef __TUYA_BLE_WEAK
+#define __TUYA_BLE_WEAK __weak
+#endif
+
+#ifndef __TUYA_BLE_ALIGN
+#define __TUYA_BLE_ALIGN(n) __align(n)
+#endif
+
+#ifndef __TUYA_BLE_PACKED
+#define __TUYA_BLE_PACKED __packed
+#endif
+
+#define TUYA_BLE_GET_SP() __current_sp()
+
+#elif defined ( __ICCARM__ )
+
+#ifndef __TUYA_BLE_ASM
+#define __TUYA_BLE_ASM __asm
+#endif
+
+#ifndef __TUYA_BLE_INLINE
+#define __TUYA_BLE_INLINE inline
+#endif
+
+#ifndef __TUYA_BLE_WEAK
+#define __TUYA_BLE_WEAK __weak
+#endif
+
+#ifndef __TUYA_BLE_ALIGN
+#define TUYA_BLE_STRING_PRAGMA(x) _Pragma(#x)
+#define __TUYA_BLE_ALIGN(n) STRING_PRAGMA(data_alignment = n)
+#endif
+
+#ifndef __TUYA_BLE_PACKED
+#define __TUYA_BLE_PACKED __packed
+#endif
+
+#define TUYA_BLE_GET_SP() __get_SP()
+
+#elif defined ( __GNUC__ )
+
+#ifndef __TUYA_BLE_ASM
+#define __TUYA_BLE_ASM __asm
+#endif
+
+#ifndef __TUYA_BLE_INLINE
+#define __TUYA_BLE_INLINE inline
+#endif
+
+#ifndef __TUYA_BLE_WEAK
+#define __TUYA_BLE_WEAK __attribute__((weak))
+#endif
+
+#ifndef __TUYA_BLE_ALIGN
+#define __TUYA_BLE_ALIGN(n) __attribute__((aligned(n)))
+#endif
+
+#ifndef __TUYA_BLE_PACKED
+#define __TUYA_BLE_PACKED __attribute__((packed))
+#endif
+
+#define TUYA_BLE_GET_SP() tuya_ble_gcc_current_sp()
+
+static inline unsigned int tuya_ble_gcc_current_sp(void)
+{
+ register unsigned sp __asm("sp");
+ return sp;
+}
+#endif
+
+
+#define TUYA_BLE_EVT_BASE 0x00
+#define TUYA_BLE_CB_EVT_BASE 0x40
+
+#define H_ID_LEN 19
+#define TUYA_BLE_PRODUCT_ID_DEFAULT_LEN 8
+//#define PRODUCT_KEY_LEN TUYA_BLE_PRODUCT_ID_OR_KEY_LEN
+#define DEVICE_ID_LEN 16
+#define DEVICE_ID_LEN_MAX 20
+#define AUTH_KEY_LEN 32
+#define LOGIN_KEY_LEN 6
+#define ECC_SECRET_KEY_LEN 32
+#define DEVICE_VIRTUAL_ID_LEN 22
+#define SECRET_KEY_LEN 16
+#define PAIR_RANDOM_LEN 6
+#define MAC_LEN 6
+#define MAC_STRING_LEN 12
+#define BEACON_KEY_LEN 16
+
+#define TUYA_BLE_PRODUCT_ID_MAX_LEN 16
+
+#define TUYA_BLE_ADV_LOCAL_NAME_MAX_LEN 5
+
+/** @defgroup TUY_BLE_DEVICE_COMMUNICATION_ABILITY tuya ble device communication ability
+ * @{
+ */
+#define TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_BLE 0x0000
+#define TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_REGISTER_FROM_BLE 0x0001
+#define TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_MESH 0x0002
+#define TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_WIFI_24G 0x0004
+#define TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_WIFI_5G 0x0008
+#define TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_ZIGBEE 0x0010
+#define TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_NB 0x0020
+/** End of TUY_BLE_DEVICE_COMMUNICATION_ABILITY
+ * @}
+ */
+
+#define TUYA_BLE_LOG_LEVEL_ERROR 1U
+#define TUYA_BLE_LOG_LEVEL_WARNING 2U
+#define TUYA_BLE_LOG_LEVEL_INFO 3U
+#define TUYA_BLE_LOG_LEVEL_DEBUG 4U
+
+#define TUYA_APP_LOG_LEVEL_ERROR 1U
+#define TUYA_APP_LOG_LEVEL_WARNING 2U
+#define TUYA_APP_LOG_LEVEL_INFO 3U
+#define TUYA_APP_LOG_LEVEL_DEBUG 4U
+
+/** @defgroup TUYA_BLE_SECURE_CONNECTION_TYPE tuya ble secure connection type
+ * @{
+ */
+#define TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY 0x00
+
+#define TUYA_BLE_SECURE_CONNECTION_WITH_ECC 0x01
+
+#define TUYA_BLE_SECURE_CONNECTION_WTIH_PASSTHROUGH 0x02
+
+#define TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_DEVCIE_ID_20 0x03 //Discarded in agreements 4.0 and later
+
+#define TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION 0x04
+/** End of TUYA_BLE_SECURE_CONNECTION_TYPE
+ * @}
+ */
+
+// enum {
+// KEY_USER_DEAL_POST = 0,
+// KEY_USER_DEAL_POST_MSG,
+// KEY_USER_DEAL_POST_EVENT,
+// KEY_USER_DEAL_POST_2,
+// };
+
+typedef enum {
+ TUYA_BLE_SUCCESS = 0x00,
+ TUYA_BLE_ERR_INTERNAL,
+ TUYA_BLE_ERR_NOT_FOUND,
+ TUYA_BLE_ERR_NO_EVENT,
+ TUYA_BLE_ERR_NO_MEM,
+ TUYA_BLE_ERR_INVALID_ADDR, // Invalid pointer supplied
+ TUYA_BLE_ERR_INVALID_PARAM, // Invalid parameter(s) supplied.
+ TUYA_BLE_ERR_INVALID_STATE, // Invalid state to perform operation.
+ TUYA_BLE_ERR_INVALID_LENGTH,
+ TUYA_BLE_ERR_DATA_SIZE,
+ TUYA_BLE_ERR_TIMEOUT,
+ TUYA_BLE_ERR_BUSY,
+ TUYA_BLE_ERR_COMMON,
+ TUYA_BLE_ERR_RESOURCES,
+ TUYA_BLE_ERR_UNKNOWN, // other ble sdk errors
+} tuya_ble_status_t;
+
+
+typedef enum {
+ TUYA_BLE_PRODUCT_ID_TYPE_PID,
+ TUYA_BLE_PRODUCT_ID_TYPE_PRODUCT_KEY,
+} tuya_ble_product_id_type_t;
+
+
+typedef enum {
+ TUYA_BLE_ADDRESS_TYPE_PUBLIC, // public address
+ TUYA_BLE_ADDRESS_TYPE_RANDOM, // random address
+} tuya_ble_addr_type_t;
+
+typedef struct {
+ tuya_ble_addr_type_t addr_type;
+ uint8_t addr[6];
+} tuya_ble_gap_addr_t;
+
+typedef struct {
+ uint8_t use_ext_license_key; //If use the license key stored by the SDK,initialized to 0, Otherwise 1.
+ uint8_t device_id_len; //if ==20,Compressed into 16
+ uint8_t device_id[DEVICE_ID_LEN_MAX];
+ uint8_t auth_key[AUTH_KEY_LEN];
+ tuya_ble_gap_addr_t mac_addr;
+ uint8_t mac_addr_string[MAC_STRING_LEN];
+
+ tuya_ble_product_id_type_t p_type;
+ uint8_t product_id_len;
+ uint8_t product_id[TUYA_BLE_PRODUCT_ID_MAX_LEN];
+ uint8_t adv_local_name_len;
+ uint8_t adv_local_name[TUYA_BLE_ADV_LOCAL_NAME_MAX_LEN]; //Only supported when TUYA_BLE_PROTOCOL_VERSION_HIGN >= 4.
+ uint32_t firmware_version; //0x00010102 : v1.1.2
+ uint32_t hardware_version;
+
+ uint8_t device_vid[DEVICE_VIRTUAL_ID_LEN];
+ uint8_t login_key[LOGIN_KEY_LEN];
+ uint8_t beacon_key[BEACON_KEY_LEN];
+ uint8_t bound_flag;
+
+ uint8_t reserve_1;
+ uint8_t reserve_2;
+} tuya_ble_device_param_t;
+
+
+typedef struct {
+ uint16_t min_conn_interval; // Range: 0x0006 to 0x0C80, Time = N * 1.25 msec, Time Range: 7.5 msec to 4 seconds.
+ uint16_t max_conn_interval; // Range: 0x0006 to 0x0C80, Time = N * 1.25 msec, Time Range: 7.5 msec to 4 seconds.
+ uint16_t slave_latency; // Range: 0x0000 to 0x01F3
+ uint16_t conn_sup_timeout; // Range: 0x000A to 0x0C80, Time = N * 10 msec, Time Range: 100 msec to 32 seconds
+} tuya_ble_gap_conn_param_t;
+
+
+typedef enum {
+ TUYA_BLE_EVT_MTU_DATA_RECEIVE = TUYA_BLE_EVT_BASE,
+ TUYA_BLE_EVT_DEVICE_INFO_UPDATE,
+ TUYA_BLE_EVT_DP_DATA_REPORTED,
+ TUYA_BLE_EVT_DP_DATA_WITH_TIME_REPORTED,
+ TUYA_BLE_EVT_DP_DATA_WITH_TIME_STRING_REPORTED,
+ TUYA_BLE_EVT_DP_DATA_WITH_FLAG_REPORTED,
+ TUYA_BLE_EVT_DP_DATA_WITH_FLAG_AND_TIME_REPORTED,
+ TUYA_BLE_EVT_DP_DATA_WITH_FLAG_AND_TIME_STRING_REPORTED,
+ TUYA_BLE_EVT_DP_DATA_SEND,
+ TUYA_BLE_EVT_DP_DATA_WITH_TIME_SEND,
+ TUYA_BLE_EVT_DEVICE_UNBIND,
+ TUYA_BLE_EVT_FACTORY_RESET,
+ TUYA_BLE_EVT_OTA_RESPONSE,
+ TUYA_BLE_EVT_BULK_DATA_RESPONSE,
+ TUYA_BLE_EVT_DATA_PASSTHROUGH,
+ TUYA_BLE_EVT_PRODUCTION_TEST_RESPONSE,
+ TUYA_BLE_EVT_UART_CMD,
+ TUYA_BLE_EVT_BLE_CMD,
+ TUYA_BLE_EVT_NET_CONFIG_RESPONSE,
+ TUYA_BLE_EVT_CUSTOM,
+ TUYA_BLE_EVT_CONNECT_STATUS_UPDATE,
+ TUYA_BLE_EVT_UNBOUND_RESPONSE,
+ TUYA_BLE_EVT_ANOMALY_UNBOUND_RESPONSE,
+ TUYA_BLE_EVT_DEVICE_RESET_RESPONSE,
+ TUYA_BLE_EVT_TIME_REQ,
+ TUYA_BLE_EVT_EXTEND_TIME_REQ,
+ TUYA_BLE_EVT_GATT_SEND_DATA,
+ TUYA_BLE_EVT_CONNECTING_REQUEST,
+ TUYA_BLE_EVT_WEATHER_DATA_REQ,
+ TUYA_BLE_EVT_LINK_STATUS_UPDATE,
+} tuya_ble_evt_t;
+
+
+/*
+ * dp data report mode
+ *@note
+ * */
+typedef enum {
+ DP_SEND_FOR_CLOUD_PANEL = 0, // The mobile app uploads the received dp data to the cloud and also sends it to the panel for display.
+ DP_SEND_FOR_CLOUD, // The mobile app will only upload the received dp data to the cloud.
+ DP_SEND_FOR_PANEL, // The mobile app will only send the received dp data to the panel display.
+ DP_SEND_FOR_NONE, // Neither uploaded to the cloud nor sent to the panel display.
+} tuya_ble_dp_data_send_mode_t;
+
+
+typedef enum {
+ DP_SEND_TYPE_ACTIVE = 0, // The device actively sends dp data.
+ DP_SEND_TYPE_PASSIVE, // The device passively sends dp data. For example, in order to answer the dp query command of the mobile app. Currently only applicable to WIFI+BLE combo devices.
+} tuya_ble_dp_data_send_type_t;
+
+
+typedef enum {
+ DP_SEND_WITH_RESPONSE = 0, // Need a mobile app to answer.
+ DP_SEND_WITHOUT_RESPONSE, // No need for mobile app to answer.
+} tuya_ble_dp_data_send_ack_t;
+
+
+typedef struct {
+ uint8_t *p_data; // Used when the length of mtu data is greater than 20.
+ uint8_t data[20]; // Used when the length of mtu data is less than or equal to 20, In order to improve communication efficiency in BLE4.0 devices.
+ uint16_t len;
+} tuya_ble_mtu_data_receive_t;
+
+
+
+
+typedef enum {
+ DEVICE_INFO_TYPE_PID,
+ DEVICE_INFO_TYPE_PRODUCT_KEY,
+ DEVICE_INFO_TYPE_LOGIN_KEY,
+ DEVICE_INFO_TYPE_BOUND,
+ DEVICE_INFO_TYPE_BEACON_KEY,
+} tuya_ble_device_info_type_t;
+
+
+typedef struct {
+ tuya_ble_device_info_type_t type;
+ uint8_t len;
+ uint8_t data[32];
+} tuya_ble_device_info_data_t;
+
+
+
+typedef struct {
+ uint8_t *p_data;
+ uint16_t data_len;
+} tuya_ble_dp_data_reported_t;
+
+
+typedef struct {
+ uint32_t timestamp;
+ uint8_t *p_data;
+ uint16_t data_len;
+} tuya_ble_dp_data_with_time_reported_t;
+
+
+typedef struct {
+ uint8_t time_string[13 + 1];
+ uint8_t *p_data;
+ uint16_t data_len;
+} tuya_ble_dp_data_with_time_string_reported_t;
+
+typedef struct {
+ uint16_t sn;
+ tuya_ble_dp_data_send_mode_t mode;
+ uint8_t *p_data;
+ uint16_t data_len;
+} tuya_ble_dp_data_with_flag_reported_t;
+
+
+typedef struct {
+ uint16_t sn;
+ tuya_ble_dp_data_send_mode_t mode;
+ uint32_t timestamp;
+ uint8_t *p_data;
+ uint16_t data_len;
+} tuya_ble_dp_data_with_flag_and_time_reported_t;
+
+
+typedef struct {
+ uint16_t sn;
+ tuya_ble_dp_data_send_mode_t mode;
+ uint8_t time_string[13 + 1];
+ uint8_t *p_data;
+ uint16_t data_len;
+} tuya_ble_dp_data_with_flag_and_time_string_reported_t;
+
+
+typedef struct {
+ uint32_t sn;
+ tuya_ble_dp_data_send_type_t type;
+ tuya_ble_dp_data_send_mode_t mode;
+ tuya_ble_dp_data_send_ack_t ack;
+ uint8_t *p_data;
+ uint16_t data_len;
+} tuya_ble_dp_data_send_data_t;
+
+
+typedef enum {
+ DP_TIME_TYPE_MS_STRING = 0,
+ DP_TIME_TYPE_UNIX_TIMESTAMP,
+} tuya_ble_dp_data_send_time_type_t;
+
+
+typedef struct {
+ uint32_t sn;
+ tuya_ble_dp_data_send_type_t type;
+ tuya_ble_dp_data_send_mode_t mode;
+ tuya_ble_dp_data_send_ack_t ack;
+ tuya_ble_dp_data_send_time_type_t time_type;
+ uint8_t time_data[13 + 1];
+ uint8_t *p_data;
+ uint16_t data_len;
+} tuya_ble_dp_data_with_time_send_data_t;
+
+
+typedef struct {
+ uint8_t reserve;
+} tuya_ble_device_unbind_t;
+
+typedef struct {
+ uint8_t reserve;
+} tuya_ble_factory_reset_t;
+
+/*
+ * ota data
+ * */
+
+typedef enum {
+ TUYA_BLE_OTA_REQ,
+ TUYA_BLE_OTA_FILE_INFO,
+ TUYA_BLE_OTA_FILE_OFFSET_REQ,
+ TUYA_BLE_OTA_DATA,
+ TUYA_BLE_OTA_END,
+ TUYA_BLE_OTA_UNKONWN,
+} tuya_ble_ota_data_type_t;
+
+
+typedef struct {
+ tuya_ble_ota_data_type_t type;
+ uint16_t data_len;
+ uint8_t *p_data;
+} tuya_ble_ota_response_t;
+
+
+typedef enum {
+ TUYA_BLE_BULK_DATA_EVT_READ_INFO,
+ TUYA_BLE_BULK_DATA_EVT_READ_BLOCK,
+ TUYA_BLE_BULK_DATA_EVT_SEND_DATA,
+ TUYA_BLE_BULK_DATA_EVT_ERASE,
+ TUYA_BLE_BULK_DATA_EVT_UNKONWN,
+} tuya_ble_bulk_data_evt_type_t;
+
+
+typedef struct {
+ uint16_t block_number;
+} tuya_ble_bulk_data_evt_read_block_req_t;
+
+
+typedef struct {
+ uint16_t block_number;
+} tuya_ble_bulk_data_evt_send_data_req_t;
+
+
+typedef struct {
+ tuya_ble_bulk_data_evt_type_t evt;
+ uint8_t bulk_type;
+ union {
+ tuya_ble_bulk_data_evt_read_block_req_t block_data_req_data;
+ tuya_ble_bulk_data_evt_send_data_req_t send_data_req_data;
+ } params;
+} tuya_ble_bulk_data_request_t;
+
+
+
+typedef struct {
+ uint8_t status;
+ uint8_t flag;
+ uint32_t bulk_data_length;
+ uint32_t bulk_data_crc;
+ uint16_t block_data_length;
+} tuya_ble_bulk_data_evt_read_info_res_t;
+
+
+typedef struct {
+ uint8_t status;
+ uint16_t block_number;
+ uint16_t block_data_length;
+ uint16_t block_data_crc16;
+ uint16_t max_packet_data_length;
+} tuya_ble_bulk_data_evt_read_block_res_t;
+
+
+typedef struct {
+ uint16_t current_block_number;
+ uint16_t current_block_length;
+ uint8_t *p_current_block_data;
+} tuya_ble_bulk_data_evt_send_data_res_t;
+
+
+typedef struct {
+ uint8_t status;
+} tuya_ble_bulk_data_evt_erase_res_t;
+
+
+typedef struct {
+ tuya_ble_bulk_data_evt_type_t evt;
+ uint8_t bulk_type;
+ union {
+ tuya_ble_bulk_data_evt_read_info_res_t bulk_info_res_data;
+ tuya_ble_bulk_data_evt_read_block_res_t block_res_data;
+ tuya_ble_bulk_data_evt_send_data_res_t send_res_data;
+ tuya_ble_bulk_data_evt_erase_res_t erase_res_data;
+ } params;
+} tuya_ble_bulk_data_response_t;
+
+
+
+typedef struct {
+ uint16_t data_len;
+ uint8_t *p_data;
+} tuya_ble_passthrough_data_t;
+
+
+typedef struct {
+ uint8_t channel;
+ uint16_t data_len;
+ uint8_t *p_data;
+} tuya_ble_production_test_response_data_t;
+
+typedef struct {
+ uint32_t cmd;
+ uint16_t data_len;
+ uint8_t *p_data;
+} tuya_ble_uart_cmd_t;
+
+
+typedef struct {
+ uint32_t cmd;
+ uint16_t data_len;
+ uint8_t *p_data;
+} tuya_ble_ble_cmd_t;
+
+typedef struct {
+ int16_t result_code;
+} tuya_ble_net_config_response_t;
+
+
+typedef struct {
+ uint8_t cmd;
+} tuya_ble_connecting_request_data_t;
+
+
+typedef struct {
+ int32_t evt_id;
+ void *data;
+ void (*custom_event_handler)(int32_t evt_id, void *data);
+} tuya_ble_custom_evt_t;
+
+
+typedef enum {
+ TUYA_BLE_CONNECTED,
+ TUYA_BLE_DISCONNECTED,
+} tuya_ble_connect_status_change_t;
+
+
+typedef struct {
+ uint8_t result_code;
+} tuya_ble_ubound_response_t;
+
+
+typedef struct {
+ uint8_t result_code;
+} tuya_ble_anomaly_ubound_response_t;
+
+
+typedef struct {
+ uint8_t result_code;
+} tuya_ble_device_reset_response_t;
+
+typedef struct {
+ // 0-13-byte millisecond string[from cloud]
+ // 1 - normal time format[from cloud]
+ // 2 - normal time format[from app local]
+ uint8_t time_type;
+} tuya_ble_time_req_data_t;
+
+
+typedef struct {
+ uint8_t n_years_dst;
+} tuya_ble_extend_time_req_data_t;
+
+
+typedef struct {
+ uint8_t *p_data;
+ uint16_t data_len;
+} tuya_ble_weather_req_data_t;
+
+
+typedef struct {
+ uint8_t link_app_status;
+} tuya_ble_link_status_update_data_t;
+
+
+typedef struct {
+ tuya_ble_evt_t event;
+ void (*event_handler)(void *evt);
+} tuya_ble_evt_hdr_t;
+
+
+/*
+ * tuya ble sdk evt parameters union
+ * */
+typedef struct {
+ tuya_ble_evt_hdr_t hdr;
+ union {
+ tuya_ble_mtu_data_receive_t mtu_data;
+ tuya_ble_device_info_data_t device_info_data;
+ tuya_ble_dp_data_reported_t reported_data;
+ tuya_ble_dp_data_with_time_reported_t reported_with_time_data;
+ tuya_ble_dp_data_with_time_string_reported_t reported_with_time_string_data;
+ tuya_ble_dp_data_with_flag_reported_t flag_reported_data;
+ tuya_ble_dp_data_with_flag_and_time_reported_t flag_reported_with_time_data;
+ tuya_ble_dp_data_with_flag_and_time_string_reported_t flag_reported_with_time_string_data;
+ tuya_ble_dp_data_send_data_t dp_send_data;
+ tuya_ble_dp_data_with_time_send_data_t dp_with_time_send_data;
+ tuya_ble_device_unbind_t device_unbind_data;
+ tuya_ble_factory_reset_t factory_reset_data;
+ tuya_ble_ota_response_t ota_response_data;
+ tuya_ble_bulk_data_response_t bulk_res_data;
+ tuya_ble_passthrough_data_t passthrough_data;
+ tuya_ble_production_test_response_data_t prod_test_res_data;
+ tuya_ble_uart_cmd_t uart_cmd_data;
+ tuya_ble_ble_cmd_t ble_cmd_data;
+ tuya_ble_net_config_response_t net_config_response_data;
+ tuya_ble_custom_evt_t custom_evt;
+ tuya_ble_connect_status_change_t connect_change_evt;
+ tuya_ble_ubound_response_t ubound_res_data;
+ tuya_ble_anomaly_ubound_response_t anomaly_ubound_res_data;
+ tuya_ble_device_reset_response_t device_reset_res_data;
+ tuya_ble_time_req_data_t time_req_data;
+ tuya_ble_extend_time_req_data_t extend_time_req_data;
+ tuya_ble_connecting_request_data_t connecting_request_data;
+ tuya_ble_weather_req_data_t weather_req_data;
+ tuya_ble_link_status_update_data_t link_update_data;
+ };
+} tuya_ble_evt_param_t;
+
+
+
+
+/*
+ * tuya ble call back event type.
+ * */
+typedef enum {
+ TUYA_BLE_CB_EVT_CONNECTE_STATUS = TUYA_BLE_CB_EVT_BASE,
+ TUYA_BLE_CB_EVT_DP_WRITE, // old version
+ TUYA_BLE_CB_EVT_DP_QUERY,
+ TUYA_BLE_CB_EVT_DP_DATA_RECEIVED, // new version
+ TUYA_BLE_CB_EVT_OTA_DATA,
+ TUYA_BLE_CB_EVT_BULK_DATA,
+ TUYA_BLE_CB_EVT_NETWORK_INFO,
+ TUYA_BLE_CB_EVT_WIFI_SSID,
+ TUYA_BLE_CB_EVT_TIME_STAMP,
+ TUYA_BLE_CB_EVT_TIME_NORMAL,
+ TUYA_BLE_CB_EVT_APP_LOCAL_TIME_NORMAL,
+ TUYA_BLE_CB_EVT_TIME_STAMP_WITH_DST,
+ TUYA_BLE_CB_EVT_DATA_PASSTHROUGH,
+ TUYA_BLE_CB_EVT_DP_DATA_REPORT_RESPONSE,
+ TUYA_BLE_CB_EVT_DP_DATA_WTTH_TIME_REPORT_RESPONSE,
+ TUYA_BLE_CB_EVT_DP_DATA_WITH_FLAG_REPORT_RESPONSE,
+ TUYA_BLE_CB_EVT_DP_DATA_WITH_FLAG_AND_TIME_REPORT_RESPONSE,
+ TUYA_BLE_CB_EVT_DP_DATA_SEND_RESPONSE, // new version
+ TUYA_BLE_CB_EVT_DP_DATA_WITH_TIME_SEND_RESPONSE, // new version
+ TUYA_BLE_CB_EVT_UNBOUND,
+ TUYA_BLE_CB_EVT_ANOMALY_UNBOUND,
+ TUYA_BLE_CB_EVT_DEVICE_RESET,
+ TUYA_BLE_CB_EVT_UPDATE_LOGIN_KEY_VID,
+ TUYA_BLE_CB_EVT_UNBIND_RESET_RESPONSE, // Notify the application of the result of the local reset
+ TUYA_BLE_CB_EVT_WEATHER_DATA_REQ_RESPONSE, // received request weather data app response
+ TUYA_BLE_CB_EVT_WEATHER_DATA_RECEIVED, // received app sync weather data
+} tuya_ble_cb_evt_t;
+
+/*
+ * current connect status
+ *@note
+ * */
+typedef enum {
+ UNBONDING_UNCONN = 0,
+ UNBONDING_CONN,
+ BONDING_UNCONN,
+ BONDING_CONN,
+ BONDING_UNAUTH_CONN,
+ UNBONDING_UNAUTH_CONN,
+ UNKNOW_STATUS
+} tuya_ble_connect_status_t;
+
+/*
+ * current link status
+ *@note
+ * */
+typedef enum {
+ LINK_DISCONNECTED = 0,
+ LINK_CONNECTED,
+ LINK_ENCRYPTED,
+ LINK_UNKNOW_STATUS
+} tuya_ble_link_status_t;
+
+/*
+ * current connect status
+ *@note
+ * */
+typedef enum {
+ TUYA_BLE_AUTH_STATUS_PHASE_NONE = 0,
+ TUYA_BLE_AUTH_STATUS_PHASE_1,
+ TUYA_BLE_AUTH_STATUS_PHASE_2,
+ TUYA_BLE_AUTH_STATUS_PHASE_3,
+} tuya_ble_auth_status_t;
+
+/*
+ * dp data buffer: (Dp_id,Dp_type,Dp_len,Dp_data),(Dp_id,Dp_type,Dp_len,Dp_data),....
+ * */
+typedef struct {
+ uint8_t *p_data;
+ uint16_t data_len;
+} tuya_ble_dp_write_data_t;
+
+/*
+ * query dp point data,if data_len is 0,means query all dp point data,otherwise query the dp point in p_data buffer.
+ * */
+typedef struct {
+ uint8_t *p_data;
+ uint16_t data_len;
+} tuya_ble_dp_query_data_t;
+
+/*
+* dp data buffer(Dp_len:2): (Dp_id,Dp_type,Dp_len,Dp_data),(Dp_id,Dp_type,Dp_len,Dp_data),....
+ * */
+typedef struct {
+ uint32_t sn;
+ uint8_t *p_data;
+ uint16_t data_len;
+} tuya_ble_dp_data_received_data_t;
+
+
+typedef struct {
+ tuya_ble_ota_data_type_t type;
+ uint16_t data_len;
+ uint8_t *p_data;
+} tuya_ble_ota_data_t;
+
+
+
+/*
+ * network data,unformatted json data,for example " {"wifi_ssid":"tuya","password":"12345678","token":"xxxxxxxxxx"} "
+ * */
+typedef struct {
+ uint16_t data_len;//include '\0'
+ uint8_t *p_data;
+} tuya_ble_network_data_t;
+
+/*
+ * wifi ssid data,unformatted json data,for example " {"wifi_ssid":"tuya","password":"12345678"} "
+ * */
+typedef struct {
+ uint16_t data_len;//include '\0'
+ uint8_t *p_data;
+} tuya_ble_wifi_ssid_data_t;
+
+
+/*
+ * uninx timestamp
+ * */
+typedef struct {
+ uint8_t timestamp_string[14];
+ int16_t time_zone; //actual time zone Multiply by 100.
+} tuya_ble_timestamp_data_t;
+
+
+/*
+ * normal time formatted
+ * */
+typedef struct {
+ uint16_t nYear;
+ uint8_t nMonth;
+ uint8_t nDay;
+ uint8_t nHour;
+ uint8_t nMin;
+ uint8_t nSec;
+ uint8_t DayIndex; /* 0 = Sunday */
+ int16_t time_zone; //actual time zone Multiply by 100.
+} tuya_ble_time_noraml_data_t;
+
+/*
+ * normal time formatted
+ * */
+typedef struct {
+ uint32_t timestamp;
+ int16_t time_zone; /**< actual time zone Multiply by 100. */
+ uint8_t n_years_dst; /**< how many years of daylight saving time. */
+ uint8_t *p_data; /**< the point of dst data. */
+ uint16_t data_len; /**< dst data length. */
+} tuya_ble_timestamp_with_dst_data_t;
+
+/*
+ *
+ * */
+typedef struct {
+ uint8_t status;
+} tuya_ble_dp_data_report_response_t;
+
+/*
+ *
+ * */
+typedef struct {
+ uint8_t status;
+} tuya_ble_dp_data_with_time_report_response_t;
+
+/*
+ *
+ * */
+typedef struct {
+ uint16_t sn;
+ tuya_ble_dp_data_send_mode_t mode;
+ uint8_t status;
+} tuya_ble_dp_data_with_flag_report_response_t;
+
+/*
+ *
+ * */
+typedef struct {
+ uint16_t sn;
+ tuya_ble_dp_data_send_mode_t mode;
+ uint8_t status;
+} tuya_ble_dp_data_with_flag_and_time_report_response_t;
+
+/*
+ *
+ * */
+typedef struct {
+ uint32_t sn;
+ tuya_ble_dp_data_send_type_t type;
+ tuya_ble_dp_data_send_mode_t mode;
+ tuya_ble_dp_data_send_ack_t ack;
+ uint8_t status; // 0 - succeed, 1- failed.
+} tuya_ble_dp_data_send_response_data_t;
+
+/*
+ *
+ * */
+typedef struct {
+ uint32_t sn;
+ tuya_ble_dp_data_send_type_t type;
+ tuya_ble_dp_data_send_mode_t mode;
+ tuya_ble_dp_data_send_ack_t ack;
+ uint8_t status; // 0 - succeed, 1- failed.
+} tuya_ble_dp_data_with_time_send_response_data_t;
+
+
+/*
+ *
+ * */
+typedef struct {
+ uint8_t data;
+} tuya_ble_unbound_data_t;
+
+/*
+ *
+ * */
+typedef struct {
+ uint8_t data;
+} tuya_ble_anomaly_unbound_data_t;
+
+/*
+ *
+ * */
+typedef struct {
+ uint8_t data;
+} tuya_ble_device_reset_data_t;
+
+/*
+ *
+ * */
+typedef struct {
+ uint8_t status;
+} tuya_ble_weather_data_req_response_t;
+
+
+/**
+ * weather data (key_len,key,vaule_type,value_len,value),(key_len,key,vaule_type,value_len,value),....
+ *
+ */
+typedef struct {
+ uint16_t object_count; /**< weather data object counts. */
+ uint8_t location; /**< location. */
+ uint8_t *p_data; /**< weather data. */
+ uint16_t data_len; /**< weather data length. */
+} tuya_ble_weather_data_received_data_t;
+
+
+/*
+ *
+ * */
+typedef struct {
+ uint8_t login_key_len;
+ uint8_t vid_len;
+ uint8_t beacon_key_len;
+ uint8_t login_key[LOGIN_KEY_LEN];
+ uint8_t vid[DEVICE_VIRTUAL_ID_LEN];
+ uint8_t beacon_key[BEACON_KEY_LEN];
+} tuya_ble_login_key_vid_data_t;
+
+typedef enum {
+ RESET_TYPE_UNBIND,
+ RESET_TYPE_FACTORY_RESET,
+} tuya_ble_reset_type_t;
+
+/*
+ *
+ * */
+typedef struct {
+ tuya_ble_reset_type_t type;
+ uint8_t status; //0-succeed,1-failed.
+} tuya_ble_unbind_reset_response_data_t;
+
+/*
+ * tuya ble sdk callback parameters union
+ * */
+typedef struct {
+ tuya_ble_cb_evt_t evt;
+ union {
+ tuya_ble_connect_status_t connect_status;
+ tuya_ble_dp_write_data_t dp_write_data;
+ tuya_ble_dp_query_data_t dp_query_data;
+ tuya_ble_dp_data_received_data_t dp_received_data;
+ tuya_ble_ota_data_t ota_data;
+ tuya_ble_bulk_data_request_t bulk_req_data;
+ tuya_ble_network_data_t network_data;
+ tuya_ble_wifi_ssid_data_t wifi_info_data;
+ tuya_ble_timestamp_data_t timestamp_data;
+ tuya_ble_time_noraml_data_t time_normal_data;
+ tuya_ble_timestamp_with_dst_data_t timestamp_with_dst_data;
+ tuya_ble_passthrough_data_t ble_passthrough_data;
+ tuya_ble_dp_data_report_response_t dp_response_data;
+ tuya_ble_dp_data_with_time_report_response_t dp_with_time_response_data;
+ tuya_ble_dp_data_with_flag_report_response_t dp_with_flag_response_data;
+ tuya_ble_dp_data_with_flag_and_time_report_response_t dp_with_flag_and_time_response_data;
+ tuya_ble_dp_data_send_response_data_t dp_send_response_data;
+ tuya_ble_dp_data_with_time_send_response_data_t dp_with_time_send_response_data;
+ tuya_ble_unbound_data_t unbound_data;
+ tuya_ble_anomaly_unbound_data_t anomaly_unbound_data;
+ tuya_ble_device_reset_data_t device_reset_data;
+ tuya_ble_login_key_vid_data_t device_login_key_vid_data;
+ tuya_ble_unbind_reset_response_data_t reset_response_data;
+ tuya_ble_weather_data_req_response_t weather_req_response_data;
+ tuya_ble_weather_data_received_data_t weather_received_data;
+ };
+} tuya_ble_cb_evt_param_t;
+
+
+/* TIMER related */
+typedef void *tuya_ble_timer_t;
+
+typedef void (*tuya_ble_timer_handler_t)(void *);
+
+
+typedef enum {
+ TUYA_BLE_TIMER_SINGLE_SHOT,
+ TUYA_BLE_TIMER_REPEATED,
+} tuya_ble_timer_mode;
+
+
+
+typedef void (*tuya_ble_callback_t)(tuya_ble_cb_evt_param_t *param);
+
+
+typedef struct {
+ uint32_t crc;
+ uint32_t settings_version;
+ uint8_t h_id[H_ID_LEN];
+ uint8_t device_id[DEVICE_ID_LEN];
+ uint8_t mac[MAC_LEN];
+ uint8_t auth_key[AUTH_KEY_LEN];
+ uint8_t mac_string[MAC_LEN * 2];
+ uint8_t pid_type;
+ uint8_t pid_len;
+ uint8_t factory_pid[TUYA_BLE_PRODUCT_ID_MAX_LEN];
+ uint8_t res[110];
+} tuya_ble_auth_settings_t;
+
+
+typedef struct {
+ uint32_t crc;
+ uint32_t settings_version;
+ tuya_ble_product_id_type_t pid_type;
+ uint8_t pid_len;
+ uint8_t common_pid[TUYA_BLE_PRODUCT_ID_MAX_LEN];
+ uint8_t login_key[LOGIN_KEY_LEN];
+ uint8_t ecc_secret_key[ECC_SECRET_KEY_LEN];
+ uint8_t device_virtual_id[DEVICE_VIRTUAL_ID_LEN];
+ uint8_t user_rand[PAIR_RANDOM_LEN];
+ uint8_t bound_flag;
+ uint8_t factory_test_flag;
+ uint8_t server_cert_pub_key[64];
+ uint8_t beacon_key[BEACON_KEY_LEN];
+ uint8_t res[47];
+} tuya_ble_sys_settings_t;
+
+
+typedef struct {
+ tuya_ble_auth_settings_t auth_settings;
+ tuya_ble_sys_settings_t sys_settings;
+ tuya_ble_product_id_type_t pid_type;
+ uint8_t pid_len;
+ uint8_t pid[TUYA_BLE_PRODUCT_ID_MAX_LEN];
+ uint8_t adv_local_name_len;
+ uint8_t adv_local_name[TUYA_BLE_ADV_LOCAL_NAME_MAX_LEN];
+} tuya_ble_parameters_settings_t;
+
+
+typedef struct {
+ tuya_ble_product_id_type_t pid_type;
+ uint8_t pid_len;
+ uint8_t pid[TUYA_BLE_PRODUCT_ID_MAX_LEN];
+ uint8_t h_id[H_ID_LEN];
+ uint8_t device_id[DEVICE_ID_LEN];
+ uint8_t mac[MAC_LEN];
+ uint8_t auth_key[AUTH_KEY_LEN];
+} tuya_ble_factory_id_data_t;
+
+
+typedef enum {
+ PRIVATE_DATA_ECC_KEY = 1,
+
+ PRIVATE_DATA_DEV_CERT = 10,
+ PRIVATE_DATA_TUYA_AUTH_TOKEN,
+} tuya_ble_private_data_type;
+
+
+/** @defgroup TUYA_BLE_PROD_OEM_TYPE tuya ble prod oem type
+ * @{
+ */
+#define TUYA_BLE_PROD_OEM_TYPE_NONE ( 0 )
+#define TUYA_BLE_PROD_OEM_TYPE_0_5 ( 1 )
+#define TUYA_BLE_PROD_OEM_TYPE_1_0 ( 2 )
+#define TUYA_BLE_PROD_OEM_TYPE_1_5 ( 3 )
+#define TUYA_BLE_PROD_OEM_TYPE_2_0 ( 4 )
+/** End of TUYA_BLE_PROD_OEM_TYPE
+ * @}
+ */
+
+
+#endif
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_unix_time.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_unix_time.h
new file mode 100644
index 0000000..d183e5d
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_unix_time.h
@@ -0,0 +1,51 @@
+/**
+ * \file tuya_ble_unix_time.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#ifndef TUYA_BLE_UNIX_TIME_H_
+#define TUYA_BLE_UNIX_TIME_H_
+
+#include "tuya_ble_stdlib.h"
+
+/* time struct */
+typedef struct {
+ uint16_t nYear;
+ uint8_t nMonth;
+ uint8_t nDay;
+ uint8_t nHour;
+ uint8_t nMin;
+ uint8_t nSec;
+ uint8_t DayIndex; /* 0 = Sunday */
+} tuya_ble_time_struct_data_t;
+
+
+void tuya_ble_utc_sec_2_mytime(uint32_t utc_sec, tuya_ble_time_struct_data_t *result, bool daylightSaving);
+
+void tuya_ble_utc_sec_2_mytime_string(uint32_t utc_sec, bool daylightSaving, char *s);
+
+uint32_t tuya_ble_mytime_2_utc_sec(tuya_ble_time_struct_data_t *currTime, bool daylightSaving);
+
+#endif
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_utils.h b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_utils.h
new file mode 100644
index 0000000..db4abfc
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/include/tuya_ble_utils.h
@@ -0,0 +1,123 @@
+/**
+ * \file tuya_ble_utils.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#ifndef TUYA_BLE_UTILS_H_
+#define TUYA_BLE_UTILS_H_
+
+#include "tuya_ble_stdlib.h"
+
+
+#define BSWAP_16(x) \
+ (uint16_t)((((uint16_t)(x) & 0x00ff) << 8) | \
+ (((uint16_t)(x) & 0xff00) >> 8) )
+
+
+#define BSWAP_32(x) \
+ (uint32_t)((((uint32_t)(x) & 0xff000000) >> 24) | \
+ (((uint32_t)(x) & 0x00ff0000) >> 8) | \
+ (((uint32_t)(x) & 0x0000ff00) << 8) | \
+ (((uint32_t)(x) & 0x000000ff) << 24))
+
+int32_t tuya_ble_rand_number(int32_t min, int32_t max);
+
+int32_t tuya_ble_count_bits(uint32_t data);
+
+void tuya_ble_inverted_array(uint8_t *array, uint16_t length);
+
+bool tuya_ble_buffer_value_is_all_x(uint8_t *buffer, uint16_t len, uint8_t value);
+
+uint8_t tuya_ble_check_sum(uint8_t *pbuf, uint16_t len);
+
+uint8_t tuya_ble_check_num(uint8_t *buf, uint8_t num);
+
+void tuya_ble_hextoascii(uint8_t *hexbuf, uint8_t len, uint8_t *ascbuf);
+
+void tuya_ble_hextostr(uint8_t *hexbuf, uint8_t len, uint8_t *strbuf);
+
+void tuya_ble_asciitohex(uint8_t *ascbuf, uint8_t *hexbuf);
+
+uint8_t tuya_ble_char_2_ascii(uint8_t data);
+
+void tuya_ble_str_to_hex(uint8_t *str_buf, uint8_t str_len, uint8_t *hex_buf);
+
+bool tuya_ble_is_word_aligned_tuya(void const *p);
+
+uint16_t tuya_ble_crc16_compute(uint8_t *p_data, uint16_t size, uint16_t *p_crc);
+
+uint32_t tuya_ble_crc32_compute(uint8_t const *p_data, uint32_t size, uint32_t const *p_crc);
+
+void tuya_ble_device_id_20_to_16(uint8_t *in, uint8_t *out);
+
+void tuya_ble_device_id_16_to_20(uint8_t *in, uint8_t *out);
+
+char tuya_ble_hexstr2hex(uint8_t *hexstr, int32_t len, uint8_t *hex);
+
+/**
+ * @brief Function for search character/symbol index from input string
+ *
+ * @param
+ * [in]data : pointer to input data
+ * [in]data : Number of bytes of data
+ * [in]symbol : Search symbol or character, Such as ':' or ','
+ * [out]index[] : Array of indexs
+ *
+ * @return The number of matched character/symbol
+ *
+ * @note
+ *
+ * */
+int32_t tuya_ble_search_symbol_index(char *data, uint16_t len, char symbol, uint8_t index[]);
+
+int32_t tuya_ble_ascii_to_int(char *ascii, uint16_t len);
+
+/**
+ * @brief Function for pem format ecc key to hex foramt
+ *
+ * @param
+ * [in]pem : pointer to pem data
+ * [out]key : pointer to output data, hex format ecc key
+ * [out]key_len: Number of bytes of key.
+ *
+ * @return 0 - failed, 1 - success
+ *
+ * @note developer could use tuya_ble_ecc_key_pem2hex_example() function to test
+ *
+ * */
+int32_t tuya_ble_ecc_key_pem2hex(const char *pem, uint8_t *key, uint16_t *key_len);
+
+/**
+ * @brief Function for extract r+s from der from ecdsa sign
+ *
+ * @param
+ * [in]der : pointer to der data
+ * [out]raw_rs : pointer to output data, the raw data[r+s] of der
+ *
+ * @return 0 - failed, 1 - success
+ *
+ * @note
+ *
+ * */
+int32_t tuya_ble_ecc_sign_secp256r1_extract_raw_from_der(const char *der, uint8_t *raw_rs);
+
+#endif /* TUYA_UTILS_H_ */
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/lib/libtuya_lib.a b/apps/common/third_party_profile/tuya_protocol/sdk/lib/libtuya_lib.a
new file mode 100644
index 0000000..44f8ff2
Binary files /dev/null and b/apps/common/third_party_profile/tuya_protocol/sdk/lib/libtuya_lib.a differ
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/lib/tuya_ble_event_handler.h b/apps/common/third_party_profile/tuya_protocol/sdk/lib/tuya_ble_event_handler.h
new file mode 100644
index 0000000..84f0bdc
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/lib/tuya_ble_event_handler.h
@@ -0,0 +1,99 @@
+/**
+ * \file tuya_ble_event_handler.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+
+#ifndef TUYA_BLE_EVENT_HANDLER_H__
+#define TUYA_BLE_EVENT_HANDLER_H__
+
+#include "tuya_ble_type.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+void tuya_ble_handle_device_info_update_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_dp_data_reported_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_dp_data_with_time_reported_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_dp_data_with_time_string_reported_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_dp_data_with_flag_reported_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_dp_data_with_flag_and_time_reported_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_dp_data_with_flag_and_time_string_reported_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_dp_data_send_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_dp_data_with_time_send_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_device_unbind_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_factory_reset_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_ota_response_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_bulk_data_evt(tuya_ble_evt_param_t *p_evt);
+
+void tuya_ble_handle_data_passthrough_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_data_prod_test_response_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_uart_cmd_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_ble_cmd_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_net_config_response_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_time_request_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_extend_time_request_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_unbound_response_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_anomaly_unbound_response_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_device_reset_response_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_connect_change_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_ble_data_evt(uint8_t *buf, uint16_t len);
+
+void tuya_ble_handle_connecting_request_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_link_update_evt(tuya_ble_evt_param_t *evt);
+
+void tuya_ble_handle_weather_data_request_evt(tuya_ble_evt_param_t *evt);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/lib/tuya_ble_secure.h b/apps/common/third_party_profile/tuya_protocol/sdk/lib/tuya_ble_secure.h
new file mode 100644
index 0000000..eb9f7f1
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/lib/tuya_ble_secure.h
@@ -0,0 +1,74 @@
+/**
+ * \file tuya_ble_secure.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#ifndef TUYA_BLE_SECURE_H_
+#define TUYA_BLE_SECURE_H_
+
+#include "tuya_ble_type.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+enum {
+ ENCRYPTION_MODE_NONE,
+ ENCRYPTION_MODE_KEY_1,
+ ENCRYPTION_MODE_KEY_2,
+ ENCRYPTION_MODE_KEY_3,
+ ENCRYPTION_MODE_KEY_4,
+ ENCRYPTION_MODE_SESSION_KEY,
+ ENCRYPTION_MODE_ECDH_KEY,
+ ENCRYPTION_MODE_FTM_KEY,
+ ENCRYPTION_MODE_MAX,
+};
+
+bool tuya_ble_register_key_generate(uint8_t *output, tuya_ble_parameters_settings_t *current_para);
+
+uint8_t tuya_ble_encryption(uint16_t protocol_version, uint8_t encryption_mode, uint8_t *iv, uint8_t *in_buf, uint32_t in_len, uint32_t *out_len, uint8_t *out_buf, tuya_ble_parameters_settings_t *current_para_data, uint8_t *dev_rand);
+
+uint8_t tuya_ble_encrypt_old_with_key(uint8_t *key, uint8_t *in_buf, uint8_t in_len, uint8_t *out_buf);
+
+bool tuya_ble_device_id_encrypt(uint8_t *key_in, uint16_t key_len, uint8_t *input, uint16_t input_len, uint8_t *output);
+
+bool tuya_ble_device_id_decrypt(uint8_t *key_in, uint16_t key_len, uint8_t *input, uint16_t input_len, uint8_t *output);
+
+bool tuya_ble_device_id_encrypt_v4(uint8_t *key_in, uint16_t key_len, uint8_t *input, uint16_t input_len, uint8_t *output);
+
+uint8_t tuya_ble_decryption(uint16_t protocol_version, uint8_t const *in_buf, uint32_t in_len, uint32_t *out_len, uint8_t *out_buf, tuya_ble_parameters_settings_t *current_para_data, uint8_t *dev_rand);
+
+bool tuya_ble_server_cert_data_verify(const uint8_t *p_data, uint16_t data_len, const uint8_t *p_sig);
+
+bool tuya_ble_sig_data_verify(const uint8_t *p_pk, const uint8_t *p_data, uint16_t data_len, const uint8_t *p_sig);
+
+void tuya_ble_event_process(tuya_ble_evt_param_t *tuya_ble_evt);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // TUYA_BLE_SECURE_H_
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_api.c b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_api.c
new file mode 100644
index 0000000..a69fa16
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_api.c
@@ -0,0 +1,1570 @@
+/**
+ * \file tuya_ble_api.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_api.h"
+#include "tuya_ble_port.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_main.h"
+#include "tuya_ble_mem.h"
+#include "tuya_ble_log.h"
+#include "tuya_ble_data_handler.h"
+#include "tuya_ble_internal_config.h"
+#include "tuya_ble_mutli_tsf_protocol.h"
+#include "tuya_ble_storage.h"
+#include "tuya_ble_utils.h"
+#include "tuya_ble_sdk_version.h"
+#include "tuya_ble_gatt_send_queue.h"
+#include "tuya_ble_event.h"
+#include "tuya_ble_app_production_test.h"
+
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE == TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION)
+#include "cJSON.h"
+#endif
+
+static uint8_t m_callback_numbers = 0;
+
+#if TUYA_BLE_USE_OS
+extern uint32_t m_cb_queue_table[TUYA_BLE_MAX_CALLBACKS];
+
+/**
+ * @brief Function for registe queue to receive call back evt when use os
+ *
+ * @note
+ *
+ * */
+tuya_ble_status_t tuya_ble_callback_queue_register(void *cb_queue)
+{
+ tuya_ble_status_t ret;
+
+ tuya_ble_device_enter_critical();
+ if (m_callback_numbers == TUYA_BLE_MAX_CALLBACKS) {
+ ret = TUYA_BLE_ERR_RESOURCES;
+ } else {
+ m_cb_queue_table[m_callback_numbers] = (uint32_t)cb_queue;
+ m_callback_numbers++;
+
+ ret = TUYA_BLE_SUCCESS;
+ }
+ tuya_ble_device_exit_critical();
+
+ return ret;
+}
+
+
+/**
+ * @brief Function for response the event.
+ *
+ * @note if use os,must be sure to call this function after process one event in queue.
+ *
+ * */
+tuya_ble_status_t tuya_ble_event_response(tuya_ble_cb_evt_param_t *param)
+{
+ return tuya_ble_inter_event_response(param);
+}
+
+#else
+
+
+extern tuya_ble_callback_t m_cb_table[TUYA_BLE_MAX_CALLBACKS];
+/**
+ * @brief Function for registe call back functions.
+ *
+ * @note appliction should receive the message from the call back registed by this function.
+ *
+ * */
+tuya_ble_status_t tuya_ble_callback_queue_register(tuya_ble_callback_t cb)
+{
+ tuya_ble_status_t ret;
+
+ tuya_ble_device_enter_critical();
+ if (m_callback_numbers == TUYA_BLE_MAX_CALLBACKS) {
+ ret = TUYA_BLE_ERR_RESOURCES;
+ } else {
+ m_cb_table[m_callback_numbers] = cb;
+ m_callback_numbers++;
+
+ ret = TUYA_BLE_SUCCESS;
+ }
+ tuya_ble_device_exit_critical();
+
+ return ret;
+}
+
+/**
+ * @brief Function for get scheduler queue size.
+ *
+ * @note If it returns 0, it means that the queue has not been initialized.
+ *
+ * */
+uint16_t tuya_ble_scheduler_queue_size_get(void)
+{
+ return tuya_ble_sched_queue_size_get();
+}
+
+/**
+ * @brief Function for get queue free space.
+ *
+ * @note
+ *
+ * */
+uint16_t tuya_ble_scheduler_queue_space_get(void)
+{
+ return tuya_ble_sched_queue_space_get();
+}
+
+/**
+ * @brief Function for get the number of current events in the queue.
+ *
+ * @note
+ *
+ * */
+uint16_t tuya_ble_scheduler_queue_events_get(void)
+{
+ return tuya_ble_sched_queue_events_get();
+}
+
+#endif
+
+/**
+ * @brief Function for check if sleep is allowed.
+ *
+ * @note If it returns true, it means that sleep is allowed.
+ *
+ * */
+bool tuya_ble_sleep_allowed_check(void)
+{
+#if TUYA_BLE_USE_OS
+ if (tuya_ble_internal_production_test_with_ble_flag_get() == 0)
+#else
+ if ((tuya_ble_scheduler_queue_events_get() == 0) && (tuya_ble_internal_production_test_with_ble_flag_get() == 0))
+#endif
+ {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+tuya_ble_status_t tuya_ble_gatt_receive_data(uint8_t *p_data, uint16_t len)
+{
+ tuya_ble_evt_param_t event;
+
+ memset(&event, 0, sizeof(tuya_ble_evt_param_t));
+
+ event.hdr.event = TUYA_BLE_EVT_MTU_DATA_RECEIVE;
+
+ if (len > TUYA_BLE_DATA_MTU_MAX) {
+ event.mtu_data.len = TUYA_BLE_DATA_MTU_MAX;
+ } else {
+ event.mtu_data.len = len;
+ }
+ if (event.mtu_data.len <= 20) {
+ memcpy(event.mtu_data.data, p_data, event.mtu_data.len);
+ } else {
+ event.mtu_data.p_data = (uint8_t *)tuya_ble_malloc(event.mtu_data.len);
+ if (event.mtu_data.p_data == NULL) {
+ printf("tuya_ble_gatt_receive_data error 1");
+ return TUYA_BLE_ERR_NO_MEM;
+ }
+ memcpy(event.mtu_data.p_data, p_data, event.mtu_data.len);
+ }
+
+ if (tuya_ble_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_event_send ble data error,data len = %d ", event.mtu_data.len);
+ if (event.mtu_data.p_data) {
+ printf("tuya_ble_gatt_receive_data error 2");
+ tuya_ble_free(event.mtu_data.p_data);
+ }
+ return TUYA_BLE_ERR_INTERNAL;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+
+/*
+ *@brief Function for receive uart data.
+ *@param
+ *
+ *@note
+ *
+ * */
+
+typedef enum {
+ TUYA_BLE_UART_REV_STATE_FOUND_NULL,
+ TUYA_BLE_UART_REV_STATE_FOUND_HEAD,
+ TUYA_BLE_UART_REV_STATE_FOUND_CMD,
+ TUYA_BLE_UART_REV_STATE_FOUND_LEN_H,
+ TUYA_BLE_UART_REV_STATE_FOUND_LEN_L,
+ TUYA_BLE_UART_REV_STATE_FOUND_DATA,
+ TUYA_BLE_UART_REV_STATE_UNKOWN,
+} tuya_ble_uart_rev_state_type_t;
+
+#define UART_RX_BUFFER_MAX 300
+#define UART_RX_DATA_LEN_MAX 249
+static volatile tuya_ble_uart_rev_state_type_t current_uart_rev_state_type = TUYA_BLE_UART_REV_STATE_FOUND_NULL;
+static uint8_t UART_RX_Buffer[UART_RX_BUFFER_MAX];
+static uint8_t UART_RX_Buffer_temp[3] = {0};
+static uint16_t uart_data_len = 0;
+static volatile uint16_t UART_RX_Count = 0;
+
+
+static bool tuya_ble_common_uart_data_unpack(uint8_t data)
+{
+ bool ret = false;
+
+ UART_RX_Buffer_temp[0] = UART_RX_Buffer_temp[1];
+ UART_RX_Buffer_temp[1] = UART_RX_Buffer_temp[2];
+ UART_RX_Buffer_temp[2] = data;
+
+ if (((UART_RX_Buffer_temp[0] == 0x55) || (UART_RX_Buffer_temp[0] == 0x66)) && (UART_RX_Buffer_temp[1] == 0xAA) && ((UART_RX_Buffer_temp[2] == 0x00) || (UART_RX_Buffer_temp[2] == 0x01))) {
+ memset(UART_RX_Buffer, 0, sizeof(UART_RX_Buffer));
+ memcpy(UART_RX_Buffer, UART_RX_Buffer_temp, 3);
+ memset(UART_RX_Buffer_temp, 0, 3);
+ UART_RX_Count = 3;
+ current_uart_rev_state_type = TUYA_BLE_UART_REV_STATE_FOUND_HEAD;
+ uart_data_len = 0;
+ return ret;
+ }
+
+ switch (current_uart_rev_state_type) {
+ case TUYA_BLE_UART_REV_STATE_FOUND_NULL:
+ break;
+ case TUYA_BLE_UART_REV_STATE_FOUND_HEAD:
+ UART_RX_Buffer[UART_RX_Count++] = data;
+ current_uart_rev_state_type = TUYA_BLE_UART_REV_STATE_FOUND_CMD;
+ break;
+ case TUYA_BLE_UART_REV_STATE_FOUND_CMD:
+ UART_RX_Buffer[UART_RX_Count++] = data;
+ current_uart_rev_state_type = TUYA_BLE_UART_REV_STATE_FOUND_LEN_H;
+ break;
+ case TUYA_BLE_UART_REV_STATE_FOUND_LEN_H:
+ UART_RX_Buffer[UART_RX_Count++] = data;
+ uart_data_len = (UART_RX_Buffer[UART_RX_Count - 2] << 8) | UART_RX_Buffer[UART_RX_Count - 1];
+ if (uart_data_len > UART_RX_DATA_LEN_MAX) {
+ memset(UART_RX_Buffer_temp, 0, 3);
+ memset(UART_RX_Buffer, 0, sizeof(UART_RX_Buffer));
+ UART_RX_Count = 0;
+ current_uart_rev_state_type = TUYA_BLE_UART_REV_STATE_FOUND_NULL;
+ uart_data_len = 0;
+ } else if (uart_data_len > 0) {
+ current_uart_rev_state_type = TUYA_BLE_UART_REV_STATE_FOUND_LEN_L;
+ } else {
+ current_uart_rev_state_type = TUYA_BLE_UART_REV_STATE_FOUND_DATA;
+ }
+ break;
+ case TUYA_BLE_UART_REV_STATE_FOUND_LEN_L:
+ UART_RX_Buffer[UART_RX_Count++] = data; //DATA
+ uart_data_len--;
+ if (uart_data_len == 0) {
+ current_uart_rev_state_type = TUYA_BLE_UART_REV_STATE_FOUND_DATA;
+ }
+ break;
+ case TUYA_BLE_UART_REV_STATE_FOUND_DATA:
+ UART_RX_Buffer[UART_RX_Count++] = data; //sum data
+ ret = true;
+ break;
+ default:
+ memset(UART_RX_Buffer_temp, 0, 3);
+ memset(UART_RX_Buffer, 0, sizeof(UART_RX_Buffer));
+ UART_RX_Count = 0;
+ current_uart_rev_state_type = TUYA_BLE_UART_REV_STATE_FOUND_NULL;
+ uart_data_len = 0;
+ break;
+ };
+
+ return ret;
+
+}
+
+tuya_ble_status_t tuya_ble_common_uart_receive_data(uint8_t *p_data, uint16_t len)
+{
+ tuya_ble_status_t ret = TUYA_BLE_ERR_NOT_FOUND;
+ tuya_ble_evt_param_t event;
+ uint8_t *uart_evt_buffer;
+ uint16_t i;
+
+ for (i = 0; i < len; i++) {
+ if (tuya_ble_common_uart_data_unpack(p_data[i])) {
+
+ uart_evt_buffer = (uint8_t *)tuya_ble_malloc(UART_RX_Count);
+
+ if (uart_evt_buffer == NULL) {
+ TUYA_BLE_LOG_ERROR("tuya_MemGet uart evt buffer fail.");
+ ret = TUYA_BLE_ERR_NO_MEM;
+ } else {
+ event.hdr.event = TUYA_BLE_EVT_UART_CMD;
+
+ event.uart_cmd_data.data_len = UART_RX_Count;
+
+ event.uart_cmd_data.p_data = uart_evt_buffer;
+
+ memcpy(event.uart_cmd_data.p_data, &UART_RX_Buffer[0], event.uart_cmd_data.data_len);
+
+ if (tuya_ble_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_event_send uart data error.");
+ tuya_ble_free(uart_evt_buffer);
+ ret = TUYA_BLE_ERR_BUSY;
+ } else {
+ ret = TUYA_BLE_SUCCESS;
+ }
+ }
+ memset(UART_RX_Buffer_temp, 0, 3);
+ memset(UART_RX_Buffer, 0, sizeof(UART_RX_Buffer));
+ UART_RX_Count = 0;
+ current_uart_rev_state_type = TUYA_BLE_UART_REV_STATE_FOUND_NULL;
+ uart_data_len = 0;
+
+ }
+ }
+
+ return ret;
+}
+
+
+/**
+ * @brief Function for send the full instruction received from uart to the sdk.
+ *
+ * @param
+ * [in]p_data : pointer to full instruction data(Complete instruction,include0x55 or 0x66 0xaa and checksum.)
+ * [in]len : Number of bytes of pdata.
+ *
+ * @note If the application uses a custom uart parsing algorithm to obtain the full uart instruction,then call this function to send the full instruction.
+ *
+ * */
+tuya_ble_status_t tuya_ble_common_uart_send_full_instruction_received(uint8_t *p_data, uint16_t len)
+{
+ tuya_ble_status_t ret = TUYA_BLE_SUCCESS;
+ tuya_ble_evt_param_t event;
+ uint16_t rev_len, data_len;
+ uint8_t *uart_evt_buffer;
+
+ if (len < 7) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+
+ if ((p_data[0] != 0x55) && (p_data[0] != 0x66)) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+
+ uart_evt_buffer = (uint8_t *)tuya_ble_malloc(len);
+
+ if (uart_evt_buffer == NULL) {
+ TUYA_BLE_LOG_ERROR("tuya_MemGet uart evt buffer fail.");
+ ret = TUYA_BLE_ERR_NO_MEM;
+ } else {
+ event.hdr.event = TUYA_BLE_EVT_UART_CMD;
+
+ event.uart_cmd_data.data_len = len;
+
+ event.uart_cmd_data.p_data = uart_evt_buffer;
+
+ memcpy(event.uart_cmd_data.p_data, p_data, len);
+
+ if (tuya_ble_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_event_send uart full cmd error.");
+ tuya_ble_free(uart_evt_buffer);
+ ret = TUYA_BLE_ERR_BUSY;
+ }
+ }
+
+ return ret;
+}
+
+
+
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+tuya_ble_status_t tuya_ble_device_update_product_id(tuya_ble_product_id_type_t type, uint8_t len, uint8_t *p_buf)
+{
+ tuya_ble_evt_param_t event;
+
+ if (len == 0) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+
+ if (len > TUYA_BLE_PRODUCT_ID_MAX_LEN) {
+ len = TUYA_BLE_PRODUCT_ID_MAX_LEN;
+ }
+
+ event.hdr.event = TUYA_BLE_EVT_DEVICE_INFO_UPDATE;
+
+ if (type == TUYA_BLE_PRODUCT_ID_TYPE_PID) {
+ event.device_info_data.type = DEVICE_INFO_TYPE_PID;
+ } else {
+ event.device_info_data.type = DEVICE_INFO_TYPE_PRODUCT_KEY;
+ }
+
+ event.device_info_data.len = len;
+ memcpy(event.device_info_data.data, p_buf, len);
+ if (tuya_ble_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_event_send product id update error");
+ return TUYA_BLE_ERR_INTERNAL;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+tuya_ble_status_t tuya_ble_device_update_login_key(uint8_t *p_buf, uint8_t len)
+{
+ tuya_ble_evt_param_t event;
+
+ event.hdr.event = TUYA_BLE_EVT_DEVICE_INFO_UPDATE;
+
+ event.device_info_data.type = DEVICE_INFO_TYPE_LOGIN_KEY;
+
+ if (len < LOGIN_KEY_LEN) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+ event.device_info_data.len = LOGIN_KEY_LEN;
+ memcpy(event.device_info_data.data, p_buf, LOGIN_KEY_LEN);
+ if (tuya_ble_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_event_send LOGIN KEY update error");
+ return TUYA_BLE_ERR_INTERNAL;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+#if ((TUYA_BLE_PROTOCOL_VERSION_HIGN==4) && (TUYA_BLE_BEACON_KEY_ENABLE))
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+tuya_ble_status_t tuya_ble_device_update_beacon_key(uint8_t *p_buf, uint8_t len)
+{
+ tuya_ble_evt_param_t event;
+
+ event.hdr.event = TUYA_BLE_EVT_DEVICE_INFO_UPDATE;
+
+ event.device_info_data.type = DEVICE_INFO_TYPE_BEACON_KEY;
+
+ if (len < BEACON_KEY_LEN) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+ event.device_info_data.len = BEACON_KEY_LEN;
+ memcpy(event.device_info_data.data, p_buf, BEACON_KEY_LEN);
+ if (tuya_ble_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_event_send BEACON KEY update error");
+ return TUYA_BLE_ERR_INTERNAL;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+#endif
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+tuya_ble_status_t tuya_ble_device_update_mcu_version(uint32_t mcu_firmware_version, uint32_t mcu_hardware_version)
+{
+ tuya_ble_set_external_mcu_version(mcu_firmware_version, mcu_hardware_version);
+ return TUYA_BLE_SUCCESS;
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+tuya_ble_status_t tuya_ble_device_update_bound_state(uint8_t state)
+{
+ tuya_ble_evt_param_t event;
+
+ event.hdr.event = TUYA_BLE_EVT_DEVICE_INFO_UPDATE;
+
+ event.device_info_data.type = DEVICE_INFO_TYPE_BOUND;
+
+ if ((state != 1) && (state != 0)) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+ event.device_info_data.len = 1;
+ event.device_info_data.data[0] = state;
+ if (tuya_ble_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_event_send bound state update error");
+ return TUYA_BLE_ERR_INTERNAL;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN==4)
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+tuya_ble_status_t tuya_ble_dp_data_send(uint32_t sn, tuya_ble_dp_data_send_type_t type, tuya_ble_dp_data_send_mode_t mode, tuya_ble_dp_data_send_ack_t ack, uint8_t *p_dp_data, uint32_t dp_data_len)
+{
+ tuya_ble_evt_param_t evt;
+ uint8_t *ble_evt_buffer = NULL;
+ mtp_ret ret;
+ klv_node_s *list = NULL;
+
+ if (tuya_ble_connect_status_get() != BONDING_CONN) {
+ return TUYA_BLE_ERR_INVALID_STATE;
+ }
+
+ if ((dp_data_len > (TUYA_BLE_SEND_MAX_DATA_LEN - 7)) || (dp_data_len == 0)) {
+ TUYA_BLE_LOG_ERROR("send dp data len error,data len = %d , max data len = %d", dp_data_len, TUYA_BLE_SEND_MAX_DATA_LEN - 7);
+ return TUYA_BLE_ERR_INVALID_LENGTH;
+ }
+ ret = data_2_klvlist(p_dp_data, dp_data_len, &list, 1);
+ if (MTP_OK != ret) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+ free_klv_list(list);
+
+ ble_evt_buffer = (uint8_t *)tuya_ble_malloc(dp_data_len + 7);
+ if (ble_evt_buffer == NULL) {
+ return TUYA_BLE_ERR_NO_MEM;
+ } else {
+ ble_evt_buffer[0] = TUYA_BLE_DP_WRITE_CURRENT_VERSION;
+ ble_evt_buffer[1] = sn >> 24;
+ ble_evt_buffer[2] = sn >> 16;
+ ble_evt_buffer[3] = sn >> 8;
+ ble_evt_buffer[4] = sn;
+ switch (type) {
+ case DP_SEND_TYPE_ACTIVE:
+ ble_evt_buffer[5] = 0;
+ break;
+ case DP_SEND_TYPE_PASSIVE:
+ ble_evt_buffer[5] = 1;
+ break;
+ default:
+ ble_evt_buffer[5] = 0;
+ break;
+
+ };
+ if (ack == DP_SEND_WITHOUT_RESPONSE) {
+ ble_evt_buffer[5] |= 0x80;
+ }
+ ble_evt_buffer[6] = mode;
+ memcpy(ble_evt_buffer + 7, p_dp_data, dp_data_len);
+ }
+
+ evt.hdr.event = TUYA_BLE_EVT_DP_DATA_SEND;
+ evt.dp_send_data.sn = sn;
+ evt.dp_send_data.type = type;
+ evt.dp_send_data.mode = mode;
+ evt.dp_send_data.ack = ack;
+ evt.dp_send_data.p_data = ble_evt_buffer;
+ evt.dp_send_data.data_len = dp_data_len + 7;
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ tuya_ble_free(ble_evt_buffer);
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+tuya_ble_status_t tuya_ble_dp_data_with_time_send(uint32_t sn, tuya_ble_dp_data_send_mode_t mode, tuya_ble_dp_data_send_time_type_t time_type, uint8_t *p_time_data, uint8_t *p_dp_data, uint32_t dp_data_len)
+{
+ tuya_ble_evt_param_t evt;
+ uint8_t *ble_evt_buffer = NULL;
+ mtp_ret ret;
+ klv_node_s *list = NULL;
+ uint16_t buffer_len = 0;
+
+ if (tuya_ble_connect_status_get() != BONDING_CONN) {
+ return TUYA_BLE_ERR_INVALID_STATE;
+ }
+
+ if ((dp_data_len > (TUYA_BLE_SEND_MAX_DATA_LEN - 7 - 14)) || (dp_data_len == 0)) {
+ return TUYA_BLE_ERR_INVALID_LENGTH;
+ }
+
+ ret = data_2_klvlist(p_dp_data, dp_data_len, &list, 1);
+ if (MTP_OK != ret) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+ free_klv_list(list);
+
+ if (time_type == DP_TIME_TYPE_UNIX_TIMESTAMP) {
+ buffer_len = dp_data_len + 12;
+ } else if (time_type == DP_TIME_TYPE_MS_STRING) {
+ buffer_len = dp_data_len + 21;
+ } else {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+
+ ble_evt_buffer = (uint8_t *)tuya_ble_malloc(buffer_len);
+
+ if (ble_evt_buffer == NULL) {
+ return TUYA_BLE_ERR_NO_MEM;
+ } else {
+ ble_evt_buffer[0] = TUYA_BLE_DP_WRITE_CURRENT_VERSION;
+ ble_evt_buffer[1] = sn >> 24;
+ ble_evt_buffer[2] = sn >> 16;
+ ble_evt_buffer[3] = sn >> 8;
+ ble_evt_buffer[4] = sn;
+ ble_evt_buffer[5] = 0; //must 0 - WITH RESPONSE
+
+ ble_evt_buffer[6] = mode;
+ ble_evt_buffer[7] = time_type;
+
+ if (time_type == DP_TIME_TYPE_UNIX_TIMESTAMP) {
+ memcpy(&ble_evt_buffer[8], p_time_data, 4);
+ memcpy(ble_evt_buffer + 12, p_dp_data, dp_data_len);
+ } else {
+ memcpy(&ble_evt_buffer[8], p_time_data, 13);
+ memcpy(ble_evt_buffer + 21, p_dp_data, dp_data_len);
+ }
+
+
+ }
+
+ evt.hdr.event = TUYA_BLE_EVT_DP_DATA_WITH_TIME_SEND;
+ evt.dp_with_time_send_data.sn = sn;
+ evt.dp_with_time_send_data.type = DP_SEND_TYPE_ACTIVE;
+ evt.dp_with_time_send_data.mode = mode;
+ evt.dp_with_time_send_data.ack = DP_SEND_WITH_RESPONSE;
+ evt.dp_with_time_send_data.p_data = ble_evt_buffer;
+ evt.dp_with_time_send_data.data_len = buffer_len;
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ tuya_ble_free(ble_evt_buffer);
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+#else
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+tuya_ble_status_t tuya_ble_dp_data_report(uint8_t *p_data, uint32_t len)
+{
+ tuya_ble_evt_param_t evt;
+ uint8_t *ble_evt_buffer;
+ mtp_ret ret;
+ klv_node_s *list = NULL;
+
+ if (tuya_ble_connect_status_get() != BONDING_CONN) {
+ return TUYA_BLE_ERR_INVALID_STATE;
+ }
+
+ if ((len > TUYA_BLE_REPORT_MAX_DP_DATA_LEN) || (len == 0)) {
+ TUYA_BLE_LOG_ERROR("report dp data len error,data len = %d , max data len = %d", len, TUYA_BLE_REPORT_MAX_DP_DATA_LEN);
+ return TUYA_BLE_ERR_INVALID_LENGTH;
+ }
+ ret = data_2_klvlist(p_data, len, &list, 0);
+ if (MTP_OK != ret) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+ free_klv_list(list);
+
+ ble_evt_buffer = (uint8_t *)tuya_ble_malloc(len);
+ if (ble_evt_buffer == NULL) {
+ return TUYA_BLE_ERR_NO_MEM;
+ } else {
+ memcpy(ble_evt_buffer, p_data, len);
+ }
+
+ evt.hdr.event = TUYA_BLE_EVT_DP_DATA_REPORTED;
+ evt.reported_data.p_data = ble_evt_buffer;
+ evt.reported_data.data_len = len;
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ tuya_ble_free(ble_evt_buffer);
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+tuya_ble_status_t tuya_ble_dp_data_with_flag_report(uint16_t sn, tuya_ble_dp_data_send_mode_t mode, uint8_t *p_data, uint32_t len)
+{
+ tuya_ble_evt_param_t evt;
+ uint8_t *ble_evt_buffer = NULL;
+ mtp_ret ret;
+ klv_node_s *list = NULL;
+
+ if (tuya_ble_connect_status_get() != BONDING_CONN) {
+ return TUYA_BLE_ERR_INVALID_STATE;
+ }
+
+ if ((len > (TUYA_BLE_REPORT_MAX_DP_DATA_LEN - 3)) || (len == 0)) {
+ TUYA_BLE_LOG_ERROR("report flag dp data len error,data len = %d , max data len = %d", len, (TUYA_BLE_REPORT_MAX_DP_DATA_LEN - 3));
+ return TUYA_BLE_ERR_INVALID_LENGTH;
+ }
+ ret = data_2_klvlist(p_data, len, &list, 0);
+ if (MTP_OK != ret) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+ free_klv_list(list);
+
+ ble_evt_buffer = (uint8_t *)tuya_ble_malloc(len + 3);
+ if (ble_evt_buffer == NULL) {
+ return TUYA_BLE_ERR_NO_MEM;
+ } else {
+ ble_evt_buffer[0] = sn >> 8;
+ ble_evt_buffer[1] = sn;
+ ble_evt_buffer[2] = mode;
+ memcpy(ble_evt_buffer + 3, p_data, len);
+ }
+
+ evt.hdr.event = TUYA_BLE_EVT_DP_DATA_WITH_FLAG_REPORTED;
+ evt.flag_reported_data.sn = sn;
+ evt.flag_reported_data.mode = mode;
+ evt.flag_reported_data.p_data = ble_evt_buffer;
+ evt.flag_reported_data.data_len = len + 3;
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ tuya_ble_free(ble_evt_buffer);
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+
+tuya_ble_status_t tuya_ble_dp_data_with_time_report(uint32_t timestamp, uint8_t *p_data, uint32_t len)
+{
+ tuya_ble_evt_param_t evt;
+ uint8_t *ble_evt_buffer;
+ mtp_ret ret;
+ klv_node_s *list = NULL;
+
+ if (tuya_ble_connect_status_get() != BONDING_CONN) {
+ return TUYA_BLE_ERR_INVALID_STATE;
+ }
+
+ if ((len > TUYA_BLE_REPORT_MAX_DP_DATA_LEN) || (len == 0)) {
+ return TUYA_BLE_ERR_INVALID_LENGTH;
+ }
+ ret = data_2_klvlist(p_data, len, &list, 0);
+ if (MTP_OK != ret) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+ free_klv_list(list);
+ ble_evt_buffer = (uint8_t *)tuya_ble_malloc(len);
+ if (ble_evt_buffer == NULL) {
+ return TUYA_BLE_ERR_NO_MEM;
+ } else {
+ memcpy(ble_evt_buffer, p_data, len);
+ }
+
+ evt.hdr.event = TUYA_BLE_EVT_DP_DATA_WITH_TIME_REPORTED;
+ evt.reported_with_time_data.timestamp = timestamp;
+ evt.reported_with_time_data.p_data = ble_evt_buffer;
+ evt.reported_with_time_data.data_len = len;
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ tuya_ble_free(ble_evt_buffer);
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+tuya_ble_status_t tuya_ble_dp_data_with_flag_and_time_report(uint16_t sn, tuya_ble_dp_data_send_mode_t mode, uint32_t timestamp, uint8_t *p_data, uint32_t len)
+{
+ tuya_ble_evt_param_t evt;
+ uint8_t *ble_evt_buffer = NULL;
+ mtp_ret ret;
+ klv_node_s *list = NULL;
+
+ if (tuya_ble_connect_status_get() != BONDING_CONN) {
+ return TUYA_BLE_ERR_INVALID_STATE;
+ }
+
+ if ((len > (TUYA_BLE_REPORT_MAX_DP_DATA_LEN - 8)) || (len == 0)) {
+ return TUYA_BLE_ERR_INVALID_LENGTH;
+ }
+ ret = data_2_klvlist(p_data, len, &list, 0);
+ if (MTP_OK != ret) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+ free_klv_list(list);
+ ble_evt_buffer = (uint8_t *)tuya_ble_malloc(len);
+ if (ble_evt_buffer == NULL) {
+ return TUYA_BLE_ERR_NO_MEM;
+ } else {
+ memcpy(ble_evt_buffer, p_data, len);
+ }
+
+ evt.hdr.event = TUYA_BLE_EVT_DP_DATA_WITH_FLAG_AND_TIME_REPORTED;
+ evt.flag_reported_with_time_data.sn = sn;
+ evt.flag_reported_with_time_data.mode = mode;
+ evt.flag_reported_with_time_data.timestamp = timestamp;
+ evt.flag_reported_with_time_data.p_data = ble_evt_buffer;
+ evt.flag_reported_with_time_data.data_len = len;
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ tuya_ble_free(ble_evt_buffer);
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note time_string: 13-byte millisecond string ,for example ,"0000000123456";
+ *
+ * */
+
+tuya_ble_status_t tuya_ble_dp_data_with_time_ms_string_report(uint8_t *time_string, uint8_t *p_data, uint32_t len)
+{
+ tuya_ble_evt_param_t evt;
+ uint8_t *ble_evt_buffer;
+ mtp_ret ret;
+ klv_node_s *list = NULL;
+
+ if (tuya_ble_connect_status_get() != BONDING_CONN) {
+ return TUYA_BLE_ERR_INVALID_STATE;
+ }
+
+ if ((len > TUYA_BLE_REPORT_MAX_DP_DATA_LEN) || (len == 0)) {
+ return TUYA_BLE_ERR_INVALID_LENGTH;
+ }
+ ret = data_2_klvlist(p_data, len, &list, 0);
+ if (MTP_OK != ret) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+ free_klv_list(list);
+ ble_evt_buffer = (uint8_t *)tuya_ble_malloc(len);
+ if (ble_evt_buffer == NULL) {
+ return TUYA_BLE_ERR_NO_MEM;
+ } else {
+ memcpy(ble_evt_buffer, p_data, len);
+ }
+
+ evt.hdr.event = TUYA_BLE_EVT_DP_DATA_WITH_TIME_STRING_REPORTED;
+ memcpy(evt.reported_with_time_string_data.time_string, time_string, 13);
+ evt.reported_with_time_string_data.p_data = ble_evt_buffer;
+ evt.reported_with_time_string_data.data_len = len;
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ tuya_ble_free(ble_evt_buffer);
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note time_string: 13-byte millisecond string ,for example ,"0000000123456";
+ *
+ * */
+tuya_ble_status_t tuya_ble_dp_data_with_flag_and_time_ms_string_report(uint16_t sn, tuya_ble_dp_data_send_mode_t mode, uint8_t *time_string, uint8_t *p_data, uint32_t len)
+{
+ tuya_ble_evt_param_t evt;
+ uint8_t *ble_evt_buffer = NULL;
+ mtp_ret ret;
+ klv_node_s *list = NULL;
+
+ if (tuya_ble_connect_status_get() != BONDING_CONN) {
+ return TUYA_BLE_ERR_INVALID_STATE;
+ }
+
+ if ((len > (TUYA_BLE_REPORT_MAX_DP_DATA_LEN - 17)) || (len == 0)) {
+ return TUYA_BLE_ERR_INVALID_LENGTH;
+ }
+ ret = data_2_klvlist(p_data, len, &list, 0);
+ if (MTP_OK != ret) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+ free_klv_list(list);
+ ble_evt_buffer = (uint8_t *)tuya_ble_malloc(len);
+ if (ble_evt_buffer == NULL) {
+ return TUYA_BLE_ERR_NO_MEM;
+ } else {
+ memcpy(ble_evt_buffer, p_data, len);
+ }
+
+ evt.hdr.event = TUYA_BLE_EVT_DP_DATA_WITH_FLAG_AND_TIME_STRING_REPORTED;
+ evt.flag_reported_with_time_string_data.sn = sn;
+ evt.flag_reported_with_time_string_data.mode = mode;
+ memcpy(evt.flag_reported_with_time_string_data.time_string, time_string, 13);
+ evt.flag_reported_with_time_string_data.p_data = ble_evt_buffer;
+ evt.flag_reported_with_time_string_data.data_len = len;
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ tuya_ble_free(ble_evt_buffer);
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+#endif
+
+/**
+ * @brief Function for data passthrough.
+ *
+ * @note The tuya sdk will forwards the data to the app.
+ *.
+ * */
+tuya_ble_status_t tuya_ble_data_passthrough(uint8_t *p_data, uint32_t len)
+{
+ tuya_ble_evt_param_t evt;
+ uint8_t *ble_evt_buffer;
+
+ if (tuya_ble_connect_status_get() != BONDING_CONN) {
+ return TUYA_BLE_ERR_INVALID_STATE;
+ }
+
+ if (len > TUYA_BLE_SEND_MAX_DATA_LEN) {
+ return TUYA_BLE_ERR_INVALID_LENGTH;
+ }
+
+ ble_evt_buffer = (uint8_t *)tuya_ble_malloc(len);
+ if (ble_evt_buffer == NULL) {
+ return TUYA_BLE_ERR_NO_MEM;
+ }
+
+ memcpy(ble_evt_buffer, (uint8_t *)p_data, len);
+ evt.hdr.event = TUYA_BLE_EVT_DATA_PASSTHROUGH;
+ evt.passthrough_data.p_data = ble_evt_buffer;
+ evt.passthrough_data.data_len = len;
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ tuya_ble_free(ble_evt_buffer);
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+
+}
+
+/**
+ * @brief Function for response the production test instruction asynchronous.
+ *
+ * @param [in]channel: 0-uart ,1 - ble.
+ * [in]p_data : pointer to production test cmd data(Complete instruction,include0x66 0xaa and checksum.)
+ * [in]len : Number of bytes of pdata.
+ * @note
+ *.
+ * */
+tuya_ble_status_t tuya_ble_production_test_asynchronous_response(uint8_t channel, uint8_t *p_data, uint32_t len)
+{
+ tuya_ble_evt_param_t evt;
+ uint8_t *ble_evt_buffer;
+
+ if (len > TUYA_BLE_SEND_MAX_DATA_LEN) {
+ return TUYA_BLE_ERR_INVALID_LENGTH;
+ }
+
+ ble_evt_buffer = (uint8_t *)tuya_ble_malloc(len);
+ if (ble_evt_buffer == NULL) {
+ return TUYA_BLE_ERR_NO_MEM;
+ }
+
+ memcpy(ble_evt_buffer, (uint8_t *)p_data, len);
+ evt.hdr.event = TUYA_BLE_EVT_PRODUCTION_TEST_RESPONSE;
+ evt.prod_test_res_data.p_data = ble_evt_buffer;
+ evt.prod_test_res_data.data_len = len;
+ evt.prod_test_res_data.channel = channel;
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ tuya_ble_free(ble_evt_buffer);
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+
+}
+
+
+/**
+ * @brief Function for response for the net config req.
+ *
+ * @note
+ *.
+ * */
+tuya_ble_status_t tuya_ble_net_config_response(int16_t result_code)
+{
+ tuya_ble_evt_param_t evt;
+ tuya_ble_connect_status_t status = tuya_ble_connect_status_get();
+
+ if ((status != BONDING_CONN) && (status != UNBONDING_CONN)) {
+ return TUYA_BLE_ERR_INVALID_STATE;
+ }
+
+ evt.hdr.event = TUYA_BLE_EVT_NET_CONFIG_RESPONSE;
+ evt.net_config_response_data.result_code = result_code;
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+
+}
+
+#if (!TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+/**
+ * @brief Function for response for ubound req.
+ *
+ * @note
+ *.
+ * */
+tuya_ble_status_t tuya_ble_ubound_response(uint8_t result_code)
+{
+ tuya_ble_evt_param_t evt;
+ tuya_ble_connect_status_t status = tuya_ble_connect_status_get();
+
+ if (status != BONDING_CONN) {
+ return TUYA_BLE_ERR_INVALID_STATE;
+ }
+
+ evt.hdr.event = TUYA_BLE_EVT_UNBOUND_RESPONSE;
+ evt.ubound_res_data.result_code = result_code;
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+
+}
+
+
+/**
+ * @brief Function for response for anomaly ubound req.
+ *
+ * @note
+ *.
+ * */
+tuya_ble_status_t tuya_ble_anomaly_ubound_response(uint8_t result_code)
+{
+ tuya_ble_evt_param_t evt;
+ tuya_ble_connect_status_t status = tuya_ble_connect_status_get();
+
+ if (status != BONDING_CONN) {
+ return TUYA_BLE_ERR_INVALID_STATE;
+ }
+
+ evt.hdr.event = TUYA_BLE_EVT_ANOMALY_UNBOUND_RESPONSE;
+ evt.anomaly_ubound_res_data.result_code = result_code;
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+
+}
+
+/**
+ * @brief Function for response for device reset req.
+ *
+ * @note
+ *.
+ * */
+tuya_ble_status_t tuya_ble_device_reset_response(uint8_t result_code)
+{
+ tuya_ble_evt_param_t evt;
+ tuya_ble_connect_status_t status = tuya_ble_connect_status_get();
+
+ if (status != BONDING_CONN) {
+ return TUYA_BLE_ERR_INVALID_STATE;
+ }
+
+ evt.hdr.event = TUYA_BLE_EVT_DEVICE_RESET_RESPONSE;
+ evt.device_reset_res_data.result_code = result_code;
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+
+}
+
+#endif
+
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+
+tuya_ble_status_t tuya_ble_device_unbind(void)
+{
+ tuya_ble_evt_param_t event;
+
+ event.hdr.event = TUYA_BLE_EVT_DEVICE_UNBIND;
+ event.device_unbind_data.reserve = 0;
+
+ if (tuya_ble_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_event_send device unbind error");
+ return TUYA_BLE_ERR_INTERNAL;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+
+tuya_ble_status_t tuya_ble_device_factory_reset(void)
+{
+ tuya_ble_evt_param_t event;
+
+ event.hdr.event = TUYA_BLE_EVT_FACTORY_RESET;
+
+ if (tuya_ble_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_event_send factory reset error");
+ return TUYA_BLE_ERR_INTERNAL;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+
+/*
+ *@brief
+ *@param time_type:
+ * 0 -13-bytes millisecond string[from cloud]
+ * 1 - normal time format[from cloud]
+ * 2 - normal time format[from app local]
+ *@note
+ *
+ * */
+
+tuya_ble_status_t tuya_ble_time_req(uint8_t time_type)
+{
+ tuya_ble_evt_param_t event;
+
+ if (time_type > 2) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+
+ event.hdr.event = TUYA_BLE_EVT_TIME_REQ;
+ event.time_req_data.time_type = time_type;
+
+ if (tuya_ble_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_event_send time req error");
+ return TUYA_BLE_ERR_INTERNAL;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+
+tuya_ble_status_t tuya_ble_ota_response(tuya_ble_ota_response_t *p_data)
+{
+ tuya_ble_evt_param_t evt;
+ uint8_t *ble_evt_buffer;
+
+ if (tuya_ble_connect_status_get() != BONDING_CONN) {
+ return TUYA_BLE_ERR_INVALID_STATE;
+ }
+
+ if (p_data->data_len > TUYA_BLE_SEND_MAX_DATA_LEN) {
+ return TUYA_BLE_ERR_INVALID_LENGTH;
+ }
+
+ ble_evt_buffer = (uint8_t *)tuya_ble_malloc(p_data->data_len);
+ if (ble_evt_buffer == NULL) {
+ return TUYA_BLE_ERR_NO_MEM;
+ }
+
+ memcpy(ble_evt_buffer, (uint8_t *)p_data->p_data, p_data->data_len);
+ evt.hdr.event = TUYA_BLE_EVT_OTA_RESPONSE;
+ evt.ota_response_data.type = p_data->type;
+ evt.ota_response_data.p_data = ble_evt_buffer;
+ evt.ota_response_data.data_len = p_data->data_len;
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ tuya_ble_free(ble_evt_buffer);
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN >= 3)
+/*
+ *@brief
+ *@param [in]on_off: 0-off ,1 - on.
+ *
+ *@note
+ *
+ * */
+tuya_ble_status_t tuya_ble_adv_data_connecting_request_set(uint8_t on_off)
+{
+ tuya_ble_connect_status_t currnet_connect_status;
+ tuya_ble_evt_param_t evt;
+
+ if (on_off > 1) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+ currnet_connect_status = tuya_ble_connect_status_get();
+ if ((currnet_connect_status != BONDING_UNCONN) && (currnet_connect_status != UNBONDING_UNCONN)) {
+ return TUYA_BLE_ERR_INVALID_STATE;
+ }
+
+ evt.hdr.event = TUYA_BLE_EVT_CONNECTING_REQUEST;
+ evt.connecting_request_data.cmd = on_off;
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+
+}
+
+#endif
+
+extern tuya_ble_parameters_settings_t tuya_ble_current_para;
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+void tuya_ble_connected_handler(void)
+{
+ tuya_ble_evt_param_t event;
+
+ event.hdr.event = TUYA_BLE_EVT_CONNECT_STATUS_UPDATE;
+ event.connect_change_evt = TUYA_BLE_CONNECTED;
+
+ if (tuya_ble_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_event_send connect handler error");
+ }
+}
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+void tuya_ble_disconnected_handler(void)
+{
+ tuya_ble_evt_param_t event;
+
+ event.hdr.event = TUYA_BLE_EVT_CONNECT_STATUS_UPDATE;
+ event.connect_change_evt = TUYA_BLE_DISCONNECTED;
+
+ if (tuya_ble_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_event_send disconnect handler error");
+ }
+}
+
+#if TUYA_BLE_LINK_LAYER_ENCRYPTION_SUPPORT_ENABLE
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+void tuya_ble_link_encrypted_handler(void)
+{
+ tuya_ble_evt_param_t event;
+
+ event.hdr.event = TUYA_BLE_EVT_LINK_STATUS_UPDATE;
+ event.link_update_data.link_app_status = 1;
+
+ if (tuya_ble_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_event_send link encrypted handler error");
+ }
+}
+
+#endif
+
+/*
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+tuya_ble_status_t tuya_ble_sdk_init(tuya_ble_device_param_t *param_data)
+{
+ tuya_ble_cb_evt_param_t event;
+ uint8_t device_id_temp[16];
+ uint8_t device_id_temp2[20];
+ tuya_ble_gap_addr_t bt_addr;
+ uint8_t mac_temp[6];
+
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE == TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION) && \
+ (TUYA_BLE_INCLUDE_CJSON_COMPONENTS != 0)
+ cJSON_Hooks hooks;
+ hooks.malloc_fn = tuya_ble_malloc;
+ hooks.free_fn = tuya_ble_free;
+ cJSON_InitHooks(&hooks);
+#endif
+
+#if (!TUYA_BLE_DEVICE_AUTH_DATA_STORE)
+ if ((param_data->use_ext_license_key != 1) || ((param_data->device_id_len != 16) && (param_data->device_id_len != 20))) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_sdk_init param_data->device_id_len error.");
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+#endif
+
+ if (param_data->adv_local_name_len > TUYA_BLE_ADV_LOCAL_NAME_MAX_LEN) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_sdk_init param_data->adv_local_name_len error.");
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+
+ tuya_ble_storage_init();
+
+ if (param_data->product_id_len > 0) { //
+ tuya_ble_current_para.pid_type = param_data->p_type;
+
+ tuya_ble_current_para.pid_len = param_data->product_id_len;
+
+ if (tuya_ble_current_para.pid_len > TUYA_BLE_PRODUCT_ID_MAX_LEN) {
+ tuya_ble_current_para.pid_len = TUYA_BLE_PRODUCT_ID_MAX_LEN;
+ }
+
+ memcpy(tuya_ble_current_para.pid, param_data->product_id, tuya_ble_current_para.pid_len);
+ } else {
+#if ( TUYA_BLE_PROD_SUPPORT_OEM_TYPE == TUYA_BLE_PROD_OEM_TYPE_0_5 )
+ tuya_ble_current_para.pid_type = tuya_ble_current_para.auth_settings.pid_type;
+ tuya_ble_current_para.pid_len = tuya_ble_current_para.auth_settings.pid_len;
+ memcpy(tuya_ble_current_para.pid, tuya_ble_current_para.auth_settings.factory_pid, tuya_ble_current_para.pid_len);
+#endif
+ }
+
+ if (param_data->adv_local_name_len > 0) { //
+ memcpy(tuya_ble_current_para.adv_local_name, param_data->adv_local_name, param_data->adv_local_name_len);
+ tuya_ble_current_para.adv_local_name_len = param_data->adv_local_name_len;
+ } else {
+ memcpy(tuya_ble_current_para.adv_local_name, "TY", 2);
+ tuya_ble_current_para.adv_local_name_len = 2;
+ }
+
+#if (!TUYA_BLE_DEVICE_AUTH_DATA_STORE)
+ if (param_data->device_id_len == 20) {
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("device_id_20 ", param_data->device_id, 20);
+ tuya_ble_device_id_20_to_16(param_data->device_id, device_id_temp);
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("device_id_16 ", device_id_temp, 16);
+ tuya_ble_device_id_16_to_20(device_id_temp, device_id_temp2);
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("device_id_20 ", device_id_temp2, 20);
+ memcpy(tuya_ble_current_para.auth_settings.device_id, device_id_temp, DEVICE_ID_LEN);
+ } else {
+ memcpy(tuya_ble_current_para.auth_settings.device_id, param_data->device_id, DEVICE_ID_LEN);
+ }
+
+ memcpy(tuya_ble_current_para.auth_settings.auth_key, param_data->auth_key, AUTH_KEY_LEN);
+
+ memcpy(tuya_ble_current_para.sys_settings.device_virtual_id, param_data->device_vid, DEVICE_VIRTUAL_ID_LEN);
+
+ /* copy mac & mac_string into tuya_ble_current_para.auth_settings */
+ tuya_ble_str_to_hex(param_data->mac_addr_string, MAC_STRING_LEN, mac_temp);
+ TUYA_BLE_LOG_HEXDUMP_INFO("The MAC address passed in by the application", mac_temp, 6);
+ tuya_ble_inverted_array(mac_temp, 6); //Convert to little endian format
+ memcpy(param_data->mac_addr.addr, mac_temp, MAC_LEN);
+ memcpy(tuya_ble_current_para.auth_settings.mac, mac_temp, MAC_LEN);
+ tuya_ble_hextoascii(mac_temp, MAC_LEN, tuya_ble_current_para.auth_settings.mac_string);
+
+ tuya_ble_current_para.sys_settings.bound_flag = param_data->bound_flag;
+
+ if (tuya_ble_current_para.sys_settings.bound_flag) {
+ memcpy(tuya_ble_current_para.sys_settings.login_key, param_data->login_key, LOGIN_KEY_LEN);
+
+#if ((TUYA_BLE_PROTOCOL_VERSION_HIGN==4) && (TUYA_BLE_BEACON_KEY_ENABLE))
+
+ memcpy(tuya_ble_current_para.sys_settings.beacon_key, param_data->beacon_key, BEACON_KEY_LEN);
+
+#endif
+ }
+
+#else
+
+ if ((param_data->use_ext_license_key == 1) && ((param_data->device_id_len == 16) || (param_data->device_id_len == 20))) {
+ if (param_data->device_id_len == 20) {
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("device_id_20 ", param_data->device_id, 20);
+ tuya_ble_device_id_20_to_16(param_data->device_id, device_id_temp);
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("device_id_16 ", device_id_temp, 16);
+ tuya_ble_device_id_16_to_20(device_id_temp, device_id_temp2);
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("device_id_20 ", device_id_temp2, 20);
+ memcpy(tuya_ble_current_para.auth_settings.device_id, device_id_temp, DEVICE_ID_LEN);
+ } else {
+ memcpy(tuya_ble_current_para.auth_settings.device_id, param_data->device_id, DEVICE_ID_LEN);
+ }
+
+ memcpy(tuya_ble_current_para.auth_settings.auth_key, param_data->auth_key, AUTH_KEY_LEN);
+
+ /* copy mac & mac_string into tuya_ble_current_para.auth_settings */
+ tuya_ble_str_to_hex(param_data->mac_addr_string, MAC_STRING_LEN, mac_temp);
+ TUYA_BLE_LOG_HEXDUMP_INFO("The MAC address passed in by the application", mac_temp, 6);
+ tuya_ble_inverted_array(mac_temp, 6); //Convert to little endian format
+ memcpy(param_data->mac_addr.addr, mac_temp, MAC_LEN);
+ memcpy(tuya_ble_current_para.auth_settings.mac, mac_temp, MAC_LEN);
+ tuya_ble_hextoascii(mac_temp, MAC_LEN, tuya_ble_current_para.auth_settings.mac_string);
+ }
+
+#endif
+
+ if (tuya_ble_gap_addr_get(&bt_addr) == TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_HEXDUMP_INFO("current device MAC address : ", bt_addr.addr, 6);
+
+ if (TUYA_BLE_DEVICE_MAC_UPDATE) {
+ if (param_data->device_id_len == 0) {
+ bt_addr.addr_type = TUYA_BLE_ADDRESS_TYPE_RANDOM;
+ memcpy(mac_temp, tuya_ble_current_para.auth_settings.mac, 6);
+ } else {
+ bt_addr.addr_type = param_data->mac_addr.addr_type;
+ memcpy(mac_temp, param_data->mac_addr.addr, 6);
+ }
+
+ if ((!tuya_ble_buffer_value_is_all_x(mac_temp, 6, 0)) && (memcmp(mac_temp, bt_addr.addr, 6))) {
+ memcpy(bt_addr.addr, mac_temp, 6);
+ if (tuya_ble_gap_addr_set(&bt_addr) != TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_ERROR("GAP ADDR SET failed!");
+ } else {
+ TUYA_BLE_LOG_INFO("GAP ADDR SET SUCCESSED!");
+ if (TUYA_BLE_DEVICE_MAC_UPDATE_RESET) {
+ tuya_ble_device_delay_ms(500);
+ tuya_ble_device_reset();
+ }
+ }
+ }
+ }
+ } else {
+ TUYA_BLE_LOG_WARNING("GAP ADDR GET failed!");
+ }
+
+ tuya_ble_set_device_version(param_data->firmware_version, param_data->hardware_version);
+
+ tuya_ble_set_external_mcu_version(0, 0); //Initialize to 0
+
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) {
+ tuya_ble_connect_status_set(BONDING_UNCONN);
+ } else {
+ tuya_ble_connect_status_set(UNBONDING_UNCONN);
+ }
+
+ tuya_ble_adv_change();
+
+ tuya_ble_event_init();
+
+ tuya_ble_gatt_send_queue_init();
+
+ tuya_ble_common_uart_init();
+
+ tuya_ble_connect_monitor_timer_init();
+
+ TUYA_BLE_LOG_HEXDUMP_INFO("auth settings mac", tuya_ble_current_para.auth_settings.mac, MAC_LEN);
+ TUYA_BLE_LOG_HEXDUMP_INFO("product_id", tuya_ble_current_para.pid, tuya_ble_current_para.pid_len);
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("device_uuid", tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN);
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("device_authkey", tuya_ble_current_para.auth_settings.auth_key, AUTH_KEY_LEN);
+ TUYA_BLE_LOG_INFO("bond_flag = %d", tuya_ble_current_para.sys_settings.bound_flag);
+
+ TUYA_BLE_LOG_INFO("tuya ble sdk version : "TUYA_BLE_SDK_VERSION_STR);
+
+ return TUYA_BLE_SUCCESS;
+}
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_bulk_data.c b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_bulk_data.c
new file mode 100644
index 0000000..7af8a36
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_bulk_data.c
@@ -0,0 +1,278 @@
+/**
+ * \file tuya_ble_bulkdata.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#include "tuya_ble_bulk_data.h"
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_heap.h"
+#include "tuya_ble_mem.h"
+#include "tuya_ble_api.h"
+#include "tuya_ble_port.h"
+#include "tuya_ble_main.h"
+#include "tuya_ble_internal_config.h"
+#include "tuya_ble_data_handler.h"
+#include "tuya_ble_mutli_tsf_protocol.h"
+#include "tuya_ble_utils.h"
+#include "tuya_ble_secure.h"
+#include "tuya_ble_main.h"
+#include "tuya_ble_storage.h"
+#include "tuya_ble_unix_time.h"
+#include "tuya_ble_log.h"
+#include "tuya_ble_gatt_send_queue.h"
+
+
+uint32_t tuya_ble_bulk_data_read_block_size_get(void)
+{
+ uint32_t mtu_length = 0;
+ uint32_t read_block_size = 0;
+
+ if (tuya_ble_connect_status_get() != BONDING_CONN) {
+ read_block_size = 0;
+ } else {
+ mtu_length = tuya_ble_send_packet_data_length_get();
+ if (mtu_length < 100) {
+ read_block_size = 256;
+ } else if ((mtu_length >= 100) && (mtu_length < 150)) {
+ read_block_size = 512;
+ } else {
+ read_block_size = TUYA_BLE_BULK_DATA_MAX_READ_BLOCK_SIZE;
+ }
+ }
+
+ return read_block_size;
+}
+
+
+void tuya_ble_handle_bulk_data_req(uint16_t cmd, uint8_t *p_recv_data, uint32_t recv_data_len)
+{
+ uint16_t data_len;
+ tuya_ble_cb_evt_param_t event;
+ uint8_t err_code = 0;
+
+ data_len = (p_recv_data[11] << 8) + p_recv_data[12];
+
+ if (data_len == 0) {
+ return;
+ } else if (p_recv_data[13] != 0) { /*Currently only supports version 0*/
+ return;
+ } else {
+
+ }
+
+ event.evt = TUYA_BLE_CB_EVT_BULK_DATA;
+
+ switch (cmd) {
+ case FRM_BULK_DATA_READ_INFO_REQ:
+ event.bulk_req_data.evt = TUYA_BLE_BULK_DATA_EVT_READ_INFO;
+ event.bulk_req_data.bulk_type = p_recv_data[14];
+ break;
+
+ case FRM_BULK_DATA_READ_DATA_REQ:
+ event.bulk_req_data.evt = TUYA_BLE_BULK_DATA_EVT_READ_BLOCK;
+ event.bulk_req_data.bulk_type = p_recv_data[14];
+ event.bulk_req_data.params.block_data_req_data.block_number = (p_recv_data[15] << 8) + p_recv_data[16];
+ break;
+
+ case FRM_BULK_DATA_ERASE_DATA_REQ:
+ event.bulk_req_data.evt = TUYA_BLE_BULK_DATA_EVT_ERASE;
+ event.bulk_req_data.bulk_type = p_recv_data[14];
+ break;
+
+ default:
+ err_code = 1;
+ break;
+ }
+
+ if (err_code == 0) {
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_bulk_data_req-tuya ble send cb event failed.");
+ }
+ }
+}
+
+
+tuya_ble_status_t tuya_ble_bulk_data_response(tuya_ble_bulk_data_response_t *p_data)
+{
+ tuya_ble_evt_param_t evt;
+
+ if (tuya_ble_connect_status_get() != BONDING_CONN) {
+ return TUYA_BLE_ERR_INVALID_STATE;
+ }
+
+ if ((p_data->evt == TUYA_BLE_BULK_DATA_EVT_SEND_DATA) && (p_data->params.send_res_data.current_block_length > (TUYA_BLE_SEND_MAX_DATA_LEN - 8))) {
+ return TUYA_BLE_ERR_INVALID_LENGTH;
+ }
+
+ evt.hdr.event = TUYA_BLE_EVT_BULK_DATA_RESPONSE;
+
+ memcpy(&evt.bulk_res_data, p_data, sizeof(tuya_ble_bulk_data_response_t));
+
+ if (p_data->evt == TUYA_BLE_BULK_DATA_EVT_SEND_DATA) {
+ evt.bulk_res_data.params.send_res_data.p_current_block_data = NULL;
+ evt.bulk_res_data.params.send_res_data.p_current_block_data = (uint8_t *)tuya_ble_malloc(p_data->params.send_res_data.current_block_length);
+ if (evt.bulk_res_data.params.send_res_data.p_current_block_data == NULL) {
+ return TUYA_BLE_ERR_NO_MEM;
+ }
+ memcpy(evt.bulk_res_data.params.send_res_data.p_current_block_data, p_data->params.send_res_data.p_current_block_data, p_data->params.send_res_data.current_block_length);
+ }
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ if (p_data->evt == TUYA_BLE_BULK_DATA_EVT_SEND_DATA) {
+ tuya_ble_free(evt.bulk_res_data.params.send_res_data.p_current_block_data);
+ }
+
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+
+void tuya_ble_handle_bulk_data_evt(tuya_ble_evt_param_t *evt)
+{
+ uint16_t bulk_data_cmd = 0;
+ uint8_t buffer[14];
+ uint8_t *p_buf = NULL;
+ uint16_t data_length = 0;
+ uint8_t encry_mode = 0;
+ tuya_ble_cb_evt_param_t event;
+ uint8_t err_code = 0;
+
+
+ if (tuya_ble_pair_rand_valid_get() == 1) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_4;
+ }
+
+ buffer[0] = 0;
+ buffer[1] = evt->bulk_res_data.bulk_type;
+
+ switch (evt->bulk_res_data.evt) {
+ case TUYA_BLE_BULK_DATA_EVT_READ_INFO:
+
+ bulk_data_cmd = FRM_BULK_DATA_READ_INFO_RESP;
+ buffer[2] = evt->bulk_res_data.params.bulk_info_res_data.status;
+ buffer[3] = evt->bulk_res_data.params.bulk_info_res_data.flag;
+ buffer[4] = evt->bulk_res_data.params.bulk_info_res_data.bulk_data_length >> 24;
+ buffer[5] = evt->bulk_res_data.params.bulk_info_res_data.bulk_data_length >> 16;
+ buffer[6] = evt->bulk_res_data.params.bulk_info_res_data.bulk_data_length >> 8;
+ buffer[7] = evt->bulk_res_data.params.bulk_info_res_data.bulk_data_length;
+ buffer[8] = evt->bulk_res_data.params.bulk_info_res_data.bulk_data_crc >> 24;
+ buffer[9] = evt->bulk_res_data.params.bulk_info_res_data.bulk_data_crc >> 16;
+ buffer[10] = evt->bulk_res_data.params.bulk_info_res_data.bulk_data_crc >> 8;
+ buffer[11] = evt->bulk_res_data.params.bulk_info_res_data.bulk_data_crc;
+ buffer[12] = evt->bulk_res_data.params.bulk_info_res_data.block_data_length >> 8;
+ buffer[13] = evt->bulk_res_data.params.bulk_info_res_data.block_data_length;
+ data_length = 14;
+ break;
+
+ case TUYA_BLE_BULK_DATA_EVT_READ_BLOCK:
+
+ bulk_data_cmd = FRM_BULK_DATA_READ_DATA_RESP;
+ buffer[2] = evt->bulk_res_data.params.block_res_data.status;
+ buffer[3] = evt->bulk_res_data.params.block_res_data.block_number >> 8;
+ buffer[4] = evt->bulk_res_data.params.block_res_data.block_number;
+ buffer[5] = evt->bulk_res_data.params.block_res_data.block_data_length >> 8;
+ buffer[6] = evt->bulk_res_data.params.block_res_data.block_data_length;
+ buffer[7] = evt->bulk_res_data.params.block_res_data.max_packet_data_length >> 8;
+ buffer[8] = evt->bulk_res_data.params.block_res_data.max_packet_data_length;
+ buffer[9] = evt->bulk_res_data.params.block_res_data.block_data_crc16 >> 8;
+ buffer[10] = evt->bulk_res_data.params.block_res_data.block_data_crc16;
+ data_length = 11;
+ break;
+
+ case TUYA_BLE_BULK_DATA_EVT_SEND_DATA :
+
+ bulk_data_cmd = FRM_BULK_DATA_SEND_DATA;
+ p_buf = (uint8_t *)tuya_ble_malloc(evt->bulk_res_data.params.send_res_data.current_block_length + 8);
+ if (p_buf) {
+ p_buf[0] = 0;
+ p_buf[1] = evt->bulk_res_data.bulk_type;
+ p_buf[2] = evt->bulk_res_data.params.send_res_data.current_block_number >> 8;
+ p_buf[3] = evt->bulk_res_data.params.send_res_data.current_block_number;
+ p_buf[4] = 0;
+ p_buf[5] = 0;
+ p_buf[6] = evt->bulk_res_data.params.send_res_data.current_block_length >> 8;
+ p_buf[7] = evt->bulk_res_data.params.send_res_data.current_block_length;
+ memcpy(&p_buf[8], evt->bulk_res_data.params.send_res_data.p_current_block_data, evt->bulk_res_data.params.send_res_data.current_block_length);
+ data_length = evt->bulk_res_data.params.send_res_data.current_block_length + 8;
+ }
+ tuya_ble_free(evt->bulk_res_data.params.send_res_data.p_current_block_data);
+ break;
+
+ case TUYA_BLE_BULK_DATA_EVT_ERASE :
+
+ bulk_data_cmd = FRM_BULK_DATA_ERASE_DATA_RESP;
+ buffer[2] = evt->bulk_res_data.params.erase_res_data.status;
+ data_length = 3;
+
+ break;
+
+ default:
+ break;
+ }
+
+ if (data_length > 0) {
+ if (evt->bulk_res_data.evt == TUYA_BLE_BULK_DATA_EVT_READ_BLOCK) {
+ err_code = tuya_ble_commData_send(bulk_data_cmd, 0, buffer, data_length, encry_mode);
+
+ if (evt->bulk_res_data.params.block_res_data.status == 0) {
+ event.evt = TUYA_BLE_CB_EVT_BULK_DATA;
+
+ event.bulk_req_data.evt = TUYA_BLE_BULK_DATA_EVT_SEND_DATA;
+ event.bulk_req_data.bulk_type = evt->bulk_res_data.bulk_type;
+
+ event.bulk_req_data.params.send_data_req_data.block_number = evt->bulk_res_data.params.block_res_data.block_number;
+
+ if (!err_code) {
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_bulk_data_evt-tuya ble send cb event failed.");
+ }
+ } else {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_bulk_data_evt-response read bulk data error.");
+ }
+ }
+
+ } else if (evt->bulk_res_data.evt == TUYA_BLE_BULK_DATA_EVT_SEND_DATA) {
+ err_code = tuya_ble_commData_send(bulk_data_cmd, 0, p_buf, data_length, encry_mode);
+ tuya_ble_free(p_buf);
+ } else {
+ tuya_ble_commData_send(bulk_data_cmd, 0, buffer, data_length, encry_mode);
+ }
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_data_handler.c b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_data_handler.c
new file mode 100644
index 0000000..2dc5dd9
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_data_handler.c
@@ -0,0 +1,2510 @@
+/**
+ * \file tuya_ble_data_handler.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_heap.h"
+#include "tuya_ble_mem.h"
+#include "tuya_ble_api.h"
+#include "tuya_ble_port.h"
+#include "tuya_ble_main.h"
+#include "tuya_ble_internal_config.h"
+#include "tuya_ble_data_handler.h"
+#include "tuya_ble_mutli_tsf_protocol.h"
+#include "tuya_ble_utils.h"
+#include "tuya_ble_secure.h"
+#include "tuya_ble_main.h"
+#include "tuya_ble_storage.h"
+#include "tuya_ble_unix_time.h"
+#include "tuya_ble_log.h"
+#include "tuya_ble_gatt_send_queue.h"
+#include "tuya_ble_bulk_data.h"
+#include "tuya_ble_app_production_test.h"
+#include "tuya_ble_app_uart_common_handler.h"
+#if (TUYA_BLE_FEATURE_WEATHER_ENABLE != 0)
+#include "tuya_ble_feature_weather.h"
+#endif
+
+
+static uint32_t tuya_ble_firmware_version = 0;
+static uint32_t tuya_ble_hardware_version = 0;
+
+static uint32_t tuya_ble_mcu_firmware_version = 0;
+static uint32_t tuya_ble_mcu_hardware_version = 0;
+
+
+static tuya_ble_r_air_recv_packet air_recv_packet;
+
+static frm_trsmitr_proc_s ty_trsmitr_proc;
+static frm_trsmitr_proc_s ty_trsmitr_proc_send;
+static uint32_t send_packet_data_len = 20;
+
+uint8_t tuya_ble_pair_rand[6] = {0};
+uint8_t tuya_ble_pair_rand_valid = 0;
+
+static uint32_t tuya_ble_receive_sn = 0;
+static uint32_t tuya_ble_send_sn = 1;
+
+
+tuya_ble_ota_status_t tuya_ble_ota_status;
+
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN==4)
+
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE==TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION)
+
+static uint8_t dev_cert_data[1024];
+static uint8_t current_ser_cert_pub_key[64];
+static uint8_t current_dev_random_for_sign[6];
+static tuya_ble_auth_status_t current_auth_status;
+
+void tuya_ble_auth_data_reset(void)
+{
+ tuya_ble_device_enter_critical();
+ current_auth_status = TUYA_BLE_AUTH_STATUS_PHASE_NONE;
+ memset(current_ser_cert_pub_key, 0, sizeof(current_ser_cert_pub_key));
+ memset(current_dev_random_for_sign, 0, sizeof(current_dev_random_for_sign));
+ tuya_ble_device_exit_critical();
+}
+
+#endif
+
+#endif
+
+static uint32_t get_ble_send_sn(void)
+{
+ uint32_t sn;
+ tuya_ble_device_enter_critical();
+ sn = tuya_ble_send_sn++;
+ tuya_ble_device_exit_critical();
+ return sn;
+}
+
+static void set_ble_receive_sn(uint32_t sn)
+{
+ tuya_ble_device_enter_critical();
+ tuya_ble_receive_sn = sn;
+ tuya_ble_device_exit_critical();
+}
+
+void tuya_ble_reset_ble_sn(void)
+{
+ tuya_ble_device_enter_critical();
+ tuya_ble_receive_sn = 0;
+ tuya_ble_send_sn = 1;
+ tuya_ble_device_exit_critical();
+}
+
+
+void tuya_ble_set_device_version(uint32_t firmware_version, uint32_t hardware_version)
+{
+ tuya_ble_firmware_version = firmware_version;
+ tuya_ble_hardware_version = hardware_version;
+}
+
+
+void tuya_ble_set_external_mcu_version(uint32_t firmware_version, uint32_t hardware_version)
+{
+ tuya_ble_device_enter_critical();
+ tuya_ble_mcu_firmware_version = firmware_version;
+ tuya_ble_mcu_hardware_version = hardware_version;
+ tuya_ble_device_exit_critical();
+}
+
+
+void tuya_ble_ota_status_set(tuya_ble_ota_status_t status)
+{
+ tuya_ble_ota_status = status;
+}
+
+
+tuya_ble_ota_status_t tuya_ble_ota_status_get(void)
+{
+ return tuya_ble_ota_status;
+}
+
+
+void tuya_ble_pair_rand_clear(void)
+{
+ tuya_ble_device_enter_critical();
+ memset(tuya_ble_pair_rand, 0, sizeof(tuya_ble_pair_rand));
+ tuya_ble_pair_rand_valid = 0;
+ tuya_ble_device_exit_critical();
+}
+
+
+uint8_t tuya_ble_pair_rand_valid_get(void)
+{
+ return tuya_ble_pair_rand_valid;
+}
+
+
+uint32_t tuya_ble_send_packet_data_length_get(void)
+{
+ return send_packet_data_len;
+}
+
+
+static bool buffer_value_is_all_x(uint8_t *buffer, uint16_t len, uint8_t value)
+{
+ bool ret = true;
+ for (uint16_t i = 0; i < len; i++) {
+ if (buffer[i] != value) {
+ ret = false;
+ break;
+ }
+ }
+ return ret;
+}
+
+void tuya_ble_air_recv_packet_free(void)
+{
+ if (air_recv_packet.recv_data) {
+ tuya_ble_free(air_recv_packet.recv_data);
+ air_recv_packet.recv_data = NULL;
+ air_recv_packet.recv_len_max = 0;
+ air_recv_packet.recv_len = 0;
+ }
+}
+
+static uint32_t ble_data_unpack(uint8_t *buf, uint32_t len)
+{
+ static uint32_t offset = 0;
+ mtp_ret ret;
+
+ ret = trsmitr_recv_pkg_decode(&ty_trsmitr_proc, buf, len);
+ if (MTP_OK != ret && MTP_TRSMITR_CONTINUE != ret) {
+ air_recv_packet.recv_len_max = 0;
+ air_recv_packet.recv_len = 0;
+ if (air_recv_packet.recv_data) {
+ tuya_ble_free(air_recv_packet.recv_data);
+ air_recv_packet.recv_data = NULL;
+ }
+
+ return 1;
+ }
+
+ if (FRM_PKG_FIRST == ty_trsmitr_proc.pkg_desc) {
+ if (air_recv_packet.recv_data) {
+ tuya_ble_free(air_recv_packet.recv_data);
+ air_recv_packet.recv_data = NULL;
+ }
+ air_recv_packet.recv_len_max = get_trsmitr_frame_total_len(&ty_trsmitr_proc);
+ if ((air_recv_packet.recv_len_max > TUYA_BLE_AIR_FRAME_MAX) || (air_recv_packet.recv_len_max == 0)) {
+ air_recv_packet.recv_len_max = 0;
+ air_recv_packet.recv_len = 0;
+ TUYA_BLE_LOG_ERROR("ble_data_unpack total size [%d ]error.", air_recv_packet.recv_len_max);
+ return 2;
+ }
+ air_recv_packet.recv_len = 0;
+ air_recv_packet.recv_data = tuya_ble_malloc(air_recv_packet.recv_len_max);
+ if (air_recv_packet.recv_data == NULL) {
+ TUYA_BLE_LOG_ERROR("ble_data_unpack malloc failed.");
+ return 2;
+ }
+ memset(air_recv_packet.recv_data, 0, air_recv_packet.recv_len_max);
+ offset = 0;
+ }
+ if ((offset + get_trsmitr_subpkg_len(&ty_trsmitr_proc)) <= air_recv_packet.recv_len_max) {
+ if (air_recv_packet.recv_data) {
+ memcpy(air_recv_packet.recv_data + offset, get_trsmitr_subpkg(&ty_trsmitr_proc), get_trsmitr_subpkg_len(&ty_trsmitr_proc));
+ offset += get_trsmitr_subpkg_len(&ty_trsmitr_proc);
+ air_recv_packet.recv_len = offset;
+ } else {
+ TUYA_BLE_LOG_ERROR("ble_data_unpack error.");
+ air_recv_packet.recv_len_max = 0;
+ air_recv_packet.recv_len = 0;
+ return 2;
+ }
+ } else {
+ ret = MTP_INVALID_PARAM;
+ TUYA_BLE_LOG_ERROR("ble_data_unpack[] error:MTP_INVALID_PARAM");
+ tuya_ble_air_recv_packet_free();
+ }
+
+ if (ret == MTP_OK) {
+ offset = 0;
+ TUYA_BLE_LOG_DEBUG("ble_data_unpack[%d]", air_recv_packet.recv_len);
+
+ return 0;
+ } else {
+ return 2;
+ }
+}
+
+static uint8_t ble_cmd_data_crc_check(uint8_t *input, uint16_t len)
+{
+ uint16_t data_len = 0;
+ uint16_t crc16 = 0xFFFF;
+ uint16_t crc16_cal = 0;
+
+ data_len = (input[10] << 8) | input[11];
+
+ if (data_len >= TUYA_BLE_RECEIVE_MAX_DATA_LEN) {
+ return 1;
+ }
+
+ crc16_cal = tuya_ble_crc16_compute(input, 12 + data_len, &crc16);
+
+ TUYA_BLE_LOG_DEBUG("crc16_cal[0x%04x]", crc16_cal);
+ crc16 = (input[12 + data_len] << 8) | input[13 + data_len];
+ TUYA_BLE_LOG_DEBUG("crc16[0x%04x]", crc16);
+ if (crc16 == crc16_cal) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+
+void tuya_ble_commonData_rx_proc(uint8_t *buf, uint16_t len)
+{
+ uint8_t temp;
+ uint32_t current_sn = 0;
+ uint16_t current_cmd = 0;
+ tuya_ble_evt_param_t evt;
+ uint8_t *ble_evt_buffer = NULL;
+ uint8_t current_encry_mode = 0;
+ uint16_t p_version = 0;
+ bool is_cmd_with_encry_mode_correct = true;
+
+ if (ble_data_unpack(buf, len)) {
+ return; //
+ }
+
+ if (air_recv_packet.recv_len > TUYA_BLE_AIR_FRAME_MAX) {
+ TUYA_BLE_LOG_ERROR("air_recv_packet.recv_len bigger than TUYA_BLE_AIR_FRAME_MAX.");
+ tuya_ble_air_recv_packet_free();
+ return;
+ }
+
+ if (ty_trsmitr_proc.version < 2) {
+ TUYA_BLE_LOG_ERROR("ty_ble_rx_proc version not compatibility!");
+ tuya_ble_air_recv_packet_free();
+ return;
+ }
+
+
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) {
+ if ((ENCRYPTION_MODE_NONE == air_recv_packet.recv_data[0]) || (ENCRYPTION_MODE_FTM_KEY == air_recv_packet.recv_data[0])) {
+ TUYA_BLE_LOG_ERROR("ty_ble_rx_proc data encryption mode error since bound_flag = 1.");
+ tuya_ble_air_recv_packet_free();
+ return;
+ }
+ }
+
+ current_encry_mode = air_recv_packet.recv_data[0];
+
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("received encry data", (uint8_t *)air_recv_packet.recv_data, air_recv_packet.recv_len); //
+
+ air_recv_packet.de_encrypt_buf = NULL;
+
+ air_recv_packet.de_encrypt_buf = (uint8_t *)tuya_ble_malloc(air_recv_packet.recv_len);
+
+ if (air_recv_packet.de_encrypt_buf == NULL) {
+ TUYA_BLE_LOG_ERROR("air_recv_packet.de_encrypt_buf malloc failed.");
+ tuya_ble_air_recv_packet_free();
+ return;
+ } else {
+ p_version = (TUYA_BLE_PROTOCOL_VERSION_HIGN << 8) + TUYA_BLE_PROTOCOL_VERSION_LOW;
+ air_recv_packet.decrypt_buf_len = 0;
+ temp = tuya_ble_decryption(p_version, (uint8_t *)air_recv_packet.recv_data, air_recv_packet.recv_len, &air_recv_packet.decrypt_buf_len,
+ (uint8_t *)air_recv_packet.de_encrypt_buf, &tuya_ble_current_para, tuya_ble_pair_rand);
+ tuya_ble_air_recv_packet_free();
+ }
+
+
+ if (temp != 0) {
+ TUYA_BLE_LOG_ERROR("ble receive data decryption error code = %d", temp);
+ tuya_ble_free(air_recv_packet.de_encrypt_buf);
+ return;
+ }
+
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("decryped data", (uint8_t *)air_recv_packet.de_encrypt_buf, air_recv_packet.decrypt_buf_len);
+
+ if (ble_cmd_data_crc_check((uint8_t *)air_recv_packet.de_encrypt_buf, air_recv_packet.decrypt_buf_len) != 0) {
+ TUYA_BLE_LOG_ERROR("ble receive data crc check error!");
+ tuya_ble_free(air_recv_packet.de_encrypt_buf);
+ return;
+ }
+
+#if TUYA_BLE_LINK_LAYER_ENCRYPTION_SUPPORT_ENABLE
+
+ if (current_cmd == FRM_QRY_DEV_INFO_REQ) {
+ tuya_ble_reset_ble_sn();
+ }
+
+#endif
+
+ current_sn = air_recv_packet.de_encrypt_buf[0] << 24;
+ current_sn += air_recv_packet.de_encrypt_buf[1] << 16;
+ current_sn += air_recv_packet.de_encrypt_buf[2] << 8;
+ current_sn += air_recv_packet.de_encrypt_buf[3];
+
+ if (current_sn <= tuya_ble_receive_sn) {
+ TUYA_BLE_LOG_ERROR("ble receive SN error!");
+ tuya_ble_gap_disconnect();
+ tuya_ble_free(air_recv_packet.de_encrypt_buf);
+ return;
+ } else {
+ set_ble_receive_sn(current_sn);
+ }
+
+ current_cmd = ((air_recv_packet.de_encrypt_buf[8] << 8) | air_recv_packet.de_encrypt_buf[9]);
+
+ if (current_cmd == FRM_FACTORY_TEST_CMD) {
+ // Check recvived cmd with encry mode corresponding relationship
+#if (TUYA_BLE_PROD_TEST_SUPPORT_ENCRYPTION != 0)
+ if (current_encry_mode != ENCRYPTION_MODE_FTM_KEY) {
+ is_cmd_with_encry_mode_correct = false;
+ }
+#else
+ if (current_encry_mode != ENCRYPTION_MODE_NONE) {
+ is_cmd_with_encry_mode_correct = false;
+ }
+#endif
+
+ if (!is_cmd_with_encry_mode_correct) {
+ tuya_ble_free(air_recv_packet.de_encrypt_buf);
+ TUYA_BLE_LOG_ERROR("ble receive cmd error on prod factory test state, need encrypt!");
+ return;
+ }
+ }
+
+ if ((BONDING_CONN != tuya_ble_connect_status_get()) && (FRM_QRY_DEV_INFO_REQ != current_cmd) && (PAIR_REQ != current_cmd)
+ && (FRM_LOGIN_KEY_REQ != current_cmd) && (FRM_FACTORY_TEST_CMD != current_cmd) && (FRM_NET_CONFIG_INFO_REQ != current_cmd) && (FRM_ANOMALY_UNBONDING_REQ != current_cmd)
+ && (FRM_AUTHENTICATE_PHASE_1_REQ != current_cmd) && (FRM_AUTHENTICATE_PHASE_2_REQ != current_cmd) && (FRM_AUTHENTICATE_PHASE_3_REQ != current_cmd)) {
+ tuya_ble_free(air_recv_packet.de_encrypt_buf);
+ TUYA_BLE_LOG_ERROR("ble receive cmd error on current bond state!");
+ return;
+ }
+
+
+ if (tuya_ble_ota_status_get() != TUYA_BLE_OTA_STATUS_NONE) {
+ if (!((current_cmd >= FRM_OTA_START_REQ) && (current_cmd <= FRM_OTA_END_REQ))) {
+ tuya_ble_free(air_recv_packet.de_encrypt_buf);
+ TUYA_BLE_LOG_ERROR("ble receive cmd error on ota state!");
+ return;
+ }
+ }
+
+ ble_evt_buffer = (uint8_t *)tuya_ble_malloc(air_recv_packet.decrypt_buf_len + 1);
+ if (ble_evt_buffer == NULL) {
+ TUYA_BLE_LOG_ERROR("ty_ble_rx_proc no mem.");
+ tuya_ble_free(air_recv_packet.de_encrypt_buf);
+ return;
+ } else {
+ memset(ble_evt_buffer, 0, air_recv_packet.decrypt_buf_len + 1);
+ }
+ ble_evt_buffer[0] = current_encry_mode;
+ memcpy(ble_evt_buffer + 1, (uint8_t *)air_recv_packet.de_encrypt_buf, air_recv_packet.decrypt_buf_len);
+ evt.hdr.event = TUYA_BLE_EVT_BLE_CMD;
+ evt.ble_cmd_data.cmd = current_cmd;
+ evt.ble_cmd_data.p_data = ble_evt_buffer;
+ evt.ble_cmd_data.data_len = air_recv_packet.decrypt_buf_len + 1;
+ TUYA_BLE_LOG_DEBUG("BLE EVENT SEND-CMD:0x%02x - LEN:0x%02x", current_cmd, air_recv_packet.decrypt_buf_len + 1);
+
+ if (tuya_ble_event_send(&evt) != 0) {
+ TUYA_BLE_LOG_ERROR("ble event send fail!");
+ tuya_ble_free(ble_evt_buffer);
+ }
+
+ tuya_ble_free(air_recv_packet.de_encrypt_buf);
+
+}
+
+
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN==4)
+
+static void tuya_ble_handle_dev_info_req(uint8_t *recv_data, uint16_t recv_len)
+{
+ uint8_t p_buf[112];
+ uint8_t payload_len = 0;
+ uint32_t ack_sn = 0;
+ uint8_t encry_mode = 0;
+ uint32_t version_temp_s, version_temp_h;
+ tuya_ble_gap_addr_t mac_addr;
+ uint16_t data_len = recv_data[11] << 8 | recv_data[12];
+
+ if (data_len != 2) {
+ TUYA_BLE_LOG_ERROR("get device infor cmd error with v4,data_len = %d", data_len);
+ tuya_ble_gap_disconnect();
+ return;
+ }
+
+ memset(p_buf, 0, sizeof(p_buf));
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ TUYA_BLE_LOG_DEBUG("get device infor-%d", tuya_ble_current_para.sys_settings.bound_flag);
+
+ send_packet_data_len = recv_data[13] << 8 | recv_data[14];
+
+ if ((send_packet_data_len == 0) || (send_packet_data_len > TUYA_BLE_DATA_MTU_MAX)) {
+ send_packet_data_len = 20;
+ }
+
+ TUYA_BLE_LOG_DEBUG("current app mtu data len = %d", send_packet_data_len);
+
+ tuya_ble_rand_generator(tuya_ble_pair_rand, 6);
+ tuya_ble_pair_rand_valid = 1;
+
+ if (TUYA_BLE_DEVICE_REGISTER_FROM_BLE) {
+ version_temp_s = tuya_ble_firmware_version;
+ version_temp_h = tuya_ble_hardware_version;
+ p_buf[4] = 0x00;
+ } else {
+ version_temp_s = tuya_ble_firmware_version >> 8;
+ version_temp_h = tuya_ble_hardware_version >> 8;
+ p_buf[4] = 0x05;
+ }
+ p_buf[0] = (version_temp_s >> 8) & 0xff;
+ p_buf[1] = (version_temp_s & 0xff);
+ p_buf[2] = TUYA_BLE_PROTOCOL_VERSION_HIGN;
+ p_buf[3] = TUYA_BLE_PROTOCOL_VERSION_LOW;
+
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE==TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION)
+
+ p_buf[4] |= 0x02;
+ if (TUYA_BLE_ADVANCED_ENCRYPTION_AUTH_ON_CONNECT) {
+ p_buf[4] |= 0x08;
+ }
+
+#endif
+
+#if (TUYA_BLE_PROTOCOL_VERSION_LOW>=1)
+
+ if (TUYA_BLE_BEACON_KEY_ENABLE) {
+ p_buf[4] |= 0x10;
+ }
+
+#endif
+
+ p_buf[5] = tuya_ble_current_para.sys_settings.bound_flag;
+ memcpy(&p_buf[6], tuya_ble_pair_rand, 6);
+ p_buf[12] = (version_temp_h >> 8) & 0xff;
+ p_buf[13] = (version_temp_h & 0xff);
+
+ tuya_ble_register_key_generate(&p_buf[14], &tuya_ble_current_para);
+
+ p_buf[46] = (tuya_ble_firmware_version >> 16) & 0xff;
+ p_buf[47] = (tuya_ble_firmware_version >> 8) & 0xff;
+ p_buf[48] = (tuya_ble_firmware_version & 0xff);
+ p_buf[49] = (tuya_ble_hardware_version >> 16) & 0xff;
+ p_buf[50] = (tuya_ble_hardware_version >> 8) & 0xff;
+ p_buf[51] = (tuya_ble_hardware_version & 0xff);
+
+ p_buf[52] = TUYA_BLE_DEVICE_COMMUNICATION_ABILITY >> 8;
+ p_buf[53] = TUYA_BLE_DEVICE_COMMUNICATION_ABILITY; //communication ability
+
+ p_buf[54] = 0x00;
+
+ memcpy(&p_buf[55], tuya_ble_current_para.sys_settings.device_virtual_id, DEVICE_VIRTUAL_ID_LEN);
+
+ p_buf[77] = (tuya_ble_mcu_firmware_version >> 16) & 0xff;
+ p_buf[78] = (tuya_ble_mcu_firmware_version >> 8) & 0xff;
+ p_buf[79] = (tuya_ble_mcu_firmware_version & 0xff);
+ p_buf[80] = (tuya_ble_mcu_hardware_version >> 16) & 0xff;
+ p_buf[81] = (tuya_ble_mcu_hardware_version >> 8) & 0xff;
+ p_buf[82] = (tuya_ble_mcu_hardware_version & 0xff);
+
+ p_buf[83] = TUYA_BLE_WIFI_DEVICE_REGISTER_MODE;
+
+#if (TUYA_BLE_PROTOCOL_VERSION_LOW>=2)
+
+ memset(&p_buf[84], 0, 4);
+
+ tuya_ble_gap_addr_get(&mac_addr);
+
+ p_buf[88] = mac_addr.addr_type;
+
+ memcpy(&p_buf[89], mac_addr.addr, 6);
+
+ p_buf[95] = strlen(TUYA_BLE_APP_FIRMWARE_KEY);
+
+ if ((p_buf[95] == 8) || (p_buf[95] == 16)) {
+ memcpy(&p_buf[96], TUYA_BLE_APP_FIRMWARE_KEY, p_buf[95]);
+ } else {
+ p_buf[95] = 0;
+ }
+
+ payload_len = 96 + p_buf[95];
+
+#else
+
+ p_buf[84] = strlen(TUYA_BLE_APP_FIRMWARE_KEY);
+
+ if ((p_buf[84] == 8) || (p_buf[84] == 16)) {
+ memcpy(&p_buf[85], TUYA_BLE_APP_FIRMWARE_KEY, p_buf[84]);
+ } else {
+ p_buf[84] = 0;
+ }
+
+ payload_len = 85 + p_buf[84];
+
+#endif
+
+ encry_mode = recv_data[0];
+
+ if (tuya_ble_commData_send(FRM_QRY_DEV_INFO_RESP, ack_sn, p_buf, payload_len, encry_mode) == 2) {
+ tuya_ble_pair_rand_clear();
+ }
+}
+
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE==TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION)
+
+static void tuya_ble_handle_authenticate_phase1(uint8_t *recv_data, uint16_t recv_len)
+{
+ uint8_t p_buf[7];
+ uint8_t encry_mode = 0;
+ uint32_t ack_sn = 0;
+ uint8_t sig_data[64];
+ uint16_t data_len = 0;
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ data_len = (recv_data[11] << 8) + recv_data[12];
+
+ if (((tuya_ble_current_para.sys_settings.bound_flag == 0) && (recv_data[13] == 0)) || ((tuya_ble_current_para.sys_settings.bound_flag == 1) && (recv_data[13] == 1))) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_authenticate_phase1 -> invalid state.");
+ tuya_ble_gap_disconnect();
+ return;
+ }
+
+ if ((data_len != 1 && data_len != 130) || (current_auth_status != TUYA_BLE_AUTH_STATUS_PHASE_NONE)) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_authenticate_phase1 -> invalid state or data length.");
+ tuya_ble_gap_disconnect();
+ return;
+ }
+
+ p_buf[0] = 0;
+
+ tuya_ble_auth_data_reset();
+
+ if (recv_data[13] == 1) {
+ if (data_len == 130) {
+ memcpy(current_ser_cert_pub_key, recv_data + 15, 64);
+ memcpy(sig_data, recv_data + 79, 64);
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("received server public key:", current_ser_cert_pub_key, sizeof(current_ser_cert_pub_key));
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("received server public key signature data:", sig_data, sizeof(sig_data));
+ if (!tuya_ble_server_cert_data_verify(recv_data + 14, 65, sig_data)) {
+ p_buf[0] = 1;
+ TUYA_BLE_LOG_ERROR("server public key signature data verify failed.");
+ } else {
+ TUYA_BLE_LOG_DEBUG("server public key signature data verify succeed.");
+ }
+ } else {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_authenticate_phase1 -> invalid state.");
+ tuya_ble_gap_disconnect();
+ return;
+ }
+ } else {
+ memcpy(current_ser_cert_pub_key, tuya_ble_current_para.sys_settings.server_cert_pub_key, 64);
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("get server public key from tuya ble current para:", current_ser_cert_pub_key, sizeof(current_ser_cert_pub_key));
+ }
+
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_2;
+ }
+
+ if (p_buf[0] == 0) {
+ tuya_ble_rand_generator(current_dev_random_for_sign, 6);
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("device generate random:", current_dev_random_for_sign, sizeof(current_dev_random_for_sign));
+ memcpy(p_buf + 1, current_dev_random_for_sign, 6);
+ current_auth_status = TUYA_BLE_AUTH_STATUS_PHASE_1;
+ tuya_ble_commData_send(FRM_AUTHENTICATE_PHASE_1_RESP, ack_sn, p_buf, 7, encry_mode);
+ } else {
+ tuya_ble_commData_send(FRM_AUTHENTICATE_PHASE_1_RESP, ack_sn, p_buf, 1, encry_mode);
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_authenticate_phase1 -> auth failed.");
+ tuya_ble_gap_disconnect();
+ }
+
+
+}
+
+
+static void tuya_ble_handle_authenticate_phase2(uint8_t *recv_data, uint16_t recv_len)
+{
+ uint8_t encry_mode = 0;
+ uint32_t ack_sn = 0;
+ uint8_t sig_data[64] = {0};
+ uint16_t data_len = 0;
+ uint32_t dev_cert_data_len = 0;
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ data_len = (recv_data[11] << 8) + recv_data[12];
+
+ if ((data_len != 65) || (current_auth_status != TUYA_BLE_AUTH_STATUS_PHASE_1)) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_authenticate_phase2 -> invalid state or data length.");
+ tuya_ble_gap_disconnect();
+ return;
+ }
+ memset(dev_cert_data, 0, sizeof(dev_cert_data));
+
+ dev_cert_data[0] = 0;
+
+ if (recv_data[13] == 0) {
+ memcpy(sig_data, recv_data + 14, 64);
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("received signature data for device random:", sig_data, sizeof(sig_data));
+ } else {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_authenticate_phase2 -> invalid data type.");
+ tuya_ble_gap_disconnect();
+ return;
+ }
+
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_2;
+ }
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("current device random:", current_dev_random_for_sign, sizeof(current_dev_random_for_sign));
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("verify signature data of device random use server public key:", current_ser_cert_pub_key, sizeof(current_ser_cert_pub_key));
+ if (!tuya_ble_sig_data_verify(current_ser_cert_pub_key, current_dev_random_for_sign, 6, sig_data)) {
+ dev_cert_data[0] = 1;
+ tuya_ble_commData_send(FRM_AUTHENTICATE_PHASE_2_RESP, ack_sn, dev_cert_data, 1, encry_mode);
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_authenticate_phase2 -> device random signature data verify failed.");
+ tuya_ble_gap_disconnect();
+ return;
+
+ } else {
+ TUYA_BLE_LOG_DEBUG("tuya_ble_handle_authenticate_phase2 -> device random signature data verify succeed.");
+ }
+
+ if (tuya_ble_current_para.sys_settings.bound_flag == 0) {
+ dev_cert_data_len = tuya_ble_get_dev_crt_len();
+
+ if (dev_cert_data_len == 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_authenticate_phase2 -> get dev cert length error.");
+ tuya_ble_gap_disconnect();
+ return;
+ } else {
+ TUYA_BLE_LOG_DEBUG("tuya_ble_handle_authenticate_phase2 -> get dev cert length = %d .", dev_cert_data_len);
+ dev_cert_data[0] = 0;
+ dev_cert_data[1] = 0;
+ if (tuya_ble_get_dev_crt_der(dev_cert_data + 2, dev_cert_data_len) != TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_authenticate_phase2 -> get dev cert data error.");
+ tuya_ble_gap_disconnect();
+ return;
+ }
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("get device cert :", dev_cert_data + 2, dev_cert_data_len);
+ tuya_ble_commData_send(FRM_AUTHENTICATE_PHASE_2_RESP, ack_sn, dev_cert_data, dev_cert_data_len + 2, encry_mode);
+ }
+ } else {
+ dev_cert_data[0] = 0;
+ tuya_ble_commData_send(FRM_AUTHENTICATE_PHASE_2_RESP, ack_sn, dev_cert_data, 1, encry_mode);
+ TUYA_BLE_LOG_DEBUG("tuya_ble_handle_authenticate_phase2 -> no need send dev cert because in bound state.");
+ }
+
+ current_auth_status = TUYA_BLE_AUTH_STATUS_PHASE_2;
+
+}
+
+
+static void tuya_ble_handle_authenticate_phase3(uint8_t *recv_data, uint16_t recv_len)
+{
+ uint8_t encry_mode = 0;
+ uint32_t ack_sn = 0;
+ uint8_t p_buf[65] = {0};
+ uint16_t data_len = 0;
+ uint8_t random[6] = {0};
+ uint8_t random_hash[32] = {0};
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ data_len = (recv_data[11] << 8) + recv_data[12];
+
+ if ((data_len != 7 && data_len != 1) || (current_auth_status != TUYA_BLE_AUTH_STATUS_PHASE_2)) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_authenticate_phase3 -> invalid state or data length.");
+ tuya_ble_gap_disconnect();
+ return;
+ }
+
+ if (recv_data[13] != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_authenticate_phase3 -> dev cert verify failed.");
+ tuya_ble_gap_disconnect();
+ return;
+ } else {
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("received server random for signature :", random, 6);
+ memcpy(random, &recv_data[14], 6);
+ }
+
+ if (tuya_ble_ecc_sign_secp256r1(NULL, random, 6, p_buf + 1) != TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_authenticate_phase3 -> server random sign failed.");
+ tuya_ble_gap_disconnect();
+ return;
+ } else {
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("tuya_ble_handle_authenticate_phase3 -> server random sign succeed.", p_buf + 1, 64);
+ }
+
+ p_buf[0] = 0;
+
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_2;
+ }
+
+ tuya_ble_commData_send(FRM_AUTHENTICATE_PHASE_3_RESP, ack_sn, p_buf, 65, encry_mode);
+
+ current_auth_status = TUYA_BLE_AUTH_STATUS_PHASE_3;
+
+}
+
+#endif
+
+extern void tuya_ble_connect_monitor_timer_stop(void);
+static void tuya_ble_handle_pair_req(uint8_t *recv_data, uint16_t recv_len)
+{
+ uint8_t p_buf[1];
+ uint8_t encry_mode = 0;
+ uint32_t ack_sn = 0;
+ uint16_t data_len = 0;
+ tuya_ble_cb_evt_param_t event;
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ data_len = (recv_data[11] << 8) + recv_data[12];
+
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE==TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION)
+
+#if (TUYA_BLE_ADVANCED_ENCRYPTION_AUTH_ON_CONNECT)
+
+ if (current_auth_status != TUYA_BLE_AUTH_STATUS_PHASE_3) {
+ TUYA_BLE_LOG_ERROR("PAIR_REQ failed ,because current_auth_status error!"); //ID not match ,and disconnected.
+ tuya_ble_gap_disconnect();
+ return;
+ }
+
+#else
+
+ if (tuya_ble_current_para.sys_settings.bound_flag == 0) {
+ if (current_auth_status != TUYA_BLE_AUTH_STATUS_PHASE_3) {
+ TUYA_BLE_LOG_ERROR("PAIR_REQ failed ,because current_auth_status error!"); //ID not match ,and disconnected.
+ tuya_ble_gap_disconnect();
+ return;
+ }
+ }
+
+#endif
+
+#endif
+
+
+ if (0 == memcmp(&recv_data[13], tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN)) {
+ tuya_ble_connect_monitor_timer_stop();
+
+ if (1 == tuya_ble_get_adv_connect_request_bit_status()) {
+ TUYA_BLE_LOG_INFO("ble adv data update,because the last broadcast data connection request flag was set!");
+ tuya_ble_adv_change();
+ }
+
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) {
+ TUYA_BLE_LOG_INFO("PAIR_REQ already bound!");
+ p_buf[0] = 2;
+ tuya_ble_connect_status_set(BONDING_CONN);
+ } else {
+#if (TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+
+#if (TUYA_BLE_PROTOCOL_VERSION_LOW>=1)
+
+ if (TUYA_BLE_BEACON_KEY_ENABLE) {
+ if (data_len < 61) {
+ p_buf[0] = 1;
+ goto pair_exit;
+ } else {
+ if (recv_data[57] != BEACON_KEY_LEN) {
+ p_buf[0] = 1;
+ goto pair_exit;
+ } else {
+ memcpy(tuya_ble_current_para.sys_settings.beacon_key, recv_data + 58, BEACON_KEY_LEN);
+ }
+ }
+
+ }
+
+#endif
+
+ memcpy(tuya_ble_current_para.sys_settings.login_key, recv_data + 29, LOGIN_KEY_LEN);
+ memcpy(tuya_ble_current_para.sys_settings.device_virtual_id, recv_data + 29 + LOGIN_KEY_LEN, DEVICE_VIRTUAL_ID_LEN);
+ tuya_ble_current_para.sys_settings.bound_flag = 1;
+
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE==TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION)
+
+ if (!tuya_ble_buffer_value_is_all_x(current_ser_cert_pub_key, 64, 0)) {
+ memcpy(tuya_ble_current_para.sys_settings.server_cert_pub_key, current_ser_cert_pub_key, 64);
+ } else {
+ p_buf[0] = 1;
+ tuya_ble_current_para.sys_settings.bound_flag = 0;
+ goto pair_exit;
+ }
+
+#endif
+
+ tuya_ble_storage_save_sys_settings();
+
+ tuya_ble_connect_status_set(BONDING_CONN);
+
+ tuya_ble_adv_change();
+ TUYA_BLE_LOG_INFO("PAIR_REQ ok-%d", tuya_ble_current_para.sys_settings.bound_flag);
+
+ event.evt = TUYA_BLE_CB_EVT_UPDATE_LOGIN_KEY_VID;
+ event.device_login_key_vid_data.login_key_len = LOGIN_KEY_LEN;
+ event.device_login_key_vid_data.vid_len = DEVICE_VIRTUAL_ID_LEN;
+
+#if (TUYA_BLE_PROTOCOL_VERSION_LOW>=1)
+ if (TUYA_BLE_BEACON_KEY_ENABLE) {
+ event.device_login_key_vid_data.beacon_key_len = BEACON_KEY_LEN;
+ memcpy(event.device_login_key_vid_data.beacon_key, tuya_ble_current_para.sys_settings.beacon_key, BEACON_KEY_LEN);
+ }
+#endif
+
+ memcpy(event.device_login_key_vid_data.login_key, tuya_ble_current_para.sys_settings.login_key, LOGIN_KEY_LEN);
+ memcpy(event.device_login_key_vid_data.vid, tuya_ble_current_para.sys_settings.device_virtual_id, DEVICE_VIRTUAL_ID_LEN);
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya ble send cb event failed.");
+ } else {
+ TUYA_BLE_LOG_DEBUG("tuya ble send cb event succeed.");
+ }
+
+
+#else
+ tuya_ble_connect_status_set(UNBONDING_CONN);
+#endif
+ p_buf[0] = 0x00;
+ }
+
+ event.evt = TUYA_BLE_CB_EVT_CONNECTE_STATUS;
+ event.connect_status = tuya_ble_connect_status_get();
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya ble send cb event failed.");
+ } else {
+ TUYA_BLE_LOG_INFO("tuya ble send cb event succeed.");
+ }
+
+
+ } else {
+ TUYA_BLE_LOG_ERROR("PAIR_REQ device id not match!"); //ID not match ,and disconnected.
+ p_buf[0] = 0x01;
+
+ }
+
+
+pair_exit:
+ if (p_buf[0] == 0) {
+#if (TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+#else
+ encry_mode = recv_data[0];
+#endif
+ } else if (p_buf[0] == 1) {
+ encry_mode = recv_data[0];
+ } else if (p_buf[0] == 2) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+
+ }
+
+ tuya_ble_commData_send(PAIR_RESP, ack_sn, p_buf, 1, encry_mode);
+
+ if (encry_mode == ENCRYPTION_MODE_SESSION_KEY) {
+ if (TUYA_BLE_AUTO_REQUEST_TIME_CONFIGURE == 1) {
+ tuya_ble_commData_send(FRM_GET_UNIX_TIME_CHAR_MS_REQ, 0, NULL, 0, encry_mode);
+ TUYA_BLE_LOG_INFO("send FRM_GET_UNIX_TIME_CHAR_MS_REQ cmd to app.\n");
+ } else if (TUYA_BLE_AUTO_REQUEST_TIME_CONFIGURE == 2) {
+ tuya_ble_commData_send(FRM_GET_APP_LOCAL_TIME_REQ, 0, NULL, 0, encry_mode);
+ TUYA_BLE_LOG_INFO("send FRM_GET_APP_LOCAL_TIME_REQ cmd to app.\n");
+ } else {
+
+ }
+ }
+
+ if (p_buf[0] == 1) {
+ tuya_ble_gap_disconnect();
+ }
+
+}
+
+
+
+#endif //TUYA_BLE_PROTOCOL_VERSION_HIGN==4
+
+
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN==3)
+
+#if (TUYA_BLE_PROTOCOL_VERSION_LOW>=2)
+
+static void tuya_ble_handle_dev_info_req(uint8_t *recv_data, uint16_t recv_len)
+{
+ uint8_t p_buf[90];
+ uint8_t payload_len = 0;
+ uint32_t ack_sn = 0;
+ uint8_t encry_mode = 0;
+ uint32_t version_temp_s, version_temp_h;
+
+ memset(p_buf, 0, sizeof(p_buf));
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ TUYA_BLE_LOG_DEBUG("get device infor-%d", tuya_ble_current_para.sys_settings.bound_flag);
+
+ send_packet_data_len = 20;
+
+ tuya_ble_rand_generator(tuya_ble_pair_rand, 6);
+ tuya_ble_pair_rand_valid = 1;
+
+ if (TUYA_BLE_DEVICE_REGISTER_FROM_BLE) {
+ version_temp_s = tuya_ble_firmware_version;
+ version_temp_h = tuya_ble_hardware_version;
+ p_buf[4] = 0x00;
+ } else {
+ version_temp_s = tuya_ble_firmware_version >> 8;
+ version_temp_h = tuya_ble_hardware_version >> 8;
+ p_buf[4] = 0x05;
+ }
+ p_buf[0] = (version_temp_s >> 8) & 0xff;
+ p_buf[1] = (version_temp_s & 0xff);
+ p_buf[2] = TUYA_BLE_PROTOCOL_VERSION_HIGN;
+ p_buf[3] = TUYA_BLE_PROTOCOL_VERSION_LOW;
+ if (TUYA_BLE_ADVANCED_ENCRYPTION_DEVICE == 1) {
+ p_buf[4] |= 0x02;
+ }
+
+ p_buf[5] = tuya_ble_current_para.sys_settings.bound_flag;
+ memcpy(&p_buf[6], tuya_ble_pair_rand, 6);
+ p_buf[12] = (version_temp_h >> 8) & 0xff;
+ p_buf[13] = (version_temp_h & 0xff);
+
+ tuya_ble_register_key_generate(&p_buf[14], &tuya_ble_current_para);
+
+ p_buf[46] = (tuya_ble_firmware_version >> 16) & 0xff;
+ p_buf[47] = (tuya_ble_firmware_version >> 8) & 0xff;
+ p_buf[48] = (tuya_ble_firmware_version & 0xff);
+ p_buf[49] = (tuya_ble_hardware_version >> 16) & 0xff;
+ p_buf[50] = (tuya_ble_hardware_version >> 8) & 0xff;
+ p_buf[51] = (tuya_ble_hardware_version & 0xff);
+
+ p_buf[52] = TUYA_BLE_DEVICE_COMMUNICATION_ABILITY >> 8;
+ p_buf[53] = TUYA_BLE_DEVICE_COMMUNICATION_ABILITY; //communication ability
+
+ p_buf[54] = 0x00;
+
+ memcpy(&p_buf[55], tuya_ble_current_para.sys_settings.device_virtual_id, DEVICE_VIRTUAL_ID_LEN);
+
+ p_buf[77] = (tuya_ble_mcu_firmware_version >> 16) & 0xff;
+ p_buf[78] = (tuya_ble_mcu_firmware_version >> 8) & 0xff;
+ p_buf[79] = (tuya_ble_mcu_firmware_version & 0xff);
+ p_buf[80] = (tuya_ble_mcu_hardware_version >> 16) & 0xff;
+ p_buf[81] = (tuya_ble_mcu_hardware_version >> 8) & 0xff;
+ p_buf[82] = (tuya_ble_mcu_hardware_version & 0xff);
+
+ p_buf[83] = TUYA_BLE_WIFI_DEVICE_REGISTER_MODE;
+
+ payload_len = 84;
+
+ encry_mode = recv_data[0];
+
+ if (tuya_ble_commData_send(FRM_QRY_DEV_INFO_RESP, ack_sn, p_buf, payload_len, encry_mode) == 2) {
+ tuya_ble_pair_rand_clear();
+ }
+}
+
+#else //version <= 3.1 TUYA_BLE_PROTOCOL_VERSION_LOW<2
+
+static void tuya_ble_handle_dev_info_req(uint8_t *recv_data, uint16_t recv_len)
+{
+ uint8_t p_buf[90];
+ uint8_t payload_len = 0;
+ uint32_t ack_sn = 0;
+ uint8_t encry_mode = 0;
+ uint32_t version_temp_s, version_temp_h;
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ TUYA_BLE_LOG_DEBUG("get device infor-%d", tuya_ble_current_para.sys_settings.bound_flag);
+
+ send_packet_data_len = 20;
+
+ tuya_ble_rand_generator(tuya_ble_pair_rand, 6);
+ tuya_ble_pair_rand_valid = 1;
+
+ if (TUYA_BLE_DEVICE_REGISTER_FROM_BLE) {
+ version_temp_s = tuya_ble_firmware_version;
+ version_temp_h = tuya_ble_hardware_version;
+ p_buf[4] = 0x00;
+ } else {
+ version_temp_s = tuya_ble_firmware_version >> 8;
+ version_temp_h = tuya_ble_hardware_version >> 8;
+ p_buf[4] = 0x05;
+ }
+ p_buf[0] = (version_temp_s >> 8) & 0xff;
+ p_buf[1] = (version_temp_s & 0xff);
+ p_buf[2] = TUYA_BLE_PROTOCOL_VERSION_HIGN;
+ p_buf[3] = TUYA_BLE_PROTOCOL_VERSION_LOW;
+ if (TUYA_BLE_ADVANCED_ENCRYPTION_DEVICE == 1) {
+ p_buf[4] |= 0x02;
+ }
+
+ p_buf[5] = tuya_ble_current_para.sys_settings.bound_flag;
+ memcpy(&p_buf[6], tuya_ble_pair_rand, 6);
+ p_buf[12] = (version_temp_h >> 8) & 0xff;
+ p_buf[13] = (version_temp_h & 0xff);
+ memcpy(&p_buf[14], tuya_ble_current_para.auth_settings.auth_key, AUTH_KEY_LEN);
+
+ p_buf[46] = (tuya_ble_firmware_version >> 16) & 0xff;
+ p_buf[47] = (tuya_ble_firmware_version >> 8) & 0xff;
+ p_buf[48] = (tuya_ble_firmware_version & 0xff);
+ p_buf[49] = (tuya_ble_hardware_version >> 16) & 0xff;
+ p_buf[50] = (tuya_ble_hardware_version >> 8) & 0xff;
+ p_buf[51] = (tuya_ble_hardware_version & 0xff);
+
+ p_buf[52] = TUYA_BLE_DEVICE_COMMUNICATION_ABILITY >> 8;
+ p_buf[53] = TUYA_BLE_DEVICE_COMMUNICATION_ABILITY; //communication ability
+
+ p_buf[54] = 0x00;
+
+ memcpy(&p_buf[55], tuya_ble_current_para.sys_settings.device_virtual_id, DEVICE_VIRTUAL_ID_LEN);
+
+ p_buf[77] = (tuya_ble_mcu_firmware_version >> 16) & 0xff;
+ p_buf[78] = (tuya_ble_mcu_firmware_version >> 8) & 0xff;
+ p_buf[79] = (tuya_ble_mcu_firmware_version & 0xff);
+ p_buf[80] = (tuya_ble_mcu_hardware_version >> 16) & 0xff;
+ p_buf[81] = (tuya_ble_mcu_hardware_version >> 8) & 0xff;
+ p_buf[82] = (tuya_ble_mcu_hardware_version & 0xff);
+
+ payload_len = 83;
+
+ encry_mode = recv_data[0];
+
+ if (tuya_ble_commData_send(FRM_QRY_DEV_INFO_RESP, ack_sn, p_buf, payload_len, encry_mode) == 2) {
+ tuya_ble_pair_rand_clear();
+ }
+}
+
+#endif
+
+extern void tuya_ble_connect_monitor_timer_stop(void);
+static void tuya_ble_handle_pair_req(uint8_t *recv_data, uint16_t recv_len)
+{
+ uint8_t p_buf[1];
+ uint8_t encry_mode = 0;
+ uint32_t ack_sn = 0;
+ tuya_ble_cb_evt_param_t event;
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ if (0 == memcmp(&recv_data[13], tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN)) {
+ tuya_ble_connect_monitor_timer_stop();
+
+ if (1 == tuya_ble_get_adv_connect_request_bit_status()) {
+ TUYA_BLE_LOG_INFO("ble adv data update,because the last broadcast data connection request flag was set!");
+ tuya_ble_adv_change();
+ }
+
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) {
+ TUYA_BLE_LOG_INFO("PAIR_REQ already bound!");
+ p_buf[0] = 2;
+ tuya_ble_connect_status_set(BONDING_CONN);
+ } else {
+#if (TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+ memcpy(tuya_ble_current_para.sys_settings.login_key, recv_data + 29, LOGIN_KEY_LEN);
+ memcpy(tuya_ble_current_para.sys_settings.device_virtual_id, recv_data + 29 + LOGIN_KEY_LEN, DEVICE_VIRTUAL_ID_LEN);
+ tuya_ble_current_para.sys_settings.bound_flag = 1;
+
+ tuya_ble_storage_save_sys_settings();
+
+ tuya_ble_connect_status_set(BONDING_CONN);
+
+ tuya_ble_adv_change();
+ TUYA_BLE_LOG_INFO("PAIR_REQ ok-%d", tuya_ble_current_para.sys_settings.bound_flag);
+
+ event.evt = TUYA_BLE_CB_EVT_UPDATE_LOGIN_KEY_VID;
+ event.device_login_key_vid_data.login_key_len = LOGIN_KEY_LEN;
+ event.device_login_key_vid_data.vid_len = DEVICE_VIRTUAL_ID_LEN;
+ memcpy(event.device_login_key_vid_data.login_key, tuya_ble_current_para.sys_settings.login_key, LOGIN_KEY_LEN);
+ memcpy(event.device_login_key_vid_data.vid, tuya_ble_current_para.sys_settings.device_virtual_id, DEVICE_VIRTUAL_ID_LEN);
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya ble send cb event failed.");
+ } else {
+ TUYA_BLE_LOG_DEBUG("tuya ble send cb event succeed.");
+ }
+
+
+#else //TUYA_BLE_DEVICE_REGISTER_FROM_BLE
+ tuya_ble_connect_status_set(UNBONDING_CONN);
+#endif
+ p_buf[0] = 0x00;
+ }
+
+
+ event.evt = TUYA_BLE_CB_EVT_CONNECTE_STATUS;
+ event.connect_status = tuya_ble_connect_status_get();
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya ble send cb event failed.");
+ } else {
+ TUYA_BLE_LOG_INFO("tuya ble send cb event succeed.");
+ }
+
+
+ } else {
+ TUYA_BLE_LOG_ERROR("PAIR_REQ device id not match!"); //ID not match ,and disconnected.
+ p_buf[0] = 0x01;
+
+ }
+
+
+ if (p_buf[0] == 0) {
+#if (TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+#else
+ encry_mode = recv_data[0];
+#endif
+ } else if (p_buf[0] == 1) {
+ encry_mode = recv_data[0];
+ } else if (p_buf[0] == 2) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+
+ }
+
+ tuya_ble_commData_send(PAIR_RESP, ack_sn, p_buf, 1, encry_mode);
+
+ if (encry_mode == ENCRYPTION_MODE_SESSION_KEY) {
+ tuya_ble_commData_send(FRM_GET_UNIX_TIME_CHAR_MS_REQ, 0, NULL, 0, encry_mode);
+ TUYA_BLE_LOG_INFO("send FRM_GET_UNIX_TIME_CHAR_MS_REQ cmd to app.\n");
+ }
+
+ if (p_buf[0] == 1) {
+ tuya_ble_gap_disconnect();
+ }
+
+}
+
+#endif
+
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN==2)
+
+static void tuya_ble_handle_dev_info_req(uint8_t *recv_data, uint16_t recv_len)
+{
+ uint8_t p_buf[70];
+ uint8_t payload_len = 0;
+ uint32_t ack_sn = 0;
+ uint8_t encry_mode = 0;
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ TUYA_BLE_LOG_INFO("get device infor-%d", tuya_ble_current_para.sys_settings.bound_flag);
+
+ send_packet_data_len = 20;
+
+ tuya_ble_rand_generator(tuya_ble_pair_rand, 6);
+ tuya_ble_pair_rand_valid = 1;
+
+
+ p_buf[0] = (tuya_ble_firmware_version >> 8) & 0xff;
+ p_buf[1] = (tuya_ble_firmware_version & 0xff);
+ p_buf[2] = TUYA_BLE_PROTOCOL_VERSION_HIGN;
+ p_buf[3] = TUYA_BLE_PROTOCOL_VERSION_LOW;
+ if (TUYA_BLE_ADVANCED_ENCRYPTION_DEVICE == 1) {
+ p_buf[4] = 0x02;
+ } else {
+ p_buf[4] = 0x00;
+ }
+ p_buf[5] = tuya_ble_current_para.sys_settings.bound_flag;
+ memcpy(&p_buf[6], tuya_ble_pair_rand, 6);
+ p_buf[12] = (tuya_ble_hardware_version >> 8) & 0xff;
+ p_buf[13] = (tuya_ble_hardware_version & 0xff);
+ memcpy(&p_buf[14], tuya_ble_current_para.auth_settings.auth_key, AUTH_KEY_LEN);
+
+ payload_len = 46;
+
+ encry_mode = recv_data[0];
+
+ if (tuya_ble_commData_send(FRM_QRY_DEV_INFO_RESP, ack_sn, p_buf, payload_len, encry_mode) == 2) {
+ tuya_ble_pair_rand_clear();
+ }
+
+}
+
+extern void tuya_ble_connect_monitor_timer_stop(void);
+static void tuya_ble_handle_pair_req(uint8_t *recv_data, uint16_t recv_len)
+{
+ uint8_t p_buf[1];
+ uint8_t encry_mode = 0;
+ uint32_t ack_sn = 0;
+ tuya_ble_cb_evt_param_t event;
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ if (0 == memcmp(&recv_data[13], tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN)) {
+ tuya_ble_connect_monitor_timer_stop();
+
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) {
+ TUYA_BLE_LOG_ERROR("PAIR_REQ already bound!");
+ p_buf[0] = 2;
+ } else {
+
+#if (TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+
+ memcpy(tuya_ble_current_para.sys_settings.login_key, recv_data + 29, LOGIN_KEY_LEN);
+ tuya_ble_current_para.sys_settings.bound_flag = 1;
+ tuya_ble_storage_save_sys_settings();
+ tuya_ble_adv_change();
+ TUYA_BLE_LOG_INFO("PAIR_REQ ok-%d", tuya_ble_current_para.sys_settings.bound_flag);
+
+ event.evt = TUYA_BLE_CB_EVT_UPDATE_LOGIN_KEY_VID;
+ event.device_login_key_vid_data.login_key_len = LOGIN_KEY_LEN;
+ event.device_login_key_vid_data.vid_len = 0;
+ memcpy(event.device_login_key_vid_data.login_key, tuya_ble_current_para.sys_settings.login_key, LOGIN_KEY_LEN);
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya ble send cb event failed.");
+ } else {
+ TUYA_BLE_LOG_DEBUG("tuya ble send cb event succeed.");
+ }
+
+#else
+ tuya_ble_connect_status_set(UNBONDING_CONN);
+#endif
+ p_buf[0] = 0x00;
+
+ }
+
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) {
+ tuya_ble_connect_status_set(BONDING_CONN);
+ }
+
+ event.evt = TUYA_BLE_CB_EVT_CONNECTE_STATUS;
+ event.connect_status = tuya_ble_connect_status_get();
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya ble send cb event failed.");
+ } else {
+ TUYA_BLE_LOG_INFO("tuya ble send cb event succeed.");
+ }
+
+
+ } else {
+ TUYA_BLE_LOG_ERROR("PAIR_REQ device id not match!"); //ID not match ,and disconnected.
+ p_buf[0] = 0x01;
+
+ }
+
+
+ if (p_buf[0] == 0) {
+#if (TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+#else
+ encry_mode = recv_data[0];
+#endif
+ } else if (p_buf[0] == 1) {
+ encry_mode = recv_data[0];
+ } else if (p_buf[0] == 2) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+
+ }
+
+ tuya_ble_commData_send(PAIR_RESP, ack_sn, p_buf, 1, encry_mode);
+
+ if (encry_mode == ENCRYPTION_MODE_SESSION_KEY) {
+ tuya_ble_commData_send(FRM_GET_UNIX_TIME_CHAR_MS_REQ, 0, NULL, 0, encry_mode);
+ TUYA_BLE_LOG_INFO("send FRM_GET_UNIX_TIME_CHAR_MS_REQ cmd to app.");
+ }
+
+ if (p_buf[0] == 1) {
+ tuya_ble_gap_disconnect();
+ }
+
+}
+
+#endif
+
+static void tuya_ble_handle_net_config_info_req(uint8_t *recv_data, uint16_t recv_len)
+{
+ uint8_t p_buf[1];
+ uint8_t encry_mode = 0;
+ uint32_t ack_sn = 0;
+ tuya_ble_cb_evt_param_t event;
+ uint16_t data_len;
+
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+ data_len = (recv_data[11] << 8) + recv_data[12];
+ encry_mode = recv_data[0];
+
+ event.evt = TUYA_BLE_CB_EVT_NETWORK_INFO;
+ uint8_t *ble_cb_evt_buffer = (uint8_t *)tuya_ble_malloc(data_len);
+ if (ble_cb_evt_buffer == NULL) {
+ p_buf[0] = 1;
+ TUYA_BLE_LOG_ERROR("ble_cb_evt_buffer malloc failed.");
+ tuya_ble_commData_send(FRM_NET_CONFIG_INFO_RESP, ack_sn, p_buf, 1, encry_mode);
+ return;
+ } else {
+ memset(ble_cb_evt_buffer, 0, data_len);
+ memcpy(ble_cb_evt_buffer, &recv_data[13], data_len);
+ }
+ event.network_data.data_len = data_len;
+ event.network_data.p_data = ble_cb_evt_buffer;
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ tuya_ble_free(ble_cb_evt_buffer);
+ TUYA_BLE_LOG_ERROR("tuya ble send cb event failed.");
+ p_buf[0] = 1;
+ tuya_ble_commData_send(FRM_NET_CONFIG_INFO_RESP, ack_sn, p_buf, 1, encry_mode);
+ return;
+ } else {
+ p_buf[0] = 0;
+ }
+
+ tuya_ble_commData_send(FRM_NET_CONFIG_INFO_RESP, ack_sn, p_buf, 1, encry_mode);
+
+
+}
+
+
+static void tuya_ble_handle_ble_passthrough_data_req(uint8_t *recv_data, uint16_t recv_len)
+{
+ tuya_ble_cb_evt_param_t event;
+ uint16_t data_len;
+
+ data_len = (recv_data[11] << 8) + recv_data[12];
+
+ event.evt = TUYA_BLE_CB_EVT_DATA_PASSTHROUGH;
+
+ uint8_t *ble_cb_evt_buffer = (uint8_t *)tuya_ble_malloc(data_len);
+ if (ble_cb_evt_buffer == NULL) {
+ TUYA_BLE_LOG_ERROR("ble_cb_evt_buffer malloc failed.");
+ return;
+ } else {
+ memcpy(ble_cb_evt_buffer, &recv_data[13], data_len);
+ }
+ event.ble_passthrough_data.data_len = data_len;
+ event.ble_passthrough_data.p_data = ble_cb_evt_buffer;
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ tuya_ble_free(ble_cb_evt_buffer);
+ TUYA_BLE_LOG_ERROR("tuya ble send cb event failed.");
+ } else {
+
+ }
+
+}
+
+
+static void tuya_ble_handle_ble_factory_test_req(uint8_t *recv_data, uint16_t recv_len)
+{
+ uint16_t data_len;
+ uint32_t ack_sn;
+ uint8_t sum;
+ uint8_t encry_mode;
+
+ data_len = (recv_data[11] << 8) + recv_data[12];
+
+ if (data_len < 7) {
+ return;
+ }
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ encry_mode = recv_data[0];
+
+ if ((recv_data[13] == 0x66) && (recv_data[14] == 0xAA)) {
+ sum = tuya_ble_check_sum(&recv_data[13], data_len - 1);
+ if (sum == recv_data[13 + data_len - 1]) {
+ tuya_ble_app_production_test_process(1, &recv_data[13], data_len);
+ }
+ }
+
+}
+
+
+static void tuya_ble_handle_ota_req(uint16_t cmd, uint8_t *recv_data, uint32_t recv_len)
+{
+ tuya_ble_cb_evt_param_t event;
+ uint16_t data_len;
+ tuya_ble_ota_data_type_t cmd_type;
+
+ data_len = (recv_data[11] << 8) + recv_data[12];
+
+ if (data_len == 0) {
+ return;
+ }
+
+ if (recv_data[13] == 1) { //extern mcu ota
+ tuya_ble_uart_common_mcu_ota_data_from_ble_handler(cmd, &recv_data[14], data_len - 1);
+ } else if (recv_data[13] == 0) {
+ event.evt = TUYA_BLE_CB_EVT_OTA_DATA;
+
+ uint8_t *ble_cb_evt_buffer = (uint8_t *)tuya_ble_malloc(data_len);
+ if (ble_cb_evt_buffer == NULL) {
+ TUYA_BLE_LOG_ERROR("ble_cb_evt_buffer malloc failed.");
+ return;
+ } else {
+ memcpy(ble_cb_evt_buffer, &recv_data[13], data_len);
+ }
+
+ switch (cmd) {
+ case FRM_OTA_START_REQ:
+ cmd_type = TUYA_BLE_OTA_REQ;
+ break;
+ case FRM_OTA_FILE_INFOR_REQ:
+ cmd_type = TUYA_BLE_OTA_FILE_INFO;
+ break;
+ case FRM_OTA_FILE_OFFSET_REQ:
+ cmd_type = TUYA_BLE_OTA_FILE_OFFSET_REQ;
+ break;
+ case FRM_OTA_DATA_REQ:
+ cmd_type = TUYA_BLE_OTA_DATA;
+ break;
+ case FRM_OTA_END_REQ:
+ cmd_type = TUYA_BLE_OTA_END;
+ break;
+ default:
+ cmd_type = TUYA_BLE_OTA_UNKONWN;
+ break;
+ }
+
+ event.ota_data.type = cmd_type;
+ event.ota_data.data_len = data_len;
+ event.ota_data.p_data = ble_cb_evt_buffer;
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ tuya_ble_free(ble_cb_evt_buffer);
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_ota_req-tuya ble send cb event failed.");
+ } else {
+
+ }
+ } else {
+
+ }
+}
+
+static char current_timems_string[14] = "000000000000";
+
+static void tuya_ble_handle_unix_time_char_ms_resp(uint8_t *recv_data, uint16_t recv_len)
+{
+ int16_t zone_temp = 0;
+ uint64_t time_stamp_ms;
+ uint32_t time_stamp;
+ tuya_ble_cb_evt_param_t event;
+
+ memset(&event, 0, sizeof(tuya_ble_cb_evt_param_t));
+
+ if (recv_len < 30) {
+ TUYA_BLE_LOG_ERROR("received unix time char cmd data length error!");
+ return;
+ }
+
+ if (!buffer_value_is_all_x(&recv_data[13], 13, 0)) {
+ memcpy(current_timems_string, &recv_data[13], 13);
+ zone_temp = (int16_t)((recv_data[26] << 8) | recv_data[27]);
+ time_stamp_ms = atoll(current_timems_string);
+ TUYA_BLE_LOG_INFO("received unix time_zone = %d\n", zone_temp);
+ time_stamp = time_stamp_ms / 1000;
+ if (time_stamp_ms % 1000 >= 500) {
+ time_stamp += 1;
+ }
+
+ tuya_ble_rtc_set_timestamp(time_stamp, zone_temp);
+
+ event.evt = TUYA_BLE_CB_EVT_TIME_STAMP;
+
+ memcpy(event.timestamp_data.timestamp_string, current_timems_string, 13);
+ event.timestamp_data.time_zone = zone_temp;
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_unix_time_char_ms_resp-tuya ble send cb event failed.");
+ }
+
+ }
+
+}
+
+
+static void tuya_ble_handle_unix_time_date_resp(uint8_t *recv_data, uint16_t recv_len)
+{
+ int16_t zone_temp = 0;
+ uint32_t time_stamp;
+ tuya_ble_cb_evt_param_t event;
+ tuya_ble_time_struct_data_t time_temp;
+
+ if (recv_len < 24) {
+ TUYA_BLE_LOG_ERROR("received unix time date cmd data length error!");
+ return;
+ }
+
+ memset(&event, 0, sizeof(tuya_ble_cb_evt_param_t));
+
+ if (!buffer_value_is_all_x(&recv_data[13], 7, 0)) {
+ time_temp.nYear = 2000 + recv_data[13];
+ time_temp.nMonth = recv_data[14];
+ time_temp.nDay = recv_data[15];
+ time_temp.nHour = recv_data[16];
+ time_temp.nMin = recv_data[17];
+ time_temp.nSec = recv_data[18];
+ time_temp.DayIndex = recv_data[19];
+
+ time_stamp = tuya_ble_mytime_2_utc_sec(&time_temp, false);
+
+ zone_temp = (int16_t)((recv_data[20] << 8) | recv_data[21]);
+
+ TUYA_BLE_LOG_INFO("received unix time_zone = %d", zone_temp);
+
+ tuya_ble_rtc_set_timestamp(time_stamp, zone_temp);
+
+ event.evt = TUYA_BLE_CB_EVT_TIME_NORMAL;
+ event.time_normal_data.nYear = recv_data[13];
+ event.time_normal_data.nMonth = recv_data[14];
+ event.time_normal_data.nDay = recv_data[15];
+ event.time_normal_data.nHour = recv_data[16];
+ event.time_normal_data.nMin = recv_data[17];
+ event.time_normal_data.nSec = recv_data[18];
+ event.time_normal_data.DayIndex = recv_data[19];
+ event.time_normal_data.time_zone = zone_temp;
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_unix_time_date_resp-tuya ble send cb event failed.");
+ }
+
+ }
+
+}
+
+static void tuya_ble_handle_app_local_time_data_resp(uint8_t *recv_data, uint16_t recv_len)
+{
+ int16_t zone_temp = 0;
+ uint32_t local_time, time_stamp;
+ tuya_ble_cb_evt_param_t event;
+ tuya_ble_time_struct_data_t time_temp;
+
+ if (recv_len < 24) {
+ TUYA_BLE_LOG_ERROR("received app local time date cmd data length error!");
+ return;
+ }
+
+ memset(&event, 0, sizeof(tuya_ble_cb_evt_param_t));
+
+ if (!buffer_value_is_all_x(&recv_data[13], 7, 0)) {
+ time_temp.nYear = 2000 + recv_data[13];
+ time_temp.nMonth = recv_data[14];
+ time_temp.nDay = recv_data[15];
+ time_temp.nHour = recv_data[16];
+ time_temp.nMin = recv_data[17];
+ time_temp.nSec = recv_data[18];
+ time_temp.DayIndex = recv_data[19];
+
+ local_time = tuya_ble_mytime_2_utc_sec(&time_temp, false);
+
+ zone_temp = (int16_t)((recv_data[20] << 8) | recv_data[21]);
+
+ TUYA_BLE_LOG_INFO("received app local time_zone = %d", zone_temp);
+
+ time_stamp = (local_time - zone_temp * 36); //!< Convert to unix timestamp
+ tuya_ble_rtc_set_timestamp(time_stamp, zone_temp);
+
+ event.evt = TUYA_BLE_CB_EVT_APP_LOCAL_TIME_NORMAL;
+ event.time_normal_data.nYear = recv_data[13];
+ event.time_normal_data.nMonth = recv_data[14];
+ event.time_normal_data.nDay = recv_data[15];
+ event.time_normal_data.nHour = recv_data[16];
+ event.time_normal_data.nMin = recv_data[17];
+ event.time_normal_data.nSec = recv_data[18];
+ event.time_normal_data.DayIndex = recv_data[19];
+ event.time_normal_data.time_zone = zone_temp;
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_app_local_time_date_resp-tuya ble send cb event failed.");
+ }
+
+ }
+}
+
+
+static void tuya_ble_handle_unix_time_with_dst_date_resp(uint8_t *recv_data, uint16_t recv_len)
+{
+ int16_t zone_temp = 0;
+ uint32_t time_stamp;
+ uint8_t years_of_dst;
+ uint16_t dst_content_len;
+ tuya_ble_cb_evt_param_t event;
+ char current_time_string[11] = "0000000000";
+ uint8_t *ble_cb_evt_buffer = NULL;
+
+ if (recv_len < 28) {
+ TUYA_BLE_LOG_ERROR("received extend unix time date cmd data length error!");
+ return;
+ }
+
+ memset(&event, 0, sizeof(tuya_ble_cb_evt_param_t));
+
+ if (!buffer_value_is_all_x(&recv_data[13], 10, 0)) {
+ memcpy(current_time_string, &recv_data[13], 10);
+ time_stamp = atol(current_time_string);
+
+ zone_temp = (int16_t)((recv_data[23] << 8) | recv_data[24]);
+ TUYA_BLE_LOG_INFO("received unix time_zone = %d\n", zone_temp);
+
+ tuya_ble_rtc_set_timestamp(time_stamp, zone_temp);
+
+ /* daylight saving time */
+ years_of_dst = recv_data[25];
+ dst_content_len = (years_of_dst * 20);
+ TUYA_BLE_LOG_INFO("received dst years= %d ", years_of_dst);
+ TUYA_BLE_LOG_HEXDUMP_INFO("dst data ", &recv_data[26], dst_content_len);
+
+ if (years_of_dst > 0) {
+ ble_cb_evt_buffer = (uint8_t *)tuya_ble_malloc(dst_content_len);
+ if (ble_cb_evt_buffer == NULL) {
+ TUYA_BLE_LOG_ERROR("ble_cb_evt_buffer malloc failed.");
+ return;
+ } else {
+ memcpy(ble_cb_evt_buffer, &recv_data[26], dst_content_len);
+ }
+ }
+
+ event.evt = TUYA_BLE_CB_EVT_TIME_STAMP_WITH_DST;
+ event.timestamp_with_dst_data.timestamp = time_stamp;
+ event.timestamp_with_dst_data.time_zone = zone_temp;
+ event.timestamp_with_dst_data.n_years_dst = years_of_dst;
+ event.timestamp_with_dst_data.p_data = ble_cb_evt_buffer;
+ event.timestamp_with_dst_data.data_len = dst_content_len;
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ if (years_of_dst > 0) {
+ tuya_ble_free(ble_cb_evt_buffer);
+ }
+
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_unix_time_with_dst_resp-tuya ble send cb event failed.");
+ }
+ }
+}
+
+static void tuya_ble_handle_dp_query_req(uint8_t *recv_data, uint16_t recv_len)
+{
+ uint8_t p_buf[1];
+ uint16_t dp_num = 0;
+ uint32_t ack_sn = 0;
+ tuya_ble_cb_evt_param_t event;
+ uint8_t *ble_cb_evt_buffer = NULL;
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ dp_num = (recv_data[11] << 8) | recv_data[12];
+
+ p_buf[0] = 0x00;
+
+ tuya_ble_commData_send(FRM_STATE_QUERY_RESP, ack_sn, p_buf, 1, ENCRYPTION_MODE_SESSION_KEY);
+
+ event.evt = TUYA_BLE_CB_EVT_DP_QUERY;
+
+ if (dp_num > 0) {
+ ble_cb_evt_buffer = (uint8_t *)tuya_ble_malloc(dp_num);
+ if (ble_cb_evt_buffer == NULL) {
+ TUYA_BLE_LOG_ERROR("ble_cb_evt_buffer malloc failed.");
+ return;
+ } else {
+ memcpy(ble_cb_evt_buffer, &recv_data[13], dp_num);
+ }
+ }
+ event.dp_query_data.p_data = ble_cb_evt_buffer;
+ event.dp_query_data.data_len = dp_num;
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_dp_query_req-tuya ble send cb event failed.");
+ if (dp_num > 0) {
+ tuya_ble_free(ble_cb_evt_buffer);
+ }
+ } else {
+
+ }
+}
+
+
+void tuya_ble_device_unbond(void)
+{
+
+ tuya_ble_gap_disconnect();
+ memset(tuya_ble_current_para.sys_settings.login_key, 0, LOGIN_KEY_LEN);
+ memset(tuya_ble_current_para.sys_settings.beacon_key, 0, BEACON_KEY_LEN);
+ tuya_ble_current_para.sys_settings.bound_flag = 0;
+ tuya_ble_storage_save_sys_settings();
+ tuya_ble_adv_change();
+ tuya_ble_connect_status_set(UNBONDING_UNCONN);
+ TUYA_BLE_LOG_INFO("tuya_ble_device_unbond current bound flag = %d", tuya_ble_current_para.sys_settings.bound_flag);
+}
+
+
+
+static void tuya_ble_handle_unbond_req(uint8_t *recv_data, uint16_t recv_len)
+{
+ uint8_t p_buf[1];
+ uint8_t encry_mode = 0;
+ uint32_t ack_sn = 0;
+ tuya_ble_cb_evt_param_t event;
+
+#if (TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+
+ p_buf[0] = 0;
+
+ tuya_ble_commData_send(FRM_UNBONDING_RESP, ack_sn, p_buf, 1, encry_mode);
+
+#if (TUYA_BLE_DEVICE_UNBIND_MODE)
+ tuya_ble_device_unbond();
+
+ event.evt = TUYA_BLE_CB_EVT_CONNECTE_STATUS;
+ event.connect_status = tuya_ble_connect_status_get();
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_unbond_req-tuya ble send cb event (connect status update) failed.");
+ } else {
+
+ }
+#else
+ tuya_ble_gap_disconnect();
+#endif
+
+#endif
+
+ event.evt = TUYA_BLE_CB_EVT_UNBOUND;
+ event.unbound_data.data = 0;
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_unbond_req-tuya ble send cb event (unbound req) failed.");
+ } else {
+
+ }
+
+}
+
+
+static void tuya_ble_handle_anomaly_unbond_req(uint8_t *recv_data, uint16_t recv_len)
+{
+ uint8_t p_buf[1];
+ uint8_t encry_mode = 0;
+ uint32_t ack_sn = 0;
+ tuya_ble_cb_evt_param_t event;
+
+#if (TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ encry_mode = ENCRYPTION_MODE_KEY_1;
+
+ p_buf[0] = 0;
+
+ tuya_ble_commData_send(FRM_ANOMALY_UNBONDING_RESP, ack_sn, p_buf, 1, encry_mode);
+ tuya_ble_device_unbond();
+
+ event.evt = TUYA_BLE_CB_EVT_CONNECTE_STATUS;
+ event.connect_status = tuya_ble_connect_status_get();
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_anomaly_unbond_req-tuya ble send cb event (connect status update) failed.");
+ } else {
+
+ }
+
+#endif
+
+ event.evt = TUYA_BLE_CB_EVT_ANOMALY_UNBOUND;
+ event.anomaly_unbound_data.data = 0;
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_anomaly_unbond_req-tuya ble send cb event (unbound req) failed.");
+ } else {
+
+ }
+
+}
+
+
+static void tuya_ble_handle_device_reset_req(uint8_t *recv_data, uint16_t recv_len)
+{
+ uint8_t p_buf[1];
+ uint8_t encry_mode = 0;
+ uint32_t ack_sn = 0;
+ tuya_ble_cb_evt_param_t event;
+
+#if (TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+
+ p_buf[0] = 0;
+
+ tuya_ble_commData_send(FRM_DEVICE_RESET_RESP, ack_sn, p_buf, 1, encry_mode);
+
+#if (TUYA_BLE_DEVICE_UNBIND_MODE)
+ memset(tuya_ble_current_para.sys_settings.device_virtual_id, 0, DEVICE_VIRTUAL_ID_LEN);
+ tuya_ble_device_unbond();
+
+ event.evt = TUYA_BLE_CB_EVT_CONNECTE_STATUS;
+ event.connect_status = tuya_ble_connect_status_get();
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_device_reset_req-tuya ble send cb event (connect status update) failed.");
+ } else {
+
+ }
+#else
+ tuya_ble_gap_disconnect();
+#endif
+
+#endif
+
+ event.evt = TUYA_BLE_CB_EVT_DEVICE_RESET;
+ event.device_reset_data.data = 0;
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_device_reset_req-tuya ble send cb event device reset req failed.");
+ } else {
+
+ }
+
+}
+
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN==4)
+
+static void tuya_ble_handle_dp_data_write_req(uint8_t *recv_data, uint16_t recv_len)
+{
+ mtp_ret ret;
+ klv_node_s *list = NULL;
+ uint8_t p_buf[6];
+ uint16_t data_len = 0;
+ uint32_t ack_sn = 0;
+ tuya_ble_cb_evt_param_t event;
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ data_len = (recv_data[11] << 8) | recv_data[12];
+
+ if ((data_len < 5) || (data_len > TUYA_BLE_RECEIVE_MAX_DP_DATA_LEN)) {
+ TUYA_BLE_LOG_ERROR("cmd dp write error,receive data len == %d", data_len);
+ if (data_len < 5) {
+ memcpy(&p_buf[0], &recv_data[13], data_len);
+ } else {
+ memcpy(&p_buf[0], &recv_data[13], 5);
+ }
+ p_buf[5] = 1;
+ tuya_ble_commData_send(FRM_DP_DATA_WRITE_RESP, ack_sn, p_buf, 6, ENCRYPTION_MODE_SESSION_KEY);
+ return;
+ } else if (recv_data[13] != 0) {
+ TUYA_BLE_LOG_ERROR("cmd dp write version not support");
+
+ memcpy(&p_buf[0], &recv_data[13], 5);
+
+ p_buf[5] = 1;
+ tuya_ble_commData_send(FRM_DP_DATA_WRITE_RESP, ack_sn, p_buf, 6, ENCRYPTION_MODE_SESSION_KEY);
+ return;
+ } else {
+
+ }
+
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("cmd_dp_write data : ", recv_data + 13, data_len);
+ memcpy(&p_buf[0], &recv_data[13], 5);
+ ret = data_2_klvlist(&recv_data[18], data_len - 5, &list, 1);
+ if (MTP_OK != ret) {
+ TUYA_BLE_LOG_ERROR("cmd rx fail-%d", ret);
+ p_buf[5] = 1;
+ tuya_ble_commData_send(FRM_DP_DATA_WRITE_RESP, ack_sn, p_buf, 6, ENCRYPTION_MODE_SESSION_KEY);
+ return;
+ }
+
+ free_klv_list(list);
+
+ event.evt = TUYA_BLE_CB_EVT_DP_DATA_RECEIVED;
+
+ uint8_t *ble_cb_evt_buffer = (uint8_t *)tuya_ble_malloc(data_len - 5);
+ if (ble_cb_evt_buffer == NULL) {
+ TUYA_BLE_LOG_ERROR("ble_cb_evt_buffer malloc failed.");
+ p_buf[5] = 0x01;
+ tuya_ble_commData_send(FRM_DP_DATA_WRITE_RESP, ack_sn, p_buf, 6, ENCRYPTION_MODE_SESSION_KEY);
+ return;
+ } else {
+ memcpy(ble_cb_evt_buffer, &recv_data[18], data_len - 5);
+ event.dp_received_data.sn = (recv_data[14] << 24) | (recv_data[15] << 16) | (recv_data[16] << 8) | recv_data[17];
+ event.dp_received_data.p_data = ble_cb_evt_buffer;
+ event.dp_received_data.data_len = data_len - 5;
+ }
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ tuya_ble_free(ble_cb_evt_buffer);
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_dp_write_req-tuya ble send cb event failed.");
+ p_buf[5] = 0x01;
+ tuya_ble_commData_send(FRM_DP_DATA_WRITE_RESP, ack_sn, p_buf, 6, ENCRYPTION_MODE_SESSION_KEY);
+ } else {
+ p_buf[5] = 0x00;
+ tuya_ble_commData_send(FRM_DP_DATA_WRITE_RESP, ack_sn, p_buf, 6, ENCRYPTION_MODE_SESSION_KEY);
+ }
+
+}
+
+static void tuya_ble_handle_dp_data_send_response(uint8_t *recv_data, uint16_t recv_len)
+{
+ tuya_ble_cb_evt_param_t event;
+ uint16_t data_len = recv_data[11] << 8 | recv_data[12];
+
+ if (data_len != 8) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_dp_data_send_response- invalid data len received.");
+ return;
+ }
+
+ event.evt = TUYA_BLE_CB_EVT_DP_DATA_SEND_RESPONSE;
+ event.dp_send_response_data.sn = recv_data[14] << 24 | recv_data[15] << 16 | recv_data[16] << 8 | recv_data[17];
+ event.dp_send_response_data.ack = ((recv_data[18] & 0x80) ? DP_SEND_WITHOUT_RESPONSE : DP_SEND_WITH_RESPONSE);
+ if ((recv_data[18] & 0x0F) == 1) {
+ event.dp_send_response_data.type = DP_SEND_TYPE_PASSIVE;
+ } else if ((recv_data[18] & 0x0F) == 0) {
+ event.dp_send_response_data.type = DP_SEND_TYPE_ACTIVE;
+ } else {
+ return;
+ }
+
+ if (recv_data[19] > 3) {
+ return;
+ }
+ event.dp_send_response_data.mode = recv_data[19];
+ event.dp_send_response_data.status = recv_data[20];
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_dp_data_send_response-tuya ble send cb event failed.");
+ } else {
+
+ }
+}
+
+static void tuya_ble_handle_dp_data_with_time_send_response(uint8_t *recv_data, uint16_t recv_len)
+{
+ tuya_ble_cb_evt_param_t event;
+ uint16_t data_len = recv_data[11] << 8 | recv_data[12];
+
+ if (data_len != 8) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_dp_data_with_time_send_response- invalid data len received.");
+ return;
+ }
+
+ event.evt = TUYA_BLE_CB_EVT_DP_DATA_WITH_TIME_SEND_RESPONSE;
+ event.dp_with_time_send_response_data.sn = recv_data[14] << 24 | recv_data[15] << 16 | recv_data[16] << 8 | recv_data[17];
+ event.dp_with_time_send_response_data.ack = ((recv_data[18] & 0x80) ? DP_SEND_WITHOUT_RESPONSE : DP_SEND_WITH_RESPONSE);
+ if ((recv_data[18] & 0x0F) == 1) {
+ event.dp_with_time_send_response_data.type = DP_SEND_TYPE_PASSIVE;
+ } else if ((recv_data[18] & 0x0F) == 0) {
+ event.dp_with_time_send_response_data.type = DP_SEND_TYPE_ACTIVE;
+ } else {
+ return;
+ }
+
+ if (recv_data[19] > 3) {
+ return;
+ }
+ event.dp_with_time_send_response_data.mode = recv_data[19];
+ event.dp_with_time_send_response_data.status = recv_data[20];
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_dp_data_with_time_send_response-tuya ble send cb event failed.");
+ } else {
+
+ }
+}
+
+#else //(TUYA_BLE_PROTOCOL_VERSION_HIGN<4)
+
+static void tuya_ble_handle_dp_write_req(uint8_t *recv_data, uint16_t recv_len)
+{
+ mtp_ret ret;
+ klv_node_s *list = NULL;
+ uint8_t p_buf[1];
+ uint16_t data_len = 0;
+ uint32_t ack_sn = 0;
+ tuya_ble_cb_evt_param_t event;
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ data_len = (recv_data[11] << 8) | recv_data[12];
+
+ if ((data_len == 0) || (data_len > TUYA_BLE_RECEIVE_MAX_DP_DATA_LEN)) {
+ TUYA_BLE_LOG_ERROR("cmd dp write receive data len == %d", data_len);
+ p_buf[0] = 0x01;
+ tuya_ble_commData_send(FRM_CMD_RESP, ack_sn, p_buf, 1, ENCRYPTION_MODE_SESSION_KEY);
+ return;
+ }
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("cmd_dp_write data : ", recv_data + 13, data_len);
+ ret = data_2_klvlist(&recv_data[13], data_len, &list, 0);
+ if (MTP_OK != ret) {
+ TUYA_BLE_LOG_ERROR("cmd rx fail-%d", ret);
+ p_buf[0] = 0x01;
+ tuya_ble_commData_send(FRM_CMD_RESP, ack_sn, p_buf, 1, ENCRYPTION_MODE_SESSION_KEY);
+ return;
+ }
+
+ free_klv_list(list);
+ p_buf[0] = 0x00;
+
+ tuya_ble_commData_send(FRM_CMD_RESP, ack_sn, p_buf, 1, ENCRYPTION_MODE_SESSION_KEY);
+
+ event.evt = TUYA_BLE_CB_EVT_DP_WRITE;
+
+ uint8_t *ble_cb_evt_buffer = (uint8_t *)tuya_ble_malloc(data_len);
+ if (ble_cb_evt_buffer == NULL) {
+ TUYA_BLE_LOG_ERROR("ble_cb_evt_buffer malloc failed.");
+ return;
+ } else {
+ memcpy(ble_cb_evt_buffer, &recv_data[13], data_len);
+ }
+ event.dp_write_data.p_data = ble_cb_evt_buffer;
+ event.dp_write_data.data_len = data_len;
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ tuya_ble_free(ble_cb_evt_buffer);
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_dp_write_req-tuya ble send cb event failed.");
+ } else {
+
+ }
+
+}
+
+static void tuya_ble_handle_dp_data_report_res(uint8_t *recv_data, uint16_t recv_len)
+{
+ tuya_ble_cb_evt_param_t event;
+
+ event.evt = TUYA_BLE_CB_EVT_DP_DATA_REPORT_RESPONSE;
+ event.dp_response_data.status = recv_data[13];
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_dp_data_report_res-tuya ble send cb event failed.");
+ } else {
+
+ }
+}
+
+static void tuya_ble_handle_dp_data_with_time_report_res(uint8_t *recv_data, uint16_t recv_len)
+{
+ tuya_ble_cb_evt_param_t event;
+
+ event.evt = TUYA_BLE_CB_EVT_DP_DATA_WTTH_TIME_REPORT_RESPONSE;
+ event.dp_response_data.status = recv_data[13];
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_dp_data_report_res-tuya ble send cb event failed.");
+ } else {
+
+ }
+}
+
+static void tuya_ble_handle_dp_data_with_flag_report_res(uint8_t *recv_data, uint16_t recv_len)
+{
+ tuya_ble_cb_evt_param_t event;
+ uint16_t data_len = recv_data[11] << 8 | recv_data[12];
+
+ if (data_len != 4) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_dp_data_with_flag_report_res- invalid data len received.");
+ return;
+ }
+
+ event.evt = TUYA_BLE_CB_EVT_DP_DATA_WITH_FLAG_REPORT_RESPONSE;
+ event.dp_with_flag_response_data.sn = recv_data[13] << 8 | recv_data[14];
+ event.dp_with_flag_response_data.mode = recv_data[15];
+ event.dp_with_flag_response_data.status = recv_data[16];
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_dp_data_with_flag_report_res-tuya ble send cb event failed.");
+ } else {
+
+ }
+}
+
+static void tuya_ble_handle_dp_data_with_flag_and_time_report_res(uint8_t *recv_data, uint16_t recv_len)
+{
+ tuya_ble_cb_evt_param_t event;
+ uint16_t data_len = recv_data[11] << 8 | recv_data[12];
+
+ if (data_len != 4) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_dp_data_with_flag_and_time_report_res- invalid data len received.");
+ return;
+ }
+
+ event.evt = TUYA_BLE_CB_EVT_DP_DATA_WITH_FLAG_AND_TIME_REPORT_RESPONSE;
+ event.dp_with_flag_and_time_response_data.sn = recv_data[13] << 8 | recv_data[14];
+ event.dp_with_flag_and_time_response_data.mode = recv_data[15];
+ event.dp_with_flag_and_time_response_data.status = recv_data[16];
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_dp_data_with_flag_and_time_report_res-tuya ble send cb event failed.");
+ } else {
+
+ }
+}
+
+#endif
+
+
+void tuya_ble_evt_process(uint16_t cmd, uint8_t *recv_data, uint32_t recv_len)
+{
+ printf("process cmd = 0x%x", cmd);
+ switch (cmd) {
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN==4)
+
+ case FRM_DP_DATA_WRITE_REQ:
+ tuya_ble_handle_dp_data_write_req(recv_data, recv_len);
+ break;
+ case FRM_DP_DATA_SEND_RESP:
+ tuya_ble_handle_dp_data_send_response(recv_data, recv_len);
+ break;
+ case FRM_DP_DATA_WITH_TIME_SEND_RESP:
+ tuya_ble_handle_dp_data_with_time_send_response(recv_data, recv_len);
+ break;
+
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE==TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION)
+
+ case FRM_AUTHENTICATE_PHASE_1_REQ:
+ tuya_ble_handle_authenticate_phase1(recv_data, recv_len);
+ break;
+ case FRM_AUTHENTICATE_PHASE_2_REQ:
+ tuya_ble_handle_authenticate_phase2(recv_data, recv_len);
+ break;
+ case FRM_AUTHENTICATE_PHASE_3_REQ:
+ tuya_ble_handle_authenticate_phase3(recv_data, recv_len);
+ break;
+
+#endif
+
+#if (TUYA_BLE_FEATURE_WEATHER_ENABLE != 0)
+ case FRM_WEATHER_DATA_REQUEST_RESP:
+ tuya_ble_handle_weather_data_request_response(recv_data, recv_len);
+ break;
+ case FRM_WEATHER_DATA_RECEIVED:
+ tuya_ble_handle_weather_data_received(recv_data, recv_len);
+ break;
+#endif
+
+#else
+ case FRM_CMD_SEND:
+ tuya_ble_handle_dp_write_req(recv_data, recv_len);
+ break;
+ case FRM_STAT_REPORT_RESP:
+ tuya_ble_handle_dp_data_report_res(recv_data, recv_len);
+ break;
+ case FRM_DATA_WITH_FLAG_REPORT_RESP:
+ tuya_ble_handle_dp_data_with_flag_report_res(recv_data, recv_len);
+ break;
+ case FRM_STAT_WITH_TIME_REPORT_RESP:
+ tuya_ble_handle_dp_data_with_time_report_res(recv_data, recv_len);
+ break;
+ case FRM_DATA_WITH_FLAG_AND_TIME_REPORT_RESP:
+ tuya_ble_handle_dp_data_with_flag_and_time_report_res(recv_data, recv_len);
+ break;
+#endif
+ case FRM_STATE_QUERY:
+ tuya_ble_handle_dp_query_req(recv_data, recv_len);
+ break;
+ case FRM_QRY_DEV_INFO_REQ:
+ tuya_ble_handle_dev_info_req(recv_data, recv_len);
+ break;
+ case PAIR_REQ:
+ tuya_ble_handle_pair_req(recv_data, recv_len);
+ break;
+ case FRM_NET_CONFIG_INFO_REQ:
+ tuya_ble_handle_net_config_info_req(recv_data, recv_len);
+ break;
+ case FRM_DATA_PASSTHROUGH_REQ:
+ tuya_ble_handle_ble_passthrough_data_req(recv_data, recv_len);
+ break;
+ case FRM_BULK_DATA_READ_INFO_REQ:
+ case FRM_BULK_DATA_READ_DATA_REQ:
+ case FRM_BULK_DATA_ERASE_DATA_REQ:
+ TUYA_BLE_LOG_INFO("RECEIVED BULK DATA CMD:0x%02x DATA LEN:0x%02x", cmd, recv_len);
+ tuya_ble_handle_bulk_data_req(cmd, recv_data, recv_len);
+ break;
+ case FRM_OTA_START_REQ:
+ case FRM_OTA_FILE_INFOR_REQ:
+ case FRM_OTA_FILE_OFFSET_REQ:
+ case FRM_OTA_DATA_REQ:
+ case FRM_OTA_END_REQ:
+ TUYA_BLE_LOG_INFO("RECEIVED OTA CMD:0x%02x DATA LEN:0x%02x", cmd, recv_len);
+ tuya_ble_handle_ota_req(cmd, recv_data, recv_len);
+ break;
+ case FRM_GET_UNIX_TIME_CHAR_MS_RESP:
+ tuya_ble_handle_unix_time_char_ms_resp(recv_data, recv_len);
+ break;
+ case FRM_GET_UNIX_TIME_CHAR_DATE_RESP:
+ tuya_ble_handle_unix_time_date_resp(recv_data, recv_len);
+ break;
+ case FRM_GET_APP_LOCAL_TIME_RESP:
+ tuya_ble_handle_app_local_time_data_resp(recv_data, recv_len);
+ break;
+ case FRM_GET_UNIX_TIME_WITH_DST_RESP:
+ tuya_ble_handle_unix_time_with_dst_date_resp(recv_data, recv_len);
+ break;
+ case FRM_UNBONDING_REQ:
+ TUYA_BLE_LOG_INFO("RECEIVED FRM_UNBONDING_REQ");
+ tuya_ble_handle_unbond_req(recv_data, recv_len);
+ break;
+ case FRM_ANOMALY_UNBONDING_REQ:
+ TUYA_BLE_LOG_INFO("RECEIVED FRM_ANOMALY_UNBONDING_REQ");
+ tuya_ble_handle_anomaly_unbond_req(recv_data, recv_len);
+ break;
+ case FRM_DEVICE_RESET:
+ TUYA_BLE_LOG_INFO("RECEIVED FRM_DEVICE_RESET_REQ");
+ tuya_ble_handle_device_reset_req(recv_data, recv_len);
+ break;
+
+ case FRM_FACTORY_TEST_CMD:
+ tuya_ble_handle_ble_factory_test_req(recv_data, recv_len);
+ break;
+ default:
+ TUYA_BLE_LOG_WARNING("RECEIVED UNKNOWN BLE EVT CMD-0x%04x", cmd);
+ break;
+ }
+}
+
+uint8_t tuya_ble_commData_send(uint16_t cmd, uint32_t ack_sn, uint8_t *data, uint16_t len, uint8_t encryption_mode)
+{
+ mtp_ret ret;
+ uint16_t send_len = 0;
+ uint8_t *p_buf = NULL;
+ uint32_t err = 0;
+ int8_t retries_cnt = 0;
+ uint8_t iv[16];
+ uint16_t rand_value = 0, i = 0;
+ uint16_t crc16 = 0;
+ uint16_t en_len = 0;
+ uint32_t out_len = 0;
+ uint32_t temp_len = 0;
+ uint32_t package_number = 0;
+ uint16_t p_version = 0;
+ tuya_ble_r_air_send_packet air_send_packet;
+
+ memset(&air_send_packet, 0, sizeof(air_send_packet));
+
+ tuya_ble_connect_status_t currnet_connect_status = tuya_ble_connect_status_get();
+
+ if ((currnet_connect_status == BONDING_UNCONN) || (currnet_connect_status == UNBONDING_UNCONN)) {
+ TUYA_BLE_LOG_ERROR("tuya ble commData_send failed,because ble not in connect status.");
+ return 2;
+ }
+
+ if ((encryption_mode >= ENCRYPTION_MODE_MAX) || (len > TUYA_BLE_SEND_MAX_DATA_LEN)) {
+ return 1;
+ }
+
+
+ if (encryption_mode != ENCRYPTION_MODE_NONE) {
+ for (i = 0; i < 16; i += 2) {
+ rand_value = rand();
+ iv[i + 0] = rand_value >> 8;
+ iv[i + 1] = rand_value;
+ }
+ en_len = 17;
+ } else {
+ en_len = 1;
+ memset(iv, 0, sizeof(iv));
+ }
+
+ air_send_packet.send_len = 14 + len;
+
+ if (air_send_packet.send_len % 16 == 0) {
+ temp_len = 0;
+ } else {
+ temp_len = 16 - air_send_packet.send_len % 16;
+ }
+
+ temp_len += air_send_packet.send_len;
+
+ if (temp_len > (TUYA_BLE_AIR_FRAME_MAX - en_len)) {
+ TUYA_BLE_LOG_ERROR("The length of the send to ble exceeds the maximum length.");
+ air_send_packet.send_len = 0;
+ return 1;
+ }
+
+ air_send_packet.send_data = NULL;
+
+ air_send_packet.send_data = (uint8_t *)tuya_ble_malloc(temp_len); //must temp_len
+
+ if (air_send_packet.send_data == NULL) {
+ TUYA_BLE_LOG_ERROR("air_send_packet.send_data malloc failed return 3.");
+ air_send_packet.send_len = 0;
+ return 3;
+ } else {
+ memset(air_send_packet.send_data, 0, temp_len);
+ }
+
+
+ uint32_t send_sn = get_ble_send_sn();
+
+ air_send_packet.send_data[0] = send_sn >> 24;
+ air_send_packet.send_data[1] = send_sn >> 16;
+ air_send_packet.send_data[2] = send_sn >> 8;
+ air_send_packet.send_data[3] = send_sn;
+
+ air_send_packet.send_data[4] = ack_sn >> 24;
+ air_send_packet.send_data[5] = ack_sn >> 16;
+ air_send_packet.send_data[6] = ack_sn >> 8;
+ air_send_packet.send_data[7] = ack_sn;
+
+ air_send_packet.send_data[8] = cmd >> 8;
+ air_send_packet.send_data[9] = cmd;
+
+ air_send_packet.send_data[10] = len >> 8;
+ air_send_packet.send_data[11] = len;
+
+ memcpy(&air_send_packet.send_data[12], data, len);
+
+ crc16 = tuya_ble_crc16_compute(air_send_packet.send_data, 12 + len, NULL);
+
+ air_send_packet.send_data[12 + len] = crc16 >> 8;
+ air_send_packet.send_data[13 + len] = crc16;
+
+
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("ble_commData_send plain data", (uint8_t *)air_send_packet.send_data, air_send_packet.send_len); //
+
+ air_send_packet.encrypt_data_buf = NULL;
+
+ air_send_packet.encrypt_data_buf = (uint8_t *)tuya_ble_malloc(temp_len + en_len);
+
+ if (air_send_packet.encrypt_data_buf == NULL) {
+ TUYA_BLE_LOG_ERROR("air_send_packet.encrypt_data_buf malloc failed.");
+ tuya_ble_free(air_send_packet.send_data);
+ return 3;
+ } else {
+ air_send_packet.encrypt_data_buf_len = 0;
+ memset(air_send_packet.encrypt_data_buf, 0, temp_len + en_len);
+ }
+
+
+ air_send_packet.encrypt_data_buf[0] = encryption_mode;
+
+ if (encryption_mode != ENCRYPTION_MODE_NONE) {
+ memcpy(&air_send_packet.encrypt_data_buf[1], iv, 16);
+ } else {
+
+ }
+
+ p_version = (TUYA_BLE_PROTOCOL_VERSION_HIGN << 8) + TUYA_BLE_PROTOCOL_VERSION_LOW;
+ if (tuya_ble_encryption(p_version, encryption_mode, iv, (uint8_t *)air_send_packet.send_data, air_send_packet.send_len, &out_len,
+ (uint8_t *)(air_send_packet.encrypt_data_buf + en_len), &tuya_ble_current_para, tuya_ble_pair_rand) == 0) {
+ if ((encryption_mode != ENCRYPTION_MODE_NONE) && (out_len != temp_len)) {
+ TUYA_BLE_LOG_ERROR("ble_commData_send encryed error.");
+ tuya_ble_free(air_send_packet.send_data);
+ tuya_ble_free(air_send_packet.encrypt_data_buf);
+ return 1;
+ }
+
+ air_send_packet.encrypt_data_buf_len = en_len + out_len;
+
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("ble_commData_send encryped data", (uint8_t *)air_send_packet.encrypt_data_buf, air_send_packet.encrypt_data_buf_len); //
+ } else {
+ TUYA_BLE_LOG_ERROR("ble_commData_send encryed fail.");
+ tuya_ble_free(air_send_packet.send_data);
+ tuya_ble_free(air_send_packet.encrypt_data_buf);
+ return 1;
+ }
+
+ tuya_ble_free(air_send_packet.send_data);
+ package_number = 0;
+ if ((send_packet_data_len == 0) || (send_packet_data_len > TUYA_BLE_DATA_MTU_MAX)) {
+ send_packet_data_len = 20;
+ }
+ trsmitr_init(&ty_trsmitr_proc_send);
+ do {
+ ret = trsmitr_send_pkg_encode_with_packet_length(&ty_trsmitr_proc_send, send_packet_data_len, TUYA_BLE_PROTOCOL_VERSION_HIGN,
+ (uint8_t *)(air_send_packet.encrypt_data_buf), air_send_packet.encrypt_data_buf_len);
+ if (MTP_OK != ret && MTP_TRSMITR_CONTINUE != ret) {
+ tuya_ble_free(air_send_packet.encrypt_data_buf);
+ return 1;
+ }
+ send_len = get_trsmitr_subpkg_len(&ty_trsmitr_proc_send);
+ p_buf = get_trsmitr_subpkg(&ty_trsmitr_proc_send);
+ package_number++;
+ tuya_ble_gatt_send_data_enqueue(p_buf, send_len);
+
+ } while (ret == MTP_TRSMITR_CONTINUE);
+
+ TUYA_BLE_LOG_INFO("ble_commData_send len = %d , package_number = %d , protocol version : 0x%02x , error code : 0x%02x", air_send_packet.encrypt_data_buf_len, package_number, TUYA_BLE_PROTOCOL_VERSION_HIGN, err);
+
+ tuya_ble_free(air_send_packet.encrypt_data_buf);
+
+ return 0;
+}
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_event.c b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_event.c
new file mode 100644
index 0000000..c7fe4a7
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_event.c
@@ -0,0 +1,225 @@
+/**
+ * \file tuya_ble_event.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_heap.h"
+#include "tuya_ble_mem.h"
+#include "tuya_ble_api.h"
+#include "tuya_ble_port.h"
+#include "tuya_ble_main.h"
+#include "tuya_ble_secure.h"
+#include "tuya_ble_data_handler.h"
+#include "tuya_ble_storage.h"
+#include "tuya_ble_sdk_version.h"
+#include "tuya_ble_utils.h"
+#include "tuya_ble_event.h"
+#include "tuya_ble_log.h"
+
+#if (!TUYA_BLE_USE_OS)
+
+static uint8_t *m_queue_event_data; /**< Array for holding the queue event data. */
+static volatile uint8_t m_queue_start_index; /**< Index of queue entry at the start of the queue. */
+static volatile uint8_t m_queue_end_index; /**< Index of queue entry at the end of the queue. */
+static uint16_t m_queue_event_size; /**< Maximum event size in queue. */
+static uint16_t m_queue_size; /**< Number of queue entries. */
+
+
+/**@brief Function for incrementing a queue index, and handle wrap-around.
+ *
+ * @param[in] index Old index.
+ *
+ * @return New (incremented) index.
+ */
+static __TUYA_BLE_INLINE uint8_t next_index(uint8_t index)
+{
+ return (index < m_queue_size) ? (index + 1) : 0;
+}
+
+
+static __TUYA_BLE_INLINE uint8_t tuya_sched_queue_full(void)
+{
+ uint8_t tmp = m_queue_start_index;
+ return next_index(m_queue_end_index) == tmp;
+}
+
+/**@brief Macro for checking if a queue is full. */
+#define TUYA_BLE_SCHED_QUEUE_FULL() tuya_sched_queue_full()
+
+
+static __TUYA_BLE_INLINE uint8_t tuya_sched_queue_empty(void)
+{
+ uint8_t tmp = m_queue_start_index;
+ return m_queue_end_index == tmp;
+}
+
+/**@brief Macro for checking if a queue is empty. */
+#define TUYA_BLE_SCHED_QUEUE_EMPTY() tuya_sched_queue_empty()
+
+
+uint32_t tuya_ble_sched_init(uint16_t event_size, uint16_t queue_size, void *p_event_buffer)
+{
+
+ // Check that buffer is correctly aligned
+ if (!tuya_ble_is_word_aligned_tuya(p_event_buffer)) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_sched_init error");
+ return 1;
+ }
+
+ // Initialize event scheduler
+ m_queue_event_data = &((uint8_t *)p_event_buffer)[0];
+ m_queue_end_index = 0;
+ m_queue_start_index = 0;
+ m_queue_event_size = event_size;
+ m_queue_size = queue_size;
+
+ return 0;
+}
+
+uint16_t tuya_ble_sched_queue_size_get(void)
+{
+ return m_queue_size;
+}
+
+uint16_t tuya_ble_sched_queue_space_get(void)
+{
+ uint16_t start = m_queue_start_index;
+ uint16_t end = m_queue_end_index;
+ uint16_t free_space = m_queue_size - ((end >= start) ?
+ (end - start) : (m_queue_size + 1 - start + end));
+ return free_space;
+}
+
+
+uint16_t tuya_ble_sched_queue_events_get(void)
+{
+ uint16_t start = m_queue_start_index;
+ uint16_t end = m_queue_end_index;
+ uint16_t number_of_events;
+ if (m_queue_size == 0) {
+ number_of_events = 0;
+ } else {
+ number_of_events = ((end >= start) ? (end - start) : (m_queue_size + 1 - start + end));
+ }
+ return number_of_events;
+}
+
+
+static tuya_ble_status_t tuya_ble_sched_event_put(void const *p_event_data, uint16_t event_data_size)
+{
+ tuya_ble_status_t err_code;
+
+ if (event_data_size <= m_queue_event_size) {
+ uint16_t event_index = 0xFFFF;
+
+ tuya_ble_device_enter_critical();
+
+ if (!TUYA_BLE_SCHED_QUEUE_FULL()) {
+ event_index = m_queue_end_index;
+ m_queue_end_index = next_index(m_queue_end_index);
+
+ }
+
+ tuya_ble_device_exit_critical();
+
+ if (event_index != 0xFFFF) {
+ // NOTE: This can be done outside the critical region since the event consumer will
+ // always be called from the main loop, and will thus never interrupt this code.
+
+ if ((p_event_data != NULL) && (event_data_size > 0)) {
+ memcpy(&m_queue_event_data[event_index * m_queue_event_size],
+ p_event_data,
+ event_data_size);
+
+ } else {
+
+ }
+
+ err_code = TUYA_BLE_SUCCESS;
+ } else {
+ err_code = TUYA_BLE_ERR_NO_MEM;
+ }
+ } else {
+ err_code = TUYA_BLE_ERR_INVALID_LENGTH;
+ }
+
+ return err_code;
+}
+
+
+void tuya_sched_execute(void)
+{
+ static tuya_ble_evt_param_t tuya_ble_evt;
+ tuya_ble_evt_param_t *evt;
+
+ evt = &tuya_ble_evt;
+
+ uint8_t end_ix = m_queue_end_index;
+
+ while (m_queue_start_index != end_ix) { //(!TUYA_BLE_SCHED_QUEUE_EMPTY())
+ // Since this function is only called from the main loop, there is no
+ // need for a critical region here, however a special care must be taken
+ // regarding update of the queue start index (see the end of the loop).
+ uint16_t event_index = m_queue_start_index;
+
+ void *p_event_data;
+
+ p_event_data = &(m_queue_event_data[event_index * m_queue_event_size]);
+
+ memcpy(evt, p_event_data, sizeof(tuya_ble_evt_param_t));
+
+ //TUYA_BLE_LOG_DEBUG("TUYA_RECEIVE_EVT-0x%04x,start index-0x%04x,end index-0x%04x\n",evt->hdr.event,m_queue_start_index,m_queue_end_index);
+
+ tuya_ble_event_process(evt);
+
+ // Event processed, now it is safe to move the queue start index,
+ // so the queue entry occupied by this event can be used to store
+ // a next one.
+ m_queue_start_index = next_index(m_queue_start_index);
+ }
+
+}
+
+
+
+void tuya_ble_event_queue_init(void)
+{
+ if ((sizeof(tuya_ble_evt_param_t)) > TUYA_BLE_EVT_SIZE) {
+ TUYA_BLE_LOG_ERROR("ERROR!!TUYA_BLE_EVT_SIZE is not enough!");
+ return;
+ }
+
+ TUYA_BLE_SCHED_INIT(TUYA_BLE_EVT_SIZE, TUYA_BLE_EVT_MAX_NUM);
+}
+
+
+tuya_ble_status_t tuya_ble_message_send(tuya_ble_evt_param_t *evt)
+{
+ return tuya_ble_sched_event_put(evt, m_queue_event_size);
+}
+
+
+#endif
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_event_handler.c b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_event_handler.c
new file mode 100644
index 0000000..849f8d2
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_event_handler.c
@@ -0,0 +1,779 @@
+/**
+ * \file tuya_ble_event_handler.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_heap.h"
+#include "tuya_ble_mem.h"
+#include "tuya_ble_api.h"
+#include "tuya_ble_port.h"
+#include "tuya_ble_main.h"
+#include "tuya_ble_secure.h"
+#include "tuya_ble_data_handler.h"
+#include "tuya_ble_storage.h"
+#include "tuya_ble_sdk_version.h"
+#include "tuya_ble_event.h"
+#include "tuya_ble_utils.h"
+#include "tuya_ble_app_uart_common_handler.h"
+#include "tuya_ble_app_production_test.h"
+#include "tuya_ble_log.h"
+#include "tuya_ble_event_handler.h"
+
+
+void tuya_ble_handle_device_info_update_evt(tuya_ble_evt_param_t *evt)
+{
+#if (!TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+ tuya_ble_cb_evt_param_t event;
+ tuya_ble_connect_status_t current_connect_status;
+#endif
+ switch (evt->device_info_data.type) {
+ case DEVICE_INFO_TYPE_PID:
+ tuya_ble_current_para.pid_type = TUYA_BLE_PRODUCT_ID_TYPE_PID;
+ tuya_ble_current_para.pid_len = evt->device_info_data.len;
+ memcpy(tuya_ble_current_para.pid, evt->device_info_data.data, tuya_ble_current_para.pid_len);
+ tuya_ble_adv_change();
+ break;
+
+ case DEVICE_INFO_TYPE_PRODUCT_KEY:
+ tuya_ble_current_para.pid_type = TUYA_BLE_PRODUCT_ID_TYPE_PRODUCT_KEY;
+ tuya_ble_current_para.pid_len = evt->device_info_data.len;
+ memcpy(tuya_ble_current_para.pid, evt->device_info_data.data, tuya_ble_current_para.pid_len);
+ tuya_ble_adv_change();
+ break;
+ case DEVICE_INFO_TYPE_LOGIN_KEY:
+#if (!TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+ if (memcmp(tuya_ble_current_para.sys_settings.login_key, evt->device_info_data.data, LOGIN_KEY_LEN)) {
+ memcpy(tuya_ble_current_para.sys_settings.login_key, evt->device_info_data.data, LOGIN_KEY_LEN);
+
+ }
+#endif
+ break;
+ case DEVICE_INFO_TYPE_BOUND:
+
+#if (!TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+ if (tuya_ble_current_para.sys_settings.bound_flag != evt->device_info_data.data[0]) {
+ tuya_ble_current_para.sys_settings.bound_flag = evt->device_info_data.data[0];
+
+ tuya_ble_adv_change();
+ current_connect_status = tuya_ble_connect_status_get();
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) { //0->1
+ if (current_connect_status == UNBONDING_CONN) {
+ tuya_ble_connect_status_set(BONDING_CONN);
+ } else if (current_connect_status == UNBONDING_UNAUTH_CONN) {
+ tuya_ble_connect_status_set(BONDING_UNAUTH_CONN);
+ } else if (current_connect_status == UNBONDING_UNCONN) {
+ tuya_ble_connect_status_set(BONDING_UNCONN);
+ } else {
+
+ }
+
+ } else { //1->0
+ if (current_connect_status == BONDING_CONN) {
+ tuya_ble_connect_status_set(UNBONDING_CONN);
+ } else if (current_connect_status == BONDING_UNAUTH_CONN) {
+ tuya_ble_connect_status_set(UNBONDING_UNAUTH_CONN);
+ } else if (current_connect_status == BONDING_UNCONN) {
+ tuya_ble_connect_status_set(UNBONDING_UNCONN);
+ } else {
+
+ }
+ }
+
+ event.evt = TUYA_BLE_CB_EVT_CONNECTE_STATUS;
+ event.connect_status = tuya_ble_connect_status_get();
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya ble send cb event failed.");
+ } else {
+ TUYA_BLE_LOG_ERROR("tuya ble send cb event succeed.");
+ }
+
+ }
+#endif
+ break;
+ default:
+ break;
+ }
+
+}
+
+
+void tuya_ble_handle_dp_data_reported_evt(tuya_ble_evt_param_t *evt)
+{
+ uint8_t encry_mode = 0;
+ if (tuya_ble_pair_rand_valid_get() == 1) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_4;
+ }
+ tuya_ble_commData_send(FRM_STAT_REPORT, 0, evt->reported_data.p_data, evt->reported_data.data_len, encry_mode);
+
+ if (evt->reported_data.p_data) {
+ tuya_ble_free(evt->reported_data.p_data);
+ }
+}
+
+void tuya_ble_handle_dp_data_with_flag_reported_evt(tuya_ble_evt_param_t *evt)
+{
+ uint8_t encry_mode = 0;
+ if (tuya_ble_pair_rand_valid_get() == 1) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_4;
+ }
+
+ tuya_ble_commData_send(FRM_DATA_WITH_FLAG_REPORT, 0, evt->flag_reported_data.p_data, evt->flag_reported_data.data_len, encry_mode);
+
+ if (evt->flag_reported_data.p_data) {
+ tuya_ble_free(evt->flag_reported_data.p_data);
+ }
+}
+
+void tuya_ble_handle_dp_data_with_time_reported_evt(tuya_ble_evt_param_t *evt)
+{
+ uint8_t *data_buffer = NULL;
+ uint16_t data_len;
+ uint8_t encry_mode = 0;
+
+ data_len = 5 + evt->reported_with_time_data.data_len;
+
+ data_buffer = (uint8_t *)tuya_ble_malloc(data_len);
+ if (data_buffer == NULL) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_dp_data_with_time_reported_evt malloc failed.");
+ if (evt->reported_with_time_data.p_data) {
+ tuya_ble_free(evt->reported_with_time_data.p_data);
+ }
+ return;
+ } else {
+ memset(data_buffer, 0, data_len);
+ }
+
+ if (tuya_ble_pair_rand_valid_get() == 1) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_4;
+ }
+
+ data_buffer[0] = 1;
+ data_buffer[1] = evt->reported_with_time_data.timestamp >> 24;
+ data_buffer[2] = evt->reported_with_time_data.timestamp >> 16;
+ data_buffer[3] = evt->reported_with_time_data.timestamp >> 8;
+ data_buffer[4] = evt->reported_with_time_data.timestamp;
+
+ memcpy(&data_buffer[5], evt->reported_with_time_data.p_data, evt->reported_with_time_data.data_len);
+
+ tuya_ble_commData_send(FRM_STAT_WITH_TIME_REPORT, 0, data_buffer, data_len, encry_mode);
+
+ tuya_ble_free(data_buffer);
+
+ if (evt->reported_with_time_data.p_data) {
+ tuya_ble_free(evt->reported_with_time_data.p_data);
+ }
+}
+
+void tuya_ble_handle_dp_data_with_flag_and_time_reported_evt(tuya_ble_evt_param_t *evt)
+{
+ uint8_t *data_buffer = NULL;
+ uint16_t data_len;
+ uint8_t encry_mode = 0;
+
+ data_len = 8 + evt->flag_reported_with_time_data.data_len;
+
+ data_buffer = (uint8_t *)tuya_ble_malloc(data_len);
+ if (data_buffer == NULL) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_dp_data_with_flag_and_time_reported_evt malloc failed.");
+ if (evt->flag_reported_with_time_data.p_data) {
+ tuya_ble_free(evt->flag_reported_with_time_data.p_data);
+ }
+ return;
+ } else {
+ memset(data_buffer, 0, data_len);
+ }
+
+ if (tuya_ble_pair_rand_valid_get() == 1) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_4;
+ }
+
+ data_buffer[0] = evt->flag_reported_with_time_data.sn >> 8;
+ data_buffer[1] = evt->flag_reported_with_time_data.sn;
+ data_buffer[2] = evt->flag_reported_with_time_data.mode;
+ data_buffer[3] = 1;
+ data_buffer[4] = evt->flag_reported_with_time_data.timestamp >> 24;
+ data_buffer[5] = evt->flag_reported_with_time_data.timestamp >> 16;
+ data_buffer[6] = evt->flag_reported_with_time_data.timestamp >> 8;
+ data_buffer[7] = evt->flag_reported_with_time_data.timestamp;
+
+ memcpy(&data_buffer[8], evt->flag_reported_with_time_data.p_data, evt->flag_reported_with_time_data.data_len);
+
+ tuya_ble_commData_send(FRM_DATA_WITH_FLAG_AND_TIME_REPORT, 0, data_buffer, data_len, encry_mode);
+
+ tuya_ble_free(data_buffer);
+
+ if (evt->flag_reported_with_time_data.p_data) {
+ tuya_ble_free(evt->flag_reported_with_time_data.p_data);
+ }
+}
+
+void tuya_ble_handle_dp_data_with_time_string_reported_evt(tuya_ble_evt_param_t *evt)
+{
+ uint8_t *data_buffer = NULL;
+ uint16_t data_len;
+ uint8_t encry_mode = 0;
+
+ data_len = 14 + evt->reported_with_time_string_data.data_len;
+
+ data_buffer = (uint8_t *)tuya_ble_malloc(data_len);
+ if (data_buffer == NULL) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_dp_data_with_time_string_reported_evt malloc failed.");
+ if (evt->reported_with_time_string_data.p_data) {
+ tuya_ble_free(evt->reported_with_time_string_data.p_data);
+ }
+ return;
+ } else {
+ memset(data_buffer, 0, data_len);
+ }
+
+ if (tuya_ble_pair_rand_valid_get() == 1) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_4;
+ }
+
+ data_buffer[0] = 0;
+
+ memcpy(&data_buffer[1], evt->reported_with_time_string_data.time_string, 13);
+
+ memcpy(&data_buffer[14], evt->reported_with_time_string_data.p_data, evt->reported_with_time_string_data.data_len);
+
+ tuya_ble_commData_send(FRM_STAT_WITH_TIME_REPORT, 0, data_buffer, data_len, encry_mode);
+
+ tuya_ble_free(data_buffer);
+
+ if (evt->reported_with_time_string_data.p_data) {
+ tuya_ble_free(evt->reported_with_time_string_data.p_data);
+ }
+}
+
+void tuya_ble_handle_dp_data_with_flag_and_time_string_reported_evt(tuya_ble_evt_param_t *evt)
+{
+ uint8_t *data_buffer = NULL;
+ uint16_t data_len;
+ uint8_t encry_mode = 0;
+
+ data_len = 17 + evt->flag_reported_with_time_string_data.data_len;
+
+ data_buffer = (uint8_t *)tuya_ble_malloc(data_len);
+ if (data_buffer == NULL) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_dp_data_with_flag_and_time_string_reported_evt malloc failed.");
+ if (evt->flag_reported_with_time_string_data.p_data) {
+ tuya_ble_free(evt->flag_reported_with_time_string_data.p_data);
+ }
+ return;
+ } else {
+ memset(data_buffer, 0, data_len);
+ }
+
+ if (tuya_ble_pair_rand_valid_get() == 1) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_4;
+ }
+
+ data_buffer[0] = evt->flag_reported_with_time_string_data.sn >> 8;
+ data_buffer[1] = evt->flag_reported_with_time_string_data.sn;
+ data_buffer[2] = evt->flag_reported_with_time_string_data.mode;
+ data_buffer[3] = 0;
+ memcpy(&data_buffer[4], evt->flag_reported_with_time_string_data.time_string, 13);
+
+ memcpy(&data_buffer[17], evt->flag_reported_with_time_string_data.p_data, evt->flag_reported_with_time_string_data.data_len);
+
+ tuya_ble_commData_send(FRM_DATA_WITH_FLAG_AND_TIME_REPORT, 0, data_buffer, data_len, encry_mode);
+
+ tuya_ble_free(data_buffer);
+
+ if (evt->flag_reported_with_time_string_data.p_data) {
+ tuya_ble_free(evt->flag_reported_with_time_string_data.p_data);
+ }
+}
+
+
+void tuya_ble_handle_dp_data_send_evt(tuya_ble_evt_param_t *evt)
+{
+ uint8_t encry_mode = 0;
+ if (tuya_ble_pair_rand_valid_get() == 1) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_4;
+ }
+
+ tuya_ble_commData_send(FRM_DP_DATA_SEND_REQ, 0, evt->dp_send_data.p_data, evt->dp_send_data.data_len, encry_mode);
+
+ if (evt->dp_send_data.p_data) {
+ tuya_ble_free(evt->dp_send_data.p_data);
+ }
+}
+
+void tuya_ble_handle_dp_data_with_time_send_evt(tuya_ble_evt_param_t *evt)
+{
+ uint8_t encry_mode = 0;
+
+ if (tuya_ble_pair_rand_valid_get() == 1) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_4;
+ }
+
+ tuya_ble_commData_send(FRM_DP_DATA_WITH_TIME_SEND_REQ, 0, evt->dp_with_time_send_data.p_data, evt->dp_with_time_send_data.data_len, encry_mode);
+
+ if (evt->dp_with_time_send_data.p_data) {
+ tuya_ble_free(evt->dp_with_time_send_data.p_data);
+ }
+}
+
+
+void tuya_ble_handle_device_unbind_evt(tuya_ble_evt_param_t *evt)
+{
+ tuya_ble_cb_evt_param_t event;
+
+ tuya_ble_device_unbond();
+
+ event.evt = TUYA_BLE_CB_EVT_CONNECTE_STATUS;
+ event.connect_status = tuya_ble_connect_status_get();
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_factory_reset_evt-tuya ble send cb event (connect status update) failed.");
+ } else {
+
+ }
+
+ event.evt = TUYA_BLE_CB_EVT_UNBIND_RESET_RESPONSE;
+ event.reset_response_data.type = RESET_TYPE_UNBIND;
+ event.reset_response_data.status = 0;
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_device_unbind_evt-tuya ble send cb event (TUYA_BLE_CB_EVT_UNBIND_RESET_RESPONSE) failed.");
+ } else {
+
+ }
+
+}
+
+
+void tuya_ble_handle_factory_reset_evt(tuya_ble_evt_param_t *evt)
+{
+ tuya_ble_cb_evt_param_t event;
+
+ memset(tuya_ble_current_para.sys_settings.device_virtual_id, 0, DEVICE_VIRTUAL_ID_LEN);
+ tuya_ble_device_unbond();
+
+ event.evt = TUYA_BLE_CB_EVT_CONNECTE_STATUS;
+ event.connect_status = tuya_ble_connect_status_get();
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_factory_reset_evt-tuya ble send cb event (connect status update) failed.");
+ } else {
+
+ }
+
+ event.evt = TUYA_BLE_CB_EVT_UNBIND_RESET_RESPONSE;
+ event.reset_response_data.type = RESET_TYPE_FACTORY_RESET;
+ event.reset_response_data.status = 0;
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_factory_reset_evt-tuya ble send cb event (TUYA_BLE_CB_EVT_UNBIND_RESET_RESPONSE) failed.");
+ } else {
+
+ }
+
+}
+
+
+void tuya_ble_handle_ota_response_evt(tuya_ble_evt_param_t *evt)
+{
+ uint16_t ota_cmd_type = 0;
+
+ uint8_t encry_mode = 0;
+ if (tuya_ble_pair_rand_valid_get() == 1) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_4;
+ }
+
+ switch (evt->ota_response_data.type) {
+ case TUYA_BLE_OTA_REQ:
+ ota_cmd_type = FRM_OTA_START_REQ;
+ break;
+ case TUYA_BLE_OTA_FILE_INFO:
+ ota_cmd_type = FRM_OTA_FILE_INFOR_REQ;
+ break;
+ case TUYA_BLE_OTA_FILE_OFFSET_REQ :
+ ota_cmd_type = FRM_OTA_FILE_OFFSET_REQ;
+ break;
+ case TUYA_BLE_OTA_DATA :
+ ota_cmd_type = FRM_OTA_DATA_REQ;
+ break;
+ case TUYA_BLE_OTA_END :
+ ota_cmd_type = FRM_OTA_END_REQ;
+ break;
+ default:
+ break;
+ }
+
+ if (ota_cmd_type != 0) {
+ tuya_ble_commData_send(ota_cmd_type, 0, evt->ota_response_data.p_data, evt->ota_response_data.data_len, encry_mode);
+ }
+
+ if (evt->ota_response_data.p_data) {
+ tuya_ble_free(evt->ota_response_data.p_data);
+ }
+}
+
+
+void tuya_ble_handle_data_passthrough_evt(tuya_ble_evt_param_t *evt)
+{
+ uint8_t encry_mode = 0;
+
+ if (tuya_ble_current_para.sys_settings.bound_flag) {
+ if (tuya_ble_pair_rand_valid_get() == 1) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_4;
+ }
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_2;
+ }
+
+ tuya_ble_commData_send(FRM_DATA_PASSTHROUGH_REQ, 0, evt->passthrough_data.p_data, evt->passthrough_data.data_len, encry_mode);
+
+ if (evt->passthrough_data.p_data) {
+ tuya_ble_free(evt->passthrough_data.p_data);
+ }
+}
+
+
+void tuya_ble_handle_data_prod_test_response_evt(tuya_ble_evt_param_t *evt)
+{
+ uint8_t encry_mode = 0;
+ tuya_ble_connect_status_t connect_status;
+
+ if (evt->prod_test_res_data.channel == 0) {
+ tuya_ble_common_uart_send_data(evt->prod_test_res_data.p_data, evt->prod_test_res_data.data_len);
+ } else if (evt->prod_test_res_data.channel == 1) {
+ connect_status = tuya_ble_connect_status_get();
+ if (connect_status == BONDING_CONN) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+#if (TUYA_BLE_PROD_TEST_SUPPORT_ENCRYPTION != 0)
+ encry_mode = ENCRYPTION_MODE_FTM_KEY;
+#else
+ encry_mode = ENCRYPTION_MODE_NONE;
+#endif
+ }
+
+ tuya_ble_commData_send(FRM_FACTORY_TEST_RESP, 0, evt->prod_test_res_data.p_data, evt->prod_test_res_data.data_len, encry_mode);
+ }
+
+ if (evt->prod_test_res_data.p_data) {
+ tuya_ble_free(evt->prod_test_res_data.p_data);
+ }
+
+}
+
+
+void tuya_ble_handle_uart_cmd_evt(tuya_ble_evt_param_t *evt)
+{
+ uint8_t sum;
+ uint8_t *uart_send_buffer;
+ uint16_t uart_send_len;
+
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("received uart cmd data", (uint8_t *)evt->uart_cmd_data.p_data, evt->uart_cmd_data.data_len); //
+
+#if (TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+
+ if (evt->uart_cmd_data.data_len > 0) {
+ sum = tuya_ble_check_sum(evt->uart_cmd_data.p_data, evt->uart_cmd_data.data_len - 1);
+ if (sum == evt->uart_cmd_data.p_data[evt->uart_cmd_data.data_len - 1]) {
+
+ switch (evt->uart_cmd_data.p_data[0]) {
+ case 0x55:
+ tuya_ble_uart_common_process(evt->uart_cmd_data.p_data, evt->uart_cmd_data.data_len);
+ break;
+ case 0x66:
+ tuya_ble_app_production_test_process(0, evt->uart_cmd_data.p_data, evt->uart_cmd_data.data_len);
+ break;
+ default:
+ break;
+ };
+
+ } else {
+ TUYA_BLE_LOG_ERROR("uart receive data check_sum error , receive sum = 0x%02x ; cal sum = 0x%02x", evt->uart_cmd_data.p_data[evt->uart_cmd_data.data_len - 1], sum);
+ }
+ }
+
+#endif
+
+ if (evt->uart_cmd_data.p_data) {
+ tuya_ble_free(evt->uart_cmd_data.p_data);
+ }
+}
+
+
+void tuya_ble_handle_ble_cmd_evt(tuya_ble_evt_param_t *evt)
+{
+
+ tuya_ble_evt_process(evt->ble_cmd_data.cmd, evt->ble_cmd_data.p_data, evt->ble_cmd_data.data_len);
+ if (evt->ble_cmd_data.p_data) {
+ tuya_ble_free(evt->ble_cmd_data.p_data);
+ }
+}
+
+
+void tuya_ble_handle_net_config_response_evt(tuya_ble_evt_param_t *evt)
+{
+ uint8_t encry_mode = 0;
+ uint8_t data[2];
+
+ if (tuya_ble_pair_rand_valid_get() == 1) {
+ encry_mode = ENCRYPTION_MODE_KEY_2;
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_1;
+ }
+
+
+ data[0] = ((int16_t)(evt->net_config_response_data.result_code)) >> 8;
+ data[1] = (int16_t)(evt->net_config_response_data.result_code);
+
+ tuya_ble_commData_send(FRM_NET_CONFIG_RESPONSE_REPORT_REQ, 0, data, 2, encry_mode);
+
+}
+
+
+void tuya_ble_handle_time_request_evt(tuya_ble_evt_param_t *evt)
+{
+ uint8_t encry_mode = 0;
+ uint16_t cmd;
+ if (tuya_ble_pair_rand_valid_get() == 1) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_4;
+ }
+
+ if (evt->time_req_data.time_type == 0) {
+ cmd = FRM_GET_UNIX_TIME_CHAR_MS_REQ;
+ } else if (evt->time_req_data.time_type == 1) {
+ cmd = FRM_GET_UNIX_TIME_CHAR_DATE_REQ;
+ } else if (evt->time_req_data.time_type == 2) {
+ cmd = FRM_GET_APP_LOCAL_TIME_REQ;
+ } else {
+ return;
+ }
+
+ tuya_ble_commData_send(cmd, 0, NULL, 0, encry_mode);
+
+}
+
+void tuya_ble_handle_extend_time_request_evt(tuya_ble_evt_param_t *evt)
+{
+ uint8_t encry_mode = 0;
+ uint8_t data[1];
+
+ if (tuya_ble_pair_rand_valid_get() == 1) {
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+ } else {
+ encry_mode = ENCRYPTION_MODE_KEY_4;
+ }
+
+ data[0] = evt->extend_time_req_data.n_years_dst;
+
+ tuya_ble_commData_send(FRM_GET_UNIX_TIME_WITH_DST_REQ, 0, data, 1, encry_mode);
+}
+
+
+void tuya_ble_handle_unbound_response_evt(tuya_ble_evt_param_t *evt)
+{
+#if (!TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+ uint8_t encry_mode = 0;
+ uint8_t result;
+
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+
+ result = evt->ubound_res_data.result_code;
+
+ tuya_ble_commData_send(FRM_UNBONDING_RESP, 0, &result, 1, encry_mode);
+#else
+ return;
+#endif
+}
+
+void tuya_ble_handle_anomaly_unbound_response_evt(tuya_ble_evt_param_t *evt)
+{
+#if (!TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+
+ uint8_t encry_mode = 0;
+ uint8_t result;
+
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+
+ result = evt->anomaly_ubound_res_data.result_code;
+
+ tuya_ble_commData_send(FRM_ANOMALY_UNBONDING_RESP, 0, &result, 1, encry_mode);
+
+#else
+ return;
+#endif
+
+}
+
+void tuya_ble_handle_device_reset_response_evt(tuya_ble_evt_param_t *evt)
+{
+#if (!TUYA_BLE_DEVICE_REGISTER_FROM_BLE)
+ uint8_t encry_mode = 0;
+ uint8_t result;
+
+ encry_mode = ENCRYPTION_MODE_SESSION_KEY;
+
+ result = evt->device_reset_res_data.result_code;
+
+ tuya_ble_commData_send(FRM_DEVICE_RESET_RESP, 0, &result, 1, encry_mode);
+#else
+ return;
+#endif
+}
+
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN >= 3)
+void tuya_ble_handle_connecting_request_evt(tuya_ble_evt_param_t *evt)
+{
+ tuya_ble_connect_status_t currnet_connect_status;
+ currnet_connect_status = tuya_ble_connect_status_get();
+ if ((currnet_connect_status != BONDING_UNCONN) && (currnet_connect_status != UNBONDING_UNCONN)) {
+ return;
+ }
+ if (evt->connecting_request_data.cmd == 0) {
+ tuya_ble_adv_change();
+ } else {
+ tuya_ble_adv_change_with_connecting_request();
+ }
+
+}
+#endif
+
+extern void tuya_ble_connect_monitor_timer_start(void);
+void tuya_ble_handle_connect_change_evt(tuya_ble_evt_param_t *evt)
+{
+ tuya_ble_cb_evt_param_t event;
+ uint8_t send_cb_flag = 1;
+
+ if (evt->connect_change_evt == TUYA_BLE_CONNECTED) {
+ TUYA_BLE_LOG_INFO("Connected!");
+ tuya_ble_reset_ble_sn();
+ if (tuya_ble_current_para.sys_settings.bound_flag != 1) {
+ tuya_ble_connect_status_set(UNBONDING_UNAUTH_CONN);
+ } else {
+ tuya_ble_connect_status_set(BONDING_UNAUTH_CONN);
+ }
+
+ tuya_ble_connect_monitor_timer_start();
+
+#if (TUYA_BLE_DEVICE_REGISTER_FROM_BLE&&TUYA_BLE_DEVICE_AUTH_DATA_STORE)
+
+ tuya_ble_internal_production_test_with_ble_flag_clear();
+
+#endif
+
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE==TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION)
+
+ tuya_ble_auth_data_reset();
+
+#endif
+
+#if TUYA_BLE_LINK_LAYER_ENCRYPTION_SUPPORT_ENABLE
+
+ tuya_ble_link_status_set(LINK_CONNECTED);
+
+#endif
+
+ } else if (evt->connect_change_evt == TUYA_BLE_DISCONNECTED) {
+ TUYA_BLE_LOG_INFO("Disonnected");
+
+ tuya_ble_reset_ble_sn();
+
+ tuya_ble_pair_rand_clear();
+
+ tuya_ble_air_recv_packet_free();
+
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) {
+ tuya_ble_connect_status_set(BONDING_UNCONN);
+ } else {
+ tuya_ble_connect_status_set(UNBONDING_UNCONN);
+ }
+
+#if TUYA_BLE_LINK_LAYER_ENCRYPTION_SUPPORT_ENABLE
+
+ tuya_ble_link_status_set(LINK_DISCONNECTED);
+
+#endif
+
+ } else {
+ TUYA_BLE_LOG_WARNING("unknown connect_change_evt!");
+ }
+
+ if (send_cb_flag) {
+ event.evt = TUYA_BLE_CB_EVT_CONNECTE_STATUS;
+ event.connect_status = tuya_ble_connect_status_get();
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya ble send cb event failed.");
+ } else {
+ TUYA_BLE_LOG_DEBUG("tuya ble send cb event succeed.");
+ }
+
+ }
+
+}
+
+
+void tuya_ble_handle_link_update_evt(tuya_ble_evt_param_t *evt)
+{
+#if TUYA_BLE_LINK_LAYER_ENCRYPTION_SUPPORT_ENABLE
+
+ if (evt->link_update_data.link_app_status == 1) {
+ tuya_ble_link_status_set(LINK_ENCRYPTED);
+ if (tuya_ble_connect_status_get() != BONDING_CONN) {
+ tuya_ble_connect_monitor_timer_stop();
+ }
+ TUYA_BLE_LOG_DEBUG("link encrypted.");
+ }
+
+#endif
+}
+
+void tuya_ble_handle_ble_data_evt(uint8_t *buf, uint16_t len)
+{
+ tuya_ble_commonData_rx_proc(buf, len);
+ if (len > 20) {
+ tuya_ble_free(buf);
+ }
+}
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_event_handler_weak.c b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_event_handler_weak.c
new file mode 100644
index 0000000..5a2cb5c
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_event_handler_weak.c
@@ -0,0 +1,193 @@
+/**
+ * \file tuya_ble_event_handler_weak.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_event_handler.h"
+
+
+
+__TUYA_BLE_WEAK void tuya_ble_handle_device_info_update_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+
+__TUYA_BLE_WEAK void tuya_ble_handle_dp_data_reported_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+
+__TUYA_BLE_WEAK void tuya_ble_handle_dp_data_with_time_reported_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+
+__TUYA_BLE_WEAK void tuya_ble_handle_dp_data_with_time_string_reported_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+__TUYA_BLE_WEAK void tuya_ble_handle_dp_data_with_flag_reported_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+__TUYA_BLE_WEAK void tuya_ble_handle_dp_data_with_flag_and_time_reported_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+__TUYA_BLE_WEAK void tuya_ble_handle_dp_data_with_flag_and_time_string_reported_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+
+__TUYA_BLE_WEAK void tuya_ble_handle_dp_data_send_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+
+__TUYA_BLE_WEAK void tuya_ble_handle_dp_data_with_time_send_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+
+__TUYA_BLE_WEAK void tuya_ble_handle_device_unbind_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+
+
+__TUYA_BLE_WEAK void tuya_ble_handle_factory_reset_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+
+__TUYA_BLE_WEAK void tuya_ble_handle_ota_response_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+__TUYA_BLE_WEAK void tuya_ble_handle_bulk_data_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+__TUYA_BLE_WEAK void tuya_ble_handle_data_passthrough_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+
+__TUYA_BLE_WEAK void tuya_ble_handle_data_prod_test_response_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+
+__TUYA_BLE_WEAK void tuya_ble_handle_uart_cmd_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+
+__TUYA_BLE_WEAK void tuya_ble_handle_ble_cmd_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+
+__TUYA_BLE_WEAK void tuya_ble_handle_net_config_response_evt(tuya_ble_evt_param_t *evt)
+{
+
+
+}
+
+
+__TUYA_BLE_WEAK void tuya_ble_handle_time_request_evt(tuya_ble_evt_param_t *evt)
+{
+
+
+}
+
+
+__TUYA_BLE_WEAK void tuya_ble_handle_extend_time_request_evt(tuya_ble_evt_param_t *evt)
+{
+
+
+}
+
+
+__TUYA_BLE_WEAK void tuya_ble_handle_unbound_response_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+__TUYA_BLE_WEAK void tuya_ble_handle_anomaly_unbound_response_evt(tuya_ble_evt_param_t *evt)
+{
+
+
+}
+
+__TUYA_BLE_WEAK void tuya_ble_handle_device_reset_response_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+__TUYA_BLE_WEAK void tuya_ble_handle_connect_change_evt(tuya_ble_evt_param_t *evt)
+{
+
+
+}
+
+__TUYA_BLE_WEAK void tuya_ble_handle_connecting_request_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+__TUYA_BLE_WEAK void tuya_ble_handle_ble_data_evt(uint8_t *buf, uint16_t len)
+{
+
+}
+
+__TUYA_BLE_WEAK void tuya_ble_handle_link_update_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+__TUYA_BLE_WEAK void tuya_ble_handle_weather_data_request_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_feature_weather.c b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_feature_weather.c
new file mode 100644
index 0000000..3c081ef
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_feature_weather.c
@@ -0,0 +1,447 @@
+/**
+ * \file tuya_ble_feature_weather.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_heap.h"
+#include "tuya_ble_mem.h"
+#include "tuya_ble_api.h"
+#include "tuya_ble_port.h"
+#include "tuya_ble_main.h"
+#include "tuya_ble_internal_config.h"
+#include "tuya_ble_feature_weather.h"
+#include "tuya_ble_data_handler.h"
+#include "tuya_ble_mutli_tsf_protocol.h"
+#include "tuya_ble_utils.h"
+#include "tuya_ble_secure.h"
+#include "tuya_ble_main.h"
+#include "tuya_ble_storage.h"
+#include "tuya_ble_unix_time.h"
+#include "tuya_ble_log.h"
+#include "tuya_ble_gatt_send_queue.h"
+
+#if ( (TUYA_BLE_PROTOCOL_VERSION_HIGN==4) && (TUYA_BLE_FEATURE_WEATHER_ENABLE != 0) )
+
+/**@brief Weather key string. */
+const char *weather_key[] = {
+ "w.temp",
+ "w.thigh",
+ "w.tlow",
+ "w.humidity",
+ "w.condition",
+ "w.pressure",
+ "w.realFeel",
+ "w.uvi",
+ "w.sunRise",
+ "w.sunSet",
+ "t.unix",
+ "t.local",
+ "w.windSpeed",
+ "w.windDir",
+ "w.windLevel",
+ "w.aqi",
+ "w.tips",
+ "w.rank",
+ "w.pm10",
+ "w.pm25",
+ "w.o3",
+ "w.no2",
+ "w.co",
+ "w.so2",
+ "w.conditionNum",
+
+ "w.data.", //**< w.data.n, n rang from [1-7]
+};
+
+static tuya_ble_weather_location_type_t cur_req_weather_location_type;
+
+/**
+ * @brief Function for calculate weather key max string length
+ *
+ * @return The max string len
+ *
+ * */
+static uint16_t calc_weather_key_max_string_len(void)
+{
+ int i, string_array_element = sizeof(weather_key) / sizeof(weather_key[0]);
+ uint16_t string_len = 0, tmp;
+
+ for (i = 0; i < string_array_element; i++) {
+ tmp = strlen(weather_key[i]);
+ if (tmp > string_len) {
+ string_len = tmp;
+ }
+ }
+
+ return string_len;
+}
+
+
+/**
+ * @brief Function for convert weather key to enum type
+ *
+ * @note For example input key "w.temp.0", convert type=WKT_TEMP day=1
+ *
+ * @param[in] key The ponit of input weather key string
+ * @param[out] type Convert type
+ * @param[out] day The day of weather data, rang from [1-7], 1-means today
+ *
+ * @retval TUYA_BLE_ERR_INVALID_PARAM The provided Parameters are not valid.
+ * @retval TUYA_BLE_ERR_NOT_FOUND No corresponding key was found.
+ * @retval TUYA_BLE_SUCCESS Successful.
+ *
+ * */
+static tuya_ble_status_t weather_key_string_to_enum_type(char *key, uint8_t key_str_len, tuya_ble_weather_key_type_t *type, uint8_t *day)
+{
+ int i, string_array_element;
+
+ if (key == NULL) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+
+ string_array_element = sizeof(weather_key) / sizeof(weather_key[0]);
+ for (i = 0; i < string_array_element; i++) {
+ if ((strncmp(key, weather_key[i], strlen(weather_key[i])) == 0) && \
+ (key_str_len <= (strlen(weather_key[i]) + 2))) {
+ if (type != NULL) {
+ *type = (tuya_ble_weather_key_type_t)(1 << i);
+ }
+
+ if (day != NULL) {
+ if (key_str_len > strlen(weather_key[i])) {
+ /* key.n */
+ *day = key[strlen(weather_key[i]) + 1] - '0' + 1;
+ } else {
+ /* only today */
+ *day = 1;
+ }
+ }
+
+ return TUYA_BLE_SUCCESS;
+ }
+ }
+
+ return TUYA_BLE_ERR_NOT_FOUND;
+}
+
+
+tuya_ble_status_t tuya_ble_feature_weather_key_enum_type_to_string(tuya_ble_weather_key_type_t type, char *key)
+{
+ int bit;
+
+ if (type >= WKT_COMBINE_BITMAP_MAXVAL || key == NULL) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+
+ /* Convert to actual weather key string based on type */
+ for (bit = 0; bit < SUPPORT_WEATHER_KEY_TYPE_MAX_NUMS; bit++) {
+ if (((type >> bit) & 0x01) == 0x01) {
+ memcpy(key, weather_key[bit], strlen(weather_key[bit]));
+ return TUYA_BLE_SUCCESS;
+ }
+ }
+
+ return TUYA_BLE_ERR_NOT_FOUND;
+}
+
+
+/**
+ * @brief Function for parse weather lktlv format data
+ *
+ * @param[in] recv_data The point of input data
+ * @param[in] recv_len The length of input data
+ *
+ * @retval TUYA_BLE_ERR_INVALID_PARAM The provided Parameters are not valid.
+ * @retval TUYA_BLE_SUCCESS Successful.
+ *
+ * */
+static tuya_ble_status_t weather_data_lktlv_parse(uint8_t *in, uint16_t in_len, uint8_t *out, uint16_t *out_len, uint16_t *object_nums)
+{
+ uint8_t key_len, value_len, n_day;
+ uint16_t object_len = 0;
+
+ tuya_ble_weather_key_type_t weather_type;
+ tuya_ble_weather_value_type_t value_type;
+ tuya_ble_wd_object_t *object;
+ uint16_t tmp_out_len = 0, tmp_object_nums = 0;
+
+ if (in == NULL || in_len == 0 || out == NULL || out_len == NULL || object_nums == NULL) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+
+ /*-------------------------------------------------------------------------
+ | 1byte | key_len | 1byte | 1byte | value_len |
+ | key_len | key | value_type | value_len | value |
+ ---------------------------------------------------------------------------*/
+ for (;;) {
+ key_len = in[0 + object_len];
+ value_type = in[1 + key_len + object_len];
+ value_len = in[2 + key_len + object_len];
+
+ if (weather_key_string_to_enum_type((char *)&in[1 + object_len], key_len, &weather_type, &n_day) != TUYA_BLE_SUCCESS) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+
+ TUYA_BLE_LOG_DEBUG("parse weather data, n_day=[%d] type=[0x%08x] val_type=[%d] ,", n_day, weather_type, value_type);
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("value :", &in[3 + key_len + object_len], value_len);
+
+ /* Convert lktlv format to tuya_ble_wd_object */
+ object = (tuya_ble_wd_object_t *)tuya_ble_malloc(sizeof(tuya_ble_wd_object_t) + value_len);
+ if (object == NULL) {
+ return TUYA_BLE_ERR_NO_MEM;
+ }
+
+ object->n_day = n_day;
+ object->key_type = weather_type;
+ object->val_type = value_type;
+ object->value_len = value_len;
+ memcpy(&(object->vaule), &in[3 + key_len + object_len], value_len);
+
+ memcpy(&out[tmp_out_len], object, (sizeof(tuya_ble_wd_object_t) + value_len));
+ tmp_out_len += (sizeof(tuya_ble_wd_object_t) + value_len);
+ tuya_ble_free((uint8_t *)object);
+
+ tmp_object_nums += 1;
+ object_len += (key_len + value_len + 3);
+ if (object_len >= in_len) {
+ *out_len = tmp_out_len;
+ *object_nums = tmp_object_nums;
+ break;
+ }
+ }
+
+ TUYA_BLE_LOG_DEBUG("parse weather data finish, total count=[%d]", tmp_object_nums);
+ return TUYA_BLE_SUCCESS;
+}
+
+
+tuya_ble_status_t tuya_ble_feature_weather_data_request_with_location(tuya_ble_weather_location_type_t location_type, uint32_t combine_type, uint8_t n_days)
+{
+ tuya_ble_evt_param_t event;
+ uint8_t *ble_evt_buffer = NULL;
+ uint16_t ble_evt_buffer_len = 0;
+ uint16_t per_weather_key_malloc_size, weather_key_len;
+ int bit, count;
+
+ if ((location_type >= WLT_MAX) || (location_type == WLT_CUSTOM_LOCATION)) {
+ TUYA_BLE_LOG_ERROR("request weather location type this sdk version unsupport");
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+
+ if (combine_type >= WKT_COMBINE_BITMAP_MAXVAL || n_days < 1 || n_days > 7) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+
+ /* Calc total bit1 counters */
+ count = tuya_ble_count_bits((uint32_t)(combine_type));
+ if (0 == count) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+
+ /* Malloc data buffer */
+ count += 1; // add w.data.n
+ per_weather_key_malloc_size = (calc_weather_key_max_string_len() + 4);
+ ble_evt_buffer = (uint8_t *)tuya_ble_malloc(2 + per_weather_key_malloc_size * count);
+ if (ble_evt_buffer == NULL) {
+ return TUYA_BLE_ERR_NO_MEM;
+ }
+
+ /* Fill version & location info */
+ cur_req_weather_location_type = location_type;
+
+ ble_evt_buffer[0] = 0;
+ ble_evt_buffer[1] = (uint8_t)(location_type);
+ ble_evt_buffer_len += 2;
+
+ /* Convert to actual weather key based on type */
+ for (bit = 0; bit < SUPPORT_WEATHER_KEY_TYPE_MAX_NUMS; bit++) {
+ if (((combine_type >> bit) & 0x01) == 0x01) {
+ /* Weather data format: [len + key] */
+ weather_key_len = strlen(weather_key[bit]);
+ ble_evt_buffer[ble_evt_buffer_len] = weather_key_len;
+ memcpy(&ble_evt_buffer[ble_evt_buffer_len + 1], weather_key[bit], weather_key_len);
+
+ ble_evt_buffer_len += (1 + weather_key_len);
+ }
+ }
+
+ /* Fill request n_days */
+ weather_key_len = sprintf((char *)&ble_evt_buffer[ble_evt_buffer_len + 1], "w.date.%d", n_days);
+ ble_evt_buffer[ble_evt_buffer_len] = weather_key_len;
+ ble_evt_buffer_len += (1 + weather_key_len);
+
+ TUYA_BLE_LOG_DEBUG("request weather location=[%d] type=[0x%x], n_days=[%d]", location_type, combine_type, n_days);
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("request weather data :", ble_evt_buffer, ble_evt_buffer_len);
+
+ event.hdr.event = TUYA_BLE_EVT_WEATHER_DATA_REQ;
+ event.weather_req_data.p_data = ble_evt_buffer;
+ event.weather_req_data.data_len = ble_evt_buffer_len;
+
+ if (tuya_ble_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_event_send weather req data error");
+ tuya_ble_free(ble_evt_buffer);
+ return TUYA_BLE_ERR_NO_EVENT;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+
+tuya_ble_status_t tuya_ble_feature_weather_data_request(uint32_t combine_type, uint8_t n_days)
+{
+ return tuya_ble_feature_weather_data_request_with_location(WLT_APP_CURRENT_LOCATION, combine_type, n_days);
+}
+
+
+void tuya_ble_handle_weather_data_request_evt(tuya_ble_evt_param_t *evt)
+{
+ uint8_t encry_mode = 0;
+
+ encry_mode = (tuya_ble_pair_rand_valid_get()) ? (ENCRYPTION_MODE_SESSION_KEY) : (ENCRYPTION_MODE_KEY_4);
+
+ tuya_ble_commData_send(FRM_WEATHER_DATA_REQUEST, 0, evt->weather_req_data.p_data, evt->weather_req_data.data_len, encry_mode);
+
+ if (evt->weather_req_data.p_data) {
+ tuya_ble_free(evt->weather_req_data.p_data);
+ }
+}
+
+
+void tuya_ble_handle_weather_data_request_response(uint8_t *recv_data, uint16_t recv_len)
+{
+ tuya_ble_cb_evt_param_t event;
+ uint16_t data_len = recv_data[11] << 8 | recv_data[12];
+
+ if (data_len != 1) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_weather_data_request_response- invalid data len received.");
+ return;
+ }
+
+ event.evt = TUYA_BLE_CB_EVT_WEATHER_DATA_REQ_RESPONSE;
+ event.weather_req_response_data.status = recv_data[13];
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_weather_data_request_response-tuya ble send cb event failed.");
+ } else {
+
+ }
+}
+
+
+void tuya_ble_handle_weather_data_received(uint8_t *recv_data, uint16_t recv_len)
+{
+ uint8_t p_buf[1];
+ uint16_t data_len = 0;
+ uint32_t ack_sn = 0;
+ tuya_ble_cb_evt_param_t event;
+ uint16_t weather_data_start_pos, weather_data_len;
+ uint16_t buffer_len, object_count;
+
+ ack_sn = recv_data[1] << 24;
+ ack_sn += recv_data[2] << 16;
+ ack_sn += recv_data[3] << 8;
+ ack_sn += recv_data[4];
+
+ data_len = (recv_data[11] << 8) | recv_data[12];
+
+ if ((data_len < 5) || (data_len > TUYA_BLE_RECEIVE_MAX_DATA_LEN)) {
+ TUYA_BLE_LOG_ERROR("cmd weather data write error,receive data len == %d", data_len);
+ p_buf[0] = 0x01;
+ tuya_ble_commData_send(FRM_WEATHER_DATA_RECEIVED_RESP, ack_sn, p_buf, 1, ENCRYPTION_MODE_SESSION_KEY);
+ return;
+ } else if (recv_data[13] != 0x00) {
+ TUYA_BLE_LOG_ERROR("cmd weather data write error, version not support");
+ p_buf[0] = 0x01;
+ tuya_ble_commData_send(FRM_WEATHER_DATA_RECEIVED_RESP, ack_sn, p_buf, 1, ENCRYPTION_MODE_SESSION_KEY);
+ return;
+ } else if ((recv_data[14] >= WLT_MAX) || (recv_data[14] == WLT_CUSTOM_LOCATION)) {
+ TUYA_BLE_LOG_ERROR("cmd weather data write error, location type this sdk version unsupport");
+ p_buf[0] = 0x01;
+ tuya_ble_commData_send(FRM_WEATHER_DATA_RECEIVED_RESP, ack_sn, p_buf, 1, ENCRYPTION_MODE_SESSION_KEY);
+ return;
+ } else if (recv_data[14] != cur_req_weather_location_type) {
+ TUYA_BLE_LOG_ERROR("cmd weather data write error, location type no correspondence");
+ p_buf[0] = 0x01;
+ tuya_ble_commData_send(FRM_WEATHER_DATA_RECEIVED_RESP, ack_sn, p_buf, 1, ENCRYPTION_MODE_SESSION_KEY);
+ return;
+ }
+
+ TUYA_BLE_LOG_HEXDUMP_DEBUG("cmd weather data write : ", recv_data + 13, data_len);
+
+ /* parse location info */
+ weather_data_start_pos = 15;
+ weather_data_len = (data_len - 2);
+
+ uint8_t *ble_cb_evt_buffer = (uint8_t *)tuya_ble_malloc(weather_data_len);
+ if (ble_cb_evt_buffer == NULL) {
+ TUYA_BLE_LOG_ERROR("ble_cb_evt_buffer malloc failed.");
+ p_buf[0] = 0x01;
+ tuya_ble_commData_send(FRM_WEATHER_DATA_RECEIVED_RESP, ack_sn, p_buf, 1, ENCRYPTION_MODE_SESSION_KEY);
+ return;
+ }
+
+ if (weather_data_lktlv_parse(&recv_data[weather_data_start_pos], weather_data_len, ble_cb_evt_buffer, &buffer_len, &object_count) != TUYA_BLE_SUCCESS) {
+ tuya_ble_free(ble_cb_evt_buffer);
+
+ TUYA_BLE_LOG_ERROR("cmd weather data parse failed");
+ p_buf[0] = 0x01;
+ tuya_ble_commData_send(FRM_WEATHER_DATA_RECEIVED_RESP, ack_sn, p_buf, 1, ENCRYPTION_MODE_SESSION_KEY);
+ return;
+ }
+
+ event.evt = TUYA_BLE_CB_EVT_WEATHER_DATA_RECEIVED;
+ event.weather_received_data.object_count = object_count;
+ event.weather_received_data.location = recv_data[14];
+ event.weather_received_data.p_data = ble_cb_evt_buffer;
+ event.weather_received_data.data_len = buffer_len;
+
+ if (tuya_ble_cb_event_send(&event) != 0) {
+ tuya_ble_free(ble_cb_evt_buffer);
+ TUYA_BLE_LOG_ERROR("tuya_ble_handle_weather_data_received-tuya ble send cb event failed.");
+
+ p_buf[0] = 0x01;
+ tuya_ble_commData_send(FRM_WEATHER_DATA_RECEIVED_RESP, ack_sn, p_buf, 1, ENCRYPTION_MODE_SESSION_KEY);
+ } else {
+ p_buf[0] = 0x00;
+ tuya_ble_commData_send(FRM_WEATHER_DATA_RECEIVED_RESP, ack_sn, p_buf, 1, ENCRYPTION_MODE_SESSION_KEY);
+ }
+}
+
+#else
+
+void tuya_ble_handle_weather_data_request_evt(tuya_ble_evt_param_t *evt)
+{
+
+}
+
+void tuya_ble_handle_weather_data_request_response(uint8_t *recv_data, uint16_t recv_len)
+{
+
+}
+
+void tuya_ble_handle_weather_data_received(uint8_t *recv_data, uint16_t recv_len)
+{
+
+}
+
+#endif
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_gatt_send_queue.c b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_gatt_send_queue.c
new file mode 100644
index 0000000..0646711
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_gatt_send_queue.c
@@ -0,0 +1,125 @@
+/**
+ * \file tuya_ble_gatt_send_queue.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_gatt_send_queue.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_config.h"
+#include "tuya_ble_port.h"
+#include "tuya_ble_mem.h"
+#include "tuya_ble_main.h"
+#include "tuya_ble_log.h"
+
+static tuya_ble_queue_t gatt_send_queue;
+static tuya_ble_gatt_send_data_t send_buf[TUYA_BLE_GATT_SEND_DATA_QUEUE_SIZE];
+
+static volatile uint8_t gatt_queue_flag = 0;
+
+void tuya_ble_gatt_send_queue_init(void)
+{
+ gatt_queue_flag = 0;
+ tuya_ble_queue_init(&gatt_send_queue, (void *) send_buf, TUYA_BLE_GATT_SEND_DATA_QUEUE_SIZE, sizeof(tuya_ble_gatt_send_data_t));
+}
+
+static void tuya_ble_gatt_send_queue_free(void)
+{
+ tuya_ble_gatt_send_data_t data = {0};
+ memset(&data, 0, sizeof(tuya_ble_gatt_send_data_t));
+ while (tuya_ble_dequeue(&gatt_send_queue, &data) == TUYA_BLE_SUCCESS) {
+ if (data.buf) {
+ tuya_ble_free(data.buf);
+ }
+ memset(&data, 0, sizeof(tuya_ble_gatt_send_data_t));
+ }
+ TUYA_BLE_LOG_DEBUG("tuya_ble_gatt_send_queue_free execute.");
+}
+
+void tuya_ble_gatt_send_data_handle(void *evt)
+{
+ tuya_ble_gatt_send_data_t data = {0};
+ tuya_ble_evt_param_t event;
+ tuya_ble_connect_status_t currnet_connect_status;
+
+ while (tuya_ble_queue_get(&gatt_send_queue, &data) == TUYA_BLE_SUCCESS) {
+ currnet_connect_status = tuya_ble_connect_status_get();
+ if ((currnet_connect_status == BONDING_UNCONN) || (currnet_connect_status == UNBONDING_UNCONN)) {
+ tuya_ble_gatt_send_queue_free();
+ break;
+ }
+
+ if (tuya_ble_gatt_send_data(data.buf, data.size) == TUYA_BLE_SUCCESS) {
+ tuya_ble_free(data.buf);
+ tuya_ble_queue_decrease(&gatt_send_queue);
+ } else {
+ event.hdr.event = TUYA_BLE_EVT_GATT_SEND_DATA;
+ event.hdr.event_handler = tuya_ble_gatt_send_data_handle;
+ if (tuya_ble_event_send(&event) != 0) {
+ tuya_ble_gatt_send_queue_free();
+ TUYA_BLE_LOG_ERROR("TUYA_BLE_EVT_GATT_SEND_DATA error.");
+ }
+
+ break;
+
+ }
+ }
+ if (tuya_ble_get_queue_used(&gatt_send_queue) == 0) {
+ tuya_ble_queue_flush(&gatt_send_queue);
+ gatt_queue_flag = 0;
+ }
+
+}
+
+
+
+tuya_ble_status_t tuya_ble_gatt_send_data_enqueue(uint8_t *p_data, uint8_t data_len)
+{
+ tuya_ble_gatt_send_data_t data = {0};
+
+ data.buf = tuya_ble_malloc(data_len);
+
+ if (data.buf) {
+ memcpy(data.buf, p_data, data_len);
+ data.size = data_len;
+ if (tuya_ble_enqueue(&gatt_send_queue, &data) == TUYA_BLE_SUCCESS) {
+ if (gatt_queue_flag == 0) {
+ gatt_queue_flag = 1;
+ tuya_ble_gatt_send_data_handle(NULL);
+ }
+ return TUYA_BLE_SUCCESS;
+ } else {
+ tuya_ble_free(data.buf);
+ return TUYA_BLE_ERR_NO_MEM;
+ }
+ } else {
+ return TUYA_BLE_ERR_NO_MEM;
+ }
+
+}
+
+uint32_t tuya_ble_get_gatt_send_queue_used(void)
+{
+ return tuya_ble_get_queue_used(&gatt_send_queue);
+}
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_heap.c b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_heap.c
new file mode 100644
index 0000000..d4c475d
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_heap.c
@@ -0,0 +1,366 @@
+/*
+ * FreeRTOS Kernel V10.0.0
+ * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. If you wish to use our Amazon
+ * FreeRTOS name, please do so in a fair use way that does not cause confusion.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * http://www.FreeRTOS.org
+ * http://aws.amazon.com/freertos
+ *
+ * 1 tab == 4 spaces!
+ */
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_heap.h"
+#include "tuya_ble_port.h"
+#include "tuya_ble_internal_config.h"
+
+#if (TUYA_BLE_USE_PLATFORM_MEMORY_HEAP==0)
+
+/* Block sizes must not get too small. */
+#define heapMINIMUM_BLOCK_SIZE ( ( uint32_t ) ( xHeapStructSize << 1 ) )
+
+/* Assumes 8bit bytes! */
+#define heapBITS_PER_BYTE ( ( uint32_t ) 8 )
+
+static uint8_t ucHeap[ TUYA_BLE_TOTAL_HEAP_SIZE ];
+
+
+/* Define the linked list structure. This is used to link free blocks in order
+of their memory address. */
+typedef struct A_BLOCK_LINK {
+ struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */
+ uint32_t xBlockSize; /*<< The size of the free block. */
+} BlockLink_t;
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Inserts a block of memory that is being freed into the correct position in
+ * the list of free memory blocks. The block being freed will be merged with
+ * the block in front it and/or the block behind it if the memory blocks are
+ * adjacent to each other.
+ */
+static void prvInsertBlockIntoFreeList(BlockLink_t *pxBlockToInsert);
+
+/*
+ * Called automatically to setup the required heap structures the first time
+ * pvPortMalloc() is called.
+ */
+static void prvHeapInit(void);
+
+/*-----------------------------------------------------------*/
+
+/* The size of the structure placed at the beginning of each allocated memory
+block must by correctly byte aligned. */
+static const uint32_t xHeapStructSize = (sizeof(BlockLink_t) + ((uint32_t)(portBYTE_ALIGNMENT - 1))) & ~((uint32_t) portBYTE_ALIGNMENT_MASK);
+
+/* Create a couple of list links to mark the start and end of the list. */
+static BlockLink_t xStart, *pxEnd = NULL;
+
+/* Keeps track of the number of free bytes remaining, but says nothing about
+fragmentation. */
+static uint32_t xFreeBytesRemaining = 0U;
+static uint32_t xMinimumEverFreeBytesRemaining = 0U;
+
+/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize
+member of an BlockLink_t structure is set then the block belongs to the
+application. When the bit is free the block is still part of the free heap
+space. */
+static uint32_t xBlockAllocatedBit = 0;
+
+/*-----------------------------------------------------------*/
+
+void *pvTuyaPortMalloc(uint32_t xWantedSize)
+{
+ BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
+ void *pvReturn = NULL;
+
+ tuya_ble_device_enter_critical();
+ {
+ /* If this is the first call to malloc then the heap will require
+ initialisation to setup the list of free blocks. */
+ if (pxEnd == NULL) {
+ prvHeapInit();
+ } else {
+ tuyaCOVERAGE_TEST_MARKER();
+ }
+
+ /* Check the requested block size is not so large that the top bit is
+ set. The top bit of the block size member of the BlockLink_t structure
+ is used to determine who owns the block - the application or the
+ kernel, so it must be free. */
+ if ((xWantedSize & xBlockAllocatedBit) == 0) {
+ /* The wanted size is increased so it can contain a BlockLink_t
+ structure in addition to the requested amount of bytes. */
+ if (xWantedSize > 0) {
+ xWantedSize += xHeapStructSize;
+
+ /* Ensure that blocks are always aligned to the required number
+ of bytes. */
+ if ((xWantedSize & portBYTE_ALIGNMENT_MASK) != 0x00) {
+ /* Byte alignment required. */
+ xWantedSize += (portBYTE_ALIGNMENT - (xWantedSize & portBYTE_ALIGNMENT_MASK));
+ tuyaASSERT((xWantedSize & portBYTE_ALIGNMENT_MASK) == 0);
+ } else {
+ tuyaCOVERAGE_TEST_MARKER();
+ }
+ } else {
+ tuyaCOVERAGE_TEST_MARKER();
+ }
+
+ if ((xWantedSize > 0) && (xWantedSize <= xFreeBytesRemaining)) {
+ /* Traverse the list from the start (lowest address) block until
+ one of adequate size is found. */
+ pxPreviousBlock = &xStart;
+ pxBlock = xStart.pxNextFreeBlock;
+ while ((pxBlock->xBlockSize < xWantedSize) && (pxBlock->pxNextFreeBlock != NULL)) {
+ pxPreviousBlock = pxBlock;
+ pxBlock = pxBlock->pxNextFreeBlock;
+ }
+
+ /* If the end marker was reached then a block of adequate size
+ was not found. */
+ if (pxBlock != pxEnd) {
+ /* Return the memory space pointed to - jumping over the
+ BlockLink_t structure at its start. */
+ pvReturn = (void *)(((uint8_t *) pxPreviousBlock->pxNextFreeBlock) + xHeapStructSize);
+
+ /* This block is being returned for use so must be taken out
+ of the list of free blocks. */
+ pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
+
+ /* If the block is larger than required it can be split into
+ two. */
+ if ((pxBlock->xBlockSize - xWantedSize) > heapMINIMUM_BLOCK_SIZE) {
+ /* This block is to be split into two. Create a new
+ block following the number of bytes requested. The void
+ cast is used to prevent byte alignment warnings from the
+ compiler. */
+ pxNewBlockLink = (void *)(((uint8_t *) pxBlock) + xWantedSize);
+ tuyaASSERT((((uint32_t) pxNewBlockLink) & portBYTE_ALIGNMENT_MASK) == 0);
+
+ /* Calculate the sizes of two blocks split from the
+ single block. */
+ pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
+ pxBlock->xBlockSize = xWantedSize;
+
+ /* Insert the new block into the list of free blocks. */
+ prvInsertBlockIntoFreeList(pxNewBlockLink);
+ } else {
+ tuyaCOVERAGE_TEST_MARKER();
+ }
+
+ xFreeBytesRemaining -= pxBlock->xBlockSize;
+
+ if (xFreeBytesRemaining < xMinimumEverFreeBytesRemaining) {
+ xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
+ } else {
+ tuyaCOVERAGE_TEST_MARKER();
+ }
+
+ /* The block is being returned - it is allocated and owned
+ by the application and has no "next" block. */
+ pxBlock->xBlockSize |= xBlockAllocatedBit;
+ pxBlock->pxNextFreeBlock = NULL;
+ } else {
+ tuyaCOVERAGE_TEST_MARKER();
+ }
+ } else {
+ tuyaCOVERAGE_TEST_MARKER();
+ }
+ } else {
+ tuyaCOVERAGE_TEST_MARKER();
+ }
+
+ tuya_traceMALLOC(pvReturn, xWantedSize);
+ }
+ (void) tuya_ble_device_exit_critical();
+
+#if( tuyaUSE_MALLOC_FAILED_HOOK == 1 )
+ {
+ if (pvReturn == NULL) {
+ extern void vApplicationMallocFailedHook(void);
+ vApplicationMallocFailedHook();
+ } else {
+ tuyaCOVERAGE_TEST_MARKER();
+ }
+ }
+#endif
+
+ tuyaASSERT((((uint32_t) pvReturn) & (uint32_t) portBYTE_ALIGNMENT_MASK) == 0);
+ return pvReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vTuyaPortFree(void *pv)
+{
+ uint8_t *puc = (uint8_t *) pv;
+ BlockLink_t *pxLink;
+
+ if (pv != NULL) {
+ /* The memory being freed will have an BlockLink_t structure immediately
+ before it. */
+ puc -= xHeapStructSize;
+
+ /* This casting is to keep the compiler from issuing warnings. */
+ pxLink = (void *) puc;
+
+ /* Check the block is actually allocated. */
+ tuyaASSERT((pxLink->xBlockSize & xBlockAllocatedBit) != 0);
+ tuyaASSERT(pxLink->pxNextFreeBlock == NULL);
+
+ if ((pxLink->xBlockSize & xBlockAllocatedBit) != 0) {
+ if (pxLink->pxNextFreeBlock == NULL) {
+ /* The block is being returned to the heap - it is no longer
+ allocated. */
+ pxLink->xBlockSize &= ~xBlockAllocatedBit;
+
+ tuya_ble_device_enter_critical();
+ {
+ /* Add this block to the list of free blocks. */
+ xFreeBytesRemaining += pxLink->xBlockSize;
+ tuya_traceFREE(pv, pxLink->xBlockSize);
+ prvInsertBlockIntoFreeList(((BlockLink_t *) pxLink));
+ }
+ (void) tuya_ble_device_exit_critical();
+ } else {
+ tuyaCOVERAGE_TEST_MARKER();
+ }
+ } else {
+ tuyaCOVERAGE_TEST_MARKER();
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+uint32_t xTuyaPortGetFreeHeapSize(void)
+{
+ return xFreeBytesRemaining;
+}
+/*-----------------------------------------------------------*/
+
+uint32_t xTuyaPortGetMinimumEverFreeHeapSize(void)
+{
+ return xMinimumEverFreeBytesRemaining;
+}
+/*-----------------------------------------------------------*/
+
+void vTuyaPortInitialiseBlocks(void)
+{
+ /* This just exists to keep the linker quiet. */
+}
+/*-----------------------------------------------------------*/
+
+static void prvHeapInit(void)
+{
+ BlockLink_t *pxFirstFreeBlock;
+ uint8_t *pucAlignedHeap;
+ uint32_t uxAddress;
+ uint32_t xTotalHeapSize = TUYA_BLE_TOTAL_HEAP_SIZE;
+
+ /* Ensure the heap starts on a correctly aligned boundary. */
+ uxAddress = (uint32_t) ucHeap;
+
+ if ((uxAddress & portBYTE_ALIGNMENT_MASK) != 0) {
+ uxAddress += (portBYTE_ALIGNMENT - 1);
+ uxAddress &= ~((uint32_t) portBYTE_ALIGNMENT_MASK);
+ xTotalHeapSize -= uxAddress - (uint32_t) ucHeap;
+ }
+
+ pucAlignedHeap = (uint8_t *) uxAddress;
+
+ /* xStart is used to hold a pointer to the first item in the list of free
+ blocks. The void cast is used to prevent compiler warnings. */
+ xStart.pxNextFreeBlock = (void *) pucAlignedHeap;
+ xStart.xBlockSize = (uint32_t) 0;
+
+ /* pxEnd is used to mark the end of the list of free blocks and is inserted
+ at the end of the heap space. */
+ uxAddress = ((uint32_t) pucAlignedHeap) + xTotalHeapSize;
+ uxAddress -= xHeapStructSize;
+ uxAddress &= ~((uint32_t) portBYTE_ALIGNMENT_MASK);
+ pxEnd = (void *) uxAddress;
+ pxEnd->xBlockSize = 0;
+ pxEnd->pxNextFreeBlock = NULL;
+
+ /* To start with there is a single free block that is sized to take up the
+ entire heap space, minus the space taken by pxEnd. */
+ pxFirstFreeBlock = (void *) pucAlignedHeap;
+ pxFirstFreeBlock->xBlockSize = uxAddress - (uint32_t) pxFirstFreeBlock;
+ pxFirstFreeBlock->pxNextFreeBlock = pxEnd;
+
+ /* Only one block exists - and it covers the entire usable heap space. */
+ xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
+ xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
+
+ /* Work out the position of the top bit in a size_t variable. */
+ xBlockAllocatedBit = ((uint32_t) 1) << ((sizeof(uint32_t) * heapBITS_PER_BYTE) - 1);
+}
+/*-----------------------------------------------------------*/
+
+static void prvInsertBlockIntoFreeList(BlockLink_t *pxBlockToInsert)
+{
+ BlockLink_t *pxIterator;
+ uint8_t *puc;
+
+ /* Iterate through the list until a block is found that has a higher address
+ than the block being inserted. */
+ for (pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock) {
+ /* Nothing to do here, just iterate to the right position. */
+ }
+
+ /* Do the block being inserted, and the block it is being inserted after
+ make a contiguous block of memory? */
+ puc = (uint8_t *) pxIterator;
+ if ((puc + pxIterator->xBlockSize) == (uint8_t *) pxBlockToInsert) {
+ pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
+ pxBlockToInsert = pxIterator;
+ } else {
+ tuyaCOVERAGE_TEST_MARKER();
+ }
+
+ /* Do the block being inserted, and the block it is being inserted before
+ make a contiguous block of memory? */
+ puc = (uint8_t *) pxBlockToInsert;
+ if ((puc + pxBlockToInsert->xBlockSize) == (uint8_t *) pxIterator->pxNextFreeBlock) {
+ if (pxIterator->pxNextFreeBlock != pxEnd) {
+ /* Form one big block from the two blocks. */
+ pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
+ pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
+ } else {
+ pxBlockToInsert->pxNextFreeBlock = pxEnd;
+ }
+ } else {
+ pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
+ }
+
+ /* If the block being inserted plugged a gab, so was merged with the block
+ before and the block after, then it's pxNextFreeBlock pointer will have
+ already been set, and should not be set here as that would make it point
+ to itself. */
+ if (pxIterator != pxBlockToInsert) {
+ pxIterator->pxNextFreeBlock = pxBlockToInsert;
+ } else {
+ tuyaCOVERAGE_TEST_MARKER();
+ }
+}
+
+#endif
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_main.c b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_main.c
new file mode 100644
index 0000000..261af5c
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_main.c
@@ -0,0 +1,1027 @@
+/**
+ * \file tuya_ble_main.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_heap.h"
+#include "tuya_ble_mem.h"
+#include "tuya_ble_api.h"
+#include "tuya_ble_port.h"
+#include "tuya_ble_main.h"
+#include "tuya_ble_secure.h"
+#include "tuya_ble_data_handler.h"
+#include "tuya_ble_storage.h"
+#include "tuya_ble_sdk_version.h"
+#include "tuya_ble_event.h"
+#include "tuya_ble_utils.h"
+#include "tuya_ble_app_uart_common_handler.h"
+#include "tuya_ble_app_production_test.h"
+#include "tuya_ble_log.h"
+#include "tuya_ble_internal_config.h"
+
+tuya_ble_parameters_settings_t tuya_ble_current_para;
+
+
+static volatile tuya_ble_connect_status_t tuya_ble_connect_status = UNKNOW_STATUS;
+
+#if TUYA_BLE_LINK_LAYER_ENCRYPTION_SUPPORT_ENABLE
+static volatile tuya_ble_link_status_t tuya_ble_link_status = LINK_UNKNOW_STATUS;
+#endif
+
+#if TUYA_BLE_USE_OS
+
+uint32_t m_cb_queue_table[TUYA_BLE_MAX_CALLBACKS];
+
+#else
+tuya_ble_callback_t m_cb_table[TUYA_BLE_MAX_CALLBACKS];
+#endif
+
+
+void tuya_ble_connect_status_set(tuya_ble_connect_status_t status)
+{
+ tuya_ble_device_enter_critical();
+ tuya_ble_connect_status = status;
+ tuya_ble_device_exit_critical();
+
+}
+
+tuya_ble_connect_status_t tuya_ble_connect_status_get(void)
+{
+ return tuya_ble_connect_status;
+}
+
+#if TUYA_BLE_LINK_LAYER_ENCRYPTION_SUPPORT_ENABLE
+
+void tuya_ble_link_status_set(tuya_ble_link_status_t status)
+{
+ tuya_ble_device_enter_critical();
+ tuya_ble_link_status = status;
+ tuya_ble_device_exit_critical();
+}
+
+tuya_ble_link_status_t tuya_ble_link_status_get(void)
+{
+ return tuya_ble_link_status;
+}
+
+#endif
+
+tuya_ble_timer_t tuya_ble_xtimer_connect_monitor;
+
+#define tuya_ble_connect_monitor_timeout_ms 30000
+
+static void tuya_ble_vtimer_conncet_monitor_callback(tuya_ble_timer_t timer)
+{
+ tuya_ble_connect_status_t connect_state = tuya_ble_connect_status_get();
+
+ if ((connect_state == UNBONDING_UNAUTH_CONN) || (connect_state == BONDING_UNAUTH_CONN)) {
+ TUYA_BLE_LOG_DEBUG("ble disconncet because monitor timer timeout.");
+ tuya_ble_gap_disconnect();
+ }
+
+}
+
+
+void tuya_ble_connect_monitor_timer_init(void)
+{
+ if (tuya_ble_timer_create(&tuya_ble_xtimer_connect_monitor, tuya_ble_connect_monitor_timeout_ms, TUYA_BLE_TIMER_SINGLE_SHOT, tuya_ble_vtimer_conncet_monitor_callback) != TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_xtimer_connect_monitor creat failed");
+ }
+
+}
+
+
+void tuya_ble_connect_monitor_timer_start(void)
+{
+ if (tuya_ble_timer_start(tuya_ble_xtimer_connect_monitor) != TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_xtimer_connect_monitor start failed");
+ }
+
+}
+
+
+void tuya_ble_connect_monitor_timer_stop(void)
+{
+
+ if (tuya_ble_timer_stop(tuya_ble_xtimer_connect_monitor) != TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_ERROR("tuya_ble_xtimer_connect_monitor start failed");
+ }
+
+}
+
+
+#if TUYA_BLE_USE_OS
+
+#if TUYA_BLE_SELF_BUILT_TASK
+void *tuya_ble_task_handle; //!< APP Task handle
+void *tuya_ble_queue_handle; //!< Event queue handle
+
+static void tuya_ble_main_task(void *p_param)
+{
+ tuya_ble_evt_param_t tuya_ble_evt;
+ uint32_t i = 0;
+
+ while (true) {
+ if (tuya_ble_os_msg_queue_recv(tuya_ble_queue_handle, &tuya_ble_evt, 0xFFFFFFFF) == true) {
+ //printf("task event:%d", tuya_ble_evt.hdr.event);
+ tuya_ble_event_process(&tuya_ble_evt);
+
+ }
+
+ }
+
+}
+#endif
+
+#else
+
+void tuya_ble_main_tasks_exec(void)
+{
+ tuya_sched_execute();
+}
+#endif
+
+
+
+
+void tuya_ble_event_init(void)
+{
+#if TUYA_BLE_USE_OS
+
+#if TUYA_BLE_SELF_BUILT_TASK
+ tuya_ble_os_task_create(&tuya_ble_task_handle, "tuya", tuya_ble_main_task, 0, TUYA_BLE_TASK_STACK_SIZE, TUYA_BLE_TASK_PRIORITY);
+ tuya_ble_os_msg_queue_create(&tuya_ble_queue_handle, MAX_NUMBER_OF_TUYA_MESSAGE, sizeof(tuya_ble_evt_param_t));
+#endif
+
+#else
+ tuya_ble_event_queue_init();
+#endif
+
+#if TUYA_BLE_USE_OS
+ for (uint8_t i = 0; i < TUYA_BLE_MAX_CALLBACKS; i++) {
+ m_cb_queue_table[i] = 0;
+ }
+
+#else
+ for (uint8_t i = 0; i < TUYA_BLE_MAX_CALLBACKS; i++) {
+ m_cb_table[i] = NULL;
+ }
+#endif
+
+}
+
+
+uint8_t tuya_ble_event_send(tuya_ble_evt_param_t *evt)
+{
+#if TUYA_BLE_USE_OS
+
+#if TUYA_BLE_SELF_BUILT_TASK
+ if (tuya_ble_os_msg_queue_send(tuya_ble_queue_handle, evt, 0)) {
+ return 0;
+ } else {
+ return 1;
+ }
+#else
+ if (tuya_ble_event_queue_send_port(evt, 0)) {
+ return 0;
+ } else {
+ return 1;
+ }
+#endif
+
+#else
+ if (tuya_ble_message_send(evt) == TUYA_BLE_SUCCESS) {
+ return 0;
+ } else {
+ return 1;
+ }
+#endif
+}
+
+
+uint8_t tuya_ble_custom_event_send(tuya_ble_custom_evt_t evt)
+{
+ static tuya_ble_evt_param_t event;
+ uint8_t ret = 0;
+
+#if TUYA_BLE_USE_OS
+ event.hdr.event = TUYA_BLE_EVT_CUSTOM;
+ event.custom_evt = evt;
+
+#if TUYA_BLE_SELT_BUILT_TASK
+ if (tuya_ble_os_msg_queue_send(tuya_ble_queue_handle, &event, 0)) {
+ return 0;
+ } else {
+ return 1;
+ }
+#else
+ if (tuya_ble_event_queue_send_port(&event, 0)) {
+ return 0;
+ } else {
+ return 1;
+ }
+#endif
+
+#else
+
+ event.hdr.event = TUYA_BLE_EVT_CUSTOM;
+ event.custom_evt = evt;
+
+ if (tuya_ble_message_send(&event) == TUYA_BLE_SUCCESS) {
+ ret = 0;
+ } else {
+ ret = 1;
+ }
+
+ return ret;
+#endif
+}
+
+
+
+tuya_ble_status_t tuya_ble_inter_event_response(tuya_ble_cb_evt_param_t *param)
+{
+
+ switch (param->evt) {
+ case TUYA_BLE_CB_EVT_CONNECTE_STATUS:
+ break;
+ case TUYA_BLE_CB_EVT_DP_WRITE:
+ if (param->dp_write_data.p_data) {
+ tuya_ble_free(param->dp_write_data.p_data);
+ }
+ break;
+ case TUYA_BLE_CB_EVT_DP_DATA_RECEIVED:
+ if (param->dp_received_data.p_data) {
+ tuya_ble_free(param->dp_received_data.p_data);
+ }
+ break;
+ case TUYA_BLE_CB_EVT_DP_QUERY:
+ if (param->dp_query_data.p_data) {
+ tuya_ble_free(param->dp_query_data.p_data);
+ }
+ break;
+ case TUYA_BLE_CB_EVT_OTA_DATA:
+ if (param->ota_data.p_data) {
+ tuya_ble_free(param->ota_data.p_data);
+ }
+ break;
+ case TUYA_BLE_CB_EVT_NETWORK_INFO:
+ if (param->network_data.p_data) {
+ tuya_ble_free(param->network_data.p_data);
+ }
+ break;
+ case TUYA_BLE_CB_EVT_WIFI_SSID:
+ if (param->wifi_info_data.p_data) {
+ tuya_ble_free(param->wifi_info_data.p_data);
+ }
+ break;
+ case TUYA_BLE_CB_EVT_TIME_STAMP:
+ break;
+ case TUYA_BLE_CB_EVT_TIME_NORMAL:
+ break;
+ case TUYA_BLE_CB_EVT_APP_LOCAL_TIME_NORMAL:
+ break;
+ case TUYA_BLE_CB_EVT_TIME_STAMP_WITH_DST:
+ if (param->timestamp_with_dst_data.p_data) {
+ tuya_ble_free(param->timestamp_with_dst_data.p_data);
+ }
+ break;
+ case TUYA_BLE_CB_EVT_DATA_PASSTHROUGH:
+
+ if (param->ble_passthrough_data.p_data) {
+ tuya_ble_free(param->ble_passthrough_data.p_data);
+ }
+ break;
+#if (TUYA_BLE_FEATURE_WEATHER_ENABLE != 0)
+ case TUYA_BLE_CB_EVT_WEATHER_DATA_RECEIVED:
+ if (param->weather_received_data.p_data) {
+ tuya_ble_free(param->weather_received_data.p_data);
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+
+ return TUYA_BLE_SUCCESS;
+}
+
+
+
+uint8_t tuya_ble_cb_event_send(tuya_ble_cb_evt_param_t *evt)
+{
+#if TUYA_BLE_USE_OS
+ if (m_cb_queue_table[0]) {
+ if (tuya_ble_os_msg_queue_send((void *)m_cb_queue_table[0], evt, 0)) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+#else
+ tuya_ble_callback_t fun;
+ if (m_cb_table[0]) {
+ fun = m_cb_table[0];
+ fun(evt);
+ tuya_ble_inter_event_response(evt);
+ }
+#endif
+ return 0;
+
+}
+
+
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN==4)
+
+/** @brief GAP - Advertisement data (max size = 31 bytes, best kept short to conserve power) */
+
+#define TUYA_BLE_ADV_DATA_LEN_MAX 31
+
+static const uint8_t adv_data_const[TUYA_BLE_ADV_DATA_LEN_MAX] = {
+ 0x02,
+ 0x01,
+ 0x06,
+ 0x03,
+ 0x02,
+ 0x50, 0xFD,
+ 0x17,
+ 0x16,
+ 0x50, 0xFD,
+ 0x41, 0x00, //Frame Control
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+
+#define TUYA_BLE_SCAN_RSP_DATA_LEN_MAX 31
+static const uint8_t scan_rsp_data_const[TUYA_BLE_SCAN_RSP_DATA_LEN_MAX] = {
+ 0x17, // length
+ 0xFF,
+ 0xD0,
+ 0x07,
+ 0x00, //Encry Mode(8)
+ 0x00, 0x00, //communication way bit0-mesh bit1-wifi bit2-zigbee bit3-NB
+ 0x00, //FLAG
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, //24
+ 0x09,
+ 0x54, 0x59,
+};
+
+static uint8_t adv_data[TUYA_BLE_ADV_DATA_LEN_MAX];
+static uint8_t scan_rsp_data[TUYA_BLE_SCAN_RSP_DATA_LEN_MAX];
+
+uint8_t tuya_ble_get_adv_connect_request_bit_status(void)
+{
+ return (adv_data[11] & 0x02);
+}
+
+void tuya_ble_adv_get(u8 **output_adv_data, u8 *adv_data_len, u8 **output_rsp_data, u8 *rsp_data_len)
+{
+ uint8_t *aes_buf = NULL;
+ uint8_t *p_buf = NULL;
+ uint8_t adv_data_length = 0;
+ uint8_t scan_rsp_data_length = 0;
+ uint8_t aes_key[16];
+ uint8_t encry_device_id[DEVICE_ID_LEN];
+
+ memcpy(adv_data, adv_data_const, TUYA_BLE_ADV_DATA_LEN_MAX);
+ memcpy(&scan_rsp_data, scan_rsp_data_const, TUYA_BLE_SCAN_RSP_DATA_LEN_MAX);
+
+ adv_data[7] = 7 + tuya_ble_current_para.pid_len;
+
+ adv_data[13] = tuya_ble_current_para.pid_type;
+ adv_data[14] = tuya_ble_current_para.pid_len;
+
+ if (TUYA_BLE_DEVICE_SHARED) {
+ adv_data[11] |= 0x04 ;
+ } else {
+ adv_data[11] &= (~0x04);
+ }
+
+ adv_data[11] &= (~0x02); //clear connect request bit
+
+ scan_rsp_data[4] = TUYA_BLE_SECURE_CONNECTION_TYPE;
+
+ scan_rsp_data[5] = TUYA_BLE_DEVICE_COMMUNICATION_ABILITY >> 8;
+ scan_rsp_data[6] = TUYA_BLE_DEVICE_COMMUNICATION_ABILITY;
+
+ if (tuya_ble_current_para.pid_len == 20) {
+ scan_rsp_data[7] |= 0x01 ;
+ } else {
+ scan_rsp_data[7] &= (~0x01);
+ }
+
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE==TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION)
+
+ if (TUYA_BLE_ADVANCED_ENCRYPTION_AUTH_ON_CONNECT) {
+ scan_rsp_data[7] |= 0x02 ;
+ } else {
+ scan_rsp_data[7] &= (~0x02);
+ }
+
+#endif
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) {
+ adv_data[11] |= 0x08 ;
+ //
+ memcpy(aes_key, tuya_ble_current_para.sys_settings.login_key, LOGIN_KEY_LEN);
+ memcpy(aes_key + LOGIN_KEY_LEN, tuya_ble_current_para.auth_settings.device_id, 16 - LOGIN_KEY_LEN);
+
+ aes_buf = tuya_ble_malloc(200);
+
+ if (aes_buf == NULL) {
+ TUYA_BLE_LOG_ERROR("Malloc failed for AES BUF in adv change.");
+ return;
+ } else {
+ memset(aes_buf, 0, 200);
+ }
+
+ tuya_ble_encrypt_old_with_key(aes_key, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, aes_buf);
+
+ memcpy(&adv_data[15], (uint8_t *)(aes_buf + 1), tuya_ble_current_para.pid_len);
+
+ tuya_ble_free(aes_buf);
+
+ tuya_ble_device_id_encrypt_v4(&adv_data[11], adv_data[7] - 3, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, encry_device_id);
+
+ memcpy(&scan_rsp_data[8], encry_device_id, DEVICE_ID_LEN);
+
+ } else {
+ adv_data[11] &= (~0x08);
+
+ memcpy(&adv_data[15], tuya_ble_current_para.pid, tuya_ble_current_para.pid_len);
+ tuya_ble_device_id_encrypt_v4(&adv_data[11], adv_data[7] - 3, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, encry_device_id);
+
+ memcpy(&scan_rsp_data[8], encry_device_id, DEVICE_ID_LEN);
+ }
+
+ if (tuya_ble_current_para.adv_local_name_len > TUYA_BLE_ADV_LOCAL_NAME_MAX_LEN) {
+ tuya_ble_current_para.adv_local_name_len = TUYA_BLE_ADV_LOCAL_NAME_MAX_LEN;
+ }
+ scan_rsp_data[24] = tuya_ble_current_para.adv_local_name_len + 1;
+ scan_rsp_data[25] = 0x09;
+ memcpy(&scan_rsp_data[26], tuya_ble_current_para.adv_local_name, tuya_ble_current_para.adv_local_name_len);
+
+ TUYA_BLE_LOG_INFO("adv data changed ,current bound flag = %d", tuya_ble_current_para.sys_settings.bound_flag);
+
+ adv_data_length = tuya_ble_current_para.pid_len + 15;
+ scan_rsp_data_length = tuya_ble_current_para.adv_local_name_len + 26;
+
+ *adv_data_len = adv_data_length;
+ *rsp_data_len = scan_rsp_data_length;
+ *output_adv_data = adv_data;
+ *output_rsp_data = scan_rsp_data;
+
+#if TUYA_BLE_LINK_LAYER_ENCRYPTION_SUPPORT_ENABLE
+
+ p_buf = tuya_ble_malloc(adv_data_length + scan_rsp_data_length + 3);
+ if (p_buf == NULL) {
+ TUYA_BLE_LOG_ERROR("Malloc failed for read buf in adv change.");
+ return;
+ } else {
+ memset(p_buf, 0, adv_data_length + scan_rsp_data_length + 3);
+ p_buf[0] = 0;
+ p_buf[1] = adv_data_length + scan_rsp_data_length;
+ memcpy(&p_buf[2], adv_data, adv_data_length);
+ memcpy(&p_buf[2 + adv_data_length], scan_rsp_data, scan_rsp_data_length);
+ }
+
+ tuya_ble_device_info_characteristic_value_update(p_buf, (adv_data_length + scan_rsp_data_length + 3));
+
+ tuya_ble_free(p_buf);
+#endif
+
+}
+
+void tuya_ble_adv_change(void)
+{
+ uint8_t *aes_buf = NULL;
+ uint8_t *p_buf = NULL;
+ uint8_t adv_data_length = 0;
+ uint8_t scan_rsp_data_length = 0;
+ uint8_t aes_key[16];
+ uint8_t encry_device_id[DEVICE_ID_LEN];
+
+ memcpy(adv_data, adv_data_const, TUYA_BLE_ADV_DATA_LEN_MAX);
+ memcpy(&scan_rsp_data, scan_rsp_data_const, TUYA_BLE_SCAN_RSP_DATA_LEN_MAX);
+
+ adv_data[7] = 7 + tuya_ble_current_para.pid_len;
+
+ adv_data[13] = tuya_ble_current_para.pid_type;
+ adv_data[14] = tuya_ble_current_para.pid_len;
+
+ if (TUYA_BLE_DEVICE_SHARED) {
+ adv_data[11] |= 0x04 ;
+ } else {
+ adv_data[11] &= (~0x04);
+ }
+
+ adv_data[11] &= (~0x02); //clear connect request bit
+
+
+ scan_rsp_data[4] = TUYA_BLE_SECURE_CONNECTION_TYPE;
+
+ scan_rsp_data[5] = TUYA_BLE_DEVICE_COMMUNICATION_ABILITY >> 8;
+ scan_rsp_data[6] = TUYA_BLE_DEVICE_COMMUNICATION_ABILITY;
+
+ if (tuya_ble_current_para.pid_len == 20) {
+ scan_rsp_data[7] |= 0x01 ;
+ } else {
+ scan_rsp_data[7] &= (~0x01);
+ }
+
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE==TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION)
+
+ if (TUYA_BLE_ADVANCED_ENCRYPTION_AUTH_ON_CONNECT) {
+ scan_rsp_data[7] |= 0x02 ;
+ } else {
+ scan_rsp_data[7] &= (~0x02);
+ }
+
+#endif
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) {
+ adv_data[11] |= 0x08 ;
+ //
+ memcpy(aes_key, tuya_ble_current_para.sys_settings.login_key, LOGIN_KEY_LEN);
+ memcpy(aes_key + LOGIN_KEY_LEN, tuya_ble_current_para.auth_settings.device_id, 16 - LOGIN_KEY_LEN);
+
+ aes_buf = tuya_ble_malloc(200);
+
+ if (aes_buf == NULL) {
+ TUYA_BLE_LOG_ERROR("Malloc failed for AES BUF in adv change.");
+ return;
+ } else {
+ memset(aes_buf, 0, 200);
+ }
+
+ tuya_ble_encrypt_old_with_key(aes_key, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, aes_buf);
+
+ memcpy(&adv_data[15], (uint8_t *)(aes_buf + 1), tuya_ble_current_para.pid_len);
+
+ tuya_ble_free(aes_buf);
+
+ tuya_ble_device_id_encrypt_v4(&adv_data[11], adv_data[7] - 3, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, encry_device_id);
+
+ memcpy(&scan_rsp_data[8], encry_device_id, DEVICE_ID_LEN);
+
+ } else {
+ adv_data[11] &= (~0x08);
+
+ memcpy(&adv_data[15], tuya_ble_current_para.pid, tuya_ble_current_para.pid_len);
+ tuya_ble_device_id_encrypt_v4(&adv_data[11], adv_data[7] - 3, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, encry_device_id);
+
+ memcpy(&scan_rsp_data[8], encry_device_id, DEVICE_ID_LEN);
+ }
+
+ if (tuya_ble_current_para.adv_local_name_len > TUYA_BLE_ADV_LOCAL_NAME_MAX_LEN) {
+ tuya_ble_current_para.adv_local_name_len = TUYA_BLE_ADV_LOCAL_NAME_MAX_LEN;
+ }
+ scan_rsp_data[24] = tuya_ble_current_para.adv_local_name_len + 1;
+ scan_rsp_data[25] = 0x09;
+ memcpy(&scan_rsp_data[26], tuya_ble_current_para.adv_local_name, tuya_ble_current_para.adv_local_name_len);
+
+ TUYA_BLE_LOG_INFO("adv data changed ,current bound flag = %d", tuya_ble_current_para.sys_settings.bound_flag);
+
+ adv_data_length = tuya_ble_current_para.pid_len + 15;
+ scan_rsp_data_length = tuya_ble_current_para.adv_local_name_len + 26;
+
+ tuya_ble_gap_advertising_adv_data_update(adv_data, adv_data_length);
+ tuya_ble_gap_advertising_scan_rsp_data_update(scan_rsp_data, scan_rsp_data_length);
+
+#if TUYA_BLE_LINK_LAYER_ENCRYPTION_SUPPORT_ENABLE
+
+ p_buf = tuya_ble_malloc(adv_data_length + scan_rsp_data_length + 3);
+ if (p_buf == NULL) {
+ TUYA_BLE_LOG_ERROR("Malloc failed for read buf in adv change.");
+ return;
+ } else {
+ memset(p_buf, 0, adv_data_length + scan_rsp_data_length + 3);
+ p_buf[0] = 0;
+ p_buf[1] = adv_data_length + scan_rsp_data_length;
+ memcpy(&p_buf[2], adv_data, adv_data_length);
+ memcpy(&p_buf[2 + adv_data_length], scan_rsp_data, scan_rsp_data_length);
+ }
+
+ tuya_ble_device_info_characteristic_value_update(p_buf, (adv_data_length + scan_rsp_data_length + 3));
+
+ tuya_ble_free(p_buf);
+#endif
+
+}
+
+void tuya_ble_adv_change_with_connecting_request(void)
+{
+ uint8_t *aes_buf = NULL;
+ uint8_t *p_buf = NULL;
+ uint8_t adv_data_length = 0;
+ uint8_t scan_rsp_data_length = 0;
+ uint8_t aes_key[16];
+ uint8_t encry_device_id[DEVICE_ID_LEN];
+
+ memcpy(adv_data, adv_data_const, TUYA_BLE_ADV_DATA_LEN_MAX);
+ memcpy(&scan_rsp_data, scan_rsp_data_const, TUYA_BLE_SCAN_RSP_DATA_LEN_MAX);
+
+ adv_data[7] = 7 + tuya_ble_current_para.pid_len;
+
+ adv_data[13] = tuya_ble_current_para.pid_type;
+ adv_data[14] = tuya_ble_current_para.pid_len;
+
+ if (TUYA_BLE_DEVICE_SHARED) {
+ adv_data[11] |= 0x04 ;
+ } else {
+ adv_data[11] &= (~0x04);
+ }
+
+ adv_data[11] |= 0x02; //set connect request bit
+
+
+ scan_rsp_data[4] = TUYA_BLE_SECURE_CONNECTION_TYPE;
+
+ scan_rsp_data[5] = TUYA_BLE_DEVICE_COMMUNICATION_ABILITY >> 8;
+ scan_rsp_data[6] = TUYA_BLE_DEVICE_COMMUNICATION_ABILITY;
+
+ if (tuya_ble_current_para.pid_len == 20) {
+ scan_rsp_data[7] |= 0x01 ;
+ } else {
+ scan_rsp_data[7] &= (~0x01);
+ }
+
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE==TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION)
+
+ if (TUYA_BLE_ADVANCED_ENCRYPTION_AUTH_ON_CONNECT) {
+ scan_rsp_data[7] |= 0x02 ;
+ } else {
+ scan_rsp_data[7] &= (~0x02);
+ }
+
+#endif
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) {
+ adv_data[11] |= 0x08 ;
+ //
+ memcpy(aes_key, tuya_ble_current_para.sys_settings.login_key, LOGIN_KEY_LEN);
+ memcpy(aes_key + LOGIN_KEY_LEN, tuya_ble_current_para.auth_settings.device_id, 16 - LOGIN_KEY_LEN);
+
+ aes_buf = tuya_ble_malloc(200);
+
+ if (aes_buf == NULL) {
+ TUYA_BLE_LOG_ERROR("Malloc failed for AES BUF in adv change with connecting request.");
+ return;
+ } else {
+ memset(aes_buf, 0, 200);
+ }
+
+ tuya_ble_encrypt_old_with_key(aes_key, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, aes_buf);
+
+ memcpy(&adv_data[15], (uint8_t *)(aes_buf + 1), tuya_ble_current_para.pid_len);
+
+ tuya_ble_free(aes_buf);
+
+ tuya_ble_device_id_encrypt_v4(&adv_data[11], adv_data[7] - 3, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, encry_device_id);
+
+ memcpy(&scan_rsp_data[8], encry_device_id, DEVICE_ID_LEN);
+
+ } else {
+ adv_data[11] &= (~0x08);
+
+ memcpy(&adv_data[15], tuya_ble_current_para.pid, tuya_ble_current_para.pid_len);
+ tuya_ble_device_id_encrypt_v4(&adv_data[11], adv_data[7] - 3, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, encry_device_id);
+
+ memcpy(&scan_rsp_data[8], encry_device_id, DEVICE_ID_LEN);
+ }
+
+ if (tuya_ble_current_para.adv_local_name_len > TUYA_BLE_ADV_LOCAL_NAME_MAX_LEN) {
+ tuya_ble_current_para.adv_local_name_len = TUYA_BLE_ADV_LOCAL_NAME_MAX_LEN;
+ }
+ scan_rsp_data[24] = tuya_ble_current_para.adv_local_name_len + 1;
+ scan_rsp_data[25] = 0x09;
+ memcpy(&scan_rsp_data[26], tuya_ble_current_para.adv_local_name, tuya_ble_current_para.adv_local_name_len);
+
+ TUYA_BLE_LOG_INFO("adv data changed ,current bound flag = %d", tuya_ble_current_para.sys_settings.bound_flag);
+
+ adv_data_length = tuya_ble_current_para.pid_len + 15;
+ scan_rsp_data_length = tuya_ble_current_para.adv_local_name_len + 26;
+
+ tuya_ble_gap_advertising_adv_data_update(adv_data, adv_data_length);
+ tuya_ble_gap_advertising_scan_rsp_data_update(scan_rsp_data, scan_rsp_data_length);
+
+#if TUYA_BLE_LINK_LAYER_ENCRYPTION_SUPPORT_ENABLE
+
+ p_buf = tuya_ble_malloc(adv_data_length + scan_rsp_data_length + 3);
+ if (p_buf == NULL) {
+ TUYA_BLE_LOG_ERROR("Malloc failed for read buf in adv change.");
+ return;
+ } else {
+ memset(p_buf, 0, adv_data_length + scan_rsp_data_length + 3);
+ p_buf[0] = 0;
+ p_buf[1] = adv_data_length + scan_rsp_data_length;
+ memcpy(&p_buf[2], adv_data, adv_data_length);
+ memcpy(&p_buf[2 + adv_data_length], scan_rsp_data, scan_rsp_data_length);
+ }
+
+ tuya_ble_device_info_characteristic_value_update(p_buf, (adv_data_length + scan_rsp_data_length + 3));
+
+ tuya_ble_free(p_buf);
+
+#endif
+
+}
+
+#endif
+
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN==3)
+
+/** @brief GAP - Advertisement data (max size = 31 bytes, best kept short to conserve power) */
+
+#define TUYA_BLE_ADV_DATA_LEN (12+TUYA_BLE_PRODUCT_ID_MAX_LEN)
+
+static const uint8_t adv_data_const[TUYA_BLE_ADV_DATA_LEN] = {
+ 0x02,
+ 0x01,
+ 0x06,
+ 0x03,
+ 0x02,
+ 0x01, 0xA2,
+ 0x14,
+ 0x16,
+ 0x01, 0xA2,
+ 0x00, //id type 00-pid 01-product key
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+
+#define TUYA_BLE_SCAN_RSP_DATA_LEN 30
+static const uint8_t scan_rsp_data_const[TUYA_BLE_SCAN_RSP_DATA_LEN] = {
+ 0x03,
+ 0x09,
+ 0x54, 0x59,
+ 0x19, // length
+ 0xFF,
+ 0xD0,
+ 0x07,
+ 0x00, //bond flag bit7
+ 0x03, //protocol version
+ 0x01, //Encry Mode
+ 0x00, 0x00, //communication way bit0-mesh bit1-wifi bit2-zigbee bit3-NB
+ 0x00, //data type
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static uint8_t adv_data[TUYA_BLE_ADV_DATA_LEN];
+static uint8_t scan_rsp_data[TUYA_BLE_SCAN_RSP_DATA_LEN];
+
+uint8_t tuya_ble_get_adv_connect_request_bit_status(void)
+{
+ return (scan_rsp_data[8] & 0x01);
+}
+
+void tuya_ble_adv_change(void)
+{
+ uint8_t *aes_buf = NULL;
+ uint8_t aes_key[16];
+ uint8_t encry_device_id[DEVICE_ID_LEN];
+
+ memcpy(adv_data, adv_data_const, TUYA_BLE_ADV_DATA_LEN);
+ memcpy(&scan_rsp_data, scan_rsp_data_const, TUYA_BLE_SCAN_RSP_DATA_LEN);
+
+ adv_data[7] = 4 + tuya_ble_current_para.pid_len;
+ adv_data[11] = tuya_ble_current_para.pid_type;
+
+ if (TUYA_BLE_DEVICE_SHARED) {
+ scan_rsp_data[8] |= 0x02 ;
+ } else {
+ scan_rsp_data[8] &= (~0x02);
+ }
+
+ scan_rsp_data[8] &= (~0x01);
+
+ scan_rsp_data[9] = TUYA_BLE_PROTOCOL_VERSION_HIGN;
+
+ scan_rsp_data[10] = TUYA_BLE_SECURE_CONNECTION_TYPE;
+
+ scan_rsp_data[11] = TUYA_BLE_DEVICE_COMMUNICATION_ABILITY >> 8;
+ scan_rsp_data[12] = TUYA_BLE_DEVICE_COMMUNICATION_ABILITY;
+
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) {
+ scan_rsp_data[8] |= 0x80 ;
+ //
+ memcpy(aes_key, tuya_ble_current_para.sys_settings.login_key, LOGIN_KEY_LEN);
+ memcpy(aes_key + LOGIN_KEY_LEN, tuya_ble_current_para.auth_settings.device_id, 16 - LOGIN_KEY_LEN);
+
+ aes_buf = tuya_ble_malloc(200);
+
+ if (aes_buf == NULL) {
+ return;
+ } else {
+ memset(aes_buf, 0, 200);
+ }
+
+ tuya_ble_encrypt_old_with_key(aes_key, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, aes_buf);
+
+ memcpy(&adv_data[12], (uint8_t *)(aes_buf + 1), tuya_ble_current_para.pid_len);
+
+ tuya_ble_free(aes_buf);
+
+ memset(aes_key, 0, sizeof(aes_key));
+ memcpy(aes_key, &adv_data[12], tuya_ble_current_para.pid_len);
+
+ tuya_ble_device_id_encrypt(aes_key, tuya_ble_current_para.pid_len, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, encry_device_id);
+
+ memcpy(&scan_rsp_data[14], encry_device_id, DEVICE_ID_LEN);
+
+ } else {
+ scan_rsp_data[8] &= (~0x80);
+
+ memcpy(&adv_data[12], tuya_ble_current_para.pid, tuya_ble_current_para.pid_len);
+ tuya_ble_device_id_encrypt(tuya_ble_current_para.pid, tuya_ble_current_para.pid_len, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, encry_device_id);
+
+ memcpy(&scan_rsp_data[14], encry_device_id, DEVICE_ID_LEN);
+ }
+ TUYA_BLE_LOG_INFO("adv data changed ,current bound flag = %d", tuya_ble_current_para.sys_settings.bound_flag);
+ tuya_ble_gap_advertising_adv_data_update(adv_data, tuya_ble_current_para.pid_len + 12);
+ tuya_ble_gap_advertising_scan_rsp_data_update(scan_rsp_data, sizeof(scan_rsp_data));
+
+}
+
+void tuya_ble_adv_change_with_connecting_request(void)
+{
+ uint8_t *aes_buf = NULL;
+ uint8_t aes_key[16];
+ uint8_t encry_device_id[DEVICE_ID_LEN];
+
+ memcpy(adv_data, adv_data_const, TUYA_BLE_ADV_DATA_LEN);
+ memcpy(&scan_rsp_data, scan_rsp_data_const, TUYA_BLE_SCAN_RSP_DATA_LEN);
+
+ adv_data[7] = 4 + tuya_ble_current_para.pid_len;
+ adv_data[11] = tuya_ble_current_para.pid_type;
+
+ if (TUYA_BLE_DEVICE_SHARED) {
+ scan_rsp_data[8] |= 0x02 ;
+ } else {
+ scan_rsp_data[8] &= (~0x02);
+ }
+
+ scan_rsp_data[8] |= 0x01 ;
+
+ scan_rsp_data[9] = TUYA_BLE_PROTOCOL_VERSION_HIGN;
+
+ scan_rsp_data[10] = TUYA_BLE_SECURE_CONNECTION_TYPE;
+
+ scan_rsp_data[11] = TUYA_BLE_DEVICE_COMMUNICATION_ABILITY >> 8;
+ scan_rsp_data[12] = TUYA_BLE_DEVICE_COMMUNICATION_ABILITY;
+
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) {
+ scan_rsp_data[8] |= 0x80 ;
+ //
+ memcpy(aes_key, tuya_ble_current_para.sys_settings.login_key, LOGIN_KEY_LEN);
+ memcpy(aes_key + LOGIN_KEY_LEN, tuya_ble_current_para.auth_settings.device_id, 16 - LOGIN_KEY_LEN);
+
+ aes_buf = tuya_ble_malloc(200);
+
+ if (aes_buf == NULL) {
+ return;
+ } else {
+ memset(aes_buf, 0, 200);
+ }
+
+ tuya_ble_encrypt_old_with_key(aes_key, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, aes_buf);
+
+ memcpy(&adv_data[12], (uint8_t *)(aes_buf + 1), tuya_ble_current_para.pid_len);
+
+ tuya_ble_free(aes_buf);
+
+ memset(aes_key, 0, sizeof(aes_key));
+ memcpy(aes_key, &adv_data[12], tuya_ble_current_para.pid_len);
+
+ tuya_ble_device_id_encrypt(aes_key, tuya_ble_current_para.pid_len, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, encry_device_id);
+
+ memcpy(&scan_rsp_data[14], encry_device_id, DEVICE_ID_LEN);
+
+ } else {
+ scan_rsp_data[8] &= (~0x80);
+
+ memcpy(&adv_data[12], tuya_ble_current_para.pid, tuya_ble_current_para.pid_len);
+ tuya_ble_device_id_encrypt(tuya_ble_current_para.pid, tuya_ble_current_para.pid_len, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, encry_device_id);
+
+
+ memcpy(&scan_rsp_data[14], encry_device_id, DEVICE_ID_LEN);
+ }
+ TUYA_BLE_LOG_INFO("adv data changed ,current bound flag = %d", tuya_ble_current_para.sys_settings.bound_flag);
+ tuya_ble_gap_advertising_adv_data_update(adv_data, tuya_ble_current_para.pid_len + 12);
+ tuya_ble_gap_advertising_scan_rsp_data_update(scan_rsp_data, sizeof(scan_rsp_data));
+
+}
+
+#endif
+
+#if (TUYA_BLE_PROTOCOL_VERSION_HIGN==2)
+
+#define TUYA_BLE_ADV_DATA_LEN 11
+
+#define TUYA_BLE_SCAN_RSP_DATA_LEN 30
+
+static const uint8_t scan_rsp_data_const[30] = {
+ /* Manufacturer Specific Data */
+ 0x1D, /* length */
+ 0xFF,
+ 0x59,
+ 0x02,
+ 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+
+static const uint8_t adv_data_const[11] = {
+ /* Flags */
+ 0x02, /* length */
+ 0x01, /* type="Flags" */
+ 0x06,
+ /* Local name */
+ 0x03, /* length */
+ 0x09,
+ 'T', 'Y',
+ 0x03,
+ 0x02,
+ 0x01, 0xA2,
+};
+
+uint8_t adv_data[TUYA_BLE_ADV_DATA_LEN];
+uint8_t scan_rsp_data[TUYA_BLE_SCAN_RSP_DATA_LEN];
+
+void tuya_ble_adv_change(void)
+{
+ uint8_t *aes_buf = NULL;
+ uint8_t aes_key[16];
+ uint8_t encry_device_id[DEVICE_ID_LEN];
+
+ memcpy(adv_data, adv_data_const, TUYA_BLE_ADV_DATA_LEN);
+ memcpy(scan_rsp_data, scan_rsp_data_const, TUYA_BLE_SCAN_RSP_DATA_LEN);
+
+ scan_rsp_data[4] &= (~0x70);
+
+ if (tuya_ble_current_para.sys_settings.bound_flag == 1) {
+ scan_rsp_data[4] |= 0x80 ;
+ //
+ memcpy(aes_key, tuya_ble_current_para.sys_settings.login_key, LOGIN_KEY_LEN);
+ memcpy(aes_key + LOGIN_KEY_LEN, tuya_ble_current_para.auth_settings.device_id, 16 - LOGIN_KEY_LEN);
+
+ aes_buf = tuya_ble_malloc(200);
+
+ if (aes_buf == NULL) {
+ return;
+ } else {
+ memset(aes_buf, 0, 200);
+ }
+
+ tuya_ble_encrypt_old_with_key(aes_key, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, aes_buf);
+
+ memcpy(&scan_rsp_data[6], (uint8_t *)(aes_buf + 1), tuya_ble_current_para.pid_len);
+
+ tuya_ble_free(aes_buf);
+
+ memset(aes_key, 0, sizeof(aes_key));
+ memcpy(aes_key, &scan_rsp_data[6], tuya_ble_current_para.pid_len);
+
+ tuya_ble_device_id_encrypt(aes_key, tuya_ble_current_para.pid_len, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, encry_device_id);
+
+ memcpy(&scan_rsp_data[14], encry_device_id, DEVICE_ID_LEN);
+
+ } else {
+ scan_rsp_data[4] &= (~0x80);
+ memcpy(&scan_rsp_data[6], tuya_ble_current_para.pid, tuya_ble_current_para.pid_len);
+ tuya_ble_device_id_encrypt(tuya_ble_current_para.pid, 8, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN, encry_device_id);
+
+ memcpy(&scan_rsp_data[14], encry_device_id, DEVICE_ID_LEN);
+ }
+
+ TUYA_BLE_LOG_INFO("adv data changed ,current bound flag = %d", tuya_ble_current_para.sys_settings.bound_flag);
+
+ tuya_ble_gap_advertising_adv_data_update(adv_data, sizeof(adv_data));
+ tuya_ble_gap_advertising_scan_rsp_data_update(scan_rsp_data, sizeof(scan_rsp_data));
+
+}
+
+#endif
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_mem.c b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_mem.c
new file mode 100644
index 0000000..bb4baf4
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_mem.c
@@ -0,0 +1,140 @@
+/**
+ * \file tuya_ble_mem.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_heap.h"
+#include "tuya_ble_mem.h"
+#include "tuya_ble_internal_config.h"
+
+
+#if (TUYA_BLE_USE_PLATFORM_MEMORY_HEAP==0)
+
+/**
+ *@brief Allocate and clear a memory block with required size.
+ *@param[in] size Required memory size.
+ *
+ *@note
+ *
+ * */
+void *tuya_ble_malloc(uint16_t size)
+{
+ uint8_t *ptr = pvTuyaPortMalloc(size);
+ if (ptr) {
+ memset(ptr, 0x0, size); //allocate buffer need init
+ }
+ return ptr;
+}
+
+
+/**
+ *@brief Free a memory block that had been allocated.
+ *@param[in] ptr The address of memory block being freed.
+ *
+ *@note
+ *
+ * */
+tuya_ble_status_t tuya_ble_free(uint8_t *ptr)
+{
+ if (ptr == NULL) {
+ return TUYA_BLE_SUCCESS;
+ }
+
+ vTuyaPortFree(ptr);
+ return TUYA_BLE_SUCCESS;
+}
+
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+void *tuya_ble_calloc_n(uint32_t n, uint32_t size)
+{
+ void *ptr = NULL;
+ ptr = pvTuyaPortMalloc(n * size);
+ if (ptr != NULL) {
+ memset(ptr, 0, n * size);
+ }
+ return ptr;
+}
+
+
+/**
+ *@brief
+ *@param
+ *
+ *@note
+ *
+ * */
+void tuya_ble_free_n(void *ptr)
+{
+ vTuyaPortFree(ptr);
+}
+
+#else
+
+
+/**
+ *@brief Allocate and clear a memory block with required size.
+ *@param[in] size Required memory size.
+ *
+ *@note
+ *
+ * */
+void *tuya_ble_malloc(uint16_t size)
+{
+ uint8_t *ptr = tuya_ble_port_malloc(size);
+ if (ptr) {
+ memset(ptr, 0x0, size); //allocate buffer need init
+ }
+ return ptr;
+}
+
+
+/**
+ *@brief Free a memory block that had been allocated.
+ *@param[in] ptr The address of memory block being freed.
+ *
+ *@note
+ *
+ * */
+tuya_ble_status_t tuya_ble_free(uint8_t *ptr)
+{
+ if (ptr == NULL) {
+ return TUYA_BLE_SUCCESS;
+ }
+
+ tuya_ble_port_free(ptr);
+ return TUYA_BLE_SUCCESS;
+}
+
+
+#endif
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_mutli_tsf_protocol.c b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_mutli_tsf_protocol.c
new file mode 100644
index 0000000..d5cf6a3
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_mutli_tsf_protocol.c
@@ -0,0 +1,710 @@
+/**
+ * \file tuya_ble_mutli_tsf_protocol.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_mem.h"
+#include "tuya_ble_mutli_tsf_protocol.h"
+
+#define __MUTLI_TSF_PROTOCOL_GLOBALS
+
+/***********************************************************
+*************************micro define***********************
+***********************************************************/
+#define MTP_DEBUG 1
+
+#if MTP_DEBUG
+#define MTP_PR_DEBUG(_fmt_, ...) \
+ printf("[mtp:dbg]%s:%d "_fmt_"\n\r", __FILE__, __LINE__, ##__VA_ARGS__)
+#define MTP_PR_DEBUG_RAW(_fmt_, ...) \
+ printf(_fmt_, ##__VA_ARGS__)
+#else
+#define MTP_PR_DEBUG(...)
+#define MTP_PR_DEBUG_RAW(_fmt_, ...)
+#endif
+
+#define MTP_PR_NOTICE(_fmt_, ...) \
+ printf("[mtp:notice]%s:%d "_fmt_"\n\r", __FILE__, __LINE__, ##__VA_ARGS__)
+#define MTP_PR_ERR(_fmt_, ...) \
+ printf("[mtp:err]%s:%d "_fmt_"\n\r", __FILE__, __LINE__, ##__VA_ARGS__)
+
+#undef NULL
+#define NULL (void *)0
+/***********************************************************
+*************************variable define********************
+***********************************************************/
+static frame_seq_t frame_seq = 0;
+
+/***********************************************************
+*************************function define********************
+***********************************************************/
+/***********************************************************
+* Function: create_trsmitr_init
+* description: create a transmitter and initialize
+* Input: none
+* Output:
+* Return: transmitter handle
+***********************************************************/
+frm_trsmitr_proc_s *create_trsmitr_init(void)
+{
+ frm_trsmitr_proc_s *frm_trsmitr = NULL;
+
+ frm_trsmitr = (frm_trsmitr_proc_s *)tuya_ble_malloc(sizeof(frm_trsmitr_proc_s));
+ if ((void *)0 == frm_trsmitr) {
+ return (void *)0;
+ }
+ memset(frm_trsmitr, 0, sizeof(frm_trsmitr_proc_s));
+
+ return frm_trsmitr;
+}
+
+/***********************************************************
+* Function: trsmitr_init
+* description: init a transmitter
+* Input: transmitter handle
+* Output:
+* Return:
+***********************************************************/
+void trsmitr_init(frm_trsmitr_proc_s *frm_trsmitr)
+{
+ memset(frm_trsmitr, 0, sizeof(frm_trsmitr_proc_s));
+}
+
+/***********************************************************
+* Function: delete_trsmitr
+* description: delete transmitter
+* Input: transmitter handle
+* Output:
+* Return:
+***********************************************************/
+void delete_trsmitr(frm_trsmitr_proc_s *frm_trsmitr)
+{
+ //free(frm_trsmitr);
+ tuya_ble_free((uint8_t *)frm_trsmitr);
+}
+
+/***********************************************************
+* Function: get_trsmitr_frame_total_len
+* description: get a transmitter total data len
+* Input: transmitter handle
+* Output:
+* Return: frame_total_t
+***********************************************************/
+frame_total_t get_trsmitr_frame_total_len(frm_trsmitr_proc_s *frm_trsmitr)
+{
+ return frm_trsmitr->total;
+}
+
+/***********************************************************
+* Function: get_trsmitr_frame_version
+* description:
+* Input: transmitter handle
+* Output:
+* Return:
+***********************************************************/
+uint8_t get_trsmitr_frame_version(frm_trsmitr_proc_s *frm_trsmitr)
+{
+ return frm_trsmitr->version;
+}
+
+/***********************************************************
+* Function: get_trsmitr_frame_seq
+* description:
+* Input: transmitter handle
+* Output:
+* Return: frame_seq_t
+***********************************************************/
+frame_seq_t get_trsmitr_frame_seq(frm_trsmitr_proc_s *frm_trsmitr)
+{
+ return frm_trsmitr->seq;
+}
+
+/***********************************************************
+* Function: get_trsmitr_subpkg_len
+* description:
+* Input: transmitter handle
+* Output:
+* Return: frame_subpkg_len_t
+***********************************************************/
+frame_subpkg_len_t get_trsmitr_subpkg_len(frm_trsmitr_proc_s *frm_trsmitr)
+{
+ return frm_trsmitr->subpkg_len;
+}
+
+/***********************************************************
+* Function: get_trsmitr_subpkg
+* description:
+* Input: transmitter handle
+* Output:
+* Return: subpackage buf
+***********************************************************/
+uint8_t *get_trsmitr_subpkg(frm_trsmitr_proc_s *frm_trsmitr)
+{
+ return frm_trsmitr->subpkg;
+}
+
+static frame_seq_t get_frame_seq(void) //Because this type of data is not used temporarily, it can be used for multi-threaded calls temporarily
+{
+ return (frame_seq >= FRAME_SEQ_LMT) ? 0 : frame_seq++;
+}
+
+/***********************************************************
+* Function: trsmitr_send_pkg_encode
+* description: frm_trsmitr->transmitter handle
+* type->frame type
+* buf->data buf
+* len->data len
+* Input:
+* Output:
+* Return: MTP_OK->buf send up
+* MTP_TRSMITR_CONTINUE->need call again to be continue
+* other->error
+* Note: could get from encode data len and encode data by calling method
+ get_trsmitr_subpkg_len() and get_trsmitr_subpkg()
+***********************************************************/
+mtp_ret trsmitr_send_pkg_encode(frm_trsmitr_proc_s *frm_trsmitr, uint8_t version, uint8_t *buf, uint32_t len)
+{
+ if (((void *)0) == frm_trsmitr) {
+ return MTP_INVALID_PARAM;
+ }
+
+ if (FRM_PKG_INIT == frm_trsmitr->pkg_desc) {
+ frm_trsmitr->total = len;
+ frm_trsmitr->version = version;
+ frm_trsmitr->seq = get_frame_seq();
+ frm_trsmitr->subpkg_num = 0;
+ frm_trsmitr->pkg_trsmitr_cnt = 0;
+ }
+
+ if (frm_trsmitr->subpkg_num >= 0x10000000 || len >= 0x10000000) {
+ return MTP_COM_ERROR;
+ }
+
+ uint16_t sunpkg_offset = 0;
+
+ // package code
+ // subpackage num encode
+ int32_t i;
+ uint32_t tmp = 0;
+ tmp = frm_trsmitr->subpkg_num;
+ for (i = 0; i < 4; i++) {
+ frm_trsmitr->subpkg[sunpkg_offset] = tmp % 0x80;
+ if ((tmp / 0x80)) {
+ frm_trsmitr->subpkg[sunpkg_offset] |= 0x80;
+ }
+ sunpkg_offset++;
+ tmp /= 0x80;
+ if (0 == tmp) {
+ break;
+ }
+ }
+
+ // the first package include the frame total len
+ if (0 == frm_trsmitr->subpkg_num) {
+ // frame len encode
+ tmp = len;
+ for (i = 0; i < 4; i++) {
+ frm_trsmitr->subpkg[sunpkg_offset] = tmp % 0x80;
+ if ((tmp / 0x80)) {
+ frm_trsmitr->subpkg[sunpkg_offset] |= 0x80;
+ }
+ sunpkg_offset++;
+ tmp /= 0x80;
+ if (0 == tmp) {
+ break;
+ }
+ }
+
+ // frame type and frame seq
+ frm_trsmitr->subpkg[sunpkg_offset++] = (frm_trsmitr->version << 0x04) | (frm_trsmitr->seq & 0x0f);
+ }
+
+ // frame data transfer
+ uint16_t send_data_len = (SNGL_PKG_TRSFR_LMT - sunpkg_offset);
+ if ((len - frm_trsmitr->pkg_trsmitr_cnt) < send_data_len) {
+ send_data_len = len - frm_trsmitr->pkg_trsmitr_cnt;
+ }
+
+ memcpy(&(frm_trsmitr->subpkg[sunpkg_offset]), buf + frm_trsmitr->pkg_trsmitr_cnt, send_data_len);
+ frm_trsmitr->subpkg_len = sunpkg_offset + send_data_len;
+
+ frm_trsmitr->pkg_trsmitr_cnt += send_data_len;
+ if (0 == frm_trsmitr->subpkg_num) {
+ frm_trsmitr->pkg_desc = FRM_PKG_FIRST;
+ } else {
+ frm_trsmitr->pkg_desc = FRM_PKG_MIDDLE;
+ }
+
+ if (frm_trsmitr->pkg_trsmitr_cnt < frm_trsmitr->total) {
+ frm_trsmitr->subpkg_num++;
+ return MTP_TRSMITR_CONTINUE;
+ }
+
+ frm_trsmitr->pkg_desc = FRM_PKG_END;
+ return MTP_OK;
+}
+
+/***********************************************************
+* Function: trsmitr_send_pkg_encode_with_packet_length
+* description: Encoding function for specifying sub-packet length
+*
+*
+*
+* Input:
+* Output:
+* Return: MTP_OK->buf send up
+* MTP_TRSMITR_CONTINUE->need call again to be continue
+* other->error
+* Note: could get from encode data len and encode data by calling method
+ get_trsmitr_subpkg_len() and get_trsmitr_subpkg()
+***********************************************************/
+mtp_ret trsmitr_send_pkg_encode_with_packet_length(frm_trsmitr_proc_s *frm_trsmitr, uint32_t pkg_len_max, uint8_t version, uint8_t *buf, uint32_t len)
+{
+ if (((void *)0) == frm_trsmitr) {
+ return MTP_INVALID_PARAM;
+ }
+
+ if ((pkg_len_max == 0) || (pkg_len_max > SNGL_PKG_TRSFR_LMT)) {
+ return MTP_INVALID_PARAM;
+ }
+
+ if (FRM_PKG_INIT == frm_trsmitr->pkg_desc) {
+ frm_trsmitr->total = len;
+ frm_trsmitr->version = version;
+ frm_trsmitr->seq = get_frame_seq();
+ frm_trsmitr->subpkg_num = 0;
+ frm_trsmitr->pkg_trsmitr_cnt = 0;
+ }
+
+ if (frm_trsmitr->subpkg_num >= 0x10000000 || len >= 0x10000000) {
+ return MTP_COM_ERROR;
+ }
+
+ uint16_t sunpkg_offset = 0;
+
+ // package code
+ // subpackage num encode
+ int32_t i;
+ uint32_t tmp = 0;
+ tmp = frm_trsmitr->subpkg_num;
+ for (i = 0; i < 4; i++) {
+ frm_trsmitr->subpkg[sunpkg_offset] = tmp % 0x80;
+ if ((tmp / 0x80)) {
+ frm_trsmitr->subpkg[sunpkg_offset] |= 0x80;
+ }
+ sunpkg_offset++;
+ tmp /= 0x80;
+ if (0 == tmp) {
+ break;
+ }
+ }
+
+ // the first package include the frame total len
+ if (0 == frm_trsmitr->subpkg_num) {
+ // frame len encode
+ tmp = len;
+ for (i = 0; i < 4; i++) {
+ frm_trsmitr->subpkg[sunpkg_offset] = tmp % 0x80;
+ if ((tmp / 0x80)) {
+ frm_trsmitr->subpkg[sunpkg_offset] |= 0x80;
+ }
+ sunpkg_offset++;
+ tmp /= 0x80;
+ if (0 == tmp) {
+ break;
+ }
+ }
+
+ // frame type and frame seq
+ frm_trsmitr->subpkg[sunpkg_offset++] = (frm_trsmitr->version << 0x04) | (frm_trsmitr->seq & 0x0f);
+ }
+
+ // frame data transfer
+ uint16_t send_data_len = (pkg_len_max - sunpkg_offset);
+ if ((len - frm_trsmitr->pkg_trsmitr_cnt) < send_data_len) {
+ send_data_len = len - frm_trsmitr->pkg_trsmitr_cnt;
+ }
+
+ memcpy(&(frm_trsmitr->subpkg[sunpkg_offset]), buf + frm_trsmitr->pkg_trsmitr_cnt, send_data_len);
+ frm_trsmitr->subpkg_len = sunpkg_offset + send_data_len;
+
+ frm_trsmitr->pkg_trsmitr_cnt += send_data_len;
+ if (0 == frm_trsmitr->subpkg_num) {
+ frm_trsmitr->pkg_desc = FRM_PKG_FIRST;
+ } else {
+ frm_trsmitr->pkg_desc = FRM_PKG_MIDDLE;
+ }
+
+ if (frm_trsmitr->pkg_trsmitr_cnt < frm_trsmitr->total) {
+ frm_trsmitr->subpkg_num++;
+ return MTP_TRSMITR_CONTINUE;
+ }
+
+ frm_trsmitr->pkg_desc = FRM_PKG_END;
+ return MTP_OK;
+}
+
+
+
+mtp_ret trsmitr_recv_pkg_decode(frm_trsmitr_proc_s *frm_trsmitr, uint8_t *raw_data, uint16_t raw_data_len)
+{
+ if (NULL == raw_data || (raw_data_len > SNGL_PKG_TRSFR_LMT) || NULL == frm_trsmitr) {
+ return MTP_INVALID_PARAM;
+ }
+
+ if (FRM_PKG_INIT == frm_trsmitr->pkg_desc) {
+ frm_trsmitr->total = 0;
+ frm_trsmitr->version = 0;
+ frm_trsmitr->seq = 0;
+ frm_trsmitr->pkg_trsmitr_cnt = 0;
+ }
+
+ uint16_t sunpkg_offset = 0;
+ // package code
+ // subpackage num decode
+ int32_t i;
+ uint32_t multiplier = 1;
+ uint8_t digit;
+ frame_subpkg_num_t subpkg_num = 0;
+//Package number
+ for (i = 0; i < 4; i++) {
+ digit = raw_data[sunpkg_offset++];
+ subpkg_num += (digit & 0x7f) * multiplier;
+ multiplier *= 0x80;
+
+ if (0 == (digit & 0x80)) {
+ break;
+ }
+ }
+
+ if (0 == subpkg_num) {
+ frm_trsmitr->total = 0;
+ frm_trsmitr->version = 0;
+ frm_trsmitr->seq = 0;
+ frm_trsmitr->pkg_trsmitr_cnt = 0;
+ frm_trsmitr->pkg_desc = FRM_PKG_FIRST;
+ } else {
+ frm_trsmitr->pkg_desc = FRM_PKG_MIDDLE;
+ }
+
+ if (frm_trsmitr->subpkg_num >= 0x10000000) {
+ return MTP_COM_ERROR;
+ }
+ // is receive the subpackage num valid?
+ if (frm_trsmitr->pkg_desc != FRM_PKG_FIRST) {
+ if (subpkg_num < frm_trsmitr->subpkg_num) {
+ return MTP_TRSMITR_ERROR;
+ } else if (subpkg_num == frm_trsmitr->subpkg_num) {
+ return MTP_TRSMITR_CONTINUE;
+ }
+
+ if (subpkg_num - frm_trsmitr->subpkg_num > 1) {
+ return MTP_TRSMITR_ERROR;
+ }
+ }
+
+ frm_trsmitr->subpkg_num = subpkg_num;
+
+ if (0 == frm_trsmitr->subpkg_num) {
+ // frame len decode
+ multiplier = 1;
+ for (i = 0; i < 4; i++) {
+ digit = raw_data[sunpkg_offset++];
+ frm_trsmitr->total += (digit & 0x7f) * multiplier;
+ multiplier *= 0x80;
+
+ if (0 == (digit & 0x80)) {
+ break;
+ }
+ }
+
+ if (frm_trsmitr->total >= 0x10000000) {
+ return MTP_COM_ERROR;
+ }
+
+ // frame type and frame seq decode
+ frm_trsmitr->version = (raw_data[sunpkg_offset] & FRM_VERSION_OFFSET) >> 4;
+ frm_trsmitr->seq = raw_data[sunpkg_offset++] & FRM_SEQ_OFFSET;
+ }
+
+ uint16_t recv_data_len = raw_data_len - sunpkg_offset;
+ if ((frm_trsmitr->total - frm_trsmitr->pkg_trsmitr_cnt) < recv_data_len) {
+ recv_data_len = frm_trsmitr->total - frm_trsmitr->pkg_trsmitr_cnt;
+ }
+
+ // decode data cp to transmitter subpackage buf
+ memcpy(frm_trsmitr->subpkg, &raw_data[sunpkg_offset], recv_data_len);
+ frm_trsmitr->subpkg_len = recv_data_len;
+ frm_trsmitr->pkg_trsmitr_cnt += recv_data_len;
+
+ if (frm_trsmitr->pkg_trsmitr_cnt < frm_trsmitr->total) {
+ return MTP_TRSMITR_CONTINUE;
+ }
+ //cannot add 'frm_trsmitr->pkg_desc = FRM_PKG_END;' here.
+ return MTP_OK;
+}
+/***********************************************************
+* Function: free_klv_list
+* description:
+* Input: list
+* Output:
+* Return:
+***********************************************************/
+void free_klv_list(klv_node_s *list)
+{
+ if (NULL == list) {
+ return;
+ }
+
+ klv_node_s *node = list;
+ klv_node_s *next_node = NULL;
+
+ do {
+ next_node = node->next;
+ //free(node);
+ tuya_ble_free((uint8_t *)(node->data));
+
+ tuya_ble_free((uint8_t *)node);
+ node = next_node;
+ } while (node);
+}
+
+/***********************************************************
+* Function: make_klv_list
+* description:
+* Input:
+* Output:
+* Return:
+***********************************************************/
+klv_node_s *make_klv_list(klv_node_s *list, uint8_t id, dp_type type, void *p_data, uint16_t len)
+{
+ klv_node_s *node = NULL;
+ uint32_t tmp4 = 0, tmp2 = 0;
+
+ if (NULL == p_data || type >= DT_LMT) {
+ return NULL;
+ }
+
+ if (DT_VALUE == type && DT_VALUE_LEN != len) {
+ goto err_ret;
+ } else if (DT_BITMAP == type && len != 1 && len != 2 && len != DT_BITMAP_MAX) {
+ goto err_ret;
+ } else if (DT_BOOL == type && DT_BOOL_LEN != len) {
+ goto err_ret;
+ } else if (DT_ENUM == type && DT_ENUM_LEN != len) {
+ goto err_ret;
+ }
+
+
+ node = (klv_node_s *)tuya_ble_malloc(sizeof(klv_node_s));
+
+ if (NULL == node) {
+ goto err_ret;
+ }
+ memset(node, 0, sizeof(klv_node_s));
+ if (len > 0) {
+ node->data = tuya_ble_malloc(len);
+ if (node->data == NULL) {
+ tuya_ble_free(node->data);
+ tuya_ble_free((uint8_t *)node);
+ goto err_ret;
+ }
+ }
+ node->id = id;
+ node->len = len;
+ node->type = type;
+
+ if (DT_VALUE == type) {
+ // change to big-end
+ tmp4 = *(uint32_t *)p_data;
+ // unsigned char shift = 0;
+ node->data[0] = (tmp4 >> 24) & 0xff;
+ node->data[1] = (tmp4 >> 16) & 0xff;
+ node->data[2] = (tmp4 >> 8) & 0xff;
+ node->data[3] = (tmp4 >> 0) & 0xff;
+ } else if (DT_BITMAP == type) {
+ if (len == 4) {
+ tmp4 = *(uint32_t *)p_data;
+ // unsigned char shift = 0;
+ node->data[0] = (tmp4 >> 24) & 0xff;
+ node->data[1] = (tmp4 >> 16) & 0xff;
+ node->data[2] = (tmp4 >> 8) & 0xff;
+ node->data[3] = (tmp4 >> 0) & 0xff;
+ } else if (len == 2) {
+ tmp2 = *(uint16_t *)p_data;
+ node->data[0] = (tmp2 >> 8) & 0xff;
+ node->data[1] = (tmp2 >> 0) & 0xff;
+ } else {
+ node->data[0] = *(uint8_t *)p_data;
+ }
+ } else {
+ if (len > 0) {
+ memcpy((void *)node->data, (uint8_t *)p_data, len);
+ }
+ }
+ node->next = list;
+ return node;
+
+err_ret:
+ free_klv_list(list);
+ return NULL;
+}
+
+/***********************************************************
+* Function: klvlist_2_data
+* description:
+* Input: type:0- 1 byte length,1- 2 byte length
+* Output:
+* Return:
+***********************************************************/
+mtp_ret klvlist_2_data(klv_node_s *list, uint8_t **data, uint32_t *len, uint8_t type)
+{
+ if (NULL == list || NULL == data || NULL == len) {
+ return MTP_INVALID_PARAM;
+ }
+
+ klv_node_s *node = list;
+
+ // count data len
+ uint32_t mk_data_len = 0;
+ while (node) {
+ mk_data_len += sizeof(klv_node_s) + node->len - sizeof(struct s_klv_node *);
+ node = node->next;
+ }
+
+ uint8_t *mk_data = (uint8_t *)tuya_ble_malloc(mk_data_len);
+ if (NULL == mk_data) {
+ return MTP_MALLOC_ERR;
+ }
+
+ // fill data
+ uint32_t offset = 0;
+ node = list;
+ while (node) {
+ mk_data[offset++] = node->id;
+ mk_data[offset++] = node->type;
+ if (1 == type) {
+ mk_data[offset++] = node->len >> 8;
+ mk_data[offset++] = node->len;
+ } else {
+ mk_data[offset++] = node->len;
+ }
+ if (node->len > 0) {
+ memcpy(&mk_data[offset], node->data, node->len);
+ }
+ offset += node->len;
+ node = node->next;
+ }
+ *len = offset;
+ *data = mk_data;
+
+ return MTP_OK;
+}
+
+/***********************************************************
+* Function: data_2_klvlist
+* description:
+* Input: type: 0- 1 byte length,1- 2 byte length
+* Output:
+* Return:
+***********************************************************/
+mtp_ret data_2_klvlist(uint8_t *data, uint32_t len, klv_node_s **list, uint8_t type)
+{
+ uint16_t dp_len = 0;
+ //The data is parsed into a list of dp points dpid+dp_tp+len+data
+ if (NULL == data || NULL == list) {
+ return MTP_INVALID_PARAM;
+ }
+
+ uint32_t offset = 0;
+ klv_node_s *klv_list = NULL;
+ klv_node_s *node = NULL;
+ do {
+ // not full klv
+ if (type == 1) {
+ if ((len - offset) < 4) {
+ free_klv_list(klv_list);
+ return MTP_COM_ERROR;
+ }
+ } else {
+ if ((len - offset) < 3) {
+ free_klv_list(klv_list);
+ return MTP_COM_ERROR;
+ }
+ }
+
+ node = (klv_node_s *)tuya_ble_malloc(sizeof(klv_node_s));
+ if (NULL == node) {
+ free_klv_list(klv_list);
+ return MTP_MALLOC_ERR;
+ }
+ memset(node, 0, sizeof(klv_node_s));
+ if (1 == type) {
+ dp_len = (data[2 + offset] << 8) + data[3 + offset];
+ } else {
+ dp_len = data[2 + offset];
+ }
+
+ if (dp_len > 0) {
+ node->data = tuya_ble_malloc(dp_len);
+ if (node->data == NULL) {
+ tuya_ble_free(node->data);
+ tuya_ble_free((uint8_t *)node);
+ free_klv_list(klv_list);
+ return MTP_MALLOC_ERR;
+ }
+ }
+ node->id = data[offset++];
+ node->type = data[offset++];
+ if (1 == type) {
+ //offset++;
+ node->len = data[offset++];
+ node->len = (node->len << 8) + data[offset++];
+ } else {
+ node->len = data[offset++];
+ }
+ if ((len - offset) < node->len) {
+ // is remain data len enougn?
+ tuya_ble_free(node->data);
+ tuya_ble_free((uint8_t *)node);
+ free_klv_list(klv_list);
+ return MTP_COM_ERROR;
+ }
+ if (node->len > 0) {
+ memcpy(node->data, &data[offset], node->len);
+ }
+
+ offset += node->len;
+
+ node->next = klv_list;
+ klv_list = node;
+ } while (offset < len);
+
+ if (NULL == klv_list) {
+ return MTP_COM_ERROR;
+ }
+ *list = klv_list;
+ return MTP_OK;
+}
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_queue.c b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_queue.c
new file mode 100644
index 0000000..fb1b330
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_queue.c
@@ -0,0 +1,100 @@
+/**
+ * \file tuya_ble_queue.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_queue.h"
+#include "tuya_ble_type.h"
+
+tuya_ble_status_t tuya_ble_queue_init(tuya_ble_queue_t *q, void *buf, uint8_t queue_size, uint8_t elem_size)
+{
+ if (buf == NULL || q == NULL) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+
+ q->buf = buf;
+ q->size = queue_size;
+ q->offset = elem_size;
+ q->rd_ptr = 0;
+ q->wr_ptr = 0;
+ q->used = 0;
+
+ return TUYA_BLE_SUCCESS;
+}
+
+tuya_ble_status_t tuya_ble_enqueue(tuya_ble_queue_t *q, void *in)
+{
+ if (q->used >= q->size) {
+ return TUYA_BLE_ERR_NO_MEM;
+ }
+
+ memcpy((uint8_t *)q->buf + q->wr_ptr * q->offset, in, q->offset);
+ q->wr_ptr = (q->wr_ptr + 1) % q->size;
+ q->used++;
+
+ return TUYA_BLE_SUCCESS;
+}
+
+tuya_ble_status_t tuya_ble_queue_get(tuya_ble_queue_t *q, void *out)
+{
+ if (q->used > 0) {
+ memcpy(out, (uint8_t *)q->buf + q->rd_ptr * q->offset, q->offset);
+ return TUYA_BLE_SUCCESS;
+ } else {
+ return TUYA_BLE_ERR_NOT_FOUND;
+ }
+}
+
+tuya_ble_status_t tuya_ble_dequeue(tuya_ble_queue_t *q, void *out)
+{
+ if (q->used > 0) {
+ memcpy(out, (uint8_t *)q->buf + q->rd_ptr * q->offset, q->offset);
+ q->rd_ptr = (q->rd_ptr + 1) % q->size;
+ q->used--;
+ return TUYA_BLE_SUCCESS;
+ } else {
+ return TUYA_BLE_ERR_NOT_FOUND;
+ }
+}
+
+void tuya_ble_queue_decrease(tuya_ble_queue_t *q)
+{
+ if (q->used > 0) {
+ q->rd_ptr = (q->rd_ptr + 1) % q->size;
+ q->used--;
+ }
+}
+
+
+void tuya_ble_queue_flush(tuya_ble_queue_t *q)
+{
+ q->rd_ptr = 0;
+ q->wr_ptr = 0;
+ q->used = 0;
+}
+
+uint8_t tuya_ble_get_queue_used(tuya_ble_queue_t *q)
+{
+ return q->used;
+}
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_storage.c b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_storage.c
new file mode 100644
index 0000000..35d304d
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_storage.c
@@ -0,0 +1,498 @@
+/**
+ * \file tuya_ble_storage.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_api.h"
+#include "tuya_ble_port.h"
+#include "tuya_ble_type.h"
+#include "tuya_ble_main.h"
+#include "tuya_ble_mem.h"
+#include "tuya_ble_data_handler.h"
+#include "tuya_ble_internal_config.h"
+#include "tuya_ble_mutli_tsf_protocol.h"
+#include "tuya_ble_storage.h"
+#include "tuya_ble_utils.h"
+#include "tuya_ble_log.h"
+
+
+typedef struct {
+ uint32_t crc;
+ uint32_t settings_version;
+ uint8_t h_id[H_ID_LEN];
+ uint8_t device_id[DEVICE_ID_LEN];
+ uint8_t mac[MAC_LEN];
+ uint8_t auth_key[AUTH_KEY_LEN];
+} tuya_ble_auth_settings_old_t;
+
+
+typedef struct {
+ uint32_t crc;
+ uint32_t settings_version;
+ tuya_ble_product_id_type_t pid_type;
+ uint8_t pid_len;
+ uint8_t common_pid[TUYA_BLE_PRODUCT_ID_MAX_LEN];
+ uint8_t login_key[LOGIN_KEY_LEN];
+ uint8_t ecc_secret_key[ECC_SECRET_KEY_LEN];
+ uint8_t device_virtual_id[DEVICE_VIRTUAL_ID_LEN];
+ uint8_t user_rand[PAIR_RANDOM_LEN];
+ uint8_t bound_flag;
+} tuya_ble_sys_settings_old_t;
+
+
+typedef struct {
+ tuya_ble_auth_settings_t flash_settings_auth;
+ tuya_ble_auth_settings_t flash_settings_auth_backup;
+} tuya_ble_storage_auth_settings_t;
+
+typedef struct {
+ tuya_ble_sys_settings_t flash_settings_sys;
+ tuya_ble_sys_settings_t flash_settings_sys_backup;
+} tuya_ble_storage_sys_settings_t;
+
+
+static bool buffer_value_is_all_x(uint8_t *buffer, uint16_t len, uint8_t value)
+{
+ bool ret = true;
+ for (uint16_t i = 0; i < len; i++) {
+ if (buffer[i] != value) {
+ ret = false;
+ break;
+ }
+ }
+ return ret;
+}
+
+
+
+static uint32_t auth_settings_crc_get(tuya_ble_auth_settings_t const *p_settings)
+{
+ // The crc is calculated from the s_dfu_settings struct, except the crc itself and the init command
+ return tuya_ble_crc32_compute((uint8_t *)(p_settings) + 4, sizeof(tuya_ble_auth_settings_t) - 4, NULL);
+}
+
+static bool auth_settings_crc_ok(tuya_ble_auth_settings_t const *p_settings, uint8_t *flash_update)
+{
+ uint32_t crc, crc_old;
+ if (p_settings->crc != 0xFFFFFFFF) {
+ // CRC is set. Content must be valid
+ crc = auth_settings_crc_get(p_settings);
+ if (crc == p_settings->crc) {
+ return true;
+ } else {
+ crc_old = tuya_ble_crc32_compute((uint8_t *)(p_settings) + 4, sizeof(tuya_ble_auth_settings_old_t) - 4, NULL);
+ if (crc_old == p_settings->crc) {
+ *flash_update = 1;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+static uint32_t sys_settings_crc_get(tuya_ble_sys_settings_t const *p_settings)
+{
+ // The crc is calculated from the s_dfu_settings struct, except the crc itself and the init command
+ return tuya_ble_crc32_compute((uint8_t *)(p_settings) + 4, sizeof(tuya_ble_sys_settings_t) - 4, NULL);
+}
+
+
+
+static bool sys_settings_crc_ok(tuya_ble_sys_settings_t const *p_settings, uint8_t *flash_update)
+{
+ uint32_t crc, crc_old;
+ if (p_settings->crc != 0xFFFFFFFF) {
+ // CRC is set. Content must be valid
+ crc = sys_settings_crc_get(p_settings);
+ if (crc == p_settings->crc) {
+ return true;
+ } else {
+ crc_old = tuya_ble_crc32_compute((uint8_t *)(p_settings) + 4, sizeof(tuya_ble_sys_settings_old_t) - 4, NULL);
+ if (crc_old == p_settings->crc) {
+ *flash_update = 1;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+uint32_t tuya_ble_storage_load_settings(void)
+{
+ uint32_t err_code = 0;
+ bool settings_valid ;
+ bool settings_backup_valid;
+ uint8_t auth_settings_flag = 1;
+ uint8_t sys_settings_flag = 1;
+ uint8_t auth_settings_update = 0;
+ uint8_t sys_settings_update = 0;
+ tuya_ble_storage_auth_settings_t *p_storage_settings_auth = NULL;
+ tuya_ble_storage_sys_settings_t *p_storage_settings_sys = NULL;
+
+ p_storage_settings_auth = (tuya_ble_storage_auth_settings_t *)tuya_ble_malloc(sizeof(tuya_ble_storage_auth_settings_t));
+
+ if (p_storage_settings_auth == NULL) {
+ TUYA_BLE_LOG_ERROR("p_storage_settings_auth malloc failed.");
+ memset(&tuya_ble_current_para.auth_settings, 0, sizeof(tuya_ble_auth_settings_t));
+ auth_settings_flag = 0;
+ } else {
+ memset(p_storage_settings_auth, 0, sizeof(tuya_ble_storage_auth_settings_t));
+ }
+
+ if (auth_settings_flag == 1) {
+ tuya_ble_nv_read(TUYA_BLE_AUTH_FLASH_ADDR, (uint8_t *)&p_storage_settings_auth->flash_settings_auth, sizeof(tuya_ble_auth_settings_t));
+ tuya_ble_nv_read(TUYA_BLE_AUTH_FLASH_BACKUP_ADDR, (uint8_t *)&p_storage_settings_auth->flash_settings_auth_backup, sizeof(tuya_ble_auth_settings_t));
+
+ settings_valid = auth_settings_crc_ok(&p_storage_settings_auth->flash_settings_auth, &auth_settings_update);
+ settings_backup_valid = auth_settings_crc_ok(&p_storage_settings_auth->flash_settings_auth_backup, &auth_settings_update);
+
+ if (settings_valid) {
+ memcpy(&tuya_ble_current_para.auth_settings, &p_storage_settings_auth->flash_settings_auth, sizeof(tuya_ble_auth_settings_t));
+ } else if (settings_backup_valid) {
+ memcpy(&tuya_ble_current_para.auth_settings, &p_storage_settings_auth->flash_settings_auth_backup, sizeof(tuya_ble_auth_settings_t));
+ } else {
+ memset(&tuya_ble_current_para.auth_settings, 0, sizeof(tuya_ble_auth_settings_t));
+ auth_settings_flag = 0;
+ }
+ if (auth_settings_update == 1) {
+ tuya_ble_storage_save_auth_settings();
+ auth_settings_update = 0;
+ }
+
+ tuya_ble_free((uint8_t *)p_storage_settings_auth);
+
+ }
+
+ p_storage_settings_sys = (tuya_ble_storage_sys_settings_t *)tuya_ble_malloc(sizeof(tuya_ble_storage_sys_settings_t));
+
+ if (p_storage_settings_sys == NULL) {
+ TUYA_BLE_LOG_ERROR("p_storage_settings_sys malloc failed.");
+ memset(&tuya_ble_current_para.sys_settings, 0, sizeof(tuya_ble_sys_settings_t));
+ sys_settings_flag = 0;
+ } else {
+ memset(p_storage_settings_sys, 0, sizeof(tuya_ble_storage_sys_settings_t));
+ }
+
+ if (sys_settings_flag == 1) {
+ tuya_ble_nv_read(TUYA_BLE_SYS_FLASH_ADDR, (uint8_t *)&p_storage_settings_sys->flash_settings_sys, sizeof(tuya_ble_sys_settings_t));
+ tuya_ble_nv_read(TUYA_BLE_SYS_FLASH_BACKUP_ADDR, (uint8_t *)&p_storage_settings_sys->flash_settings_sys_backup, sizeof(tuya_ble_sys_settings_t));
+
+ settings_valid = sys_settings_crc_ok(&p_storage_settings_sys->flash_settings_sys, &sys_settings_update);
+ settings_backup_valid = sys_settings_crc_ok(&p_storage_settings_sys->flash_settings_sys_backup, &sys_settings_update);
+
+ if (settings_valid) {
+ memcpy(&tuya_ble_current_para.sys_settings, &p_storage_settings_sys->flash_settings_sys, sizeof(tuya_ble_sys_settings_t));
+ } else if (settings_backup_valid) {
+ memcpy(&tuya_ble_current_para.sys_settings, &p_storage_settings_sys->flash_settings_sys_backup, sizeof(tuya_ble_sys_settings_t));
+ } else {
+ memset(&tuya_ble_current_para.sys_settings, 0, sizeof(tuya_ble_sys_settings_t));
+ tuya_ble_current_para.sys_settings.factory_test_flag = 0xFF;
+ sys_settings_flag = 0;
+ }
+
+ if (sys_settings_update == 1) {
+ tuya_ble_current_para.sys_settings.factory_test_flag = 0xFF;
+ tuya_ble_storage_save_sys_settings();
+ sys_settings_update = 0;
+ }
+
+ tuya_ble_free((uint8_t *)p_storage_settings_sys);
+
+ }
+
+ tuya_ble_current_para.pid_type = tuya_ble_current_para.sys_settings.pid_type;
+ tuya_ble_current_para.pid_len = tuya_ble_current_para.sys_settings.pid_len;
+ memcpy(tuya_ble_current_para.pid, tuya_ble_current_para.sys_settings.common_pid, tuya_ble_current_para.pid_len);
+
+
+ return err_code;
+}
+
+
+uint32_t tuya_ble_storage_save_auth_settings(void)
+{
+ uint32_t err_code = 0;
+
+ tuya_ble_current_para.auth_settings.crc = tuya_ble_crc32_compute((uint8_t *)&tuya_ble_current_para.auth_settings + 4, sizeof(tuya_ble_current_para.auth_settings) - 4, NULL);
+
+ if (tuya_ble_nv_erase(TUYA_BLE_AUTH_FLASH_ADDR, TUYA_NV_ERASE_MIN_SIZE) == TUYA_BLE_SUCCESS) {
+ err_code = tuya_ble_nv_write(TUYA_BLE_AUTH_FLASH_ADDR, (uint8_t *)&tuya_ble_current_para.auth_settings, sizeof(tuya_ble_auth_settings_t));
+
+ if (err_code == TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_DEBUG("write flash_settings_auth data succeed!");
+
+ if (tuya_ble_nv_erase(TUYA_BLE_AUTH_FLASH_BACKUP_ADDR, TUYA_NV_ERASE_MIN_SIZE) == TUYA_BLE_SUCCESS) {
+ if (tuya_ble_nv_write(TUYA_BLE_AUTH_FLASH_BACKUP_ADDR, (uint8_t *)&tuya_ble_current_para.auth_settings, sizeof(tuya_ble_auth_settings_t)) != TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_ERROR("write flash_settings_auth data backup failed!");
+ err_code = 1;
+ }
+ } else {
+ TUYA_BLE_LOG_ERROR("erase flash_settings_auth data backup failed!");
+ err_code = 1;
+ }
+ } else {
+ TUYA_BLE_LOG_ERROR("write flash_settings_auth data failed!");
+ err_code = 1;
+ }
+ } else {
+ TUYA_BLE_LOG_ERROR("erase flash_settings_auth data failed!");
+ err_code = 1;
+ }
+ return err_code;
+
+}
+
+uint32_t tuya_ble_storage_save_sys_settings(void)
+{
+ uint32_t err_code = 0;
+
+#if (TUYA_BLE_DEVICE_AUTH_DATA_STORE)
+
+ tuya_ble_current_para.sys_settings.crc = tuya_ble_crc32_compute((uint8_t *)&tuya_ble_current_para.sys_settings + 4, sizeof(tuya_ble_sys_settings_t) - 4, NULL);
+
+ if (tuya_ble_nv_erase(TUYA_BLE_SYS_FLASH_ADDR, TUYA_NV_ERASE_MIN_SIZE) == TUYA_BLE_SUCCESS) {
+ err_code = tuya_ble_nv_write(TUYA_BLE_SYS_FLASH_ADDR, (uint8_t *)&tuya_ble_current_para.sys_settings, sizeof(tuya_ble_sys_settings_t));
+
+ if (err_code == TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_INFO("write flash_settings_sys data succeed!");
+
+ if (tuya_ble_nv_erase(TUYA_BLE_SYS_FLASH_BACKUP_ADDR, TUYA_NV_ERASE_MIN_SIZE) == TUYA_BLE_SUCCESS) {
+ if (tuya_ble_nv_write(TUYA_BLE_SYS_FLASH_BACKUP_ADDR, (uint8_t *)&tuya_ble_current_para.sys_settings, sizeof(tuya_ble_sys_settings_t)) != TUYA_BLE_SUCCESS) {
+ TUYA_BLE_LOG_ERROR("write flash_settings_sys data backup failed!");
+ err_code = 1;
+ }
+ } else {
+ TUYA_BLE_LOG_ERROR("erase flash_settings_sys data backup failed!");
+ err_code = 1;
+ }
+
+ } else {
+ TUYA_BLE_LOG_ERROR("write flash_settings_sys data failed!");
+ err_code = 1;
+ }
+ } else {
+ TUYA_BLE_LOG_ERROR("erase flash_settings_sys data failed!");
+ err_code = 1;
+ }
+
+#endif
+
+ return err_code;
+}
+
+
+
+uint32_t tuya_ble_storage_init(void)
+{
+ uint32_t err = 0;
+
+ tuya_ble_nv_init();
+
+#if (TUYA_BLE_DEVICE_AUTH_DATA_STORE)
+
+ tuya_ble_storage_load_settings();
+
+#endif
+ return err;
+}
+
+#if (TUYA_BLE_DEVICE_AUTH_DATA_STORE)
+/**
+ * @brief Function for write pid to nv
+ *
+ * @note
+ *
+ * */
+tuya_ble_status_t tuya_ble_storage_write_pid(tuya_ble_product_id_type_t pid_type, uint8_t pid_len, uint8_t *pid)
+{
+ tuya_ble_status_t ret = TUYA_BLE_SUCCESS;
+ uint8_t is_write = 0;
+
+ if (pid_len > TUYA_BLE_PRODUCT_ID_MAX_LEN) {
+ return TUYA_BLE_ERR_INVALID_PARAM;
+ }
+
+ if ((pid_type != tuya_ble_current_para.pid_type) || (pid_len != tuya_ble_current_para.pid_len)) {
+ tuya_ble_current_para.pid_type = pid_type;
+ tuya_ble_current_para.pid_len = pid_len;
+ memcpy(tuya_ble_current_para.pid, pid, pid_len);
+ tuya_ble_current_para.sys_settings.pid_type = pid_type;
+ tuya_ble_current_para.sys_settings.pid_len = pid_len;
+ memcpy(tuya_ble_current_para.sys_settings.common_pid, pid, pid_len);
+ is_write = 1;
+ } else if (memcmp(pid, tuya_ble_current_para.pid, pid_len) != 0) {
+ tuya_ble_current_para.pid_type = pid_type;
+ tuya_ble_current_para.pid_len = pid_len;
+ memcpy(tuya_ble_current_para.pid, pid, pid_len);
+ tuya_ble_current_para.sys_settings.pid_type = pid_type;
+ tuya_ble_current_para.sys_settings.pid_len = pid_len;
+ memcpy(tuya_ble_current_para.sys_settings.common_pid, pid, pid_len);
+ is_write = 1;
+ } else {
+
+ }
+ if (is_write == 1) {
+ if (tuya_ble_storage_save_sys_settings()) {
+ ret = TUYA_BLE_ERR_BUSY;
+ }
+ }
+
+ return ret;
+}
+
+
+/**
+ * @brief Function for write hid to nv
+ *
+ * @note
+ *
+ * */
+tuya_ble_status_t tuya_ble_storage_write_hid(uint8_t *hid, uint8_t len)
+{
+ tuya_ble_status_t ret = TUYA_BLE_SUCCESS;
+
+ if (len != H_ID_LEN) {
+ ret = TUYA_BLE_ERR_INVALID_PARAM;
+ } else {
+ if (memcmp(hid, tuya_ble_current_para.auth_settings.h_id, H_ID_LEN) != 0) {
+ memcpy(tuya_ble_current_para.auth_settings.h_id, hid, H_ID_LEN);
+ if (tuya_ble_storage_save_auth_settings()) {
+ ret = TUYA_BLE_ERR_BUSY;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Function for read id parameters
+ *
+ * @note
+ *
+ * */
+tuya_ble_status_t tuya_ble_storage_read_id_info(tuya_ble_factory_id_data_t *id)
+{
+ tuya_ble_status_t ret = TUYA_BLE_SUCCESS;
+
+ id->pid_type = tuya_ble_current_para.pid_type;
+ id->pid_len = tuya_ble_current_para.pid_len;
+ memcpy(id->pid, tuya_ble_current_para.pid, tuya_ble_current_para.pid_len);
+
+ memcpy(id->h_id, tuya_ble_current_para.auth_settings.h_id, H_ID_LEN);
+ memcpy(id->device_id, tuya_ble_current_para.auth_settings.device_id, DEVICE_ID_LEN);
+ memcpy(id->mac, tuya_ble_current_para.auth_settings.mac, MAC_LEN);
+ memcpy(id->auth_key, tuya_ble_current_para.auth_settings.auth_key, AUTH_KEY_LEN);
+
+ return ret;
+}
+
+
+/**
+ * @brief Function for write auth key/uuid/mac/pid
+ *
+ * @note If the id length is 0, the corresponding id will not be written.
+ *
+ * */
+tuya_ble_status_t tuya_ble_storage_write_auth_key_device_id_mac(uint8_t *auth_key, uint8_t auth_key_len, uint8_t *device_id, uint8_t device_id_len,
+ uint8_t *mac, uint8_t mac_len, uint8_t *mac_string, uint8_t mac_string_len, uint8_t *pid, uint8_t pid_len)
+{
+ tuya_ble_status_t ret = TUYA_BLE_SUCCESS;
+ uint8_t is_write = 0;
+
+ if (((auth_key_len != AUTH_KEY_LEN) && (auth_key_len != 0)) || ((device_id_len != DEVICE_ID_LEN) && (device_id_len != 0)) || ((mac_len != MAC_LEN) && (mac_len != 0))) {
+ ret = TUYA_BLE_ERR_INVALID_PARAM;
+ } else {
+ if (auth_key_len == AUTH_KEY_LEN) {
+ if (memcmp(tuya_ble_current_para.auth_settings.auth_key, auth_key, AUTH_KEY_LEN) != 0) {
+ memcpy(tuya_ble_current_para.auth_settings.auth_key, auth_key, AUTH_KEY_LEN);
+ is_write = 1;
+ }
+ }
+ if (device_id_len == DEVICE_ID_LEN) {
+ if (memcmp(tuya_ble_current_para.auth_settings.device_id, device_id, DEVICE_ID_LEN) != 0) {
+ memcpy(tuya_ble_current_para.auth_settings.device_id, device_id, DEVICE_ID_LEN);
+ is_write = 1;
+ }
+ }
+ if (mac_len == MAC_LEN) {
+ if (memcmp(tuya_ble_current_para.auth_settings.mac, mac, MAC_LEN) != 0) {
+ memcpy(tuya_ble_current_para.auth_settings.mac, mac, MAC_LEN);
+ memcpy(tuya_ble_current_para.auth_settings.mac_string, mac_string, MAC_LEN * 2);
+ is_write = 1;
+ }
+ }
+ if (pid_len > 0) {
+ if ((tuya_ble_current_para.auth_settings.pid_len != pid_len) || (memcmp(tuya_ble_current_para.auth_settings.factory_pid, pid, pid_len) != 0)) {
+ memcpy(tuya_ble_current_para.auth_settings.factory_pid, pid, pid_len);
+ tuya_ble_current_para.auth_settings.pid_len = pid_len;
+ tuya_ble_current_para.auth_settings.pid_type = (uint8_t)TUYA_BLE_PRODUCT_ID_TYPE_PID;
+ is_write = 1;
+ }
+ }
+
+ if (is_write == 1) {
+
+#if (!TUYA_BLE_DEVICE_AUTH_DATA_STORE_EXT_MEDIUM)
+ if (tuya_ble_storage_save_auth_settings()) {
+ ret = TUYA_BLE_ERR_BUSY;
+ }
+#else
+ tuya_ble_current_para.auth_settings.crc = tuya_ble_crc32_compute((uint8_t *)&tuya_ble_current_para.auth_settings + 4, sizeof(tuya_ble_current_para.auth_settings) - 4, NULL);
+
+ if (tuya_ble_storage_private_data(PRIVATE_DATA_TUYA_AUTH_TOKEN, (uint8_t *)&tuya_ble_current_para.auth_settings, sizeof(tuya_ble_auth_settings_t))) {
+ ret = TUYA_BLE_ERR_BUSY;
+ }
+#endif // (!TUYA_BLE_DEVICE_AUTH_DATA_STORE_EXT_MEDIUM)
+ else {
+ /* force clear device_virtual_id info */
+ //if(tuya_ble_current_para.sys_settings.bound_flag==1)
+ {
+ memset(tuya_ble_current_para.sys_settings.device_virtual_id, 0, DEVICE_VIRTUAL_ID_LEN);
+ memset(tuya_ble_current_para.sys_settings.login_key, 0, LOGIN_KEY_LEN);
+ tuya_ble_current_para.sys_settings.bound_flag = 0;
+ tuya_ble_storage_save_sys_settings();
+ tuya_ble_adv_change();
+ tuya_ble_connect_status_set(UNBONDING_UNCONN);
+ TUYA_BLE_LOG_INFO("The state has changed, current bound flag = %d", tuya_ble_current_para.sys_settings.bound_flag);
+ }
+ }
+ }
+
+ }
+
+ return ret;
+}
+
+#endif
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_unix_time.c b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_unix_time.c
new file mode 100644
index 0000000..80def9c
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_unix_time.c
@@ -0,0 +1,284 @@
+/**
+ * \file tuya_ble_unix_time.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_unix_time.h"
+
+
+
+#define UTC_BASE_YEAR 1970
+#define MONTH_PER_YEAR 12
+#define DAY_PER_YEAR 365
+#define SEC_PER_DAY 86400
+#define SEC_PER_HOUR 3600
+#define SEC_PER_MIN 60
+
+/* Number of days per month */
+static const uint8_t g_day_per_mon[MONTH_PER_YEAR] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+
+
+
+/**
+ * @brief Function for Determine whether it is a leap year.
+ *
+ * @return 1:leap year
+ * @note
+ *.
+ * */
+static uint8_t applib_dt_is_leap_year(uint16_t year)
+{
+ /*----------------------------------------------------------------*/
+ /* Local Variables */
+ /*----------------------------------------------------------------*/
+
+ /*----------------------------------------------------------------*/
+ /* Code Body */
+ /*----------------------------------------------------------------*/
+ if ((year % 400) == 0) {
+ return 1;
+ } else if ((year % 100) == 0) {
+ return 0;
+ } else if ((year % 4) == 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+/**
+ * @brief Function for obtain the days of month.
+ *
+ * @return days
+ * @note
+ *.
+ * */
+static uint8_t applib_dt_last_day_of_mon(uint8_t month, uint16_t year)
+{
+ /*----------------------------------------------------------------*/
+ /* Local Variables */
+ /*----------------------------------------------------------------*/
+
+ /*----------------------------------------------------------------*/
+ /* Code Body */
+ /*----------------------------------------------------------------*/
+ if ((month == 0) || (month > 12)) {
+ return g_day_per_mon[1] + applib_dt_is_leap_year(year);
+ }
+
+ if (month != 2) {
+ return g_day_per_mon[month - 1];
+ } else {
+ return g_day_per_mon[1] + applib_dt_is_leap_year(year);
+ }
+}
+
+
+/**
+ * @brief Function for get the corresponding week based on the given date.
+ *
+ * @return
+ * @note 0-Sunday 6-Saturday
+ *.
+ * */
+static uint8_t applib_dt_dayindex(uint16_t year, uint8_t month, uint8_t day)
+{
+ int8_t century_code, year_code, month_code, day_code;
+ int32_t week = 0;
+
+ century_code = year_code = month_code = day_code = 0;
+
+ if (month == 1 || month == 2) {
+ century_code = (year - 1) / 100;
+ year_code = (year - 1) % 100;
+ month_code = month + 12;
+ day_code = day;
+ } else {
+ century_code = year / 100;
+ year_code = year % 100;
+ month_code = month;
+ day_code = day;
+ }
+
+ week = year_code + year_code / 4 + century_code / 4 - 2 * century_code + 26 * (month_code + 1) / 10 + day_code - 1;
+ week = week > 0 ? (week % 7) : ((week % 7) + 7);
+
+ return week;
+}
+
+
+/**
+ * @brief Function for Get the corresponding date according to the UTC timestamp.
+ *
+ * @param[in] daylightSaving:daylight saving time
+ * @return
+ * @note
+ *.
+ * */
+void tuya_ble_utc_sec_2_mytime(uint32_t utc_sec, tuya_ble_time_struct_data_t *result, bool daylightSaving)
+{
+ /*----------------------------------------------------------------*/
+ /* Local Variables */
+ /*----------------------------------------------------------------*/
+ int32_t sec, day;
+ uint16_t y;
+ uint8_t m;
+ uint16_t d;
+ // uint8_t dst;
+
+ /*----------------------------------------------------------------*/
+ /* Code Body */
+ /*----------------------------------------------------------------*/
+
+ if (daylightSaving) {
+ utc_sec += SEC_PER_HOUR;
+ }
+
+ /* hour, min, sec */
+ /* hour */
+ sec = utc_sec % SEC_PER_DAY;
+ result->nHour = sec / SEC_PER_HOUR;
+
+ /* min */
+ sec %= SEC_PER_HOUR;
+ result->nMin = sec / SEC_PER_MIN;
+
+ /* sec */
+ result->nSec = sec % SEC_PER_MIN;
+
+ /* year, month, day */
+ /* year */
+ /* year */
+ day = utc_sec / SEC_PER_DAY;
+ for (y = UTC_BASE_YEAR; day > 0; y++) {
+ d = (DAY_PER_YEAR + applib_dt_is_leap_year(y));
+ if (day >= d) {
+ day -= d;
+ } else {
+ break;
+ }
+ }
+
+ result->nYear = y;
+
+ for (m = 1; m < MONTH_PER_YEAR; m++) {
+ d = applib_dt_last_day_of_mon(m, y);
+ if (day >= d) {
+ day -= d;
+ } else {
+ break;
+ }
+ }
+
+ result->nMonth = m;
+ result->nDay = (uint8_t)(day + 1);
+
+ result->DayIndex = applib_dt_dayindex(result->nYear, result->nMonth, result->nDay);
+}
+
+/**
+ * @brief Function for Get the UTC timestamp according to corresponding date .
+ *
+ * @param[in] daylightSaving:daylight saving time
+ * @return
+ * @note
+ *.
+ * */
+uint32_t tuya_ble_mytime_2_utc_sec(tuya_ble_time_struct_data_t *currTime, bool daylightSaving)
+{
+ /*----------------------------------------------------------------*/
+ /* Local Variables */
+ /*----------------------------------------------------------------*/
+ uint16_t i;
+ uint32_t no_of_days = 0;
+ uint32_t utc_time;
+ uint8_t dst = 1;
+
+ /*----------------------------------------------------------------*/
+ /* Code Body */
+ /*----------------------------------------------------------------*/
+ if (currTime->nYear < UTC_BASE_YEAR) {
+ return 0;
+ }
+
+ /* year */
+ for (i = UTC_BASE_YEAR; i < currTime->nYear; i++) {
+ no_of_days += (DAY_PER_YEAR + applib_dt_is_leap_year(i));
+ }
+
+ /* month */
+ for (i = 1; i < currTime->nMonth; i++) {
+ no_of_days += applib_dt_last_day_of_mon((unsigned char) i, currTime->nYear);
+ }
+
+ /* day */
+ no_of_days += (currTime->nDay - 1);
+
+ /* sec */
+ utc_time = (unsigned int) no_of_days * SEC_PER_DAY + (unsigned int)(currTime->nHour * SEC_PER_HOUR +
+ currTime->nMin * SEC_PER_MIN + currTime->nSec);
+
+ if (dst && daylightSaving) {
+ utc_time -= SEC_PER_HOUR;
+ }
+
+ return utc_time;
+}
+
+
+void tuya_ble_utc_sec_2_mytime_string(uint32_t utc_sec, bool daylightSaving, char *s)
+{
+ tuya_ble_time_struct_data_t rtc_time = {0};
+ uint32_t temp = 0;
+
+ tuya_ble_utc_sec_2_mytime(utc_sec, &rtc_time, daylightSaving);
+
+ temp = rtc_time.nYear;
+ s[0] = temp / 1000 + 0x30;
+ temp = rtc_time.nYear % 1000;
+ s[1] = temp / 100 + 0x30;
+ temp = temp % 100;
+ s[2] = temp / 10 + 0x30;
+ s[3] = temp % 10 + 0x30;
+ s[4] = '-';
+ s[5] = rtc_time.nMonth / 10 + 0x30;
+ s[6] = rtc_time.nMonth % 10 + 0x30;
+ s[7] = '-';
+ s[8] = rtc_time.nDay / 10 + 0x30;
+ s[9] = rtc_time.nDay % 10 + 0x30;
+ s[10] = ' ';
+ s[11] = rtc_time.nHour / 10 + 0x30;
+ s[12] = rtc_time.nHour % 10 + 0x30;
+ s[13] = ':';
+ s[14] = rtc_time.nMin / 10 + 0x30;
+ s[15] = rtc_time.nMin % 10 + 0x30;
+ s[16] = ':';
+ s[17] = rtc_time.nSec / 10 + 0x30;
+ s[18] = rtc_time.nSec % 10 + 0x30;
+ s[19] = '\0';
+}
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_utils.c b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_utils.c
new file mode 100644
index 0000000..fc60185
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/sdk/src/tuya_ble_utils.c
@@ -0,0 +1,773 @@
+/**
+ * \file tuya_ble_utils.c
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+#include "tuya_ble_stdlib.h"
+#include "tuya_ble_utils.h"
+#include "tuya_ble_port.h"
+#include "tuya_ble_mem.h"
+
+
+int32_t tuya_ble_count_bits(uint32_t data)
+{
+ int32_t i = 0;
+ int32_t cnt = 0;
+
+ for (i = 0; i < 32; i++) {
+ if (data & 0x01) {
+ cnt++;
+ }
+
+ data >>= 1;
+ }
+
+ return cnt;
+}
+
+int32_t tuya_ble_rand_number(int32_t min, int32_t max)
+{
+ static bool is_srand_init = false;
+ int32_t num;
+
+ if (!is_srand_init) {
+ is_srand_init = true;
+ //srand(time(NULL));
+ }
+
+ num = rand() % (max - min) + min; // [min<=num<=max]
+
+ return num;
+}
+
+void tuya_ble_inverted_array(uint8_t *array, uint16_t length)
+{
+ uint8_t temp;
+ uint16_t i, j;
+ for (i = 0, j = length - 1; i < j; i++, j--) {
+ temp = array[i];
+ array[i] = array[j];
+ array[j] = temp;
+ }
+}
+
+bool tuya_ble_buffer_value_is_all_x(uint8_t *buffer, uint16_t len, uint8_t value)
+{
+ bool ret = true;
+ for (uint16_t i = 0; i < len; i++) {
+ if (buffer[i] != value) {
+ ret = false;
+ break;
+ }
+ }
+ return ret;
+}
+
+
+uint8_t tuya_ble_check_sum(uint8_t *pbuf, uint16_t len)
+{
+ uint32_t i = 0, ck_sum = 0;
+
+ for (i = 0; i < len ; i++) {
+ ck_sum += pbuf[i];
+ }
+ return (uint8_t)ck_sum;
+}
+
+uint8_t tuya_ble_check_num(uint8_t *buf, uint8_t num)
+{
+ uint8_t i = 0;
+
+ for (; i < buf[0]; i++) {
+ if (buf[i + 1] == num) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void tuya_ble_hextoascii(uint8_t *hexbuf, uint8_t len, uint8_t *ascbuf)
+{
+ uint8_t i = 0, j = 0, temp = 0;
+
+ for (i = 0; i < len; i++) {
+ temp = (hexbuf[i] >> 4) & 0xf;
+ if (temp <= 9) {
+ ascbuf[j] = temp + 0x30;
+ } else {
+ ascbuf[j] = temp + 87;
+ }
+ j++;
+ temp = (hexbuf[i]) & 0xf;
+ if (temp <= 9) {
+ ascbuf[j] = temp + 0x30;
+ } else {
+ ascbuf[j] = temp + 87;
+ }
+ j++;
+ }
+
+}
+
+void tuya_ble_hextostr(uint8_t *hexbuf, uint8_t len, uint8_t *strbuf)
+{
+ uint8_t i = 0, j = 0, temp = 0;
+
+ for (i = 0; i < len; i++) {
+ temp = (hexbuf[i] >> 4) & 0x0f;
+ if (temp <= 9) {
+ strbuf[j] = temp + 0x30;
+ } else {
+ strbuf[j] = temp + 87;
+ }
+ j++;
+ temp = (hexbuf[i]) & 0x0f;
+ if (temp <= 9) {
+ strbuf[j] = temp + 0x30;
+ } else {
+ strbuf[j] = temp + 87;
+ }
+ j++;
+ }
+ strbuf[j] = 0x00;
+}
+
+void tuya_ble_asciitohex(uint8_t *ascbuf, uint8_t *hexbuf)
+{
+ uint8_t i = 0, j = 0;
+
+ while (ascbuf[i]) {
+ j++;
+ if ((ascbuf[i] >= 0x30) && (ascbuf[i] <= 0x39)) {
+ hexbuf[j] = ((ascbuf[i] - 0x30) << 4);
+ } else if ((ascbuf[i] >= 65) && (ascbuf[i] <= 70)) {
+ hexbuf[j] = ((ascbuf[i] - 55) << 4);
+ } else if ((ascbuf[i] >= 97) && (ascbuf[i] <= 102)) {
+ hexbuf[j] = ((ascbuf[i] - 87) << 4);
+ }
+ i++;
+ if ((ascbuf[i] >= 0x30) && (ascbuf[i] <= 0x39)) {
+ hexbuf[j] |= (ascbuf[i] - 0x30);
+ } else if ((ascbuf[i] >= 65) && (ascbuf[i] <= 70)) {
+ hexbuf[j] |= (ascbuf[i] - 55);
+ } else if ((ascbuf[i] >= 97) && (ascbuf[i] <= 102)) {
+ hexbuf[j] |= (ascbuf[i] - 87);
+ }
+ i++;
+ }
+ hexbuf[0] = j;
+}
+
+
+
+uint8_t tuya_ble_char_2_ascii(uint8_t data)
+{
+ uint8_t ret = 0xff;
+
+ if ((data >= 48) && (data <= 57)) {
+ ret = data - 48;
+ } else if ((data >= 65) && (data <= 70)) {
+ ret = data - 55;
+ } else if ((data >= 97) && (data <= 102)) {
+ ret = data - 87;
+ }
+ return ret;
+}
+
+void tuya_ble_str_to_hex(uint8_t *str_buf, uint8_t str_len, uint8_t *hex_buf)
+{
+ uint8_t data_tmp = 0, i = 0, j = 0;
+
+ for (j = 0 ; j < str_len ; j++) {
+ data_tmp = tuya_ble_char_2_ascii(str_buf[j]);
+ if (data_tmp != 0xff) {
+ hex_buf[i] = (data_tmp << 4);
+ } else {
+ return;
+ }
+ j++;
+ data_tmp = tuya_ble_char_2_ascii(str_buf[j]);
+ if (data_tmp != 0xff) {
+ hex_buf[i] += data_tmp;
+ } else {
+ return;
+ }
+ i++;
+ }
+}
+
+void tuya_ble_swap(int16_t *a, int16_t *b)
+{
+ int16_t temp;
+ temp = *a;
+ *a = *b;
+ *b = temp;
+}
+
+
+int32_t tuya_ble_hex2int(uint8_t mhex)
+{
+ switch (mhex) {
+ case '0':
+ return 0;
+ case '1':
+ return 1;
+ case '2':
+ return 2;
+ case '3':
+ return 3;
+ case '4':
+ return 4;
+ case '5':
+ return 5;
+ case '6':
+ return 6;
+ case '7':
+ return 7;
+ case '8':
+ return 8;
+ case '9':
+ return 9;
+ case 'a':
+ case 'A':
+ return 10;
+ case 'b':
+ case 'B':
+ return 11;
+ case 'c':
+ case 'C':
+ return 12;
+ case 'd':
+ case 'D':
+ return 13;
+ case 'e':
+ case 'E':
+ return 14;
+ case 'f':
+ case 'F':
+ return 15;
+ default:
+ return -1;
+ }
+}
+char tuya_ble_hexstr2int(uint8_t *hexstr, int32_t len, uint8_t *sum)
+{
+ *sum = 0;
+ int32_t value;
+ for (int32_t i = 0; i < len; i++) {
+ value = tuya_ble_hex2int(hexstr[i]);
+ if (value == -1) {
+ return 0;
+ }
+ (*sum) = (*sum) << 4;
+ (*sum) += value;
+ }
+ return 1;
+}
+char tuya_ble_hexstr2hex(uint8_t *hexstr, int32_t len, uint8_t *hex)
+{
+ for (uint8_t i = 0; i < len; i += 2) {
+ if (tuya_ble_hexstr2int(&hexstr[i], 2, &hex[i / 2]) == 0) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+static void swapX(const uint8_t *src, uint8_t *dst, int32_t len)
+{
+ int32_t i;
+ for (i = 0; i < len; i++) {
+ dst[len - 1 - i] = src[i];
+ }
+}
+
+void tuya_ble_swap24(uint8_t dst[3], const uint8_t src[3])
+{
+ swapX(src, dst, 3);
+}
+
+void tuya_ble_swap32(uint8_t dst[4], const uint8_t src[4])
+{
+ swapX(src, dst, 4);
+}
+
+void tuya_ble_swap48(uint8_t dst[7], const uint8_t src[7])
+{
+ swapX(src, dst, 6);
+}
+
+void tuya_ble_swap56(uint8_t dst[7], const uint8_t src[7])
+{
+ swapX(src, dst, 7);
+}
+
+void tuya_ble_swap64(uint8_t dst[8], const uint8_t src[8])
+{
+ swapX(src, dst, 8);
+}
+
+void tuya_ble_swap128(uint8_t dst[16], const uint8_t src[16])
+{
+ swapX(src, dst, 16);
+}
+
+
+
+uint16_t tuya_ble_crc16_compute(uint8_t *p_data, uint16_t size, uint16_t *p_crc)
+{
+
+ uint16_t poly[2] = {0, 0xa001}; //0x8005 <==> 0xa001
+ uint16_t crc;
+ int i, j;
+ crc = (p_crc == NULL) ? 0xFFFF : *p_crc;
+
+ for (j = size; j > 0; j--) {
+ unsigned char ds = *p_data++;
+
+ for (i = 0; i < 8; i++) {
+ crc = (crc >> 1) ^ poly[(crc ^ ds) & 1];
+ ds = ds >> 1;
+ }
+ }
+
+ return crc;
+}
+
+
+uint32_t tuya_ble_crc32_compute(uint8_t const *p_data, uint32_t size, uint32_t const *p_crc)
+{
+ uint32_t crc;
+ crc = (p_crc == NULL) ? 0xFFFFFFFF : ~(*p_crc);
+ for (uint32_t i = 0; i < size; i++) {
+ crc = crc ^ p_data[i];
+ for (uint32_t j = 8; j > 0; j--) {
+ crc = (crc >> 1) ^ (0xEDB88320U & ((crc & 1) ? 0xFFFFFFFF : 0));
+ }
+ }
+ return ~crc;
+}
+
+
+
+/**@brief Function for checking if a pointer value is aligned to a 4 byte boundary.
+ *
+ * @param[in] p Pointer value to be checked.
+ *
+ * @return TRUE if pointer is aligned to a 4 byte boundary, FALSE otherwise.
+ */
+bool tuya_ble_is_word_aligned_tuya(void const *p)
+{
+ return (((uintptr_t)p & 0x03) == 0);
+}
+
+
+
+void tuya_ble_device_id_20_to_16(uint8_t *in, uint8_t *out)
+{
+ uint8_t i, j;
+ uint8_t temp[4];
+ for (i = 0; i < 5; i++) {
+ for (j = i * 4; j < (i * 4 + 4); j++) {
+ if ((in[j] >= 0x30) && (in[j] <= 0x39)) {
+ temp[j - i * 4] = in[j] - 0x30;
+ } else if ((in[j] >= 0x41) && (in[j] <= 0x5A)) {
+ temp[j - i * 4] = in[j] - 0x41 + 36;
+ } else if ((in[j] >= 0x61) && (in[j] <= 0x7A)) {
+ temp[j - i * 4] = in[j] - 0x61 + 10;
+ } else {
+
+ }
+ }
+
+ out[i * 3] = temp[0] & 0x3F;
+ out[i * 3] <<= 2;
+ out[i * 3] |= ((temp[1] >> 4) & 0x03);
+
+ out[i * 3 + 1] = temp[1] & 0x0F;
+ out[i * 3 + 1] <<= 4;
+ out[i * 3 + 1] |= ((temp[2] >> 2) & 0x0F);
+
+ out[i * 3 + 2] = temp[2] & 0x03;
+ out[i * 3 + 2] <<= 6;
+ out[i * 3 + 2] |= temp[3] & 0x3F;
+
+ }
+
+ out[15] = 0xFF;
+}
+
+void tuya_ble_device_id_16_to_20(uint8_t *in, uint8_t *out)
+{
+ uint8_t i, j;
+ uint8_t temp[4];
+ for (i = 0; i < 5; i++) {
+ j = i * 3;
+ temp[j - i * 3] = (in[j] >> 2) & 0x3F;
+ temp[j - i * 3 + 1] = in[j] & 0x03;
+ temp[j - i * 3 + 1] <<= 4;
+ temp[j - i * 3 + 1] |= (in[j + 1] >> 4) & 0x0F;
+ temp[j - i * 3 + 2] = (in[j + 1] & 0x0F) << 2;
+ temp[j - i * 3 + 2] |= ((in[j + 2] & 0xC0) >> 6) & 0x03;
+ temp[j - i * 3 + 3] = in[j + 2] & 0x3F;
+
+ for (j = i * 4; j < (i * 4 + 4); j++) {
+ if ((temp[j - i * 4] >= 0) && (temp[j - i * 4] <= 9)) {
+ out[j] = temp[j - i * 4] + 0x30;
+ } else if ((temp[j - i * 4] >= 10) && (temp[j - i * 4] <= 35)) {
+ out[j] = temp[j - i * 4] + 87;
+ } else if ((temp[j - i * 4] >= 36) && (temp[j - i * 4] <= 61)) {
+ out[j] = temp[j - i * 4] + 29;
+ } else {
+
+ }
+ }
+
+
+ }
+
+}
+
+
+/**
+ * @brief Function for search character/symbol index from input string
+ *
+ * @param
+ * [in]data : pointer to input data
+ * [in]data : Number of bytes of data
+ * [in]symbol : Search symbol or character, Such as ':' or ','
+ * [out]index[] : Array of indexs
+ *
+ * @return The number of matched character/symbol
+ *
+ * @note
+ *
+ * */
+int32_t tuya_ble_search_symbol_index(char *data, uint16_t len, char symbol, uint8_t index[])
+{
+ int32_t i;
+ uint8_t index_buf[64] = {0};
+ uint8_t symbol_cnt = 0;
+
+ if (data == NULL || len == 0 || index == NULL) {
+ return symbol_cnt;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (data[i] == symbol) {
+ index_buf[symbol_cnt] = i;
+ symbol_cnt += 1;
+
+ if (symbol_cnt >= sizeof(index_buf)) {
+ /* error, too many symbols */
+ break;
+ }
+ }
+ }
+
+ if (symbol_cnt != 0) {
+ memcpy(index, index_buf, symbol_cnt);
+ }
+
+ return symbol_cnt;
+}
+
+
+int32_t tuya_ble_ascii_to_int(char *ascii, uint16_t len)
+{
+ int32_t i;
+ int32_t num = 0;
+ bool negative = false;
+
+ if (ascii == NULL || len == 0) {
+ return num;
+ }
+
+ if (ascii[0] == 0x2D) {
+ negative = true;
+ } else {
+ num *= 10;
+ num += ascii[0] - '0';
+ }
+
+ for (i = 1; i < len; i++) {
+ num *= 10;
+ num += ascii[i] - '0';
+ }
+
+ if (negative) {
+ num = -1 * num;
+ }
+
+ return num;
+}
+
+
+static uint8_t base64_decode(const uint8_t *input, uint16_t inlen, uint8_t *output, uint16_t *outlen)
+{
+ const char *base64_tbl = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ uint8_t reverse_tbl[256] = {0};
+ int32_t off = 0;
+ int32_t i = 0;
+
+ if (NULL == input) {
+ return 1;
+ }
+
+ if (inlen == 0) {
+ inlen = strlen((char *)input);
+ }
+
+ if (inlen == 0 || (inlen % 4 != 0)) {
+ return 1;
+ }
+
+ for (i = 0; i < 64; i++) {
+ reverse_tbl[base64_tbl[i]] = i;
+ }
+
+ for (i = 0; i < inlen - 4; i += 4) {
+ output[off++] = (reverse_tbl[input[i]] << 2) | ((reverse_tbl[input[i + 1]] >> 4) & 0xFF);
+ output[off++] = (reverse_tbl[input[i + 1]] << 4) | ((reverse_tbl[input[i + 2]] >> 2) & 0xFF);
+ output[off++] = (reverse_tbl[input[i + 2]] << 6) | ((reverse_tbl[input[i + 3]]) & 0xFF);
+ }
+
+ if (input[i + 2] == '=') {
+ output[off++] = (reverse_tbl[input[i]] << 2) | ((reverse_tbl[input[i + 1]] >> 4) & 0xFF);
+ } else if (input[i + 3] == '=') {
+ output[off++] = (reverse_tbl[input[i]] << 2) | ((reverse_tbl[input[i + 1]] >> 4) & 0xFF);
+ output[off++] = (reverse_tbl[input[i + 1]] << 4) | ((reverse_tbl[input[i + 2]] >> 2) & 0xFF);
+ } else {
+ output[off++] = (reverse_tbl[input[i]] << 2) | ((reverse_tbl[input[i + 1]] >> 4) & 0xFF);
+ output[off++] = (reverse_tbl[input[i + 1]] << 4) | ((reverse_tbl[input[i + 2]] >> 2) & 0xFF);
+ output[off++] = (reverse_tbl[input[i + 2]] << 6) | ((reverse_tbl[input[i + 3]]) & 0xFF);
+ }
+
+ if (NULL != outlen) {
+ *outlen = off;
+ }
+
+ return 0;
+}
+
+static int32_t delChar(char *s, uint16_t len, char match_char)
+{
+ int32_t i, j;
+ int32_t counter = 0;
+
+ for (i = 0; i < len; i++) {
+ if (s[i] == match_char) {
+ counter++;
+
+ for (j = i; j < len; j++) {
+ s[j] = s[j + 1];
+ i--;
+ }
+ }
+ }
+ return counter;
+}
+
+
+/**
+ * @brief Function for pem format ecc key to hex foramt
+ *
+ * @param
+ * [in]pem : pointer to pem data
+ * [out]key : pointer to output data, hex format ecc key
+ * [out]key_len: Number of bytes of key.
+ *
+ * @return 0 - failed, 1 - success
+ *
+ * @note developer could use tuya_ble_ecc_key_pem2hex_example() function to test
+ *
+ * */
+int32_t tuya_ble_ecc_key_pem2hex(const char *pem, uint8_t *key, uint16_t *key_len)
+{
+ char buf1[256] = {0};
+ char buf2[256] = {0};
+ uint16_t inlen = 0;
+ uint16_t i, j, k = 0;
+ uint16_t len, len1, len2 = 0;
+
+ if (NULL == pem) {
+ return 0;
+ }
+
+ inlen = strlen(pem);
+
+ if (inlen > 256) {
+ return 0;
+ }
+
+ //head
+ if ((pem[0] != '-') || (pem[1] != '-') || (pem[2] != '-') || (pem[3] != '-') || (pem[4] != '-')) {
+ return 0;
+ }
+
+ //tail
+ if ((pem[inlen - 1] != '-') || (pem[inlen - 2] != '-') || (pem[inlen - 3] != '-') || (pem[inlen - 4] != '-') || (pem[inlen - 5] != '-')) {
+ return 0;
+ }
+
+ //find head end
+ for (i = 5; i < inlen - 5; i++) {
+ if (pem[i] == '-') {
+ if ((pem[i + 1] != '-') || (pem[i + 2] != '-') || (pem[i + 3] != '-') || (pem[i + 4] != '-')) {
+ return 0;
+ }
+
+ len1 = i + 5;
+ break;
+ }
+ }
+
+ //remove head
+ memcpy(buf1, pem + len1, inlen - len1);
+
+ //find tail
+ for (i = 0; i < inlen - len1; i++) {
+ if (buf1[i] == '-') {
+ if ((buf1[i + 1] != '-') || (buf1[i + 2] != '-') || (buf1[i + 3] != '-') || (buf1[i + 4] != '-')) {
+ return 0;
+ }
+
+ len2 = i;
+ break;
+ }
+ }
+ len = len2;
+
+ //remove \n
+ len1 = delChar(buf1, len, '\n');
+ len = len - len1;
+ //remove \r
+ len1 = delChar(buf1, len, '\r');
+ len = len - len1;
+
+ //decode
+ base64_decode((uint8_t *)buf1, len, (uint8_t *)buf2, (uint16_t *)&len2);
+
+ //next is asn.1 decode
+ if (buf2[0] != 0x30) { //0x30
+ return 0;
+ }
+
+ len1 = buf2[1];//0x30 0x41
+ if ((len1 + 2) != len2) {
+ return 0;
+ }
+
+ if (buf2[2] != 0x02) { //0x30 0x41 0x20 0x01 0x00
+ return 0;
+ }
+
+ if (buf2[5] != 0x30) {
+ return 0;
+ }
+
+ len1 = buf2[6];
+
+ if (buf2[7 + len1] != 0x04) { //0x04
+ return 0;
+ }
+
+// len2 = buf2[8+len1];//0x04 0x27
+
+ if (buf2[9 + len1] != 0x30) { //0x30
+ return 0;
+ }
+
+// len = buf2[10+len1];//0x25
+
+ if (buf2[11 + len1] != 0x02) { //0x02
+ return 0;
+ }
+
+ if (buf2[14 + len1] != 0x04) { //0x04
+ return 0;
+ }
+
+ *key_len = buf2[15 + len1];
+ memcpy(key, &buf2[16 + len1], *key_len);
+
+ return 1;
+}
+
+
+void tuya_ble_ecc_key_pem2hex_example(void)
+{
+ uint8_t key[64] = {0};
+ uint16_t keylen = 0;
+
+ char test_char[] =
+ "-----BEGIN PRIVATE KEY-----MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCBX5s0E0DJowr3ibkG41jfvjRFgaoCO7v8fU/Wq/xLlDQ==-----END PRIVATE KEY-----";
+
+ tuya_ble_ecc_key_pem2hex(test_char, key, &keylen);
+
+ /* output hex format key */
+ // 57 E6 CD 04 D0 32 68 C2 BD E2 6E 41 B8 D6 37 EF
+ // 8D 11 60 6A 80 8E EE FF 1F 53 F5 AA FF 12 E5 0D
+}
+
+
+/**
+ * @brief Function for extract r+s from der from ecdsa sign
+ *
+ * @param
+ * [in]der : pointer to der data
+ * [out]raw_rs : pointer to output data, the raw data[r+s] of der
+ *
+ * @return 0 - failed, 1 - success
+ *
+ * @note
+ *
+ * */
+int32_t tuya_ble_ecc_sign_secp256r1_extract_raw_from_der(const char *der, uint8_t *raw_rs)
+{
+ /* extract r + s from der */
+ int pos = 0;
+ uint8_t raw[64] = {0};
+
+ if (der == NULL || raw_rs == NULL) {
+ return 0;
+ }
+
+ if (der[3] != 0x20) {
+ memcpy(raw, &der[5], 32);
+ pos = 5 + 32;
+ } else {
+ memcpy(raw, &der[4], 32);
+ pos = 4 + 32;
+ }
+
+ // 37
+ if (der[pos + 1] != 0x20) {
+ memcpy(&raw[32], &der[pos + 3], 32);
+ } else {
+ memcpy(&raw[32], &der[pos + 2], 32);
+ }
+
+ memcpy(raw_rs, raw, sizeof(raw));
+ return 1;
+}
+
diff --git a/apps/common/third_party_profile/tuya_protocol/tuya_ble_config.h b/apps/common/third_party_profile/tuya_protocol/tuya_ble_config.h
new file mode 100644
index 0000000..b426d42
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/tuya_ble_config.h
@@ -0,0 +1,298 @@
+/**
+ * \file tuya_ble_config.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+
+#ifndef TUYA_BLE_CONFIG_H__
+#define TUYA_BLE_CONFIG_H__
+
+
+#if defined(CUSTOMIZED_TUYA_BLE_CONFIG_FILE)
+#include CUSTOMIZED_TUYA_BLE_CONFIG_FILE
+#endif
+
+
+/*
+ * If the application has a customized production test project(file),please define CUSTOMIZED_TUYA_BLE_APP_PRODUCT_TEST_FILE in CUSTOMIZED_TUYA_BLE_CONFIG_FILE.
+ */
+#ifndef CUSTOMIZED_TUYA_BLE_APP_PRODUCT_TEST_HEADER_FILE
+#undef CUSTOMIZED_TUYA_BLE_APP_PRODUCT_TEST_HEADER_FILE
+#endif
+
+/*
+ * If needed,please define CUSTOMIZED_TUYA_BLE_APP_UART_COMMON_FILE in CUSTOMIZED_TUYA_BLE_CONFIG_FILE.
+ */
+#ifndef CUSTOMIZED_TUYA_BLE_APP_UART_COMMON_HEADER_FILE
+#undef CUSTOMIZED_TUYA_BLE_APP_UART_COMMON_HEADER_FILE
+#endif
+
+
+/*
+ * If needed,please define TUYA_BLE_PORT_PLATFORM_HEADER_FILE in CUSTOMIZED_TUYA_BLE_CONFIG_FILE.
+ */
+#ifndef TUYA_BLE_PORT_PLATFORM_HEADER_FILE
+#undef TUYA_BLE_PORT_PLATFORM_HEADER_FILE
+#endif
+
+/*
+ * If using an OS, be sure to call the tuya api functions and SDK-related queues within the same task
+ */
+#ifndef TUYA_BLE_USE_OS
+#define TUYA_BLE_USE_OS 1
+#endif
+/*
+ * If using an OS, tuya ble sdk will create a task autonomously to process ble event.
+ */
+
+#if TUYA_BLE_USE_OS
+
+#ifndef TUYA_BLE_SELF_BUILT_TASK
+#define TUYA_BLE_SELF_BUILT_TASK 1
+#endif
+
+#if TUYA_BLE_SELF_BUILT_TASK
+
+#ifndef TUYA_BLE_TASK_PRIORITY
+#define TUYA_BLE_TASK_PRIORITY 1
+#endif
+
+#ifndef TUYA_BLE_TASK_STACK_SIZE
+#define TUYA_BLE_TASK_STACK_SIZE 256 * 10 //!< Task stack size ,application do not change this default value
+#endif
+
+#endif
+
+#endif
+/*
+ * TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_BLE ble normal
+ * TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_REGISTER_FROM_BLE device register from ble
+ * TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_MESH ble mesh
+ * TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_WIFI_24G wifi_2.4g
+ * TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_WIFI_5G wifi_5g
+ * TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_ZIGBEE zigbee
+ * TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_NB nb-iot
+ * @note:
+ * for example (TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_BLE|TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_MESH|TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_WIFI_24G)
+ */
+//#define TUYA_BLE_DEVICE_COMMUNICATION_ABILITY (TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_BLE|TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_WIFI_24G|TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_WIFI_5G)
+#ifndef TUYA_BLE_DEVICE_COMMUNICATION_ABILITY
+#define TUYA_BLE_DEVICE_COMMUNICATION_ABILITY (TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_BLE|TUYA_BLE_DEVICE_COMMUNICATION_ABILITY_REGISTER_FROM_BLE)
+#endif
+
+/*
+ * Whether it is a shared device.
+ */
+#ifndef TUYA_BLE_DEVICE_SHARED
+#define TUYA_BLE_DEVICE_SHARED 0
+#endif
+
+/*
+ * If it is 1, then sdk need to perform the unbind operation,otherwise sdk do not need.
+ */
+#ifndef TUYA_BLE_DEVICE_UNBIND_MODE
+#define TUYA_BLE_DEVICE_UNBIND_MODE 1
+#endif
+
+/*
+ * If TUYA_BLE_WIFI_DEVICE_REGISTER_MODE is 1,Mobile app must first sends instructions to query network status after sending the pairing request .
+ */
+#ifndef TUYA_BLE_WIFI_DEVICE_REGISTER_MODE
+#define TUYA_BLE_WIFI_DEVICE_REGISTER_MODE 1
+#endif
+
+/*
+ * if 1 ,tuya ble sdk authorization self-management
+ */
+#ifndef TUYA_BLE_DEVICE_AUTH_SELF_MANAGEMENT
+#define TUYA_BLE_DEVICE_AUTH_SELF_MANAGEMENT 1
+#endif
+
+/*
+ * TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY encrypt with auth key
+ * TUYA_BLE_SECURE_CONNECTION_WITH_ECC encrypt with ECDH
+ * TUYA_BLE_SECURE_CONNECTION_WTIH_PASSTHROUGH no encrypt
+ * TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION advanced encrypt(security chip ) with auth key
+ * @note : only choose one
+*/
+#ifndef TUYA_BLE_SECURE_CONNECTION_TYPE
+#define TUYA_BLE_SECURE_CONNECTION_TYPE TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY
+#endif
+
+/*
+ * MACRO for advanced encryption,if 1 will perform two-way authentication on every connection,otherwise perform certification at the first registration.
+ */
+#if (TUYA_BLE_SECURE_CONNECTION_TYPE==TUYA_BLE_SECURE_CONNECTION_WITH_AUTH_KEY_ADVANCED_ENCRYPTION)
+
+#ifndef TUYA_BLE_ADVANCED_ENCRYPTION_AUTH_ON_CONNECT
+#define TUYA_BLE_ADVANCED_ENCRYPTION_AUTH_ON_CONNECT 0
+#endif
+
+#ifndef TUYA_BLE_INCLUDE_CJSON_COMPONENTS
+#define TUYA_BLE_INCLUDE_CJSON_COMPONENTS 1
+#endif
+
+#endif
+
+/*
+ * if 1 ,ble sdk will update mac address with with the address of the authorization information.
+ */
+#ifndef TUYA_BLE_DEVICE_MAC_UPDATE
+#define TUYA_BLE_DEVICE_MAC_UPDATE 0
+#endif
+
+/*
+ * if 1 ,after update mac will reset.
+ */
+#ifndef TUYA_BLE_DEVICE_MAC_UPDATE_RESET
+#define TUYA_BLE_DEVICE_MAC_UPDATE_RESET 0
+#endif
+
+/*
+ * if defined ,ble sdk use platform memory heap.
+ */
+#ifndef TUYA_BLE_USE_PLATFORM_MEMORY_HEAP
+#define TUYA_BLE_USE_PLATFORM_MEMORY_HEAP 0
+#endif
+
+
+/*
+ * if defined ,include UART module
+ */
+//#define TUYA_BLE_UART
+
+
+/*
+ * if defined ,include product test module
+ */
+//#define TUYA_BLE_PRODUCTION_TEST
+
+
+/*
+ * gatt mtu max sizes
+ */
+
+#ifndef TUYA_BLE_DATA_MTU_MAX
+#define TUYA_BLE_DATA_MTU_MAX 243
+#endif
+
+/*
+ * if defined ,enable sdk log output
+ */
+
+#ifndef TUYA_BLE_LOG_ENABLE
+#define TUYA_BLE_LOG_ENABLE 1
+#endif
+
+#ifndef TUYA_BLE_LOG_COLORS_ENABLE
+#define TUYA_BLE_LOG_COLORS_ENABLE 0
+#endif
+
+#ifndef TUYA_BLE_LOG_LEVEL
+#define TUYA_BLE_LOG_LEVEL TUYA_BLE_LOG_LEVEL_DEBUG
+#endif
+
+
+/*
+ * if defined ,enable app log output
+ */
+
+#ifndef TUYA_APP_LOG_ENABLE
+#define TUYA_APP_LOG_ENABLE 1
+#endif
+
+#ifndef TUYA_APP_LOG_COLORS_ENABLE
+#define TUYA_APP_LOG_COLORS_ENABLE 0
+#endif
+
+#ifndef TUYA_APP_LOG_LEVEL
+#define TUYA_APP_LOG_LEVEL TUYA_APP_LOG_LEVEL_DEBUG
+#endif
+
+/*
+ * If it is 1, then sdk need to request beacon key from app when binding .
+ */
+#ifndef TUYA_BLE_BEACON_KEY_ENABLE
+#define TUYA_BLE_BEACON_KEY_ENABLE 0
+#endif
+
+/*
+ * Enable the weather module.
+ */
+#ifndef TUYA_BLE_FEATURE_WEATHER_ENABLE
+#define TUYA_BLE_FEATURE_WEATHER_ENABLE 0
+#endif
+
+/*
+ * Enable support the link layer encryption.
+ */
+#ifndef TUYA_BLE_LINK_LAYER_ENCRYPTION_SUPPORT_ENABLE
+#define TUYA_BLE_LINK_LAYER_ENCRYPTION_SUPPORT_ENABLE 0
+#endif
+
+/*
+ * Whether to automatically perform a time request after the connection is established.
+ * - 0 Not request.
+ * - 1 Request cloud time.
+ * - 2 Request phone local time.
+ */
+#ifndef TUYA_BLE_AUTO_REQUEST_TIME_CONFIGURE
+#define TUYA_BLE_AUTO_REQUEST_TIME_CONFIGURE 1
+#endif
+
+
+//nv
+/* The minimum size of flash erasure. May be a flash sector size. */
+#ifndef TUYA_NV_ERASE_MIN_SIZE
+#define TUYA_NV_ERASE_MIN_SIZE (0x100)
+#endif
+/* the flash write granularity, unit: byte*/
+#ifndef TUYA_NV_WRITE_GRAN
+#define TUYA_NV_WRITE_GRAN (4)
+#endif
+/* start address */
+#ifndef TUYA_NV_START_ADDR
+#define TUYA_NV_START_ADDR 0
+#endif
+
+/* area size. */
+#ifndef TUYA_NV_AREA_SIZE
+#define TUYA_NV_AREA_SIZE (4*TUYA_NV_ERASE_MIN_SIZE)
+#endif
+
+/*MACRO for production test module*/
+#ifndef TUYA_BLE_APP_VERSION_STRING
+#define TUYA_BLE_APP_VERSION_STRING "1.0"
+#endif
+
+#ifndef TUYA_BLE_APP_BUILD_FIRMNAME_STRING
+#define TUYA_BLE_APP_BUILD_FIRMNAME_STRING "tuya_ble_sdk_app_demo_xxx"
+#endif
+
+#ifndef TUYA_BLE_APP_FIRMWARE_KEY
+#define TUYA_BLE_APP_FIRMWARE_KEY ""
+#endif
+
+#endif
+
+
+
diff --git a/apps/common/third_party_profile/tuya_protocol/tuya_ble_sdk_version.h b/apps/common/third_party_profile/tuya_protocol/tuya_ble_sdk_version.h
new file mode 100644
index 0000000..a94f482
--- /dev/null
+++ b/apps/common/third_party_profile/tuya_protocol/tuya_ble_sdk_version.h
@@ -0,0 +1,38 @@
+/**
+ * \file tuya_ble_sdk_version.h
+ *
+ * \brief
+ */
+/*
+ * Copyright (C) 2014-2019, Tuya Inc., All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of tuya ble sdk
+ */
+
+
+#ifndef TUYA_BLE_SDK_VERSION_H__
+#define TUYA_BLE_SDK_VERSION_H__
+
+
+#define TUYA_BLE_SDK_VERSION_NUM 0x020000
+#define TUYA_BLE_SDK_VERSION_STR "2.0.0"
+
+
+#endif
+
+
+
+
diff --git a/apps/common/update/testbox_update.c b/apps/common/update/testbox_update.c
new file mode 100644
index 0000000..efe600e
--- /dev/null
+++ b/apps/common/update/testbox_update.c
@@ -0,0 +1,230 @@
+
+#include "update_loader_download.h"
+#include "update.h"
+#include "btctrler_task.h"
+#include "app_config.h"
+
+
+#if defined(CONFIG_SPP_AND_LE_CASE_ENABLE) || defined(CONFIG_HID_CASE_ENABLE)
+#include "lib_profile_cfg.h"
+#else
+#include "bt_profile_cfg.h"
+#endif
+
+#if (SMART_BOX_EN) && (CONFIG_WATCH_CASE_ENABLE)
+#include "smartbox/smartbox_task.h"
+#endif
+
+#define LOG_TAG "[TEST-UPDATE]"
+#define LOG_INFO_ENABLE
+#define LOG_ERROR_ENABLE
+#include "system/debug.h"
+
+extern u8 check_le_conn_disconnet_flag(void);
+extern void ble_app_disconnect(void);
+extern void ll_hci_destory(void);
+extern void ram_protect_close(void);
+extern void update_close_hw(void *filter_name);
+extern void btctrler_testbox_update_msg_handle_register(void (*handle)(int));
+extern void __bt_updata_reset_bt_bredrexm_addr(void);
+extern int __bt_updata_save_connection_info(void);
+extern const update_op_api_t lmp_ch_update_op;
+extern const update_op_api_t ble_ll_ch_update_op;
+static u8 ble_update_ready_jump_flag = 0;
+
+#include "asm/power_interface.h"
+void power_set_mode(u8 mode);
+
+static void testbox_bt_classic_update_private_param_fill(UPDATA_PARM *p)
+{
+
+}
+
+static void testbox_bt_classic_update_before_jump_handle(int type)
+{
+ if (UPDATE_MODULE_IS_SUPPORT(UPDATE_BT_LMP_EN)) {
+#if TCFG_USER_TWS_ENABLE || TCFG_USER_BLE_ENABLE
+ log_info("close ble hw\n");
+ ll_hci_destory();
+#endif
+
+ update_close_hw("bredr");
+ if (__bt_updata_save_connection_info()) {
+ log_error("bt save conn info fail!\n");
+ return;
+ }
+
+ ram_protect_close();
+ //note:last func will not return;
+ power_set_mode(PWR_LDO15);
+ __bt_updata_reset_bt_bredrexm_addr();
+ }
+}
+
+static void testbox_bt_classic_update_state_cbk(int type, u32 state, void *priv)
+{
+ update_ret_code_t *ret_code = (update_ret_code_t *)priv;
+
+ if (ret_code) {
+ log_info("state:%x err:%x\n", ret_code->stu, ret_code->err_code);
+ }
+
+ switch (state) {
+ case UPDATE_CH_EXIT:
+ if (UPDATE_DUAL_BANK_IS_SUPPORT()) {
+ if ((0 == ret_code->stu) && (0 == ret_code->err_code)) {
+ log_info("bt update succ\n");
+ update_result_set(UPDATA_SUCC);
+ } else {
+ log_info("bt update fail\n");
+ update_result_set(UPDATA_DEV_ERR);
+ }
+ } else {
+ if ((0 == ret_code->stu) && (0 == ret_code->err_code)) {
+ //update_mode_api(BT_UPDATA);
+ update_mode_api_v2(BT_UPDATA,
+ testbox_bt_classic_update_private_param_fill,
+ testbox_bt_classic_update_before_jump_handle);
+ }
+ }
+ break;
+ }
+}
+
+u8 ble_update_get_ready_jump_flag(void)
+{
+ return ble_update_ready_jump_flag;
+}
+
+static void testbox_ble_update_private_param_fill(UPDATA_PARM *p)
+{
+ u8 addr[6];
+ extern int le_controller_get_mac(void *addr);
+ if (BT_MODULES_IS_SUPPORT(BT_MODULE_LE) && UPDATE_MODULE_IS_SUPPORT(UPDATE_BLE_TEST_EN)) {
+ le_controller_get_mac(addr);
+ //memcpy(p->parm_priv, addr, 6);
+ update_param_priv_fill(p, addr, sizeof(addr));
+ puts("ble addr:\n");
+ put_buf(p->parm_priv, 6);
+ }
+}
+
+static void testbox_ble_update_before_jump_handle(int type)
+{
+ if (BT_MODULES_IS_SUPPORT(BT_MODULE_LE) && UPDATE_MODULE_IS_SUPPORT(UPDATE_BLE_TEST_EN)) {
+ ll_hci_destory();
+ }
+#if CONFIG_UPDATE_JUMP_TO_MASK
+ y_printf(">>>[test]:latch reset update\n");
+ latch_reset();
+
+#if 0
+ update_close_hw("null");
+ ram_protect_close();
+ /* save_spi_port(); */
+ extern void __BT_UPDATA_JUMP();
+ y_printf("update jump to __BT_UPDATA ...\n");
+ /* clk_set("sys", 48 * 1000000L); */
+ //跳转到uboot加载完,30ms左右(200410_yzb)
+ __BT_UPDATA_JUMP();
+#endif
+#else
+ cpu_reset();
+#endif
+}
+
+static void testbox_ble_update_state_cbk(int type, u32 state, void *priv)
+{
+ update_ret_code_t *ret_code = (update_ret_code_t *)priv;
+
+ if (ret_code) {
+ printf("ret_code->stu:%d err_code:%d\n", ret_code->stu, ret_code->err_code);
+ }
+
+ switch (state) {
+ case UPDATE_CH_EXIT:
+ if (UPDATE_DUAL_BANK_IS_SUPPORT()) {
+ if ((0 == ret_code->stu) && (0 == ret_code->err_code)) {
+ log_info("bt update succ\n");
+ update_result_set(UPDATA_SUCC);
+ } else {
+ log_info("bt update fail\n");
+ update_result_set(UPDATA_DEV_ERR);
+ }
+ } else {
+ if ((0 == ret_code->stu) && (0 == ret_code->err_code)) {
+#if TCFG_USER_BLE_ENABLE && (TCFG_BLE_DEMO_SELECT != DEF_BLE_DEMO_NULL) \
+ &&(TCFG_BLE_DEMO_SELECT != DEF_BLE_DEMO_ADV || defined(CONFIG_MESH_CASE_ENABLE))\
+ && (TCFG_BLE_DEMO_SELECT != DEF_BLE_DEMO_CLIENT)
+
+ ble_update_ready_jump_flag = 1;
+ /* ble_app_disconnect(); */
+ extern void ble_module_enable(u8 en);
+ ble_module_enable(0);
+ u8 cnt = 0;
+ while (!check_le_conn_disconnet_flag()) {
+ log_info("wait discon\n");
+ os_time_dly(2);
+ if (cnt++ > 5) {
+ break;
+ }
+ }
+
+ //update_mode_api(BLE_TEST_UPDATA);
+ update_mode_api_v2(BLE_TEST_UPDATA,
+ testbox_ble_update_private_param_fill,
+ testbox_ble_update_before_jump_handle);
+#endif
+ }
+ }
+ break;
+ }
+}
+
+void testbox_update_msg_handle(int msg)
+{
+ log_info("msg:%x\n", msg);
+
+ switch (msg) {
+ case MSG_BT_UPDATE_LOADER_DOWNLOAD_START:
+ if (UPDATE_MODULE_IS_SUPPORT(UPDATE_BT_LMP_EN)) {
+#if (SMART_BOX_EN) && (CONFIG_WATCH_CASE_ENABLE)
+ app_smartbox_task_prepare(0, SMARTBOX_TASK_ACTION_WATCH_TRANSFER, 0);
+#endif
+ update_mode_info_t info = {
+ .type = BT_UPDATA,
+ .state_cbk = testbox_bt_classic_update_state_cbk,
+ .p_op_api = &lmp_ch_update_op,
+ .task_en = 1,
+ };
+ app_active_update_task_init(&info);
+ }
+ break;
+
+ case MSG_BLE_TEST_OTA_LOADER_DOWNLOAD_START:
+ if (UPDATE_MODULE_IS_SUPPORT(UPDATE_BLE_TEST_EN)) {
+ update_mode_info_t info = {
+ .type = BLE_TEST_UPDATA,
+ .state_cbk = testbox_ble_update_state_cbk,
+ .p_op_api = &ble_ll_ch_update_op,
+ .task_en = 1,
+ };
+ app_active_update_task_init(&info);
+ }
+ break;
+
+defaut:
+ log_error("not support update msg:%x\n", msg);
+ break;
+ }
+
+}
+
+void testbox_update_init(void)
+{
+ if (UPDATE_MODULE_IS_SUPPORT(UPDATE_BLE_TEST_EN) || UPDATE_MODULE_IS_SUPPORT(UPDATE_BT_LMP_EN)) {
+ log_info("testbox msg handle reg:%x\n", testbox_update_msg_handle);
+ btctrler_testbox_update_msg_handle_register(testbox_update_msg_handle);
+ }
+}
+
diff --git a/apps/common/update/update.c b/apps/common/update/update.c
new file mode 100644
index 0000000..f325995
--- /dev/null
+++ b/apps/common/update/update.c
@@ -0,0 +1,577 @@
+#include "update.h"
+#include "update_loader_download.h"
+#include "asm/crc16.h"
+#include "asm/wdt.h"
+#include "os/os_api.h"
+#include "app_config.h"
+#include "cpu.h"
+#include "syscfg_id.h"
+#include "btcontroller_modules.h"
+#include "system/includes.h"
+#include "uart_update.h"
+#include "dual_bank_updata_api.h"
+#include "btstack/avctp_user.h"
+
+#if TCFG_UI_ENABLE
+#include "ui/ui_api.h"
+#endif
+
+#if RCSP_BTMATE_EN
+#include "rcsp_user_update.h"
+#elif RCSP_ADV_EN
+#include "rcsp_adv_user_update.h"
+#endif
+
+#ifdef UPDATE_VOICE_REMIND
+#include "tone_player.h"
+#include "audio_config.h"
+#endif
+
+#ifdef UPDATE_LED_REMIND
+#include "asm/pwm_led.h"
+#endif
+
+#include "custom_cfg.h"
+
+#define LOG_TAG "[APP-UPDATE]"
+#define LOG_INFO_ENABLE
+#define LOG_ERROR_ENABLE
+#include "system/debug.h"
+
+#if (JL_SMART_BOX_EXTRA_FLASH_OPT)
+#include "smartbox_extra_flash_opt.h"
+#endif
+
+#define LOADER_NAME "LOADER.BIN"
+#define DEVICE_UPDATE_KEY_ERR BIT(30)
+#define DEVICE_FIRST_START BIT(31)
+
+extern void update_module_init(void (*cbk)(update_mode_info_t *, u32, void *));
+extern void testbox_update_init(void);
+extern void ll_hci_destory(void);
+extern void hci_controller_destory(void);
+extern const int support_norflash_update_en;
+extern void ram_protect_close(void);
+extern void hwi_all_close(void);
+extern void wifi_det_close();
+
+__attribute__((weak))
+void wifi_det_close()
+{
+ printf("tmp weak func wifi_det_close\n");
+}
+extern void *dev_update_get_parm(int type);
+extern u8 get_ota_status();
+extern int get_nor_update_param(void *buf);
+extern bool get_tws_phone_connect_state(void);
+extern void tws_sniff_controle_check_disable(void);
+extern void tws_tx_unsniff_req(void);
+extern void sys_auto_sniff_controle(u8 enable, u8 *addr);
+extern void app_audio_set_wt_volume(s16 volume);
+extern u8 get_max_sys_vol(void);
+extern u8 get_ldo_trim_res(u8 *res);
+
+
+#ifdef DEV_UPDATE_SUPPORT_JUMP
+extern void __JUMP_TO_MASKROM();
+extern void save_spi_port();
+extern s32 sd1_unmount(void);
+extern void usb_sie_close_all(void);
+#endif //endif DEV_UPDATE_SUPPORT_JUMP
+
+extern const int support_norflash_update_en;
+const u8 loader_file_path[] = "mnt/norflash/C/"LOADER_NAME"";
+//升级文件路径必须是短文件名(8+3)结构,仅支持2层目录
+/* const char updata_file_name[] = "/UPDATA/JL_692X.BFU"; */
+const char updata_file_name[] = "/*.UFW";
+static u32 g_updata_flag = 0;
+static volatile u8 ota_status = 0;
+static succ_report_t succ_report;
+
+u16 update_result_get(void)
+{
+ u16 ret = UPDATA_NON;
+
+ if (!UPDATE_SUPPORT_DEV_IS_NULL()) {
+ UPDATA_PARM *p = UPDATA_FLAG_ADDR;
+ u16 crc_cal;
+ crc_cal = CRC16(((u8 *)p) + 2, sizeof(UPDATA_PARM) - 2); //2 : crc_val
+ if (crc_cal && crc_cal == p->parm_crc) {
+ ret = p->parm_result;
+ }
+ g_updata_flag = ret;
+ g_updata_flag |= ((u32)(p->magic)) << 16;
+
+ memset(p, 0x00, sizeof(UPDATA_PARM));
+ }
+
+ return ret;
+}
+
+void update_result_set(u16 result)
+{
+ if (!UPDATE_SUPPORT_DEV_IS_NULL()) {
+ UPDATA_PARM *p = UPDATA_FLAG_ADDR;
+
+ memset(p, 0x00, sizeof(UPDATA_PARM));
+ p->parm_result = result;
+ p->parm_crc = CRC16(((u8 *)p) + 2, sizeof(UPDATA_PARM) - 2);
+ }
+#if (RCSP_UPDATE_EN && SMART_BOX_EN && JL_SMART_BOX_EXTRA_FLASH_OPT)
+ if (UPDATA_SUCC == result) {
+ smartbox_eflash_update_flag_set(0);
+ smartbox_eflash_flag_set(0);
+ extern void set_update_ex_flash_flag(u8 update_flag);
+ set_update_ex_flash_flag(0);
+ }
+#endif
+}
+void update_clear_result()
+{
+ g_updata_flag = 0;
+}
+
+bool update_success_boot_check(void)
+{
+ if (!UPDATE_SUPPORT_DEV_IS_NULL()) {
+ u16 result = g_updata_flag & 0xffff;
+ u16 up_tpye = g_updata_flag >> 16;
+ if ((UPDATA_SUCC == result) && ((SD0_UPDATA == up_tpye) || (SD1_UPDATA == up_tpye) || (USB_UPDATA == up_tpye))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool device_is_first_start()
+{
+ log_info("g_updata_flag=0x%x\n", g_updata_flag);
+ if ((g_updata_flag & DEVICE_FIRST_START) || (g_updata_flag & DEVICE_UPDATE_KEY_ERR) || (g_updata_flag == UPDATA_SUCC)) {
+ puts("\n=================device_is_first_start=========================\n");
+ return true;
+ }
+ return false;
+}
+
+void led_update_start(void)
+{
+#ifdef UPDATE_LED_REMIND
+ puts("led_update_start\n");
+ pwm_led_mode_set(PWM_LED_ALL_OFF);
+#endif
+}
+
+void led_update_finish(void)
+{
+#ifdef UPDATE_LED_REMIND
+ puts("led_update_finish\n");
+ pwm_led_mode_set(PWM_LED0_LED1_FAST_FLASH);
+#endif
+}
+
+static inline void dev_update_close_ui()
+{
+
+#if (TCFG_UI_ENABLE&&(CONFIG_UI_STYLE == STYLE_JL_LED7))
+ u8 count = 0;
+ UI_SHOW_WINDOW(ID_WINDOW_POWER_OFF);
+__retry:
+ if (UI_GET_WINDOW_ID() != ID_WINDOW_POWER_OFF) {
+ /* os_time_dly(10);//增加延时防止没有关显示,由于此处关了中断,不能用os接口 */
+ delay_2ms(50);//增加延时防止没有关显示
+ count++;
+ if (count < 3) {
+ goto __retry;
+ }
+ }
+#endif
+}
+#ifdef UPDATE_VOICE_REMIND
+void update_tone_event_clear()
+{
+ struct sys_event e = {0};
+ e.type = SYS_DEVICE_EVENT;
+ e.arg = (void *)DEVICE_EVENT_FROM_TONE;
+ sys_event_clear(&e);
+}
+#endif
+extern void usr_mute_set(u8 flag);
+int update_result_deal()
+{
+#ifdef CONFIG_FPGA_ENABLE
+ return 0;
+#endif
+
+ u8 key_voice_cnt = 0;
+ u16 result = 0;
+ usr_mute_set(0);
+ result = (g_updata_flag & 0xffff);
+ log_info("<--------update_result_deal=0x%x %x--------->\n", result, g_updata_flag >> 16);
+#ifdef CONFIG_DEBUG_ENABLE
+#if TCFG_APP_BT_EN
+ u8 check_update_param_len(void);
+ ASSERT(check_update_param_len(), "UPDATE_PARAM_LEN ERROR");
+#endif
+#endif
+ if (result == UPDATA_NON || 0 == result) {
+ return 0;
+ }
+#ifdef UPDATE_VOICE_REMIND
+#endif
+ if (result == UPDATA_SUCC) {
+#if(JL_EARPHONE_APP_EN && RCSP_UPDATE_EN)
+ u8 clear_update_flag = 0;
+ syscfg_write(VM_UPDATE_FLAG, &clear_update_flag, 1);
+#endif
+#ifdef UPDATE_LED_REMIND
+ led_update_finish();
+#endif
+ }
+
+ int voice_max_cnt = 5;
+ while (1) {
+ wdt_clear();
+ key_voice_cnt++;
+#ifdef UPDATE_VOICE_REMIND
+ if (result == UPDATA_SUCC) {
+ puts("<<<<<>>>>>>>>>>\n");
+ update_tone_event_clear();
+ } else {
+ voice_max_cnt = 20; //区分下升级失败提示音
+ log_info("!!!!!!!!!!!!!!!updata waring !!!!!!!!!!!=0x%x\n", result);
+ app_audio_set_volume(APP_AUDIO_STATE_WTONE, get_max_sys_vol(), 1);
+ tone_play(TONE_SIN_NORMAL, 1);
+ os_time_dly(10);
+ update_tone_event_clear();
+ }
+#endif
+ if (key_voice_cnt > voice_max_cnt) {
+ key_voice_cnt = 0;
+ cpu_reset();
+ puts("enter_sys_soft_poweroff\n");
+ break;
+ //注:关机要慎重,要设置开机键
+ //enter_sys_soft_poweroff();
+ }
+ }
+
+ return 1;
+}
+
+void clr_update_ram_info(void)
+{
+ UPDATA_PARM *p = UPDATA_FLAG_ADDR;
+ memset(p, 0x00, sizeof(UPDATA_PARM));
+}
+
+void update_close_hw(void *filter_name)
+{
+ const struct update_target *p;
+ list_for_each_update_target(p) {
+ if (memcmp(filter_name, p->name, strlen(filter_name)) != 0) {
+ printf("close Hw Name : %s\n", p->name);
+ p->driver_close();
+ }
+ }
+}
+
+static void update_before_jump_common_handle(UPDATA_TYPE up_type)
+{
+ dev_update_close_ui();
+
+#if TCFG_AUDIO_ANC_ENABLE
+ extern void audio_anc_hw_close();
+ audio_anc_hw_close();
+#endif
+
+#if (CPU_CORE_NUM == 1) //双核在跳转前关中断lock_set后会和maskrom 初始化中断冲突导致ilock err
+ local_irq_disable();
+#endif
+
+ hwi_all_close();
+
+#ifdef CONFIG_SUPPORT_WIFI_DETECT
+ wifi_det_close();
+#endif
+ /*跳转的时候遇到死掉的情况很可能是硬件模块没关导致,加上保护可以判断哪个异常,保护的地址根据不同SDK而定*/
+ /* u8 inv = 0; */
+ /* mpu_set(1, (u32)&test_pro_addr, (u32)test_pro_addr, inv, "0r", DBG_FM); */
+}
+
+//ota.bin 放到exflash升级的方式,parm_priv存放了norflash的参数,对应实际升级方式的参数需要放在norflash参数之后
+void update_param_priv_fill(UPDATA_PARM *p, void *priv, u16 priv_len)
+{
+ int parm_offset = 0;
+ if (support_norflash_update_en) {
+ parm_offset = get_nor_update_param(p->parm_priv); //如果loader放在外挂norflash,parm_priv前面放norflash参数,后面才是升级类型本身的参数
+ }
+ memcpy(p->parm_priv + parm_offset, priv, priv_len);
+}
+
+void update_param_ext_fill(UPDATA_PARM *p, u8 ext_type, u8 *ext_data, u8 ext_len)
+{
+ struct ext_arg_t ext_arg;
+
+ ext_arg.type = ext_type;
+ ext_arg.len = ext_len;
+ ext_arg.data = ext_data;
+
+ memcpy((u8 *)p + sizeof(UPDATA_PARM) + p->ext_arg_len, &ext_arg, 2); //2byte:type + len
+ memcpy((u8 *)p + sizeof(UPDATA_PARM) + p->ext_arg_len + 2, ext_arg.data, ext_arg.len);
+ log_info("ext_fill :");
+ log_info_hexdump((u8 *)p + sizeof(UPDATA_PARM) + p->ext_arg_len, ext_arg.len + 2);
+ p->ext_arg_len += (2 + ext_arg.len);
+ p->ext_arg_crc = CRC16((u8 *)p + sizeof(UPDATA_PARM), p->ext_arg_len);
+}
+
+//fill common content \ private content \ crc16
+static void update_param_content_fill(int type, UPDATA_PARM *p, void (*priv_param_fill_hdl)(UPDATA_PARM *P))
+{
+ u8 ext_len = 0;
+ u8 *ext_data = NULL;
+
+ memset((u8 *)p, 0x00, sizeof(UPDATA_PARM));
+
+ if (support_norflash_update_en) {
+ p->parm_type = NORFLASH_UPDATA; //uboot通过该标识从外挂flash读取ota.bin
+ *((u16 *)((u8 *)p + sizeof(UPDATA_PARM) + 32)) = (u16)type; //将实际的升级类型保存到UPDATA_PARM后
+ } else {
+ p->parm_type = (u16)type;
+ }
+
+ p->parm_result = (u16)UPDATA_READY;
+ p->magic = UPDATE_PARAM_MAGIC;
+ p->ota_addr = succ_report.loader_saddr;
+
+ //支持loader放到外挂flash里ota_addr为0
+ if (0 == p->ota_addr && !support_norflash_update_en) {
+ log_error("ota addr err\n");
+ return;
+ }
+
+ if (priv_param_fill_hdl) {
+ priv_param_fill_hdl(p);
+ }
+
+#ifdef CONFIG_CPU_BR23
+#if TCFG_APP_BT_EN
+ if (type == BT_UPDATA || type == BLE_APP_UPDATA || type == SPP_APP_UPDATA || type == BLE_TEST_UPDATA) { //D版芯片蓝牙相关的升级需要保存LDO_TRIM_RES
+ ext_data = malloc(128);
+ if (ext_data != NULL) {
+ ext_len = get_ldo_trim_res(ext_data);
+ update_param_ext_fill(p, EXT_LDO_TRIM_RES, ext_data, ext_len);
+ free(ext_data);
+ }
+ }
+#endif
+#endif
+ u8 ext_flag = 0;
+ ext_len = 1;
+#if CONFIG_UPDATE_JUMP_TO_MASK
+ ext_flag = 1;
+#endif
+ update_param_ext_fill(p, EXT_JUMP_FLAG, &ext_flag, ext_len);
+ /* u8 *flag = update_param_ext_get(p, EXT_JUMP_FLAG); */
+ /* r_printf(">>>[test]:flag = %d\n", flag[0]); */
+
+
+ p->parm_crc = CRC16(((u8 *)p) + 2, sizeof(UPDATA_PARM) - 2); //2 : crc_val
+}
+
+static void update_param_ram_set(u8 *buf, u16 len)
+{
+ u8 *update_ram = UPDATA_FLAG_ADDR;
+ memcpy(update_ram, (u8 *)buf, len);
+}
+
+void update_mode_api_v2(UPDATA_TYPE type, void (*priv_param_fill_hdl)(UPDATA_PARM *p), void (*priv_update_jump_handle)(int type))
+{
+ u16 update_param_len = sizeof(UPDATA_PARM) + UPDATE_PRIV_PARAM_LEN;
+
+ UPDATA_PARM *p = malloc(update_param_len);
+
+ if (p) {
+ update_param_content_fill(type, p, priv_param_fill_hdl);
+
+ if (succ_report.update_param_write_hdl) {
+ succ_report.update_param_write_hdl(succ_report.priv_param, (u8 *)p, update_param_len);
+ }
+
+ //临时修改,升级不能跑太快的时钟,否则升级失败
+ clk_set("sys", 48000000);
+
+#ifdef UPDATE_LED_REMIND
+ led_update_start();
+#endif
+
+ update_param_ram_set((u8 *)p, update_param_len);
+
+#if CPU_CORE_NUM > 1 //双核需要把CPU1关掉
+ printf("Before Suspend Current Cpu ID:%d Cpu In Irq?:%d\n", current_cpu_id(), cpu_in_irq());
+ if (current_cpu_id() == 1) {
+ os_suspend_other_core();
+ }
+ ASSERT(current_cpu_id() == 0); //确保跳转前CPU1已经停止运行
+ cpu_suspend_other_core(0x55);
+ extern void cpu1_power_off(void);
+ cpu1_power_off();
+ printf("After Suspend Current Cpu ID:%d\n", current_cpu_id());
+#endif
+ update_before_jump_common_handle(type);
+
+ if (priv_update_jump_handle) {
+ priv_update_jump_handle(type);
+ }
+ free(p);
+ } else {
+ ASSERT(p, "malloc update param err \n");
+ }
+}
+
+int update_check_sniff_en(void)
+
+{
+ if (!UPDATE_SUPPORT_DEV_IS_NULL()) {
+ if (get_ota_status()) {
+ log_info("ota ing...");
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+ return 1;
+}
+
+
+void set_ota_status(u8 stu)
+{
+ ota_status = stu;
+}
+
+u8 get_ota_status()
+{
+ return ota_status;
+}
+
+static u8 ota_idle_query(void)
+{
+ return !ota_status;
+}
+
+//防止升级过程进入powerdown
+REGISTER_LP_TARGET(ota_lp_target) = {
+ .name = "ota",
+ .is_idle = ota_idle_query,
+};
+
+extern void tws_sync_update_api_register(const update_op_tws_api_t *op);
+extern update_op_tws_api_t *get_tws_update_api(void);
+
+extern const int support_dual_bank_update_en;
+extern int tws_ota_init(void);
+extern void sys_auto_shut_down_disable(void);
+extern void sys_auto_shut_down_enable(void);
+extern void tws_api_auto_role_switch_disable();
+extern void tws_api_auto_role_switch_enable();
+
+static void update_init_common_handle(int type)
+{
+ ota_status = 1;
+ if (UPDATE_DUAL_BANK_IS_SUPPORT()) {
+#if TCFG_AUTO_SHUT_DOWN_TIME
+ sys_auto_shut_down_disable();
+#endif
+
+#if OTA_TWS_SAME_TIME_ENABLE
+ tws_api_auto_role_switch_disable();
+ tws_sync_update_api_register(get_tws_update_api());
+ tws_ota_init();
+#endif
+ }
+}
+
+static void update_exit_common_handle(int type, void *priv)
+{
+ update_ret_code_t *ret_code = (update_ret_code_t *)priv;
+
+#if TCFG_AUTO_SHUT_DOWN_TIME
+ sys_auto_shut_down_enable();
+#endif
+
+#if OTA_TWS_SAME_TIME_ENABLE
+ if (UPDATE_DUAL_BANK_IS_SUPPORT()) {
+ tws_api_auto_role_switch_enable();
+ }
+#endif
+
+ ota_status = 0;
+}
+
+static void update_common_state_cbk(update_mode_info_t *info, u32 state, void *priv)
+{
+ int type = info->type;
+
+ log_info("type:%x state:%x code:%x\n", type, state, priv);
+
+ switch (state) {
+ case UPDATE_CH_INIT:
+ memset((u8 *)&succ_report, 0x00, sizeof(succ_report_t));
+ update_init_common_handle(info->type);
+ break;
+
+ case UPDATE_CH_SUCESS_REPORT:
+ log_info("succ report stored\n");
+ memcpy((u8 *)&succ_report, (u8 *)priv, sizeof(succ_report_t));
+ break;
+ }
+
+ if (info->state_cbk) {
+ info->state_cbk(type, state, priv);
+ }
+
+ switch (state) {
+ case UPDATE_CH_EXIT:
+ update_exit_common_handle(info->type, priv);
+ break;
+ }
+}
+
+
+static int app_update_init(void)
+{
+ update_module_init(update_common_state_cbk);
+ testbox_update_init();
+ return 0;
+}
+
+__initcall(app_update_init);
+
+
+void update_start_exit_sniff(void)
+{
+#if TCFG_USER_TWS_ENABLE
+ volatile u8 wait_tws_sniff_exit = 1;
+ if (get_tws_phone_connect_state() == TRUE) {
+ g_printf("exit sniff mode...\n");
+ user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL);
+ } else {
+ tws_tx_unsniff_req();
+ }
+ tws_sniff_controle_check_disable();
+#else
+ user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL);
+#endif
+ sys_auto_sniff_controle(0, NULL);
+}
+
+void update_param_boot_ram_set(u8 *buf, u16 len)
+{
+ u8 *boot_ram = (u8 *)BOOT_STATUS_ADDR;
+ memcpy(boot_ram, (u8 *)buf, len);
+}
+
+
diff --git a/apps/common/update/update_tws.c b/apps/common/update/update_tws.c
new file mode 100644
index 0000000..4b6c30f
--- /dev/null
+++ b/apps/common/update/update_tws.c
@@ -0,0 +1,763 @@
+#include
+#include
+#include
+
+#include "generic/lbuf.h"
+#include "init.h"
+#include "update_tws.h"
+#include "dual_bank_updata_api.h"
+#include "bt_tws.h"
+#include "app_config.h"
+#include "btstack/avctp_user.h"
+#include "update.h"
+#include "app_main.h"
+
+#if (OTA_TWS_SAME_TIME_ENABLE && !OTA_TWS_SAME_TIME_NEW)
+
+//#define LOG_TAG_CONST EARPHONE
+#define LOG_TAG "[UPDATE_TWS]"
+#define log_errorOR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#define THIS_TASK_NAME "tws_ota"
+#define SLAVE_REV_BUF_LEN 1024*2
+
+extern void sys_enter_soft_poweroff(void *priv);
+
+void db_update_notify_fail_to_phone();
+
+struct __tws_ota_var {
+ OS_SEM master_sem;
+ OS_SEM slave_sem;
+ OS_SEM confirm_sem;
+ struct __tws_ota_para para;
+ u8 ota_type;
+ u8 ota_status;
+ u8 ota_remote_status;
+ u8 ota_result;
+ volatile u32 ota_data_len;
+ u16 ota_timer_id;
+ u8 ota_verify_cnt;
+ volatile u32 ota_confirm;
+ cbuffer_t cbuffer;
+ u8 *slave_r_buf;
+};
+struct __tws_ota_var tws_ota_var;
+#define __this (&tws_ota_var)
+
+void tws_ota_event_post(u32 type, u8 event)
+{
+ struct sys_event e;
+ e.type = SYS_BT_EVENT;
+ e.arg = (void *)type;
+ e.u.bt.event = event;
+ sys_event_notify(&e);
+}
+
+u8 tws_ota_control(int type, ...)
+{
+ int ret = 0;
+ int role = 0;
+ int value = 0;
+
+ va_list argptr;
+ va_start(argptr, type);
+
+ switch (type) {
+ case OTA_TYPE_SET:
+ value = va_arg(argptr, int);
+ __this->ota_type = value;
+ break;
+ case OTA_TYPE_GET:
+ ret = __this->ota_type;
+ break;
+ case OTA_STATUS_SET:
+ value = va_arg(argptr, int);
+ __this->ota_status = value;
+ break;
+ case OTA_STATUS_GET:
+ ret = __this->ota_status;
+ break;
+ case OTA_REMOTE_STATUS_SET:
+ value = va_arg(argptr, int);
+ __this->ota_remote_status = value;
+ break;
+ case OTA_REMOTE_STATUS_GET:
+ ret = __this->ota_remote_status;
+ break;
+ case OTA_RESULT_SET:
+ value = va_arg(argptr, int);
+ role = va_arg(argptr, int);
+ if (value == 1) {
+ __this->ota_result |= BIT(role);
+ } else {
+ __this->ota_result &= ~BIT(role);
+ }
+ break;
+ case OTA_RESULT_GET:
+ ret = __this->ota_result;
+ break;
+ }
+
+ va_end(argptr);
+
+ return ret;
+}
+
+int tws_ota_init(void)
+{
+ tws_api_auto_role_switch_disable();
+ memset((u8 *)__this, 0, sizeof(struct __tws_ota_var));
+ __this->ota_status = OTA_INIT;
+ __this->ota_type = OTA_TWS;
+
+ if (a2dp_get_status() == BT_MUSIC_STATUS_STARTING) {
+ /* log_info("try pause a2dp music"); */
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PAUSE, 0, NULL);
+ }
+ return 0;
+}
+
+#define TWS_FUNC_ID_OTA_SYNC TWS_FUNC_ID('O', 'T', 'A', 'S')
+static void tws_ota_data_read_s_from_m(void *_data, u16 len, bool rx)
+{
+ if (rx && __this->ota_status == OTA_START && __this->slave_r_buf) {
+ /* r_log_info("Offset:%x r_len:%d\n",__this->ota_data_len,len); */
+ /* put_buf(_data, len); */
+ __this->ota_data_len += len;
+ if (cbuf_is_write_able(&(__this->cbuffer), len)) {
+ cbuf_write(&(__this->cbuffer), _data, len);
+ } else {
+ log_info("ota cbuf write err\n");
+ }
+ os_sem_post(&__this->slave_sem);
+ }
+}
+
+REGISTER_TWS_FUNC_STUB(app_ota_sync_stub) = {
+ .func_id = TWS_FUNC_ID_OTA_SYNC,
+ .func = tws_ota_data_read_s_from_m,
+};
+
+int tws_ota_data_send_m_to_s(u8 *buf, u16 len)
+{
+ if (!(tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED)) {
+ return 0;
+ }
+
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ return 0;
+ }
+
+ int ret = tws_api_send_data_to_slave(buf, len, TWS_FUNC_ID_OTA_SYNC);
+ return ret;
+}
+
+int tws_ota_err_callback(u8 reason)
+{
+ tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_ERR);
+ return 0;
+}
+
+static void tws_ota_update_loop(void *priv)
+{
+ u32 total_len = 0;
+ u32 len = 0;
+ u8 *tmp_buf = NULL;
+ int ret = 0;
+
+ u8 sniff_wait_exit_timeout = 30;//3s
+
+ log_info("tws_ota_update_loop\n");
+
+ while (1) {
+ os_sem_pend(&__this->slave_sem, 0);
+
+ if (sniff_wait_exit_timeout) {
+ //wait slave exit sniff
+ extern u8 btstcak_get_bt_mode(void);
+ while (btstcak_get_bt_mode() && sniff_wait_exit_timeout--) {
+ log_info("wait sniff exit \n");
+ os_time_dly(10);
+ }
+ log_info(">>>>>>>sniff timeout:%d \n", sniff_wait_exit_timeout);
+
+ if (!sniff_wait_exit_timeout) {
+ log_info(">>>>>>wait sniff exit timeout !!!! \n");
+ }
+ sniff_wait_exit_timeout = 0;
+ dual_bank_passive_update_init(__this->para.fm_crc16, __this->para.fm_size, __this->para.max_pkt_len, NULL);
+ ret = dual_bank_update_allow_check(__this->para.fm_size);
+ if (ret) {
+ log_info("fm_size:%x can't update\n", __this->para.fm_size);
+ tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_ERR);
+ continue;
+ }
+ tws_api_sync_call_by_uuid(0xA2E22223, SYNC_CMD_START_UPDATE, 400);
+ continue;
+ }
+
+ total_len = cbuf_get_data_size(&(__this->cbuffer));
+ /* log_info("total_len : %d\n",total_len); */
+ while (total_len) {
+ if (total_len > get_dual_bank_passive_update_max_buf()) {
+ len = get_dual_bank_passive_update_max_buf();
+ } else {
+ len = total_len;
+ }
+
+ if (!len) {
+ continue;
+ }
+ tmp_buf = malloc(len);
+ if (tmp_buf) {
+ if (cbuf_read(&(__this->cbuffer), tmp_buf, len) == len) {
+ putchar('D');
+ dual_bank_update_write(tmp_buf, len, NULL);
+ } else {
+ log_error("read err\n");
+ }
+ free(tmp_buf);
+ } else {
+ log_error("malloc err\n");
+ }
+ total_len -= len;
+ }
+ }
+}
+
+static void ota_finish_confirm(void *priv)
+{
+ log_info("ota_finish_confirm:%d\n", __this->ota_confirm);
+ if (!__this->ota_confirm) {
+ //ota tws confirm err,earse boot info
+ flash_update_clr_boot_info(CLEAR_APP_UPDATE_BANK);
+ /* ASSERT(0, "ota tws confirm err\n"); */
+ }
+ tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_SUCC);
+
+}
+
+u16 tws_ota_enter_verify(void *priv)
+{
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_DISCONNECTED) {
+ log_info("tws_disconn in verify\n");
+ db_update_notify_fail_to_phone();
+ return -1;
+ }
+ tws_ota_send_data_to_sibling(TWS_UPDATE_VERIFY, NULL, 0);
+ os_sem_pend(&__this->master_sem, 1000);
+ //这里pend完,要做超时的准备
+ if (__this->ota_status == OTA_VERIFY_ING) {
+ return 0;
+ } else {
+ db_update_notify_fail_to_phone();
+ return -1;
+ }
+}
+
+u16 tws_ota_exit_verify(u8 *res, u8 *up_flg)
+{
+ //not updata boot info in lib
+ *up_flg = 1;
+
+ u8 tws_ota_result[2];
+ u8 master_result = *res;
+ u8 result = 0;
+ tws_ota_control(OTA_STATUS_SET, OTA_VERIFY_END);
+ tws_ota_control(OTA_RESULT_SET, !master_result, TWS_ROLE_MASTER);
+__RESTART:
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_DISCONNECTED) {
+ db_update_notify_fail_to_phone();
+ return 0;
+ }
+ result = tws_ota_control(OTA_RESULT_GET);
+ tws_ota_result[0] = result;
+ tws_ota_result[1] = tws_ota_control(OTA_STATUS_GET);
+ tws_ota_send_data_to_sibling(TWS_UPDATE_RESULT_EXCHANGE, (u8 *)&tws_ota_result, 2);
+
+ if ((result & BIT(TWS_ROLE_SLAVE)) && (result & BIT(TWS_ROLE_SLAVE))) {
+ log_info("tws already ota succ1\n");
+ os_sem_set(&__this->master_sem, 0);
+ tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_OVER);
+ return 1;
+ } else if (__this->ota_remote_status == OTA_VERIFY_END || __this->ota_remote_status == OTA_OVER) {
+ tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_ERR);
+ return 0;
+ } else {
+ os_sem_pend(&__this->master_sem, 200);
+ goto __RESTART;
+ }
+ return 1;
+}
+
+u16 tws_ota_updata_boot_info_over(void *priv)
+{
+ log_info("master update_burn_boot_info succ\n");
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_DISCONNECTED) {
+ log_info("tws_disconn, ota open fail");
+ db_update_notify_fail_to_phone();
+ return -1;
+ }
+
+ //等待从机更新完成
+ log_info("1------pend in");
+ os_sem_pend(&__this->confirm_sem, 300);
+ log_info("1------pend out");
+
+ log_info("-------mz01");
+ if (__this->ota_confirm) {
+ log_info("-------mz02");
+ os_sem_set(&__this->confirm_sem, 0);
+ tws_ota_send_data_to_sibling(TWS_UPDATE_OVER_CONFIRM_REQ, NULL, 0);
+ log_info("2------pend in");
+ if (OS_TIMEOUT == os_sem_pend(&__this->confirm_sem, 300)) {
+ __this->ota_confirm = 0;
+ }
+ log_info("2------pend out");
+ }
+
+ if (!__this->ota_confirm) {
+ log_info("-------mz03");
+ //ota tws confirm err,earse boot info
+ flash_update_clr_boot_info(CLEAR_APP_UPDATE_BANK);
+ /* ASSERT(0, "ota tws confirm err\n"); */
+ return -1;
+ }
+ /* tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS,OTA_UPDATE_SUCC); //主机等手机发重启命令*/
+ return 0;
+
+}
+
+int tws_ota_open(struct __tws_ota_para *para)
+{
+ int ret = 0;
+ log_info("tws_ota_open\n");
+
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_DISCONNECTED) {
+ log_info("tws_disconn, ota open fail");
+ db_update_notify_fail_to_phone();
+ return -1;
+ }
+
+ os_sem_create(&__this->master_sem, 0);
+ os_sem_create(&__this->slave_sem, 0);
+ os_sem_create(&__this->confirm_sem, 0);
+
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ extern void bt_check_exit_sniff();
+ bt_check_exit_sniff();
+ //master 发命令给slave启动升级
+
+
+ log_info("master updata info: crc16:%x size:%x max_pkt_len:%d\n", para->fm_crc16, para->fm_size, para->max_pkt_len);
+ if (__this->ota_type == OTA_TWS) {
+ tws_ota_send_data_to_sibling(TWS_UPDATE_START, (u8 *)para, sizeof(struct __tws_ota_para));
+ log_info("sem pend in ...");
+ os_sem_pend(&__this->master_sem, 600);
+ log_info("sem pend out ...");
+ //判断对耳状态
+ if (__this->ota_status == OTA_START) {
+ log_info("slave has ready");
+ ret = 0;
+ } else {
+ log_info("slave answer timeout");
+ db_update_notify_fail_to_phone();
+ ret = -1;
+ }
+ }
+ } else {
+ log_info("slave updata info: crc16:%x size:%x max_pkt_len:%d\n", para->fm_crc16, para->fm_size, para->max_pkt_len);
+
+ /* tws_api_sync_call_by_uuid('T', SYNC_CMD_START_UPDATE, 100); */
+ tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_START_UPDATE_READY);
+ }
+ return ret;
+}
+
+int tws_ota_close(void)
+{
+ int ret = 0;
+ log_info("%s", __func__);
+ if (__this->slave_r_buf) {
+ free(__this->slave_r_buf);
+ __this->slave_r_buf = 0;
+ task_kill(THIS_TASK_NAME);
+ }
+ return ret;
+}
+
+static void ota_verify_timeout(void *priv)
+{
+ log_info("ota_verify_timeout:%x %x\n", __this->para.fm_size, __this->ota_data_len);
+ if (__this->ota_data_len == __this->para.fm_size) {
+ /* tws_api_sync_call_by_uuid('T', SYNC_CMD_START_VERIFY, 100); */
+ tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_START_VERIFY);
+ return;
+ }
+
+ if (__this->ota_verify_cnt > 4) {
+ log_info("code len err\n");
+ tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_ERR);
+ sys_timeout_del(__this->ota_timer_id);
+ __this->ota_timer_id = 0;
+ return;
+ }
+
+ __this->ota_verify_cnt ++;
+ __this->ota_timer_id = 0;
+ __this->ota_timer_id = sys_timeout_add(NULL, ota_verify_timeout, 500);
+}
+
+int tws_ota_get_data_from_sibling(u8 opcode, u8 *data, u8 len)
+{
+ u8 tws_ota_result[2];
+ switch (opcode) {
+ //master->slave
+ case TWS_UPDATE_START:
+ log_info("TWS_AI_START_UPDATE:%d\n", opcode);
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ if (__this->slave_r_buf) {
+ tws_ota_close();
+ }
+ tws_ota_init();
+ memcpy((u8 *) & (__this->para), data, len);
+ tws_ota_open(&(__this->para));
+ }
+ break;
+
+ //master->slave
+ case TWS_UPDATE_RESULT_EXCHANGE:
+ log_info("TWS_UPDATE_RESULT_EXCHANGE:%d %d\n", data[0], data[1]);
+ __this->ota_remote_status = data[1];
+ tws_ota_control(OTA_RESULT_SET, (data[0] & BIT(TWS_ROLE_MASTER) ? 1 : 0), TWS_ROLE_MASTER);
+
+ tws_ota_result[0] = __this->ota_result;
+ tws_ota_result[1] = __this->ota_status;
+ tws_ota_send_data_to_sibling(TWS_UPDATE_RESULT_EXCHANGE_RES, (u8 *)tws_ota_result, 2);
+ log_info("master ota result:%x %d\n", tws_ota_control(OTA_RESULT_GET), __this->ota_status);
+ break;
+
+ //slave->master
+ case TWS_UPDATE_RESULT_EXCHANGE_RES:
+ log_info("TWS_UPDATE_RESULT_EXCHANGE_RES:%d %d\n", data[0], data[1]);
+ __this->ota_remote_status = data[1];
+ tws_ota_control(OTA_RESULT_SET, (data[0] & BIT(TWS_ROLE_SLAVE) ? 1 : 0), TWS_ROLE_SLAVE);
+ log_info("slave ota result:%x %d\n", tws_ota_control(OTA_RESULT_GET), __this->ota_status);
+
+ if (tws_ota_control(OTA_RESULT_GET) & BIT(TWS_ROLE_SLAVE)) {
+ os_sem_post(&__this->master_sem);
+ }
+ break;
+
+ //master->slave
+ case TWS_UPDATE_VERIFY:
+ log_info("TWS_UPDATE_VERIFY\n");
+ tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_START_VERIFY);
+ break;
+
+ case TWS_UPDATE_OVER:
+ log_info("TWS_AI_UPDATE_OVER:%d\n", opcode);
+ __this->ota_status = OTA_OVER;
+ break;
+
+ //slave to master
+ case TWS_UPDATE_OVER_CONFIRM:
+ log_info("TWS_UPDATE_OVER_CONFIRM\n");
+ __this->ota_confirm = 1;
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ log_info("1------post");
+ os_sem_post(&__this->confirm_sem);
+ }
+ break;
+ //master->slave
+ case TWS_UPDATE_OVER_CONFIRM_REQ:
+ log_info("TWS_UPDATE_OVER_CONFIRM_REQ\n");
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ __this->ota_confirm = 1;
+ tws_ota_send_data_to_sibling(TWS_UPDATE_OVER_CONFIRM_RES, NULL, 0);
+ log_info("2------post");
+ os_sem_post(&__this->confirm_sem);
+ }
+ break;
+ //slave->master
+ case TWS_UPDATE_OVER_CONFIRM_RES:
+ log_info("TWS_UPDATE_OVER_CONFIRM_RES\n");
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ log_info("3------post");
+ os_sem_post(&__this->confirm_sem);
+ }
+ break;
+ }
+ return 0;
+}
+
+void tws_ota_send_data_to_sibling(u8 opcode, u8 *data, u8 len)
+{
+ extern void tws_data_to_sibling_send(u8 opcode, u8 * data, u8 len);
+ tws_data_to_sibling_send(opcode, data, len);
+}
+
+
+
+u8 dual_bank_update_burn_boot_info_callback(u8 ret)
+{
+ if (ret) {
+ log_info("update_burn_boot_info err\n");
+ } else {
+ log_info("slave update_burn_boot_info succ\n");
+ tws_ota_send_data_to_sibling(TWS_UPDATE_OVER_CONFIRM, NULL, 0);
+
+ //not recive master confirm
+ log_info("3------pend in");
+ os_sem_pend(&__this->confirm_sem, 300);
+ log_info("3------pend out");
+
+ if (!__this->ota_confirm) {
+ //ota tws confirm err,earse boot info
+ flash_update_clr_boot_info(CLEAR_APP_UPDATE_BANK);
+ /* ASSERT(0, "ota tws confirm err\n"); */
+ return 0;
+ }
+
+ //确保从机的回复命令送达到主机
+ os_time_dly(50);
+
+ tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_SUCC);
+ return 0;
+ }
+
+ return 1;
+}
+
+//slave ota result
+static sint32_t gma_ota_slave_result(int crc_res)
+{
+ u8 ret = crc_res;
+
+ tws_ota_control(OTA_STATUS_SET, OTA_VERIFY_END);
+
+ tws_ota_control(OTA_RESULT_SET, crc_res, TWS_ROLE_SLAVE);
+
+ log_info("gma_ota_slave_result:%d %d\n", crc_res, tws_ota_control(OTA_STATUS_GET));
+ return 0;
+}
+
+int tws_ota_sync_cmd(int reason)
+{
+ int ret = 1;
+
+ switch (reason) {
+ //slave request
+ case SYNC_CMD_START_UPDATE:
+ log_info("SYNC_CMD_START_UPDATE\n");
+
+ if (__this->ota_status != OTA_INIT) {
+ log_info("tws ota no init");
+ break;
+ }
+ __this->ota_status = OTA_START;
+ __this->ota_data_len = 0;
+ __this->ota_remote_status = OTA_START;
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ os_sem_post(&__this->master_sem);
+ } else {
+ }
+ break;
+
+ //slave request
+ case SYNC_CMD_START_VERIFY:
+ log_info("SYNC_CMD_START_VERIFY\n");
+ __this->ota_status = OTA_VERIFY_ING;
+ __this->ota_remote_status = OTA_VERIFY_ING;
+
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ os_sem_post(&__this->master_sem);
+ } else {
+ dual_bank_update_verify(NULL, NULL, gma_ota_slave_result);
+ }
+ break;
+
+ //master request
+ case SYNC_CMD_UPDATE_OVER:
+ log_info("SYNC_CMD_UPDATE_OVER\n");
+
+ __this->ota_status = OTA_OVER;
+ __this->ota_remote_status = OTA_OVER;
+ if ((__this->ota_result & BIT(TWS_ROLE_MASTER)) && (__this->ota_result & BIT(TWS_ROLE_SLAVE))) {
+ log_info("OTA SUCCESS\n");
+ //update boot info
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ dual_bank_update_burn_boot_info(dual_bank_update_burn_boot_info_callback);
+ }
+ } else {
+ log_info("OTA ERR\n");
+ /* tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS,OTA_UPDATE_SUCC); */
+ }
+ break;
+
+ //slave request
+ case SYNC_CMD_UPDATE_ERR:
+ log_info("SYNC_CMD_UPDATE_ERR\n");
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ } else {
+ tws_ota_stop(OTA_STOP_UPDATE_OVER_ERR);
+ }
+ break;
+
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+void tws_ota_app_event_deal(u8 evevt)
+{
+ if (__this->ota_status == OTA_OVER) {
+ return;
+ }
+
+ switch (evevt) {
+ case TWS_EVENT_CONNECTION_DETACH:
+ /* case TWS_EVENT_PHONE_LINK_DETACH: */
+ case TWS_EVENT_REMOVE_PAIRS:
+ log_info("stop ota : %d --1\n", evevt);
+ tws_ota_stop(OTA_STOP_LINK_DISCONNECT);
+ break;
+ default:
+ break;
+ }
+}
+
+void tws_ota_stop(u8 reason)
+{
+ log_info("%s", __func__);
+
+ if (__this->ota_status != OTA_OVER) {
+
+ //reconnect hfp when start err
+ if (reason == OTA_STOP_APP_DISCONNECT || reason == OTA_STOP_UPDATE_OVER_ERR) {
+ //在更新信息的时候,手机app断开
+
+ /* if(tws_api_get_role() == TWS_ROLE_MASTER) { */
+ /* extern void user_post_key_msg(u8 user_msg); */
+ /* user_post_key_msg(USER_TWS_OTA_RESUME); */
+ /* } */
+ }
+
+ __this->ota_status = OTA_OVER;
+ if (__this->ota_timer_id) {
+ sys_timeout_del(__this->ota_timer_id);
+ __this->ota_timer_id = 0;
+ }
+
+ tws_ota_close();
+ dual_bank_passive_update_exit(NULL);
+#if RCSP_UPDATE_EN
+ extern void rcsp_db_update_fail_deal(); //双备份升级失败处理
+ rcsp_db_update_fail_deal();
+#endif
+ }
+}
+
+int bt_ota_event_handler(struct bt_event *bt)
+{
+ int ret = 0;
+ switch (bt->event) {
+ case OTA_START_UPDATE:
+ log_info("OTA_START_UPDATE\n");
+ tws_api_sync_call_by_uuid(0xA2E22223, SYNC_CMD_START_UPDATE, 400);
+ break;
+ case OTA_START_UPDATE_READY:
+ log_info("OTA_START_UPDATE_READY:%x %x %d\n", __this->para.fm_crc16, __this->para.fm_size, __this->para.max_pkt_len);
+ extern void rcsp_before_enter_db_update_mode();
+#if(RCSP_UPDATE_EN)
+ rcsp_before_enter_db_update_mode();
+#endif
+ if (__this->slave_r_buf) {
+ ASSERT(0, "tws_ota_update_loop already exit\n");
+ }
+ task_create(tws_ota_update_loop, NULL, THIS_TASK_NAME);
+ __this->slave_r_buf = malloc(SLAVE_REV_BUF_LEN);
+ ASSERT(__this->slave_r_buf, "slave_r_buf malloc err\n");
+ cbuf_init(&(__this->cbuffer), __this->slave_r_buf, SLAVE_REV_BUF_LEN);
+
+ os_sem_post(&__this->slave_sem);
+ /* tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS,OTA_START_UPDATE); */
+ break;
+ case OTA_START_VERIFY:
+ log_info("OTA_START_VERIFY\n");
+ if (__this->ota_data_len == __this->para.fm_size) {
+ tws_api_sync_call_by_uuid(0xA2E22223, SYNC_CMD_START_VERIFY, 1000);
+ } else {
+ if (__this->ota_timer_id) {
+ sys_timeout_del(__this->ota_timer_id);
+ __this->ota_timer_id = 0;
+ }
+ __this->ota_timer_id = sys_timeout_add(NULL, ota_verify_timeout, 500);
+ }
+ break;
+ case OTA_UPDATE_OVER:
+ log_info("OTA_UPDATE_OVER\n");
+ tws_api_sync_call_by_uuid(0xA2E22223, SYNC_CMD_UPDATE_OVER, 400);
+ break;
+ case OTA_UPDATE_ERR:
+ log_info("OTA_UPDATE_ERR\n");
+ tws_api_sync_call_by_uuid(0xA2E22223, SYNC_CMD_UPDATE_ERR, 400);
+ break;
+ case OTA_UPDATE_SUCC:
+ log_info("OTA_UPDATE_SUCC\n");
+ update_result_set(UPDATA_SUCC);
+ dual_bank_passive_update_exit(NULL);
+
+ /* update_result_set(UPDATA_SUCC); */
+ /* extern void cpu_reset(); */
+ /* cpu_reset(); */
+ //user_ctl.shutdown_need_adv = 0;
+ sys_enter_soft_poweroff((void *)1);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+const update_op_tws_api_t update_tws_api = {
+ .tws_ota_start = tws_ota_open,
+ .tws_ota_data_send = tws_ota_data_send_m_to_s,
+ .tws_ota_err = tws_ota_err_callback,
+ .enter_verfiy_hdl = tws_ota_enter_verify,
+ .exit_verify_hdl = tws_ota_exit_verify,
+ .update_boot_info_hdl = tws_ota_updata_boot_info_over,
+ .tws_ota_result_hdl = NULL,
+ .tws_ota_data_send_pend = NULL,
+};
+
+update_op_tws_api_t *get_tws_update_api(void)
+{
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
+ return &update_tws_api;
+ } else {
+ return NULL;
+ }
+}
+
+static void rcsp_adv_tws_ota_sync_handler(int reason, int err)
+{
+ tws_ota_sync_cmd(reason);
+}
+
+TWS_SYNC_CALL_REGISTER(rcsp_adv_tws_ota_sync) = {
+ .uuid = 0xA2E22223,
+ .task_name = "app_core",
+ .func = rcsp_adv_tws_ota_sync_handler,
+};
+
+#endif
+
diff --git a/apps/common/update/update_tws_new.c b/apps/common/update/update_tws_new.c
new file mode 100644
index 0000000..bfc3d48
--- /dev/null
+++ b/apps/common/update/update_tws_new.c
@@ -0,0 +1,559 @@
+#include
+#include
+#include
+
+#include "generic/lbuf.h"
+#include "init.h"
+#include "update_tws_new.h"
+#include "dual_bank_updata_api.h"
+#include "bt_tws.h"
+#include "app_config.h"
+#include "btstack/avctp_user.h"
+#include "update.h"
+#include "app_main.h"
+#include "timer.h"
+
+#if (OTA_TWS_SAME_TIME_ENABLE && OTA_TWS_SAME_TIME_NEW) //(RCSP_ADV_EN || AI_APP_PROTOCOL))
+//#define LOG_TAG_CONST EARPHONE
+#define LOG_TAG "[UPDATE_TWS]"
+#define log_errorOR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#define THIS_TASK_NAME "tws_ota"
+
+OS_SEM tws_ota_sem;
+int tws_ota_timeout_hdl = 0;
+static u8 sync_update_sn = 1;
+
+static void (*user_chip_tws_update_handle)(void *data, u32 len) = NULL;
+static void (*sync_update_crc_init_hdl)(void) = NULL;
+static u32(*sync_update_crc_calc_hdl)(u32 init_crc, u8 *data, u32 len) = NULL;
+
+int clk_set(const char *name, int clk);
+
+__attribute__((weak))
+void db_update_notify_fail_to_phone()
+{
+
+}
+
+void tws_sync_update_crc_handler_register(void (*crc_init_hdl)(void), u32(*crc_calc_hdl)(u32 init_crc, u8 *data, u32 len))
+{
+ sync_update_crc_init_hdl = crc_init_hdl;
+ sync_update_crc_calc_hdl = crc_calc_hdl;
+ printf("sync_update_crc_init_hdl:%x\n sync_update_crc_calc_hdl:%x\n", sync_update_crc_init_hdl, sync_update_crc_calc_hdl);
+}
+
+void sys_enter_soft_poweroff(void *priv);
+int tws_ota_close(void);
+
+int tws_ota_get_data_from_sibling(u8 opcode, u8 *data, u8 len)
+{
+ return 0;
+}
+
+void tws_ota_timeout(void *priv) //从机没收到命令超时就退出升级
+{
+ tws_ota_close();
+ dual_bank_passive_update_exit(NULL);
+}
+
+void tws_ota_timeout_reset(void)
+{
+ if (tws_ota_timeout_hdl) {
+ sys_timeout_del(tws_ota_timeout_hdl);
+ }
+ tws_ota_timeout_hdl = sys_timeout_add(NULL, tws_ota_timeout, 8000);
+}
+
+void tws_ota_timeout_del(void)
+{
+ if (tws_ota_timeout_hdl) {
+ sys_timeout_del(tws_ota_timeout_hdl);
+ }
+}
+
+
+int tws_ota_trans_to_sibling(u8 *data, u16 len)
+{
+ if (!(tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED)) {
+ return -1;
+ }
+ return tws_api_send_data_to_sibling(data, len, TWS_FUNC_ID_OTA_TRANS);
+}
+
+u8 dual_bank_update_burn_boot_info_callback(u8 ret)
+{
+ u8 rsp_data[3] = {0};
+ rsp_data[0] = OTA_TWS_WRITE_BOOT_INFO_RSP;
+ rsp_data[1] = ++ sync_update_sn;
+ printf("sync_sn:%d\n", sync_update_sn);
+ if (ret) {
+ log_info("update_burn_boot_info err\n");
+ rsp_data[2] = OTA_TWS_CMD_ERR;
+ return -1;
+ } else {
+ log_info("slave update_burn_boot_info succ\n");
+ rsp_data[2] = OTA_TWS_CMD_SUCC;
+ //确保从机的回复命令送达到主机
+ /* os_time_dly(50); */
+ /* tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_SUCC); */
+ }
+ if (tws_ota_trans_to_sibling(rsp_data, 3)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int bt_ota_event_handler(struct bt_event *bt)
+{
+ int ret = 0;
+ switch (bt->event) {
+ case OTA_START_UPDATE:
+ log_info("OTA_START_UPDATE\n");
+ break;
+ case OTA_START_UPDATE_READY:
+ break;
+ case OTA_START_VERIFY:
+ log_info("OTA_START_VERIFY\n");
+ break;
+ case OTA_UPDATE_OVER:
+ log_info("OTA_UPDATE_OVER\n");
+ update_result_set(UPDATA_SUCC);
+ dual_bank_passive_update_exit(NULL);
+ cpu_reset();
+ //sys_enter_soft_poweroff((void *)1);
+ break;
+ case OTA_UPDATE_ERR:
+ log_info("OTA_UPDATE_ERR\n");
+ dual_bank_passive_update_exit(NULL);
+ //cpu_reset();
+ //sys_enter_soft_poweroff((void *)1);
+ break;
+ case OTA_UPDATE_SUCC:
+ log_info("OTA_UPDATE_SUCC\n");
+ update_result_set(UPDATA_SUCC);
+ dual_bank_passive_update_exit(NULL);
+ sys_enter_soft_poweroff((void *)1);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+void tws_ota_event_post(u32 type, u8 event)
+{
+ struct sys_event e;
+ e.type = SYS_BT_EVENT;
+ e.arg = (void *)type;
+ e.u.bt.event = event;
+ sys_event_notify(&e);
+}
+
+
+int tws_ota_data_send_m_to_s(u8 *buf, u16 len)
+{
+ int ret = 0;
+ u8 retry = 5;
+ os_sem_set(&tws_ota_sem, 0);
+ u8 *data = malloc(len + 2);
+ data[0] = OTA_TWS_TRANS_UPDATE_DATA;
+ data[1] = ++ sync_update_sn;
+ memcpy(&data[2], buf, len);
+ while (retry --) {
+ ret = tws_ota_trans_to_sibling(data, len + 2);
+ if (ret < 0 && ret != -1) {
+ os_time_dly(5);
+ } else {
+ break;
+ }
+ }
+ free(data);
+ return 0;
+}
+
+int tws_ota_data_send_pend(void)
+{
+ if (os_sem_pend(&tws_ota_sem, 300) == OS_TIMEOUT) { //等待收到从机的RSP
+ return -1;
+ }
+ return 0;
+}
+
+
+int tws_ota_user_chip_update_send_m_to_s(u8 cmd, u8 *buf, u16 len)
+{
+ int ret = 0;
+ u8 retry = 5;
+ u8 *data = malloc(len + 3);
+ data[0] = OTA_TWS_USER_CHIP_UPDATE;
+ data[1] = ++ sync_update_sn;
+ data[2] = cmd;
+ memcpy(&data[3], buf, len);
+ while (retry --) {
+ ret = tws_ota_trans_to_sibling(data, len + 3);
+ if (ret < 0 && ret != -1) {
+ os_time_dly(5);
+ } else {
+ break;
+ }
+ }
+ free(data);
+
+ return 0;
+}
+
+u16 tws_ota_enter_verify(void *priv)
+{
+ u8 rsp_data[2];
+ rsp_data[0] = OTA_TWS_VERIFY;
+ rsp_data[1] = ++ sync_update_sn;
+ printf("tws_ota_enter_verify111\n");
+ os_sem_set(&tws_ota_sem, 0);
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_DISCONNECTED) {
+ log_info("tws_disconn in verify\n");
+ db_update_notify_fail_to_phone();
+ return -1;
+ }
+ if (tws_ota_trans_to_sibling(&rsp_data, 2)) {
+ return -1;
+ }
+ if (os_sem_pend(&tws_ota_sem, 800) == OS_TIMEOUT) {
+ return -1;
+ }
+ printf("tws_ota_enter_verify222\n");
+ return 0;
+
+}
+
+u16 tws_ota_exit_verify(u8 *res, u8 *up_flg)
+{
+ u8 rsp_data[2];
+ rsp_data[0] = OTA_TWS_WRITE_BOOT_INFO;
+ rsp_data[1] = ++ sync_update_sn;
+
+ *up_flg = 1;
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_DISCONNECTED) {
+ log_info("tws_disconn exit verify\n");
+ db_update_notify_fail_to_phone();
+ return 0;
+ }
+ if (tws_ota_trans_to_sibling(&rsp_data, 2)) {
+ return 0;
+ }
+ if (os_sem_pend(&tws_ota_sem, 300) == OS_TIMEOUT) {
+ return 0;
+ }
+ return 1;
+}
+
+int tws_ota_result(u8 result)
+{
+ if (result == 0) {
+ tws_api_sync_call_by_uuid(0xA2E22223, SYNC_CMD_UPDATE_OVER, 400);
+ } else {
+ tws_api_sync_call_by_uuid(0xA2E22223, SYNC_CMD_UPDATE_ERR, 400);
+ }
+ return 0;
+}
+
+void tws_ota_stop(u8 reason)
+{
+ log_info("%s", __func__);
+
+ tws_ota_close();
+ dual_bank_passive_update_exit(NULL);
+#if RCSP_UPDATE_EN
+ extern void rcsp_db_update_fail_deal(); //双备份升级失败处理
+ rcsp_db_update_fail_deal();
+#endif
+}
+
+void tws_ota_app_event_deal(u8 evevt)
+{
+ switch (evevt) {
+ case TWS_EVENT_CONNECTION_DETACH:
+ /* case TWS_EVENT_PHONE_LINK_DETACH: */
+ case TWS_EVENT_REMOVE_PAIRS:
+ log_info("stop ota : %d --1\n", evevt);
+ tws_ota_stop(OTA_STOP_LINK_DISCONNECT);
+ break;
+ default:
+ break;
+ }
+}
+
+int tws_ota_init(void)
+{
+ u8 data;
+ log_info("tws_ota_init\n");
+ tws_api_auto_role_switch_disable();
+ os_sem_create(&tws_ota_sem, 0);
+ return 0;
+}
+
+int tws_ota_open(struct __tws_ota_para *para)
+{
+ int ret = 0;
+ tws_api_auto_role_switch_disable();
+ os_sem_create(&tws_ota_sem, 0);
+ u8 *data = malloc(sizeof(struct __tws_ota_para) + 2);
+ if (!data) {
+ ret = -1;
+ goto _ERR_RET;
+ }
+ log_info("tws_ota_open\n");
+
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_DISCONNECTED) {
+ log_info("tws_disconn, ota open fail");
+ db_update_notify_fail_to_phone();
+ ret = -1;
+ goto _ERR_RET;
+ }
+
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ extern void bt_check_exit_sniff();
+ bt_check_exit_sniff();
+ //master 发命令给slave启动升级
+ }
+
+ log_info("tws_ota_open1\n");
+ data[0] = OTA_TWS_START_UPDATE;
+ data[1] = ++ sync_update_sn;
+ memcpy(data + 2, para, sizeof(struct __tws_ota_para));
+ log_info("tws_ota_open2\n");
+ if (tws_ota_trans_to_sibling(data, sizeof(struct __tws_ota_para) + 2)) {
+ ret = -1;
+ goto _ERR_RET;
+ }
+ if (os_sem_pend(&tws_ota_sem, 500) == OS_TIMEOUT) {
+ log_info("tws_ota_open pend timeout\n");
+ ret = -1;
+ goto _ERR_RET;
+ }
+ printf("tws_ota_open succ...\n");
+_ERR_RET:
+ if (data) {
+ free(data);
+ }
+ return ret;
+}
+
+int tws_ota_close(void)
+{
+ int ret = 0;
+ log_info("%s", __func__);
+ task_kill(THIS_TASK_NAME);
+ return ret;
+}
+
+
+int tws_ota_err_callback(u8 reason)
+{
+ tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_ERR);
+ return 0;
+}
+
+u16 tws_ota_updata_boot_info_over(void *priv)
+{
+ return 0;
+}
+
+int tws_verify_result_hdl(int calc_crc)
+{
+ u8 rsp_data[3];
+ printf("tws_verify_result_hdl:%d\n", calc_crc);
+ rsp_data[0] = OTA_TWS_VERIFY_RSP;
+ rsp_data[1] = ++ sync_update_sn;
+ if (calc_crc == 1) {
+ rsp_data[2] = OTA_TWS_CMD_SUCC;
+ } else {
+ rsp_data[2] = OTA_TWS_CMD_ERR;
+ }
+ if (tws_ota_trans_to_sibling(rsp_data, 3)) {
+ return -1;
+ }
+ return 0;
+}
+
+int tws_trans_data_write_callback(void *priv)
+{
+ u8 rsp_data[3];
+ rsp_data[0] = OTA_TWS_TRANS_UPDATE_DATA_RSP;
+ rsp_data[1] = ++ sync_update_sn;
+ rsp_data[2] = OTA_TWS_CMD_SUCC;
+ tws_ota_trans_to_sibling(rsp_data, 3);
+ return 0;
+}
+
+
+static void deal_sibling_tws_ota_trans(void *data, u16 len, bool rx)
+{
+ static u8 last_sync_update_sn = 0;
+ int ret = 0;
+ u8 rsp_data[3];
+ u8 *recv_data = (u8 *)data;
+
+ if (rx) {
+ if (recv_data[1] == last_sync_update_sn) { //处理同一包数据会出现两次回调的情况
+ g_printf("recv_data == last_sync_update_sn:%d %d %d\n", recv_data[0], recv_data[1], last_sync_update_sn);
+ return;
+ }
+
+ last_sync_update_sn = recv_data[1];
+ /* log_info(">>>%s\n len:%d", __func__, len); */
+ /* put_buf(data, len); */
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ tws_ota_timeout_reset(); //从机接收命令超时
+ }
+ switch (recv_data[0]) {
+ case OTA_TWS_START_UPDATE:
+ g_printf("MSG_OTA_TWS_START_UPDATE\n");
+ struct __tws_ota_para para;
+ memcpy(¶, recv_data + 2, sizeof(struct __tws_ota_para));
+ printf("crc:%d fm_size:%d max_pkt_len:%d\n", para.fm_crc, para.fm_size, para.max_pkt_len);
+ dual_bank_passive_update_init(para.fm_crc, para.fm_size, para.max_pkt_len, NULL);
+ ret = dual_bank_update_allow_check(para.fm_size);
+ if (ret) {
+ rsp_data[0] = OTA_TWS_START_UPDATE_RSP;
+ rsp_data[1] = ++ sync_update_sn;
+ rsp_data[2] = OTA_TWS_CMD_ERR;
+ tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_ERR);
+ } else {
+ rsp_data[0] = OTA_TWS_START_UPDATE_RSP;
+ rsp_data[1] = ++ sync_update_sn;
+ rsp_data[2] = OTA_TWS_CMD_SUCC;
+ }
+ tws_ota_trans_to_sibling(rsp_data, 3);
+ break;
+ case OTA_TWS_START_UPDATE_RSP:
+ g_printf("MSG_OTA_TWS_START_UPDATE_RSP\n");
+ if (recv_data[2] == OTA_TWS_CMD_SUCC) {
+ os_sem_post(&tws_ota_sem);
+ }
+ break;
+ case OTA_TWS_TRANS_UPDATE_DATA:
+ printf("MSG_OTA_TWS_TRANS_UPDATE_DATA %d\n", recv_data[1]);
+ dual_bank_update_write(recv_data + 2, len - 2, tws_trans_data_write_callback);
+ break;
+ case OTA_TWS_TRANS_UPDATE_DATA_RSP:
+ printf("MSG_OTA_TWS_TRANS_UPDATE_DATA_RSP:%d\n", recv_data[1]);
+ if (recv_data[2] == OTA_TWS_CMD_SUCC) {
+ os_sem_post(&tws_ota_sem);
+ }
+ break;
+ case OTA_TWS_VERIFY:
+ g_printf("MSG_OTA_TWS_VERIFY\n");
+ clk_set("sys", 120 * 1000000L); //提升主频加快CRC校验速度
+ ret = dual_bank_update_verify(sync_update_crc_init_hdl, sync_update_crc_calc_hdl, tws_verify_result_hdl);
+ if (ret) {
+ rsp_data[0] = OTA_TWS_VERIFY_RSP;
+ rsp_data[1] = ++ sync_update_sn;
+ rsp_data[2] = OTA_TWS_CMD_ERR;
+ tws_ota_trans_to_sibling(rsp_data, 2);
+ }
+ break;
+ case OTA_TWS_VERIFY_RSP:
+ g_printf("MSG_OTA_TWS_VERIFY_RSP %d\n", recv_data[1]);
+ if (recv_data[2] == OTA_TWS_CMD_SUCC) {
+ os_sem_post(&tws_ota_sem);
+ }
+ break;
+ case OTA_TWS_WRITE_BOOT_INFO:
+ g_printf("MSG_OTA_TWS_WRITE_BOOT_INFO\n");
+ dual_bank_update_burn_boot_info(dual_bank_update_burn_boot_info_callback);
+ break;
+ case OTA_TWS_WRITE_BOOT_INFO_RSP:
+ g_printf("MSG_OTA_TWS_WRITE_BOOT_INFO_RSP\n");
+ if (recv_data[2] == OTA_TWS_CMD_SUCC) {
+ os_sem_post(&tws_ota_sem);
+ }
+ break;
+ case OTA_TWS_UPDATE_RESULT:
+ g_printf("MSG_OTA_TWS_UPDATE_RESULT\n");
+ if (recv_data[2] == OTA_TWS_CMD_SUCC) {
+ tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_OVER);
+ } else {
+ tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_ERR);
+ }
+ break;
+
+ case OTA_TWS_USER_CHIP_UPDATE:
+ if (user_chip_tws_update_handle) {
+ user_chip_tws_update_handle(recv_data + 2, len - 2);
+ }
+ break;
+ }
+ }
+}
+
+
+int tws_ota_sync_cmd(int reason)
+{
+ switch (reason) {
+ case SYNC_CMD_UPDATE_OVER:
+ g_printf("SYNC_CMD_UPDATE_OVER\n");
+ cpu_reset();
+ /* tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_OVER); */
+ break;
+ case SYNC_CMD_UPDATE_ERR:
+ g_printf("SYNC_CMD_UPDATE_ERR\n");
+ cpu_reset();
+ /* tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_ERR); */
+ break;
+ }
+ return 0;
+}
+
+static void rcsp_adv_tws_ota_sync_handler(int reason, int err)
+{
+ tws_ota_sync_cmd(reason);
+}
+
+const update_op_tws_api_t update_tws_api = {
+ .tws_ota_start = tws_ota_open,
+ .tws_ota_data_send = tws_ota_data_send_m_to_s,
+ .tws_ota_err = tws_ota_err_callback,
+ .enter_verfiy_hdl = tws_ota_enter_verify,
+ .exit_verify_hdl = tws_ota_exit_verify,
+ .update_boot_info_hdl = tws_ota_updata_boot_info_over,
+ .tws_ota_result_hdl = tws_ota_result,
+ .tws_ota_data_send_pend = tws_ota_data_send_pend,
+ //for user_chip
+ .tws_ota_user_chip_update_send = tws_ota_user_chip_update_send_m_to_s,
+};
+
+update_op_tws_api_t *get_tws_update_api(void)
+{
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
+ return &update_tws_api;
+ } else {
+ return NULL;
+ }
+}
+
+REGISTER_TWS_FUNC_STUB(tws_ota_trans) = {
+ .func_id = TWS_FUNC_ID_OTA_TRANS,
+ .func = deal_sibling_tws_ota_trans,
+};
+
+TWS_SYNC_CALL_REGISTER(rcsp_adv_tws_ota_sync) = {
+ .uuid = 0xA2E22223,
+ .task_name = "app_core",
+ .func = rcsp_adv_tws_ota_sync_handler,
+};
+
+void tws_update_register_user_chip_update_handle(void (*update_handle)(void *data, u32 len))
+{
+ user_chip_tws_update_handle = update_handle;
+}
+
+#endif
+
diff --git a/apps/earphone/app_ancbox.c b/apps/earphone/app_ancbox.c
new file mode 100644
index 0000000..7b9be34
--- /dev/null
+++ b/apps/earphone/app_ancbox.c
@@ -0,0 +1,1530 @@
+#include "init.h"
+#include "app_config.h"
+#include "system/includes.h"
+#include "btstack/avctp_user.h"
+#include "include/earphone.h"
+
+#if TCFG_ANC_BOX_ENABLE
+
+#ifdef SUPPORT_MS_EXTENSIONS
+#pragma bss_seg(".anc_box_bss")
+#pragma data_seg(".anc_box_data")
+#pragma const_seg(".anc_box_const")
+#pragma code_seg(".anc_box_code")
+#endif/*SUPPORT_MS_EXTENSIONS*/
+
+#include "audio_anc.h"
+#include "asm/charge.h"
+#include "asm/chargestore.h"
+#include "user_cfg.h"
+#include "device/vm.h"
+#include "app_action.h"
+#include "app_main.h"
+#include "app_ancbox.h"
+#include "app_power_manage.h"
+#include "app_chargestore.h"
+#include "anc_btspp.h"
+#include "user_cfg.h"
+#include "audio_config.h"
+#include "audio_codec_clock.h"
+
+#if AUDIO_ENC_MPT_SELF_ENABLE
+#include "audio_enc_mpt_self.h"
+#endif/*AUDIO_ENC_MPT_SELF_ENABLE*/
+
+#if TCFG_AUDIO_CVP_DUT_ENABLE
+#include "audio_cvp_dut.h"
+#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
+
+#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+#include "icsd_adt_app.h"
+#endif
+
+#if AUDIO_SPK_EQ_CONFIG
+#include "audio_dec_eff.h"
+#endif
+
+#define LOG_TAG_CONST APP_ANCBOX
+#define LOG_TAG "[APP_ANCBOX]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#define ANC_VERSION 1//有必要时才更新该值(例如结构体数据改了)
+
+enum {
+ FILE_ID_COEFF = 0, //系数文件ID号
+ FILE_ID_MIC_SPK = 1, //mic spk文件ID号
+ FILE_ID_GAIN = 2, //GAIN数据
+ FILE_ID_ADAPTIVE = 3, //自适应模式文件ID
+ FILE_ID_ADAPTIVE_REF = 4, //自适应模式金机曲线ID
+ //FILE_ID_SPKEQ = 5, //EQ数据
+ FILE_ID_SZ_FFT = 6, //SZ频响数据
+ FILE_ID_MIC_FFT = 7, //MIC声学频响数据
+ FILE_ID_COEFF_FGQ = 8, //新系数文件-FGQ ID号
+ FILE_ID_COEFF_FGQ_PART = 9, //新部分系数文件-FGQ ID号
+ FILE_ID_SPKEQ_DATA_L = 10, //SPK_EQ数据左耳
+ FILE_ID_SPKEQ_DATA_R = 11, //SPK_EQ数据右耳
+};
+
+struct _ear_parm {
+ u8 ts; //训练步进
+ u8 mode; //训练模式(普通/快速)
+ u16 emmtv; //误差mic下限阈值
+ u16 rmmtv; //参考mic下限阈值
+ u8 sdt; //静音检测时间
+ u8 ntt; //噪声训练时间
+ u8 emstt; //误差mic静音训练时间
+ u8 rmstt; //参考mic静音训练时间
+ u8 c1tto; //系数一次校准超时时间
+ u8 c2tto; //系数二次校准超时时间
+ u8 gen; //增益配置使能位
+ u8 gdac; //dac增益
+ s8 grmic; //参考mic增益
+ s8 gemic; //误差mic增益
+ s16 ganc; //降噪增益
+ s16 gpass; //通透增益
+};
+
+struct _ancbox_info {
+ u8 ancbox_status;//anc测试盒在线状态
+ u8 err_flag;
+ u8 status;
+ u8 test_flag;
+ u8 baud_counter;
+ u8 sz_nadap_pow;
+ u8 sz_adap_pow;
+ u8 sz_mute_pow;
+ u8 fz_nadap_pow;
+ u8 fz_adap_pow;
+ u8 fz_mute_pow;
+ u8 wz_nadap_pow;
+ u8 wz_adap_pow;
+ u8 train_step_succ;
+#if ANCTOOL_NEED_PAIR_KEY
+ u8 pair_flag;
+#endif
+ u8 audio_enc_mpt_fre_ch;
+ u8 fft_file_busy; //MIC_FFT SZ_FFT run状态获取: 1 正在run, 0 已停止
+ anc_train_para_t *para;
+ u8 *coeff;
+ u32 coeff_ptr;
+ u8 idle_flag;
+ int anc_timer;
+ int baud_timer;
+ u8 *file_hdl;
+ u32 file_id;
+ u32 file_len;
+ u32 coeff_len;
+ u32 data_offset;
+ u32 data_len;
+ u8 *data_ptr;
+ u32 type_id;
+ u32 type_value;
+ anc_gain_t gain;
+};
+
+#define DEFAULT_BAUDRATE 9600
+enum {
+ CMD_ANC_STATUS = 0x00, //获取状态
+ CMD_ANC_SET_START = 0x01, //ANC训练开始
+ CMD_ANC_MUTE_TRAIN = 0x02, //静音训练
+ CMD_ANC_SIN_TRAIN = 0x03, //找步进训练
+ CMD_ANC_NOISE_TRAIN = 0x04, //噪声训练
+ CMD_ANC_TEST_ANC_ON = 0x05, //ANC ON
+ CMD_ANC_TEST_ANC_OFF = 0x06, //ANC OFF
+ CMD_ANC_SET_STOP = 0x07, //停止训练
+ CMD_ANC_SET_PARM = 0x08, //设置参数
+ CMD_ANC_SYS_RESET = 0x09, //复位系统
+ CMD_ANC_SET_RUN_MODE = 0x0A, //设置ANC运行模式
+ CMD_ANC_TEST_PASS = 0x0B, //设置为通透
+ CMD_ANC_CHANGE_BAUD = 0x0C, //切换波特率
+ CMD_ANC_DEVELOPER_MODE = 0x0D, //开发者模式
+ CMD_ANC_ADAP = 0x0E, //开关自适应
+ CMD_ANC_WZ_BREAK = 0x0F, //退出噪声训练
+ CMD_ANC_SET_TS = 0x10, //单独设置步进
+ CMD_ANC_TRAIN_STEP = 0x11, //设置训练步进
+ CMD_ANC_GET_TRAIN_STEP = 0x12, //获取训练步进
+ CMD_ANC_GET_MUTE_TRAIN_POW = 0x13,//获取静音训练的收敛数据
+ CMD_ANC_GET_NOISE_TRAIN_POW = 0x14,//获取噪声训练的收敛数据
+ CMD_ANC_GET_TRAIN_POW = 0x15, //用于手动训练时实时读取收敛值
+ CMD_ANC_SET_ID = 0x16, //根据ID设置参数
+ CMD_ANC_GET_ID = 0x17, //根据ID读取参数
+ CMD_ANC_TEST_BYPASS = 0x18, //设置bypass模式
+ CMD_ANC_CHANGE_MODE = 0x19, //切换ANC模式 = 0x01, FF/FB/HB
+ CMD_ANC_GET_COEFF_SIZE = 0x1A, //获取系数大小
+ CMD_ANC_MUTE_TRAIN_ONLY = 0x1B,//单独进行静音训练
+ CMD_ANC_GET_VERSION = 0x1C, //获取芯片版本号
+ CMD_ANC_TRANS_TRAIN = 0x1D, //单独进行通透训练
+ CMD_ANC_CREATE_SPK_MIC = 0x1E, //触发生成SPK MIC数据
+ CMD_ANC_GET_ANC_CH = 0x1F, //获取耳机的通道 = 0x01,左声道/右声道/双声道
+ CMD_ANC_PAIR_KEY = 0x20, //和耳机进行密码验证 = 0x01,匹配才能读系数
+ CMD_ANC_PAIR_SUCC = 0x21, //绕过配对过程
+ CMD_ANC_GET_MAX_ORDER = 0x22, //获取ANC最大滤波器阶数
+ CMD_ANC_GET_HEARAID_EN = 0x23, //
+ //透传指令START
+ CMD_ANC_SZ_FFT_START = 0x51, //SZ_FFT计算开始
+ CMD_ANC_SZ_FFT_STOP = 0x52, //SZ_FFT计算停止
+ CMD_ANC_MIC_FFT_START = 0x53, //MIC_FFT计算停止
+ CMD_ANC_MIC_FFT_STOP = 0x54, //MIC_FFT计算停止
+ CMD_MUTL_SCENE_SET = 0X55, //ANC多场景设置
+ CMD_FFT_FILE_BUSY_GET = 0X56, //FFT flie busy状态获取
+ //透传指令END
+
+ CMD_ANC_GET_MAC = 0x80, //获取MAC地址
+ CMD_ANC_TOOLS_SYNC, //同步信号,同CMD_ANC_STATUS一样意思
+ CMD_ANC_SET_LINKKEY, //设置linkkey
+ CMD_ANC_SW_TO_BT, //切到蓝牙模式
+ CMD_ANC_READ_COEFF, //开始读取系数
+ CMD_ANC_READ_COEFF_CONTINUE,//连续读取系数
+ CMD_ANC_WRITE_COEFF, //开始写系数
+ CMD_ANC_WRITE_COEFF_CONTINUE,//连续写系数
+ CMD_ANC_GET_RESULT, //获取训练结果
+ CMD_ANC_SET_GAIN, //设置gain
+ CMD_ANC_GET_GAIN, //读取gain
+ CMD_ANC_READ_FILE_START,//根据ID号读文件开始
+ CMD_ANC_READ_FILE_DATA, //根据ID号读文件数据
+ CMD_ANC_WRITE_FILE_START,//根据ID号写文件开始
+ CMD_ANC_WRITE_FILE_DATA,//跟据ID号写文件数据
+ CMD_ANC_WRITE_FILE_END, //根据ID号写文件结束
+
+ CMD_ANC_EQ_DATA = 0x90, //eq数据传输
+
+ //透传指令START
+ CMD_ANC_SET_MUSIC_VOL, //设置音量
+ CMD_ANC_NEW_EQ_DATA, //eq调试新指令
+
+ CMD_ANC_CVP_DUT_DATA = 0xA0, //CVP_DUT数据传输
+ //透传指令END
+
+ CMD_ANC_FAIL = 0xFE,
+};
+
+#define ANC_POW_SIZE 15
+static u8 anc_pow[ANC_POW_SIZE];
+static u8 eq_buffer[32];
+static u8 eq_len;
+static int cvp_dut_len;
+static u8 *cvp_dut_buffer;
+static struct _ancbox_info ancbox_info;
+#define __this (&ancbox_info)
+extern void sys_auto_shut_down_disable(void);
+extern void sys_auto_shut_down_enable(void);
+extern void bt_update_mac_addr(u8 *addr);
+extern void set_temp_link_key(u8 *linkkey);
+extern void chargestore_set_baudrate(u32 baudrate);
+extern void anc_cfg_btspp_update(u8 id, int data);
+extern int anc_cfg_btspp_read(u8 id, int *data);
+extern int anc_mode_change_tool(u8 dat);
+
+static void ancbox_callback(u8 mode, u8 command)
+{
+ log_info("ancbox_callback: %d, %d\n", mode, command);
+ if (mode & 0x80) {//train step
+ __this->err_flag = ANC_EXEC_SUCC;
+ __this->train_step_succ = 1;
+ } else {
+ __this->err_flag = command;
+ }
+
+ if (__this->status == CMD_ANC_CREATE_SPK_MIC) {
+ __this->status = CMD_ANC_SET_STOP;
+ }
+}
+
+static void ancbox_pow_callback(anc_ack_msg_t *msg, u8 step)
+{
+ switch (step) {
+ case ANC_TRAIN_SZ:
+ __this->sz_nadap_pow = anc_powdat_analysis(msg->pow);
+ __this->sz_adap_pow = anc_powdat_analysis(msg->temp_pow);
+ __this->sz_mute_pow = anc_powdat_analysis(msg->mute_pow);
+ break;
+ case ANC_TRAIN_FZ:
+ __this->fz_nadap_pow = anc_powdat_analysis(msg->pow);
+ __this->fz_adap_pow = anc_powdat_analysis(msg->temp_pow);
+ __this->fz_mute_pow = anc_powdat_analysis(msg->mute_pow);
+ break;
+ case ANC_TRAIN_WZ:
+ __this->wz_nadap_pow = anc_powdat_analysis(msg->pow);
+ __this->wz_adap_pow = anc_powdat_analysis(msg->temp_pow);
+ if (msg->status == ANC_WZ_ADAP_STATUS) {
+ for (u8 i = 0; i < (ANC_POW_SIZE - 1); i++) {
+ anc_pow[i] = anc_pow[i + 1];
+ }
+ anc_pow[ANC_POW_SIZE - 1] = anc_powdat_analysis(msg->temp_pow);
+ }
+ break;
+ }
+}
+
+static void anc_event_to_user(u8 event, u32 value)
+{
+ struct sys_event e;
+ e.type = SYS_DEVICE_EVENT;
+ e.arg = (void *)DEVICE_EVENT_FROM_ANC;
+ e.u.ancbox.event = event;
+ e.u.ancbox.value = value;
+ sys_event_notify(&e);
+}
+
+static void anc_cmd_timeout_deal(void *priv)
+{
+ log_info("mabe takeup! sys reset!\n");
+ cpu_reset();
+}
+
+static void anc_cmd_timeout_init(void)
+{
+ if (__this->anc_timer == 0) {
+#if ANC_MIC_DMA_EXPORT
+ __this->anc_timer = sys_timeout_add(NULL, anc_cmd_timeout_deal, 5000);
+#else
+ __this->anc_timer = sys_timeout_add(NULL, anc_cmd_timeout_deal, 1000);
+#endif
+ } else {
+ sys_timer_modify(__this->anc_timer, 1000);
+ }
+}
+
+static void anc_cmd_timeout_del(void)
+{
+ if (__this->anc_timer) {
+ sys_timeout_del(__this->anc_timer);
+ __this->anc_timer = 0;
+ }
+}
+
+static void anc_baud_timer_deal(void *priv)
+{
+ __this->baud_counter++;
+ if (__this->baud_counter > 20) {
+ sys_timer_del(__this->baud_timer);
+ __this->baud_timer = 0;
+ __this->baud_counter = 0;
+ log_info("timer out, set baud 9600!\n");
+ chargestore_set_baudrate(DEFAULT_BAUDRATE);
+ }
+}
+
+static void anc_wz_timeout_deal(void *priv)
+{
+ anc_train_api_set(ANC_TEST_WZ_BREAK, 0, __this->para);
+}
+
+static void anc_read_file_start(u8 *cmd, u32 id)
+{
+ u32 data_len;
+ int *anc_debug_hdl;
+ __this->file_id = id;
+ switch (__this->file_id) {
+ case FILE_ID_COEFF:
+ case FILE_ID_COEFF_FGQ:
+#if ANCTOOL_NEED_PAIR_KEY
+ if (!__this->pair_flag) {
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ return;
+ }
+#endif
+#if (ANC_CHIP_VERSION == ANC_VERSION_BR36) || (ANC_CHIP_VERSION == ANC_VERSION_BR28)
+ __this->file_len = anc_coeff_size_get(ANC_CFG_READ);
+#else
+ __this->file_len = anc_coeff_size_get();
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR36*/
+ __this->file_hdl = (u8 *)anc_coeff_read();
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_READ_FILE_START;
+ if (__this->file_hdl) {//判断耳机有没有系数
+ memcpy(&cmd[2], (u8 *)&__this->file_len, 4);
+ chargestore_api_write(cmd, 6);
+ anc_cmd_timeout_del();
+ } else {
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ }
+ break;
+ case FILE_ID_MIC_SPK:
+ //这里判断是否有数据
+#if (ANC_CHIP_VERSION == ANC_VERSION_BR36) || (ANC_CHIP_VERSION == ANC_VERSION_BR28)
+ anc_debug_hdl = (u8 *)anc_debug_ctr(0);
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_READ_FILE_START;
+ if (anc_debug_hdl) {
+ __this->file_hdl = (u8 *)(anc_debug_hdl + 1); //数据指针
+ __this->file_len = anc_debug_hdl[0];
+ memcpy(&cmd[2], (u8 *)&__this->file_len, 4);
+ chargestore_api_write(cmd, 6);
+ anc_cmd_timeout_del();
+ } else {
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ }
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR36*/
+ break;
+ case FILE_ID_GAIN:
+ anc_cfg_online_deal(ANC_CFG_READ, &__this->gain);
+ __this->file_len = sizeof(anc_gain_t);
+ __this->file_hdl = (u8 *)&__this->gain;
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_READ_FILE_START;
+ memcpy(&cmd[2], (u8 *)&__this->file_len, 4);
+ chargestore_api_write(cmd, 6);
+ anc_cmd_timeout_del();
+ break;
+#if TCFG_ANC_SELF_DUT_GET_SZ
+ case FILE_ID_SZ_FFT:
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_READ_FILE_START;
+ __this->file_len = audio_anc_sz_fft_outbuf_get((&__this->file_hdl));
+ if (__this->file_hdl) {
+ memcpy(&cmd[2], (u8 *)&__this->file_len, 4);
+ chargestore_api_write(cmd, 6);
+ anc_cmd_timeout_del();
+ } else {
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ }
+ break;
+#endif/*TCFG_ANC_SELF_DUT_GET_SZ*/
+
+#if AUDIO_ENC_MPT_SELF_ENABLE
+ case FILE_ID_MIC_FFT:
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_READ_FILE_START;
+ __this->file_len = audio_enc_mpt_fre_response_file_get((&__this->file_hdl));
+ if (__this->file_hdl) {
+ memcpy(&cmd[2], (u8 *)&__this->file_len, 4);
+ chargestore_api_write(cmd, 6);
+ anc_cmd_timeout_del();
+ } else {
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ }
+ break;
+#endif/*AUDIO_ENC_MPT_SELF_ENABLE*/
+#if AUDIO_SPK_EQ_CONFIG
+ case FILE_ID_SPKEQ_DATA_L:
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_READ_FILE_START;
+ __this->file_len = spk_eq_read_seg_l((&__this->file_hdl));
+ if (__this->file_hdl) {
+ memcpy(&cmd[2], (u8 *)&__this->file_len, 4);
+ chargestore_api_write(cmd, 6);
+ anc_cmd_timeout_del();
+ } else {
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ }
+ break;
+ case FILE_ID_SPKEQ_DATA_R:
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_READ_FILE_START;
+ __this->file_len = spk_eq_read_seg_r((&__this->file_hdl));
+ if (__this->file_hdl) {
+ memcpy(&cmd[2], (u8 *)&__this->file_len, 4);
+ chargestore_api_write(cmd, 6);
+ anc_cmd_timeout_del();
+ } else {
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ }
+ break;
+#endif
+ }
+}
+
+static void anc_read_file_data(u8 *cmd, u32 offset, u32 data_len)
+{
+ u32 read_len;
+ switch (__this->file_id) {
+ case FILE_ID_COEFF:
+ case FILE_ID_COEFF_FGQ:
+#if ANCTOOL_NEED_PAIR_KEY
+ if (!__this->pair_flag) {
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ return;
+ }
+#endif
+#if AUDIO_SPK_EQ_CONFIG
+ case FILE_ID_SPKEQ_DATA_L:
+ case FILE_ID_SPKEQ_DATA_R:
+#endif/*AUDIO_SPK_EQ_CONFIG*/
+ case FILE_ID_GAIN:
+ if (__this->file_hdl == NULL) {
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ } else {
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_READ_FILE_DATA;
+ memcpy(&cmd[2], __this->file_hdl + offset, data_len);
+ chargestore_api_write(cmd, data_len + 2);
+ if (__this->file_len == offset + data_len) {
+ __this->file_hdl = NULL;
+ }
+ }
+ break;
+ case FILE_ID_MIC_SPK:
+#if (ANC_CHIP_VERSION == ANC_VERSION_BR36) || (ANC_CHIP_VERSION == ANC_VERSION_BR28)
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_READ_FILE_DATA;
+ if (__this->file_hdl) {
+ memcpy(&cmd[2], __this->file_hdl + offset, data_len);
+ chargestore_api_write(cmd, data_len + 2);
+ if (__this->file_len == offset + data_len) {
+ __this->file_hdl = (u8 *)anc_debug_ctr(1);
+ }
+ } else {
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ }
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR36*/
+ break;
+#if TCFG_ANC_SELF_DUT_GET_SZ
+ case FILE_ID_SZ_FFT:
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_READ_FILE_DATA;
+ if (__this->file_hdl) {
+ memcpy(&cmd[2], __this->file_hdl + offset, data_len);
+ chargestore_api_write(cmd, data_len + 2);
+ if (__this->file_len == offset + data_len) {
+ audio_anc_sz_fft_outbuf_release();
+ audio_codec_clock_del(ANC_DUT_SZ_FFT_MODE);
+ __this->file_hdl = NULL;
+ }
+ } else {
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ }
+ break;
+#endif/*TCFG_ANC_SELF_DUT_GET_SZ*/
+#if AUDIO_ENC_MPT_SELF_ENABLE
+ case FILE_ID_MIC_FFT:
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_READ_FILE_DATA;
+ if (__this->file_hdl) {
+ memcpy(&cmd[2], __this->file_hdl + offset, data_len);
+ chargestore_api_write(cmd, data_len + 2);
+ if (__this->file_len == offset + data_len) {
+ audio_enc_mpt_fre_response_release();
+ __this->file_hdl = NULL;
+ }
+ } else {
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ }
+ break;
+#endif/*AUDIO_ENC_MPT_SELF_ENABLE*/
+ }
+}
+
+static void anc_write_file_start(u8 *cmd, u32 id, u32 data_len)
+{
+ __this->file_id = id;
+ if (__this->file_hdl) {
+ free(__this->file_hdl);
+ __this->file_hdl = NULL;
+ }
+ if (__this->data_ptr) {
+ free(__this->data_ptr);
+ __this->data_ptr = NULL;
+ }
+
+ switch (__this->file_id) {
+ case FILE_ID_COEFF:
+ case FILE_ID_COEFF_FGQ:
+ case FILE_ID_COEFF_FGQ_PART:
+#if (ANC_CHIP_VERSION == ANC_VERSION_BR36) || (ANC_CHIP_VERSION == ANC_VERSION_BR28)
+ cmd[0] = CMD_ANC_MODULE;
+ anc_coeff_size_set(ANC_CFG_WRITE, data_len); //设置长度写anc_coeff.bin
+ __this->file_len = data_len;
+#else
+ __this->file_len = anc_coeff_size_get();
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR36*/
+ __this->file_hdl = (u8 *)malloc(__this->file_len);
+ __this->data_ptr = (u8 *)malloc(32);
+ if ((__this->file_len != data_len) || (__this->file_hdl == NULL) || (__this->data_ptr == NULL)) {
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ log_info("anc coeff size err, %d != %d\n", data_len, __this->file_len);
+ if (__this->file_hdl) {
+ free(__this->file_hdl);
+ __this->file_hdl = NULL;
+ }
+ if (__this->data_ptr) {
+ free(__this->data_ptr);
+ __this->data_ptr = NULL;
+ }
+ return;
+ } else {
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_WRITE_FILE_START;
+ chargestore_api_write(cmd, 2);
+ anc_cmd_timeout_del();
+ }
+ break;
+ case FILE_ID_GAIN:
+ __this->file_len = sizeof(anc_gain_t);
+ __this->file_hdl = (u8 *)&__this->gain;
+ __this->data_ptr = (u8 *)malloc(32);
+ if ((__this->file_len != data_len) || (__this->data_ptr == NULL)) {
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ log_info("anc gain size err, %d != %d\n", data_len, __this->file_len);
+ if (__this->data_ptr) {
+ free(__this->data_ptr);
+ __this->data_ptr = NULL;
+ }
+ } else {
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_WRITE_FILE_START;
+ chargestore_api_write(cmd, 2);
+ anc_cmd_timeout_del();
+ }
+ break;
+ }
+}
+
+static void anc_write_file_data(u8 *cmd, u32 offset, u8 *data, u32 data_len)
+{
+ switch (__this->file_id) {
+ case FILE_ID_COEFF:
+ case FILE_ID_COEFF_FGQ:
+ case FILE_ID_COEFF_FGQ_PART:
+ case FILE_ID_GAIN:
+ if (__this->file_hdl == NULL || ((offset + data_len) > __this->file_len)) {
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ } else {
+ memcpy(__this->file_hdl + offset, data, data_len);
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_WRITE_FILE_DATA;
+ chargestore_api_write(cmd, 2);
+ }
+ break;
+ }
+}
+
+static int app_anc_write_file_end(u32 file_id)
+{
+ int ret;
+ switch (file_id) {
+ case FILE_ID_COEFF:
+ ret = anc_coeff_write((int *)__this->file_hdl, __this->file_len);
+ break;
+#if ANC_MULT_ORDER_ENABLE
+ case FILE_ID_COEFF_FGQ:
+ ret = audio_anc_mult_coeff_write(ANC_MULT_COEFF_FILL_ALL, (int *)__this->file_hdl, __this->file_len);
+ break;
+ case FILE_ID_COEFF_FGQ_PART:
+ ret = audio_anc_mult_coeff_write(ANC_MULT_COEFF_FILL_PART, (int *)__this->file_hdl, __this->file_len);
+ break;
+#endif/*ANC_MULT_ORDER_ENABLE*/
+ }
+ free(__this->file_hdl);
+ free(__this->data_ptr);
+ __this->file_hdl = NULL;
+ __this->data_ptr = NULL;
+ return ret;
+}
+
+
+static void anc_write_file_end(u8 *cmd)
+{
+ switch (__this->file_id) {
+ case FILE_ID_COEFF:
+ case FILE_ID_COEFF_FGQ:
+ case FILE_ID_COEFF_FGQ_PART:
+ if (__this->file_hdl == NULL) {
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ } else {
+ anc_cmd_timeout_del();
+ if (app_anc_write_file_end(__this->file_id)) {
+ cmd[1] = CMD_ANC_FAIL;
+ } else {
+ cmd[1] = CMD_ANC_WRITE_FILE_END;
+ }
+ cmd[0] = CMD_ANC_MODULE;
+ chargestore_api_write(cmd, 2);
+ }
+ break;
+ case FILE_ID_GAIN:
+ if (__this->file_hdl == NULL) {
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ } else {
+ anc_cfg_online_deal(ANC_CFG_WRITE, &__this->gain);
+ free(__this->data_ptr);
+ __this->file_hdl = NULL;
+ __this->data_ptr = NULL;
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_WRITE_FILE_END;
+ chargestore_api_write(cmd, 2);
+ }
+ break;
+ }
+}
+
+#if ANCTOOL_NEED_PAIR_KEY
+static void anc_ack_pair_key(u8 *key)
+{
+ u8 cmd[2];
+ if (strcmp(ANCTOOL_PAIR_KEY, (const char *)key) == 0) {
+ __this->pair_flag = 1;
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_PAIR_KEY;
+ chargestore_api_write(cmd, 2);
+ } else {
+ __this->pair_flag = 0;
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ }
+}
+#endif
+
+static void anc_ack_spk_eq(u8 seq, u8 *packet, u8 len)
+{
+ u8 cmd[32];
+ if (len > 30) {
+ log_error("anc_ack_spk_eq packet len err! %d\n", len);
+ return;
+ }
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_NEW_EQ_DATA;
+ memcpy(cmd + 2, packet, len);
+ chargestore_api_write(cmd, len + 2);
+}
+
+int app_ancbox_event_handler(struct ancbox_event *anc_dev)
+{
+ u8 cmd[32], mac_addr[6];
+ u32 data_len;
+ u32 anc_coeff_total_size;
+ int ret;
+ struct application *app = get_current_app();
+
+ if (!get_total_connect_dev()) { //已经连接手机
+ void sys_auto_shut_down_disable(void);
+ void sys_auto_shut_down_enable(void);
+ sys_auto_shut_down_disable();
+ sys_auto_shut_down_enable();
+ }
+
+ switch (anc_dev->event) {
+ case CMD_ANC_MUTE_TRAIN_ONLY://独立的训练模式
+ log_info("event_CMD_ANC_MUTE_TRAIN_ONLY\n");
+ if (__this->status != CMD_ANC_MUTE_TRAIN_ONLY) {
+ __this->status = CMD_ANC_MUTE_TRAIN_ONLY;
+ __this->err_flag = 0;
+ sys_auto_shut_down_disable();
+ anc_cmd_timeout_del();
+ anc_train_api_set(ANC_MUTE_TARIN, 1, __this->para);
+ }
+ break;
+
+ case CMD_ANC_TRANS_TRAIN://独立的训练模式
+ log_info("event_CMD_ANC_TRANS_TRAIN\n");
+ if (__this->status != CMD_ANC_TRANS_TRAIN) {
+ __this->status = CMD_ANC_TRANS_TRAIN;
+ __this->err_flag = 0;
+ sys_auto_shut_down_disable();
+ anc_cmd_timeout_del();
+ anc_train_api_set(ANC_TRANS_MUTE_TARIN, 1, __this->para);
+ }
+ break;
+
+ case CMD_ANC_CREATE_SPK_MIC:
+ log_info("event_CMD_ANC_CREATE_SPK_MIC: %d\n", anc_dev->value);
+ if (__this->status != CMD_ANC_CREATE_SPK_MIC) {
+ __this->status = CMD_ANC_CREATE_SPK_MIC;
+ __this->err_flag = 0;
+ anc_train_api_set(ANC_MUTE_TARIN, anc_dev->value, __this->para);
+ sys_auto_shut_down_disable();
+ anc_cmd_timeout_del();
+ }
+ break;
+
+ case CMD_ANC_SET_START:
+ log_info("event_CMD_ANC_SET_STAR\n");
+ __this->test_flag = 1;
+ __this->status = CMD_ANC_SET_START;
+ __this->err_flag = 0;
+ sys_auto_shut_down_disable();
+ anc_cmd_timeout_del();
+ memset(anc_pow, 0, ANC_POW_SIZE);
+ break;
+ case CMD_ANC_MUTE_TRAIN:
+ log_info("event_CMD_ANC_MUTE_TRAIN\n");
+ if (__this->status != CMD_ANC_MUTE_TRAIN) {
+ __this->status = CMD_ANC_MUTE_TRAIN;
+ anc_train_api_set(ANC_MUTE_TARIN, 0, __this->para);
+ }
+ break;
+ case CMD_ANC_SIN_TRAIN:
+ log_info("event_CMD_ANC_SIN_TRAIN\n");
+ if (__this->status != CMD_ANC_SIN_TRAIN) {
+ __this->status = CMD_ANC_SIN_TRAIN;
+ anc_train_api_set(ANC_TRAIN_STEP_1, 0, __this->para);
+ }
+ break;
+ case CMD_ANC_NOISE_TRAIN:
+ log_info("event_CMD_ANC_TRAIN_SPK_ON\n");
+ if (__this->status != CMD_ANC_NOISE_TRAIN) {
+ __this->status = CMD_ANC_NOISE_TRAIN;
+ anc_train_api_set(ANC_NOISE_TARIN, 0, __this->para);
+ }
+ break;
+ case CMD_ANC_TEST_ANC_ON:
+ log_info("event_CMD_ANC_TEST_ANC_ON\n");
+ if (__this->test_flag == 1) {
+ __this->status = CMD_ANC_TEST_ANC_ON;
+ anc_train_api_set(ANC_MODE_ON, 0, __this->para);
+ } else {
+ log_info("switch to ancon!\n");
+ anc_api_set_fade_en(0);
+ anc_mode_switch(ANC_ON, 0);
+ }
+ break;
+ case CMD_ANC_TEST_ANC_OFF:
+ log_info("event_CMD_ANC_TEST_ANC_OFF\n");
+ if (__this->test_flag == 1) {
+ __this->status = CMD_ANC_TEST_ANC_OFF;
+ anc_train_api_set(ANC_MODE_OFF, 0, __this->para);
+ } else {
+ log_info("switch to ancoff!\n");
+ anc_api_set_fade_en(0);
+ anc_mode_switch(ANC_OFF, 0);
+ }
+ break;
+ case CMD_ANC_TEST_PASS:
+ log_info("event_CMD_ANC_TEST_PASS\n");
+ if (__this->test_flag == 1) {
+ __this->status = CMD_ANC_TEST_PASS;
+ anc_train_api_set(ANC_PASS_MODE_ON, 0, __this->para);
+ } else {
+ log_info("switch to pass!\n");
+ anc_api_set_fade_en(0);
+ anc_mode_switch(ANC_TRANSPARENCY, 0);
+ }
+ break;
+ case CMD_ANC_SET_STOP:
+ log_info("event_CMD_ANC_SET_STOP\n");
+ __this->status = CMD_ANC_SET_STOP;
+ __this->err_flag = 0;
+ if (__this->test_flag) {
+ __this->test_flag = 0;
+ anc_train_api_set(ANC_TRAIN_EXIT, 0, __this->para);
+ sys_auto_shut_down_enable();
+ }
+ break;
+ case CMD_ANC_SYS_RESET:
+ log_info("event_CMD_ANC_SYS_RESET\n");
+ os_time_dly(3);
+ cpu_reset();
+ break;
+ case CMD_ANC_SET_RUN_MODE:
+ log_info("event_CMD_ANC_SET_RUN_MODE = %d\n", anc_dev->value);
+ anc_api_set_fade_en(0);
+ if (anc_dev->value == 0) {
+ anc_mode_switch(ANC_OFF, 0);
+ } else if (anc_dev->value == 1) {
+ anc_mode_switch(ANC_ON, 0);
+ } else {
+ anc_mode_switch(ANC_TRANSPARENCY, 0);
+ }
+ break;
+ case CMD_ANC_TEST_BYPASS:
+ log_info("event_CMD_ANC_TEST_BYPASS\n");
+ anc_mode_switch(ANC_BYPASS, 0);
+ //bypass,此处调用底层接口根据anc_dev->value需要切换到那个mic的bypass
+ break;
+ case CMD_ANC_CHANGE_MODE:
+ log_info("event_CMD_ANC_CHANGE_MODE = %d\n", anc_dev->value);
+ anc_mode_change_tool(anc_dev->value);
+ //切换FF/FB,此处调用底层接口根据anc_dev->value需要切换到FF/FB
+ break;
+ case CMD_ANC_STATUS:
+ case CMD_ANC_TOOLS_SYNC:
+ putchar('S');
+#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+ /*关闭所有模块*/
+ if (audio_icsd_adt_is_running()) {
+ audio_icsd_adt_close_all();
+ }
+#endif
+#if TCFG_AUDIO_ANC_EAR_ADAPTIVE_EN
+ //自适应还原为默认参数
+ if (audio_anc_coeff_mode_get() == ANC_COEFF_MODE_ADAPTIVE) {
+ audio_anc_coeff_adaptive_set(ANC_COEFF_MODE_NORMAL, 0, 0);
+ }
+#endif
+#if TCFG_CHARGESTORE_PORT == LDOIN_BIND_IO
+ if (app && strcmp(app->name, APP_NAME_IDLE)) {
+ os_time_dly(1);
+ log_info("not idle app, reset sys!\n");
+ cpu_reset();
+ } else {
+ __this->idle_flag = 1;
+ }
+#endif
+ anc_cmd_timeout_init();
+ if (__this->para == NULL) {
+ __this->para = anc_api_get_train_param();
+ anc_api_set_callback(ancbox_callback, ancbox_pow_callback);
+ }
+ break;
+ case CMD_ANC_SET_LINKKEY:
+ log_info("CMD_ANC_SET_LINKKEY\n");
+ if (app && strcmp(app->name, APP_NAME_BT)) {
+ power_set_mode(TCFG_LOWPOWER_POWER_SEL);
+ app_var.play_poweron_tone = 0;
+ task_switch_to_bt();
+ anc_cmd_timeout_del();
+ }
+ break;
+ case CMD_ANC_SW_TO_BT:
+ log_info("CMD_ANC_SW_TO_BT\n");
+ bt_get_vm_mac_addr(mac_addr);
+ bt_update_mac_addr(mac_addr);
+ if (app && strcmp(app->name, APP_NAME_BT)) {
+ power_set_mode(TCFG_LOWPOWER_POWER_SEL);
+ app_var.play_poweron_tone = 0;
+ task_switch_to_bt();
+ anc_cmd_timeout_del();
+ } else {
+#if TCFG_CHARGESTORE_PORT != LDOIN_BIND_IO
+ anc_cmd_timeout_del();
+ //关闭回连
+ EARPHONE_STATE_SET_PAGE_SCAN_ENABLE();
+ user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_ENABLE, 0, NULL);
+ user_send_cmd_prepare(USER_CTRL_WRITE_CONN_ENABLE, 0, NULL);
+#endif
+ }
+ break;
+ case CMD_ANC_READ_COEFF://read start
+ log_info("CMD_ANC_READ_COEFF\n");
+ __this->coeff = (u8 *)anc_coeff_read();
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_READ_COEFF;
+ if (__this->coeff == NULL) {
+ data_len = 0;
+ } else {
+#if (ANC_CHIP_VERSION == ANC_VERSION_BR36) || (ANC_CHIP_VERSION == ANC_VERSION_BR28)
+ anc_coeff_total_size = anc_coeff_size_get(ANC_CFG_READ);
+#else
+ anc_coeff_total_size = anc_coeff_size_get();
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR36*/
+ data_len = anc_coeff_total_size;
+ }
+ __this->coeff_ptr = 0;
+ memcpy(&cmd[2], (u8 *)&data_len, 4);
+ chargestore_api_write(cmd, 6);
+ anc_cmd_timeout_del();
+ break;
+ case CMD_ANC_WRITE_COEFF://write start
+ log_info("CMD_ANC_WRITE_COEFF\n");
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_WRITE_COEFF;
+ __this->coeff_ptr = 0;
+ if (__this->coeff == NULL) {
+ __this->coeff = (u8 *)malloc(__this->coeff_len);
+ if (__this->coeff == NULL) {
+ cmd[1] = CMD_ANC_FAIL;
+ }
+ }
+ chargestore_api_write(cmd, 2);
+ anc_cmd_timeout_del();
+ break;
+ case CMD_ANC_WRITE_COEFF_CONTINUE:
+ log_info("CMD_ANC_WRITE_COEFF_CONTINUE\n");
+ if (__this->coeff) {
+ anc_cmd_timeout_del();
+ anc_coeff_write((int *)__this->coeff, __this->coeff_len);
+ free(__this->coeff);
+ __this->coeff = NULL;
+ __this->coeff_ptr = 0;
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_WRITE_COEFF_CONTINUE;
+ chargestore_api_write(cmd, 2);
+ }
+ log_info("CMD_ANC_WRITE_COEFF_CONTINUE--------end\n");
+ break;
+ case CMD_ANC_READ_FILE_START:
+ anc_read_file_start(cmd, __this->file_id);
+ break;
+ case CMD_ANC_READ_FILE_DATA:
+ anc_read_file_data(cmd, __this->data_offset, __this->data_len);
+ break;
+ case CMD_ANC_WRITE_FILE_START:
+ anc_write_file_start(cmd, __this->file_id, __this->file_len);
+ break;
+ case CMD_ANC_WRITE_FILE_DATA:
+ anc_write_file_data(cmd, __this->data_offset, __this->data_ptr, __this->data_len);
+ break;
+ case CMD_ANC_WRITE_FILE_END:
+ anc_write_file_end(cmd);
+ break;
+ case CMD_ANC_SET_GAIN:
+ log_info("CMD_ANC_SET_GAIN\n");
+ anc_cmd_timeout_del();
+ anc_cfg_online_deal(ANC_CFG_WRITE, &__this->gain);
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_SET_GAIN;
+ chargestore_api_write(cmd, 2);
+ break;
+ case CMD_ANC_GET_GAIN:
+ log_info("CMD_ANC_GET_GAIN\n");
+ anc_cfg_online_deal(ANC_CFG_READ, &__this->gain);
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_GET_GAIN;
+ memcpy(&cmd[2], (u8 *)&__this->gain, sizeof(anc_gain_t));
+ chargestore_api_write(cmd, 2 + sizeof(anc_gain_t));
+ break;
+ case CMD_ANC_CHANGE_BAUD:
+ log_info("CMD_ANC_CHANGE_BAUD: %d\n", anc_dev->value);
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_CHANGE_BAUD;
+ chargestore_api_write(cmd, 2);
+ chargestore_api_wait_complete();
+ chargestore_set_baudrate(anc_dev->value);
+ if (__this->baud_timer) {
+ sys_timeout_del(__this->baud_timer);
+ __this->baud_timer = 0;
+ }
+ if (anc_dev->value != DEFAULT_BAUDRATE) {
+ __this->baud_timer = sys_timer_add(NULL, anc_baud_timer_deal, 100);
+ __this->baud_counter = 0;
+ }
+ break;
+ case CMD_ANC_WZ_BREAK:
+ log_info("CMD_ANC_WZ_BREAK: %d s\n", anc_dev->value);
+ sys_timeout_add(NULL, anc_wz_timeout_deal, anc_dev->value * 1000);
+ break;
+ case CMD_ANC_SET_ID:
+ log_info("CMD_ANC_SET_ID: %d ,%d\n", __this->type_id, __this->type_value);
+ anc_cmd_timeout_del();
+ anc_cfg_btspp_update((u8)__this->type_id, (int)__this->type_value);
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_SET_ID;
+ chargestore_api_write(cmd, 2);
+ break;
+ case CMD_ANC_GET_ID:
+ log_info("CMD_ANC_GET_ID: %d\n", __this->type_id);
+ if (anc_cfg_btspp_read((u8)__this->type_id, (int *)&__this->type_value) == 0) {
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_GET_ID;
+ memcpy(&cmd[2], (u8 *)&__this->type_value, 4);
+ chargestore_api_write(cmd, 6);
+ } else {
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ }
+ break;
+#if AUDIO_SPK_EQ_CONFIG
+ case CMD_ANC_EQ_DATA:
+ log_info("CMD_ANC_EQ_DATA\n");
+ log_info_hexdump(eq_buffer, eq_len);
+ ret = spk_eq_spp_rx_packet(eq_buffer, eq_len);
+ if (ret == -1) {
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ } else {
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_EQ_DATA;
+ chargestore_api_write(cmd, 2);
+ }
+ break;
+ case CMD_ANC_NEW_EQ_DATA:
+ log_info("CMD_ANC_EQ_DATA\n");
+ log_info_hexdump(eq_buffer, eq_len);
+ spk_eq_set_send_data_handler(anc_ack_spk_eq);
+ spk_eq_app_online_parse(eq_buffer, eq_len, NULL, 0);
+ spk_eq_set_send_data_handler(NULL);
+ break;
+#endif
+#if TCFG_AUDIO_CVP_DUT_ENABLE
+ case CMD_ANC_CVP_DUT_DATA:
+ log_info("CMD_ANC_CVP_DUT_DATA\n");
+ log_info_hexdump(cvp_dut_buffer, cvp_dut_len);
+ ret = cvp_dut_new_rx_packet(cvp_dut_buffer, cvp_dut_len);
+ if (ret) {
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_FAIL;
+ chargestore_api_write(cmd, 2);
+ } else {
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_CVP_DUT_DATA;
+ chargestore_api_write(cmd, 2);
+ }
+ free(cvp_dut_buffer);
+ break;
+#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
+ case CMD_ANC_SET_MUSIC_VOL:
+ log_info("CMD_ANC_SET_MUSIC_VOL: %d\n", anc_dev->value);
+ app_audio_set_volume(APP_AUDIO_STATE_MUSIC, (anc_dev->value * get_max_sys_vol()) / 0x64, 0);
+ break;
+#if TCFG_ANC_SELF_DUT_GET_SZ
+ case CMD_ANC_SZ_FFT_STOP:
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_SZ_FFT_STOP;
+ audio_anc_sz_fft_stop(NULL); //SZ_FFT 停止计算
+ anc_train_close(); //关闭ANC,模式设置为ANC_OFF
+ __this->fft_file_busy = 0;
+ /* chargestore_api_write(cmd, 2); */
+ break;
+#endif/*TCFG_ANC_SELF_DUT_GET_SZ*/
+
+#if AUDIO_ENC_MPT_SELF_ENABLE
+ case CMD_ANC_MIC_FFT_START:
+ __this->fft_file_busy = 1;
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_MIC_FFT_START;
+ chargestore_api_write(cmd, 2); //先回复,再执行
+ audio_enc_mpt_fre_response_open(__this->audio_enc_mpt_fre_ch);
+ break;
+ case CMD_ANC_MIC_FFT_STOP:
+ cmd[0] = CMD_ANC_MODULE;
+ cmd[1] = CMD_ANC_MIC_FFT_STOP;
+ audio_enc_mpt_fre_response_close();
+ __this->fft_file_busy = 0;
+ break;
+#endif/*AUDIO_ENC_MPT_SELF_ENABLE*/
+ }
+ return false;
+}
+
+static int app_ancbox_module_deal(u8 *buf, u8 len)
+{
+ if (buf[0] != CMD_ANC_MODULE) {
+ //不是ANC测试指令
+ return 0;
+ }
+
+ u8 cmd, i, j;
+ u8 sendbuf[32];
+ u32 read_len;
+ u32 baudrate;
+ u32 anc_coeff_total_size;
+ u32 value;
+ struct _ear_parm parm;
+ sendbuf[0] = CMD_ANC_MODULE;
+ sendbuf[1] = buf[1];
+ __this->ancbox_status = 1;
+ __this->baud_counter = 0;
+ anc_online_busy_set(1);
+
+ if (buf[1] != 129) {
+ printf("cmd = 0x%x\n", buf[1]);
+ }
+
+ cmd = buf[1];
+ switch (buf[1]) {
+ case CMD_ANC_SET_PARM:
+ memcpy((u8 *)&parm, &buf[2], sizeof(struct _ear_parm));
+ chargestore_api_write(sendbuf, 2);
+ if (parm.mode == 0) {
+ anc_train_api_set(ANC_CHANGE_COMMAND, ANC_TRAIN_NOMA_MODE, __this->para);
+ } else {
+ anc_train_api_set(ANC_CHANGE_COMMAND, parm.mode, __this->para);
+ }
+ anc_train_api_set(ANC_SZ_LOW_THR_SET, parm.emmtv, __this->para);
+ anc_train_api_set(ANC_FZ_LOW_THR_SET, parm.rmmtv, __this->para);
+ anc_train_api_set(ANC_NONADAP_TIME_SET, parm.sdt, __this->para);
+ anc_train_api_set(ANC_SZ_ADAP_TIME_SET, parm.emstt, __this->para);
+ anc_train_api_set(ANC_FZ_ADAP_TIME_SET, parm.rmstt, __this->para);
+ anc_train_api_set(ANC_WZ_TRAIN_TIME_SET, parm.ntt, __this->para);
+ anc_train_api_set(ANC_TRAIN_STEP_SET, parm.ts, __this->para);
+ if (parm.gen) {
+#if (ANC_CHIP_VERSION != ANC_VERSION_BR36) && (ANC_CHIP_VERSION != ANC_VERSION_BR28)
+ anc_param_fill(ANC_CFG_READ, &__this->gain);
+ __this->gain.dac_gain = (u8)parm.gdac;
+ __this->gain.ref_mic_gain = (u8)parm.grmic;
+ __this->gain.err_mic_gain = (u8)parm.gemic;
+ __this->gain.anc_gain = (int)parm.ganc;
+ __this->gain.transparency_gain = (int)parm.gpass;
+ anc_param_fill(ANC_CFG_WRITE, &__this->gain);
+#endif
+ }
+ return 1;
+ case CMD_ANC_SET_START:
+ case CMD_ANC_SET_STOP:
+ case CMD_ANC_MUTE_TRAIN:
+ case CMD_ANC_MUTE_TRAIN_ONLY:
+ case CMD_ANC_SIN_TRAIN:
+ case CMD_ANC_NOISE_TRAIN:
+ case CMD_ANC_TEST_ANC_ON:
+ case CMD_ANC_TEST_ANC_OFF:
+ case CMD_ANC_TEST_PASS:
+ case CMD_ANC_SYS_RESET:
+ chargestore_api_write(sendbuf, 2);
+ break;
+ case CMD_ANC_TRANS_TRAIN:
+ if (len > 2) {
+ memcpy((u8 *)&value, &buf[2], 4);
+ anc_api_set_trans_aim_pow(value);
+ }
+ chargestore_api_write(sendbuf, 2);
+ break;
+
+ case CMD_ANC_SET_RUN_MODE:
+ case CMD_ANC_TEST_BYPASS:
+ case CMD_ANC_CHANGE_MODE:
+ case CMD_ANC_CREATE_SPK_MIC:
+ anc_event_to_user(cmd, (u32)buf[2]);
+ chargestore_api_write(sendbuf, 2);
+ return 1;
+ case CMD_ANC_STATUS:
+ case CMD_ANC_TOOLS_SYNC:
+ //在idle
+#if TCFG_CHARGESTORE_PORT == LDOIN_BIND_IO
+ if (__this->idle_flag == 0) {
+ sendbuf[1] = CMD_ANC_FAIL;
+ chargestore_api_write(sendbuf, 2);
+ } else
+#endif
+ {
+ sendbuf[2] = ANC_VERSION;//版本
+ sendbuf[3] = ANC_TRAIN_MODE;//结构
+#if ANC_MULT_ORDER_ENABLE
+ sendbuf[4] = ANC_CHIP_VERSION | 0XA0; //芯片版本
+#else
+ sendbuf[4] = ANC_CHIP_VERSION;
+#endif
+ chargestore_api_write(sendbuf, 5);
+ }
+ break;
+ case CMD_ANC_GET_MAC:
+ bt_get_vm_mac_addr(&sendbuf[2]);
+ chargestore_api_write(sendbuf, 8);
+ return 1;
+ case CMD_ANC_SET_LINKKEY:
+ bt_update_mac_addr(&buf[2]);
+ set_temp_link_key(&buf[8]);
+ chargestore_api_write(sendbuf, 2);
+ break;
+ case CMD_ANC_SW_TO_BT:
+ chargestore_api_write(sendbuf, 2);
+ break;
+ case CMD_ANC_READ_COEFF://read start
+#if ANCTOOL_NEED_PAIR_KEY
+ if (!__this->pair_flag) {
+ sendbuf[1] = CMD_ANC_FAIL;
+ chargestore_api_write(sendbuf, 2);
+ return 1;
+ }
+#endif
+ chargestore_api_set_timeout(50);
+ break;
+ case CMD_ANC_READ_COEFF_CONTINUE:
+#if ANCTOOL_NEED_PAIR_KEY
+ if (!__this->pair_flag) {
+ sendbuf[1] = CMD_ANC_FAIL;
+ chargestore_api_write(sendbuf, 2);
+ return 1;
+ }
+#endif
+ if (__this->coeff == NULL) {
+ sendbuf[1] = CMD_ANC_FAIL;
+ chargestore_api_write(sendbuf, 2);
+ } else {
+#if (ANC_CHIP_VERSION == ANC_VERSION_BR36) || (ANC_CHIP_VERSION == ANC_VERSION_BR28)
+ anc_coeff_total_size = anc_coeff_size_get(ANC_CFG_READ);
+#else
+ anc_coeff_total_size = anc_coeff_size_get();
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR36*/
+ read_len = anc_coeff_total_size - __this->coeff_ptr;
+ if (read_len > 30) {
+ read_len = 30;
+ }
+ memcpy(&sendbuf[2], __this->coeff + __this->coeff_ptr, read_len);
+ chargestore_api_write(sendbuf, read_len + 2);
+ __this->coeff_ptr += read_len;
+ if (anc_coeff_total_size == __this->coeff_ptr) {
+ __this->coeff = NULL;
+ __this->coeff_ptr = 0;
+ }
+ }
+ //读操作不需要推消息处理
+ return 1;
+ case CMD_ANC_WRITE_COEFF://write start
+ chargestore_api_set_timeout(50);
+ memcpy((u8 *)&read_len, buf + 2, 4);
+ __this->coeff_len = read_len;
+#if (ANC_CHIP_VERSION == ANC_VERSION_BR36) || (ANC_CHIP_VERSION == ANC_VERSION_BR28)
+ anc_coeff_size_set(ANC_CFG_WRITE, read_len);
+ anc_coeff_total_size = read_len;
+#else
+ anc_coeff_total_size = anc_coeff_size_get();
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR36*/
+ if (read_len != anc_coeff_total_size) {
+ sendbuf[1] = CMD_ANC_FAIL;
+ chargestore_api_write(sendbuf, 2);
+ log_info("anc coeff size err, %d != %d\n", read_len, anc_coeff_total_size);
+ return 1;
+ }
+ break;
+ case CMD_ANC_WRITE_COEFF_CONTINUE:
+ memcpy(__this->coeff + __this->coeff_ptr, buf + 2, len - 2);
+ __this->coeff_ptr += (len - 2);
+ if (__this->coeff_ptr < __this->coeff_len) {
+ //未写完成时不推消息
+ chargestore_api_write(sendbuf, 2);
+ return 1;
+ }
+ chargestore_api_set_timeout(1000);
+ break;
+ case CMD_ANC_READ_FILE_START:
+ memcpy((u8 *)&__this->file_id, buf + 2, 4);
+ chargestore_api_set_timeout(1000);
+ break;
+ case CMD_ANC_READ_FILE_DATA:
+ memcpy((u8 *)&__this->data_offset, buf + 2, 4);
+ memcpy((u8 *)&__this->data_len, buf + 6, 4);
+ chargestore_api_set_timeout(1000);
+ break;
+ case CMD_ANC_WRITE_FILE_START:
+ memcpy((u8 *)&__this->file_id, buf + 2, 4);
+ memcpy((u8 *)&__this->file_len, buf + 6, 4);
+ chargestore_api_set_timeout(1000);
+ break;
+ case CMD_ANC_WRITE_FILE_DATA:
+ memcpy((u8 *)&__this->data_offset, buf + 2, 4);
+ memcpy(__this->data_ptr, buf + 6, len - 6);
+ __this->data_len = len - 6;
+ printf("write file data, offset:%d, datalen: %d\n", __this->data_offset, __this->data_len);
+ chargestore_api_set_timeout(1000);
+ break;
+ case CMD_ANC_WRITE_FILE_END:
+ chargestore_api_set_timeout(1000);
+ break;
+ case CMD_ANC_GET_RESULT:
+ sendbuf[2] = __this->err_flag;
+ sendbuf[3] = anc_api_get_train_step();
+ chargestore_api_write(sendbuf, 4);
+ return 1;//不需要app处理
+ case CMD_ANC_SET_GAIN:
+ if ((len - 2) != sizeof(anc_gain_t)) {
+ sendbuf[1] = CMD_ANC_FAIL;
+ chargestore_api_write(sendbuf, 2);
+ return 1;
+ } else {
+ memcpy((u8 *)&__this->gain, &buf[2], sizeof(anc_gain_t));
+ chargestore_api_set_timeout(1000);
+ }
+ break;
+ case CMD_ANC_GET_GAIN:
+ chargestore_api_set_timeout(50);
+ break;
+ case CMD_ANC_CHANGE_BAUD:
+ chargestore_api_set_timeout(50);
+ memcpy((u8 *)&baudrate, &buf[2], 4);
+ anc_event_to_user(cmd, baudrate);
+ return 1;
+ case CMD_ANC_DEVELOPER_MODE:
+ anc_train_api_set(ANC_DEVELOPER_MODE, (u32)buf[2], __this->para);
+ chargestore_api_write(sendbuf, 2);
+ return 1;
+ case CMD_ANC_ADAP:
+ if (buf[2] == 0) {
+ anc_train_api_set(ANC_TEST_NADAP, 0, __this->para);
+ } else {
+ anc_train_api_set(ANC_TEST_ADAP, 0, __this->para);
+ }
+ chargestore_api_write(sendbuf, 2);
+ return 1;
+ case CMD_ANC_WZ_BREAK:
+ anc_event_to_user(cmd, (u32)buf[2]);
+ chargestore_api_write(sendbuf, 2);
+ return 1;
+ case CMD_ANC_SET_TS:
+ anc_train_api_set(ANC_TRAIN_STEP_SET, (u32)buf[2], __this->para);
+ chargestore_api_write(sendbuf, 2);
+ return 1;
+ case CMD_ANC_TRAIN_STEP:
+ __this->train_step_succ = 0;
+ anc_train_api_set(ANC_TRAIN_STEP_1, 0, __this->para);
+ chargestore_api_write(sendbuf, 2);
+ return 1;
+ case CMD_ANC_GET_TRAIN_STEP:
+ sendbuf[2] = 0;
+ if (__this->train_step_succ) {
+ sendbuf[2] = anc_api_get_train_step();
+ } else {
+ anc_train_api_set(ANC_TRAIN_STEP_CONNUTE, 0, __this->para);
+ }
+ chargestore_api_write(sendbuf, 3);
+ return 1;
+ case CMD_ANC_GET_MUTE_TRAIN_POW:
+ sendbuf[2] = __this->sz_nadap_pow;
+ sendbuf[3] = __this->sz_adap_pow;
+ sendbuf[4] = __this->sz_mute_pow;
+ sendbuf[5] = __this->fz_nadap_pow;
+ sendbuf[6] = __this->fz_adap_pow;
+ sendbuf[7] = __this->fz_mute_pow;
+ chargestore_api_write(sendbuf, 8);
+ return 1;
+ case CMD_ANC_GET_NOISE_TRAIN_POW:
+ sendbuf[2] = __this->wz_nadap_pow;
+ sendbuf[3] = __this->wz_adap_pow;
+ chargestore_api_write(sendbuf, 4);
+ return 1;
+ case CMD_ANC_GET_TRAIN_POW:
+ for (i = (ANC_POW_SIZE / 3), j = 2; i < (ANC_POW_SIZE * 2 / 3); i++, j++) {
+ sendbuf[j] = anc_pow[i];
+ }
+ chargestore_api_write(sendbuf, j);
+ return 1;
+ case CMD_ANC_SET_ID:
+ memcpy((u8 *)&__this->type_id, &buf[2], 4);
+ memcpy((u8 *)&__this->type_value, &buf[6], 4);
+ chargestore_api_set_timeout(250);
+ break;
+ case CMD_ANC_GET_ID:
+ memcpy((u8 *)&__this->type_id, &buf[2], 4);
+ chargestore_api_set_timeout(250);
+ break;
+ case CMD_ANC_GET_COEFF_SIZE:
+#if (ANC_CHIP_VERSION == ANC_VERSION_BR36) || (ANC_CHIP_VERSION == ANC_VERSION_BR28)
+ anc_coeff_total_size = anc_coeff_size_get(ANC_CFG_READ);
+#else
+ anc_coeff_total_size = anc_coeff_size_get();
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR36*/
+ read_len = anc_coeff_total_size;
+ memcpy(&sendbuf[2], (u8 *)&read_len, 4);
+ chargestore_api_write(sendbuf, 6);
+ return 1;
+ case CMD_ANC_GET_VERSION:
+#if ANC_MULT_ORDER_ENABLE
+ sendbuf[2] = ANC_CHIP_VERSION | 0XA0;
+#else
+ sendbuf[2] = ANC_CHIP_VERSION;
+#endif
+ chargestore_api_write(sendbuf, 3);
+ return 1;
+#if (ANC_CHIP_VERSION == ANC_VERSION_BR36) || (ANC_CHIP_VERSION == ANC_VERSION_BR28)
+ case CMD_ANC_GET_ANC_CH:
+ sendbuf[2] = ANC_CH;
+ chargestore_api_write(sendbuf, 3);
+ return 1;
+ case CMD_ANC_GET_MAX_ORDER:
+#if ANC_CHIP_VERSION == ANC_VERSION_BR28
+ sendbuf[2] = 20;
+#else
+ sendbuf[2] = ANC_MAX_ORDER;
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR28*/
+ chargestore_api_write(sendbuf, 3);
+ return 1;
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR36*/
+#if ANCTOOL_NEED_PAIR_KEY
+ case CMD_ANC_PAIR_KEY:
+ buf[len] = '\0';
+ log_info("CMD_ANC_PAIR_KEY: %s\n", (buf + 2));
+ anc_ack_pair_key(buf + 2);
+ return 1;
+ case CMD_ANC_PAIR_SUCC:
+ __this->pair_flag = 1;
+ chargestore_api_write(sendbuf, 2);
+ return 1;
+#endif
+
+ case CMD_ANC_EQ_DATA:
+ eq_len = len - 2;
+ memcpy(eq_buffer, buf + 2, eq_len);
+ chargestore_api_set_timeout(100);
+ break;
+ case CMD_ANC_NEW_EQ_DATA:
+ eq_len = len - 2;
+ memcpy(eq_buffer, buf + 2, eq_len);
+ chargestore_api_set_timeout(50);
+ break;
+#if TCFG_AUDIO_CVP_DUT_ENABLE
+ case CMD_ANC_CVP_DUT_DATA:
+ cvp_dut_len = len - 2;
+ cvp_dut_buffer = malloc(cvp_dut_len);
+ memcpy(cvp_dut_buffer, buf + 2, cvp_dut_len);
+ chargestore_api_set_timeout(50);
+ break;
+#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
+
+#if TCFG_ANC_SELF_DUT_GET_SZ
+ case CMD_ANC_SZ_FFT_START:
+ __this->fft_file_busy = 1;
+ void audio_anc_post_msg_sz_fft_open(u8 sel);
+ audio_anc_post_msg_sz_fft_open(buf[2]);
+ chargestore_api_write(sendbuf, 2);
+ return 1;
+ case CMD_ANC_SZ_FFT_STOP:
+ chargestore_api_set_timeout(50); //透传命令固定50*2 ms验证
+ chargestore_api_write(sendbuf, 2);
+ break;
+ /* chargestore_api_write(sendbuf, 2); */
+ /* return 1; */
+#endif/*TCFG_ANC_SELF_DUT_GET_SZ*/
+
+ case CMD_ANC_SET_MUSIC_VOL:
+ anc_event_to_user(cmd, (u32)buf[2]);
+ chargestore_api_write(sendbuf, 2);
+ return 1;
+
+#if AUDIO_ENC_MPT_SELF_ENABLE
+ case CMD_ANC_MIC_FFT_START:
+ __this->audio_enc_mpt_fre_ch = buf[2];
+ chargestore_api_set_timeout(50); //透传命令固定50*2 ms验证
+ break;
+ case CMD_ANC_MIC_FFT_STOP:
+ chargestore_api_set_timeout(50); //透传命令固定50*2 ms验证
+ chargestore_api_write(sendbuf, 2);
+ break;
+#endif/*AUDIO_ENC_MPT_SELF_ENABLE*/
+
+#if ANC_MULT_ORDER_ENABLE
+ case CMD_MUTL_SCENE_SET:
+ audio_anc_mult_scene_set(buf[2], 1);
+ chargestore_api_write(sendbuf, 2);
+ return 1;
+#endif/*ANC_MULT_ORDER_ENABLE*/
+ case CMD_FFT_FILE_BUSY_GET:
+ sendbuf[2] = __this->fft_file_busy;
+ chargestore_api_write(sendbuf, 3);
+ return 1;
+
+ default:
+ sendbuf[1] = CMD_ANC_FAIL;
+ chargestore_api_write(sendbuf, 2);
+ return 1;
+ }
+ anc_event_to_user(cmd, 0);
+ return 1;
+}
+
+u8 ancbox_get_status(void)
+{
+ return __this->ancbox_status;
+}
+
+void ancbox_clear_status(void)
+{
+ __this->ancbox_status = 0;
+}
+
+CHARGESTORE_HANDLE_REG(ancbox, app_ancbox_module_deal);
+
+#endif
+
+
diff --git a/apps/earphone/app_anctool.c b/apps/earphone/app_anctool.c
new file mode 100644
index 0000000..0a538c6
--- /dev/null
+++ b/apps/earphone/app_anctool.c
@@ -0,0 +1,1023 @@
+#include "init.h"
+#include "app_config.h"
+#include "system/includes.h"
+
+#if (TCFG_ANC_TOOL_DEBUG_ONLINE && TCFG_AUDIO_ANC_ENABLE)
+
+#ifdef SUPPORT_MS_EXTENSIONS
+#pragma bss_seg(".anc_box_bss")
+#pragma data_seg(".anc_box_data")
+#pragma const_seg(".anc_box_const")
+#pragma code_seg(".anc_box_code")
+#endif/*SUPPORT_MS_EXTENSIONS*/
+
+#include "btstack/avctp_user.h"
+#include "classic/hci_lmp.h"
+#include "app_anctool.h"
+#include "audio_anc.h"
+#include "user_cfg.h"
+#include "app_action.h"
+#include "app_main.h"
+#include "user_cfg.h"
+#include "bt_tws.h"
+
+#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+#include "icsd_adt_app.h"
+#endif
+
+#define anctool_printf log_i
+#define anctool_put_buf put_buf
+
+#if (ANC_CHIP_VERSION == ANC_VERSION_BR36) || (ANC_CHIP_VERSION == ANC_VERSION_BR28)
+#define CONFIG_VERSION "V2.1.1"
+#else
+#define CONFIG_VERSION "V2.1.0"
+#endif
+
+extern void anc_cfg_btspp_update(u8 id, int data);
+extern int anc_cfg_btspp_read(u8 id, int *data);
+extern int anc_mode_change_tool(u8 dat);
+
+enum {
+ FILE_ID_COEFF = 0, //系数文件ID号
+ FILE_ID_MIC_SPK = 1,//mic spk文件ID号
+ FILE_ID_GAIN = 2, //增益ID
+ FILE_ID_ADAPTIVE = 3, //自适应模式文件ID
+ FILE_ID_ADAPTIVE_REF = 4, //自适应模式金机曲线ID
+ FILE_ID_SPKEQ = 5, //EQ数据
+ FILE_ID_SZ_FFT = 6, //SZ频响数据
+ FILE_ID_MIC_FFT = 7, //MIC声学频响数据
+ FILE_ID_COEFF_FGQ = 8, //新系数文件-FGQ ID号
+ FILE_ID_COEFF_FGQ_PART = 9, //新部分系数文件-FGQ ID号
+};
+
+enum {
+ ERR_NO = 0,
+ ERR_EAR_OFFLINE = 1,//耳机不在线
+ ERR_EAR_FAIL = 2, //耳机返回失败
+ ERR_MIC_BUSY = 3, //表示当前处于训练阶段,mic联通状态不允许发送命令给耳机
+ ERR_COEFF_NO = 4, //读系数时耳机没有训练系数
+ ERR_COEFF_LEN = 5, //写系数时长度异常
+ ERR_PARM_LEN = 6, //参数长度异常
+ ERR_VERSION = 7, //版本匹配异常,请更新转接板固件
+ ERR_READ_FILE = 8, //读文件失败
+ ERR_WRITE_FILE = 9, //写文件失败
+ ERR_PAIR_KEY = 10, //密码校验失败
+};
+
+enum {
+ CMD_GET_VERSION = 0x04, //获取版本号
+ CMD_ANC_OFF = 0x13, //关闭ANC
+ CMD_ANC_ON = 0x14, //开降噪
+ CMD_ANC_PASS = 0x15, //通透模式
+ CMD_READ_START = 0x20, //开始读
+ CMD_READ_DATA = 0x21, //读取数据
+ CMD_WRITE_START = 0x22, //开始写
+ CMD_WRITE_DATA = 0x23, //写入数据
+ CMD_WRITE_END = 0x24, //数据写入完成
+ CMD_SET_ID = 0x29, //设置ID对应的数据
+ CMD_GET_ID = 0x2A, //获取ID对应的数据
+ CMD_TOOLS_SET_GAIN = 0x2B, //工具设置增益(PC下来多少数据就转发多少给耳机)
+ CMD_TOOLS_GET_GAIN = 0x2C, //工具读取增益(耳机过来多少数据就转发多少给PC)
+ CMD_ANC_BYPASS = 0x2D, //BYPASS让耳机进入bypass模式,带一个u8的参数
+ CMD_GET_ANC_MODE = 0x2E, //获取耳机训练模式,(FF,FB,HYB...)
+ CMD_SET_ANC_MODE = 0x2F, //切换耳机训练模式,仅在耳机训练模式为混合溃时才能切换为单溃或者双馈
+ CMD_GET_COEFF_SIZE = 0x30, //获取系数内容大小(不会因为小机没有系数导致失败)
+ CMD_MUTE_TRAIN_ONLY = 0x31, //静音训练,耳机只跑静音训练
+ CMD_MUTE_TRAIN_ONLY_END = 0x32, //静音训练,耳机只跑静音训练,结束 ear->pc
+ CMD_MUTE_TRAIN_GET_POW = 0x33, //静音训练结束后获取fz sz数据接口
+ CMD_READ_FILE_START = 0x34, //读文件开始,携带ID号,返回文件大小
+ CMD_READ_FILE_DATA = 0x35, //读取文件数据,地址,长度
+ CMD_WRITE_FILE_START = 0x36, //写文件开始,携带ID号,及文件长度
+ CMD_WRITE_FILE_DATA = 0x37, //写入文件数据,地址+数据
+ CMD_WRITE_FILE_END = 0x38, //写入文件结束
+ CMD_GET_CHIP_VERSION = 0x39, //获取耳机芯片ANC版本
+ CMD_TRANS_MUTE_TRAIN = 0x3A, //通透训练
+ CMD_TRANS_MUTE_TRAIN_END = 0x3B, //通透训练结束, EAR->PC
+ CMD_TRIGER_CREATE_SPK_MIC = 0x3C, //触发生成DAT_SPK_MIC数据
+ CMD_CREATE_SPK_MIC_END = 0x3D, //生成DAT_SPK_MIC数据完成
+ CMD_GET_ANC_CH = 0x3E, //获取耳机通道设置
+ CMD_PAIR_KEY = 0x3F, //发送密码给小机
+ CMD_PAIR_SUCC = 0x40, //小机绕过密码校验
+ CMD_MIC_DATA_EXPORT_EN = 0X41, //开启/关闭mic数据采集
+ CMD_MIC_DATA_SEND = 0X42, //实时反馈mic数据
+ CMD_GET_ANC_MAX_ORDER = 0x43, //获取ANC最大滤波器阶数
+ CMD_ANC_ADAPTIVE_MODE = 0x47, //ANC耳道自适应模式
+ CMD_ANC_IIR_SEL = 0x48, //ANC 普通参数/自适应参数切换
+ CMD_EAR_ROLE_SWITCH = 0x49, //主从切换
+ CMD_DEVELOP_MODE_SET = 0X4A, //开发者模式设置
+ CMD_MUTL_SCENE_SET = 0X55, //ANC多场景设置
+ CMD_FAIL = 0xFE, //执行失败
+ CMD_UNDEFINE = 0xFF, //未定义
+};
+
+struct _anctool_info {
+ anc_train_para_t *para;
+ u8 mute_train_flag;
+#if ANCTOOL_NEED_PAIR_KEY
+ u8 pair_flag;
+#endif
+ u8 pack_flag;
+ u8 sz_nadap_pow;
+ u8 sz_adap_pow;
+ u8 sz_mute_pow;
+ u8 fz_nadap_pow;
+ u8 fz_adap_pow;
+ u8 fz_mute_pow;
+ u8 mic_pow_type;
+ u8 anc_designer;
+ u8 *file_hdl;
+ u32 file_len;
+ u32 file_id;
+ u8 connected_flag;
+};
+static struct _anctool_info anctool_info;
+#define __this (&anctool_info)
+
+static void app_anctool_send_ack(u8 cmd2pc, u8 ret, u8 err_num)
+{
+ u8 cmd[2];
+ if (ret == TRUE) {
+ cmd[0] = cmd2pc;
+ anctool_api_write(cmd, 1);
+ } else {
+ cmd[0] = CMD_FAIL;
+ cmd[1] = err_num;
+ anctool_api_write(cmd, 2);
+ }
+}
+
+static void app_anctool_ack_get_version(void)
+{
+ u8 *cmd;
+ u32 datalen;
+ datalen = sizeof(CONFIG_VERSION) + 1;
+ cmd = anctool_api_write_alloc(datalen);
+ cmd[0] = CMD_GET_VERSION;
+ memcpy(&cmd[1], CONFIG_VERSION, datalen - 1);
+ anctool_api_write(cmd, datalen);
+ anc_online_busy_set(1);
+}
+
+static void app_anctool_ack_read_start(u8 head)
+{
+ u8 *cmd;
+ u32 data_len;
+ __this->file_hdl = (u8 *)anc_coeff_read(); //先读头获取系数
+#if (ANC_CHIP_VERSION == ANC_VERSION_BR36) || (ANC_CHIP_VERSION == ANC_VERSION_BR28)
+ __this->file_len = anc_coeff_size_get(ANC_CFG_READ);
+#else
+ __this->file_len = anc_coeff_size_get();
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR36*/
+ if (__this->file_hdl) {//判断耳机有没有系数
+ data_len = __this->file_len;
+ cmd = anctool_api_write_alloc(5);
+ cmd[0] = head;
+ memcpy(&cmd[1], (u8 *)&data_len, 4);
+ anctool_api_write(cmd, 5);
+ } else {
+ app_anctool_send_ack(head, FALSE, ERR_COEFF_NO);
+ }
+}
+
+static void app_anctool_ack_read_data(u8 head, u32 offset, u32 data_len)
+{
+ u8 *cmd = anctool_api_write_alloc(data_len + 1);
+ cmd[0] = head;
+ memcpy(&cmd[1], __this->file_hdl + offset, data_len);
+ if (offset + data_len == __this->file_len) {
+ __this->file_hdl = NULL;
+ }
+ anctool_api_write(cmd, data_len + 1);
+}
+
+static void app_anctool_ack_wirte_start(u8 cmd, u32 data_len)
+{
+ anctool_printf("CMD_WRITE_START\n");
+#if (ANC_CHIP_VERSION == ANC_VERSION_BR36) || (ANC_CHIP_VERSION == ANC_VERSION_BR28)
+ __this->file_len = data_len;
+ anc_coeff_size_set(ANC_CFG_WRITE, data_len); //设置长度写anc_coeff.bin
+ __this->file_hdl = malloc(data_len);
+ if (__this->file_hdl) {
+#else
+ __this->file_len = anc_coeff_size_get();
+ __this->file_hdl = malloc(data_len);
+ if ((data_len == __this->file_len) && __this->file_hdl) {
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR36*/
+ app_anctool_send_ack(cmd, TRUE, ERR_NO);
+ } else {
+ app_anctool_send_ack(cmd, FALSE, ERR_COEFF_LEN);
+ if (__this->file_hdl) {
+ free(__this->file_hdl);
+ __this->file_hdl = NULL;
+ }
+ }
+}
+
+static void app_anctool_ack_wirte_data(u8 cmd, u32 offset, u8 *data, u32 data_len)
+{
+ memcpy(__this->file_hdl + offset, data, data_len);
+ app_anctool_send_ack(cmd, TRUE, ERR_NO);
+}
+
+static void app_anctool_ack_write_end(u32 file_id, u8 cmd)
+{
+ int ret;
+ switch (file_id) {
+ case FILE_ID_COEFF:
+ ret = anc_coeff_write((int *)__this->file_hdl, __this->file_len);
+ break;
+#if ANC_MULT_ORDER_ENABLE
+ case FILE_ID_COEFF_FGQ:
+ /* g_printf("coeff fgq write END!"); */
+ /* put_buf(__this->file_hdl, __this->file_len); */
+ ret = audio_anc_mult_coeff_write(ANC_MULT_COEFF_FILL_ALL, (int *)__this->file_hdl, __this->file_len);
+ break;
+ case FILE_ID_COEFF_FGQ_PART:
+ /* g_printf("coeff fgq write part END!"); */
+ /* put_buf(__this->file_hdl, __this->file_len); */
+ ret = audio_anc_mult_coeff_write(ANC_MULT_COEFF_FILL_PART, (int *)__this->file_hdl, __this->file_len);
+ break;
+#endif/*ANC_MULT_ORDER_ENABLE*/
+ }
+ free(__this->file_hdl);
+ __this->file_hdl = NULL;
+ if (!ret) {
+ app_anctool_send_ack(cmd, TRUE, ERR_NO);
+ } else { //滤波器格式出错则返回ERROR
+ app_anctool_send_ack(CMD_SET_ID, FALSE, ERR_COEFF_LEN);
+ }
+}
+
+static void app_anctool_ack_anc_mode(u8 cmd)
+{
+ /* anc_api_set_fade_en(0); */ //暂时不关闭淡入淡出
+ if (!__this->anc_designer) {
+ //产测模式-可以放置产测相关的特殊设置
+ anctool_printf("ANC in Production mode\n");
+#if ANC_EAR_ADAPTIVE_EN
+ if (audio_anc_coeff_mode_get()) {
+ audio_anc_coeff_adaptive_set(0, 0, 0); //将ANC参数设置为默认
+ }
+#endif/*ANC_EAR_ADAPTIVE_EN*/
+ } else {
+ anctool_printf("ANC in Designer mode\n");
+ }
+ if (cmd == CMD_ANC_ON) {
+ anc_mode_switch(ANC_ON, 0);
+ } else if (cmd == CMD_ANC_OFF) {
+ anc_mode_switch(ANC_OFF, 0);
+ } else if (cmd == CMD_ANC_PASS) {
+ anc_mode_switch(ANC_TRANSPARENCY, 0);
+#if ANC_EAR_ADAPTIVE_EN
+ } else if (cmd == CMD_ANC_ADAPTIVE_MODE) {
+ if (audio_anc_mode_ear_adaptive(1)) {
+ app_anctool_send_ack(cmd, TRUE, ERR_NO);
+ return;
+ }
+#endif/*ANC_EAR_ADAPTIVE_EN*/
+ } else {
+ anc_mode_switch(ANC_BYPASS, 0);
+ }
+ app_anctool_send_ack(cmd, TRUE, ERR_NO);
+}
+
+static void app_anctool_ack_set_id(u32 id, u32 value)
+{
+ anc_cfg_btspp_update((u8)id, (int)value);
+ app_anctool_send_ack(CMD_SET_ID, TRUE, ERR_NO);
+}
+
+static void app_anctool_ack_get_id(u32 id)
+{
+ u8 *cmd;
+ u32 value;
+ if (anc_cfg_btspp_read((u8)id, (int *)&value) == 0) {
+ cmd = anctool_api_write_alloc(4 + 1);
+ cmd[0] = CMD_GET_ID;
+ memcpy(&cmd[1], (u8 *)&value, 4);
+ anctool_api_write(cmd, 4 + 1);
+ } else {
+ app_anctool_send_ack(CMD_SET_ID, FALSE, ERR_EAR_FAIL);
+ }
+}
+
+static void app_anctool_ack_set_gain(u8 *buf, u32 len)
+{
+ u8 *cmd;
+ u32 data_len;
+ anc_gain_t *anc_gain = malloc(sizeof(anc_gain_t));
+ if ((len != sizeof(anc_gain_t)) || (anc_gain == NULL)) {
+ app_anctool_send_ack(CMD_TOOLS_SET_GAIN, FALSE, ERR_PARM_LEN);
+ } else {
+ memcpy(anc_gain, buf, len);
+ anc_cfg_online_deal(ANC_CFG_WRITE, anc_gain);
+ app_anctool_send_ack(CMD_TOOLS_SET_GAIN, TRUE, ERR_NO);
+ }
+ if (anc_gain) {
+ free(anc_gain);
+ }
+}
+
+static void app_anctool_ack_get_gain(void)
+{
+ u8 *cmd;
+ u32 data_len;
+ anc_gain_t *anc_gain = malloc(sizeof(anc_gain_t));
+ if (anc_gain == NULL) {
+ app_anctool_send_ack(CMD_TOOLS_GET_GAIN, FALSE, ERR_PARM_LEN);
+ return;
+ }
+ data_len = sizeof(anc_gain_t) + 1;
+ cmd = anctool_api_write_alloc(data_len);
+ cmd[0] = CMD_TOOLS_GET_GAIN;
+ anc_cfg_online_deal(ANC_CFG_READ, anc_gain);
+ memcpy(&cmd[1], anc_gain, sizeof(anc_gain_t));
+ anctool_api_write(cmd, data_len);
+ free(anc_gain);
+}
+
+static void app_anctool_ack_get_chip_version(void)
+{
+ u8 *cmd = anctool_api_write_alloc(2);
+ cmd[0] = CMD_GET_CHIP_VERSION;
+#if ANC_MULT_ORDER_ENABLE
+ cmd[1] = ANC_CHIP_VERSION | 0XA0;
+#else
+ cmd[1] = ANC_CHIP_VERSION;
+#endif
+ anctool_api_write(cmd, 2);
+}
+
+static void app_anctool_ack_get_train_mode(void)
+{
+ u8 *cmd = anctool_api_write_alloc(2);
+ cmd[0] = CMD_GET_ANC_MODE;
+ cmd[1] = ANC_TRAIN_MODE;
+ anctool_api_write(cmd, 2);
+}
+
+static void app_anctool_ack_get_ch(void)
+{
+#if (ANC_CHIP_VERSION == ANC_VERSION_BR36) || (ANC_CHIP_VERSION == ANC_VERSION_BR28)
+ u8 *cmd = anctool_api_write_alloc(2);
+ cmd[0] = CMD_GET_ANC_CH;
+ //开发者模式且打开耳道自适应功能,则返回工具立体声配置
+ if (audio_anc_develop_get() && ANC_EAR_ADAPTIVE_EN) {
+ cmd[1] = ANC_L_CH | ANC_R_CH;
+ } else {
+ cmd[1] = ANC_CH;
+ }
+ anctool_api_write(cmd, 2);
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR36*/
+}
+
+static void app_anctool_ack_get_anc_max_order(void)
+{
+#if (ANC_CHIP_VERSION == ANC_VERSION_BR36) || (ANC_CHIP_VERSION == ANC_VERSION_BR28)
+ u8 *cmd = anctool_api_write_alloc(2);
+ cmd[0] = CMD_GET_ANC_MAX_ORDER;
+#if ANC_CHIP_VERSION == ANC_VERSION_BR28
+ cmd[1] = 20;
+#else
+ cmd[1] = ANC_MAX_ORDER;
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR28*/
+ anctool_api_write(cmd, 2);
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR36*/
+}
+
+static void app_anctool_ack_set_train_mode(u8 mode)
+{
+ anc_mode_change_tool(mode);
+ app_anctool_send_ack(CMD_SET_ANC_MODE, TRUE, ERR_NO);
+}
+
+static void app_anctool_ack_get_coeff_size(void)
+{
+ u8 *cmd;
+#if (ANC_CHIP_VERSION == ANC_VERSION_BR36) || (ANC_CHIP_VERSION == ANC_VERSION_BR28)
+ u32 coeff_size = anc_coeff_size_get(ANC_CFG_READ);
+#else
+ u32 coeff_size = anc_coeff_size_get();
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR36*/
+ cmd = anctool_api_write_alloc(5);
+ cmd[0] = CMD_GET_COEFF_SIZE;
+ memcpy(&cmd[1], &coeff_size, 4);
+ anctool_api_write(cmd, 5);
+}
+
+void app_anctool_ack_mute_train_get_pow(void)
+{
+ u8 *cmd;
+ cmd = anctool_api_write_alloc(7);
+ cmd[0] = CMD_MUTE_TRAIN_GET_POW;
+ cmd[1] = __this->sz_nadap_pow;
+ cmd[2] = __this->sz_adap_pow;
+ cmd[3] = __this->sz_mute_pow;
+ cmd[4] = __this->fz_nadap_pow;
+ cmd[5] = __this->fz_adap_pow;
+ cmd[6] = __this->fz_mute_pow;
+ anctool_api_write(cmd, 7);
+}
+
+#if ANC_CHIP_VERSION == ANC_VERSION_BR28
+void app_anctool_ack_mic_power(void)
+{
+ u8 *cmd;
+ u16 buf[4];
+ cmd = anctool_api_write_alloc(3);
+ audio_anc_pow_get(buf);
+ cmd[0] = CMD_MIC_DATA_SEND;
+ memcpy(cmd + 1, &buf[__this->mic_pow_type], 2);
+ anctool_api_write(cmd, 3);
+}
+#endif
+
+#if ANCTOOL_NEED_PAIR_KEY
+void app_anctool_ack_pair_key(u8 *key)
+{
+ if (strcmp(ANCTOOL_PAIR_KEY, (const char *)key) == 0) {
+ __this->pair_flag = 1;
+ app_anctool_send_ack(CMD_PAIR_KEY, TRUE, ERR_NO);
+ } else {
+ __this->pair_flag = 0;
+ app_anctool_send_ack(CMD_PAIR_KEY, FALSE, ERR_PAIR_KEY);
+ }
+}
+#endif
+
+static void anctool_ack_read_file_start(u32 id)
+{
+ u8 *cmd;
+ __this->file_id = id;
+ __this->file_len = 0;
+ int *anc_debug_hdl;
+ switch (__this->file_id) {
+ case FILE_ID_COEFF:
+ case FILE_ID_COEFF_FGQ:
+#if ANCTOOL_NEED_PAIR_KEY
+ if (!__this->pair_flag) {
+ app_anctool_send_ack(CMD_READ_FILE_START, FALSE, ERR_PAIR_KEY);
+ } else
+#endif
+ {
+ app_anctool_ack_read_start(CMD_READ_FILE_START);
+ }
+ break;
+ case FILE_ID_MIC_SPK:
+ //这里判断是否有数据
+#if (ANC_CHIP_VERSION == ANC_VERSION_BR36) || (ANC_CHIP_VERSION == ANC_VERSION_BR28)
+ anc_debug_hdl = (u8 *)anc_debug_ctr(0);
+ if (anc_debug_hdl) {
+ __this->file_hdl = (u8 *)(anc_debug_hdl + 1); //数据指针
+ __this->file_len = anc_debug_hdl[0];
+ cmd = anctool_api_write_alloc(5);
+ cmd[0] = CMD_READ_FILE_START;
+ memcpy(&cmd[1], (u8 *)&__this->file_len, 4);
+ anctool_api_write(cmd, 5);
+ } else {
+ app_anctool_send_ack(CMD_READ_FILE_START, FALSE, ERR_READ_FILE);
+ }
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR36*/
+ break;
+ case FILE_ID_GAIN:
+ __this->file_len = sizeof(anc_gain_t);
+ __this->file_hdl = (u8 *)zalloc(__this->file_len);//数据指针
+ if (__this->file_hdl) {
+ anc_cfg_online_deal(ANC_CFG_READ, (anc_gain_t *)__this->file_hdl);
+ cmd = anctool_api_write_alloc(5);
+ cmd[0] = CMD_READ_FILE_START;
+ memcpy(&cmd[1], (u8 *)&__this->file_len, 4);
+ anctool_api_write(cmd, 5);
+ } else {
+ app_anctool_send_ack(CMD_READ_FILE_START, FALSE, ERR_READ_FILE);
+ }
+ break;
+#if ANC_EAR_ADAPTIVE_EN
+ case FILE_ID_ADAPTIVE:
+ extern anc_packet_data_t *anc_adaptive_data;
+ if (anc_adaptive_data == NULL) {
+ printf("packet is NULL, return!\n");
+ app_anctool_send_ack(CMD_READ_FILE_START, FALSE, ERR_READ_FILE);
+ return;
+ }
+ if (anc_adaptive_data->dat_len == 0) {
+ printf("error: dat_len == 0\n");
+ app_anctool_send_ack(CMD_READ_FILE_START, FALSE, ERR_READ_FILE);
+ return;
+ }
+ __this->file_len = anc_adaptive_data->dat_len;
+ __this->file_hdl = (u8 *)(anc_adaptive_data->dat);
+ cmd = anctool_api_write_alloc(5);
+ cmd[0] = CMD_READ_FILE_START;
+ memcpy(&cmd[1], (u8 *)&__this->file_len, 4);
+ anctool_api_write(cmd, 5);
+ break;
+#endif/*ANC_EAR_ADAPTIVE_EN*/
+ }
+}
+
+static void anctool_ack_read_file_data(u32 offset, u32 data_len)
+{
+ u8 *cmd;
+ switch (__this->file_id) {
+ case FILE_ID_COEFF:
+ case FILE_ID_COEFF_FGQ:
+#if ANCTOOL_NEED_PAIR_KEY
+ if (!__this->pair_flag) {
+ app_anctool_send_ack(CMD_READ_FILE_DATA, FALSE, ERR_PAIR_KEY);
+ } else
+#endif
+ {
+ app_anctool_ack_read_data(CMD_READ_FILE_DATA, offset, data_len);
+ }
+ break;
+ case FILE_ID_MIC_SPK:
+#if (ANC_CHIP_VERSION == ANC_VERSION_BR36) || (ANC_CHIP_VERSION == ANC_VERSION_BR28)
+ if (__this->file_hdl) {
+ cmd = anctool_api_write_alloc(data_len + 1);
+ cmd[0] = CMD_READ_FILE_DATA;
+ memcpy(&cmd[1], __this->file_hdl + offset, data_len);
+ if (offset + data_len == __this->file_len) {
+ __this->file_hdl = (u8 *)anc_debug_ctr(1);
+ }
+ anctool_api_write(cmd, data_len + 1);
+ } else {
+ app_anctool_send_ack(CMD_READ_FILE_DATA, FALSE, ERR_READ_FILE);
+ }
+#endif/*ANC_CHIP_VERSION == ANC_VERSION_BR36*/
+ break;
+ case FILE_ID_GAIN:
+ if (__this->file_hdl) {
+ cmd = anctool_api_write_alloc(data_len + 1);
+ cmd[0] = CMD_READ_FILE_DATA;
+ memcpy(&cmd[1], __this->file_hdl + offset, data_len);
+ if (offset + data_len == __this->file_len) {
+ free(__this->file_hdl);
+ __this->file_hdl = NULL;
+ }
+ anctool_api_write(cmd, data_len + 1);
+ } else {
+ app_anctool_send_ack(CMD_READ_FILE_DATA, FALSE, ERR_READ_FILE);
+ }
+ break;
+#if ANC_EAR_ADAPTIVE_EN
+ case FILE_ID_ADAPTIVE:
+ if (__this->file_hdl) {
+ cmd = anctool_api_write_alloc(data_len + 1);
+ cmd[0] = CMD_READ_FILE_DATA;
+ memcpy(&cmd[1], __this->file_hdl + offset, data_len);
+ if (offset + data_len == __this->file_len) {
+ /* free(__this->file_hdl); */
+ __this->file_hdl = NULL;
+ }
+ anctool_api_write(cmd, data_len + 1);
+ } else {
+ app_anctool_send_ack(CMD_READ_FILE_DATA, FALSE, ERR_READ_FILE);
+ }
+ break;
+#endif/*ANC_EAR_ADAPTIVE_EN*/
+ }
+}
+
+static void anctool_ack_write_file_start(u32 id, u32 data_len)
+{
+ __this->file_id = id;
+ __this->file_len = data_len;
+ switch (__this->file_id) {
+ case FILE_ID_COEFF:
+ case FILE_ID_COEFF_FGQ:
+ case FILE_ID_COEFF_FGQ_PART:
+ app_anctool_ack_wirte_start(CMD_WRITE_FILE_START, data_len);
+ break;
+ case FILE_ID_GAIN:
+ __this->file_len = sizeof(anc_gain_t);
+ __this->file_hdl = (u8 *)malloc(__this->file_len);
+ if ((__this->file_len != data_len) || (__this->file_hdl == NULL)) {
+ anctool_printf("anc gain size err, %d != %d\n", data_len, __this->file_len);
+ app_anctool_send_ack(CMD_WRITE_FILE_START, FALSE, ERR_WRITE_FILE);
+ if (__this->file_hdl) {
+ free(__this->file_hdl);
+ __this->file_hdl = NULL;
+ }
+ } else {
+ app_anctool_send_ack(CMD_WRITE_FILE_START, TRUE, ERR_NO);
+ }
+ break;
+#if ANC_EAR_ADAPTIVE_EN
+ case FILE_ID_ADAPTIVE_REF:
+ //开始写金机曲线
+ //y_printf("\n>>>>>> [FILE_ID_ADAPTIVE_REF] id : %d, data_len : %d\n\n", __this->file_id, __this->file_len);
+ __this->file_hdl = (u8 *)malloc(__this->file_len);
+ if (__this->file_hdl == NULL) {
+ anctool_printf("anc write adaptive ref failed\n");
+ app_anctool_send_ack(CMD_WRITE_FILE_START, FALSE, ERR_WRITE_FILE);
+ } else {
+ app_anctool_send_ack(CMD_WRITE_FILE_START, TRUE, ERR_NO);
+ }
+ break;
+#endif/*ANC_EAR_ADAPTIVE_EN*/
+ }
+}
+
+static void anctool_ack_write_file_data(u32 offset, u8 *data, u32 data_len)
+{
+ switch (__this->file_id) {
+ case FILE_ID_COEFF:
+ case FILE_ID_COEFF_FGQ:
+ case FILE_ID_COEFF_FGQ_PART:
+ app_anctool_ack_wirte_data(CMD_WRITE_FILE_DATA, offset, data, data_len);
+ break;
+ case FILE_ID_GAIN:
+ if (__this->file_hdl == NULL || ((offset + data_len) > __this->file_len)) {
+ app_anctool_send_ack(CMD_WRITE_FILE_DATA, FALSE, ERR_WRITE_FILE);
+ if (__this->file_hdl) {
+ free(__this->file_hdl);
+ __this->file_hdl = NULL;
+ }
+ } else {
+ memcpy(__this->file_hdl + offset, data, data_len);
+ app_anctool_send_ack(CMD_WRITE_FILE_DATA, TRUE, ERR_NO);
+ }
+ break;
+#if ANC_EAR_ADAPTIVE_EN
+ case FILE_ID_ADAPTIVE_REF:
+ //写金机曲线...
+ //printf("\n==================================\n");
+ //put_buf(data, data_len);
+ if (__this->file_hdl == NULL || ((offset + data_len) > __this->file_len)) {
+ app_anctool_send_ack(CMD_WRITE_FILE_DATA, FALSE, ERR_WRITE_FILE);
+ if (__this->file_hdl) {
+ free(__this->file_hdl);
+ __this->file_hdl = NULL;
+ }
+ } else {
+ memcpy(__this->file_hdl + offset, data, data_len);
+ app_anctool_send_ack(CMD_WRITE_FILE_DATA, TRUE, ERR_NO);
+ }
+ break;
+#endif/*ANC_EAR_ADAPTIVE_EN*/
+ }
+}
+
+static void anctool_ack_write_file_end(void)
+{
+ switch (__this->file_id) {
+ case FILE_ID_COEFF:
+ case FILE_ID_COEFF_FGQ:
+ case FILE_ID_COEFF_FGQ_PART:
+ app_anctool_ack_write_end(__this->file_id, CMD_WRITE_FILE_END);
+ break;
+ case FILE_ID_GAIN:
+ if (__this->file_hdl == NULL) {
+ app_anctool_send_ack(CMD_WRITE_FILE_END, FALSE, ERR_WRITE_FILE);
+ } else {
+ anc_cfg_online_deal(ANC_CFG_WRITE, (anc_gain_t *)__this->file_hdl);
+ free(__this->file_hdl);
+ __this->file_hdl = NULL;
+ app_anctool_send_ack(CMD_WRITE_FILE_END, TRUE, ERR_NO);
+ }
+ break;
+#if ANC_EAR_ADAPTIVE_EN
+ case FILE_ID_ADAPTIVE_REF:
+ // 写金机曲线结束
+ if (__this->file_hdl == NULL) {
+ app_anctool_send_ack(CMD_WRITE_FILE_END, FALSE, ERR_WRITE_FILE);
+ } else {
+ //保存金机曲线数据
+ anc_adaptive_ff_ref_data_save(__this->file_hdl, __this->file_len);
+ free(__this->file_hdl);
+ __this->file_hdl = NULL;
+ app_anctool_send_ack(CMD_WRITE_FILE_END, TRUE, ERR_NO);
+ }
+ break;
+#endif
+ }
+}
+
+static void anctool_callback(u8 mode, u8 command)
+{
+ u8 cmd[2];
+ anctool_printf("anctool_callback: %d, %d\n", mode, command);
+ if (__this->mute_train_flag == 0) {
+ g_printf("%s,%d\n", __func__, __LINE__);
+ return;
+ }
+ if (__this->mute_train_flag == 1) {
+ cmd[0] = CMD_MUTE_TRAIN_ONLY_END;
+ cmd[1] = command;
+ } else if (__this->mute_train_flag == 2) {
+ cmd[0] = CMD_TRANS_MUTE_TRAIN_END;
+ cmd[1] = command;
+ } else if (__this->mute_train_flag == 3) {
+ cmd[0] = CMD_CREATE_SPK_MIC_END;
+ cmd[1] = command;
+ } else {
+ __this->mute_train_flag = 0;
+ return;
+ }
+ anctool_api_set_active(1);
+ anctool_api_write(cmd, 2);
+ anctool_api_set_active(0);
+ __this->mute_train_flag = 0;
+}
+
+static void anctool_pow_callback(anc_ack_msg_t *msg, u8 step)
+{
+ switch (step) {
+ case ANC_TRAIN_SZ:
+ __this->sz_nadap_pow = anc_powdat_analysis(msg->pow);
+ __this->sz_adap_pow = anc_powdat_analysis(msg->temp_pow);
+ __this->sz_mute_pow = anc_powdat_analysis(msg->mute_pow);
+ break;
+ case ANC_TRAIN_FZ:
+ __this->fz_nadap_pow = anc_powdat_analysis(msg->pow);
+ __this->fz_adap_pow = anc_powdat_analysis(msg->temp_pow);
+ __this->fz_mute_pow = anc_powdat_analysis(msg->mute_pow);
+ break;
+ }
+}
+
+static void app_anctool_module_deal(u8 *data, u16 len)
+{
+ u8 cmd = data[0];
+ u32 offset, data_len, id, value;
+ __this->pack_flag = 1;
+ anctool_printf("recv packet:\n");
+ anctool_put_buf(data, len);
+ __this->connected_flag = 1;
+#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+ /*关闭所有模块*/
+ if (audio_icsd_adt_is_running()) {
+ audio_icsd_adt_close_all();
+ }
+#endif
+ switch (cmd) {
+ case CMD_GET_VERSION:
+ anctool_printf("CMD_GET_VERSION\n");
+ app_anctool_ack_get_version();
+ break;
+ case CMD_READ_START:
+ anctool_printf("CMD_READ_START\n");
+#if ANCTOOL_NEED_PAIR_KEY
+ if (!__this->pair_flag) {
+ app_anctool_send_ack(CMD_READ_START, FALSE, ERR_PAIR_KEY);
+ } else
+#endif
+ {
+ app_anctool_ack_read_start(CMD_READ_START);
+ }
+ break;
+ case CMD_READ_DATA:
+ anctool_printf("CMD_READ_DATA\n");
+ memcpy((u8 *)&offset, &data[1], 4);
+ memcpy((u8 *)&data_len, &data[5], 4);
+#if ANCTOOL_NEED_PAIR_KEY
+ if (!__this->pair_flag) {
+ app_anctool_send_ack(CMD_READ_DATA, FALSE, ERR_PAIR_KEY);
+ } else
+#endif
+ {
+ app_anctool_ack_read_data(CMD_READ_DATA, offset, data_len);
+ }
+ break;
+ case CMD_WRITE_START:
+ anctool_printf("CMD_WRITE_START\n");
+ memcpy((u8 *)&data_len, &data[1], 4);
+ app_anctool_ack_wirte_start(CMD_WRITE_START, data_len);
+ break;
+ case CMD_WRITE_DATA:
+ anctool_printf("CMD_WRITE_DATA\n");
+ memcpy((u8 *)&offset, &data[1], 4);
+ app_anctool_ack_wirte_data(CMD_WRITE_DATA, offset, &data[5], len - 5);
+ break;
+ case CMD_WRITE_END:
+ anctool_printf("CMD_WRITE_END\n");
+ app_anctool_ack_write_end(FILE_ID_COEFF, CMD_WRITE_END);
+ break;
+ case CMD_ANC_OFF:
+ case CMD_ANC_ON:
+ case CMD_ANC_PASS:
+ case CMD_ANC_BYPASS:
+#if ANC_EAR_ADAPTIVE_EN
+ case CMD_ANC_ADAPTIVE_MODE:
+#endif/*ANC_EAR_ADAPTIVE_EN*/
+ anctool_printf("CMD_ANC_MODE:%d\n", cmd);
+ app_anctool_ack_anc_mode(cmd);
+ break;
+ case CMD_SET_ID:
+ memcpy((u8 *)&offset, &data[1], 4);//id
+ memcpy((u8 *)&data_len, &data[5], 4);//value
+ anctool_printf("CMD_SET_ID: 0x%x, %d\n", offset, data_len);
+ app_anctool_ack_set_id(offset, data_len);
+ break;
+ case CMD_GET_ID:
+ anctool_printf("CMD_GET_ID\n");
+ memcpy((u8 *)&offset, &data[1], 4);
+ app_anctool_ack_get_id(offset);
+ break;
+ case CMD_TOOLS_SET_GAIN:
+ anctool_printf("CMD_TOOLS_SET_GAIN: %d\n", len - 1);
+ app_anctool_ack_set_gain(&data[1], len - 1);
+ break;
+ case CMD_TOOLS_GET_GAIN:
+ anctool_printf("CMD_TOOLS_GET_GAIN\n");
+ app_anctool_ack_get_gain();
+ break;
+ case CMD_GET_ANC_MODE://获取耳机结构
+ anctool_printf("CMD_GET_ANC_MODE\n");
+ app_anctool_ack_get_train_mode();
+ break;
+ case CMD_SET_ANC_MODE://设置结构
+ anctool_printf("CMD_SET_ANC_MODE: %d\n", data[1]);
+ app_anctool_ack_set_train_mode(data[1]);
+ break;
+ case CMD_GET_COEFF_SIZE:
+ anctool_printf("MSG_PC_GET_COEFF_SIZE\n");
+ app_anctool_ack_get_coeff_size();
+ break;
+ case CMD_MUTE_TRAIN_ONLY:
+ anctool_printf("CMD_MUTE_TRAIN_ONLY\n");
+ __this->mute_train_flag = 1;
+ anc_api_set_callback(anctool_callback, anctool_pow_callback);
+ anc_train_api_set(ANC_DEVELOPER_MODE, 1, __this->para);//设置为开发者模式
+ anc_train_api_set(ANC_MUTE_TARIN, 1, __this->para);
+ app_anctool_send_ack(CMD_MUTE_TRAIN_ONLY, TRUE, ERR_NO);
+ break;
+ case CMD_MUTE_TRAIN_GET_POW:
+ anctool_printf("CMD_MUTE_TRAIN_GET_POW\n");
+ app_anctool_ack_mute_train_get_pow();
+ break;
+ case CMD_READ_FILE_START:
+ anctool_printf("CMD_READ_FILE_START\n");
+ memcpy((u8 *)&id, &data[1], 4);
+ anctool_ack_read_file_start(id);
+ break;
+ case CMD_READ_FILE_DATA:
+ anctool_printf("CMD_READ_FILE_DATA\n");
+ memcpy((u8 *)&offset, &data[1], 4);
+ memcpy((u8 *)&data_len, &data[5], 4);
+ anctool_ack_read_file_data(offset, data_len);
+ break;
+ case CMD_WRITE_FILE_START:
+ anctool_printf("CMD_WRITE_FILE_START\n");
+ memcpy((u8 *)&id, &data[1], 4);
+ memcpy((u8 *)&data_len, &data[5], 4);
+ anctool_ack_write_file_start(id, data_len);
+ break;
+ case CMD_WRITE_FILE_DATA:
+ anctool_printf("CMD_WRITE_FILE_DATA\n");
+ memcpy((u8 *)&offset, &data[1], 4);
+ anctool_ack_write_file_data(offset, &data[5], len - 5);
+ break;
+ case CMD_WRITE_FILE_END:
+ anctool_printf("CMD_WRITE_FILE_END\n");
+ anctool_ack_write_file_end();
+ break;
+ //ear 2 pc cmd
+ case CMD_MUTE_TRAIN_ONLY_END:
+ anctool_printf("pc ack cmd=[%d]!\n", cmd);
+ break;
+ case CMD_GET_CHIP_VERSION:
+ app_anctool_ack_get_chip_version();
+ anctool_printf("CMD_GET_CHIP_VERSION\n");
+ break;
+ case CMD_TRANS_MUTE_TRAIN:
+ anctool_printf("CMD_TOOLS_GET_GAIN\n");
+ if (len > 1) {
+ memcpy((u8 *)&value, &data[1], 4);
+ anc_api_set_trans_aim_pow(value);
+ }
+ app_anctool_send_ack(CMD_TRANS_MUTE_TRAIN, TRUE, ERR_NO);
+ __this->mute_train_flag = 2;
+ anc_api_set_callback(anctool_callback, anctool_pow_callback);
+ anc_train_api_set(ANC_DEVELOPER_MODE, 1, __this->para);//设置为开发者模式
+ anc_train_api_set(ANC_TRANS_MUTE_TARIN, 0, __this->para);
+ break;
+#if ANC_EAR_ADAPTIVE_EN
+ case CMD_ANC_IIR_SEL:
+ anctool_printf("CMD_ANC_IIR_SEL\n");
+ if (audio_anc_coeff_adaptive_set((u32)data[1], 1, 1)) {
+ app_anctool_send_ack(CMD_ANC_IIR_SEL, FALSE, ERR_NO);
+ } else {
+ app_anctool_send_ack(CMD_ANC_IIR_SEL, TRUE, ERR_NO);
+ }
+ break;
+#endif/*ANC_EAR_ADAPTIVE_EN*/
+ case CMD_TRIGER_CREATE_SPK_MIC:
+ //开始采集SPK MIC数据
+ anctool_printf("CMD_TRIGER_CREATE_SPK_MIC\n");
+ app_anctool_send_ack(CMD_TRIGER_CREATE_SPK_MIC, TRUE, ERR_NO);
+ anc_api_set_callback(anctool_callback, NULL);
+ anc_train_api_set(ANC_MUTE_TARIN, (u32)data[1], __this->para);
+ __this->mute_train_flag = 3;
+ //todo
+ break;
+#if TCFG_USER_TWS_ENABLE && (ANC_CH != (ANC_L_CH | ANC_R_CH))
+ case CMD_EAR_ROLE_SWITCH:
+ anctool_printf("CMD_EAR_ROLE_SWITCH\n");
+ if (get_tws_sibling_connect_state()) {
+ tws_conn_switch_role();
+ app_anctool_send_ack(CMD_EAR_ROLE_SWITCH, TRUE, ERR_NO);
+ } else {
+ app_anctool_send_ack(CMD_EAR_ROLE_SWITCH, FALSE, ERR_NO);
+ }
+ break;
+#endif
+ case CMD_GET_ANC_CH://获取耳机ANC通道
+ anctool_printf("CMD_GET_ANC_CH\n");
+ app_anctool_ack_get_ch();
+ break;
+ case CMD_GET_ANC_MAX_ORDER:
+ anctool_printf("CMD_GET_ANC_MAX_ORDER\n");
+ app_anctool_ack_get_anc_max_order();
+ break;
+#if ANC_CHIP_VERSION == ANC_VERSION_BR28
+ case CMD_MIC_DATA_EXPORT_EN://开启/关闭mic数据采集
+ anctool_printf("CMD_MIC_DATA_EXPORT_EN: %d, mic_type: %d\n", data[1], data[2]);
+ __this->mic_pow_type = data[2] - ANC_POW_SEL_R_DAC_REF; //数组下标对齐
+ audio_anc_pow_export_en(data[1], data[1]);
+ app_anctool_send_ack(CMD_MIC_DATA_EXPORT_EN, TRUE, ERR_NO);
+ break;
+ case CMD_MIC_DATA_SEND://实时反馈mic数据
+ anctool_printf("CMD_MIC_DATA_SEND\n");
+ app_anctool_ack_mic_power();
+ break;
+#endif
+#if ANCTOOL_NEED_PAIR_KEY
+ case CMD_PAIR_KEY:
+ data[len] = '\0';
+ anctool_printf("CMD_PAIR_KEY: %s\n", (data + 1));
+ app_anctool_ack_pair_key(data + 1);
+ break;
+ case CMD_PAIR_SUCC:
+ anctool_printf("CMD_PAIR_SUCC\n");
+ __this->pair_flag = 1;
+ app_anctool_send_ack(CMD_PAIR_SUCC, TRUE, ERR_NO);
+ break;
+#endif
+ case CMD_DEVELOP_MODE_SET:
+ //ANC_DESIGNER 独有命令
+ anctool_printf("CMD_DEVELOP_MODE_SET\n");
+ __this->anc_designer = 1;
+ audio_anc_develop_set(data[1]);
+ app_anctool_send_ack(CMD_DEVELOP_MODE_SET, TRUE, ERR_NO);
+ break;
+#if ANC_MULT_ORDER_ENABLE
+ case CMD_MUTL_SCENE_SET:
+ anctool_printf("CMD_MUTL_SCENE_SET\n");
+ audio_anc_mult_scene_set(data[1], 1);
+ app_anctool_send_ack(CMD_MUTL_SCENE_SET, TRUE, ERR_NO);
+ break;
+#endif/*ANC_MULT_ORDER_ENABLE*/
+ default:
+ cmd = CMD_UNDEFINE;
+ anctool_api_write(&cmd, 1);
+ break;
+ }
+}
+
+static void app_anctool_spp_tx_data(u8 *data, u16 size)
+{
+ user_send_cmd_prepare(USER_CTRL_SPP_SEND_DATA, size, data);
+}
+
+const struct anctool_data app_anctool_data = {
+ .recv_packet = app_anctool_module_deal,
+ .send_packet = app_anctool_spp_tx_data,
+};
+
+u8 app_anctool_spp_rx_data(u8 *packet, u16 size)
+{
+ __this->pack_flag = 0;
+ anctool_api_rx_data(packet, size);
+ return __this->pack_flag;
+}
+
+void app_anctool_spp_connect(void)
+{
+ anctool_printf("%s, spp_connect!\n", __FUNCTION__);
+ anctool_api_init(&app_anctool_data);
+ __this->para = anc_api_get_train_param();
+}
+
+void app_anctool_spp_disconnect(void)
+{
+ anctool_printf("%s, spp_disconnect!\n", __FUNCTION__);
+ __this->anc_designer = 0;
+ __this->connected_flag = 0;
+#if ANCTOOL_NEED_PAIR_KEY
+ __this->pair_flag = 0;
+#endif
+ anctool_api_uninit();
+}
+
+u8 get_app_anctool_spp_connected_flag()
+{
+ if (!__this) {
+ return 0;
+ }
+ return __this->connected_flag;
+}
+
+#endif
diff --git a/apps/earphone/app_main.c b/apps/earphone/app_main.c
new file mode 100644
index 0000000..4aca9ac
--- /dev/null
+++ b/apps/earphone/app_main.c
@@ -0,0 +1,497 @@
+#include "system/includes.h"
+/*#include "btcontroller_config.h"*/
+#include "btstack/btstack_task.h"
+#include "app_config.h"
+#include "app_action.h"
+#include "asm/pwm_led.h"
+#include "tone_player.h"
+#include "ui_manage.h"
+#include "gpio.h"
+#include "app_main.h"
+#include "asm/charge.h"
+#include "update.h"
+#include "app_power_manage.h"
+#include "audio_config.h"
+#include "app_charge.h"
+#include "bt_profile_cfg.h"
+#include "dev_manager/dev_manager.h"
+#include "update_loader_download.h"
+#include "usr_rtc.h"
+
+#ifndef CONFIG_MEDIA_NEW_ENABLE
+#ifndef CONFIG_MEDIA_DEVELOP_ENABLE
+#include "audio_dec_server.h"
+#endif
+#endif
+
+#if TCFG_USER_TWS_ENABLE
+#include "bt_tws.h"
+#endif
+
+#if TCFG_AUDIO_ANC_ENABLE
+#include "audio_anc.h"
+#endif
+
+#define LOG_TAG_CONST APP
+#define LOG_TAG "[APP]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#ifdef CONFIG_BOARD_AISPEECH_VAD_ASR
+u8 user_at_cmd_send_support = 1;
+#endif
+
+/*任务列表 */
+const struct task_info task_info_table[] = {
+ {"app_core", 1, 0, 768+768+2048, 256 },
+ {"sys_event", 7, 0, 256+128, 0 },
+ {"systimer", 7, 0, 128+128+128, 0 },
+ {"btctrler", 4, 0, 1536+512+128, 384 },
+ {"btencry", 1, 0, 1536+512+128, 128 },
+ //{"tws", 5, 0, 512, 128 },
+#if (BT_FOR_APP_EN)
+ {"btstack", 3, 0, 1024+1024+1024+512, 256 },
+#else
+ {"btstack", 3, 0, 1024+1024+1024+512, 256 },
+#endif
+ {"audio_dec", 5, 0, 800, 128 },
+ //{"aud_effect", 5, 1, 800, 128 },
+ /*
+ *为了防止dac buf太大,通话一开始一直解码,
+ *导致编码输入数据需要很大的缓存,这里提高编码的优先级
+ */
+ //{"audio_enc", 6, 0, 768, 128 },
+ //{"aec", 2, 1, 768, 128 },
+#if TCFG_AUDIO_HEARING_AID_ENABLE
+ {"HearingAid", 6, 0, 768, 128 },
+#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
+#ifdef CONFIG_BOARD_AISPEECH_NR
+ {"aispeech_enc", 2, 1, 512, 128 },
+#endif /*CONFIG_BOARD_AISPEECH_NR*/
+#ifdef CONFIG_BOARD_AISPEECH_VAD_ASR
+ {"asr", 1, 0, 768, 128 },
+ {"audio_asr_export_task", 1, 0, 512, 128 },
+#endif/*CONFIG_BOARD_AISPEECH_VAD_ASR*/
+#ifndef CONFIG_256K_FLASH
+ //{"aec_dbg", 3, 0, 128, 128 },
+
+#if AUDIO_ENC_MPT_SELF_ENABLE
+ {"enc_mpt_self", 3, 0, 512, 128 },
+#endif/*AUDIO_ENC_MPT_SELF_ENABLE*/
+ {"update", 1, 0, 256+128, 0 },
+ //{"tws_ota", 2, 0, 256, 0 },
+ //{"tws_ota_msg", 2, 0, 256, 128 },
+ {"dw_update", 2, 0, 256+768, 128 },
+ {"rcsp_task", 2, 0, 640, 128 },
+ //{"aud_capture", 4, 0, 512, 256 },
+ //{"data_export", 5, 0, 512, 256 },
+ //{"anc", 3, 1, 512, 128 },
+#endif
+
+#if TCFG_GX8002_NPU_ENABLE
+ {"gx8002", 2, 0, 256, 64 },
+#endif /* #if TCFG_GX8002_NPU_ENABLE */
+#if TCFG_GX8002_ENC_ENABLE
+ {"gx8002_enc", 2, 0, 128, 64 },
+#endif /* #if TCFG_GX8002_ENC_ENABLE */
+
+
+#if TCFG_KWS_VOICE_RECOGNITION_ENABLE
+ {"kws", 2, 0, 256, 64 },
+#endif /* #if TCFG_KWS_VOICE_RECOGNITION_ENABLE */
+ {"usb_msd", 1, 0, 512, 128 },
+#if !TCFG_USB_MIC_CVP_ENABLE
+ {"usbmic_write", 2, 0, 256, 128 },
+#endif
+#if AI_APP_PROTOCOL
+ {"app_proto", 2, 0, 768, 64 },
+#endif
+#if (TCFG_SPI_LCD_ENABLE||TCFG_SIMPLE_LCD_ENABLE)
+ {"ui", 2, 0, 768, 256 },
+#else
+ {"ui", 3, 0, 384 - 64, 128 },
+#endif
+#if (TCFG_DEV_MANAGER_ENABLE)
+ {"dev_mg", 3, 0, 512, 512 },
+#endif
+ {"audio_vad", 1, 1, 512, 128 },
+#if TCFG_KEY_TONE_EN
+ {"key_tone", 5, 0, 256, 32 },
+#endif
+#if (TCFG_WIRELESS_MIC_ENABLE)
+ {"wl_mic_enc", 2, 0, 768, 128 },
+#endif
+#if (TUYA_DEMO_EN)
+ {"user_deal", 7, 0, 512, 512 },//定义线程 tuya任务调度
+ {"dw_update", 2, 0, 256, 128 },
+#endif
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+ {"imu_trim", 1, 0, 256, 128 },
+#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
+#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+ {"speak_to_chat", 2, 0, 256, 128 },
+ {"icsd_adt", 2, 0, 512, 128 },
+ {"icsd_src", 2, 1, 512, 128 },
+#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
+ {"pmu_task", 6, 0, 256, 128 },
+ //{"WindDetect", 2, 0, 256, 128 },
+ {0, 0},
+};
+
+
+APP_VAR app_var;
+USR_VAR usr_var;
+void clr_wdt(void);
+u8 usr_get_ldoin();
+void app_earphone_play_voice_file(const char *name);
+extern int cpu_reset_by_soft();
+extern int audio_dec_init();
+extern int audio_enc_init();
+extern u32 timer_get_ms(void);
+extern void uart_dev_test_main();
+extern int ana_demo();
+extern void uart_dev_main_init();
+extern void usr_check_mcu_all_sta();
+extern void usr_clear_pair_info_noreset(void);
+extern void usr_disable_intterupt();
+extern void usr_disable_charge_intterupt();
+u8 power_reset_flag=0;
+/*
+ * 2ms timer中断回调函数
+ */
+
+void timer_2ms_handler()
+{
+
+}
+
+void app_var_init(void)
+{
+ memset((u8 *)&bt_user_priv_var, 0, sizeof(BT_USER_PRIV_VAR));
+ app_var.play_poweron_tone = 1;
+
+}
+
+__attribute__((weak))
+u8 get_charge_online_flag(void)
+{
+ return 0;
+}
+
+/* 软复位 / 充电唤醒时跳过开机提示音 */
+static void app_poweron_check(int update)
+{
+#if (CONFIG_BT_MODE == BT_NORMAL)
+ if (!update && cpu_reset_by_soft()) {
+ app_var.play_poweron_tone = 0;
+ return;
+ }
+
+#if TCFG_CHARGE_OFF_POWERON_NE
+ if (is_ldo5v_wakeup()) {
+ app_var.play_poweron_tone = 0;
+ return;
+ }
+#endif
+#endif
+}
+
+u8 usr_get_ldoin()
+{
+#if USR_CHG_IN_IO
+ if(gpio_read(USR_CHG_IN_IO)==0)return 1;
+ return 0;
+#else
+ #if TCFG_CHARGE_ENABLE
+ if (get_ldo5v_online_hw() && get_charge_online_flag())return 1;
+ else return 0;
+ #else
+ return 0;
+ #endif // TCFG_CHARGE_ENABLE
+#endif // USR_CHG_IN_IO
+}
+u8 usr_get_full()
+{
+#if USR_CHG_FULL_IO
+ if(gpio_read(USR_CHG_FULL_IO)==0)return 1;
+ return 0;
+#else
+ #if TCFG_CHARGE_ENABLE
+ if(get_charge_full_flag())return 1;
+ else return 0;
+ #else
+ return 0;
+ #endif // TCFG_CHARGE_ENABLE
+#endif // USR_CHG_FULL_IO
+}
+u8 usr_get_ldoin_all()
+{
+ if(usr_get_ldoin()||usr_get_full())return 1;
+ return 0;
+}
+
+#if 0
+const struct sys_time def_sys_time = { //初始一下当前时间
+ .year = 2020,
+ .month = 1,
+ .day = 1,
+ .hour = 0,
+ .min = 0,
+ .sec = 0,
+};
+
+
+const struct rtc_dev_platform_data rtc_init_data=
+{
+ .default_sys_time = &def_sys_time,
+ .default_alarm = NULL,
+ .clk_sel = CLK_SEL_32K,//CLK_SEL_LRC,//CLK_SEL_32K,
+ .cbfun = NULL, //闹钟中断的回调函数,用户自行定义
+ /* .cbfun = alarm_isr_user_cbfun, */
+};
+#endif // 0
+extern void bt_osc_offset_ext_updata(s32 offset);
+extern void usr_jb_init();
+void app_main()
+{
+ int update = 0;
+ u32 addr = 0, size = 0;
+ struct intent it;
+
+ log_info("app_main...............#####\n");
+ bt_osc_offset_ext_updata(11);
+ usr_var.usr_ota_succ_flag=0;
+ usb_iomode(1);
+
+//#ifndef CONFIG_DEBUG_ENABLE
+// uart_dev_test_main();
+//#endif // CONFIG_DEBUG_ENABLE
+ app_var.start_time = timer_get_ms();
+
+#if (defined(CONFIG_MEDIA_NEW_ENABLE) || (defined(CONFIG_MEDIA_DEVELOP_ENABLE)))
+ /*解码器*/
+ audio_enc_init();
+ audio_dec_init();
+#endif
+
+//rtc_init(&rtc_init_data);
+#ifdef BT_DUT_INTERFERE
+ void audio_demo(void);
+ audio_demo();
+#endif/*BT_DUT_INTERFERE*/
+#ifdef BT_DUT_ADC_INTERFERE
+ void audio_adc_mic_dut_open(void);
+ audio_adc_mic_dut_open();
+#endif/*BT_DUT_ADC_INTERFERE*/
+
+ if (!UPDATE_SUPPORT_DEV_IS_NULL()) {
+ update = 0;//update_result_deal();
+ }
+
+ app_var_init();
+ usr_rtc_init(); /* 打开硬件 RTC,网关 DEVICEINFO 对时走 usr_rtc_set_from_unix */
+ usr_jb_init();
+
+#if TCFG_MC_BIAS_AUTO_ADJUST
+ mc_trim_init(update);
+#endif/*TCFG_MC_BIAS_AUTO_ADJUST*/
+
+ //if (get_charge_online_flag())
+ if(0){
+
+#if(TCFG_SYS_LVD_EN == 1)
+ vbat_check_init();
+#endif
+
+ init_intent(&it);
+ it.name = "idle";
+ it.action = ACTION_IDLE_MAIN;
+ start_app(&it);
+ } else {
+ check_power_on_voltage();
+
+ app_poweron_check(update);
+ //uart_dev_main_init();
+ //sys_timeout_add(NULL,usr_check_mcu_all_sta,1000);
+ if(usr_get_ldoin()||usr_get_full())
+ {
+ usr_var.usr_power_charge_flag=1;
+ }
+ else
+ {
+ usr_var.usr_power_charge_flag=2;
+ }
+
+ /*
+ * 上电强制进入配对模式:
+ * 1) usr_goto_pair=1:后续 usr_ble_adv_init() 走绑定广播(encode4bind),不走重连广播
+ * 2) usr_clear_pair_info_noreset():清 VM 中三元组,保证 paired_flag=0
+ * 注意:须在 BLE 协议栈调用 usr_ble_adv_init() 之前设置;此处不清复位,避免上电死循环复位
+ */
+ usr_var.usr_goto_pair = 1;
+ usr_clear_pair_info_noreset();
+
+ ui_manage_init();
+ ui_update_status(STATUS_POWERON);
+
+#if TCFG_WIRELESS_MIC_ENABLE
+ extern void wireless_mic_main_run(void);
+ wireless_mic_main_run();
+#endif
+
+#if TCFG_ENTER_PC_MODE
+ init_intent(&it);
+ it.name = "pc";
+ it.action = ACTION_PC_MAIN;
+ start_app(&it);
+#else
+ init_intent(&it);
+ it.name = "earphone";
+ it.action = ACTION_EARPHONE_MAIN;
+ start_app(&it);
+#endif
+ }
+
+#if TCFG_CHARGE_ENABLE
+ set_charge_event_flag(1);
+#endif
+
+}
+
+int __attribute__((weak)) eSystemConfirmStopStatus(void)
+{
+ /* 系统进入在未来时间里,无任务超时唤醒,可根据用户选择系统停止,或者系统定时唤醒(100ms),或自己指定唤醒时间 */
+ //1:Endless Sleep
+ //0:100 ms wakeup
+ //other: x ms wakeup
+ if (get_charge_full_flag()) {
+ /* log_i("Endless Sleep"); */
+ power_set_soft_poweroff();
+ return 1;
+ } else {
+ /* log_i("100 ms wakeup"); */
+ return 0;
+ }
+}
+
+__attribute__((used)) int *__errno()
+{
+ static int err;
+ return &err;
+}
+/*
+enum {
+ KEY_USER_DEAL_POST = 0,
+ KEY_USER_DEAL_POST_MSG,
+ KEY_USER_DEAL_POST_EVENT,
+ KEY_USER_DEAL_POST_2,
+};
+
+#include "system/includes.h"
+#include "system/event.h"
+
+///自定义事件推送的线程
+
+#define Q_USER_DEAL 0xAABBCC ///自定义队列类型
+#define Q_USER_DATA_SIZE 10///理论Queue受任务声明struct task_info.qsize限制,但不宜过大,建议<=6
+
+void user_deal_send_ver(void)
+{
+ //os_taskq_post("user_deal", 1,KEY_USER_DEAL_POST);
+ os_taskq_post_msg("user_deal", 1, KEY_USER_DEAL_POST_MSG);
+ //os_taskq_post_event("user_deal",1, KEY_USER_DEAL_POST_EVENT);
+}
+
+void user_deal_rand_set(u32 rand)
+{
+ os_taskq_post("user_deal", 2, KEY_USER_DEAL_POST_2, rand);
+}
+
+void user_deal_send_array(int *msg, int argc)
+{
+ if (argc > Q_USER_DATA_SIZE) {
+ return;
+ }
+ os_taskq_post_type("user_deal", Q_USER_DEAL, argc, msg);
+}
+void user_deal_send_msg(void)
+{
+ os_taskq_post_event("user_deal", 1, KEY_USER_DEAL_POST_EVENT);
+}
+
+void user_deal_send_test(void)///模拟测试函数,可按键触发调用,自行看打印
+{
+ user_deal_send_ver();
+ user_deal_rand_set(0x11223344);
+ static u32 data[Q_USER_DATA_SIZE] = {0x11223344, 0x55667788, 0x11223344, 0x55667788, 0x11223344,
+ 0xff223344, 0x556677ee, 0x11223344, 0x556677dd, 0x112233ff,
+ };
+ user_deal_send_array(data, sizeof(data) / sizeof(int));
+}
+
+static void user_deal_task_handle(void *p)
+{
+ int msg[Q_USER_DATA_SIZE + 1] = {0, 0, 0, 0, 0, 0, 0, 0, 00, 0};
+ int res = 0;
+ while (1) {
+ res = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
+ if (res != OS_TASKQ) {
+ continue;
+ }
+ r_printf("user_deal_task_handle:0x%x", msg[0]);
+ put_buf(msg, (Q_USER_DATA_SIZE + 1) * 4);
+ if (msg[0] == Q_MSG) {
+ printf("use os_taskq_post_msg");
+ switch (msg[1]) {
+ case KEY_USER_DEAL_POST_MSG:
+ printf("KEY_USER_DEAL_POST_MSG");
+ break;
+ default:
+ break;
+ }
+ } else if (msg[0] == Q_EVENT) {
+ printf("use os_taskq_post_event");
+ switch (msg[1]) {
+ case KEY_USER_DEAL_POST_EVENT:
+ printf("KEY_USER_DEAL_POST_EVENT");
+ break;
+ default:
+ break;
+ }
+ } else if (msg[0] == Q_CALLBACK) {
+ } else if (msg[0] == Q_USER) {
+ printf("use os_taskq_post");
+ switch (msg[1]) {
+ case KEY_USER_DEAL_POST:
+ printf("KEY_USER_DEAL_POST");
+ break;
+ case KEY_USER_DEAL_POST_2:
+ printf("KEY_USER_DEAL_POST_2:0x%x", msg[2]);
+ break;
+ default:
+ break;
+ }
+ } else if (msg[0] == Q_USER_DEAL) {
+ printf("use os_taskq_post_type");
+ printf("0x%x 0x%x 0x%x 0x%x 0x%x", msg[1], msg[2], msg[3], msg[4], msg[5]);
+ printf("0x%x 0x%x 0x%x 0x%x 0x%x", msg[6], msg[7], msg[8], msg[9], msg[10]);
+ }
+ puts("");
+ }
+}
+
+void user_deal_init(void)
+{
+ //task_create(user_deal_task_handle, NULL, "user_deal");
+}
+
+void user_deal_exit(void)
+{
+ //task_kill("user_deal");
+}
+
+*/
diff --git a/apps/earphone/app_task_switch.c b/apps/earphone/app_task_switch.c
new file mode 100644
index 0000000..a60a9fa
--- /dev/null
+++ b/apps/earphone/app_task_switch.c
@@ -0,0 +1,285 @@
+#include "system/includes.h"
+#include "app_config.h"
+#include "app_task.h"
+//#include "app_music.h"
+#include "app_action.h"
+#include "earphone.h"
+#include "bt_background.h"
+
+u8 app_curr_task = 0;
+u8 app_next_task = 0;
+u8 app_prev_task = 0;
+
+extern int pc_app_check(void);
+
+const u8 app_task_list[] = {
+ APP_BT_TASK,
+#if TCFG_APP_MUSIC_EN
+ APP_MUSIC_TASK,
+#endif
+#if TCFG_PC_ENABLE
+ APP_PC_TASK,
+#endif
+#if TCFG_APP_AUX_EN
+ APP_AUX_TASK,
+#endif
+};
+
+const u8 app_task_action_tab[] = {
+ ACTION_EARPHONE_MAIN,
+#if TCFG_APP_MUSIC_EN
+ ACTION_MUSIC_MAIN,
+#endif
+#if TCFG_PC_ENABLE
+ ACTION_PC_MAIN,
+#endif
+#if TCFG_APP_AUX_EN
+ ACTION_AUX_MAIN,
+#endif
+};
+
+const char *app_task_name_tab[] = {
+ APP_NAME_BT,
+#if TCFG_APP_MUSIC_EN
+ APP_NAME_MUSIC,
+#endif
+#if TCFG_PC_ENABLE
+ APP_NAME_PC,
+#endif
+#if TCFG_APP_AUX_EN
+ APP_NAME_AUX,
+#endif
+};
+
+//*----------------------------------------------------------------------------*/
+/**@brief 模式进入检查
+ @param app_task:目标模式
+ @return TRUE可以进入, FALSE不可以进入
+ @note 例如一些需要设备在线的任务(music),
+ 如果设备在线可以进入, 没有设备在线不进入可以在这里处理
+*/
+/*----------------------------------------------------------------------------*/
+int app_task_switch_check(u8 app_task)
+{
+ int ret = false;
+ printf("app_task %x\n", app_task);
+ switch (app_task) {
+ case APP_BT_TASK:
+ ret = true;
+ break;
+#if TCFG_APP_MUSIC_EN
+ case APP_MUSIC_TASK:
+ ret = music_app_check();
+ break;
+#endif
+#if TCFG_PC_ENABLE
+ case APP_PC_TASK:
+ ret = pc_app_check();
+ break;
+#endif
+#if TCFG_APP_AUX_EN
+ case APP_AUX_TASK:
+ ret = true;
+ break;
+#endif
+ default:
+ ret = false;
+ break;
+ }
+ return ret;
+}
+
+//*----------------------------------------------------------------------------*/
+/**@brief app_core_back_to_prev_app后检查
+ @param void
+ @return TRUE:当前模式对应的设备在线, FALSE:当前模式的设备不在线却进入了模式
+ @note 用于app_core_back_to_prev_app后的检查
+*/
+/*----------------------------------------------------------------------------*/
+int app_core_back_to_prev_app_over_check(void)
+{
+ int ret = false;
+ struct application *app = get_current_app();
+
+ if (app && app->state == APP_STA_START) {
+ if (app->name == APP_NAME_BT) {
+ } else if (app->name == APP_NAME_BT) {
+ ret = true;
+ } else if (app->name == APP_NAME_MUSIC) {
+#if TCFG_APP_MUSIC_EN
+ ret = music_app_check();
+#endif
+ } else if (app->name == APP_NAME_PC) {
+#if TCFG_PC_ENABLE
+ ret = pc_app_check();
+#endif
+ } else if (app->name == APP_NAME_AUX) {
+#if TCFG_APP_AUX_EN
+ ret = true;
+#endif
+ } else {
+ ret = false;
+ }
+ }
+ return ret;
+}
+
+//*----------------------------------------------------------------------------*/
+/**@brief 模式退出检查
+ @param curr_task:当前模式
+ @return TRUE可以退出, FALSE不可以退出
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+static int app_task_switch_exit_check(u8 curr_task)
+{
+ int ret = false;
+ switch (curr_task) {
+ case APP_BT_TASK:
+ ret = bt_app_exit_check();
+ break;
+ default:
+ ret = TRUE;
+ break;
+
+ }
+ return ret;
+}
+
+//*----------------------------------------------------------------------------*/
+/**@brief 切换到指定模式
+ @param app_task:指定模式
+ @return
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+int app_task_switch_to(u8 app_task, int priv)
+{
+ struct intent it;
+
+ //相同模式不切
+ if (app_curr_task == app_task) {
+ return false;
+ }
+
+ //不在线不切
+ if (!app_task_switch_check(app_task)) {
+ return false;
+ }
+
+ //上一个模式不允许退出不切
+ if (!app_task_switch_exit_check(app_curr_task)) {
+ return false;
+ }
+
+ printf("cur --- %x \n", app_curr_task);
+ printf("new +++ %x \n", app_task);
+
+ app_prev_task = app_curr_task;
+ app_curr_task = app_task;
+
+#if CONFIG_BT_BACKGROUND_ENABLE
+ //bt_in_background()为0时,切到蓝牙模式需要初始化(关机插pc切模式的情况)
+ if ((app_task == APP_BT_TASK) && bt_in_background()) {
+ if (priv == ACTION_A2DP_START) {
+ bt_switch_to_foreground(ACTION_A2DP_START, 1);
+ } else if (priv == ACTION_DO_NOTHING) {
+ bt_switch_to_foreground(ACTION_DO_NOTHING, 1);
+ } else {
+ bt_switch_to_foreground(ACTION_TONE_PLAY, 1);
+ }
+ return true; //切到蓝牙前台
+ }
+#endif
+
+#if CONFIG_BT_BACKGROUND_ENABLE
+ if (app_prev_task != APP_BT_TASK)
+#endif
+ {
+ init_intent(&it);
+ it.action = ACTION_BACK;
+ start_app(&it);
+ }
+
+ init_intent(&it);
+ it.name = app_task_name_tab[app_task];
+ it.action = app_task_action_tab[app_task];
+ start_app(&it);
+ return true;
+}
+
+//*----------------------------------------------------------------------------*/
+/**@brief 切换到下一个模式
+ @param
+ @return
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+void app_task_switch_next(void)
+{
+ int i = 0;
+ int cur_index = 0;
+
+ for (cur_index = 0; cur_index < ARRAY_SIZE(app_task_list); cur_index++) {
+ if (app_curr_task == app_task_list[cur_index]) {//遍历当前索引
+ break;
+ }
+ }
+
+ for (i = cur_index ;;) { //遍历一圈
+ if (++i >= ARRAY_SIZE(app_task_list)) {
+ i = 0;
+ }
+ if (i == cur_index) {
+ return;
+ }
+ if (app_task_switch_to(app_task_list[i], NULL_VALUE)) {
+ return;
+ }
+ }
+}
+
+//*----------------------------------------------------------------------------*/
+/**@brief 切换到上一个模式
+ @param
+ @return
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+void app_task_switch_prev(void)
+{
+ int i = 0;
+ int cur_index = 0;
+
+ for (cur_index = 0; cur_index < ARRAY_SIZE(app_task_list); cur_index++) {
+ if (app_curr_task == app_task_list[cur_index]) {//遍历当前索引
+ break;
+ }
+ }
+
+ for (i = cur_index; ;) { //遍历一圈
+ if (i-- == 0) {
+ i = ARRAY_SIZE(app_task_list) - 1;
+ }
+ if (i == cur_index) {
+ return;
+ }
+ if (app_task_switch_to(app_task_list[i], NULL_VALUE)) {
+ return;
+ }
+ }
+}
+
+//*----------------------------------------------------------------------------*/
+/**@brief 获取当前模式
+ @param
+ @return 当前模式id
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+u8 app_get_curr_task(void)
+{
+ return app_curr_task;
+}
+
+
diff --git a/apps/earphone/app_testbox.c b/apps/earphone/app_testbox.c
new file mode 100644
index 0000000..0cfcefd
--- /dev/null
+++ b/apps/earphone/app_testbox.c
@@ -0,0 +1,462 @@
+#include "init.h"
+#include "app_config.h"
+#include "system/includes.h"
+#include "asm/chargestore.h"
+#include "user_cfg.h"
+//#include "app_chargestore.h"
+#include "app_power_manage.h"
+#include "app_testbox.h"
+#include "device/vm.h"
+#include "btstack/avctp_user.h"
+#include "app_action.h"
+#include "app_main.h"
+#include "app_charge.h"
+#include "classic/tws_api.h"
+#include "update.h"
+#include "bt_ble.h"
+#include "bt_tws.h"
+#include "app_action.h"
+#include "bt_common.h"
+#include "le_rcsp_adv_module.h"
+#include "asm/lp_touch_key_api.h"
+
+#define LOG_TAG_CONST APP_TESTBOX
+#define LOG_TAG "[APP_TESTBOX]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#if TCFG_TEST_BOX_ENABLE
+
+//testbox sub cmd
+#define CMD_BOX_BT_NAME_INFO 0x01 //获取蓝牙名
+#define CMD_BOX_SDK_VERSION 0x02 //获取sdk版本信息
+#define CMD_BOX_BATTERY_VOL 0x03 //获取电量
+#define CMD_BOX_ENTER_DUT 0x04 //进入dut模式
+#define CMD_BOX_FAST_CONN 0x05 //进入快速链接
+#define CMD_BOX_VERIFY_CODE 0x06 //获取校验码
+#define CMD_BOX_ENTER_STORAGE_MODE 0x0a //进入仓储模式
+#define CMD_BOX_GLOBLE_CFG 0x0b //测试盒配置命令(测试盒收到CMD_BOX_TWS_CHANNEL_SEL命令后发送,需使能测试盒某些配置)
+#define CMD_BOX_CUSTOM_CODE 0xf0 //客户自定义命令处理
+
+#define WRITE_LIT_U16(a,src) {*((u8*)(a)+1) = (u8)(src>>8); *((u8*)(a)+0) = (u8)(src&0xff); }
+#define WRITE_LIT_U32(a,src) {*((u8*)(a)+3) = (u8)((src)>>24); *((u8*)(a)+2) = (u8)(((src)>>16)&0xff);*((u8*)(a)+1) = (u8)(((src)>>8)&0xff);*((u8*)(a)+0) = (u8)((src)&0xff);}
+
+#define READ_LIT_U32(a) (*((u8*)(a)) + (*((u8*)(a)+1)<<8) + (*((u8*)(a)+2)<<16) + (*((u8*)(a)+3)<<24))
+
+enum {
+ UPDATE_MASK_FLAG_INQUIRY_VBAT_LEVEL = 0,
+ UPDATE_MASK_FLAG_INQUIRY_VERIFY_CODE,
+ UPDATE_MASK_FLAG_INQUIRY_SDK_VERSION,
+};
+
+static const u32 support_update_mask = BIT(UPDATE_MASK_FLAG_INQUIRY_VBAT_LEVEL) | \
+ BIT(UPDATE_MASK_FLAG_INQUIRY_SDK_VERSION) | \
+ BIT(UPDATE_MASK_FLAG_INQUIRY_VERIFY_CODE);
+
+struct testbox_info {
+ u8 bt_init_ok;//蓝牙协议栈初始化成功
+ u8 testbox_status;//测试盒在线状态
+ u8 connect_status;//通信成功
+ u8 channel;//左右
+ u8 event_hdl_flag;
+ volatile u32 global_cfg; //全局配置信息,控制耳机在/离仓行为
+ volatile u8 keep_tws_conn_flag; //保持tws连接标志
+ u8 tws_paired_flag;
+};
+
+
+enum {
+ BOX_CFG_SOFTPWROFF_AFTER_PAIRED_BIT = 0, //测试盒配对完耳机关机
+ BOX_CFG_TOUCH_TRIM_OUT_OF_BOX_BIT = 1, //离仓执行trim操作
+ BOX_CFG_TRIM_START_TIME_BIT = 2, //离仓多久trim,unit:2s (n+1)*2,即(2~8s)
+
+};
+
+#define BOX_CFG_BITS_GET_FROM_MASK(mask,index,len) (((mask & BIT(index))>>index) & (0xffffffff>>(32-len)))
+static struct testbox_info info = {
+ .global_cfg = BIT(BOX_CFG_SOFTPWROFF_AFTER_PAIRED_BIT),
+};
+#define __this (&info)
+
+extern const char *bt_get_local_name();
+extern u16 get_vbat_value(void);
+extern void bt_fast_test_api(void);
+extern const int config_btctler_eir_version_info_len;
+extern const char *sdk_version_info_get(void);
+extern u8 *sdfile_get_burn_code(u8 *len);
+extern void bt_page_scan_for_test(u8 inquiry_en);
+extern u8 get_jl_chip_id(void);
+extern u8 get_jl_chip_id2(void);
+extern void set_temp_link_key(u8 *linkkey);
+static u8 ex_enter_dut_flag = 0;
+static u8 ex_enter_storage_mode_flag = 0;//1 仓储模式, 0 普通模式
+static u8 local_packet[36];
+
+void testbox_set_bt_init_ok(u8 flag)
+{
+ __this->bt_init_ok = flag;
+}
+
+void testbox_set_testbox_tws_paired(u8 flag)
+{
+ __this->tws_paired_flag = flag;
+}
+
+u8 testbox_get_testbox_tws_paired(void)
+{
+ return __this->tws_paired_flag;
+}
+
+u8 testbox_get_touch_trim_en(u8 *sec)
+{
+ if (sec) {
+ u8 sec_bits = BOX_CFG_BITS_GET_FROM_MASK(__this->global_cfg, BOX_CFG_TRIM_START_TIME_BIT, 2);
+ *sec = (sec_bits + 1) * 2;
+ }
+
+ return BOX_CFG_BITS_GET_FROM_MASK(__this->global_cfg, BOX_CFG_TOUCH_TRIM_OUT_OF_BOX_BIT, 1);
+}
+
+u8 testbox_get_softpwroff_after_paired(void)
+{
+ return BOX_CFG_BITS_GET_FROM_MASK(__this->global_cfg, BOX_CFG_SOFTPWROFF_AFTER_PAIRED_BIT, 1);
+}
+
+u8 testbox_get_ex_enter_storage_mode_flag(void)
+{
+ return ex_enter_storage_mode_flag;
+}
+
+u8 testbox_get_ex_enter_dut_flag(void)
+{
+ return ex_enter_dut_flag;
+}
+
+u8 testbox_get_connect_status(void)
+{
+ return __this->connect_status;
+}
+
+void testbox_clear_connect_status(void)
+{
+ __this->connect_status = 0;
+}
+
+u8 testbox_get_status(void)
+{
+ return __this->testbox_status;
+}
+
+void testbox_clear_status(void)
+{
+ __this->testbox_status = 0;
+ testbox_clear_connect_status();
+}
+
+u8 testbox_get_keep_tws_conn_flag(void)
+{
+ return __this->keep_tws_conn_flag;
+}
+
+void testbox_event_to_user(u8 *packet, u32 type, u8 event, u8 size)
+{
+ struct sys_event e;
+ e.type = SYS_DEVICE_EVENT;
+ if (packet != NULL) {
+ if (size > sizeof(local_packet)) {
+ return;
+ }
+ e.u.chargestore.packet = local_packet;
+ memcpy(e.u.chargestore.packet, packet, size);
+ }
+ e.arg = (void *)type;
+ e.u.chargestore.event = event;
+ e.u.chargestore.size = size;
+ sys_event_notify(&e);
+}
+
+
+
+extern u32 link_task_idle_disable(void);
+static void app_testbox_sub_event_handle(u8 *data, u16 size)
+{
+ u8 mac = 0;
+ switch (data[0]) {
+ case CMD_BOX_FAST_CONN:
+ case CMD_BOX_ENTER_DUT:
+ __this->event_hdl_flag = 0;
+ struct application *app = get_current_app();
+ if (app) {
+ if (strcmp(app->name, APP_NAME_BT)) {
+ if (!app_var.goto_poweroff_flag) {
+ app_var.play_poweron_tone = 0;
+ task_switch_to_bt();
+ }
+ } else {
+ if ((!__this->connect_status) && __this->bt_init_ok) {
+ log_info("\n\nbt_page_inquiry_scan_for_test\n\n");
+ __this->connect_status = 1;
+ extern void bredr_set_dut_enble(u8 en, u8 phone);
+ log_info("bredr_dut_enbale\n");
+ bredr_set_dut_enble(1, 1);
+#if TCFG_USER_TWS_ENABLE
+ bt_page_scan_for_test(1);
+#endif
+ link_task_idle_disable();
+
+ }
+ }
+ }
+ break;
+ case CMD_BOX_CUSTOM_CODE:
+ __this->event_hdl_flag = 0;
+ if (data[1] == 0x00) {
+ bt_fast_test_api();
+ }
+ break;
+ }
+}
+
+//事件执行函数,在任务调用
+int app_testbox_event_handler(struct testbox_event *testbox_dev)
+{
+ struct application *app = get_current_app();
+ switch (testbox_dev->event) {
+ //case CMD_BOX_MODULE:
+ // app_testbox_sub_event_handle(testbox_dev->packet, testbox_dev->size);
+ // break;
+ /*case CMD_BOX_TWS_CHANNEL_SEL:
+ __this->event_hdl_flag = 0;
+ if (get_vbat_need_shutdown() == TRUE) {
+ //电压过低,不进行测试
+ break;
+ }
+ if (app) {
+ if (strcmp(app->name, APP_NAME_BT)) {
+ if (!app_var.goto_poweroff_flag) {
+ app_var.play_poweron_tone = 0;
+ task_switch_to_bt();
+ }
+ } else {
+ if ((!__this->connect_status) && __this->bt_init_ok) {
+ __this->connect_status = 1;
+ }
+ }
+ }*/
+ break;
+ //不是测试盒事件,返回0,未处理
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static const u8 own_private_linkkey[16] = {
+ 0x06, 0x77, 0x5f, 0x87, 0x91, 0x8d, 0xd4, 0x23,
+ 0x00, 0x5d, 0xf1, 0xd8, 0xcf, 0x0c, 0x14, 0x2b
+};
+
+static void app_testbox_sub_cmd_handle(u8 *send_buf, u8 buf_len, u8 *buf, u8 len)
+{
+ u8 temp_len;
+ u8 send_len = 0;
+
+ send_buf[0] = buf[0];
+ send_buf[1] = buf[1];
+
+ log_info("sub_cmd:%x\n", buf[1]);
+
+ switch (buf[1]) {
+ case CMD_BOX_BT_NAME_INFO:
+ temp_len = strlen(bt_get_local_name());
+ if (temp_len < (buf_len - 2)) {
+ memcpy(&send_buf[2], bt_get_local_name(), temp_len);
+ send_len = temp_len + 2;
+ chargestore_api_write(send_buf, send_len);
+ } else {
+ log_error("bt name buf len err\n");
+ }
+ break;
+
+ case CMD_BOX_BATTERY_VOL:
+ send_buf[2] = get_vbat_value();
+ send_buf[3] = get_vbat_value() >> 8;
+ send_buf[4] = get_vbat_percent();
+ send_len = sizeof(u16) + sizeof(u8) + 2; //vbat_value;u16,vabt_percent:u8,opcode:2 bytes
+ log_info("bat_val:%d %d\n", get_vbat_value(), get_vbat_percent());
+ chargestore_api_write(send_buf, send_len);
+ break;
+
+ case CMD_BOX_SDK_VERSION:
+ if (config_btctler_eir_version_info_len) {
+ temp_len = strlen(sdk_version_info_get());
+ send_len = (temp_len > (buf_len - 2)) ? buf_len : temp_len + 2;
+ log_info("version:%s ver_len:%x send_len:%x\n", sdk_version_info_get(), temp_len, send_len);
+ memcpy(send_buf + 2, sdk_version_info_get(), temp_len);
+ chargestore_api_write(send_buf, send_len);
+ }
+ break;
+
+ case CMD_BOX_FAST_CONN:
+ log_info("enter fast dut\n");
+ set_temp_link_key((u8 *)own_private_linkkey);
+ bt_get_vm_mac_addr(&send_buf[2]);
+ if (0 == __this->event_hdl_flag) {
+ testbox_event_to_user(&buf[1], DEVICE_EVENT_TEST_BOX, buf[0], 1);
+ __this->event_hdl_flag = 1;
+ }
+ if (__this->bt_init_ok) {
+ ex_enter_dut_flag = 1;
+ chargestore_api_write(send_buf, 8);
+ }
+ break;
+
+ case CMD_BOX_ENTER_DUT:
+ log_info("enter dut\n");
+ //__this->testbox_status = 1;
+ ex_enter_dut_flag = 1;
+
+ if (0 == __this->event_hdl_flag) {
+ testbox_event_to_user(&buf[1], DEVICE_EVENT_TEST_BOX, buf[0], 1);
+ __this->event_hdl_flag = 1;
+ }
+ if (__this->bt_init_ok) {
+ chargestore_api_write(send_buf, 2);
+ }
+ break;
+
+ case CMD_BOX_VERIFY_CODE:
+ log_info("get_verify_code\n");
+ u8 *p = sdfile_get_burn_code(&temp_len);
+ send_len = (temp_len > (buf_len - 2)) ? buf_len : temp_len + 2;
+ memcpy(send_buf + 2, p, temp_len);
+ chargestore_api_write(send_buf, send_len);
+ break;
+
+ case CMD_BOX_CUSTOM_CODE:
+ log_info("CMD_BOX_CUSTOM_CODE value=%x", buf[2]);
+ if (buf[2] == 0) {//测试盒自定义命令,样机进入快速测试模式
+ if (0 == __this->event_hdl_flag) {
+ __this->event_hdl_flag = 1;
+ testbox_event_to_user(&buf[1], DEVICE_EVENT_TEST_BOX, buf[0], 2);
+ }
+ }
+ send_len = 0x3;
+#if (defined(TCFG_AUDIO_SPATIAL_EFFECT_ENABLE) && TCFG_AUDIO_SPATIAL_EFFECT_ENABLE)
+ if (buf[2] == 1) {
+ __this->testbox_status = 1;
+ extern int testbox_imu_trim_run(u8 * send_buf);
+ send_len = testbox_imu_trim_run(send_buf);
+ put_buf(send_buf, 36);
+ send_len += 2;
+ }
+#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
+
+#if TCFG_LP_TOUCH_KEY_ENABLE
+ if (buf[2] == 0x6a) {//测试盒自定义命令, 0x6a 用于触摸动态阈值算法的结果显示,请大家不要冲突
+ send_buf[2] = 0x6a;
+ send_buf[3] = 'c';
+ send_buf[4] = 's';
+ send_buf[5] = 'm';
+ send_buf[6] = 'r';
+ send_buf[7] = lp_touch_key_alog_range_display((u8 *)&send_buf[8]);
+ send_len = 8 + send_buf[7];
+ log_info("send_len = %d\n", send_len);
+ }
+#endif
+
+ chargestore_api_write(send_buf, send_len);
+ break;
+
+ case CMD_BOX_ENTER_STORAGE_MODE:
+ log_info("CMD_BOX_ENTER_STORAGE_MODE");
+ ex_enter_storage_mode_flag = 1;
+ chargestore_api_write(send_buf, 2);
+ break;
+
+ case CMD_BOX_GLOBLE_CFG:
+ log_info("CMD_BOX_GLOBLE_CFG:%d %x %x", len, READ_LIT_U32(buf + 2), READ_LIT_U32(buf + 6));
+ __this->global_cfg = READ_LIT_U32(buf + 2);
+#if 0 //for test
+ u8 sec;
+ u32 trim_en = testbox_get_touch_trim_en(&sec);
+ log_info("box_cfg:%x %x %x\n",
+ testbox_get_softpwroff_after_paired(),
+ trim_en, sec);
+#endif
+
+ chargestore_api_write(send_buf, 2);
+ break;
+
+ default:
+ //send_buf[0] = CMD_UNDEFINE;
+ //send_len = 1;
+ //chargestore_api_write(send_buf, send_len);
+ break;
+ }
+
+ log_info_hexdump(send_buf, send_len);
+}
+
+//数据执行函数,在串口中断调用
+static int app_testbox_data_handler(u8 *buf, u8 len)
+{
+ u8 send_buf[36];
+ send_buf[0] = buf[0];
+ switch (buf[0]) {
+ /*case CMD_BOX_MODULE:
+ app_testbox_sub_cmd_handle(send_buf, sizeof(send_buf), buf, len);
+ break;*/
+
+ /*case CMD_BOX_UPDATE:
+ __this->testbox_status = 1;
+ if (buf[13] == get_jl_chip_id() || buf[13] == get_jl_chip_id2()) {
+ chargestore_set_update_ram();
+ cpu_reset();
+ } else if (buf[13] == 0xff) {
+ send_buf[1] = 0xff;
+ WRITE_LIT_U32(&send_buf[2], support_update_mask);
+ chargestore_api_write(send_buf, 2 + sizeof(support_update_mask));
+ log_info("rsp update_mask\n");
+ } else {
+ send_buf[1] = 0x01;//chip id err
+ chargestore_api_write(send_buf, 2);
+ }
+ break;*/
+ /*case CMD_BOX_TWS_CHANNEL_SEL:
+ __this->testbox_status = 1;
+ if (len == 3) {
+ __this->keep_tws_conn_flag = buf[2];
+ putchar('K');
+ } else {
+ __this->keep_tws_conn_flag = 0;
+ }
+ __this->channel = (buf[1] == TWS_CHANNEL_LEFT) ? 'L' : 'R';
+ if (0 == __this->event_hdl_flag) {
+ testbox_event_to_user(NULL, DEVICE_EVENT_TEST_BOX, CMD_BOX_TWS_CHANNEL_SEL, 0);
+ __this->event_hdl_flag = 1;
+ }
+ if (__this->bt_init_ok) {
+ len = chargestore_get_tws_remote_info(&send_buf[1]);
+ chargestore_api_write(send_buf, len + 1);
+ } else {
+ send_buf[0] = CMD_UNDEFINE;
+ chargestore_api_write(send_buf, 1);
+ }
+ break;*/
+
+ //不是测试盒命令,返回0,未处理
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+CHARGESTORE_HANDLE_REG(testbox, app_testbox_data_handler);
+
+#endif
+
diff --git a/apps/earphone/audio_enc_mpt_cvp_ctr.c b/apps/earphone/audio_enc_mpt_cvp_ctr.c
new file mode 100644
index 0000000..f96e61b
--- /dev/null
+++ b/apps/earphone/audio_enc_mpt_cvp_ctr.c
@@ -0,0 +1,598 @@
+/*
+ ****************************************************************
+ * Audio Enc Mass production test self CVP control
+ * File : audio_enc_mpt_cvp_crl.c
+ * note : 自研ENC产测 CVP通话算法/MIC 控制层
+ ****************************************************************
+ */
+#include "asm/includes.h"
+#include "media/includes.h"
+#include "system/includes.h"
+#include "aec_user.h"
+#include "app_main.h"
+#include "audio_config.h"
+#include "audio_enc.h"
+#include "audio_enc_mpt_self.h"
+#include "audio_anc.h"
+#include "overlay_code.h"
+
+#if AUDIO_ENC_MPT_SELF_ENABLE
+
+/* #define DUT_CVP_LOG_ENABLE */
+#ifdef DUT_CVP_LOG_ENABLE
+#define dut_cvp_log(x, ...) printf("[enc_mpt_cvp]" x " ", ## __VA_ARGS__)
+#else
+#define dut_cvp_log(...)
+#endif/*DUT_CVP_LOG_ENABLE*/
+
+/*
+ 暂不支持开ANC模式测试
+ 1没有与ANC复用ADC BUFF
+ 2没有开动态MIC增益
+*/
+
+
+extern struct adc_platform_data adc_data;
+extern struct audio_dac_hdl dac_hdl;
+extern struct audio_adc_hdl adc_hdl;
+
+#define MIC_BUF_NUM 3
+#define MIC_IRQ_POINTS 256
+
+#define CVP_MIC_SR 16000 //采样率
+
+#define CVP_MONITOR_DIS 0 //监听关闭
+#define CVP_MONITOR_PROBE 1 //监听处理前数据
+#define CVP_MONITOR_POST 2 //监听处理后数据
+//默认监听选择
+#define CVP_MONITOR_SEL CVP_MONITOR_DIS
+
+typedef struct {
+ u8 dump_cnt;
+ u8 monitor;
+ u8 mic_num; //当前MIC个数
+ u16 mic_id[4];
+ u16 dut_mic_ch;
+ struct audio_adc_output_hdl adc_output;
+ struct adc_mic_ch mic_ch;
+ s16 *tmp_buf[3];
+ s16 *mic_buf;
+} audio_cvp_t;
+static audio_cvp_t *cvp_hdl = NULL;
+
+/* 写卡使能控制, 需注意一下几点
+ 1、需打开 AUDIO_PCM_DEBUG
+ 2、AEC原本的写卡流程需关闭
+ 3、测试流程需包含CVP_OUT测试, 因为写卡只能在线程写
+*/
+#define AUDIO_ENC_MPT_UART_DEBUG_EN 0
+#define AUDIO_ENC_MPT_UART_DEBUG_CH 3 //写卡通道数
+#define AUDIO_ENC_MPT_UART_DEBUG_LEN MIC_IRQ_POINTS * 2 //写卡长度
+
+#ifdef AUDIO_PCM_DEBUG
+extern int aec_uart_init();
+extern int aec_uart_open(u8 nch, u16 single_size);
+extern int aec_uart_fill(u8 ch, void *buf, u16 size);
+extern void aec_uart_write(void);
+extern int aec_uart_close(void);
+#endif/*AUDIO_PCM_DEBUG*/
+
+/*监听输出:默认输出到dac*/
+static int cvp_monitor_output(s16 *data, int len)
+{
+ int wlen = audio_dac_write(&dac_hdl, data, len);
+ if (wlen != len) {
+ dut_cvp_log("monitor output full\n");
+ }
+ return wlen;
+}
+
+/*监听使能*/
+static int cvp_monitor_en(u8 en, int sr)
+{
+ dut_cvp_log("cvp_monitor_en:%d,sr:%d\n", en, sr);
+ if (en) {
+ app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
+ dut_cvp_log("cur_vol:%d,max_sys_vol:%d\n", app_audio_get_volume(APP_AUDIO_STATE_MUSIC), get_max_sys_vol());
+ audio_dac_set_volume(&dac_hdl, app_audio_get_volume(APP_AUDIO_STATE_MUSIC));
+ audio_dac_set_sample_rate(&dac_hdl, sr);
+ audio_dac_start(&dac_hdl);
+ } else {
+ audio_dac_stop(&dac_hdl);
+ }
+ return 0;
+}
+
+/*
+ 测试前的预处理,
+ 如方案使用模拟开关复用ADC通道,可以在此切换模拟开关
+ */
+static void audio_enc_mpt_fre_pre(u16 mic_ch)
+{
+#if 0
+ //测试算法或者TALK 主MIC
+ if (mic_ch & (AUDIO_ENC_MPT_CVP_OUT | AUDIO_ENC_MPT_TALK_MIC)) {
+ }
+ //测试算法或者TALK 副MIC
+ if (mic_ch & (AUDIO_ENC_MPT_CVP_OUT | AUDIO_ENC_MPT_SLAVE_MIC)) {
+ }
+ //测试算法或者TALK FBMIC
+ if (mic_ch & (AUDIO_ENC_MPT_CVP_OUT | AUDIO_ENC_MPT_TALK_FB_MIC)) {
+ }
+ //测试TWS FFMIC or 头戴式LFF MIC
+ if (mic_ch & AUDIO_ENC_MPT_FF_MIC) {
+ }
+ //测试TWS FBMIC or 头戴式LFB MIC
+ if (mic_ch & AUDIO_ENC_MPT_FB_MIC) {
+ }
+ //测试头戴式RFF MIC
+ if (mic_ch & AUDIO_ENC_MPT_RFF_MIC) {
+ }
+ //测试头戴式RFB MIC
+ if (mic_ch & AUDIO_ENC_MPT_RFB_MIC) {
+ }
+#endif
+}
+
+/*mic adc原始数据输出*/
+static void mic_output(void *priv, s16 *data, int len)
+{
+ /* putchar('.'); */
+ s16 *mic_data[cvp_hdl->mic_num];
+ int i;
+ u8 talk_id_cnt = 0xff;
+ //ADC启动不稳定,实测开头大约有50ms 杂音数据, 这里丢弃掉16*8 = 128ms
+ if (cvp_hdl->dump_cnt < 8) {
+ cvp_hdl->dump_cnt++;
+ return;
+ }
+
+ mic_data[0] = data;
+ //printf("mic_data:%x,%x,%d\n",data,mic1_data_pos,len);
+ if (cvp_hdl->mic_num == 2) {
+ mic_data[1] = cvp_hdl->tmp_buf[0];
+ for (u16 i = 0; i < (len >> 1); i++) {
+ mic_data[0][i] = data[i * 2];
+ mic_data[1][i] = data[i * 2 + 1];
+ }
+ mic_data[1] = data + (len / 2);
+ memcpy(mic_data[1], cvp_hdl->tmp_buf[0], len);
+
+ } else if (cvp_hdl->mic_num == 3) {
+ mic_data[1] = cvp_hdl->tmp_buf[0];
+ mic_data[2] = cvp_hdl->tmp_buf[1];
+ for (u16 i = 0; i < (len >> 1); i++) {
+ mic_data[0][i] = data[i * 3];
+ mic_data[1][i] = data[i * 3 + 1];
+ mic_data[2][i] = data[i * 3 + 2];
+ }
+ } else if (cvp_hdl->mic_num == 4) {
+ mic_data[1] = cvp_hdl->tmp_buf[0];
+ mic_data[2] = cvp_hdl->tmp_buf[1];
+ mic_data[3] = cvp_hdl->tmp_buf[2];
+ for (u16 i = 0; i < (len >> 1); i++) {
+ mic_data[0][i] = data[i * 4];
+ mic_data[1][i] = data[i * 4 + 1];
+ mic_data[2][i] = data[i * 4 + 2];
+ mic_data[3][i] = data[i * 4 + 3];
+ }
+ }
+
+ for (i = 0; i < cvp_hdl->mic_num; i++) {
+#if AUDIO_ENC_MPT_UART_DEBUG_EN && (defined AUDIO_PCM_DEBUG)
+ if (cvp_hdl->dut_mic_ch & AUDIO_ENC_MPT_CVP_OUT) {
+ aec_uart_fill(i, mic_data[i], 512);
+ }
+#endif/*AUDIO_ENC_MPT_UART_DEBUG_EN*/
+ audio_enc_mpt_fre_response_inbuf(cvp_hdl->mic_id[i], mic_data[i], len);
+ if (cvp_hdl->dut_mic_ch & AUDIO_ENC_MPT_CVP_OUT) {
+#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
+ if (cvp_hdl->mic_id[i] & AUDIO_ENC_MPT_TALK_FB_MIC) {
+ audio_aec_inbuf_ref_1(mic_data[i], len);
+ continue;
+ }
+#endif/*TCFG_AUDIO_TRIPLE_MIC_ENABLE*/
+#if TCFG_AUDIO_DUAL_MIC_ENABLE || TCFG_AUDIO_TRIPLE_MIC_ENABLE
+ if (cvp_hdl->mic_id[i] & AUDIO_ENC_MPT_SLAVE_MIC) {
+ audio_aec_inbuf_ref(mic_data[i], len);
+ continue;
+ }
+#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE || TCFG_AUDIO_TRIPLE_MIC_ENABLE*/
+ if (cvp_hdl->mic_id[i] & AUDIO_ENC_MPT_TALK_MIC) {
+ talk_id_cnt = i;
+ /* audio_aec_inbuf(mic_data[i], len); */
+ continue;
+ }
+ }
+ }
+
+ //主麦数据输入触发AEC线程,最后处理
+ if (talk_id_cnt != 0xff) { //表示有算法主麦输入
+ audio_aec_inbuf(mic_data[talk_id_cnt], len);
+ }
+
+#if CVP_MONITOR_SEL != CVP_MONITOR_DIS
+ if (cvp_hdl->monitor == CVP_MONITOR_PROBE) {
+ static u8 num = 0;
+ static int cnt = 0;
+ if (++cnt > 300) {
+ cnt = 0;
+ if (++num == cvp_hdl->mic_num) {
+ num = 0;
+ }
+ r_printf("num %d", num);
+ }
+ cvp_monitor_output(mic_data[num], len);
+ }
+#endif/*CVP_MONITOR_SEL != CVP_MONITOR_DIS*/
+}
+
+static u16 audio_enc_mpt_anc_mic_query(u8 mic_type, u16 mic_id, u8 *mic_en, u16 *mic_id_tmp, u8 *gain)
+{
+#if TCFG_AUDIO_ANC_ENABLE
+ u8 i;
+ u8 mic_max = A_MIC3 + 1;
+ for (i = A_MIC0; i < mic_max; i++) {
+ if (mic_type == i) {
+ if (!mic_en[i]) {
+ //此MIC没有开过,则使用ANC的MIC增益
+ gain[i] = audio_anc_mic_gain_get(i);
+ }
+ mic_en[i] = 1;
+ mic_id_tmp[i] |= mic_id;
+ dut_cvp_log("ANC mic%d: anc_id 0x%x, group_id 0x%x, en %x", mic_type, mic_id, mic_id_tmp[i], mic_en[i]);
+ return 0;
+ }
+ }
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+ return 1;
+}
+/*根据mic通道值获取使用的第几个mic*/
+static u8 get_mic_num(u8 bit)
+{
+ u8 i = 0;
+ for (i = 0; i < 4; i++) {
+ if (bit & 0x1) {
+ return i;
+ }
+ bit >>= 1;
+ }
+ return 0;
+}
+
+static const u16 call_mic_id[2] = {AUDIO_ENC_MPT_TALK_MIC, AUDIO_ENC_MPT_SLAVE_MIC};
+static int mic_open(u8 *mic_gain, int sr)
+{
+ int i, j;
+ u8 mic_en[4] = {0};
+ u16 mic_id_tmp[4] = {0};
+
+ dut_cvp_log("mic open sr: %d,mic_gain:%d %d %d %d\n", sr, mic_gain[0], mic_gain[1], mic_gain[2], mic_gain[3]);
+
+ cvp_hdl->dump_cnt = 0;
+ //1.测试CVP的输出 or 通话MIC相关 MIC输出
+ if (cvp_hdl->dut_mic_ch & (AUDIO_ENC_MPT_CVP_OUT | AUDIO_ENC_MPT_TALK_MIC | \
+ AUDIO_ENC_MPT_SLAVE_MIC | AUDIO_ENC_MPT_TALK_FB_MIC)) {
+#if TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_0
+ mic_en[0] = 1;
+ mic_id_tmp[0] = 1;
+#endif
+#if TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_1
+ mic_en[1] = 1;
+ mic_id_tmp[1] = 1;
+#endif
+#if TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_2
+ mic_en[2] = 1;
+ mic_id_tmp[2] = 1;
+#endif
+#if TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_3
+ mic_en[3] = 1;
+ mic_id_tmp[3] = 1;
+#endif
+
+#if TCFG_AUDIO_DUAL_MIC_ENABLE
+ //1.1 确定主副MIC-仅支持双麦定位,三麦目前还不支持
+#if (TCFG_AUDIO_DMS_MIC_MANAGE == DMS_MASTER_MIC0)
+ u8 call_cnt = 0;
+ for (i = 0; i < 4; i++) {
+ if (mic_id_tmp[i]) {
+ mic_id_tmp[i] = call_mic_id[call_cnt++];
+ }
+ }
+#else
+ u8 call_cnt = 1;
+ for (i = 0; i < 4; i++) {
+ if (mic_id_tmp[i]) {
+ mic_id_tmp[i] = call_mic_id[call_cnt--];
+ }
+ }
+#endif
+#elif TCFG_AUDIO_TRIPLE_MIC_ENABLE //三麦通话
+ //三麦通话目前需手动指定mic类型
+ mic_id_tmp[get_mic_num(app_var.talk_mic_ch)] = AUDIO_ENC_MPT_TALK_MIC;
+ mic_id_tmp[get_mic_num(app_var.talk_ref_mic_ch)] = AUDIO_ENC_MPT_SLAVE_MIC;
+ mic_id_tmp[get_mic_num(app_var.talk_fb_mic_ch)] = AUDIO_ENC_MPT_TALK_FB_MIC;
+ /* mic_id_tmp[3] = ; */
+
+#else /*单麦通话*/
+ for (i = 0; i < 4; i++) {
+ if (mic_id_tmp[i]) {
+ mic_id_tmp[i] = AUDIO_ENC_MPT_TALK_MIC;
+ break;
+ }
+ }
+#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
+
+
+ }
+ //2.只测通话MIC,不测试算法输出
+ if (!(cvp_hdl->dut_mic_ch & AUDIO_ENC_MPT_CVP_OUT)) {
+ for (i = 0; i < 4; i++) {
+ //清除非目标MIC的使能
+ if (!(cvp_hdl->dut_mic_ch & mic_id_tmp[i])) {
+ mic_id_tmp[i] = 0;
+ mic_en[i] = 0;
+ }
+ }
+ }
+
+ //3.ANC MIC映射
+#if TCFG_AUDIO_ANC_ENABLE
+ if (cvp_hdl->dut_mic_ch & AUDIO_ENC_MPT_FF_MIC) {
+#if TCFG_USER_TWS_ENABLE && (ANC_CH == ANC_R_CH)
+ audio_enc_mpt_anc_mic_query(ANCR_FF_MIC, AUDIO_ENC_MPT_FF_MIC, mic_en, mic_id_tmp, mic_gain);
+#else
+ audio_enc_mpt_anc_mic_query(ANCL_FF_MIC, AUDIO_ENC_MPT_FF_MIC, mic_en, mic_id_tmp, mic_gain);
+#endif/*TCFG_USER_TWS_ENABLE && (ANC_CH == ANC_R_CH)*/
+ }
+ if (cvp_hdl->dut_mic_ch & AUDIO_ENC_MPT_FB_MIC) {
+#if TCFG_USER_TWS_ENABLE && (ANC_CH == ANC_R_CH)
+ audio_enc_mpt_anc_mic_query(ANCR_FB_MIC, AUDIO_ENC_MPT_FB_MIC, mic_en, mic_id_tmp, mic_gain);
+#else
+ audio_enc_mpt_anc_mic_query(ANCL_FB_MIC, AUDIO_ENC_MPT_FB_MIC, mic_en, mic_id_tmp, mic_gain);
+#endif/*TCFG_USER_TWS_ENABLE && (ANC_CH == ANC_R_CH)*/
+ }
+ if (cvp_hdl->dut_mic_ch & AUDIO_ENC_MPT_RFF_MIC) {
+ audio_enc_mpt_anc_mic_query(ANCR_FF_MIC, AUDIO_ENC_MPT_RFF_MIC, mic_en, mic_id_tmp, mic_gain);
+ }
+ if (cvp_hdl->dut_mic_ch & AUDIO_ENC_MPT_RFB_MIC) {
+ audio_enc_mpt_anc_mic_query(ANCR_FB_MIC, AUDIO_ENC_MPT_RFB_MIC, mic_en, mic_id_tmp, mic_gain);
+ }
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+
+ //4.重新排列数组, 兼容ADC_BUFF的缓存结构
+ j = 0;
+ for (i = 0; i < 4; i++) {
+ if (mic_id_tmp[i]) {
+ cvp_hdl->mic_id[j++] = mic_id_tmp[i];
+ }
+ }
+
+ //5.ADC初始化
+ audio_mic_pwr_ctl(MIC_PWR_ON);
+ if (cvp_hdl) {
+ if (mic_en[0]) {
+ cvp_hdl->mic_num++;
+ audio_adc_mic_open(&cvp_hdl->mic_ch, AUDIO_ADC_MIC_0, &adc_hdl);
+ audio_adc_mic_set_gain(&cvp_hdl->mic_ch, mic_gain[0]);
+ }
+ if (mic_en[1]) {
+ cvp_hdl->mic_num++;
+ audio_adc_mic1_open(&cvp_hdl->mic_ch, AUDIO_ADC_MIC_1, &adc_hdl);
+ audio_adc_mic1_set_gain(&cvp_hdl->mic_ch, mic_gain[1]);
+ }
+ if (mic_en[2]) {
+ cvp_hdl->mic_num++;
+ audio_adc_mic2_open(&cvp_hdl->mic_ch, AUDIO_ADC_MIC_2, &adc_hdl);
+ audio_adc_mic2_set_gain(&cvp_hdl->mic_ch, mic_gain[2]);
+ }
+ if (mic_en[3]) {
+ cvp_hdl->mic_num++;
+ audio_adc_mic3_open(&cvp_hdl->mic_ch, AUDIO_ADC_MIC_3, &adc_hdl);
+ audio_adc_mic3_set_gain(&cvp_hdl->mic_ch, mic_gain[3]);
+ }
+
+ if (!cvp_hdl->mic_num) {
+ dut_cvp_log("Error valid mic_num is zero!\n");
+ return 1;
+ }
+
+ //5.1 ADC临时BUFF、ISR BUFF申请
+ for (i = 1; i < cvp_hdl->mic_num; i++) {
+ cvp_hdl->tmp_buf[i - 1] = malloc(MIC_IRQ_POINTS * sizeof(short));
+ }
+ cvp_hdl->mic_buf = malloc(cvp_hdl->mic_num * MIC_BUF_NUM * MIC_IRQ_POINTS * sizeof(short));
+
+ audio_adc_mic_set_sample_rate(&cvp_hdl->mic_ch, sr);
+ audio_adc_mic_set_buffs(&cvp_hdl->mic_ch, cvp_hdl->mic_buf, MIC_IRQ_POINTS * 2, MIC_BUF_NUM);
+
+ cvp_hdl->adc_output.handler = mic_output;
+ audio_adc_add_output_handler(&adc_hdl, &cvp_hdl->adc_output);
+ audio_adc_mic_start(&cvp_hdl->mic_ch);
+ }
+ dut_cvp_log("mic_open succ mic_num %d\n", cvp_hdl->mic_num);
+ for (i = 0; i < 4; i++) {
+ dut_cvp_log("mic%d_id 0x%x, en %d, gain %d\n", i, cvp_hdl->mic_id[i], mic_en[i], mic_gain[i]);
+ }
+ return 0;
+}
+
+static void mic_close(void)
+{
+ if (cvp_hdl) {
+ audio_adc_mic_close(&cvp_hdl->mic_ch);
+ audio_adc_del_output_handler(&adc_hdl, &cvp_hdl->adc_output);
+ for (int i = 1; i < cvp_hdl->mic_num; i++) {
+ free(cvp_hdl->tmp_buf[i - 1]);
+ }
+ free(cvp_hdl->mic_buf);
+ audio_mic_pwr_ctl(MIC_PWR_OFF);
+ }
+}
+
+/*清晰语音数据输出*/
+static int cvp_output_hdl(s16 *data, u16 len)
+{
+ /* putchar('o'); */
+
+ audio_enc_mpt_fre_response_inbuf(AUDIO_ENC_MPT_CVP_OUT, data, len);
+#if AUDIO_ENC_MPT_UART_DEBUG_EN && (defined AUDIO_PCM_DEBUG)
+ if (cvp_hdl->dut_mic_ch & AUDIO_ENC_MPT_CVP_OUT) {
+ aec_uart_fill(2, data, 512);
+ aec_uart_write();
+ }
+#endif/*AUDIO_ENC_MPT_UART_DEBUG_EN*/
+#if !AUDIO_ENC_MPT_FRERES_ASYNC
+ audio_enc_mpt_fre_response_post_run(0);
+#endif/*AUDIO_ENC_MPT_FRERES_ASYNC*/
+
+#if CVP_MONITOR_SEL != CVP_MONITOR_DIS
+ if (cvp_hdl->monitor == CVP_MONITOR_POST) {
+ cvp_monitor_output(data, len);
+ }
+#endif/*CVP_MONITOR_SEL != CVP_MONITOR_DIS*/
+ return len;
+}
+
+int audio_enc_mpt_cvp_close(void)
+{
+ if (cvp_hdl != NULL) {
+#if AUDIO_ENC_MPT_UART_DEBUG_EN && (defined AUDIO_PCM_DEBUG)
+ if (cvp_hdl->dut_mic_ch & AUDIO_ENC_MPT_CVP_OUT) {
+ aec_uart_close();
+ }
+#endif/*AUDIO_ENC_MPT_UART_DEBUG_EN*/
+#if CVP_MONITOR_SEL != CVP_MONITOR_DIS
+ if (cvp_hdl->monitor) {
+ cvp_monitor_en(0, CVP_MIC_SR);
+ }
+#endif/* CVP_MONITOR_SEL != CVP_MONITOR_DIS*/
+ if (cvp_hdl->dut_mic_ch & AUDIO_ENC_MPT_CVP_OUT) {
+ audio_aec_close();
+ }
+ //先关AEC再关MIC
+ mic_close();
+ free(cvp_hdl);
+ cvp_hdl = NULL;
+ dut_cvp_log("cvp_hdl close\n");
+ }
+ return 0;
+}
+
+int audio_enc_mpt_cvp_open(u16 mic_ch)
+{
+ int ret = 0;
+ u8 mic_gain[4];
+ if (cvp_hdl) {
+ //支持重入
+ audio_enc_mpt_cvp_close();
+ dut_cvp_log("dut_cvp start again\n");
+ }
+#if AUDIO_ENC_MPT_UART_DEBUG_EN && (defined AUDIO_PCM_DEBUG)
+ if (mic_ch & AUDIO_ENC_MPT_CVP_OUT) {
+ aec_uart_open(AUDIO_ENC_MPT_UART_DEBUG_CH, AUDIO_ENC_MPT_UART_DEBUG_LEN);
+ }
+#endif/*AUDIO_ENC_MPT_UART_DEBUG_EN*/
+ dut_cvp_log("cvp_hdl open, mic_ch %x\n", mic_ch);
+ cvp_hdl = zalloc(sizeof(audio_cvp_t));
+ ASSERT(cvp_hdl);
+ audio_enc_mpt_fre_pre(mic_ch);
+#if CVP_MONITOR_SEL != CVP_MONITOR_DIS
+ cvp_hdl->monitor = CVP_MONITOR_SEL;
+ if (cvp_hdl->monitor) {
+ cvp_monitor_en(1, CVP_MIC_SR);
+ }
+#endif/* CVP_MONITOR_SEL != CVP_MONITOR_DIS*/
+ cvp_hdl->dut_mic_ch = mic_ch;
+ mic_gain[0] = app_var.aec_mic_gain;
+ mic_gain[1] = app_var.aec_mic1_gain;
+ mic_gain[2] = app_var.aec_mic2_gain;
+ mic_gain[3] = app_var.aec_mic3_gain;
+
+ if (cvp_hdl->dut_mic_ch & AUDIO_ENC_MPT_CVP_OUT) {
+ overlay_load_code(OVERLAY_AEC);
+ audio_aec_open(CVP_MIC_SR, -1, cvp_output_hdl);
+#if 1//TCFG_AUDIO_CVP_NS_MODE == CVP_DNS_MODE
+ //默认关闭DNS
+ audio_cvp_ioctl(CVP_NS_SWITCH, 0, NULL); //降噪关
+#endif/*TCFG_AUDIO_CVP_NS_MODE*/
+ }
+ ret = mic_open(mic_gain, CVP_MIC_SR);
+ //由于产测对时钟设置不敏感,因此暂定128M
+ if (clk_get("sys") < 128 * 1000000L) {
+ clk_set("sys", 128 * 1000000L);
+ }
+ return ret;
+}
+
+void audio_enc_mpt_fre_response_open(u16 mic_ch)
+{
+#if TCFG_AUDIO_ANC_ENABLE
+ //设置为ANC产测模式
+ audio_anc_prodution_mode_set(1);
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+ audio_enc_mpt_fre_response_start(mic_ch);
+ if (audio_enc_mpt_cvp_open(mic_ch)) {
+ audio_enc_mpt_fre_response_release();
+ }
+}
+
+void audio_enc_mpt_fre_response_close(void)
+{
+ audio_enc_mpt_fre_response_stop();
+ audio_enc_mpt_cvp_close();
+}
+
+
+static u8 audio_cvp_idle_query()
+{
+ return (cvp_hdl == NULL) ? 1 : 0;
+}
+
+REGISTER_LP_TARGET(audio_cvp_lp_target) = {
+ .name = "audio_cvp",
+ .is_idle = audio_cvp_idle_query,
+};
+
+//测试func
+void audio_enc_mpt_cvp_key_test()
+{
+ static u8 cnt = 0;
+ u16 mic_ch = 0;
+ dut_cvp_log("cnt %d\n", cnt);
+
+ mem_stats();
+ switch (cnt) {
+ case 0:
+ app_var.aec_mic_gain = 15;
+ app_var.aec_mic1_gain = 15;
+ app_var.aec_mic2_gain = 15;
+ app_var.aec_mic3_gain = 15;
+ mic_ch |= AUDIO_ENC_MPT_CVP_OUT;
+ mic_ch |= AUDIO_ENC_MPT_TALK_MIC;
+ /* mic_ch |= AUDIO_ENC_MPT_SLAVE_MIC; */
+ /* mic_ch |= AUDIO_ENC_MPT_TALK_FB_MIC; */
+ /* mic_ch |= AUDIO_ENC_MPT_FF_MIC; */
+ /* mic_ch |= AUDIO_ENC_MPT_FB_MIC; */
+ /* mic_ch |= AUDIO_ENC_MPT_RFF_MIC; */
+ /* mic_ch |= AUDIO_ENC_MPT_RFB_MIC; */
+ audio_enc_mpt_fre_response_open(mic_ch);
+ break;
+ case 1:
+ audio_enc_mpt_fre_response_close();
+ break;
+ case 2:
+ u8 *buf;
+ audio_enc_mpt_fre_response_file_get(&buf);
+ break;
+ case 3:
+ audio_enc_mpt_fre_response_release();
+ break;
+ }
+ cnt++;
+ if (cnt > 3) {
+ cnt = 0;
+ }
+}
+
+#endif/*AUDIO_ENC_MPT_SELF_ENABLE*/
diff --git a/apps/earphone/audio_enc_mpt_self.c b/apps/earphone/audio_enc_mpt_self.c
new file mode 100644
index 0000000..ad142d3
--- /dev/null
+++ b/apps/earphone/audio_enc_mpt_self.c
@@ -0,0 +1,434 @@
+
+/***********************************************************
+
+ * Audio Enc Mass production test self
+ * File : audio_enc_mpt_self.c
+ * note : 自研ENC产测 声学频响测试
+
+************************************************************/
+
+#include "hw_fft.h"
+#include "app_config.h"
+#include "audio_enc_mpt_self.h"
+#include "generic/list.h"
+#include "system/task.h"
+
+#if 0
+#define encmpt_log(x, ...) printf("[enc_mpt]" x " ", ## __VA_ARGS__)
+#else
+#define encmpt_log(...)
+#endif/*log_en*/
+
+#if AUDIO_ENC_MPT_SELF_ENABLE
+
+void anc_HpEst_psd(s16 *input0, float *out0_sum, int len, int *cnt);
+void anc_HpEst_psd_out(float *out0_sum, int flen, int cnt);
+
+//输出数据类型
+typedef float ENC_OUT_TYPE;
+/* typedef short ENC_OUT_TYPE; */
+
+typedef struct {
+ struct list_head entry;
+ u16 id; //对应数据通道id
+ u16 len; //长度
+ int cnt; //计算次数
+ s16 *in; //输入地址
+ ENC_OUT_TYPE *out; //输出地址
+} enc_freres_bulk;
+
+typedef struct {
+ u16 version;
+ u16 cnt;
+ u8 dat[0]; //小心double访问非对齐异常
+} enc_freres_file_t;
+
+typedef struct {
+ u32 id;
+ u32 offset;
+ u32 len;
+} enc_freres_file_head_t;
+
+typedef struct {
+ volatile u8 state; //状态
+ u8 run_busy;
+ u8 inbuf_busy;
+ u16 ch; //目标通道
+ /* enc_freres_bulk bulk[5];//链表,最长支持5段 */
+ enc_freres_bulk *bulk;//链表,动态申请不定长
+ u8 *file_data; //输出文件
+ int file_len; //输出文件长度
+ int in_packet_len;
+ struct list_head head;
+} audio_fre_respone_t;
+
+static audio_fre_respone_t *hdl;
+
+#if 0 //输入数据连续性验证
+u8 *data1;
+u8 *data2;
+u8 *data3;
+#define ENC_CHECK_LEN 8192
+static u8 ainit = 0;
+static u16 offset1 = 0;
+static u16 offset2 = 0;
+static u16 offset3 = 0;
+void audio_enc_mpt_inbuf_check(u16 id, s16 *buf, int len)
+{
+ if (!ainit) {
+ ainit = 1;
+ data1 = zalloc(ENC_CHECK_LEN);
+ data2 = zalloc(ENC_CHECK_LEN);
+ data3 = zalloc(ENC_CHECK_LEN);
+ }
+ if (id & AUDIO_ENC_MPT_FF_MIC) {
+ if ((offset1 + len) > ENC_CHECK_LEN) {
+ offset1 = 0;
+ }
+ memcpy(data1 + offset1, (u8 *)buf, len);
+ offset1 += len;
+ }
+ if (id & AUDIO_ENC_MPT_TALK_MIC) {
+ if ((offset2 + len) > ENC_CHECK_LEN) {
+ offset2 = 0;
+ }
+ memcpy(data2 + offset2, (u8 *)buf, len);
+ offset2 += len;
+ }
+ if (id & AUDIO_ENC_MPT_CVP_OUT) {
+ if ((offset3 + len) > ENC_CHECK_LEN) {
+ offset3 = 0;
+ }
+ memcpy(data3 + offset3, (u8 *)buf, len);
+ offset3 += len;
+ }
+}
+
+void audio_enc_mpt_inbuf_printf(void)
+{
+ int i = 0;
+ s16 *dat1 = (s16 *)data1;
+ s16 *dat2 = (s16 *)data2;
+ s16 *dat3 = (s16 *)data3;
+ encmpt_log("ff");
+ for (i = 0; i < ENC_CHECK_LEN / 2; i++) {
+ printf("%d\n", dat1[i]);
+ }
+
+ encmpt_log("TALK");
+ for (i = 0; i < ENC_CHECK_LEN / 2; i++) {
+ printf("%d\n", dat2[i]);
+ }
+
+ encmpt_log("cvp");
+ for (i = 0; i < ENC_CHECK_LEN / 2; i++) {
+ printf("%d\n", dat3[i]);
+ }
+}
+#endif/*默认关闭*/
+
+//id = 0 计算链表所有满足长度的节点;
+static void audio_enc_mpt_fre_response_process(u16 id)
+{
+ /* return; */
+ enc_freres_bulk *bulk;
+ if (hdl->state != ENC_FRE_RES_STATE_RUN) {
+ return;
+ }
+
+ hdl->run_busy = 1;
+ list_for_each_entry(bulk, &hdl->head, entry) {
+ //原始数据指针、目标输出指针、计算长度
+ if ((!id) || id == bulk->id) {
+ if (bulk->len >= hdl->in_packet_len) {
+ anc_HpEst_psd(bulk->in, bulk->out, AUDIO_ENC_MPT_FRERES_POINT, &bulk->cnt);
+ bulk->len -= (hdl->in_packet_len >> 1);
+ /* encmpt_log("process id 0X%x len %d\n", bulk->id, bulk->len); */
+ if (bulk->len) { //overlap
+ memcpy(bulk->in, bulk->in + (hdl->in_packet_len >> 2), bulk->len);
+ }
+ }
+ }
+ }
+ hdl->run_busy = 0;
+}
+
+static void audio_enc_mpt_fre_resonpse_task(void *p)
+{
+ int res;
+ int msg[16];
+ u32 pend_timeout = portMAX_DELAY;
+ encmpt_log(">>>audio_fre_res_task<<<\n");
+ while (1) {
+ res = os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
+ if (res == OS_TASKQ) {
+ switch (msg[1]) {
+ case ENC_FRE_RESPONE_MSG_RUN:
+ audio_enc_mpt_fre_response_process((u16)msg[2]);
+ break;
+ }
+ } else {
+ encmpt_log("res:%d,%d", res, msg[1]);
+ }
+ }
+
+}
+
+//初始化链表以及的通道内容
+static void audio_enc_mpt_fre_response_bulk_init(enc_freres_file_t *file, u8 cnt, u16 id)
+{
+ u8 *data_home;
+ enc_freres_file_head_t *file_head = file->dat;
+
+ /* if (cnt > 4) { */
+ /* encmpt_log("ERR:Audio enc Fre bulk full!!!\n"); */
+ /* return; */
+ /* } */
+
+ data_home = file->dat + (file->cnt * 12);
+
+ //file初始化head
+ file_head[cnt].id = id;
+ //len(byte)
+ file_head[cnt].len = AUDIO_ENC_MPT_FRERES_POINT / 2 * sizeof(ENC_OUT_TYPE);
+ if (cnt) {
+ file_head[cnt].offset = file_head[cnt - 1].len + file_head[cnt - 1].offset;
+ } else {
+ file_head[cnt].offset = 0;
+ }
+
+ hdl->bulk[cnt].id = id;
+ hdl->bulk[cnt].out = (ENC_OUT_TYPE *)(data_home + file_head[cnt].offset);
+ hdl->bulk[cnt].in = (s16 *)malloc(AUDIO_ENC_MPT_FRERES_POINT * sizeof(short));
+ encmpt_log("hdl %x file %x, out %x, data_home %x, inbuf_len %d\n", (int)hdl->file_data, (int)file, \
+ (int)hdl->bulk[cnt].out, (int)data_home, AUDIO_ENC_MPT_FRERES_POINT * sizeof(short));
+ //len(byte)
+ hdl->bulk[cnt].len = 0;
+ /* hdl->bulk[cnt].len = AUDIO_ENC_MPT_FRERES_POINT * sizeof(short); */
+ list_add_tail(&hdl->bulk[cnt].entry, &hdl->head);
+}
+
+//文件内存申请,结构初始化
+static enc_freres_file_t *audio_enc_mpt_fre_response_file_init(int cnt)
+{
+ enc_freres_file_t *file;
+ //4byte(vesion + cnt) + cnt * (12byte (id + offset + len) + outdata)
+ //以目标file文件组成结构申请空间
+ //data => 复数取平方和, 因此POINT/2
+ hdl->file_len = 4 + cnt * (12 + AUDIO_ENC_MPT_FRERES_POINT / 2 * sizeof(ENC_OUT_TYPE));
+
+#if 0
+ //评估内存是否满足当前需求
+ extern size_t xPortGetPhysiceMemorySize(void);
+ int cur_mem_size = xPortGetPhysiceMemorySize();
+ if (cur_mem_size < hdl->file_len + 2000) { //至少余量多2000byte 才可使用该功能
+ printf("ERR!!!MIC_FFT debug_buf:%lu + 2000,free_mem:%d\n", hdl->file_len, cur_mem_size);
+ return NULL;
+ }
+#endif
+ encmpt_log("file init len %d\n", hdl->file_len);
+ hdl->file_data = zalloc(hdl->file_len);
+ file = (enc_freres_file_t *) hdl->file_data;
+ file->cnt = cnt;
+ return file;
+}
+
+//音频测试频响计算启动, ch 对应目标的通道
+void audio_enc_mpt_fre_response_start(u16 ch)
+{
+ enc_freres_file_t *file;
+ int cnt = 0;
+ int shift_det = 0;
+ u16 det_ch = ch;
+ int det_cnt = 0;
+ encmpt_log("%s, ch 0x%x\n", __func__, ch);
+ if (!ch) {
+ return;
+ }
+ if (hdl) {
+ //支持重入
+ hdl->state = ENC_FRE_RES_STATE_START;
+ audio_enc_mpt_fre_response_release();
+ encmpt_log("enc_fre start again\n");
+ }
+#if AUDIO_ENC_MPT_FRERES_ASYNC
+ task_create(audio_enc_mpt_fre_resonpse_task, NULL, "enc_mpt_self");
+#endif/*AUDIO_ENC_MPT_FRERES_ASYNC*/
+
+ hdl = zalloc(sizeof(audio_fre_respone_t));
+ hdl->ch = ch;
+ hdl->in_packet_len = AUDIO_ENC_MPT_FRERES_POINT * sizeof(short);
+
+ while (det_ch) {
+ if (det_ch & BIT(0)) {
+ det_cnt++;
+ }
+ det_ch >>= 1;
+ }
+ file = audio_enc_mpt_fre_response_file_init(det_cnt);
+ if (!file) {
+ free(hdl);
+ return;
+ }
+
+ //链表初始化
+ INIT_LIST_HEAD(&hdl->head);
+
+ //申请链表空间
+ hdl->bulk = zalloc(sizeof(enc_freres_bulk) * det_cnt);
+ encmpt_log("det_cnt %d, list bulk size %d\n", det_cnt, sizeof(enc_freres_bulk) * det_cnt);
+
+ while (ch) {
+ if (ch & BIT(0)) {
+ audio_enc_mpt_fre_response_bulk_init(file, cnt, BIT(shift_det));
+ encmpt_log("list init %x\n", BIT(shift_det));
+ cnt++;
+ }
+ shift_det++;
+ ch >>= 1;
+ }
+ hdl->state = ENC_FRE_RES_STATE_RUN;
+}
+
+
+//更新目标通道输入buf、len
+void audio_enc_mpt_fre_response_inbuf(u16 id, s16 *buf, int len)
+{
+ //len(byte)
+ if (!hdl) {
+ goto __err1;
+ /* return; */
+ }
+ if (hdl->state != ENC_FRE_RES_STATE_RUN) {
+ goto __err1;
+ /* return; */
+ }
+ enc_freres_bulk *bulk;
+ hdl->inbuf_busy = 1;
+ list_for_each_entry(bulk, &hdl->head, entry) {
+ if (id & bulk->id) {
+ /* bulk->id = id; */
+ if ((bulk->len + len) <= hdl->in_packet_len) {
+ /* encmpt_log("inbuf id 0X%x, len %d, %d\n", id, bulk->len, len); */
+ memcpy(((u8 *)bulk->in) + bulk->len, (u8 *)buf, len);
+ bulk->len += len;
+ } else if (bulk->len < hdl->in_packet_len) {
+ encmpt_log("id 0X%x, inbuf soon be full\n", id);
+ memcpy(bulk->in + (bulk->len >> 1), buf, hdl->in_packet_len - bulk->len);
+ bulk->len = hdl->in_packet_len;
+ } else {
+ encmpt_log("id 0X%x, inbuf full\n", id);
+ }
+#if AUDIO_ENC_MPT_FRERES_ASYNC
+ if (bulk->len >= hdl->in_packet_len) {
+ audio_enc_mpt_fre_response_post_run(bulk->id);
+ }
+#endif/*AUDIO_ENC_MPT_FRERES_ASYNC*/
+
+ }
+ }
+ hdl->inbuf_busy = 0;
+
+ return;
+__err1:
+ /* encmpt_log("inbuf err\n"); */
+ int i = 0;
+ while (id) {
+ if (id & BIT(0)) {
+ putchar('0' + i);
+ }
+ id >>= 1;
+ i++;
+ }
+}
+
+//音频测试频响计算运行
+void audio_enc_mpt_fre_response_post_run(u16 id)
+{
+ if (!hdl) {
+ return;
+ }
+ if (hdl->state != ENC_FRE_RES_STATE_RUN) {
+ return;
+ }
+#if AUDIO_ENC_MPT_FRERES_ASYNC
+ os_taskq_post_msg("enc_mpt_self", 2, ENC_FRE_RESPONE_MSG_RUN, id);
+#else
+ audio_enc_mpt_fre_response_process(0);
+#endif/*AUDIO_ENC_MPT_FRERES_ASYNC*/
+}
+
+//音频测试频响计算停止
+void audio_enc_mpt_fre_response_stop(void)
+{
+ if (!hdl) {
+ return;
+ }
+ encmpt_log("%s \n", __func__);
+ enc_freres_bulk *bulk;
+ hdl->state = ENC_FRE_RES_STATE_STOP;
+ while (hdl->inbuf_busy || hdl->run_busy) {
+ os_time_dly(1);
+ };
+ list_for_each_entry(bulk, &hdl->head, entry) {
+ if (bulk->cnt) {
+ //数据只有实部,因此 point >> 1
+ anc_HpEst_psd_out(bulk->out, AUDIO_ENC_MPT_FRERES_POINT >> 1, bulk->cnt);
+ /* encmpt_log("cnt %d \n", bulk->cnt); */
+ }
+ }
+ encmpt_log("%s ok\n", __func__);
+}
+
+//工具获取数据文件
+int audio_enc_mpt_fre_response_file_get(u8 **buf)
+{
+ if (!hdl) {
+ return 0;
+ }
+ encmpt_log("%s, len %d\n", __func__, hdl->file_len);
+ *buf = hdl->file_data;
+ /* audio_enc_mpt_inbuf_printf(); */
+ /* put_buf(hdl->file_data + 40, hdl->file_len - 40); */
+#if 0//debug
+ enc_freres_bulk *bulk;
+ int point = AUDIO_ENC_MPT_FRERES_POINT / 2;
+ list_for_each_entry(bulk, &hdl->head, entry) {
+ encmpt_log("bulk id 0X%x\n", bulk->id);
+ for (int i = 0; i < point; i++) {
+ printf("%d\n", (int)(bulk->out[i] * 10000));
+ }
+ }
+#endif
+ return hdl->file_len;
+}
+
+//数据获取结束,释放内存
+void audio_enc_mpt_fre_response_release(void)
+{
+ if (!hdl) {
+ return;
+ }
+ //mic_close
+ encmpt_log("%s\n", __func__);
+ while (hdl->inbuf_busy || hdl->run_busy) {
+ os_time_dly(1);
+ };
+#if AUDIO_ENC_MPT_FRERES_ASYNC
+ task_kill("enc_mpt_self");
+#endif/*AUDIO_ENC_MPT_FRERES_ASYNC*/
+ enc_freres_bulk *bulk;
+ list_for_each_entry(bulk, &hdl->head, entry) {
+ free(bulk->in);
+ }
+ free(hdl->file_data);
+ free(hdl->bulk);
+ free(hdl);
+ hdl = NULL;
+ encmpt_log("%s ok\n", __func__);
+}
+
+
+
+
+#endif/*AUDIO_ENC_MPT_SELF_ENABLE*/
diff --git a/apps/earphone/ble_adv.c b/apps/earphone/ble_adv.c
new file mode 100644
index 0000000..7b8359e
--- /dev/null
+++ b/apps/earphone/ble_adv.c
@@ -0,0 +1,233 @@
+#include "app_config.h"
+
+
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV)
+
+#include "earphone.h"
+#include "app_main.h"
+#include "include/bt_ble.h"
+#include "bt_common.h"
+#include "btstack/avctp_user.h"
+#include "system/includes.h"
+#include "bt_tws.h"
+
+#define LOG_TAG "[BLE-ADV]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+typedef struct {
+ u8 miss_flag: 1;
+ u8 exchange_bat: 2;
+ u8 poweron_flag: 1;
+ u8 reserver: 4;
+} icon_ctl_t;
+
+static icon_ctl_t ble_icon_contrl;
+
+
+int adv_earphone_state_set_page_scan_enable()
+{
+#if (TCFG_USER_TWS_ENABLE == 0)
+ bt_ble_icon_open(ICON_TYPE_INQUIRY);
+#elif (CONFIG_NO_DISPLAY_BUTTON_ICON || !TCFG_CHARGESTORE_ENABLE)
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ printf("switch_icon_ctl11...\n");
+ bt_ble_icon_open(ICON_TYPE_INQUIRY);
+ }
+#endif
+ return 0;
+}
+
+int adv_earphone_state_get_connect_mac_addr()
+{
+ return 0;
+}
+
+int adv_earphone_state_cancel_page_scan()
+{
+#if (TCFG_USER_TWS_ENABLE == 1)
+#if (CONFIG_NO_DISPLAY_BUTTON_ICON || !TCFG_CHARGESTORE_ENABLE)
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ if (ble_icon_contrl.miss_flag) {
+ ble_icon_contrl.miss_flag = 0;
+ puts("ble_icon_contrl.miss_flag...\n");
+ } else {
+ printf("switch_icon_ctl00...\n");
+ bt_ble_icon_open(ICON_TYPE_INQUIRY);
+ }
+ }
+#endif
+#endif
+ return 0;
+}
+
+int adv_earphone_state_tws_init(int paired)
+{
+ memset(&ble_icon_contrl, 0, sizeof(icon_ctl_t));
+ ble_icon_contrl.poweron_flag = 1;
+
+ if (paired) {
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ bt_ble_set_control_en(1);
+ } else {
+ //slave close
+ bt_ble_set_control_en(0);
+ }
+ } else {
+
+ }
+
+ return 0;
+}
+
+int adv_earphone_state_tws_connected(int first_pair, u8 *comm_addr)
+{
+ if (first_pair) {
+ bt_ble_icon_set_comm_address(comm_addr);
+ }
+ return 0;
+}
+
+int adv_earphone_state_enter_soft_poweroff()
+{
+#if (!TCFG_CHARGESTORE_ENABLE)
+ //非智能充电仓时,做停止广播操作
+ if (bt_ble_icon_get_adv_state() != ADV_ST_NULL &&
+ bt_ble_icon_get_adv_state() != ADV_ST_END) {
+ bt_ble_icon_close(1);
+ os_time_dly(50);//盒盖时间,根据效果调整时间
+ }
+#endif
+ bt_ble_exit();
+ return 0;
+}
+
+
+
+int ble_adv_hci_event_handler(struct bt_event *bt)
+{
+ switch (bt->event) {
+ case HCI_EVENT_CONNECTION_COMPLETE:
+ switch (bt->value) {
+ case ERROR_CODE_PIN_OR_KEY_MISSING:
+#if (CONFIG_NO_DISPLAY_BUTTON_ICON && TCFG_CHARGESTORE_ENABLE)
+ //已取消配对了
+ if (bt_ble_icon_get_adv_state() == ADV_ST_RECONN) {
+ //切换广播
+ bt_ble_icon_open(ICON_TYPE_INQUIRY);
+ }
+#endif
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+void ble_adv_bt_tws_event_handler(struct bt_event *bt)
+{
+ int role = bt->args[0];
+ int phone_link_connection = bt->args[1];
+ int reason = bt->args[2];
+
+ switch (bt->event) {
+ case TWS_EVENT_CONNECTED:
+ bt_ble_icon_slave_en(1);
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ //master enable
+ log_info("master do icon_open\n");
+ bt_ble_set_control_en(1);
+
+ if (phone_link_connection) {
+ bt_ble_icon_open(ICON_TYPE_RECONNECT);
+ } else {
+#if (TCFG_CHARGESTORE_ENABLE && !CONFIG_NO_DISPLAY_BUTTON_ICON)
+ bt_ble_icon_open(ICON_TYPE_RECONNECT);
+#else
+ if (ble_icon_contrl.poweron_flag) { //上电标记
+ if (bt_user_priv_var.auto_connection_counter > 0) {
+ //有回连手机动作
+ /* g_printf("ICON_TYPE_RECONNECT"); */
+ /* bt_ble_icon_open(ICON_TYPE_RECONNECT); //没按键配对的话,等回连成功的时候才显示电量。如果在这里显示,手机取消配对后耳机开机,会显示出按键的界面*/
+ } else {
+ //没有回连,设可连接
+ /* g_printf("ICON_TYPE_INQUIRY"); */
+ bt_ble_icon_open(ICON_TYPE_INQUIRY);
+ }
+
+ }
+#endif
+ }
+ } else {
+ //slave disable
+ bt_ble_set_control_en(0);
+ }
+ ble_icon_contrl.poweron_flag = 0;
+ break;
+ case TWS_EVENT_CONNECTION_TIMEOUT:
+ /*
+ * TWS连接超时
+ */
+ bt_ble_icon_slave_en(0);
+ break;
+ case TWS_EVENT_PHONE_LINK_DETACH:
+ /*
+ * 跟手机的链路LMP层已完全断开, 只有tws在连接状态才会收到此事件
+ */
+ if (reason == 0x0b) {
+ //CONNECTION ALREADY EXISTS
+ ble_icon_contrl.miss_flag = 1;
+ } else {
+ ble_icon_contrl.miss_flag = 0;
+ }
+ break;
+ }
+}
+
+int adv_sys_event_handler_specific(struct sys_event *event)
+{
+ switch (event->type) {
+ case SYS_BT_EVENT:
+ if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) {
+ } else if ((u32)event->arg == SYS_BT_EVENT_TYPE_HCI_STATUS) {
+ ble_adv_hci_event_handler(&event->u.bt);
+ }
+#if TCFG_USER_TWS_ENABLE
+ else if (((u32)event->arg == SYS_BT_EVENT_FROM_TWS)) {
+ ble_adv_bt_tws_event_handler(&event->u.bt);
+ }
+#endif
+ break;
+ }
+
+ return 0;
+}
+
+int adv_earphone_state_init()
+{
+ return 0;
+}
+
+int adv_earphone_state_sniff(u8 state)
+{
+ bt_ble_icon_state_sniff(state);
+ return 0;
+}
+
+int adv_earphone_state_role_switch(u8 role)
+{
+ bt_ble_icon_role_switch(role);
+ return 0;
+}
+
+
+
+
+
+#endif
+
diff --git a/apps/earphone/board/br28/app.ld b/apps/earphone/board/br28/app.ld
new file mode 100644
index 0000000..eec9be2
--- /dev/null
+++ b/apps/earphone/board/br28/app.ld
@@ -0,0 +1,66 @@
+#include "app_config.h"
+
+SECTIONS
+{
+ .text : ALIGN(4)
+ {
+ gsensor_dev_begin = .;
+ KEEP(*(.gsensor_dev))
+ gsensor_dev_end = .;
+
+ fm_dev_begin = .;
+ KEEP(*(.fm_dev))
+ fm_dev_end = .;
+
+ fm_emitter_dev_begin = .;
+ KEEP(*(.fm_emitter_dev))
+ fm_emitter_dev_end = .;
+
+ storage_device_begin = .;
+ KEEP(*(.storage_device))
+ storage_device_end = .;
+
+ imusensor_dev_begin = .;
+ KEEP(*(.imusensor_dev))
+ imusensor_dev_end = .;
+
+#if TCFG_APP_PC_EN
+ aac_dec_code_begin = .;
+ *(.bt_aac_dec_code)
+ *(.bt_aac_dec_sparse_code)
+ aac_dec_code_end = .;
+ aac_dec_code_size = aac_dec_code_end - aac_dec_code_begin ;
+
+ . = ALIGN(4);
+ bt_aac_dec_const_begin = .;
+ *(.bt_aac_dec_const)
+ *(.bt_aac_dec_sparse_const)
+ bt_aac_dec_const_end = .;
+ bt_aac_dec_const_size = bt_aac_dec_const_end - bt_aac_dec_const_begin ;
+
+ *(.bt_aac_dec_data)
+ *(.bt_aac_dec_bss)
+
+ . = ALIGN(4);
+ *(.aac_mem)
+ *(.aac_ctrl_mem)
+ /* . += 0x5fe8 ; */
+ /* . += 0xef88 ; */
+#endif
+
+ . = ALIGN(32);
+ }
+
+ .data ALIGN(32):
+ {
+ } > ram0
+
+ .bss ALIGN(32):
+ {
+ } > ram0
+
+ .data_code ALIGN(32):
+ {
+ } > ram0
+
+}
diff --git a/apps/earphone/board/br28/app_overlay.ld b/apps/earphone/board/br28/app_overlay.ld
new file mode 100644
index 0000000..c76e51d
--- /dev/null
+++ b/apps/earphone/board/br28/app_overlay.ld
@@ -0,0 +1,164 @@
+
+ OVERLAY : AT(0x200000) SUBALIGN(4)
+ {
+ .overlay_aec
+ {
+ aec_code_begin = . ;
+ *(.text._*)
+ *(.data._*)
+ *(.aec_code)
+ *(.aec_const)
+ *(.res_code)
+ *(.res_const)
+ *(.ns_code)
+ *(.ns_const)
+ *(.bark_const)
+ *(.fft_code)
+ *(.fft_const)
+ *(.agc_code)
+ *(.dms_code)
+ *(.dms_const)
+ *(.dms_sparse_code)
+ aec_code_end = . ;
+ aec_code_size = aec_code_end - aec_code_begin ;
+
+ *(.msbc_enc)
+ *(.cvsd_codec)
+ *(.aec_bss)
+ *(.aec_data)
+ *(.res_data)
+ *(.ns_data)
+ *(.dns_common_data)
+ *(.dns_param_data_single)
+ *(.dns_param_data_dual)
+ *(.jlsp_nlp_code)
+ *(.jlsp_nlp_const)
+ *(.jlsp_aec_code)
+ *(.jlsp_aec_const)
+ *(.jlsp_prep_code)
+ *(.jlsp_prep_const)
+ *(.jlsp_enc_code)
+ *(.jlsp_enc_const)
+ *(.jlsp_wn_code)
+ *(.jlsp_wn_const)
+ *(.jlsp_tri_code)
+ *(.jlsp_tri_const)
+ *(.jlsp_agc_code)
+ *(.jlsp_agc_const)
+ *(.res_bss)
+ *(.ns_bss)
+ *(.aec_mem)
+ }
+ .overlay_aac
+ {
+#if !TCFG_APP_PC_EN
+ aac_dec_code_begin = .;
+ *(.bt_aac_dec_code)
+ *(.bt_aac_dec_sparse_code)
+ aac_dec_code_end = .;
+ aac_dec_code_size = aac_dec_code_end - aac_dec_code_begin ;
+
+ . = ALIGN(4);
+ bt_aac_dec_const_begin = .;
+ *(.bt_aac_dec_const)
+ *(.bt_aac_dec_sparse_const)
+ bt_aac_dec_const_end = .;
+ bt_aac_dec_const_size = bt_aac_dec_const_end - bt_aac_dec_const_begin ;
+
+ *(.bt_aac_dec_data)
+ *(.bt_aac_dec_bss)
+
+ . = ALIGN(4);
+ *(.aac_mem)
+ *(.aac_ctrl_mem)
+ /* . += 0x5fe8 ; */
+ /* . += 0xef88 ; */
+#endif
+ }
+ /*
+ .overlay_lc3
+ {
+ lc3_dec_code_begin = .;
+ *(.lc3_dec_code)
+ lc3_dec_code_end = .;
+ lc3_dec_code_size = lc3_dec_code_end - lc3_dec_code_begin;
+
+ . = ALIGN(4);
+ lc3_dec_const_begin = .;
+ *(.lc3_dec_const)
+ lc3_dec_const_end = .;
+ lc3_dec_const_size = lc3_dec_const_end - lc3_dec_const_begin;
+ *(.lc3_dec_data)
+ *(.lc3_dec_bss)
+ }
+ */
+
+ .overlay_mp3
+ {
+ *(.mp3_mem)
+ *(.mp3_ctrl_mem)
+ *(.mp3pick_mem)
+ *(.mp3pick_ctrl_mem)
+ *(.dec2tws_mem)
+ }
+ .overlay_wma
+ {
+ *(.wma_mem)
+ *(.wma_ctrl_mem)
+ *(.wmapick_mem)
+ *(.wmapick_ctrl_mem)
+ }
+ .overlay_wav
+ {
+ *(.wav_mem)
+ *(.wav_ctrl_mem)
+ }
+ .overlay_ape
+ {
+ *(.ape_mem)
+ *(.ape_ctrl_mem)
+ }
+ .overlay_flac
+ {
+ *(.flac_mem)
+ *(.flac_ctrl_mem)
+ }
+ .overlay_m4a
+ {
+ *(.m4a_mem)
+ *(.m4a_ctrl_mem)
+ }
+ .overlay_amr
+ {
+ *(.amr_mem)
+ *(.amr_ctrl_mem)
+ }
+ .overlay_dts
+ {
+ *(.dts_mem)
+ *(.dts_ctrl_mem)
+ }
+ .overlay_fm
+ {
+ *(.fm_mem)
+ }
+ .overlay_pc
+ {
+ *(.usb_audio_play_dma)
+ *(.usb_audio_rec_dma)
+ *(.uac_rx)
+ *(.mass_storage)
+
+ *(.usb_ep0)
+ *(.usb_msd_dma)
+ *(.usb_hid_dma)
+ *(.usb_iso_dma)
+ *(.usb_cdc_dma)
+ *(.uac_var)
+ *(.usb_config_var)
+ *(.cdc_var)
+ }
+
+ } > ram0
+
+
diff --git a/apps/earphone/board/br28/board_config.h b/apps/earphone/board/br28/board_config.h
new file mode 100644
index 0000000..428d5f9
--- /dev/null
+++ b/apps/earphone/board/br28/board_config.h
@@ -0,0 +1,20 @@
+#ifndef BOARD_CONFIG_H
+#define BOARD_CONFIG_H
+
+
+/*
+ * 板级配置选择
+ */
+
+#define CONFIG_BOARD_JL701N_DEMO
+
+
+#include "board_jl701n_demo_cfg.h"
+
+#define DUT_AUDIO_DAC_LDO_VOLT DACVDD_LDO_1_25V
+
+#ifdef CONFIG_NEW_CFG_TOOL_ENABLE
+#define CONFIG_ENTRY_ADDRESS 0x6000100
+#endif
+
+#endif
diff --git a/apps/earphone/board/br28/board_jl701n_demo.c b/apps/earphone/board/br28/board_jl701n_demo.c
new file mode 100644
index 0000000..fb938e1
--- /dev/null
+++ b/apps/earphone/board/br28/board_jl701n_demo.c
@@ -0,0 +1,1091 @@
+#include "app_config.h"
+
+#ifdef CONFIG_BOARD_JL701N_DEMO
+
+#include "app_main.h"
+#include "system/includes.h"
+#include "media/includes.h"
+#include "asm/sdmmc.h"
+#include "asm/chargestore.h"
+#include "asm/umidigi_chargestore.h"
+#include "asm/charge.h"
+#include "asm/pwm_led.h"
+#include "tone_player.h"
+#include "audio_config.h"
+#include "key_event_deal.h"
+#include "asm/lp_touch_key_api.h"
+#include "user_cfg.h"
+#include "audio_link.h"
+#if TCFG_DEV_MANAGER_ENABLE
+#include "dev_manager.h"
+#endif
+#if TCFG_PC_ENABLE
+#include "usb/otg.h"
+#endif
+#include "norflash_sfc.h"
+#include "asm/power/power_port.h"
+//#include "app_umidigi_chargestore.h"
+#if TCFG_AUDIO_ANC_ENABLE
+#include "audio_anc.h"
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+#if TCFG_MPU6887P_ENABLE
+#include "imu_sensor/mpu6887/mpu6887p.h"
+#endif /*TCFG_MPU6887P_ENABLE*/
+#if TCFG_QMI8658_ENABLE
+#include "imu_sensor/qmi8658/qmi8658c.h"
+#endif /*TCFG_QMI8658_ENABLE*/
+#if TCFG_LSM6DSL_ENABLE
+#include "imu_sensor/lsm6dsl/lsm6dsl.h"
+#endif /*TCFG_LSM6DSL_ENABLE*/
+#if TCFG_ICM42670P_ENABLE
+#include "imu_sensor/icm_42670p/icm_42670p.h"
+#endif /*TCFG_ICM42670P_ENABLE*/
+
+#define LOG_TAG_CONST BOARD
+#define LOG_TAG "[BOARD]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+void board_power_init(void);
+
+/*各个状态下默认的闪灯方式和提示音设置,如果USER_CFG中设置了USE_CONFIG_STATUS_SETTING为1,则会从配置文件读取对应的配置来填充改结构体*/
+STATUS_CONFIG status_config = {
+ //灯状态设置
+ .led = {
+ .charge_start = PWM_LED1_ON,
+ .charge_full = PWM_LED0_ON,
+ .power_on = PWM_LED0_ON,
+ .power_off = PWM_LED1_FLASH_THREE,
+ .lowpower = PWM_LED1_SLOW_FLASH,
+ .max_vol = PWM_LED_NULL,
+ .phone_in = PWM_LED_NULL,
+ .phone_out = PWM_LED_NULL,
+ .phone_activ = PWM_LED_NULL,
+ .bt_init_ok = PWM_LED0_LED1_SLOW_FLASH,
+ .bt_connect_ok = PWM_LED0_ONE_FLASH_5S,
+ .bt_disconnect = PWM_LED0_LED1_FAST_FLASH,
+ .tws_connect_ok = PWM_LED0_LED1_FAST_FLASH,
+ .tws_disconnect = PWM_LED0_LED1_SLOW_FLASH,
+ },
+ //提示音设置
+ .tone = {
+ .charge_start = IDEX_TONE_NONE,
+ .charge_full = IDEX_TONE_NONE,
+ .power_on = IDEX_TONE_POWER_ON,
+ .power_off = IDEX_TONE_POWER_OFF,
+ .lowpower = IDEX_TONE_LOW_POWER,
+ .max_vol = IDEX_TONE_MAX_VOL,
+ .phone_in = IDEX_TONE_NONE,
+ .phone_out = IDEX_TONE_NONE,
+ .phone_activ = IDEX_TONE_NONE,
+ .bt_init_ok = IDEX_TONE_BT_MODE,
+ .bt_connect_ok = IDEX_TONE_BT_CONN,
+ .bt_disconnect = IDEX_TONE_BT_DISCONN,
+ .tws_connect_ok = IDEX_TONE_TWS_CONN,
+ .tws_disconnect = IDEX_TONE_TWS_DISCONN,
+ }
+};
+
+#define __this (&status_config)
+
+/************************** KEY MSG****************************/
+/*各个按键的消息设置,如果USER_CFG中设置了USE_CONFIG_KEY_SETTING为1,则会从配置文件读取对应的配置来填充改结构体*/
+#if (TCFG_APP_AUX_EN || TCFG_APP_MUSIC_EN || TCFG_APP_PC_EN)
+u8 key_table[KEY_NUM_MAX][KEY_EVENT_MAX] = {
+ // SHORT LONG HOLD UP DOUBLE TRIPLE
+ {KEY_MUSIC_PP, KEY_POWEROFF, KEY_POWEROFF_HOLD, KEY_NULL, KEY_CALL_LAST_NO, KEY_MODE_SWITCH}, //KEY_0
+ {KEY_MUSIC_NEXT, KEY_VOL_UP, KEY_VOL_UP, KEY_NULL, KEY_OPEN_SIRI, KEY_NULL}, //KEY_1
+ {KEY_MUSIC_PREV, KEY_VOL_DOWN, KEY_VOL_DOWN, KEY_NULL, KEY_HID_CONTROL, KEY_NULL}, //KEY_2
+};
+#else
+u8 key_table[KEY_NUM_MAX][KEY_EVENT_MAX] = {
+ // SHORT LONG HOLD UP DOUBLE TRIPLE
+ {KEY_MUSIC_PP, KEY_POWEROFF, KEY_POWEROFF_HOLD, KEY_POWEROFF_HOLD_UP, KEY_NULL, KEY_IR_NUM_2}, //KEY_0
+ {KEY_NULL, KEY_NULL, KEY_NULL, KEY_NULL, KEY_NULL, KEY_NULL}, //KEY_1
+ {KEY_NULL, KEY_NULL, KEY_NULL, KEY_NULL, KEY_NULL, KEY_NULL}, //KEY_2
+};
+#endif
+
+
+// *INDENT-OFF*
+/************************** UART config****************************/
+#if TCFG_UART0_ENABLE
+UART0_PLATFORM_DATA_BEGIN(uart0_data)
+ .tx_pin = TCFG_UART0_TX_PORT, //串口打印TX引脚选择
+ .rx_pin = TCFG_UART0_RX_PORT, //串口打印RX引脚选择
+ .baudrate = TCFG_UART0_BAUDRATE, //串口波特率
+
+ .flags = UART_DEBUG, //串口用来打印需要把改参数设置为UART_DEBUG
+UART0_PLATFORM_DATA_END()
+#endif //TCFG_UART0_ENABLE
+
+/************************** CHARGE config****************************/
+#if TCFG_CHARGE_ENABLE
+CHARGE_PLATFORM_DATA_BEGIN(charge_data)
+ .charge_en = TCFG_CHARGE_ENABLE, //内置充电使能
+ .charge_poweron_en = TCFG_CHARGE_POWERON_ENABLE, //是否支持充电开机
+ .charge_full_V = TCFG_CHARGE_FULL_V, //充电截止电压
+ .charge_full_mA = TCFG_CHARGE_FULL_MA, //充电截止电流
+ .charge_mA = TCFG_CHARGE_MA, //恒流充电电流
+ .charge_trickle_mA = TCFG_CHARGE_TRICKLE_MA, //涓流充电电流
+/*ldo5v拔出过滤值,过滤时间 = (filter*2 + 20)ms,ldoin<0.6V且时间大于过滤时间才认为拔出
+ 对于充满直接从5V掉到0V的充电仓,该值必须设置成0,对于充满由5V先掉到0V之后再升压到xV的
+ 充电仓,需要根据实际情况设置该值大小*/
+ .ldo5v_off_filter = 100,
+ .ldo5v_on_filter = 50,
+ .ldo5v_keep_filter = 220,
+ .ldo5v_pulldown_lvl = CHARGE_PULLDOWN_200K, //下拉电阻档位选择
+ .ldo5v_pulldown_keep = 0,
+//1、对于自动升压充电舱,若充电舱需要更大的负载才能检测到插入时,请将该变量置1,并且根据需求配置下拉电阻档位
+//2、对于按键升压,并且是通过上拉电阻去提供维持电压的舱,请将该变量设置1,并且根据舱的上拉配置下拉需要的电阻挡位
+//3、对于常5V的舱,可将改变量设为0,省功耗
+//4、为LDOIN防止被误触发唤醒,可设置为200k下拉
+ .ldo5v_pulldown_en = 1,
+CHARGE_PLATFORM_DATA_END()
+#endif//TCFG_CHARGE_ENABLE
+
+/************************** chargestore config****************************/
+#if TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE
+CHARGESTORE_PLATFORM_DATA_BEGIN(chargestore_data)
+ .io_port = TCFG_CHARGESTORE_PORT,
+CHARGESTORE_PLATFORM_DATA_END()
+#endif
+
+/************************** DAC ****************************/
+#if TCFG_AUDIO_DAC_ENABLE
+struct dac_platform_data dac_data = {
+ .mode = TCFG_AUDIO_DAC_MODE, //dac输出模式
+ .ldo_id = TCFG_AUDIO_DAC_LDO_SEL, //保留位
+ .pa_mute_port = TCFG_AUDIO_DAC_PA_PORT, //暂时无作用
+ .vcmo_en = 0, //是否打开VCOMO
+ .pa_mute_value = 1, //暂时无作用
+ .output = TCFG_AUDIO_DAC_CONNECT_MODE, //DAC输出配置,和具体硬件连接有关,需根据硬件来设置
+ .lpf_isel = 0xf,
+ .sys_vol_type = SYS_VOL_TYPE, //系统音量选择:模拟音量/数字音量,调节时调节对应的音量
+ .max_ana_vol = MAX_ANA_VOL, //模拟音量最大等级
+ .max_dig_vol = MAX_DIG_VOL, //数字音量最大等级
+ /* .dig_vol_tab = (s16 *)dig_vol_table, //数字音量表 */
+ .vcm_cap_en = 1, //配1代表走外部通路,vcm上有电容时,可以提升电路抑制电源噪声能力,提高ADC的性能,配0相当于vcm上无电容,抑制电源噪声能力下降,ADC性能下降
+#if (SYS_VOL_TYPE == VOL_TYPE_AD)
+ .digital_gain_limit = 16384,
+#endif // #if (SYS_VOL_TYPE == VOL_TYPE_AD)
+
+ .power_on_mode = 0,
+};
+#endif
+
+/************************** ADC ****************************/
+#if TCFG_AUDIO_ADC_ENABLE
+#ifndef TCFG_AUDIO_MIC0_BIAS_EN
+#define TCFG_AUDIO_MIC0_BIAS_EN 0
+#endif/*TCFG_AUDIO_MIC0_BIAS_EN*/
+#ifndef TCFG_AUDIO_MIC1_BIAS_EN
+#define TCFG_AUDIO_MIC1_BIAS_EN 0
+#endif/*TCFG_AUDIO_MIC1_BIAS_EN*/
+#ifndef TCFG_AUDIO_MIC2_BIAS_EN
+#define TCFG_AUDIO_MIC2_BIAS_EN 0
+#endif/*TCFG_AUDIO_MIC2_BIAS_EN*/
+#ifndef TCFG_AUDIO_MIC3_BIAS_EN
+#define TCFG_AUDIO_MIC3_BIAS_EN 0
+#endif/*TCFG_AUDIO_MIC3_BIAS_EN*/
+#ifndef TCFG_AUDIO_MIC_LDO_EN
+#define TCFG_AUDIO_MIC_LDO_EN 0
+#endif/*TCFG_AUDIO_MIC_LDO_EN*/
+
+struct adc_platform_data adc_data = {
+/*MIC LDO电流档位设置:
+ 0:0.625ua 1:1.25ua 2:1.875ua 3:2.5ua*/
+ .mic_ldo_isel = TCFG_AUDIO_ADC_LD0_SEL,
+
+/*mic_mode 工作模式定义
+ #define AUDIO_MIC_CAP_MODE 0 //单端隔直电容模式
+ #define AUDIO_MIC_CAP_DIFF_MODE 1 //差分隔直电容模式
+ #define AUDIO_MIC_CAPLESS_MODE 2 //单端省电容模式
+*/
+ .mic_mode = TCFG_AUDIO_MIC_MODE,
+ .mic1_mode = TCFG_AUDIO_MIC1_MODE,
+ .mic2_mode = TCFG_AUDIO_MIC2_MODE,
+ .mic3_mode = TCFG_AUDIO_MIC3_MODE,
+
+ .mic_bias_inside = TCFG_AUDIO_MIC0_BIAS_EN,
+ .mic1_bias_inside = TCFG_AUDIO_MIC1_BIAS_EN,
+ .mic2_bias_inside = TCFG_AUDIO_MIC2_BIAS_EN,
+ .mic3_bias_inside = TCFG_AUDIO_MIC3_BIAS_EN,
+
+/*MICLDO供电输出到PAD(PA0)控制使能*/
+ .mic_ldo_pwr = TCFG_AUDIO_MIC_LDO_EN, // MIC LDO 输出到 PA0
+
+/*MIC免电容方案需要设置,影响MIC的偏置电压
+ 0b0001~0b1001 : 0.5k ~ 4.5k step = 0.5k
+ 0b1010~0b1111 : 5k ~ 10k step = 1k */
+ .mic_bias_res = 4,
+ .mic1_bias_res = 4,
+ .mic2_bias_res = 4,
+ .mic3_bias_res = 4,
+/*MIC LDO电压档位设置,也会影响MIC的偏置电压
+ 3:2.0v 4:2.2v 5:2.4v 6:2.6v 7:2.8v */
+ .mic_ldo_vsel = 5,
+ //mic的去直流dcc寄存器配置值,可配0到15,数值越大,其高通转折点越低
+ .mic_dcc = 8,
+ /*ADC低功耗等级,越大功耗越低,对应影响THD和底噪, 范围 (0 - 2)*/
+ .lowpower_lvl = 0,
+ .adc_max_ch_en = 0,
+ .max_channel_num = 3,
+};
+#endif
+
+const struct vad_mic_platform_data vad_mic_data = {
+ .mic_data = { //
+ .mic_mode = TCFG_AUDIO_MIC_MODE,
+ .mic_ldo_isel = 2,
+ .mic_ldo_vsel = 5,
+ .mic_ldo2PAD_en = 1,
+ .mic_bias_en = 0,
+ .mic_bias_res = 0,
+ .mic_bias_inside = TCFG_AUDIO_MIC0_BIAS_EN,
+ /* ADC偏置电阻配置*/
+ .adc_rbs = 3,
+ /* ADC输入电阻配置*/
+ .adc_rin = 3,
+ /*.adc_test = 1,*/
+ },
+ .power_data = {
+ /*VADLDO电压档位:0~7*/
+ .ldo_vs = 3,
+ /*VADLDO误差运放电流档位:0~3*/
+#if TCFG_VAD_LOWPOWER_CLOCK == VAD_CLOCK_USE_PMU_STD12M
+ .ldo_is = 1,
+#else
+ .ldo_is = 2,
+#endif
+ .clock = VAD_CLOCK_USE_PMU_STD12M, /*VAD时钟选项*/
+ .acm_select = 8,
+ },
+};
+/* struct audio_pf_data audio_pf_d = { */
+/* #if TCFG_AUDIO_DAC_ENABLE */
+ /* .adc_pf_data = &adc_data, */
+/* #endif */
+
+/* #if TCFG_AUDIO_ADC_ENABLE */
+ /* .dac_pf_data = &dac_data, */
+/* #endif */
+/* }; */
+
+/* struct audio_platform_data audio_data = { */
+ /* .private_data = (void *) &audio_pf_d, */
+/* }; */
+
+
+/************************** IO KEY ****************************/
+#if TCFG_IOKEY_ENABLE
+const struct iokey_port iokey_list[] = {
+ {
+ .connect_way = TCFG_IOKEY_POWER_CONNECT_WAY, //IO按键的连接方式
+ .key_type.one_io.port = TCFG_IOKEY_POWER_ONE_PORT, //IO按键对应的引脚
+ .key_value = 0, //按键值
+ },
+};
+const struct iokey_platform_data iokey_data = {
+ .enable = TCFG_IOKEY_ENABLE, //是否使能IO按键
+ .num = ARRAY_SIZE(iokey_list), //IO按键的个数
+ .port = iokey_list, //IO按键参数表
+};
+
+#if MULT_KEY_ENABLE
+//组合按键消息映射表
+//配置注意事项:单个按键按键值需要按照顺序编号,如power:0, prev:1, next:2
+//bit_value = BIT(0) | BIT(1) 指按键值为0和按键值为1的两个按键被同时按下,
+//remap_value = 3指当这两个按键被同时按下后重新映射的按键值;
+const struct key_remap iokey_remap_table[] = {
+ {.bit_value = BIT(0) | BIT(1), .remap_value = 3},
+ {.bit_value = BIT(0) | BIT(2), .remap_value = 4},
+ {.bit_value = BIT(1) | BIT(2), .remap_value = 5},
+};
+
+const struct key_remap_data iokey_remap_data = {
+ .remap_num = ARRAY_SIZE(iokey_remap_table),
+ .table = iokey_remap_table,
+};
+#endif
+
+#endif
+/*********************** LP TOUCH KEY ****************************/
+#if TCFG_LP_TOUCH_KEY_ENABLE
+const struct lp_touch_key_platform_data lp_touch_key_config = {
+ /*触摸按键*/
+ .ch[0].enable = TCFG_LP_TOUCH_KEY0_EN,
+ .ch[0].wakeup_enable = TCFG_LP_TOUCH_KEY0_WAKEUP_EN,
+ .ch[0].port = IO_PORTB_00,
+ .ch[0].sensitivity = TCFG_LP_TOUCH_KEY0_SENSITIVITY,
+ .ch[0].key_value = 0,
+
+ .ch[1].enable = TCFG_LP_TOUCH_KEY1_EN,
+ .ch[1].wakeup_enable = TCFG_LP_TOUCH_KEY1_WAKEUP_EN,
+ .ch[1].port = IO_PORTB_01,
+ .ch[1].sensitivity = TCFG_LP_TOUCH_KEY1_SENSITIVITY,
+ .ch[1].key_value = 0,
+
+ .ch[2].enable = TCFG_LP_TOUCH_KEY2_EN,
+ .ch[2].wakeup_enable = TCFG_LP_TOUCH_KEY2_WAKEUP_EN,
+ .ch[2].port = IO_PORTB_02,
+ .ch[2].sensitivity = TCFG_LP_TOUCH_KEY2_SENSITIVITY,
+ .ch[2].key_value = 1,
+
+ .ch[3].enable = TCFG_LP_TOUCH_KEY3_EN,
+ .ch[3].wakeup_enable = TCFG_LP_TOUCH_KEY3_WAKEUP_EN,
+ .ch[3].port = IO_PORTB_04,
+ .ch[3].sensitivity = TCFG_LP_TOUCH_KEY3_SENSITIVITY,
+ .ch[3].key_value = 2,
+
+ .ch[4].enable = TCFG_LP_TOUCH_KEY4_EN,
+ .ch[4].wakeup_enable = TCFG_LP_TOUCH_KEY4_WAKEUP_EN,
+ .ch[4].port = IO_PORTB_05,
+ .ch[4].sensitivity = TCFG_LP_TOUCH_KEY4_SENSITIVITY,
+ .ch[4].key_value = 3,
+
+ //把触摸按键之间的滑动也当做按键处理,有上滑,下滑,左滑,右滑
+ .slide_mode_en = TCFG_LP_SLIDE_KEY_ENABLE,
+ .slide_mode_key_value = 3,
+
+ //入耳检测相关的配置
+ .eartch_en = TCFG_LP_EARTCH_KEY_ENABLE,
+ .eartch_ch = TCFG_LP_EARTCH_KEY_CH,
+ .eartch_ref_ch = TCFG_LP_EARTCH_KEY_REF_CH,
+ .eartch_soft_inear_val = TCFG_LP_EARTCH_SOFT_INEAR_VAL,
+ .eartch_soft_outear_val = TCFG_LP_EARTCH_SOFT_OUTEAR_VAL,
+};
+#endif /* #if TCFG_LP_TOUCH_KEY_ENABLE */
+
+/************************** PLCNT TOUCH_KEY ****************************/
+#if TCFG_TOUCH_KEY_ENABLE
+const const struct touch_key_port touch_key_list[] = {
+ {
+ .press_delta = TCFG_TOUCH_KEY0_PRESS_DELTA,
+ .port = TCFG_TOUCH_KEY0_PORT,
+ .key_value = TCFG_TOUCH_KEY0_VALUE,
+ },
+ {
+ .press_delta = TCFG_TOUCH_KEY1_PRESS_DELTA,
+ .port = TCFG_TOUCH_KEY1_PORT,
+ .key_value = TCFG_TOUCH_KEY1_VALUE,
+ },
+};
+
+const struct touch_key_platform_data touch_key_data = {
+ .num = ARRAY_SIZE(touch_key_list),
+ .port_list = touch_key_list,
+};
+#endif /* #if TCFG_TOUCH_KEY_ENABLE */
+
+/************************** AD KEY ****************************/
+#if TCFG_ADKEY_ENABLE
+const struct adkey_platform_data adkey_data = {
+ .enable = TCFG_ADKEY_ENABLE, //AD按键使能
+ .adkey_pin = TCFG_ADKEY_PORT, //AD按键对应引脚
+ .ad_channel = TCFG_ADKEY_AD_CHANNEL, //AD通道值
+ .extern_up_en = TCFG_ADKEY_EXTERN_UP_ENABLE, //是否使用外接上拉电阻
+ .ad_value = { //根据电阻算出来的电压值
+ TCFG_ADKEY_VOLTAGE0,
+ TCFG_ADKEY_VOLTAGE1,
+ TCFG_ADKEY_VOLTAGE2,
+ TCFG_ADKEY_VOLTAGE3,
+ TCFG_ADKEY_VOLTAGE4,
+ TCFG_ADKEY_VOLTAGE5,
+ TCFG_ADKEY_VOLTAGE6,
+ TCFG_ADKEY_VOLTAGE7,
+ TCFG_ADKEY_VOLTAGE8,
+ TCFG_ADKEY_VOLTAGE9,
+ },
+ .key_value = { //AD按键各个按键的键值
+ TCFG_ADKEY_VALUE0,
+ TCFG_ADKEY_VALUE1,
+ TCFG_ADKEY_VALUE2,
+ TCFG_ADKEY_VALUE3,
+ TCFG_ADKEY_VALUE4,
+ TCFG_ADKEY_VALUE5,
+ TCFG_ADKEY_VALUE6,
+ TCFG_ADKEY_VALUE7,
+ TCFG_ADKEY_VALUE8,
+ TCFG_ADKEY_VALUE9,
+ },
+};
+#endif
+
+/************************** RDEC_KEY ****************************/
+#if TCFG_RDEC_KEY_ENABLE
+const struct rdec_device rdeckey_list[] = {
+ {
+ .index = RDEC0 ,
+ .sin_port0 = TCFG_RDEC0_ECODE1_PORT,
+ .sin_port1 = TCFG_RDEC0_ECODE2_PORT,
+ .key_value0 = TCFG_RDEC0_KEY0_VALUE | BIT(7),
+ .key_value1 = TCFG_RDEC0_KEY1_VALUE | BIT(7),
+ },
+
+ {
+ .index = RDEC1 ,
+ .sin_port0 = TCFG_RDEC1_ECODE1_PORT,
+ .sin_port1 = TCFG_RDEC1_ECODE2_PORT,
+ .key_value0 = TCFG_RDEC1_KEY0_VALUE | BIT(7),
+ .key_value1 = TCFG_RDEC1_KEY1_VALUE | BIT(7),
+ },
+
+ {
+ .index = RDEC2 ,
+ .sin_port0 = TCFG_RDEC2_ECODE1_PORT,
+ .sin_port1 = TCFG_RDEC2_ECODE2_PORT,
+ .key_value0 = TCFG_RDEC2_KEY0_VALUE | BIT(7),
+ .key_value1 = TCFG_RDEC2_KEY1_VALUE | BIT(7),
+ },
+
+
+};
+const struct rdec_platform_data rdec_key_data = {
+ .enable = 1, //TCFG_RDEC_KEY_ENABLE, //是否使能RDEC按键
+ .num = ARRAY_SIZE(rdeckey_list), //RDEC按键的个数
+ .rdec = rdeckey_list, //RDEC按键参数表
+};
+#endif
+
+/************************** IIS config ****************************/
+#if (TCFG_AUDIO_INPUT_IIS || TCFG_AUDIO_OUTPUT_IIS)
+ALINK_PARM alink0_platform_data = {
+ .module = ALINK0,
+ .mclk_io = TCFG_IIS_MCLK_IO,
+ .sclk_io = TCFG_SCLK_IO,
+ .lrclk_io = TCFG_LRCLK_IO,
+ .ch_cfg[0].data_io = TCFG_DATA0_IO,
+ .ch_cfg[1].data_io = TCFG_DATA1_IO,
+ .ch_cfg[2].data_io = TCFG_DATA2_IO,
+ .ch_cfg[3].data_io = TCFG_DATA3_IO,
+ .mode = ALINK_MD_IIS,
+#if TCFG_IIS_MODE
+ .role = ALINK_ROLE_SLAVE,
+#else
+ .role = ALINK_ROLE_MASTER,
+#endif /*TCFG_IIS_MODE*/
+ .clk_mode = ALINK_CLK_FALL_UPDATE_RAISE_SAMPLE,
+ .bitwide = ALINK_LEN_16BIT,
+ .sclk_per_frame = ALINK_FRAME_32SCLK,
+ .dma_len = 4 * 1024,
+ .sample_rate = TCFG_IIS_SR,
+ .buf_mode = ALINK_BUF_CIRCLE,
+ /*.iperiod = 64, //配置该项可以控制输入的延时*/
+};
+#endif
+
+/************************** PWM_LED ****************************/
+#if TCFG_PWMLED_ENABLE
+LED_PLATFORM_DATA_BEGIN(pwm_led_data)
+ .io_mode = TCFG_PWMLED_IOMODE, //推灯模式设置:支持单个IO推两个灯和两个IO推两个灯
+ .io_cfg.one_io.pin = TCFG_PWMLED_PIN, //单个IO推两个灯的IO口配置
+LED_PLATFORM_DATA_END()
+#endif
+#if 0
+const struct soft_iic_config soft_iic_cfg[] = {
+ //iic0 data
+ {
+ .scl = TCFG_SW_I2C0_CLK_PORT, //IIC CLK脚
+ .sda = TCFG_SW_I2C0_DAT_PORT, //IIC DAT脚
+ .delay = TCFG_SW_I2C0_DELAY_CNT, //软件IIC延时参数,影响通讯时钟频率
+ .io_pu = 1, //是否打开上拉电阻,如果外部电路没有焊接上拉电阻需要置1
+ },
+
+ //iic1 data
+ {
+ .scl = IO_PORTA_05,
+ .sda = IO_PORTA_06,
+ .delay = 50,
+ .io_pu = 1,
+ },
+
+};
+#endif
+
+#if 0
+const struct hw_iic_config hw_iic_cfg[] = {
+ //iic0 data
+ {
+ /*硬件IIC端口下选择
+ SCL SDA
+ {IO_PORT_DP, IO_PORT_DM}, //group a
+ {IO_PORTC_04, IO_PORTC_05}, //group b
+ {IO_PORTC_02, IO_PORTC_03}, //group c
+ {IO_PORTA_05, IO_PORTA_06}, //group d
+ */
+ .port = TCFG_HW_I2C0_PORTS,
+ .baudrate = TCFG_HW_I2C0_CLK, //IIC通讯波特率
+ .hdrive = 0, //是否打开IO口强驱
+ .io_filter = 1, //是否打开滤波器(去纹波)
+ .io_pu = 1, //是否打开上拉电阻,如果外部电路没有焊接上拉电阻需要置1
+ },
+};
+#endif // 0
+#if TCFG_SD0_ENABLE
+SD0_PLATFORM_DATA_BEGIN(sd0_data)
+ .port = {
+ TCFG_SD0_PORT_CMD,
+ TCFG_SD0_PORT_CLK,
+ TCFG_SD0_PORT_DA0,
+ TCFG_SD0_PORT_DA1,
+ TCFG_SD0_PORT_DA2,
+ TCFG_SD0_PORT_DA3,
+ },
+ .data_width = TCFG_SD0_DAT_MODE,
+ .speed = TCFG_SD0_CLK,
+ .detect_mode = TCFG_SD0_DET_MODE,
+ .priority = 3,
+
+#if (TCFG_SD0_DET_MODE == SD_IO_DECT)
+ .detect_io = TCFG_SD0_DET_IO,
+ .detect_io_level = TCFG_SD0_DET_IO_LEVEL,
+ .detect_func = sdmmc_0_io_detect,
+ .power = sd_set_power,
+ /* .power = NULL, */
+#elif (TCFG_SD0_DET_MODE == SD_CLK_DECT)
+ .detect_io_level = TCFG_SD0_DET_IO_LEVEL,
+ .detect_func = sdmmc_0_clk_detect,
+ .power = sd_set_power,
+ /* .power = NULL, */
+#else
+ .detect_func = sdmmc_cmd_detect,
+ .power = NULL,
+#endif
+
+SD0_PLATFORM_DATA_END()
+#endif /* #if TCFG_SD0_ENABLE */
+
+/************************** otg data****************************/
+#if TCFG_OTG_MODE
+struct otg_dev_data otg_data = {
+ .usb_dev_en = TCFG_OTG_USB_DEV_EN,
+ .slave_online_cnt = TCFG_OTG_SLAVE_ONLINE_CNT,
+ .slave_offline_cnt = TCFG_OTG_SLAVE_OFFLINE_CNT,
+ .host_online_cnt = TCFG_OTG_HOST_ONLINE_CNT,
+ .host_offline_cnt = TCFG_OTG_HOST_OFFLINE_CNT,
+ .detect_mode = TCFG_OTG_MODE,
+ .detect_time_interval = TCFG_OTG_DET_INTERVAL,
+};
+#endif
+
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+GSENSOR_PLATFORM_DATA_BEGIN(motion_sensor_data)
+ .iic = 0,
+ .gSensor_name = "mpu6050",
+ .gSensor_int_io = NO_CONFIG_PORT,
+GSENSOR_PLATFORM_DATA_END();
+#endif/*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
+
+
+
+
+
+#if 1
+
+#define RTC_CLK_RES_SEL CLK_SEL_32K //rtc时钟源选择:CLK_SEL_32K/CLK_SEL_12M/CLK_SEL_24M
+
+const struct sys_time def_sys_time = { //初始一下当前时间
+ .year = 2020,
+ .month = 1,
+ .day = 1,
+ .hour = 0,
+ .min = 0,
+ .sec = 0,
+};
+const struct sys_time def_alarm = { //初始一下目标时间,即闹钟时间
+ .year = 2080,
+ .month = 1,
+ .day = 1,
+ .hour = 0,
+ .min = 0,
+ .sec = 0,
+};
+
+/* extern void alarm_isr_user_cbfun(u8 index); */
+RTC_DEV_PLATFORM_DATA_BEGIN(rtc_data)
+ .default_sys_time = &def_sys_time,
+ .default_alarm = &def_alarm,
+ .clk_sel = RTC_CLK_RES_SEL,//CLK_SEL_32K,//CLK_SEL_32K,
+ .cbfun = NULL, //闹钟中断的回调函数,用户自行定义
+ /* .cbfun = alarm_isr_user_cbfun, */
+RTC_DEV_PLATFORM_DATA_END()
+#endif // 0
+
+
+
+
+REGISTER_DEVICES(device_table) = {
+ /* { "audio", &audio_dev_ops, (void *) &audio_data }, */
+
+#if TCFG_CHARGE_ENABLE
+ { "charge", &charge_dev_ops, (void *)&charge_data },
+#endif
+#if TCFG_SD0_ENABLE
+ { "sd0", &sd_dev_ops, (void *)&sd0_data},
+#endif
+#if TCFG_OTG_MODE
+ { "otg", &usb_dev_ops, (void *)&otg_data},
+#endif
+ { "rtc", &rtc_dev_ops , (void *)&rtc_data},
+};
+
+/************************** imu sensor ****************************/
+#if TCFG_IMUSENSOR_ENABLE
+IMU_SENSOR_PLATFORM_DATA_BEGIN(imu_sensor_data)
+#if TCFG_SH3001_ENABLE
+ {
+ .peripheral_hdl = TCFG_SH3001_USER_IIC_INDEX, //iic_hdl or spi_hdl
+ .peripheral_param0= 0, //iic_delay(iic byte间间隔) or spi_cs_pin
+ .imu_sensor_name = "sh3001",
+ .imu_sensor_int_io = TCFG_SH3001_DETECT_IO,
+ },
+#endif
+#if TCFG_TP_MPU9250_ENABLE
+ {
+ .peripheral_hdl = TCFG_MPU9250_USER_IIC_INDEX, //iic_hdl or spi_hdl
+ .peripheral_param0= 1, //iic_delay(iic byte间间隔) or spi_cs_pin//iic byte间间隔
+ .imu_sensor_name = "mpu9250",
+ .imu_sensor_int_io = TCFG_MPU9250_DETECT_IO,
+ },
+#endif
+#if TCFG_MPU6887P_ENABLE
+ {
+ .peripheral_hdl = TCFG_MPU6887P_USER_IIC_INDEX, //iic_hdl or spi_hdl
+ .peripheral_param0= 0, //iic_delay(iic byte间间隔) or spi_cs_pin//iic byte间间隔
+ .imu_sensor_name = "mpu6887p",
+ .imu_sensor_int_io = TCFG_MPU6887P_DETECT_IO,
+ },
+#endif
+#if TCFG_ICM42670P_ENABLE
+ {
+ .peripheral_hdl = TCFG_ICM42670P_USER_IIC_INDEX, //iic_hdl or spi_hdl
+ .peripheral_param0= 0, //iic_delay(iic byte间间隔) or spi_cs_pin//iic byte间间隔
+ .imu_sensor_name = "icm42670p",
+ .imu_sensor_int_io = TCFG_ICM42670P_DETECT_IO,
+ },
+#endif
+#if TCFG_MPU6050_EN //未整合参数如GSENSOR_PLATFORM_DATA_BEGIN配置
+ {
+ .peripheral_hdl = 0, //iic_hdl or spi_hdl
+ .peripheral_param0= 0, //iic_delay(iic byte间间隔) or spi_cs_pin//iic byte间间隔
+ .imu_sensor_name = "mpu6050",
+ .imu_sensor_int_io = -1,
+ },
+#endif
+#if TCFG_QMI8658_ENABLE
+ {
+ .peripheral_hdl = TCFG_QMI8658_USER_IIC_INDEX, //iic_hdl or spi_hdl
+ .peripheral_param0= 0, //iic_delay(iic byte间间隔) or spi_cs_pin//iic byte间间隔
+ .imu_sensor_name = "qmi8658",
+ .imu_sensor_int_io = TCFG_QMI8658_DETECT_IO,
+ },
+#endif
+#if TCFG_LSM6DSL_ENABLE
+ {
+ .peripheral_hdl = TCFG_LSM6DSL_USER_IIC_INDEX, //iic_hdl or spi_hdl
+ .peripheral_param0= 0, //iic_delay(iic byte间间隔) or spi_cs_pin//iic byte间间隔
+ .imu_sensor_name = "lsm6dsl",
+ .imu_sensor_int_io = TCFG_LSM6DSL_DETECT_IO,
+ },
+#endif
+IMU_SENSOR_PLATFORM_DATA_END();
+#endif
+
+/************************** LOW POWER config ****************************/
+const struct low_power_param power_param = {
+ .config = TCFG_LOWPOWER_LOWPOWER_SEL, //低功耗使能,蓝牙&&系统空闲可进入低功耗
+ .btosc_hz = TCFG_CLOCK_OSC_HZ, //蓝牙晶振频率
+ .delay_us = TCFG_CLOCK_SYS_HZ / 1000000L, //提供给低功耗模块的延时(不需要需修改)
+ .vddiom_lev = TCFG_LOWPOWER_VDDIOM_LEVEL, //vddiom等级
+ .osc_type = TCFG_LOWPOWER_OSC_TYPE, //低功耗晶振类型,btosc/lrc
+
+#if TCFG_APP_RTC_EN
+ .rtc_clk = RTC_CLK_RES_SEL,
+#endif
+
+#if (TCFG_LOWPOWER_RAM_SIZE)
+ .mem_init_con = MEM_PWR_RAM_SET(TCFG_LOWPOWER_RAM_SIZE),
+#else
+ .mem_init_con = 0,
+#endif
+#if (TCFG_LP_TOUCH_KEY_ENABLE && \
+ (TCFG_LP_TOUCH_KEY0_WAKEUP_EN || \
+ TCFG_LP_TOUCH_KEY1_WAKEUP_EN || \
+ TCFG_LP_TOUCH_KEY2_WAKEUP_EN || \
+ TCFG_LP_TOUCH_KEY3_WAKEUP_EN || \
+ TCFG_LP_TOUCH_KEY4_WAKEUP_EN ))
+ .lpctmu_en = 1,
+#else
+ .lpctmu_en = 0,
+#endif
+};
+
+/************************** wk_param ****************************/
+struct port_wakeup port0 = {
+ .pullup_down_enable = ENABLE, //配置I/O 内部上下拉是否使能
+ .edge = FALLING_EDGE, //唤醒方式选择,可选:上升沿\下降沿
+ .filter = PORT_FLT_8ms,
+ .iomap = TCFG_IOKEY_POWER_ONE_PORT, //唤醒口选择
+};
+
+#if (TCFG_TEST_BOX_ENABLE || TCFG_CHARGESTORE_ENABLE || TCFG_ANC_BOX_ENABLE || TCFG_UMIDIGI_BOX_ENABLE)
+struct port_wakeup port1 = {
+ .pullup_down_enable = DISABLE, //配置I/O 内部上下拉是否使能
+#if (TCFG_TEST_BOX_ANY_IO_UPDATE)
+ .edge = RISING_EDGE, //唤醒方式选择,可选:上升沿\下降沿
+#else
+ .edge = FALLING_EDGE, //唤醒方式选择,可选:上升沿\下降沿
+#endif
+ .filter = PORT_FLT_1ms,
+ .iomap = TCFG_CHARGESTORE_PORT, //唤醒口选择
+};
+#endif
+
+#if TCFG_CHARGE_ENABLE
+struct port_wakeup charge_port = {
+ .edge = RISING_EDGE, //唤醒方式选择,可选:上升沿\下降沿\双边沿
+ .filter = PORT_FLT_16ms,
+ .iomap = IO_CHGFL_DET, //唤醒口选择
+};
+
+struct port_wakeup vbat_port = {
+ .edge = BOTH_EDGE, //唤醒方式选择,可选:上升沿\下降沿\双边沿
+ .filter = PORT_FLT_4ms,
+ .iomap = IO_VBTCH_DET, //唤醒口选择
+};
+
+struct port_wakeup ldoin_port = {
+ .edge = BOTH_EDGE, //唤醒方式选择,可选:上升沿\下降沿\双边沿
+ .filter = PORT_FLT_4ms,
+ .iomap = IO_LDOIN_DET, //唤醒口选择
+};
+#endif
+
+const struct wakeup_param wk_param = {
+#if (!(TCFG_LP_TOUCH_KEY_ENABLE && TCFG_LP_TOUCH_KEY1_EN))
+ .port[1] = &port0,
+#endif
+#if (TCFG_TEST_BOX_ENABLE || TCFG_CHARGESTORE_ENABLE || TCFG_ANC_BOX_ENABLE || TCFG_UMIDIGI_BOX_ENABLE)
+ .port[2] = &port1,
+#endif
+#if TCFG_CHARGE_ENABLE
+ .aport[0] = &charge_port,
+ .aport[1] = &vbat_port,
+ .aport[2] = &ldoin_port,
+#endif
+};
+
+void gSensor_wkupup_disable(void)
+{
+ log_info("gSensor wkup disable\n");
+ power_wakeup_index_enable(1, 0);
+}
+
+void gSensor_wkupup_enable(void)
+{
+ log_info("gSensor wkup enable\n");
+ power_wakeup_index_enable(1, 1);
+}
+
+void debug_uart_init(const struct uart_platform_data *data)
+{
+#if TCFG_UART0_ENABLE
+ if (data) {
+ uart_init(data);
+ } else {
+ uart_init(&uart0_data);
+ }
+#endif
+}
+
+
+STATUS *get_led_config(void)
+{
+ return &(__this->led);
+}
+
+STATUS *get_tone_config(void)
+{
+ return &(__this->tone);
+}
+
+u8 get_sys_default_vol(void)
+{
+ return 21;
+}
+
+u8 get_power_on_status(void)
+{
+#if TCFG_IOKEY_ENABLE
+ struct iokey_port *power_io_list = NULL;
+ power_io_list = iokey_data.port;
+
+ if (iokey_data.enable) {
+ if (gpio_read(power_io_list->key_type.one_io.port) == power_io_list->connect_way){
+ return 1;
+ }
+ }
+#endif
+
+#if TCFG_ADKEY_ENABLE
+ if (adkey_data.enable) {
+ return 1;
+ }
+#endif
+
+#if TCFG_LP_TOUCH_KEY_ENABLE
+ return lp_touch_key_power_on_status();
+#endif
+
+ return 0;
+}
+
+
+static void board_devices_init(void)
+{
+#if TCFG_PWMLED_ENABLE
+ pwm_led_init(&pwm_led_data);
+#endif
+
+#if (TCFG_IOKEY_ENABLE || TCFG_ADKEY_ENABLE || TCFG_RDEC_KEY_ENABLE || TCFG_TOUCH_KEY_ENABLE)
+ key_driver_init();
+#endif
+
+#if TCFG_UART_KEY_ENABLE
+ extern int uart_key_init(void);
+ uart_key_init();
+#endif /* #if TCFG_UART_KEY_ENABLE */
+
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+ extern void imu_sensor_power_ctl(u32 gpio,u8 value);
+ extern void imu_sensor_ad0_selete(u32 gpio, u8 value);
+ imu_sensor_power_ctl(TCFG_IMU_SENSOR_PWR_PORT,1);
+ os_time_dly(1);
+#if TCFG_MPU6050_EN
+ gravity_sensor_init(&motion_sensor_data);
+#endif /*TCFG_MPU6050_EN*/
+#if TCFG_MPU6887P_ENABLE
+ imu_sensor_ad0_selete(TCFG_MPU6887P_AD0_SELETE_IO, MPU6887P_SA0_IIC_ADDR);
+#endif /*TCFG_MPU6887P_ENABLE*/
+#if TCFG_QMI8658_ENABLE
+ imu_sensor_ad0_selete(TCFG_QMI8658_AD0_SELETE_IO, QMI8658_SD0_IIC_ADDR);
+#endif /*TCFG_QMI8658_ENABLE*/
+#if TCFG_LSM6DSL_ENABLE
+ imu_sensor_ad0_selete(TCFG_LSM6DSL_AD0_SELETE_IO, LSM6DSL_SD0_IIC_ADDR);
+#endif /*TCFG_LSM6DSL_ENABLE*/
+#if TCFG_ICM42670P_ENABLE
+ imu_sensor_ad0_selete(TCFG_ICM42670P_AD0_SELETE_IO, ICM42670P_SA0_IIC_ADDR);
+#endif /*TCFG_ICM42670P_ENABLE*/
+
+#if TCFG_IMUSENSOR_ENABLE
+ imu_sensor_init(imu_sensor_data,sizeof(imu_sensor_data));
+#endif /*TCFG_IMUSENSOR_ENABLE*/
+
+ /* //MPU进入睡眠 */
+#if TCFG_MPU6887P_ENABLE
+ imu_sensor_io_ctl("mpu6887p", IMU_SENSOR_SLEEP, NULL);
+#endif /*TCFG_MPU6887P_ENABLE*/
+#if TCFG_QMI8658_ENABLE
+ imu_sensor_io_ctl("qmi8658", IMU_SENSOR_SLEEP, NULL);
+#endif /*TCFG_QMI8658_ENABLE*/
+#if TCFG_LSM6DSL_ENABLE
+ imu_sensor_io_ctl("lsm6dsl", IMU_SENSOR_SLEEP, NULL);
+#endif /*TCFG_LSM6DSL_ENABLE*/
+#if TCFG_ICM42670P_ENABLE
+ imu_sensor_io_ctl("icm42670p", IMU_SENSOR_SLEEP, NULL);
+#endif /*TCFG_ICM42670P_ENABLE*/
+#endif/*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
+
+#if TCFG_LP_TOUCH_KEY_ENABLE
+ lp_touch_key_init(&lp_touch_key_config);
+#endif /* #if TCFG_LP_TOUCH_KEY_ENABLE */
+
+#if (!TCFG_CHARGE_ENABLE)
+ CHARGE_EN(0);
+ CHGGO_EN(0);
+#endif
+
+#if TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE
+ chargestore_api_init(&chargestore_data);
+#endif
+}
+
+extern void cfg_file_parse(u8 idx);
+void board_init()
+{
+ board_power_init();
+ //adc_vbg_init();
+ adc_init();
+ cfg_file_parse(0);
+
+#if TCFG_SD0_ENABLE
+ dev_manager_init();
+#else
+ devices_init();
+#endif
+
+#if TCFG_AUDIO_ANC_ENABLE
+ anc_init();
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+
+ board_devices_init();
+
+#if TCFG_CHARGE_ENABLE
+ if(get_charge_online_flag())
+#else
+ if (0)
+#endif
+ {
+ power_set_mode(PWR_LDO15);
+ }else{
+ power_set_mode(TCFG_LOWPOWER_POWER_SEL);
+ }
+
+ //针对硅mic要输出1给mic供电
+ /* gpio_set_pull_up(IO_PORTA_04, 0); */
+ /* gpio_set_pull_down(IO_PORTA_04, 0); */
+ /* gpio_set_direction(IO_PORTA_04, 0); */
+ /* gpio_set_output_value(IO_PORTA_04,1); */
+
+#if TCFG_UART0_ENABLE
+ if (uart0_data.rx_pin < IO_MAX_NUM) {
+ gpio_set_die(uart0_data.rx_pin, 1);
+ }
+#endif
+
+#if TCFG_SMART_VOICE_ENABLE
+ int audio_smart_voice_detect_init(struct vad_mic_platform_data *mic_data);
+ audio_smart_voice_detect_init((struct vad_mic_platform_data *)&vad_mic_data);
+#endif /* #if TCFG_SMART_VOICE_ENABLE */
+
+#ifdef CONFIG_BOARD_AISPEECH_VAD_ASR
+ extern int audio_ais_platform_asr_init(struct vad_mic_platform_data *mic_data);
+ audio_ais_platform_asr_init((struct vad_mic_platform_data *)&vad_mic_data);
+#endif /*CONFIG_BOARD_AISPEECH_VAD_ASR*/
+
+#ifdef AUDIO_PCM_DEBUG
+ extern void uartSendInit();
+ uartSendInit();
+#endif/*AUDIO_PCM_DEBUG*/
+
+ extern void bredr_set_dut_enble(u8 en, u8 phone);
+ bredr_set_dut_enble(1, 1);
+}
+
+/*进软关机之前默认将IO口都设置成高阻状态,需要保留原来状态的请修改该函数*/
+extern void dac_power_off(void);
+void board_set_soft_poweroff(void)
+{
+ //power按键
+#if TCFG_IOKEY_ENABLE
+ soff_gpio_protect(TCFG_IOKEY_POWER_ONE_PORT);
+#endif
+
+#if (!(TCFG_LP_TOUCH_KEY_ENABLE && TCFG_LP_TOUCH_KEY1_EN))
+ //默认唤醒io
+ soff_gpio_protect(IO_PORTB_01);
+#endif
+
+ board_set_soft_poweroff_common(NULL);
+
+#if (TCFG_TEST_BOX_ENABLE || TCFG_CHARGESTORE_ENABLE || TCFG_ANC_BOX_ENABLE || TCFG_UMIDIGI_BOX_ENABLE)
+#if (TCFG_CHARGESTORE_PORT != IO_PORTP_00)
+ gpio_set_pull_up(TCFG_CHARGESTORE_PORT, 0);
+ gpio_set_pull_down(TCFG_CHARGESTORE_PORT, 1);
+ gpio_set_die(TCFG_CHARGESTORE_PORT, 1);
+ gpio_set_dieh(TCFG_CHARGESTORE_PORT, 1);
+ gpio_set_direction(TCFG_CHARGESTORE_PORT, 1);
+#else
+ power_wakeup_index_enable(2, 0);
+#endif
+#endif
+
+ dac_power_off();
+}
+
+#define APP_IO_DEBUG_0(i,x) {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT &= ~BIT(x);}
+#define APP_IO_DEBUG_1(i,x) {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT |= BIT(x);}
+
+void sleep_exit_callback(u32 usec)
+{
+ sleep_exit_callback_common(NULL);
+
+ putchar('>');
+}
+
+void sleep_enter_callback(u8 step)
+{
+ /* 此函数禁止添加打印 */
+ if (step == 1) {
+ putchar('<');
+ } else {
+ gpio_set_pull_up(TCFG_CHARGESTORE_PORT, 0);
+ gpio_set_pull_down(TCFG_CHARGESTORE_PORT, 0);
+ gpio_set_die(TCFG_CHARGESTORE_PORT, 1);
+ gpio_set_dieh(TCFG_CHARGESTORE_PORT, 1);
+ gpio_set_direction(TCFG_CHARGESTORE_PORT, 1);
+
+ sleep_enter_callback_common(NULL);
+ }
+}
+
+static void port_wakeup_callback(u8 index, u8 gpio)
+{
+ /* log_info("%s:%d,%d",__FUNCTION__,index,gpio); */
+#if TCFG_UMIDIGI_BOX_ENABLE
+ if (index == 2) {
+ ldo_port_wakeup_to_cmessage();
+ }
+#endif
+ switch (index) {
+#if (TCFG_TEST_BOX_ENABLE || TCFG_CHARGESTORE_ENABLE || TCFG_ANC_BOX_ENABLE)
+ case 2:
+ extern void chargestore_ldo5v_fall_deal(void);
+ chargestore_ldo5v_fall_deal();
+ break;
+#endif
+ }
+}
+
+static void aport_wakeup_callback(u8 index, u8 gpio, u8 edge)
+{
+ /* log_info("%s:%d,%d",__FUNCTION__,index,gpio); */
+#if TCFG_CHARGE_ENABLE
+ switch (gpio) {
+ case IO_CHGFL_DET://charge port
+ charge_wakeup_isr();
+ break;
+ case IO_VBTCH_DET://vbat port
+ case IO_LDOIN_DET://ldoin port
+ ldoin_wakeup_isr();
+ break;
+ }
+#endif
+}
+
+void board_power_init(void)
+{
+ log_info("Power init : %s", __FILE__);
+
+ power_init(&power_param);
+
+ power_set_callback(TCFG_LOWPOWER_LOWPOWER_SEL, sleep_enter_callback, sleep_exit_callback, board_set_soft_poweroff);
+
+#if TCFG_UMIDIGI_BOX_ENABLE
+ gpio_set_die(TCFG_CHARGESTORE_PORT, 1);
+ umidigi_chargestore_message_callback(app_umidigi_chargetore_message_deal);
+#endif
+
+ power_keep_dacvdd_en(0);
+
+ power_wakeup_init(&wk_param);
+
+ power_awakeup_set_callback(aport_wakeup_callback);
+ power_wakeup_set_callback(port_wakeup_callback);
+}
+#endif /* #ifdef CONFIG_BOARD_JL701N_DEMO */
diff --git a/apps/earphone/board/br28/board_jl701n_demo_cfg.h b/apps/earphone/board/br28/board_jl701n_demo_cfg.h
new file mode 100644
index 0000000..c1297a6
--- /dev/null
+++ b/apps/earphone/board/br28/board_jl701n_demo_cfg.h
@@ -0,0 +1,1192 @@
+#ifndef CONFIG_BOARD_JL701N_DEMO_CFG_H
+#define CONFIG_BOARD_JL701N_DEMO_CFG_H
+
+#include "board_jl701n_demo_global_build_cfg.h"
+
+#ifdef CONFIG_BOARD_JL701N_DEMO
+
+#define CONFIG_SDFILE_ENABLE
+
+//*********************************************************************************//
+// 配置开始 //
+//*********************************************************************************//
+#define ENABLE_THIS_MOUDLE 1
+#define DISABLE_THIS_MOUDLE 0
+
+#define ENABLE 1
+#define DISABLE 0
+
+#define NO_CONFIG_PORT (-1)
+
+//*********************************************************************************//
+// UART配置 //
+//*********************************************************************************//
+#define TCFG_UART0_ENABLE ENABLE_THIS_MOUDLE //串口打印模块使能
+#define TCFG_UART0_RX_PORT NO_CONFIG_PORT //串口接收脚配置(用于打印可以选择NO_CONFIG_PORT)
+#define TCFG_UART0_TX_PORT IO_PORTC_05 //串口发送脚配置
+#define TCFG_UART0_BAUDRATE 1000000 //串口波特率配置
+
+//*********************************************************************************//
+// IIC配置 //
+//*********************************************************************************//
+/*软件IIC设置*/
+#define TCFG_SW_I2C0_CLK_PORT IO_PORTG_07 //软件IIC CLK脚选择
+#define TCFG_SW_I2C0_DAT_PORT IO_PORTG_08 //软件IIC DAT脚选择
+#define TCFG_SW_I2C0_DELAY_CNT 10 //IIC延时参数,影响通讯时钟频率
+
+/*硬件IIC端口选择
+ SCL SDA
+ 'A': IO_PORT_DP IO_PORT_DM
+ 'B': IO_PORTA_09 IO_PORTA_10
+ 'C': IO_PORTA_07 IO_PORTA_08
+ 'D': IO_PORTA_05 IO_PORTA_06
+ */
+#define TCFG_HW_I2C0_PORTS 'B'
+#define TCFG_HW_I2C0_CLK 100000 //硬件IIC波特率
+
+//*********************************************************************************//
+// 硬件SPI 配置 //
+//*********************************************************************************//
+#define TCFG_HW_SPI1_ENABLE DISABLE_THIS_MOUDLE
+#define TCFG_HW_SPI1_PORT_CLK IO_PORTC_04//IO_PORTA_00
+#define TCFG_HW_SPI1_PORT_DO IO_PORTC_05//IO_PORTA_01
+#define TCFG_HW_SPI1_PORT_DI IO_PORTC_03//IO_PORTA_02
+#define TCFG_HW_SPI1_BAUD 2000000L
+#define TCFG_HW_SPI1_MODE SPI_MODE_BIDIR_1BIT
+#define TCFG_HW_SPI1_ROLE SPI_ROLE_MASTER
+
+#define TCFG_HW_SPI2_ENABLE DISABLE_THIS_MOUDLE
+#define TCFG_HW_SPI2_PORT_CLK NO_CONFIG_PORT
+#define TCFG_HW_SPI2_PORT_DO NO_CONFIG_PORT
+#define TCFG_HW_SPI2_PORT_DI NO_CONFIG_PORT
+#define TCFG_HW_SPI2_BAUD 2000000L
+#define TCFG_HW_SPI2_MODE SPI_MODE_BIDIR_1BIT
+#define TCFG_HW_SPI2_ROLE SPI_ROLE_MASTER
+
+//*********************************************************************************//
+// SD 配置 //
+//*********************************************************************************//
+#define TCFG_SD0_ENABLE DISABLE_THIS_MOUDLE //SD0模块使能
+#define TCFG_SD0_DAT_MODE 1 //线数设置,1:一线模式 4:四线模式
+#define TCFG_SD0_DET_MODE SD_CLK_DECT //SD卡检测方式
+#define TCFG_SD0_DET_IO IO_PORTB_03 //当检测方式为IO检测可用
+#define TCFG_SD0_DET_IO_LEVEL 0 //当检测方式为IO检测可用,0:低电平检测到卡。 1:高电平(外部电源)检测到卡。 2:高电平(SD卡电源)检测到卡。
+#define TCFG_SD0_CLK (3000000 * 4L) //SD卡时钟频率设置
+#define TCFG_SD0_PORT_CMD IO_PORTC_04
+#define TCFG_SD0_PORT_CLK IO_PORTC_05
+#define TCFG_SD0_PORT_DA0 IO_PORTC_03
+#define TCFG_SD0_PORT_DA1 NO_CONFIG_PORT //当选择4线模式时要用
+#define TCFG_SD0_PORT_DA2 NO_CONFIG_PORT
+#define TCFG_SD0_PORT_DA3 NO_CONFIG_PORT
+
+//*********************************************************************************//
+// USB 配置 //
+//*********************************************************************************//
+#define TCFG_PC_ENABLE DISABLE_THIS_MOUDLE//PC模块使能
+#define TCFG_UDISK_ENABLE 0//U盘模块使能
+#define TCFG_OTG_USB_DEV_EN BIT(0)//USB0 = BIT(0) USB1 = BIT(1)
+
+#include "usb_std_class_def.h"
+#undef USB_DEVICE_CLASS_CONFIG
+#define USB_DEVICE_CLASS_CONFIG (MASSSTORAGE_CLASS|HID_CLASS|AUDIO_CLASS)
+
+//#undef TCFG_OTG_MODE
+//#define TCFG_OTG_MODE (TCFG_OTG_MODE_HOST|TCFG_OTG_MODE_SLAVE|TCFG_OTG_MODE_CHARGE|OTG_DET_DM_ONLY)
+
+//*********************************************************************************//
+// key 配置 //
+//*********************************************************************************//
+#define KEY_NUM_MAX 10
+#define KEY_NUM 3
+
+#define MULT_KEY_ENABLE DISABLE //是否使能组合按键消息, 使能后需要配置组合按键映射表
+
+#define TCFG_KEY_TONE_EN DISABLE // 按键提示音。
+
+//*********************************************************************************//
+// iokey 配置 //
+//*********************************************************************************//
+#define TCFG_IOKEY_ENABLE 1 //是否使能IO按键
+#define TCFG_IOKEY_BOOT_LOCK_ENABLE 1 //开机锁键:长按开机不松手时屏蔽按键,避免误触关机;不需要则改 0,默认第 0 个端口
+
+#define TCFG_IOKEY_POWER_CONNECT_WAY ONE_PORT_TO_LOW //按键一端接低电平一端接IO
+
+#define TCFG_IOKEY_POWER_ONE_PORT IO_PORTB_01 //IO按键端口
+
+//*********************************************************************************//
+// adkey 配置 //
+//*********************************************************************************//
+#define TCFG_ADKEY_ENABLE DISABLE_THIS_MOUDLE//是否使能AD按键
+#define TCFG_ADKEY_PORT IO_PORT_DM //AD按键端口(需要注意选择的IO口是否支持AD功能)
+/*AD通道选择,需要和AD按键的端口相对应:
+ AD_CH_PA1 AD_CH_PA3 AD_CH_PA4 AD_CH_PA5
+ AD_CH_PA9 AD_CH_PA1 AD_CH_PB1 AD_CH_PB4
+ AD_CH_PB6 AD_CH_PB7 AD_CH_DP AD_CH_DM
+ AD_CH_PB2
+*/
+#define TCFG_ADKEY_AD_CHANNEL AD_CH_DM
+#define TCFG_ADKEY_EXTERN_UP_ENABLE ENABLE_THIS_MOUDLE //是否使用外部上拉
+
+#if TCFG_ADKEY_EXTERN_UP_ENABLE
+#define R_UP 220 //22K,外部上拉阻值在此自行设置
+#else
+#define R_UP 100 //10K,内部上拉默认10K
+#endif
+
+//必须从小到大填电阻,没有则同VDDIO,填0x3ffL
+#define TCFG_ADKEY_AD0 (0) //0R
+#define TCFG_ADKEY_AD1 (0x3ffL * 30 / (30 + R_UP)) //3k
+#define TCFG_ADKEY_AD2 (0x3ffL * 62 / (62 + R_UP)) //6.2k
+#define TCFG_ADKEY_AD3 (0x3ffL * 91 / (91 + R_UP)) //9.1k
+#define TCFG_ADKEY_AD4 (0x3ffL * 150 / (150 + R_UP)) //15k
+#define TCFG_ADKEY_AD5 (0x3ffL * 240 / (240 + R_UP)) //24k
+#define TCFG_ADKEY_AD6 (0x3ffL * 330 / (330 + R_UP)) //33k
+#define TCFG_ADKEY_AD7 (0x3ffL * 510 / (510 + R_UP)) //51k
+#define TCFG_ADKEY_AD8 (0x3ffL * 1000 / (1000 + R_UP)) //100k
+#define TCFG_ADKEY_AD9 (0x3ffL * 2200 / (2200 + R_UP)) //220k
+#define TCFG_ADKEY_VDDIO (0x3ffL)
+
+#define TCFG_ADKEY_VOLTAGE0 ((TCFG_ADKEY_AD0 + TCFG_ADKEY_AD1) / 2)
+#define TCFG_ADKEY_VOLTAGE1 ((TCFG_ADKEY_AD1 + TCFG_ADKEY_AD2) / 2)
+#define TCFG_ADKEY_VOLTAGE2 ((TCFG_ADKEY_AD2 + TCFG_ADKEY_AD3) / 2)
+#define TCFG_ADKEY_VOLTAGE3 ((TCFG_ADKEY_AD3 + TCFG_ADKEY_AD4) / 2)
+#define TCFG_ADKEY_VOLTAGE4 ((TCFG_ADKEY_AD4 + TCFG_ADKEY_AD5) / 2)
+#define TCFG_ADKEY_VOLTAGE5 ((TCFG_ADKEY_AD5 + TCFG_ADKEY_AD6) / 2)
+#define TCFG_ADKEY_VOLTAGE6 ((TCFG_ADKEY_AD6 + TCFG_ADKEY_AD7) / 2)
+#define TCFG_ADKEY_VOLTAGE7 ((TCFG_ADKEY_AD7 + TCFG_ADKEY_AD8) / 2)
+#define TCFG_ADKEY_VOLTAGE8 ((TCFG_ADKEY_AD8 + TCFG_ADKEY_AD9) / 2)
+#define TCFG_ADKEY_VOLTAGE9 ((TCFG_ADKEY_AD9 + TCFG_ADKEY_VDDIO) / 2)
+
+#define TCFG_ADKEY_VALUE0 0
+#define TCFG_ADKEY_VALUE1 1
+#define TCFG_ADKEY_VALUE2 2
+#define TCFG_ADKEY_VALUE3 3
+#define TCFG_ADKEY_VALUE4 4
+#define TCFG_ADKEY_VALUE5 5
+#define TCFG_ADKEY_VALUE6 6
+#define TCFG_ADKEY_VALUE7 7
+#define TCFG_ADKEY_VALUE8 8
+#define TCFG_ADKEY_VALUE9 9
+
+//*********************************************************************************//
+// irkey 配置 //
+//*********************************************************************************//
+#define TCFG_IRKEY_ENABLE DISABLE_THIS_MOUDLE//是否使能AD按键
+#define TCFG_IRKEY_PORT IO_PORTA_08 //IR按键端口
+
+//*********************************************************************************//
+// tocuh key 配置 //
+//*********************************************************************************//
+//*********************************************************************************//
+// lp tocuh key 配置 //
+//*********************************************************************************//
+#define TCFG_LP_TOUCH_KEY_ENABLE DISABLE_THIS_MOUDLE //是否使能触摸总开关
+
+#define TCFG_LP_TOUCH_KEY0_EN 0 //是否使能触摸按键0 —— PB0
+#define TCFG_LP_TOUCH_KEY1_EN 1 //是否使能触摸按键1 —— PB1
+#define TCFG_LP_TOUCH_KEY2_EN 0 //是否使能触摸按键2 —— PB2
+#define TCFG_LP_TOUCH_KEY3_EN 0 //是否使能触摸按键3 —— PB4
+#define TCFG_LP_TOUCH_KEY4_EN 0 //是否使能触摸按键4 —— PB5
+
+#define TCFG_LP_TOUCH_KEY0_WAKEUP_EN 0 //是否使能触摸按键0可以软关机低功耗唤醒
+#define TCFG_LP_TOUCH_KEY1_WAKEUP_EN 1 //是否使能触摸按键1可以软关机低功耗唤醒
+#define TCFG_LP_TOUCH_KEY2_WAKEUP_EN 0 //是否使能触摸按键2可以软关机低功耗唤醒
+#define TCFG_LP_TOUCH_KEY3_WAKEUP_EN 0 //是否使能触摸按键3可以软关机低功耗唤醒
+#define TCFG_LP_TOUCH_KEY4_WAKEUP_EN 0 //是否使能触摸按键4可以软关机低功耗唤醒
+
+//两个按键以上,可以做简单的滑动处理
+#define TCFG_LP_SLIDE_KEY_ENABLE 0 //是否使能触摸按键的滑动功能
+#define TCFG_LP_SLIDE_KEY_SHORT_DISTANCE 1 //两个触摸按键距离是否很短,只支持两个按键,现流行适用于耳机。如果距离很远,则可以两个以上的远距离触摸按键的滑动。
+
+#define TCFG_LP_EARTCH_KEY_ENABLE 0 //是否使能触摸按键用作入耳检测
+#define TCFG_LP_EARTCH_KEY_CH 2 //带入耳检测流程的按键号:0/1/2/3/4
+#define TCFG_LP_EARTCH_KEY_REF_CH 1 //入耳检测算法需要的另一个按键通道作为参考:0/1/2/3/4, 即入耳检测至少要使能两个触摸通道
+#define TCFG_LP_EARTCH_SOFT_INEAR_VAL 3000 //入耳检测算法需要的入耳阈值,参考文档设置
+#define TCFG_LP_EARTCH_SOFT_OUTEAR_VAL 2000 //入耳检测算法需要的出耳阈值,参考文档设置
+
+//电容检测灵敏度级数配置(范围: 0 ~ 9)
+//该参数配置与触摸时电容变化量有关, 触摸时电容变化量跟模具厚度, 触摸片材质, 面积等有关,
+//触摸时电容变化量越小, 推荐选择灵敏度级数越大,
+//触摸时电容变化量越大, 推荐选择灵敏度级数越小,
+//用户可以从灵敏度级数为0开始调试, 级数逐渐增大, 直到选择一个合适的灵敏度配置值.
+#define TCFG_LP_TOUCH_KEY0_SENSITIVITY 5 //触摸按键0电容检测灵敏度配置(级数0 ~ 9)
+#define TCFG_LP_TOUCH_KEY1_SENSITIVITY 5 //触摸按键1电容检测灵敏度配置(级数0 ~ 9)
+#define TCFG_LP_TOUCH_KEY2_SENSITIVITY 5 //触摸按键2电容检测灵敏度配置(级数0 ~ 9)
+#define TCFG_LP_TOUCH_KEY3_SENSITIVITY 5 //触摸按键3电容检测灵敏度配置(级数0 ~ 9)
+#define TCFG_LP_TOUCH_KEY4_SENSITIVITY 5 //触摸按键4电容检测灵敏度配置(级数0 ~ 9)
+
+//内置触摸灵敏度调试工具使能, 使能后可以通过连接PC端上位机通过SPP调试,
+//打开该宏需要确保同时打开宏:
+//1.USER_SUPPORT_PROFILE_SPP
+//2.APP_ONLINE_DEBUG
+//可以针对每款样机校准灵敏度参数表(在lp_touch_key.c ch_sensitivity_table), 详细使用方法请参考《低功耗内置触摸介绍》文档.
+#define TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE DISABLE
+
+
+#if TCFG_LP_TOUCH_KEY_ENABLE
+//如果 IO按键与触摸按键有冲突,则需要关掉 IO按键的 宏
+#if 1
+//取消外置触摸的一些宏定义
+#ifdef TCFG_IOKEY_ENABLE
+#undef TCFG_IOKEY_ENABLE
+#define TCFG_IOKEY_ENABLE DISABLE_THIS_MOUDLE
+#endif /* #ifdef TCFG_IOKEY_ENABLE */
+#endif
+
+//如果 AD按键与触摸按键有冲突,则需要关掉 AD按键的 宏
+#if 1
+//取消外置触摸的一些宏定义
+#ifdef TCFG_ADKEY_ENABLE
+#undef TCFG_ADKEY_ENABLE
+#define TCFG_ADKEY_ENABLE DISABLE_THIS_MOUDLE
+#endif /* #ifdef TCFG_ADKEY_ENABLE */
+#endif
+
+#if TCFG_LP_EARTCH_KEY_ENABLE
+#ifdef TCFG_EARTCH_EVENT_HANDLE_ENABLE
+#undef TCFG_EARTCH_EVENT_HANDLE_ENABLE
+#endif
+#define TCFG_EARTCH_EVENT_HANDLE_ENABLE 0 //入耳检测事件APP流程处理使能
+
+#if TCFG_LP_SLIDE_KEY_ENABLE
+#error "入耳检测和滑动功能不能同时打开"
+#endif
+
+#endif /* #if TCFG_LP_EARTCH_KEY_ENABLE */
+
+#endif /* #if TCFG_LP_TOUCH_KEY_ENABLE */
+
+
+//*********************************************************************************//
+// plcnt tocuh key 配置 //
+//*********************************************************************************//
+#define TCFG_TOUCH_KEY_ENABLE DISABLE_THIS_MOUDLE //是否使能plcnt触摸按键
+//key0配置
+#define TCFG_TOUCH_KEY0_PRESS_DELTA 100//变化阈值,当触摸产生的变化量达到该阈值,则判断被按下,每个按键可能不一样,可先在驱动里加到打印,再反估阈值
+#define TCFG_TOUCH_KEY0_PORT IO_PORTB_06 //触摸按键key0 IO配置
+#define TCFG_TOUCH_KEY0_VALUE 0x12 //触摸按键key0 按键值
+//key1配置
+#define TCFG_TOUCH_KEY1_PRESS_DELTA 100//变化阈值,当触摸产生的变化量达到该阈值,则判断被按下,每个按键可能不一样,可先在驱动里加到打印,再反估阈值
+#define TCFG_TOUCH_KEY1_PORT IO_PORTB_07 //触摸按键key1 IO配置
+#define TCFG_TOUCH_KEY1_VALUE 0x34 //触摸按键key1 按键值
+
+//*********************************************************************************//
+// rdec_key 配置 //
+//*********************************************************************************//
+#define TCFG_RDEC_KEY_ENABLE DISABLE_THIS_MOUDLE //是否使能RDEC按键
+//RDEC0配置
+#define TCFG_RDEC0_ECODE1_PORT IO_PORTA_03
+#define TCFG_RDEC0_ECODE2_PORT IO_PORTA_04
+#define TCFG_RDEC0_KEY0_VALUE 0
+#define TCFG_RDEC0_KEY1_VALUE 1
+
+//RDEC1配置
+#define TCFG_RDEC1_ECODE1_PORT IO_PORTA_05
+#define TCFG_RDEC1_ECODE2_PORT IO_PORTA_06
+#define TCFG_RDEC1_KEY0_VALUE 2
+#define TCFG_RDEC1_KEY1_VALUE 3
+
+//RDEC2配置
+#define TCFG_RDEC2_ECODE1_PORT IO_PORTB_00
+#define TCFG_RDEC2_ECODE2_PORT IO_PORTB_01
+#define TCFG_RDEC2_KEY0_VALUE 4
+#define TCFG_RDEC2_KEY1_VALUE 5
+
+//*********************************************************************************//
+// Digital Hearing Aid(DHA)辅听耳机配置 //
+//*********************************************************************************//
+/*辅听功能使能*/
+#define TCFG_AUDIO_HEARING_AID_ENABLE DISABLE_THIS_MOUDLE
+/*听力验配功能*/
+#define TCFG_AUDIO_DHA_FITTING_ENABLE DISABLE
+/*辅听功能互斥配置*/
+#define TCFG_AUDIO_DHA_AND_MUSIC_MUTEX ENABLE //辅听功能和音乐播放互斥(默认互斥,资源有限)
+#define TCFG_AUDIO_DHA_AND_CALL_MUTEX ENABLE //辅听功能和通话互斥(默认互斥,资源有限)
+#define TCFG_AUDIO_DHA_AND_TONE_MUTEX ENABLE //辅听功能和提示音互斥
+/*辅听功能MIC的采样率*/
+#define TCFG_AUDIO_DHA_MIC_SAMPLE_RATE (32000)
+
+/*混叠DAC输出采样率*/
+#define TCFG_AD2DA_LOW_LATENCY_SAMPLE_RATE (48000)
+/*低延时 mic 通道*/
+#define TCFG_AD2DA_LOW_LATENCY_MIC_CHANNEL (AUDIO_ADC_MIC_0)
+
+#if TCFG_AUDIO_HEARING_AID_ENABLE
+#define TCFG_AUDIO_MUSIC_SAMPLE_RATE TCFG_AD2DA_LOW_LATENCY_SAMPLE_RATE
+#endif
+
+//*********************************************************************************//
+// Sidetone配置 //
+//*********************************************************************************//
+#define TCFG_SIDETONE_ENABLE 0 //ENABLE
+
+//*********************************************************************************//
+// Audio配置 //
+//*********************************************************************************//
+#define TCFG_AUDIO_ADC_ENABLE ENABLE_THIS_MOUDLE
+#define TCFG_AUDIO_ADC_LINE_CHA AUDIO_ADC_LINE0
+/*MIC LDO电流档位设置:
+ 0:0.625ua 1:1.25ua 2:1.875ua 3:2.5ua*/
+#define TCFG_AUDIO_ADC_LD0_SEL 2
+
+#define TCFG_AUDIO_DAC_ENABLE ENABLE_THIS_MOUDLE
+#define TCFG_AUDIO_DAC_LDO_SEL 1
+
+/*
+DAC硬件上的连接方式,可选的配置:
+ DAC_OUTPUT_MONO_L 左声道
+ DAC_OUTPUT_MONO_R 右声道
+ DAC_OUTPUT_LR 立体声
+ DAC_OUTPUT_MONO_LR_DIFF 左右差分 LP-RP
+
+ TCFG_AUDIO_DAC_CONNECT_MODE 决定方案需要使用多少个DAC声道
+ TCFG_AUDIO_DAC_MODE 决定DAC是差分输出模式还是单端输出模式
+
+ TCFG_AUDIO_DAC_CONNECT_MODE和TCFG_AUDIO_DAC_MODE不同配置组合实际使用引脚见下表:
+
++--------------------+-------------------+-------------------+----------------------------+-------------------------+
+| | DAC_OUTPUT_MONO_L | DAC_OUTPUT_MONO_R | DAC_OUTPUT_LR | DAC_OUTPUT_MONO_LR_DIFF |
++--------------------+-------------------+-------------------+----------------------------+-------------------------+
+| DAC_MODE_L_DIFF | 单声道 LP-LN | 单声道 RP-RN | 立声道 L:LP-LN R:RP-RN | 不支持 |
+| DAC_MODE_L_SINGLE | 单声道 LP-AGND | 单声道 RP-AGND | 立声道 L:LP-AGND R:RP-AGND | 单声道 LP-RP |
+| DAC_MODE_H1_DIFF | 单声道 LP-LN | 单声道 RP-RN | 立声道 L:LP-LN R:RP-RN | 不支持 |
+| DAC_MODE_H1_SINGLE | 单声道 LP-AGND | 单声道 RP-AGND | 立声道 L:LP-AGND R:RP-AGND | 单声道 LP-RP |
+| DAC_MODE_H2_DIFF | 单声道 LP-LN | 单声道 RP-RN | 立声道 L:LP-LN R:RP-RN | 不支持 |
+| DAC_MODE_H2_SINGLE | 单声道 LP-AGND | 单声道 RP-AGND | 立声道 L:LP-AGND R:RP-AGND | 单声道 LP-RP |
++--------------------+-------------------+-------------------+----------------------------+-------------------------+
+*/
+#define TCFG_AUDIO_DAC_CONNECT_MODE DAC_OUTPUT_MONO_R
+
+/*
+ DAC模式选择
+#define DAC_MODE_L_DIFF (0) // 低压差分模式 , 适用于低功率差分耳机 , 输出幅度 0~2Vpp
+#define DAC_MODE_L_SINGLE (1) // 低压单端模式 , 主要用于左右差分模式, 差分输出幅度 0~2Vpp
+#define DAC_MODE_H1_DIFF (2) // 高压1档差分模式, 适用于高功率差分耳机 , 输出幅度 0~3Vpp , VDDIO >= 3.0V
+#define DAC_MODE_H1_SINGLE (3) // 高压1档单端模式, 适用于高功率单端PA音箱, 输出幅度 0~1.5Vpp, VDDIO >= 3.0V
+#define DAC_MODE_H2_DIFF (4) // 高压2档差分模式, 适用于高功率差分PA音箱, 输出幅度 0~5Vpp , VDDIO >= 3.3V
+#define DAC_MODE_H2_SINGLE (5) // 高压2档单端模式, 适用于高功率单端PA音箱, 输出幅度 0~2.5Vpp, VDDIO >= 3.3V
+*/
+#define TCFG_AUDIO_DAC_MODE DAC_MODE_L_SINGLE // DAC_MODE_L_DIFF 低压, DAC_MODE_H1_DIFF 高压
+
+
+/*预留接口,未使用*/
+#define TCFG_AUDIO_DAC_PA_PORT NO_CONFIG_PORT
+#define CONFIG_FATFS_ENABLE 0 //文件系统
+#define TCFG_DEV_MANAGER_ENABLE 1 //设备管理
+#define CONFIG_BT_BACKGROUND_ENABLE 0 //蓝牙后台
+#define TCFG_BT_SNIFF_DISABLE 0 //蓝牙SNIFF
+//*******************************************************************************//
+// 模式配置 //
+//*******************************************************************************//
+//**********************************AUX模式**************************************//
+//#define TCFG_APP_AUX_EN DISABLE_THIS_MOUDLE
+//********************************MUSIC模式**************************************//
+#if TCFG_SD0_ENABLE
+#define TCFG_APP_MUSIC_EN DISABLE_THIS_MOUDLE //应用代码
+#define CONFIG_FATFS_ENABLE ENABLE //文件系统
+#define TCFG_DEV_MANAGER_ENABLE ENABLE //设备管理
+#endif //TCFG_SD0_ENABLE
+//***********************************PC模式**************************************//
+#define TCFG_APP_PC_EN DISABLE_THIS_MOUDLE
+#define TCFG_ENTER_PC_MODE DISABLE
+#define TCFG_ONLY_PC_ENABLE DISABLE
+#if (TCFG_APP_MUSIC_EN || TCFG_APP_PC_EN)
+#define CONFIG_BT_BACKGROUND_ENABLE ENABLE //蓝牙后台
+#define TCFG_BT_SNIFF_DISABLE DISABLE //蓝牙SNIFF
+#define TCFG_DEC2TWS_ENABLE DISABLE
+#endif
+
+//*********************************ANC配置******************************************//
+
+#define TCFG_AUDIO_ANC_ENABLE CONFIG_ANC_ENABLE //ANC总使能,根据global_bulid_cfg板级定义
+#define TCFG_ANC_TOOL_DEBUG_ONLINE DISABLE_THIS_MOUDLE //ANC工具蓝牙spp调试
+#define TCFG_ANC_SELF_DUT_GET_SZ DISABLE_THIS_MOUDLE //ANC自研产测SZ获取,用于(HYBIRD/FB)产测
+/*
+ *当通话与ANC共用FF MIC,并且通话要求更大的MIC模拟增益时,使能TCFG_AUDIO_DYNAMIC_ADC_GAIN,
+ *则通话MIC模拟增益以配置工具通话参数为准,通话时,ANC使用通话MIC模拟增益
+ */
+#define TCFG_AUDIO_DYNAMIC_ADC_GAIN 0
+//#define TCFG_AUDIO_ANC_EAR_ADAPTIVE_EN DISABLE_THIS_MOUDLE //ANC耳道自适应使能, 耳道是变量
+
+
+#define ANC_TRAIN_MODE ANC_FF_EN //ANC类型配置:单前馈,单后馈,混合馈
+#define ANC_CH ANC_L_CH //| ANC_R_CH //ANC通道使能:左通道 | 右通道
+#define ANCL_FF_MIC A_MIC0 //ANC左通道FFMIC类型
+#define ANCL_FB_MIC MIC_NULL //ANC左通道FBMIC类型
+#define ANCR_FF_MIC MIC_NULL //ANC右通道FFMIC类型
+#define ANCR_FB_MIC MIC_NULL //ANC右通道FBMIC类型
+/********************************ANC配置END*****************************************/
+
+/*通话下行(DL:DownLink)通路噪声门配置*/
+#define TCFG_AUDIO_ESCO_DL_NOISEGATE_ENABLE DISABLE_THIS_MOUDLE
+#define ESCO_NOISEGATE_THR -40.f //噪声门阈值:-90~0 Unit:dB
+#define ESCO_NOISEGATE_GAIN 0.0f //噪声增益衰减比例:0~1 Ratio
+
+/*通话下行降噪使能*/
+#define TCFG_ESCO_DL_NS_ENABLE DISABLE_THIS_MOUDLE
+
+/*通话下行限幅器使能*/
+#define TCFG_AUDIO_ESCO_LIMITER_ENABLE 0
+#define ESCO_DL_LIMITER_THR 0.0f //-60 ~0db 限幅器输出的最大幅度,
+
+/*
+ *系统音量类型选择
+ *软件数字音量是指纯软件对声音进行运算后得到的
+ *硬件数字音量是指dac内部数字模块对声音进行运算后输出
+ *选择软件数字音量或者硬件数字音量会固定模拟音量,
+ *固定的模拟音量值由 MAX_ANA_VOL 决定
+ */
+#define VOL_TYPE_DIGITAL 0 //软件数字音量
+#define VOL_TYPE_AD 2 //联合音量(模拟数字混合调节)
+#define VOL_TYPE_DIGITAL_HW 3 //硬件数字音量
+/*注意:ANC使能情况下使用软件数字音量*/
+#if (TCFG_AUDIO_ANC_ENABLE || TCFG_AD2DA_LOW_LATENCY_ENABLE || TCFG_AUDIO_HEARING_AID_ENABLE)
+#define SYS_VOL_TYPE VOL_TYPE_DIGITAL
+#else
+#define SYS_VOL_TYPE VOL_TYPE_DIGITAL_HW
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+/*
+ *通话的时候使用数字音量
+ *0:通话使用和SYS_VOL_TYPE一样的音量调节类型
+ *1:通话使用数字音量调节,更加平滑
+ */
+#define TCFG_CALL_USE_DIGITAL_VOLUME 0
+//注意:数字音量不用使能TCFG_CALL_USE_DIGITAL_VOLUME
+#if ((SYS_VOL_TYPE == VOL_TYPE_DIGITAL) || (SYS_VOL_TYPE == VOL_TYPE_DIGITAL_HW))
+#undef TCFG_CALL_USE_DIGITAL_VOLUME
+#define TCFG_CALL_USE_DIGITAL_VOLUME 0
+#endif/*SYS_VOL_TYPE*/
+
+/*PDM数字MIC配置*/
+#define TCFG_AUDIO_PLNK_SCLK_PIN IO_PORTA_04
+#define TCFG_AUDIO_PLNK_DAT0_PIN IO_PORTA_03
+#define TCFG_AUDIO_PLNK_DAT1_PIN NO_CONFIG_PORT
+
+/*MIC模式配置:单端隔直电容模式/差分隔直电容模式/单端省电容模式*/
+/*注意:ANC使能情况下,使用差分mic*/
+#if (TCFG_AUDIO_ANC_ENABLE || TCFG_AUDIO_HEARING_AID_ENABLE)
+#define TCFG_AUDIO_MIC_MODE AUDIO_MIC_CAP_DIFF_MODE
+#define TCFG_AUDIO_MIC1_MODE AUDIO_MIC_CAP_DIFF_MODE
+#define TCFG_AUDIO_MIC2_MODE AUDIO_MIC_CAP_DIFF_MODE
+#define TCFG_AUDIO_MIC3_MODE AUDIO_MIC_CAP_DIFF_MODE
+#else
+#define TCFG_AUDIO_MIC_MODE AUDIO_MIC_CAP_MODE
+#define TCFG_AUDIO_MIC1_MODE AUDIO_MIC_CAP_MODE
+#define TCFG_AUDIO_MIC2_MODE AUDIO_MIC_CAP_MODE
+#define TCFG_AUDIO_MIC3_MODE AUDIO_MIC_CAP_MODE
+#endif /*TCFG_AUDIO_ANC_ENABLE || TCFG_AUDIO_HEARING_AID_ENABLE*/
+
+/*
+ *>>MIC电源管理:根据具体方案,选择对应的mic供电方式
+ *(1)如果是多种方式混合,则将对应的供电方式或起来即可,比如(MIC_PWR_FROM_GPIO | MIC_PWR_FROM_MIC_BIAS)
+ *(2)如果使用固定电源供电(比如dacvdd),则配置成DISABLE_THIS_MOUDLE
+ */
+#define MIC_PWR_FROM_GPIO (1UL << 0) //使用普通IO输出供电
+#define MIC_PWR_FROM_MIC_BIAS (1UL << 1) //使用内部mic_ldo供电(有上拉电阻可配)
+#define MIC_PWR_FROM_MIC_LDO (1UL << 2) //使用内部mic_ldo供电
+//配置MIC电源
+#define TCFG_AUDIO_MIC_PWR_CTL MIC_PWR_FROM_MIC_BIAS
+
+//使用普通IO输出供电:不用的port配置成NO_CONFIG_PORT
+#if (TCFG_AUDIO_MIC_PWR_CTL & MIC_PWR_FROM_GPIO)
+#define TCFG_AUDIO_MIC_PWR_PORT IO_PORTC_02
+#define TCFG_AUDIO_MIC1_PWR_PORT NO_CONFIG_PORT
+#define TCFG_AUDIO_MIC2_PWR_PORT NO_CONFIG_PORT
+#endif/*MIC_PWR_FROM_GPIO*/
+
+//使用内部mic_ldo供电(有上拉电阻可配)
+#if (TCFG_AUDIO_MIC_PWR_CTL & MIC_PWR_FROM_MIC_BIAS)
+#define TCFG_AUDIO_MIC0_BIAS_EN ENABLE_THIS_MOUDLE/*Port:PA2*/
+#define TCFG_AUDIO_MIC1_BIAS_EN ENABLE_THIS_MOUDLE/*Port:PA4*/
+#define TCFG_AUDIO_MIC2_BIAS_EN ENABLE_THIS_MOUDLE/*Port:PG7*/
+#define TCFG_AUDIO_MIC3_BIAS_EN ENABLE_THIS_MOUDLE/*Port:PG5*/
+#endif/*MIC_PWR_FROM_MIC_BIAS*/
+
+//使用内部mic_ldo供电(Port:PA0)
+#if (TCFG_AUDIO_MIC_PWR_CTL & MIC_PWR_FROM_MIC_LDO)
+#define TCFG_AUDIO_MIC_LDO_EN ENABLE_THIS_MOUDLE
+#endif/*MIC_PWR_FROM_MIC_LDO*/
+/*>>MIC电源管理配置结束*/
+
+/*
+ *第三方清晰语音开发配置:
+ *(1)使用杰理自研算法
+ *#define TCFG_CVP_DEVELOP_ENABLE DISABLE_THIS_MOUDLE
+ *(2)用户自己开发算法
+ *#define TCFG_CVP_DEVELOP_ENABLE CVP_CFG_USER_DEFINED
+ *(3)使用思必驰3-mic通话算法
+ *#define TCFG_CVP_DEVELOP_ENABLE CVP_CFG_AIS_3MIC
+ */
+#define CVP_CFG_USER_DEFINED 1 //用户自定义开发算法
+#define CVP_CFG_AIS_3MIC 2 //思必驰3mic算法
+#define TCFG_CVP_DEVELOP_ENABLE DISABLE_THIS_MOUDLE
+
+#if (TCFG_CVP_DEVELOP_ENABLE == CVP_CFG_AIS_3MIC)
+#define CONFIG_BOARD_AISPEECH_NR
+#define CONFIG_BOARD_AISPEECH_NR_GAIN
+#endif /*TCFG_CVP_DEVELOP_ENABLE*/
+
+#ifdef CONFIG_BOARD_AISPEECH_NR_GAIN
+//思必驰三麦MIC增益设置
+#define TALK_MIC0_GAIN 13
+#define FF_MIC1_GAIN 13
+#define FB_MIC2_GAIN 0
+#define OTHER_MIC3_GAIN 0
+#endif /*CONFIG_BOARD_AISPEECH_NR_GAIN*/
+
+/*通话降噪模式配置*/
+#define CVP_ANS_MODE 0 /*传统降噪*/
+#define CVP_DNS_MODE 1 /*神经网络降噪*/
+#define TCFG_AUDIO_CVP_NS_MODE CVP_DNS_MODE
+
+/*
+ * ENC(双mic降噪)配置
+ * 双mic降噪包括DMS_NORMAL和DMS_FLEXIBLE,在使能TCFG_AUDIO_DUAL_MIC_ENABLE
+ * 的前提下,根据具体需求,选择对应的DMS模式
+ */
+/*ENC(双mic降噪)使能*/
+#define TCFG_AUDIO_DUAL_MIC_ENABLE DISABLE_THIS_MOUDLE
+
+/*ENC(3 mic降噪)使能*/
+#define TCFG_AUDIO_TRIPLE_MIC_ENABLE DISABLE_THIS_MOUDLE
+
+#if (TCFG_CVP_DEVELOP_ENABLE == CVP_CFG_AIS_3MIC)
+#undef TCFG_AUDIO_TRIPLE_MIC_ENABLE
+#define TCFG_AUDIO_TRIPLE_MIC_ENABLE ENABLE_THIS_MOUDLE
+#endif /*TCFG_CVP_DEVELOP_ENABLE*/
+
+/*DMS模式选择*/
+#define DMS_NORMAL 1 //普通双mic降噪(mic距离固定)
+#define DMS_FLEXIBLE 2 //适配mic距离不固定且距离比较远的情况,比如头戴式话务耳机
+#define TCFG_AUDIO_DMS_SEL DMS_NORMAL
+
+/*ENC双mic配置主mic副mic对应的mic port*/
+#define DMS_MASTER_MIC0 0 //mic0是主mic
+#define DMS_MASTER_MIC1 1 //mic1是主mic
+#define TCFG_AUDIO_DMS_MIC_MANAGE DMS_MASTER_MIC0
+
+//MIC通道配置
+#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
+#define TCFG_AUDIO_ADC_MIC_CHA (AUDIO_ADC_MIC_0 | AUDIO_ADC_MIC_1 | AUDIO_ADC_MIC_2)
+#elif TCFG_AUDIO_DUAL_MIC_ENABLE
+#define TCFG_AUDIO_ADC_MIC_CHA (AUDIO_ADC_MIC_0 | AUDIO_ADC_MIC_1)
+#else
+#define TCFG_AUDIO_ADC_MIC_CHA AUDIO_ADC_MIC_0
+#endif/*TCFG_AUDIO_TRIPLE_MIC_ENABLE*/
+
+/*
+ *支持省电容MIC模块
+ *(1)要使能省电容mic,首先要支持该模块:TCFG_SUPPORT_MIC_CAPLESS
+ *(2)只有支持该模块,才能使能该模块:TCFG_MIC_CAPLESS_ENABLE
+ */
+#define TCFG_SUPPORT_MIC_CAPLESS DISABLE_THIS_MOUDLE
+//省电容MIC使能
+#define TCFG_MIC_CAPLESS_ENABLE DISABLE_THIS_MOUDLE
+//省电容MIC1使能
+#define TCFG_MIC1_CAPLESS_ENABLE DISABLE_THIS_MOUDLE
+
+// AUTOMUTE
+#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_AND_MUSIC_MUTEX)
+#define AUDIO_OUTPUT_AUTOMUTE ENABLE_THIS_MOUDLE
+#else
+#define AUDIO_OUTPUT_AUTOMUTE ENABLE_THIS_MOUDLE
+#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
+
+// OUTPUT WAY
+#define AUDIO_OUT_WAY_TYPE AUDIO_WAY_TYPE_DAC
+
+/*Audio数据导出配置:支持BT_SPP\SD\UART载体导出*/
+#define AUDIO_DATA_EXPORT_USE_SD 1
+#define AUDIO_DATA_EXPORT_USE_SPP 2
+#define AUDIO_DATA_EXPORT_USE_UART 3
+#define TCFG_AUDIO_DATA_EXPORT_ENABLE DISABLE_THIS_MOUDLE
+/*
+ *蓝牙spp数据导出的mic 通道,调试双麦ENC时,需要和ENC的mic通道保持一致
+ */
+#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
+/*3MIC通话的时候需要导出3路麦克风数据分析*/
+#define TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA (AUDIO_ADC_MIC_0 | AUDIO_ADC_MIC_1 | AUDIO_ADC_MIC_2)
+#else
+/*2MIC通话的时候需要导出两路麦克风数据分析*/
+#define TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA (AUDIO_ADC_MIC_0 | AUDIO_ADC_MIC_1)
+#endif
+
+/*通话清晰语音处理数据导出*/
+//#define AUDIO_PCM_DEBUG
+
+/*通话参数在线调试*/
+//#define TCFG_AEC_TOOL_ONLINE_ENABLE DISABLE_THIS_MOUDLE
+
+/*麦克风测试和传递函数测试*/
+//#define TCFG_AUDIO_MIC_DUT_ENABLE DISABLE_THIS_MOUDLE
+
+/*
+ *第三方ASR(语音识别)配置
+ *(1)用户自己开发算法
+ *#define TCFG_AUDIO_ASR_DEVELOP ASR_CFG_USER_DEFINED
+ *(2)使用思必驰ASR算法
+ *#define TCFG_AUDIO_ASR_DEVELOP ASR_CFG_AIS
+ */
+#define ASR_CFG_USER_DEFINED 1
+#define ASR_CFG_AIS 2
+#define TCFG_AUDIO_ASR_DEVELOP DISABLE_THIS_MOUDLE
+
+#if (TCFG_AUDIO_ASR_DEVELOP == ASR_CFG_AIS)
+#undef TCFG_SMART_VOICE_ENABLE
+#undef TCFG_KWS_VOICE_EVENT_HANDLE_ENABLE
+#undef TCFG_VAD_LOWPOWER_CLOCK
+#define TCFG_SMART_VOICE_ENABLE DISABLE_THIS_MOUDLE
+#define TCFG_KWS_VOICE_EVENT_HANDLE_ENABLE TCFG_SMART_VOICE_ENABLE //语音事件处理流程开关
+#define TCFG_VAD_LOWPOWER_CLOCK VAD_CLOCK_USE_PMU_STD12M
+
+#define CONFIG_BOARD_AISPEECH_VAD_ASR
+#endif /*TCFG_AUDIO_ASR_DEVELOP*/
+
+
+//*********************************************************************************//
+// IIS 配置 //
+//*********************************************************************************//
+#define TCFG_AUDIO_INPUT_IIS DISABLE_THIS_MOUDLE
+#define TCFG_AUDIO_OUTPUT_IIS DISABLE_THIS_MOUDLE
+#define TCFG_AUDIO_OUTPUT_IIS_AND_DAC 0//单独iis输出使能 0:iis, 1:dac+iis
+
+//IIS 输出使用的通道号
+#define TCFG_IIS_OUTPUT_DATAPORT_SEL ALINK_CH0
+//IIS 输入使用的通道号
+#define TCFG_IIS_INPUT_DATAPORT_SEL ALINK_CH1
+
+#define TCFG_IIS_MODE (0) // 0:master 1:slave
+#define TCFG_IIS_SR (44100)
+
+#define TCFG_IIS_MCLK_IO IO_PORTA_12
+#define TCFG_SCLK_IO IO_PORTA_13
+#define TCFG_LRCLK_IO IO_PORTA_14
+#define TCFG_DATA0_IO IO_PORTA_15
+#define TCFG_DATA1_IO IO_PORTA_11
+#define TCFG_DATA2_IO IO_PORTA_11
+#define TCFG_DATA3_IO IO_PORTA_11
+
+//*********************************************************************************//
+// 充电舱配置 //
+// 充电舱/蓝牙测试盒/ANC测试三者为同级关系,开启任一功能都会初始化PP0通信接口 //
+//*********************************************************************************//
+//#define TCFG_CHARGESTORE_ENABLE DISABLE_THIS_MOUDLE //是否支持智能充电舱
+#define TCFG_TEST_BOX_ENABLE ENABLE_THIS_MOUDLE //是否支持蓝牙测试盒
+#define TCFG_ANC_BOX_ENABLE CONFIG_ANC_ENABLE //是否支持ANC测试盒
+//#define TCFG_UMIDIGI_BOX_ENABLE 0//ENABLE_THIS_MOUDLE //是否支持UMIDIGI充电舱
+/*
+#if TCFG_UMIDIGI_BOX_ENABLE
+#define _20MS_BIT 20 //传输20ms/Bit时使用
+#define _40MS_BIT 40 //传输40ms/Bit时使用
+#define TIMER2CMESSAGE _20MS_BIT //定时器收集message周期
+#endif*/
+#define TCFG_CHARGESTORE_PORT IO_PORTP_00 //耳机通讯的IO口
+#if (TCFG_TEST_BOX_ENABLE) && (TCFG_CHARGESTORE_PORT != IO_PORTP_00)
+#define TCFG_TEST_BOX_ANY_IO_UPDATE ENABLE_THIS_MOUDLE
+#undef CONFIG_UART_UPDATE_PIN
+#define CONFIG_UART_UPDATE_PIN USBDM // 如果TCFG_CHARGESTORE_PORT修改了这里也要做对应的修改
+#if (TCFG_CHARGESTORE_PORT == TCFG_IOKEY_POWER_ONE_PORT)
+#error "ERR:TCFG_CHARGESTORE_PORT AND TCFG_IOKEY_POWER_ONE_PORT IS SAME"
+#endif
+#endif
+
+
+//*********************************************************************************//
+// 充电参数配置 //
+//*********************************************************************************//
+//是否支持芯片内置充电
+#define TCFG_CHARGE_ENABLE 1
+//是否支持开机充电
+#define TCFG_CHARGE_POWERON_ENABLE 1
+//是否支持拔出充电自动开机功能
+#define TCFG_CHARGE_OFF_POWERON_NE ENABLE
+/*充电截止电压可选配置*/
+#define TCFG_CHARGE_FULL_V CHARGE_FULL_V_4199
+/*充电截止电流可选配置*/
+#define TCFG_CHARGE_FULL_MA CHARGE_FULL_mA_10
+/*恒流充电电流可选配置*/
+#define TCFG_CHARGE_MA CHARGE_mA_250
+/*涓流充电电流配置*/
+#define TCFG_CHARGE_TRICKLE_MA CHARGE_mA_10
+
+//*********************************************************************************//
+// LED 配置 //
+//*********************************************************************************//
+#define TCFG_PWMLED_ENABLE DISABLE_THIS_MOUDLE //是否支持PMW LED推灯模块
+#define TCFG_PWMLED_IOMODE LED_ONE_IO_MODE //LED模式,单IO还是两个IO推灯
+#define TCFG_PWMLED_PIN IO_PORTB_06 //LED使用的IO口
+//*********************************************************************************//
+// 时钟配置 //
+//*********************************************************************************//
+#define TCFG_CLOCK_SYS_SRC SYS_CLOCK_INPUT_PLL_BT_OSC //系统时钟源选择
+//#define TCFG_CLOCK_SYS_HZ 12000000 //系统时钟设置
+//#define TCFG_CLOCK_SYS_HZ 16000000 //系统时钟设置
+#define TCFG_CLOCK_SYS_HZ 24000000 //系统时钟设置
+//#define TCFG_CLOCK_SYS_HZ 32000000 //系统时钟设置
+//#define TCFG_CLOCK_SYS_HZ 48000000 //系统时钟设置
+//#define TCFG_CLOCK_SYS_HZ 54000000 //系统时钟设置
+//#define TCFG_CLOCK_SYS_HZ 64000000 //系统时钟设置
+#define TCFG_CLOCK_OSC_HZ 24000000 //外界晶振频率设置
+#define TCFG_CLOCK_MODE CLOCK_MODE_ADAPTIVE
+
+//*********************************************************************************//
+// 电源配置 //
+//*********************************************************************************//
+#define TCFG_LOWPOWER_POWER_SEL PWR_LDO15//PWR_LDO15 //电源模式设置,可选DCDC和LDO
+#define TCFG_LOWPOWER_BTOSC_DISABLE 0 //低功耗模式下BTOSC是否保持
+#define TCFG_LOWPOWER_LOWPOWER_SEL SLEEP_EN//DEEP_SLEEP_EN//SLEEP_EN//DEEP_SLEEP_EN //低功耗使能,蓝牙&&系统空闲可进入低功耗
+#define TCFG_LOWPOWER_VDDIOM_LEVEL VDDIOM_VOL_28V //vddiom等级
+#define TCFG_LOWPOWER_OSC_TYPE OSC_TYPE_LRC //低功耗晶振类型,btosc/lrc
+///#if (TCFG_AUDIO_ASR_DEVELOP && TCFG_CVP_DEVELOP_ENABLE)
+///#define TCFG_LOWPOWER_RAM_SIZE 0 // 低功耗掉电ram大小,单位:128K,可设置值:0、2、3
+///#elif (TCFG_SMART_VOICE_ENABLE || TCFG_AUDIO_ASR_DEVELOP || TCFG_CVP_DEVELOP_ENABLE || TCFG_AUDIO_TRIPLE_MIC_ENABLE\
+/// || TCFG_AUDIO_SPATIAL_EFFECT_ENABLE || TCFG_AUDIO_ANC_EAR_ADAPTIVE_EN || TCFG_ANC_SELF_DUT_GET_SZ || AUDIO_DUT_FRE_RESPONE_ENABLE)
+///#define TCFG_LOWPOWER_RAM_SIZE 2 // 低功耗掉电ram大小,单位:128K,可设置值:0、2、3
+///#else
+#define TCFG_LOWPOWER_RAM_SIZE 2 // 低功耗掉电ram大小,单位:128K,可设置值:0、2、3
+///#endif
+
+//*********************************************************************************//
+// EQ配置 //
+//*********************************************************************************//
+//EQ配置,使用在线EQ时,EQ文件和EQ模式无效。有EQ文件时,使能TCFG_USE_EQ_FILE,默认不用EQ模式切换功能
+#define TCFG_EQ_ENABLE 0 //支持EQ功能,EQ总使能
+// #if TCFG_EQ_ENABLE
+#define TCFG_EQ_ONLINE_ENABLE 0 //支持在线EQ调试,如果使用蓝牙串口调试,需要打开宏 APP_ONLINE_DEBUG,否则,默认使用uart调试(二选一)
+#define TCFG_BT_MUSIC_EQ_ENABLE 0 //支持蓝牙音乐EQ
+#define TCFG_PHONE_EQ_ENABLE 0 //支持通话近端EQ
+#define TCFG_AUDIO_OUT_EQ_ENABLE 0 //mix out级,增加EQ高低音接口
+#define TCFG_AEC_DCCS_EQ_ENABLE 0 // AEC DCCS
+#define TCFG_AEC_UL_EQ_ENABLE 0 // AEC UL
+#define TCFG_MUSIC_MODE_EQ_ENABLE 0 //支持音乐模式EQ
+#define TCFG_PC_MODE_EQ_ENABLE 0 //支持pc模式EQ
+
+#define TCFG_USE_EQ_FILE 0 //离线EQ使用配置文件还是默认系数表 1:使用文件 0 使用默认系数表
+#if !TCFG_USE_EQ_FILE
+#define TCFG_USER_EQ_MODE_NUM 7 //EQ默认系数表的模式个数,默认是7个
+#endif
+
+#define TCFG_EQ_FILE_SWITCH_EN 0 //支持eq配置文件切换(需使能TCFG_USE_EQ_FILE)
+#if !TCFG_USE_EQ_FILE
+#undef TCFG_EQ_FILE_SWITCH_EN
+#define TCFG_EQ_FILE_SWITCH_EN 0
+#endif
+
+#define EQ_SECTION_MAX 10 //EQ段数,最大20
+#define TCFG_CALL_DL_EQ_SECTION 3 //通话下行EQ段数,小于等于EQ_SECTION_MAX ,最大10段
+#define TCFG_CALL_UL_EQ_SECTION 3 //通话上行EQ段数,小于等于EQ_SECTION_MAX ,最大10段
+
+// #endif//TCFG_EQ_ENABLE
+
+/*省电容mic通过eq模块实现去直流滤波*/
+#if (TCFG_SUPPORT_MIC_CAPLESS && (TCFG_MIC_CAPLESS_ENABLE || TCFG_MIC1_CAPLESS_ENABLE))
+#if ((TCFG_EQ_ENABLE == 0) || (TCFG_AEC_DCCS_EQ_ENABLE == 0))
+#error "MicCapless enable,Please enable TCFG_EQ_ENABLE and TCFG_AEC_DCCS_EQ_ENABLE"
+#endif
+#endif
+
+
+#define TCFG_DRC_ENABLE 0 //DRC 总使能
+#define TCFG_BT_MUSIC_DRC_ENABLE 0 //支持蓝牙音乐DRC
+#define TCFG_MUSIC_MODE_DRC_ENABLE 0 //支持音乐模式DRC
+#define TCFG_PC_MODE_DRC_ENABLE 0 //支持PC模式DRC
+#define TCFG_CVP_UL_DRC_ENABLE 0 //支持通话上行DRC
+
+#define TCFG_AUDIO_MDRC_ENABLE 0 //音乐多带WDRC使能 0:关闭多带WDRC, 1:使能多带WDRC
+#if TCFG_AUDIO_MDRC_ENABLE
+#if !TCFG_DRC_ENABLE
+#undef TCFG_DRC_ENABLE
+#define TCFG_DRC_ENABLE 1
+#endif
+#if !TCFG_BT_MUSIC_DRC_ENABLE
+#undef TCFG_BT_MUSIC_DRC_ENABLE
+#define TCFG_BT_MUSIC_DRC_ENABLE 1
+#endif
+#endif
+
+#if TCFG_AUDIO_HEARING_AID_ENABLE
+#if !TCFG_DRC_ENABLE
+#undef TCFG_DRC_ENABLE
+#define TCFG_DRC_ENABLE 0 /*DRC 总使能*/
+#endif
+#endif
+//*********************************************************************************//
+// 新配置工具 && 调音工具 //
+//*********************************************************************************//
+#define TCFG_CFG_TOOL_ENABLE DISABLE //是否支持在线配置工具
+#define TCFG_EFFECT_TOOL_ENABLE DISABLE //是否支持在线音效调试,使能该项还需使能EQ总使能TCFG_EQ_ENABL,
+#define TCFG_NULL_COMM 0 //不支持通信
+#define TCFG_UART_COMM 1 //串口通信
+#define TCFG_USB_COMM 2 //USB通信
+#define TCFG_SPP_COMM 3 //蓝牙SPP通信
+#if (TCFG_CFG_TOOL_ENABLE || TCFG_EFFECT_TOOL_ENABLE)
+#define TCFG_COMM_TYPE TCFG_USB_COMM //通信方式选择
+#else
+#define TCFG_COMM_TYPE TCFG_NULL_COMM
+#endif
+#define TCFG_ONLINE_TX_PORT IO_PORT_DP //UART模式调试TX口选择
+#define TCFG_ONLINE_RX_PORT IO_PORT_DM //UART模式调试RX口选择
+#define TCFG_ONLINE_ENABLE (TCFG_EFFECT_TOOL_ENABLE) //是否支持音效在线调试功能
+
+/***********************************非用户配置区***********************************/
+#include "usb_std_class_def.h"
+#if (TCFG_CFG_TOOL_ENABLE || TCFG_EFFECT_TOOL_ENABLE)
+#if (TCFG_COMM_TYPE == TCFG_USB_COMM)
+#define TCFG_USB_CDC_BACKGROUND_RUN ENABLE
+#endif
+#if (TCFG_COMM_TYPE == TCFG_UART_COMM)
+#define TCFG_USB_CDC_BACKGROUND_RUN DISABLE
+#endif
+#endif
+/**********************************************************************************/
+
+/***********************************非用户配置区***********************************/
+#if TCFG_EQ_ONLINE_ENABLE
+#if (TCFG_USE_EQ_FILE == 0)
+#undef TCFG_USE_EQ_FILE
+#define TCFG_USE_EQ_FILE 0 //开在线调试时,打开使用离线配置文件宏定义
+#endif
+#if TCFG_AUDIO_OUT_EQ_ENABLE
+#undef TCFG_AUDIO_OUT_EQ_ENABLE
+#define TCFG_AUDIO_OUT_EQ_ENABLE 0 //开在线调试时,关闭高低音
+#endif
+#endif
+
+/**********************************************************************************/
+
+//*********************************************************************************//
+// g-sensor配置 //
+//*********************************************************************************//
+#define TCFG_GSENSOR_ENABLE 0 //gSensor使能
+#define TCFG_DA230_EN 0
+#define TCFG_SC7A20_EN 0
+#define TCFG_STK8321_EN 0
+#define TCFG_IRSENSOR_ENABLE 0
+#define TCFG_JSA1221_ENABLE 0
+#define TCFG_GSENOR_USER_IIC_TYPE 0 //0:软件IIC 1:硬件IIC
+
+//*********************************************************************************//
+// imu-sensor配置 //
+//*********************************************************************************//
+#define TCFG_IMUSENSOR_ENABLE 0 //imu Sensor使能
+//mpu6887 cfg
+#define TCFG_MPU6887P_ENABLE 0
+#define TCFG_MPU6887P_INTERFACE_TYPE 0 //0:iic, 1:spi
+#define TCFG_MPU6887P_USER_IIC_TYPE 0 //iic有效:1:硬件iic, 0:软件iic
+#define TCFG_MPU6887P_USER_IIC_INDEX 0 //IIC 序号
+#define TCFG_MPU6887P_DETECT_IO (-1) //传感器中断io
+#define TCFG_MPU6887P_AD0_SELETE_IO (-1) //iic地址选择io
+//icm42607p cfg
+#define TCFG_ICM42670P_ENABLE 0
+#define TCFG_ICM42670P_INTERFACE_TYPE 0 //0:iic, 1:spi
+#define TCFG_ICM42670P_USER_IIC_TYPE 0 //iic有效:1:硬件iic, 0:软件iic
+#define TCFG_ICM42670P_USER_IIC_INDEX 0 //IIC 序号
+#define TCFG_ICM42670P_DETECT_IO (-1) //传感器中断io
+#define TCFG_ICM42670P_AD0_SELETE_IO (-1) //iic地址选择io
+//mpu9250 cfg
+#define TCFG_TP_MPU9250_ENABLE 0
+#define TCFG_MPU9250_INTERFACE_TYPE 0 //不支持.0:iic, 1:spi
+#define TCFG_MPU9250_USER_IIC_TYPE 0 //iic有效:1:硬件iic, 0:软件iic
+#define TCFG_MPU9250_USER_IIC_INDEX 0 //IIC 序号
+#define TCFG_MPU9250_DETECT_IO -1 //传感器中断io
+//sh3001 cfg
+#define TCFG_SH3001_ENABLE 0
+#define TCFG_SH3001_INTERFACE_TYPE 0 //0:iic, 1:spi
+#define TCFG_SH3001_USER_IIC_TYPE 0 //1:硬件iic, 0:软件iic
+#define TCFG_SH3001_USER_IIC_INDEX 0 //IIC 序号
+#define TCFG_SH3001_DETECT_IO -1 //传感器中断io
+//qmi8658 cfg
+#define TCFG_QMI8658_ENABLE 0
+#define TCFG_QMI8658_INTERFACE_TYPE 0 //0:iic, 1:spi, 2:i3c
+#define TCFG_QMI8658_USER_IIC_TYPE 0 //1:硬件iic, 0:软件iic
+#define TCFG_QMI8658_USER_IIC_INDEX 0 //IIC 序号
+#define TCFG_QMI8658_DETECT_IO (-1) //传感器中断io
+#define TCFG_QMI8658_AD0_SELETE_IO (-1) //iic地址选择io
+//lsm6dsl cfg
+#define TCFG_LSM6DSL_ENABLE 0
+#define TCFG_LSM6DSL_INTERFACE_TYPE 0 //0:iic, 1:spi
+#define TCFG_LSM6DSL_USER_IIC_TYPE 0 //1:硬件iic, 0:软件iic
+#define TCFG_LSM6DSL_USER_IIC_INDEX 0 //IIC 序号
+#define TCFG_LSM6DSL_DETECT_IO (-1) //传感器中断io
+#define TCFG_LSM6DSL_AD0_SELETE_IO (-1) //iic地址选择io
+//mpu6050 cfg
+#define TCFG_MPU6050_EN 0
+//qmc5883 cfg
+
+/*
+ *imu-sensor power manager
+ *不用独立IO供电,则配置 NO_CONFIG_PORT
+ */
+#define TCFG_IMU_SENSOR_PWR_PORT NO_CONFIG_PORT
+
+
+/*空间音效和传感器的依赖*/
+#if (TCFG_AUDIO_SPATIAL_EFFECT_ENABLE == 0)
+#undef TCFG_IMUSENSOR_ENABLE
+#undef TCFG_MPU6887P_ENABLE
+#undef TCFG_ICM42670P_ENABLE
+#undef TCFG_QMI8658_ENABLE
+#undef TCFG_LSM6DSL_ENABLE
+#undef TCFG_TP_MPU9250_ENABLE
+#undef TCFG_SH3001_ENABLE
+#undef TCFG_MPU6050_EN
+#define TCFG_IMUSENSOR_ENABLE 0
+#define TCFG_MPU6887P_ENABLE 0
+#define TCFG_ICM42670P_ENABLE 0
+#define TCFG_QMI8658_ENABLE 0
+#define TCFG_LSM6DSL_ENABLE 0
+#define TCFG_TP_MPU9250_ENABLE 0
+#define TCFG_SH3001_ENABLE 0
+#define TCFG_MPU6050_EN 0
+#endif/*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
+
+//*********************************************************************************//
+// 系统配置 //
+//*********************************************************************************//
+#define TCFG_AUTO_SHUT_DOWN_TIME 0 //没有蓝牙连接自动关机时间
+#define TCFG_SYS_LVD_EN 0 //电量检测使能
+#define TCFG_POWER_ON_NEED_KEY 1 //是否需要按按键开机配置
+#define TWFG_APP_POWERON_IGNORE_DEV 0 //上电忽略挂载设备,0时不忽略,非0则n毫秒忽略
+
+//*********************************************************************************//
+// 蓝牙配置 //
+//*********************************************************************************//
+
+#define TCFG_USER_BLE_ENABLE 1 //BLE功能使能
+#define TCFG_USER_BT_CLASSIC_ENABLE 0 //经典蓝牙使能
+#define TCFG_BT_SUPPORT_AAC 0 //AAC格式支持
+#define TCFG_BT_SUPPORT_LDAC 0 //LDAC格式支持
+
+#if TCFG_BT_SUPPORT_LDAC
+#define CONFIG_BT_RX_BUFF_SIZE (46 * 1024)
+#else
+//#define CONFIG_BT_RX_BUFF_SIZE (22 * 1024)
+#define CONFIG_BT_RX_BUFF_SIZE (1 * 1024)
+#endif
+
+#define USER_SUPPORT_PROFILE_SPP 0
+#define USER_SUPPORT_PROFILE_HFP 0
+#define USER_SUPPORT_PROFILE_A2DP 0
+#define USER_SUPPORT_PROFILE_AVCTP 0
+#define USER_SUPPORT_PROFILE_HID 0
+#define USER_SUPPORT_PROFILE_PNP 0
+#define USER_SUPPORT_PROFILE_PBAP 0
+
+#if TCFG_USER_TWS_ENABLE
+#define TCFG_BD_NUM 1 //连接设备个数配置
+#define TCFG_AUTO_STOP_PAGE_SCAN_TIME 0 //配置一拖二第一台连接后自动关闭PAGE SCAN的时间(单位分钟)
+#else
+#define TCFG_BD_NUM 1 //连接设备个数配置
+#define TCFG_AUTO_STOP_PAGE_SCAN_TIME 0 //配置一拖二第一台连接后自动关闭PAGE SCAN的时间(单位分钟)
+#endif
+
+#define BT_INBAND_RINGTONE 0 //是否播放手机自带来电铃声
+#define BT_PHONE_NUMBER 0 //是否播放来电报号
+//#define BT_SUPPORT_DISPLAY_BAT 0 //是否使能电量检测
+//#define BT_SUPPORT_MUSIC_VOL_SYNC 0 //是否使能音量同步
+
+/*spp数据导出配置*/
+#if ((TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SPP) || TCFG_AUDIO_MIC_DUT_ENABLE)
+#undef TCFG_USER_TWS_ENABLE
+#undef TCFG_USER_BLE_ENABLE
+#undef TCFG_BD_NUM
+#undef USER_SUPPORT_PROFILE_SPP
+#undef USER_SUPPORT_PROFILE_A2DP
+#define TCFG_USER_TWS_ENABLE 0//spp数据导出,关闭tws
+#define TCFG_USER_BLE_ENABLE 0//spp数据导出,关闭ble
+#define TCFG_BD_NUM 1//连接设备个数配置
+#define USER_SUPPORT_PROFILE_SPP 1
+#define USER_SUPPORT_PROFILE_A2DP 0
+#define APP_ONLINE_DEBUG 1//通过spp导出数据
+#else
+#define APP_ONLINE_DEBUG 0//在线APP调试,发布默认不开
+#endif/*TCFG_AUDIO_DATA_EXPORT_ENABLE*/
+
+/*以下功能需要打开SPP和在线调试功能
+ *1、回音消除参数在线调试
+ *2、通话CVP_DUT 产测模式
+ *3、ANC工具蓝牙spp调试
+ *4、配置/调音工具spp调试
+ *5、空间音频在线工具spp调试
+ */
+#if (TCFG_AEC_TOOL_ONLINE_ENABLE || TCFG_AUDIO_CVP_DUT_ENABLE || TCFG_ANC_TOOL_DEBUG_ONLINE \
+ || (TCFG_SENSOR_DATA_EXPORT_ENABLE == SENSOR_DATA_EXPORT_USE_SPP) \
+ || TCFG_SPATIAL_EFFECT_ONLINE_ENABLE )||(TCFG_COMM_TYPE == TCFG_SPP_COMM) \
+ || (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_FITTING_ENABLE)
+#undef USER_SUPPORT_PROFILE_SPP
+#undef APP_ONLINE_DEBUG
+#define USER_SUPPORT_PROFILE_SPP 1
+#define APP_ONLINE_DEBUG 1
+#endif/*TCFG_AEC_TOOL_ONLINE_ENABLE*/
+
+#if ((TCFG_CFG_TOOL_ENABLE || TCFG_EFFECT_TOOL_ENABLE) && (TCFG_COMM_TYPE == TCFG_SPP_COMM))
+#if ((!USER_SUPPORT_PROFILE_SPP) || (!APP_ONLINE_DEBUG))
+#error "Please enable USER_SUPPORT_PROFILE_SPP and APP_ONLINE_DEBUG ! !"
+#endif
+#endif
+
+//*********************************************************************************//
+// 编解码格式配置(CodecFormat) //
+//*********************************************************************************//
+/*解码格式使能*/
+#define TCFG_DEC_MP3_ENABLE ENABLE
+#define TCFG_DEC_WTGV2_ENABLE 0
+#define TCFG_DEC_G729_ENABLE DISABLE
+#define TCFG_DEC_WMA_ENABLE DISABLE
+#define TCFG_DEC_WAV_ENABLE DISABLE
+#define TCFG_DEC_FLAC_ENABLE DISABLE
+#define TCFG_DEC_APE_ENABLE DISABLE
+#define TCFG_DEC_M4A_ENABLE DISABLE
+#define TCFG_DEC_ALAC_ENABLE DISABLE
+#define TCFG_DEC_AMR_ENABLE DISABLE
+#define TCFG_DEC_DTS_ENABLE DISABLE
+#define TCFG_DEC_G726_ENABLE DISABLE
+#define TCFG_DEC_MIDI_ENABLE DISABLE
+#define TCFG_DEC_MTY_ENABLE DISABLE
+#define TCFG_DEC_SBC_ENABLE 0
+#define TCFG_DEC_PCM_ENABLE DISABLE
+#define TCFG_DEC_CVSD_ENABLE DISABLE
+#define TCFG_DEC_LC3_ENABLE DISABLE
+#define TCFG_DEC_AAC_ENABLE DISABLE
+#define TCFG_DEC_LDAC_ENABLE DISABLE
+#define TCFG_DEC_SPEEX_ENABLE DISABLE
+#define TCFG_DEC_OPUS_ENABLE DISABLE
+
+/*编码格式使能*/
+#define TCFG_ENC_MSBC_ENABLE 0
+#define TCFG_ENC_CVSD_ENABLE 0
+#define TCFG_ENC_OPUS_ENABLE DISABLE
+#define TCFG_ENC_SPEEX_ENABLE DISABLE
+
+/*提示音叠加配置*/
+#define TCFG_WAV_TONE_MIX_ENABLE DISABLE
+#define TCFG_MP3_TONE_MIX_ENABLE DISABLE
+#define TCFG_AAC_TONE_MIX_ENABLE DISABLE//叠加AAC解码需要使用malloc
+#define TCFG_WTG_TONE_MIX_ENABLE 0
+#define TCFG_WTS_TONE_MIX_ENABLE 0
+
+//*********************************************************************************//
+// fm emitter 配置 (不支持) //
+//*********************************************************************************//
+#define TCFG_APP_FM_EMITTER_EN DISABLE_THIS_MOUDLE
+
+//*********************************************************************************//
+// AI配置 //
+//*********************************************************************************//
+#if TCFG_USER_BLE_ENABLE
+#define DUEROS_DMA_EN 0
+#define TRANS_DATA_EN 0
+#define BLE_HID_EN 0
+
+#if (DUEROS_DMA_EN)
+#define BT_MIC_EN 0
+#else
+#define BT_MIC_EN 0
+#endif
+
+#if (DUEROS_DMA_EN || TRANS_DATA_EN || TUYA_DEMO_EN || LL_SYNC_EN)
+#define BT_FOR_APP_EN 1
+#else
+#define BT_FOR_APP_EN 0
+#endif
+
+#if(DUEROS_DMA_EN)
+#define USE_DMA_TONE 0 //使用DMA提示音
+#else
+#define USE_DMA_TONE 0
+#endif
+
+#if (DUEROS_DMA_EN && TRANS_DATA_EN)
+#error "they can not enable at the same time!"
+#endif
+#endif
+
+//*********************************************************************************//
+// 环绕音效使能
+//*********************************************************************************//
+#define AUDIO_SURROUND_CONFIG 0//3d环绕
+
+#define AUDIO_VBASS_CONFIG 0//虚拟低音,24M mips
+
+
+#define TCFG_AUDIO_BASS_BOOST DISABLE_THIS_MOUDLE//低音增强功能
+#define TCFG_AUDIO_BASS_BOOST_TEST DISABLE_THIS_MOUDLE//默认使用PP用于功能有效性测试,产品开发时,默认关闭
+#if TCFG_AUDIO_BASS_BOOST
+#if (!TCFG_DRC_ENABLE)
+#error "低音增强需使能DRC宏TCFG_DRC_ENABLE"
+#endif
+#endif
+
+#define AEC_PITCHSHIFTER_CONFIG 0 //通话上行变声,左耳触发变大叔声,右耳触发变女声
+
+#define AEC_PRESETS_UL_EQ_CONFIG 0 //通话上行预设eq系数表使能,使能后不使用效果文件的系数表
+
+#define AUDIO_SPK_EQ_CONFIG 0//SPK_EQ 使能
+#if AUDIO_SPK_EQ_CONFIG
+#if (EQ_SECTION_MAX < 10)
+#undef EQ_SECTION_MAX
+#define EQ_SECTION_MAX 10
+#endif
+#if !APP_ONLINE_DEBUG
+#undef APP_ONLINE_DEBUG
+#define APP_ONLINE_DEBUG 1
+#endif
+#if (!TCFG_EQ_ENABLE)
+#error "需使能总eq宏TCFG_EQ_ENABLE"
+#endif
+#endif/*AUDIO_SPK_EQ_CONFIG*/
+
+
+
+//*********************************************************************************//
+// 电源切换配置 //
+//*********************************************************************************//
+
+#define CONFIG_PHONE_CALL_USE_LDO15 0
+
+
+//*********************************************************************************//
+// 时钟切换配置 //
+//*********************************************************************************//
+
+#define CONFIG_BT_NORMAL_HZ (24 * 1000000L)
+#define CONFIG_BT_CONNECT_HZ (48 * 1000000L)
+
+#if TCFG_BT_MUSIC_EQ_ENABLE
+#define CONFIG_BT_A2DP_HZ (96 * 1000000L)
+#else
+#define CONFIG_BT_A2DP_HZ (48 * 1000000L)
+#endif
+
+#define CONFIG_MUSIC_DEC_CLOCK (48 * 1000000L)
+#define CONFIG_MUSIC_IDLE_CLOCK (48 * 1000000L)
+
+#define CONFIG_BT_CALL_HZ (64 * 1000000L)
+#define CONFIG_BT_CALL_ADVANCE_HZ (64 * 1000000L)
+#define CONFIG_BT_CALL_16k_HZ (80 * 1000000L)
+#define CONFIG_BT_CALL_16k_ADVANCE_HZ (96 * 1000000L)
+#define CONFIG_BT_CALL_DNS_HZ (96 * 1000000L)
+
+
+//*********************************************************************************//
+// 第三方音效算法配置 //
+//*********************************************************************************//
+#define TCFG_DIAFX_ENABLE 0
+//#define TCFG_EFFECT_DEVELOP_ENABLE 0
+
+#if (TCFG_EQ_ONLINE_ENABLE && (!TCFG_EFFECT_TOOL_ENABLE) || (!TCFG_EQ_ONLINE_ENABLE && (TCFG_EFFECT_TOOL_ENABLE)))
+#error "音效在线调试需使能调音工具宏TCFG_EFFECT_TOOL_ENABLE"
+#endif
+
+#if TCFG_AUDIO_OUTPUT_IIS && (SYS_VOL_TYPE != VOL_TYPE_DIGITAL)
+#error "iis输出需要使用数字音量"
+#endif
+
+//*********************************************************************************//
+// 配置结束 //
+//*********************************************************************************//
+
+
+
+#endif //CONFIG_BOARD_JL701N_DEMO
+#endif //CONFIG_BOARD_JL701N_DEMO_CFG_H
diff --git a/apps/earphone/board/br28/board_jl701n_demo_global_build_cfg.h b/apps/earphone/board/br28/board_jl701n_demo_global_build_cfg.h
new file mode 100644
index 0000000..1687599
--- /dev/null
+++ b/apps/earphone/board/br28/board_jl701n_demo_global_build_cfg.h
@@ -0,0 +1,123 @@
+#ifndef CONFIG_BOARD_JL701N_DEMO_POST_BUILD_CFG_H
+#define CONFIG_BOARD_JL701N_DEMO_POST_BUILD_CFG_H
+
+/* 改文件只添加和isd_config.ini相关的配置,用以生成isd_config.ini */
+/* 其他不相关的配置请勿添加在改文件 */
+
+#ifdef CONFIG_BOARD_JL701N_DEMO
+
+/* Following Macros Affect Periods Of Both Code Compiling And Post-build */
+
+#define CONFIG_DOUBLE_BANK_ENABLE 1 //单双备份选择(若打开了改宏,FLASH结构变为双备份结构,适用于接入第三方协议的OTA, PS: JL-OTA同样支持双备份升级, 需要根据实际FLASH大小同时配置CONFIG_FLASH_SIZE)
+#define CONFIG_APP_OTA_ENABLE 1 //是否支持RCSP升级(JL-OTA)
+
+#define CONFIG_UPDATE_JUMP_TO_MASK 0 //配置升级到loader的方式0为直接reset,1为跳转(适用于芯片电源由IO口KEEP住的方案,需要注意检查跳转前是否将使用DMA的硬件模块全部关闭)
+
+#define CONFIG_IO_KEY_EN 1 //配置是否使用IO按键,配合RESET1
+#define CONFIG_UPDATE_WITH_MD5_CHECK_EN 0 //配置升级是否支持MD5校验
+
+#define CONFIG_ANC_ENABLE 0 //配置是否支持ANC
+
+//flash size vaule definition
+#define FLASH_SIZE_256K 0x40000
+#define FLASH_SIZE_512K 0x80000
+#define FLASH_SIZE_1M 0x100000
+#define FLASH_SIZE_2M 0x200000
+#define FLASH_SIZE_4M 0x400000
+
+#define CONFIG_FLASH_SIZE FLASH_SIZE_1M //配置FLASH大小
+
+
+/* Above Macros Affect Periods Of Both Code Compiling And Post-build */
+
+/* Following Macros Only For Post Bulid Configuaration */
+
+#define CONFIG_DB_UPDATE_DATA_GENERATE_EN 1 //是否生成db_data.bin(用于第三方协议接入使用)
+#define CONFIG_ONLY_GRENERATE_ALIGN_4K_CODE 1 //ufw只生成1份4K对齐的代码
+
+//config for supported chip version
+#ifdef CONFIG_BR30_C_VERSION
+#define CONFIG_SUPPORTED_CHIP_VERSION C
+#else
+#define CONFIG_SUPPORTED_CHIP_VERSION B,D,E,M,N,O,P
+#endif
+
+//DON'T MODIFY THIS CONFIG EXCEPT SDK PUBLISHER
+#define CONFIG_CHIP_NAME AC701N //除了SDK发布者,请不要修改
+//it can be modified before first programming,but keep the same as the original version
+#define CONFIG_PID AC701N //烧写或强制升级之前可以修改,之后升级要保持一致
+//it can be modified before first programming,but keep the same as the original version
+#define CONFIG_VID 0.01 //烧写或强制升级之前可以修改,之后升级要保持一致
+
+//Project with bluetooth,it must use OSC as PLL_SOURCE;
+#define CONFIG_PLL_SOURCE_USING_LRC 0 //PLL时钟源选择 1:LRC 2:OSC
+
+//config alignment size unit
+#ifdef CONFIG_256K_FLASH
+#define ALIGN_UNIT_256B 1 //FLASH对齐方式选择,如果是256K的FLASH,选择256BYTE对齐方式
+#else
+#define ALIGN_UNIT_256B 0
+#endif
+
+//partial platform check this config to select the uart IO for wired update
+#define CONFIG_UART_UPDATE_PIN -1
+
+//isd_download loader/uboot/update_loader debug io config
+//#define CONFIG_UBOOT_DEBUG_PIN PA05
+//#define CONFIG_UBOOT_DEBUG_BAUD_RATE 1000000
+
+//config long-press reset io pin,time,trigger level
+#define CONFIG_RESET_PIN LDO //io pin
+#define CONFIG_RESET_TIME 00 //unit:second
+#define CONFIG_RESET_LEVEL 0 //tigger level(0/1)
+
+#if CONFIG_IO_KEY_EN
+#define CONFIG_SUPPORT_RESET1
+#define CONFIG_RESET1_PIN PB01 //io pin
+#define CONFIG_RESET1_TIME 16 //unit:second
+#define CONFIG_RESET1_LEVEL 0 //tigger level(0/1)
+#endif
+
+//reserved three custom cfg item for the future definition
+//#define CONFIG_CUSTOM_CFG1_TYPE POWER_PIN
+//#define CONFIG_CUSTOM_CFG1_VALUE PC01_1
+
+//#define CONFIG_CUSTOM_CFG2_TYPE
+//#define CONFIG_CUSTOM_CFG2_VALUE
+
+//#define CONFIG_CUSTOM_CFG3_TYPE
+//#define CONFIG_CUSTOM_CFG3_VALUE
+
+
+#define CONFIG_VDDIO_LVD_LEVEL 3 ////VDDIO_LVD挡位,0: 1.9V 1: 2.0V 2: 2.1V 3: 2.2V 4: 2.3V 5: 2.4V 6: 2.5V 7: 2.6V
+
+//with single-bank mode,actual vm size should larger this VM_LEAST_SIZE,and dual bank mode,actual vm size equals this;
+#define CONFIG_VM_LEAST_SIZE 8K
+//config whether erased this area when do a update,1-No Operation,0-Erase
+#define CONFIG_VM_OPT 1
+
+//config whether erased this area when do a update,1-No Operation,0-Erase
+#define CONFIG_BTIF_OPT 1
+
+//reserved two custom cfg area for the future definition
+//#define CONFIG_RESERVED_AREA1 EXIF1
+#ifdef CONFIG_RESERVED_AREA1
+#define CONFIG_RESERVED_AREA1_ADDR AUTO
+#define CONFIG_RESERVED_AREA1_LEN 0x1000
+#define CONFIG_RESERVED_AREA1_OPT 1
+//#define CONFIG_RESERVED_AREA1_FILE anc_gains.bin
+#endif
+
+//#define CONFIG_RESERVED_AREA2 EXIF2
+#ifdef CONFIG_RESERVED_AREA2
+#define CONFIG_RESERVED_AREA2_ADDR AUTO
+#define CONFIG_RESERVED_AREA2_LEN 0x1000
+#define CONFIG_RESERVED_AREA2_OPT 1
+//#define CONFIG_RESERVED_AREA2_FILE anc_gains.bin
+#endif
+
+/* Above Macros Only For Post Bulid Configuaration */
+#endif /* #ifdef CONFIG_BOARD_JL701N_DEMO */
+
+#endif /* #ifndef CONFIG_BOARD_JL701N_DEMO_POST_BUILD_CFG_H */
+
diff --git a/apps/earphone/bt_auto_test.c b/apps/earphone/bt_auto_test.c
new file mode 100644
index 0000000..d720f46
--- /dev/null
+++ b/apps/earphone/bt_auto_test.c
@@ -0,0 +1,417 @@
+#if 0
+
+#include "system/includes.h"
+#include "media/includes.h"
+#include "tone_player.h"
+
+#include "app_config.h"
+#include "app_action.h"
+
+#include "btstack/avctp_user.h"
+#include "btstack/btstack_task.h"
+#include "btstack/frame_queque.h"
+#include "user_cfg.h"
+#include "aec_user.h"
+#include "classic/hci_lmp.h"
+#include "bt_common.h"
+#include "pbg_user.h"
+
+#if TCFG_USER_TWS_ENABLE
+#include "bt_tws.h"
+#endif
+
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV)
+#include "include/bt_ble.h"
+#endif
+
+#if TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE
+//#include "app_chargestore.h"
+#endif
+
+#include "asm/charge.h"
+#include "app_charge.h"
+#include "ui_manage.h"
+
+//#include "app_chargestore.h"
+#include "app_online_cfg.h"
+#include "app_main.h"
+#include "app_power_manage.h"
+#include "gSensor/gSensor_manage.h"
+#include "key_event_deal.h"
+#include "classic/tws_api.h"
+#include "asm/pwm_led.h"
+#include "vol_sync.h"
+
+
+#define CONFIG_SPP_PRINTF_DEBUG 0
+
+#define CONFIG_A2DP_PLAY_PAUSE_TEST 0
+#define CONFIG_A2DP_PLAY_NUM 0
+#define CONFIG_POWEROFF_TEST 0
+#define CONFIG_LOW_LATENCY_TEST 0
+#define CONFIG_A2DP_AUTO_PLAY 1
+#define CONFIG_IN_OUT_CHARGESTORE_TEST 0
+#define CONFIG_TWS_SUPER_TIMEOUT_TEST 0
+
+#define CONFIG_MODE_SWITCH_ENABLE 0
+#define CONFIG_ROLE_SWITCH_TEST 0
+
+#define CONFIG_GMA_TEST 0
+
+
+
+#if CONFIG_LOW_LATENCY_TEST
+
+static void low_latency_switch_test(void *p)
+{
+ struct sys_event evt;
+
+ r_printf("low_latency_test\n");
+
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ evt.arg = (void *)DEVICE_EVENT_FROM_KEY;
+ evt.type = SYS_KEY_EVENT;
+ evt.u.key.value = KEY_POWER_START;
+ evt.u.key.event = KEY_EVENT_TRIPLE_CLICK;
+
+ sys_event_notify(&evt);
+ }
+
+}
+
+#endif
+
+#if CONFIG_GMA_TEST
+static void gma_test(void *p)
+{
+ struct sys_event evt;
+
+ r_printf("gma_test\n");
+
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ evt.arg = (void *)DEVICE_EVENT_FROM_KEY;
+ evt.type = SYS_KEY_EVENT;
+ evt.u.key.value = KEY_POWER_START;
+ evt.u.key.event = KEY_EVENT_LONG;
+
+ sys_event_notify(&evt);
+
+ int ms = 10000 + rand32() % 10 * 5000;
+ sys_timeout_add(NULL, gma_test, ms);
+ }
+}
+#endif
+
+
+
+#if CONFIG_SPP_PRINTF_DEBUG
+static u32 spp_buf[1024 / 4];
+static cbuffer_t spp_buf_hdl;
+static u32 send_len = 0;
+static int spp_timer = 0;
+static char out[256];
+
+int log_print_time_to_buf(char *time);
+
+void spp_printf(const char *format, ...)
+{
+ va_list args;
+ char *p = out;
+
+ if (spp_timer == 0) {
+ return;
+ }
+
+ va_start(args, format);
+
+ int len = log_print_time_to_buf(p);
+ p += len;
+
+ len += print(&p, 0, format, args);
+ if (cbuf_is_write_able(&spp_buf_hdl, len)) {
+ cbuf_write(&spp_buf_hdl, out, len);
+ } else {
+ putchar('N');
+ }
+}
+
+void spp_send_data_timer(void *p)
+{
+ u8 *ptr;
+
+__send:
+ if (send_len == 0) {
+ ptr = cbuf_read_alloc(&spp_buf_hdl, &send_len);
+ if (send_len) {
+ if (send_len > 250) {
+ send_len = 250;
+ }
+ user_send_cmd_prepare(USER_CTRL_SPP_SEND_DATA, send_len, ptr);
+ }
+ } else {
+ if (0 == user_send_cmd_prepare(USER_CTRL_SPP_SEND_DATA, 0, NULL)) {
+ cbuf_read_updata(&spp_buf_hdl, send_len);
+ send_len = 0;
+ goto __send;
+ }
+ }
+}
+
+static void spp_data_handler(u8 packet_type, u16 ch, u8 *packet, u16 size)
+{
+ switch (packet_type) {
+ case 1:
+ cbuf_init(&spp_buf_hdl, spp_buf, sizeof(spp_buf));
+ spp_timer = sys_timer_add(NULL, spp_send_data_timer, 50);
+ spp_printf("spp connect\n");
+ break;
+ case 2:
+ printf("spp disconnect\n");
+ if (spp_timer) {
+ sys_timer_del(spp_timer);
+ spp_timer = 0;
+ }
+ break;
+ case 7:
+ //log_info("spp_rx:");
+ //put_buf(packet,size);
+ break;
+ }
+}
+
+#endif
+
+
+
+static int a2dp_open_cnt = 0;
+u8 bt_audio_is_running(void);
+
+static void a2dp_play_pause_test(void *p)
+{
+ struct sys_event evt;
+
+ if (bt_audio_is_running()) {
+ if (p) {
+ return;
+ }
+ } else {
+ if (!p) {
+ return;
+ }
+ }
+ r_printf("a2dp_play_pause_test\n");
+
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ evt.arg = (void *)DEVICE_EVENT_FROM_KEY;
+ evt.type = SYS_KEY_EVENT;
+ evt.u.key.value = KEY_POWER_START;
+ evt.u.key.event = KEY_EVENT_CLICK;
+ /*evt.u.key.event = KEY_EVENT_DOUBLE_CLICK;*/
+
+ sys_event_notify(&evt);
+ }
+}
+
+static void disconnect_test(void *p)
+{
+ r_printf("disconnect_test: %x\n", p);
+
+ if (!p) {
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ user_send_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
+ }
+ } else {
+ bt_user_priv_var.auto_connection_counter = 60 * 1000;
+ bt_tws_phone_connect_timeout();
+ }
+}
+
+#if CONFIG_TWS_SUPER_TIMEOUT_TEST
+extern void tws_timeout_test();
+static void tws_super_timeout_test(void *p)
+{
+ tws_timeout_test();
+}
+#endif
+
+#if CONFIG_ROLE_SWITCH_TEST
+static void tws_role_switch_test(void *p)
+{
+ tws_conn_switch_role();
+
+ /*void bt_tws_role_switch();
+ bt_tws_role_switch();*/
+}
+#endif
+
+
+#if CONFIG_MODE_SWITCH_ENABLE
+static void mode_switch_test()
+{
+ struct sys_event evt;
+
+ if (tws_api_get_role() == 0) {
+ evt.arg = (void *)DEVICE_EVENT_FROM_KEY;
+ evt.type = SYS_KEY_EVENT;
+ evt.u.key.value = KEY_POWER_START;
+ evt.u.key.event = KEY_EVENT_TRIPLE_CLICK;
+ sys_event_notify(&evt);
+ }
+
+}
+#endif
+
+
+
+static int bt_connction_status_event_handler(struct bt_event *bt)
+{
+ switch (bt->event) {
+ case BT_STATUS_FIRST_CONNECTED:
+#if CONFIG_SPP_PRINTF_DEBUG
+ spp_data_deal_handle_register(spp_data_handler);
+#endif
+
+#if CONFIG_A2DP_AUTO_PLAY
+ if (tws_api_get_role() == 0) {
+ sys_timeout_add((void *)1, a2dp_play_pause_test, 8000);
+ }
+#endif
+#if CONFIG_LOW_LATENCY_TEST
+ if (tws_api_get_role() == 0) {
+ sys_timer_add(NULL, low_latency_switch_test, 15000);
+ }
+#endif
+#if CONFIG_GMA_TEST
+ if (tws_api_get_role() == 0) {
+ sys_timeout_add(NULL, gma_test, 15000);
+ }
+#endif
+#if CONFIG_POWEROFF_TEST
+ {
+ int msec = 10000 ;//+ rand32() % 5 * 5000;
+ sys_timeout_add(NULL, disconnect_test, msec);
+ }
+#endif
+#if CONFIG_MODE_SWITCH_ENABLE
+ sys_timer_add(NULL, mode_switch_test, 20000);
+#endif
+ break;
+ case BT_STATUS_FIRST_DISCONNECT:
+#if CONFIG_POWEROFF_TEST
+ a2dp_open_cnt = 0;
+ sys_timeout_add((void *)1, disconnect_test, 2000);
+#endif
+ break;
+ case BT_STATUS_A2DP_MEDIA_START:
+#if CONFIG_A2DP_PLAY_PAUSE_TEST
+ if (CONFIG_A2DP_PLAY_NUM && ++a2dp_open_cnt >= CONFIG_A2DP_PLAY_NUM) {
+#if CONFIG_POWEROFF_TEST
+ sys_timeout_add(NULL, disconnect_test, 5000);
+#endif
+ } else {
+ sys_timeout_add(NULL, a2dp_play_pause_test, 10000);
+ }
+#endif
+#if CONFIG_ROLE_SWITCH_TEST
+ sys_timeout_add(NULL, tws_role_switch_test, 5000);
+#endif
+ break;
+ case BT_STATUS_A2DP_MEDIA_STOP:
+#if CONFIG_A2DP_PLAY_PAUSE_TEST
+ if (CONFIG_A2DP_PLAY_NUM == 0 || a2dp_open_cnt < CONFIG_A2DP_PLAY_NUM) {
+ sys_timeout_add((void *)1, a2dp_play_pause_test, 15000);
+ }
+#endif
+ break;
+ }
+ return 0;
+}
+
+static int bt_tws_event_handler(struct bt_event *evt)
+{
+ int role = evt->args[0];
+ int phone_link_connection = evt->args[1];
+ int reason = evt->args[2];
+
+ switch (evt->event) {
+ case TWS_EVENT_CONNECTED:
+#if CONFIG_IN_OUT_CHARGESTORE_TEST
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ void sys_enter_soft_poweroff(void *priv);
+ sys_timeout_add((void *)1, sys_enter_soft_poweroff, 5000);
+ }
+#endif
+#if CONFIG_TWS_SUPER_TIMEOUT_TEST
+ sys_timeout_add(NULL, tws_super_timeout_test, 10000);
+#endif
+#if CONFIG_ROLE_SWITCH_TEST
+ sys_timeout_add(NULL, tws_role_switch_test, 15000);
+#endif
+ break;
+ case TWS_EVENT_ROLE_SWITCH:
+#if CONFIG_ROLE_SWITCH_TEST
+ sys_timeout_add(NULL, tws_role_switch_test, 5000);
+#endif
+ break;
+ }
+ return 0;
+}
+
+
+static void auto_test_event_handler(struct sys_event *event, void *priv)
+{
+ /*
+ * 蓝牙事件处理
+ */
+ switch ((u32)event->arg) {
+ case SYS_BT_EVENT_TYPE_CON_STATUS:
+ bt_connction_status_event_handler(&event->u.bt);
+ break;
+ case SYS_BT_EVENT_TYPE_HCI_STATUS:
+ break;
+#if TCFG_USER_TWS_ENABLE
+ case SYS_BT_EVENT_FROM_TWS:
+ bt_tws_event_handler(&event->u.bt);
+ break;
+#endif
+ }
+}
+
+
+static void bt_auto_test_task(void *p)
+{
+ int res;
+ int msg[32];
+
+ register_sys_event_handler(SYS_BT_EVENT, 0, 0, auto_test_event_handler);
+
+ os_time_dly(2);
+
+#if CONFIG_IN_OUT_CHARGESTORE_TEST
+ void sys_enter_soft_poweroff(void *priv);
+ int msec = 500 + rand32() % 10 * 200;
+ sys_timeout_add((void *)1, sys_enter_soft_poweroff, msec);
+#endif
+
+ while (1) {
+ res = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
+ if (res != OS_TASKQ) {
+ continue;
+ }
+ }
+}
+
+
+int bt_auto_test_init()
+{
+ os_task_create(bt_auto_test_task, NULL, 1, 256, 256, "auto_test");
+ return 0;
+}
+late_initcall(bt_auto_test_init);
+
+
+
+
+
+
+#endif
diff --git a/apps/earphone/bt_background.c b/apps/earphone/bt_background.c
new file mode 100644
index 0000000..0efe1f9
--- /dev/null
+++ b/apps/earphone/bt_background.c
@@ -0,0 +1,255 @@
+#include "system/includes.h"
+#include "classic/tws_api.h"
+#include "btstack/avctp_user.h"
+#include "btstack/a2dp_media_codec.h"
+
+#include "app_config.h"
+#include "app_main.h"
+#include "app_action.h"
+
+#include "app_task.h"
+#include "audio_config.h"
+
+static u16 clear_to_seqn = 0;
+static u16 slience_timer;
+static u8 unmute_packet_cnt;
+static u8 g_bt_background = 0;
+static u8 energy_check_stop;
+
+u8 bt_media_is_running();
+void a2dp_dec_close();
+void bt_switch_to_foreground(int action, bool exit_curr_app);
+
+#define TWS_A2DP_CLEAR_ID TWS_FUNC_ID('A', 2, 'C', 'R')
+
+
+static void __tws_a2dp_clear_to_seqn(void *data, u16 len, bool rx)
+{
+ if (rx) {
+ clear_to_seqn = *(u16 *)data;
+ }
+}
+
+REGISTER_TWS_FUNC_STUB(tws_a2dp_clear_to_seqn) = {
+ .func_id = TWS_A2DP_CLEAR_ID,
+ .func = __tws_a2dp_clear_to_seqn,
+};
+
+bool bt_in_background()
+{
+ return g_bt_background;
+}
+
+void a2dp_slience_detect(void *p)
+{
+ int len;
+ u8 *packet;
+ int ingore_packet_num = (int)p;
+ int role = tws_api_get_role();
+
+ u32 media_type;
+ putchar('^');
+ while (1) {
+ media_type = a2dp_media_get_codec_type();
+ len = a2dp_media_try_get_packet(&packet);
+ if (len <= 0) {
+ break;
+ }
+
+ u16 seqn = (packet[2] << 8) | packet[3];
+
+ if (role == TWS_ROLE_MASTER) {
+ if (clear_to_seqn == 0) {
+ clear_to_seqn = seqn + ingore_packet_num;
+ if (clear_to_seqn == 0) {
+ clear_to_seqn = 1;
+ }
+ a2dp_media_free_packet(packet);
+ a2dp_media_clear_packet_before_seqn(clear_to_seqn);
+ break;
+ }
+
+ //能量检测
+ if (energy_check_stop == 0) {
+ int energy;
+ if (media_type == 0) {
+ energy = sbc_energy_check(packet, len);
+ } else {
+ energy = aac_energy_check(packet, len);
+
+ }
+
+ printf("energy:media_type= %d,%d, %d, %d\n", media_type, seqn, energy, unmute_packet_cnt);
+
+ if (energy >= 10) {
+ if (++unmute_packet_cnt >= 20) {
+ unmute_packet_cnt = 0;
+ energy_check_stop = 1;
+
+ //能量检测结束,通知从机丢到指定包号数据,然后开始A2DP解码
+ clear_to_seqn = seqn + 10;
+ if (clear_to_seqn == 0) {
+ clear_to_seqn = 1;
+ }
+ tws_api_send_data_to_slave(&clear_to_seqn, 2, TWS_A2DP_CLEAR_ID);
+ }
+ } else {
+ unmute_packet_cnt >>= 1;
+ }
+ a2dp_media_free_packet(packet);
+ continue;
+ }
+ }
+
+ printf("seqn: %d, %d\n", seqn, clear_to_seqn);
+
+ a2dp_media_free_packet(packet);
+
+ if (clear_to_seqn && seqn_after(seqn, clear_to_seqn)) {
+ clear_to_seqn = 0;
+ sys_timer_del(slience_timer);
+ slience_timer = 0;
+ if (!bt_in_background()) {
+ //先点击手机播放再立马按键切模式时,此处需要打开a2dp解码
+ g_bt_background = 1;
+ bt_switch_to_foreground(ACTION_A2DP_START, 0);
+ } else {
+ app_task_switch_to(APP_BT_TASK, ACTION_A2DP_START);
+ }
+ break;
+ }
+ }
+}
+
+void bt_start_a2dp_slience_detect(int ingore_packet_num)
+{
+ if (slience_timer) {
+ sys_timer_del(slience_timer);
+ }
+ clear_to_seqn = 0;
+ unmute_packet_cnt = 0;
+ energy_check_stop = 0;
+ slience_timer = sys_timer_add((void *)ingore_packet_num, a2dp_slience_detect, 40);
+ g_printf("bt_start_a2dp_slience_detect=%d\n", slience_timer);
+}
+
+void bt_stop_a2dp_slience_detect()
+{
+ if (slience_timer) {
+ sys_timer_del(slience_timer);
+ g_printf("bt_stop_a2dp_slience_detect");
+ slience_timer = 0;
+ }
+}
+
+int bt_switch_to_background()
+{
+ int a2dp_state;
+ int esco_state;
+ struct intent it;
+
+ if (app_var.siri_stu && app_var.siri_stu != 3 && get_esco_busy_flag()) {
+ // siri不退出
+ return -EINVAL;
+ }
+
+ esco_state = get_call_status();
+ if (esco_state == BT_CALL_OUTGOING ||
+ esco_state == BT_CALL_ALERT ||
+ esco_state == BT_CALL_INCOMING ||
+ esco_state == BT_CALL_ACTIVE) {
+ // 通话不退出
+ return -EINVAL;
+ }
+
+
+
+ a2dp_state = a2dp_get_status();
+ r_printf("a2dp_state=%d\n", a2dp_state);
+ if ((tws_api_get_role() == TWS_ROLE_MASTER) && (a2dp_state == BT_MUSIC_STATUS_STARTING)) {
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PAUSE, 0, NULL);
+ }
+ if (bt_media_is_running()) {
+ a2dp_dec_close();
+ a2dp_media_clear_packet_before_seqn(0);
+ bt_start_a2dp_slience_detect(30);
+ }
+
+ g_bt_background = 1;
+
+ return 0;
+}
+
+void bt_switch_to_foreground(int action, bool exit_curr_app)
+{
+ struct intent it;
+
+ if (g_bt_background) {
+ g_bt_background = 0;
+
+ /* 退出当前模式 */
+ if (exit_curr_app) {
+ init_intent(&it);
+ it.action = ACTION_BACK;
+ start_app(&it);
+ }
+ }
+
+ if (action) {
+ init_intent(&it);
+ it.name = "earphone";
+ it.action = action;
+ start_app(&it);
+ }
+}
+
+int bt_background_event_probe_handler(struct bt_event *bt)
+{
+ int len;
+
+ switch (bt->event) {
+ case BT_STATUS_INIT_OK:
+ len = syscfg_read(CFG_HAVE_MASS_STORAGE, &app_var.have_mass_storage, 1);
+ if (len != 1) {
+ if (dev_online("sd0")) {
+ app_var.have_mass_storage = 1;
+ syscfg_write(CFG_HAVE_MASS_STORAGE, &app_var.have_mass_storage, 1);
+ }
+ }
+ printf("have_mass_storage: %d\n", app_var.have_mass_storage);
+ break;
+ case BT_STATUS_A2DP_MEDIA_START:
+ puts("BT_STATUS_A2DP_MEDIA_START\n");
+ if (bt_in_background()) {
+ bt_start_a2dp_slience_detect(30);
+ return -EINVAL;
+ } else {
+ bt_stop_a2dp_slience_detect();
+ }
+ break;
+ case BT_STATUS_A2DP_MEDIA_STOP:
+ puts("BT_STATUS_A2DP_MEDIA_STOP\n");
+ if (bt_in_background()) {
+ bt_stop_a2dp_slience_detect();
+ extern void free_a2dp_using_decoder_conn();
+ free_a2dp_using_decoder_conn();
+ return -EINVAL;
+ }
+ break;
+ case BT_STATUS_VOICE_RECOGNITION:
+ if (bt->value && bt->value != 3) {
+ } else {
+ break;
+ }
+ case BT_STATUS_PHONE_INCOME:
+ case BT_STATUS_PHONE_OUT:
+ case BT_STATUS_PHONE_ACTIVE:
+ bt_switch_to_foreground(ACTION_DO_NOTHING, 0);
+ break;
+ }
+
+ return 0;
+}
+
+
+
diff --git a/apps/earphone/bt_ble.c b/apps/earphone/bt_ble.c
new file mode 100644
index 0000000..18c450b
--- /dev/null
+++ b/apps/earphone/bt_ble.c
@@ -0,0 +1,1053 @@
+#include "system/app_core.h"
+#include "system/includes.h"
+
+#include "app_config.h"
+#include "app_action.h"
+
+#include "btstack/btstack_task.h"
+#include "user_cfg.h"
+#include "vm.h"
+#include "app_power_manage.h"
+#include "btcontroller_modules.h"
+//#include "app_chargestore.h"
+#include "btstack/avctp_user.h"
+#include "bt_common.h"
+#include "le_common.h"
+#include "include/bt_ble.h"
+#include "pbg_user.h"
+#include "bt_tws.h"
+
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV)
+
+#define LOG_TAG_CONST BT_BLE
+#define LOG_TAG "[BT_BLE]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#if 1
+#define ble_puts printf
+#define ble_printf printf
+#define ble_put_buf printf_buf
+
+#else
+
+#define ble_puts log_info
+#define ble_printf log_info
+#define ble_put_buf log_debug_hexdump
+
+#endif
+
+//unit: (1ms)
+#define BLE_TIMER_SET (150)
+#define BLE_SNIFF_TIMER_SET (500*2)
+
+//unit: (0.625us)
+#define ADV_FAST_INTERVAL (48)
+#define ADV_CONN_FAST_INTERVAL (64)
+#define ADV_CONN_NORMAL_INTERVAL (64*2)
+#define ADV_SNIFF_INTERVAL (800*1)
+#define ADV_SLOW_INTERVAL (800*1)
+
+//广播变慢计时: ADV_CONN_NORMAL_INTERVAL-->ADV_SLOW_INTERVAL
+#define ADV_TIME_TO_SLOW_MS (15000/BLE_TIMER_SET + 1)
+
+//停留时间,可以自定义修改
+#define ADV_ST_CONN_HOLD_TIME (50000/BLE_TIMER_SET)//phone connect device,配对连上停留时间,默认值20s
+#define ADV_ST_RECONN_HOLD_TIME (50000/BLE_TIMER_SET)//device connect phone,回连连上停留时间,默认值20s
+
+//以下时间不建议修改
+#define ADV_ST_DISMISS_HOLD_TIME (2000/BLE_TIMER_SET +1)
+#define ADV_ST_PRE1_HOLD_TIME (200/BLE_TIMER_SET +1)
+#define ADV_ST_FAST_DISMISS_HOLD_TIME (1500/BLE_TIMER_SET +1)//to fast display reconnect
+
+#define PHONE_ICON_ONE_BETA 0 //beta case,one ear case
+
+//0---default,inquiry,connect,reconnect
+//1---only inquiry and first connect
+#define PHONE_ICON_CTRL_MODE 0 //
+
+//1--连上后,广播一段时间,超时关闭广播,去图片
+//0--连上后,一直广播,显示电量
+#define PHONE_ICON_AUTO_DISMISS 1 //auto dismiss icon
+
+#if TCFG_CHARGESTORE_ENABLE
+#define REFLASH_ICON_STATE 1 //auto reflash
+#else
+#define REFLASH_ICON_STATE 0 //not auto reflash,fixed
+#endif
+
+static u32 ble_timer_handle = 0;
+static u16 adv_st_count = 0;
+static u8 dev_battery_level[3];//master,slave,box
+static volatile u8 adv_control_enable;//master
+static volatile u8 adv_st_mode;
+static volatile u8 adv_st_next_mode;
+static volatile u8 adv_enable = 0;
+static u8 adv_data[ADV_RSP_PACKET_MAX];
+static u8 adv_data_len = 0;
+static u8 rsp_data[ADV_RSP_PACKET_MAX];
+static u8 rsp_data_len = 0;
+static u8 adv_rand;
+static u8 adv_open_lock;//lock open 标记
+static volatile u8 send_sync_pos_flag = 0;
+
+//-------------------------------------------------------------------
+//持续广播控制操作:开机快广播一段时间,后面根据状态调整广播
+
+enum { //广播步进状态
+ ADV_STEP_FAST = 0, //快速广播
+ ADV_STEP_NORMAL, //连上正常广播
+ ADV_STEP_SNIFF, //EDR进入sleep后,广播
+ ADV_STEP_SLOW, //慢广播状态
+};
+//0-normal,1-timeout,2-sniff,3-slow adv
+static u8 adv_state_step = ADV_STEP_FAST;
+static u32 adv_check_timer_ms = BLE_TIMER_SET;
+
+static u32 adv_high_timer_count = 0;
+
+//-------------------user_tag data start----------------------------------------------------------
+static u8 user_tag_data[19] = {
+ 0xd6, 0x05,
+ 0x01, 0x00,
+ 0x01, 0x00,
+ 0x00, //6
+};
+
+#define ADV_LONG_PACKET_SIZE 23//
+
+static const u8 user_pre1_tag_data[ADV_LONG_PACKET_SIZE] = {
+ 0xd6, 0x05,
+ 0x02, 0x00,
+ 0x02, 0x00,
+ 0x00, //6
+};
+
+static const u8 user_pre2_tag_data[ADV_LONG_PACKET_SIZE] = {
+ 0xd6, 0x05,
+ 0x02, 0x00,
+ 0x02, 0x00,
+ 0x00, //6
+};
+
+static const u8 user_conn_tag_data[ADV_LONG_PACKET_SIZE] = {
+ 0xd6, 0x05,
+ 0x02, 0x00,
+ 0x02, 0x00,
+ 0x00, //6
+};
+
+static const u8 user_reconn_tag_data[ADV_LONG_PACKET_SIZE] = {
+ 0xd6, 0x05,
+ 0x02, 0x00,
+ 0x02, 0x00,
+ 0x00, //6
+};
+
+//-----------------------data end------------------------------------------------------
+
+extern const char *bt_get_local_name();
+static void adv_rand_init(void);
+static u8 update_dev_battery_level(void);
+static void bt_ble_timer_init(void);
+static void bt_ble_timer_exit(void);
+
+//-------------------------------------------------------
+
+const char ble_name_string[] = "69n_ble";
+static int make_set_adv_data(u8 *info, u8 len)
+{
+ u8 offset = 0;
+ u8 *buf = (void *)adv_data;
+ u8 *tag_buf = (void *)info;
+ u8 tag_len = len;
+ /*
+ #if 0 //BLE广播使用EDR的蓝牙名字,防止连接时蓝牙名字变成693_ble蓝牙名字最多只能31-21=10字节。
+ u8 *edr_name = bt_get_local_name();
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, (void *)edr_name, strlen(edr_name));
+ #else
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, (void *)ble_name_string, strlen(ble_name_string));
+ #endif
+ */
+
+ offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_MANUFACTURER_SPECIFIC_DATA, (void *)tag_buf, tag_len);
+
+ if (offset > ADV_RSP_PACKET_MAX) {
+ ble_puts("***adv_data overflow!!!!!!\n");
+ return -1;
+ }
+ ble_printf("ADV data(%d):", offset);
+ ble_put_buf(buf, offset);
+ adv_data_len = offset;
+ return 0;
+}
+
+static int make_set_rsp_data(void)
+{
+ u8 offset = 0;
+ u8 *buf = (void *)rsp_data;
+
+ if (offset > ADV_RSP_PACKET_MAX) {
+ ble_puts("***rsp_data overflow!!!!!!\n");
+ return -1;
+ }
+
+ ble_printf("RSP data(%d):,offset");
+ ble_put_buf(buf, offset);
+ rsp_data_len = offset;
+ return 0;
+}
+
+static void adv_setup_init(void)
+{
+ u8 adv_type = 3;
+ u8 adv_channel = 0x07;
+ u16 adv_interval;
+
+ switch (adv_st_mode) {
+ case ADV_ST_INQUIRY:
+ case ADV_ST_DISMISS:
+ case ADV_ST_FAST_DISMISS:
+ //特殊状态,广播周期快
+ adv_interval = ADV_FAST_INTERVAL;
+ break;
+
+ case ADV_ST_CONN:
+ case ADV_ST_RECONN:
+ default:
+ if (adv_state_step == ADV_STEP_NORMAL) {
+ adv_interval = ADV_CONN_NORMAL_INTERVAL;
+ adv_high_timer_count = ADV_TIME_TO_SLOW_MS;
+ } else if (adv_state_step == ADV_STEP_SNIFF) {
+ adv_interval = ADV_SNIFF_INTERVAL;
+ } else if (adv_state_step == ADV_STEP_SLOW) {
+ adv_interval = ADV_SLOW_INTERVAL;
+ } else {
+ adv_interval = ADV_CONN_FAST_INTERVAL;
+ }
+ break;
+ }
+
+ ble_printf("adv_interval=%d\n", adv_interval);
+
+ ble_user_cmd_prepare(BLE_CMD_ADV_PARAM, 3, adv_interval, adv_type, adv_channel);
+
+ ble_user_cmd_prepare(BLE_CMD_ADV_DATA, 2, adv_data_len, adv_data);
+ ble_user_cmd_prepare(BLE_CMD_RSP_DATA, 2, rsp_data_len, rsp_data);
+}
+
+u8 bt_ble_get_adv_enable(void)
+{
+ return adv_enable;
+}
+
+void bt_ble_adv_enable(u8 enable)
+{
+ if (adv_enable == enable) {
+ return;
+ }
+ adv_enable = enable;
+
+ ble_printf("***** ble_adv_en:%d ******\n", enable);
+ if (enable) {
+ bt_ble_timer_init();
+ adv_setup_init();
+ } else {
+ bt_ble_timer_exit();
+ adv_high_timer_count = 0;
+ }
+ ble_user_cmd_prepare(BLE_CMD_ADV_ENABLE, 1, enable);
+}
+
+//-----------------------
+extern u8 get_charge_online_flag(void);
+static u8 get_device_bat_percent(void)
+{
+#if CONFIG_DISPLAY_DETAIL_BAT
+ u8 val = get_vbat_percent();
+#else
+ u8 val = get_self_battery_level() * 10 + 10;
+#endif
+
+ if (val > 100) {
+ val = 100;
+ }
+ val = (val | (get_charge_online_flag() << 7));
+ /* printf("[%d]",val); */
+ return val;
+}
+
+static void reflash_adv_tag_data(const u8 *tag_data, u8 len, u8 spec_val)
+{
+ u8 tmp_tag_data[32];
+ u8 tmp8;
+
+ memcpy(tmp_tag_data, tag_data, len);
+ memcpy(&tmp_tag_data[14], dev_battery_level, 3);
+
+ u8 cur_ear_pos = 'L';
+#if TCFG_CHARGESTORE_ENABLE
+ log_info("get pos form chargesstore\n");
+ cur_ear_pos = chargestore_get_earphone_pos();
+#else
+#if TCFG_USER_TWS_ENABLE
+ cur_ear_pos = bt_tws_get_local_channel();
+#endif
+#endif
+
+ //位置14,15,16 对应 L,R,BOX
+ if (cur_ear_pos != 'R') {
+ //switch position
+ ble_puts("is R pos\n");
+ tmp8 = tmp_tag_data[14];
+ tmp_tag_data[14] = tmp_tag_data[15];
+ tmp_tag_data[15] = tmp8;
+ } else {
+ ble_puts("is L pos\n");
+ }
+
+ if (spec_val != 0xff) {
+ tmp_tag_data[17] = spec_val;
+ if (spec_val != 9) {
+#if TCFG_USER_TWS_ENABLE
+ /* memset(&tmp_tag_data[14],0xff,3); */
+#endif
+ } else {
+ memset(&tmp_tag_data[14], 0xFF, 3);//关闭广播的时候不显示电量
+ }
+ }
+
+ //---
+#if (!REFLASH_ICON_STATE) //
+ if (len == ADV_LONG_PACKET_SIZE) {
+#if TCFG_USER_TWS_ENABLE
+ //fixed do,start,固定分开显示电量,如不分开,可以屏蔽这段代码
+ ble_puts("fixed two do\n");
+ /* ble_put_buf(&tmp_tag_data[14],3); */
+ if ((tmp_tag_data[14] != 0xff)
+ && (tmp_tag_data[15] != 0xff)) {
+ if ((tmp_tag_data[14]&BIT(7))
+ && (tmp_tag_data[15]&BIT(7))) {
+ tmp_tag_data[15] &= 0x7f;
+ ble_puts("fixed c1\n");
+ } else {
+ if (((tmp_tag_data[14]&BIT(7)) == 0)
+ && ((tmp_tag_data[15]&BIT(7)) == 0)) {
+ tmp_tag_data[14] |= BIT(7);
+ ble_puts("fixed c2\n");
+ }
+
+ }
+
+ }
+ //fixed do,end
+#endif
+ }
+#endif
+ //---
+
+ bt_ble_adv_enable(0);
+
+ if (send_sync_pos_flag) {
+ u8 pos_state[2];
+ //L---offset 14
+ if (tmp_tag_data[14] == 0xff) {
+ pos_state[0] = PBG_POS_NOT_EXIST;
+ } else if (tmp_tag_data[14] & BIT(7)) {
+ pos_state[0] = PBG_POS_IN_BOX;
+ } else {
+ pos_state[0] = PBG_POS_OUT_BOX;
+ }
+
+ //R---offset 15
+ if (tmp_tag_data[15] == 0xff) {
+ pos_state[1] = PBG_POS_NOT_EXIST;
+ } else if (tmp_tag_data[15] & BIT(7)) {
+ pos_state[1] = PBG_POS_IN_BOX;
+ } else {
+ pos_state[1] = PBG_POS_OUT_BOX;
+ }
+ send_sync_pos_flag = 0;
+ pbg_user_battery_level_sync(&tmp_tag_data[14]);
+ pbg_user_ear_pos_sync(pos_state[0], pos_state[1]);
+ }
+
+ //fix adv_data state
+#if 0//(CONFIG_NO_DISPLAY_BUTTON_ICON == 0)
+ //if(ADV_ST_CONN == adv_st_mode) //
+ if (0) {
+ ;
+ } else {
+ //extern int pbg_adv_data_change_parse(u8 * adv_data, u8 adv_data_len, u8 adv_rand);
+ //pbg_adv_data_change_parse(tmp_tag_data, len, adv_rand);
+ }
+#endif
+ //end
+
+ make_set_adv_data(tmp_tag_data, len);
+ bt_ble_adv_enable(1);
+}
+
+static bool check_adv_open_lock(void)
+{
+ if (get_total_connect_dev()) {
+ //已连上手机
+ adv_open_lock = 1;
+ }
+ return adv_open_lock;
+}
+
+static void change_adv_st_mode(u8 mode)
+{
+ if (mode == adv_st_mode) {
+ return;
+ }
+
+ ble_printf("ble_adv_st:old= %d,new= %d \n", adv_st_mode, mode);
+
+ adv_st_mode = mode;
+ adv_st_count = 0;
+
+ switch (mode) {
+ case ADV_ST_CONN:
+ check_adv_open_lock();
+ reflash_adv_tag_data(user_conn_tag_data, sizeof(user_conn_tag_data), 0xff);
+ break;
+
+ case ADV_ST_RECONN:
+ check_adv_open_lock();
+ reflash_adv_tag_data(user_reconn_tag_data, sizeof(user_reconn_tag_data), 0xff);
+ break;
+
+ case ADV_ST_DISMISS:
+ reflash_adv_tag_data(user_tag_data, sizeof(user_tag_data), 0x9);
+ break;
+
+ case ADV_ST_INQUIRY:
+ reflash_adv_tag_data(user_tag_data, sizeof(user_tag_data), adv_rand);
+ break;
+
+ case ADV_ST_PRE1:
+ reflash_adv_tag_data(user_pre1_tag_data, sizeof(user_pre1_tag_data), 0xff);
+ break;
+
+ case ADV_ST_PRE2:
+ reflash_adv_tag_data(user_pre2_tag_data, sizeof(user_pre2_tag_data), 0xff);
+ break;
+
+ case ADV_ST_FAST_DISMISS:
+ reflash_adv_tag_data(user_tag_data, sizeof(user_tag_data), 0x9);
+ break;
+
+ case ADV_ST_END:
+ bt_ble_adv_enable(0);
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+static void check_dev_pos_changed(u8 cur_adv_mode)
+{
+#if REFLASH_ICON_STATE
+ if (update_dev_battery_level()) {
+ ble_puts("---reflash_dev_state\n");
+ /* adv_st_next_mode = cur_adv_mode; */
+ /* change_adv_st_mode(ADV_ST_FAST_DISMISS); */
+ if (adv_state_step == ADV_STEP_SLOW) {
+ adv_state_step = ADV_STEP_NORMAL;//slow to high
+ }
+ send_sync_pos_flag = 1;
+ change_adv_st_mode(ADV_ST_END);
+ change_adv_st_mode(cur_adv_mode);
+ }
+#endif
+}
+
+static void dev_adv_reset_do(u8 cur_adv_mode)
+{
+ if (bt_ble_get_adv_enable()) {
+ ble_printf("dev_adv_reset_do:%d\n", cur_adv_mode);
+ change_adv_st_mode(ADV_ST_END);
+ change_adv_st_mode(cur_adv_mode);
+ }
+}
+
+
+static void bt_ble_timer_handler(void)
+{
+ u8 bat_percent;
+
+ putchar('~');
+
+ if (!adv_enable) {
+ return;
+ }
+
+ adv_st_count++;
+ switch (adv_st_mode) {
+ case ADV_ST_PRE1:
+ if (adv_st_count > ADV_ST_PRE1_HOLD_TIME) {
+ change_adv_st_mode(ADV_ST_PRE2);
+ }
+ break;
+
+ case ADV_ST_CONN:
+ if (adv_st_count > ADV_ST_CONN_HOLD_TIME) {
+ if (!pbg_user_is_connected()) {
+ change_adv_st_mode(ADV_ST_DISMISS);
+ break;
+ }
+#if PHONE_ICON_AUTO_DISMISS
+ change_adv_st_mode(ADV_ST_DISMISS);
+#else
+ if (adv_state_step == ADV_STEP_FAST) {
+ adv_state_step = ADV_STEP_NORMAL;
+ dev_adv_reset_do(adv_st_mode);
+ } else {
+ //keep adv
+ }
+ //change_adv_st_mode(ADV_ST_END);
+#endif
+ } else {
+ check_dev_pos_changed(adv_st_mode);
+ }
+ break;
+
+ case ADV_ST_RECONN:
+ if (adv_st_count > ADV_ST_RECONN_HOLD_TIME) {
+ if (!pbg_user_is_connected()) {
+ change_adv_st_mode(ADV_ST_DISMISS);
+ break;
+ }
+#if PHONE_ICON_AUTO_DISMISS
+ change_adv_st_mode(ADV_ST_DISMISS);
+#else
+ if (adv_state_step == ADV_STEP_FAST) {
+ adv_state_step = ADV_STEP_NORMAL;
+ dev_adv_reset_do(adv_st_mode);
+ } else {
+ //keep adv
+ }
+ //change_adv_st_mode(ADV_ST_END);
+#endif
+ } else {
+ check_dev_pos_changed(adv_st_mode);
+ }
+ break;
+
+ case ADV_ST_DISMISS:
+ if (adv_st_count > ADV_ST_DISMISS_HOLD_TIME) {
+ change_adv_st_mode(ADV_ST_END);
+ }
+ break;
+
+ case ADV_ST_FAST_DISMISS:
+ if (adv_st_count > ADV_ST_FAST_DISMISS_HOLD_TIME) {
+ change_adv_st_mode(adv_st_next_mode);
+ }
+ break;
+
+ case ADV_ST_INQUIRY:
+ check_dev_pos_changed(adv_st_mode);
+ break;
+
+ case ADV_ST_NULL:
+ case ADV_ST_PRE2:
+ break;
+
+ default:
+ break;
+ }
+
+#if(!PHONE_ICON_AUTO_DISMISS)
+ if (adv_high_timer_count && (adv_state_step != ADV_STEP_FAST)) {
+ if (adv_high_timer_count == 1) {
+ ble_printf("adv high to slow\n");
+ adv_state_step = ADV_STEP_SLOW;
+ dev_adv_reset_do(adv_st_mode);
+ }
+ adv_high_timer_count--;
+ }
+#endif
+}
+
+static void bt_ble_timer_init(void)
+{
+ if (!ble_timer_handle) {
+ ble_timer_handle = sys_timer_add(NULL, bt_ble_timer_handler, adv_check_timer_ms);
+ }
+}
+
+static void bt_ble_timer_exit(void)
+{
+ if (ble_timer_handle) {
+ sys_timer_del(ble_timer_handle);
+ ble_timer_handle = 0;
+ }
+}
+
+extern const u8 *bt_get_mac_addr();
+extern const u8 *ble_get_mac_addr(void);
+extern void swapX(const uint8_t *src, uint8_t *dst, int len);
+void bt_ble_test_tag_do(void)
+{
+ ble_puts("bt_ble_test_tag_do\n");
+ //初始化三个电量值
+ memset(dev_battery_level, 0xff, sizeof(dev_battery_level));
+ dev_battery_level[0] = get_device_bat_percent();
+ swapX(bt_get_mac_addr(), &user_tag_data[7], 6);
+ ble_puts("\n------master address------\n");
+ ble_put_buf(&user_tag_data[7], 6);
+ /* make_set_adv_data(user_tag_data, sizeof(user_tag_data)); */
+}
+
+void bt_ble_icon_set_comm_address(u8 *addr)
+{
+ swapX(addr, &user_tag_data[7], 6);
+ le_controller_set_mac(addr);//将ble广播地址改成公共地址
+
+ ble_puts("\n------reset master address------\n");
+ ble_put_buf(&user_tag_data[7], 6);
+}
+
+void bt_ble_icon_reset(void)
+{
+ ble_puts("bt_ble_icon_reset\n");
+ if (!adv_control_enable) {
+ return;
+ }
+ //重置状态,允许再广播
+ ble_puts("reset_do\n");
+ /* adv_rand_init(); */
+ adv_st_mode = ADV_ST_NULL;
+ adv_open_lock = 0;
+ bt_ble_adv_enable(0);
+}
+
+u8 bt_ble_icon_get_adv_state(void)
+{
+ return adv_st_mode;
+}
+
+extern bool get_tws_sibling_connect_state(void);
+//return change_flag
+static u8 update_dev_battery_level(void)
+{
+
+ u8 old_dev_battery[3];
+
+ memcpy(old_dev_battery, dev_battery_level, 3);
+
+ //read bat_level
+ dev_battery_level[0] = get_device_bat_percent();
+
+#if TCFG_USER_TWS_ENABLE
+ if (!get_tws_sibling_connect_state()) {
+ dev_battery_level[1] = 0xff;
+ }
+#endif
+
+ u8 sibling_bat_level = dev_battery_level[1];
+ if (sibling_bat_level == 0xff) {
+ /* ble_puts("--update_bat_00\n"); */
+ goto update_dev2;
+ }
+
+
+#if TCFG_USER_TWS_ENABLE
+ sibling_bat_level = get_tws_sibling_bat_persent();
+#endif
+
+#if TCFG_CHARGESTORE_ENABLE
+ if (sibling_bat_level == 0xff) {
+ /* ble_puts("--update_bat_01\n"); */
+ sibling_bat_level = chargestore_get_sibling_power_level();
+ }
+#endif
+
+ if (sibling_bat_level == 0xff) {
+ /* ble_puts("--update_bat_02\n"); */
+ dev_battery_level[1] = dev_battery_level[0];
+ } else {
+ dev_battery_level[1] = sibling_bat_level;
+ }
+
+update_dev2:
+ if (((dev_battery_level[0] & BIT(7)) && (dev_battery_level[0] != 0xff))
+ || ((dev_battery_level[1] & BIT(7)) && (dev_battery_level[1] != 0xff))) {
+ //earphone in charge
+#if TCFG_CHARGESTORE_ENABLE
+ dev_battery_level[2] = chargestore_get_power_level();
+#else
+ dev_battery_level[2] = 0xff;
+#endif
+ } else {
+ //all not in charge
+ dev_battery_level[2] = 0xff;
+ }
+
+ u8 i;
+ u8 change_flag = 0;
+
+ for (i = 0; i < 3; i++) {
+ if ((dev_battery_level[i]&BIT(7)) != (old_dev_battery[i]&BIT(7))) {
+ break;
+ }
+
+ if ((dev_battery_level[i] == 0xff) && (old_dev_battery[i] != 0xff)) {
+ break;
+ }
+
+ if ((dev_battery_level[i] != 0xff) && (old_dev_battery[i] == 0xff)) {
+ break;
+ }
+
+ }
+
+ if (i < 3) {
+ ble_puts("dev_pos_state have changed:");
+ ble_put_buf(old_dev_battery, 3);
+ ble_put_buf(dev_battery_level, 3);
+ change_flag = 1;
+ }
+ return change_flag;
+}
+
+
+
+//open 不同类型广播
+void bt_ble_icon_open(u8 type)
+{
+ ble_printf("bt_ble_icon_open: %d\n", type);
+
+ if (!adv_control_enable) {
+ return;
+ }
+
+ if (adv_open_lock) {
+ ble_puts("open_lock\n");
+ return;
+ }
+
+ ble_puts("open_do\n");
+
+ adv_state_step = ADV_STEP_FAST;
+ send_sync_pos_flag = 1;
+ update_dev_battery_level();
+
+ switch (adv_st_mode) {
+ case ADV_ST_NULL:
+
+#if PHONE_ICON_ONE_BETA
+ if (type == ICON_TYPE_INQUIRY) {
+ change_adv_st_mode(ADV_ST_INQUIRY);
+ } else if (type == ICON_TYPE_CONNECTED || type == ICON_TYPE_RECONNECT) {
+ //record,and not display
+ change_adv_st_mode(ADV_ST_END);
+ }
+ break;
+#endif
+
+#if (PHONE_ICON_CTRL_MODE == 1)
+ if (type == ICON_TYPE_INQUIRY) {
+ change_adv_st_mode(ADV_ST_INQUIRY);
+ } else if (type == ICON_TYPE_CONNECTED || type == ICON_TYPE_RECONNECT) {
+ //record,and not display
+ change_adv_st_mode(ADV_ST_END);
+ }
+ break;
+#endif
+
+
+ if (type == ICON_TYPE_CONNECTED || type == ICON_TYPE_RECONNECT) {
+ change_adv_st_mode(ADV_ST_RECONN);
+ } else if (type == ICON_TYPE_PRE_DEV) {
+ change_adv_st_mode(ADV_ST_PRE1);
+ } else {
+ change_adv_st_mode(ADV_ST_INQUIRY);
+ }
+ break;
+
+ case ADV_ST_INQUIRY:
+
+#if PHONE_ICON_ONE_BETA
+ if (type == ICON_TYPE_CONNECTED || type == ICON_TYPE_RECONNECT) {
+ change_adv_st_mode(ADV_ST_DISMISS);
+ }
+ break;
+#endif
+
+#if (PHONE_ICON_CTRL_MODE == 1)
+ if (type == ICON_TYPE_CONNECTED || type == ICON_TYPE_RECONNECT) {
+ change_adv_st_mode(ADV_ST_DISMISS);
+ }
+ break;
+#endif
+
+
+ switch (type) {
+ case ICON_TYPE_CONNECTED:
+#if TCFG_USER_TWS_ENABLE
+ change_adv_st_mode(ADV_ST_CONN);
+#else
+ change_adv_st_mode(ADV_ST_DISMISS);
+#endif
+ break;
+
+ case ICON_TYPE_RECONNECT:
+ change_adv_st_mode(ADV_ST_FAST_DISMISS);
+ adv_st_next_mode = ADV_ST_RECONN;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case ADV_ST_PRE1:
+ case ADV_ST_PRE2:
+ if (type == ICON_TYPE_INQUIRY) {
+ //开inquiry
+ change_adv_st_mode(ADV_ST_INQUIRY);
+ } else if (type == ICON_TYPE_CONNECTED) {
+ change_adv_st_mode(ADV_ST_CONN);
+ } else {
+ ;
+ }
+ break;
+
+
+ case ADV_ST_RECONN:
+ if (type == ICON_TYPE_INQUIRY) {
+ change_adv_st_mode(ADV_ST_FAST_DISMISS);
+ adv_st_next_mode = ADV_ST_INQUIRY;
+ } else if (type == ICON_TYPE_CONNECTED) {
+ change_adv_st_mode(ADV_ST_FAST_DISMISS);
+ adv_st_next_mode = ADV_ST_CONN;
+ } else {
+ ;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+//dismiss_flag
+void bt_ble_icon_close(u8 dismiss_flag)
+{
+ ble_printf("bt_ble_close: %d\n", dismiss_flag);
+
+ if ((!dismiss_flag) || (!adv_control_enable)) {
+ ble_puts("close_adv\n");
+ change_adv_st_mode(ADV_ST_END);
+ return;
+ }
+
+#if TCFG_CHARGESTORE_ENABLE && TCFG_USER_TWS_ENABLE
+ ble_printf("###ear_online:%x, conn_state:%x\n", chargestore_get_earphone_online(), get_tws_sibling_connect_state());
+ if (chargestore_get_earphone_online() != 2 && get_tws_sibling_connect_state()) {
+ ble_puts("sibling is running\n");
+ //另外一个耳机没有关机,不需要去icon
+ change_adv_st_mode(ADV_ST_END);
+ return;
+ }
+#endif
+
+ switch (adv_st_mode) {
+ case ADV_ST_CONN:
+ case ADV_ST_RECONN:
+ case ADV_ST_INQUIRY:
+ case ADV_ST_PRE1:
+ case ADV_ST_PRE2:
+ case ADV_ST_FAST_DISMISS:
+ case ADV_ST_DISMISS:
+ case ADV_ST_END://也要做
+
+#if TCFG_USER_TWS_ENABLE
+ if (get_tws_sibling_connect_state() == FALSE) {
+ adv_open_lock = 0;
+ adv_state_step = ADV_STEP_NORMAL;
+ bt_ble_set_control_en(1);
+ bt_ble_icon_reset();
+ }
+#endif
+ change_adv_st_mode(ADV_ST_DISMISS);
+ break;
+
+ default:
+ break;
+ }
+}
+
+//tws,need set en
+extern bool get_tws_sibling_connect_state(void);
+extern int tws_api_get_role(void);
+void bt_ble_icon_slave_en(u8 en)
+{
+ ble_printf("------icon_slave_enable = %d------\n", en);
+ if (en) {
+ dev_battery_level[1] = 0xfc;//set flag
+ } else {
+ dev_battery_level[1] = 0xff;
+ }
+
+#if TCFG_USER_TWS_ENABLE
+ if (get_tws_sibling_connect_state()) {
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ //已配对连接过的从机,记录以后不允许再广播
+ adv_open_lock = 1;//lock open 接口
+ bt_ble_icon_close(0);
+ }
+ }
+#endif
+}
+
+
+//tws,master need set en;使能ICON_OPEN 接口控制
+void bt_ble_set_control_en(u8 en)
+{
+ ble_printf("------adv_control_enable = %d------\n", en);
+ adv_control_enable = en;//set master flag
+}
+//-----------------------
+static void adv_rand_init(void)
+{
+ int ret = syscfg_read(CFG_BLE_MODE_INFO, (u8 *)&adv_rand, 1);
+ if (!ret) {
+ adv_rand = (rand32() % 7) + 1;
+ } else {
+ adv_rand++;
+ }
+
+ if (adv_rand > 7) {
+ adv_rand = 1;
+ }
+ syscfg_write(CFG_BLE_MODE_INFO, (u8 *)&adv_rand, 1);
+ ble_printf("------adv_rand = %d------\n", adv_rand);
+
+}
+
+//新增两个接口如下,用于获取和同步 adv_rand
+void adv_rand_tws_sync(u8 sibling_rand)
+{
+ ble_printf("---sync_adv_rand = %d,%d---\n", adv_rand, sibling_rand);
+ if (sibling_rand != adv_rand) {
+ ble_printf("update sync\n");
+ adv_rand = sibling_rand;
+ syscfg_write(CFG_BLE_MODE_INFO, (u8 *)&adv_rand, 1);
+ }
+}
+
+u8 adv_rand_tws_get(void)
+{
+ return adv_rand;
+}
+
+extern void dut_le_hw_open(void);
+extern void ble_bqb_test_thread_init(void);
+__BANK_INIT_ENTRY
+void bt_ble_init(void)
+{
+
+ if (BT_MODE_IS(BT_NORMAL)) {
+ ble_printf("***** ble_init******\n");
+ adv_rand_init();
+
+#if TCFG_USER_TWS_ENABLE
+ adv_control_enable = 0;//tws,default off
+#else
+ adv_control_enable = 1;//one earphone,default on
+#endif
+ adv_st_mode = ADV_ST_NULL;
+ adv_open_lock = 0;
+ bt_ble_test_tag_do();
+ /* bt_ble_timer_init(); */
+ }
+}
+
+/*
+void bt_ble_icon_set(u8 *info, u8 len)
+{
+ ble_printf("***** ble_icon_set******\n");
+
+ bt_ble_adv_enable(0);
+ update_user_tag_data(info, len);
+ bt_ble_adv_enable(1);
+}
+*/
+
+void bt_ble_exit(void)
+{
+ ble_printf("***** ble_exit******\n");
+
+ bt_ble_adv_enable(0);
+ adv_st_mode = ADV_ST_NULL;
+ adv_control_enable = 0;
+ bt_ble_timer_exit();
+}
+
+void bt_ble_icon_state_sniff(u8 state)
+{
+#if(!PHONE_ICON_AUTO_DISMISS)
+
+ ble_printf("###bt_ble_icon_state_sniff: %d, %d\n", state, adv_state_step);
+ if (state) {
+ // enter sniff
+ adv_state_step = ADV_STEP_SNIFF;
+ adv_check_timer_ms = BLE_SNIFF_TIMER_SET;
+ if (ble_timer_handle) {
+ sys_timer_modify(ble_timer_handle, adv_check_timer_ms);
+ }
+ } else {
+ if (adv_state_step != ADV_STEP_FAST) {
+ adv_state_step = ADV_STEP_NORMAL;
+ adv_check_timer_ms = BLE_TIMER_SET;
+ if (ble_timer_handle) {
+ sys_timer_modify(ble_timer_handle, adv_check_timer_ms);
+ }
+ }
+
+ }
+ dev_adv_reset_do(adv_st_mode);
+ ble_printf("adv_state_step:%d ,mdy adv timer:%d ms\n", adv_state_step, adv_check_timer_ms);
+
+#endif
+
+}
+
+void bt_ble_icon_role_switch(u8 role)
+{
+#if TCFG_USER_TWS_ENABLE
+#if(!PHONE_ICON_AUTO_DISMISS)
+ ble_printf("###bt_ble_icon_role_switch: %d\n", role);
+ if (role == TWS_ROLE_MASTER && get_total_connect_dev() && pbg_user_is_connected()) {
+ ble_printf("change to master\n");
+ adv_open_lock = 0;
+ bt_ble_set_control_en(1);
+ adv_state_step = ADV_STEP_NORMAL;
+ bt_ble_icon_reset();
+ bt_ble_icon_open(ICON_TYPE_RECONNECT);
+ } else {
+ ble_printf("change to slave\n");
+ change_adv_st_mode(ADV_ST_END);
+ bt_ble_set_control_en(0);
+ }
+#endif
+#endif
+
+}
+
+
+#endif
+
+
+
diff --git a/apps/earphone/bt_tws.c b/apps/earphone/bt_tws.c
new file mode 100644
index 0000000..b2c9650
--- /dev/null
+++ b/apps/earphone/bt_tws.c
@@ -0,0 +1,2229 @@
+#include "system/includes.h"
+#include "media/includes.h"
+#include "device/vm.h"
+#include "tone_player.h"
+
+#include "app_config.h"
+#include "app_action.h"
+#include "earphone.h"
+
+#include "btstack/avctp_user.h"
+#include "btstack/btstack_task.h"
+#include "classic/hci_lmp.h"
+#include "user_cfg.h"
+#if TCFG_USER_TWS_ENABLE
+#include "bt_tws.h"
+#endif
+#include "asm/charge.h"
+#include "app_charge.h"
+#include "ui_manage.h"
+
+#include "app_chargestore.h"
+#include "app_testbox.h"
+#include "app_online_cfg.h"
+#include "app_main.h"
+#include "app_power_manage.h"
+#include "audio_config.h"
+#include "user_cfg.h"
+
+#include "btcontroller_config.h"
+#include "bt_common.h"
+#include "asm/pwm_led.h"
+#include "bt_common.h"
+#include "pbg_user.h"
+
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV)
+#include "include/bt_ble.h"
+#endif
+
+#if TCFG_AUDIO_ANC_ENABLE
+#include "audio_anc.h"
+#endif
+
+#if TCFG_ANC_BOX_ENABLE
+#include "app_ancbox.h"
+#endif
+
+#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+#include "icsd_adt_app.h"
+#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
+
+#if TCFG_USER_TWS_ENABLE
+
+#define LOG_TAG_CONST BT_TWS
+#define LOG_TAG "[BT-TWS]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#if TCFG_DEC2TWS_ENABLE
+#define CONFIG_BT_TWS_SNIFF 0 //[WIP]
+#else
+#define CONFIG_BT_TWS_SNIFF 1 //[WIP]
+#endif
+
+#define BT_TWS_UNPAIRED 0x0001
+#define BT_TWS_PAIRED 0x0002
+#define BT_TWS_WAIT_SIBLING_SEARCH 0x0004
+#define BT_TWS_SEARCH_SIBLING 0x0008
+#define BT_TWS_CONNECT_SIBLING 0x0010
+#define BT_TWS_SIBLING_CONNECTED 0x0020
+#define BT_TWS_PHONE_CONNECTED 0x0040
+#define BT_TWS_POWER_ON 0x0080
+#define BT_TWS_TIMEOUT 0x0100
+#define BT_TWS_AUDIO_PLAYING 0x0200
+#define BT_TWS_DISCON_DLY_TIMEOUT 0x0400
+#define BT_TWS_REMOVE_PAIRS 0x0800
+#define BT_TWS_DISCON_DLY_TIMEOUT_NO_CONN 0x1000
+
+#define TWS_DLY_DISCONN_TIME 2000//超时断开,快速连接上不播提示音
+struct tws_user_var {
+ u8 addr[6];
+ u16 state;
+ s16 auto_pair_timeout;
+ int pair_timer;
+ u32 connect_time;
+ u8 device_role; //tws 记录那个是active device 活动设备,音源控制端
+ u16 tws_dly_discon_time;
+ u16 sniff_timer;
+};
+
+struct tws_user_var gtws;
+
+extern void tone_play_deal(const char *name, u8 preemption, u8 add_en);
+
+extern u8 check_tws_le_aa(void);
+extern const char *bt_get_local_name();
+extern u8 get_bredr_link_state();
+extern u8 get_esco_coder_busy_flag();
+void bt_init_ok_search_index(void);
+extern void phone_num_play_timer(void *priv);
+extern u8 phone_ring_play_start(void);
+extern bool get_esco_busy_flag();
+extern void tws_api_set_connect_aa(int);
+extern void tws_api_clear_connect_aa();
+extern u8 tws_remote_state_check(void);
+extern void tws_remote_state_clear(void);
+extern u16 bt_get_tws_device_indicate(u8 *tws_device_indicate);
+void tws_le_acc_generation_init(void);
+static void bt_tws_connect_and_connectable_switch();
+extern int earphone_a2dp_codec_get_low_latency_mode();
+extern int earphone_a2dp_codec_set_low_latency_mode(int enable, int);
+extern u32 get_bt_slot_time(u8 type, u32 time, int *ret_time, int (*local_us_time)(void));
+extern u32 get_sync_rec_instant_us_time();
+extern int update_check_sniff_en(void);
+void tws_sniff_controle_check_disable(void);
+
+static u32 local_us_time = 0;
+static u32 local_instant_us_time = 0;
+static u8 tone_together_by_systime = 0;
+static u32 tws_tone_together_time = 0;
+
+void tws_sniff_controle_check_enable(void);
+
+u8 tws_network_audio_was_started(void)
+{
+ if (gtws.state & BT_TWS_AUDIO_PLAYING) {
+ return 1;
+ }
+
+ return 0;
+}
+
+void tws_network_local_audio_start(void)
+{
+ gtws.state &= ~BT_TWS_AUDIO_PLAYING;
+}
+
+
+static void tws_sync_call_fun(int cmd, int err)
+{
+ struct sys_event event;
+ int diff_time_us = 0;
+
+ event.type = SYS_BT_EVENT;
+ event.arg = (void *)SYS_BT_EVENT_FROM_TWS;
+
+ event.u.bt.event = TWS_EVENT_SYNC_FUN_CMD;
+ event.u.bt.args[0] = 0;
+ event.u.bt.args[1] = 0;
+ event.u.bt.args[2] = cmd;
+
+ sys_event_notify(&event);
+}
+
+TWS_SYNC_CALL_REGISTER(tws_tone_sync) = {
+ .uuid = 'T',
+ .func = tws_sync_call_fun,
+};
+
+u8 tws_tone_together_without_bt(void)
+{
+ return tone_together_by_systime;
+}
+
+void tws_tone_together_clean(void)
+{
+ tone_together_by_systime = 0;
+}
+
+u32 tws_tone_local_together_time(void)
+{
+ return tws_tone_together_time;
+}
+
+u32 get_local_us_time(u32 *instant_time)
+{
+ *instant_time = local_instant_us_time;
+ return local_us_time;
+}
+
+#define msecs_to_bt_slot_clk(m) (((m + 1)* 1000) / 625)
+u32 bt_tws_master_slot_clk(void);
+u32 bt_tws_future_slot_time(u32 msecs)
+{
+ return bt_tws_master_slot_clk() + msecs_to_bt_slot_clk(msecs);
+}
+
+u16 tws_host_get_battery_voltage()
+{
+ return get_vbat_level();
+}
+
+int tws_host_channel_match(char remote_channel)
+{
+ /*r_printf("tws_host_channel_match: %c, %c\n", remote_channel,
+ bt_tws_get_local_channel());*/
+#ifdef CONFIG_NEW_BREDR_ENABLE
+#if CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_LEFT_START_PAIR || \
+ CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_RIGHT_START_PAIR || \
+ CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_MASTER_AS_LEFT || \
+ CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_SECECT_BY_CHARGESTORE
+ return 1;
+#else
+ if (remote_channel != bt_tws_get_local_channel()) {
+ return 1;
+ }
+#endif
+
+#else
+
+#if (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_MASTER_AS_LEFT)
+ return 1;
+#endif
+ if (remote_channel != bt_tws_get_local_channel() || remote_channel == 'U') {
+ return 1;
+ }
+#if CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_LEFT_START_PAIR || \
+ CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_RIGHT_START_PAIR
+ if (gtws.state & BT_TWS_SEARCH_SIBLING) {
+ return 1;
+ }
+#endif
+#endif
+
+ return 0;
+}
+
+char tws_host_get_local_channel()
+{
+ char channel;
+
+#if (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_RIGHT_START_PAIR)
+ if (gtws.state & BT_TWS_SEARCH_SIBLING) {
+ return 'R';
+ }
+#elif (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_LEFT_START_PAIR)
+ if (gtws.state & BT_TWS_SEARCH_SIBLING) {
+ return 'L';
+ }
+#endif
+ channel = bt_tws_get_local_channel();
+ if (channel != 'R') {
+ channel = 'L';
+ }
+ /*y_printf("tws_host_get_local_channel: %c\n", channel);*/
+
+ return channel;
+}
+
+#if CONFIG_TWS_COMMON_ADDR_SELECT == CONFIG_TWS_COMMON_ADDR_USED_LEFT
+#ifdef CONFIG_NEW_BREDR_ENABLE
+void tws_host_get_common_addr(u8 *remote_mac_addr, u8 *common_addr, char channel)
+{
+ if (channel == 'L') {
+ memcpy(common_addr, bt_get_mac_addr(), 6);
+ } else {
+ memcpy(common_addr, remote_mac_addr, 6);
+ }
+}
+#endif
+#endif
+
+#if TCFG_DEC2TWS_ENABLE
+int tws_host_get_local_role()
+{
+ if (app_var.have_mass_storage) {
+ return TWS_ROLE_MASTER;
+ }
+
+ return TWS_ROLE_SLAVE;
+}
+#endif
+
+/*
+ * 设置自动回连的识别码 6个byte
+ * */
+u8 auto_pair_code[6] = {0x34, 0x66, 0x33, 0x87, 0x09, 0x42};
+
+u8 *tws_set_auto_pair_code(void)
+{
+ u16 code = bt_get_tws_device_indicate(NULL);
+ auto_pair_code[0] = code >> 8;
+ auto_pair_code[1] = code & 0xff;
+ return auto_pair_code;
+}
+#if CONFIG_TWS_PAIR_MODE == CONFIG_TWS_PAIR_BY_FAST_CONN
+u8 tws_auto_pair_enable = 1;
+#else
+u8 tws_auto_pair_enable = 0;
+#endif
+
+
+u8 tws_get_sibling_addr(u8 *addr, int *result)
+{
+ u8 all_ff[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+ int len = syscfg_read(CFG_TWS_REMOTE_ADDR, addr, 6);
+ if (len != 6 || !memcmp(addr, all_ff, 6)) {
+ *result = len;
+ return -ENOENT;
+ }
+ return 0;
+}
+
+void lmp_hci_write_local_address(const u8 *addr);
+
+/*
+ * 获取左右耳信息
+ * 'L': 左耳
+ * 'R': 右耳
+ * 'U': 未知
+ */
+char bt_tws_get_local_channel()
+{
+ char channel = 'U';
+
+ syscfg_read(CFG_TWS_CHANNEL, &channel, 1);
+
+ return channel;
+}
+
+int get_bt_tws_connect_status()
+{
+ if (gtws.state & BT_TWS_SIBLING_CONNECTED) {
+ return 1;
+ }
+
+ return 0;
+}
+u8 get_bt_tws_discon_dly_state()
+{
+ if (gtws.tws_dly_discon_time) {
+ return 1;
+ }
+ return 0;
+}
+void tws_disconn_dly_deal(void *priv)
+{
+ int role = (int)priv;
+ r_printf("tws_disconn_dly_deal=0x%x\n", role);
+ STATUS *p_tone = get_tone_config();
+ gtws.tws_dly_discon_time = 0;
+ if (gtws.state & BT_TWS_DISCON_DLY_TIMEOUT) {
+ tone_play_index(p_tone->tws_disconnect, 1);
+ }
+ if ((gtws.state & BT_TWS_DISCON_DLY_TIMEOUT_NO_CONN) && (role == TWS_ROLE_SLAVE) && (!app_var.goto_poweroff_flag)) { /*关机不播断开提示音*/
+
+ tone_play_index(p_tone->bt_disconnect, 1);
+ }
+ gtws.state &= ~BT_TWS_DISCON_DLY_TIMEOUT_NO_CONN;
+}
+
+
+void tws_sync_phone_num_play_wait(void *priv)
+{
+ puts("tws_sync_phone_num_play_wait\n");
+ if (bt_user_priv_var.phone_con_sync_num_ring) {
+ puts("phone_con_sync_num_ring\n");
+ return;
+ }
+ if (bt_user_priv_var.phone_num_flag) {
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ bt_tws_play_tone_at_same_time(SYNC_TONE_PHONE_NUM, 400);
+ } else { //从机超时还没获取到
+ phone_ring_play_start();
+ }
+ } else {
+ /*电话号码还没有获取到,定时查询*/
+ if (bt_user_priv_var.get_phone_num_timecnt > 60) {
+ bt_user_priv_var.get_phone_num_timecnt = 0;
+ bt_tws_play_tone_at_same_time(SYNC_TONE_PHONE_NUM_RING, 400);
+ } else {
+ bt_user_priv_var.phone_timer_id = sys_timeout_add(NULL, tws_sync_phone_num_play_wait, 10);
+ }
+ }
+ bt_user_priv_var.get_phone_num_timecnt++;
+
+}
+
+int bt_tws_sync_phone_num(void *priv)
+{
+ int state = tws_api_get_tws_state();
+ if ((state & TWS_STA_SIBLING_CONNECTED) && (state & TWS_STA_PHONE_CONNECTED)) {
+ puts("bt_tws_sync_phone_num\n");
+#if BT_PHONE_NUMBER
+ bt_user_priv_var.get_phone_num_timecnt = 0;
+ if (tws_api_get_role() == TWS_ROLE_SLAVE && bt_user_priv_var.phone_con_sync_num_ring) { //从机同步播来电ring,不在发起sync_play
+ puts("phone_con_sync_num_ring_ing return\n");
+ return 1;
+ }
+#endif
+ if (tws_api_get_role() == TWS_ROLE_SLAVE || bt_user_priv_var.phone_con_sync_num_ring) {
+
+ if (!(state & TWS_STA_MONITOR_START)) {
+ puts(" not monitor ring_tone\n");
+ /* tws_api_sync_call_by_uuid('T', SYNC_CMD_PHONE_RING_TONE, TWS_SYNC_TIME_DO * 5); */
+ bt_user_priv_var.phone_timer_id = sys_timeout_add(NULL, (void (*)(void *priv))bt_tws_sync_phone_num, 10);
+ return 1;
+ }
+#if BT_PHONE_NUMBER
+ if (bt_user_priv_var.phone_con_sync_num_ring) {
+ puts("<<<<<<<<<< 0) {
+ if (gtws.state & BT_TWS_SIBLING_CONNECTED) {
+ timeout = 8000;
+ } else {
+#ifdef CONFIG_TWS_BY_CLICK_PAIR_WITHOUT_PAIR
+ timeout = 2000 + (rand32() % 4 + 1) * 500;
+#else
+ timeout = 4000 + (rand32() % 4 + 1) * 500;
+#endif
+ }
+ bt_user_priv_var.auto_connection_counter -= timeout ;
+ tws_api_cancle_wait_pair();
+ tws_api_cancle_create_connection();
+ user_send_cmd_prepare(USER_CTRL_START_CONNEC_VIA_ADDR, 6,
+ bt_user_priv_var.auto_connection_addr);
+ } else {
+ bt_user_priv_var.auto_connection_counter = 0;
+
+ EARPHONE_STATE_CANCEL_PAGE_SCAN();
+
+ if (gtws.state & BT_TWS_POWER_ON) {
+ /*
+ * 开机回连,获取下一个设备地址
+ */
+ if (get_current_poweron_memory_search_index(NULL)) {
+ bt_init_ok_search_index();
+ goto __again;
+ }
+ gtws.state &= ~BT_TWS_POWER_ON;
+ }
+
+ if (gtws.state & BT_TWS_SIBLING_CONNECTED) {
+ tws_api_wait_pair_by_code(bt_get_tws_device_indicate(NULL), bt_get_local_name(), 0);
+
+ tws_sniff_controle_check_enable();
+ return;
+ }
+#if CONFIG_TWS_PAIR_MODE == CONFIG_TWS_PAIR_BY_CLICK
+ if (gtws.state & BT_TWS_UNPAIRED) {
+ tws_api_wait_pair_by_code(bt_get_tws_device_indicate(NULL), bt_get_local_name(), 0);
+ return;
+ }
+#endif
+ sw = 1;
+ }
+ }
+
+ if (sw == 1) {
+ tws_api_wait_pair_by_code(bt_get_tws_device_indicate(NULL), bt_get_local_name(), 0);
+ if (!(gtws.state & BT_TWS_SIBLING_CONNECTED)) {
+ if (!(gtws.state & BT_TWS_UNPAIRED)) {
+#ifdef CONFIG_TWS_AUTO_PAIR_WITHOUT_UNPAIR
+ end_sw = 2;
+#endif
+ } else {
+#if CONFIG_TWS_PAIR_MODE == CONFIG_TWS_PAIR_BY_CLICK
+ goto __set_time;
+#endif
+ }
+ tws_api_create_connection(0);
+ //tws_api_power_saving_mode_enable();
+ }
+__set_time:
+#ifdef CONFIG_TWS_BY_CLICK_PAIR_WITHOUT_PAIR
+ timeout = 500 + (rand32() % 4 + 1) * 500;
+#else
+ timeout = 2000 + (rand32() % 4 + 1) * 500;
+#endif
+
+ EARPHONE_STATE_SET_PAGE_SCAN_ENABLE();
+
+ if (bt_user_priv_var.auto_connection_counter <= 0 && end_sw == 1) {
+ if (gtws.state & BT_TWS_SIBLING_CONNECTED) {
+ tws_sniff_controle_check_enable();
+ }
+ return;
+ }
+
+ } else if (sw == 2) {
+ u8 addr[6];
+#ifdef CONFIG_TWS_BY_CLICK_PAIR_WITHOUT_PAIR
+ timeout = 500 + (rand32() % 4 + 1) * 500;
+ tws_api_wait_pair_by_code(bt_get_tws_device_indicate(NULL), bt_get_local_name(), 0);
+
+#else
+ timeout = 2000 + (rand32() % 4 + 1) * 500;
+ memcpy(addr, tws_api_get_quick_connect_addr(), 6);
+ tws_api_set_quick_connect_addr(tws_set_auto_pair_code());
+ tws_api_create_connection(0);
+ tws_api_set_quick_connect_addr(addr);
+ /*tws_api_power_saving_mode_enable();*/
+#endif
+ }
+ if (++sw > end_sw) {
+ sw = 0;
+ }
+
+ gtws.pair_timer = sys_timeout_add((void *)sw, connect_and_connectable_switch, timeout);
+}
+
+#else
+
+static void connect_and_connectable_switch(void *_sw)
+{
+ int timeout = 0;
+ int sw = (int)_sw;
+
+ gtws.pair_timer = 0;
+
+ log_info("switch: %d, state = %x, %d\n", sw, gtws.state,
+ bt_user_priv_var.auto_connection_counter);
+
+#if CONFIG_TWS_PAIR_MODE == CONFIG_TWS_PAIR_BY_AUTO
+ if (tws_auto_pair_enable == 1) {
+ tws_auto_pair_enable = 0;
+ tws_le_acc_generation_init();
+ }
+#endif
+
+ if (tws_remote_state_check()) {
+ if (sw == 0) {
+ sw = 1;
+ } else if (sw == 3) {
+ sw = 2;
+ }
+ puts("tws_exist\n");
+ }
+
+ if (sw == 0) {
+__again:
+ if (bt_user_priv_var.auto_connection_counter > 0) {
+ timeout = 4000 + (rand32() % 4 + 1) * 500;
+ bt_user_priv_var.auto_connection_counter -= timeout ;
+ tws_api_cancle_wait_pair();
+ tws_api_cancle_create_connection();
+ user_send_cmd_prepare(USER_CTRL_START_CONNEC_VIA_ADDR, 6,
+ bt_user_priv_var.auto_connection_addr);
+ } else {
+ bt_user_priv_var.auto_connection_counter = 0;
+
+ EARPHONE_STATE_CANCEL_PAGE_SCAN();
+
+ if (gtws.state & BT_TWS_POWER_ON) {
+ /*
+ * 开机回连,获取下一个设备地址
+ */
+ if (get_current_poweron_memory_search_index(NULL)) {
+ bt_init_ok_search_index();
+ goto __again;
+ }
+ gtws.state &= ~BT_TWS_POWER_ON;
+ }
+
+ if (gtws.state & BT_TWS_SIBLING_CONNECTED) {
+ tws_api_wait_pair_by_code(bt_get_tws_device_indicate(NULL), bt_get_local_name(), 0);
+ return;
+ }
+#if CONFIG_TWS_PAIR_MODE == CONFIG_TWS_PAIR_BY_CLICK
+ if (gtws.state & BT_TWS_UNPAIRED) {
+ tws_api_wait_pair_by_code(bt_get_tws_device_indicate(NULL), bt_get_local_name(), 0);
+ return;
+ }
+#endif
+ sw = 1;
+ }
+ }
+
+ if (sw == 1) {
+ if (tws_remote_state_check()) {
+ timeout = 1000 + (rand32() % 4 + 1) * 500;
+ } else {
+ timeout = 2000 + (rand32() % 4 + 1) * 500;
+ }
+ tws_api_wait_pair_by_code(bt_get_tws_device_indicate(NULL), bt_get_local_name(), 0);
+
+ EARPHONE_STATE_SET_PAGE_SCAN_ENABLE();
+
+ } else if (sw == 2) {
+ if (tws_remote_state_check()) {
+ timeout = 4000;
+ } else {
+ timeout = 1000 + (rand32() % 4 + 1) * 500;
+ }
+ tws_remote_state_clear();
+ tws_api_create_connection(0);
+ } else if (sw == 3) {
+#if CONFIG_TWS_PAIR_MODE == CONFIG_TWS_PAIR_BY_AUTO
+ timeout = 2000 + (rand32() % 4 + 1) * 500;
+ tws_auto_pair_enable = 1;
+ tws_le_acc_generation_init();
+ tws_api_create_connection(0);
+#endif
+ }
+
+ if (gtws.state & BT_TWS_SIBLING_CONNECTED) {
+ if (++sw > 1) {
+ sw = 0;
+ }
+ } else {
+ int end_sw = 2;
+#ifdef CONFIG_TWS_AUTO_PAIR_WITHOUT_UNPAIR
+ end_sw = 3;
+#elif CONFIG_TWS_PAIR_MODE == CONFIG_TWS_PAIR_BY_AUTO
+ if (gtws.state & BT_TWS_UNPAIRED) {
+ end_sw = 3;
+ }
+#endif
+ if (++sw > end_sw) {
+ sw = 0;
+ }
+ }
+
+ gtws.pair_timer = sys_timeout_add((void *)sw, connect_and_connectable_switch, timeout);
+
+}
+#endif
+
+static void bt_tws_connect_and_connectable_switch()
+{
+ bt_tws_delete_pair_timer();
+
+#if TCFG_AUDIO_ANC_ENABLE
+#if TCFG_ANC_BOX_ENABLE
+ if (ancbox_get_status()) {
+ EARPHONE_STATE_SET_PAGE_SCAN_ENABLE();
+ user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_ENABLE, 0, NULL);
+ user_send_cmd_prepare(USER_CTRL_WRITE_CONN_ENABLE, 0, NULL);
+ return;
+ }
+#endif
+#endif
+
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ connect_and_connectable_switch(0);
+ }
+}
+
+
+int bt_tws_start_search_sibling()
+{
+ int state = get_bt_connect_status();
+
+ if (gtws.state & BT_TWS_PHONE_CONNECTED) {
+ return 0;
+ }
+
+ if (gtws.state & BT_TWS_SIBLING_CONNECTED) {
+#ifdef CONFIG_TWS_REMOVE_PAIR_ENABLE
+ puts("===========remove_pairs\n");
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ tws_api_remove_pairs();
+ gtws.state |= BT_TWS_REMOVE_PAIRS;
+ }
+#endif
+ return 0;
+ }
+
+ if (check_tws_le_aa()) {
+ return 0;
+ }
+
+#if CONFIG_TWS_PAIR_MODE == CONFIG_TWS_PAIR_BY_CLICK
+ log_i("bt_tws_start_search_sibling\n");
+ gtws.state |= BT_TWS_SEARCH_SIBLING;
+#if CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_LEFT_START_PAIR || \
+ CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_RIGHT_START_PAIR || \
+ CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_MASTER_AS_LEFT
+ tws_api_set_local_channel('U');
+#endif
+ bt_tws_search_sibling_and_pair();
+ return 1;
+#endif
+
+ return 0;
+}
+
+
+/*
+ * 自动配对状态定时切换函数
+ */
+static void __bt_tws_auto_pair_switch(void *priv)
+{
+ u32 timeout;
+ int sw = (int)priv;
+
+ gtws.pair_timer = 0;
+
+ printf("bt_tws_auto_pair: %d, %d\n", gtws.auto_pair_timeout, bt_user_priv_var.auto_connection_counter);
+
+ if (gtws.auto_pair_timeout < 0 && bt_user_priv_var.auto_connection_counter > 0) {
+ gtws.auto_pair_timeout = 4000;
+ timeout = bt_tws_connect_phone();
+ } else {
+
+ timeout = 1000 + ((rand32() % 10) * 200);
+
+ gtws.auto_pair_timeout -= timeout;
+
+ if (sw == 0) {
+ tws_api_wait_pair_by_code(bt_get_tws_device_indicate(NULL), bt_get_local_name(), 0);
+ } else if (sw == 1) {
+ bt_tws_search_sibling_and_pair();
+ }
+
+ if (++sw > 1) {
+ sw = 0;
+ }
+ }
+
+ gtws.pair_timer = sys_timeout_add((void *)sw, __bt_tws_auto_pair_switch, timeout);
+}
+
+static void bt_tws_auto_pair_switch(int timeout)
+{
+ bt_tws_delete_pair_timer();
+
+ gtws.auto_pair_timeout = timeout;
+ __bt_tws_auto_pair_switch(NULL);
+}
+
+
+
+static u8 set_channel_by_code_or_res(void)
+{
+ u8 count = 0;
+ char channel = 0;
+ char last_channel = 0;
+#if (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_EXTERN_UP_AS_LEFT)
+ gpio_set_direction(CONFIG_TWS_CHANNEL_CHECK_IO, 1);
+ gpio_set_pull_down(CONFIG_TWS_CHANNEL_CHECK_IO, 1);
+ gpio_set_die(CONFIG_TWS_CHANNEL_CHECK_IO, 1);
+ for (int i = 0; i < 5; i++) {
+ os_time_dly(2);
+ if (gpio_read(CONFIG_TWS_CHANNEL_CHECK_IO)) {
+ count++;
+ }
+ }
+ gpio_set_direction(CONFIG_TWS_CHANNEL_CHECK_IO, 1);
+ gpio_set_pull_down(CONFIG_TWS_CHANNEL_CHECK_IO, 0);
+ gpio_set_die(CONFIG_TWS_CHANNEL_CHECK_IO, 0);
+ channel = (count >= 3) ? 'L' : 'R';
+#elif (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_EXTERN_DOWN_AS_LEFT)
+ gpio_set_direction(CONFIG_TWS_CHANNEL_CHECK_IO, 1);
+ gpio_set_die(CONFIG_TWS_CHANNEL_CHECK_IO, 1);
+ gpio_set_pull_up(CONFIG_TWS_CHANNEL_CHECK_IO, 1);
+ for (int i = 0; i < 5; i++) {
+ os_time_dly(2);
+ if (gpio_read(CONFIG_TWS_CHANNEL_CHECK_IO)) {
+ count++;
+ }
+ }
+ gpio_set_direction(CONFIG_TWS_CHANNEL_CHECK_IO, 1);
+ gpio_set_die(CONFIG_TWS_CHANNEL_CHECK_IO, 0);
+ gpio_set_pull_up(CONFIG_TWS_CHANNEL_CHECK_IO, 0);
+ channel = (count >= 3) ? 'R' : 'L';
+#elif (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_AS_LEFT_CHANNEL)
+ channel = 'L';
+#elif (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_AS_RIGHT_CHANNEL)
+ channel = 'R';
+#elif (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_SECECT_BY_CHARGESTORE)
+ syscfg_read(CFG_CHARGESTORE_TWS_CHANNEL, &channel, 1);
+#endif
+
+#if CONFIG_TWS_SECECT_CHARGESTORE_PRIO
+ syscfg_read(CFG_CHARGESTORE_TWS_CHANNEL, &channel, 1);
+#endif
+
+ if (channel) {
+ syscfg_read(CFG_TWS_CHANNEL, &last_channel, 1);
+ if (channel != last_channel) {
+ syscfg_write(CFG_TWS_CHANNEL, &channel, 1);
+ }
+ tws_api_set_local_channel(channel);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * 开机tws初始化
+ */
+__BANK_INIT_ENTRY
+int bt_tws_poweron()
+{
+ int err;
+ u8 addr[6];
+ char channel;
+
+#if TCFG_TEST_BOX_ENABLE
+ if (testbox_get_ex_enter_dut_flag()) {
+ log_info("tws poweron enter dut case\n");
+ user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_ENABLE, 0, NULL);
+ user_send_cmd_prepare(USER_CTRL_WRITE_CONN_ENABLE, 0, NULL);
+ return 0;
+ }
+#endif
+
+#if TCFG_AUDIO_ANC_ENABLE
+ /*支持ANC训练快速连接,不连接tws*/
+#if TCFG_ANC_BOX_ENABLE
+ if (ancbox_get_status())
+#else
+ if (0)
+#endif/*TCFG_ANC_BOX_ENABLE*/
+ {
+ EARPHONE_STATE_SET_PAGE_SCAN_ENABLE();
+ user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_ENABLE, 0, NULL);
+ user_send_cmd_prepare(USER_CTRL_WRITE_CONN_ENABLE, 0, NULL);
+ return 0;
+ } else {
+ /*tws配对前,先关闭可发现可连接,不影响tws配对状态*/
+ //user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_DISABLE, 0, NULL);
+ //user_send_cmd_prepare(USER_CTRL_WRITE_CONN_DISABLE, 0, NULL);
+ }
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+
+ gtws.tws_dly_discon_time = 0;
+ gtws.state = BT_TWS_POWER_ON;
+ gtws.connect_time = 0;
+
+ lmp_hci_write_page_timeout(12000);
+#ifdef CONFIG_A2DP_GAME_MODE_ENABLE
+ extern void bt_set_low_latency_mode(int enable);
+
+ /* tws_api_auto_role_switch_disable(); */
+ /* bt_set_low_latency_mode(1);//开机默认低延时模式设置 */
+#endif
+
+ int result = 0;
+ err = tws_get_sibling_addr(addr, &result);
+ if (err == 0) {
+ /*
+ * 获取到对方地址, 开始连接
+ */
+ printf("\n ---------have tws info----------\n");
+ gtws.state |= BT_TWS_PAIRED;
+
+ EARPHONE_STATE_TWS_INIT(1);
+
+ tws_api_set_sibling_addr(addr);
+ if (set_channel_by_code_or_res() == 0) {
+ channel = bt_tws_get_local_channel();
+ tws_api_set_local_channel(channel);
+ }
+#if TCFG_TEST_BOX_ENABLE
+ if (testbox_get_status()) {
+ } else
+#endif
+ {
+#ifdef CONFIG_NEW_BREDR_ENABLE
+ /* if (bt_tws_get_local_channel() == 'L') { */
+ /* syscfg_read(CFG_TWS_LOCAL_ADDR, addr, 6); */
+ /* } */
+ u8 local_addr[6];
+ syscfg_read(CFG_TWS_LOCAL_ADDR, local_addr, 6);
+ for (int i = 0; i < 6; i++) {
+ addr[i] += local_addr[i];
+ }
+ tws_api_set_quick_connect_addr(addr);
+#endif
+ bt_tws_connect_sibling(CONFIG_TWS_CONNECT_SIBLING_TIMEOUT);
+ }
+
+ } else {
+ printf("\n ---------no tws info----------\n");
+
+ EARPHONE_STATE_TWS_INIT(0);
+
+ // no_tws for test
+ //EARPHONE_STATE_TWS_INIT(1);
+ //EARPHONE_STATE_SET_PAGE_SCAN_ENABLE();
+
+
+ gtws.state |= BT_TWS_UNPAIRED;
+ if (set_channel_by_code_or_res() == 0) {
+ tws_api_set_local_channel('U');
+ }
+#if TCFG_TEST_BOX_ENABLE
+ if (testbox_get_status()) {
+ } else
+#endif
+ {
+
+#if CONFIG_TWS_PAIR_MODE == CONFIG_TWS_PAIR_BY_AUTO
+ /*
+ * 未配对, 开始自动配对
+ */
+#ifdef CONFIG_NEW_BREDR_ENABLE
+ tws_api_set_quick_connect_addr(tws_set_auto_pair_code());
+#else
+ tws_auto_pair_enable = 1;
+ tws_le_acc_generation_init();
+#endif
+ bt_tws_connect_sibling(6);
+
+#else
+#if CONFIG_TWS_PAIR_MODE == CONFIG_TWS_PAIR_BY_CLICK
+ if (result == VM_INDEX_ERR) {
+ printf("tws_get_sibling_addr index_err and bt_tws_start_search_sibling =%d\n", result);
+ bt_tws_start_search_sibling();
+ } else
+#endif
+ {
+ /*
+ * 未配对, 等待发起配对
+ */
+ bt_tws_connect_and_connectable_switch();
+ /*tws_api_create_connection(0);*/
+ /*bt_tws_search_sibling_and_pair();*/
+
+ }
+#endif
+ }
+ }
+
+#ifndef CONFIG_NEW_BREDR_ENABLE
+ tws_remote_state_clear();
+#endif
+
+ return 0;
+}
+
+/*
+ * 手机开始连接
+ */
+void bt_tws_hci_event_connect()
+{
+ printf("bt_tws_hci_event_connect: %x\n", gtws.state);
+
+ gtws.state &= ~BT_TWS_POWER_ON;
+
+ bt_user_priv_var.auto_connection_counter = 0;
+
+ bt_tws_delete_pair_timer();
+ sys_auto_shut_down_disable();
+ tws_api_power_saving_mode_disable();
+
+ tws_sniff_controle_check_disable();
+
+#ifndef CONFIG_NEW_BREDR_ENABLE
+ tws_remote_state_clear();
+#endif
+}
+
+int bt_tws_phone_connected()
+{
+ int state;
+
+ printf("bt_tws_phone_connected: %x\n", gtws.state);
+
+#if TCFG_TEST_BOX_ENABLE
+ if (testbox_get_status()) {
+ return 1;
+ }
+#endif
+
+ gtws.state |= BT_TWS_PHONE_CONNECTED;
+
+ if (gtws.state & BT_TWS_UNPAIRED) {
+ return 0;
+ }
+
+ if (!(gtws.state & BT_TWS_SIBLING_CONNECTED)) {
+ bt_tws_wait_sibling_connect(0);
+ return 0;
+ }
+
+ if (app_var.phone_dly_discon_time) {
+ sys_timeout_del(app_var.phone_dly_discon_time);
+ app_var.phone_dly_discon_time = 0;
+ return 1;
+ }
+
+ /*
+ * 获取tws状态,如果正在播歌或打电话则返回1,不播连接成功提示音
+ */
+
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ //此时手机已经连接上,同步PHONE_CONN状态
+ bt_tws_led_state_sync(SYNC_LED_STA_PHONE_CONN, 300);
+ state = tws_api_get_tws_state();
+ if (state & (TWS_STA_SBC_OPEN | TWS_STA_ESCO_OPEN) ||
+ (get_call_status() != BT_CALL_HANGUP)) {
+ return 1;
+ }
+
+ log_info("[SYNC] TONE SYNC");
+ bt_tws_play_tone_at_same_time(SYNC_TONE_PHONE_CONNECTED, 1200);
+ }
+
+ return 1;
+}
+
+void bt_tws_phone_disconnected()
+{
+ gtws.state &= ~BT_TWS_PHONE_CONNECTED;
+
+ printf("bt_tws_phone_disconnected: %x\n", gtws.state);
+
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ tws_api_sync_call_by_uuid('T', SYNC_CMD_SHUT_DOWN_TIME, 400);//同步关机时间
+ }
+
+ bt_user_priv_var.auto_connection_counter = 0;
+ if (!(gtws.state & BT_TWS_SIBLING_CONNECTED)) {
+ bt_tws_connect_and_connectable_switch();
+ }
+}
+
+void bt_tws_phone_page_timeout()
+{
+ printf("bt_tws_phone_page_timeout: %x\n", gtws.state);
+
+ bt_tws_phone_disconnected();
+}
+
+
+void bt_tws_phone_connect_timeout()
+{
+ log_d("bt_tws_phone_connect_timeout: %x, %d\n", gtws.state, gtws.pair_timer);
+
+ gtws.state &= ~BT_TWS_PHONE_CONNECTED;
+
+ /*
+ * 跟手机超时断开,如果对耳未连接则优先连接对耳
+ */
+ if (gtws.state & (BT_TWS_UNPAIRED | BT_TWS_SIBLING_CONNECTED)) {
+ bt_tws_connect_and_connectable_switch();
+ } else {
+ bt_tws_connect_sibling(CONFIG_TWS_CONNECT_SIBLING_TIMEOUT);
+ }
+}
+
+void bt_get_vm_mac_addr(u8 *addr);
+
+void bt_page_scan_for_test(u8 inquiry_en)
+{
+ u8 local_addr[6];
+
+ int state = tws_api_get_tws_state();
+
+ log_info("\n\n\n\n -------------bt test page scan\n");
+
+ bt_tws_delete_pair_timer();
+
+ tws_api_cancle_wait_pair();
+ tws_api_cancle_create_connection();
+ user_send_cmd_prepare(USER_CTRL_PAGE_CANCEL, 0, NULL);
+
+ tws_api_detach(TWS_DETACH_BY_POWEROFF);
+
+ user_send_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
+
+ if (0 == get_total_connect_dev()) {
+ log_info("<<<<>>>>\n", inquiry_en);
+ bt_get_vm_mac_addr(local_addr);
+
+ //log_info("local_adr\n");
+ //put_buf(local_addr,6);
+ lmp_hci_write_local_address(local_addr);
+ if (inquiry_en) {
+ user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_ENABLE, 0, NULL);
+ }
+ user_send_cmd_prepare(USER_CTRL_WRITE_CONN_ENABLE, 0, NULL);
+ }
+
+ gtws.state = 0;
+}
+
+int bt_tws_poweroff()
+{
+ log_info("bt_tws_poweroff\n");
+
+ bt_tws_delete_pair_timer();
+
+ tws_api_cancle_wait_pair();
+ tws_api_cancle_create_connection();
+ user_send_cmd_prepare(USER_CTRL_PAGE_CANCEL, 0, NULL);
+
+ tws_api_detach(TWS_DETACH_BY_POWEROFF);
+
+ tws_profile_exit();
+
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_DISCONNECTED) {
+ return 1;
+ }
+
+ return 0;
+}
+
+void tws_page_scan_deal_by_esco(u8 esco_flag)
+{
+ if (gtws.state & BT_TWS_UNPAIRED) {
+ return;
+ }
+
+ if (esco_flag) {
+ bt_tws_delete_pair_timer();
+ gtws.state &= ~BT_TWS_CONNECT_SIBLING;
+ tws_api_cancle_create_connection();
+ tws_api_connect_in_esco();
+ puts("close scan\n");
+ }
+
+ if (!esco_flag && !(gtws.state & BT_TWS_SIBLING_CONNECTED)) {
+ puts("open scan22\n");
+ tws_api_cancle_connect_in_esco();
+ tws_api_wait_connection(0);
+ }
+}
+
+/*
+ * 解除配对,清掉对方地址信息和本地声道信息
+ */
+void bt_tws_remove_pairs()
+{
+ u8 mac_addr[6];
+ char channel = 'U';
+ char tws_channel = 0;
+
+ gtws.state &= ~BT_TWS_REMOVE_PAIRS;
+
+ memset(mac_addr, 0xFF, 6);
+ syscfg_write(CFG_TWS_COMMON_ADDR, mac_addr, 6);
+ syscfg_write(CFG_TWS_REMOTE_ADDR, mac_addr, 6);
+ syscfg_read(CFG_BT_MAC_ADDR, mac_addr, 6);
+ lmp_hci_write_local_address(mac_addr);
+
+#if (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_LEFT_START_PAIR) ||\
+ (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_RIGHT_START_PAIR) ||\
+ (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_MASTER_AS_LEFT)
+
+#if CONFIG_TWS_SECECT_CHARGESTORE_PRIO
+ syscfg_read(CFG_CHARGESTORE_TWS_CHANNEL, &tws_channel, 1);
+#endif
+ if ((tws_channel != 'L') && (tws_channel != 'R')) {
+ syscfg_write(CFG_TWS_CHANNEL, &channel, 1);
+ tws_api_set_local_channel(channel);
+ }
+#endif
+
+ tws_api_clear_connect_aa();
+
+ bt_tws_wait_pair_and_phone_connect();
+
+}
+
+#if TCFG_ADSP_UART_ENABLE
+extern void adsp_deal_sibling_uart_command(u8 type, u8 cmd);
+void tws_sync_uart_command(u8 type, u8 cmd)
+{
+ struct tws_sync_info_t sync_adsp_uart_command;
+ sync_adsp_uart_command.type = TWS_SYNC_ADSP_UART_CMD;
+ sync_adsp_uart_command.u.adsp_cmd[0] = type;
+ sync_adsp_uart_command.u.adsp_cmd[1] = cmd;
+ tws_api_send_data_to_sibling((u8 *)&sync_adsp_uart_command, sizeof(sync_adsp_uart_command));
+}
+#endif
+
+extern void set_tws_sibling_bat_level(u16 level);
+
+
+#define TWS_FUNC_ID_VOL_SYNC TWS_FUNC_ID('V', 'O', 'L', 'S')
+
+static void bt_tws_vol_sync(void *_data, u16 len, bool rx)
+{
+ if (rx) {
+ u8 *data = (u8 *)_data;
+ app_audio_set_volume(APP_AUDIO_STATE_MUSIC, data[0], 1);
+ app_audio_set_volume(APP_AUDIO_STATE_CALL, data[1], 1);
+ r_printf("vol_sync: %d, %d\n", data[0], data[1]);
+ }
+
+}
+
+
+REGISTER_TWS_FUNC_STUB(app_vol_sync_stub) = {
+ .func_id = TWS_FUNC_ID_VOL_SYNC,
+ .func = bt_tws_vol_sync,
+};
+
+void bt_tws_sync_volume()
+{
+ u8 data[2];
+
+ data[0] = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
+ data[1] = app_audio_get_volume(APP_AUDIO_STATE_CALL);
+
+ tws_api_send_data_to_slave(data, 2, TWS_FUNC_ID_VOL_SYNC);
+}
+
+#if TCFG_AUDIO_ANC_ENABLE
+#define TWS_FUNC_ID_ANC_SYNC TWS_FUNC_ID('A', 'N', 'C', 'S')
+static void bt_tws_anc_sync(void *_data, u16 len, bool rx)
+{
+ if (rx) {
+ u8 *data = (u8 *)_data;
+ //r_printf("[slave]anc_sync: %d, %d\n", data[0], data[1]);
+#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+ /*先关闭adt,同步adt状态,然后同步anc,在anc里面做判断开adt*/
+ audio_anc_icsd_adt_state_sync(data);
+#else
+ anc_mode_sync(data);
+#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
+ }
+}
+
+REGISTER_TWS_FUNC_STUB(app_anc_sync_stub) = {
+ .func_id = TWS_FUNC_ID_ANC_SYNC,
+ .func = bt_tws_anc_sync,
+};
+
+void bt_tws_sync_anc(void)
+{
+ u8 data[5];
+#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+ /*处理tws配对前一瞬间,在anc off开adt的情况*/
+ data[0] = anc_new_target_mode_get();
+#else
+ data[0] = anc_mode_get();
+#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
+#if ANC_EAR_ADAPTIVE_EN
+ data[1] = anc_ear_adaptive_seq_get();
+#endif/*ANC_EAR_ADAPTIVE_EN*/
+#if ANC_MULT_ORDER_ENABLE
+ data[2] = audio_anc_mult_scene_get();
+#endif/*ANC_MULT_ORDER_ENABLE*/
+#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+ data[3] = get_icsd_adt_mode();
+ data[4] = get_speak_to_chat_state();
+ printf("%s:%d, %x, %d", __func__, __LINE__, data[3], data[4]);
+#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
+
+ //r_printf("[master]anc_sync: %d, %d\n", data[0], data[1]);
+ tws_api_send_data_to_slave(data, 5, TWS_FUNC_ID_ANC_SYNC);
+}
+
+#if (defined ANC_ADAPTIVE_EN) && ANC_ADAPTIVE_EN
+#define TWS_FUNC_ID_ANC_ADAP_SYNC TWS_FUNC_ID('A', 'N', 'C', 'A')
+static void bt_tws_anc_adap_sync(int dat, int err)
+{
+ /* printf("%s,%d, lvl 0X%x\n", __func__, __LINE__, dat); */
+ audio_anc_adap_sync((dat >> 8), (dat & 0XFF), err);
+}
+
+TWS_SYNC_CALL_REGISTER(tws_anc_adaptive_sync) = {
+ .uuid = TWS_FUNC_ID_ANC_ADAP_SYNC,
+ .task_name = "anc",
+ .func = bt_tws_anc_adap_sync,
+};
+
+void bt_tws_anc_adap_sync_send(int ref_lvl, int err_lvl, int msec)
+{
+ tws_api_sync_call_by_uuid(TWS_FUNC_ID_ANC_ADAP_SYNC, ((ref_lvl << 8) | err_lvl), msec);
+}
+
+#define TWS_FUNC_ID_ANC_ADAP_COMPARE_SYNC TWS_FUNC_ID('A', 'N', 'C', 'B')
+static void bt_tws_anc_adap_compare(void *_data, u16 len, bool rx)
+{
+ if (rx) {
+ u8 *data = (u8 *)_data;
+ /* r_printf("tws_anc_adap_compare: %d, %d\n", data[0], data[1]); */
+ audio_anc_adap_lvl_compare(data[0], data[1]);
+ }
+}
+
+REGISTER_TWS_FUNC_STUB(tws_anc_adap_compare) = {
+ .func_id = TWS_FUNC_ID_ANC_ADAP_COMPARE_SYNC,
+ .func = bt_tws_anc_adap_compare,
+};
+
+int bt_tws_anc_adap_compare_send(int ref_lvl, int err_lvl)
+{
+ u8 data[2];
+ int ret = -EINVAL;
+ data[0] = ref_lvl;
+ data[1] = err_lvl;
+ /* r_printf("tws_anc_adap_sync: %d, %d\n", data[0], data[1]); */
+ local_irq_disable();
+ ret = tws_api_send_data_to_sibling(data, 2, TWS_FUNC_ID_ANC_ADAP_COMPARE_SYNC);
+ local_irq_enable();
+ return ret;
+}
+#endif/*(defined ANC_ADAPTIVE_EN) && ANC_ADAPTIVE_EN*/
+
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+
+#if TCFG_AUDIO_HEARING_AID_ENABLE
+extern u8 get_hearing_aid_state(void);
+extern void hearing_aid_state_sync(u8 state);
+#define TWS_FUNC_ID_HEARING_AID_SYNC TWS_FUNC_ID('D', 'H', 'A', 'S')
+
+static void bt_tws_hearing_aid_sync(int dat, int err)
+{
+ hearing_aid_state_sync(dat);
+}
+
+TWS_SYNC_CALL_REGISTER(tws_hearing_aid_sync) = {
+ .uuid = TWS_FUNC_ID_HEARING_AID_SYNC,
+ .task_name = "app_core",
+ .func = bt_tws_hearing_aid_sync,
+};
+
+void bt_tws_hearing_aid_sync_send(void)
+{
+ int state = get_hearing_aid_state();
+ int msec = 400;
+ if (state) {
+ tws_api_sync_call_by_uuid(TWS_FUNC_ID_HEARING_AID_SYNC, state, msec);
+ }
+}
+#endif /*TCFG_AUDIO_HEARING_AID_ENABLE*/
+
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+#define TWS_FUNC_ID_SPATIAL_EFFECT_STATE_SYNC TWS_FUNC_ID('A', 'S', 'E', 'S')
+extern void a2dp_spatial_audio_setup(u8 en, u8 head_track);
+extern u8 get_spatial_audio_enable();
+extern u8 get_a2dp_spatial_audio_head_tracked(void);
+static void bt_tws_spatial_effect_state_sync(void *_data, u16 len, bool rx)
+{
+ if (rx) {
+ u8 *data = (u8 *)_data;
+ //r_printf("[slave]anc_sync: %d, %d\n", data[0], data[1]);
+ a2dp_spatial_audio_setup(data[0], data[1]);
+ }
+}
+
+REGISTER_TWS_FUNC_STUB(app_spatial_effect_state_sync_stub) = {
+ .func_id = TWS_FUNC_ID_SPATIAL_EFFECT_STATE_SYNC,
+ .func = bt_tws_spatial_effect_state_sync,
+};
+
+void bt_tws_sync_spatial_effect_state(void)
+{
+ u8 data[2];
+ data[0] = get_spatial_audio_enable();
+ data[1] = get_a2dp_spatial_audio_head_tracked();;
+ //r_printf("[master]anc_sync: %d, %d\n", data[0], data[1]);
+ tws_api_send_data_to_slave(data, 2, TWS_FUNC_ID_SPATIAL_EFFECT_STATE_SYNC);
+}
+#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
+
+void tws_conn_auto_test(void *p)
+{
+ cpu_reset();
+}
+
+
+
+
+/*
+ * tws事件状态处理函数
+ */
+int bt_tws_connction_status_event_handler(struct bt_event *evt)
+{
+ u8 addr[4][6];
+ int state;
+ int pair_suss = 0;
+ int role = evt->args[0];
+ int phone_link_connection = evt->args[1];
+ int reason = evt->args[2];
+ u16 random_num = 0;
+ char channel = 0;
+ u8 mac_addr[6];
+ int work_state = 0;
+ STATUS *p_tone = get_tone_config();
+ STATUS *p_led = get_led_config();
+
+ log_info("tws-user: role= %d, phone_link_connection %d, reason=%d,event= %d\n",
+ role, phone_link_connection, reason, evt->event);
+
+ switch (evt->event) {
+ case TWS_EVENT_CONNECTED:
+ log_info("tws_event_pair_suss: %x\n", gtws.state);
+
+ syscfg_read(CFG_TWS_REMOTE_ADDR, addr[0], 6);
+ syscfg_read(CFG_TWS_COMMON_ADDR, addr[1], 6);
+ tws_api_get_sibling_addr(addr[2]);
+ tws_api_get_local_addr(addr[3]);
+
+ /*
+ * 记录对方地址
+ */
+ if (memcmp(addr[0], addr[2], 6)) {
+ syscfg_write(CFG_TWS_REMOTE_ADDR, addr[2], 6);
+ pair_suss = 1;
+ log_info("rec tws addr\n");
+ }
+ if (memcmp(addr[1], addr[3], 6)) {
+ syscfg_write(CFG_TWS_COMMON_ADDR, addr[3], 6);
+ pair_suss = 1;
+ log_info("rec comm addr\n");
+ }
+
+
+ if (pair_suss) {
+
+ gtws.state = BT_TWS_PAIRED;
+ extern void bt_update_mac_addr(u8 * addr);
+ bt_update_mac_addr((void *)addr[3]);
+ }
+
+ /*
+ * 记录左右声道
+ */
+ channel = tws_api_get_local_channel();
+ if (channel != bt_tws_get_local_channel()) {
+ syscfg_write(CFG_TWS_CHANNEL, &channel, 1);
+ }
+ r_printf("tws_local_channel: %c\n", channel);
+
+ EARPHONE_STATE_TWS_CONNECTED(pair_suss, addr[3]);
+
+#if CONFIG_TWS_PAIR_MODE == CONFIG_TWS_PAIR_BY_AUTO
+ if (tws_auto_pair_enable) {
+ tws_auto_pair_enable = 0;
+ tws_le_acc_generation_init();
+ }
+#endif
+
+#ifdef CONFIG_NEW_BREDR_ENABLE
+ /* if (channel == 'L') { */
+ /* syscfg_read(CFG_TWS_LOCAL_ADDR, addr[2], 6); */
+ /* } */
+ u8 local_addr[6];
+ syscfg_read(CFG_TWS_LOCAL_ADDR, local_addr, 6);
+ for (int i = 0; i < 6; i++) {
+ addr[2][i] += local_addr[i];
+ }
+ tws_api_set_quick_connect_addr(addr[2]);
+#else
+ tws_api_set_connect_aa(channel);
+ tws_remote_state_clear();
+#endif
+ if (reason & (TWS_STA_ESCO_OPEN | TWS_STA_SBC_OPEN)) {
+ if (role == TWS_ROLE_SLAVE) {
+ gtws.state |= BT_TWS_AUDIO_PLAYING;
+ }
+ }
+
+ if (!phone_link_connection ||
+ (reason & (TWS_STA_ESCO_OPEN | TWS_STA_SBC_OPEN))) {
+ pwm_led_clk_set(PWM_LED_CLK_BTOSC_24M);
+ }
+ /*
+ * TWS连接成功, 主机尝试回连手机
+ */
+ if (gtws.connect_time) {
+ if (role == TWS_ROLE_MASTER) {
+ bt_user_priv_var.auto_connection_counter = gtws.connect_time;
+ }
+ gtws.connect_time = 0;
+ }
+
+ gtws.state &= ~BT_TWS_TIMEOUT;
+ gtws.state |= BT_TWS_SIBLING_CONNECTED;
+
+ state = evt->args[2];
+ if (role == TWS_ROLE_MASTER) {
+ if (!phone_link_connection) {
+ //还没连上手机
+ log_info("[SYNC] LED SYNC");
+ bt_tws_led_state_sync(SYNC_LED_STA_TWS_CONN, 400);
+ } else {
+ bt_tws_led_state_sync(SYNC_LED_STA_PHONE_CONN, 400);
+ }
+ if (!get_bt_tws_discon_dly_state() && (get_call_status() == BT_CALL_HANGUP) && !(state & TWS_STA_SBC_OPEN)) {
+ //通话状态不播提示音
+ log_info("[SYNC] TONE SYNC");
+ bt_tws_play_tone_at_same_time(SYNC_TONE_TWS_CONNECTED, 400);
+ }
+ if (get_call_status() == BT_CALL_INCOMING) {
+ if (bt_user_priv_var.phone_ring_flag && !bt_user_priv_var.inband_ringtone) {
+ printf("<<<<<<<<args[3];
+ log_info("tws_event_connection_detach: state: %x,%x\n", gtws.state, work_state);
+ pbg_user_set_tws_state(0);
+
+ app_power_set_tws_sibling_bat_level(0xff, 0xff);
+
+#if TCFG_CHARGESTORE_ENABLE
+ chargestore_set_sibling_chg_lev(0xff);
+#endif
+
+ if ((!a2dp_get_status()) && (get_call_status() == BT_CALL_HANGUP)) { //如果当前正在播歌,切回RC会导致下次从机开机回连后灯状态不同步
+ pwm_led_clk_set((!TCFG_LOWPOWER_BTOSC_DISABLE) ? PWM_LED_CLK_RC32K : PWM_LED_CLK_BTOSC_24M);
+ //pwm_led_clk_set(PWM_LED_CLK_RC32K);
+ }
+
+#if TCFG_TEST_BOX_ENABLE
+ if (testbox_get_status()) {
+ break;
+ }
+#endif
+#if TWS_DLY_DISCONN_TIME
+ if (work_state && reason == TWS_DETACH_BY_SUPER_TIMEOUT) {
+ gtws.tws_dly_discon_time = sys_timeout_add((void *)role, tws_disconn_dly_deal, TWS_DLY_DISCONN_TIME);
+ r_printf("gtws.tws_dly_discon_time=%d", gtws.tws_dly_discon_time);
+ }
+
+#endif
+
+ if (phone_link_connection) {
+ ui_update_status(STATUS_BT_CONN);
+ extern void power_event_to_user(u8 event);
+ power_event_to_user(POWER_EVENT_POWER_CHANGE);
+ user_send_cmd_prepare(USER_CTRL_HFP_CMD_UPDATE_BATTARY, 0, NULL); //对耳断开后如果手机还连着,主动推一次电量给手机
+ } else {
+ ui_update_status(STATUS_BT_TWS_DISCONN);
+ }
+
+ if ((gtws.state & BT_TWS_SIBLING_CONNECTED) && (!app_var.goto_poweroff_flag)) {
+#if CONFIG_TWS_POWEROFF_SAME_TIME
+ extern u8 poweroff_sametime_flag;
+ if (!app_var.goto_poweroff_flag && !poweroff_sametime_flag && !phone_link_connection && (reason != TWS_DETACH_BY_REMOVE_PAIRS)) { /*关机不播断开提示音*/
+ if (gtws.tws_dly_discon_time) {
+ gtws.state |= BT_TWS_DISCON_DLY_TIMEOUT;
+ if (work_state & TWS_STA_PHONE_CONNECTED) {
+ gtws.state |= BT_TWS_DISCON_DLY_TIMEOUT_NO_CONN;
+ }
+ } else {
+ tone_play_index(p_tone->tws_disconnect, 1);
+ }
+ }
+#else
+ if (!app_var.goto_poweroff_flag && !phone_link_connection && (reason != TWS_DETACH_BY_REMOVE_PAIRS)) {
+ if (gtws.tws_dly_discon_time) {
+ gtws.state |= BT_TWS_DISCON_DLY_TIMEOUT;
+ } else {
+ tone_play_index(p_tone->tws_disconnect, 1);
+ }
+ }
+#endif
+ gtws.state &= ~BT_TWS_SIBLING_CONNECTED;
+ }
+
+#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_FITTING_ENABLE)
+ /*辅听验配下,对耳断开连接时,主动告诉app当前连接左右耳机辅听状态*/
+ extern u8 get_rcsp_connect_status(void);
+ extern int get_hearing_aid_state_cmd_info(u8 * data);
+ extern u32 hearing_aid_rcsp_notify(u8 * data, u16 data_len);
+ extern void audio_dha_fitting_sync_close(void);
+ if (get_rcsp_connect_status()) {
+ /*主动推送辅听状态信息*/
+ u8 tmp[4];
+ get_hearing_aid_state_cmd_info(tmp);
+ /*TWS掉线,关闭验配*/
+ tmp[3] = 0;
+ hearing_aid_rcsp_notify(tmp, 4);
+ }
+ audio_dha_fitting_sync_close();
+#endif /*TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_FITTING_ENABLE*/
+
+ if (reason == TWS_DETACH_BY_REMOVE_PAIRS) {
+ gtws.state = BT_TWS_UNPAIRED;
+ printf("<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>\n");
+ break;
+ }
+
+ if (get_esco_coder_busy_flag()) {
+ tws_api_connect_in_esco();
+ break;
+ }
+
+ //非测试盒在仓测试,直连蓝牙
+ if (reason == TWS_DETACH_BY_TESTBOX_CON) {
+ puts(">>>>>>>>>>>>>>>>TWS_DETACH_BY_TESTBOX_CON<<<<<<<<<<<<<<<<<<<\n");
+ gtws.state &= ~BT_TWS_PAIRED;
+ gtws.state |= BT_TWS_UNPAIRED;
+ //syscfg_read(CFG_BT_MAC_ADDR, mac_addr, 6);
+ if (!phone_link_connection) {
+ get_random_number(mac_addr, 6);
+ lmp_hci_write_local_address(mac_addr);
+ bt_tws_wait_pair_and_phone_connect();
+ }
+ break;
+ }
+
+ if (phone_link_connection) {
+ bt_tws_wait_sibling_connect(0);
+ } else {
+ if (reason == TWS_DETACH_BY_SUPER_TIMEOUT) {
+ if (gtws.state & BT_TWS_REMOVE_PAIRS) {
+ bt_tws_remove_pairs();
+ break;
+ }
+ if (role == TWS_ROLE_SLAVE) {
+ gtws.state |= BT_TWS_TIMEOUT;
+ gtws.connect_time = bt_user_priv_var.auto_connection_counter;
+ bt_user_priv_var.auto_connection_counter = 0;
+ }
+ bt_tws_connect_sibling(6);
+ } else {
+ bt_tws_connect_and_connectable_switch();
+ }
+ }
+ break;
+ case TWS_EVENT_PHONE_LINK_DETACH:
+ /*
+ * 跟手机的链路LMP层已完全断开, 只有tws在连接状态才会收到此事件
+ */
+ printf("tws_event_phone_link_detach: %x\n", gtws.state);
+ if (app_var.goto_poweroff_flag) {
+ break;
+ }
+
+#if TCFG_TEST_BOX_ENABLE
+ if (testbox_get_status()) {
+ break;
+ }
+#endif
+
+ sys_auto_shut_down_enable();
+
+ if ((reason != 0x08) && (reason != 0x0b)) {
+ bt_user_priv_var.auto_connection_counter = 0;
+ } else {
+ if (reason == 0x0b) {
+ bt_user_priv_var.auto_connection_counter = (8 * 1000);
+ }
+ }
+
+ bt_tws_connect_and_connectable_switch();
+
+ tws_sniff_controle_check_enable();
+
+ break;
+ case TWS_EVENT_REMOVE_PAIRS:
+ log_info("tws_event_remove_pairs\n");
+ tone_play_index(p_tone->tws_disconnect, 1);
+ bt_tws_remove_pairs();
+ app_power_set_tws_sibling_bat_level(0xff, 0xff);
+#if TCFG_CHARGESTORE_ENABLE
+ chargestore_set_sibling_chg_lev(0xff);
+#endif
+ pwm_led_clk_set((!TCFG_LOWPOWER_BTOSC_DISABLE) ? PWM_LED_CLK_RC32K : PWM_LED_CLK_BTOSC_24M);
+ //pwm_led_clk_set(PWM_LED_CLK_RC32K);
+ //tone_play(TONE_TWS_DISCONN);
+ pbg_user_set_tws_state(0);
+ break;
+ case TWS_EVENT_SYNC_FUN_CMD:
+ log_d("TWS_EVENT_SYNC_FUN_CMD: %x\n", reason);
+ /*
+ * 主从同步调用函数处理
+ */
+ if (reason == SYNC_CMD_POWER_OFF_TOGETHER) {
+ extern void sys_enter_soft_poweroff(void *priv);
+ sys_enter_soft_poweroff((void *)3);
+ } else if (reason == SYNC_CMD_SHUT_DOWN_TIME) {
+ r_printf(" SYNC_CMD_SHUT_DOWN_TIME");
+ sys_auto_shut_down_disable();
+ sys_auto_shut_down_enable();
+ } else if (reason == SYNC_CMD_LOW_LATENCY_ENABLE) {
+ if (earphone_a2dp_codec_set_low_latency_mode(1, 600) == 0) {
+ tone_play(TONE_LOW_LATENCY_IN, 1);
+ }
+ } else if (reason == SYNC_CMD_LOW_LATENCY_DISABLE) {
+ if (earphone_a2dp_codec_set_low_latency_mode(0, 600) == 0) {
+ tone_play(TONE_LOW_LATENCY_OUT, 1);
+ }
+ } else if (reason == SYNC_CMD_EARPHONE_CHAREG_START) {
+ if (a2dp_get_status() != BT_MUSIC_STATUS_STARTING) {
+ g_printf("TWS MUSIC PLAY");
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PLAY, 0, NULL);
+ }
+ } else if (reason == SYNC_CMD_IRSENSOR_EVENT_NEAR) {
+ g_printf("TWS NEAR START MUSIC PLAY");
+ g_printf("a2dp_get_status = %d", a2dp_get_status());
+ if (a2dp_get_status() != BT_MUSIC_STATUS_STARTING) {
+ r_printf("START...\n");
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PLAY, 0, NULL);
+ }
+ } else if (reason == SYNC_CMD_IRSENSOR_EVENT_FAR) {
+ g_printf("TWS FAR STOP MUSIC PLAY");
+ g_printf("a2dp_get_status = %d", a2dp_get_status());
+ if (a2dp_get_status() == BT_MUSIC_STATUS_STARTING) {
+ r_printf("STOP...\n");
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PAUSE, 0, NULL);
+ }
+ }
+ break;
+ case TWS_EVENT_ROLE_SWITCH:
+ if (!(tws_api_get_tws_state() & TWS_STA_PHONE_CONNECTED)) {
+ bt_tws_connect_and_connectable_switch();
+ tws_sniff_controle_check_enable();
+ }
+ if (role == TWS_ROLE_MASTER) {
+
+ } else {
+
+ }
+ EARPHONE_STATE_ROLE_SWITCH(role);
+ break;
+ case TWS_EVENT_ESCO_ADD_CONNECT:
+ bt_tws_sync_volume();
+ break;
+
+ case TWS_EVENT_MODE_CHANGE:
+ log_info("TWS_EVENT_MODE_CHANGE : %d", evt->args[0]);
+ if (evt->args[0] == 0) {
+ if (0 == (tws_api_get_tws_state() & TWS_STA_PHONE_CONNECTED)) {
+ tws_sniff_controle_check_enable();
+ }
+ }
+ break;
+
+ case TWS_EVENT_TONE_TEST:
+ log_info("TWS_EVENT_TEST : %d", evt->args[0]);
+ int tone_play_index(u8 index, u8 preemption);
+ tone_play_index(evt->args[0], 1);
+ break;
+ }
+ return 0;
+}
+
+/*
+ * 提示音同步播放
+ */
+static void play_tone_at_same_time(int tone_name, int err)
+{
+ STATUS *p_tone = get_tone_config();
+ int state;
+
+ switch (tone_name) {
+#if TCFG_EAR_DETECT_ENABLE
+ case SYNC_TONE_EARDET_IN:
+ tone_play(TONE_EAR_CHECK, 1);
+ break;
+#endif
+ case SYNC_TONE_TWS_CONNECTED:
+#if TCFG_DEC2TWS_ENABLE
+ break;
+#endif
+ tone_play_index(p_tone->tws_connect_ok, 1);
+ break;
+ case SYNC_TONE_PHONE_CONNECTED:
+ if (err != -TWS_SYNC_CALL_RX) {
+ state = tws_api_get_tws_state();
+ if (state & (TWS_STA_SBC_OPEN | TWS_STA_ESCO_OPEN) ||
+ (get_call_status() != BT_CALL_HANGUP)) {
+ break;
+ }
+ tone_play_index(p_tone->bt_connect_ok, 1);
+ }
+ break;
+ case SYNC_TONE_PHONE_DISCONNECTED:
+ /* 关机不播断开提示音 */
+ if (!app_var.goto_poweroff_flag) {
+ tone_play_index(p_tone->bt_disconnect, 1);
+ }
+ ui_update_status(STATUS_BT_TWS_CONN);
+ break;
+ case SYNC_TONE_MAX_VOL:
+#if TCFG_MAX_VOL_PROMPT
+ if (p_tone->max_vol != IDEX_TONE_NONE) {
+ tone_play_index(p_tone->max_vol, 0);
+ } else {
+ /* tone_sin_play(150, 1); */
+ }
+#endif
+ break;
+ case SYNC_TONE_POWER_OFF:
+ y_printf("SYNC_TONE_POWER_OFF\n");
+ if (app_var.goto_poweroff_flag == 1) {
+ app_var.goto_poweroff_flag = 2;
+ tone_play_index(p_tone->power_off, 0);
+ }
+ bt_tws_poweroff();
+ break;
+ case SYNC_TONE_PHONE_NUM:
+ if (bt_user_priv_var.phone_con_sync_num_ring) {
+ break;
+ }
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ if (bt_user_priv_var.phone_timer_id) {
+ sys_timeout_del(bt_user_priv_var.phone_timer_id);
+ bt_user_priv_var.phone_timer_id = 0;
+ }
+ }
+ if (bt_user_priv_var.phone_ring_flag) {
+ phone_num_play_timer(NULL);
+ }
+ break;
+ case SYNC_TONE_PHONE_RING:
+ if (bt_user_priv_var.phone_ring_flag) {
+ if (bt_user_priv_var.phone_con_sync_ring) {
+ if (phone_ring_play_start()) {
+ bt_user_priv_var.phone_con_sync_ring = 0;
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ //播完一声来电铃声之后,关闭aec、msbc_dec之后再次同步播来电铃声
+ }
+ }
+ } else {
+ phone_ring_play_start();
+ }
+ }
+ break;
+ case SYNC_TONE_PHONE_NUM_RING:
+ if (bt_user_priv_var.phone_ring_flag) {
+ if (phone_ring_play_start()) {
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ //播完一声来电铃声之后,关闭aec、msbc_dec之后再次同步播来电铃声
+ bt_user_priv_var.phone_con_sync_ring = 0;
+ }
+ bt_user_priv_var.phone_con_sync_num_ring = 1;
+ }
+ }
+ break;
+#if TCFG_AUDIO_ANC_ENABLE
+ case SYNC_TONE_ANC_ON:
+ case SYNC_TONE_ANC_OFF:
+ case SYNC_TONE_ANC_TRANS:
+ anc_tone_sync_play(tone_name);
+ break;
+#endif
+#if TCFG_AUDIO_HEARING_AID_ENABLE
+ case SYNC_TONE_HEARING_AID_OPEN:
+ extern int audio_hearing_aid_open(void);
+ audio_hearing_aid_open();
+ break;
+#endif /*TCFG_AUDIO_HEARING_AID_ENABLE*/
+#if TCFG_AUDIO_HEARING_AID_ENABLE
+ case SYNC_TONE_DHA_FITTING_CLOSE:
+ extern int hearing_aid_fitting_start(u8 en);
+ extern u8 set_hearing_aid_fitting_state(u8 state);
+ hearing_aid_fitting_start(0);
+ set_hearing_aid_fitting_state(0);
+ break;
+#endif /*TCFG_AUDIO_HEARING_AID_ENABLE*/
+ }
+}
+
+TWS_SYNC_CALL_REGISTER(tws_tone_play) = {
+ .uuid = 0x123A9E50,
+ .task_name = "app_core",
+ .func = play_tone_at_same_time,
+};
+
+void bt_tws_play_tone_at_same_time(int tone_name, int msec)
+{
+ tws_api_sync_call_by_uuid(0x123A9E50, tone_name, msec);
+}
+
+/*
+ * LED状态同步
+ */
+static void led_state_sync_handler(int state, int err)
+{
+ switch (state) {
+ case SYNC_LED_STA_TWS_CONN:
+ pwm_led_mode_set(PWM_LED_ALL_OFF);
+ ui_update_status(STATUS_BT_TWS_CONN);
+ break;
+ case SYNC_LED_STA_PHONE_CONN:
+ if (err != -TWS_SYNC_CALL_RX) {
+ pwm_led_mode_set(PWM_LED_ALL_OFF);
+ ui_update_status(STATUS_BT_CONN);
+ }
+ break;
+ }
+}
+
+TWS_SYNC_CALL_REGISTER(tws_led_sync) = {
+ .uuid = 0x2A1E3095,
+ .task_name = "app_core",
+ .func = led_state_sync_handler,
+};
+
+void bt_tws_led_state_sync(int led_state, int msec)
+{
+ tws_api_sync_call_by_uuid(0x2A1E3095, led_state, msec);
+}
+
+
+void tws_cancle_all_noconn()
+{
+
+ bt_tws_delete_pair_timer();
+ tws_api_cancle_wait_pair();
+ tws_api_cancle_create_connection();
+ user_send_cmd_prepare(USER_CTRL_PAGE_CANCEL, 0, NULL);
+}
+
+
+bool get_tws_sibling_connect_state(void)
+{
+ if (gtws.state & BT_TWS_SIBLING_CONNECTED) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+bool get_tws_phone_connect_state(void)
+{
+ if (gtws.state & BT_TWS_PHONE_CONNECTED) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+
+#define TWS_SNIFF_CNT_TIME 5000 //ms
+
+static void bt_tws_enter_sniff(void *parm)
+{
+ gtws.sniff_timer = 0;
+ extern void tws_tx_sniff_req(void);
+ tws_tx_sniff_req();
+}
+
+void tws_sniff_controle_check_reset(void)
+{
+ if (gtws.sniff_timer) {
+ sys_timer_modify(gtws.sniff_timer, TWS_SNIFF_CNT_TIME);
+ }
+}
+
+void tws_sniff_controle_check_enable(void)
+{
+#if (CONFIG_BT_TWS_SNIFF == 0)
+ return;
+#endif
+
+ if (update_check_sniff_en() == 0) {
+ return;
+ }
+
+ if (gtws.sniff_timer == 0) {
+ gtws.sniff_timer = sys_timeout_add(NULL, bt_tws_enter_sniff, TWS_SNIFF_CNT_TIME);
+ }
+}
+
+void tws_sniff_controle_check_disable(void)
+{
+#if (CONFIG_BT_TWS_SNIFF == 0)
+ return;
+#endif
+
+ if (gtws.sniff_timer) {
+ sys_timeout_del(gtws.sniff_timer);
+ gtws.sniff_timer = 0;
+ }
+}
+
+extern int tws_in_sniff_state();
+extern void tws_link_check_for_ble_link_switch(void);
+static u16 ble_try_switch_timer;
+void tws_phone_ble_link_try_switch(void)
+{
+ //等待退出tws sniff
+ if (!tws_in_sniff_state()) {
+ //开始启动ble controller检查,满足切换条件进行链路切换;
+ tws_link_check_for_ble_link_switch();
+ sys_timeout_del(ble_try_switch_timer);
+ ble_try_switch_timer = 0;
+ }
+}
+
+extern void tws_tx_unsniff_req(void);
+void bt_tws_ble_link_switch(void)
+{
+#if CONFIG_BT_TWS_SNIFF
+ tws_sniff_controle_check_disable();
+ tws_tx_unsniff_req();
+ ble_try_switch_timer = sys_timer_add(NULL, tws_phone_ble_link_try_switch, 20);
+#endif
+
+}
+
+//未连接手机时的TWS主从切换
+void bt_tws_role_switch()
+{
+ if (!(gtws.state & BT_TWS_SIBLING_CONNECTED)) {
+ return;
+ }
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ return;
+ }
+ puts("bt_tws_role_switch\n");
+ bt_tws_delete_pair_timer();
+ tws_api_cancle_wait_pair();
+#if CONFIG_BT_TWS_SNIFF
+ tws_sniff_controle_check_disable();
+ tws_tx_unsniff_req();
+ for (int i = 0; i < 20; i++) {
+ if (!tws_in_sniff_state()) {
+ tws_api_role_switch();
+ break;
+ }
+ os_time_dly(4);
+ }
+#else
+ tws_api_role_switch();
+#endif
+}
+
+
+#endif
diff --git a/apps/earphone/default_event_handler.c b/apps/earphone/default_event_handler.c
new file mode 100644
index 0000000..263661e
--- /dev/null
+++ b/apps/earphone/default_event_handler.c
@@ -0,0 +1,373 @@
+#include "default_event_handler.h"
+#include "app_action.h"
+#include "bt_background.h"
+#include "earphone.h"
+#include "dev_manager/dev_manager.h"
+#include "app_config.h"
+#include "btstack/avctp_user.h"
+#include "bt_tws.h"
+#include "app_main.h"
+//#include "app_music.h"
+#include "key_event_deal.h"
+#include "asm/charge.h"
+#include "app_sd_music.h"
+#include "usb/otg.h"
+#include "update.h"
+
+#if (TCFG_APP_MUSIC_EN || TCFG_PC_ENABLE)
+#include "app_task.h"
+
+#if TCFG_DEC2TWS_ENABLE
+#include "audio_dec/audio_dec_file.h"
+#endif
+
+extern u8 key_table[KEY_NUM_MAX][KEY_EVENT_MAX];
+extern int pc_device_event_handler(struct sys_event *event);
+extern u32 timer_get_ms(void);
+extern u16 dev_update_check(char *logo);
+
+int switch_to_music_app(int action)
+{
+ struct intent it;
+
+ if (action == ACTION_MUSIC_MAIN) {
+ /* 卡不在线不切到music模式,
+ * 防止TWS之间所处的模式不同导致A2DP播歌不同步
+ */
+#if TCFG_DEV_MANAGER_ENABLE
+ if (!music_app_check()) {
+ return -ENODEV;
+ }
+#else
+ if (!dev_online("sd0")) {
+ return -ENODEV;
+ }
+#endif
+ }
+ init_intent(&it);
+ it.name = "music";
+ it.action = action;
+ return start_app(&it);
+}
+
+void switch_to_prev_app()
+{
+ struct intent it;
+
+ init_intent(&it);
+ it.action = ACTION_BACK;
+ start_app(&it);
+}
+
+void switch_to_earphone_app()
+{
+ struct intent it;
+
+ init_intent(&it);
+ it.action = ACTION_BACK;
+ start_app(&it);
+}
+
+void switch_to_pc_app()
+{
+ struct intent it;
+
+ /* 退出bt和music模式 */
+ if (bt_in_background()) {
+ init_intent(&it);
+ it.action = ACTION_BACK;
+ start_app(&it);
+ }
+ init_intent(&it);
+ it.action = ACTION_BACK;
+ start_app(&it);
+
+
+ /* 切到PC模式 */
+ init_intent(&it);
+ it.name = "pc";
+ it.action = ACTION_PC_MAIN;
+ start_app(&it);
+}
+
+static void sd_event_handler(struct device_event *evt)
+{
+ //add 设备的返回值, 0成功
+ int err = 0;
+ if (evt->event == DEVICE_EVENT_IN) {
+ if (app_var.have_mass_storage == 0) {
+ app_var.have_mass_storage = 1;
+ syscfg_write(CFG_HAVE_MASS_STORAGE, &app_var.have_mass_storage, 1);
+ }
+#if TCFG_DEC2TWS_ENABLE
+ if (bt_in_background()) {
+ switch_to_music_app(ACTION_MUSIC_MAIN);
+ }
+#elif TWFG_APP_POWERON_IGNORE_DEV
+ err = dev_manager_add((char *)evt->value);
+ if ((err == 0) && (!get_charge_online_flag()) && (usb_otg_online(0) != SLAVE_MODE)) { //充电状态只add设备,不切模式
+ ///检查设备升级
+ if (dev_update_check((char *)evt->value) == UPDATA_READY) {
+ return;
+ }
+#if TCFG_APP_MUSIC_EN
+ if ((timer_get_ms() - app_var.start_time) > TWFG_APP_POWERON_IGNORE_DEV) {
+ app_task_switch_to(APP_MUSIC_TASK, NULL_VALUE);
+ }
+#endif
+ }
+
+#else
+ err = dev_manager_add((char *)evt->value);
+ if ((err == 0) && (!get_charge_online_flag()) && (usb_otg_online(0) != SLAVE_MODE)) { //充电状态只add设备,不切模式
+ ///检查设备升级
+ if (dev_update_check((char *)evt->value) == UPDATA_READY) {
+ return;
+ }
+#if TCFG_APP_MUSIC_EN
+ app_task_switch_to(APP_MUSIC_TASK, NULL_VALUE);
+#endif
+ }
+#endif
+ } else if (evt->event == DEVICE_EVENT_OUT) {
+ update_clear_result();
+#if (!TCFG_DEC2TWS_ENABLE)
+ dev_manager_del((char *)evt->value);
+#endif
+ }
+}
+
+static int default_earphone_key_event_handler(struct sys_event *event)
+{
+ struct key_event *key = &event->u.key;
+ u8 key_event = key_table[key->value][key->event];
+
+ switch (key_event) {
+ case KEY_MODE_SWITCH:
+ puts("key_mode_switch\n");
+ app_task_switch_next();
+ break;
+ }
+
+ return false;
+}
+
+#if ((TCFG_APP_MUSIC_EN || TCFG_APP_PC_EN) && TCFG_DEC2TWS_ENABLE)
+void tws_loacl_media_channe_start(struct bt_event *evt)
+{
+ int role = tws_api_get_role();
+ int state = tws_api_get_tws_state();
+
+ if (role == TWS_ROLE_MASTER) {
+ if (state & TWS_STA_PHONE_CONNECTED) {
+ tws_conn_switch_role();
+ }
+ if (state & (TWS_STA_ESCO_OPEN | TWS_STA_SBC_OPEN)) {
+ return;
+ }
+ }
+
+ if (file_dec_get_source() == FILE_FROM_LOCAL) {
+ if (role == TWS_ROLE_MASTER) {
+ return;
+ }
+ app_music_exit();
+ }
+
+ switch_to_music_app(ACTION_MUSIC_TWS_RX);
+ tws_local_media_dec_open(evt->args[0], evt->args + 2);
+ sys_auto_shut_down_disable();
+}
+
+void tws_loacl_media_channe_stop(struct bt_event *evt)
+{
+ tws_local_media_dec_close(evt->args[0]);
+
+ sys_auto_shut_down_enable();
+
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_DISCONNECTED) {
+ struct application *app = get_current_app();
+ if (app && app->action != ACTION_PC_MAIN) {
+ bt_switch_to_foreground(ACTION_DO_NOTHING, 1);
+ }
+ }
+}
+
+static int default_tws_event_handler(struct bt_event *evt)
+{
+#if TCFG_DEC2TWS_ENABLE
+ int role = evt->args[0];
+ int phone_link_connection = evt->args[1];
+ int state = evt->args[2];
+
+ switch (evt->event) {
+ case TWS_EVENT_CONNECTED:
+ tws_api_auto_role_switch_disable();
+ if (state & (TWS_STA_ESCO_OPEN | TWS_STA_SBC_OPEN)) {
+ if (bt_in_background()) {
+ bt_switch_to_foreground(ACTION_DO_NOTHING, 1);
+ }
+ break;
+ }
+ if (file_dec_get_source() == FILE_FROM_LOCAL) {
+ send_local_media_dec_open_cmd();
+ } else {
+ if (role == TWS_ROLE_MASTER) {
+ if (switch_to_music_app(ACTION_MUSIC_MAIN) == 0) {
+ break;
+ }
+ }
+ if (bt_in_background()) {
+ bt_switch_to_foreground(ACTION_DO_NOTHING, 1);
+ }
+ }
+ break;
+ case TWS_EVENT_CONNECTION_TIMEOUT:
+ if (file_dec_get_source() == -EINVAL) {
+ switch_to_music_app(ACTION_MUSIC_MAIN);
+ }
+ break;
+ case TWS_EVENT_MONITOR_START:
+ if (role == TWS_ROLE_MASTER) {
+ if (!app_var.have_mass_storage || file_dec_get_source() == FILE_FROM_TWS) {
+ tws_conn_switch_role();
+ }
+ }
+ break;
+ case TWS_EVENT_CONNECTION_DETACH:
+ break;
+ case TWS_EVENT_DATA_TRANS_OPEN:
+ printf("TWS_EVENT_DATA_TRANS_OPEN: %d, %d\n", evt->args[0], evt->args[1]);
+ break;
+ case TWS_EVENT_DATA_TRANS_START:
+ printf("TWS_EVENT_DATA_TRANS_START: %d, %d\n", evt->args[0], evt->args[1]);
+ if (evt->args[1] == TWS_DTC_LOCAL_MEDIA) {
+ tws_loacl_media_channe_start(evt);
+ }
+ break;
+ case TWS_EVENT_DATA_TRANS_STOP:
+ printf("TWS_EVENT_DATA_TRANS_STOP: %d, %d\n", evt->args[0], evt->args[1]);
+ if (evt->args[1] == TWS_DTC_LOCAL_MEDIA) {
+ tws_loacl_media_channe_stop(evt);
+ }
+ break;
+ case TWS_EVENT_DATA_TRANS_CLOSE:
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+#endif
+}
+#endif/* #if ((TCFG_APP_MUSIC_EN || TCFG_APP_PC_EN) && TCFG_DEC2TWS_ENABLE) */
+
+void default_event_handler(struct sys_event *event)
+{
+ printf("@@@default_event_handler event->type = %d\n", event->type);
+ if (bt_in_background()) {
+ bt_in_background_event_handler(event);
+ }
+ switch (event->type) {
+ case SYS_KEY_EVENT:
+ if (!bt_in_background()) {
+ default_earphone_key_event_handler(event);
+ }
+ break;
+ case SYS_BT_EVENT:
+ if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) {
+ struct bt_event *bt = &event->u.bt;
+ if (bt->event == BT_STATUS_PHONE_HANGUP || (bt->event == BT_STATUS_VOICE_RECOGNITION && !bt->value)) {
+ r_printf("BT_STATUS_SCO_STATUS_CHANGE");
+ /* if (bt->value == 0xff) */
+ {
+ app_core_back_to_prev_app();
+ if (!app_core_back_to_prev_app_over_check()) {
+ app_task_switch_to(APP_BT_TASK, ACTION_DO_NOTHING);
+ }
+ }
+ }
+ }
+#if TCFG_USER_TWS_ENABLE && TCFG_DEC2TWS_ENABLE
+ else if (((u32)event->arg == SYS_BT_EVENT_FROM_TWS)) {
+ default_tws_event_handler(&event->u.bt);
+ }
+#endif
+ break;
+
+ case SYS_DEVICE_EVENT:
+ /* 系统设备事件处理 */
+#if (TCFG_ONLINE_ENABLE || TCFG_CFG_TOOL_ENABLE)
+ if ((u32)event->arg == DEVICE_EVENT_FROM_CFG_TOOL) {
+ extern int app_cfg_tool_event_handler(struct cfg_tool_event * cfg_tool_dev);
+ app_cfg_tool_event_handler(&event->u.cfg_tool);
+ break;
+ }
+#endif
+
+#if TCFG_APP_MUSIC_EN
+ if ((u32)event->arg == DRIVER_EVENT_FROM_SD0) {
+ sd_event_handler(&event->u.dev);
+ break;
+ }
+#endif
+
+#if TCFG_PC_ENABLE
+ int ret = pc_device_event_handler(event);
+ if (ret) {
+ if (event->u.dev.event == DEVICE_EVENT_IN) {
+ app_task_switch_to(APP_PC_TASK, NULL_VALUE);
+ }
+ }
+#endif
+ break;
+ default:
+ break;
+ }
+
+}
+
+#else
+
+void default_event_handler(struct sys_event *event)
+{
+ /*puts("default_event_handler\n");*/
+ struct intent it;
+ switch (event->type) {
+ case SYS_DEVICE_EVENT:
+ /* 系统设备事件处理 */
+#if TCFG_PC_ENABLE
+ extern int pc_device_event_handler(struct sys_event * event);
+ int ret = pc_device_event_handler(event);
+ if (ret) {
+ if (event->u.dev.event == DEVICE_EVENT_IN) {
+ /* 退出bt和music模式 */
+ if (bt_in_background()) {
+ init_intent(&it);
+ it.action = ACTION_BACK;
+ start_app(&it);
+ }
+ init_intent(&it);
+ it.action = ACTION_BACK;
+ start_app(&it);
+
+ /* 切到PC模式 */
+ init_intent(&it);
+ it.name = "pc";
+ it.action = ACTION_PC_MAIN;
+ start_app(&it);
+ } else {
+ cpu_reset();
+ }
+ }
+#endif
+ break;
+ default:
+ break;
+ }
+
+
+}
+
+#endif
+
diff --git a/apps/earphone/dual_update_demo.c b/apps/earphone/dual_update_demo.c
new file mode 100644
index 0000000..1625cc0
--- /dev/null
+++ b/apps/earphone/dual_update_demo.c
@@ -0,0 +1,479 @@
+#include "board_config.h"
+#include "system/includes.h"
+#include "asm/power_interface.h"
+#include "app_config.h"
+#include "dual_bank_updata_api.h"
+#include "update.h"
+#include "update_loader_download.h"
+#include "app_main.h"
+#include "event.h"
+#undef _DEBUG_H_
+#define LOG_TAG_CONST DUAL_OTA //修改成文件名
+#define LOG_TAG "[DUAL_OTA]"
+#include "debug.h"
+#define LOG_v(t) log_tag_const_v_ ## t
+#define LOG_i(t) log_tag_const_i_ ## t
+#define LOG_d(t) log_tag_const_d_ ## t
+#define LOG_w(t) log_tag_const_w_ ## t
+#define LOG_e(t) log_tag_const_e_ ## t
+#define LOG_c(t) log_tag_const_c_ ## t
+#define LOG_tag(tag, n) n(tag)
+const char LOG_tag(LOG_TAG_CONST,LOG_v) AT(.LOG_TAG_CONST) = 0;
+const char LOG_tag(LOG_TAG_CONST,LOG_i) AT(.LOG_TAG_CONST) = 1;
+const char LOG_tag(LOG_TAG_CONST,LOG_d) AT(.LOG_TAG_CONST) = 1; //log_debug
+const char LOG_tag(LOG_TAG_CONST,LOG_w) AT(.LOG_TAG_CONST) = 1;
+const char LOG_tag(LOG_TAG_CONST,LOG_e) AT(.LOG_TAG_CONST) = 1;
+const char LOG_tag(LOG_TAG_CONST,LOG_c) AT(.LOG_TAG_CONST) = 1;
+
+/*******************************************************************************
+ * #define CONFIG_DOUBLE_BANK_ENABLE 1
+ * #define CONFIG_FLASH_SIZE FLASH_SIZE_512K //配置FLASH大小
+ * #define CONFIG_DB_UPDATE_DATA_GENERATE_EN 1
+ * #define CONFIG_ONLY_GRENERATE_ALIGN_4K_CODE 1
+ *
+ * 检查isd_config.ini文件
+ * BR22_TWS_DB = YES; // dual bank flash framework enable
+ * FLASH_SIZE = 0x100000; // flash_size cfg
+ * BR22_TWS_VERSION = 0; // default fw version
+ * DB_UPDATE_DATA = YES; // generate db_update_data.bin
+ * FORCE_4K_ALIGN = YES; // force aligin with 4k bytes
+ * SPECIAL_OPT = 0; // only generate one flash.bin
+ *
+ * const int support_dual_bank_update_en = 1;
+ * const int support_vm_data_keep = 1;
+ *******************************************************************************/
+
+#define MAX_PACKET_LEN 4096//(512 * 8)//(512 * 4) //最大包长,至少512,最好4K,需要自行组包
+
+//0:CRC-16/XMODEM Standard 杰理默认的
+//1:客户自行选择crc16的算法类型,重定义 dual_ota_crc_calc()
+#define CRC_TYPE 1
+
+__attribute__((weak))
+u16 dual_ota_crc_calc(u8 *buf, u32 len, u16 init)
+{
+ log_debug("%s weak func", __func__);
+ //CRC16-XMODEM
+ u16 poly = 0x1021;
+ u16 crc = init;
+ while(len--){
+ u16 data = *buf++;
+ crc ^= data << 8; //逆序
+ for (u8 i = 0; i < 8; ++i){
+ crc = crc & 0x8000 ? (crc << 1) ^ poly : crc << 1; //逆序
+ }
+ }
+ return crc;
+}
+
+enum{
+ DUAL_OTA_NOTIFY_SUCCESS = 0,
+ DUAL_OTA_NOTIFY_FAIL,
+ DUAL_OTA_NOTIFY_CONTINUE,
+};
+typedef enum{
+ DUAL_OTA_STEP_START = 0,
+ DUAL_OTA_STEP_WRITE,
+ DUAL_OTA_STEP_VERIFY,
+}DUAL_OTA_STEP;
+typedef struct {
+ u32 file_size; // db_update_data.bin
+ u32 file_crc; // CRC_TYPE 的对应值
+ u32 max_pkt_len; // MAX_PACKET_LEN
+}dual_ota_info;
+static dual_ota_info ota_info;
+static u8 *bin_buf=NULL;//[MAX_PACKET_LEN];
+static DUAL_OTA_STEP dual_ota_step = DUAL_OTA_STEP_START;
+static int dual_ota_written_size = 0;
+static u8 dual_ota_idle = 1; // 置 1 可进睡眠, 置 0 不可进睡眠
+
+u8 usr_get_ota_status()
+{
+ return dual_ota_idle;
+}
+
+static u8 dual_ota_idle_query(void)
+{
+ if(dual_ota_idle){
+ return 1;
+ }else{
+ return 0;
+ }
+}
+REGISTER_LP_TARGET(dual_ota_lp_target) = {
+ .name = "dual_ota_lp",
+ .is_idle = dual_ota_idle_query,
+};
+static u32 read_32(u8 *p)
+{
+ return ((u32)(p[3]) << 24) | ((u32)(p[2]) << 16) | ((u32)(p[1]) << 8) | (p[0]);
+}
+
+extern void ram_protect_close(void);
+extern void hwi_all_close(void);
+static void dual_ota_fail_exit(void)
+{
+ log_info("%s[step:%d]", __func__, dual_ota_step);
+ if(bin_buf){
+ free(bin_buf);
+ bin_buf = NULL;
+ }
+ memset(&ota_info, 0x00, sizeof(ota_info));
+ dual_ota_step = DUAL_OTA_STEP_START;
+ dual_ota_written_size = 0;
+ dual_ota_idle = 0;
+}
+
+static void dual_ota_succ_exit(void)
+{
+ log_info("%s[step:%d]", __func__, dual_ota_step);
+ if(bin_buf){
+ free(bin_buf);
+ bin_buf = NULL;
+ }
+ memset(&ota_info, 0x00, sizeof(ota_info));
+ dual_ota_step = DUAL_OTA_STEP_START;
+ dual_ota_written_size = 0;
+ dual_ota_idle = 0;
+}
+
+enum {
+ OTA_START_UPDATE = 0,
+ OTA_START_UPDATE_READY,
+ OTA_START_VERIFY,
+ OTA_UPDATE_OVER,
+ OTA_UPDATE_ERR,
+ OTA_UPDATE_SUCC,
+};
+#include "update_tws_new.h"
+void usr_ota_event_post(u32 type, u8 event);
+static void dual_ota_cpu_reset(void)
+{
+ log_info("%s", __func__);
+ dual_ota_succ_exit();
+ usr_var.usr_ota_succ_flag=2;
+ //os_task_del("dw_update");
+ //update_result_set(UPDATA_SUCC);
+ //dual_bank_passive_update_exit(NULL);
+ //ram_protect_close();
+ //hwi_all_close();
+ //cpu_reset();
+ //sys_enter_soft_poweroff(NULL);
+ //wdt_init(WDT_256MS);
+ //while(1);
+ usr_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_OVER);
+}
+static void dual_ota_fail_cpu_reset(void)
+{
+ log_info("%s", __func__);
+ dual_ota_fail_exit();
+ usr_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_ERR);
+}
+
+void usr_ota_exit()
+{
+ sys_timeout_add(NULL, dual_ota_fail_cpu_reset, 300);
+}
+extern void ble_multi_trans_disconnect(void);
+
+static void dual_ota_success_reset(void)
+{
+ log_info("%s", __func__);
+ usr_var.usr_ota_succ_flag=1;
+ ble_multi_trans_disconnect();
+ sys_timeout_add(NULL, dual_ota_cpu_reset, 300);
+ /* 通知上位机升级完整,准备复位 */
+ //dual_ota_notify_msg_to_app(DUAL_OTA_NOTIFY_SUCCESS);
+}
+
+static void dual_ota_fail_reset(void)
+{
+ log_info("%s", __func__);
+ usr_var.usr_ota_succ_flag=3;
+ ble_multi_trans_disconnect();
+ dual_ota_fail_exit();
+ //sys_timeout_add(NULL, dual_ota_fail_cpu_reset, 300);
+ wdt_init(WDT_512MS);
+ while(1);
+ /* 通知上位机升级完整,准备复位 */
+ //dual_ota_notify_msg_to_app(DUAL_OTA_NOTIFY_SUCCESS);
+}
+
+static int dual_ota_boot_info_cb(int err)
+{
+ log_info("%s[err:%d]", __func__, err);
+ if (err == 0) {
+ dual_ota_success_reset();
+ } else {
+ dual_ota_fail_reset();
+ }
+ return 0;
+}
+extern int dual_bank_update_verify_without_crc(void); //0:success 1:fail
+static int dual_ota_verify_result(int res) //1:success 0:fail
+{
+ log_info("%s[res:%d %s]", __func__, res, res ? "success" : "fail");
+ if(res){
+ /* 校验成功 */
+ dual_bank_update_burn_boot_info(dual_ota_boot_info_cb);
+ } else{
+ /* 校验失败 */
+ usr_var.usr_ota_succ_flag=1;
+ flash_update_clr_boot_info(CLEAR_APP_UPDATE_BANK);
+ dual_ota_fail_reset();
+ }
+ return 0;
+}
+static void dual_ota_crc_init_cb(void)
+{
+ log_info("%s", __func__);
+}
+static u32 dual_ota_crc_calc_cb(u32 init_crc, u8 *data, u32 len)
+{
+ u32 crc16 = 0;
+ crc16 = dual_ota_crc_calc(data, len, init_crc);
+ log_debug("%s[init_crc:0x%x len:%d crc:0x%x]", __func__, init_crc, len, crc16);
+ return crc16;
+}
+static int dual_ota_update_verify(void)
+{
+ log_info("%s[file_crc:0x%x]", __func__, ota_info.file_crc);
+ clk_set("sys", 120 * 1000000L);
+ os_time_dly(1);
+
+ if(ota_info.file_crc){
+ if(CRC_TYPE){
+ dual_bank_update_verify(dual_ota_crc_init_cb, dual_ota_crc_calc_cb,
+ dual_ota_verify_result);
+ }else{
+ dual_bank_update_verify(NULL, NULL, dual_ota_verify_result);
+ }
+ }else{
+ int ret = dual_bank_update_verify_without_crc();
+ dual_ota_verify_result(ret ? 0 : 1);
+ }
+
+ return 0;
+}
+static int dual_ota_write_cb(void *priv)
+{
+ int ret = (int)priv;
+ if (ret) {
+ log_info("%s -> fail", __func__);
+ dual_ota_fail_reset();
+ return -1;
+ }else{
+ //log_info("%s -> success", __func__);
+ /* 通知上位机发送下一组数据 */
+ dual_ota_notify_msg_to_app(DUAL_OTA_NOTIFY_CONTINUE);
+ return 0;
+ }
+}
+static int dual_ota_update_init(u32 file_size, u32 file_crc, u32 pkt_len)
+{
+ log_info("%s[size:%d crc:0x%x ptk_len:%d]",__func__,file_size, file_crc, pkt_len);
+ if(bin_buf) return -1;
+ bin_buf = malloc(MAX_PACKET_LEN);
+ if(bin_buf == NULL) return -2;
+ if((u32)bin_buf % 4) {//4byte对齐
+ log_info("buf err !!!!!!!");
+ ASSERT(0, "%s: bin_buf addr unaligned !!!!", __func__);
+ }
+ memset(bin_buf, 0x00, MAX_PACKET_LEN);
+ int ret = 0;
+ ret = dual_bank_passive_update_init(file_crc, file_size, pkt_len, NULL);
+ if(ret == 0){
+ ret = dual_bank_update_allow_check(file_size);
+ if(ret == 0){
+ dual_ota_idle = 0;
+ dual_ota_written_size = 0;
+ ota_info.file_size = file_size;
+ ota_info.file_crc = file_crc;
+ ota_info.max_pkt_len = pkt_len;
+ /* 可以升级,需要通知上位机准备发包 */
+ dual_ota_notify_msg_to_app(DUAL_OTA_NOTIFY_CONTINUE);
+ }
+ }
+ log_info("%s[ret:%d]", __func__, ret);
+ if(ret){
+ dual_ota_fail_reset();
+ //dual_ota_fail_exit(); /* 无法升级 */
+ return -3;
+ }
+ return ret;
+}
+static int dual_ota_update_deal(u8 step, u8 *buf, u32 len) //升级流程处理
+{
+ int ret = 0;
+ int w_ret = 0xffff;
+ //log_info("%s[step:%d]", __func__, step);
+ switch(step){
+ case DUAL_OTA_STEP_START:
+ u32 *data = (u32 *)buf; //buf 地址需要aligned(4)
+ u32 file_size = data[0];
+ u32 file_crc = data[1];
+
+
+ /* update_mode_info_t info = {
+ .type = BLE_APP_UPDATA,
+ .state_cbk = NULL,
+ .p_op_api = NULL,
+ .task_en = 1,
+ };*/
+
+ //app_active_update_task_init(&info);
+ //os_time_dly(2);
+
+ ret = dual_ota_update_init(file_size, file_crc, MAX_PACKET_LEN);
+ break;
+ case DUAL_OTA_STEP_WRITE:
+ //OS_ENTER_CRITICAL();
+ w_ret=dual_bank_update_write(buf, len, dual_ota_write_cb);
+ dual_ota_written_size += len;
+ //printf("w_ret = %d written_size=%d\n",w_ret,dual_ota_written_size);
+ //OS_EXIT_CRITICAL();
+ break;
+ case DUAL_OTA_STEP_VERIFY:
+ dual_ota_update_verify();
+ break;
+ }
+ return ret;
+}
+
+/********************************************************************************
+ * 跟上位机通信接口
+ * 自行按照协议,自行修改,这个写法只是个demo
+ * 数据来源:串口、USB、BLE等
+ * 数据包很小,需要缓存成一包大包:MAX_PACKET_LEN,才能调用dual_bank_update_write
+ * MAX_PACKET_LEN 定义成 小包的整数倍 : MAX_PACKET_LEN == len * n
+ * 必须在低优先级任务执行,不能在中断函数、蓝牙回调函数执行
+ * https://gitee.com/Jieli-Tech/fw-AC63_BT_SDK/issues/I79ORW
+ *********************************************************************************/
+
+int dual_ota_app_data_deal(u32 msg, u8 *buf, u32 len)
+{
+ if((buf == NULL) || (len == 0)){
+ log_info("%s para is error", __func__);
+ return -1;
+ }
+ //log_info("%s[msg:%d len:%d]", __func__, msg, len);
+ /* log_debug_hexdump(buf, len); */
+ int ret = 0;
+ static u32 size = 0;
+ if(dual_ota_step == DUAL_OTA_STEP_WRITE){
+ //log_info("##### size = %d len = %d ota_info.max_pkt_len = %d\n",size,len,ota_info.max_pkt_len);
+ if((size < ota_info.max_pkt_len) && (size + len <= ota_info.max_pkt_len)){
+ memcpy(bin_buf + size, buf, len);
+ size += len;
+ }else{
+ log_info("%s size + len over MAX_PACKET_LEN", __func__);
+ }
+ if((size == ota_info.max_pkt_len)
+ ||(size + dual_ota_written_size >= ota_info.file_size))
+ {
+ if(size + dual_ota_written_size >= ota_info.file_size){
+ dual_ota_step = DUAL_OTA_STEP_VERIFY;
+ }
+ dual_ota_update_deal(DUAL_OTA_STEP_WRITE, bin_buf, size);
+ size = 0;
+ }
+ }else{
+ log_info("444444444444444");
+ if((buf[0] == 0x55) && (buf[1] == 0xAA)){
+ u32 data[2];
+ data[0] = read_32(buf + 2); //file_size
+ data[1] = read_32(buf + 6); //file_crc
+ flash_update_clr_boot_info(CLEAR_APP_UPDATE_BANK);
+ ret = dual_ota_update_deal(DUAL_OTA_STEP_START, (u8 *)data, sizeof(data));
+ if(ret == 0){
+ log_info("555555555555");
+ dual_ota_step = DUAL_OTA_STEP_WRITE;
+ }
+ }
+ if((buf[0] == 0xAA) && (buf[1] == 0x55)){
+ dual_ota_update_deal(DUAL_OTA_STEP_VERIFY, NULL, 0);
+ }
+ }
+ return ret;
+}
+
+extern int uart_tr_send_data(u8 *data, u32 len);
+/* int dual_ota_notify_msg_to_app(u32 msg, u8 *buf, u32 len) */
+int dual_ota_notify_msg_to_app(u32 msg)
+{
+ int ret = 0;
+ char * str = NULL;
+ //log_info("%s[msg:%d]", __func__, msg);
+ switch(msg)
+ {
+ case DUAL_OTA_NOTIFY_SUCCESS: //成功
+ str = "success\r\n";
+ log_info("#########3 DUAL_OTA_NOTIFY_SUCCESS");
+ break;
+ case DUAL_OTA_NOTIFY_FAIL: //失败
+ str = "fail\r\n";
+ log_info("#########3 DUAL_OTA_NOTIFY_FAIL");
+ break;
+ case DUAL_OTA_NOTIFY_CONTINUE: //上一组数据处理成功,继续下一组
+ str = "continue\r\n";
+// log_info("#########3 DUAL_OTA_NOTIFY_CONTINUE");
+ break;
+ }
+// uart_tr_send_data((u8 *)str, strlen(str));
+ return ret;
+}
+
+
+
+
+
+int bt_ota_event_handler(struct bt_event *bt)
+{
+ int ret = 0;
+ switch (bt->event) {
+ case OTA_START_UPDATE:
+ log_info("OTA_START_UPDATE\n");
+
+ break;
+
+ case OTA_UPDATE_OVER:
+ log_info("11OTA_UPDATE_OVER@##################3\n");
+// update_result_set(UPDATA_SUCC);
+// //os_time_dly(5);
+ dual_bank_passive_update_exit(NULL);
+ cpu_reset();
+ break;
+ case OTA_UPDATE_ERR:
+ log_info("111OTA_UPDATE_ERR@##################3\n");
+ dual_bank_passive_update_exit(NULL);
+ cpu_reset();
+ break;
+ /*case OTA_UPDATE_SUCC:
+ printf("OTA_UPDATE_SUCC\n");
+ update_result_set(UPDATA_SUCC);
+ dual_bank_passive_update_exit(NULL);
+ sys_enter_soft_poweroff((void *)1);
+ break;*/
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+void usr_ota_event_post(u32 type, u8 event)
+{
+ struct sys_event e;
+
+ log_info("usr_ota_event_post = %d\n",event);
+
+ e.type = SYS_BT_EVENT;
+ e.arg = (void *)type;
+ e.u.bt.event = event;
+ sys_event_notify(&e);
+}
+
+
+
+
diff --git a/apps/earphone/earphone.c b/apps/earphone/earphone.c
new file mode 100644
index 0000000..fe96fe1
--- /dev/null
+++ b/apps/earphone/earphone.c
@@ -0,0 +1,2770 @@
+#include "system/includes.h"
+#include "media/includes.h"
+#include "tone_player.h"
+#include "earphone.h"
+
+#include "app_config.h"
+#include "app_action.h"
+#include "app_task.h"
+
+#include "btstack/avctp_user.h"
+#include "btstack/btstack_task.h"
+#include "btctrler/btctrler_task.h"
+#include "btstack/frame_queque.h"
+#include "user_cfg.h"
+#include "aec_user.h"
+#include "classic/hci_lmp.h"
+#include "bt_common.h"
+#include "bt_ble.h"
+#include "bt_tws.h"
+#include "pbg_user.h"
+#include "btstack/bluetooth.h"
+
+#if TCFG_AUDIO_ANC_ENABLE
+#include "audio_anc.h"
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+
+#if TCFG_ANC_BOX_ENABLE
+#include "app_ancbox.h"
+#endif
+
+#if TCFG_USER_TWS_ENABLE
+#include "bt_tws.h"
+#endif
+
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+#include "spatial_imu_trim.h"
+#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
+
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV)
+#include "include/bt_ble.h"
+#endif
+
+#if TCFG_AUDIO_CVP_DUT_ENABLE
+#include "audio_cvp_dut.h"
+#endif /*TCFG_AUDIO_CVP_DUT_ENABLE*/
+
+
+//#include "jl_kws/jl_kws_api.h"
+
+#include "asm/charge.h"
+#include "app_charge.h"
+#include "ui_manage.h"
+
+//#include "app_chargestore.h"
+//#include "app_umidigi_chargestore.h"
+#include "app_testbox.h"
+#include "app_online_cfg.h"
+#include "app_main.h"
+#include "app_power_manage.h"
+#include "key_event_deal.h"
+#include "classic/tws_api.h"
+#include "asm/pwm_led.h"
+#include "vol_sync.h"
+#include "bt_background.h"
+#include "default_event_handler.h"
+
+#ifdef CONFIG_BOARD_AISPEECH_VAD_ASR
+extern int ais_platform_asr_open(void);
+extern void ais_platform_asr_close(void);
+#endif /*CONFIG_BOARD_AISPEECH_VAD_ASR*/
+
+#define LOG_TAG_CONST EARPHONE
+#define LOG_TAG "[EARPHONE]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+
+#define TIMEOUT_CONN_TIME 60 //超时断开之后回连的时间s
+#define POWERON_AUTO_CONN_TIME 12 //开机去回连的时间
+#define TWS_RETRY_CONN_TIMEOUT ((rand32() & BIT(0)) ? 200 : 400)
+#define PHONE_DLY_DISCONN_TIME 0//4000 //超时断开,快速连接上不播提示音
+
+extern void dac_analog_power_control(u8 en);
+extern u8 is_dac_power_off();
+extern u8 get_esco_coder_busy_flag();
+extern void dac_power_off(void);
+extern void bredr_fcc_init(u8 mode, u8 fre);
+extern void bredr_set_dut_enble(u8 en, u8 phone);
+extern int lmp_private_esco_suspend_resume(int flag);
+extern void tws_user_sync_call_vol();
+extern void ble_enter_single_carrier_mode(u8 ch_index);
+extern int music_player_get_play_status(void);
+
+/* extern void set_adjust_conn_dac_check(u8 value); */
+
+void sys_auto_shut_down_disable(void);
+extern void bt_pll_para(u32 osc, u32 sys, u8 low_power, u8 xosc);
+
+BT_USER_COMM_VAR bt_user_comm_var;
+BT_USER_PRIV_VAR bt_user_priv_var;
+
+int phone_call_begin(void *priv);
+int phone_call_end(void *priv);
+int earphone_a2dp_audio_codec_open(int media_type);
+void earphone_a2dp_audio_codec_close();
+u8 bt_audio_is_running(void);
+void tws_try_connect_disable(void);
+int lmp_private_esco_suspend_resume(int flag);
+
+u8 hci_standard_connect_check(void);
+void ble_adv_enable(u8 enable);
+int a2dp_dec_open(int media_type);
+int a2dp_dut_dec_open(int media_type);
+void a2dp_dec_close();
+int esco_dec_open(void *, u8);
+void esco_dec_close();
+void esco_enc_close();
+void __set_sbc_cap_bitpool(u8 sbc_cap_bitpoola);
+
+
+static u16 power_mode_timer = 0;
+
+u8 init_ok = 0;
+u8 get_bt_init_status(void)
+{
+ return init_ok;
+}
+
+static u8 sniff_out = 0;
+u8 get_sniff_out_status()
+{
+ return sniff_out;
+}
+void clear_sniff_out_status()
+{
+ sniff_out = 0;
+}
+
+void earphone_change_pwr_mode(int mode, int msec)
+{
+#if TCFG_POWER_MODE_QUIET_ENABLE
+ if (power_mode_timer) {
+ sys_timeout_del(power_mode_timer);
+ power_mode_timer = 0;
+ }
+ if (msec == 0) {
+ power_set_mode(mode);
+ } else {
+ power_mode_timer = sys_timeout_add((void *)mode, power_set_mode, msec);
+ }
+#endif
+}
+
+
+/*开关可发现可连接的函数接口*/
+void bt_wait_phone_connect_control(u8 enable)
+{
+#if TCFG_USER_TWS_ENABLE
+ return;
+#endif
+
+ if (enable && app_var.goto_poweroff_flag) {
+ return;
+ }
+
+ if (enable) {
+ log_info("is_1t2_connection:%d \t total_conn_dev:%d\n", is_1t2_connection(), get_total_connect_dev());
+ if (is_1t2_connection()) {
+ /*达到最大连接数,可发现(0)可连接(0)*/
+ user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_DISABLE, 0, NULL);
+ user_send_cmd_prepare(USER_CTRL_WRITE_CONN_DISABLE, 0, NULL);
+ } else {
+ if (get_total_connect_dev() == 1) {
+ /*支持连接2台,只连接一台的情况下,可发现(0)可连接(1)*/
+ user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_DISABLE, 0, NULL);
+ user_send_cmd_prepare(USER_CTRL_WRITE_CONN_ENABLE, 0, NULL);
+ } else {
+ /*可发现(1)可连接(1)*/
+ EARPHONE_STATE_SET_PAGE_SCAN_ENABLE();
+ user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_ENABLE, 0, NULL);
+ user_send_cmd_prepare(USER_CTRL_WRITE_CONN_ENABLE, 0, NULL);
+ }
+ }
+ } else {
+ user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_DISABLE, 0, NULL);
+ user_send_cmd_prepare(USER_CTRL_WRITE_CONN_DISABLE, 0, NULL);
+ }
+}
+
+void bt_send_keypress(u8 key)
+{
+ user_send_cmd_prepare(USER_CTRL_KEYPRESS, 1, &key);
+}
+
+void bt_send_pair(u8 en)
+{
+ user_send_cmd_prepare(USER_CTRL_PAIR, 1, &en);
+}
+
+void bt_init_ok_search_index(void)
+{
+ if (!bt_user_priv_var.auto_connection_counter && get_current_poweron_memory_search_index(bt_user_priv_var.auto_connection_addr)) {
+ log_info("bt_wait_connect_and_phone_connect_switch\n");
+ clear_current_poweron_memory_search_index(1);
+ bt_user_priv_var.auto_connection_counter = POWERON_AUTO_CONN_TIME * 1000; //8000ms
+ EARPHONE_STATE_GET_CONNECT_MAC_ADDR();
+ }
+}
+
+int bt_wait_connect_and_phone_connect_switch(void *p)
+{
+ int ret = 0;
+ int timeout = 0;
+ s32 wait_timeout;
+
+ if (bt_user_priv_var.auto_connection_counter <= 0) {
+ bt_user_priv_var.auto_connection_timer = 0;
+ bt_user_priv_var.auto_connection_counter = 0;
+
+ EARPHONE_STATE_CANCEL_PAGE_SCAN();
+
+ log_info("auto_connection_counter = 0\n");
+ user_send_cmd_prepare(USER_CTRL_PAGE_CANCEL, 0, NULL);
+
+ if (get_current_poweron_memory_search_index(NULL)) {
+ bt_init_ok_search_index();
+ return bt_wait_connect_and_phone_connect_switch(0);
+ } else {
+ bt_wait_phone_connect_control(1);
+ return 0;
+ }
+ }
+ /* log_info(">>>phone_connect_switch=%d\n",bt_user_priv_var.auto_connection_counter ); */
+ if ((int)p == 0) {
+ if (bt_user_priv_var.auto_connection_counter) {
+ timeout = 5600;
+ bt_wait_phone_connect_control(0);
+ user_send_cmd_prepare(USER_CTRL_START_CONNEC_VIA_ADDR, 6, bt_user_priv_var.auto_connection_addr);
+ ret = 1;
+ }
+ } else {
+ timeout = 400;
+ user_send_cmd_prepare(USER_CTRL_PAGE_CANCEL, 0, NULL);
+ bt_wait_phone_connect_control(1);
+ }
+ if (bt_user_priv_var.auto_connection_counter) {
+ bt_user_priv_var.auto_connection_counter -= timeout ;
+ log_info("do=%d\n", bt_user_priv_var.auto_connection_counter);
+ }
+ bt_user_priv_var.auto_connection_timer = sys_timeout_add((void *)(!(int)p),
+ bt_wait_connect_and_phone_connect_switch, timeout);
+
+ return ret;
+}
+
+void bt_close_page_scan(void *p)
+{
+ log_info(">>>%s\n", __func__);
+ bt_wait_phone_connect_control(0);
+ sys_timer_del(app_var.auto_stop_page_scan_timer);
+}
+
+
+extern bool get_esco_busy_flag();
+extern u8 get_cur_battery_level(void);
+extern void audio_adc_mic_demo(u8 mic_idx, u8 gain, u8 mic_2_dac);
+extern void audio_fast_mode_test();
+extern void audio_adc_mic_demo_close();
+static int bt_get_battery_value()
+{
+ //取消默认蓝牙定时发送电量给手机,需要更新电量给手机使用USER_CTRL_HFP_CMD_UPDATE_BATTARY命令
+ /*电量协议的是0-9个等级,请比例换算*/
+ return get_cur_battery_level();
+}
+
+void bt_fast_test_api(void)
+{
+ log_info("------------bt_fast_test_api---------\n");
+ //进入快速测试模式,用户根据此标志判断测试,如测试按键-开按键音 、测试mic-开扩音 、根据fast_test_mode根据改变led闪烁方式、关闭可发现可连接
+ if (bt_user_priv_var.fast_test_mode == 0) {
+ bt_user_priv_var.fast_test_mode = 1;
+ audio_fast_mode_test();
+ pwm_led_mode_set(PWM_LED_ALL_ON);
+ }
+}
+
+static void bt_dut_api(void)
+{
+ log_info("bt in dut \n");
+ sys_auto_shut_down_disable();
+#if TCFG_USER_TWS_ENABLE
+ extern void tws_cancle_all_noconn();
+ tws_cancle_all_noconn() ;
+#else
+ sys_timer_del(app_var.auto_stop_page_scan_timer);
+ extern void bredr_close_all_scan();
+ bredr_close_all_scan();
+#endif
+
+ if (bt_user_priv_var.auto_connection_timer) {
+ sys_timeout_del(bt_user_priv_var.auto_connection_timer);
+ bt_user_priv_var.auto_connection_timer = 0;
+ }
+
+#if TCFG_USER_BLE_ENABLE
+#if (CONFIG_BT_MODE == BT_NORMAL)
+ bt_ble_adv_enable(0);
+#endif
+#endif
+}
+
+void bit_clr_ie(unsigned char index);
+void bt_fix_fre_api(u8 fre)
+{
+ bt_dut_api();
+
+ bit_clr_ie(IRQ_BREDR_IDX);
+ bit_clr_ie(IRQ_BT_CLKN_IDX);
+
+ bredr_fcc_init(BT_FRE, fre);
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 蓝牙模式进入定频测试接收发射
+ @param mode :0 测试发射 1:测试接收
+ mac_addr:测试设置的地址
+ fre:定频的频点 0=2402 1=2403
+ packet_type:数据包类型
+
+ #define DH1_1 0
+ #define DH3_1 1
+ #define DH5_1 2
+ #define DH1_2 3
+ #define DH3_2 4
+ #define DH5_2 5
+
+ payload:数据包内容 0x0000 0x0055 0x00aa 0x00ff
+ 0xffff:prbs9
+ @return
+ @note 量产的时候通过串口,发送设置的参数,设置发送接收的参数
+
+ 关闭定频接收发射测试
+ void link_fix_txrx_disable();
+
+ 更新接收结果
+ void bt_updata_fix_rx_result()
+
+struct link_fix_rx_result {
+ u32 rx_err_b; //接收到err bit
+ u32 rx_sum_b; //接收到正确bit
+ u32 rx_perr_p; //接收到crc 错误 包数
+ u32 rx_herr_p; //接收到crc 以外其他错误包数
+ u32 rx_invail_p; //接收到crc错误bit太多的包数,丢弃不统计到err bit中
+};
+
+*/
+
+/*----------------------------------------------------------------------------*/
+void bt_fix_txrx_api(u8 mode, u8 *mac_addr, u8 fre, u8 packet_type, u16 payload)
+{
+ bt_dut_api();
+ local_irq_disable();
+ link_fix_txrx_disable();
+ if (mode) {
+ link_fix_rx_enable(mac_addr, fre, packet_type, 0xffff);
+ } else {
+ link_fix_tx_enable(mac_addr, fre, packet_type, 0xffff);
+ }
+ local_irq_enable();
+}
+
+
+void bt_updata_fix_rx_result()
+{
+ struct link_fix_rx_result fix_rx_result;
+ link_fix_rx_update_result(&fix_rx_result);
+ printf("err_b:%d sum_b:%d perr:%d herr_b:%d invaile:%d \n",
+ fix_rx_result.rx_err_b,
+ fix_rx_result.rx_sum_b,
+ fix_rx_result.rx_perr_p,
+ fix_rx_result.rx_herr_p,
+ fix_rx_result.rx_invail_p
+ );
+}
+#if (defined TCFG_USER_RSSI_TEST_EN && TCFG_USER_RSSI_TEST_EN)
+extern s8 get_rssi_api(s8 *phone_rssi, s8 *tws_rssi);
+static void spp_send_rssi(int slave_rssi)
+{
+ s8 send_buf[8];
+ send_buf[0] = 0xfe;
+ send_buf[1] = 0xdc;
+ send_buf[2] = 0x04;
+ send_buf[3] = 0x02;
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_local_channel() == 'L') {
+ get_rssi_api(&send_buf[4], &send_buf[6]);
+ send_buf[5] = (s8)slave_rssi;
+ } else
+#endif
+ {
+ get_rssi_api(&send_buf[5], &send_buf[6]);
+ send_buf[4] = (s8)slave_rssi;
+ }
+ send_buf[7] = 0xba;
+ user_send_cmd_prepare(USER_CTRL_SPP_SEND_DATA, sizeof(send_buf), send_buf);
+ /* put_buf(send_buf, sizeof(send_buf)); */
+ /* printf("get rssi, l:%d, r:%d, tws:%d", send_buf[4], send_buf[5], send_buf[6]); */
+}
+
+static void app_core_send_rssi(int slave_rssi)
+{
+ int msg[3];
+
+ msg[0] = spp_send_rssi;
+ msg[1] = 1;
+ msg[2] = slave_rssi;
+ os_taskq_post_type("app_core", Q_CALLBACK, 3, msg);
+}
+
+#if TCFG_USER_TWS_ENABLE
+#define TWS_FUNC_ID_RSSI_SYNC TWS_FUNC_ID('R', 'S', 'S', 'I')
+
+static void tws_get_rssi_handler(void *_data, u16 len, bool rx)
+{
+ u8 *data = (u8 *)_data;
+
+ if (rx) {
+ app_core_send_rssi(data[0]);
+ }
+}
+
+REGISTER_TWS_FUNC_STUB(tws_get_rssi) = {
+ .func_id = TWS_FUNC_ID_RSSI_SYNC,
+ .func = tws_get_rssi_handler,
+};
+#endif
+
+static int spp_get_rssi_handler(u8 *packet, u16 size)
+{
+ const u8 get_rssi_cmd[] = {0xfe, 0xdc, 0x01, 0x01, 0xba};
+ u8 send_cmd_buffer[2];
+ if (size == strlen(get_rssi_cmd) && !memcmp(packet, get_rssi_cmd, size)) {
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ get_rssi_api(&send_cmd_buffer[0], &send_cmd_buffer[1]);
+ tws_api_send_data_to_sibling(send_cmd_buffer, sizeof(send_cmd_buffer), TWS_FUNC_ID_RSSI_SYNC);
+ }
+ } else
+#endif
+ {
+ app_core_send_rssi(-127);
+ }
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+
+void spp_data_handler(u8 packet_type, u16 ch, u8 *packet, u16 size)
+{
+ switch (packet_type) {
+ case 1:
+ log_info("spp connect\n");
+ break;
+ case 2:
+ log_info("spp disconnect\n");
+ break;
+ case 7:
+ //log_info("spp_rx:");
+ //put_buf(packet,size);
+#if AEC_DEBUG_ONLINE
+ aec_debug_online(packet, size);
+#endif
+
+#if (defined TCFG_USER_RSSI_TEST_EN && TCFG_USER_RSSI_TEST_EN)
+ spp_get_rssi_handler(packet, size);
+#endif
+ break;
+ }
+}
+
+extern const char *sdk_version_info_get(void);
+static u8 *bt_get_sdk_ver_info(u8 *len)
+{
+ char *p = sdk_version_info_get();
+ if (len) {
+ *len = strlen(p);
+ }
+
+ log_info("sdk_ver:%s %x\n", p, *len);
+ return (u8 *)p;
+}
+
+extern void bt_set_tx_power(u8 txpower);
+extern void __set_aac_bitrate(u32 bitrate);
+extern void user_spp_data_handler(u8 packet_type, u16 ch, u8 *packet, u16 size);
+extern void online_spp_init(void);
+extern u16 get_vbat_value(void);
+extern u8 get_vbat_percent(void);
+extern u8 *sdfile_get_burn_code(u8 *len);
+
+void bredr_handle_register()
+{
+#if (USER_SUPPORT_PROFILE_SPP==1)
+#if APP_ONLINE_DEBUG
+ spp_data_deal_handle_register(user_spp_data_handler);
+ online_spp_init();
+#else
+ spp_data_deal_handle_register(spp_data_handler);
+#endif
+#endif
+ bt_fast_test_handle_register(bt_fast_test_api);//测试盒快速测试接口
+#if BT_SUPPORT_MUSIC_VOL_SYNC
+ music_vol_change_handle_register(set_music_device_volume, phone_get_device_vol);
+#endif
+#if BT_SUPPORT_DISPLAY_BAT
+ get_battery_value_register(bt_get_battery_value); /*电量显示获取电量的接口*/
+#endif
+
+ bt_dut_test_handle_register(bt_dut_api);
+}
+u8 usr_mac_addr[6];
+extern void __set_support_ldac_flag(bool flag);
+extern void lib_make_ble_address(u8 *ble_address, u8 *edr_address);
+extern int le_controller_set_mac(void *addr);
+void bt_function_select_init()
+{
+
+ /* #if TCFG_LOWEST_POWER_EN */
+ void set_qos_value(u8 qos_on_value, u8 qos_off_value);
+ void set_pure_monitor_eanble_qos(u8 en);
+ /* set_pure_monitor_eanble_qos(1); */
+ /* set_qos_value(5, 15); */
+ /* #endif */
+ /* set_bt_data_rate_acl_3mbs_mode(1); */
+ if (CONFIG_WIFI_DETECT_ENABLE) {
+ set_bt_afh_classs_enc(1);//report 手机用wifi_detect的频点,不设置用回手机
+ }
+ __set_user_ctrl_conn_num(TCFG_BD_NUM);
+#ifdef CONFIG_CPU_BR21
+ __set_support_msbc_flag(0);
+#else
+ __set_support_msbc_flag(1);
+#endif
+
+ __set_aac_bitrate(131 * 1000);
+#if TCFG_BT_SUPPORT_AAC && (!CONFIG_A2DP_GAME_MODE_ENABLE)
+ /* #if TCFG_BT_SUPPORT_AAC */
+ __set_support_aac_flag(1);
+#else
+ __set_support_aac_flag(0);
+#endif
+#if TCFG_BT_SUPPORT_LDAC && (!CONFIG_A2DP_GAME_MODE_ENABLE)
+ __set_support_ldac_flag(1);
+ __set_a2dp_ldac_sampling_freq(LDAC_SAMPLING_FREQ_44100 | LDAC_SAMPLING_FREQ_48000 | LDAC_SAMPLING_FREQ_88200 | LDAC_SAMPLING_FREQ_96000); /* 设置ldac支持采样率,0x20//44.1KHZ,0x10//48KHZ,0x08//88.1KHZ,0x04//96KHZ */
+#else
+ __set_support_ldac_flag(0);
+#endif
+#if BT_SUPPORT_DISPLAY_BAT
+ __bt_set_update_battery_time(60);
+#else
+ __bt_set_update_battery_time(0);
+#endif
+ __set_page_timeout_value(8000); /*回连搜索时间长度设置,可使用该函数注册使用,ms单位,u16*/
+ __set_super_timeout_value(8000); /*回连时超时参数设置。ms单位。做主机有效*/
+#if (TCFG_BD_NUM == 2)
+ __set_auto_conn_device_num(2);
+#endif
+#if BT_SUPPORT_MUSIC_VOL_SYNC
+ vol_sys_tab_init();
+#endif
+ //io_capabilities ; /*0: Display only 1: Display YesNo 2: KeyboardOnly 3: NoInputNoOutput*/
+ //authentication_requirements: 0:not protect 1 :protect
+ __set_simple_pair_param(3, 0, 2);
+ bt_testbox_ex_info_get_handle_register(TESTBOX_INFO_VBAT_VALUE, get_vbat_value);
+ bt_testbox_ex_info_get_handle_register(TESTBOX_INFO_VBAT_PERCENT, get_vbat_percent);
+ bt_testbox_ex_info_get_handle_register(TESTBOX_INFO_BURN_CODE, sdfile_get_burn_code);
+ bt_testbox_ex_info_get_handle_register(TESTBOX_INFO_SDK_VERSION, bt_get_sdk_ver_info);
+
+#if TCFG_USER_BLE_ENABLE
+ {
+ u8 tmp_ble_addr[6];
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV)
+ /* bt_set_tx_power(9);//ble txpwer level:0~9 */
+ memcpy(tmp_ble_addr, (void *)bt_get_mac_addr(), 6);
+#else
+ lib_make_ble_address(tmp_ble_addr, (void *)bt_get_mac_addr());
+#endif //
+ le_controller_set_mac((void *)tmp_ble_addr);
+ printf("\n-----edr + ble 's address-----");
+ printf_buf((void *)bt_get_mac_addr(), 6);
+ printf_buf((void *)tmp_ble_addr, 6);
+ memcpy(usr_mac_addr,tmp_ble_addr,6);
+ }
+#endif // TCFG_USER_BLE_ENABLE
+
+ /* #if (CONFIG_BT_MODE != BT_NORMAL) */
+ set_bt_enhanced_power_control(1);
+ /* #endif */
+//#endif
+#if (TCFG_USER_TWS_ENABLE==0)
+ extern void set_g_need_inc_power(u8 en);
+ set_g_need_inc_power(1);
+#endif
+}
+
+void phone_sync_vol(void)
+{
+ user_send_cmd_prepare(USER_CTRL_HFP_CALL_SET_VOLUME, 1, &bt_user_priv_var.phone_vol);
+}
+
+/*配置通话时前面丢掉的数据包包数*/
+#define ESCO_DUMP_PACKET_ADJUST 1 /*配置使能*/
+#define ESCO_DUMP_PACKET_DEFAULT 0
+#ifdef CONFIG_NEW_BREDR_ENABLE
+#define ESCO_DUMP_PACKET_CALL 60 /*0~0xFF*/
+#else
+#define ESCO_DUMP_PACKET_CALL 120 /*0~0xFF*/
+#endif
+
+static u8 esco_dump_packet = ESCO_DUMP_PACKET_CALL;
+#if ESCO_DUMP_PACKET_ADJUST
+u8 get_esco_packet_dump(void)
+{
+ //log_info("esco_dump_packet:%d\n", esco_dump_packet);
+ return esco_dump_packet;
+}
+#endif
+
+/*
+ * app模式切换
+ */
+void task_switch(const char *name, int action)
+{
+ struct intent it;
+ struct application *app;
+
+ log_info("app_exit\n");
+
+ init_intent(&it);
+ app = get_current_app();
+ if (app) {
+ /*
+ * 退出当前app, 会执行state_machine()函数中APP_STA_STOP 和 APP_STA_DESTORY
+ */
+ it.name = app->name;
+ it.action = ACTION_BACK;
+ start_app(&it);
+ }
+
+ /*
+ * 切换到app (name)并执行action分支
+ */
+ it.name = name;
+ it.action = action;
+ start_app(&it);
+}
+
+#if(USE_DMA_UART_TEST) //使用dm串口测试时不能同时打开
+#define MY_SNIFF_EN 0
+#else
+#define MY_SNIFF_EN 0 //默认打开
+#endif
+///Jim
+/*
+ *以下情况,关闭sniff
+ *(1)通过spp在线调试eq
+ *(2)通过spp导出数据
+ */
+#if APP_ONLINE_DEBUG
+#if (TCFG_EQ_ONLINE_ENABLE || (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SPP) || TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE)
+#undef MY_SNIFF_EN
+#define MY_SNIFF_EN 0
+#endif
+#endif/*APP_ONLINE_DEBUG*/
+
+#define SNIFF_CNT_TIME 10/////<空闲10S之后进入sniff模式
+
+#define SNIFF_MAX_INTERVALSLOT 800
+#define SNIFF_MIN_INTERVALSLOT 100
+#define SNIFF_ATTEMPT_SLOT 4
+#define SNIFF_TIMEOUT_SLOT 1
+
+u8 sniff_ready_status = 0; //0:sniff_ready 1:sniff_not_ready
+int exit_sniff_timer = 0;
+
+bool bt_is_sniff_close(void)
+{
+ return (bt_user_priv_var.sniff_timer == 0);
+}
+
+void bt_check_exit_sniff()
+{
+ sys_timeout_del(exit_sniff_timer);
+ exit_sniff_timer = 0;
+
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ return;
+ }
+#endif
+ user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL);
+}
+
+void bt_sniff_ready_clean(void)
+{
+ sniff_ready_status = 1;
+}
+
+static u8 bt_sniff_enable = 1;
+void bt_check_enter_sniff()
+{
+ struct sniff_ctrl_config_t sniff_ctrl_config;
+ u8 addr[12];
+ u8 conn_cnt = 0;
+ u8 i = 0;
+
+ if (!bt_sniff_enable) {
+ return;
+ }
+
+#if TCFG_AUDIO_ANC_ENABLE
+ if (anc_train_open_query() || anc_online_busy_get()) { //如果ANC训练则不进入SNIFF
+ return;
+ }
+#endif
+#if (RCSP_ADV_EN)
+ extern u8 get_ble_adv_modify(void);
+ extern u8 get_ble_adv_notify(void);
+ // if (get_ble_adv_modify() || get_ble_adv_notify()) {
+ // return;
+ // }
+#endif
+ if (sniff_ready_status) {
+ sniff_ready_status = 0;
+ return;
+ }
+ /*putchar('H');*/
+ conn_cnt = bt_api_enter_sniff_status_check(SNIFF_CNT_TIME, addr);
+
+#if (TCFG_BD_NUM == 2)
+ /* if (BT_STATUS_PLAYING_MUSIC == get_bt_connect_status() || get_esco_coder_busy_flag()) { */
+ if (get_esco_coder_busy_flag()) {
+ return;
+ }
+#endif
+ ASSERT(conn_cnt <= 2);
+
+ for (i = 0; i < conn_cnt; i++) {
+ log_info("-----USER SEND SNIFF IN %d %d\n", i, conn_cnt);
+ sniff_ctrl_config.sniff_max_interval = SNIFF_MAX_INTERVALSLOT;
+ sniff_ctrl_config.sniff_mix_interval = SNIFF_MIN_INTERVALSLOT;
+ sniff_ctrl_config.sniff_attemp = SNIFF_ATTEMPT_SLOT;
+ sniff_ctrl_config.sniff_timeout = SNIFF_TIMEOUT_SLOT;
+ memcpy(sniff_ctrl_config.sniff_addr, addr + i * 6, 6);
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ return;
+ }
+#endif
+ user_send_cmd_prepare(USER_CTRL_SNIFF_IN, sizeof(struct sniff_ctrl_config_t), (u8 *)&sniff_ctrl_config);
+ }
+
+}
+void sys_auto_sniff_controle(u8 enable, u8 *addr)
+{
+ if (app_var.goto_poweroff_flag) {
+ return;
+ }
+log_info("sniff ctr not change\n");
+ if (addr) {
+ if (bt_api_conn_mode_check(enable, addr) == 0) {
+ log_info("sniff ctr not change\n");
+ return;
+ }
+ }
+
+ if (enable) {
+ if (addr) {
+ log_info("sniff cmd timer init\n");
+ user_send_cmd_prepare(USER_CTRL_HALF_SEC_LOOP_CREATE, 0, NULL);
+ /* user_cmd_timer_init(); */
+ }
+
+ if (bt_user_priv_var.sniff_timer == 0) {
+ log_info("check_sniff_enable\n");
+ bt_user_priv_var.sniff_timer = sys_timer_add(NULL, bt_check_enter_sniff, 1000);
+ }
+ EARPHONE_STATE_SNIFF(0);
+ } else {
+
+ if (addr) {
+ log_info("sniff cmd timer remove\n");
+ user_send_cmd_prepare(USER_CTRL_HALF_SEC_LOOP_DEL, 0, NULL);
+ /* remove_user_cmd_timer(); */
+ }
+
+ if (bt_user_priv_var.sniff_timer) {
+ log_info("check_sniff_disable\n");
+ sys_timeout_del(bt_user_priv_var.sniff_timer);
+ bt_user_priv_var.sniff_timer = 0;
+
+ if (exit_sniff_timer == 0) {
+ /* exit_sniff_timer = sys_timer_add(NULL, bt_check_exit_sniff, 5000); */
+ }
+ }
+ EARPHONE_STATE_SNIFF(1);
+ }
+}
+
+u8 lmp_rx_sniff_req_check()
+{
+ return !bt_sniff_enable;
+}
+
+extern void tws_tx_unsniff_req(void);
+void bt_sniff_set_enable(u8 en)
+{
+ bt_sniff_enable = en;
+
+ if (en) {
+ sys_auto_sniff_controle(1, NULL);
+ tws_sniff_controle_check_enable();
+ } else {
+#if TCFG_USER_TWS_ENABLE
+ if (get_tws_phone_connect_state() == TRUE) {
+ user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL);
+ } else {
+ tws_tx_unsniff_req();
+ }
+ tws_sniff_controle_check_disable();
+#else
+ user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL);
+#endif
+ sys_auto_sniff_controle(0, NULL);
+ }
+}
+
+void bt_sniff_feature_init()
+{
+#if TCFG_BT_SNIFF_DISABLE
+ u8 feature = lmp_hci_read_local_supported_features(0);
+ feature &= ~BIT(7); //BIT_SNIFF_MODE;
+ lmp_hci_write_local_supported_features(feature, 0);
+#endif
+}
+
+int btstack_exit();
+
+void wait_exit_btstack_flag(void *priv)
+{
+ if (!bt_audio_is_running()) {
+ //btstack_exit();
+ lmp_hci_reset();
+ os_time_dly(2);
+ sys_timer_del(app_var.wait_exit_timer);
+ if (priv == NULL) {
+ log_info("task_switch to idle...\n");
+ task_switch("idle", ACTION_IDLE_MAIN);
+ } else if (priv == (void *)1) {
+ log_info("cpu_reset!!!\n");
+ cpu_reset();
+ }
+
+ } else {
+ app_var.goto_poweroff_cnt++;
+ if (app_var.goto_poweroff_cnt > 200) {
+ log_info("audio:%d, status:%d, hci:%d\n",
+ bt_audio_is_running(),
+ get_curr_channel_state(),
+ hci_standard_connect_check());
+ log_info("mabe ..... death!\n");
+ log_info("cpu_reset!!!\n");
+ cpu_reset();
+ }
+ }
+}
+
+#if TCFG_USER_TWS_ENABLE
+static void power_off_at_same_time(void *p)
+{
+
+ if (!bt_audio_is_running()) {
+ int state = tws_api_get_tws_state();
+ log_info("wait_phone_link_detach: %x\n", state);
+ if (state & TWS_STA_PHONE_DISCONNECTED) {
+ if (state & TWS_STA_SIBLING_CONNECTED) {
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ bt_tws_play_tone_at_same_time(SYNC_TONE_POWER_OFF, 400);
+ } else {
+ /* 防止TWS异常断开导致从耳不关机 */
+ bt_tws_play_tone_at_same_time(SYNC_TONE_POWER_OFF, 2400);
+ }
+ sys_timer_del(app_var.wait_exit_timer);
+ task_switch("idle", ACTION_IDLE_POWER_OFF);
+ } else {
+ sys_timer_del(app_var.wait_exit_timer);
+ task_switch("idle", ACTION_IDLE_MAIN);
+ }
+ } else {
+ lmp_hci_reset();
+ os_time_dly(2);
+ }
+ } else {
+ app_var.goto_poweroff_cnt++;
+ if (app_var.goto_poweroff_cnt > 200) {
+ log_info("audio:%d, status:%d, hci:%d\n",
+ bt_audio_is_running(),
+ get_curr_channel_state(),
+ hci_standard_connect_check());
+ log_info("mabe ..... death!\n");
+ log_info("cpu_reset!!!\n");
+ cpu_reset();
+ }
+ }
+}
+#endif
+
+extern int tws_sniff_state_check();
+void poweroff_sniff_all_exit()
+{
+ u8 exit_cnt = 0;
+ sys_auto_sniff_controle(0, NULL);
+#if TCFG_USER_TWS_ENABLE
+ log_info("%s %d %d %d %d\n", __func__, get_tws_phone_connect_state(), get_tws_sibling_connect_state(), bt_api_get_sniff_state(), tws_sniff_state_check());
+ if (get_tws_phone_connect_state()) {
+ while (bt_api_get_sniff_state() || tws_sniff_state_check()) { //wait lmp and tws_sniff exit
+ if (exit_cnt % 5 == 0) {
+ user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL); //lmp_sniff exit then tws_sniff will exit
+ }
+ if (exit_cnt ++ >= 25) {
+ exit_cnt = 0;
+ break;
+ }
+ os_time_dly(10); //500ms * 5
+ }
+ } else if (get_tws_sibling_connect_state()) { //if only tws connect
+ while (tws_sniff_state_check()) {
+ if (exit_cnt % 5 == 0) {
+ tws_tx_unsniff_req();
+ }
+ if (exit_cnt ++ >= 25) {
+ exit_cnt = 0;
+ break;
+ }
+ os_time_dly(10); //500ms * 5
+ }
+ }
+ log_info("%s %d %d %d %d\n", __func__, get_tws_phone_connect_state(), get_tws_sibling_connect_state(), bt_api_get_sniff_state(), tws_sniff_state_check());
+#else
+ while (bt_api_get_sniff_state()) { //wait lmp and tws_sniff exit
+ if (exit_cnt % 5 == 0) {
+ user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL); //lmp_sniff exit then tws_sniff will exit
+ }
+ if (exit_cnt ++ >= 25) {
+ exit_cnt = 0;
+ break;
+ }
+ os_time_dly(10); //500ms * 5
+ }
+#endif /*TCFG_USER_TWS_ENABLE*/
+}
+
+
+void sys_enter_soft_poweroff(void *priv)
+{
+ int detach_phone = 1;
+ struct sys_event clear_key_event = {.type = SYS_KEY_EVENT, .arg = "key"};
+ log_info("%s, %d\n", __func__, (int)priv);
+
+ if (app_var.goto_poweroff_flag) {
+ return;
+ }
+
+ if ((int)priv != 4) {
+#if CONFIG_BT_BACKGROUND_ENABLE
+ bt_switch_to_foreground(ACTION_DO_NOTHING, 1);
+#endif
+ ui_update_status(STATUS_POWEROFF);
+ }
+
+ sys_auto_sniff_controle(0, NULL);
+ app_var.goto_poweroff_flag = 1;
+ app_var.goto_poweroff_cnt = 0;
+ sys_key_event_disable();
+ sys_event_clear(&clear_key_event);
+ sys_auto_shut_down_disable();
+
+ poweroff_sniff_all_exit(); //确保关机前sniff已经退出
+ /* user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL); */
+
+ EARPHONE_STATE_ENTER_SOFT_POWEROFF();
+
+#if TCFG_AUDIO_ANC_ENABLE
+ anc_poweroff();
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+
+#if TCFG_USER_TWS_ENABLE
+ if ((int)priv == 3) {
+ user_send_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
+ if (app_var.wait_exit_timer == 0) {
+ app_var.wait_exit_timer = sys_timer_add(NULL, power_off_at_same_time, 50);
+ }
+ return;
+ }
+
+#if TCFG_CHARGESTORE_ENABLE
+ if (chargestore_get_earphone_online() != 2) {
+ bt_tws_poweroff();
+ }
+#else
+ bt_tws_poweroff();
+#endif
+
+ int state = tws_api_get_tws_state();
+ if (state & TWS_STA_PHONE_DISCONNECTED) {
+ detach_phone = 0;
+ }
+ log_info("detach_phone: %x, %d\n", state, detach_phone);
+#endif
+
+ if (detach_phone) {
+ user_send_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
+ }
+
+ if (app_var.wait_exit_timer == 0) {
+ app_var.wait_exit_timer = sys_timer_add(priv, wait_exit_btstack_flag, 50);
+ }
+}
+
+static void sys_auto_shut_down_deal(void *priv)
+{
+ r_printf("%s\n", __func__);
+#if TCFG_USER_TWS_ENABLE
+ if (get_bt_tws_connect_status()) {
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ tws_api_sync_call_by_uuid('T', SYNC_CMD_POWER_OFF_TOGETHER, 400);
+ }
+ } else
+#endif
+ {
+ sys_enter_soft_poweroff(0);
+ }
+}
+
+void sys_auto_shut_down_enable(void)
+{
+#if TCFG_AUTO_SHUT_DOWN_TIME
+ log_info("sys_auto_shut_down_enable\n");
+#if TCFG_AUDIO_ANC_ENABLE
+ /*ANC打开,不支持自动关机*/
+ if (anc_status_get()) {
+ return;
+ }
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+#if TCFG_APP_PC_EN
+ /*PC模式下,不支持自动关机*/
+ if (app_get_curr_task() == APP_PC_TASK) {
+ log_info("APP_PC_TASK now sys_auto_shut_down_disable\n");
+ return;
+ }
+#endif/*TCFG_APP_PC_EN*/
+ if (app_var.auto_shut_down_timer == 0) {
+ app_var.auto_shut_down_timer = sys_timeout_add(NULL, sys_auto_shut_down_deal, (app_var.auto_off_time * 1000));
+ }
+#endif
+}
+
+void sys_auto_shut_down_disable(void)
+{
+#if TCFG_AUTO_SHUT_DOWN_TIME
+ log_info("sys_auto_shut_down_disable\n");
+ if (app_var.auto_shut_down_timer) {
+ sys_timeout_del(app_var.auto_shut_down_timer);
+ app_var.auto_shut_down_timer = 0;
+ }
+#endif
+}
+
+/*static u32 len_lst[34];*/
+
+static const u32 num0_9[] = {
+ (u32)TONE_NUM_0,
+ (u32)TONE_NUM_1,
+ (u32)TONE_NUM_2,
+ (u32)TONE_NUM_3,
+ (u32)TONE_NUM_4,
+ (u32)TONE_NUM_5,
+ (u32)TONE_NUM_6,
+ (u32)TONE_NUM_7,
+ (u32)TONE_NUM_8,
+ (u32)TONE_NUM_9,
+} ;
+static u8 check_phone_income_idle(void)
+{
+ if (bt_user_priv_var.phone_ring_flag) {
+ return 0;
+ }
+ return 1;
+}
+/*
+REGISTER_LP_TARGET(phone_incom_lp_target) = {
+ .name = "phone_check",
+ .is_idle = check_phone_income_idle,
+};
+*/
+static void number_to_play_list(char *num, u32 *lst)
+{
+ u8 i = 0;
+
+#if BT_PHONE_NUMBER
+ if (num) {
+ for (; i < strlen(num); i++) {
+ lst[i] = num0_9[num[i] - '0'] ;
+ }
+ }
+#endif
+
+ lst[i++] = (u32)TONE_REPEAT_BEGIN(-1);
+ lst[i++] = (u32)TONE_RING;
+ lst[i++] = (u32)TONE_REPEAT_END();
+ lst[i++] = (u32)NULL;
+}
+
+extern u8 is_siri_open();
+void phone_num_play_timer(void *priv)
+{
+ char *len_lst[34];
+
+ if (get_call_status() == BT_CALL_HANGUP || is_siri_open()) {
+ log_info("hangup,--phone num play return\n");
+ return;
+ }
+ log_info("%s\n", __FUNCTION__);
+
+ if (bt_user_priv_var.phone_num_flag) {
+ tone_play_stop();
+ number_to_play_list((char *)(bt_user_priv_var.income_phone_num), (u32 *)len_lst);
+ tone_file_list_play((const char *)len_lst, 1);
+ } else {
+ /*电话号码还没有获取到,定时查询*/
+ bt_user_priv_var.phone_timer_id = sys_timeout_add(NULL, phone_num_play_timer, 200);
+ }
+}
+
+static void phone_num_play_start(void)
+{
+ /* check if support inband ringtone */
+ if (!bt_user_priv_var.inband_ringtone) {
+ bt_user_priv_var.phone_num_flag = 0;
+ bt_user_priv_var.phone_timer_id = sys_timeout_add(NULL, phone_num_play_timer, 500);
+ }
+}
+
+void phone_check_inband_ring_play_timer(void *priv)
+{
+#if BT_INBAND_RINGTONE
+ if (bt_user_priv_var.inband_ringtone && bt_user_priv_var.phone_ring_flag) {
+ if (!get_esco_coder_busy_flag()) {
+ r_printf("phone_check_inband_ring_play_timer play");
+ bt_user_priv_var.inband_ringtone = 0;
+#if TCFG_USER_TWS_ENABLE
+ if (!bt_tws_sync_phone_num(NULL))
+#endif
+ {
+ extern u8 phone_ring_play_start(void);
+ phone_ring_play_start();
+ }
+ }
+ }
+#endif
+}
+u8 phone_ring_play_start(void)
+{
+ char *len_lst[34];
+
+ if (get_call_status() == BT_CALL_HANGUP || is_siri_open()) {
+ log_info("hangup,--phone ring play return\n");
+ return 0;
+ }
+ log_info("%s,%d\n", __FUNCTION__, bt_user_priv_var.inband_ringtone);
+ /* check if support inband ringtone */
+ if (!bt_user_priv_var.inband_ringtone) {
+ tone_play_stop();
+ number_to_play_list(NULL, len_lst);
+ tone_file_list_play((const char **)len_lst, 1);
+ return 1;
+ } else {
+#if BT_INBAND_RINGTONE
+ /* bt_user_priv_var.phone_timer_id = sys_timeout_add(NULL, phone_check_inband_ring_play_timer, 4000); //4s之后检测有没建立通话链路,没有建立播本地铃声 */
+#endif
+ }
+ return 0;
+}
+
+
+static u16 play_poweron_ok_timer_id = 0;
+
+static void play_poweron_ok_timer(void *priv)
+{
+ app_var.wait_timer_do = 0;
+
+ log_d("\n-------play_poweron_ok_timer-------\n", priv);
+ if (is_dac_power_off()) {
+#if TCFG_USER_TWS_ENABLE
+ bt_tws_poweron();
+#else
+ bt_wait_connect_and_phone_connect_switch(0);
+#endif
+ return;
+ }
+
+ app_var.wait_timer_do = sys_timeout_add(priv, play_poweron_ok_timer, 100);
+}
+static void play_bt_connect_dly(void *priv)
+{
+ app_var.wait_timer_do = 0;
+
+ log_d("\n-------play_bt_connect_dly-------\n", priv);
+
+ if (!app_var.goto_poweroff_flag) {
+ STATUS *p_tone = get_tone_config();
+ tone_play_index(p_tone->bt_connect_ok, 1);
+ }
+}
+
+
+
+//=============================================================================//
+//NOTE by MO: For fix Make, should be implemented later;
+__attribute__((weak))
+int earphone_a2dp_codec_get_low_latency_mode()
+{
+ return 0;
+}
+
+__attribute__((weak))
+int earphone_a2dp_codec_set_low_latency_mode(int enable, int msec)
+{
+ return 0;
+}
+//=============================================================================//
+
+
+int bt_get_low_latency_mode()
+{
+ return earphone_a2dp_codec_get_low_latency_mode();
+}
+
+void bt_set_low_latency_mode(int enable)
+{
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
+ if (enable) {
+ tws_api_sync_call_by_uuid('T', SYNC_CMD_LOW_LATENCY_ENABLE, 300);
+ } else {
+ tws_api_sync_call_by_uuid('T', SYNC_CMD_LOW_LATENCY_DISABLE, 300);
+ }
+ } else {
+ if (earphone_a2dp_codec_set_low_latency_mode(enable, enable ? 800 : 600) == 0) {
+ if (enable) {
+ tone_play(TONE_LOW_LATENCY_IN, 1);
+ } else {
+ tone_play(TONE_LOW_LATENCY_OUT, 1);
+ }
+ }
+ }
+ }
+#else
+ earphone_a2dp_codec_set_low_latency_mode(enable, enable ? 800 : 600);
+#endif
+}
+
+static void bt_discon_dly_handle(void *priv)
+{
+ app_var.phone_dly_discon_time = 0;
+
+ STATUS *p_tone = get_tone_config();
+
+#if(TCFG_BD_NUM == 2) //对耳在bt_tws同步播放提示音
+ /* tone_play(TONE_DISCONN); */
+ tone_play_index(p_tone->bt_disconnect, 1);
+#else
+
+#if TCFG_USER_TWS_ENABLE
+ if (!get_bt_tws_connect_status() && !get_bt_tws_discon_dly_state())
+#endif
+ {
+ tone_play_index(p_tone->bt_disconnect, 1);
+ }
+#endif
+
+#if TCFG_USER_TWS_ENABLE
+ STATUS *p_led = get_led_config();
+ if (get_bt_tws_connect_status()) {
+#if TCFG_CHARGESTORE_ENABLE
+ chargestore_set_phone_disconnect();
+#endif
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ bt_tws_play_tone_at_same_time(SYNC_TONE_PHONE_DISCONNECTED, 400);
+ }
+ } else {
+ //断开手机时,如果对耳未连接,要把LED时钟切到RC(因为单台会进SNIFF)
+ pwm_led_clk_set((!TCFG_LOWPOWER_BTOSC_DISABLE) ? PWM_LED_CLK_RC32K : PWM_LED_CLK_BTOSC_24M);
+ //pwm_led_clk_set(PWM_LED_CLK_RC32K);
+ ui_update_status(STATUS_BT_DISCONN);
+ }
+#endif
+
+}
+
+#if TCFG_CALL_KWS_SWITCH_ENABLE
+extern int audio_phone_call_kws_start(void);
+extern int audio_phone_call_kws_close(void);
+extern void audio_smart_voice_detect_close(void);
+extern int esco_ul_stream_switch(u8 en);
+extern u8 bt_phone_dec_is_running();
+#endif
+
+static void jl_call_kws_handler(int event)
+{
+ if (event == BT_STATUS_PHONE_INCOME) {
+#if TCFG_KWS_VOICE_RECOGNITION_ENABLE
+ extern void a2dp_media_suspend_resume(u8 flag);
+ a2dp_media_suspend_resume(1);
+ a2dp_dec_close();
+ audio_aec_reboot(1);
+ jl_kws_speech_recognition_open();
+ jl_kws_speech_recognition_start();
+#endif /* #if TCFG_KWS_VOICE_RECOGNITION_ENABLE */
+#if TCFG_CALL_KWS_SWITCH_ENABLE
+ extern void a2dp_media_suspend_resume(u8 flag);
+ a2dp_media_suspend_resume(1);
+ a2dp_dec_close();
+ audio_aec_reboot(1);
+ //esco_ul_stream_switch(0);
+ audio_phone_call_kws_start();
+#endif /* #if TCFG_CALL_KWS_SWITCH_ENABLE */
+ } else if (event == BT_STATUS_PHONE_ACTIVE) {
+#if TCFG_KWS_VOICE_RECOGNITION_ENABLE
+ jl_kws_speech_recognition_close();
+ audio_aec_reboot(0);
+#endif /* #if TCFG_KWS_VOICE_RECOGNITION_ENABLE */
+#ifdef CONFIG_BOARD_AISPEECH_VAD_ASR
+ printf("----aispeech_state phone active");
+ ais_platform_asr_close();
+ esco_mic_reset();
+#endif /*CONFIG_BOARD_AISPEECH_VAD_ASR*/
+#if TCFG_CALL_KWS_SWITCH_ENABLE
+ audio_smart_voice_detect_close();
+ audio_aec_reboot(0);
+ //esco_ul_stream_switch(1);
+#endif /* TCFG_CALL_KWS_SWITCH_ENABLE */
+ } else if (event == BT_STATUS_PHONE_HANGUP) {
+#if TCFG_KWS_VOICE_RECOGNITION_ENABLE
+ jl_kws_speech_recognition_close();
+#endif /* #if TCFG_KWS_VOICE_RECOGNITION_ENABLE */
+#if TCFG_CALL_KWS_SWITCH_ENABLE
+ if (!bt_phone_dec_is_running()) {
+ audio_phone_call_kws_close();
+ }
+#endif /* TCFG_CALL_KWS_SWITCH_ENABLE */
+ }
+}
+
+extern void tws_page_scan_deal_by_esco(u8 esco_flag);
+
+/*
+ * 对应原来的状态处理函数,连接,电话状态等
+ */
+void tws_conn_switch_role();
+static int bt_connction_status_event_handler(struct bt_event *bt)
+{
+ STATUS *p_tone = get_tone_config();
+ u8 *phone_number = NULL;
+
+#if CONFIG_BT_BACKGROUND_ENABLE
+ int ret = bt_background_event_probe_handler(bt);
+ if (ret == -EINVAL) {
+ return 0;
+ }
+#endif
+ //log_info("bt_conn_event:%d", bt->event);
+
+ switch (bt->event) {
+ case BT_STATUS_INIT_OK:
+ /*
+ * 蓝牙初始化完成
+ */
+ log_info("BT_STATUS_INIT_OK\n");
+ init_ok = 1;
+
+#if TCFG_AUDIO_DATA_EXPORT_ENABLE
+#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SPP)
+ lmp_hci_set_role_switch_supported(0);
+#endif/*AUDIO_DATA_EXPORT_USE_SPP*/
+ extern int audio_capture_init();
+ audio_capture_init();
+#endif/*TCFG_AUDIO_DATA_EXPORT_ENABLE*/
+
+#if TCFG_AUDIO_ANC_ENABLE
+ anc_poweron();
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+ __set_sbc_cap_bitpool(38);
+
+#if (TCFG_USER_BLE_ENABLE)
+ if (BT_MODE_IS(BT_BQB)) {
+ ble_bqb_test_thread_init();
+ } else {
+#if !TCFG_WIRELESS_MIC_ENABLE
+ bt_ble_init();
+#endif
+
+#if BLE_HID_EN && (!TCFG_USER_TWS_ENABLE)
+ ble_module_enable(1);
+#endif
+ }
+
+#endif
+
+#if TCFG_USER_TWS_ENABLE
+ extern void pbg_demo_init(void);
+ pbg_demo_init();
+#endif
+
+#if TCFG_USER_EMITTER_ENABLE
+////发射器设置回调等
+ void bt_emitter_init() ;
+ bt_emitter_init();
+ extern u8 emitter_search_result(char *name, u8 name_len, u8 * addr, u32 dev_class, char rssi);
+ inquiry_result_handle_register(emitter_search_result);
+ extern void emitter_or_receiver_switch(u8 flag);
+ emitter_or_receiver_switch(BT_EMITTER_EN);
+ break;
+#endif
+
+ bt_init_ok_search_index();
+ ui_update_status(STATUS_BT_INIT_OK);
+#if TCFG_CHARGESTORE_ENABLE
+ chargestore_set_bt_init_ok(1);
+#endif
+#if TCFG_TEST_BOX_ENABLE
+ testbox_set_bt_init_ok(1);
+#endif
+
+
+#if ((CONFIG_BT_MODE == BT_BQB)||(CONFIG_BT_MODE == BT_PER))
+ bt_wait_phone_connect_control(1);
+#else
+ if (is_dac_power_off()) {
+#if TCFG_USER_TWS_ENABLE
+ bt_tws_poweron();
+#else
+ bt_wait_connect_and_phone_connect_switch(0);
+#endif
+ } else {
+ app_var.wait_timer_do = sys_timeout_add(NULL, play_poweron_ok_timer, 100);
+ }
+#endif
+
+ /*if (app_var.play_poweron_tone) {
+ tone_play_index(p_tone->power_on, 1);
+ }*/
+ break;
+
+ case BT_STATUS_SECOND_CONNECTED:
+ clear_current_poweron_memory_search_index(0);
+ case BT_STATUS_FIRST_CONNECTED:
+ log_info("BT_STATUS_CONNECTED\n");
+ earphone_change_pwr_mode(PWR_DCDC15, 3000);
+ sys_auto_shut_down_disable();
+#if TCFG_ADSP_UART_ENABLE
+ ADSP_UART_Init();
+#endif
+
+#if(JL_EARPHONE_APP_EN && RCSP_UPDATE_EN)
+ extern u8 rcsp_update_get_role_switch(void);
+ if (rcsp_update_get_role_switch()) {
+ tws_conn_switch_role();
+ tws_api_auto_role_switch_disable();
+ }
+#endif
+
+#if(TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV)
+ {
+ u8 connet_type;
+ if (get_auto_connect_state(bt->args)) {
+ connet_type = ICON_TYPE_RECONNECT;
+ } else {
+ connet_type = ICON_TYPE_CONNECTED;
+ }
+
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ bt_ble_icon_open(connet_type);
+ } else {
+ //maybe slave already open
+ bt_ble_icon_close(0);
+ }
+
+#else
+ bt_ble_icon_open(connet_type);
+#endif
+ }
+#endif
+
+
+#if (TCFG_BD_NUM == 2)
+ if (get_current_poweron_memory_search_index(NULL) == 0) {
+ bt_wait_phone_connect_control(1);
+ }
+#endif
+
+#if TCFG_USER_TWS_ENABLE
+ if (!get_bt_tws_connect_status()) { //如果对耳还未连接就连上手机,要切换闪灯状态
+ ui_update_status(STATUS_BT_CONN);
+ }
+
+#if TCFG_CHARGESTORE_ENABLE
+ chargestore_set_phone_connect();
+#endif
+
+ if (bt_tws_phone_connected()) {
+ break;
+ }
+#else
+ ui_update_status(STATUS_BT_CONN); //单台在此处设置连接状态,对耳的连接状态需要同步,在bt_tws.c中去设置
+#if (TCFG_AUTO_STOP_PAGE_SCAN_TIME && TCFG_BD_NUM == 2)
+ if (get_total_connect_dev() == 1) { //当前有一台连接上了
+ if (app_var.auto_stop_page_scan_timer == 0) {
+ app_var.auto_stop_page_scan_timer = sys_timeout_add(NULL, bt_close_page_scan, (TCFG_AUTO_STOP_PAGE_SCAN_TIME * 1000)); //2
+ }
+ } else {
+ if (app_var.auto_stop_page_scan_timer) {
+ sys_timeout_del(app_var.auto_stop_page_scan_timer);
+ app_var.auto_stop_page_scan_timer = 0;
+ }
+ }
+#endif //endif AUTO_STOP_PAGE_SCAN_TIME
+#endif
+ /* tone_play(TONE_CONN); */
+
+
+ /*os_time_dly(40); // for test*/
+ log_info("tone status:%d\n", tone_get_status());
+ if (get_call_status() == BT_CALL_HANGUP) {
+ if (app_var.phone_dly_discon_time) {
+ sys_timeout_del(app_var.phone_dly_discon_time);
+ app_var.phone_dly_discon_time = 0;
+ } else {
+ app_var.wait_timer_do = sys_timeout_add(NULL, play_bt_connect_dly, 1600);
+ /* tone_play_index(p_tone->bt_connect_ok, 1); */
+ }
+ }
+
+ /*int timeout = 5000 + rand32() % 10000;
+ sys_timeout_add(NULL, connect_phone_test, timeout);*/
+ break;
+ case BT_STATUS_FIRST_DISCONNECT:
+ case BT_STATUS_SECOND_DISCONNECT:
+ log_info("BT_STATUS_DISCONNECT\n");
+#if TCFG_ADSP_UART_ENABLE
+ ADSP_UART_Deinit();
+#endif
+ if (app_var.goto_poweroff_flag) {
+ /*关机不播断开提示音*/
+ /*关机时不改UI*/
+ break;
+ }
+
+#if PHONE_DLY_DISCONN_TIME
+ if (app_var.phone_dly_discon_time == 0) {
+ app_var.phone_dly_discon_time = sys_timeout_add(NULL, bt_discon_dly_handle, PHONE_DLY_DISCONN_TIME);
+ }
+#else
+ bt_discon_dly_handle(NULL);
+#endif
+ break;
+
+ //phone status deal
+ case BT_STATUS_PHONE_INCOME:
+ log_info("BT_STATUS_PHONE_INCOME\n");
+ esco_dump_packet = ESCO_DUMP_PACKET_CALL;
+ ui_update_status(STATUS_PHONE_INCOME);
+ u8 tmp_bd_addr[6];
+ memcpy(tmp_bd_addr, bt->args, 6);
+ jl_call_kws_handler(BT_STATUS_PHONE_INCOME);
+ /*
+ *(1)1t2有一台通话的时候,另一台如果来电不要提示
+ *(2)1t2两台同时来电,现来的题示,后来的不播
+ */
+ if ((check_esco_state_via_addr(tmp_bd_addr) != BD_ESCO_BUSY_OTHER) &&
+ (bt_user_priv_var.phone_ring_flag == 0)) {
+
+#if BT_INBAND_RINGTONE
+ extern u8 get_device_inband_ringtone_flag(void);
+ bt_user_priv_var.inband_ringtone = get_device_inband_ringtone_flag();
+#else
+ bt_user_priv_var.inband_ringtone = 0 ;
+ lmp_private_esco_suspend_resume(3);
+#endif
+
+ g_printf("bt_user_priv_var.inband_ringtone=0x%x\n", bt_user_priv_var.inband_ringtone);
+ bt_user_priv_var.phone_ring_flag = 1;
+ bt_user_priv_var.phone_income_flag = 1;
+#if TCFG_USER_TWS_ENABLE
+ if (!bt_tws_sync_phone_num(NULL))
+#endif
+ {
+#if BT_PHONE_NUMBER
+ phone_num_play_start();
+#else
+ phone_ring_play_start();
+#endif
+
+ }
+ user_send_cmd_prepare(USER_CTRL_HFP_CALL_CURRENT, 0, NULL); //发命令获取电话号码
+ } else {
+ log_info("SCO busy now:%d,%d\n", check_esco_state_via_addr(tmp_bd_addr),
+ bt_user_priv_var.phone_ring_flag);
+ }
+ break;
+ case BT_STATUS_PHONE_OUT:
+ log_info("BT_STATUS_PHONE_OUT\n");
+ esco_dump_packet = ESCO_DUMP_PACKET_CALL;
+ ui_update_status(STATUS_PHONE_OUT);
+ bt_user_priv_var.phone_income_flag = 0;
+ user_send_cmd_prepare(USER_CTRL_HFP_CALL_CURRENT, 0, NULL); //发命令获取电话号码
+ break;
+ case BT_STATUS_PHONE_ACTIVE:
+ jl_call_kws_handler(BT_STATUS_PHONE_ACTIVE);
+ log_info("BT_STATUS_PHONE_ACTIVE\n");
+ ui_update_status(STATUS_PHONE_ACTIV);
+ if (bt_user_priv_var.phone_call_dec_begin) {
+ log_info("call_active,dump_packet clear\n");
+ esco_dump_packet = ESCO_DUMP_PACKET_DEFAULT;
+ }
+ if (bt_user_priv_var.phone_ring_flag) {
+ bt_user_priv_var.phone_ring_flag = 0;
+ tone_play_stop();
+ if (bt_user_priv_var.phone_timer_id) {
+ sys_timeout_del(bt_user_priv_var.phone_timer_id);
+ bt_user_priv_var.phone_timer_id = 0;
+ }
+ }
+ lmp_private_esco_suspend_resume(4);
+ bt_user_priv_var.phone_income_flag = 0;
+ bt_user_priv_var.phone_num_flag = 0;
+ bt_user_priv_var.phone_con_sync_num_ring = 0;
+ bt_user_priv_var.phone_con_sync_ring = 0;
+ bt_user_priv_var.phone_vol = 15;
+ //phone_sync_vol();
+#if TCFG_USER_TWS_ENABLE
+ bt_tws_sync_volume();
+#endif
+ r_printf("phone_active:%d\n", app_var.call_volume);
+ app_audio_set_volume(APP_AUDIO_STATE_CALL, app_var.call_volume, 1);
+#if TCFG_EAR_DETECT_ENABLE
+#if TCFG_EAR_DETECT_CALL_CTL_SCO
+ ear_detect_phone_active_deal();
+#endif
+#if (TCFG_EAR_DETECT_AUTO_CHG_MASTER && TCFG_USER_TWS_ENABLE)
+ ear_detect_call_chg_master_deal();
+#endif //TCFG_EAR_DETECT_AUTO_CHG_MASTER
+#endif // TCFG_EAR_DETECT_ENABLE
+
+ break;
+ case BT_STATUS_PHONE_HANGUP:
+ esco_dump_packet = ESCO_DUMP_PACKET_CALL;
+ log_info("phone_handup\n");
+ jl_call_kws_handler(BT_STATUS_PHONE_HANGUP);
+ if (bt_user_priv_var.phone_ring_flag) {
+ bt_user_priv_var.phone_ring_flag = 0;
+ tone_play_stop();
+ if (bt_user_priv_var.phone_timer_id) {
+ sys_timeout_del(bt_user_priv_var.phone_timer_id);
+ bt_user_priv_var.phone_timer_id = 0;
+ }
+ }
+ bt_user_priv_var.phone_income_flag = 0;
+ bt_user_priv_var.phone_num_flag = 0;
+ bt_user_priv_var.phone_con_sync_num_ring = 0;
+ bt_user_priv_var.phone_con_sync_ring = 0;
+ lmp_private_esco_suspend_resume(4);
+#if (TCFG_EAR_DETECT_ENABLE && TCFG_EAR_DETECT_AUTO_CHG_MASTER && TCFG_USER_TWS_ENABLE)
+ ear_detect_change_master_timer_del(); //假如通话结束了,但是还没开始切换主从,取消切换
+#endif
+ break;
+ case BT_STATUS_PHONE_NUMBER:
+ log_info("BT_STATUS_PHONE_NUMBER\n");
+ phone_number = (u8 *)bt->value;
+ //put_buf(phone_number, strlen((const char *)phone_number));
+ if (bt_user_priv_var.phone_num_flag == 1) {
+ break;
+ }
+ bt_user_priv_var.income_phone_len = 0;
+ memset(bt_user_priv_var.income_phone_num, '\0', sizeof(bt_user_priv_var.income_phone_num));
+ for (int i = 0; i < strlen((const char *)phone_number); i++) {
+ if (phone_number[i] >= '0' && phone_number[i] <= '9') {
+ //过滤,只有数字才能报号
+ bt_user_priv_var.income_phone_num[bt_user_priv_var.income_phone_len++] = phone_number[i];
+ if (bt_user_priv_var.income_phone_len >= sizeof(bt_user_priv_var.income_phone_num)) {
+ break; /*buffer 空间不够,后面不要了*/
+ }
+ }
+ }
+ if (bt_user_priv_var.income_phone_len > 0) {
+ bt_user_priv_var.phone_num_flag = 1;
+ } else {
+ log_info("PHONE_NUMBER len err\n");
+ }
+ break;
+ case BT_STATUS_INBAND_RINGTONE:
+ log_info("BT_STATUS_INBAND_RINGTONE\n");
+#if BT_INBAND_RINGTONE
+ bt_user_priv_var.inband_ringtone = bt->value;
+#else
+ bt_user_priv_var.inband_ringtone = 0;
+#endif
+ printf("bt_user_priv_var.inband_ringtone=0x%x\n", bt_user_priv_var.inband_ringtone);
+ break;
+
+
+ case BT_STATUS_BEGIN_AUTO_CON:
+ log_info("BT_STATUS_BEGIN_AUTO_CON\n");
+ break;
+ case BT_STATUS_A2DP_MEDIA_START:
+ log_info(" BT_STATUS_A2DP_MEDIA_START:0x%x", bt->value);
+#if TCFG_AUDIO_CVP_DUT_ENABLE
+ if (audio_dec_dut_en_get(0)) {
+ a2dp_dut_dec_open(bt->value);
+ } else
+#endif /*TCFG_AUDIO_CVP_DUT_ENABLE*/
+ {
+ a2dp_dec_open(bt->value);
+ }
+ break;
+ case BT_STATUS_A2DP_MEDIA_STOP:
+ log_info(" BT_STATUS_A2DP_MEDIA_STop");
+ a2dp_dec_close();
+
+ extern void free_a2dp_using_decoder_conn();
+ free_a2dp_using_decoder_conn();
+ break;
+ case BT_STATUS_SCO_STATUS_CHANGE:
+ printf(" BT_STATUS_SCO_STATUS_CHANGE len:%d ,type:%d", (bt->value >> 16), (bt->value & 0x0000ffff));
+ if (bt->value != 0xff) {
+ puts("<<<<<<<<<<value);*/
+ esco_dec_open(&bt->value, 0);
+
+ bt_user_priv_var.phone_call_dec_begin = 1;
+ if (get_call_status() == BT_CALL_ACTIVE) {
+ log_info("dec_begin,dump_packet clear\n");
+ esco_dump_packet = ESCO_DUMP_PACKET_DEFAULT;
+ }
+#if TCFG_USER_TWS_ENABLE
+ tws_page_scan_deal_by_esco(1);
+ pbg_user_mic_fixed_deal(1);
+#endif
+ } else {
+ puts("<<<<<<<<<<value);
+ //u8 volume = app_audio_get_max_volume() * bt->value / 15;
+ u8 volume = bt->value;
+ u8 call_status = get_call_status();
+
+#if BT_INBAND_RINGTONE
+ if ((call_status != BT_CALL_ACTIVE) && (bt->value == 0)) {
+ printf("not set vol\n");
+ break;
+ }
+#endif
+
+ bt_user_priv_var.phone_vol = bt->value;
+ if ((call_status == BT_CALL_ACTIVE) || (call_status == BT_CALL_OUTGOING) || app_var.siri_stu) {
+ app_audio_set_volume(APP_AUDIO_STATE_CALL, volume, 1);
+#if TCFG_USER_TWS_ENABLE
+ if (call_status == BT_CALL_ACTIVE) {
+ bt_tws_sync_volume();
+ }
+#endif
+ } else { /*if (call_status != BT_CALL_HANGUP)*/
+ /*
+ *只保存,不设置到dac
+ *微信语音通话的时候,会更新音量到app,但是此时的call status可能是hangup
+ */
+ app_var.call_volume = volume;
+ }
+ break;
+ case BT_STATUS_SNIFF_STATE_UPDATE:
+ log_info(" BT_STATUS_SNIFF_STATE_UPDATE %d\n", bt->value); //0退出SNIFF
+ if (bt->value == 0) {
+ sniff_out = 1;
+#if defined CFG_LED_MODE && (CFG_LED_MODE == CFG_LED_SOFT_MODE)
+ pwm_led_mode_set(pwm_led_display_mode_get());
+#endif
+#if(TCFG_USER_TWS_ENABLE == 1)
+ led_module_exit_sniff_mode();
+ pwm_led_clk_set(PWM_LED_CLK_BTOSC_24M);
+#endif
+ sys_auto_sniff_controle(MY_SNIFF_EN, bt->args);
+ } else {
+#if(TCFG_USER_TWS_ENABLE == 1)
+ led_module_enter_sniff_mode();
+ pwm_led_clk_set((!TCFG_LOWPOWER_BTOSC_DISABLE) ? PWM_LED_CLK_RC32K : PWM_LED_CLK_BTOSC_24M);
+#endif
+ sys_auto_sniff_controle(0, bt->args);
+ }
+ break;
+
+ case BT_STATUS_LAST_CALL_TYPE_CHANGE:
+ log_info("BT_STATUS_LAST_CALL_TYPE_CHANGE:%d\n", bt->value);
+ bt_user_priv_var.last_call_type = bt->value;
+ break;
+
+ case BT_STATUS_CONN_A2DP_CH:
+ case BT_STATUS_CONN_HFP_CH:
+
+ if ((!is_1t2_connection()) && (get_current_poweron_memory_search_index(NULL))) { //回连下一个device
+ if (get_esco_coder_busy_flag()) {
+ clear_current_poweron_memory_search_index(0);
+ } else {
+ user_send_cmd_prepare(USER_CTRL_START_CONNECTION, 0, NULL);
+ }
+ }
+ break;
+ case BT_STATUS_PHONE_MANUFACTURER:
+ log_info("BT_STATUS_PHONE_MANUFACTURER:%d\n", bt->value);
+ extern const u8 hid_conn_depend_on_dev_company;
+ app_var.remote_dev_company = bt->value;
+ if (hid_conn_depend_on_dev_company) {
+ if (bt->value) {
+ //user_send_cmd_prepare(USER_CTRL_HID_CONN, 0, NULL);
+ } else {
+
+ if (get_curr_channel_state() == HID_CH) {
+ //如果只连上hid 先不断开
+ } else {
+ user_send_cmd_prepare(USER_CTRL_HID_DISCONNECT, 0, NULL);
+ }
+ }
+ }
+ break;
+ case BT_STATUS_VOICE_RECOGNITION:
+ log_info(" BT_STATUS_VOICE_RECOGNITION:%d \n", bt->value);
+ /* put_buf(bt, sizeof(struct bt_event)); */
+ app_var.siri_stu = bt->value;
+ esco_dump_packet = ESCO_DUMP_PACKET_DEFAULT;
+ break;
+ case BT_STATUS_AVRCP_INCOME_OPID:
+#define AVC_VOLUME_UP 0x41
+#define AVC_VOLUME_DOWN 0x42
+ log_info("BT_STATUS_AVRCP_INCOME_OPID:%d\n", bt->value);
+ if (bt->value == AVC_VOLUME_UP) {
+
+ }
+ if (bt->value == AVC_VOLUME_DOWN) {
+
+ }
+ break;
+ default:
+ log_info(" BT STATUS DEFAULT\n");
+ break;
+ }
+ return 0;
+}
+
+
+
+
+static void sys_time_auto_connection_deal(void *arg)
+{
+ if (bt_user_priv_var.auto_connection_counter) {
+ log_info("------------------------auto_timeout conuter %d", bt_user_priv_var.auto_connection_counter);
+ bt_user_priv_var.auto_connection_counter--;
+ user_send_cmd_prepare(USER_CTRL_START_CONNEC_VIA_ADDR, 6, bt_user_priv_var.auto_connection_addr);
+ }
+}
+
+static void bt_hci_event_inquiry(struct bt_event *bt)
+{
+#if TCFG_USER_EMITTER_ENABLE
+ if (bt_user_priv_var.emitter_or_receiver == BT_EMITTER_EN) {
+ extern void emitter_search_stop();
+ emitter_search_stop();
+ }
+#endif
+}
+
+static void bt_hci_event_connection(struct bt_event *bt)
+{
+ //clk_set_sys_lock(BT_CONNECT_HZ, 0);
+ log_info("tws_conn_state=%d\n", bt_user_priv_var.tws_conn_state);
+
+#if TCFG_USER_TWS_ENABLE
+ bt_tws_hci_event_connect();
+#ifndef CONFIG_NEW_BREDR_ENABLE
+ tws_try_connect_disable();
+#endif
+#else
+ if (bt_user_priv_var.auto_connection_timer) {
+ sys_timeout_del(bt_user_priv_var.auto_connection_timer);
+ bt_user_priv_var.auto_connection_timer = 0;
+ }
+ bt_user_priv_var.auto_connection_counter = 0;
+ bt_wait_phone_connect_control(0);
+ user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL);
+#endif
+
+}
+
+extern void bt_get_vm_mac_addr(u8 *addr);
+static void bt_discovery_and_connectable_using_loca_mac_addr(u8 inquiry_scan_en, u8 page_scan_en)
+{
+
+ u8 local_addr[6];
+ log_info("<<<<<<<<<<>>>>>>>>>>>>\n", inquiry_scan_en, page_scan_en);
+
+ bt_get_vm_mac_addr(local_addr);
+ //log_info("local_adr\n");
+ //put_buf(local_addr,6);
+
+ lmp_hci_write_local_address(local_addr);
+ if (page_scan_en) {
+ user_send_cmd_prepare(USER_CTRL_WRITE_CONN_ENABLE, 0, NULL);
+ }
+ if (inquiry_scan_en) {
+ user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_ENABLE, 0, NULL);
+ }
+}
+
+static void bt_hci_event_disconnect(struct bt_event *bt)
+{
+ if (app_var.goto_poweroff_flag) {
+ return;
+ }
+ earphone_change_pwr_mode(PWR_LDO15, 0);
+
+ /* if (get_total_connect_dev() == 0) { //已经没有设备连接 */
+ /* sys_auto_shut_down_enable(); */
+ /* } */
+
+ log_info("<<<<<<<<<<<<<>>>>>>>>>>>>\n", get_total_connect_dev());
+ if (!get_curr_channel_state()) {
+ /* if (get_total_connect_dev() == 0) { //已经没有设备连接 */
+#if (TCFG_USER_TWS_ENABLE == 0)
+ if (!app_var.goto_poweroff_flag) { /*关机时不改UI*/
+ ui_update_status(STATUS_BT_DISCONN);
+ }
+#endif
+ sys_auto_shut_down_enable();
+ }
+#if (TCFG_BD_NUM == 2)
+ log_info("get_bt_connect_status = 0x%x,%x\n", get_bt_connect_status(), get_curr_channel_state());
+ if (!get_curr_channel_state()) {
+ sys_auto_shut_down_enable();
+ }
+#endif
+
+#if TCFG_TEST_BOX_ENABLE
+ if (testbox_get_ex_enter_dut_flag()) {
+ bt_discovery_and_connectable_using_loca_mac_addr(1, 1);
+ return;
+ }
+
+ if (testbox_get_status()) {
+ bt_discovery_and_connectable_using_loca_mac_addr(0, 1);
+ return;
+ }
+#endif
+
+#if (TCFG_AUTO_STOP_PAGE_SCAN_TIME && TCFG_BD_NUM == 2)
+ if (get_total_connect_dev() == 1) { //当前有一台连接上了
+ if (app_var.auto_stop_page_scan_timer == 0) {
+ app_var.auto_stop_page_scan_timer = sys_timeout_add(NULL, bt_close_page_scan, (TCFG_AUTO_STOP_PAGE_SCAN_TIME * 1000)); //2
+ }
+ } else {
+ if (app_var.auto_stop_page_scan_timer) {
+ sys_timeout_del(app_var.auto_stop_page_scan_timer);
+ app_var.auto_stop_page_scan_timer = 0;
+ }
+ }
+#endif //endif AUTO_STOP_PAGE_SCAN_TIME
+
+#if (TCFG_BD_NUM == 2)
+ if ((bt->event == ERROR_CODE_CONNECTION_REJECTED_DUE_TO_UNACCEPTABLE_BD_ADDR)
+ || (bt->event == ERROR_CODE_CONNECTION_ACCEPT_TIMEOUT_EXCEEDED)
+ || (bt->event == ERROR_CODE_ROLE_SWITCH_FAILED)
+ || (bt->event == ERROR_CODE_ACL_CONNECTION_ALREADY_EXISTS)) {
+ /*
+ *连接接受超时
+ *如果支持1t2,可以选择继续回连下一台,除非已经回连完毕
+ */
+ if (get_current_poweron_memory_search_index(NULL)) {
+ user_send_cmd_prepare(USER_CTRL_START_CONNECTION, 0, NULL);
+ return;
+ }
+ }
+#endif
+
+#if TCFG_USER_TWS_ENABLE
+ if (bt->value == ERROR_CODE_CONNECTION_TIMEOUT) {
+ bt_tws_phone_connect_timeout();
+ } else {
+ bt_tws_phone_disconnected();
+ }
+#else
+ bt_wait_phone_connect_control(1);
+#endif
+}
+
+static void bt_hci_event_linkkey_missing(struct bt_event *bt)
+{
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV)
+#if (CONFIG_NO_DISPLAY_BUTTON_ICON && TCFG_CHARGESTORE_ENABLE)
+ //已取消配对了
+ if (bt_ble_icon_get_adv_state() == ADV_ST_RECONN) {
+ //切换广播
+ log_info("switch_INQ\n");
+ bt_ble_icon_open(ICON_TYPE_INQUIRY);
+ }
+#endif
+#endif
+}
+
+static void bt_hci_event_page_timeout()
+{
+
+ log_info("------------------------HCI_EVENT_PAGE_TIMEOUT conuter %d", bt_user_priv_var.auto_connection_counter);
+#if TCFG_USER_TWS_ENABLE
+ bt_tws_phone_page_timeout();
+#else
+ /* if (!bt_user_priv_var.auto_connection_counter) { */
+ if (bt_user_priv_var.auto_connection_timer) {
+ sys_timer_del(bt_user_priv_var.auto_connection_timer);
+ bt_user_priv_var.auto_connection_timer = 0;
+ }
+
+#if (TCFG_BD_NUM == 2)
+ if (get_current_poweron_memory_search_index(NULL)) {
+ user_send_cmd_prepare(USER_CTRL_START_CONNECTION, 0, NULL);
+ }
+#endif
+
+ bt_wait_phone_connect_control(1);
+#endif
+}
+
+static void bt_hci_event_connection_timeout(struct bt_event *bt)
+{
+ earphone_change_pwr_mode(PWR_LDO15, 0);
+
+#if TCFG_TEST_BOX_ENABLE
+ if (testbox_get_ex_enter_dut_flag()) {
+ bt_discovery_and_connectable_using_loca_mac_addr(1, 1);
+ return;
+ }
+#endif
+
+ if (!get_remote_test_flag() && !get_esco_busy_flag()) {
+ bt_user_priv_var.auto_connection_counter = (TIMEOUT_CONN_TIME * 1000);
+ memcpy(bt_user_priv_var.auto_connection_addr, bt->args, 6);
+#if TCFG_USER_TWS_ENABLE
+ bt_tws_phone_connect_timeout();
+#else
+
+#if ((CONFIG_BT_MODE == BT_BQB)||(CONFIG_BT_MODE == BT_PER))
+ bt_wait_phone_connect_control(1);
+#else
+ user_send_cmd_prepare(USER_CTRL_PAGE_CANCEL, 0, NULL);
+#if (TCFG_BD_NUM == 2)
+ if (bt_user_priv_var.auto_connection_timer) {
+ log_info("1To2 had registered timer,del it\n");//1To2 存在两个手机都断连的情况,所以要判断,删掉第一个手机断连时候的定时器
+ sys_timeout_del(bt_user_priv_var.auto_connection_timer);
+ bt_user_priv_var.auto_connection_timer = 0;
+ }
+#endif
+ bt_wait_connect_and_phone_connect_switch(0);
+#endif
+ //user_send_cmd_prepare(USER_CTRL_START_CONNEC_VIA_ADDR, 6, bt->args);
+#endif
+ } else {
+#if TCFG_USER_TWS_ENABLE
+ bt_tws_phone_disconnected();
+#else
+ bt_wait_phone_connect_control(1);
+#endif
+
+ }
+}
+
+static void bt_hci_event_connection_exist(struct bt_event *bt)
+{
+
+ if (!get_remote_test_flag() && !get_esco_busy_flag()) {
+ bt_user_priv_var.auto_connection_counter = (8 * 1000);
+ memcpy(bt_user_priv_var.auto_connection_addr, bt->args, 6);
+#if TCFG_USER_TWS_ENABLE
+ bt_tws_phone_connect_timeout();
+#else
+ if (bt_user_priv_var.auto_connection_timer) {
+ sys_timer_del(bt_user_priv_var.auto_connection_timer);
+ bt_user_priv_var.auto_connection_timer = 0;
+ }
+ bt_wait_connect_and_phone_connect_switch(0);
+ //user_send_cmd_prepare(USER_CTRL_START_CONNEC_VIA_ADDR, 6, bt->args);
+#endif
+ } else {
+#if TCFG_USER_TWS_ENABLE
+ bt_tws_phone_disconnected();
+#else
+ bt_wait_phone_connect_control(1);
+#endif
+
+ }
+}
+
+
+
+void eartch_testbox_flag(u8 flag);
+
+enum {
+ TEST_STATE_INIT = 1,
+ TEST_STATE_EXIT = 3,
+};
+
+enum {
+ ITEM_KEY_STATE_DETECT = 0,
+ ITEM_IN_EAR_DETECT,
+};
+
+static u8 in_ear_detect_test_flag = 0;
+static void testbox_in_ear_detect_test_flag_set(u8 flag)
+{
+ in_ear_detect_test_flag = flag;
+}
+
+u8 testbox_in_ear_detect_test_flag_get(void)
+{
+ return in_ear_detect_test_flag;
+}
+
+static void bt_in_ear_detection_test_state_handle(u8 state, u8 *value)
+{
+ switch (state) {
+ case TEST_STATE_INIT:
+ testbox_in_ear_detect_test_flag_set(1);
+
+#if TCFG_EARTCH_EVENT_HANDLE_ENABLE
+ eartch_testbox_flag(1);
+#endif
+ //start trim
+ break;
+ case TEST_STATE_EXIT:
+ testbox_in_ear_detect_test_flag_set(0);
+#if TCFG_EARTCH_EVENT_HANDLE_ENABLE
+ eartch_testbox_flag(0);
+#endif
+ break;
+ }
+}
+
+static void bt_vendor_meta_event_handle(u8 sub_evt, u8 *arg, u8 len)
+{
+ log_info("vendor event:%x\n", sub_evt);
+ log_info_hexdump(arg, 6);
+
+ if (sub_evt != HCI_SUBEVENT_VENDOR_TEST_MODE_CFG) {
+ log_info("unknow_sub_evt:%x\n", sub_evt);
+ return;
+ }
+
+ u8 test_item = arg[0];
+ u8 state = arg[1];
+
+ if (ITEM_IN_EAR_DETECT == test_item) {
+ bt_in_ear_detection_test_state_handle(state, NULL);
+ }
+}
+
+extern void set_remote_test_flag(u8 own_remote_test);
+
+static int bt_hci_event_handler(struct bt_event *bt)
+{
+ //对应原来的蓝牙连接上断开处理函数 ,bt->value=reason
+ log_info("------------------------bt_hci_event_handler reason %x %x", bt->event, bt->value);
+
+ if (bt->event == HCI_EVENT_VENDOR_REMOTE_TEST) {
+ if (VENDOR_TEST_DISCONNECTED == bt->value) {
+#if TCFG_TEST_BOX_ENABLE
+ if (testbox_get_status()) {
+ if (get_remote_test_flag()) {
+ testbox_clear_connect_status();
+ }
+ }
+#endif
+ set_remote_test_flag(0);
+ log_info("clear_test_box_flag");
+ cpu_reset();
+ return 0;
+ } else {
+
+#if TCFG_USER_BLE_ENABLE
+#if (CONFIG_BT_MODE == BT_NORMAL)
+ //1:edr con;2:ble con;
+ if (VENDOR_TEST_LEGACY_CONNECTED_BY_BT_CLASSIC == bt->value) {
+ extern void bt_ble_adv_enable(u8 enable);
+ bt_ble_adv_enable(0);
+ }
+#endif
+#endif
+#if TCFG_USER_TWS_ENABLE
+ if (VENDOR_TEST_CONNECTED_WITH_TWS != bt->value) {
+ bt_tws_poweroff();
+ }
+#endif
+ }
+ }
+
+ /* if (((bt->event != HCI_EVENT_CONNECTION_COMPLETE) && (bt->event != HCI_EVENT_VENDOR_REMOTE_TEST)) \ */
+ /* || ((bt->event == HCI_EVENT_CONNECTION_COMPLETE) && (bt->value != ERROR_CODE_SUCCESS))) { */
+ /* #if TCFG_TEST_BOX_ENABLE */
+ /* if (testbox_get_status()) { */
+ /* if (get_remote_test_flag()) { */
+ /* chargestore_clear_connect_status(); */
+ /* } */
+ /* //return 0; */
+ /* } */
+ /* #endif */
+ /* } */
+
+ switch (bt->event) {
+ case HCI_EVENT_VENDOR_META:
+ bt_vendor_meta_event_handle(bt->value, bt->args, 6);
+ break;
+ case HCI_EVENT_INQUIRY_COMPLETE:
+ log_info(" HCI_EVENT_INQUIRY_COMPLETE \n");
+ bt_hci_event_inquiry(bt);
+ break;
+ case HCI_EVENT_USER_CONFIRMATION_REQUEST:
+ log_info(" HCI_EVENT_USER_CONFIRMATION_REQUEST \n");
+ ///<可通过按键来确认是否配对 1:配对 0:取消
+ bt_send_pair(1);
+ break;
+ case HCI_EVENT_USER_PASSKEY_REQUEST:
+ log_info(" HCI_EVENT_USER_PASSKEY_REQUEST \n");
+ ///<可以开始输入6位passkey
+ break;
+ case HCI_EVENT_USER_PRESSKEY_NOTIFICATION:
+ log_info(" HCI_EVENT_USER_PRESSKEY_NOTIFICATION %x\n", bt->value);
+ ///<可用于显示输入passkey位置 value 0:start 1:enrer 2:earse 3:clear 4:complete
+ break;
+ case HCI_EVENT_PIN_CODE_REQUEST :
+ log_info("HCI_EVENT_PIN_CODE_REQUEST \n");
+ bt_send_pair(1);
+ break;
+
+ case HCI_EVENT_VENDOR_NO_RECONN_ADDR :
+ log_info("HCI_EVENT_VENDOR_NO_RECONN_ADDR \n");
+ bt_hci_event_disconnect(bt) ;
+ break;
+
+ case HCI_EVENT_DISCONNECTION_COMPLETE :
+ log_info("HCI_EVENT_DISCONNECTION_COMPLETE \n");
+ bt_hci_event_disconnect(bt) ;
+ break;
+
+ case BTSTACK_EVENT_HCI_CONNECTIONS_DELETE:
+ case HCI_EVENT_CONNECTION_COMPLETE:
+#if PHONE_DLY_DISCONN_TIME
+ if (bt->value == ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION) {
+ if (app_var.phone_dly_discon_time) {
+ sys_timeout_del(app_var.phone_dly_discon_time);
+ bt_discon_dly_handle(NULL);
+ }
+ }
+#endif
+ log_info(" HCI_EVENT_CONNECTION_COMPLETE \n");
+ switch (bt->value) {
+ case ERROR_CODE_SUCCESS :
+ log_info("ERROR_CODE_SUCCESS \n");
+ testbox_in_ear_detect_test_flag_set(0);
+ bt_hci_event_connection(bt);
+ break;
+ case ERROR_CODE_PIN_OR_KEY_MISSING:
+ log_info(" ERROR_CODE_PIN_OR_KEY_MISSING \n");
+ bt_hci_event_linkkey_missing(bt);
+
+ case ERROR_CODE_SYNCHRONOUS_CONNECTION_LIMIT_TO_A_DEVICE_EXCEEDED :
+ case ERROR_CODE_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES:
+ case ERROR_CODE_CONNECTION_REJECTED_DUE_TO_UNACCEPTABLE_BD_ADDR:
+ case ERROR_CODE_CONNECTION_ACCEPT_TIMEOUT_EXCEEDED :
+ case ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION :
+ case ERROR_CODE_CONNECTION_TERMINATED_BY_LOCAL_HOST :
+ case ERROR_CODE_AUTHENTICATION_FAILURE :
+ //case CUSTOM_BB_AUTO_CANCEL_PAGE:
+ bt_hci_event_disconnect(bt) ;
+ break;
+
+ case ERROR_CODE_PAGE_TIMEOUT:
+ log_info(" ERROR_CODE_PAGE_TIMEOUT \n");
+ bt_hci_event_page_timeout();
+ break;
+
+ case ERROR_CODE_CONNECTION_TIMEOUT:
+ log_info(" ERROR_CODE_CONNECTION_TIMEOUT \n");
+ bt_hci_event_connection_timeout(bt);
+ break;
+
+ case ERROR_CODE_ROLE_SWITCH_FAILED:
+ log_info("ERROR_CODE_ROLE_SWITCH_FAILED \n");
+ case ERROR_CODE_ACL_CONNECTION_ALREADY_EXISTS :
+ log_info("ERROR_CODE_ACL_CONNECTION_ALREADY_EXISTS \n");
+ bt_hci_event_connection_exist(bt);
+ break;
+ default:
+ break;
+
+ }
+ break;
+ default:
+ break;
+
+ }
+ return 0;
+}
+
+
+//恢复前台运行
+static void earphone_run_at_foreground()
+{
+ sys_auto_shut_down_disable();
+}
+
+
+
+
+/*
+ * 系统事件处理函数
+ */
+static int event_handler(struct application *app, struct sys_event *event)
+{
+ if (SYS_EVENT_REMAP(event)) {
+ g_printf("****SYS_EVENT_REMAP**** \n");
+ return 0;
+ }
+
+ switch (event->type) {
+ case SYS_KEY_EVENT:
+ /*
+ * 普通按键消息处理
+ */
+ if (bt_user_priv_var.fast_test_mode) {
+ //audio_adc_mic_demo_close();
+ tone_play_index(IDEX_TONE_NORMAL, 1);
+ }
+#if CONFIG_BT_BACKGROUND_ENABLE
+ if (bt_in_background()) {
+ break;
+ }
+#endif
+ app_earphone_key_event_handler(event);
+ break;
+
+ case SYS_BT_EVENT:
+ /*
+ * 蓝牙事件处理
+ */
+ if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) {
+ bt_connction_status_event_handler(&event->u.bt);
+ } else if ((u32)event->arg == SYS_BT_EVENT_TYPE_HCI_STATUS) {
+ bt_hci_event_handler(&event->u.bt);
+ }
+#if TCFG_ADSP_UART_ENABLE
+ else if (!strcmp(event->arg, "UART")) {
+ extern void bt_uart_command_handler(struct uart_event * event);
+ bt_uart_command_handler(&event->u.uart);
+ } else if (!strcmp(event->arg, "UART_CMD")) {
+ extern void adsp_uart_command_event_handle(struct uart_cmd_event * uart_cmd);
+ adsp_uart_command_event_handle(&event->u.uart_cmd);
+ }
+#endif
+#if TCFG_USER_TWS_ENABLE
+ else if (((u32)event->arg == SYS_BT_EVENT_FROM_TWS)) {
+ /*
+ * tws事件处理函数
+ */
+ bt_tws_connction_status_event_handler(&event->u.bt);
+ }
+#endif
+ break;
+ case SYS_DEVICE_EVENT:
+ /*
+ * 系统设备事件处理
+ */
+ if ((u32)event->arg == DEVICE_EVENT_FROM_CHARGE) {
+#if TCFG_CHARGE_ENABLE
+ return app_charge_event_handler(&event->u.dev);
+#endif
+#if (TCFG_ONLINE_ENABLE || TCFG_CFG_TOOL_ENABLE)
+ } else if ((u32)event->arg == DEVICE_EVENT_FROM_CFG_TOOL) {
+ extern int app_cfg_tool_event_handler(struct cfg_tool_event * cfg_tool_dev);
+ app_cfg_tool_event_handler(&event->u.cfg_tool);
+#endif
+#if TCFG_ONLINE_ENABLE
+ } else if ((u32)event->arg == DEVICE_EVENT_FROM_CI_UART) {
+ ci_data_rx_handler(CI_UART);
+#if TCFG_USER_TWS_ENABLE
+ } else if ((u32)event->arg == DEVICE_EVENT_FROM_CI_TWS) {
+ ci_data_rx_handler(CI_TWS);
+#endif
+#endif
+ } else if ((u32)event->arg == DEVICE_EVENT_FROM_POWER) {
+ return app_power_event_handler(&event->u.dev);
+ }
+#if TCFG_CHARGESTORE_ENABLE
+ else if ((u32)event->arg == DEVICE_EVENT_CHARGE_STORE) {
+ app_chargestore_event_handler(&event->u.chargestore);
+ }
+#endif
+#if TCFG_UMIDIGI_BOX_ENABLE
+ else if ((u32)event->arg == DEVICE_EVENT_UMIDIGI_CHARGE_STORE) {
+ app_umidigi_chargestore_event_handler(&event->u.umidigi_chargestore);
+ }
+#endif
+#if TCFG_TEST_BOX_ENABLE
+ else if ((u32)event->arg == DEVICE_EVENT_TEST_BOX) {
+ app_testbox_event_handler(&event->u.testbox);
+ }
+#endif
+#if TCFG_EAR_DETECT_ENABLE
+ else if ((u32)event->arg == DEVICE_EVENT_FROM_EAR_DETECT) {
+ ear_detect_event_handle(event->u.ear.value);
+ }
+#endif
+#if TCFG_ANC_BOX_ENABLE
+ else if ((u32)event->arg == DEVICE_EVENT_FROM_ANC) {
+ return app_ancbox_event_handler(&event->u.ancbox);
+ }
+#endif
+#if TCFG_EARTCH_EVENT_HANDLE_ENABLE
+ else if ((u32)event->arg == DEVICE_EVENT_FROM_EARTCH) {
+ extern void eartch_event_handle(u8 state);
+ eartch_event_handle(event->u.ear.value);
+ }
+#endif /* #if TCFG_EARTCH_EVENT_HANDLE_ENABLE */
+
+#if APP_ONLINE_DEBUG
+ else if ((u32)event->arg == DEVICE_EVENT_ONLINE_DATA) {
+ extern void app_online_event_handle(int evt_value);
+ app_online_event_handle(event->u.dev.value);
+ }
+#endif /* #if TCFG_EARTCH_EVENT_HANDLE_ENABLE */
+
+ break;
+
+#if TCFG_USER_TWS_ENABLE
+ case SYS_IR_EVENT:
+ g_printf("[SYS_IR_EVENT]");
+#if TCFG_USER_TWS_ENABLE
+ if (get_bt_tws_connect_status()) {
+ if (event->u.ir.event == IR_SENSOR_EVENT_FAR) { //FAR
+ tws_api_sync_call_by_uuid('T', SYNC_CMD_IRSENSOR_EVENT_FAR, 500);
+ } else if (event->u.ir.event == IR_SENSOR_EVENT_NEAR) { //NEAR
+ tws_api_sync_call_by_uuid('T', SYNC_CMD_IRSENSOR_EVENT_NEAR, 500);
+ }
+ } else
+#endif
+ {
+ if (event->u.ir.event == IR_SENSOR_EVENT_FAR) { //FAR
+ g_printf("TWS FAR STOP MUSIC PLAY");
+ g_printf("a2dp_get_status = %d", a2dp_get_status());
+ if (a2dp_get_status() == BT_MUSIC_STATUS_STARTING) {
+ r_printf("STOP...\n");
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PAUSE, 0, NULL);
+ }
+ } else if (event->u.ir.event == IR_SENSOR_EVENT_NEAR) { //NEAR
+ g_printf("TWS NEAR START MUSIC PLAY");
+ g_printf("a2dp_get_status = %d", a2dp_get_status());
+ if (a2dp_get_status() != BT_MUSIC_STATUS_STARTING) {
+ r_printf("START...\n");
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PLAY, 0, NULL);
+ }
+ }
+ }
+
+ return 0;
+
+ case SYS_PBG_EVENT:
+ pbg_user_event_deal(&event->u.pbg);
+ break;
+#endif
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+ /*空间音频校准*/
+ case SYS_AUD_EVENT:
+ if ((u32)event->arg == AUDIO_EVENT_TRIM_IMU_START) {
+ extern int spatial_imu_trim_start();
+ spatial_imu_trim_task_start();
+ } else if ((u32)event->arg == AUDIO_EVENT_TRIM_IMU_STOP) {
+ extern int spatial_imu_trim_task_stop();
+ spatial_imu_trim_task_stop();
+ }
+ break;
+#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
+
+ default:
+ return false;
+ }
+
+ SYS_EVENT_HANDLER_SPECIFIC(event);
+#ifdef CONFIG_BT_BACKGROUND_ENABLE
+ if (app) {
+ default_event_handler(event);
+ }
+#endif
+ return false;
+}
+
+int bt_in_background_event_handler(struct sys_event *event)
+{
+ return event_handler(NULL, event);
+}
+
+u8 bt_app_exit_check(void)
+{
+ int esco_state;
+ if (app_var.siri_stu && app_var.siri_stu != 3) {
+ // siri不退出
+ return 0;
+ }
+ esco_state = get_call_status();
+ if (esco_state == BT_CALL_OUTGOING ||
+ esco_state == BT_CALL_ALERT ||
+ esco_state == BT_CALL_INCOMING ||
+ esco_state == BT_CALL_ACTIVE) {
+ // 通话不退出
+ return 0;
+ }
+
+ return 1;
+}
+
+int bt_app_exit(void *priv)
+{
+ int a2dp_state;
+ init_ok = 0;
+ a2dp_state = a2dp_get_status();
+ extern u8 bt_media_is_running();
+ extern void a2dp_dec_close();
+ if (bt_media_is_running()) {
+ a2dp_dec_close();
+ a2dp_media_clear_packet_before_seqn(0);
+ }
+
+ tone_play_stop();
+
+ user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_DISABLE, 0, NULL);
+ user_send_cmd_prepare(USER_CTRL_WRITE_CONN_DISABLE, 0, NULL);
+ user_send_cmd_prepare(USER_CTRL_PAGE_CANCEL, 0, NULL);
+ user_send_cmd_prepare(USER_CTRL_CONNECTION_CANCEL, 0, NULL);
+ user_send_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
+
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_DISCONNECTED) {
+ return 1;
+ }
+#endif
+ btstack_exit();
+ sys_auto_shut_down_disable();
+ return 1;
+}
+
+static void tone_play_end_callback(void *priv, int flag)
+{
+ int index = (int)priv;
+
+ switch (index) {
+ case IDEX_TONE_BT_MODE:
+ printf("%s:IDEX_TONE_BT_MODE", __FUNCTION__);
+ /* 按键消息使能 */
+ sys_key_event_enable();
+ break;
+ }
+}
+
+/*
+ * earphone 模式状态机, 通过start_app()控制状态切换
+ */
+/* extern int audio_mic_init(); */
+
+static int state_machine(struct application *app, enum app_state state, struct intent *it)
+{
+ int error = 0;
+ static u8 tone_player_err = 0;
+
+ r_printf("bt_state_machine=%d\n", state);
+ switch (state) {
+ case APP_STA_CREATE:
+ /* set_adjust_conn_dac_check(0); */
+#if TCFG_SD0_ENABLE || TCFG_PC_ENABLE
+ STATUS *p_tone = get_tone_config();
+ tone_play_index(p_tone->bt_init_ok, 1);
+#else
+ if (app_var.play_poweron_tone) {
+ STATUS *p_tone = get_tone_config();
+ /* tone_play_index(p_tone->power_on, 1); */
+ //tone_player_err = tone_play_index_with_callback(p_tone->power_on, 1, tone_play_end_callback, (void *)IDEX_TONE_BT_MODE);
+ sys_key_event_enable();
+ } else {
+#ifdef CONFIG_CURRENT_SOUND_DEAL_ENABLE
+ dac_analog_power_control(0);
+#endif
+ }
+#endif
+ break;
+ case APP_STA_START:
+ //进入蓝牙模式,UI退出充电状态
+ ui_update_status(STATUS_EXIT_LOWPOWER);
+ if (!it) {
+ break;
+ }
+ switch (it->action) {
+ case ACTION_EARPHONE_MAIN://Jim
+ /*
+ * earphone 模式初始化
+ */
+
+ clk_set("sys", BT_NORMAL_HZ);
+ u32 sys_clk = clk_get("sys");
+ bt_pll_para(TCFG_CLOCK_OSC_HZ, sys_clk, 0, 0);
+
+ /* bredr_set_dut_enble(1, 1); */
+ bt_function_select_init();
+ //bredr_handle_register();
+ EARPHONE_STATE_INIT();
+ btstack_init();
+#if 0//TCFG_USER_TWS_ENABLE
+ tws_profile_init();
+ sys_key_event_filter_disable();
+#endif
+
+ /* 按键消息使能 */
+ sys_key_event_enable();
+#if TCFG_AUDIO_WIDE_AREA_TAP_ENABLE
+ extern int audio_wat_click_open();
+ audio_wat_click_open();
+#endif /*TCFG_AUDIO_WIDE_AREA_TAP_ENABLE*/
+ sys_auto_shut_down_enable();
+ bt_sniff_feature_init();
+ sys_auto_sniff_controle(MY_SNIFF_EN, NULL);
+ app_var.dev_volume = -1;
+ break;
+ case ACTION_A2DP_START:
+#if (BT_SUPPORT_MUSIC_VOL_SYNC && CONFIG_BT_BACKGROUND_ENABLE)
+ app_audio_set_volume(APP_AUDIO_STATE_MUSIC, app_var.bt_volume, 1);
+ r_printf("BT_BACKGROUND RESET ACTION_A2DP_START STATE_MUSIC bt_volume=%d\n", app_var.bt_volume);
+#endif
+ a2dp_dec_open(0);
+ break;
+ case ACTION_BY_KEY_MODE:
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PLAY, 0, NULL);
+ break;
+ case ACTION_TONE_PLAY:
+ STATUS *p_tone = get_tone_config();
+ tone_play_index(p_tone->bt_init_ok, 1);
+ break;
+ case ACTION_DO_NOTHING:
+ break;
+ }
+ break;
+ case APP_STA_PAUSE:
+ //转入后台运行
+#if CONFIG_BT_BACKGROUND_ENABLE
+ error = bt_switch_to_background();
+ if (error == 0) {
+ sys_auto_shut_down_disable();
+ }
+#if (BT_SUPPORT_MUSIC_VOL_SYNC)
+ app_var.bt_volume = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
+ if (app_var.dev_volume != -1) { //切换到其它模式恢复上一次的音量
+ r_printf("resume dev_volume=%d\n", app_var.dev_volume);
+ app_audio_set_volume(APP_AUDIO_STATE_MUSIC, app_var.dev_volume, 1);
+ app_var.dev_volume = -1;
+ }
+#endif
+ log_info("APP_STA_PAUSE: %d\n", error);
+#endif
+ break;
+ case APP_STA_RESUME:
+#if (BT_SUPPORT_MUSIC_VOL_SYNC && CONFIG_BT_BACKGROUND_ENABLE)
+ app_var.dev_volume = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
+ r_printf("APP_STA_RESUME rec dev_volume=%d\n", app_audio_get_volume(APP_AUDIO_STATE_MUSIC));
+#endif
+ //恢复前台运行
+ sys_auto_shut_down_disable();
+ sys_key_event_enable();
+ break;
+ case APP_STA_STOP:
+ break;
+ case APP_STA_DESTROY:
+ r_printf("APP_STA_DESTROY\n");
+ if (!app_var.goto_poweroff_flag) {
+ bt_app_exit(NULL);
+ }
+ break;
+ }
+
+ return error;
+}
+
+static const struct application_operation app_earphone_ops = {
+ .state_machine = state_machine,
+ .event_handler = event_handler,
+};
+
+/*
+ * 注册earphone模式
+ */
+REGISTER_APPLICATION(app_earphone) = {
+ .name = "earphone",
+ .action = ACTION_EARPHONE_MAIN,
+ .ops = &app_earphone_ops,
+ .state = APP_STA_DESTROY,
+};
diff --git a/apps/earphone/eartch_event_deal.c b/apps/earphone/eartch_event_deal.c
new file mode 100644
index 0000000..ec247c9
--- /dev/null
+++ b/apps/earphone/eartch_event_deal.c
@@ -0,0 +1,672 @@
+//===========================================================//
+// LP TOUCH EAR EVENT HANDLE //
+//===========================================================//
+//1.入耳事件产生 --> sync state --> state 回调中处理播放暂停, 通话转换
+#include "includes.h"
+#include "key_event_deal.h"
+#include "btstack/avctp_user.h"
+#if TCFG_USER_TWS_ENABLE
+#include "bt_tws.h"
+#endif /* #if TCFG_USER_TWS_ENABLE */
+#include "tone_player.h"
+#include "app_config.h"
+#include "classic/tws_api.h"
+
+#define LOG_TAG_CONST EARTCH_EVENT_DEAL
+#define LOG_TAG "[EARTCH_EVENT_DEAL]"
+/* #define LOG_ERROR_ENABLE */
+/* #define LOG_DEBUG_ENABLE */
+#define LOG_INFO_ENABLE
+#define LOG_DUMP_ENABLE
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+/* #define SUPPORT_MS_EXTENSIONS */
+/* #ifdef SUPPORT_MS_EXTENSIONS */
+/* #pragma bss_seg( ".eartch_event_deal_bss") */
+/* #pragma data_seg(".eartch_event_deal_data") */
+/* #pragma const_seg(".eartch_event_deal_const") */
+/* #pragma code_seg(".eartch_event_deal_code") */
+/* #endif */
+
+#if TCFG_EARTCH_EVENT_HANDLE_ENABLE
+//========================================================================================//
+//入耳检测UI控制流程:
+//1.控制音乐播放条件:
+// 1)两只取下, 音乐暂停, 15s内佩戴耳机, 控制音乐为播放状态;
+// 2)一只取下, 音乐暂停, 没有时间限制, 控制音乐为播放状态;
+//2.控制音乐暂停条件: 当音乐播放时, 取下任意一个耳机, 音乐暂停;
+//3.控制通话语音转移到远端: 在通话状态下, 当两个耳机都取下, 语音由耳机端转移到远端;
+//4.控制通话语音转移到耳机端: 在通话状态下, 佩戴任意一个耳机, 语音由手机端端转移到耳机端;
+//========================================================================================//
+
+bool __attribute__((weak)) get_tws_sibling_connect_state(void)
+{
+ return FALSE;
+}
+
+#define TWS_FUNC_ID_EARTCH_SYNC TWS_FUNC_ID('E', 'A', 'T', 'H')
+
+
+#define TCFG_EARTCH_MUSIC_CTL_TIMEOUT_ENABLE 0 //对耳不在耳, 15s超时后入耳控制音乐播放无效
+#define TCFG_EARTCH_MUSIC_CTL_A2DP_CONNECT 0 //对耳不在耳, 断开a2dp链路, 音乐转移到手机扬声器
+#define TCFG_EARTCH_CALL_CTL_SCO_CONNECT 1 //对耳不在耳, 断开SCO链路, 通话转移到手机扬声器
+#define TCFG_EARTCH_AUTO_CHANGE_MASTER 1
+#define TCFG_EARTCH_SWITCH_CFG_ENABLE 1 //入耳消息处理使能开关, 配置项保存到vm, 支持动态开关
+
+struct eartch_control {
+ u8 eartch_event_deal_en;
+ u8 local_state: 1;
+ u8 remote_state: 1;
+ u8 last_state: 1;
+ u8 event_source: 1;
+ u8 a2dp_connect_state: 1;
+ u8 a2dp_send_flag: 1;
+ u8 music_ctrl_en: 1;
+ u8 state_check_cnt;
+ u8 a2dp_play_state_cnt;
+ u8 a2dp_stop_state_cnt;
+ u16 state_check_timer;
+ u16 music_ctrl_en_timer;
+ u16 a2dp_monitor_timer;
+};
+
+static struct eartch_control _eartch = {
+ .local_state = EARTCH_STATE_OUT,
+ .remote_state = EARTCH_STATE_OUT,
+ .last_state = EARTCH_STATE_OUT,
+};
+
+#define __this (&_eartch)
+
+//============= 关于配置项保存信息 ==========//
+#define EARTCH_SWITCH_CFG_LEN 1 //配置项长度
+
+enum EARTCH_TWS_SYNC_CMD {
+ EARTCH_TWS_STATE_IN = 0x00,
+ EARTCH_TWS_STATE_OUT = 0x01,
+ EARTCH_TWS_STATE_TRIM_OK = 0x02,
+ EARTCH_TWS_STATE_TRIM_ERR = 0x03,
+ EARTCH_TWS_CFG_SAVE_EVENT_DEAL_ENABLE = 0x10,
+ EARTCH_TWS_CFG_SAVE_EVENT_DEAL_DISABLE = 0x20,
+};
+
+u8 earin_status = 0;
+u8 last_status = 0;
+u16 earin_lock_time = 0;
+
+static void eartch_post_event(u8 event)
+{
+ struct sys_event e;
+ user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL);
+ e.type = SYS_DEVICE_EVENT;
+ e.arg = (void *)DEVICE_EVENT_FROM_EARTCH;
+ e.u.ear.value = event;
+ log_info("notify event: %d", event);
+ sys_event_notify(&e);
+}
+
+static void eartch_send_bt_ctrl_cmd(u8 cmd)
+{
+ static u8 last_cmd = 0;
+ static u32 last_jiffies = 0;
+ u32 cur_jiffies = jiffies;
+ if (last_cmd == cmd) {
+ if (jiffies_to_msecs(cur_jiffies - last_jiffies) < 1000) {
+ log_debug("same cmd: %d", cmd);
+ return;
+ }
+ }
+ log_info("send cmd: %d", cmd);
+ last_cmd = cmd;
+ last_jiffies = cur_jiffies;
+ user_send_cmd_prepare(cmd, 0, NULL);
+}
+
+static void eartch_music_state_check_timer_del(void)
+{
+ log_debug("timer del");
+ if (__this->state_check_timer) {
+ usr_timer_del(__this->state_check_timer);
+ }
+ __this->state_check_timer = 0;
+ __this->state_check_cnt = 0;
+}
+
+static void eartch_music_state_check(void *priv)
+{
+ struct eartch_control *eartch = (struct eartch_control *)priv;
+
+ if (get_total_connect_dev() == 0) {
+ log_info("no connect dev");
+ eartch_music_state_check_timer_del();
+ return;
+ }
+
+ u8 a2dp_state;
+
+ log_debug("music_check_state cnt: %d, a2dp_connect_state = %d", __this->state_check_cnt, __this->a2dp_connect_state);
+ if (__this->a2dp_connect_state) {
+ a2dp_state = a2dp_get_status();
+ log_debug("a2dp_state = %d", a2dp_state);
+ if (__this->last_state == EARTCH_STATE_IN) {
+ if (__this->music_ctrl_en) {
+ if (a2dp_state != BT_MUSIC_STATUS_STARTING) {
+ log_info("SEND PLAY");
+ eartch_send_bt_ctrl_cmd(USER_CTRL_AVCTP_OPID_PLAY);
+ __this->a2dp_send_flag = 0;
+ eartch_music_state_check_timer_del();
+ }
+ }
+ } else {
+ if (a2dp_state == BT_MUSIC_STATUS_STARTING) {
+ log_info("SEND PAUSE");
+ eartch_send_bt_ctrl_cmd(USER_CTRL_AVCTP_OPID_PAUSE);
+ __this->a2dp_send_flag = 0;
+ eartch_music_state_check_timer_del();
+ }
+ }
+ }
+
+ __this->state_check_cnt++;
+ if (__this->state_check_cnt > 15) {
+ eartch_music_state_check_timer_del();
+ }
+}
+
+static void eartch_music_state_check_timer_add(void)
+{
+ if (__this->state_check_timer != 0) {
+ eartch_music_state_check_timer_del();
+ }
+
+ log_debug("timer add");
+
+// __this->state_check_timer = usr_timer_add((void *)__this, eartch_music_state_check, 200, 1);
+}
+
+static void eartch_a2dp_status_callback_handle(u8 conn_flag)
+{
+ log_debug("update a2dp conflag: %d", conn_flag);
+ if (conn_flag) {
+ __this->a2dp_connect_state = 1;
+ log_debug("a2dp_send_flag: %d, event_deal_en: %d", __this->a2dp_send_flag, __this->eartch_event_deal_en);
+ if (__this->eartch_event_deal_en) {
+ if (__this->a2dp_send_flag) {
+ if (__this->music_ctrl_en) {
+ eartch_music_state_check_timer_add();
+ }
+ }
+ }
+ } else {
+ __this->a2dp_connect_state = 0;
+ }
+}
+
+
+
+static void eartch_sync_tws_state(u8 state)
+{
+ if (get_tws_sibling_connect_state() == TRUE) {
+ tws_api_send_data_to_sibling(&state, 1, TWS_FUNC_ID_EARTCH_SYNC);
+ }
+}
+
+
+static void eartch_sync_tws_state_deal(void *_data, u16 len, bool rx)
+{
+ u8 *data = (u8 *)_data;
+ u8 state = data[0];
+ if (rx) {
+ if (state <= EARTCH_TWS_STATE_OUT) {
+ __this->remote_state = state & BIT(0);
+ __this->event_source = 0;
+ log_debug("sync remote_state: %d", __this->remote_state);
+ }
+ }
+ //TODO: post event
+ log_debug("state: %d, local_state: %d, remote_state = %d", state, __this->local_state, __this->remote_state);
+ eartch_post_event(state);
+}
+
+static void eartch_music_ctrl_timeout_handle(void *priv)
+{
+ log_info("Disnable music ctrl");
+ __this->music_ctrl_en = 0;
+ __this->music_ctrl_en_timer = 0;
+}
+
+
+static void eartch_music_ctrl_timeout_del(void)
+{
+ if (__this->music_ctrl_en_timer) {
+ usr_timer_del(__this->music_ctrl_en_timer);
+ __this->music_ctrl_en_timer = 0;
+ }
+}
+
+static void eartch_music_ctrl_timeout_add(void)
+{
+ if (__this->music_ctrl_en_timer) {
+ eartch_music_ctrl_timeout_del();
+ }
+ __this->music_ctrl_en_timer = usr_timeout_add((void *)__this, eartch_music_ctrl_timeout_handle, 15000, 1);
+}
+
+#define A2DP_PLAY_STATE_CNT 2
+#define A2DP_STOP_STATE_CNT 2
+static void eartch_a2dp_status_monitor(void *priv)
+{
+ if (get_total_connect_dev() == 0) {
+ __this->a2dp_stop_state_cnt = 0;
+ __this->a2dp_play_state_cnt = 0;
+ return;
+ }
+ u8 a2dp_state = a2dp_get_status();
+ if (a2dp_state == BT_MUSIC_STATUS_STARTING) { //在播歌
+ __this->a2dp_stop_state_cnt = 0;
+ __this->a2dp_play_state_cnt++;
+ if (__this->a2dp_play_state_cnt > A2DP_PLAY_STATE_CNT) {
+ if (__this->music_ctrl_en == 0) {
+ log_info("Enable music ctrl");
+ __this->music_ctrl_en = 1;
+ }
+ }
+ } else {
+ __this->a2dp_play_state_cnt = 0;
+ __this->a2dp_stop_state_cnt++;
+ }
+}
+
+
+static void eartch_a2dp_status_monitor_init(u8 init)
+{
+ if (__this->a2dp_monitor_timer) {
+ sys_timer_del(__this->a2dp_monitor_timer);
+ __this->a2dp_monitor_timer = 0;
+ }
+ if (init) {
+ __this->a2dp_monitor_timer = sys_timer_add(NULL, eartch_a2dp_status_monitor, 500);
+ __this->a2dp_stop_state_cnt = 0;
+ __this->a2dp_play_state_cnt = 0;
+ }
+}
+
+extern void test_esco_role_switch(u8 flag);
+//master: local out
+static void eartch_in_bt_control_handle(void)
+{
+ u8 call_status = get_call_status();
+ u8 tws_con = get_tws_sibling_connect_state();
+ u8 role;
+ u8 a2dp_state;
+ if (tws_con) {
+ role = tws_api_get_role();
+ }
+
+ if (call_status != BT_CALL_HANGUP) {
+ //通话中
+#if TCFG_EARTCH_CALL_CTL_SCO_CONNECT
+ if (call_status == BT_CALL_ACTIVE) {//通话中
+ if ((tws_con && ((__this->local_state != EARTCH_STATE_IN) || (__this->remote_state != EARTCH_STATE_IN))) //对耳戴上一只
+ || (!tws_con)) { //单耳且入耳
+ log_info("USER_CTRL_CONN_SCO\n");
+ eartch_send_bt_ctrl_cmd(USER_CTRL_CONN_SCO);
+ }
+ }
+#endif /* #if TCFG_EARTCH_CALL_CTL_SCO_CONNECT */
+#if TCFG_EARTCH_AUTO_CHANGE_MASTER
+ if (tws_con && ((role == TWS_ROLE_MASTER) && ((__this->local_state == EARTCH_STATE_OUT) && (__this->remote_state == EARTCH_STATE_IN)))) {//主机不在耳,从机在耳,切换主从
+ log_info("master no inside, start change role");
+ tws_api_auto_role_switch_disable();
+ test_esco_role_switch(1); //主机调用
+ }
+#endif /* #if TCFG_EARTCH_AUTO_CHANGE_MASTER */
+ } else {
+#if TCFG_EARTCH_MUSIC_CTL_A2DP_CONNECT
+ log_info("a2dp_connect_state: %d", __this->a2dp_connect_state);
+ if (__this->a2dp_connect_state == 0) {
+ /* if ((tws_con && (((__this->local_state == EARTCH_STATE_OUT) && (__this->remote_state == EARTCH_STATE_IN)) || */
+ /* ((__this->local_state == EARTCH_STATE_IN) && (__this->remote_state == EARTCH_STATE_OUT)))) || //对耳一只戴上 */
+ /* (!tws_con)) { //单耳 */
+ log_info("CONN_A2DP");
+ eartch_send_bt_ctrl_cmd(USER_CTRL_CONN_A2DP); //链接链路
+ __this->a2dp_send_flag = 1;
+ /* } */
+ } else
+#endif /* #if TCFG_EARTCH_MUSIC_CTL_A2DP_CONNECT */
+ {
+ log_info("music ctrl en: %d", __this->music_ctrl_en);
+ if (__this->music_ctrl_en) {
+ a2dp_state = a2dp_get_status();
+ log_info("a2dp_state: %d", a2dp_state);
+ if (a2dp_state != BT_MUSIC_STATUS_STARTING) { //没有播放
+ log_info("SEND PLAY");
+ eartch_send_bt_ctrl_cmd(USER_CTRL_AVCTP_OPID_PLAY);
+ } else {
+ eartch_music_state_check_timer_add();
+ }
+ }
+ }
+ }
+}
+
+static void eartch_out_bt_control_handle(void)
+{
+ u8 call_status = get_call_status();
+ u8 tws_con = get_tws_sibling_connect_state();
+ u8 role;
+ u8 a2dp_state;
+ if (tws_con) {
+ role = tws_api_get_role();
+ }
+
+ if (call_status != BT_CALL_HANGUP) {//通话中
+ if (call_status == BT_CALL_ACTIVE) {//通话中
+ if ((tws_con && ((__this->local_state == EARTCH_STATE_OUT) && (__this->remote_state == EARTCH_STATE_OUT))) //对耳且都不在耳朵上
+ || (!tws_con)) { //单耳且不在耳朵
+#if TCFG_EARTCH_CALL_CTL_SCO_CONNECT
+ log_info("USER_CTRL_DISCONN_SCO\n");
+ eartch_send_bt_ctrl_cmd(USER_CTRL_DISCONN_SCO);
+#endif /* #if TCFG_EARTCH_CALL_CTL_SCO_CONNECT */
+ }
+#if TCFG_EARTCH_AUTO_CHANGE_MASTER
+ if (tws_con && ((role == TWS_ROLE_MASTER) && ((__this->local_state == EARTCH_STATE_OUT) && (__this->remote_state == EARTCH_STATE_IN)))) {//主机不在耳,从机在耳,切换主从
+ log_info("master no inside, start change role");
+ tws_api_auto_role_switch_disable();
+ test_esco_role_switch(1); //主机调用
+ }
+#endif /* #if TCFG_EARTCH_AUTO_CHANGE_MASTER */
+ }
+ } else {
+ log_info("a2dp_connect_state: %d", __this->a2dp_connect_state);
+ if (__this->a2dp_connect_state) {
+#if TCFG_EARTCH_MUSIC_CTL_A2DP_CONNECT
+ if ((tws_con && ((__this->local_state == EARTCH_STATE_OUT) && (__this->remote_state == EARTCH_STATE_OUT))) || //对耳出耳, 断开链路
+ (!tws_con)) { //单耳出耳
+ log_info("DISCON A2DP");
+ eartch_send_bt_ctrl_cmd(USER_CTRL_DISCONN_A2DP);
+ } else
+#endif /* #if TCFG_EARTCH_MUSIC_CTL_A2DP_CONNECT */
+ {
+ a2dp_state = a2dp_get_status();
+ log_info("a2dp_state: %d", a2dp_state);
+ if (a2dp_state == BT_MUSIC_STATUS_STARTING) { //在播放
+ log_info("SEND PAUSE");
+ eartch_send_bt_ctrl_cmd(USER_CTRL_AVCTP_OPID_PAUSE);
+ } else {
+ eartch_music_state_check_timer_add();
+ }
+ }
+ }
+ }
+}
+//-------------测试盒流程-----------------//
+u8 testbox_in_ear_detect_test_flag_get(void);
+void lp_touch_key_testbox_inear_trim(u8 flag);
+
+enum {
+ IN_EAR_TRIM_SUCC_KEY = 0xf4,
+ IN_EAR_DETECT_IN,
+ IN_EAR_DETECT_OUT,
+ IN_EAR_TRIM_FAIL_KEY,
+};
+
+void test_in_ear_detect_state_notify(u8 key)
+{
+ user_send_cmd_prepare(USER_CTRL_TEST_KEY, 1, &key); //
+}
+
+__attribute__((weak))
+void lp_touch_key_testbox_inear_trim(u8 flag)
+{
+
+}
+
+void eartch_testbox_flag(u8 flag)
+{
+ lp_touch_key_testbox_inear_trim(flag);
+}
+
+static void eartch_bt_event_control_handle(u8 event)
+{
+ u8 call_status;
+ if (get_total_connect_dev() == 0) {
+ log_info("no connect dev");
+ return;
+ }
+
+ u8 tws_con = get_tws_sibling_connect_state();
+
+ if (event == EARTCH_STATE_IN) {
+ eartch_music_ctrl_timeout_del();
+ eartch_in_bt_control_handle();
+ } else {
+#if TCFG_EARTCH_MUSIC_CTL_TIMEOUT_ENABLE
+ if ((tws_con && ((__this->local_state == EARTCH_STATE_OUT) && (__this->remote_state == EARTCH_STATE_OUT))) //对耳且都不在耳朵上
+ || (!tws_con)) { //单耳且不在耳朵
+ if (__this->music_ctrl_en) {
+ eartch_music_ctrl_timeout_add();
+ }
+ }
+#endif /* #if TCFG_EARTCH_MUSIC_CTL_TIMEOUT_ENABLE */
+ eartch_out_bt_control_handle();
+
+ }
+}
+
+static void eartch_event_deal_en_cfg_save(u8 cfg_data)
+{
+ u8 rdata = 0;
+ int ret = 0;
+
+ ret = syscfg_read(CFG_EARTCH_ENABLE_ID, &rdata, EARTCH_SWITCH_CFG_LEN);
+ if (ret == EARTCH_SWITCH_CFG_LEN) {
+ if (rdata == cfg_data) {
+ log_debug("cfg same: %d", rdata);
+ return;
+ }
+ }
+
+ rdata = cfg_data;
+ log_debug("cfg write: %d", rdata);
+ ret = syscfg_write(CFG_EARTCH_ENABLE_ID, &rdata, EARTCH_SWITCH_CFG_LEN);
+ if (ret != EARTCH_SWITCH_CFG_LEN) {
+ log_error("cfg write err!!!");
+ }
+}
+
+
+void eartch_state_update(u8 state)
+{
+ switch (state) {
+ case EARTCH_TWS_STATE_IN:
+ case EARTCH_TWS_STATE_OUT:
+ __this->local_state = state;
+ __this->event_source = 1;
+ log_debug("update local_state: %d", __this->local_state);
+
+ if (__this->eartch_event_deal_en == 0) {
+ log_debug("eartch event deal en 0");
+ return;
+ }
+ break;
+ case EARTCH_TWS_STATE_TRIM_OK:
+ if (testbox_in_ear_detect_test_flag_get()) {
+ test_in_ear_detect_state_notify(IN_EAR_TRIM_SUCC_KEY);
+ }
+ return;
+
+ case EARTCH_TWS_STATE_TRIM_ERR:
+ if (testbox_in_ear_detect_test_flag_get()) {
+ test_in_ear_detect_state_notify(IN_EAR_TRIM_FAIL_KEY);
+ }
+ return;
+ }
+
+ if (get_tws_sibling_connect_state() == TRUE) {
+ eartch_sync_tws_state(state);
+ } else {
+ eartch_post_event(state);
+ }
+
+}
+
+extern void eartch_hardware_suspend(void);
+extern void eartch_hardware_recover(void);
+
+__attribute__((weak))
+void eartch_hardware_suspend(void)
+{
+ return;
+}
+
+__attribute__((weak))
+void eartch_hardware_recover(void)
+{
+ return;
+}
+
+void eartch_event_deal_enable(void)
+{
+ __this->eartch_event_deal_en = 1;
+#if TCFG_EARTCH_MUSIC_CTL_TIMEOUT_ENABLE
+ eartch_a2dp_status_monitor_init(1);
+#endif
+ eartch_hardware_recover();
+}
+
+void eartch_event_deal_disable()
+{
+ __this->eartch_event_deal_en = 0;
+#if TCFG_EARTCH_MUSIC_CTL_TIMEOUT_ENABLE
+ eartch_a2dp_status_monitor_init(0);
+#endif
+ eartch_hardware_suspend();
+}
+
+void eartch_event_deal_enable_cfg_save(u8 en)
+{
+#if TCFG_EARTCH_SWITCH_CFG_ENABLE
+ if (en) {
+ eartch_event_deal_enable();
+ eartch_event_deal_en_cfg_save(1);
+ } else {
+ eartch_event_deal_disable();
+ eartch_event_deal_en_cfg_save(0);
+ }
+#endif /* #if TCFG_EARTCH_SWITCH_CFG_ENABLE */
+}
+
+void eartch_handle()
+{
+ if (earin_status == EARTCH_STATE_IN) {
+ if (get_tws_sibling_connect_state() == TRUE) {
+ if ((__this->remote_state == EARTCH_STATE_OUT) && (__this->local_state == EARTCH_STATE_IN)) {
+ log_info("tone_play1");
+ tone_play(TONE_NORMAL, 1);
+ }
+ } else {
+ log_info("tone_play2");
+ tone_play(TONE_NORMAL, 1);
+ }
+
+ if (testbox_in_ear_detect_test_flag_get()) {
+ test_in_ear_detect_state_notify(IN_EAR_DETECT_IN);
+ }
+ } else {
+ if (testbox_in_ear_detect_test_flag_get()) {
+ test_in_ear_detect_state_notify(IN_EAR_DETECT_OUT);
+ }
+
+ }
+
+
+ eartch_bt_event_control_handle(earin_status);
+ __this->last_state = earin_status;
+ sys_timer_del(earin_lock_time);
+ earin_lock_time = 0;
+}
+
+void eartch_event_handle(u8 event)
+{
+ switch (event) {
+ case EARTCH_TWS_STATE_IN:
+ case EARTCH_TWS_STATE_OUT:
+ last_status = event;
+ if (earin_lock_time == 0) {
+ earin_status = event;
+ earin_lock_time = sys_timeout_add(NULL, eartch_handle, 500);
+ } else {
+ if (earin_status != last_status) {
+ earin_status = last_status;
+ sys_timer_modify(earin_lock_time, 500);
+ }
+ }
+ break;
+
+#if TCFG_EARTCH_SWITCH_CFG_ENABLE
+ case EARTCH_TWS_CFG_SAVE_EVENT_DEAL_ENABLE:
+ eartch_event_deal_enable_cfg_save(1);
+ break;
+
+ case EARTCH_TWS_CFG_SAVE_EVENT_DEAL_DISABLE:
+ eartch_event_deal_enable_cfg_save(0);
+ break;
+#endif /* #if TCFG_EARTCH_SWITCH_CFG_ENABLE */
+
+ default:
+ break;
+ }
+}
+
+void a2dp_connect_status_register(void (*cbk)(u8 conn_flag));
+int eartch_event_deal_init(void)
+{
+ u8 rdata = 0;
+ int ret = 0;
+
+#if TCFG_EARTCH_SWITCH_CFG_ENABLE
+ ret = syscfg_read(CFG_EARTCH_ENABLE_ID, &rdata, EARTCH_SWITCH_CFG_LEN);
+ if (ret == EARTCH_SWITCH_CFG_LEN) {
+ __this->eartch_event_deal_en = rdata;
+ log_debug("switch cfg: %d", rdata);
+ } else
+#endif /* #if TCFG_EARTCH_SWITCH_CFG_ENABLE */
+ {
+ log_debug("switch cfg not write, default enable");
+ __this->eartch_event_deal_en = 1;
+ }
+
+#if TCFG_EARTCH_MUSIC_CTL_A2DP_CONNECT
+ a2dp_connect_status_register(eartch_a2dp_status_callback_handle);
+#else
+ __this->a2dp_connect_state = 1;
+#endif /* #if TCFG_EARTCH_MUSIC_CTL_A2DP_CONNECT */
+#if TCFG_EARTCH_MUSIC_CTL_TIMEOUT_ENABLE
+ if (__this->eartch_event_deal_en) {
+ eartch_a2dp_status_monitor_init(1);
+ }
+#else
+ __this->music_ctrl_en = 1;
+#endif /* #if TCFG_EARTCH_MUSIC_CTL_TIMEOUT_ENABLE */
+ return __this->eartch_event_deal_en;
+}
+
+
+void eartch_event_deal_enable_cfg_tws_save(u8 en)
+{
+ if (en) {
+ eartch_state_update(EARTCH_TWS_CFG_SAVE_EVENT_DEAL_ENABLE);
+ } else {
+ eartch_state_update(EARTCH_TWS_CFG_SAVE_EVENT_DEAL_DISABLE);
+ }
+}
+
+
+REGISTER_TWS_FUNC_STUB(ear_lptch_sync) = {
+ .func_id = TWS_FUNC_ID_EARTCH_SYNC,
+ .func = eartch_sync_tws_state_deal,
+};
+
+#endif /* #if TCFG_EARTCH_EVENT_HANDLE_ENABLE */
diff --git a/apps/earphone/font/fontinit.c b/apps/earphone/font/fontinit.c
new file mode 100644
index 0000000..3799992
--- /dev/null
+++ b/apps/earphone/font/fontinit.c
@@ -0,0 +1,87 @@
+#include "font/font_all.h"
+#include "font/language_list.h"
+#include "app_config.h"
+#include "ui/res_config.h"
+
+#if TCFG_UI_ENABLE
+#if (TCFG_SPI_LCD_ENABLE || TCFG_SIMPLE_LCD_ENABLE)
+
+
+extern void platform_putchar(struct font_info *info, u8 *pixel, u16 width, u16 height, u16 x, u16 y);//字库输出显示函数
+extern void ui_simple_putchar(struct font_info *info, u8 *pixel, u16 width, u16 height, u16 x, u16 y);//字库输出显示函数
+
+#if TCFG_SPI_LCD_ENABLE
+#define font_putchar (platform_putchar)
+#else
+#define font_putchar (ui_simple_putchar)
+#endif
+
+/* 语言字库配置 */
+
+#define LANGUAGE BIT(Chinese_Simplified)|\
+ BIT(English)|\
+ BIT(Chinese_Traditional)
+
+const struct font_info font_info_table[] = {
+
+#if LANGUAGE&BIT(Chinese_Simplified)
+ //gb2312
+ {
+ .language_id = Chinese_Simplified,
+ .flags = FONT_SHOW_PIXEL | FONT_SHOW_MULTI_LINE,
+ .pixel.file.name = (char *)FONT_PATH"F_GB2312.PIX",
+ .ascpixel.file.name = (char *)FONT_PATH"F_ASCII.PIX",
+ .tabfile.name = (char *)FONT_PATH"F_GB2312.TAB",
+ .isgb2312 = true,
+ .bigendian = false,
+ .putchar = font_putchar,
+ },
+ //gbk
+ /* { */
+ /* .language_id = Chinese_Simplified, */
+ /* .flags = FONT_SHOW_PIXEL | FONT_SHOW_MULTI_LINE, */
+ /* .pixel.file.name = (char *)"mnt/sdfile/res/F_GBK.PIX", */
+ /* .ascpixel.file.name = (char *)"mnt/sdfile/res/F_ASCII.PIX", */
+ /* .tabfile.name = (char *)"mnt/sdfile/res/F_GBK.TAB", */
+ /* .isgb2312 = false, */
+ /* .bigendian = false, */
+ /* .putchar = platform_putchar, */
+ /* }, */
+#endif
+
+#if LANGUAGE&BIT(Chinese_Traditional)
+ {
+ .language_id = Chinese_Traditional,
+ .flags = FONT_SHOW_PIXEL | FONT_SHOW_MULTI_LINE,
+ .pixel.file.name = (char *)FONT_PATH"F_GBK.PIX",
+ .ascpixel.file.name = (char *)FONT_PATH"F_ASCII.PIX",
+ .tabfile.name = (char *)FONT_PATH"F_GBK.TAB",
+ .isgb2312 = false,
+ .bigendian = false,
+ .putchar = font_putchar,
+ },
+#endif
+
+#if LANGUAGE&BIT(English)
+ {
+ .language_id = English,
+ .flags = FONT_SHOW_PIXEL | FONT_SHOW_MULTI_LINE,
+ .pixel.file.name = (char *)"mnt/sdfile/res/F_GBK.PIX",
+ .ascpixel.file.name = (char *)"mnt/sdfile/res/F_ASCII.PIX",
+ .tabfile.name = (char *)"mnt/sdfile/res/F_GBK.TAB",
+ .isgb2312 = false,
+ .bigendian = false,
+ .putchar = font_putchar,
+ },
+#endif
+ {
+ .language_id = 0,//不能删
+ },
+
+};
+
+
+
+
+#endif
+#endif
diff --git a/apps/earphone/idle.c b/apps/earphone/idle.c
new file mode 100644
index 0000000..f0564c8
--- /dev/null
+++ b/apps/earphone/idle.c
@@ -0,0 +1,251 @@
+#include "system/includes.h"
+#include "media/includes.h"
+#include "app_config.h"
+#include "app_action.h"
+#include "tone_player.h"
+#include "asm/charge.h"
+#include "app_charge.h"
+#include "app_main.h"
+#include "ui_manage.h"
+#include "vm.h"
+//#include "app_chargestore.h"
+//#include "app_umidigi_chargestore.h"
+#include "app_testbox.h"
+#include "user_cfg.h"
+#include "default_event_handler.h"
+
+#if TCFG_ANC_BOX_ENABLE
+#include "app_ancbox.h"
+#endif
+
+#define LOG_TAG_CONST APP_IDLE
+#define LOG_TAG "[APP_IDLE]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#if CHARGING_CLEAN_PHONE_INFO
+#include "key_event_deal.h"
+#include "btstack/btstack_typedef.h"
+#endif
+
+#ifdef CONFIG_MEDIA_DEVELOP_ENABLE
+#define AUDIO_PLAY_EVENT_END AUDIO_DEC_EVENT_END
+#endif /* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
+
+static void app_idle_enter_softoff(void)
+{
+ //ui_update_status(STATUS_POWEROFF);
+ /*while (get_ui_busy_status()) {
+ log_info("ui_status:%d\n", get_ui_busy_status());
+ }*/
+#if TCFG_CHARGE_ENABLE
+ if (get_lvcmp_det() && (0 == get_charge_full_flag())) {
+ log_info("charge inset, system reset!\n");
+ cpu_reset();
+ }
+#endif
+
+#if TCFG_SMART_VOICE_ENABLE
+ extern void audio_smart_voice_detect_close(void);
+ audio_smart_voice_detect_close();
+#endif
+
+
+#ifdef CONFIG_BOARD_AISPEECH_VAD_ASR
+ extern void ais_platform_asr_close(void);
+ ais_platform_asr_close();
+#endif /*CONFIG_BOARD_AISPEECH_VAD_ASR*/
+
+ extern void dac_power_off(void);
+ dac_power_off(); // 关机前先关dac
+
+ power_set_soft_poweroff();
+}
+
+static int app_idle_tone_event_handler(struct device_event *dev)
+{
+ int ret = false;
+
+ switch (dev->event) {
+ case AUDIO_PLAY_EVENT_END:
+ if (app_var.goto_poweroff_flag) {
+ log_info("audio_play_event_end,enter soft poweroff");
+ app_idle_enter_softoff();
+ }
+ break;
+ }
+
+ return ret;
+}
+
+#if CHARGING_CLEAN_PHONE_INFO
+
+#define IDLE_CLEAN_INFO_CNT 20
+
+static u8 idle_key_table[KEY_NUM_MAX][KEY_EVENT_MAX] = {
+ //SHORT LONG HOLD UP DOUBLE TRIPLE
+ {KEY_NULL, KEY_CLEAN_PHONE_INFO, KEY_CLEAN_PHONE_INFO_HOLD, KEY_CLEAN_PHONE_INFO_UP, KEY_NULL, KEY_NULL}, //KEY_0
+};
+int app_idle_key_event_handler(struct sys_event *event)
+{
+ int ret = false;
+ struct key_event *key = &event->u.key;
+ u8 key_event = idle_key_table[key->value][key->event];
+ static u16 key_hold_cnt = 0;
+ static u8 key_press_flag = 0;
+
+ switch (key_event) {
+ case KEY_CLEAN_PHONE_INFO:
+ log_info("KEY_CLEAN_PHONE_INFO");
+ key_hold_cnt = 0;
+ key_press_flag = 1;
+ P33_CON_SET(P3_PINR_CON, 0, 1, 0);
+ break;
+ case KEY_CLEAN_PHONE_INFO_HOLD:
+ key_hold_cnt++;
+ if (key_press_flag) {
+ if (key_hold_cnt == IDLE_CLEAN_INFO_CNT) {
+ log_info("KEY_CLEAN_PHONE_INFO_HOLD");
+ extern void delete_link_key_for_app(bd_addr_t *bd_addr, u8 id);
+ delete_link_key_for_app(NULL, 0);
+ tone_play(TONE_SIN_NORMAL, 1);
+ key_press_flag = 0;
+ }
+ }
+ break;
+ case KEY_CLEAN_PHONE_INFO_UP:
+ log_info("KEY_CLEAN_PHONE_INFO_UP");
+ key_hold_cnt = 0;
+ key_press_flag = 0;
+ P33_CON_SET(P3_PINR_CON, 0, 1, 1);
+ break;
+ }
+ return ret;
+}
+
+#endif
+
+static int idle_event_handler(struct application *app, struct sys_event *event)
+{
+ switch (event->type) {
+ case SYS_KEY_EVENT:
+#if CHARGING_CLEAN_PHONE_INFO
+ /* log_info("idle_event_handler:SYS_KEY_EVENT\n"); */
+ app_idle_key_event_handler(event);
+#endif
+ return 0;
+ case SYS_BT_EVENT:
+ return 0;
+ case SYS_DEVICE_EVENT:
+ if ((u32)event->arg == DEVICE_EVENT_FROM_CHARGE) {
+#if TCFG_CHARGE_ENABLE
+ return app_charge_event_handler(&event->u.dev);
+#endif
+ }
+ if ((u32)event->arg == DEVICE_EVENT_FROM_TONE) {
+ return app_idle_tone_event_handler(&event->u.dev);
+ }
+#if TCFG_CHARGESTORE_ENABLE
+ if ((u32)event->arg == DEVICE_EVENT_CHARGE_STORE) {
+ app_chargestore_event_handler(&event->u.chargestore);
+ }
+#endif
+#if TCFG_UMIDIGI_BOX_ENABLE
+ else if ((u32)event->arg == DEVICE_EVENT_UMIDIGI_CHARGE_STORE) {
+ app_umidigi_chargestore_event_handler(&event->u.umidigi_chargestore);
+ }
+#endif
+#if TCFG_TEST_BOX_ENABLE
+ if ((u32)event->arg == DEVICE_EVENT_TEST_BOX) {
+ app_testbox_event_handler(&event->u.testbox);
+ }
+#endif
+#if TCFG_ANC_BOX_ENABLE
+ if ((u32)event->arg == DEVICE_EVENT_FROM_ANC) {
+ return app_ancbox_event_handler(&event->u.ancbox);
+ }
+#endif
+ break;
+ default:
+ return false;
+ }
+
+#if (CONFIG_BT_BACKGROUND_ENABLE || TCFG_PC_ENABLE)
+#if(!TCFG_ONLY_PC_ENABLE)
+ default_event_handler(event);
+#endif
+#endif
+
+ return false;
+}
+
+static int idle_state_machine(struct application *app, enum app_state state,
+ struct intent *it)
+{
+ int ret;
+ switch (state) {
+ case APP_STA_CREATE:
+ break;
+ case APP_STA_START:
+ if (!it) {
+ break;
+ }
+ switch (it->action) {
+ case ACTION_IDLE_MAIN:
+ log_info("ACTION_IDLE_MAIN\n");
+ if (app_var.goto_poweroff_flag) {
+ syscfg_write(CFG_MUSIC_VOL, &app_var.music_volume, 1);
+ /* tone_play(TONE_POWER_OFF); */
+ os_taskq_flush();
+ STATUS *p_tone = get_tone_config();
+ ret = 1;//tone_play_index(p_tone->power_off, 1);
+ //printf("power_off tone play ret:%d", ret);
+ if (ret) {
+ if (app_var.goto_poweroff_flag) {
+ log_info("power_off tone play err,enter soft poweroff");
+ app_idle_enter_softoff();
+ }
+ }
+ }
+#if CHARGING_CLEAN_PHONE_INFO
+ else {
+ sys_key_event_enable();
+ }
+#endif
+ break;
+ case ACTION_IDLE_POWER_OFF:
+ os_taskq_flush();
+ syscfg_write(CFG_MUSIC_VOL, &app_var.music_volume, 1);
+ break;
+ }
+ break;
+ case APP_STA_PAUSE:
+ break;
+ case APP_STA_RESUME:
+ break;
+ case APP_STA_STOP:
+ break;
+ case APP_STA_DESTROY:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct application_operation app_idle_ops = {
+ .state_machine = idle_state_machine,
+ .event_handler = idle_event_handler,
+};
+
+REGISTER_APPLICATION(app_app_idle) = {
+ .name = "idle",
+ .action = ACTION_IDLE_MAIN,
+ .ops = &app_idle_ops,
+ .state = APP_STA_DESTROY,
+};
+
+
diff --git a/apps/earphone/include/aec_user.h b/apps/earphone/include/aec_user.h
new file mode 100644
index 0000000..5c04003
--- /dev/null
+++ b/apps/earphone/include/aec_user.h
@@ -0,0 +1,209 @@
+#ifndef _AEC_USER_H_
+#define _AEC_USER_H_
+
+#include "generic/typedef.h"
+#include "user_cfg.h"
+
+#define AEC_DEBUG_ONLINE 0
+#define AEC_READ_CONFIG 1
+
+/*
+ *CVP(清晰语音模式定义)
+ */
+#define CVP_MODE_NONE 0x00 //清晰语音处理关闭
+#define CVP_MODE_NORMAL 0x01 //通用模式
+#define CVP_MODE_DMS 0x02 //双mic降噪(ENC)模式
+#define CVP_MODE_SMS 0x03 //单mic系统(外加延时估计)
+#define CVP_MODE_SMS_TDE 0x04 //单mic系统(内置延时估计)
+#define CVP_MODE_SEL CVP_MODE_NORMAL
+
+#define AEC_EN BIT(0)
+#define NLP_EN BIT(1)
+#define ANS_EN BIT(2)
+#define ENC_EN BIT(3)
+#define AGC_EN BIT(4)
+#define WNC_EN BIT(5)
+#define MFDT_EN BIT(6)
+
+/*aec module enable bit define*/
+#define AEC_MODE_ADVANCE (AEC_EN | NLP_EN | ANS_EN )
+#define AEC_MODE_REDUCE (NLP_EN | ANS_EN )
+
+#define AEC_MODE_SIMPLEX (ANS_EN)
+
+/*
+ *SMS模式选择
+ *(1)SMS模式性能更好,同时也需要更多的ram和mips
+ *(2)SMS_NORMAL和SMS_TDE功能一样,只是SMS_TDE内置了延时估计和延时补偿
+ *可以更好的兼容延时不固定的场景
+ */
+#define SMS_DISABLE 0
+#define SMS_NORMAL 1
+#define SMS_TDE 2
+#define TCFG_AUDIO_SMS_ENABLE SMS_DISABLE
+
+/*
+ *DMS版本配置
+ *DMS_GLOBAL_V100:第一版双麦算法
+ *DMS_GLOBAL_V200:第二版双麦算法,更少的ram和mips
+ */
+#define TCFG_AUDIO_DMS_GLOBAL_VERSION DMS_GLOBAL_V100
+
+#if (defined(CONFIG_MEDIA_NEW_ENABLE) || (defined(CONFIG_MEDIA_DEVELOP_ENABLE)))
+
+extern const u8 CONST_AEC_SIMPLEX;
+
+/*兼容SMS和DMS*/
+#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
+#include "commproc_tms.h"
+#define aec_open aec_tms_init
+#define aec_close aec_tms_exit
+#define aec_in_data aec_tms_fill_in_data
+#define aec_in_data_ref aec_tms_fill_in_ref_data
+#define aec_in_data_ref_1 aec_tms_fill_in_ref_1_data
+#define aec_ref_data aec_tms_fill_ref_data
+
+#elif TCFG_AUDIO_DUAL_MIC_ENABLE
+#include "commproc_dms.h"
+#if (TCFG_AUDIO_DMS_SEL == DMS_NORMAL)
+#define aec_open aec_dms_init
+#define aec_close aec_dms_exit
+#define aec_in_data aec_dms_fill_in_data
+#define aec_in_data_ref aec_dms_fill_in_ref_data
+#define aec_ref_data aec_dms_fill_ref_data
+#else
+#define aec_open aec_dms_flexible_init
+#define aec_close aec_dms_flexible_exit
+#define aec_in_data aec_dms_flexible_fill_in_data
+#define aec_in_data_ref aec_dms_flexible_fill_in_ref_data
+#define aec_ref_data aec_dms_flexible_fill_ref_data
+#endif/*TCFG_AUDIO_DMS_SEL*/
+
+void aec_cfg_fill(AEC_DMS_CONFIG *cfg);
+/*
+*********************************************************************
+* Audio AEC Output Select
+* Description: 输出选择
+* Arguments : sel = Default 默认输出算法处理结果
+* = Master 输出主mic(通话mic)的原始数据
+* = Slave 输出副mic(降噪mic)的原始数据
+* agc 输出数据要不要经过agc自动增益控制模块
+* Return : None.
+* Note(s) : 可以通过选择不同的输出,来测试mic的频响和ENC指标
+*********************************************************************
+*/
+void audio_aec_output_sel(CVP_OUTPUT_ENUM sel, u8 agc);
+
+#elif (TCFG_AUDIO_SMS_ENABLE == SMS_TDE)
+#include "commproc.h"
+#define aec_open sms_tde_init
+#define aec_close sms_tde_exit
+#define aec_in_data sms_tde_fill_in_data
+#define aec_in_data_ref(...)
+#define aec_ref_data sms_tde_fill_ref_data
+void aec_cfg_fill(AEC_CONFIG *cfg);
+#else
+#include "commproc.h"
+#define aec_open aec_init
+#define aec_close aec_exit
+#define aec_in_data aec_fill_in_data
+#define aec_in_data_ref(...)
+#define aec_ref_data aec_fill_ref_data
+void aec_cfg_fill(AEC_CONFIG *cfg);
+#endif
+
+s8 aec_debug_online(void *buf, u16 size);
+void aec_input_clear_enable(u8 enable);
+
+int audio_aec_init(u16 sample_rate);
+void audio_aec_close(void);
+void audio_aec_inbuf(s16 *buf, u16 len);
+void audio_aec_inbuf_ref(s16 *buf, u16 len);
+void audio_aec_inbuf_ref_1(s16 *buf, u16 len);
+void audio_aec_refbuf(s16 *buf, u16 len);
+u8 audio_aec_status(void);
+void audio_aec_reboot(u8 reduce);
+void audio_aec_ref_start(u8 en);
+/*
+*********************************************************************
+* Audio AEC Open
+* Description: 初始化AEC模块
+* Arguments : sr 采样率(8000/16000)
+* enablebit 使能模块(AEC/NLP/AGC/ANS...)
+* out_hdl 自定义回调函数,NULL则用默认的回调
+* Return : 0 成功 其他 失败
+* Note(s) : 该接口是对audio_aec_init的扩展,支持自定义使能模块以及
+* 数据输出回调函数
+*********************************************************************
+*/
+int audio_aec_open(u16 sample_rate, s16 enablebit, int (*out_hdl)(s16 *data, u16 len));
+
+/*
+*********************************************************************
+* Audio CVP IOCTL
+* Description: CVP功能配置
+* Arguments : cmd 操作命令
+* value 操作数
+* priv 操作内存地址
+* Return : 0 成功 其他 失败
+* Note(s) : (1)比如动态开关降噪NS模块:
+* audio_cvp_ioctl(CVP_NS_SWITCH,1,NULL); //降噪关
+* audio_cvp_ioctl(CVP_NS_SWITCH,0,NULL); //降噪开
+*********************************************************************
+*/
+int audio_cvp_ioctl(int cmd, int value, void *priv);
+
+/*获取风噪的检测结果,1:有风噪,0:无风噪*/
+int audio_cvp_dms_wnc_state(void);
+
+/*获取单双麦切换状态
+ * 0: 正常双麦 ;
+ * 1: 副麦坏了,触发故障
+ * -1: 主麦坏了,触发故障
+ */
+int audio_cvp_dms_malfunc_state();
+
+/*
+ * 获取mic的能量值,开了MFDT_EN才能用
+ * mic: 0 获取主麦能量
+ * mic:1 获取副麦能量
+ * return:返回能量值,[0~90.3],返回-1表示错误
+ */
+float audio_cvp_dms_mic_energy(u8 mic);
+
+/*tri_en: 1 正常3MIC降噪
+ * 0 变成2MIC降噪,不使用 FB MIC数据*/
+int audio_tms_mode_choose(u8 tri_en);
+
+#else
+
+extern struct aec_s_attr aec_param;
+extern const u8 CONST_AEC_SIMPLEX;
+
+struct aec_s_attr *aec_param_init(u16 sr);
+s8 aec_debug_online(void *buf, u16 size);
+void aec_cfg_fill(AEC_CONFIG *cfg);
+void aec_input_clear_enable(u8 enable);
+
+#endif /* #if (defined(CONFIG_MEDIA_NEW_ENABLE) || (defined(CONFIG_MEDIA_DEVELOP_ENABLE))) */
+
+
+//aec 上行音效
+enum {
+ SOUND_ORIGINAL, //原声
+ SOUND_UNCLE, //大叔
+ SOUND_GODDESS, //女神
+};
+
+#if defined(AEC_PRESETS_UL_EQ_CONFIG) && AEC_PRESETS_UL_EQ_CONFIG
+#ifndef UL_PRESETS_EQ_NSECTION
+#define UL_PRESETS_EQ_NSECTION 5
+#endif
+#if (UL_PRESETS_EQ_NSECTION > EQ_SECTION_MAX )
+#error "EQ_SETCTION_MAX too samll"
+#endif
+void aec_ul_eq_update();
+void ul_presets_eq_set(u8 tab_num);
+#endif/*AEC_PRESETS_UL_EQ_CONFIG*/
+
+#endif/*_AEC_USER_H_*/
diff --git a/apps/earphone/include/app_action.h b/apps/earphone/include/app_action.h
new file mode 100644
index 0000000..5c61a59
--- /dev/null
+++ b/apps/earphone/include/app_action.h
@@ -0,0 +1,31 @@
+#ifndef APP_ACTION_H
+#define APP_ACTION_H
+
+
+#define ACTION_EARPHONE_MAIN 0x0001
+#define ACTION_A2DP_START 0x0002
+#define ACTION_ESCO_START 0x0003
+#define ACTION_BY_KEY_MODE 0x0004
+
+#define ACTION_IDLE_MAIN 0x0010
+#define ACTION_IDLE_POWER_OFF 0x0011
+
+#define ACTION_MUSIC_MAIN 0x0020
+#define ACTION_MUSIC_TWS_RX 0x0021
+
+#define ACTION_PC_MAIN 0x0030
+
+#define ACTION_AUX_MAIN 0x0040
+
+#define APP_NAME_BT "earphone"
+#define APP_NAME_IDLE "idle"
+#define APP_NAME_PC "pc"
+#define APP_NAME_MUSIC "music"
+#define APP_NAME_AUX "aux"
+
+extern void task_switch(const char *name, int action);
+#define task_switch_to_bt() task_switch(APP_NAME_BT, ACTION_EARPHONE_MAIN)
+
+
+#endif
+
diff --git a/apps/earphone/include/app_ancbox.h b/apps/earphone/include/app_ancbox.h
new file mode 100644
index 0000000..caffff3
--- /dev/null
+++ b/apps/earphone/include/app_ancbox.h
@@ -0,0 +1,12 @@
+#ifndef _APP_ANCBOX_H_
+#define _APP_ANCBOX_H_
+
+#include "typedef.h"
+#include "system/event.h"
+
+extern int app_ancbox_event_handler(struct ancbox_event *anc_dev);
+extern u8 ancbox_get_status(void);
+extern void ancbox_clear_status(void);
+
+#endif //_APP_CHARGESTORE_H_
+
diff --git a/apps/earphone/include/app_anctool.h b/apps/earphone/include/app_anctool.h
new file mode 100644
index 0000000..71ded67
--- /dev/null
+++ b/apps/earphone/include/app_anctool.h
@@ -0,0 +1,13 @@
+#ifndef _APP_ANCTOOL_H_
+#define _APP_ANCTOOL_H_
+
+#include "typedef.h"
+#include "anctool.h"
+
+u8 app_anctool_spp_rx_data(u8 *packet, u16 size);
+void app_anctool_spp_connect(void);
+void app_anctool_spp_disconnect(void);
+u8 get_app_anctool_spp_connected_flag();
+
+#endif //_APP_CHARGESTORE_H_
+
diff --git a/apps/earphone/include/app_charge.h b/apps/earphone/include/app_charge.h
new file mode 100644
index 0000000..8586dd3
--- /dev/null
+++ b/apps/earphone/include/app_charge.h
@@ -0,0 +1,17 @@
+#ifndef _APP_CHARGE_H_
+#define _APP_CHARGE_H_
+
+#include "typedef.h"
+#include "system/event.h"
+
+extern void charge_close_deal(void);
+extern void charge_start_deal(void);
+extern void ldo5v_keep_deal(void);
+extern void charge_full_deal(void);
+extern void charge_ldo5v_in_deal(void);
+extern void charge_ldo5v_off_deal(void);
+extern u8 get_charge_full_flag(void);
+
+extern int app_charge_event_handler(struct device_event *dev);
+
+#endif //_APP_CHARGE_H_
diff --git a/apps/earphone/include/app_config.h b/apps/earphone/include/app_config.h
new file mode 100644
index 0000000..f5a0ba0
--- /dev/null
+++ b/apps/earphone/include/app_config.h
@@ -0,0 +1,556 @@
+#ifndef APP_CONFIG_H
+#define APP_CONFIG_H
+
+/*
+ * 系统打印总开关
+ */
+
+#define LIB_DEBUG 0
+#define CONFIG_DEBUG_LIB(x) (x & LIB_DEBUG)
+
+#define CONFIG_DEBUG_ENABLE
+
+#ifndef CONFIG_DEBUG_ENABLE
+//#define CONFIG_DEBUG_LITE_ENABLE //轻量级打印开关, 默认关闭
+#endif
+
+
+#define TCFG_APP_RTC_EN 1
+
+//*********************************************************************************//
+// AI配置 //
+//*********************************************************************************//
+#define CONFIG_APP_BT_ENABLE
+
+#ifdef CONFIG_APP_BT_ENABLE
+#define TRANS_DATA_EN 0
+#define RCSP_BTMATE_EN 0
+#define RCSP_ADV_EN 1
+//#define AI_APP_PROTOCOL 0
+//#define LL_SYNC_EN 0
+#define TUYA_DEMO_EN 0
+#else
+#define TRANS_DATA_EN 0
+#define RCSP_BTMATE_EN 1
+#define RCSP_ADV_EN 1
+//#define AI_APP_PROTOCOL 0
+//#define LL_SYNC_EN 0
+#define TUYA_DEMO_EN 0
+#endif
+
+
+#include "board_config.h"
+#ifdef TCFG_AUDIO_CVP_NS_MODE
+#if (TCFG_AUDIO_CVP_NS_MODE==CVP_DNS_MODE) || (TCFG_KWS_VOICE_RECOGNITION_ENABLE == 1)||(TCFG_AUDIO_ANC_ENABLE==1&&TCFG_AUDIO_DUAL_MIC_ENABLE==1)
+#undef CONFIG_MOVABLE_ENABLE
+#define CONFIG_MOVABLE_ENABLE //省ram空间,将部分ram空间的代码挪到flash
+#endif
+#endif
+
+#if defined(TCFG_CVP_DEVELOP_ENABLE) && (TCFG_CVP_DEVELOP_ENABLE == 1)
+#undef CONFIG_MOVABLE_ENABLE
+#define CONFIG_MOVABLE_ENABLE //省ram空间,将部分ram空间的代码挪到flash
+#endif
+
+#if CONFIG_UPDATE_WITH_MD5_CHECK_EN
+#define UPDATE_MD5_ENABLE 1
+#else
+#define UPDATE_MD5_ENABLE 0
+#endif
+
+
+//升级需要打开CONFIG_APP_OTA_ENABLE,同时单双备份的配置也在board_xxx_global_cfg里配置,需要注意只有JL_RCSP才支持单备份,其余升级都是只支持双备份升级
+//支持TWS同步升级,OTA_TWS_SAME_TIME_NEW宏需要配置为1,旧的流程已不再支持
+#if (RCSP_ADV_EN) //rcsp需要打开ble
+#define JL_EARPHONE_APP_EN 1
+// #define CONFIG_CHARGESTORE_REMAP_ENABLE //充电仓重映射接收函数使能
+#if CONFIG_APP_OTA_ENABLE
+#define RCSP_UPDATE_EN 1 //是否支持rcsp升级
+#if CONFIG_DOUBLE_BANK_ENABLE //双备份才能打开同步升级流程
+#define OTA_TWS_SAME_TIME_ENABLE 0 //是否支持TWS同步升级
+#define OTA_TWS_SAME_TIME_NEW 0 //使用新的tws ota流程
+#else
+#define OTA_TWS_SAME_TIME_ENABLE 0 //是否支持TWS同步升级
+#define OTA_TWS_SAME_TIME_NEW 0 //使用新的tws ota流程
+#endif //CONFIG_DOUBLE_BANK_ENABLE
+#else
+#define RCSP_UPDATE_EN 0 //是否支持rcsp升级
+#define OTA_TWS_SAME_TIME_ENABLE 0 //是否支持TWS同步升级
+#define OTA_TWS_SAME_TIME_NEW 0 //使用新的tws ota流程
+#endif
+#undef TCFG_USER_BLE_ENABLE
+#define TCFG_USER_BLE_ENABLE 1 //BLE功能使能
+#elif (AI_APP_PROTOCOL)
+#define BT_MIC_EN 0
+#define OTA_TWS_SAME_TIME_ENABLE 0 //是否支持TWS同步升级
+#elif (LL_SYNC_EN)
+#define JL_EARPHONE_APP_EN 0
+#define OTA_TWS_SAME_TIME_ENABLE 1
+#define OTA_TWS_SAME_TIME_NEW 1 //使用新的tws ota流程
+#elif (TUYA_DEMO_EN)
+#define JL_EARPHONE_APP_EN 0
+#define OTA_TWS_SAME_TIME_ENABLE 0
+#define OTA_TWS_SAME_TIME_NEW 0 //使用新的tws ota流程
+#else
+#define JL_EARPHONE_APP_EN 0
+#define OTA_TWS_SAME_TIME_ENABLE 0
+#define OTA_TWS_SAME_TIME_NEW 0 //使用新的tws ota流程
+#endif
+
+#define CONFIG_MEDIA_LIB_USE_MALLOC 1
+
+
+
+#include "usb_std_class_def.h"
+
+#undef USB_MALLOC_ENABLE
+#define USB_MALLOC_ENABLE 1
+///USB 配置重定义
+// #undef USB_DEVICE_CLASS_CONFIG
+// #define USB_DEVICE_CLASS_CONFIG (AUDIO_CLASS)
+/////要确保 上面 undef 后在include usb
+#include "usb_common_def.h"
+
+#define USB_PC_NO_APP_MODE 0
+
+#if ((TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE) \
+ && TCFG_CHARGESTORE_PORT == IO_PORT_DP)
+#undef TCFG_OTG_MODE
+#define TCFG_OTG_MODE (TCFG_OTG_MODE_HOST|TCFG_OTG_MODE_SLAVE|TCFG_OTG_MODE_CHARGE|OTG_DET_DM_ONLY)
+#endif
+
+
+#include "btcontroller_mode.h"
+
+#include "user_cfg_id.h"
+
+#ifndef __LD__
+#include "bt_profile_cfg.h"
+#endif
+
+
+// #ifdef CONFIG_APP_BT_ENABLE
+// #if(APP_ONLINE_DEBUG)
+// #error "they can not enable at the same time,just select one!!!"
+// #endif
+// #endif
+
+
+#ifdef CONFIG_SDFILE_ENABLE
+
+#define SDFILE_DEV "sdfile"
+#define SDFILE_MOUNT_PATH "mnt/sdfile"
+
+#if (USE_SDFILE_NEW)
+#define SDFILE_APP_ROOT_PATH SDFILE_MOUNT_PATH"/app/" //app分区
+#define SDFILE_RES_ROOT_PATH SDFILE_MOUNT_PATH"/res/" //资源文件分区
+#else
+#define SDFILE_RES_ROOT_PATH SDFILE_MOUNT_PATH"/C/"
+#endif
+
+#endif
+
+#define STYLE_JL_WTACH (1)//彩屏demo
+#define STYLE_JL_SOUNDBOX (2)//点阵屏demo
+#define STYLE_JL_CHARGE (3)//点阵屏充电仓
+#define STYLE_JL_LED7 (4)//led7
+#define STYLE_UI_SIMPLE (5)//没有ui框架
+
+
+//*********************************************************************************//
+// 测试模式配置 //
+//*********************************************************************************//
+#if (CONFIG_BT_MODE != BT_NORMAL)
+#undef TCFG_BD_NUM
+#define TCFG_BD_NUM 1
+
+#undef TCFG_USER_TWS_ENABLE
+#define TCFG_USER_TWS_ENABLE 0 //tws功能使能
+
+#undef TCFG_USER_BLE_ENABLE
+#define TCFG_USER_BLE_ENABLE 1 //BLE功能使能
+
+#undef TCFG_AUTO_SHUT_DOWN_TIME
+#define TCFG_AUTO_SHUT_DOWN_TIME 0
+
+#undef TCFG_SYS_LVD_EN
+#define TCFG_SYS_LVD_EN 0
+
+#undef TCFG_LOWPOWER_LOWPOWER_SEL
+#define TCFG_LOWPOWER_LOWPOWER_SEL 0
+
+#undef TCFG_AUDIO_DAC_LDO_VOLT
+#define TCFG_AUDIO_DAC_LDO_VOLT DUT_AUDIO_DAC_LDO_VOLT
+
+#undef TCFG_LOWPOWER_POWER_SEL
+#define TCFG_LOWPOWER_POWER_SEL PWR_LDO15
+
+#undef TCFG_PWMLED_ENABLE
+#define TCFG_PWMLED_ENABLE DISABLE_THIS_MOUDLE
+
+#undef TCFG_ADKEY_ENABLE
+#define TCFG_ADKEY_ENABLE DISABLE_THIS_MOUDLE
+
+#undef TCFG_IOKEY_ENABLE
+#define TCFG_IOKEY_ENABLE DISABLE_THIS_MOUDLE
+
+#undef TCFG_TEST_BOX_ENABLE
+#define TCFG_TEST_BOX_ENABLE 0
+
+#undef TCFG_AUTO_SHUT_DOWN_TIME
+#define TCFG_AUTO_SHUT_DOWN_TIME 0
+
+#undef TCFG_POWER_ON_NEED_KEY
+#define TCFG_POWER_ON_NEED_KEY 0
+
+/* #undef TCFG_UART0_ENABLE
+#define TCFG_UART0_ENABLE DISABLE_THIS_MOUDLE */
+
+#endif //(CONFIG_BT_MODE != BT_NORMAL)
+
+
+#if TCFG_USER_TWS_ENABLE
+
+#define CONFIG_TWS_COMMON_ADDR_AUTO 0 /* 自动生成TWS配对后的MAC地址 */
+#define CONFIG_TWS_COMMON_ADDR_USED_LEFT 1 /* 使用左耳的MAC地址作为TWS配对后的地址
+ 可配合烧写器MAC地址自增功能一起使用
+ 多台交叉配对会出现MAC地址相同情况 */
+#define CONFIG_TWS_COMMON_ADDR_SELECT CONFIG_TWS_COMMON_ADDR_AUTO
+
+//*********************************************************************************//
+// 对耳配置方式配置 //
+//*********************************************************************************//
+#define CONFIG_TWS_CONNECT_SIBLING_TIMEOUT 4 /* 开机或超时断开后对耳互连超时时间,单位s */
+// #define CONFIG_TWS_REMOVE_PAIR_ENABLE [> 不连手机的情况下双击按键删除配对信息 <]
+#define CONFIG_TWS_POWEROFF_SAME_TIME 1 /*按键关机时两个耳机同时关机*/
+
+#define ONE_KEY_CTL_DIFF_FUNC 1 /*通过左右耳实现一个按键控制两个功能*/
+#define CONFIG_TWS_SCO_ONLY_MASTER 0 /*通话的时候只有主机出声音*/
+
+/* 配对方式选择 */
+#define CONFIG_TWS_PAIR_BY_CLICK 0 /* 按键发起配对 */
+#define CONFIG_TWS_PAIR_BY_AUTO 1 /* 开机自动配对 */
+#define CONFIG_TWS_PAIR_BY_FAST_CONN 2 /* 开机快速连接,连接速度比自动配对快,不支持取消配对操作 */
+#define CONFIG_TWS_PAIR_MODE CONFIG_TWS_PAIR_BY_AUTO
+
+
+/* 声道确定方式选择 */
+#define CONFIG_TWS_MASTER_AS_LEFT 0 //主机作为左耳
+#define CONFIG_TWS_AS_LEFT_CHANNEL 1 //固定左耳
+#define CONFIG_TWS_AS_RIGHT_CHANNEL 2 //固定右耳
+#define CONFIG_TWS_LEFT_START_PAIR 3 //双击发起配对的耳机做左耳
+#define CONFIG_TWS_RIGHT_START_PAIR 4 //双击发起配对的耳机做右耳
+#define CONFIG_TWS_EXTERN_UP_AS_LEFT 5 //外部有上拉电阻作为左耳
+#define CONFIG_TWS_EXTERN_DOWN_AS_LEFT 6 //外部有下拉电阻作为左耳
+#define CONFIG_TWS_SECECT_BY_CHARGESTORE 7 //充电仓决定左右耳
+#define CONFIG_TWS_CHANNEL_SELECT CONFIG_TWS_LEFT_START_PAIR //配对方式选择
+
+#define CONFIG_TWS_CHANNEL_CHECK_IO -1 //上下拉电阻检测引脚
+
+
+#if CONFIG_TWS_PAIR_MODE != CONFIG_TWS_PAIR_BY_CLICK
+#if (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_LEFT_START_PAIR) ||\
+ (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_RIGHT_START_PAIR)
+#undef CONFIG_TWS_CHANNEL_SELECT
+#define CONFIG_TWS_CHANNEL_SELECT CONFIG_TWS_MASTER_AS_LEFT
+#endif
+
+#if CONFIG_TWS_PAIR_MODE == CONFIG_TWS_PAIR_BY_AUTO
+#define CONFIG_TWS_AUTO_PAIR_WITHOUT_UNPAIR /* 不取消配对也可以配对新的耳机 */
+#endif
+
+#if CONFIG_TWS_PAIR_MODE == CONFIG_TWS_PAIR_BY_FAST_CONN
+#undef CONFIG_TWS_REMOVE_PAIR_ENABLE
+#endif
+
+#endif
+
+#define CONFIG_A2DP_GAME_MODE_ENABLE 0 //游戏模式
+#define CONFIG_A2DP_GAME_MODE_DELAY_TIME 35 //游戏模式延时ms
+
+//*********************************************************************************//
+// 低延时游戏模式脚步声、枪声增强,需使能蓝牙音乐10段eq以及蓝牙音乐drc
+// 用户开关宏AUDIO_GAME_EFFECT_CONFIG(开关蓝牙低延时模式的游戏音效)
+// 低延时eq效果文件使用eq_game_eff.bin,调试时需保存成该文件,并在批处理-res后添加
+// 非低延时eq效果文件使用eq_cfg_hw.bin,也需在批处理-res后添加
+//*********************************************************************************//
+#if CONFIG_A2DP_GAME_MODE_ENABLE
+#define AUDIO_GAME_EFFECT_CONFIG 1 //低延时游戏模式脚步声、枪声增强 1:使能、0:关闭
+#else
+#define AUDIO_GAME_EFFECT_CONFIG 0 //低延时游戏模式脚步声、枪声增强 1:使能、0:关闭
+#endif
+/***********************************非用户配置区***********************************/
+//以下宏定义,是游戏音效使能后,需要开启的宏定义,已配好,用户不用修改
+#if AUDIO_GAME_EFFECT_CONFIG
+#if (TCFG_EQ_ENABLE == 0)
+#undef TCFG_EQ_ENABLE
+#define TCFG_EQ_ENABLE 1
+#endif/* (TCFG_EQ_ENABLE == 0) */
+#if (TCFG_BT_MUSIC_EQ_ENABLE == 0)
+#undef TCFG_BT_MUSIC_EQ_ENABLE
+#define TCFG_BT_MUSIC_EQ_ENABLE 1
+#endif/*(TCFG_BT_MUSIC_EQ_ENABLE == 0)*/
+#if (TCFG_DRC_ENABLE == 0)
+#undef TCFG_DRC_ENABLE
+#define TCFG_DRC_ENABLE 1
+#endif/* (TCFG_DRC_ENABLE == 0) */
+#if (TCFG_BT_MUSIC_DRC_ENABLE == 0)
+#undef TCFG_BT_MUSIC_DRC_ENABLE
+#define TCFG_BT_MUSIC_DRC_ENABLE 1
+#endif/* (TCFG_BT_MUSIC_DRC_ENABLE == 0) */
+#if (EQ_SECTION_MAX < 10)
+#undef EQ_SECTION_MAX
+#define EQ_SECTION_MAX 10
+#endif/* (EQ_SECTION_MAX < 10) */
+#if (TCFG_USE_EQ_FILE == 0)
+#undef TCFG_USE_EQ_FILE
+#define TCFG_USE_EQ_FILE 1
+#endif/* TCFG_USE_EQ_FILE */
+#endif/* AUDIO_GAME_EFFECT_CONFIG */
+/**********************************************************************************/
+
+
+
+#if CONFIG_TWS_PAIR_MODE == CONFIG_TWS_PAIR_BY_CLICK
+#define CONFIG_TWS_BY_CLICK_PAIR_WITHOUT_PAIR /*双击按键可以配对已配对过的样机,即交叉配对 */
+#ifdef CONFIG_TWS_BY_CLICK_PAIR_WITHOUT_PAIR
+#define CONFIG_TWS_AUTO_PAIR_WITHOUT_UNPAIR /* 不取消配对也可以配对新的耳机 */
+#endif
+#endif
+
+
+#if TCFG_CHARGESTORE_ENABLE
+#undef CONFIG_TWS_CHANNEL_SELECT
+#define CONFIG_TWS_CHANNEL_SELECT CONFIG_TWS_SECECT_BY_CHARGESTORE //充电仓区分左右
+#endif //TCFG_CHARGESTORE_ENABLE
+
+#if TCFG_TEST_BOX_ENABLE && (!TCFG_CHARGESTORE_ENABLE)
+#define CONFIG_TWS_SECECT_CHARGESTORE_PRIO 1 //测试盒配置左右耳优先
+#else
+#define CONFIG_TWS_SECECT_CHARGESTORE_PRIO 0
+#endif //TCFG_TEST_BOX_ENABLE
+
+//*********************************************************************************//
+// 对耳电量显示方式 //
+//*********************************************************************************//
+
+#if BT_SUPPORT_DISPLAY_BAT
+#define CONFIG_DISPLAY_TWS_BAT_LOWER 1 //对耳手机端电量显示,显示低电量耳机的电量
+#define CONFIG_DISPLAY_TWS_BAT_HIGHER 2 //对耳手机端电量显示,显示高电量耳机的电量
+#define CONFIG_DISPLAY_TWS_BAT_LEFT 3 //对耳手机端电量显示,显示左耳的电量
+#define CONFIG_DISPLAY_TWS_BAT_RIGHT 4 //对耳手机端电量显示,显示右耳的电量
+
+#define CONFIG_DISPLAY_TWS_BAT_TYPE CONFIG_DISPLAY_TWS_BAT_LOWER
+#endif //BT_SUPPORT_DISPLAY_BAT
+
+#define CONFIG_DISPLAY_DETAIL_BAT 0 //BLE广播显示具体的电量
+#define CONFIG_NO_DISPLAY_BUTTON_ICON 1 //BLE广播不显示按键界面,智能充电仓置1
+
+#endif //TCFG_USER_TWS_ENABLE
+
+#ifndef CONFIG_BT_RX_BUFF_SIZE
+#define CONFIG_BT_RX_BUFF_SIZE (14 * 1024)
+#endif
+
+#ifdef CONFIG_APP_BT_ENABLE
+#if TCFG_BT_SUPPORT_AAC || TCFG_BT_SUPPORT_LDAC
+#define CONFIG_BT_TX_BUFF_SIZE (5 * 1024)
+#else
+#define CONFIG_BT_TX_BUFF_SIZE (4 * 1024)
+#endif
+#else
+#if TCFG_BT_SUPPORT_AAC || TCFG_BT_SUPPORT_LDAC
+#define CONFIG_BT_TX_BUFF_SIZE (4 * 1024)
+#else
+#define CONFIG_BT_TX_BUFF_SIZE (3 * 1024)
+#endif
+#endif
+
+
+#ifndef CONFIG_NEW_BREDR_ENABLE
+
+#if TCFG_USER_TWS_ENABLE
+
+#ifdef CONFIG_LOCAL_TWS_ENABLE
+#define CONFIG_TWS_BULK_POOL_SIZE (4 * 1024)
+#else
+#define CONFIG_TWS_BULK_POOL_SIZE (2 * 1024)
+#endif
+#endif
+#endif
+
+
+#if (CONFIG_BT_MODE != BT_NORMAL)
+////bqb 如果测试3M tx buf 最好加大一点
+#undef CONFIG_BT_TX_BUFF_SIZE
+#define CONFIG_BT_TX_BUFF_SIZE (6 * 1024)
+
+#endif
+
+//*********************************************************************************//
+// 电源切换配置 //
+//*********************************************************************************//
+
+#define PHONE_CALL_USE_LDO15 CONFIG_PHONE_CALL_USE_LDO15
+
+//*********************************************************************************//
+// 时钟切换配置 //
+//*********************************************************************************//
+#define BT_NORMAL_HZ CONFIG_BT_NORMAL_HZ
+#define BT_CONNECT_HZ CONFIG_BT_CONNECT_HZ
+
+#define BT_A2DP_HZ CONFIG_BT_A2DP_HZ
+
+#define BT_CALL_HZ CONFIG_BT_CALL_HZ
+#define BT_CALL_ADVANCE_HZ CONFIG_BT_CALL_ADVANCE_HZ
+#define BT_CALL_16k_HZ CONFIG_BT_CALL_16k_HZ
+#define BT_CALL_16k_ADVANCE_HZ CONFIG_BT_CALL_16k_ADVANCE_HZ
+
+
+#define MUSIC_DEC_FASTEST_CLOCK CONFIG_MUSIC_DEC_FASTEST_CLOCK
+#define MUSIC_DEC_FAST_CLOCK CONFIG_MUSIC_DEC_FAST_CLOCK
+#define MUSIC_DEC_CLOCK CONFIG_MUSIC_DEC_CLOCK
+#define MUSIC_DEC_IDLE_CLOCK CONFIG_MUSIC_IDLE_CLOCK
+#define MUSIC_FSCAN_CLOCK CONFIG_MUSIC_FSCAN_CLOCK
+#define LINEIN_CLOCK CONFIG_LINEIN_CLOCK
+#define FM_CLOCK CONFIG_FM_CLOCK
+#define FM_EMITTER_CLOCK CONFIG_FM_EMITTER_CLOCK
+#define PC_CLOCK CONFIG_PC_CLOCK
+#define RECODRD_CLOCK CONFIG_RECORD_CLOCK
+#define SPDIF_CLOCK CONFIG_SPDIF_CLOCK
+
+////////////////////////
+#if TCFG_BT_SUPPORT_AAC || TCFG_BT_SUPPORT_LDAC
+#define BT_A2DP_STEREO_EQ_HZ 48 * 1000000L
+#else
+#define BT_A2DP_STEREO_EQ_HZ 32 * 1000000L
+#endif
+#define BT_A2DP_AAC_HZ 48 * 1000000L
+#define BT_A2DP_TWS_AAC_HZ 64 * 1000000L
+#define BT_A2DP_MONO_EQ_HZ 32 * 1000000L
+#define BT_A2DP_ONLINE_EQ_HZ 48 * 1000000L
+
+#define BT_CALL_SIMPLEX_HZ 96 * 1000000L
+#ifdef CONFIG_ANS_V2
+//#define BT_CALL_16k_HZ 96 * 1000000L
+//#define BT_CALL_16k_ADVANCE_HZ 120 * 1000000L
+#else
+//#define BT_CALL_16k_HZ 80 * 1000000L
+//#define BT_CALL_16k_ADVANCE_HZ 96 * 1000000L
+#endif
+#define BT_CALL_16k_SIMPLEX_HZ 120 * 1000000L
+////////////////////////
+
+#ifdef CONFIG_FPGA_ENABLE
+
+// #undef TCFG_CLOCK_OSC_HZ
+// #define TCFG_CLOCK_OSC_HZ 12000000
+
+#endif
+
+
+#ifdef CONFIG_CPU_BR26
+#undef BT_CALL_16k_HZ
+#undef BT_CALL_16k_ADVANCE_HZ
+#define BT_CALL_16k_HZ 96 * 1000000L
+#define BT_CALL_16k_ADVANCE_HZ 96 * 1000000L
+#endif
+
+#ifdef CONFIG_CPU_BR23
+#undef BT_A2DP_STEREO_EQ_HZ
+#define BT_A2DP_STEREO_EQ_HZ 48 * 1000000L
+#undef BT_A2DP_MONO_EQ_HZ
+#define BT_A2DP_MONO_EQ_HZ 48 * 1000000L
+#endif
+
+#ifdef CONFIG_CPU_BR25
+#undef BT_A2DP_STEREO_EQ_HZ
+#define BT_A2DP_STEREO_EQ_HZ 48 * 1000000L
+#undef BT_A2DP_MONO_EQ_HZ
+#define BT_A2DP_MONO_EQ_HZ 48 * 1000000L
+#endif
+
+#ifdef CONFIG_FPGA_ENABLE
+
+// #undef TCFG_CLOCK_OSC_HZ
+// #define TCFG_CLOCK_OSC_HZ 12000000
+
+#undef TCFG_MC_BIAS_AUTO_ADJUST
+#define TCFG_MC_BIAS_AUTO_ADJUST MC_BIAS_ADJUST_DISABLE
+
+#endif
+//*********************************************************************************//
+// 低功耗配置 //
+//*********************************************************************************//
+#if TCFG_IRKEY_ENABLE
+#undef TCFG_LOWPOWER_LOWPOWER_SEL
+#define TCFG_LOWPOWER_LOWPOWER_SEL 0 //开红外不进入低功耗
+#endif /* #if TCFG_IRKEY_ENABLE */
+
+//*********************************************************************************//
+// LED使用 16SLOT TIMER 同步 //
+//*********************************************************************************//
+//LED模块使用slot timer同步使用注意点:
+// 1.soundbox不开该功能, 原因: 默认打开osc时钟, 使用原来的osc流程同步即可
+// 2.带sd卡earphone不开该功能, 一般为单耳, 不需要同步, 使用原来的流程(lrc)
+// 3.一般用在tws应用中, 而且默认关闭osc;
+#if TCFG_USER_TWS_ENABLE
+#define TCFG_PWMLED_USE_SLOT_TIME ENABLE_THIS_MOUDLE
+#endif
+
+//*********************************************************************************//
+// 升级配置 //
+//*********************************************************************************//
+//升级LED显示使能
+//#define UPDATE_LED_REMIND
+//升级提示音使能
+//#define UPDATE_VOICE_REMIND
+
+#ifndef CONFIG_UPDATE_JUMP_TO_MASK
+#define CONFIG_UPDATE_JUMP_TO_MASK 0
+#endif
+
+#if CONFIG_UPDATE_JUMP_TO_MASK
+//升级IO保持使能
+#define DEV_UPDATE_SUPPORT_JUMP //目前只有br23\br25支持
+#endif
+
+
+#if TCFG_APP_MUSIC_EN
+#define CONFIG_SD_UPDATE_ENABLE
+#define CONFIG_USB_UPDATE_ENABLE
+#endif
+//*********************************************************************************//
+// Audio配置 //
+//*********************************************************************************//
+
+#if TCFG_AUDIO_ANC_ENABLE
+#if ((defined VOL_TYPE_ANALOG) && (SYS_VOL_TYPE == VOL_TYPE_ANALOG)) || \
+ ((defined VOL_TYPE_AD) && (SYS_VOL_TYPE == VOL_TYPE_AD))
+#error "ANC can not use VOL_TYPE_ANALOG and VOL_TYPE_AD!!!"
+#endif/*(SYS_VOL_TYPE = VOL_TYPE_ANALOG) || (SYS_VOL_TYPE = VOL_TYPE_AD)*/
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+
+/*通话语音处理算法放在.data段*/
+#ifndef TCFG_AUDIO_CVP_CODE_AT_RAM
+#define TCFG_AUDIO_CVP_CODE_AT_RAM 1
+#endif/*TCFG_AUDIO_CVP_CODE_AT_RAM*/
+
+/*AAC解码算法放在.data段*/
+#ifndef TCFG_AUDIO_AAC_CODE_AT_RAM
+#define TCFG_AUDIO_AAC_CODE_AT_RAM 1
+#endif/*TCFG_AUDIO_AAC_CODE_AT_RAM*/
+
+#if (TCFG_AUDIO_DUAL_MIC_ENABLE && TCFG_AUDIO_TRIPLE_MIC_ENABLE)
+#error "TCFG_AUDIO_DUAL_MIC_ENABLE and TCFG_AUDIO_TRIPLE_MIC_ENABLE can not enable together !!!"
+#endif
+
+//*********************************************************************************//
+// 充电中按键清除手机配对信息配置 //
+//*********************************************************************************//
+
+#define CHARGING_CLEAN_PHONE_INFO 0
+
+
+
+#endif
diff --git a/apps/earphone/include/app_main.h b/apps/earphone/include/app_main.h
new file mode 100644
index 0000000..c7e3c30
--- /dev/null
+++ b/apps/earphone/include/app_main.h
@@ -0,0 +1,136 @@
+#ifndef APP_MAIN_H
+#define APP_MAIN_H
+
+typedef struct _USR_VAR {
+ u8 usr_start_write_flash ;
+ u8 usr_plan_cnt ;
+ u8 usr_intterupt_reinit_falg ;
+ u8 usr_goto_updata ;
+ u8 usr_goto_pair ;
+ u8 usr_can_pair ;
+ u8 usr_ota_succ_flag ;
+ u8 usr_adv_flag ;
+ u8 usr_low_power_flag ;
+ u8 usr_allow_to_sleep_cnt;
+ u8 usr_power_charge_flag ;
+ u8 usr_disable_zjhendong;
+ u8 usr_enter_dlps_flag ;
+
+ u16 usr_bat_level_read ;
+ u16 usr_auto_off_cnt ;
+ u16 usr_interrupt_cnt ;
+ u16 usr_adv_interval ;
+ u16 usr_bat_level ;
+
+ u32 usr_data_index ;
+ u32 usr_allow_to_flash ;
+ u32 usr_ota_data_size ;
+ u32 usr_cureent_utc ;
+
+ int usr_double_ota_timer_id ;
+ int ota_timer ;
+ int usr_ota_data_id ;
+ int usr_timezoneOffset ;
+} USR_VAR;
+
+
+typedef struct {
+ float talk;
+ float ff;
+ float fb;
+} audio_mic_cmp_t;
+
+typedef struct _APP_VAR {
+ s8 bt_volume;
+ s8 dev_volume;
+ s8 music_volume;
+ s8 call_volume;
+ s8 wtone_volume;
+ u8 opid_play_vol_sync;
+ u8 aec_dac_gain;
+ u8 aec_mic_gain;
+ u8 aec_mic1_gain;
+ u8 aec_mic2_gain;
+ u8 aec_mic3_gain;
+ u8 rf_power;
+ u8 goto_poweroff_flag;
+ u8 goto_poweroff_cnt;
+ u8 play_poweron_tone;
+ u8 remote_dev_company;
+ u8 siri_stu;
+ u8 cycle_mode;
+ u8 have_mass_storage;
+ int auto_stop_page_scan_timer; //用于1拖2时,有一台连接上后,超过三分钟自动关闭Page Scan
+ volatile int auto_shut_down_timer;
+ volatile int wait_exit_timer;
+ u16 auto_off_time;
+ u16 warning_tone_v;
+ u16 poweroff_tone_v;
+ u16 phone_dly_discon_time;
+ u8 usb_mic_gain;
+ int wait_timer_do;
+ u32 start_time;
+ float audio_mic_array_diff_cmp;//麦克风阵列补偿值
+ u8 audio_mic_array_trim_en; //麦克风阵列校准
+ audio_mic_cmp_t audio_mic_cmp;
+ float enc_degradation;//default:1,range[0:1]
+ /*3麦通话配置使用:选择第几个mic*/
+ u8 talk_mic_ch; //主MIC通道选择
+ u8 talk_ref_mic_ch; //副MIC通道选择
+ u8 talk_fb_mic_ch; //FB通道选择
+} APP_VAR;
+
+typedef struct _BT_USER_PRIV_VAR {
+ //phone
+ u8 phone_ring_flag: 1;
+ u8 phone_num_flag: 1;
+ u8 phone_income_flag: 1;
+ u8 phone_call_dec_begin: 1;
+ u8 phone_con_sync_num_ring: 1;
+ u8 phone_con_sync_ring: 1;
+ // u8 reserved: 2;
+ u8 emitter_or_receiver: 2;
+ u8 get_phone_num_timecnt;
+
+ u8 inband_ringtone;
+ u8 phone_vol;
+ u16 phone_timer_id;
+ u8 last_call_type;
+ u8 income_phone_num[30];
+ u8 income_phone_len;
+ s32 auto_connection_counter;
+ int auto_connection_timer;
+ u8 auto_connection_addr[6];
+ int tws_con_timer;
+ u8 tws_start_con_cnt;
+ u8 tws_conn_state;
+ bool search_tws_ing;
+ int sniff_timer;
+ bool fast_test_mode;
+} BT_USER_PRIV_VAR;
+
+#define BT_EMITTER_EN 1
+#define BT_RECEIVER_EN 2
+#define earphone (&bt_user_priv_var)
+
+typedef struct _BT_USER_COMM_VAR {
+} BT_USER_COMM_VAR;
+
+
+
+
+
+
+
+
+
+
+
+extern APP_VAR app_var;
+extern USR_VAR usr_var;
+extern BT_USER_PRIV_VAR bt_user_priv_var;
+
+
+
+
+#endif
diff --git a/apps/earphone/include/app_online_cfg.h b/apps/earphone/include/app_online_cfg.h
new file mode 100644
index 0000000..1a181b1
--- /dev/null
+++ b/apps/earphone/include/app_online_cfg.h
@@ -0,0 +1,13 @@
+#ifndef ONLINE_CONFIG_H
+#define ONLINE_CONFIG_H
+
+#define DEVICE_EVENT_FROM_CI_UART (('C' << 24) | ('I' << 16) | ('U' << 8) | '\0')
+#define DEVICE_EVENT_FROM_CI_TWS (('C' << 24) | ('I' << 16) | ('T' << 8) | '\0')
+
+#define CI_UART 0
+#define CI_TWS 1
+
+void ci_data_rx_handler(u8 type);
+u32 eq_cfg_sync(u8 priority);
+#endif
+
diff --git a/apps/earphone/include/app_power_manage.h b/apps/earphone/include/app_power_manage.h
new file mode 100644
index 0000000..563ad10
--- /dev/null
+++ b/apps/earphone/include/app_power_manage.h
@@ -0,0 +1,39 @@
+#ifndef APP_POWER_MANAGE_H
+#define APP_POWER_MANAGE_H
+
+#include "typedef.h"
+#include "system/event.h"
+
+#define LOW_POWER_SHUTDOWN 300 //低电直接关机电压-拔出不开机-开盖不开机
+#define LOW_POWER_OFF_VAL 330 //低电关机电压
+#define LOW_POWER_WARN_VAL 340 //低电提醒电压
+#define LOW_POWER_WARN_TIME (60 * 1000) //低电提醒时间
+
+#define DEVICE_EVENT_FROM_POWER (('P' << 24) | ('O' << 16) | ('W' << 8) | '\0')
+
+enum {
+ POWER_EVENT_POWER_NORMAL,
+ POWER_EVENT_POWER_WARNING,
+ POWER_EVENT_POWER_LOW,
+ POWER_EVENT_POWER_CHANGE,
+ POWER_EVENT_SYNC_TWS_VBAT_LEVEL,
+ POWER_EVENT_POWER_CHARGE,
+};
+
+int app_power_event_handler(struct device_event *dev);
+void check_power_on_voltage(void);
+u16 get_vbat_level(void);
+u8 get_vbat_percent(void);
+void vbat_check_init(void);
+void vbat_timer_update(u32 msec);
+void vbat_timer_delete(void);
+void tws_sync_bat_level(void);
+u8 get_tws_sibling_bat_level(void);
+u8 get_tws_sibling_bat_persent(void);
+bool get_vbat_need_shutdown(void);
+u8 get_self_battery_level(void);
+
+void app_power_set_tws_sibling_bat_level(u8 vbat, u8 percent);
+
+#endif
+
diff --git a/apps/earphone/include/app_sd_music.h b/apps/earphone/include/app_sd_music.h
new file mode 100644
index 0000000..64106cd
--- /dev/null
+++ b/apps/earphone/include/app_sd_music.h
@@ -0,0 +1,6 @@
+#ifndef CONFIG_APP_SD_MUSIC_H
+#define CONFIG_APP_SD_MUSIC_H
+
+int music_app_check(void);//music 在线检测 切换模式判断使用
+
+#endif
diff --git a/apps/earphone/include/app_task.h b/apps/earphone/include/app_task.h
new file mode 100644
index 0000000..0587e1e
--- /dev/null
+++ b/apps/earphone/include/app_task.h
@@ -0,0 +1,32 @@
+#ifndef APP_TASK_H
+#define APP_TASK_H
+
+#include "typedef.h"
+#define NULL_VALUE 0
+
+enum {
+ APP_BT_TASK,
+#if TCFG_APP_MUSIC_EN
+ APP_MUSIC_TASK,
+#endif
+#if TCFG_PC_ENABLE
+ APP_PC_TASK,
+#endif
+ APP_RTC_TASK,
+#if TCFG_APP_AUX_EN
+ APP_AUX_TASK,
+#endif
+};
+
+extern u8 app_curr_task;
+extern u8 app_next_task;
+extern u8 app_prev_task;
+
+int app_task_switch_check(u8 app_task);
+int app_core_back_to_prev_app_over_check(void);
+int app_task_switch_to(u8 app_task, int priv);
+void app_task_switch_next(void);
+void app_task_switch_prev(void);
+u8 app_get_curr_task(void);
+
+#endif
diff --git a/apps/earphone/include/app_testbox.h b/apps/earphone/include/app_testbox.h
new file mode 100644
index 0000000..8b8421e
--- /dev/null
+++ b/apps/earphone/include/app_testbox.h
@@ -0,0 +1,18 @@
+#ifndef _APP_TESTBOX_H_
+#define _APP_TESTBOX_H_
+
+#include "typedef.h"
+#include "system/event.h"
+
+extern void testbox_set_bt_init_ok(u8 flag);
+extern u8 testbox_get_status(void);
+extern void testbox_clear_status(void);
+extern u8 testbox_get_ex_enter_dut_flag(void);
+extern u8 testbox_get_ex_enter_storage_mode_flag(void);
+extern u8 testbox_get_connect_status(void);
+extern void testbox_clear_connect_status(void);
+extern u8 testbox_get_keep_tws_conn_flag(void);
+extern int app_testbox_event_handler(struct testbox_event *testbox_dev);
+
+
+#endif //_APP_TESTBOX_H_
diff --git a/apps/earphone/include/audio_enc_mpt_self.h b/apps/earphone/include/audio_enc_mpt_self.h
new file mode 100644
index 0000000..aefb881
--- /dev/null
+++ b/apps/earphone/include/audio_enc_mpt_self.h
@@ -0,0 +1,69 @@
+
+#ifndef __AUDIO_ENC_MPT_FRE_RESPONE_H_
+#define __AUDIO_ENC_MPT_FRE_RESPONE_H_
+
+#include "asm/cpu.h"
+
+/********************用户配置****************************/
+
+//计算长度 输入单位s16/输出单位float
+#define AUDIO_ENC_MPT_FRERES_POINT 1024
+
+/********************非用户配置****************************/
+
+//MIC频响测试通道ID u16
+#define AUDIO_ENC_MPT_FF_MIC 0X01 //测试TWS FFMIC or 头戴式LFF MIC
+#define AUDIO_ENC_MPT_FB_MIC 0X02 //测试TWS FBMIC or 头戴式LFB MIC
+#define AUDIO_ENC_MPT_RFF_MIC 0X04 //测试头戴式RFF MIC
+#define AUDIO_ENC_MPT_RFB_MIC 0X08 //测试头戴式RFB MIC
+#define AUDIO_ENC_MPT_CVP_OUT 0X10 //测试通话算法输出
+#define AUDIO_ENC_MPT_TALK_MIC 0X20 //测试通话TALK 主MIC
+#define AUDIO_ENC_MPT_SLAVE_MIC 0X40 //测试通话TALK 副MIC
+#define AUDIO_ENC_MPT_TALK_FB_MIC 0X80 //测试通话TALK FBMIC
+
+//常见通道组合
+//FF+TALK+算法输出频响测试,默认关闭DNS, 外部喇叭发声
+#define AUDIO_ENC_MPT_CH_TWS_CVP_ENC (AUDIO_ENC_MPT_SLAVE_MIC | AUDIO_ENC_MPT_TALK_MIC | AUDIO_ENC_MPT_CVP_OUT)
+
+//FF回声/气密性+FB频响测试,耳机喇叭发声
+#define AUDIO_ENC_MPT_CH_TWS_FF_FB (AUDIO_ENC_MPT_FF_MIC | AUDIO_ENC_MPT_FB_MIC)
+
+
+#define AUDIO_ENC_MPT_FRERES_ASYNC 1 //是否异步处理, 异步算不过来要加时钟提醒
+
+enum {
+ ENC_FRE_RES_STATE_START = 0,
+ ENC_FRE_RES_STATE_RUN,
+ ENC_FRE_RES_STATE_STOP,
+};
+
+enum {
+ ENC_FRE_RESPONE_MSG_RUN = 0xA1,
+};
+
+//更新目标通道输入buf、len
+void audio_enc_mpt_fre_response_inbuf(u16 id, s16 *buf, int len);
+
+//音频测试频响计算运行
+void audio_enc_mpt_fre_response_post_run(u16 id);
+
+//音频测试频响计算启动, ch 对应目标的通道
+void audio_enc_mpt_fre_response_start(u16 ch);
+
+//音频测试频响计算停止
+void audio_enc_mpt_fre_response_stop(void);
+
+//工具获取数据文件
+int audio_enc_mpt_fre_response_file_get(u8 **buf);
+
+//数据获取结束,释放内存
+void audio_enc_mpt_fre_response_release(void);
+
+//音频测试MIC频响开启, ch 对应目标的通道
+void audio_enc_mpt_fre_response_open(u16 ch);
+
+//音频测试MIC频响关闭
+void audio_enc_mpt_fre_response_close(void);
+
+#endif /*__AUDIO_ENC_MPT_FRE_RESPONE_H_*/
+
diff --git a/apps/earphone/include/bt_background.h b/apps/earphone/include/bt_background.h
new file mode 100644
index 0000000..99cde25
--- /dev/null
+++ b/apps/earphone/include/bt_background.h
@@ -0,0 +1,43 @@
+#ifndef BT_BACKGROUND_H
+#define BT_BACKGROUND_H
+
+
+#include "generic/typedef.h"
+
+bool bt_in_background();
+
+
+void bt_switch_to_foreground(int action, bool exit_curr_app);
+
+
+int bt_switch_to_background();
+
+
+void bt_stop_a2dp_slience_detect();
+
+
+void bt_start_a2dp_slience_detect(int ingore_packet_num);
+
+
+int bt_background_event_probe_handler(struct bt_event *bt);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#endif
+
diff --git a/apps/earphone/include/bt_ble.h b/apps/earphone/include/bt_ble.h
new file mode 100644
index 0000000..b3de437
--- /dev/null
+++ b/apps/earphone/include/bt_ble.h
@@ -0,0 +1,48 @@
+#ifndef APP_BT_BLE_H
+#define APP_BT_BLE_H
+
+#include "typedef.h"
+
+// #define ADV_RSP_PACKET_MAX 31
+#define ADV_RAND_MAX 7
+
+// typedef struct {
+// u16 pid; //厂家id,默认用杰理的id (0x5d6)
+// u8 private_data[17];//厂家自定义数据内容
+
+// } manufacturer_data_t;
+
+enum {
+ ICON_TYPE_INQUIRY = 0,
+ ICON_TYPE_CONNECTED,
+ ICON_TYPE_RECONNECT,
+ ICON_TYPE_PRE_DEV,
+};
+
+
+enum {
+ ADV_ST_NULL,
+ ADV_ST_PRE1,
+ ADV_ST_PRE2,
+ ADV_ST_INQUIRY,
+ ADV_ST_CONN,
+ ADV_ST_RECONN,
+ ADV_ST_DISMISS,
+ ADV_ST_FAST_DISMISS,
+ ADV_ST_END,
+};
+
+extern void bt_ble_icon_set(u8 *info, u8 len);
+extern u8 bt_ble_get_adv_enable(void);
+extern void bt_ble_icon_open(u8 type);
+extern void bt_ble_icon_close(u8 dismiss_flag);
+extern void bt_ble_icon_set_comm_address(u8 *addr);
+extern void bt_ble_icon_reset(void);
+extern void bt_ble_set_control_en(u8 en);
+extern void bt_ble_icon_slave_en(u8 en);
+extern u8 bt_ble_icon_get_adv_state(void);
+extern void bt_ble_icon_role_switch(u8 role);
+extern void bt_ble_icon_state_sniff(u8 state);
+
+#endif
+
diff --git a/apps/earphone/include/bt_emitter.h b/apps/earphone/include/bt_emitter.h
new file mode 100644
index 0000000..f341a8d
--- /dev/null
+++ b/apps/earphone/include/bt_emitter.h
@@ -0,0 +1,26 @@
+#ifndef _BT_EMITTER_H
+#define _BT_EMITTER_H
+
+
+extern void bt_search_device(void);
+extern void emitter_search_noname(u8 status, u8 *addr, u8 *name);
+extern u8 bt_emitter_stu_set(u8 *addr, u8 on);
+extern u8 bt_emitter_stu_get(void);
+extern int bt_emitter_mic_open(void);
+extern void bt_emitter_mic_close(void);
+extern int bt_emitter_iis_open(void);
+extern void bt_emitter_iis_close(void);
+extern void emitter_media_source(u8 *addr, u8 source, u8 en);
+extern u8 emitter_search_result(char *name, u8 name_len, u8 *addr, u32 dev_class, char rssi);
+extern void emitter_search_stop(u8 result);
+extern void emitter_media_source(u8 *addr, u8 source, u8 en);
+extern void bt_emitter_receiver_sw();
+extern u8 bt_emitter_pp(u8 pp);
+extern void emitter_or_receiver_switch(u8 flag);
+extern u8 bt_emitter_role_get();
+extern void bt_emitter_start_search_device();
+extern void bt_emitter_stop_search_device();
+extern void emitter_open(u8 source);
+extern void emitter_close(u8 source);
+
+#endif
diff --git a/apps/earphone/include/bt_tws.h b/apps/earphone/include/bt_tws.h
new file mode 100644
index 0000000..77b03c1
--- /dev/null
+++ b/apps/earphone/include/bt_tws.h
@@ -0,0 +1,194 @@
+#ifndef APP_BT_TWS_H
+#define APP_BT_TWS_H
+
+#include "classic/tws_api.h"
+#include "classic/tws_event.h"
+#include "system/includes.h"
+
+#define TWS_FUNC_ID_VOL_SYNC TWS_FUNC_ID('V', 'O', 'L', 'S')
+#define TWS_FUNC_ID_VBAT_SYNC TWS_FUNC_ID('V', 'B', 'A', 'T')
+#define TWS_FUNC_ID_CHARGE_SYNC TWS_FUNC_ID('C', 'H', 'G', 'S')
+#define TWS_FUNC_ID_BOX_SYNC TWS_FUNC_ID('B', 'O', 'X', 'S')
+#define TWS_FUNC_ID_AI_DMA_RAND TWS_FUNC_ID('A', 'I', 'D', 'M')
+#define TWS_FUNC_ID_AI_SPEECH_STOP TWS_FUNC_ID('A', 'I', 'S', 'T')
+#define TWS_FUNC_ID_APP_MODE TWS_FUNC_ID('M', 'O', 'D', 'E')
+#define TWS_FUNC_ID_AI_SYNC TWS_FUNC_ID('A', 'I', 'P', 'A')
+#define TWS_FUNC_ID_EAR_DETECT_SYNC TWS_FUNC_ID('E', 'D', 'E', 'T')
+#define TWS_FUNC_ID_LL_SYNC_STATE TWS_FUNC_ID('L', 'L', 'S', 'S')
+#define TWS_FUNC_ID_TUYA_STATE TWS_FUNC_ID('T', 'U', 'Y', 'A')
+
+enum {
+ DEBUG_LINK_PAGE_STATE = 0,
+ DEBUG_LINK_INQUIRY_STATE,
+ DEBUG_LINK_PAGE_SCAN_STATE,
+ DEBUG_LINK_INQUIRY_SCAN_STATE,
+ DEBUG_LINK_CONNECTION_STATE,
+ DEBUG_LINK_PAGE_TWS_STATE,
+ DEBUG_LINK_PAGE_SCAN_TWS_STATE,
+};
+enum {
+ BT_TWS_STATUS_INIT_OK = 1,
+ BT_TWS_STATUS_SEARCH_START,
+ BT_TWS_STATUS_SEARCH_TIMEOUT,
+ BT_TWS_STATUS_PHONE_CONN,
+ BT_TWS_STATUS_PHONE_DISCONN,
+};
+
+enum {
+ SYNC_TONE_TWS_CONNECTED = 1,
+ SYNC_TONE_PHONE_CONNECTED,
+ SYNC_TONE_PHONE_DISCONNECTED,
+ SYNC_TONE_PHONE_NUM,
+ SYNC_TONE_PHONE_RING,
+ SYNC_TONE_PHONE_NUM_RING,
+ SYNC_TONE_MAX_VOL,
+ SYNC_TONE_POWER_OFF,
+ SYNC_TONE_ANC_ON,
+ SYNC_TONE_ANC_OFF,
+ SYNC_TONE_ANC_TRANS,
+ SYNC_TONE_EARDET_IN,
+ SYNC_TONE_VOICE_RECOGNIZE,
+ SYNC_TONE_HEARING_AID_OPEN,
+ SYNC_TONE_DHA_FITTING_CLOSE,
+ SYNC_TONE_ICSD_ADT_SUSPEND,
+ SYNC_TONE_ICSD_ADT_VOICE_STATE,
+ SYNC_TONE_ICSD_ADT_OPEN,
+};
+
+enum {
+ SYNC_LED_STA_TWS_CONN,
+ SYNC_LED_STA_PHONE_CONN,
+ SYNC_LED_STA_PHONE_DISCONN,
+};
+
+enum {
+ SYNC_CMD_SHUT_DOWN_TIME,
+ SYNC_CMD_POWER_OFF_TOGETHER,
+ SYNC_CMD_LOW_LATENCY_ENABLE,
+ SYNC_CMD_LOW_LATENCY_DISABLE,
+ SYNC_CMD_EARPHONE_CHAREG_START,
+ SYNC_CMD_IRSENSOR_EVENT_NEAR,
+ SYNC_CMD_IRSENSOR_EVENT_FAR,
+#if(USE_DMA_TONE)
+ SYNC_CMD_CUT_TWS_TONE, //断开对耳提示音
+ SYNC_CMD_START_SPEECH_TONE,//AI键提示音
+ SYNC_CMD_DMA_CONNECTED_ALL_FINISH_TONE, //AI连接成功
+ SYNC_CMD_NEED_BT_TONE, //需要连接蓝牙
+ SYNC_CMD_PLEASE_OPEN_XIAODU_TONE,//请打开小度
+#endif
+#if(RCSP_ADV_EN)
+ SYNC_CMD_SYNC_ADV_SETTING,
+ SYNC_CMD_ADV_COMMON_SETTING_SYNC,
+ SYNC_CMD_APP_RESET_LED_UI,
+ SYNC_CMD_MUSIC_INFO,
+ SYNC_CMD_RCSP_AUTH_RES,
+ SYNC_CMD_MUSIC_PLAYER_STATE,
+ SYNC_CMD_MUSIC_PLAYER_TIEM_EN,
+#endif
+ SYNC_CMD_OPUS_CLOSE,
+};
+
+enum {
+ TWS_SYNC_VOL = 0,
+ TWS_SYNC_VBAT,
+ TWS_SYNC_CHG,
+ TWS_SYNC_CALL_VOL,
+ TWS_SYNC_PBG_INFO,
+ TWS_SYNC_ADSP_UART_CMD,
+ TWS_APP_DATA_SEND,
+ TWS_AI_DMA_RAND,
+ TWS_DATA_SEND,
+
+ TWS_UPDATE_START,
+ TWS_UPDATE_RESULT_EXCHANGE,
+ TWS_UPDATE_RESULT_EXCHANGE_RES,
+ TWS_UPDATE_OVER,
+ TWS_UPDATE_OVER_CONFIRM,
+ TWS_UPDATE_OVER_CONFIRM_REQ,
+ TWS_UPDATE_OVER_CONFIRM_RES,
+ TWS_UPDATE_VERIFY,
+
+ TWS_AI_A2DP_DROP_FRAME_CTL,
+};
+struct tws_sync_info_t {
+ u8 type;
+ union {
+ s8 volume_lev;
+ u16 vbat_lev;
+ u8 chg_lev;
+ u8 adsp_cmd[2];
+ u8 conn_type;
+ u8 data[9];
+ u8 data_large[32];
+ } u;
+};
+
+
+
+struct tws_sync_big_info_t {
+ u8 type;
+ u8 sub_type;
+ union {
+ u8 pbg_info[36];
+ } u;
+};
+
+
+typedef struct time_stamp_bt_name {
+ u8 bt_name[32];
+ u32 time_stamp;
+} tws_time_stamp_bt_name;
+
+
+#define TWS_WAIT_CONN_TIMEOUT (400)
+
+#define TWS_SYNC_TIME_DO 400
+// #define TWS_CON_SUPER_TIMEOUT 8000
+#define TWS_CON_SEARCH_TIMEOUT 0x07//(n*1.28s)
+
+
+char bt_tws_get_local_channel();
+
+int bt_tws_connction_status_event_handler(struct bt_event *evt);
+
+int bt_tws_poweron();
+
+int bt_tws_poweroff();
+
+int bt_tws_start_search_sibling();
+
+void bt_tws_hci_event_connect();
+
+bool get_tws_phone_connect_state(void);
+
+int bt_tws_phone_connected();
+
+void bt_tws_phone_page_timeout();
+
+void bt_tws_phone_connect_timeout();
+
+void bt_tws_phone_disconnected();
+
+int bt_tws_sync_phone_num(void *priv);
+
+int bt_tws_sync_led_status();
+
+int get_bt_tws_connect_status();
+u8 get_bt_tws_discon_dly_state();
+
+void bt_tws_sync_volume();
+
+u8 tws_network_audio_was_started(void);
+
+void tws_network_local_audio_start(void);
+
+u32 bt_tws_future_slot_time(u32 msecs);
+
+void bt_tws_play_tone_at_same_time(int tone_name, int msec);
+void bt_tws_led_state_sync(int led_state, int msec);
+bool get_tws_sibling_connect_state(void);
+
+void tws_cancle_all_noconn();
+void tws_sniff_controle_check_enable(void);
+void tws_sniff_controle_check_disable(void);
+#endif
diff --git a/apps/earphone/include/default_event_handler.h b/apps/earphone/include/default_event_handler.h
new file mode 100644
index 0000000..0f5599c
--- /dev/null
+++ b/apps/earphone/include/default_event_handler.h
@@ -0,0 +1,41 @@
+#ifndef DEFAULT_EVENT_HANDLER_H
+#define DEFAULT_EVENT_HANDLER_H
+
+
+#include "system/includes.h"
+
+
+void default_event_handler(struct sys_event *event);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#endif
+
diff --git a/apps/earphone/include/earphone.h b/apps/earphone/include/earphone.h
new file mode 100644
index 0000000..68c7f83
--- /dev/null
+++ b/apps/earphone/include/earphone.h
@@ -0,0 +1,272 @@
+#ifndef EARPHONE_H
+#define EARPHONE_H
+
+#include "system/includes.h"
+///搜索完整结束的事件
+#define HCI_EVENT_INQUIRY_COMPLETE 0x01
+///连接完成的事件
+#define HCI_EVENT_CONNECTION_COMPLETE 0x03
+///断开的事件,会有一些错误码区分不同情况的断开
+#define HCI_EVENT_DISCONNECTION_COMPLETE 0x05
+///连接中请求pin code的事件,给这个事件上来目前是做了一个确认的操作
+#define HCI_EVENT_PIN_CODE_REQUEST 0x16
+///连接设备发起了简易配对加密的连接
+#define HCI_EVENT_IO_CAPABILITY_REQUEST 0x31
+///这个事件上来目前是做了一个连接确认的操作
+#define HCI_EVENT_USER_CONFIRMATION_REQUEST 0x33
+///这个事件是需要输入6个数字的连接消息,一般在键盘应用才会有
+#define HCI_EVENT_USER_PASSKEY_REQUEST 0x34
+///<可用于显示输入passkey位置 value 0:start 1:enrer 2:earse 3:clear 4:complete
+#define HCI_EVENT_USER_PRESSKEY_NOTIFICATION 0x3B
+///杰理自定义的事件,上电回连的时候读不到VM的地址。
+#define HCI_EVENT_VENDOR_NO_RECONN_ADDR 0xF8
+///杰理自定义的事件,有测试盒连接的时候会有这个事件
+#define HCI_EVENT_VENDOR_REMOTE_TEST 0xFE
+///杰理自定义的事件,可以认为是断开之后协议栈资源释放完成的事件
+#define BTSTACK_EVENT_HCI_CONNECTIONS_DELETE 0x6D
+
+
+#define ERROR_CODE_SUCCESS 0x00
+///<回连超时退出消息
+#define ERROR_CODE_PAGE_TIMEOUT 0x04
+///<连接过程中linkkey错误
+#define ERROR_CODE_AUTHENTICATION_FAILURE 0x05
+///<连接过程中linkkey丢失,手机删除了linkkey,回连就会出现一次
+#define ERROR_CODE_PIN_OR_KEY_MISSING 0x06
+///<连接超时,一般拿远就会断开有这个消息
+#define ERROR_CODE_CONNECTION_TIMEOUT 0x08
+///<连接个数超出了资源允许
+#define ERROR_CODE_SYNCHRONOUS_CONNECTION_LIMIT_TO_A_DEVICE_EXCEEDED 0x0A
+///<回连的时候发现设备还没释放我们这个地址,一般直接断电开机回连会出现
+#define ERROR_CODE_ACL_CONNECTION_ALREADY_EXISTS 0x0B
+///<需要回连的设备资源不够。有些手机连了一个设备之后就会用这个拒绝。或者其它的资源原因
+#define ERROR_CODE_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES 0x0D
+///<有些可能只允许指定地址连接的,可能会用这个去拒绝连接。或者我们设备的地址全0或者有问题
+#define ERROR_CODE_CONNECTION_REJECTED_DUE_TO_UNACCEPTABLE_BD_ADDR 0x0F
+///<连接的时间太长了,手机要断开了。这种容易复现可以联系我们分析
+#define ERROR_CODE_CONNECTION_ACCEPT_TIMEOUT_EXCEEDED 0x10
+///<经常用的连接断开消息。就认为断开就行
+#define ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION 0x13
+///<正常的断开消息,本地L2CAP资源释放之后就会发这个值上来了
+#define ERROR_CODE_CONNECTION_TERMINATED_BY_LOCAL_HOST 0x16
+///<回连的时候发现设备两次role switch失败了,发断开在重新连接
+#define ERROR_CODE_ROLE_SWITCH_FAILED 0x35
+///杰理自定义,在回连的过程中使用page cancel命令主动取消成功会有这个命令
+#define CUSTOM_BB_AUTO_CANCEL_PAGE 0xFD //// app cancle page
+///杰理自定义,库里面有些功能需要停止page的时候会有。比如page的时候来了电话
+#define BB_CANCEL_PAGE 0xFE //// bb cancle page
+
+
+#if (TCFG_USER_BLE_ENABLE && (CONFIG_BT_MODE == BT_NORMAL))
+
+#if RCSP_ADV_EN
+
+int rcsp_earphone_state_init();
+int rcsp_earphone_state_set_page_scan_enable();
+int rcsp_earphone_state_get_connect_mac_addr();
+int rcsp_earphone_state_cancel_page_scan();
+int rcsp_earphone_state_enter_soft_poweroff();
+int rcsp_earphone_state_tws_init(int paired);
+int rcsp_earphone_state_tws_connected(int first_pair, u8 *comm_addr);
+int rcsp_sys_event_handler_specific(struct sys_event *event);
+
+#define EARPHONE_STATE_INIT() rcsp_earphone_state_init()
+#define EARPHONE_STATE_SET_PAGE_SCAN_ENABLE() rcsp_earphone_state_set_page_scan_enable()
+#define EARPHONE_STATE_GET_CONNECT_MAC_ADDR() rcsp_earphone_state_get_connect_mac_addr()
+#define EARPHONE_STATE_CANCEL_PAGE_SCAN() rcsp_earphone_state_cancel_page_scan()
+#define EARPHONE_STATE_ENTER_SOFT_POWEROFF() rcsp_earphone_state_enter_soft_poweroff()
+#define EARPHONE_STATE_TWS_INIT(a) rcsp_earphone_state_tws_init(a)
+#define EARPHONE_STATE_TWS_CONNECTED(a, b) rcsp_earphone_state_tws_connected(a,b)
+#define SYS_EVENT_HANDLER_SPECIFIC(a) rcsp_sys_event_handler_specific(a)
+#define SYS_EVENT_REMAP(a) 0
+#define EARPHONE_STATE_SNIFF(a)
+#define EARPHONE_STATE_ROLE_SWITCH(a)
+
+#elif TRANS_DATA_EN
+
+int trans_data_earphone_state_init();
+int trans_data_earphone_state_set_page_scan_enable();
+int trans_data_earphone_state_get_connect_mac_addr();
+int trans_data_earphone_state_cancel_page_scan();
+int trans_data_earphone_state_enter_soft_poweroff();
+int trans_data_earphone_state_tws_init(int paired);
+int trans_data_earphone_state_tws_connected(int first_pair, u8 *comm_addr);
+int trans_data_sys_event_handler_specific(struct sys_event *event);
+
+#define EARPHONE_STATE_INIT() trans_data_earphone_state_init()
+#define EARPHONE_STATE_SET_PAGE_SCAN_ENABLE() trans_data_earphone_state_set_page_scan_enable()
+#define EARPHONE_STATE_GET_CONNECT_MAC_ADDR() trans_data_earphone_state_get_connect_mac_addr()
+#define EARPHONE_STATE_CANCEL_PAGE_SCAN() trans_data_earphone_state_cancel_page_scan()
+#define EARPHONE_STATE_ENTER_SOFT_POWEROFF() trans_data_earphone_state_enter_soft_poweroff()
+#define EARPHONE_STATE_TWS_INIT(a) trans_data_earphone_state_tws_init(a)
+#define EARPHONE_STATE_TWS_CONNECTED(a, b) trans_data_earphone_state_tws_connected(a,b)
+#define SYS_EVENT_HANDLER_SPECIFIC(a) trans_data_sys_event_handler_specific(a)
+#define SYS_EVENT_REMAP(a) 0
+#define EARPHONE_STATE_SNIFF(a)
+#define EARPHONE_STATE_ROLE_SWITCH(a)
+
+#elif BLE_HID_EN
+
+int ble_hid_earphone_state_init();
+int ble_hid_earphone_state_set_page_scan_enable();
+int ble_hid_earphone_state_get_connect_mac_addr();
+int ble_hid_earphone_state_cancel_page_scan();
+int ble_hid_earphone_state_enter_soft_poweroff();
+int ble_hid_earphone_state_tws_init(int paired);
+int ble_hid_earphone_state_tws_connected(int first_pair, u8 *comm_addr);
+int ble_hid_sys_event_handler_specific(struct sys_event *event);
+
+#define EARPHONE_STATE_INIT() ble_hid_earphone_state_init()
+#define EARPHONE_STATE_SET_PAGE_SCAN_ENABLE() ble_hid_earphone_state_set_page_scan_enable()
+#define EARPHONE_STATE_GET_CONNECT_MAC_ADDR() ble_hid_earphone_state_get_connect_mac_addr()
+#define EARPHONE_STATE_CANCEL_PAGE_SCAN() ble_hid_earphone_state_cancel_page_scan()
+#define EARPHONE_STATE_ENTER_SOFT_POWEROFF() ble_hid_earphone_state_enter_soft_poweroff()
+#define EARPHONE_STATE_TWS_INIT(a) ble_hid_earphone_state_tws_init(a)
+#define EARPHONE_STATE_TWS_CONNECTED(a, b) ble_hid_earphone_state_tws_connected(a,b)
+#define SYS_EVENT_HANDLER_SPECIFIC(a) ble_hid_sys_event_handler_specific(a)
+#define SYS_EVENT_REMAP(a) 0
+#define EARPHONE_STATE_SNIFF(a)
+#define EARPHONE_STATE_ROLE_SWITCH(a)
+
+
+
+#elif LL_SYNC_EN
+
+int ll_sync_earphone_state_init();
+int ll_sync_earphone_state_set_page_scan_enable();
+int ll_sync_earphone_state_get_connect_mac_addr();
+int ll_sync_earphone_state_cancel_page_scan();
+int ll_sync_earphone_state_enter_soft_poweroff();
+int ll_sync_earphone_state_tws_init(int paired);
+int ll_sync_earphone_state_tws_connected(int first_pair, u8 *comm_addr);
+int ll_sync_sys_event_handler_specific(struct sys_event *event);
+
+#define EARPHONE_STATE_INIT() ll_sync_earphone_state_init()
+#define EARPHONE_STATE_SET_PAGE_SCAN_ENABLE() ll_sync_earphone_state_set_page_scan_enable()
+#define EARPHONE_STATE_GET_CONNECT_MAC_ADDR() ll_sync_earphone_state_get_connect_mac_addr()
+#define EARPHONE_STATE_CANCEL_PAGE_SCAN() ll_sync_earphone_state_cancel_page_scan()
+#define EARPHONE_STATE_ENTER_SOFT_POWEROFF() ll_sync_earphone_state_enter_soft_poweroff()
+#define EARPHONE_STATE_TWS_INIT(a) ll_sync_earphone_state_tws_init(a)
+#define EARPHONE_STATE_TWS_CONNECTED(a, b) ll_sync_earphone_state_tws_connected(a,b)
+#define SYS_EVENT_HANDLER_SPECIFIC(a) ll_sync_sys_event_handler_specific(a)
+#define SYS_EVENT_REMAP(a) 0
+#define EARPHONE_STATE_SNIFF(a)
+#define EARPHONE_STATE_ROLE_SWITCH(a)
+
+#elif TUYA_DEMO_EN
+int tuya_earphone_state_init();
+int tuya_earphone_state_set_page_scan_enable();
+int tuya_earphone_state_get_connect_mac_addr();
+int tuya_earphone_state_cancel_page_scan();
+int tuya_earphone_state_enter_soft_poweroff();
+int tuya_earphone_state_tws_init(int paired);
+int tuya_earphone_state_tws_connected(int first_pair, u8 *comm_addr);
+int tuya_sys_event_handler_specific(struct sys_event *event);
+
+#define EARPHONE_STATE_INIT() tuya_earphone_state_init()
+#define EARPHONE_STATE_SET_PAGE_SCAN_ENABLE() tuya_earphone_state_set_page_scan_enable()
+#define EARPHONE_STATE_GET_CONNECT_MAC_ADDR() tuya_earphone_state_get_connect_mac_addr()
+#define EARPHONE_STATE_CANCEL_PAGE_SCAN() tuya_earphone_state_cancel_page_scan()
+#define EARPHONE_STATE_ENTER_SOFT_POWEROFF() tuya_earphone_state_enter_soft_poweroff()
+#define EARPHONE_STATE_TWS_INIT(a) tuya_earphone_state_tws_init(a)
+#define EARPHONE_STATE_TWS_CONNECTED(a, b) tuya_earphone_state_tws_connected(a,b)
+#define SYS_EVENT_HANDLER_SPECIFIC(a) tuya_sys_event_handler_specific(a)
+#define SYS_EVENT_REMAP(a) 0
+#define EARPHONE_STATE_SNIFF(a)
+#define EARPHONE_STATE_ROLE_SWITCH(a)
+
+
+#elif (AI_APP_PROTOCOL | LE_AUDIO_EN)
+
+int app_protocol_sys_event_handler(struct sys_event *event);
+#define EARPHONE_STATE_INIT() do { } while(0)
+#define EARPHONE_STATE_SET_PAGE_SCAN_ENABLE() do { } while(0)
+#define EARPHONE_STATE_GET_CONNECT_MAC_ADDR() do { } while(0)
+#define EARPHONE_STATE_CANCEL_PAGE_SCAN() do { } while(0)
+#define EARPHONE_STATE_ENTER_SOFT_POWEROFF() do { } while(0)
+#define EARPHONE_STATE_TWS_INIT(a) do { } while(0)
+#define EARPHONE_STATE_TWS_CONNECTED(a, b) do { } while(0)
+#define SYS_EVENT_HANDLER_SPECIFIC(a) app_protocol_sys_event_handler(a)
+#define SYS_EVENT_REMAP(a) 0
+#define EARPHONE_STATE_SNIFF(a)
+#define EARPHONE_STATE_ROLE_SWITCH(a)
+
+#elif TCFG_WIRELESS_MIC_ENABLE
+#define EARPHONE_STATE_INIT() do { } while(0)
+#define EARPHONE_STATE_SET_PAGE_SCAN_ENABLE() do { } while(0)
+#define EARPHONE_STATE_GET_CONNECT_MAC_ADDR() do { } while(0)
+#define EARPHONE_STATE_CANCEL_PAGE_SCAN() do { } while(0)
+#define EARPHONE_STATE_ENTER_SOFT_POWEROFF() do { } while(0)
+#define EARPHONE_STATE_TWS_INIT(a) do { } while(0)
+#define EARPHONE_STATE_TWS_CONNECTED(a, b) do { } while(0)
+#define SYS_EVENT_HANDLER_SPECIFIC(a) do { } while(0)
+#define SYS_EVENT_REMAP(a) 0
+#define EARPHONE_STATE_SNIFF(a)
+#define EARPHONE_STATE_ROLE_SWITCH(a)
+
+#else
+int adv_earphone_state_init();
+int adv_earphone_state_set_page_scan_enable();
+int adv_earphone_state_get_connect_mac_addr();
+int adv_earphone_state_cancel_page_scan();
+int adv_earphone_state_enter_soft_poweroff();
+int adv_earphone_state_tws_init(int paired);
+int adv_earphone_state_tws_connected(int first_pair, u8 *comm_addr);
+int adv_sys_event_handler_specific(struct sys_event *event);
+int adv_earphone_state_sniff(u8 state);
+int adv_earphone_state_role_switch(u8 role);
+
+#define EARPHONE_STATE_INIT() adv_earphone_state_init()
+#define EARPHONE_STATE_SET_PAGE_SCAN_ENABLE() adv_earphone_state_set_page_scan_enable()
+#define EARPHONE_STATE_GET_CONNECT_MAC_ADDR() adv_earphone_state_get_connect_mac_addr()
+#define EARPHONE_STATE_CANCEL_PAGE_SCAN() adv_earphone_state_cancel_page_scan()
+#define EARPHONE_STATE_ENTER_SOFT_POWEROFF() adv_earphone_state_enter_soft_poweroff()
+#define EARPHONE_STATE_TWS_INIT(a) adv_earphone_state_tws_init(a)
+#define EARPHONE_STATE_TWS_CONNECTED(a, b) adv_earphone_state_tws_connected(a,b)
+#define SYS_EVENT_HANDLER_SPECIFIC(a) adv_sys_event_handler_specific(a)
+#define SYS_EVENT_REMAP(a) 0
+#define EARPHONE_STATE_SNIFF(a) adv_earphone_state_sniff(a)
+#define EARPHONE_STATE_ROLE_SWITCH(a) adv_earphone_state_role_switch(a)
+
+#endif
+
+
+#else
+
+#define EARPHONE_STATE_INIT() do { } while(0)
+#define EARPHONE_STATE_SET_PAGE_SCAN_ENABLE() do { } while(0)
+#define EARPHONE_STATE_GET_CONNECT_MAC_ADDR() do { } while(0)
+#define EARPHONE_STATE_CANCEL_PAGE_SCAN() do { } while(0)
+#define EARPHONE_STATE_ENTER_SOFT_POWEROFF() do { } while(0)
+#define EARPHONE_STATE_TWS_INIT(a) do { } while(0)
+#define EARPHONE_STATE_TWS_CONNECTED(a, b) do { } while(0)
+#define SYS_EVENT_HANDLER_SPECIFIC(a) do { } while(0)
+#define SYS_EVENT_REMAP(a) 0
+#define EARPHONE_STATE_SNIFF(a)
+#define EARPHONE_STATE_ROLE_SWITCH(a)
+#endif
+
+
+
+
+extern void sys_auto_shut_down_enable(void);
+
+extern void sys_auto_shut_down_disable(void);
+
+extern int bt_in_background_event_handler(struct sys_event *event);
+
+extern u8 bt_app_exit_check(void);
+
+
+
+
+
+
+
+
+
+
+
+
+
+#endif
diff --git a/apps/earphone/include/key_event_deal.h b/apps/earphone/include/key_event_deal.h
new file mode 100644
index 0000000..cb01cf1
--- /dev/null
+++ b/apps/earphone/include/key_event_deal.h
@@ -0,0 +1,103 @@
+#ifndef __KEY_EVENT_DEAL_H__
+#define __KEY_EVENT_DEAL_H__
+
+#include "typedef.h"
+#include "bt_profile_cfg.h"
+#include "system/event.h"
+
+enum {
+ KEY_POWER_ON = KEY_EVENT_MAX,
+ KEY_POWEROFF,
+ KEY_POWEROFF_HOLD,
+ KEY_POWEROFF_HOLD_UP,
+ KEY_MUSIC_PP,
+ KEY_MUSIC_PREV,
+ KEY_MUSIC_NEXT,
+ KEY_VOL_UP,
+ KEY_VOL_DOWN,
+ KEY_CALL_LAST_NO,
+ KEY_CALL_HANG_UP,
+ KEY_CALL_ANSWER,
+ KEY_CALL_ANSWER_UP,
+ KEY_OPEN_SIRI,
+ KEY_HID_CONTROL,
+ KEY_LOW_LANTECY,
+ KEY_MODE_SWITCH,
+ KEY_IR_NUM_0,
+ KEY_IR_NUM_1,
+ KEY_IR_NUM_2,
+ KEY_EQ_MODE,
+ KEY_THIRD_CLICK,
+
+ KEY_MUSIC_FF,
+ KEY_MUSIC_FR,
+ KEY_MUSIC_PLAYER_START,
+ KEY_MUSIC_PLAYER_END,
+ KEY_MUSIC_PLAYER_DEC_ERR,
+ KEY_MUSIC_DEVICE_TONE_END,
+ KEY_MUSIC_PLAYER_QUIT,
+ KEY_MUSIC_PLAYER_AUTO_NEXT,
+ KEY_MUSIC_PLAYER_PLAY_FIRST,
+ KEY_MUSIC_PLAYER_PLAY_LAST,
+ KEY_MUSIC_CHANGE_REPEAT,
+ KEY_MUSIC_CHANGE_DEV,
+ KEY_MUSIC_AUTO_NEXT_DEV,
+ KEY_MUSIC_CHANGE_DEV_REPEAT,
+ KEY_MUSIC_SET_PITCH,
+ KEY_MUSIC_SET_SPEED,
+ KEY_MUSIC_PLAYE_BY_DEV_FILENUM,
+ KEY_MUSIC_PLAYE_BY_DEV_SCLUST,
+ KEY_MUSIC_PLAYE_BY_DEV_PATH,
+ KEY_MUSIC_DELETE_FILE,
+ KEY_MUSIC_PLAYE_NEXT_FOLDER,
+ KEY_MUSIC_PLAYE_PREV_FOLDER,
+ KEY_MUSIC_PLAYE_REC_FOLDER_SWITCH,
+ KEY_MUSIC_PLAYER_AB_REPEAT_SWITCH,
+
+ KEY_SEND_SPEECH_START,
+ KEY_SEND_SPEECH_STOP,
+#if (BT_FOR_APP_EN)
+ KEY_AI_DEC_SUSPEND,
+ KEY_AI_DEC_RESUME,
+
+#endif
+
+ KEY_EARTCH_ENABLE,
+ KEY_EARTCH_DISABLE,
+ KEY_ANC_SWITCH,
+ KEY_ANC_EAR_ADAPTIVE,
+ KEY_ANC_COEFF_SWITCH,
+ KEY_MUSIC_EFF, //播歌音效切换
+ KEY_PHONE_PITCH,//通话上行 变声切换
+ KEY_HEARING_AID_TOGGLE,//辅听功能开关
+
+ MSG_HALF_SECOND,
+ KEY_CLEAN_PHONE_INFO,
+ KEY_CLEAN_PHONE_INFO_HOLD,
+ KEY_CLEAN_PHONE_INFO_UP,
+
+ KEY_SPATIAL_EFFECT_MODE_SWITCH, /*切换空间音频模式*/
+ KEY_SPEAK_TO_CHAT_SWITCH, /*智能免摘开关*/
+ KEY_WIND_NOISE_DET_SWITCH, /*风噪检测开关*/
+ KEY_WIDE_AREA_TAP_SWITCH, /*广域点击开关*/
+ KEY_ANC_MULT_SCENE_SWITCH, /*多滤波器切换demo*/
+ KEY_NULL = 0xFF,
+};
+
+enum {
+ ONE_KEY_CTL_NEXT_PREV = 1,
+ ONE_KEY_CTL_VOL_UP_DOWN,
+};
+
+enum {
+ EARTCH_STATE_IN,
+ EARTCH_STATE_OUT,
+ EARTCH_STATE_TRIM_OK,
+ EARTCH_STATE_TRIM_ERR,
+};
+
+extern void volume_up(u8 inc);
+extern void volume_down(u8 inc);
+extern int app_earphone_key_event_handler(struct sys_event *);
+
+#endif
diff --git a/apps/earphone/include/pbg_user.h b/apps/earphone/include/pbg_user.h
new file mode 100644
index 0000000..c2442fe
--- /dev/null
+++ b/apps/earphone/include/pbg_user.h
@@ -0,0 +1,31 @@
+#ifndef PBG_USER_H_
+#define PBG_USER_H_
+
+#include "typedef.h"
+#include "key_event_deal.h"
+
+enum {
+ PBG_POS_IN_EAR = 0, //入耳
+ PBG_POS_OUT_BOX, //出仓
+ PBG_POS_IN_BOX, //在仓
+ PBG_POS_NOT_EXIST, //不在线
+ PBG_POS_KEEP_NOW = 0x0f, //维持,不改变
+ PBG_POS_MAX, //
+};
+
+
+#define BD_ADDR_LEN 6
+typedef uint8_t bd_addr_t[BD_ADDR_LEN];
+
+void pbg_user_set_tws_state(u8 conn_flag);
+void pbg_user_recieve_sync_info(u8 *sync_info);
+void pbg_user_mic_fixed_deal(u8 mode);
+void pbg_user_event_deal(struct pbg_event *evt);
+bool pbg_user_key_vaild(u8 *key_msg, struct sys_event *event);
+void pbg_user_ear_pos_sync(u8 left, u8 right);
+void pbg_user_battery_level_sync(u8 *dev_bat);
+int pbg_user_is_connected(void);
+
+#endif
+
+
diff --git a/apps/earphone/include/tone_player.h b/apps/earphone/include/tone_player.h
new file mode 100644
index 0000000..32e458f
--- /dev/null
+++ b/apps/earphone/include/tone_player.h
@@ -0,0 +1,157 @@
+#ifndef TONE_PLAYER_H
+#define TONE_PLAYER_H
+
+#include "app_config.h"
+#include "tone_player_api.h"
+
+#define TONE_NUM_0 SDFILE_RES_ROOT_PATH"tone/0.*"
+#define TONE_NUM_1 SDFILE_RES_ROOT_PATH"tone/1.*"
+#define TONE_NUM_2 SDFILE_RES_ROOT_PATH"tone/2.*"
+#define TONE_NUM_3 SDFILE_RES_ROOT_PATH"tone/3.*"
+#define TONE_NUM_4 SDFILE_RES_ROOT_PATH"tone/4.*"
+#define TONE_NUM_5 SDFILE_RES_ROOT_PATH"tone/5.*"
+#define TONE_NUM_6 SDFILE_RES_ROOT_PATH"tone/6.*"
+#define TONE_NUM_7 SDFILE_RES_ROOT_PATH"tone/7.*"
+#define TONE_NUM_8 SDFILE_RES_ROOT_PATH"tone/8.*"
+#define TONE_NUM_9 SDFILE_RES_ROOT_PATH"tone/9.*"
+#define TONE_BT_MODE SDFILE_RES_ROOT_PATH"tone/bt.*"
+#define TONE_BT_CONN SDFILE_RES_ROOT_PATH"tone/bt_conn.*"
+#define TONE_BT_DISCONN SDFILE_RES_ROOT_PATH"tone/bt_dconn.*"
+#define TONE_TWS_CONN SDFILE_RES_ROOT_PATH"tone/tws_conn.*"
+#define TONE_TWS_DISCONN SDFILE_RES_ROOT_PATH"tone/tws_dconn.*"
+#define TONE_LOW_POWER SDFILE_RES_ROOT_PATH"tone/low_power.*"
+#define TONE_POWER_OFF SDFILE_RES_ROOT_PATH"tone/power_off.*"
+#define TONE_POWER_ON SDFILE_RES_ROOT_PATH"tone/power_on.*"
+#define TONE_RING SDFILE_RES_ROOT_PATH"tone/ring.*"
+#define TONE_MAX_VOL SDFILE_RES_ROOT_PATH"tone/vol_max.*"
+#define TONE_ANC_OFF SDFILE_RES_ROOT_PATH"tone/anc_off.*"
+#define TONE_ANC_ON SDFILE_RES_ROOT_PATH"tone/anc_on.*"
+#define TONE_TRANSPARENCY SDFILE_RES_ROOT_PATH"tone/anc_trans.*"
+#define TONE_ANC_ADAPTIVE SDFILE_RES_ROOT_PATH"tone/adaptive.*"
+#define TONE_ANC_ADAPTIVE_COEFF SDFILE_RES_ROOT_PATH"tone/adap_coeff.*"
+#define TONE_ANC_NORMAL_COEFF SDFILE_RES_ROOT_PATH"tone/nor_coeff.*"
+#define TONE_EAR_CHECK SDFILE_RES_ROOT_PATH"tone/ear_check.*"
+#define TONE_MUSIC_MODE SDFILE_RES_ROOT_PATH"tone/music.*"
+#define TONE_PC_MODE SDFILE_RES_ROOT_PATH"tone/pc.*"
+#define TONE_SPKCHAT_OFF SDFILE_RES_ROOT_PATH"tone/spkchat_off.*"
+#define TONE_SPKCHAT_ON SDFILE_RES_ROOT_PATH"tone/spkchat_on.*"
+#define TONE_WCLICK_OFF SDFILE_RES_ROOT_PATH"tone/wclick_off.*"
+#define TONE_WCLICK_ON SDFILE_RES_ROOT_PATH"tone/wclick_on.*"
+#define TONE_WINDDET_OFF SDFILE_RES_ROOT_PATH"tone/winddet_off.*"
+#define TONE_WINDDET_ON SDFILE_RES_ROOT_PATH"tone/winddet_on.*"
+
+
+#define SINE_WTONE_NORAML 0
+#define SINE_WTONE_TWS_CONNECT 1
+#define SINE_WTONE_TWS_DISCONNECT 2
+#define SINE_WTONE_LOW_POWER 4
+#define SINE_WTONE_RING 5
+#define SINE_WTONE_MAX_VOLUME 6
+#define SINE_WTONE_ADSP 7
+#define SINE_WTONE_LOW_LATENRY_IN 8
+#define SINE_WTONE_LOW_LATENRY_OUT 9
+#define SINE_WTONE_ANC_ADAPTIVE_1 10
+#define SINE_WTONE_ANC_ADAPTIVE_2 11
+
+#if CONFIG_USE_DEFAULT_SINE
+#undef TONE_TWS_CONN
+#define TONE_TWS_CONN DEFAULT_SINE_TONE(SINE_WTONE_TWS_CONNECT)
+#undef TONE_TWS_DISCONN
+#define TONE_TWS_DISCONN DEFAULT_SINE_TONE(SINE_WTONE_TWS_DISCONNECT)
+
+#undef TONE_MAX_VOL
+#define TONE_MAX_VOL DEFAULT_SINE_TONE(SINE_WTONE_MAX_VOLUME)
+
+#undef TONE_NORMAL
+#define TONE_NORMAL DEFAULT_SINE_TONE(SINE_WTONE_NORAML)
+#if BT_PHONE_NUMBER
+
+#else
+#undef TONE_RING
+#define TONE_RING DEFAULT_SINE_TONE(SINE_WTONE_RING)
+#endif
+
+#undef TONE_LOW_POWER
+#define TONE_LOW_POWER DEFAULT_SINE_TONE(SINE_WTONE_LOW_POWER)
+#endif
+
+#define TONE_SIN_NORMAL DEFAULT_SINE_TONE(SINE_WTONE_NORAML)
+
+#define TONE_LOW_LATENCY_IN DEFAULT_SINE_TONE(SINE_WTONE_LOW_LATENRY_IN)
+#define TONE_LOW_LATENCY_OUT DEFAULT_SINE_TONE(SINE_WTONE_LOW_LATENRY_OUT)
+
+#define TONE_ANC_ADAPTIVE_LVL1 DEFAULT_SINE_TONE(SINE_WTONE_ANC_ADAPTIVE_1)
+#define TONE_ANC_ADAPTIVE_LVL2 DEFAULT_SINE_TONE(SINE_WTONE_ANC_ADAPTIVE_2)
+
+
+enum {
+ IDEX_TONE_NUM_0,
+ IDEX_TONE_NUM_1,
+ IDEX_TONE_NUM_2,
+ IDEX_TONE_NUM_3,
+ IDEX_TONE_NUM_4,
+ IDEX_TONE_NUM_5,
+ IDEX_TONE_NUM_6,
+ IDEX_TONE_NUM_7,
+ IDEX_TONE_NUM_8,
+ IDEX_TONE_NUM_9,
+ IDEX_TONE_BT_MODE,
+ IDEX_TONE_BT_CONN,
+ IDEX_TONE_BT_DISCONN,
+ IDEX_TONE_TWS_CONN,
+ IDEX_TONE_TWS_DISCONN,
+ IDEX_TONE_LOW_POWER,
+ IDEX_TONE_POWER_OFF,
+ IDEX_TONE_POWER_ON,
+ IDEX_TONE_RING,
+ IDEX_TONE_MAX_VOL,
+ IDEX_TONE_NORMAL,
+ IDEX_TONE_ANC_OFF,
+ IDEX_TONE_ANC_ON,
+ IDEX_TONE_TRANSPARCNCY,
+ IDEX_TONE_ANC_ADAPTIVE,
+ IDEX_TONE_ANC_ADAPTIVE_COEFF,
+ IDEX_TONE_ANC_NORMAL_COEFF,
+
+
+ IDEX_TONE_NONE = 0xFF,
+};
+
+
+
+int tone_play_init(void);
+int tone_play_index(u8 index, u8 preemption);
+int tone_play_index_with_callback(u8 index, u8 preemption, void (*user_evt_handler)(void *priv), void *priv);
+int tone_play_index_no_tws(u8 index, u8 preemption);
+/*
+ *@brief:提示音比较,确认目标提示音和正在播放的提示音是否一致
+ *@return: 0 匹配
+ * 非0 不匹配或者当前没有提示音播放
+ *@note:通过提示音索引比较
+ */
+int tone_name_cmp_by_index(u8 index);
+
+
+// 按键提示音初始化
+int audio_key_tone_init(void);
+// 注销按键提示音播放
+void audio_key_tone_destroy(void);
+
+// 播放正弦波数组
+int audio_key_tone_play_sin(struct audio_sin_param *sin, u8 sin_num, u8 preemption);
+// 播放文件
+int audio_key_tone_play_name(const char *name, u8 preemption);
+// 按序号播放文件 // 使用key_tone_index[]数组
+int audio_key_tone_play_index(u8 index, u8 preemption);
+// 按键提示音播放 // 默认播放数组中第一个
+void audio_key_tone_play(void);
+
+// 检测按键提示音是否在播放
+int audio_key_tone_is_play(void);
+
+// 设置按键提示音的音量
+void audio_key_tone_digvol_set(u8 volume);
+
+#endif
+
+
diff --git a/apps/earphone/include/ui_manage.h b/apps/earphone/include/ui_manage.h
new file mode 100644
index 0000000..622af09
--- /dev/null
+++ b/apps/earphone/include/ui_manage.h
@@ -0,0 +1,39 @@
+#ifndef __UI_MANAGE_H_
+#define __UI_MANAGE_H_
+
+#include "typedef.h"
+
+typedef enum {
+ STATUS_NULL = 0,
+ STATUS_POWERON,
+ STATUS_POWEROFF,
+ STATUS_POWERON_LOWPOWER,
+ STATUS_BT_INIT_OK,
+ STATUS_BT_CONN,
+ STATUS_BT_SLAVE_CONN_MASTER,
+ STATUS_BT_MASTER_CONN_ONE,
+ STATUS_BT_DISCONN,
+ STATUS_BT_TWS_CONN,
+ STATUS_BT_TWS_DISCONN,
+ STATUS_PHONE_INCOME,
+ STATUS_PHONE_OUT,
+ STATUS_PHONE_ACTIV,
+ STATUS_CHARGE_START,
+ STATUS_CHARGE_FULL,
+ STATUS_CHARGE_CLOSE,
+ STATUS_CHARGE_ERR,
+ STATUS_LOWPOWER,
+ STATUS_CHARGE_LDO5V_OFF,
+ STATUS_EXIT_LOWPOWER,
+ STATUS_NORMAL_POWER,
+ STATUS_POWER_NULL,
+} UI_STATUS;
+
+
+int ui_manage_init(void);
+void ui_update_status(u8 status);
+u8 get_ui_busy_status();
+void led_module_enter_sniff_mode();
+void led_module_exit_sniff_mode();
+
+#endif
diff --git a/apps/earphone/include/user_cfg_id.h b/apps/earphone/include/user_cfg_id.h
new file mode 100644
index 0000000..665bb46
--- /dev/null
+++ b/apps/earphone/include/user_cfg_id.h
@@ -0,0 +1,68 @@
+#ifndef _USER_CFG_ID_H_
+#define _USER_CFG_ID_H_
+
+//=================================================================================//
+// 与APP CASE相关配置项[1 ~ 60] //
+//=================================================================================//
+
+#define CFG_EARTCH_ENABLE_ID 1
+#define CFG_PBG_MODE_INFO 2
+#define CFG_CHARGESTORE_TWS_CHANNEL 3
+#define CFG_SYS_VOL 4
+
+#define CFG_MIC_ARRAY_DIFF_CMP_VALUE 5//麦克风阵列算法前补偿值
+#define CFG_MIC_ARRAY_TRIM_EN 6//麦克风补偿使能
+#define CFG_DMS_MALFUNC_STATE_ID 7//dms故障麦克风检测默认使用哪个mic的参数id
+#define CFG_MIC_TARGET_DIFF_CMP 8//目标MIC补偿值
+
+
+
+#define CFG_DHA_FITTING_ID 26 //辅听验配保存参数的id
+#define CFG_REMOTE_DN_00 27
+
+#define CFG_IMU_GYRO_OFFEST_ID 28 //空间音频imu陀螺仪偏置
+#define CFG_IMU_ACC_OFFEST_ID 29 //空间音频imu加速度偏置
+
+#define VM_LP_TOUCH_KEY0_ALOG_CFG 30
+#define VM_LP_TOUCH_KEY1_ALOG_CFG 31
+#define VM_LP_TOUCH_KEY2_ALOG_CFG 32
+#define VM_LP_TOUCH_KEY3_ALOG_CFG 33
+#define VM_LP_TOUCH_KEY4_ALOG_CFG 34
+
+#define VM_UPDATE_FLAG 35
+#define VM_DMA_RAND 36
+#define VM_DMA_RAND 37
+#define VM_GMA_ALI_PARA 38
+#define CFG_BCS_MAP_WEIGHT 39
+#define CFG_RCSP_ADV_HIGH_LOW_VOL 40
+#define CFG_RCSP_ADV_EQ_MODE_SETTING 41
+#define CFG_RCSP_ADV_EQ_DATA_SETTING 42
+#define ADV_SEQ_RAND 43
+#define CFG_RCSP_ADV_TIME_STAMP 44
+#define CFG_RCSP_ADV_WORK_SETTING 45
+#define CFG_RCSP_ADV_MIC_SETTING 46
+#define CFG_RCSP_ADV_LED_SETTING 47
+#define CFG_RCSP_ADV_KEY_SETTING 48
+
+#define CFG_USB_BREAKPOINT0 49
+#define CFG_SD0_BREAKPOINT0 50
+#define CFG_SD1_BREAKPOINT0 51
+
+#define CFG_HAVE_MASS_STORAGE 52
+#define CFG_MUSIC_MODE 53
+
+#define LP_KEY_EARTCH_TRIM_VALUE 54
+
+#define CFG_RCSP_ADV_ANC_VOICE 55
+#define CFG_RCSP_ADV_ANC_VOICE_MODE 56
+#define CFG_RCSP_ADV_ANC_VOICE_KEY 57
+
+
+#define CFG_SPK_EQ_SEG_SAVE 58
+#define CFG_SPK_EQ_GLOBAL_GAIN_SAVE 59
+
+#define CFG_ANC_ADAPTIVE_DATA_ID 60//保存ANC自适应参数id
+
+#define CFG_REMOTE_DN_00 63
+
+#endif /* #ifndef _USER_CFG_ID_H_ */
diff --git a/apps/earphone/include/vol_sync.h b/apps/earphone/include/vol_sync.h
new file mode 100644
index 0000000..9786120
--- /dev/null
+++ b/apps/earphone/include/vol_sync.h
@@ -0,0 +1,9 @@
+#ifndef __VOL_SYNC_H__
+#define __VOL_SYNC_H__
+
+void vol_sys_tab_init(void);
+void set_music_device_volume(int volume);
+int phone_get_device_vol(void);
+void opid_play_vol_sync_fun(u8 *vol, u8 mode);
+
+#endif
diff --git a/apps/earphone/key_event_deal.c b/apps/earphone/key_event_deal.c
new file mode 100644
index 0000000..7b5015c
--- /dev/null
+++ b/apps/earphone/key_event_deal.c
@@ -0,0 +1,431 @@
+#include "key_event_deal.h"
+#include "btstack/avctp_user.h"
+#include "event.h"
+#include "app_power_manage.h"
+#include "app_main.h"
+#include "app_task.h"
+#include "tone_player.h"
+#include "audio_config.h"
+#include "user_cfg.h"
+#include "system/timer.h"
+#include "vol_sync.h"
+#include "media/includes.h"
+#include "pbg_user.h"
+#include "key_driver.h"
+#if TCFG_EQ_ENABLE
+#include "application/eq_config.h"
+#endif/*TCFG_EQ_ENABLE*/
+
+#if TCFG_USER_TWS_ENABLE
+#include "bt_tws.h"
+#endif
+#if TCFG_AUDIO_ANC_ENABLE
+#include "audio_anc.h"
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+#include "icsd_adt_app.h"
+#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
+
+#define LOG_TAG_CONST KEY_EVENT_DEAL
+#define LOG_TAG "[KEY_EVENT_DEAL]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#define POWER_OFF_CNT 10
+
+extern u8 key_table[KEY_NUM_MAX][KEY_EVENT_MAX];
+extern u8 get_max_sys_vol(void);
+extern void sys_enter_soft_poweroff(void *priv);
+extern bool get_tws_sibling_connect_state(void);
+extern int bt_get_low_latency_mode();
+extern void bt_set_low_latency_mode(int enable);
+
+void audio_aec_pitch_change_ctrl();
+void audio_surround_voice_ctrl();
+extern void start_streamer_test(void);
+extern void usr_intterupt_close();
+
+
+u8 poweroff_sametime_flag = 0;
+
+#if CONFIG_TWS_POWEROFF_SAME_TIME
+enum {
+ FROM_HOST_POWEROFF_CNT_ENOUGH = 1,
+ FROM_TWS_POWEROFF_CNT_ENOUGH,
+ POWEROFF_CNT_ENOUGH,
+};
+
+static u16 poweroff_sametime_timer_id = 0;
+static void poweroff_sametime_timer(void *priv)
+{
+ log_info("poweroff_sametime_timer\n");
+ int state = tws_api_get_tws_state();
+ if (!(state & TWS_STA_SIBLING_CONNECTED)) {
+ sys_enter_soft_poweroff(NULL);
+ return;
+ }
+ if (priv == NULL || poweroff_sametime_flag == POWEROFF_CNT_ENOUGH) {
+ poweroff_sametime_timer_id = sys_timeout_add((void *)1, poweroff_sametime_timer, 500);
+ } else {
+ poweroff_sametime_timer_id = 0;
+ }
+}
+
+static void poweroff_sametime_timer_init(void)
+{
+ if (poweroff_sametime_timer_id) {
+ return;
+ }
+
+ poweroff_sametime_timer_id = sys_timeout_add(NULL, poweroff_sametime_timer, 500);
+}
+#endif
+
+void volume_up_down_direct(s8 value);
+
+#if TCFG_USER_TWS_ENABLE
+u8 replay_tone_flag = 1;
+int max_tone_timer_hdl = 0;
+static void max_tone_timer(void *priv)
+{
+ if (!tone_get_status()) {
+ max_tone_timer_hdl = 0;
+ replay_tone_flag = 1;
+ } else {
+ max_tone_timer_hdl = sys_timeout_add(NULL, max_tone_timer, TWS_SYNC_TIME_DO + 100);
+ }
+}
+#endif
+
+static u8 volume_flag = 1;
+void volume_up(u8 inc)
+{
+ u8 test_box_vol_up = 0x41;
+ s8 cur_vol = 0;
+ u8 call_status = get_call_status();
+
+ if (tone_get_status() && volume_flag) {
+ if (get_call_status() == BT_CALL_INCOMING) {
+ volume_up_down_direct(1);
+ }
+ return;
+ }
+
+ /*打电话出去彩铃要可以调音量大小*/
+ if ((call_status == BT_CALL_ACTIVE) || (call_status == BT_CALL_OUTGOING)) {
+ cur_vol = app_audio_get_volume(APP_AUDIO_STATE_CALL);
+ } else {
+ cur_vol = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
+ }
+ if (get_remote_test_flag()) {
+ user_send_cmd_prepare(USER_CTRL_TEST_KEY, 1, &test_box_vol_up); //音量加
+ }
+
+ if (cur_vol >= app_audio_get_max_volume()) {
+#if TCFG_USER_TWS_ENABLE
+ if (get_tws_sibling_connect_state()) {
+ if (tws_api_get_role() == TWS_ROLE_MASTER && replay_tone_flag) {
+ replay_tone_flag = 0; //防止提示音被打断标志
+ bt_tws_play_tone_at_same_time(SYNC_TONE_MAX_VOL, 400);
+ max_tone_timer_hdl = sys_timeout_add(NULL, max_tone_timer, TWS_SYNC_TIME_DO + 100); //同步在TWS_SYNC_TIME_DO之后才会播放提示音,所以timer需要在这个时间之后才去检测提示音状态
+ }
+ } else
+#endif
+ {
+#if TCFG_MAX_VOL_PROMPT
+ STATUS *p_tone = get_tone_config();
+ tone_play_index(p_tone->max_vol, 0);
+#endif
+ }
+
+ if (get_call_status() != BT_CALL_HANGUP) {
+ /*本地音量最大,如果手机音量还没最大,继续加,以防显示不同步*/
+ if (bt_user_priv_var.phone_vol < 15) {
+ if (get_curr_channel_state() & HID_CH) {
+ user_send_cmd_prepare(USER_CTRL_HID_VOL_UP, 0, NULL);
+ } else {
+ user_send_cmd_prepare(USER_CTRL_HFP_CALL_VOLUME_UP, 0, NULL);
+ }
+ }
+ return;
+ }
+#if BT_SUPPORT_MUSIC_VOL_SYNC
+ opid_play_vol_sync_fun(&app_var.music_volume, 1);
+ user_send_cmd_prepare(USER_CTRL_CMD_SYNC_VOL_INC, 0, NULL);
+#endif/*BT_SUPPORT_MUSIC_VOL_SYNC*/
+ return;
+ }
+
+#if BT_SUPPORT_MUSIC_VOL_SYNC
+ opid_play_vol_sync_fun(&app_var.music_volume, 1);
+ app_audio_set_volume(APP_AUDIO_STATE_MUSIC, app_var.music_volume, 1);
+#else
+ app_audio_volume_up(inc);
+#endif/*BT_SUPPORT_MUSIC_VOL_SYNC*/
+ log_info("vol+: %d", app_audio_get_volume(APP_AUDIO_CURRENT_STATE));
+ if (get_call_status() != BT_CALL_HANGUP) {
+ if (get_curr_channel_state() & HID_CH) {
+ user_send_cmd_prepare(USER_CTRL_HID_VOL_UP, 0, NULL);
+ } else {
+ user_send_cmd_prepare(USER_CTRL_HFP_CALL_VOLUME_UP, 0, NULL);
+ }
+ } else {
+#if BT_SUPPORT_MUSIC_VOL_SYNC
+ /* opid_play_vol_sync_fun(&app_var.music_volume, 1); */
+
+#if TCFG_USER_TWS_ENABLE
+ user_send_cmd_prepare(USER_CTRL_CMD_SYNC_VOL_INC, 0, NULL); //使用HID调音量
+ //user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_SEND_VOL, 0, NULL);
+#else
+ user_send_cmd_prepare(USER_CTRL_CMD_SYNC_VOL_INC, 0, NULL);
+#endif/*TCFG_USER_TWS_ENABLE*/
+#endif/*BT_SUPPORT_MUSIC_VOL_SYNC*/
+ }
+}
+void volume_down(u8 dec)
+{
+ u8 test_box_vol_down = 0x42;
+ if (tone_get_status() && volume_flag) {
+ if (get_call_status() == BT_CALL_INCOMING) {
+ volume_up_down_direct(-1);
+ }
+ return;
+ }
+ if (get_remote_test_flag()) {
+ user_send_cmd_prepare(USER_CTRL_TEST_KEY, 1, &test_box_vol_down); //音量减
+ }
+
+ if (app_audio_get_volume(APP_AUDIO_CURRENT_STATE) <= 0) {
+ if (get_call_status() != BT_CALL_HANGUP) {
+ /*
+ *本地音量最小,如果手机音量还没最小,继续减
+ *注意:有些手机通话最小音量是1(GREE G0245D)
+ */
+ if (bt_user_priv_var.phone_vol > 1) {
+ if (get_curr_channel_state() & HID_CH) {
+ user_send_cmd_prepare(USER_CTRL_HID_VOL_DOWN, 0, NULL);
+ } else {
+ user_send_cmd_prepare(USER_CTRL_HFP_CALL_VOLUME_DOWN, 0, NULL);
+
+ }
+ }
+ return;
+ }
+#if BT_SUPPORT_MUSIC_VOL_SYNC
+ opid_play_vol_sync_fun(&app_var.music_volume, 0);
+ user_send_cmd_prepare(USER_CTRL_CMD_SYNC_VOL_DEC, 0, NULL);
+#endif
+ return;
+ }
+
+#if BT_SUPPORT_MUSIC_VOL_SYNC
+ opid_play_vol_sync_fun(&app_var.music_volume, 0);
+ app_audio_set_volume(APP_AUDIO_STATE_MUSIC, app_var.music_volume, 1);
+#else
+ app_audio_volume_down(dec);
+#endif/*BT_SUPPORT_MUSIC_VOL_SYNC*/
+ log_info("vol-: %d", app_audio_get_volume(APP_AUDIO_CURRENT_STATE));
+ if (get_call_status() != BT_CALL_HANGUP) {
+ if (get_curr_channel_state() & HID_CH) {
+ user_send_cmd_prepare(USER_CTRL_HID_VOL_DOWN, 0, NULL);
+ } else {
+ user_send_cmd_prepare(USER_CTRL_HFP_CALL_VOLUME_DOWN, 0, NULL);
+ }
+ } else {
+#if BT_SUPPORT_MUSIC_VOL_SYNC
+ /* opid_play_vol_sync_fun(&app_var.music_volume, 0); */
+ if (app_audio_get_volume(APP_AUDIO_CURRENT_STATE) == 0) {
+ app_audio_volume_down(0);
+ }
+
+#if TCFG_USER_TWS_ENABLE
+ user_send_cmd_prepare(USER_CTRL_CMD_SYNC_VOL_DEC, 0, NULL);
+ //user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_SEND_VOL, 0, NULL);
+#else
+ user_send_cmd_prepare(USER_CTRL_CMD_SYNC_VOL_DEC, 0, NULL);
+#endif
+
+#endif
+ }
+}
+
+
+
+#if ONE_KEY_CTL_DIFF_FUNC
+static void lr_diff_otp_deal(u8 opt, char channel)
+{
+ log_info("lr_diff_otp_deal:%d", opt);
+ switch (opt) {
+ case ONE_KEY_CTL_NEXT_PREV:
+ if (channel == 'L') {
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_NEXT, 0, NULL);
+ } else if (channel == 'R') {
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PREV, 0, NULL);
+ } else {
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_NEXT, 0, NULL);
+ }
+ break;
+ case ONE_KEY_CTL_VOL_UP_DOWN:
+ if (channel == 'L') {
+ volume_up(1);
+ } else if (channel == 'R') {
+ volume_down(1);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void key_tws_lr_diff_deal(struct sys_event *event, u8 opt)
+{
+ u8 channel = 'U';
+ if (get_bt_tws_connect_status()) {
+ channel = tws_api_get_local_channel();
+ if ('L' == channel) {
+ channel = (u32)event->arg == KEY_EVENT_FROM_TWS ? 'R' : 'L';
+ } else {
+ channel = (u32)event->arg == KEY_EVENT_FROM_TWS ? 'L' : 'R';
+ }
+ }
+ lr_diff_otp_deal(opt, channel);
+}
+#else
+void key_tws_lr_diff_deal(struct sys_event *event, u8 opt)
+{
+}
+#endif
+
+int app_earphone_key_event_handler(struct sys_event *event)
+{
+ int ret = false;
+ struct key_event *key = &event->u.key;
+
+ u8 key_event;
+
+#if TCFG_APP_MUSIC_EN
+ if (event->arg == DEVICE_EVENT_FROM_CUSTOM) {
+ log_e("is music mode msg\n");
+ return false;
+ }
+#endif
+
+
+ key_event = key_table[key->value][key->event];
+
+ void bt_sniff_ready_clean(void);
+ bt_sniff_ready_clean();
+
+#if RCSP_ADV_EN
+ extern void set_key_event_by_rcsp_info(struct sys_event * event, u8 * key_event);
+ set_key_event_by_rcsp_info(event, &key_event);
+#endif
+
+ log_info("key_event:%d %d %d\n", key_event, key->value, key->event);
+
+ switch (key_event) {
+ case KEY_MUSIC_PP:
+ break;
+ case KEY_IR_NUM_0:
+// tone_play_by_path(TONE_POWER_ON, 0);
+ break;
+ case KEY_IR_NUM_1:
+// tone_play_by_path(TONE_RING, 0);
+ break;
+ case KEY_IR_NUM_2:
+// tone_play_by_path(TONE_RING, 0);
+ break;
+ case KEY_POWEROFF:
+ if(usr_var.usr_power_charge_flag==1)break;
+ poweroff_sametime_flag = 0;
+ user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL);
+ break;
+ case KEY_POWEROFF_HOLD:
+ break;
+ case KEY_POWEROFF_HOLD_UP:
+ break;
+ case KEY_MUSIC_PREV:
+ break;
+ case KEY_MUSIC_NEXT:
+ break;
+ case KEY_VOL_UP:
+ volume_up(1);
+ break;
+ case KEY_VOL_DOWN:
+ volume_down(1);
+ break;
+ case KEY_CALL_LAST_NO:
+ if (bt_user_priv_var.last_call_type == BT_STATUS_PHONE_INCOME) {
+ user_send_cmd_prepare(USER_CTRL_DIAL_NUMBER, bt_user_priv_var.income_phone_len,
+ bt_user_priv_var.income_phone_num);
+ } else {
+ user_send_cmd_prepare(USER_CTRL_HFP_CALL_LAST_NO, 0, NULL);
+ }
+ break;
+ case KEY_CALL_HANG_UP:
+
+ break;
+ case KEY_CALL_ANSWER:
+ /* sys_enter_soft_poweroff(NULL); */
+ break;
+ case KEY_OPEN_SIRI:
+ user_send_cmd_prepare(USER_CTRL_HFP_GET_SIRI_OPEN, 0, NULL);
+ break;
+ case KEY_EQ_MODE:
+#if(TCFG_EQ_ENABLE == 1)
+ eq_mode_sw();
+#endif
+ break;
+ case KEY_HID_CONTROL:
+ log_info("get_curr_channel_state:%x\n", get_curr_channel_state());
+ if (get_curr_channel_state() & HID_CH) {
+ log_info("KEY_HID_CONTROL\n");
+ user_send_cmd_prepare(USER_CTRL_HID_IOS, 0, NULL);
+ }
+ break;
+ case KEY_THIRD_CLICK:
+ log_info("KEY_THIRD_CLICK");
+ key_tws_lr_diff_deal(event, ONE_KEY_CTL_NEXT_PREV);
+ break;
+ case KEY_LOW_LANTECY:
+ bt_set_low_latency_mode(!bt_get_low_latency_mode());
+ break;
+
+ case KEY_NULL:
+ break;
+ case KEY_MUSIC_EFF:
+
+ break;
+
+ case KEY_PHONE_PITCH:
+
+ break;
+
+#if TCFG_APP_AUX_EN
+ case KEY_MODE_SWITCH:
+ log_info("KEY_MODE_SWITCH");
+ app_task_switch_next();
+ break;
+#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
+ }
+ return ret;
+}
+
+void adsp_volume_up(void)
+{
+ volume_flag = 0;
+ volume_up(1);
+ volume_flag = 1;
+}
+
+void adsp_volume_down(void)
+{
+ volume_flag = 0;
+ volume_down(1);
+ volume_flag = 1;
+}
+
diff --git a/apps/earphone/kws_voice_event_deal.c b/apps/earphone/kws_voice_event_deal.c
new file mode 100644
index 0000000..3414e44
--- /dev/null
+++ b/apps/earphone/kws_voice_event_deal.c
@@ -0,0 +1,182 @@
+#include "includes.h"
+#include "event.h"
+#include "app_config.h"
+#include "btstack/avctp_user.h"
+#include "media/kws_event.h"
+
+#if TCFG_USER_TWS_ENABLE
+#include "bt_tws.h"
+#endif
+#if TCFG_AUDIO_ANC_ENABLE
+#include "audio_anc.h"
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+
+#define LOG_TAG_CONST KWS_VOICE_EVENT
+#define LOG_TAG "[KWS_VOICE_EVENT]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#if ((defined TCFG_KWS_VOICE_EVENT_HANDLE_ENABLE) && (TCFG_KWS_VOICE_EVENT_HANDLE_ENABLE))
+
+struct jl_kws_event_hdl {
+ u32 last_event;
+ u32 last_event_jiffies;
+};
+
+static struct jl_kws_event_hdl kws_hdl = {
+ .last_event = 0,
+ .last_event_jiffies = 0,
+};
+
+#define __this (&kws_hdl)
+
+
+extern void volume_up(u8 inc);
+extern void volume_down(u8 inc);
+
+/* ---------------------------------------------------------------------------- */
+/**
+ * @brief: 关键词唤醒语音事件处理流程
+ *
+ * @param event: 系统事件
+ *
+ * @return : true: 处理该事件; false: 不处理该事件, 由
+ */
+/* ---------------------------------------------------------------------------- */
+int jl_kws_voice_event_handle(struct sys_event *event)
+{
+ struct key_event *key = &(event->u.key);
+
+ if (key->type != KEY_DRIVER_TYPE_VOICE) {
+ return false;
+ }
+
+ u32 cur_jiffies = jiffies;
+ u8 a2dp_state;
+ u8 call_state;
+ u32 voice_event = key->event;
+
+ log_info("%s: event: %d", __func__, voice_event);
+
+ if (voice_event == __this->last_event) {
+ if (jiffies_to_msecs(cur_jiffies - __this->last_event_jiffies) < 1000) {
+ log_info("voice event %d same, ignore", voice_event);
+ __this->last_event_jiffies = cur_jiffies;
+ return true;
+ }
+ }
+ __this->last_event_jiffies = cur_jiffies;
+ __this->last_event = voice_event;
+
+ switch (voice_event) {
+ case KWS_EVENT_HEY_KEYWORD:
+ case KWS_EVENT_XIAOJIE:
+ //主唤醒词:
+ log_info("send SIRI cmd");
+ user_send_cmd_prepare(USER_CTRL_HFP_GET_SIRI_OPEN, 0, NULL);
+ break;
+
+ case KWS_EVENT_XIAODU:
+ //主唤醒词:
+ log_info("send SIRI cmd");
+ user_send_cmd_prepare(USER_CTRL_HFP_GET_SIRI_OPEN, 0, NULL);
+ break;
+
+ case KWS_EVENT_PLAY_MUSIC:
+ case KWS_EVENT_STOP_MUSIC:
+ case KWS_EVENT_PAUSE_MUSIC:
+ call_state = get_call_status();
+ if ((call_state == BT_CALL_OUTGOING) ||
+ (call_state == BT_CALL_ALERT)) {
+ //user_send_cmd_prepare(USER_CTRL_HFP_CALL_HANGUP, 0, NULL);
+ } else if (call_state == BT_CALL_INCOMING) {
+ //user_send_cmd_prepare(USER_CTRL_HFP_CALL_ANSWER, 0, NULL);
+ } else if (call_state == BT_CALL_ACTIVE) {
+ //user_send_cmd_prepare(USER_CTRL_HFP_CALL_HANGUP, 0, NULL);
+ } else {
+ a2dp_state = a2dp_get_status();
+ if (a2dp_state == BT_MUSIC_STATUS_STARTING) {
+ if (voice_event == KWS_EVENT_PAUSE_MUSIC) {
+ log_info("send PAUSE cmd");
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PAUSE, 0, NULL);
+ } else if (voice_event == KWS_EVENT_STOP_MUSIC) {
+ log_info("send STOP cmd");
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_STOP, 0, NULL);
+ }
+ } else {
+ if (voice_event == KWS_EVENT_PLAY_MUSIC) {
+ log_info("send PLAY cmd");
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PLAY, 0, NULL);
+ }
+ }
+ }
+ break;
+
+ case KWS_EVENT_VOLUME_UP:
+ log_info("volume up");
+ volume_up(4); //music: 0 ~ 16, call: 0 ~ 15, step: 25%
+ break;
+
+ case KWS_EVENT_VOLUME_DOWN:
+ log_info("volume down");
+ volume_down(4); //music: 0 ~ 16, call: 0 ~ 15, step: 25%
+ break;
+
+ case KWS_EVENT_PREV_SONG:
+ log_info("Send PREV cmd");
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PREV, 0, NULL);
+ break;
+
+ case KWS_EVENT_NEXT_SONG:
+ log_info("Send NEXT cmd");
+ user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_NEXT, 0, NULL);
+ break;
+
+ case KWS_EVENT_CALL_ACTIVE:
+ if (get_call_status() == BT_CALL_INCOMING) {
+ log_info("Send ANSWER cmd");
+ user_send_cmd_prepare(USER_CTRL_HFP_CALL_ANSWER, 0, NULL);
+ }
+ break;
+
+ case KWS_EVENT_CALL_HANGUP:
+ log_info("Send HANG UP cmd");
+ if ((get_call_status() >= BT_CALL_INCOMING) && (get_call_status() <= BT_CALL_ALERT)) {
+ user_send_cmd_prepare(USER_CTRL_HFP_CALL_HANGUP, 0, NULL);
+ }
+ break;
+#if TCFG_AUDIO_ANC_ENABLE
+ case KWS_EVENT_ANC_ON:
+ anc_mode_switch(ANC_ON, 1);
+ break;
+ case KWS_EVENT_TRANSARENT_ON:
+ anc_mode_switch(ANC_TRANSPARENCY, 1);
+ break;
+ case KWS_EVENT_ANC_OFF:
+ anc_mode_switch(ANC_OFF, 1);
+ break;
+#endif
+
+ case KWS_EVENT_NULL:
+ log_info("KWS_EVENT_NULL");
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+#else /* #if ((defined TCFG_KWS_VOICE_EVENT_HANDLE_ENABLE) && (TCFG_KWS_VOICE_EVENT_HANDLE_ENABLE)) */
+
+int jl_kws_voice_event_handle(struct key_event *key)
+{
+ return false;
+}
+
+#endif /* #if ((defined TCFG_KWS_VOICE_EVENT_HANDLE_ENABLE) && (TCFG_KWS_VOICE_EVENT_HANDLE_ENABLE)) */
diff --git a/apps/earphone/log_config/app_config.c b/apps/earphone/log_config/app_config.c
new file mode 100644
index 0000000..a307a06
--- /dev/null
+++ b/apps/earphone/log_config/app_config.c
@@ -0,0 +1,180 @@
+/*********************************************************************************************
+ * Filename : log_config.c
+
+ * Description : Optimized Code & RAM (编译优化Log配置)
+
+ * Author : Bingquan
+
+ * Email : caibingquan@zh-jieli.com
+
+ * Last modifiled : 2019-03-18 14:45
+
+ * Copyright:(c)JIELI 2011-2019 @ , All Rights Reserved.
+*********************************************************************************************/
+#include "system/includes.h"
+
+/**
+ * @brief Bluetooth Controller Log
+ */
+/*-----------------------------------------------------------*/
+const char log_tag_const_v_SETUP AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_SETUP AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_SETUP AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_d_SETUP AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_SETUP AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_BOARD AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_BOARD AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_BOARD AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_w_BOARD AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_BOARD AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_EARPHONE AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_EARPHONE AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_EARPHONE AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_EARPHONE AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_EARPHONE AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_UI AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_UI AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_UI AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_UI AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_UI AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_APP_CHARGE AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_APP_CHARGE AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_APP_CHARGE AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_APP_CHARGE AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_APP_CHARGE AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_APP_ANCBOX AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_APP_ANCBOX AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_APP_ANCBOX AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_APP_ANCBOX AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_APP_ANCBOX AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_KEY_EVENT_DEAL AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_KEY_EVENT_DEAL AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_KEY_EVENT_DEAL AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_KEY_EVENT_DEAL AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_KEY_EVENT_DEAL AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_APP_CHARGESTORE AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_APP_CHARGESTORE AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_APP_CHARGESTORE AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_APP_CHARGESTORE AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_APP_CHARGESTORE AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_APP_UMIDIGI_CHARGESTORE AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_APP_UMIDIGI_CHARGESTORE AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_APP_UMIDIGI_CHARGESTORE AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_APP_UMIDIGI_CHARGESTORE AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_APP_UMIDIGI_CHARGESTORE AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_APP_CFG_TOOL AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_APP_CFG_TOOL AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_APP_CFG_TOOL AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_APP_CFG_TOOL AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_APP_CFG_TOOL AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_APP_TESTBOX AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_APP_TESTBOX AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_APP_TESTBOX AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_APP_TESTBOX AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_APP_TESTBOX AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_APP_IDLE AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_APP_IDLE AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_APP_IDLE AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_APP_IDLE AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_APP_IDLE AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_APP_POWER AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_APP_POWER AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_APP_POWER AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_APP_POWER AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_APP_POWER AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_APP AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_APP AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_APP AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_APP AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_APP AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_USER_CFG AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_USER_CFG AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_USER_CFG AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_USER_CFG AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_USER_CFG AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_APP_TONE AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_APP_TONE AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_APP_TONE AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_APP_TONE AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_APP_TONE AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_BT_TWS AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_BT_TWS AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_BT_TWS AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_BT_TWS AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_BT_TWS AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_AEC_USER AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_AEC_USER AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_AEC_USER AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_AEC_USER AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_AEC_USER AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_BT_BLE AT(.LOG_TAG_CONST) = 0;
+const char log_tag_const_i_BT_BLE AT(.LOG_TAG_CONST) = 0;
+const char log_tag_const_d_BT_BLE AT(.LOG_TAG_CONST) = 1;
+const char log_tag_const_w_BT_BLE AT(.LOG_TAG_CONST) = 1;
+const char log_tag_const_e_BT_BLE AT(.LOG_TAG_CONST) = 1;
+
+const char log_tag_const_v_EARTCH_EVENT_DEAL AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_EARTCH_EVENT_DEAL AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_EARTCH_EVENT_DEAL AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_EARTCH_EVENT_DEAL AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_EARTCH_EVENT_DEAL AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_ONLINE_DB AT(.LOG_TAG_CONST) = 0;
+const char log_tag_const_i_ONLINE_DB AT(.LOG_TAG_CONST) = 0;
+const char log_tag_const_d_ONLINE_DB AT(.LOG_TAG_CONST) = 0;
+const char log_tag_const_w_ONLINE_DB AT(.LOG_TAG_CONST) = 0;
+const char log_tag_const_e_ONLINE_DB AT(.LOG_TAG_CONST) = 1;
+
+const char log_tag_const_v_MUSIC AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_MUSIC AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_w_MUSIC AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_d_MUSIC AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_MUSIC AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_APP_MUSIC AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_APP_MUSIC AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_APP_MUSIC AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_APP_MUSIC AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_APP_MUSIC AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_PC AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_PC AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_w_PC AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_d_PC AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_PC AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_AUX AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_AUX AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_AUX AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_w_AUX AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_AUX AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_WIRELESSMIC AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_WIRELESSMIC AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_w_WIRELESSMIC AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_d_WIRELESSMIC AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_WIRELESSMIC AT(.LOG_TAG_CONST) = TRUE;
+
+const char log_tag_const_v_KWS_VOICE_EVENT AT(.LOG_TAG_CONST) = FALSE;
+const char log_tag_const_i_KWS_VOICE_EVENT AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_d_KWS_VOICE_EVENT AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_w_KWS_VOICE_EVENT AT(.LOG_TAG_CONST) = TRUE;
+const char log_tag_const_e_KWS_VOICE_EVENT AT(.LOG_TAG_CONST) = TRUE;
diff --git a/apps/earphone/log_config/lib_btctrler_config.c b/apps/earphone/log_config/lib_btctrler_config.c
new file mode 100644
index 0000000..0724916
--- /dev/null
+++ b/apps/earphone/log_config/lib_btctrler_config.c
@@ -0,0 +1,540 @@
+/*********************************************************************************************
+ * Filename : btctrler_config.c
+
+ * Description : Optimized Code & RAM (编译优化配置)
+
+ * Author : Bingquan
+
+ * Email : caibingquan@zh-jieli.com
+
+ * Last modifiled : 2019-03-16 11:49
+
+ * Copyright:(c)JIELI 2011-2019 @ , All Rights Reserved.
+*********************************************************************************************/
+#include "app_config.h"
+#include "system/includes.h"
+#include "btcontroller_config.h"
+#include "bt_common.h"
+
+/**
+ * @brief Bluetooth Module
+ */
+
+//固定使用正常发射功率的等级:0-使用不同模式的各自等级;1~10-固定发射功率等级
+const int config_force_bt_pwr_tab_using_normal_level = 0;
+const int CONFIG_BLE_SYNC_WORD_BIT = 30;
+const int CONFIG_LNA_CHECK_VAL = -80;
+
+#if TCFG_USER_TWS_ENABLE
+
+#if (BT_FOR_APP_EN || TCFG_USER_BLE_ENABLE)
+const int config_btctler_modules = /*BT_MODULE_CLASSIC |*/ BT_MODULE_LE;
+#else
+#ifdef CONFIG_NEW_BREDR_ENABLE
+#if (BT_FOR_APP_EN)
+const int config_btctler_modules = (/*BT_MODULE_CLASSIC |*/ BT_MODULE_LE);
+#else
+const int config_btctler_modules = (BT_MODULE_CLASSIC);
+#endif
+#else
+const int config_btctler_modules = (/*BT_MODULE_CLASSIC |*/ BT_MODULE_LE);
+#endif
+#endif
+
+
+#ifdef CONFIG_NEW_BREDR_ENABLE
+const int config_btctler_le_tws = 0;
+const int CONFIG_BTCTLER_FAST_CONNECT_ENABLE = 0;
+#if TCFG_DEC2TWS_ENABLE
+const int CONFIG_TWS_WORK_MODE = 1;
+#else
+const int CONFIG_TWS_WORK_MODE = 2;
+#endif
+
+#ifdef CONFIG_SUPPORT_EX_TWS_ADJUST
+const int CONFIG_EX_TWS_ADJUST = 1;
+#else
+const int CONFIG_EX_TWS_ADJUST = 0;
+#endif
+const int CONFIG_EXTWS_NACK_LIMIT_INT_CNT = 4;
+
+const int CONFIG_TWS_RUN_SLOT = 200;
+const int CONFIG_PHONE_RUN_SLOT = 160;
+const int CONFIG_TWS_LOW_LATENCY_RUN_SLOT = 8;
+const int CONFIG_PHONE_LOW_LATENCY_RUN_SLOT = 120;
+const int CONFIG_TWS_FORWARD_TIMEOUT = 64;
+#else
+const int config_btctler_le_tws = 1;
+const int CONFIG_BTCTLER_FAST_CONNECT_ENABLE = 0;
+#endif
+
+const int CONFIG_BTCTLER_TWS_ENABLE = 1;
+
+
+#ifdef CONFIG_256K_FLASH
+const int CONFIG_TWS_POWER_BALANCE_ENABLE = 0;
+const int CONFIG_LOW_LATENCY_ENABLE = 0;
+const int CONFIG_TWS_AFH_ENABLE = 0;
+#else
+const int CONFIG_TWS_POWER_BALANCE_ENABLE = 1;
+const int CONFIG_LOW_LATENCY_ENABLE = 1;
+const int CONFIG_TWS_AFH_ENABLE = 1;
+#endif
+const int CONFIG_MASTER_MAX_RX_BULK_PERSENT = 70;
+
+#else //TCFG_USER_TWS_ENABLE
+
+/* #if (TCFG_USER_BLE_ENABLE || GMA_EN) */
+#if (TCFG_USER_BLE_ENABLE)
+const int config_btctler_modules = /*BT_MODULE_CLASSIC |*/ BT_MODULE_LE;
+#else
+const int config_btctler_modules = BT_MODULE_CLASSIC;
+#endif
+const int config_btctler_le_tws = 0;
+const int CONFIG_BTCTLER_TWS_ENABLE = 0;
+const int CONFIG_TWS_AFH_ENABLE = 0;
+const int CONFIG_LOW_LATENCY_ENABLE = 0;
+const int CONFIG_MASTER_MAX_RX_BULK_PERSENT = 0;
+const int CONFIG_TWS_POWER_BALANCE_ENABLE = 0;
+const int CONFIG_BTCTLER_FAST_CONNECT_ENABLE = 0;
+
+#endif
+
+const int CONFIG_A2DP_MAX_BUF_SIZE = 2 * 1024;//20 * 1024;
+const int CONFIG_BT_TX_BUFF_MAX_SIZE = 1 * 1024;//10 * 1024;
+const int CONFIG_TWS_SUPER_TIMEOUT = 2000;
+const int CONFIG_BTCTLER_QOS_ENABLE = 1;
+const int CONFIG_A2DP_DATA_CACHE_LOW_AAC = 100;
+const int CONFIG_A2DP_DATA_CACHE_HI_AAC = 250;
+const int CONFIG_A2DP_DATA_CACHE_LOW_SBC = 150;
+const int CONFIG_A2DP_DATA_CACHE_HI_SBC = 260;
+#if TCFG_EQ_ONLINE_ENABLE
+const int CONFIG_A2DP_DELAY_TIME = 200;//调音时,减少延时,避免影响频响测试
+#else
+const int CONFIG_A2DP_DELAY_TIME = 340;
+#endif
+const int CONFIG_A2DP_DELAY_TIME_LO = 100;
+#ifdef CONFIG_A2DP_GAME_MODE_DELAY_TIME
+const int CONFIG_A2DP_SBC_DELAY_TIME_LO = CONFIG_A2DP_GAME_MODE_DELAY_TIME + 12;
+#else
+const int CONFIG_A2DP_SBC_DELAY_TIME_LO = 75;
+#endif
+
+const int CONFIG_PAGE_POWER = 4;
+const int CONFIG_PAGE_SCAN_POWER = 7;
+const int CONFIG_INQUIRY_POWER = 7;
+const int CONFIG_INQUIRY_SCAN_POWER = 7;
+const int CONFIG_DUT_POWER = 10;
+
+#if (CONFIG_BT_MODE != BT_NORMAL)
+const int config_btctler_hci_standard = 1;
+#else
+const int config_btctler_hci_standard = 0;
+#endif
+
+const int config_btctler_mode = CONFIG_BT_MODE;
+/*-----------------------------------------------------------*/
+
+/**
+ * @brief Bluetooth Classic setting
+ */
+const u8 rx_fre_offset_adjust_enable = 1;
+
+const int config_bredr_fcc_fix_fre = 0;
+const int ble_disable_wait_enable = 1;
+
+const int config_btctler_eir_version_info_len = 21;
+
+#ifdef CONFIG_256K_FLASH
+const int CONFIG_TEST_DUT_CODE = 1;
+const int CONFIG_TEST_FCC_CODE = 0;
+const int CONFIG_TEST_DUT_ONLY_BOX_CODE = 1;
+#else
+const int CONFIG_TEST_DUT_CODE = 1;
+const int CONFIG_TEST_FCC_CODE = 1;
+const int CONFIG_TEST_DUT_ONLY_BOX_CODE = 0;
+#endif
+
+const int CONFIG_ESCO_MUX_RX_BULK_ENABLE = 0;
+
+#if TCFG_USER_EMITTER_ENABLE
+const int CONFIG_BREDR_INQUIRY = 1;
+const int CONFIG_LMP_MASTER_ESCO_ENABLE = 1;
+#else
+const int CONFIG_BREDR_INQUIRY = 0;
+const int CONFIG_LMP_MASTER_ESCO_ENABLE = 0;
+#endif
+const int CONFIG_INQUIRY_PAGE_OFFSET_ADJUST = 0;
+
+const int CONFIG_LMP_NAME_REQ_ENABLE = 0;
+const int CONFIG_LMP_PASSKEY_ENABLE = 0;
+
+ // *INDENT-OFF*
+#ifdef CONFIG_SUPPORT_WIFI_DETECT
+ #if TCFG_USER_TWS_ENABLE
+ const int CONFIG_WIFI_DETECT_ENABLE = 1;
+ #else
+ const int CONFIG_WIFI_DETECT_ENABLE = 1;
+ #endif
+
+#else
+ const int CONFIG_WIFI_DETECT_ENABLE = 0;
+
+#endif
+
+const int ESCO_FORWARD_ENABLE = 0;
+// *INDENT-ON*
+
+
+const int config_bt_function = 0;
+
+///bredr 强制 做 maseter
+const int config_btctler_bredr_master = 0;
+const int config_btctler_dual_a2dp = 0;
+
+///afh maseter 使用app设置的map 通过USER_CTRL_AFH_CHANNEL 设置
+const int config_bredr_afh_user = 0;
+//bt PLL 温度跟随trim
+const int config_bt_temperature_pll_trim = 0;
+/*security check*/
+const int config_bt_security_vulnerability = 0;
+
+const int config_delete_link_key = 1; //配置是否连接失败返回PIN or Link Key Missing时删除linkKey
+/*-----------------------------------------------------------*/
+
+/**
+ * @brief Bluetooth LE setting
+ */
+
+#if (TCFG_USER_BLE_ENABLE)
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV)
+const int config_btctler_le_roles = (LE_ADV);
+const uint64_t config_btctler_le_features = 0;
+#elif (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_WIRELESS_MIC_CLIENT)
+const uint64_t config_btctler_le_features = LE_ENCRYPTION | LE_CODED_PHY | LE_DATA_PACKET_LENGTH_EXTENSION | LE_2M_PHY;
+const int config_btctler_le_roles = (LE_SCAN | LE_INIT | LE_MASTER);
+
+#elif (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_WIRELESS_MIC_SERVER)
+const int config_btctler_le_roles = (LE_ADV | LE_SLAVE);
+const uint64_t config_btctler_le_features = LE_ENCRYPTION | LE_CODED_PHY | LE_DATA_PACKET_LENGTH_EXTENSION | LE_2M_PHY;
+
+#elif (TCFG_BLE_DEMO_SELECT == DEF_LE_AUDIO_CENTRAL)
+const int config_btctler_le_roles = (LE_SCAN | LE_INIT | LE_MASTER);
+const uint64_t config_btctler_le_features = LE_ENCRYPTION | LE_CODED_PHY | LE_FEATURES_ISO | LE_2M_PHY;
+
+#elif (TCFG_BLE_DEMO_SELECT == DEF_LE_AUDIO_PERIPHERAL)
+const int config_btctler_le_roles = (LE_ADV | LE_SLAVE);
+const uint64_t config_btctler_le_features = LE_ENCRYPTION | LE_CODED_PHY | LE_FEATURES_ISO | LE_2M_PHY;
+
+#elif (BLE_HID_EN)
+const int config_btctler_le_roles = (LE_ADV | LE_SLAVE);
+const uint64_t config_btctler_le_features = LE_ENCRYPTION;
+
+#else
+const int config_btctler_le_roles = (LE_ADV | LE_SLAVE);
+const uint64_t config_btctler_le_features = LE_ENCRYPTION| LE_DATA_PACKET_LENGTH_EXTENSION | LE_2M_PHY;
+#endif
+#else
+const int config_btctler_le_roles = 0;
+const uint64_t config_btctler_le_features = 0;
+#endif
+
+
+// Master multi-link
+const int config_btctler_le_master_multilink = 0;
+// LE RAM Control
+
+#ifdef CONFIG_NEW_BREDR_ENABLE
+const int config_btctler_le_hw_nums = 1;
+#else
+const int config_btctler_le_hw_nums = 2;
+#endif
+
+
+const int config_btctler_le_slave_conn_update_winden = 2500;//range:100 to 2500
+
+// LE vendor baseband
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_WIRELESS_MIC_CLIENT)
+//const u32 config_vendor_le_bb = VENDOR_BB_MD_CLOSE |
+//VENDOR_BB_CONNECT_SLOT |
+//VENDOR_BB_EVT_HOLD |
+//VENDOR_BB_EVT_HOLD_TRIGG(25) |
+//VENDOR_BB_EVT_HOLD_TICK(0); //LE vendor baseband
+const u32 config_vendor_le_bb = VENDOR_BB_MD_CLOSE | VENDOR_BB_CONNECT_SLOT | VENDOR_BB_ADV_PDU_INT(3);//LE vendor baseband
+// Master AFH
+const int config_btctler_le_afh_en = 1;
+const int config_btctler_le_rx_nums = 8;
+const int config_btctler_le_acl_packet_length = 251;
+const int config_btctler_le_acl_total_nums = 1;
+
+#elif (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_WIRELESS_MIC_SERVER)
+const u32 config_vendor_le_bb = VENDOR_BB_MD_CLOSE | VENDOR_BB_CONNECT_SLOT | VENDOR_BB_ADV_PDU_INT(3);//LE vendor baseband
+// Master AFH
+const int config_btctler_le_afh_en = 1;
+const int config_btctler_le_rx_nums = 8;
+const int config_btctler_le_acl_packet_length = 251;
+const int config_btctler_le_acl_total_nums = 1;
+
+#else
+// Master AFH
+const int config_btctler_le_afh_en = 0;
+const u32 config_vendor_le_bb = 0;
+
+const int config_btctler_le_rx_nums = 8;
+const int config_btctler_le_acl_packet_length = 251;
+const int config_btctler_le_acl_total_nums = 8;
+
+#endif
+
+/*-----------------------------------------------------------*/
+/**
+ * @brief Bluetooth Analog setting
+ */
+/*-----------------------------------------------------------*/
+#if ((!TCFG_USER_BT_CLASSIC_ENABLE) && TCFG_USER_BLE_ENABLE)
+const int config_btctler_single_carrier_en = 1; ////单模ble才设置
+#else
+const int config_btctler_single_carrier_en = 0;
+#endif
+
+const int sniff_support_reset_anchor_point = 0; //sniff状态下是否支持reset到最近一次通信点,用于HID
+
+const int sniff_long_interval = (500 / 0.625); //sniff状态下进入long interval的通信间隔(ms)
+
+const int config_rf_oob = 0;
+
+/*-----------------------------------------------------------*/
+
+/**
+ * @brief Log (Verbose/Info/Debug/Warn/Error)
+ */
+/*-----------------------------------------------------------*/
+//RF part
+const char log_tag_const_v_Analog AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_Analog AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_Analog AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_Analog AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_e_Analog AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+
+const char log_tag_const_v_RF AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_RF AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_RF AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_RF AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_e_RF AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+
+//Classic part
+const char log_tag_const_v_HCI_LMP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_HCI_LMP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_d_HCI_LMP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_HCI_LMP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_HCI_LMP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LMP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LMP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_d_LMP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LMP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LMP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+//LE part
+const char log_tag_const_v_LE_BB AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LE_BB AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LE_BB AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_LE_BB AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_e_LE_BB AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LE5_BB AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LE5_BB AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LE5_BB AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LE5_BB AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LE5_BB AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_HCI_LL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_HCI_LL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_HCI_LL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_HCI_LL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_e_HCI_LL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_LL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_e_LL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_E AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_E AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LL_E AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_E AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_E AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_M AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_M AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LL_M AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_M AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_M AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_ADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_ADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LL_ADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_ADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_ADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_SCAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_SCAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LL_SCAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_SCAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_SCAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_INIT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_INIT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LL_INIT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_INIT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_INIT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_EXT_ADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_EXT_ADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LL_EXT_ADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_EXT_ADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_EXT_ADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_EXT_SCAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_EXT_SCAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LL_EXT_SCAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_EXT_SCAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_EXT_SCAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_EXT_INIT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_EXT_INIT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LL_EXT_INIT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_EXT_INIT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_EXT_INIT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_TWS_ADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_TWS_ADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LL_TWS_ADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_TWS_ADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_TWS_ADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_TWS_SCAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_TWS_SCAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LL_TWS_SCAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_TWS_SCAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_TWS_SCAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_S AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_S AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_d_LL_S AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_S AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_S AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_RL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_RL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_d_LL_RL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_RL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_RL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_WL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_WL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_d_LL_WL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_WL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_WL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_AES AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_AES AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_AES AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_AES AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_AES AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_PADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_PADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LL_PADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_PADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_PADV AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_DX AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_DX AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LL_DX AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_DX AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_DX AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_PHY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_PHY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LL_PHY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_PHY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_PHY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_AFH AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_AFH AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_d_LL_AFH AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_LL_AFH AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_AFH AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+//HCI part
+const char log_tag_const_v_Thread AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_Thread AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_Thread AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_Thread AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_Thread AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_HCI_STD AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_HCI_STD AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_HCI_STD AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_HCI_STD AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_HCI_STD AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_HCI_LL5 AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_HCI_LL5 AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_HCI_LL5 AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_HCI_LL5 AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_HCI_LL5 AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_ISO AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_i_LL_ISO AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_d_LL_ISO AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_ISO AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_ISO AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_BIS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_BIS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LL_BIS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_BIS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_BIS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_LL_CIS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_LL_CIS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_LL_CIS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_LL_CIS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_LL_CIS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_BL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_BL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_BL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_BL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_BL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_c_BL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+
+const char log_tag_const_v_TWS_LE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_i_TWS_LE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_TWS_LE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_TWS_LE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_e_TWS_LE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_c_TWS_LE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+
+const char log_tag_const_v_TWS_LMP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_i_TWS_LMP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_d_TWS_LMP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_TWS_LMP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_e_TWS_LMP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+
+const char log_tag_const_v_TWS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_TWS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_d_TWS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_TWS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_e_TWS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+
+const char log_tag_const_v_TWS_ESCO AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_i_TWS_ESCO AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_d_TWS_ESCO AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_TWS_ESCO AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_e_TWS_ESCO AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
diff --git a/apps/earphone/log_config/lib_btstack_config.c b/apps/earphone/log_config/lib_btstack_config.c
new file mode 100644
index 0000000..d7fdb0f
--- /dev/null
+++ b/apps/earphone/log_config/lib_btstack_config.c
@@ -0,0 +1,85 @@
+/*********************************************************************************************
+ * Filename : btstack_config.c
+
+ * Description : Optimized Code & RAM (编译优化配置)
+
+ * Author : Bingquan
+
+ * Email : caibingquan@zh-jieli.com
+
+ * Last modifiled : 2019-03-16 11:49
+
+ * Copyright:(c)JIELI 2011-2019 @ , All Rights Reserved.
+*********************************************************************************************/
+#include "app_config.h"
+#include "system/includes.h"
+#include "btcontroller_config.h"
+#include "bt_common.h"
+
+/**
+ * @brief Bluetooth Stack Module
+ */
+
+#ifdef CONFIG_SOUNDBOX_FLASH_256K
+const int CONFIG_BTSTACK_BIG_FLASH_ENABLE = 0;
+#else
+const int CONFIG_BTSTACK_BIG_FLASH_ENABLE = 1;
+#endif
+
+
+#if TCFG_BT_SUPPORT_AAC
+const int CONFIG_BTSTACK_SUPPORT_AAC = 1;
+#else
+const int CONFIG_BTSTACK_SUPPORT_AAC = 0;
+#endif
+
+#if TCFG_BT_SUPPORT_LDAC
+const int CONFIG_BTSTACK_SUPPORT_LDAC = 1;
+#else
+const int CONFIG_BTSTACK_SUPPORT_LDAC = 0;
+#endif
+//协议栈接收到命令是否自动退出sniff
+const int config_btstask_auto_exit_sniff = 1;
+
+
+
+#if SMART_BOX_EN
+const int config_rcsp_stack_enable = 1;
+#else
+const int config_rcsp_stack_enable = 0;
+#endif
+
+#if (TCFG_USER_BLE_ENABLE)
+//le 配置,可以优化代码和RAM
+#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_WIRELESS_MIC_CLIENT)
+const int config_le_hci_connection_num = 1;//支持同时连接个数
+const int config_le_sm_support_enable = 0; //是否支持加密配对
+const int config_le_gatt_client_num = 1; //支持client角色个数
+const int config_le_gatt_server_num = 0; //支持server角色个数
+
+#elif (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_WIRELESS_MIC_SERVER)
+const int config_le_hci_connection_num = 1;//支持同时连接个数
+const int config_le_sm_support_enable = 0; //是否支持加密配对
+const int config_le_gatt_client_num = 0; //支持client角色个数
+const int config_le_gatt_server_num = 1; //支持server角色个数
+
+#elif (BLE_HID_EN)
+const int config_le_hci_connection_num = 1;//支持同时连接个数
+const int config_le_sm_support_enable = 1; //是否支持加密配对
+const int config_le_gatt_server_num = 1; //支持server角色个数
+const int config_le_gatt_client_num = 0; //支持client角色个数
+
+#else
+const int config_le_hci_connection_num = 1;//支持同时连接个数
+const int config_le_sm_support_enable = 1; //是否支持加密配对
+const int config_le_gatt_server_num = 1; //支持server角色个数
+const int config_le_gatt_client_num = 0; //支持client角色个数
+#endif
+
+#else
+//no ble
+const int config_le_hci_connection_num = 0;//支持同时连接个数
+const int config_le_sm_support_enable = 0; //是否支持加密配对
+const int config_le_gatt_server_num = 0; //支持server角色个数
+const int config_le_gatt_client_num = 0; //支持client角色个数
+#endif
diff --git a/apps/earphone/log_config/lib_driver_config.c b/apps/earphone/log_config/lib_driver_config.c
new file mode 100644
index 0000000..5ce350e
--- /dev/null
+++ b/apps/earphone/log_config/lib_driver_config.c
@@ -0,0 +1,231 @@
+/*********************************************************************************************
+ * Filename : lib_driver_config.c
+
+ * Description : Optimized Code & RAM (编译优化配置)
+
+ * Author : Bingquan
+
+ * Email : caibingquan@zh-jieli.com
+
+ * Last modifiled : 2019-03-18 14:58
+
+ * Copyright:(c)JIELI 2011-2019 @ , All Rights Reserved.
+*********************************************************************************************/
+#include "app_config.h"
+#include "system/includes.h"
+
+#if TCFG_SD0_SD1_USE_THE_SAME_HW
+const int sd0_sd1_use_the_same_hw = 1;
+#else
+const int sd0_sd1_use_the_same_hw = 0;
+#endif
+#ifdef CONFIG_MOVABLE_ENABLE
+const int config_spi_code_user_cache = 1;
+#else
+const int config_spi_code_user_cache = 0;
+#endif
+
+#if TCFG_KEEP_CARD_AT_ACTIVE_STATUS
+const int keep_card_at_active_status = 1;
+#else
+const int keep_card_at_active_status = 0;
+#endif
+
+#if TCFG_SDX_CAN_OPERATE_MMC_CARD
+const int sdx_can_operate_mmc_card = TCFG_SDX_CAN_OPERATE_MMC_CARD;
+#else
+const int sdx_can_operate_mmc_card = 0;
+#endif
+
+#if TCFG_POWER_MODE_QUIET_ENABLE
+const int config_dcdc_mode = 1;
+#else
+const int config_dcdc_mode = 0;
+#endif
+
+#if(TCFG_CLOCK_SYS_SRC == SYS_CLOCK_INPUT_PLL_RCL) //系统时钟源选择
+const int clock_sys_src_use_lrc_hw = 1; //当使用lrc时timer.c需要特殊设置
+#else
+const int clock_sys_src_use_lrc_hw = 0;
+#endif
+
+#ifdef TCFG_VAD_LOWPOWER_CLOCK
+const char config_vad_lowpower_clock = TCFG_VAD_LOWPOWER_CLOCK;
+#else
+const char config_vad_lowpower_clock = 0;
+#endif
+
+#if defined(CONFIG_CPU_BR28) || ((TCFG_OTG_MODE & OTG_DET_DM_ONLY) != 0)
+const int config_otg_slave_detect_method_2 = 1;
+#else
+const int config_otg_slave_detect_method_2 = 0;
+#endif
+/**
+ * @brief Log (Verbose/Info/Debug/Warn/Error)
+ */
+/*-----------------------------------------------------------*/
+const char log_tag_const_v_CLOCK AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE) ;
+const char log_tag_const_i_CLOCK AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE) ;
+const char log_tag_const_d_CLOCK AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_w_CLOCK AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_CLOCK AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_LP_TIMER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_LP_TIMER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_LP_TIMER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_LP_TIMER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_LP_TIMER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_LRC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_LRC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_LRC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_LRC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_LRC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_RCH AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_RCH AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_RCH AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_RCH AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_RCH AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_P33_MISC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_P33_MISC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_P33_MISC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_P33_MISC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_P33_MISC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_P33 AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_P33 AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_d_P33 AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_P33 AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_P33 AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_PMU AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_PMU AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_PMU AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_PMU AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_PMU AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_RTC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_RTC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_d_RTC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_RTC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_RTC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_WKUP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_WKUP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_WKUP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_WKUP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_WKUP AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_SDFILE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_SDFILE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_SDFILE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_SDFILE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_SDFILE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_CHARGE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_CHARGE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_CHARGE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_CHARGE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_CHARGE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_DEBUG AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_DEBUG AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_DEBUG AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_DEBUG AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_DEBUG AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_PWM_LED AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_PWM_LED AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_PWM_LED AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_PWM_LED AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_PWM_LED AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_KEY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_KEY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_KEY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_KEY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_KEY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_TMR AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_TMR AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_TMR AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_TMR AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_TMR AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_VM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_VM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_d_VM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_VM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_VM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_TRIM_VDD AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE) ;
+const char log_tag_const_i_TRIM_VDD AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_d_TRIM_VDD AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_w_TRIM_VDD AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_TRIM_VDD AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+//audio dac
+const char log_tag_const_v_SYS_DAC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_SYS_DAC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_SYS_DAC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_SYS_DAC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_e_SYS_DAC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+
+
+const char log_tag_const_v_APP_EDET AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_APP_EDET AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_APP_EDET AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_APP_EDET AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_e_APP_EDET AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+
+
+const char log_tag_const_v_FM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_FM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_FM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_FM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_e_FM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+
+const char log_tag_const_v_CORE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_CORE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_d_CORE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_CORE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_e_CORE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+
+const char log_tag_const_v_CACHE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_CACHE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(1);
+const char log_tag_const_d_CACHE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_CACHE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_e_CACHE AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+
+const char log_tag_const_v_LP_KEY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_LP_KEY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_d_LP_KEY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_w_LP_KEY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_LP_KEY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_SD AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_SD AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_d_SD AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_SD AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_e_SD AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_EAR_DETECT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_EAR_DETECT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_d_EAR_DETECT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_EAR_DETECT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_e_EAR_DETECT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+
+const char log_tag_const_v_TDM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_TDM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_d_TDM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_w_TDM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_TDM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_USB AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_USB AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_USB AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_w_USB AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_USB AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
diff --git a/apps/earphone/log_config/lib_media_config.c b/apps/earphone/log_config/lib_media_config.c
new file mode 100644
index 0000000..f465b3a
--- /dev/null
+++ b/apps/earphone/log_config/lib_media_config.c
@@ -0,0 +1,544 @@
+/*********************************************************************************************
+ * Filename : lib_driver_config.c
+
+ * Description : Optimized Code & RAM (编译优化配置)
+
+ * Author : Bingquan
+
+ * Email : caibingquan@zh-jieli.com
+
+ * Last modifiled : 2019-03-18 14:58
+
+ * Copyright:(c)JIELI 2011-2019 @ , All Rights Reserved.
+*********************************************************************************************/
+#include "app_config.h"
+#include "system/includes.h"
+#include "media/includes.h"
+#include "audio_adc.h"
+#include "audio_config.h"
+#include "media/hw_fft.h"
+#if TCFG_AUDIO_ANC_ENABLE
+#include "audio_anc.h"
+#endif
+
+#if (TCFG_AUDIO_DECODER_OCCUPY_TRACE)
+const u8 audio_decoder_occupy_trace_enable = 1;
+const u8 audio_decoder_occupy_trace_dump = 0;
+#else
+const u8 audio_decoder_occupy_trace_enable = 0;
+const u8 audio_decoder_occupy_trace_dump = 0;
+#endif/*TCFG_AUDIO_DECODER_OCCUPY_TRACE*/
+
+
+const int JL_HW_FFT_V = FFT_EXT ; //FFT硬件版本
+
+/* #if (TCFG_APP_MUSIC_EN && !TCFG_DEC2TWS_ENABLE) */
+
+const int WMA_TWSDEC_EN = 0; // wma tws 解码控制
+
+// 解码一次输出点数,1代表32对点,n就是n*32对点
+// 超过1时,解码需要使用malloc,如config_mp3_dec_use_malloc=1
+const int MP3_OUTPUT_LEN = 1;
+const int WMA_OUTPUT_LEN = 1;
+
+
+#define FAST_FREQ_restrict 0x01 //限制超过16k的频率不解【一般超出人耳听力范围,但是仪器会测出来】
+#define FAST_FILTER_restrict 0x02 //限制滤波器长度【子带滤波器旁瓣加大,边缘不够陡】
+#define FAST_CHANNEL_restrict 0x04 //混合左右声道,再解码【如果是左右声道独立性较强的歌曲,会牺牲空间感,特别耳机听会听出来的话】
+const int config_mp3_dec_speed_mode = 0;//FAST_FREQ_restrict | FAST_FILTER_restrict | FAST_CHANNEL_restrict; //3个开关都置上,是最快的解码模式
+/* #endif // (TCFG_APP_MUSIC_EN && !TCFG_DEC2TWS_ENABLE) */
+
+
+const int WAV_MAX_BITRATEV = (48 * 2 * 32); // wav最大支持比特率,单位kbps
+
+
+// 解码一次输出点数,建议范围32到900,例如128代表128对点
+// 超过128时,解码需要使用malloc,如config_wav_dec_use_malloc=1
+const int WAV_DECODER_PCM_POINTS = 128;
+
+// output超过128时,如果不使用malloc,需要增大对应buf
+// 可以看打印中解码器需要的大小,一般输出每增加1长度增加4个字节
+int wav_mem_ext[(1336 + 3) / 4] SEC(.wav_mem); //超过128要增加这个数组的大小
+
+const int OPUS_SRINDEX = 0; //选择opus解码文件的帧大小,0代表一帧40字节,1代表一帧80字节,2代表一帧160字节
+
+const int WTGV2_STACK2BUF = 0; //等于1时解码buf会加大760,栈会减小
+
+const int const_sel_adpcm_type = 0;//1:使用imaen_adpcm, 0:msen_adpcm
+
+#ifdef CONFIG_MIDI_DEC_ADDR
+const int MIDI_TONE_MODE = 0;//0是地址访问(仅支持在内置flash,读数快,消耗mips低),1 是文件访问(内置、外挂flash,sd,u盘均可,读数慢,消耗mips较大)
+#else
+const int MIDI_TONE_MODE = 1;
+#endif
+const int MAINTRACK_USE_CHN = 0; //MAINTRACK_USE_CHN控制主通道区分方式; 0用track号区分主通道 1用chn号区分主通道
+const int MAX_PLAYER_CNT = 18; //控制可配置的最大同时发声的key数的BUF[1,32]
+
+#if CONFIG_MEDIA_LIB_USE_MALLOC
+const int config_mp3_dec_use_malloc = 1;
+const int config_mp3pick_dec_use_malloc = 1;
+const int config_wma_dec_use_malloc = 1;
+const int config_wmapick_dec_use_malloc = 1;
+const int config_m4a_dec_use_malloc = 1;
+const int config_m4apick_dec_use_malloc = 1;
+const int config_wav_dec_use_malloc = 1;
+const int config_alac_dec_use_malloc = 1;
+const int config_dts_dec_use_malloc = 1;
+const int config_amr_dec_use_malloc = 1;
+const int config_flac_dec_use_malloc = 1;
+const int config_ape_dec_use_malloc = 1;
+const int config_aac_dec_use_malloc = 1;
+const int config_ldac_dec_use_malloc = 1;
+const int config_aptx_dec_use_malloc = 1;
+const int config_midi_dec_use_malloc = 1;
+const int config_lc3_dec_use_malloc = 1;
+const int config_speex_dec_use_malloc = 1;
+const int config_opus_dec_use_malloc = 1;
+#else
+const int config_mp3_dec_use_malloc = 0;
+const int config_mp3pick_dec_use_malloc = 0;
+const int config_wma_dec_use_malloc = 0;
+const int config_wmapick_dec_use_malloc = 0;
+const int config_m4a_dec_use_malloc = 0;
+const int config_m4apick_dec_use_malloc = 0;
+const int config_wav_dec_use_malloc = 0;
+const int config_alac_dec_use_malloc = 0;
+const int config_dts_dec_use_malloc = 0;
+const int config_amr_dec_use_malloc = 0;
+const int config_flac_dec_use_malloc = 0;
+const int config_ape_dec_use_malloc = 0;
+const int config_aac_dec_use_malloc = 0;
+const int config_ldac_dec_use_malloc = 0;
+const int config_aptx_dec_use_malloc = 0;
+const int config_midi_dec_use_malloc = 0;
+const int config_lc3_dec_use_malloc = 0;
+const int config_speex_dec_use_malloc = 0;
+const int config_opus_dec_use_malloc = 0;
+
+#endif
+
+const int LC3_SUPPORT_CH = 2; //lc3解码输入通道数 1:单声道输入, 2:双声道输入(br30可支持2)
+const int LC3_DMS_VAL = 25; //单位ms, 【只支持 25,50,100】
+const int LC3_DMS_FSINDEX = 4; //配置采样率【只支持0到4】,影响用哪组表以及一次的处理长度(<=8k的时候,配0. <=16k的时候,配1.<=24k的时候,配2.<=32k的时候,配3.<=48k的时候,配4)
+const int LC3_QUALTIY_CONFIG = 4;//【范围1到4, 1需要的速度最少,这个默认先配4】
+
+//wts解码支持采样率可选择,可以同时打开也可以单独打开
+const int silk_fsN_enable = 1; //支持8-12k采样率
+const int silk_fsW_enable = 1; //支持16-24k采样率
+
+/*省电容mic使能配置*/
+#if TCFG_SUPPORT_MIC_CAPLESS
+const u8 const_mic_capless_en = 1;
+#else
+const u8 const_mic_capless_en = 0;
+#endif/*TCFG_SUPPORT_MIC_CAPLESS*/
+
+// 快进快退到文件end返回结束消息
+const int config_decoder_ff_fr_end_return_event_end = 0;
+
+
+const int config_audio_eq_en = 0
+#if TCFG_EQ_ENABLE
+ | EQ_EN //eq使能
+#if TCFG_EQ_ONLINE_ENABLE
+ | EQ_ONLINE_EN //在线调试使能
+#endif/*TCFG_AUDIO_OUT_EQ_ENABLE*/
+#if TCFG_USE_EQ_FILE
+ | EQ_FILE_EN //使用eq_cfg_hw.bin文件效果
+
+#if TCFG_EQ_FILE_SWITCH_EN
+ | EQ_FILE_SWITCH_EN //使能eq_cfg_hw.bin多文件切换,对应旧版config_audio_eq_file_sw_en
+#endif
+#endif/*TCFG_USE_EQ_FILE*/
+#if TCFG_AUDIO_OUT_EQ_ENABLE
+ | EQ_HIGH_BASS_EN //高低音接口使能
+ | EQ_HIGH_BASS_FADE_EN //高低音接口数据更新使用淡入淡出,配合config_audio_eq_fade_step步进使用
+#endif/*TCFG_AUDIO_OUT_EQ_ENABLE*/
+#if (RCSP_ADV_EN)&&(JL_EARPHONE_APP_EN)&&(TCFG_DRC_ENABLE == 0)
+ /* |EQ_FILTER_COEFF_LIMITER_ZERO_EN */
+#endif
+#ifndef CONFIG_SOUNDBOX_FLASH_256K
+ | EQ_HW_UPDATE_COEFF_ONLY_EN
+ | EQ_HW_LR_ALONE
+#endif/* CONFIG_SOUNDBOX_FLASH_256K */
+#if defined(EQ_CORE_V1) && TCFG_DRC_ENABLE
+ | EQ_SUPPORT_MULIT_CHANNEL_EN //eq是否支持多声道(3~8) 打开:支持 否则:仅支持1~2声道*/
+ | EQ_HW_CROSSOVER_TYPE0_EN //硬件分频器用序列进序列出
+ //|EQ_HW_CROSSOVER_TYPE1_EN //硬件分频器使用块出方式,会增加mem(该方式仅支持单声道处理)
+#endif/*(EQ_CORE_V1) && TCFG_DRC_ENABLE*/
+#if defined(TCFG_EQ_DIVIDE_ENABLE) && TCFG_EQ_DIVIDE_ENABLE
+ | EQ_LR_DIVIDE_EN
+#endif/*TCFG_EQ_DIVIDE_ENABLE*/
+
+#if defined(EQ_LITE_CODE) && EQ_LITE_CODE
+ | EQ_LITE_VER_EN //不支持异步,不支持默认效果切换接口,仅支持文件解析
+#if TCFG_DRC_ENABLE
+ | EQ_SUPPORT_32BIT_SYNC_EN //32bit同步方式eq使能,eq_lite_en后,该宏需使能
+#endif/*TCFG_DRC_ENABLE*/
+#endif/* EQ_LITE_CODE */
+ | EQ_FILTER_COEFF_FADE_EN//默认系数切换更新时使用淡入淡出
+
+#if defined(EQ_CORE_V1)
+ | EQ_SUPPORT_OLD_VER_EN //AC700N,或上BIT(1)支持版本0.7.1.0,0.7.1.1
+#endif/*EQ_CORE_V1*/
+#endif/* TCFG_EQ_ENABLE */
+ | 0; //end
+
+const float config_audio_eq_fade_step = 0.1f;//播歌高低音增益调节步进
+
+
+const int const_eq_debug = 0;
+const int AUDIO_EQ_CLEAR_MEM_BY_MUTE_TIME_MS = 0;//300 //连续多长时间静音就清除EQ MEM
+const int AUDIO_EQ_CLEAR_MEM_BY_MUTE_LIMIT = 0; //静音判断阀值
+
+const int config_audio_drc_en = 0
+#if TCFG_DRC_ENABLE
+ | DRC_EN //drc使能
+#if ((defined(TCFG_AUDIO_HEARING_AID_ENABLE) && TCFG_AUDIO_HEARING_AID_ENABLE) || TCFG_CVP_UL_DRC_ENABLE || (defined(TCFG_AUDIO_BASS_BOOST)&&TCFG_AUDIO_BASS_BOOST) || defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE)
+ | WDRC_TYPE_EN
+#endif
+ /* |DRC_COMPRESSOF_DIS //关闭压缩器 */
+ /* |DRC_NBAND_DIS //关闭多带压缩器,关闭多带限幅器 */
+#endif /*TCFG_DRC_ENABLE*/
+ | 0; //end
+
+#ifdef CONFIG_ANC_30C_ENABLE
+const char config_audio_30c_en = 1;
+#else
+const char config_audio_30c_en = 0;
+#endif
+
+#if AUDIO_SURROUND_CONFIG
+const int const_surround_en = BIT(2) | 1;//或上BIT(2)使能新的环绕音效
+#else
+const int const_surround_en = 0;
+#endif
+
+#if AUDIO_VBASS_CONFIG
+const int const_vbass_en = 1;
+#else
+const int const_vbass_en = 0;
+#endif
+
+const int A2DP_AUDIO_PLC_ENABLE = 0;
+const int LPC_JUST_FADE = 0; //播歌PLC仅淡入淡出配置, 0 - 补包运算(Ram 3660bytes, Code 1268bytes),1 - 仅淡出淡入(Ram 688bytes, Code 500bytes)
+const char config_audio_mixer_ch_highlight_enable = 0; //混音器声音突出功能使能
+
+#ifdef SBC_CUSTOM_DECODER_BUF_SIZE
+const short config_sbc_decoder_buf_size = 512;
+#endif
+// tws音频解码自动设置输出声道。
+// 单声道:AUDIO_CH_L/AUDIO_CH_R。双声道:AUDIO_CH_DUAL_L/AUDIO_CH_DUAL_R
+// 关闭后,按照output_ch_num和output_ch_type/ch_type设置输出声道
+const int audio_tws_auto_channel = 1;
+
+const int MP3_SEARCH_MAX = 200; //本地解码设成200, 网络解码可以设成3
+const int MP3_TGF_TWS_EN = 1; //tws解码使能
+const int MP3_TGF_POSPLAY_EN = 1; //定点播放 获取ms级别时间 接口使能
+const int MP3_TGF_AB_EN = 1; //AB点复读使能
+const int MP3_TGF_FASTMO = 0; //快速解码使能【默认关闭,之前给一个sdk单独加的,配置是否解高频,解双声道等】
+
+#if (TCFG_MIC_EFFECT_ENABLE || TCFG_AUDIO_DAC_MIX_ENABLE)
+const int config_audio_dac_mix_enable = 1;
+#else
+const int config_audio_dac_mix_enable = 0;
+#endif
+
+#if TCFG_AUDIO_DAC_MIX_ENABLE
+const int config_audio_dac_noisefloor_optimize_enable = 0;
+#else
+const int config_audio_dac_noisefloor_optimize_enable = BIT(1);
+#endif
+
+// mixer在单独任务中输出
+#if TCFG_MIXER_CYCLIC_TASK_EN
+const int config_mixer_task = 1;
+#else
+const int config_mixer_task = 0;
+#endif
+
+// mixer各个通道拥有独立buf
+const int config_mixer_ch_self_buf_en = 0;
+
+#ifdef CONFIG_256K_FLASH
+// mixer模块使能。不使能将关闭大部分功能,mix为直通
+const int config_mixer_en = 0;
+// mixer变采样使能
+const int config_mixer_src_en = 0;
+
+// audio解码资源叠加功能使能。不使能,如果配置了叠加方式,将改成抢占方式
+const int config_audio_dec_wait_protect_en = 0;
+
+// audio数据流分支功能使能。
+const int config_audio_stream_frame_copy_en = 0;
+
+// audio dec app调用mixer相关函数控制。关闭后需上层设置数据流的输出节点
+const int audio_dec_app_mix_en = 0;
+
+#else
+
+// mixer模块使能。不使能将关闭大部分功能,mix为直通
+const int config_mixer_en = 1;
+// mixer变采样使能
+const int config_mixer_src_en = 1;
+
+// audio解码资源叠加功能使能。不使能,如果配置了叠加方式,将改成抢占方式
+const int config_audio_dec_wait_protect_en = 1;
+
+// audio数据流分支功能使能。
+const int config_audio_stream_frame_copy_en = 1;
+
+// audio dec app调用mixer相关函数控制。关闭后需上层设置数据流的输出节点
+const int audio_dec_app_mix_en = 1;
+
+#endif
+
+// audio数据流分支cbuf大小控制
+const int config_audio_stream_frame_copy_cbuf_min = 128;
+const int config_audio_stream_frame_copy_cbuf_max = 1024;
+
+// 超时等待其他解码unactive步骤完成
+const int config_audio_dec_unactive_to = 0;
+// audio数据流ioctrl使能
+const int config_audio_stream_frame_ioctrl_en = 0;
+
+// audio dec app tws同步使能
+const int audio_dec_app_sync_en = 0;
+
+// 解码使用单独任务做输出
+#if TCFG_AUDIO_DEC_OUT_TASK
+const int config_audio_dec_out_task_en = 1;
+#else
+const int config_audio_dec_out_task_en = 0;
+#endif
+
+
+#ifdef CONFIG_256K_FLASH
+const char config_audio_mini_enable = 1;
+#else
+const char config_audio_mini_enable = 0;
+#endif
+
+enum {
+ PLATFORM_FREQSHIFT_CORDIC = 0,
+ PLATFORM_FREQSHIFT_CORDICV2 = 1
+};
+
+/* 备注: */
+/* br23/br25/br30/br34/br40是PLATFORM_FREQSHIFT_CORDIC */
+/* , br36/br28/br27是PLATFORM_FREQSHIFT_CORDICV2 */
+
+#if (CONFIG_CPU_BR28 || CONFIG_CPU_BR27 || CONFIG_CPU_BR36)
+#define PLATFORM_PARM_SEL PLATFORM_FREQSHIFT_CORDICV2
+#else
+#define PLATFORM_PARM_SEL PLATFORM_FREQSHIFT_CORDIC
+#endif
+
+const int howling_freshift_PLATFORM = PLATFORM_PARM_SEL;
+const int howling_freshift_highmode_flag = 0; //移频快速模式
+const int howling_pitchshift_fastmode_flag = 1;//移频啸叫抑制快速模式使能
+
+const int vc_pitchshift_fastmode_flag = 1; //变声快速模式使能
+const int vc_pitchshift_downmode_flag = 0; //变声下采样处理使能
+const int VC_KINDO_TVM = 1; //含义为EFFECT_VOICECHANGE_KIN0是否另一种算法 : 0表示跟原来一样,1表示用另一种
+const int RS_FAST_MODE_QUALITY = 2; //软件变采样 滤波阶数配置,范围2到8, 8代表16阶的变采样模式 ,速度跟它的大小呈正相关
+const int config_howling_enable_pemafrow_mode = 0;
+const int config_howling_enable_trap_mode = 1;//陷波啸叫抑制模式使能
+const int config_howling_enable_pitchps_mode = 1; //移频啸叫抑制模式使能
+
+const unsigned char config_audio_dac_underrun_protect = 1;
+
+#if ((SYS_VOL_TYPE == VOL_TYPE_DIGITAL_HW) || (SYS_VOL_TYPE == VOL_TYPE_DIGITAL))
+const char config_audio_dac_trim_enable = 1;
+#else
+const char config_audio_dac_trim_enable = 1;
+#endif
+
+#if TCFG_LOWPOWER_LOWPOWER_SEL
+const int config_audio_dac_delay_off_ms = 300;
+#else
+const int config_audio_dac_delay_off_ms = 0;
+#endif
+
+const int config_audio_dac_vcm_chsel_delay = 1500;
+
+
+// 解码任务测试
+const int audio_decoder_test_en = 0;
+// 当audio_decoder_test_en使能时需要实现以下接口
+#if 0
+void audio_decoder_test_out_before(struct audio_decoder *dec, void *buff, int len) {} ;
+void audio_decoder_test_out_after(struct audio_decoder *dec, int wlen) {} ;
+void audio_decoder_test_read_before(struct audio_decoder *dec, int len, u32 offset) {} ;
+void audio_decoder_test_read_after(struct audio_decoder *dec, u8 *data, int rlen) {} ;
+void audio_decoder_test_get_frame_before(struct audio_decoder *dec) {} ;
+void audio_decoder_test_get_frame_after(struct audio_decoder *dec, u8 *frame, int rlen) {} ;
+void audio_decoder_test_fetch_before(struct audio_decoder *dec) {} ;
+void audio_decoder_test_fetch_after(struct audio_decoder *dec, u8 *frame, int rlen) {} ;
+void audio_decoder_test_run_before(struct audio_decoder *dec) {} ;
+void audio_decoder_test_run_after(struct audio_decoder *dec, int err) {} ;
+#else
+// 接口实现示例
+//#include "audio/demo/audio_decoder_test.c"
+#endif
+
+
+// 编码任务测试
+const int audio_encoder_test_en = 0;
+// 当audio_encoder_test_en使能时需要实现以下接口
+#if 0
+void audio_encoder_test_out_before(struct audio_encoder *enc, void *buff, int len) {} ;
+void audio_encoder_test_out_after(struct audio_encoder *enc, int wlen) {} ;
+void audio_encoder_test_get_frame_before(struct audio_encoder *enc, u16 frame_len) {} ;
+void audio_encoder_test_get_frame_after(struct audio_encoder *enc, s16 *frame, int rlen) {} ;
+void audio_encoder_test_run_before(struct audio_encoder *enc) {} ;
+void audio_encoder_test_run_after(struct audio_encoder *enc, int err) {} ;
+#else
+// 接口实现示例
+//#include "audio/demo/audio_encoder_test.c"
+#endif
+//数字音量节点 是否使用汇编优化 不支持的芯片需置0
+#if(CONFIG_CPU_BR18)
+const int const_config_digvol_use_round = 0;
+#else
+const int const_config_digvol_use_round = 1;
+#endif
+
+/*杰理KWS关键词识别*/
+#if TCFG_SMART_VOICE_ENABLE
+const int CONFIG_KWS_WAKE_WORD_MODEL_ENABLE = 0;
+const int CONFIG_KWS_MULTI_CMD_MODEL_ENABLE = 1;
+#if TCFG_CALL_KWS_SWITCH_ENABLE
+const int CONFIG_KWS_CALL_CMD_MODEL_ENABLE = 1;
+#else
+const int CONFIG_KWS_CALL_CMD_MODEL_ENABLE = 0;
+#endif
+#ifdef CONFIG_CPU_BR28
+const int CONFIG_KWS_RAM_USE_ENABLE = 1;
+#else
+const int CONFIG_KWS_RAM_USE_ENABLE = 2;
+#endif
+const int CONFIG_KWS_ONLINE_MODEL = 1;
+const float CONFIG_KWS_MULTI_CONFIDENCE[] = {
+ 0.4, 0.4, 0.4, 0.4, //小杰小杰,小杰同学,播放音乐,停止播放
+ 0.4, 0.4, 0.4, 0.3, //暂停播放,增大音量,减小音量,上一首
+ 0.3, 0.35, 0.35, 0.35, //下一首,打开降噪,关闭降噪,打开通透
+};
+
+const float CONFIG_KWS_CALL_CONFIDENCE[] = {
+ 0.4, 0.4, //接听电话,挂断电话
+};
+#else
+const int CONFIG_KWS_WAKE_WORD_MODEL_ENABLE = 0;
+const int CONFIG_KWS_MULTI_CMD_MODEL_ENABLE = 0;
+const int CONFIG_KWS_CALL_CMD_MODEL_ENABLE = 0;
+const int CONFIG_KWS_ONLINE_MODEL = 0;
+#endif
+
+#if (defined TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN) && TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+const int config_resample_pcm_frame_buffer = 512;
+#else
+const int config_resample_pcm_frame_buffer = 128;
+#endif
+
+/*第二版串口写卡工具,支持写不定长度数据*/
+u8 const_audio_pcm_debug_v2_en = 0;
+
+/**
+ * @brief Log (Verbose/Info/Debug/Warn/Error)
+ */
+/*-----------------------------------------------------------*/
+const char log_tag_const_v_EQ_CFG AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_EQ_CFG AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_EQ_CFG AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_EQ_CFG AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_EQ_CFG AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_EQ_CFG_TOOL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_EQ_CFG_TOOL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_EQ_CFG_TOOL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_EQ_CFG_TOOL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_EQ_CFG_TOOL AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_EQ_APPLY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_EQ_APPLY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_EQ_APPLY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_EQ_APPLY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_EQ_APPLY AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_DRC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_DRC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_DRC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_DRC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_DRC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_APP_DRC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_APP_DRC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_APP_DRC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_APP_DRC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_APP_DRC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+
+const char log_tag_const_v_EQ AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_EQ AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_EQ AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_EQ AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_EQ AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_AUD_ADC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_AUD_ADC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_AUD_ADC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_AUD_ADC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_e_AUD_ADC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+
+const char log_tag_const_v_AUD_DAC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_AUD_DAC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_AUD_DAC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_AUD_DAC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_e_AUD_DAC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+
+const char log_tag_const_v_APP_DAC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_APP_DAC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_APP_DAC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_APP_DAC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_e_APP_DAC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+
+const char log_tag_const_v_AUD_AUX AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_AUD_AUX AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_AUD_AUX AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_w_AUD_AUX AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_e_AUD_AUX AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+
+const char log_tag_const_v_MIXER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_c_MIXER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_MIXER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_MIXER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_MIXER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_AUDIO_STREAM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_c_AUDIO_STREAM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_AUDIO_STREAM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_AUDIO_STREAM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_AUDIO_STREAM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_AUDIO_DECODER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_c_AUDIO_DECODER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_AUDIO_DECODER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_AUDIO_DECODER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_AUDIO_DECODER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_AUDIO_ENCODER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_c_AUDIO_ENCODER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_AUDIO_ENCODER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_AUDIO_ENCODER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_AUDIO_ENCODER AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+
+const char log_tag_const_v_SYNCTS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_c_SYNCTS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_i_SYNCTS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_d_SYNCTS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
+const char log_tag_const_e_SYNCTS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+
+
diff --git a/apps/earphone/log_config/lib_system_config.c b/apps/earphone/log_config/lib_system_config.c
new file mode 100644
index 0000000..c731afb
--- /dev/null
+++ b/apps/earphone/log_config/lib_system_config.c
@@ -0,0 +1,109 @@
+/*********************************************************************************************
+ * Filename : lib_system_config.c
+
+ * Description : Optimized Code & RAM (编译优化配置)
+
+ * Author : Bingquan
+
+ * Email : caibingquan@zh-jieli.com
+
+ * Last modifiled : 2019-03-18 15:22
+
+ * Copyright:(c)JIELI 2011-2019 @ , All Rights Reserved.
+*********************************************************************************************/
+
+#include "app_config.h"
+#include "system/includes.h"
+
+
+///打印是否时间打印信息
+const int config_printf_time = 1;
+
+///异常中断,asser打印开启
+#ifdef CONFIG_RELEASE_ENABLE
+const int config_asser = 0;
+#else
+const int config_asser = 1;
+#endif
+
+const int config_system_info = 0;
+
+//================================================//
+// SDFILE 精简使能 //
+//================================================//
+const int SDFILE_VFS_REDUCE_ENABLE = 1;
+
+//================================================//
+// dev使用异步读使能 //
+//================================================//
+#ifdef TCFG_DEVICE_BULK_READ_ASYNC_ENABLE
+const int device_bulk_read_async_enable = 1;
+#else
+const int device_bulk_read_async_enable = 0;
+#endif
+
+
+const int VIRFAT_FLASH_ENABLE = 0;
+
+//================================================//
+// UI //
+//================================================//
+const int ENABLE_LUA_VIRTUAL_MACHINE = 0;
+
+//================================================//
+// 不可屏蔽中断使能配置(unmask_irq) //
+//================================================//
+const int CONFIG_CPU_UNMASK_IRQ_ENABLE = 0;
+
+/**
+ * @brief Log (Verbose/Info/Debug/Warn/Error)
+ */
+/*-----------------------------------------------------------*/
+const char log_tag_const_v_SYS_TMR AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_SYS_TMR AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_SYS_TMR AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_SYS_TMR AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_SYS_TMR AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_JLFS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_JLFS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_JLFS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_JLFS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_JLFS AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+//FreeRTOS
+const char log_tag_const_v_PORT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_PORT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_PORT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_PORT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_PORT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_KTASK AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_KTASK AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_KTASK AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_KTASK AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_KTASK AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_uECC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_uECC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_uECC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_uECC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_uECC AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_HEAP_MEM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_HEAP_MEM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_HEAP_MEM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_w_HEAP_MEM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_HEAP_MEM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_V_MEM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_V_MEM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_V_MEM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_V_MEM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_V_MEM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+
+const char log_tag_const_v_P_MEM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_i_P_MEM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_d_P_MEM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
+const char log_tag_const_w_P_MEM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
+const char log_tag_const_e_P_MEM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(TRUE);
diff --git a/apps/earphone/log_config/lib_update_config.c b/apps/earphone/log_config/lib_update_config.c
new file mode 100644
index 0000000..62bcf21
--- /dev/null
+++ b/apps/earphone/log_config/lib_update_config.c
@@ -0,0 +1,48 @@
+
+#include "app_config.h"
+#include "system/includes.h"
+#include "update_loader_download.h"
+
+#ifdef CONFIG_256K_FLASH
+const int config_update_mode = UPDATE_UART_EN;
+#else
+const int config_update_mode = UPDATE_BT_LMP_EN \
+ | UPDATE_STORAGE_DEV_EN | UPDATE_BLE_TEST_EN | UPDATE_APP_EN | UPDATE_UART_EN;
+#endif
+
+#ifndef CONFIG_APP_BT_ENABLE
+//是否采用双备份升级方案:0-单备份;1-双备份
+#if CONFIG_DOUBLE_BANK_ENABLE
+const int support_dual_bank_update_en = 1;
+#else
+const int support_dual_bank_update_en = 0;
+#endif //CONFIG_DOUBLE_BANK_ENABLE
+#else
+
+//是否采用双备份升级方案:0-单备份;1-双备份
+#if CONFIG_DOUBLE_BANK_ENABLE
+const int support_dual_bank_update_en = 1;
+#else
+const int support_dual_bank_update_en = 0;
+#endif //CONFIG_DOUBLE_BANK_ENABLE
+#endif
+
+#if OTA_TWS_SAME_TIME_NEW //使用新的同步升级流程
+const int support_ota_tws_same_time_new = 1;
+#else
+const int support_ota_tws_same_time_new = 0;
+#endif
+//是否支持升级之后保留vm数据
+const int support_vm_data_keep = 1;
+
+//是否支持外挂flash升级,需要打开Board.h中的TCFG_NOR_FS_ENABLE
+const int support_norflash_update_en = 0;
+
+//支持从外挂flash读取ufw文件升级使能
+const int support_norflash_ufw_update_en = 0;
+
+const char log_tag_const_v_UPDATE AT(.LOG_TAG_CONST) = LIB_DEBUG & FALSE;
+const char log_tag_const_i_UPDATE AT(.LOG_TAG_CONST) = LIB_DEBUG & TRUE;
+const char log_tag_const_d_UPDATE AT(.LOG_TAG_CONST) = LIB_DEBUG & FALSE;
+const char log_tag_const_w_UPDATE AT(.LOG_TAG_CONST) = LIB_DEBUG & TRUE;
+const char log_tag_const_e_UPDATE AT(.LOG_TAG_CONST) = LIB_DEBUG & TRUE;
diff --git a/apps/earphone/pc/pc.c b/apps/earphone/pc/pc.c
new file mode 100644
index 0000000..7d87648
--- /dev/null
+++ b/apps/earphone/pc/pc.c
@@ -0,0 +1,345 @@
+#include "system/includes.h"
+//#include "music/music_player.h"
+//#include "music/breakpoint.h"
+#include "app_action.h"
+#include "key_event_deal.h"
+#include "audio_config.h"
+#include "bt_background.h"
+#include "default_event_handler.h"
+#include "usb/device/usb_stack.h"
+#include "usb/device/hid.h"
+#include "tone_player.h"
+#include "user_cfg.h"
+#include "app_task.h"
+#include "earphone.h"
+#include "app_power_manage.h"
+#include "app_charge.h"
+
+#if ((TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE) \
+ && TCFG_CHARGESTORE_PORT == IO_PORT_DP)
+#include "asm/chargestore.h"
+#endif
+
+#define LOG_TAG_CONST PC
+#define LOG_TAG "[PC]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#if TCFG_PC_ENABLE
+
+
+struct app_pc_var {
+ u8 inited;
+ u8 idle;
+};
+
+static struct app_pc_var g_pc;
+
+#if(TCFG_TYPE_C_ENABLE)
+static u8 pc_key_table[][KEY_EVENT_MAX] = {
+ // SHORT LONG HOLD
+ // UP DOUBLE TRIPLE
+ {
+ KEY_MUSIC_PP, KEY_CALL_ANSWER, KEY_NULL,
+ KEY_CALL_ANSWER_UP, KEY_NULL, KEY_NULL
+ },
+
+ {
+ KEY_MUSIC_NEXT, KEY_VOL_UP, KEY_VOL_UP,
+ KEY_NULL, KEY_NULL, KEY_NULL
+ },
+
+ {
+ KEY_MUSIC_PREV, KEY_VOL_DOWN, KEY_VOL_DOWN,
+ KEY_NULL, KEY_NULL, KEY_NULL
+ },
+};
+#else
+static u8 pc_key_table[][KEY_EVENT_MAX] = {
+ // SHORT LONG HOLD
+ // UP DOUBLE TRIPLE
+ {
+ KEY_MUSIC_PP, KEY_POWEROFF, KEY_POWEROFF_HOLD,
+ KEY_NULL, KEY_MODE_SWITCH, KEY_NULL
+ },
+
+ {
+ KEY_MUSIC_NEXT, KEY_VOL_UP, KEY_VOL_UP,
+ KEY_NULL, KEY_NULL, KEY_NULL
+ },
+
+ {
+ KEY_MUSIC_PREV, KEY_VOL_DOWN, KEY_VOL_DOWN,
+ KEY_NULL, KEY_NULL, KEY_NULL
+ },
+};
+#endif
+
+static u8 pc_idle_query()
+{
+ return !g_pc.idle;
+}
+REGISTER_LP_TARGET(pc_lp_target) = {
+ .name = "pc",
+ .is_idle = pc_idle_query,
+};
+
+
+//*----------------------------------------------------------------------------*/
+/**@brief pc 在线检测 切换模式判断使用
+ @param 无
+ @return 1 linein设备在线 0 设备不在线
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+int pc_app_check(void)
+{
+ log_info("pc_app_check");
+#if TCFG_ONLY_PC_ENABLE
+ return true; //不需要检测
+#endif
+ u32 r = usb_otg_online(0);
+ if ((r == SLAVE_MODE) ||
+ (r == SLAVE_MODE_WAIT_CONFIRMATION)) {
+ return true;
+ }
+ log_info("pc check offline");
+ return false;
+}
+
+
+static void app_pc_exit();
+static void app_pc_init(enum app_state state)
+{
+ log_info("app_pc_init");
+ g_pc.idle = 1;
+#if TCFG_PC_ENABLE
+ clk_set("sys", 96000000); //提高系统时钟,优化usb出盘符速度
+ if (pc_app_check() == false) {
+ if (state == APP_STA_RESUME) {
+ log_info("APP_PC_RESUME err");
+ /* APP_STA_RESUME时若设备不在线,不可在该位置切模式,
+ 因为上一次的app切换还没完成,还未真正进入PC模式 */
+ app_pc_exit();
+ } else {
+ app_task_switch_next();
+ }
+ } else {
+#if TCFG_USB_CDC_BACKGROUND_RUN
+ usb_stop();
+#endif
+ usb_start();
+ }
+#endif
+}
+
+static void app_pc_exit()
+{
+ log_info("app_pc_exit");
+ if (pc_app_check() == false) {
+ usb_stop();
+ } else {
+ usb_pause();
+#if TCFG_USB_CDC_BACKGROUND_RUN
+ usb_cdc_background_run();
+#endif
+ }
+ g_pc.idle = 0;
+}
+
+static int app_pc_key_event_handler(struct sys_event *event)
+{
+ struct key_event *key = &event->u.key;
+ int key_event = pc_key_table[key->value][key->event];
+ switch (key_event) {
+#if TCFG_USB_SLAVE_HID_ENABLE
+ case KEY_MUSIC_PP:
+ log_info("KEY_MUSIC_PP");
+ hid_key_handler(0, USB_AUDIO_PP);
+ break;
+ case KEY_MUSIC_NEXT:
+ log_info("KEY_MUSIC_NEXT");
+#if(TCFG_TYPE_C_ENABLE)
+ hid_key_handler(0, USB_AUDIO_PP);
+ os_time_dly(2);
+ hid_key_handler(0, USB_AUDIO_PP);
+#else
+ hid_key_handler(0, USB_AUDIO_NEXTFILE);
+#endif
+ break;
+ case KEY_MUSIC_PREV:
+ log_info("KEY_MUSIC_PREV");
+#if(TCFG_TYPE_C_ENABLE)
+ hid_key_handler(0, USB_AUDIO_PP);
+ os_time_dly(2);
+ hid_key_handler(0, USB_AUDIO_PP);
+ os_time_dly(2);
+ hid_key_handler(0, USB_AUDIO_PP);
+#else
+ hid_key_handler(0, USB_AUDIO_PREFILE);
+#endif
+ break;
+ case KEY_VOL_UP:
+ log_info("KEY_MUSIC_UP");
+ hid_key_handler(0, USB_AUDIO_VOLUP);
+ break;
+ case KEY_VOL_DOWN:
+ log_info("KEY_MUSIC_DOWN");
+ hid_key_handler(0, USB_AUDIO_VOLDOWN);
+ break;
+#if(TCFG_TYPE_C_ENABLE)
+ case KEY_CALL_ANSWER:
+ puts("KEY_CALL_ANSWER\n");
+ hid_key_handler_send_one_packet(0, USB_AUDIO_PP);
+ break;
+ case KEY_CALL_ANSWER_UP:
+ puts("KEY_CALL_ANSWER_UP\n");
+ hid_key_handler_send_one_packet(0, 0);
+ break;
+#endif
+#endif//end TCFG_USB_SLAVE_HID_ENABLE
+ case KEY_MODE_SWITCH:
+ log_info("KEY_MODE_SWITCH");
+ app_task_switch_next();
+ break;
+ case KEY_POWEROFF:
+ case KEY_POWEROFF_HOLD:
+ app_earphone_key_event_handler(event);
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+
+/*
+ * 系统事件处理函数
+ */
+static int event_handler(struct application *app, struct sys_event *event)
+{
+ /*if (SYS_EVENT_REMAP(event)) {
+ g_printf("****SYS_EVENT_REMAP**** \n");
+ return 0;
+ }*/
+
+ switch (event->type) {
+ case SYS_KEY_EVENT:
+ /*
+ * 普通按键消息处理
+ */
+ return app_pc_key_event_handler(event);
+ case SYS_BT_EVENT:
+ /*
+ * 蓝牙事件处理
+ */
+ break;
+ case SYS_DEVICE_EVENT:
+ /*
+ * 系统设备事件处理
+ */
+ if ((u32)event->arg == DEVICE_EVENT_FROM_OTG) {
+ if (event->u.dev.event == DEVICE_EVENT_OUT) {
+ app_task_switch_next();
+ return true;
+ }
+ } else if ((u32)event->arg == DEVICE_EVENT_FROM_POWER) {
+ app_power_event_handler(&event->u.dev);
+ return true;
+ } else if ((u32)event->arg == DEVICE_EVENT_FROM_CHARGE) {
+#if TCFG_CHARGE_ENABLE
+ app_charge_event_handler(&event->u.dev);
+#endif
+ return true;
+ }
+
+ break;
+ default:
+ return false;
+ }
+
+#if(!TCFG_ONLY_PC_ENABLE)
+ default_event_handler(event);
+#endif
+
+ return false;
+}
+
+static int state_machine(struct application *app, enum app_state state,
+ struct intent *it)
+{
+ switch (state) {
+ case APP_STA_CREATE:
+ log_info("APP_STA_CREATE");
+ STATUS *p_tone = get_tone_config();
+ tone_play(TONE_PC_MODE, 1);
+ break;
+ case APP_STA_START:
+ log_info("APP_STA_START");
+ if (!it) {
+ break;
+ }
+ switch (it->action) {
+ case ACTION_PC_MAIN:
+ log_info("ACTION_PC_MAIN");
+ ///按键使能
+ sys_key_event_enable();
+ //关闭自动关机
+ sys_auto_shut_down_disable();
+#if ((TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE) \
+ && TCFG_CHARGESTORE_PORT == IO_PORT_DP)
+ power_wakeup_index_enable(2, 0);
+ chargestore_api_stop();
+#endif
+ app_pc_init(state);
+ break;
+ }
+ break;
+ case APP_STA_PAUSE:
+ log_info("APP_STA_PAUSE");
+ app_pc_exit();
+ break;
+ case APP_STA_RESUME:
+ log_info("APP_STA_RESUME");
+ app_pc_init(state);
+ break;
+ case APP_STA_STOP:
+ log_info("APP_STA_STOP");
+ app_pc_exit();
+#if ((TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE) \
+ && TCFG_CHARGESTORE_PORT == IO_PORT_DP)
+ chargestore_api_restart();
+ power_wakeup_index_enable(2, 1);
+#endif
+ break;
+ case APP_STA_DESTROY:
+ log_info("APP_STA_DESTROY");
+ break;
+ }
+
+ return 0;
+}
+
+static const struct application_operation app_pc_ops = {
+ .state_machine = state_machine,
+ .event_handler = event_handler,
+};
+
+/*
+ * 注册pc模式
+ */
+REGISTER_APPLICATION(app_pc) = {
+ .name = "pc",
+ .action = ACTION_PC_MAIN,
+ .ops = &app_pc_ops,
+ .state = APP_STA_DESTROY,
+};
+
+
+#endif
+
diff --git a/apps/earphone/power_manage/app_charge.c b/apps/earphone/power_manage/app_charge.c
new file mode 100644
index 0000000..09ce57a
--- /dev/null
+++ b/apps/earphone/power_manage/app_charge.c
@@ -0,0 +1,743 @@
+#include "app_config.h"
+#include "asm/charge.h"
+#include "asm/pwm_led.h"
+#include "asm/power_interface.h"
+#include "ui_manage.h"
+#include "system/event.h"
+#include "system/app_core.h"
+#include "system/includes.h"
+#include "app_action.h"
+#include "asm/wdt.h"
+#include "app_power_manage.h"
+//#include "app_chargestore.h"
+#include "app_testbox.h"
+#include "btstack/avctp_user.h"
+#include "app_action.h"
+#include "app_main.h"
+#include "bt_tws.h"
+#include "usb/otg.h"
+#include "bt_common.h"
+
+#if TCFG_AUDIO_ANC_ENABLE
+#include "audio_anc.h"
+#endif
+
+#if NTC_DET_EN
+#include "ntc_det_api.h"
+#endif
+
+#if TCFG_ANC_BOX_ENABLE
+#include "app_ancbox.h"
+#endif
+
+#define LOG_TAG_CONST APP_CHARGE
+#define LOG_TAG "[APP_CHARGE]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+extern void sys_enter_soft_poweroff(void *priv);
+extern void gSensor_wkupup_enable(void);
+extern void gSensor_wkupup_disable(void);
+extern u32 dual_bank_update_exist_flag_get(void);
+extern u32 classic_update_task_exist_flag_get(void);
+extern void lp_touch_key_disable(void);
+extern void linein_det_disable(void);
+extern void linein_det_enable(void);
+
+#if TCFG_CHARGE_ENABLE
+
+static u8 charge_full_flag = 0;
+#if TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE
+static int ldo5v_keep_timer = 0;
+#endif
+static u8 delay_timeout = 20;
+static int ldo5v_in_reset_timer = 0;
+static void ldo5v_in_reset_delay(void)
+{
+ int deal_state = tws_api_get_tws_state();
+ u8 cpu_reset_flag = 1;
+ if (delay_timeout) {
+ delay_timeout--;
+ }
+ if (deal_state & TWS_STA_SIBLING_CONNECTED && deal_state & TWS_STA_PHONE_CONNECTED && !(deal_state & TWS_STA_MONITOR_START)) {
+ //tws已连接 手机已连接 从机未监听手机
+ cpu_reset_flag = 0;
+ } else {
+ if (deal_state & TWS_STA_SIBLING_CONNECTED && deal_state & TWS_STA_ESCO_OPEN && !get_esco_coder_busy_flag()) {
+ //手机有请求但没建立ESCO链路
+ cpu_reset_flag = 0;
+ }
+ }
+ printf("----------------ldo5v_in_reset_delay tws state:%x, delay_timeout:%d, cpu_reset_flag:%d\n", deal_state, delay_timeout, cpu_reset_flag);
+ if (delay_timeout == 0 || cpu_reset_flag == 1) {
+ if (ldo5v_in_reset_timer) {
+ sys_timer_del(ldo5v_in_reset_timer);
+ ldo5v_in_reset_timer = 0;
+ }
+ sys_enter_soft_poweroff((void *)1);
+ }
+}
+
+extern void power_event_to_user(u8 event);
+
+u8 get_charge_full_flag(void)
+{
+ return charge_full_flag;
+}
+
+void charge_start_deal(void)
+{
+ log_info("%s\n", __FUNCTION__);
+
+ power_set_mode(PWR_LDO15);
+
+ struct application *app;
+ app = get_current_app();
+ //在IDLE时才开启充电UI
+ if (app && (!strcmp(app->name, APP_NAME_IDLE))) {
+ ui_update_status(STATUS_CHARGE_START);
+ }
+}
+
+static void ldo5v_keep_delay_deal(void *priv)
+{
+ log_info("%s\n", __func__);
+
+#if TCFG_TEST_BOX_ENABLE
+ ldo5v_keep_timer = 0;
+ if (testbox_get_status()) {
+ log_info("testbox online!\n");
+ return;
+ }
+#endif
+
+#if TCFG_ANC_BOX_ENABLE
+ ldo5v_keep_timer = 0;
+ if (ancbox_get_status()) {
+ log_info("ancbox online!\n");
+ return;
+ }
+#endif
+
+ struct application *app;
+ app = get_current_app();
+ if (app) {
+ if (strcmp(app->name, APP_NAME_IDLE)) {
+ sys_enter_soft_poweroff((void *)2);
+ }
+ }
+
+ pwm_led_mode_set(PWM_LED_ALL_OFF);
+ os_time_dly(30);
+ pwm_led_mode_set(PWM_LED1_ON);
+ os_time_dly(40);
+
+ //兼容一些充电仓5v输出慢的时候会导致无法充电的问题
+ if (get_lvcmp_det()) {
+ log_info("...charge ing...\n");
+ cpu_reset();
+ }
+
+ log_info("get_charge_online_flag:%d %d\n", get_charge_online_flag(), get_ldo5v_online_hw());
+ if (get_ldo5v_online_hw() && get_charge_online_flag()) {
+ power_set_soft_poweroff();
+ } else {
+#if TCFG_CHARGE_OFF_POWERON_NE
+ cpu_reset();
+#else
+ charge_check_and_set_pinr(1);
+ power_set_soft_poweroff();
+#endif
+ }
+}
+
+
+/*ldoin电压大于拔出电压(0.6V左右)且小于VBat电压时调用该函数进行一些错误提示或其他处理*/
+void ldo5v_keep_deal(void)
+{
+
+ log_info("%s\n", __func__);
+
+ //插入交换
+ power_event_to_user(POWER_EVENT_POWER_CHANGE);
+
+#if TCFG_GSENSOR_ENABLE
+ //在舱关闭gSensor
+ gSensor_wkupup_disable();
+#endif
+
+#if TCFG_LINEIN_ENABLE
+ //入舱关闭linein
+ linein_det_disable();
+#endif
+
+#if TCFG_LP_TOUCH_KEY_ENABLE
+ extern void lp_touch_key_charge_mode_enter();
+ lp_touch_key_charge_mode_enter();
+#endif /* #if TCFG_LP_TOUCH_KEY_ENABLE */
+
+#if TCFG_GX8002_NPU_ENABLE
+ extern void gx8002_module_suspend(u8 keep_vddio);
+ gx8002_module_suspend(0);
+#endif /* #if TCFG_GX8002_NPU_ENABLE */
+
+
+ charge_check_and_set_pinr(0);
+
+#if TCFG_AUDIO_ANC_ENABLE
+#if TCFG_ANC_BOX_ENABLE
+ if (!ancbox_get_status())
+#endif
+ {
+ anc_suspend();
+ }
+#endif
+
+ if (get_charge_poweron_en() == 0) {
+#if TCFG_CHARGESTORE_ENABLE
+ //智能充电舱不处理充电err
+ struct application *app;
+ app = get_current_app();
+ if (app && (!strcmp(app->name, APP_NAME_IDLE))) {
+ ui_update_status(STATUS_CHARGE_LDO5V_OFF);
+ }
+
+#else //TCFG_CHARGESTORE_ENABLE
+
+#if defined(TCFG_CHARGE_KEEP_UPDATA) && TCFG_CHARGE_KEEP_UPDATA
+ if (dual_bank_update_exist_flag_get() || classic_update_task_exist_flag_get()) {
+ return;
+ }
+#endif
+
+#if TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE
+ if (testbox_get_ex_enter_dut_flag()) {
+ putchar('D');
+ return;
+ }
+
+ if (testbox_get_ex_enter_storage_mode_flag()) {
+ putchar('S');
+ return;
+ }
+
+ if (ldo5v_keep_timer == 0) {
+ //延时执行避免测试盒通信不上
+ ldo5v_keep_timer = sys_timeout_add(NULL, ldo5v_keep_delay_deal, 250);
+ }
+#else
+ ldo5v_keep_delay_deal(NULL);
+#endif//TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE
+#endif//TCFG_CHARGESTORE_ENABLE
+ } else {
+ ui_update_status(STATUS_CHARGE_ERR);
+ }
+}
+
+extern u8 umidigi_chargestore_get_cover_status(void);
+void charge_full_deal(void)
+{
+ log_info("%s\n", __func__);
+
+ charge_full_flag = 1;
+
+ charge_close();
+ if (get_charge_poweron_en() == 0) {
+
+#if (TCFG_LP_TOUCH_KEY_ENABLE && CHARGING_CLEAN_PHONE_INFO)
+ extern void lp_touch_key_charge_mode_enter();
+ lp_touch_key_charge_mode_enter();
+#endif
+ /* power_set_soft_poweroff(); */
+#if TCFG_USER_TWS_ENABLE
+
+#else
+ ui_update_status(STATUS_CHARGE_FULL);
+#endif
+#if (!TCFG_CHARGESTORE_ENABLE)
+#if TCFG_UMIDIGI_BOX_ENABLE
+//当前为开盖
+ if (umidigi_chargestore_get_cover_status() == 1) {
+ vbat_timer_delete();
+ }
+#else
+ vbat_timer_delete();
+#endif
+#endif
+ } else {
+ ui_update_status(STATUS_CHARGE_FULL);
+ }
+}
+
+void charge_close_deal(void)
+{
+ log_info("%s\n", __FUNCTION__);
+
+ power_set_mode(TCFG_LOWPOWER_POWER_SEL);
+
+#if TCFG_USER_TWS_ENABLE
+ //在idle的时候才执行充电关闭的UI
+ struct application *app;
+ app = get_current_app();
+ if (app && (!strcmp(app->name, APP_NAME_IDLE))) {
+ ui_update_status(STATUS_CHARGE_CLOSE);
+ }
+#endif
+}
+
+
+void charge_ldo5v_in_deal(void)
+{
+ log_info("%s\n", __FUNCTION__);
+
+
+#if TCFG_IRSENSOR_ENABLE
+ if (get_bt_tws_connect_status()) {
+ tws_api_sync_call_by_uuid('T', SYNC_CMD_EARPHONE_CHAREG_START, 300);
+ }
+#endif
+
+ //插入交换
+ power_event_to_user(POWER_EVENT_POWER_CHANGE);
+
+ charge_full_flag = 0;
+
+#if TCFG_GSENSOR_ENABLE
+ //入舱关闭gSensor
+ gSensor_wkupup_disable();
+#endif
+
+#if TCFG_LINEIN_ENABLE
+ //入舱关闭linein
+ linein_det_disable();
+#endif
+
+#if (TCFG_LP_TOUCH_KEY_ENABLE && !CHARGING_CLEAN_PHONE_INFO)
+ extern void lp_touch_key_charge_mode_enter();
+ lp_touch_key_charge_mode_enter();
+#endif /* #if TCFG_LP_TOUCH_KEY_ENABLE */
+
+#if TCFG_GX8002_NPU_ENABLE
+ extern void gx8002_module_suspend(u8 keep_vddio);
+ gx8002_module_suspend(0);
+#endif /* #if TCFG_GX8002_NPU_ENABLE */
+
+ charge_check_and_set_pinr(0);
+
+#if TCFG_AUDIO_ANC_ENABLE
+ anc_suspend();
+#endif
+
+#if TCFG_TEST_BOX_ENABLE
+ testbox_clear_status();
+ if (ldo5v_keep_timer) {
+ sys_timeout_del(ldo5v_keep_timer);
+ ldo5v_keep_timer = 0;
+ }
+#endif
+
+#if TCFG_ANC_BOX_ENABLE
+ ancbox_clear_status();
+ if (ldo5v_keep_timer) {
+ sys_timeout_del(ldo5v_keep_timer);
+ ldo5v_keep_timer = 0;
+ }
+#endif
+
+#if TCFG_CHARGESTORE_ENABLE
+ chargestore_shutdown_reset();
+#endif
+
+ if (get_charge_poweron_en() == 0) {
+#if defined(TCFG_CHARGE_KEEP_UPDATA) && TCFG_CHARGE_KEEP_UPDATA
+ if (dual_bank_update_exist_flag_get() || classic_update_task_exist_flag_get()) {
+ return;
+ }
+#endif
+ struct application *app;
+ app = get_current_app();
+
+#if TCFG_WIRELESS_MIC_ENABLE
+ if (strcmp(app->name, APP_NAME_IDLE) != 0) {
+ sys_enter_soft_poweroff((void *)1);
+ }
+#endif
+ if (app && strcmp(app->name, APP_NAME_IDLE)) {
+#if (TCFG_CHARGESTORE_ENABLE && TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV)
+ if (!chargestore_check_going_to_poweroff()) {
+#endif
+#if TCFG_USER_TWS_ENABLE
+ printf("----------------tws_api_get_tws_state %x\n", tws_api_get_tws_state());
+ int deal_state = tws_api_get_tws_state();
+ if (tws_api_get_role() == TWS_ROLE_MASTER && deal_state & TWS_STA_SIBLING_CONNECTED && deal_state & TWS_STA_PHONE_CONNECTED && !(deal_state & TWS_STA_MONITOR_START)) {
+ if (ldo5v_in_reset_timer == 0) {
+ delay_timeout = 30;
+ ldo5v_in_reset_timer = sys_timer_add(NULL, ldo5v_in_reset_delay, 100);
+ }
+ } else {
+ if (ldo5v_in_reset_timer) {
+ sys_timer_del(ldo5v_in_reset_timer);
+ ldo5v_in_reset_timer = 0;
+ }
+ sys_enter_soft_poweroff((void *)1);
+ }
+#else
+ sys_enter_soft_poweroff((void *)1);
+#endif
+#if (TCFG_CHARGESTORE_ENABLE && TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV)
+ } else {
+ log_info("chargestore do poweroff!\n");
+ }
+#endif
+ } else {
+ charge_start();
+ wdt_init(WDT_32S);
+ log_info("set wdt to 32s!\n");
+ goto _check_reset;
+ }
+ } else {
+ charge_start();
+ goto _check_reset;
+ }
+ return;
+
+_check_reset:
+ //防止耳机低电时,插拔充电有几率出现关机不充电问题
+ if (app_var.goto_poweroff_flag) {
+ cpu_reset();
+ }
+}
+
+#if TCFG_EARTCH_EVENT_HANDLE_ENABLE
+static u8 _enter_softoff_flag = 0;
+extern lp_touch_key_testbox_inear_trim(u8 flag);
+void exit_lp_touch_eartch_trim(void *priv)
+{
+ log_info("<<<<<<<<<< exit_lp_touch_eartch_trim!\n");
+ lp_touch_key_testbox_inear_trim(0);
+#if TCFG_PWMLED_ENABLE
+ gpio_set_direction(TCFG_PWMLED_PIN, 1);
+#endif
+ if (_enter_softoff_flag) {
+ log_info("<<<<<<<<<<< sys_enter_soft_poweroff after eartch_trim!\n");
+ sys_enter_soft_poweroff(NULL);
+ } else {
+ cpu_reset();
+ }
+}
+void enter_lp_touch_eartch_trim(void *priv)
+{
+ log_info(">>>>>>>>>> enter_lp_touch_eartch_trim!\n");
+ lp_touch_key_testbox_inear_trim(1);
+ sys_timeout_add(NULL, exit_lp_touch_eartch_trim, 1000);
+}
+#endif
+
+//外置触摸断电
+void __attribute__((weak)) external_touch_key_disable(void)
+{
+
+}
+//使能外置电源控制芯片对耳机进行断电
+void __attribute__((weak)) external_storage_io_disable(void)
+{
+
+}
+//关闭vddio keep
+u8 __attribute__((weak)) power_set_vddio_keep(u8 en)
+{
+
+}
+void charge_ldo5v_off_deal(void)
+{
+ log_info("%s\n", __FUNCTION__);
+
+ //拨出交换
+ power_event_to_user(POWER_EVENT_POWER_CHANGE);
+#if (TCFG_CHARGESTORE_ENABLE && TCFG_USER_TWS_ENABLE)
+ if (TWS_ROLE_SLAVE == tws_api_get_role()) {
+ chargestore_set_power_level(0xFF);
+ }
+#endif
+ charge_full_flag = 0;
+
+ charge_close();
+
+ struct application *app;
+ app = get_current_app();
+ //在idle的时候才执行充电拔出的UI
+ if (app && (!strcmp(app->name, APP_NAME_IDLE))) {
+ ui_update_status(STATUS_CHARGE_LDO5V_OFF);
+ }
+
+ charge_check_and_set_pinr(1);
+
+#if TCFG_TEST_BOX_ENABLE
+
+#if TCFG_EARTCH_EVENT_HANDLE_ENABLE
+ u8 sec = 0;
+ u8 eartch_trim_en = testbox_get_touch_trim_en(&sec);
+ if (eartch_trim_en) {
+ log_info("******* testbox_get_touch_trim_en : %ds\n", sec);
+ sys_timeout_add(NULL, enter_lp_touch_eartch_trim, sec * 1000);
+#if TCFG_PWMLED_ENABLE
+ gpio_set_pull_up(TCFG_PWMLED_PIN, 0);
+ gpio_set_pull_down(TCFG_PWMLED_PIN, 0);
+ gpio_set_die(TCFG_PWMLED_PIN, 0);
+ gpio_set_direction(TCFG_PWMLED_PIN, 0);
+ gpio_write(TCFG_PWMLED_PIN, 1);
+#endif
+ }
+#endif
+
+ if (testbox_get_status() && !get_total_connect_dev()) {
+ if (!testbox_get_keep_tws_conn_flag()) {
+ log_info("<<<<<<<<<<<<<>>>>>>>>>>>>>>\n");
+ if (testbox_get_testbox_tws_paired() && testbox_get_softpwroff_after_paired()) {
+#if TCFG_EARTCH_EVENT_HANDLE_ENABLE
+ if (eartch_trim_en) {
+ _enter_softoff_flag = 1;
+ } else
+#endif
+ {
+ sys_enter_soft_poweroff(NULL);
+ }
+ } else {
+#if TCFG_EARTCH_EVENT_HANDLE_ENABLE
+ if (eartch_trim_en) {
+ } else
+#endif
+ {
+ cpu_reset();
+ }
+ }
+ } else {
+ log_info("testbox out ret\n");
+ }
+ }
+ testbox_clear_status();
+ if (ldo5v_keep_timer) {
+ sys_timeout_del(ldo5v_keep_timer);
+ ldo5v_keep_timer = 0;
+ }
+#endif
+
+#if TCFG_CHARGESTORE_ENABLE
+ chargestore_shutdown_reset();
+#endif
+
+#if TCFG_AUDIO_ANC_ENABLE
+#if TCFG_ANC_BOX_ENABLE
+ if (ldo5v_keep_timer) {
+ sys_timeout_del(ldo5v_keep_timer);
+ ldo5v_keep_timer = 0;
+ }
+ if (ancbox_get_status()) {
+ return;
+ } else
+#endif
+ {
+ anc_resume();
+ }
+#endif
+
+#if TCFG_TEST_BOX_ENABLE
+ if (testbox_get_ex_enter_storage_mode_flag()) {
+ power_set_vddio_keep(0);//关VDDIO KEEP
+#if TCFG_LP_TOUCH_KEY_ENABLE
+ lp_touch_key_disable();//仓储模式关内置触摸
+#else
+ external_touch_key_disable(); //仓储模式关外置触摸供电
+#endif /* #if TCFG_LP_TOUCH_KEY_ENABLE */
+#if TCFG_EXTERN_STORAGE_MODE_ENABLE
+ external_storage_io_disable();
+#endif/* TCFG_EXTERN_STORAGE_MODE_ENABLE */
+ power_set_soft_poweroff();
+ }
+#endif
+
+
+ if ((get_charge_poweron_en() == 0)) {
+
+ wdt_init(WDT_4S);
+ log_info("set wdt to 4s!\n");
+#if TCFG_CHARGESTORE_ENABLE
+ if (chargestore_get_power_status()) {
+#endif
+#if TCFG_CHARGE_OFF_POWERON_NE
+ log_info("ldo5v off,task switch to BT\n");
+ app_var.play_poweron_tone = 0;
+#if TCFG_SYS_LVD_EN
+ vbat_check_init();
+#endif
+ if (app && (app_var.goto_poweroff_flag == 0)) {
+ if (strcmp(app->name, APP_NAME_BT)) {
+#if TCFG_SYS_LVD_EN
+ if (get_vbat_need_shutdown() == FALSE) {
+#if TCFG_WIRELESS_MIC_ENABLE
+ cpu_reset();
+#endif
+ task_switch_to_bt();
+ } else {
+ log_info("ldo5v off,lowpower,need enter softpoweroff\n");
+ power_set_soft_poweroff();
+ }
+#else
+ task_switch_to_bt();
+#endif
+ }
+ }
+#else //TCFG_CHARGE_OFF_POWERON_NE
+ log_info("ldo5v off,enter softpoweroff\n");
+#if TCFG_LP_TOUCH_KEY_ENABLE
+ extern void lp_touch_key_charge_mode_exit();
+ lp_touch_key_charge_mode_exit();
+#endif /* #if TCFG_LP_TOUCH_KEY_ENABLE */
+ power_set_soft_poweroff();
+#endif //TCFG_CHARGE_OFF_POWERON_NE
+#if TCFG_CHARGESTORE_ENABLE
+ } else {
+ log_info("ldo5v off,enter softpoweroff\n");
+ if (app && (!strcmp(app->name, APP_NAME_BT))) { //软关机
+ sys_enter_soft_poweroff(NULL);
+ } else {
+ power_set_soft_poweroff();
+ }
+ }
+#endif
+ } else {
+ if (app && (!strcmp(app->name, APP_NAME_IDLE)) && (app_var.goto_poweroff_flag == 0)) {
+#if TCFG_CHARGE_OFF_POWERON_NE
+ log_info("ldo5v off,task switch to BT\n");
+ app_var.play_poweron_tone = 0;
+#if TCFG_SYS_LVD_EN
+ vbat_check_init();
+#endif
+#if TCFG_SYS_LVD_EN
+ if (get_vbat_need_shutdown() == FALSE) {
+ task_switch_to_bt();
+ } else {
+ log_info("ldo5v off,lowpower,need enter softpoweroff\n");
+ power_set_soft_poweroff();
+ }
+#else
+ task_switch_to_bt();
+#endif
+#else
+ power_set_soft_poweroff();
+#endif
+ }
+ }
+#if TCFG_GSENSOR_ENABLE
+ //出舱使能gSensor
+ gSensor_wkupup_enable();
+#endif
+
+#if TCFG_LINEIN_ENABLE
+ //出舱开启linein检测
+ linein_det_enable();
+#endif
+
+#if TCFG_LP_TOUCH_KEY_ENABLE
+ extern void lp_touch_key_charge_mode_exit();
+ lp_touch_key_charge_mode_exit();
+#endif /* #if TCFG_LP_TOUCH_KEY_ENABLE */
+
+#if TCFG_TEST_BOX_ENABLE
+ if (testbox_get_ex_enter_storage_mode_flag()) {
+ power_set_vddio_keep(0);//关VDDIO KEEP
+#if TCFG_LP_TOUCH_KEY_ENABLE
+ lp_touch_key_disable();//仓储模式关内置触摸
+#else
+ external_touch_key_disable(); //仓储模式关外置触摸供电
+#endif /* #if TCFG_LP_TOUCH_KEY_ENABLE */
+ //测试盒仓储模式使能后,断开测试盒直接关机
+ power_set_soft_poweroff();
+ }
+#endif
+
+#if TCFG_GX8002_NPU_ENABLE
+ extern void gx8002_module_resumed();
+ gx8002_module_resumed();
+#endif /* #if TCFG_GX8002_NPU_ENABLE */
+}
+
+int app_charge_event_handler(struct device_event *dev)
+{
+ int ret = false;
+ u8 otg_status = 0;
+
+ switch (dev->event) {
+ case CHARGE_EVENT_CHARGE_START:
+#if NTC_DET_EN
+ ntc_det_start();
+#endif
+ charge_start_deal();
+ break;
+ case CHARGE_EVENT_CHARGE_CLOSE:
+#if NTC_DET_EN
+ ntc_det_stop();
+#endif
+ charge_close_deal();
+ break;
+ case CHARGE_EVENT_CHARGE_FULL:
+ charge_full_deal();
+ break;
+ case CHARGE_EVENT_LDO5V_KEEP:
+#if NTC_DET_EN
+ ntc_det_stop();
+#endif
+ ldo5v_keep_deal();
+ break;
+ case CHARGE_EVENT_LDO5V_IN:
+#if ((TCFG_OTG_MODE & OTG_SLAVE_MODE) && (TCFG_OTG_MODE & OTG_CHARGE_MODE))
+ while (1) {
+ otg_status = usb_otg_online(0);
+ if (otg_status != IDLE_MODE) {
+ break;
+ }
+ os_time_dly(2);
+ }
+ if (otg_status == SLAVE_MODE) {
+ set_charge_poweron_en(1);
+ }
+#endif
+
+ if (get_charge_poweron_en() || (otg_status != SLAVE_MODE)) {
+ charge_ldo5v_in_deal();
+ }
+ break;
+ case CHARGE_EVENT_LDO5V_OFF:
+#if ((TCFG_OTG_MODE & OTG_SLAVE_MODE) && (TCFG_OTG_MODE & OTG_CHARGE_MODE))
+ while (1) {
+ otg_status = usb_otg_online(0);
+ if (otg_status != IDLE_MODE) {
+ break;
+ }
+ os_time_dly(2);
+ }
+#endif
+ if (get_charge_poweron_en() || (otg_status != SLAVE_MODE)) {
+ charge_ldo5v_off_deal();
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+#else
+
+u8 get_charge_full_flag(void)
+{
+ return 0;
+}
+
+#endif
+
diff --git a/apps/earphone/power_manage/app_power_manage.c b/apps/earphone/power_manage/app_power_manage.c
new file mode 100644
index 0000000..7aef482
--- /dev/null
+++ b/apps/earphone/power_manage/app_power_manage.c
@@ -0,0 +1,475 @@
+#include "system/includes.h"
+#include "app_power_manage.h"
+#include "app_main.h"
+#include "app_config.h"
+#include "app_action.h"
+#include "asm/charge.h"
+#include "ui_manage.h"
+#include "tone_player.h"
+#include "asm/adc_api.h"
+#include "btstack/avctp_user.h"
+#include "user_cfg.h"
+#include "asm/charge.h"
+
+#if TCFG_USER_TWS_ENABLE
+#include "bt_tws.h"
+#endif
+
+#define LOG_TAG_CONST APP_POWER
+#define LOG_TAG "[APP_POWER]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+enum {
+ VBAT_NORMAL = 0,
+ VBAT_WARNING,
+ VBAT_LOWPOWER,
+} VBAT_STATUS;
+
+#define VBAT_DETECT_CNT 6
+static int vbat_slow_timer = 0;
+static int vbat_fast_timer = 0;
+static int lowpower_timer = 0;
+static u8 old_battery_level = 9;
+static u16 bat_val = 0;
+static volatile u8 cur_battery_level = 0;
+static u16 battery_full_value = 0;
+static u8 tws_sibling_bat_level = 0xff;
+static u8 tws_sibling_bat_percent_level = 0xff;
+static u8 cur_bat_st = VBAT_NORMAL;
+
+void vbat_check(void *priv);
+void sys_enter_soft_poweroff(void *priv);
+void clr_wdt(void);
+void power_event_to_user(u8 event);
+
+
+u8 get_tws_sibling_bat_level(void)
+{
+#if TCFG_USER_TWS_ENABLE
+ /* log_info("***********get_tws_sibling_bat_level: %2x", tws_sibling_bat_percent_level); */
+ return tws_sibling_bat_level & 0x7f;
+#endif
+ return 0xff;
+}
+
+u8 get_tws_sibling_bat_persent(void)
+{
+#if TCFG_USER_TWS_ENABLE
+ /* log_info("***********get_tws_sibling_bat_level: %2x", tws_sibling_bat_percent_level); */
+ return tws_sibling_bat_percent_level;
+#endif
+ return 0xff;
+}
+
+void app_power_set_tws_sibling_bat_level(u8 vbat, u8 percent)
+{
+#if TCFG_USER_TWS_ENABLE
+ tws_sibling_bat_level = vbat;
+ tws_sibling_bat_percent_level = percent;
+ /*
+ ** 发出电量同步事件进行进一步处理
+ **/
+ power_event_to_user(POWER_EVENT_SYNC_TWS_VBAT_LEVEL);
+
+ log_info("set_sibling_bat_level: %d, %d\n", vbat, percent);
+#endif
+}
+
+
+static void set_tws_sibling_bat_level(void *_data, u16 len, bool rx)
+{
+ u8 *data = (u8 *)_data;
+
+ if (rx) {
+ app_power_set_tws_sibling_bat_level(data[0], data[1]);
+ }
+}
+
+#if TCFG_USER_TWS_ENABLE
+REGISTER_TWS_FUNC_STUB(vbat_sync_stub) = {
+ .func_id = TWS_FUNC_ID_VBAT_SYNC,
+ .func = set_tws_sibling_bat_level,
+};
+#endif
+
+void tws_sync_bat_level(void)
+{
+#if (TCFG_USER_TWS_ENABLE && BT_SUPPORT_DISPLAY_BAT)
+ u8 battery_level = cur_battery_level;
+#if CONFIG_DISPLAY_DETAIL_BAT
+ u8 percent_level = get_vbat_percent();
+#else
+ u8 percent_level = get_self_battery_level() * 10 + 10;
+#endif
+ if (get_charge_online_flag()) {
+ percent_level |= BIT(7);
+ }
+
+ u8 data[2];
+ data[0] = battery_level;
+ data[1] = percent_level;
+ tws_api_send_data_to_sibling(data, 2, TWS_FUNC_ID_VBAT_SYNC);
+
+ log_info("tws_sync_bat_level: %d,%d\n", battery_level, percent_level);
+#endif
+}
+
+void power_event_to_user(u8 event)
+{
+ struct sys_event e;
+ e.type = SYS_DEVICE_EVENT;
+ e.arg = (void *)DEVICE_EVENT_FROM_POWER;
+ e.u.dev.event = event;
+ e.u.dev.value = 0;
+ sys_event_notify(&e);
+}
+
+int app_power_event_handler(struct device_event *dev)
+{
+ int ret = false;
+
+#if(TCFG_SYS_LVD_EN == 1)
+ switch (dev->event) {
+ case POWER_EVENT_POWER_NORMAL:
+ ui_update_status(STATUS_EXIT_LOWPOWER);
+ break;
+ case POWER_EVENT_POWER_WARNING:
+ ui_update_status(STATUS_LOWPOWER);
+ /* tone_play(TONE_LOW_POWER); */
+ STATUS *p_tone = get_tone_config();
+ tone_play_index(p_tone->lowpower, 0);
+ if (lowpower_timer == 0) {
+ lowpower_timer = sys_timer_add((void *)POWER_EVENT_POWER_WARNING, (void (*)(void *))power_event_to_user, LOW_POWER_WARN_TIME);
+ }
+ break;
+ case POWER_EVENT_POWER_LOW:
+ printf(" POWER_EVENT_POWER_LOW");
+ vbat_timer_delete();
+ if (lowpower_timer) {
+ sys_timer_del(lowpower_timer);
+ lowpower_timer = 0 ;
+ }
+#if TCFG_APP_BT_EN
+#if (RCSP_ADV_EN)
+ extern u8 adv_tws_both_in_charge_box(u8 type);
+ adv_tws_both_in_charge_box(1);
+#endif
+ sys_enter_soft_poweroff(NULL);
+#else
+ void app_entry_idle() ;
+ app_entry_idle() ;
+#endif
+ break;
+#if TCFG_APP_BT_EN
+#if TCFG_USER_TWS_ENABLE
+ case POWER_EVENT_SYNC_TWS_VBAT_LEVEL:
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ user_send_cmd_prepare(USER_CTRL_HFP_CMD_UPDATE_BATTARY, 0, NULL);
+ }
+ break;
+#endif
+
+ case POWER_EVENT_POWER_CHANGE:
+ /* log_info("POWER_EVENT_POWER_CHANGE\n"); */
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
+ if (tws_api_get_tws_state()&TWS_STA_ESCO_OPEN) {
+ break;
+ }
+ tws_sync_bat_level();
+ }
+#endif
+ user_send_cmd_prepare(USER_CTRL_HFP_CMD_UPDATE_BATTARY, 0, NULL);
+#endif
+ break;
+ case POWER_EVENT_POWER_CHARGE:
+ if (lowpower_timer) {
+ sys_timer_del(lowpower_timer);
+ lowpower_timer = 0 ;
+ }
+ break;
+ default:
+ break;
+ }
+#endif
+
+ return ret;
+}
+
+
+u16 get_vbat_level(void)
+{
+ //return 370; //debug
+ return (adc_get_voltage(AD_CH_VBAT) * 4/* / 10*/);
+}
+
+__attribute__((weak)) u8 remap_calculate_vbat_percent(u16 bat_val)
+{
+ return 0;
+}
+
+u16 get_vbat_value(void)
+{
+ return bat_val;
+}
+
+u8 get_vbat_percent(void)
+{
+ u16 tmp_bat_val;
+ u16 bat_val = get_vbat_level();
+ if (battery_full_value == 0) {
+#if TCFG_CHARGE_ENABLE
+ battery_full_value = (get_charge_full_value() - 100) / 10; //防止部分电池充不了这么高电量,充满显示未满的情况
+#else
+ battery_full_value = 420;
+#endif
+ }
+
+ if (bat_val <= app_var.poweroff_tone_v) {
+ return 0;
+ }
+
+ tmp_bat_val = remap_calculate_vbat_percent(bat_val);
+ if (!tmp_bat_val) {
+ tmp_bat_val = ((u32)bat_val - app_var.poweroff_tone_v) * 100 / (battery_full_value - app_var.poweroff_tone_v);
+ if (tmp_bat_val > 100) {
+ tmp_bat_val = 100;
+ }
+ }
+ return (u8)tmp_bat_val;
+}
+
+bool get_vbat_need_shutdown(void)
+{
+ if ((bat_val <= LOW_POWER_SHUTDOWN) || adc_check_vbat_lowpower()) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+//将当前电量转换为1~9级发送给手机同步电量
+u8 battery_value_to_phone_level(u16 bat_val)
+{
+ u8 battery_level = 0;
+ u8 vbat_percent = get_vbat_percent();
+
+ if (vbat_percent < 5) { //小于5%电量等级为0,显示10%
+ return 0;
+ }
+
+ battery_level = (vbat_percent - 5) / 10;
+
+ return battery_level;
+}
+
+//获取自身的电量
+u8 get_self_battery_level(void)
+{
+ return cur_battery_level;
+}
+
+u8 get_cur_battery_level(void)
+{
+ u8 bat_lev = tws_sibling_bat_level & (~BIT(7));
+#if TCFG_USER_TWS_ENABLE
+ if (bat_lev == 0x7f) {
+ return cur_battery_level;
+ }
+
+#if (CONFIG_DISPLAY_TWS_BAT_TYPE == CONFIG_DISPLAY_TWS_BAT_LOWER)
+ return cur_battery_level < bat_lev ? cur_battery_level : bat_lev;
+#elif (CONFIG_DISPLAY_TWS_BAT_TYPE == CONFIG_DISPLAY_TWS_BAT_HIGHER)
+ return cur_battery_level < bat_lev ? bat_lev : cur_battery_level;
+#elif (CONFIG_DISPLAY_TWS_BAT_TYPE == CONFIG_DISPLAY_TWS_BAT_LEFT)
+ return tws_api_get_local_channel() == 'L' ? cur_battery_level : bat_lev;
+#elif (CONFIG_DISPLAY_TWS_BAT_TYPE == CONFIG_DISPLAY_TWS_BAT_RIGHT)
+ return tws_api_get_local_channel() == 'R' ? cur_battery_level : bat_lev;
+#else
+ return cur_battery_level;
+#endif //END CONFIG_DISPLAY_TWS_BAT_TYPE
+
+#else //TCFG_USER_TWS_ENABLE == 0
+ return cur_battery_level;
+#endif
+}
+
+void vbat_check_slow(void *priv)
+{
+ if (vbat_fast_timer == 0) {
+ vbat_fast_timer = usr_timer_add(NULL, vbat_check, 10, 1);
+ }
+ if (get_charge_online_flag()) {
+ sys_timer_modify(vbat_slow_timer, 60 * 1000);
+ } else {
+ sys_timer_modify(vbat_slow_timer, 10 * 1000);
+ }
+}
+
+void vbat_check_init(void)
+{
+ if (vbat_slow_timer == 0) {
+ vbat_slow_timer = sys_timer_add(NULL, vbat_check_slow, 10 * 1000);
+ } else {
+ sys_timer_modify(vbat_slow_timer, 10 * 1000);
+ }
+
+ if (vbat_fast_timer == 0) {
+ vbat_fast_timer = usr_timer_add(NULL, vbat_check, 10, 1);
+ }
+}
+
+void vbat_timer_delete(void)
+{
+ if (vbat_slow_timer) {
+ sys_timer_del(vbat_slow_timer);
+ vbat_slow_timer = 0;
+ }
+ if (vbat_fast_timer) {
+ usr_timer_del(vbat_fast_timer);
+ vbat_fast_timer = 0;
+ }
+}
+
+void vbat_check(void *priv)
+{
+ static u8 unit_cnt = 0;
+ static u8 low_warn_cnt = 0;
+ static u8 low_off_cnt = 0;
+ static u8 low_voice_cnt = 0;
+ static u8 low_power_cnt = 0;
+ static u8 power_normal_cnt = 0;
+ static u8 charge_online_flag = 0;
+ static u8 low_voice_first_flag = 1;//进入低电后先提醒一次
+
+ if (!bat_val) {
+ bat_val = get_vbat_level();
+ } else {
+ bat_val = (get_vbat_level() + bat_val) / 2;
+ }
+
+ cur_battery_level = battery_value_to_phone_level(bat_val);
+
+ /* printf("bv:%d, bl:%d , check_vbat:%d\n", bat_val, cur_battery_level, adc_check_vbat_lowpower()); */
+
+ unit_cnt++;
+
+ /* if (bat_val < LOW_POWER_OFF_VAL) { */
+ if (adc_check_vbat_lowpower() || (bat_val <= app_var.poweroff_tone_v)) {
+ low_off_cnt++;
+ }
+ /* if (bat_val < LOW_POWER_WARN_VAL) { */
+ if (bat_val <= app_var.warning_tone_v) {
+ low_warn_cnt++;
+ }
+
+ /* log_info("unit_cnt:%d\n", unit_cnt); */
+
+ if (unit_cnt >= VBAT_DETECT_CNT) {
+
+ if (get_charge_online_flag() == 0) {
+ if (low_off_cnt > (VBAT_DETECT_CNT / 2)) { //低电关机
+ low_power_cnt++;
+ low_voice_cnt = 0;
+ power_normal_cnt = 0;
+ cur_bat_st = VBAT_LOWPOWER;
+ if (low_power_cnt > 6) {
+ log_info("\n*******Low Power,enter softpoweroff********\n");
+ low_power_cnt = 0;
+ power_event_to_user(POWER_EVENT_POWER_LOW);
+ usr_timer_del(vbat_fast_timer);
+ vbat_fast_timer = 0;
+ }
+ } else if (low_warn_cnt > (VBAT_DETECT_CNT / 2)) { //低电提醒
+ low_voice_cnt ++;
+ low_power_cnt = 0;
+ power_normal_cnt = 0;
+ cur_bat_st = VBAT_WARNING;
+ if ((low_voice_first_flag && low_voice_cnt > 1) || //第一次进低电10s后报一次
+ (!low_voice_first_flag && low_voice_cnt >= 5)) {
+ low_voice_first_flag = 0;
+ low_voice_cnt = 0;
+ if (!lowpower_timer) {
+ log_info("\n**Low Power,Please Charge Soon!!!**\n");
+ power_event_to_user(POWER_EVENT_POWER_WARNING);
+ }
+ }
+ } else {
+ power_normal_cnt++;
+ low_voice_cnt = 0;
+ low_power_cnt = 0;
+ if (power_normal_cnt > 2) {
+ if (cur_bat_st != VBAT_NORMAL) {
+ log_info("[Noraml power]\n");
+ cur_bat_st = VBAT_NORMAL;
+ power_event_to_user(POWER_EVENT_POWER_NORMAL);
+ }
+ }
+ }
+ } else {
+ power_event_to_user(POWER_EVENT_POWER_CHARGE);
+ }
+
+ unit_cnt = 0;
+ low_off_cnt = 0;
+ low_warn_cnt = 0;
+
+ if (cur_bat_st != VBAT_LOWPOWER) {
+ usr_timer_del(vbat_fast_timer);
+ vbat_fast_timer = 0;
+ cur_battery_level = battery_value_to_phone_level(bat_val);
+ if (cur_battery_level != old_battery_level) {
+ power_event_to_user(POWER_EVENT_POWER_CHANGE);
+ } else {
+ if (charge_online_flag != get_charge_online_flag()) {
+ //充电变化也要交换,确定是否在充电仓
+ power_event_to_user(POWER_EVENT_POWER_CHANGE);
+ }
+ }
+ charge_online_flag = get_charge_online_flag();
+ old_battery_level = cur_battery_level;
+ }
+ }
+}
+
+bool vbat_is_low_power(void)
+{
+ return (cur_bat_st != VBAT_NORMAL);
+}
+
+void check_power_on_voltage(void)
+{
+#if(TCFG_SYS_LVD_EN == 1)
+
+ u16 val = 0;
+ u8 normal_power_cnt = 0;
+ u8 low_power_cnt = 0;
+
+ while (1) {
+ clr_wdt();
+ val = get_vbat_level();
+ printf("vbat: %d\n", val);
+ if ((val < app_var.poweroff_tone_v) || adc_check_vbat_lowpower()) {
+ low_power_cnt++;
+ normal_power_cnt = 0;
+ if (low_power_cnt > 10) {
+ ui_update_status(STATUS_POWERON_LOWPOWER);
+ os_time_dly(100);
+ log_info("power on low power , enter softpoweroff!\n");
+ power_set_soft_poweroff();
+ }
+ } else {
+ normal_power_cnt++;
+ low_power_cnt = 0;
+ if (normal_power_cnt > 10) {
+ vbat_check_init();
+ return;
+ }
+ }
+ }
+#endif
+}
diff --git a/apps/earphone/rcsp/jl_phone_app.c b/apps/earphone/rcsp/jl_phone_app.c
new file mode 100644
index 0000000..384ce47
--- /dev/null
+++ b/apps/earphone/rcsp/jl_phone_app.c
@@ -0,0 +1,15 @@
+
+#include "app_config.h"
+#include "btstack/avctp_user.h"
+#include "adv_music_info_setting.h"
+
+#if (JL_EARPHONE_APP_EN)
+
+int jl_phone_app_init()
+{
+#if RCSP_ADV_MUSIC_INFO_ENABLE
+ bt_music_info_handle_register(rcsp_adv_music_info_deal);
+#endif
+ return 0;
+}
+#endif
diff --git a/apps/earphone/rcsp/rcsp_adv.c b/apps/earphone/rcsp/rcsp_adv.c
new file mode 100644
index 0000000..23c3630
--- /dev/null
+++ b/apps/earphone/rcsp/rcsp_adv.c
@@ -0,0 +1,481 @@
+#include "app_config.h"
+
+#if RCSP_ADV_EN
+
+#include "earphone.h"
+#include "app_main.h"
+#include "le_rcsp_adv_module.h"
+#include "rcsp_adv_bluetooth.h"
+#include "rcsp_bluetooth.h"
+#include "adv_mic_setting.h"
+#include "JL_rcsp_api.h"
+#include "update_tws.h"
+#include "update_tws_new.h"
+#include "3th_profile_api.h"
+#include "adv_time_stamp_setting.h"
+#include "adv_anc_voice.h"
+
+#include "btstack/avctp_user.h"
+#include "btstack/btstack_task.h"
+#include "bt_tws.h"
+
+#define LOG_TAG "[RCSP-ADV]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+extern APP_VAR app_var;
+extern void rcsp_spp_init();
+extern u8 get_app_connect_type(void);
+extern void ble_app_disconnect(void);
+extern u8 get_app_connect_type(void);
+extern void mic_data_sync_tx_deal(void);
+extern void set_ble_connect_type(u8 type);
+extern void bt_ble_adv_enable(u8 enable);
+extern void app_tws_get_data_from_sibling(u8 cmd, u8 *data, u8 len);
+extern u8 JL_get_cur_bt_channel_sel(void);
+extern void send_version_to_sibling(void);
+extern void set_rcsp_dev_type_spp(void);
+extern u8 rcsp_get_update_flag(void);
+
+u8 ble_adv_miss_flag = 0;
+u8 ble_adv_poweron_flag = 0;
+
+int rcsp_earphone_state_set_page_scan_enable()
+{
+#if (TCFG_USER_TWS_ENABLE == 0)
+ bt_ble_adv_ioctl(BT_ADV_SET_EDR_CON_FLAG, SECNE_UNCONNECTED, 1);
+#elif (CONFIG_NO_DISPLAY_BUTTON_ICON || !TCFG_CHARGESTORE_ENABLE)
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ printf("switch_icon_ctl11...\n");
+ bt_ble_adv_ioctl(BT_ADV_SET_EDR_CON_FLAG, SECNE_UNCONNECTED, 1);
+ }
+#endif
+ return 0;
+}
+
+int rcsp_earphone_state_get_connect_mac_addr()
+{
+ bt_ble_adv_ioctl(BT_ADV_SET_EDR_CON_FLAG, SECNE_CONNECTING, 1);
+ return 0;
+}
+
+int rcsp_earphone_state_cancel_page_scan()
+{
+#if (TCFG_USER_TWS_ENABLE == 0)
+ bt_ble_adv_ioctl(BT_ADV_SET_EDR_CON_FLAG, SECNE_UNCONNECTED, 1);
+#elif (CONFIG_NO_DISPLAY_BUTTON_ICON || !TCFG_CHARGESTORE_ENABLE)
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ if (ble_adv_miss_flag) {
+ ble_adv_miss_flag = 0;
+ puts("ble_adv_miss_flag...\n");
+ } else {
+ printf("switch_icon_ctl00...\n");
+ bt_ble_adv_ioctl(BT_ADV_SET_EDR_CON_FLAG, SECNE_UNCONNECTED, 1);
+ }
+ }
+#endif
+ return 0;
+}
+
+int rcsp_earphone_state_tws_init(int paired)
+{
+ ble_adv_poweron_flag = 1;
+
+ if (paired) {
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ bt_ble_adv_ioctl(BT_ADV_ENABLE, 0, 1);
+ } else {
+ //slave close
+ bt_ble_adv_ioctl(BT_ADV_DISABLE, 0, 1);
+ }
+ } else {
+#if 0 //disable
+ //no_pair_adv,last do
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ printf("switch_icon_ctl no_pair...\n");
+ bt_ble_set_control_en(1);
+ bt_ble_icon_open(ICON_TYPE_INQUIRY);
+ } else {
+ bt_ble_set_control_en(0);
+ }
+#endif
+ }
+ return 0;
+}
+
+int rcsp_earphone_state_tws_connected(int first_pair, u8 *comm_addr)
+{
+#if JL_EARPHONE_APP_EN
+#if RCSP_ADV_MUSIC_INFO_ENABLE
+ extern void stop_get_music_timer(u8 en) ;
+ stop_get_music_timer(0);
+#endif
+#endif
+
+ if (first_pair) {
+ extern void ble_module_enable(u8 en);
+ extern void bt_update_mac_addr(u8 * addr);
+ extern void lib_make_ble_address(u8 * ble_address, u8 * edr_address);
+ /* bt_ble_adv_enable(0); */
+ u8 tmp_ble_addr[6] = {0};
+ lib_make_ble_address(tmp_ble_addr, comm_addr);
+ le_controller_set_mac(tmp_ble_addr);//将ble广播地址改成公共地址
+ bt_update_mac_addr(comm_addr);
+ /* bt_ble_adv_enable(1); */
+
+
+ /*新的连接,公共地址改变了,要重新将新的地址广播出去*/
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ printf("\nNew Connect Master!!!\n\n");
+ ble_app_disconnect();
+ bt_ble_adv_enable(0);
+ bt_ble_adv_enable(1);
+ } else {
+ printf("\nConnect Slave!!!\n\n");
+ /*从机ble关掉*/
+ ble_app_disconnect();
+ bt_ble_adv_enable(0);
+ }
+ }
+
+ return 0;
+}
+
+int rcsp_earphone_state_enter_soft_poweroff()
+{
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ u8 adv_cmd = 0x3;
+ extern u8 adv_info_device_request(u8 * buf, u16 len);
+ extern u8 adv_tws_both_in_charge_box(u8 type);
+ if (adv_tws_both_in_charge_box(0)) {
+ adv_info_device_request(&adv_cmd, sizeof(adv_cmd));
+ }
+ }
+#endif
+ extern void bt_ble_exit(void);
+ bt_ble_exit();
+ return 0;
+}
+
+int rcsp_adv_bt_status_event_handler(struct bt_event *bt)
+{
+ switch (bt->event) {
+ case BT_STATUS_SECOND_CONNECTED:
+ case BT_STATUS_FIRST_CONNECTED:
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_role() == TWS_ROLE_MASTER || JL_get_cur_bt_channel_sel() == RCSP_SPP) {
+ bt_ble_adv_ioctl(BT_ADV_SET_EDR_CON_FLAG, SECNE_CONNECTED, 1);
+ } else {
+ //maybe slave already open
+ bt_ble_adv_ioctl(BT_ADV_DISABLE, 0, 1);
+ }
+#else
+ bt_ble_adv_ioctl(BT_ADV_SET_EDR_CON_FLAG, SECNE_CONNECTED, 1);
+#endif
+ break;
+ case BT_STATUS_FIRST_DISCONNECT:
+ case BT_STATUS_SECOND_DISCONNECT:
+ bt_adv_seq_change();
+ if (!app_var.goto_poweroff_flag) {
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_role() == TWS_ROLE_MASTER || JL_get_cur_bt_channel_sel() == RCSP_SPP) {
+ bt_ble_adv_ioctl(BT_ADV_SET_EDR_CON_FLAG, SECNE_UNCONNECTED, 1);
+ } else {
+ //maybe slave already open
+ bt_ble_adv_ioctl(BT_ADV_DISABLE, 0, 1);
+ }
+#else
+ bt_ble_adv_ioctl(BT_ADV_SET_EDR_CON_FLAG, SECNE_UNCONNECTED, 1);
+#endif
+ }
+ break;
+ case BT_STATUS_SCO_STATUS_CHANGE:
+#if TCFG_USER_TWS_ENABLE
+ if (bt->value != 0xff) {
+ rcsp_user_mic_fixed_deal(1);
+ } else {
+ rcsp_user_mic_fixed_deal(0);
+ }
+#endif
+ break;
+
+ case BT_STATUS_PHONE_INCOME:
+ case BT_STATUS_PHONE_OUT:
+ case BT_STATUS_PHONE_ACTIVE:
+ printf("BT_STATUS_PHONE_ACTIVE\n");
+#if RCSP_ADV_FIND_DEVICE_ENABLE
+ extern void send_find_device_stop(void);
+ send_find_device_stop();
+#endif
+ // 更新通话状态
+ extern void JL_bt_phone_state_update(void);
+ JL_bt_phone_state_update();
+ break;
+ case BT_STATUS_PHONE_HANGUP:
+ printf("BT_STATUS_PHONE_HANGUP\n");
+ // 更新通话状态
+ extern void JL_bt_phone_state_update(void);
+ JL_bt_phone_state_update();
+ break;
+ }
+
+ return 0;
+}
+
+
+int rcsp_adv_hci_event_handler(struct bt_event *bt)
+{
+ switch (bt->event) {
+ case HCI_EVENT_CONNECTION_COMPLETE:
+ switch (bt->value) {
+ case ERROR_CODE_PIN_OR_KEY_MISSING:
+#if (CONFIG_NO_DISPLAY_BUTTON_ICON && TCFG_CHARGESTORE_ENABLE)
+ //已取消配对了, 切换广播
+ bt_ble_adv_ioctl(BT_ADV_SET_EDR_CON_FLAG, SECNE_UNCONNECTED, 1);
+#endif
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+void rcsp_bt_tws_event_handler(struct bt_event *bt)
+{
+ int role = bt->args[0];
+ int phone_link_connection = bt->args[1];
+ int reason = bt->args[2];
+
+ switch (bt->event) {
+ case TWS_EVENT_CONNECTED:
+ //bt_ble_adv_enable(1);
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ //master enable
+ log_info("master do icon_open\n");
+ if (phone_link_connection) {
+ bt_ble_adv_ioctl(BT_ADV_SET_EDR_CON_FLAG, SECNE_CONNECTED, 1);
+ } else {
+#if (TCFG_CHARGESTORE_ENABLE && !CONFIG_NO_DISPLAY_BUTTON_ICON)
+ bt_ble_adv_ioctl(BT_ADV_SET_EDR_CON_FLAG, SECNE_CONNECTED, 1);
+#else
+ if (ble_adv_poweron_flag) { //上电标记
+ if (bt_user_priv_var.auto_connection_counter > 0) {
+ //有回连手机动作
+ /* g_printf("ICON_TYPE_RECONNECT"); */
+ bt_ble_adv_ioctl(BT_ADV_SET_EDR_CON_FLAG, SECNE_CONNECTING, 1);
+ //没按键配对的话,等回连成功的时候才显示电量。如果在这里显示,手机取消配对后耳机开机,会显示出按键的界面
+ } else {
+ //没有回连,设可连接
+ /* g_printf("ICON_TYPE_INQUIRY"); */
+ bt_ble_adv_ioctl(BT_ADV_SET_EDR_CON_FLAG, SECNE_UNCONNECTED, 1);
+ }
+
+ }
+#endif
+ }
+ } else {
+ //slave disable
+ printf("\nConnect Slave!!!\n\n");
+ /*从机ble关掉*/
+ ble_app_disconnect();
+ bt_ble_adv_enable(0);
+ }
+ send_version_to_sibling();
+ ble_adv_poweron_flag = 0;
+
+#if RCSP_ADV_ANC_VOICE
+ anc_voice_setting_sync();
+#endif
+
+ sync_setting_by_time_stamp();
+
+#if (RCSP_ADV_FIND_DEVICE_ENABLE && TCFG_USER_TWS_ENABLE)
+ extern void find_decice_tws_connect_handle(u8 flag, u8 * param);
+ find_decice_tws_connect_handle(0, NULL);
+#endif
+
+ break;
+ case TWS_EVENT_PHONE_LINK_DETACH:
+ /*
+ * 跟手机的链路LMP层已完全断开, 只有tws在连接状态才会收到此事件
+ */
+ if (reason == 0x0b) {
+ //CONNECTION ALREADY EXISTS
+ ble_adv_miss_flag = 1;
+ } else {
+ ble_adv_miss_flag = 0;
+ }
+ break;
+ case TWS_EVENT_CONNECTION_DETACH:
+ /*
+ * TWS连接断开
+ */
+ if (app_var.goto_poweroff_flag) {
+ break;
+ }
+ if (get_app_connect_type() == 0) {
+ printf("\ntws detach to open ble~~~\n\n");
+ bt_ble_adv_enable(1);
+ }
+ set_ble_connect_type(TYPE_NULL);
+
+ deal_adv_setting_gain_time_stamp();
+ break;
+ case TWS_EVENT_SYNC_FUN_CMD:
+#if JL_EARPHONE_APP_EN
+ if (reason == SYNC_CMD_APP_RESET_LED_UI) {
+#if RCSP_ADV_LED_SET_ENABLE
+ extern void update_led_setting_state(void);
+ update_led_setting_state();
+#endif
+ } else if (reason == SYNC_CMD_MUSIC_INFO) {
+#if RCSP_ADV_MUSIC_INFO_ENABLE
+ extern void get_music_info(void);
+ get_music_info();
+#endif
+ } else if (reason == SYNC_CMD_RCSP_AUTH_RES) {
+ extern void rcsp_tws_auth_sync_deal(void);
+ rcsp_tws_auth_sync_deal();
+ } else if (reason == SYNC_CMD_MUSIC_PLAYER_STATE) {
+#if RCSP_ADV_MUSIC_INFO_ENABLE
+ void rcsp_update_player_state(void);
+ rcsp_update_player_state();
+#endif
+ } else if (reason == SYNC_CMD_MUSIC_PLAYER_TIEM_EN) {
+#if RCSP_ADV_MUSIC_INFO_ENABLE
+ extern void reset_player_time_en(void);
+ reset_player_time_en();
+#endif
+ }
+#endif
+ break;
+ case TWS_EVENT_ROLE_SWITCH:
+ if (role == TWS_ROLE_MASTER) { // 切换后触发
+#if JL_EARPHONE_APP_EN
+#if RCSP_ADV_LED_SET_ENABLE
+ extern void update_led_setting_state(void);
+ update_led_setting_state();
+#endif
+#endif
+ }
+ {
+ extern void adv_role_switch_handle(void);
+ adv_role_switch_handle();
+ }
+ break;
+ }
+
+#if OTA_TWS_SAME_TIME_ENABLE
+ tws_ota_app_event_deal(bt->event);
+#endif
+}
+
+int rcsp_sys_event_handler_specific(struct sys_event *event)
+{
+ switch (event->type) {
+ case SYS_BT_EVENT:
+ if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) {
+ rcsp_adv_bt_status_event_handler(&event->u.bt);
+ } else if ((u32)event->arg == SYS_BT_EVENT_TYPE_HCI_STATUS) {
+ rcsp_adv_hci_event_handler(&event->u.bt);
+ }
+#if TCFG_USER_TWS_ENABLE
+ else if (((u32)event->arg == SYS_BT_EVENT_FROM_TWS)) {
+ rcsp_bt_tws_event_handler(&event->u.bt);
+ }
+#endif
+#if 1//OTA_TWS_SAME_TIME_ENABLE
+ else if (((u32)event->arg == SYS_BT_OTA_EVENT_TYPE_STATUS)) {
+ bt_ota_event_handler(&event->u.bt);
+ }
+#endif
+ break;
+ case SYS_DEVICE_EVENT:
+ if ((u32)event->arg == DEVICE_EVENT_FROM_RCSP) {
+ int JL_rcsp_event_handler(struct rcsp_event * rcsp);
+ JL_rcsp_event_handler(&event->u.rcsp);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+
+
+int user_spp_state_specific(u8 packet_type)
+{
+ u8 tws_need_update = 0;
+
+ switch (packet_type) {
+ case 1:
+ ble_app_disconnect();
+ bt_ble_adv_enable(0);
+// set_app_connect_type(TYPE_SPP);
+#if (0 == BT_CONNECTION_VERIFY)
+ JL_rcsp_auth_reset();
+#endif
+
+ set_rcsp_dev_type_spp();
+ set_connect_flag(2);
+ bt_ble_adv_ioctl(BT_ADV_SET_NOTIFY_EN, 1, 1);
+ break;
+ case 2:
+
+// set_app_connect_type(TYPE_NULL);
+
+#if TCFG_USER_TWS_ENABLE
+ if (syscfg_read(VM_UPDATE_FLAG, &tws_need_update, sizeof(tws_need_update)) == 1) {
+ printf("packet_type:%d need:%d\n", packet_type, tws_need_update);
+ if (tws_need_update) { //这里直接return防止升级过程从机断开SPP之后又开广播然后被主机误连
+ return 0;
+ }
+ }
+ if (!(tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED)) {
+ if (!rcsp_get_update_flag()) {
+ ble_module_enable(1);
+ }
+ } else {
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ if (!rcsp_get_update_flag()) {
+ ble_module_enable(1);
+ }
+ }
+ }
+#else
+ ble_module_enable(1);
+#endif
+
+#if (0 == BT_CONNECTION_VERIFY)
+ JL_rcsp_auth_reset();
+#endif
+ break;
+ }
+ return 0;
+}
+
+
+int rcsp_earphone_state_init()
+{
+// rcsp_spp_init();
+ rcsp_init();
+ spp_data_deal_handle_register(user_spp_data_handler);
+
+#if JL_EARPHONE_APP_EN
+ extern int jl_phone_app_init();
+ jl_phone_app_init();
+#endif
+ return 0;
+}
+
+
+
+
+
+#endif
diff --git a/apps/earphone/sdk_version.z.S b/apps/earphone/sdk_version.z.S
new file mode 100644
index 0000000..b7afe5a
--- /dev/null
+++ b/apps/earphone/sdk_version.z.S
@@ -0,0 +1,4 @@
+.section .sys.version, "ax"
+
+.long 254991771
+.asciz "JL701N_V1.6.1-@20240130-$8f8f3995"
diff --git a/apps/earphone/tone_table.c b/apps/earphone/tone_table.c
new file mode 100644
index 0000000..f6698d7
--- /dev/null
+++ b/apps/earphone/tone_table.c
@@ -0,0 +1,223 @@
+#include "tone_player.h"
+#include "system/includes.h"
+
+
+#ifdef CONFIG_MEDIA_NEW_ENABLE
+
+
+
+static const char *const tone_index[] = {
+ TONE_NUM_0,
+ TONE_NUM_1,
+ TONE_NUM_2,
+ TONE_NUM_3,
+ TONE_NUM_4,
+ TONE_NUM_5,
+ TONE_NUM_6,
+ TONE_NUM_7,
+ TONE_NUM_8,
+ TONE_NUM_9,
+ TONE_BT_MODE,
+ TONE_BT_CONN,
+ TONE_BT_DISCONN,
+ TONE_TWS_CONN,
+ TONE_TWS_DISCONN,
+ TONE_LOW_POWER,
+ TONE_POWER_OFF,
+ TONE_POWER_ON,
+ TONE_RING,
+ TONE_MAX_VOL,
+ TONE_NORMAL,
+ TONE_ANC_OFF,
+ TONE_ANC_ON,
+ TONE_TRANSPARENCY,
+ TONE_ANC_ADAPTIVE,
+ TONE_ANC_ADAPTIVE_COEFF,
+ TONE_ANC_NORMAL_COEFF,
+};
+
+/*
+ * 参数配置:
+ * freq : 实际频率 * 512
+ * points : 正弦波点数
+ * win : 正弦窗
+ * decay : 衰减系数(百分比), 正弦窗模式下为频率设置:频率*512
+ *
+ */
+static const struct sin_param sine_16k_normal[] __BANK_TONE = {
+ /*{0, 1000, 0, 100},*/
+ {1000 << 9, 4000, 0, 100},
+};
+
+static const struct sin_param sine_key_tone[] __BANK_TONE = {
+ /*sine_make.c/fade_points = 0效果更加*/
+ {2800 << 9, 1400, 1, 60 << 9},
+};
+
+static const struct sin_param sine_low_latency_in[] __BANK_TONE = {
+ /*{0, 1000, 0, 100},*/
+ {400 << 9, 4000, 0, 100},
+};
+
+static const struct sin_param sine_low_latency_out[] __BANK_TONE = {
+ /*{0, 1000, 0, 100},*/
+ {600 << 9, 8000, 0, 100},
+};
+
+static const struct sin_param sine_tws_disconnect_16k[] __BANK_TONE = {
+ /*
+ {390 << 9, 4026, SINE_TOTAL_VOLUME / 4026},
+ {262 << 9, 8000, SINE_TOTAL_VOLUME / 8000},
+ */
+ {262 << 9, 4026, 0, 100},
+ {390 << 9, 8000, 0, 100},
+};
+
+static const struct sin_param sine_tws_connect_16k[] __BANK_TONE = {
+ /*
+ {262 << 9, 4026, SINE_TOTAL_VOLUME / 4026},
+ {390 << 9, 8000, SINE_TOTAL_VOLUME / 8000},
+ */
+ {262.298 * 512, 8358, 0, 100},
+};
+
+static const struct sin_param sine_low_power[] __BANK_TONE = {
+ {424 << 9, 3613, 0, 100},
+ {319 << 9, 3623, 0, 100},
+};
+
+static const struct sin_param sine_ring[] __BANK_TONE = {
+ {450 << 9, 24960, 1, 16.667 * 512},
+ {0, 16000, 0, 100},
+};
+
+static const struct sin_param sine_tws_max_volume[] __BANK_TONE = {
+ {210 << 9, 2539, 0, 100},
+ {260 << 9, 7619, 0, 100},
+ {400 << 9, 2539, 0, 100},
+};
+
+static const struct sin_param sine_anc_adaptive_1[] __BANK_TONE = {
+ {330 << 9, 2539, 0, 100}, //低 mi
+ {392 << 9, 7619, 0, 100}, //低 so
+};
+
+static const struct sin_param sine_anc_adaptive_2[] __BANK_TONE = {
+ {392 << 9, 2539, 0, 100}, //低 so
+ {330 << 9, 7619, 0, 100}, //低 mi
+};
+
+
+__BANK_TONE_ENTRY
+static const struct sin_param *get_sine_param_by_index(u8 index, u8 *num)
+{
+ const struct sin_param *param_data;
+
+ switch (index) {
+ case SINE_WTONE_NORAML:
+ param_data = sine_16k_normal;
+ *num = ARRAY_SIZE(sine_16k_normal);
+ break;
+ case SINE_WTONE_TWS_CONNECT:
+ param_data = sine_tws_connect_16k;
+ *num = ARRAY_SIZE(sine_tws_connect_16k);
+ break;
+ case SINE_WTONE_TWS_DISCONNECT:
+ param_data = sine_tws_disconnect_16k;
+ *num = ARRAY_SIZE(sine_tws_disconnect_16k);
+ break;
+ case SINE_WTONE_LOW_POWER:
+ param_data = sine_low_power;
+ *num = ARRAY_SIZE(sine_low_power);
+ break;
+ case SINE_WTONE_RING:
+ param_data = sine_ring;
+ *num = ARRAY_SIZE(sine_ring);
+ break;
+ case SINE_WTONE_MAX_VOLUME:
+ param_data = sine_tws_max_volume;
+ *num = ARRAY_SIZE(sine_tws_max_volume);
+ break;
+ case SINE_WTONE_LOW_LATENRY_IN:
+ param_data = sine_low_latency_in;
+ *num = ARRAY_SIZE(sine_low_latency_in);
+ break;
+ case SINE_WTONE_LOW_LATENRY_OUT:
+ param_data = sine_low_latency_out;
+ *num = ARRAY_SIZE(sine_low_latency_out);
+ break;
+ case SINE_WTONE_ANC_ADAPTIVE_1:
+ param_data = sine_anc_adaptive_1;
+ *num = ARRAY_SIZE(sine_anc_adaptive_1);
+ break;
+ case SINE_WTONE_ANC_ADAPTIVE_2:
+ param_data = sine_anc_adaptive_2;
+ *num = ARRAY_SIZE(sine_anc_adaptive_2);
+ break;
+
+ default:
+ return NULL;
+ }
+
+ return param_data;
+}
+
+/*
+ *index:提示音索引
+ *preemption:抢断标志
+ */
+__BANK_TONE_ENTRY
+int tone_play_index(u8 index, u8 preemption)
+{
+ printf("tone_play_index:%d,preemption:%d", index, preemption);
+ if (index >= IDEX_TONE_NONE) {
+ return 0;
+ }
+ return tone_play(tone_index[index], preemption);
+}
+/*
+ *@brief:提示音比较,确认目标提示音和正在播放的提示音是否一致
+ *@return: 0 匹配
+ * 非0 不匹配或者当前没有提示音播放
+ *@note:通过提示音索引比较
+ */
+int tone_name_cmp_by_index(u8 index)
+{
+ if (index >= IDEX_TONE_NONE) {
+ return 0;
+ }
+ return tone_name_compare(tone_index[index]);
+}
+
+__BANK_TONE_ENTRY
+int tone_play_index_no_tws(u8 index, u8 preemption)
+{
+ printf("tone_play_index no tws:%d,preemption:%d", index, preemption);
+ if (index >= IDEX_TONE_NONE) {
+ return 0;
+ }
+ return tone_play_no_tws(tone_index[index], preemption);
+}
+
+/* __BANK_TONE_ENTRY */
+int tone_play_index_with_callback(u8 index, u8 preemption, void (*user_evt_handler)(void *priv), void *priv)
+{
+ printf("tone_play_index:%d,preemption:%d", index, preemption);
+ if (index >= IDEX_TONE_NONE) {
+ return 0;
+ }
+ return tone_play_with_callback(tone_index[index], preemption, user_evt_handler, priv);
+}
+
+
+
+__BANK_INIT_ENTRY
+int tone_table_init()
+{
+ tone_play_set_sine_param_handler(get_sine_param_by_index);
+ return 0;
+}
+__initcall(tone_table_init);
+
+#endif /*CONFIG_MEDIA_NEW_ENABLE*/
+
diff --git a/apps/earphone/trans_data_demo/trans_data_demo.c b/apps/earphone/trans_data_demo/trans_data_demo.c
new file mode 100644
index 0000000..38b86a8
--- /dev/null
+++ b/apps/earphone/trans_data_demo/trans_data_demo.c
@@ -0,0 +1,217 @@
+#include "app_config.h"
+
+
+#include "earphone.h"
+#include "app_main.h"
+#include "update_tws.h"
+#include "3th_profile_api.h"
+
+#include "btstack/avctp_user.h"
+#include "btstack/btstack_task.h"
+#include "bt_tws.h"
+#include "spp_trans_data.h"
+#include "spp_user.h"
+
+
+#if TRANS_DATA_EN
+
+#define LOG_TAG "[TRANS_DATA]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+
+u8 ble_adv_miss_flag = 0;
+u8 ble_adv_poweron_flag = 0;
+
+int trans_data_earphone_state_set_page_scan_enable()
+{
+ return 0;
+}
+
+int trans_data_earphone_state_get_connect_mac_addr()
+{
+ return 0;
+}
+
+int trans_data_earphone_state_cancel_page_scan()
+{
+ return 0;
+}
+
+int trans_data_earphone_state_tws_init(int paired)
+{
+ return 0;
+}
+
+int trans_data_earphone_state_tws_connected(int first_pair, u8 *comm_addr)
+{
+ if (first_pair) {
+ extern void ble_module_enable(u8 en);
+ extern void bt_update_mac_addr(u8 * addr);
+ extern void lib_make_ble_address(u8 * ble_address, u8 * edr_address);
+ /* bt_ble_adv_enable(0); */
+ u8 tmp_ble_addr[6] = {0};
+ lib_make_ble_address(tmp_ble_addr, comm_addr);
+ le_controller_set_mac(tmp_ble_addr);//将ble广播地址改成公共地址
+ bt_update_mac_addr(comm_addr);
+ /* bt_ble_adv_enable(1); */
+
+
+ /*新的连接,公共地址改变了,要重新将新的地址广播出去*/
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ printf("\nNew Connect Master!!!\n\n");
+ ble_app_disconnect();
+ bt_ble_adv_enable(0);
+ bt_ble_adv_enable(1);
+ } else {
+ printf("\nConnect Slave!!!\n\n");
+ /*从机ble关掉*/
+ ble_app_disconnect();
+ bt_ble_adv_enable(0);
+ }
+ }
+
+ return 0;
+}
+
+int trans_data_earphone_state_enter_soft_poweroff()
+{
+ extern void bt_ble_exit(void);
+ bt_ble_exit();
+ return 0;
+}
+
+int trans_data_adv_bt_status_event_handler(struct bt_event *bt)
+{
+ return 0;
+}
+
+
+int trans_data_adv_hci_event_handler(struct bt_event *bt)
+{
+
+ return 0;
+}
+
+void trans_data_bt_tws_event_handler(struct bt_event *bt)
+{
+ int role = bt->args[0];
+ int phone_link_connection = bt->args[1];
+ int reason = bt->args[2];
+
+ switch (bt->event) {
+ case TWS_EVENT_CONNECTED:
+ //bt_ble_adv_enable(1);
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ //master enable
+ printf("\nConnect Slave!!!\n\n");
+ /*从机ble关掉*/
+ ble_app_disconnect();
+ bt_ble_adv_enable(0);
+ }
+
+ break;
+ case TWS_EVENT_PHONE_LINK_DETACH:
+ /*
+ * 跟手机的链路LMP层已完全断开, 只有tws在连接状态才会收到此事件
+ */
+ break;
+ case TWS_EVENT_CONNECTION_DETACH:
+ /*
+ * TWS连接断开
+ */
+ if (app_var.goto_poweroff_flag) {
+ break;
+ }
+ if (get_app_connect_type() == 0) {
+ printf("\ntws detach to open ble~~~\n\n");
+ bt_ble_adv_enable(1);
+ }
+ set_ble_connect_type(TYPE_NULL);
+
+ break;
+ case TWS_EVENT_SYNC_FUN_CMD:
+ break;
+ case TWS_EVENT_ROLE_SWITCH:
+ break;
+ }
+
+#if OTA_TWS_SAME_TIME_ENABLE
+ tws_ota_app_event_deal(bt->event);
+#endif
+}
+
+int trans_data_sys_event_handler_specific(struct sys_event *event)
+{
+ switch (event->type) {
+ case SYS_BT_EVENT:
+ if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) {
+
+ } else if ((u32)event->arg == SYS_BT_EVENT_TYPE_HCI_STATUS) {
+
+ }
+#if TCFG_USER_TWS_ENABLE
+ else if (((u32)event->arg == SYS_BT_EVENT_FROM_TWS)) {
+ trans_data_bt_tws_event_handler(&event->u.bt);
+ }
+#endif
+#if OTA_TWS_SAME_TIME_ENABLE
+ else if (((u32)event->arg == SYS_BT_OTA_EVENT_TYPE_STATUS)) {
+ bt_ota_event_handler(&event->u.bt);
+ }
+#endif
+ break;
+ case SYS_DEVICE_EVENT:
+ break;
+ }
+
+ return 0;
+}
+
+int user_spp_state_specific(u8 packet_type)
+{
+
+ switch (packet_type) {
+ case 1:
+ bt_ble_adv_enable(0);
+ set_app_connect_type(TYPE_SPP);
+ break;
+ case 2:
+
+ set_app_connect_type(TYPE_NULL);
+
+#if TCFG_USER_TWS_ENABLE
+ if (!(tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED)) {
+ ble_module_enable(1);
+ } else {
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ ble_module_enable(1);
+ }
+ }
+#else
+ ble_module_enable(1);
+#endif
+
+ break;
+ }
+ return 0;
+}
+
+
+int trans_data_earphone_state_init()
+{
+ transport_spp_init();
+ spp_data_deal_handle_register(user_spp_data_handler);
+
+ return 0;
+}
+
+
+
+
+
+#endif
diff --git a/apps/earphone/ui_manage.c b/apps/earphone/ui_manage.c
new file mode 100644
index 0000000..10aa825
--- /dev/null
+++ b/apps/earphone/ui_manage.c
@@ -0,0 +1,352 @@
+#include "ui_manage.h"
+#include "asm/pwm_led.h"
+#include "system/includes.h"
+#include "app_config.h"
+#include "user_cfg.h"
+#include "classic/tws_api.h"
+
+#define LOG_TAG_CONST UI
+#define LOG_TAG "[UI]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#define LED_VDDIO_KEEP 1
+#define UI_MANAGE_BUF 8
+
+typedef struct _ui_var {
+ u8 ui_init_flag;
+ u8 other_status;
+ u8 power_status;
+ u8 current_status;
+ volatile u8 ui_flash_cnt;
+ cbuffer_t ui_cbuf;
+ u8 ui_buf[UI_MANAGE_BUF];
+ int sys_ui_timer;
+} ui_var;
+
+static ui_var sys_ui_var = {.power_status = STATUS_NORMAL_POWER};
+
+extern int get_bt_tws_connect_status();
+
+u8 get_ui_status(u8 *status)
+{
+ return cbuf_read(&(sys_ui_var.ui_cbuf), status, 1);
+}
+
+u8 get_ui_status_len(void)
+{
+ return cbuf_get_data_size(&(sys_ui_var.ui_cbuf));
+}
+
+u8 get_ui_busy_status()
+{
+ return sys_ui_var.ui_flash_cnt;
+}
+
+#if (RCSP_ADV_EN)
+u8 adv_get_led_status(void)
+{
+ return sys_ui_var.other_status;
+}
+#endif
+
+void ui_manage_scan(void *priv)
+{
+
+ STATUS *p_led = get_led_config();
+
+ sys_ui_var.sys_ui_timer = 0;
+
+ log_info("ui_flash_cnt:%d cur_ui_status:%d", sys_ui_var.ui_flash_cnt, sys_ui_var.current_status);
+
+ if (sys_ui_var.ui_flash_cnt == 0 || sys_ui_var.ui_flash_cnt == 7) { //有特殊的闪烁状态等当前状态执行完再进入下一个状态
+ if (get_ui_status(&sys_ui_var.current_status)) {
+ if (sys_ui_var.current_status >= STATUS_CHARGE_START && sys_ui_var.current_status <= STATUS_NORMAL_POWER) {
+ sys_ui_var.power_status = sys_ui_var.current_status;
+ } else {
+ sys_ui_var.other_status = sys_ui_var.current_status;
+ }
+ }
+ }
+
+ if (sys_ui_var.ui_flash_cnt) {
+ sys_ui_var.ui_flash_cnt --;
+ sys_ui_var.sys_ui_timer = usr_timeout_add(NULL, ui_manage_scan, 300, 1);
+ } else if (get_ui_status_len()) {
+ sys_ui_var.sys_ui_timer = usr_timeout_add(NULL, ui_manage_scan, 100, 1);
+ }
+
+#if ((RCSP_ADV_EN)&&(JL_EARPHONE_APP_EN))
+ if (tws_api_get_role() == TWS_ROLE_SLAVE) {
+ pwm_led_mode_set(PWM_LED_ALL_OFF);
+ return;
+ }
+#endif
+
+ if (sys_ui_var.other_status != STATUS_POWEROFF && sys_ui_var.power_status != STATUS_NORMAL_POWER) { //关机的状态优先级要高于电源状态
+ switch (sys_ui_var.power_status) {
+ case STATUS_LOWPOWER:
+ log_info("[STATUS_LOWPOWER]\n");
+ pwm_led_mode_set(p_led->lowpower);
+ return;
+
+ case STATUS_CHARGE_START:
+ log_info("[STATUS_CHARGE_START]\n");
+ pwm_led_mode_set(p_led->charge_start);
+ return;
+
+ case STATUS_CHARGE_FULL:
+ log_info("[STATUS_CHARGE_FULL]\n");
+ pwm_led_mode_set(p_led->charge_full);
+ return;
+
+ case STATUS_CHARGE_ERR:
+ log_info("[STATUS_CHARGE_ERR]\n");
+ pwm_led_mode_set(PWM_LED0_ON);
+ pwm_led_mode_set(PWM_LED1_ON);
+ return;
+
+ case STATUS_CHARGE_CLOSE:
+ log_info("[STATUS_CHARGE_CLOSE]\n");
+ pwm_led_mode_set(PWM_LED0_OFF);
+ pwm_led_mode_set(PWM_LED1_OFF);
+ return;
+
+ case STATUS_CHARGE_LDO5V_OFF:
+ log_info("[STATUS_CHARGE_LDO5V_OFF]\n");
+ case STATUS_EXIT_LOWPOWER:
+ case STATUS_NORMAL_POWER:
+ //pwm_led_mode_set(PWM_LED0_OFF);
+ //pwm_led_mode_set(PWM_LED1_OFF);
+ sys_ui_var.power_status = STATUS_NORMAL_POWER;
+ break;
+ }
+ }
+
+ switch (sys_ui_var.other_status) {
+ case STATUS_POWERON:
+ log_info("[STATUS_POWERON]\n");
+ if (p_led->power_on != PWM_LED0_FLASH_THREE) {
+ pwm_led_mode_set(p_led->power_on);
+ } else {
+ if (sys_ui_var.ui_flash_cnt) {
+ if (get_bt_tws_connect_status()) {
+ sys_ui_var.ui_flash_cnt = 0;
+ ui_manage_scan(NULL);
+ return;
+ }
+ if (sys_ui_var.ui_flash_cnt % 2) {
+ pwm_led_mode_set(PWM_LED0_OFF);
+ } else {
+ pwm_led_mode_set(PWM_LED0_ON);
+ }
+ }
+ }
+ break;
+ case STATUS_POWEROFF:
+ log_info("[STATUS_POWEROFF]\n");
+ if (p_led->power_off != PWM_LED1_FLASH_THREE) {
+ pwm_led_mode_set(p_led->power_off);
+ } else {
+ if (sys_ui_var.ui_flash_cnt) {
+ if (sys_ui_var.ui_flash_cnt % 2) {
+ pwm_led_mode_set(PWM_LED1_OFF);
+ } else {
+ pwm_led_mode_set(PWM_LED1_ON);
+ }
+ }
+ }
+ break;
+
+ case STATUS_BT_INIT_OK:
+ log_info("[STATUS_BT_INIT_OK]\n");
+ pwm_led_mode_set(p_led->bt_init_ok);
+ break;
+
+ case STATUS_BT_SLAVE_CONN_MASTER:
+ pwm_led_mode_set(PWM_LED1_SLOW_FLASH);
+ break;
+
+ case STATUS_BT_CONN:
+ log_info("[STATUS_BT_CONN]\n");
+ pwm_led_mode_set(p_led->bt_connect_ok);
+ break;
+
+ case STATUS_BT_MASTER_CONN_ONE:
+ log_info("[STATUS_BT_MASTER_CONN_ONE]\n");
+ pwm_led_mode_set(PWM_LED0_LED1_SLOW_FLASH);
+ break;
+
+ case STATUS_BT_DISCONN:
+ log_info("[STATUS_BT_DISCONN]\n");
+ pwm_led_mode_set(p_led->bt_disconnect);
+ break;
+
+ case STATUS_PHONE_INCOME:
+ log_info("[STATUS_PHONE_INCOME]\n");
+ pwm_led_mode_set(p_led->phone_in);
+ break;
+
+ case STATUS_PHONE_OUT:
+ log_info("[STATUS_PHONE_OUT]\n");
+ pwm_led_mode_set(p_led->phone_out);
+ break;
+
+ case STATUS_PHONE_ACTIV:
+ log_info("[STATUS_PHONE_ACTIV]\n");
+ pwm_led_mode_set(p_led->phone_activ);
+ break;
+
+ case STATUS_POWERON_LOWPOWER:
+ log_info("[STATUS_POWERON_LOWPOWER]\n");
+ pwm_led_mode_set(p_led->lowpower);
+ break;
+
+ case STATUS_BT_TWS_CONN:
+ log_info("[STATUS_BT_TWS_CONN]\n");
+ pwm_led_mode_set(p_led->tws_connect_ok);
+ break;
+ case STATUS_BT_TWS_DISCONN:
+ log_info("[STATUS_BT_TWS_DISCONN]\n");
+ pwm_led_mode_set(p_led->tws_disconnect);
+ break;
+ }
+}
+
+int ui_manage_init(void)
+{
+ if (!sys_ui_var.ui_init_flag) {
+ cbuf_init(&(sys_ui_var.ui_cbuf), &(sys_ui_var.ui_buf), UI_MANAGE_BUF);
+ sys_ui_var.ui_init_flag = 1;
+ }
+ return 0;
+}
+
+void ui_update_status(u8 status)
+{
+ STATUS *p_led = get_led_config();
+ if (!sys_ui_var.ui_init_flag) { //更新UI状态之前需先初始化ui_cbuf
+ ui_manage_init();
+ }
+ log_info("update ui status :%d", status);
+ if ((status == STATUS_POWERON && p_led->power_on == PWM_LED0_FLASH_THREE) || (status == STATUS_POWEROFF && p_led->power_off == PWM_LED1_FLASH_THREE)) {
+ log_info(">>>set ui_flash_cnt");
+ sys_ui_var.ui_flash_cnt = 7;
+ }
+ cbuf_write(&(sys_ui_var.ui_cbuf), &status, 1);
+ /* if (!sys_ui_var.sys_ui_timer) { */
+ /* sys_ui_var.sys_ui_timer = usr_timeout_add(NULL, ui_manage_scan, 10); */
+ /* } */
+ if (sys_ui_var.ui_flash_cnt >= 1 && sys_ui_var.ui_flash_cnt <= 6) {
+ return;
+ }
+
+ ui_manage_scan(NULL);
+}
+
+u8 pdown_keep_pw_gate()
+{
+#if(LED_VDDIO_KEEP == 1) //led 进入powerdown时模块的电源是否降低,降低会导致灯抖动,不降的话功耗会高100ua
+ return true;
+#else
+ if ((sys_ui_var.current_status == STATUS_BT_DISCONN) ||
+ (sys_ui_var.current_status == STATUS_BT_INIT_OK) ||
+ (sys_ui_var.current_status == STATUS_BT_TWS_DISCONN)) {
+ return true;
+ } else {
+ return false;
+ }
+#endif
+}
+
+#if (TCFG_USER_TWS_ENABLE == 1)
+__attribute__((weak))
+bool is_led_module_on()
+{
+ return 0;
+}
+
+__attribute__((weak))
+void led_module_on()
+{
+
+}
+
+__attribute__((weak))
+void led_module_off()
+{
+
+}
+
+__attribute__((weak))
+void led_timer_del()
+{
+
+}
+
+__attribute__((weak))
+void led_module_enter_sniff_mode()
+{
+
+}
+
+__attribute__((weak))
+void led_module_exit_sniff_mode()
+{
+
+}
+
+__attribute__((weak))
+void led_sniff_mode_double_display(u32 index)
+{
+
+}
+
+extern int get_bt_tws_connect_status();
+//对耳连接成功之后利用SNIFF的节奏来进行闪灯同步,只是通过开关LED模块来实现同步
+void sniff_achor_point_hook(u32 slot)
+{
+ u8 led_mode = pwm_led_display_mode_get();
+ if (led_mode != PWM_LED0_ONE_FLASH_5S && led_mode != PWM_LED1_ONE_FLASH_5S) {
+ if (get_bt_tws_connect_status()) {
+ //交替闪进sniff同步
+ if (led_mode == PWM_LED0_LED1_FAST_FLASH) {
+ if ((slot % ((CFG_DOUBLE_FAST_FLASH_FREQ * 1000) / 625)) < 800) {
+ led_sniff_mode_double_display((slot / ((CFG_DOUBLE_FAST_FLASH_FREQ * 1000) / 625)) & BIT(0));
+ }
+ } else if (led_mode == PWM_LED0_LED1_SLOW_FLASH) {
+ if ((slot % ((CFG_DOUBLE_SLOW_FLASH_FREQ * 1000) / 625)) < 800) {
+ led_sniff_mode_double_display((slot / ((CFG_DOUBLE_SLOW_FLASH_FREQ * 1000) / 625)) & BIT(0));
+ }
+ }
+ }
+ return;
+ }
+ /* if (get_bt_tws_connect_status()) { */
+#if defined CFG_LED_MODE && (CFG_LED_MODE == CFG_LED_SOFT_MODE)
+ led_timer_del();
+#endif
+ if (is_led_module_on()) {
+ led_module_off();
+ }
+ if ((slot % (1600 * 5)) < 800) { //一个slot = 0.625ms 1600*0.625 = 1s
+ led_module_on();
+ }
+ /* } else { */
+
+ /* } */
+}
+#else
+
+__attribute__((weak))
+int get_bt_tws_connect_status()
+{
+ return 0;
+}
+
+#endif
+
diff --git a/apps/earphone/user_cfg.c b/apps/earphone/user_cfg.c
new file mode 100644
index 0000000..93a6a3d
--- /dev/null
+++ b/apps/earphone/user_cfg.c
@@ -0,0 +1,583 @@
+#include "app_config.h"
+#include "user_cfg.h"
+#include "fs.h"
+#include "string.h"
+#include "system/includes.h"
+#include "vm.h"
+#include "btcontroller_config.h"
+#include "app_main.h"
+#include "media/includes.h"
+#include "audio_config.h"
+#include "asm/pwm_led.h"
+#include "aec_user.h"
+#include "app_power_manage.h"
+
+#define LOG_TAG_CONST USER_CFG
+#define LOG_TAG "[USER_CFG]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+#define LOG_DUMP_ENABLE
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+void lp_winsize_init(struct lp_ws_t *lp);
+void bt_max_pwr_set(u8 pwr, u8 pg_pwr, u8 iq_pwr, u8 ble_pwr);
+void app_set_sys_vol(s16 vol_l, s16 vol_r);
+
+BT_CONFIG bt_cfg = {
+ .edr_name = {'Y', 'L', '-', 'B', 'R', '3', '0'},
+ .mac_addr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ .tws_local_addr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ .rf_power = 10,
+ .dac_analog_gain = 25,
+ .mic_analog_gain = 7,
+ .tws_device_indicate = 0x6688,
+};
+
+
+AUDIO_CONFIG audio_cfg = {
+ .max_sys_vol = SYS_MAX_VOL,
+ .default_vol = SYS_DEFAULT_VOL,
+ .tone_vol = SYS_DEFAULT_TONE_VOL,
+};
+
+//======================================================================================//
+// BTIF配置项表 //
+// 参数1: 配置项名字 //
+// 参数2: 配置项需要多少个byte存储 //
+// 说明: 配置项ID注册到该表后该配置项将读写于BTIF区域, 其它没有注册到该表 //
+// 的配置项则默认读写于VM区域. //
+//======================================================================================//
+const struct btif_item btif_table[] = {
+// item id len //
+ {CFG_BT_MAC_ADDR, 6 },
+ {CFG_BT_FRE_OFFSET, 6 }, //测试盒矫正频偏值
+ //{CFG_DAC_DTB, 2 },
+ //{CFG_MC_BIAS, 1 },
+ {0, 0 }, //reserved cfg
+};
+
+//============================= VM 区域空间最大值 ======================================//
+//以下宏在app_cfg中配置:
+const int vm_max_page_align_size_config = VM_MAX_PAGE_ALIGN_SIZE_CONFIG; //page对齐vm管理空间最大值配置
+const int vm_max_sector_align_size_config = VM_MAX_SECTOR_ALIGN_SIZE_CONFIG; //sector对齐vm管理空间最大值配置
+//======================================================================================//
+
+struct lp_ws_t lp_winsize = {
+ .lrc_ws_inc = 480, //260
+ .lrc_ws_init = 160,
+ .bt_osc_ws_inc = 100,
+ .bt_osc_ws_init = 140,
+ .osc_change_mode = 0,
+};
+
+u16 bt_get_tws_device_indicate(u8 *tws_device_indicate)
+{
+ return bt_cfg.tws_device_indicate;
+}
+
+const u8 *bt_get_mac_addr()
+{
+ return bt_cfg.mac_addr;
+}
+
+void bt_update_mac_addr(u8 *addr)
+{
+ memcpy(bt_cfg.mac_addr, addr, 6);
+}
+
+static u8 bt_mac_addr_for_testbox[6] = {0};
+void bt_get_vm_mac_addr(u8 *addr)
+{
+#if 0
+ //中断不能调用syscfg_read;
+ int ret = 0;
+
+ ret = syscfg_read(CFG_BT_MAC_ADDR, addr, 6);
+ if ((ret != 6)) {
+ syscfg_write(CFG_BT_MAC_ADDR, addr, 6);
+ }
+#else
+
+ memcpy(addr, bt_mac_addr_for_testbox, 6);
+#endif
+}
+
+void bt_get_tws_local_addr(u8 *addr)
+{
+ memcpy(addr, bt_cfg.tws_local_addr, 6);
+}
+
+const char *sdk_version_info_get(void)
+{
+ extern u32 __VERSION_BEGIN;
+ char *version_str = ((char *)&__VERSION_BEGIN) + 4;
+
+ return version_str;
+}
+
+const char *bt_get_local_name()
+{
+ return (const char *)(bt_cfg.edr_name);
+}
+
+const char *bt_get_pin_code()
+{
+ return "0000";
+}
+
+extern STATUS_CONFIG status_config;
+extern struct charge_platform_data charge_data;
+/* extern struct dac_platform_data dac_data; */
+extern struct adkey_platform_data adkey_data;
+extern struct led_platform_data pwm_led_data;
+extern struct adc_platform_data adc_data;
+
+extern u8 key_table[KEY_EVENT_MAX][KEY_NUM_MAX];
+
+u8 get_max_sys_vol(void)
+{
+ return (audio_cfg.max_sys_vol);
+}
+
+u8 get_tone_vol(void)
+{
+ if (!audio_cfg.tone_vol) {
+ return (get_max_sys_vol());
+ }
+ if (audio_cfg.tone_vol > get_max_sys_vol()) {
+ return (get_max_sys_vol());
+ }
+
+ return (audio_cfg.tone_vol);
+}
+
+#define USE_CONFIG_BIN_FILE 0
+
+#define USE_CONFIG_STATUS_SETTING 1 //状态设置,包括灯状态和提示音
+#define USE_CONFIG_AUDIO_SETTING USE_CONFIG_BIN_FILE //音频设置
+#define USE_CONFIG_CHARGE_SETTING USE_CONFIG_BIN_FILE //充电设置
+#define USE_CONFIG_KEY_SETTING USE_CONFIG_BIN_FILE //按键消息设置
+#define USE_CONFIG_MIC_TYPE_SETTING USE_CONFIG_BIN_FILE //MIC类型设置
+#define USE_CONFIG_LOWPOWER_V_SETTING USE_CONFIG_BIN_FILE //低电提示设置
+#define USE_CONFIG_AUTO_OFF_SETTING USE_CONFIG_BIN_FILE //自动关机时间设置
+#define USE_CONFIG_VOL_SETTING 1 //音量表读配置
+
+__attribute__((weak))
+void get_config_mic_gain(u8 mic_gain0, u8 mic_gain1, u8 mic_gain2)
+{
+
+}
+
+/*更加mic通道值获取使用的第几个mic*/
+u8 get_mic_num(u8 bit)
+{
+ u8 i = 0;
+ for (i = 0; i < 4; i++) {
+ if (bit & 0x1) {
+ return i;
+ }
+ bit >>= 1;
+ }
+ return 0;
+}
+
+__BANK_INIT_ENTRY
+void cfg_file_parse(u8 idx)
+{
+ u8 tmp[128] = {0};
+ int ret = 0;
+
+ memset(tmp, 0x00, sizeof(tmp));
+
+ /*************************************************************************/
+ /* CFG READ IN cfg_tools.bin */
+ /*************************************************************************/
+
+
+ //-----------------------------CFG_BT_NAME--------------------------------------//
+ ret = syscfg_read(CFG_BT_NAME, tmp, 32);
+ if (ret < 0) {
+ log_info("read bt name err");
+ } else if (ret >= LOCAL_NAME_LEN) {
+ memset(bt_cfg.edr_name, 0x00, LOCAL_NAME_LEN);
+ memcpy(bt_cfg.edr_name, tmp, LOCAL_NAME_LEN);
+ bt_cfg.edr_name[LOCAL_NAME_LEN - 1] = 0;
+ } else {
+ memset(bt_cfg.edr_name, 0x00, LOCAL_NAME_LEN);
+ memcpy(bt_cfg.edr_name, tmp, ret);
+ }
+ /* g_printf("bt name config:%s", bt_cfg.edr_name); */
+ log_info("bt name config:%s", bt_cfg.edr_name);
+
+ //-----------------------------CFG_TWS_PAIR_CODE_ID----------------------------//
+ ret = syscfg_read(CFG_TWS_PAIR_CODE_ID, &bt_cfg.tws_device_indicate, 2);
+ if (ret < 0) {
+ log_debug("read pair code err");
+ bt_cfg.tws_device_indicate = 0x8888;
+ }
+ /* g_printf("tws pair code config:"); */
+ log_info("tws pair code config:");
+ log_info_hexdump(&bt_cfg.tws_device_indicate, 2);
+
+ //-----------------------------CFG_BT_RF_POWER_ID----------------------------//
+ ret = syscfg_read(CFG_BT_RF_POWER_ID, &app_var.rf_power, 1);
+ if (ret < 0) {
+ log_debug("read rf err");
+ app_var.rf_power = 10;
+ }
+ bt_max_pwr_set(app_var.rf_power, 5, 8, 9);//last is ble tx_pwer(0~9)
+ /* g_printf("rf config:%d\n", app_var.rf_power); */
+ log_info("rf config:%d\n", app_var.rf_power);
+
+ //-----------------------------CFG_AEC_ID------------------------------------//
+#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
+ log_info("3mic config:");
+ AEC_TMS_CONFIG aec;
+ ret = syscfg_read(CFG_TMS_DNS_ID, &aec, sizeof(aec));
+#elif TCFG_AUDIO_DUAL_MIC_ENABLE
+#if ((defined TCFG_AUDIO_DMS_SEL) && (TCFG_AUDIO_DMS_SEL == DMS_FLEXIBLE))
+#if(TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE)
+ log_info("dms_flexible config:");/*双mic话务耳机降噪*/
+ DMS_FLEXIBLE_CONFIG aec;
+ ret = syscfg_read(CFG_DMS_FLEXIBLE_ID, &aec, sizeof(aec));
+#else /*DMS_DNS*/
+ log_info("dms_dns_flexible config:");/*双mic话务耳机神经网络降噪*/
+ DMS_FLEXIBLE_CONFIG aec;
+ ret = syscfg_read(CFG_DMS_DNS_FLEXIBLE_ID, &aec, sizeof(aec));
+#endif/*TCFG_AUDIO_CVP_NS_MODE*/
+#else /*TCFG_AUDIO_DMS_SEL == DMS_NORMAL*/
+#if(TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE)
+ log_info("dms_ans config:");/*双mic传统降噪*/
+ AEC_DMS_CONFIG aec;
+ ret = syscfg_read(CFG_DMS_ID, &aec, sizeof(aec));
+#else /*DMS_DNS*/
+ log_info("dms_dns config:");/*双mic神经网络降噪*/
+ AEC_DMS_CONFIG aec;
+ ret = syscfg_read(CFG_DMS_DNS_ID, &aec, sizeof(aec));
+#endif/*TCFG_AUDIO_CVP_NS_MODE*/
+#if TCFG_AUDIO_MIC_ARRAY_TRIM_ENABLE
+ app_var.enc_degradation = aec.target_signal_degradation;
+#endif /*TCFG_AUDIO_MIC_ARRAY_TRIM_ENABLE*/
+#endif/*TCFG_AUDIO_DMS_SEL*/
+#else /*single mic*/
+ AEC_CONFIG aec;
+#if(TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE)
+ log_info("sms_ans config:");
+ ret = syscfg_read(CFG_AEC_ID, &aec, sizeof(aec));
+#else /*SMS_DNS*/
+ log_info("sms_dns config:");
+ ret = syscfg_read(CFG_SMS_DNS_ID, &aec, sizeof(aec));
+#endif/*TCFG_AUDIO_CVP_NS_MODE*/
+#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
+ //log_info("ret:%d,aec_cfg size:%d\n",ret,sizeof(aec));
+ if (ret == sizeof(aec)) {
+ log_info("aec cfg read succ\n");
+ log_info_hexdump(&aec, sizeof(aec));
+
+ app_var.aec_mic_gain = aec.mic_again;
+ app_var.aec_mic1_gain = aec.mic_again;
+ app_var.aec_mic2_gain = aec.mic_again;
+ app_var.aec_mic3_gain = aec.mic_again;
+#if TCFG_AUDIO_DUAL_MIC_ENABLE
+#if ((defined TCFG_AUDIO_DMS_SEL) && (TCFG_AUDIO_DMS_SEL == DMS_FLEXIBLE))
+ app_var.aec_mic1_gain = aec.mic1_again;
+#endif/*TCFG_AUDIO_DMS_SEL*/
+#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
+ get_config_mic_gain(app_var.aec_mic_gain, app_var.aec_mic1_gain, app_var.aec_mic1_gain);
+
+ /*3麦增益设置*/
+#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
+ app_var.talk_mic_ch = aec.talk_mic_ch;
+ app_var.talk_ref_mic_ch = aec.talk_ref_mic_ch;
+ app_var.talk_fb_mic_ch = aec.talk_fb_mic_ch;
+ printf("3 mic ch sel , talk : %d, ref : %d, fb : %d", app_var.talk_mic_ch, app_var.talk_ref_mic_ch, app_var.talk_fb_mic_ch);
+
+ u8 gain[4] = {0};
+ gain[get_mic_num(aec.talk_mic_ch)] = aec.mic_again;
+ gain[get_mic_num(aec.talk_ref_mic_ch)] = aec.mic_again;
+ gain[get_mic_num(aec.talk_fb_mic_ch)] = aec.fb_mic_again;
+ app_var.aec_mic_gain = gain[0];
+ app_var.aec_mic1_gain = gain[1];
+ app_var.aec_mic2_gain = gain[2];
+ app_var.aec_mic3_gain = gain[3];
+#endif
+
+ app_var.aec_dac_gain = aec.dac_again;
+#if AEC_READ_CONFIG
+#ifdef CONFIG_MEDIA_ORIGIN_ENABLE
+ aec_cfg_fill(&aec);
+#endif/*CONFIG_MEDIA_ORIGIN_ENABLE*/
+#endif/*AEC_READ_CONFIG*/
+ } else {
+ log_info("aec cfg read err ret: %d, aec : %d,use default value\n", ret, sizeof(aec));
+ app_var.talk_mic_ch = 1;
+ app_var.talk_ref_mic_ch = 2;
+ app_var.talk_fb_mic_ch = 4;
+
+ app_var.aec_mic_gain = 6;
+ app_var.aec_mic1_gain = 6;
+ app_var.aec_mic2_gain = 1;
+ app_var.aec_mic3_gain = 1;
+ app_var.aec_dac_gain = 12;/*初始化默认值要注意不能大于芯片支持最大模拟音量*/
+ }
+ log_info("CVP_cfg Mic0_gain:%d Mic1_gain:%d Mic2_gain:%d Mic3_gain:%d DAC_Gain:%d",
+ app_var.aec_mic_gain, app_var.aec_mic1_gain, app_var.aec_mic2_gain, app_var.aec_mic3_gain, app_var.aec_dac_gain);
+
+ //-----------------------------CFG_MIC_ARRAY_TRIM-------------------------------------//
+#if TCFG_AUDIO_MIC_ARRAY_TRIM_ENABLE
+
+ extern void put_float(double fv);
+ ret = syscfg_read(CFG_MIC_ARRAY_TRIM_EN, (u8 *)(&app_var.audio_mic_array_trim_en), sizeof(app_var.audio_mic_array_trim_en));
+ if (ret != sizeof(app_var.audio_mic_array_trim_en)) {
+ log_info("audio_mic_array_trim_en vm read fail %d, %d!!!", ret, sizeof(app_var.audio_mic_array_trim_en));
+ }
+ ret = syscfg_read(CFG_MIC_ARRAY_DIFF_CMP_VALUE, (u8 *)(&app_var.audio_mic_array_diff_cmp), sizeof(app_var.audio_mic_array_diff_cmp));
+ if (ret != sizeof(app_var.audio_mic_array_diff_cmp)) {
+ log_info("audio_mic_array_diff_cmp vm read fail %d, %d!!!", ret, sizeof(app_var.audio_mic_array_diff_cmp));
+ app_var.audio_mic_array_diff_cmp = 1.0f;
+ }
+ ret = syscfg_read(CFG_MIC_TARGET_DIFF_CMP, (u8 *)(&app_var.audio_mic_cmp), sizeof(audio_mic_cmp_t));
+ if (ret != sizeof(audio_mic_cmp_t)) {
+ log_info("audio_mic_array_diff_cmp vm read fail %d, %d!!!", ret, sizeof(audio_mic_cmp_t));
+ app_var.audio_mic_cmp.talk = 1.0f;
+ app_var.audio_mic_cmp.ff = 1.0f;
+ app_var.audio_mic_cmp.fb = 1.0f;
+ }
+
+ log_info("mic array trim en: %d\n", app_var.audio_mic_array_trim_en);
+ log_info("mic_array_diff_cmp:");
+ put_float(app_var.audio_mic_array_diff_cmp);
+ log_info("mic_cmp-talk:");
+ put_float(app_var.audio_mic_cmp.talk);
+ log_info("mic_cmp-ff:");
+ put_float(app_var.audio_mic_cmp.ff);
+ log_info("mic_cmp-fb:");
+ put_float(app_var.audio_mic_cmp.fb);
+
+#endif
+
+ //-----------------------------CFG_VOL_LIST-------------------------------------//
+ audio_volume_list_init(USE_CONFIG_VOL_SETTING);
+
+ //-----------------------------CFG_MIC_TYPE_ID------------------------------------//
+#if USE_CONFIG_MIC_TYPE_SETTING
+ log_info("mic_type_config:");
+ extern int read_mic_type_config(void);
+ read_mic_type_config();
+
+#endif
+
+#if TCFG_MC_BIAS_AUTO_ADJUST
+ ret = syscfg_read(CFG_MC_BIAS, &adc_data.mic_bias_res, 1);
+ log_info("mic_bias_res:%d", adc_data.mic_bias_res);
+ if (ret != 1) {
+ log_info("mic_bias_adjust NULL");
+ }
+ u8 mic_ldo_idx;
+ ret = syscfg_read(CFG_MIC_LDO_VSEL, &mic_ldo_idx, 1);
+ if (ret == 1) {
+ adc_data.mic_ldo_vsel = mic_ldo_idx & 0x3;
+ log_info("mic_ldo_vsel:%d,%d\n", adc_data.mic_ldo_vsel, mic_ldo_idx);
+ } else {
+ log_info("mic_ldo_vsel_adjust NULL\n");
+ }
+#endif
+
+#if USE_CONFIG_STATUS_SETTING
+ /* g_printf("status_config:"); */
+ log_info("status_config:");
+ STATUS_CONFIG *status = (STATUS_CONFIG *)tmp;
+ ret = syscfg_read(CFG_UI_TONE_STATUS_ID, status, sizeof(STATUS_CONFIG));
+ if (ret > 0) {
+ memcpy((u8 *)&status_config, (u8 *)status, sizeof(STATUS_CONFIG));
+ log_info_hexdump(&status_config, sizeof(STATUS_CONFIG));
+ }
+#endif
+
+#if USE_CONFIG_AUDIO_SETTING
+ /* g_printf("app audio_config:"); */
+ log_info("app audio_config:");
+ ret = syscfg_read(CFG_AUDIO_ID, (u8 *)&audio_cfg, sizeof(AUDIO_CONFIG));
+ if (ret > 0) {
+ log_info_hexdump((u8 *)&audio_cfg, sizeof(AUDIO_CONFIG));
+#else
+ {
+#endif
+ /* dac_data.max_ana_vol = audio_cfg.max_sys_vol; */
+ /* if (dac_data.max_ana_vol > 30) { */
+ /* dac_data.max_ana_vol = 30; */
+ /* } */
+
+ u8 default_volume = audio_cfg.default_vol;
+ s8 music_volume = -1;
+#if SYS_DEFAULT_VOL
+ default_volume = audio_cfg.default_vol;
+#else
+ syscfg_read(CFG_SYS_VOL, &default_volume, 1);
+ ret = syscfg_read(CFG_MUSIC_VOL, &music_volume, 1);
+ if (ret < 0) {
+ music_volume = -1;
+ }
+#endif
+ if (default_volume > audio_cfg.max_sys_vol) {
+ default_volume = audio_cfg.max_sys_vol;
+ }
+ if (default_volume == 0) {
+ default_volume = audio_cfg.max_sys_vol / 2;
+ }
+
+ app_var.music_volume = music_volume == -1 ? default_volume : music_volume;
+ app_var.wtone_volume = audio_cfg.tone_vol;
+#if TCFG_CALL_USE_DIGITAL_VOLUME
+ app_var.call_volume = 15;
+#else
+ app_var.call_volume = app_var.aec_dac_gain;
+#endif
+ app_var.opid_play_vol_sync = default_volume * 127 / audio_cfg.max_sys_vol;
+
+ log_info("max vol:%d default vol:%d tone vol:%d", audio_cfg.max_sys_vol, default_volume, audio_cfg.tone_vol);
+ }
+
+#if (USE_CONFIG_CHARGE_SETTING) && (TCFG_CHARGE_ENABLE)
+ /* g_printf("app charge config:"); */
+ log_info("app charge config:");
+ CHARGE_CONFIG *charge = (CHARGE_CONFIG *)tmp;
+ ret = syscfg_read(CFG_CHARGE_ID, charge, sizeof(CHARGE_CONFIG));
+ if (ret > 0) {
+ log_info_hexdump(charge, sizeof(CHARGE_CONFIG));
+ log_info("sw:%d poweron_en:%d full_v:%d full_mA:%d charge_mA:%d",
+ charge->sw, charge->poweron_en, charge->full_v, charge->full_c, charge->charge_c);
+ memcpy((u8 *)&charge_data, (u8 *)charge, sizeof(CHARGE_CONFIG));
+ }
+#endif
+
+#if (USE_CONFIG_KEY_SETTING) && (TCFG_ADKEY_ENABLE || TCFG_IOKEY_ENABLE)
+ /* g_printf("app key config:"); */
+ log_info("app key config:");
+ KEY_OP *key_msg = (KEY_OP *)tmp;
+ ret = syscfg_read(CFG_KEY_MSG_ID, key_msg, sizeof(KEY_OP) * KEY_NUM_MAX);
+ if (ret > 0) {
+ log_info_hexdump(key_msg, sizeof(KEY_OP) * KEY_NUM);
+ memcpy(key_table, key_msg, sizeof(KEY_OP) * KEY_NUM);
+ }
+
+ log_info("key_msg:");
+ log_info_hexdump((u8 *)key_table, KEY_EVENT_MAX * KEY_NUM_MAX);
+#endif
+
+
+#if USE_CONFIG_LOWPOWER_V_SETTING
+ /* g_printf("auto low power config:"); */
+ log_info("auto low power config:");
+ AUTO_LOWPOWER_V_CONFIG auto_lowpower;
+ ret = syscfg_read(CFG_LOWPOWER_V_ID, &auto_lowpower, sizeof(AUTO_LOWPOWER_V_CONFIG));
+ if (ret > 0) {
+ app_var.warning_tone_v = auto_lowpower.warning_tone_v;
+ app_var.poweroff_tone_v = auto_lowpower.poweroff_tone_v;
+ }
+ log_info("warning_tone_v:%d poweroff_tone_v:%d", app_var.warning_tone_v, app_var.poweroff_tone_v);
+#else
+ app_var.warning_tone_v = LOW_POWER_WARN_VAL;
+ app_var.poweroff_tone_v = LOW_POWER_OFF_VAL;
+ log_info("warning_tone_v:%d poweroff_tone_v:%d", app_var.warning_tone_v, app_var.poweroff_tone_v);
+#endif
+
+#if USE_CONFIG_AUTO_OFF_SETTING
+ /* g_printf("auto off time config:"); */
+ log_info("auto off time config:");
+ AUTO_OFF_TIME_CONFIG auto_off_time;
+ ret = syscfg_read(CFG_AUTO_OFF_TIME_ID, &auto_off_time, sizeof(AUTO_OFF_TIME_CONFIG));
+ if (ret > 0) {
+ app_var.auto_off_time = auto_off_time.auto_off_time * 60;
+ }
+ log_info("auto_off_time:%d", app_var.auto_off_time);
+#else
+ app_var.auto_off_time = TCFG_AUTO_SHUT_DOWN_TIME;
+ log_info("auto_off_time:%d", app_var.auto_off_time);
+#endif
+
+ /*************************************************************************/
+ /* CFG READ IN VM */
+ /*************************************************************************/
+ u8 mac_buf[6];
+ u8 mac_buf_tmp[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+ u8 mac_buf_tmp2[6] = {0, 0, 0, 0, 0, 0};
+#if TCFG_USER_TWS_ENABLE
+ int len = syscfg_read(CFG_TWS_LOCAL_ADDR, bt_cfg.tws_local_addr, 6);
+ if (len != 6) {
+ get_random_number(bt_cfg.tws_local_addr, 6);
+ syscfg_write(CFG_TWS_LOCAL_ADDR, bt_cfg.tws_local_addr, 6);
+ }
+ log_debug("tws_local_mac:");
+ log_info_hexdump(bt_cfg.tws_local_addr, sizeof(bt_cfg.tws_local_addr));
+
+ ret = syscfg_read(CFG_TWS_COMMON_ADDR, mac_buf, 6);
+ if (ret != 6 || !memcmp(mac_buf, mac_buf_tmp, 6))
+#endif
+ do {
+ ret = syscfg_read(CFG_BT_MAC_ADDR, mac_buf, 6);
+ if ((ret != 6) || !memcmp(mac_buf, mac_buf_tmp, 6) || !memcmp(mac_buf, mac_buf_tmp2, 6)) {
+ get_random_number(mac_buf, 6);
+ syscfg_write(CFG_BT_MAC_ADDR, mac_buf, 6);
+ }
+ } while (0);
+
+
+ syscfg_read(CFG_BT_MAC_ADDR, bt_mac_addr_for_testbox, 6);
+ if (!memcmp(bt_mac_addr_for_testbox, mac_buf_tmp, 6)) {
+ get_random_number(bt_mac_addr_for_testbox, 6);
+ syscfg_write(CFG_BT_MAC_ADDR, bt_mac_addr_for_testbox, 6);
+ log_info(">>>init mac addr!!!\n");
+ }
+
+ log_info("mac:");
+ log_info_hexdump(mac_buf, sizeof(mac_buf));
+ memcpy(bt_cfg.mac_addr, mac_buf, 6);
+
+#if (CONFIG_BT_MODE != BT_NORMAL)
+ const u8 dut_name[] = "AC693x_DUT";
+ const u8 dut_addr[6] = {0x12, 0x34, 0x56, 0x56, 0x34, 0x12};
+ memcpy(bt_cfg.edr_name, dut_name, sizeof(dut_name));
+ memcpy(bt_cfg.mac_addr, dut_addr, 6);
+#endif
+
+ /*************************************************************************/
+ /* CFG READ IN isd_config.ini */
+ /*************************************************************************/
+ LRC_CONFIG lrc_cfg;
+ ret = syscfg_read(CFG_LRC_ID, &lrc_cfg, sizeof(LRC_CONFIG));
+ if (ret > 0) {
+ log_info("lrc cfg:");
+ log_info_hexdump(&lrc_cfg, sizeof(LRC_CONFIG));
+ lp_winsize.lrc_ws_inc = lrc_cfg.lrc_ws_inc;
+ lp_winsize.lrc_ws_init = lrc_cfg.lrc_ws_init;
+ lp_winsize.bt_osc_ws_inc = lrc_cfg.btosc_ws_inc;
+ lp_winsize.bt_osc_ws_init = lrc_cfg.btosc_ws_init;
+ lp_winsize.osc_change_mode = lrc_cfg.lrc_change_mode;
+ }
+ /* printf("%d %d %d ",lp_winsize.lrc_ws_inc,lp_winsize.lrc_ws_init,lp_winsize.osc_change_mode); */
+ lp_winsize_init(&lp_winsize);
+}
+
+extern void lmp_hci_write_local_name(const char *name);
+int bt_modify_name(u8 *new_name)
+{
+ u8 new_len = strlen(new_name);
+
+ if (new_len >= LOCAL_NAME_LEN) {
+ new_name[LOCAL_NAME_LEN - 1] = 0;
+ }
+
+ if (strcmp(new_name, bt_cfg.edr_name)) {
+ syscfg_write(CFG_BT_NAME, new_name, LOCAL_NAME_LEN);
+ memcpy(bt_cfg.edr_name, new_name, LOCAL_NAME_LEN);
+ lmp_hci_write_local_name(bt_get_local_name());
+ log_info("mdy_name sucess\n");
+ return 1;
+ }
+ return 0;
+}
+
+
diff --git a/apps/earphone/version.c b/apps/earphone/version.c
new file mode 100644
index 0000000..676d188
--- /dev/null
+++ b/apps/earphone/version.c
@@ -0,0 +1,32 @@
+#include "system/includes.h"
+#include "generic/log.h"
+
+extern char __VERSION_BEGIN[];
+extern char __VERSION_END[];
+
+_INLINE_
+int app_version_check()
+{
+ /*lib_version_check();*/
+
+ char *version;
+
+ puts("=================Version===============\n");
+ for (version = __VERSION_BEGIN; version < __VERSION_END;) {
+ version += 4;
+ printf("%s\n", version);
+ version += strlen(version) + 1;
+ }
+ puts("=======================================\n");
+
+ /*#ifdef CONFIG_FATFS_ENBALE
+ VERSION_CHECK(fatfs, FATFS_VERSION);
+ #endif
+
+ #ifdef SDFILE_VERSION
+ VERSION_CHECK(sdfile, SDFILE_VERSION);
+ #endif*/
+ return 0;
+}
+
+
diff --git a/apps/earphone/vol_sync.c b/apps/earphone/vol_sync.c
new file mode 100644
index 0000000..644f58f
--- /dev/null
+++ b/apps/earphone/vol_sync.c
@@ -0,0 +1,182 @@
+#include "typedef.h"
+#include "app_main.h"
+#include "app_config.h"
+#include "vol_sync.h"
+#include "tone_player.h"
+#include "app_core.h"
+
+u8 vol_sys_tab[17] = {0, 2, 3, 4, 6, 8, 10, 11, 12, 14, 16, 18, 19, 20, 22, 23, 25};
+const u8 vol_sync_tab[17] = {0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 127};
+
+extern u8 get_max_sys_vol(void);
+extern bool get_esco_busy_flag(void);
+
+void vol_sys_tab_init(void)
+{
+#if BT_SUPPORT_MUSIC_VOL_SYNC
+
+#if 1
+ u8 i = 0;
+ u8 max_vol = get_max_sys_vol();
+ for (i = 0; i < 17; i++) {
+ vol_sys_tab[i] = i * max_vol / 16;
+ }
+#else
+ u8 i = 0;
+ u8 max_vol = get_max_sys_vol();
+ vol_sys_tab[0] = 0;
+
+ //最大音量<16,补最大值
+ if (max_vol <= 16) {
+ for (i = 1; i <= max_vol; i++) {
+ vol_sys_tab[i] = i;
+ }
+ for (; i < 17; i++) {
+ vol_sys_tab[i] = max_vol;
+ }
+ } else {
+ u8 j = max_vol - 16;
+ u8 k = 1;
+ for (i = 1; i <= max_vol; i++) {
+ /* g_printf("i=%d j=%d k=%d",i,j,k); */
+ if (i % 2) {
+ } else {
+ //忽略多余的级数
+ if (j > 0) {
+ j--;
+ continue;
+ }
+ }
+
+ if (k < 17) {
+ vol_sys_tab[k] = i;
+ }
+ k++;
+ }
+
+ vol_sys_tab[16] = max_vol;
+ }
+
+#endif
+
+#if 1
+ for (i = 0; i < 17; i++) {
+ g_printf("[%d]:%d ", i, vol_sys_tab[i]);
+ }
+#endif
+
+#endif //BT_SUPPORT_MUSIC_VOL_SYNC
+}
+
+//注册给库的回调函数,用户手机设置设备音量
+void set_music_device_volume(int volume)
+{
+ r_printf("set_music_device_volume=%d\n", volume);
+#if BT_SUPPORT_MUSIC_VOL_SYNC
+ s16 music_volume;
+
+#if CONFIG_BT_BACKGROUND_ENABLE
+ struct application *app = get_current_app();
+ if (app->name != "earphone") {
+ app_var.bt_volume = ((volume + 1) * 16) / 127;
+ r_printf("set_app_var.bt_volume=%d\n", app_var.bt_volume);
+ return;
+ }
+#endif
+
+ //音量同步最大是127,请计数比例
+ if (volume > 127) {
+ /*log_info("vol %d invalid\n", volume);*/
+#if TCFG_VOL_RESET_WHEN_NO_SUPPORT_VOL_SYNC
+ /*不支持音量同步的设备,默认设置到最大值,可以根据实际需要进行修改。
+ 注意如果不是最大值,设备又没有按键可以调音量到最大,则输出也就达不到最大*/
+ music_volume = get_max_sys_vol();
+ log_i("unsupport vol_sync,reset vol:%d\n", music_volume);
+ app_audio_set_volume(APP_AUDIO_STATE_MUSIC, music_volume, 1);
+#endif
+ return;
+ }
+ if (tone_get_status() || get_esco_busy_flag()) {
+ log_i("It's not smart to sync a2dp vol now\n");
+ //app_var.music_volume = vol_sys_tab[(volume + 1) / 8];
+ app_var.music_volume = ((volume + 1) * 16) / 127;
+ return;
+ }
+
+#if 1
+ /*
+ *0~16,总共17级
+ *这里将手机的0~127的音量值换成实际的dac音量等级
+ */
+ music_volume = ((volume + 1) * 16) / 127;
+#else
+ music_volume = vol_sys_tab[(volume + 1) / 8];
+#endif
+ y_printf("phone_vol:%d,dac_vol:%d", volume, music_volume);
+ app_var.opid_play_vol_sync = vol_sync_tab[(volume + 1) / 8];
+
+ app_audio_set_volume(APP_AUDIO_STATE_MUSIC, music_volume, 1);
+
+#endif
+}
+
+//注册给库的回调函数,用于手机获取当前设备音量
+int phone_get_device_vol(void)
+{
+ //音量同步最大是127,请计数比例
+#if 0
+ return (app_var.sys_vol_l * get_max_sys_vol() / 127) ;
+#else
+ return app_var.opid_play_vol_sync;
+#endif
+}
+
+
+void opid_play_vol_sync_fun(u8 *vol, u8 mode)
+{
+#if BT_SUPPORT_MUSIC_VOL_SYNC
+ u8 i = 0;
+ vol_sys_tab[16] = get_max_sys_vol();
+
+ if (*vol == 0) {
+ if (mode) {
+ *vol = vol_sys_tab[1];
+ app_var.opid_play_vol_sync = vol_sync_tab[1];
+ } else {
+ *vol = vol_sys_tab[0];
+ app_var.opid_play_vol_sync = vol_sync_tab[0];
+ }
+ } else if (*vol >= get_max_sys_vol()) {
+ if (mode) {
+ *vol = vol_sys_tab[16];
+ app_var.opid_play_vol_sync = vol_sync_tab[16];
+ } else {
+ *vol = vol_sys_tab[15];
+ app_var.opid_play_vol_sync = vol_sync_tab[15];
+ }
+ } else {
+ for (i = 0; i < sizeof(vol_sys_tab); i++) {
+ if (*vol == vol_sys_tab[i]) {
+ if (mode) {
+ app_var.opid_play_vol_sync = vol_sync_tab[i + 1];
+ *vol = vol_sys_tab[i + 1];
+ } else {
+ app_var.opid_play_vol_sync = vol_sync_tab[i - 1];
+ *vol = vol_sys_tab[i - 1];
+ }
+ break;
+ } else if (*vol < vol_sys_tab[i]) {
+ if (mode) {
+ *vol = vol_sys_tab[i + 1];
+ app_var.opid_play_vol_sync = vol_sync_tab[i];
+ } else {
+ *vol = vol_sys_tab[i - 1];
+ app_var.opid_play_vol_sync = vol_sync_tab[i - 1];
+ }
+ break;
+ }
+ }
+ }
+#endif
+}
+
diff --git a/apps/usr_jb_proto/Protocol/jb_product.c b/apps/usr_jb_proto/Protocol/jb_product.c
new file mode 100644
index 0000000..1afb4a6
--- /dev/null
+++ b/apps/usr_jb_proto/Protocol/jb_product.c
@@ -0,0 +1,249 @@
+/* ================================================================
+ * jb_product.c — 用户层实现(请填补空白处)
+ * 设备: 侠客猫激光 | 生成时间: 2026-07-31 17:08:51
+ *
+ * ══ 开发流程 ══
+ * 1. 实现硬件抽象: jbGetTimerCount(定时器由 SOC SDK 提供)
+ * 发送由 SOC SDK 的 ble_send_data 承担,协议层已直接调用,无需 uartWrite
+ * 2. userInit() 设置 DP 默认值与外设初始化
+ * 3. userHandle() 用户数据采集
+ * 4. jbEventProcess() 处理 APP 下发的控制命令
+ * 5. 主动上报 / OTA 的网关应答在收到 REPORTCMD_V2 后调用 jbReportAckCheck 清除等待
+ * 6. main.c / 调用方需周期性调用 jbReportAckCheck(cmd, cnt, int0)
+ * ================================================================
+ */
+
+#include "jb_product.h"
+
+/* ════════════════════════════════════════════════════════════════
+ * 全局变量
+ * ════════════════════════════════════════════════════════════════ */
+
+jb_data_point_t gDevData;
+static volatile uint32_t timerMs;
+
+/* ════════════════════════════════════════════════════════════════
+ * userInit — DP 默认值
+ * ════════════════════════════════════════════════════════════════ */
+void userInit(void)
+{
+ memset(&gDevData, 0, sizeof(jb_data_point_t));
+
+ gDevData.power = 0; /* DP0 开关 0=关 1=开 */
+ gDevData.play_mode = 0; /* PLAY_MODE_0 (关) */
+ gDevData.hand_mode = 0; /* HAND_MODE_0 (关) */
+ gDevData.alm_low_battery = 0; /* DP3 低电量报警 0=关 1=开 */
+ gDevData.beep_trig = 0; /* DP4 声音开关 0=关 1=开 */
+ gDevData.battery = 0; /* DP5 电量上报 */
+ gDevData.shake_wake = 0; /* DP6 震动触发开机 0=关 1=开 */
+ memset(gDevData.no_disturb_enable, 0, 13); /* DP7 勿扰模式开关 */
+ gDevData.reserva_dp1 = 0; /* DP8 预留DP1 */
+ gDevData.reserva_dp2 = 0; /* DP9 预留DP2 */
+ gDevData.reserva_dp3 = 0; /* DP10 预留DP3 */
+}
+
+/* ════════════════════════════════════════════════════════════════
+ * userHandle — 用户数据采集
+ * 协议层自动检测变化并上报(注意:此处是上报,不是下发控制)
+ * ════════════════════════════════════════════════════════════════ */
+void userHandle(void)
+{
+ /* ── 可上报 DP (RO / RW): 用户数据采集 ── */
+ // gDevData.power = read_sensor(); /* DP0 开关 */
+ // gDevData.play_mode = read_sensor(); /* DP1 自动模式 */
+ // gDevData.alm_low_battery = read_sensor(); /* DP3 低电量报警 */
+ // gDevData.beep_trig = read_sensor(); /* DP4 声音开关 */
+ // gDevData.battery = read_sensor(); /* DP5 电量上报 */
+ // gDevData.shake_wake = read_sensor(); /* DP6 震动触发开机 */
+ // memcpy(gDevData.no_disturb_enable, sensor_read(), 13); /* DP7 勿扰模式开关 */
+ // gDevData.reserva_dp1 = read_sensor(); /* DP8 预留DP1 */
+ // gDevData.reserva_dp2 = read_sensor(); /* DP9 预留DP2 */
+ // gDevData.reserva_dp3 = read_sensor(); /* DP10 预留DP3 */
+}
+
+/* ════════════════════════════════════════════════════════════════
+ * jbEventProcess — 0x03 APP 控制事件处理(下行 / DP 赋值方向)
+ *
+ * 协议层自动解包 0x03 帧后调用本函数。
+ * info->dp_ids[] = 被控制的 DP ID 列表
+ * ctrl 已填入下发的值;复制到 gDevData 并执行动作
+ * ════════════════════════════════════════════════════════════════ */
+int8_t jbEventProcess(jb_event_info_t *info, jb_data_point_t *ctrl)
+{
+ if (!info || !ctrl)
+ {
+ return -1;
+ }
+
+ for (uint8_t i = 0; i < info->count; i++)
+ {
+ switch (info->dp_ids[i])
+ {
+
+ /* ── DP0 开关 (bool) ── */
+ case DP_ID_POWER:
+ if (ctrl->power)
+ {
+ gDevData.power = 1;
+ // TODO: 开 — 执行动作
+ }
+ else
+ {
+ gDevData.power = 0;
+ // TODO: 关 — 执行动作
+ }
+ break;
+
+ /* ── DP1 自动模式 (enum) ── */
+ case DP_ID_PLAY_MODE:
+ gDevData.play_mode = ctrl->play_mode;
+ switch (ctrl->play_mode)
+ {
+ case PLAY_MODE_0: /* 关 */
+ // TODO: 处理 关
+ break;
+ case PLAY_MODE_1: /* mode1 */
+ // TODO: 处理 mode1
+ break;
+ case PLAY_MODE_2: /* mode2 */
+ // TODO: 处理 mode2
+ break;
+ case PLAY_MODE_3: /* mode3 */
+ // TODO: 处理 mode3
+ break;
+ case PLAY_MODE_4: /* mode4 */
+ // TODO: 处理 mode4
+ break;
+ default:
+ break;
+ }
+ break;
+
+ /* ── DP2 手动模式 (enum) ── */
+ case DP_ID_HAND_MODE:
+ gDevData.hand_mode = ctrl->hand_mode;
+ switch (ctrl->hand_mode)
+ {
+ case HAND_MODE_0: /* 关 */
+ // TODO: 处理 关
+ break;
+ case HAND_MODE_1: /* 顺时针 */
+ // TODO: 处理 顺时针
+ break;
+ case HAND_MODE_2: /* 逆时针 */
+ // TODO: 处理 逆时针
+ break;
+ default:
+ break;
+ }
+ break;
+
+ /* ── DP4 声音开关 (bool) ── */
+ case DP_ID_BEEP_TRIG:
+ if (ctrl->beep_trig)
+ {
+ gDevData.beep_trig = 1;
+ // TODO: 开 — 执行动作
+ }
+ else
+ {
+ gDevData.beep_trig = 0;
+ // TODO: 关 — 执行动作
+ }
+ break;
+
+ /* ── DP6 震动触发开机 (bool) ── */
+ case DP_ID_SHAKE_WAKE:
+ if (ctrl->shake_wake)
+ {
+ gDevData.shake_wake = 1;
+ // TODO: 开 — 执行动作
+ }
+ else
+ {
+ gDevData.shake_wake = 0;
+ // TODO: 关 — 执行动作
+ }
+ break;
+
+ /* ── DP7 勿扰模式开关 (raw) ── */
+ case DP_ID_NO_DISTURB_ENABLE:
+ memcpy(gDevData.no_disturb_enable, ctrl->no_disturb_enable, 13);
+ // TODO: 根据 gDevData.no_disturb_enable 执行动作 (长度 13 字节)
+ break;
+
+ /* ── DP8 预留DP1 (uint32) ── */
+ case DP_ID_RESERVA_DP1:
+ gDevData.reserva_dp1 = ctrl->reserva_dp1;
+ // TODO: 根据 ctrl->reserva_dp1 执行动作
+ break;
+
+ /* ── DP9 预留DP2 (uint32) ── */
+ case DP_ID_RESERVA_DP2:
+ gDevData.reserva_dp2 = ctrl->reserva_dp2;
+ // TODO: 根据 ctrl->reserva_dp2 执行动作
+ break;
+
+ /* ── DP10 预留DP3 (uint32) ── */
+ case DP_ID_RESERVA_DP3:
+ gDevData.reserva_dp3 = ctrl->reserva_dp3;
+ // TODO: 根据 ctrl->reserva_dp3 执行动作
+ break;
+
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+/* 0x30 OTA 升级请求 */
+void jbOnOtaNotify(uint32_t fwVersion, uint32_t fwLength, uint32_t fwCrc32)
+{
+ (void)fwVersion; (void)fwLength; (void)fwCrc32;
+ // TODO: 检查 Flash 空间与版本,决定是否接收升级
+ // 允许: 直接返回(协议层默认应答 JB_OK + MaxDataLen=128)
+ // 拒绝: 在 jbHandleOtaNotify 中改为 jbSendFrame(CMD_OTA_NOTIFY_ACK, sn, 错误码, 3)
+}
+
+/* 0x32 OTA 数据(含分片序号)*/
+void jbOnOtaData(const uint8_t *data, uint16_t len,
+ uint16_t shardIdx, uint16_t totalShards)
+{
+ (void)data; (void)len; (void)shardIdx; (void)totalShards;
+ // TODO: 写入 Flash,累计 CRC32
+ // 全部数据接收完成后调用 jbSendOtaResult(JB_OK, mcuVersion)
+}
+
+/* 0x36 / 0x38 停止 OTA */
+void jbOnOtaStop(void)
+{
+ // TODO: 终止 OTA,释放资源
+}
+
+/* 任意 MCU→BLE 请求的 ACK 回调(cmd 标识是哪条请求的应答,result 为结果码)
+ - SOC 仅保留 OTA 主动请求应答: OTA完成 0x35 / 停止 0x39
+ - 可在本回调中设置"XX 完成/失败"标志,供主循环判断"确认成功才继续" */
+void jbOnAck(uint8_t cmd, uint8_t result)
+{
+ (void)cmd; (void)result;
+ // TODO: switch(cmd){ case CMD_OTA_COMPLETE_ACK: gOtaDone = (result==JB_OK); break; case CMD_OTA_STOP_MCU_ACK: ... }
+}
+
+/* ════════════════════════════════════════════════════════════════
+ * 硬件抽象(按实际平台实现)
+ * ════════════════════════════════════════════════════════════════ */
+
+/* ── 定时器 ── */
+void jbTimerIrq(void)
+{
+ timerMs++;
+} /* 在 1ms 中断中调用本函数 */
+
+uint32_t jbGetTimerCount(void)
+{
+ return timerMs;
+}
+
+/* SOC: 发送由 SOC SDK 的 ble_send_data 承担,无需 uartInit / uartWrite;
+ * 定时器由 SOC SDK 提供,仅保留 jbTimerIrq / jbGetTimerCount 接入即可。 */
diff --git a/apps/usr_jb_proto/Protocol/jb_product.h b/apps/usr_jb_proto/Protocol/jb_product.h
new file mode 100644
index 0000000..af034db
--- /dev/null
+++ b/apps/usr_jb_proto/Protocol/jb_product.h
@@ -0,0 +1,55 @@
+/* ================================================================
+ * jb_product.h — 用户层头文件(自动生成)
+ * 设备: 侠客猫激光 | 生成时间: 2026-07-31 17:08:51
+ *
+ * 声明用户需实现的函数。数据结构定义见 jb_protocol.h
+ * ================================================================
+ */
+
+#ifndef _JB_PRODUCT_H
+#define _JB_PRODUCT_H
+
+#include "jb_protocol.h"
+
+/* ════════════════════════════════════════════════════════════════
+ * 硬件配置(SOC SDK 已提供定时器,无需 UART 波特率配置)
+ * ════════════════════════════════════════════════════════════════ */
+#define TIMER_PERIOD_MS 1
+
+/* ════════════════════════════════════════════════════════════════
+ * 版本管理
+ * ════════════════════════════════════════════════════════════════ */
+/* MCU software version: Vmajor.minor.patch */
+#define JB_MCU_SW_VERSION_MAJOR 1
+#define JB_MCU_SW_VERSION_MINOR 0
+#define JB_MCU_SW_VERSION_PATCH 0
+
+/* MCU hardware version: Vmajor.minor.patch */
+#define JB_MCU_HW_VERSION_MAJOR 1
+#define JB_MCU_HW_VERSION_MINOR 0
+#define JB_MCU_HW_VERSION_PATCH 0
+
+/* ════════════════════════════════════════════════════════════════
+ * 用户 API
+ * ════════════════════════════════════════════════════════════════ */
+
+/* 全局设备数据 — 协议层直接读写该变量 */
+extern jb_data_point_t gDevData;
+
+/* ==================== 用户必须实现 ============================== */
+void userInit(void); /* DP 默认值与外设初始化 */
+void userHandle(void); /* 用户数据采集 */
+void jbTimerIrq(void); /* Call from 1ms timer ISR */
+
+/* =========== 协议回调(声明见 jb_protocol.h)================== */
+/* int8_t jbEventProcess(...); // 0x03 控制事件 */
+/* void jbOnOtaNotify(...); // 0x30 OTA 请求 */
+/* void jbOnOtaData(...); // 0x32 OTA 数据 */
+/* void jbOnOtaStop(); // 0x36/0x38 停止 OTA */
+/* void jbOnAck(...); // 任意请求 ACK(结果) */
+
+/* ============= 主动请求(声明见 jb_protocol.h)================ */
+/* int32_t jbNotifyOtaStop(); // 0x38 通知 BLE 停止 OTA */
+/* int32_t jbSendOtaResult(...); // 0x34 OTA 结果 */
+
+#endif /* _JB_PRODUCT_H */
diff --git a/apps/usr_jb_proto/Protocol/jb_protocol.c b/apps/usr_jb_proto/Protocol/jb_protocol.c
new file mode 100644
index 0000000..4fc8ec2
--- /dev/null
+++ b/apps/usr_jb_proto/Protocol/jb_protocol.c
@@ -0,0 +1,749 @@
+/* ================================================================
+ * jb_protocol.c — 见宝 IOT 协议实现(自动生成)
+ * 设备: 侠客猫激光 | 生成时间: 2026-07-31 17:08:51
+ * ================================================================
+ */
+
+#include "jb_protocol.h"
+#include "jb_product.h"
+#include "jb_ringbuffer.h"
+#include "jb_common.h"
+
+/* ════════════════════════════════════════════════════════════════
+ * 全局实例
+ * ════════════════════════════════════════════════════════════════ */
+jb_protocol_t jbProtocol;
+static jb_ringbuffer_t rb; /* UART 接收缓冲区 */
+
+/* ════════════════════════════════════════════════════════════════
+ * jbInit — 协议层初始化
+ * ════════════════════════════════════════════════════════════════ */
+void jbInit(void)
+{
+ memset(&jbProtocol, 0, sizeof(jb_protocol_t));
+ jbRbInit(&rb);
+}
+
+/* ════════════════════════════════════════════════════════════════
+ * jbPutData — UART 中断将数据压入环形缓冲区
+ * ════════════════════════════════════════════════════════════════ */
+int32_t jbPutData(uint8_t *buf, uint32_t len)
+{
+ if (!buf)
+{
+ return -1;
+ }
+ for (uint32_t i = 0; i < len; i++)
+ {
+ jbRbPush(&rb, buf[i]);
+ }
+ return (int32_t)len;
+}
+
+/* ════════════════════════════════════════════════════════════════
+ * jbSendFrame — 组装协议帧并经 ble_send_data 发送(SOC 无串口)
+ * 返回帧总长度,< 0 表示出错
+ * ════════════════════════════════════════════════════════════════ */
+static int32_t jbSendFrame(uint8_t cmd, uint8_t sn,
+ const uint8_t *payload, uint16_t pLen)
+{
+ uint8_t buf[MAX_PACKAGE_LEN];
+ uint16_t lenField = pLen + 3; /* CMD + SN + payload + CKSUM */
+ uint16_t total = lenField + 4;
+
+ if (total > MAX_PACKAGE_LEN)
+ {
+ return -1;
+ }
+
+ /* 55 AA | LEN_H LEN_L | CMD | SN | payload | CKSUM */
+ buf[0] = PKT_HEAD_0;
+ buf[1] = PKT_HEAD_1;
+ jbWriteU16BE(&buf[2], lenField);
+ buf[4] = cmd;
+ buf[5] = sn;
+ if (payload && pLen > 0)
+ {
+ memcpy(&buf[6], payload, pLen);
+ }
+ buf[total - 1] = jbChecksum(buf, total);
+
+ ble_send_data(buf, total);
+ return (int32_t)total;
+}
+
+/* 发送单字节结果应答 */
+static void jbSendAck(uint8_t cmd, uint8_t sn, uint8_t result)
+{
+ jbSendFrame(cmd, sn, &result, 1);
+}
+
+/* ════════════════════════════════════════════════════════════════
+ * jbGetOnePacket — 从环形缓冲区提取完整帧
+ * 返回: 0 = 成功, 1 = 需要更多数据, -2 = 校验和错误
+ * ════════════════════════════════════════════════════════════════ */
+static int8_t jbGetOnePacket(uint8_t *out, uint16_t *outLen)
+{
+ static uint8_t state = 0;
+ static uint16_t expect = 0;
+ static uint16_t idx = 0;
+ static uint8_t prev = 0;
+
+ while (jbRbAvailable(&rb))
+ {
+ uint8_t b = jbRbPop(&rb);
+
+ if (state == 0)
+ {
+ /* 搜索同步头 55 AA */
+ if (prev == PKT_HEAD_0 && b == PKT_HEAD_1)
+ {
+ out[0] = PKT_HEAD_0;
+ out[1] = PKT_HEAD_1;
+ idx = 2;
+ state = 1;
+ }
+ }
+ else if (state == 1)
+ {
+ /* 接收 LEN(2B) + CMD + SN */
+ out[idx++] = b;
+ if (idx == 6)
+ {
+ expect = 4 + jbReadU16BE(&out[2]);
+ if (expect > MAX_PACKAGE_LEN || expect < 7)
+ {
+ state = 0;
+ }
+ else
+ {
+ state = 2;
+ }
+ }
+ }
+ else
+ {
+ /* 接收剩余数据 */
+ out[idx++] = b;
+ if (idx >= expect)
+ {
+ state = 0;
+ if (out[expect - 1] == jbChecksum(out, expect))
+ {
+ *outLen = expect;
+ return 0;
+ }
+ return -2;
+ }
+ }
+ prev = b;
+ }
+ return 1;
+}
+
+/* ════════════════════════════════════════════════════════════════
+ * jbPackDps — dataPoint → outBuf[bitmap | values]
+ * mask 指定要打包的 DP(bit 序号 = DP ID)
+ * 返回 outBuf 总字节数(bitmap + values)
+ * 仅打包 RO / RW 方向的 DP
+ * ════════════════════════════════════════════════════════════════ */
+static uint16_t jbPackDps(const jb_data_point_t *dp,
+ const uint8_t *mask, uint8_t *outBuf)
+{
+ uint8_t *bitmap = outBuf;
+ uint8_t *out = outBuf + DP_BITMAP_SIZE;
+ uint16_t valIdx = 0;
+ memset(bitmap, 0, DP_BITMAP_SIZE);
+
+ /* DP0 开关 (bool, 1B, RW) */
+ if (mask[DP_ID_POWER / 8] & (1 << (DP_ID_POWER % 8)))
+ {
+ bitmap[DP_ID_POWER / 8] |= (1 << (DP_ID_POWER % 8));
+ out[valIdx++] = dp->power ? 1 : 0;
+ }
+ /* DP1 自动模式 (enum, 1B, RW) */
+ if (mask[DP_ID_PLAY_MODE / 8] & (1 << (DP_ID_PLAY_MODE % 8)))
+ {
+ bitmap[DP_ID_PLAY_MODE / 8] |= (1 << (DP_ID_PLAY_MODE % 8));
+ out[valIdx++] = (uint8_t)dp->play_mode;
+ }
+ /* DP3 低电量报警 (bool, 1B, RO) */
+ if (mask[DP_ID_ALM_LOW_BATTERY / 8] & (1 << (DP_ID_ALM_LOW_BATTERY % 8)))
+ {
+ bitmap[DP_ID_ALM_LOW_BATTERY / 8] |= (1 << (DP_ID_ALM_LOW_BATTERY % 8));
+ out[valIdx++] = dp->alm_low_battery ? 1 : 0;
+ }
+ /* DP4 声音开关 (bool, 1B, RW) */
+ if (mask[DP_ID_BEEP_TRIG / 8] & (1 << (DP_ID_BEEP_TRIG % 8)))
+ {
+ bitmap[DP_ID_BEEP_TRIG / 8] |= (1 << (DP_ID_BEEP_TRIG % 8));
+ out[valIdx++] = dp->beep_trig ? 1 : 0;
+ }
+ /* DP5 电量上报 (uint8, 1B, RO) */
+ if (mask[DP_ID_BATTERY / 8] & (1 << (DP_ID_BATTERY % 8)))
+ {
+ bitmap[DP_ID_BATTERY / 8] |= (1 << (DP_ID_BATTERY % 8));
+ out[valIdx++] = (uint8_t)dp->battery;
+ }
+ /* DP6 震动触发开机 (bool, 1B, RW) */
+ if (mask[DP_ID_SHAKE_WAKE / 8] & (1 << (DP_ID_SHAKE_WAKE % 8)))
+ {
+ bitmap[DP_ID_SHAKE_WAKE / 8] |= (1 << (DP_ID_SHAKE_WAKE % 8));
+ out[valIdx++] = dp->shake_wake ? 1 : 0;
+ }
+ /* DP7 勿扰模式开关 (raw, 13B, RW) */
+ if (mask[DP_ID_NO_DISTURB_ENABLE / 8] & (1 << (DP_ID_NO_DISTURB_ENABLE % 8)))
+ {
+ bitmap[DP_ID_NO_DISTURB_ENABLE / 8] |= (1 << (DP_ID_NO_DISTURB_ENABLE % 8));
+ memcpy(&out[valIdx], dp->no_disturb_enable, 13);
+ valIdx += 13;
+ }
+ /* DP8 预留DP1 (uint32, 4B, RW) */
+ if (mask[DP_ID_RESERVA_DP1 / 8] & (1 << (DP_ID_RESERVA_DP1 % 8)))
+ {
+ bitmap[DP_ID_RESERVA_DP1 / 8] |= (1 << (DP_ID_RESERVA_DP1 % 8));
+ jbWriteU32BE(&out[valIdx], (uint32_t)dp->reserva_dp1);
+ valIdx += 4;
+ }
+ /* DP9 预留DP2 (uint32, 4B, RW) */
+ if (mask[DP_ID_RESERVA_DP2 / 8] & (1 << (DP_ID_RESERVA_DP2 % 8)))
+ {
+ bitmap[DP_ID_RESERVA_DP2 / 8] |= (1 << (DP_ID_RESERVA_DP2 % 8));
+ jbWriteU32BE(&out[valIdx], (uint32_t)dp->reserva_dp2);
+ valIdx += 4;
+ }
+ /* DP10 预留DP3 (uint32, 4B, RW) */
+ if (mask[DP_ID_RESERVA_DP3 / 8] & (1 << (DP_ID_RESERVA_DP3 % 8)))
+ {
+ bitmap[DP_ID_RESERVA_DP3 / 8] |= (1 << (DP_ID_RESERVA_DP3 % 8));
+ jbWriteU32BE(&out[valIdx], (uint32_t)dp->reserva_dp3);
+ valIdx += 4;
+ }
+
+ return DP_BITMAP_SIZE + valIdx;
+}
+
+/* ════════════════════════════════════════════════════════════════
+ * jbUnpackDps — bitmap+values → dataPoint + event_info
+ * 仅解包 WO / RW 方向的 DP
+ * ════════════════════════════════════════════════════════════════ */
+static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
+ uint16_t valLen, jb_data_point_t *dp,
+ jb_event_info_t *info)
+{
+ uint16_t valIdx = 0;
+ if (info)
+ {
+ info->count = 0;
+ }
+
+ /* DP0 开关 (bool, 1B, RW) */
+ if (bitmap[DP_ID_POWER / 8] & (1 << (DP_ID_POWER % 8)))
+ {
+ if (valIdx < valLen)
+ {
+ dp->power = (values[valIdx++] != 0);
+ }
+ if (info && info->count < DP_ID_MAX)
+ {
+ info->dp_ids[info->count++] = DP_ID_POWER;
+ }
+ }
+ /* DP1 自动模式 (enum, 1B, RW) */
+ if (bitmap[DP_ID_PLAY_MODE / 8] & (1 << (DP_ID_PLAY_MODE % 8)))
+ {
+ if (valIdx < valLen)
+ {
+ dp->play_mode = values[valIdx++];
+ }
+ if (info && info->count < DP_ID_MAX)
+ {
+ info->dp_ids[info->count++] = DP_ID_PLAY_MODE;
+ }
+ }
+ /* DP2 手动模式 (enum, 1B, WO) */
+ if (bitmap[DP_ID_HAND_MODE / 8] & (1 << (DP_ID_HAND_MODE % 8)))
+ {
+ if (valIdx < valLen)
+ {
+ dp->hand_mode = values[valIdx++];
+ }
+ if (info && info->count < DP_ID_MAX)
+ {
+ info->dp_ids[info->count++] = DP_ID_HAND_MODE;
+ }
+ }
+ /* DP4 声音开关 (bool, 1B, RW) */
+ if (bitmap[DP_ID_BEEP_TRIG / 8] & (1 << (DP_ID_BEEP_TRIG % 8)))
+ {
+ if (valIdx < valLen)
+ {
+ dp->beep_trig = (values[valIdx++] != 0);
+ }
+ if (info && info->count < DP_ID_MAX)
+ {
+ info->dp_ids[info->count++] = DP_ID_BEEP_TRIG;
+ }
+ }
+ /* DP6 震动触发开机 (bool, 1B, RW) */
+ if (bitmap[DP_ID_SHAKE_WAKE / 8] & (1 << (DP_ID_SHAKE_WAKE % 8)))
+ {
+ if (valIdx < valLen)
+ {
+ dp->shake_wake = (values[valIdx++] != 0);
+ }
+ if (info && info->count < DP_ID_MAX)
+ {
+ info->dp_ids[info->count++] = DP_ID_SHAKE_WAKE;
+ }
+ }
+ /* DP7 勿扰模式开关 (raw, 13B, RW) */
+ if (bitmap[DP_ID_NO_DISTURB_ENABLE / 8] & (1 << (DP_ID_NO_DISTURB_ENABLE % 8)))
+ {
+ if (valIdx + 13 <= valLen)
+ {
+ memcpy(dp->no_disturb_enable, &values[valIdx], 13);
+ valIdx += 13;
+ }
+ if (info && info->count < DP_ID_MAX)
+ {
+ info->dp_ids[info->count++] = DP_ID_NO_DISTURB_ENABLE;
+ }
+ }
+ /* DP8 预留DP1 (uint32, 4B, RW) */
+ if (bitmap[DP_ID_RESERVA_DP1 / 8] & (1 << (DP_ID_RESERVA_DP1 % 8)))
+ {
+ if (valIdx + 4 <= valLen)
+ {
+ dp->reserva_dp1 = (uint32_t)jbReadU32BE(&values[valIdx]);
+ valIdx += 4;
+ }
+ if (info && info->count < DP_ID_MAX)
+ {
+ info->dp_ids[info->count++] = DP_ID_RESERVA_DP1;
+ }
+ }
+ /* DP9 预留DP2 (uint32, 4B, RW) */
+ if (bitmap[DP_ID_RESERVA_DP2 / 8] & (1 << (DP_ID_RESERVA_DP2 % 8)))
+ {
+ if (valIdx + 4 <= valLen)
+ {
+ dp->reserva_dp2 = (uint32_t)jbReadU32BE(&values[valIdx]);
+ valIdx += 4;
+ }
+ if (info && info->count < DP_ID_MAX)
+ {
+ info->dp_ids[info->count++] = DP_ID_RESERVA_DP2;
+ }
+ }
+ /* DP10 预留DP3 (uint32, 4B, RW) */
+ if (bitmap[DP_ID_RESERVA_DP3 / 8] & (1 << (DP_ID_RESERVA_DP3 % 8)))
+ {
+ if (valIdx + 4 <= valLen)
+ {
+ dp->reserva_dp3 = (uint32_t)jbReadU32BE(&values[valIdx]);
+ valIdx += 4;
+ }
+ if (info && info->count < DP_ID_MAX)
+ {
+ info->dp_ids[info->count++] = DP_ID_RESERVA_DP3;
+ }
+ }
+}
+
+/* ════════════════════════════════════════════════════════════════
+ * jbBuildDiffMask — 比较上次与当前值,为变化的可上报 DP 置 mask 位
+ * 返回: 1 = 有 DP 发生变化, 0 = 全部未变化
+ * ════════════════════════════════════════════════════════════════ */
+static uint8_t jbBuildDiffMask(const jb_data_point_t *last,
+ const jb_data_point_t *cur,
+ uint8_t *mask)
+{
+ uint8_t hasChange = 0;
+ memset(mask, 0, DP_BITMAP_SIZE);
+
+ /* DP0 开关 */
+ if (last->power != cur->power)
+ {
+ mask[DP_ID_POWER / 8] |= (1 << (DP_ID_POWER % 8));
+ hasChange = 1;
+ }
+ /* DP1 自动模式 */
+ if (last->play_mode != cur->play_mode)
+ {
+ mask[DP_ID_PLAY_MODE / 8] |= (1 << (DP_ID_PLAY_MODE % 8));
+ hasChange = 1;
+ }
+ /* DP3 低电量报警 */
+ if (last->alm_low_battery != cur->alm_low_battery)
+ {
+ mask[DP_ID_ALM_LOW_BATTERY / 8] |= (1 << (DP_ID_ALM_LOW_BATTERY % 8));
+ hasChange = 1;
+ }
+ /* DP4 声音开关 */
+ if (last->beep_trig != cur->beep_trig)
+ {
+ mask[DP_ID_BEEP_TRIG / 8] |= (1 << (DP_ID_BEEP_TRIG % 8));
+ hasChange = 1;
+ }
+ /* DP5 电量上报 */
+ if (last->battery != cur->battery)
+ {
+ mask[DP_ID_BATTERY / 8] |= (1 << (DP_ID_BATTERY % 8));
+ hasChange = 1;
+ }
+ /* DP6 震动触发开机 */
+ if (last->shake_wake != cur->shake_wake)
+ {
+ mask[DP_ID_SHAKE_WAKE / 8] |= (1 << (DP_ID_SHAKE_WAKE % 8));
+ hasChange = 1;
+ }
+ /* DP7 勿扰模式开关 */
+ if (memcmp(last->no_disturb_enable, cur->no_disturb_enable, 13))
+ {
+ mask[DP_ID_NO_DISTURB_ENABLE / 8] |= (1 << (DP_ID_NO_DISTURB_ENABLE % 8));
+ hasChange = 1;
+ }
+ /* DP8 预留DP1 */
+ if (last->reserva_dp1 != cur->reserva_dp1)
+ {
+ mask[DP_ID_RESERVA_DP1 / 8] |= (1 << (DP_ID_RESERVA_DP1 % 8));
+ hasChange = 1;
+ }
+ /* DP9 预留DP2 */
+ if (last->reserva_dp2 != cur->reserva_dp2)
+ {
+ mask[DP_ID_RESERVA_DP2 / 8] |= (1 << (DP_ID_RESERVA_DP2 % 8));
+ hasChange = 1;
+ }
+ /* DP10 预留DP3 */
+ if (last->reserva_dp3 != cur->reserva_dp3)
+ {
+ mask[DP_ID_RESERVA_DP3 / 8] |= (1 << (DP_ID_RESERVA_DP3 % 8));
+ hasChange = 1;
+ }
+
+ return hasChange;
+}
+
+/* 置全量掩码(所有可上报 DP)*/
+static void jbSetFullMask(uint8_t *mask)
+{
+ memset(mask, 0xFF, DP_BITMAP_SIZE);
+ if (DP_COUNT % 8)
+ {
+ mask[DP_BITMAP_SIZE - 1] &= (1 << (DP_COUNT % 8)) - 1;
+ }
+}
+
+/* ════════════════════════════════════════════════════════════════
+ * jbSendReqWithAck — 发送请求帧并登记 ACK 重传
+ *
+ * 与 jbSendFrame 不同,本函数把完整帧缓存到 waitAck.buf,
+ * 并启动 ACK 等待。主动上报 / OTA 等网关应答均走 REPORTCMD_V2,
+ * 由 jbReportAckCheck() 清除等待;若 SEND_MAX_TIME 内未收到,
+ * jbAckRetry() 自动重传,最多 SEND_MAX_NUM 次。
+ * 返回 ble_send_data 结果(<0 出错)。
+ * ════════════════════════════════════════════════════════════════ */
+static int32_t jbSendReqWithAck(uint8_t cmd, uint8_t sn,
+ const uint8_t *payload, uint16_t pLen)
+{
+ uint16_t lenField = pLen + 3; /* CMD + SN + payload + CKSUM */
+ uint16_t total = lenField + 4; /* + 55 AA + LEN(2) */
+
+ if (total > MAX_PACKAGE_LEN)
+ {
+ return -1;
+ }
+
+ uint8_t buf[MAX_PACKAGE_LEN];
+ buf[0] = PKT_HEAD_0;
+ buf[1] = PKT_HEAD_1;
+ jbWriteU16BE(&buf[2], lenField);
+ buf[4] = cmd;
+ buf[5] = sn;
+ if (payload && pLen > 0)
+ {
+ memcpy(&buf[6], payload, pLen);
+ }
+ buf[total - 1] = jbChecksum(buf, total);
+
+ /* 缓存整帧,供超时重传 */
+ memcpy(jbProtocol.waitAck.buf, buf, total);
+ jbProtocol.waitAck.len = total;
+ jbProtocol.waitAck.active = 1;
+ jbProtocol.waitAck.sn = sn;
+ jbProtocol.waitAck.retry = 0;
+ jbProtocol.waitAck.sendTime = jbGetTimerCount();
+
+ ble_send_data(buf, total);
+ return (int32_t)total;
+}
+
+/* ════════════════════════════════════════════════════════════════
+ * jbAckRetry — ACK 超时重传
+ * ════════════════════════════════════════════════════════════════ */
+static void jbAckRetry(void)
+{
+ if (!jbProtocol.waitAck.active)
+ {
+ return;
+ }
+ if (jbProtocol.waitAck.retry >= SEND_MAX_NUM)
+ {
+ memset(&jbProtocol.waitAck, 0, sizeof(jb_wait_ack_t));
+ return;
+ }
+ if (jbGetTimerCount() - jbProtocol.waitAck.sendTime > SEND_MAX_TIME)
+ {
+ ble_send_data(jbProtocol.waitAck.buf, jbProtocol.waitAck.len);
+ jbProtocol.waitAck.retry++;
+ jbProtocol.waitAck.sendTime = jbGetTimerCount();
+ }
+}
+
+/* ════════════════════════════════════════════════════════════════
+ * jbReportAckCheck — 网关应答确认(主动上报 / OTA 共用)
+ *
+ * 网关通过 REPORTCMD_V2 回传(非 55AA)。成功条件:
+ * cmd == 0
+ * gateway_int_cnt == 1
+ * gateway_int0 == 0
+ * 满足则清除 waitAck,停止重传,并回调 jbOnAck(wait_cmd, 0)。
+ *
+ * 返回: 1=成功并清除等待; 0=未命中/条件不符。
+ * ════════════════════════════════════════════════════════════════ */
+int8_t jbReportAckCheck(uint16_t cmd, uint8_t gateway_int_cnt, int32_t gateway_int0)
+{
+ if (!jbProtocol.waitAck.active)
+ {
+ return 0;
+ }
+ if (cmd == 0 && gateway_int_cnt == 1 && gateway_int0 == 0)
+ {
+ uint8_t wait_cmd = jbProtocol.waitAck.buf[4];
+ memset(&jbProtocol.waitAck, 0, sizeof(jb_wait_ack_t));
+ jbOnAck(wait_cmd, 0); /* result=0 表示应答成功 */
+ return 1;
+ }
+ return 0;
+}
+
+/* ════════════════════════════════════════════════════════════════
+ * jbSendReport — 发送主动上报 (0x07)
+ *
+ * mask 指定本次上报包含哪些 DP:
+ * - 差分掩码(来自 jbBuildDiffMask) → 仅上报变化的 DP
+ * - 全量掩码(来自 jbSetFullMask) → 定时全量同步
+ * ════════════════════════════════════════════════════════════════ */
+static void jbSendReport(jb_data_point_t *data, const uint8_t *mask)
+{
+ uint8_t payload[MAX_PACKAGE_LEN];
+ uint16_t plen = jbPackDps(data, mask, payload);
+ uint8_t sn = jbProtocol.sn++;
+ jbSendReqWithAck(CMD_REPORT, sn, payload, plen);
+}
+
+/* ════════════════════════════════════════════════════════════════
+ * jbReportPolicy — 变化上报(差分) + 定时上报(全量)
+ *
+ * 策略:
+ * 1. DP 发生变化 → 仅上报变化的 DP(差分掩码)
+ * 2. 每隔 REPORT_PERIOD ms → 上报全部可上报 DP(全量同步)
+ * ════════════════════════════════════════════════════════════════ */
+static void jbReportPolicy(jb_data_point_t *data)
+{
+ uint32_t now = jbGetTimerCount();
+ uint8_t diffMask[DP_BITMAP_SIZE];
+
+ /* ── 1. 变化上报(差分) ── */
+ uint8_t hasChange = jbBuildDiffMask(&jbProtocol.lastData, data, diffMask);
+ if (hasChange && !jbProtocol.waitAck.active &&
+ (now - jbProtocol.lastChangeTime > REPORT_DEBOUNCE))
+ {
+ jbSendReport(data, diffMask);
+ memcpy(&jbProtocol.lastData, data, sizeof(jb_data_point_t));
+ jbProtocol.lastChangeTime = now;
+ jbProtocol.lastReportTime = now;
+ return;
+ }
+
+ /* ── 2. 定时全量上报 ── */
+ if (!jbProtocol.waitAck.active &&
+ (now - jbProtocol.lastReportTime > REPORT_PERIOD))
+ {
+ uint8_t fullMask[DP_BITMAP_SIZE];
+ jbSetFullMask(fullMask);
+ jbSendReport(data, fullMask);
+ memcpy(&jbProtocol.lastData, data, sizeof(jb_data_point_t));
+ jbProtocol.lastReportTime = now;
+ }
+}
+
+/* ════════════════════════════════════════════════════════════════
+ * 命令处理函数(BLE → MCU 下行帧)
+ * ════════════════════════════════════════════════════════════════ */
+
+/* ── 0x03 APP 下发控制 ── */
+static void jbHandleControl(uint8_t *frame, uint16_t len)
+{
+ uint8_t sn = frame[5];
+ uint8_t *bitmap = &frame[6];
+ uint8_t *values = &frame[6 + DP_BITMAP_SIZE];
+ uint16_t valLen = len - 7 - DP_BITMAP_SIZE;
+
+ jb_event_info_t info;
+ jb_data_point_t ctrlData;
+ memset(&ctrlData, 0, sizeof(ctrlData));
+ jbUnpackDps(bitmap, values, valLen, &ctrlData, &info);
+
+ /* 分发给用户层;用户在回调中更新 gDevData */
+ jbEventProcess(&info, &ctrlData);
+ jbSendAck(CMD_CONTROL_ACK, sn, JB_OK);
+}
+
+/* ── 0x05 APP 读取请求 ── */
+static void jbHandleRead(uint8_t *frame, uint16_t len,
+ jb_data_point_t *data)
+{
+ uint8_t sn = frame[5];
+ uint8_t *reqBitmap = &frame[6];
+
+ uint8_t mask[DP_BITMAP_SIZE];
+ memcpy(mask, reqBitmap, DP_BITMAP_SIZE);
+
+ /* bitmap 全 1(=0xFF...) 表示读取全部 DP */
+ uint8_t allOnes = 1;
+ for (int i = 0; i < DP_BITMAP_SIZE; i++)
+ {
+ if (mask[i] != 0xFF)
+ {
+ allOnes = 0;
+ break;
+ }
+ }
+ if (allOnes)
+ {
+ jbSetFullMask(mask);
+ }
+
+ uint8_t payload[MAX_PACKAGE_LEN];
+ uint16_t plen = jbPackDps(data, mask, payload);
+ jbSendFrame(CMD_READ_ACK, sn, payload, plen);
+}
+
+/* ── 0x30 OTA 升级请求 ── */
+static void jbHandleOtaNotify(uint8_t *frame, uint16_t len)
+{
+ uint8_t sn = frame[5];
+ uint32_t fwVersion = ((uint32_t)frame[6] << 16)
+ | ((uint32_t)frame[7] << 8)
+ | frame[8];
+ uint32_t fwLength = jbReadU32BE(&frame[9]);
+ uint32_t fwCrc32 = jbReadU32BE(&frame[13]);
+
+ jbOnOtaNotify(fwVersion, fwLength, fwCrc32);
+
+ /* 默认应答: 结果码 + 最大单包长度(2B) */
+ /* maxDataLen 由 MCU 自身能力决定,填入 0x31 应答,BLE 据此分片 */
+ uint8_t ack[3];
+ ack[0] = JB_OK;
+ ack[1] = (uint8_t)(JB_OTA_MAX_PAYLOAD >> 8);
+ ack[2] = (uint8_t)(JB_OTA_MAX_PAYLOAD & 0xFF);
+ jbSendFrame(CMD_OTA_NOTIFY_ACK, sn, ack, 3);
+}
+
+/* ── 0x32 OTA 数据(含分片序号)── */
+static void jbHandleOtaData(uint8_t *frame, uint16_t len)
+{
+ uint8_t sn = frame[5];
+ uint16_t shardIdx = jbReadU16BE(&frame[6]);
+ uint16_t totalShards = jbReadU16BE(&frame[8]);
+ const uint8_t *pData = &frame[10];
+ uint16_t dataLen = (len > 11) ? (len - 11) : 0;
+ jbOnOtaData(pData, dataLen, shardIdx, totalShards);
+ jbSendAck(CMD_OTA_DATA_ACK, sn, JB_OK);
+}
+
+/* ── 0x36 BLE 通知停止 OTA ── */
+static void jbHandleOtaStop(uint8_t *frame, uint16_t len)
+{
+ uint8_t sn = frame[5];
+ jbOnOtaStop();
+ jbSendAck(CMD_OTA_STOP_BLE_ACK, sn, JB_OK);
+}
+
+/* 0x38 通知 BLE 停止 OTA(MCU 主动,等待 ACK 重传)*/
+int32_t jbNotifyOtaStop(void)
+{
+ uint8_t sn = jbProtocol.sn++;
+ return jbSendReqWithAck(CMD_OTA_STOP_MCU, sn, NULL, 0);
+}
+
+/* 0x34 OTA 升级完成(result + MCU 版本 3B,等待 ACK 重传)*/
+int32_t jbSendOtaResult(uint8_t result, const uint8_t *mcuVersion)
+{
+ uint8_t sn = jbProtocol.sn++;
+ uint8_t payload[4];
+ payload[0] = result;
+ if (mcuVersion)
+ {
+ memcpy(&payload[1], mcuVersion, 3);
+ }
+ else
+ {
+ memset(&payload[1], 0, 3);
+ }
+ return jbSendReqWithAck(CMD_OTA_COMPLETE, sn, payload, 4);
+}
+
+/* ════════════════════════════════════════════════════════════════
+ * jbProtocolHandle — 协议主循环(在 while(1) 中调用)
+ * ════════════════════════════════════════════════════════════════ */
+int32_t jbProtocolHandle(jb_data_point_t *data)
+{
+ if (!data)
+ {
+ return -1;
+ }
+
+ /* ACK 超时重传 */
+ jbAckRetry();
+
+ /* 提取一帧 */
+ uint16_t pktLen = 0;
+ int8_t ret = jbGetOnePacket(jbProtocol.rxBuf, &pktLen);
+ uint8_t cmd;
+ if (ret == 0)
+ {
+ cmd = jbProtocol.rxBuf[4];
+
+ /* 按命令码统一分发 BLE → MCU 的所有帧(含 MCU 主动请求的应答)*/
+ switch (cmd)
+ {
+ /* ── APP-BLE 数据 ── */
+ case CMD_CONTROL:
+ jbHandleControl(jbProtocol.rxBuf, pktLen);
+ break;
+ case CMD_READ:
+ jbHandleRead(jbProtocol.rxBuf, pktLen, data);
+ break;
+ /* ── BLE-MCU OTA ── */
+ case CMD_OTA_NOTIFY:
+ jbHandleOtaNotify(jbProtocol.rxBuf, pktLen);
+ break;
+ case CMD_OTA_DATA:
+ jbHandleOtaData(jbProtocol.rxBuf, pktLen);
+ break;
+ case CMD_OTA_STOP_BLE:
+ jbHandleOtaStop(jbProtocol.rxBuf, pktLen);
+ break;
+ /* 主动上报 / OTA 完成&停止 的网关应答均走 REPORTCMD_V2 → jbReportAckCheck */
+ default:
+ break;
+ }
+ }
+
+ jbReportPolicy(data);
+ return 0;
+}
diff --git a/apps/usr_jb_proto/Protocol/jb_protocol.h b/apps/usr_jb_proto/Protocol/jb_protocol.h
new file mode 100644
index 0000000..e009008
--- /dev/null
+++ b/apps/usr_jb_proto/Protocol/jb_protocol.h
@@ -0,0 +1,266 @@
+/* ================================================================
+ * jb_protocol.h — 见宝 IOT 协议层(自动生成)
+ * 设备: 侠客猫激光 | DP 数: 11 | Bitmap: 2B
+ * 协议版本: V1.0 | 生成时间: 2026-07-31 17:08:51
+ *
+ * 帧格式: [55 AA] [LEN_H LEN_L] [CMD] [SN] [payload...] [CKSUM]
+ * LEN = CMD(1) + SN(1) + payload + CKSUM(1) = payload + 3
+ * CKSUM = sum(LEN_H .. payload_last) & 0xFF
+ * Bitmap = 每个 DP 占 1 bit,bit 序号 = DP ID(0 起始)
+ * Values = 按 bitmap 置位顺序排列,每个 DP 占完整 byte_length
+ * ================================================================
+ */
+
+#ifndef _JB_PROTOCOL_H
+#define _JB_PROTOCOL_H
+
+#include
+#include
+#include
+
+/* ════════════════════════════════════════════════════════════════
+ * 协议常量
+ * ════════════════════════════════════════════════════════════════ */
+#define PKT_HEAD_0 0x55
+#define PKT_HEAD_1 0xAA
+#define MAX_PACKAGE_LEN 128
+#define JB_OTA_MAX_PAYLOAD 96 /* OTA 单包 Payload 上限(Byte); 须 <= MAX_PACKAGE_LEN - 11(0x32 帧开销) */
+
+#define DP_COUNT 11
+#define DP_BITMAP_SIZE 2
+
+#define SEND_MAX_TIME 2500 /* ACK 重传超时(ms);BLE Indication往返常需数百ms~1s,过短会误重传导致双应答 */
+#define SEND_MAX_NUM 3 /* 最大重传次数 */
+#define REPORT_DEBOUNCE 2000 /* 变化上报防抖时间(ms) */
+#define REPORT_PERIOD 600000 /* 定时全量上报周期(ms) */
+
+/* Device identity: change these values for the target product.
+ * JB_CATEGORY_CODE: 必须 4 字符 ASCII,供 BLE 广播 prodcode 使用
+ * JB_PRODUCT_CODE : 必须 6 字符 ASCII,供 BLE 广播 pcode 使用
+ */
+#define JB_PROTOCOL_VERSION 0x0100 /* V1.0 */
+#define JB_CATEGORY_CODE "CBC0"
+#define JB_PRODUCT_CODE "PICBC0"
+#define JB_DEVICE_SN 0x00
+#define JB_DEVICE_CAPABILITY 0ULL
+
+/* ════════════════════════════════════════════════════════════════
+ * 命令码(见《MCU方案接入协议通讯文档》)
+ * ════════════════════════════════════════════════════════════════ */
+typedef enum
+{
+ /* ── APP-BLE 数据(6) ── */
+ CMD_CONTROL = 0x03, /* APP/BLE → MCU: 下发控制 */
+ CMD_CONTROL_ACK = 0x04, /* MCU → APP/BLE: 控制应答 */
+ CMD_READ = 0x05, /* APP/BLE → MCU: 读取请求 */
+ CMD_READ_ACK = 0x06, /* MCU → APP/BLE: 读取应答 */
+ CMD_REPORT = 0x07, /* MCU → APP/BLE: 主动上报 */
+ CMD_REPORT_ACK = 0x08, /* APP/BLE → MCU: 上报应答 */
+ /* ── OTA(10) ── */
+ CMD_OTA_NOTIFY = 0x30, /* BLE → MCU: OTA 升级请求 */
+ CMD_OTA_NOTIFY_ACK = 0x31, /* MCU → BLE: OTA 应答(含MaxLen) */
+ CMD_OTA_DATA = 0x32, /* BLE → MCU: OTA 数据 */
+ CMD_OTA_DATA_ACK = 0x33, /* MCU → BLE: OTA 数据应答 */
+ CMD_OTA_COMPLETE = 0x34, /* MCU → BLE: OTA 完成 */
+ CMD_OTA_COMPLETE_ACK = 0x35, /* BLE → MCU: OTA 完成应答 */
+ CMD_OTA_STOP_BLE = 0x36, /* BLE → MCU: 停止 OTA */
+ CMD_OTA_STOP_BLE_ACK = 0x37, /* MCU → BLE: 停止应答 */
+ CMD_OTA_STOP_MCU = 0x38, /* MCU → BLE: 通知停止 OTA */
+ CMD_OTA_STOP_MCU_ACK = 0x39, /* BLE → MCU: 停止应答 */
+} jb_cmd_t;
+
+/* ════════════════════════════════════════════════════════════════
+ * 结果码
+ * ════════════════════════════════════════════════════════════════ */
+typedef enum
+{
+ JB_OK = 0x00,
+ JB_PARAM_ERR = 0x01,
+ JB_BUSY = 0x02,
+ JB_NOT_SUPPORT = 0x03,
+ JB_CRC_ERR = 0x04,
+ JB_FAIL = 0x05,
+ /* ── OTA 专用错误码 ── */
+ JB_OTA_NO_NEED = 0x20, /* 无需升级(版本一致) */
+ JB_OTA_VER_LOW = 0x21, /* OTA 版本低于当前版本 */
+ JB_OTA_SPACE_ERR = 0x22, /* Flash 空间不足 */
+ JB_OTA_STATE_ERR = 0x23, /* OTA 状态错误 */
+ JB_OTA_FILE_ERR = 0x24, /* OTA 文件检验失败 */
+ JB_OTA_FAIL = 0x25, /* 升级失败 */
+} jb_result_t;
+
+/* ════════════════════════════════════════════════════════════════
+ * BLE 工作状态位 (0x14)
+ * ════════════════════════════════════════════════════════════════ */
+#define WS_CONFIGURED (1 << 0) /* 已配网 */
+#define WS_INTERNET (1 << 1) /* 已连外网 */
+#define WS_APP_ONLINE (1 << 2) /* App 在线 */
+#define WS_BLE_CONNECTED (1 << 3) /* 手机 BLE 已连接 */
+#define WS_OTA_UPGRADING (1 << 4) /* OTA 升级中 */
+#define WS_PAIRING_MODE (1 << 5) /* 配对模式激活 */
+
+/* ════════════════════════════════════════════════════════════════
+ * 设备能力位图 (0x02 Capability Bitmap, 8B 大端)
+ * ════════════════════════════════════════════════════════════════ */
+#define CAP_BLE_OTA (1ULL << 0) /* BLE OTA */
+#define CAP_MCU_OTA (1ULL << 1) /* MCU OTA */
+#define CAP_APP_DIRECT (1ULL << 2) /* APP 直连 BLE */
+#define CAP_IPC_GATEWAY (1ULL << 3) /* IPC 网关连接 */
+#define CAP_PRODUCTION (1ULL << 4) /* 产测模式 */
+#define CAP_PARAM_CFG (1ULL << 5) /* 参数配置 */
+#define CAP_LOG (1ULL << 6) /* 日志功能 */
+
+/* ════════════════════════════════════════════════════════════════
+ * 身份信息 (0x02) / MCU 信息 (0x41)
+ * ════════════════════════════════════════════════════════════════ */
+/* ════════════════════════════════════════════════════════════════
+ * DP ID 枚举(从 Excel 自动生成)
+ * ════════════════════════════════════════════════════════════════ */
+typedef enum
+{
+ DP_ID_POWER = 0, /* 开关 (bool, RW) */
+ DP_ID_PLAY_MODE = 1, /* 自动模式 (enum, RW) */
+ DP_ID_HAND_MODE = 2, /* 手动模式 (enum, WO) */
+ DP_ID_ALM_LOW_BATTERY = 3, /* 低电量报警 (bool, RO) */
+ DP_ID_BEEP_TRIG = 4, /* 声音开关 (bool, RW) */
+ DP_ID_BATTERY = 5, /* 电量上报 (uint8, RO) */
+ DP_ID_SHAKE_WAKE = 6, /* 震动触发开机 (bool, RW) */
+ DP_ID_NO_DISTURB_ENABLE = 7, /* 勿扰模式开关 (raw, RW) */
+ DP_ID_RESERVA_DP1 = 8, /* 预留DP1 (uint32, RW) */
+ DP_ID_RESERVA_DP2 = 9, /* 预留DP2 (uint32, RW) */
+ DP_ID_RESERVA_DP3 = 10, /* 预留DP3 (uint32, RW) */
+ DP_ID_MAX
+} dp_id_t;
+
+/* DP 数据长度(字节) */
+#define DP_LEN_POWER 1
+#define DP_LEN_PLAY_MODE 1
+#define DP_LEN_HAND_MODE 1
+#define DP_LEN_ALM_LOW_BATTERY 1
+#define DP_LEN_BEEP_TRIG 1
+#define DP_LEN_BATTERY 1
+#define DP_LEN_SHAKE_WAKE 1
+#define DP_LEN_NO_DISTURB_ENABLE 13
+#define DP_LEN_RESERVA_DP1 4
+#define DP_LEN_RESERVA_DP2 4
+#define DP_LEN_RESERVA_DP3 4
+
+/* ════════════════════════════════════════════════════════════════
+ * DP 枚举值定义
+ * ════════════════════════════════════════════════════════════════ */
+/* 自动模式 */
+typedef enum
+{
+ PLAY_MODE_0 = 0, /* 关 */
+ PLAY_MODE_1 = 1, /* mode1 */
+ PLAY_MODE_2 = 2, /* mode2 */
+ PLAY_MODE_3 = 3, /* mode3 */
+ PLAY_MODE_4 = 4, /* mode4 */
+} PLAY_MODE_t;
+
+/* 手动模式 */
+typedef enum
+{
+ HAND_MODE_0 = 0, /* 关 */
+ HAND_MODE_1 = 1, /* 顺时针 */
+ HAND_MODE_2 = 2, /* 逆时针 */
+} HAND_MODE_t;
+
+/* ════════════════════════════════════════════════════════════════
+ * 数据结构
+ * ════════════════════════════════════════════════════════════════ */
+
+/* 数据点 — 所有 DP 的当前值 */
+typedef struct
+{
+ uint8_t power; /* DP0 开关 */
+ uint8_t play_mode; /* DP1 自动模式 */
+ uint8_t hand_mode; /* DP2 手动模式 */
+ uint8_t alm_low_battery;/* DP3 低电量报警 */
+ uint8_t beep_trig; /* DP4 声音开关 */
+ uint8_t battery; /* DP5 电量上报 */
+ uint8_t shake_wake; /* DP6 震动触发开机 */
+ uint8_t no_disturb_enable[13];/* DP7 勿扰模式开关 */
+ uint32_t reserva_dp1; /* DP8 预留DP1 */
+ uint32_t reserva_dp2; /* DP9 预留DP2 */
+ uint32_t reserva_dp3; /* DP10 预留DP3 */
+} jb_data_point_t;
+
+/* 控制事件信息 */
+typedef struct
+{
+ uint8_t count;
+ uint8_t dp_ids[DP_ID_MAX];
+} jb_event_info_t;
+
+/* ACK 等待 / 重传管理器 */
+typedef struct
+{
+ uint8_t active; /* 是否有等待中的请求 */
+ uint8_t sn; /* 帧序列号 */
+ uint8_t retry;
+ uint8_t buf[MAX_PACKAGE_LEN];
+ uint16_t len;
+ uint32_t sendTime;
+} jb_wait_ack_t;
+
+/* 协议全局状态 */
+typedef struct
+{
+ uint8_t sn; /* 设备 SN 计数器 */
+ uint8_t rxBuf[MAX_PACKAGE_LEN];
+ jb_wait_ack_t waitAck; /* ACK 重传管理器 */
+ jb_data_point_t lastData; /* 上次上报快照 */
+ uint32_t lastReportTime; /* 上次上报时刻 */
+ uint32_t lastChangeTime; /* 上次变化上报时刻 */
+} jb_protocol_t;
+
+/* ════════════════════════════════════════════════════════════════
+ * 全局实例
+ * ════════════════════════════════════════════════════════════════ */
+extern jb_protocol_t jbProtocol;
+
+/* ════════════════════════════════════════════════════════════════
+ * 协议层 API(自动生成)
+ * ════════════════════════════════════════════════════════════════ */
+void jbInit(void);
+int32_t jbPutData(uint8_t *buf, uint32_t len);
+
+int32_t jbNotifyOtaStop(void);
+int32_t jbSendOtaResult(uint8_t result, const uint8_t *mcuVersion);
+
+int32_t jbProtocolHandle(jb_data_point_t *data);
+
+/*
+ * 网关应答确认(主动上报 / OTA 共用,REPORTCMD_V2,非 55AA)
+ * cmd: ble_proto 包 cmd
+ * gateway_int_cnt: gateway int 个数
+ * gateway_int0: gateway_int[0]
+ * 成功条件: cmd==0 && gateway_int_cnt==1 && gateway_int0==0
+ * 返回: 1=成功并清除等待; 0=未命中/条件不符
+ */
+int8_t jbReportAckCheck(uint16_t cmd, uint8_t gateway_int_cnt, int32_t gateway_int0);
+
+/* ════════════════════════════════════════════════════════════════
+ * 硬件抽象(用户实现)
+ * ════════════════════════════════════════════════════════════════ */
+uint32_t jbGetTimerCount(void); /* ms 计数器(定时器由 SOC SDK 提供) */
+
+/* 发送接口:经 SOC SDK 提供的 BLE 发送封装(由用户/SDK 实现,非本生成代码范围)*/
+extern void ble_send_data(uint8_t *data, uint16_t len);
+
+/* ════════════════════════════════════════════════════════════════
+ * 用户回调(用户实现)
+ * ════════════════════════════════════════════════════════════════ */
+/* 0x03 APP 下发控制事件 */
+int8_t jbEventProcess(jb_event_info_t *info, jb_data_point_t *data);
+
+/* BLE → MCU 事件回调 */
+void jbOnOtaNotify(uint32_t fwVersion, uint32_t fwLength, uint32_t fwCrc32); /* 0x30 */
+void jbOnOtaData(const uint8_t *data, uint16_t len,uint16_t shardIdx, uint16_t totalShards); /* 0x32 */
+void jbOnOtaStop(void); /* 0x36 / 0x38 停止 */
+
+/* MCU → BLE 应答回调(收到 BLE 应答时触发)*/
+void jbOnAck(uint8_t cmd, uint8_t result); /* 任意请求 ACK(结果) */
+
+#endif /* _JB_PROTOCOL_H */
diff --git a/apps/usr_jb_proto/Utils/jb_common.c b/apps/usr_jb_proto/Utils/jb_common.c
new file mode 100644
index 0000000..a631a1b
--- /dev/null
+++ b/apps/usr_jb_proto/Utils/jb_common.c
@@ -0,0 +1,69 @@
+/* ================================================================
+ * jb_common.c — 工具函数实现
+ * ================================================================
+ */
+#include "jb_common.h"
+
+/* ════════════════════════════════════════════════════════════════
+ * 校验和
+ * ════════════════════════════════════════════════════════════════ */
+uint8_t jbChecksum(const uint8_t *frame, uint16_t totalLen)
+{
+ if (!frame || totalLen < 4)
+ {
+ return 0;
+ }
+ uint16_t sum = 0;
+ /* 从 LEN_H(buf[2]) 累加到最后一个 payload 字节(buf[totalLen-2]) */
+ for (uint16_t i = 2; i < totalLen - 1; i++)
+ {
+ sum += frame[i];
+ }
+ return (uint8_t)(sum & 0xFF);
+}
+
+/* ════════════════════════════════════════════════════════════════
+ * 大端序读写
+ * ════════════════════════════════════════════════════════════════ */
+uint16_t jbReadU16BE(const uint8_t *buf)
+{
+ if (!buf)
+ {
+ return 0;
+ }
+ return ((uint16_t)buf[0] << 8) | buf[1];
+}
+
+uint32_t jbReadU32BE(const uint8_t *buf)
+{
+ if (!buf)
+ {
+ return 0;
+ }
+ return ((uint32_t)buf[0] << 24)
+ | ((uint32_t)buf[1] << 16)
+ | ((uint32_t)buf[2] << 8)
+ | buf[3];
+}
+
+void jbWriteU16BE(uint8_t *buf, uint16_t val)
+{
+ if (!buf)
+ {
+ return;
+ }
+ buf[0] = (uint8_t)(val >> 8);
+ buf[1] = (uint8_t)(val & 0xFF);
+}
+
+void jbWriteU32BE(uint8_t *buf, uint32_t val)
+{
+ if (!buf)
+ {
+ return;
+ }
+ buf[0] = (uint8_t)(val >> 24);
+ buf[1] = (uint8_t)(val >> 16);
+ buf[2] = (uint8_t)(val >> 8);
+ buf[3] = (uint8_t)(val & 0xFF);
+}
diff --git a/apps/usr_jb_proto/Utils/jb_common.h b/apps/usr_jb_proto/Utils/jb_common.h
new file mode 100644
index 0000000..c9face2
--- /dev/null
+++ b/apps/usr_jb_proto/Utils/jb_common.h
@@ -0,0 +1,37 @@
+/* ================================================================
+ * jb_common.h — 工具函数(校验和、大端序转换)
+ *
+ * 说明: 见宝协议采用大端序(Big-Endian)。
+ * 多字节值(uint16/uint32)按高位在前传输。
+ * ================================================================
+ */
+#ifndef _JB_COMMON_H
+#define _JB_COMMON_H
+
+#include
+#include
+
+/* ════════════════════════════════════════════════════════════════
+ * 校验和
+ * sum(LEN_H, LEN_L, CMD, SN, ...payload_last) & 0xFF
+ * buf[0]=55, buf[1]=AA,累加范围从 buf[2] 到 buf[totalLen-2]
+ * ════════════════════════════════════════════════════════════════ */
+uint8_t jbChecksum(const uint8_t *frame, uint16_t totalLen);
+
+/* ════════════════════════════════════════════════════════════════
+ * 大端序转换
+ * ════════════════════════════════════════════════════════════════ */
+
+/* 从字节数组读取 uint16(大端序)*/
+uint16_t jbReadU16BE(const uint8_t *buf);
+
+/* 从字节数组读取 uint32(大端序)*/
+uint32_t jbReadU32BE(const uint8_t *buf);
+
+/* 将 uint16 写入字节数组(大端序)*/
+void jbWriteU16BE(uint8_t *buf, uint16_t val);
+
+/* 将 uint32 写入字节数组(大端序)*/
+void jbWriteU32BE(uint8_t *buf, uint32_t val);
+
+#endif /* _JB_COMMON_H */
diff --git a/apps/usr_jb_proto/Utils/jb_ringbuffer.c b/apps/usr_jb_proto/Utils/jb_ringbuffer.c
new file mode 100644
index 0000000..b9c2e28
--- /dev/null
+++ b/apps/usr_jb_proto/Utils/jb_ringbuffer.c
@@ -0,0 +1,75 @@
+/* ================================================================
+ * jb_ringbuffer.c — 环形缓冲区实现
+ * ================================================================
+ */
+#include "jb_ringbuffer.h"
+
+/* ── 初始化 ── */
+void jbRbInit(jb_ringbuffer_t *rb)
+{
+ if (!rb)
+ {
+ return;
+ }
+ rb->write = rb->read = rb->count = 0;
+}
+
+/* ── 压入一个字节 ── */
+void jbRbPush(jb_ringbuffer_t *rb, uint8_t byte)
+{
+ if (!rb)
+ {
+ return;
+ }
+ if (rb->count >= JB_RB_CAPACITY)
+ {
+ return; /* 已满 — 丢弃 */
+ }
+ rb->buf[rb->write] = byte;
+ rb->write = (rb->write + 1) % JB_RB_CAPACITY;
+ rb->count++;
+}
+
+/* ── 弹出一个字节 ── */
+uint8_t jbRbPop(jb_ringbuffer_t *rb)
+{
+ if (!rb || rb->count == 0)
+ {
+ return 0;
+ }
+ uint8_t byte = rb->buf[rb->read];
+ rb->read = (rb->read + 1) % JB_RB_CAPACITY;
+ rb->count--;
+ return byte;
+}
+
+/* ── 查看指定偏移字节(不消费)── */
+uint8_t jbRbPeek(const jb_ringbuffer_t *rb, uint16_t offset)
+{
+ if (!rb || offset >= rb->count)
+ {
+ return 0;
+ }
+ uint16_t idx = (rb->read + offset) % JB_RB_CAPACITY;
+ return rb->buf[idx];
+}
+
+/* ── 可读字节数 ── */
+uint16_t jbRbAvailable(const jb_ringbuffer_t *rb)
+{
+ if (!rb)
+ {
+ return 0;
+ }
+ return rb->count;
+}
+
+/* ── 清空缓冲区 ── */
+void jbRbClear(jb_ringbuffer_t *rb)
+{
+ if (!rb)
+ {
+ return;
+ }
+ rb->write = rb->read = rb->count = 0;
+}
diff --git a/apps/usr_jb_proto/Utils/jb_ringbuffer.h b/apps/usr_jb_proto/Utils/jb_ringbuffer.h
new file mode 100644
index 0000000..190a82b
--- /dev/null
+++ b/apps/usr_jb_proto/Utils/jb_ringbuffer.h
@@ -0,0 +1,30 @@
+/* ================================================================
+ * jb_ringbuffer.h — 环形缓冲区(UART 接收)
+ * ================================================================
+ */
+#ifndef _JB_RINGBUFFER_H
+#define _JB_RINGBUFFER_H
+
+#include
+#include
+
+/* 缓冲区配置 */
+#define JB_RB_CAPACITY 256 /* 缓冲区容量(2 的幂可优化取模运算)*/
+
+/* 环形缓冲区实例 */
+typedef struct
+{
+ uint8_t buf[JB_RB_CAPACITY];
+ uint16_t write; /* 写索引 */
+ uint16_t read; /* 读索引 */
+ uint16_t count; /* 已用字节数 */
+} jb_ringbuffer_t;
+
+void jbRbInit(jb_ringbuffer_t *rb);
+void jbRbPush(jb_ringbuffer_t *rb, uint8_t byte);
+uint8_t jbRbPop(jb_ringbuffer_t *rb);
+uint8_t jbRbPeek(const jb_ringbuffer_t *rb, uint16_t offset);
+uint16_t jbRbAvailable(const jb_ringbuffer_t *rb);
+void jbRbClear(jb_ringbuffer_t *rb);
+
+#endif /* _JB_RINGBUFFER_H */
diff --git a/apps/usr_jb_proto/usr_jb_main.c b/apps/usr_jb_proto/usr_jb_main.c
new file mode 100644
index 0000000..ebf80b1
--- /dev/null
+++ b/apps/usr_jb_proto/usr_jb_main.c
@@ -0,0 +1,49 @@
+#include "system/includes.h"
+#include "app_config.h"
+#include "app_main.h"
+#include "app_task.h"
+#include "user_cfg.h"
+#include "vm.h"
+#include "sys_time.h"
+
+#include "jb_protocol.h"
+#include "jb_product.h"
+#include "jb_ringbuffer.h"
+#include "jb_common.h"
+#include "usr_le_product.h"
+
+/* 向 usr_le_code 库提供产品身份(换产品只改 jb_protocol.h 宏即可) */
+const uint8_t g_usr_le_prodcode[USR_LE_PRODCODE_LEN] = {
+ JB_CATEGORY_CODE[0], JB_CATEGORY_CODE[1],
+ JB_CATEGORY_CODE[2], JB_CATEGORY_CODE[3]
+};
+const uint8_t g_usr_le_pcode[USR_LE_PCODE_LEN] = {
+ JB_PRODUCT_CODE[0], JB_PRODUCT_CODE[1], JB_PRODUCT_CODE[2],
+ JB_PRODUCT_CODE[3], JB_PRODUCT_CODE[4], JB_PRODUCT_CODE[5]
+};
+
+void usr_timer_1_ms();
+static int jb_timer_id=0;
+
+void usr_jb_init()
+{
+ jbInit();
+ userInit();
+ if(jb_timer_id==0)jb_timer_id = sys_s_hi_timer_add(NULL, usr_timer_1_ms, TIMER_PERIOD_MS);
+}
+
+void usr_timer_1_ms()
+{
+ jbTimerIrq();
+}
+
+void usr_jb_le_recieve_data(u8* data,u16 len)
+{
+ jbPutData(data,len);
+}
+
+void usr_timer_loop()///500ms
+{
+ userHandle();
+ jbProtocolHandle(&gDevData);
+}
diff --git a/apps/usr_le_code/lib/libusr_le_code.a b/apps/usr_le_code/lib/libusr_le_code.a
new file mode 100644
index 0000000..f337979
Binary files /dev/null and b/apps/usr_le_code/lib/libusr_le_code.a differ
diff --git a/apps/usr_le_code/usr_le_api.h b/apps/usr_le_code/usr_le_api.h
new file mode 100644
index 0000000..4ccb3ba
--- /dev/null
+++ b/apps/usr_le_code/usr_le_api.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ * @file usr_le_api.h
+ * @brief usr_le_code 静态库对外应用 API(配网 / 配对 / OTA)
+ * @author cyWu <1917507415@qq.com>
+ * @date 2026.08.03
+ * @version V1.0.1
+ * @history
+ * - V1.0.0, 2026.08.03, cyWu, 首次发布
+ * - V1.0.1, 2026.08.19, cyWu, 收敛公开 API,移除 BLE 栈钩子声明
+ *
+ * @note usr_ble_adv_init / usr_le_data_recieve 为 BLE/RCSP 协议栈链接钩子,
+ * 由库内部实现并导出符号,不作为应用层公开接口。
+ ******************************************************************************/
+
+#ifndef __USR_LE_API_H__
+#define __USR_LE_API_H__
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief 进入配对/配网模式
+ * @note 断开当前连接、清除配对信息(不复位),重新发绑定广播
+ */
+void usr_goto_pair_mode(void);
+
+/**
+ * @brief 清除配对信息但不复位
+ */
+void usr_clear_pair_info_noreset(void);
+
+/**
+ * @brief 清除配对信息并延时复位
+ */
+void usr_clear_pair_info(void);
+
+/**
+ * @brief 获取当前是否已配对
+ * @return 1=已配对,0=未配对
+ */
+uint8_t usr_get_pair_flag(void);
+
+/**
+ * @brief 启动应用侧 OTA 流程
+ * @note 置位 usr_goto_updata,并创建 1s 周期定时器驱动断连与 OTA 广播切换
+ */
+void usr_app_ota_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USR_LE_API_H__ */
diff --git a/apps/usr_le_code/usr_le_product.h b/apps/usr_le_code/usr_le_product.h
new file mode 100644
index 0000000..90bcda4
--- /dev/null
+++ b/apps/usr_le_code/usr_le_product.h
@@ -0,0 +1,46 @@
+/******************************************************************************
+ * @file usr_le_product.h
+ * @brief usr_le_code 产品身份配置接口(由应用层提供符号,库内不写死)
+ * @author cyWu <1917507415@qq.com>
+ * @date 2026.08.03
+ * @version V1.0.0
+ * @history
+ * - V1.0.0, 2026.08.03, cyWu, 首次发布
+ ******************************************************************************/
+
+#ifndef __USR_LE_PRODUCT_H__
+#define __USR_LE_PRODUCT_H__
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** 与 bleproto_packer.h 中 BLEPROTO_ADV_TLV_LENGTH_PRODCODE 一致 */
+#ifndef USR_LE_PRODCODE_LEN
+#define USR_LE_PRODCODE_LEN 4
+#endif
+
+/** 与 bleproto_packer.h 中 BLE_PROTO_ADV_LENGTH_PCODE 一致 */
+#ifndef USR_LE_PCODE_LEN
+#define USR_LE_PCODE_LEN 6
+#endif
+
+/**
+ * @brief 产品类别码,对应 BLE 广播 prodcode(固定 4 字节 ASCII)
+ * @note 应用层用 JB_CATEGORY_CODE 填充,见 usr_jb_main.c
+ */
+extern const uint8_t g_usr_le_prodcode[USR_LE_PRODCODE_LEN];
+
+/**
+ * @brief 平台产品码,对应 BLE 广播 pcode(固定 6 字节 ASCII)
+ * @note 应用层用 JB_PRODUCT_CODE 填充,见 usr_jb_main.c
+ */
+extern const uint8_t g_usr_le_pcode[USR_LE_PCODE_LEN];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USR_LE_PRODUCT_H__ */
diff --git a/apps/usr_periph/usr_rtc.c b/apps/usr_periph/usr_rtc.c
new file mode 100644
index 0000000..d44dbe4
--- /dev/null
+++ b/apps/usr_periph/usr_rtc.c
@@ -0,0 +1,363 @@
+/******************************************************************************
+ * @file usr_rtc.c
+ * @brief 板级 RTC 外设实现(BR28 硬件 rtc_dev_ops)
+ * @author cyWu <1917507415@qq.com>
+ * @date 2026.08.19
+ * @version V1.1.0
+ * @history
+ * - V1.0.0, 2026.08.19, cyWu, 从模组固件移植至 SOC SDK
+ * - V1.1.0, 2026.08.19, cyWu, 精简公共接口与缓存逻辑
+ ******************************************************************************/
+
+#include "system/includes.h"
+#include "app_config.h"
+#include "usr_rtc.h"
+#include "asm/rtc.h"
+
+#define LOG_TAG_CONST APP
+#define LOG_TAG "[USR_RTC]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+#include "debug.h"
+
+/*============================================================================*/
+/* 私有宏 / 类型 */
+/*============================================================================*/
+
+#define USR_RTC_TZ_MAGIC (0x52544331u) /**< 'RTC1',校验 VM 时区 */
+
+typedef struct {
+ uint32_t magic;
+ int32_t tz_s;
+} UsrRtcTzVm_t;
+
+typedef struct {
+ uint8_t inited;
+ uint8_t tz_valid;
+ int32_t tz_s;
+ void *dev;
+} UsrRtc_t;
+
+/*============================================================================*/
+/* 私有变量 */
+/*============================================================================*/
+
+static UsrRtc_t s_rtc;
+
+/*============================================================================*/
+/* 私有函数声明 */
+/*============================================================================*/
+
+static uint8_t usr_rtc_is_leap(uint16_t year);
+static uint8_t usr_rtc_days_in_month(uint16_t year, uint8_t month);
+static uint8_t usr_rtc_year_ok(uint16_t year);
+static void usr_rtc_unix_to_calendar(uint32_t unix_utc, int32_t tz_s,
+ struct sys_time *t);
+static UsrRtc_Ret_t usr_rtc_write(const struct sys_time *t);
+static void usr_rtc_load_tz(void);
+static void usr_rtc_save_tz(int32_t tz_s);
+
+/*============================================================================*/
+/* 公有函数 */
+/*============================================================================*/
+
+/**
+ * @brief 打开 rtc 设备并加载时区
+ * @return UsrRtc_Ret_t
+ */
+UsrRtc_Ret_t usr_rtc_init(void)
+{
+ struct sys_time t;
+
+ if (s_rtc.inited)
+ {
+ return USR_RTC_OK;
+ }
+
+#if TCFG_APP_RTC_EN
+ s_rtc.dev = dev_open("rtc", NULL);
+ if (!s_rtc.dev)
+ {
+ log_error("open rtc fail");
+ return USR_RTC_ERR_NOT_INIT;
+ }
+#else
+ log_error("TCFG_APP_RTC_EN=0");
+ return USR_RTC_ERR_NOT_INIT;
+#endif
+
+ usr_rtc_load_tz();
+ s_rtc.inited = 1;
+
+ memset(&t, 0, sizeof(t));
+ read_sys_time(&t);
+ log_info("rtc open %u-%02u-%02u %02u:%02u:%02u tz=%ld tz_ok=%u",
+ t.year, t.month, t.day, t.hour, t.min, t.sec,
+ (long)s_rtc.tz_s, s_rtc.tz_valid);
+ return USR_RTC_OK;
+}
+
+/**
+ * @brief 获取当前本地时间
+ * @param t 成功时赋值;失败不改动
+ * @return 1/0
+ */
+uint8_t usr_rtc_get_time(struct sys_time *t)
+{
+ struct sys_time tmp;
+
+ if (!t || !s_rtc.inited || !s_rtc.tz_valid)
+ {
+ return 0;
+ }
+
+ memset(&tmp, 0, sizeof(tmp));
+ read_sys_time(&tmp);
+ if (!usr_rtc_year_ok(tmp.year))
+ {
+ return 0;
+ }
+
+ *t = tmp;
+ return 1;
+}
+
+/**
+ * @brief UTC 秒 + 时区 → 本地日历写入 RTC
+ * @param unix_utc UTC 秒
+ * @param tz_s 时区偏移秒
+ * @return UsrRtc_Ret_t
+ */
+UsrRtc_Ret_t usr_rtc_set_from_unix(uint64_t unix_utc, int32_t tz_s)
+{
+ struct sys_time t;
+ UsrRtc_Ret_t ret;
+
+ if (!s_rtc.inited)
+ {
+ return USR_RTC_ERR_NOT_INIT;
+ }
+ if (unix_utc == 0)
+ {
+ log_debug("unix=0, ignore");
+ return USR_RTC_ERR_PARAM;
+ }
+
+ /* 网关采样到写入大约慢 1s,在 UTC 上补偿 */
+ unix_utc += USR_RTC_SYNC_COMPENSATE_S;
+ if ((tz_s > USR_RTC_TZ_ABS_MAX_S) || (tz_s < -USR_RTC_TZ_ABS_MAX_S))
+ {
+ log_error("tz out of range %ld", (long)tz_s);
+ return USR_RTC_ERR_PARAM;
+ }
+ if (unix_utc > 0xFFFFFFFFull)
+ {
+ log_error("unix too large");
+ return USR_RTC_ERR_PARAM;
+ }
+
+ usr_rtc_unix_to_calendar((uint32_t)unix_utc, tz_s, &t);
+ if (!usr_rtc_year_ok(t.year))
+ {
+ log_error("year %u not in %u~%u, wait sync",
+ t.year, USR_RTC_YEAR_MIN, USR_RTC_YEAR_MAX);
+ return USR_RTC_ERR_INVALID;
+ }
+
+ ret = usr_rtc_write(&t);
+ if (ret != USR_RTC_OK)
+ {
+ return ret;
+ }
+
+ usr_rtc_save_tz(tz_s);
+ log_info("set rtc %u-%02u-%02u %02u:%02u:%02u tz=%ld",
+ t.year, t.month, t.day, t.hour, t.min, t.sec, (long)tz_s);
+ return USR_RTC_OK;
+}
+
+/*============================================================================*/
+/* 私有函数 */
+/*============================================================================*/
+
+/**
+ * @brief 写硬件日历
+ * @param t 本地日历
+ * @return UsrRtc_Ret_t
+ */
+static UsrRtc_Ret_t usr_rtc_write(const struct sys_time *t)
+{
+ struct sys_time tmp;
+
+ if (!t)
+ {
+ return USR_RTC_ERR_PARAM;
+ }
+ if (!s_rtc.inited)
+ {
+ return USR_RTC_ERR_NOT_INIT;
+ }
+ if (!usr_rtc_year_ok(t->year) || (t->month < 1) || (t->month > 12) ||
+ (t->day < 1) || (t->hour > 23) || (t->min > 59) || (t->sec > 59))
+ {
+ return USR_RTC_ERR_PARAM;
+ }
+ if (t->day > usr_rtc_days_in_month(t->year, t->month))
+ {
+ return USR_RTC_ERR_PARAM;
+ }
+
+ tmp = *t;
+ write_sys_time(&tmp);
+ return USR_RTC_OK;
+}
+
+/**
+ * @brief 是否闰年
+ * @param year 公历年
+ * @return 1/0
+ */
+static uint8_t usr_rtc_is_leap(uint16_t year)
+{
+ if ((year % 400u) == 0)
+ {
+ return 1;
+ }
+ if ((year % 100u) == 0)
+ {
+ return 0;
+ }
+ return ((year % 4u) == 0) ? 1 : 0;
+}
+
+/**
+ * @brief 某月天数
+ * @param year 年
+ * @param month 月 1~12
+ * @return 天数,非法月返回 0
+ */
+static uint8_t usr_rtc_days_in_month(uint16_t year, uint8_t month)
+{
+ static const uint8_t days[12] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+ if ((month < 1) || (month > 12))
+ {
+ return 0;
+ }
+ if ((month == 2) && usr_rtc_is_leap(year))
+ {
+ return 29;
+ }
+ return days[month - 1];
+}
+
+/**
+ * @brief 年份是否在合法窗口
+ * @param year 年
+ * @return 1/0
+ */
+static uint8_t usr_rtc_year_ok(uint16_t year)
+{
+ return ((year >= USR_RTC_YEAR_MIN) && (year <= USR_RTC_YEAR_MAX)) ? 1 : 0;
+}
+
+/**
+ * @brief UTC 秒 + 时区 → 本地日历
+ * @param unix_utc UTC 秒
+ * @param tz_s 时区偏移
+ * @param t 输出
+ */
+static void usr_rtc_unix_to_calendar(uint32_t unix_utc, int32_t tz_s,
+ struct sys_time *t)
+{
+ int64_t local;
+ uint32_t days;
+ uint32_t tod;
+ uint16_t y;
+ uint8_t m;
+ uint8_t dim;
+
+ memset(t, 0, sizeof(*t));
+ local = (int64_t)unix_utc + (int64_t)tz_s;
+ if (local < 0)
+ {
+ local = 0;
+ }
+
+ tod = (uint32_t)(local % 86400);
+ days = (uint32_t)(local / 86400);
+ t->sec = (uint8_t)(tod % 60u);
+ t->min = (uint8_t)((tod / 60u) % 60u);
+ t->hour = (uint8_t)(tod / 3600u);
+
+ y = 1970;
+ while (1)
+ {
+ uint32_t diy = usr_rtc_is_leap(y) ? 366u : 365u;
+ if (days < diy)
+ {
+ break;
+ }
+ days -= diy;
+ y++;
+ if (y > 4095u)
+ {
+ break;
+ }
+ }
+ t->year = y;
+
+ for (m = 1; m <= 12u; m++)
+ {
+ dim = usr_rtc_days_in_month(y, m);
+ if (days < dim)
+ {
+ break;
+ }
+ days -= dim;
+ }
+ t->month = m;
+ t->day = (uint8_t)(days + 1u);
+}
+
+/**
+ * @brief 从 VM 加载时区
+ */
+static void usr_rtc_load_tz(void)
+{
+ UsrRtcTzVm_t vm;
+ int ret;
+
+ s_rtc.tz_valid = 0;
+ s_rtc.tz_s = 0;
+ memset(&vm, 0, sizeof(vm));
+ ret = syscfg_read(CFG_USER_TIM_FLAG, (u8 *)&vm, sizeof(vm));
+ if ((ret == (int)sizeof(vm)) && (vm.magic == USR_RTC_TZ_MAGIC))
+ {
+ if ((vm.tz_s <= USR_RTC_TZ_ABS_MAX_S) && (vm.tz_s >= -USR_RTC_TZ_ABS_MAX_S))
+ {
+ s_rtc.tz_s = vm.tz_s;
+ s_rtc.tz_valid = 1;
+ log_info("tz from vm %ld", (long)s_rtc.tz_s);
+ return;
+ }
+ }
+ log_debug("tz vm empty");
+}
+
+/**
+ * @brief 时区写入 VM
+ * @param tz_s 时区偏移秒
+ */
+static void usr_rtc_save_tz(int32_t tz_s)
+{
+ UsrRtcTzVm_t vm;
+
+ s_rtc.tz_s = tz_s;
+ s_rtc.tz_valid = 1;
+ vm.magic = USR_RTC_TZ_MAGIC;
+ vm.tz_s = tz_s;
+ syscfg_write(CFG_USER_TIM_FLAG, (u8 *)&vm, sizeof(vm));
+}
diff --git a/apps/usr_periph/usr_rtc.h b/apps/usr_periph/usr_rtc.h
new file mode 100644
index 0000000..9c5de7e
--- /dev/null
+++ b/apps/usr_periph/usr_rtc.h
@@ -0,0 +1,64 @@
+/******************************************************************************
+ * @file usr_rtc.h
+ * @brief 板级 RTC:硬件对时 + 客户读本地日历
+ * @author cyWu <1917507415@qq.com>
+ * @date 2026.08.19
+ * @version V1.1.0
+ * @history
+ * - V1.0.0, 2026.08.19, cyWu, 从模组固件移植至 SOC SDK
+ * - V1.1.0, 2026.08.19, cyWu, 精简接口;usr_rtc_get_time 返回本地日历
+ ******************************************************************************/
+
+#ifndef __USR_RTC_H__
+#define __USR_RTC_H__
+
+#include
+#include "system/sys_time.h"
+
+/*============================================================================*/
+/* 宏定义 */
+/*============================================================================*/
+
+#define USR_RTC_YEAR_MIN (2026u) /**< 合法年份下限 */
+#define USR_RTC_YEAR_MAX (2098u) /**< 合法年份上限 */
+#define USR_RTC_TZ_ABS_MAX_S (57600) /**< 时区偏移绝对值上限(±16h) */
+#define USR_RTC_SYNC_COMPENSATE_S (1u) /**< 网关对时延迟补偿(秒) */
+
+/*============================================================================*/
+/* 错误码(init / set_from_unix) */
+/*============================================================================*/
+
+typedef enum {
+ USR_RTC_OK = 0,
+ USR_RTC_ERR_PARAM,
+ USR_RTC_ERR_NOT_INIT,
+ USR_RTC_ERR_INVALID, /**< 年份非法,等待 App 对时 */
+} UsrRtc_Ret_t;
+
+/*============================================================================*/
+/* 外部接口 */
+/*============================================================================*/
+
+/**
+ * @brief 打开 "rtc" 设备并加载时区
+ * @return UsrRtc_Ret_t
+ * @note app_main 启动时调用一次即可
+ */
+UsrRtc_Ret_t usr_rtc_init(void);
+
+/**
+ * @brief 获取当前本地时间(客户常用)
+ * @param t 成功时写入年月日时分秒;失败时不改动
+ * @return 1=已对时且读成功,0=未初始化/未对时/参数非法
+ */
+uint8_t usr_rtc_get_time(struct sys_time *t);
+
+/**
+ * @brief App/网关 DEVICEINFO:UTC 秒 + 时区写入 RTC
+ * @param unix_utc UTC Unix 秒;0 无效
+ * @param tz_s 时区偏移秒(东八区 28800)
+ * @return UsrRtc_Ret_t
+ */
+UsrRtc_Ret_t usr_rtc_set_from_unix(uint64_t unix_utc, int32_t tz_s);
+
+#endif /* __USR_RTC_H__ */
diff --git a/cpu/br28/a2dp_dec.c b/cpu/br28/a2dp_dec.c
new file mode 100644
index 0000000..4bcad15
--- /dev/null
+++ b/cpu/br28/a2dp_dec.c
@@ -0,0 +1,2871 @@
+/*************************************************************************************************/
+/*!
+* \file a2dp_dec.c
+*
+* \brief
+*
+* Copyright (c) 2011-2022 ZhuHai Jieli Technology Co.,Ltd.
+*
+*/
+/*************************************************************************************************/
+#include "sound_device.h"
+#include "media/bt_audio_timestamp.h"
+#include "media/a2dp_sample_detect.h"
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+#include "spatial_effect/spatial_effect.h"
+#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
+
+#define A2DP_AUDIO_PLC_ENABLE 1
+
+#if A2DP_AUDIO_PLC_ENABLE
+#include "media/tech_lib/LFaudio_plc_api.h"
+#endif
+
+#if TCFG_AUDIO_SPEAK_TO_CHAT_ENABLE
+#include "icsd_adt_app.h"
+#endif
+
+#if AUDIO_VBASS_CONFIG
+#include "application/audio_vbass.h"
+#endif
+
+#if TCFG_AUDIO_CVP_DUT_ENABLE
+#include "audio_cvp_dut.h"
+#endif /*TCFG_AUDIO_CVP_DUT_ENABLE*/
+
+///#include "audio_effect_develop.h"
+
+#if (TCFG_AUDIO_SPATIAL_EFFECT_ENABLE)
+#define CONFIG_AUDIO_EFFECT_TASK_ENABLE TCFG_AUDIO_EFFECT_TASK_EBABLE
+#else
+#define CONFIG_AUDIO_EFFECT_TASK_ENABLE 0
+#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
+#define A2DP_FLUENT_STREAM_MODE 1//流畅模式
+#define A2DP_FLUENT_DETECT_INTERVAL 100000//ms 流畅播放延时检测时长
+#if A2DP_FLUENT_STREAM_MODE
+#define A2DP_MAX_PENDING_TIME 120
+#else
+#define A2DP_MAX_PENDING_TIME 40
+#endif
+
+#define A2DP_STREAM_NO_ERR 0
+#define A2DP_STREAM_UNDERRUN 1
+#define A2DP_STREAM_OVERRUN 2
+#define A2DP_STREAM_MISSED 3
+#define A2DP_STREAM_DECODE_ERR 4
+#define A2DP_STREAM_LOW_UNDERRUN 5
+
+#ifdef TCFG_AUDIO_MUSIC_SAMPLE_RATE
+#define A2DP_SOUND_SAMPLE_RATE TCFG_AUDIO_MUSIC_SAMPLE_RATE
+#else
+#define A2DP_SOUND_SAMPLE_RATE 0
+#endif
+
+#if TCFG_USER_TWS_ENABLE && TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+#define CONFIG_TWS_SPATIAL_AUDIO_ENABLE 1
+#else
+#define CONFIG_TWS_SPATIAL_AUDIO_ENABLE 0
+#endif
+
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+static u8 spatial_audio_enable = 1;
+static u8 spatial_audio_head_tracked = 0;
+void a2dp_spatial_audio_head_tracked_en(u8 en);
+int aud_spatial_sensor_init();
+int aud_spatial_sensor_exit();
+int aud_spatial_sensor_run(void *priv, void *data, int len);
+#endif
+int aud_effect_push_data(void *priv, s16 *data, u16 len);
+
+/**************************************************************************************************
+ * A2DP音频数据流异步任务处理说明
+ *
+ * 1、解码后数据流的顺序
+ * 通常A2DP解码后的数据流会按照以下顺序进行流数据处理:
+ * PLC -> 空间音频(Spatial audio) -> 数字音量(Digtal vol) -> 环绕音效(Surround) ->
+ * 虚拟音效(Vbass) -> 低音增强(bass_boost)-> 动态增益控制(ANC) -> 音频同步(Syncts) -> EQ/DRC -> 混音器(mixer) -> DAC
+ *
+ * 以上流程以实际形态的功能开关为准。
+ * 2、异步任务处理节点方法:
+ * a2dp_decoder_effect_task_enter();
+ *
+ * 要加入的节点
+ *
+ * a2dp_decoder_effect_task_output();
+ *
+ * 由该方式包住的节点则都会被归纳到effect task中执行
+ *
+ **************************************************************************************************/
+#define A2DP_NODE_BEGIN 0x1
+#define A2DP_NODE_END 0x2
+#define A2DP_NODE_BLOCK 0x4
+#define A2DP_NODE_SUB_STREAM_BEGIN 0x8
+#define A2DP_NODE_SUB_STREAM_END 0x10
+
+enum a2dp_stream_id {
+ A2DP_NODE_DECODER = 0x0,
+#if A2DP_AUDIO_PLC_ENABLE
+ A2DP_NODE_PLC,
+#endif
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+ A2DP_NODE_SPATIAL_AUDIO,
+#if TCFG_SENSOR_DATA_READ_IN_DEC_TASK
+ A2DP_NODE_SENSOR_DATA_STREAM,
+#endif /*TCFG_SENSOR_DATA_READ_IN_DEC_TASK*/
+#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ A2DP_NODE_DIGITAL_VOLUME,
+#endif
+#if (AUDIO_SURROUND_CONFIG || AUDIO_VBASS_CONFIG)
+ A2DP_NODE_SURROUND_VBASS,
+#endif
+#if defined(TCFG_AUDIO_BASS_BOOST)&&TCFG_AUDIO_BASS_BOOST
+ A2DP_NODE_BASS_BOOST,
+#endif
+
+#if TCFG_AUDIO_ANC_ENABLE && ANC_MUSIC_DYNAMIC_GAIN_EN
+ A2DP_NODE_DYNAMIC_GAIN,
+#endif/*ANC_MUSIC_DYNAMIC_GAIN_EN*/
+
+#if AUDIO_CODEC_SUPPORT_SYNC
+ A2DP_NODE_BEFORE_SYNCTS,
+ A2DP_NODE_SYNCTS,
+#endif
+
+#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
+ A2DP_NODE_EFFECT_TASK_ENTER,
+#endif
+
+#if (TCFG_EQ_ENABLE && TCFG_BT_MUSIC_EQ_ENABLE)
+ A2DP_NODE_EQ_DRC,
+#endif
+
+#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
+ A2DP_NODE_EFFECT_TASK_OUT,
+#endif
+
+#if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE)
+ A2DP_NODE_EFFECT_DEVELOP,
+#endif
+ A2DP_NODE_MIXER,
+ A2DP_NODE_MAX,
+};
+
+struct a2dp_stream_node {
+ enum a2dp_stream_id id;
+ u8 attribute;
+ u8 remain;
+ void *priv;
+ int (*data_handler)(void *priv, void *data, int len);
+ void (*wakeup)(void *stream);
+ int (*set_wakeup_handler)(void *priv, void *stream, void (*wakeup)(void *));
+};
+
+struct a2dp_dec_hdl {
+ struct audio_decoder decoder;
+ struct audio_res_wait wait;
+ struct audio_mixer_ch mix_ch;
+ enum audio_channel channel;
+ u8 start;
+ u8 ch;
+ s16 header_len;
+ u8 remain;
+ u8 eq_remain;
+ u8 fetch_lock;
+ u8 preempt;
+ u8 stream_error;
+ u8 new_frame;
+ u8 repair;
+ u8 dut_enable;
+ void *sample_detect;
+ void *syncts;
+ void *repair_pkt;
+ s16 repair_pkt_len;
+ u16 missed_num;
+ u16 repair_frames;
+ u16 overrun_seqn;
+ u16 slience_frames;
+#if AUDIO_CODEC_SUPPORT_SYNC
+ u8 ts_start;
+ u8 sync_step;
+ void *ts_handle;
+ u32 timestamp;
+ u32 base_time;
+#endif /*AUDIO_CODEC_SUPPORT_SYNC*/
+#if A2DP_AUDIO_PLC_ENABLE
+ LFaudio_PLC_API *plc_ops;
+ void *plc_mem;
+#endif /*A2DP_AUDIO_PLC_ENABLE*/
+ u32 mix_ch_event_params[3];
+
+ u32 pending_time;
+ u16 seqn;
+ u32 sample_rate;
+ int timer;
+ u32 coding_type;
+ u16 delay_time;
+ u16 detect_timer;
+ u8 underrun_feedback;
+ /*
+ u8 underrun_count;
+ u32 underrun_time;
+ u32 underrun_cool_time;
+ */
+
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+ void *spatial_audio;
+ s16 spatial_data_len;
+ u8 spatial_node_id;
+ u16 spatial_data_offset;
+#endif
+#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
+ void *aud_effect;
+#endif
+#if TCFG_EQ_ENABLE&&TCFG_BT_MUSIC_EQ_ENABLE
+ struct dec_eq_drc *eq_drc;
+#endif//TCFG_BT_MUSIC_EQ_ENABLE
+
+#if AUDIO_SURROUND_CONFIG
+ struct dec_sur *sur;
+#endif//AUDIO_SURROUND_CONFIG
+
+#if AUDIO_VBASS_CONFIG
+ vbass_hdl *vbass; //虚拟低音句柄
+#endif//AUDIO_VBASS_CONFIG
+
+#if defined(TCFG_AUDIO_BASS_BOOST)&&TCFG_AUDIO_BASS_BOOST
+ struct audio_drc *bass_boost;
+#endif
+#if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE)
+ void *effect_develop;
+#endif
+
+ struct a2dp_stream_node stream_node[A2DP_NODE_MAX + 1];
+ u8 node_num;
+};
+
+extern const int CONFIG_LOW_LATENCY_ENABLE;
+extern const int CONFIG_A2DP_DELAY_TIME;
+extern const int CONFIG_A2DP_DELAY_TIME_LO;
+extern const int CONFIG_A2DP_SBC_DELAY_TIME_LO;
+
+static u16 a2dp_delay_time;
+static u8 a2dp_low_latency = 0;
+static u16 drop_a2dp_timer;
+static u16 a2dp_low_latency_seqn = 0;
+
+
+struct a2dp_dec_hdl *a2dp_dec = NULL;
+
+static void a2dp_stream_node_init(struct a2dp_dec_hdl *dec);
+static void a2dp_stream_node_add(struct a2dp_dec_hdl *dec,
+ void *priv,
+ int (*data_handler)(void *, void *, int),
+ void (*wakeup)(void *),
+ int (*set_wakeup_handler)(void *, void *, void (*wakeup)(void *)),
+ u8 attribute);
+static void a2dp_stream_node_wakeup(void *priv);
+
+extern u32 bt_audio_sync_lat_time(void);
+extern void bt_audio_sync_nettime_select(u8 base);
+void audio_mix_ch_event_handler(void *priv, int event)
+{
+ switch (event) {
+ case MIXER_EVENT_CH_OPEN:
+ if (priv) {
+ u32 *params = (u32 *)priv;
+ struct audio_mixer_ch *ch = (struct audio_mixer_ch *)params[0];
+ u32 base_time = params[2];
+ sound_pcm_dev_add_syncts((void *)params[1]);
+ u32 current_time = (bt_audio_sync_lat_time() * 625 * TIME_US_FACTOR);
+ u32 time_diff = ((base_time - current_time) & 0xffffffff) / TIME_US_FACTOR;
+ printf("-----base time : %u, current_time : %u------\n", base_time, current_time);
+ if (time_diff < 500000) {
+ int buf_frame = sound_pcm_dev_buffered_frames();
+ int slience_frames = (u64)time_diff * audio_mixer_get_sample_rate(&mixer) / 1000000 - buf_frame;
+ if (slience_frames < 0) {
+ slience_frames = 0;
+ }
+ printf("-------slience_frames : %d-------\n", slience_frames);
+ sound_pcm_update_frame_num((void *)params[1], -slience_frames);
+ audio_mixer_ch_add_slience_samples(ch, slience_frames * sound_pcm_dev_channel_mapping(0));
+ }
+ }
+ break;
+ case MIXER_EVENT_CH_CLOSE:
+ if (priv) {
+ u32 *params = (u32 *)priv;
+ sound_pcm_dev_remove_syncts((void *)params[1]);
+ }
+ break;
+ }
+}
+
+#define RB16(b) (u16)(((u8 *)b)[0] << 8 | (((u8 *)b))[1])
+#define RB32(b) (u32)(((u8 *)b)[0] << 24 | (((u8 *)b))[1] << 16 | (((u8 *)b))[2] << 8 | (((u8 *)b))[3])
+
+static int get_rtp_header_len(u8 new_frame, u8 *buf, int len)
+{
+ int ext, csrc;
+ int byte_len;
+ int header_len = 0;
+ u8 *data = buf;
+
+ csrc = buf[0] & 0x0f;
+ ext = buf[0] & 0x10;
+
+ byte_len = 12 + 4 * csrc;
+ buf += byte_len;
+
+ if (ext) {
+ ext = (RB16(buf + 2) + 1) << 2;
+ }
+
+ if (new_frame) {
+ header_len = byte_len + ext + (a2dp_dec->coding_type == AUDIO_CODING_AAC ? 0 : 1);
+ } else {
+ header_len = byte_len + ext;
+ }
+
+ if (header_len > len - 1) {
+ return len;
+ }
+
+ if (a2dp_dec->coding_type == AUDIO_CODING_SBC) {
+ for (; header_len < len; header_len++) {
+ if (data[header_len] == 0x9c) {
+ return header_len;
+ }
+ }
+ log_e("==== find sbc header error === \n");
+ put_buf(data, len);
+ }
+
+ return header_len;
+}
+
+__attribute__((weak))
+int audio_dac_get_channel(struct audio_dac_hdl *p)
+{
+ return 0;
+}
+
+void __a2dp_drop_frame(void *p)
+{
+ int len;
+ u8 *frame;
+
+#if 0
+ int num = a2dp_media_get_packet_num();
+ if (num > 1) {
+ for (int i = 0; i < num; i++) {
+ len = a2dp_media_get_packet(&frame);
+ if (len <= 0) {
+ break;
+ }
+ //printf("a2dp_drop_frame: %d\n", len);
+ a2dp_media_free_packet(frame);
+ }
+ }
+#else
+ while (1) {
+ len = a2dp_media_try_get_packet(&frame);
+ if (len <= 0) {
+ break;
+ }
+ a2dp_media_free_packet(frame);
+ }
+
+#endif
+
+}
+
+static void __a2dp_clean_frame_by_number(struct a2dp_dec_hdl *dec, u16 num)
+{
+ u16 end_seqn = dec->seqn + num;
+ if (end_seqn == 0) {
+ end_seqn++;
+ }
+ /*__a2dp_drop_frame(NULL);*/
+ /*dec->drop_seqn = end_seqn;*/
+ a2dp_media_clear_packet_before_seqn(end_seqn);
+}
+
+static void a2dp_tws_clean_frame(void *arg)
+{
+ u8 master = 0;
+#if TCFG_USER_TWS_ENABLE
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ master = 1;
+ }
+#else
+ master = 1;
+#endif
+ if (!master) {
+ return;
+ }
+
+ int msecs = a2dp_media_get_remain_play_time(0);
+ if (msecs <= 0) {
+ return;
+ }
+
+ if (a2dp_dec && a2dp_dec->fetch_lock) {
+ return;
+ }
+ int len = 0;
+ u16 seqn = 0;
+ u8 *packet = a2dp_media_fetch_packet(&len, NULL);
+ if (!packet) {
+ return;
+ }
+ seqn = RB16(packet + 2) + 10;
+ if (seqn == 0) {
+ seqn = 1;
+ }
+ a2dp_media_clear_packet_before_seqn(seqn);
+}
+
+static u8 a2dp_suspend = 0;
+static u32 a2dp_resume_time = 0;
+
+
+
+int a2dp_decoder_pause(void)
+{
+ if (a2dp_dec) {
+ return audio_decoder_pause(&(a2dp_dec->decoder));
+ }
+
+ return 0;
+}
+
+int a2dp_decoder_start(void)
+{
+ if (a2dp_dec) {
+ return audio_decoder_start(&(a2dp_dec->decoder));
+ }
+
+ return 0;
+}
+u8 get_a2dp_drop_frame_flag()
+{
+ if (a2dp_dec) {
+ return a2dp_dec->timer;
+ }
+ return 0;
+}
+
+void a2dp_drop_frame_start()
+{
+ if (a2dp_dec && (a2dp_dec->timer == 0)) {
+ a2dp_dec->timer = sys_timer_add(NULL, __a2dp_drop_frame, 50);
+ a2dp_tws_audio_conn_offline();
+ }
+}
+
+void a2dp_drop_frame_stop()
+{
+ if (a2dp_dec && a2dp_dec->timer) {
+ sys_timer_del(a2dp_dec->timer);
+ a2dp_tws_audio_conn_delete();
+ a2dp_dec->timer = 0;
+ }
+}
+
+static void a2dp_dec_set_output_channel(struct a2dp_dec_hdl *dec)
+{
+ int state = 0;
+ enum audio_channel channel;
+ u8 dac_connect_mode = 0;
+
+ u8 ch_num = sound_pcm_dev_channel_mapping(1);
+#if TCFG_USER_TWS_ENABLE
+ state = tws_api_get_tws_state();
+ if (state & TWS_STA_SIBLING_CONNECTED) {
+ if (ch_num == 2) {
+ channel = tws_api_get_local_channel() == 'L' ? AUDIO_CH_DUAL_L : AUDIO_CH_DUAL_R;
+ } else {
+ channel = tws_api_get_local_channel() == 'L' ? AUDIO_CH_L : AUDIO_CH_R;
+ }
+ } else {
+ if (ch_num == 2) {
+ channel = AUDIO_CH_LR;
+ } else {
+ channel = AUDIO_CH_DIFF;
+ }
+ }
+ dec->ch = ch_num;
+#if CONFIG_TWS_SPATIAL_AUDIO_ENABLE
+ if (spatial_audio_enable || dec->spatial_audio) {
+ channel = AUDIO_CH_LR;
+#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
+ dec->ch = 2;
+#endif/*CONFIG_AUDIO_EFFECT_TASK_ENABLE*/
+ //printf("Spatial Effect,ch:%d,%d\n",dec->ch,channel);
+ }
+#endif/*CONFIG_TWS_SPATIAL_AUDIO_ENABLE*/
+#else
+ if (ch_num == 2) {
+ channel = AUDIO_CH_LR;
+ } else {
+ channel = AUDIO_CH_DIFF;
+ }
+ dec->ch = ch_num;
+#endif
+
+
+#if TCFG_APP_FM_EMITTER_EN
+ channel = AUDIO_CH_LR;
+#endif
+ if (channel != dec->channel) {
+ printf("set_channel: %d\n", channel);
+#if CONFIG_TWS_SPATIAL_AUDIO_ENABLE
+ if (dec->spatial_audio) {
+ if (state & TWS_STA_SIBLING_CONNECTED) {
+ spatial_audio_set_mapping_channel(dec->spatial_audio, tws_api_get_local_channel() == 'L' ? AUDIO_CH_L : AUDIO_CH_R);
+ } else {
+ spatial_audio_set_mapping_channel(dec->spatial_audio, AUDIO_CH_MIX_MONO);
+ }
+ }
+#endif
+ audio_decoder_set_output_channel(&dec->decoder, channel);
+ dec->channel = channel;
+#if TCFG_EQ_ENABLE&&TCFG_BT_MUSIC_EQ_ENABLE
+ if (dec->eq_drc && dec->eq_drc->eq) {
+ audio_eq_set_channel(dec->eq_drc->eq, dec->ch);
+ }
+#endif//TCFG_BT_MUSIC_EQ_ENABLE
+
+
+ /* #if TCFG_USER_TWS_ENABLE */
+#if AUDIO_SURROUND_CONFIG
+ if (dec->sur) {
+ audio_surround_set_ch(dec->sur, channel);
+ }
+#endif//AUDIO_SURROUND_CONFIG
+ /* #endif//TCFG_USER_TWS_ENABLE */
+
+ }
+}
+
+
+/*
+ *
+ */
+static int a2dp_decoder_set_timestamp(struct a2dp_dec_hdl *dec, u16 seqn)
+{
+#if AUDIO_CODEC_SUPPORT_SYNC
+ u32 timestamp;
+
+ timestamp = a2dp_audio_update_timestamp(dec->ts_handle, seqn, audio_syncts_get_dts(dec->syncts));
+ if (!dec->ts_start) {
+ dec->ts_start = 1;
+ dec->mix_ch_event_params[2] = timestamp;
+ } else {
+ audio_syncts_next_pts(dec->syncts, timestamp);
+ audio_syncts_update_sample_rate(dec->syncts, a2dp_audio_sample_rate(dec->ts_handle));;
+ }
+ dec->timestamp = timestamp;
+ /* printf("timestamp : %d, %d\n", seqn, timestamp / TIME_US_FACTOR / 625); */
+#endif
+ return 0;
+}
+
+static bool a2dp_audio_is_underrun(struct a2dp_dec_hdl *dec)
+{
+#if AUDIO_CODEC_SUPPORT_SYNC
+ if (dec->ts_start != 2) {
+ return false;
+ }
+#endif
+ int underrun_time = a2dp_low_latency ? 1 : 20;
+ if (sound_pcm_dev_buffered_time() < underrun_time) {
+ return true;
+ }
+ return false;
+}
+
+static bool a2dp_bt_rx_overrun(void)
+{
+ return a2dp_media_get_remain_buffer_size() < 768 ? true : false;
+}
+
+static void a2dp_decoder_stream_free(struct a2dp_dec_hdl *dec, void *packet)
+{
+ if (packet) {
+ a2dp_media_free_packet(packet);
+ }
+
+ if ((void *)packet == (void *)dec->repair_pkt) {
+ dec->repair_pkt = NULL;
+ }
+
+ if (dec->repair_pkt) {
+ a2dp_media_free_packet(dec->repair_pkt);
+ dec->repair_pkt = NULL;
+ }
+ dec->repair_pkt_len = 0;
+}
+
+static void a2dp_stream_underrun_feedback(void *priv);
+static int a2dp_audio_delay_time(struct a2dp_dec_hdl *dec);
+#define a2dp_seqn_before(a, b) ((a < b && (u16)(b - a) < 1000) || (a > b && (u16)(a - b) > 1000))
+static int a2dp_buffered_stream_sample_rate(struct a2dp_dec_hdl *dec, u8 *from_packet, u16 *end_seqn)
+{
+ u8 *packet = from_packet;
+ int len = 0;
+ int sample_rate = 0;
+
+ if (!dec->sample_detect) {
+ return dec->sample_rate;
+ }
+
+ a2dp_frame_sample_detect_start(dec->sample_detect, a2dp_media_dump_rx_time(packet));
+ while (1) {
+ packet = a2dp_media_fetch_packet(&len, packet);
+ if (!packet) {
+ break;
+ }
+ sample_rate = a2dp_frame_sample_detect(dec->sample_detect, packet, len, a2dp_media_dump_rx_time(packet));
+ *end_seqn = RB16(packet + 2);
+ }
+
+ /*printf("A2DP sample detect : %d - %d\n", sample_rate, dec->sample_rate);*/
+ return sample_rate;
+}
+
+static int a2dp_stream_overrun_handler(struct a2dp_dec_hdl *dec, u8 **frame, int *len)
+{
+ u8 *packet = NULL;
+ int rlen = 0;
+
+ int msecs = 0;
+ int overrun = 0;
+ int sample_rate = 0;
+ u16 from_seqn = RB16(dec->repair_pkt + 2);
+ u16 seqn = from_seqn;
+ u16 end_seqn = 0;
+ overrun = 1;
+ while (1) {
+ msecs = a2dp_audio_delay_time(dec);
+ if (msecs < (CONFIG_A2DP_DELAY_TIME + 50) && !a2dp_bt_rx_overrun()) {
+ break;
+ }
+ overrun = 0;
+ rlen = a2dp_media_try_get_packet(&packet);
+ if (rlen <= 0) {
+ break;
+ }
+
+ sample_rate = a2dp_buffered_stream_sample_rate(dec, dec->repair_pkt, &end_seqn);
+ a2dp_decoder_stream_free(dec, NULL);
+ dec->repair_pkt = packet;
+ dec->repair_pkt_len = rlen;
+ seqn = RB16(packet + 2);
+ if (!a2dp_seqn_before(seqn, dec->overrun_seqn)) {
+ *frame = packet;
+ *len = rlen;
+ /*printf("------> end frame : %d\n", dec->overrun_seqn);*/
+ return 1;
+ }
+
+ if (/*sample_rate < (dec->sample_rate * 4 / 5) || */sample_rate > (dec->sample_rate * 4 / 3)) {
+ if (a2dp_seqn_before(dec->overrun_seqn, end_seqn)) {
+ dec->overrun_seqn = end_seqn;
+ }
+ continue;
+ }
+ }
+ if (overrun) {
+ /*putchar('+');*/
+ /* dec->overrun_seqn++; */
+ } else {
+ /*putchar('-');*/
+ }
+
+ *frame = dec->repair_pkt;
+ *len = dec->repair_pkt_len;
+ return 0;
+}
+
+static int a2dp_stream_missed_handler(struct a2dp_dec_hdl *dec, u8 **frame, int *len)
+{
+ int msecs = a2dp_audio_delay_time(dec);
+ *frame = dec->repair_pkt;
+ *len = dec->repair_pkt_len;
+ if ((msecs >= (dec->delay_time + 50) || a2dp_bt_rx_overrun()) || --dec->missed_num == 0) {
+ /*putchar('M');*/
+ return 1;
+ }
+ /*putchar('m');*/
+ return 0;
+}
+
+static int a2dp_stream_underrun_handler(struct a2dp_dec_hdl *dec, u8 **packet)
+{
+
+ if (!a2dp_audio_is_underrun(dec)) {
+ putchar('x');
+ return 0;
+ }
+ putchar('X');
+ if (dec->stream_error != A2DP_STREAM_UNDERRUN) {
+ if (!dec->stream_error) {
+ a2dp_stream_underrun_feedback(dec);
+ }
+ dec->stream_error = a2dp_low_latency ? A2DP_STREAM_LOW_UNDERRUN : A2DP_STREAM_UNDERRUN;
+ dec->repair = a2dp_low_latency ? 0 : 1;
+ }
+ *packet = dec->repair_pkt;
+ dec->repair_frames++;
+ return dec->repair_pkt_len;
+}
+
+static int a2dp_stream_error_filter(struct a2dp_dec_hdl *dec, u8 new_packet, u8 *packet, int len)
+{
+ int err = 0;
+
+ if (dec->coding_type == AUDIO_CODING_AAC) {
+ dec->header_len = get_rtp_header_len(dec->new_frame, packet, len);
+ dec->new_frame = 0;
+ } else {
+ dec->header_len = get_rtp_header_len(1, packet, len);
+ }
+
+ if (dec->header_len >= len) {
+ printf("##A2DP header error : %d\n", dec->header_len);
+ a2dp_decoder_stream_free(dec, packet);
+ return -EFAULT;
+ }
+
+ u16 seqn = RB16(packet + 2);
+ if (new_packet) {
+ if (dec->stream_error == A2DP_STREAM_UNDERRUN) {
+ int missed_frames = (u16)(seqn - dec->seqn) - 1;
+ if (missed_frames > dec->repair_frames) {
+ dec->stream_error = A2DP_STREAM_MISSED;
+ dec->missed_num = missed_frames - dec->repair_frames + 1;
+ /*printf("case 0 : %d, %d\n", missed_frames, dec->repair_frames);*/
+ err = -EAGAIN;
+ } else if (missed_frames < dec->repair_frames) {
+ dec->stream_error = A2DP_STREAM_OVERRUN;
+ dec->overrun_seqn = seqn + dec->repair_frames - missed_frames;
+ /*printf("case 1 : %d, %d, seqn : %d, %d\n", missed_frames, dec->repair_frames, seqn, dec->overrun_seqn);*/
+ err = -EAGAIN;
+ }
+ } else if (!dec->stream_error && (u16)(seqn - dec->seqn) > 1) {
+ dec->stream_error = A2DP_STREAM_MISSED;
+ if (a2dp_audio_delay_time(dec) < dec->delay_time) {
+ dec->missed_num = (u16)(seqn - dec->seqn);
+ err = -EAGAIN;
+ }
+ int pkt_len;
+ void *head = a2dp_media_fetch_packet(&pkt_len, NULL);
+ /*printf("case 2 : %d, %d, pkt : 0x%x, 0x%x\n", seqn, dec->seqn, (u32)head, (u32)packet);*/
+ if (dec->missed_num > 30) {
+ printf("##A serious mistake : A2DP stream missed too much, %d\n", dec->missed_num);
+ dec->missed_num = 30;
+ }
+ }
+ dec->repair_frames = 0;
+ }
+ if (!err && new_packet) {
+ dec->seqn = seqn;
+ }
+ dec->repair_pkt = packet;
+ dec->repair_pkt_len = len;
+ return err;
+}
+
+static int a2dp_dec_get_frame(struct audio_decoder *decoder, u8 **frame)
+{
+ struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);
+ u8 *packet = NULL;
+ int len = 0;
+ u8 new_packet = 0;
+
+try_again:
+ switch (dec->stream_error) {
+ case A2DP_STREAM_OVERRUN:
+ new_packet = a2dp_stream_overrun_handler(dec, &packet, &len);
+ break;
+ case A2DP_STREAM_MISSED:
+ new_packet = a2dp_stream_missed_handler(dec, &packet, &len);
+ break;
+ default:
+ len = a2dp_media_try_get_packet(&packet);
+ if (len <= 0) {
+ len = a2dp_stream_underrun_handler(dec, &packet);
+ } else {
+ a2dp_decoder_stream_free(dec, NULL);
+ new_packet = 1;
+ }
+ break;
+ }
+
+ if (len <= 0) {
+ return 0;
+ }
+
+ int err = a2dp_stream_error_filter(dec, new_packet, packet, len);
+ if (err) {
+ if (-err == EAGAIN) {
+ dec->new_frame = 1;
+ goto try_again;
+ }
+ return 0;
+ }
+
+ *frame = packet + dec->header_len;
+ len -= dec->header_len;
+ if (dec->stream_error && new_packet) {
+#if AUDIO_CODEC_SUPPORT_SYNC && TCFG_USER_TWS_ENABLE
+ if (dec->ts_handle) {
+ tws_a2dp_share_timestamp(dec->ts_handle);
+ }
+#endif
+ dec->stream_error = 0;
+ }
+
+ if (dec->slience_frames) {
+ dec->slience_frames--;
+ }
+ a2dp_decoder_set_timestamp(dec, dec->seqn);
+
+ return len;
+}
+
+
+static void a2dp_dec_put_frame(struct audio_decoder *decoder, u8 *frame)
+{
+ struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);
+
+ if (frame) {
+ if (!a2dp_media_channel_exist() || app_var.goto_poweroff_flag) {
+ a2dp_decoder_stream_free(dec, (void *)(frame - dec->header_len));
+ }
+ /*a2dp_media_free_packet((void *)(frame - dec->header_len));*/
+ }
+}
+
+static int a2dp_dec_fetch_frame(struct audio_decoder *decoder, u8 **frame)
+{
+ struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);
+ u8 *packet = NULL;
+ int len = 0;
+ u32 wait_timeout = 0;
+
+ if (!dec->start) {
+ wait_timeout = jiffies + msecs_to_jiffies(500);
+ }
+
+ dec->fetch_lock = 1;
+__retry_fetch:
+ packet = a2dp_media_fetch_packet(&len, NULL);
+ if (packet) {
+ dec->header_len = get_rtp_header_len(1, packet, len);
+ *frame = packet + dec->header_len;
+ len -= dec->header_len;
+ } else if (!dec->start) {
+ if (time_before(jiffies, wait_timeout)) {
+ os_time_dly(1);
+ goto __retry_fetch;
+ }
+ }
+
+ dec->fetch_lock = 0;
+ return len;
+}
+
+static const struct audio_dec_input a2dp_input = {
+ .coding_type = AUDIO_CODING_SBC,
+ .data_type = AUDIO_INPUT_FRAME,
+ .ops = {
+ .frame = {
+ .fget = a2dp_dec_get_frame,
+ .fput = a2dp_dec_put_frame,
+ .ffetch = a2dp_dec_fetch_frame,
+ }
+ }
+};
+
+#define bt_time_before(t1, t2) \
+ (((t1 < t2) && ((t2 - t1) & 0x7ffffff) < 0xffff) || \
+ ((t1 > t2) && ((t1 - t2) & 0x7ffffff) > 0xffff))
+#define bt_time_to_msecs(clk) (((clk) * 625) / 1000)
+#define msecs_to_bt_time(m) (((m + 1)* 1000) / 625)
+
+static int a2dp_audio_delay_time(struct a2dp_dec_hdl *dec)
+{
+ /*struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);*/
+ int msecs = 0;
+
+#if TCFG_USER_TWS_ENABLE
+ msecs = a2dp_media_get_remain_play_time(1);
+#else
+ msecs = a2dp_media_get_remain_play_time(0);
+#endif
+
+ if (dec->syncts) {
+ msecs += sound_buffered_between_syncts_and_device(dec->syncts, 0);
+ }
+
+ msecs += sound_pcm_dev_buffered_time();
+
+ return msecs;
+}
+
+
+static int a2dp_dec_rx_delay_monitor(struct audio_decoder *decoder, struct rt_stream_info *info)
+{
+ struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);
+ int msecs = 0;
+ int err = 0;
+
+#if AUDIO_CODEC_SUPPORT_SYNC
+ msecs = a2dp_audio_delay_time(dec);
+ if (dec->stream_error) {
+ return 0;
+ }
+
+ if (dec->sync_step == 2) {
+ int distance_time = msecs - a2dp_delay_time;
+ if (a2dp_bt_rx_overrun() && distance_time < 50) {
+ distance_time = 50;
+ }
+
+ if (dec->ts_handle) {
+ a2dp_audio_delay_offset_update(dec->ts_handle, distance_time);
+ }
+ }
+
+#endif
+ /*printf("%d -> %dms, delay_time : %dms\n", msecs1, msecs, a2dp_delay_time);*/
+ return 0;
+}
+static int a2dp_decoder_stream_delay_update(struct audio_decoder *decoder)
+{
+ struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);
+ int msecs = 0;
+ int err = 0;
+
+#if AUDIO_CODEC_SUPPORT_SYNC
+ msecs = a2dp_audio_delay_time(dec);
+ if (dec->stream_error) {
+ return 0;
+ }
+
+ if (dec->sync_step == 2) {
+ int distance_time = msecs - a2dp_delay_time;
+ if (a2dp_bt_rx_overrun() && distance_time < 50) {
+ distance_time = 50;
+ }
+
+ if (dec->ts_handle) {
+ a2dp_audio_delay_offset_update(dec->ts_handle, distance_time);
+ }
+ }
+
+#endif
+ /*printf("%d -> %dms, delay_time : %dms\n", msecs1, msecs, a2dp_delay_time);*/
+ return 0;
+}
+
+/*
+ * A2DP 音频同步控制处理函数
+ * 1.包括音频延时浮动参数;
+ * 2.处理因为超时等情况丢弃音频样点;
+ * 3.调用与蓝牙主机音频延时做同步的功能;
+ * 4.处理TWS从机加入与解码被打断的情况。
+ *
+ */
+static int a2dp_decoder_audio_sync_handler(struct audio_decoder *decoder)
+{
+ struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);
+ int err;
+
+ if (!dec->syncts) {
+ return 0;
+ }
+
+
+ err = a2dp_decoder_stream_delay_update(decoder);
+ if (err) {
+ audio_decoder_suspend(decoder, 0);
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static u16 a2dp_max_interval = 0;
+#define A2DP_EST_AUDIO_CAPACITY 550//ms
+
+static void a2dp_stream_underrun_feedback(void *priv)
+{
+ struct a2dp_dec_hdl *dec = (struct a2dp_dec_hdl *)priv;
+
+ dec->underrun_feedback = 1;
+
+ if (a2dp_delay_time < a2dp_max_interval + 50) {
+ a2dp_delay_time = a2dp_max_interval + 50;
+ } else {
+ a2dp_delay_time += 50;
+ }
+ if (a2dp_delay_time > A2DP_EST_AUDIO_CAPACITY) {
+ a2dp_delay_time = A2DP_EST_AUDIO_CAPACITY;
+ }
+}
+
+/*void a2dp_stream_interval_time_handler(int time)*/
+void reset_a2dp_sbc_instant_time(u16 time)
+{
+ if (a2dp_max_interval < time) {
+ a2dp_max_interval = time;
+ if (a2dp_max_interval > 350) {
+ a2dp_max_interval = 350;
+ }
+#if A2DP_FLUENT_STREAM_MODE
+ if (a2dp_max_interval > a2dp_delay_time) {
+ a2dp_delay_time = a2dp_max_interval + 5;
+ if (a2dp_delay_time > A2DP_EST_AUDIO_CAPACITY) {
+ a2dp_delay_time = A2DP_EST_AUDIO_CAPACITY;
+ }
+ }
+#endif
+ /*printf("Max : %dms\n", time);*/
+ }
+}
+
+static void a2dp_stream_stability_detect(void *priv)
+{
+ struct a2dp_dec_hdl *dec = (struct a2dp_dec_hdl *)priv;
+
+ if (dec->underrun_feedback) {
+ dec->underrun_feedback = 0;
+ return;
+ }
+
+ if (a2dp_delay_time > dec->delay_time) {
+ if (a2dp_max_interval < a2dp_delay_time) {
+ a2dp_delay_time -= 50;
+ if (a2dp_delay_time < dec->delay_time) {
+ a2dp_delay_time = dec->delay_time;
+ }
+
+ if (a2dp_delay_time < a2dp_max_interval) {
+ a2dp_delay_time = a2dp_max_interval + 5;
+ }
+ }
+ a2dp_max_interval = dec->delay_time;
+ }
+}
+
+#if AUDIO_CODEC_SUPPORT_SYNC
+static void a2dp_decoder_update_base_time(struct a2dp_dec_hdl *dec)
+{
+ int distance_time = a2dp_low_latency ? a2dp_delay_time : (a2dp_delay_time - a2dp_media_get_remain_play_time(1));
+ if (!a2dp_low_latency) {
+ distance_time = a2dp_delay_time;
+ } else if (distance_time < 20) {
+ distance_time = 20;
+ }
+ dec->base_time = bt_audio_sync_lat_time() + msecs_to_bt_time(distance_time);
+}
+
+#endif
+static int a2dp_decoder_stream_is_available(struct a2dp_dec_hdl *dec)
+{
+ int err = 0;
+ u8 *packet = NULL;
+ int len = 0;
+ int drop = 0;
+
+#if AUDIO_CODEC_SUPPORT_SYNC
+ if (dec->sync_step) {
+ return 0;
+ }
+
+ packet = (u8 *)a2dp_media_fetch_packet(&len, NULL);
+ if (!packet) {
+ return -EINVAL;
+ }
+
+ dec->seqn = RB16(packet + 2);
+ if (dec->ts_handle) {
+#if TCFG_USER_TWS_ENABLE
+ if (!tws_network_audio_was_started() && !a2dp_audio_timestamp_is_available(dec->ts_handle, dec->seqn, 0, &drop)) {
+ if (drop) {
+ local_irq_disable();
+ u8 *check_packet = (u8 *)a2dp_media_fetch_packet(&len, NULL);
+ if (check_packet && RB16(check_packet + 2) == dec->seqn) {
+ a2dp_media_free_packet(packet);
+ }
+ local_irq_enable();
+ a2dp_decoder_update_base_time(dec);
+ a2dp_audio_set_base_time(dec->ts_handle, dec->base_time);
+ }
+ return -EINVAL;
+ }
+#endif
+ }
+ dec->sync_step = 2;
+#endif
+ return 0;
+}
+
+static int a2dp_dec_probe_handler(struct audio_decoder *decoder)
+{
+ struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);
+ int err = 0;
+
+ err = a2dp_decoder_stream_is_available(dec);
+ if (err) {
+ audio_decoder_suspend(decoder, 0);
+ return err;
+ }
+
+ err = a2dp_decoder_audio_sync_handler(decoder);
+ if (err) {
+ audio_decoder_suspend(decoder, 0);
+ return err;
+ }
+
+ dec->new_frame = 1;
+
+ a2dp_dec_set_output_channel(dec);
+
+ return err;
+}
+
+/*
+*********************************************************************
+* 蓝牙音乐解码输出
+* Description: a2dp高级音频解码输出句柄
+* Arguments :
+* Return : 返回后级消耗的解码数据长度
+* Note(s) : None.
+*********************************************************************
+*/
+#if 0
+static int a2dp_output_after_syncts_filter(void *priv, void *data, int len)
+{
+ int wlen = 0;
+ int drop_len = 0;
+ struct a2dp_dec_hdl *dec = (struct a2dp_dec_hdl *)priv;
+
+#if TCFG_EQ_ENABLE&&TCFG_BT_MUSIC_EQ_ENABLE
+ if (dec->eq_drc && dec->eq_drc->async) {//异步方式eq
+ return eq_drc_run(dec->eq_drc, data, len);
+ }
+#endif//TCFG_BT_MUSIC_EQ_ENABLE
+
+ return audio_mixer_ch_write(&dec->mix_ch, data, len);
+}
+#endif
+
+static int a2dp_output_before_syncts_handler(struct a2dp_dec_hdl *dec, void *data, int len)
+{
+#if AUDIO_CODEC_SUPPORT_SYNC
+ if (dec->ts_start == 1) {
+ u32 timestamp = dec->timestamp;
+ u32 current_time = ((bt_audio_sync_lat_time() + (30000 / 625)) & 0x7ffffff) * 625 * TIME_US_FACTOR;
+#define time_after_timestamp(t1, t2) \
+ ((t1 > t2 && ((t1 - t2) < (10000000L * TIME_US_FACTOR))) || (t1 < t2 && ((t2 - t1) > (10000000L * TIME_US_FACTOR))))
+ if (!time_after_timestamp(timestamp, current_time)) {//时间戳与当前解码时间相差太近,直接丢掉
+ audio_syncts_resample_suspend(dec->syncts);
+ } else {
+ audio_syncts_resample_resume(dec->syncts);
+ dec->mix_ch_event_params[2] = timestamp;
+ dec->ts_start = 2;
+ }
+ }
+#endif
+ return len;
+}
+
+static void audio_filter_resume_decoder(void *priv)
+{
+ struct audio_decoder *decoder = (struct audio_decoder *)priv;
+
+ audio_decoder_resume(decoder);
+}
+
+static int a2dp_decoder_slience_plc_filter(struct a2dp_dec_hdl *dec, void *data, int len)
+{
+ if (len == 0) {
+ a2dp_decoder_stream_free(dec, NULL);
+ if (!dec->stream_error) {
+ dec->stream_error = A2DP_STREAM_DECODE_ERR;
+ dec->repair = 1;
+ }
+ return 0;
+ }
+ if (dec->stream_error) {
+ memset(data, 0x0, len);
+ }
+#if TCFG_USER_TWS_ENABLE
+ u8 tws_pairing = 0;
+ if (dec->preempt || tws_network_audio_was_started()) {
+ /*a2dp播放中副机加入,声音淡入进去*/
+ tws_network_local_audio_start();
+ dec->preempt = 0;
+ tws_pairing = 1;
+ memset(data, 0x0, len);
+ dec->slience_frames = 30;
+ }
+#endif
+#if A2DP_AUDIO_PLC_ENABLE
+ if (dec->plc_ops) {
+ if (dec->slience_frames) {
+ dec->plc_ops->run(dec->plc_mem, data, data, len >> 1, 2);
+ } else if (dec->stream_error) {
+ dec->plc_ops->run(dec->plc_mem, data, data, len >> 1, dec->repair ? 1 : 2);
+ dec->repair = 0;
+ } else {
+ dec->plc_ops->run(dec->plc_mem, data, data, len >> 1, 0);
+ }
+ }
+#else
+ if (dec->slience_frames) {
+ memset(data, 0x0, len);
+ }
+#endif
+ return len;
+}
+
+#if 0
+static int a2dp_output_async_data_handler(struct a2dp_dec_hdl *dec, s16 *data, int len)
+{
+ int offset = 0;
+ int wlen = 0;
+ int data_len = len;
+
+#if (CONFIG_AUDIO_EFFECT_TASK_ENABLE == 0)
+#if CONFIG_TWS_SPATIAL_AUDIO_ENABLE
+ if (dec->spatial_audio) {
+ data_len = dec->spatial_data_len;
+ }
+#endif
+#endif/*CONFIG_AUDIO_EFFECT_TASK_ENABLE*/
+
+#if AUDIO_CODEC_SUPPORT_SYNC
+ if (dec->syncts) {
+ int wlen = audio_syncts_frame_filter(dec->syncts, data, data_len);
+ if (wlen < data_len) {
+ audio_syncts_trigger_resume(dec->syncts, (void *)&dec->decoder, audio_filter_resume_decoder);
+ }
+#if (CONFIG_AUDIO_EFFECT_TASK_ENABLE == 0)
+#if CONFIG_TWS_SPATIAL_AUDIO_ENABLE
+ if (dec->spatial_audio) {
+ dec->spatial_data_len -= wlen;
+ }
+#endif /*CONFIG_TWS_SPATIAL_AUDIO_ENABLE*/
+#endif/*CONFIG_AUDIO_EFFECT_TASK_ENABLE*/
+ dec->remain = wlen < data_len ? 1 : 0;
+ return dec->remain ? wlen : len;
+ }
+#endif
+ wlen = a2dp_output_after_syncts_filter(dec, data, data_len);
+#if (CONFIG_AUDIO_EFFECT_TASK_ENABLE == 0)
+#if CONFIG_TWS_SPATIAL_AUDIO_ENABLE
+ dec->spatial_data_len -= wlen;
+#endif
+#endif/*CONFIG_AUDIO_EFFECT_TASK_ENABLE*/
+ dec->remain = wlen < data_len ? 1 : 0;
+ return dec->remain ? wlen : len;
+
+}
+#endif
+
+static void a2dp_stream_node_init(struct a2dp_dec_hdl *dec)
+{
+ struct a2dp_stream_node *node = &dec->stream_node[A2DP_NODE_DECODER];
+
+ memset(dec->stream_node, 0x0, sizeof(dec->stream_node));
+
+ node->priv = (void *)&dec->decoder;
+ node->id = A2DP_NODE_DECODER;
+ node->wakeup = (void (*)(void *))audio_decoder_resume;
+ node->attribute = A2DP_NODE_BEGIN;
+
+ node = &dec->stream_node[A2DP_NODE_MAX];
+ node->attribute = A2DP_NODE_END;
+ node->id = A2DP_NODE_MAX;
+ dec->node_num = 1;
+}
+
+static void a2dp_stream_node_add(struct a2dp_dec_hdl *dec,
+ void *priv,
+ int (*data_handler)(void *, void *, int),
+ void (*wakeup)(void *),
+ int (*set_wakeup_handler)(void *, void *, void (*wakeup)(void *)),
+ u8 attribute)
+{
+ struct a2dp_stream_node *node = &dec->stream_node[dec->node_num++];
+ node->id = dec->node_num - 1;
+ node->priv = priv;
+ node->data_handler = data_handler;
+ node->wakeup = wakeup;
+ node->set_wakeup_handler = set_wakeup_handler;
+ node->attribute |= attribute;
+}
+
+static void a2dp_stream_node_wakeup(void *priv)
+{
+ struct a2dp_stream_node *node = (struct a2dp_stream_node *)priv;
+ struct a2dp_stream_node *prev_node = node - 1;
+ while (1) {
+ if (prev_node->wakeup) {
+ prev_node->wakeup(prev_node->priv);
+ break;
+ }
+ if (prev_node->attribute & A2DP_NODE_BEGIN) {
+ break;
+ }
+ prev_node--;
+ }
+}
+
+static void a2dp_stream_node_block_and_remain(struct a2dp_stream_node *node)
+{
+ struct a2dp_stream_node *prev_node = node - 1;
+
+ if (node->set_wakeup_handler) {
+ node->set_wakeup_handler(node->priv, node, a2dp_stream_node_wakeup);
+ }
+
+ while (1) {
+ prev_node->remain = 1;
+ if ((prev_node->attribute & A2DP_NODE_BEGIN) || (prev_node->attribute & A2DP_NODE_BLOCK)) {
+ break;
+ }
+ prev_node--;
+ }
+}
+
+static int a2dp_stream_node_data_handler(void *priv, void *data, int len)
+{
+ struct a2dp_stream_node *node = (struct a2dp_stream_node *)priv;
+
+ if (node->attribute & A2DP_NODE_END) {
+ return len;
+ }
+
+ while (1) {
+ node++;
+ if ((node->attribute & A2DP_NODE_END)) {
+ break;
+ }
+
+ if (!node->data_handler) {
+ continue;
+ }
+
+ if ((node->attribute & A2DP_NODE_BLOCK)) {
+ int wlen = node->data_handler(node->priv, data, len);
+ if (wlen < len) {
+ a2dp_stream_node_block_and_remain(node);
+ }
+
+ return wlen;
+ }
+
+ if (!node->remain) {
+ node->data_handler(node->priv, data, len);
+ }
+ node->remain = 0;
+ if (node->attribute & A2DP_NODE_SUB_STREAM_END) {
+ break;
+ }
+ }
+
+ return len;
+}
+
+static int a2dp_dec_output_handler(struct audio_decoder *decoder, s16 *data, int len, void *priv)
+{
+ int wlen = 0;
+ struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);
+
+ return a2dp_stream_node_data_handler(&dec->stream_node[A2DP_NODE_DECODER], data, len);
+#if 0
+ if (!dec->remain) {
+ wlen = a2dp_decoder_slience_plc_filter(dec, data, len);
+ if (wlen < len) {
+ return wlen;
+ }
+#if (CONFIG_AUDIO_EFFECT_TASK_ENABLE == 0)
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+ if (dec->spatial_audio) {
+ dec->spatial_data_len = spatial_audio_filter(dec->spatial_audio, data, len);
+ }
+#endif
+#endif/*CONFIG_AUDIO_EFFECT_TASK_ENABLE*/
+
+#if (TCFG_AUDIO_SPATIAL_EFFECT_ENABLE && TCFG_SENSOR_DATA_READ_IN_DEC_TASK)
+ aud_spatial_sensor_run();
+#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE && TCFG_SENSOR_DATA_READ_IN_DEC_TASK*/
+
+//开空间音效的时候,软件数字音量在空间音效处理后面做
+#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
+ if (!spatial_audio_enable) {
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_run(MUSIC_DVOL, data, len);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+ }
+#endif /*CONFIG_AUDIO_EFFECT_TASK_ENABLE*/
+ a2dp_surround_vbass_handler(dec, data, len);
+
+#if TCFG_EQ_ENABLE&&TCFG_BT_MUSIC_EQ_ENABLE
+ if (dec->eq_drc && !dec->eq_drc->async) {//同步方式eq
+ eq_drc_run(dec->eq_drc, data, len);
+ }
+#endif//TCFG_BT_MUSIC_EQ_ENABLE
+
+ a2dp_output_before_syncts_handler(dec, data, len);
+ }
+
+#if TCFG_AUDIO_ANC_ENABLE && ANC_MUSIC_DYNAMIC_GAIN_EN
+ audio_anc_music_dynamic_gain_det(data, len);
+#endif/*ANC_MUSIC_DYNAMIC_GAIN_EN*/
+
+ return a2dp_output_async_data_handler(dec, data, len);
+#endif
+}
+
+static int a2dp_dec_post_handler(struct audio_decoder *decoder)
+{
+ return 0;
+}
+
+static const struct audio_dec_handler a2dp_dec_handler = {
+ .dec_probe = a2dp_dec_probe_handler,
+ .dec_output = a2dp_dec_output_handler,
+ .dec_post = a2dp_dec_post_handler,
+};
+
+void a2dp_dec_close();
+
+static void a2dp_dec_release()
+{
+ audio_decoder_task_del_wait(&decode_task, &a2dp_dec->wait);
+ a2dp_drop_frame_stop();
+
+ local_irq_disable();
+ free(a2dp_dec);
+ a2dp_dec = NULL;
+ local_irq_enable();
+}
+
+static void a2dp_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
+{
+ switch (argv[0]) {
+ case AUDIO_DEC_EVENT_END:
+ puts("AUDIO_DEC_EVENT_END\n");
+ a2dp_dec_close();
+ break;
+ }
+}
+
+
+static void a2dp_decoder_delay_time_setup(struct a2dp_dec_hdl *dec)
+{
+#if TCFG_USER_TWS_ENABLE
+ int a2dp_low_latency = tws_api_get_low_latency_state();
+#endif
+ if (a2dp_low_latency) {
+ a2dp_delay_time = a2dp_dec->coding_type == AUDIO_CODING_AAC ? CONFIG_A2DP_DELAY_TIME_LO : CONFIG_A2DP_SBC_DELAY_TIME_LO;
+ /*空间音频跑异步任务时,开低延时初始延时需要多10ms*/
+#if (TCFG_AUDIO_SPATIAL_EFFECT_ENABLE && CONFIG_AUDIO_EFFECT_TASK_ENABLE)
+ a2dp_delay_time += 10;
+#endif
+
+ } else {
+ a2dp_delay_time = CONFIG_A2DP_DELAY_TIME;
+ }
+ a2dp_max_interval = 0;
+
+ dec->delay_time = a2dp_delay_time;
+
+ dec->detect_timer = sys_timer_add((void *)dec, a2dp_stream_stability_detect, A2DP_FLUENT_DETECT_INTERVAL);
+}
+
+static int a2dp_decoder_syncts_setup(struct a2dp_dec_hdl *dec)
+{
+ int err = 0;
+#if AUDIO_CODEC_SUPPORT_SYNC
+ a2dp_stream_node_add(dec, dec, a2dp_output_before_syncts_handler, NULL, NULL, 0);
+
+ struct audio_syncts_params params = {0};
+ params.nch = dec->ch;
+ params.pcm_device = sound_pcm_sync_device_select();//PCM_INSIDE_DAC;
+ if (audio_mixer_get_sample_rate(&mixer)) {
+ params.rout_sample_rate = audio_mixer_get_sample_rate(&mixer);
+ } else {
+ params.rout_sample_rate = sound_pcm_match_sample_rate(dec->sample_rate);
+ }
+ params.network = AUDIO_NETWORK_BT2_1;
+ params.rin_sample_rate = dec->sample_rate;
+ params.priv = (void *)&dec->stream_node[dec->node_num];
+ params.factor = TIME_US_FACTOR;
+ params.output = a2dp_stream_node_data_handler;//a2dp_output_after_syncts_filter;
+
+ bt_audio_sync_nettime_select(0);//0 - a2dp主机,1 - tws, 2 - BLE
+
+ a2dp_decoder_update_base_time(dec);
+ dec->ts_handle = a2dp_audio_timestamp_create(dec->sample_rate, dec->base_time, TIME_US_FACTOR);
+
+ err = audio_syncts_open(&dec->syncts, ¶ms);
+ if (!err) {
+ dec->mix_ch_event_params[0] = (u32)&dec->mix_ch;
+ dec->mix_ch_event_params[1] = (u32)dec->syncts;
+ dec->mix_ch_event_params[2] = dec->base_time * 625 * TIME_US_FACTOR;
+ audio_mixer_ch_set_event_handler(&dec->mix_ch, (void *)dec->mix_ch_event_params, audio_mix_ch_event_handler);
+ }
+
+ dec->sync_step = 0;
+ a2dp_stream_node_add(dec, dec->syncts, audio_syncts_frame_filter, NULL, audio_syncts_trigger_resume, A2DP_NODE_BLOCK);
+#endif
+ return err;
+}
+
+static void a2dp_decoder_syncts_free(struct a2dp_dec_hdl *dec)
+{
+#if AUDIO_CODEC_SUPPORT_SYNC
+ if (dec->ts_handle) {
+ a2dp_audio_timestamp_close(dec->ts_handle);
+ dec->ts_handle = NULL;
+ }
+ if (dec->syncts) {
+ audio_syncts_close(dec->syncts);
+ dec->syncts = NULL;
+ }
+#endif
+}
+
+static int a2dp_decoder_plc_setup(struct a2dp_dec_hdl *dec)
+{
+#if A2DP_AUDIO_PLC_ENABLE
+ int plc_mem_size;
+ /*开空间音频没有使用独立任务处理时*/
+#if (TCFG_AUDIO_SPATIAL_EFFECT_ENABLE && (!CONFIG_AUDIO_EFFECT_TASK_ENABLE))
+ u8 ch = 2;
+#else
+ u8 ch = dec->ch;
+#endif
+ dec->plc_ops = get_lfaudioPLC_api();
+ plc_mem_size = dec->plc_ops->need_buf(ch); // 3660bytes,请衡量是否使用该空间换取PLC处理
+ dec->plc_mem = malloc(plc_mem_size);
+ if (!dec->plc_mem) {
+ dec->plc_ops = NULL;
+ return -ENOMEM;
+ }
+ dec->plc_ops->open(dec->plc_mem, ch, a2dp_low_latency ? 4 : 0);
+ a2dp_stream_node_add(dec, dec, a2dp_decoder_slience_plc_filter, NULL, NULL, 0);
+#endif
+ return 0;
+}
+
+static void a2dp_decoder_plc_free(struct a2dp_dec_hdl *dec)
+{
+#if A2DP_AUDIO_PLC_ENABLE
+ if (dec->plc_mem) {
+ free(dec->plc_mem);
+ dec->plc_mem = NULL;
+ }
+#endif
+}
+
+void a2dp_decoder_sample_detect_setup(struct a2dp_dec_hdl *dec)
+{
+ dec->sample_detect = a2dp_sample_detect_open(dec->sample_rate, dec->coding_type);
+}
+
+void a2dp_decoder_sample_detect_free(struct a2dp_dec_hdl *dec)
+{
+ if (dec->sample_detect) {
+ a2dp_sample_detect_close(dec->sample_detect);
+ dec->sample_detect = NULL;
+ }
+}
+
+static int a2dp_decoder_spatial_data_handler(void *priv, void *data, int len)
+{
+ struct a2dp_dec_hdl *dec = (struct a2dp_dec_hdl *)priv;
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+
+ if (!dec->spatial_data_len) {
+ dec->spatial_data_len = spatial_audio_filter(dec->spatial_audio, data, len);
+ dec->spatial_data_offset = 0;
+ }
+
+ if (dec->spatial_data_len) {
+ int wlen = a2dp_stream_node_data_handler(&dec->stream_node[dec->spatial_node_id], (u8 *)data + dec->spatial_data_offset, dec->spatial_data_len);
+ dec->spatial_data_offset += wlen;
+ dec->spatial_data_len -= wlen;
+
+ return dec->spatial_data_len ? 0 : len;
+ }
+
+ return 0;
+#endif
+}
+
+void a2dp_decoder_spatial_audio_setup(struct a2dp_dec_hdl *dec)
+{
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+ if (spatial_audio_enable) {
+ dec->spatial_audio = spatial_audio_open();
+ a2dp_spatial_audio_head_tracked_en(spatial_audio_head_tracked);
+ /*clk_set("sys", SYS_128M);*/
+#if CONFIG_TWS_SPATIAL_AUDIO_ENABLE
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
+ spatial_audio_set_mapping_channel(dec->spatial_audio, tws_api_get_local_channel() == 'L' ? AUDIO_CH_L : AUDIO_CH_R);
+ } else {
+ spatial_audio_set_mapping_channel(dec->spatial_audio, AUDIO_CH_MIX_MONO);
+ }
+#endif
+ a2dp_stream_node_add(dec, dec, a2dp_decoder_spatial_data_handler, NULL, NULL, A2DP_NODE_BLOCK);
+ dec->spatial_node_id = dec->node_num - 1;
+ }
+#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
+}
+
+static void a2dp_stream_read_spatial_audio_setup(struct a2dp_dec_hdl *dec)
+{
+#if (TCFG_AUDIO_SPATIAL_EFFECT_ENABLE && TCFG_SENSOR_DATA_READ_IN_DEC_TASK)
+ if (spatial_audio_head_tracked) {
+ aud_spatial_sensor_init();
+ a2dp_stream_node_add(dec, NULL, aud_spatial_sensor_run, NULL, NULL, 0);
+ }
+#endif /*TCFG_SENSOR_DATA_READ_IN_DEC_TASK*/
+}
+
+#if (TCFG_AUDIO_SPATIAL_EFFECT_ENABLE && TCFG_SENSOR_DATA_READ_IN_DEC_TASK)
+typedef struct {
+ s16 sensor_buf[512];
+ cbuffer_t sensor_cbuf;
+ u16 period;
+ u32 next_period;
+} aud_sensor_t;
+aud_sensor_t *aud_sensor = NULL;
+
+int aud_spatial_sensor_init()
+{
+ int err = 0;
+ aud_sensor = zalloc(sizeof(aud_sensor_t));
+ printf("aud_spatial_sensor_init,need bufsize:%d\n", sizeof(aud_sensor_t));
+ if (aud_sensor) {
+ cbuf_init(&aud_sensor->sensor_cbuf, aud_sensor->sensor_buf, sizeof(aud_sensor->sensor_buf));
+ aud_sensor->period = TCFG_SENSOR_DATA_READ_INTERVAL;
+ aud_sensor->next_period = jiffies;
+ }
+ return err;
+}
+
+int aud_spatial_sensor_exit()
+{
+ int err = 0;
+ printf("aud_spatial_sensor_exit\n");
+ if (aud_sensor) {
+ free(aud_sensor);
+ aud_sensor = NULL;
+ }
+ return err;
+}
+
+extern int spatial_audio_space_data_read(void *data);
+/*定时读取传感器数据到cbuf*/
+static s16 sensor_tmp_data[320];
+int aud_spatial_sensor_run(void *priv, void *data, int len)
+{
+ if (aud_sensor) {
+ if (time_after(jiffies, aud_sensor->next_period)) {
+ aud_sensor->next_period = jiffies + msecs_to_jiffies(aud_sensor->period);
+ int len = spatial_audio_space_data_read(sensor_tmp_data);
+ if (len) {
+ int wlen = cbuf_write(&aud_sensor->sensor_cbuf, sensor_tmp_data, len);
+ }
+ }
+ }
+ return len;
+}
+
+/*从cbuf读取传感器数据*/
+int aud_spatial_sensor_data_read(s16 *data, int len)
+{
+ int rlen = 0;
+ if (aud_sensor) {
+ local_irq_disable();
+ rlen = cbuf_read(&aud_sensor->sensor_cbuf, data, len);
+ local_irq_enable();
+ }
+ return rlen;
+}
+
+/*当前传感器数据量*/
+int aud_spatial_sensor_get_data_len()
+{
+ int len = 0;
+ if (aud_sensor) {
+ len = cbuf_get_data_len(&aud_sensor->sensor_cbuf);
+ }
+ return len;
+}
+#endif /*(TCFG_AUDIO_SPATIAL_EFFECT_ENABLE && TCFG_SENSOR_DATA_READ_IN_DEC_TASK)*/
+
+#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
+
+#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+#define AUD_EFFECT_INBUF_POINTS 1024
+#else
+#define AUD_EFFECT_INBUF_POINTS 512
+#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
+#define AUD_EFFECT_INBUF_SIZE (AUD_EFFECT_INBUF_POINTS << 1)
+#define A2DP_AUDIO_EFFECT_RUN 1
+#define A2DP_AUDIO_EFFECT_FLUSH 2
+#define A2DP_AUDIO_EFFECT_STOP 3
+#define AUDIO_EFFECT_RUN_LEN (AUD_EFFECT_INBUF_SIZE / 2)
+typedef struct {
+ volatile u8 run_flush;
+ volatile u8 need_wakeup;
+ u8 output;
+ u8 trigger_resume;
+ u8 *buff;
+ u16 remain;
+ u16 run_len;
+ s16 *run_buff;
+ s16 output_buf[AUD_EFFECT_INBUF_POINTS];
+ s16 source_buf[AUD_EFFECT_INBUF_POINTS * 2];
+ cbuffer_t source_cbuf;
+ cbuffer_t output_cbuf;
+ void *entry_stream;
+ int (*entry_data_handler)(void *priv, void *data, int len);
+ void *output_priv;
+ int (*output_data_handler)(void *priv, void *data, int len);
+ void *resume_priv;
+ void (*resume_handler)(void *priv);
+ void *parent;
+ spinlock_t lock;
+
+} aud_effect_t;
+/*aud_effect_t *aud_effect = NULL;*/
+
+int aud_effect_push_data(void *priv, s16 *data, u16 len)
+{
+ int wlen = 0;
+ aud_effect_t *effect = (struct aud_effect *)priv;
+
+ if (!effect) {
+ return 0;
+ }
+
+ /*数据写入音效task的音源缓冲*/
+ wlen = cbuf_write(&effect->source_cbuf, data, len);
+ if (wlen < len) {
+ spin_lock(&effect->lock);
+ effect->trigger_resume = 1;
+ spin_unlock(&effect->lock);
+ } else {
+ os_taskq_post_msg("aud_effect", 2, A2DP_AUDIO_EFFECT_RUN, (int)effect);
+ }
+
+ do {
+ if (!effect->output) { /*还未确认运行数据长度*/
+ break;
+ }
+
+ if (!effect->remain) {
+ effect->run_len = AUDIO_EFFECT_RUN_LEN;
+ /*上次输出缓冲已消耗完*/
+ if (cbuf_get_data_len(&effect->output_cbuf) < effect->run_len) {
+ /*输出缓冲不足一次音效run的长度,这里主要使用音效一次run的长度作为运行的基数*/
+ break;
+ }
+ /*复用循环buffer作为输出的缓冲暂存*/
+ effect->buff = cbuf_get_readptr(&effect->output_cbuf);
+ effect->remain = effect->run_len;
+ }
+
+ int output_len = effect->output_data_handler(effect->output_priv, effect->buff, effect->remain);
+ /*printf("%d - %d\n", effect->remain, output_len);*/
+ effect->remain -= output_len;
+ effect->buff += output_len;
+ if (effect->remain) {
+ break;
+ }
+ /*输出完成后更新读指针并刷新至音效task*/
+ cbuf_read_updata(&effect->output_cbuf, effect->run_len);
+ spin_lock(&effect->lock);
+ if (effect->need_wakeup) {
+ effect->need_wakeup = 0;
+ os_taskq_post_msg("aud_effect", 2, A2DP_AUDIO_EFFECT_RUN, (int)effect);
+ }
+ spin_unlock(&effect->lock);
+ } while (1);
+
+ return wlen;
+}
+
+static void aud_effect_data_flush(aud_effect_t *effect)
+{
+ if (effect->need_wakeup) {
+ effect->need_wakeup = 0;
+ }
+}
+
+static int aud_effect_output_data_handler(void *priv, void *data, int len)
+{
+ aud_effect_t *effect = (aud_effect_t *)priv;
+ if (!effect->output) {
+ effect->output = 1;
+ }
+
+ spin_lock(&effect->lock);
+ if (!cbuf_is_write_able(&effect->output_cbuf, len)) {
+ effect->need_wakeup = 1;
+ spin_unlock(&effect->lock);
+ return 0;
+ }
+ spin_unlock(&effect->lock);
+
+ return cbuf_write(&effect->output_cbuf, data, len);
+}
+
+static void aud_effect_data_handler(void *priv)
+{
+ aud_effect_t *effect = (aud_effect_t *)priv;
+ struct a2dp_dec_hdl *dec = (struct a2dp_dec_hdl *)effect->parent;
+
+ if (!effect) {
+ return;
+ }
+
+ while (1) {
+ if (cbuf_get_data_len(&effect->source_cbuf) < AUDIO_EFFECT_RUN_LEN) {
+ return;
+ }
+
+ effect->run_buff = cbuf_get_readptr(&effect->source_cbuf);
+ int run_len = AUDIO_EFFECT_RUN_LEN;
+
+#if 0
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+ if (dec->spatial_audio) {
+ run_len = spatial_audio_filter(dec->spatial_audio, effect->run_buff, run_len);
+ }
+#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
+#else
+ if (effect->entry_data_handler) {
+ run_len = effect->entry_data_handler(effect->entry_stream, effect->run_buff, run_len);
+ }
+#endif
+
+ /*run_len = aud_effect_output_data_handler(effect, effect->run_buff, run_len);*/
+ /*printf("run : %d\n", run_len);*/
+ cbuf_read_updata(&effect->source_cbuf, run_len);
+ spin_lock(&effect->lock);
+ if (effect->trigger_resume) {
+ if (run_len) {
+ effect->resume_handler(effect->resume_priv);
+ }
+ effect->trigger_resume = 0;
+ }
+ spin_unlock(&effect->lock);
+ if (run_len < AUDIO_EFFECT_RUN_LEN) {
+ break;
+ }
+ }
+}
+
+static void aud_effect_task(void *p)
+{
+ printf("===Audio Effect Task===\n");
+ int wlen = 0;
+ u8 pend = 1;
+ int msg[16];
+ int res;
+
+ while (1) {
+ if (pend) {
+ res = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
+ } else {
+ res = os_taskq_accept(ARRAY_SIZE(msg), msg);
+ }
+
+ if (res == OS_TASKQ) {
+ switch (msg[1]) {
+ case A2DP_AUDIO_EFFECT_RUN:
+ aud_effect_data_handler((void *)msg[2]);
+ break;
+ case A2DP_AUDIO_EFFECT_FLUSH:
+ aud_effect_data_flush((aud_effect_t *)msg[2]);
+ break;
+ case A2DP_AUDIO_EFFECT_STOP:
+ os_taskq_flush();
+ os_sem_post((OS_SEM *)msg[2]);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+#endif /*CONFIG_AUDIO_EFFECT_TASK_ENABLE*/
+
+int a2dp_decoder_effect_task_enter(struct a2dp_dec_hdl *dec)
+{
+ int err = 0;
+
+#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
+ aud_effect_t *aud_effect = zalloc(sizeof(aud_effect_t));
+ printf("audio_dec_effect_process_start,need bufsize:%d\n", sizeof(aud_effect_t));
+ if (aud_effect) {
+ cbuf_init(&aud_effect->source_cbuf, aud_effect->source_buf, sizeof(aud_effect->source_buf));
+ cbuf_init(&aud_effect->output_cbuf, aud_effect->output_buf, sizeof(aud_effect->output_buf));
+ err = task_create(aud_effect_task, NULL, "aud_effect");
+
+ aud_effect->parent = (void *)dec;
+ aud_effect->resume_handler = (void (*)(void *))a2dp_stream_node_wakeup;
+ aud_effect->resume_priv = (void *)&dec->stream_node[dec->node_num];
+ aud_effect->entry_stream = (void *)&dec->stream_node[dec->node_num];
+ aud_effect->entry_data_handler = a2dp_stream_node_data_handler;
+ spin_lock_init(&aud_effect->lock);
+
+ dec->aud_effect = aud_effect;
+ a2dp_stream_node_add(dec, aud_effect, aud_effect_push_data, NULL, NULL, A2DP_NODE_SUB_STREAM_BEGIN | A2DP_NODE_BLOCK);
+ }
+#endif
+
+ return err;
+}
+
+int a2dp_decoder_effect_task_output(struct a2dp_dec_hdl *dec)
+{
+#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
+ if (dec->aud_effect) {
+ aud_effect_t *aud_effect = (aud_effect_t *)dec->aud_effect;
+ aud_effect->output_data_handler = a2dp_stream_node_data_handler;
+ aud_effect->output_priv = (void *)&dec->stream_node[dec->node_num];
+ a2dp_stream_node_add(dec, aud_effect, aud_effect_output_data_handler, NULL, NULL, A2DP_NODE_SUB_STREAM_END | A2DP_NODE_BLOCK);
+ }
+#endif
+ return 0;
+}
+
+int audio_effect_process_stop(struct a2dp_dec_hdl *dec)
+{
+ int err = 0;
+#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
+ aud_effect_t *aud_effect = (aud_effect_t *)dec->aud_effect;
+ printf("audio_effect_process_stop\n");
+ if (aud_effect) {
+ OS_SEM *sem = (OS_SEM *)malloc(sizeof(OS_SEM));
+ os_sem_create(sem, 0);
+ /*处理消息队列满了的情况*/
+ while (os_taskq_post_msg("aud_effect", 2, A2DP_AUDIO_EFFECT_STOP, (int)sem)) {
+ os_time_dly(2);
+ }
+ os_sem_pend(sem, 0);
+ free(sem);
+ task_kill("aud_effect");
+ free(aud_effect);
+ aud_effect = NULL;
+ }
+ dec->aud_effect = NULL;
+#endif
+ return err;
+}
+
+static int a2dp_decoder_volume_run(void *priv, void *data, int len)
+{
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_run((u8)priv, data, len);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+ return len;
+}
+
+static void a2dp_decoder_volume_setup(struct a2dp_dec_hdl *dec)
+{
+ app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_open(MUSIC_DVOL, app_audio_get_volume(APP_AUDIO_STATE_MUSIC), MUSIC_DVOL_MAX, MUSIC_DVOL_FS, -1);
+ a2dp_stream_node_add(dec, (void *)MUSIC_DVOL, a2dp_decoder_volume_run, NULL, NULL, 0);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+}
+
+
+static int a2dp_anc_dynamic_gain_handler(void *priv, void *data, int len)
+{
+#if TCFG_AUDIO_ANC_ENABLE && ANC_MUSIC_DYNAMIC_GAIN_EN
+ audio_anc_music_dynamic_gain_det(data, len);
+#endif/*ANC_MUSIC_DYNAMIC_GAIN_EN*/
+ return len;
+}
+
+static void a2dp_anc_dynamic_gain_setup(struct a2dp_dec_hdl *dec)
+{
+#if TCFG_AUDIO_ANC_ENABLE && ANC_MUSIC_DYNAMIC_GAIN_EN
+ audio_anc_music_dynamic_gain_init(dec->sample_rate);
+ a2dp_stream_node_add(dec, 0, a2dp_anc_dynamic_gain_handler, NULL, NULL, 0);
+#endif/*ANC_MUSIC_DYNAMIC_GAIN_EN*/
+}
+static int a2dp_surround_vbass_handler(struct a2dp_dec_hdl *dec, void *data, int len);
+static void a2dp_surround_vbass_setup(struct a2dp_dec_hdl *dec)
+{
+#if AUDIO_SURROUND_CONFIG
+ dec->sur = audio_surround_setup(dec->channel, a2dp_surround_eff);
+#endif//AUDIO_SURROUND_CONFIG
+
+#if AUDIO_VBASS_CONFIG
+ dec->vbass = audio_vbass_setup(dec->sample_rate, dec->ch);
+#endif//AUDIO_VBASS_CONFIG
+
+#if AUDIO_SURROUND_CONFIG || AUDIO_VBASS_CONFIG
+ a2dp_stream_node_add(dec, dec, a2dp_surround_vbass_handler, NULL, NULL, 0);
+#endif
+}
+
+static int a2dp_surround_vbass_handler(struct a2dp_dec_hdl *dec, void *data, int len)
+{
+#if AUDIO_SURROUND_CONFIG
+ if (dec->sur && dec->sur->surround) {
+ audio_surround_run(dec->sur->surround, data, len);
+ }
+#endif/*AUDIO_SURROUND_CONFIG*/
+
+#if AUDIO_VBASS_CONFIG
+ if (dec->vbass) {
+ if (!dec->vbass->status) {
+ struct virtual_bass_tool_set *parm = get_vbass_parm();
+ GainProcess_16Bit(data, data, powf(10, parm->prev_gain / 20.0f), dec->ch, (dec->ch == 1 ? 1 : 2), (dec->ch == 1 ? 1 : 2), (len >> 1) / dec->ch);
+ }
+
+ audio_vbass_run(dec->vbass, data, len);
+ }
+#endif/*AUDIO_VBASS_CONFIG*/
+
+ return len;
+}
+
+static void a2dp_eq_drc_setup(struct a2dp_dec_hdl *dec)
+{
+#if TCFG_EQ_ENABLE&&TCFG_BT_MUSIC_EQ_ENABLE
+ u8 drc_en = 0;
+#if TCFG_DRC_ENABLE&&TCFG_BT_MUSIC_DRC_ENABLE
+ drc_en = 1;
+#endif//TCFG_BT_MUSIC_DRC_ENABLE
+
+ a2dp_decoder_sample_detect_setup(dec);
+ int async = 1;
+#if defined(AUDIO_GAME_EFFECT_CONFIG) && AUDIO_GAME_EFFECT_CONFIG
+ if (a2dp_low_latency) {
+ drc_en |= BIT(1);
+ async = 0;
+ }
+#endif /*AUDIO_GAME_EFFECT_CONFIG*/
+
+#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
+ async = 0;
+#endif
+ u32 sample_rate = dec->sample_rate;
+ if (audio_mixer_get_sample_rate(&mixer)) {
+ sample_rate = audio_mixer_get_sample_rate(&mixer);
+ }
+#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
+ if (1) {//spatial_audio_enable) {
+ /*audio_effect_process_start(dec, &dec->mix_ch, audio_mixer_ch_write);*/
+ dec->eq_drc = dec_eq_drc_setup((void *)&dec->stream_node[dec->node_num], (eq_output_cb)a2dp_stream_node_data_handler, sample_rate, dec->ch, async, drc_en);
+ a2dp_stream_node_add(dec, dec->eq_drc, eq_drc_run, NULL, NULL, async ? A2DP_NODE_BLOCK : 0);
+ } else
+#endif/*CONFIG_AUDIO_EFFECT_TASK_ENABLE*/
+ {
+ dec->eq_drc = dec_eq_drc_setup((void *)&dec->stream_node[dec->node_num], (eq_output_cb)a2dp_stream_node_data_handler, sample_rate, dec->ch, async, drc_en);
+ a2dp_stream_node_add(dec, dec->eq_drc, eq_drc_run, NULL, NULL, async ? A2DP_NODE_BLOCK : 0);
+ }
+
+#endif//TCFG_BT_MUSIC_EQ_ENABLE
+}
+
+static void a2dp_bass_bost_setup(struct a2dp_dec_hdl *dec)
+{
+#if defined(TCFG_AUDIO_BASS_BOOST)&&TCFG_AUDIO_BASS_BOOST
+ dec->bass_boost = audio_bass_boost_open(dec->sample_rate, dec->ch);
+ a2dp_stream_node_add(dec, dec->bass_boost, audio_bass_boost_run, NULL, NULL, 0);
+#endif
+}
+
+static int a2dp_effect_develop_setup(struct a2dp_dec_hdl *dec)
+{
+#if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE)
+ dec->effect_develop = audio_effect_develop_open(dec->sample_rate, dec->ch, 16);
+ a2dp_stream_node_add(dec, dec->effect_develop, audio_effect_develop_data_handler, NULL, NULL, 0);
+#endif
+ return 0;
+}
+
+static void a2dp_effect_develop_close(struct a2dp_dec_hdl *dec)
+{
+#if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE)
+ if (dec->effect_develop) {
+ audio_effect_develop_close(dec->effect_develop);
+ dec->effect_develop = NULL;
+ }
+#endif
+}
+
+void audio_overlay_load_code(u32 type);
+int a2dp_dec_start()
+{
+ int err;
+ struct audio_fmt *fmt;
+ enum audio_channel channel;
+ struct a2dp_dec_hdl *dec = a2dp_dec;
+
+ if (!a2dp_dec) {
+ return -EINVAL;
+ }
+
+ a2dp_drop_frame_stop();
+ puts("a2dp_dec_start: in\n");
+
+ if (a2dp_dec->coding_type == AUDIO_CODING_AAC) {
+ audio_overlay_load_code(a2dp_dec->coding_type);
+ }
+
+ err = audio_decoder_open(&dec->decoder, &a2dp_input, &decode_task);
+ if (err) {
+ goto __err1;
+ }
+ dec->channel = AUDIO_CH_MAX;
+
+ audio_decoder_set_handler(&dec->decoder, &a2dp_dec_handler);
+ audio_decoder_set_event_handler(&dec->decoder, a2dp_dec_event_handler, 0);
+
+ if (a2dp_dec->coding_type != a2dp_input.coding_type) {
+ struct audio_fmt f = {0};
+ f.coding_type = a2dp_dec->coding_type;
+ err = audio_decoder_set_fmt(&dec->decoder, &f);
+ if (err) {
+ goto __err2;
+ }
+ }
+
+ err = audio_decoder_get_fmt(&dec->decoder, &fmt);
+ if (err) {
+ goto __err2;
+ }
+
+ if (fmt->sample_rate == 0) {
+ log_w("A2DP stream maybe error\n");
+ goto __err2;
+ }
+ //dac_hdl.dec_channel_num = fmt->channel;
+ dec->sample_rate = fmt->sample_rate;
+
+ a2dp_dec_set_output_channel(dec);
+
+ a2dp_stream_node_init(dec);
+
+ a2dp_decoder_delay_time_setup(dec);
+
+ a2dp_decoder_plc_setup(dec);
+
+#if !CONFIG_AUDIO_EFFECT_TASK_ENABLE /*当空间音效不在异步task中时放在解码后第二个节点效率最高*/
+ a2dp_decoder_spatial_audio_setup(dec);
+#endif
+ a2dp_stream_read_spatial_audio_setup(dec);
+
+ set_source_sample_rate(fmt->sample_rate);
+
+ /*sound_pcm_set_underrun_params(3, dec, NULL);//a2dp_stream_underrun_feedback);*/
+
+ audio_mixer_ch_open(&dec->mix_ch, &mixer);
+ audio_mixer_ch_set_sample_rate(&dec->mix_ch, A2DP_SOUND_SAMPLE_RATE ? A2DP_SOUND_SAMPLE_RATE : sound_pcm_match_sample_rate(fmt->sample_rate));
+
+#if !CONFIG_AUDIO_EFFECT_TASK_ENABLE
+ a2dp_decoder_volume_setup(dec);
+#endif
+
+ a2dp_effect_develop_setup(dec);
+
+ a2dp_surround_vbass_setup(dec);
+ a2dp_bass_bost_setup(dec);
+
+ a2dp_anc_dynamic_gain_setup(dec);
+
+ a2dp_decoder_syncts_setup(dec);
+
+ a2dp_eq_drc_setup(dec);
+
+ a2dp_decoder_effect_task_enter(dec); /*enter到output的节点全部在effect task中执行*/
+
+#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
+ a2dp_decoder_spatial_audio_setup(dec);
+
+ a2dp_decoder_volume_setup(dec); /*数字音量处理放在空间音频之后处理*/
+#endif
+
+ a2dp_decoder_effect_task_output(dec);
+
+ a2dp_stream_node_add(dec, &dec->mix_ch, (int (*)(void *, void *, int))audio_mixer_ch_write, NULL, NULL, A2DP_NODE_BLOCK);
+ audio_mixer_ch_set_resume_handler(&dec->mix_ch, &dec->stream_node[dec->node_num - 1], a2dp_stream_node_wakeup);
+
+ a2dp_drop_frame_stop();
+ dec->remain = 0;
+ audio_codec_clock_set(AUDIO_A2DP_MODE, dec->coding_type, dec->wait.preemption);
+ /* dec->state = A2DP_STREAM_START; */
+
+ err = audio_decoder_start(&dec->decoder);
+ if (err) {
+ goto __err3;
+ }
+
+ if (get_sniff_out_status()) {
+ clear_sniff_out_status();
+ }
+ sound_pcm_dev_try_power_on();
+ dec->start = 1;
+
+ return 0;
+
+__err3:
+ audio_mixer_ch_close(&a2dp_dec->mix_ch);
+__err2:
+ audio_decoder_close(&dec->decoder);
+__err1:
+ a2dp_dec_release();
+
+ return err;
+}
+
+static int a2dp_dut_dec_start(void)
+{
+ int err;
+ struct audio_fmt *fmt;
+ enum audio_channel channel;
+ struct a2dp_dec_hdl *dec = a2dp_dec;
+
+ if (!a2dp_dec) {
+ return -EINVAL;
+ }
+
+ a2dp_drop_frame_stop();
+ puts("a2dp_dut_dec_start: in\n");
+
+ if (a2dp_dec->coding_type == AUDIO_CODING_AAC) {
+ audio_overlay_load_code(a2dp_dec->coding_type);
+ }
+
+ err = audio_decoder_open(&dec->decoder, &a2dp_input, &decode_task);
+ if (err) {
+ goto __err1;
+ }
+ dec->channel = AUDIO_CH_MAX;
+
+ audio_decoder_set_handler(&dec->decoder, &a2dp_dec_handler);
+ audio_decoder_set_event_handler(&dec->decoder, a2dp_dec_event_handler, 0);
+
+ if (a2dp_dec->coding_type != a2dp_input.coding_type) {
+ struct audio_fmt f = {0};
+ f.coding_type = a2dp_dec->coding_type;
+ err = audio_decoder_set_fmt(&dec->decoder, &f);
+ if (err) {
+ goto __err2;
+ }
+ }
+
+ err = audio_decoder_get_fmt(&dec->decoder, &fmt);
+ if (err) {
+ goto __err2;
+ }
+
+ if (fmt->sample_rate == 0) {
+ log_w("A2DP stream maybe error\n");
+ goto __err2;
+ }
+ //dac_hdl.dec_channel_num = fmt->channel;
+ dec->sample_rate = fmt->sample_rate;
+
+ a2dp_dec_set_output_channel(dec);
+ a2dp_stream_node_init(dec);
+
+ a2dp_decoder_delay_time_setup(dec);
+
+ a2dp_decoder_plc_setup(dec);
+
+ set_source_sample_rate(fmt->sample_rate);
+
+ audio_mixer_ch_open(&dec->mix_ch, &mixer);
+ audio_mixer_ch_set_sample_rate(&dec->mix_ch, A2DP_SOUND_SAMPLE_RATE ? A2DP_SOUND_SAMPLE_RATE : sound_pcm_match_sample_rate(fmt->sample_rate));
+
+ //dut 需添加数字音量处理
+ a2dp_decoder_volume_setup(dec);
+
+#if TCFG_AUDIO_CVP_DUT_ENABLE
+ if (audio_dec_dut_en_get(0) == AUDIO_DEC_DUT_MODE_SPK_EQ) {
+ a2dp_eq_drc_setup(dec);
+ }
+#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
+
+ a2dp_decoder_syncts_setup(dec);
+
+ a2dp_stream_node_add(dec, &dec->mix_ch, (int (*)(void *, void *, int))audio_mixer_ch_write, NULL, NULL, A2DP_NODE_BLOCK);
+ audio_mixer_ch_set_resume_handler(&dec->mix_ch, &dec->stream_node[dec->node_num - 1], a2dp_stream_node_wakeup);
+ dec->remain = 0;
+ audio_codec_clock_set(AUDIO_A2DP_MODE, dec->coding_type, dec->wait.preemption);
+
+ err = audio_decoder_start(&dec->decoder);
+ if (err) {
+ goto __err3;
+ }
+
+ sound_pcm_dev_try_power_on();
+ dec->start = 1;
+
+ return 0;
+
+__err3:
+ audio_mixer_ch_close(&a2dp_dec->mix_ch);
+__err2:
+ audio_decoder_close(&dec->decoder);
+__err1:
+ a2dp_dec_release();
+
+ return err;
+}
+
+static int __a2dp_audio_res_close(void)
+{
+ a2dp_dec->start = 0;
+ if (a2dp_dec->detect_timer) {
+ sys_timer_del(a2dp_dec->detect_timer);
+ }
+ a2dp_decoder_sample_detect_free(a2dp_dec);
+ audio_decoder_close(&a2dp_dec->decoder);
+ audio_effect_process_stop(a2dp_dec);
+ audio_mixer_ch_close(&a2dp_dec->mix_ch);
+ a2dp_decoder_syncts_free(a2dp_dec);
+ a2dp_decoder_plc_free(a2dp_dec);
+ a2dp_effect_develop_close(a2dp_dec);
+ a2dp_decoder_stream_free(a2dp_dec, NULL);
+#if TCFG_EQ_ENABLE&&TCFG_BT_MUSIC_EQ_ENABLE
+ if (a2dp_dec->eq_drc) {
+ dec_eq_drc_free(a2dp_dec->eq_drc);
+ a2dp_dec->eq_drc = NULL;
+ }
+#endif//TCFG_BT_MUSIC_EQ_ENABLE
+
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+ if (a2dp_dec->spatial_audio) {
+ spatial_audio_close(a2dp_dec->spatial_audio);
+ a2dp_dec->spatial_audio = NULL;
+ }
+#if TCFG_SENSOR_DATA_READ_IN_DEC_TASK
+ aud_spatial_sensor_exit();
+#endif /*TCFG_SENSOR_DATA_READ_IN_DEC_TASK*/
+#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
+
+#if AUDIO_SURROUND_CONFIG
+ if (a2dp_dec->sur) {
+ audio_surround_free(a2dp_dec->sur);
+ a2dp_dec->sur = NULL;
+ }
+#endif//AUDIO_SURROUND_CONFIG
+
+#if AUDIO_VBASS_CONFIG
+ if (a2dp_dec->vbass) {
+ audio_vbass_free(a2dp_dec->vbass);
+ a2dp_dec->vbass = NULL;
+ }
+#endif//AUDIO_VBASS_CONFIG
+
+#if defined(TCFG_AUDIO_BASS_BOOST) && TCFG_AUDIO_BASS_BOOST
+ if (a2dp_dec->bass_boost) {
+ audio_bass_boost_close(a2dp_dec->bass_boost);
+ a2dp_dec->bass_boost = NULL;
+ }
+#endif
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_close(MUSIC_DVOL);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+#if 0
+ clk_set_sys_lock(BT_NORMAL_HZ, 0);
+#else
+ audio_codec_clock_del(AUDIO_A2DP_MODE);
+#endif
+
+ a2dp_dec->preempt = 1;
+ app_audio_state_exit(APP_AUDIO_STATE_MUSIC);
+ return 0;
+}
+
+static int a2dp_wait_res_handler(struct audio_res_wait *wait, int event)
+{
+ int err = 0;
+
+ if (event == AUDIO_RES_GET) {
+ printf("a2dp_res:Get\n");
+ if (a2dp_dec->dut_enable) {
+ err = a2dp_dut_dec_start();
+ } else {
+ err = a2dp_dec_start();
+ }
+ } else if (event == AUDIO_RES_PUT) {
+ printf("a2dp_res:Put\n");
+ if (a2dp_dec->start) {
+ __a2dp_audio_res_close();
+ a2dp_drop_frame_start();
+ }
+ }
+ return err;
+}
+
+#define A2DP_CODEC_SBC 0x00
+#define A2DP_CODEC_MPEG12 0x01
+#define A2DP_CODEC_MPEG24 0x02
+#define A2DP_CODEC_LDAC 0x0B
+int __a2dp_dec_open(int media_type, u8 resume, u8 dut_enable)
+{
+#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_AND_MUSIC_MUTEX)
+ /*辅听与播歌互斥时,关闭辅听*/
+ if (get_hearing_aid_fitting_state() == 0) {
+ audio_hearing_aid_suspend();
+ }
+#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
+
+ struct a2dp_dec_hdl *dec;
+
+ if (strcmp(os_current_task(), "app_core") != 0) {
+ log_e("a2dp dec open in task : %s\n", os_current_task());
+ }
+
+ if (a2dp_suspend) {
+ if (tws_api_get_role() == TWS_ROLE_MASTER) {
+ if (drop_a2dp_timer == 0) {
+ drop_a2dp_timer = sys_timer_add(NULL,
+ a2dp_media_clear_packet_before_seqn, 100);
+ }
+ }
+ return 0;
+ }
+
+ if (a2dp_dec) {
+ return 0;
+ }
+
+ media_type = a2dp_media_get_codec_type();
+ printf("a2dp_dec_open: %d\n", media_type);
+
+ dec = zalloc(sizeof(*dec));
+ if (!dec) {
+ return -ENOMEM;
+ }
+
+ switch (media_type) {
+ case A2DP_CODEC_SBC:
+ printf("a2dp_media_type:SBC");
+ dec->coding_type = AUDIO_CODING_SBC;
+ break;
+ case A2DP_CODEC_MPEG24:
+ printf("a2dp_media_type:AAC");
+ dec->coding_type = AUDIO_CODING_AAC;
+ break;
+ case A2DP_CODEC_LDAC:
+ printf("a2dp_media_type:LDAC");
+ dec->coding_type = AUDIO_CODING_LDAC;
+ break;
+ default:
+ printf("a2dp_media_type unsupoport:%d", media_type);
+ free(dec);
+ return -EINVAL;
+ }
+
+#if TCFG_USER_TWS_ENABLE
+ if (CONFIG_LOW_LATENCY_ENABLE) {
+ a2dp_low_latency = tws_api_get_low_latency_state();
+ }
+#endif
+ a2dp_dec = dec;
+ dec->preempt = resume ? 1 : 0;
+ dec->wait.priority = 0;
+ dec->wait.preemption = 1;
+ dec->wait.handler = a2dp_wait_res_handler;
+ dec->dut_enable = dut_enable;
+ audio_decoder_task_add_wait(&decode_task, &dec->wait);
+
+
+#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_FITTING_ENABLE)
+ /*辅听验配过程不允许播放歌曲*/
+ extern u8 get_hearing_aid_fitting_state(void);
+ if (get_hearing_aid_fitting_state()) {
+ printf("hearing aid fitting : %d\n !!!", get_hearing_aid_fitting_state());
+ extern a2dp_tws_dec_suspend(void *p);
+ a2dp_tws_dec_suspend(NULL);
+ return 0;
+ }
+#endif /*TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_FITTING_ENABLE*/
+ if (a2dp_dec && (a2dp_dec->start == 0)) {
+ a2dp_drop_frame_start();
+ }
+
+ return 0;
+}
+
+int a2dp_dec_open(int media_type)
+{
+#if TCFG_AUDIO_SPEAK_TO_CHAT_ENABLE
+ if (get_speak_to_chat_state() == AUDIO_ADT_CHAT) {
+ audio_speak_to_char_sync_suspend();
+ }
+#endif
+ return __a2dp_dec_open(media_type, 0, 0);
+}
+
+int a2dp_dut_dec_open(int media_type)
+{
+ return __a2dp_dec_open(media_type, 0, 1);
+}
+
+void a2dp_dec_close()
+{
+ if (!a2dp_dec) {
+ if (CONFIG_LOW_LATENCY_ENABLE) {
+ a2dp_low_latency_seqn = 0;
+ }
+ if (drop_a2dp_timer) {
+ sys_timer_del(drop_a2dp_timer);
+ drop_a2dp_timer = 0;
+ }
+ return;
+ }
+
+ if (a2dp_dec->start) {
+ __a2dp_audio_res_close();
+ }
+
+ a2dp_dec_release();
+
+#if TCFG_AUDIO_ANC_ENABLE && ANC_MUSIC_DYNAMIC_GAIN_EN
+ audio_anc_music_dynamic_gain_reset(1);
+#endif/*ANC_MUSIC_DYNAMIC_GAIN_EN*/
+#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_AND_MUSIC_MUTEX)
+ audio_hearing_aid_resume();
+#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
+
+ puts("a2dp_dec_close: exit\n");
+}
+
+void a2dp_dec_dut_enable(u8 dut_enable)
+{
+ if (!a2dp_dec) {
+ return;
+ }
+ if (a2dp_dec->start) {
+ a2dp_dec_close();
+ if (dut_enable) {
+ a2dp_dut_dec_open(0);
+ } else {
+ a2dp_dec_open(0);
+ }
+ }
+}
+
+//*********************************************************************************//
+// 空间音效接口(Spatial Effect APIs) //
+//*********************************************************************************//
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+int a2dp_spatial_audio_open(void)
+{
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+ spatial_audio_enable = 1;
+ if (a2dp_dec && !a2dp_dec->spatial_audio) {
+ a2dp_dec->spatial_audio = spatial_audio_open();
+ }
+#endif
+ return 0;
+}
+
+void a2dp_spatial_audio_close(void)
+{
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+ local_irq_disable();
+ if (a2dp_dec && a2dp_dec->spatial_audio) {
+ spatial_audio_close(a2dp_dec->spatial_audio);
+ a2dp_dec->spatial_audio = NULL;
+ }
+ spatial_audio_enable = 0;
+ spatial_audio_head_tracked = 0;
+ local_irq_enable();
+#endif
+}
+
+u8 get_a2dp_spatial_audio_status(void)
+{
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+ if (a2dp_dec) {
+ return (a2dp_dec->spatial_audio != NULL) ? 1 : 0;
+ }
+#endif
+ return 0;
+}
+
+u8 get_spatial_audio_enable()
+{
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+ return spatial_audio_enable;
+#endif
+ return 0;
+}
+
+void a2dp_spatial_audio_head_tracked_en(u8 en)
+{
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+ if (a2dp_dec && a2dp_dec->spatial_audio) {
+ spatial_audio_head_tracked = en;
+ spatial_audio_head_tracked_en(a2dp_dec->spatial_audio, en);
+ }
+#endif
+}
+
+u8 get_a2dp_spatial_audio_head_tracked(void)
+{
+#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
+ return spatial_audio_head_tracked;
+#endif
+ return 0;
+}
+
+void a2dp_spatial_audio_setup(u8 en, u8 head_track)
+{
+ spatial_audio_enable = en;
+ spatial_audio_head_tracked = head_track;
+}
+int a2dp_tws_dec_suspend(void *p);
+void a2dp_tws_dec_resume(void);
+/*
+ 空间音效模式切换
+mode:
+ 0:关闭头部跟踪
+ 1:打开空间音效
+ 2:打开头部跟踪
+tone_play:
+ 1 : 切换时播放提示音
+ 0 : 不播放提示音
+*/
+void audio_spatial_effects_mode_switch(u8 mode, u8 tone_play)
+{
+ u8 tone_index = 0;
+ if (a2dp_dec) {
+ /*先挂起再改变标志*/
+ a2dp_tws_dec_suspend(a2dp_dec);
+ if (mode == 0) {
+ printf("SpatialAudio:close_fixed");
+ a2dp_spatial_audio_setup(0, 0);
+ tone_index = IDEX_TONE_NUM_0;
+ } else if (mode == 1) {
+ printf("SpatialAudio:open_fixed");
+ a2dp_spatial_audio_setup(1, 0);
+ tone_index = IDEX_TONE_NUM_1;
+ } else if (mode == 2) {
+ printf("SpatialAudio:open_tracked");
+ a2dp_spatial_audio_setup(1, 1);
+ tone_index = IDEX_TONE_NUM_2;
+ }
+ a2dp_tws_dec_resume();
+ if (tone_play) {
+ tone_play_index(tone_index, 1);
+ }
+ }
+}
+#endif/*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
+
+
+static void a2dp_low_latency_clear_a2dp_packet(u8 *data, int len, int rx)
+{
+ if (rx) {
+ a2dp_low_latency_seqn = (data[0] << 8) | data[1];
+ }
+}
+REGISTER_TWS_FUNC_STUB(audio_dec_clear_a2dp_packet) = {
+ .func_id = 0x132A6578,
+ .func = a2dp_low_latency_clear_a2dp_packet,
+};
+
+
+static void low_latency_drop_a2dp_frame(void *p)
+{
+ int len;
+
+ /*y_printf("low_latency_drop_a2dp_frame\n");*/
+
+ if (a2dp_low_latency_seqn == 0) {
+ a2dp_media_clear_packet_before_seqn(0);
+ return;
+ }
+ while (1) {
+ u8 *packet = a2dp_media_fetch_packet(&len, NULL);
+ if (!packet) {
+ return;
+ }
+ u16 seqn = (packet[2] << 8) | packet[3];
+ if (seqn_after(seqn, a2dp_low_latency_seqn)) {
+ printf("clear_end: %d\n", seqn);
+ break;
+ }
+ a2dp_media_free_packet(packet);
+ /*printf("clear: %d\n", seqn);*/
+ }
+
+ if (drop_a2dp_timer) {
+ sys_timer_del(drop_a2dp_timer);
+ drop_a2dp_timer = 0;
+ }
+ int type = a2dp_media_get_codec_type();
+ if (type >= 0) {
+ /*a2dp_dec_open(type);*/
+ __a2dp_dec_open(type, 1, 0);
+ }
+
+ if (a2dp_low_latency == 0) {
+ tws_api_auto_role_switch_enable();
+ }
+
+ printf("a2dp_delay: %d\n", a2dp_media_get_remain_play_time(1));
+}
+
+
+int earphone_a2dp_codec_set_low_latency_mode(int enable, int msec)
+{
+ int ret = 0;
+ int len, err;
+
+ if (CONFIG_LOW_LATENCY_ENABLE == 0) {
+ return -EINVAL;
+ }
+
+ if (esco_dec) {
+ return -EINVAL;
+ }
+ if (drop_a2dp_timer) {
+ return -EINVAL;
+ }
+ if (a2dp_suspend) {
+ return -EINVAL;
+ }
+
+ a2dp_low_latency = enable;
+ a2dp_low_latency_seqn = 0;
+
+ r_printf("a2dp_low_latency: %d, %d, %d\n", a2dp_dec->seqn, a2dp_delay_time, enable);
+
+ if (!a2dp_dec || a2dp_dec->start == 0) {
+#if TCFG_USER_TWS_ENABLE
+ tws_api_low_latency_enable(enable);
+#endif
+ return 0;
+ }
+
+ if (a2dp_dec->coding_type == AUDIO_CODING_SBC) {
+ a2dp_low_latency_seqn = a2dp_dec->seqn + (msec + a2dp_delay_time) / 15;
+ } else {
+ a2dp_low_latency_seqn = a2dp_dec->seqn + (msec + a2dp_delay_time) / 20;
+ }
+
+#if TCFG_USER_TWS_ENABLE
+ u8 data[2];
+ data[0] = a2dp_low_latency_seqn >> 8;
+ data[1] = a2dp_low_latency_seqn;
+ err = tws_api_send_data_to_slave(data, 2, 0x132A6578);
+ if (err == -ENOMEM) {
+ return -EINVAL;
+ }
+#endif
+
+ a2dp_dec_close();
+
+ a2dp_media_clear_packet_before_seqn(0);
+
+#if TCFG_USER_TWS_ENABLE
+ if (enable) {
+ tws_api_auto_role_switch_disable();
+ }
+ tws_api_low_latency_enable(enable);
+#endif
+
+ drop_a2dp_timer = sys_timer_add(NULL, low_latency_drop_a2dp_frame, 40);
+
+ /*r_printf("clear_to_seqn: %d\n", a2dp_low_latency_seqn);*/
+
+ return 0;
+}
+
+int earphone_a2dp_codec_get_low_latency_mode()
+{
+#if TCFG_USER_TWS_ENABLE
+ return tws_api_get_low_latency_state();
+#endif
+ return a2dp_low_latency;
+}
+
+
+int a2dp_tws_dec_suspend(void *p)
+{
+ r_printf("a2dp_tws_dec_suspend\n");
+ /*mem_stats();*/
+
+ if (a2dp_suspend) {
+ return -EINVAL;
+ }
+ a2dp_suspend = 1;
+
+ if (a2dp_dec) {
+ a2dp_dec_close();
+ a2dp_media_clear_packet_before_seqn(0);
+ if (tws_api_get_role() == 0) {
+ drop_a2dp_timer = sys_timer_add(NULL, (void (*)(void *))a2dp_media_clear_packet_before_seqn, 100);
+ }
+ }
+
+ int err = audio_decoder_fmt_lock(&decode_task, AUDIO_CODING_AAC);
+ if (err) {
+ log_e("AAC_dec_lock_faild\n");
+ }
+
+ return err;
+}
+
+
+void a2dp_tws_dec_resume(void)
+{
+ r_printf("a2dp_tws_dec_resume\n");
+
+ if (a2dp_suspend) {
+ a2dp_suspend = 0;
+
+ if (drop_a2dp_timer) {
+ sys_timer_del(drop_a2dp_timer);
+ drop_a2dp_timer = 0;
+ }
+
+ audio_decoder_fmt_unlock(&decode_task, AUDIO_CODING_AAC);
+
+ int type = a2dp_media_get_codec_type();
+ printf("codec_type: %d\n", type);
+ if (type >= 0) {
+ if (tws_api_get_role() == 0) {
+ a2dp_media_clear_packet_before_seqn(0);
+ }
+ a2dp_resume_time = jiffies + msecs_to_jiffies(80);
+ /*a2dp_dec_open(type);*/
+ __a2dp_dec_open(type, 1, 0);
+ }
+ }
+}
diff --git a/cpu/br28/adc_api.c b/cpu/br28/adc_api.c
new file mode 100644
index 0000000..2a25afe
--- /dev/null
+++ b/cpu/br28/adc_api.c
@@ -0,0 +1,680 @@
+#include "typedef.h"
+#include "asm/clock.h"
+#include "asm/adc_api.h"
+#include "timer.h"
+#include "init.h"
+#include "asm/efuse.h"
+#include "irq.h"
+#include "asm/power/p33.h"
+#include "asm/power/p11.h"
+#include "asm/power_interface.h"
+#include "jiffies.h"
+
+u32 adc_sample(u32 ch);
+static volatile u16 _adc_res;
+static volatile u16 cur_ch_value;
+static u8 cur_ch = 0;
+struct adc_info_t {
+ u32 ch;
+ u16 value;
+ u32 jiffies;
+ u32 sample_period;
+};
+
+#define ENABLE_OCCUPY_MODE 1
+
+static struct adc_info_t adc_queue[ADC_MAX_CH + ENABLE_OCCUPY_MODE];
+
+
+static u8 adc_sample_flag = 0;
+
+static u16 dtemp_voltage = 0;
+
+
+#define ADC_SRC_CLK clk_get("adc")
+
+/*config adc clk according to sys_clk*/
+static const u32 sys2adc_clk_info[] = {
+ 128000000L,
+ 96000000L,
+ 72000000L,
+ 48000000L,
+ 24000000L,
+ 12000000L,
+ 6000000L,
+ 1000000L,
+};
+
+u32 adc_add_sample_ch(u32 ch)
+{
+ u32 i = 0;
+ for (i = 0; i < ADC_MAX_CH; i++) {
+ /* printf("%s() %d %x %x\n", __func__, i, ch, adc_queue[i].ch); */
+ if (adc_queue[i].ch == ch) {
+ break;
+ } else if (adc_queue[i].ch == -1) {
+ adc_queue[i].ch = ch;
+ adc_queue[i].value = 1;
+ adc_queue[i].jiffies = 0;
+ adc_queue[i].sample_period = msecs_to_jiffies(0);
+ printf("add sample ch %x\n", ch);
+ break;
+ }
+ }
+ return i;
+}
+
+u32 adc_set_sample_freq(u32 ch, u32 ms)
+{
+ u32 i;
+ for (i = 0; i < ADC_MAX_CH; i++) {
+ if (adc_queue[i].ch == ch) {
+ adc_queue[i].sample_period = msecs_to_jiffies(ms);
+ adc_queue[i].jiffies = msecs_to_jiffies(ms) + jiffies;
+ break;
+ }
+ }
+ return i;
+}
+
+u32 adc_remove_sample_ch(u32 ch)
+{
+ u32 i = 0;
+ for (i = 0; i < ADC_MAX_CH; i++) {
+ if (adc_queue[i].ch == ch) {
+ adc_queue[i].ch = -1;
+ break;
+ }
+ }
+ return i;
+}
+static u32 adc_get_next_ch(u32 cur_ch)
+{
+ for (int i = cur_ch + 1; i < ADC_MAX_CH; i++) {
+ if (adc_queue[i].ch != -1) {
+ return i;
+ }
+ }
+ return 0;
+}
+
+
+
+#define PMU_CH_SAMPLE_FREQ 500 //ms
+
+#define PMU_CH_VALUE_ARRAY_SIZE (16 + 1)
+
+static u16 vbat_value_array[PMU_CH_VALUE_ARRAY_SIZE];
+static u16 vbg_value_array[PMU_CH_VALUE_ARRAY_SIZE];
+
+static void adc_value_push(u16 *array, u16 adc_value)
+{
+ u16 pos = array[0];
+ pos++;
+ if (pos >= PMU_CH_VALUE_ARRAY_SIZE) {
+ pos = 1;
+ }
+ array[pos] = adc_value;
+ array[0] = pos;
+}
+
+static u16 adc_value_avg(u16 *array)
+{
+ u32 i, j, sum = 0;
+ for (i = 1, j = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i++) {
+ if (array[i]) {
+ sum += array[i];
+ j += 1;
+ }
+ }
+ if (sum) {
+ return (sum / j);
+ }
+ return 1;
+}
+
+static void adc_value_array_reset(u16 *array)
+{
+ for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i++) {
+ array[i] = 0;
+ }
+}
+
+u32 adc_get_value(u32 ch)
+{
+ if (ch == AD_CH_VBAT) {
+ return adc_value_avg(vbat_value_array);
+ } else if (ch == AD_CH_LDOREF) {
+ return adc_value_avg(vbg_value_array);
+ }
+
+ for (int i = 0; i < ADC_MAX_CH; i++) {
+ if (adc_queue[i].ch == ch) {
+ return adc_queue[i].value;
+ }
+ }
+ return 1;
+}
+#define VBG_CENTER 801
+#define VBG_RES 3
+u32 adc_value_to_voltage(u32 adc_vbg, u32 adc_ch_val)
+{
+ u32 adc_res = adc_ch_val;
+ u32 adc_trim = get_vbg_trim();
+ u32 tmp, tmp1;
+
+ tmp1 = adc_trim & 0x0f;
+ tmp = (adc_trim & BIT(4)) ? VBG_CENTER - tmp1 * VBG_RES : VBG_CENTER + tmp1 * VBG_RES;
+ /* printf("adc_res %d mv vbg:%d adc:%d adc_trim:%x\n", adc_res, adc_vbg, adc_ch_val, adc_trim); */
+
+ if (adc_vbg == 0) {
+ adc_vbg = 1; //防止div0异常
+ }
+ adc_res = adc_res * tmp / adc_vbg;
+ return adc_res;
+}
+
+u32 adc_get_voltage(u32 ch)
+{
+#ifdef CONFIG_FPGA_ENABLE
+ return 1000;
+#endif
+
+ if (ch == AD_CH_DTEMP) {
+ return dtemp_voltage;
+ }
+
+ u32 adc_vbg = adc_get_value(AD_CH_LDOREF);
+ u32 adc_res = adc_get_value(ch);
+ return adc_value_to_voltage(adc_vbg, adc_res);
+}
+u32 adc_check_vbat_lowpower()
+{
+ return 0;
+}
+void adc_audio_ch_select(u32 ch)
+{
+ SFR(JL_ADDA->ADDA_CON1, 1, 1, 1);
+ SFR(JL_ADDA->ADDA_CON0, 0, 12, 0);
+
+ switch (ch << 16) {
+ case AD_AUDIO_VADADC:
+ SFR(JL_ADDA->ADDA_CON0, 12, 1, 1);
+ break;
+ case AD_AUDIO_VCM:
+ SFR(JL_ADDA->ADDA_CON0, 11, 1, 1);
+ break;
+ case AD_AUDIO_VBGLDO:
+ SFR(JL_ADDA->ADDA_CON0, 10, 1, 1);
+ break;
+ case AD_AUDIO_HPVDD:
+ SFR(JL_ADDA->ADDA_CON0, 9, 1, 1);
+ break;
+ case AD_AUDIO_RN:
+ SFR(JL_ADDA->ADDA_CON0, 4, 1, 1);
+ break;
+ case AD_AUDIO_RP:
+ SFR(JL_ADDA->ADDA_CON0, 3, 1, 1);
+ break;
+ case AD_AUDIO_LN:
+ SFR(JL_ADDA->ADDA_CON0, 2, 1, 1);
+ break;
+ case AD_AUDIO_LP:
+ SFR(JL_ADDA->ADDA_CON0, 1, 1, 1);
+ break;
+ case AD_AUDIO_DACVDD:
+ SFR(JL_ADDA->ADDA_CON0, 0, 1, 1);
+ break;
+ default:
+ break;
+ }
+}
+
+void adc_close()
+{
+ JL_ADC->CON = 0;
+ JL_ADC->CON = 0;
+}
+void adc_suspend()
+{
+ JL_ADC->CON &= ~BIT(4);
+}
+void adc_resume()
+{
+ JL_ADC->CON |= BIT(4);
+}
+
+void adc_enter_occupy_mode(u32 ch)
+{
+ if (JL_ADC->CON & BIT(4)) {
+ return;
+ }
+ adc_queue[ADC_MAX_CH].ch = ch;
+ cur_ch_value = adc_sample(ch);
+}
+void adc_exit_occupy_mode()
+{
+ adc_queue[ADC_MAX_CH].ch = -1;
+}
+u32 adc_occupy_run()
+{
+ if (adc_queue[ADC_MAX_CH].ch != -1) {
+ while (1) {
+ asm volatile("idle");//wait isr
+ if (_adc_res != (u16) - 1) {
+ break;
+ }
+ }
+ if (_adc_res == 0) {
+ _adc_res ++;
+ }
+ adc_queue[ADC_MAX_CH].value = _adc_res;
+ _adc_res = cur_ch_value;
+ return adc_queue[ADC_MAX_CH].value;
+ }
+ return 0;
+}
+u32 adc_get_occupy_value()
+{
+ if (adc_queue[ADC_MAX_CH].ch != -1) {
+ return adc_queue[ADC_MAX_CH].value;
+ }
+ return 0;
+}
+u32 get_adc_div(u32 src_clk)
+{
+ u32 adc_clk;
+ u32 adc_clk_idx;
+ u32 cnt;
+ adc_clk = src_clk;
+ cnt = ARRAY_SIZE(sys2adc_clk_info);
+ for (adc_clk_idx = 0; adc_clk_idx < cnt; adc_clk_idx ++) {
+ if (adc_clk > sys2adc_clk_info[adc_clk_idx]) {
+ break;
+ }
+ }
+
+ if (adc_clk_idx < cnt) {
+ adc_clk_idx = cnt - adc_clk_idx;
+ } else {
+ adc_clk_idx = cnt - 1;
+ }
+ return adc_clk_idx;
+}
+
+___interrupt
+static void adc_isr()
+{
+ _adc_res = JL_ADC->RES;
+
+ local_irq_disable();
+ JL_ADC->CON = BIT(6);
+ local_irq_enable();
+
+#if 1
+ if (adc_sample_flag > 1) {
+ extern void adc_scan(void *priv);
+ adc_scan((void *)&adc_sample_flag);
+ }
+#endif
+}
+
+u32 adc_sample(u32 ch)
+{
+ const u32 tmp_adc_res = _adc_res;
+ _adc_res = (u16) - 1;
+
+ u32 adc_con = 0;
+ SFR(adc_con, 0, 3, 0b110);//div 96
+
+
+ adc_con |= (0xf << 12); //启动延时控制,实际启动延时为此数值*8个ADC时钟
+ adc_con |= BIT(3); //ana en
+ adc_con |= BIT(6); //clr pend
+ adc_con |= BIT(5);//ie
+ adc_con |= BIT(17);//clk en
+ /* adc_con |= BIT(18)|BIT(19);//clk en */
+
+ SFR(adc_con, 21, 3, 0b010);
+ switch (ch & 0xff) {
+ case AD_CH_BT:
+ SFR(adc_con, 18, 3, AD_CH_BT & 0xf);
+ break;
+ case AD_CH_PMU:
+ if (adc_sample_flag > 1) {
+ SFR(adc_con, 0, 3, 0b011);//div 24
+ adc_con &= ~(0xf << 12);
+ }
+ SFR(adc_con, 18, 3, AD_CH_PMU & 0xf);
+ adc_pmu_ch_select(ch >> 16);
+ break;
+
+ case AD_CH_AUDIO:
+ SFR(adc_con, 18, 3, AD_CH_AUDIO & 0xf);
+ adc_audio_ch_select(ch >> 16);
+ break;
+
+ case AD_CH_LPCTM:
+ SFR(adc_con, 18, 3, AD_CH_LPCTM & 0xf);
+ break;
+
+ case AD_CH_X32K:
+ SFR(adc_con, 18, 3, AD_CH_X32K & 0xf);
+ break;
+ case AD_CH_PLL1:
+ SFR(adc_con, 18, 3, AD_CH_PLL1 & 0xf);
+ break;
+ default:
+ SFR(adc_con, 21, 3, 0b001);
+ SFR(adc_con, 8, 4, ch & 0xf);
+ break;
+ }
+
+ JL_ADC->CON = adc_con;
+ JL_ADC->CON |= BIT(4);//en
+
+ /* printf("ch %x %x %x %x",ch,ch >> 16,JL_ADC->CON,P3_ANA_CON4); */
+
+ JL_ADC->CON |= BIT(6);//kistart
+
+ return tmp_adc_res;
+}
+
+void adc_scan(void *priv)
+{
+ static u16 vbg_adc_res = 0;
+ static u16 dtemp_adc_res = 0;
+
+ if ((priv == NULL) && (adc_sample_flag > 1)) {
+ return;
+ }
+
+ if (adc_queue[ADC_MAX_CH].ch != -1) { //occupy mode
+ return;
+ }
+
+ if (JL_ADC->CON & BIT(4)) {
+ adc_sample_flag = 0;
+ return ;
+ }
+
+ if (_adc_res == 0xffff) {
+ adc_sample_flag = 0;
+ }
+
+ if (adc_sample_flag) {
+ if (adc_sample_flag == 2) {
+ dtemp_adc_res = _adc_res;
+ adc_sample_flag = 3;
+ adc_sample(AD_CH_LDOREF);
+ return;
+ } else if (adc_sample_flag == 3) {
+ vbg_adc_res = _adc_res;
+ dtemp_voltage = adc_value_to_voltage(vbg_adc_res, dtemp_adc_res);
+ /* printf("vbg:%d dtemp:%d vol:%dmv\n", vbg_adc_res, dtemp_adc_res, dtemp_voltage); */
+ } else {
+ adc_queue[cur_ch].value = _adc_res;
+ if (adc_queue[cur_ch].ch == AD_CH_VBAT) {
+ adc_value_push(vbat_value_array, _adc_res);
+ /* printf("vbat %d",_adc_res); */
+ } else if (adc_queue[cur_ch].ch == AD_CH_LDOREF) {
+ adc_value_push(vbg_value_array, _adc_res);
+ /* printf("vbg %d",_adc_res); */
+ }
+ }
+ adc_sample_flag = 0;
+ }
+
+ u8 next_ch = adc_get_next_ch(cur_ch);
+
+ if (adc_queue[next_ch].sample_period) {
+ if (time_before(adc_queue[next_ch].jiffies, jiffies)) {
+ if (adc_queue[next_ch].ch == AD_CH_DTEMP) {
+ adc_sample_flag = 2;
+ } else {
+ adc_sample_flag = 1;
+ }
+ adc_sample(adc_queue[next_ch].ch);
+ adc_queue[next_ch].jiffies += adc_queue[next_ch].sample_period;
+ }
+ } else {
+ adc_sample(adc_queue[next_ch].ch);
+ adc_sample_flag = 1;
+ }
+
+ cur_ch = next_ch;
+}
+
+static u16 adc_wait_pnd()
+{
+ while (!(JL_ADC->CON & BIT(7)));
+ u32 adc_res = JL_ADC->RES;
+ /* printf("adc_res =%d\n",adc_res); */
+ asm("nop");
+ JL_ADC->CON |= BIT(6);
+ return adc_res;
+}
+
+static int hpvdd_voltage = 0;
+static void read_hpvdd_voltage(void)
+{
+ int hpvdd_adc_value = 0;
+ int tvalue = 0;
+ adc_sample(AD_CH_AUDIO_HPVDD);
+ for (int i = 0; i < 10; i++) {
+ tvalue = adc_wait_pnd();
+ hpvdd_adc_value += tvalue;
+ }
+ hpvdd_adc_value /= 10;
+
+ u32 adc_vbg = adc_get_value(AD_CH_LDOREF);
+ hpvdd_voltage = adc_value_to_voltage(adc_vbg, hpvdd_adc_value);
+ printf("hpvdd = %d mV\n", hpvdd_voltage);
+ SFR(JL_ADDA->ADDA_CON0, 9, 1, 0);
+}
+
+int get_hpvdd_voltage(void)
+{
+ return hpvdd_voltage;
+}
+
+void adc_reset(void)
+{
+ int i, j;
+ local_irq_disable();
+ JL_ADC->CON = 0;
+
+ memset(vbg_value_array, 0x0, sizeof(vbg_value_array));
+ memset(vbat_value_array, 0x0, sizeof(vbat_value_array));
+
+ u32 sum_ad = 0;
+ adc_sample(AD_CH_LDOREF);
+ for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
+ sum_ad += adc_wait_pnd();
+ }
+ sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
+ adc_value_push(vbg_value_array, sum_ad);
+ printf("vbg_adc_value = %d\n", adc_value_avg(vbg_value_array));
+
+ sum_ad = 0;
+ adc_sample(AD_CH_VBAT);
+ for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
+ sum_ad += adc_wait_pnd();
+ }
+ sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
+ adc_value_push(vbat_value_array, sum_ad);
+ printf("vbat_adc_value = %d\n", adc_value_avg(vbat_value_array));
+ printf("vbat = %d mv\n", adc_get_voltage(AD_CH_VBAT) * 4);
+
+ JL_ADC->CON = BIT(6);
+ cur_ch = 0;
+ adc_sample_flag = 0;
+ local_irq_enable();
+}
+
+void _adc_init(u32 sys_lvd_en)
+{
+ memset(adc_queue, 0xff, sizeof(adc_queue));
+ memset(vbg_value_array, 0x0, sizeof(vbg_value_array));
+ memset(vbat_value_array, 0x0, sizeof(vbat_value_array));
+
+ JL_ADC->CON = 0;
+ JL_ADC->CON = 0;
+
+ adc_add_sample_ch(AD_CH_LDOREF);
+ adc_set_sample_freq(AD_CH_LDOREF, PMU_CH_SAMPLE_FREQ);
+
+ adc_add_sample_ch(AD_CH_VBAT);
+ adc_set_sample_freq(AD_CH_VBAT, PMU_CH_SAMPLE_FREQ);
+
+ adc_add_sample_ch(AD_CH_DTEMP);
+ adc_set_sample_freq(AD_CH_DTEMP, PMU_CH_SAMPLE_FREQ);
+
+ u32 sum_ad = 0;
+ adc_sample(AD_CH_LDOREF);
+ for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
+ sum_ad += adc_wait_pnd();
+ }
+ sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
+ adc_value_push(vbg_value_array, sum_ad);
+ printf("vbg_adc_value = %d\n", adc_value_avg(vbg_value_array));
+
+ sum_ad = 0;
+ adc_sample(AD_CH_VBAT);
+ for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
+ sum_ad += adc_wait_pnd();
+ }
+ sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
+ adc_value_push(vbat_value_array, sum_ad);
+ printf("vbat_adc_value = %d\n", adc_value_avg(vbat_value_array));
+ printf("vbat = %d mv\n", adc_get_voltage(AD_CH_VBAT) * 4);
+
+ sum_ad = 0;
+ adc_sample(AD_CH_DTEMP);
+ for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
+ sum_ad += adc_wait_pnd();
+ }
+ sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
+ dtemp_voltage = adc_value_to_voltage(adc_value_avg(vbg_value_array), sum_ad);
+ printf("dtemp_adc_value = %d\n", sum_ad);
+ printf("dtemp = %d mv\n", dtemp_voltage);
+
+ read_hpvdd_voltage();
+
+ request_irq(IRQ_GPADC_IDX, 0, adc_isr, 0);
+
+ usr_timer_add(NULL, adc_scan, 5, 0); //2ms
+
+ /* void btosc_fast_boot_test(void); */
+ /* btosc_fast_boot_test(); */
+ /* sys_timer_add(NULL, adc_scan, 10); //2ms */
+
+ /* void adc_test(); */
+ /* usr_timer_add(NULL, adc_test, 1000, 0); //2ms */
+
+ /* extern void wdt_close(); */
+ /* wdt_close(); */
+ /* */
+ /* while(1); */
+}
+u32 get_vdd_voltage(u32 ch)
+{
+ u32 vbg_value = 0;
+ u32 wvdd_value = 0;
+
+ adc_sample(AD_CH_LDOREF);
+ for (int i = 0; i < 10; i++) {
+ vbg_value += adc_wait_pnd();
+ }
+
+ adc_sample(ch);
+ for (int i = 0; i < 10; i++) {
+ wvdd_value += adc_wait_pnd();
+ }
+
+ u32 adc_vbg = vbg_value / 10;
+ u32 adc_res = wvdd_value / 10;
+
+ return adc_value_to_voltage(adc_vbg, adc_res);
+}
+
+
+#define ADC_SCAN_NUM 16
+__attribute__((noinline))
+AT(.volatile_ram_code)
+u32 get_vddio_voltage()
+{
+
+ u32 vbg_value = 0;
+ u32 vddio_value = 0;
+ u32 min = -1;
+ u32 max = 0;
+ adc_pmu_detect_en(0);
+ adc_sample(AD_CH_LDOREF);
+ for (int i = 0; i < ADC_SCAN_NUM; i++) {
+ while (!(JL_ADC->CON & BIT(7))) { //wait pending
+ }
+
+ u32 adc_res = JL_ADC->RES;
+ vbg_value += adc_res;
+ JL_ADC->CON |= BIT(6);
+ if (max < adc_res) {
+ max = adc_res;
+ }
+ if (min > adc_res) {
+ min = adc_res;
+ }
+ }
+
+
+ u32 adc_vbg = (vbg_value - max - min) / (ADC_SCAN_NUM - 2);
+
+ u32 adc_trim = get_vbg_trim();
+
+ u32 vbg_voltage, tmp1;
+
+ tmp1 = adc_trim & 0x0f;
+ vbg_voltage = (adc_trim & BIT(4)) ? VBG_CENTER - tmp1 * VBG_RES : VBG_CENTER + tmp1 * VBG_RES;
+ u32 vddio_voltage = vbg_voltage * 1023 / adc_vbg;
+ return vddio_voltage;
+}
+
+void adc_init()
+{
+ adc_pmu_detect_en(1);
+
+ volatage_trim_init();
+
+ _adc_init(1);
+}
+//late_initcall(adc_init);
+
+void adc_test()
+{
+ /* void efuse_test(); */
+ /* efuse_test(); */
+ /* printf("\n\n%s() chip_id :%x\n", __func__, get_chip_id()); */
+ /* printf("%s() vbg trim:%x\n", __func__, get_vbg_trim()); */
+ /* printf("%s() vbat trim:%x\n", __func__, get_vbat_trim()); */
+
+ /* printf("\n\nWLA_CON0 %x\n", JL_ANA->WLA_CON0); */
+ /* printf("WLA_CON9 %x\n", JL_ANA->WLA_CON9); */
+ /* printf("WLA_CON10 %x\n", JL_ANA->WLA_CON10); */
+ /* printf("WLA_CON21 %x\n", JL_ANA->WLA_CON21); */
+
+ /* printf("ADA_CON %x\n", JL_ANA->ADA_CON3); */
+ /* printf("PLL_CON1 %x\n", JL_CLOCK->PLL_CON1); */
+
+ printf("\n%s() VBAT:%d %d mv\n\n", __func__,
+ adc_get_value(AD_CH_VBAT), adc_get_voltage(AD_CH_VBAT) * 4);
+
+ /* printf("\n%s() pa3:%d %d mv\n\n", __func__, */
+ /* adc_get_value(AD_CH_PA3), adc_get_voltage(AD_CH_PA3)); */
+
+
+}
+void adc_vbg_init()
+{
+ return ;
+}
+//__initcall(adc_vbg_init);
diff --git a/cpu/br28/app_audio.c b/cpu/br28/app_audio.c
new file mode 100644
index 0000000..7a4fb61
--- /dev/null
+++ b/cpu/br28/app_audio.c
@@ -0,0 +1,1069 @@
+#include "system/includes.h"
+#include "media/includes.h"
+#include "app_config.h"
+#include "app_action.h"
+#include "app_main.h"
+#include "user_cfg.h"
+#include "audio_config.h"
+#include "audio_dvol.h"
+//#include "audio_anc.h"
+#include "audio_output_dac.h"
+#include "asm/math_fast_function.h"
+
+#define LOG_TAG "[APP_AUDIO]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#define DEFAULT_DIGTAL_VOLUME 16384
+
+typedef short unaligned_u16 __attribute__((aligned(1)));
+struct app_audio_config {
+ u8 state;
+ u8 prev_state;
+ u8 mute_when_vol_zero;
+ volatile u8 fade_gain_l;
+ volatile u8 fade_gain_r;
+ volatile s16 fade_dgain_l;
+ volatile s16 fade_dgain_r;
+ volatile s16 fade_dgain_step_l;
+ volatile s16 fade_dgain_step_r;
+ volatile int fade_timer;
+ s16 digital_volume;
+ u8 analog_volume_l;
+ u8 analog_volume_r;
+ atomic_t ref;
+ s16 max_volume[APP_AUDIO_STATE_WTONE + 1];
+ u8 sys_cvol_max;
+ u8 call_cvol_max;
+ u16 sys_hw_dvol_max; //系统最大硬件数字音量(非通话模式)
+ u16 call_hw_dvol_max; //通话模式最大硬件数字音量
+ unaligned_u16 *sys_cvol;
+ unaligned_u16 *call_cvol;
+};
+static const char *audio_state[] = {
+ "idle",
+ "music",
+ "call",
+ "tone",
+ "err",
+};
+
+static struct app_audio_config app_audio_cfg = {0};
+
+#define __this (&app_audio_cfg)
+extern struct audio_dac_hdl dac_hdl;
+extern struct dac_platform_data dac_data;
+
+/*
+ *************************************************************
+ *
+ * audio volume fade
+ *
+ *************************************************************
+ */
+
+static void audio_fade_timer(void *priv)
+{
+ u8 gain_l = dac_hdl.vol_l;
+ u8 gain_r = dac_hdl.vol_r;
+ //printf("", gain_l, gain_r, __this->fade_gain_l, __this->fade_gain_r);
+ local_irq_disable();
+ if ((gain_l == __this->fade_gain_l) && (gain_r == __this->fade_gain_r)) {
+ usr_timer_del(__this->fade_timer);
+ __this->fade_timer = 0;
+ /*音量为0的时候mute住*/
+ audio_dac_set_L_digital_vol(&dac_hdl, gain_l ? __this->digital_volume : 0);
+ audio_dac_set_R_digital_vol(&dac_hdl, gain_r ? __this->digital_volume : 0);
+ if ((gain_l == 0) && (gain_r == 0)) {
+ if (__this->mute_when_vol_zero) {
+ __this->mute_when_vol_zero = 0;
+ audio_dac_mute(&dac_hdl, 1);
+ }
+ }
+ local_irq_enable();
+ /*
+ *淡入淡出结束,也把当前的模拟音量设置一下,防止因为淡入淡出的音量和保存音量的变量一致,
+ *而寄存器已经被清0的情况
+ */
+ audio_dac_set_analog_vol(&dac_hdl, gain_l);
+ /* log_info("dac_fade_end, VOL : 0x%x 0x%x\n", JL_ADDA->DAA_CON1, JL_AUDIO->DAC_VL0); */
+ return;
+ }
+ if (gain_l > __this->fade_gain_l) {
+ gain_l--;
+ } else if (gain_l < __this->fade_gain_l) {
+ gain_l++;
+ }
+
+ if (gain_r > __this->fade_gain_r) {
+ gain_r--;
+ } else if (gain_r < __this->fade_gain_r) {
+ gain_r++;
+ }
+ audio_dac_set_analog_vol(&dac_hdl, gain_l);
+ local_irq_enable();
+}
+
+static int audio_fade_timer_add(u8 gain_l, u8 gain_r)
+{
+ /* r_printf("dac_fade_begin:0x%x,gain_l:%d,gain_r:%d\n", __this->fade_timer, gain_l, gain_r); */
+ local_irq_disable();
+ __this->fade_gain_l = gain_l;
+ __this->fade_gain_r = gain_r;
+ if (__this->fade_timer == 0) {
+ __this->fade_timer = usr_timer_add((void *)0, audio_fade_timer, 2, 1);
+ /* y_printf("fade_timer:0x%x", __this->fade_timer); */
+ }
+ local_irq_enable();
+
+ return 0;
+}
+
+
+#if (SYS_VOL_TYPE == VOL_TYPE_AD)
+
+#define DGAIN_SET_MAX_STEP (300)
+#define DGAIN_SET_MIN_STEP (30)
+
+static unsigned short combined_vol_list[17][2] = {
+ { 0, 0}, //0: None
+ { 0, 412}, // 1:-50.00 db
+ { 0, 604}, // 2:-46.67 db
+ { 0, 887}, // 3:-43.33 db
+ { 0, 1301}, // 4:-40.00 db
+ { 0, 1910}, // 5:-36.67 db
+ { 0, 2804}, // 6:-33.33 db
+ { 0, 4115}, // 7:-30.00 db
+ { 0, 6041}, // 8:-26.67 db
+ { 0, 8867}, // 9:-23.33 db
+ { 0, 13014}, // 10:-20.00 db
+ { 1, 9574}, // 11:-16.67 db
+ { 1, 14052}, // 12:-13.33 db
+ { 2, 10338}, // 13:-10.00 db
+ { 2, 15174}, // 14:-6.67 db
+ { 3, 11162}, // 15:-3.33 db
+ { 3, 16384}, // 16:0.00 db
+};
+static unsigned short call_combined_vol_list[16][2] = {
+ { 0, 0}, //0: None
+ { 0, 412}, // 1:-50.00 db
+ { 0, 604}, // 2:-46.67 db
+ { 0, 887}, // 3:-43.33 db
+ { 0, 1301}, // 4:-40.00 db
+ { 0, 1910}, // 5:-36.67 db
+ { 0, 2804}, // 6:-33.33 db
+ { 0, 4115}, // 7:-30.00 db
+ { 0, 6041}, // 8:-26.67 db
+ { 0, 8867}, // 9:-23.33 db
+ { 0, 13014}, // 10:-20.00 db
+ { 1, 9574}, // 11:-16.67 db
+ { 1, 14052}, // 12:-13.33 db
+ { 2, 10338}, // 13:-10.00 db
+ { 2, 15174}, // 14:-6.67 db
+ { 3, 11162}, // 15:-3.33 db
+};
+
+void audio_combined_vol_init(u8 cfg_en)
+{
+ u16 sys_cvol_len = 0;
+ u16 call_cvol_len = 0;
+ u8 *sys_cvol = NULL;
+ u8 *call_cvol = NULL;
+ unaligned_u16 *cvol;
+
+ __this->sys_cvol_max = ARRAY_SIZE(combined_vol_list) - 1;
+ __this->sys_cvol = combined_vol_list;
+ __this->call_cvol_max = ARRAY_SIZE(call_combined_vol_list) - 1;
+ __this->call_cvol = call_combined_vol_list;
+
+ if (cfg_en) {
+ sys_cvol = syscfg_ptr_read(CFG_COMBINE_SYS_VOL_ID, &sys_cvol_len);
+ //ASSERT(((u32)sys_cvol & BIT(0)) == 0, "sys_cvol addr unalignd(2):%x\n", sys_cvol);
+ if (sys_cvol && sys_cvol_len) {
+ __this->sys_cvol = sys_cvol;
+ __this->sys_cvol_max = sys_cvol_len / 4 - 1;
+ //y_printf("read sys_combine_vol succ:%x,len:%d",__this->sys_cvol,sys_cvol_len);
+ /* cvol = __this->sys_cvol;
+ for(int i = 0,j = 0;i < (sys_cvol_len / 2);j++) {
+ printf("sys_vol %d: %d, %d\n",j,*cvol++,*cvol++);
+ i += 2;
+ } */
+ } else {
+ r_printf("read sys_cvol false:%x,%x\n", sys_cvol, sys_cvol_len);
+ }
+
+ call_cvol = syscfg_ptr_read(CFG_COMBINE_CALL_VOL_ID, &call_cvol_len);
+ //ASSERT(((u32)call_cvol & BIT(0)) == 0, "call_cvol addr unalignd(2):%d\n", call_cvol);
+ if (call_cvol && call_cvol_len) {
+ __this->call_cvol = (unaligned_u16 *)call_cvol;
+ __this->call_cvol_max = call_cvol_len / 4 - 1;
+ //y_printf("read call_combine_vol succ:%x,len:%d",__this->call_cvol,call_cvol_len);
+ /* cvol = __this->call_cvol;
+ for(int i = 0,j = 0;i < call_cvol_len / 2;j++) {
+ printf("call_vol %d: %d, %d\n",j,*cvol++,*cvol++);
+ i += 2;
+ } */
+ } else {
+ r_printf("read call_combine_vol false:%x,%x\n", call_cvol, call_cvol_len);
+ }
+ }
+
+ log_info("sys_cvol_max:%d,call_cvol_max:%d\n", __this->sys_cvol_max, __this->call_cvol_max);
+}
+
+static int audio_combined_fade_timer_add(u8 gain_l, u8 gain_r)
+{
+ u8 gain_max;
+ u8 target_again_l = 0;
+ u8 target_again_r = 0;
+ u16 target_dgain_l = 0;
+ u16 target_dgain_r = 0;
+
+ if (__this->state == APP_AUDIO_STATE_CALL) {
+ gain_max = __this->call_cvol_max;
+ gain_l = (gain_l > gain_max) ? gain_max : gain_l;
+ gain_r = (gain_r > gain_max) ? gain_max : gain_r;
+ target_again_l = *(&__this->call_cvol[gain_l * 2]);
+ target_again_r = *(&__this->call_cvol[gain_r * 2]);
+ target_dgain_l = *(&__this->call_cvol[gain_l * 2 + 1]);
+ target_dgain_r = *(&__this->call_cvol[gain_r * 2 + 1]);
+ } else {
+ gain_max = __this->sys_cvol_max;
+ gain_l = (gain_l > gain_max) ? gain_max : gain_l;
+ gain_r = (gain_r > gain_max) ? gain_max : gain_r;
+ target_again_l = *(&__this->sys_cvol[gain_l * 2]);
+ target_again_r = *(&__this->sys_cvol[gain_r * 2]);
+ target_dgain_l = *(&__this->sys_cvol[gain_l * 2 + 1]);
+ target_dgain_r = *(&__this->sys_cvol[gain_r * 2 + 1]);
+ }
+#if 0//TCFG_AUDIO_ANC_ENABLE
+ target_again_l = anc_dac_gain_get(ANC_DAC_CH_L);
+ target_again_r = anc_dac_gain_get(ANC_DAC_CH_R);
+#endif
+
+ printf("[l]v:%d,Av:%d,Dv:%d", gain_l, target_again_l, target_dgain_l);
+ //y_printf("[r]v:%d,Av:%d,Dv:%d", gain_r, target_again_r, target_dgain_r);
+ /* log_info("dac_com_fade_begin:0x%x\n", __this->fade_timer); */
+
+ local_irq_disable();
+
+ __this->fade_gain_l = target_again_l;
+ __this->fade_gain_r = target_again_r;
+ __this->fade_dgain_l = target_dgain_l;
+ __this->fade_dgain_r = target_dgain_r;
+
+ if (__this->fade_timer == 0) {
+ /* __this->fade_timer = usr_timer_add((void *)0, audio_combined_fade_timer, 2, 1); */
+ /* log_info("combined_fade_timer:0x%x", __this->fade_timer); */
+ }
+
+ audio_dac_vol_set(TYPE_DAC_AGAIN, 0x3, __this->fade_gain_l, 1);
+ audio_dac_vol_set(TYPE_DAC_DGAIN, 0x3, __this->fade_dgain_l, 1);
+
+ local_irq_enable();
+
+ return 0;
+}
+
+#endif/*SYS_VOL_TYPE == VOL_TYPE_AD*/
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL_HW)
+#define DVOL_HW_LEVEL_MAX 31 /*注意:总共是(DVOL_HW_LEVEL_MAX + 1)级*/
+u16 hw_dig_vol_table[DVOL_HW_LEVEL_MAX + 1] = {
+ 0 , //0
+ 93 , //1
+ 111 , //2
+ 132 , //3
+ 158 , //4
+ 189 , //5
+ 226 , //6
+ 270 , //7
+ 323 , //8
+ 386 , //9
+ 462 , //10
+ 552 , //11
+ 660 , //12
+ 789 , //13
+ 943 , //14
+ 1127, //15
+ 1347, //16
+ 1610, //17
+ 1925, //18
+ 2301, //19
+ 2751, //20
+ 3288, //21
+ 3930, //22
+ 4698, //23
+ 5616, //24
+ 6713, //25
+ 8025, //26
+ 9592, //27
+ 10222,//28
+ 14200,//29
+ 16000,//30
+ 16384 //31
+};
+
+//float dB_Convert_Mag(float x)
+/* #define DIG_VOL_MAX_VALUE (0.0f) // 数字音量最大值(单位:dB) */
+/* #define DIG_VOL_STEP (1.5f) // 逐级递减差值(单位:dB) */
+void audio_hw_digital_vol_init(u8 cfg_en)
+{
+ float dB_value = DIG_VOL_MAX_VALUE;
+#if (TCFG_AUDIO_ANC_ENABLE)
+ dB_value = (dB_value > ANC_MODE_DIG_VOL_LIMIT) ? ANC_MODE_DIG_VOL_LIMIT : dB_value;
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+#if 0
+ int vol = get_max_sys_vol();
+ float temp = 0;
+ //printf("hw digital volume list:\n");
+ while (vol) {
+ temp = 16384.0f * dB_Convert_Mag(dB_value);
+ hw_dig_vol_table[vol] = (u16)temp;
+ //printf("[%d] dB:%.1f %.1f %d\n", vol, dB_value, temp, hw_dig_vol_table[vol]);
+ dB_value -= DIG_VOL_STEP;
+ vol--;
+ }
+ hw_dig_vol_table[0] = 0;
+#else
+ app_var.aec_dac_gain = (app_var.aec_dac_gain > BT_CALL_VOL_LEAVE_MAX) ? BT_CALL_VOL_LEAVE_MAX : app_var.aec_dac_gain;
+ __this->sys_hw_dvol_max = (u16)(16384.f * dB_Convert_Mag(dB_value));
+ float call_hw_dvol_max_dB = DIG_VOL_MAX_VALUE + (BT_CALL_VOL_LEAVE_MAX - app_var.aec_dac_gain) * BT_CALL_VOL_STEP;
+ printf("aec_dac_gain:%d,call_hw_dvol_max_dB:%.1f\n", app_var.aec_dac_gain, call_hw_dvol_max_dB);
+ __this->call_hw_dvol_max = (u16)(16384.f * dB_Convert_Mag(call_hw_dvol_max_dB));
+ printf("sys_hw_dvol_max:%d,call_hw_dvol_max:%d\n", __this->sys_hw_dvol_max, __this->call_hw_dvol_max);
+#endif
+}
+
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL_HW*/
+
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+
+#define DVOL_SW_LEVEL_MAX 31 /*注意:总共是(DVOL_SW_LEVEL_MAX + 1)级*/
+u16 sw_dig_vol_table[DVOL_SW_LEVEL_MAX + 1] = {0};
+
+void audio_sw_digital_vol_init(u8 cfg_en)
+{
+ printf("audio_sw_digital_vol_init,user-defined[%d]\n", SW_DIG_VOL_TAB_USER_DEFINED);
+ float dB_value = DIG_VOL_MAX_VALUE;
+#if (TCFG_AUDIO_ANC_ENABLE)
+ dB_value = (dB_value > ANC_MODE_DIG_VOL_LIMIT) ? ANC_MODE_DIG_VOL_LIMIT : dB_value;
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+
+#if SW_DIG_VOL_TAB_USER_DEFINED
+ int vol = get_max_sys_vol();
+ float temp = 0;
+ //printf("sw digital volume list:\n");
+ while (vol) {
+ temp = 16384.0f * dB_Convert_Mag(dB_value);
+ sw_dig_vol_table[vol] = (u16)temp;
+ //printf("[%d] dB:%.1f %.1f %d\n", vol, dB_value, temp, sw_dig_vol_table[vol]);
+ dB_value -= DIG_VOL_STEP;
+ vol--;
+ }
+ sw_dig_vol_table[0] = 0;
+ __this->sys_hw_dvol_max = DEFAULT_DIGITAL_VOLUME;
+ audio_digital_vol_init(sw_dig_vol_table, get_max_sys_vol());
+#else
+ __this->sys_hw_dvol_max = (u16)(16384.0f * dB_Convert_Mag(dB_value));
+ audio_digital_vol_init(NULL, 0);
+#endif/*SW_DIG_VOL_TAB_USER_DEFINED*/
+
+ app_var.aec_dac_gain = (app_var.aec_dac_gain > BT_CALL_VOL_LEAVE_MAX) ? BT_CALL_VOL_LEAVE_MAX : app_var.aec_dac_gain;
+ __this->call_hw_dvol_max = (u16)(__this->sys_hw_dvol_max * dB_Convert_Mag((BT_CALL_VOL_LEAVE_MAX - app_var.aec_dac_gain) * BT_CALL_VOL_STEP));
+ printf("sys_hw_dvol_max:%d,call_hw_dvol_max:%d\n", __this->sys_hw_dvol_max, __this->call_hw_dvol_max);
+}
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+void audio_volume_list_init(u8 cfg_en)
+{
+#if (SYS_VOL_TYPE == VOL_TYPE_AD)
+ audio_combined_vol_init(cfg_en);
+#elif (SYS_VOL_TYPE == VOL_TYPE_DIGITAL_HW)
+ audio_hw_digital_vol_init(cfg_en);
+#elif (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_sw_digital_vol_init(cfg_en);
+#endif/*SYS_VOL_TYPE*/
+}
+
+static void set_audio_device_volume(u8 type, s16 vol)
+{
+ audio_dac_set_analog_vol(&dac_hdl, vol);
+}
+
+static int get_audio_device_volume(u8 vol_type)
+{
+ return 0;
+}
+
+void volume_up_down_direct(s8 value)
+{
+
+}
+
+/*
+*********************************************************************
+* Audio Volume Fade
+* Description: 音量淡入淡出
+* Arguments : left_vol
+* right_vol
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+void audio_fade_in_fade_out(u8 left_vol, u8 right_vol)
+{
+ /*根据audio state切换的时候设置的最大音量,限制淡入淡出的最大音量*/
+ u8 max_vol_l = __this->max_volume[__this->state];
+ u8 max_vol_r = max_vol_l;
+ /*printf("[fade]state:%s,max_volume:%d,cur:%d,%d", audio_state[__this->state], max_vol_l, left_vol, left_vol);*/
+ /*淡入淡出音量限制*/
+ u8 left_gain = left_vol > max_vol_l ? max_vol_l : left_vol;
+ u8 right_gain = right_vol > max_vol_r ? max_vol_r : right_vol;
+
+ /*数字音量*/
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ u8 dvol_idx = 0; //记录音量通道供数字音量控制使用
+ s8 volume = right_gain;
+ switch (__this->state) {
+ case APP_AUDIO_STATE_IDLE:
+ case APP_AUDIO_STATE_MUSIC:
+ dvol_idx = MUSIC_DVOL;
+ break;
+ case APP_AUDIO_STATE_CALL:
+ dvol_idx = CALL_DVOL;
+ break;
+ case APP_AUDIO_STATE_WTONE:
+ dvol_idx = TONE_DVOL;
+ break;
+ default:
+ break;
+ }
+
+ if (volume > __this->max_volume[__this->state]) {
+ volume = __this->max_volume[__this->state];
+ }
+ /*printf("set_vol[%s]:=%d\n", audio_state[__this->state], volume);*/
+
+ /*按照配置限制通话时候spk最大音量*/
+ if (__this->state == APP_AUDIO_STATE_CALL) {
+ __this->digital_volume = __this->call_hw_dvol_max;
+ } else {
+ __this->digital_volume = __this->sys_hw_dvol_max;
+ }
+ /*printf("[SW_DVOL]Gain:%d,AVOL:%d,DVOL:%d\n", left_gain, __this->analog_volume_l, __this->digital_volume);*/
+ audio_dac_vol_set(TYPE_DAC_AGAIN, 0x3, __this->analog_volume_l, 1);
+ audio_dac_vol_set(TYPE_DAC_DGAIN, 0x3, __this->digital_volume, 1);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+ /*模拟数字联合音量*/
+#if (SYS_VOL_TYPE == VOL_TYPE_AD)
+#if TCFG_CALL_USE_DIGITAL_VOLUME
+ if (__this->state == APP_AUDIO_STATE_CALL) {
+ audio_fade_timer_add(left_gain, right_gain);
+ } else {
+ audio_combined_fade_timer_add(left_gain, right_gain);
+ }
+#else
+ audio_combined_fade_timer_add(left_gain, right_gain);
+#endif/*TCFG_CALL_USE_DIGITAL_VOLUME*/
+#endif/*SYS_VOL_TYPE == VOL_TYPE_AD*/
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL_HW)
+ /* u8 dvol_hw_level = 0; */
+ /* dvol_hw_level = left_gain * DVOL_HW_LEVEL_MAX / get_max_sys_vol(); */
+ /* __this->digital_volume = hw_dig_vol_table[dvol_hw_level]; */
+#if 0
+ __this->digital_volume = hw_dig_vol_table[left_gain];
+ /* audio_fade_timer_add(__this->analog_volume_l, __this->analog_volume_r); */
+#else
+ float dvol_db = 0;
+ if (left_gain) {
+ if (__this->state == APP_AUDIO_STATE_CALL) {
+ dvol_db = (BT_CALL_VOL_LEAVE_MAX - left_gain) * BT_CALL_VOL_STEP;
+ __this->digital_volume = (s16)(__this->call_hw_dvol_max * dB_Convert_Mag(dvol_db));
+ } else {
+ dvol_db = (BT_MUSIC_VOL_LEAVE_MAX - left_gain) * BT_MUSIC_VOL_STEP;
+ __this->digital_volume = (s16)(__this->sys_hw_dvol_max * dB_Convert_Mag(dvol_db));
+ }
+ } else {
+ __this->digital_volume = 0;
+ }
+#endif
+ printf("[HW_DVOL]Gain:%d,AVOL:%d,DVOL:%d\n", left_gain, __this->analog_volume_l, __this->digital_volume);
+ audio_dac_vol_set(TYPE_DAC_AGAIN, 0x3, __this->analog_volume_l, 1);
+ audio_dac_vol_set(TYPE_DAC_DGAIN, 0x3, __this->digital_volume, 1);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL_HW*/
+}
+
+/*
+*********************************************************************
+* Audio Volume Set
+* Description: 音量设置
+* Arguments : state 目标声音通道
+* volume 目标音量值
+* fade 是否淡入淡出
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+void app_audio_set_volume(u8 state, s8 volume, u8 fade)
+{
+ u8 dvol_idx = 0; //记录音量通道供数字音量控制使用
+ switch (state) {
+ case APP_AUDIO_STATE_IDLE:
+ case APP_AUDIO_STATE_MUSIC:
+ app_var.music_volume = volume;
+ dvol_idx = MUSIC_DVOL;
+ break;
+ case APP_AUDIO_STATE_CALL:
+ app_var.call_volume = volume;
+ dvol_idx = CALL_DVOL;
+#if TCFG_CALL_USE_DIGITAL_VOLUME
+ audio_digital_vol_set(volume);
+ return;
+#endif/*TCFG_CALL_USE_DIGITAL_VOLUME*/
+ break;
+ case APP_AUDIO_STATE_WTONE:
+ app_var.wtone_volume = volume;
+ dvol_idx = TONE_DVOL;
+ break;
+ default:
+ return;
+ }
+ printf("set_vol[%s]:%s=%d\n", audio_state[__this->state], audio_state[state], volume);
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ if (volume > __this->max_volume[state]) {
+ volume = __this->max_volume[state];
+ }
+ audio_digital_vol_set(dvol_idx, volume);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+ if (state == __this->state) {
+ audio_dac_set_volume(&dac_hdl, volume);
+ audio_fade_in_fade_out(volume, volume);
+ }
+}
+
+/*
+*********************************************************************
+* Audio Volume Get
+* Description: 音量获取
+* Arguments : state 要获取音量值的音量状态
+* Return : 返回指定状态对应得音量值
+* Note(s) : None.
+*********************************************************************
+*/
+s8 app_audio_get_volume(u8 state)
+{
+ s8 volume = 0;
+ switch (state) {
+ case APP_AUDIO_STATE_IDLE:
+ case APP_AUDIO_STATE_MUSIC:
+ volume = app_var.music_volume;
+ break;
+ case APP_AUDIO_STATE_CALL:
+ volume = app_var.call_volume;
+ break;
+ case APP_AUDIO_STATE_WTONE:
+ volume = app_var.wtone_volume;
+ if (!volume) {
+ volume = app_var.music_volume;
+ }
+ break;
+ case APP_AUDIO_CURRENT_STATE:
+ volume = app_audio_get_volume(__this->state);
+ break;
+ default:
+ break;
+ }
+
+ return volume;
+}
+
+
+/*
+*********************************************************************
+* Audio Mute
+* Description: 静音控制
+* Arguments : value Mute操作
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+static const char *audio_mute_string[] = {
+ "mute_default",
+ "unmute_default",
+ "mute_L",
+ "unmute_L",
+ "mute_R",
+ "unmute_R",
+};
+
+#define AUDIO_MUTE_FADE 1
+#define AUDIO_UMMUTE_FADE 1
+void app_audio_mute(u8 value)
+{
+ u8 volume = 0;
+ printf("audio_mute:%s", audio_mute_string[value]);
+ switch (value) {
+ case AUDIO_MUTE_DEFAULT:
+#if AUDIO_MUTE_FADE
+ audio_fade_in_fade_out(0, 0);
+ __this->mute_when_vol_zero = 1;
+#else
+ audio_dac_set_analog_vol(&dac_hdl, 0);
+ audio_dac_mute(&dac_hdl, 1);
+#endif/*AUDIO_MUTE_FADE*/
+ break;
+ case AUDIO_UNMUTE_DEFAULT:
+#if AUDIO_UMMUTE_FADE
+ audio_dac_mute(&dac_hdl, 0);
+ volume = app_audio_get_volume(APP_AUDIO_CURRENT_STATE);
+ audio_fade_in_fade_out(volume, volume);
+#else
+ audio_dac_mute(&dac_hdl, 0);
+ volume = app_audio_get_volume(APP_AUDIO_CURRENT_STATE);
+ audio_dac_set_analog_vol(&dac_hdl, volume);
+#endif/*AUDIO_UMMUTE_FADE*/
+ break;
+ }
+}
+
+/*
+*********************************************************************
+* Audio Volume Up
+* Description: 增加当前音量通道的音量
+* Arguments : value 要增加的音量值
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+void app_audio_volume_up(u8 value)
+{
+ s16 volume = 0;
+ switch (__this->state) {
+ case APP_AUDIO_STATE_IDLE:
+ case APP_AUDIO_STATE_MUSIC:
+ app_var.music_volume += value;
+ if (app_var.music_volume > get_max_sys_vol()) {
+ app_var.music_volume = get_max_sys_vol();
+ }
+ volume = app_var.music_volume;
+ break;
+ case APP_AUDIO_STATE_CALL:
+ app_var.call_volume += value;
+#if TCFG_CALL_USE_DIGITAL_VOLUME
+ audio_digital_vol_set(volume);
+ return;
+#endif
+ if (app_var.call_volume > app_var.aec_dac_gain) {
+ app_var.call_volume = app_var.aec_dac_gain;
+ }
+ volume = app_var.call_volume;
+
+ break;
+ case APP_AUDIO_STATE_WTONE:
+ app_var.wtone_volume += value;
+ if (app_var.wtone_volume > get_max_sys_vol()) {
+ app_var.wtone_volume = get_max_sys_vol();
+ }
+ volume = app_var.wtone_volume;
+ break;
+ default:
+ return;
+ }
+
+ app_audio_set_volume(__this->state, volume, 1);
+}
+
+
+void app_audio_volume_set(u8 value)
+{
+ s16 volume = 0;
+ switch (__this->state) {
+ case APP_AUDIO_STATE_IDLE:
+ case APP_AUDIO_STATE_MUSIC:
+ app_var.music_volume = value;
+ if (app_var.music_volume > get_max_sys_vol()) {
+ app_var.music_volume = get_max_sys_vol();
+ }
+ volume = app_var.music_volume;
+ break;
+ case APP_AUDIO_STATE_CALL:
+ app_var.call_volume = value;
+#if TCFG_CALL_USE_DIGITAL_VOLUME
+ audio_digital_vol_set(volume);
+ return;
+#endif
+ if (app_var.call_volume > app_var.aec_dac_gain) {
+ app_var.call_volume = app_var.aec_dac_gain;
+ }
+ volume = app_var.call_volume;
+
+ break;
+ case APP_AUDIO_STATE_WTONE:
+ app_var.wtone_volume = value;
+ if (app_var.wtone_volume > get_max_sys_vol()) {
+ app_var.wtone_volume = get_max_sys_vol();
+ }
+ volume = app_var.wtone_volume;
+ break;
+ default:
+ return;
+ }
+
+ app_audio_set_volume(__this->state, volume, 1);
+}
+
+
+/*
+*********************************************************************
+* Audio Volume Down
+* Description: 减少当前音量通道的音量
+* Arguments : value 要减少的音量值
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+void app_audio_volume_down(u8 value)
+{
+ s16 volume = 0;
+ switch (__this->state) {
+ case APP_AUDIO_STATE_IDLE:
+ case APP_AUDIO_STATE_MUSIC:
+ app_var.music_volume -= value;
+ if (app_var.music_volume < 0) {
+ app_var.music_volume = 0;
+ }
+ volume = app_var.music_volume;
+ break;
+ case APP_AUDIO_STATE_CALL:
+ app_var.call_volume -= value;
+ if (app_var.call_volume < 0) {
+ app_var.call_volume = 0;
+ }
+ volume = app_var.call_volume;
+#if TCFG_CALL_USE_DIGITAL_VOLUME
+ audio_digital_vol_set(volume);
+ return;
+#endif
+ break;
+ case APP_AUDIO_STATE_WTONE:
+ app_var.wtone_volume -= value;
+ if (app_var.wtone_volume < 0) {
+ app_var.wtone_volume = 0;
+ }
+ volume = app_var.wtone_volume;
+ break;
+ default:
+ return;
+ }
+
+ app_audio_set_volume(__this->state, volume, 1);
+}
+
+/*level:0~15*/
+static const u16 phone_call_dig_vol_tab[] = {
+ 0, //0
+ 111,//1
+ 161,//2
+ 234,//3
+ 338,//4
+ 490,//5
+ 708,//6
+ 1024,//7
+ 1481,//8
+ 2142,//9
+ 3098,//10
+ 4479,//11
+ 6477,//12
+ 9366,//13
+ 14955,//14
+ 16384 //15
+};
+
+/*
+*********************************************************************
+* Audio State Switch
+* Description: 切换声音状态
+* Arguments : state
+* max_volume
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+void app_audio_state_switch(u8 state, s16 max_volume)
+{
+ r_printf("audio state old:%s,new:%s,vol:%d\n", audio_state[__this->state], audio_state[state], max_volume);
+ printf(">>>>>>>>>>>>>> audio state old:%s,new:%s,vol:%d\n", audio_state[__this->state], audio_state[state], max_volume);
+
+ u8 analog_vol = MAX_ANA_VOL;
+#if TCFG_AUDIO_ANC_ENABLE
+ analog_vol = anc_dac_gain_get(ANC_DAC_CH_L); //获取ANC设置的DAC模拟增益
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+ __this->prev_state = __this->state;
+ __this->state = state;
+#if TCFG_CALL_USE_DIGITAL_VOLUME
+ if (__this->state == APP_AUDIO_STATE_CALL) {
+ audio_digital_vol_open(max_volume, max_volume, 4);
+ /*调数字音量的时候,模拟音量定最大*/
+ audio_dac_set_analog_vol(&dac_hdl, max_volume);
+ }
+#endif
+ /*限制最大音量*/
+ __this->max_volume[state] = max_volume;
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL_HW)
+ __this->analog_volume_l = analog_vol;
+ __this->analog_volume_r = analog_vol;
+#else
+ __this->digital_volume = DEFAULT_DIGITAL_VOLUME;
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL_HW*/
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ __this->analog_volume_l = MAX_ANA_VOL;
+ __this->analog_volume_r = MAX_ANA_VOL;
+#if 0//TCFG_AUDIO_ANC_ENABLE
+ __this->analog_volume_l = anc_dac_gain_get(ANC_DAC_CH_L);
+ __this->analog_volume_r = anc_dac_gain_get(ANC_DAC_CH_R);
+ //g_printf("anc mode,vol_l:%d,vol_r:%d", __this->analog_volume_l, __this->analog_volume_r);
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+#else
+ if (__this->state == APP_AUDIO_STATE_CALL) {
+#if TCFG_CALL_USE_DIGITAL_VOLUME
+ u8 call_volume_level_max = ARRAY_SIZE(phone_call_dig_vol_tab) - 1;
+ app_var.call_volume = (app_var.call_volume > call_volume_level_max) ? call_volume_level_max : app_var.call_volume;
+ __this->digital_volume = phone_call_dig_vol_tab[app_var.call_volume];
+ printf("call_volume:%d,digital_volume:%d", app_var.call_volume, __this->digital_volume);
+ dac_digital_vol_open();
+ dac_digital_vol_tab_register(phone_call_dig_vol_tab, ARRAY_SIZE(phone_call_dig_vol_tab));
+ /*调数字音量的时候,模拟音量定最大*/
+ audio_dac_set_analog_vol(&dac_hdl, max_volume);
+#elif (SYS_VOL_TYPE == VOL_TYPE_AD)
+ /*通话联合音量调节的时候,最大音量为15,和手机的等级一致*/
+ __this->max_volume[state] = BT_CALL_VOL_LEAVE_MAX;
+#endif/*TCFG_CALL_USE_DIGITAL_VOLUME*/
+ }
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+ app_audio_set_volume(state, app_audio_get_volume(state), 1);
+}
+
+/*
+*********************************************************************
+* Audio State Exit
+* Description: 退出当前的声音状态
+* Arguments : state 要退出的声音状态
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+void app_audio_state_exit(u8 state)
+{
+#if TCFG_CALL_USE_DIGITAL_VOLUME
+ if (__this->state == APP_AUDIO_STATE_CALL) {
+ audio_digital_vol_close();
+ }
+#endif/*TCFG_CALL_USE_DIGITAL_VOLUME*/
+ if (state == __this->state) {
+ __this->state = __this->prev_state;
+ __this->prev_state = APP_AUDIO_STATE_IDLE;
+ } else if (state == __this->prev_state) {
+ __this->prev_state = APP_AUDIO_STATE_IDLE;
+ }
+}
+
+/*
+*********************************************************************
+* Audio Set Max Volume
+* Description: 设置最大音量
+* Arguments : state 要设置最大音量的声音状态
+* max_volume 最大音量
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+void app_audio_set_max_volume(u8 state, s16 max_volume)
+{
+ __this->max_volume[state] = max_volume;
+}
+
+/*
+*********************************************************************
+* Audio State Get
+* Description: 获取当前声音状态
+* Arguments : None.
+* Return : 返回当前的声音状态
+* Note(s) : None.
+*********************************************************************
+*/
+u8 app_audio_get_state(void)
+{
+ return __this->state;
+}
+
+/*
+*********************************************************************
+* Audio Volume_Max Get
+* Description: 获取当前声音通道的最大音量
+* Arguments : None.
+* Return : 返回当前的声音通道最大音量
+* Note(s) : None.
+*********************************************************************
+*/
+s16 app_audio_get_max_volume(void)
+{
+ if (__this->state == APP_AUDIO_STATE_IDLE) {
+ return get_max_sys_vol();
+ }
+#if TCFG_CALL_USE_DIGITAL_VOLUME
+ if (__this->state == APP_AUDIO_STATE_CALL) {
+ return (ARRAY_SIZE(phone_call_dig_vol_tab) - 1);
+ }
+#endif/*TCFG_CALL_USE_DIGITAL_VOLUME*/
+ return __this->max_volume[__this->state];
+}
+
+void app_audio_set_mix_volume(u8 front_volume, u8 back_volume)
+{
+ /*set_audio_device_volume(AUDIO_MIX_FRONT_VOL, front_volume);
+ set_audio_device_volume(AUDIO_MIX_BACK_VOL, back_volume);*/
+}
+#if 0
+
+void audio_vol_test()
+{
+ app_set_sys_vol(10, 10);
+ log_info("sys vol %d %d\n", get_audio_device_volume(AUDIO_SYS_VOL) >> 16, get_audio_device_volume(AUDIO_SYS_VOL) & 0xffff);
+ log_info("ana vol %d %d\n", get_audio_device_volume(AUDIO_ANA_VOL) >> 16, get_audio_device_volume(AUDIO_ANA_VOL) & 0xffff);
+ log_info("dig vol %d %d\n", get_audio_device_volume(AUDIO_DIG_VOL) >> 16, get_audio_device_volume(AUDIO_DIG_VOL) & 0xffff);
+ log_info("max vol %d %d\n", get_audio_device_volume(AUDIO_MAX_VOL) >> 16, get_audio_device_volume(AUDIO_MAX_VOL) & 0xffff);
+
+ app_set_max_vol(30);
+ app_set_ana_vol(25, 24);
+ app_set_dig_vol(90, 90);
+
+ log_info("sys vol %d %d\n", get_audio_device_volume(AUDIO_SYS_VOL) >> 16, get_audio_device_volume(AUDIO_SYS_VOL) & 0xffff);
+ log_info("ana vol %d %d\n", get_audio_device_volume(AUDIO_ANA_VOL) >> 16, get_audio_device_volume(AUDIO_ANA_VOL) & 0xffff);
+ log_info("dig vol %d %d\n", get_audio_device_volume(AUDIO_DIG_VOL) >> 16, get_audio_device_volume(AUDIO_DIG_VOL) & 0xffff);
+ log_info("max vol %d %d\n", get_audio_device_volume(AUDIO_MAX_VOL) >> 16, get_audio_device_volume(AUDIO_MAX_VOL) & 0xffff);
+}
+#endif
+
+void dac_power_on(void)
+{
+ log_info(">>>dac_power_on:%d", __this->ref.counter);
+#if TCFG_AUDIO_DAC_ENABLE
+ if (atomic_inc_return(&__this->ref) == 1) {
+ audio_dac_open(&dac_hdl);
+ }
+#endif // #if TCFG_AUDIO_DAC_ENABLE
+}
+
+void dac_power_off(void)
+{
+#if TCFG_AUDIO_DAC_ENABLE
+ /*log_info(">>>dac_power_off:%d", __this->ref.counter);*/
+ if (atomic_read(&__this->ref) != 0 && atomic_dec_return(&__this->ref)) {
+ return;
+ }
+#if 0
+ app_audio_mute(AUDIO_MUTE_DEFAULT);
+ if (dac_hdl.vol_l || dac_hdl.vol_r) {
+ u8 fade_time = dac_hdl.vol_l * 2 / 10 + 1;
+ os_time_dly(fade_time);
+ printf("fade_time:%d ms", fade_time);
+ }
+#endif
+ audio_dac_close(&dac_hdl);
+#endif // #if TCFG_AUDIO_DAC_ENABLE
+}
+
+#if 0
+/*
+ *写到dac buf的数据接口
+ */
+void audio_write_data_hook(void *data, u32 len)
+{
+
+}
+#endif
+
+/*
+ *dac快速校准
+ */
+//#define DAC_TRIM_FAST_EN
+#ifdef DAC_TRIM_FAST_EN
+u8 dac_trim_fast_en()
+{
+ return 1;
+}
+#endif/*DAC_TRIM_FAST_EN*/
+
+/*
+ *自定义dac上电延时时间,具体延时多久应通过示波器测量
+ */
+#if 1
+void dac_power_on_delay()
+{
+#if TCFG_MC_BIAS_AUTO_ADJUST
+ void mic_capless_auto_adjust_init();
+ mic_capless_auto_adjust_init();
+#endif
+ os_time_dly(50);
+}
+#endif
+
+#define TRIM_VALUE_LR_ERR_MAX (600) // 距离参考值的差值限制
+#define abs(x) ((x)>0?(x):-(x))
+int audio_dac_trim_value_check(struct audio_dac_trim *dac_trim)
+{
+ printf("audio_dac_trim_value_check %d %d\n", dac_trim->left, dac_trim->right);
+ s16 reference = 0;
+ if (TCFG_AUDIO_DAC_CONNECT_MODE != DAC_OUTPUT_MONO_R) {
+ if (abs(dac_trim->left - reference) > TRIM_VALUE_LR_ERR_MAX) {
+ log_error("dac trim channel l err\n");
+ return -1;
+ }
+ }
+ if (TCFG_AUDIO_DAC_CONNECT_MODE != DAC_OUTPUT_MONO_L) {
+ if (abs(dac_trim->right - reference) > TRIM_VALUE_LR_ERR_MAX) {
+ log_error("dac trim channel r err\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ *capless模式一开始不要的数据包数量
+ */
+u16 get_ladc_capless_dump_num(void)
+{
+ return 10;
+}
+
+extern struct adc_platform_data adc_data;
+int read_mic_type_config(void)
+{
+ MIC_TYPE_CONFIG mic_type;
+ int ret = syscfg_read(CFG_MIC_TYPE_ID, &mic_type, sizeof(MIC_TYPE_CONFIG));
+ if (ret > 0) {
+ log_info_hexdump(&mic_type, sizeof(MIC_TYPE_CONFIG));
+ adc_data.mic_capless = mic_type.type;
+ adc_data.mic_bias_res = mic_type.pull_up;
+ adc_data.mic_ldo_vsel = mic_type.ldo_lev;
+ return 0;
+ }
+ return -1;
+}
+
+
diff --git a/cpu/br28/audio_capture.c b/cpu/br28/audio_capture.c
new file mode 100644
index 0000000..95c672a
--- /dev/null
+++ b/cpu/br28/audio_capture.c
@@ -0,0 +1,1080 @@
+/*
+ ****************************************************************************
+ * Audio Capture Module(AC)
+ *
+ *
+ ****************************************************************************
+ */
+
+#include "audio_capture.h"
+#include "system/includes.h"
+#include "media/includes.h"
+#include "app_config.h"
+#include "tone_player.h"
+#include "app_main.h"
+#include "user_cfg.h"
+#include "online_db_deal.h"
+#include "audio_enc.h"
+#if TCFG_SMART_VOICE_ENABLE
+#include "smart_voice/smart_voice.h"
+#endif
+
+extern int spp_data_export(u8 ch, u8 *buf, u16 len);
+extern int aec_data_export_init(u8 ch);
+
+#if TCFG_AUDIO_DATA_EXPORT_ENABLE
+
+#define AC_LOG_ENABLE
+#ifdef AC_LOG_ENABLE
+#define AC_LOG y_printf
+#define AC_ERR_LOG r_printf
+#else
+#define AC_LOG(...)
+#define AC_ERR_LOG(...)
+#endif/*AC_LOG_ENABLE*/
+
+extern struct audio_dac_hdl dac_hdl;
+extern struct audio_adc_hdl adc_hdl;
+
+#define AudioCapture_CLK (128 * 1000000L)
+
+#define AC_A_MIC 1 //2个模拟mic(Analog)
+#define AC_D_MIC 2 //2个PDM mic(Digital)
+#define AC_AD_MIC 3 //一个模拟mic、一个PDM mic
+#define AC_VAD_MIC 4 //VAD模拟mic
+#define AC_MIC_TYPE AC_A_MIC
+#define AC_SAMPLE_RATE 16000 //AudioCapture Sample Rate
+
+/**********************LED INDICATE CONFIG*********************/
+#define LED_INDICATE_EN 0
+#define LED_PORT JL_PORTC
+#define LED_PORT_NUM 0
+#define LED_DISPLAY_INIT() LED_PORT->DIR &= ~BIT(LED_PORT_NUM)
+#define LED_DISPLAY_ON() LED_PORT->OUT |= BIT(LED_PORT_NUM)
+#define LED_DISPLAY_OFF() LED_PORT->OUT &= ~BIT(LED_PORT_NUM)
+/***************************************************************/
+
+#define DM_2_DAC_EN 0 //双mic的数据输出到DAC播放(debug)
+#define PLNK_MIC_CH 2
+#define NS_DEMO_EN 0 //降噪模型测试使能
+
+#define DM_RUN_POINT 256 //DualMic运行frame长(points)
+#define DM_RUN_SIZE (DM_RUN_POINT * 2) //DualMic运行frame长(bytes)
+
+#define ADC_MIC0_EN 1
+#define ADC_MIC1_EN 1
+#define ADC_DM_BUF_NUM 2
+#if (NS_DEMO_EN || (AC_MIC_TYPE & AC_VAD_MIC))
+#define ADC_DM_CH_NUM 1
+#else /*使用AC_AD_MIC*/
+#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
+/*开3路ADC*/
+#define ADC_DM_CH_NUM 3
+#else /*双麦*/
+/*开2路ADC*/
+#define ADC_DM_CH_NUM 2
+#endif /*TCFG_AUDIO_TRIPLE_MIC_ENABLE*/
+#endif/*NS_DEMO_EN*/
+#define ADC_DM_IRQ_POINTS 256
+#define ADC_DM_BUFS_SIZE (ADC_DM_BUF_NUM * ADC_DM_IRQ_POINTS * ADC_DM_CH_NUM)
+
+#if (AC_MIC_TYPE == AC_AD_MIC)
+#undef PLNK_MIC_CH
+#undef ADC_DM_CH_NUM
+#undef ADC_DM_BUFS_SIZE
+#define PLNK_MIC_CH 1
+#define ADC_DM_CH_NUM 1
+#define ADC_DM_BUFS_SIZE (ADC_DM_BUF_NUM * ADC_DM_IRQ_POINTS * ADC_DM_CH_NUM)
+#endif
+
+
+/******************SPP_DATA_EXPORT_CONFIG****************************/
+
+#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SPP)
+#define SPP_EXPORT_HEAD 4 /*4 bytes seqn*/
+#define SPP_EXPORT_DATA_LEN 640 /*数据包长度*/
+#define SPP_EXPORT_MTU (SPP_EXPORT_DATA_LEN + SPP_EXPORT_HEAD)
+#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
+#define SPP_EXPORT_CH 3 /*导出数据通道数*/
+#else /*两个通道*/
+#define SPP_EXPORT_CH 2 /*导出数据通道数*/
+#endif /*TCFG_AUDIO_TRIPLE_MIC_ENABLE*/
+#define SPP_SEND_BY_TIMER 1 /*通过定时器定时发送*/
+#if (SPP_EXPORT_CH == 3)
+#define SPP_SEND_INTERVAL 4 //ms
+#else
+#define SPP_SEND_INTERVAL 6 //ms
+#endif
+#endif
+/******************************************************************/
+
+#define SD_START_BLOCK 50000 // SD卡起始扇区
+#define SD_PCM_CHANNLE 1 // PCM数据通道
+#define SD_PCM_BUF_SIZE (512 * SD_PCM_CHANNLE) // 每次写的数据长度
+#define DE_HEADER_LEN 12 //数据头的长度
+#define SD_PCM_BUF_SIZE_H (SD_PCM_BUF_SIZE - DE_HEADER_LEN) // 每次写的数据长度(with packet header)
+
+/*数据导出添加数据头*/
+#define DE_PACKET_HEADER_EN 0 //DE:DataExport
+
+extern struct device *force_open_sd(char *sdx);
+extern void force_write_sd(u8 *buf, u32 sector, u32 sector_num);
+
+/*Audio Capture state*/
+enum {
+ AC_STATE_INIT,
+ AC_STATE_START,
+ AC_STATE_STOP,
+};
+
+static u16 mic_ch_sw = 0;
+
+#if DE_PACKET_HEADER_EN
+#define DE_HEADER_MAGIC 0x5A
+typedef struct {
+ u8 magic; //标识符0x5A
+ u8 ch; //通道号:0 1 2 0 1 2
+ u16 seqn; //序列号:0 1 2 3 4 5
+ u16 crc; //校验码
+ u16 len; //数据长度
+ u32 total_len; //数据累加总长
+} de_header;
+#endif/*DATA_PACKET_HEADER_EN*/
+
+typedef struct {
+ u8 state;
+ u16 sr;
+ OS_SEM sem;
+ struct device *sd_hdl;
+ s16 mic0_buf[ADC_DM_IRQ_POINTS * 4]; // mic0的原始数据buf
+ s16 mic1_buf[ADC_DM_IRQ_POINTS * 4]; // mic1的原始数据buf
+ s16 mic2_buf[ADC_DM_IRQ_POINTS * 4]; // mic2的原始数据buf
+ //s16 out_buf[ADC_DM_IRQ_POINTS * 4]; // dm noise reduce output
+ cbuffer_t mic0_cb;
+ cbuffer_t mic1_cb;
+ cbuffer_t mic2_cb;
+ //cbuffer_t out_cb;
+ s16 mic0[DM_RUN_POINT];
+ s16 mic1[DM_RUN_POINT];
+ s16 mic2[DM_RUN_POINT];
+ s16 output[DM_RUN_POINT];
+#if (AC_MIC_TYPE & AC_VAD_MIC)
+ void *vad_mic;
+#endif
+
+#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SPP)
+ u8 export_buf[SPP_EXPORT_MTU];
+#endif
+
+#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SD)
+ u32 sd_write_sector;
+ OS_SEM sd_sem;
+ u8 sd_wbuf[SD_PCM_BUF_SIZE]; // 数据导出buf
+#if DE_PACKET_HEADER_EN
+ s16 ch0_buf[ADC_DM_IRQ_POINTS * 3];
+ s16 ch1_buf[ADC_DM_IRQ_POINTS * 3];
+ s16 ch2_buf[ADC_DM_IRQ_POINTS * 3];
+ cbuffer_t ch0_cb;
+ cbuffer_t ch1_cb;
+ cbuffer_t ch2_cb;
+#endif/*DE_PACKET_HEADER_EN*/
+#endif/*TCFG_AUDIO_DATA_EXPORT_ENABLE*/
+ s16 out_buf[ADC_DM_IRQ_POINTS * 6]; // dm noise reduce output
+ cbuffer_t out_cbuf;
+} dual_mic_t;
+dual_mic_t dm;
+
+static void led_init()
+{
+#if LED_INDICATE_EN
+ LED_DISPLAY_INIT();
+ LED_DISPLAY_ON();
+#endif/*LED_INDICATE_EN*/
+}
+
+static void led_run(u16 ms)
+{
+#if LED_INDICATE_EN
+ static u16 led_flash_cnt = 2000;
+ u16 flash_time = ms / 16;
+ if (led_flash_cnt++ > flash_time) {
+ LED_DISPLAY_OFF();
+ if (led_flash_cnt > (flash_time + 30)) {
+ led_flash_cnt = 0;
+ LED_DISPLAY_ON();
+ }
+ }
+#endif/*LED_INDICATE_EN*/
+}
+
+#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SD)
+static int data_export_run(void *dat, u16 len, u8 ch)
+{
+#if DE_PACKET_HEADER_EN
+ int wlen = 0;
+ //printf("export_run:%d",ch);
+ if (ch == 0) {
+ wlen = cbuf_write(&dm.ch0_cb, dat, len);
+ if (wlen != len) {
+ AC_ERR_LOG("[dm]sd%d buf full\n", ch);
+ }
+ } else if (ch == 1) {
+ wlen = cbuf_write(&dm.ch1_cb, dat, len);
+ if (wlen != len) {
+ AC_ERR_LOG("[dm]sd%d buf full\n", ch);
+ }
+ } else {
+ wlen = cbuf_write(&dm.ch2_cb, dat, len);
+ if (wlen != len) {
+ AC_ERR_LOG("[dm]sd%d buf full\n", ch);
+ }
+ }
+ os_sem_set(&dm.sd_sem, 0);
+ os_sem_post(&dm.sd_sem);
+#else
+ int wlen = cbuf_write(&dm.out_cbuf, dat, len);
+ if (wlen != len) {
+ AC_ERR_LOG("[dm]sd buf full\n");
+ }
+ if (dm.out_cbuf.data_len >= SD_PCM_BUF_SIZE) {
+ os_sem_set(&dm.sd_sem, 0);
+ os_sem_post(&dm.sd_sem);
+ }
+#endif
+ return 0;
+}
+
+#if DE_PACKET_HEADER_EN
+static void DataExport_Task(void *p)
+{
+ AC_LOG(">>>DataExport_Task[Header]<<<\n");
+ u8 pend;
+ u8 wch = 0;
+ de_header header;
+ u16 seqn0 = 0;
+ u16 seqn1 = 0;
+ u16 seqn2 = 0;
+ u32 total_len0 = 0;
+ u32 total_len1 = 0;
+ u32 total_len2 = 0;
+ header.magic = DE_HEADER_MAGIC;
+ while (1) {
+ pend = 1;
+ if (wch == 0) {
+ if (dm.ch0_cb.data_len >= SD_PCM_BUF_SIZE_H) { // 每次必须CBUF有足够的数据长度,才可以写。
+ pend = 0;
+ cbuf_read(&dm.ch0_cb, &dm.sd_wbuf[DE_HEADER_LEN], SD_PCM_BUF_SIZE_H);
+ header.ch = wch;
+ header.seqn = seqn0++;
+ header.crc = CRC16(&dm.sd_wbuf[DE_HEADER_LEN], SD_PCM_BUF_SIZE_H);
+ header.len = SD_PCM_BUF_SIZE_H;
+ total_len0 += header.len;
+ header.total_len = total_len0;
+ memcpy(&dm.sd_wbuf, &header, sizeof(de_header));
+ //y_printf("ch:%d,%d,%x,%d",header.ch,header.seqn,header.crc,header.len);
+ if (dm.sd_hdl) {
+ putchar('.');
+ led_run(7000);
+ force_write_sd(dm.sd_wbuf, dm.sd_write_sector, SD_PCM_CHANNLE);
+ dm.sd_write_sector += SD_PCM_CHANNLE;
+ /* printf("sd:%d\n",dm.sd_write_sector); //打印当前写的扇区位置。 */
+ }
+ wch++;
+ }
+ } else if (wch == 1) {
+ if (dm.ch1_cb.data_len >= SD_PCM_BUF_SIZE_H) { // 每次必须CBUF有足够的数据长度,才可以写。
+ pend = 0;
+ cbuf_read(&dm.ch1_cb, &dm.sd_wbuf[DE_HEADER_LEN], SD_PCM_BUF_SIZE_H);
+ header.ch = wch;
+ header.seqn = seqn1++;
+ header.crc = CRC16(&dm.sd_wbuf[DE_HEADER_LEN], SD_PCM_BUF_SIZE_H);
+ header.len = SD_PCM_BUF_SIZE_H;
+ total_len1 += header.len;
+ header.total_len = total_len1;
+ memcpy(&dm.sd_wbuf, &header, sizeof(de_header));
+ //g_printf("ch:%d,%d,%x,%d",header.ch,header.seqn,header.crc,header.len);
+ if (dm.sd_hdl) {
+ putchar('.');
+ led_run(7000);
+ force_write_sd(dm.sd_wbuf, dm.sd_write_sector, SD_PCM_CHANNLE);
+ dm.sd_write_sector += SD_PCM_CHANNLE;
+ /* printf("sd:%d\n",dm.sd_write_sector); //打印当前写的扇区位置。 */
+ }
+ wch++;
+ }
+ } else if (wch == 2) {
+ if (dm.ch2_cb.data_len >= SD_PCM_BUF_SIZE_H) { // 每次必须CBUF有足够的数据长度,才可以写。
+ pend = 0;
+ cbuf_read(&dm.ch2_cb, &dm.sd_wbuf[DE_HEADER_LEN], SD_PCM_BUF_SIZE_H);
+ header.ch = wch;
+ header.seqn = seqn2++;
+ header.crc = CRC16(&dm.sd_wbuf[DE_HEADER_LEN], SD_PCM_BUF_SIZE_H);
+ header.len = SD_PCM_BUF_SIZE_H;
+ total_len2 += header.len;
+ header.total_len = total_len2;
+ memcpy(&dm.sd_wbuf, &header, sizeof(de_header));
+ //g_printf("ch:%d,%d,%x,%d",header.ch,header.seqn,header.crc,header.len);
+ if (dm.sd_hdl) {
+ putchar('.');
+ led_run(7000);
+ force_write_sd(dm.sd_wbuf, dm.sd_write_sector, SD_PCM_CHANNLE);
+ dm.sd_write_sector += SD_PCM_CHANNLE;
+ /* printf("sd:%d\n",dm.sd_write_sector); //打印当前写的扇区位置。 */
+ }
+ wch = 0;
+ }
+ }
+ //printf("wch:%d,pend:%d,len:%d,%d,%d",wch,pend,dm.ch0_cb.data_len,dm.ch1_cb.data_len,dm.ch2_cb.data_len);
+ if (pend) {
+ os_sem_pend(&dm.sd_sem, 0);
+ }
+ }
+}
+
+#else
+static void DataExport_Task(void *p)
+{
+ AC_LOG(">>>DataExport_Task<<<\n");
+ while (1) {
+ if (dm.out_cbuf.data_len >= SD_PCM_BUF_SIZE) { // 每次必须CBUF有足够的数据长度,才可以写。
+ cbuf_read(&dm.out_cbuf, dm.sd_wbuf, SD_PCM_BUF_SIZE);
+ if (dm.sd_hdl) {
+ putchar('.');
+ led_run(7000);
+
+ force_write_sd(dm.sd_wbuf, dm.sd_write_sector, SD_PCM_CHANNLE);
+ dm.sd_write_sector += SD_PCM_CHANNLE;
+ /* printf("sd:%d\n",dm.sd_write_sector); //打印当前写的扇区位置。 */
+ }
+ } else {
+ os_sem_pend(&dm.sd_sem, 0);
+ }
+ }
+}
+#endif
+
+#else
+static int data_export_run(void *dat, u16 len, u8 ch)
+{
+ return 0;
+}
+#endif/*TCFG_AUDIO_DATA_EXPORT_ENABLE*/
+
+/*
+ *数据导出初始化
+ */
+typedef struct {
+ u8 ch_idx;
+ u8 retry;
+ u16 send_timer;
+ u32 seqn0;
+ u32 seqn1;
+ u32 seqn2;
+} data_export_t;
+data_export_t de;
+int data_export_init()
+{
+ AC_LOG("[dm]data_export_init\n");
+#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SD)
+ /*使能板子RT9193,供电给sd卡*/
+ JL_PORTB->DIR &= ~BIT(3);
+ JL_PORTB->OUT |= BIT(3);
+ dm.sd_hdl = force_open_sd("sd0");
+ AC_LOG("sd_hdl:%x\n", dm.sd_hdl);
+ //os_time_dly(10);
+#if DE_PACKET_HEADER_EN
+ cbuf_init(&dm.ch0_cb, dm.ch0_buf, sizeof(dm.ch0_buf));
+ cbuf_init(&dm.ch1_cb, dm.ch1_buf, sizeof(dm.ch1_buf));
+ cbuf_init(&dm.ch2_cb, dm.ch2_buf, sizeof(dm.ch2_buf));
+ AC_LOG("de packet header size:%d\n", sizeof(de_header));
+#else
+ cbuf_init(&dm.out_cbuf, dm.out_buf, sizeof(dm.out_buf));
+#endif/*DE_PACKET_HEADER_EN*/
+ dm.sd_write_sector = SD_START_BLOCK;
+ os_sem_create(&dm.sd_sem, 0);
+ task_create(DataExport_Task, NULL, "data_export");
+#endif/*AUDIO_DATA_EXPORT_USE_SD*/
+
+#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SPP)
+ aec_data_export_init(SPP_EXPORT_CH);
+#endif/*AUDIO_DATA_EXPORT_USE_SPP*/
+ memset(&de, 0, sizeof(data_export_t));
+ cbuf_init(&dm.out_cbuf, dm.out_buf, sizeof(dm.out_buf));
+
+ return 0;
+}
+
+
+typedef struct {
+ struct audio_adc_output_hdl adc_output;
+ struct adc_mic_ch mic_ch;
+ s16 adc_buf[ADC_DM_BUFS_SIZE]; //align 4Bytes
+ s16 mic_tmp_data[ADC_DM_IRQ_POINTS];
+ s16 mic1_tmp_data[ADC_DM_IRQ_POINTS];
+} adc_dm_t;
+adc_dm_t *adc_dm = NULL;
+
+void dm_2_dac_open(u16 sr)
+{
+#if DM_2_DAC_EN
+ y_printf("%s,sr = %d\n", sr);
+ audio_dac_set_sample_rate(&dac_hdl, sr);
+ audio_dac_start(&dac_hdl);
+ printf("max_sys_vol:%d\n", get_max_sys_vol());
+ app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
+ printf("cur_vol:%d\n", app_audio_get_volume(APP_AUDIO_STATE_MUSIC));
+ audio_dac_set_volume(&dac_hdl, app_audio_get_volume(APP_AUDIO_STATE_MUSIC));
+#endif
+}
+
+static void adc_mic_output(void *priv, s16 *data, int len)
+{
+ /* printf("<%x,%x,%d>",adc_dm->adc_buf,data,len); */
+ u16 wlen;
+#if (ADC_DM_CH_NUM == 2)
+ /*
+ *这里先把mic0的数据取出来放在临时buf,mic1的数据就可以
+ *放到mic本来的buf了,不用再开一个buf放mic1_data
+ */
+ s16 *mic0_data = adc_dm->mic_tmp_data;
+ s16 *mic1_data = data;
+ for (u16 i = 0; i < (len >> 1); i++) {
+ mic0_data[i] = data[i * 2];
+ mic1_data[i] = data[i * 2 + 1];
+ }
+
+ wlen = cbuf_write(&dm.mic0_cb, mic0_data, len);
+ if (wlen != len) {
+ AC_ERR_LOG("mic0_cbuf full:%d,%d\n", wlen, len);
+ }
+
+#if (TCFG_AUDIO_TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SPP)
+#if (SPP_EXPORT_CH > 1)
+ wlen = cbuf_write(&dm.mic1_cb, mic1_data, len);
+ if (wlen != len) {
+ AC_ERR_LOG("mic1_cbuf full\n");
+ }
+#endif/*SPP_EXPORT_CH == 2*/
+#else
+ wlen = cbuf_write(&dm.mic1_cb, mic1_data, len);
+ if (wlen != len) {
+ AC_ERR_LOG("mic1_cbuf full\n");
+ }
+#endif/*TCFG_AUDIO_TCFG_AUDIO_DATA_EXPORT_ENABLE*/
+
+ os_sem_post(&dm.sem);
+
+#if DM_2_DAC_EN
+ if (tone_get_status()) {
+ return;
+ }
+ if (mic_ch_sw++ < 300) {
+ putchar('0');
+ wlen = audio_dac_write(&dac_hdl, mic0_data, len);
+ } else {
+ putchar('1');
+ wlen = audio_dac_write(&dac_hdl, mic1_data, len);
+ if (mic_ch_sw >= 600) {
+ mic_ch_sw = 0;
+ }
+ }
+#endif/*DM_2_DAC_EN*/
+
+#elif (ADC_DM_CH_NUM == 3)
+ /*
+ *这里先把mic0的数据取出来放在临时buf,mic1的数据就可以
+ *放到mic本来的buf了,不用再开一个buf放mic1_data
+ */
+ s16 *mic0_data = data;
+ s16 *mic1_data = adc_dm->mic_tmp_data;
+ s16 *mic2_data = adc_dm->mic1_tmp_data;
+ for (u16 i = 0; i < (len >> 1); i++) {
+ mic0_data[i] = data[i * 3];
+ mic1_data[i] = data[i * 3 + 1];
+ mic2_data[i] = data[i * 3 + 2];
+ }
+
+ wlen = cbuf_write(&dm.mic0_cb, mic0_data, len);
+ if (wlen != len) {
+ AC_ERR_LOG("mic0_cbuf full:%d,%d\n", wlen, len);
+ }
+
+ wlen = cbuf_write(&dm.mic1_cb, mic1_data, len);
+ if (wlen != len) {
+ AC_ERR_LOG("mic1_cbuf full:%d,%d\n", wlen, len);
+ }
+
+ wlen = cbuf_write(&dm.mic2_cb, mic2_data, len);
+ if (wlen != len) {
+ AC_ERR_LOG("mic2_cbuf full:%d,%d\n", wlen, len);
+ }
+ os_sem_post(&dm.sem);
+
+#if DM_2_DAC_EN
+ if (tone_get_status()) {
+ return;
+ }
+ if (mic_ch_sw++ < 300) {
+ putchar('0');
+ wlen = audio_dac_write(&dac_hdl, mic0_data, len);
+ } else if (mic_ch_sw++ < 600) {
+ putchar('1');
+ wlen = audio_dac_write(&dac_hdl, mic1_data, len);
+ } else {
+ putchar('2');
+ wlen = audio_dac_write(&dac_hdl, mic2_data, len);
+ if (mic_ch_sw >= 900) {
+ mic_ch_sw = 0;
+ }
+ }
+#endif/*DM_2_DAC_EN*/
+
+#else /*单模拟MIC(ADC_DM_CH_NUM == 1)*/
+ //putchar('m');
+ wlen = cbuf_write(&dm.mic1_cb, data, len);
+ if (wlen != len) {
+ AC_ERR_LOG("mic1_cbuf full\n");
+ }
+ os_sem_post(&dm.sem);
+#if (DM_2_DAC_EN && (NS_DEMO_EN == 0))
+ if (mic_ch_sw >= 300) {
+ mic_ch_sw++;
+ putchar('1');
+ wlen = audio_dac_write(&dac_hdl, data, len);
+ if (mic_ch_sw >= 600) {
+ mic_ch_sw = 0;
+ }
+ }
+#endif/*DM_2_DAC_EN*/
+#endif/*ADC_DM_CH_NUM*/
+}
+
+static u8 dual_mic_idle_query()
+{
+ return 0;
+}
+
+REGISTER_LP_TARGET(dual_mic_lp_target) = {
+ .name = "dual_mic",
+ .is_idle = dual_mic_idle_query,
+};
+
+/*初始化 mic*/
+int audio_mic_init(u16 sr)
+{
+ AC_LOG("[dm]audio_mic_init\n");
+ adc_dm = zalloc(sizeof(*adc_dm));
+ /*
+ *range:0(00000:-8dB)~19(1001:30dB)
+ *step:2dB
+ */
+ u8 mic0_gain = 10;
+ u8 mic1_gain = 10;
+ u8 mic2_gain = 10;
+ u8 mic3_gain = 10;
+
+ //使用通话配置的mic增益,更加直观反映mic的数据采样情况
+ mic0_gain = app_var.aec_mic_gain;
+ mic1_gain = app_var.aec_mic1_gain;
+ mic2_gain = app_var.aec_mic2_gain;
+ mic3_gain = app_var.aec_mic3_gain;
+ AC_LOG("[AC]mic_gain:%d,%d,%d,%d\n", mic0_gain, mic1_gain, mic2_gain, mic3_gain);
+
+ if (adc_dm) {
+#if (TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA & AUDIO_ADC_MIC_0)
+ audio_adc_mic_open(&adc_dm->mic_ch, TCFG_AUDIO_ADC_MIC_CHA, &adc_hdl);
+ audio_adc_mic_set_gain(&adc_dm->mic_ch, app_var.aec_mic_gain);
+#endif/*TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA & AUDIO_ADC_MIC_0*/
+#if (TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA & AUDIO_ADC_MIC_1)
+ audio_adc_mic1_open(&adc_dm->mic_ch, TCFG_AUDIO_ADC_MIC_CHA, &adc_hdl);
+ audio_adc_mic1_set_gain(&adc_dm->mic_ch, app_var.aec_mic1_gain);
+#endif/*(TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA & AUDIO_ADC_MIC_1)*/
+#if (TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA & AUDIO_ADC_MIC_2)
+ audio_adc_mic2_open(&adc_dm->mic_ch, TCFG_AUDIO_ADC_MIC_CHA, &adc_hdl);
+ audio_adc_mic2_set_gain(&adc_dm->mic_ch, app_var.aec_mic2_gain);
+#endif/*(TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA & AUDIO_ADC_MIC_2)*/
+#if (TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA & AUDIO_ADC_MIC_3)
+ audio_adc_mic3_open(&adc_dm->mic_ch, TCFG_AUDIO_ADC_MIC_CHA, &adc_hdl);
+ audio_adc_mic3_set_gain(&adc_dm->mic_ch, app_var.aec_mic3_gain);
+#endif/*(TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA & AUDIO_ADC_MIC_3)*/
+
+ audio_adc_mic_set_sample_rate(&adc_dm->mic_ch, sr);
+ audio_adc_mic_set_buffs(&adc_dm->mic_ch, adc_dm->adc_buf, ADC_DM_IRQ_POINTS * 2, ADC_DM_BUF_NUM);
+ adc_dm->adc_output.handler = adc_mic_output;
+ audio_adc_add_output_handler(&adc_hdl, &adc_dm->adc_output);
+ audio_adc_mic_start(&adc_dm->mic_ch);
+
+
+ }
+ return 0;
+}
+
+void audio_mic_close(void)
+{
+ if (adc_dm) {
+ audio_adc_mic_close(&adc_dm->mic_ch);
+ audio_adc_del_output_handler(&adc_hdl, &adc_dm->adc_output);
+ free(adc_dm);
+ adc_dm = NULL;
+ }
+}
+
+#include "pdm_link.h"
+audio_plnk_t *plnk_mic = NULL;
+
+/*
+ *数据结构:
+ *单声道:ch00 ch01 ch02 ch0n
+ *双声道:ch00 ch01 ch02 ch0n ch10 ch11 ch12 ch1n
+ */
+static void plnk_mic_output(void *buf, u16 len)
+{
+ s16 *mic0;
+ s16 *mic1;
+ /* audio_plnk_t *plnk = priv; */
+ /* s16 *buf = plnk->buf; */
+ /* u16 len = plnk->buf_len; */
+
+ //ch0
+ mic0 = (s16 *)buf;
+#if (PLNK_MIC_CH == 2)
+ //ch1
+ mic1 = (s16 *)buf + len * 2;
+#endif/*PLNK_MIC_CH == 2*/
+
+#if 0 //合并两个声道的声音:LLLRRR... -> LRLRLR...
+ for (int cnt = 0; cnt < len; cnt++) {
+ tmp_buf[cnt * 2] = mic0[cnt];
+ tmp_buf[cnt * 2 + 1] = mic1[cnt];
+ }
+#endif
+
+ u16 olen = len << 1;
+ u16 wlen;
+
+ putchar('o');
+ //printf("olen:%d,%d",len,olen);
+
+ wlen = cbuf_write(&dm.mic0_cb, mic0, olen);
+ if (wlen != olen) {
+ AC_ERR_LOG("mic0_cbuf full:%d,%d\n", wlen, olen);
+ }
+#if ((AC_MIC_TYPE == AC_D_MIC) && (PLNK_MIC_CH == 2))
+ wlen = cbuf_write(&dm.mic1_cb, mic1, olen);
+ if (wlen != olen) {
+ AC_ERR_LOG("mic1_cbuf full:%d,%d\n", wlen, olen);
+ }
+#endif
+ os_sem_post(&dm.sem);
+
+#if DM_2_DAC_EN
+#if (AC_MIC_TYPE == AC_D_MIC)
+#if (PLNK_MIC_CH == 2)
+ if (mic_ch_sw++ < 300) {
+ putchar('0');
+ wlen = audio_dac_write(&dac_hdl, mic0, olen);
+ } else {
+ putchar('1');
+ wlen = audio_dac_write(&dac_hdl, mic1, olen);
+ if (mic_ch_sw >= 600) {
+ mic_ch_sw = 0;
+ }
+ }
+#else/*单mic数据输出*/
+ wlen = audio_dac_write(&dac_hdl, mic0, olen);
+#endif/*PLNK_MIC_CH*/
+#else
+ if (mic_ch_sw < 300) {
+ mic_ch_sw++;
+ putchar('0');
+ wlen = audio_dac_write(&dac_hdl, mic0, olen);
+ }
+#endif/*AC_MIC_TYPE*/
+ if (wlen != olen) {
+ putchar('F');
+ }
+#endif/*DM_2_DAC_EN*/
+}
+
+//#define PLNK_SCLK_PIN IO_PORTA_02
+//#define PLNK_DAT0_PIN IO_PORTA_01
+//#define PLNK_CH_EN PLNK_CH0_EN //(PLNK_CH0_EN | PLNK_CH1_EN)
+static int audio_pdm_mic_init(u16 sr)
+{
+#if 0/*br28目前app层还没有做pdm*/
+ AC_LOG("[dm]audio_pdm_mic_init:%d\n", sr);
+
+ //MIC_PWR0
+ JL_PORTA->DIR &= ~BIT(2);
+ JL_PORTA->OUT |= BIT(2);
+ //6976B PA2 PA3双绑
+ JL_PORTA->DIR |= BIT(3);
+ JL_PORTA->PU &= ~BIT(3);
+ JL_PORTA->PD &= ~BIT(3);
+
+#if (AC_MIC_TYPE == AC_D_MIC)
+ //MIC_PWR1
+ JL_PORTB->DIR &= ~BIT(7);
+ JL_PORTB->OUT |= BIT(7);
+#endif
+
+ plnk_mic = zalloc(sizeof(audio_plnk_t));
+ if (plnk_mic) {
+ plnk_mic->ch_num = PLNK_MIC_CH;
+ plnk_mic->sr = sr;
+ plnk_mic->buf_len = 256;
+#if (PLNK_CH_EN == PLNK_CH0_EN)/*两个通道,复用ch0*/
+ plnk_mic->ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE;
+ plnk_mic->ch1_mode = CH1MD_CH0_SCLK_FALLING_EDGE;
+#elif (PLNK_CH_EN == PLNK_CH1_EN)/*两个通道,复用ch1*/
+ plnk_mic->ch0_mode = CH0MD_CH1_SCLK_FALLING_EDGE;
+ plnk_mic->ch1_mode = CH1MD_CH1_SCLK_RISING_EDGE;
+#else/*两个通道,用两个data ch*/
+ plnk_mic->ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE;
+ plnk_mic->ch1_mode = CH1MD_CH1_SCLK_RISING_EDGE;
+#endif/*PLNK_CH_EN*/
+ plnk_mic->buf = zalloc(plnk_mic->ch_num * plnk_mic->buf_len * 2 * 2);
+ ASSERT(plnk_mic->buf);
+ plnk_mic->output = plnk_mic_output;
+
+ plnk_mic->sclk_io = TCFG_AUDIO_PLNK_SCLK_PIN;
+ plnk_mic->ch0_io = TCFG_AUDIO_PLNK_DAT0_PIN;
+
+ audio_plnk_open(plnk_mic);
+ audio_plnk_start(plnk_mic);
+
+ //dm_2_dac_open(plnk_mic->sr);
+ }
+#endif
+ return 0;
+}
+
+static int DualMic_NoiseReduce_run(s16 *dat0, s16 *dat2, s16 *out, u16 points)
+{
+ memcpy(out, dat0, points << 1);
+ return points;
+}
+
+#define SPP_EXPORT_RETRY_EN 0
+
+#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SPP)
+static void spp_data_export_run()
+{
+ int ret;
+ int out_points;
+
+ if (dm.state != AC_STATE_START) {
+ return;
+ }
+
+#if AC_MIC_TYPE == AC_VAD_MIC
+ de.ch_idx = 1;
+#endif
+ switch (de.ch_idx) {
+ case 0:
+ //putchar('0');
+ if (de.retry == 0) {
+ ret = cbuf_read(&dm.mic0_cb, &dm.export_buf[4], SPP_EXPORT_DATA_LEN);
+ memcpy(dm.export_buf, &de.seqn0, SPP_EXPORT_HEAD);
+ } else {
+ ret = SPP_EXPORT_DATA_LEN;
+ }
+ if (ret == SPP_EXPORT_DATA_LEN) {
+ ret = spp_data_export(0, dm.export_buf, SPP_EXPORT_MTU);
+ if (ret == SPP_EXPORT_MTU) {
+ de.seqn0++;
+ de.ch_idx++;
+ de.retry = 0;
+ //putchar('A');
+ } else if (ret == -1) {
+ de.retry = SPP_EXPORT_RETRY_EN;
+ } else {
+ de.ch_idx++;
+ de.retry = 0;
+ }
+ }
+ break;
+ case 1:
+ //putchar('1');
+#if NS_DEMO_EN
+ ret = cbuf_read(&dm.out_cbuf, &dm.export_buf[4], SPP_EXPORT_DATA_LEN);
+#else
+#if AC_MIC_TYPE == AC_VAD_MIC
+ if (cbuf_get_data_len(&dm.mic1_cb) < SPP_EXPORT_DATA_LEN) {
+ break;
+ }
+#endif
+ ret = cbuf_read(&dm.mic1_cb, &dm.export_buf[4], SPP_EXPORT_DATA_LEN);
+#endif/*NS_DEMO_EN*/
+ memcpy(dm.export_buf, &de.seqn1, SPP_EXPORT_HEAD);
+ if (ret == SPP_EXPORT_DATA_LEN) {
+ ret = spp_data_export(1, dm.export_buf, SPP_EXPORT_MTU);
+ if (ret == SPP_EXPORT_MTU) {
+ de.seqn1++;
+ de.ch_idx++;
+ de.retry = 0;
+ //putchar('B');
+ } else if (ret == -1) {
+ de.retry = SPP_EXPORT_RETRY_EN;
+ } else {
+ de.ch_idx++;
+ de.retry = 0;
+ }
+ }
+ break;
+ case 2:
+ //putchar('2');
+ ret = cbuf_read(&dm.mic2_cb, &dm.export_buf[4], SPP_EXPORT_DATA_LEN);
+ memcpy(dm.export_buf, &de.seqn2, SPP_EXPORT_HEAD);
+ if (ret == SPP_EXPORT_DATA_LEN) {
+ //putchar('C');
+ ret = spp_data_export(2, dm.export_buf, SPP_EXPORT_MTU);
+ if (ret == SPP_EXPORT_MTU) {
+ de.seqn2++;
+ de.ch_idx++;
+ de.retry = 0;
+ } else if (ret == -1) {
+ de.retry = SPP_EXPORT_RETRY_EN;
+ } else {
+ de.ch_idx++;
+ de.retry = 0;
+ }
+ }
+ break;
+ }
+ if (de.ch_idx > (SPP_EXPORT_CH - 1)) {
+ de.ch_idx = 0;
+ }
+
+}
+static void aec_export_timer(void *priv)
+{
+#if SPP_SEND_BY_TIMER
+ spp_data_export_run();
+#else
+ os_sem_set(&dm.sem, 0);
+ os_sem_post(&dm.sem);
+#endif
+}
+
+#endif
+
+
+
+static int audio_ns_open(u16 sr);
+int audio_capture_start(void);
+static void audio_capture_board_init()
+{
+ led_init();
+ clk_set("sys", AudioCapture_CLK);
+ data_export_init();
+#if NS_DEMO_EN
+ audio_ns_open(dm.sr);
+#endif /*NS_DEMO_EN*/
+
+ /*spp数据导出,由spp控制声音捕捉启动;SD数据导出,则默认自动启动声音捕捉*/
+#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SD)
+ audio_capture_start();
+#endif/*AUDIO_DATA_EXPORT_USE_SD*/
+
+#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_UART)
+ audio_capture_start();
+ aec_uart_init();
+#endif/*AUDIO_DATA_EXPORT_USE_SD*/
+
+ dm.state = AC_STATE_INIT;
+}
+
+int audio_capture_start(void)
+{
+ dm.sr = AC_SAMPLE_RATE;
+ cbuf_init(&dm.mic0_cb, dm.mic0_buf, sizeof(dm.mic0_buf));
+ cbuf_init(&dm.mic1_cb, dm.mic1_buf, sizeof(dm.mic1_buf));
+ cbuf_init(&dm.mic2_cb, dm.mic2_buf, sizeof(dm.mic2_buf));
+ //cbuf_init(&dm.out_cb, dm.out_buf, sizeof(dm.out_buf));
+#if (AC_MIC_TYPE & AC_A_MIC)
+ audio_mic_pwr_ctl(MIC_PWR_ON);
+ audio_mic_init(dm.sr);
+#endif/*AC_MIC_TYPE*/
+
+#if (AC_MIC_TYPE & AC_D_MIC)
+ audio_pdm_mic_init(dm.sr);
+#endif/*AC_MIC_TYPE*/
+
+#if (AC_MIC_TYPE & AC_VAD_MIC)
+ /*VAD MIC数据先通过mic1通道导出*/
+ dm.vad_mic = audio_vad_mic_capture(dm.sr, &dm, adc_mic_output);
+#endif /*AC_VAD_MIC*/
+ memset(&de, 0, sizeof(data_export_t));
+#if SPP_SEND_BY_TIMER
+ de.send_timer = usr_timer_add(NULL, aec_export_timer, SPP_SEND_INTERVAL, 1);
+#endif/*SPP_SEND_BY_TIMER*/
+
+ dm_2_dac_open(dm.sr);
+ dm.state = AC_STATE_START;
+ AC_LOG("DataExport Start\n");
+ return 0;
+}
+
+void audio_capture_stop(void)
+{
+#if !(AC_MIC_TYPE & AC_VAD_MIC)
+ audio_mic_pwr_ctl(MIC_PWR_OFF);
+ audio_mic_close();
+#else
+ audio_vad_mic_stop_capture(dm.vad_mic);
+ dm.vad_mic = NULL;
+#endif
+ if (de.send_timer) {
+ usr_timeout_del(de.send_timer);
+ de.send_timer = 0;
+ }
+ dm.state = AC_STATE_STOP;
+ AC_LOG("DataExport Stop\n");
+}
+
+/*Noise Reduction/Suppression*/
+#include "commproc_ns.h"
+typedef struct {
+ u16 bypass;
+ s16 inbuf[DM_RUN_POINT];
+ s16 outbuf[320];
+ noise_suppress_param param;
+} audio_ns_t;
+audio_ns_t *audio_ns = NULL;
+
+static int audio_ns_run(s16 *in, s16 *out, u16 points)
+{
+ int out_points = 0;
+ if (audio_ns->bypass) {
+ out_points = points;
+ memcpy(out, in, (out_points << 1));
+ } else {
+ out_points = noise_suppress_run(in, out, points);
+ //printf(" <%d> ",out_points);
+ }
+ return (out_points << 1);
+}
+
+static int audio_ns_open(u16 sr)
+{
+ printf("audio_ns_open:%d\n", sr);
+
+ extern u32 aec_addr[], aec_begin[], aec_size[];
+ memcpy(aec_addr, aec_begin, (u32)aec_size) ;
+
+ audio_ns = zalloc(sizeof(audio_ns_t));
+ //audio_ns->bypass = 1;
+ audio_ns->param.wideband = 1;
+ audio_ns->param.mode = 1;
+ audio_ns->param.AggressFactor = 1.25f;
+ audio_ns->param.MinSuppress = 0.04f;
+ audio_ns->param.NoiseLevel = 2.2e4f;
+ noise_suppress_open(&audio_ns->param);
+ printf("audio_ns_open succ\n");
+ return 0;
+}
+
+static void audio_ns_close(void)
+{
+ if (audio_ns) {
+ noise_suppress_close();
+ free(audio_ns);
+ audio_ns = NULL;
+ }
+}
+
+extern int aec_uart_init();
+extern int aec_uart_fill(u8 ch, void *buf, u16 size);
+extern void aec_uart_write(void);
+extern int aec_uart_close(void);
+#define UART_EXPORT_MTU 512
+u8 uart_wbuf[UART_EXPORT_MTU];
+static void AudioCapture_Task(void *p)
+{
+ int ret = 0;
+ AC_LOG(">>>AudioCapture_Task<<<\n");
+
+ while (tone_get_status()) {
+ os_time_dly(2);
+ }
+
+ audio_capture_board_init();
+#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SD)
+ while (1) {
+ if ((dm.mic0_cb.data_len >= DM_RUN_SIZE) && (dm.mic1_cb.data_len >= DM_RUN_SIZE)) {
+ cbuf_read(&dm.mic0_cb, dm.mic0, DM_RUN_SIZE);
+ data_export_run(dm.mic0, DM_RUN_SIZE, 0);
+ cbuf_read(&dm.mic1_cb, dm.mic1, DM_RUN_SIZE);
+ data_export_run(dm.mic1, DM_RUN_SIZE, 1);
+ int out_points = DualMic_NoiseReduce_run(dm.mic0, dm.mic1, dm.output, DM_RUN_POINT);
+ data_export_run(dm.output, (out_points << 1), 2);
+ } else {
+ os_sem_pend(&dm.sem, 0);
+ }
+ }
+#elif (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_UART)
+ AC_LOG(">>>AudioCapture_Task[UART]<<<\n");
+ while (1) {
+ if (dm.mic0_cb.data_len >= UART_EXPORT_MTU) {
+ putchar('w');
+ ret = cbuf_read(&dm.mic0_cb, uart_wbuf, UART_EXPORT_MTU);
+ if (ret == UART_EXPORT_MTU) {
+ aec_uart_fill(0, uart_wbuf, UART_EXPORT_MTU); //主mic数据
+ putchar('0');
+ }
+ ret = cbuf_read(&dm.mic1_cb, uart_wbuf, UART_EXPORT_MTU);
+ if (ret == UART_EXPORT_MTU) {
+ aec_uart_fill(1, uart_wbuf, UART_EXPORT_MTU); //主mic数据
+ putchar('1');
+ }
+ ret = cbuf_read(&dm.mic2_cb, uart_wbuf, UART_EXPORT_MTU);
+ if (ret == UART_EXPORT_MTU) {
+ aec_uart_fill(2, uart_wbuf, UART_EXPORT_MTU); //主mic数据
+ putchar('2');
+ }
+ aec_uart_write();
+ } else {
+ os_sem_pend(&dm.sem, 0);
+ }
+ }
+#else
+ while (1) {
+ os_sem_pend(&dm.sem, 0);
+
+ //do ans here:
+ if (audio_ns) {
+ if (cbuf_read(&dm.mic1_cb, audio_ns->inbuf, DM_RUN_SIZE) == DM_RUN_SIZE) {
+ cbuf_write(&dm.mic0_cb, audio_ns->inbuf, DM_RUN_SIZE);
+ int out_size = audio_ns_run(audio_ns->inbuf, audio_ns->outbuf, DM_RUN_POINT);
+#if DM_2_DAC_EN
+ ret = audio_dac_write(&dac_hdl, audio_ns->outbuf, out_size);
+#endif /*DM_2_DAC_EN*/
+ ret = cbuf_write(&dm.out_cbuf, audio_ns->outbuf, out_size);
+ if (ret != out_size) {
+ AC_LOG("NS output full\n");
+ }
+ }
+ }
+
+#if (SPP_SEND_BY_TIMER == 0)
+ spp_data_export_run();
+#endif
+ }
+#endif
+}
+
+int audio_capture_init(void)
+{
+ AC_LOG("Audio Capture init\n");
+ os_sem_create(&dm.sem, 0);
+ task_create(AudioCapture_Task, NULL, "aud_capture");
+ return 0;
+}
+
+int audio_capture_exit()
+{
+ return 0;
+}
+
+#endif
diff --git a/cpu/br28/audio_capture.h b/cpu/br28/audio_capture.h
new file mode 100644
index 0000000..6b8552a
--- /dev/null
+++ b/cpu/br28/audio_capture.h
@@ -0,0 +1,9 @@
+#ifndef _AUDIO_CAPTURE_H_
+#define _AUDIO_CAPTURE_H_
+
+#include "generic/typedef.h"
+
+int audio_capture_init(void);
+int audio_capture_exit(void);
+
+#endif/*_AUDIO_CAPTURE_H_*/
diff --git a/cpu/br28/audio_codec_clock.c b/cpu/br28/audio_codec_clock.c
new file mode 100644
index 0000000..998553b
--- /dev/null
+++ b/cpu/br28/audio_codec_clock.c
@@ -0,0 +1,374 @@
+/*****************************************************************
+>file name : audio_codec_clock.c
+>create time : Thu 03 Jun 2021 09:36:12 AM CST
+>History :
+ 2021-11-19 : 增加后台叠加时钟的配置,用于满足一些后台运行的
+ 音频处理
+*****************************************************************/
+#define LOG_TAG "[CODEC_CLK]"
+#define LOG_INFO_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_DUMP_ENABLE
+#define LOG_ERROR_ENABLE
+#define LOG_WARN_ENABLE
+#include "debug.h"
+#include "app_config.h"
+#include "system/includes.h"
+#include "audio_codec_clock.h"
+#include "audio_dec_eff.h"
+#include "asm/dac.h"
+#include "avctp_user.h"
+
+#define AUDIO_CODING_ALL (0xffffffff)
+#define MAX_CODING_TYPE_NUM 4 //可根据模式的解码格式需求扩展
+#define AUDIO_CODEC_BASE_CLK SYS_24M
+
+static LIST_HEAD(codec_clock_head);
+
+struct audio_codec_clock {
+ u32 coding_type;
+ u32 clk;
+ u8 background; //后台运行的时钟
+};
+
+struct audio_codec_clk_context {
+ u8 mode;
+ struct audio_codec_clock params;
+ struct list_head entry;
+};
+
+#define SYS_60M SYS_64M
+const struct audio_codec_clock audio_clock[AUDIO_MAX_MODE][MAX_CODING_TYPE_NUM] = {
+ {
+ //A2DP_MODE
+ {
+ AUDIO_CODING_SBC,
+#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG || defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE
+ SYS_76M,
+#elif (AUDIO_SURROUND_CONFIG && (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)) || (defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE)
+ SYS_76M,
+#elif (TCFG_BT_MUSIC_EQ_ENABLE && ((EQ_SECTION_MAX >= 10) && AUDIO_OUT_EFFECT_ENABLE)) || (AUDIO_VBASS_CONFIG || AUDIO_SURROUND_CONFIG)
+ SYS_60M,
+#elif (TCFG_BT_MUSIC_EQ_ENABLE && ((EQ_SECTION_MAX >= 10) || AUDIO_OUT_EFFECT_ENABLE) || TCFG_DRC_ENABLE || TCFG_AUDIO_ANC_ENABLE || TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
+ SYS_48M,
+#else
+ SYS_32M,
+#endif
+ },
+ {
+ AUDIO_CODING_AAC,
+
+#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
+ SYS_96M,
+#else
+#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG || AUDIO_VBASS_CONFIG || defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE
+ SYS_76M,
+#elif (AUDIO_SURROUND_CONFIG && (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR))|| (defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE)
+ SYS_64M,
+#elif (TCFG_BT_MUSIC_EQ_ENABLE && ((EQ_SECTION_MAX >= 10) || AUDIO_OUT_EFFECT_ENABLE)) || AUDIO_SURROUND_CONFIG || TCFG_DRC_ENABLE
+#if (TCFG_AUDIO_ANC_ENABLE)
+ SYS_64M,
+#else
+ SYS_60M,
+#endif /*TCFG_AUDIO_ANC_ENABLE*/
+#else
+ SYS_48M,
+#endif
+#endif
+ },
+ {
+ AUDIO_CODING_LDAC,
+#if (AUDIO_SURROUND_CONFIG && (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR))|| (defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE)
+ SYS_128M,
+#elif (TCFG_BT_MUSIC_EQ_ENABLE && ((EQ_SECTION_MAX >= 10) || AUDIO_OUT_EFFECT_ENABLE)) | (AUDIO_VBASS_CONFIG || AUDIO_SURROUND_CONFIG) || TCFG_DRC_ENABLE
+#if (TCFG_AUDIO_ANC_ENABLE)
+ SYS_128M,
+#else
+ SYS_128M,
+#endif /*TCFG_AUDIO_ANC_ENABLE*/
+#else
+#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
+ SYS_128M,
+#else
+ SYS_128M,
+#endif /*TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR*/
+#endif
+ }
+ },
+
+ {
+ //ESCO MODE
+ {
+ AUDIO_CODING_MSBC,
+#if TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR
+#if (TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE)
+ SYS_76M,
+#else /*TCFG_AUDIO_CVP_NS_MODE == CVP_DNS_MODE*/
+ SYS_96M,
+#endif /*TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE*/
+#else
+ /* SYS_48M, */
+ 0,
+#endif
+ },
+ {AUDIO_CODING_CVSD, 0},
+ },
+
+ {
+ //TONE MODE
+ {AUDIO_CODING_AAC | AUDIO_CODING_WAV | AUDIO_CODING_WTGV2 | AUDIO_CODING_MP3, SYS_64M},
+ {AUDIO_CODING_ALL, 0},
+ },
+
+ {
+ //FILE MODE
+ {AUDIO_CODING_ALL, 120 * 1000000L},
+ },
+
+ {
+ //PC MODE
+ {AUDIO_CODING_ALL, 96 * 1000000L},
+ },
+
+ {
+ //USB MIC MODE
+#if (TCFG_CVP_DEVELOP_ENABLE == CVP_CFG_AIS_3MIC)
+ {AUDIO_CODING_ALL, 128 * 1000000L},
+#else
+ {AUDIO_CODING_ALL, 96 * 1000000L},
+#endif
+ },
+
+ {
+ //VAD MODE
+ {AUDIO_CODING_ALL, SYS_32M, 1},
+ },
+
+ {
+ //SPATIAL EFFECT MODE
+#if ((defined TCFG_AUDIO_EFFECT_TASK_EBABLE) && TCFG_AUDIO_EFFECT_TASK_EBABLE)
+ {AUDIO_CODING_ALL, SYS_32M, 1},
+#else
+ {AUDIO_CODING_ALL, SYS_120M, 1},
+#endif /*TCFG_AUDIO_EFFECT_TASK_EBABLE*/
+ },
+ {
+ // SPEAK_TO_CHAT_MODE
+ {AUDIO_CODING_ALL, 48 * 1000000L}
+ },
+
+ {
+ // ANC_EAR_ADAPTIVE_MODE
+ {AUDIO_CODING_ALL, SYS_160M, 0}
+ },
+
+ {
+ // ANC_DUT_SZ_FFT_MODE
+ {AUDIO_CODING_ALL, SYS_120M, 0}
+ },
+ //TODO
+};
+
+static u32 audio_codec_background_clock(void)
+{
+ struct audio_codec_clk_context *ctx;
+ u32 clk = 0;
+
+ if (list_empty(&codec_clock_head)) {
+ return 0;
+ }
+ list_for_each_entry(ctx, &codec_clock_head, entry) {
+ if (ctx->params.background) {
+ clk += ctx->params.clk;
+ }
+ }
+
+ return clk;
+}
+
+static void audio_codec_background_clock_add(u32 clk)
+{
+ struct audio_codec_clk_context *ctx;
+
+ if (list_empty(&codec_clock_head)) {
+ return;
+ }
+ list_for_each_entry(ctx, &codec_clock_head, entry) {
+ ctx->params.clk += clk;
+ }
+}
+
+static void audio_codec_background_clock_del(u32 clk)
+{
+ struct audio_codec_clk_context *ctx;
+
+ if (list_empty(&codec_clock_head)) {
+ return;
+ }
+
+ list_for_each_entry(ctx, &codec_clock_head, entry) {
+ ctx->params.clk -= clk;
+ }
+}
+
+static bool audio_codec_mode_exist(u8 mode)
+{
+ struct audio_codec_clk_context *ctx;
+
+ if (list_empty(&codec_clock_head)) {
+ return false;
+ }
+
+ list_for_each_entry(ctx, &codec_clock_head, entry) {
+ if (ctx->mode == mode) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+int audio_codec_clock_set(u8 mode, u32 coding_type, u8 preemption)
+{
+ u32 new_clk = 0;
+ u32 background_clk = 0;
+
+ if (mode >= AUDIO_MAX_MODE) {
+ log_error("Not support this mode : %d", mode);
+ return -EINVAL;
+ }
+
+ if (audio_codec_mode_exist(mode)) {
+ return 0;
+ }
+ const struct audio_codec_clock *params = audio_clock[mode];
+ int i = 0;
+
+ for (i = 0; i < MAX_CODING_TYPE_NUM; i++) {
+ if (params[i].coding_type & coding_type) {
+ goto match_clock;
+ }
+ }
+
+ log_error("Not found right coding type : %d", coding_type);
+ return -EINVAL;
+
+match_clock:
+ if (params[i].background) {
+ /*如果是后台运行的,则需要处理最终时钟为前台+后台时钟总和*/
+ audio_codec_background_clock_add(params[i].clk);
+ new_clk = params[i].clk;
+ struct audio_codec_clk_context *first = list_empty(&codec_clock_head) ? NULL : list_first_entry(&codec_clock_head, struct audio_codec_clk_context, entry);
+ if (first) {
+ new_clk = first->params.clk;
+ } else {
+ /*后台运行时钟比较接近负载极限,容易导致其他跑不过来,因此多加12M*/
+ new_clk += 12 * 1000000L;
+ }
+ goto clock_set;
+ }
+
+ background_clk = audio_codec_background_clock();
+ new_clk = (params[i].clk ? params[i].clk : clk_get("sys")) + background_clk;
+ if (!preemption) {
+ struct audio_codec_clk_context *ctx1;
+ if (!list_empty(&codec_clock_head)) {
+ ctx1 = list_first_entry(&codec_clock_head, struct audio_codec_clk_context, entry);
+ if (ctx1 && !ctx1->params.background) {
+ if (new_clk <= ctx1->params.clk) {
+ /*叠加解码的时钟不可小于在播放的音频时钟*/
+ new_clk = ctx1->params.clk + 12 * 1000000;
+ } else {
+ new_clk += 32 * 1000000;
+ }
+ }
+ }
+ }
+
+clock_set:
+ struct audio_codec_clk_context *ctx = (struct audio_codec_clk_context *)zalloc(sizeof(struct audio_codec_clk_context));
+ ctx->mode = mode;
+ ctx->params.coding_type = coding_type;
+ ctx->params.background = params[i].background;
+ ctx->params.clk = ctx->params.background ? params[i].clk : new_clk;
+ clk_set("sys", new_clk);
+ if (ctx->params.background) {
+ list_add_tail(&ctx->entry, &codec_clock_head);
+ } else {
+ list_add(&ctx->entry, &codec_clock_head);
+ }
+
+ return 0;
+}
+
+void audio_codec_clock_del(u8 mode)
+{
+ struct audio_codec_clk_context *ctx;
+ int next_clk = 0;
+ u32 remove_clk = 0;
+
+ list_for_each_entry(ctx, &codec_clock_head, entry) {
+ if (ctx->mode == mode) {
+ goto clock_del;
+ }
+ }
+
+ return;
+clock_del:
+ list_del(&ctx->entry);
+ if (ctx->params.background) {
+ audio_codec_background_clock_del(ctx->params.clk);
+ remove_clk = ctx->params.clk;
+ }
+ free(ctx);
+
+ if (!list_empty(&codec_clock_head)) {
+ ctx = list_first_entry(&codec_clock_head, struct audio_codec_clk_context, entry);
+ if (ctx) {
+ next_clk = ctx->params.clk;
+ }
+ } else {
+ u32 current_clk = clk_get("sys");
+#if (TCFG_BD_NUM == 2)&&(TCFG_BT_SUPPORT_AAC==1)
+ if ((mode == AUDIO_A2DP_MODE) && (get_total_connect_dev() > 1)) {
+ next_clk = current_clk - remove_clk;
+ } else {
+ if (remove_clk) {
+ next_clk = current_clk - remove_clk;
+ } else {
+ next_clk = AUDIO_CODEC_BASE_CLK; //不是后台时钟,设置音频基础时钟
+ }
+ }
+#else
+ if (remove_clk) {
+ next_clk = current_clk - remove_clk;
+ } else {
+ next_clk = AUDIO_CODEC_BASE_CLK; //不是后台时钟,设置音频基础时钟
+ }
+#endif
+ }
+
+ if (!next_clk || next_clk < AUDIO_CODEC_BASE_CLK) {
+ next_clk = list_empty(&codec_clock_head) ? clk_get("sys") : AUDIO_CODEC_BASE_CLK;
+ }
+ clk_set("sys", next_clk);
+}
+
+void audio_codec_clock_check(void)
+{
+ struct audio_codec_clk_context *ctx;
+
+ if (!list_empty(&codec_clock_head)) {
+ ctx = list_first_entry(&codec_clock_head, struct audio_codec_clk_context, entry);
+ if (!ctx) {
+ return;
+ }
+
+ u32 current_clk = clk_get("sys");
+ u32 expect_clk = ctx->params.background ? (ctx->params.clk + 12 * 1000000L) : ctx->params.clk;
+ if ((current_clk < 192 * 1000000L) && current_clk < expect_clk) {
+ log_error("Audio codec clock error : %dM, %dM.", current_clk / 1000000, expect_clk / 1000000);
+ clk_set("sys", expect_clk);
+ }
+ }
+}
diff --git a/cpu/br28/audio_codec_clock.h b/cpu/br28/audio_codec_clock.h
new file mode 100644
index 0000000..ec78132
--- /dev/null
+++ b/cpu/br28/audio_codec_clock.h
@@ -0,0 +1,55 @@
+/*****************************************************************
+>file name : audio_codec_clock.h
+>create time : Thu 03 Jun 2021 09:36:25 AM CST
+*****************************************************************/
+#ifndef _AUDIO_CODEC_CLOCK_H_
+#define _AUDIO_CODEC_CLOCK_H_
+#include "audio_base.h"
+
+enum {
+ AUDIO_A2DP_MODE = 0,
+ AUDIO_ESCO_MODE,
+ AUDIO_TONE_MODE,
+ AUDIO_FILE_MODE,
+ AUDIO_PC_MODE,
+ AUDIO_USB_MIC_MODE,
+ SMART_VOICE_MODE,
+ SPATIAL_EFFECT_MODE,
+ SPEAK_TO_CHAT_MODE,
+ ANC_EAR_ADAPTIVE_MODE,
+ ANC_DUT_SZ_FFT_MODE,
+ AUDIO_MAX_MODE,
+};
+
+
+/*************************************************************************
+ * 音频编解码时钟设置
+ *
+ * Input : mode - 音频模式,coding_type - 模式下的解码格式
+ * preemption - 打断/叠加.
+ * Output : 0 - 成功, 非0 - 出错.
+ * Notes : 目前在耳机SDK用于A2DP/ESCO/TONE三个模式的时钟切换.
+ * History : 2021/06/03 初始版本
+ *=======================================================================*/
+int audio_codec_clock_set(u8 mode, u32 coding_type, u8 preemption);
+
+/*************************************************************************
+ * 音频编解码时钟删除
+ *
+ * Input : mode - 音频模式
+ * Output : 无.
+ * Notes : 需和audio_codec_clock_set结对使用.
+ * History : 2021/06/03 初始版本
+ *=======================================================================*/
+void audio_codec_clock_del(u8 mode);
+
+/*************************************************************************
+ * 音频编解码时钟检查
+ *
+ * Input : 无
+ * Output : 无.
+ * Notes : 检查音频使用中是否有时钟被修改的情况并报错
+ * History : 2021/11/18
+ *=======================================================================*/
+void audio_codec_clock_check(void);
+#endif
diff --git a/cpu/br28/audio_common/audio_mic_codec.c b/cpu/br28/audio_common/audio_mic_codec.c
new file mode 100644
index 0000000..7bc3ae7
--- /dev/null
+++ b/cpu/br28/audio_common/audio_mic_codec.c
@@ -0,0 +1,304 @@
+#include "asm/includes.h"
+#include "media/includes.h"
+#include "system/includes.h"
+#include "classic/hci_lmp.h"
+#include "aec_user.h"
+#include "asm/audio_src.h"
+#include "audio_enc.h"
+#if TCFG_AUDIO_ANC_ENABLE
+#include "audio_anc.h"
+#endif
+#include "app_main.h"
+#include "btstack/avctp_user.h"
+
+#if (TCFG_ENC_OPUS_ENABLE) || (TCFG_ENC_SPEEX_ENABLE)
+
+extern struct audio_encoder_task *encode_task;
+//static struct audio_encoder_task *encode_task = NULL;
+
+#define ENC_ADC_BUF_NUM (2)
+#if TCFG_AUDIO_ANC_ENABLE
+//JL701N打开ANC,ADC需要使用相同buffer和中断点数
+#define ENC_ADC_IRQ_POINTS (256)
+#else
+#define ENC_ADC_IRQ_POINTS (320)
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+#define ENC_ADC_BUFS_SIZE (ENC_ADC_BUF_NUM * ENC_ADC_IRQ_POINTS)
+
+#define MIC_USE_MIC_CHANNEL (1)
+#define MIC_ENC_IN_SIZE (ENC_ADC_IRQ_POINTS * 2)
+#define MIC_ENC_OUT_SIZE (ENC_ADC_IRQ_POINTS)
+
+struct mic_enc_hdl {
+ struct audio_encoder encoder;
+ OS_SEM pcm_frame_sem;
+ u8 output_frame[MIC_ENC_OUT_SIZE];
+ u8 pcm_frame[MIC_ENC_IN_SIZE];
+ u8 frame_size;
+ u8 in_cbuf_buf[MIC_ENC_IN_SIZE * 4];
+ cbuffer_t pcm_in_cbuf;
+ int (*mic_output)(void *priv, void *buf, int len);
+#if mic_ENC_PACK_ENABLE
+ u16 cp_type;
+ u16 packet_head_sn;
+#endif
+#if MIC_USE_MIC_CHANNEL
+ struct audio_adc_output_hdl adc_output;
+ struct adc_mic_ch mic_ch;
+ s16 adc_buf[ENC_ADC_BUFS_SIZE]; //align 4Bytes
+#endif
+};
+
+static struct mic_enc_hdl *mic_enc = NULL;
+
+static void mic_enc_output_func_register(int (*output_func)(void *priv, void *buf, int len))
+{
+ if (mic_enc) {
+ mic_enc->mic_output = output_func;
+ }
+}
+
+void mic_enc_resume(void)
+{
+ if (mic_enc) {
+ os_sem_post(&mic_enc->pcm_frame_sem);
+ }
+}
+
+static int mic_enc_pcm_get(struct audio_encoder *encoder, s16 **frame, u16 frame_len)
+{
+ int pcm_len = 0;
+ if (mic_enc == NULL) {
+ r_printf("mic_enc NULL\n");
+ return 0;
+ }
+
+
+ /* putchar('!'); */
+ if ((&mic_enc->pcm_in_cbuf)->data_len < frame_len) {
+ /* putchar('#'); */
+ os_sem_set(&mic_enc->pcm_frame_sem, 0);
+ os_sem_pend(&mic_enc->pcm_frame_sem, 5);
+ if (mic_enc == NULL) {
+ printf("mic_enc is NULL\n");
+ return 0;
+ }
+ }
+
+ pcm_len = cbuf_read(&mic_enc->pcm_in_cbuf, mic_enc->pcm_frame, frame_len);
+ if (pcm_len != frame_len) {
+ putchar('L');
+ }
+ /* putchar('D'); */
+
+ *frame = mic_enc->pcm_frame;
+ return pcm_len;
+}
+
+static void mic_enc_pcm_put(struct audio_encoder *encoder, s16 *frame)
+{
+}
+
+static const struct audio_enc_input mic_enc_input = {
+ .fget = mic_enc_pcm_get,
+ .fput = mic_enc_pcm_put,
+};
+
+static int mic_enc_probe_handler(struct audio_encoder *encoder)
+{
+ return 0;
+}
+
+
+
+
+static int mic_enc_output_handler(struct audio_encoder *encoder, u8 *frame, int len)
+{
+ if (encoder == NULL) {
+ r_printf("encoder NULL");
+ }
+ wdt_clear();
+ /* printf("mic frame len:%d \n",len); */
+ if (mic_enc && mic_enc->mic_output) {
+ mic_enc->mic_output(NULL, frame, len);
+ }
+ /* put_buf(frame, 16); */
+ return len;
+}
+
+const static struct audio_enc_handler mic_enc_handler = {
+ .enc_probe = mic_enc_probe_handler,
+ .enc_output = mic_enc_output_handler,
+};
+
+static void mic_enc_event_handler(struct audio_decoder *decoder, int argc, int *argv)
+{
+ printf("mic_enc_event_handler:0x%x,%d\n", argv[0], argv[0]);
+ switch (argv[0]) {
+ case AUDIO_ENC_EVENT_END:
+ puts("AUDIO_ENC_EVENT_END\n");
+ break;
+ }
+}
+
+
+
+static void adc_mic_output_handler(void *priv, s16 *data, int len)
+{
+ if (mic_enc) {
+ u16 wlen = cbuf_write(&mic_enc->pcm_in_cbuf, data, len);
+ if (wlen != len) {
+ putchar('@');
+ }
+ audio_encoder_resume(&mic_enc->encoder);
+ mic_enc_resume();
+ }
+}
+
+
+
+#define HIGHT_COMPLEX 0
+#define LOW_COMPLEX (BIT(4))
+
+
+extern struct audio_adc_hdl adc_hdl;
+int audio_mic_enc_open(int (*mic_output)(void *priv, void *buf, int len), u32 code_type, u8 ai_type)
+{
+ int err;
+ struct audio_fmt fmt;
+
+ switch (code_type) {
+ case AUDIO_CODING_OPUS:
+ //1. quality:bitrate 0:16kbps 1:32kbps 2:64kbps
+ // quality: MSB_2:(bit7_bit6) format_mode //0:百度_无头. 1:酷狗_eng+range.
+ // quality:LMSB_2:(bit5_bit4) low_complexity //0:高复杂度,高质量.兼容之前库. 1:低复杂度,低质量.
+ //2. sample_rate sample_rate=16k ignore
+ fmt.quality = 0 | ai_type/*| LOW_COMPLEX*/;
+ fmt.sample_rate = 16000;
+ fmt.coding_type = AUDIO_CODING_OPUS;
+ break;
+ case AUDIO_CODING_SPEEX:
+ fmt.quality = 5;
+ fmt.complexity = 2;
+ fmt.sample_rate = 16000;
+ fmt.coding_type = AUDIO_CODING_SPEEX;
+ break;
+ default:
+ printf("do not support this type !!!\n");
+ return -1;
+ break;
+ }
+
+ if (!encode_task) {
+ encode_task = zalloc(sizeof(*encode_task));
+ if (!encode_task) {
+ printf("encode_task NULL !!!\n");
+ }
+ audio_encoder_task_create(encode_task, "audio_enc");
+ }
+ if (!mic_enc) {
+ mic_enc = zalloc(sizeof(*mic_enc));
+ if (!mic_enc) {
+ printf("mic_enc NULL !!!\n");
+ }
+ memset(mic_enc, 0x00, sizeof(*mic_enc));
+ }
+
+ mic_enc_output_func_register(mic_output);
+ cbuf_init(&mic_enc->pcm_in_cbuf, mic_enc->in_cbuf_buf, MIC_ENC_IN_SIZE * 4);
+ os_sem_create(&mic_enc->pcm_frame_sem, 0);
+ audio_encoder_open(&mic_enc->encoder, &mic_enc_input, encode_task);
+ audio_encoder_set_handler(&mic_enc->encoder, &mic_enc_handler);
+ audio_encoder_set_fmt(&mic_enc->encoder, &fmt);
+ audio_encoder_set_event_handler(&mic_enc->encoder, mic_enc_event_handler, 0);
+ audio_encoder_set_output_buffs(&mic_enc->encoder, mic_enc->output_frame,
+ sizeof(mic_enc->output_frame), 1);
+ if (!mic_enc->encoder.enc_priv) {
+ log_e("encoder err, maybe coding(0x%x) disable \n", fmt.coding_type);
+ err = -EINVAL;
+ goto __err;
+ }
+
+ int start_err = audio_encoder_start(&mic_enc->encoder);
+
+#if MIC_USE_MIC_CHANNEL
+ fmt.sample_rate = 16000;
+ audio_mic_pwr_ctl(MIC_PWR_ON);
+ audio_adc_mic_open(&mic_enc->mic_ch, BIT(0), &adc_hdl);
+ audio_adc_mic_set_sample_rate(&mic_enc->mic_ch, fmt.sample_rate);
+#if TCFG_AUDIO_ANC_ENABLE
+ app_var.aec_mic_gain = audio_anc_ffmic_gain_get();
+#endif
+ printf(">>>>>>>>>mic gain:%d \n", app_var.aec_mic_gain);
+ audio_adc_mic_set_gain(&mic_enc->mic_ch, app_var.aec_mic_gain);
+
+#if TCFG_AUDIO_ANC_ENABLE
+ //JL701N打开ANC,ADC需要使用相同buffer和中断点数
+ extern s16 esco_adc_buf[];
+ audio_adc_mic_set_buffs(&mic_enc->mic_ch, esco_adc_buf,
+ ENC_ADC_IRQ_POINTS * 2, ENC_ADC_BUF_NUM);
+#else
+ audio_adc_mic_set_buffs(&mic_enc->mic_ch, mic_enc->adc_buf,
+ ENC_ADC_IRQ_POINTS * 2, ENC_ADC_BUF_NUM);
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+ mic_enc->adc_output.handler = adc_mic_output_handler;
+ audio_adc_add_output_handler(&adc_hdl, &mic_enc->adc_output);
+
+
+ //app_audio_output_samplerate_set(44100);
+ //app_audio_output_start();
+ audio_adc_mic_start(&mic_enc->mic_ch);
+#endif
+
+ printf("mic_enc_open ok %d\n", start_err);
+
+
+ return 0;
+__err:
+ audio_encoder_close(&mic_enc->encoder);
+
+ local_irq_disable();
+ free(mic_enc);
+ mic_enc = NULL;
+ local_irq_enable();
+
+ return err;
+}
+
+
+
+
+int audio_mic_enc_close()
+{
+ if (!mic_enc) {
+ return -1;
+ }
+ printf("audio_mic_enc_close\n");
+#if MIC_USE_MIC_CHANNEL
+ audio_adc_mic_close(&mic_enc->mic_ch);
+#if TCFG_AUDIO_ANC_ENABLE
+ if (anc_status_get() == 0) {
+ audio_mic_pwr_ctl(MIC_PWR_OFF);
+ }
+#else
+ audio_mic_pwr_ctl(MIC_PWR_OFF);
+#endif
+ audio_adc_del_output_handler(&adc_hdl, &mic_enc->adc_output);
+#endif
+ mic_enc_resume();
+ audio_encoder_close(&mic_enc->encoder);
+
+ /* if (encode_task) { */
+ /* audio_encoder_task_del(encode_task); */
+ /* free(encode_task); */
+ /* encode_task = NULL; */
+ /* } */
+
+ free(mic_enc);
+ mic_enc = NULL;
+
+ printf("audio_mic_enc_close end\n");
+ return 0;
+}
+
+#endif
diff --git a/cpu/br28/audio_config.h b/cpu/br28/audio_config.h
new file mode 100644
index 0000000..cdf383f
--- /dev/null
+++ b/cpu/br28/audio_config.h
@@ -0,0 +1,208 @@
+#ifndef _APP_AUDIO_H_
+#define _APP_AUDIO_H_
+
+#include "generic/typedef.h"
+#include "board_config.h"
+
+#if BT_SUPPORT_MUSIC_VOL_SYNC
+#define TCFG_MAX_VOL_PROMPT 0
+#else
+#define TCFG_MAX_VOL_PROMPT 0
+#endif
+
+//*********************************************************************************//
+// USB Audio配置 //
+//*********************************************************************************//
+/*usb mic的数据是否经过CVP,包括里面的回音消除(AEC)、非线性回音压制(NLP)、降噪(ANS)模块*/
+#define TCFG_USB_MIC_CVP_ENABLE DISABLE_THIS_MOUDLE
+#define TCFG_USB_MIC_CVP_MODE (ANS_EN | NLP_EN)
+
+//*********************************************************************************//
+// CVP配置 //
+//*********************************************************************************//
+//麦克风阵列校准使能
+#define TCFG_AUDIO_MIC_ARRAY_TRIM_ENABLE 0
+
+//上行同步使能
+//#define TCFG_AUDIO_CVP_SYNC 0
+
+/*
+ *该配置适用于没有音量按键的产品,防止打开音量同步之后
+ *连接支持音量同步的设备,将音量调小过后,连接不支持音
+ *量同步的设备,音量没有恢复,导致音量小的问题
+ */
+#define TCFG_VOL_RESET_WHEN_NO_SUPPORT_VOL_SYNC 0 //不支持音量同步的设备默认最大音量
+
+#define MC_BIAS_ADJUST_DISABLE 0 //省电容mic偏置校准关闭
+#define MC_BIAS_ADJUST_ONE 1 //省电容mic偏置只校准一次(跟dac trim一样)
+#define MC_BIAS_ADJUST_POWER_ON 2 //省电容mic偏置每次上电复位都校准(Power_On_Reset)
+#define MC_BIAS_ADJUST_ALWAYS 3 //省电容mic偏置每次开机都校准(包括上电复位和其他复位)
+/*
+ *省电容mic偏置电压自动调整(因为校准需要时间,所以有不同的方式)
+ *1、烧完程序(完全更新,包括配置区)开机校准一次
+ *2、上电复位的时候都校准,即断电重新上电就会校准是否有偏差(默认)
+ *3、每次开机都校准,不管有没有断过电,即校准流程每次都跑
+ */
+#define TCFG_MC_BIAS_AUTO_ADJUST MC_BIAS_ADJUST_DISABLE
+
+#define TCFG_ESCO_PLC 0 //通话丢包修复
+#define TCFG_AEC_ENABLE 0 //通话回音消除使能
+#define TCFG_AUDIO_CONFIG_TRACE 0 //音频模块配置跟踪查看
+#define TCFG_DIG_PHASE_INVERTER_EN 0 //数字反相器,用来矫正DAC的输出相位(AC701N输出正相,默认关)
+
+
+#define MAX_ANA_VOL (3) //系统最大模拟音量 (0-3)
+#define MAX_COM_VOL (10) // 具体数值应小于联合音量等级的数组大小 (combined_vol_list)
+#define MAX_DIG_VOL (10)
+
+/*
+ 数字音量等级表生成参数(软件数字音量和硬件数字音量共用两个参数)
+ 修改 DIG_VOL_MAX_VALUE 也要留意一下 DIG_VOL_STEP 参数,避免在小音量等级时候音量太小。
+*/
+#if TCFG_AUDIO_HEARING_AID_ENABLE
+#define DIG_VOL_MAX_VALUE (0.0f) // 数字音量最大值(单位:dB)
+#elif (TCFG_AUDIO_DAC_MODE == DAC_MODE_L_DIFF)
+#define DIG_VOL_MAX_VALUE (-5.0f) // 数字音量最大值(单位:dB)
+#elif (TCFG_AUDIO_DAC_MODE == DAC_MODE_H1_DIFF)
+#define DIG_VOL_MAX_VALUE (-8.0f) // 数字音量最大值(单位:dB)
+#else
+#define DIG_VOL_MAX_VALUE (0.0f) // 数字音量最大值(单位:dB)
+#endif
+#define DIG_VOL_STEP (3.0f) // 逐级递减差值(单位:dB)
+
+/*
+ *ANC下,当数字音量大于-6dB时,会导致播歌失真,以下任意一种方式都可解决, SDK默认第一种
+ *1、数字音量限制在-6dB以下
+ *2、开启音乐动态增益ANC_MUSIC_DYNAMIC_GAIN_EN
+ */
+#if (TCFG_AUDIO_ANC_ENABLE)
+#define ANC_MODE_DIG_VOL_LIMIT (-6.0f)
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+
+/*
+ *软件数字音量表自定义
+ * 0:使用软件数字音量文件中的默认数组
+ * 1:按上面设置的参数重新生成
+ */
+#define SW_DIG_VOL_TAB_USER_DEFINED 0
+
+#if ((SYS_VOL_TYPE == VOL_TYPE_DIGITAL) || (SYS_VOL_TYPE == VOL_TYPE_DIGITAL_HW))
+#define SYS_MAX_VOL MAX_DIG_VOL
+#define SYS_DEFAULT_VOL 0//SYS_MAX_VOL
+#define SYS_DEFAULT_TONE_VOL 0
+#define SYS_DEFAULT_SIN_VOL 0
+
+#elif (SYS_VOL_TYPE == VOL_TYPE_AD)
+#define SYS_MAX_VOL MAX_COM_VOL
+#define SYS_DEFAULT_VOL SYS_MAX_VOL
+#define SYS_DEFAULT_TONE_VOL 14
+#define SYS_DEFAULT_SIN_VOL 8
+#else
+#error "SYS_VOL_TYPE define error"
+#endif
+
+
+
+/*数字音量最大值定义*/
+#define DEFAULT_DIGITAL_VOLUME 16384
+
+
+#define BT_MUSIC_VOL_LEAVE_MAX 16 /*高级音频音量等级*/
+#define BT_MUSIC_VOL_STEP (-3.0f) /*高级音频音量等级衰减步进*/
+#define BT_CALL_VOL_LEAVE_MAX 15 /*通话音量等级*/
+#define BT_CALL_VOL_STEP (-2.0f) /*通话音量等级衰减步进*/
+
+
+/*
+ *audio state define
+ */
+#define APP_AUDIO_STATE_IDLE 0
+#define APP_AUDIO_STATE_MUSIC 1
+#define APP_AUDIO_STATE_CALL 2
+#define APP_AUDIO_STATE_WTONE 3
+#define APP_AUDIO_STATE_LINEIN 4
+#define APP_AUDIO_CURRENT_STATE 5
+
+#define APP_AUDIO_MAX_STATE (APP_AUDIO_CURRENT_STATE + 1)
+
+
+#define AUDIO_OUTPUT_INCLUDE_BT ((defined(AUDIO_OUTPUT_WAY)) && (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_BT)) \
+ || ((defined(AUDIO_OUT_WAY_TYPE)) && (AUDIO_OUT_WAY_TYPE & AUDIO_WAY_TYPE_BT))
+
+
+#define AUDIO_OUTPUT_INCLUDE_FM ((defined(AUDIO_OUTPUT_WAY)) && (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_FM)) \
+ || ((defined(AUDIO_OUT_WAY_TYPE)) && (AUDIO_OUT_WAY_TYPE & AUDIO_WAY_TYPE_FM))
+
+
+#if TCFG_MIC_EFFECT_ENABLE
+#define TCFG_AUDIO_DAC_MIX_ENABLE (1)
+#define TCFG_AUDIO_DAC_MIX_SAMPLE_RATE (TCFG_REVERB_SAMPLERATE_DEFUAL)
+#elif (TCFG_AD2DA_LOW_LATENCY_ENABLE || TCFG_AUDIO_HEARING_AID_ENABLE)
+#define TCFG_AUDIO_DAC_MIX_ENABLE (1)
+#define TCFG_AUDIO_DAC_MIX_SAMPLE_RATE (TCFG_AD2DA_LOW_LATENCY_SAMPLE_RATE)
+#elif TCFG_SIDETONE_ENABLE
+#define TCFG_AUDIO_DAC_MIX_ENABLE (1)
+#define TCFG_AUDIO_DAC_MIX_SAMPLE_RATE (44100)
+#else
+#define TCFG_AUDIO_DAC_MIX_ENABLE (0)
+#define TCFG_AUDIO_DAC_MIX_SAMPLE_RATE (44100)
+#endif
+
+u8 get_max_sys_vol(void);
+u8 get_tone_vol(void);
+
+s8 app_audio_get_volume(u8 state);
+s8 app_audio_get_volume_r(u8 state);
+void app_audio_set_volume(u8 state, s8 volume, u8 fade);
+void app_audio_set_volume_each_channel(u8 state, s8 volume_l, s8 volume_r, u8 fade);
+void app_audio_volume_up(u8 value);
+void app_audio_volume_down(u8 value);
+void app_audio_volume_set(u8 value);
+void app_audio_state_switch(u8 state, s16 max_volume);
+void app_audio_mute(u8 value);
+s16 app_audio_get_max_volume(void);
+void app_audio_state_switch(u8 state, s16 max_volume);
+void app_audio_state_exit(u8 state);
+void app_audio_set_max_volume(u8 state, s16 max_volume);
+u8 app_audio_get_state(void);
+void volume_up_down_direct(s8 value);
+void app_audio_set_mix_volume(u8 front_volume, u8 back_volume);
+void app_audio_set_digital_volume(s16 volume);
+
+void app_set_sys_vol(s16 vol_l, s16 vol_r);
+void app_set_max_vol(s16 vol);
+void audio_volume_list_init(u8 cfg_en);
+
+u32 phone_call_eq_open();
+int eq_mode_sw();
+int mic_test_start();
+int mic_test_stop();
+
+void dac_power_on(void);
+void dac_power_off(void);
+
+/*打印audio模块的数字模拟增益:DAC/ADC*/
+void audio_gain_dump();
+void audio_adda_dump(void); //打印所有的dac,adc寄存器
+
+void app_audio_volume_init(void);
+void app_audio_output_init(void);
+int app_audio_output_mode_set(u8 output);
+int app_audio_output_mode_get(void);
+int app_audio_output_channel_get(void);
+int app_audio_output_channel_set(u8 channel);
+int app_audio_output_write(void *buf, int len);
+int app_audio_output_samplerate_select(u32 sample_rate, u8 high);
+int app_audio_output_samplerate_set(int sample_rate);
+int app_audio_output_samplerate_get(void);
+int app_audio_output_start(void);
+int app_audio_output_stop(void);
+int audio_dac_trim_value_check(struct audio_dac_trim *dac_trim);
+
+int esco_enc_reset(void);
+u8 bt_phone_dec_is_running();
+u8 bt_media_is_running(void);
+void a2dp_dec_dut_enable(u8 dut_enable);
+
+
+#endif/*_APP_AUDIO_H_*/
diff --git a/cpu/br28/audio_cvp_dut.c b/cpu/br28/audio_cvp_dut.c
new file mode 100644
index 0000000..af93866
--- /dev/null
+++ b/cpu/br28/audio_cvp_dut.c
@@ -0,0 +1,652 @@
+/*
+ ****************************************************************************
+ * Audio CVP DUT
+ *
+ *
+ ****************************************************************************
+ */
+#include "audio_cvp_dut.h"
+#include "online_db_deal.h"
+#include "system/includes.h"
+#include "app_config.h"
+#include "audio_adc.h"
+#include "anc.h"
+#include "aec_user.h"
+#include "app_main.h"
+#include "user_cfg_id.h"
+#include "audio_config.h"
+#include "math.h"
+
+#if 0
+#define cvp_dut_log printf
+#define cvp_dut_put_float put_float
+#else
+#define cvp_dut_log(...)
+#define cvp_dut_put_float(...)
+#endif
+
+#define CVP_DUT_BIG_ENDDIAN 1 //大端数据输出
+#define CVP_DUT_LITTLE_ENDDIAN 2 //小端数据输出
+#define CVP_DUT_OUTPUT_WAY CVP_DUT_LITTLE_ENDDIAN
+
+#if TCFG_AUDIO_CVP_DUT_ENABLE
+static cvp_dut_t *cvp_dut_hdl = NULL;
+static int cvp_dut_app_online_parse(u8 *packet, u8 size, u8 *ext_data, u16 ext_size);
+int cvp_dut_new_rx_packet(u8 *dat, u8 len);
+int cvp_dut_spp_rx_packet(u8 *dat, u8 len);
+
+#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
+extern void audio_aec_output_sel(u8 sel, u8 agc);
+#endif/*TCFG_AUDIO_TRIPLE_MIC_ENABLE*/
+
+extern void put_float(double fv);
+extern void sys_enter_soft_poweroff(void *priv);
+extern int audio_aec_toggle_set(u8 toggle);
+
+/*未经过算法处理,主要用于分析ANC MIC的频响*/
+int cvp_dut_bypass_mic_ch_sel(u8 mic_num)
+{
+ if (cvp_dut_hdl) {
+ switch (mic_num) {
+ case A_MIC0:
+ cvp_dut_hdl->mic_ch_sel = AUDIO_ADC_MIC_0;
+ break;
+ case A_MIC1:
+ cvp_dut_hdl->mic_ch_sel = AUDIO_ADC_MIC_1;
+ break;
+ case A_MIC2:
+ cvp_dut_hdl->mic_ch_sel = AUDIO_ADC_MIC_2;
+ break;
+ case A_MIC3:
+ cvp_dut_hdl->mic_ch_sel = AUDIO_ADC_MIC_3;
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+u8 cvp_dut_mic_ch_get(void)
+{
+ if (cvp_dut_hdl) {
+ return cvp_dut_hdl->mic_ch_sel;
+ }
+ return 0;
+}
+
+u8 cvp_dut_mode_get(void)
+{
+ if (cvp_dut_hdl) {
+ return cvp_dut_hdl->mode;
+ }
+ return 0;
+}
+
+void cvp_dut_mode_set(u8 mode)
+{
+ if (cvp_dut_hdl) {
+ cvp_dut_hdl->mode = mode;
+ }
+}
+
+int cvp_dut_event_deal(u8 *dat)
+{
+ if (cvp_dut_hdl) {
+ switch (dat[3]) {
+#if TCFG_AUDIO_DUAL_MIC_ENABLE
+//双麦ENC DUT 事件处理
+ case CVP_DUT_DMS_MASTER_MIC:
+ cvp_dut_log("CMD:CVP_DUT_DMS_MASTER_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_output_sel(DMS_OUTPUT_SEL_MASTER, 0);
+ break;
+ case CVP_DUT_DMS_SLAVE_MIC:
+ cvp_dut_log("CMD:CVP_DUT_DMS_SLAVE_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_output_sel(DMS_OUTPUT_SEL_SLAVE, 0);
+ break;
+ case CVP_DUT_DMS_OPEN_ALGORITHM:
+ cvp_dut_log("CMD:CVP_DUT_DMS_OPEN_ALGORITHM\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_output_sel(DMS_OUTPUT_SEL_DEFAULT, 1);
+ break;
+#elif TCFG_AUDIO_TRIPLE_MIC_ENABLE
+ case CVP_DUT_3MIC_MASTER_MIC:
+ cvp_dut_log("CMD:CVP_DUT_3MIC_MASTER_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_output_sel(1, 0);
+ break;
+ case CVP_DUT_3MIC_SLAVE_MIC:
+ cvp_dut_log("CMD:CVP_DUT_3MIC_SLAVE_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_output_sel(2, 0);
+ break;
+ case CVP_DUT_3MIC_FB_MIC:
+ cvp_dut_log("CMD:CVP_DUT_3MIC_FB_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_output_sel(3, 0);
+ break;
+ case CVP_DUT_3MIC_OPEN_ALGORITHM:
+ cvp_dut_log("CMD:CVP_DUT_3MIC_OPEN_ALGORITHM\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_output_sel(0, 0);
+ break;
+#else
+//单麦SMS/DNS DUT 事件处理
+ case CVP_DUT_DMS_MASTER_MIC:
+ cvp_dut_log("CMD:SMS/CVP_DUT_DMS_MASTER_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_toggle_set(0);
+ break;
+ case CVP_DUT_DMS_OPEN_ALGORITHM:
+ cvp_dut_log("CMD:SMS/CVP_DUT_DMS_OPEN_ALGORITHM\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_toggle_set(1);
+ break;
+#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
+
+#if TCFG_AUDIO_ANC_ENABLE
+ case CVP_DUT_FF_MIC: //TWS_FF_MIC测试 或者 头戴式FF_L_MIC测试
+ cvp_dut_log("CMD:CVP_DUT_FF_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
+ if (ANC_CH & ANC_L_CH) {
+ cvp_dut_bypass_mic_ch_sel(ANCL_FF_MIC);
+ } else {
+ cvp_dut_bypass_mic_ch_sel(ANCR_FF_MIC);
+ }
+ break;
+ case CVP_DUT_FB_MIC: //TWS_FB_MIC测试 或者 头戴式FB_L_MIC测试
+ cvp_dut_log("CMD:CVP_DUT_FB_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
+ if (ANC_CH & ANC_L_CH) {
+ cvp_dut_bypass_mic_ch_sel(ANCL_FB_MIC);
+ } else {
+ cvp_dut_bypass_mic_ch_sel(ANCR_FB_MIC);
+ }
+ break;
+ case CVP_DUT_HEAD_PHONE_R_FF_MIC: //头戴式FF_R_MIC测试
+ cvp_dut_log("CMD:CVP_DUT_HEAD_PHONE_R_FF_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
+ if (ANC_CH == (ANC_L_CH | ANC_R_CH)) {
+ cvp_dut_bypass_mic_ch_sel(ANCR_FF_MIC);
+ }
+ break;
+ case CVP_DUT_HEAD_PHONE_R_FB_MIC: //头戴式FB_R_MIC测试
+ cvp_dut_log("CMD:CVP_DUT_HEAD_PHONE_R_FB_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
+ if (ANC_CH == (ANC_L_CH | ANC_R_CH)) {
+ cvp_dut_bypass_mic_ch_sel(ANCR_FB_MIC);
+ }
+ break;
+ case CVP_DUT_MODE_ALGORITHM_SET: //CVP恢复正常模式
+ cvp_dut_log("CMD:CVP_DUT_RESUME\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ break;
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+
+//JL自研算法指令API
+#if !TCFG_CVP_DEVELOP_ENABLE
+ case CVP_DUT_NS_OPEN:
+ cvp_dut_log("CMD:CVP_DUT_NS_OPEN\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_cvp_ioctl(CVP_NS_SWITCH, 1, NULL); //降噪关
+ break;
+ case CVP_DUT_NS_CLOSE:
+ cvp_dut_log("CMD:CVP_DUT_NS_CLOSE\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_cvp_ioctl(CVP_NS_SWITCH, 0, NULL); //降噪开
+ break;
+#endif/*TCFG_CVP_DEVELOP_ENABLE*/
+
+ case CVP_DUT_OPEN_ALGORITHM:
+ cvp_dut_log("CMD:CVP_DUT_OPEN_ALGORITHM\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_toggle_set(1);
+ break;
+ case CVP_DUT_CLOSE_ALGORITHM:
+ cvp_dut_log("CMD:CVP_DUT_CLOSE_ALGORITHM\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_toggle_set(0);
+ break;
+ case CVP_DUT_POWEROFF:
+ cvp_dut_log("CMD:CVP_DUT_POWEROFF\n");
+ sys_enter_soft_poweroff(NULL);
+ break;
+ default:
+ cvp_dut_log("CMD:UNKNOW CMD!!!\n");
+ return CVP_DUT_ACK_ERR_UNKNOW;
+ }
+ return CVP_DUT_ACK_SUCCESS;
+ }
+ return CVP_DUT_ACK_ERR_UNKNOW;
+}
+
+void cvp_dut_init(void)
+{
+ cvp_dut_log("tx dat");
+ if (cvp_dut_hdl == NULL) {
+ cvp_dut_hdl = zalloc(sizeof(cvp_dut_t));
+ }
+ //开机默认设置成算法模式
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ app_online_db_register_handle(DB_PKT_TYPE_DMS, cvp_dut_app_online_parse);
+}
+
+void cvp_dut_unit(void)
+{
+ free(cvp_dut_hdl);
+ cvp_dut_hdl = NULL;
+}
+
+int cvp_dut_spp_tx_packet(u8 command)
+{
+ if (cvp_dut_hdl) {
+ cvp_dut_hdl->tx_buf.magic = CVP_DUT_SPP_MAGIC;
+ cvp_dut_hdl->tx_buf.dat[0] = 0;
+ cvp_dut_hdl->tx_buf.dat[1] = 0;
+ cvp_dut_hdl->tx_buf.dat[2] = 0;
+ cvp_dut_hdl->tx_buf.dat[3] = command;
+ cvp_dut_log("tx dat");
+#if CVP_DUT_OUTPUT_WAY == CVP_DUT_LITTLE_ENDDIAN // 小端格式
+ cvp_dut_hdl->tx_buf.crc = CRC16((&cvp_dut_hdl->tx_buf.dat), CVP_DUT_PACK_NUM - 4);
+ put_buf((u8 *)&cvp_dut_hdl->tx_buf.magic, CVP_DUT_PACK_NUM);
+ app_online_db_send(DB_PKT_TYPE_DMS, (u8 *)&cvp_dut_hdl->tx_buf.magic, CVP_DUT_PACK_NUM);
+#else
+ u16 crc_temp;
+ int i;
+ u8 dat[CVP_DUT_PACK_NUM];
+ u8 dat_temp;
+ memcpy(dat, &(cvp_dut_hdl->tx_buf), CVP_DUT_PACK_NUM);
+ crc_temp = CRC16(dat + 4, 6);
+ printf("crc0x%x,0x%x", crc_temp, cvp_dut_hdl->tx_buf.crc);
+ for (i = 0; i < 6; i += 2) { //小端数据转大端
+ dat_temp = dat[i];
+ dat[i] = dat[i + 1];
+ dat[i + 1] = dat_temp;
+ }
+ crc_temp = CRC16(dat + 4, CVP_DUT_PACK_NUM - 4);
+ dat[2] = crc_temp >> 8;
+ dat[3] = crc_temp & 0xff;
+ put_buf(dat, CVP_DUT_PACK_NUM);
+ app_online_db_send(DB_PKT_TYPE_DMS, dat, CVP_DUT_PACK_NUM);
+#endif
+
+ }
+ return 0;
+}
+
+static int cvp_dut_app_online_parse(u8 *packet, u8 size, u8 *ext_data, u16 ext_size)
+{
+ if (cvp_dut_hdl) {
+ cvp_dut_hdl->parse_seq = ext_data[1];
+ int ret = cvp_dut_spp_rx_packet(packet, size);
+ if (ret) {
+ cvp_dut_new_rx_packet(packet, size);
+ }
+ }
+ return 0;
+}
+
+
+int cvp_dut_spp_rx_packet(u8 *dat, u8 len)
+{
+ if (cvp_dut_hdl) {
+ u8 dat_temp;
+ u16 crc = 0;
+ int ret = 0;
+ u8 dat_packet[CVP_DUT_PACK_NUM];
+ if (len > CVP_DUT_PACK_NUM) {
+ return 1;
+ }
+ /* cvp_dut_log("rx dat,%d\n", CVP_DUT_PACK_NUM); */
+ put_buf(dat, len);
+ memcpy(dat_packet, dat, len);
+ crc = CRC16(dat + 4, len - 4);
+#if CVP_DUT_OUTPUT_WAY == CVP_DUT_BIG_ENDDIAN // 大端格式
+ for (int i = 0; i < 6; i += 2) { // 大端数据转小端
+ dat_temp = dat_packet[i];
+ dat_packet[i] = dat_packet[i + 1];
+ dat_packet[i + 1] = dat_temp;
+ }
+#endif
+ cvp_dut_log("rx dat_packet");
+ memcpy(&(cvp_dut_hdl->rx_buf), dat_packet, 4);
+ if (cvp_dut_hdl->rx_buf.magic == CVP_DUT_SPP_MAGIC) {
+ cvp_dut_log("crc %x,cvp_dut_hdl->rx_buf.crc %x\n", crc, cvp_dut_hdl->rx_buf.crc);
+ if (cvp_dut_hdl->rx_buf.crc == crc || cvp_dut_hdl->rx_buf.crc == 0x1) {
+ memcpy(&(cvp_dut_hdl->rx_buf), dat_packet, len);
+ ret = cvp_dut_event_deal(cvp_dut_hdl->rx_buf.dat);
+ cvp_dut_spp_tx_packet(ret); //反馈收到命令
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+/***************************************************************************
+ CVP SPP产测 NEW STRUCT
+***************************************************************************/
+
+struct cvp_dut_packet_t {
+ u8 cmd; //命令
+ u16 len; //参数长度
+ u8 dat[0]; //参数
+} __attribute__((packed));
+
+struct cvp_dut_head_t {
+ u16 magic; //标识符
+ u16 crc; //CRC, 从packet开始计算
+ struct cvp_dut_packet_t packet;
+} __attribute__((packed));
+
+/*
+ CVP 命令处理函数
+ param: struct cvp_dut_head_t 类型的数据
+ return 执行结果
+*/
+int cvp_dut_new_event_deal(void *packet)
+{
+ struct cvp_dut_packet_t *hdl = (struct cvp_dut_packet_t *)packet;
+ u16 len = hdl->len;
+ int wlen = 0;
+ int ret = -1;
+ u8 last_mode, reset_flag;
+ cvp_dut_log("CVP_DUT CMD:0X%x,LEN:%d\n", hdl->cmd, len);
+ put_buf((u8 *)packet, hdl->len + sizeof(struct cvp_dut_packet_t));
+ if (cvp_dut_hdl) {
+ reset_flag = 0;
+ last_mode = cvp_dut_hdl->mode;
+ switch (hdl->cmd) {
+#if TCFG_AUDIO_DUAL_MIC_ENABLE
+//双麦ENC DUT 事件处理
+ case CVP_DUT_DMS_MASTER_MIC:
+ cvp_dut_log("CMD:CVP_DUT_DMS_MASTER_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_output_sel(DMS_OUTPUT_SEL_MASTER, 0);
+ break;
+ case CVP_DUT_DMS_SLAVE_MIC:
+ cvp_dut_log("CMD:CVP_DUT_DMS_SLAVE_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_output_sel(DMS_OUTPUT_SEL_SLAVE, 0);
+ break;
+ case CVP_DUT_DMS_OPEN_ALGORITHM:
+ cvp_dut_log("CMD:CVP_DUT_DMS_OPEN_ALGORITHM\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_output_sel(DMS_OUTPUT_SEL_DEFAULT, 1);
+ break;
+#elif TCFG_AUDIO_TRIPLE_MIC_ENABLE
+ case CVP_DUT_3MIC_MASTER_MIC:
+ cvp_dut_log("CMD:CVP_DUT_3MIC_MASTER_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_output_sel(1, 0);
+ break;
+ case CVP_DUT_3MIC_SLAVE_MIC:
+ cvp_dut_log("CMD:CVP_DUT_3MIC_SLAVE_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_output_sel(2, 0);
+ break;
+ case CVP_DUT_3MIC_FB_MIC:
+ cvp_dut_log("CMD:CVP_DUT_3MIC_FB_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_output_sel(3, 0);
+ break;
+ case CVP_DUT_3MIC_OPEN_ALGORITHM:
+ cvp_dut_log("CMD:CVP_DUT_3MIC_OPEN_ALGORITHM\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_output_sel(0, 0);
+ break;
+#else
+//单麦SMS/DNS DUT 事件处理
+ case CVP_DUT_DMS_MASTER_MIC:
+ cvp_dut_log("CMD:SMS/CVP_DUT_DMS_MASTER_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_toggle_set(0);
+ break;
+ case CVP_DUT_DMS_OPEN_ALGORITHM:
+ cvp_dut_log("CMD:SMS/CVP_DUT_DMS_OPEN_ALGORITHM\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_toggle_set(1);
+ break;
+#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
+
+#if TCFG_AUDIO_ANC_ENABLE
+ case CVP_DUT_FF_MIC: //TWS_FF_MIC测试 或者 头戴式FF_L_MIC测试
+ cvp_dut_log("CMD:CVP_DUT_FF_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
+ if (ANC_CH & ANC_L_CH) {
+ cvp_dut_bypass_mic_ch_sel(ANCL_FF_MIC);
+ } else {
+ cvp_dut_bypass_mic_ch_sel(ANCR_FF_MIC);
+ }
+ reset_flag = 1;
+ break;
+ case CVP_DUT_FB_MIC: //TWS_FB_MIC测试 或者 头戴式FB_L_MIC测试
+ cvp_dut_log("CMD:CVP_DUT_FB_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
+ if (ANC_CH & ANC_L_CH) {
+ cvp_dut_bypass_mic_ch_sel(ANCL_FB_MIC);
+ } else {
+ cvp_dut_bypass_mic_ch_sel(ANCR_FB_MIC);
+ }
+ reset_flag = 1;
+ break;
+ case CVP_DUT_HEAD_PHONE_R_FF_MIC: //头戴式FF_R_MIC测试
+ cvp_dut_log("CMD:CVP_DUT_HEAD_PHONE_R_FF_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
+ if (ANC_CH == (ANC_L_CH | ANC_R_CH)) {
+ cvp_dut_bypass_mic_ch_sel(ANCR_FF_MIC);
+ }
+ reset_flag = 1;
+ break;
+ case CVP_DUT_HEAD_PHONE_R_FB_MIC: //头戴式FB_R_MIC测试
+ cvp_dut_log("CMD:CVP_DUT_HEAD_PHONE_R_FB_MIC\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
+ if (ANC_CH == (ANC_L_CH | ANC_R_CH)) {
+ cvp_dut_bypass_mic_ch_sel(ANCR_FB_MIC);
+ }
+ reset_flag = 1;
+ break;
+ case CVP_DUT_MODE_ALGORITHM_SET: //CVP恢复正常模式
+ cvp_dut_log("CMD:CVP_DUT_RESUME\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ break;
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+
+//JL自研算法指令API
+#if !TCFG_CVP_DEVELOP_ENABLE
+ case CVP_DUT_NS_OPEN:
+ cvp_dut_log("CMD:CVP_DUT_NS_OPEN\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_cvp_ioctl(CVP_NS_SWITCH, 1, NULL); //降噪关
+ break;
+ case CVP_DUT_NS_CLOSE:
+ cvp_dut_log("CMD:CVP_DUT_NS_CLOSE\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_cvp_ioctl(CVP_NS_SWITCH, 0, NULL); //降噪开
+ break;
+#endif/*TCFG_CVP_DEVELOP_ENABLE*/
+
+ case CVP_DUT_OPEN_ALGORITHM:
+ cvp_dut_log("CMD:CVP_DUT_OPEN_ALGORITHM\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_toggle_set(1);
+ break;
+ case CVP_DUT_CLOSE_ALGORITHM:
+ cvp_dut_log("CMD:CVP_DUT_CLOSE_ALGORITHM\n");
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_aec_toggle_set(0);
+ break;
+ case CVP_DUT_POWEROFF:
+ cvp_dut_log("CMD:CVP_DUT_POWEROFF\n");
+ sys_enter_soft_poweroff(NULL);
+ break;
+
+ /*enc麦克风校准补偿*/
+#if TCFG_AUDIO_MIC_ARRAY_TRIM_ENABLE
+ case CVP_ENC_MIC_DIFF_CMP_SET: //主MIC - 副MIC
+ cvp_dut_log("CMD:CVP_ENC_MIC_DIFF_CMP_SET\n");
+ float diff;
+ memcpy((u8 *)&diff, hdl->dat, len);
+ cvp_dut_log("diff:");
+ cvp_dut_put_float(diff);
+ float dms_mic_diff = log10(app_var.enc_degradation) * 20;
+ app_var.audio_mic_array_diff_cmp = pow(10, (diff + dms_mic_diff) / 20);
+ wlen = syscfg_write(CFG_MIC_ARRAY_DIFF_CMP_VALUE, (u8 *)(&app_var.audio_mic_array_diff_cmp), sizeof(app_var.audio_mic_array_diff_cmp));
+ if (wlen != sizeof(app_var.audio_mic_array_diff_cmp)) {
+ printf("mic array diff cap vm write fail !!!");
+ ret = CVP_DUT_ACK_VM_WRITE_ERR;
+ }
+ cvp_dut_log("mic_array_diff_cmp:");
+ cvp_dut_put_float(app_var.audio_mic_array_diff_cmp);
+ break;
+ case CVP_ENC_MIC_DIFF_CMP_EN:
+ cvp_dut_log("CMD:CVP_ENC_MIC_DIFF_CMP_EN\n");
+ u8 en;
+ memcpy(&en, hdl->dat, len);
+ app_var.audio_mic_array_trim_en = en;
+ wlen = syscfg_write(CFG_MIC_ARRAY_TRIM_EN, (u8 *)(&app_var.audio_mic_array_trim_en), sizeof(app_var.audio_mic_array_trim_en));
+ if (wlen != sizeof(app_var.audio_mic_array_trim_en)) {
+ cvp_dut_log("mic array trim en vm write fail !!!");
+ ret = CVP_DUT_ACK_VM_WRITE_ERR;
+ }
+ cvp_dut_log("mic array trim en: %d\n", app_var.audio_mic_array_trim_en);
+ break;
+ case CVP_ENC_MIC_DIFF_CMP_CLEAN:
+ cvp_dut_log("CMD:CVP_ENC_MIC_DIFF_CMP_CLEAN\n");
+ app_var.audio_mic_array_diff_cmp = 1.0f;
+ app_var.audio_mic_cmp.talk = 1.0f;
+ app_var.audio_mic_cmp.ff = 1.0f;
+ app_var.audio_mic_cmp.fb = 1.0f;
+
+ wlen = syscfg_write(CFG_MIC_ARRAY_DIFF_CMP_VALUE, (u8 *)(&app_var.audio_mic_array_diff_cmp), sizeof(app_var.audio_mic_array_diff_cmp));
+ if (wlen != sizeof(app_var.audio_mic_array_diff_cmp)) {
+ cvp_dut_log("mic array diff cap vm write fail !!!");
+ ret = CVP_DUT_ACK_VM_WRITE_ERR;
+ }
+ wlen = syscfg_write(CFG_MIC_TARGET_DIFF_CMP, (u8 *)(&app_var.audio_mic_cmp), sizeof(audio_mic_cmp_t));
+ if (wlen != sizeof(audio_mic_cmp_t)) {
+ printf("mic array diff cap vm write fail !!!");
+ ret = CVP_DUT_ACK_VM_WRITE_ERR;
+ }
+ cvp_dut_log("CMD:CVP_ENC_MIC_DIFF_CMP_CLEAN\n");
+ break;
+ case CVP_ENC_TARGET_MIC_DIFF_SET:
+ cvp_dut_log("CMD:CVP_ENC_TARGET_MIC_DIFF_SET\n");
+ float talk_diff, ff_diff, fb_diff;
+ memcpy((u8 *)&talk_diff, hdl->dat, 4);
+ memcpy((u8 *)&ff_diff, hdl->dat + 4, 4);
+ memcpy((u8 *)&fb_diff, hdl->dat + 8, 4);
+ cvp_dut_log("talk_diff:");
+ cvp_dut_put_float(talk_diff);
+ cvp_dut_log("ff_diff:");
+ cvp_dut_put_float(ff_diff);
+ cvp_dut_log("fb_diff:");
+ cvp_dut_put_float(fb_diff);
+ app_var.audio_mic_cmp.talk = pow(10, (talk_diff) / 20);
+ app_var.audio_mic_cmp.ff = pow(10, (ff_diff) / 20);
+ app_var.audio_mic_cmp.fb = pow(10, (fb_diff) / 20);
+ wlen = syscfg_write(CFG_MIC_TARGET_DIFF_CMP, (u8 *)(&app_var.audio_mic_cmp), sizeof(audio_mic_cmp_t));
+ if (wlen != sizeof(audio_mic_cmp_t)) {
+ printf("mic array diff cap vm write fail !!!");
+ ret = CVP_DUT_ACK_VM_WRITE_ERR;
+ }
+ break;
+#endif /*TCFG_AUDIO_MIC_ARRAY_TRIM_ENABLE*/
+
+ /*通话算法模块开关*/
+ case CVP_DUT_CVP_IOCTL:
+ cvp_dut_log("CMD:CVP_DUT_CVP_IOCTL\n");
+ u8 ioctl_cmd = hdl->dat[0];
+ u8 toggle = hdl->dat[1];
+ cvp_dut_log(" io ctl cmd %d, toggle %d", ioctl_cmd, toggle);
+ cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
+ audio_cvp_ioctl(ioctl_cmd, toggle, NULL);
+ break;
+ case CVP_DUT_DEC_DUT_SET:
+ cvp_dut_log("CVP_DUT_DEC_DUT_SET: %d\n", hdl->dat[0]);
+ cvp_dut_hdl->dec_dut_enable = hdl->dat[0];
+ a2dp_dec_dut_enable(cvp_dut_hdl->dec_dut_enable);
+ break;
+ default:
+ cvp_dut_log("CMD:UNKNOW CMD!!!\n");
+ ret = CVP_DUT_ACK_ERR_UNKNOW;
+ }
+ if (last_mode != cvp_dut_hdl->mode) {
+ reset_flag = 1; //模式被修改,则复位通话
+ }
+ if (reset_flag) {
+ if (bt_phone_dec_is_running()) {
+ esco_enc_reset();
+ }
+ }
+ ret = (ret == -1) ? CVP_DUT_ACK_SUCCESS : ret;
+ }
+ return ret;
+}
+
+//len = 参数数据长度(不包括cmd)
+int cvp_dut_new_tx_packet(u8 cmd, u8 *data, int len)
+{
+ if (cvp_dut_hdl) {
+ int packet_len = sizeof(struct cvp_dut_head_t) + len;
+ struct cvp_dut_head_t *head = (struct cvp_dut_head_t *)malloc(packet_len);
+ head->magic = CVP_DUT_NEW_SPP_MAGIC;
+ head->packet.cmd = cmd;
+ head->packet.len = len;
+ head->crc = CRC16(&head->packet, packet_len - 4);
+ if (len) {
+ memcpy(head->packet.dat, data, len);
+ }
+ cvp_dut_log("tx new_dat_packet %d\n", packet_len);
+ //put_buf((u8 *)head, packet_len);
+ app_online_db_send(DB_PKT_TYPE_DMS, (u8 *)head, packet_len);
+ free(head);
+ }
+ return 0;
+}
+
+int cvp_dut_new_rx_packet(u8 *dat, u8 len)
+{
+ u16 crc = 0;
+ int ret = 0;
+ struct cvp_dut_head_t *head = (struct cvp_dut_head_t *)dat;
+ if (cvp_dut_hdl) {
+ cvp_dut_log("rx new_dat_packet");
+ //put_buf(dat, len);
+ crc = CRC16(&head->packet, len - 4);
+ if (head->magic == CVP_DUT_NEW_SPP_MAGIC) {
+ if (head->crc == crc || head->crc == 0x1) {
+ ret = cvp_dut_new_event_deal(&head->packet);
+ cvp_dut_new_tx_packet(ret, NULL, 0); //反馈收到命令
+ if (ret == CVP_DUT_ACK_SUCCESS) {
+ return 0;
+ }
+ } else {
+ cvp_dut_log("ERR head->crc %x != %x\n", head->crc, crc);
+ cvp_dut_new_tx_packet(CVP_DUT_ACK_CRC_ERR, NULL, 0); //反馈收到命令
+ }
+ }
+ }
+ return 1;
+}
+
+/*
+ DEC产测状态获取
+ param: music_decide 1 需判断播歌状态; 0 不需判断
+*/
+u8 audio_dec_dut_en_get(u8 music_decide)
+{
+ if (!cvp_dut_hdl) {
+ return 0;
+ }
+ if (music_decide && !bt_media_is_running()) {
+ //当前非播歌状态
+ return 0;
+ }
+ return cvp_dut_hdl->dec_dut_enable;
+}
+
+#endif /*TCFG_AUDIO_CVP_DUT_ENABLE*/
+
diff --git a/cpu/br28/audio_cvp_dut.h b/cpu/br28/audio_cvp_dut.h
new file mode 100644
index 0000000..79158b8
--- /dev/null
+++ b/cpu/br28/audio_cvp_dut.h
@@ -0,0 +1,121 @@
+#ifndef _AUDIO_CVP_DUT_H_
+#define _AUDIO_CVP_DUT_H_
+
+#include "generic/typedef.h"
+
+/*******************CVP测试命令集*********************/
+#define CVP_DUT_DMS_MASTER_MIC 0x01 //DMS-测试主MIC SMS-关闭CVP算法
+#define CVP_DUT_DMS_SLAVE_MIC 0x02 //DMS-测试副MIC
+#define CVP_DUT_DMS_OPEN_ALGORITHM 0x03 //DMS-测试dms算法 SMS-打开CVP算法
+
+#define CVP_DUT_NS_OPEN 0x04 //打开NS模块
+#define CVP_DUT_NS_CLOSE 0x05 //关闭NS模块
+
+//ANC MIC 频响测试指令,且需切换到CVP_DUT_MODE_BYPASS,在通话HFP前设置
+#define CVP_DUT_FF_MIC 0x06 //测试TWS FF MIC/头戴式左耳FF_MIC
+#define CVP_DUT_FB_MIC 0x07 //测试TWS FB MIC/头戴式左耳FB_MIC
+#define CVP_DUT_HEAD_PHONE_R_FF_MIC 0x08 //测试头戴式右耳FF_MIC
+#define CVP_DUT_HEAD_PHONE_R_FB_MIC 0x09 //测试头戴式右耳FB_MIC
+
+#define CVP_DUT_OPEN_ALGORITHM 0x0a //CVP算法开启
+#define CVP_DUT_CLOSE_ALGORITHM 0x0b //CVP算法关闭
+#define CVP_DUT_MODE_ALGORITHM_SET 0x0c //CVP_DUT 开关算法模式
+#define CVP_DUT_POWEROFF 0x0d //耳机关机指令
+
+#define CVP_ENC_MIC_DIFF_CMP_SET 0x0f //设置补偿值(主MIC - 副MIC)
+#define CVP_ENC_MIC_DIFF_CMP_EN 0x10 //补偿使能
+#define CVP_ENC_MIC_DIFF_CMP_CLEAN 0x11 //清除补偿
+
+//三麦通话测试指令
+#define CVP_DUT_3MIC_MASTER_MIC CVP_DUT_DMS_MASTER_MIC //测试三麦算法主麦频响
+#define CVP_DUT_3MIC_SLAVE_MIC CVP_DUT_DMS_SLAVE_MIC //测试三麦算法副麦频响
+#define CVP_DUT_3MIC_FB_MIC 0x0e //测试三麦算法FBmic频响
+#define CVP_DUT_3MIC_OPEN_ALGORITHM CVP_DUT_DMS_OPEN_ALGORITHM //测试三麦算法副麦频响
+
+#define CVP_DUT_CVP_IOCTL 0x12 //CVP算法单元独立控制
+
+#define CVP_DUT_DEC_DUT_SET 0x13 //DEC 产测模式设置 (bypass数据处理)
+#define CVP_ENC_TARGET_MIC_DIFF_SET 0x14 //设置MIC与目标金机MIC的差值(主-副-FB)
+
+//命令回复
+#define CVP_DUT_ACK_SUCCESS 0x01 //命令接收成功
+//错误回复
+#define CVP_DUT_ACK_ERR_UNKNOW 0xA1 //未知命令
+#define CVP_DUT_ACK_CRC_ERR 0xA2 //CRC错误
+#define CVP_DUT_ACK_VM_WRITE_ERR 0xA3 //VM写入错误
+/*******************CVP测试命令集END*********************/
+
+#define CVP_DUT_SPP_MAGIC 0x55BB
+#define CVP_DUT_PACK_NUM sizeof(cvp_dut_data_t) //数据包总长度
+
+#define CVP_DUT_NEW_SPP_MAGIC 0x55CC
+
+typedef enum {
+ /*
+ CVP_DUT 算法模式
+ 通话中设置命令,可自由开关每个算法,测试性能指标
+ */
+ CVP_DUT_MODE_ALGORITHM = 1,
+
+ /*
+ CVP_DUT BYPASS模式
+ 通话前设置命令,不经过算法,可自由选择需要测试的MIC
+ 每次通话结束默认恢复成 CVP_DUT算法模式
+ */
+ CVP_DUT_MODE_BYPASS = 2,
+
+} CVP_DUT_mode_t;
+
+typedef enum {
+ CVP_3MIC_OUTPUT_SEL_DEFAULT = 0, /*默认输出*/
+ CVP_3MIC_OUTPUT_SEL_MASTER, /*Talk mic原始数据*/
+ CVP_3MIC_OUTPUT_SEL_SLAVE, /*FF mic原始数据*/
+ CVP_3MIC_OUTPUT_SEL_FBMIC, /*FB mic原始数据*/
+} CVP_3MIC_OUTPUT_ENUM;
+
+//DEC 产测模式
+typedef enum {
+ AUDIO_DEC_DUT_MODE_CLOSE = 0, /*DEC_DUT 关闭*/
+ AUDIO_DEC_DUT_MODE_BYPASS, /*DEC_DUT 开启:bypass所有数据处理*/
+ AUDIO_DEC_DUT_MODE_SPK_EQ, /*DEC_DUT 开启:仅保留SPK_EQ*/
+} audio_dec_dut_mode_t;
+
+typedef struct {
+ u16 magic;
+ u16 crc;
+ u8 dat[4];
+} cvp_dut_data_t;
+
+typedef struct {
+ u8 parse_seq;
+ u8 mic_ch_sel; //bypass模式下,MIC通道号
+ u8 mode; //CVP DUT MODE
+ u8 dec_dut_enable; //DEC DUT 模式
+ cvp_dut_data_t rx_buf; //spp接收buf
+ cvp_dut_data_t tx_buf; //spp发送buf
+} cvp_dut_t;
+//cvp_dut 测试初始化接口
+void cvp_dut_init(void);
+
+//cvp_dut 卸载接口
+void cvp_dut_unit(void);
+
+//cvp_dut MIC 通道 获取接口
+u8 cvp_dut_mic_ch_get(void);
+
+//cvp_dut 模式获取
+u8 cvp_dut_mode_get(void);
+
+//cvp_dut 模式设置
+void cvp_dut_mode_set(u8 mode);
+
+/*
+ DEC产测状态获取
+ param: music_decide 1 需判断播歌状态; 0 不需判断
+*/
+u8 audio_dec_dut_en_get(u8 music_decide);
+
+//cvp_dut 数据解析函数
+int cvp_dut_new_rx_packet(u8 *dat, u8 len);
+
+#endif/*_AUDIO_CVP_DUT_*/
diff --git a/cpu/br28/audio_dec.c b/cpu/br28/audio_dec.c
new file mode 100644
index 0000000..d1d0330
--- /dev/null
+++ b/cpu/br28/audio_dec.c
@@ -0,0 +1,1852 @@
+#include "asm/includes.h"
+#include "media/includes.h"
+#include "system/includes.h"
+#include "classic/tws_api.h"
+#include "classic/hci_lmp.h"
+#include "effectrs_sync.h"
+#include "audio_syncts.h"
+#include "application/eq_config.h"
+#include "application/audio_energy_detect.h"
+#include "application/audio_surround.h"
+#include "app_config.h"
+#include "audio_config.h"
+#include "aec_user.h"
+#include "audio_enc.h"
+#include "app_main.h"
+#include "btstack/avctp_user.h"
+#include "btstack/a2dp_media_codec.h"
+#include "tone_player.h"
+/* #include "audio_demo/audio_demo.h" */
+#include "media/audio_vbass.h"
+#include "audio_plc.h"
+#include "audio_dec_eff.h"
+#include "audio_codec_clock.h"
+#if TCFG_AUDIO_HEARING_AID_ENABLE
+#include "audio_hearing_aid.h"
+#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
+#if TCFG_USER_TWS_ENABLE
+#include "bt_tws.h"
+#endif/*TCFG_USER_TWS_ENABLE*/
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+#include "audio_dvol.h"
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+#if TCFG_APP_FM_EMITTER_EN
+#include "fm_emitter/fm_emitter_manage.h"
+#endif/*TCFG_APP_FM_EMITTER_EN*/
+#if TCFG_AUDIO_ANC_ENABLE
+#include "audio_anc.h"
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+#if (defined(TCFG_PHONE_MESSAGE_ENABLE) && (TCFG_PHONE_MESSAGE_ENABLE))
+#include "phone_message/phone_message.h"
+#endif/*TCFG_PHONE_MESSAGE_ENABLE*/
+
+#if TCFG_SMART_VOICE_ENABLE
+#include "smart_voice/smart_voice.h"
+#include "media/jl_kws.h"
+#if TCFG_CALL_KWS_SWITCH_ENABLE
+#include "btstack/avctp_user.h"
+#endif
+#endif
+#include "media/audio_gain_process.h"
+
+#ifdef SUPPORT_MS_EXTENSIONS
+/* #pragma bss_seg(".audio_decoder_bss") */
+/* #pragma data_seg(".audio_decoder_data") */
+#pragma const_seg(".audio_decoder_const")
+#pragma code_seg(".audio_decoder_code")
+#endif/*SUPPORT_MS_EXTENSIONS*/
+
+#include "sound_device.h"
+
+#if TCFG_ESCO_DL_NS_ENABLE
+#include "audio_ns.h"
+#define DL_NS_MODE 0
+#define DL_NS_NOISELEVEL 100.0f
+#define DL_NS_AGGRESSFACTOR 1.0f
+#define DL_NS_MINSUPPRESS 0.09f
+#endif/*TCFG_ESCO_DL_NS_ENABLE*/
+
+#if TCFG_AUDIO_ESCO_DL_NOISEGATE_ENABLE
+#include "audio_NoiseGate.h"
+static u8 *esco_dl_noisegate_buf = NULL;
+#endif/*TCFG_AUDIO_ESCO_DL_NOISEGATE_ENABLE*/
+
+#if ((defined TCFG_DIAFX_ENABLE) && TCFG_DIAFX_ENABLE)
+#include "diafx.h"
+#endif
+
+#if (TCFG_AUDIO_OUTPUT_IIS)
+#include "audio_iis.h"
+#endif
+
+#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+#include "icsd_adt_app.h"
+#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
+
+#define AUDIO_CODEC_SUPPORT_SYNC 1
+
+#define ESCO_DRC_EN 0 //通话下行增加限幅器处理,默认关闭,need en TCFG_DRC_ENABLE
+
+#if (!TCFG_DRC_ENABLE || !TCFG_PHONE_EQ_ENABLE)
+#undef ESCO_DRC_EN 0
+#define ESCO_DRC_EN 0
+#endif
+
+#if TCFG_AUDIO_ANC_ENABLE && TCFG_DRC_ENABLE
+#define MIX_OUT_DRC_EN 0/*mixout后增加一级限幅处理,默认关闭,need en TCFG_DRC_ENABLE*/
+#else
+#define MIX_OUT_DRC_EN 0/*mixout后增加一级限幅处理,默认关闭,need en TCFG_DRC_ENABLE*/
+#endif/*TCFG_AUDIO_ANC_ENABLE && TCFG_DRC_ENABLE*/
+
+
+
+#if AUDIO_OUT_EFFECT_ENABLE
+int audio_out_effect_open(void *priv, u16 sample_rate);
+void audio_out_effect_close(void);
+int audio_out_effect_stream_clear();
+struct dec_eq_drc *audio_out_effect = NULL;
+#endif /*AUDIO_OUT_EFFECT_ENABLE*/
+
+
+static u8 audio_out_effect_dis = 0;
+static u8 mix_out_remain = 0;
+
+struct tone_dec_hdl {
+ struct audio_decoder decoder;
+ void (*handler)(void *, int argc, int *argv);
+ void *priv;
+};
+
+
+#if AUDIO_SURROUND_CONFIG
+static u8 a2dp_surround_eff; //音效模式记录
+void a2dp_surround_set(u8 eff)
+{
+ a2dp_surround_eff = eff;
+}
+#endif
+
+
+struct esco_dec_hdl {
+ struct audio_decoder decoder;
+ struct audio_res_wait wait;
+ struct audio_mixer_ch mix_ch;
+ u32 coding_type;
+ u8 *frame;
+ u8 frame_len;
+ u8 offset;
+ u8 data_len;
+ u8 tws_mute_en;
+ u8 start;
+ u8 enc_start;
+ u8 frame_time;
+ u8 preempt;
+ u8 channels;
+ u8 ul_stream_open;
+ u16 slience_frames;
+ u16 sample_rate;
+ void *syncts;
+#if AUDIO_CODEC_SUPPORT_SYNC
+ void *ts_handle;
+ u8 ts_start;
+ u8 sync_step;
+#endif
+ u32 mix_ch_event_params[3];
+ u8 esco_len;
+ u16 remain;
+ int data[15];/*ALIGNED(4)*/
+
+#if TCFG_EQ_ENABLE&&TCFG_PHONE_EQ_ENABLE
+ struct dec_eq_drc *eq_drc;
+#endif//TCFG_PHONE_EQ_ENABLE
+
+#if TCFG_ESCO_DL_NS_ENABLE
+ void *dl_ns;
+ s16 dl_ns_out[NS_OUT_POINTS_MAX];
+ u16 dl_ns_offset;
+ u16 dl_ns_remain;
+#endif/*TCFG_ESCO_DL_NS_ENABLE*/
+
+#if TCFG_AUDIO_ESCO_LIMITER_ENABLE
+ struct audio_drc *limiter;
+#endif
+ u32 hash;
+ s16 fade_trigger;
+ s16 fade_volume;
+ s16 fade_step;
+#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+ u8 icsd_adt_state;
+#endif
+
+};
+
+#if AUDIO_OUTPUT_AUTOMUTE
+void *mix_out_automute_hdl = NULL;
+extern void mix_out_automute_open();
+extern void mix_out_automute_close();
+#endif //#if AUDIO_OUTPUT_AUTOMUTE
+
+#define AUDIO_DAC_DELAY_TIME 30
+
+#define DIGITAL_OdB_VOLUME 16384
+
+#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)||(TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_MONO_LR_DIFF)
+#define MIX_POINTS_NUM 256
+#else
+#define MIX_POINTS_NUM 256
+#endif
+
+s16 mix_buff[MIX_POINTS_NUM];
+
+/* #define MAX_SRC_NUMBER 3 */
+/* s16 audio_src_hw_filt[24 * 2 * MAX_SRC_NUMBER]; */
+
+static u16 dac_idle_delay_max = 10000;
+static u16 dac_idle_delay_cnt = 10000;
+static struct tone_dec_hdl *tone_dec = NULL;
+struct audio_decoder_task decode_task;
+extern struct audio_dac_hdl dac_hdl;
+struct audio_mixer mixer;
+extern struct dac_platform_data dac_data;
+extern struct audio_adc_hdl adc_hdl;
+
+struct esco_dec_hdl *esco_dec = NULL;
+
+
+int lmp_private_get_esco_remain_buffer_size();
+int lmp_private_get_esco_data_len();
+void *lmp_private_get_esco_packet(int *len, u32 *hash);
+void lmp_private_free_esco_packet(void *packet);
+extern int lmp_private_esco_suspend_resume(int flag);
+extern void user_sat16(s32 *in, s16 *out, u32 npoint);
+
+void *esco_play_sync_open(u8 channel, u16 sample_rate, u16 output_rate);
+//void audio_adc_init(void);
+void *audio_adc_open(void *param, const char *source);
+int audio_adc_sample_start(void *adc);
+
+void set_source_sample_rate(u32 sample_rate);
+u8 bt_audio_is_running(void);
+void audio_resume_all_decoder(void)
+{
+ audio_decoder_resume_all(&decode_task);
+}
+
+void audio_src_isr_deal(void)
+{
+ audio_resume_all_decoder();
+}
+
+__attribute__((weak))
+u8 get_sniff_out_status()
+{
+ return 0;
+}
+__attribute__((weak))
+void clear_sniff_out_status()
+{
+
+}
+u8 is_dac_power_off()
+{
+#if 1
+ return 1;
+#else
+//开机播完提示音再初始化蓝牙
+ if (a2dp_dec || esco_dec || get_call_status() != BT_CALL_HANGUP || !tone_get_status()) {
+ return 1;
+ }
+ return 0;
+#endif
+}
+
+#include "a2dp_dec.c" //这里将A2DP解码代码分解到另外文件
+
+#define AUDIO_DECODE_TASK_WAKEUP_TIME 4 //ms
+#if AUDIO_DECODE_TASK_WAKEUP_TIME
+#include "timer.h"
+static void audio_decoder_wakeup_timer(void *priv)
+{
+ //putchar('k');
+ audio_decoder_resume_all(&decode_task);
+}
+int audio_decoder_task_add_probe(struct audio_decoder_task *task)
+{
+ local_irq_disable();
+ if (task->wakeup_timer == 0) {
+ task->wakeup_timer = usr_timer_add(NULL, audio_decoder_wakeup_timer, AUDIO_DECODE_TASK_WAKEUP_TIME, 1);
+ log_i("audio_decoder_task_add_probe:%d\n", task->wakeup_timer);
+ }
+ local_irq_enable();
+ return 0;
+}
+int audio_decoder_task_del_probe(struct audio_decoder_task *task)
+{
+ log_i("audio_decoder_task_del_probe\n");
+ if (audio_decoder_task_wait_state(task) > 0) {
+ /*解码任务列表还有任务*/
+ return 0;
+ }
+
+ local_irq_disable();
+ if (task->wakeup_timer) {
+ log_i("audio_decoder_task_del_probe:%d\n", task->wakeup_timer);
+ usr_timer_del(task->wakeup_timer);
+ task->wakeup_timer = 0;
+ }
+ local_irq_enable();
+ return 0;
+}
+
+int audio_decoder_wakeup_modify(int msecs)
+{
+ if (decode_task.wakeup_timer) {
+ usr_timer_modify(decode_task.wakeup_timer, msecs);
+ }
+
+ return 0;
+}
+
+/*
+ * DA输出源启动后可使用DAC irq做唤醒,省去hi_timer
+ */
+int audio_decoder_wakeup_select(u8 source)
+{
+ if (source == 0) {
+ /*唤醒源为hi_timer*/
+ local_irq_disable();
+ if (!decode_task.wakeup_timer) {
+ decode_task.wakeup_timer = usr_timer_add(NULL, audio_decoder_wakeup_timer, AUDIO_DECODE_TASK_WAKEUP_TIME, 1);
+ }
+ local_irq_enable();
+ } else if (source == 1) {
+ /*唤醒源为输出目标中断*/
+ if (!sound_pcm_dev_is_running()) {
+ return audio_decoder_wakeup_select(0);
+ }
+
+ int err = sound_pcm_trigger_resume(a2dp_low_latency ? 2 : AUDIO_DECODE_TASK_WAKEUP_TIME,
+ NULL, audio_decoder_wakeup_timer);
+
+ if (err) {
+ return audio_decoder_wakeup_select(0);
+ }
+
+ local_irq_disable();
+ if (decode_task.wakeup_timer) {
+ usr_timer_del(decode_task.wakeup_timer);
+ decode_task.wakeup_timer = 0;
+ }
+ local_irq_enable();
+ }
+ return 0;
+}
+
+
+#endif/*AUDIO_DECODE_TASK_WAKEUP_TIME*/
+
+static u8 bt_dec_idle_query()
+{
+ if (a2dp_dec || esco_dec) {
+ return 0;
+ }
+
+ return 1;
+}
+REGISTER_LP_TARGET(bt_dec_lp_target) = {
+ .name = "bt_dec",
+ .is_idle = bt_dec_idle_query,
+};
+
+
+___interrupt
+static void audio_irq_handler()
+{
+ if (JL_AUDIO->DAC_CON & BIT(7)) {
+ JL_AUDIO->DAC_CON |= BIT(6);
+ if (JL_AUDIO->DAC_CON & BIT(5)) {
+ audio_decoder_resume_all(&decode_task);
+ audio_dac_irq_handler(&dac_hdl);
+ }
+ }
+
+ if (JL_AUDIO->ADC_CON & BIT(7)) {
+ JL_AUDIO->ADC_CON |= BIT(6);
+ if ((JL_AUDIO->ADC_CON & BIT(5)) && (JL_AUDIO->ADC_CON & BIT(4))) {
+ audio_adc_irq_handler(&adc_hdl);
+ }
+ }
+}
+
+#if AUDIO_OUTPUT_AUTOMUTE
+void usr_mute_set(u8 flag)
+{
+ /*gpio_set_direction(IO_PORTA_02,1);
+ gpio_set_pull_down(IO_PORTA_02,0);
+ gpio_set_pull_up (IO_PORTA_02,0);
+
+ gpio_set_direction(IO_PORTA_03,0);
+ gpio_set_pull_down(IO_PORTA_03,0);
+ gpio_set_pull_up (IO_PORTA_03,0);
+ gpio_set_output_value(IO_PORTA_03,flag);*/
+}
+void audio_mix_out_automute_mute(u8 mute)
+{
+ printf(">>>>>>>>>>>>>>>>>>>> %s\n", mute ? ("MUTE") : ("UNMUTE"));
+ usr_mute_set(mute);
+}
+
+/* #define AUDIO_E_DET_UNMUTE (0x00) */
+/* #define AUDIO_E_DET_MUTE (0x01) */
+void mix_out_automute_handler(u8 event, u8 ch)
+{
+ printf(">>>> ch:%d %s\n", ch, event ? ("MUTE") : ("UNMUTE"));
+#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_AND_MUSIC_MUTEX)
+ if (ch == sound_pcm_dev_channel_mapping(ch)) {
+ printf("[DHA]>>>>>>>>>>>>>>>>>>>> %s\n", event ? ("MUTE") : ("UNMUTE"));
+ if (a2dp_dec) {
+ if (event) {
+ audio_hearing_aid_resume();
+ } else {
+ audio_hearing_aid_suspend();
+ }
+ }
+ }
+#else
+ sound_pcm_dev_channel_mute(BIT(ch), event);
+ if (ch == sound_pcm_dev_channel_mapping(ch)) {
+ audio_mix_out_automute_mute(event);
+ }
+#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
+}
+
+void mix_out_automute_skip(u8 skip)
+{
+ u8 mute = !skip;
+ if (mix_out_automute_hdl) {
+ audio_energy_detect_skip(mix_out_automute_hdl, 0xFFFF, skip);
+ mix_out_automute_handler(mute, sound_pcm_dev_channel_mapping(0));
+ }
+}
+
+void mix_out_automute_open()
+{
+ if (mix_out_automute_hdl) {
+ printf("mix_out_automute is already open !\n");
+ return;
+ }
+ audio_energy_detect_param e_det_param = {0};
+ e_det_param.mute_energy = 5;
+ e_det_param.unmute_energy = 10;
+ e_det_param.mute_time_ms = 1000;
+ e_det_param.unmute_time_ms = 50;
+ e_det_param.count_cycle_ms = 10;
+ e_det_param.sample_rate = 44100;
+ e_det_param.event_handler = mix_out_automute_handler;
+ e_det_param.ch_total = sound_pcm_dev_channel_mapping(0);
+ e_det_param.dcc = 1;
+ mix_out_automute_hdl = audio_energy_detect_open(&e_det_param);
+}
+
+void mix_out_automute_close()
+{
+ if (mix_out_automute_hdl) {
+ audio_energy_detect_close(mix_out_automute_hdl);
+ }
+}
+#endif //#if AUDIO_OUTPUT_AUTOMUTE
+
+
+static void mixer_event_handler(struct audio_mixer *mixer, int event)
+{
+ switch (event) {
+ case MIXER_EVENT_CH_OPEN:
+ if ((audio_mixer_get_ch_num(mixer) == 1) || (audio_mixer_get_start_ch_num(mixer) == 1)) {
+#if AUDIO_OUTPUT_AUTOMUTE
+ audio_energy_detect_sample_rate_update(mix_out_automute_hdl, audio_mixer_get_sample_rate(mixer));
+#endif //#if AUDIO_OUTPUT_AUTOMUTE
+#if TCFG_APP_FM_EMITTER_EN
+
+#else
+#if TCFG_AUDIO_ANC_ENABLE
+ audio_anc_mix_process(1);
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+ sound_pcm_dev_start(NULL, audio_mixer_get_sample_rate(mixer), app_audio_get_volume(APP_AUDIO_CURRENT_STATE));
+#endif
+#if AUDIO_OUT_EFFECT_ENABLE
+ if (!audio_out_effect_dis) {
+ audio_out_effect_open(mixer, audio_mixer_get_sample_rate(mixer));
+ }
+#endif
+ mix_out_remain = 0;
+#if MIX_OUT_DRC_EN
+ mix_out_drc_close();
+ mix_out_drc_open(audio_mixer_get_sample_rate(mixer));
+#endif//MIX_OUT_DRC_EN
+
+ }
+ break;
+ case MIXER_EVENT_CH_CLOSE:
+ if (audio_mixer_get_ch_num(mixer) == 0) {
+#if AUDIO_OUT_EFFECT_ENABLE
+ audio_out_effect_close();
+#endif
+#if MIX_OUT_DRC_EN
+ mix_out_drc_close();
+#endif//MIX_OUT_DRC_EN
+
+#if TCFG_APP_FM_EMITTER_EN
+
+#else
+ sound_pcm_dev_stop(NULL);
+#if TCFG_AUDIO_ANC_ENABLE
+ audio_anc_mix_process(0);
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+#endif
+ }
+ break;
+ }
+}
+
+static int mix_probe_handler(struct audio_mixer *mixer)
+{
+ return 0;
+}
+
+static int mix_output_handler(struct audio_mixer *mixer, s16 *data, u16 len)
+{
+ int rlen = len;
+ int wlen = 0;
+ if (!mix_out_remain) {
+#if MIX_OUT_DRC_EN
+ mix_out_drc_run(data, len);
+#endif//MIX_OUT_DRC_EN
+
+#if ((defined TCFG_DIAFX_ENABLE) && TCFG_DIAFX_ENABLE)
+ jl_platform_diafx_run(data, len >> 1);
+#endif
+
+ }
+ /* audio_aec_refbuf(data, len); */
+
+#if AUDIO_OUTPUT_AUTOMUTE
+ audio_energy_detect_run(mix_out_automute_hdl, data, len);
+#endif //#if AUDIO_OUTPUT_AUTOMUTE
+#if TCFG_APP_FM_EMITTER_EN
+ fm_emitter_cbuf_write((u8 *)data, len);
+#else
+ wlen = sound_pcm_dev_write(NULL, data, len);
+ /*printf("0x%x, %d, %d\n", (u32)data, len, wlen);*/
+ /*
+ if (wlen == len) {
+ audio_decoder_resume_all(&decode_task);
+ }
+ */
+#endif/*TCFG_APP_FM_EMITTER_EN*/
+ if (wlen >= len) {
+ mix_out_remain = 0;
+ } else {
+ mix_out_remain = 1;
+ }
+
+ return wlen;
+}
+
+#if AUDIO_OUT_EFFECT_ENABLE
+static int mix_output_effect_handler(struct audio_mixer *mixer, s16 *data, u16 len)
+{
+ if (!audio_out_effect) {
+ return mix_output_handler(mixer, data, len);
+ }
+ if (audio_out_effect && audio_out_effect->async) {
+ return eq_drc_run(audio_out_effect, data, len);
+ }
+
+
+ if (!audio_out_effect->remain) {
+ if (audio_out_effect && !audio_out_effect->async) {
+ eq_drc_run(audio_out_effect, data, len);
+ }
+ }
+ int wlen = mix_output_handler(mixer, data, len);
+ if (wlen == len) {
+ audio_out_effect->remain = 0;
+ } else {
+ audio_out_effect->remain = 1;
+ }
+ return wlen;
+}
+#endif//AUDIO_OUT_EFFECT_ENABLE
+
+static const struct audio_mix_handler mix_handler = {
+ .mix_probe = mix_probe_handler,
+
+#if AUDIO_OUT_EFFECT_ENABLE
+ .mix_output = mix_output_effect_handler,
+#else
+ .mix_output = mix_output_handler,
+#endif//AUDIO_OUT_EFFECT_ENABLE
+};
+
+static const u8 msbc_mute_data[] = {
+ 0xAD, 0x00, 0x00, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6D, 0xB6, 0xDD, 0xDB, 0x6D, 0xB7, 0x76,
+ 0xDB, 0x6D, 0xDD, 0xB6, 0xDB, 0x77, 0x6D, 0xB6, 0xDD, 0xDB, 0x6D, 0xB7, 0x76, 0xDB, 0x6D, 0xDD,
+ 0xB6, 0xDB, 0x77, 0x6D, 0xB6, 0xDD, 0xDB, 0x6D, 0xB7, 0x76, 0xDB, 0x6D, 0xDD, 0xB6, 0xDB, 0x77,
+ 0x6D, 0xB6, 0xDD, 0xDB, 0x6D, 0xB7, 0x76, 0xDB, 0x6C, 0x00,
+};
+
+static int headcheck(u8 *buf)
+{
+ int sync_word = buf[0] | ((buf[1] & 0x0f) << 8);
+ return (sync_word == 0x801) && (buf[2] == 0xAD);
+}
+
+static int esco_dump_rts_info(struct rt_stream_info *pkt)
+{
+ u32 hash = 0xffffffff;
+ int read_len = 0;
+ pkt->baddr = lmp_private_get_esco_packet(&read_len, &hash);
+ pkt->seqn = hash;
+ /* printf("hash0=%d,%d ",hash,pkt->baddr ); */
+ if (pkt->baddr && read_len) {
+ pkt->remain_len = lmp_private_get_esco_remain_buffer_size();
+ pkt->data_len = lmp_private_get_esco_data_len();
+ return 0;
+ }
+ if (read_len == -EINVAL) {
+ //puts("----esco close\n");
+ return -EINVAL;
+ }
+ if (read_len < 0) {
+
+ return -ENOMEM;
+ }
+ return ENOMEM;
+}
+
+static int esco_dec_get_frame(struct audio_decoder *decoder, u8 **frame)
+{
+ int len = 0;
+ u32 hash = 0;
+ struct esco_dec_hdl *dec = container_of(decoder, struct esco_dec_hdl, decoder);
+
+__again:
+ if (dec->frame) {
+ int len = dec->frame_len - dec->offset;
+ if (len > dec->esco_len - dec->data_len) {
+ len = dec->esco_len - dec->data_len;
+ }
+ /*memcpy((u8 *)dec->data + dec->data_len, msbc_mute_data, sizeof(msbc_mute_data));*/
+ memcpy((u8 *)dec->data + dec->data_len, dec->frame + dec->offset, len);
+ dec->offset += len;
+ dec->data_len += len;
+ if (dec->offset == dec->frame_len) {
+ lmp_private_free_esco_packet(dec->frame);
+ dec->frame = NULL;
+ }
+ }
+ if (dec->data_len < dec->esco_len) {
+ dec->frame = lmp_private_get_esco_packet(&len, &hash);
+ /* printf("hash1=%d,%d ",hash,dec->frame ); */
+ if (len <= 0) {
+ printf("rlen=%d ", len);
+ return -EIO;
+ }
+#if AUDIO_CODEC_SUPPORT_SYNC
+ u32 timestamp;
+ if (dec->ts_handle) {
+ timestamp = esco_audio_timestamp_update(dec->ts_handle, hash);
+ if (dec->syncts && (((hash - dec->hash) & 0x7ffffff) == dec->frame_time)) {
+ audio_syncts_next_pts(dec->syncts, timestamp);
+ }
+ dec->hash = hash;
+ if (!dec->ts_start) {
+ dec->ts_start = 1;
+ dec->mix_ch_event_params[2] = timestamp;
+ }
+ }
+#endif
+#if (defined(TCFG_PHONE_MESSAGE_ENABLE) && (TCFG_PHONE_MESSAGE_ENABLE))
+ phone_message_enc_write(dec->frame + 2, len - 2);
+#endif
+ dec->offset = 0;
+ dec->frame_len = len;
+ goto __again;
+ }
+ *frame = (u8 *)dec->data;
+ return dec->esco_len;
+}
+
+static void esco_dec_put_frame(struct audio_decoder *decoder, u8 *frame)
+{
+ struct esco_dec_hdl *dec = container_of(decoder, struct esco_dec_hdl, decoder);
+
+ dec->data_len = 0;
+ /*lmp_private_free_esco_packet((void *)frame);*/
+}
+
+static const struct audio_dec_input esco_input = {
+ .coding_type = AUDIO_CODING_MSBC,
+ .data_type = AUDIO_INPUT_FRAME,
+ .ops = {
+ .frame = {
+ .fget = esco_dec_get_frame,
+ .fput = esco_dec_put_frame,
+ }
+ }
+};
+
+u32 lmp_private_clear_sco_packet(u8 clear_num);
+static void esco_dec_clear_all_packet(struct esco_dec_hdl *dec)
+{
+ lmp_private_clear_sco_packet(0xff);
+}
+
+static int esco_dec_probe_handler(struct audio_decoder *decoder)
+{
+ struct esco_dec_hdl *dec = container_of(decoder, struct esco_dec_hdl, decoder);
+ int err = 0;
+ int find_packet = 0;
+ struct rt_stream_info rts_info = {0};
+ err = esco_dump_rts_info(&rts_info);
+ if (err == -EINVAL) {
+ return err;
+ }
+ if (err || !dec->enc_start) {
+ audio_decoder_suspend(decoder, 0);
+ return -EAGAIN;
+ }
+
+#if TCFG_USER_TWS_ENABLE
+ if (tws_network_audio_was_started()) {
+ /*清除从机声音加入标志*/
+ dec->slience_frames = 20;
+ tws_network_local_audio_start();
+ }
+#endif
+ if (dec->preempt) {
+ dec->preempt = 0;
+ dec->slience_frames = 20;
+ }
+ return err;
+
+}
+
+
+
+#define MONO_TO_DUAL_POINTS 30
+
+
+//////////////////////////////////////////////////////////////////////////////
+static inline void audio_pcm_mono_to_dual(s16 *dual_pcm, s16 *mono_pcm, int points)
+{
+ //printf("<%d,%x>",points,mono_pcm);
+ s16 *mono = mono_pcm;
+ int i = 0;
+ u8 j = 0;
+
+ for (i = 0; i < points; i++, mono++) {
+ *dual_pcm++ = *mono;
+ *dual_pcm++ = *mono;
+ }
+}
+/*level:0~15*/
+static const u16 esco_dvol_tab[] = {
+ 0, //0
+ 111,//1
+ 161,//2
+ 234,//3
+ 338,//4
+ 490,//5
+ 708,//6
+ 1024,//7
+ 1481,//8
+ 2142,//9
+ 3098,//10
+ 4479,//11
+ 6477,//12
+ 9366,//13
+ 14955,//14
+ 16384 //15
+};
+
+
+/*
+*********************************************************************
+* ESCO Decode mix filter
+* Description: ESCO语音解码输出接入mix滤镜
+* Arguments : data - 音频数据,len - 音频byte长度
+* Return : 输出到后级的数据长度
+* Note(s) : 音频后级PCM设备为单声道直接写入mixer,PCM设备为双声道,
+* 这里通过1 to 2ch的处理将数据写入mixer,并返回消耗的原始
+* 数据长度。
+*********************************************************************
+*/
+static s16 two_ch_data[MONO_TO_DUAL_POINTS * 2];
+static s16 dual_offset_points = 0;
+static s16 dual_total_points = 0;
+static int esco_decoder_mix_filter(struct esco_dec_hdl *dec, s16 *data, int len)
+{
+ int wlen = 0;
+ s16 point_num = 0;
+ u8 mono_to_dual = 0;
+ s16 *mono_data = (s16 *)data;
+ u16 remain_points = (len >> 1);
+
+ /*
+ *如果dac输出是双声道,因为esco解码出来时单声道
+ *所以这里要根据dac通道确定是否做单变双
+ */
+
+ mono_to_dual = sound_pcm_dev_channel_mapping(1) == 2 ? 1 : 0;
+
+ if (mono_to_dual) {
+ do {
+ if (dual_offset_points < dual_total_points) {
+ int tmp_len = audio_mixer_ch_write(&dec->mix_ch, &two_ch_data[dual_offset_points], (dual_total_points - dual_offset_points) << 1);
+ dual_offset_points += tmp_len >> 1;
+ if (tmp_len < ((dual_total_points - dual_offset_points) << 1)) {
+ break;
+ }
+ if (dual_offset_points < dual_total_points) {
+ continue;
+ }
+ }
+ point_num = MONO_TO_DUAL_POINTS;
+ if (point_num >= remain_points) {
+ point_num = remain_points;
+ }
+ audio_pcm_mono_to_dual(two_ch_data, mono_data, point_num);
+ dual_offset_points = 0;
+ dual_total_points = point_num << 1;
+ int tmp_len = audio_mixer_ch_write(&dec->mix_ch, &two_ch_data[dual_offset_points], (dual_total_points - dual_offset_points) << 1);
+ dual_offset_points += tmp_len >> 1;
+ wlen += dual_total_points << 1;
+ remain_points -= (dual_total_points >> 1);
+ mono_data += point_num;
+ if (tmp_len < (dual_total_points - dual_offset_points) << 1) {
+ break;
+ }
+ } while (remain_points);
+ } else {
+
+ wlen = audio_mixer_ch_write(&dec->mix_ch, data, len);
+ }
+
+ wlen = mono_to_dual ? (wlen >> 1) : wlen;
+
+ return wlen;
+}
+
+
+/*
+*********************************************************************
+* ESCO Decode DL_NS filter
+* Description: ESCO语音解码输出下行降噪滤镜
+* Arguments : data - 音频数据,len - 音频byte长度
+* Return : 输出到后级的数据长度
+* Note(s) : 下行降噪通话接通前为直通,接通后进行NS RUN处理。
+*********************************************************************
+*/
+static int esco_decoder_dl_ns_filter(struct esco_dec_hdl *dec, s16 *data, int len)
+{
+#if TCFG_ESCO_DL_NS_ENABLE
+ int wlen = 0;
+ int ret_len = len;
+
+ if (dec->dl_ns_remain) {
+ wlen = esco_decoder_mix_filter(dec, dec->dl_ns_out + (dec->dl_ns_offset / 2), dec->dl_ns_remain);
+ dec->dl_ns_offset += wlen;
+ dec->dl_ns_remain -= wlen;
+ if (dec->dl_ns_remain) {
+ return 0;
+ }
+ }
+
+ if (get_call_status() == BT_CALL_ACTIVE) {
+ /*接通的时候再开始做降噪*/
+ int ns_out = audio_ns_run(dec->dl_ns, data, dec->dl_ns_out, len);
+ //输入消耗完毕,没有输出
+ if (ns_out == 0) {
+ return len;
+ }
+ len = ns_out;
+ } else {
+ memcpy(dec->dl_ns_out, data, len);
+ }
+ wlen = esco_decoder_mix_filter(dec, dec->dl_ns_out, len);
+ dec->dl_ns_offset = wlen;
+ dec->dl_ns_remain = len - wlen;
+ return ret_len;
+#else
+ return 0;
+#endif/*TCFG_ESCO_DL_NS_ENABLE*/
+}
+
+/*
+*********************************************************************
+* ESCO output after syncts
+* Description: esco同步滤镜后的数据流滤镜
+* Arguments : data - 音频数据,len - 音频byte长度
+* Return : 输出到后级的数据长度
+* Note(s) : 音频同步后使用。
+*********************************************************************
+*/
+static int esco_output_after_syncts_filter(void *priv, s16 *data, int len)
+{
+ struct esco_dec_hdl *dec = (struct esco_dec_hdl *)priv;
+ int wlen = 0;
+ /*
+ *如果dac输出是双声道,因为esco解码出来时单声道
+ *所以这里要根据dac通道确定是否做单变双
+ */
+
+#if TCFG_ESCO_DL_NS_ENABLE
+ wlen = esco_decoder_dl_ns_filter(dec, data, len);
+#else
+ wlen = esco_decoder_mix_filter(dec, data, len);
+#endif
+
+ return wlen;
+}
+/*
+ *slience_frames结束前增加淡入处理,防止声音突变,听到一下的不适感
+ * */
+static void esco_fade_in(struct esco_dec_hdl *dec, s16 *data, int len)
+{
+ if (dec->fade_trigger) {
+ int tmp = 0;
+ s16 *p = data;
+ u16 frames = (len >> 1) / dec->channels;
+ for (int i = 0; i < frames; i++) {
+ for (int j = 0; j < dec->channels; j++) {
+ tmp = *p;
+ *p++ = dec->fade_volume * tmp / DIGITAL_OdB_VOLUME;
+ }
+ dec->fade_volume += dec->fade_step;
+ if (dec->fade_volume > DIGITAL_OdB_VOLUME) {
+ dec->fade_volume = DIGITAL_OdB_VOLUME;
+ break;
+ }
+ }
+ if (dec->fade_volume == DIGITAL_OdB_VOLUME) {
+ dec->fade_trigger = 0;
+ }
+ }
+}
+/*
+*********************************************************************
+* ESCO Decode Output
+* Description: 蓝牙通话解码输出
+* Arguments : *priv 数据包错误表示(1 == error)
+* Return : 输出到后级的数据长度
+* Note(s) : dec->remain不等于0表示解码输出的数据后级没有消耗完
+* 也就是说,只有(dec->remain == 0)的情况,才是新解码
+* 出来的数据,才是需要做后处理的数据,否则直接输出到
+* 后级即可。
+*********************************************************************
+*/
+static int esco_dec_output_handler(struct audio_decoder *decoder, s16 *buf, int size, void *priv)
+{
+ int wlen = 0;
+ int ret_len = size;
+ int len = size;
+ short *data = buf;
+ struct esco_dec_hdl *dec = container_of(decoder, struct esco_dec_hdl, decoder);
+
+ /*非上次残留数据,进行后处理*/
+ if (!dec->remain) {
+#if (defined(TCFG_PHONE_MESSAGE_ENABLE) && (TCFG_PHONE_MESSAGE_ENABLE))
+ phone_message_call_api_esco_out_data(data, len);
+#endif/*TCFG_PHONE_MESSAGE_ENABLE*/
+ if (priv) {
+ audio_plc_run(data, len, *(u8 *)priv);
+ }
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_run(CALL_DVOL, data, len);
+ u16 dvol_val = esco_dvol_tab[app_var.aec_dac_gain];
+ for (u16 i = 0; i < len / 2; i++) {
+ s32 tmp_data = data[i];
+ if (tmp_data < 0) {
+ tmp_data = -tmp_data;
+ tmp_data = (tmp_data * dvol_val) >> 14;
+ tmp_data = -tmp_data;
+ } else {
+ tmp_data = (tmp_data * dvol_val) >> 14;
+ }
+ data[i] = tmp_data;
+ }
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+#if TCFG_AUDIO_ESCO_DL_NOISEGATE_ENABLE
+ /*来电去电铃声不做处理*/
+ if ((get_call_status() == BT_CALL_ACTIVE) && esco_dl_noisegate_buf) {
+ audio_noise_gate_run(esco_dl_noisegate_buf, data, data, len / 2);
+ }
+#endif/*TCFG_AUDIO_ESCO_DL_NOISEGATE_ENABLE*/
+
+
+#if TCFG_AUDIO_ESCO_LIMITER_ENABLE
+ if (dec->limiter) {
+ esco_limiter_run(dec->limiter, data, len);
+ }
+#endif
+
+#if TCFG_EQ_ENABLE&&TCFG_PHONE_EQ_ENABLE
+ eq_drc_run(dec->eq_drc, data, len);
+#endif//TCFG_PHONE_EQ_ENABLE
+
+ if (dec->slience_frames) {
+ if (dec->slience_frames == 1) {
+ int fade_time = 6;
+ int sample_rate = dec->decoder.fmt.sample_rate;
+ dec->fade_step = DIGITAL_OdB_VOLUME / ((fade_time * sample_rate) / 1000);
+ dec->fade_trigger = 1;
+ dec->fade_volume = 0;
+ } else {
+ dec->fade_trigger = 0;
+ dec->fade_volume = 0;
+ memset(data, 0x0, len);
+ }
+ dec->slience_frames--;
+ }
+ esco_fade_in(dec, data, len);
+
+ }
+
+#if AUDIO_CODEC_SUPPORT_SYNC
+ if (dec->syncts) {
+ wlen = audio_syncts_frame_filter(dec->syncts, data, len);
+ if (wlen < len) {
+ audio_syncts_trigger_resume(dec->syncts, (void *)decoder, audio_filter_resume_decoder);
+ }
+ goto ret_handle;
+ }
+#endif
+ wlen = esco_output_after_syncts_filter(dec, data, len);
+
+ret_handle:
+
+ dec->remain = wlen == len ? 0 : 1;
+
+ return wlen;
+}
+
+static int esco_dec_post_handler(struct audio_decoder *decoder)
+{
+
+ return 0;
+}
+
+static const struct audio_dec_handler esco_dec_handler = {
+ .dec_probe = esco_dec_probe_handler,
+ .dec_output = esco_dec_output_handler,
+ .dec_post = esco_dec_post_handler,
+};
+
+void esco_dec_release()
+{
+#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+ if (get_icsd_adt_mode()) {
+ audio_icsd_adt_open(0);
+ }
+#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
+
+ audio_decoder_task_del_wait(&decode_task, &esco_dec->wait);
+ free(esco_dec);
+ esco_dec = NULL;
+}
+
+void esco_dec_close();
+
+static void esco_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
+{
+ switch (argv[0]) {
+ case AUDIO_DEC_EVENT_END:
+ puts("AUDIO_DEC_EVENT_END\n");
+ esco_dec_close();
+ break;
+ }
+}
+
+u32 source_sr;
+void set_source_sample_rate(u32 sample_rate)
+{
+ source_sr = sample_rate;
+}
+
+u16 get_source_sample_rate()
+{
+ if (bt_audio_is_running()) {
+ return source_sr;
+ }
+ return 0;
+}
+
+int esco_dec_dac_gain_set(u8 gain)
+{
+ app_var.aec_dac_gain = gain;
+ if (esco_dec) {
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL_HW)
+ app_audio_set_max_volume(APP_AUDIO_STATE_CALL, gain);
+ app_audio_set_volume(APP_AUDIO_STATE_CALL, app_audio_get_volume(APP_AUDIO_STATE_CALL), 1);
+#else
+ sound_pcm_dev_set_analog_gain(gain);
+#endif/*SYS_VOL_TYPE*/
+ }
+ return 0;
+}
+
+
+#define ESCO_SIRI_WAKEUP() (app_var.siri_stu == 1 || app_var.siri_stu == 2)
+
+static int esco_decoder_syncts_setup(struct esco_dec_hdl *dec)
+{
+ int err = 0;
+#if AUDIO_CODEC_SUPPORT_SYNC
+#define ESCO_DELAY_TIME 60
+#define ESCO_RECOGNTION_TIME 220
+ int delay_time = ESCO_DELAY_TIME;
+ if (get_sniff_out_status()) {
+ clear_sniff_out_status();
+ if (ESCO_SIRI_WAKEUP()) {
+ /*fix : Siri出sniff蓝牙数据到音频通路延迟过长,容易引入同步的问题*/
+ delay_time = ESCO_RECOGNTION_TIME;
+ }
+ }
+ struct audio_syncts_params params = {0};
+ int sample_rate = dec->decoder.fmt.sample_rate;
+
+ params.nch = dec->decoder.fmt.channel;
+
+ params.pcm_device = sound_pcm_sync_device_select();//PCM_INSIDE_DAC;
+ params.rout_sample_rate = sound_pcm_match_sample_rate(sample_rate);
+ params.network = AUDIO_NETWORK_BT2_1;
+ params.rin_sample_rate = sample_rate;
+ params.priv = dec;
+ params.factor = TIME_US_FACTOR;
+ params.output = (int (*)(void *, void *, int))esco_output_after_syncts_filter;
+
+ bt_audio_sync_nettime_select(0);//0 - 主机,1 - tws, 2 - BLE
+ u8 frame_clkn = dec->esco_len >= 60 ? 12 : 6;
+ dec->ts_handle = esco_audio_timestamp_create(frame_clkn, delay_time, TIME_US_FACTOR);
+ dec->frame_time = frame_clkn;
+ audio_syncts_open(&dec->syncts, ¶ms);
+ if (!err) {
+ dec->mix_ch_event_params[0] = (u32)&dec->mix_ch;
+ dec->mix_ch_event_params[1] = (u32)dec->syncts;
+ audio_mixer_ch_set_event_handler(&dec->mix_ch, (void *)dec->mix_ch_event_params, audio_mix_ch_event_handler);
+ }
+ dec->ts_start = 0;
+#endif
+ return err;
+}
+
+static void esco_decoder_syncts_free(struct esco_dec_hdl *dec)
+{
+#if AUDIO_CODEC_SUPPORT_SYNC
+ if (dec->ts_handle) {
+ esco_audio_timestamp_close(dec->ts_handle);
+ dec->ts_handle = NULL;
+ }
+ if (dec->syncts) {
+ audio_syncts_close(dec->syncts);
+ dec->syncts = NULL;
+ }
+#endif
+}
+
+int esco_ul_stream_open(u32 sample_rate, u16 esco_len, u32 codec_type)
+{
+ int err = 0;
+ printf("esco_ul_open,sr = %d,len = %d,type = %x\n", sample_rate, esco_len, codec_type);
+ if (esco_dec->start == 0) {
+ printf("esco_ul_stream close ing,return\n");
+ return 0;
+ }
+ if (esco_dec->ul_stream_open) {
+ printf("esco_ul_stream_open now,return\n");
+ return 0;
+ }
+ esco_dec->ul_stream_open = 1;
+ err = 0;//audio_aec_init(sample_rate);
+ if (err) {
+ printf("audio_aec_init failed:%d", err);
+ //goto __err3;
+ }
+
+ err = esco_enc_open(codec_type, esco_len);
+ if (err) {
+ printf("audio_enc_open failed:%d", err);
+ //goto __err3;
+ }
+ return err;
+}
+
+int esco_ul_stream_close(void)
+{
+ printf("esco_ul_stream_close\n");
+ if (esco_dec->ul_stream_open == 0) {
+ printf("esco_ul_stream_closed,return\n");
+ return 0;
+ }
+ //audio_aec_close();
+ //esco_enc_close();
+ esco_dec->ul_stream_open = 0;
+ return 0;
+}
+
+int esco_ul_stream_switch(u8 en)
+{
+ if (esco_dec == NULL) {
+ printf("esco_ul_stream_close now,return\n");
+ return 0;
+ }
+ if (en) {
+ return esco_ul_stream_open(esco_dec->sample_rate, esco_dec->esco_len, esco_dec->coding_type);
+ } else {
+ return esco_ul_stream_close();
+ }
+}
+
+int esco_enc_reset(void)
+{
+ if (esco_dec == NULL) {
+ printf("esco_ul_stream_close now,return\n");
+ return 0;
+ }
+ esco_enc_close();
+ esco_enc_open(esco_dec->coding_type, esco_dec->esco_len);
+ return 0;
+}
+
+int esco_dec_start()
+{
+ int err;
+ struct audio_fmt f;
+ enum audio_channel channel;
+ struct esco_dec_hdl *dec = esco_dec;
+ u16 mix_buf_len_fix = 240;
+
+ if (!esco_dec) {
+ return -EINVAL;
+ }
+
+#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+ /*通话前关闭adt*/
+ esco_dec->icsd_adt_state = audio_icsd_adt_is_running();
+ if (esco_dec->icsd_adt_state) {
+ audio_icsd_adt_close(0);
+ }
+#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
+
+ err = audio_decoder_open(&dec->decoder, &esco_input, &decode_task);
+ if (err) {
+ goto __err1;
+ }
+
+ audio_decoder_set_handler(&dec->decoder, &esco_dec_handler);
+ audio_decoder_set_event_handler(&dec->decoder, esco_dec_event_handler, 0);
+
+ if (dec->coding_type == AUDIO_CODING_MSBC) {
+ f.coding_type = AUDIO_CODING_MSBC;
+ f.sample_rate = 16000;
+ f.channel = 1;
+ } else if (dec->coding_type == AUDIO_CODING_CVSD) {
+ f.coding_type = AUDIO_CODING_CVSD;
+ f.sample_rate = 8000;
+ f.channel = 1;
+ mix_buf_len_fix = 120;
+ }
+ dec->sample_rate = f.sample_rate;
+ set_source_sample_rate(f.sample_rate);
+
+ err = audio_decoder_set_fmt(&dec->decoder, &f);
+ if (err) {
+ goto __err2;
+ }
+ dec->channels = f.channel;
+
+ /*
+ *虽然mix有直通的处理,但是如果混合第二种声音进来的时候,就会按照mix_buff
+ *的大小来混合输出,该buff太大,回导致dac没有连续的数据播放
+ */
+ /*audio_mixer_set_output_buf(&mixer, mix_buff, sizeof(mix_buff) / 8);*/
+ audio_mixer_set_output_buf(&mixer, mix_buff, mix_buf_len_fix);
+ audio_mixer_ch_open(&dec->mix_ch, &mixer);
+ audio_mixer_ch_set_sample_rate(&dec->mix_ch, sound_pcm_match_sample_rate(f.sample_rate));
+ audio_mixer_ch_set_resume_handler(&dec->mix_ch, (void *)&dec->decoder, (void (*)(void *))audio_decoder_resume);
+
+
+
+#if TCFG_AUDIO_ESCO_DL_NOISEGATE_ENABLE
+ esco_dl_noisegate_buf = audio_noise_gate_open(300, 5, ESCO_NOISEGATE_THR, ESCO_NOISEGATE_GAIN, 16000, 1);
+#endif/*TCFG_AUDIO_ESCO_DL_NOISEGATE_ENABLE*/
+
+#if TCFG_AUDIO_ESCO_LIMITER_ENABLE
+ dec->limiter = esco_limiter_open(f.sample_rate, f.channel);
+#endif/*TCFG_AUDIO_ESCO_LIMITER_ENABLE*/
+
+#if TCFG_EQ_ENABLE&&TCFG_PHONE_EQ_ENABLE
+ u8 drc_en = 0;
+#if TCFG_DRC_ENABLE&&ESCO_DRC_EN
+ drc_en = 1;
+#endif//ESCO_DRC_EN
+
+ dec->eq_drc = esco_eq_drc_setup(&dec->mix_ch, (eq_output_cb)audio_mixer_ch_write, f.sample_rate, f.channel, 0, drc_en);
+#endif//TCFG_PHONE_EQ_ENABLE
+
+ app_audio_state_switch(APP_AUDIO_STATE_CALL, BT_CALL_VOL_LEAVE_MAX);
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_open(CALL_DVOL, app_audio_get_volume(APP_AUDIO_STATE_CALL), CALL_DVOL_MAX, CALL_DVOL_FS, -1);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+ printf("max_vol:%d,call_vol:%d", app_var.aec_dac_gain, app_audio_get_volume(APP_AUDIO_STATE_CALL));
+ app_audio_set_volume(APP_AUDIO_STATE_CALL, app_var.call_volume, 1);
+
+#if AUDIO_CODEC_SUPPORT_SYNC
+ esco_decoder_syncts_setup(dec);
+#endif/*AUDIO_CODEC_SUPPORT_SYNC*/
+
+ /*plc调用需要考虑到代码overlay或者压缩操作*/
+ audio_plc_open(f.sample_rate);
+
+ sound_pcm_dev_set_delay_time(30, 50);
+ lmp_private_esco_suspend_resume(2);
+ err = audio_decoder_start(&dec->decoder);
+ if (err) {
+ goto __err3;
+ }
+ sound_pcm_dev_try_power_on();
+ audio_out_effect_dis = 1;//通话模式关闭高低音
+
+ dec->start = 1;
+ dec->remain = 0;
+
+#if TCFG_ESCO_DL_NS_ENABLE
+ dec->dl_ns = audio_ns_open(f.sample_rate, DL_NS_MODE, DL_NS_NOISELEVEL, DL_NS_AGGRESSFACTOR, DL_NS_MINSUPPRESS);
+ dec->dl_ns_remain = 0;
+#endif/*TCFG_ESCO_DL_NS_ENABLE*/
+
+ err = esco_ul_stream_open(f.sample_rate, dec->esco_len, dec->coding_type);
+
+#if (TCFG_AUDIO_OUTPUT_IIS)
+ audio_aec_ref_src_open(TCFG_IIS_SR, f.sample_rate);
+#endif
+
+ clk_set_sys_lock(96 * (1000000L), 0);
+ audio_codec_clock_set(AUDIO_ESCO_MODE, dec->coding_type, dec->wait.preemption);
+ /* #if TCFG_DRC_ENABLE&&ESCO_DRC_EN */
+ /* #endif//ESCO_DRC_EN */
+
+ dec->enc_start = 1; //该函数所在任务优先级低可能未open编码就开始解码,加入enc开始的标志防止解码过快输出
+ printf("esco_dec_start ok\n");
+
+
+ return 0;
+
+__err3:
+ audio_mixer_ch_close(&dec->mix_ch);
+__err2:
+ audio_decoder_close(&dec->decoder);
+__err1:
+ esco_dec_release();
+ return err;
+}
+
+static int __esco_dec_res_close(void)
+{
+ if (!esco_dec->start) {
+ return 0;
+ }
+
+ esco_dec->start = 0;
+ esco_dec->enc_start = 0;
+ esco_dec->preempt = 1;
+
+ esco_ul_stream_close();
+ /* audio_aec_close(); */
+ /* esco_enc_close(); */
+#if TCFG_AUDIO_CVP_DUT_ENABLE
+ cvp_dut_mode_set(CVP_DUT_MODE_ALGORITHM); //通话结束 CVP_DUT恢复成算法模式
+#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
+ app_audio_state_exit(APP_AUDIO_STATE_CALL);
+ audio_decoder_close(&esco_dec->decoder);
+ audio_mixer_ch_close(&esco_dec->mix_ch);
+ sound_pcm_dev_set_delay_time(20, AUDIO_DAC_DELAY_TIME);
+#if AUDIO_CODEC_SUPPORT_SYNC
+ esco_decoder_syncts_free(esco_dec);
+ esco_dec->sync_step = 0;
+#endif
+#if TCFG_EQ_ENABLE&&TCFG_PHONE_EQ_ENABLE
+ if (esco_dec->eq_drc) {
+ esco_eq_drc_free(esco_dec->eq_drc);
+ esco_dec->eq_drc = NULL;
+ }
+#endif//TCFG_PHONE_EQ_ENABLE
+
+ audio_out_effect_dis = 0;
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_close(CALL_DVOL);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+#if TCFG_ESCO_DL_NS_ENABLE
+ audio_ns_close(esco_dec->dl_ns);
+#endif/*TCFG_ESCO_DL_NS_ENABLE*/
+
+ audio_plc_close();
+#if TCFG_AUDIO_ESCO_DL_NOISEGATE_ENABLE
+ audio_noise_gate_close(esco_dl_noisegate_buf);
+#endif/*TCFG_AUDIO_ESCO_DL_NOISEGATE_ENABLE*/
+
+#if TCFG_AUDIO_ESCO_LIMITER_ENABLE
+ if (esco_dec->limiter) {
+ esco_limiter_close(esco_dec->limiter);
+ esco_dec->limiter = NULL;
+ }
+#endif
+ audio_codec_clock_del(AUDIO_ESCO_MODE);
+ dual_offset_points = 0;
+ dual_total_points = 0;
+ return 0;
+}
+
+static int esco_wait_res_handler(struct audio_res_wait *wait, int event)
+{
+ int err = 0;
+
+ printf("esco_wait_res_handler:%d", event);
+ if (event == AUDIO_RES_GET) {
+ err = esco_dec_start();
+ } else if (event == AUDIO_RES_PUT) {
+ err = __esco_dec_res_close();
+ lmp_private_esco_suspend_resume(1);
+ }
+
+ return err;
+}
+
+static void esco_smart_voice_detect_handler(void)
+{
+#if TCFG_SMART_VOICE_ENABLE
+#if TCFG_CALL_KWS_SWITCH_ENABLE
+ if (ESCO_SIRI_WAKEUP() || (get_call_status() != BT_CALL_INCOMING)) {
+ audio_smart_voice_detect_close();
+ }
+#else
+ audio_smart_voice_detect_close();
+#endif
+#endif
+}
+
+/*
+*********************************************************************
+* SCO/ESCO Decode Open
+* Description: 打开蓝牙通话解码
+* Arguments : param 蓝牙协议栈传递上来的编解码信息
+* Return : 0 成功 其他 失败
+* Note(s) : None.
+*********************************************************************
+*/
+int esco_dec_open(void *param, u8 mute)
+{
+ int err;
+ struct esco_dec_hdl *dec;
+ u32 esco_param = *(u32 *)param;
+ int esco_len = esco_param >> 16;
+ int codec_type = esco_param & 0x000000ff;
+
+ printf("esco_dec_open, type=%d,len=%d\n", codec_type, esco_len);
+#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_AND_CALL_MUTEX)
+ audio_hearing_aid_suspend();
+#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
+
+ esco_smart_voice_detect_handler();
+ dec = zalloc(sizeof(*dec));
+ if (!dec) {
+ return -ENOMEM;
+ }
+ esco_dec = dec;
+ dec->esco_len = esco_len;
+ if (codec_type == 3) {
+ dec->coding_type = AUDIO_CODING_MSBC;
+ } else if (codec_type == 2) {
+ dec->coding_type = AUDIO_CODING_CVSD;
+ } else {
+ printf("Unknow ESCO codec type:%d\n", codec_type);
+ }
+
+ dec->tws_mute_en = mute;
+
+ dec->wait.priority = 2;
+ dec->wait.preemption = 1;
+ dec->wait.handler = esco_wait_res_handler;
+ err = audio_decoder_task_add_wait(&decode_task, &dec->wait);
+ if (esco_dec && esco_dec->start == 0) {
+ dec->preempt = 1;
+ lmp_private_esco_suspend_resume(1);
+ }
+
+#if AUDIO_OUTPUT_AUTOMUTE
+ mix_out_automute_skip(1);
+#endif
+
+ return err;
+}
+
+/*
+*********************************************************************
+* SCO/ESCO Decode Close
+* Description: 关闭蓝牙通话解码
+* Arguments : None.
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+void esco_dec_close(void)
+{
+ if (!esco_dec) {
+ return;
+ }
+
+
+ __esco_dec_res_close();
+ esco_dec_release();
+
+#if (TCFG_AUDIO_OUTPUT_IIS)
+ audio_aec_ref_src_close();
+#endif
+
+#if AUDIO_OUTPUT_AUTOMUTE
+ mix_out_automute_skip(0);
+#endif
+
+#if (defined(TCFG_PHONE_MESSAGE_ENABLE) && (TCFG_PHONE_MESSAGE_ENABLE))
+ phone_message_call_api_stop();
+#endif/*TCFG_PHONE_MESSAGE_ENABLE*/
+
+ audio_mixer_set_output_buf(&mixer, mix_buff, sizeof(mix_buff));
+#if TCFG_SMART_VOICE_ENABLE
+ audio_smart_voice_detect_open(JL_KWS_COMMAND_KEYWORD);
+#endif
+
+#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_AND_CALL_MUTEX)
+ audio_hearing_aid_resume();
+#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
+ printf("esco_dec_close succ\n");
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+u8 bt_audio_is_running(void)
+{
+ return (a2dp_dec || esco_dec);
+}
+u8 bt_media_is_running(void)
+{
+ return a2dp_dec != NULL;
+}
+u8 bt_phone_dec_is_running()
+{
+ return esco_dec != NULL;
+}
+__attribute__((weak))
+void mic_trim_run(void)
+{
+ printf("==========weak fun for tmp\n");
+}
+extern u32 read_capless_DTB(void);
+static u8 audio_dec_inited = 0;
+
+/*音频配置实时跟踪,可以用来查看ADC/DAC增益,或者其他寄存器配置*/
+static void audio_config_trace(void *priv)
+{
+ printf(">>Audio_Config_Trace:\n");
+ audio_gain_dump();
+ //audio_adda_dump();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+int audio_dec_init()
+{
+ int err;
+ printf("audio_dec_init\n");
+
+ tone_play_init();
+
+#if TCFG_KEY_TONE_EN
+ // 按键音初始化
+ audio_key_tone_init();
+#endif
+
+ err = audio_decoder_task_create(&decode_task, "audio_dec");
+#if TCFG_AUDIO_ANC_ENABLE
+ /* audio_dac_anc_set(&dac_hdl, 1); */
+ /* dac_data.max_ana_vol = anc_dac_gain_get(ANC_DAC_CH_L); //获取ANC设置的模拟增益 */
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+
+ request_irq(IRQ_AUDIO_IDX, 2, audio_irq_handler, 0);
+
+ /*硬件SRC模块滤波器buffer设置,可根据最大使用数量设置整体buffer*/
+ /* audio_src_base_filt_init(audio_src_hw_filt, sizeof(audio_src_hw_filt)); */
+
+ sound_pcm_driver_init();
+ sound_pcm_dev_set_delay_time(20, AUDIO_DAC_DELAY_TIME);
+
+ audio_mixer_open(&mixer);
+ audio_mixer_set_handler(&mixer, &mix_handler);
+ audio_mixer_set_event_handler(&mixer, mixer_event_handler);
+#if defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE
+ audio_mixer_set_mode(&mixer, 4, BIT24_MODE);
+#endif
+ audio_mixer_set_output_buf(&mixer, mix_buff, sizeof(mix_buff));
+
+#if AUDIO_OUTPUT_AUTOMUTE
+ mix_out_automute_open();
+#endif //#if AUDIO_OUTPUT_AUTOMUTE
+
+#if TCFG_AUDIO_CONFIG_TRACE
+ sys_timer_add(NULL, audio_config_trace, 3000);
+#endif/*TCFG_AUDIO_CONFIG_TRACE*/
+
+#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
+ spk_eq_read_from_vm();
+#endif
+
+#if ((defined TCFG_DIAFX_ENABLE) && TCFG_DIAFX_ENABLE)
+ diafx_init_mode(0);
+ diafx_enabled(1);
+#endif
+ audio_dec_inited = 1;
+
+#if TCFG_AUDIO_ANC_ENABLE && TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+ /*需要再dac trim后调用*/
+ /*同时开ANC和免摘功能时,配置ADC固定打开的adc数字通道数*/
+ extern struct adc_platform_data adc_data;
+ adc_data.anc_adt_en = 1;
+ u8 esco_mic_num = audio_adc_file_get_esco_mic_num();
+ u8 adt_mic_num = get_icsd_adt_mic_num();
+ adc_data.anc_adt_mic_ch_num = esco_mic_num > adt_mic_num ? esco_mic_num : adt_mic_num;
+#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
+
+ return err;
+}
+
+static u8 audio_dec_init_complete()
+{
+ if (!audio_dec_inited) {
+ return 0;
+ }
+
+ return 1;
+}
+extern void audio_adc_mic_demo_open(u8 mic_idx, u8 gain, u16 sr, u8 mic_2_dac);
+extern void dac_analog_power_control(u8 en);
+void audio_fast_mode_test()
+{
+ //sound_pcm_dev_start(NULL, 44100, app_audio_get_volume(APP_AUDIO_CURRENT_STATE));
+ //audio_adc_mic_demo_open(AUDIO_ADC_MIC_0, 10, 16000, 1);
+
+}
+REGISTER_LP_TARGET(audio_dec_init_lp_target) = {
+ .name = "audio_dec_init",
+ .is_idle = audio_dec_init_complete,
+};
+
+#if AUDIO_OUT_EFFECT_ENABLE
+int audio_out_effect_stream_clear()
+{
+ if (!audio_out_effect) {
+ return 0;
+ }
+
+ if (audio_out_effect->eq && audio_out_effect->async) {
+ audio_eq_async_data_clear(audio_out_effect->eq);
+ }
+ return 0;
+}
+
+void audio_out_effect_close(void)
+{
+ if (!audio_out_effect) {
+ return ;
+ }
+ audio_out_eq_drc_free(audio_out_effect);
+ audio_out_effect = NULL;
+}
+
+
+int audio_out_effect_open(void *priv, u16 sample_rate)
+{
+ audio_out_effect_close();
+
+ u8 ch_num;
+#if TCFG_APP_FM_EMITTER_EN
+ ch_num = 2;
+#else
+ ch_num = sound_pcm_dev_channel_mapping(0);
+#endif//TCFG_APP_FM_EMITTER_EN
+
+ u8 drc_en = 0;//
+ u8 async = 0;
+ if (drc_en) {
+ async = 1;
+ }
+
+ audio_out_effect = audio_out_eq_drc_setup(priv, (eq_output_cb)mix_output_handler, sample_rate, ch_num, async, drc_en);
+ return 0;
+}
+
+int audio_out_eq_spec_set_gain(u8 idx, int gain)
+{
+ if (!audio_out_effect) {
+ return -1;
+ }
+ audio_out_eq_set_gain(audio_out_effect, idx, gain);
+ return 0;
+}
+#endif//AUDIO_OUT_EFFECT_ENABLE
+
+/*----------------------------------------------------------------------------*/
+/**@brief 获取输出默认采样率
+ @param
+ @return 0: 采样率可变
+ @return 非0: 固定采样率
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+u32 audio_output_nor_rate(void)
+{
+#if TCFG_AUDIO_OUTPUT_IIS
+ return TCFG_IIS_SR;
+#endif /*TCFG_AUDIO_OUTPUT_IIS*/
+
+#if AUDIO_OUTPUT_INCLUDE_DAC
+
+#if (TCFG_MIC_EFFECT_ENABLE)
+ return TCFG_REVERB_SAMPLERATE_DEFUAL;
+#endif
+ /* return app_audio_output_samplerate_select(input_rate, 1); */
+#elif (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_BT)
+
+#elif (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_FM)
+ return 41667;
+#else
+ return 44100;
+#endif
+
+ /* #if TCFG_VIR_UDISK_ENABLE */
+ /* return 44100; */
+ /* #endif */
+
+ return 0;
+}
+
+int audio_dac_sample_rate_select(struct audio_dac_hdl *dac, u32 sample_rate, u8 high)
+{
+ u32 sample_rate_tbl[] = {8000, 11025, 12000, 16000, 22050, 24000,
+ 32000, 44100, 48000, 64000, 88200, 96000
+ };
+ int rate_num = ARRAY_SIZE(sample_rate_tbl);
+ int i = 0;
+
+ for (i = 0; i < rate_num; i++) {
+ if (sample_rate == sample_rate_tbl[i]) {
+ return sample_rate;
+ }
+
+ if (sample_rate < sample_rate_tbl[i]) {
+ if (high) {
+ return sample_rate_tbl[i];
+ } else {
+ return sample_rate_tbl[i > 0 ? (i - 1) : 0];
+ }
+ }
+ }
+
+ return sample_rate_tbl[rate_num - 1];
+}
+
+/*******************************************************
+* Function name : app_audio_output_samplerate_select
+* Description : 将输入采样率与输出采样率进行匹配对比
+* Parameter :
+* @sample_rate 输入采样率
+* @high: 0 - 低一级采样率,1 - 高一级采样率
+* Return : 匹配后的采样率
+********************* -HB ******************************/
+int app_audio_output_samplerate_select(u32 sample_rate, u8 high)
+{
+ return audio_dac_sample_rate_select(&dac_hdl, sample_rate, high);
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 获取输出采样率
+ @param input_rate: 输入采样率
+ @return 输出采样率
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+u32 audio_output_rate(int input_rate)
+{
+ u32 out_rate = audio_output_nor_rate();
+ if (out_rate) {
+ return out_rate;
+ }
+
+#if (TCFG_REVERB_ENABLE || TCFG_MIC_EFFECT_ENABLE)
+ if (input_rate > 48000) {
+ return 48000;
+ }
+#endif
+ return app_audio_output_samplerate_select(input_rate, 1);
+}
+
+#if TCFG_USER_TWS_ENABLE
+#if AUDIO_SURROUND_CONFIG
+#define TWS_FUNC_ID_A2DP_EFF \
+ ((int)(('A' + '2' + 'D' + 'P') << (2 * 8)) | \
+ (int)(('E' + 'F' + 'F') << (1 * 8)) | \
+ (int)(('S' + 'Y' + 'N' + 'C') << (0 * 8)))
+/*
+ *发环绕左右耳效果同步
+ * */
+void audio_surround_voice_ctrl()
+{
+ int state = tws_api_get_tws_state();
+ if (state & TWS_STA_SIBLING_CONNECTED) {
+ if (a2dp_dec && a2dp_dec->sur && a2dp_dec->sur->surround) {
+ if (!a2dp_dec->sur->surround_eff) {
+ a2dp_dec->sur->surround_eff = 1;
+ } else {
+ a2dp_dec->sur->surround_eff = 0;
+ }
+ int a2dp_eff = a2dp_dec->sur->surround_eff;
+ tws_api_send_data_to_sibling((u8 *)&a2dp_eff, sizeof(int), TWS_FUNC_ID_A2DP_EFF);
+ }
+ }
+}
+
+/*
+ *左右耳环绕效果同步回调
+ * */
+static void tws_a2dp_eff_align(void *data, u16 len, bool rx)
+{
+ if (a2dp_dec && a2dp_dec->sur && a2dp_dec->sur->surround) {
+ int a2dp_eff;
+ memcpy(&a2dp_eff, data, sizeof(int));
+ a2dp_dec->sur->surround_eff = a2dp_eff;
+ a2dp_surround_set(a2dp_eff);
+ audio_surround_voice(a2dp_dec->sur, a2dp_dec->sur->surround_eff);
+ }
+}
+
+REGISTER_TWS_FUNC_STUB(a2dp_align_eff) = {
+ .func_id = TWS_FUNC_ID_A2DP_EFF,
+ .func = tws_a2dp_eff_align,
+};
+#endif//AUDIO_SURROUND_CONFIG
+#endif /* TCFG_USER_TWS_ENABLE */
+
+
diff --git a/cpu/br28/audio_dec/audio_dec.h b/cpu/br28/audio_dec/audio_dec.h
new file mode 100644
index 0000000..db36b9d
--- /dev/null
+++ b/cpu/br28/audio_dec/audio_dec.h
@@ -0,0 +1,99 @@
+
+#ifndef _AUDIO_DEC_H_
+#define _AUDIO_DEC_H_
+
+#include "asm/includes.h"
+#include "media/includes.h"
+#include "system/includes.h"
+#include "asm/audio_src.h"
+// #include "audio_digital_vol.h"
+/*#include "application/audio_eq_drc_apply.h"*/
+
+
+#ifndef RB16
+#define RB16(b) (u16)(((u8 *)b)[0] << 8 | (((u8 *)b))[1])
+#endif
+
+extern struct audio_decoder_task decode_task;
+extern struct audio_mixer mixer;
+extern struct audio_mixer recorder_mixer;
+
+u32 audio_output_rate(int input_rate);
+u32 audio_output_channel_num(void);
+int audio_output_set_start_volume(u8 state);
+
+int audio_output_start(u32 sample_rate, u8 reset_rate);
+void audio_output_stop(void);
+
+struct audio_src_handle *audio_hw_resample_open(void *priv, int (*output_handler)(void *, void *, int),
+ u8 channel, u16 input_sample_rate, u16 output_sample_rate);
+void audio_hw_resample_close(struct audio_src_handle *hdl);
+
+void audio_resume_all_decoder(void);
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+void audio_sbc_enc_inbuf_resume(void);
+
+int audio_dec_init();
+
+void set_source_sample_rate(u16 sample_rate);
+u16 get_source_sample_rate();
+#if USER_DIGITAL_VOLUME_ADJUST_ENABLE != 0
+void a2dp_user_digital_volume_set(u8 vol);
+u8 a2dp_user_audio_digital_volume_get();
+void a2dp_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
+
+void linein_user_digital_volume_set(u8 vol);
+u8 linein_user_audio_digital_volume_get();
+void linein_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
+
+void fm_user_digital_volume_set(u8 vol);
+u8 fm_user_audio_digital_volume_get();
+void fm_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
+
+void file_user_digital_volume_set(u8 vol);
+u8 file_user_audio_digital_volume_get();
+void file_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
+
+void pc_user_digital_volume_set(u8 vol);
+u8 pc_user_audio_digital_volume_get();
+void pc_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
+
+void spdif_user_digital_volume_set(u8 vol);
+u8 spdif_user_audio_digital_volume_get();
+void spdif_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
+
+
+void reverb_user_digital_volume_set(u8 vol);
+u8 reverb_user_audio_digital_volume_get();
+void reverb_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
+#endif
+void reverb_set_dodge_threshold(int threshold_in, int threshold_out, u8 fade_tar, u8 dodge_en);
+
+
+void a2dp_dec_output_set_start_bt_time(u32 bt_tmr);
+/*void mix_out_high_bass(u32 cmd, struct high_bass *hb);
+void mix_out_high_bass_dis(u32 cmd, u8 dis);*/
+
+//////////////////////////////////////////////////////////////////////////////
+static inline void audio_pcm_mono_to_dual(s16 *dual_pcm, s16 *mono_pcm, int points)
+{
+ s16 *mono = mono_pcm;
+ int i = 0;
+ u8 j = 0;
+
+ for (i = 0; i < points; i++, mono++) {
+ *dual_pcm++ = *mono;
+ *dual_pcm++ = *mono;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+#include "audio_dec_file.h"
+
+
+#endif
+
diff --git a/cpu/br28/audio_dec/audio_dec_file.c b/cpu/br28/audio_dec/audio_dec_file.c
new file mode 100644
index 0000000..ab747dc
--- /dev/null
+++ b/cpu/br28/audio_dec/audio_dec_file.c
@@ -0,0 +1,1305 @@
+/*
+ ****************************************************************
+ *File : audio_dec_file.c
+ *Note :
+ *
+ ****************************************************************
+ */
+//////////////////////////////////////////////////////////////////////////////
+#include "asm/includes.h"
+#include "media/includes.h"
+#include "media/file_decoder.h"
+#include "system/includes.h"
+#include "effectrs_sync.h"
+#include "app_config.h"
+#include "audio_config.h"
+#include "audio_dec.h"
+#include "app_config.h"
+#include "app_main.h"
+#include "classic/tws_api.h"
+#include "audio_dec/audio_dec_file.h"
+#include "media/audio_stream.h"
+//#include "music/music_decrypt.h"
+//#include "music/music_id3.h"
+#include "application/eq_config.h"
+#include "audio_dec_eff.h"
+#include "bt_tws.h"
+#include "media/bt_audio_timestamp.h"
+#include "media/audio_syncts.h"
+#include "audio_codec_clock.h"
+#include "sound_device.h"
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+#include "audio_dvol.h"
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+#if TCFG_APP_MUSIC_EN
+#define FILE_DEC_PICK_EN 0 // 本地解码拆包转发
+
+#define FILE_DEC_ALIGN 0
+#define FILE_DEC_START 1
+#define FILE_DEC_INVITE 2
+
+#if (!TCFG_DEC2TWS_ENABLE)
+#undef FILE_DEC_PICK_EN
+#define FILE_DEC_PICK_EN 0
+#endif
+
+#ifndef BREAKPOINT_DATA_LEN
+#define BREAKPOINT_DATA_LEN 32
+#endif
+
+const int FILE_DEC_ONCE_OUT_NUM = ((512 * 4) * 2); // 一次最多输出长度。避免多解码叠加时卡住其他解码太长时间
+
+const int FILE_DEC_PP_FADE_MS = 50; // pp淡入淡出时长。0-不使用淡入淡出
+
+struct file_dec_hdl *file_dec = NULL; // 文件解码句柄
+u8 file_dec_start_pause = 0; // 启动解码后但不马上开始播放
+extern struct audio_dac_hdl dac_hdl;
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+void file_eq_drc_open(struct file_dec_hdl *hdl, u16 sample_rate, u8 ch_num);
+void file_eq_drc_close(struct file_dec_hdl *hdl);
+
+extern void *local_tws_dec_sync_open(u8 channel, u16 sample_rate, u16 output_rate);
+extern void local_tws_sync_no_check_data_buf(u8 no_check);
+extern void audio_mix_ch_event_handler(void *priv, int event);
+extern void bt_audio_sync_nettime_select(u8 base);
+
+int file_dec_repeat_set(u8 repeat_num);
+
+//////////////////////////////////////////////////////////////////////////////
+/*----------------------------------------------------------------------------*/
+/**@brief 获取文件解码hdl
+ @param
+ @return
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+void *get_file_dec_hdl()
+{
+ return file_dec;
+}
+
+static enum audio_channel file_dec_get_output_channel()
+{
+ enum audio_channel channel;
+
+#if TCFG_USER_TWS_ENABLE
+ int state = tws_api_get_tws_state();
+ if (state & TWS_STA_SIBLING_CONNECTED) {
+ channel = tws_api_get_local_channel() == 'L' ? AUDIO_CH_L : AUDIO_CH_R;
+ } else {
+ u8 dac_connect_mode = audio_dac_get_channel(&dac_hdl);
+ if (dac_connect_mode == DAC_OUTPUT_LR) {
+ channel = AUDIO_CH_LR;
+ } else {
+ channel = AUDIO_CH_DIFF;
+ }
+ }
+#else
+ u8 dac_connect_mode = audio_dac_get_channel(&dac_hdl);
+ if (dac_connect_mode == DAC_OUTPUT_LR) {
+ channel = AUDIO_CH_LR;
+ } else {
+ channel = AUDIO_CH_DIFF;
+ }
+#endif
+ return channel;
+}
+
+static u8 file_dec_output_channel_num(void)
+{
+ u8 dac_connect_mode = audio_dac_get_channel(&dac_hdl);
+ if (dac_connect_mode == AUDIO_CH_LR) {
+ return 2;
+ }
+ return 1;
+}
+/*----------------------------------------------------------------------------*/
+/**@brief 读取文件数据
+ @param *decoder: 解码器句柄
+ @param *buf: 数据
+ @param len: 数据长度
+ @return >=0:读到的数据长度
+ @return <0:错误
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+static int file_fread(struct audio_decoder *decoder, void *buf, u32 len)
+{
+ int rlen;
+ struct file_dec_hdl *dec = file_dec;
+
+#if TCFG_DEC_DECRYPT_ENABLE
+ u32 addr;
+ addr = fpos(dec->file);
+ rlen = fread(dec->file, buf, len);
+ if (rlen && (rlen <= len)) {
+ cryptanalysis_buff(&dec->mply_cipher, buf, addr, rlen);
+ }
+#else
+ rlen = fread(dec->file, buf, len);
+#endif
+ if (rlen > len) {
+ // putchar('r');
+ if (rlen == (-1)) {
+ //file err
+ dec->read_err = 1;
+ } else {
+ //dis err
+ dec->read_err = 2;
+ }
+ rlen = 0;
+ } else {
+ // putchar('R');
+ dec->read_err = 0;
+ }
+ return rlen;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 文件指针定位
+ @param *decoder: 解码器句柄
+ @param offset: 定位偏移
+ @param seek_mode: 定位类型
+ @return 0:成功
+ @return 非0:错误
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+static int file_fseek(struct audio_decoder *decoder, u32 offset, int seek_mode)
+{
+ struct file_dec_hdl *dec = file_dec;
+
+ return fseek(dec->file, offset, seek_mode);
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 读取文件长度
+ @param *decoder: 解码器句柄
+ @return 文件长度
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+static int file_flen(struct audio_decoder *decoder)
+{
+ int len = 0;
+ struct file_dec_hdl *dec = file_dec;
+
+ len = flen(dec->file);
+ return len;
+}
+
+static const u32 file_input_coding_more[] = {
+#if TCFG_DEC_WAV_ENABLE
+ AUDIO_CODING_WAV,
+#endif
+#if TCFG_DEC_MP3_ENABLE
+ AUDIO_CODING_MP3,
+#endif
+ 0,
+};
+
+static const struct audio_dec_input file_input = {
+ .coding_type = 0
+#if TCFG_DEC_WMA_ENABLE
+ | AUDIO_CODING_WMA
+#endif
+
+#if TCFG_DEC_FLAC_ENABLE
+ | AUDIO_CODING_FLAC
+#endif
+#if TCFG_DEC_APE_ENABLE
+ | AUDIO_CODING_APE
+#endif
+#if TCFG_DEC_M4A_ENABLE
+ | AUDIO_CODING_M4A
+#endif
+#if TCFG_DEC_ALAC_ENABLE
+ | AUDIO_CODING_ALAC
+#endif
+#if TCFG_DEC_AMR_ENABLE
+ | AUDIO_CODING_AMR
+#endif
+#if TCFG_DEC_DTS_ENABLE
+ | AUDIO_CODING_DTS
+#endif
+#if TCFG_DEC_G726_ENABLE
+ | AUDIO_CODING_G726
+#endif
+
+ ,
+ .p_more_coding_type = (u32 *)file_input_coding_more,
+ .data_type = AUDIO_INPUT_FILE,
+ .ops = {
+ .file = {
+ .fread = file_fread,
+ .fseek = file_fseek,
+ .flen = file_flen,
+ }
+ }
+};
+
+#if TCFG_DEC2TWS_ENABLE
+
+static inline u16 local_tws_audio_seqn(void *buf)
+{
+ u16 seqn;
+ /*Get local tws audio sequence.*/
+ if (!buf) {
+ return 0;
+ }
+
+ memcpy(&seqn, buf, sizeof(seqn));
+ return seqn;
+}
+
+static inline u16 local_tws_audio_timestamp(void *buf)
+{
+ u32 timestamp;
+ /*Get local tws audio sequence.*/
+ if (!buf) {
+ return 0;
+ }
+
+ memcpy(×tamp, buf, sizeof(timestamp));
+ return timestamp;
+}
+
+/*static int frame_fread(struct audio_decoder *decoder, u8 **frame)*/
+static int frame_fread(struct audio_decoder *decoder, void *buf, u32 len)
+{
+ int offset = 0;
+ int frame_len;
+ struct file_dec_hdl *dec = file_dec;
+
+ while (len) {
+ int clen = MIN(dec->frame_remain_len, len);
+ if (clen) {
+ memcpy((u8 *)buf + offset,
+ dec->frame + dec->frame_len - dec->frame_remain_len, clen);
+ len -= clen;
+ offset += clen;
+ dec->frame_remain_len -= clen;
+ break;
+ } else {
+ if (dec->frame) {
+ tws_api_data_trans_free(dec->tws_channel, dec->frame);
+ }
+ dec->frame = tws_api_data_trans_pop(dec->tws_channel, &frame_len);
+ if (!dec->frame) {
+ dec->frame_remain_len = 0;
+ break;
+ }
+#if 0
+ u16 seqn = local_tws_audio_seqn(dec->frame);
+ if ((u16)(seqn - dec->seqn) > 1) {
+ log_w("Local tws audio sequence error : %d, %d.\n", seqn, dec->seqn);
+ }
+ dec->seqn = seqn;
+#else
+ u32 timestamp = local_tws_audio_timestamp(dec->frame);
+ audio_syncts_next_pts(dec->syncts, timestamp);
+ dec->mix_ch_event_params[2] = timestamp;
+#endif
+ dec->frame_len = frame_len;
+ dec->frame_remain_len = frame_len - sizeof(dec->seqn);
+ }
+ }
+
+ if (offset == 0) {
+// r_printf("no_data\n");
+ if (dec->trans_dec_end) {
+ return -EINVAL;
+ }
+ }
+
+ return offset;
+}
+
+static int frame_fseek(struct audio_decoder *decoder, u32 offset, int seek_mode)
+{
+ return 0;
+}
+
+static int frame_flen(struct audio_decoder *decoder)
+{
+ return 0x7fffffff;
+}
+
+static const struct audio_dec_input frame_input = {
+ .coding_type = 0,
+ .data_type = AUDIO_INPUT_FILE,
+ .ops = {
+ .file = {
+ .fread = frame_fread,
+ .fseek = frame_fseek,
+ .flen = frame_flen,
+ }
+ }
+};
+#endif
+
+
+
+/*----------------------------------------------------------------------------*/
+/**@brief 文件解码释放
+ @param
+ @return
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+static void file_dec_release(void)
+{
+ struct file_dec_hdl *dec = file_dec;
+
+#if TCFG_DEC_ID3_V1_ENABLE
+ if (dec->p_mp3_id3_v1) {
+ id3_obj_post(&dec->p_mp3_id3_v1);
+ }
+#endif
+#if TCFG_DEC_ID3_V2_ENABLE
+ if (dec->p_mp3_id3_v2) {
+ id3_obj_post(&dec->p_mp3_id3_v2);
+ }
+#endif
+
+ audio_decoder_task_del_wait(&decode_task, &dec->wait);
+
+ audio_codec_clock_del(AUDIO_FILE_MODE);
+
+#if TCFG_DEC2TWS_ENABLE
+ if (dec->tws_channel) {
+ tws_api_data_trans_close(dec->tws_channel);
+ }
+#endif
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_close(MUSIC_DVOL);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+
+ local_irq_disable();
+ if (file_dec->dec_bp) {
+ free(file_dec->dec_bp);
+ file_dec->dec_bp = NULL;
+ }
+ free(file_dec);
+ file_dec = NULL;
+ local_irq_enable();
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 文件解码事件处理
+ @param *decoder: 解码器句柄
+ @param argc: 参数个数
+ @param *argv: 参数
+ @return
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+static void file_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
+{
+ printf("file_dec_event_handler: %d\n", argv[0]);
+
+ switch (argv[0]) {
+ case AUDIO_DEC_EVENT_END:
+ log_i("AUDIO_DEC_EVENT_END\n");
+ if (!file_dec) {
+ log_i("file_dec handle err ");
+ break;
+ }
+#if TCFG_DEC2TWS_ENABLE
+ if (decoder == &file_dec->trans_dec.decoder) {
+ file_dec->trans_dec_end = 1;
+ break;
+ }
+#endif
+ if (decoder != &file_dec->file_dec.decoder) {
+ break;
+ }
+
+ // 有回调,让上层close,避免close后上层读不到断点等
+ if (file_dec->evt_cb) {
+ /* file_dec->evt_cb(file_dec->evt_priv, argc, argv); */
+ int msg[2];
+ msg[0] = argv[0];
+ msg[1] = file_dec->read_err;
+ /* log_i("read err0:%d ", file_dec->read_err); */
+ file_dec->evt_cb(file_dec->evt_priv, 2, msg);
+ } else {
+ file_dec_close();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static int file_decoder_output_after_syncts(void *priv, void *data, int len)
+{
+ struct file_dec_hdl *dec = (struct file_dec_hdl *)priv;
+#if TCFG_EQ_ENABLE&&TCFG_MUSIC_MODE_EQ_ENABLE
+ if (dec->eq_drc && dec->eq_drc->async) {
+ return eq_drc_run(dec->eq_drc, data, len);//异步eq
+ }
+#endif//TCFG_MUSIC_MODE_EQ_ENABLE
+
+ int wlen = audio_mixer_ch_write(&dec->mix_ch, data, len);
+ return wlen;
+}
+
+static int file_decoder_output_hander(struct file_decoder *decoder, s16 *data, int len)
+{
+ int wlen = 0;
+
+ struct file_dec_hdl *dec = container_of(decoder, struct file_dec_hdl, file_dec);
+
+ if (!dec->remain) {
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_run(MUSIC_DVOL, data, len);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+#if TCFG_EQ_ENABLE&&TCFG_MUSIC_MODE_EQ_ENABLE
+ if (dec->eq_drc && !dec->eq_drc->async) {
+ eq_drc_run(dec->eq_drc, data, len);//同步eq
+ }
+#endif
+ }
+#if TCFG_DEC2TWS_ENABLE
+ if (dec->syncts) {
+ int wlen = audio_syncts_frame_filter(dec->syncts, data, len);
+ if (wlen < len) {
+ audio_syncts_trigger_resume(dec->syncts, (void *)decoder, (void (*)(void *))audio_decoder_resume);
+ }
+ dec->remain = wlen < len ? 1 : 0;
+ return wlen;
+ }
+#endif
+ wlen = file_decoder_output_after_syncts(dec, data, len);
+ dec->remain = wlen < len ? 1 : 0;
+ return wlen;
+}
+
+static int tws_local_media_trans_handler(struct file_decoder *decoder, s16 *data, int len)
+{
+ /*int wlen = tws_api_local_media_trans_bulk_push((u8 *)data, len);*/
+ struct file_dec_hdl *dec = container_of(decoder, struct file_dec_hdl, file_dec);
+ int wlen = 0;
+#if TCFG_DEC2TWS_ENABLE
+ /*wlen = tws_api_local_media_push_with_sequence((u8 *)data, len, file_dec->tx_seqn);*/
+ u32 timestamp = 0;
+ if (dec->ts_handle) {
+ timestamp = file_audio_timestamp_update(dec->ts_handle, dec->pcm_num);
+ }
+ wlen = tws_api_local_media_push_with_timestamp((u8 *)data, len, timestamp);
+ if (wlen) {
+ u16 pcm_num = 0;
+ memcpy(&pcm_num, data, sizeof(pcm_num));
+ /*printf("Num : %d x 32\n", pcm_num);*/
+ dec->pcm_num += (pcm_num * 32);
+ /*file_dec->tx_seqn++;*/
+ }
+#endif
+ /*printf("trans: %d, %d\n", wlen, len);*/
+ return wlen;
+}
+
+static int tws_file_decoder_syncts_setup(struct file_dec_hdl *dec)
+{
+ int err = 0;
+#if TCFG_DEC2TWS_ENABLE
+ struct audio_syncts_params params = {0};
+ params.nch = file_dec_output_channel_num();
+ params.pcm_device = PCM_INSIDE_DAC;
+ params.network = AUDIO_NETWORK_BT2_1;
+ params.rin_sample_rate = dec->file_dec.sample_rate;
+ params.rout_sample_rate = dec->file_dec.sample_rate;
+ params.priv = dec;
+ params.factor = TIME_US_FACTOR;
+ params.output = file_decoder_output_after_syncts;
+
+ bt_audio_sync_nettime_select(1);
+ err = audio_syncts_open(&dec->syncts, ¶ms);
+ if (!err) {
+ dec->mix_ch_event_params[0] = (u32)&dec->mix_ch;
+ dec->mix_ch_event_params[1] = (u32)dec->syncts;
+ audio_mixer_ch_set_event_handler(&dec->mix_ch, (void *)dec->mix_ch_event_params, audio_mix_ch_event_handler);
+ }
+#endif
+ return err;
+}
+
+
+
+static void tws_file_decoder_syncts_free(struct file_dec_hdl *dec)
+{
+#if TCFG_DEC2TWS_ENABLE
+ if (dec->syncts) {
+ audio_syncts_close(dec->syncts);
+ dec->syncts = NULL;
+ }
+#endif
+}
+static int tws_data_trans_handler(struct file_decoder *dec, s16 *data, int len)
+{
+ int wlen = 0;
+
+#if TCFG_DEC2TWS_ENABLE
+ u8 *buf = tws_api_data_trans_buf_alloc(file_dec->tws_channel, len + 2);
+ if (!buf) {
+ return 0;
+ }
+
+ memcpy(buf, &file_dec->tx_seqn, 2);
+ memcpy(buf + 2, data, len);
+ tws_api_data_trans_push(file_dec->tws_channel, buf, len + 2);
+ file_dec->tx_seqn++;
+#endif
+ /*printf("trans: %d, %d\n", wlen, len);*/
+ return len;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 文件解码开始
+ @param
+ @return 0:成功
+ @return 非0:失败
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+static int file_dec_start()
+{
+ int err;
+ enum audio_channel channel;
+ struct file_dec_hdl *dec = file_dec;
+ struct audio_mixer *p_mixer = &mixer;
+
+ if (!dec) {
+ return -EINVAL;
+ }
+
+ log_i("file_dec_start: in\n");
+
+ // 打开file解码器
+#if TCFG_DEC2TWS_ENABLE
+ err = frame_decoder_open(&dec->file_dec, &frame_input, &decode_task);
+#else
+ err = file_decoder_open(&dec->file_dec, &file_input, &decode_task, dec->bp, 0);
+#endif
+ if (err) {
+ goto __err1;
+ }
+ dec->file_dec.output_handler = file_decoder_output_hander;
+ file_decoder_set_event_handler(&dec->file_dec, file_dec_event_handler, dec->id);
+
+ channel = file_dec_get_output_channel();
+ audio_decoder_set_output_channel(&dec->file_dec.decoder, channel);
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_open(MUSIC_DVOL, app_audio_get_volume(APP_AUDIO_STATE_MUSIC), MUSIC_DVOL_MAX, MUSIC_DVOL_FS, -1);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+ // 设置叠加功能
+ audio_mixer_ch_open(&dec->mix_ch, p_mixer);
+ audio_mixer_ch_set_sample_rate(&dec->mix_ch, dec->file_dec.sample_rate);
+ int ch_num = 1;
+ if (channel == AUDIO_CH_LR) {
+ ch_num = 2;
+ }
+ file_eq_drc_open(dec, dec->file_dec.sample_rate, ch_num);
+
+ sound_pcm_dev_channel_mapping(ch_num);
+
+#if TCFG_DEC2TWS_ENABLE
+ tws_file_decoder_syncts_setup(dec);
+#endif
+
+ app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
+
+ // 设置时钟
+ /*clk_set("sys", 120000000);*/
+ audio_codec_clock_set(AUDIO_FILE_MODE, dec->file_dec.coding_type, dec->wait.preemption);
+
+ dec->file_dec.status = FILE_DEC_STATUS_PLAY;
+ if (dec->evt_cb) {
+ int msg[2];
+ msg[0] = AUDIO_DEC_EVENT_START;
+ dec->evt_cb(dec->evt_priv, 2, msg);
+ }
+
+ err = audio_decoder_start(&dec->file_dec.decoder);
+ if (err) {
+ goto __err2;
+ }
+
+ return 0;
+
+__err2:
+ dec->file_dec.status = 0;
+ audio_mixer_ch_close(&dec->mix_ch);
+ file_eq_drc_close(dec);
+ file_decoder_close(&dec->file_dec);
+
+__err1:
+ if (dec->evt_cb && (dec->wait_add)) {
+ int msg[2];
+ msg[0] = AUDIO_DEC_EVENT_ERR;
+ dec->evt_cb(dec->evt_priv, 2, msg);
+ }
+ file_dec_release();
+ /*clk_set("sys", 24000000);*/
+ audio_codec_clock_del(AUDIO_FILE_MODE);
+
+ return err;
+}
+
+#if TCFG_DEC2TWS_ENABLE
+static void tws_file_trans_timestamp_free(struct file_dec_hdl *dec)
+{
+ if (dec->ts_handle) {
+ file_audio_timestamp_close(dec->ts_handle);
+ dec->ts_handle = NULL;
+ }
+}
+
+static void tws_file_trans_timestamp_create(struct file_dec_hdl *dec)
+{
+ tws_file_trans_timestamp_free(dec);
+ bt_audio_sync_nettime_select(1);
+ dec->ts_handle = file_audio_timestamp_create(0, dec->trans_dec.sample_rate, bt_audio_sync_lat_time(), 250, TIME_US_FACTOR);
+ dec->pcm_num = 0;
+}
+static void send_data_trans_dec_start_cmd();
+static int tws_file_dec_trans_start(void)
+{
+ int err;
+ u8 channel = AUDIO_CH_LR;
+ struct file_dec_hdl *dec = file_dec;
+
+ if (!dec) {
+ return -EINVAL;
+ }
+
+ log_i("file_dec_trans_start: in\n");
+
+ // 打开file解码器
+ err = file_decoder_open(&dec->trans_dec, &file_input, &decode_task, dec->bp, 1);
+ if (err) {
+ goto __err1;
+ }
+ dec->tx_seqn = 1;
+ dec->trans_dec.output_handler = tws_data_trans_handler;
+ file_decoder_set_event_handler(&dec->trans_dec, file_dec_event_handler, dec->id);
+ audio_decoder_set_output_channel(&dec->trans_dec.decoder, channel);
+ audio_decoder_set_run_max(&dec->trans_dec.decoder, 5);
+
+ dec->file_dec.sample_rate = dec->trans_dec.sample_rate;
+ dec->file_dec.coding_type = dec->trans_dec.coding_type & 0x0fffffff;
+
+ log_i("total_time : %d\n", dec->trans_dec.dec_total_time);
+
+ // 设置时钟
+ /*clk_set("sys", 120000000);*/
+ audio_codec_clock_set(AUDIO_FILE_MODE, dec->file_dec.coding_type, dec->wait.preemption);
+
+ dec->tws_channel = tws_api_data_trans_open(dec->tws_channel,
+ TWS_DTC_LOCAL_MEDIA, 10 * 1024);
+
+ send_data_trans_dec_start_cmd();
+
+ int ch_num = 1;
+ if (channel == AUDIO_CH_LR) {
+ ch_num = 2;
+ }
+
+ /* file_eq_drc_open(dec, dec->file_dec.sample_rate, ch_num); */
+ tws_file_trans_timestamp_create(dec);
+ dec->trans_dec_end = 0;
+ dec->trans_dec.status = FILE_DEC_STATUS_PLAY;
+ err = audio_decoder_start(&dec->trans_dec.decoder);
+ if (err) {
+ goto __err2;
+ }
+
+ return 0;
+
+__err2:
+ dec->file_dec.status = 0;
+ file_decoder_close(&dec->file_dec);
+ tws_file_trans_timestamp_free(dec);
+ tws_api_data_trans_stop(dec->tws_channel);
+ file_eq_drc_close(dec);
+
+__err1:
+ file_dec_release();
+ /*clk_set("sys", 24000000);*/
+ audio_codec_clock_del(AUDIO_FILE_MODE);
+
+ return err;
+}
+#endif
+/*----------------------------------------------------------------------------*/
+/**@brief 文件解码资源等待
+ @param *wait: 句柄
+ @param event: 事件
+ @return 0:成功
+ @note 用于多解码打断处理
+*/
+/*----------------------------------------------------------------------------*/
+static int file_wait_res_handler(struct audio_res_wait *wait, int event)
+{
+ int err = 0;
+
+ log_i("file_wait_res_handler, event:%d, status:%d ", event,
+ file_dec->file_dec.status);
+
+ if (event == AUDIO_RES_GET) {
+ // 启动解码
+ if (file_dec->file_dec.status == 0) {
+ err = file_dec_start();
+ } else if (file_dec->file_dec.tmp_pause) {
+ file_dec->file_dec.tmp_pause = 0;
+ if (file_dec->file_dec.status == FILE_DEC_STATUS_PLAY) {
+ audio_mixer_ch_open(&file_dec->mix_ch, &mixer);
+#if TCFG_DEC2TWS_ENABLE
+ tws_api_auto_drop_frame_enable(0);
+ tws_file_decoder_syncts_setup(file_dec);
+#endif
+ err = audio_decoder_start(&file_dec->file_dec.decoder);
+ audio_decoder_resume_all(&decode_task);
+ } else if (file_dec->file_dec.status == FILE_DEC_STATUS_PAUSE) {
+ audio_mixer_ch_open(&file_dec->mix_ch, &mixer);
+ }
+ }
+ } else if (event == AUDIO_RES_PUT) {
+ // 被打断
+ if (file_dec->file_dec.status) {
+ if (file_dec->file_dec.status == FILE_DEC_STATUS_PLAY || \
+ file_dec->file_dec.status == FILE_DEC_STATUS_PAUSE) {
+ audio_decoder_resume_all(&decode_task);
+ err = audio_decoder_pause(&file_dec->file_dec.decoder);
+ audio_mixer_ch_close(&file_dec->mix_ch);
+#if TCFG_DEC2TWS_ENABLE
+ tws_file_decoder_syncts_free(file_dec);
+ tws_api_auto_drop_frame_enable(1);
+#endif
+ }
+ file_dec->file_dec.tmp_pause = 1;
+ }
+ }
+
+ return err;
+}
+
+#if TCFG_DEC2TWS_ENABLE
+
+static void send_data_trans_dec_start_cmd()
+{
+ u8 args[8];
+
+ if (file_dec->file_dec.status) {
+ u32 data[1];
+ data[0] = FILE_DEC_INVITE;
+ tws_api_send_data_to_sibling(data, sizeof(data), TWS_FUNC_ID_FILE_DEC);
+ }
+
+ if (file_dec->file_dec.coding_type == AUDIO_CODING_MP3) {
+ args[0] = 1;
+ } else if (file_dec->file_dec.coding_type == AUDIO_CODING_WMA) {
+ args[0] = 2;
+ }
+ args[1] = file_dec->file_dec.sample_rate;
+ args[2] = file_dec->file_dec.sample_rate >> 8;
+ args[3] = file_dec->id & 0xff;
+
+ tws_api_data_trans_start(file_dec->tws_channel, args, 4);
+}
+
+
+static int tws_file_wait_res_handler(struct audio_res_wait *wait, int event)
+{
+ int err = 0;
+
+ log_i("tws_file_wait_res_handler, event:%d, status:%d ", event,
+ file_dec->trans_dec.status);
+
+ if (event == AUDIO_RES_GET) {
+ // 启动解码
+ if (file_dec->trans_dec.status == 0) {
+ err = tws_file_dec_trans_start();
+ if (err) {
+ return err;
+ }
+ } else if (file_dec->trans_dec.tmp_pause) {
+ file_dec->trans_dec.tmp_pause = 0;
+ if (file_dec->trans_dec.status == FILE_DEC_STATUS_PLAY) {
+ err = audio_decoder_start(&file_dec->trans_dec.decoder);
+ }
+ }
+ } else if (event == AUDIO_RES_PUT) {
+ // 被打断
+ if (file_dec->trans_dec.status) {
+ if (file_dec->trans_dec.status == FILE_DEC_STATUS_PLAY || \
+ file_dec->trans_dec.status == FILE_DEC_STATUS_PAUSE) {
+ err = audio_decoder_pause(&file_dec->trans_dec.decoder);
+ }
+ file_dec->trans_dec.tmp_pause = 1;
+ }
+ }
+
+ file_wait_res_handler(wait, event);
+
+ return err;
+}
+
+void send_local_media_dec_open_cmd()
+{
+ puts("send_local_media_dec_open_cmd\n");
+
+ if (!file_dec) {
+ return;
+ }
+ if (file_dec->trans_dec.status) {
+ puts("---trans_open\n");
+ file_dec->tws_channel = tws_api_data_trans_open(file_dec->tws_channel,
+ TWS_DTC_LOCAL_MEDIA, 10 * 1024);
+ }
+ if (file_dec->file_dec.status) {
+ puts("---dec_open\n");
+ send_data_trans_dec_start_cmd();
+ }
+}
+
+#endif
+/*----------------------------------------------------------------------------*/
+/**@brief file解码pp处理
+ @param play: 1-播放。0-暂停
+ @return
+ @note 弱函数重定义
+*/
+/*----------------------------------------------------------------------------*/
+static void file_dec_pp_ctrl(u8 play)
+{
+ if (!file_dec) {
+ return ;
+ }
+#if TCFG_DEC2TWS_ENABLE
+ if (play) {
+ // 播放前处理
+ if (!file_dec->pick_flag) {
+ audio_mixer_ch_pause(&file_dec->mix_ch, 0);
+ }
+ } else {
+ // 暂停后处理
+ if (!file_dec->pick_flag) {
+ audio_mixer_ch_pause(&file_dec->mix_ch, 1);
+ }
+ audio_decoder_resume_all_by_sem(&decode_task, 2); // 超时等待解码task运行一轮
+ }
+#else
+ if (play) {
+ // 播放前处理
+ if (!file_dec->pick_flag) {
+ audio_mixer_ch_open(&file_dec->mix_ch, &mixer);
+ }
+ } else {
+ // 暂停后处理
+ if (!file_dec->pick_flag) {
+ audio_mixer_ch_close(&file_dec->mix_ch);
+ }
+ audio_decoder_resume_all_by_sem(&decode_task, 2); // 超时等待解码task运行一轮
+ }
+
+#endif
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 创建一个文件解码
+ @param *priv: 事件回调私有参数
+ @param *handler: 事件回调句柄
+ @return 0:成功
+ @return 非0:失败
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+int file_dec_create(void *priv, void (*handler)(void *, int argc, int *argv))
+{
+ struct file_dec_hdl *dec;
+ if (file_dec) {
+ file_dec_close();
+ }
+
+ dec = zalloc(sizeof(*dec));
+ if (!dec) {
+ return -ENOMEM;
+ }
+
+ file_dec = dec;
+ file_dec->evt_cb = handler;
+ file_dec->evt_priv = priv;
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 设置解码数据流设置回调接口
+ @param *dec: 解码句柄
+ @param *stream_handler: 数据流设置回调
+ @param *stream_priv: 数据流设置回调私有句柄
+ @return
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+void file_dec_set_stream_set_hdl(struct file_dec_hdl *dec,
+ void (*stream_handler)(void *priv, int event, struct file_dec_hdl *),
+ void *stream_priv)
+{
+ if (dec) {
+ dec->stream_handler = stream_handler;
+ dec->stream_priv = stream_priv;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 打开文件解码
+ @param *file: 文件句柄
+ @param *bp: 断点信息
+ @return 0:成功
+ @return 非0:失败
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+int file_dec_open(void *file, struct audio_dec_breakpoint *bp)
+{
+ int err;
+ struct file_dec_hdl *dec = file_dec;
+
+ log_i("file_dec_open: in, 0x%x, bp:0x%x \n", file, bp);
+
+ if ((!dec) || (!file)) {
+ return -EPERM;
+ }
+ dec->file = file;
+ dec->bp = bp;
+ dec->id = rand32();
+
+ dec->file_dec.ch_type = AUDIO_CH_MAX;
+ dec->file_dec.output_ch_num = 2;//audio_output_channel_num();
+
+#if TCFG_DEC_DECRYPT_ENABLE
+ cipher_init(&dec->mply_cipher, TCFG_DEC_DECRYPT_KEY);
+ cipher_check_decode_file(&dec->mply_cipher, file);
+#endif
+ dec->wait_add = 1;
+#if TCFG_DEC2TWS_ENABLE
+ dec->wait.priority = 1;
+ dec->wait.preemption = 1;
+ dec->wait.handler = tws_file_wait_res_handler;
+ err = audio_decoder_task_add_wait(&decode_task, &dec->wait);
+#else
+ dec->wait.priority = 1;
+ dec->wait.preemption = 1;
+ dec->wait.handler = file_wait_res_handler;
+ err = audio_decoder_task_add_wait(&decode_task, &dec->wait);
+#endif
+ if (file_dec) {
+ file_dec->wait_add = 0;
+ }
+
+ return err;
+}
+
+int tws_local_media_dec_open(u8 channel, u8 *arg)
+{
+ int err;
+ struct file_dec_hdl *dec = file_dec;
+
+ log_i("tws_local_media_dec_open\n");
+
+ if (!dec) {
+ dec = zalloc(sizeof(*dec));
+ if (!dec) {
+ return -EPERM;
+ }
+ file_dec = dec;
+ }
+
+ if (arg[0] == 1) {
+ dec->file_dec.coding_type = AUDIO_CODING_MP3;
+ } else if (arg[0] == 2) {
+ dec->file_dec.coding_type = AUDIO_CODING_WMA;
+ }
+ dec->file_dec.sample_rate = (arg[2] << 8) | arg[1];
+ dec->id = arg[3];
+#if TCFG_USER_TWS_ENABLE
+ dec->tws_channel = channel;
+#endif
+
+ dec->wait.priority = 1;
+ dec->wait.preemption = 1;
+ dec->wait.handler = file_wait_res_handler;
+ err = audio_decoder_task_add_wait(&decode_task, &dec->wait);
+
+ return err;
+}
+
+int tws_local_media_dec_state()
+{
+ if (!file_dec) {
+ return 0;
+ }
+ if (file_dec->file_dec.status == FILE_DEC_STATUS_PLAY) {
+ return 1;
+ }
+ return 0;
+}
+
+static void __file_dec_close(void)
+{
+ if (!file_dec) {
+ return;
+ }
+
+ if (file_dec->file_dec.status) {
+ file_dec->file_dec.status = 0;
+ audio_mixer_ch_pause(&file_dec->mix_ch, 1);
+ file_decoder_close(&file_dec->file_dec);
+ file_eq_drc_close(file_dec);
+ tws_file_decoder_syncts_free(file_dec);
+ audio_mixer_ch_close(&file_dec->mix_ch);
+
+ if (file_dec->stream_handler) {
+ file_dec->stream_handler(file_dec->stream_priv, FILE_DEC_STREAM_CLOSE,
+ file_dec);
+ }
+#if TCFG_DEC2TWS_ENABLE
+ if (file_dec->frame) {
+ tws_api_data_trans_free(file_dec->tws_channel, file_dec->frame);
+ file_dec->frame = NULL;
+ }
+#endif
+ }
+
+ file_dec_release();
+
+ log_i("file_dec_close: exit\n");
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 关闭文件解码
+ @param
+ @return
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+void file_dec_close(void)
+{
+#if TCFG_DEC2TWS_ENABLE
+ if (!file_dec) {
+ return;
+ }
+ if (file_dec->trans_dec.status) {
+ file_dec->trans_dec.status = 0;
+ file_decoder_close(&file_dec->trans_dec);
+ tws_api_data_trans_stop(file_dec->tws_channel);
+ file_eq_drc_close(file_dec);
+ }
+
+ tws_file_trans_timestamp_free(file_dec);
+ tws_api_data_trans_clear(file_dec->tws_channel);
+#endif
+ __file_dec_close();
+
+}
+
+#if TCFG_DEC2TWS_ENABLE
+void tws_local_media_dec_close()
+{
+ file_dec_close();
+}
+#endif
+
+/*----------------------------------------------------------------------------*/
+/**@brief 获取file_dec句柄
+ @param
+ @return file_dec句柄
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+struct file_decoder *file_dec_get_file_decoder_hdl(void)
+{
+ if (!file_dec) {
+ return NULL;
+ }
+
+#if TCFG_DEC2TWS_ENABLE
+ return &file_dec->trans_dec;
+#else
+ return &file_dec->file_dec;
+#endif
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 获取file_dec状态
+ @param
+ @return 解码状态
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+int file_dec_get_status(void)
+{
+ struct file_decoder *dec = file_dec_get_file_decoder_hdl();
+ if (dec) {
+ return dec->status;
+ }
+ return FILE_DEC_STATUS_STOP;
+}
+
+int file_dec_get_source()
+{
+ if (!file_dec) {
+ return -EINVAL;
+ }
+#if TCFG_DEC2TWS_ENABLE
+ if (file_dec->trans_dec.status) {
+ return FILE_FROM_LOCAL;
+ }
+ if (file_dec->file_dec.status) {
+ return FILE_FROM_TWS;
+ }
+#else
+ if (file_dec->file_dec.status) {
+ return FILE_FROM_LOCAL;
+ }
+#endif
+ return -EINVAL;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 文件解码重新开始
+ @param id: 文件解码id
+ @return 0:成功
+ @return 非0:失败
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+int file_dec_restart(int id)
+{
+ if ((!file_dec) || (id != file_dec->id)) {
+ return -1;
+ }
+ if (file_dec->bp == NULL) {
+ if (file_dec->dec_bp == NULL) {
+ file_dec->dec_bp = zalloc(sizeof(struct audio_dec_breakpoint) +
+ BREAKPOINT_DATA_LEN);
+ ASSERT(file_dec->dec_bp);
+ file_dec->dec_bp->data_len = BREAKPOINT_DATA_LEN;
+ }
+ file_dec->bp = file_dec->dec_bp;
+ }
+ if (file_dec->file_dec.status && file_dec->bp) {
+ audio_decoder_get_breakpoint(&file_dec->file_dec.decoder, file_dec->bp);
+ }
+
+ void *file = file_dec->file;
+ void *bp = file_dec->bp;
+ void *evt_cb = file_dec->evt_cb;
+ void *evt_priv = file_dec->evt_priv;
+ int err;
+ void *dec_bp = file_dec->dec_bp; // 先保存一下,避免close被释放
+ file_dec->dec_bp = NULL;
+
+ file_dec_close();
+
+ err = file_dec_create(evt_priv, evt_cb);
+ if (!err) {
+ file_dec->dec_bp = dec_bp; // 还原回去
+ err = file_dec_open(file, bp);
+ } else {
+ if (dec_bp) {
+ free(dec_bp); // 失败,释放
+ }
+ }
+ return err;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 推送文件解码重新开始命令
+ @param
+ @return true:成功
+ @return false:失败
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+int file_dec_push_restart(void)
+{
+ if (!file_dec) {
+ return false;
+ }
+ int argv[3];
+ argv[0] = (int)file_dec_restart;
+ argv[1] = 1;
+ argv[2] = (int)file_dec->id;
+ os_taskq_post_type(os_current_task(), Q_CALLBACK, ARRAY_SIZE(argv), argv);
+ return true;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief file decoder pp处理
+ @param *dec: file解码句柄
+ @param play: 1-播放。0-暂停
+ @return
+ @note 弱函数重定义
+*/
+/*----------------------------------------------------------------------------*/
+void file_decoder_pp_ctrl(struct file_decoder *dec, u8 play)
+{
+ if (file_dec && (&file_dec->file_dec == dec)) {
+ file_dec_pp_ctrl(play);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 音乐模式 eq drc 打开
+ @param sample_rate:采样率
+ @param ch_num:通道个数
+ @return 句柄
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+void file_eq_drc_open(struct file_dec_hdl *hdl, u16 sample_rate, u8 ch_num)
+{
+#if TCFG_EQ_ENABLE&&TCFG_MUSIC_MODE_EQ_ENABLE
+ u8 drc_en = 0;
+#if TCFG_DRC_ENABLE&&TCFG_MUSIC_MODE_DRC_ENABLE
+ drc_en = 1;
+#endif//TCFG_MUSIC_MODE_DRC_ENABLE
+
+ hdl->eq_drc = dec_eq_drc_setup(&hdl->mix_ch, (eq_output_cb)audio_mixer_ch_write, sample_rate, ch_num, 1, drc_en);
+#endif//TCFG_MUSIC_MODE_EQ_ENABLE
+
+}
+/*----------------------------------------------------------------------------*/
+/**@brief 音乐模式 eq drc 关闭
+ @param 句柄
+ @return
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+void file_eq_drc_close(struct file_dec_hdl *hdl)
+{
+#if TCFG_EQ_ENABLE&&TCFG_MUSIC_MODE_EQ_ENABLE
+ if (hdl->eq_drc) {
+ dec_eq_drc_free(hdl->eq_drc);
+ hdl->eq_drc = NULL;
+ }
+#endif//TCFG_MUSIC_MODE_EQ_ENABLE
+
+}
+
+
+#endif /*TCFG_APP_MUSIC_EN*/
+
diff --git a/cpu/br28/audio_dec/audio_dec_file.h b/cpu/br28/audio_dec/audio_dec_file.h
new file mode 100644
index 0000000..4a238e1
--- /dev/null
+++ b/cpu/br28/audio_dec/audio_dec_file.h
@@ -0,0 +1,127 @@
+
+#ifndef _AUDIO_DEC_FILE_H_
+#define _AUDIO_DEC_FILE_H_
+
+#include "asm/includes.h"
+#include "media/includes.h"
+#include "media/file_decoder.h"
+#include "system/includes.h"
+#include "media/audio_decoder.h"
+#include "app_config.h"
+//#include "music/music_decrypt.h"
+//#include "music/music_id3.h"
+
+#include "audio_dec_eff.h"
+
+
+#define FILE_DEC_REPEAT_EN 0 // 无缝循环播放
+
+enum {
+ FILE_DEC_STREAM_CLOSE = 0,
+ FILE_DEC_STREAM_OPEN,
+};
+
+struct file_dec_hdl {
+ //struct audio_stream *stream; // 音频流
+ struct file_decoder file_dec; // file解码句柄
+ struct audio_res_wait wait; // 资源等待句柄
+#if TCFG_USER_TWS_ENABLE
+ struct file_decoder trans_dec; // 解码句柄
+ u8 *frame;
+ u16 frame_len;
+ u16 frame_remain_len;
+ u8 trans_dec_end;
+ u8 wait_tws_confirm;
+ u8 tws_channel;
+ u16 seqn;
+ u16 tx_seqn;
+ u32 wait_tws_timeout;
+ void *ts_handle;
+ void *syncts;
+ u32 pcm_num;
+ u32 mix_ch_event_params[3];
+#endif
+ struct audio_mixer_ch mix_ch; // 叠加句柄
+
+#if TCFG_EQ_ENABLE&&TCFG_MUSIC_MODE_EQ_ENABLE
+ struct dec_eq_drc *eq_drc;
+#endif//TCFG_MUSIC_MODE_EQ_ENABLE
+
+ u8 remain;
+
+ struct audio_dec_breakpoint *dec_bp; // 断点
+ u32 id; // 唯一标识符,随机值
+ void *file; // 文件句柄
+ u32 pick_flag : 1; // 挑出数据帧发送(如MP3等)。不是输出pcm,后级不能接任何音效处理等
+ u32 pcm_enc_flag : 1; // pcm压缩成数据帧发送(如WAV等)
+ u32 read_err : 2; // 读数出错 0:no err, 1:fat err, 2:disk err
+ u32 wait_add : 1; // 是否马上得到执行
+
+#if TCFG_DEC_DECRYPT_ENABLE
+ CIPHER mply_cipher; // 解密播放
+#endif
+#if TCFG_DEC_ID3_V1_ENABLE
+ MP3_ID3_OBJ *p_mp3_id3_v1; // id3_v1信息
+#endif
+#if TCFG_DEC_ID3_V2_ENABLE
+ MP3_ID3_OBJ *p_mp3_id3_v2; // id3_v2信息
+#endif
+
+#if FILE_DEC_REPEAT_EN
+ u8 repeat_num; // 无缝循环次数
+ struct fixphase_repair_obj repair_buf; // 无缝循环句柄
+#endif
+
+ struct audio_dec_breakpoint *bp; // 断点信息
+
+ void *evt_priv; // 事件回调私有参数
+ void (*evt_cb)(void *, int argc, int *argv); // 事件回调句柄
+
+ void (*stream_handler)(void *priv, int event, struct file_dec_hdl *); // 数据流设置回调
+ void *stream_priv; // 数据流设置回调私有句柄
+};
+
+enum {
+ FILE_FROM_LOCAL,
+ FILE_FROM_TWS,
+};
+
+
+
+struct file_decoder *file_dec_get_file_decoder_hdl(void);
+
+#define file_dec_is_stop() file_decoder_is_stop(file_dec_get_file_decoder_hdl())
+#define file_dec_is_play() file_decoder_is_play(file_dec_get_file_decoder_hdl())
+#define file_dec_is_pause() file_decoder_is_pause(file_dec_get_file_decoder_hdl())
+#define file_dec_pp() file_decoder_pp(file_dec_get_file_decoder_hdl())
+#define file_dec_FF(x) file_decoder_FF(file_dec_get_file_decoder_hdl(),x)
+#define file_dec_FR(x) file_decoder_FR(file_dec_get_file_decoder_hdl(),x)
+#define file_dec_get_breakpoint(x) file_decoder_get_breakpoint(file_dec_get_file_decoder_hdl(),x)
+#define file_dec_get_total_time() file_decoder_get_total_time(file_dec_get_file_decoder_hdl())
+#define file_dec_get_cur_time() file_decoder_get_cur_time(file_dec_get_file_decoder_hdl())
+#define file_dec_get_decoder_type() file_decoder_get_decoder_type(file_dec_get_file_decoder_hdl())
+
+int file_dec_create(void *priv, void (*handler)(void *, int argc, int *argv));
+int file_dec_open(void *file, struct audio_dec_breakpoint *bp);
+void file_dec_close();
+int file_dec_restart(int id);
+int file_dec_push_restart(void);
+int file_dec_get_status(void);
+
+void file_dec_set_stream_set_hdl(struct file_dec_hdl *dec,
+ void (*stream_handler)(void *priv, int event, struct file_dec_hdl *),
+ void *stream_priv);
+void *get_file_dec_hdl();
+
+int tws_local_media_dec_open(u8 channel, u8 *arg);
+
+void tws_local_media_dec_close(u8 channel);
+
+int tws_local_media_dec_state();
+
+void send_local_media_dec_open_cmd();
+
+int file_dec_get_source();
+
+#endif /*TCFG_APP_MUSIC_EN*/
+
diff --git a/cpu/br28/audio_dec/audio_dec_iis.c b/cpu/br28/audio_dec/audio_dec_iis.c
new file mode 100644
index 0000000..b46879c
--- /dev/null
+++ b/cpu/br28/audio_dec/audio_dec_iis.c
@@ -0,0 +1,391 @@
+#include "audio_dec_iis.h"
+#include "app_config.h"
+#include "audio_decoder.h"
+#include "media/includes.h"
+#include "audio_config.h"
+#include "system/includes.h"
+#include "audio_enc.h"
+#include "application/audio_eq.h"
+#include "application/audio_drc.h"
+#include "app_config.h"
+#include "audio_config.h"
+#include "audio_dec.h"
+#include "app_main.h"
+#include "clock_cfg.h"
+#include "audio_dec_eff.h"
+#include "audio_codec_clock.h"
+#include "audio_dvol.h"
+#include "audio_link.h"
+#include "circular_buf.h"
+#include "sound_device.h"
+
+
+#if (TCFG_AUDIO_INPUT_IIS)
+
+extern ALINK_PARM alink0_platform_data;
+extern struct audio_dac_hdl dac_hdl;
+extern struct audio_decoder_task decode_task;
+extern struct audio_mixer mixer;
+/* extern void *hw_alink; //alink初始化句柄 */
+#define IIS_IN_STORE_PCM_SIZE (4 * 1024)
+
+//iis 驱动结构体
+struct iis_in_sample_hdl {
+ OS_SEM sem;
+ s16 *store_pcm_buf;
+ cbuffer_t cbuf;
+ int sample_rate;
+ void *hw_alink;
+ void *alink_ch;
+};
+
+// iis 输入解码结构体
+struct iis_in_dec_hdl {
+ struct audio_decoder decoder;
+ struct audio_res_wait wait;
+ struct audio_mixer_ch mix_ch;
+ u8 channel;
+ u8 start;
+ u8 need_resume;
+ u8 remain;
+ u8 output_ch;
+ int sample_rate;
+ void *iis_in; //驱动句柄
+};
+static struct iis_in_dec_hdl *iis_in_dec = NULL;
+
+// ********************** iis in 驱动 ************************* //
+static void iis_in_dec_resume(void)
+{
+ if (iis_in_dec) {
+ audio_decoder_resume(&iis_in_dec->decoder);
+ }
+}
+
+static void pcm_LR_to_mono(s16 *pcm_lr, s16 *pcm_mono, int points_len)
+{
+ s16 pcm_L;
+ s16 pcm_R;
+ int i = 0;
+
+ for (i = 0; i < points_len; i++, pcm_lr += 2) {
+ pcm_L = *pcm_lr;
+ pcm_R = *(pcm_lr + 1);
+ *pcm_mono++ = (s16)(((int)pcm_L + pcm_R) >> 1);
+ }
+}
+
+static void iis_in_data_handler(void *priv, void *_data, int len)
+{
+ struct iis_in_sample_hdl *iis_in = (struct iis_in_sample_hdl *)priv;
+ s16 *data = (s16 *)_data;
+ u16 temp_len = len;
+ int wlen = 0;
+
+ if (iis_in_dec->start == 0) {
+ goto __exit;
+ }
+ //iis 默认输入的是双声道数据
+ if (iis_in_dec->output_ch == 1) {
+ s16 *mono_data = data;
+ for (int i = 0; i < len / 4; i++) {
+ mono_data[i] = mono_data[i * 2];
+ }
+ len = len / 2;
+ wlen = cbuf_write(&iis_in->cbuf, mono_data, len);
+ if (wlen != len) {
+ putchar('w');
+ }
+ } else if (iis_in_dec->output_ch == 2) {
+ wlen = cbuf_write(&iis_in->cbuf, data, len);
+ /* os_sem_post(&iis_in->sem); */
+ if (wlen != len) {
+ putchar('W');
+ }
+ } else {
+ putchar('e');
+ goto __exit;
+ }
+
+ if (iis_in_dec && iis_in_dec->need_resume) {
+ iis_in_dec->need_resume = 0;
+ iis_in_dec_resume();
+ }
+__exit:
+ alink_set_shn(&alink0_platform_data.ch_cfg[1], temp_len / 4);
+}
+
+static void *iis_in_open(int sr)
+{
+ struct iis_in_sample_hdl *iis_in = NULL;
+ iis_in = zalloc(sizeof(struct iis_in_sample_hdl));
+ if (!iis_in) {
+ return NULL;
+ }
+ iis_in->store_pcm_buf = malloc(IIS_IN_STORE_PCM_SIZE);
+ if (!iis_in->store_pcm_buf) {
+ free(iis_in);
+ return NULL;
+ }
+ cbuf_init(&iis_in->cbuf, iis_in->store_pcm_buf, IIS_IN_STORE_PCM_SIZE);
+ iis_in->hw_alink = (ALINK_PARM *)get_iis_alink_param();
+ if (iis_in->hw_alink == NULL) {
+ iis_in->hw_alink = alink_init(&alink0_platform_data);
+ }
+ iis_in->alink_ch = alink_channel_init(iis_in->hw_alink, 1, ALINK_DIR_RX, (void *)iis_in, iis_in_data_handler);
+ alink_start(iis_in->hw_alink);
+ iis_in->sample_rate = sr;
+ return iis_in;
+}
+
+
+// *********************** iis in dec 解码 ***************************//
+static int iis_in_stream_read(struct audio_decoder *decoder, void *buf, u32 len)
+{
+ int rlen = 0;
+ struct iis_in_sample_hdl *iis_in = (struct iis_in_sample_hdl *)iis_in_dec->iis_in;
+ if (!iis_in || iis_in_dec->start == 0) {
+ goto __exit;
+ }
+ if (!iis_in->store_pcm_buf) {
+ goto __exit;
+ }
+ int read_len = cbuf_get_data_size(&iis_in->cbuf);
+ if (read_len) {
+ read_len = read_len > len ? len : read_len;
+ rlen = cbuf_read(&iis_in->cbuf, buf, read_len);
+ /* printf("--- rlen : %d\n", rlen); */
+ }
+__exit:
+ if (!rlen) {
+ iis_in_dec->need_resume = 1;
+ return -1;
+ }
+ /* y_printf("--- rlen = %d\n",rlen); */
+ return rlen;
+}
+
+static int iis_in_dec_probe_handler(struct audio_decoder *decoder)
+{
+ /* struct pcm_dec_hdl *dec = container_of(decoder, struct pcm_dec_hdl, decoder); */
+ struct iis_in_dec_hdl *dec = container_of(decoder, struct iis_in_dec_hdl, decoder);
+ return 0;
+}
+
+static int iis_in_dec_output_handler(struct audio_decoder *decoder, s16 *data, int len, void *priv)
+{
+ struct iis_in_dec_hdl *dec = container_of(decoder, struct iis_in_dec_hdl, decoder);
+
+ if (!dec) {
+ return 0;
+ }
+ int rlen = len;
+ int wlen = 0;
+
+ if (!dec->remain) {
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_run(MUSIC_DVOL, data, len);
+#endif
+ }
+
+ wlen = audio_mixer_ch_write(&dec->mix_ch, data, rlen);
+ if (!wlen) {
+ putchar('w');
+ }
+ rlen -= wlen;
+
+ if (rlen == 0) {
+ dec->remain = 0;
+ } else {
+ dec->remain = 1;
+ }
+ return len - rlen;
+}
+
+static const struct audio_dec_handler iis_in_dec_handler = {
+ .dec_probe = iis_in_dec_probe_handler,
+ .dec_output = iis_in_dec_output_handler,
+};
+
+static const struct audio_dec_input iis_input = {
+ .coding_type = AUDIO_CODING_PCM,
+ .data_type = AUDIO_INPUT_FILE,
+ .ops = {
+ .file = {
+ .fread = iis_in_stream_read,
+ }
+ }
+};
+
+static void iis_in_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
+{
+ switch (argv[0]) {
+ case AUDIO_DEC_EVENT_END:
+ /*pcm_audio_close();*/
+ break;
+ }
+}
+
+//开始 iis dec 解码
+static int iis_in_dec_start(void)
+{
+ int err;
+ y_printf(">>>>>>>> Enter Func: %s \n", __func__);
+ struct audio_fmt f = {0};
+ struct iis_in_dec_hdl *dec = iis_in_dec;
+
+ if (!iis_in_dec && iis_in_dec->start == 1) {
+ return -EINVAL;
+ }
+
+ err = audio_decoder_open(&dec->decoder, &iis_input, &decode_task);
+ if (err) {
+ goto __err;
+ }
+ if (dec->iis_in == NULL) {
+ y_printf("--> %s, %d, Init iis_in!\n", __func__, __LINE__);
+ dec->iis_in = iis_in_open(dec->sample_rate);
+ if (!dec->iis_in) {
+ goto __err;
+ }
+ }
+
+ audio_decoder_set_handler(&dec->decoder, &iis_in_dec_handler);
+ audio_decoder_set_event_handler(&dec->decoder, iis_in_dec_event_handler, 0);
+ u8 dac_conn = audio_dac_get_channel(&dac_hdl);
+ if (dac_conn == DAC_OUTPUT_LR) {
+ dec->output_ch = 2;
+ } else {
+ dec->output_ch = 1;
+ }
+
+ f.coding_type = AUDIO_CODING_PCM;
+ f.sample_rate = dec->sample_rate;
+ f.channel = dec->output_ch;
+
+ sound_pcm_dev_channel_mapping(dec->output_ch);
+
+ err = audio_decoder_set_fmt(&dec->decoder, &f);
+ if (err) {
+ goto __err;
+ }
+
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_open(MUSIC_DVOL, app_audio_get_volume(APP_AUDIO_STATE_MUSIC), MUSIC_DVOL_MAX, MUSIC_DVOL_FS, -1);
+#endif
+
+ // 设置叠加功能
+ audio_mixer_ch_open(&dec->mix_ch, &mixer);
+ audio_mixer_ch_set_sample_rate(&dec->mix_ch, audio_output_rate(f.sample_rate));
+ app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
+
+ int vol = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
+ app_audio_set_volume(APP_AUDIO_STATE_MUSIC, vol, 1);
+
+ err = audio_decoder_start(&dec->decoder);
+ if (err) {
+ goto __err;
+ }
+ /* audio_codec_clock_set(AUDIO_PC_MODE, AUDIO_CODING_PCM, dec->wait.preemption); */
+ dec->start = 1;
+ return 0;
+
+__err:
+ return err;
+}
+
+// iis in 解码资源等待
+void iis_in_dec_stop(void);
+
+static int iis_in_wait_res_handler(struct audio_res_wait *wait, int event)
+{
+ int err = 0;
+ if (event == AUDIO_RES_GET) {
+ // 启动解码
+ err = iis_in_dec_start();
+ } else if (event == AUDIO_RES_PUT) {
+ // 被打断
+ iis_in_dec_stop();
+ }
+ return err;
+}
+
+int iis_in_dec_open(void)
+{
+ int err;
+ struct iis_in_dec_hdl *dec = NULL;;
+ dec = zalloc(sizeof(*dec));
+ if (!dec) {
+ return -ENOMEM;
+ }
+ iis_in_dec = dec;
+ dec->sample_rate = TCFG_IIS_SR;
+ dec->channel = 2; //iis 是双声道数据
+ dec->wait.priority = 2;
+ dec->wait.preemption = 1;
+ dec->wait.handler = iis_in_wait_res_handler;
+
+ err = audio_decoder_task_add_wait(&decode_task, &dec->wait);
+ clock_add(DEC_PCM_CLK);
+ return err;
+}
+
+
+void iis_in_dec_stop(void)
+{
+ if (iis_in_dec && iis_in_dec->start == 1) {
+ struct iis_in_sample_hdl *iis_in = (struct iis_in_sample_hdl *)iis_in_dec->iis_in;
+ iis_in_dec->start = 0;
+ audio_decoder_close(&iis_in_dec->decoder);
+ audio_mixer_ch_close(&iis_in_dec->mix_ch);
+ app_audio_state_exit(APP_AUDIO_STATE_MUSIC);
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_close(MUSIC_DVOL);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+ local_irq_disable();
+#if 1
+ if (iis_in) {
+ void *alink_p = (ALINK_PARM *)get_iis_alink_param();
+ if (iis_in->hw_alink && !alink_p) {
+ alink_uninit(iis_in->hw_alink);
+ iis_in->hw_alink = NULL;
+ } else {
+ /* alink_uninit(iis_in->hw_alink); */
+ alink_channel_close(iis_in->alink_ch);
+ }
+ if (iis_in->store_pcm_buf) {
+ free(iis_in->store_pcm_buf);
+ iis_in->store_pcm_buf = NULL;
+ }
+ free(iis_in);
+ iis_in = NULL;
+ iis_in_dec->iis_in = NULL;
+ }
+#endif
+ local_irq_enable();
+ }
+}
+
+void iis_in_dec_close(void)
+{
+ if (!iis_in_dec) {
+ return;
+ }
+ iis_in_dec_stop();
+ audio_decoder_task_del_wait(&decode_task, &iis_in_dec->wait);
+ clock_remove(DEC_PCM_CLK);
+ local_irq_disable();
+ free(iis_in_dec);
+ iis_in_dec = NULL;
+ local_irq_enable();
+}
+
+
+
+#endif
+
+
+
diff --git a/cpu/br28/audio_dec/audio_dec_iis.h b/cpu/br28/audio_dec/audio_dec_iis.h
new file mode 100644
index 0000000..8aea956
--- /dev/null
+++ b/cpu/br28/audio_dec/audio_dec_iis.h
@@ -0,0 +1,9 @@
+#ifndef __AUDIO_DEC_IIS_H
+#define __AUDIO_DEC_IIS_H
+
+
+
+
+
+#endif
+
diff --git a/cpu/br28/audio_dec/audio_dec_pc.c b/cpu/br28/audio_dec/audio_dec_pc.c
new file mode 100644
index 0000000..4cba5d2
--- /dev/null
+++ b/cpu/br28/audio_dec/audio_dec_pc.c
@@ -0,0 +1,921 @@
+#include "uac_stream.h"
+#include "app_config.h"
+#include "audio_decoder.h"
+#include "media/includes.h"
+#include "audio_config.h"
+#include "system/includes.h"
+#include "audio_enc.h"
+#include "application/audio_eq.h"
+#include "application/audio_drc.h"
+#include "app_config.h"
+#include "audio_config.h"
+#include "audio_dec.h"
+#include "app_main.h"
+#include "clock_cfg.h"
+#include "audio_dec_eff.h"
+#include "audio_codec_clock.h"
+#include "audio_dvol.h"
+#include "sound_device.h"
+
+#if TCFG_UI_ENABLE
+#include "ui/ui_api.h"
+#endif
+
+
+#if TCFG_PC_ENABLE//TCFG_APP_PC_EN
+#if (defined(TCFG_PCM2TWS_SBC_ENABLE) && (TCFG_PCM2TWS_SBC_ENABLE))
+#define UAC_DEC_PCM_ENC_TYPE AUDIO_CODING_SBC
+#define UAC_DEC_PCM_ENC_CHANNEL AUDIO_CH_LR
+#else
+#define UAC_DEC_PCM_ENC_TYPE AUDIO_CODING_MP3
+#define UAC_DEC_PCM_ENC_CHANNEL AUDIO_CH_LR
+#endif
+
+struct usb_audio_handle {
+ int top_size;
+ int bottom_size;
+ int begin_size;
+};
+
+#define RATE_INC_STEP 2
+#define RATE_DEC_STEP 2
+
+
+struct uac_dec_hdl {
+ struct audio_decoder decoder;
+ struct audio_res_wait wait;
+ struct audio_mixer_ch mix_ch;
+ int begin_size;
+ int top_size;
+ int bottom_size;
+ u8 start;
+ u8 channel;
+ u8 output_ch;
+ u8 sync_start;
+ u32 src_out_sr;
+ u32 dec_no_out_sound : 1; // 解码不直接输出声音(用于TWS转发)
+ u32 sample_rate;
+ u32 audio_new_rate;
+ u32 usb_audio_max_speed;
+ u32 usb_audio_min_speed;
+ struct audio_src_handle *src_sync;
+ u8 remain;
+#if TCFG_EQ_ENABLE&&TCFG_PC_MODE_EQ_ENABLE
+ struct dec_eq_drc *eq_drc;
+#endif
+
+
+ struct user_audio_parm *user_hdl;
+
+
+ u32 cnt: 8;
+
+ u32 state: 1;
+
+ int check_data_timer;
+
+
+};
+
+extern struct audio_dac_hdl dac_hdl;
+extern struct audio_decoder_task decode_task;
+extern struct audio_mixer mixer;
+
+static u16 sys_event_id = 0;
+static struct uac_dec_hdl *uac_dec = NULL;
+
+static u8 uac_dec_maigc = 0;
+
+
+extern void uac_get_cur_vol(const u8 id, u16 *l_vol, u16 *r_vol);
+extern u8 uac_get_mute(void);
+extern void bt_tws_sync_volume();
+
+void pc_eq_drc_open(struct uac_dec_hdl *dec, struct audio_fmt *fmt);
+void pc_eq_drc_close(struct uac_dec_hdl *dec);
+
+int uac_vol_switch(int vol)
+{
+ u16 valsum = vol * (SYS_MAX_VOL + 1) / 100;
+
+ if (valsum > SYS_MAX_VOL) {
+ valsum = SYS_MAX_VOL;
+ }
+ return valsum;
+}
+
+static void uac_dec_set_output_channel(struct uac_dec_hdl *dec)
+{
+ u8 dac_conn = audio_dac_get_channel(&dac_hdl);
+
+ if (dac_conn == DAC_OUTPUT_LR) {
+ dec->output_ch = 2;
+ } else {
+
+ dec->output_ch = 1;
+ }
+}
+
+static int uac_sync_output_handler(void *priv, void *buf, int len)
+{
+ struct uac_dec_hdl *dec = (struct uac_dec_hdl *)priv;
+ int remain_len = len;
+ int wlen = 0;
+ s16 *data = (s16 *)buf;
+
+#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
+ if (dec->dec_no_out_sound) {
+ return pcm2tws_enc_output(NULL, data, len);
+ }
+#endif
+
+ wlen = audio_mixer_ch_write(&dec->mix_ch, data, len);
+ return wlen;
+}
+
+
+static void pcm_LR_to_mono(s16 *pcm_lr, s16 *pcm_mono, int points_len)
+{
+ s16 pcm_L;
+ s16 pcm_R;
+ int i = 0;
+
+ for (i = 0; i < points_len; i++, pcm_lr += 2) {
+ pcm_L = *pcm_lr;
+ pcm_R = *(pcm_lr + 1);
+ *pcm_mono++ = (s16)(((int)pcm_L + pcm_R) >> 1);
+ }
+}
+
+
+static int uac_dec_output_handler(struct audio_decoder *decoder, s16 *data, int len, void *priv)
+{
+ struct uac_dec_hdl *dec = container_of(decoder, struct uac_dec_hdl, decoder);
+ int rlen = len;
+ int wlen = 0;
+
+
+ /* if (dec->channel == 2 && dec->output_ch == 1) { //这里 */
+
+ /* pcm_LR_to_mono((s16 *)data, (s16 *)data, len >> 2); //这里有双声道转单声道 */
+ /* len >>= 1; */
+ /* } */
+
+
+ if (!dec->remain) {
+#if (defined(USER_AUDIO_PROCESS_ENABLE) && (USER_AUDIO_PROCESS_ENABLE != 0))
+ if (dec->user_hdl) {
+ u8 ch_num = dec->output_ch;
+ user_audio_process_handler_run(dec->user_hdl, data, len, ch_num);
+ }
+#endif
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_run(MUSIC_DVOL, data, len);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+ }
+#if TCFG_EQ_ENABLE&&TCFG_PC_MODE_EQ_ENABLE
+ if (dec->eq_drc && dec->eq_drc->async) {
+ int eqlen = eq_drc_run(dec->eq_drc, data, len);
+ len -= eqlen;
+ if (len == 0) {
+ dec->remain = 0;
+ } else {
+ dec->remain = 1;
+ }
+ return eqlen;
+ }
+
+ if (!dec->remain) {
+ eq_drc_run(dec->eq_drc, data, len);
+ }
+#endif//TCFG_PC_MODE_EQ_ENABLE
+
+ if (dec->src_sync) {
+ wlen = audio_src_resample_write(dec->src_sync, data, rlen);
+ /*printf("%d - %d\n", len, wlen);*/
+ /* return wlen; */
+#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
+ } else if (dec->dec_no_out_sound) {
+ wlen = pcm2tws_enc_output(NULL, data, rlen);
+#endif
+ } else {
+ wlen = audio_mixer_ch_write(&dec->mix_ch, data, rlen);
+ }
+
+ rlen -= wlen;
+
+ if (rlen == 0) {
+ dec->remain = 0;
+ } else {
+ dec->remain = 1;
+ }
+
+
+ return len - rlen;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 检测uac是否收到数据,没数据时暂停mix_ch
+ @param *priv: 私有参数
+ @return
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+static void audio_pc_check_timer(void *priv)
+{
+#if 1
+ u8 alive = uac_speaker_get_alive();
+ if (alive) {
+ uac_dec->cnt++;
+ if (uac_dec->cnt > 5) {
+ if (!uac_dec->state) {
+#if TCFG_DEC2TWS_ENABLE
+ if (uac_dec->pcm_dec.dec_no_out_sound) {
+ localtws_decoder_pause(1);
+ }
+#endif
+ audio_mixer_ch_pause(&uac_dec->mix_ch, 1);
+ audio_decoder_resume_all(&decode_task);
+ uac_dec->state = 1;
+ }
+ }
+ } else {
+ if (uac_dec->cnt) {
+ uac_dec->cnt--;
+ }
+ if (uac_dec->state) {
+ uac_dec->state = 0;
+ uac_dec->cnt = 0;
+#if TCFG_DEC2TWS_ENABLE
+ if (uac_dec->pcm_dec.dec_no_out_sound) {
+ localtws_decoder_pause(0);
+ }
+#endif
+ audio_mixer_ch_pause(&uac_dec->mix_ch, 0);
+ audio_decoder_resume_all(&decode_task);
+ }
+ }
+ uac_speaker_set_alive(1);
+#else
+ static u8 cnt = 0;
+ if (uac_speaker_stream_size(NULL) == 0) {
+ if (cnt < 20) {
+ cnt++;
+ }
+ if (cnt == 15) {
+#if TCFG_DEC2TWS_ENABLE
+ if (uac_dec->pcm_dec.dec_no_out_sound) {
+ localtws_decoder_pause(1);
+ }
+#endif
+ audio_mixer_ch_pause(&uac_dec->mix_ch, 1);
+ audio_decoder_resume_all(&decode_task);
+ }
+ } else {
+ if (cnt > 14) {
+#if TCFG_DEC2TWS_ENABLE
+ if (uac_dec->pcm_dec.dec_no_out_sound) {
+ localtws_decoder_pause(0);
+ }
+#endif
+ audio_mixer_ch_pause(&uac_dec->mix_ch, 0);
+ audio_decoder_resume_all(&decode_task);
+ }
+ cnt = 0;
+ }
+#endif
+}
+
+
+
+static int uac_stream_read(struct audio_decoder *decoder, void *buf, u32 len)
+{
+ int rlen = 0;
+ struct uac_dec_hdl *dec = container_of(decoder, struct uac_dec_hdl, decoder);
+
+ if (!dec->sync_start) {
+ if (uac_speaker_stream_size() < dec->begin_size) {
+ return -1;
+ }
+ dec->sync_start = 1;
+ }
+
+
+ rlen = uac_speaker_read(NULL, (void *)buf, len);
+
+ if (dec->channel == 2 && dec->output_ch == 1) {
+ pcm_LR_to_mono((s16 *)buf, (s16 *)buf, rlen >> 2);
+ rlen >>= 1;
+ }
+
+
+
+ if (!rlen) {
+
+
+ return -1;
+ }
+
+
+ return rlen;
+}
+
+static const struct audio_dec_input uac_input = {
+ .coding_type = AUDIO_CODING_PCM,
+ .data_type = AUDIO_INPUT_FILE,
+ .ops = {
+ .file = {
+ .fread = uac_stream_read,
+ /*.fseek = uac_stream_seek,*/
+ /*.flen = uac_stream_len,*/
+ }
+ }
+};
+int uac_speaker_stream_sample_rate(void);
+static int usb_audio_stream_sync(struct uac_dec_hdl *dec, int data_size)
+{
+ if (!dec->src_sync) {
+ return 0;
+ }
+
+#if 1
+//优化下行播放同步得调节步进
+
+ u32 in_sr = uac_speaker_stream_sample_rate();
+
+ u32 out_sr = (long long)dec->audio_new_rate * (long long)in_sr / dec->sample_rate; //统计得输入采样率,转换成输出采样率
+
+
+ if (data_size < dec->bottom_size) {
+ out_sr += out_sr * 5 / 10000;
+ /* putchar('+'); */
+ }
+
+ if (data_size > dec->top_size) {
+ out_sr -= out_sr * 5 / 10000;
+ /* putchar('-'); */
+ }
+
+ if (out_sr != dec->audio_new_rate) {
+ audio_hw_src_set_rate(dec->src_sync, dec->sample_rate, out_sr);
+ }
+#else
+
+
+ u32 sr = dec->audio_new_rate;
+
+ if (data_size < dec->bottom_size) {
+ dec->audio_new_rate += RATE_INC_STEP;
+ /*printf("rate inc\n");*/
+ }
+
+ if (data_size > dec->top_size) {
+ dec->audio_new_rate -= RATE_DEC_STEP;
+ /*printf("rate dec : %d\n", __this->audio_new_rate);*/
+ }
+
+ if (dec->audio_new_rate < dec->usb_audio_min_speed) {
+ dec->audio_new_rate = dec->usb_audio_min_speed;
+ } else if (dec->audio_new_rate > dec->usb_audio_max_speed) {
+ dec->audio_new_rate = dec->usb_audio_max_speed;
+ }
+
+ if (sr != dec->audio_new_rate) {
+ audio_hw_src_set_rate(dec->src_sync, dec->sample_rate, dec->audio_new_rate);
+ }
+#endif
+
+ return 0;
+}
+
+static int uac_dec_probe_handler(struct audio_decoder *decoder)
+{
+ struct uac_dec_hdl *dec = container_of(decoder, struct uac_dec_hdl, decoder);
+ int err = 0;
+
+#if 0
+ if (!dec->sync_start) {
+ if (uac_speaker_stream_size() > dec->begin_size) {
+ dec->sync_start = 1;
+ return 0;
+ } else {
+ os_time_dly(2);
+ audio_decoder_suspend(&dec->decoder, 0);
+ /* audio_decoder_resume(&dec->decoder); */
+ /* return 0;//临时 */
+ return -EINVAL;
+ }
+ }
+#else
+ if (!dec->sync_start) {
+ return 0;
+ }
+#endif
+
+#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
+ if (dec->dec_no_out_sound) {
+ // localtws同步有微调处理
+ return 0;
+ }
+#endif
+
+ usb_audio_stream_sync(dec, uac_speaker_stream_size());
+ return err;
+}
+
+static const struct audio_dec_handler uac_dec_handler = {
+ .dec_probe = uac_dec_probe_handler,
+ .dec_output = uac_dec_output_handler,
+};
+
+static int uac_audio_sync_init(struct uac_dec_hdl *dec)
+{
+ dec->sync_start = 0;
+ dec->begin_size = uac_speaker_stream_length() * 60 / 100;
+ dec->top_size = uac_speaker_stream_length() * 70 / 100;
+ dec->bottom_size = uac_speaker_stream_length() * 40 / 100;
+
+ dec->audio_new_rate = dec->src_out_sr;//audio_output_rate(dec->sample_rate);
+ printf("out_sr:%d, dsr:%d, \n", dec->audio_new_rate, dec->sample_rate);
+ dec->usb_audio_max_speed = dec->audio_new_rate + 50;
+ dec->usb_audio_min_speed = dec->audio_new_rate - 50;
+
+#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
+ if (dec->dec_no_out_sound) {
+ if (dec->audio_new_rate == dec->sample_rate) {
+ return -ENODEV;
+ }
+ }
+#endif
+
+ dec->src_sync = zalloc(sizeof(struct audio_src_handle));
+ if (!dec->src_sync) {
+ return -ENODEV;
+ }
+ audio_hw_src_open(dec->src_sync, dec->output_ch, SRC_TYPE_RESAMPLE);
+
+ audio_hw_src_set_rate(dec->src_sync, dec->sample_rate, dec->audio_new_rate);
+
+ audio_src_set_output_handler(dec->src_sync, dec, uac_sync_output_handler);
+ return 0;
+}
+
+static int uac_audio_sync_release(struct uac_dec_hdl *dec)
+{
+ if (dec->src_sync) {
+ audio_hw_src_stop(dec->src_sync);
+ audio_hw_src_close(dec->src_sync);
+ local_irq_disable();
+ free(dec->src_sync);
+ dec->src_sync = NULL;
+ local_irq_enable();
+ }
+
+ return 0;
+}
+
+static int uac_audio_close(void)
+{
+ if (!uac_dec || !uac_dec->start) {
+ return 0;
+ }
+
+ uac_dec->start = 0;
+ uac_dec->sync_start = 0;
+
+ if (uac_dec->check_data_timer) {
+ sys_hi_timer_del(uac_dec->check_data_timer);
+ }
+
+ audio_decoder_close(&uac_dec->decoder);
+ uac_audio_sync_release(uac_dec);
+ if (!uac_dec->dec_no_out_sound) {
+ audio_mixer_ch_close(&uac_dec->mix_ch);
+ app_audio_state_exit(APP_AUDIO_STATE_MUSIC);
+ }
+
+#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
+ if (uac_dec->dec_no_out_sound) {
+ uac_dec->dec_no_out_sound = 0;
+ pcm2tws_enc_close();
+ encfile_tws_dec_close();
+ local_tws_stop();
+
+ }
+
+#endif
+ pc_eq_drc_close(uac_dec);
+#if (defined(USER_AUDIO_PROCESS_ENABLE) && (USER_AUDIO_PROCESS_ENABLE != 0))
+ if (uac_dec->user_hdl) {
+ user_audio_process_close(uac_dec->user_hdl);
+ uac_dec->user_hdl = NULL;
+ }
+#endif
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_close(MUSIC_DVOL);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+
+ /* 此处不进行clock_del,改为在usb_audio_demo_exit后 */
+ /* 由于usb_audio_mic_close前adc中断还会不断唤醒usb_audio_mic_write_task */
+ /* 降低时钟会导致系统跑不过来 */
+ /* audio_codec_clock_del(AUDIO_PC_MODE); */
+ return 0;
+}
+
+static void uac_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
+{
+ switch (argv[0]) {
+ case AUDIO_DEC_EVENT_END:
+ puts("USB AUDIO_DEC_EVENT_END\n");
+ if ((u8)argv[1] != (u8)(uac_dec_maigc - 1)) {
+ log_i("maigc err, %s\n", __FUNCTION__);
+ break;
+ }
+ /*uac_audio_close();*/
+ break;
+ }
+}
+
+
+static int uac_audio_start(void)
+{
+ int err;
+ struct audio_fmt f = {0};
+ struct uac_dec_hdl *dec = uac_dec;
+
+ if (!uac_dec) {
+ return -EINVAL;
+ }
+
+ err = audio_decoder_open(&dec->decoder, &uac_input, &decode_task);
+ if (err) {
+ goto __err;
+ }
+
+ audio_decoder_set_handler(&dec->decoder, &uac_dec_handler);
+ audio_decoder_set_event_handler(&dec->decoder, uac_dec_event_handler, uac_dec_maigc++);
+
+
+ uac_dec_set_output_channel(dec);
+
+ f.coding_type = AUDIO_CODING_PCM;
+ f.sample_rate = dec->sample_rate;
+ f.channel = dec->output_ch;
+
+ sound_pcm_dev_channel_mapping(dec->output_ch);
+
+ err = audio_decoder_set_fmt(&dec->decoder, &f);
+
+ if (err) {
+ goto __err;
+ }
+
+#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
+ dec->dec_no_out_sound = 0;
+ if (dec2tws_check_enable() == true) {
+ audio_decoder_set_output_channel(&dec->decoder, UAC_DEC_PCM_ENC_CHANNEL);
+ dec->output_ch = AUDIO_CH_IS_MONO(UAC_DEC_PCM_ENC_CHANNEL) ? 1 : 2;;
+ struct audio_fmt enc_fmt = {0};
+ enc_fmt.coding_type = UAC_DEC_PCM_ENC_TYPE;
+ enc_fmt.bit_rate = 128;
+ enc_fmt.channel = dec->output_ch;
+ enc_fmt.sample_rate = audio_output_rate(dec->sample_rate);//dec->decoder.fmt.sample_rate;
+#if (defined(TCFG_PCM2TWS_SBC_ENABLE) && (TCFG_PCM2TWS_SBC_ENABLE))
+#endif
+
+ int ret = pcm2tws_enc_open(&enc_fmt);
+ if (ret == 0) {
+#if (defined(TCFG_PCM2TWS_SBC_ENABLE) && (TCFG_PCM2TWS_SBC_ENABLE))
+ pcm2tws_enc_set_output_handler(local_tws_output);
+#else
+ pcm2tws_enc_set_output_handler(encfile_tws_wfile);
+ ret = encfile_tws_dec_open(&enc_fmt);
+#endif
+ if (ret == 0) {
+ dec->dec_no_out_sound = 1;
+ pcm2tws_enc_set_resume_handler(uac_dec_resume);
+ audio_decoder_task_del_wait(&decode_task, &dec->wait);
+ local_tws_start(&enc_fmt);
+ audio_decoder_set_run_max(&dec->decoder, 20);
+ dec->src_out_sr = enc_fmt.sample_rate;
+ goto __dec_start;
+ } else {
+ pcm2tws_enc_close();
+ }
+ }
+ }
+#endif
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_open(MUSIC_DVOL, app_audio_get_volume(APP_AUDIO_STATE_MUSIC), MUSIC_DVOL_MAX, MUSIC_DVOL_FS, -1);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+ // 设置叠加功能
+ audio_mixer_ch_open(&dec->mix_ch, &mixer);
+ audio_mixer_ch_set_sample_rate(&dec->mix_ch, audio_output_rate(f.sample_rate));
+
+
+ dec->src_out_sr = audio_output_rate(f.sample_rate);
+
+__dec_start:
+ uac_audio_sync_init(dec);
+ pc_eq_drc_open(dec, &f);
+
+ app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
+
+
+ u16 l_volume, r_volume;
+
+ uac_get_cur_vol(0, &l_volume, &r_volume);
+ u8 vol = uac_vol_switch(l_volume);
+ app_audio_set_volume(APP_AUDIO_STATE_MUSIC, vol, 0);
+
+
+
+#if (defined(TCFG_DEC2TWS_ENABLE) && (TCFG_DEC2TWS_ENABLE))
+ bt_tws_sync_volume();
+#endif
+
+#if (defined(USER_AUDIO_PROCESS_ENABLE) && (USER_AUDIO_PROCESS_ENABLE != 0))
+ struct user_audio_digital_parm vol_parm = {0};
+#if (defined(USER_DIGITAL_VOLUME_ADJUST_ENABLE) && (USER_DIGITAL_VOLUME_ADJUST_ENABLE != 0))
+ vol_parm.en = true;
+ vol_parm.vol = app_audio_get_volume(APP_AUDIO_CURRENT_STATE);
+ vol_parm.vol_max = app_audio_get_max_volume();
+ vol_parm.fade_step = 2;
+#endif
+ dec->user_hdl = user_audio_process_open((void *)&vol_parm, NULL, NULL);
+#endif
+
+ err = audio_decoder_start(&dec->decoder);
+ if (err) {
+ goto __err;
+ }
+
+ dec->state = 0;
+ dec->cnt = 0;
+ dec->check_data_timer = sys_hi_timer_add(NULL, audio_pc_check_timer, 10);
+ audio_codec_clock_set(AUDIO_PC_MODE, AUDIO_CODING_PCM, dec->wait.preemption);
+ dec->start = 1;
+ return 0;
+
+__err:
+
+ pc_eq_drc_close(dec);
+#if (defined(USER_AUDIO_PROCESS_ENABLE) && (USER_AUDIO_PROCESS_ENABLE != 0))
+ if (dec->user_hdl) {
+ user_audio_process_close(dec->user_hdl);
+ dec->user_hdl = NULL;
+ }
+#endif
+
+ return err;
+}
+
+
+static int uac_wait_res_handler(struct audio_res_wait *wait, int event)
+{
+ int err = 0;
+
+ if (event == AUDIO_RES_GET) {
+ err = uac_audio_start();
+ } else if (event == AUDIO_RES_PUT) {
+ uac_audio_close();
+ }
+
+ return err;
+}
+
+static void uac_speaker_stream_rx_handler(int event, void *data, int len)
+{
+ if (uac_dec) {
+ audio_decoder_resume(&uac_dec->decoder);
+ }
+}
+
+extern struct uac_stream_info *puac_speaker_info;
+static int usb_audio_play_open(void *_info)
+{
+ struct uac_dec_hdl *dec;
+
+ if (uac_dec) {
+ return 0;
+ }
+
+ dec = zalloc(sizeof(*dec));
+ if (!dec) {
+ return -ENOMEM;
+ }
+
+ uac_dec = dec;
+
+ dec->sample_rate = (u32)_info & 0xFFFFFF;
+ dec->channel = (u32)_info >> 24;
+ printf("usb_audio_play_open sr:%d ch:%d\n", dec->sample_rate, dec->channel); //通道是2个
+ set_uac_speaker_rx_handler(dec, uac_speaker_stream_rx_handler);
+ dec->wait.priority = 2;
+ dec->wait.preemption = 1;
+ dec->wait.handler = uac_wait_res_handler;
+ audio_decoder_task_add_wait(&decode_task, &dec->wait);
+
+ clock_add(DEC_PCM_CLK);
+
+ return 0;
+}
+
+static int usb_audio_play_close(void *arg)
+{
+ int err = 0;
+
+ if (!uac_dec) {
+ return 0;
+ }
+
+ if (uac_dec->start) {
+ uac_audio_close();
+ }
+
+
+ audio_decoder_task_del_wait(&decode_task, &uac_dec->wait);
+
+ clock_remove(DEC_PCM_CLK);
+
+ local_irq_disable();
+ free(uac_dec);
+ uac_dec = NULL;
+ local_irq_enable();
+
+ return 0;
+}
+
+
+int uac_dec_restart(int magic)
+{
+ if ((!uac_dec) || (magic != uac_dec_maigc)) {
+ return -1;
+ }
+ int _info = (uac_dec->channel << 24) | uac_dec->sample_rate;
+ usb_audio_play_close(NULL);
+ int err = usb_audio_play_open((void *)_info);
+ return err;
+}
+
+int uac_dec_push_restart(void)
+{
+ if (!uac_dec) {
+ return false;
+ }
+ int argv[3];
+ argv[0] = (int)uac_dec_restart;
+ argv[1] = 1;
+ argv[2] = (int)uac_dec_maigc;
+ os_taskq_post_type(os_current_task(), Q_CALLBACK, ARRAY_SIZE(argv), argv);
+ return true;
+}
+
+void uac_dec_resume(void)
+{
+ if (uac_dec && (uac_dec->start)) {
+ audio_decoder_resume(&uac_dec->decoder);
+ }
+}
+int uac_dec_no_out_sound(void)
+{
+ if (uac_dec && uac_dec->dec_no_out_sound) {
+ return true;
+ }
+ return false;
+}
+
+
+extern int usb_audio_mic_open(void *_info);
+extern int usb_audio_mic_close(void *arg);
+extern void usb_audio_mic_set_gain(int gain);
+
+static int usb_device_event_handler(u8 event, int value)
+{
+ switch (event) {
+ case USB_AUDIO_PLAY_OPEN:
+ /*tone_play_stop();*/
+ usb_audio_play_open((void *)value);
+ break;
+ case USB_AUDIO_PLAY_CLOSE:
+ usb_audio_play_close((void *)value);
+ break;
+ case USB_AUDIO_MIC_OPEN:
+ usb_audio_mic_open((void *)value);
+ break;
+ case USB_AUDIO_MIC_CLOSE:
+ usb_audio_mic_close((void *)value);
+ break;
+ case USB_AUDIO_SET_MIC_VOL:
+ usb_audio_mic_set_gain(value);
+ break;
+ case USB_AUDIO_SET_PLAY_VOL:
+
+ value = uac_vol_switch(value & 0xffff); //left ch volume
+ app_audio_set_volume(APP_AUDIO_STATE_MUSIC, value, 1);
+#if (defined(TCFG_DEC2TWS_ENABLE) && (TCFG_DEC2TWS_ENABLE))
+ bt_tws_sync_volume();
+#endif
+
+#if TCFG_UI_ENABLE
+ u8 vol = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
+ ui_set_tmp_menu(MENU_MAIN_VOL, 1000, vol, NULL);
+#endif //TCFG_UI_ENABLE
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static void usb_audio_event_handler(struct sys_event *event, void *priv)
+{
+ switch (event->type) {
+ case SYS_DEVICE_EVENT:
+ if ((u32)event->arg == DEVICE_EVENT_FROM_UAC) {
+ log_d("usb device event : %d %x\n", event->u.dev.event, event->u.dev.value);
+ usb_device_event_handler(event->u.dev.event, event->u.dev.value);
+ }
+ return;
+ default:
+ break;
+ }
+ return;
+}
+
+__attribute__((weak))int audio_dev_init()
+{
+ return 0;
+}
+
+int usb_audio_demo_init(void)
+{
+ int err = 0;
+
+ audio_dev_init();
+ register_sys_event_handler(SYS_DEVICE_EVENT, DEVICE_EVENT_FROM_UAC, 2,
+ usb_audio_event_handler);
+
+
+ return 0;
+}
+
+void usb_audio_demo_exit(void)
+{
+ unregister_sys_event_handler(usb_audio_event_handler);
+ usb_audio_play_close(NULL);
+ usb_audio_mic_close(NULL);
+ audio_codec_clock_del(AUDIO_PC_MODE);
+}
+int audio_pc_src_resample_write(void *priv, s16 *data, u32 len)
+{
+ if (uac_dec && uac_dec->start) { //避免src已经关闭,异步eq 还在输出写src,导致异常
+ return audio_src_resample_write(priv, data, len);
+ }
+ return 0;
+}
+void pc_eq_drc_open(struct uac_dec_hdl *dec, struct audio_fmt *fmt)
+{
+ if (!dec) {
+ return;
+ }
+#if TCFG_EQ_ENABLE&&TCFG_PC_MODE_EQ_ENABLE
+ u8 drc_en = 0;
+#if TCFG_DRC_ENABLE&&TCFG_PC_MODE_DRC_ENABLE
+ drc_en = 1;
+#endif//TCFG_PC_MODE_DRC_ENABLE
+
+ if (dec->src_sync) {
+ dec->eq_drc = dec_eq_drc_setup(dec->src_sync, (eq_output_cb)audio_pc_src_resample_write, fmt->sample_rate, dec->output_ch, 1, drc_en);
+ } else if (dec->dec_no_out_sound) {
+#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
+ dec->eq_drc = dec_eq_drc_setup(dec->dec_no_out_sound, (eq_output_cb)pcm2tws_enc_output, fmt->sample_rate, dec->output_ch, 1, drc_en);
+#endif
+ } else {
+ dec->eq_drc = dec_eq_drc_setup(&dec->mix_ch, (eq_output_cb)audio_mixer_ch_write, fmt->sample_rate, dec->output_ch, 1, drc_en);
+ }
+#endif//TCFG_PC_MODE_EQ_ENABLE
+
+}
+
+
+void pc_eq_drc_close(struct uac_dec_hdl *dec)
+{
+ if (!dec) {
+ return;
+ }
+#if TCFG_EQ_ENABLE&&TCFG_PC_MODE_EQ_ENABLE
+ if (dec->eq_drc) {
+ dec_eq_drc_free(dec->eq_drc);
+ dec->eq_drc = NULL;
+ }
+#endif//TCFG_PC_MODE_EQ_ENABLE
+
+}
+#endif /* TCFG_APP_PC_EN */
+
diff --git a/cpu/br28/audio_dec/audio_dec_pcm.c b/cpu/br28/audio_dec/audio_dec_pcm.c
new file mode 100644
index 0000000..e55ada8
--- /dev/null
+++ b/cpu/br28/audio_dec/audio_dec_pcm.c
@@ -0,0 +1,286 @@
+#include "app_config.h"
+#include "audio_decoder.h"
+#include "media/includes.h"
+#include "audio_config.h"
+#include "system/includes.h"
+#include "audio_enc.h"
+#include "application/audio_eq.h"
+#include "application/audio_drc.h"
+#include "app_config.h"
+#include "audio_config.h"
+#include "audio_dec.h"
+#include "app_main.h"
+#include "clock_cfg.h"
+#include "audio_dec_eff.h"
+#include "audio_codec_clock.h"
+#include "audio_dvol.h"
+#include "audio_dec_pcm.h"
+
+struct pcm_dec_hdl {
+ struct audio_decoder decoder;
+ struct audio_res_wait wait;
+ struct audio_mixer_ch mix_ch;
+ u8 start;
+ u8 remain;
+ u8 channel;
+ u8 output_ch;
+ int sample_rate;
+ int (*pcm_read_cb)(void *, void *, int);
+};
+static struct pcm_dec_hdl *pcm_dec = NULL;
+extern struct audio_decoder_task decode_task;
+extern struct audio_dac_hdl dac_hdl;
+
+
+void pcm_dec_set_read_cb(int (*pcm_read_func)(void *, void *, int))
+{
+ local_irq_disable();
+ if (pcm_dec && pcm_dec->start == 1) {
+ pcm_dec->pcm_read_cb = pcm_read_func;
+ } else {
+ y_printf(">>> %s, %d, pcm_dec set read cb failed!\n", __func__, __LINE__);
+ }
+ local_irq_enable();
+}
+
+static void pcm_LR_to_mono(s16 *pcm_lr, s16 *pcm_mono, int points_len)
+{
+ s16 pcm_L;
+ s16 pcm_R;
+ int i = 0;
+
+ for (i = 0; i < points_len; i++, pcm_lr += 2) {
+ pcm_L = *pcm_lr;
+ pcm_R = *(pcm_lr + 1);
+ *pcm_mono++ = (s16)(((int)pcm_L + pcm_R) >> 1);
+ }
+}
+
+static int pcm_stream_read(struct audio_decoder *decoder, void *buf, u32 len)
+{
+ int rlen = 0;
+ struct pcm_dec_hdl *dec = container_of(decoder, struct pcm_dec_hdl, decoder);
+
+ local_irq_disable();
+ if (dec) {
+ if (dec->pcm_read_cb) {
+ rlen = dec->pcm_read_cb(NULL, (void *)buf, len);
+ }
+ if (dec->channel == 2 && dec->output_ch == 1) {
+ /* pcm_LR_to_mono((s16 *)buf, (s16 *)buf, rlen >> 2); */
+ /* rlen >>= 1; */
+ }
+ }
+ local_irq_enable();
+ if (!rlen) {
+ return -1;
+ }
+ return rlen;
+}
+
+static const struct audio_dec_input pcm_input = {
+ .coding_type = AUDIO_CODING_PCM,
+ .data_type = AUDIO_INPUT_FILE,
+ .ops = {
+ .file = {
+ .fread = pcm_stream_read,
+ }
+ }
+};
+
+static int pcm_dec_probe_handler(struct audio_decoder *decoder)
+{
+ struct pcm_dec_hdl *dec = container_of(decoder, struct pcm_dec_hdl, decoder);
+ return 0;
+}
+
+static int pcm_dec_output_handler(struct audio_decoder *decoder, s16 *data, int len, void *priv)
+{
+ struct pcm_dec_hdl *dec = container_of(decoder, struct pcm_dec_hdl, decoder);
+
+ if (!dec) {
+ return 0;
+ }
+ int rlen = len;
+ int wlen = 0;
+
+ if (!dec->remain) {
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_run(MUSIC_DVOL, data, len);
+#endif
+ }
+
+ wlen = audio_mixer_ch_write(&dec->mix_ch, data, rlen);
+ if (!wlen) {
+ putchar('w');
+ }
+ rlen -= wlen;
+
+ if (rlen == 0) {
+ dec->remain = 0;
+ } else {
+ dec->remain = 1;
+ }
+ return len - rlen;
+}
+
+static const struct audio_dec_handler pcm_dec_handler = {
+ .dec_probe = pcm_dec_probe_handler,
+ .dec_output = pcm_dec_output_handler,
+};
+
+static void pcm_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
+{
+ switch (argv[0]) {
+ case AUDIO_DEC_EVENT_END:
+ /*pcm_audio_close();*/
+ break;
+ }
+}
+
+void pcm_dec_resume(void)
+{
+ local_irq_disable();
+ if (pcm_dec && pcm_dec->start) {
+ audio_decoder_resume(&pcm_dec->decoder);
+ }
+ local_irq_enable();
+}
+
+static int pcm_audio_play_start(void)
+{
+ int err;
+ y_printf(">>>>>>>> Enter Func: %s \n", __func__);
+ struct audio_fmt f = {0};
+ struct pcm_dec_hdl *dec = pcm_dec;
+
+ if (!pcm_dec) {
+ return -EINVAL;
+ }
+
+ err = audio_decoder_open(&dec->decoder, &pcm_input, &decode_task);
+ if (err) {
+ goto __err;
+ }
+
+ audio_decoder_set_handler(&dec->decoder, &pcm_dec_handler);
+ audio_decoder_set_event_handler(&dec->decoder, pcm_dec_event_handler, 0);
+
+ u8 dac_conn = audio_dac_get_channel(&dac_hdl);
+ if (dac_conn == DAC_OUTPUT_LR) {
+ dec->output_ch = 2;
+ } else {
+ dec->output_ch = 1;
+ }
+
+ f.coding_type = AUDIO_CODING_PCM;
+ f.sample_rate = dec->sample_rate;
+ f.channel = dec->output_ch;
+
+ err = audio_decoder_set_fmt(&dec->decoder, &f);
+
+ printf(">>>>>>>> %s, dec->output_ch : %d\n", __func__, dec->output_ch);
+
+#if TCFG_AUDIO_OUTPUT_IIS
+ sound_pcm_dev_channel_mapping(dec->output_ch);
+#endif
+
+ if (err) {
+ goto __err;
+ }
+
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_open(MUSIC_DVOL, app_audio_get_volume(APP_AUDIO_STATE_MUSIC), MUSIC_DVOL_MAX, MUSIC_DVOL_FS, -1);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+ // 设置叠加功能
+ audio_mixer_ch_open(&dec->mix_ch, &mixer);
+ audio_mixer_ch_set_sample_rate(&dec->mix_ch, audio_output_rate(f.sample_rate));
+ app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
+
+ int vol = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
+ app_audio_set_volume(APP_AUDIO_STATE_MUSIC, vol, 0);
+
+ err = audio_decoder_start(&dec->decoder);
+ if (err) {
+ goto __err;
+ }
+ audio_codec_clock_set(AUDIO_PC_MODE, AUDIO_CODING_PCM, dec->wait.preemption);
+ dec->start = 1;
+ return 0;
+
+__err:
+
+ return err;
+}
+
+static int pcm_audio_play_stop(void)
+{
+ if (!pcm_dec || !pcm_dec->start) {
+ return 0;
+ }
+ pcm_dec->start = 0;
+ audio_decoder_close(&pcm_dec->decoder);
+ audio_mixer_ch_close(&pcm_dec->mix_ch);
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_close(MUSIC_DVOL);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+ return 0;
+}
+
+static int pcm_wait_res_handler(struct audio_res_wait *wait, int event)
+{
+ int err = 0;
+
+ if (event == AUDIO_RES_GET) {
+ err = pcm_audio_play_start();
+ } else if (event == AUDIO_RES_PUT) {
+ /* pcm_audio_play_stop(); */
+ }
+ return err;
+}
+
+
+int pcm_audio_play_open(int sr, u8 ch)
+{
+ struct pcm_dec_hdl *dec;
+
+ if (pcm_dec) {
+ return 0;
+ }
+
+ dec = zalloc(sizeof(*dec));
+ if (!dec) {
+ return -ENOMEM;
+ }
+
+ pcm_dec = dec;
+
+ dec->sample_rate = sr;
+ dec->channel = ch;
+ y_printf(">>> pcm_audio_play_open sr:%d ch:%d\n", dec->sample_rate, dec->channel); //通道是2个
+ dec->wait.priority = 2;
+ dec->wait.preemption = 1;
+ dec->wait.handler = pcm_wait_res_handler;
+ audio_decoder_task_add_wait(&decode_task, &dec->wait);
+
+ clock_add(DEC_PCM_CLK);
+ return 0;
+}
+
+
+void pcm_audio_play_close(void)
+{
+ if (!pcm_dec) {
+ return;
+ }
+ pcm_audio_play_stop();
+ audio_decoder_task_del_wait(&decode_task, &pcm_dec->wait);
+ clock_remove(DEC_PCM_CLK);
+ local_irq_disable();
+ free(pcm_dec);
+ pcm_dec = NULL;
+ local_irq_enable();
+}
+
diff --git a/cpu/br28/audio_dec/audio_dec_pcm.h b/cpu/br28/audio_dec/audio_dec_pcm.h
new file mode 100644
index 0000000..788cf64
--- /dev/null
+++ b/cpu/br28/audio_dec/audio_dec_pcm.h
@@ -0,0 +1,16 @@
+#ifndef __AUDIO_DEC_PCM_H
+#define __AUDIO_DEC_PCM_H
+
+#include "asm/cpu.h"
+
+
+void pcm_dec_resume(void);
+void pcm_dec_set_read_cb(int (*pcm_read_func)(void *, void *, int));
+int pcm_audio_play_open(int sr, u8 ch);
+void pcm_audio_play_close(void);
+
+
+extern int sound_pcm_dev_channel_mapping(int ch_num);
+
+#endif
+
diff --git a/cpu/br28/audio_dec/audio_usb_mic.c b/cpu/br28/audio_dec/audio_usb_mic.c
new file mode 100644
index 0000000..d0f047b
--- /dev/null
+++ b/cpu/br28/audio_dec/audio_usb_mic.c
@@ -0,0 +1,920 @@
+#include "asm/includes.h"
+#include "media/includes.h"
+#include "system/includes.h"
+#include "device/uac_stream.h"
+#include "audio_enc.h"
+#include "app_main.h"
+#include "user_cfg_id.h"
+#include "app_config.h"
+#include "audio_codec_clock.h"
+#include "audio_config.h"
+/* #include "application/audio_echo_reverb.h" */
+
+/*USB MIC上行数据同步及变采样模块使能*/
+#define USB_MIC_SRC_ENABLE 1
+
+#if TCFG_USB_MIC_CVP_ENABLE
+#include "aec_user.h"
+#include "overlay_code.h"
+#endif/*TCFG_USB_MIC_CVP_ENABLE*/
+
+#if USB_MIC_SRC_ENABLE
+#include "audio_track.h"
+#include "Resample_api.h"
+#endif/*USB_MIC_SRC_ENABLE*/
+
+#define USB_AUDIO_MIC_WRITE_TASK_NAME "usbmic_write"
+
+#define PCM_ENC2USB_OUTBUF_LEN (6 * 1024)
+
+#define USB_MIC_BUF_NUM 3
+
+#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
+#define USB_MIC_CH_NUM 3 /* 3mic通话 */
+#elif TCFG_AUDIO_DUAL_MIC_ENABLE
+#define USB_MIC_CH_NUM 2 /* 双mic通话 */
+#else
+#define USB_MIC_CH_NUM 1 /* 单mic通话 */
+#endif
+
+#define USB_MIC_IRQ_POINTS 256
+#define USB_MIC_BUFS_SIZE (USB_MIC_CH_NUM * USB_MIC_BUF_NUM * USB_MIC_IRQ_POINTS)
+
+#define USB_MIC_STOP 0x00
+#define USB_MIC_START 0x01
+
+#ifndef VM_USB_MIC_GAIN
+#define VM_USB_MIC_GAIN 5
+#endif
+
+#define USB_PLNK_MIC_GAIN_ENABLE 1 //PLNK_MIC数字增益放大使能
+#define USB_PLNK_MIC_DIG_GAIN 60.f //PLNK_MIC数字增益(Gain = 10^(dB_diff/20))
+
+extern struct audio_adc_hdl adc_hdl;
+extern u16 uac_get_mic_vol(const u8 usb_id);
+extern int usb_output_sample_rate();
+#if USB_MIC_SRC_ENABLE
+typedef struct {
+ u8 start;
+ u8 busy;
+ u16 in_sample_rate;
+ u16 out_sample_rate;
+ u32 *runbuf;
+ s16 output[320 * 3 + 16];
+ RS_STUCT_API *ops;
+ void *audio_track;
+} usb_mic_sw_src_t;
+static usb_mic_sw_src_t *usb_mic_src = NULL;
+#endif/*USB_MIC_SRC_ENABLE*/
+
+
+
+struct _usb_mic_hdl {
+ struct audio_adc_output_hdl adc_output;
+ struct adc_mic_ch mic_ch;
+ s16 adc_buf[USB_MIC_BUFS_SIZE];
+ enum enc_source source;
+ OS_SEM sem;
+
+ cbuffer_t output_cbuf;
+ u8 *output_buf;//[PCM_ENC2USB_OUTBUF_LEN];
+ u8 rec_tx_channels;
+ u8 mic_data_ok;/*mic数据等到一定长度再开始发送*/
+ u8 status;
+ u8 drop_data; //用来丢掉刚开mic的前几帧数据
+#if TCFG_USB_MIC_ECHO_ENABLE
+ ECHO_API_STRUCT *p_echo_hdl;
+#endif
+#if (USB_MIC_CH_NUM > 1)
+ s16 tmp_buf[USB_MIC_IRQ_POINTS];
+#endif/*USB_MIC_CH_NUM*/
+#if (USB_MIC_CH_NUM > 2)
+ s16 tmp_buf_1[USB_MIC_IRQ_POINTS];
+#endif/*USB_MIC_CH_NUM*/
+ s16 *usb_mic_data;
+ u16 data_len;
+ float dig_gain;
+};
+
+struct audio_sample_track_context {
+ u32 in_sr;
+ volatile u8 track_step;
+ volatile int samples;
+ volatile u32 sample_rate;
+ volatile u32 adc_points;
+ volatile u32 next_period;
+ volatile int period;
+};
+static u32 adc_hwp = 0;
+static u32 adc_points = 0;
+static void *user_audio_local_sample_track_open(int in_sr, int sample_rate, int period)
+{
+ struct audio_sample_track_context *ctx;
+ ctx = (struct audio_sample_track_context *)zalloc(sizeof(struct audio_sample_track_context));
+ if (!ctx) {
+ return NULL;
+ }
+ ctx->in_sr = in_sr;
+ ctx->sample_rate = sample_rate;
+ ctx->period = period * sample_rate / 1000;
+ adc_points = 0;
+ return ctx;
+}
+int get_audio_adc_points_time()//获取总的采样周期
+{
+ return adc_points + ((JL_AUDIO->ADC_HWP > adc_hwp) ? (JL_AUDIO->ADC_HWP - adc_hwp) : (JL_AUDIO->ADC_HWP + JL_AUDIO->ADC_LEN - adc_hwp));
+}
+static int user_audio_local_sample_track_in_period(void *c, int samples)
+{
+ struct audio_sample_track_context *ctx = (struct audio_sample_track_context *)c;
+ if (ctx->track_step == 0) {
+ ctx->track_step = 1;
+ goto __exit;
+ }
+ if (ctx->track_step == 1) {
+ ctx->track_step = 2;
+ ctx->next_period = ctx->period;
+ ctx->samples = 0;
+ goto __exit;
+ }
+ ctx->samples += samples;
+ if (time_after(ctx->samples, ctx->next_period)) {
+ int adc_points = get_audio_adc_points_time();
+ int points_diff = (adc_points - ctx->adc_points);
+ if (points_diff > 0) {
+ int sample_rate = ((u64)((u64)ctx->in_sr * (u64)ctx->samples)) / points_diff;
+ /* printf("> track : %d %d %d %d< \n", sample_rate, ctx->samples, ctx->in_sr, points_diff); */
+ /* printf("> track : %d < \n", sample_rate); */
+ ctx->sample_rate = sample_rate;
+ }
+ ctx->adc_points = adc_points;
+ ctx->next_period = ctx->period;
+ ctx->samples = 0;
+ }
+__exit:
+ return ctx->sample_rate;
+}
+static int user_audio_local_sample_track_rate(void *c)
+{
+ struct audio_sample_track_context *ctx = (struct audio_sample_track_context *)c;
+ return ctx->sample_rate;
+}
+static void user_audio_local_sample_track_close(void *c)
+{
+ struct audio_sample_track_context *ctx = (struct audio_sample_track_context *)c;
+ if (!ctx) {
+ return;
+ }
+ ctx->track_step = 0;
+ free(ctx);
+}
+
+static struct _usb_mic_hdl *usb_mic_hdl = NULL;
+#if TCFG_USB_MIC_ECHO_ENABLE
+ECHO_PARM_SET usbmic_echo_parm_default = {
+ .delay = 200, //回声的延时时间 0-300ms
+ .decayval = 50, // 0-70%
+ .direct_sound_enable = 1, //直达声使能 0/1
+ .filt_enable = 1, //发散滤波器使能
+};
+EF_REVERB_FIX_PARM usbmic_echo_fix_parm_default = {
+ .wetgain = 2048, ////湿声增益:[0:4096]
+ .drygain = 4096, ////干声增益: [0:4096]
+ .sr = MIC_EFFECT_SAMPLERATE, ////采样率
+ .max_ms = 200, ////所需要的最大延时,影响 need_buf 大小
+};
+#endif
+static int usb_audio_mic_sync(u32 data_size)
+{
+#if 0
+ int change_point = 0;
+
+ if (data_size > __this->rec_top_size) {
+ change_point = -1;
+ } else if (data_size < __this->rec_bottom_size) {
+ change_point = 1;
+ }
+
+ if (change_point) {
+ struct audio_pcm_src src;
+ src.resample = 0;
+ src.ratio_i = (1024) * 2;
+ src.ratio_o = (1024 + change_point) * 2;
+ src.convert = 1;
+ dev_ioctl(__this->rec_dev, AUDIOC_PCM_RATE_CTL, (u32)&src);
+ }
+#endif
+
+ return 0;
+}
+
+static int usb_audio_mic_tx_handler(int event, void *data, int len)
+{
+ if (usb_mic_hdl == NULL) {
+ return 0;
+ }
+ if (usb_mic_hdl->status == USB_MIC_STOP) {
+ return 0;
+ }
+
+ int i = 0;
+ int r_len = 0;
+ u8 ch = 0;
+ u8 double_read = 0;
+
+ /* int rlen = 0; */
+
+ if (usb_mic_hdl->mic_data_ok == 0) {
+ if (usb_mic_hdl->output_cbuf.data_len > (PCM_ENC2USB_OUTBUF_LEN / 4)) {
+ usb_mic_hdl->mic_data_ok = 1;
+ }
+ //y_printf("mic_tx NULL\n");
+ memset(data, 0, len);
+ return len;
+ }
+
+#if USB_MIC_SRC_ENABLE
+ if (usb_mic_src && usb_mic_src->audio_track) {
+ user_audio_local_sample_track_in_period(usb_mic_src->audio_track, (len >> 1) / usb_mic_hdl->rec_tx_channels);
+ }
+#endif/*USB_MIC_SRC_ENABLE*/
+
+ /* usb_audio_mic_sync(size); */
+ if (usb_mic_hdl->rec_tx_channels == 2) {
+ len = cbuf_read(&usb_mic_hdl->output_cbuf, data, len / 2);
+ s16 *tx_pcm = (s16 *)data;
+ int cnt = len / 2;
+ for (cnt = len / 2; cnt >= 2;) {
+ tx_pcm[cnt - 1] = tx_pcm[cnt / 2 - 1];
+ tx_pcm[cnt - 2] = tx_pcm[cnt / 2 - 1];
+ cnt -= 2;
+ }
+ len *= 2;
+ } else {
+ len = cbuf_read(&usb_mic_hdl->output_cbuf, data, len);
+ }
+ if (!len) {
+ putchar('M');
+ }
+ return len;
+}
+
+
+int usb_audio_mic_write(void *data, u16 len)
+{
+ int wlen = len;
+ if (usb_mic_hdl) {
+ if (usb_mic_hdl->status == USB_MIC_STOP) {
+ return len;
+ }
+
+ int outlen = len;
+ s16 *obuf = data;
+
+#if USB_MIC_SRC_ENABLE
+ if (usb_mic_src && usb_mic_src->start) {
+ usb_mic_src->busy = 1;
+ u32 sr = usb_output_sample_rate();
+ usb_mic_src->ops->set_sr(usb_mic_src->runbuf, sr);
+ outlen = usb_mic_src->ops->run(usb_mic_src->runbuf, data, len >> 1, usb_mic_src->output);
+ usb_mic_src->busy = 0;
+ ASSERT(outlen <= (sizeof(usb_mic_src->output) >> 1));
+ //printf("16->48k:%d,%d,%d\n",len >> 1,outlen,sizeof(usb_mic_src->output));
+ obuf = usb_mic_src->output;
+ outlen = outlen << 1;
+ }
+#endif/*USB_MIC_SRC_ENABLE*/
+ wlen = cbuf_write(&usb_mic_hdl->output_cbuf, obuf, outlen);
+ if (wlen != outlen) {
+ r_printf("usb_mic write full:%d-%d\n", wlen, outlen);
+ }
+ }
+ return wlen;
+}
+
+static void adc_output_to_cbuf(void *priv, s16 *data, int len)
+{
+ if (usb_mic_hdl == NULL) {
+ return ;
+ }
+ if (usb_mic_hdl->status == USB_MIC_STOP) {
+ return ;
+ }
+
+
+
+ switch (usb_mic_hdl->source) {
+ case ENCODE_SOURCE_MIC:
+ case ENCODE_SOURCE_LINE0_LR:
+ case ENCODE_SOURCE_LINE1_LR:
+ case ENCODE_SOURCE_LINE2_LR: {
+
+ adc_hwp = JL_AUDIO->ADC_HWP;
+ adc_points += len / 2;
+
+
+#if TCFG_USB_MIC_CVP_ENABLE
+#if (USB_MIC_CH_NUM == 3)/*3 Mic*/
+ s16 *mic0_data = data;
+ s16 *mic1_data = usb_mic_hdl->tmp_buf;
+ s16 *mic1_data_pos = usb_mic_hdl->tmp_buf_1;
+ //printf("mic_data: %x, %x, %d\n",data, mic1_data_pos, len);
+ for (u16 i = 0; i < (len >> 1); i++) {
+ mic0_data[i] = data[i * 3];
+ mic1_data[i] = data[i * 3 + 1];
+ mic1_data_pos[i] = data[i * 3 + 2];
+ }
+ audio_aec_inbuf_ref(mic1_data, len);
+ audio_aec_inbuf_ref_1(mic1_data_pos, len);
+ audio_aec_inbuf(data, len);
+ return;
+
+#elif (USB_MIC_CH_NUM == 2)/*DualMic*/
+ s16 *mic0_data = data;
+ s16 *mic1_data = usb_mic_hdl->tmp_buf;
+ s16 *mic1_data_pos = data + (len / 2);
+ //printf("mic_data:%x,%x,%d\n",data,mic1_data_pos,len);
+ for (u16 i = 0; i < (len >> 1); i++) {
+ mic0_data[i] = data[i * 2];
+ mic1_data[i] = data[i * 2 + 1];
+ }
+ memcpy(mic1_data_pos, mic1_data, len);
+
+#if 0 /*debug*/
+ static u16 mic_cnt = 0;
+ if (mic_cnt++ > 300) {
+ putchar('1');
+ audio_aec_inbuf(mic1_data_pos, len);
+ if (mic_cnt > 600) {
+ mic_cnt = 0;
+ }
+ } else {
+ putchar('0');
+ audio_aec_inbuf(mic0_data, len);
+ }
+ return;
+#endif/*debug end*/
+#if (TCFG_AUDIO_DMS_MIC_MANAGE == DMS_MASTER_MIC0)
+ audio_aec_inbuf_ref(mic1_data_pos, len);
+ audio_aec_inbuf(data, len);
+#else
+ audio_aec_inbuf_ref(data, len);
+ audio_aec_inbuf(mic1_data_pos, len);
+#endif/*TCFG_AUDIO_DMS_MIC_MANAGE*/
+#else/*SingleMic*/
+ audio_aec_inbuf(data, len);
+#endif/*USB_MIC_CH_NUM*/
+
+#else /* TCFG_USB_MIC_CVP_ENABLE == 0 */
+ if (usb_mic_hdl->drop_data != 0) {
+ usb_mic_hdl-> drop_data--;
+ memset(data, 0, len);
+ }
+#if TCFG_USB_MIC_ECHO_ENABLE
+ if (usb_mic_hdl->p_echo_hdl) {
+ run_echo(usb_mic_hdl->p_echo_hdl, data, data, len);
+ }
+#endif
+
+ /* 由于usb_audio_mic_write中SRC执行时间较长在adc中断中写数据会影响usb中断 */
+ /* 改为在usb_audio_mic_write_task中向usb写数据 */
+ /* adc输入一帧数据,唤醒一次运行任务处理数据 */
+ usb_mic_hdl->usb_mic_data = data;
+ usb_mic_hdl->data_len = len;
+ os_sem_set(&usb_mic_hdl->sem, 0);
+ os_sem_post(&usb_mic_hdl->sem);
+#endif
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+
+#if USB_MIC_SRC_ENABLE
+static int sw_src_init(u32 in_sr, u32 out_sr)
+{
+ usb_mic_src = zalloc(sizeof(usb_mic_sw_src_t));
+ ASSERT(usb_mic_src);
+
+ usb_mic_src->in_sample_rate = in_sr;
+ usb_mic_src->out_sample_rate = out_sr;
+
+ usb_mic_src->ops = get_rs16_context();
+ /* usb_mic_src->ops = get_rsfast_context(); */
+ g_printf("ops:0x%x\n", usb_mic_src->ops);
+ ASSERT(usb_mic_src->ops);
+ u32 need_buf = usb_mic_src->ops->need_buf();
+ g_printf("runbuf:%d\n", need_buf);
+ usb_mic_src->runbuf = malloc(need_buf);
+ ASSERT(usb_mic_src->runbuf);
+ RS_PARA_STRUCT rs_para_obj;
+ rs_para_obj.nch = 1;
+
+ rs_para_obj.new_insample = in_sr;
+ rs_para_obj.new_outsample = out_sr;
+ printf("sw src,in = %d,out = %d\n", rs_para_obj.new_insample, rs_para_obj.new_outsample);
+ usb_mic_src->ops->open(usb_mic_src->runbuf, &rs_para_obj);
+
+ usb_mic_src->audio_track = user_audio_local_sample_track_open(in_sr, out_sr, 2000);
+ usb_mic_src->start = 1;
+ return 0;
+}
+
+static int sw_src_exit(void)
+{
+ if (usb_mic_src) {
+ usb_mic_src->start = 0;
+ while (usb_mic_src->busy) {
+ putchar('w');
+ os_time_dly(2);
+ }
+
+ user_audio_local_sample_track_close(usb_mic_src->audio_track);
+ usb_mic_src->audio_track = NULL;
+
+ local_irq_disable();
+ if (usb_mic_src->runbuf) {
+ free(usb_mic_src->runbuf);
+ usb_mic_src->runbuf = 0;
+ }
+ free(usb_mic_src);
+ usb_mic_src = NULL;
+ local_irq_enable();
+ printf("sw_src_exit\n");
+ }
+ printf("sw_src_exit ok\n");
+ return 0;
+}
+#endif/*USB_MIC_SRC_ENABLE*/
+
+
+
+#if TCFG_USB_MIC_CVP_ENABLE
+static int usb_mic_aec_output(s16 *data, u16 len)
+{
+ //putchar('k');
+ if (usb_mic_hdl == NULL) {
+ return len ;
+ }
+ if (usb_mic_hdl->status == USB_MIC_STOP) {
+ return len;
+ }
+
+ int outlen = len;
+ s16 *outdat = data;
+ /* if (aec_hdl->dump_packet) { */
+ /* aec_hdl->dump_packet--; */
+ /* //memset(outdat, 0, outlen); */
+ /* } */
+ u16 wlen = usb_audio_mic_write(outdat, outlen);
+ return len;
+
+}
+#endif
+
+int uac_mic_vol_switch(int vol)
+{
+ return vol * 14 / 100;
+}
+
+float uac_mic_dig_gain_switch(int vol)
+{
+ float gain = vol / 10.f;
+ return gain;
+}
+
+/*
+*********************************************************************
+* USB Audio MIC Write Task
+* Description: USB MIC 写数据任务
+* Arguments : priv 私用参数
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+static void usb_audio_mic_write_task(void *priv)
+{
+ printf("==Audio Usb Mic Write Task==\n");
+
+ while (1) {
+ os_sem_pend(&usb_mic_hdl->sem, 0);
+
+ putchar('.');
+ if (usb_mic_hdl->status) {
+ usb_audio_mic_write(usb_mic_hdl->usb_mic_data, usb_mic_hdl->data_len);
+ }
+ }
+}
+
+/*
+*********************************************************************
+* PDM MIC API
+* Description: PDM mic操作接口
+* Arguments : None.
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+#if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC)
+/* #define USB_PLNK_SR 16000#<{(|16000/44100/48000|)}># */
+#define USB_PLNK_SCLK 2400000 /*1M-4M,SCLK/SR需为整数且在1-4096范围*/
+#define USB_PLNK_CH_NUM 1 /*支持的最大通道(max = 2)*/
+#define USB_PLNK_IRQ_POINTS 256 /*采样中断点数*/
+#include "pdm_link.h"
+#include "media/audio_gain_process.h"
+static audio_plnk_t *audio_plnk_mic = NULL;
+static void audio_plnk_mic_output(void *buf, u16 len)
+{
+ s16 *mic0 = (s16 *)buf;
+ if (audio_plnk_mic) {
+#if TCFG_USB_MIC_CVP_ENABLE
+ audio_aec_inbuf(mic0, len << 1);
+#else
+#if USB_PLNK_MIC_GAIN_ENABLE
+ GainProcess_16Bit(mic0, mic0, USB_PLNK_MIC_DIG_GAIN, 1, 1, 1, len);
+#endif
+ usb_mic_hdl->usb_mic_data = mic0;
+ usb_mic_hdl->data_len = len << 1;
+ os_sem_set(&usb_mic_hdl->sem, 0);
+ os_sem_post(&usb_mic_hdl->sem);
+#endif
+ }
+}
+
+static int usb_pdm_mic_en(u8 en, u16 sr, u16 gain)
+{
+ printf("usb_pdm_mic_en:%d\n", en);
+ if (en) {
+ if (audio_plnk_mic) {
+ printf("audio_plnk_mic re-malloc error\n");
+ return -1;
+ }
+ audio_plnk_mic = zalloc(sizeof(audio_plnk_t));
+ if (audio_plnk_mic == NULL) {
+ printf("audio_plnk_mic zalloc failed\n");
+ return -1;
+ }
+ audio_mic_pwr_ctl(MIC_PWR_ON);
+ audio_plnk_mic->ch_num = USB_PLNK_CH_NUM;
+ audio_plnk_mic->sr = sr;
+ audio_plnk_mic->buf_len = USB_PLNK_IRQ_POINTS;
+#if (PLNK_CH_EN == PLNK_CH0_EN)
+ audio_plnk_mic->ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE;
+ audio_plnk_mic->ch1_mode = CH1MD_CH0_SCLK_FALLING_EDGE;
+#elif (PLNK_CH_EN == PLNK_CH1_EN)
+ audio_plnk_mic->ch0_mode = CH0MD_CH1_SCLK_FALLING_EDGE;
+ audio_plnk_mic->ch1_mode = CH1MD_CH1_SCLK_RISING_EDGE;
+#else
+ audio_plnk_mic->ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE;
+ audio_plnk_mic->ch1_mode = CH1MD_CH1_SCLK_RISING_EDGE;
+#endif
+ audio_plnk_mic->buf = zalloc(audio_plnk_mic->buf_len * audio_plnk_mic->ch_num * 2 * 2);
+ ASSERT(audio_plnk_mic->buf);
+ audio_plnk_mic->sclk_io = TCFG_AUDIO_PLNK_SCLK_PIN;
+ audio_plnk_mic->ch0_io = TCFG_AUDIO_PLNK_DAT0_PIN;
+ audio_plnk_mic->ch1_io = TCFG_AUDIO_PLNK_DAT1_PIN;
+ audio_plnk_mic->output = audio_plnk_mic_output;
+ audio_plnk_open(audio_plnk_mic);
+ audio_plnk_start(audio_plnk_mic);
+ SFR(JL_ASS->CLK_CON, 0, 2, 3);
+ } else {
+ audio_plnk_close();
+#if TCFG_AUDIO_ANC_ENABLE
+ //printf("anc_status:%d\n",anc_status_get());
+ if (anc_status_get() == 0) {
+ audio_mic_pwr_ctl(MIC_PWR_OFF);
+ }
+#else
+ audio_mic_pwr_ctl(MIC_PWR_OFF);
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+ if (audio_plnk_mic->buf) {
+ free(audio_plnk_mic->buf);
+ }
+ if (audio_plnk_mic) {
+ free(audio_plnk_mic);
+ audio_plnk_mic = NULL;
+ }
+ }
+ return 0;
+}
+#endif/* #if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC) */
+
+int usb_audio_mic_open(void *_info)
+{
+ int err = 0;
+ if (usb_mic_hdl) {
+ return 0;
+ }
+ usb_mic_hdl = zalloc(sizeof(*usb_mic_hdl));
+ if (!usb_mic_hdl) {
+ return -EFAULT;
+ }
+ usb_mic_hdl->status = USB_MIC_STOP;
+
+ usb_mic_hdl->output_buf = zalloc(PCM_ENC2USB_OUTBUF_LEN);
+ if (!usb_mic_hdl->output_buf) {
+ printf("usb_mic_hdl->output_buf NULL\n");
+
+ if (usb_mic_hdl) {
+ free(usb_mic_hdl);
+ usb_mic_hdl = NULL;
+ }
+ return -EFAULT;
+ }
+
+ u32 sample_rate = (u32)_info & 0xFFFFFF;
+ usb_mic_hdl->rec_tx_channels = (u32)_info >> 24;
+ usb_mic_hdl->source = ENCODE_SOURCE_MIC;
+ printf("usb mic sr:%d ch:%d\n", sample_rate, usb_mic_hdl->rec_tx_channels);
+
+
+ usb_mic_hdl->drop_data = 10; //用来丢掉前几帧数据
+ usb_mic_hdl->dig_gain = 1.f; // 用来初始化数字增益
+ u32 out_sample_rate = sample_rate;
+#if TCFG_USB_MIC_CVP_ENABLE
+ sample_rate = 16000;
+ printf("usb mic sr[aec]:%d\n", sample_rate);
+ /*加载清晰语音处理代码*/
+ audio_cvp_code_load();
+ audio_aec_open(sample_rate, TCFG_USB_MIC_CVP_MODE, usb_mic_aec_output);
+#else
+ os_sem_create(&usb_mic_hdl->sem, 0);
+ err = task_create(usb_audio_mic_write_task, NULL, USB_AUDIO_MIC_WRITE_TASK_NAME);
+#endif
+
+#if USB_MIC_SRC_ENABLE
+ sw_src_init(sample_rate, out_sample_rate);
+#endif /*USB_MIC_SRC_ENABLE*/
+
+
+ cbuf_init(&usb_mic_hdl->output_cbuf, usb_mic_hdl->output_buf, PCM_ENC2USB_OUTBUF_LEN);
+
+#if TCFG_MIC_EFFECT_ENABLE
+ app_var.usb_mic_gain = mic_effect_get_micgain();
+#else
+ app_var.usb_mic_gain = uac_mic_vol_switch(uac_get_mic_vol(0));
+#endif//TCFG_MIC_EFFECT_ENABLE
+
+#if (TCFG_USB_MIC_DATA_FROM_MICEFFECT)
+ mic_effect_to_usbmic_onoff(1);
+#else
+#if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC)
+ usb_pdm_mic_en(1, sample_rate, app_var.usb_mic_gain);
+#else
+ audio_mic_pwr_ctl(MIC_PWR_ON);
+#if 1
+#if (TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_0)
+ printf("adc_mic0 open\n");
+ audio_adc_mic_open(&usb_mic_hdl->mic_ch, AUDIO_ADC_MIC_0, &adc_hdl);
+#ifndef TALK_MIC0_GAIN
+ audio_adc_mic_set_gain(&usb_mic_hdl->mic_ch, app_var.usb_mic_gain);
+#else
+ audio_adc_mic_set_gain(&usb_mic_hdl->mic_ch, TALK_MIC0_GAIN);
+#endif
+#endif/*TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_0*/
+#if (TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_1)
+ printf("adc_mic1 open\n");
+ audio_adc_mic1_open(&usb_mic_hdl->mic_ch, AUDIO_ADC_MIC_1, &adc_hdl);
+#ifndef FF_MIC1_GAIN
+ audio_adc_mic1_set_gain(&usb_mic_hdl->mic_ch, app_var.usb_mic_gain);
+#else
+ audio_adc_mic1_set_gain(&usb_mic_hdl->mic_ch, FF_MIC1_GAIN);
+#endif
+#endif/*(TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_1)*/
+#if (TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_2)
+ printf("adc_mic2 open\n");
+ audio_adc_mic2_open(&usb_mic_hdl->mic_ch, AUDIO_ADC_MIC_2, &adc_hdl);
+#ifndef FB_MIC2_GAIN
+ audio_adc_mic2_set_gain(&usb_mic_hdl->mic_ch, app_var.usb_mic_gain);
+#else
+ audio_adc_mic2_set_gain(&usb_mic_hdl->mic_ch, FB_MIC2_GAIN);
+#endif
+#endif/*(TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_2)*/
+#if (TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_3)
+ printf("adc_mic3 open\n");
+ audio_adc_mic3_open(&usb_mic_hdl->mic_ch, AUDIO_ADC_MIC_3, &adc_hdl);
+#ifndef OTHER_MIC3_GAIN
+ audio_adc_mic3_set_gain(&usb_mic_hdl->mic_ch, app_var.usb_mic_gain);
+#else
+ audio_adc_mic3_set_gain(&usb_mic_hdl->mic_ch, OTHER_MIC3_GAIN);
+#endif
+#endif/*(TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_3)*/
+ audio_adc_mic_set_sample_rate(&usb_mic_hdl->mic_ch, sample_rate);
+ audio_adc_mic_set_buffs(&usb_mic_hdl->mic_ch, usb_mic_hdl->adc_buf, USB_MIC_IRQ_POINTS * 2, USB_MIC_BUF_NUM);
+ usb_mic_hdl->adc_output.handler = adc_output_to_cbuf;
+ audio_adc_add_output_handler(&adc_hdl, &usb_mic_hdl->adc_output);
+ audio_adc_mic_start(&usb_mic_hdl->mic_ch);
+#else
+ audio_mic_open(&usb_mic_hdl->mic_ch, sample_rate, app_var.usb_mic_gain);
+ usb_mic_hdl->adc_output.handler = adc_output_to_cbuf;
+ audio_mic_add_output(&usb_mic_hdl->adc_output);
+ audio_mic_start(&usb_mic_hdl->mic_ch);
+#endif
+#endif/*TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC*/
+#if TCFG_USB_MIC_ECHO_ENABLE
+ usb_mic_hdl->p_echo_hdl = open_echo(&usbmic_echo_parm_default, &usbmic_echo_fix_parm_default);
+ if (usb_mic_hdl->p_echo_hdl) {
+ update_echo_gain(usb_mic_hdl->p_echo_hdl, usbmic_echo_fix_parm_default.wetgain, usbmic_echo_fix_parm_default.drygain);
+ }
+#endif
+#endif//TCFG_USB_MIC_DATA_FROM_MICEFFECT
+ set_uac_mic_tx_handler(NULL, usb_audio_mic_tx_handler);
+
+ /* 需要用时钟管理,防止其他操作降低USB_MIC时钟 */
+ audio_codec_clock_set(AUDIO_USB_MIC_MODE, AUDIO_CODING_PCM, 0);
+
+ usb_mic_hdl->status = USB_MIC_START;
+ /* __this->rec_begin = 0; */
+ return 0;
+
+ return -EFAULT;
+}
+
+u32 usb_mic_is_running()
+{
+ if (usb_mic_hdl) {
+ return SPK_AUDIO_RATE;
+ }
+ return 0;
+}
+
+/*
+ *************************************************************
+ *
+ * usb mic gain save
+ *
+ *************************************************************
+ */
+static int usb_mic_gain_save_timer;
+static u8 usb_mic_gain_save_cnt;
+static void usb_audio_mic_gain_save_do(void *priv)
+{
+ //printf(" usb_audio_mic_gain_save_do %d\n", usb_mic_gain_save_cnt);
+ local_irq_disable();
+ if (++usb_mic_gain_save_cnt >= 5) {
+ sys_timer_del(usb_mic_gain_save_timer);
+ usb_mic_gain_save_timer = 0;
+ usb_mic_gain_save_cnt = 0;
+ local_irq_enable();
+ printf("USB_GAIN_SAVE\n");
+ syscfg_write(VM_USB_MIC_GAIN, &app_var.usb_mic_gain, 1);
+ return;
+ }
+ local_irq_enable();
+}
+
+static void usb_audio_mic_gain_change(u8 gain)
+{
+ local_irq_disable();
+ app_var.usb_mic_gain = gain;
+ usb_mic_gain_save_cnt = 0;
+ if (usb_mic_gain_save_timer == 0) {
+ usb_mic_gain_save_timer = sys_timer_add(NULL, usb_audio_mic_gain_save_do, 1000);
+ }
+ local_irq_enable();
+}
+
+int usb_audio_mic_get_gain(void)
+{
+ return app_var.usb_mic_gain;
+}
+
+void usb_audio_mic_set_gain(int gain)
+{
+ if (usb_mic_hdl == NULL) {
+ r_printf("usb_mic_hdl NULL gain");
+ return;
+ }
+#ifndef CONFIG_BOARD_AISPEECH_NR_GAIN
+ gain = uac_mic_vol_switch(gain);
+ audio_adc_mic_set_gain(&usb_mic_hdl->mic_ch, gain);
+ usb_audio_mic_gain_change(gain);
+#else
+ printf("AIS 3MIC set digital gain");
+ usb_mic_hdl->dig_gain = uac_mic_dig_gain_switch(gain);
+#endif /*CONFIG_BOARD_AISPEECH_NR_GAIN*/
+}
+
+float usb_audio_mic_get_dig_gain(void)
+{
+ if (usb_mic_hdl == NULL) {
+ r_printf("usb_mic_hdl NULL gain");
+ return 1;
+ }
+
+ return usb_mic_hdl->dig_gain;
+}
+
+int usb_audio_mic_close(void *arg)
+{
+ if (usb_mic_hdl == NULL) {
+ r_printf("usb_mic_hdl NULL close");
+ return 0;
+ }
+ printf("usb_mic_hdl->status %x\n", usb_mic_hdl->status);
+ if (usb_mic_hdl && usb_mic_hdl->status == USB_MIC_START) {
+ printf("usb_audio_mic_close in\n");
+ usb_mic_hdl->status = USB_MIC_STOP;
+#if TCFG_USB_MIC_CVP_ENABLE
+ audio_aec_close();
+#else
+ task_kill(USB_AUDIO_MIC_WRITE_TASK_NAME);
+#endif
+#if (TCFG_USB_MIC_DATA_FROM_MICEFFECT)
+ mic_effect_to_usbmic_onoff(0);
+#else
+#if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC)
+ usb_pdm_mic_en(0, 0, 0);
+#else
+#if 1
+ audio_adc_mic_close(&usb_mic_hdl->mic_ch);
+ audio_adc_del_output_handler(&adc_hdl, &usb_mic_hdl->adc_output);
+#else
+ audio_mic_close(&usb_mic_hdl->mic_ch, &usb_mic_hdl->adc_output);
+#endif
+ audio_mic_pwr_ctl(MIC_PWR_OFF);
+#endif/*TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC*/
+#if TCFG_USB_MIC_ECHO_ENABLE
+ if (usb_mic_hdl->p_echo_hdl) {
+ close_echo(usb_mic_hdl->p_echo_hdl);
+ }
+#endif
+#endif
+
+#if USB_MIC_SRC_ENABLE
+ sw_src_exit();
+#endif /*USB_MIC_SRC_ENABLE*/
+ cbuf_clear(&usb_mic_hdl->output_cbuf);
+ if (usb_mic_hdl) {
+
+ if (usb_mic_hdl->output_buf) {
+ free(usb_mic_hdl->output_buf);
+ usb_mic_hdl->output_buf = NULL;
+ }
+ free(usb_mic_hdl);
+ usb_mic_hdl = NULL;
+ }
+#if TCFG_USB_MIC_CVP_ENABLE
+ audio_codec_clock_del(AUDIO_USB_MIC_MODE);
+#endif /*TCFG_USB_MIC_CVP_ENABLE*/
+ }
+ printf("usb_audio_mic_close out\n");
+
+ return 0;
+}
+
+int usb_mic_stream_sample_rate(void)
+{
+#if USB_MIC_SRC_ENABLE
+ if (usb_mic_src && usb_mic_src->audio_track) {
+ int sr = user_audio_local_sample_track_rate(usb_mic_src->audio_track);
+ if ((sr < (usb_mic_src->out_sample_rate + 50)) && (sr > (usb_mic_src->out_sample_rate - 50))) {
+ return sr;
+ }
+ return usb_mic_src->out_sample_rate;
+ }
+#endif /*USB_MIC_SRC_ENABLE*/
+
+ return 0;
+}
+
+u32 usb_mic_stream_size()
+{
+ if (!usb_mic_hdl) {
+ return 0;
+ }
+ if (usb_mic_hdl->status == USB_MIC_START) {
+ if (usb_mic_hdl) {
+ return cbuf_get_data_size(&usb_mic_hdl->output_cbuf);
+ }
+ }
+
+ return 0;
+}
+
+u32 usb_mic_stream_length()
+{
+ return PCM_ENC2USB_OUTBUF_LEN;
+}
+
+int usb_output_sample_rate()
+{
+ int sample_rate = usb_mic_stream_sample_rate();
+ int buf_size = usb_mic_stream_size();
+
+ sample_rate = (u32)(usb_mic_src->in_sample_rate * sample_rate) / usb_mic_src->out_sample_rate;/*统计输出采样率,重新转换成输入采样率调输入*/
+ if (buf_size >= (usb_mic_stream_length() * 1 / 2)) {
+ sample_rate += (sample_rate * 5 / 10000);
+ //putchar('+');
+ }
+ if (buf_size <= (usb_mic_stream_length() / 3)) {
+ sample_rate -= (sample_rate * 5 / 10000);
+ //putchar('-');
+ }
+
+ return sample_rate;
+}
+
diff --git a/cpu/br28/audio_dec_eff.c b/cpu/br28/audio_dec_eff.c
new file mode 100644
index 0000000..fffbc37
--- /dev/null
+++ b/cpu/br28/audio_dec_eff.c
@@ -0,0 +1,1860 @@
+#include "audio_dec_eff.h"
+
+#include "debug.h"
+#include "system/syscfg_id.h"
+#if TCFG_AUDIO_CVP_DUT_ENABLE
+#include "audio_cvp_dut.h"
+#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
+extern struct audio_dac_hdl dac_hdl;
+extern const int const_surround_en;
+void user_sat16(s32 *in, s16 *out, u32 npoint);
+void a2dp_surround_set(u8 eff);
+int audio_out_eq_get_filter_info(void *eq, int sr, struct audio_eq_filter_info *info);
+int audio_out_eq_spec_set_info(struct audio_eq *eq, u8 idx, int freq, float gain);
+void *dec_eq_drc_setup_new(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en);
+void eq_cfg_default_init(EQ_CFG *eq_cfg);
+void drc_default_init(EQ_CFG *eq_cfg, u8 mode);
+
+
+/*----------------------------------------------------------------------------*/
+/**@brief 环绕音效切换测试例子
+ @param
+ @return
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+void surround_switch_test(void *p)
+{
+#if 0
+ if (!p) {
+ return;
+ }
+ static u8 cnt_type = 0;
+ if (EFFECT_OFF == cnt_type) {
+ //中途关开测试
+ static u8 en = 0;
+ en = !en;
+ audio_surround_parm_update(p, cnt_type, (surround_update_parm *)en);
+ } else {
+ //音效切换测试
+ audio_surround_parm_update(p, cnt_type, NULL);
+ }
+ printf("cnt_type 0x%x\n", cnt_type);
+ if (++cnt_type > EFFECT_OFF) {
+ cnt_type = EFFECT_3D_PANORAMA;
+ }
+#endif
+}
+
+void *audio_surround_setup(u8 channel, u8 eff)
+{
+#if AUDIO_SURROUND_CONFIG
+ struct dec_sur *sur = zalloc(sizeof(struct dec_sur));
+ u8 nch = EFFECT_CH_L;
+ if (channel == AUDIO_CH_L) {
+ nch = EFFECT_CH_L;
+ } else if (channel == AUDIO_CH_R) {
+ nch = EFFECT_CH_R;
+ } else if (channel == AUDIO_CH_LR) {
+ nch = 2;
+ } else if (channel == AUDIO_CH_DUAL_L) {
+ nch = EFFECT_CH2_L;
+ } else if (channel == AUDIO_CH_DUAL_R) {
+ nch = EFFECT_CH2_R;
+ } else {
+ if (sur) {
+ free(sur);
+ }
+ log_e("surround ch_type err %d\n", channel);
+ return NULL;
+ }
+ surround_open_parm parm = {0};
+ parm.channel = nch;
+ parm.surround_effect_type = EFFECT_3D_PANORAMA;//打开时默认使用3d全景音,使用者,根据需求修改
+ sur->surround = audio_surround_open(&parm);
+ sur->surround_eff = eff;
+ audio_surround_voice(sur, sur->surround_eff);//还原按键触发的音效
+ //sur_test = sys_timer_add(sur->surround, surround_switch_test, 10000);
+ return sur;
+#else
+ return NULL;
+#endif//AUDIO_SURROUND_CONFIG
+
+}
+
+void audio_surround_free(void *sur)
+{
+#if AUDIO_SURROUND_CONFIG
+ struct dec_sur *surh = (struct dec_sur *)sur;
+ if (!surh) {
+ return;
+ }
+
+ if (surh->surround) {
+ audio_surround_close(surh->surround);
+ surh->surround = NULL;
+ }
+ free(surh);
+#endif//AUDIO_SURROUND_CONFIG
+
+}
+
+void audio_surround_set_ch(void *sur, u8 channel)
+{
+#if AUDIO_SURROUND_CONFIG
+ struct dec_sur *surh = (struct dec_sur *)sur;
+ if (!surh) {
+ return;
+ }
+
+ u8 nch = EFFECT_CH_L;
+ if (channel == AUDIO_CH_L) {
+ nch = EFFECT_CH_L;
+ } else if (channel == AUDIO_CH_R) {
+ nch = EFFECT_CH_R;
+ } else if (channel == AUDIO_CH_LR) {
+ nch = 2;
+ } else if (channel == AUDIO_CH_DUAL_L) {
+ nch = EFFECT_CH2_L;
+ } else if (channel == AUDIO_CH_DUAL_R) {
+ nch = EFFECT_CH2_R;
+ } else {
+ log_e("surround ch_type err %d\n", channel);
+ return ;
+ }
+
+ if (surh->surround) {
+ audio_surround_switch_nch(surh->surround, nch);
+ }
+#endif//AUDIO_SURROUND_CONFIG
+
+}
+
+/*
+ *环绕音效开关控制
+ * */
+void audio_surround_voice(void *sur, u8 en)
+{
+#if AUDIO_SURROUND_CONFIG
+ struct dec_sur *surh = (struct dec_sur *)sur;
+ surround_hdl *surround = (surround_hdl *)surh->surround;
+ if (surround) {
+ if (en) {
+ if (const_surround_en & BIT(2)) {
+ surround_update_parm parm = {0};
+ parm.surround_type = EFFECT_3D_LRDRIFT2;//音效类型
+ parm.rotatestep = 4; //建议1~6,环绕速度
+ parm.damping = 40;//混响音量(0~70),空间感
+ parm.feedback = 100;//干声音量(0~100),清晰度
+ parm.roomsize = 128;//无效参数
+ audio_surround_parm_update(surround, EFFECT_SUR2, &parm);
+ } else {
+ audio_surround_parm_update(surround, EFFECT_3D_ROTATES, NULL);
+ }
+ } else {
+ surround_update_parm parm = {0};
+ audio_surround_parm_update(surround, EFFECT_OFF2, &parm);//关音效
+ }
+ }
+#endif /* AUDIO_SURROUND_CONFIG */
+}
+
+
+
+
+#if AUDIO_VBASS_CONFIG
+/*----------------------------------------------------------------------------*/
+/**@brief 虚拟低音参数更新例子
+ @param
+ @return
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+
+
+#define AEID_MUSIC_VBASS 1
+
+vbass_hdl *audio_vbass_open_demo(u32 vbass_name, u32 sample_rate, u8 ch_num)
+{
+ VirtualBassParam parm = {0};
+ u8 tar = 0;
+
+ struct virtual_bass_tool_set *param = get_vbass_parm();
+ u8 bypass = 0;
+ parm.ratio = param->parm.ratio;
+ parm.boost = param->parm.boost;
+ parm.fc = param->parm.fc;
+ parm.channel = ch_num;
+ parm.SampleRate = sample_rate;
+ parm.pcm_info.IndataBit = DATA_INT_16BIT;
+ parm.pcm_info.OutdataBit = DATA_INT_16BIT;
+ parm.pcm_info.IndataInc = (ch_num == 2) ? 2 : 1;
+ parm.pcm_info.OutdataInc = (ch_num == 2) ? 2 : 1;
+ parm.pcm_info.Qval = 15;
+ //printf("vbass ratio %d, boost %d, fc %d, channel %d, SampleRate %d\n", parm.ratio, parm.boost, parm.fc,parm.channel, parm.SampleRate);
+ vbass_hdl *vbass = audio_vbass_open(vbass_name, &parm);
+ vbass->lowfreq_en = 1; //1:保留低频;0:不保留
+ audio_vbass_bypass(vbass_name, bypass);
+ /* clock_add(DEC_VBASS_CLK); */
+ return vbass;
+}
+
+
+void audio_vbass_close_demo(vbass_hdl *vbass)
+{
+ if (vbass) {
+ audio_vbass_close(vbass);
+ vbass = NULL;
+ }
+ /* clock_remove(DEC_VBASS_CLK); */
+}
+
+
+
+void audio_vbass_update_demo(u32 vbass_name, VirtualBassUdateParam *parm, u32 bypass)
+{
+ audio_vbass_parm_update(vbass_name, parm);
+ audio_vbass_bypass(vbass_name, bypass);
+}
+
+
+void vbass_udate_parm_test(void *p)
+{
+#if 0
+ //虚拟低音增益调节例子
+ vbass_parm.ratio = 56;//比率(0~100),越大,低音强度越大
+ vbass_parm.boost = 1;//(低音增强0, 1)
+ vbass_parm.fc = 100;//截止频率(30~300Hz)
+ audio_vbass_parm_update(AEID_MUSIC_VBASS, &vbass_parm);
+ audio_vbass_bypass(AEID_MUSIC_VBASS, 0);
+#endif
+#if 0
+ //开关虚拟低音例子
+ static u8 bypass = 0;
+ /* bypass = 1;//关 */
+ /* bypass = 0;//开 */
+ bypass = !bypass;
+ audio_vbass_bypass(AEID_MUSIC_VBASS, bypass);
+#endif
+}
+
+vbass_hdl *audio_vbass_setup(u32 sample_rate, u8 channel)
+{
+ return audio_vbass_open_demo(AEID_MUSIC_VBASS, sample_rate, channel);
+}
+
+void audio_vbass_free(vbass_hdl *vbass)
+{
+ audio_vbass_close_demo(vbass);
+}
+#endif//AUDIO_VBASS_CONFIG
+
+
+
+void eq_32bit_out(struct dec_eq_drc *eff)
+{
+ if (!config_eq_lite_en) {
+ int wlen = 0;
+ int point_len = 2;
+#if defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE
+ point_len = 4;
+ s32 *out_tmp = eff->eq_out_buf;
+#else
+ s16 *out_tmp = eff->eq_out_buf;
+#endif
+ if (eff->priv && eff->out_cb) {
+ wlen = eff->out_cb(eff->priv, &out_tmp[eff->eq_out_points], (eff->eq_out_total - eff->eq_out_points) * point_len);
+ }
+ eff->eq_out_points += wlen / point_len;
+ }
+}
+
+static int eq_output(void *priv, void *buf, u32 len)
+{
+ if (!config_eq_lite_en) {
+ int wlen = 0;
+ int rlen = len;
+ s16 *data = (s16 *)buf;
+ struct dec_eq_drc *eff = priv;
+ if (!eff->async) {
+ return rlen;
+ }
+
+ if (eff->drc && eff->async) {
+ if (eff->eq_out_buf && (eff->eq_out_points < eff->eq_out_total)) {
+ eq_32bit_out(eff);
+ if (eff->eq_out_points < eff->eq_out_total) {
+ return 0;
+ }
+ }
+
+ audio_drc_run(eff->drc, data, len);
+
+#if defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE
+ if ((!eff->eq_out_buf) || (eff->eq_out_buf_len < len)) {
+ if (eff->eq_out_buf) {
+ free(eff->eq_out_buf);
+ }
+ eff->eq_out_buf_len = len;
+ eff->eq_out_buf = malloc(eff->eq_out_buf_len);
+ ASSERT(eff->eq_out_buf);
+ }
+ memcpy(eff->eq_out_buf, data, len);
+ eff->eq_out_points = 0;
+ eff->eq_out_total = len / 4;
+#else
+ if ((!eff->eq_out_buf) || (eff->eq_out_buf_len < len / 2)) {
+ if (eff->eq_out_buf) {
+ free(eff->eq_out_buf);
+ }
+ eff->eq_out_buf_len = len / 2;
+ eff->eq_out_buf = malloc(eff->eq_out_buf_len);
+ ASSERT(eff->eq_out_buf);
+ }
+ user_sat16((s32 *)data, (s16 *)eff->eq_out_buf, len / 4);
+ eff->eq_out_points = 0;
+ eff->eq_out_total = len / 4;
+#endif
+
+ eq_32bit_out(eff);
+ return len;
+ }
+
+ int out_len = 0;
+ if (eff->priv && eff->out_cb) {
+ out_len = eff->out_cb(eff->priv, data, len);
+ }
+ return out_len;
+ } else {
+ return len;
+ }
+}
+
+
+
+int wdrc_get_filter_info(void *drc, struct audio_drc_filter_info *info)
+{
+ static struct drc_ch wdrc_p = {0};
+ struct threshold_group threshold[5] = {{-100 + 90.3f, -91.9f + 90.3f}, {-87 + 90.3f, -72.5f + 90.3f}, {-58.6f + 90.3f, -60.3f + 90.3f}, {-43.5f + 90.3f, -29.7f + 90.3f}, {0 + 90.3f, -10.9f + 90.3f}};
+ /* struct threshold_group threshold[3] = {{0x42166666, 0x0}, {0x42580000, 0x42a40000},{0x42f00000, 0x42c50000}}; */
+
+ wdrc_p.nband = 1;
+ wdrc_p.type = 3;//wdrc
+
+ //left
+ int i = 0;
+ wdrc_p._p.wdrc[i].attacktime = 1;
+ wdrc_p._p.wdrc[i].releasetime = 500;
+ memcpy(wdrc_p._p.wdrc[i].threshold, threshold, sizeof(threshold));
+ wdrc_p._p.wdrc[i].threshold_num = ARRAY_SIZE(threshold);
+ wdrc_p._p.wdrc[i].rms_time = 25;
+ wdrc_p._p.wdrc[i].algorithm = 0;
+ wdrc_p._p.wdrc[i].mode = 1;
+
+ info->R_pch = info->pch = &wdrc_p;
+ return 0;
+}
+
+u8 left_or_right_earphone()
+{
+#if 0//TCFG_USER_TWS_ENABLE
+ if (config_wdrc_en) {
+ u8 channel = 0;
+ int state = 0;
+ u8 dac_connect_mode;
+ state = tws_api_get_tws_state();
+ if (state & TWS_STA_SIBLING_CONNECTED) {
+ dac_connect_mode = audio_dac_get_channel(&dac_hdl);
+ if (dac_connect_mode == DAC_OUTPUT_LR) {
+ if (tws_api_get_local_channel() == 'L') {
+ channel |= LL_wdrc;
+ } else {
+ channel |= RR_wdrc;
+ }
+ } else {
+ if (tws_api_get_local_channel() == 'L') {
+ channel |= L_wdrc;
+ } else {
+ channel |= R_wdrc;
+ }
+ }
+ }
+ return channel;
+ }
+#endif
+ return 0;
+}
+
+void *dec_eq_drc_setup(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en)
+{
+#if TCFG_EQ_ENABLE
+ if (config_eq_lite_en) { //仅支持同步方式eq处理
+ async = 0;//
+ }
+#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
+ async = 0;
+#endif
+#if defined(AUDIO_GAME_EFFECT_CONFIG) && AUDIO_GAME_EFFECT_CONFIG
+ if (drc_en & BIT(1)) { //game eff drc
+ return dec_eq_drc_setup_new(priv, eq_output_cb, sample_rate, channel, async, drc_en);
+ }
+#endif/* AUDIO_GAME_EFFECT_CONFIG */
+
+ struct dec_eq_drc *eff = zalloc(sizeof(struct dec_eq_drc));
+ struct audio_eq_param eq_param = {0};
+ eff->priv = priv;
+ eff->out_cb = eq_output_cb;
+
+ eq_param.channels = channel;
+ eq_param.online_en = 1;
+ eq_param.mode_en = 1;
+ eq_param.remain_en = 1;
+ eq_param.no_wait = async;
+ if (drc_en) {
+ eq_param.out_32bit = 1;
+ }
+ eq_param.max_nsection = EQ_SECTION_MAX;
+ eq_param.cb = eq_get_filter_info;
+ eq_param.eq_name = song_eq_mode;
+ eq_param.sr = sample_rate;
+ eq_param.priv = eff;
+ eq_param.output = eq_output;
+ eff->eq = audio_dec_eq_open(&eq_param);
+ eff->async = async;
+#if TCFG_DRC_ENABLE
+ if (drc_en) {
+ struct audio_drc_param drc_param = {0};
+ drc_param.sr = sample_rate;
+ drc_param.channels = channel | left_or_right_earphone();
+ drc_param.online_en = 1;
+ drc_param.remain_en = 1;
+ drc_param.out_32bit = 1;
+ drc_param.cb = drc_get_filter_info;
+ drc_param.drc_name = song_eq_mode;
+ eff->drc = audio_dec_drc_open(&drc_param);
+ }
+#endif//TCFG_DRC_ENABLE
+
+#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
+ eff->spk_eq = spk_eq_open(sample_rate, channel, drc_en ? 1 : 0);
+#endif/*AUDIO_SPK_EQ_CONFIG*/
+
+
+ return eff;
+#else
+ return NULL;
+#endif//TCFG_EQ_ENABLE
+
+}
+
+void dec_eq_drc_free(void *eff)
+{
+#if TCFG_EQ_ENABLE
+ struct dec_eq_drc *eff_hdl = (struct dec_eq_drc *)eff;
+ if (!eff_hdl) {
+ return;
+ }
+ u8 tmp = 0;
+ if (eff_hdl->drc_bef_eq) {
+ tmp = 1;
+ }
+ if (eff_hdl->drc_prev) {
+ audio_dec_drc_close(eff_hdl->drc_prev);
+ eff_hdl->drc_prev = NULL;
+ }
+
+ if (eff_hdl->eq) {
+ audio_dec_eq_close(eff_hdl->eq);
+ eff_hdl->eq = NULL;
+ }
+
+ if (eff_hdl->drc) {
+ audio_dec_drc_close(eff_hdl->drc);
+ eff_hdl->drc = NULL;
+ }
+
+#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
+ if (eff_hdl->spk_eq) {
+ spk_eq_close(eff_hdl->spk_eq);
+ eff_hdl->spk_eq = NULL;
+ }
+#endif
+
+ if (eff_hdl->eq_out_buf) {
+ free(eff_hdl->eq_out_buf);
+ eff_hdl->eq_out_buf = NULL;
+ }
+
+#if AUDIO_EQ_FADE_EN
+ if (eff_hdl->fade.tmr) {
+ sys_hi_timer_del(eff_hdl->fade.tmr);
+ eff_hdl->fade.tmr = 0;
+ }
+#endif
+ free(eff_hdl);
+ if (tmp) { //还原非游戏音效eq drc 效果
+ EQ_CFG *eq_cfg = get_eq_cfg_hdl();
+ eq_cfg->eq_type = EQ_TYPE_MODE_TAB;
+ eq_cfg_default_init(get_eq_cfg_hdl());
+ drc_default_init(get_eq_cfg_hdl(), song_eq_mode);
+ if (!eq_file_get_cfg(get_eq_cfg_hdl(), (u8 *)SDFILE_RES_ROOT_PATH"eq_cfg_hw.bin")) {
+ eq_cfg->eq_type = EQ_TYPE_FILE;
+ }
+ }
+#endif//TCFG_EQ_ENABLE
+
+}
+struct drc_ch esco_drc_p = {0};
+int esco_drc_get_filter_info(void *drc, struct audio_drc_filter_info *info)
+{
+ float th = -0.5f;//db -60db~0db,限幅器阈值
+ int threshold = roundf(powf(10.0f, th / 20.0f) * 32768);
+ esco_drc_p.nband = 1;
+ esco_drc_p.type = 1;
+ esco_drc_p._p.limiter[0].attacktime = 5;
+ esco_drc_p._p.limiter[0].releasetime = 500;
+ esco_drc_p._p.limiter[0].threshold[0] = threshold;
+ esco_drc_p._p.limiter[0].threshold[1] = 32768;
+ info->R_pch = info->pch = &esco_drc_p;
+ return 0;
+}
+void *esco_eq_drc_setup(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en)
+{
+#if TCFG_EQ_ENABLE && TCFG_PHONE_EQ_ENABLE
+
+ if (config_eq_lite_en) { //仅支持同步方式eq处理
+ async = 0;//
+ }
+
+ struct dec_eq_drc *eff = zalloc(sizeof(struct dec_eq_drc));
+
+#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
+ eff->spk_eq = spk_eq_open(sample_rate, channel, drc_en ? 1 : 0);
+#endif/*AUDIO_SPK_EQ_CONFIG*/
+
+
+ struct audio_eq_param eq_param = {0};
+
+ eff->priv = priv;
+ eff->out_cb = eq_output_cb;
+ eq_param.channels = channel;
+ eq_param.online_en = 1;
+ eq_param.mode_en = 0;
+ eq_param.remain_en = 0;
+ eq_param.no_wait = async;//a2dp_low_latency ? 0 : 1;
+ if (drc_en) {
+ eq_param.out_32bit = 1;
+ }
+ eq_param.max_nsection = EQ_SECTION_MAX;
+ eq_param.cb = eq_phone_get_filter_info;
+ eq_param.eq_name = call_eq_mode;
+ eq_param.sr = sample_rate;
+ eq_param.priv = eff;
+ eq_param.output = eq_output;
+ eff->eq = audio_dec_eq_open(&eq_param);
+
+#if TCFG_DRC_ENABLE
+ if (drc_en) {
+ struct audio_drc_param drc_param = {0};
+ drc_param.sr = sample_rate;
+ drc_param.channels = channel;
+ drc_param.online_en = 0;
+ drc_param.remain_en = 0;
+ drc_param.out_32bit = 1;
+ drc_param.cb = esco_drc_get_filter_info;
+ drc_param.drc_name = call_eq_mode;
+ eff->drc = audio_dec_drc_open(&drc_param);
+ eff->async = async;
+ }
+#endif//TCFG_DRC_ENABLE
+
+ return eff;
+#else
+ return NULL;
+#endif//TCFG_EQ_ENABLE && TCFG_PHONE_EQ_ENABLE
+
+}
+void esco_eq_drc_free(void *eff)
+{
+ dec_eq_drc_free(eff);
+}
+#define audio_out_drc_get_filter esco_drc_get_filter_info//可复用通话下行限幅器系数
+void *audio_out_eq_drc_setup(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en)
+{
+#if TCFG_EQ_ENABLE &&AUDIO_OUT_EQ_USE_SPEC_NUM
+ if (config_eq_lite_en) { //仅支持同步方式eq处理
+ async = 0;//
+ }
+
+ struct dec_eq_drc *eff = zalloc(sizeof(struct dec_eq_drc));
+ struct audio_eq_param eq_param = {0};
+
+ eff->priv = priv;
+ eff->out_cb = eq_output_cb;
+
+ eq_param.channels = channel;
+ eq_param.online_en = 0;
+ eq_param.mode_en = 0;
+ eq_param.remain_en = 0;
+ eq_param.no_wait = async;
+ if (drc_en) {
+ eq_param.out_32bit = 1;
+ }
+ eq_param.max_nsection = AUDIO_OUT_EQ_USE_SPEC_NUM;
+ eq_param.cb = audio_out_eq_get_filter_info;
+ eq_param.eq_name = song_eq_mode;
+ eq_param.sr = sample_rate;
+ eq_param.priv = eff;
+ eq_param.output = eq_output;
+ eff->eq = audio_dec_eq_open(&eq_param);
+#if TCFG_DRC_ENABLE
+ if (drc_en) {
+ struct audio_drc_param drc_param = {0};
+ drc_param.sr = sample_rate;
+ drc_param.channels = channel;
+ drc_param.online_en = 0;
+ drc_param.remain_en = 0;
+ drc_param.out_32bit = 1;
+ drc_param.cb = audio_out_drc_get_filter;
+ drc_param.drc_name = song_eq_mode;
+ eff->drc = audio_dec_drc_open(&drc_param);
+ eff->async = async;
+ }
+#endif //TCFG_DRC_ENABLE
+
+ return eff;
+#else
+ return NULL;
+#endif//TCFG_EQ_ENABLE &&AUDIO_OUT_EQ_USE_SPEC_NUM
+
+}
+void audio_out_eq_drc_free(void *eff)
+{
+#if AUDIO_OUT_EQ_USE_SPEC_NUM
+ dec_eq_drc_free(eff);
+#endif//AUDIO_OUT_EQ_USE_SPEC_NUM
+
+}
+
+__attribute__((always_inline))
+void sat16_to_sat32(s16 *in, s32 *out, u32 npoint, int factor)
+{
+#if 0
+ for (int i = 0; i < npoint; i ++) {
+ out[i] = in[i] * factor;
+ }
+#else
+ s64 tmp;
+ __asm__ volatile(
+ "1: \n\t"
+ "rep %2 { \n\t" //循环
+ "%3 = h[%1 ++= 2]*%4(s) \n\t"
+ "[%0 ++= 4] = %3.l \n\t" //%3.l意思是取tmp的低32位
+ "} \n\t"
+ "if(%2 != 0) goto 1b \n\t"
+ :
+ "=&r"(out),
+ "=&r"(in),
+ "=&r"(npoint),
+ "=&r"(tmp)
+ :
+ "r"(factor),
+ "0"(out),
+ "1"(in),
+ "2"(npoint),
+ "3"(tmp)
+ :
+ );
+
+#endif
+}
+
+int eq_drc_run(void *priv, void *data, u32 len)
+{
+#if TCFG_EQ_ENABLE
+ struct dec_eq_drc *eff = (struct dec_eq_drc *)priv;
+ if (!eff) {
+ return 0;
+ }
+
+#if TCFG_AUDIO_CVP_DUT_ENABLE
+ if (audio_dec_dut_en_get(1) == AUDIO_DEC_DUT_MODE_SPK_EQ) {
+#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
+ spk_eq_run(eff->spk_eq, data, data, len);
+ return 0;
+#endif
+ }
+#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
+
+#if defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE
+ if (!eff->async) {
+ if (eff->eq_out_buf && (eff->eq_out_points < eff->eq_out_total)) {
+ eq_32bit_out(eff);
+ if (eff->eq_out_points < eff->eq_out_total) {
+ return 0;
+ }
+ }
+ }
+#endif
+
+
+#if TCFG_DRC_ENABLE
+ if (eff->drc && !eff->async) {//同步32bit eq drc 处理
+ if ((!eff->eq_out_buf) || (eff->eq_out_buf_len < len * 2)) {
+ if (eff->eq_out_buf) {
+ free(eff->eq_out_buf);
+ }
+ eff->eq_out_buf_len = len * 2;
+ eff->eq_out_buf = malloc(eff->eq_out_buf_len);
+ ASSERT(eff->eq_out_buf);
+ }
+ audio_eq_set_output_buf(eff->eq, eff->eq_out_buf, len);
+
+ if (eff->drc_bef_eq && eff->drc_prev) {
+ sat16_to_sat32((short *)data, (int *)eff->eq_out_buf, len >> 1, 1);
+ audio_drc_run(eff->drc_prev, eff->eq_out_buf, len * 2);
+ }
+ }
+#endif//TCFG_DRC_ENABLE
+
+ int eqlen = 0;
+ if (eff->drc_bef_eq) {
+ eqlen = audio_eq_run(eff->eq, eff->eq_out_buf, len * 2);
+ } else {
+ eqlen = audio_eq_run(eff->eq, data, len);
+ }
+#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
+ if (!eff->async) {
+ if (eff->drc) {
+ spk_eq_run(eff->spk_eq, eff->eq_out_buf, eff->eq_out_buf, len * 2);
+ } else {
+ spk_eq_run(eff->spk_eq, data, data, len);
+ }
+ }
+#endif
+
+#if TCFG_DRC_ENABLE
+ if (eff->drc && !eff->async) {//同步32bit eq drc 处理
+ audio_drc_run(eff->drc, eff->eq_out_buf, len * 2);
+#if defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE
+ eff->eq_out_points = 0;
+ eff->eq_out_total = (len * 2) / 4;
+ eq_32bit_out(eff);
+ return len;//返回16bit位宽长度
+#else
+ user_sat16((s32 *)eff->eq_out_buf, (s16 *)data, (len * 2) / 4);
+#endif
+ }
+#endif//TCFG_DRC_ENABLE
+
+ if (eff->drc && !eff->async) {
+ return len;
+ }
+ return eqlen;
+#else
+ return len;
+#endif
+}
+
+#if AUDIO_OUT_EQ_USE_SPEC_NUM
+
+static struct eq_seg_info audio_out_eq_tab[AUDIO_OUT_EQ_USE_SPEC_NUM] = {
+#ifdef EQ_CORE_V1
+ {0, EQ_IIR_TYPE_BAND_PASS, 125, 0, 0.7f},
+ {1, EQ_IIR_TYPE_BAND_PASS, 12000, 0, 0.3f},
+#else
+ {0, EQ_IIR_TYPE_BAND_PASS, 125, 0 * (1 << 20), 0.7f * (1 << 24)},
+ {1, EQ_IIR_TYPE_BAND_PASS, 12000, 0 * (1 << 20), 0.3f * (1 << 24)},
+#endif
+};
+
+
+
+int audio_out_eq_get_filter_info(void *eq, int sr, struct audio_eq_filter_info *info)
+{
+ struct audio_eq *eq_hdl = (struct audio_eq *)eq;
+ if (!eq_hdl) {
+ return -1;
+ }
+ local_irq_disable();
+ u8 nsection = ARRAY_SIZE(audio_out_eq_tab);
+ if (!eq_hdl->eq_coeff_tab) {
+ eq_hdl->eq_coeff_tab = zalloc(sizeof(int) * 5 * nsection);
+ }
+ for (int i = 0; i < nsection; i++) {
+ eq_seg_design(&audio_out_eq_tab[i], sr, &eq_hdl->eq_coeff_tab[5 * i]);
+ }
+
+ local_irq_enable();
+ info->L_coeff = info->R_coeff = (void *)eq_hdl->eq_coeff_tab;
+ info->L_gain = info->R_gain = 0;
+ info->nsection = nsection;
+ return 0;
+}
+int audio_out_eq_spec_set_info(struct audio_eq *eq, u8 idx, int freq, float gain)
+{
+ if (idx >= AUDIO_OUT_EQ_USE_SPEC_NUM) {
+ return false;
+ }
+ if (gain > 12) {
+ gain = 12;
+ }
+ if (gain < -12) {
+ gain = -12;
+ }
+ if (freq) {
+ audio_out_eq_tab[idx].freq = freq;
+ }
+#ifdef EQ_CORE_V1
+ audio_out_eq_tab[idx].gain = gain;
+#else
+ audio_out_eq_tab[idx].gain = gain * (1 << 20);
+#endif
+
+ /* printf("audio out eq, idx:%d, freq:%d,%d, gain:%d,%d \n", idx, freq, audio_out_eq_tab[idx].freq, gain, audio_out_eq_tab[idx].gain); */
+
+#if !AUDIO_EQ_FADE_EN
+ local_irq_disable();
+ if (eq) {
+ eq->updata = 1;
+ }
+ local_irq_enable();
+#endif
+
+ return true;
+}
+
+#if AUDIO_EQ_FADE_EN
+
+void eq_fade_run(void *p)
+{
+ struct dec_eq_drc *eff = (struct dec_eq_drc *)p;
+ struct eq_filter_fade *fade = &eff->fade;
+ struct audio_eq *eq = (struct audio_eq *)eff->eq;
+
+
+ u8 update = 0;
+ u8 design = 0;
+ for (int i = 0; i < ARRAY_SIZE(audio_out_eq_tab); i++) {
+ if (fade->cur_gain[i] > fade->use_gain[i]) {
+#ifdef EQ_CORE_V1
+ fade->cur_gain[i] -= HIGH_BASS_EQ_FADE_STEP;
+#else
+ fade->cur_gain[i] -= HIGH_BASS_EQ_FADE_STEP * (1 << 20);
+#endif
+ if (fade->cur_gain[i] < fade->use_gain[i]) {
+ fade->cur_gain[i] = fade->use_gain[i];
+ }
+ design = 1;
+ } else if (fade->cur_gain[i] < fade->use_gain[i]) {
+#ifdef EQ_CORE_V1
+ fade->cur_gain[i] += HIGH_BASS_EQ_FADE_STEP;
+#else
+ fade->cur_gain[i] += HIGH_BASS_EQ_FADE_STEP * (1 << 20);
+#endif
+ if (fade->cur_gain[i] > fade->use_gain[i]) {
+ fade->cur_gain[i] = fade->use_gain[i];
+ }
+ design = 1;
+ }
+
+ if (design) {
+ design = 0;
+ update = 1;
+ /* audio_out_eq_spec_set_info(p, i, 0, fade->cur_gain[i]); */
+ /* if (eq) { */
+ audio_out_eq_tab[i].gain = fade->cur_gain[i];//gain;//gain << 20;
+ /* } */
+
+ }
+ }
+
+ if (update) {
+ update = 0;
+ local_irq_disable();
+ if (eq) {
+ eq->updata = 1;
+ }
+ local_irq_enable();
+ }
+}
+
+
+
+#endif
+
+
+int audio_out_eq_set_gain(void *eff, u8 idx, int gain)
+{
+ struct dec_eq_drc *eff_hdl = (struct dec_eq_drc *)eff;
+ if (!eff_hdl) {
+ return 0;
+ }
+ if (!idx) {
+ idx = 0;
+ } else {
+ idx = 1;
+ }
+
+#if AUDIO_EQ_FADE_EN
+ eff_hdl->fade.use_gain[idx] = gain;
+ if (eff_hdl->fade.tmr == 0) {
+ eff_hdl->fade.tmr = sys_hi_timer_add(eff_hdl, eq_fade_run, 20);
+ }
+#else
+ if (!idx) {
+ audio_out_eq_spec_set_info(eff_hdl->eq, 0, 0, gain);//低音
+ } else {
+ audio_out_eq_spec_set_info(eff_hdl->eq, 1, 0, gain);//高音
+ }
+#endif
+
+ return true;
+}
+#endif /*AUDIO_OUT_EQ_USE_SPEC_NUM*/
+
+
+static struct audio_drc *mix_out_drc = NULL;
+
+
+static float mix_out_drc_threadhold = -0.5f;//db -60db~0db,限幅器阈值
+static struct drc_ch mix_out_drc_p = {0};
+int mix_out_drc_get_filter_info(void *drc, struct audio_drc_filter_info *info)
+{
+ float th = mix_out_drc_threadhold;//db -60db~0db,限幅器阈值
+ int threshold = roundf(powf(10.0f, th / 20.0f) * 32768);
+ mix_out_drc_p.nband = 1;
+ mix_out_drc_p.type = 1;
+ mix_out_drc_p._p.limiter[0].attacktime = 5;
+ mix_out_drc_p._p.limiter[0].releasetime = 500;
+ mix_out_drc_p._p.limiter[0].threshold[0] = threshold;
+ mix_out_drc_p._p.limiter[0].threshold[1] = 32768;
+ info->R_pch = info->pch = &mix_out_drc_p;
+ return 0;
+}
+
+void mix_out_drc_open(u16 sample_rate)
+{
+ u8 ch_num;
+#if TCFG_APP_FM_EMITTER_EN
+ ch_num = 2;
+#else
+ u8 dac_connect_mode = audio_dac_get_channel(&dac_hdl);
+ if (dac_connect_mode == DAC_OUTPUT_LR) {
+ ch_num = 2;
+ } else {
+ ch_num = 1;
+ }
+#endif//TCFG_APP_FM_EMITTER_EN
+
+#if TCFG_DRC_ENABLE
+ struct audio_drc_param drc_param = {0};
+ drc_param.sr = sample_rate;
+ drc_param.channels = ch_num;
+ drc_param.online_en = 0;
+ drc_param.remain_en = 0;
+ drc_param.out_32bit = 0;
+ drc_param.cb = mix_out_drc_get_filter_info;
+ drc_param.drc_name = song_eq_mode;
+ mix_out_drc = audio_dec_drc_open(&drc_param);
+#endif//TCFG_DRC_ENABLE
+
+}
+
+void mix_out_drc_close()
+{
+#if TCFG_DRC_ENABLE
+ if (mix_out_drc) {
+ audio_dec_drc_close(mix_out_drc);
+ mix_out_drc = NULL;
+ }
+#endif//TCFG_DRC_ENABLE
+
+}
+
+void mix_out_drc_run(s16 *data, u32 len)
+{
+ u8 en = 1;
+#if TCFG_DRC_ENABLE
+#if TCFG_AUDIO_ANC_ENABLE
+ en = anc_status_get();
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+ if (mix_out_drc && en) {
+ audio_drc_run(mix_out_drc, data, len);
+ }
+#endif//TCFG_DRC_ENABLE
+
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief mix_out后限幅器系数更新
+ @param threadhold限幅器阈值,-60~0,单位db
+ @return
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+void mix_out_drc_threadhold_update(float threadhold)
+{
+#if TCFG_DRC_ENABLE
+ mix_out_drc_threadhold = threadhold;
+
+ local_irq_disable();
+ if (mix_out_drc) {
+ mix_out_drc->updata = 1;
+ }
+ local_irq_enable();
+#endif//TCFG_DRC_ENABLE
+
+}
+
+struct audio_eq *audio_dec_eq_open_new(struct audio_eq_param *parm, struct eq_parm_new *par_new)
+{
+ struct audio_eq_param *eq_param = parm;
+ struct audio_eq *eq = zalloc(sizeof(struct audio_eq) + sizeof(struct hw_eq_ch));
+ if (eq) {
+ eq->eq_ch = (struct hw_eq_ch *)((int)eq + sizeof(struct audio_eq));
+
+ audio_eq_open(eq, eq_param);
+ audio_eq_set_samplerate(eq, eq_param->sr);
+ audio_eq_set_info_new(eq, eq_param->channels, par_new->in_mode, eq_param->out_32bit, par_new->run_mode, par_new->data_in_mode, par_new->data_out_mode);
+ /* log_info("eq_param->sr %d, eq_param->channels %d\n", eq_param->sr, eq_param->channels); */
+ audio_eq_set_output_handle(eq, eq_param->output, eq_param->priv);
+ audio_eq_start(eq);
+ /* log_info("audio_dec_eq_open name %d\n", eq_param->eq_name); */
+ }
+ return eq;
+}
+
+#if defined(AUDIO_GAME_EFFECT_CONFIG) && AUDIO_GAME_EFFECT_CONFIG
+
+struct drc_ch dec_drc_p = {0};
+int dec_drc_get_filter_info(void *drc, struct audio_drc_filter_info *info)
+{
+ float th = -0.5f;//db -60db~0db,限幅器阈值
+ int threshold = roundf(powf(10.0f, th / 20.0f) * 32768);
+ dec_drc_p.nband = 1;
+ dec_drc_p.type = 1;
+ dec_drc_p._p.limiter[0].attacktime = 5;
+ dec_drc_p._p.limiter[0].releasetime = 500;
+ dec_drc_p._p.limiter[0].threshold[0] = threshold;
+ dec_drc_p._p.limiter[0].threshold[1] = 32768;
+ info->R_pch = info->pch = &dec_drc_p;
+ return 0;
+}
+
+
+void *dec_eq_drc_setup_new(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en)
+{
+#if TCFG_EQ_ENABLE
+
+ struct dec_eq_drc *eff = zalloc(sizeof(struct dec_eq_drc));
+ if (config_eq_lite_en) { //仅支持同步方式eq处理
+ async = 0;//
+ }
+
+#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
+ eff->spk_eq = spk_eq_open(sample_rate, channel, drc_en ? 1 : 0);
+#endif/*AUDIO_SPK_EQ_CONFIG*/
+
+#if TCFG_DRC_ENABLE
+ if (drc_en & BIT(1)) { //game eff drc
+ if (!eq_file_get_cfg(get_eq_cfg_hdl(), (u8 *)SDFILE_RES_ROOT_PATH"eq_game_eff.bin")) { //加载游戏音效
+ EQ_CFG *eq_cfg = get_eq_cfg_hdl();
+ eq_cfg->eq_type = EQ_TYPE_FILE;
+ }
+ eff->drc_bef_eq = 1;
+ async = 0;
+ struct audio_drc_param drc_param = {0};
+ drc_param.sr = sample_rate;
+ drc_param.channels = channel;
+ drc_param.online_en = 1;
+ drc_param.remain_en = 1;
+ drc_param.out_32bit = 1;
+ drc_param.cb = drc_get_filter_info;
+ drc_param.drc_name = song_eq_mode;
+ eff->drc_prev = audio_dec_drc_open(&drc_param);
+ }
+#endif//TCFG_DRC_ENABLE
+
+ eff->priv = priv;
+ eff->out_cb = eq_output_cb;
+
+ struct audio_eq_param eq_param = {0};
+ eq_param.channels = channel;
+ eq_param.online_en = 1;
+ eq_param.mode_en = 1;
+ eq_param.remain_en = 1;
+ eq_param.no_wait = async;
+ if (drc_en) {
+ eq_param.out_32bit = 1;
+ }
+ eq_param.max_nsection = EQ_SECTION_MAX;
+ eq_param.cb = eq_get_filter_info;
+ eq_param.eq_name = song_eq_mode;
+ eq_param.sr = sample_rate;
+ eq_param.priv = eff;
+ eq_param.output = eq_output;
+
+ struct eq_parm_new par_new = {0};
+ par_new.in_mode = DATI_INT;
+ par_new.run_mode = NORMAL;
+ par_new.data_in_mode = SEQUENCE_DAT_IN;
+ par_new.data_out_mode = SEQUENCE_DAT_OUT;
+ eff->eq = audio_dec_eq_open_new(&eq_param, &par_new);
+ eff->async = async;
+#if TCFG_DRC_ENABLE
+ if (drc_en) {
+ struct audio_drc_param drc_param = {0};
+ drc_param.sr = sample_rate;
+ drc_param.channels = channel;
+ if (eff->drc_bef_eq) {
+ drc_param.online_en = 0;
+ drc_param.remain_en = 0;
+ drc_param.out_32bit = 1;
+ drc_param.cb = dec_drc_get_filter_info;
+ drc_param.drc_name = mic_eq_mode;
+ } else {
+ drc_param.online_en = 1;
+ drc_param.remain_en = 1;
+ drc_param.out_32bit = 1;
+ drc_param.cb = drc_get_filter_info;
+ drc_param.drc_name = song_eq_mode;
+ }
+ eff->drc = audio_dec_drc_open(&drc_param);
+ }
+#endif//TCFG_DRC_ENABLE
+
+ return eff;
+#else
+ return NULL;
+#endif//TCFG_EQ_ENABLE
+
+}
+#endif /*AUDIO_GAME_EFFECT_CONFIG*/
+
+
+#if TCFG_AUDIO_ESCO_LIMITER_ENABLE
+#if !TCFG_DRC_ENABLE
+#error "需打开宏TCFG_DRC_ENABLE"
+#endif
+#ifndef ESCO_DL_LIMITER_THR
+#define ESCO_DL_LIMITER_THR 0
+#endif
+static struct drc_ch esco_drc = {0};
+int esco_limiter_get_filter_info(void *drc, struct audio_drc_filter_info *info)
+{
+ float th = ESCO_DL_LIMITER_THR;//db -60db~0db,限幅器阈值
+ int threshold = roundf(powf(10.0f, th / 20.0f) * 32768);
+ esco_drc.nband = 1;
+ esco_drc.type = 1;
+ esco_drc._p.limiter[0].attacktime = 5;
+ esco_drc._p.limiter[0].releasetime = 500;
+ esco_drc._p.limiter[0].threshold[0] = threshold;
+ esco_drc._p.limiter[0].threshold[1] = 32768;
+ info->R_pch = info->pch = &esco_drc;
+ return 0;
+}
+
+struct audio_drc *esco_limiter_open(u16 sample_rate, u16 ch_num)
+{
+#if TCFG_DRC_ENABLE
+
+ struct audio_drc_param drc_param = {0};
+ drc_param.sr = sample_rate;
+ drc_param.channels = ch_num;
+ drc_param.cb = esco_limiter_get_filter_info;
+ drc_param.drc_name = call_eq_mode;
+ return audio_dec_drc_open(&drc_param);
+#else
+ return NULL;
+#endif//TCFG_DRC_ENABLE
+}
+
+void esco_limiter_close(struct audio_drc *limiter)
+{
+#if TCFG_DRC_ENABLE
+ if (limiter) {
+ audio_dec_drc_close(limiter);
+ limiter = NULL;
+ }
+#endif//TCFG_DRC_ENABLE
+
+}
+
+void esco_limiter_run(struct audio_drc *limiter, s16 *data, u32 len)
+{
+#if TCFG_DRC_ENABLE
+ if (limiter) {
+ audio_drc_run(limiter, data, len);
+ }
+#endif//TCFG_DRC_ENABLE
+}
+#endif/*TCFG_AUDIO_ESCO_LIMITER_ENABLE*/
+
+#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
+#define AUDIO_SPK_EQ_STERO 1//支持左右声道独立的spk_eq
+
+
+/*
+ *spk_eq系数表
+ * */
+static struct eq_seg_info spk_eq_seg_tab[] = {
+ /*L*/
+ {0, EQ_IIR_TYPE_BAND_PASS, 31, 0, 0.7f},
+ {1, EQ_IIR_TYPE_BAND_PASS, 62, 0, 0.7f},
+ {2, EQ_IIR_TYPE_BAND_PASS, 125, 0, 0.7f},
+ {3, EQ_IIR_TYPE_BAND_PASS, 250, 0, 0.7f},
+ {4, EQ_IIR_TYPE_BAND_PASS, 500, 0, 0.7f},
+ {5, EQ_IIR_TYPE_BAND_PASS, 1000, 0, 0.7f},
+ {6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, 0.7f},
+ {7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, 0.7f},
+ {8, EQ_IIR_TYPE_BAND_PASS, 8000, 0, 0.7f},
+ {9, EQ_IIR_TYPE_BAND_PASS, 16000, 0, 0.7f},
+#if AUDIO_SPK_EQ_STERO
+ /*R*/
+ {0, EQ_IIR_TYPE_BAND_PASS, 31, 0, 0.7f},
+ {1, EQ_IIR_TYPE_BAND_PASS, 62, 0, 0.7f},
+ {2, EQ_IIR_TYPE_BAND_PASS, 125, 0, 0.7f},
+ {3, EQ_IIR_TYPE_BAND_PASS, 250, 0, 0.7f},
+ {4, EQ_IIR_TYPE_BAND_PASS, 500, 0, 0.7f},
+ {5, EQ_IIR_TYPE_BAND_PASS, 1000, 0, 0.7f},
+ {6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, 0.7f},
+ {7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, 0.7f},
+ {8, EQ_IIR_TYPE_BAND_PASS, 8000, 0, 0.7f},
+ {9, EQ_IIR_TYPE_BAND_PASS, 16000, 0, 0.7f}
+#endif
+};
+#if AUDIO_SPK_EQ_STERO
+static struct eq_seg_info *spk_eq_seg_tab_R = &spk_eq_seg_tab[10];
+#endif
+
+/*
+ *spk_eq系数表运算后存放的buf
+ * */
+static float spk_eq_coeff_tab[10][5];
+static float spk_eq_coeff_tab_R[10][5];
+/*
+ *spk_eq 总增益
+ * */
+static float spk_eq_global_gain[2] = {0};//[0]:左声道 [1]:右声道
+static u32 seg_sel = 0;
+static u32 seg_sel_R = 0;
+static u32 spk_eq_sample_rate = 0;
+/*
+ *spk_eq系数回调函数
+ * */
+int spk_eq_get_filter_info(void *_eq, int sr, struct audio_eq_filter_info *info)
+{
+ struct audio_eq *eq = _eq;
+ if (!sr) {
+ sr = spk_eq_sample_rate;
+ }
+ u8 ch_num;
+#if TCFG_APP_FM_EMITTER_EN
+ ch_num = 2;
+#else
+ u8 dac_connect_mode = audio_dac_get_channel(&dac_hdl);
+ if (dac_connect_mode == DAC_OUTPUT_LR) {
+ ch_num = 2;
+ } else {
+ ch_num = 1;
+ }
+#endif//TCFG_APP_FM_EMITTER_EN
+
+ local_irq_disable();
+ u8 cnt = 1;
+#if AUDIO_SPK_EQ_STERO
+ cnt = 2;
+#endif
+ u8 nsection = ARRAY_SIZE(spk_eq_seg_tab) / cnt;
+ for (int i = 0; i < nsection; i++) {
+ if (seg_sel & BIT(i)) {
+ seg_sel &= ~BIT(i);
+ eq_seg_design(&spk_eq_seg_tab[i], sr, &spk_eq_coeff_tab[i]);
+ /* float *tar_buf = &spk_eq_coeff_tab[i]; */
+ /* printf("cal coeff:0x%x, 0x%x, 0x%x, 0x%x, 0x%x " */
+ /* , *(int *)&tar_buf[0] */
+ /* , *(int *)&tar_buf[1] */
+ /* , *(int *)&tar_buf[2] */
+ /* , *(int *)&tar_buf[3] */
+ /* , *(int *)&tar_buf[4] */
+ /* ); */
+ }
+#if AUDIO_SPK_EQ_STERO
+ if (ch_num == 2) {
+ if (seg_sel_R & BIT(i)) {
+ seg_sel_R &= ~BIT(i);
+ eq_seg_design(&spk_eq_seg_tab_R[i], sr, &spk_eq_coeff_tab_R[i]);
+ }
+ }
+#endif
+ }
+ /* printf("spk_eq_global_gain[0] %d\n",(int)spk_eq_global_gain[0]); */
+ /* printf("spk_eq_global_gain[1] %d\n",(int)spk_eq_global_gain[1]); */
+ local_irq_enable();
+#if AUDIO_SPK_EQ_STERO
+ if (ch_num == 2) {
+ info->L_coeff = (void *)spk_eq_coeff_tab;//系数指针赋值
+ info->R_coeff = (void *)spk_eq_coeff_tab_R;//系数指针赋值
+ info->L_gain = spk_eq_global_gain[0];//总增益填写,用户可修改(-20~20db)
+ info->R_gain = spk_eq_global_gain[1];//总增益填写,用户可修改(-20~20db)
+ } else
+#endif
+ {
+ info->L_coeff = info->R_coeff = (void *)spk_eq_coeff_tab;//系数指针赋值
+ info->L_gain = info->R_gain = spk_eq_global_gain[0];//总增益填写,用户可修改(-20~20db)
+ }
+ info->nsection = nsection;//eq段数,根据提供给的系数表来填写,例子是2
+ return 0;
+}
+
+static struct audio_eq *spk_eq = NULL;
+/*
+ *spk_eq 系数更新接口,更新第几段eq系数
+ *parm: *seg
+ *seg->index:第几段(0~9)
+ *seg->iir_type:滤波器类型(EQ_IIR_TYPE)
+ *seg->freq:中心截止频率(20~20kHz)
+ *seg->gain:增益(-12~13dB)
+ * */
+void spk_eq_seg_update(struct eq_seg_info *seg)
+{
+ if (!seg) {
+ log_e("spk_eq seg null\n");
+ return ;
+ }
+ u8 i = seg->index;
+ u8 cnt = 1;
+#if AUDIO_SPK_EQ_STERO
+ cnt = 2;
+#endif
+
+ if (i >= ARRAY_SIZE(spk_eq_seg_tab) / cnt) {
+ log_e("spk_eq index err: %d >= %d\n", seg->index, ARRAY_SIZE(spk_eq_seg_tab) / cnt);
+ return ;
+ }
+ local_irq_disable();
+ memcpy(&spk_eq_seg_tab[i], seg, sizeof(struct eq_seg_info));
+ seg_sel |= BIT(i);
+ if (spk_eq) {
+ struct audio_eq *eq = spk_eq;
+ eq->updata = 1;//设置更新标志
+ }
+ local_irq_enable();
+}
+
+/*
+ *spk_eq 右声道系数更新接口,更新第几段eq系数
+ *parm: *seg
+ *seg->index:第几段(0~9)
+ *seg->iir_type:滤波器类型(EQ_IIR_TYPE)
+ *seg->freq:中心截止频率(20~20kHz)
+ *seg->gain:增益(-12~13dB)
+ * */
+void spk_eq_seg_update_R(struct eq_seg_info *seg)
+{
+ u8 cnt = 1;
+#if AUDIO_SPK_EQ_STERO
+ if (!seg) {
+ log_e("spk_eq seg null\n");
+ return ;
+ }
+ u8 i = seg->index;
+ cnt = 2;
+
+ if (i >= ARRAY_SIZE(spk_eq_seg_tab) / cnt) {
+ log_e("spk_eq index err: %d >= %d\n", seg->index, ARRAY_SIZE(spk_eq_seg_tab) / cnt);
+ return ;
+ }
+ local_irq_disable();
+ memcpy(&spk_eq_seg_tab_R[i], seg, sizeof(struct eq_seg_info));
+ seg_sel_R |= BIT(i);
+ if (spk_eq) {
+ struct audio_eq *eq = spk_eq;
+ eq->updata = 1;//设置更新标志
+ }
+ local_irq_enable();
+#endif
+}
+
+/*
+ *spk_eq 总增益更新
+ * */
+void spk_eq_global_gain_udapte(float global_gain)
+{
+ spk_eq_global_gain[0] = global_gain;
+ local_irq_disable();
+ if (spk_eq) {
+ /* printf("spk_eq_global_gain[L] %d\n",(int)spk_eq_global_gain[0]); */
+ struct audio_eq *eq = spk_eq;
+ eq->updata = 1;//设置更新标志
+ }
+ local_irq_enable();
+}
+
+void spk_eq_global_gain_udapte_R(float global_gain)
+{
+ spk_eq_global_gain[1] = global_gain;
+ local_irq_disable();
+ if (spk_eq) {
+ /* printf("spk_eq_global_gain[R] %d\n",(int)spk_eq_global_gain[1]); */
+ struct audio_eq *eq = spk_eq;
+ eq->updata = 1;//设置更新标志
+ }
+ local_irq_enable();
+}
+
+/*
+ *spk_eq 打开
+ * */
+void *spk_eq_open(u32 sample_rate, u8 ch_num, u8 bitwide)
+{
+#if TCFG_AUDIO_CVP_DUT_ENABLE
+ //DEC_DUT模式默认仅保留spk_eq, 因此改为16bit位宽
+ if (audio_dec_dut_en_get(1) == AUDIO_DEC_DUT_MODE_SPK_EQ) {
+ bitwide = 0;
+ }
+#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
+ spk_eq_sample_rate = sample_rate;
+ seg_sel = 0xffff;
+ seg_sel_R = 0xffff;
+ struct audio_eq_param eq_param = {0};
+
+ eq_param.channels = ch_num;
+ eq_param.max_nsection = EQ_SECTION_MAX;
+ eq_param.cb = spk_eq_get_filter_info;
+ eq_param.eq_name = song_eq_mode;
+ eq_param.sr = sample_rate;
+ eq_param.out_32bit = bitwide ? 1 : 0;
+
+
+ struct eq_parm_new par_new = {0};
+ par_new.in_mode = bitwide ? DATI_INT : DATI_SHORT;
+ par_new.run_mode = NORMAL;
+ par_new.data_in_mode = SEQUENCE_DAT_IN;
+ par_new.data_out_mode = SEQUENCE_DAT_OUT;
+ void *eq = audio_dec_eq_open_new(&eq_param, &par_new);
+ local_irq_disable();
+ spk_eq = eq;//记录spk_eq 指针,用于系数更新调用
+ local_irq_enable();
+ /* sys_timer_add(NULL, spk_eq_global_gain_udpate_test, 5000); */
+ /* sys_timer_add(NULL,spk_eq_seg_udpate_test , 5000); */
+ return eq;
+}
+
+/*
+ *spk_eq 关闭
+ * */
+void spk_eq_close(void *eq)
+{
+ if (eq) {
+ local_irq_disable();
+ spk_eq = NULL;
+ local_irq_enable();
+ audio_dec_eq_close(eq);
+ }
+}
+
+/*
+ *spk_eq 数据处理
+ * */
+void spk_eq_run(void *eq, void *in, void *out, u16 len)
+{
+ if (!eq) {
+ return ;
+ }
+
+ audio_eq_set_output_buf(eq, out, len);
+ audio_eq_run(eq, in, len);
+}
+
+/*
+ *spk_eq 系数表保存到vm
+ * */
+int spk_eq_save_to_vm(void)
+{
+ int ret_tmp = 0;
+ /* puts("====jj===========to save \n"); */
+ /* printf("sizeof(spk_eq_seg_tab) %d, %d\n", sizeof(spk_eq_seg_tab), sizeof(float)); */
+ /* printf("%d %d\n", CFG_SPK_EQ_SEG_SAVE, CFG_SPK_EQ_GLOBAL_GAIN_SAVE); */
+ int ret = syscfg_write(CFG_SPK_EQ_SEG_SAVE, spk_eq_seg_tab, sizeof(spk_eq_seg_tab));
+ if (ret <= 0) {
+ printf("spk_eq tab write to vm err, ret %d\n", ret);
+ ret_tmp = -1;
+ }
+ ret = syscfg_write(CFG_SPK_EQ_GLOBAL_GAIN_SAVE, spk_eq_global_gain, sizeof(spk_eq_global_gain));
+ if (ret <= 0) {
+ printf("spk_eq global gain write to vm err ret %d\n", ret);
+ ret_tmp = -1;
+ }
+ /* puts("===============to save end\n"); */
+ return ret_tmp;
+}
+/*
+ *spk_eq 系数表从vm中读取
+ * */
+void spk_eq_read_from_vm()
+{
+ int ret = syscfg_read(CFG_SPK_EQ_SEG_SAVE, spk_eq_seg_tab, sizeof(spk_eq_seg_tab));
+ if (ret <= 0) {
+ printf("skp_eq read from vm err\n");
+ }
+ ret = syscfg_read(CFG_SPK_EQ_GLOBAL_GAIN_SAVE, spk_eq_global_gain, sizeof(spk_eq_global_gain));
+ if (ret <= 0) {
+ printf("spk_eq global gain read from vm err\n");
+ }
+}
+
+/* typedef struct { */
+/* u8 cmd; */
+/* struct eq_seg_info seg; */
+/* }spk_seg_info; */
+
+/* typedef struct { */
+/* u8 cmd; */
+/* float global_gain; */
+/* }spk_global_gain_info; */
+
+
+typedef struct {
+ u16 magic; //0x3344
+ u16 crc; //data crc
+ u8 data[32]; //data
+} SPK_EQ_PACK;
+
+#define CMD_SEG 0x1
+#define CMD_GLOBAL 0x2
+#define CMD_SAVE_PARM 0x3
+#define CMD_RESET_PARM 0x4
+/*
+ *右声道更新命令
+ * */
+#define CMD_SEG_R 0x5
+#define CMD_GLOBAL_R 0x6
+
+#define CMD_SUPPORT_GLOBAL_GAIN 0x7
+
+
+#define CMD_READ_SEG_L 0x8//左声道或者单声道获取系数表
+#define CMD_READ_SEG_R 0x9//右声道获取系数表
+
+#define CMD_READ_GLOBAL_L 0xa //左声道或者单声道获取总增益
+#define CMD_READ_GLOBAL_R 0xb //右声道获取总增益
+
+#define SPK_EQ_CRC_EN 0//是否使能crc校验
+
+static u8 parse_seq = 0;
+void (*send_data_handler)(u8 seq, u8 *packet, u8 size);
+
+static spk_eq_ack_packet(u8 seq, u8 *packet, u8 size)
+{
+ if (send_data_handler) {
+ send_data_handler(seq, packet, size);
+ } else {
+ app_online_db_ack(seq, packet, size);
+ }
+}
+
+int spk_eq_spp_rx_packet(u8 *packet, u8 len)
+{
+
+ SPK_EQ_PACK pack = {0};//packet;
+ memcpy(&pack, packet, len);
+ if (pack.magic != 0x3344) {
+ printf("magic err 0x%x\n", pack.magic);
+ return -1;
+ }
+ struct eq_seg_info seg = {0};
+ float global_gain = 0;
+ u8 cmd = pack.data[0];
+ u16 crc;
+ printf("cmd %d\n", cmd);
+ switch (cmd) {
+ case CMD_SEG:
+#if SPK_EQ_CRC_EN
+ crc = CRC16(pack.data, len - 4);
+ if (crc != pack.crc) {
+ printf("spk_seg pack crc err %x, %x\n", crc, pack.crc);
+ return -1;
+ }
+#endif
+ memcpy(&seg, &pack.data[1], sizeof(struct eq_seg_info));
+ spk_eq_seg_update(&seg);
+
+ printf("idx:%d, iir:%d, frq:%d, gain:0x%x, q:0x%x \n", seg.index, seg.iir_type, seg.freq, *(int *)&seg.gain, *(int *)&seg.q);
+ break;
+ case CMD_GLOBAL:
+#if SPK_EQ_CRC_EN
+ crc = CRC16(pack.data, len - 4);
+ if (crc != pack.crc) {
+ printf("spk global gain info pack crc err %x, %x\n", crc, pack.crc);
+ return -1;
+ }
+#endif
+ memcpy(&global_gain, &pack.data[1], sizeof(float));
+ spk_eq_global_gain_udapte(global_gain);
+ printf("global_gain 0x%x\n", *(int *)&global_gain);
+ break;
+ case CMD_SEG_R:
+#if SPK_EQ_CRC_EN
+ crc = CRC16(pack.data, len - 4);
+ if (crc != pack.crc) {
+ printf("spk_seg_r pack crc err %x, %x\n", crc, pack.crc);
+ return -1;
+ }
+#endif
+ memcpy(&seg, &pack.data[1], sizeof(struct eq_seg_info));
+ spk_eq_seg_update_R(&seg);
+
+ printf("R idx:%d, iir:%d, frq:%d, gain:0x%x, q:0x%x \n", seg.index, seg.iir_type, seg.freq, *(int *)&seg.gain, *(int *)&seg.q);
+ break;
+ case CMD_GLOBAL_R:
+#if SPK_EQ_CRC_EN
+ crc = CRC16(pack.data, len - 4);
+ if (crc != pack.crc) {
+ printf("spk global gain info pack crc err %x, %x\n", crc, pack.crc);
+ return -1;
+ }
+#endif
+ memcpy(&global_gain, &pack.data[1], sizeof(float));
+ spk_eq_global_gain_udapte_R(global_gain);
+ printf("R global_gain 0x%x\n", *(int *)&global_gain);
+ break;
+ case CMD_SAVE_PARM:
+ return spk_eq_save_to_vm();
+ break;
+ case CMD_RESET_PARM:
+ local_irq_disable();
+ u8 cnt = 1;
+#if AUDIO_SPK_EQ_STERO
+ cnt = 2;
+#endif
+
+ for (int i = 0; i < ARRAY_SIZE(spk_eq_seg_tab) / cnt; i++) {
+ spk_eq_seg_tab[i].index = i;
+ spk_eq_seg_tab[i].freq = 100;
+ spk_eq_seg_tab[i].iir_type = EQ_IIR_TYPE_BAND_PASS;
+ spk_eq_seg_tab[i].gain = 0.0f;
+ spk_eq_seg_tab[i].q = 0.7f;
+ seg_sel |= BIT(i);
+
+#if AUDIO_SPK_EQ_STERO
+ spk_eq_seg_tab_R[i].index = i;
+ spk_eq_seg_tab_R[i].freq = 100;
+ spk_eq_seg_tab_R[i].iir_type = EQ_IIR_TYPE_BAND_PASS;
+ spk_eq_seg_tab_R[i].gain = 0.0f;
+ spk_eq_seg_tab_R[i].q = 0.7f;
+ seg_sel_R |= BIT(i);
+#endif
+ }
+ local_irq_enable();
+ spk_eq_global_gain_udapte(0);
+ spk_eq_global_gain_udapte_R(0);
+
+ return spk_eq_save_to_vm();
+ break;
+ case CMD_SUPPORT_GLOBAL_GAIN:
+ //support global_gain
+ break;
+ case CMD_READ_SEG_L:
+ spk_eq_ack_packet(parse_seq, spk_eq_seg_tab, sizeof(spk_eq_seg_tab) / 2);
+ return 1;
+ case CMD_READ_SEG_R:
+ spk_eq_ack_packet(parse_seq, &spk_eq_seg_tab[10], sizeof(spk_eq_seg_tab) / 2);
+ return 1;
+ case CMD_READ_GLOBAL_L:
+ spk_eq_ack_packet(parse_seq, &spk_eq_global_gain[0], 4);
+ return 1;
+ case CMD_READ_GLOBAL_R:
+ spk_eq_ack_packet(parse_seq, &spk_eq_global_gain[1], 4);
+ return 1;
+
+ default:
+ printf("crc %d\n", pack.crc);
+ printf("cmd err %x\n", cmd);
+ return -1;
+ }
+ return 0;
+}
+
+int spk_eq_read_seg_l(u8 **buf)
+{
+ *buf = (u8 *)(&spk_eq_seg_tab[0]);
+ return sizeof(spk_eq_seg_tab) / 2;
+}
+
+int spk_eq_read_seg_r(u8 **buf)
+{
+#if AUDIO_SPK_EQ_STERO
+ *buf = (u8 *)(&spk_eq_seg_tab[10]);
+ return sizeof(spk_eq_seg_tab) / 2;
+#else
+ return 0;
+#endif
+}
+
+int spk_eq_app_online_parse(u8 *packet, u8 size, u8 *ext_data, u16 ext_size)
+{
+ if (ext_data) {
+ parse_seq = ext_data[1];
+ } else {
+ parse_seq = 0xff;
+ }
+ printf("parse_seq %x\n", parse_seq);
+ int ret = spk_eq_spp_rx_packet(packet, size);
+ if (!ret) {
+ u8 ack[] = "OK";
+ spk_eq_ack_packet(parse_seq, ack, sizeof(ack));
+ /* spk_eq_ack_packet(parse_seq, packet, size); */
+ } else if (ret != 1) {
+ u8 ack[] = "ER";
+ spk_eq_ack_packet(parse_seq, ack, sizeof(ack));
+ /* spk_eq_ack_packet(parse_seq, packet, size); */
+ }
+ return 0;
+}
+
+void spk_eq_set_send_data_handler(void (*handler)(u8 seq, u8 *packet, u8 size))
+{
+ send_data_handler = handler;
+}
+
+int spk_eq_init(void)
+{
+#if APP_ONLINE_DEBUG
+ app_online_db_register_handle(DB_PKT_TYPE_SPK_EQ, spk_eq_app_online_parse);
+#endif
+ return 0;
+}
+__initcall(spk_eq_init);
+
+
+#endif/*AUDIO_SPK_EQ_CONFIG*/
+
+#if defined(TCFG_AUDIO_BASS_BOOST) && TCFG_AUDIO_BASS_BOOST
+
+#if TCFG_AUDIO_BASS_BOOST_TEST
+static u8 bass_boost_run = 1;
+u8 test_bass_boost = 1;
+#else
+static u8 bass_boost_run = 1;
+#endif/*TCFG_AUDIO_BASS_BOOST_TEST*/
+
+#if TCFG_AUDIO_BASS_BOOST_TEST
+#define TWS_FUNC_ID_BASS_EFF \
+ ((int)(('A' + '2' + 'D' + 'P') << (2 * 8)) | \
+ (int)(('E' + 'F' + 'F') << (1 * 8)) | \
+ (int)(('S' + 'Y' + 'N' + 'C') << (0 * 8)))
+void audio_bass_ctrl()
+{
+ int state = tws_api_get_tws_state();
+ if (state & TWS_STA_SIBLING_CONNECTED) {
+ test_bass_boost = !test_bass_boost;
+ if (test_bass_boost) { //对耳链接,进入低音增强,播个提示音
+ /* tone_play_index(TONE_NORMAL, 1); */
+ } else {
+ }
+
+ tws_api_send_data_to_sibling((u8 *)&test_bass_boost, sizeof(int), TWS_FUNC_ID_BASS_EFF);
+ } else {
+ test_bass_boost = !test_bass_boost;
+ bass_boost_run = test_bass_boost;
+
+ }
+}
+
+static void tws_a2dp_eff_align_bass(void *data, u16 len, bool rx)
+{
+ int a2dp_eff;
+ memcpy(&a2dp_eff, data, sizeof(int));
+ bass_boost_run = a2dp_eff;
+ test_bass_boost = bass_boost_run;
+}
+
+REGISTER_TWS_FUNC_STUB(a2dp_align_bass) = {
+ .func_id = TWS_FUNC_ID_BASS_EFF,
+ .func = tws_a2dp_eff_align_bass,
+};
+#endif/*TCFG_AUDIO_BASS_BOOST_TEST*/
+
+static int bass_boost_get_filter_info(void *drc, struct audio_drc_filter_info *info)
+{
+#if (TCFG_AUDIO_BASS_BOOST && TCFG_DRC_ENABLE)
+ static struct drc_ch wdrc_p = {0};
+ struct threshold_group low_threshold[] = {//低频
+ {0, 0},
+ {79, 79},
+ {140, 80},
+ };
+
+ struct threshold_group mid_threshold[] = {//中频
+ {0, 0},
+ {82, 82},
+ {140, 82}
+ };
+
+ wdrc_p.nband = 2;
+ wdrc_p.type = 3;//wdrc
+ wdrc_p.low_freq = 90; //低中分频点 (20~600hz)
+ wdrc_p.high_freq = 2000;//中高分频点 (0~20000hz)
+ wdrc_p.order = 2;////分频阶数 2或者4
+ int i = 0;
+ //低频
+ wdrc_p._p.wdrc[0].attacktime = 10;
+ wdrc_p._p.wdrc[0].releasetime = 100;
+ memcpy(wdrc_p._p.wdrc[0].threshold, low_threshold, sizeof(low_threshold));
+ wdrc_p._p.wdrc[0].threshold_num = ARRAY_SIZE(low_threshold);
+ wdrc_p._p.wdrc[0].rms_time = 25;
+ wdrc_p._p.wdrc[0].algorithm = 0;
+ wdrc_p._p.wdrc[0].mode = 1;
+ wdrc_p._p.wdrc[0].inputgain = 0;
+ wdrc_p._p.wdrc[0].outputgain = 8;
+
+ //高频
+ //right
+ wdrc_p._p.wdrc[1].attacktime = 10;
+ wdrc_p._p.wdrc[1].releasetime = 100;
+ memcpy(wdrc_p._p.wdrc[1].threshold, mid_threshold, sizeof(mid_threshold));
+ wdrc_p._p.wdrc[1].threshold_num = ARRAY_SIZE(mid_threshold);
+ wdrc_p._p.wdrc[1].rms_time = 25;
+ wdrc_p._p.wdrc[1].algorithm = wdrc_p._p.wdrc[0].algorithm;
+ wdrc_p._p.wdrc[1].mode = wdrc_p._p.wdrc[0].mode;
+ wdrc_p._p.wdrc[1].inputgain = wdrc_p._p.wdrc[0].inputgain;
+ wdrc_p._p.wdrc[1].outputgain = wdrc_p._p.wdrc[0].outputgain;
+
+
+ info->R_pch = info->pch = &wdrc_p;
+#endif/*TCFG_AUDIO_BASS_BOOST*/
+ return 0;
+}
+void *audio_bass_boost_open(u32 sample_rate, u8 ch_num)
+{
+ struct audio_drc *bass_boost = NULL;
+ struct audio_drc_param drc_param = {0};
+ drc_param.sr = sample_rate;
+ drc_param.channels = ch_num;
+ drc_param.cb = bass_boost_get_filter_info;
+ bass_boost = audio_dec_drc_open(&drc_param);
+ return bass_boost;
+}
+
+void audio_bass_boost_run(void *hdl, s16 *data, int len)
+{
+ if (!hdl) {
+ return;
+ }
+ if (bass_boost_run) {
+ audio_drc_run(hdl, data, len);
+ }
+}
+
+
+void audio_bass_boost_close(void *hdl)
+{
+
+ if (!hdl) {
+ return;
+ }
+ audio_dec_drc_close(hdl);
+}
+#endif
diff --git a/cpu/br28/audio_dec_eff.h b/cpu/br28/audio_dec_eff.h
new file mode 100644
index 0000000..1557cec
--- /dev/null
+++ b/cpu/br28/audio_dec_eff.h
@@ -0,0 +1,134 @@
+#ifndef _AUD_DEC_EFF_H
+#define _AUD_DEC_EFF_H
+#include "asm/includes.h"
+#include "media/includes.h"
+#include "system/includes.h"
+#include "classic/tws_api.h"
+#include "classic/hci_lmp.h"
+#include "media/eq_config.h"
+#include "media/audio_surround.h"
+#include "app_config.h"
+#include "audio_config.h"
+#include "app_main.h"
+#include "media/audio_vbass.h"
+#if TCFG_AUDIO_ANC_ENABLE
+#include "audio_anc.h"
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+
+#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
+#include "online_db_deal.h"
+#endif
+
+struct dec_sur {
+#if AUDIO_SURROUND_CONFIG
+ surround_hdl *surround; //环绕音效句柄
+ u8 surround_eff; //音效模式记录
+#endif
+
+};
+
+#if (defined(TCFG_AUDIO_OUT_EQ_ENABLE) && (TCFG_AUDIO_OUT_EQ_ENABLE != 0))
+#define AUDIO_OUT_EQ_USE_SPEC_NUM 2 // 使用特定的eq段
+#else
+#define AUDIO_OUT_EQ_USE_SPEC_NUM 0
+#endif
+#define AUDIO_EQ_FADE_EN 1
+#define HIGH_BASS_EQ_FADE_STEP (1)
+
+#if TCFG_EQ_ENABLE&&TCFG_AUDIO_OUT_EQ_ENABLE
+#define AUDIO_OUT_EFFECT_ENABLE 1 // 音频输出时的音效处理
+#else
+#define AUDIO_OUT_EFFECT_ENABLE 0
+#endif//TCFG_AUDIO_OUT_EQ_ENABLE
+extern struct audio_mixer mixer;
+
+typedef int (*eq_output_cb)(void *, void *, int);
+
+struct eq_filter_fade {
+ u16 tmr;
+ int cur_gain[AUDIO_OUT_EQ_USE_SPEC_NUM];
+ int use_gain[AUDIO_OUT_EQ_USE_SPEC_NUM];
+};
+struct dec_eq_drc {
+ s16 *eq_out_buf;
+ int eq_out_buf_len;
+ int eq_out_points;
+ int eq_out_total;
+
+ void *priv;
+ eq_output_cb out_cb;
+ void *drc_prev;
+ void *eq;
+ void *spk_eq;
+ void *drc;
+ u8 async;
+ u8 drc_bef_eq;
+ struct eq_filter_fade fade;
+ u8 remain;
+};
+
+struct eq_parm_new {
+ u8 in_mode: 2;
+ u8 run_mode: 2;
+ u8 data_in_mode: 2;
+ u8 data_out_mode: 2;
+};
+void *audio_surround_setup(u8 channel, u8 eff);
+void audio_surround_free(void *sur);
+void audio_surround_set_ch(void *sur, u8 channel);
+void audio_surround_voice(void *sur, u8 en);
+
+
+vbass_hdl *audio_vbass_setup(u32 sample_rate, u8 channel);
+void audio_vbass_free(vbass_hdl *vbass);
+
+
+void *dec_eq_drc_setup(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en);
+void dec_eq_drc_free(void *eff);
+
+
+void *esco_eq_drc_setup(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en);
+void esco_eq_drc_free(void *eff);
+
+
+void *audio_out_eq_drc_setup(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en);
+void audio_out_eq_drc_free(void *eff);
+int audio_out_eq_set_gain(void *eff, u8 idx, int gain);
+
+int eq_drc_run(void *priv, void *data, u32 len);
+
+void mix_out_drc_open(u16 sample_rate);
+void mix_out_drc_close();
+void mix_out_drc_run(s16 *data, u32 len);
+/*----------------------------------------------------------------------------*/
+/**@brief mix_out后限幅器系数更新
+ @param threadhold限幅器阈值,-60~0,单位db
+ @return
+ @note
+*/
+/*----------------------------------------------------------------------------*/
+void mix_out_drc_threadhold_update(float threadhold);
+
+struct audio_drc *esco_limiter_open(u16 sample_rate, u16 ch_num);
+void esco_limiter_run(struct audio_drc *limiter, s16 *data, u32 len);
+void esco_limiter_close(struct audio_drc *limiter);
+
+void spk_eq_seg_update(struct eq_seg_info *seg);
+void spk_eq_global_gain_udapte(float global_gain);
+void *spk_eq_open(u32 sample_rate, u8 ch_num, u8 bitwide);
+void spk_eq_close(void *eq);
+void spk_eq_run(void *eq, void *in, void *out, u16 len);
+int spk_eq_save_to_vm();
+void spk_eq_read_from_vm();
+void spk_eq_set_send_data_handler(void (*handler)(u8 seq, u8 *packet, u8 size));
+int spk_eq_app_online_parse(u8 *packet, u8 size, u8 *ext_data, u16 ext_size);
+int spk_eq_spp_rx_packet(u8 *packet, u8 len);
+int spk_eq_read_seg_l(u8 **buf);
+int spk_eq_read_seg_r(u8 **buf);
+
+void *audio_bass_boost_open(u32 sample_rate, u8 ch_num);
+void audio_bass_boost_run(void *hdl, s16 *data, int len);
+void audio_bass_boost_close(void *hdl);
+
+extern struct virtual_bass_tool_set *get_vbass_parm();
+#endif
diff --git a/cpu/br28/audio_enc.c b/cpu/br28/audio_enc.c
new file mode 100644
index 0000000..fb00e01
--- /dev/null
+++ b/cpu/br28/audio_enc.c
@@ -0,0 +1,1035 @@
+#include "asm/includes.h"
+#include "media/includes.h"
+#include "system/includes.h"
+#include "classic/hci_lmp.h"
+#include "aec_user.h"
+#include "audio_config.h"
+#include "app_main.h"
+#include "audio_enc.h"
+#if TCFG_AUDIO_CVP_DUT_ENABLE
+#include "audio_cvp_dut.h"
+#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
+#if TCFG_AUDIO_ANC_ENABLE
+#include "audio_anc.h"
+#endif
+#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+#include "icsd_adt_app.h"
+#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
+
+#ifdef CONFIG_BOARD_AISPEECH_VAD_ASR
+#include "btstack/avctp_user.h"
+extern int ais_platform_asr_open(void);
+extern void ais_platform_asr_close(void);
+#endif /*CONFIG_BOARD_AISPEECH_VAD_ASR*/
+
+extern struct adc_platform_data adc_data;
+
+extern int msbc_encoder_init();
+extern int cvsd_encoder_init();
+
+struct audio_adc_hdl adc_hdl;
+struct esco_enc_hdl *esco_enc = NULL;
+struct audio_encoder_task *encode_task = NULL;
+
+struct esco_enc_hdl {
+ struct audio_encoder encoder;
+ OS_SEM pcm_frame_sem;
+ s16 output_frame[30]; //align 4Bytes
+ int pcm_frame[60];
+ u8 state; //align 4Bytes
+};
+
+/*
+ *mic电源管理
+ *设置mic vdd对应port的状态
+ */
+void audio_mic_pwr_io(u32 gpio, u8 out_en)
+{
+ gpio_set_die(gpio, 1);
+ gpio_set_pull_up(gpio, 0);
+ gpio_set_pull_down(gpio, 0);
+ gpio_direction_output(gpio, out_en);
+}
+
+void audio_mic_pwr_ctl(u8 state)
+{
+#if (TCFG_AUDIO_MIC_PWR_CTL & MIC_PWR_FROM_GPIO)
+ switch (state) {
+ case MIC_PWR_INIT:
+ case MIC_PWR_OFF:
+ /*mic供电IO配置:输出0*/
+#if ((TCFG_AUDIO_MIC_PWR_PORT != NO_CONFIG_PORT))
+ audio_mic_pwr_io(TCFG_AUDIO_MIC_PWR_PORT, 0);
+#endif/*TCFG_AUDIO_MIC_PWR_PORT*/
+#if ((TCFG_AUDIO_MIC1_PWR_PORT != NO_CONFIG_PORT))
+ audio_mic_pwr_io(TCFG_AUDIO_MIC1_PWR_PORT, 0);
+#endif/*TCFG_AUDIO_MIC1_PWR_PORT*/
+#if ((TCFG_AUDIO_MIC2_PWR_PORT != NO_CONFIG_PORT))
+ audio_mic_pwr_io(TCFG_AUDIO_MIC2_PWR_PORT, 0);
+#endif/*TCFG_AUDIO_MIC2_PWR_PORT*/
+
+ /*mic信号输入端口配置:
+ *mic0:PA1
+ *mic1:PB8*/
+#if (TCFG_AUDIO_ADC_MIC_CHA & LADC_CH_MIC_L)
+ audio_mic_pwr_io(IO_PORTA_01, 0);//MIC0
+#endif/*TCFG_AUDIO_ADC_MIC_CHA*/
+
+#if (TCFG_AUDIO_ADC_MIC_CHA & LADC_CH_MIC_R)
+ audio_mic_pwr_io(IO_PORTB_08, 0);//MIC1
+#endif/*TCFG_AUDIO_ADC_MIC_CHA*/
+ break;
+
+ case MIC_PWR_ON:
+ /*mic供电IO配置:输出1*/
+#if (TCFG_AUDIO_MIC_PWR_PORT != NO_CONFIG_PORT)
+ audio_mic_pwr_io(TCFG_AUDIO_MIC_PWR_PORT, 1);
+#endif/*TCFG_AUDIO_MIC_PWR_CTL*/
+#if (TCFG_AUDIO_MIC1_PWR_PORT != NO_CONFIG_PORT)
+ audio_mic_pwr_io(TCFG_AUDIO_MIC1_PWR_PORT, 1);
+#endif/*TCFG_AUDIO_MIC1_PWR_PORT*/
+#if (TCFG_AUDIO_MIC2_PWR_PORT != NO_CONFIG_PORT)
+ audio_mic_pwr_io(TCFG_AUDIO_MIC2_PWR_PORT, 1);
+#endif/*TCFG_AUDIO_MIC2_PWR_PORT*/
+ break;
+
+ case MIC_PWR_DOWN:
+ break;
+ }
+#endif/*TCFG_AUDIO_MIC_PWR_CTL*/
+}
+
+/*
+*********************************************************************
+* PDM MIC API
+* Description: PDM mic操作接口
+* Arguments : None.
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+/* #define ESCO_PLNK_SR 16000#<{(|16000/44100/48000|)}># */
+#define ESCO_PLNK_SCLK 2400000 /*1M-4M,SCLK/SR需为整数且在1-4096范围*/
+#define ESCO_PLNK_CH_NUM 1 /*支持的最大通道(max = 2)*/
+#define ESCO_PLNK_IRQ_POINTS 256 /*采样中断点数*/
+#include "pdm_link.h"
+static audio_plnk_t *audio_plnk_mic = NULL;
+static void audio_plnk_mic_output(void *buf, u16 len)
+{
+ s16 *mic0 = (s16 *)buf;
+ if (esco_enc) {
+#if (defined(TCFG_PHONE_MESSAGE_ENABLE) && (TCFG_PHONE_MESSAGE_ENABLE))
+ int ret = phone_message_mic_write(mic0, len << 1);
+ if (ret >= 0) {
+ esco_enc_resume();
+ return ;
+ }
+#endif/*TCFG_PHONE_MESSAGE_ENABLE*/
+ audio_aec_inbuf(mic0, len << 1);
+ }
+}
+
+static int esco_pdm_mic_en(u8 en, u16 sr, u16 gain)
+{
+ printf("esco_pdm_mic_en:%d\n", en);
+ if (en) {
+ if (audio_plnk_mic) {
+ printf("audio_plnk_mic re-malloc error\n");
+ return -1;
+ }
+ audio_plnk_mic = zalloc(sizeof(audio_plnk_t));
+ if (audio_plnk_mic == NULL) {
+ printf("audio_plnk_mic zalloc failed\n");
+ return -1;
+ }
+ audio_mic_pwr_ctl(MIC_PWR_ON);
+ audio_plnk_mic->ch_num = ESCO_PLNK_CH_NUM;
+ audio_plnk_mic->sr = sr;
+ audio_plnk_mic->buf_len = ESCO_PLNK_IRQ_POINTS;
+#if (PLNK_CH_EN == PLNK_CH0_EN)
+ audio_plnk_mic->ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE;
+ audio_plnk_mic->ch1_mode = CH1MD_CH0_SCLK_FALLING_EDGE;
+#elif (PLNK_CH_EN == PLNK_CH1_EN)
+ audio_plnk_mic->ch0_mode = CH0MD_CH1_SCLK_FALLING_EDGE;
+ audio_plnk_mic->ch1_mode = CH1MD_CH1_SCLK_RISING_EDGE;
+#else
+ audio_plnk_mic->ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE;
+ audio_plnk_mic->ch1_mode = CH1MD_CH1_SCLK_RISING_EDGE;
+#endif
+ audio_plnk_mic->buf = zalloc(audio_plnk_mic->buf_len * audio_plnk_mic->ch_num * 2 * 2);
+ ASSERT(audio_plnk_mic->buf);
+ audio_plnk_mic->sclk_io = TCFG_AUDIO_PLNK_SCLK_PIN;
+ audio_plnk_mic->ch0_io = TCFG_AUDIO_PLNK_DAT0_PIN;
+ audio_plnk_mic->ch1_io = TCFG_AUDIO_PLNK_DAT1_PIN;
+ audio_plnk_mic->output = audio_plnk_mic_output;
+ audio_plnk_open(audio_plnk_mic);
+ audio_plnk_start(audio_plnk_mic);
+ SFR(JL_ASS->CLK_CON, 0, 2, 3);
+ } else {
+ audio_plnk_close();
+#if TCFG_AUDIO_ANC_ENABLE
+ //printf("anc_status:%d\n",anc_status_get());
+ if (anc_status_get() == 0) {
+ audio_mic_pwr_ctl(MIC_PWR_OFF);
+ }
+#else
+ audio_mic_pwr_ctl(MIC_PWR_OFF);
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+ if (audio_plnk_mic->buf) {
+ free(audio_plnk_mic->buf);
+ }
+ if (audio_plnk_mic) {
+ free(audio_plnk_mic);
+ audio_plnk_mic = NULL;
+ }
+ }
+ return 0;
+}
+
+/*
+*********************************************************************
+* IIS MIC API
+* Description: iis mic操作接口
+* Arguments : None.
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+static void audio_iis_mic_output(s16 *data, u16 len)
+{
+
+}
+static int esco_iis_mic_en(u8 en, u16 sr, u16 gain)
+{
+ if (en) {
+
+ } else {
+
+ }
+ return 0;
+}
+
+/*
+*********************************************************************
+* ADC MIC API
+* Description: adc mic操作接口
+* Arguments : None.
+* Return : None.
+* Note(s) : None.
+*********************************************************************
+*/
+#define ESCO_ADC_BUF_NUM 3
+#define ESCO_ADC_IRQ_POINTS 256
+#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
+#define ESCO_ADC_CH 3 //3mic通话
+#elif TCFG_AUDIO_DUAL_MIC_ENABLE
+#define ESCO_ADC_CH 2 //双mic通话
+#else
+#define ESCO_ADC_CH 1 //单mic通话
+#endif
+#if defined(TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN) && TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+#define ESCO_ADC_BUFS_SIZE (ESCO_ADC_BUF_NUM * ESCO_ADC_IRQ_POINTS * ESCO_ADC_CH * 3)
+#else
+#define ESCO_ADC_BUFS_SIZE (ESCO_ADC_BUF_NUM * ESCO_ADC_IRQ_POINTS * ESCO_ADC_CH)
+#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
+struct esco_mic_hdl {
+ struct audio_adc_output_hdl adc_output;
+ struct adc_mic_ch mic_ch;
+ /* s16 adc_buf[ESCO_ADC_BUFS_SIZE]; //align 2Bytes */
+#if (ESCO_ADC_CH > 1)
+ s16 tmp_buf[ESCO_ADC_IRQ_POINTS];
+#endif/*ESCO_ADC_CH*/
+#if (ESCO_ADC_CH > 2)
+ s16 tmp_buf_1[ESCO_ADC_IRQ_POINTS];
+#endif/*ESCO_ADC_CH*/
+};
+s16 esco_adc_buf[ESCO_ADC_BUFS_SIZE]; //align 2Bytes
+static struct esco_mic_hdl *esco_mic = NULL;
+static void adc_mic_output_handler(void *priv, s16 *data, int len)
+{
+ //printf("buf:%x,data:%x,len:%d",esco_enc->adc_buf,data,len);
+ if (esco_mic) {
+
+#if defined(TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN) && TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
+ if (adc_data.anc_adt_en) {
+ u8 esco_mic_num = audio_adc_file_get_esco_mic_num();
+ u8 adt_mic_num = get_icsd_adt_mic_num();
+ /* 1mic通话,2mic/3mic免摘
+ * 2mic通话,3mic免摘*/
+ if (esco_mic_num < adt_mic_num) {
+ for (int i = 0; i < len / 2; i++) {
+ memcpy(&data[esco_mic_num * i], &data[adt_mic_num * i], esco_mic_num * sizeof(short));
+ }
+ }
+ }
+#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
+
+#if (defined(TCFG_PHONE_MESSAGE_ENABLE) && (TCFG_PHONE_MESSAGE_ENABLE))
+ int ret = phone_message_mic_write(data, len);
+ if (ret >= 0) {
+ esco_enc_resume();
+ return ;
+ }
+#endif/*TCFG_PHONE_MESSAGE_ENABLE*/
+
+#if TCFG_AUDIO_CVP_DUT_ENABLE
+ if (cvp_dut_mode_get() == CVP_DUT_MODE_BYPASS) {
+ audio_aec_inbuf(data, len);
+ return;
+ }
+#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
+
+#if (ESCO_ADC_CH == 3)/*3 Mic*/
+ s16 *mic_data[3];
+ mic_data[0] = data;
+ mic_data[1] = data + (len / 2);
+ mic_data[2] = data + (len / 2) * 2;
+
+ /*拆分mic数据*/
+ s16 *mic1_data_pos = esco_mic->tmp_buf;
+ s16 *mic2_data_pos = esco_mic->tmp_buf_1;
+ //printf("mic_data:%x,%x,%d\n",data,mic1_data_pos,len);
+ for (u16 i = 0; i < (len >> 1); i++) {
+ mic_data[0][i] = data[i * 3];
+ mic1_data_pos[i] = data[i * 3 + 1];
+ mic2_data_pos[i] = data[i * 3 + 2];
+ }
+ memcpy(mic_data[1], mic1_data_pos, len);
+ memcpy(mic_data[2], mic2_data_pos, len);
+
+ u8 mic_ch = TCFG_AUDIO_ADC_MIC_CHA;
+ u8 cnt = 0;
+ u8 talk_data_num = 0;//记录通话MIC数据位置
+ for (int i = 0; i < 4; i++) {
+ if ((mic_ch & BIT(i)) == app_var.talk_fb_mic_ch) {
+ audio_aec_inbuf_ref_1(mic_data[cnt++], len);
+ continue;
+ }
+ if ((mic_ch & BIT(i)) == app_var.talk_mic_ch) {
+ talk_data_num = cnt++;
+ continue;
+ }
+ if ((mic_ch & BIT(i)) == app_var.talk_ref_mic_ch) {
+ audio_aec_inbuf_ref(mic_data[cnt++], len);
+ continue;
+ }
+ }
+ /*通话MIC数据需要最后传进算法*/
+ audio_aec_inbuf(mic_data[talk_data_num], len);
+ return;
+
+#elif (ESCO_ADC_CH == 2)/*DualMic*/
+ s16 *mic0_data = data;
+ s16 *mic1_data = esco_mic->tmp_buf;
+ s16 *mic1_data_pos = data + (len / 2);
+ //printf("mic_data:%x,%x,%d\n",data,mic1_data_pos,len);
+ for (u16 i = 0; i < (len >> 1); i++) {
+ mic0_data[i] = data[i * 2];
+ mic1_data[i] = data[i * 2 + 1];
+ }
+ memcpy(mic1_data_pos, mic1_data, len);
+
+#if 0 /*debug*/
+ static u16 mic_cnt = 0;
+ if (mic_cnt++ > 300) {
+ putchar('1');
+ audio_aec_inbuf(mic1_data_pos, len);
+ if (mic_cnt > 600) {
+ mic_cnt = 0;
+ }
+ } else {
+ putchar('0');
+ audio_aec_inbuf(mic0_data, len);
+ }
+#else
+#if (TCFG_AUDIO_DMS_MIC_MANAGE == DMS_MASTER_MIC0)
+ audio_aec_inbuf_ref(mic1_data_pos, len);
+ audio_aec_inbuf(data, len);
+#else
+ audio_aec_inbuf_ref(data, len);
+ audio_aec_inbuf(mic1_data_pos, len);
+#endif/*TCFG_AUDIO_DMS_MIC_MANAGE*/
+#endif/*debug end*/
+#else/*SingleMic*/
+ //audio_aec_inbuf(data, len);
+#endif/*ESCO_ADC_CH*/
+ }
+}
+
+static int esco_mic_en(u8 en, u16 sr, u16 mic0_gain, u16 mic1_gain, u16 mic2_gain, u16 mic3_gain)
+{
+ u8 mic_ch;
+ printf("esco_mic_en:%d\n", en);
+ if (en) {
+ if (esco_mic) {
+ printf("esco_mic re-malloc error\n");
+ return -1;
+ }
+ esco_mic = zalloc(sizeof(struct esco_mic_hdl));
+ if (esco_mic == NULL) {
+ printf("esco mic zalloc failed\n");
+ return -1;
+ }
+ audio_mic_pwr_ctl(MIC_PWR_ON);
+#if TCFG_AUDIO_ANC_ENABLE && TCFG_AUDIO_DYNAMIC_ADC_GAIN
+ anc_dynamic_micgain_start(get_master_mic_gain(1));
+#endif/*TCFG_AUDIO_ANC_ENABLE && TCFG_AUDIO_DYNAMIC_ADC_GAIN*/
+#if (TCFG_AUDIO_CVP_DUT_ENABLE && TCFG_AUDIO_ANC_ENABLE)
+ if (cvp_dut_mode_get() == CVP_DUT_MODE_BYPASS) {
+ //使用ANC MIC增益 测试ANC MIC频响
+ mic0_gain = audio_anc_mic_gain_get(0);
+ mic1_gain = audio_anc_mic_gain_get(1);
+ mic2_gain = audio_anc_mic_gain_get(2);
+ mic3_gain = audio_anc_mic_gain_get(3);
+ mic_ch = cvp_dut_mic_ch_get();
+ } else {
+ mic_ch = TCFG_AUDIO_ADC_MIC_CHA;
+ }
+#else
+ mic_ch = TCFG_AUDIO_ADC_MIC_CHA;
+#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
+
+ if (mic_ch & AUDIO_ADC_MIC_0) {
+ audio_adc_mic_open(&esco_mic->mic_ch, mic_ch, &adc_hdl);
+ audio_adc_mic_set_gain(&esco_mic->mic_ch, mic0_gain);
+ }
+ if (mic_ch & AUDIO_ADC_MIC_1) {
+ audio_adc_mic1_open(&esco_mic->mic_ch, mic_ch, &adc_hdl);
+ audio_adc_mic1_set_gain(&esco_mic->mic_ch, mic1_gain);
+ }
+ if (mic_ch & AUDIO_ADC_MIC_2) {
+ audio_adc_mic2_open(&esco_mic->mic_ch, mic_ch, &adc_hdl);
+ audio_adc_mic2_set_gain(&esco_mic->mic_ch, mic2_gain);
+ }
+ if (mic_ch & AUDIO_ADC_MIC_3) {
+ audio_adc_mic3_open(&esco_mic->mic_ch, mic_ch, &adc_hdl);
+ audio_adc_mic3_set_gain(&esco_mic->mic_ch, mic3_gain);
+ }
+
+ audio_adc_mic_set_sample_rate(&esco_mic->mic_ch, sr);
+ audio_adc_mic_set_buffs(&esco_mic->mic_ch, esco_adc_buf,
+ ESCO_ADC_IRQ_POINTS * 2, ESCO_ADC_BUF_NUM);
+ esco_mic->adc_output.handler = adc_mic_output_handler;
+ audio_adc_add_output_handler(&adc_hdl, &esco_mic->adc_output);
+
+ audio_adc_mic_start(&esco_mic->mic_ch);
+ } else {
+ if (esco_mic) {
+#if TCFG_AUDIO_ANC_ENABLE && TCFG_AUDIO_DYNAMIC_ADC_GAIN
+ anc_dynamic_micgain_stop();
+#endif/*TCFG_AUDIO_ANC_ENABLE && TCFG_AUDIO_DYNAMIC_ADC_GAIN*/
+ audio_adc_mic_close(&esco_mic->mic_ch);
+ audio_adc_del_output_handler(&adc_hdl, &esco_mic->adc_output);
+#if TCFG_AUDIO_ANC_ENABLE
+ //printf("anc_status:%d\n",anc_status_get());
+ if (anc_status_get() == 0) {
+ audio_mic_pwr_ctl(MIC_PWR_OFF);
+ }
+#else
+ audio_mic_pwr_ctl(MIC_PWR_OFF);
+#endif/*TCFG_AUDIO_ANC_ENABLE*/
+ free(esco_mic);
+ esco_mic = NULL;
+ }
+ }
+ return 0;
+}
+
+/*按顺序给用到的1/2/3个麦赋值*/
+void get_config_mic_gain(u8 mic_gain0, u8 mic_gain1, u8 mic_gain2)
+{
+ u8 mic_ch = TCFG_AUDIO_ADC_MIC_CHA;
+ u8 temp = 0, i = 0;
+ u8 gain[4];
+ for (i = 0; i < 4; i++) {
+ temp = mic_ch & 0x01;
+ if (temp && mic_gain0) {
+ gain[i] = mic_gain0;
+ mic_gain0 = 0;
+ } else if (temp && mic_gain1) {
+ gain[i] = mic_gain1;
+ mic_gain1 = 0;
+ } else if (temp && mic_gain2) {
+ gain[i] = mic_gain2;
+ mic_gain2 = 0;
+ } else {
+ gain[i] = 0;
+ }
+ mic_ch >>= 1;
+ }
+ app_var.aec_mic_gain = gain[0];
+ app_var.aec_mic1_gain = gain[1];
+ app_var.aec_mic2_gain = gain[2];
+ app_var.aec_mic3_gain = gain[3];
+}
+
+/*
+*********************************************************************
+* get_master_mic_gain
+* Description: 获取双麦时主麦或副麦增益
+* Arguments : master, 1:获取主麦增益,0:获取副麦增益
+* Return : 获取到的mic增益
+* Note(s) : None.
+*********************************************************************
+*/
+u8 get_master_mic_gain(u8 master)
+{
+ u8 gain[4], i = 0, cnt = 0;
+ gain[0] = app_var.aec_mic_gain;
+ gain[1] = app_var.aec_mic1_gain;
+ gain[2] = app_var.aec_mic2_gain;
+ gain[3] = app_var.aec_mic3_gain;
+ for (i = 0; i < 4; i++) {
+ if (gain[i]) {
+ cnt++;
+#if (TCFG_AUDIO_DMS_MIC_MANAGE == DMS_MASTER_MIC0)/*第一个麦是主麦时*/
+ if (master && cnt == 1) {
+ /*返回第一个使用的麦的增益*/
+ return gain[i];
+ } else if (!master && cnt == 2) {
+ return gain[i];
+ }
+#else /*第二个麦是主麦时*/
+ if (master && cnt == 2) {
+ /*返回第二个使用的麦的增益*/
+ return gain[i];
+ } else if (!master && cnt == 1) {
+ return gain[i];
+ }
+#endif
+ }
+ }
+ return 0;
+}
+
+/*用于ANC打开ADC数字时,初始化ADC的buffer的地址和长度*/
+void esco_adc_mic_set_buffs(void)
+{
+ audio_adc_mic_set_buffs(NULL, esco_adc_buf,
+ ESCO_ADC_IRQ_POINTS * 2, ESCO_ADC_BUF_NUM);
+}
+
+__attribute__((weak)) int audio_aec_output_read(s16 *buf, u16 len)
+{
+ return 0;
+}
+
+void esco_enc_resume(void)
+{
+ if (esco_enc) {
+ audio_encoder_resume(&esco_enc->encoder);
+ }
+}
+
+static int esco_enc_pcm_get(struct audio_encoder *encoder, s16 **frame, u16 frame_len)
+{
+ int rlen = 0;
+ if (encoder == NULL) {
+ printf("encoder NULL");
+ }
+ struct esco_enc_hdl *enc = container_of(encoder, struct esco_enc_hdl, encoder);
+
+ if (enc == NULL) {
+ printf("enc NULL");
+ }
+
+ while (1) {
+#if (defined(TCFG_PHONE_MESSAGE_ENABLE) && (TCFG_PHONE_MESSAGE_ENABLE))
+ rlen = phone_message_output_read(enc->pcm_frame, frame_len);
+ if (rlen == frame_len) {
+ break;
+ } else if (rlen == 0) {
+ return 0;
+ }
+#endif/*TCFG_PHONE_MESSAGE_ENABLE*/
+ rlen = audio_aec_output_read(enc->pcm_frame, frame_len);
+ if (rlen == frame_len) {
+ /*esco编码读取数据正常*/
+ break;
+ } else if (rlen == 0) {
+ /*esco编码读不到数,返回0*/
+ return 0;
+ } else {
+ /*通话结束,aec已经释放*/
+ printf("audio_enc end:%d\n", rlen);
+ rlen = 0;
+ break;
+ }
+ }
+
+ *frame = enc->pcm_frame;
+ return rlen;
+}
+static void esco_enc_pcm_put(struct audio_encoder *encoder, s16 *frame)
+{
+}
+
+static const struct audio_enc_input esco_enc_input = {
+ .fget = esco_enc_pcm_get,
+ .fput = esco_enc_pcm_put,
+};
+
+static int esco_enc_probe_handler(struct audio_encoder *encoder)
+{
+ return 0;
+}
+
+static int esco_enc_output_handler(struct audio_encoder *encoder, u8 *frame, int len)
+{
+ lmp_private_send_esco_packet(NULL, frame, len);
+ //printf("frame:%x,out:%d\n",frame, len);
+
+ return len;
+}
+
+const static struct audio_enc_handler esco_enc_handler = {
+ .enc_probe = esco_enc_probe_handler,
+ .enc_output = esco_enc_output_handler,
+};
+
+static void esco_enc_event_handler(struct audio_decoder *decoder, int argc, int *argv)
+{
+ printf("esco_enc_event_handler:0x%x,%d\n", argv[0], argv[0]);
+ switch (argv[0]) {
+ case AUDIO_ENC_EVENT_END:
+ puts("AUDIO_ENC_EVENT_END\n");
+ break;
+ }
+}
+
+#ifdef CONFIG_BOARD_AISPEECH_VAD_ASR
+static u16 aispeech_esco_sample_rate = 16000;
+static u16 aispeech_esco_mic0_gain = TALK_MIC0_GAIN;
+static u16 aispeech_esco_mic1_gain = FF_MIC1_GAIN;
+static u16 aispeech_esco_mic2_gain = FB_MIC2_GAIN;
+static u16 aispeech_esco_mic3_gain = OTHER_MIC3_GAIN;
+
+void esco_mic_cfg_set(u16 sr, u16 mic0_gain, u16 mic1_gain, u16 mic2_gain, u16 mic3_gain)
+{
+ aispeech_esco_sample_rate = sr;
+ aispeech_esco_mic0_gain = mic0_gain;
+ aispeech_esco_mic1_gain = mic1_gain;
+ aispeech_esco_mic2_gain = mic2_gain;
+ aispeech_esco_mic3_gain = mic3_gain;
+}
+
+void esco_mic_reset(void)
+{
+ esco_mic_en(1, aispeech_esco_sample_rate,
+ aispeech_esco_mic0_gain,
+ aispeech_esco_mic1_gain,
+ aispeech_esco_mic2_gain,
+ aispeech_esco_mic3_gain);
+}
+#endif /*CONFIG_BOARD_AISPEECH_VAD_ASR*/
+
+int esco_enc_open(u32 coding_type, u8 frame_len)
+{
+ int err;
+ struct audio_fmt fmt;
+
+ printf("esco_enc_open: %d,frame_len:%d\n", coding_type, frame_len);
+
+ fmt.channel = 1;
+ fmt.frame_len = frame_len;
+ if (coding_type == AUDIO_CODING_MSBC) {
+ fmt.sample_rate = 16000;
+ fmt.coding_type = AUDIO_CODING_MSBC;
+ } else if (coding_type == AUDIO_CODING_CVSD) {
+ fmt.sample_rate = 8000;
+ fmt.coding_type = AUDIO_CODING_CVSD;
+ } else {
+ /*Unsupoport eSCO Air Mode*/
+ }
+
+
+ if (!encode_task) {
+ encode_task = zalloc(sizeof(*encode_task));
+ audio_encoder_task_create(encode_task, "audio_enc");
+ }
+ if (!esco_enc) {
+ esco_enc = zalloc(sizeof(*esco_enc));
+ }
+
+ os_sem_create(&esco_enc->pcm_frame_sem, 0);
+
+ audio_encoder_open(&esco_enc->encoder, &esco_enc_input, encode_task);
+ audio_encoder_set_handler(&esco_enc->encoder, &esco_enc_handler);
+ audio_encoder_set_fmt(&esco_enc->encoder, &fmt);
+ audio_encoder_set_event_handler(&esco_enc->encoder, esco_enc_event_handler, 0);
+ audio_encoder_set_output_buffs(&esco_enc->encoder, esco_enc->output_frame,
+ sizeof(esco_enc->output_frame), 1);
+
+ if (!esco_enc->encoder.enc_priv) {
+ log_e("encoder err, maybe coding(0x%x) disable \n", fmt.coding_type);
+ err = -EINVAL;
+ goto __err;
+ }
+
+ audio_encoder_start(&esco_enc->encoder);
+
+#ifdef CONFIG_BOARD_AISPEECH_NR_GAIN
+ app_var.aec_mic_gain = TALK_MIC0_GAIN;
+#endif/*CONFIG_BOARD_AISPEECH_NR_GAIN*/
+
+#if TCFG_AUDIO_ANC_ENABLE && (!TCFG_AUDIO_DYNAMIC_ADC_GAIN)
+ app_var.aec_mic_gain = audio_anc_ffmic_gain_get();
+#endif/*TCFG_AUDIO_ANC_ENABLE && (!TCFG_AUDIO_DYNAMIC_ADC_GAIN)*/
+
+ printf("esco sample_rate: %d,mic_gain:%d %d %d %d\n", fmt.sample_rate, app_var.aec_mic_gain, \
+ app_var.aec_mic1_gain, app_var.aec_mic2_gain, app_var.aec_mic3_gain);
+
+ /*pdm mic*/
+#if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC)
+#if TCFG_AUDIO_CVP_DUT_ENABLE
+ if (cvp_dut_mode_get() == CVP_DUT_MODE_BYPASS) {
+ esco_mic_en(1, fmt.sample_rate, app_var.aec_mic_gain, app_var.aec_mic1_gain, app_var.aec_mic2_gain, app_var.aec_mic3_gain);
+ } else
+#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
+ {
+ esco_pdm_mic_en(1, fmt.sample_rate, app_var.aec_mic_gain);
+ }
+ return 0;
+#endif/*TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC*/
+
+ /*iis mic*/
+#if (TCFG_AUDIO_ADC_MIC_CHA == ALNK_MIC)
+ esco_iis_mic_en(1, fmt.sample_rate, app_var.aec_mic_gain);
+ return 0;
+#endif/*TCFG_AUDIO_ADC_MIC_CHA == ALNK_MIC*/
+
+#ifdef CONFIG_BOARD_AISPEECH_VAD_ASR
+ if (get_call_status() != BT_CALL_INCOMING) {
+ ais_platform_asr_close();
+ /*adc mic*/
+ /* esco_mic_en(1, fmt.sample_rate, app_var.aec_mic_gain, app_var.aec_mic_gain, 1, app_var.aec_mic_gain); */
+ esco_mic_en(1, fmt.sample_rate, TALK_MIC0_GAIN, FF_MIC1_GAIN, FB_MIC2_GAIN, OTHER_MIC3_GAIN);
+ }
+ esco_mic_cfg_set(fmt.sample_rate, TALK_MIC0_GAIN, FF_MIC1_GAIN, FB_MIC2_GAIN, OTHER_MIC3_GAIN);
+ /* esco_mic_cfg_set(fmt.sample_rate, app_var.aec_mic_gain, app_var.aec_mic_gain, 1, app_var.aec_mic_gain); */
+#elif (defined CONFIG_BOARD_AISPEECH_NR)
+ esco_mic_en(1, fmt.sample_rate, TALK_MIC0_GAIN, FF_MIC1_GAIN, FB_MIC2_GAIN, OTHER_MIC3_GAIN);
+#else /*JL自研算法*/
+ /*adc mic*/
+ esco_mic_en(1, fmt.sample_rate, app_var.aec_mic_gain, app_var.aec_mic1_gain, app_var.aec_mic2_gain, app_var.aec_mic3_gain);
+#endif /*CONFIG_BOARD_AISPEECH_VAD_ASR*/
+
+ esco_enc->state = 1;
+ return 0;
+__err:
+ audio_encoder_close(&esco_enc->encoder);
+
+#ifdef CONFIG_BOARD_AISPEECH_VAD_ASR
+ ais_platform_asr_open();
+#endif /*CONFIG_BOARD_AISPEECH_VAD_ASR*/
+
+ local_irq_disable();
+ free(esco_enc);
+ esco_enc = NULL;
+ local_irq_enable();
+
+ return err;
+}
+
+int esco_adc_mic_en()
+{
+ if (esco_enc && esco_enc->state) {
+ /* audio_adc_mic_start(&esco_enc->mic_ch); */
+ /* audio_mic_start(&esco_enc->mic_ch); */
+ return 0;
+ }
+ return -1;
+}
+
+void esco_enc_close()
+{
+ printf("esco_enc_close\n");
+ if (!esco_enc) {
+ printf("esco_enc NULL\n");
+ return;
+ }
+ esco_enc->state = 0;
+ os_sem_post(&esco_enc->pcm_frame_sem);
+#if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC)
+#if TCFG_AUDIO_CVP_DUT_ENABLE
+ if (cvp_dut_mode_get() == CVP_DUT_MODE_BYPASS) {
+ esco_mic_en(0, 0, 0, 0, 0, 0);
+ } else
+#endif /*TCFG_AUDIO_CVP_DUT_ENABLE*/
+ {
+ esco_pdm_mic_en(0, 0, 0);
+ }
+#elif (TCFG_AUDIO_ADC_MIC_CHA == ALNK_MIC)
+ esco_iis_mic_en(0, 0, 0);
+#else
+ esco_mic_en(0, 0, 0, 0, 0, 0);
+#endif/*TCFG_AUDIO_ADC_MIC_CH*/
+ audio_encoder_close(&esco_enc->encoder);
+
+
+ free(esco_enc);
+ esco_enc = NULL;
+ if (encode_task) {
+ audio_encoder_task_del(encode_task);
+ free(encode_task);
+ encode_task = NULL;
+ }
+#ifdef CONFIG_BOARD_AISPEECH_VAD_ASR
+ ais_platform_asr_open();
+#endif /*CONFIG_BOARD_AISPEECH_VAD_ASR*/
+}
+
+int esco_enc_mic_gain_set(u8 gain)
+{
+ app_var.aec_mic_gain = gain;
+ if (esco_mic) {
+ printf("esco mic 0 set gain %d\n", app_var.aec_mic_gain);
+ audio_adc_mic_set_gain(&esco_mic->mic_ch, app_var.aec_mic_gain);
+ }
+ return 0;
+}
+int esco_enc_mic1_gain_set(u8 gain)
+{
+ app_var.aec_mic_gain = gain;
+ if (esco_mic) {
+ printf("esco mic 1 set gain %d\n", app_var.aec_mic_gain);
+ audio_adc_mic1_set_gain(&esco_mic->mic_ch, app_var.aec_mic_gain);
+ }
+ return 0;
+}
+int esco_enc_mic2_gain_set(u8 gain)
+{
+ app_var.aec_mic_gain = gain;
+ if (esco_mic) {
+ printf("esco mic 2 set gain %d\n", app_var.aec_mic_gain);
+ audio_adc_mic2_set_gain(&esco_mic->mic_ch, app_var.aec_mic_gain);
+ }
+ return 0;
+}
+int esco_enc_mic3_gain_set(u8 gain)
+{
+ app_var.aec_mic_gain = gain;
+ if (esco_mic) {
+ printf("esco mic 3 set gain %d\n", app_var.aec_mic_gain);
+ audio_adc_mic3_set_gain(&esco_mic->mic_ch, app_var.aec_mic_gain);
+ }
+ return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
+
+#define PCM_ENC2TWS_OUTBUF_LEN (4 * 1024)
+struct pcm2tws_enc_hdl {
+ struct audio_encoder encoder;
+ OS_SEM pcm_frame_sem;
+ s16 output_frame[30]; //align 4Bytes
+ int pcm_frame[60]; //align 4Bytes
+ u8 output_buf[PCM_ENC2TWS_OUTBUF_LEN];
+ cbuffer_t output_cbuf;
+ void (*resume)(void);
+ u32 status : 3;
+ u32 reserved: 29;
+};
+struct pcm2tws_enc_hdl *pcm2tws_enc = NULL;
+
+extern void local_tws_start(u32 coding_type, u32 rate);
+extern void local_tws_stop(void);
+extern int local_tws_resolve(u32 coding_type, u32 rate);
+extern int local_tws_output(s16 *data, int len);
+
+void pcm2tws_enc_close();
+void pcm2tws_enc_resume(void);
+
+int pcm2tws_enc_output(void *priv, s16 *data, int len)
+{
+ if (!pcm2tws_enc) {
+ return 0;
+ }
+ u16 wlen = cbuf_write(&pcm2tws_enc->output_cbuf, data, len);
+ os_sem_post(&pcm2tws_enc->pcm_frame_sem);
+ if (!wlen) {
+ /* putchar(','); */
+ }
+ /* printf("wl:%d ", wlen); */
+ pcm2tws_enc_resume();
+ return wlen;
+}
+
+void pcm2tws_enc_set_resume_handler(void (*resume)(void))
+{
+ if (pcm2tws_enc) {
+ pcm2tws_enc->resume = resume;
+ }
+}
+
+static void pcm2tws_enc_need_data(void)
+{
+ if (pcm2tws_enc && pcm2tws_enc->resume) {
+ pcm2tws_enc->resume();
+ }
+}
+
+static int pcm2tws_enc_pcm_get(struct audio_encoder *encoder, s16 **frame, u16 frame_len)
+{
+ int rlen = 0;
+ if (encoder == NULL) {
+ r_printf("encoder NULL");
+ }
+ struct pcm2tws_enc_hdl *enc = container_of(encoder, struct pcm2tws_enc_hdl, encoder);
+
+ if (enc == NULL) {
+ r_printf("enc NULL");
+ }
+ os_sem_set(&pcm2tws_enc->pcm_frame_sem, 0);
+ /* printf("l:%d", frame_len); */
+
+ do {
+ rlen = cbuf_read(&pcm2tws_enc->output_cbuf, enc->pcm_frame, frame_len);
+ if (rlen == frame_len) {
+ break;
+ }
+ if (rlen == -EINVAL) {
+ return 0;
+ }
+ if (!pcm2tws_enc->status) {
+ return 0;
+ }
+ pcm2tws_enc_need_data();
+ os_sem_pend(&pcm2tws_enc->pcm_frame_sem, 2);
+ } while (1);
+
+ *frame = enc->pcm_frame;
+ return rlen;
+}
+static void pcm2tws_enc_pcm_put(struct audio_encoder *encoder, s16 *frame)
+{
+}
+
+static const struct audio_enc_input pcm2tws_enc_input = {
+ .fget = pcm2tws_enc_pcm_get,
+ .fput = pcm2tws_enc_pcm_put,
+};
+
+static int pcm2tws_enc_probe_handler(struct audio_encoder *encoder)
+{
+ return 0;
+}
+
+static int pcm2tws_enc_output_handler(struct audio_encoder *encoder, u8 *frame, int len)
+{
+ struct pcm2tws_enc_hdl *enc = container_of(encoder, struct pcm2tws_enc_hdl, encoder);
+ local_tws_resolve(encoder->fmt.coding_type, encoder->fmt.sample_rate | (encoder->fmt.channel << 16));
+ int ret = local_tws_output(frame, len);
+ if (!ret) {
+ /* putchar('L'); */
+ } else {
+ /* printf("w:%d ", len); */
+ }
+ return ret;
+}
+
+const static struct audio_enc_handler pcm2tws_enc_handler = {
+ .enc_probe = pcm2tws_enc_probe_handler,
+ .enc_output = pcm2tws_enc_output_handler,
+};
+
+
+
+int pcm2tws_enc_open(u32 codec_type, u32 info)
+{
+ int err;
+ struct audio_fmt fmt;
+ u16 rate = info & 0x0000ffff;
+ u16 channel = (info >> 16) & 0x0f;
+
+ printf("pcm2tws_enc_open: %d\n", codec_type);
+
+ fmt.channel = channel;
+ fmt.sample_rate = rate;
+ fmt.coding_type = codec_type;
+
+ if (!encode_task) {
+ encode_task = zalloc(sizeof(*encode_task));
+ audio_encoder_task_create(encode_task, "audio_enc");
+ }
+ if (pcm2tws_enc) {
+ pcm2tws_enc_close();
+ }
+ pcm2tws_enc = zalloc(sizeof(*pcm2tws_enc));
+
+ os_sem_create(&pcm2tws_enc->pcm_frame_sem, 0);
+
+ cbuf_init(&pcm2tws_enc->output_cbuf, pcm2tws_enc->output_buf, PCM_ENC2TWS_OUTBUF_LEN);
+
+ audio_encoder_open(&pcm2tws_enc->encoder, &pcm2tws_enc_input, encode_task);
+ audio_encoder_set_handler(&pcm2tws_enc->encoder, &pcm2tws_enc_handler);
+ audio_encoder_set_fmt(&pcm2tws_enc->encoder, &fmt);
+ audio_encoder_set_output_buffs(&pcm2tws_enc->encoder, pcm2tws_enc->output_frame,
+ sizeof(pcm2tws_enc->output_frame), 1);
+
+ if (!pcm2tws_enc->encoder.enc_priv) {
+ log_e("encoder err, maybe coding(0x%x) disable \n", fmt.coding_type);
+ err = -EINVAL;
+ goto __err;
+ }
+
+ local_tws_start(pcm2tws_enc->encoder.fmt.coding_type, pcm2tws_enc->encoder.fmt.sample_rate | (pcm2tws_enc->encoder.fmt.channel << 16));
+
+ pcm2tws_enc->status = 1;
+
+ audio_encoder_start(&pcm2tws_enc->encoder);
+
+ printf("sample_rate: %d\n", fmt.sample_rate);
+
+ return 0;
+__err:
+ audio_encoder_close(&pcm2tws_enc->encoder);
+
+ local_irq_disable();
+ free(pcm2tws_enc);
+ pcm2tws_enc = NULL;
+ local_irq_enable();
+
+ return err;
+}
+
+void pcm2tws_enc_close()
+{
+ if (!pcm2tws_enc) {
+ return;
+ }
+ pcm2tws_enc->status = 0;
+ printf("pcm2tws_enc_close");
+ local_tws_stop();
+ audio_encoder_close(&pcm2tws_enc->encoder);
+ free(pcm2tws_enc);
+ pcm2tws_enc = NULL;
+ if (encode_task) {
+ audio_encoder_task_del(encode_task);
+ free(encode_task);
+ encode_task = NULL;
+ }
+}
+
+void pcm2tws_enc_resume(void)
+{
+ if (pcm2tws_enc && pcm2tws_enc->status) {
+ audio_encoder_resume(&pcm2tws_enc->encoder);
+ }
+}
+
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+int audio_enc_init()
+{
+ printf("audio_enc_init\n");
+
+ audio_adc_init(&adc_hdl, &adc_data);
+#if TCFG_AUDIO_CVP_DUT_ENABLE
+ cvp_dut_init();
+#endif /*TCFG_AUDIO_CVP_DUT_ENABLE*/
+ return 0;
+}
+
diff --git a/cpu/br28/audio_enc.h b/cpu/br28/audio_enc.h
new file mode 100644
index 0000000..31dfd7e
--- /dev/null
+++ b/cpu/br28/audio_enc.h
@@ -0,0 +1,29 @@
+#ifndef _AUDIO_ENC_H_
+#define _AUDIO_ENC_H_
+
+#include "generic/typedef.h"
+
+enum enc_source {
+ ENCODE_SOURCE_MIX = 0x0,
+ ENCODE_SOURCE_MIC,
+ ENCODE_SOURCE_LINE0_LR,
+ ENCODE_SOURCE_LINE1_LR,
+ ENCODE_SOURCE_LINE2_LR,
+ ENCODE_SOURCE_USER,
+};
+
+enum {
+ MIC_PWR_INIT = 1, /*开机状态*/
+ MIC_PWR_ON, /*工作状态*/
+ MIC_PWR_OFF, /*空闲状态*/
+ MIC_PWR_DOWN, /*低功耗状态*/
+
+};
+
+int esco_enc_open(u32 coding_type, u8 frame_len);
+void esco_enc_close();
+void audio_mic_pwr_ctl(u8 state);
+u8 get_master_mic_gain(u8 master);
+void esco_mic_reset(void);
+void esco_mic_cfg_set(u16 sr, u16 mic0_gain, u16 mic1_gain, u16 mic2_gain, u16 mic3_gain);
+#endif/*_AUDIO_ENC_H_*/
diff --git a/cpu/br28/audio_general.c b/cpu/br28/audio_general.c
new file mode 100644
index 0000000..8d2ed0b
--- /dev/null
+++ b/cpu/br28/audio_general.c
@@ -0,0 +1,46 @@
+/*
+ ****************************************************************
+ * AUDIO General APIs
+ * Brief : 实现一些依赖CPU的通用接口,适配所有case
+ * Notes :
+ ****************************************************************
+ */
+#include "system/includes.h"
+#include "media/includes.h"
+#include "audio_config.h"
+
+void audio_adda_dump(void) //打印所有的dac,adc寄存器
+{
+ printf("JL_WL_AUD CON0:%x", JL_WL_AUD->CON0);
+ printf("AUD_CON:%x", JL_AUDIO->AUD_CON);
+ printf("DAC_CON:%x", JL_AUDIO->DAC_CON);
+ printf("ADC_CON:%x", JL_AUDIO->ADC_CON);
+ printf("ADC_CON1:%x", JL_AUDIO->ADC_CON1);
+ printf("DAC_TM0:%x", JL_AUDIO->DAC_TM0);
+ printf("DAA_CON 0:%x 1:%x, 2:%x, 3:%x 4:%x\n", JL_ADDA->DAA_CON0, JL_ADDA->DAA_CON1, JL_ADDA->DAA_CON2, JL_ADDA->DAA_CON3, JL_ADDA->DAA_CON4);
+ printf("ADA_CON 0:%x 1:%x 2:%x 3:%x 4:%x 5:%x\n", JL_ADDA->ADA_CON0, JL_ADDA->ADA_CON1, JL_ADDA->ADA_CON2, JL_ADDA->ADA_CON3, JL_ADDA->ADA_CON4, JL_ADDA->ADA_CON5);
+}
+
+void audio_gain_dump(void)
+{
+ int dac_again_max = 7;
+ u8 dac_again_l = JL_ADDA->DAA_CON1 & 0xF;
+ u8 dac_again_r = (JL_ADDA->DAA_CON1 >> 4) & 0xF;
+ int dac_dgain_max = 16384;
+ u32 dac_dgain_l = JL_AUDIO->DAC_VL0 & 0xFFFF;
+ u32 dac_dgain_r = (JL_AUDIO->DAC_VL0 >> 16) & 0xFFFF;
+
+ u8 mic0_0_6 = (JL_ADDA->ADA_CON4) & 0x1;
+ u8 mic1_0_6 = (JL_ADDA->ADA_CON5) & 0x1;
+ u8 mic2_0_6 = (JL_ADDA->ADA_CON6) & 0x1;
+ u8 mic3_0_6 = (JL_ADDA->ADA_CON7) & 0x1;
+
+ u8 mic0_gain = JL_ADDA->ADA_CON8 & 0x1F;
+ u8 mic1_gain = (JL_ADDA->ADA_CON8 >> 5) & 0x1F;
+ u8 mic2_gain = (JL_ADDA->ADA_CON8 >> 10) & 0x1F;
+ u8 mic3_gain = (JL_ADDA->ADA_CON8 >> 15) & 0x1F;
+
+ printf("L Mute:%d ,R Mute:%d\n", (JL_ADDA->DAA_CON2 >> 1) & 0x1, (JL_ADDA->DAA_CON2 >> 11) & 0x1); //PA MUTE
+ printf("MIC_G:%d,%d,%d,%d,MIC_6dB_EN:%d,%d,%d,%d,DAC_AG_MAX:%d,DAC_AG:%d,%d,DAC_DG_MAX:%d,DAC_DG:%d,%d\n", mic0_gain, mic1_gain, mic2_gain, mic3_gain, mic0_0_6, mic1_0_6, mic2_0_6, mic3_0_6, dac_again_max, dac_again_l, dac_again_r, dac_dgain_max, dac_dgain_l, dac_dgain_r);
+
+}
diff --git a/cpu/br28/audio_iis.c b/cpu/br28/audio_iis.c
new file mode 100644
index 0000000..bd31d5b
--- /dev/null
+++ b/cpu/br28/audio_iis.c
@@ -0,0 +1,543 @@
+
+#define IIS_TX_MIN_PNS (JL_ALNK0->LEN / 4)
+struct audio_iis_sync_node {
+ void *hdl;
+ struct list_head entry;
+};
+/***********************************************************
+ * i2s 使用接口
+ *
+ ***********************************************************/
+int audio_iis_buffered_frames(struct audio_iis_hdl *iis)
+{
+ return (JL_ALNK0->LEN - *ALNK0_SHN[iis->hw_ch] - 1);
+}
+
+int audio_iis_buffered_time(struct audio_iis_hdl *iis)
+{
+ if (!iis) {
+ return 0;
+ }
+
+ int buffered_time = ((audio_iis_buffered_frames(iis) * 1000000) / iis->sample_rate) / 1000;
+
+ return buffered_time;
+}
+
+int audio_iis_set_underrun_params(struct audio_iis_hdl *iis, int time, void *priv, void (*feedback)(void *))
+{
+ local_irq_disable();
+ iis->underrun_time = time;
+ iis->underrun_pns = 0;
+ iis->underrun_data = priv;
+ iis->underrun_feedback = feedback;
+ local_irq_enable();
+
+ return 0;
+}
+
+void audio_iis_syncts_update_frame(struct audio_iis_hdl *iis)
+{
+ struct audio_iis_sync_node *node;
+ list_for_each_entry(node, &iis->sync_list, entry) {
+ sound_pcm_enter_update_frame(node->hdl);
+ }
+}
+
+void audio_iis_syncts_latch_trigger(struct audio_iis_hdl *iis)
+{
+ struct audio_iis_sync_node *node;
+
+ list_for_each_entry(node, &iis->sync_list, entry) {
+ sound_pcm_syncts_latch_trigger(node->hdl);
+ }
+}
+
+
+void audio_iis_dma_update_to_syncts(struct audio_iis_hdl *iis, int frames)
+{
+ struct audio_iis_sync_node *node;
+ u8 have_syncts = 0;
+
+ list_for_each_entry(node, &iis->sync_list, entry) {
+ sound_pcm_update_frame_num(node->hdl, frames);
+ have_syncts = 1;
+ }
+
+ if (have_syncts) {
+ u16 free_points = *ALNK0_SHN[iis->hw_ch];
+ int timeout = (1000000 / iis->sample_rate) * (clk_get("sys") / 1000000);
+ while (free_points == *ALNK0_SHN[iis->hw_ch] && (--timeout > 0));
+ }
+}
+
+void audio_iis_add_syncts_handle(struct audio_iis_hdl *iis, void *syncts)
+{
+ struct audio_iis_sync_node *node = (struct audio_iis_sync_node *)zalloc(sizeof(struct audio_iis_sync_node));
+ node->hdl = syncts;
+
+ list_add(&node->entry, &iis->sync_list);
+
+ if (iis->state == SOUND_PCM_STATE_RUNNING) {
+ sound_pcm_syncts_latch_trigger(syncts);
+ }
+ ALINK_DA2BTSRC_SEL(ALINK0, iis->hw_ch);
+}
+
+void audio_iis_remove_syncts_handle(struct audio_iis_hdl *iis, void *syncts)
+{
+ struct audio_iis_sync_node *node;
+
+ list_for_each_entry(node, &iis->sync_list, entry) {
+ if (node->hdl == syncts) {
+ goto remove_node;
+ }
+ }
+
+ return;
+remove_node:
+
+ list_del(&node->entry);
+ free(node);
+}
+
+static void audio_iis_tx_irq_handler(struct audio_iis_hdl *iis)
+{
+ if (iis->irq_trigger && iis->trigger_handler) {
+ iis->trigger_handler(iis->trigger_data);
+ iis->irq_trigger = 0;
+ }
+
+ if (iis->underrun_pns) {
+ int unread_frames = JL_ALNK0->LEN - *ALNK0_SHN[iis->hw_ch] - 1;
+ if (unread_frames <= iis->underrun_pns) {
+ //TODO
+ } else {
+ ALINK_OPNS_SET(ALINK0, iis->underrun_pns);
+ ALINK_CLR_CHx_PND(ALINK0, iis->hw_ch);
+ return;
+ }
+ }
+
+ ALINK_CHx_IE(ALINK0, iis->hw_ch, 0);
+ ALINK_CLR_CHx_PND(ALINK0, iis->hw_ch);
+}
+
+extern ALINK_PARM alink0_platform_data;
+int audio_iis_pcm_tx_open(struct audio_iis_hdl *iis, u8 ch, int sample_rate)
+{
+ memset(iis, 0x0, sizeof(struct audio_iis_hdl));
+ INIT_LIST_HEAD(&iis->sync_list);
+ iis->state = SOUND_PCM_STATE_IDLE;
+ iis->sample_rate = sample_rate;
+ iis->alink0_param = alink_init(&alink0_platform_data);
+ alink_channel_init(iis->alink0_param, ch, ALINK_DIR_TX, iis, audio_iis_tx_irq_handler);
+ /*alink_start();*/
+ iis->hw_ch = ch;
+}
+
+void audio_iis_pcm_tx_close(struct audio_iis_hdl *iis)
+{
+ alink_channel_close(iis->hw_ch);
+ iis->state = SOUND_PCM_STATE_IDLE;
+}
+
+int audio_iis_pcm_sample_rate(struct audio_iis_hdl *iis)
+{
+ return iis->sample_rate;
+}
+
+int audio_iis_set_delay_time(struct audio_iis_hdl *iis, int prepared_time, int delay_time)
+{
+ iis->prepared_time = prepared_time;
+ iis->delay_time = delay_time;
+ return 0;
+}
+
+int audio_iis_pcm_remapping(struct audio_iis_hdl *iis, u8 mapping)
+{
+ if (!iis->input_mapping) {
+ iis->input_mapping = mapping;
+ }
+ if ((iis->input_mapping & SOUND_CHMAP_RL) || (iis->input_mapping & SOUND_CHMAP_RR)) {
+ printf("Not support this channel map : 0x%x\n", mapping);
+ }
+ return 0;
+}
+
+int audio_iis_pcm_channel_num(struct audio_iis_hdl *iis)
+{
+ int num = 0;
+ for (int i = 0; i < 2; i++) {
+ if (iis->input_mapping & BIT(i)) {
+ num++;
+ }
+ }
+ return num;
+}
+
+#if 0
+const unsigned char sin44K[88] ALIGNED(4) = {
+ 0x00, 0x00, 0x45, 0x0E, 0x41, 0x1C, 0xAA, 0x29, 0x3B, 0x36, 0xB2, 0x41, 0xD5, 0x4B, 0x6E, 0x54,
+ 0x51, 0x5B, 0x5A, 0x60, 0x70, 0x63, 0x82, 0x64, 0x8A, 0x63, 0x8E, 0x60, 0x9D, 0x5B, 0xD1, 0x54,
+ 0x4D, 0x4C, 0x3D, 0x42, 0xD5, 0x36, 0x50, 0x2A, 0xF1, 0x1C, 0xFB, 0x0E, 0xB7, 0x00, 0x70, 0xF2,
+ 0x6E, 0xE4, 0xFD, 0xD6, 0x60, 0xCA, 0xD9, 0xBE, 0xA5, 0xB4, 0xF7, 0xAB, 0xFC, 0xA4, 0xDA, 0x9F,
+ 0xAB, 0x9C, 0x7F, 0x9B, 0x5E, 0x9C, 0x3F, 0x9F, 0x19, 0xA4, 0xCE, 0xAA, 0x3D, 0xB3, 0x3A, 0xBD,
+ 0x92, 0xC8, 0x0A, 0xD5, 0x60, 0xE2, 0x50, 0xF0
+};
+
+int read_44k_sine_data(void *buf, int bytes, int offset, u8 channel)
+{
+ s16 *sine = (s16 *)sin44K;
+ s16 *data = (s16 *)buf;
+ int frame_len = (bytes >> 1) / channel;
+ int sin44k_frame_len = sizeof(sin44K) / 2;
+ int i, j;
+
+ offset = offset % sin44k_frame_len;
+
+ for (i = 0; i < frame_len; i++) {
+ for (j = 0; j < channel; j++) {
+ *data++ = sine[offset];
+ }
+ if (++offset >= sin44k_frame_len) {
+ offset = 0;
+ }
+ }
+
+ return i * 2 * channel;
+}
+static int frames_offset = 0;
+#endif
+
+static int __audio_iis_pcm_write(s16 *dst, s16 *src, int frames, int remapping)
+{
+
+ /* int frame_bytes = read_44k_sine_data(dst, frames * 2 * 2, frames_offset, 2); */
+ /* putchar('k'); */
+ /* frames_offset += (frame_bytes >> 1) / 2; */
+ /* return frame_bytes; */
+
+ if (remapping == 1) {
+ for (int i = 0; i < frames; i++) {
+ dst[i * 2] = src[i];
+ dst[i * 2 + 1] = src[i];
+ }
+ return frames << 1;
+ }
+
+ if (remapping == 2) {
+ memcpy(dst, src, (frames << 1) * 2);
+ return frames << 2;
+ }
+
+ return frames;
+}
+
+#define CVP_REF_SRC_ENABLE
+#ifdef CVP_REF_SRC_ENABLE
+#define CVP_REF_SRC_TASK_NAME "RefSrcTask"
+#include "Resample_api.h"
+#include "aec_user.h"
+
+#define CVP_REF_SRC_FRAME_SIZE 512
+typedef struct {
+ volatile u8 state;
+ volatile u8 busy;
+ RS_STUCT_API *sw_src_api;
+ u8 *sw_src_buf;
+ u16 input_rate;
+ u16 output_rate;
+ s16 ref_tmp_buf[CVP_REF_SRC_FRAME_SIZE / 2];
+ cbuffer_t cbuf;
+ u8 ref_buf[CVP_REF_SRC_FRAME_SIZE * 3];
+} aec_ref_src_t;
+static aec_ref_src_t *aec_ref_src = NULL;
+
+extern void audio_aec_ref_src_get_output_rate(u16 *input_rate, u16 *output_rate);
+extern u8 bt_phone_dec_is_running();
+
+extern struct audio_iis_hdl iis_hdl;
+void audio_aec_ref_src_run(s16 *data, int len)
+{
+ u16 ref_len = 0;
+ if (aec_ref_src) {
+ if (iis_hdl.input_mapping != SOUND_CHMAP_MONO) {
+ /*双变单*/
+ for (int i = 0; i < (len >> 2); i++) {
+ aec_ref_src->ref_tmp_buf[i] = data[2 * i];
+ }
+ len >>= 1;
+ }
+ /* audio_aec_ref_src_get_output_rate(&aec_ref_src->input_rate, &aec_ref_src->output_rate); */
+ /* printf("%d %d \n",input_rate,output_rate); */
+ if (aec_ref_src->sw_src_api) {
+ /* aec_ref_src->sw_src_api->set_sr(aec_ref_src->sw_src_buf, aec_ref_src->output_rate); */
+ ref_len = aec_ref_src->sw_src_api->run(aec_ref_src->sw_src_buf, aec_ref_src->ref_tmp_buf, len >> 1, aec_ref_src->ref_tmp_buf);
+ ref_len <<= 1;
+ }
+ /* printf("ref_len %d", ref_len); */
+ audio_aec_refbuf(aec_ref_src->ref_tmp_buf, ref_len);
+ }
+}
+
+static void audio_aec_ref_src_task(void *p)
+{
+ int res;
+ int msg[16];
+ while (1) {
+
+ res = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
+
+ if (aec_ref_src && aec_ref_src->state) {
+ s16 *data = (int)msg[1];
+ int len = msg[2];
+ int rlen = 0;
+
+ aec_ref_src->busy = 1;
+ if (cbuf_get_data_len(&aec_ref_src->cbuf) >= CVP_REF_SRC_FRAME_SIZE) {
+ cbuf_read(&aec_ref_src->cbuf, aec_ref_src->ref_tmp_buf, CVP_REF_SRC_FRAME_SIZE);
+ audio_aec_ref_src_run(aec_ref_src->ref_tmp_buf, CVP_REF_SRC_FRAME_SIZE);
+ }
+ aec_ref_src->busy = 0;
+ }
+ }
+}
+
+int audio_aec_ref_src_data_fill(void *p, s16 *data, int len)
+{
+ int ret = 0;
+ if (aec_ref_src && aec_ref_src->state) {
+ audio_aec_ref_start(1);
+ if (0 == cbuf_write(&aec_ref_src->cbuf, data, len)) {
+ /* cbuf_clear(&aec_ref_src->cbuf); */
+ printf("ref src cbuf wfail!!");
+ }
+ if (cbuf_get_data_len(&aec_ref_src->cbuf) >= CVP_REF_SRC_FRAME_SIZE) {
+ ret = os_taskq_post_msg(CVP_REF_SRC_TASK_NAME, 2, (int)data, len);
+ }
+ }
+ return ret;
+}
+
+int audio_aec_ref_src_open(u32 insr, u32 outsr)
+{
+ if (aec_ref_src) {
+ printf("aec_ref_src alreadly open !!!");
+ return -1;
+ }
+ aec_ref_src = zalloc(sizeof(aec_ref_src_t));
+ if (aec_ref_src == NULL) {
+ printf("aec_ref_src malloc fail !!!");
+ return -1;
+ }
+
+ cbuf_init(&aec_ref_src->cbuf, aec_ref_src->ref_buf, sizeof(aec_ref_src->ref_buf));
+ int err = os_task_create(audio_aec_ref_src_task, NULL, 4, 256, 128, CVP_REF_SRC_TASK_NAME);
+ if (err != OS_NO_ERR) {
+ printf("task create error!");
+ free(aec_ref_src);
+ aec_ref_src = NULL;
+ return -1;
+ }
+
+ /* audio_aec_ref_src_get_output_rate(&aec_ref_src->input_rate, &aec_ref_src->output_rate); */
+ aec_ref_src->input_rate = insr;
+ aec_ref_src->output_rate = outsr;
+ aec_ref_src->sw_src_api = get_rs16_context();
+ printf("sw_src_api:0x%x\n", aec_ref_src->sw_src_api);
+ ASSERT(aec_ref_src->sw_src_api);
+ int sw_src_need_buf = aec_ref_src->sw_src_api->need_buf();
+ printf("sw_src_buf:%d\n", sw_src_need_buf);
+ aec_ref_src->sw_src_buf = zalloc(sw_src_need_buf);
+ ASSERT(aec_ref_src->sw_src_buf, "sw_src_buf zalloc fail");
+ RS_PARA_STRUCT rs_para_obj;
+ rs_para_obj.nch = 1;
+ if (insr == 44100) {
+ rs_para_obj.new_insample = 44117;
+ } else {
+ rs_para_obj.new_insample = insr;
+ }
+ rs_para_obj.new_outsample = outsr;
+ printf("sw src,ch = %d, in = %d,out = %d\n", rs_para_obj.nch, rs_para_obj.new_insample, rs_para_obj.new_outsample);
+ aec_ref_src->sw_src_api->open(aec_ref_src->sw_src_buf, &rs_para_obj);
+
+ aec_ref_src->state = 1;
+ return 0;
+}
+
+void audio_aec_ref_src_close()
+{
+ if (aec_ref_src) {
+ aec_ref_src->state = 0;
+ while (aec_ref_src->busy) {
+ putchar('w');
+ os_time_dly(1);
+ }
+ int err = os_task_del(CVP_REF_SRC_TASK_NAME);
+ if (err) {
+ log_i("kill task %s: err=%d\n", CVP_REF_SRC_TASK_NAME, err);
+ }
+ if (aec_ref_src->sw_src_api) {
+ aec_ref_src->sw_src_api = NULL;
+ }
+ if (aec_ref_src->sw_src_buf) {
+ free(aec_ref_src->sw_src_buf);
+ aec_ref_src->sw_src_buf = NULL;
+ }
+ free(aec_ref_src);
+ aec_ref_src = NULL;
+ }
+}
+#endif/*CVP_REF_SRC_ENABLE*/
+
+int audio_iis_pcm_write(struct audio_iis_hdl *iis, void *data, int len)
+{
+ if (iis->state != SOUND_PCM_STATE_RUNNING) {
+ return 0;
+ }
+ int remapping_ch = 2;
+ int frames = 0;
+ if (iis->input_mapping == SOUND_CHMAP_MONO) {
+ frames = len >> 1;
+ remapping_ch = 1;
+ } else if (iis->input_mapping & SOUND_CHMAP_FR) {
+ frames = len >> 2;
+ remapping_ch = 2;
+ } else {
+
+ }
+
+ s16 *ref_data = (s16 *)data;
+ int swp = *ALNK0_SWPTR[iis->hw_ch];
+ int free_frames = *ALNK0_SHN[iis->hw_ch] - iis->reserved_frames;
+
+ /* printf("free : %d, %d\n", *ALNK0_SHN[iis->hw_ch], free_frames); */
+ if (free_frames <= 0) {
+ return 0;
+ }
+
+ if (free_frames > frames) {
+ free_frames = frames;
+ }
+
+ frames = 0;
+ if (swp + free_frames > JL_ALNK0->LEN) {
+ frames = JL_ALNK0->LEN - swp;
+ __audio_iis_pcm_write((s16 *)(*ALNK0_BUF_ADR[iis->hw_ch] + swp * 2 * 2), (s16 *)data, frames, remapping_ch);
+ free_frames -= frames;
+ data = (s16 *)data + frames * remapping_ch;
+ swp = 0;
+ }
+
+ __audio_iis_pcm_write((s16 *)(*ALNK0_BUF_ADR[iis->hw_ch] + swp * 2 * 2), (s16 *)data, free_frames, remapping_ch);
+ frames += free_frames;
+
+ audio_iis_syncts_update_frame(iis);
+ *ALNK0_SHN[iis->hw_ch] = frames;
+ __asm_csync();
+ audio_iis_dma_update_to_syncts(iis, frames);
+
+ /*printf("frames : %d\n", frames);*/
+ /*printf("CLK CON2 : %d, %d\n", JL_CLOCK->CLK_CON2 & 0x3, (JL_CLOCK->CLK_CON2 >> 2) & 0x3);*/
+
+#ifdef CVP_REF_SRC_ENABLE
+ if (bt_phone_dec_is_running()) {
+ audio_aec_ref_src_data_fill(iis, ref_data, (frames << 1) * remapping_ch);
+ }
+#endif
+ return (frames << 1) * remapping_ch;
+}
+
+static void audio_iis_dma_fifo_start(struct audio_iis_hdl *iis)
+{
+ if (iis->state != SOUND_PCM_STATE_PREPARED) {
+ return;
+ }
+
+ if (iis->prepared_frames) {
+ *ALNK0_SHN[iis->hw_ch] = iis->prepared_frames;
+ __asm_csync();
+ }
+
+ local_irq_disable();
+ iis->state = SOUND_PCM_STATE_RUNNING;
+ ALINK_CHx_IE(ALINK0, iis->hw_ch, 1);
+ ALINK_CLR_CHx_PND(ALINK0, iis->hw_ch);
+ local_irq_enable();
+ audio_iis_syncts_latch_trigger(iis);
+}
+
+static int audio_iis_fifo_set_delay(struct audio_iis_hdl *iis)
+{
+ iis->prepared_frames = iis->prepared_time * iis->sample_rate / 1000;
+ int delay_frames = (iis->delay_time * iis->sample_rate) / 1000 / 2 * 2;
+ if (iis->prepared_frames >= JL_ALNK0->LEN) {
+ iis->prepared_frames = JL_ALNK0->LEN / 2;
+ }
+ if (delay_frames < JL_ALNK0->LEN) {
+ iis->reserved_frames = JL_ALNK0->LEN - delay_frames;
+ } else {
+ iis->reserved_frames = 0;
+ }
+ return 0;
+}
+
+int audio_iis_trigger_interrupt(struct audio_iis_hdl *iis, int time_ms, void *priv, void (*callback)(void *))
+{
+ if (iis->state != SOUND_PCM_STATE_RUNNING) {
+ return -EINVAL;
+ }
+
+ int irq_frames = time_ms * iis->sample_rate / 1000;
+ int pns = audio_iis_buffered_frames(iis) - irq_frames;
+ if (pns < irq_frames) {
+ sys_hi_timeout_add(priv, callback, time_ms);
+ return -EINVAL;
+ }
+ local_irq_disable();
+ if (pns > ALINK_OPNS(ALINK0)) {
+ ALINK_OPNS_SET(ALINK0, pns);
+ }
+
+ iis->irq_trigger = 1;
+ iis->trigger_handler = callback;
+ iis->trigger_data = priv;
+ ALINK_CHx_IE(ALINK0, iis->hw_ch, 1);
+ local_irq_enable();
+
+ return 0;
+}
+
+int audio_iis_dma_start(struct audio_iis_hdl *iis)
+{
+ if (iis->state == SOUND_PCM_STATE_RUNNING) {
+ return 0;
+ }
+
+ audio_iis_fifo_set_delay(iis);
+ iis->underrun_pns = iis->underrun_time ? (iis->underrun_time * iis->sample_rate / 1000) : 0;
+ ALINK_OPNS_SET(ALINK0, (iis->underrun_pns ? iis->underrun_pns : IIS_TX_MIN_PNS));
+ iis->state = SOUND_PCM_STATE_PREPARED;
+ /* printf("DMA : %d, %d, %d\n", *ALNK0_SHN[iis->hw_ch], *ALNK0_SWPTR[iis->hw_ch], *ALNK0_HWPTR[iis->hw_ch]); */
+ audio_iis_dma_fifo_start(iis);
+ alink_start(iis->alink0_param);
+ /* printf("[iis dma start]... %d, free : %d, prepared_frames : %d, reserved_frames : %d\n", JL_ALNK0->LEN, *ALNK0_SHN[iis->hw_ch], iis->prepared_frames, iis->reserved_frames); */
+}
+
+int audio_iis_dma_stop(struct audio_iis_hdl *iis)
+{
+ if (iis->state != SOUND_PCM_STATE_RUNNING) {
+ return 0;
+ }
+ /*audio_iis_buffered_frames_fade_out(iis, JL_ALNK0->LEN - *ALNK0_SHN[iis->hw_ch] - 1);*/
+ ALINK_CHx_IE(ALINK0, iis->hw_ch, 0);
+ ALINK_CLR_CHx_PND(ALINK0, iis->hw_ch);
+ /* alink_uninit(iis->alink0_param); */
+
+ iis->input_mapping = 0;
+ iis->state = SOUND_PCM_STATE_SUSPENDED;
+ return 0;
+}
+
+
diff --git a/cpu/br28/audio_iis.h b/cpu/br28/audio_iis.h
new file mode 100644
index 0000000..89c61be
--- /dev/null
+++ b/cpu/br28/audio_iis.h
@@ -0,0 +1,68 @@
+/*****************************************************************
+>file name : audio_iis.h
+>create time : Fri 25 Feb 2022 04:35:37 PM CST
+*****************************************************************/
+#ifndef _AUDIO_IIS_H_
+#define _AUDIO_IIS_H_
+#include "system/includes.h"
+#include "sound/pcm.h"
+#include "asm/iis.h"
+#include "audio_link.h"
+
+struct audio_iis_hdl {
+ u8 state;
+ u8 hw_ch;
+ u8 irq_trigger;
+ u8 input_mapping;
+ short delay_time;
+ short prepared_time;
+ short prepared_frames;
+ short reserved_frames;
+ short underrun_time;
+ short underrun_pns;
+ void *underrun_data;
+ void (*underrun_feedback)(void *);
+ void *trigger_data;
+ void (*trigger_handler)(void *);
+ int sample_rate;
+ struct list_head sync_list;
+ ALINK_PARM *alink0_param;
+};
+
+int audio_iis_pcm_tx_open(struct audio_iis_hdl *iis, u8 ch, int smaple_rate);
+
+void audio_iis_pcm_tx_close(struct audio_iis_hdl *iis);
+
+int audio_iis_pcm_remapping(struct audio_iis_hdl *iis, u8 mapping);
+
+int audio_iis_pcm_write(struct audio_iis_hdl *iis, void *data, int len);
+
+int audio_iis_dma_start(struct audio_iis_hdl *iis);
+
+int audio_iis_dma_stop(struct audio_iis_hdl *iis);
+
+int audio_iis_set_delay_time(struct audio_iis_hdl *iis, int prepared_time, int delay_time);
+
+int audio_iis_set_underrun_params(struct audio_iis_hdl *iis, int time, void *priv, void (*feedback)(void *));
+
+int audio_iis_trigger_interrupt(struct audio_iis_hdl *iis, int time, void *priv, void (*callback)(void *));
+
+void audio_iis_add_syncts_handle(struct audio_iis_hdl *iis, void *syncts);
+
+void audio_iis_remove_syncts_handle(struct audio_iis_hdl *iis, void *syncts);
+
+void audio_iis_syncts_update_frame(struct audio_iis_hdl *iis);
+
+int audio_iis_buffered_frames(struct audio_iis_hdl *iis);
+
+int audio_iis_buffered_time(struct audio_iis_hdl *iis);
+
+int audio_iis_pcm_channel_num(struct audio_iis_hdl *iis);
+
+int audio_iis_pcm_sample_rate(struct audio_iis_hdl *iis);
+
+int audio_aec_ref_src_data_fill(void *p, s16 *data, int len);
+int audio_aec_ref_src_open(u32 insr, u32 outsr);
+void audio_aec_ref_src_close();
+#endif
+
diff --git a/cpu/br28/audio_link.c b/cpu/br28/audio_link.c
new file mode 100644
index 0000000..ed41f66
--- /dev/null
+++ b/cpu/br28/audio_link.c
@@ -0,0 +1,808 @@
+/*****************************************************************
+>file name : lib/media/cpu/br22/audio_link.c
+>author :
+>create time : Fri 7 Dec 2018 14:59:12 PM CST
+*****************************************************************/
+#include "includes.h"
+#include "asm/includes.h"
+#include "media/includes.h"
+#include "system/includes.h"
+#include "asm/clock.h"
+#include "asm/iis.h"
+#include "audio_link.h"
+#include "app_config.h"
+#include "update.h"
+#include "audio_syncts.h"
+#include "audio_iis.h"
+#include "sound/sound.h"
+
+/* #if TCFG_AUDIO_INPUT_IIS || TCFG_AUDIO_OUTPUT_IIS */
+#define ALINK_TEST_ENABLE 0
+
+#define ALINK_DEBUG_INFO
+#ifdef ALINK_DEBUG_INFO
+#define alink_printf printf
+#else
+#define alink_printf(...)
+#endif
+
+static void alink0_info_dump();
+static u32 *ALNK0_BUF_ADR[] = {
+ (u32 *)(&(JL_ALNK0->ADR0)),
+ (u32 *)(&(JL_ALNK0->ADR1)),
+ (u32 *)(&(JL_ALNK0->ADR2)),
+ (u32 *)(&(JL_ALNK0->ADR3)),
+};
+
+static u32 *ALNK0_HWPTR[] = {
+ (u32 *)(&(JL_ALNK0->HWPTR0)),
+ (u32 *)(&(JL_ALNK0->HWPTR1)),
+ (u32 *)(&(JL_ALNK0->HWPTR2)),
+ (u32 *)(&(JL_ALNK0->HWPTR3)),
+};
+
+static u32 *ALNK0_SWPTR[] = {
+ (u32 *)(&(JL_ALNK0->SWPTR0)),
+ (u32 *)(&(JL_ALNK0->SWPTR1)),
+ (u32 *)(&(JL_ALNK0->SWPTR2)),
+ (u32 *)(&(JL_ALNK0->SWPTR3)),
+};
+
+static u32 *ALNK0_SHN[] = {
+ (u32 *)(&(JL_ALNK0->SHN0)),
+ (u32 *)(&(JL_ALNK0->SHN1)),
+ (u32 *)(&(JL_ALNK0->SHN2)),
+ (u32 *)(&(JL_ALNK0->SHN3)),
+};
+
+static u32 PFI_ALNK0_DAT[] = {
+ PFI_ALNK0_DAT0,
+ PFI_ALNK0_DAT1,
+ PFI_ALNK0_DAT2,
+ PFI_ALNK0_DAT3,
+};
+
+static u32 FO_ALNK0_DAT[] = {
+ FO_ALNK0_DAT0,
+ FO_ALNK0_DAT1,
+ FO_ALNK0_DAT2,
+ FO_ALNK0_DAT3,
+};
+
+
+enum {
+ MCLK_11M2896K = 0,
+ MCLK_12M288K
+};
+
+enum {
+ MCLK_EXTERNAL = 0u,
+ MCLK_SYS_CLK ,
+ MCLK_OSC_CLK ,
+ MCLK_PLL_CLK ,
+};
+
+enum {
+ MCLK_DIV_1 = 0u,
+ MCLK_DIV_2 ,
+ MCLK_DIV_4 ,
+ MCLK_DIV_8 ,
+ MCLK_DIV_16 ,
+};
+
+enum {
+ MCLK_LRDIV_EX = 0u,
+ MCLK_LRDIV_64FS ,
+ MCLK_LRDIV_128FS ,
+ MCLK_LRDIV_192FS ,
+ MCLK_LRDIV_256FS ,
+ MCLK_LRDIV_384FS ,
+ MCLK_LRDIV_512FS ,
+ MCLK_LRDIV_768FS ,
+};
+#ifndef TCFG_IIS_SR
+#define TCFG_IIS_SR 44100
+#endif
+
+extern u32 clock_get_pll_target_frequency();
+u32 audio_iis_hw_rates_match(u32 sr)
+{
+ u8 i = 0;
+ u32 pll_tar = clock_get_pll_target_frequency();
+ if (pll_tar == 240) {
+ u32 hw_rates[] = {ALINK_SR_48000, ALINK_SR_44100, ALINK_SR_32000, ALINK_SR_24000, ALINK_SR_22050, ALINK_SR_16000, ALINK_SR_12000, ALINK_SR_11025, ALINK_SR_8000};
+ for (i = 0; i < ARRAY_SIZE(hw_rates); i++) {
+ if (hw_rates[i] == sr) {
+ log_i("match sr %d\n", sr);
+ return sr;
+ }
+ }
+ } else {
+ u32 hw_rates[] = {ALINK_SR_44100, ALINK_SR_22050, ALINK_SR_11025};
+ for (i = 0; i < ARRAY_SIZE(hw_rates); i++) {
+ if (hw_rates[i] == sr) {
+ log_i("match sr %d\n", sr);
+ return sr;
+ }
+ }
+ }
+ log_e("not match is hw sr %d\n", sr);
+ return TCFG_IIS_SR;
+}
+
+
+static ALINK_PARM *p_alink0_parm = NULL;
+
+u32 alink_get_addr(void *hw_channel)
+{
+ struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
+ u32 buf_addr = 0;
+ buf_addr = *ALNK0_BUF_ADR[hw_channel_parm->ch_idx];
+ return buf_addr;
+}
+
+u32 alink_get_shn(void *hw_channel)
+{
+ struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
+ int shn = 0;
+ shn = *ALNK0_SHN[hw_channel_parm->ch_idx];
+ return shn;
+}
+
+void alink_set_shn(void *hw_channel, u32 len)
+{
+ struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
+ if (len) {
+ *ALNK0_SHN[hw_channel_parm->ch_idx] = len;
+ }
+}
+
+u32 alink_get_swptr(void *hw_channel)
+{
+ struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
+ int swptr = 0;
+ swptr = *ALNK0_SWPTR[hw_channel_parm->ch_idx];
+ return swptr;
+}
+
+void alink_set_swptr(void *hw_channel, u32 value)
+{
+ struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
+ *ALNK0_SWPTR[hw_channel_parm->ch_idx] = value;
+}
+
+u32 alink_get_hwptr(void *hw_channel)
+{
+ struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
+ int hwptr = 0;
+ hwptr = *ALNK0_HWPTR[hw_channel_parm->ch_idx];
+ return hwptr;
+}
+
+void alink_set_hwptr(void *hw_channel, u32 value)
+{
+ struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
+ *ALNK0_HWPTR[hw_channel_parm->ch_idx] = value;
+}
+
+void alink_set_ch_ie(void *hw_channel, u32 value)
+{
+ struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
+ ALINK_CHx_IE(hw_channel_parm->module, hw_channel_parm->ch_idx, value);
+}
+
+void alink_clr_ch_pnd(void *hw_channel)
+{
+ struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
+ ALINK_CLR_CHx_PND(hw_channel_parm->module, hw_channel_parm->ch_idx);
+}
+
+//==================================================
+static void alink_io_in_init(u8 gpio)
+{
+ gpio_set_direction(gpio, 1);
+ gpio_set_pull_down(gpio, 0);
+ gpio_set_pull_up(gpio, 1);
+ gpio_set_die(gpio, 1);
+}
+
+static void alink_io_out_init(u8 gpio)
+{
+ gpio_set_direction(gpio, 0);
+ gpio_set_pull_down(gpio, 0);
+ gpio_set_pull_up(gpio, 0);
+ gpio_set_die(gpio, 0);
+ gpio_direction_output(gpio, 1);
+}
+
+static void *alink_addr(void *hw_alink, u8 ch)
+{
+ ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
+ s16 *buf_addr = NULL; //can be used
+ u32 buf_index = 0;
+
+ if (hw_alink_parm->buf_mode == ALINK_BUF_CIRCLE) {
+ buf_addr = (s16 *)(*ALNK0_BUF_ADR[ch] + *ALNK0_SWPTR[ch] * 4);
+ } else {
+ buf_addr = (s16 *)(hw_alink_parm->ch_cfg[ch].buf);
+ u8 index_table[4] = {12, 13, 14, 15};
+ u8 bit_index = index_table[ch];
+ buf_index = (ALINK_SEL(hw_alink_parm->module, CON0) & BIT(bit_index)) ? 0 : 1;
+ buf_addr = buf_addr + ((hw_alink_parm->dma_len / 2 / 2) * buf_index);
+ }
+ return buf_addr;
+}
+
+___interrupt
+static void alink0_dma_isr(void)
+{
+ u16 reg;
+ s16 *buf_addr = NULL ;
+ u8 ch = 0;
+
+ reg = JL_ALNK0->CON2;
+ reg >>= 4;
+
+ for (ch = 0; ch < 4; ch++) {
+ if (!(reg & BIT(ch))) {
+ continue;
+ }
+ buf_addr = (s16 *)alink_addr(p_alink0_parm, ch);
+ if (p_alink0_parm->ch_cfg[ch].isr_cb) {
+ if (p_alink0_parm->buf_mode == ALINK_BUF_CIRCLE) {
+ p_alink0_parm->ch_cfg[ch].isr_cb(p_alink0_parm->ch_cfg[ch].private_data, buf_addr, (JL_ALNK0->PNS & 0xffff) * 4);
+ } else {
+ p_alink0_parm->ch_cfg[ch].isr_cb(p_alink0_parm->ch_cfg[ch].private_data, buf_addr, p_alink0_parm->dma_len / 2);
+ }
+ }
+ ALINK_CLR_CHx_PND(p_alink0_parm->module, ch);
+ }
+}
+
+
+static void alink_sr(void *hw_alink, u32 rate)
+{
+ alink_printf("ALINK_SR = %d\n", rate);
+ ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
+ hw_alink_parm->sample_rate = rate;
+ u8 module = hw_alink_parm->module;
+
+ u8 pll_target_frequency = clock_get_pll_target_frequency();
+ alink_printf("pll_target_frequency = %d\n", pll_target_frequency);
+
+ switch (rate) {
+ case ALINK_SR_48000:
+ /*12.288Mhz 256fs*/
+ audio_link_clock_sel(ALINK_CLOCK_12M288K);
+ ALINK_MDIV(module, MCLK_DIV_1);
+ ALINK_LRDIV(module, MCLK_LRDIV_256FS);
+ break ;
+
+ case ALINK_SR_44100:
+ /*11.289Mhz 256fs*/
+ audio_link_clock_sel(ALINK_CLOCK_11M2896K);
+ ALINK_MDIV(module, MCLK_DIV_1);
+ if (pll_target_frequency == 192) {
+ ALINK_LRDIV(module, MCLK_LRDIV_256FS);
+ } else if (pll_target_frequency == 240) {
+ ALINK_LRDIV(module, MCLK_LRDIV_128FS);
+ }
+ break ;
+
+ case ALINK_SR_32000:
+ /*12.288Mhz 384fs*/
+ audio_link_clock_sel(ALINK_CLOCK_12M288K);
+ ALINK_MDIV(module, MCLK_DIV_1);
+ ALINK_LRDIV(module, MCLK_LRDIV_384FS);
+ break ;
+
+ case ALINK_SR_24000:
+ /*12.288Mhz 512fs*/
+ audio_link_clock_sel(ALINK_CLOCK_12M288K);
+ ALINK_MDIV(module, MCLK_DIV_2);
+ ALINK_LRDIV(module, MCLK_LRDIV_256FS);
+ break ;
+
+ case ALINK_SR_22050:
+ /*11.289Mhz 512fs*/
+ audio_link_clock_sel(ALINK_CLOCK_11M2896K);
+ ALINK_MDIV(module, MCLK_DIV_1);
+ if (pll_target_frequency == 192) {
+ ALINK_LRDIV(module, MCLK_LRDIV_512FS);
+ } else if (pll_target_frequency == 240) {
+ ALINK_LRDIV(module, MCLK_LRDIV_256FS);
+ }
+ break ;
+
+ case ALINK_SR_16000:
+ /*12.288/2Mhz 384fs*/
+ audio_link_clock_sel(ALINK_CLOCK_12M288K);
+ ALINK_MDIV(module, MCLK_DIV_1);
+ ALINK_LRDIV(module, MCLK_LRDIV_768FS);
+ break ;
+
+ case ALINK_SR_12000:
+ /*12.288/2Mhz 512fs*/
+ audio_link_clock_sel(ALINK_CLOCK_12M288K);
+ ALINK_MDIV(module, MCLK_DIV_4);
+ ALINK_LRDIV(module, MCLK_LRDIV_256FS);
+ break ;
+
+ case ALINK_SR_11025:
+ /*11.289/2Mhz 512fs*/
+ audio_link_clock_sel(ALINK_CLOCK_11M2896K);
+ ALINK_MDIV(module, MCLK_DIV_2);
+ if (pll_target_frequency == 192) {
+ ALINK_LRDIV(module, MCLK_LRDIV_512FS);
+ } else if (pll_target_frequency == 240) {
+ ALINK_LRDIV(module, MCLK_LRDIV_256FS);
+ }
+ break ;
+
+ case ALINK_SR_8000:
+ /*12.288/4Mhz 384fs*/
+ audio_link_clock_sel(ALINK_CLOCK_12M288K);
+ ALINK_MDIV(module, MCLK_DIV_4);
+ ALINK_LRDIV(module, MCLK_LRDIV_384FS);
+ break ;
+
+ default:
+ //44100
+ /*11.289Mhz 256fs*/
+ audio_link_clock_sel(ALINK_CLOCK_11M2896K);
+ ALINK_MDIV(module, MCLK_DIV_1);
+ ALINK_LRDIV(module, MCLK_LRDIV_256FS);
+ break;
+ }
+ if (hw_alink_parm->role == ALINK_ROLE_SLAVE) {
+ ALINK_LRDIV(module, MCLK_LRDIV_EX);
+ }
+}
+
+
+void *alink_channel_init(void *hw_alink, ALINK_CH ch_idx, u8 dir, void *priv, void (*handle)(void *priv, void *addr, int len))
+{
+ if (!hw_alink) {
+ return NULL;
+ }
+
+ ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
+ u8 module = hw_alink_parm->module;
+
+ hw_alink_parm->ch_cfg[ch_idx].module = module;
+ hw_alink_parm->ch_cfg[ch_idx].dir = dir;
+ hw_alink_parm->ch_cfg[ch_idx].ch_idx = ch_idx;
+ hw_alink_parm->ch_cfg[ch_idx].isr_cb = handle;
+ hw_alink_parm->ch_cfg[ch_idx].private_data = priv;
+ printf("dma len %d", hw_alink_parm->dma_len);
+ hw_alink_parm->ch_cfg[ch_idx].buf = zalloc(hw_alink_parm->dma_len);
+
+ printf(">>> alink_channel_init %x\n", hw_alink_parm->ch_cfg[ch_idx].buf);
+ u32 *buf_addr;
+
+ //===================================//
+ // ALNK CH DMA BUF //
+ //===================================//
+ buf_addr = ALNK0_BUF_ADR[ch_idx];
+ *buf_addr = (u32)(hw_alink_parm->ch_cfg[ch_idx].buf);
+
+ //===================================//
+ // ALNK工作模式 //
+ //===================================//
+ if (hw_alink_parm->mode > ALINK_MD_IIS_RALIGN) {
+ ALINK_CHx_MODE_SEL(module, ch_idx, (hw_alink_parm->mode - ALINK_MD_IIS_RALIGN));
+ } else {
+ ALINK_CHx_MODE_SEL(module, ch_idx, (hw_alink_parm->mode));
+ }
+ //===================================//
+ // ALNK CH DAT IO INIT //
+ //===================================//
+ if (hw_alink_parm->ch_cfg[ch_idx].dir == ALINK_DIR_RX) {
+ alink_io_in_init(hw_alink_parm->ch_cfg[ch_idx].data_io);
+ gpio_set_fun_input_port(hw_alink_parm->ch_cfg[ch_idx].data_io, PFI_ALNK0_DAT[ch_idx], LOW_POWER_FREE);
+ } else {
+ alink_io_out_init(hw_alink_parm->ch_cfg[ch_idx].data_io);
+ gpio_set_fun_output_port(hw_alink_parm->ch_cfg[ch_idx].data_io, FO_ALNK0_DAT[ch_idx], 1, 1, LOW_POWER_FREE);
+ }
+
+ ALINK_CHx_DIR_MODE(module, ch_idx, dir);
+ ALINK_CHx_IE(module, ch_idx, 1);
+
+ r_printf("alink%d, ch%d init\n", module, ch_idx);
+
+ return &hw_alink_parm->ch_cfg[ch_idx];
+}
+
+static void alink0_info_dump()
+{
+ alink_printf("JL_ALNK0->CON0 = 0x%x", JL_ALNK0->CON0);
+ alink_printf("JL_ALNK0->CON1 = 0x%x", JL_ALNK0->CON1);
+ alink_printf("JL_ALNK0->CON2 = 0x%x", JL_ALNK0->CON2);
+ alink_printf("JL_ALNK0->CON3 = 0x%x", JL_ALNK0->CON3);
+ alink_printf("JL_ALNK0->LEN = 0x%x", JL_ALNK0->LEN);
+ alink_printf("JL_ALNK0->ADR0 = 0x%x", JL_ALNK0->ADR0);
+ alink_printf("JL_ALNK0->ADR1 = 0x%x", JL_ALNK0->ADR1);
+ alink_printf("JL_ALNK0->ADR2 = 0x%x", JL_ALNK0->ADR2);
+ alink_printf("JL_ALNK0->ADR3 = 0x%x", JL_ALNK0->ADR3);
+ alink_printf("JL_ALNK0->PNS = 0x%x", JL_ALNK0->PNS);
+ alink_printf("JL_ALNK0->HWPTR0 = 0x%x", JL_ALNK0->HWPTR0);
+ alink_printf("JL_ALNK0->HWPTR1 = 0x%x", JL_ALNK0->HWPTR1);
+ alink_printf("JL_ALNK0->HWPTR2 = 0x%x", JL_ALNK0->HWPTR2);
+ alink_printf("JL_ALNK0->HWPTR3 = 0x%x", JL_ALNK0->HWPTR3);
+ alink_printf("JL_ALNK0->SWPTR0 = 0x%x", JL_ALNK0->SWPTR0);
+ alink_printf("JL_ALNK0->SWPTR1 = 0x%x", JL_ALNK0->SWPTR1);
+ alink_printf("JL_ALNK0->SWPTR2 = 0x%x", JL_ALNK0->SWPTR2);
+ alink_printf("JL_ALNK0->SWPTR3 = 0x%x", JL_ALNK0->SWPTR3);
+ alink_printf("JL_ALNK0->SHN0 = 0x%x", JL_ALNK0->SHN0);
+ alink_printf("JL_ALNK0->SHN1 = 0x%x", JL_ALNK0->SHN1);
+ alink_printf("JL_ALNK0->SHN2 = 0x%x", JL_ALNK0->SHN2);
+ alink_printf("JL_ALNK0->SHN3 = 0x%x", JL_ALNK0->SHN3);
+}
+
+void *alink_init(void *hw_alink)
+{
+ if (hw_alink == NULL) {
+ return NULL;
+ }
+ ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
+ u8 module = hw_alink_parm->module;
+ p_alink0_parm = (ALINK_PARM *)hw_alink_parm;
+
+ ALNK_CON_RESET(module);
+ ALNK_HWPTR_RESET(module);
+ ALNK_SWPTR_RESET(module);
+ ALNK_ADR_RESET(module);
+ ALNK_SHN_RESET(module);
+ ALNK_PNS_RESET(module);
+ ALINK_CLR_ALL_PND(module);
+
+
+ ALINK_MSRC(module, MCLK_PLL_CLK); /*MCLK source*/
+
+ //===================================//
+ // 输出时钟配置 //
+ //===================================//
+ if (hw_alink_parm->role == ALINK_ROLE_MASTER) {
+ //主机输出时钟
+ if (hw_alink_parm->mclk_io != ALINK_CLK_OUPUT_DISABLE) {
+ alink_io_out_init(hw_alink_parm->mclk_io);
+ gpio_set_fun_output_port(hw_alink_parm->mclk_io, FO_ALNK0_MCLK, 1, 1, LOW_POWER_FREE);
+ ALINK_MOE(module, 1); /*MCLK output to IO*/
+ }
+ if ((hw_alink_parm->sclk_io != ALINK_CLK_OUPUT_DISABLE) && (p_alink0_parm->lrclk_io != ALINK_CLK_OUPUT_DISABLE)) {
+ alink_io_out_init(hw_alink_parm->lrclk_io);
+ gpio_set_fun_output_port(hw_alink_parm->lrclk_io, FO_ALNK0_LRCK, 1, 1, LOW_POWER_FREE);
+ alink_io_out_init(hw_alink_parm->sclk_io);
+ gpio_set_fun_output_port(hw_alink_parm->sclk_io, FO_ALNK0_SCLK, 1, 1, LOW_POWER_FREE);
+ ALINK_SOE(module, 1); /*SCLK/LRCK output to IO*/
+ }
+ } else {
+ //从机输入时钟
+ alink_io_in_init(hw_alink_parm->mclk_io);
+ alink_io_in_init(hw_alink_parm->sclk_io);
+ alink_io_in_init(hw_alink_parm->lrclk_io);
+ gpio_set_fun_input_port(hw_alink_parm->mclk_io, PFI_ALNK0_MCLK, LOW_POWER_FREE);
+ gpio_set_fun_input_port(hw_alink_parm->sclk_io, PFI_ALNK0_SCLK, LOW_POWER_FREE);
+ gpio_set_fun_input_port(hw_alink_parm->lrclk_io, PFI_ALNK0_LRCK, LOW_POWER_FREE);
+ ALINK_MOE(module, 0); /*MCLK input to IO*/
+ ALINK_SOE(module, 0); /*SCLK/LRCK output to IO*/
+ }
+ //===================================//
+ // 基本模式/扩展模式 //
+ //===================================//
+ ALINK_DSPE(module, hw_alink_parm->mode >> 2);
+
+ //===================================//
+ // 数据位宽16/32bit //
+ //===================================//
+ //注意: 配置了24bit, 一定要选ALINK_FRAME_64SCLK, 因为sclk32 x 2才会有24bit;
+ if (hw_alink_parm->bitwide == ALINK_LEN_24BIT) {
+ ASSERT(hw_alink_parm->sclk_per_frame == ALINK_FRAME_64SCLK);
+ ALINK_24BIT_MODE(module);
+ //一个点需要4bytes, LR = 2, 双buf = 2
+ } else {
+ ALINK_16BIT_MODE(module);
+ //一个点需要2bytes, LR = 2, 双buf = 2
+ }
+ //===================================//
+ // 时钟边沿选择 //
+ //===================================//
+ SCLKINV(module, hw_alink_parm->clk_mode);
+ //===================================//
+ // 每帧数据sclk个数 //
+ //===================================//
+ F32_EN(module, hw_alink_parm->sclk_per_frame);
+ //===================================//
+ // 设置数据采样率 //
+ //===================================//
+ alink_sr(hw_alink_parm, hw_alink_parm->sample_rate);
+
+ //===================================//
+ // 设置DMA MODE //
+ //===================================//
+ ALINK_DMA_MODE_SEL(module, hw_alink_parm->buf_mode);
+ if (hw_alink_parm->buf_mode == ALINK_BUF_CIRCLE) {
+ ALINK_OPNS_SET(module, hw_alink_parm->dma_len / 16);
+ if (hw_alink_parm->iperiod) {
+ ALINK_IPNS_SET(module, hw_alink_parm->iperiod);
+ } else {
+ ALINK_IPNS_SET(module, hw_alink_parm->dma_len / 8);
+ }
+ //一个点需要2bytes, LR = 2
+ ALINK_LEN_SET(module, hw_alink_parm->dma_len / 4);
+ } else {
+ //一个点需要2bytes, LR = 2, 双buf = 2
+ ALINK_LEN_SET(module, hw_alink_parm->dma_len / 8);
+ }
+ request_irq(IRQ_ALINK0_IDX, 3, alink0_dma_isr, 0);
+
+ return hw_alink_parm;
+}
+
+void alink_channel_close(void *hw_channel)
+{
+ struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
+
+ ALINK_CHx_CLOSE(hw_channel_parm->module, hw_channel_parm->ch_idx);
+ ALINK_CHx_IE(hw_channel_parm->module, hw_channel_parm->ch_idx, 0);
+
+ gpio_set_pull_up(hw_channel_parm->data_io, 0);
+ gpio_set_pull_down(hw_channel_parm->data_io, 0);
+ gpio_set_direction(hw_channel_parm->data_io, 1);
+ gpio_set_die(hw_channel_parm->data_io, 0);
+ if (hw_channel_parm->buf) {
+ free(hw_channel_parm->buf);
+ hw_channel_parm->buf = NULL;
+ }
+ r_printf("alink_ch %d closed\n", hw_channel_parm->ch_idx);
+}
+
+
+int alink_start(void *hw_alink)
+{
+ ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
+ if (hw_alink_parm) {
+ ALINK_EN(hw_alink_parm->module, 1);
+ return 0;
+ }
+ return -1;
+}
+
+void alink_uninit(void *hw_alink)
+{
+ ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
+
+ if (!hw_alink_parm) {
+ return;
+ }
+
+ ALINK_EN(hw_alink_parm->module, 0);
+ for (int i = 0; i < 4; i++) {
+ if (hw_alink_parm->ch_cfg[i].buf) {
+ alink_channel_close(&hw_alink_parm->ch_cfg[i]);
+ }
+ }
+ ALNK_CON_RESET(hw_alink_parm->module);
+ hw_alink_parm = NULL;
+ alink_printf("audio_link_exit OK\n");
+}
+
+static u8 iis_driver_close(void)
+{
+ alink_uninit(p_alink0_parm);
+ return 0;
+}
+
+REGISTER_UPDATE_TARGET(iis_update_target) = {
+ .name = "iis",
+ .driver_close = iis_driver_close,
+};
+
+int alink_get_sr(void *hw_alink)
+{
+ ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
+ if (hw_alink_parm) {
+ return hw_alink_parm->sample_rate;
+ } else {
+ return -1;
+ }
+}
+
+int alink_set_sr(void *hw_alink, u32 sr)
+{
+ ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
+
+ if (!hw_alink_parm) {
+ return -1;
+ }
+
+ if (hw_alink_parm->sample_rate == sr) {
+ return 0;
+ }
+
+ u8 is_alink_en = (ALINK_SEL(hw_alink_parm->module, CON0) & BIT(11));
+
+ if (is_alink_en) {
+ ALINK_EN(hw_alink_parm->module, 0);
+ }
+
+ alink_sr(hw_alink_parm, sr);
+
+ if (is_alink_en) {
+ ALINK_EN(hw_alink_parm->module, 1);
+ }
+
+ return 0;
+}
+
+u32 alink_get_dma_len(void *hw_alink)
+{
+ ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
+ return ALINK_FIFO_LEN(hw_alink_parm->module);
+}
+
+void alink_set_tx_pns(void *hw_alink, u32 len)
+{
+ ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
+ ALINK_OPNS_SET(hw_alink_parm->module, len);
+}
+
+void alink_set_rx_pns(void *hw_alink, u32 len)
+{
+ ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
+ ALINK_IPNS_SET(hw_alink_parm->module, len);
+}
+
+int alink_get_tx_pns(void *hw_alink)
+{
+ ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
+
+ return ALINK_SEL(hw_alink_parm->module, PNS);
+}
+
+#include "audio_iis.c"
+//===============================================//
+// for APP use demo //
+//===============================================//
+
+#if ALINK_TEST_ENABLE
+
+short const tsin_441k[441] = {
+ 0x0000, 0x122d, 0x23fb, 0x350f, 0x450f, 0x53aa, 0x6092, 0x6b85, 0x744b, 0x7ab5, 0x7ea2, 0x7fff, 0x7ec3, 0x7af6, 0x74ab, 0x6c03,
+ 0x612a, 0x545a, 0x45d4, 0x35e3, 0x24db, 0x1314, 0x00e9, 0xeeba, 0xdce5, 0xcbc6, 0xbbb6, 0xad08, 0xa008, 0x94fa, 0x8c18, 0x858f,
+ 0x8181, 0x8003, 0x811d, 0x84ca, 0x8af5, 0x9380, 0x9e3e, 0xaaf7, 0xb969, 0xc94a, 0xda46, 0xec06, 0xfe2d, 0x105e, 0x223a, 0x3365,
+ 0x4385, 0x5246, 0x5f5d, 0x6a85, 0x7384, 0x7a2d, 0x7e5b, 0x7ffa, 0x7f01, 0x7b75, 0x7568, 0x6cfb, 0x6258, 0x55b7, 0x4759, 0x3789,
+ 0x2699, 0x14e1, 0x02bc, 0xf089, 0xdea7, 0xcd71, 0xbd42, 0xae6d, 0xa13f, 0x95fd, 0x8ce1, 0x861a, 0x81cb, 0x800b, 0x80e3, 0x844e,
+ 0x8a3c, 0x928c, 0x9d13, 0xa99c, 0xb7e6, 0xc7a5, 0xd889, 0xea39, 0xfc5a, 0x0e8f, 0x2077, 0x31b8, 0x41f6, 0x50de, 0x5e23, 0x697f,
+ 0x72b8, 0x799e, 0x7e0d, 0x7fee, 0x7f37, 0x7bed, 0x761f, 0x6ded, 0x6380, 0x570f, 0x48db, 0x392c, 0x2855, 0x16ad, 0x048f, 0xf259,
+ 0xe06b, 0xcf20, 0xbed2, 0xafd7, 0xa27c, 0x9705, 0x8db0, 0x86ab, 0x821c, 0x801a, 0x80b0, 0x83da, 0x8988, 0x919c, 0x9bee, 0xa846,
+ 0xb666, 0xc603, 0xd6ce, 0xe86e, 0xfa88, 0x0cbf, 0x1eb3, 0x3008, 0x4064, 0x4f73, 0x5ce4, 0x6874, 0x71e6, 0x790a, 0x7db9, 0x7fdc,
+ 0x7f68, 0x7c5e, 0x76d0, 0x6ed9, 0x64a3, 0x5863, 0x4a59, 0x3acc, 0x2a0f, 0x1878, 0x0661, 0xf42a, 0xe230, 0xd0d0, 0xc066, 0xb145,
+ 0xa3bd, 0x9813, 0x8e85, 0x8743, 0x8274, 0x8030, 0x8083, 0x836b, 0x88da, 0x90b3, 0x9acd, 0xa6f5, 0xb4ea, 0xc465, 0xd515, 0xe6a3,
+ 0xf8b6, 0x0aee, 0x1ced, 0x2e56, 0x3ecf, 0x4e02, 0x5ba1, 0x6764, 0x710e, 0x786f, 0x7d5e, 0x7fc3, 0x7f91, 0x7cc9, 0x777a, 0x6fc0,
+ 0x65c1, 0x59b3, 0x4bd3, 0x3c6a, 0x2bc7, 0x1a41, 0x0833, 0xf5fb, 0xe3f6, 0xd283, 0xc1fc, 0xb2b7, 0xa503, 0x9926, 0x8f60, 0x87e1,
+ 0x82d2, 0x804c, 0x805d, 0x8303, 0x8833, 0x8fcf, 0x99b2, 0xa5a8, 0xb372, 0xc2c9, 0xd35e, 0xe4da, 0xf6e4, 0x091c, 0x1b26, 0x2ca2,
+ 0x3d37, 0x4c8e, 0x5a58, 0x664e, 0x7031, 0x77cd, 0x7cfd, 0x7fa3, 0x7fb4, 0x7d2e, 0x781f, 0x70a0, 0x66da, 0x5afd, 0x4d49, 0x3e04,
+ 0x2d7d, 0x1c0a, 0x0a05, 0xf7cd, 0xe5bf, 0xd439, 0xc396, 0xb42d, 0xa64d, 0x9a3f, 0x9040, 0x8886, 0x8337, 0x806f, 0x803d, 0x82a2,
+ 0x8791, 0x8ef2, 0x989c, 0xa45f, 0xb1fe, 0xc131, 0xd1aa, 0xe313, 0xf512, 0x074a, 0x195d, 0x2aeb, 0x3b9b, 0x4b16, 0x590b, 0x6533,
+ 0x6f4d, 0x7726, 0x7c95, 0x7f7d, 0x7fd0, 0x7d8c, 0x78bd, 0x717b, 0x67ed, 0x5c43, 0x4ebb, 0x3f9a, 0x2f30, 0x1dd0, 0x0bd6, 0xf99f,
+ 0xe788, 0xd5f1, 0xc534, 0xb5a7, 0xa79d, 0x9b5d, 0x9127, 0x8930, 0x83a2, 0x8098, 0x8024, 0x8247, 0x86f6, 0x8e1a, 0x978c, 0xa31c,
+ 0xb08d, 0xbf9c, 0xcff8, 0xe14d, 0xf341, 0x0578, 0x1792, 0x2932, 0x39fd, 0x499a, 0x57ba, 0x6412, 0x6e64, 0x7678, 0x7c26, 0x7f50,
+ 0x7fe6, 0x7de4, 0x7955, 0x7250, 0x68fb, 0x5d84, 0x5029, 0x412e, 0x30e0, 0x1f95, 0x0da7, 0xfb71, 0xe953, 0xd7ab, 0xc6d4, 0xb725,
+ 0xa8f1, 0x9c80, 0x9213, 0x89e1, 0x8413, 0x80c9, 0x8012, 0x81f3, 0x8662, 0x8d48, 0x9681, 0xa1dd, 0xaf22, 0xbe0a, 0xce48, 0xdf89,
+ 0xf171, 0x03a6, 0x15c7, 0x2777, 0x385b, 0x481a, 0x5664, 0x62ed, 0x6d74, 0x75c4, 0x7bb2, 0x7f1d, 0x7ff5, 0x7e35, 0x79e6, 0x731f,
+ 0x6a03, 0x5ec1, 0x5193, 0x42be, 0x328f, 0x2159, 0x0f77, 0xfd44, 0xeb1f, 0xd967, 0xc877, 0xb8a7, 0xaa49, 0x9da8, 0x9305, 0x8a98,
+ 0x848b, 0x80ff, 0x8006, 0x81a5, 0x85d3, 0x8c7c, 0x957b, 0xa0a3, 0xadba, 0xbc7b, 0xcc9b, 0xddc6, 0xefa2, 0x01d3, 0x13fa, 0x25ba,
+ 0x36b6, 0x4697, 0x5509, 0x61c2, 0x6c80, 0x750b, 0x7b36, 0x7ee3, 0x7ffd, 0x7e7f, 0x7a71, 0x73e8, 0x6b06, 0x5ff8, 0x52f8, 0x444a,
+ 0x343a, 0x231b, 0x1146, 0xff17, 0xecec, 0xdb25, 0xca1d, 0xba2c, 0xaba6, 0x9ed6, 0x93fd, 0x8b55, 0x850a, 0x813d, 0x8001, 0x815e,
+ 0x854b, 0x8bb5, 0x947b, 0x9f6e, 0xac56, 0xbaf1, 0xcaf1, 0xdc05, 0xedd3
+};
+
+static short const tsin_16k[16] = {
+ 0x0000, 0x30fd, 0x5a83, 0x7641, 0x7fff, 0x7642, 0x5a82, 0x30fc, 0x0000, 0xcf04, 0xa57d, 0x89be, 0x8000, 0x89be, 0xa57e, 0xcf05,
+};
+static u16 tx_s_cnt = 0;
+static int get_sine_data(u16 *s_cnt, s16 *data, u16 points, u8 ch)
+{
+ while (points--) {
+ if (*s_cnt >= 441) {
+ *s_cnt = 0;
+ }
+ *data++ = tsin_441k[*s_cnt];
+ if (ch == 2) {
+ *data++ = tsin_441k[*s_cnt];
+ }
+ (*s_cnt)++;
+ }
+ return 0;
+}
+
+static int get_sine_16k_data(u16 *s_cnt, s16 *data, u16 points, u8 ch)
+{
+ while (points--) {
+ if (*s_cnt >= 16) {
+ *s_cnt = 0;
+ }
+ *data++ = tsin_16k[*s_cnt];
+ if (ch == 2) {
+ *data++ = tsin_16k[*s_cnt];
+ }
+ (*s_cnt)++;
+ }
+ return 0;
+}
+
+extern struct audio_decoder_task decode_task;
+void handle_tx(void *priv, void *buf, u16 len)
+{
+ putchar('o');
+#if 1
+ /* get_sine_16k_data(&tx_s_cnt, buf, len / 2 / 2, 2); */
+ get_sine_data(&tx_s_cnt, buf, len / 2 / 2, 2);
+ printf("tx len %x %d", buf, len);
+ /* memset(buf, 0, len); */
+ alink_set_shn(&p_alink0_parm->ch_cfg[0], len / 4);
+#endif
+}
+
+extern struct audio_dac_hdl dac_hdl;
+void handle_rx(void *priv, void *buf, u16 len)
+{
+ /* putchar('r'); */
+#if 1
+ put_buf(buf, 32);
+#else
+
+#endif
+ alink_set_shn(&p_alink0_parm->ch_cfg[1], len / 4);
+}
+
+ALINK_PARM test_alink = {
+ .module = ALINK0,
+ .mclk_io = IO_PORTA_12,
+ .sclk_io = IO_PORTA_13,
+ .lrclk_io = IO_PORTA_14,
+ .ch_cfg[0].data_io = IO_PORTA_15,
+ .ch_cfg[1].data_io = IO_PORTA_11,
+ /* .mode = ALINK_MD_IIS_LALIGN, */
+ .mode = ALINK_MD_IIS,
+ /* .role = ALINK_ROLE_SLAVE, */
+ .role = ALINK_ROLE_MASTER,
+ /* .clk_mode = ALINK_CLK_RAISE_UPDATE_FALL_SAMPLE, */
+ .clk_mode = ALINK_CLK_FALL_UPDATE_RAISE_SAMPLE,
+ .bitwide = ALINK_LEN_16BIT,
+ /* .bitwide = ALINK_LEN_24BIT, */
+ .sclk_per_frame = ALINK_FRAME_32SCLK,
+ /* .dma_len = ALNK_BUF_POINTS_NUM * 2 * 2 , */
+ .dma_len = 4 * 1024,
+ /* .sample_rate = 16000, */
+ .sample_rate = 44100,
+ /* .sample_rate = TCFG_IIS_SAMPLE_RATE, */
+ /* .buf_mode = ALINK_BUF_CIRCLE, */
+ .buf_mode = ALINK_BUF_DUAL,
+};
+
+
+
+void audio_link_test(void)
+{
+ void *hw_alink = alink_init(&test_alink);
+
+ void *alink_ch0 = alink_channel_init(hw_alink, 0, ALINK_DIR_TX, NULL, handle_tx);
+ /* void *alink_ch1 = alink_channel_init(hw_alink, 1, ALINK_DIR_RX, NULL, handle_rx); */
+ /* void *alink_ch2 = alink_channel_init(hw_alink, 2, ALINK_DIR_TX, NULL, handle_tx); */
+ /* void *alink_ch3 = alink_channel_init(hw_alink, 3, ALINK_DIR_RX, NULL, handle_rx); */
+ clk_set("sys", 96 * 1000000L);
+ alink_start(hw_alink);
+
+
+ alink0_info_dump();
+ while (1) {
+ /* void clr_wdt(void); */
+ /* clr_wdt(); */
+ os_time_dly(2);
+ }
+}
+
+#endif
+
diff --git a/cpu/br28/audio_link.h b/cpu/br28/audio_link.h
new file mode 100644
index 0000000..245b2ed
--- /dev/null
+++ b/cpu/br28/audio_link.h
@@ -0,0 +1,132 @@
+#ifndef _AUDIO_LINK_H_
+#define _AUDIO_LINK_H_
+
+#define ALNK_BUF_POINTS_NUM 256
+
+#define ALINK_CLK_OUPUT_DISABLE 0xFF
+
+typedef enum {
+ ALINK0 = 0u, //BR28只有一个ALNK模块
+} ALINK_PORT;
+
+//ch_num
+typedef enum {
+ ALINK_CH0 = 0u,
+ ALINK_CH1,
+ ALINK_CH2,
+ ALINK_CH3,
+} ALINK_CH;
+
+//ch_dir
+typedef enum {
+ ALINK_DIR_TX = 0u,
+ ALINK_DIR_RX ,
+} ALINK_DIR;
+
+typedef enum {
+ ALINK_LEN_16BIT = 0u,
+ ALINK_LEN_24BIT , //ALINK_FRAME_MODE需要选择: ALINK_FRAME_64SCLK
+} ALINK_DATA_WIDTH;
+
+//ch_mode
+typedef enum {
+ ALINK_MD_NONE = 0u,
+ ALINK_MD_IIS ,
+ ALINK_MD_IIS_LALIGN ,
+ ALINK_MD_IIS_RALIGN ,
+ ALINK_MD_DSP0 ,
+ ALINK_MD_DSP1 ,
+} ALINK_MODE;
+
+//ch_mode
+typedef enum {
+ ALINK_ROLE_MASTER, //主机
+ ALINK_ROLE_SLAVE, //从机
+} ALINK_ROLE;
+
+typedef enum {
+ ALINK_CLK_FALL_UPDATE_RAISE_SAMPLE, //下降沿更新数据, 上升沿采样数据
+ ALINK_CLK_RAISE_UPDATE_FALL_SAMPLE, //上降沿更新数据, 下升沿采样数据
+} ALINK_CLK_MODE;
+
+typedef enum {
+ ALINK_FRAME_64SCLK, //64 sclk/frame
+ ALINK_FRAME_32SCLK, //32 sclk/frame
+} ALINK_FRAME_MODE;
+
+//SDK默认PLL是192M,仅支持44100,22050,11025采样率,如需其他采样率,需设置PLL为240M,可支持所有采样率
+typedef enum {
+ ALINK_SR_48000 = 48000,
+ ALINK_SR_44100 = 44100,
+ ALINK_SR_32000 = 32000,
+ ALINK_SR_24000 = 24000,
+ ALINK_SR_22050 = 22050,
+ ALINK_SR_16000 = 16000,
+ ALINK_SR_12000 = 12000,
+ ALINK_SR_11025 = 11025,
+ ALINK_SR_8000 = 8000,
+} ALINK_SR;
+
+typedef enum {
+ ALINK_BUF_DUAL, //乒乓BUF
+ ALINK_BUF_CIRCLE, //循环BUF
+} ALINK_BUF_MODE;
+
+struct alnk_hw_ch {
+ ALINK_PORT module;
+ ALINK_CH ch_idx;
+ u8 data_io; //data IO配置
+ ALINK_DIR dir; //通道传输数据方向: Tx, Rx
+ void *buf; //dma buf地址
+ void (*isr_cb)(void *priv, void *addr, int len); //中断回调
+ void *private_data; //音频私有数据
+};
+
+//===================================//
+//多个通道使用需要注意:
+//1.数据位宽需要保持一致
+//2.buf长度相同
+//===================================//
+typedef struct _ALINK_PARM {
+ ALINK_PORT module;
+ u8 mclk_io; //mclk IO输出配置: ALINK_CLK_OUPUT_DISABLE不输出该时钟
+ u8 sclk_io; //sclk IO输出配置: ALINK_CLK_OUPUT_DISABLE不输出该时钟
+ u8 lrclk_io; //lrclk IO输出配置: ALINK_CLK_OUPUT_DISABLE不输出该时钟
+ struct alnk_hw_ch ch_cfg[4]; //通道内部配置
+ ALINK_MODE mode; //IIS, left, right, dsp0, dsp1
+ ALINK_ROLE role; //主机/从机
+ ALINK_CLK_MODE clk_mode; //更新和采样边沿
+ ALINK_DATA_WIDTH bitwide; //数据位宽16/32bit
+ ALINK_FRAME_MODE sclk_per_frame; //32/64 sclk/frame
+ u16 dma_len; //buf长度: byte
+ u16 iperiod; //输入中断的周期点数
+ ALINK_SR sample_rate; //采样
+ ALINK_BUF_MODE buf_mode; //乒乓buf or 循环buf率
+} ALINK_PARM;
+
+//iis 模块相关
+void *alink_init(void *hw_alink); //iis 初始化
+int alink_start(void *hw_alink); //iis 开启
+int alink_set_sr(void *hw_alink, u32 sr); //iis 设置采样率
+int alink_get_sr(void *hw_alink); //iis 获取采样率
+u32 alink_get_dma_len(void *hw_alink); //iis 获取DMA_LEN
+void alink_set_rx_pns(void *hw_alink, u32 len); //iis 设置接收PNS
+void alink_set_tx_pns(void *hw_alink, u32 len); //iis 设置发送PNS
+void alink_uninit(void *hw_alink); //iis 退出
+int alink_get_tx_pns(void *hw_alink);
+
+//iis 通道相关
+void *alink_channel_init(void *hw_alink, ALINK_CH ch_idx, u8 dir, void *priv, void (*handle)(void *priv, void *addr, int len)); //iis通道初始化,返回句柄
+void alink_channel_close(void *hw_channel); //iis通道关闭
+u32 alink_get_addr(void *hw_channel); //iis获取通道DMA地址
+u32 alink_get_shn(void *hw_channel); //iis获取通道SHN
+void alink_set_shn(void *hw_channel, u32 len); //iis设置通道SHN
+u32 alink_get_swptr(void *hw_channel); //iis获取通道swptr
+void alink_set_swptr(void *hw_channel, u32 value); //iis设置通道swptr
+u32 alink_get_hwptr(void *hw_channel); //iis获取通道hwptr
+void alink_set_hwptr(void *hw_channel, u32 value); //iis设置通道hwptr
+void alink_set_ch_ie(void *hw_channel, u32 value); //iis设置通道ie
+void alink_clr_ch_pnd(void *hw_channel); //iis清除通道pnd
+
+u32 audio_iis_hw_rates_match(u32 sr);
+#endif
diff --git a/cpu/br28/audio_sync.c b/cpu/br28/audio_sync.c
new file mode 100644
index 0000000..9381725
--- /dev/null
+++ b/cpu/br28/audio_sync.c
@@ -0,0 +1,108 @@
+
+#include "board_config.h"
+#include "asm/dac.h"
+#include "media/includes.h"
+//#include "media/audio_dev.h"
+#include "effectrs_sync.h"
+#include "asm/gpio.h"
+
+#if 0
+
+extern struct audio_dac_hdl dac_hdl;
+extern int bt_media_sync_master(u8 type);
+extern u8 bt_media_device_online(u8 dev);
+extern void *bt_media_sync_open(void);
+extern void bt_media_sync_close(void *);
+extern int a2dp_media_get_total_buffer_size();
+/*extern u32 get_bt_slot_time(u8 type, u32 time, u32 *pre_time);*/
+extern int bt_send_audio_sync_data(void *, void *buf, u32 len);
+extern void bt_media_sync_set_handler(void *, void *priv,
+ void (*event_handler)(void *, int *, int));
+extern int bt_audio_sync_nettime_select(u8 basetime);
+
+
+const static struct audio_tws_conn_ops tws_conn_ops = {
+ .open = bt_media_sync_open,
+ .set_handler = bt_media_sync_set_handler,
+ .close = bt_media_sync_close,
+ /*.time = get_bt_slot_time,*/
+ .master = bt_media_sync_master,
+ .online = bt_media_device_online,
+ .send = bt_send_audio_sync_data,
+};
+
+#if (CONFIG_BD_NUM == 2)
+#define SYNC_DATA_TOP_PERCENT 70
+#define SYNC_DATA_BOTTOM_PERCENT 50
+#define SYNC_DATA_BEGIN_PERCENT 60
+#elif (TCFG_USER_TWS_ENABLE == 1)
+#if TCFG_BT_SUPPORT_AAC
+#define SYNC_DATA_TOP_PERCENT 70
+#define SYNC_DATA_BOTTOM_PERCENT 50
+#define SYNC_DATA_BEGIN_PERCENT 50
+#else
+#define SYNC_DATA_TOP_PERCENT 80
+#define SYNC_DATA_BOTTOM_PERCENT 60
+#define SYNC_DATA_BEGIN_PERCENT 60
+#endif
+#else
+#define SYNC_DATA_TOP_PERCENT 80
+#define SYNC_DATA_BOTTOM_PERCENT 60
+#define SYNC_DATA_BEGIN_PERCENT 70
+#endif
+
+#define SYNC_START_TIME 100
+void *a2dp_play_sync_open(u8 channel, u32 sample_rate, u32 output_rate, u32 coding_type)
+{
+ struct audio_wireless_sync_info sync_param;
+ int a2dp_total_size = 0;
+
+ if (coding_type == AUDIO_CODING_AAC) {
+ a2dp_total_size = 15 * 1024;
+ } else if (coding_type == AUDIO_CODING_SBC) {
+ a2dp_total_size = a2dp_media_get_total_buffer_size();
+ }
+
+ sync_param.channel = channel;
+ sync_param.tws_ops = &tws_conn_ops;
+ sync_param.sample_rate = sample_rate;
+ sync_param.output_rate = output_rate;
+
+ sync_param.data_top = SYNC_DATA_BEGIN_PERCENT * a2dp_total_size / 100;
+ sync_param.data_bottom = SYNC_DATA_BOTTOM_PERCENT * a2dp_total_size / 100;
+ sync_param.begin_size = SYNC_DATA_BEGIN_PERCENT * a2dp_total_size / 100;
+ sync_param.tws_together_time = SYNC_START_TIME;
+
+ sync_param.protocol = WL_PROTOCOL_RTP;
+ /*sync_param.dev_type = AUDIO_OUTPUT_DAC;*/
+ sync_param.dev = &dac_hdl;
+
+ bt_audio_sync_nettime_select(0);
+
+ return audio_wireless_sync_open(&sync_param);
+}
+
+void *esco_play_sync_open(u8 channel, u16 sample_rate, u16 output_rate)
+
+{
+ struct audio_wireless_sync_info sync_param;
+
+ int esco_buffer_size = 60 * 50;
+
+ sync_param.channel = channel;
+ sync_param.sample_rate = sample_rate;
+ sync_param.tws_ops = &tws_conn_ops;
+ sync_param.data_top = 40 * esco_buffer_size / 100;
+ sync_param.data_bottom = 10 * esco_buffer_size / 100;
+ sync_param.begin_size = 15 * esco_buffer_size / 100; /*60*50*6/100 = 180(3 packet)*/
+ sync_param.tws_together_time = SYNC_START_TIME;
+ /*sync_param.dev_type = AUDIO_OUTPUT_DAC;*/
+ sync_param.dev = &dac_hdl;
+
+ sync_param.protocol = WL_PROTOCOL_SCO;
+
+ bt_audio_sync_nettime_select(0);
+
+ return audio_wireless_sync_open(&sync_param);
+}
+#endif
diff --git a/cpu/br28/charge.c b/cpu/br28/charge.c
new file mode 100644
index 0000000..13aff32
--- /dev/null
+++ b/cpu/br28/charge.c
@@ -0,0 +1,531 @@
+#include "asm/clock.h"
+#include "timer.h"
+#include "asm/power/p33.h"
+#include "asm/charge.h"
+#include "asm/adc_api.h"
+#include "uart.h"
+#include "device/device.h"
+#include "asm/power_interface.h"
+#include "asm/power/power_wakeup.h"
+#include "system/event.h"
+#include "asm/efuse.h"
+#include "gpio.h"
+#include "app_config.h"
+
+#define LOG_TAG_CONST CHARGE
+#define LOG_TAG "[CHARGE]"
+#define LOG_INFO_ENABLE
+#define LOG_DUMP_ENABLE
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#include "debug.h"
+
+typedef struct _CHARGE_VAR {
+ struct charge_platform_data *data;
+ volatile u8 charge_online_flag;
+ volatile u8 charge_event_flag;
+ volatile u8 init_ok;
+ volatile u8 detect_stop;
+ volatile int ldo5v_timer; //检测LDOIN状态变化的usr timer
+ volatile int charge_timer; //检测充电是否充满的usr timer
+ volatile int cc_timer; //涓流切恒流的sys timer
+} CHARGE_VAR;
+
+#define __this (&charge_var)
+static CHARGE_VAR charge_var;
+static u8 charge_flag;
+
+#define BIT_LDO5V_IN BIT(0)
+#define BIT_LDO5V_OFF BIT(1)
+#define BIT_LDO5V_KEEP BIT(2)
+
+u8 get_charge_poweron_en(void)
+{
+ return __this->data->charge_poweron_en;
+}
+
+void set_charge_poweron_en(u32 onOff)
+{
+ __this->data->charge_poweron_en = onOff;
+}
+
+void charge_check_and_set_pinr(u8 level)
+{
+ u8 pinr_io, reg;
+ reg = P33_CON_GET(P3_PINR_CON1);
+ //开启LDO5V_DET长按复位
+ if ((reg & BIT(0)) && ((reg & BIT(3)) == 0)) {
+ if (level == 0) {
+ P33_CON_SET(P3_PINR_CON1, 2, 1, 0);
+ } else {
+ P33_CON_SET(P3_PINR_CON1, 2, 1, 1);
+ }
+ }
+}
+
+extern void udelay(u32 usec);
+static u8 check_charge_state(void)
+{
+ u16 i, det_max_time;
+
+#if TCFG_UMIDIGI_BOX_ENABLE
+ det_max_time = TIMER2CMESSAGE * 16;
+#else
+ det_max_time = 20;
+#endif
+
+ __this->charge_online_flag = 0;
+
+ for (i = 0; i < det_max_time; i++) {
+ if (LVCMP_DET_GET() || LDO5V_DET_GET()) {
+ __this->charge_online_flag = 1;
+ break;
+ }
+ udelay(1000);
+ }
+ return __this->charge_online_flag;
+}
+
+void set_charge_online_flag(u8 flag)
+{
+ __this->charge_online_flag = flag;
+}
+
+u8 get_charge_online_flag(void)
+{
+ return __this->charge_online_flag;
+}
+
+void set_charge_event_flag(u8 flag)
+{
+ __this->charge_event_flag = flag;
+}
+
+u8 get_ldo5v_online_hw(void)
+{
+ return LDO5V_DET_GET();
+}
+
+u8 get_lvcmp_det(void)
+{
+ return LVCMP_DET_GET();
+}
+
+u8 get_ldo5v_pulldown_en(void)
+{
+ if (!__this->data) {
+ return 0;
+ }
+ if (get_ldo5v_online_hw()) {
+ if (__this->data->ldo5v_pulldown_keep == 0) {
+ return 0;
+ }
+ }
+ return __this->data->ldo5v_pulldown_en;
+}
+
+u8 get_ldo5v_pulldown_res(void)
+{
+ if (__this->data) {
+ return __this->data->ldo5v_pulldown_lvl;
+ }
+ return CHARGE_PULLDOWN_200K;
+}
+
+void charge_event_to_user(u8 event)
+{
+ struct sys_event e;
+ e.type = SYS_DEVICE_EVENT;
+ e.arg = (void *)DEVICE_EVENT_FROM_CHARGE;
+ e.u.dev.event = event;
+ e.u.dev.value = 0;
+ sys_event_notify(&e);
+}
+
+static void charge_cc_check(void *priv)
+{
+ if ((adc_get_voltage(AD_CH_VBAT) * 4 / 10) > CHARGE_CCVOL_V) {
+ set_charge_mA(__this->data->charge_mA);
+ usr_timer_del(__this->cc_timer);
+ __this->cc_timer = 0;
+ power_awakeup_gpio_enable(IO_CHGFL_DET, 1);
+ charge_wakeup_isr();
+ }
+}
+
+void charge_start(void)
+{
+ u8 check_full = 0;
+ log_info("%s\n", __func__);
+
+#if !TCFG_EXTERN_CHARGE_ENABLE
+ if (__this->charge_timer) {
+ usr_timer_del(__this->charge_timer);
+ __this->charge_timer = 0;
+ }
+
+ //进入恒流充电之后,才开启充满检测
+ if ((adc_get_voltage(AD_CH_VBAT) * 4 / 10) > CHARGE_CCVOL_V) {
+ set_charge_mA(__this->data->charge_mA);
+ power_awakeup_gpio_enable(IO_CHGFL_DET, 1);
+ check_full = 1;
+ } else {
+ //涓流阶段系统不进入低功耗,防止电池电量更新过慢导致涓流切恒流时间过长
+ set_charge_mA(__this->data->charge_trickle_mA);
+ if (!__this->cc_timer) {
+ __this->cc_timer = usr_timer_add(NULL, charge_cc_check, 1000, 1);
+ }
+ }
+
+ CHARGE_EN(1);
+ CHGGO_EN(1);
+
+ charge_event_to_user(CHARGE_EVENT_CHARGE_START);
+
+ //开启充电时,充满标记为1时,主动检测一次是否充满
+ if (check_full && CHARGE_FULL_FLAG_GET()) {
+ charge_wakeup_isr();
+ }
+#else
+
+ /* 插入检测时使用vpwr 。Full_DET没充满时高阻,充满时低。 */
+ //检测到开始充电,仅发送消息给其他app
+ charge_event_to_user(CHARGE_EVENT_CHARGE_START);
+
+ /* 初始化充满检测io */
+ //设置为上拉输入
+ gpio_direction_input(TCFG_EXTERN_CHARGE_PORT);
+ gpio_set_pull_down(TCFG_EXTERN_CHARGE_PORT, 0);
+ gpio_set_pull_up(TCFG_EXTERN_CHARGE_PORT, 1);
+ gpio_set_die(TCFG_EXTERN_CHARGE_PORT, 1);
+
+ if (0 == gpio_read(TCFG_EXTERN_CHARGE_PORT)) {
+ log_info("ex_charge has been full\n");
+ //检测到低电平,已经充满了的情况下触发充电,直接走充满流程
+ charge_event_to_user(CHARGE_EVENT_CHARGE_FULL);
+ }
+ power_wakeup_enable_with_port(TCFG_EXTERN_CHARGE_PORT);
+ //此时还有一个低电检测定时器在跑,如果需要省充电功耗可以直接关机,等到下降沿来了就会会触发开机进行处理流程。
+ /* power_set_soft_poweroff(); */
+#endif
+
+}
+
+void charge_close(void)
+{
+ log_info("%s\n", __func__);
+
+#if !TCFG_EXTERN_CHARGE_ENABLE
+ CHARGE_EN(0);
+ CHGGO_EN(0);
+
+ power_awakeup_gpio_enable(IO_CHGFL_DET, 0);
+
+ charge_event_to_user(CHARGE_EVENT_CHARGE_CLOSE);
+
+ if (__this->charge_timer) {
+ usr_timer_del(__this->charge_timer);
+ __this->charge_timer = 0;
+ }
+ if (__this->cc_timer) {
+ usr_timer_del(__this->cc_timer);
+ __this->cc_timer = 0;
+ }
+#else
+ power_wakeup_disable_with_port(TCFG_EXTERN_CHARGE_PORT);
+ //检测到开始充电,仅发送消息给其他app
+ charge_event_to_user(CHARGE_EVENT_CHARGE_CLOSE);
+#endif
+}
+
+static void charge_full_detect(void *priv)
+{
+ static u16 charge_full_cnt = 0;
+
+ if (CHARGE_FULL_FILTER_GET()) {
+ /* putchar('F'); */
+ if (CHARGE_FULL_FLAG_GET() && LVCMP_DET_GET()) {
+ /* putchar('1'); */
+ if (charge_full_cnt < 10) {
+ charge_full_cnt++;
+ } else {
+ charge_full_cnt = 0;
+ power_awakeup_gpio_enable(IO_CHGFL_DET, 0);
+ usr_timer_del(__this->charge_timer);
+ __this->charge_timer = 0;
+ charge_event_to_user(CHARGE_EVENT_CHARGE_FULL);
+ }
+ } else {
+ /* putchar('0'); */
+ charge_full_cnt = 0;
+ }
+ } else {
+ /* putchar('K'); */
+ charge_full_cnt = 0;
+ usr_timer_del(__this->charge_timer);
+ __this->charge_timer = 0;
+ }
+}
+
+static void ldo5v_detect(void *priv)
+{
+ /* log_info("%s\n",__func__); */
+
+ static u16 ldo5v_on_cnt = 0;
+ static u16 ldo5v_keep_cnt = 0;
+ static u16 ldo5v_off_cnt = 0;
+
+ if (__this->detect_stop) {
+ return;
+ }
+
+ if (LVCMP_DET_GET()) { //ldoin > vbat
+ /* putchar('X'); */
+ if (ldo5v_on_cnt < __this->data->ldo5v_on_filter) {
+ ldo5v_on_cnt++;
+ } else {
+ /* printf("ldo5V_IN\n"); */
+ set_charge_online_flag(1);
+ ldo5v_off_cnt = 0;
+ ldo5v_keep_cnt = 0;
+ //消息线程未准备好接收消息,继续扫描
+ if (__this->charge_event_flag == 0) {
+ return;
+ }
+ ldo5v_on_cnt = 0;
+ usr_timer_del(__this->ldo5v_timer);
+ __this->ldo5v_timer = 0;
+ if ((charge_flag & BIT_LDO5V_IN) == 0) {
+ charge_flag = BIT_LDO5V_IN;
+ charge_event_to_user(CHARGE_EVENT_LDO5V_IN);
+ }
+ }
+ } else if (LDO5V_DET_GET() == 0) { //ldoin<拔出电压(0.6)
+ /* putchar('Q'); */
+ if (ldo5v_off_cnt < (__this->data->ldo5v_off_filter + 20)) {
+ ldo5v_off_cnt++;
+ } else {
+ /* printf("ldo5V_OFF\n"); */
+ set_charge_online_flag(0);
+ ldo5v_on_cnt = 0;
+ ldo5v_keep_cnt = 0;
+ //消息线程未准备好接收消息,继续扫描
+ if (__this->charge_event_flag == 0) {
+ return;
+ }
+ ldo5v_off_cnt = 0;
+ usr_timer_del(__this->ldo5v_timer);
+ __this->ldo5v_timer = 0;
+ if ((charge_flag & BIT_LDO5V_OFF) == 0) {
+ charge_flag = BIT_LDO5V_OFF;
+ charge_event_to_user(CHARGE_EVENT_LDO5V_OFF);
+ }
+ }
+ } else { //拔出电压(0.6左右)< ldoin < vbat
+ /* putchar('E'); */
+ if (ldo5v_keep_cnt < __this->data->ldo5v_keep_filter) {
+ ldo5v_keep_cnt++;
+ } else {
+ /* printf("ldo5V_ERR\n"); */
+ set_charge_online_flag(1);
+ ldo5v_off_cnt = 0;
+ ldo5v_on_cnt = 0;
+ //消息线程未准备好接收消息,继续扫描
+ if (__this->charge_event_flag == 0) {
+ return;
+ }
+ ldo5v_keep_cnt = 0;
+ usr_timer_del(__this->ldo5v_timer);
+ __this->ldo5v_timer = 0;
+ if ((charge_flag & BIT_LDO5V_KEEP) == 0) {
+ charge_flag = BIT_LDO5V_KEEP;
+ if (__this->data->ldo5v_off_filter) {
+ charge_event_to_user(CHARGE_EVENT_LDO5V_KEEP);
+ }
+ }
+ }
+ }
+}
+
+void ldoin_wakeup_isr(void)
+{
+ if (!__this->init_ok) {
+ return;
+ }
+ /* printf(" %s \n", __func__); */
+ if (__this->ldo5v_timer == 0) {
+ __this->ldo5v_timer = usr_timer_add(0, ldo5v_detect, 2, 1);
+ }
+}
+
+void charge_wakeup_isr(void)
+{
+ if (!__this->init_ok) {
+ return;
+ }
+ /* printf(" %s \n", __func__); */
+ if (__this->charge_timer == 0) {
+ __this->charge_timer = usr_timer_add(0, charge_full_detect, 2, 1);
+ }
+}
+
+void charge_set_ldo5v_detect_stop(u8 stop)
+{
+ __this->detect_stop = stop;
+}
+
+u8 get_charge_mA_config(void)
+{
+ return __this->data->charge_mA;
+}
+
+void set_charge_mA(u8 charge_mA)
+{
+ static u8 charge_mA_old = 0xff;
+ if (charge_mA_old != charge_mA) {
+ charge_mA_old = charge_mA;
+ if (charge_mA & BIT(4)) {
+ CHG_TRICKLE_EN(1);
+ } else {
+ CHG_TRICKLE_EN(0);
+ }
+ CHARGE_mA_SEL(charge_mA & 0x0F);
+ }
+}
+
+const u16 full_table[CHARGE_FULL_V_MAX] = {
+ 4041, 4061, 4081, 4101, 4119, 4139, 4159, 4179,
+ 4199, 4219, 4238, 4258, 4278, 4298, 4318, 4338,
+ 4237, 4257, 4275, 4295, 4315, 4335, 4354, 4374,
+ 4394, 4414, 4434, 4454, 4474, 4494, 4514, 4534,
+};
+u16 get_charge_full_value(void)
+{
+ ASSERT(__this->init_ok, "charge not init ok!\n");
+ ASSERT(__this->data->charge_full_V < CHARGE_FULL_V_MAX);
+ return full_table[__this->data->charge_full_V];
+}
+
+static void charge_config(void)
+{
+ u8 charge_trim_val;
+ u8 offset = 0;
+ u8 charge_full_v_val = 0;
+ //判断是用高压档还是低压档
+ if (__this->data->charge_full_V < CHARGE_FULL_V_4237) {
+ CHG_HV_MODE(0);
+ charge_trim_val = get_vbat_trim();//4.20V对应的trim出来的实际档位
+ if (charge_trim_val == 0xf) {
+ log_info("vbat low not trim, use default config!!!!!!");
+ charge_trim_val = CHARGE_FULL_V_4199;
+ }
+ log_info("low charge_trim_val = %d\n", charge_trim_val);
+ if (__this->data->charge_full_V >= CHARGE_FULL_V_4199) {
+ offset = __this->data->charge_full_V - CHARGE_FULL_V_4199;
+ charge_full_v_val = charge_trim_val + offset;
+ if (charge_full_v_val > 0xf) {
+ charge_full_v_val = 0xf;
+ }
+ } else {
+ offset = CHARGE_FULL_V_4199 - __this->data->charge_full_V;
+ if (charge_trim_val >= offset) {
+ charge_full_v_val = charge_trim_val - offset;
+ } else {
+ charge_full_v_val = 0;
+ }
+ }
+ } else {
+ CHG_HV_MODE(1);
+ charge_trim_val = get_vbat_trim_435();//4.35V对应的trim出来的实际档位
+ if (charge_trim_val == 0xf) {
+ log_info("vbat high not trim, use default config!!!!!!");
+ charge_trim_val = CHARGE_FULL_V_4354 - 16;
+ }
+ log_info("high charge_trim_val = %d\n", charge_trim_val);
+ if (__this->data->charge_full_V >= CHARGE_FULL_V_4354) {
+ offset = __this->data->charge_full_V - CHARGE_FULL_V_4354;
+ charge_full_v_val = charge_trim_val + offset;
+ if (charge_full_v_val > 0xf) {
+ charge_full_v_val = 0xf;
+ }
+ } else {
+ offset = CHARGE_FULL_V_4354 - __this->data->charge_full_V;
+ if (charge_trim_val >= offset) {
+ charge_full_v_val = charge_trim_val - offset;
+ } else {
+ charge_full_v_val = 0;
+ }
+ }
+ }
+
+ log_info("charge_full_v_val = %d\n", charge_full_v_val);
+
+ CHARGE_FULL_V_SEL(charge_full_v_val);
+ CHARGE_FULL_mA_SEL(__this->data->charge_full_mA);
+ set_charge_mA(__this->data->charge_trickle_mA);
+}
+
+int charge_init(const struct dev_node *node, void *arg)
+{
+ log_info("%s\n", __func__);
+
+ __this->data = (struct charge_platform_data *)arg;
+
+ ASSERT(__this->data);
+
+ __this->init_ok = 0;
+ __this->charge_online_flag = 0;
+
+ /*先关闭充电使能,后面检测到充电插入再开启*/
+ power_awakeup_gpio_enable(IO_CHGFL_DET, 0);
+ CHARGE_EN(0);
+ CHGGO_EN(0);
+
+ /*LDO5V的100K下拉电阻使能*/
+ L5V_RES_DET_S_SEL(__this->data->ldo5v_pulldown_lvl);
+ L5V_LOAD_EN(__this->data->ldo5v_pulldown_en);
+
+ charge_config();
+
+ if (check_charge_state()) {
+ if (__this->ldo5v_timer == 0) {
+ __this->ldo5v_timer = usr_timer_add(0, ldo5v_detect, 2, 1);
+ }
+ } else {
+ charge_flag = BIT_LDO5V_OFF;
+ }
+
+ __this->init_ok = 1;
+
+ return 0;
+}
+
+void charge_module_stop(void)
+{
+ if (!__this->init_ok) {
+ return;
+ }
+ charge_close();
+ power_awakeup_index_enable(IO_LDOIN_DET, 0);
+ power_awakeup_index_enable(IO_VBTCH_DET, 0);
+ if (__this->ldo5v_timer) {
+ usr_timer_del(__this->ldo5v_timer);
+ __this->ldo5v_timer = 0;
+ }
+}
+
+void charge_module_restart(void)
+{
+ if (!__this->init_ok) {
+ return;
+ }
+ if (!__this->ldo5v_timer) {
+ __this->ldo5v_timer = usr_timer_add(NULL, ldo5v_detect, 2, 1);
+ }
+ power_awakeup_index_enable(IO_LDOIN_DET, 1);
+ power_awakeup_index_enable(IO_VBTCH_DET, 1);
+}
+
+const struct device_operations charge_dev_ops = {
+ .init = charge_init,
+};
diff --git a/cpu/br28/chargestore.c b/cpu/br28/chargestore.c
new file mode 100644
index 0000000..77205e5
--- /dev/null
+++ b/cpu/br28/chargestore.c
@@ -0,0 +1,335 @@
+#include "generic/typedef.h"
+#include "generic/gpio.h"
+#include "asm/power/p33.h"
+#include "asm/power/p33_app.h"
+#include "asm/hwi.h"
+#include "asm/gpio.h"
+#include "asm/clock.h"
+#include "asm/charge.h"
+#include "asm/chargestore.h"
+#include "update.h"
+#include "app_config.h"
+
+#if (TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE)
+struct chargestore_handle {
+ const struct chargestore_platform_data *data;
+ JL_UART_TypeDef *UART;
+ u32 baudrate;
+};
+#define DMA_ISR_LEN 64
+#define DMA_BUF_LEN 64
+#define __this (&hdl)
+static struct chargestore_handle hdl;
+u8 uart_dma_buf[DMA_BUF_LEN] __attribute__((aligned(4)));
+volatile u8 send_busy;
+
+//串口时钟和串口超时时钟是分开的
+#define UART_SRC_CLK clk_get("uart")
+#define UART_OT_CLK clk_get("lsb")
+
+enum {
+ UPGRADE_NULL = 0,
+ UPGRADE_USB_HARD_KEY,
+ UPGRADE_USB_SOFTKEY,
+ UPGRADE_UART_SOFT_KEY,
+ UPGRADE_UART_ONE_WIRE_HARD_KEY,
+};
+extern void charge_reset_pb5_pd_status(void);
+extern void nvram_set_boot_state(u32 state);
+void update_param_boot_ram_set(u8 *buf, u16 len);
+
+void chargestore_set_update_ram(void)
+{
+ //需要补充设置ram
+ int tmp;
+ __asm__ volatile("%0 =icfg" : "=r"(tmp));
+ tmp &= ~(3 << 8);
+ __asm__ volatile("icfg = %0" :: "r"(tmp));//GIE1
+ local_irq_disable();
+#if TCFG_TEST_BOX_ANY_IO_UPDATE
+ update_param_boot_ram_set("UART_UPDATE_CUSTOM", sizeof("UART_UPDATE_CUSTOM"));
+#else
+ nvram_set_boot_state(UPGRADE_UART_SOFT_KEY);
+#endif
+}
+
+void __attribute__((weak)) chargestore_data_deal(u8 cmd, u8 *data, u8 len)
+{
+
+}
+
+void __attribute__((weak)) chargestore_uart_data_deal(u8 *data, u8 len)
+{
+
+}
+
+static u8 chargestore_get_f95_det_res(u32 equ_res)
+{
+ u8 det_res = (equ_res + 50) / 100;
+ if (det_res > 0) {
+ det_res -= 1;
+ }
+ if (det_res > 0x0f) {
+ det_res = 0x0f;
+ }
+ return det_res;
+}
+
+//br30(PMU数据未知,IC还未给出测试数据,说是和BR23基本一致)
+u8 chargestore_get_det_level(u8 chip_type)
+{
+ u32 res = 1600;
+ switch (chip_type) {
+ case TYPE_F95:
+ if (IS_L5V_LOAD_EN()) {
+ res = (GET_L5V_RES_DET_S_SEL() + 1) * 50;
+ }
+ return chargestore_get_f95_det_res(res);
+ case TYPE_NORMAL:
+ default:
+ return 0x0f;
+ }
+}
+
+___interrupt
+static void uart_isr(void)
+{
+ u16 i;
+ u32 rx_len = 0;
+ if (__this->data->io_port == IO_PORT_DP) {
+ //测试盒选DP,跟USB功能复用
+ local_irq_disable();
+ }
+ if ((__this->UART->CON0 & BIT(2)) && (__this->UART->CON0 & BIT(15))) {
+ __this->UART->CON0 |= BIT(13);
+ send_busy = 0;
+ chargestore_data_deal(CMD_COMPLETE, NULL, 0);
+ }
+ if ((__this->UART->CON0 & BIT(3)) && (__this->UART->CON0 & BIT(14))) {
+ __this->UART->CON0 |= BIT(12);//清RX PND
+ chargestore_data_deal(CMD_RECVDATA, uart_dma_buf, DMA_ISR_LEN);
+ memset((void *)uart_dma_buf, 0, sizeof(uart_dma_buf));
+ __this->UART->RXSADR = (u32)uart_dma_buf;
+ __this->UART->RXEADR = (u32)(uart_dma_buf + DMA_BUF_LEN);
+ __this->UART->RXCNT = DMA_ISR_LEN;
+ }
+ if ((__this->UART->CON0 & BIT(5)) && (__this->UART->CON0 & BIT(11))) {
+ //OTCNT PND
+ __this->UART->CON0 |= BIT(7);//DMA模式
+ __this->UART->CON0 |= BIT(10);//清OTCNT PND
+ asm volatile("nop");
+ rx_len = __this->UART->HRXCNT;//读当前串口接收数据的个数
+ __this->UART->CON0 |= BIT(12);//清RX PND(这里的顺序不能改变,这里要清一次)
+ chargestore_data_deal(CMD_RECVDATA, uart_dma_buf, rx_len);
+ chargestore_uart_data_deal(uart_dma_buf, rx_len);
+ memset((void *)uart_dma_buf, 0, sizeof(uart_dma_buf));
+ __this->UART->RXSADR = (u32)uart_dma_buf;
+ __this->UART->RXEADR = (u32)(uart_dma_buf + DMA_BUF_LEN);
+ __this->UART->RXCNT = DMA_ISR_LEN;
+ }
+ if (__this->data->io_port == IO_PORT_DP) {
+ //测试盒选DP,跟USB功能复用
+ local_irq_enable();
+ }
+}
+
+void chargestore_write(u8 *data, u8 len)
+{
+ ASSERT(((u32)data) % 4 == 0); //4byte对齐
+ send_busy = 1;
+ __this->UART->TXADR = (u32)data;
+ __this->UART->TXCNT = len;
+}
+
+void chargestore_open(u8 mode)
+{
+ __this->UART->CON0 = BIT(13) | BIT(12) | BIT(10);
+ if (mode == MODE_RECVDATA) {
+ charge_set_ldo5v_detect_stop(0);
+ gpio_direction_input(__this->data->io_port);
+ gpio_set_die(__this->data->io_port, 1);
+ __this->UART->CON1 &= ~BIT(4);
+ if (__this->UART == JL_UART0) {
+ gpio_set_fun_input_port(__this->data->io_port, PFI_UART0_RX, LOW_POWER_FREE);
+ } else if (__this->UART == JL_UART1) {
+ gpio_set_fun_input_port(__this->data->io_port, PFI_UART1_RX, LOW_POWER_FREE);
+ } else {
+ gpio_set_fun_input_port(__this->data->io_port, PFI_UART2_RX, LOW_POWER_FREE);
+ }
+ memset((void *)uart_dma_buf, 0, sizeof(uart_dma_buf));
+ __this->UART->RXSADR = (u32)uart_dma_buf;
+ __this->UART->RXEADR = (u32)(uart_dma_buf + DMA_BUF_LEN);
+ __this->UART->RXCNT = DMA_ISR_LEN;
+ __this->UART->CON0 |= BIT(6) | BIT(5) | BIT(3);
+ } else {
+ charge_set_ldo5v_detect_stop(1);
+ gpio_direction_output(__this->data->io_port, 1);
+ gpio_set_hd(__this->data->io_port, 1);
+ __this->UART->CON1 |= BIT(4);
+ if (__this->UART == JL_UART0) {
+ gpio_set_fun_output_port(__this->data->io_port, FO_UART0_TX, 1, 1, LOW_POWER_FREE);
+ } else if (__this->UART == JL_UART1) {
+ gpio_set_fun_output_port(__this->data->io_port, FO_UART1_TX, 1, 1, LOW_POWER_FREE);
+ } else {
+ gpio_set_fun_output_port(__this->data->io_port, FO_UART2_TX, 1, 1, LOW_POWER_FREE);
+
+ }
+ __this->UART->CON0 |= BIT(2);
+ }
+ __this->UART->CON0 |= BIT(13) | BIT(12) | BIT(10) | BIT(1) | BIT(0);
+}
+
+void chargestore_close(void)
+{
+ __this->UART->CON0 = BIT(13) | BIT(12) | BIT(10) | BIT(0);
+ gpio_set_pull_down(__this->data->io_port, 0);
+ gpio_set_pull_up(__this->data->io_port, 0);
+ gpio_set_die(__this->data->io_port, 1);
+ gpio_set_hd(__this->data->io_port, 0);
+ gpio_direction_input(__this->data->io_port);
+ memset((void *)uart_dma_buf, 0, sizeof(uart_dma_buf));
+ charge_set_ldo5v_detect_stop(0);
+}
+
+void chargestore_set_baudrate(u32 baudrate)
+{
+ u32 uart_timeout;
+ __this->baudrate = baudrate;
+ uart_timeout = 20 * 1000000 / __this->baudrate;
+ __this->UART->OTCNT = uart_timeout * (UART_OT_CLK / 1000000);
+ __this->UART->BAUD = (UART_SRC_CLK / __this->baudrate) / 4 - 1;
+}
+
+#if 0
+void chargestore_init(const struct chargestore_platform_data *data)
+{
+ u32 uart_timeout;
+ __this->data = (struct chargestore_platform_data *)data;
+ ASSERT(data);
+ switch (__this->data->uart_irq) {
+ case IRQ_UART0_IDX:
+ __this->UART = JL_UART0;
+ break;
+ case IRQ_UART1_IDX:
+ __this->UART = JL_UART1;
+ break;
+ default:
+ ASSERT(0, "uart irq(%d) err!\n", __this->data->uart_irq);
+ break;
+ }
+ if (__this->UART->CON0 & BIT(0)) {
+ ASSERT(0, "uart used!\n");
+ }
+ uart_timeout = 20 * 1000000 / __this->data->baudrate;
+ __this->UART->CON0 = BIT(13) | BIT(12) | BIT(10);
+ __this->UART->OTCNT = uart_timeout * (clk_get("uart") / 1000000);
+ __this->UART->BAUD = (clk_get("uart") / __this->data->baudrate) / 4 - 1;
+ __this->UART->CON1 = (((clk_get("uart") / __this->data->baudrate) % 4) << 4);
+ gpio_set_pull_down(__this->data->io_port, 0);
+ gpio_set_pull_up(__this->data->io_port, 0);
+ gpio_set_die(__this->data->io_port, 1);
+ gpio_direction_input(__this->data->io_port);
+ request_irq(__this->data->uart_irq, 2, uart_isr, 0);
+ JL_IOMAP->CON1 &= ~(0xf << 8);
+ //约定:
+ //使用UART0时,使用output channel0 和 input channel 0
+ //使用UART1时,使用output channel1 和 input channel 1 //由于irflt需要用到INPUT_CH1,所以串口1输入改成INPUT_CH3
+ if (__this->UART == JL_UART0) {
+ //不占用IO
+ JL_IOMAP->CON3 &= ~BIT(3);
+ //100:input channel0
+ //101:input channel1
+ //110:input channel2
+ //111:input channel3
+ JL_IOMAP->CON3 &= ~(0b111 << 0);
+ JL_IOMAP->CON3 |= (0b100 << 0);
+ //[29:24]:input channel 3 io sel
+ //[21:16]:input channel 2 io sel
+ //[13:08]:input channel 1 io sel
+ //[05:00]:input channel 0 io sel
+ JL_IOMAP->CON2 &= ~(0b111111 << 0);
+ JL_IOMAP->CON2 |= (__this->data->io_port << 0);
+ //000:output channel 0 sel UT0_TX
+ //001:output channel 0 sel UT1_TX
+ JL_IOMAP->CON1 &= ~(0b1111 << 8);
+ JL_IOMAP->CON1 |= (0 << 8);//outchl0 -> ut0_tx
+ } else {
+ //不占用IO
+ JL_IOMAP->CON3 &= ~BIT(7);
+ //100:input channel0
+ //101:input channel1
+ //110:input channel2
+ //111:input channel3
+ JL_IOMAP->CON3 &= ~(0b111 << 4);
+ JL_IOMAP->CON3 |= (0b111 << 4);
+ //[29:24]:input channel 3 io sel
+ //[21:16]:input channel 2 io sel
+ //[13:08]:input channel 1 io sel
+ //[05:00]:input channel 0 io sel
+ JL_IOMAP->CON2 &= ~(0b111111 << 24);
+ JL_IOMAP->CON2 |= (__this->data->io_port << 24);
+ //000:output channel 1 sel UT0_TX
+ //001:output channel 1 sel UT1_TX
+ JL_IOMAP->CON3 &= ~(0b1111 << 20);
+ JL_IOMAP->CON3 |= (1 << 20);//outchl1 -> ut1_tx
+ }
+}
+#endif
+
+#if 1
+void chargestore_init(const struct chargestore_platform_data *data)
+{
+ u32 uart_timeout;
+ __this->data = (struct chargestore_platform_data *)data;
+ ASSERT(data);
+ if (!(JL_UART0->CON0 & BIT(0))) {
+ JL_UART0->CON0 = BIT(13) | BIT(12) | BIT(10);
+ request_irq(IRQ_UART0_IDX, 2, uart_isr, 0);
+ __this->UART = JL_UART0;
+ } else if (!(JL_UART1->CON0 & BIT(0))) {
+ JL_UART1->CON0 = BIT(13) | BIT(12) | BIT(10);
+ request_irq(IRQ_UART1_IDX, 2, uart_isr, 0);
+ __this->UART = JL_UART1;
+ } else if (!(JL_UART2->CON0 & BIT(0))) {
+ JL_UART2->CON0 = BIT(13) | BIT(12) | BIT(10);
+ request_irq(IRQ_UART2_IDX, 2, uart_isr, 0);
+ __this->UART = JL_UART2;
+ } else {
+ ASSERT(0, "uart all used!\n");
+ }
+ send_busy = 0;
+ uart_timeout = 20 * 1000000 / __this->data->baudrate;
+ __this->UART->CON0 = BIT(13) | BIT(12) | BIT(10) | BIT(1) | BIT(0);//占用该串口,不被其他模块使用
+ __this->UART->OTCNT = uart_timeout * (UART_OT_CLK / 1000000);
+ __this->UART->BAUD = (UART_SRC_CLK / __this->data->baudrate) / 4 - 1;
+ __this->baudrate = __this->data->baudrate;
+ gpio_set_pull_down(__this->data->io_port, 0);
+ gpio_set_pull_up(__this->data->io_port, 0);
+ gpio_set_die(__this->data->io_port, 1);
+ gpio_direction_input(__this->data->io_port);
+}
+#endif
+
+static void clock_critical_enter(void)
+{
+ u8 cmp_buf[2] = {0x55, 0xAA};
+ //等待数据收完
+ extern void *memmem(void *srcmem, int src_len, void *desmem, int des_len);
+ while (memmem(uart_dma_buf, sizeof(uart_dma_buf), cmp_buf, sizeof(cmp_buf)));
+ //等待数据发完
+ while (send_busy);
+}
+static void clock_critical_exit(void)
+{
+ u32 uart_timeout;
+ if (__this->UART == NULL) {
+ return;
+ }
+ uart_timeout = 20 * 1000000 / __this->baudrate;
+ __this->UART->OTCNT = uart_timeout * (UART_OT_CLK / 1000000);
+ __this->UART->BAUD = (UART_SRC_CLK / __this->baudrate) / 4 - 1;
+}
+CLOCK_CRITICAL_HANDLE_REG(chargestore, clock_critical_enter, clock_critical_exit)
+
+#endif
+
diff --git a/cpu/br28/clock_cfg.h b/cpu/br28/clock_cfg.h
new file mode 100644
index 0000000..c5347d6
--- /dev/null
+++ b/cpu/br28/clock_cfg.h
@@ -0,0 +1,118 @@
+#ifndef CLOCK_CFG_H
+#define CLOCK_CFG_H
+
+#include "typedef.h"
+/*
+
+ */
+
+
+enum {
+
+ BT_IDLE_CLOCK = 1,
+ MUSIC_IDLE_CLOCK,
+ FM_IDLE_CLOCK,
+ LINEIN_IDLE_CLOCK,
+ PC_IDLE_CLOCK,
+ REC_IDLE_CLOCK,
+ RTC_IDLE_CLOCK,
+ SPDIF_IDLE_CLOCK,
+ BOX_IDLE_CLOCK,
+
+
+ DEC_SBC_CLK ,
+ DEC_AAC_CLK ,
+ DEC_MSBC_CLK,
+ DEC_CVSD_CLK,
+
+ AEC8K_CLK ,
+ AEC8K_ADV_CLK,
+ AEC16K_CLK ,
+ AEC16K_ADV_CLK,
+ AEC8K_SPX_CLK,
+ AEC16K_SPX_CLK,
+
+ DEC_TONE_CLK,
+ DEC_MP3_CLK ,
+ DEC_WAV_CLK , /// 10
+ DEC_G729_CLK,
+ DEC_G726_CLK,
+ DEC_PCM_CLK ,
+ DEC_MTY_CLK ,
+ DEC_WMA_CLK ,
+
+ DEC_APE_CLK ,
+ DEC_FLAC_CLK,
+ DEC_AMR_CLK ,
+ DEC_DTS_CLK ,
+
+ DEC_M4A_CLK , ///20
+ DEC_ALAC_CLK,
+ DEC_FM_CLK ,
+ DEC_LINE_CLK,
+ DEC_TWS_SBC_CLK,
+ SPDIF_CLK ,
+
+ ENC_RECODE_CLK,
+ ENC_SBC_CLK ,
+ ENC_WAV_CLK ,
+ ENC_G726_CLK,
+ ENC_MP3_CLK ,
+ ENC_TWS_SBC_CLK,
+
+ ENC_MSBC_CLK, //////30
+ ENC_CVSD_CLK,
+ SYNC_CLK ,
+ AUTOMUTE_CLK ,
+ FINDF_CLK ,
+ FM_INSIDE_CLK,
+ BT_CONN_CLK ,
+
+ EQ_CLK ,
+ EQ_DRC_CLK ,
+ EQ_ONLINE_CLK,
+ REVERB_CLK ,
+ REVERB_HOWLING_CLK,
+ REVERB_PITCH_CLK,
+
+ DEC_MP3PICK_CLK ,
+ DEC_WMAPICK_CLK ,
+ DEC_M4APICK_CLK ,
+ DEC_MIX_CLK,
+
+ DEC_IIS_CLK,
+ DEC_UI_CLK,
+ DEC_MIDI_CLK,
+
+ DEC_3D_CLK,
+ DEC_VBASS_CLK,
+ DEC_LOUDNES_CLK,
+
+ DONGLE_ENC_CLK,
+
+ LCD_UI_CLK,
+ SCAN_DISK_CLK,
+ SPECTRUM_CLK,
+
+ LOCALTWS_CLK,
+
+ AI_SPEECH_CLK,
+ SMARTBOX_ACTION_CLK,
+
+ ADAPTER_PROCESS_CLK,
+
+ ENUM_MAX_CLK = 63 ,
+};
+
+void clock_pause_play(u8 mode);
+
+
+void clock_idle(u32 type);
+void clock_add(u32 type);
+void clock_remove(u32 type);
+void clock_set_cur(void);
+void clock_add_set(u32 type);
+void clock_remove_set(u32 type);
+
+
+#endif
diff --git a/cpu/br28/clock_manager.c b/cpu/br28/clock_manager.c
new file mode 100644
index 0000000..d98d894
--- /dev/null
+++ b/cpu/br28/clock_manager.c
@@ -0,0 +1,411 @@
+#include "system/includes.h"
+#include "app_config.h"
+#include "clock_cfg.h"
+#include "asm/dac.h"
+struct clock_type {
+ u8 type;
+ u32 clock;
+ const char *name;
+};
+
+/*****
+
+idle clk : 模式里面的空闲时钟
+
+时钟通过idle clk 加上每一种解码或者运算的时钟
+累加总和来设置需要的时钟
+
+模式空闲时钟设置
+void clock_idle(u32 type)
+
+
+把时钟设置加入到ext中,但是不是立刻设置时钟
+需要最后调用clock_set_cur来最后设置时钟
+用于连续地方设置时钟
+用完后必须把时钟remove
+void clock_add(u32 type)
+void clock_remove(u32 type)
+void clock_set_cur(void)
+
+
+把时钟设置加入到ext中,立刻设置时钟
+需要立刻添加时钟
+用完后必须把时钟remove
+void clock_add_set(u32 type)
+void clock_remove_set(u32 type)
+
+*****/
+
+//// 如果clock_fix 为0 就按照配置设置时钟,如果有值就固定频率
+#if TCFG_MIC_EFFECT_ENABLE
+#define CLOCK_FIX (192)
+#else
+#define CLOCK_FIX 0
+#endif
+
+#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_FRONT_LR_REAR_LR) && TCFG_EQ_DIVIDE_ENABLE
+#define EQ4_CLK (24)
+#else
+#define EQ4_CLK (0)
+#endif
+
+#if TCFG_EQ_ONLINE_ENABLE
+#define EQ_ONLINE_CLK (64)
+#else
+#define EQ_ONLINE_CLK (0)
+#endif
+
+#define MIX_SRC_CLK (24)//src
+
+const struct clock_type clock_enum[] = {
+
+ { BT_IDLE_CLOCK , (24), " BT_IDLE_CLOCK " },
+#ifndef CONFIG_SOUNDBOX_FLASH_256K
+ { MUSIC_IDLE_CLOCK , (24), " MUSIC_IDLE_CLOCK " },
+ { FM_IDLE_CLOCK , (12), " FM_IDLE_CLOCK " },
+ { LINEIN_IDLE_CLOCK , (96), " LINEIN_IDLE_CLOCK " },
+ { PC_IDLE_CLOCK , (120), " PC_IDLE_CLOCK " },
+ { REC_IDLE_CLOCK , (12), " REC_IDLE_CLOCK " },
+ { RTC_IDLE_CLOCK , (12), " RTC_IDLE_CLOCK " },
+ { SPDIF_IDLE_CLOCK , (12), " SPDIF_IDLE_CLOCK " },
+ { BOX_IDLE_CLOCK , (24), " BOX_IDLE_CLOCK " },
+
+
+ { DEC_SBC_CLK , (32), "DEC_SBC_CLK " },
+ { DEC_AAC_CLK , (32), "DEC_AAC_CLK " },
+#endif
+ { DEC_MSBC_CLK , (12), "DEC_MSBC_CLK " },
+ { DEC_CVSD_CLK , (8), "DEC_CVSD_CLK " },
+
+ { AEC8K_CLK , (10), "AEC8K_CLK " },
+ { AEC8K_ADV_CLK , (50), "AEC8K_ADV_CLK " },
+ { AEC16K_CLK , (10), "AEC16K_CLK " },
+ { AEC16K_ADV_CLK, (50), "AEC16K_ADV_CLK " },
+ { AEC8K_SPX_CLK , (10), "AEC8K_SPX_CLK " },
+ { AEC16K_SPX_CLK, (10), "AEC16K_SPX_CLK " },
+
+ { DEC_TONE_CLK , (24 + 32), "DEC_TONE_CLK " },
+ { DEC_G729_CLK , (24), "DEC_G729_CLK " },
+ { DEC_PCM_CLK , (24), "DEC_PCM_CLK " },
+#ifndef CONFIG_SOUNDBOX_FLASH_256K
+ { DEC_MP3_CLK , (80), "DEC_MP3_CLK " },
+ { DEC_WAV_CLK , (32), "DEC_WAV_CLK " },
+ { DEC_G726_CLK , (24), "DEC_G726_CLK " },
+ { DEC_MTY_CLK , (24), "DEC_MTY_CLK " },
+ { DEC_WMA_CLK , (48), "DEC_WMA_CLK " },
+
+ { DEC_APE_CLK , (160), "DEC_APE_CLK "},
+ { DEC_FLAC_CLK , (96), "DEC_FLAC_CLK "},
+ { DEC_AMR_CLK , (96), "DEC_AMR_CLK "},
+ { DEC_DTS_CLK , (120), "DEC_DTS_CLK " },
+
+ { DEC_M4A_CLK , (48), "DEC_M4A_CLK "},
+ { DEC_ALAC_CLK , (48), "DEC_ALAC_CLK "},
+ { DEC_FM_CLK , (12), "DEC_FM_CLK " },
+ { DEC_LINE_CLK , (24), "DEC_LINE_CLK " },
+ { DEC_TWS_SBC_CLK, (32), "DEC_TWS_SBC_CLK" },
+ { SPDIF_CLK , (120), "SPDIF_CLK " },
+
+ { ENC_RECODE_CLK, (64), "ENC_RECODE_CLK " },
+ { ENC_SBC_CLK , (64), "ENC_SBC_CLK " },
+ { ENC_WAV_CLK , (96), "ENC_WAV_CLK " },
+ { ENC_G726_CLK, (64), "ENC_G726_CLK " },
+ { ENC_MP3_CLK , (120), "ENC_MP3_CLK " },
+ { ENC_TWS_SBC_CLK, (48), "ENC_TWS_SBC_CLK" },
+#endif
+ { ENC_MSBC_CLK , (12), "ENC_MSBC_CLK " },
+ { ENC_CVSD_CLK , (8), "ENC_CVSD_CLK " },
+
+ { SYNC_CLK , (4), "SYNC_CLK " },
+ { AUTOMUTE_CLK , (16), "AUTOMUTE_CLK" },
+
+#ifndef CONFIG_SOUNDBOX_FLASH_256K
+ { FINDF_CLK , (120), "FINDF_CLK " },
+ { FM_INSIDE_CLK , (96), "FM_INSIDE_CLK " },
+#endif
+#if TCFG_DEC2TWS_ENABLE
+ { BT_CONN_CLK , (48), "BT_CONN_CLK " },
+#else
+ { BT_CONN_CLK , (16), "BT_CONN_CLK " },
+#endif
+
+
+ { EQ_CLK , (24 + EQ_ONLINE_CLK + EQ4_CLK), " EQ_CLK " },
+ { EQ_DRC_CLK , (60), " EQ_DRC_CLK " },
+ /* { EQ_ONLINE_CLK, (120), " EQ_ONLINE_CLK " }, */
+#ifndef CONFIG_SOUNDBOX_FLASH_256K
+ { REVERB_CLK , (64), " REVERB_CLK " },
+ { REVERB_HOWLING_CLK , (32), " REVERB_HOWLING_CLK " },
+ { REVERB_PITCH_CLK , (24), " REVERB_PITCH_CLK " },
+
+ { DEC_MP3PICK_CLK, (8), "DEC_MP3PICK_CLK" },
+ { DEC_WMAPICK_CLK, (8), "DEC_WMAICK_CLK" },
+ { DEC_M4APICK_CLK, (8), "DEC_M4AICK_CLK" },
+#endif
+ { DEC_MIX_CLK, (6 + MIX_SRC_CLK), "DEC_MIX_CLK" },
+
+ { DEC_UI_CLK, (160), "DEC_UI_CLK" },
+#ifndef CONFIG_SOUNDBOX_FLASH_256K
+ { DEC_IIS_CLK, (64), "DEC_IIS_CLK" },
+
+ //midi音色文件跳转读取频繁,外挂flash baud 调到6000000L, midi_clk 80M就够
+ { DEC_MIDI_CLK, (110), "DEC_MIDI_CLK" },
+ /* { DEC_MIDI_CLK, (80), "DEC_MIDI_CLK" }, */
+
+ { DEC_3D_CLK, (24), "DEC_3D_CLK" },
+ { DEC_VBASS_CLK, (8), "DEC_VBASS_CLK" },
+ { DEC_LOUDNES_CLK, (108), "DEC_LOUDNES_CLK"},
+
+ { DONGLE_ENC_CLK, (48), "DONGLE_ENC_CLK" },
+#endif
+
+ { SCAN_DISK_CLK, (120), "SCAN_DISK_CLK" },//提高扫盘速度
+
+#if TCFG_DEC2TWS_ENABLE
+ { LOCALTWS_CLK, (24), "LOCALTWS_CLK" },
+#endif
+ {SPECTRUM_CLK, (5), "SPECTRUM_CLK" },
+
+ {AI_SPEECH_CLK, (120), "AI_SPEECH_CLK" },
+ {SMARTBOX_ACTION_CLK, (160), "SMARTBOX_ACTION_CLK" },
+
+#ifdef CONFIG_ADAPTER_ENABLE
+ {ADAPTER_PROCESS_CLK, (64), "ADAPTER_PROCESS_CLK" },
+#endif
+};
+
+
+
+#if (defined(TCFG_CLOCK_PLL_240MHZ) && TCFG_CLOCK_PLL_240MHZ)
+static int hsb_clock_init(void)
+{
+ clock_set_pll_target_frequency(240);
+ return 0;
+}
+platform_initcall(hsb_clock_init);
+
+const u8 clock_tb[] = {
+ 24,
+ 32,
+ 48,
+ 80,
+ 96,
+ 120,
+ 160,
+};
+#else /* #if TCFG_CLOCK_PLL_240MHZ */
+const u8 clock_tb[] = {
+ 24,
+ 32,
+ 48,
+ 64,
+ 96,
+ 128,
+ 160,
+};
+#endif /* #if TCFG_CLOCK_PLL_240MHZ */
+
+static u8 ext_clk_tb[10];
+static u32 idle_type = 0;
+
+static void clock_ext_dump()
+{
+ u8 i, j;
+ for (i = 0; i < ARRAY_SIZE(clock_enum); i++) {
+ if (idle_type == clock_enum[i].type) {
+ y_printf("--- %d %s \n", clock_enum[i].clock, clock_enum[i].name);
+ break;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ext_clk_tb); i++) {
+ if (ext_clk_tb[i]) {
+ for (j = 0; j < ARRAY_SIZE(clock_enum); j++) {
+ if (ext_clk_tb[i] == clock_enum[j].type) {
+ y_printf("--- %d %s \n", clock_enum[j].clock, clock_enum[j].name);
+ continue;
+ }
+ }
+ }
+ }
+}
+
+
+u8 clock_idle_selet(u32 type)
+{
+ u8 i;
+
+#if (CLOCK_FIX )
+ return CLOCK_FIX;
+#endif
+
+ for (i = 0; i < ARRAY_SIZE(clock_enum); i++) {
+ if (type == clock_enum[i].type) {
+ /* y_printf("--- %d %s \n", clock_enum[i].clock, clock_enum[i].name); */
+ return clock_enum[i].clock;
+ }
+ }
+
+ return 24;
+}
+
+u8 clock_ext_push(u8 ext_type)
+{
+ u8 i;
+ for (i = 0; i < ARRAY_SIZE(ext_clk_tb); i++) {
+ if (ext_type == ext_clk_tb[i]) {
+ return 0;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ext_clk_tb); i++) {
+ if (!ext_clk_tb[i]) {
+ ext_clk_tb[i] = ext_type;
+ return 1;
+ }
+ }
+
+ y_printf("clock ext over!!! \n");
+ return 0;
+}
+
+u8 clock_ext_pop(u8 ext_type)
+{
+ u8 i;
+ for (i = 0; i < ARRAY_SIZE(ext_clk_tb); i++) {
+ if (ext_type == ext_clk_tb[i]) {
+ ext_clk_tb[i] = 0;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+u16 clock_match(u16 clk)
+{
+ u8 i;
+ for (i = 0; i < ARRAY_SIZE(clock_tb); i++) {
+ if (clk <= clock_tb[i]) {
+ return clock_tb[i];
+ }
+ }
+ y_printf("clock overlimit!!! %d\n", clock_tb[ARRAY_SIZE(clock_tb) - 1]);
+ return clock_tb[ARRAY_SIZE(clock_tb) - 1];
+}
+
+
+u16 clock_ext_cal()
+{
+ u32 ext_clk = 0 ;
+ u8 i, j;
+
+ for (i = 0; i < ARRAY_SIZE(ext_clk_tb); i++) {
+ if (ext_clk_tb[i]) {
+ for (j = 0; j < ARRAY_SIZE(clock_enum); j++) {
+ if (ext_clk_tb[i] == clock_enum[j].type) {
+ /* y_printf("--- %d %s \n", clock_enum[j].clock, clock_enum[j].name); */
+ ext_clk += clock_enum[j].clock;
+ continue;
+ }
+ }
+ }
+ }
+
+ return ext_clk;
+}
+
+u32 clock_cur_cal()
+{
+ u32 idle_clk, cur_clk, ext_clk;
+
+#if (CLOCK_FIX )
+ return CLOCK_FIX;
+#endif
+
+ local_irq_disable();
+ idle_clk = clock_idle_selet(idle_type);
+ ext_clk = clock_ext_cal();
+ cur_clk = idle_clk + ext_clk;
+ cur_clk = clock_match(cur_clk);
+ local_irq_enable();
+ return cur_clk ;
+}
+
+void clock_pause_play(u8 mode)
+{
+ u32 idle_clk, cur_clk ;
+ if (mode) {
+ idle_clk = clock_idle_selet(idle_type);
+ clk_set("sys", idle_clk * 1000000L);
+ } else {
+ clock_ext_dump();
+ cur_clk = clock_cur_cal();
+ clk_set("sys", cur_clk * 1000000L);
+ }
+}
+
+void clock_idle(u32 type)
+{
+ u32 cur_clk;
+ local_irq_disable();
+ idle_type = type;
+ cur_clk = clock_cur_cal();
+ local_irq_enable();
+ clock_ext_dump();
+ clk_set("sys", cur_clk * 1000000L);
+}
+
+//////把时钟设置加入到ext中,但是不是立刻设置时钟
+void clock_add(u32 type)
+{
+ u32 cur_clk ;
+ u8 resoult = clock_ext_push(type);
+ if (!resoult) {
+ return;
+ }
+}
+
+void clock_remove(u32 type)
+{
+ u32 cur_clk ;
+
+ u8 resoult = clock_ext_pop(type);
+ if (!resoult) {
+ return;
+ }
+}
+
+void clock_set_cur(void)
+{
+ u32 cur_clk ;
+ clock_ext_dump();
+ cur_clk = clock_cur_cal();
+ clk_set("sys", cur_clk * 1000000L);
+}
+
+//////把时钟设置加入到ext中,立刻设置时钟
+void clock_add_set(u32 type)
+{
+ u32 cur_clk ;
+ u8 resoult = clock_ext_push(type);
+ if (!resoult) {
+ return;
+ }
+ clock_ext_dump();
+ cur_clk = clock_cur_cal();
+ clk_set("sys", cur_clk * 1000000L);
+}
+
+void clock_remove_set(u32 type)
+{
+ u32 cur_clk ;
+
+ u8 resoult = clock_ext_pop(type);
+ if (!resoult) {
+ return;
+ }
+
+ clock_ext_dump();
+ cur_clk = clock_cur_cal();
+ clk_set("sys", cur_clk * 1000000L);
+}
diff --git a/cpu/br28/eq_config.c b/cpu/br28/eq_config.c
new file mode 100644
index 0000000..7cced63
--- /dev/null
+++ b/cpu/br28/eq_config.c
@@ -0,0 +1,697 @@
+
+#include "system/includes.h"
+#include "media/includes.h"
+#include "app_config.h"
+#include "app_online_cfg.h"
+#include "online_db/online_db_deal.h"
+#include "config/config_interface.h"
+#include "application/eq_config.h"
+#include "audio_config.h"
+#include "cfg_tool.h"
+
+#ifdef CONFIG_EQ_APP_SEG_ENABLE
+#pragma const_seg( ".eq_app_codec_const")
+#pragma code_seg ( ".eq_app_codec_code" )
+#endif
+const u8 audio_eq_sdk_name[16] = "AC701N";
+#if defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE
+const u8 audio_eq_ver[4] = {0, 8, 4, 0};//包含虚拟低音、多带drc、以及辅听耳机音效
+#else
+#if defined(TCFG_AUDIO_HEARING_AID_ENABLE) && TCFG_AUDIO_HEARING_AID_ENABLE
+const u8 audio_eq_ver[4] = {0, 8, 3, 0};
+#else
+const u8 audio_eq_ver[4] = {0, 8, 0, 0};
+#endif
+#endif /*TCFG_AUDIO_HEARING_AID_ENABLE*/
+
+#if TCFG_EQ_FILE_SWITCH_EN
+const u8 *eq_file_switch_list[] = {
+ (u8 *)SDFILE_RES_ROOT_PATH"eq_cfg_hw.bin",
+ (u8 *)SDFILE_RES_ROOT_PATH"eq_cfg_hw1.bin",
+ (u8 *)SDFILE_RES_ROOT_PATH"eq_cfg_hw2.bin",
+};
+#endif
+
+//eq_cfg_hw.bin中播歌eq曲线,当作用户自定义模式,参与效果切换.
+//通话宽频上下行eq曲线也对应放到phone_eq_tab_normal、ul_eq_tab_normal
+//EQ_FILE_CP_TO_CUSTOM 1使能时,同时板极文件中 TCFG_USE_EQ_FILE 配 0
+#define EQ_FILE_CP_TO_CUSTOM 0
+
+
+/*************************非用户配置区*************************/
+#if TCFG_EQ_ONLINE_ENABLE
+#undef EQ_FILE_CP_TO_CUSTOM
+#define EQ_FILE_CP_TO_CUSTOM 0
+#endif
+#ifndef TCFG_USER_EQ_MODE_NUM
+#define TCFG_USER_EQ_MODE_NUM 0
+#endif
+#ifndef APP_ONLINE_DEBUG
+#define APP_ONLINE_DEBUG 0
+#endif
+
+
+#ifndef TCFG_CALL_DL_EQ_SECTION
+#define TCFG_CALL_DL_EQ_SECTION 3
+#endif
+#ifndef TCFG_CALL_UL_EQ_SECTION
+#define TCFG_CALL_UL_EQ_SECTION 3
+#endif
+/*************************************************************/
+
+#if (TCFG_EQ_ENABLE != 0)
+
+#if (RCSP_ADV_EN)&&(JL_EARPHONE_APP_EN)&&(TCFG_DRC_ENABLE == 0)
+#define AUDIO_EQ_Q 1.5f
+#else
+#define AUDIO_EQ_Q 0.7f
+#endif
+
+
+#if !TCFG_USE_EQ_FILE
+const struct eq_seg_info eq_tab_normal[] = {
+#if TCFG_USER_EQ_MODE_NUM > 0
+ {0, EQ_IIR_TYPE_BAND_PASS, 31, 0, AUDIO_EQ_Q},
+ {1, EQ_IIR_TYPE_BAND_PASS, 62, 0, AUDIO_EQ_Q},
+ {2, EQ_IIR_TYPE_BAND_PASS, 125, 0, AUDIO_EQ_Q},
+ {3, EQ_IIR_TYPE_BAND_PASS, 250, 0, AUDIO_EQ_Q},
+ {4, EQ_IIR_TYPE_BAND_PASS, 500, 0, AUDIO_EQ_Q},
+ {5, EQ_IIR_TYPE_BAND_PASS, 1000, 0, AUDIO_EQ_Q},
+ {6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
+ {7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
+ {8, EQ_IIR_TYPE_BAND_PASS, 8000, 0, AUDIO_EQ_Q},
+ {9, EQ_IIR_TYPE_BAND_PASS, 16000, 0, AUDIO_EQ_Q},
+
+#if (EQ_SECTION_MAX > 10)
+ //10段之后频率值设置96k,目的是让10段之后的eq走直通
+ {10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+#endif
+
+#endif
+};
+
+const struct eq_seg_info eq_tab_rock[] = {
+
+#if TCFG_USER_EQ_MODE_NUM > 1
+ {0, EQ_IIR_TYPE_BAND_PASS, 31, -2, AUDIO_EQ_Q},
+ {1, EQ_IIR_TYPE_BAND_PASS, 62, 0, AUDIO_EQ_Q},
+ {2, EQ_IIR_TYPE_BAND_PASS, 125, 2, AUDIO_EQ_Q},
+ {3, EQ_IIR_TYPE_BAND_PASS, 250, 4, AUDIO_EQ_Q},
+ {4, EQ_IIR_TYPE_BAND_PASS, 500, -2, AUDIO_EQ_Q},
+ {5, EQ_IIR_TYPE_BAND_PASS, 1000, -2, AUDIO_EQ_Q},
+ {6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
+ {7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
+ {8, EQ_IIR_TYPE_BAND_PASS, 8000, 4, AUDIO_EQ_Q},
+ {9, EQ_IIR_TYPE_BAND_PASS, 16000, 4, AUDIO_EQ_Q},
+
+#if (EQ_SECTION_MAX > 10)
+ //10段之后频率值设置96k,目的是让10段之后的eq走直通
+ {10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+#endif
+
+#endif
+};
+
+const struct eq_seg_info eq_tab_pop[] = {
+
+#if TCFG_USER_EQ_MODE_NUM > 2
+ {0, EQ_IIR_TYPE_BAND_PASS, 31, 3, AUDIO_EQ_Q},
+ {1, EQ_IIR_TYPE_BAND_PASS, 62, 1, AUDIO_EQ_Q},
+ {2, EQ_IIR_TYPE_BAND_PASS, 125, 0, AUDIO_EQ_Q},
+ {3, EQ_IIR_TYPE_BAND_PASS, 250, -2, AUDIO_EQ_Q},
+ {4, EQ_IIR_TYPE_BAND_PASS, 500, -4, AUDIO_EQ_Q},
+ {5, EQ_IIR_TYPE_BAND_PASS, 1000, -4, AUDIO_EQ_Q},
+ {6, EQ_IIR_TYPE_BAND_PASS, 2000, -2, AUDIO_EQ_Q},
+ {7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
+ {8, EQ_IIR_TYPE_BAND_PASS, 8000, 1, AUDIO_EQ_Q},
+ {9, EQ_IIR_TYPE_BAND_PASS, 16000, 2, AUDIO_EQ_Q},
+
+#if (EQ_SECTION_MAX > 10)
+ //10段之后频率值设置96k,目的是让10段之后的eq走直通
+ {10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+#endif
+
+#endif
+};
+
+const struct eq_seg_info eq_tab_classic[] = {
+
+#if TCFG_USER_EQ_MODE_NUM > 3
+ {0, EQ_IIR_TYPE_BAND_PASS, 31, 0, AUDIO_EQ_Q},
+ {1, EQ_IIR_TYPE_BAND_PASS, 62, 8, AUDIO_EQ_Q},
+ {2, EQ_IIR_TYPE_BAND_PASS, 125, 8, AUDIO_EQ_Q},
+ {3, EQ_IIR_TYPE_BAND_PASS, 250, 4, AUDIO_EQ_Q},
+ {4, EQ_IIR_TYPE_BAND_PASS, 500, 0, AUDIO_EQ_Q},
+ {5, EQ_IIR_TYPE_BAND_PASS, 1000, 0, AUDIO_EQ_Q},
+ {6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
+ {7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
+ {8, EQ_IIR_TYPE_BAND_PASS, 8000, 2, AUDIO_EQ_Q},
+ {9, EQ_IIR_TYPE_BAND_PASS, 16000, 2, AUDIO_EQ_Q},
+
+#if (EQ_SECTION_MAX > 10)
+ //10段之后频率值设置96k,目的是让10段之后的eq走直通
+ {10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+#endif
+
+#endif
+};
+
+const struct eq_seg_info eq_tab_country[] = {
+#if TCFG_USER_EQ_MODE_NUM > 5
+ {0, EQ_IIR_TYPE_BAND_PASS, 31, -2, AUDIO_EQ_Q},
+ {1, EQ_IIR_TYPE_BAND_PASS, 62, 0, AUDIO_EQ_Q},
+ {2, EQ_IIR_TYPE_BAND_PASS, 125, 0, AUDIO_EQ_Q},
+ {3, EQ_IIR_TYPE_BAND_PASS, 250, 2, AUDIO_EQ_Q},
+ {4, EQ_IIR_TYPE_BAND_PASS, 500, 2, AUDIO_EQ_Q},
+ {5, EQ_IIR_TYPE_BAND_PASS, 1000, 0, AUDIO_EQ_Q},
+ {6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
+ {7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
+ {8, EQ_IIR_TYPE_BAND_PASS, 8000, 4, AUDIO_EQ_Q},
+ {9, EQ_IIR_TYPE_BAND_PASS, 16000, 4, AUDIO_EQ_Q},
+
+#if (EQ_SECTION_MAX > 10)
+ //10段之后频率值设置96k,目的是让10段之后的eq走直通
+ {10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+#endif
+#endif
+};
+
+const struct eq_seg_info eq_tab_jazz[] = {
+#if TCFG_USER_EQ_MODE_NUM > 4
+ {0, EQ_IIR_TYPE_BAND_PASS, 31, 0, AUDIO_EQ_Q},
+ {1, EQ_IIR_TYPE_BAND_PASS, 62, 0, AUDIO_EQ_Q},
+ {2, EQ_IIR_TYPE_BAND_PASS, 125, 0, AUDIO_EQ_Q},
+ {3, EQ_IIR_TYPE_BAND_PASS, 250, 4, AUDIO_EQ_Q},
+ {4, EQ_IIR_TYPE_BAND_PASS, 500, 4, AUDIO_EQ_Q},
+ {5, EQ_IIR_TYPE_BAND_PASS, 1000, 4, AUDIO_EQ_Q},
+ {6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
+ {7, EQ_IIR_TYPE_BAND_PASS, 4000, 2, AUDIO_EQ_Q},
+ {8, EQ_IIR_TYPE_BAND_PASS, 8000, 3, AUDIO_EQ_Q},
+ {9, EQ_IIR_TYPE_BAND_PASS, 16000, 4, AUDIO_EQ_Q},
+
+#if (EQ_SECTION_MAX > 10)
+ //10段之后频率值设置96k,目的是让10段之后的eq走直通
+ {10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+#endif
+#endif
+
+};
+struct eq_seg_info eq_tab_custom[] = {
+#if TCFG_USER_EQ_MODE_NUM > 6
+ {0, EQ_IIR_TYPE_BAND_PASS, 31, 0, AUDIO_EQ_Q},
+ {1, EQ_IIR_TYPE_BAND_PASS, 62, 0, AUDIO_EQ_Q},
+ {2, EQ_IIR_TYPE_BAND_PASS, 125, 0, AUDIO_EQ_Q},
+ {3, EQ_IIR_TYPE_BAND_PASS, 250, 0, AUDIO_EQ_Q},
+ {4, EQ_IIR_TYPE_BAND_PASS, 500, 0, AUDIO_EQ_Q},
+ {5, EQ_IIR_TYPE_BAND_PASS, 1000, 0, AUDIO_EQ_Q},
+ {6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
+ {7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
+ {8, EQ_IIR_TYPE_BAND_PASS, 8000, 0, AUDIO_EQ_Q},
+ {9, EQ_IIR_TYPE_BAND_PASS, 16000, 0, AUDIO_EQ_Q},
+
+#if (EQ_SECTION_MAX > 10)
+ //10段之后频率值设置96k,目的是让10段之后的eq走直通
+ {10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+ {19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
+#endif
+
+#endif
+};
+
+
+const EQ_CFG_SEG *eq_type_tab[EQ_MODE_MAX] = {
+ eq_tab_normal, eq_tab_rock, eq_tab_pop, eq_tab_classic, eq_tab_jazz, eq_tab_country, eq_tab_custom
+};
+// 默认系数表,每个表对应的总增益,用户可修改
+float type_gain_tab[EQ_MODE_MAX] = {0, 0, 0, 0, 0, 0, 0};
+#endif
+
+__attribute__((weak)) u32 get_eq_mode_tab(void)
+{
+#if !TCFG_USE_EQ_FILE
+ return (u32)eq_type_tab;
+#else
+ return 0;
+#endif
+}
+
+__attribute__((weak)) u8 get_eq_mode_max(void)
+{
+ return EQ_MODE_MAX;
+}
+
+#if (EQ_SECTION_MAX==9)
+static const u8 eq_mode_use_idx[] = {
+ 0, 1, 2, 3, 4, 5, /*6,*/ 7, 8, 9
+};
+#elif (EQ_SECTION_MAX==8)
+static const u8 eq_mode_use_idx[] = {
+ 0, /*1,*/ 2, 3, 4, 5, 6, 7, /*8,*/ 9
+};
+#elif (EQ_SECTION_MAX==7)
+static const u8 eq_mode_use_idx[] = {
+ 0, /*1,*/ 2, 3, 4, 5, /*6,*/ 7, /*8,*/ 9
+};
+#elif (EQ_SECTION_MAX==6)
+static const u8 eq_mode_use_idx[] = {
+ 0, /*1,*/ 2, 3, 4, /*5,*/ /*6,*/ 7, /*8,*/ 9
+};
+#elif (EQ_SECTION_MAX==5)
+static const u8 eq_mode_use_idx[] = {
+ /*0,*/ 1, /*2,*/ 3, /*4,*/ 5, /*6,*/ 7, /*8,*/ 9
+};
+#else
+static const u8 eq_mode_use_idx[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+};
+#endif
+/*
+ *通话下行eq系数表
+ * */
+#if TCFG_EQ_ENABLE && TCFG_PHONE_EQ_ENABLE
+#if EQ_FILE_CP_TO_CUSTOM
+struct eq_seg_info phone_eq_tab_normal[] = {
+#else
+const struct eq_seg_info phone_eq_tab_normal[] = {
+#endif
+ {0, EQ_IIR_TYPE_HIGH_PASS, 200, 0, 0.7f},
+ {1, EQ_IIR_TYPE_BAND_PASS, 300, 0, 0.7f},
+ {2, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
+#if TCFG_CALL_DL_EQ_SECTION > 3
+ {3, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
+ {4, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
+ {5, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
+ {6, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
+ {7, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
+ {8, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
+ {9, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
+#endif
+};
+#endif
+
+/*
+ *通话上行eq系数表
+ * */
+#if EQ_FILE_CP_TO_CUSTOM
+struct eq_seg_info ul_eq_tab_normal[] = {
+#else
+const struct eq_seg_info ul_eq_tab_normal[] = {
+#endif
+ {0, EQ_IIR_TYPE_HIGH_PASS, 200, 0, 0.7f},
+ {1, EQ_IIR_TYPE_BAND_PASS, 300, 0, 0.7f},
+ {2, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
+#if TCFG_CALL_UL_EQ_SECTION > 3
+ {3, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
+ {4, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
+ {5, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
+ {6, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
+ {7, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
+ {8, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
+ {9, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
+#endif
+
+};
+
+
+
+#define SONG_SECTION EQ_SECTION_MAX
+#define CALL_SECTION TCFG_CALL_DL_EQ_SECTION//下行段数,小于等于SONG_SECTION
+#define UL_SECTION TCFG_CALL_UL_EQ_SECTION//上行段数,小于等于SONG_SECTION
+/*
+ *下行的宽频和窄频段数需一致,上行的宽频和窄频段数需要一致
+ *表的每一项顺序不可修改
+ * */
+eq_tool_cfg eq_tool_tab[] = {
+ {call_eq_mode, (u8 *)"通话宽频下行EQ", 0x3001, CALL_SECTION, 1, {EQ_ONLINE_CMD_CALL_EQ_V1_SEG, 0}},
+ {call_narrow_eq_mode, (u8 *)"通话窄频下行EQ", 0x3002, CALL_SECTION, 1, {EQ_ONLINE_CMD_CALL_EQ_V1_SEG, 0}},
+ {aec_eq_mode, (u8 *)"通话宽频上行EQ", 0x3003, UL_SECTION, 1, {EQ_ONLINE_CMD_AEC_EQ_V1_SEG, 0}},
+ {aec_narrow_eq_mode, (u8 *)"通话窄频上行EQ", 0x3004, UL_SECTION, 1, {EQ_ONLINE_CMD_AEC_EQ_V1_SEG, 0}},
+#if defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE
+ {song_eq_mode, (u8 *)"普通音频EQ", 0x3000, SONG_SECTION, 3, {EQ_ONLINE_CMD_SONG_EQ_V1_SEG, EQ_ONLINE_CMD_SONG_MULTI_WDRC, EQ_ONLINE_CMD_VIRTUAL_BASS}},//多带wdrc
+ {hearing_aid_mode, (u8 *)"辅听EQ", 0x3005, SONG_SECTION, 2, {EQ_ONLINE_CMD_HEARING_AID_EQ_SEG, EQ_ONLINE_CMD_SONG_WDRC}},
+ {hearing_aid_mode2, (u8 *)"辅听EQ2", 0x3006, SONG_SECTION, 1, {EQ_ONLINE_CMD_HEARING_AID_EQ_SEG2}},
+#else
+ {song_eq_mode, (u8 *)"普通音频EQ", 0x3000, SONG_SECTION, 3, { EQ_ONLINE_CMD_SONG_EQ_V1_SEG, EQ_ONLINE_CMD_SONG_DRC, EQ_ONLINE_CMD_VIRTUAL_BASS}},
+#if defined(TCFG_AUDIO_HEARING_AID_ENABLE) && TCFG_AUDIO_HEARING_AID_ENABLE
+ {hearing_aid_mode, (u8 *)"辅听EQ", 0x3005, SONG_SECTION, 2, {EQ_ONLINE_CMD_HEARING_AID_EQ_SEG, EQ_ONLINE_CMD_SONG_WDRC}},
+ {hearing_aid_mode2, (u8 *)"辅听EQ2", 0x3006, SONG_SECTION, 1, {EQ_ONLINE_CMD_HEARING_AID_EQ_SEG2}},
+#endif /*TCFG_AUDIO_HEARING_AID_ENABLE*/
+#endif
+};
+
+/*----------------------------------------------------------------------------*/
+/**@brief eq 段数更新,需要在eq_init前就准备好
+ @param mode:call_eq_mode\call_narrow_eq_section等模式
+ @param section:段数最大为EQ_SECTION_MAX
+ @return
+ @note 下行的宽频和窄频段数需一致,上行的宽频和窄频段数需要一致
+*/
+/*----------------------------------------------------------------------------*/
+void set_eq_tool_tab_section(u8 mode, u8 section)
+{
+ for (int i = 0; i < ARRAY_SIZE(eq_tool_tab); i++) {
+ if (mode == eq_tool_tab[i].mode_index) {
+ eq_tool_tab[i].section = section;
+ }
+ }
+}
+
+void eq_section_num_set(u8 song, u8 call_16k_8k, u8 aec_16k_8k)
+{
+ set_eq_tool_tab_section(song_eq_mode, song);
+ set_eq_tool_tab_section(call_eq_mode, call_16k_8k);
+ set_eq_tool_tab_section(call_narrow_eq_mode, call_16k_8k);
+ set_eq_tool_tab_section(aec_eq_mode, aec_16k_8k);
+ set_eq_tool_tab_section(aec_narrow_eq_mode, aec_16k_8k);
+}
+void drc_default_init(EQ_CFG *eq_cfg, u8 mode)
+{
+#if TCFG_DRC_ENABLE
+ int i = mode;
+ if (eq_cfg && eq_cfg->drc) {
+ //限幅器的初始值
+ int th = 0;//db -60db~0db
+ int threshold = roundf(powf(10.0f, th / 20.0f) * 32768); // 0db:32768, -60db:33
+ eq_cfg->cfg_parm[i].drc_parm.parm.drc.nband = 1;
+ eq_cfg->cfg_parm[i].drc_parm.parm.drc.type = 1;
+ eq_cfg->cfg_parm[i].drc_parm.parm.drc._p.limiter[0].attacktime = 5;
+ eq_cfg->cfg_parm[i].drc_parm.parm.drc._p.limiter[0].releasetime = 500;
+ eq_cfg->cfg_parm[i].drc_parm.parm.drc._p.limiter[0].threshold[0] = threshold;
+ eq_cfg->cfg_parm[i].drc_parm.parm.drc._p.limiter[0].threshold[1] = 32768;
+ }
+#endif
+
+}
+#if EQ_FILE_CP_TO_CUSTOM
+//eq_cfg_hw.bin中播歌eq曲线,当作用户自定义模式,参与效果切换.
+//通话宽频上下行eq曲线也对应放到phone_eq_tab_normal、ul_eq_tab_normal
+//EQ_FILE_CP_TO_CUSTOM 1使能时,同时板极文件中 TCFG_USE_EQ_FILE 配 0
+static void eq_file_cp_to_custon_mode_fun(EQ_CFG *eq_cfg)
+{
+ if (eq_cfg->eq_type == EQ_TYPE_FILE) {
+ eq_cfg->eq_type = EQ_TYPE_MODE_TAB;
+ for (int i = 0; i < eq_cfg->mode_num; i++) {
+ if ((i == song_eq_mode) || (i == call_eq_mode) || (i == aec_eq_mode)) { //播歌eq 通话宽频上下行eq
+ u32 seg_num = eq_cfg->cfg_parm[i].song_eq_parm.parm.par.seg_num;
+ u8 index = 0;
+ for (int j = 0; j < ARRAY_SIZE(eq_tool_tab); j++) {
+ if (i == eq_tool_tab[j].mode_index) {
+ index = j;
+ }
+ }
+ if (seg_num > eq_tool_tab[index].section) {
+ seg_num = eq_tool_tab[index].section;
+ }
+ void *tar = NULL;
+ if (i == call_eq_mode) {
+#if TCFG_PHONE_EQ_ENABLE
+ tar = eq_cfg->phone_eq_tab;
+#endif
+ } else if (i == aec_eq_mode) {
+ tar = eq_cfg->ul_eq_tab;
+ } else if (i == song_eq_mode) {
+ tar = eq_tab_custom;
+ eq_cfg->type_gain_tab[EQ_MODE_MAX - 1] = eq_cfg->cfg_parm[i].song_eq_parm.parm.par.global_gain;
+ }
+ if (tar) {
+ memcpy(tar, eq_cfg->cfg_parm[i].song_eq_parm.parm.seg, seg_num * sizeof(EQ_CFG_SEG));
+ eq_cfg->seg_num[i] = seg_num;
+ }
+ }
+ }
+ }
+}
+#endif
+
+__attribute__((weak))
+s16 get_ci_tx_size()
+{
+ return 0x30;
+}
+/*----------------------------------------------------------------------------*/
+static u8 reply_to_tool = 0;
+static u8 reply_sq = 0;
+/*
+ *新调音回调
+ * */
+static void eq_online_callback_new_protocol(uint8_t *packet, uint16_t size)
+{
+ u8 *ptr = packet;
+ reply_sq = ptr[1];
+ reply_to_tool = 0;
+ u8 *new_packet = (void *)&packet[2];
+ eq_online_callback(new_packet, size);
+}
+//新调音注册
+REGISTER_DETECT_TARGET(eq_adj_target) = {
+ .id = EQ_CONFIG_ID,
+ .tool_message_deal = eq_online_callback_new_protocol,
+};
+
+
+/*
+/*----------------------------------------------------------------------------*/
+int ci_send_cmd(void *priv, u32 id, u8 *packet, int size)
+{
+ EQ_CFG *eq_cfg = (EQ_CFG *)priv;
+ if (!eq_cfg) {
+ return 0;
+ }
+#if TCFG_ONLINE_ENABLE
+#if defined(TCFG_EFFECT_TOOL_ENABLE) && TCFG_EFFECT_TOOL_ENABLE
+ all_assemble_package_send_to_pc(reply_to_tool, reply_sq, packet, size);
+#else
+ ci_send_packet(id, packet, size);
+#endif
+#endif
+ return 0;
+}
+struct virtual_bass_tool_set vbass_default_param = {
+ .prev_gain = -3, //dB预处理,降低数据增益,防止虚拟低音把数据调爆
+ .parm = {
+ .ratio = 10, //比率(0~100),越大,低音强度越大
+ .boost = 1, //(低音自动增强0, 1)
+ .fc = 100, //截止频率(30~300Hz)
+ },
+};
+
+struct virtual_bass_tool_set *get_vbass_parm()
+{
+ EQ_CFG *eq_cfg = get_eq_cfg_hdl();
+ if (!eq_cfg) {
+ return NULL;
+ }
+#if defined(TCFG_EFFECT_TOOL_ENABLE) && TCFG_EFFECT_TOOL_ENABLE
+ return &eq_cfg->cfg_parm[song_eq_mode].vbass_parm.parm;
+#else
+ if (eq_cfg->vbass_file) {
+ return &eq_cfg->cfg_parm[song_eq_mode].vbass_parm.parm;
+ } else {
+ return &vbass_default_param;
+ }
+#endif
+}
+
+
+int eq_init(void)
+{
+ eq_adjust_parm parm = {0};
+#if TCFG_EQ_ONLINE_ENABLE
+ parm.online_en = 1;
+#endif
+ if (config_filter_coeff_fade_en) {
+ parm.fade_en = 1;
+ }
+
+#if TCFG_USE_EQ_FILE
+ parm.file_en = 1;
+#endif
+
+#if EQ_FILE_CP_TO_CUSTOM
+ parm.file_en = 1;
+ parm.type_gain_tab = type_gain_tab;
+#endif
+
+#if TCFG_DRC_ENABLE
+ parm.drc = 1;
+#endif
+
+#if TCFG_USER_TWS_ENABLE
+ parm.tws = 1;
+#endif
+
+
+#if (RCSP_ADV_EN)&&(JL_EARPHONE_APP_EN)&&(TCFG_DRC_ENABLE == 0)
+ /* parm.limit_zero = 1; */
+#endif
+
+ /* #if TCFG_EQ_DIVIDE_ENABLE */
+ /* parm.stero = 1; */
+ /* parm.mode_num = 8; */
+ /* #endif */
+
+ if (!parm.stero) {
+#if defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE
+ parm.mode_num = 7;//一共有多少个模式
+#else
+#if defined(TCFG_AUDIO_HEARING_AID_ENABLE) && TCFG_AUDIO_HEARING_AID_ENABLE
+ parm.mode_num = 7;// 一共有多少个模式
+#else
+ parm.mode_num = 5;// 一共有多少个模式
+#endif
+#endif /*TCFG_AUDIO_HEARING_AID_ENABLE*/
+ /* #ifdef DAC_OUTPUT_FRONT_LR_REAR_LR */
+ /* #if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_FRONT_LR_REAR_LR) */
+ /* parm.mode_num = 6; */
+ /* #endif */
+ /* #endif */
+ }
+
+#if TCFG_PHONE_EQ_ENABLE
+ parm.phone_eq_tab = (void *)phone_eq_tab_normal;
+ parm.phone_eq_tab_size = TCFG_CALL_DL_EQ_SECTION;//ARRAY_SIZE(phone_eq_tab_normal);
+#endif
+
+#if TCFG_AEC_UL_EQ_ENABLE
+ parm.ul_eq_tab = (void *)ul_eq_tab_normal;
+ parm.ul_eq_tab_size = TCFG_CALL_UL_EQ_SECTION;//ARRAY_SIZE(ul_eq_tab_normal);
+#endif
+
+ parm.eq_tool_tab = eq_tool_tab;
+ parm.eq_mode_use_idx = (u8 *)eq_mode_use_idx;
+
+ parm.eq_type_tab = (void *)get_eq_mode_tab();
+#if TCFG_USER_EQ_MODE_NUM
+ parm.type_num = TCFG_USER_EQ_MODE_NUM;//EQ_MODE_MAX;
+#endif
+
+ parm.section_max = EQ_SECTION_MAX;
+
+ EQ_CFG *eq_cfg = eq_cfg_open(&parm);
+ if (eq_cfg) {
+ eq_cfg->priv = eq_cfg;
+ eq_cfg->send_cmd = ci_send_cmd;
+ eq_cfg->custom_mode_id = EQ_MODE_CUSTOM;
+#if defined(AUDIO_VBASS_CONFIG)&&AUDIO_VBASS_CONFIG
+ eq_cfg->vbass = 1;
+#endif
+#if EQ_FILE_CP_TO_CUSTOM
+ eq_file_cp_to_custon_mode_fun(eq_cfg);
+#else
+ for (int i = 0; i < eq_cfg->mode_num; i++) {
+ if (eq_cfg->eq_type == EQ_TYPE_MODE_TAB) {
+ if (!eq_cfg->type_gain_tab) {//没指定总增益时,才配置默认总增益0
+ set_global_gain(eq_cfg, i, 0);
+ }
+ drc_default_init(eq_cfg, i);
+ }
+ }
+#endif
+ }
+
+ int cpu_section = 0;
+ //单声道或者立体声申请的cpu eq mem
+ if (EQ_SECTION_MAX > 10) {
+ u8 add_num = 0;
+ if (hw_crossover_type0) {
+ add_num = 4;//drc分频器使用eq硬件加速时、3段4阶使用最大eq段数24段(每段4个eq, 6声道)
+ }
+ cpu_section = EQ_SECTION_MAX - (int)&EQ_PRIV_SECTION_NUM + add_num;
+ }
+ audio_eq_init(cpu_section);
+ return 0;
+}
+__initcall(eq_init);
+
+
+#if TCFG_EQ_FILE_SWITCH_EN
+//根据eq_file_switch_list切换到指定的eq文件
+void eq_file_set_by_index(u8 index)
+{
+ if (index >= ARRAY_SIZE(eq_file_switch_list)) {
+ printf("err, max index %d\n", ARRAY_SIZE(eq_file_switch_list));
+ return;
+ }
+ EQ_CFG *eq_cfg = get_eq_cfg_hdl();
+ if (!eq_cfg) {
+ return;
+ }
+ int ret = eq_file_get_cfg(eq_cfg, eq_file_switch_list[index]);
+ printf("eq_file_switch : %d, ret : %d", index, ret);
+}
+
+//根据eq_file_switch_list成员个数顺序切换eq文件
+void eq_file_switch()
+{
+ static u8 index = 0;
+ index++;
+ if (index >= ARRAY_SIZE(eq_file_switch_list)) {
+ index = 0;
+ }
+ eq_file_set_by_index(index);
+}
+
+#endif
+#endif
diff --git a/cpu/br28/hw_fft.c b/cpu/br28/hw_fft.c
new file mode 100644
index 0000000..0fb1117
--- /dev/null
+++ b/cpu/br28/hw_fft.c
@@ -0,0 +1,220 @@
+#include "includes.h"
+
+/*FFT模块资源互斥方式配置*/
+#define CRITICAL_NULL 0
+#define CRITICAL_IRQ 1
+#define CRITICAL_MUTEX 2
+#define CRITICAL_SPIN_LOCK 3
+#define FFT_CRITICAL_MODE CRITICAL_SPIN_LOCK
+
+#if (FFT_CRITICAL_MODE == CRITICAL_MUTEX)
+static OS_MUTEX fft_mutex;
+#define FFT_CRITICAL_INIT() os_mutex_create(&fft_mutex)
+#define FFT_ENTER_CRITICAL() os_mutex_pend(&fft_mutex, 0)
+#define FFT_EXIT_CRITICAL() os_mutex_post(&fft_mutex)
+#elif (FFT_CRITICAL_MODE == CRITICAL_IRQ)
+#define FFT_CRITICAL_INIT(...)
+#define FFT_ENTER_CRITICAL() local_irq_disable()
+#define FFT_EXIT_CRITICAL() local_irq_enable()
+#elif (FFT_CRITICAL_MODE == CRITICAL_SPIN_LOCK)
+static spinlock_t fft_lock;
+#define FFT_CRITICAL_INIT() spin_lock_init(&fft_lock)
+#define FFT_ENTER_CRITICAL() spin_lock(&fft_lock)
+#define FFT_EXIT_CRITICAL() spin_unlock(&fft_lock)
+
+#endif /*FFT_CRITICAL_MODE*/
+
+static volatile u8 fft_init = 0;
+
+typedef struct {
+ unsigned int fft_config;
+ const int *in;
+ int *out;
+} pi32v2_hw_fft_ctx;
+
+#define FFT_ISR_IE 0
+void hw_fft_wrap(pi32v2_hw_fft_ctx *ctx)
+{
+ if (fft_init == 0) {
+ fft_init = 1;
+ FFT_CRITICAL_INIT();
+ }
+ FFT_ENTER_CRITICAL();
+
+ JL_FFT->CON = 0;
+ JL_FFT->CON |= 1 << 8;
+ JL_FFT->CADR = (unsigned int)ctx;
+ JL_FFT->CON = (1 << 8) | (0 << 6) | (FFT_ISR_IE << 2) | (0 << 1) | (1 << 0); //((1<<8)|(1<<0))
+ while ((JL_FFT->CON & (1 << 7)) == 0);
+ JL_FFT->CON |= (1 << 6);
+
+ FFT_EXIT_CRITICAL();
+}
+
+static int REAL_FFT_CONFIG[6] = {
+ 809501970, 813696546, 822085426, 838862898, 872417602, 939526722,
+};
+
+/**** Real IFFT *******/
+static int REAL_IFFT_CONFIG[6] = {
+ 809501958, 1082131974, 822085382, 1107298310, 872417542, 1207962118,
+};
+
+/****************************
+ *
+ * Complex Support points
+ * 32\64\128\256\512\1024\2048
+ *
+ * *************************/
+/**** Complex FFT *******/
+static int COMPLEX_FFT_CONFIG[7] = {
+ 538969360, 541066784, 545261344, 553650224, 570427696, 603982400, 671091520,
+};
+
+/**** Complex IFFT *******/
+static int COMPLEX_IFFT_CONFIG[7] = {
+ 1075840276, 809502212, 1082132244, 822085636, 1107298580, 872417796, 1207962388,
+};
+
+
+
+/*********************************************************************
+* hw_fft_config
+* Description: 根据配置生成 FFT_config
+* Arguments : N 运算数据量;
+ log2N 运算数据量的对数值
+ is_same_addr 输入输出是否同一个地址,0:否,1:是
+ is_ifft 运算类型 0:FFT运算, 1:IFFT运算
+ is_real 运算数据的类型 1:实数, 0:复数
+* Return : ConfgPars 写入FFT寄存器
+* Note(s) : None.
+*********************************************************************/
+unsigned int hw_fft_config(int N, int log2N, int is_same_addr, int is_ifft, int is_real)
+{
+ unsigned int ConfgPars;
+ ConfgPars = 0;
+ if (is_real == 1) {
+ if (is_ifft == 0) {
+ ConfgPars = REAL_FFT_CONFIG[log2N - 6];
+ ConfgPars |= is_same_addr;
+ } else {
+ ConfgPars = REAL_IFFT_CONFIG[log2N - 6];
+ ConfgPars |= is_same_addr;
+ }
+ } else {
+ if (is_ifft == 0) {
+ ConfgPars = COMPLEX_FFT_CONFIG[log2N - 5];
+ ConfgPars |= is_same_addr;
+ } else {
+ ConfgPars = COMPLEX_IFFT_CONFIG[log2N - 5];
+ ConfgPars |= is_same_addr;
+ }
+ }
+ /* printf("ConfgPars%x\n",ConfgPars); */
+ return ConfgPars;
+}
+
+/*********************************************************************
+* hw_fft_run
+* Description: fft/ifft运算函数
+* Arguments :fft_config FFT运算配置寄存器值
+ in 输入数据地址(满足4byte对其,以及非const类型)
+ out 输出数据地址
+* Return : void
+* Note(s) : None.
+*********************************************************************/
+void hw_fft_run(unsigned int fft_config, const int *in, int *out)
+{
+ pi32v2_hw_fft_ctx ctx;
+ ctx.fft_config = fft_config;
+ ctx.in = in;
+ ctx.out = out;
+ hw_fft_wrap(&ctx);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// VECTOR
+//////////////////////////////////////////////////////////////////////////
+
+typedef struct {
+ unsigned long vector_con;
+ unsigned long vector_xadr;
+ unsigned long vector_yadr;
+ unsigned long vector_zadr;
+ unsigned long vector_config0;
+ unsigned long vector_config1;
+ unsigned long vector_config2;
+ unsigned long null;
+} hwvec_ctx_t;
+
+static hwvec_ctx_t g_vector_core_set __attribute__((aligned(16)));
+
+//__attribute__ ((always_inline)) inline
+void hwvec_exec(
+ void *xptr,
+ void *yptr,
+ void *zptr,
+ short x_inc,
+ short y_inc,
+ short z_inc,
+ short nlen,
+ short nloop,
+ char q,
+ long config,
+ long const_dat
+)
+{
+
+ if (fft_init == 0) {
+ fft_init = 1;
+ FFT_CRITICAL_INIT();
+ }
+
+ FFT_ENTER_CRITICAL();
+
+ g_vector_core_set.vector_con = config;
+ g_vector_core_set.vector_config0 = (q << 24) | (nloop << 12) | (nlen);
+ g_vector_core_set.vector_config1 = (z_inc << 20) | (y_inc << 10) | x_inc;
+ //printf("nlen0:%d,nloop:%d,q:%d,config:%d,%d\n",nlen,nloop,q,config,const_dat);
+
+ g_vector_core_set.vector_xadr = (unsigned long)xptr;
+ g_vector_core_set.vector_yadr = (unsigned long)yptr;
+ g_vector_core_set.vector_zadr = (unsigned long)zptr;
+
+ JL_FFT->CONST = const_dat;
+
+ JL_FFT->CADR = (unsigned long)(&g_vector_core_set);
+
+
+ // nu clr vector ie en
+ JL_FFT->CON = (1 << 8) | (1 << 6) | (1 << 3) | (1 << 2) | (1 << 0);
+
+
+ lp_waiting((int *)&JL_FFT->CON, BIT(7), BIT(6), 116);
+
+ FFT_EXIT_CRITICAL();
+}
+
+u8 fft_wrap_for_ldac_enable(void)
+{
+ return 1;
+}
+
+int _FFT_wrap_(int cfg, int *in, int *out)
+{
+ //init pi32v2 fft hardware
+ pi32v2_hw_fft_ctx ctx;
+ if (in == out) {
+ cfg |= 1;
+ }
+
+ ctx.fft_config = cfg;
+ ctx.in = in;
+ ctx.out = out;
+ hw_fft_wrap(&ctx);
+
+ return 0;
+}
+
+
+
diff --git a/cpu/br28/iic_hw.c b/cpu/br28/iic_hw.c
new file mode 100644
index 0000000..1db4c21
--- /dev/null
+++ b/cpu/br28/iic_hw.c
@@ -0,0 +1,366 @@
+#include "asm/iic_hw.h"
+#include "system/generic/gpio.h"
+#include "system/generic/log.h"
+#include "asm/clock.h"
+#include "asm/cpu.h"
+
+/*
+ [[ 注意!!! ]]
+ * 适用于带cfg_done的硬件IIC,另一种硬件IIC另作说明
+ * 硬件IIC的START / ACK(NACK)必须在发送或接收字节cfg_done前设置,且不能
+ 接cfg_done单独发送;而STOP则应在发送或接收字节cfg_done后设置,必须接
+ cfg_done单独发送
+*/
+
+static JL_IIC_TypeDef *const iic_regs[IIC_HW_NUM] = {
+ JL_IIC,
+};
+
+#define iic_get_id(iic) (iic)
+
+#define iic_info_port(iic, x) (hw_iic_cfg[iic_get_id(iic)].port[x])
+#define iic_info_baud(iic) (hw_iic_cfg[iic_get_id(iic)].baudrate)
+#define iic_info_hdrive(iic) (hw_iic_cfg[iic_get_id(iic)].hdrive)
+#define iic_info_io_filt(iic) (hw_iic_cfg[iic_get_id(iic)].io_filter)
+#define iic_info_io_pu(iic) (hw_iic_cfg[iic_get_id(iic)].io_pu)
+#define iic_info_role(iic) (hw_iic_cfg[iic_get_id(iic)].role)
+
+static inline u32 iic_get_scl(hw_iic_dev iic)
+{
+ u8 port = iic_info_port(iic, 0);
+ return port;
+}
+
+static inline u32 iic_get_sda(hw_iic_dev iic)
+{
+ u8 port = iic_info_port(iic, 1);
+ return port;
+}
+
+static int iic_port_init(hw_iic_dev iic)
+{
+ u32 reg;
+ int ret = 0;
+ u8 id = iic_get_id(iic);
+ u32 scl, sda;
+ scl = iic_get_scl(iic);
+ sda = iic_get_sda(iic);
+ if (id == 0) {
+ gpio_set_fun_output_port(scl, FO_IIC_SCL, 1, 1, LOW_POWER_FREE);
+ gpio_set_fun_output_port(sda, FO_IIC_SDA, 1, 1, LOW_POWER_FREE);
+ gpio_set_fun_input_port(scl, PFI_IIC_SCL, LOW_POWER_FREE);
+ gpio_set_fun_input_port(sda, PFI_IIC_SDA, LOW_POWER_FREE);
+ if (iic_info_hdrive(iic)) {
+ gpio_set_hd(scl, 1);
+ gpio_set_hd(sda, 1);
+ } else {
+ gpio_set_hd(scl, 0);
+ gpio_set_hd(sda, 0);
+ }
+ if (iic_info_io_pu(iic)) {
+ gpio_set_pull_up(scl, 1);
+ gpio_set_pull_up(sda, 1);
+ } else {
+ gpio_set_pull_up(scl, 0);
+ gpio_set_pull_up(sda, 0);
+ }
+ } else {
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+int hw_iic_set_baud(hw_iic_dev iic, u32 baud)
+{
+ //f_iic = f_sys / ((IIC_BAUD + 1) * 2)
+ //=> IIC_BAUD = f_sys / (2 * f_iic) - 1
+ u32 sysclk;
+ u8 id = iic_get_id(iic);
+
+ sysclk = clk_get("lsb");
+ if (sysclk < 2 * baud) {
+ return -EINVAL;
+ }
+ iic_baud_reg(iic_regs[id]) = sysclk / (2 * baud) - 1;
+ return 0;
+}
+
+static void hw_iic_set_die(hw_iic_dev iic, u8 en)
+{
+ u8 id = iic_get_id(iic);
+ u32 scl, sda;
+ scl = iic_get_scl(iic);
+ sda = iic_get_sda(iic);
+ if (id == 0) {
+ gpio_set_die(scl, en);
+ gpio_set_die(sda, en);
+ } else {
+ //undefined
+ }
+}
+
+void hw_iic_suspend(hw_iic_dev iic)
+{
+ hw_iic_set_die(iic, 0);
+}
+
+void hw_iic_resume(hw_iic_dev iic)
+{
+ hw_iic_set_die(iic, 1);
+}
+
+int hw_iic_init(hw_iic_dev iic)
+{
+ int ret;
+ u8 id = iic_get_id(iic);
+
+ if ((ret = iic_port_init(iic))) {
+ log_e("invalid hardware iic port\n");
+ return ret;
+ }
+ hw_iic_set_die(iic, 1);
+ if (iic_info_role(iic) == IIC_MASTER) {
+ iic_role_host(iic_regs[id]);
+ } else {
+ iic_role_slave(iic_regs[id]);
+ iic_si_mode_en(iic_regs[id]);
+ }
+ if (iic_info_io_filt(iic)) {
+ iic_isel_filter(iic_regs[id]);
+ } else {
+ iic_isel_direct(iic_regs[id]);
+ }
+ if ((ret = hw_iic_set_baud(iic, iic_info_baud(iic)))) {
+ log_e("iic baudrate is invalid\n");
+ return ret ;
+ }
+ iic_pnd_clr(iic_regs[id]);
+ iic_end_pnd_clr(iic_regs[id]);
+ iic_start_pnd_clr(iic_regs[id]);
+ iic_enable(iic_regs[id]);
+#if 0
+ printf("info->scl = %d\n", iic_get_scl(iic));
+ printf("info->sda = %d\n", iic_get_sda(iic));
+ printf("info->baudrate = %d\n", iic_info_baud(iic));
+ printf("info->hdrive = %d\n", iic_info_hdrive(iic));
+ printf("info->io_filter = %d\n", iic_info_io_filt(iic));
+ printf("info->io_pu = %d\n", iic_info_io_pu(iic));
+ printf("info->role = %d\n", iic_info_role(iic));
+ printf("IIC_CON0 0x%04x\n", iic_regs[id]->CON0);
+ printf("IIC_CON1 0x%04x\n", iic_regs[id]->CON1);
+ printf("IIC_BAUD 0x%02x\n", iic_regs[id]->BAUD);
+ //printf("IIC_BUF %02x\n", iic_regs[id]->BUF);
+ printf("IOMC1 0x%08x\n", JL_IOMAP->CON1);
+#endif
+ return 0;
+}
+
+void hw_iic_uninit(hw_iic_dev iic)
+{
+ u8 id = iic_get_id(iic);
+ u32 scl, sda;
+
+ scl = iic_get_scl(iic);
+ sda = iic_get_sda(iic);
+ hw_iic_set_die(iic, 0);
+ if (id == 0) {
+ gpio_set_hd(scl, 0);
+ gpio_set_hd(sda, 0);
+ gpio_set_pull_up(scl, 0);
+ gpio_set_pull_up(sda, 0);
+ }
+ iic_disable(iic_regs[id]);
+}
+
+void hw_iic_start(hw_iic_dev iic)
+{
+ u8 id = iic_get_id(iic);
+ iic_preset_restart(iic_regs[id]);
+ //don't add iic_cfg_done() here, it must be used with send byte
+}
+
+void hw_iic_stop(hw_iic_dev iic)
+{
+ u8 id = iic_get_id(iic);
+ iic_preset_end(iic_regs[id]);
+ iic_cfg_done(iic_regs[id]);
+}
+
+u8 hw_iic_tx_byte(hw_iic_dev iic, u8 byte)
+{
+ u8 id = iic_get_id(iic);
+ iic_dir_out(iic_regs[id]);
+ iic_buf_reg(iic_regs[id]) = byte;
+ iic_cfg_done(iic_regs[id]);
+ /* putchar('a'); */
+ while (!iic_pnd(iic_regs[id]));
+ iic_pnd_clr(iic_regs[id]);
+ /* putchar('b'); */
+ return iic_send_is_ack(iic_regs[id]);
+}
+
+u8 hw_iic_rx_byte(hw_iic_dev iic, u8 ack)
+{
+ u8 id = iic_get_id(iic);
+ iic_dir_in(iic_regs[id]);
+ if (ack) {
+ iic_recv_ack(iic_regs[id]);
+ } else {
+ iic_recv_nack(iic_regs[id]);
+ }
+ iic_buf_reg(iic_regs[id]) = 0xff;
+ iic_cfg_done(iic_regs[id]);
+ /* putchar('c'); */
+ while (!iic_pnd(iic_regs[id]));
+ iic_pnd_clr(iic_regs[id]);
+ /* putchar('d'); */
+ return iic_buf_reg(iic_regs[id]);
+}
+
+int hw_iic_read_buf(hw_iic_dev iic, void *buf, int len)
+{
+ u8 id = iic_get_id(iic);
+ int i;
+
+ if (!buf || !len) {
+ return -1;
+ }
+ iic_dir_in(iic_regs[id]);
+ iic_recv_ack(iic_regs[id]);
+ for (i = 0; i < len; i++) {
+ if (i == len - 1) {
+ iic_recv_nack(iic_regs[id]);
+ }
+ iic_buf_reg(iic_regs[id]) = 0xff;
+ iic_cfg_done(iic_regs[id]);
+ while (!iic_pnd(iic_regs[id]));
+ iic_pnd_clr(iic_regs[id]);
+ ((u8 *)buf)[i] = iic_buf_reg(iic_regs[id]);
+ }
+ return len;
+}
+
+int hw_iic_write_buf(hw_iic_dev iic, const void *buf, int len)
+{
+ u8 id = iic_get_id(iic);
+ int i = 0;
+
+ if (!buf || !len) {
+ return -1;
+ }
+ iic_dir_out(iic_regs[id]);
+ for (i = 0; i < len; i++) {
+ iic_buf_reg(iic_regs[id]) = ((u8 *)buf)[i];
+ iic_cfg_done(iic_regs[id]);
+ while (!iic_pnd(iic_regs[id]));
+ iic_pnd_clr(iic_regs[id]);
+ if (!iic_send_is_ack(iic_regs[id])) {
+ break;
+ }
+ }
+ return i;
+}
+
+void hw_iic_set_ie(hw_iic_dev iic, u8 en)
+{
+ u8 id = iic_get_id(iic);
+
+ if (en) {
+ iic_set_ie(iic_regs[id]);
+ } else {
+ iic_clr_ie(iic_regs[id]);
+ }
+}
+
+u8 hw_iic_get_pnd(hw_iic_dev iic)
+{
+ u8 id = iic_get_id(iic);
+
+ return !!iic_pnd(iic_regs[id]);
+}
+
+void hw_iic_clr_pnd(hw_iic_dev iic)
+{
+ u8 id = iic_get_id(iic);
+
+ iic_pnd_clr(iic_regs[id]);
+}
+
+void hw_iic_set_end_ie(hw_iic_dev iic, u8 en)
+{
+ u8 id = iic_get_id(iic);
+
+ if (en) {
+ iic_set_end_ie(iic_regs[id]);
+ } else {
+ iic_clr_end_ie(iic_regs[id]);
+ }
+}
+
+u8 hw_iic_get_end_pnd(hw_iic_dev iic)
+{
+ u8 id = iic_get_id(iic);
+
+ return !!iic_end_pnd(iic_regs[id]);
+}
+
+void hw_iic_clr_end_pnd(hw_iic_dev iic)
+{
+ u8 id = iic_get_id(iic);
+
+ iic_end_pnd_clr(iic_regs[id]);
+}
+
+void hw_iic_slave_set_addr(hw_iic_dev iic, u8 addr, u8 addr_ack)
+{
+ u8 id = iic_get_id(iic);
+
+ iic_baud_reg(iic_regs[id]) = (addr & 0xfe) | !!addr_ack;
+}
+
+void hw_iic_slave_rx_prepare(hw_iic_dev iic, u8 ack)
+{
+ u8 id = iic_get_id(iic);
+
+ iic_dir_in(iic_regs[id]);
+ if (ack) {
+ iic_recv_ack(iic_regs[id]);
+ } else {
+ iic_recv_nack(iic_regs[id]);
+ }
+ iic_buf_reg(iic_regs[id]) = 0xff;
+ iic_cfg_done(iic_regs[id]);
+}
+
+u8 hw_iic_slave_rx_byte(hw_iic_dev iic, bool *is_start_addr)
+{
+ u8 id = iic_get_id(iic);
+ if (iic_start_pnd(iic_regs[id])) {
+ iic_start_pnd_clr(iic_regs[id]);
+ is_start_addr ? (*is_start_addr = 1) : 0;
+ } else {
+ is_start_addr ? (*is_start_addr = 0) : 0;
+ }
+ return iic_buf_reg(iic_regs[id]);
+}
+
+void hw_iic_slave_tx_byte(hw_iic_dev iic, u8 byte)
+{
+ u8 id = iic_get_id(iic);
+
+ iic_dir_out(iic_regs[id]);
+ iic_buf_reg(iic_regs[id]) = byte;
+ iic_cfg_done(iic_regs[id]);
+}
+
+u8 hw_iic_slave_tx_check_ack(hw_iic_dev iic)
+{
+ u8 id = iic_get_id(iic);
+
+ return iic_send_is_ack(iic_regs[id]);
+}
+void iic_disable_for_ota()
+{
+ JL_IIC->CON0 = 0;
+}
+
diff --git a/cpu/br28/iic_soft.c b/cpu/br28/iic_soft.c
new file mode 100644
index 0000000..09e33bf
--- /dev/null
+++ b/cpu/br28/iic_soft.c
@@ -0,0 +1,345 @@
+
+//#include "system/init.h"
+#include "asm/iic_soft.h"
+#include "generic/gpio.h"
+
+#define IIC_SCL_DIR(scl, val) \
+ gpio_set_direction(scl, val)
+
+#define IIC_SCL_SET_PU(scl, on) \
+ gpio_set_pull_up(scl, on)
+
+#define IIC_SCL_SET_PD(scl, on) \
+ gpio_set_pull_down(scl, on)
+
+#define IIC_SCL_SET_DIE(scl, on) \
+ gpio_set_die(scl, on)
+
+#define IIC_SCL_H(scl) \
+ gpio_set_direction(scl, 1)
+
+#define IIC_SCL_L(scl) \
+ gpio_direction_output(scl, 0)
+
+#define IIC_SDA_DIR(sda, val) \
+ gpio_set_direction(sda, val)
+
+#define IIC_SDA_SET_PU(sda, on) \
+ gpio_set_pull_up(sda, on)
+
+#define IIC_SDA_SET_PD(sda, on) \
+ gpio_set_pull_down(sda, on)
+
+#define IIC_SDA_SET_DIE(sda, on) \
+ gpio_set_die(sda, on)
+
+#define IIC_SDA_H(sda) \
+ gpio_set_direction(sda, 1)
+
+#define IIC_SDA_L(sda) \
+ gpio_direction_output(sda, 0)
+
+#define IIC_SDA_READ(sda) \
+ gpio_read(sda)
+
+#define iic_get_id(iic) (iic)
+
+static inline u32 iic_get_scl(soft_iic_dev iic)
+{
+ u8 id = iic_get_id(iic);
+ return soft_iic_cfg[id].scl;
+}
+
+static inline u32 iic_get_sda(soft_iic_dev iic)
+{
+ u8 id = iic_get_id(iic);
+ return soft_iic_cfg[id].sda;
+}
+
+static inline u32 iic_get_delay(soft_iic_dev iic)
+{
+ u8 id = iic_get_id(iic);
+ return soft_iic_cfg[id].delay;
+ /* return soft_iic_real_delay[id]; */
+}
+
+static inline u32 iic_get_io_pu(soft_iic_dev iic)
+{
+ u8 id = iic_get_id(iic);
+ return soft_iic_cfg[id].io_pu;
+}
+
+
+int soft_iic_init(soft_iic_dev iic)
+{
+ u32 scl, sda;
+
+ scl = iic_get_scl(iic);
+ sda = iic_get_sda(iic);
+
+ if (iic_get_io_pu(iic)) {
+ IIC_SCL_SET_PU(scl, 1);
+ IIC_SDA_SET_PU(sda, 1);
+ } else {
+ IIC_SCL_SET_PU(scl, 0);
+ IIC_SDA_SET_PU(sda, 0);
+ }
+
+ gpio_set_hd(scl, 0);
+ gpio_set_hd0(scl, 1);
+ gpio_set_hd(sda, 0);
+ gpio_set_hd0(sda, 1);
+ IIC_SDA_H(sda);
+ IIC_SCL_H(scl);
+ IIC_SCL_SET_PD(scl, 0);
+ IIC_SCL_SET_DIE(scl, 1);
+ IIC_SDA_SET_PD(sda, 0);
+ IIC_SDA_SET_DIE(sda, 1);
+ return 0;
+}
+
+void soft_iic_uninit(soft_iic_dev iic)
+{
+ u32 scl, sda;
+
+ scl = iic_get_scl(iic);
+ sda = iic_get_sda(iic);
+
+ IIC_SCL_DIR(scl, 1);
+ IIC_SCL_SET_PU(scl, 0);
+ IIC_SCL_SET_PD(scl, 0);
+ IIC_SCL_SET_DIE(scl, 0);
+ gpio_set_hd(scl, 0);
+ gpio_set_hd0(scl, 0);
+
+ IIC_SDA_DIR(sda, 1);
+ IIC_SDA_SET_PU(sda, 0);
+ IIC_SDA_SET_PD(sda, 0);
+ IIC_SDA_SET_DIE(sda, 0);
+ gpio_set_hd(sda, 0);
+ gpio_set_hd0(sda, 0);
+}
+
+void soft_iic_suspend(soft_iic_dev iic)
+{
+ u32 scl, sda;
+
+ scl = iic_get_scl(iic);
+ sda = iic_get_sda(iic);
+
+ IIC_SCL_SET_DIE(scl, 0);
+ IIC_SDA_SET_DIE(sda, 0);
+}
+
+void soft_iic_resume(soft_iic_dev iic)
+{
+ u32 scl, sda;
+
+ scl = iic_get_scl(iic);
+ sda = iic_get_sda(iic);
+
+ IIC_SCL_SET_DIE(scl, 1);
+ IIC_SDA_SET_DIE(sda, 1);
+}
+
+void soft_iic_start(soft_iic_dev iic)
+{
+ u32 scl, sda, dly_t;
+
+ scl = iic_get_scl(iic);
+ sda = iic_get_sda(iic);
+ dly_t = iic_get_delay(iic);
+
+ IIC_SDA_H(sda);
+ delay(dly_t);
+
+ IIC_SCL_H(scl);
+ delay(dly_t * 2);
+
+ IIC_SDA_L(sda);
+ delay(dly_t);
+
+ IIC_SCL_L(scl);
+ delay(dly_t);
+}
+
+void soft_iic_stop(soft_iic_dev iic)
+{
+ u32 scl, sda, dly_t;
+
+ scl = iic_get_scl(iic);
+ sda = iic_get_sda(iic);
+ dly_t = iic_get_delay(iic);
+
+ IIC_SDA_L(sda);
+ delay(dly_t);
+
+ IIC_SCL_H(scl);
+ delay(dly_t * 2);
+
+ IIC_SDA_H(sda);
+ delay(dly_t);
+}
+
+static u8 soft_iic_check_ack(soft_iic_dev iic)
+{
+ u8 ack;
+ u32 scl, sda, dly_t;
+
+ scl = iic_get_scl(iic);
+ sda = iic_get_sda(iic);
+ dly_t = iic_get_delay(iic);
+
+ IIC_SDA_DIR(sda, 1);
+ IIC_SCL_L(scl);
+ delay(dly_t);
+
+ IIC_SCL_H(scl);
+ delay(dly_t);
+
+ if (IIC_SDA_READ(sda) == 0) {
+ ack = 1;
+ } else {
+ ack = 0;
+ }
+ delay(dly_t);
+
+ IIC_SCL_L(scl);
+ delay(dly_t);
+ IIC_SDA_DIR(sda, 0);
+ IIC_SDA_L(sda);
+
+ return ack;
+}
+
+static void soft_iic_rx_ack(soft_iic_dev iic)
+{
+ u32 scl, sda, dly_t;
+
+ scl = iic_get_scl(iic);
+ sda = iic_get_sda(iic);
+ dly_t = iic_get_delay(iic);
+
+ IIC_SDA_L(sda);
+ delay(dly_t);
+
+ IIC_SCL_H(scl);
+ delay(dly_t * 2);
+
+ IIC_SCL_L(scl);
+ delay(dly_t);
+}
+
+static void soft_iic_rx_nack(soft_iic_dev iic)
+{
+ u32 scl, sda, dly_t;
+
+ scl = iic_get_scl(iic);
+ sda = iic_get_sda(iic);
+ dly_t = iic_get_delay(iic);
+
+ IIC_SDA_H(sda);
+ delay(dly_t);
+
+ IIC_SCL_H(scl);
+ delay(dly_t * 2);
+
+ IIC_SCL_L(scl);
+ delay(dly_t);
+}
+
+u8 soft_iic_tx_byte(soft_iic_dev iic, u8 byte)
+{
+ u8 i, ret;
+ u32 scl, sda, dly_t;
+
+ scl = iic_get_scl(iic);
+ sda = iic_get_sda(iic);
+ dly_t = iic_get_delay(iic);
+
+ IIC_SCL_L(scl);
+ for (i = 0; i < 8; i++) { //MSB FIRST
+ if ((byte << i) & 0x80) {
+ IIC_SDA_H(sda);
+ } else {
+ IIC_SDA_L(sda);
+ }
+ delay(dly_t);
+
+ IIC_SCL_H(scl);
+ delay(dly_t * 2);
+
+ IIC_SCL_L(scl);
+ delay(dly_t);
+ }
+ return soft_iic_check_ack(iic);
+}
+
+u8 soft_iic_rx_byte(soft_iic_dev iic, u8 ack)
+{
+ u8 byte = 0, i;
+ u32 scl, sda, dly_t;
+
+ scl = iic_get_scl(iic);
+ sda = iic_get_sda(iic);
+ dly_t = iic_get_delay(iic);
+
+ IIC_SDA_DIR(sda, 1);
+
+ for (i = 0; i < 8; i++) {
+ delay(dly_t);
+
+ IIC_SCL_H(scl);
+ delay(dly_t);
+
+ byte = byte << 1;
+ if (IIC_SDA_READ(sda)) {
+ byte |= 1;
+ }
+ delay(dly_t);
+
+ IIC_SCL_L(scl);
+ delay(dly_t);
+ }
+
+ IIC_SDA_DIR(sda, 0);
+ if (ack) {
+ soft_iic_rx_ack(iic);
+ } else {
+ soft_iic_rx_nack(iic);
+ }
+
+ return byte;
+}
+
+
+int soft_iic_read_buf(soft_iic_dev iic, void *buf, int len)
+{
+ int i = 0;
+
+ if (!buf || !len) {
+ return -1;
+ }
+ for (i = 0; i < len - 1; i++) {
+ ((u8 *)buf)[i] = soft_iic_rx_byte(iic, 1);
+ }
+ ((u8 *)buf)[len - 1] = soft_iic_rx_byte(iic, 0);
+ return len;
+}
+
+int soft_iic_write_buf(soft_iic_dev iic, const void *buf, int len)
+{
+ int i;
+ u8 ack;
+
+ if (!buf || !len) {
+ return -1;
+ }
+ for (i = 0; i < len; i++) {
+ ack = soft_iic_tx_byte(iic, ((u8 *)buf)[i]);
+ if (ack == 0) {
+ break;
+ }
+ }
+ return i;
+}
diff --git a/cpu/br28/irflt.c b/cpu/br28/irflt.c
new file mode 100644
index 0000000..84914d6
--- /dev/null
+++ b/cpu/br28/irflt.c
@@ -0,0 +1,234 @@
+#include "asm/includes.h"
+#include "asm/irflt.h"
+#include "timer.h"
+#include "generic/gpio.h"
+
+#define ir_log printf
+
+//红外定时器定义
+#define IR_TIMER TIMER5
+#define IR_IRQ_TIME_IDX IRQ_TIME5_IDX
+#define IR_TIME_REG JL_TIMER5
+
+#define USE_IRFLT_OUT 1
+
+IR_CODE ir_code; ///<红外遥控信息
+
+static u8 cmp_start = 0;
+
+static const u16 timer_div[] = {
+ /*0000*/ 1,
+ /*0001*/ 4,
+ /*0010*/ 16,
+ /*0011*/ 64,
+ /*0100*/ 2,
+ /*0101*/ 8,
+ /*0110*/ 32,
+ /*0111*/ 128,
+ /*1000*/ 256,
+ /*1001*/ 4 * 256,
+ /*1010*/ 16 * 256,
+ /*1011*/ 64 * 256,
+ /*1100*/ 2 * 256,
+ /*1101*/ 8 * 256,
+ /*1110*/ 32 * 256,
+ /*1111*/ 128 * 256,
+};
+
+
+/*----------------------------------------------------------------------------*/
+/**@brief time1红外中断服务函数
+ @param void
+ @param void
+ @return void
+ @note void timer1_ir_isr(void)
+*/
+/*----------------------------------------------------------------------------*/
+___interrupt
+void timer_ir_isr(void)
+{
+ IR_TIME_REG->CON |= BIT(14);
+ u16 bCap1 = IR_TIME_REG->PRD;
+ IR_TIME_REG->CNT = 0;
+ u8 cap = bCap1 / ir_code.timer_pad;
+
+ ir_code.boverflow = 0;
+
+ if (cmp_start < 3) {
+ return;
+ }
+
+ /* putchar('0' + (cap/10)); */
+ /* putchar('0' + (cap%10)); */
+
+ if (cap <= 1) {
+ ir_code.wData >>= 1;
+ ir_code.bState++;
+ } else if (cap == 2) {
+ ir_code.wData >>= 1;
+ ir_code.wData |= 0x8000;
+ ir_code.bState++;
+ }
+
+ if (ir_code.bState == 16) {
+ ir_code.wUserCode = ir_code.wData;
+ }
+ if (ir_code.bState == 33) {
+ ir_code.bState = 1;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief ir按键初始化
+ @param void
+ @param void
+ @return void
+ @note void set_ir_clk(void)
+
+ ((cnt - 1)* 分频数)/lsb_clk = 1ms
+*/
+/*----------------------------------------------------------------------------*/
+#define TIMER_UNIT_MS 1
+#define MAX_TIME_CNT 0x07ff //分频准确范围,更具实际情况调整
+#define MIN_TIME_CNT 0x0030
+void set_ir_clk(void)
+{
+ u32 prd_cnt;
+ u8 index;
+ u32 app_timer_clk = 24000000;
+
+ for (index = 0; index < (sizeof(timer_div) / sizeof(timer_div[0])); index++) {
+ prd_cnt = TIMER_UNIT_MS * (app_timer_clk / 1000) / timer_div[index];
+ if (prd_cnt > MIN_TIME_CNT && prd_cnt < MAX_TIME_CNT) {
+ break;
+ }
+ }
+ ir_code.timer_pad = prd_cnt;
+ cmp_start = 0;
+ if (IR_IRQ_TIME_IDX == IRQ_TIME3_IDX) {
+ bit_clr_ie(IRQ_TIME3_IDX);
+ }
+ request_irq(IR_IRQ_TIME_IDX, 5, timer_ir_isr, 0);
+#if USE_IRFLT_OUT
+ IR_TIME_REG->CON = ((6 << 10) | (index << 4) | BIT(2) | BIT(1) | BIT(0));
+#else
+ IR_TIME_REG->CON = ((6 << 10) | (index << 4) | BIT(1) | BIT(0));
+#endif
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief 获取ir按键值
+ @param void
+ @param void
+ @return void
+ @note void get_irkey_value(void)
+*/
+/*----------------------------------------------------------------------------*/
+u8 get_irflt_value(void)
+{
+ u8 tkey = 0xff;
+ if (ir_code.bState != 32) {
+ return tkey;
+ }
+ if ((((u8 *)&ir_code.wData)[0] ^ ((u8 *)&ir_code.wData)[1]) == 0xff) {
+ tkey = (u8)ir_code.wData;
+ } else {
+ ir_code.bState = 0;
+ }
+ return tkey;
+}
+
+static u8 ir_io_level = 0;
+static u8 ir_io = 0;
+void ir_input_io_sel(u8 port)
+{
+ ir_io = port;
+#if USE_IRFLT_OUT
+ gpio_ich_sel_iutput_signal(port, INPUT_CH_SIGNAL_IRFLT, INPUT_CH_TYPE_GP_ICH);
+#else
+ gpio_ich_sel_iutput_signal(port, INPUT_CH_SIGNAL_TIMER0_CAPTURE + 2 * IR_TIMER, INPUT_CH_TYPE_GP_ICH);
+#endif
+ gpio_set_direction(port, 1);
+ gpio_set_die(port, 1);
+ gpio_set_pull_up(port, 1);
+ gpio_set_pull_down(port, 0);
+}
+
+void ir_output_timer_sel()
+{
+}
+
+static void ir_timeout(void *priv)
+{
+ ir_code.boverflow++;
+ if (ir_code.boverflow > 56) { //56*2ms ~= 112ms
+ ir_code.boverflow = 56;
+ ir_code.bState = 0;
+ }
+ cmp_start ++;
+ if (cmp_start > 3) {
+ cmp_start = 3;
+ }
+}
+
+void ir_timeout_set(void)
+{
+ sys_s_hi_timer_add(NULL, ir_timeout, 2); //2ms
+}
+
+static u8 ir_io_sus = 0;
+u8 ir_io_suspend(void)
+{
+ if (ir_io_sus) {
+ return 1;
+ }
+ if (ir_code.boverflow < 7) { //14ms内,红外接收有可能在忙碌
+ return 1;
+ }
+ ir_io_level = gpio_read(ir_io);
+ IR_TIME_REG->CON |= BIT(14);
+ IR_TIME_REG->CON &= ~(0b11 << 0);
+ ir_io_sus = 1;
+ return 0;
+}
+
+u8 ir_io_resume(void)
+{
+ if (!ir_io_sus) {
+ return 0;
+ }
+ ir_io_sus = 0;
+ gpio_set_direction(ir_io, 1);
+ gpio_set_die(ir_io, 1);
+ gpio_set_pull_up(ir_io, 1);
+ gpio_set_pull_down(ir_io, 0);
+ delay(10);
+ if ((ir_io_level) && (ir_io_level != (gpio_read(ir_io)))) {
+ ir_code.boverflow = 0;
+ }
+ cmp_start = 0;
+ IR_TIME_REG->CNT = 0;
+ IR_TIME_REG->CON |= BIT(14);
+ IR_TIME_REG->CON |= (0b11 << 0);
+ return 0;
+}
+
+
+void irflt_config()
+{
+ JL_IR->RFLT_CON = 0;
+ /* JL_IR->RFLT_CON |= BIT(7); //256 div */
+ /* JL_IR->RFLT_CON |= BIT(3); //osc 24m */
+ JL_IR->RFLT_CON |= BIT(7) | BIT(4); //512 div
+ JL_IR->RFLT_CON |= BIT(3) | BIT(2); //PLL_48m(兼容省晶振)
+ JL_IR->RFLT_CON |= BIT(0); //irflt enable
+
+ set_ir_clk();
+}
+
+void log_irflt_info()
+{
+ ir_log("RFLT_CON = 0x%x", JL_IR->RFLT_CON);
+ ir_log("IR_TIME_REG = 0x%x", IR_TIME_REG->CON);
+}
+
diff --git a/cpu/br28/liba/SensorCalib.a b/cpu/br28/liba/SensorCalib.a
new file mode 100644
index 0000000..b1120f5
Binary files /dev/null and b/cpu/br28/liba/SensorCalib.a differ
diff --git a/cpu/br28/liba/SpatialAudio.a b/cpu/br28/liba/SpatialAudio.a
new file mode 100644
index 0000000..fc70305
Binary files /dev/null and b/cpu/br28/liba/SpatialAudio.a differ
diff --git a/cpu/br28/liba/VirtualBass.a b/cpu/br28/liba/VirtualBass.a
new file mode 100644
index 0000000..3d4aa35
Binary files /dev/null and b/cpu/br28/liba/VirtualBass.a differ
diff --git a/cpu/br28/liba/aac_dec_lib.a b/cpu/br28/liba/aac_dec_lib.a
new file mode 100644
index 0000000..e728eb0
Binary files /dev/null and b/cpu/br28/liba/aac_dec_lib.a differ
diff --git a/cpu/br28/liba/aec.a b/cpu/br28/liba/aec.a
new file mode 100644
index 0000000..ca9c952
Binary files /dev/null and b/cpu/br28/liba/aec.a differ
diff --git a/cpu/br28/liba/agreement.a b/cpu/br28/liba/agreement.a
new file mode 100644
index 0000000..76fb4b2
Binary files /dev/null and b/cpu/br28/liba/agreement.a differ
diff --git a/cpu/br28/liba/amr_dec_lib.a b/cpu/br28/liba/amr_dec_lib.a
new file mode 100644
index 0000000..5bcc3d9
Binary files /dev/null and b/cpu/br28/liba/amr_dec_lib.a differ
diff --git a/cpu/br28/liba/ape_dec_lib.a b/cpu/br28/liba/ape_dec_lib.a
new file mode 100644
index 0000000..5f90e88
Binary files /dev/null and b/cpu/br28/liba/ape_dec_lib.a differ
diff --git a/cpu/br28/liba/bfilterfun_lib.a b/cpu/br28/liba/bfilterfun_lib.a
new file mode 100644
index 0000000..e1e3c6e
Binary files /dev/null and b/cpu/br28/liba/bfilterfun_lib.a differ
diff --git a/cpu/br28/liba/bt_hash_enc.a b/cpu/br28/liba/bt_hash_enc.a
new file mode 100644
index 0000000..4a39294
Binary files /dev/null and b/cpu/br28/liba/bt_hash_enc.a differ
diff --git a/cpu/br28/liba/btctrler.a b/cpu/br28/liba/btctrler.a
new file mode 100644
index 0000000..c0b2b90
Binary files /dev/null and b/cpu/br28/liba/btctrler.a differ
diff --git a/cpu/br28/liba/btstack.a b/cpu/br28/liba/btstack.a
new file mode 100644
index 0000000..256cdda
Binary files /dev/null and b/cpu/br28/liba/btstack.a differ
diff --git a/cpu/br28/liba/compressor.a b/cpu/br28/liba/compressor.a
new file mode 100644
index 0000000..ed92c5d
Binary files /dev/null and b/cpu/br28/liba/compressor.a differ
diff --git a/cpu/br28/liba/cpu.a b/cpu/br28/liba/cpu.a
new file mode 100644
index 0000000..78cbd40
Binary files /dev/null and b/cpu/br28/liba/cpu.a differ
diff --git a/cpu/br28/liba/crossover_coff_old.a b/cpu/br28/liba/crossover_coff_old.a
new file mode 100644
index 0000000..a7b253a
Binary files /dev/null and b/cpu/br28/liba/crossover_coff_old.a differ
diff --git a/cpu/br28/liba/crypto_toolbox_Osize.a b/cpu/br28/liba/crypto_toolbox_Osize.a
new file mode 100644
index 0000000..0c57aa4
Binary files /dev/null and b/cpu/br28/liba/crypto_toolbox_Osize.a differ
diff --git a/cpu/br28/liba/drc.a b/cpu/br28/liba/drc.a
new file mode 100644
index 0000000..e156ce2
Binary files /dev/null and b/cpu/br28/liba/drc.a differ
diff --git a/cpu/br28/liba/dts_dec_lib.a b/cpu/br28/liba/dts_dec_lib.a
new file mode 100644
index 0000000..fc3d537
Binary files /dev/null and b/cpu/br28/liba/dts_dec_lib.a differ
diff --git a/cpu/br28/liba/flac_dec_lib.a b/cpu/br28/liba/flac_dec_lib.a
new file mode 100644
index 0000000..77b4ad4
Binary files /dev/null and b/cpu/br28/liba/flac_dec_lib.a differ
diff --git a/cpu/br28/liba/google_fps.a b/cpu/br28/liba/google_fps.a
new file mode 100644
index 0000000..5ede20d
Binary files /dev/null and b/cpu/br28/liba/google_fps.a differ
diff --git a/cpu/br28/liba/howling.a b/cpu/br28/liba/howling.a
new file mode 100644
index 0000000..b154e62
Binary files /dev/null and b/cpu/br28/liba/howling.a differ
diff --git a/cpu/br28/liba/lc3_codec_lib.a b/cpu/br28/liba/lc3_codec_lib.a
new file mode 100644
index 0000000..867afa1
Binary files /dev/null and b/cpu/br28/liba/lc3_codec_lib.a differ
diff --git a/cpu/br28/liba/ldac_dec_lib.a b/cpu/br28/liba/ldac_dec_lib.a
new file mode 100644
index 0000000..1e3b6b3
Binary files /dev/null and b/cpu/br28/liba/ldac_dec_lib.a differ
diff --git a/cpu/br28/liba/lfaudio_plc_lib.a b/cpu/br28/liba/lfaudio_plc_lib.a
new file mode 100644
index 0000000..19035bd
Binary files /dev/null and b/cpu/br28/liba/lfaudio_plc_lib.a differ
diff --git a/cpu/br28/liba/libAdaptiveEchoSuppress_pi32v2_OnChip.a b/cpu/br28/liba/libAdaptiveEchoSuppress_pi32v2_OnChip.a
new file mode 100644
index 0000000..c6fe4d2
Binary files /dev/null and b/cpu/br28/liba/libAdaptiveEchoSuppress_pi32v2_OnChip.a differ
diff --git a/cpu/br28/liba/libAptFilt_pi32v2_OnChip.a b/cpu/br28/liba/libAptFilt_pi32v2_OnChip.a
new file mode 100644
index 0000000..f6f1961
Binary files /dev/null and b/cpu/br28/liba/libAptFilt_pi32v2_OnChip.a differ
diff --git a/cpu/br28/liba/libDelayEstimate_pi32v2_OnChip.a b/cpu/br28/liba/libDelayEstimate_pi32v2_OnChip.a
new file mode 100644
index 0000000..030d355
Binary files /dev/null and b/cpu/br28/liba/libDelayEstimate_pi32v2_OnChip.a differ
diff --git a/cpu/br28/liba/libDualMicSystem_flexible_pi32v2_OnChip.a b/cpu/br28/liba/libDualMicSystem_flexible_pi32v2_OnChip.a
new file mode 100644
index 0000000..e276390
Binary files /dev/null and b/cpu/br28/liba/libDualMicSystem_flexible_pi32v2_OnChip.a differ
diff --git a/cpu/br28/liba/libDualMicSystem_pi32v2_OnChip.a b/cpu/br28/liba/libDualMicSystem_pi32v2_OnChip.a
new file mode 100644
index 0000000..ecaa80c
Binary files /dev/null and b/cpu/br28/liba/libDualMicSystem_pi32v2_OnChip.a differ
diff --git a/cpu/br28/liba/libEchoSuppress_pi32v2_OnChip.a b/cpu/br28/liba/libEchoSuppress_pi32v2_OnChip.a
new file mode 100644
index 0000000..a22c6b9
Binary files /dev/null and b/cpu/br28/liba/libEchoSuppress_pi32v2_OnChip.a differ
diff --git a/cpu/br28/liba/libFFT_pi32v2_OnChip.a b/cpu/br28/liba/libFFT_pi32v2_OnChip.a
new file mode 100644
index 0000000..0d2c9a0
Binary files /dev/null and b/cpu/br28/liba/libFFT_pi32v2_OnChip.a differ
diff --git a/cpu/br28/liba/libNoiseSuppress_pi32v2_OnChip.a b/cpu/br28/liba/libNoiseSuppress_pi32v2_OnChip.a
new file mode 100644
index 0000000..3dab718
Binary files /dev/null and b/cpu/br28/liba/libNoiseSuppress_pi32v2_OnChip.a differ
diff --git a/cpu/br28/liba/libOpcore_maskrom_pi32v2_OnChip.a b/cpu/br28/liba/libOpcore_maskrom_pi32v2_OnChip.a
new file mode 100644
index 0000000..1ae0e4b
Binary files /dev/null and b/cpu/br28/liba/libOpcore_maskrom_pi32v2_OnChip.a differ
diff --git a/cpu/br28/liba/libSplittingFilter_pi32v2_OnChip.a b/cpu/br28/liba/libSplittingFilter_pi32v2_OnChip.a
new file mode 100644
index 0000000..924167d
Binary files /dev/null and b/cpu/br28/liba/libSplittingFilter_pi32v2_OnChip.a differ
diff --git a/cpu/br28/liba/lib_diafx.a b/cpu/br28/liba/lib_diafx.a
new file mode 100644
index 0000000..8b2f6cd
Binary files /dev/null and b/cpu/br28/liba/lib_diafx.a differ
diff --git a/cpu/br28/liba/lib_dns.a b/cpu/br28/liba/lib_dns.a
new file mode 100644
index 0000000..4fc0b1b
Binary files /dev/null and b/cpu/br28/liba/lib_dns.a differ
diff --git a/cpu/br28/liba/lib_esco_repair.a b/cpu/br28/liba/lib_esco_repair.a
new file mode 100644
index 0000000..5ad3aa6
Binary files /dev/null and b/cpu/br28/liba/lib_esco_repair.a differ
diff --git a/cpu/br28/liba/lib_howlings_phf.a b/cpu/br28/liba/lib_howlings_phf.a
new file mode 100644
index 0000000..dc73b65
Binary files /dev/null and b/cpu/br28/liba/lib_howlings_phf.a differ
diff --git a/cpu/br28/liba/lib_icsd_adt.a b/cpu/br28/liba/lib_icsd_adt.a
new file mode 100644
index 0000000..3ad24e8
Binary files /dev/null and b/cpu/br28/liba/lib_icsd_adt.a differ
diff --git a/cpu/br28/liba/lib_icsd_anc.a b/cpu/br28/liba/lib_icsd_anc.a
new file mode 100644
index 0000000..c0d2910
Binary files /dev/null and b/cpu/br28/liba/lib_icsd_anc.a differ
diff --git a/cpu/br28/liba/lib_pitchshifter.a b/cpu/br28/liba/lib_pitchshifter.a
new file mode 100644
index 0000000..b89f2c7
Binary files /dev/null and b/cpu/br28/liba/lib_pitchshifter.a differ
diff --git a/cpu/br28/liba/lib_point360_td.a b/cpu/br28/liba/lib_point360_td.a
new file mode 100644
index 0000000..1860a60
Binary files /dev/null and b/cpu/br28/liba/lib_point360_td.a differ
diff --git a/cpu/br28/liba/lib_resample_cal.a b/cpu/br28/liba/lib_resample_cal.a
new file mode 100644
index 0000000..6b84a71
Binary files /dev/null and b/cpu/br28/liba/lib_resample_cal.a differ
diff --git a/cpu/br28/liba/lib_resample_fast_cal.a b/cpu/br28/liba/lib_resample_fast_cal.a
new file mode 100644
index 0000000..b92e755
Binary files /dev/null and b/cpu/br28/liba/lib_resample_fast_cal.a differ
diff --git a/cpu/br28/liba/lib_sur_cal.a b/cpu/br28/liba/lib_sur_cal.a
new file mode 100644
index 0000000..cbd1f00
Binary files /dev/null and b/cpu/br28/liba/lib_sur_cal.a differ
diff --git a/cpu/br28/liba/libepmotion.a b/cpu/br28/liba/libepmotion.a
new file mode 100644
index 0000000..0688309
Binary files /dev/null and b/cpu/br28/liba/libepmotion.a differ
diff --git a/cpu/br28/liba/libjlsp.a b/cpu/br28/liba/libjlsp.a
new file mode 100644
index 0000000..98f6775
Binary files /dev/null and b/cpu/br28/liba/libjlsp.a differ
diff --git a/cpu/br28/liba/libjlsp_kws.a b/cpu/br28/liba/libjlsp_kws.a
new file mode 100644
index 0000000..bf041df
Binary files /dev/null and b/cpu/br28/liba/libjlsp_kws.a differ
diff --git a/cpu/br28/liba/libkwscommon.a b/cpu/br28/liba/libkwscommon.a
new file mode 100644
index 0000000..4e93d81
Binary files /dev/null and b/cpu/br28/liba/libkwscommon.a differ
diff --git a/cpu/br28/liba/libllns.a b/cpu/br28/liba/libllns.a
new file mode 100644
index 0000000..3ed3585
Binary files /dev/null and b/cpu/br28/liba/libllns.a differ
diff --git a/cpu/br28/liba/limiter.a b/cpu/br28/liba/limiter.a
new file mode 100644
index 0000000..0ab25c9
Binary files /dev/null and b/cpu/br28/liba/limiter.a differ
diff --git a/cpu/br28/liba/limiter_noiseGate.a b/cpu/br28/liba/limiter_noiseGate.a
new file mode 100644
index 0000000..502a621
Binary files /dev/null and b/cpu/br28/liba/limiter_noiseGate.a differ
diff --git a/cpu/br28/liba/m4a_dec_lib.a b/cpu/br28/liba/m4a_dec_lib.a
new file mode 100644
index 0000000..49663cb
Binary files /dev/null and b/cpu/br28/liba/m4a_dec_lib.a differ
diff --git a/cpu/br28/liba/media.a b/cpu/br28/liba/media.a
new file mode 100644
index 0000000..202acd1
Binary files /dev/null and b/cpu/br28/liba/media.a differ
diff --git a/cpu/br28/liba/media_app.a b/cpu/br28/liba/media_app.a
new file mode 100644
index 0000000..44e88a7
Binary files /dev/null and b/cpu/br28/liba/media_app.a differ
diff --git a/cpu/br28/liba/mp3_dec_lib.a b/cpu/br28/liba/mp3_dec_lib.a
new file mode 100644
index 0000000..a9057fd
Binary files /dev/null and b/cpu/br28/liba/mp3_dec_lib.a differ
diff --git a/cpu/br28/liba/mp3_decstream_lib.a b/cpu/br28/liba/mp3_decstream_lib.a
new file mode 100644
index 0000000..bd8c6e9
Binary files /dev/null and b/cpu/br28/liba/mp3_decstream_lib.a differ
diff --git a/cpu/br28/liba/mp3tsy_dec_lib.a b/cpu/br28/liba/mp3tsy_dec_lib.a
new file mode 100644
index 0000000..4112a37
Binary files /dev/null and b/cpu/br28/liba/mp3tsy_dec_lib.a differ
diff --git a/cpu/br28/liba/noisegate.a b/cpu/br28/liba/noisegate.a
new file mode 100644
index 0000000..b949cf5
Binary files /dev/null and b/cpu/br28/liba/noisegate.a differ
diff --git a/cpu/br28/liba/opus_dec_lib.a b/cpu/br28/liba/opus_dec_lib.a
new file mode 100644
index 0000000..1e5af28
Binary files /dev/null and b/cpu/br28/liba/opus_dec_lib.a differ
diff --git a/cpu/br28/liba/opus_enc_lib.a b/cpu/br28/liba/opus_enc_lib.a
new file mode 100644
index 0000000..f095f8e
Binary files /dev/null and b/cpu/br28/liba/opus_enc_lib.a differ
diff --git a/cpu/br28/liba/rcsp_stack.a b/cpu/br28/liba/rcsp_stack.a
new file mode 100644
index 0000000..cce3d2d
Binary files /dev/null and b/cpu/br28/liba/rcsp_stack.a differ
diff --git a/cpu/br28/liba/sbc_eng_lib.a b/cpu/br28/liba/sbc_eng_lib.a
new file mode 100644
index 0000000..3341b7c
Binary files /dev/null and b/cpu/br28/liba/sbc_eng_lib.a differ
diff --git a/cpu/br28/liba/speex_enc_lib.a b/cpu/br28/liba/speex_enc_lib.a
new file mode 100644
index 0000000..2ed5f65
Binary files /dev/null and b/cpu/br28/liba/speex_enc_lib.a differ
diff --git a/cpu/br28/liba/system.a b/cpu/br28/liba/system.a
new file mode 100644
index 0000000..3643ca1
Binary files /dev/null and b/cpu/br28/liba/system.a differ
diff --git a/cpu/br28/liba/tme_stack.a b/cpu/br28/liba/tme_stack.a
new file mode 100644
index 0000000..24ba277
Binary files /dev/null and b/cpu/br28/liba/tme_stack.a differ
diff --git a/cpu/br28/liba/update.a b/cpu/br28/liba/update.a
new file mode 100644
index 0000000..dd08807
Binary files /dev/null and b/cpu/br28/liba/update.a differ
diff --git a/cpu/br28/liba/update000.a b/cpu/br28/liba/update000.a
new file mode 100644
index 0000000..dfe6aea
Binary files /dev/null and b/cpu/br28/liba/update000.a differ
diff --git a/cpu/br28/liba/wav_dec_lib.a b/cpu/br28/liba/wav_dec_lib.a
new file mode 100644
index 0000000..7212e8e
Binary files /dev/null and b/cpu/br28/liba/wav_dec_lib.a differ
diff --git a/cpu/br28/liba/wma_dec_lib.a b/cpu/br28/liba/wma_dec_lib.a
new file mode 100644
index 0000000..b3e450f
Binary files /dev/null and b/cpu/br28/liba/wma_dec_lib.a differ
diff --git a/cpu/br28/liba/wtg_dec_lib.a b/cpu/br28/liba/wtg_dec_lib.a
new file mode 100644
index 0000000..e72d98b
Binary files /dev/null and b/cpu/br28/liba/wtg_dec_lib.a differ
diff --git a/cpu/br28/lp_touch_key.c b/cpu/br28/lp_touch_key.c
new file mode 100644
index 0000000..09aed5a
--- /dev/null
+++ b/cpu/br28/lp_touch_key.c
@@ -0,0 +1,1595 @@
+#include "includes.h"
+#include "asm/power/p11.h"
+#include "asm/power/p33.h"
+#include "asm/lp_touch_key_tool.h"
+#include "asm/lp_touch_key_alog.h"
+#include "device/key_driver.h"
+#include "key_event_deal.h"
+#include "app_config.h"
+#include "asm/lp_touch_key_api.h"
+#include "asm/charge.h"
+
+#define LOG_TAG_CONST LP_KEY
+#define LOG_TAG "[LP_KEY]"
+/* #define LOG_ERROR_ENABLE */
+/* #define LOG_DEBUG_ENABLE */
+#define LOG_INFO_ENABLE
+#define LOG_DUMP_ENABLE
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+
+#if TCFG_LP_TOUCH_KEY_ENABLE
+
+#define CTMU_CHECK_LONG_CLICK_BY_RES 1
+
+/*************************************************************************************************************************
+ lp_touch_key driver
+*************************************************************************************************************************/
+
+#define LP_TOUCH_KEY_TIMER_MAGIC_NUM 0xFFFF
+
+struct ctmu_key _ctmu_key = {
+ .slide_dir = TOUCH_KEY_EVENT_MAX,
+ .click_cnt = {0, 0, 0, 0, 0},
+ .last_key = {CTMU_KEY_NULL, CTMU_KEY_NULL, CTMU_KEY_NULL, CTMU_KEY_NULL, CTMU_KEY_NULL},
+ .short_timer = {LP_TOUCH_KEY_TIMER_MAGIC_NUM, LP_TOUCH_KEY_TIMER_MAGIC_NUM, LP_TOUCH_KEY_TIMER_MAGIC_NUM, LP_TOUCH_KEY_TIMER_MAGIC_NUM, LP_TOUCH_KEY_TIMER_MAGIC_NUM},
+};
+
+#define __this (&_ctmu_key)
+
+static volatile u8 is_lpkey_active = 0;
+
+
+extern void lp_touch_key_send_cmd(enum CTMU_M2P_CMD cmd);
+
+//======================================================//
+// 内置触摸灵敏度表, 由内置触摸灵敏度调试工具生成 //
+// 请将该表替换sdk中lp_touch_key.c中同名的参数表 //
+//======================================================//
+const static struct ch_adjust_table ch_sensitivity_table[] = {
+ /* cfg0 cfg1 cfg2 */
+//ch0 PB0
+ { 109, 131, 4318}, // level 0
+ { 109, 131, 3982}, // level 1
+ { 109, 131, 3646}, // level 2
+ { 109, 131, 3310}, // level 3
+ { 109, 131, 2974}, // level 4
+ { 109, 131, 2638}, // level 5
+ { 109, 131, 2303}, // level 6
+ { 109, 131, 1967}, // level 7
+ { 109, 131, 1631}, // level 8
+ { 109, 131, 1295}, // level 9
+//ch1 PB1
+ { 10, 15, 126}, // level 0
+ { 10, 15, 117}, // level 1
+ { 10, 15, 107}, // level 2
+ { 10, 15, 97}, // level 3
+ { 10, 15, 87}, // level 4
+ { 10, 15, 77}, // level 5
+ { 10, 15, 67}, // level 6
+ { 10, 15, 57}, // level 7
+ { 10, 15, 47}, // level 8
+ { 10, 15, 38}, // level 9
+//ch2 PB2
+ { 10, 15, 152}, // level 0
+ { 10, 15, 140}, // level 1
+ { 10, 15, 128}, // level 2
+ { 10, 15, 116}, // level 3
+ { 10, 15, 104}, // level 4
+ { 10, 15, 92}, // level 5
+ { 10, 15, 81}, // level 6
+ { 10, 15, 69}, // level 7
+ { 10, 15, 57}, // level 8
+ { 10, 15, 45}, // level 9
+//ch3 PB4
+ { 10, 15, 152}, // level 0
+ { 10, 15, 140}, // level 1
+ { 10, 15, 128}, // level 2
+ { 10, 15, 116}, // level 3
+ { 10, 15, 104}, // level 4
+ { 10, 15, 92}, // level 5
+ { 10, 15, 81}, // level 6
+ { 10, 15, 69}, // level 7
+ { 10, 15, 57}, // level 8
+ { 10, 15, 45}, // level 9
+ //ch4 PB5
+ { 109, 131, 4318}, // level 0
+ { 109, 131, 3982}, // level 1
+ { 109, 131, 3646}, // level 2
+ { 109, 131, 3310}, // level 3
+ { 109, 131, 2974}, // level 4
+ { 109, 131, 2638}, // level 5
+ { 109, 131, 2303}, // level 6
+ { 109, 131, 1967}, // level 7
+ { 109, 131, 1631}, // level 8
+ { 109, 131, 1295}, // level 9
+};
+
+
+#define LPCTMU_VH_LEVEL 3 // 上限电压档位
+#define LPCTMU_VL_LEVEL 0 // 下限电压档位
+#define LPCTMU_CUR_LEVEL 7 // 充放电电流档位
+
+static const u8 lpctmu_ana_vh_table[4] = {
+ LPCTMU_VH_065V,
+ LPCTMU_VH_070V,
+ LPCTMU_VH_075V,
+ LPCTMU_VH_080V,
+};
+static const u8 lpctmu_ana_vl_table[4] = {
+ LPCTMU_VL_020V,
+ LPCTMU_VL_025V,
+ LPCTMU_VL_030V,
+ LPCTMU_VL_035V,
+};
+static const u8 lpctmu_ana_cur_table[8] = {
+ LPCTMU_ISEL_036UA,
+ LPCTMU_ISEL_072UA,
+ LPCTMU_ISEL_108UA,
+ LPCTMU_ISEL_144UA,
+ LPCTMU_ISEL_180UA,
+ LPCTMU_ISEL_216UA,
+ LPCTMU_ISEL_252UA,
+ LPCTMU_ISEL_288UA
+};
+
+u8 get_lpctmu_ana_level(void)
+{
+ return ((lpctmu_ana_vh_table[LPCTMU_VH_LEVEL]) | \
+ (lpctmu_ana_vl_table[LPCTMU_VL_LEVEL]) | \
+ (lpctmu_ana_cur_table[LPCTMU_CUR_LEVEL]));
+}
+
+
+struct lp_touch_key_alog_cfg {
+ u16 ready_flag;
+ u16 range;
+ s32 sigma;
+};
+static struct lp_touch_key_alog_cfg alog_cfg[5];
+static u32 alog_sta_cnt[5];
+static u8 ch_range_sensity[5] = {7, 7, 7, 7, 7};
+static u16 save_alog_cfg_timeout[5] = {0, 0, 0, 0, 0};
+static u16 ctmu_res_scan_time_add = 0;
+#define TOUCH_RANGE_MIN 50
+#define TOUCH_RANGE_MAX 500
+
+#define CTMU_RES_BUF_SIZE 15
+static u16 ctmu_res_buf[5][CTMU_RES_BUF_SIZE];
+static u16 ctmu_res_buf_in[5] = {0, 0, 0, 0, 0};
+static u16 falling_res_avg[5] = {0, 0, 0, 0, 0};
+static u16 long_event_res_avg[5] = {0, 0, 0, 0, 0};
+
+static const u8 _ch_priv[5] = {0, 1, 2, 3, 4};
+
+int __attribute__((weak)) lp_touch_key_event_remap(struct sys_event *e)
+{
+ return true;
+}
+
+static void __ctmu_notify_key_event(struct sys_event *event, u8 ch)
+{
+
+#if CFG_DISABLE_KEY_EVENT
+ return;
+#endif
+
+ event->type = SYS_KEY_EVENT;
+ event->u.key.type = KEY_DRIVER_TYPE_CTMU_TOUCH; //区分按键类型
+ event->arg = (void *)DEVICE_EVENT_FROM_KEY;
+
+ if (__this->key_ch_msg_lock) {//锁住期间不能发消息
+ return;
+ }
+
+#if TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE
+ if (lp_touch_key_online_debug_key_event_handle(ch, event)) {
+ return;
+ }
+#endif /* #if TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE */
+
+ if (lp_touch_key_event_remap(event)) {
+ sys_event_notify(event);
+ }
+}
+
+__attribute__((weak)) u8 remap_ctmu_short_click_event(u8 ch, u8 click_cnt, u8 event)
+{
+ return event;
+}
+
+
+#if (TCFG_LP_SLIDE_KEY_ENABLE && (!TCFG_LP_SLIDE_KEY_SHORT_DISTANCE))
+
+u8 __attribute__((weak)) ctmu_slide_direction_handle(u8 cur_ch, u8 pre_ch)
+{
+ if ((cur_ch == 0xff) || (pre_ch == 0xff)) {
+ return TOUCH_KEY_EVENT_MAX;
+ }
+ u8 dir_case = (pre_ch << 4) | (cur_ch & 0xf);
+ log_debug("ctmu_touch_key_slide_direction = 0x%x : %x -> %x\n", dir_case, pre_ch, cur_ch);
+ switch (dir_case) {
+ case 0x12: //方向 1 -> 2
+ case 0x23: //方向 2 -> 3
+ case 0x13: //方向 1 -> 3
+ return TOUCH_KEY_EVENT_SLIDE_UP;
+ break;
+ case 0x32: //方向 3 -> 2
+ case 0x21: //方向 2 -> 1
+ case 0x31: //方向 3 -> 1
+ return TOUCH_KEY_EVENT_SLIDE_DOWN;
+ break;
+ }
+ return TOUCH_KEY_EVENT_MAX;
+}
+
+#endif
+
+static void __ctmu_short_click_time_out_handle(void *priv)
+{
+ u8 ch = *((u8 *)priv);
+ struct sys_event e;
+ switch (__this->click_cnt[ch]) {
+ case 0:
+ return;
+ break;
+ case 1:
+ e.u.key.event = KEY_EVENT_CLICK;
+ break;
+ case 2:
+ e.u.key.event = KEY_EVENT_DOUBLE_CLICK;
+ break;
+ case 3:
+ e.u.key.event = KEY_EVENT_TRIPLE_CLICK;
+ break;
+ case 4:
+ e.u.key.event = KEY_EVENT_FOURTH_CLICK;
+ break;
+ case 5:
+ e.u.key.event = KEY_EVENT_FIRTH_CLICK;
+ break;
+ default:
+ e.u.key.event = KEY_EVENT_USER;
+ break;
+ }
+
+ e.u.key.event = remap_ctmu_short_click_event(ch, __this->click_cnt[ch], e.u.key.event);
+ e.u.key.value = __this->config->ch[ch].key_value;
+
+#if (TCFG_LP_SLIDE_KEY_ENABLE && (!TCFG_LP_SLIDE_KEY_SHORT_DISTANCE))
+ if (__this->slide_dir < TOUCH_KEY_EVENT_MAX) {
+ e.u.key.event = __this->slide_dir;
+ e.u.key.value = __this->config->slide_mode_key_value;
+ __this->slide_dir = ctmu_slide_direction_handle(0xff, 0xff);
+ }
+#endif
+
+ log_debug("notify key%d short event, cnt: %d", ch, __this->click_cnt[ch]);
+ __ctmu_notify_key_event(&e, ch);
+
+ __this->short_timer[ch] = LP_TOUCH_KEY_TIMER_MAGIC_NUM;
+ __this->last_key[ch] = CTMU_KEY_NULL;
+ __this->click_cnt[ch] = 0;
+}
+
+static void ctmu_short_click_handle(u8 ch)
+{
+ static u8 pre_ch = 0xff;
+ __this->slide_dir = TOUCH_KEY_EVENT_MAX;
+ __this->last_key[ch] = CTMU_KEY_SHORT_CLICK;
+ if (__this->short_timer[ch] == LP_TOUCH_KEY_TIMER_MAGIC_NUM) {
+
+#if (TCFG_LP_SLIDE_KEY_ENABLE && (!TCFG_LP_SLIDE_KEY_SHORT_DISTANCE))
+ if (__this->config->slide_mode_en) {
+ if ((pre_ch != 0xff) && (pre_ch != ch) && (__this->click_cnt[pre_ch] == 1)) {
+ usr_timeout_del(__this->short_timer[pre_ch]);
+ __this->short_timer[pre_ch] = LP_TOUCH_KEY_TIMER_MAGIC_NUM;
+ __this->click_cnt[pre_ch] = 0;
+ __this->last_key[pre_ch] = CTMU_KEY_NULL;
+ __this->slide_dir = ctmu_slide_direction_handle(ch, pre_ch);
+ }
+ pre_ch = ch;
+ }
+#endif
+ __this->click_cnt[ch] = 1;
+#if (TCFG_LP_SLIDE_KEY_ENABLE && TCFG_LP_SLIDE_KEY_SHORT_DISTANCE)
+ __this->short_timer[ch] = usr_timeout_add((void *)&_ch_priv[ch], __ctmu_short_click_time_out_handle, CTMU_SHORT_CLICK_DELAY_TIME + 150, 1);
+#else
+ __this->short_timer[ch] = usr_timeout_add((void *)&_ch_priv[ch], __ctmu_short_click_time_out_handle, CTMU_SHORT_CLICK_DELAY_TIME, 1);
+#endif
+ } else {
+ __this->click_cnt[ch]++;
+ usr_timer_modify(__this->short_timer[ch], CTMU_SHORT_CLICK_DELAY_TIME);
+ }
+}
+
+static void ctmu_raise_click_handle(u8 ch)
+{
+ struct sys_event e = {0};
+ if (__this->last_key[ch] >= CTMU_KEY_LONG_CLICK) {
+ e.u.key.event = KEY_EVENT_UP;
+ e.u.key.value = __this->config->ch[ch].key_value;
+ __ctmu_notify_key_event(&e, ch);
+
+ __this->last_key[ch] = CTMU_KEY_NULL;
+ log_debug("notify key HOLD UP event");
+ } else {
+ ctmu_short_click_handle(ch);
+ }
+}
+
+static void ctmu_long_click_handle(u8 ch)
+{
+ __this->last_key[ch] = CTMU_KEY_LONG_CLICK;
+
+ struct sys_event e;
+ e.u.key.event = KEY_EVENT_LONG;
+ e.u.key.value = __this->config->ch[ch].key_value;
+
+ __ctmu_notify_key_event(&e, ch);
+}
+
+static void ctmu_hold_click_handle(u8 ch)
+{
+ __this->last_key[ch] = CTMU_KEY_HOLD_CLICK;
+
+ struct sys_event e;
+ e.u.key.event = KEY_EVENT_HOLD;
+ e.u.key.value = __this->config->ch[ch].key_value;
+
+ __ctmu_notify_key_event(&e, ch);
+}
+
+
+#if TCFG_LP_EARTCH_KEY_ENABLE
+
+__attribute__((weak))
+void ear_lptouch_update_state(u8 state)
+{
+ return;
+}
+
+static void __ctmu_ear_in_timeout_handle(void *priv)
+{
+#if CFG_DISABLE_INEAR_EVENT
+ return;
+#endif
+ if (__this->config->ch[__this->config->eartch_ch].key_value == 0xFF) {
+ //使用外部自定义流程
+ if (__this->eartch_last_state == EAR_IN) {
+ ear_lptouch_update_state(0);
+ } else {
+ ear_lptouch_update_state(1);
+ }
+ return;
+ }
+
+#if TCFG_EARTCH_EVENT_HANDLE_ENABLE
+ u8 state;
+ if (__this->eartch_last_state == EAR_IN) {
+ state = EARTCH_STATE_IN;
+ } else if (__this->eartch_last_state == EAR_OUT) {
+ state = EARTCH_STATE_OUT;
+ } else {
+ return;
+ }
+ eartch_state_update(state);
+#endif /* #if TCFG_EARTCH_EVENT_HANDLE_ENABLE */
+}
+
+static void __ctmu_key_unlock_timeout_handle(void *priv)
+{
+ __this->key_ch_msg_lock = false;
+ __this->key_ch_msg_lock_timer = 0;
+}
+
+static void ctmu_eartch_event_handle(u8 eartch_state)
+{
+ __this->eartch_last_state = eartch_state;
+
+#if TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE
+ struct sys_event event;
+ if (eartch_state == EAR_IN) {
+ event.u.key.event = 10;
+ } else if (eartch_state == EAR_OUT) {
+ event.u.key.event = 11;
+ }
+ if (lp_touch_key_online_debug_key_event_handle(__this->config->eartch_ch, &event)) {
+ return;
+ }
+#endif /* #if TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE */
+
+ __this->key_ch_msg_lock = true;
+
+ if (__this->key_ch_msg_lock_timer == 0) {
+ __this->key_ch_msg_lock_timer = sys_hi_timeout_add(NULL, __ctmu_key_unlock_timeout_handle, ERATCH_KEY_MSG_LOCK_TIME);
+ } else {
+ sys_hi_timer_modify(__this->key_ch_msg_lock_timer, ERATCH_KEY_MSG_LOCK_TIME);
+ }
+ __ctmu_ear_in_timeout_handle(NULL);
+}
+
+#endif
+
+/*************************************************************************************************************************
+ lp_touch_key driver
+*************************************************************************************************************************/
+#if CTMU_CHECK_LONG_CLICK_BY_RES
+
+static void lp_touch_key_ctmu_res_buf_clear(u8 ch)
+{
+ ctmu_res_buf_in[ch] = 0;
+ for (u8 i = 0; i < CTMU_RES_BUF_SIZE; i ++) {
+ ctmu_res_buf[ch][i] = 0;
+ }
+}
+
+static void lp_touch_key_ctmu_res_all_buf_clear(void)
+{
+ for (u8 ch = 0; ch < LP_CTMU_CHANNEL_SIZE; ch ++) {
+ lp_touch_key_ctmu_res_buf_clear(ch);
+ }
+}
+
+static u32 lp_touch_key_ctmu_res_buf_avg(u8 ch)
+{
+#if !TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE
+ u32 res_sum = 0;
+ u8 j = 0;
+ u8 cnt = ctmu_res_buf_in[ch];
+ for (u8 i = 0; i < (CTMU_RES_BUF_SIZE - 5); i ++) {
+ if (ctmu_res_buf[ch][cnt]) {
+ res_sum += ctmu_res_buf[ch][cnt];
+ j ++;
+ } else {
+ return 0;
+ }
+ cnt ++;
+ if (cnt >= CTMU_RES_BUF_SIZE) {
+ cnt = 0;
+ }
+ }
+ if (res_sum) {
+ return (res_sum / j);
+ }
+#endif
+ return 0;
+}
+
+static u8 lp_touch_key_check_long_click_by_ctmu_res(u8 ch)
+{
+#if !TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE
+ long_event_res_avg[ch] = lp_touch_key_ctmu_res_buf_avg(ch);
+ log_debug("long_event_res_avg: %d\n", long_event_res_avg[ch]);
+ if ((falling_res_avg[ch] < 2000) || \
+ (falling_res_avg[ch] > 20000) || \
+ (long_event_res_avg[ch] < 2000) || \
+ (long_event_res_avg[ch] > 20000)) {
+ } else {
+ u16 cfg2 = (M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG2H + ch * 8) << 8) | M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG2L + ch * 8);
+ u16 diff = (falling_res_avg[ch] > long_event_res_avg[ch]) ? (falling_res_avg[ch] - long_event_res_avg[ch]) : (long_event_res_avg[ch] - falling_res_avg[ch]);
+ if (diff < (cfg2 / 2)) {
+ log_debug("long event return ! diff: %d < cfg2/2: %d\n", diff, (cfg2 / 2));
+
+ //复位算法
+ lp_touch_key_send_cmd(CTMU_M2P_RESET_ALGO);
+ return 1;
+ }
+ }
+#endif
+ return 0;
+}
+
+#endif
+
+u8 lp_touch_key_alog_range_display(u8 *display_buf)
+{
+ if (__this->init == 0) {
+ return 0;
+ }
+ u8 tmp_buf[32], i = 0;
+ memset(tmp_buf, 0, sizeof(tmp_buf));
+ for (u8 ch = 0; ch < LP_CTMU_CHANNEL_SIZE; ch ++) {
+ if (__this->config->ch[ch].enable) {
+ u16 range = alog_cfg[ch].range % 1000;
+ tmp_buf[0 + i * 4] = (range / 100) + '0';
+ tmp_buf[1 + i * 4] = ((range % 100) / 10) + '0';
+ tmp_buf[2 + i * 4] = (range % 10) + '0';
+ tmp_buf[3 + i * 4] = ' ';
+ i ++;
+ }
+ }
+ if (i) {
+ display_buf[0] = i * 4 + 1;
+ display_buf[1] = 0x01;
+ memcpy((u8 *)&display_buf[2], tmp_buf, i * 4);
+ printf_buf(display_buf, i * 4 + 2);
+ return (display_buf[0] + 1);
+ }
+ return 0;
+}
+
+#if !TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE
+
+void lp_touch_key_save_alog_cfg(void *priv)
+{
+ u8 ch = *((u8 *)priv);
+ int ret = syscfg_write(VM_LP_TOUCH_KEY0_ALOG_CFG + ch, (void *)&alog_cfg[ch], sizeof(struct lp_touch_key_alog_cfg));
+ if (ret != sizeof(struct lp_touch_key_alog_cfg)) {
+ log_info("write vm alog cfg ready flag error !\n");
+ }
+ save_alog_cfg_timeout[ch] = 0;
+}
+
+void lp_touch_key_ctmu_cfg2_check_update(u8 ch, u16 cfg2_new)
+{
+ u16 cfg0 = (M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG0H + ch * 8) << 8) | M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG0L + ch * 8);
+ u16 cfg2_old = (M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG2H + ch * 8) << 8) | M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG2L + ch * 8);
+ if ((cfg2_old != cfg2_new) && (cfg2_new > (3 * cfg0))) {
+ printf("ctmu ch%d cfg2_old = %d cfg2_new = %d\n", ch, cfg2_old, cfg2_new);
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG2L + ch * 8) = cfg2_new & 0xff;
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG2H + ch * 8) = (cfg2_new >> 8) & 0xff;
+ u16 cfg1 = (M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG1H + ch * 8) << 8) | (M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG1L + ch * 8));
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG0L + ch * 8) = cfg1 & 0xff;
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG0H + ch * 8) = (cfg1 >> 8) & 0xff;
+ }
+}
+
+static void lp_touch_key_ctmu_res_scan(void *priv)
+{
+ for (u8 ch = 0; ch < LP_CTMU_CHANNEL_SIZE; ch ++) {
+ if (__this->config->ch[ch].enable) {
+ if (__this->config->eartch_en && (__this->config->eartch_ch == ch)) {
+ } else {
+ u16 ctmu_res0;
+ u16 ctmu_res1;
+__read_res:
+ ctmu_res0 = (P2M_MESSAGE_ACCESS(P2M_MASSAGE_CTMU_CH0_H_RES + ch * 2) << 8) | P2M_MESSAGE_ACCESS(P2M_MASSAGE_CTMU_CH0_L_RES + ch * 2);
+ delay(100);
+ ctmu_res1 = (P2M_MESSAGE_ACCESS(P2M_MASSAGE_CTMU_CH0_H_RES + ch * 2) << 8) | P2M_MESSAGE_ACCESS(P2M_MASSAGE_CTMU_CH0_L_RES + ch * 2);
+ if (ctmu_res0 != ctmu_res1) {
+ goto __read_res;
+ }
+#if 1
+
+ if ((ctmu_res0 < 2000) || (ctmu_res0 > 20000)) {
+ continue;
+ }
+
+#if CTMU_CHECK_LONG_CLICK_BY_RES
+ ctmu_res_buf[ch][ctmu_res_buf_in[ch]] = ctmu_res0;
+ ctmu_res_buf_in[ch] ++;
+ if (ctmu_res_buf_in[ch] >= CTMU_RES_BUF_SIZE) {
+ ctmu_res_buf_in[ch] = 0;
+ }
+#endif
+
+ if (alog_cfg[ch].ready_flag == 0) {
+ continue;
+ }
+ if (alog_sta_cnt[ch] < 50) {
+ alog_sta_cnt[ch] ++;
+ continue;
+ }
+ TouchAlgo_Update(ch, ctmu_res0);
+
+ u8 range_valid = 0;
+ u16 touch_range = TouchAlgo_GetRange(ch, (u8 *)&range_valid);
+ s32 touch_sigma = TouchAlgo_GetSigma(ch);
+ /* printf("ch%d res:%d range:%d val:%d sigma:%d\n", ch, ctmu_res0, touch_range, range_valid, touch_sigma); */
+ if ((range_valid) && (touch_range > TOUCH_RANGE_MIN) && (touch_range < TOUCH_RANGE_MAX)) {
+ if (touch_range != alog_cfg[ch].range) {
+ u16 cfg2_new = touch_range * (10 - ch_range_sensity[ch]) / 10;
+ lp_touch_key_ctmu_cfg2_check_update(ch, cfg2_new);
+ alog_cfg[ch].range = touch_range;
+ alog_cfg[ch].sigma = touch_sigma;
+ if (save_alog_cfg_timeout[ch] == 0) {
+ save_alog_cfg_timeout[ch] = sys_timeout_add((void *)&_ch_priv[ch], lp_touch_key_save_alog_cfg, 1);
+ }
+ }
+ } else if ((range_valid) && (touch_range >= TOUCH_RANGE_MAX)) {
+ TouchAlgo_SetRange(ch, alog_cfg[ch].range);
+ }
+#endif
+ }
+ }
+ }
+}
+
+void lp_touch_key_alog_ready_flag_check_and_set(void)
+{
+ for (u8 ch = 0; ch < LP_CTMU_CHANNEL_SIZE; ch ++) {
+ if (__this->config->ch[ch].enable) {
+ if (__this->config->eartch_en && (__this->config->eartch_ch == ch)) {
+ } else {
+ alog_cfg[ch].ready_flag = 0;
+ syscfg_read(VM_LP_TOUCH_KEY0_ALOG_CFG + ch, (void *)&alog_cfg[ch], sizeof(struct lp_touch_key_alog_cfg));
+ if (alog_cfg[ch].ready_flag == 0) {
+ alog_cfg[ch].ready_flag = 1;
+ lp_touch_key_save_alog_cfg((void *)&ch);
+ }
+ }
+ }
+ }
+}
+
+#endif
+
+
+static void ctmu_port_init(u8 port)
+{
+ gpio_set_die(port, 0);
+ gpio_set_dieh(port, 0);
+ gpio_set_direction(port, 1);
+ gpio_set_pull_down(port, 0);
+ gpio_set_pull_up(port, 0);
+}
+
+u8 p11_wakeup_query(void)
+{
+ return is_wakeup_source(PWR_WK_REASON_P11);
+};
+
+void lp_touch_key_send_cmd(enum CTMU_M2P_CMD cmd)
+{
+ M2P_CTMU_CMD = cmd;
+ P11_M2P_INT_SET = BIT(M2P_CTMU_INDEX);
+}
+
+#define IO_RESET_PORTB_01 18
+void lp_touch_key_init(const struct lp_touch_key_platform_data *config)
+{
+ log_info("%s >>>>", __func__);
+
+ ASSERT(config && (__this->init == 0));
+ __this->config = config;
+
+ u8 pinr_io;
+ if (P33_CON_GET(P3_PINR_CON) & BIT(0)) {
+ pinr_io = P33_CON_GET(P3_PORT_SEL0);
+ if (pinr_io == IO_RESET_PORTB_01) {
+ P33_CON_SET(P3_PINR_CON, 0, 8, 0);
+ P33_CON_SET(P3_PINR_CON1, 0, 8, 0x16);
+ P33_CON_SET(P3_PINR_CON1, 0, 1, 1);
+ log_info("reset pin change: old: %d, P3_PINR_CON1 = 0x%x", pinr_io, P33_CON_GET(P3_PINR_CON1));
+ }
+ }
+
+ u8 ch_enable = 0;
+ u8 ch_wakeup_en = 0;
+ u8 ch_debug = 0;
+ for (u8 ch = 0; ch < LP_CTMU_CHANNEL_SIZE; ch ++) {
+ if (__this->config->ch[ch].enable) {
+ ch_enable |= BIT(ch);
+ if (__this->config->ch[ch].wakeup_enable) {
+ ch_wakeup_en |= BIT(ch);
+ }
+ if (CFG_CHx_DEBUG_ENABLE & BIT(ch)) {
+ ch_debug |= BIT(ch);
+ }
+ }
+ }
+ if (p11_wakeup_query() == 0 || get_charge_online_flag() || (!(ch_wakeup_en)) || (is_ldo5v_wakeup())) {
+ for (u32 m2p_addr = 0x18; m2p_addr < 0x56; m2p_addr ++) {
+ M2P_MESSAGE_ACCESS(m2p_addr) = 0;
+ }
+ for (u32 p2m_addr = 0x10; p2m_addr < 0x24; p2m_addr ++) {
+ P2M_MESSAGE_ACCESS(p2m_addr) = 0;
+ }
+ }
+
+ M2P_CTMU_MSG = 0;
+ M2P_CTMU_CH_CFG = 0;
+ M2P_CTMU_TIME_BASE = CTMU_SAMPLE_RATE_PRD;
+
+ M2P_CTMU_LONG_TIMEL = (CTMU_LONG_KEY_DELAY_TIME & 0xFF);
+ M2P_CTMU_LONG_TIMEH = ((CTMU_LONG_KEY_DELAY_TIME >> 8) & 0xFF);
+ M2P_CTMU_HOLD_TIMEL = (CTMU_HOLD_CLICK_DELAY_TIME & 0xFF);
+ M2P_CTMU_HOLD_TIMEH = ((CTMU_HOLD_CLICK_DELAY_TIME >> 8) & 0xFF);
+
+ M2P_CTMU_SOFTOFF_LONG_TIMEL = (CFG_M2P_CTMU_SOFTOFF_LONG_TIME & 0xFF);
+ M2P_CTMU_SOFTOFF_LONG_TIMEH = ((CFG_M2P_CTMU_SOFTOFF_LONG_TIME >> 8) & 0xFF);
+
+#if TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE
+ M2P_CTMU_LONG_PRESS_RESET_TIME_VALUE_L = 0;
+ M2P_CTMU_LONG_PRESS_RESET_TIME_VALUE_H = 0;
+#else
+ M2P_CTMU_LONG_PRESS_RESET_TIME_VALUE_L = (CTMU_RESET_TIME_CONFIG & 0xFF);
+ M2P_CTMU_LONG_PRESS_RESET_TIME_VALUE_H = ((CTMU_RESET_TIME_CONFIG >> 8) & 0xFF);
+#endif
+
+ log_info("M2P_CTMU_LONG_TIMEL = 0x%x", M2P_CTMU_LONG_TIMEL);
+ log_info("M2P_CTMU_LONG_TIMEH = 0x%x", M2P_CTMU_LONG_TIMEH);
+ log_info("M2P_CTMU_HOLD_TIMEL = 0x%x", M2P_CTMU_HOLD_TIMEL);
+ log_info("M2P_CTMU_HOLD_TIMEH = 0x%x", M2P_CTMU_HOLD_TIMEH);
+
+ log_info("M2P_CTMU_SOFTOFF_LONG_TIMEL = 0x%x", M2P_CTMU_SOFTOFF_LONG_TIMEL);
+ log_info("M2P_CTMU_SOFTOFF_LONG_TIMEH = 0x%x", M2P_CTMU_SOFTOFF_LONG_TIMEH);
+
+ log_info("M2P_CTMU_LONG_PRESS_RESET_TIME_VALUE_L = 0x%x", M2P_CTMU_LONG_PRESS_RESET_TIME_VALUE_L);
+ log_info("M2P_CTMU_LONG_PRESS_RESET_TIME_VALUE_H = 0x%x", M2P_CTMU_LONG_PRESS_RESET_TIME_VALUE_H);
+
+ M2P_CTMU_CH_ENABLE = ch_enable;
+ M2P_CTMU_CH_WAKEUP_EN = ch_wakeup_en;
+ M2P_CTMU_CH_DEBUG = ch_debug;
+
+ for (u8 ch = 0; ch < LP_CTMU_CHANNEL_SIZE; ch ++) {
+ if (__this->config->ch[ch].enable) {
+ u8 ch_sensity = __this->config->ch[ch].sensitivity;
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG0L + ch * 8) = ((ch_sensitivity_table[ch_sensity + ch * 10].cfg0) & 0xFF);
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG0H + ch * 8) = (((ch_sensitivity_table[ch_sensity + ch * 10].cfg0) >> 8) & 0xFF);
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG1L + ch * 8) = ((ch_sensitivity_table[ch_sensity + ch * 10].cfg1) & 0xFF);
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG1H + ch * 8) = (((ch_sensitivity_table[ch_sensity + ch * 10].cfg1) >> 8) & 0xFF);
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG2L + ch * 8) = ((ch_sensitivity_table[ch_sensity + ch * 10].cfg2) & 0xFF);
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG2H + ch * 8) = (((ch_sensitivity_table[ch_sensity + ch * 10].cfg2) >> 8) & 0xFF);
+
+ log_info("M2P_CTMU_CH%d_CFG0L = 0x%x", ch, M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG0L + ch * 8));
+ log_info("M2P_CTMU_CH%d_CFG0H = 0x%x", ch, M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG0H + ch * 8));
+ log_info("M2P_CTMU_CH%d_CFG1L = 0x%x", ch, M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG1L + ch * 8));
+ log_info("M2P_CTMU_CH%d_CFG1H = 0x%x", ch, M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG1H + ch * 8));
+ log_info("M2P_CTMU_CH%d_CFG2L = 0x%x", ch, M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG2L + ch * 8));
+ log_info("M2P_CTMU_CH%d_CFG2H = 0x%x", ch, M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG2H + ch * 8));
+
+ ctmu_port_init(__this->config->ch[ch].port);
+#if TCFG_LP_EARTCH_KEY_ENABLE
+ if (__this->config->eartch_en && (__this->config->eartch_ch == ch)) {
+ M2P_CTMU_CH_CFG |= BIT(1);
+ M2P_CTMU_EARTCH_CH = (__this->config->eartch_ref_ch << 4) | (__this->config->eartch_ch & 0xf);
+#if (TCFG_EARTCH_EVENT_HANDLE_ENABLE && TCFG_LP_EARTCH_KEY_ENABLE)
+ extern int eartch_event_deal_init(void);
+ eartch_event_deal_init();
+#endif
+ u16 trim_value;
+ int ret = syscfg_read(LP_KEY_EARTCH_TRIM_VALUE, &trim_value, sizeof(trim_value));
+ __this->eartch_trim_flag = 0;
+ __this->eartch_inear_ok = 0;
+ __this->eartch_trim_value = 0;
+ if (ret > 0) {
+ __this->eartch_inear_ok = 1;
+ __this->eartch_trim_value = trim_value;
+ log_info("eartch_trim_value = %d", __this->eartch_trim_value);
+ M2P_CTMU_EARTCH_TRIM_VALUE_L = (__this->eartch_trim_value & 0xFF);
+ M2P_CTMU_EARTCH_TRIM_VALUE_H = ((__this->eartch_trim_value >> 8) & 0xFF);
+ } else {
+ //没有trim的情况下用不了
+ M2P_CTMU_EARTCH_TRIM_VALUE_L = (10000 & 0xFF);
+ M2P_CTMU_EARTCH_TRIM_VALUE_H = ((10000 >> 8) & 0xFF);
+ }
+ //软件触摸灵敏度调试
+ M2P_CTMU_INEAR_VALUE_L = __this->config->eartch_soft_inear_val & 0xFF;
+ M2P_CTMU_INEAR_VALUE_H = __this->config->eartch_soft_inear_val >> 8;
+ M2P_CTMU_OUTEAR_VALUE_L = __this->config->eartch_soft_outear_val & 0xFF;
+ M2P_CTMU_OUTEAR_VALUE_H = __this->config->eartch_soft_outear_val >> 8;
+ } else
+#endif
+ {
+#if !TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE
+ TouchAlgo_Init(ch, TOUCH_RANGE_MIN, TOUCH_RANGE_MAX);
+ alog_sta_cnt[ch] = 0;
+ ch_range_sensity[ch] = ch_sensity;
+ log_info("read vm alog cfg\n");
+ int ret = syscfg_read(VM_LP_TOUCH_KEY0_ALOG_CFG + ch, (void *)&alog_cfg[ch], sizeof(struct lp_touch_key_alog_cfg));
+ if ((ret == (sizeof(struct lp_touch_key_alog_cfg))) && (alog_cfg[ch].range > TOUCH_RANGE_MIN) && (alog_cfg[ch].range < TOUCH_RANGE_MAX)) {
+ log_info("vm read ch%d alog ready:%d sigma:%d range:%d\n", ch, alog_cfg[ch].ready_flag, alog_cfg[ch].sigma, alog_cfg[ch].range);
+ u16 cfg0 = (M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG0H + ch * 8) << 8) | (M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG0L + ch * 8));
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG1L + ch * 8) = (cfg0 + 5) & 0xff;
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG1H + ch * 8) = ((cfg0 + 5) >> 8) & 0xff;
+ u16 cfg2_new = alog_cfg[ch].range * (10 - ch_range_sensity[ch]) / 10;
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG2L + ch * 8) = cfg2_new & 0xff;
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG2H + ch * 8) = (cfg2_new >> 8) & 0xff;
+ TouchAlgo_SetSigma(ch, alog_cfg[ch].sigma);
+ TouchAlgo_SetRange(ch, alog_cfg[ch].range);
+ }
+
+#endif
+ }
+ }
+ }
+
+#if !TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE
+
+#if 1 //触摸算法要尽可能的在装完整机之后开始跑,而这里是耳机生产流程中获取它第一次在舱内开机的时候,在vm标记一个变量,从此开始跑算法。
+
+ if (get_charge_online_flag()) {
+ log_info("check charge online!\n");
+ lp_touch_key_alog_ready_flag_check_and_set();//如果有其他好的位置,请将该函数移到那个位置执行。
+ }
+
+#endif
+
+ if (ctmu_res_scan_time_add == 0) {
+ ctmu_res_scan_time_add = usr_timer_add(NULL, lp_touch_key_ctmu_res_scan, 20, 0);
+ }
+
+#if CTMU_CHECK_LONG_CLICK_BY_RES
+ lp_touch_key_ctmu_res_all_buf_clear();
+#endif
+
+#endif
+
+ //CTMU 初始化命令
+ if (p11_wakeup_query() == 0 || get_charge_online_flag() || (!(ch_wakeup_en)) || (is_ldo5v_wakeup())) {
+ log_info("lp touch init by %d_%d_%d_%d\n", p11_wakeup_query(), get_charge_online_flag(), (!(ch_wakeup_en)), is_ldo5v_wakeup());
+ LPCTMU_ANA0_CONFIG(get_lpctmu_ana_level());
+ P2M_CTMU_WKUP_MSG &= (~(P2M_MESSAGE_INIT_MODE_FLAG));
+ } else {
+ P2M_CTMU_WKUP_MSG |= (P2M_MESSAGE_INIT_MODE_FLAG);
+ log_info("p11 wakeup, lp touch key continue work");
+ }
+ __this->softoff_mode = LP_TOUCH_SOFTOFF_MODE_ADVANCE;
+
+ log_info("M2P_CTMU_CH_ENABLE = 0x%x", M2P_CTMU_CH_ENABLE);
+ log_info("M2P_CTMU_CH_WAKEUP_EN = 0x%x", M2P_CTMU_CH_WAKEUP_EN);
+ log_info("M2P_CTMU_CH_CFG = 0x%x", M2P_CTMU_CH_CFG);
+ log_info("M2P_CTMU_EARTCH_CH = 0x%x", M2P_CTMU_EARTCH_CH);
+
+ lp_touch_key_send_cmd(CTMU_M2P_INIT);
+
+#if TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE
+ lp_touch_key_online_debug_init();
+#endif /* #if TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE */
+
+ __this->init = 1;
+}
+
+
+#if (TCFG_LP_SLIDE_KEY_ENABLE && TCFG_LP_SLIDE_KEY_SHORT_DISTANCE)
+
+
+/******************************双通道滑动触摸识别的基础原理***********************************
+
+1.单击,但如果超过设定的长按时间,那就为长按
+chx __________________________________________
+chx ___________ __________
+ |_______>180________|
+
+
+2.单击,但如果超过设定的长按时间,那就为长按
+chx ___________ __________
+ |_______>180________|
+chx _______ <30 <30 ______
+ |___________________________|
+
+
+3.单击,但如果超过设定的长按时间,那就为长按
+chx ___________ __________
+ |_______>180________|
+chx _______ <30 >30 __
+ |_______________________________|
+
+
+4.单击,但如果超过设定的长按时间,那就为长按
+chx ___________ __________
+ |_______>180________|
+chx ___ >30 <30 ______
+ |_______________________________|
+
+
+5.单击,但如果超过设定的长按时间,那就为长按
+chx ___________ __________
+ |_______>180________|
+chx ___ >30 >30 __
+ |___________________________________|
+
+
+6.单击,但如果超过设定的长按时间,那就为长按
+chx ___________ ______
+ |_______________________|
+chx _______ <30 >180 _<30______
+ |_______________________|
+
+
+7.根据前后操作,有可能是滑动,也有可能是连击中的后单击,也有可能是无效操作
+chx ___________ __________
+ |_______________|
+chx _______ <30 <180 _<30__________
+ |_______________|
+
+
+8.滑动,t < 设定的长按的时间
+chx ___________ __________
+ |_______________|
+chx ___ >30 t _<30__________
+ |___________________|
+
+
+9.滑动,t < 设定的长按的时间
+chx ___________ ______
+ |___________________|
+chx ___ >30 t __>30_________
+ |___________________|
+
+
+10.滑动,t < 设定的长按的时间
+chx ___________ ______
+ |___________________|
+chx _______ <30 t __>30_________
+ |_______________|
+
+*****************************************************************************/
+
+enum falling_order_type {
+ FALLING_NULL,
+ FALLING_FIRST,
+ FALLING_SECOND,
+};
+enum raising_order_type {
+ RAISING_NULL,
+ RAISING_FIRST,
+ RAISING_SECOND,
+};
+
+enum time_interval_type {
+ LONG_TIME,
+ SHORT_TIME,
+};
+
+enum slide_key_type {
+ SHORT_CLICK = 1,
+ DOUBLE_CLICK,
+ TRIPLE_CLICK,
+ FOURTH_CLICK,
+ FIRTH_CLICK,
+ LONG_CLICK = 8,
+ LONG_HOLD_CLICK = 9,
+ LONG_UP_CLICK = 10,
+ SLIDE_UP = 0x12,
+ SLIDE_DOWN = 0x21,
+};
+
+static u8 falling_order[2] = {FALLING_NULL, FALLING_NULL};
+static u8 raising_order[2] = {RAISING_NULL, RAISING_NULL};
+static u8 falling_time_interval = 0;
+static u8 raising_time_interval = 0;
+static u8 last_key_type = 0;
+
+#define FALLING_TIMEOUT_TIME 30 //两个按下边沿的时间间隔的阈值
+static int falling_timeout_add = 0;
+static void falling_timeout_handle(void *priv)
+{
+ falling_timeout_add = 0;
+}
+
+#define RAISING_TIMEOUT_TIME 30 //两个抬起边沿的时间间隔的阈值
+static int raising_timeout_add = 0;
+static void raising_timeout_handle(void *priv)
+{
+ raising_timeout_add = 0;
+}
+
+#define CLICK_IDLE_TIMEOUT_TIME 500 //如果该时间内,没有单击,那么该时间之后的第一次单击,识别为首次单击
+static int click_idle_timeout_add = 0;
+static void click_idle_timeout_handle(void *priv)
+{
+ click_idle_timeout_add = 0;
+}
+
+#define FIRST_SHORT_CLICK_TIMEOUT_TIME 190 //只针对首次单击,要满足按够那么长时间。连击时,后面的单击没有该时间要求
+static int first_short_click_timeout_add = 0;
+static void first_short_click_timeout_handle(void *priv)
+{
+ first_short_click_timeout_add = 0;
+}
+
+void __attribute__((weak)) send_keytone_event(void)
+{
+ //可以在此处发送按键音的消息
+ /* struct sys_event e; */
+ /* e.u.key.event = 5; */
+ /* e.u.key.value = 3; */
+ /* __ctmu_notify_key_event(&e, 0); */
+}
+
+#define SEND_KEYTONE_TIMEOUT_TIME 250 //长按时的按键音,在按下后的多长时间要响
+static u8 send_keytone_flag = 0;
+static int send_keytone_timeout_add = 0;
+static void send_keytone_timeout_handle(void *priv)
+{
+ send_keytone_event();
+ send_keytone_timeout_add = 0;
+ send_keytone_flag = 1;
+}
+
+#define SLIDE_CLICK_TIMEOUT_TIME 500 //识别为滑动之后,该时间内,如果有case7.也要识别为滑动
+#define FAST_SLIDE_CNT_MAX 4 //一来就连续那么多次的case7.,就会识别为一次滑动。
+static u8 fast_slide_cnt = 0;
+static u8 fast_slide_type = 0;
+static int slide_click_timeout_add = 0;
+void slide_click_timeout_handle(void *priv)
+{
+ slide_click_timeout_add = 0;
+}
+
+static void check_channel_falling_info(u8 ch)
+{
+ falling_order[ch] = FALLING_FIRST;
+ if (falling_order[!ch] == FALLING_FIRST) {
+ falling_order[ch] = FALLING_SECOND;
+ }
+ send_keytone_flag = 0;
+ if (send_keytone_timeout_add == 0) {
+ send_keytone_timeout_add = sys_hi_timeout_add(NULL, send_keytone_timeout_handle, SEND_KEYTONE_TIMEOUT_TIME);
+ } else {
+ sys_hi_timer_modify(send_keytone_timeout_add, SEND_KEYTONE_TIMEOUT_TIME);
+ }
+ if ((last_key_type != SHORT_CLICK) || (click_idle_timeout_add == 0)) {
+ if (first_short_click_timeout_add == 0) {
+ first_short_click_timeout_add = sys_hi_timeout_add(NULL, first_short_click_timeout_handle, FIRST_SHORT_CLICK_TIMEOUT_TIME);
+ } else {
+ sys_hi_timer_modify(first_short_click_timeout_add, FIRST_SHORT_CLICK_TIMEOUT_TIME);
+ }
+ }
+ if (falling_order[ch] == FALLING_FIRST) {
+ if (falling_timeout_add == 0) {
+ falling_timeout_add = sys_hi_timeout_add(NULL, falling_timeout_handle, FALLING_TIMEOUT_TIME);
+ } else {
+ sys_hi_timer_modify(falling_timeout_add, FALLING_TIMEOUT_TIME);
+ }
+ falling_time_interval = SHORT_TIME;
+ } else if (falling_order[ch] == FALLING_SECOND) {
+ if (falling_timeout_add) {
+ sys_hi_timeout_del(falling_timeout_add);
+ falling_timeout_add = 0;
+ falling_time_interval = SHORT_TIME;
+ } else {
+ falling_time_interval = LONG_TIME;
+ }
+ }
+}
+
+static u8 check_channel_raising_info_and_key_type(u8 ch)
+{
+ u8 key_type = 0;
+ fast_slide_type = 0;
+ if (falling_order[ch] == FALLING_NULL) {
+ return key_type;
+ }
+ raising_order[ch] = RAISING_FIRST;
+ if (raising_order[!ch] == RAISING_FIRST) {
+ raising_order[ch] = RAISING_SECOND;
+ }
+ if (falling_order[ch] > falling_order[!ch]) {
+ if (raising_order[ch] == RAISING_FIRST) {
+ key_type = SHORT_CLICK; //case 1~5.
+ } else {
+ if (falling_time_interval == SHORT_TIME) {
+ if (raising_timeout_add) {
+ sys_hi_timeout_del(raising_timeout_add);
+ raising_timeout_add = 0;
+ key_type = SHORT_CLICK; //case 6~7.
+ if (ch == 0) {
+ fast_slide_type = SLIDE_DOWN;
+ } else {
+ fast_slide_type = SLIDE_UP;
+ }
+ } else if (ch == 0) {
+ key_type = SLIDE_DOWN; //case 10.
+ } else {
+ key_type = SLIDE_UP; //case 10.
+ }
+ } else if (ch == 0) {
+ key_type = SLIDE_DOWN; //caee 8~9.
+ } else {
+ key_type = SLIDE_UP; //case 8~9.
+ }
+ }
+ } else {
+ if (raising_order[ch] == RAISING_FIRST) {
+ if (falling_time_interval == SHORT_TIME) {
+ if (raising_timeout_add == 0) {
+ raising_timeout_add = sys_hi_timeout_add(NULL, raising_timeout_handle, RAISING_TIMEOUT_TIME);
+ } else {
+ sys_hi_timer_modify(raising_timeout_add, RAISING_TIMEOUT_TIME);
+ }
+ } else if (ch == 0) {
+ key_type = SLIDE_UP; //case 8~9.
+ } else {
+ key_type = SLIDE_DOWN; //case 8~9.
+ }
+ } else {
+ if (falling_time_interval == SHORT_TIME) {
+ if (raising_timeout_add) {
+ sys_hi_timeout_del(raising_timeout_add);
+ raising_timeout_add = 0;
+ key_type = SHORT_CLICK; //case 6~7
+ if (ch == 0) {
+ fast_slide_type = SLIDE_UP;
+ } else {
+ fast_slide_type = SLIDE_DOWN;
+ }
+ } else if (ch == 0) {
+ key_type = SLIDE_UP; //case 10.
+ } else {
+ key_type = SLIDE_DOWN; //case 10.
+ }
+ } else if (ch == 0) {
+ key_type = SLIDE_UP; //case 8~9.
+ } else {
+ key_type = SLIDE_DOWN; //case 8~9.
+ }
+ }
+ }
+ return key_type;
+}
+
+static u8 get_slide_event_ch(void)
+{
+ u8 event_ch = 1;
+ for (u8 ch = 0; ch < LP_CTMU_CHANNEL_SIZE; ch ++) {
+ if (__this->config->ch[ch].enable) {
+ event_ch = ch;
+ break;
+ }
+ }
+ return event_ch;
+}
+
+static u8 check_slide_key_type(u8 event, u8 ch)
+{
+ u8 key_type = 0;
+ u8 event_ch = get_slide_event_ch();
+ if (event == (CTMU_P2M_CH0_FALLING_EVENT + ch * 8)) {
+ if (ch == event_ch) {
+ check_channel_falling_info(0);
+ } else {
+ check_channel_falling_info(1);
+ }
+ } else if (event == (CTMU_P2M_CH0_RAISING_EVENT + ch * 8)) {
+ if (ch == event_ch) {
+ if ((last_key_type == LONG_CLICK) || (last_key_type == LONG_HOLD_CLICK)) {
+ key_type = LONG_UP_CLICK; //一定是长按抬起
+ } else {
+ key_type = check_channel_raising_info_and_key_type(0);
+ }
+ } else {
+ key_type = check_channel_raising_info_and_key_type(1);
+ }
+ } else if (event == (CTMU_P2M_CH0_LONG_KEY_EVENT + event_ch * 8)) {//长按只判断通道号小的那个按键
+ key_type = LONG_CLICK;
+ } else if (event == (CTMU_P2M_CH0_HOLD_KEY_EVENT + event_ch * 8)) {//长按只判断通道号小的那个按键
+ key_type = LONG_HOLD_CLICK;
+ }
+
+ if (key_type) {
+ falling_order[0] = FALLING_NULL;
+ falling_order[1] = FALLING_NULL;
+ raising_order[0] = RAISING_NULL;
+ raising_order[1] = RAISING_NULL;
+ falling_time_interval = 0;
+ last_key_type = key_type;
+ if (send_keytone_timeout_add) {
+ sys_hi_timeout_del(send_keytone_timeout_add);
+ send_keytone_timeout_add = 0;
+ }
+ if (key_type == SHORT_CLICK) { //case 6~7 的进一步处理
+ if (first_short_click_timeout_add) {
+ sys_hi_timeout_del(first_short_click_timeout_add);
+ first_short_click_timeout_add = 0;
+
+ if (slide_click_timeout_add) {
+ sys_hi_timeout_del(slide_click_timeout_add);
+ slide_click_timeout_add = 0;
+ if (fast_slide_type) {
+ key_type = fast_slide_type;
+ last_key_type = key_type;
+ } else {
+ key_type = 0xff;
+ last_key_type = key_type;
+ }
+ fast_slide_cnt = 0;
+ } else {
+ if (fast_slide_type) {
+ fast_slide_cnt ++;
+ if (fast_slide_cnt >= FAST_SLIDE_CNT_MAX) {
+ fast_slide_cnt = 0;
+ key_type = fast_slide_type;
+ last_key_type = key_type;
+ } else {
+ key_type = 0xff;
+ last_key_type = key_type;
+ }
+ } else {
+ fast_slide_cnt = 0;
+ key_type = 0xff;
+ last_key_type = key_type;
+ }
+ }
+ } else {
+ if (send_keytone_flag == 0) {
+ send_keytone_event();
+ }
+ if (slide_click_timeout_add) {
+ sys_hi_timeout_del(slide_click_timeout_add);
+ slide_click_timeout_add = 0;
+ }
+ fast_slide_cnt = 0;
+ }
+ if (click_idle_timeout_add == 0) {
+ click_idle_timeout_add = sys_hi_timeout_add(NULL, click_idle_timeout_handle, CLICK_IDLE_TIMEOUT_TIME);
+ } else {
+ sys_hi_timer_modify(click_idle_timeout_add, CLICK_IDLE_TIMEOUT_TIME);
+ }
+ } else {
+ fast_slide_cnt = 0;
+ }
+
+ if ((key_type == SLIDE_UP) || (key_type == SLIDE_DOWN)) {
+ if (slide_click_timeout_add == 0) {
+ slide_click_timeout_add = sys_hi_timeout_add(NULL, slide_click_timeout_handle, SLIDE_CLICK_TIMEOUT_TIME);
+ } else {
+ sys_hi_timer_modify(slide_click_timeout_add, SLIDE_CLICK_TIMEOUT_TIME);
+ }
+ }
+ }
+
+ return key_type;
+}
+
+static void ctmu_send_slide_key_type_event(u8 key_type)
+{
+ struct sys_event e;
+ u8 event_ch = get_slide_event_ch();
+ switch (key_type) {
+ case SHORT_CLICK: //单击
+ ctmu_short_click_handle(event_ch);
+ break;
+ case LONG_CLICK: //长按
+#if CTMU_CHECK_LONG_CLICK_BY_RES
+ if (lp_touch_key_check_long_click_by_ctmu_res(event_ch)) {
+ last_key_type = 0;
+ return;
+ }
+#endif
+ ctmu_long_click_handle(event_ch);
+ break;
+ case LONG_HOLD_CLICK: //长按保持
+#if CTMU_CHECK_LONG_CLICK_BY_RES
+ if (lp_touch_key_check_long_click_by_ctmu_res(event_ch)) {
+ last_key_type = 0;
+ return;
+ }
+#endif
+ ctmu_hold_click_handle(event_ch);
+ break;
+ case LONG_UP_CLICK: //长按抬起
+ ctmu_raise_click_handle(event_ch);
+ break;
+ case SLIDE_UP: //向上滑动
+ e.u.key.event = TOUCH_KEY_EVENT_SLIDE_UP;
+ e.u.key.value = __this->config->slide_mode_key_value;
+ printf("key.event = TOUCH_KEY_EVENT_SLIDE_UP\n");
+ printf("key.value = %d\n", e.u.key.value);
+ __ctmu_notify_key_event(&e, event_ch);
+ break;
+ case SLIDE_DOWN: //向下滑动
+ e.u.key.event = TOUCH_KEY_EVENT_SLIDE_DOWN;
+ e.u.key.value = __this->config->slide_mode_key_value;
+ printf("key.event = TOUCH_KEY_EVENT_SLIDE_DOWN\n");
+ printf("key.value = %d\n", e.u.key.value);
+ __ctmu_notify_key_event(&e, event_ch);
+ break;
+ default:
+ break;
+ }
+}
+
+#endif
+
+
+u8 last_state = CTMU_P2M_EARTCH_OUT_EVENT;
+void p33_ctmu_key_event_irq_handler()
+{
+ u8 ret = 0;
+ u8 ctmu_event = P2M_CTMU_KEY_EVENT;
+ u8 ch_num = P2M_CTMU_KEY_CNT;
+ u16 ch_res = 0;
+ u16 chx_res[LP_CTMU_CHANNEL_SIZE];
+
+#if TCFG_LP_EARTCH_KEY_ENABLE
+ if (testbox_get_key_action_test_flag(NULL)) {
+ if (__this->config->eartch_en && (__this->config->eartch_ch == ch_num)) {
+ ret = lp_touch_key_testbox_remote_test(ch_num, ctmu_event);
+ if (ret == true) {
+ return;
+ }
+ }
+ }
+#endif
+ /* printf("ctmu_event = 0x%x\n", ctmu_event); */
+ switch (ctmu_event) {
+ case CTMU_P2M_CH0_RES_EVENT:
+ case CTMU_P2M_CH1_RES_EVENT:
+ case CTMU_P2M_CH2_RES_EVENT:
+ case CTMU_P2M_CH3_RES_EVENT:
+ case CTMU_P2M_CH4_RES_EVENT:
+ chx_res[0] = (P2M_CTMU_CH0_H_RES << 8) | P2M_CTMU_CH0_L_RES;
+ chx_res[1] = (P2M_CTMU_CH1_H_RES << 8) | P2M_CTMU_CH1_L_RES;
+ chx_res[2] = (P2M_CTMU_CH2_H_RES << 8) | P2M_CTMU_CH2_L_RES;
+ chx_res[3] = (P2M_CTMU_CH3_H_RES << 8) | P2M_CTMU_CH3_L_RES;
+ chx_res[4] = (P2M_CTMU_CH4_H_RES << 8) | P2M_CTMU_CH4_L_RES;
+ ch_res = chx_res[ch_num];
+ /* printf("ch%d_res: %d\n", ch_num, ch_res); */
+
+#if TWS_BT_SEND_KEY_CH_RES_DATA_ENABLE
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
+ lpctmu_tws_send_res_data(BT_KEY_CH_RES_MSG,
+ chx_res[0],
+ chx_res[1],
+ chx_res[2],
+ chx_res[3],
+ chx_res[4]);
+ }
+#endif
+
+#if TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE
+ lp_touch_key_online_debug_send(ch_num, ch_res);
+#endif
+
+#if TCFG_LP_EARTCH_KEY_ENABLE
+ if (__this->config->eartch_en && (__this->config->eartch_ch == ch_num)) {
+
+ u16 eartch_ch_res = chx_res[ch_num];
+ u16 eartch_ref_ch_res = chx_res[__this->config->eartch_ref_ch];
+ u16 eartch_iir = (P2M_CTMU_EARTCH_H_IIR_VALUE << 8) | P2M_CTMU_EARTCH_L_IIR_VALUE;
+ u16 eartch_trim = (P2M_CTMU_EARTCH_H_TRIM_VALUE << 8) | P2M_CTMU_EARTCH_L_TRIM_VALUE;
+ u16 eartch_diff = (P2M_CTMU_EARTCH_H_DIFF_VALUE << 8) | P2M_CTMU_EARTCH_L_DIFF_VALUE;
+
+#if TWS_BT_SEND_EARTCH_RES_DATA_ENABLE
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
+ lpctmu_tws_send_res_data(BT_EARTCH_RES_MSG,
+ eartch_ch_res,
+ eartch_ref_ch_res,
+ eartch_iir,
+ eartch_trim,
+ eartch_diff);
+ }
+#endif
+
+#if !TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE
+ if (__this->eartch_trim_flag) {
+ if (__this->eartch_trim_value == 0) {
+ __this->eartch_trim_value = eartch_diff;
+ } else {
+ __this->eartch_trim_value = ((eartch_diff + __this->eartch_trim_value) >> 1);
+ }
+ if (__this->eartch_trim_flag++ > 20) {
+ __this->eartch_trim_flag = 0;
+ M2P_CTMU_CH_DEBUG &= ~BIT(ch_num);
+ int ret = syscfg_write(LP_KEY_EARTCH_TRIM_VALUE, &(__this->eartch_trim_value), sizeof(__this->eartch_trim_value));
+ log_info("write ret = %d", ret);
+ if (ret > 0) {
+ M2P_CTMU_EARTCH_TRIM_VALUE_L = (__this->eartch_trim_value & 0xFF);
+ M2P_CTMU_EARTCH_TRIM_VALUE_H = ((__this->eartch_trim_value >> 8) & 0xFF);
+ __this->eartch_inear_ok = 1;
+#if TCFG_EARTCH_EVENT_HANDLE_ENABLE
+ eartch_state_update(EARTCH_STATE_TRIM_OK);
+#endif
+ log_info("trim: %d\n", __this->eartch_inear_ok);
+ is_lpkey_active = 0;
+ } else {
+ __this->eartch_inear_ok = 0;
+#if TCFG_EARTCH_EVENT_HANDLE_ENABLE
+ eartch_state_update(EARTCH_STATE_TRIM_ERR);
+#endif
+ log_info("trim: %d\n", __this->eartch_inear_ok);
+ is_lpkey_active = 0;
+ }
+ }
+ log_debug("eartch ch trim value: %d, res = %d", __this->eartch_trim_value, eartch_diff);
+ }
+#endif
+
+ if (P2M_CTMU_EARTCH_EVENT != last_state) {
+ last_state = P2M_CTMU_EARTCH_EVENT;
+ if (last_state == CTMU_P2M_EARTCH_IN_EVENT) {
+ printf("soft inear\n");
+#if TWS_BT_SEND_EVENT_ENABLE
+ lpctmu_tws_send_event_data(EAR_IN, BT_EVENT_SW_MSG);
+#endif
+ if (__this->eartch_inear_ok) {
+ ctmu_eartch_event_handle(EAR_IN);
+ }
+
+ } else if (last_state == CTMU_P2M_EARTCH_OUT_EVENT) {
+ printf("soft outear");
+#if TWS_BT_SEND_EVENT_ENABLE
+ lpctmu_tws_send_event_data(EAR_OUT, BT_EVENT_SW_MSG);
+#endif
+ if (__this->eartch_inear_ok) {
+ ctmu_eartch_event_handle(EAR_OUT);
+ }
+
+ }
+ }
+
+ }
+#endif
+ break;
+
+ case CTMU_P2M_CH0_SHORT_KEY_EVENT:
+ case CTMU_P2M_CH1_SHORT_KEY_EVENT:
+ case CTMU_P2M_CH2_SHORT_KEY_EVENT:
+ case CTMU_P2M_CH3_SHORT_KEY_EVENT:
+ case CTMU_P2M_CH4_SHORT_KEY_EVENT:
+ log_debug("CH%d: SHORT click", ch_num);
+#if (TCFG_LP_SLIDE_KEY_ENABLE && TCFG_LP_SLIDE_KEY_SHORT_DISTANCE)
+#else
+ ctmu_short_click_handle(ch_num);
+#endif
+ break;
+ case CTMU_P2M_CH0_LONG_KEY_EVENT:
+ case CTMU_P2M_CH1_LONG_KEY_EVENT:
+ case CTMU_P2M_CH2_LONG_KEY_EVENT:
+ case CTMU_P2M_CH3_LONG_KEY_EVENT:
+ case CTMU_P2M_CH4_LONG_KEY_EVENT:
+ log_debug("CH%d: LONG click", ch_num);
+ is_lpkey_active = 0;
+
+#if (TCFG_LP_SLIDE_KEY_ENABLE && TCFG_LP_SLIDE_KEY_SHORT_DISTANCE)
+#else
+
+#if CTMU_CHECK_LONG_CLICK_BY_RES
+ if (lp_touch_key_check_long_click_by_ctmu_res(ch_num)) {
+ return;
+ }
+#endif
+ ctmu_long_click_handle(ch_num);
+#endif
+ break;
+ case CTMU_P2M_CH0_HOLD_KEY_EVENT:
+ case CTMU_P2M_CH1_HOLD_KEY_EVENT:
+ case CTMU_P2M_CH2_HOLD_KEY_EVENT:
+ case CTMU_P2M_CH3_HOLD_KEY_EVENT:
+ case CTMU_P2M_CH4_HOLD_KEY_EVENT:
+ log_debug("CH%d: HOLD click", ch_num);
+ is_lpkey_active = 0;
+
+#if (TCFG_LP_SLIDE_KEY_ENABLE && TCFG_LP_SLIDE_KEY_SHORT_DISTANCE)
+#else
+
+#if CTMU_CHECK_LONG_CLICK_BY_RES
+ if (lp_touch_key_check_long_click_by_ctmu_res(ch_num)) {
+ return;
+ }
+#endif
+ ctmu_hold_click_handle(ch_num);
+#endif
+ break;
+ case CTMU_P2M_CH0_FALLING_EVENT:
+ case CTMU_P2M_CH1_FALLING_EVENT:
+ case CTMU_P2M_CH2_FALLING_EVENT:
+ case CTMU_P2M_CH3_FALLING_EVENT:
+ case CTMU_P2M_CH4_FALLING_EVENT:
+ log_debug("CH%d: FALLING", ch_num);
+ is_lpkey_active = 1;
+
+#if CTMU_CHECK_LONG_CLICK_BY_RES
+ falling_res_avg[ch_num] = lp_touch_key_ctmu_res_buf_avg(ch_num);
+ log_debug("falling_res_avg: %d", falling_res_avg[ch_num]);
+#endif
+ break;
+ case CTMU_P2M_CH0_RAISING_EVENT:
+ case CTMU_P2M_CH1_RAISING_EVENT:
+ case CTMU_P2M_CH2_RAISING_EVENT:
+ case CTMU_P2M_CH3_RAISING_EVENT:
+ case CTMU_P2M_CH4_RAISING_EVENT:
+ log_debug("CH%d: RAISING", ch_num);
+ is_lpkey_active = 0;
+
+#if CTMU_CHECK_LONG_CLICK_BY_RES
+ lp_touch_key_ctmu_res_buf_clear(ch_num);
+#endif
+
+#if (TCFG_LP_SLIDE_KEY_ENABLE && TCFG_LP_SLIDE_KEY_SHORT_DISTANCE)
+#else
+ ctmu_raise_click_handle(ch_num);
+#endif
+ break;
+ case CTMU_P2M_EARTCH_IN_EVENT:
+ log_debug("CH%d: IN", ch_num);
+ break;
+ case CTMU_P2M_EARTCH_OUT_EVENT:
+ log_debug("CH%d: OUT", ch_num);
+ break;
+ default:
+ break;
+ }
+
+#if (TCFG_LP_SLIDE_KEY_ENABLE && TCFG_LP_SLIDE_KEY_SHORT_DISTANCE)
+ u8 key_type = check_slide_key_type(ctmu_event, ch_num);
+ if (key_type) {
+ printf("CH%d: key_type = 0x%x\n", ch_num, key_type);
+ ctmu_send_slide_key_type_event(key_type);
+ }
+#endif
+}
+
+u8 lp_touch_key_power_on_status()
+{
+ //extern u8 power_reset_flag;
+ u8 sfr = 0;//power_reset_flag;
+ u8 ret = 0;
+ log_debug("P3_RST_SRC = %x, P2M_CTMU_CTMU_WKUP_MSG = 0x%x", sfr, P2M_CTMU_WKUP_MSG);
+ if (P2M_CTMU_WKUP_MSG & P2M_MESSAGE_POWER_ON_FLAG) { //长按开机查询
+ if (P2M_CTMU_WKUP_MSG & (P2M_MESSAGE_KEY_ACTIVE_FLAG)) { //按键释放查询, 0:释放, 1: 触摸保持
+ ret = 1; //key active
+ }
+ }
+ return ret;
+}
+
+void lp_touch_key_disable(void)
+{
+ log_debug("%s", __func__);
+ P2M_CTMU_WKUP_MSG &= (~(P2M_MESSAGE_SYNC_FLAG));
+ lp_touch_key_send_cmd(CTMU_M2P_DISABLE);
+ while (!(P2M_CTMU_WKUP_MSG & P2M_MESSAGE_SYNC_FLAG));
+ __this->softoff_mode = LP_TOUCH_SOFTOFF_MODE_LEGACY;
+}
+
+void lp_touch_key_enable(void)
+{
+ log_debug("%s", __func__);
+ lp_touch_key_send_cmd(CTMU_M2P_ENABLE);
+ __this->softoff_mode = LP_TOUCH_SOFTOFF_MODE_ADVANCE;
+}
+
+void lp_touch_key_charge_mode_enter()
+{
+ log_debug("%s", __func__);
+#if (!LP_TOUCH_KEY_CHARGE_MODE_SW_DISABLE)
+ P2M_CTMU_WKUP_MSG &= (~(P2M_MESSAGE_SYNC_FLAG));
+ lp_touch_key_send_cmd(CTMU_M2P_CHARGE_ENTER_MODE);
+ while (!(P2M_CTMU_WKUP_MSG & P2M_MESSAGE_SYNC_FLAG));
+ __this->softoff_mode = LP_TOUCH_SOFTOFF_MODE_LEGACY;
+#endif
+}
+
+void lp_touch_key_charge_mode_exit()
+{
+ log_debug("%s", __func__);
+
+ P2M_CTMU_WKUP_MSG &= (~(P2M_MESSAGE_RESET_ALGO_FLAG));
+ lp_touch_key_send_cmd(CTMU_M2P_RESET_ALGO);
+ while (!(P2M_CTMU_WKUP_MSG & P2M_MESSAGE_RESET_ALGO_FLAG));
+
+#if (!LP_TOUCH_KEY_CHARGE_MODE_SW_DISABLE)
+ lp_touch_key_send_cmd(CTMU_M2P_CHARGE_EXIT_MODE);
+ __this->softoff_mode = LP_TOUCH_SOFTOFF_MODE_ADVANCE;
+#endif
+}
+
+//=============================================//
+//NOTE: 该函数为进关机时被库里面回调
+//在板级配置struct low_power_param power_param中变量lpctmu_en配置为TCFG_LP_TOUCH_KEY_ENABLE时:
+//该函数在决定softoff进触摸模式还是普通模式:
+// return 1: 进触摸模式关机(LP_TOUCH_SOFTOFF_MODE_ADVANCE);
+// return 0: 进普通模式关机(触摸关闭)(LP_TOUCH_SOFTOFF_MODE_LEGACY);
+//使用场景:
+// 1)在充电舱外关机, 需要触摸开机, 进带触摸关机模式;
+// 2)在充电舱内关机,可以关闭触摸模块, 进普通关机模式, 关机功耗进一步降低.
+//=============================================//
+u8 lp_touch_key_softoff_mode_query(void)
+{
+ return __this->softoff_mode;
+}
+
+void set_lpkey_active(u8 set)
+{
+ is_lpkey_active = set;
+}
+
+static u8 lpkey_idle_query(void)
+{
+ return !is_lpkey_active;
+}
+
+REGISTER_LP_TARGET(key_lp_target) = {
+ .name = "lpkey",
+ .is_idle = lpkey_idle_query,
+};
+
+
+#endif
+
diff --git a/cpu/br28/lp_touch_key_alog.c b/cpu/br28/lp_touch_key_alog.c
new file mode 100644
index 0000000..4cd40b1
--- /dev/null
+++ b/cpu/br28/lp_touch_key_alog.c
@@ -0,0 +1,589 @@
+#include "includes.h"
+#include "asm/lp_touch_key_alog.h"
+
+
+#define ABS(a) ((a)>0?(a):-(a))
+#define MIN(a,b) ((a)>(b)?(b):(a))
+#define MAX(a,b) ((a)<(b)?(b):(a))
+#define ELEM_SWAP_USHORT(a,b) { unsigned short t=(a);(a)=(b);(b)=t; }
+
+#define INIT_SIGMA (5)
+#define MIN_SIGMA (5)
+#define OUTLIER_ZSCORE (6)
+#define PRESSED_ZSCORE (12)
+#define PULSE_WIDTH (5)
+#define MIN_VALLEY_SAMPLE (3)
+#define FIFO_BUF_SIZE (8)
+#define HISTORY_BUF_SIZE (12)
+#define UNBALANCED_TH (2) //0.2
+#define RANGE_TH_ALPHA (5)
+#define RANGE_TH_DOWN_ALPHA (2)
+#define RANGE_TH_DOWNWARD_EN (0)
+#define RANGE_STABLE_CHECK_EN (1)
+#define RANGE_STABLE_VALUE_TH (3) //0.3
+#define RANGE_STABLE_COUNT_TH (10)
+#define RANGE_STABLE_ALPHA (12) //0.04296875
+
+typedef struct {
+ u32 count;
+
+ //for median filter
+ s16 med_dat0;
+ s16 med_dat1;
+ u8 med_sign;
+
+ //for gradient
+ s16 fifo_buf[FIFO_BUF_SIZE];
+ u8 fifo_pos;
+ u8 fifo_size;
+ s32 grad_max;
+
+ u8 key_state;
+
+ //for sigma tracing
+ s32 std_sum;
+ s32 std_count;
+ s32 sigma_iir_state;
+ s16 sigma_iir_alpha;
+ s16 sigma_iir_alpha_fast;
+
+ //stable count
+ s32 stable_count;
+ u8 is_stable;
+
+ //for valley tracing
+ s16 valley_grad;
+ s16 delayed_valley_grad;
+ s16 peak_grad;
+ s16 valley_val;
+ s16 peak_max;
+ s16 valley_duration;
+ //down continued
+ u8 down_cont;
+ //up continued
+ u8 up_cont;
+ u8 delayed_keyup;
+
+#if RANGE_TH_DOWNWARD_EN
+ s32 high_undetect_count;
+ s32 low_detect_count;
+
+ u8 th_downward;
+#endif
+
+ //for delta filter
+ u16 prev_val;
+
+ u16 range;
+ u16 range_median;
+ u16 range_for_th;
+ u16 range_list[HISTORY_BUF_SIZE];
+ u16 range_list_median[HISTORY_BUF_SIZE];
+ u8 range_size;
+ u8 range_pos;
+ u8 range_valid;
+
+ u16 range_min;
+ u16 range_max;
+
+ u8 maybe_noise;
+
+#if RANGE_STABLE_CHECK_EN
+ s32 range_stable_iir_state;
+ s32 range_stable_count;
+ u8 range_isstable;
+#endif
+} TouchAlgo_t;
+
+static TouchAlgo_t ta_ch[5];
+
+static inline unsigned short kth_smallest_ushort(unsigned short a[], int n, int k)
+{
+ int i, j, l, m ;
+ unsigned short x ;
+ l = 0 ;
+ m = n - 1 ;
+ while (l < m) {
+ x = a[k] ;
+ i = l ;
+ j = m ;
+ do {
+ while (a[i] < x) {
+ i++ ;
+ }
+ while (x < a[j]) {
+ j-- ;
+ }
+ if (i <= j) {
+ ELEM_SWAP_USHORT(a[i], a[j]) ;
+ i++ ;
+ j-- ;
+ }
+ } while (i <= j) ;
+ if (j < k) {
+ l = i ;
+ }
+ if (k < i) {
+ m = j ;
+ }
+ }
+ return a[k] ;
+}
+
+static u16 medfilt(TouchAlgo_t *ta, u16 x)
+{
+ u16 ret = 0;
+ if (ta->med_sign) {
+ //dat0 <= dat1;
+ if (x <= ta->med_dat0) {
+ ret = ta->med_dat0;
+ ta->med_sign = 0;
+ } else if (x >= ta->med_dat1) {
+ ret = ta->med_dat1;
+ ta->med_sign = 1;
+ } else {
+ ret = x;
+ ta->med_sign = 0;
+ }
+ } else {
+ //da0 > dat1;
+ if (x <= ta->med_dat1) {
+ ret = ta->med_dat1;
+ ta->med_sign = 0;
+ } else if (x >= ta->med_dat0) {
+ ret = ta->med_dat0;
+ ta->med_sign = 1;
+ } else {
+ ret = x;
+ ta->med_sign = 1;
+ }
+ }
+ ta->med_dat0 = ta->med_dat1;
+ ta->med_dat1 = x;
+ return ret;
+}
+
+static s32 iir_filter(s32 *state, u16 x, s16 alpha)
+{
+ *state = (*state * (256 - alpha) + ((s32)x << 6) * alpha + 128) >> 8;
+ return *state;
+}
+
+static s32 newton_sqrt(s32 in)
+{
+ int x = 1;
+ int y = (x + in / x) >> 1;
+
+ while (ABS(y - x) > 1) {
+ x = y;
+ y = (x + in / x) >> 1;
+ }
+ return y;
+}
+
+static void TouchAlgo_tracing(TouchAlgo_t *ta, u16 x)
+{
+
+ s32 sigma;
+ s32 delta, delta_abs;
+ s32 outlier_th;
+ s32 pressed_th, sigma_pressed_th;
+ s32 grad, grad_abs, grad_abs_max;
+ s32 grad_sign_max;
+
+ sigma = (ta->sigma_iir_state + 32) >> 6;
+
+ sigma_pressed_th = sigma * PRESSED_ZSCORE;
+ outlier_th = sigma * OUTLIER_ZSCORE;
+
+ if (ta->range_valid || ta->range_size > 0) {
+ pressed_th = ta->range_for_th / 2;
+
+ if (pressed_th < sigma_pressed_th) {
+ pressed_th = sigma_pressed_th;
+ }
+ } else {
+ pressed_th = sigma_pressed_th;
+ }
+
+ //delta filter
+ delta = (s32)x - (s32)ta->prev_val;
+ ta->prev_val = x;
+
+ delta_abs = delta;
+ if (delta_abs < 0) {
+ delta_abs = -delta_abs;
+ }
+
+ if (delta_abs < outlier_th) {
+ ta->std_sum += delta * delta;
+ ta->std_count += 1;
+
+ if (ta->std_count == 128) {
+ s32 var = newton_sqrt((ta->std_sum + ta->std_count / 2) / ta->std_count);
+ ta->std_count = 0;
+ ta->std_sum = 0;
+
+ if (var < MIN_SIGMA) {
+ var = MIN_SIGMA;
+ }
+
+ if (ta->count < 128 * 8) {
+ iir_filter(&ta->sigma_iir_state, var, ta->sigma_iir_alpha_fast);
+ } else {
+ iir_filter(&ta->sigma_iir_state, var, ta->sigma_iir_alpha);
+ }
+ }
+
+ ta->stable_count += 1;
+ if (ta->stable_count > 10) {
+ ta->is_stable = 1;
+ }
+ } else {
+ ta->stable_count = 0;
+ ta->is_stable = 0;
+ }
+ // printf("%d\n", sigma);
+
+ //gradient
+ grad_abs_max = delta_abs;
+ grad_sign_max = delta >> 31;
+ for (int i = 1; i < ta->fifo_size; i += 2) {
+ int idx = (FIFO_BUF_SIZE + ta->fifo_pos - 1 - i) % FIFO_BUF_SIZE;
+
+ grad = x - ta->fifo_buf[idx];
+ grad_abs = ABS(grad);
+
+ if (grad_abs > grad_abs_max) {
+ grad_abs_max = grad_abs;
+ grad_sign_max = grad >> 31;
+ }
+ }
+
+ if (grad_sign_max == -1) {
+ ta->grad_max = -grad_abs_max;
+ } else {
+ ta->grad_max = grad_abs_max;
+ }
+
+ //append to fifo
+ ta->fifo_buf[ta->fifo_pos] = x;
+ ta->fifo_pos = (ta->fifo_pos + 1) % FIFO_BUF_SIZE;
+ ta->fifo_size += 1;
+ if (ta->fifo_size > FIFO_BUF_SIZE) {
+ ta->fifo_size = FIFO_BUF_SIZE;
+ }
+
+#if RANGE_TH_DOWNWARD_EN
+ if (grad_abs_max <= pressed_th) {
+ ta->high_undetect_count += 1;
+ if (grad_abs_max > sigma_pressed_th) {
+ ta->low_detect_count += 1;
+ }
+
+ if (ta->high_undetect_count >= 60000 && ta->low_detect_count > 0) { //10min
+ ta->th_downward = 1;
+ }
+
+ if (ta->th_downward && ta->high_undetect_count % 100 == 0) {
+ ta->range_for_th = (ta->range_for_th * (256 - RANGE_TH_DOWN_ALPHA) + sigma_pressed_th * 2 * RANGE_TH_DOWN_ALPHA + 128) >> 8;
+ }
+ } else {
+ ta->high_undetect_count = 0;
+ ta->low_detect_count = 0;
+
+ ta->th_downward = 0;
+ }
+#endif
+
+ if (ta->maybe_noise) {
+ if (ta->is_stable) {
+ ta->maybe_noise = 0;
+ } else {
+ return;
+ }
+ }
+
+ //key state machine
+ if (ta->key_state == 0) {
+ if (grad_abs_max > pressed_th && grad_sign_max == 0) {
+ //key up
+ //nothing to do
+ if (ta->up_cont == 0) {
+ ta->maybe_noise = 1;
+ }
+
+ if (ta->up_cont) {
+ if (ta->peak_max < x) {
+ ta->peak_max = x;
+ ta->peak_grad = ta->peak_max - ta->valley_val;
+ }
+ }
+
+ ta->down_cont = 0;
+ ta->up_cont = 1;
+ } else if (grad_abs_max > pressed_th && grad_sign_max == -1) {
+ //key down
+ ta->key_state = 1;
+ ta->valley_duration = 1;
+ ta->valley_val = x;
+ ta->valley_grad = grad_abs_max;
+
+ ta->down_cont = 1;
+ ta->up_cont = 0;
+ } else {
+ //nothing to do
+ ta->down_cont = 0;
+ ta->up_cont = 0;
+ }
+ } else {
+ if (grad_abs_max > pressed_th && grad_sign_max == 0) {
+ //key up
+ ta->key_state = 0;
+
+ ta->peak_max = x;
+ ta->peak_grad = ta->peak_max - ta->valley_val;
+
+ if (ta->valley_duration >= PULSE_WIDTH) {
+ ta->delayed_keyup = 1;
+ ta->delayed_valley_grad = ta->valley_grad;
+ }
+
+ ta->down_cont = 0;
+
+ ta->up_cont = 1;
+
+ } else if (grad_abs_max > pressed_th && grad_sign_max == -1) {
+ //key down
+
+ if (ta->down_cont) {
+ ta->valley_duration += 1;
+ if (x < ta->valley_val) {
+ ta->valley_grad += ta->valley_val - x;
+ ta->valley_val = x;
+ }
+ } else {
+ //keydown when it's already in keydown state
+ //Discarding all history information, cause it's not reliable
+ // ta->range_size = 0;
+ // ta->range_pos = 0;
+ // ta->range_valid = 0;
+ // printf("keydown when it's already in keydown state\n");
+
+ //reset keydown state
+ ta->key_state = 1;
+ ta->valley_duration = 1;
+ ta->valley_val = x;
+ ta->valley_grad = grad_abs_max;
+ }
+
+ ta->down_cont = 1;
+ ta->up_cont = 0;
+
+ } else {
+ ta->valley_duration += 1;
+ if (x < ta->valley_val) {
+ ta->valley_grad += ta->valley_val - x;
+ ta->valley_val = x;
+ }
+ ta->down_cont = 0;
+ ta->up_cont = 0;
+
+ }
+
+ if (ta->delayed_keyup && ta->up_cont == 0) {
+ s16 peak_grad = ta->peak_grad;
+
+ s16 min_grad = MIN(peak_grad, ta->delayed_valley_grad);
+ s16 max_grad = MAX(peak_grad, ta->delayed_valley_grad);
+ s32 stablized_range;
+ s32 range_th;
+
+ ta->delayed_keyup = 0;
+
+#if RANGE_STABLE_CHECK_EN
+ stablized_range = (ta->range_stable_iir_state + 32) >> 6;
+ range_th = stablized_range * RANGE_STABLE_VALUE_TH / 10;
+
+ if ((max_grad - min_grad) * 10 < max_grad * UNBALANCED_TH
+ && min_grad > ta->range_min
+ && max_grad < ta->range_max
+ && ((ta->range_isstable && ABS(stablized_range - max_grad) < range_th) || ta->range_isstable == 0))
+#else
+ if ((max_grad - min_grad) * 10 < max_grad * UNBALANCED_TH
+ && min_grad > ta->range_min
+ && max_grad < ta->range_max)
+#endif
+ {
+ ta->range_list[ta->range_pos] = max_grad;
+ ta->range_pos = (ta->range_pos + 1) % HISTORY_BUF_SIZE;
+ if (ta->range_size < HISTORY_BUF_SIZE) {
+ ta->range_size += 1;
+ }
+
+ ta->range = ta->range_list[0];
+ for (int i = 1; i < ta->range_size; i++) {
+ if (ta->range < ta->range_list[i]) {
+ ta->range = ta->range_list[i];
+ }
+ }
+
+
+ memcpy(&ta->range_list_median, &ta->range_list, ta->range_size * sizeof(u16));
+ ta->range_median = kth_smallest_ushort(ta->range_list_median, ta->range_size, ta->range_size / 2);
+
+ // if(ta->range_size > HISTORY_BUF_SIZE/2)
+ // {
+ ta->range = ta->range_median;
+ // }
+
+ if (ta->range_valid == 0) {
+ ta->range_for_th = sigma_pressed_th * 2;
+#if RANGE_STABLE_CHECK_EN
+ ta->range_stable_iir_state = ta->range << 6;
+#endif
+ } else {
+
+ ta->range_for_th = (ta->range_for_th * (256 - RANGE_TH_ALPHA) + ta->range_median * RANGE_TH_ALPHA + 128) >> 8;
+
+#if RANGE_STABLE_CHECK_EN
+
+ iir_filter(&ta->range_stable_iir_state, ta->range, RANGE_STABLE_ALPHA);
+
+ if (ta->range > stablized_range - range_th
+ && ta->range < stablized_range + range_th
+ ) {
+ ta->range_stable_count += 1;
+ } else {
+ ta->range_stable_count = 0;
+ }
+
+ if (ta->range_stable_count > RANGE_STABLE_COUNT_TH) {
+ ta->range_isstable = 1;
+ }
+#endif
+ }
+
+ if (ta->range_size >= MIN_VALLEY_SAMPLE) {
+ ta->range_valid = 1;
+ }
+ if (ta->range_valid) {
+ // printf("range:%d, median:%d\n", ta->range, ta->range_median);
+ }
+ } else {
+ printf("invalid touch value\n");
+ }
+ }
+ }
+
+ return;
+}
+
+
+void TouchAlgo_Init(u8 ch, u16 min, u16 max)
+{
+ TouchAlgo_t *ta = (TouchAlgo_t *)&ta_ch[ch];
+
+ ta->count = 0;
+
+ ta->fifo_pos = 0;
+ ta->fifo_size = 0;
+
+ ta->key_state = 0;
+
+ ta->med_dat0 = ta->med_dat1 = 0;
+ ta->med_sign = 1;
+
+ ta->std_sum = 0;
+ ta->std_count = 0;
+ ta->sigma_iir_alpha = 5;
+ ta->sigma_iir_alpha_fast = 32;
+ ta->sigma_iir_state = INIT_SIGMA << 6;
+
+ ta->stable_count = 0;
+ ta->is_stable = 0;
+
+ ta->valley_val = 0;
+ ta->valley_duration = 0;
+ ta->prev_val = 0;
+
+ ta->delayed_keyup = 0;
+
+#if RANGE_TH_DOWNWARD_EN
+ ta->high_undetect_count = 0;
+ ta->low_detect_count = 0;
+ ta->th_downward = 0;
+#endif
+ ta->range_valid = 0;
+ ta->range_median = 0;
+ ta->range = 0;
+ ta->range_size = 0;
+ ta->range_pos = 0;
+
+ ta->range_min = min;
+ ta->range_max = max;
+
+ ta->maybe_noise = 0;
+
+#if RANGE_STABLE_CHECK_EN
+ ta->range_stable_iir_state = 0;
+ ta->range_stable_count = 0;
+ ta->range_isstable = 0;
+#endif
+}
+
+void TouchAlgo_Update(u8 ch, u16 x)
+{
+ TouchAlgo_t *ta = (TouchAlgo_t *)&ta_ch[ch];
+ u16 dat0;
+
+ dat0 = medfilt(ta, x);
+ if (ta->count < 3) {
+ ta->count++;
+
+ ta->prev_val = dat0;
+ return;
+ }
+
+ TouchAlgo_tracing(ta, dat0);
+
+ ta->count++;
+ return;
+}
+
+void TouchAlgo_Reset(u8 ch, u16 min, u16 max)
+{
+ TouchAlgo_Init(ch, min, max);
+}
+
+s32 TouchAlgo_GetSigma(u8 ch)
+{
+ TouchAlgo_t *ta = (TouchAlgo_t *)&ta_ch[ch];
+ return ta->sigma_iir_state;
+}
+
+u16 TouchAlgo_GetRange(u8 ch, u8 *valid)
+{
+ TouchAlgo_t *ta = (TouchAlgo_t *)&ta_ch[ch];
+ *valid = ta->range_valid;
+ return ta->range_valid ? ta->range : 0;
+}
+
+void TouchAlgo_SetRange(u8 ch, u16 range)
+{
+ TouchAlgo_t *ta = (TouchAlgo_t *)&ta_ch[ch];
+ ta->range = range;
+ ta->range_valid = 1;
+
+ ta->range_list[0] = range;
+ ta->range_size = 1;
+ ta->range_pos = 1;
+}
+
+void TouchAlgo_SetSigma(u8 ch, s32 sigma)
+{
+ TouchAlgo_t *ta = (TouchAlgo_t *)&ta_ch[ch];
+ ta->sigma_iir_state = sigma;
+}
+
+
diff --git a/cpu/br28/lp_touch_key_tool.c b/cpu/br28/lp_touch_key_tool.c
new file mode 100644
index 0000000..ba794a5
--- /dev/null
+++ b/cpu/br28/lp_touch_key_tool.c
@@ -0,0 +1,443 @@
+/**@file lp_touch_key_tool.c
+* @brief 低功耗内置触摸调试工具
+* @date 2021-8-26
+* @version V1.0
+* @copyright Copyright:(c)JIELI 2011-2020 @ , All Rights Reserved.
+ */
+#include "includes.h"
+#include "asm/lp_touch_key_tool.h"
+#include "asm/lp_touch_key_api.h"
+#include "btstack/avctp_user.h"
+#include "classic/tws_api.h"
+#include "app_config.h"
+
+#define LOG_TAG_CONST LP_KEY
+#define LOG_TAG "[LP_KEY]"
+/* #define LOG_ERROR_ENABLE */
+/* #define LOG_DEBUG_ENABLE */
+#define LOG_INFO_ENABLE
+#define LOG_DUMP_ENABLE
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#define __this (&_ctmu_key)
+
+
+
+/**@defgroup lp_touch_key_tool_tws
+* @{
+ */
+#define TWS_FUNC_ID_VOL_LP_KEY TWS_FUNC_ID('L', 'K', 'E', 'Y')
+
+
+static int tws_api_send_data(void *data, int len, u32 func_id)
+{
+ int ret = -EINVAL;
+
+ local_irq_disable();
+ ret = tws_api_send_data_to_sibling(data, len, func_id);
+ local_irq_enable();
+
+ return ret;
+}
+
+void lpctmu_tws_send_event_data(int msg, int type)
+{
+ u32 event_data[4];
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
+ event_data[0] = type;
+ event_data[1] = jiffies_to_msecs(jiffies);
+ event_data[2] = msg;
+ tws_api_send_data(event_data, 3 * sizeof(int), TWS_FUNC_ID_VOL_LP_KEY);
+ }
+}
+
+void lpctmu_tws_send_res_data(int type, int data1, int data2, int data3, int data4, int data5)
+{
+ u32 event_data[6];
+ if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
+ event_data[0] = type;
+ event_data[1] = data1;
+ event_data[2] = data2;
+ event_data[3] = data3;
+ event_data[4] = data4;
+ event_data[5] = data5;
+ tws_api_send_data(event_data, 6 * sizeof(int), TWS_FUNC_ID_VOL_LP_KEY);
+ }
+}
+
+static void res_receive_handle(void *_data, u16 len, bool rx)
+{
+ u32 *data = _data;
+ if (rx) {
+ switch (data[0]) {
+ case BT_KEY_CH_RES_MSG:
+ log_debug("ch0:%08d, ch1:%08d, ch2:%08d, ch3:%08d, ch4:%08d\n",
+ data[1],
+ data[2],
+ data[3],
+ data[4],
+ data[5]);
+ break;
+ case BT_EARTCH_RES_MSG:
+ log_debug("ear_ch:%08d, ref_ch:%08d, iir:%08d, trim:%08d, diff:%08d\n",
+ data[1],
+ data[2],
+ data[3],
+ data[4],
+ data[5]);
+ break;
+ case BT_EVENT_SW_MSG:
+ log_debug("len = %d, %d ms", len, data[1]);
+ if (data[2] == EPD_IN) {
+ log_debug("SW: IN");
+ } else if (data[2] == EPD_OUT) {
+ log_debug("SW: OUT");
+ }
+ break;
+ case BT_EVENT_HW_MSG:
+ log_debug("len = %d, %d ms", len, data[1]);
+ if (data[2] == EAR_IN) {
+ log_debug("HW: IN");
+ } else if (data[2] == EAR_OUT) {
+ log_debug("HW: OUT");
+ }
+ break;
+ case BT_EVENT_VDDIO:
+ log_debug("BT_EVENT_VDDIO: %d", data[2]);
+ break;
+ }
+ }
+}
+
+REGISTER_TWS_FUNC_STUB(lp_touch_res_sync_stub) = {
+ .func_id = TWS_FUNC_ID_VOL_LP_KEY,
+ .func = res_receive_handle, //handle
+};
+/** @} lp_touch_key_tool_tws*/
+
+
+
+/**@defgroup lp_touch_key_tool_spp
+* @{
+ */
+#if TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE
+#include "online_db_deal.h"
+
+//LP KEY在线调试工具版本号管理
+const u8 lp_key_sdk_name[16] = "AC7016N";
+const u8 lp_key_bt_ver[4] = {0, 0, 1, 0};
+struct lp_key_ver_info {
+ char sdkname[16];
+ u8 lp_key_ver[4];
+};
+
+// 通道号 按键事件个数
+const char ch_content[] = {
+ 0x01, //版本号
+ 'c', 'h', '0', '\0', 6, 0, 1, 2, 3, 4, 5,
+ 'c', 'h', '1', '\0', 6, 0, 1, 2, 3, 4, 5,
+ 'c', 'h', '2', '\0', 6, 0, 1, 2, 3, 4, 5,
+ 'c', 'h', '3', '\0', 6, 0, 1, 2, 3, 4, 5,
+ 'c', 'h', '4', '\0', 6, 0, 1, 2, 3, 4, 5
+};
+
+enum {
+ TOUCH_RECORD_GET_VERSION = 0x05,
+ TOUCH_RECORD_GET_CH_SIZE = 0x0B,
+ TOUCH_RECORD_GET_CH_CONTENT = 0x0C,
+ TOUCH_RECORD_CHANGE_MODE = 0x0E,
+ TOUCH_RECORD_COUNT = 0x200,
+ TOUCH_RECORD_START,
+ TOUCH_RECORD_STOP,
+ ONLINE_OP_QUERY_RECORD_PACKAGE_LENGTH,
+ TOUCH_CH_CFG_UPDATE = 0x3000,
+ TOUCH_CH_VOL_CFG_UPDATE = 0x3001,
+ TOUCH_CH_CFG_CONFIRM = 0x3100,
+};
+
+enum {
+ LP_KEY_ONLINE_ST_INIT = 0,
+ LP_KEY_ONLINE_ST_READY,
+ LP_KEY_ONLINE_ST_CH_RES_DEBUG_START,
+ LP_KEY_ONLINE_ST_CH_RES_DEBUG_STOP,
+ LP_KEY_ONLINE_ST_CH_KEY_DEBUG_START,
+ LP_KEY_ONLINE_ST_CH_KEY_DEBUG_CONFIRM,
+};
+
+//小机接收命令包格式, 使用DB_PKT_TYPE_TOUCH通道接收
+typedef struct {
+ int cmd_id;
+ int mode;
+ int data[];
+} touch_receive_cmd_t;
+
+//小机发送按键消息格式, 使用DB_PKT_TYPE_TOUCH通道发送
+typedef struct {
+ u32 cmd_id;
+ u32 mode;
+ u32 key_event;
+} lp_touch_online_key_event_t;
+
+typedef struct {
+ u8 state;
+ u8 current_record_ch;
+ u16 res_packet;
+ struct ch_adjust_table debug_cfg;
+ lp_touch_online_key_event_t online_key_event;
+ struct ch_ana_cfg ch_ana;
+} lp_touch_key_online;
+
+static lp_touch_key_online lp_key_online = {0};
+
+int lp_touch_key_online_debug_key_event_handle(u8 ch_index, struct sys_event *event)
+{
+ int err = 0;
+ if ((lp_key_online.state == LP_KEY_ONLINE_ST_CH_KEY_DEBUG_START) && (lp_key_online.current_record_ch == ch_index)) {
+ lp_key_online.online_key_event.cmd_id = 0x3100;
+ lp_key_online.online_key_event.mode = 0;
+ lp_key_online.online_key_event.key_event = event->u.key.event;
+ log_debug("send %d event to PC", lp_key_online.online_key_event.key_event);
+ err = app_online_db_send(DB_PKT_TYPE_TOUCH, (u8 *)(&(lp_key_online.online_key_event)), sizeof(lp_touch_online_key_event_t));
+ }
+
+ if ((lp_key_online.state == LP_KEY_ONLINE_ST_CH_KEY_DEBUG_CONFIRM) ||
+ (lp_key_online.state <= LP_KEY_ONLINE_ST_READY)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int lp_touch_key_debug_reinit(u8 update_state)
+{
+ log_debug("%s, current_record_ch = %d", __func__, lp_key_online.current_record_ch);
+
+ lp_touch_key_disable();
+
+ u8 ch = lp_key_online.current_record_ch;
+ switch (update_state) {
+ case LP_KEY_ONLINE_ST_CH_RES_DEBUG_START:
+ M2P_CTMU_CH_DEBUG &= ~0b11111;
+ M2P_CTMU_CH_DEBUG |= BIT(ch);
+ if (lp_key_online.ch_ana.isel) {
+ LPCTMU_ANA0_CONFIG((lp_key_online.ch_ana.vhsel << 6) | (lp_key_online.ch_ana.vlsel << 4) | (lp_key_online.ch_ana.isel << 1));
+ } else {
+ LPCTMU_ANA0_CONFIG(get_lpctmu_ana_level());
+ }
+ break;
+ case LP_KEY_ONLINE_ST_CH_RES_DEBUG_STOP:
+ M2P_CTMU_CH_DEBUG &= ~0b11111;
+ break;
+ case LP_KEY_ONLINE_ST_CH_KEY_DEBUG_START:
+ M2P_CTMU_CH_DEBUG &= ~0b11111;
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG0L + ch * 8) = ((lp_key_online.debug_cfg.cfg0) & 0xFF);
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG0H + ch * 8) = (((lp_key_online.debug_cfg.cfg0) >> 8) & 0xFF);
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG1L + ch * 8) = ((lp_key_online.debug_cfg.cfg1) & 0xFF);
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG1H + ch * 8) = (((lp_key_online.debug_cfg.cfg1) >> 8) & 0xFF);
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG2L + ch * 8) = ((lp_key_online.debug_cfg.cfg2) & 0xFF);
+ M2P_MESSAGE_ACCESS(M2P_MASSAGE_CTMU_CH0_CFG2H + ch * 8) = (((lp_key_online.debug_cfg.cfg2) >> 8) & 0xFF);
+ break;
+ case LP_KEY_ONLINE_ST_CH_KEY_DEBUG_CONFIRM:
+ M2P_CTMU_CH_DEBUG &= ~0b11111;
+ break;
+ default:
+ break;
+ }
+
+ if (__this->short_timer[ch] != 0xFFFF) {
+ usr_timer_del(__this->short_timer[ch]);
+ __this->short_timer[ch] = 0xFFFF;
+ }
+ __this->last_key[ch] = CTMU_KEY_NULL;
+ P2M_CTMU_WKUP_MSG &= (~(P2M_MESSAGE_INIT_MODE_FLAG)); //普通模式初始化
+
+ __this->softoff_mode = LP_TOUCH_SOFTOFF_MODE_ADVANCE;
+ //CTMU 初始化命令
+ lp_touch_key_send_cmd(CTMU_M2P_INIT);
+
+ return 0;
+}
+
+static int lp_touch_key_online_debug_parse(u8 *packet, u8 size, u8 *ext_data, u16 ext_size)
+{
+ int res_data = 0;
+ touch_receive_cmd_t *touch_cmd;
+ int err = 0;
+ u8 parse_seq = ext_data[1];
+ struct ch_adjust_table *receive_cfg;
+ struct ch_ana_cfg *ana_cfg;
+ struct lp_key_ver_info ver_info = {0};
+
+ static u32 _offset = 0;
+ static u32 _size = 0;
+
+ res_data = 4;
+ log_debug("%s", __func__);
+ put_buf(packet, size);
+ put_buf(ext_data, ext_size);
+ touch_cmd = (touch_receive_cmd_t *)packet;
+ switch (touch_cmd->cmd_id) {
+ case TOUCH_RECORD_START:
+ log_debug("TOUCH_RECORD_START");
+ err = app_online_db_ack(parse_seq, (u8 *)&res_data, 1); //该命令随便ack一个byte即可
+ lp_key_online.state = LP_KEY_ONLINE_ST_CH_RES_DEBUG_START;
+ lp_touch_key_debug_reinit(lp_key_online.state);
+ break;
+ case TOUCH_RECORD_STOP:
+ log_debug("TOUCH_RECORD_STOP");
+ app_online_db_ack(parse_seq, (u8 *)&res_data, 1); //该命令随便ack一个byte即可
+ lp_key_online.state = LP_KEY_ONLINE_ST_CH_RES_DEBUG_STOP;
+ lp_touch_key_debug_reinit(lp_key_online.state);
+ break;
+ case TOUCH_CH_CFG_UPDATE:
+ log_debug("TOUCH_CH_CFG_UPDATE");
+ app_online_db_ack(parse_seq, (u8 *)"OK", 2); //回"OK"字符串
+ lp_key_online.state = LP_KEY_ONLINE_ST_CH_KEY_DEBUG_START;
+
+ receive_cfg = (struct ch_adjust_table *)(touch_cmd->data);
+ lp_key_online.debug_cfg.cfg0 = receive_cfg->cfg0;
+ lp_key_online.debug_cfg.cfg1 = receive_cfg->cfg1;
+ lp_key_online.debug_cfg.cfg2 = receive_cfg->cfg2;
+ log_debug("update, cfg0 = %d, cfg1 = %d, cfg2 = %d", lp_key_online.debug_cfg.cfg0, lp_key_online.debug_cfg.cfg1, lp_key_online.debug_cfg.cfg2);
+ lp_touch_key_debug_reinit(lp_key_online.state);
+ break;
+ case TOUCH_CH_VOL_CFG_UPDATE:
+ log_debug("TOUCH_CH_VOL_CFG_UPDATE");
+ app_online_db_ack(parse_seq, (u8 *)"OK", 2); //回"OK"字符串
+ ana_cfg = (struct ch_ana_cfg *)(touch_cmd->data);
+ lp_key_online.ch_ana.isel = ana_cfg->isel;
+ lp_key_online.ch_ana.vhsel = ana_cfg->vhsel;
+ lp_key_online.ch_ana.vlsel = ana_cfg->vlsel;
+ log_debug("update, isel = %d, vhsel = %d, vlsel = %d", lp_key_online.ch_ana.isel, lp_key_online.ch_ana.vhsel, lp_key_online.ch_ana.vlsel);
+ break;
+ case TOUCH_CH_CFG_CONFIRM:
+ log_debug("TOUCH_CH_CFG_CONFIRM");
+ app_online_db_ack(parse_seq, (u8 *)"OK", 2); //回"OK"字符串
+ lp_key_online.state = LP_KEY_ONLINE_ST_CH_KEY_DEBUG_CONFIRM;
+ break;
+ case TOUCH_RECORD_GET_VERSION:
+ log_debug("TOUCH_RECORD_GET_VERSION");
+ memcpy(ver_info.sdkname, lp_key_sdk_name, sizeof(lp_key_sdk_name));
+ memcpy(ver_info.lp_key_ver, lp_key_bt_ver, sizeof(lp_key_bt_ver));
+ app_online_db_ack(parse_seq, (u8 *)(&ver_info), sizeof(ver_info)); //回复版本号数据结构
+ break;
+ case TOUCH_RECORD_GET_CH_SIZE:
+ log_debug("TOUCH_RECORD_GET_CH_SIZE");
+ res_data = sizeof(ch_content);
+ _size = res_data;
+ _offset = 0;
+ err = app_online_db_ack(parse_seq, (u8 *)&res_data, 4); //回复对应的通道数据长度
+ break;
+ case TOUCH_RECORD_GET_CH_CONTENT:
+ log_debug("TOUCH_RECORD_GET_CH_CONTENT");
+ if (_size > 32) {
+ app_online_db_ack(parse_seq, (u8 *)(&ch_content) + _offset, 32);
+ _size -= 32;
+ _offset += 32;
+ } else {
+ app_online_db_ack(parse_seq, (u8 *)(&ch_content) + _offset, _size);
+ _size = 0;
+ _offset = 0;
+ }
+ break;
+ case TOUCH_RECORD_CHANGE_MODE:
+ log_debug("TOUCH_RECORD_CHANGE_MODE, cmd_mode = %d", touch_cmd->mode);
+ lp_key_online.current_record_ch = touch_cmd->mode;
+ lp_key_online.ch_ana.isel = 0;
+ app_online_db_ack(parse_seq, (u8 *)"OK", 2); //回"OK"字符串
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int lp_touch_key_online_debug_send(u8 ch, u16 val)
+{
+ int err = 0;
+
+ putchar('s');
+ if (lp_key_online.state == LP_KEY_ONLINE_ST_CH_RES_DEBUG_START) {
+ lp_key_online.res_packet = val;
+ err = app_online_db_send(DB_PKT_TYPE_DAT_CH0, (u8 *)(&(lp_key_online.res_packet)), 2);
+ }
+
+ return err;
+}
+
+int lp_touch_key_online_debug_init(void)
+{
+ log_debug("%s", __func__);
+ app_online_db_register_handle(DB_PKT_TYPE_TOUCH, lp_touch_key_online_debug_parse);
+ lp_key_online.state = LP_KEY_ONLINE_ST_READY;
+
+ return 0;
+}
+
+int lp_touch_key_online_debug_exit(void)
+{
+ return 0;
+}
+
+#endif /* #if TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE */
+/** @} lp_touch_key_tool_spp*/
+
+
+
+/**@defgroup lp_touch_key_tool_testbox
+* @{
+ */
+extern u8 testbox_get_key_action_test_flag(void *priv);
+extern void eartch_state_update(u8 state);
+
+__attribute__((weak))
+u32 user_send_cmd_prepare(USER_CMD_TYPE cmd, u16 param_len, u8 *param)
+{
+ return 0;
+}
+
+u8 lp_touch_key_testbox_remote_test(u8 ch, u8 event)
+{
+ u8 ret = true;
+ u8 key_report = 0;
+ if (event == (CTMU_P2M_CH0_FALLING_EVENT + ch * 8)) {
+ key_report = 0xF1;
+ log_info("Notify testbox CH%d Down", ch);
+ } else if (event == (CTMU_P2M_CH0_RAISING_EVENT + ch * 8)) {
+ key_report = 0xF2;
+ log_info("Notify testbox CH%d Up", ch);
+ } else if (event == (CTMU_P2M_CH0_SHORT_KEY_EVENT + ch * 8)) {
+ } else if (event == (CTMU_P2M_CH0_LONG_KEY_EVENT + ch * 8)) {
+ } else if (event == (CTMU_P2M_CH0_HOLD_KEY_EVENT + ch * 8)) {
+ } else {
+ ret = false;
+ }
+ if (key_report) {
+ user_send_cmd_prepare(USER_CTRL_TEST_KEY, 1, &key_report); //音量加
+ }
+ return ret;
+}
+
+void lp_touch_key_testbox_inear_trim(u8 flag)
+{
+#if (!TCFG_LP_TOUCH_KEY_BT_TOOL_ENABLE)
+ if (flag == 1) {
+ __this->eartch_trim_flag = 1;
+ __this->eartch_inear_ok = 0;
+ __this->eartch_trim_value = 0;
+ M2P_CTMU_CH_DEBUG |= BIT(__this->config->eartch_ch);
+ log_info("__this->eartch_trim_flag = %d", __this->eartch_trim_flag);
+ set_lpkey_active(1);
+ } else {
+ __this->eartch_trim_flag = 0;
+ M2P_CTMU_CH_DEBUG &= ~BIT(__this->config->eartch_ch);
+ log_info("__this->eartch_trim_flag = %d", __this->eartch_trim_flag);
+ }
+#endif
+}
+/** @} lp_touch_key_tool_testbox*/
+
+
+
diff --git a/cpu/br28/lua_port_api.c b/cpu/br28/lua_port_api.c
new file mode 100644
index 0000000..5f5bc3e
--- /dev/null
+++ b/cpu/br28/lua_port_api.c
@@ -0,0 +1,140 @@
+//--- support functions for Lua
+
+#include
+#include "cpu.h"
+
+#if 1
+void abort()
+{
+ printf("lua aborted !!!!!\n");
+ while (1);
+}
+#endif
+
+char *_user_strerror(
+ int errnum,
+ int internal,
+ int *errptr)
+{
+ /* prevent warning about unused parameters */
+ (void)errnum;
+ (void)internal;
+ (void)errptr;
+
+ return 0;
+}
+
+unsigned int luaP_makeseed(void)
+{
+ int rand = (JL_RAND->R64H << 32) | JL_RAND->R64L;
+ return rand;
+}
+
+void luaP_writeline(void)
+{
+ putchar('\n');
+}
+
+void luaP_writestring(const char *p, int l)
+{
+ for (int i = 0; i < l; i++) {
+ putchar(*p++);
+ }
+}
+
+
+#if 1
+void *my_realloc(void *ptr, size_t osize, size_t nsize)
+{
+ /* printf("realloc(%x, %d)\n", ptr, size); */
+ if (!ptr) {
+ return malloc(nsize);
+ }
+ if (nsize == 0) {
+ free(ptr);
+ ptr = NULL;
+ return NULL;
+ }
+
+ void *p = malloc(nsize);
+ if (p) {
+ if (ptr != NULL) {
+ // 照较小的buffer大小拷贝,防止溢出
+ size_t copy_size = (osize > nsize) ? nsize : osize;
+ memcpy(p, ptr, copy_size);
+ free(ptr);
+ ptr = NULL;
+ }
+ return p;
+ }
+ return NULL;
+}
+#endif
+
+int my_sprintf(char *s, const char *fmt, ...)
+{
+ va_list args;
+ double argv;
+ int ret = 0;
+
+ if (!strcmp(fmt, "%.7g")) {
+ va_start(args, fmt);
+ argv = va_arg(args, double);
+
+ char format[9] = {0};
+ int integer = 0;
+ int trim = 0;
+ if ((argv > -0.00000001) && (argv < 0.00000001)) {
+ sprintf(format, "%%d.%%d");
+ } else if (argv >= 0.00000001) {
+ integer = (int)argv;
+ int decimal = (int)(((__int64)((argv - integer) * 100000000 + 5)) % 100000000);
+ decimal /= 10;
+ trim = decimal;
+ int bits = 7;
+ while (bits) {
+ int n = trim % 10;
+ if (n != 0) {
+ break;
+ } else {
+ trim /= 10;
+ bits--;
+ }
+ }
+ if (bits) {
+ sprintf(format, "%%d.%%0%dd", bits);
+ } else {
+ sprintf(format, "%%d.%%d");
+ }
+ } else {
+ argv = -argv;
+ integer = (int)argv;
+ int decimal = (int)(((__int64)((argv - integer) * 100000000 + 5)) % 100000000);
+ decimal /= 10;
+ trim = decimal;
+ int bits = 7;
+ while (bits) {
+ int n = trim % 10;
+ if (n != 0) {
+ break;
+ } else {
+ trim /= 10;
+ bits--;
+ }
+ }
+ if (bits) {
+ sprintf(format, "-%%d.%%0%dd", bits);
+ } else {
+ sprintf(format, "-%%d.%%d");
+ }
+ }
+ ret = sprintf(s, format, integer, trim);
+ va_end(args);
+ } else {
+ ASSERT(0, "format %s not support!", fmt);
+ }
+
+ return ret;
+}
+
+
diff --git a/cpu/br28/maskrom_stubs.ld b/cpu/br28/maskrom_stubs.ld
new file mode 100644
index 0000000..5abeb7f
--- /dev/null
+++ b/cpu/br28/maskrom_stubs.ld
@@ -0,0 +1,236 @@
+ lp_signature_set = ABSOLUTE(0x1fd6c);
+ memmem = ABSOLUTE(0x1fd70);
+ memcpy = ABSOLUTE(0x1fd74);
+ memmove = ABSOLUTE(0x1fd78);
+ memcmp = ABSOLUTE(0x1fd7c);
+ memset = ABSOLUTE(0x1fd80);
+ strcmp = ABSOLUTE(0x1fd84);
+ strcpy = ABSOLUTE(0x1fd88);
+ strlen = ABSOLUTE(0x1fd8c);
+ strncmp = ABSOLUTE(0x1fd90);
+ strstr = ABSOLUTE(0x1fd94);
+ strchr = ABSOLUTE(0x1fd98);
+ __divdi3 = ABSOLUTE(0x1fd9c);
+ __udivmoddi4 = ABSOLUTE(0x1fda0);
+ __adddf3 = ABSOLUTE(0x1fda4);
+ __fixdfsi = ABSOLUTE(0x1fda8);
+ flush_dcache = ABSOLUTE(0x1fdac);
+ flushinv_dcache = ABSOLUTE(0x1fdb0);
+ IcuWaitIdle = ABSOLUTE(0x1fdb4);
+ DcuWaitIdle = ABSOLUTE(0x1fdb8);
+ IcuInitial = ABSOLUTE(0x1fdbc);
+ DcuInitial = ABSOLUTE(0x1fdc0);
+ /* sfc_suspend = ABSOLUTE(0x1fdc4); */
+ /* sfc_resume = ABSOLUTE(0x1fdc8); */
+ sfc_drop_cache = ABSOLUTE(0x1fdcc);
+ chip_crc16 = ABSOLUTE(0x1fdd0);
+ CrcDecode = ABSOLUTE(0x1fdd4);
+ get_flash_file_key = ABSOLUTE(0x1fdd8);
+ dec_isd_cfg_ini = ABSOLUTE(0x1fddc);
+ _jlfs_mount = ABSOLUTE(0x1fde0);
+ sfc_boot = ABSOLUTE(0x1fde4);
+ mask_init = ABSOLUTE(0x1fde8);
+ /* wdt_clr = ABSOLUTE(0x1fdec); */
+ nvram_set_boot_state = ABSOLUTE(0x1fdf0);
+ chip_reset = ABSOLUTE(0x1fdf4);
+ the_debug_isr = ABSOLUTE(0x1fdf8);
+ print = ABSOLUTE(0x1fdfc);
+ sprintf = ABSOLUTE(0x1fe00);
+ printf = ABSOLUTE(0x1fe04);
+ puts = ABSOLUTE(0x1fe08);
+ doe = ABSOLUTE(0x1fe0c);
+ spi_get_port = ABSOLUTE(0x1fe10);
+ _pll_init = ABSOLUTE(0x1fe14);
+ flash_poweron = ABSOLUTE(0x1fe18);
+ spi_unmount = ABSOLUTE(0x1fe1c);
+ spi_port_io_init = ABSOLUTE(0x1fe20);
+ usb_slave_mode = ABSOLUTE(0x1fe24);
+ LZ4_setStreamDecode = ABSOLUTE(0x1fe28);
+ LZ4_decompress_safe_continue = ABSOLUTE(0x1fe2c);
+ LZ4_decompress_generic = ABSOLUTE(0x1fe30);
+ _sdk_mkey_lock = ABSOLUTE(0x1fe34);
+ g_hash_function = ABSOLUTE(0x1fe38);
+ f1_hash_function = ABSOLUTE(0x1fe3c);
+ f2_hash_function = ABSOLUTE(0x1fe40);
+ f3_hash_function = ABSOLUTE(0x1fe44);
+ h2_hash_function = ABSOLUTE(0x1fe48);
+ h3_hash_function = ABSOLUTE(0x1fe4c);
+ h4_hash_function = ABSOLUTE(0x1fe50);
+ h5_hash_function = ABSOLUTE(0x1fe54);
+ g_function = ABSOLUTE(0x1fe58);
+ f1_function = ABSOLUTE(0x1fe5c);
+ f2_function = ABSOLUTE(0x1fe60);
+ f3_function = ABSOLUTE(0x1fe64);
+ sha256Compute = ABSOLUTE(0x1fe68);
+ uECC_compute_public_key = ABSOLUTE(0x1fe6c);
+ uECC_shared_secret = ABSOLUTE(0x1fe70);
+ bi_initialize = ABSOLUTE(0x1fe74);
+ bi_read_from_byte = ABSOLUTE(0x1fe78);
+ bi_poly_mod2 = ABSOLUTE(0x1fe7c);
+ bi_poly_mul = ABSOLUTE(0x1fe80);
+ trim = ABSOLUTE(0x1fe84);
+ bi_wirte_to_byte = ABSOLUTE(0x1fe88);
+ bi_free = ABSOLUTE(0x1fe8c);
+ bi_terminate = ABSOLUTE(0x1fe90);
+ get_cvsd_codec_ops = ABSOLUTE(0x1fe94);
+ wtgv2_silk_NLSF_CB_NB_MB = ABSOLUTE(0x18590);
+ wtgv2_LSFCosTab_FIX_Q12 = ABSOLUTE(0x1848c);
+ icdf_global_table = ABSOLUTE(0x18a88);
+ get_wtgv2dec_ops = ABSOLUTE(0x1fe98);
+ wtgv2_silk_Decode = ABSOLUTE(0x1fe9c);
+ wtgv2_silk_decode_frame = ABSOLUTE(0x1fea0);
+ wtgv2_silk_decoder_set_fs = ABSOLUTE(0x1fea4);
+ wtgv2_silk_decode_indices = ABSOLUTE(0x1fea8);
+ wtgv2_silk_decode_pulses = ABSOLUTE(0x1feac);
+ wtgv2_silk_decode_parameters = ABSOLUTE(0x1feb0);
+ wtgv2_silk_decode_core = ABSOLUTE(0x1feb4);
+ logAprx_CORDIC_float = ABSOLUTE(0x1feb8);
+ expAprx_CORDIC_float = ABSOLUTE(0x1febc);
+ magnAprx_float = ABSOLUTE(0x1fec0);
+ MatrixCopy_float_c_c = ABSOLUTE(0x1fec4);
+ MatrixCopy_float_f_f = ABSOLUTE(0x1fec8);
+ MatrixEwMulAndSumOneDim_float_c_c_c_s0 = ABSOLUTE(0x1fecc);
+ MatrixEwMulAndSumOneDim_float_c_c_c_s1 = ABSOLUTE(0x1fed0);
+ MatrixEwMulAndSumOneDim_float_f_f_f_s0 = ABSOLUTE(0x1fed4);
+ MatrixEwMulAndSumOneDim_float_f_f_f_s1 = ABSOLUTE(0x1fed8);
+ MatrixEwConjMulAndSumOneDim_float_c_c_c_s0 = ABSOLUTE(0x1fedc);
+ MatrixEwConjMulAndSumOneDim_float_c_c_c_s1 = ABSOLUTE(0x1fee0);
+ VecMeanSq_s16_f32 = ABSOLUTE(0x1fee4);
+ VecOverShift_s16_f32 = ABSOLUTE(0x1fee8);
+ VecMinus_s16_f32_f32 = ABSOLUTE(0x1feec);
+ VectorCopy_f32_s16 = ABSOLUTE(0x1fef0);
+ VecEleMul_s16_s16_f32 = ABSOLUTE(0x1fef4);
+ VecEleMul_f32_s16_f32 = ABSOLUTE(0x1fef8);
+ VecMeanSq_float_f_f = ABSOLUTE(0x1fefc);
+ VectorSet_float_f_f = ABSOLUTE(0x1ff00);
+ VecMagRecAve_float_c_f_f = ABSOLUTE(0x1ff04);
+ VecMulScalar_float_c_f_c = ABSOLUTE(0x1ff08);
+ VecConjEleMul_float_c_c_c = ABSOLUTE(0x1ff0c);
+ VecPlus_float_f_f_f = ABSOLUTE(0x1ff10);
+ VecDivide_float_c_f_c_f = ABSOLUTE(0x1ff14);
+ VecPlus_float_c_c_c = ABSOLUTE(0x1ff18);
+ VecConjMulRecAve_float_c_c_c_f = ABSOLUTE(0x1ff1c);
+ VecGetMag_float_c_f = ABSOLUTE(0x1ff20);
+ VecMax_float_f_f = ABSOLUTE(0x1ff24);
+ VecRecAve_float_f_f_f = ABSOLUTE(0x1ff28);
+ VecEleMul_float_f_f_f = ABSOLUTE(0x1ff2c);
+ VecMagAndDiv_float_c_f_f_f = ABSOLUTE(0x1ff30);
+ VecMin_float_f_f = ABSOLUTE(0x1ff34);
+ VecMinus_float_f_f_f = ABSOLUTE(0x1ff38);
+ VecMean_float_f_f = ABSOLUTE(0x1ff3c);
+ VecEleMul_float_c_f_c = ABSOLUTE(0x1ff40);
+ VecMeanSqu_float_c_f = ABSOLUTE(0x1ff44);
+ VecCopy_float_f_f = ABSOLUTE(0x1ff48);
+ VecMin_float_f_f_f = ABSOLUTE(0x1ff4c);
+ VecDivide_float_f_f_f_f = ABSOLUTE(0x1ff50);
+ VecCompBT_float_f_f_f = ABSOLUTE(0x1ff54);
+ VecCondCopy_float_f_f_f = ABSOLUTE(0x1ff58);
+ VecMulScalar_float_f_f_f = ABSOLUTE(0x1ff5c);
+ VecPlusScalar_float_f_f_f = ABSOLUTE(0x1ff60);
+ VecMinScalar_float_f_f_f = ABSOLUTE(0x1ff64);
+ VecOpposite_float_f_f = ABSOLUTE(0x1ff68);
+ VecEleMla_float_f_f_f = ABSOLUTE(0x1ff6c);
+ VecEleMla_float_c_c_c = ABSOLUTE(0x1ff70);
+ VecMinus_float_c_c_c = ABSOLUTE(0x1ff74);
+ VecDotProduct_float_f_f_f = ABSOLUTE(0x1ff78);
+ VecDotProduct_float_c_c_c = ABSOLUTE(0x1ff7c);
+ VecDotProduct_float_c_f_c = ABSOLUTE(0x1ff80);
+ VecCopy_float_c_c = ABSOLUTE(0x1ff84);
+ VecCopy_float_f_c = ABSOLUTE(0x1ff88);
+ VecConjDotProduct_float_c_c_c = ABSOLUTE(0x1ff8c);
+ VecNormalize_float_c_c_f = ABSOLUTE(0x1ff90);
+ VecRecAve_float_c_c_f = ABSOLUTE(0x1ff94);
+ VecOverlapShift_float_f_f_i = ABSOLUTE(0x1ff98);
+ VecMax_float_f_f_f = ABSOLUTE(0x1ff9c);
+ VecConjEwMulAndDiv_float_c_c_f_f_c = ABSOLUTE(0x1ffa0);
+ VecPlusMulScalar_float_c_c_f_c = ABSOLUTE(0x1ffa4);
+ VecCondCopy_float_c_i_c = ABSOLUTE(0x1ffa8);
+ VecEleMulAndDiv_float_f_f_f_f_f = ABSOLUTE(0x1ffac);
+ VectorSet_float_f_c = ABSOLUTE(0x1ffb0);
+ VecDivScalar_float_f_f_f = ABSOLUTE(0x1ffb4);
+ VecDivScalar_float_c_f_c = ABSOLUTE(0x1ffb8);
+ VecPlusScalar_float_c_f_c = ABSOLUTE(0x1ffbc);
+ VecMinScalar_float_c_f_c = ABSOLUTE(0x1ffc0);
+ mdct_tab_256 = ABSOLUTE(0x19000);
+ mdct_tab_2048 = ABSOLUTE(0x19200);
+ sine_long_1024 = ABSOLUTE(0x1a200);
+ sine_short_128 = ABSOLUTE(0x1b200);
+ kbd_long_1024 = ABSOLUTE(0x1b400);
+ kbd_short_128 = ABSOLUTE(0x1c400);
+ Huffmancb_SCL = ABSOLUTE(0x1c634);
+ num_swb_960_window = ABSOLUTE(0x1c844);
+ num_swb_1024_window = ABSOLUTE(0x1c850);
+ num_swb_128_window = ABSOLUTE(0x1c85c);
+ swb_offset_1024_96 = ABSOLUTE(0x1c868);
+ swb_offset_128_96 = ABSOLUTE(0x1c8bc);
+ swb_offset_1024_64 = ABSOLUTE(0x1c8d6);
+ swb_offset_128_64 = ABSOLUTE(0x1c936);
+ swb_offset_1024_48 = ABSOLUTE(0x1c950);
+ swb_offset_128_48 = ABSOLUTE(0x1c9b4);
+ swb_offset_1024_32 = ABSOLUTE(0x1c9d2);
+ swb_offset_1024_24 = ABSOLUTE(0x1ca3a);
+ swb_offset_128_24 = ABSOLUTE(0x1ca9a);
+ swb_offset_1024_16 = ABSOLUTE(0x1caba);
+ swb_offset_128_16 = ABSOLUTE(0x1cb12);
+ swb_offset_1024_8 = ABSOLUTE(0x1cb32);
+ swb_offset_128_8 = ABSOLUTE(0x1cb84);
+ swb_offset_1024_window = ABSOLUTE(0x1cba4);
+ swb_offset_128_window = ABSOLUTE(0x1cbd4);
+ iq_table = ABSOLUTE(0x1cc04);
+ tns_coef_0_3 = ABSOLUTE(0x1d008);
+ tns_coef_0_4 = ABSOLUTE(0x1d048);
+ tns_coef_1_3 = ABSOLUTE(0x1d088);
+ tns_coef_1_4 = ABSOLUTE(0x1d0c8);
+ pow05_table = ABSOLUTE(0x1d108);
+ sample_rates = ABSOLUTE(0x1d124);
+ pred_sfb_max = ABSOLUTE(0x1d154);
+ tns_sbf_max = ABSOLUTE(0x1d160);
+ Huffmancb_1 = ABSOLUTE(0x1d1a0);
+ Huffmancb_2 = ABSOLUTE(0x1d338);
+ Huffmancb_3 = ABSOLUTE(0x1d470);
+ Huffmancb_4 = ABSOLUTE(0x1d5a8);
+ Huffmancb_5 = ABSOLUTE(0x1d6d8);
+ Huffmancb_6 = ABSOLUTE(0x1d820);
+ Huffmancb_7 = ABSOLUTE(0x1d960);
+ Huffmancb_8 = ABSOLUTE(0x1da58);
+ Huffmancb_9 = ABSOLUTE(0x1db50);
+ Huffmancb_10 = ABSOLUTE(0x1ddf0);
+ Huffmancb_11 = ABSOLUTE(0x1e080);
+ AACcodeBookDTable = ABSOLUTE(0x1e540);
+ AAC_SFHUFF_TAB = ABSOLUTE(0x1c83c);
+ get_aac_ops = ABSOLUTE(0x1ffc4);
+ silk_NLSF_CB_WB = ABSOLUTE(0x1e5b8);
+ silk_LTP_vq_ptrs_Q7 = ABSOLUTE(0x1ea5c);
+ get_opus_enc_ops = ABSOLUTE(0x1ffc8);
+ opus_encode = ABSOLUTE(0x1ffcc);
+ silk_Encode = ABSOLUTE(0x1ffd0);
+ silk_encode_do_VAD_FIX = ABSOLUTE(0x1ffd4);
+ silk_encode_frame_FIX = ABSOLUTE(0x1ffd8);
+ silk_find_pitch_lags_FIX = ABSOLUTE(0x1ffdc);
+ silk_noise_shape_analysis_FIX = ABSOLUTE(0x1ffe0);
+ silk_find_pred_coefs_FIX = ABSOLUTE(0x1ffe4);
+ silk_process_gains_FIX = ABSOLUTE(0x1ffe8);
+ silk_prefilter_FIX = ABSOLUTE(0x1ffec);
+ silk_NSQ_del_dec_c = ABSOLUTE(0x1fff0);
+ silk_encode_indices = ABSOLUTE(0x1fff4);
+ silk_encode_pulses = ABSOLUTE(0x1fff8);
+ silk_ana_filt_bank_1 = ABSOLUTE(0x1fffc);
+ STFT_Win_FixHalf_M512_D160 = ABSOLUTE(0x3804);
+ STFT_Win_FixHalf_M256_D160 = ABSOLUTE(0x3c04);
+ STFT_Win_FixHalf_M256_D80 = ABSOLUTE(0x3e04);
+ STFT_Win_FixHalf_M128_D80 = ABSOLUTE(0x4004);
+ WOLAAnalysisFilter_Float_M64_m4_r1 = ABSOLUTE(0x4);
+ WOLASynthesisFilter_Float_M64_m4_r1 = ABSOLUTE(0x404);
+ WOLAAnalysisFilter_Float_M128_m4_r1 = ABSOLUTE(0x804);
+ WOLASynthesisFilter_Float_M128_m4_r1 = ABSOLUTE(0x1004);
+ WOLAAnalysisFilter_Float_M256_m4_r1 = ABSOLUTE(0x1804);
+ WOLASynthesisFilter_Float_M256_m4_r1 = ABSOLUTE(0x2804);
+ quantize_intervals_LF = ABSOLUTE(0x9914);
+ invert_quantize_dither_factors_LF = ABSOLUTE(0x9a18);
+ quantize_dither_factors_LF = ABSOLUTE(0x9b1c);
+ quantize_factor_select_offset_LF = ABSOLUTE(0x9c20);
+ hd_quantize_intervals_LF = ABSOLUTE(0x9ca4);
+ boot_arg_list = ABSOLUTE(0x19fc28);
+ _IRQ_MEM_ADDR = ABSOLUTE(0x19fe00);
+ _MASK_MEM_BEGIN = ABSOLUTE(0x19fc00);
+ _MASK_MEM_SIZE = ABSOLUTE(0x1a4);
diff --git a/cpu/br28/mcpwm.c b/cpu/br28/mcpwm.c
new file mode 100644
index 0000000..eda3c91
--- /dev/null
+++ b/cpu/br28/mcpwm.c
@@ -0,0 +1,511 @@
+#include "asm/mcpwm.h"
+#include "asm/clock.h"
+#include "asm/gpio.h"
+
+#define MCPWM_DEBUG_ENABLE 1
+#if MCPWM_DEBUG_ENABLE
+#define mcpwm_debug(fmt, ...) printf("[MCPWM] "fmt, ##__VA_ARGS__)
+#else
+#define mcpwm_debug(...)
+#endif
+
+#define MCPWM_CLK clk_get("mcpwm")
+
+
+PWM_TIMER_REG *get_pwm_timer_reg(pwm_ch_num_type index)
+{
+ PWM_TIMER_REG *reg = NULL;
+ switch (index) {
+ case pwm_ch0:
+ reg = (PWM_TIMER_REG *)(&(JL_MCPWM->TMR0_CON));
+ break;
+ case pwm_ch1:
+ reg = (PWM_TIMER_REG *)(&(JL_MCPWM->TMR1_CON));
+ break;
+ case pwm_ch2:
+ reg = (PWM_TIMER_REG *)(&(JL_MCPWM->TMR2_CON));
+ break;
+ case pwm_ch3:
+ reg = (PWM_TIMER_REG *)(&(JL_MCPWM->TMR3_CON));
+ break;
+ default:
+ break;
+ }
+ return reg;
+}
+
+PWM_CH_REG *get_pwm_ch_reg(pwm_ch_num_type index)
+{
+ PWM_CH_REG *reg = NULL;
+ switch (index) {
+ case pwm_ch0:
+ reg = (PWM_CH_REG *)(&(JL_MCPWM->CH0_CON0));
+ break;
+ case pwm_ch1:
+ reg = (PWM_CH_REG *)(&(JL_MCPWM->CH1_CON0));
+ break;
+ case pwm_ch2:
+ reg = (PWM_CH_REG *)(&(JL_MCPWM->CH2_CON0));
+ break;
+ case pwm_ch3:
+ reg = (PWM_CH_REG *)(&(JL_MCPWM->CH3_CON0));
+ break;
+ default:
+ break;
+ }
+ return reg;
+}
+
+static u8 clk_in_io = IO_PORTC_02;
+/*
+ * @brief 更改MCPWM的频率
+ * @parm frequency 频率
+ */
+void mcpwm_set_frequency(pwm_ch_num_type ch, pwm_aligned_mode_type align, u32 frequency)
+{
+ PWM_TIMER_REG *reg = get_pwm_timer_reg(ch);
+ if (reg == NULL) {
+ return;
+ }
+
+ reg->tmr_con = 0;
+ reg->tmr_cnt = 0;
+ reg->tmr_pr = 0;
+
+ u32 i = 0;
+ u32 mcpwm_div_clk = 0;
+ u32 mcpwm_tmr_pr = 0;
+ u32 mcpwm_fre_min = 0;
+ u32 clk = MCPWM_CLK;
+ for (i = 0; i < 16; i++) {
+ mcpwm_fre_min = clk / (65536 * (1 << i));
+ if ((frequency >= mcpwm_fre_min) || (i == 15)) {
+ break;
+ }
+ }
+ reg->tmr_con |= (i << 3); //div 2^i
+ mcpwm_div_clk = clk / (1 << i);
+ if (frequency == 0) {
+ mcpwm_tmr_pr = 0;
+ } else {
+ if (align == pwm_center_aligned) { //中心对齐
+ mcpwm_tmr_pr = mcpwm_div_clk / (frequency * 2) - 1;
+ } else {
+ mcpwm_tmr_pr = mcpwm_div_clk / frequency - 1;
+ }
+ }
+ reg->tmr_pr = mcpwm_tmr_pr;
+ //timer mode
+ if (align == pwm_center_aligned) { //中心对齐
+ reg->tmr_con |= 0b10;
+ } else {
+ reg->tmr_con |= 0b01;
+ }
+}
+
+static u32 old_mcpwm_clk = 0;
+static void clock_critical_enter(void)
+{
+ old_mcpwm_clk = clk_get("mcpwm");
+}
+static void clock_critical_exit(void)
+{
+ u32 new_mcpwm_clk = clk_get("mcpwm");
+ if (new_mcpwm_clk == old_mcpwm_clk) {
+ return;
+ }
+ PWM_CH_REG *pwm_reg = NULL;
+ PWM_TIMER_REG *timer_reg = NULL;
+ for (u8 ch = 0; ch < 4; ch++) {
+ if (JL_MCPWM->MCPWM_CON0 & BIT(ch + 8)) {
+ pwm_reg = get_pwm_ch_reg(ch);
+ timer_reg = get_pwm_timer_reg(ch);
+ if (new_mcpwm_clk > old_mcpwm_clk) {
+ timer_reg->tmr_pr = timer_reg->tmr_pr * (new_mcpwm_clk / old_mcpwm_clk);
+ pwm_reg->ch_cmpl = pwm_reg->ch_cmpl * (new_mcpwm_clk / old_mcpwm_clk);
+ } else {
+ timer_reg->tmr_pr = timer_reg->tmr_pr / (old_mcpwm_clk / new_mcpwm_clk);
+ pwm_reg->ch_cmpl = pwm_reg->ch_cmpl / (old_mcpwm_clk / new_mcpwm_clk);
+ }
+ pwm_reg->ch_cmph = pwm_reg->ch_cmpl;
+ }
+ }
+}
+CLOCK_CRITICAL_HANDLE_REG(mcpwm, clock_critical_enter, clock_critical_exit)
+
+/*
+ * @brief 设置一个通道的占空比
+ * @parm pwm_ch_num 通道号:pwm_ch0,pwm_ch1,pwm_ch2
+ * @parm duty 占空比:0 ~ 10000 对应 0% ~ 100%
+ */
+void mcpwm_set_duty(pwm_ch_num_type pwm_ch, u16 duty)
+{
+ PWM_TIMER_REG *timer_reg = get_pwm_timer_reg(pwm_ch);
+ PWM_CH_REG *pwm_reg = get_pwm_ch_reg(pwm_ch);
+
+ if (pwm_reg && timer_reg) {
+ pwm_reg->ch_cmpl = timer_reg->tmr_pr * duty / 10000;
+ pwm_reg->ch_cmph = pwm_reg->ch_cmpl;
+ timer_reg->tmr_cnt = 0;
+ timer_reg->tmr_con |= 0b01;
+ if (duty == 10000) {
+ timer_reg->tmr_cnt = 0;
+ timer_reg->tmr_con &= ~(0b11);
+ } else if (duty == 0) {
+ timer_reg->tmr_cnt = pwm_reg->ch_cmpl;
+ timer_reg->tmr_con &= ~(0b11);
+ }
+ }
+}
+
+/*
+ * @brief 打开或者关闭一个时基
+ * @parm pwm_ch_num 通道号:pwm_ch0,pwm_ch1,pwm_ch2
+ * @parm enable 1:打开 0:关闭
+ */
+void mctimer_ch_open_or_close(pwm_ch_num_type pwm_ch, u8 enable)
+{
+ if (pwm_ch > pwm_ch_max) {
+ return;
+ }
+ if (enable) {
+ JL_MCPWM->MCPWM_CON0 |= BIT(pwm_ch + 8); //TnEN
+ } else {
+ JL_MCPWM->MCPWM_CON0 &= (~BIT(pwm_ch + 8)); //TnDIS
+ }
+}
+
+
+/*
+ * @brief 打开或者关闭一个通道
+ * @parm pwm_ch_num 通道号:pwm_ch0,pwm_ch1,pwm_ch2
+ * @parm enable 1:打开 0:关闭
+ */
+void mcpwm_ch_open_or_close(pwm_ch_num_type pwm_ch, u8 enable)
+{
+ if (pwm_ch >= pwm_ch_max) {
+ return;
+ }
+ if (enable) {
+ JL_MCPWM->MCPWM_CON0 |= BIT(pwm_ch); //PWMnEN
+ } else {
+ JL_MCPWM->MCPWM_CON0 &= (~BIT(pwm_ch)); //PWMnDIS
+ }
+}
+
+/*
+ * @brief 关闭MCPWM模块
+ */
+void mcpwm_open(pwm_ch_num_type pwm_ch)
+{
+ if (pwm_ch >= pwm_ch_max) {
+ return;
+ }
+ PWM_CH_REG *pwm_reg = get_pwm_ch_reg(pwm_ch);
+ pwm_reg->ch_con1 &= ~(0b111 << 8);
+ pwm_reg->ch_con1 |= (pwm_ch << 8); //sel mctmr
+ mcpwm_ch_open_or_close(pwm_ch, 1);
+ mctimer_ch_open_or_close(pwm_ch, 1);
+}
+
+
+/*
+ * @brief 关闭MCPWM模块
+ */
+void mcpwm_close(pwm_ch_num_type pwm_ch)
+{
+ mctimer_ch_open_or_close(pwm_ch, 0);
+ mcpwm_ch_open_or_close(pwm_ch, 0);
+}
+
+
+void log_pwm_info(pwm_ch_num_type pwm_ch)
+{
+ PWM_CH_REG *pwm_reg = get_pwm_ch_reg(pwm_ch);
+ PWM_TIMER_REG *timer_reg = get_pwm_timer_reg(pwm_ch);
+ mcpwm_debug("tmr%d con0 = 0x%x", pwm_ch, timer_reg->tmr_con);
+ mcpwm_debug("tmr%d pr = 0x%x", pwm_ch, timer_reg->tmr_pr);
+ mcpwm_debug("pwm ch%d_con0 = 0x%x", pwm_ch, pwm_reg->ch_con0);
+ mcpwm_debug("pwm ch%d_con1 = 0x%x", pwm_ch, pwm_reg->ch_con1);
+ mcpwm_debug("pwm ch%d_cmph = 0x%x, pwm ch%d_cmpl = 0x%x", pwm_ch, pwm_reg->ch_cmph, pwm_ch, pwm_reg->ch_cmpl);
+ mcpwm_debug("MCPWM_CON0 = 0x%x", JL_MCPWM->MCPWM_CON0);
+ mcpwm_debug("mcpwm clk = %d", MCPWM_CLK);
+}
+
+void mcpwm_init(struct pwm_platform_data *arg)
+{
+ //set output IO
+ PWM_CH_REG *pwm_reg = get_pwm_ch_reg(arg->pwm_ch_num);
+ if (pwm_reg == NULL) {
+ return;
+ }
+
+ //set mctimer frequency
+ mcpwm_set_frequency(arg->pwm_ch_num, arg->pwm_aligned_mode, arg->frequency);
+
+ pwm_reg->ch_con0 = 0;
+
+ if (arg->complementary_en) { //是否互补
+ pwm_reg->ch_con0 &= ~(BIT(5) | BIT(4));
+ pwm_reg->ch_con0 |= BIT(5); //L_INV
+ } else {
+ pwm_reg->ch_con0 &= ~(BIT(5) | BIT(4));
+ }
+
+ mcpwm_open(arg->pwm_ch_num); //mcpwm enable
+ //set duty
+ mcpwm_set_duty(arg->pwm_ch_num, arg->duty);
+
+ //H:
+ if (arg->h_pin < IO_MAX_NUM) { //任意引脚
+ pwm_reg->ch_con0 |= BIT(2); //H_EN
+ gpio_och_sel_output_signal(arg->h_pin, OUTPUT_CH_SIGNAL_MC_PWM0_H + 2 * arg->pwm_ch_num);
+ gpio_set_direction(arg->h_pin, 0); //DIR output
+ }
+ //L:
+ if (arg->l_pin < IO_MAX_NUM) { //任意引脚
+ pwm_reg->ch_con0 |= BIT(3); //L_EN
+ gpio_och_sel_output_signal(arg->l_pin, OUTPUT_CH_SIGNAL_MC_PWM0_L + 2 * arg->pwm_ch_num);
+ gpio_set_direction(arg->l_pin, 0); //DIR output
+ }
+
+ log_pwm_info(arg->pwm_ch_num);
+}
+
+
+///////////// for test code //////////////////
+void mcpwm_test(void)
+{
+#define PWM_CH0_ENABLE 1
+#define PWM_CH1_ENABLE 1
+#define PWM_CH2_ENABLE 1
+#define PWM_CH3_ENABLE 1
+
+ struct pwm_platform_data pwm_p_data;
+
+#if PWM_CH0_ENABLE
+ pwm_p_data.pwm_aligned_mode = pwm_edge_aligned; //边沿对齐
+ pwm_p_data.pwm_ch_num = pwm_ch0; //通道号
+ pwm_p_data.frequency = 1000; //1KHz
+ pwm_p_data.duty = 5000; //占空比50%
+ pwm_p_data.h_pin = IO_PORTA_06; //任意引脚
+ pwm_p_data.l_pin = -1; //任意引脚,不需要就填-1
+ pwm_p_data.complementary_en = 0; //两个引脚的波形, 0: 同步, 1: 互补,互补波形的占空比体现在H引脚上
+ mcpwm_init(&pwm_p_data);
+#endif
+#if PWM_CH1_ENABLE
+ pwm_p_data.pwm_aligned_mode = pwm_edge_aligned; //边沿对齐
+ pwm_p_data.pwm_ch_num = pwm_ch1; //通道号
+ pwm_p_data.frequency = 1000; //1KHz
+ pwm_p_data.duty = 2500; //占空比25%
+ pwm_p_data.h_pin = IO_PORTA_08; //任意引脚
+ pwm_p_data.l_pin = IO_PORTA_09; //任意引脚,不需要就填-1
+ pwm_p_data.complementary_en = 1; //两个引脚的波形, 0: 同步, 1: 互补,互补波形的占空比体现在H引脚上
+ mcpwm_init(&pwm_p_data);
+#endif
+#if PWM_CH2_ENABLE
+ pwm_p_data.pwm_aligned_mode = pwm_edge_aligned; //边沿对齐
+ pwm_p_data.pwm_ch_num = pwm_ch2; //通道号
+ pwm_p_data.frequency = 10000; //10KHz
+ pwm_p_data.duty = 5000; //占空比50%
+ pwm_p_data.h_pin = IO_PORTA_03; //任意引脚
+ pwm_p_data.l_pin = -1; //任意引脚,不需要就填-1
+ mcpwm_init(&pwm_p_data);
+#endif
+#if PWM_CH3_ENABLE
+ pwm_p_data.pwm_aligned_mode = pwm_edge_aligned; //边沿对齐
+ pwm_p_data.pwm_ch_num = pwm_ch3; //通道号
+ pwm_p_data.frequency = 10000; //10KHz
+ pwm_p_data.duty = 7500; //占空比75%
+ pwm_p_data.h_pin = IO_PORTA_04; //任意引脚
+ pwm_p_data.l_pin = IO_PORTA_05; //任意引脚,不需要就填-1
+ pwm_p_data.complementary_en = 0; //两个引脚的波形, 0: 同步, 1: 互补,互补波形的占空比体现在H引脚上
+ mcpwm_init(&pwm_p_data);
+#endif
+
+ extern void clk_out(u8 gpio, enum CLK_OUT_SOURCE clk);
+ clk_out(IO_PORTA_07, LSB_CLK_OUT);
+ extern void wdt_clear();
+ while (1) {
+ wdt_clear();
+ }
+}
+
+
+
+/******************************* 外部引脚中断参考代码 ***************************/
+
+void (*io_isr_cbfun)(u8 index) = NULL;
+void set_io_ext_interrupt_cbfun(void (*cbfun)(u8 index))
+{
+ io_isr_cbfun = cbfun;
+}
+___interrupt
+void io_interrupt(void)
+{
+ u32 io_index = -1;
+ if (JL_MCPWM->CH0_CON1 & BIT(15)) {
+ JL_MCPWM->CH0_CON1 |= BIT(14);
+ io_index = 0;
+ } else if (JL_MCPWM->CH1_CON1 & BIT(15)) {
+ JL_MCPWM->CH1_CON1 |= BIT(14);
+ io_index = 1;
+ } else if (JL_MCPWM->CH2_CON1 & BIT(15)) {
+ JL_MCPWM->CH2_CON1 |= BIT(14);
+ io_index = 2;
+ } else if (JL_MCPWM->CH3_CON1 & BIT(15)) {
+ JL_MCPWM->CH3_CON1 |= BIT(14);
+ io_index = 3;
+ } else {
+ return;
+ }
+ if (io_isr_cbfun) {
+ io_isr_cbfun(io_index);
+ }
+}
+void io_ext_interrupt_init(u8 index, u8 port, u8 trigger_mode)
+{
+ if (port > IO_PORT_MAX) {
+ return;
+ }
+ gpio_set_die(port, 1);
+ gpio_set_direction(port, 1);
+ if (trigger_mode) {
+ gpio_set_pull_up(port, 1);
+ gpio_set_pull_down(port, 0);
+ JL_MCPWM->FPIN_CON &= ~BIT(16 + index);//下降沿触发
+ } else {
+ gpio_set_pull_up(port, 0);
+ gpio_set_pull_down(port, 1);
+ JL_MCPWM->FPIN_CON |= BIT(16 + index);//上升沿触发
+ }
+ JL_MCPWM->FPIN_CON |= BIT(8 + index);//开启滤波
+ JL_MCPWM->FPIN_CON |= (0b111111 << 0); //滤波时间 = 16 * 64 / hsb_clk (单位:s)
+
+ gpio_ich_sel_iutput_signal(port, INPUT_CH_SIGNAL_MC_FPIN0 + index, INPUT_CH_TYPE_GP_ICH);
+ request_irq(IRQ_MCPWM_CHX_IDX, 3, io_interrupt, 0); //注册中断函数
+ PWM_CH_REG *pwm_reg = get_pwm_ch_reg(index);
+ pwm_reg->ch_con1 = BIT(14) | BIT(11) | BIT(4) | (index << 0);
+ JL_MCPWM->MCPWM_CON0 |= BIT(index);
+
+ printf("JL_MCPWM->CH%d_CON1 = 0x%x\n", index, pwm_reg->ch_con1);
+ printf("JL_MCPWM->FPIN_CON = 0x%x\n", JL_MCPWM->FPIN_CON);
+ printf("JL_MCPWM->MCPWM_CON0 = 0x%x\n", JL_MCPWM->MCPWM_CON0);
+ printf("JL_IOMAP->ICH_CON0 = 0x%x\n", JL_IOMAP->ICH_CON0);
+ printf("JL_IOMAP->ICH_CON1 = 0x%x\n", JL_IOMAP->ICH_CON1);
+ printf("JL_IOMAP->ICH_CON2 = 0x%x\n", JL_IOMAP->ICH_CON2);
+ printf("JL_IOMAP->ICH_CON3 = 0x%x\n", JL_IOMAP->ICH_CON3);
+ printf("JL_IMAP->FI_GP_ICH0 = %d\n", JL_IMAP->FI_GP_ICH0);
+ printf("JL_IMAP->FI_GP_ICH1 = %d\n", JL_IMAP->FI_GP_ICH1);
+ printf("JL_IMAP->FI_GP_ICH2 = %d\n", JL_IMAP->FI_GP_ICH2);
+ printf("JL_IMAP->FI_GP_ICH3 = %d\n", JL_IMAP->FI_GP_ICH3);
+ printf("JL_IMAP->FI_GP_ICH4 = %d\n", JL_IMAP->FI_GP_ICH4);
+ printf("JL_IMAP->FI_GP_ICH5 = %d\n", JL_IMAP->FI_GP_ICH5);
+ printf("JL_IMAP->FI_GP_ICH6 = %d\n", JL_IMAP->FI_GP_ICH6);
+ printf("JL_IMAP->FI_GP_ICH7 = %d\n", JL_IMAP->FI_GP_ICH7);
+ printf("JL_IMAP->FI_GP_ICH8 = %d\n", JL_IMAP->FI_GP_ICH8);
+ printf("JL_IMAP->FI_GP_ICH9 = %d\n", JL_IMAP->FI_GP_ICH9);
+}
+void io_ext_interrupt_close(u8 index, u8 port)
+{
+ if (port > IO_PORT_MAX) {
+ return;
+ }
+ gpio_set_die(port, 0);
+ gpio_set_direction(port, 1);
+ gpio_set_pull_up(port, 0);
+ gpio_set_pull_down(port, 0);
+ gpio_ich_disable_iutput_signal(port, INPUT_CH_SIGNAL_MC_FPIN0 + index, INPUT_CH_TYPE_GP_ICH);
+ PWM_CH_REG *pwm_reg = get_pwm_ch_reg(index);
+ pwm_reg->ch_con1 = BIT(14);
+}
+
+///////////// 使用举例如下 //////////////////
+void my_io_isr_cbfun(u8 index)
+{
+ printf("io index --> %d Hello world !\n", index);
+}
+void io_ext_interrupt_test(void)
+{
+ set_io_ext_interrupt_cbfun(my_io_isr_cbfun);
+ io_ext_interrupt_init(0, IO_PORTA_04, 1);
+ io_ext_interrupt_init(1, IO_PORTB_01, 1);
+ io_ext_interrupt_init(2, IO_PORTC_02, 1);
+ io_ext_interrupt_init(3, IO_PORTG_01, 1);
+ extern void wdt_clear();
+ while (1) {
+ wdt_clear();
+ }
+}
+
+
+/******************************* 用timer做pwm的参考代码 ***************************/
+
+/**
+ * @param JL_TIMERx : JL_TIMER0/1/2/3
+ * @param pwm_io : JL_PORTA_01, JL_PORTB_02,,,等等,支持任意普通IO
+ * @param fre : 频率,单位Hz
+ * @param duty : 初始占空比,0~10000对应0~100%
+ */
+void timer_pwm_init(JL_TIMER_TypeDef *JL_TIMERx, u32 pwm_io, u32 fre, u32 duty)
+{
+ switch ((u32)JL_TIMERx) {
+ case (u32)JL_TIMER0 :
+ gpio_och_sel_output_signal(pwm_io, OUTPUT_CH_SIGNAL_TIMER0_PWM);
+ break;
+ case (u32)JL_TIMER1 :
+ gpio_och_sel_output_signal(pwm_io, OUTPUT_CH_SIGNAL_TIMER1_PWM);
+ break;
+ case (u32)JL_TIMER2 :
+ gpio_och_sel_output_signal(pwm_io, OUTPUT_CH_SIGNAL_TIMER2_PWM);
+ break;
+ case (u32)JL_TIMER3 :
+ bit_clr_ie(IRQ_TIME3_IDX);
+ gpio_och_sel_output_signal(pwm_io, OUTPUT_CH_SIGNAL_TIMER3_PWM);
+ break;
+ case (u32)JL_TIMER4 :
+ gpio_och_sel_output_signal(pwm_io, OUTPUT_CH_SIGNAL_TIMER4_PWM);
+ break;
+ case (u32)JL_TIMER5 :
+ gpio_och_sel_output_signal(pwm_io, OUTPUT_CH_SIGNAL_TIMER5_PWM);
+ break;
+ default:
+ return;
+ }
+ u32 u_clk = 24000000;
+ //初始化timer
+ JL_TIMERx->CON = 0;
+ JL_TIMERx->CON |= (0b110 << 10); //时钟源选择STD_24M时钟源
+ JL_TIMERx->CON |= (0b0001 << 4); //时钟源再4分频
+ JL_TIMERx->CNT = 0; //清计数值
+ JL_TIMERx->PRD = u_clk / (4 * fre); //设置周期
+ JL_TIMERx->PWM = (JL_TIMERx->PRD * duty) / 10000; //设置初始占空比,0~10000对应0~100%
+ JL_TIMERx->CON |= (0b01 << 0); //计数模式
+ JL_TIMERx->CON |= BIT(8); //PWM使能
+ //设置引脚状态
+ gpio_set_die(pwm_io, 1);
+ gpio_set_pull_up(pwm_io, 0);
+ gpio_set_pull_down(pwm_io, 0);
+ gpio_set_direction(pwm_io, 0);
+
+ printf("JL_TIMERx->PRD = 0x%x\n", JL_TIMERx->PRD);
+ printf("JL_TIMERx->CON = 0x%x\n", JL_TIMERx->CON);
+}
+
+void set_timer_pwm_duty(JL_TIMER_TypeDef *JL_TIMERx, u32 duty)
+{
+ JL_TIMERx->PWM = (JL_TIMERx->PRD * duty) / 10000; //0~10000对应0~100%
+}
+
+void timer_pwm_test(void)
+{
+ timer_pwm_init(JL_TIMER2, IO_PORTC_03, 10000, 7000);
+ timer_pwm_init(JL_TIMER3, IO_PORTG_04, 1000, 2000);
+ extern void wdt_clear();
+ while (1) {
+ wdt_clear();
+ }
+}
+
+
+
diff --git a/cpu/br28/mic_dut_process.c b/cpu/br28/mic_dut_process.c
new file mode 100644
index 0000000..10a6006
--- /dev/null
+++ b/cpu/br28/mic_dut_process.c
@@ -0,0 +1,538 @@
+
+#include "mic_dut_process.h"
+#include "audio_enc.h"
+#include "app_config.h"
+#include "audio_adc.h"
+#include "audio_config.h"
+#include "asm/dac.h"
+#include "audio_dvol.h"
+#include "application/eq_config.h"
+#include "audio_dec_eff.h"
+/* #include "sound_device.h" */
+
+#if ((defined TCFG_AUDIO_MIC_DUT_ENABLE) && TCFG_AUDIO_MIC_DUT_ENABLE)
+#include "online_debug/aud_mic_dut.h"
+
+/*移植代码时需要重新实现或者修改的函数或者变量
+ * AUDIO_ADC_CH
+ * int audio_mic_dut_info_get(mic_dut_info_t *info);
+ * int audio_mic_dut_dac_start(u32 sr, u16 vol);
+ * int audio_mic_dut_dac_stop(void);
+ * int audio_mic_dut_dac_write(s16 *data, int len);
+ * int audio_mic_en(u8 ,u16, u16, u16. u16, u16, void *);
+ * int audio_mic_dut_gain_set(u16 gain);
+ */
+
+
+/*mic数据输出开头丢掉的数据包数*/
+#define MIC_DUT_IN_DUMP_PACKET 10
+
+/*MIC上行eq*/
+#define MIC_DUT_EQ_ENABLE 1
+
+
+#define AUDIO_ADC_BUF_NUM 3 //mic_adc采样buf个数
+#define AUDIO_ADC_IRQ_POINTS 320 //mic_adc采样长度(单位:点数)
+#define AUDIO_ADC_CH 4 //双mic通话
+#define AUDIO_ADC_BUFS_SIZE (AUDIO_ADC_BUF_NUM * AUDIO_ADC_IRQ_POINTS * AUDIO_ADC_CH)
+struct audio_mic_hdl {
+ struct audio_adc_output_hdl adc_output;
+ struct adc_mic_ch mic_ch;
+ s16 adc_buf[AUDIO_ADC_BUFS_SIZE]; //align 2Bytes
+ s16 output_buf[AUDIO_ADC_BUFS_SIZE]; //数据输出缓存
+ cbuffer_t output_cbuf;
+ u16 dump_packet;
+ struct dec_eq_drc *mic_dut_eq;
+};
+static struct audio_mic_hdl *audio_mic = NULL;
+
+extern struct audio_adc_hdl adc_hdl;
+extern struct audio_dac_hdl dac_hdl;
+
+void *mic_dut_eq_open(u32 sample_rate, u8 ch_num)
+{
+#if TCFG_EQ_ENABLE
+
+ struct dec_eq_drc *eff = zalloc(sizeof(struct dec_eq_drc));
+ struct audio_eq_param eq_param = {0};
+
+ eq_param.channels = ch_num;
+ eq_param.online_en = 1;
+ eq_param.mode_en = 0;
+ eq_param.remain_en = 0;
+ eq_param.no_wait = 0;
+ eq_param.out_32bit = 0;
+ eq_param.max_nsection = EQ_SECTION_MAX;
+ eq_param.cb = eq_get_filter_info;
+ eq_param.eq_name = song_eq_mode;
+ eq_param.sr = sample_rate;
+ eff->eq = audio_dec_eq_open(&eq_param);
+ return eff;
+#else
+ return NULL;
+#endif//TCFG_EQ_ENABLE
+}
+
+void mic_dut_eq_run(struct dec_eq_drc *eq_drc, void *data, u32 len)
+{
+ struct dec_eq_drc *eff_hdl = (struct dec_eq_drc *)eq_drc;
+#if TCFG_EQ_ENABLE
+ if (eff_hdl->eq) {
+ audio_eq_run(eff_hdl->eq, data, len);
+ }
+#endif/*TCFG_EQ_ENABLE*/
+}
+
+void mic_dut_eq_close(struct dec_eq_drc *eq_drc)
+{
+#if TCFG_EQ_ENABLE
+ struct dec_eq_drc *eff_hdl = (struct dec_eq_drc *)eq_drc;
+ /* struct audio_eq_drc *eff_hdl = (struct audio_eq_drc *)eq_drc; */
+ if (eff_hdl->eq) {
+ audio_dec_eq_close(eff_hdl->eq);
+ eff_hdl->eq = NULL;
+ }
+ free(eff_hdl);
+#endif /*TCFG_EQ_ENABLE*/
+}
+
+/*获取麦克风测试硬件数据*/
+int audio_mic_dut_info_get(mic_dut_info_t *info)
+{
+ mic_dut_info_t mic_info = {
+ .version = 0x01,
+#if (AUDIO_ADC_CH > 2)
+ .amic_enable_bit = BIT(0) | BIT(1) | BIT(2) | BIT(3),
+#elif (AUDIO_ADC_CH > 1)
+ .amic_enable_bit = BIT(0) | BIT(1),
+#else /*AUDIO_ADC_CH == 1*/
+ .amic_enable_bit = BIT(0),
+#endif /*AUDIO_ADC_CH*/
+ .dmic_enable_bit = 0x00,
+ .channel = 1,
+ .bit_wide = 16,
+ .sr_enable_bit = MIC_ADC_SR_8000 | MIC_ADC_SR_16000 | MIC_ADC_SR_32000,
+ .sr_default = 16000,
+ .mic_gain = 19,
+ .mic_gain_default = 10,
+ .dac_gain = 15,
+ .dac_gain_default = 2,
+ };
+
+ memcpy(info, &mic_info, sizeof(mic_dut_info_t));
+ return 0;
+}
+
+/* struct audio_dac_channel mic_dut_dac_ch; */
+/*打开dac*/
+int audio_mic_dut_dac_start(u32 sr, u16 vol)
+{
+ printf("dac sr: , vol: %d\n", sr, vol);
+ app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
+ app_audio_set_volume(APP_AUDIO_STATE_MUSIC, vol, 0);
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_open(MUSIC_DVOL, app_audio_get_volume(APP_AUDIO_STATE_MUSIC), MUSIC_DVOL_MAX, MUSIC_DVOL_FS, -1);
+#endif /*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+#if 0
+ // DAC 初始化
+ audio_dac_new_channel(&dac_hdl, &mic_dut_dac_ch);
+ struct audio_dac_channel_attr attr;
+ attr.delay_time = 20;
+ attr.protect_time = 8;
+ attr.write_mode = WRITE_MODE_BLOCK;
+ audio_dac_channel_set_attr(&mic_dut_dac_ch, &attr);
+ sound_pcm_dev_start(&mic_dut_dac_ch, sr, app_audio_get_volume(APP_AUDIO_STATE_MUSIC));
+#else
+ audio_dac_set_volume(&dac_hdl, vol);
+ audio_dac_set_sample_rate(&dac_hdl, sr);
+ audio_dac_start(&dac_hdl);
+#endif
+ return 0;
+}
+
+/*关闭dac*/
+int audio_mic_dut_dac_stop(void)
+{
+#if 0
+ sound_pcm_dev_stop(&mic_dut_dac_ch);
+#else
+ audio_dac_stop(&dac_hdl);
+#endif
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_close(MUSIC_DVOL);
+#endif /*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+ return 0;
+}
+
+/*写数到dac*/
+#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
+s16 mic_dut_mono_to_dual[AUDIO_ADC_IRQ_POINTS * 2 + 4];
+#endif/*TCFG_AUDIO_DAC_CONNECT_MODE*/
+int audio_mic_dut_dac_write(s16 *data, int len)
+{
+ s16 *dac_data = data;
+ u16 data_len = len;
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_run(MUSIC_DVOL, dac_data, len);
+#endif /*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
+ for (u16 i = 0; i < (len >> 1); i++) {
+ mic_dut_mono_to_dual[2 * i] = dac_data[i];
+ mic_dut_mono_to_dual[2 * i + 1] = dac_data[i];
+ }
+ dac_data = mic_dut_mono_to_dual;
+ data_len = len + data_len;
+#endif/*TCFG_AUDIO_DAC_CONNECT_MODE*/
+
+#if 0
+ int wlen = 0;
+ int offset = 0;
+ int cnt = 0;
+ do {
+ wlen = sound_pcm_dev_write(&mic_dut_dac_ch, dac_data + (offset >> 1), data_len - offset);
+ offset = offset + wlen;
+ cnt ++;
+ } while ((offset != data_len) && (cnt < 1000));
+
+ return offset;
+#else
+ return audio_dac_write(&dac_hdl, dac_data, data_len);
+#endif
+}
+
+/*
+*********************************************************************
+* AUDIO ADC MIC OPEN
+* Description: 打开mic通道
+* Arguments : mic_ch mic通道 LADC_CH_MIC_R/LADC_CH_MIC_L/AUDIO_ADC_MIC_0/AUDIO_ADC_MIC_1/AUDIO_ADC_MIC_2/AUDIO_ADC_MIC_3
+* sr mic采样率 8000/16000/32000/44100/48000
+* gain0 mic0增益
+* gain1 mic0增益
+* gain2 mic0增益
+* gain3 mic0增益
+* Return : None.
+* Note(s) : (1)打开一个mic通道示例:
+* audio_mic_en(LADC_CH_MIC_L,16000,10,0,0,0);
+* 或者
+* audio_mic_en(LADC_CH_MIC_R,16000,10,0,0,0);
+* (2)打开两个mic通道示例:
+* audio_mic_en(LADC_CH_MIC_R|LADC_CH_MIC_L,16000,10,10,0,0);
+*********************************************************************
+*/
+int audio_mic_en(u8 mic_ch, u16 sr,
+ u16 gain0, u16 gain1, u16 gain2, u16 gain3,
+ void (*data_handler)(void *priv, s16 *data, int len))
+{
+ printf("mic ch : %d\n\n", mic_ch);
+ if (mic_ch) {
+ if (audio_mic) {
+ printf("audio_mic re-malloc error\n");
+ return -1;
+ }
+ audio_mic = zalloc(sizeof(struct audio_mic_hdl));
+ if (audio_mic == NULL) {
+ printf("audio mic zalloc failed\n");
+ return -1;
+ }
+
+#if MIC_DUT_EQ_ENABLE
+ audio_mic->mic_dut_eq = mic_dut_eq_open(sr, 1);
+#endif /*MIC_DUT_EQ_ENABLE*/
+
+ cbuf_init(&audio_mic->output_cbuf, audio_mic->output_buf, sizeof(audio_mic->output_buf));
+ cbuf_clear(&audio_mic->output_cbuf);
+
+ /*打开mic电压*/
+ audio_mic_pwr_ctl(MIC_PWR_ON);
+ /*打开mic0*/
+ if (mic_ch & BIT(0)) {
+ printf("adc_mic0 open, sr:%d, gain:%d\n", sr, gain0);
+ audio_adc_mic_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
+ audio_adc_mic_set_gain(&audio_mic->mic_ch, gain0);
+ }
+ /*打开mic1*/
+ if (mic_ch & BIT(1)) {
+ printf("adc_mic1 open, sr:%d, gain:%d\n", sr, gain1);
+ audio_adc_mic1_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
+ audio_adc_mic1_set_gain(&audio_mic->mic_ch, gain1);
+ }
+#if (AUDIO_ADC_CH > 2)
+ /*打开mic2*/
+ if (mic_ch & BIT(2)) {
+ printf("adc_mic2 open, sr:%d, gain:%d\n", sr, gain2);
+ audio_adc_mic2_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
+ audio_adc_mic2_set_gain(&audio_mic->mic_ch, gain2);
+ }
+ /*打开mic3*/
+ if (mic_ch & BIT(3)) {
+ printf("adc_mic3 open, sr:%d, gain:%d\n", sr, gain3);
+ audio_adc_mic3_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
+ audio_adc_mic3_set_gain(&audio_mic->mic_ch, gain3);
+ }
+#endif /*AUDIO_ADC_CH*/
+ audio_adc_mic_set_sample_rate(&audio_mic->mic_ch, sr);
+ audio_adc_mic_set_buffs(&audio_mic->mic_ch, audio_mic->adc_buf,
+ AUDIO_ADC_IRQ_POINTS * 2, AUDIO_ADC_BUF_NUM);
+ audio_mic->adc_output.handler = data_handler;
+ audio_adc_add_output_handler(&adc_hdl, &audio_mic->adc_output);
+ audio_adc_mic_start(&audio_mic->mic_ch);
+ /*清掉mic开头几包数据*/
+ audio_mic->dump_packet = MIC_DUT_IN_DUMP_PACKET;
+ } else {
+ if (audio_mic) {
+ audio_adc_mic_close(&audio_mic->mic_ch);
+ audio_adc_del_output_handler(&adc_hdl, &audio_mic->adc_output);
+ audio_mic_pwr_ctl(MIC_PWR_OFF);
+
+#if MIC_DUT_EQ_ENABLE
+ mic_dut_eq_close(audio_mic->mic_dut_eq);
+#endif /*MIC_DUT_EQ_ENABLE*/
+
+ free(audio_mic);
+ audio_mic = NULL;
+ }
+ }
+ return 0;
+}
+
+/*设置mic增益*/
+int audio_mic_dut_gain_set(u16 gain)
+{
+ if (audio_mic) {
+ audio_adc_mic_set_gain(&audio_mic->mic_ch, gain);
+ audio_adc_mic1_set_gain(&audio_mic->mic_ch, gain);
+#if (AUDIO_ADC_CH > 2)
+ audio_adc_mic2_set_gain(&audio_mic->mic_ch, gain);
+ audio_adc_mic3_set_gain(&audio_mic->mic_ch, gain);
+#endif /*AUDIO_ADC_CH*/
+ }
+ return 0;
+}
+
+/*
+*********************************************************************
+* Comfort Noise Generator
+* Description: 舒适噪声生成
+* Arguments : state 伪随机数生成状态
+* gain 舒适噪声的增益
+* data 待添加舒适噪声的数据
+* npoint 待添加舒适噪声的数据长度
+* Return : None.
+* Note(s) : 增益计算公式:gain cal(python):
+* >>>import math
+* >>>gain=math.pow(10,gain_db/20.)*2**20;
+* >>>print(gain)
+*********************************************************************
+*/
+//int wn_gain = 1865; /*Normal*/
+//int wn_gain = 1<<19;
+//
+static unsigned int next = 457;
+void set_srand(unsigned int seek)
+{
+ next = seek;
+}
+
+static int my_rand()
+{
+ next = next * 1103515245 + 12345;
+ return next >> 16;
+}
+#define COMFORT_NOISE_SEED 457
+static unsigned int seed = COMFORT_NOISE_SEED;
+void set_comfort_noise_seed(unsigned int sd)
+{
+ seed = sd;
+ set_srand(sd);
+}
+static void comfort_noise_run(unsigned int *state, int gain, short *data, int npoint)
+{
+ for (int i = 0; i < npoint; i++) {
+#if 0
+ *state = (*state * 1103515245 + 12345) & 0x7fffffff;
+ int tmp32 = (*state >> 15) - (1 << 15);
+ tmp32 = (long long)tmp32 * gain >> 20;
+ tmp32 += data[i];
+ if (tmp32 > 32767) {
+ tmp32 = 32767;
+ }
+ if (tmp32 < -32768) {
+ tmp32 = -32768;
+ }
+ data[i] = tmp32;
+#else
+ short tmp16 = (short)my_rand();
+ int tmp32 = ((long long)tmp16 * gain) >> 20;
+ if (tmp32 > 32767) {
+ tmp32 = 32767;
+ }
+ if (tmp32 < -32768) {
+ tmp32 = -32768;
+ }
+ data[i] = (short)tmp32;
+#endif
+ }
+}
+
+/*
+*********************************************************************
+* AUDIO MIC OUTPUT
+* Description: mic采样数据回调
+* Arguments : pric 私有参数
+* data mic数据
+* len 数据长度
+* Return : 0 成功 其他 失败
+* Note(s) : 单声道数据格式
+* L0 L1 L2 L3 L4 ...
+* 双声道数据格式()
+* L0 R0 L1 R1 L2 R2...
+*********************************************************************
+*/
+void audio_mic_dut_eq_run(s16 *data, int len)
+{
+ u8 scan_start = mic_dut_online_get_scan_state();
+#if MIC_DUT_EQ_ENABLE
+ if (scan_start && audio_mic) {
+ mic_dut_eq_run(audio_mic->mic_dut_eq, data, len);
+ }
+#endif /*MIC_DUT_EQ_ENABLE*/
+}
+
+static void audio_mic_dut_output_handle(void *priv, s16 *data, int len)
+{
+ if (audio_mic) {
+ s16 *mic_data = data;
+ int wlen = 0;
+ u8 mic_idx = mic_dut_online_get_mic_idx();
+ u8 mic_start = mic_dut_online_get_mic_state();
+ u8 scan_start = mic_dut_online_get_scan_state();
+ /* printf("mic_data:%x,%d\n",data,len); */
+ for (u16 i = 0; i < (len >> 1); i++) {
+ mic_data[i] = data[i * AUDIO_ADC_CH + mic_idx];
+ }
+ /*清掉开头10包数据*/
+ if (audio_mic->dump_packet) {
+ audio_mic->dump_packet --;
+ }
+ if ((mic_start || scan_start) && !audio_mic->dump_packet) {
+#if MIC_DUT_EQ_ENABLE
+ /* if(scan_start) { */
+ /* mic_dut_eq_run(audio_mic->mic_dut_eq, mic_data, len); */
+ /* } */
+#endif /*MIC_DUT_EQ_ENABLE*/
+ wlen = cbuf_write(&audio_mic->output_cbuf, mic_data, len);
+ if (wlen != len) {
+ printf("dut out buf full !!!\n");
+ }
+ }
+ /*dac播放白噪*/
+ if (scan_start && !audio_mic->dump_packet) {
+ s16 tmpbuf[AUDIO_ADC_IRQ_POINTS];
+ comfort_noise_run(&seed, 1048576, tmpbuf, len / 2);
+ wlen = audio_mic_dut_dac_write(tmpbuf, len);
+ if (wlen != len) {
+ printf("dut scan dac write fail !!!\n");
+ }
+ }
+ mic_dut_online_sem_post();
+ }
+}
+
+int audio_mic_dut_sample_rate_set(u32 sr)
+{
+
+ return 0;
+}
+
+int audio_mic_dut_amic_select(u8 idx)
+{
+
+ return 0;
+}
+
+int audio_mic_dut_dmic_select(u8 idx)
+{
+
+ return 0;
+}
+
+/*打开mic*/
+int audio_mic_dut_start(void)
+{
+ u8 amic_enable_bit = mic_dut_online_amic_enable_bit();
+ u16 gain = mic_dut_online_get_mic_gain();
+ u32 sr = mic_dut_online_get_sample_rate();
+ /*打开所有MIC*/
+ audio_mic_en(amic_enable_bit,
+ sr,
+ gain,
+ gain,
+ gain,
+ gain,
+ audio_mic_dut_output_handle);
+
+ return 0;
+}
+
+/*关闭mic*/
+int audio_mic_dut_stop(void)
+{
+ /*关闭所有MIC*/
+ audio_mic_en(0, 0,
+ 0, 0, 0, 0,
+ NULL);
+ return 0;
+}
+
+/*获取mic数据*/
+int audio_mic_dut_data_get(s16 *data, int len)
+{
+ /*获取对应的MIC数据,并返回获取到的数据大小*/
+ int rlen = 0;
+ if (audio_mic) {
+ rlen = cbuf_read(&audio_mic->output_cbuf, data, len);
+ }
+ return rlen;
+}
+
+/*获取mic缓存数据长度*/
+int audio_mic_dut_get_data_len(void)
+{
+ return cbuf_get_data_len(&audio_mic->output_cbuf);
+}
+
+/*设置dac输出音量*/
+int audio_mic_dut_dac_gain_set(u16 gain)
+{
+ app_audio_set_volume(APP_AUDIO_STATE_MUSIC, gain, 0);
+ return 0;
+}
+
+/*开始mic频响扫描*/
+int audio_mic_dut_scan_start(void)
+{
+ u32 sr = mic_dut_online_get_sample_rate();
+ u16 vol = mic_dut_online_get_dac_gain();
+ /*重置随机白噪声种子*/
+ set_comfort_noise_seed(COMFORT_NOISE_SEED);
+ // 打开DAC
+ audio_mic_dut_dac_start(sr, vol);
+ // 打开mic
+ audio_mic_dut_start();
+
+ return 0;
+}
+
+/*关闭mic频响扫描*/
+int audio_mic_dut_scan_stop(void)
+{
+ //关闭mic
+ audio_mic_dut_stop();
+ // DAC 关闭
+ audio_mic_dut_dac_stop();
+ return 0;
+}
+#endif /*((defined TCFG_AUDIO_MIC_DUT_ENABLE) && TCFG_AUDIO_MIC_DUT_ENABLE)*/
diff --git a/cpu/br28/mic_dut_process.h b/cpu/br28/mic_dut_process.h
new file mode 100644
index 0000000..0ff8be0
--- /dev/null
+++ b/cpu/br28/mic_dut_process.h
@@ -0,0 +1,40 @@
+#ifndef _MIC_DUT_PROCESS_H_
+#define _MIC_DUT_PROCESS_H_
+
+#include "generic/typedef.h"
+#if 0
+#include "online_debug/aud_mic_dut.h"
+
+/*获取麦克风测试硬件数据*/
+int audio_mic_dut_info_get(mic_dut_info_t *info);
+
+/*设置mic增益*/
+int audio_mic_dut_gain_set(u16 gain);
+
+/*打开mic*/
+int audio_mic_dut_start(void);
+
+/*关闭mic*/
+int audio_mic_dut_stop(void);
+
+/*获取mic数据*/
+int audio_mic_dut_data_get(s16 *data, int len);
+
+/*获取mic缓存数据长度*/
+int audio_mic_dut_get_data_len(void);
+
+int audio_mic_dut_sample_rate_set(u32 sr);
+int audio_mic_dut_amic_select(u8 idx);
+int audio_mic_dut_dmic_select(u8 idx);
+
+/*设置dac输出音量*/
+int audio_mic_dut_dac_gain_set(u16 gain);
+
+/*开始mic频响扫描*/
+int audio_mic_dut_scan_start(void);
+
+/*关闭mic频响扫描*/
+int audio_mic_dut_scan_stop(void);
+#endif // 0
+#endif /*_MIC_DUT_PROCESS_H_*/
+
diff --git a/cpu/br28/overlay_code.c b/cpu/br28/overlay_code.c
new file mode 100644
index 0000000..01d0f95
--- /dev/null
+++ b/cpu/br28/overlay_code.c
@@ -0,0 +1,58 @@
+#include "asm/includes.h"
+#include "media/includes.h"
+#include "overlay_code.h"
+
+
+struct code_type {
+ u32 type;
+ u32 dst;
+ u32 src;
+ u32 size;
+};
+
+extern int aec_addr, aec_begin, aec_size;
+extern int aac_addr, aac_begin, aac_size;
+
+
+const struct code_type ctype[] = {
+ {OVERLAY_AEC, (u32) &aec_addr, (u32) &aec_begin, (u32) &aec_size},
+ {OVERLAY_M4A, (u32) &aac_addr, (u32) &aac_begin, (u32) &aac_size },
+};
+
+struct audio_overlay_type {
+ u32 atype;
+ u32 otype;
+};
+
+const struct audio_overlay_type aotype[] = {
+
+ {AUDIO_CODING_MSBC, OVERLAY_AEC },
+ {AUDIO_CODING_CVSD, OVERLAY_AEC },
+ /* {AUDIO_CODING_M4A, OVERLAY_M4A }, */
+ /* {AUDIO_CODING_ALAC, OVERLAY_M4A }, */
+ {AUDIO_CODING_AAC, OVERLAY_M4A },
+};
+
+
+void overlay_load_code(u32 type)
+{
+ int i = 0;
+ for (i = 0; i < ARRAY_SIZE(ctype); i++) {
+ if (type == ctype[i].type) {
+ if (ctype[i].dst != 0) {
+ memcpy((void *)ctype[i].dst, (void *)ctype[i].src, (int)ctype[i].size);
+ }
+ break;
+ }
+ }
+}
+
+void audio_overlay_load_code(u32 type)
+{
+ int i = 0;
+ for (i = 0; i < ARRAY_SIZE(aotype); i++) {
+ if (type == aotype[i].atype) {
+ overlay_load_code(aotype[i].otype);
+ }
+ }
+}
diff --git a/cpu/br28/overlay_code.h b/cpu/br28/overlay_code.h
new file mode 100644
index 0000000..31a5701
--- /dev/null
+++ b/cpu/br28/overlay_code.h
@@ -0,0 +1,30 @@
+
+#ifndef _OVERLAY_CODE_H_
+#define _OVERLAY_CODE_H_
+
+#include "typedef.h"
+
+enum {
+ OVERLAY_AEC = 0,
+ OVERLAY_WAV,
+ OVERLAY_APE,
+ OVERLAY_FLAC,
+ OVERLAY_M4A,
+ OVERLAY_AMR,
+ OVERLAY_DTS,
+ OVERLAY_FM,
+
+#ifdef CONFIG_MP3_WMA_LIB_SPECIAL
+ OVERLAY_MP3,
+ OVERLAY_WMA,
+#endif
+ OVERLAY_LC3,
+
+};
+
+void overlay_load_code(u32 type);
+void audio_overlay_load_code(u32 type);
+int audio_cvp_code_load(void);
+
+#endif
+
diff --git a/cpu/br28/pdm_link.c b/cpu/br28/pdm_link.c
new file mode 100644
index 0000000..9a28732
--- /dev/null
+++ b/cpu/br28/pdm_link.c
@@ -0,0 +1,246 @@
+#include "includes.h"
+#include "asm/includes.h"
+#include "asm/gpio.h"
+#include "asm/dac.h"
+#include "media/includes.h"
+#include "pdm_link.h"
+
+#define PLNK_DEBUG_ENABLE
+#ifdef PLNK_DEBUG_ENABLE
+//#define PLNK_LOG(fmt, ...) printf("[PLNK] "fmt, ##__VA_ARGS__)
+#define PLNK_LOG y_printf
+#else
+#define PLNK_LOG(...)
+#endif
+
+
+#define PLNK_TEST_ENABLE 0
+
+
+static audio_plnk_t *pdm_hdl = NULL;
+___interrupt
+static void audio_plnk_isr(void)
+{
+ JL_PORTA->OUT ^= BIT(12);
+ u8 buf_flag;
+ s16 *buf = pdm_hdl->buf;
+ u16 len = pdm_hdl->buf_len;
+ s16 *data_buf;
+ if (JL_PLNK->CON & BIT(15)) {
+ PLNK_PND_CLR();
+ if (JL_PLNK->CON & BIT(9)) {
+ buf_flag = 0; //buf0 available
+ } else {
+ buf_flag = 1; //buf1 available
+ }
+ data_buf = (s16 *)buf;
+ data_buf += buf_flag * len;
+ }
+ if (pdm_hdl && pdm_hdl->output) {
+ pdm_hdl->output(data_buf, len);
+ }
+}
+
+static void plnk_info_dump()
+{
+ PLNK_LOG("PLNK_CON = 0x%x", JL_PLNK->CON);
+ PLNK_LOG("CLK_CON = 0x%x", JL_CLOCK->CLK_CON0);
+ PLNK_LOG("PLNK_CON1 = 0x%x", JL_PLNK->CON1);
+ PLNK_LOG("PLNK_LEN = 0x%x", JL_PLNK->LEN);
+ PLNK_LOG("PLNK_ADR = 0x%x", JL_PLNK->ADR);
+ PLNK_LOG("PLNK_SMR = %d", JL_PLNK->SMR);
+ PLNK_LOG("PLNK_DOR = %d", JL_PLNK->DOR);
+}
+
+static void audio_plnk_sr_set(u16 sr)
+{
+ PLNK_LOG("PLNK_SR = %d\n", sr);
+ JL_PLNK->DOR = PLNK_SCLK / sr - 1;
+ u8 div = PLNK_CLK / PLNK_SCLK - 1;
+ SFR(JL_ASS->CLK_CON, 2, 5, div);
+}
+
+static void audio_plnk_sclk_io_init(u8 port)
+{
+ r_printf("port === %d\n", port);
+ gpio_set_fun_output_port(port, FO_PLNK_SCLK, 0, 1, LOW_POWER_FREE);
+ gpio_set_direction(port, 0);
+ gpio_set_die(port, 0);
+ gpio_direction_output(port, 1);
+}
+
+
+static void audio_plnk_ch_io_init(u8 ch_index, u8 port)
+{
+ gpio_set_pull_down(port, 0);
+ gpio_set_pull_up(port, 1);
+ gpio_set_direction(port, 1);
+ gpio_set_die(port, 1);
+ if (ch_index) {
+ gpio_set_fun_input_port(port, PFI_PLNK_DAT1, LOW_POWER_FREE);
+ } else {
+ gpio_set_fun_input_port(port, PFI_PLNK_DAT0, LOW_POWER_FREE);
+ }
+}
+
+
+int audio_plnk_open(audio_plnk_t *hdl)
+{
+ if (hdl == NULL) {
+ return -EINVAL;
+ }
+
+ pdm_hdl = hdl;
+ PLNK_LOG("audio_plnk_open,ch=%d,sr=%d", pdm_hdl->ch_num, pdm_hdl->sr);
+ PLNK_CON_RESET();
+ JL_PLNK->ADR = (u32)pdm_hdl->buf;
+ JL_PLNK->LEN = pdm_hdl->buf_len;
+ /*
+ *PLNK_CLK -> SMR -> SCLK -> DOR ->SR
+ *1MHz <= SCLK <= 4MHz
+ *sclk = PLINK_CLK / (SMR + 1)
+ *5 <= SMR <= 47
+ *PLNK_DOR
+ *Version(A/B):0~4096
+ *Version(C):1~2048
+ */
+ SFR(JL_PLNK->CON, 1, 1, 0); //DFDLY1_SEL(0:M=1 1:M=2)
+ SFR(JL_PLNK->CON, 5, 1, 0); //DFDLY1_SEL(0:M=1 1:M=2)
+ audio_plnk_sr_set(pdm_hdl->sr);
+ audio_plnk_sclk_io_init(pdm_hdl->sclk_io);
+ audio_plnk_ch_io_init(0, pdm_hdl->ch0_io);
+ /* audio_plnk_ch_io_init(1, pdm_hdl->ch1_io); */
+ SFR(JL_PLNK->CON1, 26, 1, 0); //DFDLY1_SEL(0:M=1 1:M=2)
+ SFR(JL_PLNK->CON1, 10, 1, 0); //DFDLY0_SEL(0:M=1 1:M=2)
+
+ SFR(JL_PLNK->CON1, 19, 5, 10); //SHIFT1_SEL[23:19]
+ SFR(JL_PLNK->CON1, 3, 5, 10); //SHIFT0_SEL[7:3]
+
+ SFR(JL_PLNK->CON1, 16, 3, 3); //SCALE1_SEL
+ SFR(JL_PLNK->CON1, 0, 3, 3); //SCALE0_SEL
+
+ SFR(JL_PLNK->CON1, 24, 2, 0); //ORDER1_SEL
+ SFR(JL_PLNK->CON1, 8, 2, 0); //ORDER0_SEL
+
+ SFR(JL_PLNK->CON1, 27, 1, 0); //SHDIR1_SEL
+ SFR(JL_PLNK->CON1, 11, 1, 0); //SHDIR0_SEL
+
+ SFR(JL_PLNK->CON1, 28, 2, 0);
+ SFR(JL_PLNK->CON1, 12, 2, 0);
+
+ SFR(JL_PLNK->CON1, 30, 1, 0); //CIC1_EN
+ SFR(JL_PLNK->CON1, 14, 1, 0); //CIC0_EN
+
+
+ if (PLNK_CH_EN == PLNK_CH0_EN) {
+ PLNK_CH0_MD_SET(pdm_hdl->ch0_mode);
+ } else if (PLNK_CH_EN == PLNK_CH1_EN) {
+ PLNK_CH1_MD_SET(pdm_hdl->ch1_mode);
+ } else {
+ PLNK_CH0_MD_SET(pdm_hdl->ch0_mode);
+ PLNK_CH1_MD_SET(pdm_hdl->ch1_mode);
+ }
+ PLNK_PND_CLR();
+ request_irq(IRQ_PDM_LINK_IDX, 1, audio_plnk_isr, 0);
+ return 0;
+}
+
+int audio_plnk_start(audio_plnk_t *hdl)
+{
+ JL_PLNK->CON |= BIT(8); //IE
+ if (hdl->ch_num == 1) {
+ SFR(JL_PLNK->CON, 0, 1, 1); //CH0EN
+ SFR(JL_PLNK->CON, 4, 1, 0); //CH1 DIS
+ } else {
+ SFR(JL_PLNK->CON, 0, 1, 1); //CH0EN
+ SFR(JL_PLNK->CON, 4, 1, 1); //CH1EN
+ }
+ plnk_info_dump();
+ return 0;
+}
+
+int audio_plnk_close(void)
+{
+ JL_PLNK->CON = 0;
+ pdm_hdl = NULL;
+ return 0;
+}
+
+#if PLNK_TEST_ENABLE
+
+extern struct audio_dac_hdl dac_hdl;
+
+static short const sin0_16k[16] = {
+ 0x0000, 0x30fd, 0x5a83, 0x7641, 0x7fff, 0x7642, 0x5a82, 0x30fc, 0x0000, 0xcf04, 0xa57d, 0x89be, 0x8000, 0x89be, 0xa57e, 0xcf05,
+};
+
+static u16 tx1_s_cnt = 0;
+static int get_sine0_data(u16 *s_cnt, s16 *data, u16 points, u8 ch)
+{
+ while (points--) {
+ if (*s_cnt >= 16) {
+ *s_cnt = 0;
+ }
+ *data++ = sin0_16k[*s_cnt];
+ if (ch == 2) {
+ *data++ = sin0_16k[*s_cnt];
+ }
+ (*s_cnt)++;
+ }
+ return 0;
+}
+
+static void handle_output(void *buf, u16 len)
+{
+ /* get_sine0_data(&tx1_s_cnt, buf, 256, 1); */
+ s16 *paddr = (s16 *)buf;
+ u32 len0 = 256 * 2;
+ u32 rlen = 256 * 2;
+ while (len0) {
+ rlen = audio_dac_write(&dac_hdl, paddr, len0);
+ /* printf("rlen = %d\n", rlen); */
+ if (rlen != len0) {
+ printf("rlen = %d, len0 = %d\n", rlen, len0);
+ }
+ len0 -= rlen;
+ paddr += rlen / 2;
+ if (rlen == 0) {
+ }
+ }
+}
+
+audio_plnk_t test_plink = {
+ .sclk_io = IO_PORTA_04,
+ .ch_num = 1,
+ .ch0_io = IO_PORTA_03,
+ .ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE,
+ .sr = 16000,
+ .buf_len = 256,
+};
+
+void audio_plnk_test(void)
+{
+ y_printf("pdm link demo\n");
+
+ test_plink.output = handle_output;
+ test_plink.buf = zalloc(test_plink.buf_len * test_plink.ch_num * 2 * 2);
+ ASSERT(test_plink.buf);
+ /* JL_WL_AUD->CON0 |= BIT(0); */
+
+ audio_plnk_open(&test_plink);
+ audio_plnk_start(&test_plink);
+
+#if 1
+ extern void app_audio_state_switch(u8 state, s16 max_volume);
+ app_audio_state_switch(1, 16);
+ audio_dac_set_volume(&dac_hdl, 16);
+ audio_dac_set_sample_rate(&dac_hdl, 16000);
+ audio_dac_start(&dac_hdl);
+ SFR(JL_ASS->CLK_CON, 0, 2, 3);
+#endif
+
+ while (1);
+
+}
+
+#endif
diff --git a/cpu/br28/plcnt.c b/cpu/br28/plcnt.c
new file mode 100644
index 0000000..9dcc53f
--- /dev/null
+++ b/cpu/br28/plcnt.c
@@ -0,0 +1,237 @@
+#include "includes.h"
+#include "asm/plcnt.h"
+#include "asm/gpio.h"
+
+
+static u8 port_index_mapping_talbe[PLCNT_KEY_CH_MAX] = {0};
+static u32 touch_pre_value[PLCNT_KEY_CH_MAX] = {0};
+static u32 touch_normal_value[PLCNT_KEY_CH_MAX] = {0};
+
+#define TOUCH_VAL_CALIBRATE_CYCLE (200)//周期大约2秒
+static u32 touch_calibrate_cnt[PLCNT_KEY_CH_MAX] = {0};
+static u32 touch_calibrate_tmp_value[PLCNT_KEY_CH_MAX] = {0};
+
+static u8 touch_state = 0;
+
+
+static const struct touch_key_platform_data *user_data = NULL;
+
+static JL_PORT_FLASH_TypeDef *PLCNT_IO_PORTx = NULL;
+static u8 PLCNT_IO_xx;
+
+void plcnt_io_out(struct touch_key_port *key)
+{
+ if (key->port > IO_MAX_NUM) {
+ return;
+ } else if ((key->port / 16) == 0) {
+ PLCNT_IO_PORTx = JL_PORTA;
+ } else if ((key->port / 16) == 1) {
+ PLCNT_IO_PORTx = JL_PORTB;
+ }
+ PLCNT_IO_xx = key->port % 16;
+ PLCNT_IO_PORTx->DIE |= BIT(PLCNT_IO_xx);
+ PLCNT_IO_PORTx->PU &= ~BIT(PLCNT_IO_xx);
+ PLCNT_IO_PORTx->PD |= BIT(PLCNT_IO_xx);
+ PLCNT_IO_PORTx->OUT |= BIT(PLCNT_IO_xx);
+ PLCNT_IO_PORTx->DIR &= ~BIT(PLCNT_IO_xx);
+}
+
+void plcnt_io_in(struct touch_key_port *key)
+{
+ if (key->port > IO_MAX_NUM) {
+ return;
+ } else if ((key->port / 16) == 0) {
+ PLCNT_IO_PORTx = JL_PORTA;
+ } else if ((key->port / 16) == 1) {
+ PLCNT_IO_PORTx = JL_PORTB;
+ }
+ PLCNT_IO_xx = key->port % 16;
+ PLCNT_IO_PORTx->DIE |= BIT(PLCNT_IO_xx);
+ PLCNT_IO_PORTx->PU &= ~BIT(PLCNT_IO_xx);
+ PLCNT_IO_PORTx->PD |= BIT(PLCNT_IO_xx);
+ PLCNT_IO_PORTx->OUT |= BIT(PLCNT_IO_xx);
+ PLCNT_IO_PORTx->DIR |= BIT(PLCNT_IO_xx);
+}
+
+void plcnt_iomc(struct touch_key_port *key)
+{
+ //放电计数引脚选择intputchannel2
+ gpio_ich_sel_iutput_signal(key->port, INPUT_CH_SIGNAL_CAP, INPUT_CH_TYPE_GP_ICH);
+ /*gpio_set_fun_input_port(key->port, PFI_GP_ICH6);*/
+ /*SFR(JL_IOMAP->CON1, 8, 4, 6);*/
+}
+
+static u32 key_or = 0;
+void plcnt_flt(u32 cur_val, u32 ch)
+{
+ /* printf("ch%d : %d\n", ch, cur_val); */
+ //简单滤波
+ if (touch_pre_value[ch] == 0) {
+ touch_pre_value[ch] = cur_val;
+ } else if (cur_val >= touch_pre_value[ch]) {
+ touch_pre_value[ch] = touch_pre_value[ch] + (u32)((cur_val - touch_pre_value[ch]) * 0.2f);
+ } else {
+ touch_pre_value[ch] = touch_pre_value[ch] - (u32)((touch_pre_value[ch] - cur_val) * 0.2f);
+ }
+ //处理滤波之后的值
+ if (touch_pre_value[ch] > (touch_normal_value[ch] + user_data->port_list[ch].press_delta)) {
+ key_or |= BIT(ch);
+ touch_calibrate_cnt[ch] = 0;
+ } else {
+ key_or &= ~BIT(ch);
+ touch_calibrate_cnt[ch] ++;
+ }
+ //定期标定常态下的基准值
+ if (touch_calibrate_cnt[ch] > TOUCH_VAL_CALIBRATE_CYCLE) {
+ touch_normal_value[ch] = touch_calibrate_tmp_value[ch] / 10;
+ touch_calibrate_tmp_value[ch] = 0;
+ touch_calibrate_cnt[ch] = 0;
+ } else if (touch_calibrate_cnt[ch] >= (TOUCH_VAL_CALIBRATE_CYCLE / 2)) {
+ if (touch_calibrate_cnt[ch] < ((TOUCH_VAL_CALIBRATE_CYCLE / 2) + 10)) {
+ touch_calibrate_tmp_value[ch] += touch_pre_value[ch];
+ }
+ } else {
+ touch_calibrate_tmp_value[ch] = 0;
+ }
+}
+
+void scan_capkey_async(void *priv)
+{
+ if (!user_data) {
+ return;
+ }
+ static u8 cur_ch = 0;
+ static u32 new_val = 0;
+ static u32 old_val = 0;
+
+ u8 pre_ch = cur_ch - 1;
+ u8 net_ch = cur_ch + 1;
+ if (cur_ch == 0) {
+ pre_ch = user_data->num - 1;
+ }
+ if (net_ch >= user_data->num) {
+ net_ch = 0;
+ }
+
+ new_val = JL_PCNT->VAL;
+ u32 delta_val = 0;
+ if (new_val >= old_val) {
+ delta_val = new_val - old_val;
+ } else {
+ delta_val = (u32) - new_val + old_val;
+ }
+ plcnt_flt(delta_val, pre_ch);
+ old_val = JL_PCNT->VAL;
+ plcnt_iomc(&(user_data->port_list[cur_ch]));
+ plcnt_io_in(&(user_data->port_list[cur_ch]));
+ if (net_ch != cur_ch) {
+ plcnt_io_out(&(user_data->port_list[net_ch]));
+ }
+ cur_ch = net_ch;
+}
+
+void scan_capkey(void *priv)
+{
+ if (!user_data) {
+ return;
+ }
+ for (u8 ch = 0; ch < user_data->num; ch ++) {
+ plcnt_io_out(&(user_data->port_list[ch]));
+ plcnt_iomc(&(user_data->port_list[ch]));
+ u32 tmp_val, start_val, end_val, delta_val = 0;
+ for (u8 i = 0; i < 5; i ++) {
+ delay(100);
+ start_val = JL_PCNT->VAL;
+ PLCNT_IO_PORTx->DIR |= BIT(PLCNT_IO_xx);
+ __asm__ volatile("csync");
+ while (PLCNT_IO_PORTx->IN & BIT(PLCNT_IO_xx));
+ end_val = JL_PCNT->VAL;
+ PLCNT_IO_PORTx->DIR &= ~BIT(PLCNT_IO_xx);
+ if (end_val > start_val) {
+ tmp_val = end_val - start_val;
+ } else {
+ tmp_val = (u32) - start_val + end_val;
+ }
+ delta_val += tmp_val;
+ }
+ delta_val = delta_val / 5;
+ /* printf("%d: %d\n", ch, delta_val); */
+ plcnt_flt(delta_val, ch);
+ }
+}
+
+
+
+/*
+ @brief 引脚放电计数模块初始化
+*/
+int plcnt_init(void *_data)
+{
+ if (_data == NULL) {
+ return -1;
+ }
+ user_data = (const struct touch_key_platform_data *)_data;
+
+ if (user_data->num > PLCNT_KEY_CH_MAX) {
+ return -1;
+ }
+
+ for (u8 ch = 0; ch < user_data->num; ch ++) {
+ touch_normal_value[ch] = 0 - (2 * user_data->port_list[ch].press_delta);
+ }
+
+ for (u8 ch = 0; ch < user_data->num; ch ++) {
+ plcnt_iomc(&(user_data->port_list[ch]));
+ plcnt_io_out(&(user_data->port_list[ch]));
+ }
+
+ JL_PCNT->CON = 0;
+ JL_PCNT->CON |= (0b11 << 2); //选择PLL240M为时钟源
+ JL_PCNT->CON |= BIT(1); //引脚放电计数使能
+
+ /* sys_s_hi_timer_add(NULL, scan_capkey_async, 2); //2ms */
+ sys_s_hi_timer_add(NULL, scan_capkey, 10); //10ms
+
+ return 0;
+}
+
+static u8 key_filter(u8 key)
+{
+ static u8 used_key = 0xff;
+ static u8 old_key;
+ static u8 key_counter;
+
+ if (old_key != key) {
+ key_counter = 0;
+ old_key = key;
+ } else {
+ key_counter++;
+ if (key_counter == 3) {
+ used_key = key;
+ }
+ }
+ return used_key;
+}
+
+u8 get_plcnt_value(void)
+{
+ /* printf("%d %d %d\n", touch_pre_value[0], touch_pre_value[1], touch_pre_value[2]); */
+ static u8 pre_i = 0;
+ u8 key_num = 0xff;
+ if (key_or) {
+ if (key_or & BIT(pre_i)) {
+ key_num = pre_i;
+ } else {
+ for (u8 ch = 0; ch < user_data->num; ch ++) {
+ if (key_or & BIT(ch)) {
+ key_num = ch;
+ pre_i = ch;
+ break;
+ }
+ }
+ }
+ /* printf("key_num : %d\n", key_num); */
+ }
+ return key_filter(key_num);
+}
+
diff --git a/cpu/br28/power/power_app.c b/cpu/br28/power/power_app.c
new file mode 100644
index 0000000..c11ac5d
--- /dev/null
+++ b/cpu/br28/power/power_app.c
@@ -0,0 +1,32 @@
+#include "asm/power_interface.h"
+#include "app_config.h"
+#include "includes.h"
+
+
+const char BTOSC_FASTBOOT_EN = 0;
+
+///Jim ˫ʧ
+#if (TCFG_LOWPOWER_LOWPOWER_SEL/* == SLEEP_EN*/)
+
+
+static enum LOW_POWER_LEVEL power_app_level(void)
+{
+#if (TCFG_LOWPOWER_LOWPOWER_SEL==SLEEP_EN)
+ return LOW_POWER_MODE_SLEEP;
+#else
+ return LOW_POWER_MODE_DEEP_SLEEP;
+#endif
+}
+
+static u8 power_app_idle(void)
+{
+ return 1;
+}
+
+REGISTER_LP_TARGET(power_app_lp_target) = {
+ .name = "power_app",
+ .level = power_app_level,
+ .is_idle = power_app_idle,
+};
+
+#endif
diff --git a/cpu/br28/power/power_check.c b/cpu/br28/power/power_check.c
new file mode 100644
index 0000000..ffb680a
--- /dev/null
+++ b/cpu/br28/power/power_check.c
@@ -0,0 +1,69 @@
+/**@file power_check.c
+* @brief 低功耗检查点
+* @details HW API
+* @author JL
+* @date 2021-11-30
+* @version V1.0
+* @copyright Copyright:(c)JIELI 2011-2020 @ , All Rights Reserved.
+ */
+
+#include "asm/power_interface.h"
+#include "app_config.h"
+#include "includes.h"
+#include "asm/clock_hw.h"
+
+#pragma bss_seg(".volatile_ram_code")
+#pragma data_seg(".volatile_ram_code")
+#pragma code_seg(".volatile_ram_code")
+#pragma const_seg(".volatile_ram_code")
+#pragma str_literal_override(".volatile_ram_code")
+
+void pmut_put_u8hex(u8 dat);
+void pmu_put_u16hex(u16 dat);
+void pmu_put_u32hex(u32 dat);
+void pmu_put_u64hex(u64 dat);
+void pmu_put_buf(const u8 *buf, int len);
+
+AT_VOLATILE_RAM_CODE_POWER
+u8 sleep_safety_check(void)
+{
+#if 0
+ u32 get_rch_freq();
+ JL_PORTA->DIR &= ~BIT(5);
+ JL_OMAP->PA5_OUT = FO_UART0_TX;
+ MAIN_CLOCK_SEL(MAIN_CLOCK_IN_RC);
+ HSB_CLK_DIV(0);
+ LSB_CLK_DIV(0);
+ UART_CLOCK_IN(UART_CLOCK_IN_LSB);
+
+ JL_UART0->BAUD = (get_rch_freq() * 1000 / 115200) / 4 - 1;
+
+ void check_gpio_safety();
+ check_gpio_safety();
+
+ void wdt_close();
+ wdt_close();
+ while (1);
+#endif
+ return 0;
+}
+
+AT_VOLATILE_RAM_CODE_POWER
+u8 soff_safety_check(void)
+{
+#if 0
+ u32 get_rch_freq();
+ JL_PORTA->DIR &= ~BIT(5);
+ JL_OMAP->PA5_OUT = FO_UART0_TX;
+ MAIN_CLOCK_SEL(MAIN_CLOCK_IN_RC);
+ HSB_CLK_DIV(0);
+ LSB_CLK_DIV(0);
+ UART_CLOCK_IN(UART_CLOCK_IN_LSB);
+
+ JL_UART0->BAUD = (get_rch_freq() * 1000 / 115200) / 4 - 1;
+
+ void check_gpio_safety();
+ check_gpio_safety();
+#endif
+ return 0;
+}
diff --git a/cpu/br28/power/power_port.c b/cpu/br28/power/power_port.c
new file mode 100644
index 0000000..bba8354
--- /dev/null
+++ b/cpu/br28/power/power_port.c
@@ -0,0 +1,205 @@
+#include "asm/power_interface.h"
+#include "app_config.h"
+#include "includes.h"
+#include "app_main.h"
+static u8 gpiousb = 0x3;
+static u32 usb_io_con = 0;
+
+/* cpu公共流程:
+ * 请勿添加板级相关的流程,例如宏定义
+ * 可以重写改流程
+ * 所有io保持原状,除usb io
+ */
+void sleep_gpio_protect(u32 gpio)
+{
+ if (gpio == IO_PORT_DP) {
+ gpiousb &= ~BIT(0);
+ } else if (gpio == IO_PORT_DM) {
+ gpiousb &= ~BIT(1);
+ }
+}
+
+void sleep_enter_callback_common(void *priv)
+{
+ usb_io_con = JL_USB_IO->CON0;
+
+ if (gpiousb) {
+ usb_iomode(1);
+
+ if (gpiousb & BIT(0)) {
+ gpio_set_pull_up(IO_PORT_DP, 0);
+ gpio_set_pull_down(IO_PORT_DP, 0);
+ gpio_set_direction(IO_PORT_DP, 1);
+ gpio_set_die(IO_PORT_DP, 0);
+ gpio_set_dieh(IO_PORT_DP, 0);
+ }
+
+ if (gpiousb & BIT(1)) {
+ gpio_set_pull_up(IO_PORT_DM, 0);
+ gpio_set_pull_down(IO_PORT_DM, 0);
+ gpio_set_direction(IO_PORT_DM, 1);
+ gpio_set_die(IO_PORT_DM, 0);
+ gpio_set_dieh(IO_PORT_DM, 0);
+ }
+ }
+}
+
+void sleep_exit_callback_common(void *priv)
+{
+ JL_USB_IO->CON0 = usb_io_con;
+ gpiousb = 0x3;
+}
+
+static struct gpio_value soff_gpio_config = {
+ .gpioa = 0xffff,
+ .gpiob = 0xffff,
+ .gpioc = 0xffff,
+ .gpiod = 0xffff,
+ .gpioe = 0xffff,
+ .gpiog = 0xffff,
+ .gpiop = 0x1,//
+ .gpiousb = 0x3,
+};
+
+void soff_gpio_protect(u32 gpio)
+{
+ if ((gpio >= 0) && (gpio < IO_MAX_NUM)) {
+ port_protect((u16 *)&soff_gpio_config, gpio);
+ } else if (gpio == IO_PORT_DP) {
+ soff_gpio_config.gpiousb &= ~BIT(0);
+ } else if (gpio == IO_PORT_DM) {
+ soff_gpio_config.gpiousb &= ~BIT(1);
+ }
+}
+
+/* cpu公共流程:
+ * 请勿添加板级相关的流程,例如宏定义
+ * 可以重写改流程
+ * 释放除内置flash外的所有io
+ */
+//maskrom 使用到的io
+static void mask_io_cfg()
+{
+ struct boot_soft_flag_t boot_soft_flag = {0};
+ boot_soft_flag.flag0.boot_ctrl.wdt_dis = 0;
+ boot_soft_flag.flag0.boot_ctrl.poweroff = 0;
+ boot_soft_flag.flag0.boot_ctrl.is_port_b = JL_IOMAP->CON0 & BIT(16) ? 1 : 0;
+ boot_soft_flag.flag0.boot_ctrl.lvd_en = (GET_VLVD_EN() ? 1 : 0);
+
+ boot_soft_flag.flag1.misc.usbdm = SOFTFLAG_HIGH_RESISTANCE;
+ boot_soft_flag.flag1.misc.usbdp = SOFTFLAG_HIGH_RESISTANCE;
+
+ boot_soft_flag.flag1.misc.uart_key_port = 0;
+ boot_soft_flag.flag1.misc.ldoin = SOFTFLAG_HIGH_RESISTANCE;
+
+ boot_soft_flag.flag2.pg2_pg3.pg2 = SOFTFLAG_HIGH_RESISTANCE;
+ boot_soft_flag.flag2.pg2_pg3.pg3 = SOFTFLAG_HIGH_RESISTANCE;
+
+ boot_soft_flag.flag3.pg4_res.pg4 = SOFTFLAG_HIGH_RESISTANCE;
+
+ boot_soft_flag.flag4.fast_boot_ctrl.fast_boot = 0;
+ boot_soft_flag.flag4.fast_boot_ctrl.flash_stable_delay_sel = 0;
+
+ mask_softflag_config(&boot_soft_flag);
+
+}
+
+void board_set_soft_poweroff_common(void *priv)
+{
+ //flash电源
+ if (get_sfc_port() == 0) {
+ soff_gpio_protect(SPI0_PWR_A);
+ soff_gpio_protect(SPI0_CS_A);
+ soff_gpio_protect(SPI0_CLK_A);
+ soff_gpio_protect(SPI0_DO_D0_A);
+ soff_gpio_protect(SPI0_DI_D1_A);
+ if (get_sfc_bit_mode() == 4) {
+ soff_gpio_protect(SPI0_WP_D2_A);
+ soff_gpio_protect(SPI0_HOLD_D3_A);
+ }
+ } else {
+ soff_gpio_protect(SPI0_PWR_B);
+ soff_gpio_protect(SPI0_CS_B);
+ soff_gpio_protect(SPI0_CLK_B);
+ soff_gpio_protect(SPI0_DO_D0_B);
+ soff_gpio_protect(SPI0_DI_D1_B);
+ if (get_sfc_bit_mode() == 4) {
+ soff_gpio_protect(SPI0_WP_D2_B);
+ soff_gpio_protect(SPI0_HOLD_D3_B);
+ }
+ }
+
+ mask_io_cfg();
+
+ gpio_dir(GPIOA, 0, 16, soff_gpio_config.gpioa, GPIO_OR);
+ gpio_set_pu(GPIOA, 0, 16, ~soff_gpio_config.gpioa, GPIO_AND);
+ gpio_set_pd(GPIOA, 0, 16, ~soff_gpio_config.gpioa, GPIO_AND);
+ gpio_die(GPIOA, 0, 16, ~soff_gpio_config.gpioa, GPIO_AND);
+ gpio_dieh(GPIOA, 0, 16, ~soff_gpio_config.gpioa, GPIO_AND);
+
+
+ gpio_set_pull_up (IO_PORTA_01,0);
+ gpio_set_pull_down(IO_PORTA_01,0);
+
+ gpio_dir(GPIOB, 0, 16, soff_gpio_config.gpiob, GPIO_OR);
+ gpio_set_pu(GPIOB, 0, 16, ~soff_gpio_config.gpiob, GPIO_AND);
+ gpio_set_pd(GPIOB, 0, 16, ~soff_gpio_config.gpiob, GPIO_AND);
+ gpio_die(GPIOB, 0, 16, ~soff_gpio_config.gpiob, GPIO_AND);
+ gpio_dieh(GPIOB, 0, 16, ~soff_gpio_config.gpiob, GPIO_AND);
+
+ gpio_dir(GPIOC, 0, 16, soff_gpio_config.gpioc, GPIO_OR);
+ gpio_set_pu(GPIOC, 0, 16, ~soff_gpio_config.gpioc, GPIO_AND);
+ gpio_set_pd(GPIOC, 0, 16, ~soff_gpio_config.gpioc, GPIO_AND);
+ gpio_die(GPIOC, 0, 16, ~soff_gpio_config.gpioc, GPIO_AND);
+ gpio_dieh(GPIOC, 0, 16, ~soff_gpio_config.gpioc, GPIO_AND);
+
+ gpio_dir(GPIOD, 0, 16, soff_gpio_config.gpiod, GPIO_OR);
+ gpio_set_pu(GPIOD, 0, 16, ~soff_gpio_config.gpiod, GPIO_AND);
+ gpio_set_pd(GPIOD, 0, 16, ~soff_gpio_config.gpiod, GPIO_AND);
+ gpio_die(GPIOD, 0, 16, ~soff_gpio_config.gpiod, GPIO_AND);
+ gpio_dieh(GPIOD, 0, 16, ~soff_gpio_config.gpiod, GPIO_AND);
+
+ gpio_dir(GPIOE, 0, 16, soff_gpio_config.gpioe, GPIO_OR);
+ gpio_set_pu(GPIOE, 0, 16, ~soff_gpio_config.gpioe, GPIO_AND);
+ gpio_set_pd(GPIOE, 0, 16, ~soff_gpio_config.gpioe, GPIO_AND);
+ gpio_die(GPIOE, 0, 16, ~soff_gpio_config.gpioe, GPIO_AND);
+ gpio_dieh(GPIOE, 0, 16, ~soff_gpio_config.gpioe, GPIO_AND);
+
+ gpio_dir(GPIOG, 0, 16, soff_gpio_config.gpiog, GPIO_OR);
+ gpio_set_pu(GPIOG, 0, 16, ~soff_gpio_config.gpiog, GPIO_AND);
+ gpio_set_pd(GPIOG, 0, 16, ~soff_gpio_config.gpiog, GPIO_AND);
+ gpio_die(GPIOG, 0, 16, ~soff_gpio_config.gpiog, GPIO_AND);
+ gpio_dieh(GPIOG, 0, 16, ~soff_gpio_config.gpiog, GPIO_AND);
+
+ gpio_dir(GPIOP, 0, 1, soff_gpio_config.gpiop, GPIO_OR);
+ gpio_set_pu(GPIOP, 0, 1, ~soff_gpio_config.gpiop, GPIO_AND);
+ gpio_set_pd(GPIOP, 0, 1, ~soff_gpio_config.gpiop, GPIO_AND);
+ gpio_die(GPIOP, 0, 1, ~soff_gpio_config.gpiop, GPIO_AND);
+ gpio_dieh(GPIOP, 0, 1, ~soff_gpio_config.gpiop, GPIO_AND);
+
+
+
+
+ if (soff_gpio_config.gpiousb) {
+ usb_iomode(1);
+
+ if (soff_gpio_config.gpiousb & BIT(0)) {
+
+ gpio_set_pull_up(IO_PORT_DP, 0);
+ gpio_set_pull_down(IO_PORT_DP, 0);
+ gpio_set_direction(IO_PORT_DP, 1);
+ gpio_set_die(IO_PORT_DP, 0);
+ gpio_set_dieh(IO_PORT_DP, 0);
+ }
+
+ if (soff_gpio_config.gpiousb & BIT(1)) {
+ gpio_set_pull_up(IO_PORT_DM, 0);
+ gpio_set_pull_down(IO_PORT_DM, 0);
+ gpio_set_direction(IO_PORT_DM, 1);
+ gpio_set_die(IO_PORT_DM, 0);
+ gpio_set_dieh(IO_PORT_DM, 0);
+ }
+ }
+}
+
+
diff --git a/cpu/br28/power/power_trim.c b/cpu/br28/power/power_trim.c
new file mode 100644
index 0000000..b557947
--- /dev/null
+++ b/cpu/br28/power/power_trim.c
@@ -0,0 +1,292 @@
+#include "asm/power_interface.h"
+#include "asm/adc_api.h"
+#include "app_config.h"
+#include "includes.h"
+#include "stdlib.h"
+
+__attribute__((noinline))
+AT(.volatile_ram_code)
+static u8 wiovdd_trim(u8 trim, s16 *adc_wiovdd_voltage)
+{
+ u32 wiovdd_lev = 7;
+ u32 miovdd_lev = 0;
+ P33_CON_SET(P3_ANA_CON5, 3, 3, wiovdd_lev);
+ delay(215);//延时50us
+ P33_CON_SET(P3_ANA_CON5, 0, 3, miovdd_lev);
+ delay(430);
+
+ if (trim) {
+ for (; wiovdd_lev > 3; wiovdd_lev--) {
+ P33_CON_SET(P3_ANA_CON5, 3, 3, wiovdd_lev);
+ delay(700);//延时50us
+ adc_wiovdd_voltage[wiovdd_lev] = get_vddio_voltage();;
+ }
+
+ for (int i = 3; i >= 0; i--) {
+ adc_wiovdd_voltage[i] = adc_wiovdd_voltage[i + 1] - 200;
+ }
+ }
+
+ return 0;
+}
+
+__attribute__((noinline))
+AT(.volatile_ram_code)
+u8 miovdd_trim(u8 trim, s16 *adc_miovdd_voltage)
+{
+ u32 wiovdd_lev = 0;
+ u32 miovdd_lev = 7;
+ P33_CON_SET(P3_ANA_CON5, 0, 3, miovdd_lev);
+ delay(430);
+ P33_CON_SET(P3_ANA_CON5, 3, 3, wiovdd_lev);
+ delay(215);//延时50us
+
+ if (trim) {
+ for (; miovdd_lev > 3; miovdd_lev--) {
+ P33_CON_SET(P3_ANA_CON5, 0, 3, miovdd_lev);
+ delay(700);//延时50us
+ adc_miovdd_voltage[miovdd_lev] = get_vddio_voltage();;
+ }
+
+ for (int i = 3; i >= 0; i--) {
+ adc_miovdd_voltage[i] = adc_miovdd_voltage[i + 1] - 200;
+ }
+ }
+
+ return 0;
+}
+
+
+__attribute__((noinline))
+AT(.volatile_ram_code)
+u32 iovdd_trim(u8 trim, u8 *miovdd_lev, u8 *wiovdd_lev)
+{
+
+ const u32 m_iovdd_lev = P3_ANA_CON5 & 0xf;
+ if (trim == 0) {
+ return 1;
+ }
+
+ u32 check_vbat = get_vdd_voltage(AD_CH_VBAT) * 4;
+ printf("check_vbat = %d\n", check_vbat);
+ if (check_vbat < 3700) {
+ printf("%s %d\n", __func__, __LINE__);
+ *miovdd_lev = m_iovdd_lev | BIT(7);
+ *wiovdd_lev = m_iovdd_lev | BIT(7);
+ return 0;
+ }
+ local_irq_disable();
+
+ const u32 lvd_con = P3_VLVD_CON;
+ P3_VLVD_CON &= ~BIT(2);
+ delay(100);
+ P3_VLVD_CON &= ~BIT(0); //关闭lvd
+
+ s16 adc_wiovdd_voltage[8];
+ s16 adc_miovdd_voltage[8];
+
+ miovdd_trim(trim, adc_miovdd_voltage);
+ wiovdd_trim(trim, adc_wiovdd_voltage);
+
+ if (lvd_con & BIT(0)) {
+ P3_VLVD_CON |= BIT(0);//en
+ delay(3);
+ P3_VLVD_CON |= BIT(2);//oe
+ }
+
+ local_irq_enable();
+
+ int miovdd_voltage = m_iovdd_lev * 200 + 2000;
+ u32 min_diff = -1;
+ int mlev = 0;
+
+ for (int i = 7; i >= 0; i--) {
+ u32 diff = abs(miovdd_voltage - adc_miovdd_voltage[i]);
+ if (diff < min_diff) {
+ mlev = i;
+ min_diff = diff;
+ }
+ }
+ *miovdd_lev = mlev;
+
+ u32 wlev = 0;
+ min_diff = -1;
+ for (int i = 7; i >= 0; i--) {
+ u32 diff = abs(adc_miovdd_voltage[mlev] - adc_wiovdd_voltage[i]);
+ if (diff < min_diff) {
+ wlev = i;
+ min_diff = diff;
+ }
+ }
+
+ *wiovdd_lev = wlev;
+
+
+ for (u8 i = 0; i < 8; i++) {
+ printf("adc_wiovdd_voltage[%d] = %d\n", i, adc_wiovdd_voltage[i]);
+ printf("adc_miovdd_voltage[%d] = %d\n", i, adc_miovdd_voltage[i]);
+ }
+ return 0;
+}
+
+static u8 wvdd_trim(u8 trim)
+{
+ u8 wvdd_lev = 0;
+ wvdd_lev = 0;
+ int v = 0;
+ u8 err = 0;
+
+ if (trim) {
+
+ v = get_wvdd_level_trim();
+ if (v == 0) {
+ //0.65v
+ wvdd_lev = 0b0011;
+ } else if (v == 1) {
+ //0.7v
+ wvdd_lev = 0b0100;
+ } else if (v == 2) {
+ //0.75v
+ wvdd_lev = 0b0101;
+ } else {
+ //0.8v
+ //wvdd_lev = 0b0110;
+ WVDD_VOL_SEL(wvdd_lev);
+ WVDD_LOAD_EN(1);
+ WLDO06_EN(1);
+ delay(2000);//1ms
+ do {
+ WVDD_VOL_SEL(wvdd_lev);
+ delay(2000);//1ms * n
+ v = get_vdd_voltage(AD_CH_WVDD);
+ if (v > WVDD_VOL_TRIM) {
+ break;
+ }
+ wvdd_lev ++;
+ } while (wvdd_lev < WVDD_LEVEL_MAX);
+ WVDD_LOAD_EN(0);
+ WLDO06_EN(0);
+
+ u8 min = (WVDD_VOL_TRIM - WVDD_VOL_MIN) / WVDD_VOL_STEP - 2;
+ u8 max = (WVDD_VOL_TRIM - WVDD_VOL_MIN) / WVDD_VOL_STEP + 2;
+ if (!(wvdd_lev >= min && wvdd_lev <= max)) {
+ wvdd_lev = WVDD_LEVEL_DEFAULT;
+ err = 1;
+ }
+ }
+
+ //update_wvdd_trim_level(wvdd_lev);
+ } else {
+ wvdd_lev = get_wvdd_trim_level();
+ }
+
+ printf("trim: %d, wvdd_lev: %d, v: %d, err: %d\n", trim, wvdd_lev, v, err);
+
+ M2P_WDVDD = wvdd_lev;
+
+ if (err) {
+ return WVDD_LEVEL_ERR;
+ }
+
+ return wvdd_lev;
+}
+
+static u8 pvdd_trim(u8 trim)
+{
+ /* return 0; */
+ u32 v = 0;
+ u8 lev_high_now = PVDD_LEVEL_DEFAULT;
+ u8 err = 0;
+
+ if (trim) {
+ PVDD_LEVEL_HIGH_NOW(PVDD_LEVEL_REF);
+ delay(2000);//1ms
+ v = get_vdd_voltage(AD_CH_PVDD);//adc_get_voltage_preemption(AD_CH_PVDD);
+
+ if ((v < (PVDD_VOL_REF - 2 * PVDD_VOL_STEP)) || (v > (PVDD_VOL_REF + 2 * PVDD_VOL_STEP))) {
+ lev_high_now = PVDD_LEVEL_DEFAULT;
+ M2P_PVDD_LEVEL_SLEEP_TRIM = PVDD_LEVEL_SLEEP;
+ err = 1;
+
+ } else {
+ M2P_PVDD_LEVEL_SLEEP_TRIM = (PVDD_LEVEL_REF - (v - PVDD_VOL_SLEEP) / PVDD_VOL_STEP);
+ lev_high_now = M2P_PVDD_LEVEL_SLEEP_TRIM + (PVDD_VOL_HIGH_NOW - PVDD_VOL_SLEEP) / PVDD_VOL_STEP;
+
+ }
+ } else {
+ lev_high_now = get_pvdd_trim_level();
+ M2P_PVDD_LEVEL_SLEEP_TRIM = get_pvdd_level() - (PVDD_VOL_HIGH_NOW - PVDD_VOL_SLEEP) / PVDD_VOL_STEP;
+ }
+
+#if (!PMU_NEW_FLOW)
+ if (get_pvdd_dcdc_cfg()) {
+ //外接dcdc,pvdd配置为3档
+ lev_high_now = 3;
+
+ }
+#endif
+
+ PVDD_LEVEL_HIGH_NOW(lev_high_now);
+ delay(2000);
+ PVDD_AUTO_PRD(0x3);
+ PVDD_LEVEL_AUTO(0x1);
+ PVDD_LEVEL_LOW(M2P_WDVDD);
+
+#if PMU_NEW_FLOW
+ if (get_pvdd_dcdc_cfg()) {
+ power_set_pvdd_mode(PWR_PVDD_DCDC);
+ }
+#endif
+
+ printf("trim: %d, pvdd_vol_ref: %d, pvdd_level_high_now_trim: %d, pvdd_level_sleep_trim: %d, pvdd_level_lev_l_trim: %d, err: %d\n", \
+ trim, v, lev_high_now, M2P_PVDD_LEVEL_SLEEP_TRIM, M2P_WDVDD, err);
+ cap_rch_enable();
+
+ if (err) {
+ return PVDD_LEVEL_ERR;
+ }
+
+ return lev_high_now;
+}
+
+void volatage_trim_init()
+{
+ /* trim wvdd */
+ printf("lvd_con = 0x%x\n", P3_VLVD_CON);
+ u8 trim = load_pmu_trim_value_from_vm();
+ u8 wvdd_lev = 0;
+ u8 pvdd_lev = 0;
+
+ extern bool vm_need_recover(void);
+ if (vm_need_recover()) { // 升级完后重新trim
+ trim = 0xff;
+ }
+
+ printf("trim = 0x%x\n", trim);
+
+ wvdd_lev = wvdd_trim((trim & TRIM_WVDD) ? 1 : 0);
+ pvdd_lev = pvdd_trim((trim & TRIM_PVDD) ? 1 : 0);
+
+ u8 miovdd_lev = 0;
+ u8 wiovdd_lev = 0;
+ if (trim & TRIM_IOVDD) {
+ u8 trim_succ = iovdd_trim(trim, &miovdd_lev, &wiovdd_lev);
+ } else {
+ miovdd_lev = get_miovdd_trim_level();
+ wiovdd_lev = get_wiovdd_trim_level();
+ }
+
+ if (trim) {
+ if ((wvdd_lev != WVDD_LEVEL_ERR) && (pvdd_lev != PVDD_LEVEL_ERR)) {
+ store_pmu_trim_value_to_vm(wvdd_lev, pvdd_lev, miovdd_lev, wiovdd_lev);
+ }
+ }
+
+ printf("miovdd_lev = %x\n", miovdd_lev);
+ printf("wiovdd_lev = %x\n", wiovdd_lev);
+
+ P33_CON_SET(P3_ANA_CON5, 0, 3, miovdd_lev);
+ P33_CON_SET(P3_ANA_CON5, 3, 3, 0);
+}
+
+
diff --git a/cpu/br28/private_iis.c b/cpu/br28/private_iis.c
new file mode 100644
index 0000000..568d819
--- /dev/null
+++ b/cpu/br28/private_iis.c
@@ -0,0 +1,229 @@
+#include "private_iis.h"
+#include "app_config.h"
+#include "audio_decoder.h"
+#include "media/includes.h"
+#include "audio_config.h"
+#include "system/includes.h"
+#include "audio_enc.h"
+#include "application/audio_eq.h"
+#include "application/audio_drc.h"
+#include "app_config.h"
+#include "audio_config.h"
+#include "audio_dec.h"
+#include "app_main.h"
+#include "clock_cfg.h"
+#include "audio_dec_eff.h"
+#include "audio_codec_clock.h"
+#include "audio_dvol.h"
+#include "audio_link.h"
+#include "circular_buf.h"
+#include "sound_device.h"
+
+#define PRIVATE_IIS_MSG_CHECK_EN 1 //使能格式检查
+
+struct __private_iis_data {
+ u32 msg[CMD_LEN / 4];
+ u8 get_msg_flag;
+ u8 msg_len;
+};
+static struct __private_iis_data private_iis_data = {0};
+
+struct private_iis_hdl {
+ OS_SEM sem;
+ /* s16 *store_pcm_buf; */
+ /* cbuffer_t cbuf; */
+ int sample_rate;
+ void *hw_alink;
+ void *alink_ch;
+ u32 cmd; //要求发送或者接收到的cmd
+};
+static struct private_iis_hdl *private_iis = NULL;
+
+extern ALINK_PARM alink0_platform_data;
+
+/********************************* private iis Rx *********************************/
+// 这个格式检查需要根据具体消息自己定义!!, 也可以不做检查
+static u8 private_iis_check_msg(void)
+{
+#if PRIVATE_IIS_MSG_CHECK_EN
+ if (private_iis_data.msg[0] == PRIVATE_IIS_CMD && private_iis_data.msg[1] != private_iis_data.msg[0]) {
+ return 1;
+ }
+ return 0; //格式检查不过
+#else
+ return 1;
+#endif
+}
+
+
+// 接收消息
+static void private_iis_in_data_handler(void *priv, void *_data, int len)
+{
+ s16 *data = (s16 *)_data;
+ /* memcpy(private_iis_data.msg, data, len); */
+ u8 *temp = memchr(data, private_iis->cmd, len);
+ if (temp && private_iis_data.get_msg_flag == 0) {
+ memcpy(private_iis_data.msg, temp, CMD_LEN);
+ if (private_iis_check_msg()) {
+ private_iis_data.get_msg_flag = 1;
+ private_iis_data.msg_len = CMD_LEN;
+ }
+ }
+ alink_set_shn(&alink0_platform_data.ch_cfg[1], len / 4);
+}
+
+/*
+ * 打开iis接收,用来接收私有数据
+ */
+void private_iis_rx_open(void)
+{
+ if (private_iis) {
+ printf("private iis is running!\n");
+ return;
+ }
+ struct private_iis_hdl *iis_in = NULL;
+ iis_in = zalloc(sizeof(struct private_iis_hdl));
+ if (!iis_in) {
+ return;
+ }
+
+ private_iis = iis_in;
+
+ iis_in->cmd = PRIVATE_IIS_CMD;
+ /* iis_in->store_pcm_buf = malloc(IIS_IN_STORE_PCM_SIZE); */
+ /* if (!iis_in->store_pcm_buf) { */
+ /* free(iis_in); */
+ /* return; */
+ /* } */
+ /* cbuf_init(&iis_in->cbuf, iis_in->store_pcm_buf, IIS_IN_STORE_PCM_SIZE); */
+ iis_in->hw_alink = (ALINK_PARM *)get_iis_alink_param();
+ if (iis_in->hw_alink == NULL) {
+ iis_in->hw_alink = alink_init(&alink0_platform_data);
+ }
+ iis_in->alink_ch = alink_channel_init(iis_in->hw_alink, 1, ALINK_DIR_RX, (void *)iis_in, private_iis_in_data_handler);
+ alink_start(iis_in->hw_alink);
+ iis_in->sample_rate = TCFG_IIS_SR;
+}
+
+
+u8 get_private_iis_get_msg_flag(void)
+{
+ return private_iis_data.get_msg_flag;
+}
+
+void show_private_msg(void)
+{
+ if (private_iis_data.get_msg_flag) {
+ for (int i = 0; i < private_iis_data.msg_len / 4; i++) {
+ y_printf(">>>msg[%d] = %d\n", i, private_iis_data.msg[i]);
+ }
+ } else {
+ r_printf(">>>>> Show private msg failed!\n");
+ }
+}
+
+
+void private_iis_rx_close(void)
+{
+ if (private_iis) {
+ void *alink_param = (ALINK_PARM *)get_iis_alink_param();
+ if (!alink_param) {
+ //如果 alink_param 为NULL,则说明还没打开 iis tx
+ alink_uninit(private_iis->hw_alink);
+ } else {
+ alink_channel_close(private_iis->alink_ch);
+ }
+
+ free(private_iis);
+ private_iis = NULL;
+ }
+}
+
+
+/********************************* private iis Tx *********************************/
+
+// 发送消息
+static void private_iis_out_data_handler(void *priv, void *_data, int len)
+{
+ u32 *buf_u32 = (u32 *)_data;
+ buf_u32[0] = private_iis->cmd;
+ buf_u32[1] = TCFG_IIS_SR;
+ buf_u32[2] = PRIVATE_IIS_TX_LINEIN_CH_IDX;
+ buf_u32[3] = PRIVATE_IIS_TX_LINEIN_GAIN;
+ alink_set_shn(&alink0_platform_data.ch_cfg[0], len / 4);
+}
+
+void private_iis_tx_open(void)
+{
+ if (private_iis) {
+ printf("private iis is running!\n");
+ return;
+ }
+ struct private_iis_hdl *iis_out = NULL;
+ iis_out = zalloc(sizeof(struct private_iis_hdl));
+ if (!iis_out) {
+ return;
+ }
+
+ private_iis = iis_out;
+
+ iis_out->cmd = PRIVATE_IIS_CMD;
+
+ iis_out->hw_alink = (ALINK_PARM *)get_iis_alink_param();
+ if (iis_out->hw_alink == NULL) {
+ iis_out->hw_alink = alink_init(&alink0_platform_data);
+ }
+ iis_out->alink_ch = alink_channel_init(iis_out->hw_alink, 0, ALINK_DIR_TX, (void *)iis_out, private_iis_out_data_handler);
+ alink_start(iis_out->hw_alink);
+ iis_out->sample_rate = TCFG_IIS_SR;
+}
+
+void private_iis_tx_close(void)
+{
+ if (private_iis) {
+ void *alink_param = (ALINK_PARM *)get_iis_alink_param();
+ if (!alink_param) {
+ //如果 alink_param 为NULL,则说明还没打开 iis tx
+ alink_uninit(private_iis->hw_alink);
+ } else {
+ alink_channel_close(private_iis->alink_ch);
+ }
+
+ free(private_iis);
+ private_iis = NULL;
+ }
+}
+
+
+
+// ************* test ************
+static void private_iis_test_timer_cb(void *p)
+{
+ static u32 tick = 0;
+ tick++;
+ printf(">>>>>>>>>>>>>>> tick : %d\n", tick);
+ if (get_private_iis_get_msg_flag()) {
+ y_printf("(test) >>>>>>> GET MSG!\n");
+ show_private_msg();
+ private_iis_rx_close();
+ }
+}
+void private_iis_rx_test(void)
+{
+ y_printf("-------------------- Enter %s !", __func__);
+ private_iis_rx_open();
+ sys_timer_add(NULL, private_iis_test_timer_cb, 1000);
+}
+
+
+void private_iis_tx_test(void)
+{
+ y_printf("-------------------- Enter %s !", __func__);
+ private_iis_tx_open();
+ os_time_dly(10);
+ private_iis_tx_close();
+ extern int iis_in_dec_open(void);
+ iis_in_dec_open();
+}
+
+
diff --git a/cpu/br28/private_iis.h b/cpu/br28/private_iis.h
new file mode 100644
index 0000000..1fa7202
--- /dev/null
+++ b/cpu/br28/private_iis.h
@@ -0,0 +1,27 @@
+#ifndef __PRIVATE_IIS_H
+#define __PRIVATE_IIS_H
+
+#include "cpu.h"
+
+// #define PRIVATE_IIS_RX_SR 44100
+#define PRIVATE_MESSAGE_SIZE 512 //接收消息
+#define PRIVATE_IIS_CMD 0x12345678
+
+#define PRIVATE_IIS_TX_LINEIN_CH_IDX (AUDIO_ADC_LINE1 | AUDIO_ADC_LINE0)
+#define PRIVATE_IIS_TX_LINEIN_GAIN 4
+
+//定义命令的长度为多少字节, 变量个数* 变量类型字节数
+#define CMD_LEN 4 * 4
+
+
+void private_iis_rx_open(void);
+u8 get_private_iis_get_msg_flag(void);
+void show_private_msg(void);
+void private_iis_rx_close(void);
+
+void private_iis_tx_open(void);
+void private_iis_tx_close(void);
+
+
+#endif
+
diff --git a/cpu/br28/pwm_led.c b/cpu/br28/pwm_led.c
new file mode 100644
index 0000000..1d0eb7a
--- /dev/null
+++ b/cpu/br28/pwm_led.c
@@ -0,0 +1,1918 @@
+/* #define __LOG_LEVEL __LOG_WARN */
+/*#define __LOG_LEVEL __LOG_DEBUG*/
+/*#define __LOG_LEVEL __LOG_VERBOSE*/
+#define __LOG_LEVEL __LOG_INFO
+
+#include "generic/gpio.h"
+#include "asm/includes.h"
+#include "asm/pwm_led.h"
+#include "asm/power/p11.h"
+#include "asm/power/p33.h"
+#include "system/timer.h"
+#include "app_config.h"
+#include "classic/tws_api.h"
+
+/*******************************************************************
+* 推灯注意事项:
+* 1)PWM_CON1的BIT(4), OUT_LOGIC位一定要设置为1;
+* 2)PWM_CON1的BIT(0), PWM0_INV位一定要设置为0;
+* 3)在非呼吸灯效果下, 单IO双LED模式, PWM_PRD_DIV寄存器和PWM_BRI_PRD设置成相同值;
+* 4)在闪灯模式下, PWM_BRI_PRD(亮度值)固定下来后, PWM0的BRI_DUTY0和BRI_DUTY1一定不能超过PWM_BRI_PRD;
+*********************************************************************/
+/* #ifdef SUPPORT_MS_EXTENSIONS */
+/* #pragma bss_seg( ".pwm_led_bss") */
+/* #pragma data_seg( ".pwm_led_data") */
+/* #pragma const_seg( ".pwm_led_const") */
+/* #pragma code_seg( ".pwm_led_code") */
+/* #endif */
+
+//#define PWM_LED_TEST_MODE //LED模块测试函数
+
+//#define PWM_LED_DEBUG_ENABLE
+#ifdef PWM_LED_DEBUG_ENABLE
+#define led_debug(fmt, ...) g_printf("[PWM_LED] "fmt, ##__VA_ARGS__)
+#define led_err(fmt, ...) r_printf("[PWM_LED_ERR] "fmt, ##__VA_ARGS__)
+#else
+#define led_debug(...)
+#define led_err(...)
+#endif
+
+//////////////////////////////////////////////////////////////
+#define PWM_LED_SFR SFR
+
+//========================= 0.模块开关相关寄存器
+#define LED_PWM_ENABLE (JL_PLED->CON0 |= BIT(0))
+#define LED_PWM_DISABLE (JL_PLED->CON0 &= ~BIT(0))
+#define IS_PWM_LED_ON (JL_PLED->CON0 & BIT(0))
+
+#define RESET_PWM_CON0 (JL_PLED->CON0 = 0)
+#define RESET_PWM_CON1 (JL_PLED->CON1 = 0)
+#define RESET_PWM_CON2 (JL_PLED->CON2 = 0)
+#define RESET_PWM_CON3 (JL_PLED->CON3 = 0)
+
+//========================= 1.时钟设置相关寄存器
+//PWM0 CLK DIV
+#define CLK_DIV_1 0
+#define CLK_DIV_4 1
+#define CLK_DIV_16 2
+#define CLK_DIV_64 3
+
+#define CLK_DIV_x2(x) (0x04 | x)
+#define CLK_DIV_x256(x) (0x08 | x)
+#define CLK_DIV_x2_x256(x) (0x0c | x)
+//SOURCE
+//SOURCE -- DIV --> PWM0
+//[1:0] 00:div1 01:div4 10:div16 11:div64
+//[2]: 0:x1 1:x2
+//[3]: 0:x1 1:x256
+//DIV = [1:0] * [2] * [3]
+#define LED_PWM0_CLK_DIV(x) PWM_LED_SFR(JL_PLED->CON0, 4, 4, x)
+//PWM0 -- DIV --> PWM1
+//PWM_CON3[3:0] -- PWM_PRD_DIVL[7:0] //12bit
+#define LED_PWM1_CLK_DIV(x) {do {JL_PLED->PRD_DIVL = ((x-1) & 0xFF); JL_PLED->CON3 &= ~(0xF); JL_PLED->CON3 |= (((x-1) >> 8) & 0xF);} while(0);}
+
+//========================= 2.亮度设置相关寄存器
+//最高亮度级数设置
+//PWM_BRI_PRDH[1:0] -- PWM_BRI_PRDL[7:0] //10bit
+#define LED_BRI_DUTY_CYCLE(x) {do {JL_PLED->BRI_PRDL = (x & 0xFF); JL_PLED->BRI_PRDH = ((x >> 8) & 0x3);} while(0);}
+//高电平亮灯亮度设置
+#define LED_BRI_DUTY1_SET(x) {do {JL_PLED->BRI_DUTY0L = (x & 0xFF); JL_PLED->BRI_DUTY0H = ((x >> 8) & 0x3);} while(0);}
+//低电平亮灯亮度设置
+#define LED_BRI_DUTY0_SET(x) {do {JL_PLED->BRI_DUTY1L = (x & 0xFF); JL_PLED->BRI_DUTY1H = ((x >> 8) & 0x3);} while(0);}
+//同步LED0 <-- LED1亮度
+#define LED_BRI_DUTY0_SYNC1() {do {JL_PLED->BRI_DUTY0L = JL_PLED->BRI_DUTY1L; JL_PLED->BRI_DUTY0H = JL_PLED->BRI_DUTY1H;} while(0);}
+//同步LED1 <-- LED0亮度
+#define LED_BRI_DUTY1_SYNC0() {do {JL_PLED->BRI_DUTY1L = JL_PLED->BRI_DUTY0L; JL_PLED->BRI_DUTY1H = JL_PLED->BRI_DUTY0H;} while(0);}
+
+
+//========================= 3.亮灭设置相关寄存器
+//duty_cycle 固定为255或者设置PWM_DUTY3, 8bit
+// _duty1_ _duty3_
+// | | | |
+// | | | |
+//0__ __ duty0| | __ duty2| |__ __255/PWM_DUTY3
+
+//PWM1 duty_cycle 选择
+#define LED_PWM1_DUTY_FIX_SET (JL_PLED->CON1 &= ~BIT(3)) //固定PWM1周期为0xFF
+#define LED_PWM1_DUTY_VARY_SET(x) {do {JL_PLED->CON1 |= BIT(3); JL_PLED->DUTY3 = x;} while(0);}
+
+#define LED_PWM1_DUTY0_SET(x) (JL_PLED->DUTY0 = x)
+#define LED_PWM1_DUTY1_SET(x) (JL_PLED->DUTY1 = x)
+#define LED_PWM1_DUTY2_SET(x) (JL_PLED->DUTY2 = x)
+#define LED_PWM1_DUTY3_SET(x) (JL_PLED->DUTY3 = x) //可以设置为PWM1_DUTY_CYCLE
+#define LED_PWM1_PRD_SEL_DIS (JL_PLED->CON1 &= ~BIT(3))
+
+#define LED_PWM1_PRD_SEL_EN (JL_PLED->CON1 |= BIT(3))
+#define LED_PWM1_DUTY0_EN (JL_PLED->CON1 |= BIT(4))
+#define LED_PWM1_DUTY1_EN (JL_PLED->CON1 |= BIT(5))
+#define LED_PWM1_DUTY2_EN (JL_PLED->CON1 |= BIT(6))
+#define LED_PWM1_DUTY3_EN (JL_PLED->CON1 |= BIT(7))
+
+#define LED_PWM1_ALL_DUTY_DIS (JL_PLED->CON1 &= ~(0xF << 4))
+#define LED_PWM1_DUTY0_DIS (JL_PLED->CON1 &= ~BIT(4))
+#define LED_PWM1_DUTY1_DIS (JL_PLED->CON1 &= ~BIT(5))
+#define LED_PWM1_DUTY2_DIS (JL_PLED->CON1 &= ~BIT(6))
+#define LED_PWM1_DUTY3_DIS (JL_PLED->CON1 &= ~BIT(7))
+
+//========================= 5.输出取反相关寄存器
+//以下几个需要设置为固定值
+#define LED_PWM0_INV_DISABLE (JL_PLED->CON1 &= ~BIT(0))
+#define LED_PWM1_INV_DISABLE (JL_PLED->CON1 &= ~BIT(1)) //周期从灭灯开始
+#define LED_PWM1_INV_ENABLE (JL_PLED->CON1 |= BIT(1)) //周期从亮灯开始
+#define LED_PWM_OUT_LOGIC_SET (JL_PLED->CON3 |= BIT(4))
+//以下几个可以灵活设置
+#define LED_PWM_OUTPUT_INV_ENABLE (JL_PLED->CON1 |= BIT(2))
+#define LED_PWM_OUTPUT_INV_DISABLE (JL_PLED->CON1 &= ~BIT(2))
+
+//========================= 6.与周期变色相关寄存器
+#define LED_PWM_SHIFT_DUTY_SET(x) PWM_LED_SFR(JL_PLED->CON2, 4, 4, x)
+
+//========================= 7.与驱动强度相关寄存器
+#define LED_PWM_IO_MAX_DRIVE(x) PWM_LED_SFR(JL_PLED->CON2, 0, 2, x)
+
+//========================= 8.与中断相关寄存器
+#define LED_PWM_INT_EN (JL_PLED->CON3 |= BIT(5))
+#define LED_PWM_INT_DIS (JL_PLED->CON3 &= ~BIT(5))
+#define LED_PWM_CLR_PENDING (JL_PLED->CON3 |= BIT(6))
+
+//========================= 9.与呼吸模式相关寄存器
+#define LED_PWM_BREATHE_ENABLE (JL_PLED->CON0 |= BIT(1))
+#define LED_PWM_BREATHE_DISABLE (JL_PLED->CON0 &= ~BIT(1))
+//LED呼吸灭灯延时设置, 16bit
+#define LED_PWM_BREATHE_BLANK_TIME_SET(x) {do {LED_PWM1_DUTY2_EN; LED_PWM1_DUTY3_EN; LED_PWM1_DUTY2_SET((x & 0xFF)); LED_PWM1_DUTY3_SET((x >> 8) & 0xFF)} while(0)}
+//LED呼吸灯(低电平灯)最高亮度延时设置, 8bit
+#define LED0_PWM_BREATHE_LIGHT_TIME_SET(x) {do {LED_PWM1_DUTY0_EN; LED_PWM1_DUTY0_SET(x)} while(0)}
+//LED呼吸灯(高电平灯)最高亮度延时设置, 8bit
+#define LED1_PWM_BREATHE_LIGHT_TIME_SET(x) {do {LED_PWM1_DUTY1_EN; LED_PWM1_DUTY1_SET(x)} while(0)}
+
+
+#define PLED_CNT_READ_KICK_START() (JL_PLED->CON4 |= BIT(4))
+#define PLED_CNT_READ_WAIT_READY() while(!(JL_PLED->CON4 & BIT(5)))
+#define PLED_GET_READ_CNT() (JL_PLED->CNT_RD)
+#define PLED_LOCAL_SYNC_REMOTE(v) (JL_PLED->CNT_SYNC = v)
+#define PLED_LOCAL_SYNC_DEC_CNT(v) (JL_PLED->CNT_DEC = v)
+
+struct pwm_led {
+ u8 init;
+ u8 led_pin;
+ u8 clock;
+ u8 last_mode;
+ const struct led_platform_data *user_data;
+ //中断相关
+ void (*pwm_led_extern_isr)(void);
+ void (*pwm_led_local_isr)(void);
+#ifdef PWM_LED_TWO_IO_SUPPORT
+ u8 display_index;
+#endif /* #ifdef PWM_LED_TWO_IO_SUPPORT */
+};
+
+enum _PWM0_CLK {
+ PWM0_CLK_32K, //for rc normal
+ //BT24M
+ PWM0_CLK_46K, //24M / 512 = 46875, for normal period < 22s
+ PWM0_CLK_23K, //24M / 1024 = 23437, for normal period > 22s
+};
+
+//#define PWM0_RC_CLK32K_VALUE 32000
+extern u32 __get_lrc_hz(void);
+#define PWM0_RC_CLK32K_VALUE (__get_lrc_hz() / 4)
+#define PWM0_BT_CLK23K_VALUE 23437
+#define PWM0_BT_CLK46K_VALUE 46875
+
+#define PWM_LED_USER_DEFINE_MODE 0xFE
+
+static struct pwm_led _led;
+
+#define __this (&_led)
+
+static void _pwm_led_display_mode(u8 display);
+static void _led_pwm1_duty_set(u8 duty_prd, u8 duty0, u8 duty1, u8 duty2, u8 breathe);
+static void pwm_led_16slot_timer_free(void);
+static void pwm_led_one_io_mode_slot_timer_display(u8 display);
+
+
+//=================================================================================//
+// P11_P2M_CLK_CON0[7 : 5]:
+// 000: None;
+// 001: RC_250K, open @ P3_ANA_CON0[7];
+// 010: RC_16M, open @ P11_CLK_CON0[1];
+// 011: LRC_OSC_200K, open @ P3_LRC_CON0[0]
+// 100: RTC_OSC;
+// 101: SYS_CLK;
+//=================================================================================//
+static void pwm_clock_set(u8 _clock)
+{
+ u8 clock = _clock;
+ u8 clk_val = 0;
+
+ switch (clock) {
+ case PWM_LED_CLK_RC32K:
+ //RC_32K
+ clk_val = 0b011; //LRC_OSC_200K
+ /* P3_LRC_CON0 |= BIT(0); //Enable this clock */
+
+ //RC_16M
+ /* clk_val = 0b010; */
+ /* P11_CLK_CON0 |= BIT(1); //Enable this clock */
+
+ //RC_250K
+ /* clk_val = 0b001; */
+ /* P3_ANA_CON0 |= BIT(7); //Enable this clock */
+ break;
+ case PWM_LED_CLK_BTOSC_24M:
+ //SYS_CLK:
+ clk_val = 0b101;
+ break;
+
+ default:
+ break;
+ }
+
+ //MO Note: Make sure P11 part have been patch key
+ P11_P2M_CLK_CON0 &= ~(0b111 << 5);
+ P11_P2M_CLK_CON0 |= (clk_val << 5);
+ __this->clock = clock;
+ led_debug("clock = 0x%x, clk_val= %d, P11_P2M_CLK_CON0 = 0x%x", __this->clock, clk_val, ((P11_P2M_CLK_CON0 >> 5) & 0b111));
+}
+
+
+/*
+ * IO使能注意, 否则有可能会出现在显示效果前会出现闪烁
+ * 1)设置PU, PD为1;
+ * 2)设置DIR, OUT为1;
+ * 3)最后设置为方向为输出;
+ */
+static void led_pin_set_enable(u8 gpio)
+{
+ gpio_set_pull_up(gpio, 1);
+ gpio_set_pull_down(gpio, 1);
+ gpio_set_die(gpio, 1);
+
+ gpio_set_output_value(gpio, 1);
+ gpio_set_direction(gpio, 0);
+}
+
+//把IO设置为高阻
+static void led_pin_set_disable(u8 disable_pin)
+{
+ gpio_set_pull_down(disable_pin, 0);
+ gpio_set_pull_up(disable_pin, 0);
+ gpio_direction_input(disable_pin);
+}
+
+
+___interrupt
+static void pwm_led_isr_func(void)
+{
+ LED_PWM_CLR_PENDING;
+ led_debug("led isr");
+ if (__this->pwm_led_extern_isr) {
+ __this->pwm_led_extern_isr();
+ }
+ if (__this->pwm_led_local_isr) {
+ __this->pwm_led_local_isr();
+ }
+}
+
+//index = 1: 内部切IO中断;
+//index = 0: 外部注册中断;
+static void _pwm_led_register_irq(void (*func)(void), u8 index)
+{
+ LED_PWM_INT_DIS;
+ LED_PWM_CLR_PENDING;
+
+ if (func) {
+ if (index) {
+ __this->pwm_led_local_isr = func;
+ } else {
+ __this->pwm_led_extern_isr = func;
+ }
+ request_irq(IRQ_PWM_LED_IDX, 1, pwm_led_isr_func, 0);
+ LED_PWM_INT_EN;
+ }
+}
+
+
+static void _pwm_led_close_irq(void)
+{
+ __this->pwm_led_extern_isr = NULL;
+ __this->pwm_led_local_isr = NULL;
+ LED_PWM_INT_DIS;
+}
+
+
+void pwm_led_init(const struct led_platform_data *user_data)
+{
+ led_debug("pwm led init ...");
+
+ memset(__this, 0, sizeof(struct pwm_led));
+
+ LED_PWM_DISABLE;
+ LED_PWM_BREATHE_DISABLE; //呼吸灯使能位
+
+ RESET_PWM_CON0;
+ RESET_PWM_CON1;
+ RESET_PWM_CON2;
+ RESET_PWM_CON3;
+
+ LED_PWM_OUT_LOGIC_SET;
+ LED_PWM_CLR_PENDING;
+
+ pwm_clock_set(PWM_LED_CLK_RC32K);
+ //pwm_clock_set(PWM_LED_CLK_BTOSC_24M);
+
+ if (user_data->io_mode == LED_ONE_IO_MODE) {
+ __this->led_pin = user_data->io_cfg.one_io.pin;
+ led_pin_set_enable(user_data->io_cfg.one_io.pin); //一个IO推两个灯
+ }
+
+ __this->user_data = user_data;
+ __this->last_mode = PWM_LED_ALL_OFF;
+
+ __this->init = 1;
+}
+
+//prd: 亮度总级数
+//duty: 设置亮度级数
+//实际输出频率 = Flrc / prd
+//输出占空比: duty /prd
+//gpio: 设置输出的IO
+//注意:duty不能大于prd,并且prd和duty是非标准非线性的,建议用示波器看着来调
+int pwm_led_output_clk(u8 gpio, u8 prd, u8 duty)
+{
+ RESET_PWM_CON0;
+ RESET_PWM_CON1;
+ RESET_PWM_CON2;
+ RESET_PWM_CON3;
+
+ pwm_clock_set(PWM_LED_CLK_RC32K);
+ LED_PWM0_CLK_DIV(0);
+
+ duty = duty > prd ? prd : duty;
+
+ LED_BRI_DUTY_CYCLE(prd);
+ LED_BRI_DUTY1_SET(duty);
+ LED_BRI_DUTY0_SET(duty);
+
+ LED_PWM1_INV_ENABLE;
+
+ /* LED_PWM1_DUTY0_SET(1); */
+ /* LED_PWM1_DUTY0_EN; */
+
+ LED_PWM_OUT_LOGIC_SET;
+
+ LED_PWM1_CLK_DIV(200);
+ led_pin_set_enable(gpio);
+ LED_PWM_ENABLE;
+
+ return 0;
+}
+
+void log_pwm_led_info()
+{
+ led_debug("======== PWM LED CONFIG ======");
+ led_debug("P11_P2M_CLK_CON0 = 0x%x, lrc = %d", P11_P2M_CLK_CON0, __get_lrc_hz());
+ led_debug("PWM_CON0 = 0x%x", JL_PLED->CON0);
+ led_debug("PWM_CON1 = 0x%x", JL_PLED->CON1);
+ led_debug("PWM_CON2 = 0x%x", JL_PLED->CON2);
+ led_debug("PWM_CON3 = 0x%x", JL_PLED->CON3);
+ led_debug("PRD_DIVL = 0x%x", JL_PLED->PRD_DIVL);
+
+ led_debug("BRI_PRDL = 0x%x", JL_PLED->BRI_PRDL);
+ led_debug("BRI_PRDH = 0x%x", JL_PLED->BRI_PRDH);
+
+ led_debug("BRI_DUTY0L = 0x%x", JL_PLED->BRI_DUTY0L);
+ led_debug("BRI_DUTY0H = 0x%x", JL_PLED->BRI_DUTY0H);
+
+ led_debug("BRI_DUTY1L = 0x%x", JL_PLED->BRI_DUTY1L);
+ led_debug("BRI_DUTY1H = 0x%x", JL_PLED->BRI_DUTY1H);
+
+ led_debug("PWM1_DUTY0 = 0x%x", JL_PLED->DUTY0);
+ led_debug("PWM1_DUTY1 = 0x%x", JL_PLED->DUTY1);
+ led_debug("PWM1_DUTY2 = 0x%x", JL_PLED->DUTY2);
+ led_debug("PWM1_DUTY3 = 0x%x", JL_PLED->DUTY3);
+}
+
+
+/**
+ * @brief: pwm0 时钟设置
+ * 默认RC = 32K,
+ * 呼吸BT24M = 93750Hz
+ * 普通BT24M = 46875Hz/23437Hz
+ *
+ * @param: clk0
+ * @return int
+ */
+static int _led_pwm0_clk_set(enum _PWM0_CLK clk0)
+{
+ u8 pwm0_clk_div_val = 0;
+
+ if (__this->clock == PWM_LED_CLK_RC32K) {
+ if (clk0 != PWM0_CLK_32K) {
+ return -1;
+ }
+ //RC32k div 1 = 32k
+ //pwm0_clk_div_val = CLK_DIV_1;
+ //RC200k div 4 = 50k
+ pwm0_clk_div_val = CLK_DIV_4;
+
+ //RC16M div 512 = 32k
+ /* pwm0_clk_div_val = CLK_DIV_x2(CLK_DIV_1) | CLK_DIV_x256(CLK_DIV_1); */
+
+ //RC250K div 8 = 32k
+ /* pwm0_clk_div_val = CLK_DIV_x2(CLK_DIV_4); */
+ } else if (__this->clock == PWM_LED_CLK_BTOSC_24M) {
+#if CONFIG_FPGA_ENABLE
+ //12M
+ if (clk0 == PWM0_CLK_46K) {
+ pwm0_clk_div_val = CLK_DIV_x256(CLK_DIV_1); //12M div 256 = 46875Hz
+ } else if (clk0 == PWM0_CLK_23K) {
+ pwm0_clk_div_val = CLK_DIV_x256(CLK_DIV_x2(CLK_DIV_1)); //12M div 512 = 23437Hz
+ } else {
+ return -1;
+ }
+#else
+ if (clk0 == PWM0_CLK_46K) {
+ pwm0_clk_div_val = CLK_DIV_x256(CLK_DIV_x2(CLK_DIV_1)); //24M div 512 = 46875Hz
+ } else if (clk0 == PWM0_CLK_23K) {
+ pwm0_clk_div_val = CLK_DIV_x256(CLK_DIV_4); //24M div 1024 = 23437Hz
+ } else {
+ return -1;
+ }
+#endif /* #if CONFIG_FPGA_ENABLE */
+ }
+
+ LED_PWM0_CLK_DIV(pwm0_clk_div_val);
+
+ return 0;
+}
+
+
+
+static void led_pwm_pre_set()
+{
+ LED_PWM_DISABLE;
+ LED_PWM_BREATHE_DISABLE;
+}
+
+
+#ifdef PWM_LED_TWO_IO_SUPPORT
+
+static void _change_io_display(void)
+{
+ u8 disable_pin = 0;
+ u8 enable_pin = 0;
+ if (__this->display_index == 0) {
+ enable_pin = __this->user_data->io_cfg.two_io.pin1;
+ disable_pin = __this->user_data->io_cfg.two_io.pin0;
+ __this->display_index = 1;
+ } else {
+ enable_pin = __this->user_data->io_cfg.two_io.pin0;
+ disable_pin = __this->user_data->io_cfg.two_io.pin1;
+ __this->display_index = 0;
+ }
+
+ led_pin_set_disable(disable_pin);
+ led_pin_set_enable(enable_pin);
+}
+
+static void pwm_led_two_io_mode_display(u8 display)
+{
+ u8 change_mode = 0;
+ u8 isr_mode = 0;
+
+ led_pin_set_disable(__this->user_data->io_cfg.two_io.pin0);
+ led_pin_set_disable(__this->user_data->io_cfg.two_io.pin1);
+
+ switch (display) {
+ case PWM_LED_ALL_OFF:
+ case PWM_LED0_OFF:
+ case PWM_LED1_OFF:
+ _pwm_led_display_mode(PWM_LED_ALL_OFF);
+ break;
+
+ case PWM_LED1_ON:
+ case PWM_LED1_SLOW_FLASH:
+ case PWM_LED1_FAST_FLASH:
+ case PWM_LED1_ONE_FLASH_5S:
+ case PWM_LED1_DOUBLE_FLASH_5S:
+ case PWM_LED1_BREATHE:
+ led_pin_set_enable(__this->user_data->io_cfg.two_io.pin1);
+ _pwm_led_display_mode(display);
+ break;
+
+ case PWM_LED0_ON:
+ change_mode = PWM_LED1_ON;
+ break;
+ case PWM_LED0_SLOW_FLASH:
+ change_mode = PWM_LED1_SLOW_FLASH;
+ break;
+ case PWM_LED0_FAST_FLASH:
+ change_mode = PWM_LED1_FAST_FLASH;
+ break;
+ case PWM_LED0_ONE_FLASH_5S:
+ change_mode = PWM_LED1_ONE_FLASH_5S;
+ break;
+ case PWM_LED0_DOUBLE_FLASH_5S:
+ change_mode = PWM_LED1_DOUBLE_FLASH_5S;
+ break;
+ case PWM_LED0_BREATHE:
+ change_mode = PWM_LED1_BREATHE;
+ break;
+ case PWM_LED_ALL_ON:
+ _pwm_led_display_mode(PWM_LED1_ON);
+ led_pin_set_enable(__this->user_data->io_cfg.two_io.pin0);
+ led_pin_set_enable(__this->user_data->io_cfg.two_io.pin1);
+ break;
+/////////////
+
+//双灯互闪
+ case PWM_LED0_LED1_FAST_FLASH: //使用中断切灯
+ isr_mode = PWM_LED1_FAST_FLASH;
+ break;
+ case PWM_LED0_LED1_SLOW_FLASH:
+ isr_mode = PWM_LED1_SLOW_FLASH;
+ break;
+//呼吸模式
+ case PWM_LED0_LED1_BREATHE: //使用中断切灯
+ isr_mode = PWM_LED1_BREATHE;
+ break;
+
+ default:
+ break;
+ }
+ if (change_mode) {
+ _pwm_led_display_mode(change_mode);
+ LED_PWM_DISABLE;
+ LED_BRI_DUTY1_SYNC0();
+ led_pin_set_enable(__this->user_data->io_cfg.two_io.pin0);
+ LED_PWM_ENABLE;
+ }
+ if (isr_mode) {
+ _pwm_led_display_mode(isr_mode);
+ _led_pwm1_duty_set(0xFF, 2, 0, 0, 0); //占满整个周期
+ _pwm_led_register_irq(_change_io_display, 0);
+ led_pin_set_enable(__this->user_data->io_cfg.two_io.pin0);
+ __this->display_index = 0;
+ }
+}
+
+static void _pwm_led_two_io_user_define_mode(u8 led_index)
+{
+ led_pwm_pre_set(); //led disable
+ led_pin_set_disable(__this->user_data->io_cfg.two_io.pin0);
+ led_pin_set_disable(__this->user_data->io_cfg.two_io.pin1);
+
+ if (led_index == 0) {
+ led_pin_set_enable(__this->user_data->io_cfg.two_io.pin0);
+ } else if (led_index == 1) {
+ led_pin_set_enable(__this->user_data->io_cfg.two_io.pin1);
+ } else if (led_index == 2) {
+ //双灯互闪切换
+ __this->display_index = 0;
+ led_pin_set_enable(__this->user_data->io_cfg.two_io.pin0);
+ _pwm_led_register_irq(_change_io_display, 0);
+ }
+}
+
+#if TCFG_PWMLED_USE_SLOT_TIME
+static void pwm_led_two_io_mode_slot_timer_display(u8 display)
+{
+ u8 change_mode = 0;
+ u8 isr_mode = 0;
+ pwm_led_16slot_timer_free();
+
+ led_pin_set_disable(__this->user_data->io_cfg.two_io.pin0);
+ led_pin_set_disable(__this->user_data->io_cfg.two_io.pin1);
+
+ switch (display) {
+ case PWM_LED_ALL_OFF:
+ case PWM_LED0_OFF:
+ case PWM_LED1_OFF:
+ pwm_led_one_io_mode_slot_timer_display(display);
+ break;
+
+ case PWM_LED1_ON:
+ case PWM_LED1_SLOW_FLASH:
+ case PWM_LED1_FAST_FLASH:
+ case PWM_LED1_ONE_FLASH_5S:
+ case PWM_LED1_DOUBLE_FLASH_5S:
+ case PWM_LED1_BREATHE:
+ led_pin_set_enable(__this->user_data->io_cfg.two_io.pin1);
+ pwm_led_one_io_mode_slot_timer_display(display);
+ break;
+
+ case PWM_LED0_ON:
+ change_mode = PWM_LED1_ON;
+ break;
+ case PWM_LED0_SLOW_FLASH:
+ change_mode = PWM_LED1_SLOW_FLASH;
+ break;
+ case PWM_LED0_FAST_FLASH:
+ change_mode = PWM_LED1_FAST_FLASH;
+ break;
+ case PWM_LED0_ONE_FLASH_5S:
+ change_mode = PWM_LED1_ONE_FLASH_5S;
+ break;
+ case PWM_LED0_DOUBLE_FLASH_5S:
+ change_mode = PWM_LED1_DOUBLE_FLASH_5S;
+ break;
+ case PWM_LED0_BREATHE:
+ change_mode = PWM_LED1_BREATHE;
+ break;
+ case PWM_LED_ALL_ON:
+ pwm_led_one_io_mode_slot_timer_display(display);
+ led_pin_set_enable(__this->user_data->io_cfg.two_io.pin0);
+ led_pin_set_enable(__this->user_data->io_cfg.two_io.pin1);
+ break;
+/////////////
+
+//双灯互闪
+ case PWM_LED0_LED1_FAST_FLASH: //使用中断切灯
+ isr_mode = PWM_LED1_FAST_FLASH;
+ break;
+ case PWM_LED0_LED1_SLOW_FLASH:
+ isr_mode = PWM_LED1_SLOW_FLASH;
+ break;
+//呼吸模式
+ case PWM_LED0_LED1_BREATHE: //使用中断切灯
+ pwm_led_two_io_mode_display(display);
+ break;
+
+ default:
+ break;
+ }
+ if (change_mode) {
+ pwm_led_one_io_mode_slot_timer_display(display);
+ LED_PWM_DISABLE;
+ LED_BRI_DUTY1_SYNC0();
+ led_pin_set_enable(__this->user_data->io_cfg.two_io.pin0);
+ }
+ if (isr_mode) {
+ pwm_led_one_io_mode_slot_timer_display(isr_mode);
+ led_pin_set_enable(__this->user_data->io_cfg.two_io.pin0);
+ }
+}
+#endif /* #if TCFG_PWMLED_USE_SLOT_TIME */
+
+#else
+static void pwm_led_two_io_mode_display(u8 display)
+{
+ return;
+}
+
+
+static void pwm_led_two_io_mode_slot_timer_display(u8 display)
+{
+ return;
+}
+#endif /* #ifdef PWM_LED_TWO_IO_SUPPORT */
+
+static void pwm_led_one_io_mode_display(u8 display)
+{
+ _pwm_led_display_mode(display);
+}
+
+/////////////////////////////
+/**
+ * @brief: 设置led灯亮度
+ * @param: bri_max, 最大亮度, 10bit, 0 ~ 1023
+ * @param: bri_duty0, LED0亮度, 10bit, 0 ~ 1023
+ * @param: bri_duty1, LED1亮度, 10bit, 0 ~ 1023
+ *
+ * @return void
+ */
+static void _led_pwm_bright_set(u16 bri_max, u16 bri_duty0, u16 bri_duty1)
+{
+ bri_max = bri_max >= 1024 ? 1023 : bri_max;
+ bri_duty0 = bri_duty0 >= 1024 ? 1023 : bri_duty0;
+ bri_duty1 = bri_duty1 >= 1024 ? 1023 : bri_duty1;
+
+ bri_duty0 = bri_duty0 >= bri_max ? bri_max : bri_duty0;
+ bri_duty1 = bri_duty1 >= bri_max ? bri_max : bri_duty1;
+
+ LED_BRI_DUTY_CYCLE(bri_max);
+ LED_BRI_DUTY0_SET(bri_duty0);
+ LED_BRI_DUTY1_SET(bri_duty1);
+}
+
+
+/**
+ * @brief: 设置PWM输出逻辑,
+ * @param: pwm_inv_en, 最后pwm波形输出逻辑(默认是高电平灯亮),
+ 0: 不取反, 高电平灯亮; 1: 取反, 低电平灯亮;
+ * @param: shift_num
+ 是否需要互闪,
+ 0: 单闪; 1 ~ : 互闪;
+ *
+ * @return void
+ */
+static void _led_pwm_output_logic_set(u8 pwm_inv_en, u8 shift_num)
+{
+ if (pwm_inv_en) {
+ LED_PWM_OUTPUT_INV_ENABLE;
+ } else {
+ LED_PWM_OUTPUT_INV_DISABLE;
+ }
+ LED_PWM_OUT_LOGIC_SET;
+ LED_PWM_SHIFT_DUTY_SET(shift_num);
+}
+
+/**
+ * @brief: 设置PWM1亮灭设置, 可以实现一个周期亮灭1次和2次,
+ * @param: pwm_inv_en, 最后pwm波形输出逻辑(默认是高电平灯亮),
+ 0: 不取反, 高电平灯亮; 1: 取反, 低电平灯亮;
+ * @param: shift_num
+ 是否需要互闪,
+ 0: 单闪; 1 ~ : 互闪;
+ *duty_cycle 固定为255或者设置PWM_DUTY3, 8bit
+ * _duty1_ _duty3_
+ * | | | |
+ * | | | |
+ *0__ __ duty0| | __ duty2| |__ __255/PWM_DUTY3
+ * @return void
+ */
+static void _led_pwm1_duty_set(u8 duty_prd, u8 duty0, u8 duty1, u8 duty2, u8 breathe)
+{
+ if (duty_prd != 0xFF) {
+ if (breathe == 0) {
+ duty0 = duty0 > duty_prd ? duty_prd : duty0;
+ duty1 = duty1 > duty_prd ? duty_prd : duty1;
+ duty2 = duty2 > duty_prd ? duty_prd : duty2;
+ LED_PWM1_PRD_SEL_EN;
+ LED_PWM1_DUTY3_DIS;
+ } else {
+ LED_PWM1_PRD_SEL_DIS; //呼吸模式, duty0/1是亮灯延时, {duty3,duty2}是灭灯延时
+ LED_PWM1_DUTY3_EN;
+ }
+
+ LED_PWM1_DUTY3_SET(duty_prd);
+ } else {
+ LED_PWM1_PRD_SEL_DIS;
+ LED_PWM1_DUTY3_DIS;
+ }
+ if (duty0) {
+ LED_PWM1_DUTY0_SET(duty0);
+ LED_PWM1_DUTY0_EN;
+ } else {
+ LED_PWM1_DUTY0_DIS;
+ }
+ if (duty1) {
+ LED_PWM1_DUTY1_SET(duty1);
+ LED_PWM1_DUTY1_EN;
+ } else {
+ LED_PWM1_DUTY1_DIS;
+ }
+ if (duty2) {
+ LED_PWM1_DUTY2_SET(duty2);
+ LED_PWM1_DUTY2_EN;
+ } else {
+ LED_PWM1_DUTY2_DIS;
+ }
+}
+
+
+/**
+ * @brief:
+ * @param: module_en = 0, breathe_en = 0, 关LED模块
+ * @param: module_en = 0, breathe_en = 1, 关LED模块
+ * @param: module_en = 1, breathe_en = 0, 开LED普通闪烁模式
+ * @param: module_en = 1, breathe_en = 1, 开LED呼吸模式
+ * @return void
+ */
+static void _led_pwm_module_enable(u8 module_en, u8 breathe_en)
+{
+ if (breathe_en) {
+ LED_PWM_BREATHE_ENABLE;
+ } else {
+ LED_PWM_BREATHE_DISABLE;
+ }
+
+ if (module_en) {
+ LED_PWM_ENABLE;
+ } else {
+ LED_PWM_DISABLE;
+ }
+}
+
+/**
+ * @brief: 设置pwm0时钟分频
+ * clk0_div
+ * pwm0_clk --------> pwm1_clk
+ * @param: clk0_div, 12bit, 0 ~ 4095
+ *
+ * @return void
+ */
+static void _led_pwm1_clk_set(u16 clk0_div)
+{
+ clk0_div = clk0_div > 4096 ? 4096 : clk0_div;
+ LED_PWM1_CLK_DIV(clk0_div);
+}
+
+/**
+ * @brief: 关 led 配置, 亮度也设置为0
+ *
+ * @param led_index: 0: led0, 1:led1, 2:led0 & led1
+ * @param led0_bright: 0 ~ 100
+ * @param led1_bright: 0 ~ 100
+ *
+ * @return void
+ */
+static void _pwm_led_off_display(void)
+{
+ //TODO: set bright duty 0: avoid set on case
+ led_pwm_pre_set(); //led disable
+ _led_pwm_bright_set(0xFF, 0, 0);
+}
+
+
+
+/**
+ * @brief: led 常亮显示设置
+ * @param led_index: 0: led0, 1:led1, 2:led0 & led1
+ * @param led0_bright, LED0亮度: 0 ~ 500
+ * @param led1_bright, LED1亮度: 0 ~ 500
+ *
+ * @return void
+ */
+static void _pwm_led_on_display(u8 led_index, u16 led0_bright, u16 led1_bright)
+{
+ //step1: pwm0 clock
+ if (__this->clock == PWM_LED_CLK_RC32K) {
+ _led_pwm0_clk_set(PWM0_CLK_32K);
+ } else {
+ _led_pwm0_clk_set(PWM0_CLK_46K);
+ }
+ //step2: pwm1 clock
+ _led_pwm1_clk_set(4);
+
+ //bright set
+ u8 shift_num = 0;
+ u8 out_inv = 0;
+ u16 led0_bri_duty = 0;
+ u16 led1_bri_duty = 0;
+ u16 led_bri_prd = 200;
+
+ led0_bri_duty = led0_bright;
+ led1_bri_duty = led1_bright;
+
+ switch (led_index) {
+ case 0:
+ out_inv = 1;
+ break;
+ case 1:
+ break;
+ case 2:
+ shift_num = 1;
+ led_bri_prd = 160;
+ break;
+ default:
+ led_debug("%s led index err", __func__);
+ return;
+ break;
+ }
+
+ led0_bri_duty = (led0_bri_duty * led_bri_prd) / 500;
+ led1_bri_duty = (led1_bri_duty * led_bri_prd) / 500; //调试数据
+
+ //step3: bright亮度
+ _led_pwm_bright_set(led_bri_prd, led0_bri_duty, led1_bri_duty);
+
+ //step4: 1.输出取反, 2.变色(互闪);
+ _led_pwm_output_logic_set(out_inv, shift_num);
+
+ //step5: 周期亮灭配置
+ //pwm1 duty0, duty1, duty2
+ _led_pwm1_duty_set(40, 2, 0, 0, 0);
+
+ //step6: enable led module
+ _led_pwm_module_enable(1, 0);
+}
+
+static void __pwm_led_flash_common_handle(u8 led_index, u16 led0_bright, u16 led1_bright, u32 period)
+{
+//step1: pwm0 clock
+ u16 pwm0_prd = 500;
+ u16 pwm0_div = 0;
+ if (__this->clock == PWM_LED_CLK_RC32K) {
+ _led_pwm0_clk_set(PWM0_CLK_32K);
+ pwm0_div = (PWM0_RC_CLK32K_VALUE * period) / (1000 * 256);
+ } else {
+ if (period < 22000) {
+ _led_pwm0_clk_set(PWM0_CLK_46K);
+ pwm0_div = (PWM0_BT_CLK46K_VALUE * period) / (1000 * 256);
+ } else {
+ _led_pwm0_clk_set(PWM0_CLK_23K);
+ pwm0_div = (PWM0_BT_CLK23K_VALUE * period) / (1000 * 256);
+ pwm0_prd = 300;
+ led0_bright = (led0_bright * 300) / 500;
+ led1_bright = (led1_bright * 300) / 500;
+ }
+ }
+ //step2: pwm1 clock
+ _led_pwm1_clk_set(pwm0_div);
+
+ //bright set
+ u8 shift_num = 0;
+ u8 out_inv = 0;
+ u16 led0_bri_duty = 0;
+ u16 led1_bri_duty = 0;
+
+ switch (led_index) {
+ case 0:
+ led0_bri_duty = led0_bright;
+ led1_bri_duty = 0;
+ out_inv = 1;
+ break;
+
+ case 1:
+ led0_bri_duty = 0;
+ led1_bri_duty = led1_bright;
+ break;
+ case 2:
+ shift_num = 1;
+ led0_bri_duty = led0_bright;
+ led1_bri_duty = led1_bright;
+ break;
+ default:
+ led_debug("%s led index err", __func__);
+ return;
+ break;
+ }
+
+ //step3: bright亮度
+ _led_pwm_bright_set(pwm0_prd, led0_bri_duty, led1_bri_duty);
+
+ //step4: 1.输出取反, 2.变色(互闪);
+ _led_pwm_output_logic_set(out_inv, shift_num);
+}
+
+/**
+ * @brief: led 周期闪一次显示设置
+ * @param led_index: 0: led0, 1:led1, 2:led0 & led1(互闪)
+ led0_bright: led0亮度(0 ~ 500),
+ led1_bright: led1亮度(0 ~ 500),
+ period: 闪灯周期(ms), 多少ms闪一下(100 ~ 20000), 100ms - 20S,
+ start_light_time: 在周期中开始亮灯的时间, -1: 周期最后亮灯, 默认填-1即可,
+ light_time: 灯亮持续时间,
+ *
+ * @return void
+ */
+static void _pwm_led_one_flash_display(u8 led_index, u16 led0_bright, u16 led1_bright,
+ u32 period, u32 start_light_time, u32 light_time)
+{
+ __pwm_led_flash_common_handle(led_index, led0_bright, led1_bright, period);
+ //step5: 周期亮灭配置
+ //pwm1 duty0, duty1, duty2
+ u8 pwm1_duty0 = 0;
+ u8 pwm1_duty1 = 0;
+ if (start_light_time != -1) {
+ if (start_light_time >= period) {
+ led_err("start_light_time config err");
+ _pwm_led_off_display(); //led off
+ return;
+ }
+ //指定从哪个时间亮,
+ pwm1_duty0 = (256 * start_light_time) / period;
+ pwm1_duty0 = (pwm1_duty0) ? pwm1_duty0 : 2;
+ if ((start_light_time + light_time) > period) {
+ pwm1_duty1 = 0; //只开duty0
+ } else {
+ pwm1_duty1 = (256 * light_time) / period;
+ pwm1_duty1 = (pwm1_duty1) ? pwm1_duty1 : 2;
+ if ((pwm1_duty0 + pwm1_duty1) > 0xFF) {
+ pwm1_duty1 = 0 ;
+ } else {
+ pwm1_duty1 += pwm1_duty0;
+ }
+ }
+ } else {
+ pwm1_duty0 = (256 * light_time) / period;
+ pwm1_duty0 = (pwm1_duty0) ? pwm1_duty0 : 2;
+ pwm1_duty0 = 256 - pwm1_duty0;
+ }
+
+ if ((led_index == 2) && (light_time == -1)) { //互闪, 占满整个周期
+ pwm1_duty0 = 2;
+ pwm1_duty1 = 0;
+ }
+ _led_pwm1_duty_set(0xFF, pwm1_duty0, pwm1_duty1, 0, 0);
+
+ //step6: enable led module
+ _led_pwm_module_enable(1, 0);
+}
+
+
+/**
+ * @brief: led 周期闪一次显示设置
+ * @param led_index: 0: led0, 1:led1, 2:led0 & led1(互闪)
+ led0_bright: led0亮度,
+ led1_bright: led1亮度,
+ period: 闪灯周期(ms), 多少ms闪一下
+ first_light_time: 第一次亮灯持续时间,
+ second_light_time: 第二次亮灯持续时间,
+ gap_time: 两次亮灯时间间隔,
+ * @param led0_bright, LED0亮度: 0 ~ 500
+ * @param led1_bright, LED1亮度: 0 ~ 500
+ *
+ * @return void
+ */
+static void _pwm_led_double_flash_display(u8 led_index, u16 led0_bright, u16 led1_bright,
+ u32 period, u32 first_light_time, u32 gap_time, u32 second_light_time)
+{
+ __pwm_led_flash_common_handle(led_index, led0_bright, led1_bright, period);
+
+ //step5: 周期亮灭配置
+ //pwm1 duty0, duty1, duty2
+ u8 pwm1_duty0 = 0;
+ u8 pwm1_duty1 = 0;
+ u8 pwm1_duty2 = 0;
+
+ pwm1_duty2 = (256 * second_light_time) / period;
+ pwm1_duty2 = (pwm1_duty2) ? (0xFF - pwm1_duty2) : (0xFF - 2);
+
+ pwm1_duty1 = (256 * gap_time) / period;
+ pwm1_duty1 = (pwm1_duty1) ? (pwm1_duty2 - pwm1_duty1) : (pwm1_duty2 - 2);
+
+ pwm1_duty0 = (256 * first_light_time) / period;
+ pwm1_duty0 = (pwm1_duty0) ? (pwm1_duty1 - pwm1_duty0) : (pwm1_duty1 - 2);
+
+ _led_pwm1_duty_set(0xFF, pwm1_duty0, pwm1_duty1, pwm1_duty2, 0);
+
+ //step6: enable led module
+ _led_pwm_module_enable(1, 0);
+}
+
+/**
+ * @brief: led 周期呼吸显示,
+ * @param led_index: 0: led0, 1:led1, 2:led0 & led1(交互呼吸)
+ breathe_time: 呼吸周期(灭->最亮->灭), 设置范围: 500ms以上;
+ led0_bright: led0呼吸到最亮的亮度(0 ~ 500);
+ led1_bright: led1呼吸到最亮的亮度(0 ~ 500);
+ led0_light_delay_time: led0最高亮度延时(0 ~ 100ms);
+ led1_light_delay_time: led1最高亮度延时(0 ~ 100ms);
+ led_blink_delay_time: led0和led1灭灯延时(0 ~ 20000ms), 0 ~ 20S;
+ *
+ * @return void
+ */
+static void _pwm_led_breathe_display(u8 led_index, u16 breathe_time, u16 led0_bright, u16 led1_bright,
+ u32 led0_light_delay_time, u32 led1_light_delay_time, u32 led_blink_delay_time)
+{
+ u16 led0_bri_duty = led0_bright;
+ u16 led1_bri_duty = led1_bright;
+ u16 pwm1_div = 0;
+ u16 Tpwm1 = 0;
+ pwm1_div = led0_bri_duty > led1_bri_duty ? led0_bri_duty : led1_bri_duty;
+
+ breathe_time = breathe_time / 2; //呼吸总时间, 单个灭到最亮的时间
+ //step1: pwm0 clock
+ if (__this->clock == PWM_LED_CLK_RC32K) {
+ _led_pwm0_clk_set(PWM0_CLK_32K);
+ /* pwm1_div = breathe_time * 32 / pwm1_div; */
+ /* Tpwm1 = (pwm1_div * 1000 / 32000); //ms */
+ pwm1_div = breathe_time * (PWM0_RC_CLK32K_VALUE / 1000) / pwm1_div;
+ Tpwm1 = (pwm1_div * 1000 / PWM0_RC_CLK32K_VALUE); //ms
+ } else {
+ _led_pwm0_clk_set(PWM0_CLK_46K);
+ pwm1_div = breathe_time * 46 / pwm1_div;
+ Tpwm1 = (pwm1_div * 1000 / 46000); //ms
+ }
+ //step2: pwm1 clock
+ _led_pwm1_clk_set(pwm1_div);
+
+ //bright set
+ u8 shift_num = 0;
+ u8 out_inv = 0;
+
+ switch (led_index) {
+ case 0:
+ led1_bri_duty = 0;
+ out_inv = 1;
+ break;
+
+ case 1:
+ led0_bri_duty = 0;
+ break;
+ case 2:
+ shift_num = 2;
+ break;
+ default:
+ led_debug("%s led index err", __func__);
+ return;
+ }
+
+ //step3: bright亮度
+ _led_pwm_bright_set(500, led0_bri_duty, led1_bri_duty);
+
+ //step4: 1.输出取反, 2.变色(互闪);
+ _led_pwm_output_logic_set(out_inv, shift_num);
+
+ //step5: 周期亮灭配置
+ //pwm1 duty0, duty1, duty2
+ u8 pwm1_duty0 = 0;
+ u8 pwm1_duty1 = 0;
+ u8 pwm1_duty2 = 0;
+ u8 pwm1_duty3 = 0xFF;
+
+ if (Tpwm1 == 0) {
+ led0_light_delay_time *= 2;
+ led1_light_delay_time *= 2;
+ led_blink_delay_time *= 2;
+ Tpwm1 = 1;
+ }
+
+ //最高亮度延时
+ pwm1_duty0 = led0_light_delay_time / Tpwm1;
+ pwm1_duty1 = led1_light_delay_time / Tpwm1;
+ //灭灯延时,{duty3, duty2}, 16bit
+ pwm1_duty2 = (led_blink_delay_time / Tpwm1) & 0xFF;
+ pwm1_duty3 = ((led_blink_delay_time / Tpwm1) >> 8) & 0xFF;
+
+ _led_pwm1_duty_set(pwm1_duty3, pwm1_duty0, pwm1_duty1, pwm1_duty2, 1);
+
+ //step6: enable led module
+ _led_pwm_module_enable(1, 1);
+}
+
+static void _pwm_led_display_mode(u8 display)
+{
+ led_pwm_pre_set();
+
+ switch (display) {
+ case PWM_LED_ALL_OFF:
+ case PWM_LED0_OFF:
+ case PWM_LED1_OFF:
+ _pwm_led_off_display();
+ break;
+//灯常亮
+ case PWM_LED0_ON:
+ _pwm_led_on_display(0, CFG_LED0_LIGHT, CFG_LED1_LIGHT);
+ break;
+ case PWM_LED1_ON:
+ _pwm_led_on_display(1, CFG_LED0_LIGHT, CFG_LED1_LIGHT);
+ break;
+
+ case PWM_LED_ALL_ON:
+ _pwm_led_on_display(2, CFG_LED0_LIGHT, CFG_LED1_LIGHT);
+ break;
+//单灯单闪
+ case PWM_LED0_SLOW_FLASH:
+ _pwm_led_one_flash_display(0, CFG_LED0_LIGHT, CFG_LED1_LIGHT, CFG_SINGLE_SLOW_FLASH_FREQ, -1, CFG_SINGLE_SLOW_LIGHT_TIME);
+ break;
+ case PWM_LED1_SLOW_FLASH:
+ _pwm_led_one_flash_display(1, CFG_LED0_LIGHT, CFG_LED1_LIGHT, CFG_SINGLE_SLOW_FLASH_FREQ, -1, CFG_SINGLE_SLOW_LIGHT_TIME);
+ break;
+ case PWM_LED0_FAST_FLASH:
+ _pwm_led_one_flash_display(0, CFG_LED0_LIGHT, CFG_LED1_LIGHT, CFG_SINGLE_FAST_FLASH_FREQ, -1, CFG_SINGLE_FAST_LIGHT_TIME);
+ break;
+ case PWM_LED1_FAST_FLASH:
+ _pwm_led_one_flash_display(1, CFG_LED0_LIGHT, CFG_LED1_LIGHT, CFG_SINGLE_FAST_FLASH_FREQ, -1, CFG_SINGLE_FAST_LIGHT_TIME);
+ break;
+ case PWM_LED0_ONE_FLASH_5S:
+ _pwm_led_one_flash_display(0, CFG_LED0_LIGHT, CFG_LED1_LIGHT, 5000, 10, CFG_LED_5S_FLASH_LIGHT_TIME);
+ break;
+ case PWM_LED1_ONE_FLASH_5S:
+ _pwm_led_one_flash_display(1, CFG_LED0_LIGHT, CFG_LED1_LIGHT, 5000, 10, CFG_LED_5S_FLASH_LIGHT_TIME);
+ break;
+//单灯双闪
+ case PWM_LED0_DOUBLE_FLASH_5S:
+ _pwm_led_double_flash_display(0, CFG_LED0_LIGHT, CFG_LED1_LIGHT, 5000, 100, 200, 100);
+ break;
+ case PWM_LED1_DOUBLE_FLASH_5S:
+ _pwm_led_double_flash_display(1, CFG_LED0_LIGHT, CFG_LED1_LIGHT, 5000, 100, 200, 100);
+ break;
+
+//双灯互闪
+ case PWM_LED0_LED1_FAST_FLASH:
+ _pwm_led_one_flash_display(2, CFG_LED0_LIGHT, CFG_LED1_LIGHT, CFG_DOUBLE_FAST_FLASH_FREQ, -1, -1);
+ break;
+ case PWM_LED0_LED1_SLOW_FLASH:
+ _pwm_led_one_flash_display(2, CFG_LED0_LIGHT, CFG_LED1_LIGHT, CFG_DOUBLE_SLOW_FLASH_FREQ, -1, -1);
+ break;
+
+//呼吸模式
+ case PWM_LED0_BREATHE:
+ _pwm_led_breathe_display(0, CFG_LED_BREATH_TIME, CFG_LED0_BREATH_BRIGHT, CFG_LED1_BREATH_BRIGHT, 0, 0, CFG_LED_BREATH_BLINK_TIME);
+ break;
+ case PWM_LED1_BREATHE:
+ _pwm_led_breathe_display(1, CFG_LED_BREATH_TIME, CFG_LED0_BREATH_BRIGHT, CFG_LED1_BREATH_BRIGHT, 0, 0, CFG_LED_BREATH_BLINK_TIME);
+ break;
+ case PWM_LED0_LED1_BREATHE:
+ _pwm_led_breathe_display(2, CFG_LED_BREATH_TIME, CFG_LED0_BREATH_BRIGHT, CFG_LED1_BREATH_BRIGHT, 0, 0, CFG_LED_BREATH_BLINK_TIME);
+ break;
+ }
+}
+
+static void _pwm_led_user_define_mode_handle(u8 dis_mode)
+{
+ return;
+}
+
+//=================================================================================//
+// 以下为 LED API //
+//=================================================================================//
+
+
+//=================================================================================//
+//@brief: LED模式显示模式设置
+//@input: display, 显示模式
+//@return: void
+//@note:
+//=================================================================================//
+void pwm_led_mode_set(u8 display)
+{
+ if (__this->init == 0) {
+ led_debug("led no init");
+ return;
+ }
+
+ led_debug("Mode %d Display", display);
+
+ if (display == PWM_LED_NULL) {
+ return;
+ }
+
+ if (((display >= PWM_LED_USER_DEFINE_BEGIN) && (display <= PWM_LED_USER_DEFINE_END))) {
+ //用户自定义模式
+ if (display != __this->last_mode) {
+#if TCFG_PWMLED_USE_SLOT_TIME
+ pwm_led_16slot_timer_free();
+#endif
+ _pwm_led_user_define_mode_handle(display);
+ }
+ return;
+ }
+
+ if ((display >= PWM_LED_MODE_END) /* || (display == __this->last_mode) */) {
+ return;
+ }
+
+ if ((display == PWM_LED_ALL_OFF) || (display == PWM_LED0_OFF) || (display == PWM_LED1_OFF)) {
+#if TCFG_PWMLED_USE_SLOT_TIME
+ pwm_led_16slot_timer_free();
+#endif /* #if TCFG_PWMLED_USE_SLOT_TIME */
+ led_pwm_pre_set(); //关LED
+ __this->last_mode = display;
+ return;
+ }
+
+ _pwm_led_close_irq();
+
+ if (__this->user_data->io_mode == LED_TWO_IO_MODE) {
+#if TCFG_PWMLED_USE_SLOT_TIME
+ pwm_led_two_io_mode_slot_timer_display(display);
+#else
+ pwm_led_two_io_mode_display(display);
+#endif /* #if TCFG_PWMLED_USE_SLOT_TIME */
+ } else {
+#if TCFG_PWMLED_USE_SLOT_TIME
+ pwm_led_one_io_mode_slot_timer_display(display);
+#else
+ pwm_led_one_io_mode_display(display);
+#endif /* #if TCFG_PWMLED_USE_SLOT_TIME */
+ }
+ __this->last_mode = display;
+ log_pwm_led_info();
+}
+
+//=================================================================================//
+//@brief: LED模块时钟源选择
+//@input: src, 时钟源BT24M/RC32K
+//@return: void
+//@note:
+//=================================================================================//
+void pwm_led_clk_set(enum pwm_led_clk_source src)
+{
+ u8 mode_bak;
+
+ if (__this->init == 0) {
+ return;
+ }
+
+ led_debug("%s: src = %d", __func__, src);
+#if TCFG_PWMLED_USE_SLOT_TIME
+ //switch to rc: enter sniff
+ if (src == PWM_LED_CLK_RC32K) {
+ pwm_led_16slot_timer_free();
+ if (__this->user_data->io_mode != LED_TWO_IO_MODE) {
+ led_debug("[LED]: led use lrc");
+ pwm_led_one_io_mode_display(__this->last_mode);
+#ifdef PWM_LED_TWO_IO_SUPPORT
+ } else {
+ pwm_led_two_io_mode_display(__this->last_mode);
+#endif /* #ifdef PWM_LED_TWO_IO_SUPPORT */
+ }
+
+ } else {
+
+ //exit sniff or tws connected
+ if (__this->user_data->io_mode != LED_TWO_IO_MODE) {
+ led_debug("[LED]: led use slot time");
+ pwm_led_one_io_mode_slot_timer_display(__this->last_mode); //同步slot timer
+#ifdef PWM_LED_TWO_IO_SUPPORT
+ } else {
+ pwm_led_two_io_mode_slot_timer_display(__this->last_mode); //同步slot timer
+#endif /* #ifdef PWM_LED_TWO_IO_SUPPORT */
+ }
+ }
+
+ return;
+#endif /* #if TCFG_PWMLED_USE_SLOT_TIME */
+
+ if (src == __this->clock) {
+ return;
+ }
+
+ if (src != PWM_LED_CLK_RC32K && src != PWM_LED_CLK_BTOSC_24M) {
+ return;
+ }
+
+ mode_bak = __this->last_mode;
+ pwm_led_mode_set(PWM_LED_ALL_OFF);
+ pwm_clock_set(src);
+ pwm_led_mode_set(mode_bak);
+}
+
+//=================================================================================//
+//@brief: LED显示周期复位, 重新开始一个周期, 可用于同步等操作
+//@input: void
+//@return: void
+//@note:
+//=================================================================================//
+void pwm_led_display_mode_reset(void)
+{
+ /* u8 last_mode; */
+ /* last_mode = __this->last_mode; */
+ /* pwm_led_mode_set(PWM_LED_ALL_OFF); */
+ /* pwm_led_mode_set(last_mode); */
+
+ if (__this->init == 0) {
+ return;
+ }
+ LED_PWM_DISABLE;
+ LED_PWM_ENABLE;
+}
+
+//=================================================================================//
+//@brief: 获取LED当前显示模式
+//@input: void
+//@return: 当前LED显示模式
+//@note:
+//=================================================================================//
+enum pwm_led_mode pwm_led_display_mode_get(void)
+{
+ return __this->last_mode;
+}
+
+//=================================================================================//
+//@brief: 修改LED灯IO口驱动能力,
+//@input: void
+//@return: 当前LED显示模式
+//@note:
+//挡位: 0 ~ 3
+// 0: 2.4mA(8mA mos + 120Ωres)
+// 1: 8mA(8mA mos)
+// 2: 18.4mA(24mA mos + 120Ωres)
+// 3: 24mA(24mA mos)
+//=================================================================================//
+void pwm_led_io_max_drive_set(u8 strength)
+{
+ LED_PWM_IO_MAX_DRIVE(strength);
+}
+
+//=================================================================================//
+//@brief: 获取LED模块是否开启, 可用于sniff灯同步
+//@input: void
+//@return: 0: 模块开启; 1: 模块关闭
+//@note:
+//=================================================================================//
+u8 is_pwm_led_on(void)
+{
+ if (__this->init == 0) {
+ return 0;
+ }
+ return IS_PWM_LED_ON;
+}
+
+bool is_led_module_on()
+{
+ if (__this->init == 0) {
+ return 0;
+ }
+ return IS_PWM_LED_ON;
+}
+
+//=================================================================================//
+//@brief: 获取LED模块开启, 可用于sniff灯同步
+//@input: void
+//@return: void
+//@note:
+//=================================================================================//
+void pwm_led_set_on(void)
+{
+ if (__this->init == 0) {
+ return;
+ }
+ LED_PWM_ENABLE;
+}
+
+void led_module_on()
+{
+ led_debug("module_on");
+ if (__this->init == 0) {
+ return;
+ }
+ LED_PWM_ENABLE;
+}
+//=================================================================================//
+//@brief: 获取LED模块关闭, 可用于sniff灯同步
+//@input: void
+//@return: void
+//@note:
+//=================================================================================//
+void pwm_led_set_off(void)
+{
+ if (__this->init == 0) {
+ return;
+ }
+ LED_PWM_DISABLE;
+}
+
+void led_module_off()
+{
+ led_debug("module_off");
+ if (__this->init == 0) {
+ return;
+ }
+ LED_PWM_DISABLE;
+}
+//=================================================================================//
+//@brief: 自定义设置单灯闪状态
+//@input: void
+// led_index: 0: led0, 1:led1, 2:led0 & led1(互闪)
+// led0_bright: led0亮度(0 ~ 500),
+// led1_bright: led1亮度(0 ~ 500),
+// period: 闪灯周期(ms), 多少ms闪一下,
+// start_light_time: 在周期中开始亮灯的时间, -1: 周期最后亮灯, 默认填-1即可,
+// light_time: 灯亮持续时间(ms),
+//@return: void
+//@note:
+//=================================================================================//
+void pwm_led_one_flash_display(u8 led_index, u16 led0_bright, u16 led1_bright,
+ u32 period, u32 start_light_time, u32 light_time)
+{
+ _pwm_led_close_irq();
+ //两个IO特殊处理
+ if (__this->user_data->io_mode == LED_TWO_IO_MODE) {
+#ifdef PWM_LED_TWO_IO_SUPPORT
+ _pwm_led_two_io_user_define_mode(led_index);
+ if (led_index == 0) {
+ led_index = 1;
+ led1_bright = led0_bright;
+ }
+#endif /* #ifdef PWM_LED_TWO_IO_SUPPORT */
+ }
+ _pwm_led_one_flash_display(led_index, led0_bright, led1_bright,
+ period, start_light_time, light_time);
+ __this->last_mode = PWM_LED_USER_DEFINE_MODE;
+}
+
+
+//=================================================================================//
+//@brief: 自定义设置单灯双闪状态
+//@input:
+// led_index: 0: led0, 1:led1, 2:led0 & led1(互闪)
+// led0_bright: led0亮度,
+// led1_bright: led1亮度,
+// period: 闪灯周期(ms), 多少ms闪一下
+// first_light_time: 第一次亮灯持续时间,
+// second_light_time: 第二次亮灯持续时间,
+// gap_time: 两次亮灯时间间隔,
+// led0_bright, LED0亮度: 0 ~ 500
+// led1_bright, LED1亮度: 0 ~ 500
+//@return: void
+//@note:
+//=================================================================================//
+void pwm_led_double_flash_display(u8 led_index, u16 led0_bright, u16 led1_bright,
+ u32 period, u32 first_light_time, u32 gap_time, u32 second_light_time)
+{
+ _pwm_led_close_irq();
+ //两个IO特殊处理
+ if (__this->user_data->io_mode == LED_TWO_IO_MODE) {
+#ifdef PWM_LED_TWO_IO_SUPPORT
+ _pwm_led_two_io_user_define_mode(led_index);
+
+ if (led_index == 0) {
+ led_index = 1;
+ led1_bright = led0_bright;
+ }
+
+ led_index = 0;
+#endif /* #ifdef PWM_LED_TWO_IO_SUPPORT */
+ }
+ _pwm_led_double_flash_display(led_index, led0_bright, led1_bright,
+ period, first_light_time, gap_time, second_light_time);
+
+ __this->last_mode = PWM_LED_USER_DEFINE_MODE;
+}
+
+
+//=================================================================================//
+//@brief: 自定义设置呼吸模式
+//@input:
+// led_index: 0: led0, 1:led1, 2:led0 & led1(互闪)
+// led0_bright: led0亮度,
+// led1_bright: led1亮度,
+// period: 闪灯周期(ms), 多少ms闪一下,
+// start_light_time: 在周期中开始亮灯的时间, -1: 周期最后亮灯
+// light_time: 灯亮持续时间,
+// led0_bright, LED0亮度: 0 ~ 500
+// led1_bright, LED1亮度: 0 ~ 500
+//@return: void
+//@note:
+//=================================================================================//
+void pwm_led_breathe_display(u8 led_index, u16 breathe_time, u16 led0_bright, u16 led1_bright,
+ u32 led0_light_delay_time, u32 led1_light_delay_time, u32 led_blink_delay_time)
+{
+ _pwm_led_close_irq();
+ if (__this->user_data->io_mode == LED_TWO_IO_MODE) {
+#ifdef PWM_LED_TWO_IO_SUPPORT
+ _pwm_led_two_io_user_define_mode(led_index);
+ if (led_index == 0) {
+ led_index = 1;
+ led1_bright = led0_bright;
+ }
+
+#endif /* #ifdef PWM_LED_TWO_IO_SUPPORT */
+ }
+ _pwm_led_breathe_display(led_index, breathe_time, led0_bright, led1_bright,
+ led0_light_delay_time, led1_light_delay_time, led_blink_delay_time);
+
+ __this->last_mode = PWM_LED_USER_DEFINE_MODE;
+}
+
+
+//=================================================================================//
+//@brief: 注册LED周期中断函数, 每个LED周期结束后会调用一次, 可以统计指定状态闪烁多少次
+//@input:
+//@return: void
+//@note:
+//=================================================================================//
+void pwm_led_register_irq(void (*func)(void))
+{
+ _pwm_led_register_irq(func, 1);
+}
+
+
+//=================================================================================//
+//============ PWM USE SLOT TIME SYNC
+//=================================================================================//
+#if TCFG_PWMLED_USE_SLOT_TIME
+struct _led_slot_timer {
+ u8 timer;
+ u8 sniff_mode;
+ u8 bling_period;
+ u8 double_mode;
+ u32 slot_num;
+ u32 light_slot_num;
+ u32 double_cnt;
+};
+
+static struct _led_slot_timer led_slot_timer = {
+ .timer = 0xFF,
+};
+
+
+/////////////////////16SLOT TIME////////////////////////
+#ifdef CONFIG_NEW_BREDR_ENABLE
+extern u8 slot_timer_get();
+extern void slot_timer_set(u8 timer, void (*handler)(void *), void *priv, int slot);
+extern void slot_timer_reset(u8 timer, int slot);
+extern void slot_timer_put(u8 timer);
+#define __timer_16slot_get slot_timer_get
+#define __timer_16slot_put slot_timer_put
+#define __timer_16slot_set slot_timer_set
+#define __timer_16slot_reset slot_timer_reset
+#define __pwm_led_get_16slot_num(x) (x * 1000 / 625)
+
+#else /* #ifdef CONFIG_NEW_BREDR_ENABLE */
+
+extern u8 timer_16slot_get();
+extern void timer_16slot_put(u8 i);
+extern void timer_16slot_set(u8 i, void *timer_handle, void *priv, u32 slot_num);
+extern void timer_16slot_reset(u8 i, u32 slot_num);
+#define __timer_16slot_get timer_16slot_get
+#define __timer_16slot_put timer_16slot_put
+#define __timer_16slot_set timer_16slot_set
+#define __timer_16slot_reset timer_16slot_reset
+#define __pwm_led_get_16slot_num(x) (x * 1000 / (625 * 16))
+
+#endif /* #ifdef CONFIG_NEW_BREDR_ENABLE */
+
+static void pwm_led_timer_16slot_handle(void *priv)
+{
+ struct _led_slot_timer *t = (struct _led_slot_timer *)priv;
+ u8 disable_pin = 0;
+ u8 enable_pin = 0;
+ if (t->double_mode) {
+#ifdef PWM_LED_TWO_IO_SUPPORT
+ if (__this->user_data->io_mode == LED_TWO_IO_MODE) {
+ if (t->double_cnt % 2) {
+ enable_pin = __this->user_data->io_cfg.two_io.pin1;
+ disable_pin = __this->user_data->io_cfg.two_io.pin0;
+ } else {
+ enable_pin = __this->user_data->io_cfg.two_io.pin0;
+ disable_pin = __this->user_data->io_cfg.two_io.pin1;
+ }
+ led_pin_set_disable(disable_pin);
+ led_pin_set_enable(enable_pin);
+ } else {
+ if (t->double_cnt % 2) {
+ //互闪
+ led_debug("slot timer chance 1 on");
+ _pwm_led_display_mode(PWM_LED1_ON);
+ } else {
+ led_debug("slot timer chance 0 on");
+ _pwm_led_display_mode(PWM_LED0_ON);
+ }
+ }
+
+#else
+ if (t->double_cnt % 2) {
+ //互闪
+ _pwm_led_display_mode(PWM_LED1_ON);
+ } else {
+ _pwm_led_display_mode(PWM_LED0_ON);
+ }
+#endif /* #ifdef PWM_LED_TWO_IO_SUPPORT */
+
+ t->double_cnt++;
+ __timer_16slot_reset(t->timer, t->slot_num);
+ } else {
+ if (t->bling_period) {
+ led_debug("slot timer set off");
+ pwm_led_set_off();
+ t->bling_period = 0;
+ __timer_16slot_reset(t->timer, t->slot_num);
+ } else {
+ led_debug("slot timer set on");
+ pwm_led_set_on();
+ t->bling_period = 1;
+ __timer_16slot_reset(t->timer, t->light_slot_num); //5s闪, 快闪?
+ }
+ }
+}
+
+static void pwm_led_16slot_timer_set(u32 period)
+{
+ u8 timer = __timer_16slot_get();
+ int slot_num = __pwm_led_get_16slot_num(period);
+
+ led_debug("[LED]: timer set");
+ __timer_16slot_set(timer, (void *)pwm_led_timer_16slot_handle, (void *)&led_slot_timer, slot_num);
+ led_slot_timer.timer = timer;
+ led_slot_timer.slot_num = slot_num;
+}
+
+static void pwm_led_16slot_timer_free(void)
+{
+ if (led_slot_timer.timer == 0xFF) {
+ led_debug("[LED]: timer have free");
+ return;
+ }
+ led_debug("[LED]: timer free");
+ __timer_16slot_put(led_slot_timer.timer);
+
+ led_slot_timer.timer = 0xFF;
+}
+
+void led_module_exit_sniff_mode()
+{
+ led_slot_timer.sniff_mode = 0;
+}
+
+void led_module_enter_sniff_mode()
+{
+ led_slot_timer.sniff_mode = 1;
+}
+
+void led_sniff_mode_double_display(u32 index)
+{
+ led_slot_timer.double_cnt = index;
+ pwm_led_timer_16slot_handle(&led_slot_timer);
+}
+
+static bool led_module_is_in_sniff_mode()
+{
+ led_debug("sniff mode : %d", led_slot_timer.sniff_mode);
+ return led_slot_timer.sniff_mode;
+}
+
+static void pwm_led_one_io_mode_slot_timer_display(u8 display)
+{
+ CPU_CRITICAL_ENTER();
+ led_debug("[LED]: mode set %d, tws: %d", display, tws_api_get_tws_state() & TWS_STA_SIBLING_DISCONNECTED);
+ pwm_led_16slot_timer_free();
+ if ((tws_api_get_tws_state() & TWS_STA_SIBLING_DISCONNECTED) || (led_module_is_in_sniff_mode())) {
+ //如果tws未连接, 使用lrc节奏
+ led_debug("[LED]: tws not connect or sniff mode, use lrc");
+ pwm_led_one_io_mode_display(display);
+ CPU_CRITICAL_EXIT();
+ return;
+ }
+ led_pwm_pre_set();
+
+ u32 period = 0;
+ u32 light_time = 0;
+ u32 led_index = 0;
+ u8 need_slot_timer = 0;
+
+ switch (display) {
+ case PWM_LED_ALL_OFF:
+ case PWM_LED0_OFF:
+ case PWM_LED1_OFF:
+//灯常亮
+ case PWM_LED0_ON:
+ case PWM_LED1_ON:
+ case PWM_LED_ALL_ON:
+//呼吸模式
+ case PWM_LED0_BREATHE:
+ case PWM_LED1_BREATHE:
+ case PWM_LED0_LED1_BREATHE:
+//单灯双闪
+ case PWM_LED0_DOUBLE_FLASH_5S:
+ case PWM_LED1_DOUBLE_FLASH_5S:
+ _pwm_led_display_mode(display);
+ break;
+//单灯单闪
+ case PWM_LED0_SLOW_FLASH: //1s ~ 20s
+ need_slot_timer = 1;
+ led_index = 0;
+ period = CFG_SINGLE_SLOW_FLASH_FREQ;
+ light_time = CFG_SINGLE_SLOW_LIGHT_TIME;
+ break;
+ case PWM_LED1_SLOW_FLASH:
+ led_index = 1;
+ need_slot_timer = 1;
+ period = CFG_SINGLE_SLOW_FLASH_FREQ;
+ light_time = CFG_SINGLE_SLOW_LIGHT_TIME;
+ break;
+ case PWM_LED0_FAST_FLASH:
+ led_index = 0;
+ need_slot_timer = 1;
+ period = CFG_SINGLE_FAST_FLASH_FREQ;
+ light_time = CFG_SINGLE_FAST_LIGHT_TIME;
+ break;
+ case PWM_LED1_FAST_FLASH:
+ led_index = 1;
+ need_slot_timer = 1;
+ period = CFG_SINGLE_FAST_FLASH_FREQ;
+ light_time = CFG_SINGLE_FAST_LIGHT_TIME;
+ break;
+ case PWM_LED0_ONE_FLASH_5S:
+ led_index = 0;
+ period = 5000;
+ need_slot_timer = 1;
+ light_time = CFG_LED_5S_FLASH_LIGHT_TIME;
+ break;
+ case PWM_LED1_ONE_FLASH_5S:
+ led_index = 1;
+ period = 5000;
+ need_slot_timer = 1;
+ light_time = CFG_LED_5S_FLASH_LIGHT_TIME;
+ break;
+
+//双灯互闪
+ case PWM_LED0_LED1_FAST_FLASH:
+ led_index = 2;
+ need_slot_timer = 1;
+ period = CFG_DOUBLE_FAST_FLASH_FREQ;
+ break;
+ case PWM_LED0_LED1_SLOW_FLASH:
+ led_index = 2;
+ need_slot_timer = 1;
+ period = CFG_DOUBLE_SLOW_FLASH_FREQ;
+ break;
+
+ default:
+ break;
+ }
+
+ //互闪
+ if (need_slot_timer) {
+ if (led_index == 2) {
+ //互闪使用timer切灯, 否则使用lrc切灯会引入误差
+ led_slot_timer.double_mode = 1;
+ led_slot_timer.double_cnt = 0;
+ pwm_led_16slot_timer_set(period);
+ } else {
+ //是否支持快闪
+ led_slot_timer.double_mode = 0;
+ led_slot_timer.bling_period = 0;
+ led_slot_timer.double_cnt = 0;
+ led_slot_timer.light_slot_num = __pwm_led_get_16slot_num(light_time);
+ _pwm_led_one_flash_display(led_index, CFG_LED0_LIGHT, CFG_LED1_LIGHT, 5000, 10, light_time);
+ //_pwm_led_one_flash_display(led_index, CFG_LED0_LIGHT, CFG_LED1_LIGHT, 2000, 10, light_time);
+ pwm_led_16slot_timer_set(period);
+ }
+ }
+
+ CPU_CRITICAL_EXIT();
+}
+#endif /* #if TCFG_PWMLED_USE_SLOT_TIME */
+
+
+#ifdef PWM_LED_TEST_MODE
+void pwm_led_mode_test()
+{
+ //pwm_led_mode_set(PWM_LED0_SLOW_FLASH);
+ //pwm_led_mode_set(PWM_LED0_ON);
+ pwm_led_mode_set(PWM_LED0_LED1_FAST_FLASH);
+}
+
+static void _pwm_led_test_isr(void)
+{
+ led_debug("%s", __func__);
+}
+
+void pwm_led_test()
+{
+ static const char *dis_mode[] = {
+ "ALL off",
+ "ALL on",
+
+ "BLUE on",
+ "BLUE off",
+ "BLUE slow flash",
+ "BLUE fast flash",
+ "BLUE double flash 5s",
+ "BLUE one flash 5s",
+
+ "RED on",
+ "RED off",
+ "RED slow flash",
+ "RED fast flash",
+ "RED double flash 5s",
+ "RED one flash 5s",
+
+ "RED & BLUE fast falsh",
+ "RED & BLUE slow",
+ "BLUE breathe",
+ "RED breathe",
+ "RED & BLUE breathe",
+ };
+ /* static u8 index = C_BLED_BREATHE; */
+ /* static u8 index = PWM_LED_ALL_OFF; */
+ //static u8 index = PWM_LED_ALL_ON;
+ static u8 index = PWM_LED0_BREATHE;
+ //static u8 index = PWM_LED1_ON;
+
+ led_debug("\n\nDISPPLAY MODE : %d-%s", index, dis_mode[index - 1]);
+
+ pwm_led_mode_set(index++);
+ pwm_led_register_irq(_pwm_led_test_isr);
+
+ if (index >= PWM_LED_MODE_END) {
+ index = PWM_LED_ALL_OFF;
+ }
+}
+
+void pwm_two_io_test()
+{
+#define TEST_STATUS1 PWM_LED_ALL_ON
+#define TEST_STATUS2 PWM_LED0_LED1_SLOW_FLASH
+
+ static u8 index = TEST_STATUS1;
+ pwm_led_mode_set(index);
+ if (index == TEST_STATUS1) {
+ index = TEST_STATUS2;
+ } else {
+ index = TEST_STATUS1;
+ }
+}
+
+//====== Test pwm led singal to ALL IO
+struct io_group_test {
+ u8 start;
+ u8 end;
+};
+
+static const struct io_group_test led_io_group[] = {
+ {IO_PORTA_00, IO_PORTA_08}, //PA0 ~ PA8
+ {IO_PORTB_00, IO_PORTB_08}, //PB0 ~ PB8
+ {IO_PORTC_00, IO_PORTC_05}, //PC0 ~ PC5
+};
+
+static void led_io_group_test(void)
+{
+ u8 i, j;
+ for (i = 0; i < ARRAY_SIZE(led_io_group); i++) {
+ for (j = led_io_group[i].start; j < led_io_group[i].end + 1; j++) {
+ led_pin_set_enable(j);
+ }
+ }
+}
+
+
+#endif /* #ifdef PWM_LED_TEST_MODE */
+
diff --git a/cpu/br28/rdec.c b/cpu/br28/rdec.c
new file mode 100644
index 0000000..95ce14b
--- /dev/null
+++ b/cpu/br28/rdec.c
@@ -0,0 +1,182 @@
+#include "asm/includes.h"
+#include "generic/gpio.h"
+#include "asm/rdec.h"
+#include "timer.h"
+
+#define RDEC_DEBUG_ENABLE
+#ifdef RDEC_DEBUG_ENABLE
+#define rdec_debug(fmt, ...) printf("[RDEC] "fmt, ##__VA_ARGS__)
+#else
+#define rdec_debug(...)
+#endif
+#define RDEC_IRQ_MODE 0
+#define rdec_error(fmt, ...) printf("[RDEC] ERR: "fmt, ##__VA_ARGS__)
+struct rdec {
+ u8 init;
+ const struct rdec_platform_data *user_data;
+};
+static struct rdec _rdec = {0};
+#define __this (&_rdec)
+
+typedef struct {
+ u32 con;
+ int dat;
+ int smp;
+} RDEC_REG;
+
+RDEC_REG *rdec_get_reg(u8 index)
+{
+ RDEC_REG *reg = NULL;
+ switch (index) {
+ case 0:
+ reg = (RDEC_REG *)JL_RDEC0;
+ break;
+ case 1:
+ reg = (RDEC_REG *)JL_RDEC1;
+ break;
+ case 2:
+ reg = (RDEC_REG *)JL_RDEC2;
+ break;
+ }
+ return reg;
+}
+
+s8 get_rdec_rdat(int i);
+___interrupt
+static void rdec0_isr()
+{
+ get_rdec_rdat(0);
+}
+
+___interrupt
+static void rdec1_isr()
+{
+ get_rdec_rdat(1);
+}
+
+___interrupt
+static void rdec2_isr()
+{
+ get_rdec_rdat(2);
+}
+static void __rdec_port_init(u8 port)
+{
+ gpio_set_pull_down(port, 0);
+ gpio_set_pull_up(port, 1);
+ gpio_set_die(port, 1);
+ gpio_set_direction(port, 1);
+
+}
+static void rdec_port_init(const struct rdec_device *rdec)
+{
+ const u32 d0_table[] = {PFI_RDEC0_DAT0, PFI_RDEC1_DAT0, PFI_RDEC2_DAT0};
+ const u32 d1_table[] = {PFI_RDEC0_DAT1, PFI_RDEC1_DAT1, PFI_RDEC2_DAT1};
+ u32 index = rdec->index;
+
+ __rdec_port_init(rdec->sin_port0);
+ __rdec_port_init(rdec->sin_port1);
+
+ printf("rdec->sin_port0 = %d", rdec->sin_port0);
+ printf("rdec->sin_port1 = %d", rdec->sin_port1);
+
+ gpio_set_fun_input_port(rdec->sin_port0, d0_table[index], LOW_POWER_FREE);
+ gpio_set_fun_input_port(rdec->sin_port1, d1_table[index], LOW_POWER_FREE);
+}
+static void log_rdec_info(u32 index)
+{
+ RDEC_REG *reg = NULL;
+ reg = rdec_get_reg(index);
+ rdec_debug("RDEC CON = 0x%x", reg->con);
+ printf("FI_RDEC3_DA0 = 0x%x", JL_IMAP->FI_RDEC0_DAT0);
+ printf("FI_RDEC3_DA1 = 0x%x", JL_IMAP->FI_RDEC0_DAT1);
+
+ printf("PB_DIR = 0x%x", JL_PORTB->DIR);
+ printf("PB_OUT = 0x%x", JL_PORTB->OUT);
+ printf("PB_PU = 0x%x", JL_PORTB->PU);
+ printf("PB_PD = 0x%x", JL_PORTB->PD);
+}
+
+int rdec_init(const struct rdec_platform_data *user_data)
+{
+ u8 i;
+ RDEC_REG *reg = NULL;
+ rdec_debug("rdec init...");
+ __this->init = 0;
+ if (user_data == NULL) {
+ return -1;
+ }
+ for (i = 0; i < user_data->num; i++) {
+ u32 index = user_data->rdec[i].index;
+ reg = rdec_get_reg(index);
+ rdec_port_init(&(user_data->rdec[i]));
+ //module init
+ reg->con = 0;
+ reg->con |= (0xe << 2); //2^14, fpga lsb = 24MHz, 2^14 / 24us = 682us = 0.68ms
+ reg->con &= ~BIT(1); //pol = 0, io should pull up
+ reg->con |= BIT(6); //clear pending
+ reg->con |= BIT(8); //mouse mode
+ reg->con |= BIT(0); //RDECx EN
+
+#if RDEC_IRQ_MODE
+ const u32 irq_table[] = {IRQ_RDEC0_IDX, IRQ_RDEC1_IDX, IRQ_RDEC2_IDX};
+ const void (*irq_fun[3])(void) = {rdec0_isr, rdec1_isr, rdec2_isr};
+ request_irq(irq_table[index], 1, irq_fun[index], 0);
+#endif
+ log_rdec_info(index);
+ }
+ __this->init = 1;
+ __this->user_data = user_data;
+ return 0;
+}
+s8 get_rdec_rdat(int i)
+{
+ RDEC_REG *reg = NULL;
+ s8 rdat = 0;
+ s8 _rdat = 0;
+ reg = rdec_get_reg(i);
+ if (reg->con & BIT(7)) {
+ asm("csync");
+ rdat = reg->dat;
+ reg->con |= BIT(6);
+ asm("csync");
+ _rdat = reg->dat;
+ }
+ if (_rdat != 0) {
+ rdec_debug("RDEC: %d , rdat: %d, _rdat: %d", i, rdat, _rdat);
+ }
+ return _rdat;
+}
+
+#define JL_RDEC_SEL 0
+#define RDEC_TEST 0
+#if RDEC_TEST
+const struct rdec_device rdec_device_list[] = {
+ {
+ .index = JL_RDEC_SEL,
+ .sin_port0 = IO_PORTA_01,
+ .sin_port1 = IO_PORTA_02,
+ },
+};
+
+RDEC_PLATFORM_DATA_BEGIN(rdec_data)
+.enable = 1,
+ .num = ARRAY_SIZE(rdec_device_list),
+ .rdec = rdec_device_list,
+ RDEC_PLATFORM_DATA_END()
+#endif
+
+ static void rdec_poll(void *p)
+{
+ for (int i = 0; i < 3; i++) {
+ get_rdec_rdat(i);
+ }
+}
+
+void rdec_test()
+{
+#if RDEC_TEST
+ rdec_init(&rdec_data);
+
+ sys_timer_add(NULL, rdec_poll, 100);
+#endif
+}
diff --git a/cpu/br28/sdk.ld b/cpu/br28/sdk.ld
new file mode 100644
index 0000000..e05c972
--- /dev/null
+++ b/cpu/br28/sdk.ld
@@ -0,0 +1,2079 @@
+
+
+
+
+
+ lp_signature_set = ABSOLUTE(0x1fd6c);
+ memmem = ABSOLUTE(0x1fd70);
+ memcpy = ABSOLUTE(0x1fd74);
+ memmove = ABSOLUTE(0x1fd78);
+ memcmp = ABSOLUTE(0x1fd7c);
+ memset = ABSOLUTE(0x1fd80);
+ strcmp = ABSOLUTE(0x1fd84);
+ strcpy = ABSOLUTE(0x1fd88);
+ strlen = ABSOLUTE(0x1fd8c);
+ strncmp = ABSOLUTE(0x1fd90);
+ strstr = ABSOLUTE(0x1fd94);
+ strchr = ABSOLUTE(0x1fd98);
+ __divdi3 = ABSOLUTE(0x1fd9c);
+ __udivmoddi4 = ABSOLUTE(0x1fda0);
+ __adddf3 = ABSOLUTE(0x1fda4);
+ __fixdfsi = ABSOLUTE(0x1fda8);
+ flush_dcache = ABSOLUTE(0x1fdac);
+ flushinv_dcache = ABSOLUTE(0x1fdb0);
+ IcuWaitIdle = ABSOLUTE(0x1fdb4);
+ DcuWaitIdle = ABSOLUTE(0x1fdb8);
+ IcuInitial = ABSOLUTE(0x1fdbc);
+ DcuInitial = ABSOLUTE(0x1fdc0);
+
+
+ sfc_drop_cache = ABSOLUTE(0x1fdcc);
+ chip_crc16 = ABSOLUTE(0x1fdd0);
+ CrcDecode = ABSOLUTE(0x1fdd4);
+ get_flash_file_key = ABSOLUTE(0x1fdd8);
+ dec_isd_cfg_ini = ABSOLUTE(0x1fddc);
+ _jlfs_mount = ABSOLUTE(0x1fde0);
+ sfc_boot = ABSOLUTE(0x1fde4);
+ mask_init = ABSOLUTE(0x1fde8);
+
+ nvram_set_boot_state = ABSOLUTE(0x1fdf0);
+ chip_reset = ABSOLUTE(0x1fdf4);
+ the_debug_isr = ABSOLUTE(0x1fdf8);
+ print = ABSOLUTE(0x1fdfc);
+ sprintf = ABSOLUTE(0x1fe00);
+ printf = ABSOLUTE(0x1fe04);
+ puts = ABSOLUTE(0x1fe08);
+ doe = ABSOLUTE(0x1fe0c);
+ spi_get_port = ABSOLUTE(0x1fe10);
+ _pll_init = ABSOLUTE(0x1fe14);
+ flash_poweron = ABSOLUTE(0x1fe18);
+ spi_unmount = ABSOLUTE(0x1fe1c);
+ spi_port_io_init = ABSOLUTE(0x1fe20);
+ usb_slave_mode = ABSOLUTE(0x1fe24);
+ LZ4_setStreamDecode = ABSOLUTE(0x1fe28);
+ LZ4_decompress_safe_continue = ABSOLUTE(0x1fe2c);
+ LZ4_decompress_generic = ABSOLUTE(0x1fe30);
+ _sdk_mkey_lock = ABSOLUTE(0x1fe34);
+ g_hash_function = ABSOLUTE(0x1fe38);
+ f1_hash_function = ABSOLUTE(0x1fe3c);
+ f2_hash_function = ABSOLUTE(0x1fe40);
+ f3_hash_function = ABSOLUTE(0x1fe44);
+ h2_hash_function = ABSOLUTE(0x1fe48);
+ h3_hash_function = ABSOLUTE(0x1fe4c);
+ h4_hash_function = ABSOLUTE(0x1fe50);
+ h5_hash_function = ABSOLUTE(0x1fe54);
+ g_function = ABSOLUTE(0x1fe58);
+ f1_function = ABSOLUTE(0x1fe5c);
+ f2_function = ABSOLUTE(0x1fe60);
+ f3_function = ABSOLUTE(0x1fe64);
+ sha256Compute = ABSOLUTE(0x1fe68);
+ uECC_compute_public_key = ABSOLUTE(0x1fe6c);
+ uECC_shared_secret = ABSOLUTE(0x1fe70);
+ bi_initialize = ABSOLUTE(0x1fe74);
+ bi_read_from_byte = ABSOLUTE(0x1fe78);
+ bi_poly_mod2 = ABSOLUTE(0x1fe7c);
+ bi_poly_mul = ABSOLUTE(0x1fe80);
+ trim = ABSOLUTE(0x1fe84);
+ bi_wirte_to_byte = ABSOLUTE(0x1fe88);
+ bi_free = ABSOLUTE(0x1fe8c);
+ bi_terminate = ABSOLUTE(0x1fe90);
+ get_cvsd_codec_ops = ABSOLUTE(0x1fe94);
+ wtgv2_silk_NLSF_CB_NB_MB = ABSOLUTE(0x18590);
+ wtgv2_LSFCosTab_FIX_Q12 = ABSOLUTE(0x1848c);
+ icdf_global_table = ABSOLUTE(0x18a88);
+ get_wtgv2dec_ops = ABSOLUTE(0x1fe98);
+ wtgv2_silk_Decode = ABSOLUTE(0x1fe9c);
+ wtgv2_silk_decode_frame = ABSOLUTE(0x1fea0);
+ wtgv2_silk_decoder_set_fs = ABSOLUTE(0x1fea4);
+ wtgv2_silk_decode_indices = ABSOLUTE(0x1fea8);
+ wtgv2_silk_decode_pulses = ABSOLUTE(0x1feac);
+ wtgv2_silk_decode_parameters = ABSOLUTE(0x1feb0);
+ wtgv2_silk_decode_core = ABSOLUTE(0x1feb4);
+ logAprx_CORDIC_float = ABSOLUTE(0x1feb8);
+ expAprx_CORDIC_float = ABSOLUTE(0x1febc);
+ magnAprx_float = ABSOLUTE(0x1fec0);
+ MatrixCopy_float_c_c = ABSOLUTE(0x1fec4);
+ MatrixCopy_float_f_f = ABSOLUTE(0x1fec8);
+ MatrixEwMulAndSumOneDim_float_c_c_c_s0 = ABSOLUTE(0x1fecc);
+ MatrixEwMulAndSumOneDim_float_c_c_c_s1 = ABSOLUTE(0x1fed0);
+ MatrixEwMulAndSumOneDim_float_f_f_f_s0 = ABSOLUTE(0x1fed4);
+ MatrixEwMulAndSumOneDim_float_f_f_f_s1 = ABSOLUTE(0x1fed8);
+ MatrixEwConjMulAndSumOneDim_float_c_c_c_s0 = ABSOLUTE(0x1fedc);
+ MatrixEwConjMulAndSumOneDim_float_c_c_c_s1 = ABSOLUTE(0x1fee0);
+ VecMeanSq_s16_f32 = ABSOLUTE(0x1fee4);
+ VecOverShift_s16_f32 = ABSOLUTE(0x1fee8);
+ VecMinus_s16_f32_f32 = ABSOLUTE(0x1feec);
+ VectorCopy_f32_s16 = ABSOLUTE(0x1fef0);
+ VecEleMul_s16_s16_f32 = ABSOLUTE(0x1fef4);
+ VecEleMul_f32_s16_f32 = ABSOLUTE(0x1fef8);
+ VecMeanSq_float_f_f = ABSOLUTE(0x1fefc);
+ VectorSet_float_f_f = ABSOLUTE(0x1ff00);
+ VecMagRecAve_float_c_f_f = ABSOLUTE(0x1ff04);
+ VecMulScalar_float_c_f_c = ABSOLUTE(0x1ff08);
+ VecConjEleMul_float_c_c_c = ABSOLUTE(0x1ff0c);
+ VecPlus_float_f_f_f = ABSOLUTE(0x1ff10);
+ VecDivide_float_c_f_c_f = ABSOLUTE(0x1ff14);
+ VecPlus_float_c_c_c = ABSOLUTE(0x1ff18);
+ VecConjMulRecAve_float_c_c_c_f = ABSOLUTE(0x1ff1c);
+ VecGetMag_float_c_f = ABSOLUTE(0x1ff20);
+ VecMax_float_f_f = ABSOLUTE(0x1ff24);
+ VecRecAve_float_f_f_f = ABSOLUTE(0x1ff28);
+ VecEleMul_float_f_f_f = ABSOLUTE(0x1ff2c);
+ VecMagAndDiv_float_c_f_f_f = ABSOLUTE(0x1ff30);
+ VecMin_float_f_f = ABSOLUTE(0x1ff34);
+ VecMinus_float_f_f_f = ABSOLUTE(0x1ff38);
+ VecMean_float_f_f = ABSOLUTE(0x1ff3c);
+ VecEleMul_float_c_f_c = ABSOLUTE(0x1ff40);
+ VecMeanSqu_float_c_f = ABSOLUTE(0x1ff44);
+ VecCopy_float_f_f = ABSOLUTE(0x1ff48);
+ VecMin_float_f_f_f = ABSOLUTE(0x1ff4c);
+ VecDivide_float_f_f_f_f = ABSOLUTE(0x1ff50);
+ VecCompBT_float_f_f_f = ABSOLUTE(0x1ff54);
+ VecCondCopy_float_f_f_f = ABSOLUTE(0x1ff58);
+ VecMulScalar_float_f_f_f = ABSOLUTE(0x1ff5c);
+ VecPlusScalar_float_f_f_f = ABSOLUTE(0x1ff60);
+ VecMinScalar_float_f_f_f = ABSOLUTE(0x1ff64);
+ VecOpposite_float_f_f = ABSOLUTE(0x1ff68);
+ VecEleMla_float_f_f_f = ABSOLUTE(0x1ff6c);
+ VecEleMla_float_c_c_c = ABSOLUTE(0x1ff70);
+ VecMinus_float_c_c_c = ABSOLUTE(0x1ff74);
+ VecDotProduct_float_f_f_f = ABSOLUTE(0x1ff78);
+ VecDotProduct_float_c_c_c = ABSOLUTE(0x1ff7c);
+ VecDotProduct_float_c_f_c = ABSOLUTE(0x1ff80);
+ VecCopy_float_c_c = ABSOLUTE(0x1ff84);
+ VecCopy_float_f_c = ABSOLUTE(0x1ff88);
+ VecConjDotProduct_float_c_c_c = ABSOLUTE(0x1ff8c);
+ VecNormalize_float_c_c_f = ABSOLUTE(0x1ff90);
+ VecRecAve_float_c_c_f = ABSOLUTE(0x1ff94);
+ VecOverlapShift_float_f_f_i = ABSOLUTE(0x1ff98);
+ VecMax_float_f_f_f = ABSOLUTE(0x1ff9c);
+ VecConjEwMulAndDiv_float_c_c_f_f_c = ABSOLUTE(0x1ffa0);
+ VecPlusMulScalar_float_c_c_f_c = ABSOLUTE(0x1ffa4);
+ VecCondCopy_float_c_i_c = ABSOLUTE(0x1ffa8);
+ VecEleMulAndDiv_float_f_f_f_f_f = ABSOLUTE(0x1ffac);
+ VectorSet_float_f_c = ABSOLUTE(0x1ffb0);
+ VecDivScalar_float_f_f_f = ABSOLUTE(0x1ffb4);
+ VecDivScalar_float_c_f_c = ABSOLUTE(0x1ffb8);
+ VecPlusScalar_float_c_f_c = ABSOLUTE(0x1ffbc);
+ VecMinScalar_float_c_f_c = ABSOLUTE(0x1ffc0);
+ mdct_tab_256 = ABSOLUTE(0x19000);
+ mdct_tab_2048 = ABSOLUTE(0x19200);
+ sine_long_1024 = ABSOLUTE(0x1a200);
+ sine_short_128 = ABSOLUTE(0x1b200);
+ kbd_long_1024 = ABSOLUTE(0x1b400);
+ kbd_short_128 = ABSOLUTE(0x1c400);
+ Huffmancb_SCL = ABSOLUTE(0x1c634);
+ num_swb_960_window = ABSOLUTE(0x1c844);
+ num_swb_1024_window = ABSOLUTE(0x1c850);
+ num_swb_128_window = ABSOLUTE(0x1c85c);
+ swb_offset_1024_96 = ABSOLUTE(0x1c868);
+ swb_offset_128_96 = ABSOLUTE(0x1c8bc);
+ swb_offset_1024_64 = ABSOLUTE(0x1c8d6);
+ swb_offset_128_64 = ABSOLUTE(0x1c936);
+ swb_offset_1024_48 = ABSOLUTE(0x1c950);
+ swb_offset_128_48 = ABSOLUTE(0x1c9b4);
+ swb_offset_1024_32 = ABSOLUTE(0x1c9d2);
+ swb_offset_1024_24 = ABSOLUTE(0x1ca3a);
+ swb_offset_128_24 = ABSOLUTE(0x1ca9a);
+ swb_offset_1024_16 = ABSOLUTE(0x1caba);
+ swb_offset_128_16 = ABSOLUTE(0x1cb12);
+ swb_offset_1024_8 = ABSOLUTE(0x1cb32);
+ swb_offset_128_8 = ABSOLUTE(0x1cb84);
+ swb_offset_1024_window = ABSOLUTE(0x1cba4);
+ swb_offset_128_window = ABSOLUTE(0x1cbd4);
+ iq_table = ABSOLUTE(0x1cc04);
+ tns_coef_0_3 = ABSOLUTE(0x1d008);
+ tns_coef_0_4 = ABSOLUTE(0x1d048);
+ tns_coef_1_3 = ABSOLUTE(0x1d088);
+ tns_coef_1_4 = ABSOLUTE(0x1d0c8);
+ pow05_table = ABSOLUTE(0x1d108);
+ sample_rates = ABSOLUTE(0x1d124);
+ pred_sfb_max = ABSOLUTE(0x1d154);
+ tns_sbf_max = ABSOLUTE(0x1d160);
+ Huffmancb_1 = ABSOLUTE(0x1d1a0);
+ Huffmancb_2 = ABSOLUTE(0x1d338);
+ Huffmancb_3 = ABSOLUTE(0x1d470);
+ Huffmancb_4 = ABSOLUTE(0x1d5a8);
+ Huffmancb_5 = ABSOLUTE(0x1d6d8);
+ Huffmancb_6 = ABSOLUTE(0x1d820);
+ Huffmancb_7 = ABSOLUTE(0x1d960);
+ Huffmancb_8 = ABSOLUTE(0x1da58);
+ Huffmancb_9 = ABSOLUTE(0x1db50);
+ Huffmancb_10 = ABSOLUTE(0x1ddf0);
+ Huffmancb_11 = ABSOLUTE(0x1e080);
+ AACcodeBookDTable = ABSOLUTE(0x1e540);
+ AAC_SFHUFF_TAB = ABSOLUTE(0x1c83c);
+ get_aac_ops = ABSOLUTE(0x1ffc4);
+ silk_NLSF_CB_WB = ABSOLUTE(0x1e5b8);
+ silk_LTP_vq_ptrs_Q7 = ABSOLUTE(0x1ea5c);
+ get_opus_enc_ops = ABSOLUTE(0x1ffc8);
+ opus_encode = ABSOLUTE(0x1ffcc);
+ silk_Encode = ABSOLUTE(0x1ffd0);
+ silk_encode_do_VAD_FIX = ABSOLUTE(0x1ffd4);
+ silk_encode_frame_FIX = ABSOLUTE(0x1ffd8);
+ silk_find_pitch_lags_FIX = ABSOLUTE(0x1ffdc);
+ silk_noise_shape_analysis_FIX = ABSOLUTE(0x1ffe0);
+ silk_find_pred_coefs_FIX = ABSOLUTE(0x1ffe4);
+ silk_process_gains_FIX = ABSOLUTE(0x1ffe8);
+ silk_prefilter_FIX = ABSOLUTE(0x1ffec);
+ silk_NSQ_del_dec_c = ABSOLUTE(0x1fff0);
+ silk_encode_indices = ABSOLUTE(0x1fff4);
+ silk_encode_pulses = ABSOLUTE(0x1fff8);
+ silk_ana_filt_bank_1 = ABSOLUTE(0x1fffc);
+ STFT_Win_FixHalf_M512_D160 = ABSOLUTE(0x3804);
+ STFT_Win_FixHalf_M256_D160 = ABSOLUTE(0x3c04);
+ STFT_Win_FixHalf_M256_D80 = ABSOLUTE(0x3e04);
+ STFT_Win_FixHalf_M128_D80 = ABSOLUTE(0x4004);
+ WOLAAnalysisFilter_Float_M64_m4_r1 = ABSOLUTE(0x4);
+ WOLASynthesisFilter_Float_M64_m4_r1 = ABSOLUTE(0x404);
+ WOLAAnalysisFilter_Float_M128_m4_r1 = ABSOLUTE(0x804);
+ WOLASynthesisFilter_Float_M128_m4_r1 = ABSOLUTE(0x1004);
+ WOLAAnalysisFilter_Float_M256_m4_r1 = ABSOLUTE(0x1804);
+ WOLASynthesisFilter_Float_M256_m4_r1 = ABSOLUTE(0x2804);
+ quantize_intervals_LF = ABSOLUTE(0x9914);
+ invert_quantize_dither_factors_LF = ABSOLUTE(0x9a18);
+ quantize_dither_factors_LF = ABSOLUTE(0x9b1c);
+ quantize_factor_select_offset_LF = ABSOLUTE(0x9c20);
+ hd_quantize_intervals_LF = ABSOLUTE(0x9ca4);
+ boot_arg_list = ABSOLUTE(0x19fc28);
+ _IRQ_MEM_ADDR = ABSOLUTE(0x19fe00);
+ _MASK_MEM_BEGIN = ABSOLUTE(0x19fc00);
+ _MASK_MEM_SIZE = ABSOLUTE(0x1a4);
+
+EXTERN(
+_start
+
+sdfile_vfs_ops
+sbc_decoder
+
+
+
+msbc_decoder
+
+
+
+sbc_hwaccel
+
+
+
+cvsd_decoder
+
+
+
+pcm_decoder
+
+
+
+
+
+
+
+mp3_decoder
+);
+
+UPDATA_SIZE = 0x80;
+UPDATA_BEG = _MASK_MEM_BEGIN - UPDATA_SIZE;
+UPDATA_BREDR_BASE_BEG = 0x1A0000;
+
+RAM_LIMIT_L = 0x100000;
+RAM_LIMIT_H = UPDATA_BEG;
+PHY_RAM_SIZE = RAM_LIMIT_H - RAM_LIMIT_L;
+
+
+ISR_BASE = _IRQ_MEM_ADDR;
+ROM_RAM_SIZE = _MASK_MEM_SIZE;
+ROM_RAM_BEG = _MASK_MEM_BEGIN;
+
+
+RAM0_BEG = RAM_LIMIT_L + (128K * 2);
+
+
+
+RAM0_END = RAM_LIMIT_H;
+RAM0_SIZE = RAM0_END - RAM0_BEG;
+
+RAM1_BEG = RAM_LIMIT_L;
+RAM1_END = RAM0_BEG;
+RAM1_SIZE = RAM1_END - RAM1_BEG;
+
+
+CODE_BEG = 0x6000100;
+
+
+
+
+
+
+EQ_PRIV_COEFF_BASE =0x1A0600;
+EQ_PRIV_SECTION_NUM = 10;
+EQ_PRIV_COEFF_END = EQ_PRIV_COEFF_BASE + 4 * EQ_PRIV_SECTION_NUM * (5+3)*2;
+EQ_SECTION_NUM = 10;
+
+
+
+
+MEMORY
+{
+ code0(rx) : ORIGIN = CODE_BEG, LENGTH = 0x100000
+ ram0(rwx) : ORIGIN = RAM0_BEG, LENGTH = RAM0_SIZE
+
+
+
+
+ psr_ram(rwx) : ORIGIN = 0x2000000, LENGTH = 8*1024*1024
+}
+
+
+ENTRY(_start)
+
+SECTIONS
+{
+ . = ORIGIN(code0);
+ .text ALIGN(4):
+ {
+ PROVIDE(text_rodata_begin = .);
+
+ *(.startup.text)
+
+ *(.text)
+
+ . = ALIGN(4);
+ update_target_begin = .;
+ PROVIDE(update_target_begin = .);
+ KEEP(*(.update_target))
+ update_target_end = .;
+ PROVIDE(update_target_end = .);
+ . = ALIGN(4);
+
+ *(.LOG_TAG_CONST*)
+ *(.rodata*)
+
+ . = ALIGN(4);
+ PROVIDE(text_rodata_end = .);
+
+ clock_critical_handler_begin = .;
+ KEEP(*(.clock_critical_txt))
+ clock_critical_handler_end = .;
+
+ chargestore_handler_begin = .;
+ KEEP(*(.chargestore_callback_txt))
+ chargestore_handler_end = .;
+
+
+ *(.opcore_table_maskrom)
+ *(.bfilt_table_maskroom)
+ *(.opcore_maskrom)
+ *(.bfilt_code)
+ *(.bfilt_const)
+
+
+ . = ALIGN(4);
+
+ lcd_interface_begin = .;
+ KEEP(*(.lcd_if_info))
+ lcd_interface_end = .;
+
+ ui_style_begin = .;
+ KEEP(*(.ui_style))
+ ui_style_end = .;
+
+
+ elm_event_handler_begin_JL = .;
+ KEEP(*(.elm_event_handler_JL))
+ elm_event_handler_end_JL = .;
+
+ elm_event_handler_begin_UPGRADE = .;
+ KEEP(*(.elm_event_handler_UPGRADE))
+ elm_event_handler_end_UPGRADE = .;
+
+
+
+ elm_event_handler_begin_DIAL = .;
+ KEEP(*(.elm_event_handler_DIAL))
+ elm_event_handler_end_DIAL = .;
+
+
+ control_event_handler_begin = .;
+ KEEP(*(.control_event_handler))
+ control_event_handler_end = .;
+
+ control_ops_begin = .;
+ KEEP(*(.control_ops))
+ control_ops_end = .;
+
+ battery_notify_begin = .;
+ *(.battery_notify)
+ battery_notify_end = .;
+ . = ALIGN(4);
+ __VERSION_BEGIN = .;
+ KEEP(*(.sys.version))
+ __VERSION_END = .;
+
+ *(.noop_version)
+ . = ALIGN(4);
+
+ . = ALIGN(4);
+ tool_interface_begin = .;
+ KEEP(*(.tool_interface))
+ tool_interface_end = .;
+ . = ALIGN(4);
+ cmd_interface_begin = .;
+ KEEP(*(.eff_cmd))
+ cmd_interface_end = .;
+ . = ALIGN(4);
+
+
+ . = ALIGN(32);
+ m_code_addr = . ;
+ *(.m.code*)
+ *(.movable.code*)
+ m_code_size = ABSOLUTE(. - m_code_addr) ;
+ . = ALIGN(32);
+ } > code0
+
+ . = ORIGIN(ram0);
+
+ .mmu_tlb ALIGN(0x10000):
+ {
+ *(.mmu_tlb_segment);
+ } > ram0
+
+ .boot_info ALIGN(32):
+ {
+ *(.boot_info)
+ . = ALIGN(32);
+ } > ram0
+
+ .irq_stack ALIGN(32):
+ {
+ _cpu0_sstack_begin = .;
+ *(.cpu0_stack)
+ _cpu0_sstack_end = .;
+ . = ALIGN(4);
+
+ _cpu1_sstack_begin = .;
+ *(.cpu1_stack)
+ _cpu1_sstack_end = .;
+ . = ALIGN(4);
+
+ } > ram0
+
+ .data ALIGN(32):
+ {
+
+ . = ALIGN(4);
+ *(.data_magic)
+
+ . = ALIGN(4);
+
+
+ . = ALIGN(4);
+ audio_sync_data_begin = .;
+ *(.audio_sync_data)
+ audio_sync_data_end = .;
+ . = ALIGN(4);
+
+ *(.sbc_data)
+ *(.msbc_data)
+ *(.cvsd_data)
+ *(.aac_data)
+ *(.sbc_eng_data)
+ *(.bt_audioplc_data)
+ *(.lc3_decoder_data)
+ *(.lc3_dec_data)
+ *(.wtgv2_data)
+ *(.wtgv2dec_data)
+
+ *(.anc_data)
+ *(.anc_core_data)
+ *(.anc_user_data)
+ *(.anc_box_data)
+ *(.anc_btspp_data)
+
+ *(.sms_data)
+ *(.audio_track_data)
+ *(.audio_adc_data)
+
+ . = ALIGN(4);
+ *(.data*)
+
+ . = ALIGN(4);
+ } > ram0
+
+ .bss ALIGN(32):
+ {
+ . = ALIGN(4);
+ *(.bss)
+ . = ALIGN(4);
+ *(.volatile_ram)
+
+ *(.btstack_pool)
+
+ *(.mem_heap)
+ *(.memp_memory_x)
+
+ . = ALIGN(4);
+ *(.non_volatile_ram)
+
+ . = ALIGN(32);
+
+ *(.usb_h_dma)
+ *(.usb_ep0)
+
+
+
+
+
+
+
+ *(.usb_audio_play_dma)
+ *(.usb_audio_rec_dma)
+ *(.uac_rx)
+ *(.mass_storage)
+
+ *(.usb_msd_dma)
+ *(.usb_hid_dma)
+ *(.usb_iso_dma)
+ *(.usb_cdc_dma)
+ *(.uac_var)
+ *(.usb_config_var)
+ *(.cdc_var)
+ . = ALIGN(32);
+
+ } > ram0
+
+ .data_code ALIGN(32):
+ {
+ data_code_pc_limit_begin = .;
+ *(.flushinv_icache)
+ *(.cache)
+ *(.os_critical_code)
+ *(.volatile_ram_code)
+ *(.chargebox_code)
+ *(.fat_data_code)
+ *(.fat_data_code_ex)
+
+ *(.ui_ram)
+ *(.math_fast_funtion_code)
+ . = ALIGN(4);
+ *(.pSOUND360TD_cal_const)
+ *(.pSOUND360TD_cal_code)
+ . = ALIGN(4);
+ *(.SpatialAudio.text.const)
+ *(.SpatialAudio.text)
+ *(.SpatialAudio.text.cache.L1)
+
+ . = ALIGN(4);
+ _SPI_CODE_START = . ;
+ *(.spi_code)
+ . = ALIGN(4);
+ _SPI_CODE_END = . ;
+ . = ALIGN(4);
+
+ } > ram0
+
+ .moveable_slot ALIGN(4):
+ {
+ *(movable.slot.*)
+
+ } >ram0
+
+ __report_overlay_begin = .;
+
+
+ OVERLAY : AT(0x200000) SUBALIGN(4)
+ {
+ .overlay_aec
+ {
+ aec_code_begin = . ;
+ *(.text._*)
+ *(.data._*)
+ *(.aec_code)
+ *(.aec_const)
+ *(.res_code)
+ *(.res_const)
+ *(.ns_code)
+ *(.ns_const)
+ *(.bark_const)
+ *(.fft_code)
+ *(.fft_const)
+ *(.agc_code)
+ *(.dms_code)
+ *(.dms_const)
+ *(.dms_sparse_code)
+ aec_code_end = . ;
+ aec_code_size = aec_code_end - aec_code_begin ;
+
+ *(.msbc_enc)
+ *(.cvsd_codec)
+ *(.aec_bss)
+ *(.aec_data)
+ *(.res_data)
+ *(.ns_data)
+ *(.dns_common_data)
+ *(.dns_param_data_single)
+ *(.dns_param_data_dual)
+ *(.jlsp_nlp_code)
+ *(.jlsp_nlp_const)
+ *(.jlsp_aec_code)
+ *(.jlsp_aec_const)
+ *(.jlsp_prep_code)
+ *(.jlsp_prep_const)
+ *(.jlsp_enc_code)
+ *(.jlsp_enc_const)
+ *(.jlsp_wn_code)
+ *(.jlsp_wn_const)
+ *(.jlsp_tri_code)
+ *(.jlsp_tri_const)
+ *(.jlsp_agc_code)
+ *(.jlsp_agc_const)
+ *(.res_bss)
+ *(.ns_bss)
+ *(.aec_mem)
+ }
+ .overlay_aac
+ {
+
+ aac_dec_code_begin = .;
+ *(.bt_aac_dec_code)
+ *(.bt_aac_dec_sparse_code)
+ aac_dec_code_end = .;
+ aac_dec_code_size = aac_dec_code_end - aac_dec_code_begin ;
+
+ . = ALIGN(4);
+ bt_aac_dec_const_begin = .;
+ *(.bt_aac_dec_const)
+ *(.bt_aac_dec_sparse_const)
+ bt_aac_dec_const_end = .;
+ bt_aac_dec_const_size = bt_aac_dec_const_end - bt_aac_dec_const_begin ;
+
+ *(.bt_aac_dec_data)
+ *(.bt_aac_dec_bss)
+
+ . = ALIGN(4);
+ *(.aac_mem)
+ *(.aac_ctrl_mem)
+
+
+
+ }
+ .overlay_mp3
+ {
+ *(.mp3_mem)
+ *(.mp3_ctrl_mem)
+ *(.mp3pick_mem)
+ *(.mp3pick_ctrl_mem)
+ *(.dec2tws_mem)
+ }
+ .overlay_wma
+ {
+ *(.wma_mem)
+ *(.wma_ctrl_mem)
+ *(.wmapick_mem)
+ *(.wmapick_ctrl_mem)
+ }
+ .overlay_wav
+ {
+ *(.wav_mem)
+ *(.wav_ctrl_mem)
+ }
+ .overlay_ape
+ {
+ *(.ape_mem)
+ *(.ape_ctrl_mem)
+ }
+ .overlay_flac
+ {
+ *(.flac_mem)
+ *(.flac_ctrl_mem)
+ }
+ .overlay_m4a
+ {
+ *(.m4a_mem)
+ *(.m4a_ctrl_mem)
+ }
+ .overlay_amr
+ {
+ *(.amr_mem)
+ *(.amr_ctrl_mem)
+ }
+ .overlay_dts
+ {
+ *(.dts_mem)
+ *(.dts_ctrl_mem)
+ }
+ .overlay_fm
+ {
+ *(.fm_mem)
+ }
+ .overlay_pc
+ {
+ *(.usb_audio_play_dma)
+ *(.usb_audio_rec_dma)
+ *(.uac_rx)
+ *(.mass_storage)
+
+ *(.usb_ep0)
+ *(.usb_msd_dma)
+ *(.usb_hid_dma)
+ *(.usb_iso_dma)
+ *(.usb_cdc_dma)
+ *(.uac_var)
+ *(.usb_config_var)
+ *(.cdc_var)
+ }
+
+ } > ram0
+
+ data_code_pc_limit_end = .;
+ __report_overlay_end = .;
+
+ _HEAP_BEGIN = . ;
+ _HEAP_END = RAM0_END;
+
+
+ . = ORIGIN(psr_ram);
+ .psr_data_code ALIGN(32):
+ {
+ *(.psram_data_code)
+ . = ALIGN(4);
+ } > psr_ram
+
+ .psr_bss_code ALIGN(32):
+ {
+ . = ALIGN(4);
+ } > psr_ram
+}
+
+
+
+
+SECTIONS
+{
+ .text : ALIGN(4)
+ {
+ gsensor_dev_begin = .;
+ KEEP(*(.gsensor_dev))
+ gsensor_dev_end = .;
+
+ fm_dev_begin = .;
+ KEEP(*(.fm_dev))
+ fm_dev_end = .;
+
+ fm_emitter_dev_begin = .;
+ KEEP(*(.fm_emitter_dev))
+ fm_emitter_dev_end = .;
+
+ storage_device_begin = .;
+ KEEP(*(.storage_device))
+ storage_device_end = .;
+
+ imusensor_dev_begin = .;
+ KEEP(*(.imusensor_dev))
+ imusensor_dev_end = .;
+ . = ALIGN(32);
+ }
+
+ .data ALIGN(32):
+ {
+ } > ram0
+
+ .bss ALIGN(32):
+ {
+ } > ram0
+
+ .data_code ALIGN(32):
+ {
+ } > ram0
+
+}
+
+
+SECTIONS
+{
+ .data : ALIGN(4)
+ {
+ update_data_start = .;
+
+ update_data_end = .;
+ } > ram0
+
+ .bss (NOLOAD) :ALIGN(4)
+ {
+ update_bss_start = .;
+
+ *(.update_bss)
+ update_bss_end = .;
+ } > ram0
+
+ .text : ALIGN(4)
+ {
+ update_code_start = .;
+
+ *(.bt_updata_ram_code)
+ *(.update_const)
+ *(.update_code)
+
+ update_code_end = .;
+ } > code0
+
+
+ UPDATE_CODE_TOTAL_SIZE = update_code_end - update_code_start;
+}
+SECTIONS
+{
+ .data : ALIGN(4)
+ {
+ btstack_data_start = .;
+ *(.bt_stack_data)
+ *(.ble_db_data)
+ *(.ble_sm_data)
+ *(.ble_att_data)
+ *(.ble_gatt_data)
+
+
+ BTSTACK_LE_HOST_MESH_DATA_START = .;
+ . = (. +3) & ~ 3;
+ _net_buf_pool_list = .;
+ *(._net_buf_pool.static.*)
+
+ *(.ble_mesh_data)
+ *(.ble_mesh_tinycrypt_data)
+ BTSTACK_LE_HOST_MESH_DATA_SIZE = ABSOLUTE(. - BTSTACK_LE_HOST_MESH_DATA_START);
+
+ btstack_data_end = .;
+
+ } > ram0
+
+ .bss (NOLOAD) :ALIGN(4)
+ {
+ btstack_bss_start = .;
+ *(.bt_stack_bss)
+ *(.ble_db_bss)
+ *(.ble_sm_bss)
+ *(.ble_att_bss)
+ *(.ble_gatt_bss)
+ *(.btstack_pool)
+
+
+ BTSTACK_LE_HOST_MESH_BSS_START = .;
+ *(.ble_mesh_bss)
+ *(.ble_mesh_tinycrypt_bss)
+ BTSTACK_LE_HOST_MESH_BSS_SIZE = ABSOLUTE(. - BTSTACK_LE_HOST_MESH_BSS_START);
+
+ btstack_bss_end = .;
+ } > ram0
+
+ .text : ALIGN(4)
+ {
+ btstack_code_start = .;
+
+ . = ALIGN(4);
+
+ a2dp_source_media_codec_begin = .;
+ KEEP(*(.a2dp_source_media_codec))
+ a2dp_source_media_codec_end = .;
+ a2dp_sink_media_probe_begin = .;
+ KEEP(*(.a2dp_sink_media_probe))
+ a2dp_sink_media_probe_end = .;
+
+ a2dp_sink_media_codec_begin = .;
+ KEEP(*(.a2dp_sink_media_codec))
+ a2dp_sink_media_codec_end = .;
+
+ a2dp_event_handler_begin = .;
+ KEEP(*(.a2dp_event_handler))
+ a2dp_event_handler_end = .;
+
+ sdp_record_item_begin = .;
+ KEEP(*(.sdp_record_item))
+ sdp_record_item_end = .;
+
+ bt_sleep_begin = .;
+ KEEP(*(.bt_sleep))
+ bt_sleep_end = .;
+
+ *(.bt_stack_const)
+ *(.bt_stack_code)
+ *(.ble_db_const)
+ *(.ble_db_code)
+ *(.ble_sm_const)
+ *(.ble_sm_code)
+ *(.ble_att_const)
+ *(.ble_att_code)
+ *(.ble_gatt_const)
+ *(.ble_gatt_code)
+
+
+ BTSTACK_LE_HOST_MESH_CODE_START = .;
+ *(.ble_mesh_code)
+ *(.ble_mesh_tinycrypt_code)
+
+ *(.ble_mesh_const)
+ *(.ble_mesh_tinycrypt_const)
+ BTSTACK_LE_HOST_MESH_CODE_SIZE = ABSOLUTE(. - BTSTACK_LE_HOST_MESH_CODE_START);
+
+ btstack_code_end = .;
+ . = ALIGN(4);
+ } > code0
+}
+
+BTSTACK_LE_HOST_MESH_RAM_TOTAL = BTSTACK_LE_HOST_MESH_DATA_SIZE + BTSTACK_LE_HOST_MESH_BSS_SIZE;
+BTSTACK_LE_HOST_MESH_FLASH_TOTAL = BTSTACK_LE_HOST_MESH_CODE_SIZE;
+
+BTSTACK_CODE_SIZE = (btstack_code_end - btstack_code_start) + (btstack_data_end - btstack_data_start);
+SECTIONS
+{
+ .data : ALIGN(4)
+ {
+ . = ALIGN(4);
+ system_data_start = .;
+
+ _video_subdev_begin = .;
+ PROVIDE(video_subdev_begin = .);
+ KEEP(*(.video_subdev.0))
+ KEEP(*(.video_subdev.1))
+ KEEP(*(.video_subdev.2))
+ KEEP(*(.video_subdev.3))
+ KEEP(*(.video_subdev.4))
+ KEEP(*(.video_subdev.5))
+ _video_subdev_end = .;
+ PROVIDE(video_subdev_end = .);
+
+ _audio_subdev_begin = .;
+ PROVIDE(audio_subdev_begin = .);
+ KEEP(*(.audio_subdev.0))
+ KEEP(*(.audio_subdev.1))
+ KEEP(*(.audio_subdev.2))
+ KEEP(*(.audio_subdev.3))
+ _audio_subdev_end = .;
+ PROVIDE(audio_subdev_end = .);
+
+ _iic_device_begin = .;
+ PROVIDE(iic_device_begin = .);
+ KEEP(*(.iic))
+ _iic_device_end = .;
+ PROVIDE(iic_device_end = .);
+
+ _avin_spi_device_begin = .;
+ PROVIDE(avin_spi_device_begin = .);
+ KEEP(*(.sw_spi))
+ _avin_spi_device_end = .;
+ PROVIDE(avin_spi_device_end = .);
+
+ _video_dev_begin = .;
+ PROVIDE(video_dev_begin = .);
+ KEEP(*(.video_device))
+ _video_dev_end = .;
+ PROVIDE(video_dev_end = .);
+
+ _key_driver_ops_begin = .;
+ PROVIDE(key_driver_ops_begin = .);
+ KEEP(*(.key_driver_ops))
+ _key_driver_ops_end = .;
+ PROVIDE(key_driver_ops_end = .);
+
+ _touch_driver_begin = .;
+ PROVIDE(touch_driver_begin = .);
+ KEEP(*(.touch_driver))
+ _touch_driver_end = .;
+ PROVIDE(touch_driver_end = .);
+
+ _static_hi_timer_begin = .;
+ PROVIDE(static_hi_timer_begin = .);
+ KEEP(*(.hi_timer))
+ _static_hi_timer_end = .;
+ PROVIDE(static_hi_timer_end = .);
+
+ _sys_cpu_timer_begin = .;
+ PROVIDE(sys_cpu_timer_begin = .);
+ KEEP(*(.sys_cpu_timer))
+ _sys_cpu_timer_end = .;
+ PROVIDE(sys_cpu_timer_end = .);
+
+ _sys_config_begin = .;
+ PROVIDE(sys_config_begin = .);
+ KEEP(*(.sys_cfg))
+ _sys_config_end = .;
+ PROVIDE(sys_config_end = .);
+
+ _sys_fat_begin = .;
+ PROVIDE(sys_fat_begin = .);
+ KEEP(*(.fs_fat))
+ _sys_fat_end = .;
+ PROVIDE(sys_fat_end = .);
+
+ _app_begin = .;
+ PROVIDE(app_begin = .);
+ KEEP(*(.app))
+ _app_end = .;
+ PROVIDE(app_end = .);
+
+ *(.crypto_ecdh_data)
+ *(.crypto_data)
+
+ *(.mem_data)
+ *(.os_port_data)
+
+ *(.os_str)
+ *(.os_data)
+
+ *(.uECC_data)
+ *(.ECDH_sample_data)
+
+ __movable_slot_start = .;
+ *(movable.slot.*);
+ __movable_slot_end = .;
+
+ system_data_end = .;
+
+ } > ram0
+
+ .bss (NOLOAD) :ALIGN(4)
+ {
+ system_bss_start = .;
+ . = ALIGN(4);
+ *(.os_bss)
+ *(.mem_heap)
+ *(.memp_memory_x)
+ *(.mem_bss)
+ *(.os_port_bss)
+
+ *(.uECC_bss)
+ *(.ECDH_sample_bss)
+
+ system_bss_end = .;
+
+ } > ram0
+
+ .text : ALIGN(4)
+ {
+ . = ALIGN(4);
+ system_text_start = .;
+
+ _device_node_begin = .;
+ PROVIDE(device_node_begin = .);
+ KEEP(*(.device))
+ _device_node_end = .;
+ PROVIDE(device_node_end = .);
+
+ config_target_begin = .;
+ PROVIDE(config_target_begin = .);
+ KEEP(*(.config_target))
+ config_target_end = .;
+ PROVIDE(config_target_end = .);
+
+ system_code_begin = .;
+ KEEP(*(.system.*.text))
+ system_code_end = .;
+ . = ALIGN(4);
+ system_code_size = system_code_end - system_code_begin;
+
+ vfs_ops_begin = .;
+ KEEP(*(.vfs_operations))
+ vfs_ops_end = .;
+
+ _lib_version_begin = .;
+ PROVIDE(lib_version_begin = .);
+ KEEP(*(.lib_version))
+ _lib_version_end = .;
+ PROVIDE(lib_version_end = .);
+
+ _initcall_begin = .;
+ PROVIDE(initcall_begin = .);
+ KEEP(*(.initcall))
+ _initcall_end = .;
+ PROVIDE(initcall_end = .);
+
+ _early_initcall_begin = .;
+ PROVIDE(early_initcall_begin = .);
+ KEEP(*(.early.initcall))
+ _early_initcall_end = .;
+ PROVIDE(early_initcall_end = .);
+
+ _late_initcall_begin = .;
+ PROVIDE(late_initcall_begin = .);
+ KEEP(*(.late.initcall))
+ _late_initcall_end = .;
+ PROVIDE(late_initcall_end = .);
+
+ _platform_initcall_begin = .;
+ PROVIDE(platform_initcall_begin = .);
+ KEEP(*(.platform.initcall))
+ _platform_initcall_end = .;
+ PROVIDE(platform_initcall_end = .);
+
+ _module_initcall_begin = .;
+ PROVIDE(module_initcall_begin = .);
+ KEEP(*(.module.initcall))
+ _module_initcall_end = .;
+ PROVIDE(module_initcall_end = .);
+
+ _sys_event_handler_begin = .;
+ PROVIDE(sys_event_handler_begin = .);
+ KEEP(*(.sys_event.4.handler))
+ KEEP(*(.sys_event.3.handler))
+ KEEP(*(.sys_event.2.handler))
+ KEEP(*(.sys_event.1.handler))
+ KEEP(*(.sys_event.0.handler))
+ _sys_event_handler_end = .;
+ PROVIDE(sys_event_handler_end = .);
+
+ _syscfg_arg_begin = .;
+ PROVIDE(syscfg_arg_begin = .);
+ KEEP(*(.syscfg.arg))
+ _syscfg_arg_end = .;
+ PROVIDE(syscfg_arg_end = .);
+
+ _syscfg_handler_begin = .;
+ PROVIDE(syscfg_handler_begin = .);
+ KEEP(*(.syscfg.handler))
+ _syscfg_handler_end = .;
+ PROVIDE(syscfg_handler_end = .);
+
+ _syscfg_ops_begin = .;
+ PROVIDE(syscfg_ops_begin = .);
+ KEEP(*(.syscfg.2.ops))
+ KEEP(*(.syscfg.1.ops))
+ KEEP(*(.syscfg.0.ops))
+ _syscfg_ops_end = .;
+ PROVIDE(syscfg_ops_end = .);
+
+ _server_info_begin = .;
+ PROVIDE(server_info_begin = .);
+ KEEP(*(.server_info))
+ _server_info_end = .;
+ PROVIDE(server_info_end = .);
+
+ _bus_device_begin = .;
+ PROVIDE(bus_device_begin = .);
+ KEEP(*(.bus_device))
+ _bus_device_end = .;
+ PROVIDE(bus_device_end = .);
+
+ _sys_power_hal_ops_begin = .;
+ PROVIDE(sys_power_hal_ops_begin = .);
+ KEEP(*(.sys_power_hal_ops))
+ _sys_power_hal_ops_end = .;
+ PROVIDE(sys_power_hal_ops_end = .);
+
+
+
+ crypto_begin = .;
+ *(.crypto_ecdh_code)
+ *(.crypto_ecdh_const)
+
+ *(.crypto_bigint_code)
+ *(.crypto_bigint_const)
+
+ *(.crypto_code)
+ *(.crypto_const)
+
+ *(.ECDH_sample_code)
+ *(.ECDH_sample_const)
+
+ *(.uECC_code)
+ *(.uECC_const)
+
+ *(.hmac_code)
+ *(.hmac_const)
+
+ *(.hash_sample_code)
+ *(.hash_sample_const)
+
+ *(.aes_cmac_sample_code)
+ *(.aes_cmac_sample_const)
+ crypto_end = .;
+ crypto_size = . - crypto_begin;
+
+ *(.mem_code)
+ *(.mem_const)
+
+ *(.os_port_code)
+ *(.os_port_const)
+
+ *(.os_const)
+
+ *(.math_fast_funtion_code)
+
+ __movable_function_start = .;
+ *(movable.text.*);
+ *(movable.stub.*);
+ *(movable.region.*);
+
+ __movable_function_end = .;
+ __movable_function_size = __movable_function_end - __movable_function_start;
+
+ system_text_end = .;
+
+
+ system_code_total_size = system_text_end - system_text_start;
+ } > code0
+
+ .data_code ALIGN(32):
+ {
+ *(.os_code)
+ } > ram0
+}
+SECTIONS
+{
+ .data : ALIGN(4)
+ {
+ btctler_data_start = .;
+
+ BTCTLER_CONTROLLER_DATA_START = .;
+ *(.bt_rf_data)
+ *(.vendor_manager_data)
+ *(.device_manager_data)
+ *(.hci_controller_data)
+ *(.hci_interface_data)
+ BTCTLER_CONTROLLER_DATA_SIZE = ABSOLUTE(. - BTCTLER_CONTROLLER_DATA_START);
+
+ BTCTLER_LE_CONTROLLER_DATA_START = .;
+ *(.ble_ll_data)
+ *(.ble_hci_data)
+ *(.ble_rf_data)
+ BTCTLER_LE_CONTROLLER_DATA_SIZE = ABSOLUTE(. - BTCTLER_LE_CONTROLLER_DATA_START);
+
+ BTCTLER_CL_DATA_START = .;
+ *(.classic_hci_data)
+ *(.classic_lmp_data)
+ *(.classic_lmp_auth_data)
+ *(.classic_lmp_bigint_data)
+ *(.classic_lmp_crypt_data)
+ *(.classic_lmp_ecdh_data)
+ *(.classic_lmp_linkbulk_data)
+ *(.classic_lmp_hmac_data)
+ *(.classic_rf_data)
+ *(.classic_bb_data)
+ BTCTLER_CL_DATA_SIZE = ABSOLUTE(. - BTCTLER_CL_DATA_START);
+
+ btctler_data_end = .;
+
+ } > ram0
+
+ .bss (NOLOAD) :ALIGN(4)
+ {
+ btctler_bss_start = .;
+
+ BTCTLER_CONTROLLER_BSS_START = .;
+
+ *(.bd_base)
+ *(.bredr_rxtx_bulk)
+ *(.bredr_tx_bulk)
+ *(.bt_rf_bss)
+ *(.hci_controller_bss)
+ *(.hci_interface_bss)
+ *(.device_manager_bss)
+ *(.vendor_manager_bss)
+ BTCTLER_CONTROLLER_BSS_SIZE = ABSOLUTE(. - BTCTLER_CONTROLLER_BSS_START);
+
+ BTCTLER_LE_CONTROLLER_BSS_START = .;
+ *(.ble_hci_bss)
+ *(.ble_ll_bss)
+ *(.ble_rf_bss)
+ BTCTLER_LE_CONTROLLER_BSS_SIZE = ABSOLUTE(. - BTCTLER_LE_CONTROLLER_BSS_START);
+
+ BTCTLER_CL_BSS_START = .;
+ *(.classic_rf_bss)
+ *(.classic_lmp_bss)
+ *(.classic_lmp_auth_bss)
+ *(.classic_lmp_bigint_bss)
+ *(.classic_lmp_crypt_bss)
+ *(.classic_lmp_ecdh_bss)
+ *(.classic_lmp_linkbulk_bss)
+ *(.classic_lmp_hmac_bss)
+ *(.classic_bb_bss)
+ *(.classic_hci_bss)
+ BTCTLER_CL_BSS_SIZE = ABSOLUTE(. - BTCTLER_CL_BSS_START);
+
+ btctler_bss_end = .;
+ } > ram0
+
+ .text : ALIGN(4)
+ {
+ btctler_code_start = .;
+
+ BTCTLER_CONTROLLER_CODE_START = .;
+ *(.bt_rf_const)
+ *(.bt_rf_code)
+ *(.vendor_manager_const)
+ *(.vendor_manager_code)
+ *(.device_manager_const)
+ *(.device_manager_code)
+ *(.hci_controller_const)
+ *(.hci_controller_code)
+ *(.hci_interface_const)
+ *(.hci_interface_code)
+ BTCTLER_CONTROLLER_CODE_SIZE = ABSOLUTE(. - BTCTLER_CONTROLLER_CODE_START);
+
+ BTCTLER_LE_CONTROLLER_CODE_START = .;
+ *(.ble_rf_const)
+ *(.ble_rf_code)
+
+ *(.ble_ll_const)
+ *(.ble_ll_code)
+ *(.ble_hci_const)
+ *(.ble_hci_code)
+ BTCTLER_LE_CONTROLLER_CODE_SIZE = ABSOLUTE(. - BTCTLER_LE_CONTROLLER_CODE_START);
+
+ BTCTLER_CL_CODE_START = .;
+ *(.bredr_irq)
+ *(.bredr_irq_code)
+ *(.bredr_irq_const)
+
+ *(.classic_hci_const)
+ *(.classic_hci_code)
+ *(.classic_lmp_const)
+ *(.classic_lmp_auth_const)
+ *(.classic_lmp_bigint_const)
+ *(.classic_lmp_crypt_const)
+ *(.classic_lmp_ecdh_const)
+ *(.classic_lmp_hmac_const)
+ *(.classic_lmp_code)
+ *(.classic_lmp_auth_code)
+ *(.classic_lmp_bigint_code)
+ *(.classic_lmp_crypt_code)
+ *(.classic_lmp_ecdh_code)
+ *(.classic_lmp_hmac_code)
+ *(.classic_rf_const)
+ *(.classic_rf_code)
+ *(.classic_bb_const)
+ *(.classic_bb_code)
+ BTCTLER_CL_CODE_SIZE = ABSOLUTE(. - BTCTLER_CL_CODE_START);
+
+ *(.classic_tws_const)
+ *(.classic_tws_code)
+ *(.classic_tws_code.esco)
+
+ . = ALIGN(4);
+
+ } > code0
+
+
+ .data_code ALIGN(32):
+ {
+
+ . = ALIGN(4);
+
+ *(.lmp_irq_code)
+ *(.link_bulk_code)
+ *(.frame_irq_code)
+
+ . = ALIGN(4);
+ *(.link_task_const)
+ *(.link_task_code)
+
+ . = ALIGN(4);
+ *(.classic_irq_const)
+ *(.classic_irq_code)
+
+
+ . = ALIGN(4);
+ *(.tws_irq_code)
+
+ . = ALIGN(4);
+ tws_sync_call_begin = .;
+ KEEP(*(.tws_sync_call))
+ tws_sync_call_end = .;
+
+ . = ALIGN(4);
+ tws_func_stub_begin = .;
+ KEEP(*(.tws_func_stub))
+ tws_func_stub_end = .;
+
+ *(.tws_media_sync_code)
+ *(.tws_media_sync_const)
+
+ *(.tws_data_forward_code)
+ *(.tws_data_forward_const)
+
+ . = ALIGN(4);
+ tws_sync_channel_begin = .;
+ KEEP(*(.tws_sync_channel.0))
+ KEEP(*(.tws_sync_channel.1))
+ KEEP(*(.tws_sync_channel.2))
+ KEEP(*(.tws_sync_channel.3))
+ KEEP(*(.tws_sync_channel.4))
+ KEEP(*(.tws_sync_channel.5))
+ KEEP(*(.tws_sync_channel.6))
+ KEEP(*(.tws_sync_channel.7))
+ KEEP(*(.tws_sync_channel.8))
+ KEEP(*(.tws_sync_channel.9))
+ KEEP(*(.tws_sync_channel.10))
+ KEEP(*(.tws_sync_channel.11))
+ KEEP(*(.tws_sync_channel.12))
+ KEEP(*(.tws_sync_channel.13))
+ tws_sync_channel_end = .;
+
+ btctler_code_end = .;
+
+ . = ALIGN(4);
+ } > ram0
+
+
+ BTCTLER_LE_RAM_TOTAL = BTCTLER_LE_CONTROLLER_DATA_SIZE + BTCTLER_LE_CONTROLLER_BSS_SIZE;
+ BTCTLER_LE_CODE_TOTAL = BTCTLER_LE_CONTROLLER_CODE_SIZE;
+
+ BTCTLER_CL_RAM_TOTAL = BTCTLER_CL_DATA_SIZE + BTCTLER_CL_BSS_SIZE;
+ BTCTLER_CL_CODE_TOTAL = BTCTLER_CL_CODE_SIZE;
+
+ BTCTLER_COMMON_RAM_TOTAL = BTCTLER_CONTROLLER_BSS_SIZE + BTCTLER_CONTROLLER_DATA_SIZE;
+ BTCTLER_COMMON_CODE_TOTAL = BTCTLER_CONTROLLER_CODE_SIZE ;
+
+ BTCTLER_RAM_TOTAL = (btctler_data_end - btctler_data_start) + (btctler_bss_end - btctler_bss_start);
+ BTCTLER_CODE_TOTAL = (btctler_code_end - btctler_code_start);
+}
+SECTIONS
+{
+ .data : ALIGN(4)
+ {
+ driver_data_start = .;
+
+
+ CLOCK_DATA_START = .;
+ *(.clock_data)
+ CLOCK_DATA_SIZE = ABSOLUTE(. - CLOCK_DATA_START);
+
+ *(.debug_data)
+
+ *(.uart_data)
+
+ *(.power_driver.data)
+ *(.power_reset.data)
+ *(.power_wakeup.data)
+
+ driver_data_end = .;
+ . = ALIGN(32);
+ } > ram0
+
+ .bss (NOLOAD) :ALIGN(4)
+ {
+ driver_bss_start = .;
+
+ CLOCK_BSS_START = .;
+ *(.clock_bss)
+ CLOCK_BSS_SIZE = ABSOLUTE(. - CLOCK_BSS_START);
+
+ *(.debug_bss)
+
+ *(.uart_bss)
+
+ *(.sd_var)
+
+ *(.power_driver.data.bss)
+ *(.power_reset.data.bss)
+ *(.power_wakeup.data.bss)
+
+ driver_bss_end = .;
+ } > ram0
+
+ .text : ALIGN(4)
+ {
+ driver_code_start = .;
+
+ *(.fm_code)
+
+ CLOCK_CODE_START = .;
+ *(.clock_code)
+ *(.clock_const)
+ CLOCK_CODE_SIZE = ABSOLUTE(. - CLOCK_CODE_START);
+
+ *(.debug_code)
+ *(.debug_const)
+
+ *(.uart_code)
+ *(.uart_const)
+
+ *(.power_driver.text)
+ *(.power_driver.text.const)
+
+ *(.power_reset.text)
+ *(.power_reset.text.const)
+
+ *(.power_wakeup.text)
+ *(.power_wakeup.text.const)
+
+ . = ALIGN(4);
+ lp_target_begin = .;
+ PROVIDE(lp_target_begin = .);
+ KEEP(*(.lp_target))
+ lp_target_end = .;
+ PROVIDE(lp_target_end = .);
+
+ . = ALIGN(4);
+ lp_request_begin = .;
+ PROVIDE(lp_request_begin = .);
+ KEEP(*(.lp_request))
+ lp_request_end = .;
+ PROVIDE(lp_request_end = .);
+
+ . = ALIGN(4);
+ deepsleep_target_begin = .;
+ PROVIDE(deepsleep_target_begin = .);
+ KEEP(*(.deepsleep_target))
+ deepsleep_target_end = .;
+ PROVIDE(deepsleep_target_end = .);
+
+ . = ALIGN(4);
+ p2m_msg_handler_begin = .;
+ PROVIDE(p2m_msg_handler_begin = .);
+ KEEP(*(.p2m_msg_handler))
+ PROVIDE(p2m_msg_handler_end = .);
+ p2m_msg_handler_end = .;
+
+ driver_code_end = .;
+ . = ALIGN(4);
+ } > code0
+
+ .data_code : ALIGN(4)
+ {
+ driver_data_code_start = .;
+
+
+ CLOCK_CACHE_L1_CODE_START = .;
+ *(.clock.text.cache.L1)
+ CLOCK_CACHE_L1_SIZE = ABSOLUTE(. - CLOCK_CACHE_L1_CODE_START);
+
+ *(.vm.text.cache.L1)
+
+ *(.power_driver.text.cache.L1)
+ *(.timer.text.cache.L1)
+ *(.gpio.text.cache.L1)
+ *(.iic_hw.text.cache.L1)
+ driver_data_code_end = .;
+ . = ALIGN(4);
+ } > ram0
+
+
+ DRIVER_RAM_TOTAL = (driver_data_end - driver_data_start) + (driver_bss_end - driver_bss_start);
+ DRIVER_CODE_TOTAL = (driver_code_end - driver_code_start);
+ DRIVER_DATA_CODE_TOTAL = (driver_data_code_end - driver_data_code_start);
+
+}
+SECTIONS
+{
+ .data : ALIGN(4)
+ {
+ . = ALIGN(4);
+ audio_sync_data_begin = .;
+ *(.audio_sync_data)
+ audio_sync_data_end = .;
+ . = ALIGN(4);
+
+ *(.sbc_data)
+ *(.msbc_data)
+ *(.cvsd_data)
+ *(.aac_data)
+ *(.ldac_decoder_data)
+ *(.sbc_eng_data)
+ *(.bt_audioplc_data)
+ *(.lc3_decoder_data)
+ *(.lc3_dec_data)
+ *(.wtgv2_data)
+ *(.wtgv2dec_data)
+ *(.opus_encoder_data)
+ *(.speex_encoder_data)
+
+ *(.anc_data)
+ *(.anc_user_data)
+ *(.anc_box_data)
+ *(.anc_btspp_data)
+ *(.audio_adc_data)
+ *(.audio_cfifo_data)
+
+ *(.sms_data)
+ . = ALIGN(4);
+ *(.pSOUND360TD_cal_data)
+ . = ALIGN(4);
+ *(.jlsp_data)
+ *(.jlsp_aec_data)
+ *(.jlsp_nlp_data)
+ *(.jlsp_dns_data)
+ *(.jlsp_enc_data)
+ *(.jlsp_prep_data)
+ *(.jlsp_wn_data)
+ *(.jlsp_tri_data)
+ *(.jlsp_agc_data)
+ . = ALIGN(4);
+
+
+
+
+ } > ram0
+
+ .bss (NOLOAD) :ALIGN(4)
+ {
+ . = ALIGN(4);
+ audio_sync_bss_begin = .;
+ *(.audio_sync_bss)
+ audio_sync_bss_end = .;
+ . = ALIGN(4);
+
+ *(.cvsd_bss)
+ *(.aac_bss)
+ *(.ldac_decoder_bss)
+ *(.sbc_eng_bss)
+ *(.bt_audioplc_bss)
+ *(.lc3_decoder_bss)
+ *(.lc3_dec_bss)
+ *(.wtgv2_bss)
+ *(.wtgv2dec_bss)
+ *(.speex_encoder_bss)
+ *(.opus_encoder_bss)
+
+ *(.anc_bss)
+ *(.anc_user_bss)
+ *(.anc_box_bss)
+ *(.anc_btspp_bss)
+ *(.audio_adc_bss)
+ *(.audio_cfifo_bss)
+
+ *(.audio_dec_bss)
+ *(.audio_buf)
+ *(.src_filt)
+ *(.src_dma)
+
+ *(.jlsp_bss)
+ *(.jlsp_aec_bss)
+ *(.jlsp_nlp_bss)
+ *(.jlsp_dns_bss)
+ *(.jlsp_enc_bss)
+ *(.jlsp_prep_bss)
+ *(.jlsp_wn_bss)
+ *(.jlsp_tri_bss)
+ *(.jlsp_agc_bss)
+ . = ALIGN(4);
+ *(.pSOUND360TD_cal_bss)
+
+ } > ram0
+
+ .text : ALIGN(4)
+ {
+ media_text_start = .;
+
+ . = ALIGN(4);
+ *(.stream_code)
+ *(.howlings_phf_code)
+ *(.notchhowling_sparse_code)
+ *(.notchhowling_code)
+ *(.howlings_phf_sparse_code)
+ *(.notchhowling_const)
+ *(.howlings_phf_const)
+
+ . = ALIGN(4);
+ *(.llns.text)
+ *(.llns.text.const)
+
+ . = ALIGN(4);
+ *(.aec_code)
+ *(.aec_const)
+
+ . = ALIGN(4);
+ *(.res_code)
+ *(.res_const)
+
+ . = ALIGN(4);
+ *(.ns_code)
+ *(.ns_const)
+ *(.bark_const)
+
+ . = ALIGN(4);
+ *(.jlsp_code)
+ . = ALIGN(4);
+ *(.jlsp_const)
+ . = ALIGN(4);
+ *(.dns_16k_data)
+ . = ALIGN(4);
+ *(.dns_8k_data)
+ . = ALIGN(4);
+ *(.jlsp_dns_code)
+ *(.jlsp_dns_const)
+ *(.dns_param_data_wind)
+ *(.dns_common_data_wind)
+
+ *(.agc_code)
+ *(.dms_code)
+ *(.dms_sparse_code)
+
+ *(.nlp_code)
+ *(.nlp_const)
+ *(.der_code)
+ *(.der_const)
+ *(.qmf_code)
+ *(.qmf_const)
+ *(.fft_code)
+ *(.fft_const)
+ *(.drc_sparse_code)
+ *(.drc_code)
+ *(.drc_const)
+
+ *(.audio_gain_code)
+ *(.audio_gain_const)
+
+ *(.ns_sparse_code )
+ *(.aec_sparse_code)
+ *(.nlp_sparse_code)
+ *(.der_sparse_code)
+ *(.qmf_sparse_code)
+ *(.bt_audioplc_code)
+ *(.bt_audioplc_sparse_code)
+ *(.bt_audioplc_const)
+ . = ALIGN(4);
+ *(.lf_audioplc_code)
+ *(.lf_audioplc_sparse_code)
+ *(.lf_audioplc_const)
+
+ . = ALIGN(4);
+ *(.pcm_code)
+ *(.pcm_const)
+
+
+
+
+ *(.wtg_dec_code)
+ *(.wtg_dec_sparse_code)
+ *(.wtg_dec_const)
+ *(.wtgv2_code)
+ *(.wtgv2_const)
+ *(.wtgv2dec_code)
+ *(.wtgv2dec_const)
+ *(.wtgv2dec_str)
+ *(.wtg_decv2_sparse_code)
+ *(.speex_dec_code)
+ *(.speex_dec_const)
+ *(.speex_const)
+ *(.speex_code)
+ *(.speex_encoder_code)
+ *(.speex_encoder_const)
+ *(.opus_code)
+ *(.opus_const)
+ *(.opus_encoder_code)
+ *(.opus_encoder_const)
+ *(.mp3_code)
+ *(.mp3_const)
+ *(.mp3_dec_sparse_code)
+ *(.mp3_dec_sparse_const)
+ *(.mp3_dec_code)
+ *(.mp3_dec_const)
+ *(.bfilt_code)
+ *(.msbc_code)
+ *(.msbc_const)
+ *(.mty_code)
+ *(.mp3tsy_dec_code)
+ *(.mp3tsy_dec_sparse_code)
+ *(.mp3tsy_dec_const)
+ *(.sbc_code)
+ *(.sbc_const)
+ *(.sine_code)
+ *(.sine_const)
+ *(.wav_code)
+ *(.wav_const)
+ *(.wav_dec_code)
+ *(.wav_dec_const)
+ *(.wav_dec_sparse_code)
+ *(.wav_dec_sparse_const)
+ *(.wma_code)
+ *(.wma_const)
+ *(.wma_dec_code)
+ *(.wma_dec_sparse_code)
+ *(.wma_dec_const)
+ *(.aac_code)
+ *(.aac_const)
+ *(.ldac_decoder_code)
+ *(.ldac_decoder_const)
+ *(.bt_ldac_dec_code)
+ *(.bt_ldac_dec_const)
+ *(.amr_code)
+ *(.amr_const)
+ *(.amr_dec_code)
+ *(.amr_dec_const)
+ *(.amr_dec_sparse_code)
+ *(.ape_code)
+ *(.ape_const)
+ *(.ape_dec_code)
+ *(.ape_dec_sparse_code)
+ *(.ape_dec_const)
+ *(.dts_code)
+ *(.dts_const)
+ *(.dts_dec_sparse_code)
+ *(.dts_dec_code)
+ *(.dts_dec_const)
+ *(.dts_dec_ff_const)
+ *(.flac_code)
+ *(.flac_const)
+ *(.flac_dec_code)
+ *(.flac_dec_const)
+ *(.flac_dec_sparse_code)
+ *(.audio_decoder_code)
+ *(.audio_decoder_const)
+ *(.audio_track_const)
+ *(.audio_track_code)
+
+
+
+ *(.m4a_code)
+ *(.m4a_const)
+ *(.m4a_dec_code)
+ *(.m4a_dec_sparse_code)
+ *(.m4a_dec_sparse_const)
+ *(.bt_aac_dec_core_sparse_const)
+ *(.bt_aac_dec_core_sparse_code)
+ *(.bt_aac_dec_core_code)
+ *(.bt_aac_dec_eng_code)
+ *(.bt_aac_dec_eng_const)
+ *(.alac_code)
+ *(.alac_const)
+ *(.alac_dec_code)
+ *(.media_device_code)
+ *(.media_device_const)
+ *(.audio_encoder_code)
+ *(.audio_encoder_const)
+ *(.mixer_code)
+ *(.mixer_const)
+ *(.dec_server_code)
+ *(.dec_server_const)
+ *(.rec_server_code)
+ *(.rec_server_const)
+ *(.auto_mute_code)
+ *(.auto_mute_const)
+ *(.plc_code)
+ *(.plc_const)
+ *(.wireless_sync_code)
+ *(.wireless_sync_const)
+ *(.sbc_eng_code)
+ *(.sbc_eng_const)
+
+ anc_code_begin = .;
+ *(.anc_user_const)
+ *(.anc_user_code)
+ *(.anc_const)
+ *(.anc_code)
+ *(.anc_core_const)
+ *(.anc_core_code)
+ *(.anc_box_const)
+ *(.anc_box_code)
+ *(.anc_btspp_const)
+ *(.anc_btspp_code)
+ anc_code_end = .;
+ anc_code_size = anc_code_end - anc_code_begin;
+
+ *(.audio_codec_code)
+ *(.audio_adc_code)
+ *(.audio_adc_const)
+ *(.audio_cfifo_code)
+ *(.audio_cfifo_const)
+
+ *(.bt_compressor_sparse_const)
+ *(.bt_compressor_sparse_code)
+ *(.compressor_sparse_code)
+ *(.compressor_sparse_const)
+
+ *(.bt_limiter_sparse_const)
+ *(.bt_limiter_sparse_code)
+ *(.limiter_sparse_code)
+ *(.limiter_sparse_const)
+
+ *(.bt_crossOver_sparse_const)
+ *(.bt_crossOver_sparse_code)
+ *(.crossOver_sparse_code)
+ *(.crossOver_sparse_const)
+
+ *(.lib_pitchshift_code)
+ *(.lib_pitchshift_const)
+
+ . = ALIGN(4);
+ _audio_decoder_begin = .;
+ PROVIDE(audio_decoder_begin = .);
+ *(.audio_decoder)
+ _audio_decoder_end = .;
+ PROVIDE(audio_decoder_end = .);
+
+ _audio_encoder_begin = .;
+ PROVIDE(audio_encoder_begin = .);
+ *(.audio_encoder)
+ _audio_encoder_end = .;
+ PROVIDE(audio_encoder_end = .);
+
+ _audio_package_begin = .;
+ PROVIDE(audio_package_begin = .);
+ *(.audio_package)
+ _audio_package_end = .;
+ PROVIDE(audio_package_end = .);
+
+ _audio_dev_begin = .;
+ PROVIDE(audio_dev_begin = .);
+ *(.audio_device)
+ _audio_dev_end = .;
+ PROVIDE(audio_dev_end = .);
+
+ _audio_hwaccel_begin = .;
+ PROVIDE(audio_hwaccel_begin = .);
+ *(.audio_hwaccel)
+ _audio_hwaccel_end = .;
+ PROVIDE(audio_hwaccel_end = .);
+
+ . = ALIGN(4);
+ media_code_begin = .;
+ *(.media.*.text)
+ . = ALIGN(4);
+
+ *(.compressor_code)
+ *(.compressor_const)
+ *(.bt_compressor_const)
+ *(.bt_compressor_code)
+
+ *(.crossOver_code)
+ *(.crossOver_const)
+ *(.bt_crossOver_const)
+ *(.bt_crossOver_code)
+
+ *(.limiter_code)
+ *(.limiter_const)
+ *(.bt_limiter_const)
+ *(.bt_limiter_code)
+
+ *(.lc3_decoder_const)
+ *(.lc3_decoder_code)
+ *(.lc3_dec_const)
+ *(.lc3_dec_code)
+
+ *(.audio_vbass_code)
+ *(.audio_vbass_const)
+ *(.vbss_code)
+ *(.vbss_const)
+ *(.vbss_sparse_code)
+ *(.vbss_sparse_const)
+
+
+ . = ALIGN(4);
+ *(.pSOUND360TD_cal_sparse_code)
+
+ . = ALIGN(4);
+ *(.g729_code)
+ *(.g729_const)
+ *(.cvsd_code)
+ *(.cvsd_const)
+
+ *(.media.audio*)
+ *(.media.mixer*)
+ *(.media.media*)
+
+ *( .lib_wtg_dec_code )
+ *( .lib_wtg_dec_const)
+
+ *(.audio_resample_code)
+ *(.audio_resample_const)
+
+ *(.resample_fastcal_sparse_code)
+ *(.resample_fastcal_code)
+ *(.resample_fastcal_const)
+
+ audio_sync_code_begin = .;
+ *(.audio_sync_code)
+ audio_sync_code_end = .;
+
+ . = ALIGN(4);
+
+ media_code_end = .;
+ . = ALIGN(4);
+ media_code_size = media_code_end - media_code_begin;
+
+ . = ALIGN(4);
+ media_text_end = .;
+ } > code0
+
+
+ .data_code ALIGN(32):
+ {
+ *(.media.aec.text)
+ } > ram0
+}
+
+text_begin = ADDR(.text);
+text_size = SIZEOF(.text);
+text_end = text_begin + text_size;
+
+bss_begin = ADDR(.bss);
+bss_size = SIZEOF(.bss);
+bss_end = bss_begin + bss_size;
+
+data_addr = ADDR(.data);
+data_begin = text_begin + text_size;
+data_size = SIZEOF(.data);
+
+moveable_slot_addr = ADDR(.moveable_slot);
+moveable_slot_begin = data_begin + data_size;
+moveable_slot_size = SIZEOF(.moveable_slot);
+
+data_code_addr = ADDR(.data_code);
+data_code_begin = moveable_slot_begin + moveable_slot_size;
+data_code_size = SIZEOF(.data_code);
+
+
+
+aec_addr = ADDR(.overlay_aec);
+aec_begin = data_code_begin + data_code_size;
+aec_size = SIZEOF(.overlay_aec);
+
+aac_addr = ADDR(.overlay_aac);
+aac_begin = aec_begin + aec_size;
+aac_size = SIZEOF(.overlay_aac);
+
+psr_data_code_addr = ADDR(.psr_data_code);
+psr_data_code_begin = aac_begin + aac_size;
+psr_data_code_size = SIZEOF(.psr_data_code);
+ASSERT(_HEAP_BEGIN > bss_begin,"_HEAP_BEGIN < bss_begin");
+ASSERT(_HEAP_BEGIN > data_addr,"_HEAP_BEGIN < data_addr");
+ASSERT(_HEAP_BEGIN > data_code_addr,"_HEAP_BEGIN < data_code_addr");
+
+
+
+PROVIDE(HEAP_BEGIN = _HEAP_BEGIN);
+PROVIDE(HEAP_END = _HEAP_END);
+_MALLOC_SIZE = _HEAP_END - _HEAP_BEGIN;
+PROVIDE(MALLOC_SIZE = _HEAP_END - _HEAP_BEGIN);
+
+ASSERT(MALLOC_SIZE >= 0x8000, "heap space too small !")
+
+
+
+
+report_text_beign = ADDR(.text);
+report_text_size = SIZEOF(.text);
+report_text_end = report_text_beign + report_text_size;
+
+report_mmu_tlb_begin = ADDR(.mmu_tlb);
+report_mmu_tlb_size = SIZEOF(.mmu_tlb);
+report_mmu_tlb_end = report_mmu_tlb_begin + report_mmu_tlb_size;
+
+report_boot_info_begin = ADDR(.boot_info);
+report_boot_info_size = SIZEOF(.boot_info);
+report_boot_info_end = report_boot_info_begin + report_boot_info_size;
+
+report_irq_stack_begin = ADDR(.irq_stack);
+report_irq_stack_size = SIZEOF(.irq_stack);
+report_irq_stack_end = report_irq_stack_begin + report_irq_stack_size;
+
+report_data_begin = ADDR(.data);
+report_data_size = SIZEOF(.data);
+report_data_end = report_data_begin + report_data_size;
+
+report_bss_begin = ADDR(.bss);
+report_bss_size = SIZEOF(.bss);
+report_bss_end = report_bss_begin + report_bss_size;
+
+report_data_code_begin = ADDR(.data_code);
+report_data_code_size = SIZEOF(.data_code);
+report_data_code_end = report_data_code_begin + report_data_code_size;
+
+report_overlay_begin = __report_overlay_begin;
+report_overlay_size = __report_overlay_end - __report_overlay_begin;
+report_overlay_end = __report_overlay_end;
+
+report_heap_beign = _HEAP_BEGIN;
+report_heap_size = _HEAP_END - _HEAP_BEGIN;
+report_heap_end = _HEAP_END;
+
+BR28_PHY_RAM_SIZE = PHY_RAM_SIZE;
+BR28_SDK_RAM_SIZE = report_mmu_tlb_size + report_boot_info_size + report_irq_stack_size + report_data_size + report_bss_size + report_overlay_size + report_data_code_size + report_heap_size;
diff --git a/cpu/br28/sdk_ld.c b/cpu/br28/sdk_ld.c
new file mode 100644
index 0000000..b06b687
--- /dev/null
+++ b/cpu/br28/sdk_ld.c
@@ -0,0 +1,421 @@
+// *INDENT-OFF*
+#include "app_config.h"
+
+/* ================= BR28 SDK memory ========================
+ _______________ ___ 0x1A0000(176K)
+| isr base |
+|_______________|___ _IRQ_MEM_ADDR(size = 0x100)
+|rom export ram |
+|_______________|
+| update |
+|_______________|___ RAM_LIMIT_H
+| HEAP |
+|_______________|___ data_code_pc_limit_H
+| audio overlay |
+|_______________|
+| data_code |
+|_______________|___ data_code_pc_limit_L
+| bss |
+|_______________|
+| data |
+|_______________|
+| irq_stack |
+|_______________|
+| boot info |
+|_______________|
+| TLB |
+|_______________|0 RAM_LIMIT_L
+
+ =========================================================== */
+
+#include "maskrom_stubs.ld"
+
+EXTERN(
+_start
+#include "sdk_used_list.c"
+);
+
+UPDATA_SIZE = 0x80;
+UPDATA_BEG = _MASK_MEM_BEGIN - UPDATA_SIZE;
+UPDATA_BREDR_BASE_BEG = 0x1A0000;
+
+RAM_LIMIT_L = 0x100000;
+RAM_LIMIT_H = UPDATA_BEG;
+PHY_RAM_SIZE = RAM_LIMIT_H - RAM_LIMIT_L;
+
+//from mask export
+ISR_BASE = _IRQ_MEM_ADDR;
+ROM_RAM_SIZE = _MASK_MEM_SIZE;
+ROM_RAM_BEG = _MASK_MEM_BEGIN;
+
+#ifdef TCFG_LOWPOWER_RAM_SIZE
+RAM0_BEG = RAM_LIMIT_L + (128K * TCFG_LOWPOWER_RAM_SIZE);
+#else
+RAM0_BEG = RAM_LIMIT_L;
+#endif
+RAM0_END = RAM_LIMIT_H;
+RAM0_SIZE = RAM0_END - RAM0_BEG;
+
+RAM1_BEG = RAM_LIMIT_L;
+RAM1_END = RAM0_BEG;
+RAM1_SIZE = RAM1_END - RAM1_BEG;
+
+#ifdef CONFIG_NEW_CFG_TOOL_ENABLE
+CODE_BEG = 0x6000100;
+#else
+CODE_BEG = 0x6000120;
+#endif
+
+//============ About EQ coeff RAM ================
+//internal EQ priv ram
+EQ_PRIV_COEFF_BASE =0x1A0600;
+EQ_PRIV_SECTION_NUM = 10;
+EQ_PRIV_COEFF_END = EQ_PRIV_COEFF_BASE + 4 * EQ_PRIV_SECTION_NUM * (5+3)*2;
+EQ_SECTION_NUM = EQ_SECTION_MAX;
+
+//=============== About BT RAM ===================
+//CONFIG_BT_RX_BUFF_SIZE = (1024 * 18);
+
+MEMORY
+{
+ code0(rx) : ORIGIN = CODE_BEG, LENGTH = CONFIG_FLASH_SIZE
+ ram0(rwx) : ORIGIN = RAM0_BEG, LENGTH = RAM0_SIZE
+
+ //ram1 - 用于volatile-heap
+ //ram1(rwx) : ORIGIN = RAM1_BEG, LENGTH = RAM1_SIZE
+
+ psr_ram(rwx) : ORIGIN = 0x2000000, LENGTH = 8*1024*1024
+}
+
+
+ENTRY(_start)
+
+SECTIONS
+{
+ . = ORIGIN(code0);
+ .text ALIGN(4):
+ {
+ PROVIDE(text_rodata_begin = .);
+
+ *(.startup.text)
+
+ *(.text)
+
+ . = ALIGN(4);
+ update_target_begin = .;
+ PROVIDE(update_target_begin = .);
+ KEEP(*(.update_target))
+ update_target_end = .;
+ PROVIDE(update_target_end = .);
+ . = ALIGN(4);
+
+ *(.LOG_TAG_CONST*)
+ *(.rodata*)
+
+ . = ALIGN(4); // must at tail, make rom_code size align 4
+ PROVIDE(text_rodata_end = .);
+
+ clock_critical_handler_begin = .;
+ KEEP(*(.clock_critical_txt))
+ clock_critical_handler_end = .;
+
+ chargestore_handler_begin = .;
+ KEEP(*(.chargestore_callback_txt))
+ chargestore_handler_end = .;
+
+ /********maskrom arithmetic ****/
+ *(.opcore_table_maskrom)
+ *(.bfilt_table_maskroom)
+ *(.opcore_maskrom)
+ *(.bfilt_code)
+ *(.bfilt_const)
+ /********maskrom arithmetic end****/
+
+ . = ALIGN(4);
+ #include "ui/ui/ui.ld"
+ . = ALIGN(4);
+ __VERSION_BEGIN = .;
+ KEEP(*(.sys.version))
+ __VERSION_END = .;
+
+ *(.noop_version)
+ . = ALIGN(4);
+
+ . = ALIGN(4);
+ tool_interface_begin = .;
+ KEEP(*(.tool_interface))
+ tool_interface_end = .;
+ . = ALIGN(4);
+ cmd_interface_begin = .;
+ KEEP(*(.eff_cmd))
+ cmd_interface_end = .;
+ . = ALIGN(4);
+
+
+ . = ALIGN(32);
+ m_code_addr = . ;
+ *(.m.code*)
+ *(.movable.code*)
+ m_code_size = ABSOLUTE(. - m_code_addr) ;
+ . = ALIGN(32);
+ } > code0
+
+ . = ORIGIN(ram0);
+ //TLB 起始需要16K 对齐;
+ .mmu_tlb ALIGN(0x10000):
+ {
+ *(.mmu_tlb_segment);
+ } > ram0
+
+ .boot_info ALIGN(32):
+ {
+ *(.boot_info)
+ . = ALIGN(32);
+ } > ram0
+
+ .irq_stack ALIGN(32):
+ {
+ _cpu0_sstack_begin = .;
+ *(.cpu0_stack)
+ _cpu0_sstack_end = .;
+ . = ALIGN(4);
+
+ _cpu1_sstack_begin = .;
+ *(.cpu1_stack)
+ _cpu1_sstack_end = .;
+ . = ALIGN(4);
+
+ } > ram0
+
+ .data ALIGN(32):
+ {
+ //cpu start
+ . = ALIGN(4);
+ *(.data_magic)
+
+ . = ALIGN(4);
+ #include "media/cpu/br28/audio_lib_data.ld"
+
+ . = ALIGN(4);
+ *(.data*)
+
+ . = ALIGN(4);
+ } > ram0
+
+ .bss ALIGN(32):
+ {
+ . = ALIGN(4);
+ *(.bss)
+ . = ALIGN(4);
+ *(.volatile_ram)
+
+ *(.btstack_pool)
+
+ *(.mem_heap)
+ *(.memp_memory_x)
+
+ . = ALIGN(4);
+ *(.non_volatile_ram)
+
+ . = ALIGN(32);
+
+ *(.usb_h_dma)
+ *(.usb_ep0)
+
+#if TCFG_USB_CDC_BACKGROUND_RUN
+ *(.usb_cdc_dma)
+ *(.usb_config_var)
+ *(.cdc_var)
+#endif
+
+ *(.usb_audio_play_dma)
+ *(.usb_audio_rec_dma)
+ *(.uac_rx)
+ *(.mass_storage)
+
+ *(.usb_msd_dma)
+ *(.usb_hid_dma)
+ *(.usb_iso_dma)
+ *(.usb_cdc_dma)
+ *(.uac_var)
+ *(.usb_config_var)
+ *(.cdc_var)
+ . = ALIGN(32);
+
+ } > ram0
+
+ .data_code ALIGN(32):
+ {
+ data_code_pc_limit_begin = .;
+ *(.flushinv_icache)
+ *(.cache)
+ *(.os_critical_code)
+ *(.volatile_ram_code)
+ *(.chargebox_code)
+ *(.fat_data_code)
+ *(.fat_data_code_ex)
+
+ *(.ui_ram)
+ *(.math_fast_funtion_code)
+ . = ALIGN(4);
+ *(.pSOUND360TD_cal_const)
+ *(.pSOUND360TD_cal_code)
+ . = ALIGN(4);
+ *(.SpatialAudio.text.const)
+ *(.SpatialAudio.text)
+ *(.SpatialAudio.text.cache.L1)
+
+ . = ALIGN(4);
+ _SPI_CODE_START = . ;
+ *(.spi_code)
+ . = ALIGN(4);
+ _SPI_CODE_END = . ;
+ . = ALIGN(4);
+
+ } > ram0
+
+ .moveable_slot ALIGN(4):
+ {
+ *(movable.slot.*)
+
+ } >ram0
+
+ __report_overlay_begin = .;
+ #include "app_overlay.ld"
+
+ data_code_pc_limit_end = .;
+ __report_overlay_end = .;
+
+ _HEAP_BEGIN = . ;
+ _HEAP_END = RAM0_END;
+
+
+ . = ORIGIN(psr_ram);
+ .psr_data_code ALIGN(32):
+ {
+ *(.psram_data_code)
+ . = ALIGN(4);
+ } > psr_ram
+
+ .psr_bss_code ALIGN(32):
+ {
+ . = ALIGN(4);
+ } > psr_ram
+}
+
+#include "app.ld"
+#include "update/update.ld"
+#include "btstack/btstack_lib.ld"
+#include "system/port/br28/system_lib.ld"
+#include "btctrler/port/br28/btctler_lib.ld"
+#include "driver/cpu/br28/driver_lib.ld"
+#include "media/cpu/br28/audio_lib.ld"
+//================== Section Info Export ====================//
+text_begin = ADDR(.text);
+text_size = SIZEOF(.text);
+text_end = text_begin + text_size;
+
+bss_begin = ADDR(.bss);
+bss_size = SIZEOF(.bss);
+bss_end = bss_begin + bss_size;
+
+data_addr = ADDR(.data);
+data_begin = text_begin + text_size;
+data_size = SIZEOF(.data);
+
+moveable_slot_addr = ADDR(.moveable_slot);
+moveable_slot_begin = data_begin + data_size;
+moveable_slot_size = SIZEOF(.moveable_slot);
+
+data_code_addr = ADDR(.data_code);
+data_code_begin = moveable_slot_begin + moveable_slot_size;
+data_code_size = SIZEOF(.data_code);
+
+
+//================ OVERLAY Code Info Export ==================//
+aec_addr = ADDR(.overlay_aec);
+aec_begin = data_code_begin + data_code_size;
+aec_size = SIZEOF(.overlay_aec);
+
+aac_addr = ADDR(.overlay_aac);
+aac_begin = aec_begin + aec_size;
+aac_size = SIZEOF(.overlay_aac);
+
+psr_data_code_addr = ADDR(.psr_data_code);
+psr_data_code_begin = aac_begin + aac_size;
+psr_data_code_size = SIZEOF(.psr_data_code);
+
+/*
+lc3_addr = ADDR(.overlay_lc3);
+lc3_begin = aac_begin + aac_size;
+lc3_size = SIZEOF(.overlay_lc3);
+*/
+
+/* moveable_addr = ADDR(.overlay_moveable) ; */
+/* moveable_size = SIZEOF(.overlay_moveable) ; */
+//===================== HEAP Info Export =====================//
+ASSERT(_HEAP_BEGIN > bss_begin,"_HEAP_BEGIN < bss_begin");
+ASSERT(_HEAP_BEGIN > data_addr,"_HEAP_BEGIN < data_addr");
+ASSERT(_HEAP_BEGIN > data_code_addr,"_HEAP_BEGIN < data_code_addr");
+/* ASSERT(_HEAP_BEGIN > moveable_slot_addr,"_HEAP_BEGIN < moveable_slot_addr"); */
+/* ASSERT(_HEAP_BEGIN > __report_overlay_begin,"_HEAP_BEGIN < __report_overlay_begin"); */
+
+PROVIDE(HEAP_BEGIN = _HEAP_BEGIN);
+PROVIDE(HEAP_END = _HEAP_END);
+_MALLOC_SIZE = _HEAP_END - _HEAP_BEGIN;
+PROVIDE(MALLOC_SIZE = _HEAP_END - _HEAP_BEGIN);
+
+ASSERT(MALLOC_SIZE >= 0x8000, "heap space too small !")
+
+//============================================================//
+//=== report section info begin:
+//============================================================//
+report_text_beign = ADDR(.text);
+report_text_size = SIZEOF(.text);
+report_text_end = report_text_beign + report_text_size;
+
+report_mmu_tlb_begin = ADDR(.mmu_tlb);
+report_mmu_tlb_size = SIZEOF(.mmu_tlb);
+report_mmu_tlb_end = report_mmu_tlb_begin + report_mmu_tlb_size;
+
+report_boot_info_begin = ADDR(.boot_info);
+report_boot_info_size = SIZEOF(.boot_info);
+report_boot_info_end = report_boot_info_begin + report_boot_info_size;
+
+report_irq_stack_begin = ADDR(.irq_stack);
+report_irq_stack_size = SIZEOF(.irq_stack);
+report_irq_stack_end = report_irq_stack_begin + report_irq_stack_size;
+
+report_data_begin = ADDR(.data);
+report_data_size = SIZEOF(.data);
+report_data_end = report_data_begin + report_data_size;
+
+report_bss_begin = ADDR(.bss);
+report_bss_size = SIZEOF(.bss);
+report_bss_end = report_bss_begin + report_bss_size;
+
+report_data_code_begin = ADDR(.data_code);
+report_data_code_size = SIZEOF(.data_code);
+report_data_code_end = report_data_code_begin + report_data_code_size;
+
+report_overlay_begin = __report_overlay_begin;
+report_overlay_size = __report_overlay_end - __report_overlay_begin;
+report_overlay_end = __report_overlay_end;
+
+report_heap_beign = _HEAP_BEGIN;
+report_heap_size = _HEAP_END - _HEAP_BEGIN;
+report_heap_end = _HEAP_END;
+
+BR28_PHY_RAM_SIZE = PHY_RAM_SIZE;
+BR28_SDK_RAM_SIZE = report_mmu_tlb_size + \
+ report_boot_info_size + \
+ report_irq_stack_size + \
+ report_data_size + \
+ report_bss_size + \
+ report_overlay_size + \
+ report_data_code_size + \
+ report_heap_size;
+//============================================================//
+//=== report section info end
+//============================================================//
+
diff --git a/cpu/br28/sdk_used_list.c b/cpu/br28/sdk_used_list.c
new file mode 100644
index 0000000..f715693
--- /dev/null
+++ b/cpu/br28/sdk_used_list.c
@@ -0,0 +1,196 @@
+#include "app_config.h"
+
+#if TCFG_USER_TWS_ENABLE
+tws_local_media_sync
+#if TCFG_EQ_ONLINE_ENABLE
+tws_ci_data
+#endif /* #if TCFG_EQ_ONLINE_ENABLE */
+tws_acl_data_sync
+tws_event_sync
+tws_conn_sync
+tws_lmp_slot_sync
+tws_low_latency
+tws_media_sync
+tws_power_balance
+tws_sync_call
+tws_tx_sync
+tws_link_sync
+tws_afh_sync
+#endif /* #if TCFG_USER_TWS_ENABLE */
+
+#if CONFIG_FATFS_ENABLE
+fat_vfs_ops
+#endif
+
+#if VFS_ENABLE
+sdfile_vfs_ops
+
+#if TCFG_NORFLASH_SFC_DEV_ENABLE || TCFG_NORFLASH_DEV_ENABLE || TCFG_VIRFAT_INSERT_FLASH_ENABLE
+nor_fs_vfs_ops
+nor_sdfile_vfs_ops
+nor_rec_fs_vfs_ops
+fat_sdfile_fat_ops
+#endif
+
+#endif /*VFS_ENABLE*/
+
+#if FLASH_INSIDE_REC_ENABLE
+inside_nor_fs_vfs_ops
+#endif
+
+#ifndef TCFG_DEC_SBC_CLOSE
+sbc_decoder
+#endif
+
+#ifndef TCFG_DEC_MSBC_CLOSE
+msbc_decoder
+#endif
+
+#ifndef TCFG_DEC_SBC_HWACCEL_CLOSE
+sbc_hwaccel
+#endif
+
+#ifndef TCFG_DEC_CVSD_CLOSE
+cvsd_decoder
+#endif
+
+#ifndef TCFG_DEC_PCM_CLOSE
+pcm_decoder
+#endif
+
+#if TCFG_DEC_MTY_ENABLE
+mty_decoder
+#endif
+
+#if TCFG_DEC_MP3_ENABLE
+mp3_decoder
+#if TCFG_DEC2TWS_ENABLE
+mp3pick_decoder
+#endif
+#endif
+
+#if TCFG_DEC_WMA_ENABLE
+wma_decoder
+#if TCFG_DEC2TWS_ENABLE
+wmapick_decoder
+#endif
+#endif
+
+#if TCFG_DEC_FLAC_ENABLE
+flac_decoder
+#endif
+
+#if TCFG_DEC_APE_ENABLE
+ape_decoder
+#endif
+
+#if TCFG_DEC_M4A_ENABLE
+m4a_decoder
+#if TCFG_DEC2TWS_ENABLE
+m4apick_decoder
+#endif
+#endif
+
+#if TCFG_DEC_ALAC_ENABLE
+alac_decoder
+#endif
+
+#if TCFG_DEC_AMR_ENABLE
+amr_decoder
+#endif
+
+#if TCFG_DEC_DTS_ENABLE
+dts_decoder
+#endif
+
+#if TCFG_DEC_G729_ENABLE || TCFG_BT_SUPPORT_G729
+g729_decoder
+#endif
+
+#if TCFG_DEC_WTGV2_ENABLE
+wtgv2_decoder
+#endif
+
+#if TCFG_DEC_AAC_ENABLE || TCFG_BT_SUPPORT_AAC
+aac_decoder
+#endif
+
+#if TCFG_DEC_LDAC_ENABLE || TCFG_BT_SUPPORT_LDAC
+ldac_decoder
+#endif
+
+#if TCFG_DEC_G726_ENABLE
+g726_decoder
+#endif
+
+#if TCFG_DEC_MIDI_ENABLE
+midi_decoder
+#endif
+
+#if TCFG_DEC_WAV_ENABLE
+wav_decoder
+#endif
+
+#if AUDIO_MIDI_CTRL_CONFIG
+midi_ctrl_decoder
+#endif
+
+#if TCFG_DEC_LC3_ENABLE
+lc3_decoder
+#endif
+
+
+
+
+#if TCFG_ENC_CVSD_ENABLE
+cvsd_encoder
+#endif
+
+#if TCFG_ENC_MSBC_ENABLE
+msbc_encoder
+#endif
+
+#if TCFG_ENC_MP3_ENABLE
+mp3_encoder
+#endif
+
+#if TCFG_ENC_G726_ENABLE
+g726_encoder
+#endif
+
+#if TCFG_ENC_ADPCM_ENABLE
+adpcm_encoder
+#endif
+
+#if TCFG_ENC_PCM_ENABLE
+pcm_encoder
+#endif
+
+#if TCFG_ENC_OPUS_ENABLE
+opus_encoder
+#endif
+
+#if TCFG_DEC_OPUS_ENABLE
+opus_decoder
+#endif
+
+#if TCFG_ENC_SPEEX_ENABLE
+speex_encoder
+#endif
+
+#if TCFG_DEC_SPEEX_ENABLE
+speex_decoder
+#endif
+
+#if TCFG_ENC_SBC_ENABLE
+sbc_encoder
+#endif
+
+
+#ifdef AUDIO_OUT_WAY_TYPE
+#if (AUDIO_OUT_WAY_TYPE & AUDIO_WAY_TYPE_DAC)
+audio_dac_driver
+#endif /*(AUDIO_OUT_WAY_TYPE & AUDIO_WAY_TYPE_DAC)*/
+#endif /*AUDIO_OUT_WAY_TYPE*/
+
+
diff --git a/cpu/br28/setup.c b/cpu/br28/setup.c
new file mode 100644
index 0000000..737d049
--- /dev/null
+++ b/cpu/br28/setup.c
@@ -0,0 +1,254 @@
+#include "asm/includes.h"
+//#include "asm/ldo.h"
+//#include "asm/cache.h"
+#include "asm/wdt.h"
+#include "asm/debug.h"
+#include "asm/efuse.h"
+#include "system/task.h"
+#include "timer.h"
+#include "asm/power_interface.h"
+#include "app_config.h"
+#include "gpio.h"
+#include "app_main.h"
+//#include "power_manage.h"
+//
+#define LOG_TAG_CONST SETUP
+#define LOG_TAG "[SETUP]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+//extern void dv15_dac_early_init(u8 ldo_sel, u8 pwr_sel, u32 dly_msecs);
+//
+extern void sys_timer_init(void);
+
+extern void tick_timer_init(void);
+
+extern void exception_irq_handler(void);
+int __crc16_mutex_init();
+
+extern int __crc16_mutex_init();
+
+#define DEBUG_SINGAL_IDLE(x) //if (x) IO_DEBUG_1(A, 7) else IO_DEBUG_0(A, 7)
+#define DEBUG_SINGAL_1S(x) //if (x) IO_DEBUG_1(A, 6) else IO_DEBUG_0(A, 6)
+
+#if (defined CONFIG_DEBUG_ENABLE) || (defined CONFIG_DEBUG_LITE_ENABLE)
+void debug_uart_init(const struct uart_platform_data *data);
+#endif
+
+#if 0
+___interrupt
+void exception_irq_handler(void)
+{
+ ___trig;
+
+ exception_analyze();
+
+ log_flush();
+ while (1);
+}
+#endif
+
+
+
+/*
+ * 此函数在cpu0上电后首先被调用,负责初始化cpu内部模块
+ *
+ * 此函数返回后,操作系统才开始初始化并运行
+ *
+ */
+
+#if 0
+static void early_putchar(char a)
+{
+ if (a == '\n') {
+ UT2_BUF = '\r';
+ __asm_csync();
+ while ((UT2_CON & BIT(15)) == 0);
+ }
+ UT2_BUF = a;
+ __asm_csync();
+ while ((UT2_CON & BIT(15)) == 0);
+}
+
+void early_puts(char *s)
+{
+ do {
+ early_putchar(*s);
+ } while (*(++s));
+}
+#endif
+
+void cpu_assert_debug()
+{
+#ifdef CONFIG_DEBUG_ENABLE
+ log_flush();
+ __local_irq_disable();
+ while (1);
+#else
+ P3_PCNT_SET0 = 0xac;
+ cpu_reset();
+#endif
+}
+
+/* AT(.psram_data_code) */
+void timer(void *p)
+{
+ /* DEBUG_SINGAL_1S(1); */
+ /* sys_timer_dump_time(); */
+ /* printf("cpu %d run", current_cpu_id()); */
+ /* DEBUG_SINGAL_1S(0);*/
+
+ /* os_system_info_output(); */
+
+ /* mem_stats(); */
+}
+
+extern void sputchar(char c);
+extern void sput_buf(const u8 *buf, int len);
+void sput_u32hex(u32 dat);
+
+void test_fun()
+{
+ wdt_close();
+ while (1);
+
+}
+
+
+__attribute__((weak))
+void maskrom_init(void)
+{
+ return;
+}
+
+
+#if (CPU_CORE_NUM > 1)
+void cpu1_setup_arch()
+{
+ q32DSP(core_num())->PMU_CON1 &= ~BIT(8); //open bpu
+
+ request_irq(IRQ_EXCEPTION_IDX, 7, exception_irq_handler, 1);
+
+ //用于控制其他核进入停止状态。
+ extern void cpu_suspend_handle(void);
+ request_irq(IRQ_SOFT0_IDX, 0, cpu_suspend_handle, 0);
+ request_irq(IRQ_SOFT1_IDX, 0, cpu_suspend_handle, 1);
+
+ debug_init();
+}
+#else
+void cpu1_setup_arch()
+{
+ return;
+}
+#endif /* #if (CPU_CORE_NUM > 1) */
+
+
+static void (*uart_db_irq_handler_callback)(u8 *packet, u32 size);
+extern void uart_dev_set_irq_handler_hook(void *uart_irq_hook);
+static void uart_db_irq_handler_hook(u8 *rbuf, u32 len)
+{
+ if (len) {
+ log_info("uart_rx_data %d:", len);
+ put_buf(rbuf, len);
+ }
+
+ if (uart_db_irq_handler_callback) {
+ uart_db_irq_handler_callback(rbuf, len);
+ }
+}
+
+void uart_db_regiest_recieve_callback(void *rx_cb)
+{
+ uart_db_irq_handler_callback = rx_cb;
+}
+
+//==================================================//
+
+extern void gpio_longpress_pin0_reset_config(u32 pin, u32 level, u32 time);
+void memory_init(void);
+void setup_arch()
+{
+ q32DSP(core_num())->PMU_CON1 &= ~BIT(8); //open bpu
+
+ gpio_longpress_pin0_reset_config(TCFG_IOKEY_POWER_ONE_PORT, 0, 0);
+ gpio_longpress_pin1_reset_config(TCFG_IOKEY_POWER_ONE_PORT, 0, 0);
+ //gpio_longpress_pin0_reset_config(IO_PORTG_08, 0, 0);
+ //gpio_longpress_pin1_reset_config(IO_PORTG_08, 0, 0);
+ memory_init();
+
+ //P11 系统必须提前打开
+ p11_init();
+
+ wdt_init(WDT_16S);
+ /* wdt_close(); */
+ efuse_init();
+
+ clk_voltage_init(TCFG_CLOCK_MODE, SYSVDD_VOL_SEL_126V);
+ xosc_hcs_trim();
+ clk_early_init(TCFG_CLOCK_SYS_SRC, TCFG_CLOCK_OSC_HZ, TCFG_CLOCK_SYS_HZ);
+ tick_timer_init();
+ /*interrupt_init();*/
+
+ //上电初始所有io
+ port_init();
+#if (defined CONFIG_DEBUG_ENABLE) || (defined CONFIG_DEBUG_LITE_ENABLE)
+ debug_uart_init(NULL);
+
+#if TCFG_UART0_RX_PORT != NO_CONFIG_PORT
+ JL_UART0->CON0 &= ~BIT(2); //disable Tx pending Enable
+ uart_dev_set_irq_handler_hook(uart_db_irq_handler_hook);
+
+#if TCFG_LOWPOWER_LOWPOWER_SEL
+ /*需要关闭POWERDOWN,否则接收会丢数据*/
+#error "need define TCFG_LOWPOWER_LOWPOWER_SEL 0 !!!!!!"
+#endif
+#endif
+
+#ifdef CONFIG_DEBUG_ENABLE
+ log_early_init(1024);
+#endif
+
+#endif
+
+ /*printf("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
+ printf(" setup_arch %s %s", __DATE__, __TIME__);
+ printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");*/
+
+
+ clock_dump();
+
+ /* log_info("resour est: %d", get_boot_flag()); */
+ //set_boot_flag(99);
+ /* log_info("resour est: %d", get_boot_flag()); */
+
+ reset_source_dump();
+
+ power_wakeup_reason_dump();
+
+ /* power_reset_source_dump(); */
+
+ //Register debugger interrupt
+#ifndef CONFIG_BP_DEBUG_ENABLE
+ request_irq(0, 2, exception_irq_handler, 0);
+#else
+//使用uboot的断点功能需要用到该中断
+ /* request_irq(0, 2, exception_irq_handler, 0); */
+#endif
+ request_irq(1, 2, exception_irq_handler, 0);
+
+ sys_timer_init();
+
+ debug_init();
+ /* sys_timer_add(NULL, timer, 3 * 1000); */
+ /* usr_timer_add(NULL, timer, 5 * 1000, 0); */
+
+ __crc16_mutex_init();
+}
+
+
+/*-----------------------------------------------------------*/
diff --git a/cpu/br28/sound_device.c b/cpu/br28/sound_device.c
new file mode 100644
index 0000000..fc0ca23
--- /dev/null
+++ b/cpu/br28/sound_device.c
@@ -0,0 +1,386 @@
+/*****************************************************************
+>file name : sound_device.c
+>create time : Fri 25 Feb 2022 05:44:41 PM CST
+*****************************************************************/
+#include "app_config.h"
+#include "media/includes.h"
+#include "audio_iis.h"
+#include "sound_device.h"
+#include "audio_config.h"
+#include "audio_syncts.h"
+#include "audio_dvol.h"
+#include "aec_user.h"
+#if TCFG_AUDIO_DAC_ENABLE
+#define SOUND_PCM_DAC_ENABLE 1
+#else
+#define SOUND_PCM_DAC_ENABLE 0
+#endif
+
+#if TCFG_AUDIO_OUTPUT_IIS
+#define SOUND_PCM_IIS_ENABLE 1
+
+#if !TCFG_AUDIO_OUTPUT_IIS_AND_DAC
+/*暂时不支持iis和dac同时输出*/
+#undef SOUND_PCM_DAC_ENABLE
+#define SOUND_PCM_DAC_ENABLE 0
+#endif
+
+#else /*TCFG_AUDIO_OUTPUT_IIS == 0*/
+#define SOUND_PCM_IIS_ENABLE 0
+#endif /*end TCFG_AUDIO_OUTPUT_IIS*/
+
+#define SOUND_PCM_DEV_NUM (SOUND_PCM_DAC_ENABLE + SOUND_PCM_IIS_ENABLE)
+
+#if SOUND_PCM_DAC_ENABLE
+#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)||(TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_MONO_R)
+s16 dac_buff[4 * 1024 + 512];
+#else
+s16 dac_buff[2 * 1024 + 512];
+#endif
+#else
+s16 dac_buff[0];
+#endif
+
+struct audio_dac_hdl dac_hdl;
+struct audio_iis_hdl iis_hdl;
+
+extern const int config_audio_dac_mix_enable;
+extern struct dac_platform_data dac_data;
+void audio_fade_in_fade_out(u8 left_vol, u8 right_vol);
+
+int sound_pcm_dev_is_running(void)
+{
+ if (SOUND_PCM_DAC_ENABLE) {
+ return audio_dac_is_working(&dac_hdl);
+ }
+ return 1;
+}
+
+void sound_pcm_dev_channel_mute(u8 ch, u8 mute)
+{
+ if (SOUND_PCM_DAC_ENABLE) {
+ audio_dac_ch_mute(&dac_hdl, ch, mute);
+ }
+}
+
+
+int sound_pcm_trigger_resume(int time_ms, void *priv, void (*callback)(void *priv))
+{
+ int err = 0;
+
+ if (SOUND_PCM_DAC_ENABLE) {
+ err = audio_dac_irq_enable(&dac_hdl, time_ms, priv, callback);
+ }
+
+ if (SOUND_PCM_DEV_NUM == 1) {
+ if (SOUND_PCM_IIS_ENABLE) {
+ err = audio_iis_trigger_interrupt(&iis_hdl, time_ms, priv, callback);
+ }
+ }
+
+ return err;
+}
+
+int sound_pcm_dev_set_delay_time(int prepared_time, int delay_time)
+{
+ if (SOUND_PCM_DAC_ENABLE) {
+ audio_dac_set_delay_time(&dac_hdl, prepared_time, delay_time);
+ }
+
+ if (SOUND_PCM_IIS_ENABLE) {
+ audio_iis_set_delay_time(&iis_hdl, prepared_time, delay_time);
+ }
+
+ return 0;
+}
+
+int sound_pcm_dev_start(void *private_data, int sample_rate, s16 volume)
+{
+ if (SOUND_PCM_DAC_ENABLE) {
+ if (!audio_dac_is_working(&dac_hdl)) {
+ audio_dac_set_sample_rate(&dac_hdl, sample_rate);
+ audio_dac_set_volume(&dac_hdl, volume);
+ audio_dac_start(&dac_hdl);
+ }
+ audio_dac_channel_start(private_data);
+ }
+
+ if (SOUND_PCM_IIS_ENABLE) {
+ audio_iis_dma_start(&iis_hdl);
+ }
+
+ return 0;
+}
+
+int sound_pcm_dev_stop(void *private_data)
+{
+ if (SOUND_PCM_DAC_ENABLE) {
+ audio_dac_set_protect_time(&dac_hdl, 0, NULL, NULL);
+ audio_dac_channel_close(private_data);
+ audio_dac_stop(&dac_hdl);
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ u8 dvol_idx = MUSIC_DVOL;
+ audio_digital_vol_set_no_fade(dvol_idx, 0); //更新当前数字音量为0
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+ }
+
+ if (SOUND_PCM_IIS_ENABLE) {
+ audio_iis_dma_stop(&iis_hdl);
+ }
+
+ return 0;
+}
+
+int sound_pcm_match_sample_rate(int sample_rate)
+{
+ if (SOUND_PCM_IIS_ENABLE) {
+ return audio_iis_pcm_sample_rate(&iis_hdl);
+ }
+
+ return sample_rate;
+}
+
+int sound_pcm_dev_write(void *private_data, void *data, int len)
+{
+ int wlen = len;
+ int wlen1 = 0;
+ if (SOUND_PCM_DEV_NUM == 1) {
+ if (SOUND_PCM_DAC_ENABLE) {
+ if (config_audio_dac_mix_enable) {
+ return audio_dac_channel_write(private_data, &dac_hdl, data, len);
+ } else {
+ return audio_dac_write(&dac_hdl, data, len);
+ }
+ }
+
+ if (SOUND_PCM_IIS_ENABLE) {
+ wlen1 = audio_iis_pcm_write(&iis_hdl, data, len);
+ return wlen1;
+ }
+ return 0;
+ }
+
+ if (SOUND_PCM_DAC_ENABLE) {
+ if (config_audio_dac_mix_enable) {
+ wlen = audio_dac_channel_write(private_data, &dac_hdl, data, len);
+ } else {
+ wlen = audio_dac_write(&dac_hdl, data, len);
+ }
+ }
+
+ if (SOUND_PCM_IIS_ENABLE) {
+ wlen1 = audio_iis_pcm_write(&iis_hdl, data, wlen);
+ }
+
+ if (wlen != wlen1) {
+ printf("iis wlen1 %d != dac wlen %d\nl", wlen1, wlen);
+ /*
+ * TODO :
+ * 这个时候说明DAC与IIS的数据消耗不同步,需要启动同步处理机制
+ * */
+ }
+
+ return wlen;
+}
+
+void sound_pcm_dev_add_syncts(void *priv)
+{
+ /*蓝牙音频同步仅能挂载到一个设备上,无法挂载多个*/
+
+ if (SOUND_PCM_DAC_ENABLE) {
+ audio_dac_add_syncts_handle(&dac_hdl, priv);
+ return;
+ }
+
+ if (SOUND_PCM_IIS_ENABLE) {
+ audio_iis_add_syncts_handle(&iis_hdl, priv);
+ }
+}
+
+void sound_pcm_dev_remove_syncts(void *handle)
+{
+ if (SOUND_PCM_DAC_ENABLE) {
+ audio_dac_remove_syncts_handle(&dac_hdl, handle);
+ }
+
+ if (SOUND_PCM_IIS_ENABLE) {
+ audio_iis_remove_syncts_handle(&iis_hdl, handle);
+ }
+}
+
+int sound_pcm_dev_channel_mapping(int ch_num)
+{
+ if (SOUND_PCM_DEV_NUM == 1) {
+ u8 ch_map = SOUND_CHMAP_MONO;
+ if (SOUND_PCM_DAC_ENABLE) {
+ ch_map = audio_dac_get_channel(&dac_hdl);
+ if (ch_map == DAC_OUTPUT_LR) {
+ return 2;
+ }
+ return 1;
+ }
+
+ if (SOUND_PCM_IIS_ENABLE) {
+ if (ch_num == 0) {
+ return audio_iis_pcm_channel_num(&iis_hdl);
+ }
+
+ if (ch_num == 1) {
+ ch_map = SOUND_CHMAP_MONO;
+ } else if (ch_num == 2) {
+ ch_map = SOUND_CHMAP_FL | SOUND_CHMAP_FR;
+ }
+ audio_iis_pcm_remapping(&iis_hdl, ch_map);
+ return audio_iis_pcm_channel_num(&iis_hdl);
+ }
+ } else {
+ u8 ch_map = SOUND_CHMAP_MONO;
+ if (SOUND_PCM_DAC_ENABLE) {
+ ch_map = audio_dac_get_channel(&dac_hdl);
+ ch_num = 1;
+ if (ch_map == DAC_OUTPUT_LR) {
+ ch_num = 2;
+ }
+ }
+
+ if (SOUND_PCM_IIS_ENABLE) {
+ if (ch_num == 0) {
+ return audio_iis_pcm_channel_num(&iis_hdl);
+ }
+
+ if (ch_num == 1) {
+ ch_map = SOUND_CHMAP_MONO;
+ } else if (ch_num == 2) {
+ ch_map = SOUND_CHMAP_FL | SOUND_CHMAP_FR;
+ }
+ audio_iis_pcm_remapping(&iis_hdl, ch_map);
+ return audio_iis_pcm_channel_num(&iis_hdl);
+ }
+ }
+
+ return 0;
+}
+
+int sound_pcm_dev_buffered_frames(void)
+{
+ if (SOUND_PCM_DAC_ENABLE) {
+ return audio_dac_buffered_frames(&dac_hdl);
+ }
+
+ if (SOUND_PCM_IIS_ENABLE) {
+ return audio_iis_buffered_frames(&iis_hdl);
+ }
+ return 0;
+}
+
+int sound_pcm_dev_buffered_time(void)
+{
+ if (SOUND_PCM_DAC_ENABLE) {
+ return audio_dac_data_time(&dac_hdl);
+ }
+
+ if (SOUND_PCM_IIS_ENABLE) {
+ return audio_iis_buffered_time(&iis_hdl);
+ }
+
+ return 0;
+}
+
+void sound_pcm_set_underrun_params(int time_ms, void *priv, void (*callback)(void *))
+{
+ if (SOUND_PCM_DAC_ENABLE) {
+ audio_dac_set_protect_time(&dac_hdl, time_ms, priv, callback);
+ }
+
+ if (SOUND_PCM_IIS_ENABLE) {
+ audio_iis_set_underrun_params(&iis_hdl, time_ms, priv, callback);
+ }
+}
+
+void sound_pcm_dev_try_power_on(void)
+{
+ if (SOUND_PCM_DAC_ENABLE) {
+ if (!sound_pcm_dev_is_running()) {
+ audio_dac_try_power_on(&dac_hdl);
+ }
+ }
+}
+
+void sound_pcm_dev_set_analog_gain(s16 gain)
+{
+ if (SOUND_PCM_DAC_ENABLE) {
+ audio_dac_set_analog_vol(&dac_hdl, gain);
+ }
+}
+
+static void sound_pcm_dac_driver_init(void)
+{
+ if (!SOUND_PCM_DAC_ENABLE) {
+ return;
+ }
+
+ audio_dac_init(&dac_hdl, &dac_data);
+
+ /* u8 mode = TCFG_AUDIO_DAC_DEFAULT_VOL_MODE; */
+ /* if (1 != syscfg_read(CFG_VOLUME_ENHANCEMENT_MODE, &mode, 1)) { */
+ /* printf("vm no CFG_VOLUME_ENHANCEMENT_MODE !\n"); */
+ /* } */
+ /* app_audio_dac_vol_mode_set(mode); */
+
+#if defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE
+ audio_dac_set_bit_mode(&dac_hdl, 1);
+#endif/*TCFG_AUDIO_DAC_24BIT_MODE*/
+
+ //u32 dacr32 = read_capless_DTB();
+ //audio_dac_set_capless_DTB(&dac_hdl, dacr32);
+ audio_dac_set_buff(&dac_hdl, dac_buff, sizeof(dac_buff));
+ audio_dac_set_delay_time(&dac_hdl, 20, 30);
+ audio_dac_set_analog_vol(&dac_hdl, 0);
+
+ struct audio_dac_trim dac_trim = {0};
+ int len = syscfg_read(CFG_DAC_TRIM_INFO, (void *)&dac_trim, sizeof(dac_trim));
+ if (len != sizeof(dac_trim) || audio_dac_trim_value_check(&dac_trim)) {
+ audio_dac_do_trim(&dac_hdl, &dac_trim, 0);
+ syscfg_write(CFG_DAC_TRIM_INFO, (void *)&dac_trim, sizeof(dac_trim));
+ }
+
+ //mic_trim_run();
+ audio_dac_set_trim_value(&dac_hdl, &dac_trim);
+ audio_dac_set_fade_handler(&dac_hdl, NULL, audio_fade_in_fade_out);
+}
+
+static void sound_pcm_iis_driver_init(void)
+{
+ audio_iis_pcm_tx_open(&iis_hdl, TCFG_IIS_OUTPUT_DATAPORT_SEL, TCFG_IIS_SR);
+}
+
+int sound_pcm_driver_init(void)
+{
+ if (SOUND_PCM_DAC_ENABLE) {
+ sound_pcm_dac_driver_init();
+ } else if (TCFG_AUDIO_ADC_ENABLE) {
+ audio_dac_init(&dac_hdl, &dac_data);
+ }
+
+ if (SOUND_PCM_IIS_ENABLE) {
+ sound_pcm_iis_driver_init();
+ }
+ return 0;
+}
+
+void *get_iis_alink_param(void)
+{
+ return (void *)iis_hdl.alink0_param;
+}
+
+
+int sound_pcm_sync_device_select(void)
+{
+ if (SOUND_PCM_DAC_ENABLE) {
+ return PCM_INSIDE_DAC;
+ }
+
+ if (SOUND_PCM_IIS_ENABLE) {
+ return PCM_OUTSIDE_DAC;
+ }
+}
diff --git a/cpu/br28/sound_device.h b/cpu/br28/sound_device.h
new file mode 100644
index 0000000..e9e6080
--- /dev/null
+++ b/cpu/br28/sound_device.h
@@ -0,0 +1,50 @@
+/*****************************************************************
+>file name : sound_device.h
+>create time : Sat 25 Feb 2022 02:25:50 PM CST
+*****************************************************************/
+#ifndef _SOUND_PCM_DEVICE_H_
+#define _SOUND_PCM_DEVICE_H_
+#include "media/sound/sound.h"
+
+int sound_pcm_driver_init(void);
+
+int sound_pcm_sync_device_select(void);
+
+void sound_pcm_dev_try_power_on(void);
+
+void sound_pcm_dev_set_analog_gain(s16 gain);
+
+void sound_pcm_set_underrun_params(int time_ms, void *priv, void (*callback)(void *));
+
+int sound_pcm_dev_buffered_time(void);
+
+int sound_pcm_dev_buffered_frames(void);
+
+int sound_pcm_dev_channel_mapping(int ch_num);
+
+int sound_pcm_dev_write(void *private_data, void *data, int len);
+
+int sound_pcm_dev_start(void *private_data, int sample_rate, s16 volume);
+
+int sound_pcm_dev_stop(void *private_data);
+
+int sound_pcm_match_sample_rate(int sample_rate);
+
+int sound_pcm_dev_set_delay_time(int prepared_time, int delay_time);
+
+int sound_pcm_trigger_resume(int time_ms, void *priv, void (*callback)(void *priv));
+
+void sound_pcm_dev_channel_mute(u8 ch, u8 mute);
+
+int sound_pcm_dev_set_delay_time(int prepared_time, int delay_time);
+
+int sound_pcm_dev_is_running(void);
+
+void sound_pcm_dev_add_syncts(void *priv);
+
+void sound_pcm_dev_remove_syncts(void *handle);
+
+void *get_iis_alink_param(void);
+#endif
+
+
diff --git a/cpu/br28/spi.c b/cpu/br28/spi.c
new file mode 100644
index 0000000..8fac582
--- /dev/null
+++ b/cpu/br28/spi.c
@@ -0,0 +1,563 @@
+
+#undef LOG_TAG_CONST
+#define LOG_TAG "[SPI]"
+#define LOG_ERROR_ENABLE
+//#define LOG_DEBUG_ENABLE
+#include "system/debug.h"
+#include "generic/gpio.h"
+#include "asm/clock.h"
+#include "asm/spi.h"
+
+
+#define spi_enable(reg) ((reg)->CON |= BIT(0))
+#define spi_disable(reg) ((reg)->CON &= ~BIT(0))
+#define spi_role_slave(reg) ((reg)->CON |= BIT(1))
+#define spi_role_master(reg) ((reg)->CON &= ~BIT(1))
+#define spi_cs_en(reg) ((reg)->CON |= BIT(2))
+#define spi_cs_dis(reg) ((reg)->CON &= ~BIT(2))
+#define spi_bidir(reg) ((reg)->CON |= BIT(3))
+#define spi_unidir(reg) ((reg)->CON &= ~BIT(3))
+#define spi_smp_edge_rise(reg) ((reg)->CON &= ~BIT(4))
+#define spi_smp_edge_fall(reg) ((reg)->CON |= BIT(4))
+#define spi_ud_edge_rise(reg) ((reg)->CON &= ~BIT(5))
+#define spi_ud_edge_fall(reg) ((reg)->CON |= BIT(5))
+#define spi_clk_idle_h(reg) ((reg)->CON |= BIT(6))
+#define spi_clk_idle_l(reg) ((reg)->CON &= ~BIT(6))
+#define spi_cs_idle_h(reg) ((reg)->CON |= BIT(7))
+#define spi_cs_idle_l(reg) ((reg)->CON &= ~BIT(7))
+#define spi_data_width(reg, x) ((reg)->CON = (reg->CON&~(3<<10))|((x)<<10))
+#define spi_dir_in(reg) ((reg)->CON |= BIT(12))
+#define spi_dir_out(reg) ((reg)->CON &= ~BIT(12))
+#define spi_ie_en(reg) ((reg)->CON |= BIT(13))
+#define spi_ie_dis(reg) ((reg)->CON &= ~BIT(13))
+#define spi_clr_pnd(reg) ((reg)->CON |= BIT(14))
+#define spi_pnd(reg) ((reg)->CON & BIT(15))
+
+#define spi_w_reg_con(reg, val) ((reg)->CON = (val))
+#define spi_r_reg_con(reg) ((reg)->CON)
+#define spi_w_reg_buf(reg, val) ((reg)->BUF = (val))
+#define spi_r_reg_buf(reg) ((reg)->BUF)
+#define spi_w_reg_baud(reg, baud) ((reg)->BAUD = (baud))
+#define spi_r_reg_baud(reg) ((reg)->BAUD)
+#define spi_w_reg_dma_addr(reg, addr) ((reg)->ADR = (addr))
+#define spi_w_reg_dma_cnt(reg, cnt) ((reg)->CNT = (cnt))
+
+
+#define SPI1_ENABLE 1 //是否使能SPI1,使能后需定义spi1_p_data
+#define SPI2_ENABLE 1 //是否使能SPI2,使能后需定义spi2_p_data
+
+static JL_SPI_TypeDef *const spi_regs[SPI_MAX_HW_NUM] = {
+ NULL,
+ JL_SPI1,
+ JL_SPI2,
+};
+
+static u8 spi_get_info_id(spi_dev spi)
+{
+ ASSERT(spi < SPI_MAX_HW_NUM);
+ return spi;
+}
+
+static u8 *spi_get_info_port(spi_dev spi)
+{
+ u8 *port = NULL;
+ u8 id = spi_get_info_id(spi);
+ switch (id) {
+#if SPI1_ENABLE
+ case SPI1:
+ port = (u8 *)spi1_p_data.port;
+ break;
+#endif
+#if SPI2_ENABLE
+ case SPI2:
+ port = (u8 *)spi2_p_data.port;
+ break;
+#endif
+ default:
+ break;
+ }
+ return port;
+}
+
+static u8 spi_get_info_mode(spi_dev spi)
+{
+ u8 mode = (u8) - 1;
+ u8 id = spi_get_info_id(spi);
+ switch (id) {
+#if SPI1_ENABLE
+ case SPI1:
+ mode = spi1_p_data.mode;
+ break;
+#endif
+#if SPI2_ENABLE
+ case SPI2:
+ mode = spi2_p_data.mode;
+ break;
+#endif
+ default:
+ break;
+ }
+ return mode;
+}
+
+static u8 spi_get_info_role(spi_dev spi)
+{
+ u8 role = (u8) - 1;
+ u8 id = spi_get_info_id(spi);
+ switch (id) {
+#if SPI1_ENABLE
+ case SPI1:
+ role = spi1_p_data.role;
+ break;
+#endif
+#if SPI2_ENABLE
+ case SPI2:
+ role = spi2_p_data.role;
+ break;
+#endif
+ default:
+ break;
+ }
+ return role;
+}
+
+static u32 spi_get_info_clock(spi_dev spi)
+{
+ u32 clock = (u8) - 1;
+ u8 id = spi_get_info_id(spi);
+ switch (id) {
+#if SPI1_ENABLE
+ case SPI1:
+ clock = spi1_p_data.clk;
+ break;
+#endif
+#if SPI2_ENABLE
+ case SPI2:
+ clock = spi2_p_data.clk;
+ break;
+#endif
+ default:
+ break;
+ }
+ return clock;
+}
+
+static void spi1_iomc_config(spi_dev spi)
+{
+ u8 *port = spi_get_info_port(spi);
+ u8 mode = spi_get_info_mode(spi);
+ gpio_set_fun_output_port(port[0], FO_SPI1_CLK, 1, 1, LOW_POWER_FREE);
+ gpio_set_fun_output_port(port[1], FO_SPI1_DA0, 1, 1, LOW_POWER_FREE);
+ gpio_set_fun_output_port(port[2], FO_SPI1_DA1, 1, 1, LOW_POWER_FREE);
+ gpio_set_fun_input_port(port[0], PFI_SPI1_CLK, LOW_POWER_FREE);
+ gpio_set_fun_input_port(port[1], PFI_SPI1_DA0, LOW_POWER_FREE);
+ gpio_set_fun_input_port(port[2], PFI_SPI1_DA1, LOW_POWER_FREE);
+ if (mode == SPI_MODE_UNIDIR_4BIT) {
+ gpio_set_fun_output_port(port[3], FO_SPI1_DA2, 1, 1, LOW_POWER_FREE);
+ gpio_set_fun_output_port(port[4], FO_SPI1_DA3, 1, 1, LOW_POWER_FREE);
+ gpio_set_fun_input_port(port[3], PFI_SPI1_DA2, LOW_POWER_FREE);
+ gpio_set_fun_input_port(port[4], PFI_SPI1_DA3, LOW_POWER_FREE);
+ }
+}
+
+static void spi2_iomc_config(spi_dev spi)
+{
+ u8 *port = spi_get_info_port(spi);
+ u8 mode = spi_get_info_mode(spi);
+ gpio_set_fun_output_port(port[0], FO_SPI2_CLK, 1, 1, LOW_POWER_FREE);
+ gpio_set_fun_output_port(port[1], FO_SPI2_DA0, 1, 1, LOW_POWER_FREE);
+ gpio_set_fun_output_port(port[2], FO_SPI2_DA1, 1, 1, LOW_POWER_FREE);
+ gpio_set_fun_input_port(port[0], PFI_SPI2_CLK, LOW_POWER_FREE);
+ gpio_set_fun_input_port(port[1], PFI_SPI2_DA0, LOW_POWER_FREE);
+ gpio_set_fun_input_port(port[2], PFI_SPI2_DA1, LOW_POWER_FREE);
+ if (mode == SPI_MODE_UNIDIR_4BIT) {
+ gpio_set_fun_output_port(port[3], FO_SPI2_DA2, 1, 1, LOW_POWER_FREE);
+ gpio_set_fun_output_port(port[4], FO_SPI2_DA3, 1, 1, LOW_POWER_FREE);
+ gpio_set_fun_input_port(port[3], PFI_SPI2_DA2, LOW_POWER_FREE);
+ gpio_set_fun_input_port(port[4], PFI_SPI2_DA3, LOW_POWER_FREE);
+ }
+}
+
+static void (*pSPI_IOMC_CONFIG[])(spi_dev spi) = {
+ NULL,
+ spi1_iomc_config,
+ spi2_iomc_config,
+};
+
+
+static void spi_io_port_init(u8 port, u8 dir)
+{
+ if (port != (u8) - 1) {
+ if (dir == 1) {
+ gpio_set_direction(port, 1);
+ } else {
+ gpio_set_direction(port, 0);
+ }
+ gpio_set_die(port, 1);
+ gpio_set_pull_up(port, 0);
+ gpio_set_pull_down(port, 0);
+ }
+}
+
+static void spi_io_port_uninit(u8 port)
+{
+ if (port != (u8) - 1) {
+ gpio_set_direction(port, 1);
+ gpio_set_die(port, 0);
+ gpio_set_pull_up(port, 0);
+ gpio_set_pull_down(port, 0);
+ }
+}
+
+/*
+ * @brief 设置波特率
+ * @parm spi spi句柄
+ * @parm baud 波特率
+ * @return 0 成功,< 0 失败
+ */
+int spi_set_baud(spi_dev spi, u32 baud)
+{
+ //SPICK = sysclk / (SPIx_BAUD + 1)
+ //=> SPIx_BAUD = sysclk / SPICK - 1
+ u8 id = spi_get_info_id(spi);
+ u32 sysclk;
+
+ sysclk = clk_get("spi");
+ log_debug("spi clock source freq %lu", sysclk);
+ if (sysclk < baud) {
+ spi_w_reg_baud(spi_regs[id], 0);
+ return -EINVAL;
+ }
+ spi_w_reg_baud(spi_regs[id], sysclk / baud - 1);
+ return 0;
+}
+
+/*
+ * @brief 获取波特率
+ * @parm spi spi句柄
+ * @return 波特率
+ */
+u32 spi_get_baud(spi_dev spi)
+{
+ u8 id = spi_get_info_id(spi);
+ return spi_get_info_clock(spi);
+}
+
+static int __spi_wait_ok(spi_dev spi, u32 n)
+{
+ u8 id = spi_get_info_id(spi);
+ u32 baud = spi_get_info_clock(spi);
+ baud = clk_get("spi") / baud - 1;
+ u32 retry = baud * (clk_get("sys") / clk_get("spi")) * 8 * n * 5; //500% spi baudate
+
+ while (!spi_pnd(spi_regs[id])) {
+ __asm__ volatile("nop");
+ if (--retry == 0) {
+ log_error("spi wait pnd timeout");
+ return -EFAULT;
+ }
+ }
+ spi_clr_pnd(spi_regs[id]);
+ return 0;
+}
+
+/*
+ * @brief 发送1个字节
+ * @parm spi spi句柄
+ * @parm byte 发送的字节
+ * @return 0 成功,< 0 失败
+ */
+int spi_send_byte(spi_dev spi, u8 byte)
+{
+ u8 id = spi_get_info_id(spi);
+
+ spi_dir_out(spi_regs[id]);
+ spi_w_reg_buf(spi_regs[id], byte);
+ return __spi_wait_ok(spi, 1);
+}
+
+/*
+ * @brief 发送1个字节,不等待pnd,用于中断
+ * @parm spi spi句柄
+ * @parm byte 发送的字节
+ * @return null
+ */
+void spi_send_byte_for_isr(spi_dev spi, u8 byte)
+{
+ u8 id = spi_get_info_id(spi);
+
+ spi_dir_out(spi_regs[id]);
+ spi_w_reg_buf(spi_regs[id], byte);
+}
+
+/*
+ * @brief 接收1个字节
+ * @parm spi spi句柄
+ * @parm err 返回错误信息,若err为非空指针,0 成功,< 0 失败,若为空指针,忽略
+ * @return 接收的字节
+ */
+u8 spi_recv_byte(spi_dev spi, int *err)
+{
+ u8 id = spi_get_info_id(spi);
+ int ret;
+
+ spi_dir_in(spi_regs[id]);
+ spi_w_reg_buf(spi_regs[id], 0xff);
+ ret = __spi_wait_ok(spi, 1);
+ if (ret) {
+ err != NULL ? *err = ret : 0;
+ return 0;
+ }
+ err != NULL ? *err = 0 : 0;
+ return spi_r_reg_buf(spi_regs[id]);
+}
+
+
+/*
+ * @brief 接收1个字节,不等待pnd,用于中断
+ * @parm spi spi句柄
+ * @return 接收的字节
+ */
+u8 spi_recv_byte_for_isr(spi_dev spi)
+{
+ u8 id = spi_get_info_id(spi);
+
+ spi_dir_in(spi_regs[id]);
+ return spi_r_reg_buf(spi_regs[id]);
+}
+
+/*
+ * @brief 发送并接收1个字节,在8个时钟内完成,仅使用于SPI_MODE_BIDIR_1BIT
+ * @parm spi spi句柄
+ * @parm byte 发送的字节
+ * @parm err 返回错误信息,若err为非空指针,0 成功,< 0 失败,若为空指针,忽略
+ * @return 接收的字节
+ */
+u8 spi_send_recv_byte(spi_dev spi, u8 byte, int *err)
+{
+ u8 id = spi_get_info_id(spi);
+ int ret;
+
+ spi_w_reg_buf(spi_regs[id], byte);
+ ret = __spi_wait_ok(spi, 1);
+ if (ret) {
+ err != NULL ? *err = ret : 0;
+ return 0;
+ }
+ err != NULL ? *err = 0 : 0;
+ return spi_r_reg_buf(spi_regs[id]);
+}
+
+/*
+ * @brief 设置spi[单向/双向,位数]模式
+ * @parm spi spi句柄
+ * @parm mode 模式
+ * @return null
+ */
+void spi_set_bit_mode(spi_dev spi, int mode)
+{
+ u8 id = spi_get_info_id(spi);
+ u8 *port = spi_get_info_port(spi);
+ u8 role = spi_get_info_role(spi);
+
+ switch (mode) {
+ case SPI_MODE_BIDIR_1BIT:
+ spi_bidir(spi_regs[id]);
+ spi_data_width(spi_regs[id], 0);
+ break;
+ case SPI_MODE_UNIDIR_1BIT:
+ spi_unidir(spi_regs[id]);
+ spi_data_width(spi_regs[id], 0);
+ break;
+ case SPI_MODE_UNIDIR_2BIT:
+ spi_unidir(spi_regs[id]);
+ spi_data_width(spi_regs[id], 1);
+ break;
+ case SPI_MODE_UNIDIR_4BIT:
+ spi_unidir(spi_regs[id]);
+ spi_data_width(spi_regs[id], 2);
+ break;
+ }
+
+ spi_io_port_init(port[0], role == SPI_ROLE_MASTER ? 0 : 1);
+ if (mode == SPI_MODE_BIDIR_1BIT) {
+ spi_io_port_init(port[1], 0);
+ spi_io_port_init(port[2], 1);
+ } else if (mode == SPI_MODE_UNIDIR_2BIT) {
+ spi_io_port_init(port[1], role == SPI_ROLE_MASTER ? 0 : 1);
+ spi_io_port_init(port[2], role == SPI_ROLE_MASTER ? 0 : 1);
+ } else if (mode == SPI_MODE_UNIDIR_4BIT) {
+ spi_io_port_init(port[1], role == SPI_ROLE_MASTER ? 0 : 1);
+ spi_io_port_init(port[2], role == SPI_ROLE_MASTER ? 0 : 1);
+ spi_io_port_init(port[3], role == SPI_ROLE_MASTER ? 0 : 1);
+ spi_io_port_init(port[4], role == SPI_ROLE_MASTER ? 0 : 1);
+ }
+}
+
+/*
+ * @brief 打开spi
+ * @parm spi spi句柄
+ * @return 0 成功,< 0 失败
+ */
+int spi_open(spi_dev spi)
+{
+ int err;
+ u8 id = spi_get_info_id(spi);
+ u8 mode = spi_get_info_mode(spi);
+ u8 role = spi_get_info_role(spi);
+ u32 clock = spi_get_info_clock(spi);
+
+ pSPI_IOMC_CONFIG[id](spi);
+
+ spi_set_bit_mode(spi, mode);
+ spi_cs_dis(spi_regs[id]);
+ if (role == SPI_ROLE_MASTER) {
+ spi_role_master(spi_regs[id]);
+ } else if (role == SPI_ROLE_SLAVE) {
+ spi_role_slave(spi_regs[id]);
+ }
+ spi_smp_edge_rise(spi_regs[id]);
+ spi_ud_edge_fall(spi_regs[id]);
+ spi_cs_idle_h(spi_regs[id]);
+ spi_clk_idle_l(spi_regs[id]);
+ spi_clr_pnd(spi_regs[id]);
+ if ((err = spi_set_baud(spi, clock))) {
+ log_error("invalid spi baudrate");
+ /* return 0; */
+ }
+ if (role == SPI_ROLE_MASTER) {
+ spi_w_reg_buf(spi_regs[id], 0);//设定spi初始化后DO口默认电平为低
+ } else if (role == SPI_ROLE_SLAVE) {
+ spi_w_reg_buf(spi_regs[id], 0xff);
+ }
+ spi_enable(spi_regs[id]);
+
+#if 0
+ printf("spi%d clk = %d\n", id, clock);
+ printf("spi%d mode = %d\n", id, mode);
+ printf("spi%d role = %d\n", id, role);
+ printf("spi%d clk_pin = %d\n", id, port[0]);
+ printf("spi%d do_pin = %d\n", id, port[1]);
+ printf("spi%d di_pin = %d\n", id, port[2]);
+ printf("spi%d CON = %04x\n", id, spi_r_reg_con(spi_regs[id]));
+ printf("spi%d IOMC1 = %08x\n", id, JL_IOMAP->CON1);
+#endif
+ return 0;
+}
+
+/*
+ * @brief spi dma接收
+ * @parm spi spi句柄
+ * @parm buf 接收缓冲区基地址
+ * @parm len 期望接收长度
+ * @return 实际接收长度,< 0表示失败
+ */
+int spi_dma_recv(spi_dev spi, void *buf, u32 len)
+{
+ u8 id = spi_get_info_id(spi);
+
+ /* ASSERT((u32)buf % 4 == 0, "spi dma addr need 4-aligned"); */
+ spi_dir_in(spi_regs[id]);
+ spi_w_reg_dma_addr(spi_regs[id], (u32)buf);
+ spi_w_reg_dma_cnt(spi_regs[id], len);
+ asm("csync");
+ if (__spi_wait_ok(spi, len)) {
+ return -EFAULT;
+ }
+ return len;
+}
+
+/*
+ * @brief spi dma发送
+ * @parm spi spi句柄
+ * @parm buf 发送缓冲区基地址
+ * @parm len 期望发送长度
+ * @return 实际发送长度,< 0表示失败
+ */
+int spi_dma_send(spi_dev spi, const void *buf, u32 len)
+{
+ u8 id = spi_get_info_id(spi);
+
+ /* ASSERT((u32)buf % 4 == 0, "spi dma addr need 4-aligned"); */
+ spi_dir_out(spi_regs[id]);
+ spi_w_reg_dma_addr(spi_regs[id], (u32)buf);
+ spi_w_reg_dma_cnt(spi_regs[id], len);
+ asm("csync");
+ if (__spi_wait_ok(spi, len)) {
+ return -EFAULT;
+ }
+ return len;
+}
+
+/*
+ * @brief spi 配置dma,不等待pnd,用于中断
+ * @parm spi spi句柄
+ * @parm buf 缓冲区基地址
+ * @parm len 期望长度
+ * @parm rw 1 接收 / 0 发送
+ * @return null
+ */
+void spi_dma_set_addr_for_isr(spi_dev spi, void *buf, u32 len, u8 rw)
+{
+ u8 id = spi_get_info_id(spi);
+
+ /* ASSERT((u32)buf % 4 == 0, "spi dma addr need 4-aligned"); */
+ rw ? spi_dir_in(spi_regs[id]) : spi_dir_out(spi_regs[id]);
+ spi_w_reg_dma_addr(spi_regs[id], (u32)buf);
+ spi_w_reg_dma_cnt(spi_regs[id], len);
+}
+
+/*
+ * @brief 中断使能
+ * @parm spi spi句柄
+ * @parm en 1 使能,0 失能
+ * @return null
+ */
+void spi_set_ie(spi_dev spi, u8 en)
+{
+ u8 id = spi_get_info_id(spi);
+ en ? spi_ie_en(spi_regs[id]) : spi_ie_dis(spi_regs[id]);
+}
+
+/*
+ * @brief 判断中断标志
+ * @parm spi spi句柄
+ * @return 0 / 1
+ */
+u8 spi_get_pending(spi_dev spi)
+{
+ u8 id = spi_get_info_id(spi);
+ return spi_pnd(spi_regs[id]) ? 1 : 0;
+}
+
+/*
+ * @brief 清除中断标志
+ * @parm spi spi句柄
+ * @return null
+ */
+void spi_clear_pending(spi_dev spi)
+{
+ u8 id = spi_get_info_id(spi);
+ spi_clr_pnd(spi_regs[id]);
+}
+
+/*
+ * @brief 关闭spi
+ * @parm spi spi句柄
+ * @return null
+ */
+void spi_close(spi_dev spi)
+{
+ u8 id = spi_get_info_id(spi);
+ u8 *port = spi_get_info_port(spi);
+ spi_io_port_uninit(port[0]);
+ spi_io_port_uninit(port[1]);
+ spi_io_port_uninit(port[2]);
+ spi_disable(spi_regs[id]);
+}
+void spi_disable_for_ota()
+{
+ for (int i = 0; i < 2; i++) {
+ spi_disable(spi_regs[i]);
+ }
+}
diff --git a/cpu/br28/tone_player.c b/cpu/br28/tone_player.c
new file mode 100644
index 0000000..837df3b
--- /dev/null
+++ b/cpu/br28/tone_player.c
@@ -0,0 +1,2044 @@
+#include "system/includes.h"
+#include "media/includes.h"
+#include "tone_player.h"
+#include "audio_config.h"
+#include "app_main.h"
+#include "btstack/avctp_user.h"
+#include "aec_user.h"
+#include "audio_dvol.h"
+#include "audio_codec_clock.h"
+#include "sound_device.h"
+#if TCFG_AUDIO_HEARING_AID_ENABLE
+#include "audio_hearing_aid.h"
+#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
+
+#if TCFG_APP_FM_EMITTER_EN
+#include "fm_emitter/fm_emitter_manage.h"
+#endif
+
+
+#define LOG_TAG_CONST APP_TONE
+#define LOG_TAG "[APP-TONE]"
+#define LOG_ERROR_ENABLE
+#define LOG_INFO_ENABLE
+#define LOG_DUMP_ENABLE
+#include "debug.h"
+
+#define TONE_LIST_MAX_NUM 4
+
+#if TCFG_USER_TWS_ENABLE
+#include "media/bt_audio_timestamp.h"
+#include "audio_syncts.h"
+#include "bt_tws.h"
+
+#define msecs_to_bt_time(m) (((m + 1)* 1000) / 625)
+#define TWS_TONE_ALIGN_TIME 0
+#define TWS_TONE_ALIGN_MIX 1
+
+#define TONE_DEC_NOT_START 0
+#define TONE_DEC_WAIT_ALIGN_TIME 1
+#define TONE_DEC_WAIT_MIX 2
+#define TONE_DEC_CONFIRM 3
+
+#define TWS_TONE_CONFIRM_TIME 250 /*TWS提示音音频同步确认时间(也是音频解码主从确认超时时间)*/
+
+#endif
+
+/*ANC提示音播放,背景音乐自动淡出变小声(提示音名字格式:ancxxx.*) */
+#define ANC_TONE_BGM_FADEOUT 1
+
+#define TONE_FILE_DEC_MIX 1 //提示音叠加播放
+/*支持提示音叠加播放的音频格式列表*/
+static const char *tone_mix_fmt_tab[] = {
+#if TCFG_WTS_TONE_MIX_ENABLE
+ "wts",
+#endif/*TCFG_WTS_TONE_MIX_ENABLE*/
+#if TCFG_WTG_TONE_MIX_ENABLE
+ "wtg",
+#endif/*TCFG_WTG_TONE_MIX_ENABLE*/
+#if TCFG_WAV_TONE_MIX_ENABLE
+ "wav",
+#endif/*TCFG_WAV_TONE_MIX_ENABLE*/
+#if TCFG_MP3_TONE_MIX_ENABLE
+ "mp3",
+#endif/*TCFG_MP3_TONE_MIX_ENABLE*/
+#if TCFG_AAC_TONE_MIX_ENABLE
+ "aac",
+#endif/*TCFG_AAC_TONE_MIX_ENABLE*/
+};
+
+static OS_MUTEX tone_mutex;
+struct tone_file_handle {
+ u8 start;
+ u8 idx;
+ u8 repeat_begin;
+ u8 remain;
+ u8 tws;
+ u16 loop;
+ u32 magic;
+ void *file;
+ const char **list;
+ enum audio_channel channel;
+ struct audio_decoder decoder;
+ struct audio_mixer_ch mix_ch;
+ u8 ch_num;
+ u16 target_sample_rate;
+#if TCFG_USER_TWS_ENABLE
+ u32 wait_time;
+ u8 tws_align_step;
+ u8 ts_start;
+ void *audio_sync;
+ void *syncts;
+ void *ts_handle;
+ u32 time_base;
+#endif
+ u32 mix_ch_event_params[3];
+ struct audio_src_handle *hw_src;
+ u32 clk_before_dec;
+ u8 dec_mix;
+};
+
+struct tone_sine_handle {
+ u8 start;
+ u8 repeat;
+ u32 sine_id;
+ u32 sine_offset;
+ void *sin_maker;
+ struct audio_decoder decoder;
+ struct audio_mixer_ch mix_ch;
+ struct sin_param sin_dynamic_params[8];
+ u32 clk_before;
+ u8 dec_mix;
+ u8 remain;
+};
+
+struct tone_dec_handle {
+ u8 r_index;
+ u8 w_index;
+ u8 list_cnt;
+ u8 preemption;
+ const char **list[4];
+ struct audio_res_wait wait;
+ u8 dec_mix;
+
+ u8 normal_end; // 正常结束
+ const char *user_evt_owner;
+ void (*user_evt_handler)(void *priv);
+ void *priv;
+};
+
+
+extern struct audio_mixer mixer;
+extern struct audio_dac_hdl dac_hdl;
+extern struct audio_decoder_task decode_task;
+
+static struct tone_file_handle *file_dec;
+static struct tone_sine_handle *sine_dec;
+static char *single_file[2] = {NULL};
+struct tone_dec_handle *tone_dec;
+
+int sine_dec_close(void);
+int tone_file_dec_start();
+u16 get_source_sample_rate();
+extern void audio_mix_ch_event_handler(void *priv, int event);
+extern int bt_audio_sync_nettime_select(u8 basetime);
+extern u32 bt_audio_sync_lat_time(void);
+static void file_decoder_syncts_free(struct tone_file_handle *dec);
+
+void tone_event_to_user(u8 event, const char *name);
+void tone_event_clear()
+{
+ struct sys_event e = {0};
+ e.type = SYS_DEVICE_EVENT;
+ e.arg = (void *)DEVICE_EVENT_FROM_TONE;
+ sys_event_clear(&e);
+}
+void tone_set_user_event_handler(struct tone_dec_handle *dec, void (*user_evt_handler)(void *priv), void *priv)
+
+{
+ printf("tone_set_user_event_handler:%d\n", *(u8 *)priv);
+ dec->user_evt_owner = os_current_task();
+ dec->user_evt_handler = user_evt_handler;
+ dec->priv = priv;
+}
+
+
+int tone_event_handler(struct tone_dec_handle *dec)
+{
+ int argv[4];
+ if (!dec->user_evt_handler) {
+ /* log_info("user_evt_handler null\n"); */
+ return -1;
+ }
+
+ if (strcmp(os_current_task(), dec->user_evt_owner) == 0) {
+ ((void(*)(void *, int))dec->user_evt_handler)(dec->priv, (!dec->normal_end));
+ /* dec->user_evt_handler(dec->priv); */
+ return 0;
+ }
+ /* dec->user_evt_handler(dec->priv); */
+ argv[0] = (int)dec->user_evt_handler;
+ argv[1] = 2;
+ argv[2] = (int)dec->priv;
+ argv[3] = (int)(!dec->normal_end);//是否是被打断 关闭,0正常关闭,1被打断关闭
+
+ return os_taskq_post_type(dec->user_evt_owner, Q_CALLBACK, 4, argv);
+ /* return 0; */
+}
+
+__attribute__((weak))
+int audio_dac_stop(struct audio_dac_hdl *p)
+{
+ return 0;
+}
+__attribute__((weak))
+int audio_dac_write(struct audio_dac_hdl *dac, void *data, int len)
+{
+ return len;
+}
+
+__attribute__((weak))
+int audio_dac_get_sample_rate(struct audio_dac_hdl *p)
+{
+ return 16000;
+}
+
+__attribute__((weak))
+void audio_dac_clear(struct audio_dac_hdl *dac)
+{
+
+}
+static u8 tone_dec_idle_query()
+{
+ if (file_dec || sine_dec) {
+ return 0;
+ }
+ return 1;
+}
+REGISTER_LP_TARGET(tone_dec_lp_target) = {
+ .name = "tone_dec",
+ .is_idle = tone_dec_idle_query,
+};
+
+#if TCFG_USER_TWS_ENABLE
+
+#define bt_time_before(t1, t2) \
+ (((t1 < t2) && ((t2 - t1) & 0x7ffffff) < 0xffff) || \
+ ((t1 > t2) && ((t1 - t2) & 0x7ffffff) > 0xffff))
+
+#define TWS_FUNC_ID_TONE_ALIGN \
+ (((u8)('T' + 'O' + 'N' + 'E') << (2 * 8)) | \
+ ((u8)('P' + 'L' + 'A' + 'Y' + 'E' + 'R') << (1 * 8)) | \
+ ((u8)('S' + 'Y' + 'N' + 'C') << (0 * 8)))
+
+struct tws_tone_align {
+ u8 confirm;
+ u8 type;
+ union {
+ int time;
+ int position;
+ };
+};
+struct tws_tone_align tws_tone = {0};
+/*static u8 tws_tone_align = 0;*/
+/*static int tws_tone_align_time = 0;*/
+static void tws_tone_play_rx_align_data(void *data, u16 len, bool rx)
+{
+ local_irq_disable();
+ memcpy(&tws_tone, data, sizeof(tws_tone));
+ tws_tone.confirm = 1;
+ local_irq_enable();
+ y_printf("tone tws confirm rx : %d\n", tws_tone.time);
+}
+
+REGISTER_TWS_FUNC_STUB(tone_play_align) = {
+ .func_id = TWS_FUNC_ID_TONE_ALIGN,
+ .func = tws_tone_play_rx_align_data,
+};
+
+static void tone_mixer_ch_event_handler(void *priv, int event)
+{
+ struct tone_file_handle *dec = (struct tone_file_handle *)priv;
+
+ switch (event) {
+ case MIXER_EVENT_CH_OPEN:
+ break;
+ case MIXER_EVENT_CH_CLOSE:
+ case MIXER_EVENT_CH_RESET:
+ break;
+ default:
+ break;
+ }
+}
+#endif
+
+void tone_event_to_user(u8 event, const char *name)
+{
+ struct sys_event e;
+ e.type = SYS_DEVICE_EVENT;
+ e.arg = (void *)DEVICE_EVENT_FROM_TONE;
+ e.u.dev.event = event;
+ e.u.dev.value = (int)name;
+ sys_event_notify(&e);
+}
+
+static char *get_file_ext_name(char *name)
+{
+ int len = strlen(name);
+ char *ext = (char *)name;
+
+ while (len--) {
+ if (*ext++ == '.') {
+ break;
+ }
+ }
+
+ return ext;
+}
+
+static void tone_file_dec_release()
+{
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_bg_fade(0);
+ audio_digital_vol_close(TONE_DVOL);
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+ free(file_dec);
+ file_dec = NULL;
+}
+
+int tone_list_play_start(const char **list, u8 preemption, u8 tws);
+
+static int tone_file_list_clean(u8 decoding)
+{
+ int i = 0;
+
+ if (!tone_dec) {
+ return 0;
+ }
+
+ for (i = 0; i < TONE_LIST_MAX_NUM; i++) {
+ if (tone_dec->list[i]) {
+ if (decoding && i == tone_dec->r_index) {
+ continue;
+ }
+ free(tone_dec->list[i]);
+ tone_dec->list[i] = NULL;
+ }
+ }
+
+ if (decoding) {
+ tone_dec->w_index = tone_dec->r_index + 1;
+ if (tone_dec->w_index >= TONE_LIST_MAX_NUM) {
+ tone_dec->w_index = 0;
+ }
+ tone_dec->list_cnt = 1;
+ } else {
+ tone_dec->list_cnt = 0;
+ }
+ return 0;
+}
+
+void tone_dec_release()
+{
+ if (!tone_dec) {
+ os_mutex_post(&tone_mutex);
+ return;
+ }
+
+ tone_event_handler(tone_dec);
+ audio_decoder_task_del_wait(&decode_task, &tone_dec->wait);
+
+ tone_file_list_clean(0);
+ free(tone_dec);
+ tone_dec = NULL;
+ os_mutex_post(&tone_mutex);
+}
+
+void tone_dec_end_handler(int event, const char *name)
+{
+ const char **list;
+
+ list = tone_dec->list[tone_dec->r_index];
+
+ if (++tone_dec->r_index >= TONE_LIST_MAX_NUM) {
+ tone_dec->r_index = 0;
+ }
+ if (--tone_dec->list_cnt > 0) {
+ tone_list_play_start(tone_dec->list[tone_dec->r_index], tone_dec->preemption, 1);
+ } else {
+ tone_dec_release();
+ }
+
+ tone_event_to_user(event, name);
+}
+
+
+static int tone_file_list_repeat(struct audio_decoder *decoder)
+{
+ int err = 0;
+
+ file_dec->idx++;
+ if (!file_dec->list[file_dec->idx]) {
+ log_info("repeat end 1:idx end");
+ return 0;
+ }
+
+ if (IS_REPEAT_END(file_dec->list[file_dec->idx])) {
+ //log_info("repeat_loop:%d",file_dec->loop);
+ if (file_dec->loop) {
+ file_dec->loop--;
+ file_dec->idx = file_dec->repeat_begin;
+ } else {
+ file_dec->idx++;
+ if (!file_dec->list[file_dec->idx]) {
+ log_info("repeat end 2:idx end");
+ return 0;
+ }
+ }
+ }
+
+ if (IS_REPEAT_BEGIN(file_dec->list[file_dec->idx])) {
+ if (!file_dec->loop) {
+ file_dec->loop = TONE_REPEAT_COUNT(file_dec->list[file_dec->idx]);
+ log_info("repeat begin:%d", file_dec->loop);
+ }
+ file_dec->idx++;
+ file_dec->repeat_begin = file_dec->idx;
+ }
+
+ log_info("repeat idx:%d,%s", file_dec->idx, file_dec->list[file_dec->idx]);
+ file_dec->file = fopen(file_dec->list[file_dec->idx], "r");
+ if (!file_dec->file) {
+ log_error("repeat end:fopen repeat file faild");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int tone_audio_res_close(u8 rpt)
+{
+ if (file_dec->start) {
+ audio_decoder_close(&file_dec->decoder);
+ }
+
+ if (file_dec->hw_src) {
+ audio_hw_src_stop(file_dec->hw_src);
+ audio_hw_src_close(file_dec->hw_src);
+ free(file_dec->hw_src);
+ file_dec->hw_src = NULL;
+ }
+
+ if (file_dec->start) {
+ audio_mixer_ch_close(&file_dec->mix_ch);
+ file_dec->start = 0;
+ }
+
+#if TCFG_USER_TWS_ENABLE
+ file_decoder_syncts_free(file_dec);
+#endif
+
+ if (!rpt) {
+ if (app_audio_get_state() == APP_AUDIO_STATE_WTONE) {
+ app_audio_state_exit(APP_AUDIO_STATE_WTONE);
+ }
+ }
+
+#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_AND_TONE_MUTEX)
+ audio_hearing_aid_resume();
+#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
+ return 0;
+}
+
+static void tone_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
+{
+ int repeat = 0;
+ switch (argv[0]) {
+ case AUDIO_DEC_EVENT_END:
+ case AUDIO_DEC_EVENT_ERR:
+ if (argv[1] != file_dec->magic) {
+ log_error("file_dec magic no match:%d-%d", argv[1], file_dec->magic);
+ break;
+ }
+ repeat = tone_file_list_repeat(decoder);
+ log_info("AUDIO_DEC_EVENT_END,err=%x,repeat=%d\n", argv[0], repeat);
+
+ if (repeat) {
+ tone_audio_res_close(repeat);
+
+ tone_file_dec_start();
+ } else {
+ if (tone_dec) {
+ tone_dec->normal_end = 1; // 标记为正常解码结束
+ }
+ tone_file_list_stop(0);
+ if (tone_dec) {
+ tone_dec->normal_end = 0; // 恢复为非正常结束
+ }
+ }
+ break;
+ default:
+ return;
+ }
+}
+
+int tone_get_status()
+{
+ return tone_dec ? TONE_START : TONE_STOP;
+}
+
+int tone_get_dec_status()
+{
+ if (tone_dec && file_dec && (file_dec->decoder.state != DEC_STA_WAIT_STOP)) {
+ return TONE_START;
+ }
+ if (tone_dec && sine_dec && (sine_dec->decoder.state != DEC_STA_WAIT_STOP)) {
+ return TONE_START;
+ }
+ return TONE_STOP;
+}
+int tone_dec_wait_stop(u32 timeout_ms)
+{
+ u32 to_cnt = 0;
+ while (tone_get_dec_status()) {
+ /* putchar('t'); */
+ os_time_dly(1);
+ if (timeout_ms) {
+ to_cnt += 10;
+ if (to_cnt >= timeout_ms) {
+ break;
+ }
+ }
+ }
+ return tone_get_dec_status();
+}
+
+static int tone_fread(struct audio_decoder *decoder, void *buf, u32 len)
+{
+ int rlen = 0;
+
+ if (!file_dec->file) {
+ return 0;
+ }
+
+ rlen = fread(file_dec->file, buf, len);
+ if (rlen < len) {
+ fclose(file_dec->file);
+ file_dec->file = NULL;
+ }
+ return rlen;
+}
+
+static int tone_fseek(struct audio_decoder *decoder, u32 offset, int seek_mode)
+{
+ if (!file_dec->file) {
+ return 0;
+ }
+ return fseek(file_dec->file, offset, seek_mode);
+}
+
+static int tone_flen(struct audio_decoder *decoder)
+{
+ void *tone_file = NULL;
+ int len = 0;
+
+ if (file_dec->file) {
+ len = flen(file_dec->file);
+ return len;
+ }
+
+ tone_file = fopen(file_dec->list[file_dec->idx], "r");
+ if (tone_file) {
+ len = flen(tone_file);
+ fclose(tone_file);
+ tone_file = NULL;
+ }
+ return len;
+}
+
+static int tone_fclose(void *file)
+{
+ if (file_dec->file) {
+ fclose(file_dec->file);
+ file_dec->file = NULL;
+ }
+
+ file_dec->idx = 0;
+ return 0;
+}
+
+struct tone_format {
+ const char *fmt;
+ u32 coding_type;
+};
+
+const struct tone_format tone_fmt_support_list[] = {
+#if TCFG_DEC_WTGV2_ENABLE
+ {"wts", AUDIO_CODING_WTGV2},
+#endif/*TCFG_DEC_WTGV2_ENABLE*/
+#if TCFG_DEC_G729_ENABLE
+ {"wtg", AUDIO_CODING_G729},
+#endif/*TCFG_DEC_G729_ENABLE*/
+ {"msbc", AUDIO_CODING_MSBC},
+ {"sbc", AUDIO_CODING_SBC},
+ {"mty", AUDIO_CODING_MTY},
+#if TCFG_DEC_AAC_ENABLE
+ {"aac", AUDIO_CODING_AAC},
+#endif/*TCFG_DEC_AAC_ENABLE*/
+#if TCFG_DEC_MP3_ENABLE
+ {"mp3", AUDIO_CODING_MP3},
+#endif/*TCFG_DEC_MP3_ENABLE*/
+#if TCFG_DEC_WAV_ENABLE
+ {"wav", AUDIO_CODING_WAV},
+#endif/*TCFG_DEC_WAV_ENABLE*/
+ {"lc3", AUDIO_CODING_LC3},
+#if TCFG_DEC_SPEEX_ENABLE
+ {"speex", AUDIO_CODING_SPEEX},
+#endif/*TCFG_DEC_SPEEX_ENABLE*/
+#if TCFG_DEC_OPUS_ENABLE
+ {"opus", AUDIO_CODING_OPUS},
+#endif/*TCFG_DEC_OPUS_ENABLE*/
+};
+
+static struct audio_dec_input tone_input = {
+ .coding_type = AUDIO_CODING_G729,
+ .data_type = AUDIO_INPUT_FILE,
+ .ops = {
+ .file = {
+ .fread = tone_fread,
+ .fseek = tone_fseek,
+ .flen = tone_flen,
+ }
+ }
+};
+
+static u32 tone_file_format_match(char *fmt)
+{
+ int list_num = ARRAY_SIZE(tone_fmt_support_list);
+ int i = 0;
+
+#ifdef BT_DUT_INTERFERE
+ return AUDIO_CODING_UNKNOW;
+#endif
+
+ if (fmt == NULL) {
+ return AUDIO_CODING_UNKNOW;
+ }
+
+ for (i = 0; i < list_num; i++) {
+ if (ASCII_StrCmpNoCase(fmt, tone_fmt_support_list[i].fmt, 4) == 0) {
+ return tone_fmt_support_list[i].coding_type;
+ }
+ }
+
+ return AUDIO_CODING_UNKNOW;
+}
+
+#if TCFG_USER_TWS_ENABLE
+static u8 tws_tone_dec_confirm_timeout(struct audio_decoder *decoder)
+{
+ struct tone_file_handle *dec = container_of(decoder, struct tone_file_handle, decoder);
+
+ if (time_after(jiffies, dec->wait_time)) {
+ return 1;
+ }
+ return 0;
+}
+
+
+u8 tws_tone_together_without_bt(void);
+void tws_tone_together_clean(void);
+u32 tws_tone_local_together_time(void);
+extern u8 bt_audio_is_running(void);
+#endif
+
+static int tone_dec_probe_handler(struct audio_decoder *decoder)
+{
+ struct tone_file_handle *dec = container_of(decoder, struct tone_file_handle, decoder);
+ int err = 0;
+
+#if TCFG_USER_TWS_ENABLE
+ if (dec->tws_align_step == 0 && dec->ts_handle) {
+ if (!tws_file_timestamp_available(dec->ts_handle)) {
+ audio_decoder_suspend(decoder, 0);
+ return -EINVAL;
+ }
+ dec->tws_align_step = 1;
+ }
+#endif
+
+ return 0;
+}
+
+static int tone_final_output_handler(struct tone_file_handle *dec, s16 *data, int len)
+{
+ return audio_mixer_ch_write(&dec->mix_ch, data, len);
+}
+
+static int tone_output_after_syncts_filter(void *priv, void *data, int len)
+{
+ struct tone_file_handle *dec = (struct tone_file_handle *)priv;
+ int wlen = 0;
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ if (dec->remain == 0) {
+ audio_digital_vol_run(TONE_DVOL, data, len);
+ }
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+
+ if (dec->hw_src) {
+ wlen = audio_src_resample_write(dec->hw_src, data, len);
+ if (wlen < len) {
+ audio_hw_src_trigger_resume(dec->hw_src, &dec->decoder, (void (*)(void *))audio_decoder_resume);
+ }
+
+ goto ret;
+ }
+ wlen = tone_final_output_handler(dec, data, len);
+
+ret:
+ dec->remain = wlen < len ? 1 : 0;
+
+ return wlen;
+}
+
+static int tone_dec_output_handler(struct audio_decoder *decoder, s16 *data, int len, void *priv)
+{
+ int wlen = 0;
+ int remain_len = len;
+ struct tone_file_handle *dec = container_of(decoder, struct tone_file_handle, decoder);
+
+#if TCFG_USER_TWS_ENABLE
+ if (dec->syncts) {
+ if (dec->ts_handle) {
+ u32 timestamp = file_audio_timestamp_update(dec->ts_handle, audio_syncts_get_dts(dec->syncts));
+ audio_syncts_next_pts(dec->syncts, timestamp);
+ if (!dec->ts_start) {
+ dec->mix_ch_event_params[2] = timestamp;
+ dec->ts_start = 1;
+ }
+ }
+ wlen = audio_syncts_frame_filter(dec->syncts, data, len);
+ if (wlen < len) {
+ audio_syncts_trigger_resume(dec->syncts, decoder, (void (*)(void *))audio_decoder_resume);
+ }
+ return wlen;
+ }
+#endif
+ return tone_output_after_syncts_filter(dec, data, len);
+}
+
+static int tone_dec_post_handler(struct audio_decoder *decoder)
+{
+ return 0;
+}
+
+const struct audio_dec_handler tone_dec_handler = {
+ .dec_probe = tone_dec_probe_handler,
+ .dec_output = tone_dec_output_handler,
+ .dec_post = tone_dec_post_handler,
+};
+
+
+static void tone_dec_set_output_channel(struct tone_file_handle *dec)
+{
+ int state;
+ enum audio_channel channel;
+#if TCFG_APP_FM_EMITTER_EN
+ dec->channel = AUDIO_CH_LR;
+ audio_decoder_set_output_channel(&dec->decoder, dec->channel);
+ dec->ch_num = 2;
+#else
+
+ int dev_ch_num = sound_pcm_dev_channel_mapping(1);
+ dec->ch_num = 1;
+ if (dev_ch_num == 2) {
+ channel = AUDIO_CH_LR;
+ dec->ch_num = 2;
+ } else {
+ channel = AUDIO_CH_DIFF;
+ }
+
+ /* if (channel != dec->channel) { */
+ printf("set_channel: %d, dec_channel_num: %d\n", channel, dec->ch_num);
+ audio_decoder_set_output_channel(&dec->decoder, channel);
+ dec->channel = channel;
+ /* } */
+#endif
+}
+
+
+static int file_decoder_syncts_setup(struct tone_file_handle *dec)
+{
+ int err = 0;
+#if TCFG_USER_TWS_ENABLE
+
+ int state = tws_api_get_tws_state();
+ if (!(state & TWS_STA_SIBLING_CONNECTED)) {
+ return 0;
+ }
+
+
+ if (dec->hw_src) {
+ audio_hw_src_close(dec->hw_src);
+ free(dec->hw_src);
+ dec->hw_src = NULL;
+ }
+ struct audio_syncts_params params = {0};
+ params.nch = dec->ch_num;
+ params.pcm_device = sound_pcm_sync_device_select();//PCM_INSIDE_DAC;
+ params.rout_sample_rate = dec->target_sample_rate;
+ params.network = AUDIO_NETWORK_BT2_1;
+ params.rin_sample_rate = dec->decoder.fmt.sample_rate;
+ params.priv = dec;
+ params.factor = TIME_US_FACTOR;
+ params.output = tone_output_after_syncts_filter;
+ printf("======dec->target_sample_rate %d, dec->decoder.fmt.sample_rate %d\n", dec->target_sample_rate, dec->decoder.fmt.sample_rate);
+
+ u8 base = dec->dec_mix ? 3 : 1;
+
+ bt_audio_sync_nettime_select(base);//3 - 优先选择远端主机为网络时钟
+
+ dec->ts_start = 0;
+ dec->ts_handle = file_audio_timestamp_create(0,
+ dec->decoder.fmt.sample_rate,
+ bt_audio_sync_lat_time(),
+ TWS_TONE_CONFIRM_TIME,
+ TIME_US_FACTOR);
+ err = audio_syncts_open(&dec->syncts, ¶ms);
+ if (!err) {
+ dec->mix_ch_event_params[0] = (u32)&dec->mix_ch;
+ dec->mix_ch_event_params[1] = (u32)dec->syncts;
+ audio_mixer_ch_set_event_handler(&dec->mix_ch, (void *)dec->mix_ch_event_params, audio_mix_ch_event_handler);
+ } else {
+ log_e("tone audio syncts open err\n");
+ }
+
+#endif
+ return err;
+}
+
+static void file_decoder_syncts_free(struct tone_file_handle *dec)
+{
+#if TCFG_USER_TWS_ENABLE
+ if (dec->ts_handle) {
+ file_audio_timestamp_close(dec->ts_handle);
+ dec->ts_handle = NULL;
+ }
+
+ if (dec->syncts) {
+ audio_syncts_close(dec->syncts);
+ dec->syncts = NULL;
+ }
+#endif
+}
+
+
+int tone_file_dec_start()
+{
+ int err;
+ struct audio_fmt *fmt;
+ u8 file_name[16];
+
+ if (!file_dec || !file_dec->file) {
+ return -EINVAL;
+ }
+
+ if (file_dec->start) {
+ return 0;
+ }
+
+#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_AND_TONE_MUTEX)
+ audio_hearing_aid_suspend();
+#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
+
+ fget_name(file_dec->file, file_name, 16);
+ printf("file_name:%s\n", file_name);
+ tone_input.coding_type = tone_file_format_match(get_file_ext_name((char *)file_name));
+ if (tone_input.coding_type == AUDIO_CODING_UNKNOW) {
+ log_e("unknow tone file format:%x\n", tone_input.coding_type);
+ return -EINVAL;
+ }
+
+#if 0
+ if ((tone_input.coding_type == AUDIO_CODING_AAC) ||
+ (tone_input.coding_type == AUDIO_CODING_WAV) ||
+ (tone_input.coding_type == AUDIO_CODING_WTGV2) ||
+ (tone_input.coding_type == AUDIO_CODING_MP3)) {
+ file_dec->clk_before_dec = clk_get("sys");
+ /*文件提示音解码需要的时钟配置*/
+#define FILE_TONE_DEC_CLK (96 * 1000000L)
+ u32 file_tone_play_clk = (file_dec->clk_before_dec) > FILE_TONE_DEC_CLK ? file_dec->clk_before_dec : FILE_TONE_DEC_CLK;
+ printf("file tone play clk:%d->%d\n", file_dec->clk_before_dec, file_tone_play_clk);
+ clk_set_sys_lock(file_tone_play_clk, 1);
+ }
+#else
+ audio_codec_clock_set(AUDIO_TONE_MODE, tone_input.coding_type, tone_dec->wait.preemption);
+#endif
+
+ err = audio_decoder_open(&file_dec->decoder, &tone_input, &decode_task);
+ if (err) {
+ return err;
+ }
+
+ audio_decoder_set_handler(&file_dec->decoder, &tone_dec_handler);
+ /*用于处理DEC_EVENT与当前解码的匹配*/
+ file_dec->magic = rand32();
+ audio_decoder_set_event_handler(&file_dec->decoder, tone_dec_event_handler, file_dec->magic);
+
+ err = audio_decoder_get_fmt(&file_dec->decoder, &fmt);
+ if (err) {
+ goto __err1;
+ }
+
+ tone_dec_set_output_channel(file_dec);
+
+ audio_mixer_ch_open(&file_dec->mix_ch, &mixer);
+ audio_mixer_ch_set_resume_handler(&file_dec->mix_ch, (void *)&file_dec->decoder, (void (*)(void *))audio_decoder_resume);
+
+#if TONE_FILE_DEC_MIX
+ int mixer_sample_rate = audio_mixer_get_sample_rate(&mixer);
+
+#if (TCFG_AUDIO_DAC_MIX_ENABLE && !TCFG_AUDIO_DHA_AND_TONE_MUTEX)
+ file_dec->target_sample_rate = TCFG_AUDIO_DAC_MIX_SAMPLE_RATE;
+#else
+ file_dec->target_sample_rate = (file_dec->dec_mix && mixer_sample_rate) ? mixer_sample_rate : sound_pcm_match_sample_rate(fmt->sample_rate);
+#endif /*TCFG_AUDIO_DAC_MIX_ENABLE && !TCFG_AUDIO_DHA_AND_TONE_MUTEX*/
+ audio_mixer_ch_set_sample_rate(&file_dec->mix_ch, file_dec->target_sample_rate);
+ /*audio_mixer_ch_sound_highlight(&file_dec->mix_ch, 4096, 128, file_dec->ch_num);*/
+ printf("file_dec->ch_num %d\n", file_dec->ch_num);
+ printf("fmt->sample_rate %d\n", fmt->sample_rate);
+ printf("file_dec->target_sample_rate %d\n", file_dec->target_sample_rate);
+ /* printf("mixer sr:[%d]\n\n",audio_mixer_get_sample_rate(&mixer)); */
+ /* printf("\n sr:[%d];src sr:[%d] \n\n",fmt->sample_rate,file_dec->target_sample_rate); */
+ if (fmt->sample_rate != file_dec->target_sample_rate) {
+ printf("src->sr:%d, or:%d ", fmt->sample_rate, file_dec->target_sample_rate);
+ file_dec->hw_src = zalloc(sizeof(struct audio_src_handle));
+ if (file_dec->hw_src) {
+ audio_hw_src_open(file_dec->hw_src, file_dec->ch_num, SRC_TYPE_RESAMPLE);
+ audio_hw_src_set_rate(file_dec->hw_src, fmt->sample_rate, file_dec->target_sample_rate);
+ audio_src_set_output_handler(file_dec->hw_src, file_dec, tone_final_output_handler);
+ }
+ }
+
+ if (file_dec->dec_mix && (audio_mixer_get_ch_num(&mixer) > 1)) {
+ goto __dec_start;
+ }
+#else
+ audio_mixer_ch_set_sample_rate(&file_dec->mix_ch, sound_pcm_match_sample_rate(fmt->sample_rate));
+ file_dec->target_sample_rate = fmt->sample_rate;
+#endif
+
+#ifdef TCFG_WTONT_ONCE_VOL
+ extern u8 get_tone_once_vol(void);
+ app_audio_state_switch(APP_AUDIO_STATE_WTONE, get_tone_once_vol());
+#else
+ app_audio_state_switch(APP_AUDIO_STATE_WTONE, get_tone_vol());
+ app_audio_set_volume(APP_AUDIO_STATE_WTONE, get_tone_vol(), 1);
+
+#endif
+
+__dec_start:
+#if TCFG_USER_TWS_ENABLE
+ if (file_dec->tws) {
+ file_decoder_syncts_setup(file_dec);
+ }
+ file_dec->tws_align_step = 0;
+#endif
+
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+#if ANC_TONE_BGM_FADEOUT
+ if (ASCII_StrCmpNoCase(file_name, "anc", 3) == 0) {
+ //printf("ANC tone play,BGM fade_out automatically\n");
+ audio_digital_vol_bg_fade(1);
+ }
+#endif/*ANC_TONE_BGM_FADEOUT*/
+ audio_digital_vol_open(TONE_DVOL, SYS_DEFAULT_TONE_VOL, TONE_DVOL_MAX, TONE_DVOL_FS, -1);
+#endif/*VOL_TYPE_DIGITAL*/
+
+ err = audio_decoder_start(&file_dec->decoder);
+ if (err) {
+ goto __err2;
+ }
+ file_dec->start = 1;
+
+ sound_pcm_dev_try_power_on();
+ return 0;
+
+__err2:
+#if TCFG_APP_FM_EMITTER_EN
+
+#else
+ audio_mixer_ch_close(&file_dec->mix_ch);
+#endif
+__err1:
+ audio_decoder_close(&file_dec->decoder);
+ if (file_dec->hw_src) {
+ audio_hw_src_stop(file_dec->hw_src);
+ audio_hw_src_close(file_dec->hw_src);
+ free(file_dec->hw_src);
+ file_dec->hw_src = NULL;
+ log_info("hw_src close end\n");
+ }
+
+ tone_file_dec_release();
+ return err;
+}
+
+static int tone_wait_res_handler(struct audio_res_wait *wait, int event)
+{
+ int err = 0;
+
+ if (event == AUDIO_RES_GET) {
+ err = tone_file_dec_start();
+ } else if (event == AUDIO_RES_PUT) {
+ tone_file_list_stop(0);
+ }
+ return err;
+}
+
+
+int tone_file_list_stop(u8 no_end)
+{
+ const char *name = NULL;
+ log_info("tone_file_list_stop\n");
+
+ os_mutex_pend(&tone_mutex, 0);
+ if (!file_dec) {
+ log_info("tone_file_list_stop out 0\n");
+ os_mutex_post(&tone_mutex);
+ return 0;
+ }
+
+ tone_audio_res_close(0);
+
+#if 0
+ if (file_dec->clk_before_dec) {
+ printf("tone_play end,clk restore:%d", file_dec->clk_before_dec);
+ clk_set_sys_lock(file_dec->clk_before_dec, 2);
+ file_dec->clk_before_dec = 0;
+ }
+#else
+ audio_codec_clock_del(AUDIO_TONE_MODE);
+#endif
+
+ if (file_dec->list[file_dec->idx]) {
+ name = (const char *)file_dec->list[file_dec->idx];
+ } else if (file_dec->idx) {
+ name = (const char *)file_dec->list[file_dec->idx - 1];
+ }
+ if (file_dec->file) {
+ fclose(file_dec->file);
+ }
+
+ tone_file_dec_release();
+
+ tone_dec_end_handler(AUDIO_DEC_EVENT_END, name);
+
+ log_info("tone_file_list_stop out 1\n");
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+void *sin_tone_open(const struct sin_param *param, int num, u8 channel, u8 repeat);
+int sin_tone_make(void *_maker, void *data, int len);
+int sin_tone_points(void *_maker);
+void sin_tone_close(void *_maker);
+
+/*static const u8 pcm_wav_header[] = {
+ 'R', 'I', 'F', 'F', //rid
+ 0xff, 0xff, 0xff, 0xff, //file length
+ 'W', 'A', 'V', 'E', //wid
+ 'f', 'm', 't', ' ', //fid
+ 0x14, 0x00, 0x00, 0x00, //format size
+ 0x01, 0x00, //format tag
+ 0x01, 0x00, //channel num
+ 0x80, 0x3e, 0x00, 0x00, //sr 16K
+ 0x00, 0x7d, 0x00, 0x00, //avgbyte
+ 0x02, 0x00, //blockalign
+ 0x10, 0x00, //persample
+ 0x02, 0x00,
+ 0x00, 0x00,
+ 'f', 'a', 'c', 't', //f2id
+ 0x40, 0x00, 0x00, 0x00, //flen
+ 0xff, 0xff, 0xff, 0xff, //datalen
+ 'd', 'a', 't', 'a', //"data"
+ 0xff, 0xff, 0xff, 0xff, //sameple size
+};*/
+
+int sine_get_status()
+{
+ return sine_dec ? TONE_START : TONE_STOP;
+}
+
+static int sine_fread(struct audio_decoder *decoder, void *buf, u32 len)
+{
+ int offset;
+ u8 *data = (u8 *)buf;
+
+ offset = sin_tone_make(sine_dec->sin_maker, data, len);
+ sine_dec->sine_offset += offset;
+
+ return offset;
+}
+
+static int sine_fseek(struct audio_decoder *decoder, u32 offset, int seek_mode)
+{
+ sine_dec->sine_offset = 0;
+ return 0;
+}
+
+static int sine_flen(struct audio_decoder *decoder)
+{
+ return sin_tone_points(sine_dec->sin_maker) * 2;
+}
+
+
+
+static const struct audio_dec_input sine_input = {
+ .coding_type = AUDIO_CODING_PCM,
+ .data_type = AUDIO_INPUT_FILE,
+ .ops = {
+ .file = {
+ .fread = sine_fread,
+ .fseek = sine_fseek,
+ .flen = sine_flen,
+ }
+ }
+};
+
+
+static void sine_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
+{
+ log_info("sin_dec_event:%x", argv[0]);
+ switch (argv[0]) {
+ case AUDIO_DEC_EVENT_END:
+ case AUDIO_DEC_EVENT_ERR:
+ log_info("sine player end\n");
+ sine_dec_close();
+ break;
+ default:
+ return;
+ }
+
+}
+
+
+
+
+
+static void sine_param_resample(struct sin_param *dst, const struct sin_param *src, u32 sample_rate)
+{
+ u32 coef = (sample_rate << 10) / DEFAULT_SINE_SAMPLE_RATE;
+
+ dst->freq = (src->freq << 10) / coef;
+ dst->points = ((u64)src->points * coef) >> 10;
+ dst->win = src->win;
+ if (src->win) {
+ dst->decay = ((u64)src->decay << 10) / coef;
+ } else {
+ dst->decay = ((u64)SINE_TOTAL_VOLUME * src->decay / 100) / (u32)dst->points;
+ }
+}
+
+static struct sin_param *get_default_sine_param(const struct sin_param *data, u32 sample_rate, u8 data_num)
+{
+ int i = 0;
+ for (i = 0; i < data_num; i++) {
+ /*sin_dynamic_params[i].idx_increment = ((u64)data[i].idx_increment << 8) / coef;*/
+ sine_param_resample(&sine_dec->sin_dynamic_params[i], data + i, sample_rate);
+ }
+ return sine_dec->sin_dynamic_params;
+}
+
+struct sine_param_head {
+ u16 repeat_time;
+ u8 set_cnt;
+ u8 cur_cnt;
+};
+
+static struct sin_param *get_sine_file_param(const char *name, u32 sample_rate, u8 *data_num)
+{
+ FILE *file;
+ struct sine_param_head head;
+ struct sin_param param;
+ int r_len = 0;
+ int i = 0;
+
+ file = fopen(name, "r");
+ if (!file) {
+ return NULL;
+ }
+
+ r_len = fread(file, (void *)&head, sizeof(head));
+ if (r_len != sizeof(head)) {
+ fclose(file);
+ return NULL;
+ }
+
+ do {
+ r_len = fread(file, (void *)¶m, sizeof(param));
+ if (r_len != sizeof(param)) {
+ break;
+ }
+ /*
+ printf("sine param : \nfreq : %d\npoints : %d\nwin : %d\ndecay : %d\n",
+ param.freq, param.points, param.win, param.decay);
+ */
+ if (!param.points) {
+ break;
+ }
+
+ if (!param.win) {
+ param.decay = param.decay * 100 / 32767;
+ }
+ sine_param_resample(&sine_dec->sin_dynamic_params[i], (const struct sin_param *)¶m, sample_rate);
+ i++;
+ } while (1);
+
+ *data_num = i;
+ fclose(file);
+
+ return sine_dec->sin_dynamic_params;
+}
+
+#if 0
+static const struct sin_param *get_sine_param_data(u8 id, u8 *num)
+{
+ const struct sin_param *param_data;
+
+ switch (id) {
+ case SINE_WTONE_NORAML:
+ param_data = sine_16k_normal;
+ *num = ARRAY_SIZE(sine_16k_normal);
+ break;
+#if CONFIG_USE_DEFAULT_SINE
+ case SINE_WTONE_TWS_CONNECT:
+ param_data = sine_tws_connect_16k;
+ *num = ARRAY_SIZE(sine_tws_connect_16k);
+ break;
+ case SINE_WTONE_TWS_DISCONNECT:
+ param_data = sine_tws_disconnect_16k;
+ *num = ARRAY_SIZE(sine_tws_disconnect_16k);
+ break;
+ case SINE_WTONE_LOW_POWER:
+ param_data = sine_low_power;
+ *num = ARRAY_SIZE(sine_low_power);
+ break;
+ case SINE_WTONE_RING:
+ param_data = sine_ring;
+ *num = ARRAY_SIZE(sine_ring);
+ break;
+ case SINE_WTONE_MAX_VOLUME:
+ param_data = sine_tws_max_volume;
+ *num = ARRAY_SIZE(sine_tws_max_volume);
+ break;
+#ifdef SINE_WTONE_LOW_LATENRY_IN
+ case SINE_WTONE_LOW_LATENRY_IN:
+ param_data = sine_low_latency_in;
+ *num = ARRAY_SIZE(sine_low_latency_in);
+ break;
+ case SINE_WTONE_LOW_LATENRY_OUT:
+ param_data = sine_low_latency_out;
+ *num = ARRAY_SIZE(sine_low_latency_out);
+ break;
+#endif
+#endif
+ default:
+ return NULL;
+ }
+
+ return param_data;
+}
+#endif
+static get_sine_param_t get_sine_param_data = NULL;
+
+__BANK_INIT
+void tone_play_set_sine_param_handler(get_sine_param_t handler)
+{
+ get_sine_param_data = handler;
+}
+
+static struct sin_param *get_sine_param(u32 sine_id, u32 sample_rate, u8 *data_num)
+{
+ const struct sin_param *sin_data_param;
+ u8 num = 0;
+
+ if (IS_DEFAULT_SINE(sine_id)) {
+ if (!get_sine_param_data) {
+ return NULL;
+ }
+ sin_data_param = get_sine_param_data(DEFAULT_SINE_ID(sine_id), &num);
+ if (!sin_data_param) {
+ return NULL;
+ }
+ *data_num = num;
+ return get_default_sine_param(sin_data_param, sample_rate, num);
+ } else {
+ return get_sine_file_param((const char *)sine_id, sample_rate, data_num);
+ }
+
+}
+
+
+static int sine_dec_probe_handler(struct audio_decoder *decoder)
+{
+ u8 num = 0;
+ const struct sin_param *param;
+
+ if (!sine_dec->sin_maker) {
+#ifdef CONFIG_CPU_BR18
+ int channel = 2;
+#else
+
+ int channel = sound_pcm_dev_channel_mapping(0);
+#endif /*CONFIG_CPU_BR18*/
+#if (TCFG_AUDIO_DAC_MIX_ENABLE && !TCFG_AUDIO_DHA_AND_TONE_MUTEX)
+ /*DAC多通道mix功能使能的时候,sin信号直接按照最终输出信号Fs生成*/
+ int sample_rate = TCFG_AUDIO_DAC_MIX_SAMPLE_RATE;
+#else
+ int sample_rate = audio_mixer_get_sample_rate(&mixer);
+#endif /*TCFG_AUDIO_DAC_MIX_ENABLE && !TCFG_AUDIO_DHA_AND_TONE_MUTEX*/
+ if (sample_rate == 0) {
+ sample_rate = 16000;
+ }
+
+ printf("sine: %d, %d\n", sample_rate, channel);
+
+ param = get_sine_param(sine_dec->sine_id, sample_rate, &num);
+ if (!param) {
+ return -ENOENT;
+ }
+ sine_dec->sin_maker = sin_tone_open(param, num, channel, sine_dec->repeat);
+ if (!sine_dec->sin_maker) {
+ return -ENOENT;
+ }
+ audio_mixer_ch_set_sample_rate(&sine_dec->mix_ch, sound_pcm_match_sample_rate(sample_rate));
+
+ }
+
+ return 0;
+}
+
+static int sine_dec_output_handler(struct audio_decoder *decoder, s16 *data, int len, void *priv)
+{
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ if (sine_dec->remain == 0) {
+ audio_digital_vol_run(TONE_DVOL, data, len);
+ }
+#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
+ int wlen = audio_mixer_ch_write(&sine_dec->mix_ch, data, len);
+ if (wlen != len) {
+ sine_dec->remain = 1;
+ } else {
+ sine_dec->remain = 0;
+ }
+ return wlen;
+}
+
+static int sine_dec_post_handler(struct audio_decoder *decoder)
+{
+ return 0;
+}
+
+const struct audio_dec_handler sine_dec_handler = {
+ .dec_probe = sine_dec_probe_handler,
+ .dec_output = sine_dec_output_handler,
+ .dec_post = sine_dec_post_handler,
+};
+
+static void sine_dec_release()
+{
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_close(TONE_DVOL);
+#endif/*VOL_TYPE_DIGITAL*/
+ free(sine_dec);
+ sine_dec = NULL;
+}
+
+int sine_dec_start()
+{
+ int err;
+ int decode_task_state;
+ struct audio_fmt *fmt;
+
+ if (!sine_dec) {
+ return -EINVAL;
+ }
+ if (sine_dec->start) {
+ return 0;
+ }
+
+#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_AND_TONE_MUTEX)
+ audio_hearing_aid_suspend();
+#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
+
+ printf("sine_dec_start: id = %x, repeat = %d\n", sine_dec->sine_id, sine_dec->repeat);
+
+ err = audio_decoder_open(&sine_dec->decoder, &sine_input, &decode_task);
+ if (err) {
+ return err;
+ }
+ err = audio_decoder_get_fmt(&sine_dec->decoder, &fmt);
+
+ decode_task_state = audio_decoder_task_wait_state(&decode_task);
+ /*
+ *以下情况需要独立设置提示音音量
+ *(1)抢断播放
+ *(2)当前只有提示音一个解码任务
+ */
+ if ((tone_dec->wait.preemption == 1) || (decode_task_state == 1)) {
+ app_audio_state_switch(APP_AUDIO_STATE_WTONE, SYS_DEFAULT_SIN_VOL);
+ }
+#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
+ audio_digital_vol_open(TONE_DVOL, SYS_DEFAULT_SIN_VOL, TONE_DVOL_MAX, TONE_DVOL_FS, -1);
+#endif/*VOL_TYPE_DIGITAL*/
+
+#if 0
+ /*
+ *播放一个不打断的提示音,默认提高提高时钟
+ *等提示音播放结束,再恢复原先的时钟
+ */
+ if (tone_dec->wait.preemption == 0) {
+ u32 cur_clk = clk_get("sys");
+ u32 need_clk = cur_clk + 12000000L;
+ printf("sin_tone_clk_inc:%d->%d", cur_clk, need_clk);
+ sine_dec->clk_before = clk_get("sys");
+ clk_set_sys_lock(need_clk, 1);
+ }
+#else
+ audio_codec_clock_set(AUDIO_TONE_MODE, AUDIO_CODING_PCM, tone_dec->wait.preemption);
+#endif
+
+ audio_decoder_set_handler(&sine_dec->decoder, &sine_dec_handler);
+ audio_decoder_set_event_handler(&sine_dec->decoder, sine_dec_event_handler, 0);
+
+ audio_mixer_ch_open(&sine_dec->mix_ch, &mixer);
+ audio_mixer_ch_set_resume_handler(&sine_dec->mix_ch, (void *)&sine_dec->decoder, (void (*)(void *))audio_decoder_resume);
+
+ err = audio_decoder_start(&sine_dec->decoder);
+ if (err) {
+ goto __err2;
+ }
+ sine_dec->start = 1;
+
+ return 0;
+
+__err2:
+ audio_mixer_ch_close(&sine_dec->mix_ch);
+__err1:
+ audio_decoder_close(&sine_dec->decoder);
+ sine_dec_release();
+ return err;
+
+}
+
+static int sine_wait_res_handler(struct audio_res_wait *wait, int event)
+{
+ int err = 0;
+
+ if (event == AUDIO_RES_GET) {
+ err = sine_dec_start();
+ } else if (event == AUDIO_RES_PUT) {
+
+ }
+
+ return err;
+}
+
+int sine_dec_open(u32 sine_id, u8 repeat, u8 preemption)
+{
+ int err = 0;
+
+ if (sine_dec) {
+ sine_dec_close();
+ if (sine_dec) {
+ return -EINVAL;
+ }
+ }
+
+ sine_dec = zalloc(sizeof(*sine_dec));
+ if (!sine_dec) {
+ log_error("sine_dec zalloc failed");
+ return -ENOMEM;
+ }
+
+ sine_dec->repeat = repeat;
+ sine_dec->sine_id = sine_id;
+
+ tone_dec->wait.priority = 3;
+ tone_dec->wait.preemption = preemption;
+ tone_dec->wait.handler = sine_wait_res_handler;
+ printf("sine_dec_open,preemption = %d", preemption);
+ audio_decoder_task_add_wait(&decode_task, &tone_dec->wait);
+
+ if (sine_dec && preemption == 0 && sine_dec->start == 0) {
+ err = sine_dec_start();
+ }
+
+ return err;
+}
+
+int sine_dec_close(void)
+{
+ if (!sine_dec) {
+ return 0;
+ }
+
+ puts("sine_dec_close\n");
+
+ audio_decoder_close(&sine_dec->decoder);
+ audio_mixer_ch_close(&sine_dec->mix_ch);
+ if (sine_dec->sin_maker) {
+ sin_tone_close(sine_dec->sin_maker);
+ }
+
+ if (app_audio_get_state() == APP_AUDIO_STATE_WTONE) {
+ app_audio_state_exit(APP_AUDIO_STATE_WTONE);
+ }
+
+#if 0
+ if ((tone_dec->wait.preemption == 0)/* && (audio_aec_status() == 1)*/) {
+ //y_printf("clk_before2:%d",sine_dec->clk_before);
+ if (sine_dec->clk_before) {
+ clk_set_sys_lock(sine_dec->clk_before, 1);
+ sine_dec->clk_before = 0;
+ }
+ }
+#else
+ audio_codec_clock_del(AUDIO_TONE_MODE);
+#endif
+ sine_dec_release();
+
+ tone_dec_end_handler(AUDIO_DEC_EVENT_END, NULL);
+
+#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_AND_TONE_MUTEX)
+ audio_hearing_aid_resume();
+#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
+ return 0;
+}
+
+
+int audio_decoder_find_coding_type(struct audio_decoder_task *task, u32 coding_type);
+int tone_list_play_start(const char **list, u8 preemption, u8 tws)
+{
+ int err;
+ u8 file_name[16];
+ char *format = NULL;
+ FILE *file = NULL;
+ int index = 0;
+
+ if (IS_REPEAT_BEGIN(list[0])) {
+ index = 1;
+ }
+
+ if (IS_DEFAULT_SINE(list[index])) {
+ format = "sin";
+ } else {
+ file = fopen(list[index], "r");
+ if (!file) {
+ return -EINVAL;
+ }
+ fget_name(file, file_name, 16);
+ format = get_file_ext_name((char *)file_name);
+ }
+
+ if (format) {
+ printf("tone_play format:%s\n", format);
+ }
+
+ if (ASCII_StrCmpNoCase(format, "sin", 3) == 0) {
+ if (file) {
+ fclose(file);
+ }
+ /*正弦波参数文件*/
+ return sine_dec_open((u32)list[index], index == 1, preemption);
+ } else {
+ file_dec = zalloc(sizeof(*file_dec));
+
+ file_dec->list = list;
+ file_dec->idx = index;
+ file_dec->file = file;
+ file_dec->tws = tws;
+ if (index == 1) {
+ file_dec->loop = TONE_REPEAT_COUNT(list[0]);
+ }
+
+#if 0
+ if (!preemption) {
+ file_dec->dec_mix = 1;
+ tone_dec->wait.protect = 1;
+ }
+#endif
+ tone_dec->wait.priority = 3;
+ tone_dec->wait.preemption = preemption;
+#if TONE_FILE_DEC_MIX
+ file_dec->dec_mix = 0;
+ if (tone_dec->wait.preemption == 0) {
+ u8 tone_mix_fmt_tab_num = ARRAY_SIZE(tone_mix_fmt_tab);
+ //printf("tone_mix_fmt_tab size:%d\n",tone_mix_fmt_tab_num);;
+ /*检查提示音格式是否支持叠加播放*/
+ for (u8 i = 0; i < tone_mix_fmt_tab_num; i++) {
+ //printf("tone %d format:%s\n",i,tone_mix_fmt_tab[i]);
+ if (ASCII_StrCmpNoCase(format, tone_mix_fmt_tab[i], 3) == 0) {
+ file_dec->dec_mix = 1; //叠加播放
+ /*tone_dec->wait.protect = 1;*/ //提示音播放不用来做低优先级的背景音
+ printf("tone_mix_fmt_tab match\n");
+ break;
+ }
+ }
+ /*不支持叠加播放,默认使用抢断播放*/
+ if (file_dec->dec_mix == 0) {
+ tone_dec->wait.preemption = 1;
+ }
+ }
+#endif/*TONE_FILE_DEC_MIX*/
+ tone_dec->wait.handler = tone_wait_res_handler;
+ err = audio_decoder_task_add_wait(&decode_task, &tone_dec->wait);
+#if 0
+ if (!err && file_dec->start == 0) {
+ /*decoder中有该解码器,则强制使用打断方式,防止overlay冲突*/
+ if (audio_decoder_find_coding_type(&decode_task, tone_file_format_match(format))) {
+ tone_dec->wait.preemption = 1;
+ err = audio_decoder_task_add_wait(&decode_task, &tone_dec->wait);
+ } else {
+ err = tone_file_dec_start();
+ }
+ }
+#endif
+ if (err) {
+ if (tone_dec) {
+ audio_decoder_task_del_wait(&decode_task, &tone_dec->wait);
+ tone_file_dec_release();
+ }
+ } else {
+ if (file_dec->dec_mix && !file_dec->start) {
+ err = tone_file_dec_start();
+ }
+ }
+ return err;
+ }
+}
+
+static int __tone_file_list_play(const char **list, u8 preemption, u8 tws)
+{
+ int i = 0;
+ int err = 0;
+
+ if (!list) {
+ return -EINVAL;
+ }
+
+
+ if (tone_dec == NULL) {
+ tone_dec = zalloc(sizeof(*tone_dec));
+ if (tone_dec == NULL) {
+ log_error("tone dec zalloc failed");
+ return -ENOMEM;
+ }
+ }
+
+ while (list[i] != NULL) {
+ i++;
+ }
+ char **p = malloc(4 * (i + 1));
+ memcpy(p, list, 4 * (i + 1));
+
+ tone_dec->list[tone_dec->w_index++] = (const char **)p;
+ if (tone_dec->w_index >= TONE_LIST_MAX_NUM) {
+ tone_dec->w_index = 0;
+ }
+
+
+ tone_dec->list_cnt++;
+ tone_dec->preemption = preemption;
+ if (tone_dec->list_cnt == 1) {
+ err = tone_list_play_start(tone_dec->list[tone_dec->r_index], tone_dec->preemption, tws);
+ if (err == -EINVAL) {
+ free(p);
+ free(tone_dec);
+ tone_dec = NULL;
+ }
+ return err;
+ } else {
+ puts("tone_file_add_tail\n");
+ }
+
+ return 0;
+}
+
+int tone_file_list_play(const char **list, u8 preemption)
+{
+ return __tone_file_list_play(list, preemption, 1);
+}
+
+int tone_file_list_play_with_callback(const char **list, u8 preemption, void (*user_evt_handler)(void *priv), void *priv)
+{
+ int i = 0;
+ int err = 0;
+
+ putchar('A');
+ if (!list) {
+ return -EINVAL;
+ }
+
+ putchar('B');
+
+ if (tone_dec == NULL) {
+ tone_dec = zalloc(sizeof(*tone_dec));
+ if (tone_dec == NULL) {
+ log_error("tone dec zalloc failed");
+ return -ENOMEM;
+ }
+ }
+ putchar('C');
+
+ while (list[i] != NULL) {
+ i++;
+ }
+ char **p = malloc(4 * (i + 1));
+ memcpy(p, list, 4 * (i + 1));
+
+ tone_dec->list[tone_dec->w_index++] = (const char **)p;
+ if (tone_dec->w_index >= TONE_LIST_MAX_NUM) {
+ tone_dec->w_index = 0;
+ }
+
+ putchar('D');
+ if (user_evt_handler) {
+ tone_set_user_event_handler(tone_dec, user_evt_handler, priv);
+ }
+
+ tone_dec->list_cnt++;
+ tone_dec->preemption = preemption;
+ if (tone_dec->list_cnt == 1) {
+ err = tone_list_play_start(tone_dec->list[tone_dec->r_index], tone_dec->preemption, 1);
+ if (err == -EINVAL) {
+ free(p);
+ free(tone_dec);
+ tone_dec = NULL;
+ }
+ return err;
+ } else {
+ puts("tone_file_add_tail\n");
+ }
+
+ return 0;
+}
+
+
+static int tone_play2(int parm)
+{
+ int *ptr = (int *)parm;
+ return tone_play((const char *)ptr[0], (u8)ptr[1]);
+}
+static void tone_stop(u8 force);
+extern void usr_mute_set(u8 flag);
+int tone_play(const char *name, u8 preemption)
+{
+#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_FITTING_ENABLE)
+ /*辅听验配过程不允许播放提示音*/
+ extern u8 get_hearing_aid_fitting_state(void);
+ if (get_hearing_aid_fitting_state()) {
+ printf("hearing aid fitting : %d\n !!!", get_hearing_aid_fitting_state());
+ return 0;
+ }
+#endif /*TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_FITTING_ENABLE*/
+ usr_mute_set(0);
+ g_printf("tone_play:%s,preemption:%d", IS_DEFAULT_SINE(name) ? "sine" : name, preemption);
+
+ if (strcmp(os_current_task(), "app_core") != 0) {
+ g_printf("Tone play not in right task.");
+
+ int *ptr = malloc(2 * sizeof(int));
+ ptr[0] = (int)name;
+ ptr[1] = (int)preemption;
+ OS_SEM *sem = malloc(sizeof(OS_SEM) + 4);
+ int *err = (int *)(sem + 1);
+ ASSERT(sem);
+ int msg[8];
+ msg[0] = (int)tone_play2;
+ msg[1] = 1 | BIT(8) | BIT(9);
+ msg[2] = (int)ptr;
+ msg[3] = (int)err;
+ msg[4] = (int)sem;
+
+ os_sem_create(sem, 0);
+ int ret_err;
+ while (1) {
+ int ret_err = os_taskq_post_type("app_core", Q_CALLBACK, 5, msg);
+ if (ret_err == OS_ERR_NONE) {
+ os_sem_pend(sem, 0);
+ ret_err = *err;
+ break;
+ }
+
+ if (ret_err != OS_Q_FULL) {
+ break;
+ }
+ os_time_dly(2);
+ }
+ free(sem);
+ free(ptr);
+ g_printf("switch to app_core paly tone ok\n");
+ return ret_err;
+ }
+
+ if (tone_dec) {
+ log_info("tone dec busy now,tone stop first");
+ tone_stop(0);
+ }
+ single_file[0] = (char *)name;
+ single_file[1] = NULL;
+ return tone_file_list_play((const char **)single_file, preemption);
+}
+
+int tone_play_no_tws(const char *name, u8 preemption)
+{
+ g_printf("tone_play no tws:%s,preemption:%d", IS_DEFAULT_SINE(name) ? "sine" : name, preemption);
+
+ if (tone_dec) {
+ log_info("tone dec busy now,tone stop first");
+ tone_stop(0);
+ }
+ single_file[0] = (char *)name;
+ single_file[1] = NULL;
+ return __tone_file_list_play((const char **)single_file, preemption, 0);
+}
+
+
+static int tone_play_with_callback2(int parm)
+{
+ int *ptr = (int *)parm;
+ int ret = tone_play_with_callback((const char *)ptr[0], (u8)ptr[1], (void *)ptr[2], (void *)ptr[3]);
+ return ret;
+}
+
+int tone_play_with_callback(const char *name, u8 preemption, void (*user_evt_handler)(void *priv), void *priv)
+{
+ g_printf("tone_play:%s,preemption:%d", IS_DEFAULT_SINE(name) ? "sine" : name, preemption);
+ if (strcmp(os_current_task(), "app_core") != 0) {
+ g_printf("Tone play not in right task.");
+
+ int *ptr = malloc(4 * sizeof(int));
+ ptr[0] = (int)name;
+ ptr[1] = (int)preemption;
+ ptr[2] = (int)user_evt_handler;
+ ptr[3] = (int)priv;
+ OS_SEM *sem = malloc(sizeof(OS_SEM) + 4);
+ int *err = (int *)(sem + 1);
+ ASSERT(sem);
+ int msg[8];
+ msg[0] = (int)tone_play_with_callback2;
+ msg[1] = 1 | BIT(8) | BIT(9);
+ msg[2] = (int)ptr;
+ msg[3] = (int)err;
+ msg[4] = (int)sem;
+
+ os_sem_create(sem, 0);
+ int ret_err;
+ while (1) {
+ ret_err = os_taskq_post_type("app_core", Q_CALLBACK, 5, msg);
+ if (ret_err == OS_ERR_NONE) {
+ os_sem_pend(sem, 0);
+ ret_err = *err;
+ break;
+ }
+
+ if (ret_err != OS_Q_FULL) {
+ break;
+ }
+ os_time_dly(2);
+ }
+ free(sem);
+ free(ptr);
+ g_printf("switch to app_core paly tone ok\n");
+ return ret_err;
+ }
+ if (tone_dec) {
+ tone_event_clear();
+ log_info("tone dec busy now,tone stop first");
+ tone_stop(0);
+ }
+
+ single_file[0] = (char *)name;
+ single_file[1] = NULL;
+ return tone_file_list_play_with_callback((const char **)single_file, preemption, user_evt_handler, priv);
+}
+
+int tone_play_add(const char *name, u8 preemption)
+{
+ g_printf("tone_play_add:%s,preemption:%d", IS_DEFAULT_SINE(name) ? "sine" : name, preemption);
+
+ if (tone_dec) {
+ log_info("tone dec busy now,tone file add next");
+ //tone_stop(0);
+ }
+ single_file[0] = (char *)name;
+ single_file[1] = NULL;
+ return tone_file_list_play((const char **)single_file, preemption);
+}
+
+const char *get_playing_tone_name(u8 index)
+{
+ if (tone_dec) {
+ const char **list = tone_dec->list[tone_dec->r_index + index];
+ if (list) {
+ return list[0];
+ }
+ }
+ return 0;
+}
+
+
+static void tone_stop(u8 force)
+{
+ if (tone_dec == NULL) {
+ return;
+ }
+
+ if (force) {
+ tone_file_list_clean(1);
+ }
+ tone_file_list_stop(0);
+ sine_dec_close();
+ tone_dec_release();
+
+}
+
+static u8 audio_tone_idle_query()
+{
+ if (tone_dec) {
+ return 0;
+ }
+ return 1;
+}
+REGISTER_LP_TARGET(audio_tone_lp_target) = {
+ .name = "audio_tone",
+ .is_idle = audio_tone_idle_query,
+};
+
+
+
+#if 0 //(USE_DMA_TONE)
+static volatile u8 tone_play_falg = 0; //用于播放提示音后,作相应的动作
+void set_tone_play_falg(u8 flag)
+{
+ tone_play_falg = flag;
+}
+
+u8 get_tone_play_flag(void)
+{
+ return tone_play_falg;
+}
+
+int tone_play_index_for_dma(u8 index, u8 flag)
+{
+ set_tone_play_falg(flag);
+ return tone_play_index(index, 1);
+
+}
+
+static u32 dma_tone_arg_before = 0; //记录下按键的arg值
+void set_dma_tone_arg_before(u32 arg)
+{
+ dma_tone_arg_before = arg;
+}
+
+u32 get_dma_tone_arg_before(void)
+{
+ return dma_tone_arg_before;
+}
+
+void clear_dma_tone_arg_before(void)
+{
+ dma_tone_arg_before = 0;
+}
+#endif
+
+
+
+static volatile s32 tone_play_end_cmd = TONE_PLAY_END_CB_CMD_NONE; //用于播放提示音后,作相应的动作
+void tone_play_end_cb_cmd_set(int cmd)
+{
+ tone_play_end_cmd = cmd;
+}
+
+s32 tone_play_end_cb_cmd_get(void)
+{
+ return tone_play_end_cmd;
+}
+
+int tone_play_index_with_cb_cmd(u8 index, int flag)
+{
+ tone_play_end_cb_cmd_set(flag);
+ return tone_play_index(index, 1);
+
+}
+
+static u32 tone_arg_storage = 0; //记录下按键的arg值
+void tone_arg_store(u32 arg)
+{
+ tone_arg_storage = arg;
+}
+
+u32 tone_arg_restore(void)
+{
+ return tone_arg_storage;
+}
+
+void tone_arg_storage_clean(void)
+{
+ tone_arg_storage = 0;
+}
+
+
+int tone_play_init(void)
+{
+ os_mutex_create(&tone_mutex);
+ return 0;
+}
+
+
+int tone_play_stop(void)
+{
+ log_info("tone_play_stop");
+ tone_stop(1);
+ return 0;
+}
+
+/*
+ *@brief:提示音比较,确认目标提示音和正在播放的提示音是否一致
+ *@return: 0 匹配
+ * 非0 不匹配或者当前没有提示音播放
+ *@note:通过提示音名字比较
+ */
+int tone_name_compare(const char *name)
+{
+ if (tone_dec) {
+ if (file_dec) {
+ printf("file_name:%s,cmp_name:%s\n", file_dec->list[file_dec->idx], name);
+ return strcmp(name, file_dec->list[file_dec->idx]);
+ } else if (sine_dec) {
+ printf("sin_id:0x%x,cmp_id:0x%x\n", sine_dec->sine_id, (u32)name);
+ if (sine_dec->sine_id == (u32)name) {
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+ }
+ printf("tone_dec idle now\n");
+ return -1;
+}
diff --git a/cpu/br28/tone_player_api.h b/cpu/br28/tone_player_api.h
new file mode 100644
index 0000000..be85ea9
--- /dev/null
+++ b/cpu/br28/tone_player_api.h
@@ -0,0 +1,66 @@
+#ifndef _TONE_PLAYER_API_H
+#define _TONE_PLAYER_API_H
+
+#include "audio_config.h"
+#include "sine_make.h"
+
+#define TONE_STOP 0
+#define TONE_START 1
+
+#define CONFIG_USE_DEFAULT_SINE 1
+#define DEVICE_EVENT_FROM_TONE (('T' << 24) | ('N' << 16) | ('E' << 8) | '\0')
+
+#define TONE_DEFAULT_VOL SYS_MAX_VOL
+
+
+
+#define TONE_REPEAT_BEGIN(a) (char *)((0x1 << 30) | (a & 0xffff))
+#define TONE_REPEAT_END() (char *)(0x2 << 30)
+
+#define IS_REPEAT_BEGIN(a) ((((u32)a >> 30) & 0x3) == 0x1 ? 1 : 0)
+#define IS_REPEAT_END(a) ((((u32)a >> 30) & 0x3) == 0x2 ? 1 : 0)
+#define TONE_REPEAT_COUNT(a) (((u32)a) & 0xffff)
+
+#define DEFAULT_SINE_TONE(a) (char *)(((u32)0x3 << 30) | (a))
+#define IS_DEFAULT_SINE(a) ((((u32)a >> 30) & 0x3) == 0x3 ? 1 : 0)
+#define DEFAULT_SINE_ID(a) ((u32)a & 0xffff)
+
+typedef const struct sin_param *(*get_sine_param_t)(u8 id, u8 *num);
+
+void tone_play_set_sine_param_handler(get_sine_param_t handler);
+
+
+int tone_play(const char *name, u8 preemption) ;
+
+int tone_play_no_tws(const char *name, u8 preemption);
+
+int tone_play_with_callback(const char *name, u8 preemption, void (*user_evt_handler)(void *priv), void *priv);
+
+int tone_file_list_play(const char **list, u8 preemption);
+
+int tone_play_stop(void);
+
+int tone_sin_play(int time_ms, u8 wait);
+
+int tone_get_status();
+
+int tone_file_list_stop(u8 no_end);
+
+/*
+ *@brief:提示音比较,确认目标提示音和正在播放的提示音是否一致
+ *@return: 0 匹配
+ * 非0 不匹配或者当前没有提示音播放
+ *@note:通过提示音名字比较
+ */
+int tone_name_compare(const char *name);
+
+
+enum {
+ TONE_PLAY_END_CB_CMD_NONE = -1,
+ TONE_FLAG_KEY_START,
+ TONE_FLAG_KEY_START_UP_CLK,
+};
+
+
+
+#endif
diff --git a/cpu/br28/tools/AC701N_配置工具入口(Config Tools Entry).jlxproj b/cpu/br28/tools/AC701N_配置工具入口(Config Tools Entry).jlxproj
new file mode 100644
index 0000000..3579ad4
--- /dev/null
+++ b/cpu/br28/tools/AC701N_配置工具入口(Config Tools Entry).jlxproj
@@ -0,0 +1,120 @@
+local lang_en = {
+ ["打开EQ工具"]="Open EQ Tool",
+ ["打开音效配置工具(新EQ工具)"]="Open Audio Effect Config Tool (New EQ)",
+ ["打开下载目录"]="Open Download Directory",
+ ["显示原理图"]="Show Schematic Design",
+ ["编译前配置工具"]="Pre-compiling Config Tool",
+ ["编辑FW文件"]="FW Editing Tools",
+ ["应用信息:AC701N-SDK"]="Application: AC701N-SDK",
+ ["内置触摸调试工具"]="Builtin Touching Debug Tool",
+ ["调音工具"]="Audio Config Tool",
+ ["检查依赖的软件包是否更新"]="Check Update",
+ ["配置工具"]="Config Tool",
+ ["生成配置\n(生成 cfg_tool.bin)"]="Generate Config\n(generate cfg_tool.bin)",
+ ["配置音效\n(生成 eq_cfg_hw.bin)"]="Generate Audio Effect\n(generate eq_cfg_hw.bin)",
+ ["编辑FW/UFW中蓝牙名,替换资源"]="Edit FW/UFW (BT Name, Resources)",
+ ["打开"]="Open",
+ ["路径"]="Path",
+};
+
+cfg:setTranslate("en", lang_en);
+
+local rootDir = cfg.rootDir;
+
+local pkgman = rootDir .. "/pkgman.exe";
+local req_pkgs = {"eq", "efftool", "sdktool", "luaconfig", "3rd", "sdkaudiocvt", "ancdesigner"};
+local check_prog = {pkgman};
+
+local missing_pkgs = {};
+for k, v in pairs(req_pkgs) do
+ if cfg:utilsGetPkg(v) == nil then
+ table.insert(missing_pkgs, v)
+ end
+end
+
+for k, v in pairs(missing_pkgs) do table.insert(check_prog, v) end
+
+if #missing_pkgs ~= 0 then
+ if (cfg:runProg(check_prog) ~= 0) then
+ cfg:msgBox("warn", "软件包不是最新,可能会出现问题");
+ end
+end
+
+
+local sdktool = rootDir .. '/' .. cfg:utilsGetPkg("sdktool").run;
+local luaconfig = rootDir .. '/' .. cfg:utilsGetPkg("luaconfig").run;
+local projdir = cfg.dir .. '/download/';
+local efftool = rootDir .. '/' .. cfg:utilsGetPkg("efftool").run;
+local ancdesigner = rootDir .. '/' .. cfg:utilsGetPkg("ancdesigner").run;
+local title = "AC701N-SDK";
+
+local default_bin_path = cfg.dir .. '/cfg_tool.bin';
+local default_tone_path = cfg.dir .. '/tone.cfg';
+
+local cfgtool_entry_view = cfg:stEntry(":/uires/icon_settle.png",
+ "配置工具", "生成配置\n(生成 cfg_tool.bin)", nil,
+ cfg:stButton2("打开", "", "main", function ()
+ cfg:runProgNoWait({luaconfig,
+ '-u', 'earphone-1.2.0', '-e',
+ '-p', cfg.dir,
+ '-r', rootDir,
+ '-b', default_bin_path,
+ '-t', default_tone_path});
+ end));
+
+local efftool_entry_view = cfg:stEntry(":/uires/icon_eq.png",
+ "调音工具", "配置音效\n(生成 eq_cfg_hw.bin)", nil,
+ cfg:stButton2("打开", "", "main", function ()
+ cfg:runProgNoWait({efftool, '--type', 'eq', '--async-serial'});
+ end));
+
+local ancdesigner_entry_view = cfg:stEntry(":/uires/icon_eq.png",
+ "ANC Designer", "ANC 调试工具\n(生成 anc_gains.bin、anc_coeff.bin 等)", nil,
+ cfg:stButton2("打开", "", "main", function ()
+ cfg:runProgNoWait({ancdesigner});
+ end));
+
+local sdktool_entry_view = cfg:stEntry(":/uires/icon_settle.png",
+ "编辑FW文件", "编辑FW/UFW中蓝牙名,替换资源", nil,
+ cfg:stButton2("打开", "", "main", function ()
+ cfg:runProgNoWait({sdktool});
+ end));
+
+local touch_debug_entry_view = cfg:stEntry(":/uires/icon_settle.png",
+ "内置触摸调试工具", "", nil,
+ cfg:stButton2("打开", "", "main", function ()
+ cfg:runProgNoWait({efftool, '--type', 'touch_debug'});
+ end));
+
+local check_allupdate_btn = cfg:stButton2("检查依赖的软件包是否更新", "", "secondary", function ()
+ local check_prog = {pkgman};
+ for k, v in pairs(req_pkgs) do table.insert(check_prog, v) end
+ if (cfg:runProg(check_prog) ~= 0) then
+ if(cfg.lang == "zh") then
+ cfg:msgBox("warn", "软件包不是最新,可能会出现问题");
+ else
+ cfg:msgBox("warn", "software Packages are not up-to-date and may have problems");
+ end
+ else
+ if(cfg.lang == "zh") then
+ cfg:msgBox("info", "已经是最新");
+ else
+ cfg:msgBox("info", "software Packages are up-to-date");
+ end
+ end
+end);
+
+local layout = cfg:vBox{ cfg:stGroup(title, cfg:stHScroll ( cfg:vBox {
+ cfgtool_entry_view,
+ sdktool_entry_view,
+ efftool_entry_view,
+ ancdesigner_entry_view,
+ touch_debug_entry_view,
+ check_allupdate_btn,
+}))};
+
+cfg:addKeyInfo("jlxproj.width", "600");
+cfg:addKeyInfo("jlxproj.height", "700");
+cfg:addKeyInfo("jlxproj.title", title);
+
+cfg:setLayout(layout)
diff --git a/cpu/br28/tools/aac.bin b/cpu/br28/tools/aac.bin
new file mode 100644
index 0000000..e69de29
diff --git a/cpu/br28/tools/aec.bin b/cpu/br28/tools/aec.bin
new file mode 100644
index 0000000..e69de29
diff --git a/cpu/br28/tools/anc_coeff.bin b/cpu/br28/tools/anc_coeff.bin
new file mode 100644
index 0000000..2bfa426
Binary files /dev/null and b/cpu/br28/tools/anc_coeff.bin differ
diff --git a/cpu/br28/tools/anc_gains.bin b/cpu/br28/tools/anc_gains.bin
new file mode 100644
index 0000000..ddda86f
Binary files /dev/null and b/cpu/br28/tools/anc_gains.bin differ
diff --git a/cpu/br28/tools/aptx.bin b/cpu/br28/tools/aptx.bin
new file mode 100644
index 0000000..e69de29
diff --git a/cpu/br28/tools/br28loader.bin b/cpu/br28/tools/br28loader.bin
new file mode 100644
index 0000000..d8f4807
Binary files /dev/null and b/cpu/br28/tools/br28loader.bin differ
diff --git a/cpu/br28/tools/br28loader.uart b/cpu/br28/tools/br28loader.uart
new file mode 100644
index 0000000..3bb176d
Binary files /dev/null and b/cpu/br28/tools/br28loader.uart differ
diff --git a/cpu/br28/tools/cfg_tool.bin b/cpu/br28/tools/cfg_tool.bin
new file mode 100644
index 0000000..f99f7ec
Binary files /dev/null and b/cpu/br28/tools/cfg_tool.bin differ
diff --git a/cpu/br28/tools/cfg_tool_state_complete.lua b/cpu/br28/tools/cfg_tool_state_complete.lua
new file mode 100644
index 0000000..442d9e0
--- /dev/null
+++ b/cpu/br28/tools/cfg_tool_state_complete.lua
@@ -0,0 +1 @@
+{["bt_osc_ws_init"]=400,["osc_change_mode"]=1,["1"]="CBCT\095UPDATE",["19"]="jl\095earphone\09519",["20"]="jl\095earphone\09520",["蓝牙名字开关20"]=0,["经典蓝牙MAC地址:"]={255,255,255,255,255,255},["17"]="jl\095earphone\09517",["蓝牙名字开关18"]=0,["经典蓝牙发射功率:"]=10,["Pin Code:"]="",["低功耗蓝牙MAC地址:"]={255,255,255,255,255,255},["低功耗蓝牙发射功率:"]=10,["12"]="jl\095earphone\09512",["没有连接自动关机时间配置: "]=3,["蓝牙名字开关16"]=0,["15"]="jl\095earphone\09515",["对耳配对码(2字节)"]=65535,["lrc_ws_inc"]=400,["lrc_ws_init"]=400,["bt_osc_ws_inc"]=400,["蓝牙名字开关14"]=0,["蓝牙名字开关15"]=0,["16"]="jl\095earphone\09516",["18"]="jl\095earphone\09518",["14"]="jl\095earphone\09514",["低功耗蓝牙名字"]="CBCT\095UPDATE",["10"]="jl\095earphone\09510",["13"]="jl\095earphone\09513",["蓝牙名字开关9"]=0,["蓝牙名字开关19"]=0,["蓝牙名字开关11"]=0,["蓝牙名字开关17"]=0,["蓝牙名字开关13"]=0,["蓝牙名字开关12"]=0,["蓝牙名字开关3"]=0,["6"]="jl\095earphone\0956",["7"]="jl\095earphone\0957",["蓝牙名字开关1"]=1,["蓝牙名字开关10"]=0,["蓝牙名字开关5"]=0,["蓝牙名字开关6"]=0,["蓝牙名字开关7"]=0,["8"]="jl\095earphone\0958",["蓝牙名字开关8"]=0,["11"]="jl\095earphone\09511",["2"]="jl\095earphone\0952",["4"]="jl\095earphone\0954",["9"]="jl\095earphone\0959",["3"]="jl\095earphone\0953",["蓝牙名字开关4"]=0,["蓝牙名字开关2"]=0,["5"]="jl\095earphone\0955",["MIC模式选择"]=0,["提示音"]={{"0","E\058\047JieLi\095Chip\095Date\047JL\095AC701X\047project\047\232\167\129\229\174\157\047JL701n\095earphone\095release\095v1\0466\0461\095250904\047sdk\047cpu\047br28\047tools\047extra\095tones\0470\046wts",0},{"power\095on","E\058\047JieLi\095Chip\095Date\047JL\095AC701X\047project\047\232\167\129\229\174\157\047JL701n\095earphone\095release\095v1\0466\0461\095250904\047sdk\047cpu\047br28\047tools\047extra\095tones\047power\095on\046wts",17}},["comvol期望音量-1 23"]=0.000000,["偏置电阻选择:"]=4,["cvp.3mic.dnsKEY1 按键抬按消息"]=255,["cvp.3mic.dnsKEY1 按键双击消息"]=255,["cvpEQ"]=0,["cvpMIC_Gain"]=8,["cvpDT_FADE_IN"]=1.300000,["通话参数类型选择"]=0,["cvpNS"]=0,["cvpDAC_Gain"]=8,["cvpAEC"]=0,["cvpNDT_FADE_IN"]=1.300000,["cvpAGC"]=0,["cvpNDT_FADE_OUT"]=1.300000,["MICLDO电压选择:"]=5,["cvpNLP"]=0,["cvp.2mic.dnsAEC_Process_MinFrequency"]=0,["cvp.2mic.dnsNLP_Process_MaxFrequency"]=8000,["cvp.2mic.dnsDNS_GainFloor"]=0.100000,["cvp.2mic.dnsENC_Process_MaxFreq"]=8000,["cvp.2mic.dnsDNS_NoiseLevel"]=-75.000000,["cvp.2mic.dnsMIC_Distance"]=15,["cvp.2mic.dnsECHO_PRESENT_THR"]=-70.000000,["cvp.2mic.dnsNLP_Process_MinFrequency"]=0,["cvp.2mic.dnsDT_MIN_GAIN"]=0.000000,["cvp.2mic.dnsENC_Minsuppress"]=0.090000,["cvp.2mic.dnsAF_Length"]=128,["cvp.2mic.dnsMic RMS diff"]=0.000000,["cvp.2mic.dnsAEC_Mode"]=30,["cvp.2mic.tfAEC"]=0,["cvp.2mic.tfNLP"]=1,["cvp.2mic.tfNS"]=1,["cvp.2mic.tfAGC"]=1,["cvp.2mic.dnsGlobalMinsuppress"]=0.040000,["cvp.2mic.dnsOverDrive"]=1.000000,["cvp.2mic.dnsDNS_OverDrive"]=1.000000,["cvp.2mic.tfENC"]=1,["cvp.2mic.tfEQ"]=1,["cvp.2mic.tfMIC1_Gain"]=10,["cvp.2mic.dnsENC_Process_MinFreq"]=0,["cvp.2mic.dnsTarget_Signal_Degradation"]=1.000000,["cvp.2mic.dnsENC_Aggressfactor"]=4.000000,["cvp.2mic.tfMIC_Gain"]=8,["cvp.2mic.tfDAC_Gain"]=8,["cvp.2mic.dnsAEC_Process_MaxFrequency"]=8000,["cvp.2mic.dnsDT_SPEECH_THR"]=-40.000000,["cvp.2mic.dnsMic_Distance:float"]=0.015000,["cvp.2mic.dnsSIR_MaxFreq"]=3000,["cvp.2mic.tfDT_FADE_IN"]=1.300000,["cvp.2mic.tfNDT_FADE_OUT"]=1.300000,["cvp.2mic.tfDT_FADE_OUT"]=1.300000,["cvp.2mic.tfDT_MIN_GAIN"]=0.000000,["cvp.2mic.tfECHO_PRESENT_THR"]=-70.000000,["cvp.2mic.tfDT_MAX_GAIN"]=12.000000,["cvp.2mic.tfAEC_Process_MaxFrequency"]=8000,["cvp.2mic.tfAEC_Process_MinFrequency"]=0,["cvp.2mic.tfNLP_Process_MinFrequency"]=0,["cvp.2mic.tfOverDrive"]=1.000000,["cvp.2mic.tfAggressFactor"]=1.250000,["cvp.2mic.tfAF_Length"]=128,["cvp.2mic.tfNLP_Process_MaxFrequency"]=8000,["cvp.2mic.tfNDT_MAX_GAIN"]=8.000000,["cvp.2mic.tfNDT_MIN_GAIN"]=4.000000,["cvp.2mic.tfNDT_SPEECH_THR"]=-50.000000,["cvp.2mic.tfDT_SPEECH_THR"]=-40.000000,["cvp.2mic.tfNDT_FADE_IN"]=1.300000,["cvp.dnsMIC_Gain"]=8,["cvpNLP_MIN_SUPPRESS"]=4.000000,["cvpAEC_REFENGTHR"]=-70.000000,["cvpAEC_Mode"]=0,["cvpNDT_SPEECH_THR"]=-50.000000,["cvp.dnsDAC_Gain"]=8,["cvp.dnsDT_FADE_IN"]=1.300000,["cvp.dnsDT_FADE_OUT"]=1.300000,["cvpNDT_MIN_GAIN"]=4.000000,["cvpDT_MAX_GAIN"]=12.000000,["cvp.dnsNDT_SPEECH_THR"]=-50.000000,["cvpANS_SUPPRESS"]=0.090000,["cvpAEC_DT_AGGRESS"]=1.000000,["cvpECHO_PRESENT_THR"]=-70.000000,["cvp.dnsDT_MAX_GAIN"]=12.000000,["cvp.dnsDT_MIN_GAIN"]=0.000000,["cvp.dnsAEC"]=0,["cvp.dnsNDT_FADE_IN"]=1.300000,["cvpDT_SPEECH_THR"]=-40.000000,["cvpNLP_AGGRESS_FACTOR"]=-3.000000,["cvp.dnsNS"]=1,["cvp.dnsAGC"]=1,["cvpDT_MIN_GAIN"]=0.000000,["cvp.dnsNDT_MIN_GAIN"]=4.000000,["cvpNDT_MAX_GAIN"]=8.000000,["cvp.dnsNDT_FADE_OUT"]=1.300000,["cvp.dnsNDT_MAX_GAIN"]=8.000000,["cvpDT_FADE_OUT"]=1.300000,["cvpANS_AGGRESS"]=1.250000,["cvp.dnsNLP"]=1,["cvp.dnsEQ"]=1,["cvp.dnsNLP_AGGRESS_FACTOR"]=-3.000000,["cvp.dnsNLP_MIN_SUPPRESS"]=4.000000,["cvp.2micNS"]=1,["cvp.2micEQ"]=1,["cvp.dnsDT_SPEECH_THR"]=-40.000000,["cvp.dnsDNS_OverDrive"]=1.000000,["cvp.dnsAEC_Mode"]=22,["cvp.2micNLP"]=1,["cvp.2micAEC"]=0,["cvp.dnsAEC_REFENGTHR"]=-70.000000,["cvp.2micMIC_Gain"]=8,["cvp.2micAGC"]=1,["cvp.dnsDNS_GainFloor"]=0.100000,["cvp.2micENC"]=1,["cvp.2micDAC_Gain"]=8,["cvp.dnsECHO_PRESENT_THR"]=-70.000000,["cvp.dnsAEC_DT_AGGRESS"]=1.000000,["cvp.2micDT_FADE_IN"]=1.300000,["cvp.2micNDT_FADE_IN"]=1.300000,["cvp.2micDT_FADE_OUT"]=1.300000,["cvp.2micNDT_MAX_GAIN"]=8.000000,["cvp.2micDT_MAX_GAIN"]=12.000000,["cvp.2micOverDrive"]=1.000000,["cvp.2micNDT_MIN_GAIN"]=4.000000,["cvp.2micAEC_Process_MaxFrequency"]=8000,["cvp.2micMinSuppress"]=0.040000,["cvp.2micENC_Process_MaxFreq"]=8000,["cvp.2micMIC_Distance"]=15,["cvp.2micMic RMS diff"]=0.000000,["cvp.2micTarget_Signal_Degradation"]=1.000000,["cvp.2micENC_Aggressfactor"]=4.000000,["cvp.2micENC_Minsuppress"]=0.090000,["cvp.2micGlobalMinsuppress"]=0.040000,["cvp.2micNLP_Process_MinFrequency"]=0,["cvp.2micAEC_Mode"]=30,["comvol使能-1-22"]=0,["cvp.2micDT_MIN_GAIN"]=0.000000,["cvp.2micNDT_SPEECH_THR"]=-50.000000,["cvp.2micAEC_Process_MinFrequency"]=0,["cvp.2micDT_SPEECH_THR"]=-40.000000,["cvp.2micECHO_PRESENT_THR"]=-70.000000,["cvp.2micNLP_Process_MaxFrequency"]=8000,["cvp.2micAggressFactor"]=1.250000,["cvp.2micAF_Length"]=128,["cvp.2micMicNoiseLevel"]=-75.000000,["cvp.2micSIR_MaxFreq"]=3000,["cvp.2micNDT_FADE_OUT"]=1.300000,["cvp.2micENC_Process_MinFreq"]=0,["cvp.2micMic_Distance:float"]=0.015000,["cvp.2mic.dnsMIC_Gain"]=8,["cvp.2mic.dnsNDT_FADE_IN"]=1.300000,["cvp.2mic.dnsNLP"]=1,["cvp.2mic.dnsNS"]=1,["cvp.2mic.dnsDAC_Gain"]=8,["cvp.2mic.dnsAEC"]=0,["cvp.2mic.dnsDT_FADE_OUT"]=1.300000,["cvp.2mic.dnsNDT_MIN_GAIN"]=4.000000,["cvp.2mic.dnsNDT_SPEECH_THR"]=-50.000000,["cvp.2mic.dnsDT_MAX_GAIN"]=12.000000,["cvp.2mic.dnsEQ"]=1,["cvp.2mic.dnsNDT_MAX_GAIN"]=8.000000,["comvol期望音量-1 22"]=0.000000,["cvp.2mic.dnsDT_FADE_IN"]=1.300000,["cvp.2mic.dnsNDT_FADE_OUT"]=1.300000,["dvol使能-1-22"]=0,["cvp.2mic.dnsENC"]=1,["cvp.2mic.dnsAGC"]=1,["comvol期望音量-2 93"]=0.000000,["comvol使能-2-93"]=0,["comvol期望音量-2 97"]=0.000000,["comvol期望音量-2 98"]=0.000000,["comvol使能-2-98"]=0,["comvol期望音量-2 94"]=0.000000,["comvol使能-2-95"]=0,["comvol期望音量-2 99"]=0.000000,["comvol使能-2-100"]=0,["comvol期望音量-2 96"]=0.000000,["comvol期望音量-out-x-zero2"]=0,["comvol期望音量-out-avol2-1"]=0,["comvol使能-2-96"]=0,["comvol期望音量-2 95"]=0.000000,["comvol期望音量-2 100"]=0.000000,["comvol期望音量-out-x-2-2"]=0,["comvol期望音量-out-avol2-2"]=0,["comvol期望音量-out-x-2-3"]=0,["comvol期望音量-out-avol2-3"]=0,["comvol期望音量-out-avol2-4"]=0,["comvol使能-2-97"]=0,["comvol期望音量-out-x-2-5"]=0,["comvol总是使能-2-"]=1,["comvol期望音量-out-x-2-4"]=0,["comvol期望音量-out-avol2-5"]=0,["comvol使能-2-94"]=0,["comvol期望音量-out-x-2-6"]=0,["comvol期望音量-out-avol2-6"]=0,["comvol期望音量-out-x-2-7"]=0,["comvol期望音量-out-avol-zero2"]=0,["comvol使能-2-99"]=0,["comvol期望音量-out-x-2-1"]=0,["comvol期望音量-out-avol2-19"]=0,["comvol期望音量-out-x-2-20"]=0,["comvol期望音量-out-x-2-12"]=0,["comvol期望音量-out-avol2-8"]=0,["comvol期望音量-out-x-2-19"]=0,["comvol期望音量-out-avol2-7"]=0,["comvol期望音量-out-x-2-15"]=0,["comvol期望音量-out-x-2-18"]=0,["comvol期望音量-out-avol2-21"]=0,["comvol期望音量-out-x-2-23"]=0,["comvol期望音量-out-x-2-10"]=0,["comvol期望音量-out-avol2-18"]=0,["comvol期望音量-out-x-2-13"]=0,["comvol期望音量-out-x-2-22"]=0,["comvol期望音量-out-x-2-8"]=0,["comvol期望音量-out-avol2-10"]=0,["comvol期望音量-out-avol2-12"]=0,["comvol期望音量-out-avol2-13"]=0,["comvol期望音量-out-x-2-11"]=0,["comvol期望音量-out-avol2-15"]=0,["comvol期望音量-out-x-2-16"]=0,["comvol期望音量-out-x-2-17"]=0,["comvol期望音量-out-x-2-21"]=0,["comvol期望音量-out-avol2-16"]=0,["comvol期望音量-out-avol2-9"]=0,["comvol期望音量-out-x-2-14"]=0,["comvol期望音量-out-x-2-9"]=0,["comvol期望音量-out-avol2-20"]=0,["comvol期望音量-out-avol2-17"]=0,["comvol期望音量-out-avol2-22"]=0,["comvol期望音量-out-avol2-11"]=0,["comvol期望音量-out-avol2-14"]=0,["comvol使能-2-28"]=0,["comvol使能-2-29"]=0,["comvol期望音量-2 30"]=0.000000,["comvol使能-2-24"]=0,["comvol使能-2-32"]=0,["comvol使能-2-33"]=0,["comvol使能-2-34"]=0,["comvol使能-2-35"]=0,["comvol期望音量-2 36"]=0.000000,["comvol使能-2-36"]=0,["comvol使能-2-37"]=0,["comvol期望音量-2 38"]=0.000000,["comvol使能-2-38"]=0,["comvol期望音量-2 37"]=0.000000,["comvol期望音量-2 25"]=0.000000,["comvol期望音量-2 31"]=0.000000,["comvol期望音量-2 29"]=0.000000,["comvol期望音量-2 32"]=0.000000,["comvol期望音量-2 34"]=0.000000,["comvol期望音量-2 33"]=0.000000,["comvol期望音量-2 35"]=0.000000,["comvol使能-2-30"]=0,["comvol使能-2-26"]=0,["comvol使能-2-25"]=0,["comvol使能-2-23"]=0,["comvol期望音量-2 26"]=0.000000,["comvol使能-2-31"]=0,["comvol使能-2-27"]=0,["comvol期望音量-2 24"]=0.000000,["comvol期望音量-2 27"]=0.000000,["comvol期望音量-2 28"]=0.000000,["comvol期望音量-2 23"]=0.000000,["comvol期望音量-2 41"]=0.000000,["comvol使能-2-44"]=0,["comvol期望音量-2 52"]=0.000000,["comvol使能-2-49"]=0,["comvol使能-2-52"]=0,["comvol使能-2-39"]=0,["comvol期望音量-2 40"]=0.000000,["comvol期望音量-2 46"]=0.000000,["comvol使能-2-40"]=0,["comvol期望音量-2 48"]=0.000000,["comvol使能-2-48"]=0,["comvol期望音量-2 51"]=0.000000,["comvol期望音量-2 53"]=0.000000,["comvol使能-2-53"]=0,["comvol期望音量-2 42"]=0.000000,["comvol使能-2-47"]=0,["comvol期望音量-2 54"]=0.000000,["comvol使能-2-54"]=0,["comvol期望音量-2 43"]=0.000000,["comvol期望音量-2 47"]=0.000000,["comvol使能-2-41"]=0,["comvol使能-2-46"]=0,["comvol使能-2-45"]=0,["comvol期望音量-2 39"]=0.000000,["comvol使能-2-50"]=0,["comvol期望音量-2 45"]=0.000000,["comvol期望音量-2 44"]=0.000000,["comvol期望音量-2 50"]=0.000000,["comvol使能-2-43"]=0,["comvol使能-2-42"]=0,["comvol期望音量-2 49"]=0.000000,["comvol使能-2-51"]=0,["comvol期望音量-2 70"]=0.000000,["comvol期望音量-2 66"]=0.000000,["comvol使能-2-70"]=0,["comvol期望音量-2 56"]=0.000000,["comvol使能-2-57"]=0,["comvol期望音量-2 61"]=0.000000,["comvol期望音量-2 58"]=0.000000,["comvol使能-2-62"]=0,["comvol期望音量-2 60"]=0.000000,["comvol使能-2-60"]=0,["comvol使能-2-55"]=0,["comvol使能-2-61"]=0,["comvol期望音量-2 63"]=0.000000,["comvol使能-2-63"]=0,["comvol使能-2-58"]=0,["comvol期望音量-2 62"]=0.000000,["comvol使能-2-65"]=0,["comvol期望音量-2 65"]=0.000000,["comvol使能-2-64"]=0,["comvol期望音量-2 67"]=0.000000,["comvol使能-2-59"]=0,["comvol使能-2-66"]=0,["comvol使能-2-56"]=0,["comvol期望音量-2 55"]=0.000000,["comvol使能-2-67"]=0,["comvol期望音量-2 68"]=0.000000,["comvol使能-2-68"]=0,["comvol期望音量-2 69"]=0.000000,["comvol期望音量-2 57"]=0.000000,["comvol期望音量-2 59"]=0.000000,["comvol期望音量-2 64"]=0.000000,["comvol使能-2-69"]=0,["comvol期望音量-2 78"]=0.000000,["comvol期望音量-2 73"]=0.000000,["comvol使能-2-78"]=0,["comvol期望音量-2 77"]=0.000000,["comvol使能-2-79"]=0,["comvol期望音量-2 81"]=0.000000,["comvol使能-2-74"]=0,["comvol期望音量-2 82"]=0.000000,["comvol使能-2-85"]=0,["comvol使能-2-71"]=0,["comvol期望音量-2 74"]=0.000000,["comvol期望音量-2 72"]=0.000000,["comvol使能-2-72"]=0,["comvol使能-2-82"]=0,["comvol期望音量-2 86"]=0.000000,["comvol使能-2-76"]=0,["comvol使能-2-86"]=0,["comvol使能-2-75"]=0,["comvol期望音量-2 71"]=0.000000,["comvol使能-2-73"]=0,["comvol期望音量-2 76"]=0.000000,["comvol期望音量-2 75"]=0.000000,["comvol期望音量-2 80"]=0.000000,["comvol使能-2-80"]=0,["comvol使能-2-83"]=0,["comvol期望音量-2 84"]=0.000000,["comvol期望音量-2 79"]=0.000000,["comvol期望音量-2 83"]=0.000000,["comvol使能-2-84"]=0,["comvol期望音量-2 85"]=0.000000,["comvol使能-2-77"]=0,["comvol使能-2-81"]=0,["comvol使能-2-89"]=0,["comvol期望音量-2 89"]=0.000000,["comvol使能-2-87"]=0,["comvol使能-2-88"]=0,["comvol期望音量-2 91"]=0.000000,["comvol使能-2-91"]=0,["comvol期望音量-2 88"]=0.000000,["comvol期望音量-2 90"]=0.000000,["comvol期望音量-2 87"]=0.000000,["comvol期望音量-2 92"]=0.000000,["comvol使能-2-92"]=0,["comvol使能-2-90"]=0,["cvp.3mic.dnsNLP"]=1,["cvp.2mic.tf.dnsDNS_NoiseLevel"]=-75.000000,["cvp.2mic.tf.dnsDT_MIN_GAIN"]=0.000000,["cvp.3mic.dnsNS"]=1,["cvp.2mic.tf.dnsDT_FADE_IN"]=1.300000,["cvp.2mic.tf.dnsENC_Suppress_Pre"]=0.600000,["cvp.2mic.tf.dnsDNS_OverDrive"]=1.000000,["cvp.2mic.tf.dnsDT_MAX_GAIN"]=12.000000,["cvp.2mic.tf.dnsDT_SPEECH_THR"]=-40.000000,["cvp.2mic.tf.dnsENC_Suppress_Post"]=0.150000,["cvp.2mic.tf.dnsNLP_Process_MaxFrequency"]=8000,["cvp.2mic.tf.dnsDT_FADE_OUT"]=1.300000,["cvp.2mic.tf.dnsNDT_FADE_OUT"]=1.300000,["cvp.2mic.tf.dnsENC_Minsuppress"]=0.090000,["cvp.2mic.tf.dnsAEC_Process_MaxFrequency"]=8000,["cvp.2mic.tf.dnsDNS_GainFloor"]=0.100000,["cvp.2mic.tf.dnsENC_Disconverge_Thr"]=-6.000000,["cvp.2mic.tf.dnsNDT_SPEECH_THR"]=-50.000000,["cvp.2mic.tf.dnsNDT_MAX_GAIN"]=8.000000,["cvp.2mic.tf.dnsNDT_FADE_IN"]=1.300000,["cvp.2mic.tf.dnsOverDrive"]=1.000000,["cvp.2mic.tf.dnsAEC_Mode"]=30,["cvp.2mic.tf.dnsAF_Length"]=128,["cvp.2mic.tf.dnsNLP_Process_MinFrequency"]=0,["cvp.3mic.dnsAEC"]=0,["cvp.2mic.tf.dnsNDT_MIN_GAIN"]=4.000000,["cvp.2mic.tf.dnsECHO_PRESENT_THR"]=-70.000000,["cvp.2mic.tf.dnsAEC_Process_MinFrequency"]=0,["cvp.2mic.tf.dnsAEC"]=0,["cvp.2mic.tf.dnsENC"]=1,["cvp.2mic.tf.dnsMIC_Gain"]=8,["cvp.2mic.tfENC_Disconverge_Thr"]=-6.000000,["cvp.2mic.tf.dnsMIC1_Gain"]=10,["cvp.2mic.tf.dnsDAC_Gain"]=8,["cvp.2mic.tfMinSuppress"]=0.040000,["cvp.2mic.tfMicNoiseLevel"]=-75.000000,["cvp.2mic.tf.dnsAGC"]=1,["cvp.2mic.tf.dnsNS"]=1,["cvp.2mic.tf.dnsEQ"]=1,["cvp.2mic.tfENC_Suppress_Pre"]=0.600000,["cvp.2mic.tfENC_Suppress_Post"]=0.150000,["cvp.2mic.tfENC_Minsuppress"]=0.090000,["cvp.2mic.tfAEC_Mode"]=30,["cvp.2mic.tf.dnsNLP"]=1,["cvp.3mic.dnsDT_MAX_GAIN"]=12.000000,["cvp.3mic.dnsDT_MIN_GAIN"]=0.000000,["cvp.3mic.dnsSIR_MaxFreq"]=3000,["cvp.3mic.dnsMic RMS diff"]=0.000000,["cvp.3mic.dnsTRI_CompenDb"]=0.000000,["cvp.3mic.dnsNDT_SPEECH_THR"]=-50.000000,["cvp.3mic.dnsDT_SPEECH_THR"]=-40.000000,["cvp.3mic.dnsDNS_NoiseLevel"]=-75.000000,["cvp.3mic.dnsADDITION_MAG_DB_LEVEL"]=0,["cvp.3mic.dnsCLIP_MAG_LEVEL"]=-3,["cvp.3mic.dnsAEC_Process_MaxFrequency"]=8000,["cvp.3mic.dnsECHO_PRESENT_THR"]=-70.000000,["cvp.3mic.dnsENC_Process_MaxFreq"]=8000,["cvp.3mic.dnsMIC_Distance"]=15,["cvp.3mic.dnsTarget_Signal_Degradation"]=1.000000,["cvp.3mic.dnsOverDrive"]=1.000000,["cvp.3mic.dnsMic_Distance:float"]=0.015000,["cvp.3mic.dnsENC_Aggressfactor"]=1.000000,["cvp.3mic.dnsFLOOR_MAG_LEVEL "]=-70,["cvp.3mic.dnsMAX_MAG_DB_LEVEL"]=-3,["cvp.3mic.dnsAF_Length"]=128,["cvp.3mic.dnsENC_Process_MinFreq"]=0,["cvp.3mic.dnsENC_Minsuppress"]=0.090000,["cvp.3mic.dnsNLP_Process_MinFrequency"]=0,["cvp.3mic.dnsMIN_MAG_DB_LEVEL"]=-50,["cvp.3mic.dnsDNS_GainFloor"]=0.100000,["cvp.3mic.dnsTri_SnrThreshold0"]=0.500000,["cvp.3mic.dnsNLP_Process_MaxFrequency"]=8000,["cvp.3mic.dnsAEC_Process_MinFrequency"]=0,["cvp.3mic.dnsDNS_OverDrive"]=1.000000,["cvp.3mic.dnsTri_SnrThreshold1"]=0.500000,["cvp.3mic.dnsAGC_TYPE"]=0,["cvp.3mic.dnsFB_MIC_Gain"]=1,["cvp.3mic.dnsMIC_Gain"]=8,["cvp.3mic.dnsDAC_Gain"]=8,["cvp.3mic.dnsEQ"]=1,["cvp.3mic.dnsTALK REF MIC"]=2,["cvp.3mic.dnsTALK FB MIC"]=4,["cvp.3mic.dnsNDT_FADE_IN"]=1.300000,["cvp.3mic.dnsNDT_FADE_OUT"]=1.300000,["cvp.3mic.dnsWNC"]=0,["cvp.3mic.dnsTALK MIC"]=1,["cvp.3mic.dnsDT_FADE_IN"]=1.300000,["cvp.3mic.dnsDT_FADE_OUT"]=1.300000,["cvp.3mic.dnsNDT_MAX_GAIN"]=8.000000,["cvp.3mic.dnsNDT_MIN_GAIN"]=4.000000,["cvp.3mic.dnsAGC"]=1,["cvp.3mic.dnsENC"]=1,["comvol期望音量-1 4"]=0.000000,["comvol期望音量-1 1"]=0.000000,["comvol使能-1-6"]=0,["comvol期望音量-1 8"]=0.000000,["comvol使能-1-8"]=0,["comvol期望音量-1 9"]=0.000000,["comvol期望音量-1 7"]=0.000000,["cvp.3mic.dnsAEC_Mode"]=30,["comvol期望音量-1 2"]=0.000000,["comvol使能-1-9"]=0,["comvol期望音量-1 10"]=0.000000,["comvol使能-1-10"]=0,["cvp.3mic.dnsWN_GAIN_OFFSET"]=0,["comvol期望音量-1 5"]=0.000000,["comvol使能-1-5"]=0,["comvol期望音量-1 11"]=0.000000,["comvol使能-1-11"]=0,["comvol期望音量-1 12"]=0.000000,["comvol使能-1-12"]=0,["cvp.3mic.dnsWNC_MSC_TH"]=0.600000,["comvol使能-1-4"]=0,["cvp.3mic.dnsMS_TH"]=80.000000,["comvol期望音量-1 6"]=0.000000,["comvol使能-1-2"]=0,["comvol期望音量-1 3"]=0.000000,["comvol使能-1-7"]=0,["固定模拟音量"]=0,["comvol使能-1-1"]=0,["comvol使能-1-3"]=0,["comvol使能-1-17"]=0,["comvol使能-1-18"]=0,["comvol使能-1-19"]=0,["comvol使能-1-20"]=0,["comvol期望音量-1 13"]=0.000000,["comvol期望音量-1 16"]=0.000000,["comvol期望音量-1 19"]=0.000000,["comvol使能-1-21"]=0,["comvol期望音量-1 14"]=0.000000,["comvol使能-1-13"]=0,["comvol使能-1-14"]=0,["comvol使能-1-15"]=0,["comvol期望音量-1 18"]=0.000000,["comvol期望音量-1 20"]=0.000000,["comvol期望音量-1 15"]=0.000000,["comvol期望音量-1 21"]=0.000000,["comvol期望音量-1 17"]=0.000000,["comvol使能-1-16"]=0,["comvol使能-1-33"]=0,["comvol期望音量-1 42"]=0.000000,["comvol期望音量-1 38"]=0.000000,["comvol期望音量-1 29"]=0.000000,["comvol期望音量-1 28"]=0.000000,["comvol期望音量-1 32"]=0.000000,["comvol使能-1-29"]=0,["comvol使能-1-27"]=0,["comvol使能-1-35"]=0,["comvol期望音量-1 37"]=0.000000,["comvol期望音量-1 35"]=0.000000,["comvol使能-1-36"]=0,["comvol使能-1-37"]=0,["comvol使能-1-38"]=0,["comvol期望音量-1 27"]=0.000000,["comvol期望音量-1 34"]=0.000000,["comvol期望音量-1 31"]=0.000000,["comvol使能-1-41"]=0,["comvol使能-1-28"]=0,["comvol使能-1-26"]=0,["comvol使能-1-32"]=0,["comvol期望音量-1 36"]=0.000000,["comvol期望音量-1 33"]=0.000000,["comvol使能-1-31"]=0,["comvol期望音量-1 39"]=0.000000,["comvol使能-1-39"]=0,["comvol使能-1-40"]=0,["comvol期望音量-1 40"]=0.000000,["comvol期望音量-1 41"]=0.000000,["comvol期望音量-1 30"]=0.000000,["comvol使能-1-30"]=0,["comvol使能-1-34"]=0,["comvol期望音量-1 45"]=0.000000,["comvol期望音量-1 43"]=0.000000,["comvol期望音量-1 55"]=0.000000,["comvol期望音量-1 44"]=0.000000,["comvol使能-1-50"]=0,["comvol使能-1-52"]=0,["comvol使能-1-53"]=0,["comvol使能-1-47"]=0,["comvol期望音量-1 56"]=0.000000,["comvol使能-1-49"]=0,["comvol期望音量-1 49"]=0.000000,["comvol期望音量-1 52"]=0.000000,["comvol期望音量-1 48"]=0.000000,["comvol期望音量-1 50"]=0.000000,["comvol期望音量-1 57"]=0.000000,["comvol使能-1-55"]=0,["comvol使能-1-45"]=0,["comvol期望音量-1 54"]=0.000000,["comvol使能-1-57"]=0,["comvol使能-1-42"]=0,["comvol期望音量-1 46"]=0.000000,["comvol使能-1-46"]=0,["comvol期望音量-1 51"]=0.000000,["comvol使能-1-43"]=0,["comvol使能-1-44"]=0,["comvol使能-1-48"]=0,["comvol使能-1-51"]=0,["comvol期望音量-1 53"]=0.000000,["comvol期望音量-1 47"]=0.000000,["comvol使能-1-54"]=0,["comvol使能-1-56"]=0,["comvol期望音量-1 58"]=0.000000,["comvol使能-1-58"]=0,["comvol使能-1-64"]=0,["comvol期望音量-1 67"]=0.000000,["comvol使能-1-68"]=0,["comvol使能-1-70"]=0,["comvol期望音量-1 71"]=0.000000,["comvol期望音量-1 68"]=0.000000,["comvol使能-1-69"]=0,["comvol使能-1-61"]=0,["comvol期望音量-1 72"]=0.000000,["comvol使能-1-72"]=0,["comvol使能-1-67"]=0,["comvol使能-1-65"]=0,["comvol期望音量-1 66"]=0.000000,["comvol使能-1-60"]=0,["comvol使能-1-63"]=0,["comvol期望音量-1 69"]=0.000000,["comvol期望音量-1 73"]=0.000000,["comvol使能-1-73"]=0,["comvol使能-1-71"]=0,["comvol期望音量-1 74"]=0.000000,["comvol期望音量-1 70"]=0.000000,["comvol期望音量-1 60"]=0.000000,["comvol使能-1-59"]=0,["comvol期望音量-1 61"]=0.000000,["comvol使能-1-62"]=0,["comvol期望音量-1 64"]=0.000000,["comvol期望音量-1 65"]=0.000000,["comvol使能-1-66"]=0,["comvol期望音量-1 59"]=0.000000,["comvol期望音量-1 62"]=0.000000,["comvol期望音量-1 63"]=0.000000,["comvol期望音量-1 25"]=0.000000,["comvol使能-1-25"]=0,["comvol期望音量-1 26"]=0.000000,["comvol期望音量-1 24"]=0.000000,["comvol使能-1-23"]=0,["comvol使能-1-24"]=0,["comvol期望音量-out-avol1-10"]=0,["comvol期望音量-out-x-1-22"]=0,["comvol期望音量-out-avol1-12"]=0,["comvol期望音量-out-x-1-10"]=0,["comvol期望音量-out-avol1-16"]=0,["comvol期望音量-out-x-1-18"]=0,["comvol期望音量-out-avol1-22"]=0,["comvol期望音量-out-avol1-18"]=0,["comvol期望音量-out-x-1-12"]=0,["comvol期望音量-out-x-1-23"]=0,["comvol期望音量-out-avol1-23"]=0,["comvol期望音量-out-x-1-19"]=0,["comvol期望音量-out-x-1-11"]=0,["comvol期望音量-out-avol1-19"]=0,["comvol期望音量-out-avol1-8"]=0,["comvol期望音量-out-x-1-13"]=0,["comvol期望音量-out-avol1-11"]=0,["comvol期望音量-out-avol1-17"]=0,["comvol期望音量-out-x-1-17"]=0,["comvol期望音量-out-x-1-20"]=0,["comvol期望音量-out-avol1-21"]=0,["comvol期望音量-out-avol1-9"]=0,["comvol期望音量-out-avol1-13"]=0,["comvol期望音量-out-x-1-14"]=0,["comvol期望音量-out-x-1-16"]=0,["comvol期望音量-out-x-1-8"]=0,["comvol期望音量-out-avol1-14"]=0,["comvol期望音量-out-x-1-9"]=0,["comvol期望音量-out-x-1-15"]=0,["comvol期望音量-out-avol1-20"]=0,["comvol期望音量-out-x-1-21"]=0,["comvol期望音量-out-avol1-15"]=0,["comvol期望音量-1 89"]=0.000000,["comvol使能-1-89"]=0,["comvol使能-1-83"]=0,["comvol使能-1-74"]=0,["comvol期望音量-1 80"]=0.000000,["comvol使能-1-80"]=0,["comvol期望音量-1 82"]=0.000000,["comvol期望音量-1 90"]=0.000000,["comvol使能-1-75"]=0,["comvol期望音量-1 78"]=0.000000,["comvol期望音量-1 79"]=0.000000,["comvol使能-1-79"]=0,["comvol使能-1-81"]=0,["comvol期望音量-1 88"]=0.000000,["comvol期望音量-1 75"]=0.000000,["comvol期望音量-1 76"]=0.000000,["comvol使能-1-84"]=0,["comvol期望音量-1 84"]=0.000000,["comvol期望音量-1 81"]=0.000000,["comvol使能-1-85"]=0,["comvol期望音量-1 86"]=0.000000,["comvol期望音量-1 85"]=0.000000,["comvol使能-1-78"]=0,["comvol期望音量-1 87"]=0.000000,["comvol使能-1-77"]=0,["comvol使能-1-87"]=0,["comvol使能-1-76"]=0,["comvol期望音量-1 77"]=0.000000,["comvol使能-1-88"]=0,["comvol使能-1-82"]=0,["comvol期望音量-1 83"]=0.000000,["comvol使能-1-86"]=0,["comvol使能-1-94"]=0,["comvol期望音量-1 95"]=0.000000,["comvol期望音量-1 91"]=0.000000,["comvol期望音量-1 97"]=0.000000,["comvol使能-1-97"]=0,["comvol期望音量-1 100"]=0.000000,["comvol使能-1-95"]=0,["comvol使能-1-93"]=0,["comvol使能-1-98"]=0,["comvol使能-1-91"]=0,["comvol期望音量-1 92"]=0.000000,["comvol使能-1-100"]=0,["comvol总是使能-1-"]=1,["comvol期望音量-1 99"]=0.000000,["comvol期望音量-out-avol1-3"]=0,["comvol使能-1-96"]=0,["comvol期望音量-out-avol-zero1"]=0,["comvol期望音量-out-avol1-1"]=0,["comvol使能-1-90"]=0,["comvol期望音量-out-x-zero1"]=0,["comvol期望音量-out-x-1-2"]=0,["comvol期望音量-out-x-1-3"]=0,["comvol期望音量-1 93"]=0.000000,["comvol使能-1-99"]=0,["comvol期望音量-out-x-1-1"]=0,["comvol期望音量-1 94"]=0.000000,["comvol期望音量-out-x-1-4"]=0,["comvol期望音量-1 96"]=0.000000,["comvol期望音量-out-avol1-4"]=0,["comvol使能-1-92"]=0,["comvol期望音量-1 98"]=0.000000,["comvol期望音量-out-avol1-2"]=0,["comvol期望音量-out-avol1-7"]=0,["comvol期望音量-out-avol1-5"]=0,["comvol期望音量-out-x-1-5"]=0,["comvol期望音量-out-x-1-6"]=0,["comvol期望音量-out-avol1-6"]=0,["comvol期望音量-out-x-1-7"]=0,["comvol期望音量-out-avol1-45"]=0,["comvol期望音量-out-avol1-57"]=0,["comvol期望音量-out-x-1-55"]=0,["comvol期望音量-out-x-1-47"]=0,["comvol期望音量-out-x-1-58"]=0,["comvol期望音量-out-avol1-49"]=0,["comvol期望音量-out-avol1-54"]=0,["comvol期望音量-out-avol1-46"]=0,["comvol期望音量-out-x-1-44"]=0,["comvol期望音量-out-avol1-48"]=0,["comvol期望音量-out-x-1-50"]=0,["comvol期望音量-out-avol1-55"]=0,["comvol期望音量-out-avol1-56"]=0,["comvol期望音量-out-avol1-58"]=0,["comvol期望音量-out-x-1-45"]=0,["comvol期望音量-out-avol1-51"]=0,["comvol期望音量-out-avol1-50"]=0,["comvol期望音量-out-avol1-52"]=0,["comvol期望音量-out-x-1-43"]=0,["comvol期望音量-out-avol1-43"]=0,["comvol期望音量-out-avol1-44"]=0,["comvol期望音量-out-x-1-51"]=0,["comvol期望音量-out-x-1-48"]=0,["comvol期望音量-out-x-1-53"]=0,["comvol期望音量-out-avol1-53"]=0,["comvol期望音量-out-x-1-52"]=0,["comvol期望音量-out-x-1-56"]=0,["comvol期望音量-out-avol1-47"]=0,["comvol期望音量-out-x-1-54"]=0,["comvol期望音量-out-x-1-57"]=0,["comvol期望音量-out-x-1-46"]=0,["comvol期望音量-out-x-1-49"]=0,["comvol期望音量-out-x-1-69"]=0,["comvol期望音量-out-x-1-74"]=0,["comvol期望音量-out-avol1-74"]=0,["comvol期望音量-out-avol1-60"]=0,["comvol期望音量-out-x-1-64"]=0,["comvol期望音量-out-x-1-59"]=0,["comvol期望音量-out-x-1-60"]=0,["comvol期望音量-out-avol1-62"]=0,["comvol期望音量-out-x-1-61"]=0,["comvol期望音量-out-x-1-63"]=0,["comvol期望音量-out-avol1-67"]=0,["comvol期望音量-out-x-1-68"]=0,["comvol期望音量-out-avol1-63"]=0,["comvol期望音量-out-avol1-68"]=0,["comvol期望音量-out-avol1-69"]=0,["comvol期望音量-out-x-1-70"]=0,["comvol期望音量-out-x-1-71"]=0,["comvol期望音量-out-x-1-67"]=0,["comvol期望音量-out-avol1-71"]=0,["comvol期望音量-out-x-1-72"]=0,["comvol期望音量-out-x-1-73"]=0,["comvol期望音量-out-avol1-59"]=0,["comvol期望音量-out-avol1-61"]=0,["comvol期望音量-out-avol1-64"]=0,["comvol期望音量-out-avol1-70"]=0,["comvol期望音量-out-x-1-65"]=0,["comvol期望音量-out-avol1-65"]=0,["comvol期望音量-out-x-1-62"]=0,["comvol期望音量-out-x-1-66"]=0,["comvol期望音量-out-avol1-66"]=0,["comvol期望音量-out-avol1-73"]=0,["comvol期望音量-out-avol1-72"]=0,["comvol期望音量-out-avol1-25"]=0,["comvol期望音量-out-x-1-30"]=0,["comvol期望音量-out-x-1-24"]=0,["comvol期望音量-out-x-1-27"]=0,["comvol期望音量-out-avol1-31"]=0,["comvol期望音量-out-avol1-32"]=0,["comvol期望音量-out-avol1-27"]=0,["comvol期望音量-out-avol1-33"]=0,["comvol期望音量-out-x-1-29"]=0,["comvol期望音量-out-x-1-35"]=0,["comvol期望音量-out-x-1-36"]=0,["comvol期望音量-out-avol1-38"]=0,["comvol期望音量-out-x-1-37"]=0,["comvol期望音量-out-avol1-24"]=0,["comvol期望音量-out-x-1-28"]=0,["comvol期望音量-out-x-1-26"]=0,["comvol期望音量-out-x-1-25"]=0,["comvol期望音量-out-avol1-29"]=0,["comvol期望音量-out-avol1-30"]=0,["comvol期望音量-out-avol1-35"]=0,["comvol期望音量-out-avol1-37"]=0,["comvol期望音量-out-x-1-39"]=0,["comvol期望音量-out-avol1-28"]=0,["comvol期望音量-out-x-1-31"]=0,["comvol期望音量-out-avol1-34"]=0,["comvol期望音量-out-x-1-34"]=0,["comvol期望音量-out-avol1-36"]=0,["comvol期望音量-out-x-1-38"]=0,["comvol期望音量-out-avol1-39"]=0,["comvol期望音量-out-avol1-26"]=0,["comvol期望音量-out-x-1-32"]=0,["comvol期望音量-out-x-1-33"]=0,["comvol期望音量-out-avol1-40"]=0,["comvol期望音量-out-avol1-41"]=0,["comvol期望音量-out-avol1-42"]=0,["comvol期望音量-out-x-1-40"]=0,["comvol期望音量-out-x-1-41"]=0,["comvol期望音量-out-x-1-42"]=0,["comvol期望音量-2 9"]=0.000000,["comvol期望音量-2 19"]=0.000000,["comvol使能-2-22"]=0,["comvol使能-2-11"]=0,["comvol期望音量-2 14"]=0.000000,["comvol期望音量-2 17"]=0.000000,["comvol期望音量-2 20"]=0.000000,["comvol使能-2-19"]=0,["comvol使能-2-14"]=0,["comvol期望音量-2 7"]=0.000000,["comvol使能-2-12"]=0,["comvol期望音量-2 15"]=0.000000,["comvol期望音量-2 16"]=0.000000,["comvol使能-2-21"]=0,["comvol使能-2-13"]=0,["comvol使能-2-8"]=0,["comvol使能-2-10"]=0,["comvol使能-2-18"]=0,["comvol使能-2-9"]=0,["comvol使能-2-15"]=0,["comvol期望音量-2 10"]=0.000000,["comvol期望音量-2 18"]=0.000000,["comvol期望音量-2 8"]=0.000000,["comvol期望音量-2 12"]=0.000000,["comvol期望音量-2 11"]=0.000000,["comvol使能-2-17"]=0,["comvol使能-2-20"]=0,["comvol期望音量-2 21"]=0.000000,["comvol使能-2-7"]=0,["comvol期望音量-2 22"]=0.000000,["comvol使能-2-16"]=0,["comvol期望音量-2 13"]=0.000000,["comvol期望音量-out-avol1-87"]=0,["comvol期望音量-out-avol1-90"]=0,["comvol期望音量-out-avol1-89"]=0,["comvol期望音量-out-avol1-75"]=0,["comvol期望音量-out-x-1-81"]=0,["comvol期望音量-out-x-1-83"]=0,["comvol期望音量-out-x-1-77"]=0,["comvol期望音量-out-x-1-79"]=0,["comvol期望音量-out-x-1-78"]=0,["comvol期望音量-out-avol1-76"]=0,["comvol期望音量-out-avol1-81"]=0,["comvol期望音量-out-avol1-83"]=0,["comvol期望音量-out-x-1-84"]=0,["comvol期望音量-out-avol1-84"]=0,["comvol期望音量-out-avol1-86"]=0,["comvol期望音量-out-avol1-88"]=0,["comvol期望音量-out-x-1-86"]=0,["comvol期望音量-out-x-1-75"]=0,["comvol期望音量-out-avol1-77"]=0,["comvol期望音量-out-x-1-89"]=0,["comvol期望音量-out-x-1-90"]=0,["comvol期望音量-out-x-1-88"]=0,["comvol期望音量-out-avol1-78"]=0,["comvol期望音量-out-avol1-79"]=0,["comvol期望音量-out-x-1-76"]=0,["comvol期望音量-out-x-1-80"]=0,["comvol期望音量-out-x-1-82"]=0,["comvol期望音量-out-avol1-82"]=0,["comvol期望音量-out-x-1-85"]=0,["comvol期望音量-out-avol1-80"]=0,["comvol期望音量-out-avol1-85"]=0,["comvol期望音量-out-x-1-87"]=0,["comvol期望音量-out-avol1-100"]=0,["comvol第一种,最大音量1"]=0.000000,["comvol期望音量-out-x-1-96"]=0,["comvol期望音量-out-avol1-99"]=0,["comvol使能-2-3"]=0,["comvol期望音量-out-x-1-97"]=0,["comvol期望音量-out-x-1-100"]=0,["comvol第一种,档位个数1"]=31,["comvol期望音量-2 1"]=0.000000,["comvol期望音量-out-avol1-91"]=0,["comvol期望音量-out-avol1-92"]=0,["comvol期望音量-out-avol1-95"]=0,["comvol期望音量-out-avol1-96"]=0,["comvol期望音量-out-avol1-93"]=0,["comvol期望音量-out-x-1-98"]=0,["comvol期望音量-out-avol1-98"]=0,["comvol期望音量-out-avol1-97"]=0,["comvol第一种,最小音量1"]=-50.000000,["comvol期望音量-out-x-1-99"]=0,["comvol期望音量-out-avol1-94"]=0,["comvol期望音量-out-x-1-94"]=0,["comvol期望音量-out-x-1-93"]=0,["comvol期望音量-out-x-1-92"]=0,["comvol期望音量-out-x-1-95"]=0,["comvol第二种,递音量1"]=2.000000,["comvol使能-2-1"]=0,["comvol期望音量-2 2"]=0.000000,["comvol期望音量-out-x-1-91"]=0,["comvol使能-2-2"]=0,["comvol第二种,最大音量1"]=0.000000,["comvol期望音量-2 3"]=0.000000,["comvol第二种,最小音量1"]=-50.000000,["comvol期望音量-2 4"]=0.000000,["comvol期望音量-2 6"]=0.000000,["comvol使能-2-6"]=0,["comvol使能-2-5"]=0,["comvol使能-2-4"]=0,["comvol期望音量-2 5"]=0.000000,["comvol期望音量-out-avol2-89"]=0,["comvol期望音量-out-x-2-85"]=0,["comvol期望音量-out-avol2-86"]=0,["comvol期望音量-out-x-2-88"]=0,["comvol期望音量-out-avol2-81"]=0,["comvol期望音量-out-avol2-87"]=0,["comvol期望音量-out-x-2-82"]=0,["comvol期望音量-out-avol2-82"]=0,["comvol期望音量-out-avol2-88"]=0,["comvol期望音量-out-x-2-90"]=0,["comvol期望音量-out-x-2-84"]=0,["comvol期望音量-out-avol2-79"]=0,["comvol期望音量-out-x-2-86"]=0,["comvol期望音量-out-x-2-89"]=0,["comvol期望音量-out-avol2-91"]=0,["comvol期望音量-out-avol2-78"]=0,["comvol期望音量-out-avol2-90"]=0,["comvol期望音量-out-x-2-92"]=0,["comvol期望音量-out-avol2-92"]=0,["comvol期望音量-out-x-2-93"]=0,["comvol期望音量-out-x-2-87"]=0,["comvol期望音量-out-x-2-91"]=0,["comvol期望音量-out-x-2-80"]=0,["comvol期望音量-out-avol2-77"]=0,["comvol期望音量-out-x-2-78"]=0,["comvol期望音量-out-x-2-83"]=0,["comvol期望音量-out-x-2-79"]=0,["comvol期望音量-out-avol2-80"]=0,["comvol期望音量-out-x-2-81"]=0,["comvol期望音量-out-avol2-83"]=0,["comvol期望音量-out-avol2-84"]=0,["comvol期望音量-out-avol2-85"]=0,["dvol期望音量-1 5"]=0.000000,["comvol期望音量-out-x-2-94"]=0,["comvol期望音量-out-x-2-95"]=0,["comvol期望音量-out-avol2-100"]=0,["dvol期望音量-1 6"]=0.000000,["comvol期望音量-out-avol2-98"]=0,["comvol期望音量-out-x-2-97"]=0,["comvol期望音量-out-avol2-96"]=0,["comvol期望音量-out-x-2-98"]=0,["comvol期望音量-out-avol2-99"]=0,["comvol第一种,最大音量2"]=-14.000000,["comvol期望音量-out-avol2-97"]=0,["comvol第一种,档位个数2"]=15,["comvol第二种,递音量2"]=2.000000,["comvol期望音量-out-avol2-94"]=0,["comvol第二种,最大音量2"]=-14.000000,["dvol期望音量-1 1"]=0.000000,["dvol期望音量-1 2"]=0.000000,["comvol期望音量-out-avol2-93"]=0,["comvol期望音量-out-x-2-99"]=0,["comvol第一种,最小音量2"]=-45.000000,["dvol使能-1-1"]=0,["dvol使能-1-2"]=0,["dvol期望音量-1 3"]=0.000000,["dvol使能-1-3"]=0,["dvol期望音量-1 4"]=0.000000,["dvol使能-1-5"]=0,["comvol期望音量-out-x-2-96"]=0,["comvol期望音量-out-x-2-100"]=0,["comvol第二种,最小音量2"]=-45.000000,["dvol使能-1-4"]=0,["comvol期望音量-out-avol2-95"]=0,["dvol期望音量-1 17"]=0.000000,["dvol期望音量-1 13"]=0.000000,["dvol使能-1-17"]=0,["dvol期望音量-1 12"]=0.000000,["dvol期望音量-1 21"]=0.000000,["dvol使能-1-10"]=0,["dvol期望音量-1 15"]=0.000000,["dvol使能-1-18"]=0,["dvol使能-1-9"]=0,["dvol使能-1-13"]=0,["dvol期望音量-1 8"]=0.000000,["dvol期望音量-1 7"]=0.000000,["dvol期望音量-1 14"]=0.000000,["dvol使能-1-15"]=0,["dvol期望音量-1 16"]=0.000000,["dvol使能-1-19"]=0,["dvol期望音量-1 19"]=0.000000,["dvol使能-1-8"]=0,["dvol期望音量-1 18"]=0.000000,["dvol使能-1-6"]=0,["dvol期望音量-1 10"]=0.000000,["dvol使能-1-16"]=0,["dvol期望音量-1 20"]=0.000000,["dvol使能-1-14"]=0,["dvol期望音量-1 11"]=0.000000,["dvol使能-1-20"]=0,["dvol使能-1-21"]=0,["dvol期望音量-1 22"]=0.000000,["dvol使能-1-7"]=0,["dvol使能-1-11"]=0,["dvol期望音量-1 9"]=0.000000,["dvol使能-1-12"]=0,["comvol期望音量-out-x-2-30"]=0,["comvol期望音量-out-x-2-29"]=0,["comvol期望音量-out-avol2-29"]=0,["comvol期望音量-out-x-2-34"]=0,["comvol期望音量-out-x-2-26"]=0,["comvol期望音量-out-x-2-39"]=0,["comvol期望音量-out-x-2-32"]=0,["comvol期望音量-out-avol2-38"]=0,["comvol期望音量-out-x-2-25"]=0,["comvol期望音量-out-x-2-27"]=0,["comvol期望音量-out-avol2-23"]=0,["comvol期望音量-out-avol2-25"]=0,["comvol期望音量-out-avol2-28"]=0,["comvol期望音量-out-x-2-24"]=0,["comvol期望音量-out-x-2-31"]=0,["comvol期望音量-out-avol2-32"]=0,["comvol期望音量-out-avol2-30"]=0,["comvol期望音量-out-avol2-33"]=0,["comvol期望音量-out-x-2-35"]=0,["comvol期望音量-out-avol2-24"]=0,["comvol期望音量-out-avol2-35"]=0,["comvol期望音量-out-x-2-36"]=0,["comvol期望音量-out-avol2-36"]=0,["comvol期望音量-out-x-2-37"]=0,["comvol期望音量-out-x-2-28"]=0,["comvol期望音量-out-avol2-31"]=0,["comvol期望音量-out-avol2-27"]=0,["comvol期望音量-out-x-2-33"]=0,["comvol期望音量-out-avol2-34"]=0,["comvol期望音量-out-avol2-26"]=0,["comvol期望音量-out-avol2-37"]=0,["comvol期望音量-out-x-2-38"]=0,["comvol期望音量-out-avol2-50"]=0,["comvol期望音量-out-x-2-51"]=0,["comvol期望音量-out-avol2-52"]=0,["comvol期望音量-out-x-2-46"]=0,["comvol期望音量-out-x-2-48"]=0,["comvol期望音量-out-avol2-49"]=0,["comvol期望音量-out-avol2-48"]=0,["comvol期望音量-out-x-2-49"]=0,["comvol期望音量-out-avol2-51"]=0,["comvol期望音量-out-x-2-41"]=0,["comvol期望音量-out-avol2-39"]=0,["comvol期望音量-out-avol2-47"]=0,["comvol期望音量-out-x-2-52"]=0,["comvol期望音量-out-x-2-50"]=0,["comvol期望音量-out-x-2-42"]=0,["comvol期望音量-out-avol2-46"]=0,["comvol期望音量-out-x-2-53"]=0,["comvol期望音量-out-avol2-53"]=0,["comvol期望音量-out-x-2-54"]=0,["comvol期望音量-out-avol2-54"]=0,["comvol期望音量-out-avol2-41"]=0,["comvol期望音量-out-x-2-55"]=0,["comvol期望音量-out-x-2-40"]=0,["comvol期望音量-out-avol2-42"]=0,["comvol期望音量-out-avol2-43"]=0,["comvol期望音量-out-x-2-44"]=0,["comvol期望音量-out-avol2-44"]=0,["comvol期望音量-out-avol2-40"]=0,["comvol期望音量-out-x-2-43"]=0,["comvol期望音量-out-x-2-45"]=0,["comvol期望音量-out-avol2-45"]=0,["comvol期望音量-out-x-2-47"]=0,["comvol期望音量-out-avol2-60"]=0,["comvol期望音量-out-avol2-66"]=0,["comvol期望音量-out-x-2-68"]=0,["comvol期望音量-out-avol2-70"]=0,["comvol期望音量-out-x-2-71"]=0,["comvol期望音量-out-x-2-56"]=0,["comvol期望音量-out-avol2-56"]=0,["comvol期望音量-out-x-2-57"]=0,["comvol期望音量-out-avol2-57"]=0,["comvol期望音量-out-x-2-63"]=0,["comvol期望音量-out-x-2-64"]=0,["comvol期望音量-out-x-2-67"]=0,["comvol期望音量-out-avol2-59"]=0,["comvol期望音量-out-avol2-67"]=0,["comvol期望音量-out-x-2-60"]=0,["comvol期望音量-out-avol2-68"]=0,["comvol期望音量-out-avol2-61"]=0,["comvol期望音量-out-avol2-65"]=0,["comvol期望音量-out-x-2-66"]=0,["comvol期望音量-out-avol2-64"]=0,["comvol期望音量-out-x-2-58"]=0,["comvol期望音量-out-x-2-59"]=0,["comvol期望音量-out-avol2-55"]=0,["comvol期望音量-out-avol2-62"]=0,["comvol期望音量-out-x-2-62"]=0,["comvol期望音量-out-x-2-69"]=0,["comvol期望音量-out-avol2-69"]=0,["comvol期望音量-out-x-2-70"]=0,["comvol期望音量-out-avol2-63"]=0,["comvol期望音量-out-avol2-58"]=0,["comvol期望音量-out-x-2-61"]=0,["comvol期望音量-out-x-2-65"]=0,["comvol期望音量-out-x-2-73"]=0,["comvol期望音量-out-avol2-74"]=0,["comvol期望音量-out-avol2-75"]=0,["comvol期望音量-out-x-2-75"]=0,["comvol期望音量-out-x-2-76"]=0,["comvol期望音量-out-avol2-73"]=0,["comvol期望音量-out-avol2-76"]=0,["comvol期望音量-out-x-2-77"]=0,["comvol期望音量-out-avol2-71"]=0,["comvol期望音量-out-x-2-72"]=0,["comvol期望音量-out-x-2-74"]=0,["comvol期望音量-out-avol2-72"]=0,["dvol使能-1-24"]=0,["dvol期望音量-1 28"]=0.000000,["dvol期望音量-1 29"]=0.000000,["dvol使能-1-29"]=0,["dvol期望音量-1 32"]=0.000000,["dvol期望音量-1 34"]=0.000000,["dvol期望音量-1 35"]=0.000000,["dvol使能-1-23"]=0,["dvol期望音量-1 23"]=0.000000,["dvol期望音量-1 36"]=0.000000,["dvol使能-1-25"]=0,["dvol期望音量-1 37"]=0.000000,["dvol期望音量-1 31"]=0.000000,["dvol使能-1-33"]=0,["dvol期望音量-1 38"]=0.000000,["dvol使能-1-36"]=0,["dvol使能-1-31"]=0,["dvol使能-1-34"]=0,["dvol使能-1-37"]=0,["dvol期望音量-1 30"]=0.000000,["dvol使能-1-30"]=0,["dvol使能-1-35"]=0,["dvol使能-1-38"]=0,["dvol使能-1-32"]=0,["dvol期望音量-1 33"]=0.000000,["dvol期望音量-1 24"]=0.000000,["dvol期望音量-1 26"]=0.000000,["dvol使能-1-28"]=0,["dvol期望音量-1 25"]=0.000000,["dvol期望音量-1 27"]=0.000000,["dvol使能-1-26"]=0,["dvol使能-1-27"]=0,["dvol使能-1-50"]=0,["dvol使能-1-51"]=0,["dvol期望音量-1 51"]=0.000000,["dvol期望音量-1 52"]=0.000000,["dvol使能-1-52"]=0,["dvol期望音量-1 44"]=0.000000,["dvol期望音量-1 48"]=0.000000,["dvol使能-1-40"]=0,["dvol期望音量-1 53"]=0.000000,["dvol期望音量-1 54"]=0.000000,["dvol使能-1-44"]=0,["dvol使能-1-42"]=0,["dvol使能-1-53"]=0,["dvol使能-1-54"]=0,["dvol期望音量-1 47"]=0.000000,["dvol期望音量-1 46"]=0.000000,["dvol使能-1-46"]=0,["dvol期望音量-1 42"]=0.000000,["dvol期望音量-1 43"]=0.000000,["dvol期望音量-1 45"]=0.000000,["dvol期望音量-1 41"]=0.000000,["dvol期望音量-1 39"]=0.000000,["dvol使能-1-39"]=0,["dvol期望音量-1 40"]=0.000000,["dvol使能-1-41"]=0,["dvol期望音量-1 49"]=0.000000,["dvol使能-1-45"]=0,["dvol使能-1-49"]=0,["dvol使能-1-43"]=0,["dvol使能-1-47"]=0,["dvol使能-1-48"]=0,["dvol期望音量-1 50"]=0.000000,["dvol使能-1-59"]=0,["dvol期望音量-1 55"]=0.000000,["dvol期望音量-1 56"]=0.000000,["dvol使能-1-56"]=0,["dvol使能-1-57"]=0,["dvol期望音量-1 60"]=0.000000,["dvol期望音量-1 57"]=0.000000,["dvol使能-1-60"]=0,["dvol使能-1-62"]=0,["dvol使能-1-58"]=0,["dvol期望音量-1 64"]=0.000000,["dvol使能-1-64"]=0,["dvol期望音量-1 62"]=0.000000,["dvol期望音量-1 65"]=0.000000,["dvol期望音量-1 66"]=0.000000,["dvol使能-1-66"]=0,["dvol使能-1-67"]=0,["dvol期望音量-1 58"]=0.000000,["dvol使能-1-55"]=0,["dvol使能-1-61"]=0,["dvol使能-1-63"]=0,["dvol使能-1-65"]=0,["dvol期望音量-1 67"]=0.000000,["dvol期望音量-1 61"]=0.000000,["dvol使能-1-68"]=0,["dvol期望音量-1 59"]=0.000000,["dvol期望音量-1 63"]=0.000000,["dvol期望音量-1 69"]=0.000000,["dvol期望音量-1 68"]=0.000000,["dvol期望音量-1 70"]=0.000000,["dvol使能-1-69"]=0,["dvol使能-1-70"]=0,["dvol期望音量-1 83"]=0.000000,["dvol期望音量-1 80"]=0.000000,["dvol使能-1-84"]=0,["dvol使能-1-81"]=0,["dvol使能-1-83"]=0,["dvol期望音量-1 76"]=0.000000,["dvol期望音量-1 86"]=0.000000,["dvol使能-1-71"]=0,["dvol使能-1-76"]=0,["dvol期望音量-1 71"]=0.000000,["dvol使能-1-77"]=0,["dvol期望音量-1 82"]=0.000000,["dvol期望音量-1 79"]=0.000000,["dvol使能-1-85"]=0,["dvol期望音量-1 73"]=0.000000,["dvol使能-1-86"]=0,["dvol期望音量-1 72"]=0.000000,["dvol期望音量-1 75"]=0.000000,["dvol使能-1-78"]=0,["dvol使能-1-79"]=0,["dvol期望音量-1 84"]=0.000000,["dvol期望音量-1 78"]=0.000000,["dvol期望音量-1 85"]=0.000000,["dvol使能-1-75"]=0,["dvol使能-1-74"]=0,["dvol期望音量-1 77"]=0.000000,["dvol使能-1-80"]=0,["dvol期望音量-1 81"]=0.000000,["dvol使能-1-73"]=0,["dvol期望音量-1 74"]=0.000000,["dvol使能-1-72"]=0,["dvol使能-1-82"]=0,["dvol使能-1-95"]=0,["dvol使能-1-92"]=0,["dvol期望音量-1 94"]=0.000000,["dvol期望音量-1 96"]=0.000000,["dvol期望音量-1 98"]=0.000000,["dvol期望音量-1 88"]=0.000000,["dvol期望音量-1 92"]=0.000000,["dvol使能-1-98"]=0,["dvol期望音量-1 93"]=0.000000,["dvol期望音量-1 99"]=0.000000,["dvol使能-1-99"]=0,["dvol期望音量-1 100"]=0.000000,["dvol期望音量-1 91"]=0.000000,["dvol期望音量-out-x-1-1"]=0,["dvol期望音量-1 90"]=0.000000,["dvol期望音量-1 89"]=0.000000,["dvol使能-1-91"]=0,["dvol使能-1-87"]=0,["dvol使能-1-88"]=0,["dvol使能-1-94"]=0,["dvol期望音量-1 95"]=0.000000,["dvol使能-1-96"]=0,["dvol使能-1-100"]=0,["dvol期望音量-1 97"]=0.000000,["dvol使能-1-89"]=0,["dvol使能-1-97"]=0,["dvol期望音量-1 87"]=0.000000,["dvol使能-1-90"]=0,["dvol使能-1-93"]=0,["dvol期望音量-out-x-1-10"]=0,["dvol期望音量-out-x-1-12"]=0,["dvol期望音量-out-avol1-5"]=0,["dvol期望音量-out-avol1-12"]=0,["dvol期望音量-out-x-1-4"]=0,["dvol期望音量-out-x-1-7"]=0,["dvol期望音量-out-x-1-8"]=0,["dvol期望音量-out-x-1-14"]=0,["dvol期望音量-out-x-1-9"]=0,["dvol期望音量-out-avol1-2"]=0,["dvol期望音量-out-x-1-5"]=0,["dvol期望音量-out-avol1-13"]=0,["dvol期望音量-out-x-1-15"]=0,["dvol期望音量-out-x-1-13"]=0,["dvol期望音量-out-avol1-15"]=0,["dvol期望音量-out-x-1-16"]=0,["dvol期望音量-out-avol1-16"]=0,["dvol期望音量-out-avol1-10"]=0,["dvol期望音量-out-x-1-17"]=0,["dvol期望音量-out-x-1-6"]=0,["dvol期望音量-out-avol1-6"]=0,["dvol期望音量-out-avol1-7"]=0,["dvol期望音量-out-avol1-8"]=0,["dvol期望音量-out-x-1-3"]=0,["dvol期望音量-out-x-1-2"]=0,["dvol期望音量-out-x-1-11"]=0,["dvol期望音量-out-avol1-11"]=0,["dvol期望音量-out-avol1-14"]=0,["dvol期望音量-out-avol1-3"]=0,["dvol期望音量-out-avol1-4"]=0,["dvol期望音量-out-avol1-1"]=0,["dvol期望音量-out-avol1-9"]=0,["dvol期望音量-out-x-1-21"]=0,["dvol期望音量-out-avol1-21"]=0,["dvol期望音量-out-x-1-22"]=0,["dvol期望音量-out-avol1-22"]=0,["dvol期望音量-out-x-1-23"]=0,["dvol期望音量-out-x-1-20"]=0,["dvol期望音量-out-x-1-19"]=0,["dvol期望音量-out-x-1-18"]=0,["dvol期望音量-out-avol1-18"]=0,["dvol期望音量-out-avol1-17"]=0,["dvol期望音量-out-avol1-19"]=0,["dvol期望音量-out-avol1-20"]=0,["dvol使能-2-7"]=0,["dvol使能-2-8"]=0,["dvol期望音量-2 21"]=0.000000,["dvol期望音量-2 22"]=0.000000,["dvol期望音量-2 9"]=0.000000,["dvol期望音量-2 13"]=0.000000,["dvol使能-2-16"]=0,["dvol期望音量-2 17"]=0.000000,["dvol使能-2-19"]=0,["dvol使能-2-15"]=0,["dvol期望音量-2 14"]=0.000000,["dvol使能-2-18"]=0,["dvol使能-2-12"]=0,["dvol期望音量-2 20"]=0.000000,["dvol使能-2-10"]=0,["dvol使能-2-20"]=0,["dvol使能-2-9"]=0,["dvol使能-2-13"]=0,["dvol使能-2-21"]=0,["dvol期望音量-2 18"]=0.000000,["dvol期望音量-2 12"]=0.000000,["dvol期望音量-2 11"]=0.000000,["dvol期望音量-2 15"]=0.000000,["dvol期望音量-2 7"]=0.000000,["dvol使能-2-11"]=0,["dvol期望音量-2 16"]=0.000000,["dvol期望音量-2 8"]=0.000000,["dvol使能-2-17"]=0,["dvol期望音量-2 10"]=0.000000,["dvol使能-2-14"]=0,["dvol期望音量-2 19"]=0.000000,["dvol使能-2-6"]=0,["dvol期望音量-out-x-1-37"]=0,["dvol期望音量-out-avol1-23"]=0,["dvol期望音量-out-avol1-28"]=0,["dvol期望音量-out-avol1-24"]=0,["dvol期望音量-out-avol1-31"]=0,["dvol期望音量-out-avol1-37"]=0,["dvol期望音量-out-avol1-25"]=0,["dvol期望音量-out-x-1-38"]=0,["dvol期望音量-out-x-1-24"]=0,["dvol期望音量-out-avol1-38"]=0,["dvol期望音量-out-x-1-33"]=0,["dvol期望音量-out-x-1-36"]=0,["dvol期望音量-out-x-1-39"]=0,["dvol期望音量-out-x-1-28"]=0,["dvol期望音量-out-avol1-29"]=0,["dvol期望音量-out-avol1-33"]=0,["dvol期望音量-out-avol1-36"]=0,["dvol期望音量-out-avol1-26"]=0,["dvol期望音量-out-avol1-35"]=0,["dvol期望音量-out-x-1-30"]=0,["dvol期望音量-out-avol1-30"]=0,["dvol期望音量-out-x-1-27"]=0,["dvol期望音量-out-avol1-34"]=0,["dvol期望音量-out-avol1-32"]=0,["dvol期望音量-out-x-1-25"]=0,["dvol期望音量-out-x-1-26"]=0,["dvol期望音量-out-x-1-29"]=0,["dvol期望音量-out-x-1-31"]=0,["dvol期望音量-out-x-1-32"]=0,["dvol期望音量-out-x-1-34"]=0,["dvol期望音量-out-avol1-27"]=0,["dvol期望音量-out-x-1-35"]=0,["dvol期望音量-out-x-1-51"]=0,["dvol期望音量-out-x-1-45"]=0,["dvol期望音量-out-x-1-48"]=0,["dvol期望音量-out-x-1-55"]=0,["dvol期望音量-out-avol1-49"]=0,["dvol期望音量-out-x-1-53"]=0,["dvol期望音量-out-avol1-51"]=0,["dvol期望音量-out-avol1-50"]=0,["dvol期望音量-out-avol1-43"]=0,["dvol期望音量-out-avol1-47"]=0,["dvol期望音量-out-avol1-52"]=0,["dvol期望音量-out-avol1-53"]=0,["dvol期望音量-out-x-1-42"]=0,["dvol期望音量-out-x-1-47"]=0,["dvol期望音量-out-x-1-54"]=0,["dvol期望音量-out-avol1-40"]=0,["dvol期望音量-out-avol1-46"]=0,["dvol期望音量-out-x-1-52"]=0,["dvol期望音量-out-avol1-45"]=0,["dvol期望音量-out-avol1-48"]=0,["dvol期望音量-out-x-1-44"]=0,["dvol期望音量-out-x-1-46"]=0,["dvol期望音量-out-avol1-39"]=0,["dvol期望音量-out-x-1-40"]=0,["dvol期望音量-out-x-1-41"]=0,["dvol期望音量-out-x-1-49"]=0,["dvol期望音量-out-avol1-41"]=0,["dvol期望音量-out-x-1-50"]=0,["dvol期望音量-out-avol1-42"]=0,["dvol期望音量-out-avol1-54"]=0,["dvol期望音量-out-x-1-43"]=0,["dvol期望音量-out-avol1-44"]=0,["dvol期望音量-out-avol1-68"]=0,["dvol期望音量-out-x-1-56"]=0,["dvol期望音量-out-x-1-61"]=0,["dvol期望音量-out-x-1-63"]=0,["dvol期望音量-out-x-1-65"]=0,["dvol期望音量-out-avol1-55"]=0,["dvol期望音量-out-x-1-60"]=0,["dvol期望音量-out-avol1-61"]=0,["dvol期望音量-out-avol1-62"]=0,["dvol期望音量-out-x-1-68"]=0,["dvol期望音量-out-x-1-69"]=0,["dvol期望音量-out-x-1-59"]=0,["dvol期望音量-out-avol1-69"]=0,["dvol期望音量-out-x-1-70"]=0,["dvol期望音量-out-avol1-70"]=0,["dvol期望音量-out-x-1-71"]=0,["dvol期望音量-out-avol1-65"]=0,["dvol期望音量-out-avol1-59"]=0,["dvol期望音量-out-x-1-62"]=0,["dvol期望音量-out-avol1-58"]=0,["dvol期望音量-out-avol1-57"]=0,["dvol期望音量-out-x-1-64"]=0,["dvol期望音量-out-avol1-60"]=0,["dvol期望音量-out-x-1-57"]=0,["dvol期望音量-out-avol1-63"]=0,["dvol期望音量-out-avol1-64"]=0,["dvol期望音量-out-x-1-66"]=0,["dvol期望音量-out-x-1-67"]=0,["dvol期望音量-out-avol1-56"]=0,["dvol期望音量-out-avol1-67"]=0,["dvol期望音量-out-x-1-58"]=0,["dvol期望音量-out-avol1-66"]=0,["dvol期望音量-out-avol1-73"]=0,["dvol期望音量-out-x-1-79"]=0,["dvol期望音量-out-x-1-81"]=0,["dvol期望音量-out-x-1-75"]=0,["dvol期望音量-out-x-1-87"]=0,["dvol期望音量-out-avol1-71"]=0,["dvol期望音量-out-x-1-76"]=0,["dvol期望音量-out-x-1-72"]=0,["dvol期望音量-out-avol1-75"]=0,["dvol期望音量-out-avol1-76"]=0,["dvol期望音量-out-x-1-77"]=0,["dvol期望音量-out-avol1-77"]=0,["dvol期望音量-out-x-1-78"]=0,["dvol期望音量-out-avol1-72"]=0,["dvol期望音量-out-x-1-80"]=0,["dvol期望音量-out-avol1-81"]=0,["dvol期望音量-out-x-1-82"]=0,["dvol期望音量-out-avol1-80"]=0,["dvol期望音量-out-avol1-83"]=0,["dvol期望音量-out-x-1-73"]=0,["dvol期望音量-out-avol1-74"]=0,["dvol期望音量-out-avol1-84"]=0,["dvol期望音量-out-x-1-83"]=0,["dvol期望音量-out-avol1-78"]=0,["dvol期望音量-out-x-1-85"]=0,["dvol期望音量-out-avol1-82"]=0,["dvol期望音量-out-x-1-74"]=0,["dvol期望音量-out-x-1-86"]=0,["dvol期望音量-out-avol1-85"]=0,["dvol期望音量-out-avol1-86"]=0,["dvol期望音量-out-x-1-84"]=0,["dvol期望音量-out-avol1-79"]=0,["dvol期望音量-out-avol1-89"]=0,["dvol期望音量-out-x-1-90"]=0,["dvol期望音量-out-x-1-93"]=0,["dvol期望音量-out-x-1-94"]=0,["dvol期望音量-out-x-1-95"]=0,["dvol第一种,档位个数1"]=31,["dvol期望音量-out-x-1-97"]=0,["dvol期望音量-out-x-1-99"]=0,["dvol期望音量-out-avol1-91"]=0,["dvol期望音量-out-avol1-93"]=0,["dvol期望音量-out-avol1-97"]=0,["dvol期望音量-out-x-1-91"]=0,["dvol期望音量-out-avol1-88"]=0,["dvol期望音量-out-avol1-99"]=0,["dvol第一种,最小音量1"]=-50.000000,["dvol期望音量-out-x-1-89"]=0,["dvol期望音量-out-avol1-90"]=0,["dvol期望音量-out-avol1-92"]=0,["dvol期望音量-out-x-1-92"]=0,["dvol第二种,递音量1"]=2.000000,["dvol第二种,最大音量1"]=0.000000,["dvol期望音量-out-x-1-96"]=0,["dvol期望音量-out-avol1-94"]=0,["dvol期望音量-out-avol1-87"]=0,["dvol期望音量-out-avol1-95"]=0,["dvol期望音量-out-avol1-96"]=0,["dvol期望音量-out-x-1-98"]=0,["dvol期望音量-out-x-1-88"]=0,["dvol期望音量-out-avol1-98"]=0,["dvol期望音量-out-x-1-100"]=0,["dvol期望音量-out-avol1-100"]=0,["dvol第一种,最大音量1"]=0.000000,["dvol期望音量-2 6"]=0.000000,["dvol第二种,最小音量1"]=-50.000000,["dvol使能-2-2"]=0,["dvol期望音量-2 3"]=0.000000,["dvol期望音量-2 5"]=0.000000,["dvol使能-2-1"]=0,["dvol期望音量-2 1"]=0.000000,["dvol期望音量-2 2"]=0.000000,["dvol使能-2-3"]=0,["dvol期望音量-2 4"]=0.000000,["dvol使能-2-4"]=0,["dvol使能-2-5"]=0,["dvol期望音量-out-avol2-93"]=0,["dvol期望音量-out-x-2-96"]=0,["dvol期望音量-out-avol2-98"]=0,["cvp.3mic.dns状态同步使能开关"]=1,["开始充电LED"]=9,["开始充电TONE"]=255,["dvol第二种,递音量2"]=2.000000,["dvol第二种,最小音量2"]=-45.000000,["充电完成LED"]=3,["充电完成TONE"]=255,["开机LED"]=3,["dvol期望音量-out-x-2-100"]=0,["dvol期望音量-out-avol2-95"]=0,["dvol期望音量-out-avol2-100"]=0,["dvol期望音量-out-x-2-95"]=0,["dvol期望音量-out-avol2-96"]=0,["dvol期望音量-out-x-2-97"]=0,["dvol期望音量-out-x-2-98"]=0,["dvol第一种,档位个数2"]=15,["dvol第一种,最小音量2"]=-45.000000,["dvol第二种,最大音量2"]=-14.000000,["dvol期望音量-out-avol2-94"]=0,["dvol期望音量-out-avol2-97"]=0,["dvol期望音量-out-x-2-94"]=0,["dvol期望音量-out-x-2-99"]=0,["volume_cfg"]=0,["dvol期望音量-out-avol2-99"]=0,["dvol第一种,最大音量2"]=-14.000000,["对耳断开连接LED"]=16,["cvp.3mic.dnsKEY0 按键HOLD消息"]=255,["蓝牙初始化完成TONE"]=10,["cvp.3mic.dnsKEY0 按键抬按消息"]=255,["cvp.3mic.dnsKEY0 按键双击消息"]=255,["cvp.3mic.dnsKEY0 按键三击消息"]=255,["cvp.3mic.dnsKEY1 按键短按消息"]=255,["cvp.3mic.dnsKEY1 按键长按消息"]=255,["cvp.3mic.dnsKEY1 按键HOLD消息"]=255,["关机LED"]=21,["开机TONE"]=17,["低电LED"]=14,["最大音量TONE"]=19,["蓝牙连接成功TONE"]=11,["通话中LED"]=255,["蓝牙连接成功LED"]=1,["来电LED"]=255,["蓝牙初始化完成LED"]=16,["蓝牙断开连接TONE"]=12,["对耳连接成功LED"]=15,["对耳连接成功TONE"]=13,["去电TONE"]=255,["对耳断开连接TONE"]=14,["关机TONE"]=16,["cvp.3mic.dnsKEY0 按键短按消息"]=255,["来电TONE"]=18,["蓝牙断开连接LED"]=15,["最大音量LED"]=255,["通话中TONE"]=255,["低电TONE"]=15,["去电LED"]=255,["cvp.3mic.dnsKEY0 按键长按消息"]=255,["dvol期望音量-2 35"]=0.000000,["dvol使能-2-24"]=0,["dvol使能-2-35"]=0,["dvol期望音量-2 37"]=0.000000,["dvol使能-2-22"]=0,["dvol期望音量-2 29"]=0.000000,["dvol使能-2-33"]=0,["dvol使能-2-25"]=0,["dvol期望音量-2 36"]=0.000000,["dvol期望音量-2 23"]=0.000000,["dvol期望音量-2 32"]=0.000000,["dvol期望音量-2 31"]=0.000000,["dvol使能-2-29"]=0,["dvol使能-2-37"]=0,["dvol期望音量-2 38"]=0.000000,["dvol使能-2-31"]=0,["dvol期望音量-2 30"]=0.000000,["dvol期望音量-2 34"]=0.000000,["dvol使能-2-36"]=0,["dvol使能-2-23"]=0,["dvol使能-2-28"]=0,["dvol期望音量-2 25"]=0.000000,["dvol期望音量-2 26"]=0.000000,["dvol使能-2-26"]=0,["dvol期望音量-2 24"]=0.000000,["dvol使能-2-27"]=0,["dvol期望音量-2 28"]=0.000000,["dvol使能-2-30"]=0,["dvol使能-2-32"]=0,["dvol期望音量-2 33"]=0.000000,["dvol期望音量-2 27"]=0.000000,["dvol使能-2-34"]=0,["dvol使能-2-45"]=0,["dvol期望音量-2 40"]=0.000000,["dvol使能-2-40"]=0,["dvol期望音量-2 42"]=0.000000,["dvol使能-2-38"]=0,["dvol使能-2-43"]=0,["dvol期望音量-2 44"]=0.000000,["dvol使能-2-48"]=0,["dvol使能-2-41"]=0,["dvol使能-2-47"]=0,["dvol期望音量-2 49"]=0.000000,["dvol使能-2-50"]=0,["dvol使能-2-53"]=0,["dvol期望音量-2 54"]=0.000000,["dvol使能-2-46"]=0,["dvol期望音量-2 53"]=0.000000,["dvol期望音量-2 43"]=0.000000,["dvol期望音量-2 47"]=0.000000,["dvol期望音量-2 39"]=0.000000,["dvol期望音量-2 41"]=0.000000,["dvol期望音量-2 46"]=0.000000,["dvol使能-2-42"]=0,["dvol使能-2-44"]=0,["dvol期望音量-2 45"]=0.000000,["dvol使能-2-49"]=0,["dvol期望音量-2 50"]=0.000000,["dvol期望音量-2 51"]=0.000000,["dvol使能-2-51"]=0,["dvol使能-2-39"]=0,["dvol期望音量-2 48"]=0.000000,["dvol期望音量-2 52"]=0.000000,["dvol使能-2-52"]=0,["dvol期望音量-2 66"]=0.000000,["dvol期望音量-2 62"]=0.000000,["dvol使能-2-62"]=0,["dvol使能-2-69"]=0,["dvol期望音量-2 70"]=0.000000,["dvol期望音量-2 59"]=0.000000,["dvol使能-2-61"]=0,["dvol使能-2-54"]=0,["dvol使能-2-58"]=0,["dvol期望音量-2 60"]=0.000000,["dvol使能-2-60"]=0,["dvol使能-2-59"]=0,["dvol使能-2-56"]=0,["dvol期望音量-2 65"]=0.000000,["dvol期望音量-2 68"]=0.000000,["dvol期望音量-2 56"]=0.000000,["dvol期望音量-2 55"]=0.000000,["dvol期望音量-2 57"]=0.000000,["dvol期望音量-2 63"]=0.000000,["dvol使能-2-66"]=0,["dvol期望音量-2 67"]=0.000000,["dvol使能-2-63"]=0,["dvol使能-2-67"]=0,["dvol使能-2-68"]=0,["dvol期望音量-2 69"]=0.000000,["dvol期望音量-2 58"]=0.000000,["dvol期望音量-2 61"]=0.000000,["dvol使能-2-55"]=0,["dvol期望音量-2 64"]=0.000000,["dvol使能-2-57"]=0,["dvol使能-2-64"]=0,["dvol使能-2-65"]=0,["dvol期望音量-2 71"]=0.000000,["dvol期望音量-2 75"]=0.000000,["dvol期望音量-2 79"]=0.000000,["dvol期望音量-2 76"]=0.000000,["dvol使能-2-70"]=0,["dvol使能-2-79"]=0,["dvol使能-2-72"]=0,["dvol期望音量-2 82"]=0.000000,["dvol使能-2-82"]=0,["dvol使能-2-83"]=0,["dvol使能-2-84"]=0,["dvol使能-2-73"]=0,["dvol使能-2-76"]=0,["dvol期望音量-2 85"]=0.000000,["dvol期望音量-2 81"]=0.000000,["dvol使能-2-71"]=0,["dvol期望音量-2 86"]=0.000000,["dvol期望音量-2 80"]=0.000000,["dvol使能-2-74"]=0,["dvol使能-2-77"]=0,["dvol使能-2-78"]=0,["dvol使能-2-80"]=0,["dvol使能-2-81"]=0,["dvol期望音量-2 83"]=0.000000,["dvol期望音量-2 78"]=0.000000,["dvol期望音量-2 72"]=0.000000,["dvol使能-2-75"]=0,["dvol期望音量-2 73"]=0.000000,["dvol期望音量-2 77"]=0.000000,["dvol期望音量-2 84"]=0.000000,["dvol使能-2-85"]=0,["dvol期望音量-2 74"]=0.000000,["dvol使能-2-93"]=0,["dvol期望音量-2 94"]=0.000000,["dvol期望音量-2 88"]=0.000000,["dvol使能-2-92"]=0,["dvol使能-2-99"]=0,["dvol期望音量-2 87"]=0.000000,["dvol使能-2-90"]=0,["dvol期望音量-2 93"]=0.000000,["dvol期望音量-2 97"]=0.000000,["dvol期望音量-2 100"]=0.000000,["dvol使能-2-100"]=0,["dvol使能-2-95"]=0,["dvol期望音量-2 96"]=0.000000,["dvol使能-2-86"]=0,["dvol期望音量-2 91"]=0.000000,["dvol使能-2-89"]=0,["dvol使能-2-97"]=0,["dvol使能-2-94"]=0,["dvol期望音量-2 92"]=0.000000,["dvol使能-2-87"]=0,["dvol使能-2-88"]=0,["dvol期望音量-2 95"]=0.000000,["dvol使能-2-96"]=0,["dvol期望音量-2 90"]=0.000000,["dvol使能-2-98"]=0,["dvol期望音量-2 99"]=0.000000,["dvol使能-2-91"]=0,["dvol期望音量-2 98"]=0.000000,["dvol期望音量-2 89"]=0.000000,["dvol期望音量-out-avol2-4"]=0,["dvol期望音量-out-avol2-6"]=0,["dvol期望音量-out-x-2-5"]=0,["dvol期望音量-out-x-2-2"]=0,["dvol期望音量-out-avol2-12"]=0,["dvol期望音量-out-avol2-15"]=0,["dvol期望音量-out-avol2-3"]=0,["dvol期望音量-out-avol2-5"]=0,["dvol期望音量-out-avol2-7"]=0,["dvol期望音量-out-x-2-8"]=0,["dvol期望音量-out-x-2-9"]=0,["dvol期望音量-out-x-2-13"]=0,["dvol期望音量-out-avol2-13"]=0,["dvol期望音量-out-x-2-3"]=0,["dvol期望音量-out-avol2-10"]=0,["dvol期望音量-out-x-2-10"]=0,["dvol期望音量-out-x-2-11"]=0,["dvol期望音量-out-x-2-16"]=0,["dvol期望音量-out-avol2-8"]=0,["dvol期望音量-out-x-2-12"]=0,["dvol期望音量-out-x-2-15"]=0,["dvol期望音量-out-x-2-1"]=0,["dvol期望音量-out-x-2-4"]=0,["dvol期望音量-out-avol2-11"]=0,["dvol期望音量-out-x-2-6"]=0,["dvol期望音量-out-avol2-9"]=0,["dvol期望音量-out-x-2-14"]=0,["dvol期望音量-out-avol2-16"]=0,["dvol期望音量-out-avol2-1"]=0,["dvol期望音量-out-avol2-2"]=0,["dvol期望音量-out-avol2-14"]=0,["dvol期望音量-out-x-2-7"]=0,["dvol期望音量-out-avol2-32"]=0,["dvol期望音量-out-avol2-17"]=0,["dvol期望音量-out-x-2-19"]=0,["dvol期望音量-out-avol2-19"]=0,["dvol期望音量-out-avol2-27"]=0,["dvol期望音量-out-x-2-20"]=0,["dvol期望音量-out-x-2-23"]=0,["dvol期望音量-out-x-2-24"]=0,["dvol期望音量-out-avol2-26"]=0,["dvol期望音量-out-x-2-18"]=0,["dvol期望音量-out-avol2-28"]=0,["dvol期望音量-out-x-2-29"]=0,["dvol期望音量-out-x-2-30"]=0,["dvol期望音量-out-avol2-21"]=0,["dvol期望音量-out-x-2-32"]=0,["dvol期望音量-out-x-2-21"]=0,["dvol期望音量-out-x-2-26"]=0,["dvol期望音量-out-x-2-27"]=0,["dvol期望音量-out-avol2-18"]=0,["dvol期望音量-out-x-2-25"]=0,["dvol期望音量-out-avol2-25"]=0,["dvol期望音量-out-x-2-28"]=0,["dvol期望音量-out-x-2-22"]=0,["dvol期望音量-out-avol2-24"]=0,["dvol期望音量-out-x-2-17"]=0,["dvol期望音量-out-avol2-29"]=0,["dvol期望音量-out-avol2-30"]=0,["dvol期望音量-out-avol2-20"]=0,["dvol期望音量-out-avol2-23"]=0,["dvol期望音量-out-avol2-22"]=0,["dvol期望音量-out-x-2-31"]=0,["dvol期望音量-out-avol2-31"]=0,["dvol期望音量-out-x-2-46"]=0,["dvol期望音量-out-avol2-47"]=0,["dvol期望音量-out-x-2-47"]=0,["dvol期望音量-out-x-2-48"]=0,["dvol期望音量-out-avol2-48"]=0,["dvol期望音量-out-avol2-33"]=0,["dvol期望音量-out-avol2-35"]=0,["dvol期望音量-out-x-2-40"]=0,["dvol期望音量-out-avol2-44"]=0,["dvol期望音量-out-x-2-36"]=0,["dvol期望音量-out-avol2-34"]=0,["dvol期望音量-out-avol2-37"]=0,["dvol期望音量-out-avol2-41"]=0,["dvol期望音量-out-avol2-40"]=0,["dvol期望音量-out-avol2-36"]=0,["dvol期望音量-out-x-2-41"]=0,["dvol期望音量-out-x-2-33"]=0,["dvol期望音量-out-x-2-37"]=0,["dvol期望音量-out-x-2-39"]=0,["dvol期望音量-out-avol2-39"]=0,["dvol期望音量-out-avol2-42"]=0,["dvol期望音量-out-x-2-44"]=0,["dvol期望音量-out-x-2-42"]=0,["dvol期望音量-out-avol2-43"]=0,["dvol期望音量-out-x-2-35"]=0,["dvol期望音量-out-avol2-38"]=0,["dvol期望音量-out-x-2-43"]=0,["dvol期望音量-out-x-2-38"]=0,["dvol期望音量-out-x-2-45"]=0,["dvol期望音量-out-avol2-45"]=0,["dvol期望音量-out-x-2-34"]=0,["dvol期望音量-out-avol2-46"]=0,["dvol期望音量-out-avol2-50"]=0,["dvol期望音量-out-avol2-56"]=0,["dvol期望音量-out-avol2-63"]=0,["dvol期望音量-out-x-2-64"]=0,["dvol期望音量-out-avol2-64"]=0,["dvol期望音量-out-x-2-54"]=0,["dvol期望音量-out-x-2-55"]=0,["dvol期望音量-out-avol2-57"]=0,["dvol期望音量-out-x-2-50"]=0,["dvol期望音量-out-avol2-52"]=0,["dvol期望音量-out-x-2-58"]=0,["dvol期望音量-out-x-2-61"]=0,["dvol期望音量-out-avol2-49"]=0,["dvol期望音量-out-avol2-51"]=0,["dvol期望音量-out-x-2-57"]=0,["dvol期望音量-out-avol2-54"]=0,["dvol期望音量-out-x-2-59"]=0,["dvol期望音量-out-avol2-59"]=0,["dvol期望音量-out-avol2-53"]=0,["dvol期望音量-out-avol2-60"]=0,["dvol期望音量-out-avol2-58"]=0,["dvol期望音量-out-avol2-62"]=0,["dvol期望音量-out-x-2-56"]=0,["dvol期望音量-out-x-2-62"]=0,["dvol期望音量-out-x-2-53"]=0,["dvol期望音量-out-x-2-63"]=0,["dvol期望音量-out-x-2-51"]=0,["dvol期望音量-out-x-2-60"]=0,["dvol期望音量-out-avol2-61"]=0,["dvol期望音量-out-avol2-55"]=0,["dvol期望音量-out-x-2-52"]=0,["dvol期望音量-out-x-2-49"]=0,["dvol期望音量-out-avol2-73"]=0,["dvol期望音量-out-x-2-68"]=0,["dvol期望音量-out-x-2-73"]=0,["dvol期望音量-out-avol2-74"]=0,["dvol期望音量-out-avol2-77"]=0,["dvol期望音量-out-avol2-69"]=0,["dvol期望音量-out-avol2-76"]=0,["dvol期望音量-out-avol2-75"]=0,["dvol期望音量-out-avol2-70"]=0,["dvol期望音量-out-avol2-72"]=0,["dvol期望音量-out-x-2-77"]=0,["dvol期望音量-out-x-2-78"]=0,["dvol期望音量-out-avol2-65"]=0,["dvol期望音量-out-avol2-66"]=0,["dvol期望音量-out-avol2-68"]=0,["dvol期望音量-out-x-2-66"]=0,["dvol期望音量-out-x-2-70"]=0,["dvol期望音量-out-x-2-72"]=0,["dvol期望音量-out-x-2-74"]=0,["dvol期望音量-out-x-2-76"]=0,["dvol期望音量-out-avol2-78"]=0,["dvol期望音量-out-avol2-71"]=0,["dvol期望音量-out-x-2-71"]=0,["dvol期望音量-out-avol2-67"]=0,["dvol期望音量-out-x-2-75"]=0,["dvol期望音量-out-x-2-79"]=0,["dvol期望音量-out-x-2-69"]=0,["dvol期望音量-out-avol2-79"]=0,["dvol期望音量-out-x-2-80"]=0,["dvol期望音量-out-avol2-80"]=0,["dvol期望音量-out-x-2-67"]=0,["dvol期望音量-out-x-2-65"]=0,["dvol期望音量-out-avol2-83"]=0,["dvol期望音量-out-x-2-93"]=0,["dvol期望音量-out-x-2-85"]=0,["dvol期望音量-out-avol2-86"]=0,["dvol期望音量-out-avol2-81"]=0,["dvol期望音量-out-x-2-82"]=0,["dvol期望音量-out-avol2-85"]=0,["dvol期望音量-out-x-2-87"]=0,["dvol期望音量-out-x-2-88"]=0,["dvol期望音量-out-x-2-91"]=0,["dvol期望音量-out-x-2-86"]=0,["dvol期望音量-out-x-2-81"]=0,["dvol期望音量-out-avol2-89"]=0,["dvol期望音量-out-x-2-84"]=0,["dvol期望音量-out-avol2-82"]=0,["dvol期望音量-out-x-2-83"]=0,["dvol期望音量-out-avol2-91"]=0,["dvol期望音量-out-x-2-89"]=0,["dvol期望音量-out-avol2-87"]=0,["dvol期望音量-out-avol2-84"]=0,["dvol期望音量-out-avol2-88"]=0,["dvol期望音量-out-avol2-90"]=0,["dvol期望音量-out-x-2-92"]=0,["dvol期望音量-out-avol2-92"]=0,["dvol期望音量-out-x-2-90"]=0,["cvp.3mic.dnsKEY1 按键三击消息"]=255,["cvp.3mic.dnsKEY4 按键三击消息"]=255,["cvp.3mic.dnsKEY4 按键长按消息"]=255,["cvp.3mic.dnsKEY4 按键抬按消息"]=255,["cvp.3mic.dnsKEY4 按键HOLD消息"]=255,["cvp.3mic.dnsKEY5 按键抬按消息"]=255,["cvp.3mic.dnsKEY3 按键长按消息"]=255,["cvp.3mic.dnsKEY3 按键三击消息"]=255,["cvp.3mic.dnsKEY5 按键长按消息"]=255,["cvp.3mic.dnsKEY5 按键三击消息"]=255,["cvp.3mic.dnsKEY6 按键短按消息"]=255,["cvp.3mic.dnsKEY6 按键长按消息"]=255,["cvp.3mic.dnsKEY6 按键HOLD消息"]=255,["cvp.3mic.dnsKEY3 按键HOLD消息"]=255,["cvp.3mic.dnsKEY2 按键长按消息"]=255,["cvp.3mic.dnsKEY6 按键抬按消息"]=255,["cvp.3mic.dnsKEY6 按键双击消息"]=255,["cvp.3mic.dnsKEY4 按键短按消息"]=255,["cvp.3mic.dnsKEY2 按键三击消息"]=255,["cvp.3mic.dnsKEY4 按键双击消息"]=255,["cvp.3mic.dnsKEY5 按键HOLD消息"]=255,["cvp.3mic.dnsKEY3 按键双击消息"]=255,["cvp.3mic.dnsKEY3 按键抬按消息"]=255,["cvp.3mic.dnsKEY5 按键短按消息"]=255,["cvp.3mic.dnsKEY2 按键HOLD消息"]=255,["cvp.3mic.dnsKEY2 按键抬按消息"]=255,["cvp.3mic.dnsKEY5 按键双击消息"]=255,["cvp.3mic.dnsKEY6 按键三击消息"]=255,["cvp.3mic.dnsKEY2 按键短按消息"]=255,["cvp.3mic.dnsKEY2 按键双击消息"]=255,["cvp.3mic.dnsKEY3 按键短按消息"]=255,["cvp.3mic.dnsKEY7 按键短按消息"]=255,["cvp.3mic.dnsKEY8 按键HOLD消息"]=255,["cvp.3mic.dnsKEY9 按键长按消息"]=255,["cvp.3mic.dnsKEY9 按键双击消息"]=255,["cvp.3mic.dns开机充电使能开关"]=0,["cvp.3mic.dnsKEY8 按键双击消息"]=255,["cvp.3mic.dns充电电流"]=3,["cvp.3mic.dns入耳检测按键灵敏度配置"]=5,["cvp.3mic.dnsKEY9 按键HOLD消息"]=255,["cvp.3mic.dnsKEY8 按键短按消息"]=255,["cvp.3mic.dnsKEY7 按键双击消息"]=255,["cvp.3mic.dnsKEY8 按键抬按消息"]=255,["cvp.3mic.dns触摸按键灵敏度配置"]=5,["cvp.3mic.dnsKEY7 按键HOLD消息"]=255,["cvp.3mic.dnsKEY8 按键长按消息"]=255,["cvp.3mic.dnsKEY9 按键短按消息"]=255,["cvp.3mic.dnsKEY9 按键抬按消息"]=255,["cvp.3mic.dnsKEY7 按键长按消息"]=255,["cvp.3mic.dns充电满电流"]=3,["cvp.3mic.dns低电关机电压设置"]=330,["cvp.3mic.dnsKEY8 按键三击消息"]=255,["cvp.3mic.dns充电满电压"]=8,["cvp.3mic.dns充电配置使能开关"]=1,["cvp.3mic.dnsKEY9 按键三击消息"]=255,["cvp.3mic.dnsKEY7 按键三击消息"]=255,["cvp.3mic.dns低电提醒电压设置"]=340,["cvp.3mic.dnsKEY7 按键抬按消息"]=255,["cvp.3mic.dns触摸按键灵敏度配置使能"]=0,["ANCr_fbgain:/show"]=0.000000,["ANCr_fbgain:"]=1.000000,["ANCr_cmpgain:/show"]=0.000000,["ANCr_cmpgain:"]=1.000000,["ANCdac_gain:"]=3,["ANCcmp_en:"]=1,["ANCr_ffgain:"]=1.000000,["ANCl_ffmic_gain"]=4,["ANCl_ffgain:/show"]=0.000000,["ANCgain_sign:"]=0,["ANCdrc_en:"]=0,["ANCl_fbmic_gain"]=4,["ANCl_transgain:/show"]=0.000000,["ANCl_fbgain:/show"]=0.000000,["ANCl_cmpgain:/show"]=0.000000,["ANCl_cmpgain:"]=1.000000,["ANCr_transgain:/show"]=0.000000,["ANCfade_step:"]=1,["ANCalogm:"]=5,["ANCr_ffgain:/show"]=0.000000,["ANCr_transgain:"]=1.000000,["ANCahs_en:"]=1,["ANCl_fbgain:"]=1.000000,["ANCtrans_alogm:"]=3,["ANCl_ffgain:"]=1.000000,["ANCl_transgain:"]=1.000000,["ANCnoise_lvl:"]=0,["ANCdrcfb_norgain:/show"]=0.000000,["ANCdrcff_lgain:"]=1024,["ANCdrcff_hgain:"]=513,["ANCdrctrans_lgain:/show"]=0.000000,["ANCdrcff_norgain:/show"]=0.000000,["ANCdrcfb_lgain:/show"]=0.000000,["ANCdrcfb_lgain:"]=1024,["ANCdrcff_hgain:/show"]=-6.000000,["ANCdrcff_lthr:"]=0,["ANCdrcff_norgain:"]=1024,["ANCdrcff_hthr:"]=6000,["ANCdrcfb_norgain:"]=1024,["ANCdrcfb_hthr:"]=6000,["ANCdrctrans_lgain:"]=1024,["ANCdrctrans_lthr:"]=0,["ANCdrcff_lgain:/show"]=0.000000,["ANCdrcfb_hgain:/show"]=-6.000000,["ANCdrcfb_lthr:"]=0,["ANCdrcfb_hgain:"]=513,["ANCdrctrans_hgain:/show"]=0.000000,["ANCdrctrans_hthr:"]=32767,["ANCdrctrans_hgain:"]=1024,["ANCr_ffmic_gain"]=4,["ANCdrctrans_norgain:"]=1024,["ANCahs_wn_shift:"]=9,["*device-info-checksum*"]="",["ANCdrc_ff_2dcc:"]=0,["ANCff_2nd_dcc:"]=4,["ANCdrc_dcc_res_time:"]=10,["ANCdrc_fb_2dcc:"]=0,["ANCr_fbmic_gain"]=4,["*device-info-vid*"]="",["*device-info-pid*"]="",["ANCdrc_dcc_det_time:"]=200,["*device-info-sdk-version*"]="",["ANCdrctrans_norgain:/show"]=0.000000,["ANCfb_2nd_dcc:"]=4}
\ No newline at end of file
diff --git a/cpu/br28/tools/data_code.bin b/cpu/br28/tools/data_code.bin
new file mode 100644
index 0000000..955374e
Binary files /dev/null and b/cpu/br28/tools/data_code.bin differ
diff --git a/cpu/br28/tools/download.bat b/cpu/br28/tools/download.bat
new file mode 100644
index 0000000..64f3c15
--- /dev/null
+++ b/cpu/br28/tools/download.bat
@@ -0,0 +1,48 @@
+
+
+
+
+
+@echo off
+Setlocal enabledelayedexpansion
+@echo ********************************************************************************
+@echo SDK BR28
+@echo ********************************************************************************
+@echo %date%
+
+
+cd /d %~dp0
+
+set OBJDUMP=C:\JL\pi32\bin\llvm-objdump.exe
+set OBJCOPY=C:\JL\pi32\bin\llvm-objcopy.exe
+set ELFFILE=sdk.elf
+set bankfiles=
+set LZ4_PACKET=.\lz4_packet.exe
+
+REM %OBJDUMP% -D -address-mask=0x1ffffff -print-dbg $1.elf > $1.lst
+%OBJCOPY% -O binary -j .text %ELFFILE% text.bin
+%OBJCOPY% -O binary -j .data %ELFFILE% data.bin
+%OBJCOPY% -O binary -j .data_code %ELFFILE% data_code.bin
+%OBJCOPY% -O binary -j .overlay_aec %ELFFILE% aec.bin
+%OBJCOPY% -O binary -j .overlay_aac %ELFFILE% aac.bin
+%OBJCOPY% -O binary -j .overlay_aptx %ELFFILE% aptx.bin
+
+%OBJCOPY% -O binary -j .common %ELFFILE% common.bin
+
+for /L %%i in (0,1,20) do (
+ %OBJCOPY% -O binary -j .overlay_bank%%i %ELFFILE% bank%%i.bin
+ set bankfiles=!bankfiles! bank%%i.bin 0x0
+ )
+
+
+%LZ4_PACKET% -dict text.bin -input common.bin 0 aec.bin 0 aac.bin 0 !bankfiles! -o bank.bin
+
+%OBJDUMP% -section-headers -address-mask=0x1ffffff %ELFFILE%
+REM %OBJDUMP% -t %ELFFILE% > symbol_tbl.txt
+
+copy /b text.bin + data.bin + mov_slot.bin + data_code.bin + aec.bin + aac.bin + psr_data_code.bin app.bin
+
+
+del !bankfiles! common.bin text.bin data.bin bank.bin
+copy eq_cfg_hw_less.bin eq_cfg_hw.bin
+call download/earphone/download_app_ota.bat
diff --git a/cpu/br28/tools/download.c b/cpu/br28/tools/download.c
new file mode 100644
index 0000000..4d23cfb
--- /dev/null
+++ b/cpu/br28/tools/download.c
@@ -0,0 +1,198 @@
+// *INDENT-OFF*
+#include "app_config.h"
+
+#ifdef __SHELL__
+
+##!/bin/sh
+
+${OBJDUMP} -D -address-mask=0x7ffffff -print-imm-hex -print-dbg -mcpu=r3 $1.elf > $1.lst
+${OBJCOPY} -O binary -j .text $1.elf text.bin
+${OBJCOPY} -O binary -j .data $1.elf data.bin
+${OBJCOPY} -O binary -j .moveable_slot $1.elf mov_slot.bin
+${OBJCOPY} -O binary -j .data_code $1.elf data_code.bin
+${OBJCOPY} -O binary -j .overlay_aec $1.elf aec.bin
+${OBJCOPY} -O binary -j .overlay_aac $1.elf aac.bin
+${OBJCOPY} -O binary -j .psr_data_code $1.elf psr_data_code.bin
+
+${OBJDUMP} -section-headers -address-mask=0x7ffffff $1.elf
+${OBJSIZEDUMP} -lite -skip-zero -enable-dbg-info $1.elf | sort -k 1 > symbol_tbl.txt
+
+cat text.bin data.bin mov_slot.bin data_code.bin aec.bin aac.bin psr_data_code.bin > app.bin
+
+/* if [ -f version ]; then */
+ /* host-client -project ${NICKNAME}$2 -f app.bin version $1.elf p11_code.bin br28loader.bin br28loader.uart uboot.boot uboot.boot_debug ota.bin ota_debug.bin isd_config.ini */
+/* else */
+ /* host-client -project ${NICKNAME}$2 -f app.bin $1.elf p11_code.bin br28loader.bin br28loader.uart uboot.boot uboot.boot_debug ota.bin ota_debug.bin isd_config.ini */
+
+/* fi */
+#if defined(CONFIG_EARPHONE_CASE_ENABLE)
+#if TCFG_DRC_ENABLE
+#if defined(TCFG_AUDIO_HEARING_AID_ENABLE) && TCFG_AUDIO_HEARING_AID_ENABLE && defined(AUDIO_VBASS_CONFIG)&&AUDIO_VBASS_CONFIG
+cp eq_cfg_hw_aid_vbass.bin eq_cfg_hw.bin
+#elif defined(TCFG_AUDIO_HEARING_AID_ENABLE) && TCFG_AUDIO_HEARING_AID_ENABLE
+cp eq_cfg_hw_wdrc.bin eq_cfg_hw.bin
+#elif defined(AUDIO_VBASS_CONFIG)&&AUDIO_VBASS_CONFIG
+cp eq_cfg_hw_drc_vbass.bin eq_cfg_hw.bin
+#else
+cp eq_cfg_hw_full.bin eq_cfg_hw.bin
+#endif /*TCFG_AUDIO_HEARING_AID_ENABLE*/
+#else
+#if defined(AUDIO_VBASS_CONFIG)&&AUDIO_VBASS_CONFIG
+cp eq_cfg_hw_vbass.bin eq_cfg_hw.bin
+#else
+cp eq_cfg_hw_less.bin eq_cfg_hw.bin
+#endif
+#endif
+
+#else
+#if defined(TCFG_MIC_EFFECT_ENABLE)&& TCFG_MIC_EFFECT_ENABLE && (TCFG_MIC_EFFECT_SEL == MIC_EFFECT_REVERB)&& TCFG_AUDIO_MIC_EFFECT_POST_EQ_ENABLE
+cp ./effect_file/mic_effect_reverb_full.bin eq_cfg_hw.bin
+#elif defined(TCFG_MIC_EFFECT_ENABLE)&& TCFG_MIC_EFFECT_ENABLE && (TCFG_MIC_EFFECT_SEL == MIC_EFFECT_REVERB)
+cp ./effect_file/mic_effect_reverb.bin eq_cfg_hw.bin
+#elif defined(TCFG_MIC_EFFECT_ENABLE)&& TCFG_MIC_EFFECT_ENABLE && (TCFG_MIC_EFFECT_SEL == MIC_EFFECT_ECHO)&& TCFG_AUDIO_MIC_EFFECT_POST_EQ_ENABLE
+cp ./effect_file/mic_effect_echo_full.bin eq_cfg_hw.bin
+#elif defined(TCFG_MIC_EFFECT_ENABLE)&& TCFG_MIC_EFFECT_ENABLE && (TCFG_MIC_EFFECT_SEL == MIC_EFFECT_ECHO)
+cp ./effect_file/mic_effect_echo.bin eq_cfg_hw.bin
+#elif defined(TCFG_MIC_EFFECT_ENABLE)&& TCFG_MIC_EFFECT_ENABLE && (TCFG_MIC_EFFECT_SEL == MIC_EFFECT_REVERB_ECHO)
+cp ./effect_file/mic_effect_full.bin eq_cfg_hw.bin
+#elif defined(TCFG_MIC_EFFECT_ENABLE)&& TCFG_MIC_EFFECT_ENABLE && (TCFG_MIC_EFFECT_SEL == MIC_EFFECT_MEGAPHONE)
+cp ./effect_file/mic_effect_megaphone.bin eq_cfg_hw.bin
+#elif defined(SOUND_TRACK_2_P_X_CH_CONFIG) &&SOUND_TRACK_2_P_X_CH_CONFIG&& (TWO_POINT_X_SPECIAL_CONFIG == 0)
+cp ./effect_file/music_2to1_2to2.bin eq_cfg_hw.bin
+#elif defined(SOUND_TRACK_2_P_X_CH_CONFIG) &&SOUND_TRACK_2_P_X_CH_CONFIG && TWO_POINT_X_SPECIAL_CONFIG
+cp ./effect_file/music_2to1_2to2_special.bin eq_cfg_hw.bin
+#elif defined(TCFG_DYNAMIC_EQ_ENABLE)&& TCFG_DYNAMIC_EQ_ENABLE && defined(LINEIN_MODE_SOLE_EQ_EN) && LINEIN_MODE_SOLE_EQ_EN
+cp ./effect_file/music_advance_linein.bin eq_cfg_hw.bin
+#elif defined(TCFG_DYNAMIC_EQ_ENABLE)&& TCFG_DYNAMIC_EQ_ENABLE
+cp ./effect_file/music_advance.bin eq_cfg_hw.bin
+#elif defined(LINEIN_MODE_SOLE_EQ_EN) && LINEIN_MODE_SOLE_EQ_EN
+cp ./effect_file/music_base_linein.bin eq_cfg_hw.bin
+#else
+cp ./effect_file/music_base.bin eq_cfg_hw.bin
+#endif
+#endif/*CONFIG_EARPHONE_CASE_ENABLE*/
+
+
+
+/opt/utils/strip-ini -i isd_config.ini -o isd_config.ini
+
+if [ -f version ]; then
+ files="app.bin version $1.elf p11_code.bin br28loader.bin br28loader.uart uboot.boot uboot.boot_debug ota.bin ota_debug.bin isd_config.ini"
+else
+ files="app.bin $1.elf p11_code.bin br28loader.bin br28loader.uart uboot.boot uboot.boot_debug ota.bin ota_debug.bin isd_config.ini"
+
+fi
+
+host-client -project ${NICKNAME}$2_${APP_CASE} -f ${files}
+
+#else
+
+@echo off
+Setlocal enabledelayedexpansion
+@echo ********************************************************************************
+@echo SDK BR28
+@echo ********************************************************************************
+@echo %date%
+
+
+cd /d %~dp0
+
+set OBJDUMP=C:\JL\pi32\bin\llvm-objdump.exe
+set OBJCOPY=C:\JL\pi32\bin\llvm-objcopy.exe
+set ELFFILE=sdk.elf
+set bankfiles=
+set LZ4_PACKET=.\lz4_packet.exe
+
+REM %OBJDUMP% -D -address-mask=0x1ffffff -print-dbg $1.elf > $1.lst
+%OBJCOPY% -O binary -j .text %ELFFILE% text.bin
+%OBJCOPY% -O binary -j .data %ELFFILE% data.bin
+%OBJCOPY% -O binary -j .data_code %ELFFILE% data_code.bin
+%OBJCOPY% -O binary -j .overlay_aec %ELFFILE% aec.bin
+%OBJCOPY% -O binary -j .overlay_aac %ELFFILE% aac.bin
+%OBJCOPY% -O binary -j .overlay_aptx %ELFFILE% aptx.bin
+
+%OBJCOPY% -O binary -j .common %ELFFILE% common.bin
+
+for /L %%i in (0,1,20) do (
+ %OBJCOPY% -O binary -j .overlay_bank%%i %ELFFILE% bank%%i.bin
+ set bankfiles=!bankfiles! bank%%i.bin 0x0
+ )
+
+
+%LZ4_PACKET% -dict text.bin -input common.bin 0 aec.bin 0 aac.bin 0 !bankfiles! -o bank.bin
+
+%OBJDUMP% -section-headers -address-mask=0x1ffffff %ELFFILE%
+REM %OBJDUMP% -t %ELFFILE% > symbol_tbl.txt
+
+copy /b text.bin + data.bin + mov_slot.bin + data_code.bin + aec.bin + aac.bin + psr_data_code.bin app.bin
+
+
+del !bankfiles! common.bin text.bin data.bin bank.bin
+
+#if defined(CONFIG_EARPHONE_CASE_ENABLE)
+
+#if TCFG_DRC_ENABLE
+
+#if defined(TCFG_AUDIO_HEARING_AID_ENABLE) && TCFG_AUDIO_HEARING_AID_ENABLE && defined(AUDIO_VBASS_CONFIG)&&AUDIO_VBASS_CONFIG
+copy eq_cfg_hw_aid_vbass.bin eq_cfg_hw.bin
+#elif defined(TCFG_AUDIO_HEARING_AID_ENABLE) && TCFG_AUDIO_HEARING_AID_ENABLE
+copy eq_cfg_hw_wdrc.bin eq_cfg_hw.bin
+#elif defined(AUDIO_VBASS_CONFIG)&&AUDIO_VBASS_CONFIG
+copy eq_cfg_hw_drc_vbass.bin eq_cfg_hw.bin
+#else
+copy eq_cfg_hw_full.bin eq_cfg_hw.bin
+#endif /*TCFG_AUDIO_HEARING_AID_ENABLE*/
+
+#else
+#if defined(AUDIO_VBASS_CONFIG)&&AUDIO_VBASS_CONFIG
+copy eq_cfg_hw_vbass.bin eq_cfg_hw.bin
+#else
+copy eq_cfg_hw_less.bin eq_cfg_hw.bin
+#endif
+#endif
+
+#else
+#if defined(TCFG_MIC_EFFECT_ENABLE)&& TCFG_MIC_EFFECT_ENABLE && (TCFG_MIC_EFFECT_SEL == MIC_EFFECT_REVERB) && TCFG_AUDIO_MIC_EFFECT_POST_EQ_ENABLE
+copy .\effect_file\mic_effect_reverb_full.bin eq_cfg_hw.bin
+#elif defined(TCFG_MIC_EFFECT_ENABLE)&& TCFG_MIC_EFFECT_ENABLE && (TCFG_MIC_EFFECT_SEL == MIC_EFFECT_REVERB)
+copy .\effect_file\mic_effect_reverb.bin eq_cfg_hw.bin
+#elif defined(TCFG_MIC_EFFECT_ENABLE)&& TCFG_MIC_EFFECT_ENABLE && (TCFG_MIC_EFFECT_SEL == MIC_EFFECT_ECHO) && TCFG_AUDIO_MIC_EFFECT_POST_EQ_ENABLE
+copy .\effect_file\mic_effect_echo_full.bin eq_cfg_hw.bin
+#elif defined(TCFG_MIC_EFFECT_ENABLE)&& TCFG_MIC_EFFECT_ENABLE && (TCFG_MIC_EFFECT_SEL == MIC_EFFECT_ECHO)
+copy .\effect_file\mic_effect_echo.bin eq_cfg_hw.bin
+#elif defined(TCFG_MIC_EFFECT_ENABLE)&& TCFG_MIC_EFFECT_ENABLE && (TCFG_MIC_EFFECT_SEL == MIC_EFFECT_REVERB_ECHO)
+copy .\effect_file\mic_effect_full.bin eq_cfg_hw.bin
+#elif defined(TCFG_MIC_EFFECT_ENABLE)&& TCFG_MIC_EFFECT_ENABLE && (TCFG_MIC_EFFECT_SEL == MIC_EFFECT_MEGAPHONE)
+copy .\effect_file\mic_effect_megaphone.bin eq_cfg_hw.bin
+#elif defined(SOUND_TRACK_2_P_X_CH_CONFIG) &&SOUND_TRACK_2_P_X_CH_CONFIG&& (TWO_POINT_X_SPECIAL_CONFIG == 0)
+copy .\effect_file\music_2to1_2to2.bin eq_cfg_hw.bin
+#elif defined(SOUND_TRACK_2_P_X_CH_CONFIG) &&SOUND_TRACK_2_P_X_CH_CONFIG && TWO_POINT_X_SPECIAL_CONFIG
+copy .\effect_file\music_2to1_2to2_special.bin eq_cfg_hw.bin
+#elif defined(TCFG_DYNAMIC_EQ_ENABLE)&& TCFG_DYNAMIC_EQ_ENABLE && defined(LINEIN_MODE_SOLE_EQ_EN) && LINEIN_MODE_SOLE_EQ_EN
+copy .\effect_file\music_advance_linein.bin eq_cfg_hw.bin
+#elif defined(TCFG_DYNAMIC_EQ_ENABLE)&& TCFG_DYNAMIC_EQ_ENABLE
+copy .\effect_file\music_advance.bin eq_cfg_hw.bin
+#elif defined(LINEIN_MODE_SOLE_EQ_EN) && LINEIN_MODE_SOLE_EQ_EN
+copy .\effect_file\music_base_linein.bin eq_cfg_hw.bin
+#else
+copy .\effect_file\music_base.bin eq_cfg_hw.bin
+#endif
+#endif/*CONFIG_EARPHONE_CASE_ENABLE*/
+
+#ifdef CONFIG_WATCH_CASE_ENABLE
+call download/watch/download.bat
+#elif defined(CONFIG_SOUNDBOX_CASE_ENABLE)
+call download/soundbox/download.bat
+#elif defined(CONFIG_EARPHONE_CASE_ENABLE)
+#if (RCSP_ADV_EN == 0)
+call download/earphone/download.bat
+#else
+call download/earphone/download_app_ota.bat
+#endif
+#elif defined(CONFIG_HID_CASE_ENABLE) ||defined(CONFIG_SPP_AND_LE_CASE_ENABLE)||defined(CONFIG_MESH_CASE_ENABLE)||defined(CONFIG_DONGLE_CASE_ENABLE) //数传
+call download/data_trans/download.bat
+#else
+//to do other case
+#endif //endif app_case
+
+#endif
diff --git a/cpu/br28/tools/download/earphone/RS-5B88.key b/cpu/br28/tools/download/earphone/RS-5B88.key
new file mode 100644
index 0000000..10a9892
--- /dev/null
+++ b/cpu/br28/tools/download/earphone/RS-5B88.key
@@ -0,0 +1 @@
+3DBA0ACD41A68B534365C721F7B23619914B4106E1024B5592A0A49D1DD417152E4DCF18
\ No newline at end of file
diff --git a/cpu/br28/tools/download/earphone/download_app_ota.bat b/cpu/br28/tools/download/earphone/download_app_ota.bat
new file mode 100644
index 0000000..bb583c5
--- /dev/null
+++ b/cpu/br28/tools/download/earphone/download_app_ota.bat
@@ -0,0 +1,47 @@
+@echo off
+
+cd %~dp0
+
+copy ..\..\script.ver .
+copy ..\..\tone.cfg .
+copy ..\..\p11_code.bin .
+copy ..\..\br28loader.bin .
+copy ..\..\ota.bin .
+copy ..\..\anc_coeff.bin .
+copy ..\..\anc_gains.bin .
+
+..\..\isd_download.exe ..\..\isd_config.ini -tonorflash -dev br28 -boot 0x120000 -div8 -wait 300 -uboot ..\..\uboot.boot -app ..\..\app.bin -res ..\..\cfg_tool.bin tone.cfg p11_code.bin -uboot_compress
+
+:: -format all -key RS-5B88.key
+::-reboot 2500
+
+@rem ɾʱļ-format all
+if exist *.mp3 del *.mp3
+if exist *.PIX del *.PIX
+if exist *.TAB del *.TAB
+if exist *.res del *.res
+if exist *.sty del *.sty
+
+..\..\ufw_maker.exe -fw_to_ufw jl_isd.fw
+copy jl_isd.ufw update.ufw
+del jl_isd.ufw
+
+@REM ļļ
+::ufw_maker.exe -chip AC800X %ADD_KEY% -output config.ufw -res bt_cfg.cfg
+
+::IF EXIST jl_696x.bin del jl_696x.bin
+
+if exist script.ver del script.ver
+if exist tone.cfg del tone.cfg
+if exist p11_code.bin del p11_code.bin
+if exist br28loader.bin del br28loader.bin
+if exist anc_coeff.bin del anc_coeff.bin
+if exist anc_gains.bin del anc_gains.bin
+
+@rem ˵
+@rem -format vm //VM
+@rem -format cfg //BT CFG
+@rem -format 0x3f0-2 //ʾӵ 0x3f0 sector ʼ 2 sector(һΪ16ƻ10ƶɣڶ10)
+
+ping /n 2 127.1>null
+IF EXIST null del null
diff --git a/cpu/br28/tools/eq_cfg_hw.bin b/cpu/br28/tools/eq_cfg_hw.bin
new file mode 100644
index 0000000..b589b69
Binary files /dev/null and b/cpu/br28/tools/eq_cfg_hw.bin differ
diff --git a/cpu/br28/tools/eq_cfg_hw_aid_vbass.bin b/cpu/br28/tools/eq_cfg_hw_aid_vbass.bin
new file mode 100644
index 0000000..5a22679
Binary files /dev/null and b/cpu/br28/tools/eq_cfg_hw_aid_vbass.bin differ
diff --git a/cpu/br28/tools/eq_cfg_hw_drc_vbass.bin b/cpu/br28/tools/eq_cfg_hw_drc_vbass.bin
new file mode 100644
index 0000000..30454d5
Binary files /dev/null and b/cpu/br28/tools/eq_cfg_hw_drc_vbass.bin differ
diff --git a/cpu/br28/tools/eq_cfg_hw_full.bin b/cpu/br28/tools/eq_cfg_hw_full.bin
new file mode 100644
index 0000000..86a3385
Binary files /dev/null and b/cpu/br28/tools/eq_cfg_hw_full.bin differ
diff --git a/cpu/br28/tools/eq_cfg_hw_less.bin b/cpu/br28/tools/eq_cfg_hw_less.bin
new file mode 100644
index 0000000..b589b69
Binary files /dev/null and b/cpu/br28/tools/eq_cfg_hw_less.bin differ
diff --git a/cpu/br28/tools/eq_cfg_hw_vbass.bin b/cpu/br28/tools/eq_cfg_hw_vbass.bin
new file mode 100644
index 0000000..0b9e78e
Binary files /dev/null and b/cpu/br28/tools/eq_cfg_hw_vbass.bin differ
diff --git a/cpu/br28/tools/eq_game_eff.bin b/cpu/br28/tools/eq_game_eff.bin
new file mode 100644
index 0000000..0748376
Binary files /dev/null and b/cpu/br28/tools/eq_game_eff.bin differ
diff --git a/cpu/br28/tools/extra_tones/0.wts b/cpu/br28/tools/extra_tones/0.wts
new file mode 100644
index 0000000..562a6e5
Binary files /dev/null and b/cpu/br28/tools/extra_tones/0.wts differ
diff --git a/cpu/br28/tools/extra_tones/power_on.wts b/cpu/br28/tools/extra_tones/power_on.wts
new file mode 100644
index 0000000..7f7f02b
Binary files /dev/null and b/cpu/br28/tools/extra_tones/power_on.wts differ
diff --git a/cpu/br28/tools/fw_add b/cpu/br28/tools/fw_add
new file mode 100644
index 0000000..6aa600e
Binary files /dev/null and b/cpu/br28/tools/fw_add differ
diff --git a/cpu/br28/tools/fw_add.exe b/cpu/br28/tools/fw_add.exe
new file mode 100644
index 0000000..958d972
Binary files /dev/null and b/cpu/br28/tools/fw_add.exe differ
diff --git a/cpu/br28/tools/isd_config.ini b/cpu/br28/tools/isd_config.ini
new file mode 100644
index 0000000..a3be0ba
--- /dev/null
+++ b/cpu/br28/tools/isd_config.ini
@@ -0,0 +1,81 @@
+
+
+
+[EXTRA_CFG_PARAM]
+
+BR22_TWS_DB = YES;
+FLASH_SIZE = 0x100000;
+BR22_TWS_VERSION = 0;
+FORCE_4K_ALIGN = YES;
+SPECIAL_OPT = 0;
+
+DB_UPDATE_DATA = YES;
+CHIP_NAME = AC701N;
+ENTRY = 0x6000100;
+PID = AC701N;
+VID = 0.01;
+
+SDK_VERSION = JL701N_V1.6.1;
+
+RESERVED_OPT = 0;
+
+UFW_ELEMENT = 0x10 - 0x0, 0x1 - 0x0;
+
+DOWNLOAD_MODEL = USB;
+SERIAL_DEVICE_NAME = JlVirtualJtagSerial;
+SERIAL_BARD_RATE = 1000000;
+SERIAL_CMD_OPT = 2;
+SERIAL_CMD_RATE = 100;
+SERIAL_CMD_RES = 0;
+SERIAL_INIT_BAUD_RATE = 9600;
+LOADER_BAUD_RATE = 1000000;
+LOADER_ASK_BAUD_RATE = 1000000;
+BEFORE_LOADER_WAIT_TIME = 150;
+SERIAL_SEND_KEY = YES;
+
+
+
+
+
+
+[CHIP_VERSION]
+SUPPORTED_LIST = P, B;
+
+[SYS_CFG_PARAM]
+SPI = 2_3_0_0;
+
+
+
+
+
+
+UTTX = PB02;
+UTBD = 1000000;
+UTRX = -1;
+
+
+
+
+
+RESET1 = PB01_16_0;
+
+
+
+VLVD = 3;
+[FW_ADDITIONAL]
+FILE_LIST = (file = ota.bin: type = 100);
+[RESERVED_CONFIG]
+BTIF_ADR = AUTO;
+BTIF_LEN = 0x1000;
+BTIF_OPT = 1;
+PRCT_ADR = 0;
+PRCT_LEN = CODE_LEN;
+PRCT_OPT = 2;
+
+
+
+VM_ADR = 0;
+VM_LEN = 8K;
+VM_OPT = 1;
+[BURNER_CONFIG]
+SIZE = 32;
diff --git a/cpu/br28/tools/isd_config_rule.c b/cpu/br28/tools/isd_config_rule.c
new file mode 100644
index 0000000..dba8ea9
--- /dev/null
+++ b/cpu/br28/tools/isd_config_rule.c
@@ -0,0 +1,431 @@
+#include "board_config.h"
+
+
+#define _CAT2(a,b) a ## _ ## b
+#define CAT2(a,b) _CAT2(a,b)
+
+#define _CAT3(a,b,c) a ## _ ## b ## _ ## c
+#define CAT3(a,b,c) _CAT3(a,b,c)
+
+#define _CAT4(a,b,c,d) a ## _ ## b ## _ ## c ## _ ## d
+#define CAT4(a,b,c,d) _CAT4(a,b,c,d)
+
+#ifndef CONFIG_DOWNLOAD_MODEL
+#define CONFIG_DOWNLOAD_MODEL USB //下载模式选择,可选配置USB\SERIAL
+#endif
+
+#ifndef CONFIG_DEVICE_NAME
+#define CONFIG_DEVICE_NAME JlVirtualJtagSerial //串口通讯的设备名(配置串口通讯时使用)
+#endif
+
+#ifndef CONFIG_SERIAL_BAUD_RATE
+#define CONFIG_SERIAL_BAUD_RATE 1000000 //串口通讯的波特率(配置串口通讯时使用)
+#endif
+
+#ifndef CONFIG_SERIAL_CMD_OPT
+#define CONFIG_SERIAL_CMD_OPT 2 //串口通讯公共配置参数(配置串口通讯时使用)
+#endif
+
+#ifndef CONFIG_SERIAL_CMD_RATE
+#define CONFIG_SERIAL_CMD_RATE 100 //串口通讯时公共配置参数(配置串口通讯时使用)[n*10000]
+#endif
+
+#ifndef CONFIG_SERIAL_CMD_RES
+#define CONFIG_SERIAL_CMD_RES 0 //串口通讯时公共配置参数(配置串口通讯时使用)
+#endif
+
+#ifndef CONFIG_SERIAL_INIT_BAUD_RATE
+#define CONFIG_SERIAL_INIT_BAUD_RATE 9600 //串口通信初始化时通讯的波特率(配置串口通讯时使用)
+#endif
+
+#ifndef CONFIG_LOADER_BAUD_RATE
+#define CONFIG_LOADER_BAUD_RATE 1000000 //写入loader文件时通讯的波特率(配置串口通讯时使用)
+#endif
+
+#ifndef CONFIG_LOADER_ASK_BAUD_RATE
+#define CONFIG_LOADER_ASK_BAUD_RATE 1000000
+#endif
+#ifndef CONFIG_SERIAL_SEND_KEY
+#define CONFIG_SERIAL_SEND_KEY YES //SERIAL_SEND_KEY:串口交互时数据是否需要进行加密(配置串口通讯时使用,有效值:YES)
+#endif
+
+#ifndef CONFIG_BREFORE_LOADER_WAIT_TIME
+#define CONFIG_BREFORE_LOADER_WAIT_TIME 150 //写入loader前延时时间(配置串口通讯时使用)
+#endif
+
+#ifndef CONFIG_ENTRY_ADDRESS
+#define CONFIG_ENTRY_ADDRESS 0x6000120 //程序入口地址,一般不需要修改(跟张恺讨论过把RESERVED_OPT=0合并到一个配置项)
+#endif
+
+
+/* #ifndef CONFIG_SDK_TYPE */
+/* #define CONFIG_SDK_TYPE SOUNDBOX // SOUNDBOX:音箱方案 OTHER:其他方案(比如:耳机,BLE) SDK类型:当前仅支持音箱和非音箱两种类型 */
+/* #endif */
+
+#ifndef CONFIG_SPI_DATA_WIDTH
+#define CONFIG_SPI_DATA_WIDTH 2 //data_width[0 1 2 3 4] 3的时候uboot自动识别2或者4线
+#endif
+
+#ifndef CONFIG_SPI_CLK_DIV
+#define CONFIG_SPI_CLK_DIV 3 //clk [0-255]
+#endif
+
+//mode:
+// 0 RD_OUTPUT, 1 cmd 1 addr
+// 1 RD_I/O, 1 cmd x addr
+// 2 RD_I/O_CONTINUE] no_send_cmd x add
+#ifndef CONFIG_SPI_MODE
+#define CONFIG_SPI_MODE 0
+#endif
+//port:
+// 0 优先选A端口 CS:PD3 CLK:PD0 D0:PD1 D1:PD2 D2:PB7 D3:PD5
+// 1 优先选B端口 CS:PA13 CLK:PD0 D0:PD1 D1:PA14 D2:PA15 D3:PD5
+#ifndef CONFIG_SPI_PORT
+#define CONFIG_SPI_PORT 0
+#endif
+
+//uboot and ota.bin串口tx
+#ifndef CONFIG_UBOOT_DEBUG_PIN
+#define CONFIG_UBOOT_DEBUG_PIN PB02
+#endif
+
+//uboot and ota.bin串口波特率[EXTRA_CFG_PARAM]
+#ifndef CONFIG_UBOOT_DEBUG_BAUD_RATE
+#define CONFIG_UBOOT_DEBUG_BAUD_RATE 1000000
+#endif
+
+[EXTRA_CFG_PARAM]
+#if CONFIG_DOUBLE_BANK_ENABLE
+BR22_TWS_DB = YES; //dual bank flash framework enable
+FLASH_SIZE = CONFIG_FLASH_SIZE; //flash_size cfg
+BR22_TWS_VERSION = 0; //default fw version
+FORCE_4K_ALIGN = YES; // force aligin with 4k bytes
+SPECIAL_OPT = 0; // only generate one flash.bin
+#if CONFIG_DB_UPDATE_DATA_GENERATE_EN
+DB_UPDATE_DATA = YES; //generate db_update_data.bin
+#endif
+#else
+NEW_FLASH_FS = YES; //enable single bank flash framework
+#endif //CONFIG_DOUBLE_BANK_ENABLE
+
+#if ALIGN_UNIT_256B
+AREA_ALIGN = ALIGN_UNIT_256B; //using n*256B unit for boundary alignment
+#endif
+
+CHIP_NAME = CONFIG_CHIP_NAME;
+ENTRY = CONFIG_ENTRY_ADDRESS;
+PID = CONFIG_PID;
+VID = CONFIG_VID;
+
+SDK_VERSION = JL701N_V1.6.1; //jenkins脚本生成
+
+RESERVED_OPT = 0;
+
+UFW_ELEMENT = 0x10 - 0x0, 0x1 - 0x0;
+
+DOWNLOAD_MODEL = CONFIG_DOWNLOAD_MODEL; //
+SERIAL_DEVICE_NAME = CONFIG_DEVICE_NAME;
+SERIAL_BARD_RATE = CONFIG_SERIAL_BAUD_RATE;
+SERIAL_CMD_OPT = CONFIG_SERIAL_CMD_OPT;
+SERIAL_CMD_RATE = CONFIG_SERIAL_CMD_RATE;
+SERIAL_CMD_RES = CONFIG_SERIAL_CMD_RES;
+SERIAL_INIT_BAUD_RATE = CONFIG_SERIAL_INIT_BAUD_RATE;
+LOADER_BAUD_RATE = CONFIG_LOADER_BAUD_RATE;
+LOADER_ASK_BAUD_RATE = CONFIG_LOADER_ASK_BAUD_RATE;
+BEFORE_LOADER_WAIT_TIME = CONFIG_BREFORE_LOADER_WAIT_TIME;
+SERIAL_SEND_KEY = CONFIG_SERIAL_SEND_KEY;
+
+#if CONFIG_ANC_ENABLE
+COMPACT_SETTING = YES;
+#endif
+
+// #####匹配的芯片版本,请勿随意改动######
+[CHIP_VERSION]
+SUPPORTED_LIST = P, B;
+
+[SYS_CFG_PARAM]
+SPI = CAT4(CONFIG_SPI_DATA_WIDTH, CONFIG_SPI_CLK_DIV, CONFIG_SPI_MODE, CONFIG_SPI_PORT); //width_clk_mode_port;
+
+#if (CONFIG_PLL_SOURCE_USING_LRC == 1)
+PLL_SRC = LRC; //PLL时钟源:屏蔽或!=LRC; 默认选择晶振。 值=LRC,且用no_ota_uboot,则时钟源选LRC
+#endif
+
+#ifdef CONFIG_UBOOT_DEBUG_PIN
+UTTX = CONFIG_UBOOT_DEBUG_PIN; //uboot串口tx
+UTBD = CONFIG_UBOOT_DEBUG_BAUD_RATE; //uboot串口波特率
+#endif
+
+//外部FLASH 硬件连接配置
+#ifdef CONFIG_EXTERN_FLASH_SIZE
+EX_FLASH = PC03_1A_PC08; //CS_pin / spi (0/1/2) /port(A/B) / power_io
+EX_FLASH_IO = 2_PC01_PC02_PC04_PC05_PC00; //data_width / CLK_pin / DO_pin / DI_pin / D2_pin / D3_pin 当data_width为4的时候,D2_pin和D3_pin才有效
+#endif
+/* #0:disable */
+/* #1:PA9 PA10 */
+/* #2:USB */
+/* #3:PB1 PB2 */
+/* #4:PB6 PB7 */
+
+/* #sdtap=2; */
+
+/* #enable: */
+/* # 0: uboot 不初始化psram; */
+/* # 1: uboot 初始化psram */
+/* #mode: */
+/* # 0: 1线模式; */
+/* # 1: 4线模式0, 命令1线, 地址4线, 数据4线, */
+/* # 2: 4线模式1, 命令4线, 地址4线, 数据4线, */
+/* #div: */
+/* # 1分频, 192M, div = 0; */
+/* # 2分频, 96M, div = 4; */
+/* # 3分频, 64M, div = 1; */
+/* # 4分频, 48M, div = 8; */
+/* # 5分频, 38.4M, div = 2; */
+/* # 6分频, 32M, div = 5; */
+/* # 7分频, 27.4M, div = 3; */
+/* # 8分频, 24M, div = C; */
+/* # 10分频, 19.2M, div = 6; */
+/* # 12分频, 16M, div = 9; */
+/* # 14分频, 13.7M, div = 7; */
+/* # 20分频, 9.6M, div = A; */
+/* # 24分频, 8M, div = D; */
+/* # 28分频, 6.8M, div = B; */
+/* # 40分频, 4.8M, div = E; */
+/* # 56分频, 3.4M, div = F; */
+//#enable_mode_div
+#ifdef CONFIG_PSRAM_ENABLE
+PSRAM = 1_2_A;
+#endif
+
+
+#ifdef CONFIG_UART_UPDATE_PIN
+UTRX = CONFIG_UART_UPDATE_PIN; //串口升级[PB00 PB05 PA05]
+#endif
+
+/* RESET = CAT3(CONFIG_RESET_PIN, CONFIG_RESET_TIME, CONFIG_RESET_LEVEL); //port口_长按时间_有效电平(长按时间有00、01、02、04、08三个值可选,单位为秒,当长按时间为00时,则关闭长按复位功能。) */
+
+#ifdef CONFIG_SUPPORT_RESET1
+RESET1 = CAT3(CONFIG_RESET1_PIN, CONFIG_RESET1_TIME, CONFIG_RESET1_LEVEL); //port口_长按时间_有效电平(长按时间有00、01、02、04、08三个值可选,单位为秒,当长按时间为00时,则关闭长按复位功能。)
+#endif
+
+#ifdef CONFIG_VDDIO_LVD_LEVEL
+VLVD = CONFIG_VDDIO_LVD_LEVEL; //VDDIO_LVD挡位,0: 1.8V 1: 1.9V 2: 2.0V 3: 2.1V 4: 2.2V 5: 2.3V 6: 2.4V 7: 2.5V
+#endif
+
+/* #ifdef CONFIG_UPDATE_JUMP_TO_MASK */
+/* UPDATE_JUMP = CONFIG_UPDATE_JUMP_TO_MASK; */
+/* #endif */
+
+#ifdef CONFIG_CUSTOM_CFG1_TYPE
+CONFIG_CUSTOM_CFG1_TYPE = CONFIG_CUSTOM_CFG1_VALUE;
+#endif
+#ifdef CONFIG_CUSTOM_CFG2_TYPE
+CONFIG_CUSTOM_CFG2_TYPE = CONFIG_CUSTOM_CFG2_VALUE;
+#endif
+#ifdef CONFIG_CUSTOM_CFG3_TYPE
+CONFIG_CUSTOM_CFG3_TYPE = CONFIG_CUSTOM_CFG3_VALUE;
+#endif
+
+//#############################################################################################################################################
+
+#ifndef CONFIG_VM_ADDR
+#define CONFIG_VM_ADDR 0
+#endif
+
+#ifndef CONFIG_VM_LEAST_SIZE
+#if ALIGN_UNIT_256B
+#define CONFIG_VM_LEAST_SIZE 0x200
+#else
+#define CONFIG_VM_LEAST_SIZE 32K
+#endif
+#endif
+
+#ifndef CONFIG_VM_OPT
+#define CONFIG_VM_OPT 1
+#endif
+
+#ifndef CONFIG_BTIF_ADDR
+#define CONFIG_BTIF_ADDR AUTO
+#endif
+
+#ifndef CONFIG_BTIF_LEN
+#if ALIGN_UNIT_256B
+#define CONFIG_BTIF_LEN 0x200
+#else
+#define CONFIG_BTIF_LEN 0x1000
+#endif
+#endif
+
+#ifndef CONFIG_BTIF_OPT
+#define CONFIG_BTIF_OPT 1
+#endif
+
+#ifndef CONFIG_PRCT_ADDR
+#define CONFIG_PRCT_ADDR 0
+#endif
+
+#ifndef CONFIG_PRCT_LEN
+#define CONFIG_PRCT_LEN CODE_LEN
+#endif
+
+#ifndef CONFIG_PRCT_OPT
+#define CONFIG_PRCT_OPT 2
+#endif
+
+#ifndef CONFIG_EXIF_ADDR
+#define CONFIG_EXIF_ADDR AUTO
+#endif
+
+#ifndef CONFIG_EXIF_LEN
+#define CONFIG_EXIF_LEN 0x1000
+#endif
+
+#ifndef CONFIG_EXIF_OPT
+#define CONFIG_EXIF_OPT 1
+#endif
+
+#ifndef CONIFG_BURNER_INFO_SIZE
+#define CONFIG_BURNER_INFO_SIZE 32
+#endif
+
+[FW_ADDITIONAL]
+FILE_LIST = (file = ota.bin: type = 100);
+
+// ########flash空间使用配置区域###############################################
+// #PDCTNAME: 产品名,对应此代码,用于标识产品,升级时可以选择匹配产品名
+// #BOOT_FIRST: 1=代码更新后,提示APP是第一次启动;0=代码更新后,不提示
+// #UPVR_CTL: 0:不允许高版本升级低版本 1:允许高版本升级低版本
+// #XXXX_ADR: 区域起始地址 AUTO:由工具自动分配起始地址
+// #XXXX_LEN: 区域长度 CODE_LEN:代码长度
+// #XXXX_OPT: 区域操作属性
+// #
+// #
+// #
+// #操作符说明 OPT:
+// # 0: 下载代码时擦除指定区域
+// # 1: 下载代码时不操作指定区域
+// # 2: 下载代码时给指定区域加上保护
+// ############################################################################
+[RESERVED_CONFIG]
+BTIF_ADR = CONFIG_BTIF_ADDR;
+BTIF_LEN = CONFIG_BTIF_LEN;
+BTIF_OPT = CONFIG_BTIF_OPT;
+
+#if (CONFIG_APP_OTA_ENABLE && !CONFIG_DOUBLE_BANK_ENABLE)
+EXIF_ADR = CONFIG_EXIF_ADDR;
+EXIF_LEN = CONFIG_EXIF_LEN;
+EXIF_OPT = CONFIG_EXIF_OPT;
+#endif
+
+// #WTIF_ADR=BEGIN_END;
+// #WTIF_LEN=0x1000;
+// #WTIF_OPT=1;
+
+//forprotect area cfg
+PRCT_ADR = CONFIG_PRCT_ADDR;
+PRCT_LEN = CONFIG_PRCT_LEN;
+PRCT_OPT = CONFIG_PRCT_OPT;
+
+//for volatile memory area cfg
+//VM大小默认为CONFIG_VM_LEAST_SIZE,如果代码空间不够可以适当改小,需要满足4*2*n; 改小可能会导致不支持测试盒蓝牙升级(不影响串口升级)
+VM_ADR = CONFIG_VM_ADDR;
+VM_LEN = CONFIG_VM_LEAST_SIZE;
+VM_OPT = CONFIG_VM_OPT;
+
+#ifdef CONFIG_RESERVED_AREA1
+CAT2(CONFIG_RESERVED_AREA1, ADR) = CONFIG_RESERVED_AREA1_ADDR;
+CAT2(CONFIG_RESERVED_AREA1, LEN) = CONFIG_RESERVED_AREA1_LEN;
+CAT2(CONFIG_RESERVED_AREA1, OPT) = CONFIG_RESERVED_AREA1_OPT;
+
+#ifdef CONFIG_RESERVED_AREA1_FILE
+CAT2(CONFIG_RESERVED_AREA1, FILE) = CONFIG_RESERVED_AREA1_FILE;
+#endif
+
+#endif
+
+#ifdef CONFIG_RESERVED_AREA2
+CAT2(CONFIG_RESERVED_AREA2, ADR) = CONFIG_RESERVED_AREA2_ADDR;
+CAT2(CONFIG_RESERVED_AREA2, LEN) = CONFIG_RESERVED_AREA2_LEN;
+CAT2(CONFIG_RESERVED_AREA2, OPT) = CONFIG_RESERVED_AREA2_OPT;
+
+#ifdef CONFIG_RESERVED_AREA2_FILE
+CAT2(CONFIG_RESERVED_AREA2, FILE) = CONFIG_RESERVED_AREA2_FILE;
+#endif
+
+#endif
+#if TCFG_EQ_ONLINE_ENABLE || TCFG_MIC_EFFECT_ONLINE_ENABLE
+EFFECT_ADR = AUTO;
+EFFECT_LEN = 4K;
+EFFECT_OPT = 1;
+#endif
+
+/*
+ ****************************************************************************
+ * ANC配置区
+ *Notes:
+ *(1)需要根据flash容量手动配置ANC配置区起始地址:
+ * 4Mbit:0x7E000 8Mbit:0xFE000 16Mbit:0x1FE000
+ *(2)加载ANC增益/系数配置文件,则表示使用配置文件的增益/系数配置
+ *(3)ANC两个配置区是连续的,即第一个配置区起始地址加上自身长度,即为第二个配置
+ * 区起始地址:CONFIG_ANCIF1_ADDR = CONFIG_ANCIF_ADDR + CONFIG_ANCIF_LEN
+ *****************************************************************************
+ */
+#if CONFIG_ANC_ENABLE
+
+/*******************用户配置区************************/
+//加载ANC增益配置文件使能
+#define CONFIG_ANCIF_GAINS_FILE_ENABLE 1
+//加载ANC系数配置文件使能
+#define CONFIG_ANCIF1_COEFF_FILE_ENABLE 1
+
+//ANC配置区起始地址配置(跟进芯片flash容量进行配置)
+//4Mbit:0x7E000 8Mbit:0xFE000 16Mbit:0x1FE000
+#ifndef CONFIG_ANCIF_ADDR
+#define CONFIG_ANCIF_ADDR 0xFD000
+#endif/*CONFIG_ANCIF_ADDR*/
+#ifndef CONFIG_ANCIF1_ADDR
+#define CONFIG_ANCIF1_ADDR 0xFD100
+#endif/*CONFIG_ANCIF1_ADDR*/
+
+//ANC配置区下载操作配置
+#ifndef CONFIG_ANCIF_OPT
+#define CONFIG_ANCIF_OPT 1
+#endif
+#ifndef CONFIG_ANCIF1_OPT
+#define CONFIG_ANCIF1_OPT 1
+#endif
+/*******************用户配置区************************/
+
+
+/*******************非用户配置区**********************/
+//ANC配置区长度定义
+#define CONFIG_ANCIF_LEN 0x100
+/* #if ANC_MAX_ORDER > 10 */
+#define CONFIG_ANCIF1_LEN 0x1F00
+/* #else */
+/* #define CONFIG_ANCIF1_LEN 0xF00 */
+/* #endif#<{(|ANC_MAX_ORDER > 10 |)}># */
+
+//ANC系数配置保留区0
+#if CONFIG_ANCIF_GAINS_FILE_ENABLE
+ANCIF_FILE = anc_gains.bin;
+#endif
+ANCIF_ADR = CONFIG_ANCIF_ADDR;
+ANCIF_LEN = CONFIG_ANCIF_LEN;
+ANCIF_OPT = CONFIG_ANCIF_OPT;
+
+//ANC系数配置保留区1
+#if CONFIG_ANCIF1_COEFF_FILE_ENABLE
+ANCIF1_FILE = anc_coeff.bin;
+#endif
+ANCIF1_ADR = CONFIG_ANCIF1_ADDR;
+ANCIF1_LEN = CONFIG_ANCIF1_LEN;
+ANCIF1_OPT = CONFIG_ANCIF1_OPT;
+/*******************非用户配置区**********************/
+#endif/*CONFIG_ANC_ENABLE*/
+
+[BURNER_CONFIG]
+SIZE = CONFIG_BURNER_INFO_SIZE;
+
+
+
diff --git a/cpu/br28/tools/isd_download b/cpu/br28/tools/isd_download
new file mode 100644
index 0000000..ed5e725
Binary files /dev/null and b/cpu/br28/tools/isd_download differ
diff --git a/cpu/br28/tools/isd_download.exe b/cpu/br28/tools/isd_download.exe
new file mode 100644
index 0000000..4b5cc43
Binary files /dev/null and b/cpu/br28/tools/isd_download.exe differ
diff --git a/cpu/br28/tools/ota.bin b/cpu/br28/tools/ota.bin
new file mode 100644
index 0000000..6850dec
Binary files /dev/null and b/cpu/br28/tools/ota.bin differ
diff --git a/cpu/br28/tools/ota_debug.bin b/cpu/br28/tools/ota_debug.bin
new file mode 100644
index 0000000..6f0d014
Binary files /dev/null and b/cpu/br28/tools/ota_debug.bin differ
diff --git a/cpu/br28/tools/p11_code.bin b/cpu/br28/tools/p11_code.bin
new file mode 100644
index 0000000..3ee174f
Binary files /dev/null and b/cpu/br28/tools/p11_code.bin differ
diff --git a/cpu/br28/tools/rom.lst b/cpu/br28/tools/rom.lst
new file mode 100644
index 0000000..f4556a9
--- /dev/null
+++ b/cpu/br28/tools/rom.lst
@@ -0,0 +1,36858 @@
+
+rom.exe: file format ELF32-pi32v2
+
+Disassembly of section .rom_code:
+_start:
+ 0: c0 ea 8e 50 goto 0xa11c <_startup : a120 > ## startup.S:34:0
+
+
+WOLAAnalysisFilter_Float_M64_m4_r1:
+ 4: 00 00 00 00 4a 9f c4 38 ....J..8
+ c: b4 54 06 39 be 55 30 39 .T.9.U09
+ 14: 4b cc 60 39 b5 18 8c 39 K.`9...9
+ 1c: 56 7e ab 39 79 d1 ce 39 V~.9y..9
+ 24: b6 4a f6 39 0f 10 11 3a .J.9...:
+ 2c: 57 42 29 3a c2 d3 43 3a WB):..C:
+ 34: ab d9 60 3a 66 33 80 3a ..`:f3.:
+ 3c: 7c 45 91 3a 46 a9 a3 3a |E.:F..:
+ 44: 37 63 b7 3a 98 75 cc 3a 7c.:.u.:
+ 4c: 9c e0 e2 3a ea a1 fa 3a ...:...:
+ 54: 5b da 09 3b a8 08 17 3b [..;...;
+ 5c: 97 d6 24 3b 51 3d 33 3b ..$;Q=3;
+ 64: 58 34 42 3b 81 b1 51 3b X4B;..Q;
+ 6c: db a8 61 3b 91 0c 72 3b ..a;..r;
+ 74: 78 66 81 3b 2c ec 89 3b xf.;,..;
+ 7c: 92 8d 92 3b d5 3f 9b 3b ...;.?.;
+ 84: 18 f7 a3 3b 7a a6 ac 3b ...;z..;
+ 8c: 13 40 b5 3b ec b4 bd 3b .@.;...;
+ 94: 0f f5 c5 3b 82 ef cd 3b ...;...;
+ 9c: 50 92 d5 3b 8f ca dc 3b P..;...;
+ a4: 67 84 e3 3b 1d ab e9 3b g..;...;
+ ac: 21 29 ef 3b 18 e8 f3 3b !).;...;
+ b4: ec d0 f7 3b d9 cb fa 3b ...;...;
+ bc: 8e c0 fc 3b 2a 96 fd 3b ...;*..;
+ c4: 63 33 fd 3b 93 7e fb 3b c3.;.~.;
+ cc: d9 5d f8 3b 29 b7 f3 3b .].;)..;
+ d4: 6a 70 ed 3b 93 6f e5 3b jp.;.o.;
+ dc: ca 9a db 3b 7b d8 cf 3b ...;{..;
+ e4: 7c 0f c2 3b 29 27 b2 3b |..;)'.;
+ ec: 87 07 a0 3b 66 99 8b 3b ...;f..;
+ f4: e6 8c 69 3b e0 f2 36 3b ..i;..6;
+ fc: fd 78 fe 3a 43 88 84 3a .x.:C..:
+ 104: 00 00 00 00 8a f5 8f ba ........
+ 10c: 7c 7d 15 bb 18 ba 68 bb |}....h.
+ 114: de e2 a0 bb c6 58 d0 bb .....X..
+ 11c: a3 62 01 bc 52 16 1c bc .b..R...
+ 124: 71 48 38 bc db f8 55 bc qH8...U.
+ 12c: 28 26 75 bc d9 e6 8a bc (&u.....
+ 134: ca f5 9b bc 42 bd ad bc ....B...
+ 13c: 07 3a c0 bc 1c 68 d3 bc .:...h..
+ 144: e5 42 e7 bc 1d c5 fb bc .B......
+ 14c: 63 74 08 bd 9f 53 13 bd ct...S..
+ 154: 9b 7c 1e bd 5c eb 29 bd .|..\.).
+ 15c: 98 9b 35 bd ae 88 41 bd ..5...A.
+ 164: b3 ad 4d bd 72 05 5a bd ..M.r.Z.
+ 16c: 6e 8a 66 bd df 36 73 bd n.f..6s.
+ 174: 61 02 80 bd ec 76 86 bd a....v..
+ 17c: d1 f5 8c bd ba 7b 93 bd .....{..
+ 184: 37 05 9a bd c6 8e a0 bd 7.......
+ 18c: d1 14 a7 bd b2 93 ad bd ........
+ 194: ba 07 b4 bd 2a 6d ba bd ....*m..
+ 19c: 47 c0 c0 bd 4c fd c6 bd G...L...
+ 1a4: 6d 20 cd bd fd 25 d3 bd m ...%..
+ 1ac: 35 0a d9 bd 69 c9 de bd 5...i...
+ 1b4: fc 5f e4 bd 5c ca e9 bd ._..\...
+ 1bc: 13 05 ef bd ad 0c f4 bd ........
+ 1c4: f5 dd f8 bd ac 75 fd bd .....u..
+ 1cc: 6b e8 00 be 40 f6 02 be k...@...
+ 1d4: fa e2 04 be 49 ad 06 be ....I...
+ 1dc: f0 53 08 be de d5 09 be .S......
+ 1e4: 05 32 0b be 75 67 0c be .2..ug..
+ 1ec: 55 75 0d be f2 5a 0e be Uu...Z..
+ 1f4: a3 17 0f be f6 aa 0f be ........
+ 1fc: 79 14 10 be e3 53 10 be y....S..
+ 204: 0b 69 10 be e3 53 10 be .i...S..
+ 20c: 79 14 10 be f6 aa 0f be y.......
+ 214: a3 17 0f be f2 5a 0e be .....Z..
+ 21c: 55 75 0d be 75 67 0c be Uu..ug..
+ 224: 05 32 0b be de d5 09 be .2......
+ 22c: f0 53 08 be 49 ad 06 be .S..I...
+ 234: fa e2 04 be 40 f6 02 be ....@...
+ 23c: 6b e8 00 be ac 75 fd bd k....u..
+ 244: f5 dd f8 bd ad 0c f4 bd ........
+ 24c: 13 05 ef bd 5c ca e9 bd ....\...
+ 254: fc 5f e4 bd 69 c9 de bd ._..i...
+ 25c: 35 0a d9 bd fd 25 d3 bd 5....%..
+ 264: 6d 20 cd bd 4c fd c6 bd m ..L...
+ 26c: 47 c0 c0 bd 2a 6d ba bd G...*m..
+ 274: ba 07 b4 bd b2 93 ad bd ........
+ 27c: d1 14 a7 bd c6 8e a0 bd ........
+ 284: 37 05 9a bd ba 7b 93 bd 7....{..
+ 28c: d1 f5 8c bd ec 76 86 bd .....v..
+ 294: 61 02 80 bd df 36 73 bd a....6s.
+ 29c: 6e 8a 66 bd 72 05 5a bd n.f.r.Z.
+ 2a4: b3 ad 4d bd ae 88 41 bd ..M...A.
+ 2ac: 98 9b 35 bd 5c eb 29 bd ..5.\.).
+ 2b4: 9b 7c 1e bd 9f 53 13 bd .|...S..
+ 2bc: 63 74 08 bd 1d c5 fb bc ct......
+ 2c4: e5 42 e7 bc 1c 68 d3 bc .B...h..
+ 2cc: 07 3a c0 bc 42 bd ad bc .:..B...
+ 2d4: ca f5 9b bc d9 e6 8a bc ........
+ 2dc: 28 26 75 bc db f8 55 bc (&u...U.
+ 2e4: 71 48 38 bc 52 16 1c bc qH8.R...
+ 2ec: a3 62 01 bc c6 58 d0 bb .b...X..
+ 2f4: de e2 a0 bb 18 ba 68 bb ......h.
+ 2fc: 7c 7d 15 bb 8a f5 8f ba |}......
+ 304: 00 00 00 00 43 88 84 3a ....C..:
+ 30c: fd 78 fe 3a e0 f2 36 3b .x.:..6;
+ 314: e6 8c 69 3b 66 99 8b 3b ..i;f..;
+ 31c: 87 07 a0 3b 29 27 b2 3b ...;)'.;
+ 324: 7c 0f c2 3b 7b d8 cf 3b |..;{..;
+ 32c: ca 9a db 3b 93 6f e5 3b ...;.o.;
+ 334: 6a 70 ed 3b 29 b7 f3 3b jp.;)..;
+ 33c: d9 5d f8 3b 93 7e fb 3b .].;.~.;
+ 344: 63 33 fd 3b 2a 96 fd 3b c3.;*..;
+ 34c: 8e c0 fc 3b d9 cb fa 3b ...;...;
+ 354: ec d0 f7 3b 18 e8 f3 3b ...;...;
+ 35c: 21 29 ef 3b 1d ab e9 3b !).;...;
+ 364: 67 84 e3 3b 8f ca dc 3b g..;...;
+ 36c: 50 92 d5 3b 82 ef cd 3b P..;...;
+ 374: 0f f5 c5 3b ec b4 bd 3b ...;...;
+ 37c: 13 40 b5 3b 7a a6 ac 3b .@.;z..;
+ 384: 18 f7 a3 3b d5 3f 9b 3b ...;.?.;
+ 38c: 92 8d 92 3b 2c ec 89 3b ...;,..;
+ 394: 78 66 81 3b 91 0c 72 3b xf.;..r;
+ 39c: db a8 61 3b 81 b1 51 3b ..a;..Q;
+ 3a4: 58 34 42 3b 51 3d 33 3b X4B;Q=3;
+ 3ac: 97 d6 24 3b a8 08 17 3b ..$;...;
+ 3b4: 5b da 09 3b ea a1 fa 3a [..;...:
+ 3bc: 9c e0 e2 3a 98 75 cc 3a ...:.u.:
+ 3c4: 37 63 b7 3a 46 a9 a3 3a 7c.:F..:
+ 3cc: 7c 45 91 3a 66 33 80 3a |E.:f3.:
+ 3d4: ab d9 60 3a c2 d3 43 3a ..`:..C:
+ 3dc: 57 42 29 3a 0f 10 11 3a WB):...:
+ 3e4: b6 4a f6 39 79 d1 ce 39 .J.9y..9
+ 3ec: 56 7e ab 39 b5 18 8c 39 V~.9...9
+ 3f4: 4b cc 60 39 be 55 30 39 K.`9.U09
+ 3fc: b4 54 06 39 4a 9f c4 38 .T.9J..8
+
+
+WOLASynthesisFilter_Float_M64_m4_r1:
+ 404: c6 52 a3 3c 7b 1b f6 3c .R.<{..<
+ 40c: 18 98 22 3d c8 00 48 3d .."=..H=
+ 414: a3 02 6b 3d d3 ad 85 3d ..k=...=
+ 41c: c7 66 94 3d 27 8f a1 3d .f.='..=
+ 424: 55 0c ad 3d 64 c6 b6 3d U..=d..=
+ 42c: 57 a8 be 3d 4f a0 c4 3d W..=O..=
+ 434: d4 9f c8 3d 06 9c ca 3d ...=...=
+ 43c: c0 8d ca 3d c4 71 c8 3d ...=.q.=
+ 444: e8 48 c4 3d 21 18 be 3d .H.=!..=
+ 44c: a0 e8 b5 3d db c7 ab 3d ...=...=
+ 454: 98 c7 9f 3d e4 fd 91 3d ...=...=
+ 45c: 10 85 82 3d 23 f7 62 3d ...=#.b=
+ 464: eb 07 3e 3d 6f 89 16 3d ..>=o..=
+ 46c: 60 a0 d9 3c a7 6f 82 3c `..<.o.<
+ 474: 2a 15 a1 3b 27 37 d0 bb *..;'7..
+ 47c: 8d ad 91 bc 91 fb ec bc ........
+ 484: 58 8b 9c bd 86 34 df bd X....4..
+ 48c: 18 d3 0f be d1 ab 2e be ........
+ 494: 07 e1 4b be cd 30 67 be ..K..0g.
+ 49c: 9a 2d 80 be 74 91 8b be .-..t...
+ 4a4: c2 a6 95 be 23 52 9e be ....#R..
+ 4ac: 43 7a a5 be 00 08 ab be Cz......
+ 4b4: e0 e6 ae be 01 05 b1 be ........
+ 4bc: 95 53 b1 be d4 c6 af be .S......
+ 4c4: 6a 56 ac be 6c fd a6 be jV..l...
+ 4cc: 96 ba 9f be 76 90 96 be ....v...
+ 4d4: 6f 85 8b be ab 47 7d be o....G}.
+ 4dc: 20 f4 5f be 1a 35 3f be ._..5?.
+ 4e4: 86 37 1b be 12 61 e8 bd .7...a..
+ 4ec: 85 ba 94 bd d8 15 f0 bc ........
+ 4f4: 61 92 84 3c 2f 1b 82 3d a..
+ 504: ca da 83 3e 42 28 ae 3e ...>B(.>
+ 50c: 78 ec d7 3e 20 68 00 3f x..> h.?
+ 514: 8a 3d 14 3f b6 49 27 3f .=.?.I'?
+ 51c: ba 5f 39 3f b3 52 4a 3f ._9?.RJ?
+ 524: 2d f6 59 3f 45 1e 68 3f -.Y?E.h?
+ 52c: 08 a0 74 3f bd 51 7f 3f ..t?.Q.?
+ 534: 8a 05 84 3f d2 52 87 3f ...?.R.?
+ 53c: 5f 7e 89 3f 25 77 8a 3f _~.?%w.?
+ 544: 49 2d 8a 3f 47 92 88 3f I-.?G..?
+ 54c: 35 99 85 3f b5 36 81 3f 5..?.6.?
+ 554: 34 c2 76 3f 21 21 68 3f 4.v?!!h?
+ 55c: 37 7e 56 3f 7a d1 41 3f 7~V?z.A?
+ 564: eb 16 2a 3f ba 4e 0f 3f ..*?.N.?
+ 56c: 9e fa e2 3e bd 56 a1 3e ...>.V.>
+ 574: d0 97 33 3e 4d cf c7 3c ..3>M..<
+ 57c: 44 d5 0c be a6 29 9e be D....)..
+ 584: 59 54 09 bf 17 61 44 bf YT...aD.
+ 58c: 0d c2 80 bf 89 41 a0 bf .....A..
+ 594: 0c 90 c0 bf 37 8d e1 bf ....7...
+ 59c: 9c 8b 01 c0 90 85 12 c0 ........
+ 5a4: 6e a2 23 c0 cc cf 34 c0 n.#...4.
+ 5ac: f0 fa 45 c0 d8 10 57 c0 ..E...W.
+ 5b4: 72 fe 67 c0 92 b0 78 c0 r.g...x.
+ 5bc: 18 8a 84 c0 31 8b 8c c0 ....1...
+ 5c4: 48 52 94 c0 3d d6 9b c0 HR..=...
+ 5cc: 2a 0e a3 c0 80 f1 a9 c0 *.......
+ 5d4: f5 77 b0 c0 a6 99 b6 c0 .w......
+ 5dc: 22 4f bc c0 5e 91 c1 c0 "O..^...
+ 5e4: e4 59 c6 c0 b8 a2 ca c0 .Y......
+ 5ec: 77 66 ce c0 5c a0 d1 c0 wf..\...
+ 5f4: 40 4c d4 c0 a1 66 d6 c0 @L...f..
+ 5fc: b3 ec d7 c0 c1 e5 d8 c0 ........
+ 604: 48 0b d8 c0 60 77 d6 c0 H...`w..
+ 60c: 4c 4f d4 c0 f0 95 d1 c0 LO......
+ 614: d7 4e ce c0 3d 7e ca c0 .N..=~..
+ 61c: fc 28 c6 c0 7c 54 c1 c0 .(..|T..
+ 624: cb 06 bc c0 6f 46 b6 c0 ....oF..
+ 62c: 7a 1a b0 c0 70 8a a9 c0 z...p...
+ 634: 3a 9e a2 c0 27 5e 9b c0 :...'^..
+ 63c: db d2 93 c0 3a 05 8c c0 ....:...
+ 644: 6b fe 83 c0 86 8f 77 c0 k.....w.
+ 64c: 73 d5 66 c0 a8 e1 55 c0 s.f...U.
+ 654: 4c c7 44 c0 7c 99 33 c0 L.D.|.3.
+ 65c: 38 6b 22 c0 2f 4f 11 c0 8k"./O..
+ 664: c5 57 00 c0 fd 2d df bf .W...-..
+ 66c: 86 3c be bf e3 fc 9d bf .<......
+ 674: 9d 1e 7d bf 29 25 40 bf ..}.)%@.
+ 67c: 7a 47 05 bf 08 f4 98 be zG......
+ 684: 26 c5 e7 bd 7b a3 43 3d &...{.C=
+ 68c: bb 73 4a 3e 60 34 ac 3e .sJ>`4.>
+ 694: 01 42 ed 3e cb 24 14 3f .B.>.$.?
+ 69c: 44 9d 2e 3f 73 06 46 3f D..?s.F?
+ 6a4: a4 60 5a 3f 39 b0 6b 3f .`Z?9.k?
+ 6ac: a4 fd 79 3f 9f aa 82 3f ..y?...?
+ 6b4: 9b e3 86 3f 8d b3 89 3f ...?...?
+ 6bc: 0f 26 8b 3f 45 48 8b 3f .&.?EH.?
+ 6c4: cc 28 8a 3f aa d7 87 3f .(.?...?
+ 6cc: 23 66 84 3f 3b cd 7f 3f #f.?;..?
+ 6d4: fc d8 74 3f 07 18 68 3f ..t?..h?
+ 6dc: 4d b4 59 3f f4 d8 49 3f M.Y?..I?
+ 6e4: fc b1 38 3f 06 6c 26 3f ..8?.l&?
+ 6ec: 05 34 13 3f fd 6d fe 3e .4.?.m.>
+ 6f4: 79 43 d5 3e 1f 41 ab 3e yC.>.A.>
+ 6fc: 0e be 80 3e 80 60 2b 3e ...>.`+>
+ 704: 2a 26 c7 3d c1 b0 45 3d *&.=..E=
+ 70c: a8 86 5f 3a 4f e0 36 bd .._:O.6.
+ 714: 10 0e b4 bd 48 c1 03 be ....H...
+ 71c: 86 a2 2a be 5f 6e 4e be ..*._nN.
+ 724: 8d f0 6e be 6f fe 85 be ..n.o...
+ 72c: a7 b7 92 be fb 95 9d be ........
+ 734: 7e 8f a6 be 41 9e ad be ~...A...
+ 73c: 25 c0 b2 be d8 f6 b5 be %.......
+ 744: a6 47 b7 be 6a bb b6 be .G..j...
+ 74c: 3a 5e b4 be 5c 3f b0 be :^..\?..
+ 754: 08 71 aa be 21 08 a3 be .q..!...
+ 75c: 18 1c 9a be a1 c6 8f be ........
+ 764: 67 23 84 be cf 9f 6e be g#....n.
+ 76c: 38 d6 52 be 63 2a 35 be 8.R.c*5.
+ 774: be de 15 be 33 6e ea bd ....3n..
+ 77c: 44 f0 a6 bd c0 f3 41 bd D.....A.
+ 784: e6 ea 85 bc 9c de 98 bb ........
+ 78c: 5f 1f e0 3b b9 f7 93 3c _..;...<
+ 794: 6e c7 ec 3c 71 d9 20 3d n...
+ 8ec: ab ba 44 bb 55 d5 4a bb ..D.U.J.
+ 8f4: b7 f7 50 bb d1 1f 57 bb ..P...W.
+ 8fc: 97 4b 5d bb e5 78 63 bb .K]..xc.
+ 904: 7a a5 69 bb 01 cf 6f bb z.i...o.
+ 90c: 14 f3 75 bb 2b 0f 7c bb ..u.+.|.
+ 914: 56 10 81 bb 72 12 84 bb V...r...
+ 91c: 84 0c 87 bb 20 fd 89 bb .... ...
+ 924: c7 e2 8c bb f5 bb 8f bb ........
+ 92c: 16 87 92 bb 92 42 95 bb .....B..
+ 934: be ec 97 bb e7 83 9a bb ........
+ 93c: 54 06 9d bb 3d 72 9f bb T...=r..
+ 944: d0 c5 a1 bb 34 ff a3 bb ....4...
+ 94c: 88 1c a6 bb d9 1b a8 bb ........
+ 954: 37 fb a9 bb a0 b8 ab bb 7.......
+ 95c: 11 52 ad bb 79 c5 ae bb .R..y...
+ 964: c3 10 b0 bb d1 31 b1 bb .....1..
+ 96c: 81 26 b2 bb a7 ec b2 bb .&......
+ 974: 16 82 b3 bb 9a e4 b3 bb ........
+ 97c: f6 11 b4 bb eb 07 b4 bb ........
+ 984: 3b c4 b3 bb 9d 44 b3 bb ;....D..
+ 98c: cc 86 b2 bb 7d 88 b1 bb ....}...
+ 994: 64 47 b0 bb 2f c1 ae bb dG../...
+ 99c: 98 f3 ac bb 4d dc aa bb ....M...
+ 9a4: 03 79 a8 bb 6d c7 a5 bb .y..m...
+ 9ac: 41 c5 a2 bb 3b 70 9f bb A...;p..
+ 9b4: 15 c6 9b bb 93 c4 97 bb ........
+ 9bc: 76 69 93 bb 8b b2 8e bb vi......
+ 9c4: a1 9d 89 bb 91 28 84 bb .....(..
+ 9cc: 71 a2 7c bb fe 2a 70 bb q.|..*p.
+ 9d4: a6 e6 62 bb 5c d1 54 bb ..b.\.T.
+ 9dc: 2f e7 45 bb 2e 24 36 bb /.E..$6.
+ 9e4: 9b 84 25 bb bc 04 14 bb ..%.....
+ 9ec: fb a0 01 bb b4 ab dc ba ........
+ 9f4: f4 3f b4 ba 33 f8 89 ba .?..3...
+ 9fc: 70 9c 3b ba f0 ef be b9 p.;.....
+ a04: 00 00 00 00 5d df c8 39 ....]..9
+ a0c: 0c 48 4c 3a 9b 0d 9c 3a .HL:...:
+ a14: 2b f9 d3 3a 6c f5 06 3b +..:l..;
+ a1c: 4c f3 24 3b f0 f7 43 3b L.$;..C;
+ a24: f8 04 64 3b e4 8d 82 3b ..d;...;
+ a2c: ce 9e 93 3b c0 35 a5 3b ...;.5.;
+ a34: 24 53 b7 3b 50 f7 c9 3b $S.;P..;
+ a3c: 79 22 dd 3b bf d4 f0 3b y".;...;
+ a44: 14 87 02 3c 4d e7 0c 3c ...>=v.B=
+ af4: 5d 6d 47 3d b7 08 4c 3d ]mG=..L=
+ afc: f0 a5 50 3d 63 44 55 3d ..P=cDU=
+ b04: 79 e3 59 3d 8f 82 5e 3d y.Y=..^=
+ b0c: 05 21 63 3d 38 be 67 3d .!c=8.g=
+ b14: 82 59 6c 3d 41 f2 70 3d .Yl=A.p=
+ b1c: cc 87 75 3d 7c 19 7a 3d ..u=|.z=
+ b24: a9 a6 7e 3d 56 97 81 3d ..~=V..=
+ b2c: 6d d8 83 3d 43 16 86 3d m..=C..=
+ b34: 85 50 88 3d df 86 8a 3d .P.=...=
+ b3c: fa b8 8c 3d 81 e6 8e 3d ...=...=
+ b44: 20 0f 91 3d 82 32 93 3d ..=.2.=
+ b4c: 53 50 95 3d 3f 68 97 3d SP.=?h.=
+ b54: f3 79 99 3d 1b 85 9b 3d .y.=...=
+ b5c: 66 89 9d 3d 82 86 9f 3d f..=...=
+ b64: 1d 7c a1 3d e9 69 a3 3d .|.=.i.=
+ b6c: 94 4f a5 3d d4 2c a7 3d .O.=.,.=
+ b74: 57 01 a9 3d d5 cc aa 3d W..=...=
+ b7c: 02 8f ac 3d 92 47 ae 3d ...=.G.=
+ b84: 41 f6 af 3d c4 9a b1 3d A..=...=
+ b8c: d7 34 b3 3d 36 c4 b4 3d .4.=6..=
+ b94: 9f 48 b6 3d d2 c1 b7 3d .H.=...=
+ b9c: 8d 2f b9 3d 95 91 ba 3d ./.=...=
+ ba4: ae e7 bb 3d 9e 31 bd 3d ...=.1.=
+ bac: 2d 6f be 3d 26 a0 bf 3d -o.=&..=
+ bb4: 55 c4 c0 3d 87 db c1 3d U..=...=
+ bbc: 8e e5 c2 3d 3c e2 c3 3d ...=<..=
+ bc4: 66 d1 c4 3d e2 b2 c5 3d f..=...=
+ bcc: 8a 86 c6 3d 3a 4c c7 3d ...=:L.=
+ bd4: d0 03 c8 3d 2c ad c8 3d ...=,..=
+ bdc: 30 48 c9 3d c3 d4 c9 3d 0H.=...=
+ be4: ca 52 ca 3d 32 c2 ca 3d .R.=2..=
+ bec: e6 22 cb 3d d7 74 cb 3d .".=.t.=
+ bf4: f4 b7 cb 3d 35 ec cb 3d ...=5..=
+ bfc: 8d 11 cc 3d f8 27 cc 3d ...=.'.=
+ c04: 71 2f cc 3d f8 27 cc 3d q/.=.'.=
+ c0c: 8d 11 cc 3d 35 ec cb 3d ...=5..=
+ c14: f4 b7 cb 3d d7 74 cb 3d ...=.t.=
+ c1c: e6 22 cb 3d 32 c2 ca 3d .".=2..=
+ c24: ca 52 ca 3d c3 d4 c9 3d .R.=...=
+ c2c: 30 48 c9 3d 2c ad c8 3d 0H.=,..=
+ c34: d0 03 c8 3d 3a 4c c7 3d ...=:L.=
+ c3c: 8a 86 c6 3d e2 b2 c5 3d ...=...=
+ c44: 66 d1 c4 3d 3c e2 c3 3d f..=<..=
+ c4c: 8e e5 c2 3d 87 db c1 3d ...=...=
+ c54: 55 c4 c0 3d 26 a0 bf 3d U..=&..=
+ c5c: 2d 6f be 3d 9e 31 bd 3d -o.=.1.=
+ c64: ae e7 bb 3d 95 91 ba 3d ...=...=
+ c6c: 8d 2f b9 3d d2 c1 b7 3d ./.=...=
+ c74: 9f 48 b6 3d 36 c4 b4 3d .H.=6..=
+ c7c: d7 34 b3 3d c4 9a b1 3d .4.=...=
+ c84: 41 f6 af 3d 92 47 ae 3d A..=.G.=
+ c8c: 02 8f ac 3d d5 cc aa 3d ...=...=
+ c94: 57 01 a9 3d d4 2c a7 3d W..=.,.=
+ c9c: 94 4f a5 3d e9 69 a3 3d .O.=.i.=
+ ca4: 1d 7c a1 3d 82 86 9f 3d .|.=...=
+ cac: 66 89 9d 3d 1b 85 9b 3d f..=...=
+ cb4: f3 79 99 3d 3f 68 97 3d .y.=?h.=
+ cbc: 53 50 95 3d 82 32 93 3d SP.=.2.=
+ cc4: 20 0f 91 3d 81 e6 8e 3d ..=...=
+ ccc: fa b8 8c 3d df 86 8a 3d ...=...=
+ cd4: 85 50 88 3d 43 16 86 3d .P.=C..=
+ cdc: 6d d8 83 3d 56 97 81 3d m..=V..=
+ ce4: a9 a6 7e 3d 7c 19 7a 3d ..~=|.z=
+ cec: cc 87 75 3d 41 f2 70 3d ..u=A.p=
+ cf4: 82 59 6c 3d 38 be 67 3d .Yl=8.g=
+ cfc: 05 21 63 3d 8f 82 5e 3d .!c=..^=
+ d04: 79 e3 59 3d 63 44 55 3d y.Y=cDU=
+ d0c: f0 a5 50 3d b7 08 4c 3d ..P=..L=
+ d14: 5d 6d 47 3d 76 d4 42 3d ]mG=v.B=
+ d1c: 9d 3e 3e 3d 64 ac 39 3d .>>=d.9=
+ d24: 65 1e 35 3d 2c 95 30 3d e.5=,.0=
+ d2c: 4b 11 2c 3d 4a 93 27 3d K.,=J.'=
+ d34: b9 1b 23 3d 19 ab 1e 3d ..#=...=
+ d3c: f0 41 1a 3d c0 e0 15 3d .A.=...=
+ d44: 05 88 11 3d 3d 38 0d 3d ...==8.=
+ d4c: d9 f1 08 3d 54 b5 04 3d ...=T..=
+ d54: 1d 83 00 3d 3c b7 f8 3c ...=<..<
+ d5c: 8d 7e f0 3c f6 5c e8 3c .~.<.\.<
+ d64: 37 53 e0 3c 1c 62 d8 3c 7S.<.b.<
+ d6c: 51 8a d0 3c 92 cc c8 3c Q..<...<
+ d74: 7b 29 c1 3c b7 a1 b9 3c {).<...<
+ d7c: dd 35 b2 3c 83 e6 aa 3c .5.<...<
+ d84: 2f b4 a3 3c 68 9f 9c 3c /...
+ f24: d8 a3 38 bb 30 ab 32 bb ..8.0.2.
+ f2c: 32 c1 2c bb 6d e7 26 bb 2.,.m.&.
+ f34: 4a 1f 21 bb 29 6a 1b bb J.!.)j..
+ f3c: 4d c9 15 bb e6 3d 10 bb M....=..
+ f44: 0b c9 0a bb cb 6b 05 bb .....k..
+ f4c: 13 27 00 bb 8b f7 f5 ba .'......
+ f54: 51 d5 eb ba fa e8 e1 ba Q.......
+ f5c: bc 33 d8 ba d4 b6 ce ba .3......
+ f64: 3c 73 c5 ba dc 69 bc ba ...>
+ 1114: 41 9c 37 3e ae d5 4e 3e A.7>..N>
+ 111c: e7 92 65 3e c2 c7 7b 3e ..e>..{>
+ 1124: 14 b4 88 3e 1b 34 93 3e ...>.4.>
+ 112c: 15 5e 9d 3e 30 2c a7 3e .^.>0,.>
+ 1134: c0 98 b0 3e 2d 9e b9 3e ...>-..>
+ 113c: fe 36 c2 3e e1 5d ca 3e .6.>.].>
+ 1144: ad 0d d2 3e 53 41 d9 3e ...>SA.>
+ 114c: fe f3 df 3e ff 20 e6 3e ...>. .>
+ 1154: e1 c3 eb 3e 52 d8 f0 3e ...>R..>
+ 115c: 47 5a f5 3e e6 45 f9 3e GZ.>.E.>
+ 1164: 92 97 fc 3e ef 4b ff 3e ...>.K.>
+ 116c: f0 af 00 3f 45 68 01 3f ...?Eh.?
+ 1174: ab cd 01 3f fc de 01 3f ...?...?
+ 117c: 35 9b 01 3f 7c 01 01 3f 5..?|..?
+ 1184: 1d 11 00 3f 0f 93 fd 3e ...?...>
+ 118c: b5 54 fa 3e b0 66 f6 3e .T.>.f.>
+ 1194: e7 c8 f1 3e 86 7b ec 3e ...>.{.>
+ 119c: 1b 7f e6 3e 8d d4 df 3e ...>...>
+ 11a4: 15 7d d8 3e 51 7a d0 3e .}.>Qz.>
+ 11ac: 2e ce c7 3e fe 7a be 3e ...>.z.>
+ 11b4: 6d 83 b4 3e 83 ea a9 3e m..>...>
+ 11bc: 9d b3 9e 3e 80 e2 92 3e ...>...>
+ 11c4: 4e 7b 86 3e fc 04 73 3e N{.>..s>
+ 11cc: d0 f9 57 3e 82 df 3b 3e ..W>..;>
+ 11d4: 27 c1 1e 3e 8d aa 00 3e '..>...>
+ 11dc: 8d 50 c3 3d ed 8e 83 3d .P.=...=
+ 11e4: 1c 58 04 3d fd f3 ba b9 .X.=....
+ 11ec: 60 0f 0a bd 6d 9a 8a bd `...m...
+ 11f4: 38 52 d1 bd 71 86 0c be 8R..q...
+ 11fc: 79 d3 30 be 44 40 54 be y.0.D@T.
+ 1204: 6e 4c 93 be f1 d6 b1 be nL......
+ 120c: ec 51 d0 be 41 ae ee be .Q..A...
+ 1214: 54 6e 06 bf d8 66 15 bf Tn...f..
+ 121c: d7 38 24 bf 78 dc 32 bf .8$.x.2.
+ 1224: ca 49 41 bf d8 78 4f bf .IA..xO.
+ 122c: 99 61 5d bf 1e fc 6a bf .a]...j.
+ 1234: 42 40 78 bf 10 93 82 bf B@x.....
+ 123c: cc d2 88 bf 6a db 8e bf ....j...
+ 1244: e3 a8 94 bf 50 37 9a bf ....P7..
+ 124c: cb 82 9f bf 77 87 a4 bf ....w...
+ 1254: 7d 41 a9 bf 21 ad ad bf }A..!...
+ 125c: a8 c6 b1 bf 76 8a b5 bf ....v...
+ 1264: f9 f4 b8 bf b0 02 bc bf ........
+ 126c: 32 b0 be bf 2f fa c0 bf 2.../...
+ 1274: 72 dd c2 bf d6 56 c4 bf r....V..
+ 127c: 5e 63 c5 bf 11 00 c6 bf ^c......
+ 1284: 3d 2a c6 bf 33 df c5 bf =*..3...
+ 128c: 54 1c c5 bf 55 df c3 bf T...U...
+ 1294: ea 25 c2 bf e9 ed bf bf .%......
+ 129c: 65 35 bd bf 87 fa b9 bf e5......
+ 12a4: a3 3b b6 bf 38 f7 b1 bf .;..8...
+ 12ac: ed 2b ad bf 9d d8 a7 bf .+......
+ 12b4: 3b fc a1 bf ff 95 9b bf ;.......
+ 12bc: 2f a5 94 bf 67 29 8d bf /...g)..
+ 12c4: 53 22 85 bf a5 1f 79 bf S"....y.
+ 12cc: 0a e4 66 bf 46 92 53 bf ..f.F.S.
+ 12d4: 51 2b 3f bf 79 b0 29 bf Q+?.y.).
+ 12dc: 6b 23 13 bf 6e 0c f7 be k#..n...
+ 12e4: a9 b6 c5 be 34 4b 92 be ....4K..
+ 12ec: 19 a1 39 be 9d 37 95 bd ..9..7..
+ 12f4: 8a a5 21 3d ec 5c 1f 3e ..!=.\.>
+ 12fc: dc 15 8d 3e 47 85 cb 3e ...>G..>
+ 1304: e7 9f 10 3f d7 59 39 3f ...?.Y9?
+ 130c: b1 e6 62 3f 6f 9e 86 3f ..b?o..?
+ 1314: 39 29 9c 3f a6 0e b2 3f 9).?...?
+ 131c: 66 49 c8 3f 1b d4 de 3f fI.?...?
+ 1324: 19 a9 f5 3f 63 61 06 40 ...?ca.@
+ 132c: a2 0d 12 40 52 d6 1d 40 ...@R..@
+ 1334: 67 b8 29 40 cd b0 35 40 g.)@..5@
+ 133c: 62 bc 41 40 f1 d7 4d 40 b.A@..M@
+ 1344: 4b 00 5a 40 27 32 66 40 K.Z@'2f@
+ 134c: 38 6a 72 40 2b a5 7e 40 8jr@+.~@
+ 1354: d4 6f 85 40 2a 8b 8b 40 .o.@*..@
+ 135c: e2 a2 91 40 4a b5 97 40 ...@J..@
+ 1364: af c0 9d 40 5f c3 a3 40 ...@_..@
+ 136c: a3 bb a9 40 c6 a7 af 40 ...@...@
+ 1374: 18 86 b5 40 eb 54 bb 40 ...@.T.@
+ 137c: 8e 12 c1 40 5a bd c6 40 ...@Z..@
+ 1384: a6 53 cc 40 d0 d3 d1 40 .S.@...@
+ 138c: 38 3c d7 40 4a 8b dc 40 8<.@J..@
+ 1394: 72 bf e1 40 21 d7 e6 40 r..@!..@
+ 139c: d9 d0 eb 40 15 ab f0 40 ...@...@
+ 13a4: 60 64 f5 40 55 fb f9 40 `d.@U..@
+ 13ac: 89 6e fe 40 52 5e 01 41 .n.@R^.A
+ 13b4: 2a 72 03 41 2c 72 05 41 *r.A,r.A
+ 13bc: b5 5d 07 41 3f 34 09 41 .].A?4.A
+ 13c4: 1a f5 0a 41 d9 9f 0c 41 ...A...A
+ 13cc: e0 33 0e 41 c0 b0 0f 41 .3.A...A
+ 13d4: f9 15 11 41 19 63 12 41 ...A.c.A
+ 13dc: bb 97 13 41 81 b3 14 41 ...A...A
+ 13e4: f9 b5 15 41 e9 9e 16 41 ...A...A
+ 13ec: f9 6d 17 41 e6 22 18 41 .m.A.".A
+ 13f4: 6a bd 18 41 64 3d 19 41 j..Ad=.A
+ 13fc: 8f a2 19 41 2a f4 19 41 ...A*..A
+ 1404: 82 af 19 41 dc 47 19 41 ...A.G.A
+ 140c: 78 c5 18 41 80 28 18 41 x..A.(.A
+ 1414: 21 71 17 41 ae 9f 16 41 !q.A...A
+ 141c: 5d b4 15 41 7a af 14 41 ]..Az..A
+ 1424: 64 91 13 41 72 5a 12 41 d..ArZ.A
+ 142c: 08 0b 11 41 91 a3 0f 41 ...A...A
+ 1434: 7a 24 0e 41 3b 8e 0c 41 z$.A;..A
+ 143c: 5f e1 0a 41 67 1e 09 41 _..Ag..A
+ 1444: da 45 07 41 4c 58 05 41 .E.ALX.A
+ 144c: 59 56 03 41 9d 40 01 41 YV.A.@.A
+ 1454: 73 2f fe 40 ae b8 f9 40 s/.@...@
+ 145c: 4b 1e f5 40 aa 61 f0 40 K..@.a.@
+ 1464: 3e 84 eb 40 79 87 e6 40 >..@y..@
+ 146c: db 6c e1 40 e7 35 dc 40 .l.@.5.@
+ 1474: 2e e4 d6 40 40 79 d1 40 ...@@y.@
+ 147c: b8 f6 cb 40 33 5e c6 40 ...@3^.@
+ 1484: 53 b1 c0 40 c3 f1 ba 40 S..@...@
+ 148c: 29 21 b5 40 35 41 af 40 )!.@5A.@
+ 1494: 97 53 a9 40 06 5a a3 40 .S.@.Z.@
+ 149c: 2e 56 9d 40 c7 49 97 40 .V.@.I.@
+ 14a4: 85 36 91 40 1d 1e 8b 40 .6.@...@
+ 14ac: 3f 02 85 40 3f c9 7d 40 ?..@?.}@
+ 14b4: da 8d 71 40 a8 55 65 40 ..q@.Ue@
+ 14bc: fb 23 59 40 1e fc 4c 40 .#Y@..L@
+ 14c4: 50 e1 40 40 d4 d6 34 40 P.@@..4@
+ 14cc: ce df 28 40 65 ff 1c 40 ..(@e..@
+ 14d4: ac 38 11 40 ac 8e 05 40 .8.@...@
+ 14dc: b7 08 f4 3f 4b 39 dd 3f ...?K9.?
+ 14e4: c0 b4 c6 3f ae 80 b0 3f ...?...?
+ 14ec: 6e a2 9a 3f 47 1f 85 3f n..?G..?
+ 14f4: b0 f8 5f 3f 0e 7d 36 3f .._?.}6?
+ 14fc: 42 d5 0d 3f 47 48 cb 3e B..?GH.>
+ 1504: 93 2d 84 3e 24 e4 0d 3e .-.>$..>
+ 150c: 2b 5b ba 3c 67 b8 b6 bd +[.
+ 162c: 41 af 29 3e f7 c2 46 3e A.)>..F>
+ 1634: 66 d0 62 3e 7f cc 7d 3e f.b>..}>
+ 163c: 84 d6 8b 3e 21 34 98 3e ...>!4.>
+ 1644: b1 fa a3 3e 1b 26 af 3e ...>.&.>
+ 164c: a6 b2 b9 3e fa 9c c3 3e ...>...>
+ 1654: 16 e2 cc 3e 5c 7f d5 3e ...>\..>
+ 165c: 84 72 dd 3e a6 b9 e4 3e .r.>...>
+ 1664: 35 53 eb 3e fe 3d f1 3e 5S.>.=.>
+ 166c: 21 79 f6 3e 22 04 fb 3e !y.>"..>
+ 1674: d4 de fe 3e af 04 01 3f ...>...?
+ 167c: 24 42 02 3f 2f 28 03 3f $B.?/(.?
+ 1684: 65 b7 03 3f 7b f0 03 3f e..?{..?
+ 168c: 54 d4 03 3f f7 63 03 3f T..?.c.?
+ 1694: 90 a0 02 3f 6b 8b 01 3f ...?k..?
+ 169c: fa 25 00 3f a9 e3 fc 3e .%.?...>
+ 16a4: 50 e1 f8 3e 96 48 f4 3e P..>.H.>
+ 16ac: 5a 1d ef 3e b1 63 e9 3e Z..>.c.>
+ 16b4: eb 1f e3 3e 93 56 dc 3e ...>.V.>
+ 16bc: 51 0c d5 3e 11 46 cd 3e Q..>.F.>
+ 16c4: db 08 c5 3e e7 59 bc 3e ...>.Y.>
+ 16cc: 8a 3e b3 3e 48 bc a9 3e .>.>H..>
+ 16d4: b4 d8 9f 3e 90 99 95 3e ...>...>
+ 16dc: a1 04 8b 3e dd 1f 80 3e ...>...>
+ 16e4: 66 e2 69 3e 68 fd 52 3e f.i>h.R>
+ 16ec: ec 9c 3b 3e 3c cd 23 3e ..;><.#>
+ 16f4: a4 9a 0b 3e 07 23 e6 3d ...>.#.=
+ 16fc: 87 7c b4 3d 4b 14 81 3d .|.=K..=
+ 1704: 0f df f7 3c 24 eb b2 3c ...<$..<
+ 170c: 85 64 5c 3c f9 76 a7 3b .d\<.v.;
+ 1714: 19 4f 4f bb 0c fa 39 bc .OO...9.
+ 171c: 04 35 9f bc 41 6c e0 bc .5..Al..
+ 1724: 10 3f 10 bd 99 a3 2f bd .?..../.
+ 172c: 96 52 4e bd 7d 3b 6c bd .RN.};l.
+ 1734: 30 a7 84 bd 00 be 92 bd 0.......
+ 173c: dd 5a a0 bd d4 76 ad bd .Z...v..
+ 1744: 3c 0b ba bd e9 11 c6 bd <.......
+ 174c: dd 84 d1 bd 8b 5e dc bd .....^..
+ 1754: e3 99 e6 bd 12 32 f0 bd .....2..
+ 175c: a4 22 f9 bd c7 b3 00 be ."......
+ 1764: a1 7e 04 be 38 f0 07 be .~..8...
+ 176c: 15 07 0b be 02 c2 0d be ........
+ 1774: ee 1f 10 be 07 20 12 be ..... ..
+ 177c: 92 c1 13 be 16 04 15 be ........
+ 1784: 50 e7 15 be 1e 6b 16 be P....k..
+ 178c: 95 8f 16 be f1 54 16 be .....T..
+ 1794: b1 bb 15 be 5c c4 14 be ....\...
+ 179c: c1 6f 13 be da be 11 be .o......
+ 17a4: b8 b2 0f be a6 4c 0d be .....L..
+ 17ac: 0d 8e 0a be 86 78 07 be .....x..
+ 17b4: c7 0d 04 be a4 4f 00 be .....O..
+ 17bc: 44 80 f8 bd de c2 ef bd D.......
+ 17c4: 61 6b e6 bd bc 7e dc bd ak...~..
+ 17cc: cd 01 d2 bd b6 f9 c6 bd ........
+ 17d4: f0 6b bb bd 01 5e af bd .k...^..
+ 17dc: ac d5 a2 bd d8 d8 95 bd ........
+ 17e4: 96 6d 88 bd 2d 34 75 bd .m..-4u.
+ 17ec: 5d c9 58 bd 91 a7 3b bd ].X...;.
+ 17f4: e6 db 1d bd 21 e7 fe bc ....!...
+ 17fc: dd f7 c0 bc bd 40 80 bc .....@..
+
+
+WOLAAnalysisFilter_Float_M256_m4_r1:
+ 1804: 00 00 00 00 d3 bc 26 b8 ......&.
+ 180c: 8e 3f 36 b8 9f 6d 46 b8 .?6..mF.
+ 1814: c5 4a 57 b8 c4 da 68 b8 .JW...h.
+ 181c: 5e 21 7b b8 2d 11 87 b8 ^!{.-...
+ 1824: be f0 90 b8 49 31 9b b8 ....I1..
+ 182c: b1 d4 a5 b8 dc dc b0 b8 ........
+ 1834: ad 4b bc b8 09 23 c8 b8 .K...#..
+ 183c: d6 64 d4 b8 f9 12 e1 b8 .d......
+ 1844: 46 2f ee b8 ad bb fb b8 F/......
+ 184c: 00 dd 04 b9 10 16 0c b9 ........
+ 1854: f8 89 13 b9 a1 39 1b b9 .....9..
+ 185c: f4 25 23 b9 db 4f 2b b9 .%#..O+.
+ 1864: 41 b8 33 b9 07 60 3c b9 A.3..`<.
+ 186c: 17 48 45 b9 47 71 4e b9 .HE.GqN.
+ 1874: 80 dc 57 b9 9d 8a 61 b9 ..W...a.
+ 187c: 7c 7c 6b b9 e9 b2 75 b9 ||k...u.
+ 1884: 61 17 80 b9 6d 78 85 b9 a...mx..
+ 188c: 00 fd 8a b9 7a a5 90 b9 ....z...
+ 1894: 46 72 96 b9 c1 63 9c b9 Fr...c..
+ 189c: 4d 7a a2 b9 49 b6 a8 b9 Mz..I...
+ 18a4: 10 18 af b9 f9 9f b5 b9 ........
+ 18ac: 61 4e bc b9 99 23 c3 b9 aN...#..
+ 18b4: f8 1f ca b9 c5 43 d1 b9 .....C..
+ 18bc: 58 8f d8 b9 f8 02 e0 b9 X.......
+ 18c4: e9 9e e7 b9 74 63 ef b9 ....tc..
+ 18cc: dd 50 f7 b9 5c 67 ff b9 .P..\g..
+ 18d4: 9b d3 03 ba 4e 08 08 ba ....N...
+ 18dc: e4 51 0c ba 75 b0 10 ba .Q..u...
+ 18e4: 17 24 15 ba e1 ac 19 ba .$......
+ 18ec: e7 4a 1e ba 38 fe 22 ba .J..8.".
+ 18f4: e5 c6 27 ba fc a4 2c ba ..'...,.
+ 18fc: 88 98 31 ba 92 a1 36 ba ..1...6.
+ 1904: 24 c0 3b ba 3f f4 40 ba $.;.?.@.
+ 190c: e7 3d 46 ba 20 9d 4b ba .=F. .K.
+ 1914: e4 11 51 ba 32 9c 56 ba ..Q.2.V.
+ 191c: 01 3c 5c ba 49 f1 61 ba .<\.I.a.
+ 1924: ff bb 67 ba 16 9c 6d ba ..g...m.
+ 192c: 7a 91 73 ba 1a 9c 79 ba z.s...y.
+ 1934: e1 bb 7f ba 5a f8 82 ba ....Z...
+ 193c: 3b 1d 86 ba 89 4c 89 ba ;....L..
+ 1944: 2d 86 8c ba 1e ca 8f ba -.......
+ 194c: 3a 18 93 ba 78 70 96 ba :...xp..
+ 1954: be d2 99 ba f3 3e 9d ba .....>..
+ 195c: 06 b5 a0 ba cb 34 a4 ba .....4..
+ 1964: 31 be a7 ba 16 51 ab ba 1....Q..
+ 196c: 60 ed ae ba e5 92 b2 ba `.......
+ 1974: 81 41 b6 ba 1c f9 b9 ba .A......
+ 197c: 81 b9 bd ba 86 82 c1 ba ........
+ 1984: 10 54 c5 ba ed 2d c9 ba .T...-..
+ 198c: e9 0f cd ba d0 f9 d0 ba ........
+ 1994: 7f eb d4 ba c4 e4 d8 ba ........
+ 199c: 5a e5 dc ba 15 ed e0 ba Z.......
+ 19a4: ba fb e4 ba 0c 11 e9 ba ........
+ 19ac: d0 2c ed ba c8 4e f1 ba .,...N..
+ 19b4: ba 76 f5 ba 57 a4 f9 ba .v..W...
+ 19bc: 64 d7 fd ba ca 07 01 bb d.......
+ 19c4: 54 26 03 bb 27 47 05 bb T&..'G..
+ 19cc: 20 6a 07 bb 13 8f 09 bb j......
+ 19d4: db b5 0b bb 54 de 0d bb ....T...
+ 19dc: 47 08 10 bb 96 33 12 bb G....3..
+ 19e4: 12 60 14 bb 87 8d 16 bb .`......
+ 19ec: ca bb 18 bb b0 ea 1a bb ........
+ 19f4: 06 1a 1d bb 9c 49 1f bb .....I..
+ 19fc: 3b 79 21 bb b8 a8 23 bb ;y!...#.
+ 1a04: d6 d7 25 bb 62 06 28 bb ..%.b.(.
+ 1a0c: 28 34 2a bb f2 60 2c bb (4*..`,.
+ 1a14: 85 8c 2e bb a8 b6 30 bb ......0.
+ 1a1c: 1d df 32 bb b1 05 35 bb ..2...5.
+ 1a24: 1f 2a 37 bb 2b 4c 39 bb .*7.+L9.
+ 1a2c: 9a 6b 3b bb 29 88 3d bb .k;.).=.
+ 1a34: 9a a1 3f bb ac b7 41 bb ..?...A.
+ 1a3c: 1a ca 43 bb 9f d8 45 bb ..C...E.
+ 1a44: fb e2 47 bb e4 e8 49 bb ..G...I.
+ 1a4c: 17 ea 4b bb 4a e6 4d bb ..K.J.M.
+ 1a54: 38 dd 4f bb 90 ce 51 bb 8.O...Q.
+ 1a5c: 11 ba 53 bb 6a 9f 55 bb ..S.j.U.
+ 1a64: 4e 7e 57 bb 73 56 59 bb N~W.sVY.
+ 1a6c: 88 27 5b bb 43 f1 5c bb .'[.C.\.
+ 1a74: 4c b3 5e bb 57 6d 60 bb L.^.Wm`.
+ 1a7c: 15 1f 62 bb 2f c8 63 bb ..b./.c.
+ 1a84: 53 68 65 bb 31 ff 66 bb She.1.f.
+ 1a8c: 68 8c 68 bb ad 0f 6a bb h.h...j.
+ 1a94: a9 88 6b bb fe f6 6c bb ..k...l.
+ 1a9c: 55 5a 6e bb 59 b2 6f bb UZn.Y.o.
+ 1aa4: b0 fe 70 bb fc 3e 72 bb ..p..>r.
+ 1aac: e1 72 73 bb 06 9a 74 bb .rs...t.
+ 1ab4: 0c b4 75 bb 9a c0 76 bb ..u...v.
+ 1abc: 50 bf 77 bb cc af 78 bb P.w...x.
+ 1ac4: b4 91 79 bb a0 64 7a bb ..y..dz.
+ 1acc: 37 28 7b bb 19 dc 7b bb 7({...{.
+ 1ad4: dd 7f 7c bb 26 13 7d bb ..|.&.}.
+ 1adc: 8f 95 7d bb b8 06 7e bb ..}...~.
+ 1ae4: 3c 66 7e bb b2 b3 7e bb C_.
+ 1b64: 60 9a 5c bb 9a d2 59 bb `.\...Y.
+ 1b6c: 81 eb 56 bb b7 e4 53 bb ..V...S.
+ 1b74: d9 bd 50 bb 7c 76 4d bb ..P.|vM.
+ 1b7c: 45 0e 4a bb ce 84 46 bb E.J...F.
+ 1b84: b3 d9 42 bb 96 0c 3f bb ..B...?.
+ 1b8c: 15 1d 3b bb cc 0a 37 bb ..;...7.
+ 1b94: 66 d5 32 bb 7b 7c 2e bb f.2.{|..
+ 1b9c: b6 ff 29 bb b0 5e 25 bb ..)..^%.
+ 1ba4: 17 99 20 bb 87 ae 1b bb .. .....
+ 1bac: ac 9e 16 bb 27 69 11 bb ....'i..
+ 1bb4: a6 0d 0c bb d3 8b 06 bb ........
+ 1bbc: 51 e3 00 bb 98 27 f6 ba Q....'..
+ 1bc4: e7 39 ea ba e5 fc dd ba .9......
+ 1bcc: ec 6f d1 ba 63 92 c4 ba .o..c...
+ 1bd4: a6 63 b7 ba 13 e3 a9 ba .c......
+ 1bdc: 1f 10 9c ba 1f ea 8d ba ........
+ 1be4: 28 e1 7e ba c1 45 61 ba (.~..Ea.
+ 1bec: ee 00 43 ba 9b 11 24 ba ..C...$.
+ 1bf4: b5 76 04 ba 61 5e c8 b9 .v..a^..
+ 1bfc: 0e 74 86 b9 f2 58 06 b9 .t...X..
+ 1c04: 00 00 00 00 87 04 0f 39 .......9
+ 1c0c: 26 ed 8e 39 c5 bc d7 39 &..9...9
+ 1c14: 6e f9 10 3a 90 c8 36 3a n..:..6:
+ 1c1c: 94 4c 5d 3a 24 43 82 3a .L]:$C.:
+ 1c24: 38 3b 96 3a d7 8e aa 3a 8;.:...:
+ 1c2c: 6f 3e bf 3a 45 4a d4 3a o>.:EJ.:
+ 1c34: ae b2 e9 3a f8 77 ff 3a ...:.w.:
+ 1c3c: 39 cd 0a 3b 2e 0d 16 3b 9..;...;
+ 1c44: 00 7c 21 3b c7 19 2d 3b .|!;..-;
+ 1c4c: a2 e6 38 3b af e2 44 3b ..8;..D;
+ 1c54: 03 0e 51 3b b8 68 5d 3b ..Q;.h];
+ 1c5c: df f2 69 3b 85 ac 76 3b ..i;..v;
+ 1c64: e2 ca 81 3b 50 57 88 3b ...;PW.;
+ 1c6c: 95 fb 8e 3b b6 b7 95 3b ...;...;
+ 1c74: b2 8b 9c 3b 8d 77 a3 3b ...;.w.;
+ 1c7c: 4b 7b aa 3b e9 96 b1 3b K{.;...;
+ 1c84: 66 ca b8 3b bc 15 c0 3b f..;...;
+ 1c8c: ee 78 c7 3b f1 f3 ce 3b .x.;...;
+ 1c94: c0 86 d6 3b 55 31 de 3b ...;U1.;
+ 1c9c: a5 f3 e5 3b a6 cd ed 3b ...;...;
+ 1ca4: 4e bf f5 3b 92 c8 fd 3b N..;...;
+ 1cac: b0 f4 02 3c d5 10 07 3c ...<...<
+ 1cb4: b0 38 0b 3c 38 6c 0f 3c .8.<8l.<
+ 1cbc: 64 ab 13 3c 29 f6 17 3c d..<)..<
+ 1cc4: 7d 4c 1c 3c 54 ae 20 3c }L..5=
+ 1e4c: bb 49 37 3d 2f e2 38 3d .I7=/.8=
+ 1e54: 8e 79 3a 3d c3 0f 3c 3d .y:=..<=
+ 1e5c: c6 a4 3d 3d 85 38 3f 3d ..==.8?=
+ 1e64: ee ca 40 3d f5 5b 42 3d ..@=.[B=
+ 1e6c: 8d eb 43 3d a4 79 45 3d ..C=.yE=
+ 1e74: 29 06 47 3d 13 91 48 3d ).G=..H=
+ 1e7c: 4d 1a 4a 3d cc a1 4b 3d M.J=..K=
+ 1e84: 80 27 4d 3d 59 ab 4e 3d .'M=Y.N=
+ 1e8c: 4a 2d 50 3d 41 ad 51 3d J-P=A.Q=
+ 1e94: 33 2b 53 3d 0e a7 54 3d 3+S=..T=
+ 1e9c: c6 20 56 3d 4a 98 57 3d . V=J.W=
+ 1ea4: 8d 0d 59 3d 7f 80 5a 3d ..Y=..Z=
+ 1eac: 12 f1 5b 3d 39 5f 5d 3d ..[=9_]=
+ 1eb4: e4 ca 5e 3d 02 34 60 3d ..^=.4`=
+ 1ebc: 8a 9a 61 3d 6a fe 62 3d ..a=j.b=
+ 1ec4: 96 5f 64 3d fd bd 65 3d ._d=..e=
+ 1ecc: 95 19 67 3d 4d 72 68 3d ..g=Mrh=
+ 1ed4: 18 c8 69 3d e9 1a 6b 3d ..i=..k=
+ 1edc: b2 6a 6c 3d 66 b7 6d 3d .jl=f.m=
+ 1ee4: f4 00 6f 3d 53 47 70 3d ..o=SGp=
+ 1eec: 71 8a 71 3d 48 ca 72 3d q.q=H.r=
+ 1ef4: c5 06 74 3d db 3f 75 3d ..t=.?u=
+ 1efc: 83 75 76 3d aa a7 77 3d .uv=..w=
+ 1f04: 43 d6 78 3d 48 01 7a 3d C.x=H.z=
+ 1f0c: a8 28 7b 3d 57 4c 7c 3d .({=WL|=
+ 1f14: 4a 6c 7d 3d 74 88 7e 3d Jl}=t.~=
+ 1f1c: ca a0 7f 3d a0 5a 80 3d ...=.Z.=
+ 1f24: e5 e2 80 3d 30 69 81 3d ...=0i.=
+ 1f2c: 78 ed 81 3d bb 6f 82 3d x..=.o.=
+ 1f34: f2 ef 82 3d 17 6e 83 3d ...=.n.=
+ 1f3c: 25 ea 83 3d 18 64 84 3d %..=.d.=
+ 1f44: ea db 84 3d 96 51 85 3d ...=.Q.=
+ 1f4c: 16 c5 85 3d 67 36 86 3d ...=g6.=
+ 1f54: 84 a5 86 3d 66 12 87 3d ...=f..=
+ 1f5c: 0a 7d 87 3d 6d e5 87 3d .}.=m..=
+ 1f64: 87 4b 88 3d 58 af 88 3d .K.=X..=
+ 1f6c: d7 10 89 3d 03 70 89 3d ...=.p.=
+ 1f74: d8 cc 89 3d 51 27 8a 3d ...=Q'.=
+ 1f7c: 6b 7f 8a 3d 21 d5 8a 3d k..=!..=
+ 1f84: 70 28 8b 3d 53 79 8b 3d p(.=Sy.=
+ 1f8c: ca c7 8b 3d ce 13 8c 3d ...=...=
+ 1f94: 5e 5d 8c 3d 75 a4 8c 3d ^].=u..=
+ 1f9c: 12 e9 8c 3d 31 2b 8d 3d ...=1+.=
+ 1fa4: cf 6a 8d 3d ea a7 8d 3d .j.=...=
+ 1fac: 7f e2 8d 3d 8a 1a 8e 3d ...=...=
+ 1fb4: 0b 50 8e 3d 00 83 8e 3d .P.=...=
+ 1fbc: 63 b3 8e 3d 36 e1 8e 3d c..=6..=
+ 1fc4: 74 0c 8f 3d 1e 35 8f 3d t..=.5.=
+ 1fcc: 2f 5b 8f 3d a8 7e 8f 3d /[.=.~.=
+ 1fd4: 87 9f 8f 3d c8 bd 8f 3d ...=...=
+ 1fdc: 6e d9 8f 3d 75 f2 8f 3d n..=u..=
+ 1fe4: dc 08 90 3d a3 1c 90 3d ...=...=
+ 1fec: c9 2d 90 3d 4c 3c 90 3d .-.=L<.=
+ 1ff4: 2e 48 90 3d 6b 51 90 3d .H.=kQ.=
+ 1ffc: 04 58 90 3d fb 5b 90 3d .X.=.[.=
+ 2004: 4d 5d 90 3d fb 5b 90 3d M].=.[.=
+ 200c: 04 58 90 3d 6b 51 90 3d .X.=kQ.=
+ 2014: 2e 48 90 3d 4c 3c 90 3d .H.=L<.=
+ 201c: c9 2d 90 3d a3 1c 90 3d .-.=...=
+ 2024: dc 08 90 3d 75 f2 8f 3d ...=u..=
+ 202c: 6e d9 8f 3d c8 bd 8f 3d n..=...=
+ 2034: 87 9f 8f 3d a8 7e 8f 3d ...=.~.=
+ 203c: 2f 5b 8f 3d 1e 35 8f 3d /[.=.5.=
+ 2044: 74 0c 8f 3d 36 e1 8e 3d t..=6..=
+ 204c: 63 b3 8e 3d 00 83 8e 3d c..=...=
+ 2054: 0b 50 8e 3d 8a 1a 8e 3d .P.=...=
+ 205c: 7f e2 8d 3d ea a7 8d 3d ...=...=
+ 2064: cf 6a 8d 3d 31 2b 8d 3d .j.=1+.=
+ 206c: 12 e9 8c 3d 75 a4 8c 3d ...=u..=
+ 2074: 5e 5d 8c 3d ce 13 8c 3d ^].=...=
+ 207c: ca c7 8b 3d 53 79 8b 3d ...=Sy.=
+ 2084: 70 28 8b 3d 21 d5 8a 3d p(.=!..=
+ 208c: 6b 7f 8a 3d 51 27 8a 3d k..=Q'.=
+ 2094: d8 cc 89 3d 03 70 89 3d ...=.p.=
+ 209c: d7 10 89 3d 58 af 88 3d ...=X..=
+ 20a4: 87 4b 88 3d 6d e5 87 3d .K.=m..=
+ 20ac: 0a 7d 87 3d 66 12 87 3d .}.=f..=
+ 20b4: 84 a5 86 3d 67 36 86 3d ...=g6.=
+ 20bc: 16 c5 85 3d 96 51 85 3d ...=.Q.=
+ 20c4: ea db 84 3d 18 64 84 3d ...=.d.=
+ 20cc: 25 ea 83 3d 17 6e 83 3d %..=.n.=
+ 20d4: f2 ef 82 3d bb 6f 82 3d ...=.o.=
+ 20dc: 78 ed 81 3d 30 69 81 3d x..=0i.=
+ 20e4: e5 e2 80 3d a0 5a 80 3d ...=.Z.=
+ 20ec: ca a0 7f 3d 74 88 7e 3d ...=t.~=
+ 20f4: 4a 6c 7d 3d 57 4c 7c 3d Jl}=WL|=
+ 20fc: a8 28 7b 3d 48 01 7a 3d .({=H.z=
+ 2104: 43 d6 78 3d aa a7 77 3d C.x=..w=
+ 210c: 83 75 76 3d db 3f 75 3d .uv=.?u=
+ 2114: c5 06 74 3d 48 ca 72 3d ..t=H.r=
+ 211c: 71 8a 71 3d 53 47 70 3d q.q=SGp=
+ 2124: f4 00 6f 3d 66 b7 6d 3d ..o=f.m=
+ 212c: b2 6a 6c 3d e9 1a 6b 3d .jl=..k=
+ 2134: 18 c8 69 3d 4d 72 68 3d ..i=Mrh=
+ 213c: 95 19 67 3d fd bd 65 3d ..g=..e=
+ 2144: 96 5f 64 3d 6a fe 62 3d ._d=j.b=
+ 214c: 8a 9a 61 3d 02 34 60 3d ..a=.4`=
+ 2154: e4 ca 5e 3d 39 5f 5d 3d ..^=9_]=
+ 215c: 12 f1 5b 3d 7f 80 5a 3d ..[=..Z=
+ 2164: 8d 0d 59 3d 4a 98 57 3d ..Y=J.W=
+ 216c: c6 20 56 3d 0e a7 54 3d . V=..T=
+ 2174: 33 2b 53 3d 41 ad 51 3d 3+S=A.Q=
+ 217c: 4a 2d 50 3d 59 ab 4e 3d J-P=Y.N=
+ 2184: 80 27 4d 3d cc a1 4b 3d .'M=..K=
+ 218c: 4d 1a 4a 3d 13 91 48 3d M.J=..H=
+ 2194: 29 06 47 3d a4 79 45 3d ).G=.yE=
+ 219c: 8d eb 43 3d f5 5b 42 3d ..C=.[B=
+ 21a4: ee ca 40 3d 85 38 3f 3d ..@=.8?=
+ 21ac: c6 a4 3d 3d c3 0f 3c 3d ..==..<=
+ 21b4: 8e 79 3a 3d 2f e2 38 3d .y:=/.8=
+ 21bc: bb 49 37 3d 3e b0 35 3d .I7=>.5=
+ 21c4: c7 15 34 3d 66 7a 32 3d ..4=fz2=
+ 21cc: 29 de 30 3d 23 41 2f 3d ).0=#A/=
+ 21d4: 5c a3 2d 3d e6 04 2c 3d \.-=..,=
+ 21dc: d2 65 2a 3d 2a c6 28 3d .e*=*.(=
+ 21e4: 02 26 27 3d 66 85 25 3d .&'=f.%=
+ 21ec: 63 e4 23 3d 0b 43 22 3d c.#=.C"=
+ 21f4: 6b a1 20 3d 8f ff 1e 3d k. =...=
+ 21fc: 8c 5d 1d 3d 68 bb 1b 3d .].=h..=
+ 2204: 39 19 1a 3d 07 77 18 3d 9..=.w.=
+ 220c: e3 d4 16 3d da 32 15 3d ...=.2.=
+ 2214: fc 90 13 3d 56 ef 11 3d ...=V..=
+ 221c: f6 4d 10 3d e9 ac 0e 3d .M.=...=
+ 2224: 3d 0c 0d 3d ff 6b 0b 3d =..=.k.=
+ 222c: 3c cc 09 3d 05 2d 08 3d <..=.-.=
+ 2234: 62 8e 06 3d 65 f0 04 3d b..=e..=
+ 223c: 19 53 03 3d 8c b6 01 3d .S.=...=
+ 2244: c8 1a 00 3d b5 ff fc 3c ...=...<
+ 224c: a9 cb f9 3c 7a 99 f6 3c ....:...:
+ 23e4: 38 3b 96 3a 24 43 82 3a 8;.:$C.:
+ 23ec: 94 4c 5d 3a 90 c8 36 3a .L]:..6:
+ 23f4: 6e f9 10 3a c5 bc d7 39 n..:...9
+ 23fc: 26 ed 8e 39 87 04 0f 39 &..9...9
+ 2404: 00 00 00 00 f2 58 06 b9 .....X..
+ 240c: 0e 74 86 b9 61 5e c8 b9 .t..a^..
+ 2414: b5 76 04 ba 9b 11 24 ba .v....$.
+ 241c: ee 00 43 ba c1 45 61 ba ..C..Ea.
+ 2424: 28 e1 7e ba 1f ea 8d ba (.~.....
+ 242c: 1f 10 9c ba 13 e3 a9 ba ........
+ 2434: a6 63 b7 ba 63 92 c4 ba .c..c...
+ 243c: ec 6f d1 ba e5 fc dd ba .o......
+ 2444: e7 39 ea ba 98 27 f6 ba .9...'..
+ 244c: 51 e3 00 bb d3 8b 06 bb Q.......
+ 2454: a6 0d 0c bb 27 69 11 bb ....'i..
+ 245c: ac 9e 16 bb 87 ae 1b bb ........
+ 2464: 17 99 20 bb b0 5e 25 bb .. ..^%.
+ 246c: b6 ff 29 bb 7b 7c 2e bb ..).{|..
+ 2474: 66 d5 32 bb cc 0a 37 bb f.2...7.
+ 247c: 15 1d 3b bb 96 0c 3f bb ..;...?.
+ 2484: b3 d9 42 bb ce 84 46 bb ..B...F.
+ 248c: 45 0e 4a bb 7c 76 4d bb E.J.|vM.
+ 2494: d9 bd 50 bb b7 e4 53 bb ..P...S.
+ 249c: 81 eb 56 bb 9a d2 59 bb ..V...Y.
+ 24a4: 60 9a 5c bb 3e 43 5f bb `.\.>C_.
+ 24ac: 99 cd 61 bb d5 39 64 bb ..a..9d.
+ 24b4: 5b 88 66 bb 8e b9 68 bb [.f...h.
+ 24bc: d8 cd 6a bb 9d c5 6c bb ..j...l.
+ 24c4: 44 a1 6e bb 38 61 70 bb D.n.8ap.
+ 24cc: df 05 72 bb a2 8f 73 bb ..r...s.
+ 24d4: e3 fe 74 bb 12 54 76 bb ..t..Tv.
+ 24dc: 95 8f 77 bb cf b1 78 bb ..w...x.
+ 24e4: 2d bb 79 bb 19 ac 7a bb -.y...z.
+ 24ec: f5 84 7b bb 2a 46 7c bb ..{.*F|.
+ 24f4: 27 f0 7c bb 4e 83 7d bb '.|.N.}.
+ 24fc: 07 00 7e bb b8 66 7e bb ..~..f~.
+ 2504: ce b7 7e bb aa f3 7e bb ..~...~.
+ 250c: b5 1a 7f bb 58 2d 7f bb ....X-..
+ 2514: f4 2b 7f bb f7 16 7f bb .+......
+ 251c: c0 ee 7e bb b2 b3 7e bb ..~...~.
+ 2524: 3c 66 7e bb b8 06 7e bb r.
+ 2564: b0 fe 70 bb 59 b2 6f bb ..p.Y.o.
+ 256c: 55 5a 6e bb fe f6 6c bb UZn...l.
+ 2574: a9 88 6b bb ad 0f 6a bb ..k...j.
+ 257c: 68 8c 68 bb 31 ff 66 bb h.h.1.f.
+ 2584: 53 68 65 bb 2f c8 63 bb She./.c.
+ 258c: 15 1f 62 bb 57 6d 60 bb ..b.Wm`.
+ 2594: 4c b3 5e bb 43 f1 5c bb L.^.C.\.
+ 259c: 88 27 5b bb 73 56 59 bb .'[.sVY.
+ 25a4: 4e 7e 57 bb 6a 9f 55 bb N~W.j.U.
+ 25ac: 11 ba 53 bb 90 ce 51 bb ..S...Q.
+ 25b4: 38 dd 4f bb 4a e6 4d bb 8.O.J.M.
+ 25bc: 17 ea 4b bb e4 e8 49 bb ..K...I.
+ 25c4: fb e2 47 bb 9f d8 45 bb ..G...E.
+ 25cc: 1a ca 43 bb ac b7 41 bb ..C...A.
+ 25d4: 9a a1 3f bb 29 88 3d bb ..?.).=.
+ 25dc: 9a 6b 3b bb 2b 4c 39 bb .k;.+L9.
+ 25e4: 1f 2a 37 bb b1 05 35 bb .*7...5.
+ 25ec: 1d df 32 bb a8 b6 30 bb ..2...0.
+ 25f4: 85 8c 2e bb f2 60 2c bb .....`,.
+ 25fc: 28 34 2a bb 62 06 28 bb (4*.b.(.
+ 2604: d6 d7 25 bb b8 a8 23 bb ..%...#.
+ 260c: 3b 79 21 bb 9c 49 1f bb ;y!..I..
+ 2614: 06 1a 1d bb b0 ea 1a bb ........
+ 261c: ca bb 18 bb 87 8d 16 bb ........
+ 2624: 12 60 14 bb 96 33 12 bb .`...3..
+ 262c: 47 08 10 bb 54 de 0d bb G...T...
+ 2634: db b5 0b bb 13 8f 09 bb ........
+ 263c: 20 6a 07 bb 27 47 05 bb j..'G..
+ 2644: 54 26 03 bb ca 07 01 bb T&......
+ 264c: 64 d7 fd ba 57 a4 f9 ba d...W...
+ 2654: ba 76 f5 ba c8 4e f1 ba .v...N..
+ 265c: d0 2c ed ba 0c 11 e9 ba .,......
+ 2664: ba fb e4 ba 15 ed e0 ba ........
+ 266c: 5a e5 dc ba c4 e4 d8 ba Z.......
+ 2674: 7f eb d4 ba d0 f9 d0 ba ........
+ 267c: e9 0f cd ba ed 2d c9 ba .....-..
+ 2684: 10 54 c5 ba 86 82 c1 ba .T......
+ 268c: 81 b9 bd ba 1c f9 b9 ba ........
+ 2694: 81 41 b6 ba e5 92 b2 ba .A......
+ 269c: 60 ed ae ba 16 51 ab ba `....Q..
+ 26a4: 31 be a7 ba cb 34 a4 ba 1....4..
+ 26ac: 06 b5 a0 ba f3 3e 9d ba .....>..
+ 26b4: be d2 99 ba 78 70 96 ba ....xp..
+ 26bc: 3a 18 93 ba 1e ca 8f ba :.......
+ 26c4: 2d 86 8c ba 89 4c 89 ba -....L..
+ 26cc: 3b 1d 86 ba 5a f8 82 ba ;...Z...
+ 26d4: e1 bb 7f ba 1a 9c 79 ba ......y.
+ 26dc: 7a 91 73 ba 16 9c 6d ba z.s...m.
+ 26e4: ff bb 67 ba 49 f1 61 ba ..g.I.a.
+ 26ec: 01 3c 5c ba 32 9c 56 ba .<\.2.V.
+ 26f4: e4 11 51 ba 20 9d 4b ba ..Q. .K.
+ 26fc: e7 3d 46 ba 3f f4 40 ba .=F.?.@.
+ 2704: 24 c0 3b ba 92 a1 36 ba $.;...6.
+ 270c: 88 98 31 ba fc a4 2c ba ..1...,.
+ 2714: e5 c6 27 ba 38 fe 22 ba ..'.8.".
+ 271c: e7 4a 1e ba e1 ac 19 ba .J......
+ 2724: 17 24 15 ba 75 b0 10 ba .$..u...
+ 272c: e4 51 0c ba 4e 08 08 ba .Q..N...
+ 2734: 9b d3 03 ba 5c 67 ff b9 ....\g..
+ 273c: dd 50 f7 b9 74 63 ef b9 .P..tc..
+ 2744: e9 9e e7 b9 f8 02 e0 b9 ........
+ 274c: 58 8f d8 b9 c5 43 d1 b9 X....C..
+ 2754: f8 1f ca b9 99 23 c3 b9 .....#..
+ 275c: 61 4e bc b9 f9 9f b5 b9 aN......
+ 2764: 10 18 af b9 49 b6 a8 b9 ....I...
+ 276c: 4d 7a a2 b9 c1 63 9c b9 Mz...c..
+ 2774: 46 72 96 b9 7a a5 90 b9 Fr..z...
+ 277c: 00 fd 8a b9 6d 78 85 b9 ....mx..
+ 2784: 61 17 80 b9 e9 b2 75 b9 a.....u.
+ 278c: 7c 7c 6b b9 9d 8a 61 b9 ||k...a.
+ 2794: 80 dc 57 b9 47 71 4e b9 ..W.GqN.
+ 279c: 17 48 45 b9 07 60 3c b9 .HE..`<.
+ 27a4: 41 b8 33 b9 db 4f 2b b9 A.3..O+.
+ 27ac: f4 25 23 b9 a1 39 1b b9 .%#..9..
+ 27b4: f8 89 13 b9 10 16 0c b9 ........
+ 27bc: 00 dd 04 b9 ad bb fb b8 ........
+ 27c4: 46 2f ee b8 f9 12 e1 b8 F/......
+ 27cc: d6 64 d4 b8 09 23 c8 b8 .d...#..
+ 27d4: ad 4b bc b8 dc dc b0 b8 .K......
+ 27dc: b1 d4 a5 b8 49 31 9b b8 ....I1..
+ 27e4: be f0 90 b8 2d 11 87 b8 ....-...
+ 27ec: 5e 21 7b b8 c4 da 68 b8 ^!{...h.
+ 27f4: c5 4a 57 b8 9f 6d 46 b8 .JW..mF.
+ 27fc: 8e 3f 36 b8 d3 bc 26 b8 .?6...&.
+
+
+WOLASynthesisFilter_Float_M256_m4_r1:
+ 2804: e8 d3 d0 bc 04 9d fd bc ........
+ 280c: e5 04 15 bd b6 0a 2b bd ......+.
+ 2814: 93 dd 40 bd 11 7b 56 bd ..@..{V.
+ 281c: d7 e0 6b bd 44 86 80 bd ..k.D...
+ 2824: eb fd 8a bd 2d 56 95 bd ....-V..
+ 282c: e5 8d 9f bd ee a3 a9 bd ........
+ 2834: 22 97 b3 bd 67 66 bd bd "...gf..
+ 283c: 98 10 c7 bd a3 94 d0 bd ........
+ 2844: 5e f1 d9 bd ba 25 e3 bd ^....%..
+ 284c: b8 30 ec bd 32 11 f5 bd .0..2...
+ 2854: 19 c6 fd bd 3f 27 03 be ....?'..
+ 285c: aa 54 07 be cd 6a 0b be .T...j..
+ 2864: 2a 69 0f be 40 4f 13 be *i..@O..
+ 286c: 9e 1c 17 be cb d0 1a be ........
+ 2874: 54 6b 1e be c2 eb 21 be Tk....!.
+ 287c: a8 51 25 be 9b 9c 28 be .Q%...(.
+ 2884: 29 cc 2b be f5 df 2e be ).+.....
+ 288c: 92 d7 31 be a3 b2 34 be ..1...4.
+ 2894: c4 70 37 be a3 11 3a be .p7...:.
+ 289c: d5 94 3c be 18 fa 3e be ..<...>.
+ 28a4: 06 41 41 be 5c 69 43 be .AA.\iC.
+ 28ac: ca 72 45 be 00 5d 47 be .rE..]G.
+ 28b4: c7 27 49 be cf d2 4a be .'I...J.
+ 28bc: dc 5d 4c be b8 c8 4d be .]L...M.
+ 28c4: 2e 13 4f be fa 3c 50 be ..O...5.;.
+ 293c: 3d 16 39 be d7 5a 36 be =.9..Z6.
+ 2944: 4c 80 33 be ed 86 30 be L.3...0.
+ 294c: 04 6f 2d be fc 38 2a be .o-..8*.
+ 2954: 2c e5 26 be f3 73 23 be ,.&..s#.
+ 295c: b5 e5 1f be e4 3a 1c be .....:..
+ 2964: ec 73 18 be 3e 91 14 be .s..>...
+ 296c: 5a 93 10 be ac 7a 0c be Z....z..
+ 2974: c0 47 08 be 1c fb 03 be .G......
+ 297c: 83 2a ff bd 76 2d f6 bd .*..v-..
+ 2984: 3c 00 ed bd f9 a3 e3 bd <.......
+ 298c: d7 19 da bd 25 63 d0 bd ....%c..
+ 2994: 0e 81 c6 bd df 74 bc bd .....t..
+ 299c: ee 3f b2 bd 8c e3 a7 bd .?......
+ 29a4: 18 61 9d bd fb b9 92 bd .a......
+ 29ac: a0 ef 87 bd f7 06 7a bd ......z.
+ 29b4: 0e ee 63 bd 90 97 4d bd ..c...M.
+ 29bc: 8d 06 37 bd 29 3e 20 bd ..7.)> .
+ 29c4: 82 41 09 bd ad 27 e4 bc .A...'..
+ 29cc: e0 70 b5 bc 3a 65 86 bc .p..:e..
+ 29d4: df 16 2e bc 4f a9 9d bb ....O...
+ 29dc: 0d 73 87 3a 8a 48 e2 3b .s.:.H.;
+ 29e4: da be 51 3c f0 57 99 3c ..Q<.W.<
+ 29ec: 70 f4 c9 3c 9b ad fa 3c p..<...<
+ 29f4: 10 be 15 3d 38 2c 2e 3d ...=8,.=
+ 29fc: 93 9d 46 3d f6 ef 5b 3d ..F=..[=
+ 2a04: f6 a1 d1 3d a8 4a f5 3d ...=.J.=
+ 2a0c: bc 63 0c 3e ff 09 1e 3e .c.>...>
+ 2a14: e9 95 2f 3e 47 05 41 3e ../>G.A>
+ 2a1c: e6 55 52 3e 98 85 63 3e .UR>..c>
+ 2a24: 22 92 74 3e ac bc 82 3e ".t>...>
+ 2a2c: 86 1c 8b 3e 86 67 93 3e ...>.g.>
+ 2a34: 95 9c 9b 3e a0 ba a3 3e ...>...>
+ 2a3c: 93 c0 ab 3e 4b ad b3 3e ...>K..>
+ 2a44: d3 7f bb 3e fd 36 c3 3e ...>.6.>
+ 2a4c: d0 d1 ca 3e 2d 4f d2 3e ...>-O.>
+ 2a54: 16 ae d9 3e 77 ed e0 3e ...>w..>
+ 2a5c: 55 0c e8 3e a0 09 ef 3e U..>...>
+ 2a64: 53 e4 f5 3e 7a 9b fc 3e S..>z..>
+ 2a6c: 03 97 01 3f 8a cd 04 3f ...?...?
+ 2a74: ca f0 07 3f 51 00 0b 3f ...?Q..?
+ 2a7c: 9f fb 0d 3f 43 e2 10 3f ...?C..?
+ 2a84: c6 b3 13 3f b5 6f 16 3f ...?.o.?
+ 2a8c: 9b 15 19 3f 09 a5 1b 3f ...?...?
+ 2a94: 8f 1d 1e 3f c6 7e 20 3f ...?.~ ?
+ 2a9c: 3f c8 22 3f 98 f9 24 3f ?."?..$?
+ 2aa4: 6d 12 27 3f 52 12 29 3f m.'?R.)?
+ 2aac: eb f8 2a 3f d5 c5 2c 3f ..*?..,?
+ 2ab4: bd 78 2e 3f 46 11 30 3f .x.?F.0?
+ 2abc: 1a 8f 31 3f dc f1 32 3f ..1?..2?
+ 2ac4: 4b 39 34 3f 09 65 35 3f K94?.e5?
+ 2acc: d3 74 36 3f 58 68 37 3f .t6?Xh7?
+ 2ad4: 60 3f 38 3f 9a f9 38 3f `?8?..8?
+ 2adc: c7 96 39 3f b4 16 3a 3f ..9?..:?
+ 2ae4: 20 79 3a 3f d8 bd 3a 3f y:?..:?
+ 2aec: a1 e4 3a 3f 4d ed 3a 3f ..:?M.:?
+ 2af4: b8 d7 3a 3f af a3 3a 3f ..:?..:?
+ 2afc: 13 51 3a 3f bb df 39 3f .Q:?..9?
+ 2b04: 8b 4f 39 3f 66 a0 38 3f .O9?f.8?
+ 2b0c: 32 d2 37 3f e1 e4 36 3f 2.7?..6?
+ 2b14: 5b d8 35 3f 9c ac 34 3f [.5?..4?
+ 2b1c: 8e 61 33 3f 36 f7 31 3f .a3?6.1?
+ 2b24: 8e 6d 30 3f 92 c4 2e 3f .m0?...?
+ 2b2c: 55 fc 2c 3f d5 14 2b 3f U.,?..+?
+ 2b34: 27 0e 29 3f 55 e8 26 3f '.)?U.&?
+ 2b3c: 7b a3 24 3f b5 3f 22 3f {.$?.?"?
+ 2b44: 11 bd 1f 3f c5 1b 1d 3f ...?...?
+ 2b4c: e3 5b 1a 3f a4 7d 17 3f .[.?.}.?
+ 2b54: 2f 81 14 3f b3 66 11 3f /..?.f.?
+ 2b5c: 68 2e 0e 3f 86 d8 0a 3f h..?...?
+ 2b64: 4f 65 07 3f 04 d5 03 3f Oe.?...?
+ 2b6c: e8 27 00 3f 8c bc f8 3e .'.?...>
+ 2b74: d8 f0 f0 3e 58 ed e8 3e ...>X..>
+ 2b7c: c2 b2 e0 3e c9 41 d8 3e ...>.A.>
+ 2b84: 21 9b cf 3e 98 bf c6 3e !..>...>
+ 2b8c: f9 af bd 3e 1b 6d b4 3e ...>.m.>
+ 2b94: dd f7 aa 3e 1e 51 a1 3e ...>.Q.>
+ 2b9c: d9 79 97 3e 00 73 8d 3e .y.>.s.>
+ 2ba4: 8e 3d 83 3e 20 b5 71 3e .=.> .q>
+ 2bac: 1e 96 5c 3e 49 20 47 3e ..\>I G>
+ 2bb4: dd 55 31 3e 2d 39 1b 3e .U1>-9.>
+ 2bbc: 90 cc 04 3e df 24 dc 3d ...>.$.=
+ 2bc4: a5 1a ae 3d de fe 7e 3d ...=..~=
+ 2bcc: f5 b0 20 3d 58 ac 82 3c .. =X..<
+ 2bd4: b2 34 f8 bb 3b 5a 00 bd .4..;Z..
+ 2bdc: 73 99 62 bd 55 dc a2 bd s.b.U...
+ 2be4: 0e d6 d4 bd f6 99 03 be ........
+ 2bec: e5 f7 1c be be 81 36 be ......6.
+ 2bf4: 5a 34 50 be 79 0c 6a be Z4P.y.j.
+ 2bfc: 71 03 82 be 30 26 8e be q...0&..
+ 2c04: 15 c2 b3 be a2 8a c9 be ........
+ 2c0c: 82 53 df be 0a 1a f5 be .S......
+ 2c14: ca 6d 05 bf bd 4a 10 bf .m...J..
+ 2c1c: 82 22 1b bf c7 f3 25 bf ."....%.
+ 2c24: 23 bd 30 bf 45 7d 3b bf #.0.E};.
+ 2c2c: bf 32 46 bf 38 dc 50 bf .2F.8.P.
+ 2c34: 4b 78 5b bf 92 05 66 bf Kx[...f.
+ 2c3c: a7 82 70 bf 1b ee 7a bf ..p...z.
+ 2c44: 48 a3 82 bf 48 c5 87 bf H...H...
+ 2c4c: 66 dc 8c bf da e7 91 bf f.......
+ 2c54: f3 e6 96 bf 02 d9 9b bf ........
+ 2c5c: 45 bd a0 bf 14 93 a5 bf E.......
+ 2c64: b0 59 aa bf 5e 10 af bf .Y..^...
+ 2c6c: 78 b6 b3 bf 34 4b b8 bf x...4K..
+ 2c74: ea cd bc bf e2 3d c1 bf .....=..
+ 2c7c: 63 9a c5 bf bd e2 c9 bf c.......
+ 2c84: 2f 16 ce bf 1a 34 d2 bf /....4..
+ 2c8c: bc 3b d6 bf 6f 2c da bf .;..o,..
+ 2c94: 71 05 de bf 22 c6 e1 bf q..."...
+ 2c9c: ca 6d e5 bf c2 fb e8 bf .m......
+ 2ca4: 58 6f ec bf d6 c7 ef bf Xo......
+ 2cac: a3 04 f3 bf 10 25 f6 bf .....%..
+ 2cb4: 74 28 f9 bf 1f 0e fc bf t(......
+ 2cbc: 7c d5 fe bf f0 be 00 c0 |.......
+ 2cc4: 58 03 02 c0 a0 37 03 c0 X....7..
+ 2ccc: 7d 5b 04 c0 9c 6e 05 c0 }[...n..
+ 2cd4: b9 70 06 c0 80 61 07 c0 .p...a..
+ 2cdc: ab 40 08 c0 e9 0d 09 c0 .@......
+ 2ce4: fc c8 09 c0 93 71 0a c0 .....q..
+ 2cec: 68 07 0b c0 3b 8a 0b c0 h...;...
+ 2cf4: c6 f9 0b c0 c5 55 0c c0 .....U..
+ 2cfc: f5 9d 0c c0 1c d2 0c c0 ........
+ 2d04: f1 f1 0c c0 3f fd 0c c0 ....?...
+ 2d0c: c7 f3 0c c0 4e d5 0c c0 ....N...
+ 2d14: 98 a1 0c c0 75 58 0c c0 ....uX..
+ 2d1c: a9 f9 0b c0 01 85 0b c0 ........
+ 2d24: 4c fa 0a c0 58 59 0a c0 L...XY..
+ 2d2c: f5 a1 09 c0 f2 d3 08 c0 ........
+ 2d34: 24 ef 07 c0 62 f3 06 c0 $...b...
+ 2d3c: 87 e0 05 c0 63 b6 04 c0 ....c...
+ 2d44: d6 74 03 c0 bd 1b 02 c0 .t......
+ 2d4c: f3 aa 00 c0 bf 44 fe bf .....D..
+ 2d54: b8 03 fb bf a7 92 f7 bf ........
+ 2d5c: 4a f1 f3 bf 7d 1f f0 bf J...}...
+ 2d64: 11 1d ec bf d1 e9 e7 bf ........
+ 2d6c: ad 85 e3 bf 7c f0 de bf ....|...
+ 2d74: 13 2a da bf 72 32 d5 bf .*..r2..
+ 2d7c: 81 09 d0 bf 1d af ca bf ........
+ 2d84: 4f 23 c5 bf fe 65 bf bf O#...e..
+ 2d8c: 32 77 b9 bf eb 56 b3 bf 2w...V..
+ 2d94: 29 05 ad bf fe 81 a6 bf ).......
+ 2d9c: 70 cd 9f bf 92 e7 98 bf p.......
+ 2da4: 7d d0 91 bf 48 88 8a bf }...H...
+ 2dac: 17 0f 83 bf 11 ca 76 bf ......v.
+ 2db4: 90 14 67 bf fc fd 56 bf ..g...V.
+ 2dbc: bc 86 46 bf 35 af 35 bf ..F.5.5.
+ 2dc4: de 77 24 bf 32 e1 12 bf .w$.2...
+ 2dcc: b5 eb 00 bf dd 2f dd be ...../..
+ 2dd4: 00 cd b7 be f9 af 91 be ........
+ 2ddc: 4d b4 55 be c1 99 06 be M.U.....
+ 2de4: e3 4c 58 bd 33 e2 de 3c .LX.3..<
+ 2dec: 20 63 de 3d 5d e9 43 3e c.=].C>
+ 2df4: 1a 00 8d 3e 45 b9 b8 3e ...>E..>
+ 2dfc: 5a 1e e5 3e 82 75 08 3f Z..>.u.?
+ 2e04: 40 60 29 3f f6 c8 45 3f @`)?..E?
+ 2e0c: fe 7f 62 3f b4 83 7f 3f ..b?...?
+ 2e14: 40 69 8e 3f 4c 35 9d 3f @i.?L5.?
+ 2e1c: 31 25 ac 3f 0d 38 bb 3f 1%.?.8.?
+ 2e24: f4 6c ca 3f 0d c3 d9 3f .l.?...?
+ 2e2c: 65 39 e9 3f 10 cf f8 3f e9.?...?
+ 2e34: 92 41 04 40 52 2a 0c 40 .A.@R*.@
+ 2e3c: 4f 21 14 40 07 26 1c 40 O!.@.&.@
+ 2e44: 04 38 24 40 bd 56 2c 40 .8$@.V,@
+ 2e4c: b2 81 34 40 5f b8 3c 40 ..4@_.<@
+ 2e54: 44 fa 44 40 d4 46 4d 40 D.D@.FM@
+ 2e5c: 84 9d 55 40 e3 fd 5d 40 ..U@..]@
+ 2e64: 45 67 66 40 34 d9 6e 40 Egf@4.n@
+ 2e6c: 11 53 77 40 67 d4 7f 40 .Sw@g..@
+ 2e74: 47 2e 84 40 86 75 88 40 G..@.u.@
+ 2e7c: a3 bf 8c 40 54 0c 91 40 ...@T..@
+ 2e84: 55 5b 95 40 52 ac 99 40 U[.@R..@
+ 2e8c: 06 ff 9d 40 2e 53 a2 40 ...@.S.@
+ 2e94: 70 a8 a6 40 8d fe aa 40 p..@...@
+ 2e9c: 32 55 af 40 17 ac b3 40 2U.@...@
+ 2ea4: ef 02 b8 40 6d 59 bc 40 ...@mY.@
+ 2eac: 45 af c0 40 27 04 c5 40 E..@'..@
+ 2eb4: cb 57 c9 40 e3 a9 cd 40 .W.@...@
+ 2ebc: 1e fa d1 40 34 48 d6 40 ...@4H.@
+ 2ec4: d3 93 da 40 af dc de 40 ...@...@
+ 2ecc: 81 22 e3 40 eb 64 e7 40 .".@.d.@
+ 2ed4: ad a3 eb 40 7d de ef 40 ...@}..@
+ 2edc: 03 15 f4 40 f1 46 f8 40 ...@.F.@
+ 2ee4: 0a 74 fc 40 f7 4d 00 41 .t.@.M.A
+ 2eec: 2f 5f 02 41 82 6d 04 41 /_.A.m.A
+ 2ef4: cf 78 06 41 ed 80 08 41 .x.A...A
+ 2efc: b5 85 0a 41 05 87 0c 41 ...A...A
+ 2f04: b4 84 0e 41 9f 7e 10 41 ...A.~.A
+ 2f0c: 9f 74 12 41 91 66 14 41 .t.A.f.A
+ 2f14: 51 54 16 41 ba 3d 18 41 QT.A.=.A
+ 2f1c: a8 22 1a 41 f4 02 1c 41 .".A...A
+ 2f24: 7d de 1d 41 1f b5 1f 41 }..A...A
+ 2f2c: b8 86 21 41 26 53 23 41 ..!A&S#A
+ 2f34: 4c 1a 25 41 f5 db 26 41 L.%A..&A
+ 2f3c: 16 98 28 41 7b 4e 2a 41 ..(A{N*A
+ 2f44: 0f ff 2b 41 b3 a9 2d 41 ..+A..-A
+ 2f4c: 3c 4e 2f 41 8b ec 30 41 AR.?A
+ 2f7c: b0 fe 40 41 7b 49 42 41 ..@A{IBA
+ 2f84: 93 8c 43 41 ed c7 44 41 ..CA..DA
+ 2f8c: 74 fb 45 41 fe 26 47 41 t.EA.&GA
+ 2f94: 8c 4a 48 41 e9 65 49 41 .JHA.eIA
+ 2f9c: 1e 79 4a 41 f9 83 4b 41 .yJA..KA
+ 2fa4: 79 86 4c 41 7e 80 4d 41 y.LA~.MA
+ 2fac: fe 71 4e 41 e4 5a 4f 41 .qNA.ZOA
+ 2fb4: 10 3b 50 41 84 12 51 41 .;PA..QA
+ 2fbc: 1e e1 51 41 df a6 52 41 ..QA..RA
+ 2fc4: 9d 63 53 41 63 17 54 41 .cSAc.TA
+ 2fcc: 1c c2 54 41 a8 63 55 41 ..TA.cUA
+ 2fd4: 11 fc 55 41 39 8b 56 41 ..UA9.VA
+ 2fdc: 1f 11 57 41 b9 8d 57 41 ..WA..WA
+ 2fe4: f1 00 58 41 c8 6a 58 41 ..XA.jXA
+ 2fec: 34 cb 58 41 29 22 59 41 4.XA)"YA
+ 2ff4: 9e 6f 59 41 92 b3 59 41 .oYA..YA
+ 2ffc: f0 ed 59 41 7e 29 5a 41 ..YA~)ZA
+ 3004: cf f7 59 41 8a bc 59 41 ..YA..YA
+ 300c: c4 77 59 41 69 29 59 41 .wYAi)YA
+ 3014: 98 d1 58 41 5a 70 58 41 ..XAZpXA
+ 301c: a7 05 58 41 88 91 57 41 ..XA..WA
+ 3024: 1d 14 57 41 5a 8d 56 41 ..WAZ.VA
+ 302c: 4c fd 55 41 11 64 55 41 L.UA.dUA
+ 3034: a9 c1 54 41 1e 16 54 41 ..TA..TA
+ 303c: 87 61 53 41 ec a3 52 41 .aSA..RA
+ 3044: 59 dd 51 41 ed 0d 51 41 Y.QA..QA
+ 304c: a8 35 50 41 aa 54 4f 41 .5PA.TOA
+ 3054: f2 6a 4e 41 ab 78 4d 41 .jNA.xMA
+ 305c: d4 7d 4c 41 8d 7a 4b 41 .}LA.zKA
+ 3064: e1 6e 4a 41 ee 5a 49 41 .nJA.ZIA
+ 306c: c0 3e 48 41 76 1a 47 41 .>HAv.GA
+ 3074: 24 ee 45 41 eb b9 44 41 $.EA..DA
+ 307c: ca 7d 43 41 eb 39 42 41 .}CA.9BA
+ 3084: 6e ee 40 41 5c 9b 3f 41 n.@A\.?A
+ 308c: e1 40 3e 41 07 df 3c 41 .@>A..:x.>
+ 320c: 72 ce 86 3e 60 a5 37 3e r..>`.7>
+ 3214: db 1a c6 3d f6 87 7d 3c ...=..}<
+ 321c: 46 ec 83 bd 53 5b 12 be F...S[..
+ 3224: 0e 54 61 be bc 6e 97 be .Ta..n..
+ 322c: 6b 7a bd be b5 cb e2 be kz......
+ 3234: bf b0 03 bf 3b 9d 15 bf ....;...
+ 323c: d6 2a 27 bf fe 58 38 bf .*'..X8.
+ 3244: 3d 27 49 bf 21 95 59 bf ='I.!.Y.
+ 324c: 47 a2 69 bf 44 4e 79 bf G.i.DNy.
+ 3254: 62 4c 84 bf c2 c0 8b bf bL......
+ 325c: 14 04 93 bf 48 16 9a bf ....H...
+ 3264: 34 f7 a0 bf ce a6 a7 bf 4.......
+ 326c: ff 24 ae bf b4 71 b4 bf .$...q..
+ 3274: f8 8c ba bf b0 76 c0 bf .....v..
+ 327c: e4 2e c6 bf 9e b5 cb bf ........
+ 3284: dd 0a d1 bf ba 2e d6 bf ........
+ 328c: 2d 21 db bf 69 e2 df bf -!..i...
+ 3294: 6d 72 e4 bf 63 d1 e8 bf mr..c...
+ 329c: 6d ff ec bf ad fc f0 bf m.......
+ 32a4: 43 c9 f4 bf 6b 65 f8 bf C...ke..
+ 32ac: 4e d1 fb bf 20 0d ff bf N... ...
+ 32b4: 89 0c 01 c0 b7 7a 02 c0 .....z..
+ 32bc: 39 d1 03 c0 30 10 05 c0 9...0...
+ 32c4: b9 37 06 c0 02 48 07 c0 .7...H..
+ 32cc: 31 41 08 c0 6c 23 09 c0 1A..l#..
+ 32d4: dd ee 09 c0 b5 a3 0a c0 ........
+ 32dc: 20 42 0b c0 4b ca 0b c0 B..K...
+ 32e4: 68 3c 0c c0 af 98 0c c0 h<......
+ 32ec: 55 df 0c c0 88 10 0d c0 U.......
+ 32f4: 88 2c 0d c0 87 33 0d c0 .,...3..
+ 32fc: c8 25 0d c0 82 03 0d c0 .%......
+ 3304: f3 cc 0c c0 5a 82 0c c0 ....Z...
+ 330c: fb 23 0c c0 10 b2 0b c0 .#......
+ 3314: e4 2c 0b c0 b8 94 0a c0 .,......
+ 331c: d1 e9 09 c0 77 2c 09 c0 ....w,..
+ 3324: ee 5c 08 c0 85 7b 07 c0 .\...{..
+ 332c: 83 88 06 c0 34 84 05 c0 ....4...
+ 3334: e3 6e 04 c0 dc 48 03 c0 .n...H..
+ 333c: 73 12 02 c0 ef cb 00 c0 s.......
+ 3344: 4f eb fe bf da 1f fc bf O.......
+ 334c: 0d 36 f9 bf a9 2e f6 bf .6......
+ 3354: 46 0a f3 bf 93 c9 ef bf F.......
+ 335c: 2f 6d ec bf d3 f5 e8 bf /m......
+ 3364: 17 64 e5 bf c3 b8 e1 bf .d......
+ 336c: 6f f4 dd bf d3 17 da bf o.......
+ 3374: 9e 23 d6 bf 8b 18 d2 bf .#......
+ 337c: 38 f7 cd bf 6e c0 c9 bf 8...n...
+ 3384: cd 74 c5 bf 1e 15 c1 bf .t......
+ 338c: 01 a2 bc bf 37 1c b8 bf ....7...
+ 3394: 6f 84 b3 bf 62 db ae bf o...b...
+ 339c: c9 21 aa bf 53 58 a5 bf .!..SX..
+ 33a4: c3 7f a0 bf c8 98 9b bf ........
+ 33ac: 1a a4 96 bf 6a a2 91 bf ....j...
+ 33b4: 79 94 8c bf ee 7a 87 bf y....z..
+ 33bc: 93 56 82 bf 0d 50 7a bf .V...Pz.
+ 33c4: 1c e0 6f bf b1 5e 65 bf ..o..^e.
+ 33cc: 33 cd 5a bf 0d 2d 50 bf 3.Z..-P.
+ 33d4: a6 7f 45 bf 58 c6 3a bf ..E.X.:.
+ 33dc: 8b 02 30 bf a3 35 25 bf ..0..5%.
+ 33e4: fb 60 1a bf eb 85 0f bf .`......
+ 33ec: d0 a5 04 bf 12 84 f3 be ........
+ 33f4: cd b7 dd be 75 e9 c7 be ....u...
+ 33fc: ad 1b b2 be f5 7b 9b be .....{..
+ 3404: fd 72 7c be bc 72 62 be .r|..rb.
+ 340c: 44 95 48 be d5 dd 2e be D.H.....
+ 3414: a3 4f 15 be b1 db f7 bd .O......
+ 341c: 14 77 c5 bd 90 77 93 bd .w...w..
+ 3424: 36 c6 43 bd 62 fe c2 bc 6.C.b...
+ 342c: 03 64 16 b8 8d 76 c0 3c .d...v.<
+ 3434: 51 98 3f 3d 5f f3 8e 3d Q.?=_..=
+ 343c: f3 8d bd 3d af 96 eb 3d ...=...=
+ 3444: 44 84 0c 3e 41 ef 22 3e D..>A.">
+ 344c: e5 09 39 3e da d1 4e 3e ..9>..N>
+ 3454: c6 44 64 3e 81 60 79 3e .Dd>.`y>
+ 345c: 69 11 87 3e cf 44 91 3e i..>.D.>
+ 3464: 6b 49 9b 3e 43 1e a5 3e kI.>C..>
+ 346c: 5c c2 ae 3e cf 34 b8 3e \..>.4.>
+ 3474: b4 74 c1 3e 27 81 ca 3e .t.>'..>
+ 347c: 62 59 d3 3e 83 fc db 3e bY.>...>
+ 3484: ca 69 e4 3e 86 a0 ec 3e .i.>...>
+ 348c: 03 a0 f4 3e 82 67 fc 3e ...>.g.>
+ 3494: 37 fb 01 3f 19 a6 05 3f 7..?...?
+ 349c: 12 34 09 3f e2 a4 0c 3f .4.?...?
+ 34a4: 4b f8 0f 3f 0d 2e 13 3f K..?...?
+ 34ac: ef 45 16 3f bd 3f 19 3f .E.?.?.?
+ 34b4: 42 1b 1c 3f 4d d8 1e 3f B..?M..?
+ 34bc: c5 76 21 3f 75 f6 23 3f .v!?u.#?
+ 34c4: 40 57 26 3f 13 99 28 3f @W&?..(?
+ 34cc: c8 bb 2a 3f 53 bf 2c 3f ..*?S.,?
+ 34d4: 9b a3 2e 3f 98 68 30 3f ...?.h0?
+ 34dc: 46 0e 32 3f 94 94 33 3f F.2?..3?
+ 34e4: 87 fb 34 3f 26 43 36 3f ..4?&C6?
+ 34ec: 6b 6b 37 3f 6b 74 38 3f kk7?kt8?
+ 34f4: 2c 5e 39 3f c8 28 3a 3f ,^9?.(:?
+ 34fc: 49 d4 3a 3f d0 60 3b 3f I.:?.`;?
+ 3504: 78 ce 3b 3f 57 1d 3c 3f x.;?W.
+ 350c: 9f 4d 3c 3f 6c 5f 3c 3f .M
+ 359c: 91 b4 f7 3e 37 d2 f0 3e ...>7..>
+ 35a4: 60 cd e9 3e 08 a7 e2 3e `..>...>
+ 35ac: 2c 60 db 3e e1 f9 d3 3e ,`.>...>
+ 35b4: 24 75 cc 3e 0d d3 c4 3e $u.>...>
+ 35bc: a1 14 bd 3e ed 3a b5 3e ...>.:.>
+ 35c4: 10 47 ad 3e 0c 3a a5 3e .G.>.:.>
+ 35cc: 02 15 9d 3e 01 d9 94 3e ...>...>
+ 35d4: 23 87 8c 3e 7b 20 84 3e #..>{ .>
+ 35dc: 46 4c 77 3e 64 32 66 3e FLw>d2f>
+ 35e4: 83 f5 54 3e d6 97 43 3e ..T>..C>
+ 35ec: 92 1b 32 3e ea 82 20 3e ..2>.. >
+ 35f4: 12 d0 0e 3e 6d 0a fa 3d ...>m..=
+ 35fc: 25 49 d6 3d 98 8c b0 3d %I.=...=
+ 3604: 9f 0c 44 3d 7f 78 2b 3d ..D=.x+=
+ 360c: 1d e8 12 3d 99 be f4 3c ...=...<
+ 3614: 79 c3 c3 3c 3c e6 92 3c y..<<..<
+ 361c: 66 5c 44 3c 46 8a c6 3b f\D>.q.;.
+ 376c: 50 18 39 be d2 58 36 be P.9..X6.
+ 3774: 64 7c 33 be 5c 83 30 be d|3.\.0.
+ 377c: 19 6e 2d be 05 3d 2a be .n-..=*.
+ 3784: 8d f0 26 be 14 89 23 be ..&...#.
+ 378c: 0d 07 20 be dd 6a 1c be .. ..j..
+ 3794: 09 b5 18 be f7 e5 14 be ........
+ 379c: 1f fe 10 be 01 fe 0c be ........
+ 37a4: 15 e6 08 be e2 b6 04 be ........
+ 37ac: da 70 00 be 07 29 f8 bd .p...)..
+ 37b4: d4 44 ef bd 10 36 e6 bd .D...6..
+ 37bc: e0 fd dc bd 43 9d d3 bd ....C...
+ 37c4: 61 15 ca bd 45 67 c0 bd a...Eg..
+ 37cc: 11 94 b6 bd e8 9c ac bd ........
+ 37d4: e4 82 a2 bd 2b 47 98 bd ....+G..
+ 37dc: e7 ea 8d bd 42 6f 83 bd ....Bo..
+ 37e4: bd aa 71 bd dd 3c 5c bd ..q..<\.
+ 37ec: 49 97 46 bd 53 bc 30 bd I.F.S.0.
+ 37f4: 6f ae 1a bd ec 6f 04 bd o....o..
+ 37fc: 8c 06 dc bc 99 58 ac bc .....X..
+
+
+STFT_Win_FixHalf_M512_D160:
+ 3804: 00 00 c9 00 92 01 5b 02 ......[.
+ 380c: 24 03 ed 03 b6 04 7f 05 $.......
+ 3814: 48 06 11 07 d9 07 a2 08 H.......
+ 381c: 6b 09 33 0a fb 0a c4 0b k.3.....
+ 3824: 8c 0c 54 0d 1c 0e e4 0e ..T.....
+ 382c: ab 0f 73 10 3a 11 01 12 ..s.:...
+ 3834: c8 12 8f 13 55 14 1c 15 ....U...
+ 383c: e2 15 a8 16 6e 17 33 18 ....n.3.
+ 3844: f9 18 be 19 83 1a 47 1b ......G.
+ 384c: 0c 1c d0 1c 93 1d 57 1e ......W.
+ 3854: 1a 1f dd 1f 9f 20 62 21 ..... b!
+ 385c: 24 22 e5 22 a7 23 67 24 $".".#g$
+ 3864: 28 25 e8 25 a8 26 68 27 (%.%.&h'
+ 386c: 27 28 e5 28 a4 29 62 2a '(.(.)b*
+ 3874: 1f 2b dc 2b 99 2c 55 2d .+.+.,U-
+ 387c: 11 2e cc 2e 87 2f 42 30 ...../B0
+ 3884: fc 30 b5 31 6e 32 27 33 .0.1n2'3
+ 388c: df 33 97 34 4e 35 04 36 .3.4N5.6
+ 3894: ba 36 70 37 25 38 d9 38 .6p7%8.8
+ 389c: 8d 39 40 3a f3 3a a5 3b .9@:.:.;
+ 38a4: 57 3c 08 3d b8 3d 68 3e W<.=.=h>
+ 38ac: 17 3f c6 3f 74 40 21 41 .?.?t@!A
+ 38b4: ce 41 7a 42 26 43 d1 43 .AzB&C.C
+ 38bc: 7b 44 24 45 cd 45 75 46 {D$E.EuF
+ 38c4: 1d 47 c4 47 6a 48 0f 49 .G.GjH.I
+ 38cc: b4 49 58 4a fb 4a 9e 4b .IXJ.J.K
+ 38d4: 40 4c e1 4c 81 4d 21 4e @L.L.M!N
+ 38dc: c0 4e 5e 4f fb 4f 98 50 .N^O.O.P
+ 38e4: 34 51 cf 51 69 52 03 53 4Q.QiR.S
+ 38ec: 9b 53 33 54 ca 54 60 55 .S3T.T`U
+ 38f4: f6 55 8a 56 1e 57 b1 57 .U.V.W.W
+ 38fc: 43 58 d4 58 64 59 f4 59 CX.XdY.Y
+ 3904: 82 5a 10 5b 9d 5b 29 5c .Z.[.[)\
+ 390c: b4 5c 3e 5d c8 5d 50 5e .\>].]P^
+ 3914: d7 5e 5e 5f e4 5f 68 60 .^^_._h`
+ 391c: ec 60 6f 61 f1 61 72 62 .`oa.arb
+ 3924: f2 62 71 63 ef 63 6c 64 .bqc.cld
+ 392c: e9 64 64 65 de 65 57 66 .dde.eWf
+ 3934: d0 66 47 67 bd 67 32 68 .fGg.g2h
+ 393c: a7 68 1a 69 8c 69 fd 69 .h.i.i.i
+ 3944: 6e 6a dd 6a 4b 6b b8 6b nj.jKk.k
+ 394c: 24 6c 8f 6c f9 6c 62 6d $l.l.lbm
+ 3954: ca 6d 31 6e 97 6e fb 6e .m1n.n.n
+ 395c: 5f 6f c2 6f 23 70 83 70 _o.o#p.p
+ 3964: e3 70 41 71 9e 71 fa 71 .pAq.q.q
+ 396c: 55 72 af 72 08 73 5f 73 Ur.r.s_s
+ 3974: b6 73 0b 74 60 74 b3 74 .s.t`t.t
+ 397c: 05 75 56 75 a6 75 f4 75 .uVu.u.u
+ 3984: 42 76 8e 76 d9 76 23 77 Bv.v.v#w
+ 398c: 6c 77 b4 77 fb 77 40 78 lw.w.w@x
+ 3994: 85 78 c8 78 0a 79 4a 79 .x.x.yJy
+ 399c: 8a 79 c9 79 06 7a 42 7a .y.y.zBz
+ 39a4: 7d 7a b7 7a ef 7a 27 7b }z.z.z'{
+ 39ac: 5d 7b 92 7b c6 7b f9 7b ]{.{.{.{
+ 39b4: 2a 7c 5a 7c 89 7c b7 7c *|Z|.|.|
+ 39bc: e4 7c 0f 7d 3a 7d 63 7d .|.}:}c}
+ 39c4: 8a 7d b1 7d d6 7d fb 7d .}.}.}.}
+ 39cc: 1e 7e 3f 7e 60 7e 7f 7e .~?~`~.~
+ 39d4: 9d 7e ba 7e d6 7e f0 7e .~.~.~.~
+ 39dc: 0a 7f 22 7f 38 7f 4e 7f ..".8.N.
+ 39e4: 62 7f 75 7f 87 7f 98 7f b.u.....
+ 39ec: a7 7f b5 7f c2 7f ce 7f ........
+ 39f4: d9 7f e2 7f ea 7f f1 7f ........
+ 39fc: f6 7f fa 7f fe 7f ff 7f ........
+ 3a04: ff 7f ff 7f fe 7f fa 7f ........
+ 3a0c: f6 7f f1 7f ea 7f e2 7f ........
+ 3a14: d9 7f ce 7f c2 7f b5 7f ........
+ 3a1c: a7 7f 98 7f 87 7f 75 7f ......u.
+ 3a24: 62 7f 4e 7f 38 7f 22 7f b.N.8.".
+ 3a2c: 0a 7f f0 7e d6 7e ba 7e ...~.~.~
+ 3a34: 9d 7e 7f 7e 60 7e 3f 7e .~.~`~?~
+ 3a3c: 1e 7e fb 7d d6 7d b1 7d .~.}.}.}
+ 3a44: 8a 7d 63 7d 3a 7d 0f 7d .}c}:}.}
+ 3a4c: e4 7c b7 7c 89 7c 5a 7c .|.|.|Z|
+ 3a54: 2a 7c f9 7b c6 7b 92 7b *|.{.{.{
+ 3a5c: 5d 7b 27 7b ef 7a b7 7a ]{'{.z.z
+ 3a64: 7d 7a 42 7a 06 7a c9 79 }zBz.z.y
+ 3a6c: 8a 79 4a 79 0a 79 c8 78 .yJy.y.x
+ 3a74: 85 78 40 78 fb 77 b4 77 .x@x.w.w
+ 3a7c: 6c 77 23 77 d9 76 8e 76 lw#w.v.v
+ 3a84: 42 76 f4 75 a6 75 56 75 Bv.u.uVu
+ 3a8c: 05 75 b3 74 60 74 0b 74 .u.t`t.t
+ 3a94: b6 73 5f 73 08 73 af 72 .s_s.s.r
+ 3a9c: 55 72 fa 71 9e 71 41 71 Ur.q.qAq
+ 3aa4: e3 70 83 70 23 70 c2 6f .p.p#p.o
+ 3aac: 5f 6f fb 6e 97 6e 31 6e _o.n.n1n
+ 3ab4: ca 6d 62 6d f9 6c 8f 6c .mbm.l.l
+ 3abc: 24 6c b8 6b 4b 6b dd 6a $l.kKk.j
+ 3ac4: 6e 6a fd 69 8c 69 1a 69 nj.i.i.i
+ 3acc: a7 68 32 68 bd 67 47 67 .h2h.gGg
+ 3ad4: d0 66 57 66 de 65 64 65 .fWf.ede
+ 3adc: e9 64 6c 64 ef 63 71 63 .dld.cqc
+ 3ae4: f2 62 72 62 f1 61 6f 61 .brb.aoa
+ 3aec: ec 60 68 60 e4 5f 5e 5f .`h`._^_
+ 3af4: d7 5e 50 5e c8 5d 3e 5d .^P^.]>]
+ 3afc: b4 5c 29 5c 9d 5b 10 5b .\)\.[.[
+ 3b04: 82 5a f4 59 64 59 d4 58 .Z.YdY.X
+ 3b0c: 43 58 b1 57 1e 57 8a 56 CX.W.W.V
+ 3b14: f6 55 60 55 ca 54 33 54 .U`U.T3T
+ 3b1c: 9b 53 03 53 69 52 cf 51 .S.SiR.Q
+ 3b24: 34 51 98 50 fb 4f 5e 4f 4Q.P.O^O
+ 3b2c: c0 4e 21 4e 81 4d e1 4c .N!N.M.L
+ 3b34: 40 4c 9e 4b fb 4a 58 4a @L.K.JXJ
+ 3b3c: b4 49 0f 49 6a 48 c4 47 .I.IjH.G
+ 3b44: 1d 47 75 46 cd 45 24 45 .GuF.E$E
+ 3b4c: 7b 44 d1 43 26 43 7a 42 {D.C&CzB
+ 3b54: ce 41 21 41 74 40 c6 3f .A!At@.?
+ 3b5c: 17 3f 68 3e b8 3d 08 3d .?h>.=.=
+ 3b64: 57 3c a5 3b f3 3a 40 3a W<.;.:@:
+ 3b6c: 8d 39 d9 38 25 38 70 37 .9.8%8p7
+ 3b74: ba 36 04 36 4e 35 97 34 .6.6N5.4
+ 3b7c: df 33 27 33 6e 32 b5 31 .3'3n2.1
+ 3b84: fc 30 42 30 87 2f cc 2e .0B0./..
+ 3b8c: 11 2e 55 2d 99 2c dc 2b ..U-.,.+
+ 3b94: 1f 2b 62 2a a4 29 e5 28 .+b*.).(
+ 3b9c: 27 28 68 27 a8 26 e8 25 '(h'.&.%
+ 3ba4: 28 25 67 24 a7 23 e5 22 (%g$.#."
+ 3bac: 24 22 62 21 9f 20 dd 1f $"b!. ..
+ 3bb4: 1a 1f 57 1e 93 1d d0 1c ..W.....
+ 3bbc: 0c 1c 47 1b 83 1a be 19 ..G.....
+ 3bc4: f9 18 33 18 6e 17 a8 16 ..3.n...
+ 3bcc: e2 15 1c 15 55 14 8f 13 ....U...
+ 3bd4: c8 12 01 12 3a 11 73 10 ....:.s.
+ 3bdc: ab 0f e4 0e 1c 0e 54 0d ......T.
+ 3be4: 8c 0c c4 0b fb 0a 33 0a ......3.
+ 3bec: 6b 09 a2 08 d9 07 11 07 k.......
+ 3bf4: 48 06 7f 05 b6 04 ed 03 H.......
+ 3bfc: 24 03 5b 02 92 01 c9 00 $.[.....
+
+
+STFT_Win_FixHalf_M256_D160:
+ 3c04: 00 00 18 02 30 04 48 06 ....0.H.
+ 3c0c: 5f 08 76 0a 8c 0c a1 0e _.v.....
+ 3c14: b5 10 c8 12 da 14 ea 16 ........
+ 3c1c: f9 18 06 1b 11 1d 1a 1f ........
+ 3c24: 21 21 26 23 28 25 28 27 !!(%('
+ 3c2c: 25 29 1f 2b 17 2d 0b 2f %).+.-./
+ 3c34: fc 30 e9 32 d4 34 ba 36 .0.2.4.6
+ 3c3c: 9d 38 7c 3a 57 3c 2d 3e .8|:W<->
+ 3c44: 00 40 ce 41 98 43 5d 45 .@.A.C]E
+ 3c4c: 1d 47 d8 48 8f 4a 40 4c .G.H.J@L
+ 3c54: ec 4d 93 4f 34 51 cf 52 .M.O4Q.R
+ 3c5c: 65 54 f6 55 80 57 04 59 eT.U.W.Y
+ 3c64: 82 5a fa 5b 6c 5d d7 5e .Z.[l].^
+ 3c6c: 3c 60 9a 61 f2 62 43 64 <`.a.bCd
+ 3c74: 8d 65 d0 66 0b 68 40 69 .e.f.h@i
+ 3c7c: 6e 6a 94 6b b3 6c ca 6d nj.k.l.m
+ 3c84: da 6e e2 6f e3 70 dc 71 .n.o.p.q
+ 3c8c: cd 72 b6 73 97 74 70 75 .r.s.tpu
+ 3c94: 42 76 0b 77 cc 77 85 78 Bv.w.w.x
+ 3c9c: 35 79 dd 79 7d 7a 14 7b 5y.y}z.{
+ 3ca4: a3 7b 2a 7c a8 7c 1d 7d .{*|.|.}
+ 3cac: 8a 7d ef 7d 4a 7e 9d 7e .}.}J~.~
+ 3cb4: e8 7e 29 7f 62 7f 92 7f .~).b...
+ 3cbc: ba 7f d9 7f ee 7f fc 7f ........
+ 3cc4: ff 7f ff 7f ff 7f ff 7f ........
+ 3ccc: ff 7f ff 7f ff 7f ff 7f ........
+ 3cd4: ff 7f ff 7f ff 7f ff 7f ........
+ 3cdc: ff 7f ff 7f ff 7f ff 7f ........
+ 3ce4: ff 7f ff 7f ff 7f ff 7f ........
+ 3cec: ff 7f ff 7f ff 7f ff 7f ........
+ 3cf4: ff 7f ff 7f ff 7f ff 7f ........
+ 3cfc: ff 7f ff 7f ff 7f ff 7f ........
+ 3d04: ff 7f ff 7f ff 7f ff 7f ........
+ 3d0c: ff 7f ff 7f ff 7f ff 7f ........
+ 3d14: ff 7f ff 7f ff 7f ff 7f ........
+ 3d1c: ff 7f ff 7f ff 7f ff 7f ........
+ 3d24: ff 7f ff 7f ff 7f ff 7f ........
+ 3d2c: ff 7f ff 7f ff 7f ff 7f ........
+ 3d34: ff 7f ff 7f ff 7f ff 7f ........
+ 3d3c: ff 7f ff 7f ff 7f ff 7f ........
+ 3d44: ff 7f fc 7f ee 7f d9 7f ........
+ 3d4c: ba 7f 92 7f 62 7f 29 7f ....b.).
+ 3d54: e8 7e 9d 7e 4a 7e ef 7d .~.~J~.}
+ 3d5c: 8a 7d 1d 7d a8 7c 2a 7c .}.}.|*|
+ 3d64: a3 7b 14 7b 7d 7a dd 79 .{.{}z.y
+ 3d6c: 35 79 85 78 cc 77 0b 77 5y.x.w.w
+ 3d74: 42 76 70 75 97 74 b6 73 Bvpu.t.s
+ 3d7c: cd 72 dc 71 e3 70 e2 6f .r.q.p.o
+ 3d84: da 6e ca 6d b3 6c 94 6b .n.m.l.k
+ 3d8c: 6e 6a 40 69 0b 68 d0 66 nj@i.h.f
+ 3d94: 8d 65 43 64 f2 62 9a 61 .eCd.b.a
+ 3d9c: 3c 60 d7 5e 6c 5d fa 5b <`.^l].[
+ 3da4: 82 5a 04 59 80 57 f6 55 .Z.Y.W.U
+ 3dac: 65 54 cf 52 34 51 93 4f eT.R4Q.O
+ 3db4: ec 4d 40 4c 8f 4a d8 48 .M@L.J.H
+ 3dbc: 1d 47 5d 45 98 43 ce 41 .G]E.C.A
+ 3dc4: 00 40 2d 3e 57 3c 7c 3a .@->W<|:
+ 3dcc: 9d 38 ba 36 d4 34 e9 32 .8.6.4.2
+ 3dd4: fc 30 0b 2f 17 2d 1f 2b .0./.-.+
+ 3ddc: 25 29 28 27 28 25 26 23 %)('(%
+ 3de4: 21 21 1a 1f 11 1d 06 1b !!......
+ 3dec: f9 18 ea 16 da 14 c8 12 ........
+ 3df4: b5 10 a1 0e 8c 0c 76 0a ......v.
+ 3dfc: 5f 08 48 06 30 04 18 02 _.H.0...
+
+
+STFT_Win_FixHalf_M256_D80:
+ 3e04: 00 00 92 01 24 03 b6 04 ....$...
+ 3e0c: 48 06 d9 07 6b 09 fb 0a H...k...
+ 3e14: 8c 0c 1c 0e ab 0f 3a 11 ......:.
+ 3e1c: c8 12 55 14 e2 15 6e 17 ..U...n.
+ 3e24: f9 18 83 1a 0c 1c 93 1d ........
+ 3e2c: 1a 1f 9f 20 24 22 a7 23 ... $".#
+ 3e34: 28 25 a8 26 27 28 a4 29 (%.&'(.)
+ 3e3c: 1f 2b 99 2c 11 2e 87 2f .+.,.../
+ 3e44: fc 30 6e 32 df 33 4e 35 .0n2.3N5
+ 3e4c: ba 36 25 38 8d 39 f3 3a .6%8.9.:
+ 3e54: 57 3c b8 3d 17 3f 74 40 W<.=.?t@
+ 3e5c: ce 41 26 43 7b 44 cd 45 .A&C{D.E
+ 3e64: 1d 47 6a 48 b4 49 fb 4a .GjH.I.J
+ 3e6c: 40 4c 81 4d c0 4e fb 4f @L.M.N.O
+ 3e74: 34 51 69 52 9b 53 ca 54 4QiR.S.T
+ 3e7c: f6 55 1e 57 43 58 64 59 .U.WCXdY
+ 3e84: 82 5a 9d 5b b4 5c c8 5d .Z.[.\.]
+ 3e8c: d7 5e e4 5f ec 60 f1 61 .^._.`.a
+ 3e94: f2 62 ef 63 e9 64 de 65 .b.c.d.e
+ 3e9c: d0 66 bd 67 a7 68 8c 69 .f.g.h.i
+ 3ea4: 6e 6a 4b 6b 24 6c f9 6c njKk$l.l
+ 3eac: ca 6d 97 6e 5f 6f 23 70 .m.n_o#p
+ 3eb4: e3 70 9e 71 55 72 08 73 .p.qUr.s
+ 3ebc: b6 73 60 74 05 75 a6 75 .s`t.u.u
+ 3ec4: 42 76 d9 76 6c 77 fb 77 Bv.vlw.w
+ 3ecc: 85 78 0a 79 8a 79 06 7a .x.y.y.z
+ 3ed4: 7d 7a ef 7a 5d 7b c6 7b }z.z]{.{
+ 3edc: 2a 7c 89 7c e4 7c 3a 7d *|.|.|:}
+ 3ee4: 8a 7d d6 7d 1e 7e 60 7e .}.}.~`~
+ 3eec: 9d 7e d6 7e 0a 7f 38 7f .~.~..8.
+ 3ef4: 62 7f 87 7f a7 7f c2 7f b.......
+ 3efc: d9 7f ea 7f f6 7f fe 7f ........
+ 3f04: ff 7f fe 7f f6 7f ea 7f ........
+ 3f0c: d9 7f c2 7f a7 7f 87 7f ........
+ 3f14: 62 7f 38 7f 0a 7f d6 7e b.8....~
+ 3f1c: 9d 7e 60 7e 1e 7e d6 7d .~`~.~.}
+ 3f24: 8a 7d 3a 7d e4 7c 89 7c .}:}.|.|
+ 3f2c: 2a 7c c6 7b 5d 7b ef 7a *|.{]{.z
+ 3f34: 7d 7a 06 7a 8a 79 0a 79 }z.z.y.y
+ 3f3c: 85 78 fb 77 6c 77 d9 76 .x.wlw.v
+ 3f44: 42 76 a6 75 05 75 60 74 Bv.u.u`t
+ 3f4c: b6 73 08 73 55 72 9e 71 .s.sUr.q
+ 3f54: e3 70 23 70 5f 6f 97 6e .p#p_o.n
+ 3f5c: ca 6d f9 6c 24 6c 4b 6b .m.l$lKk
+ 3f64: 6e 6a 8c 69 a7 68 bd 67 nj.i.h.g
+ 3f6c: d0 66 de 65 e9 64 ef 63 .f.e.d.c
+ 3f74: f2 62 f1 61 ec 60 e4 5f .b.a.`._
+ 3f7c: d7 5e c8 5d b4 5c 9d 5b .^.].\.[
+ 3f84: 82 5a 64 59 43 58 1e 57 .ZdYCX.W
+ 3f8c: f6 55 ca 54 9b 53 69 52 .U.T.SiR
+ 3f94: 34 51 fb 4f c0 4e 81 4d 4Q.O.N.M
+ 3f9c: 40 4c fb 4a b4 49 6a 48 @L.J.IjH
+ 3fa4: 1d 47 cd 45 7b 44 26 43 .G.E{D&C
+ 3fac: ce 41 74 40 17 3f b8 3d .At@.?.=
+ 3fb4: 57 3c f3 3a 8d 39 25 38 W<.:.9%8
+ 3fbc: ba 36 4e 35 df 33 6e 32 .6N5.3n2
+ 3fc4: fc 30 87 2f 11 2e 99 2c .0./...,
+ 3fcc: 1f 2b a4 29 27 28 a8 26 .+.)'(.&
+ 3fd4: 28 25 a7 23 24 22 9f 20 (%.#$".
+ 3fdc: 1a 1f 93 1d 0c 1c 83 1a ........
+ 3fe4: f9 18 6e 17 e2 15 55 14 ..n...U.
+ 3fec: c8 12 3a 11 ab 0f 1c 0e ..:.....
+ 3ff4: 8c 0c fb 0a 6b 09 d9 07 ....k...
+ 3ffc: 48 06 b6 04 24 03 92 01 H...$...
+
+
+STFT_Win_FixHalf_M128_D80:
+ 4004: 00 00 30 04 5f 08 8c 0c ..0._...
+ 400c: b5 10 da 14 f9 18 11 1d ........
+ 4014: 21 21 28 25 25 29 17 2d !!(%%).-
+ 401c: fc 30 d4 34 9d 38 57 3c .0.4.8W<
+ 4024: 00 40 98 43 1d 47 8f 4a .@.C.G.J
+ 402c: ec 4d 34 51 65 54 80 57 .M4QeT.W
+ 4034: 82 5a 6c 5d 3c 60 f2 62 .Zl]<`.b
+ 403c: 8d 65 0b 68 6e 6a b3 6c .e.hnj.l
+ 4044: da 6e e3 70 cd 72 97 74 .n.p.r.t
+ 404c: 42 76 cc 77 35 79 7d 7a Bv.w5y}z
+ 4054: a3 7b a8 7c 8a 7d 4a 7e .{.|.}J~
+ 405c: e8 7e 62 7f ba 7f ee 7f .~b.....
+ 4064: ff 7f ff 7f ff 7f ff 7f ........
+ 406c: ff 7f ff 7f ff 7f ff 7f ........
+ 4074: ff 7f ff 7f ff 7f ff 7f ........
+ 407c: ff 7f ff 7f ff 7f ff 7f ........
+ 4084: ff 7f ff 7f ff 7f ff 7f ........
+ 408c: ff 7f ff 7f ff 7f ff 7f ........
+ 4094: ff 7f ff 7f ff 7f ff 7f ........
+ 409c: ff 7f ff 7f ff 7f ff 7f ........
+ 40a4: ff 7f ee 7f ba 7f 62 7f ......b.
+ 40ac: e8 7e 4a 7e 8a 7d a8 7c .~J~.}.|
+ 40b4: a3 7b 7d 7a 35 79 cc 77 .{}z5y.w
+ 40bc: 42 76 97 74 cd 72 e3 70 Bv.t.r.p
+ 40c4: da 6e b3 6c 6e 6a 0b 68 .n.lnj.h
+ 40cc: 8d 65 f2 62 3c 60 6c 5d .e.b<`l]
+ 40d4: 82 5a 80 57 65 54 34 51 .Z.WeT4Q
+ 40dc: ec 4d 8f 4a 1d 47 98 43 .M.J.G.C
+ 40e4: 00 40 57 3c 9d 38 d4 34 .@W<.8.4
+ 40ec: fc 30 17 2d 25 29 28 25 .0.-%)(%
+ 40f4: 21 21 11 1d f9 18 da 14 !!......
+ 40fc: b5 10 8c 0c 5f 08 30 04 ...._.0.
+
+
+memcmp:
+ 4104: 74 04 [--sp] = {rets, r4}
+ 4106: 82 f9 05 08 if (r2 < 0x4) goto 0xa
+ 410a: 90 e1 10 30 r3 = r1 | r0
+ 410e: 60 ff 03 30 0b 00 if ((r3 & 0x3) == 0) goto 0x16
+ 4114: 02 51 if (r2 == 0) goto 0x22
+ 4116: 13 07 r3 = b[r1++=0x1] (u)
+ 4118: 04 07 r4 = b[r0++=0x1] (u)
+ 411a: fa 3f r2 += -0x1
+ 411c: 03 e8 fa 41 if (r4 == r3) goto -0xc
+ 4120: c8 1e r0 = r4 - r3
+ 4122: 54 04 {pc, r4} = [sp++]
+ 4124: fa 3c r2 += -0x4
+ 4126: c1 24 r1 += 0x4
+ 4128: c0 24 r0 += 0x4
+ 412a: 82 f9 f3 09 if (r2 < 0x4) goto -0x1a
+ 412e: 13 60 r3 = [r1+0x0]
+ 4130: 04 60 r4 = [r0+0x0]
+ 4132: 03 e8 f7 41 if (r4 == r3) goto -0x12
+ 4136: f7 8e goto -0x24
+ 4138: 40 20 r0 = 0x0
+ 413a: 54 04 {pc, r4} = [sp++]
+
+
+memmove:
+ 413c: 76 04 [--sp] = {rets, r6-r4}
+ 413e: 00 ec 03 10 if (r1 > r0) goto 0x6
+ 4142: 93 1c r3 = r1 + r2
+ 4144: 00 ec 29 30 if (r3 > r0) goto 0x52
+ 4148: 03 16 r3 = r0
+ 414a: 82 f9 14 10 if (r2 < 0x8) goto 0x28
+ 414e: 65 e1 03 10 r5 = r1 & 0x3
+ 4152: 64 e1 03 30 r4 = r3 & 0x3
+ 4156: 04 46 if (r4 == 0) goto 0xc
+ 4158: a6 e0 04 40 r6 = 0x4 - r4
+ 415c: a2 1f r2 = r2 - r6
+ 415e: 16 03 rep 0x4 r6 {
+ 4160: 16 07 r6 = b[r1++=0x1] (u)
+ 4162: b6 07 b[r3++=0x1] = r6
+ }
+ 4164: 5c 19 r4 ^= r5
+ 4166: a5 a2 r5 = r2 >> 0x2
+ 4168: 84 4a if (r4 != 0) goto 0x14
+ 416a: 15 03 rep 0x4 r5 {
+ 416c: 16 05 r6 = [r1++=0x4]
+ 416e: b6 05 [r3++=0x4] = r6
+ }
+ 4170: f5 5c if (r5 != 0) goto -0x8
+ 4172: 62 e1 03 20 r2 = r2 & 0x3
+ 4176: 12 03 rep 0x4 r2 {
+ 4178: 12 07 r2 = b[r1++=0x1] (u)
+ 417a: b2 07 b[r3++=0x1] = r2
+ }
+ 417c: 56 04 {pc, r6-r4} = [sp++]
+ 417e: a5 03 rep 0x16 r5 {
+ 4180: 16 07 r6 = b[r1++=0x1] (u)
+ 4182: 14 07 r4 = b[r1++=0x1] (u)
+ 4184: a6 f1 20 44 r6 <= insert(r4, p:0x8, l:0x8) #
+ 4188: 14 07 r4 = b[r1++=0x1] (u)
+ 418a: a6 f1 20 48 r6 <= insert(r4, p:0x10, l:0x8) #
+ 418e: 14 07 r4 = b[r1++=0x1] (u)
+ 4190: a6 e1 20 4c r6 <= insert(r4, p:0x18, l:0x8)
+ 4194: b6 05 [r3++=0x4] = r6
+ }
+ 4196: f5 53 if (r5 != 0) goto -0x1a
+ 4198: f7 8c goto -0x28
+ 419a: 83 1c r3 = r0 + r2
+ 419c: 91 1c r1 = r1 + r2
+ 419e: 82 f9 17 10 if (r2 < 0x8) goto 0x2e
+ 41a2: 65 e1 03 10 r5 = r1 & 0x3
+ 41a6: 64 e1 03 30 r4 = r3 & 0x3
+ 41aa: 04 47 if (r4 == 0) goto 0xe
+ 41ac: 22 1f r2 = r2 - r4
+ 41ae: 46 16 r6 = r4
+ 41b0: 36 03 rep 0x8 r6 {
+ 41b2: 59 ee 1f 6f r6 = b[++r1=-0x1] (u)
+ 41b6: 5b ee 3f 6f b[++r3=-0x1] = r6
+ }
+ 41ba: 5c 19 r4 ^= r5
+ 41bc: a5 a2 r5 = r2 >> 0x2
+ 41be: 84 4e if (r4 != 0) goto 0x1c
+ 41c0: 35 03 rep 0x8 r5 {
+ 41c2: d7 ec 1e 6f r6 = [++r1=-0x4]
+ 41c6: d7 ec 3f 6f [++r3=-0x4] = r6
+ }
+ 41ca: f5 5a if (r5 != 0) goto -0xc
+ 41cc: 62 e1 03 20 r2 = r2 & 0x3
+ 41d0: 32 03 rep 0x8 r2 {
+ 41d2: 59 ee 1f 6f r6 = b[++r1=-0x1] (u)
+ 41d6: 5b ee 3f 6f b[++r3=-0x1] = r6
+ }
+ 41da: 56 04 {pc, r6-r4} = [sp++]
+ 41dc: f9 3f r1 += -0x1
+ 41de: b5 03 rep 0x18 r5 {
+ 41e0: 1e 07 r6 = b[r1++=-0x1] (u)
+ 41e2: 66 b8 r6 = r6 << 0x18
+ 41e4: 1c 07 r4 = b[r1++=-0x1] (u)
+ 41e6: a6 f1 20 48 r6 <= insert(r4, p:0x10, l:0x8) #
+ 41ea: 1c 07 r4 = b[r1++=-0x1] (u)
+ 41ec: a6 f1 20 44 r6 <= insert(r4, p:0x8, l:0x8) #
+ 41f0: 1c 07 r4 = b[r1++=-0x1] (u)
+ 41f2: 46 19 r6 |= r4
+ 41f4: d7 ec 3f 6f [++r3=-0x4] = r6
+ }
+ 41f8: f5 52 if (r5 != 0) goto -0x1c
+ 41fa: 19 81 r1 = r1 + 0x1
+ 41fc: f7 87 goto -0x32
+
+
+memmem:
+ 41fe: 77 04 [--sp] = {rets, r7-r4}
+ 4200: 35 16 r5 = r3
+ 4202: 26 16 r6 = r2
+ 4204: 17 16 r7 = r1
+ 4206: 04 16 r4 = r0
+ 4208: 85 49 if (r5 != 0) goto 0x12
+ 420a: 04 8b goto 0x16
+ 420c: 40 16 r0 = r4
+ 420e: 61 16 r1 = r6
+ 4210: 52 16 r2 = r5
+ 4212: bf ea 77 ff call -0x112
+ 4216: 00 45 if (r0 == 0) goto 0xa
+ 4218: ff 3f r7 += -0x1
+ 421a: c4 21 r4 += 0x1
+ 421c: 05 e9 f6 71 if (r7 >= r5) goto -0x14
+ 4220: 44 20 r4 = 0x0
+ 4222: 40 16 r0 = r4
+ 4224: 57 04 {pc, r7-r4} = [sp++]
+
+
+memset:
+ 4226: 74 04 [--sp] = {rets, r4}
+ 4228: 03 16 r3 = r0
+ 422a: 02 52 if (r2 == 0) goto 0x24
+ 422c: 33 ea 03 40 if ((r3 & 0x3) != 0) {
+ 4230: f2 f0 01 20 r2 = r2 - 0x1 #
+ 4234: b1 07 b[r3++=0x1] = r1
+ 4236: f7 99 goto -0xe
+ }
+ 4238: a4 a2 r4 = r2 >> 0x2
+ 423a: a1 e1 20 14 r1 <= insert(r1, p:0x8, l:0x8)
+ 423e: a1 e1 40 18 r1 <= insert(r1, p:0x10, l:0x10)
+ 4242: 04 03 rep 0x2 r4 {
+ 4244: b1 05 [r3++=0x4] = r1
+ }
+ 4246: f4 5d if (r4 != 0) goto -0x6
+ 4248: 62 e1 03 20 r2 = r2 & 0x3
+ 424c: 02 03 rep 0x2 r2 {
+ 424e: b1 07 b[r3++=0x1] = r1
+ }
+ 4250: 54 04 {pc, r4} = [sp++]
+
+
+modf:
+ 4252: 79 04 [--sp] = {rets, r9-r4}
+ 4254: 04 15 r5_r4 = r1_r0
+ 4256: d0 e1 04 4b r5_r4 >>= 0x34
+ 425a: 43 e0 ff 07 r3 = 0x7ff
+ 425e: b4 19 r4 &= r3
+ 4260: 33 e1 01 4c r3 = r4 + -0x3ff
+ 4264: 03 fe 08 26 ifs (r3 > 0x13) goto 0x10
+ 4268: 74 fc 1d fc if (r4 > 0x3fe) goto 0x3a
+ 426c: 65 e1 00 14 r5 = r1 & 0x80000000
+ 4270: 44 20 r4 = 0x0
+ 4272: 50 ec 21 40 d[r2+0x0] = r5_r4
+ 4276: 59 04 {pc, r9-r4} = [sp++]
+ 4278: 03 fd 2c 68 ifs (r3 >= 0x34) goto 0x58
+ 427c: 33 e1 ed 4b r3 = r4 + -0x413
+ 4280: 14 3f r4 = -0x1
+ 4282: c8 e1 42 33 r3 = r4 >> r3
+ 4286: 03 fa 25 00 if ((r3 & r0) == 0) goto 0x4a
+ 428a: 44 20 r4 = 0x0
+ 428c: 90 e1 03 63 r6 = r0 & ~r3
+ 4290: 15 16 r5 = r1
+ 4292: 47 16 r7 = r4
+ 4294: 90 e1 70 95 r9 = r7 | r5
+ 4298: 90 e1 60 84 r8 = r6 | r4
+ 429c: 50 ec 21 80 d[r2+0x0] = r9_r8
+ 42a0: 62 16 r2 = r6
+ 42a2: 53 16 r3 = r5
+ 42a4: 04 94 goto 0x28
+ 42a6: c4 ff ff ff 0f 00 r4 = 0xfffff <$data.__3+0xBDBE : ffffe >
+ 42ac: c8 e1 42 33 r3 = r4 >> r3
+ 42b0: 90 e1 32 41 r4 = r3 & r1
+ 42b4: 04 19 r4 |= r0
+ 42b6: 04 4e if (r4 == 0) goto 0x1c
+ 42b8: 90 e1 13 43 r4 = r1 & ~r3
+ 42bc: 45 20 r5 = 0x0
+ 42be: 46 16 r6 = r4
+ 42c0: 47 20 r7 = 0x0
+ 42c2: d0 e1 00 62 r7_r6 <<= 0x20
+ 42c6: 50 ec 21 60 d[r2+0x0] = r7_r6
+ 42ca: 42 20 r2 = 0x0
+ 42cc: 43 16 r3 = r4
+ 42ce: 39 04 {rets, r9-r4} = [sp++]
+ 42d0: c0 ea c3 9b goto 0x13786 <__subdf3 : 17a5a >
+ 42d4: 50 ec 21 00 d[r2+0x0] = r1_r0
+ 42d8: 61 e1 00 14 r1 = r1 & 0x80000000
+ 42dc: 40 20 r0 = 0x0
+ 42de: 59 04 {pc, r9-r4} = [sp++]
+
+
+strchr:
+ 42e0: 11 17 r1 = r1.b0 (u)
+ 42e2: 02 07 r2 = b[r0++=0x1] (u)
+ 42e4: 01 e8 01 20 if (r2 == r1) goto 0x2
+ 42e8: f2 5c if (r2 != 0) goto -0x8
+ 42ea: f8 3f r0 += -0x1
+ 42ec: 92 e8 00 01 if (r2 != r1) {
+ 42f0: 40 20 r0 = 0x0
+ }
+ 42f2: 80 00 rts
+
+
+strcmp:
+ 42f4: 77 04 [--sp] = {rets, r7-r4}
+ 42f6: 64 e1 03 00 r4 = r0 & 0x3
+ 42fa: 04 4b if (r4 == 0) goto 0x16
+ 42fc: a4 e0 04 40 r4 = 0x4 - r4
+ 4300: 0a 40 r2 = b[r0+0x0] (u)
+ 4302: 22 41 if (r2 == 0) goto 0x82
+ 4304: 1b 40 r3 = b[r1+0x0] (u)
+ 4306: 83 e8 3f 20 if (r2 != r3) goto 0x7e
+ 430a: 08 81 r0 = r0 + 0x1
+ 430c: 19 81 r1 = r1 + 0x1
+ 430e: 04 ea f7 ff if (--r4 != 0) goto -0x12
+ 4312: 90 e1 10 20 r2 = r1 | r0
+ 4316: c6 ff ff fe fe fe r6 = 0xfefefeff
+ 431c: 61 ff 03 20 13 00 if ((r2 & 0x3) != 0) goto 0x26
+ 4322: 02 60 r2 = [r0+0x0]
+ 4324: 13 60 r3 = [r1+0x0]
+ 4326: 83 e8 26 20 if (r2 != r3) goto 0x4c
+ 432a: 14 16 r4 = r1
+ 432c: a1 1d r1 = r2 + r6
+ 432e: 90 e1 13 12 r1 = r1 & ~r2
+ 4332: 61 ff 80 13 2c 00 if ((r1 & 0x80808080) != 0) goto 0x58
+ 4338: 02 61 r2 = [r0+0x4]
+ 433a: 45 61 r5 = [r4+0x4]
+ 433c: 49 84 r1 = r4 + 0x4
+ 433e: 08 84 r0 = r0 + 0x4
+ 4340: 14 16 r4 = r1
+ 4342: 05 e8 f3 21 if (r2 == r5) goto -0x1a
+ 4346: 04 97 goto 0x2e
+ 4348: 14 16 r4 = r1
+ 434a: 02 60 r2 = [r0+0x0]
+ 434c: 43 07 r3 = b[r4++=0x1] (u)
+ 434e: 45 07 r5 = b[r4++=0x1] (u)
+ 4350: a3 e1 20 54 r3 <= insert(r5, p:0x8, l:0x8)
+ 4354: 45 07 r5 = b[r4++=0x1] (u)
+ 4356: a3 e1 20 58 r3 <= insert(r5, p:0x10, l:0x8)
+ 435a: 45 07 r5 = b[r4++=0x1] (u)
+ 435c: a3 e1 20 5c r3 <= insert(r5, p:0x18, l:0x8)
+ 4360: 83 e8 09 20 if (r2 != r3) goto 0x12
+ 4364: a5 1d r5 = r2 + r6
+ 4366: 90 e1 53 52 r5 = r5 & ~r2
+ 436a: 61 ff 80 53 10 00 if ((r5 & 0x80808080) != 0) goto 0x20
+ 4370: 08 84 r0 = r0 + 0x4
+ 4372: 19 84 r1 = r1 + 0x4
+ 4374: f7 89 goto -0x2e
+ 4376: 0a 40 r2 = b[r0+0x0] (u)
+ 4378: 02 46 if (r2 == 0) goto 0xc
+ 437a: 1c 40 r4 = b[r1+0x0] (u)
+ 437c: 84 e8 04 20 if (r2 != r4) goto 0x8
+ 4380: 08 81 r0 = r0 + 0x1
+ 4382: 19 81 r1 = r1 + 0x1
+ 4384: f7 98 goto -0x10
+ 4386: 42 20 r2 = 0x0
+ 4388: 13 16 r3 = r1
+ 438a: 38 40 r0 = b[r3+0x0] (u)
+ 438c: 20 1e r0 = r2 - r0
+ 438e: 57 04 {pc, r7-r4} = [sp++]
+ 4390: 40 20 r0 = 0x0
+ 4392: 57 04 {pc, r7-r4} = [sp++]
+
+
+strcpy:
+ 4394: 77 04 [--sp] = {rets, r7-r4}
+ 4396: 07 16 r7 = r0
+ 4398: 64 e1 03 00 r4 = r0 & 0x3
+ 439c: 04 47 if (r4 == 0) goto 0xe
+ 439e: a4 e0 04 40 r4 = 0x4 - r4
+ 43a2: 12 07 r2 = b[r1++=0x1] (u)
+ 43a4: 82 07 b[r0++=0x1] = r2
+ 43a6: 12 4b if (r2 == 0) goto 0x56
+ 43a8: 04 ea fb ff if (--r4 != 0) goto -0xa
+ 43ac: 90 e1 10 20 r2 = r1 | r0
+ 43b0: c6 ff ff fe fe fe r6 = 0xfefefeff
+ 43b6: 61 ff 03 20 0a 00 if ((r2 & 0x3) != 0) goto 0x14
+ 43bc: 12 60 r2 = [r1+0x0]
+ 43be: a3 1d r3 = r2 + r6
+ 43c0: 90 e1 33 32 r3 = r3 & ~r2
+ 43c4: 61 ff 80 33 17 00 if ((r3 & 0x80808080) != 0) goto 0x2e
+ 43ca: 19 84 r1 = r1 + 0x4
+ 43cc: 82 05 [r0++=0x4] = r2
+ 43ce: f7 96 goto -0x14
+ 43d0: 14 16 r4 = r1
+ 43d2: 42 07 r2 = b[r4++=0x1] (u)
+ 43d4: 45 07 r5 = b[r4++=0x1] (u)
+ 43d6: a2 e1 20 54 r2 <= insert(r5, p:0x8, l:0x8)
+ 43da: 45 07 r5 = b[r4++=0x1] (u)
+ 43dc: a2 e1 20 58 r2 <= insert(r5, p:0x10, l:0x8)
+ 43e0: 45 07 r5 = b[r4++=0x1] (u)
+ 43e2: a2 e1 20 5c r2 <= insert(r5, p:0x18, l:0x8)
+ 43e6: a5 1d r5 = r2 + r6
+ 43e8: 90 e1 53 52 r5 = r5 & ~r2
+ 43ec: 61 ff 80 53 03 00 if ((r5 & 0x80808080) != 0) goto 0x6
+ 43f2: 82 05 [r0++=0x4] = r2
+ 43f4: 41 16 r1 = r4
+ 43f6: f7 8c goto -0x28
+ 43f8: 12 07 r2 = b[r1++=0x1] (u)
+ 43fa: 82 07 b[r0++=0x1] = r2
+ 43fc: f2 5d if (r2 != 0) goto -0x6
+ 43fe: 70 16 r0 = r7
+ 4400: 57 04 {pc, r7-r4} = [sp++]
+
+
+strlen:
+ 4402: 01 16 r1 = r0
+ 4404: 12 07 r2 = b[r1++=0x1] (u)
+ 4406: f2 5e if (r2 != 0) goto -0x4
+ 4408: f9 3f r1 += -0x1
+ 440a: 10 1e r0 = r1 - r0
+ 440c: 80 00 rts
+
+
+strncmp:
+ 440e: 74 04 [--sp] = {rets, r4}
+ 4410: 02 4c if (r2 == 0) goto 0x18
+ 4412: a2 e0 01 20 r2 = 0x1 - r2
+ 4416: 04 84 goto 0x8
+ 4418: 02 46 if (r2 == 0) goto 0xc
+ 441a: 83 e8 04 40 if (r4 != r3) goto 0x8
+ 441e: c2 21 r2 += 0x1
+ 4420: 13 07 r3 = b[r1++=0x1] (u)
+ 4422: 04 07 r4 = b[r0++=0x1] (u)
+ 4424: f4 59 if (r4 != 0) goto -0xe
+ 4426: c8 1e r0 = r4 - r3
+ 4428: 54 04 {pc, r4} = [sp++]
+ 442a: 40 20 r0 = 0x0
+ 442c: 54 04 {pc, r4} = [sp++]
+
+
+strstr:
+ 442e: 74 04 [--sp] = {rets, r4}
+ 4430: 0a 40 r2 = b[r0+0x0] (u)
+ 4432: 82 4f if (r2 != 0) goto 0x1e
+ 4434: 19 40 r1 = b[r1+0x0] (u)
+ 4436: 01 4f if (r1 == 0) goto 0x1e
+ 4438: 40 20 r0 = 0x0
+ 443a: 54 04 {pc, r4} = [sp++]
+ 443c: 42 20 r2 = 0x0
+ 443e: d8 ee 10 32 r3 = b[r1+r2] (u)
+ 4442: 03 49 if (r3 == 0) goto 0x12
+ 4444: d8 ee 00 42 r4 = b[r0+r2] (u)
+ 4448: c2 21 r2 += 0x1
+ 444a: 04 e8 f8 31 if (r3 == r4) goto -0x10
+ 444e: 58 ee 01 20 r2 = b[++r0=0x1] (u)
+ 4452: f2 54 if (r2 != 0) goto -0x18
+ 4454: f7 91 goto -0x1e
+ 4456: 54 04 {pc, r4} = [sp++]
+
+
+nvram_ota_tag:
+ 4458: 4f 54 41 85 66 3a 7b 63 OTA.f:{c
+
+
+nvram_uart_tag:
+ 4460: 75 61 72 74 d9 c4 05 a8 uart....
+
+
+nvram_usb_tag:
+ 4468: 75 73 62 ed 63 81 67 ef usb.c.g.
+
+
+nvram_boot_state:
+ 4470: 74 04 [--sp] = {rets, r4} ## boot_nvram.c:51:0
+ 4472: c4 ff 00 08 18 00 r4 = 0x180800 ## boot_nvram.c:51:0
+ 4478: c1 ff 68 44 00 00 r1 = 0x4468