commit 2914489fe665ea8df89e1773371dbcf26021eb9f Author: Wuchuyuan <1917507415@qq.com> Date: Fri Sep 4 10:33:31 2026 +0800 生成的代码包 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fb83704 --- /dev/null +++ b/.gitignore @@ -0,0 +1,107 @@ +# ============================================================================= +# AC701N (杰理 BR28) SDK - Git 忽略规则 +# ============================================================================= + +# ----------------------------------------------------------------------------- +# 编译输出目录(CodeBlocks / Makefile 生成) +# ----------------------------------------------------------------------------- +obj/ +**/obj/ +*.o +*.d +*.dep +*.obj + +# ----------------------------------------------------------------------------- +# CodeBlocks 工程临时文件(保留 AC701N.cbp) +# ----------------------------------------------------------------------------- +*.depend +*.layout +*.cbTemp +*.workspace + +# ----------------------------------------------------------------------------- +# 链接 / 编译中间产物(cpu/br28/tools 下生成) +# 注意:不要用 cpu/*/tools/*.bin —— 根目录 aac.bin/ota.bin 等是 SDK 要入库的 +# ----------------------------------------------------------------------------- +cpu/*/tools/sdk.elf +cpu/*/tools/sdk.elf.* +cpu/*/tools/sdk.map +cpu/*/tools/rom.lst +cpu/*/tools/app.bin +cpu/*/tools/data_code.bin +cpu/*/tools/p11_code.bin +cpu/*/tools/*.bc + +# 打包下载目录:每次烧录会拷贝固件、改写 .bat(可能注入 -key),不要入库 +cpu/*/tools/download/**/*.bin +cpu/*/tools/download/**/*.fw +cpu/*/tools/download/**/*.ufw +cpu/*/tools/download/**/*.hex +cpu/*/tools/download/**/*.bat + +# 配置工具本地数据库 +cpu/*/tools/local.db + +# ----------------------------------------------------------------------------- +# WorkBuddy / Cursor 本地会话(记忆、产物、规则缓存) +# ----------------------------------------------------------------------------- +.workbuddy/ +.cursor/ + +# ----------------------------------------------------------------------------- +# IDE / 编辑器 +# ----------------------------------------------------------------------------- +.vscode/ +.idea/ +*.user +*.suo +*.ncb +*.aps +*.opt +*.plg +*.clw +*.pdb +*.idb +*.ilk + +# ----------------------------------------------------------------------------- +# 操作系统杂项 +# ----------------------------------------------------------------------------- +.DS_Store +.DS_Store? +._* +Thumbs.db +ehthumbs.db +Desktop.ini +$RECYCLE.BIN/ + +# ----------------------------------------------------------------------------- +# 临时 / 备份 / 日志 +# ----------------------------------------------------------------------------- +*~ +*.tmp +*.temp +*.bak +*.swp +*.swo +*.log +*.orig +*.rej + +# ----------------------------------------------------------------------------- +# Release 交付产物(由 tools/package_release.py 生成,勿提交) +# ----------------------------------------------------------------------------- +release/ +Release_Project_*/ + +# ----------------------------------------------------------------------------- +# 注意:以下内容请保留上传,不要忽略 +# - cpu/br28/liba/*.a SDK 预编译库 +# - apps/usr_le_code/lib/*.a 见宝 BLE 预编译库(无 intentional 改动不要提交) +# - AC701N.cbp / Makefile 工程文件 +# - cpu/br28/tools/*.exe 等 下载/打包工具 +# - cpu/br28/tools/*.bin SDK 资源(ota.bin 等) +# - include_lib/ / apps/ 头文件与应用源码 +# - Doc/ 需求规格书 +# ----------------------------------------------------------------------------- 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/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..8a91f3e --- /dev/null +++ b/apps/usr_jb_proto/Protocol/jb_product.c @@ -0,0 +1,358 @@ +/* ================================================================ + * jb_product.c — 用户层实现(请填补空白处) + * 设备: 电子开关-加热垫 | 生成时间: 2026-09-04 10:30:37 + * + * ══ 开发流程 ══ + * 1. 实现硬件抽象: jbGetTimerCount(定时器由 SOC SDK 提供) + * 发送由 SOC SDK 的 ble_send_data 承担,协议层已直接调用,无需 uartWrite + * 2. userInit() 设置 DP 默认值与外设初始化 + * 3. userHandle() 用户数据采集 + * 4. jbEventProcess() 处理 APP 下发的控制命令 + * 5. 主动上报 / OTA 的网关应答在收到 REPORTCMD_V2 后调用 jbReportAckCheck 清除等待 + * ================================================================ + */ + +#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.heat_switch = 0; /* DP0 加热开关 0=关 1=开 */ + gDevData.temp_control_switch = 0; /* DP1 温控开关 0=关 1=开 */ + memset(gDevData.temp_control_time, 0, 4); /* DP2 温控时间 */ + gDevData.mode = 0; /* MODE_0 (??) */ + gDevData.min_temp = 0.0f; /* DP4 最低温度 (float) */ + gDevData.max_temp = 0.0f; /* DP5 最高温度 (float) */ + gDevData.current_temp = 0.0f; /* DP6 当前温度 (float) */ + gDevData.linkage_delete = 0; /* DP7 联动删除 0=关 1=开 */ + memset(gDevData.linkage_config, 0, 20); /* DP8 联动配置 */ + gDevData.time_en = 0; /* DP9 定时使能 0=关 1=开 */ + memset(gDevData.time_config1, 0, 8); /* DP10 定时配置1 */ + memset(gDevData.time_config2, 0, 8); /* DP11 定时配置2 */ + memset(gDevData.time_config3, 0, 8); /* DP12 定时配置3 */ + memset(gDevData.time_config4, 0, 8); /* DP13 定时配置4 */ + memset(gDevData.time_config5, 0, 8); /* DP14 定时配置5 */ + memset(gDevData.time_config6, 0, 8); /* DP15 定时配置6 */ + memset(gDevData.time_config7, 0, 8); /* DP16 定时配置7 */ + memset(gDevData.run_record, 0, 124); /* DP17 运行记录 */ + gDevData.heartbeat = 0; /* DP18 心跳 0=关 1=开 */ + gDevData.fault_en = 0; /* DP19 设备故障使能 */ + gDevData.fault_code = 0; /* DP20 设备故障 */ + gDevData.alarm_en = 0; /* DP21 设备告警使能 */ + gDevData.alarm_code = 0; /* DP22 设备告警 */ + gDevData.factory_reset = 0; /* DP23 恢复出厂设置 0=关 1=开 */ + gDevData.reserva_dp1 = 0; /* DP24 预留DP1 */ + gDevData.reserva_dp2 = 0; /* DP25 预留DP2 */ + gDevData.reserva_dp3 = 0; /* DP26 预留DP3 */ +} + +/* ════════════════════════════════════════════════════════════════ + * userHandle — 用户数据采集 + * 协议层自动检测变化并上报(注意:此处是上报,不是下发控制) + * ════════════════════════════════════════════════════════════════ */ +void userHandle(void) +{ + /* ── 可上报 DP (RO / RW): 用户数据采集 ── */ + // gDevData.heat_switch = read_sensor(); /* DP0 加热开关 */ + // gDevData.temp_control_switch = read_sensor(); /* DP1 温控开关 */ + // memcpy(gDevData.temp_control_time, sensor_read(), 4); /* DP2 温控时间 */ + // gDevData.mode = read_sensor(); /* DP3 模式 */ + // gDevData.min_temp = 23.5f; /* DP4 最低温度 (float, scale=0.1), 直接填物理量 */ + // gDevData.max_temp = 23.5f; /* DP5 最高温度 (float, scale=0.1), 直接填物理量 */ + // gDevData.current_temp = 23.5f; /* DP6 当前温度 (float, scale=0.1), 直接填物理量 */ + // gDevData.linkage_delete = read_sensor(); /* DP7 联动删除 */ + // memcpy(gDevData.linkage_config, sensor_read(), 20); /* DP8 联动配置 */ + // gDevData.time_en = read_sensor(); /* DP9 定时使能 */ + // memcpy(gDevData.time_config1, sensor_read(), 8); /* DP10 定时配置1 */ + // memcpy(gDevData.time_config2, sensor_read(), 8); /* DP11 定时配置2 */ + // memcpy(gDevData.time_config3, sensor_read(), 8); /* DP12 定时配置3 */ + // memcpy(gDevData.time_config4, sensor_read(), 8); /* DP13 定时配置4 */ + // memcpy(gDevData.time_config5, sensor_read(), 8); /* DP14 定时配置5 */ + // memcpy(gDevData.time_config6, sensor_read(), 8); /* DP15 定时配置6 */ + // memcpy(gDevData.time_config7, sensor_read(), 8); /* DP16 定时配置7 */ + // memcpy(gDevData.run_record, sensor_read(), 124); /* DP17 运行记录 */ + // gDevData.fault_en = read_sensor(); /* DP19 设备故障使能 */ + // gDevData.fault_code = read_sensor(); /* DP20 设备故障 */ + // gDevData.alarm_en = read_sensor(); /* DP21 设备告警使能 */ + // gDevData.alarm_code = read_sensor(); /* DP22 设备告警 */ + // gDevData.reserva_dp1 = read_sensor(); /* DP24 预留DP1 */ + // gDevData.reserva_dp2 = read_sensor(); /* DP25 预留DP2 */ + // gDevData.reserva_dp3 = read_sensor(); /* DP26 预留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_HEAT_SWITCH: + if (ctrl->heat_switch) + { + gDevData.heat_switch = 1; + // TODO: 开 — 执行动作 + } + else + { + gDevData.heat_switch = 0; + // TODO: 关 — 执行动作 + } + break; + + /* ── DP1 温控开关 (bool) ── */ + case DP_ID_TEMP_CONTROL_SWITCH: + if (ctrl->temp_control_switch) + { + gDevData.temp_control_switch = 1; + // TODO: 开 — 执行动作 + } + else + { + gDevData.temp_control_switch = 0; + // TODO: 关 — 执行动作 + } + break; + + /* ── DP2 温控时间 (raw) ── */ + case DP_ID_TEMP_CONTROL_TIME: + memcpy(gDevData.temp_control_time, ctrl->temp_control_time, 4); + // TODO: 根据 gDevData.temp_control_time 执行动作 (长度 4 字节) + break; + + /* ── DP3 模式 (enum) ── */ + case DP_ID_MODE: + gDevData.mode = ctrl->mode; + // TODO: 根据 ctrl->mode 执行动作 + break; + + /* ── DP4 最低温度 (float, scale=0.1) ── */ + case DP_ID_MIN_TEMP: + gDevData.min_temp = ctrl->min_temp; + // TODO: 根据 ctrl->min_temp 执行动作 (已是浮点物理量) + break; + + /* ── DP5 最高温度 (float, scale=0.1) ── */ + case DP_ID_MAX_TEMP: + gDevData.max_temp = ctrl->max_temp; + // TODO: 根据 ctrl->max_temp 执行动作 (已是浮点物理量) + break; + + /* ── DP7 联动删除 (bool) ── */ + case DP_ID_LINKAGE_DELETE: + if (ctrl->linkage_delete) + { + gDevData.linkage_delete = 1; + // TODO: 开 — 执行动作 + } + else + { + gDevData.linkage_delete = 0; + // TODO: 关 — 执行动作 + } + break; + + /* ── DP8 联动配置 (raw) ── */ + case DP_ID_LINKAGE_CONFIG: + memcpy(gDevData.linkage_config, ctrl->linkage_config, 20); + // TODO: 根据 gDevData.linkage_config 执行动作 (长度 20 字节) + break; + + /* ── DP9 定时使能 (bool) ── */ + case DP_ID_TIME_EN: + if (ctrl->time_en) + { + gDevData.time_en = 1; + // TODO: 开 — 执行动作 + } + else + { + gDevData.time_en = 0; + // TODO: 关 — 执行动作 + } + break; + + /* ── DP10 定时配置1 (raw) ── */ + case DP_ID_TIME_CONFIG1: + memcpy(gDevData.time_config1, ctrl->time_config1, 8); + // TODO: 根据 gDevData.time_config1 执行动作 (长度 8 字节) + break; + + /* ── DP11 定时配置2 (raw) ── */ + case DP_ID_TIME_CONFIG2: + memcpy(gDevData.time_config2, ctrl->time_config2, 8); + // TODO: 根据 gDevData.time_config2 执行动作 (长度 8 字节) + break; + + /* ── DP12 定时配置3 (raw) ── */ + case DP_ID_TIME_CONFIG3: + memcpy(gDevData.time_config3, ctrl->time_config3, 8); + // TODO: 根据 gDevData.time_config3 执行动作 (长度 8 字节) + break; + + /* ── DP13 定时配置4 (raw) ── */ + case DP_ID_TIME_CONFIG4: + memcpy(gDevData.time_config4, ctrl->time_config4, 8); + // TODO: 根据 gDevData.time_config4 执行动作 (长度 8 字节) + break; + + /* ── DP14 定时配置5 (raw) ── */ + case DP_ID_TIME_CONFIG5: + memcpy(gDevData.time_config5, ctrl->time_config5, 8); + // TODO: 根据 gDevData.time_config5 执行动作 (长度 8 字节) + break; + + /* ── DP15 定时配置6 (raw) ── */ + case DP_ID_TIME_CONFIG6: + memcpy(gDevData.time_config6, ctrl->time_config6, 8); + // TODO: 根据 gDevData.time_config6 执行动作 (长度 8 字节) + break; + + /* ── DP16 定时配置7 (raw) ── */ + case DP_ID_TIME_CONFIG7: + memcpy(gDevData.time_config7, ctrl->time_config7, 8); + // TODO: 根据 gDevData.time_config7 执行动作 (长度 8 字节) + break; + + /* ── DP18 心跳 (bool) ── */ + case DP_ID_HEARTBEAT: + if (ctrl->heartbeat) + { + gDevData.heartbeat = 1; + // TODO: 开 — 执行动作 + } + else + { + gDevData.heartbeat = 0; + // TODO: 关 — 执行动作 + } + break; + + /* ── DP19 设备故障使能 (uint8) ── */ + case DP_ID_FAULT_EN: + gDevData.fault_en = ctrl->fault_en; + // TODO: 根据 ctrl->fault_en 执行动作 + break; + + /* ── DP21 设备告警使能 (uint8) ── */ + case DP_ID_ALARM_EN: + gDevData.alarm_en = ctrl->alarm_en; + // TODO: 根据 ctrl->alarm_en 执行动作 + break; + + /* ── DP23 恢复出厂设置 (bool) ── */ + case DP_ID_FACTORY_RESET: + if (ctrl->factory_reset) + { + gDevData.factory_reset = 1; + // TODO: 开 — 执行动作 + } + else + { + gDevData.factory_reset = 0; + // TODO: 关 — 执行动作 + } + break; + + /* ── DP24 预留DP1 (uint32) ── */ + case DP_ID_RESERVA_DP1: + gDevData.reserva_dp1 = ctrl->reserva_dp1; + // TODO: 根据 ctrl->reserva_dp1 执行动作 + break; + + /* ── DP25 预留DP2 (uint32) ── */ + case DP_ID_RESERVA_DP2: + gDevData.reserva_dp2 = ctrl->reserva_dp2; + // TODO: 根据 ctrl->reserva_dp2 执行动作 + break; + + /* ── DP26 预留DP3 (uint32) ── */ + case DP_ID_RESERVA_DP3: + gDevData.reserva_dp3 = ctrl->reserva_dp3; + // TODO: 根据 ctrl->reserva_dp3 执行动作 + break; + + default: + break; + } + } + return 0; +} + +/* 0x30 OTA 升级请求 + * 返回 0=接受升级(协议层应答 JB_OK + MaxDataLen) + * 非 0=拒绝,返回值即错误码(JB_OTA_*) + * + * ⚠ SOC 侧 OTA 尚未实现:当前仅应答,不执行任何升级动作。 */ +int8_t jbOnOtaNotify(uint32_t fwVersion, uint32_t fwLength, uint32_t fwCrc32) +{ + (void)fwVersion; (void)fwLength; (void)fwCrc32; + // TODO: 检查 Flash 空间与版本,决定是否接收升级 + // 允许: 返回 JB_OK(协议层应答 JB_OK + MaxDataLen) + // 拒绝: 返回对应 JB_OTA_* 错误码(如 JB_OTA_VER_LOW / JB_OTA_SPACE_ERR) + return JB_OK; +} + +/* 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; +} 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..b1f04b1 --- /dev/null +++ b/apps/usr_jb_proto/Protocol/jb_product.h @@ -0,0 +1,55 @@ +/* ================================================================ + * jb_product.h — 用户层头文件(自动生成) + * 设备: 电子开关-加热垫 | 生成时间: 2026-09-04 10:30:37 + * + * 声明用户需实现的函数。数据结构定义见 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 控制事件 */ +/* int8_t 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..31f8fe8 --- /dev/null +++ b/apps/usr_jb_proto/Protocol/jb_protocol.c @@ -0,0 +1,1124 @@ +/* ================================================================ + * jb_protocol.c — 见宝 IOT 协议实现(自动生成) + * 设备: 电子开关-加热垫 | 生成时间: 2026-09-04 10:30:37 + * ================================================================ + */ + +#include "jb_protocol.h" +#include "jb_common.h" +#include "jb_product.h" +#include "jb_ringbuffer.h" +#include "stdio.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_HEAT_SWITCH / 8] & (1 << (DP_ID_HEAT_SWITCH % 8))) + { + bitmap[DP_ID_HEAT_SWITCH / 8] |= (1 << (DP_ID_HEAT_SWITCH % 8)); + out[valIdx++] = dp->heat_switch ? 1 : 0; + } + /* DP1 温控开关 (bool, 1B, RW) */ + if (mask[DP_ID_TEMP_CONTROL_SWITCH / 8] & (1 << (DP_ID_TEMP_CONTROL_SWITCH % 8))) + { + bitmap[DP_ID_TEMP_CONTROL_SWITCH / 8] |= (1 << (DP_ID_TEMP_CONTROL_SWITCH % 8)); + out[valIdx++] = dp->temp_control_switch ? 1 : 0; + } + /* DP2 温控时间 (raw, 4B, RW) */ + if (mask[DP_ID_TEMP_CONTROL_TIME / 8] & (1 << (DP_ID_TEMP_CONTROL_TIME % 8))) + { + bitmap[DP_ID_TEMP_CONTROL_TIME / 8] |= (1 << (DP_ID_TEMP_CONTROL_TIME % 8)); + memcpy(&out[valIdx], dp->temp_control_time, 4); + valIdx += 4; + } + /* DP3 模式 (enum, 1B, RW) */ + if (mask[DP_ID_MODE / 8] & (1 << (DP_ID_MODE % 8))) + { + bitmap[DP_ID_MODE / 8] |= (1 << (DP_ID_MODE % 8)); + out[valIdx++] = (uint8_t)dp->mode; + } + /* DP4 最低温度 (float, 2B, RW (float, scale=0.1)) */ + if (mask[DP_ID_MIN_TEMP / 8] & (1 << (DP_ID_MIN_TEMP % 8))) + { + bitmap[DP_ID_MIN_TEMP / 8] |= (1 << (DP_ID_MIN_TEMP % 8)); + int16_t _raw = (int16_t)(dp->min_temp * 10.0f); + jbWriteU16BE(&out[valIdx], (uint16_t)_raw); + valIdx += 2; + } + /* DP5 最高温度 (float, 2B, RW (float, scale=0.1)) */ + if (mask[DP_ID_MAX_TEMP / 8] & (1 << (DP_ID_MAX_TEMP % 8))) + { + bitmap[DP_ID_MAX_TEMP / 8] |= (1 << (DP_ID_MAX_TEMP % 8)); + int16_t _raw = (int16_t)(dp->max_temp * 10.0f); + jbWriteU16BE(&out[valIdx], (uint16_t)_raw); + valIdx += 2; + } + /* DP6 当前温度 (float, 2B, RO (float, scale=0.1)) */ + if (mask[DP_ID_CURRENT_TEMP / 8] & (1 << (DP_ID_CURRENT_TEMP % 8))) + { + bitmap[DP_ID_CURRENT_TEMP / 8] |= (1 << (DP_ID_CURRENT_TEMP % 8)); + int16_t _raw = (int16_t)(dp->current_temp * 10.0f); + jbWriteU16BE(&out[valIdx], (uint16_t)_raw); + valIdx += 2; + } + /* DP7 联动删除 (bool, 1B, RW) */ + if (mask[DP_ID_LINKAGE_DELETE / 8] & (1 << (DP_ID_LINKAGE_DELETE % 8))) + { + bitmap[DP_ID_LINKAGE_DELETE / 8] |= (1 << (DP_ID_LINKAGE_DELETE % 8)); + out[valIdx++] = dp->linkage_delete ? 1 : 0; + } + /* DP8 联动配置 (raw, 20B, RW) */ + if (mask[DP_ID_LINKAGE_CONFIG / 8] & (1 << (DP_ID_LINKAGE_CONFIG % 8))) + { + bitmap[DP_ID_LINKAGE_CONFIG / 8] |= (1 << (DP_ID_LINKAGE_CONFIG % 8)); + memcpy(&out[valIdx], dp->linkage_config, 20); + valIdx += 20; + } + /* DP9 定时使能 (bool, 1B, RW) */ + if (mask[DP_ID_TIME_EN / 8] & (1 << (DP_ID_TIME_EN % 8))) + { + bitmap[DP_ID_TIME_EN / 8] |= (1 << (DP_ID_TIME_EN % 8)); + out[valIdx++] = dp->time_en ? 1 : 0; + } + /* DP10 定时配置1 (raw, 8B, RW) */ + if (mask[DP_ID_TIME_CONFIG1 / 8] & (1 << (DP_ID_TIME_CONFIG1 % 8))) + { + bitmap[DP_ID_TIME_CONFIG1 / 8] |= (1 << (DP_ID_TIME_CONFIG1 % 8)); + memcpy(&out[valIdx], dp->time_config1, 8); + valIdx += 8; + } + /* DP11 定时配置2 (raw, 8B, RW) */ + if (mask[DP_ID_TIME_CONFIG2 / 8] & (1 << (DP_ID_TIME_CONFIG2 % 8))) + { + bitmap[DP_ID_TIME_CONFIG2 / 8] |= (1 << (DP_ID_TIME_CONFIG2 % 8)); + memcpy(&out[valIdx], dp->time_config2, 8); + valIdx += 8; + } + /* DP12 定时配置3 (raw, 8B, RW) */ + if (mask[DP_ID_TIME_CONFIG3 / 8] & (1 << (DP_ID_TIME_CONFIG3 % 8))) + { + bitmap[DP_ID_TIME_CONFIG3 / 8] |= (1 << (DP_ID_TIME_CONFIG3 % 8)); + memcpy(&out[valIdx], dp->time_config3, 8); + valIdx += 8; + } + /* DP13 定时配置4 (raw, 8B, RW) */ + if (mask[DP_ID_TIME_CONFIG4 / 8] & (1 << (DP_ID_TIME_CONFIG4 % 8))) + { + bitmap[DP_ID_TIME_CONFIG4 / 8] |= (1 << (DP_ID_TIME_CONFIG4 % 8)); + memcpy(&out[valIdx], dp->time_config4, 8); + valIdx += 8; + } + /* DP14 定时配置5 (raw, 8B, RW) */ + if (mask[DP_ID_TIME_CONFIG5 / 8] & (1 << (DP_ID_TIME_CONFIG5 % 8))) + { + bitmap[DP_ID_TIME_CONFIG5 / 8] |= (1 << (DP_ID_TIME_CONFIG5 % 8)); + memcpy(&out[valIdx], dp->time_config5, 8); + valIdx += 8; + } + /* DP15 定时配置6 (raw, 8B, RW) */ + if (mask[DP_ID_TIME_CONFIG6 / 8] & (1 << (DP_ID_TIME_CONFIG6 % 8))) + { + bitmap[DP_ID_TIME_CONFIG6 / 8] |= (1 << (DP_ID_TIME_CONFIG6 % 8)); + memcpy(&out[valIdx], dp->time_config6, 8); + valIdx += 8; + } + /* DP16 定时配置7 (raw, 8B, RW) */ + if (mask[DP_ID_TIME_CONFIG7 / 8] & (1 << (DP_ID_TIME_CONFIG7 % 8))) + { + bitmap[DP_ID_TIME_CONFIG7 / 8] |= (1 << (DP_ID_TIME_CONFIG7 % 8)); + memcpy(&out[valIdx], dp->time_config7, 8); + valIdx += 8; + } + /* DP17 运行记录 (raw, 124B, RO) */ + if (mask[DP_ID_RUN_RECORD / 8] & (1 << (DP_ID_RUN_RECORD % 8))) + { + bitmap[DP_ID_RUN_RECORD / 8] |= (1 << (DP_ID_RUN_RECORD % 8)); + memcpy(&out[valIdx], dp->run_record, 124); + valIdx += 124; + } + /* DP19 设备故障使能 (uint8, 1B, RW) */ + if (mask[DP_ID_FAULT_EN / 8] & (1 << (DP_ID_FAULT_EN % 8))) + { + bitmap[DP_ID_FAULT_EN / 8] |= (1 << (DP_ID_FAULT_EN % 8)); + out[valIdx++] = (uint8_t)dp->fault_en; + } + /* DP20 设备故障 (uint8, 1B, RO) */ + if (mask[DP_ID_FAULT_CODE / 8] & (1 << (DP_ID_FAULT_CODE % 8))) + { + bitmap[DP_ID_FAULT_CODE / 8] |= (1 << (DP_ID_FAULT_CODE % 8)); + out[valIdx++] = (uint8_t)dp->fault_code; + } + /* DP21 设备告警使能 (uint8, 1B, RW) */ + if (mask[DP_ID_ALARM_EN / 8] & (1 << (DP_ID_ALARM_EN % 8))) + { + bitmap[DP_ID_ALARM_EN / 8] |= (1 << (DP_ID_ALARM_EN % 8)); + out[valIdx++] = (uint8_t)dp->alarm_en; + } + /* DP22 设备告警 (uint8, 1B, RO) */ + if (mask[DP_ID_ALARM_CODE / 8] & (1 << (DP_ID_ALARM_CODE % 8))) + { + bitmap[DP_ID_ALARM_CODE / 8] |= (1 << (DP_ID_ALARM_CODE % 8)); + out[valIdx++] = (uint8_t)dp->alarm_code; + } + /* DP24 预留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; + } + /* DP25 预留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; + } + /* DP26 预留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_HEAT_SWITCH / 8] & (1 << (DP_ID_HEAT_SWITCH % 8))) + { + if (valIdx < valLen) + { + dp->heat_switch = (values[valIdx++] != 0); + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_HEAT_SWITCH; + } + } + /* DP1 温控开关 (bool, 1B, RW) */ + if (bitmap[DP_ID_TEMP_CONTROL_SWITCH / 8] & (1 << (DP_ID_TEMP_CONTROL_SWITCH % 8))) + { + if (valIdx < valLen) + { + dp->temp_control_switch = (values[valIdx++] != 0); + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_TEMP_CONTROL_SWITCH; + } + } + /* DP2 温控时间 (raw, 4B, RW) */ + if (bitmap[DP_ID_TEMP_CONTROL_TIME / 8] & (1 << (DP_ID_TEMP_CONTROL_TIME % 8))) + { + if (valIdx + 4 <= valLen) + { + memcpy(dp->temp_control_time, &values[valIdx], 4); + valIdx += 4; + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_TEMP_CONTROL_TIME; + } + } + /* DP3 模式 (enum, 1B, RW) */ + if (bitmap[DP_ID_MODE / 8] & (1 << (DP_ID_MODE % 8))) + { + if (valIdx < valLen) + { + dp->mode = values[valIdx++]; + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_MODE; + } + } + /* DP4 最低温度 (float, 2B, RW (float, scale=0.1)) */ + if (bitmap[DP_ID_MIN_TEMP / 8] & (1 << (DP_ID_MIN_TEMP % 8))) + { + if (valIdx + 2 <= valLen) + { + int16_t _raw = (int16_t)jbReadU16BE(&values[valIdx]); + dp->min_temp = (float)_raw * 0.1f; + valIdx += 2; + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_MIN_TEMP; + } + } + /* DP5 最高温度 (float, 2B, RW (float, scale=0.1)) */ + if (bitmap[DP_ID_MAX_TEMP / 8] & (1 << (DP_ID_MAX_TEMP % 8))) + { + if (valIdx + 2 <= valLen) + { + int16_t _raw = (int16_t)jbReadU16BE(&values[valIdx]); + dp->max_temp = (float)_raw * 0.1f; + valIdx += 2; + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_MAX_TEMP; + } + } + /* DP7 联动删除 (bool, 1B, RW) */ + if (bitmap[DP_ID_LINKAGE_DELETE / 8] & (1 << (DP_ID_LINKAGE_DELETE % 8))) + { + if (valIdx < valLen) + { + dp->linkage_delete = (values[valIdx++] != 0); + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_LINKAGE_DELETE; + } + } + /* DP8 联动配置 (raw, 20B, RW) */ + if (bitmap[DP_ID_LINKAGE_CONFIG / 8] & (1 << (DP_ID_LINKAGE_CONFIG % 8))) + { + if (valIdx + 20 <= valLen) + { + memcpy(dp->linkage_config, &values[valIdx], 20); + valIdx += 20; + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_LINKAGE_CONFIG; + } + } + /* DP9 定时使能 (bool, 1B, RW) */ + if (bitmap[DP_ID_TIME_EN / 8] & (1 << (DP_ID_TIME_EN % 8))) + { + if (valIdx < valLen) + { + dp->time_en = (values[valIdx++] != 0); + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_TIME_EN; + } + } + /* DP10 定时配置1 (raw, 8B, RW) */ + if (bitmap[DP_ID_TIME_CONFIG1 / 8] & (1 << (DP_ID_TIME_CONFIG1 % 8))) + { + if (valIdx + 8 <= valLen) + { + memcpy(dp->time_config1, &values[valIdx], 8); + valIdx += 8; + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_TIME_CONFIG1; + } + } + /* DP11 定时配置2 (raw, 8B, RW) */ + if (bitmap[DP_ID_TIME_CONFIG2 / 8] & (1 << (DP_ID_TIME_CONFIG2 % 8))) + { + if (valIdx + 8 <= valLen) + { + memcpy(dp->time_config2, &values[valIdx], 8); + valIdx += 8; + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_TIME_CONFIG2; + } + } + /* DP12 定时配置3 (raw, 8B, RW) */ + if (bitmap[DP_ID_TIME_CONFIG3 / 8] & (1 << (DP_ID_TIME_CONFIG3 % 8))) + { + if (valIdx + 8 <= valLen) + { + memcpy(dp->time_config3, &values[valIdx], 8); + valIdx += 8; + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_TIME_CONFIG3; + } + } + /* DP13 定时配置4 (raw, 8B, RW) */ + if (bitmap[DP_ID_TIME_CONFIG4 / 8] & (1 << (DP_ID_TIME_CONFIG4 % 8))) + { + if (valIdx + 8 <= valLen) + { + memcpy(dp->time_config4, &values[valIdx], 8); + valIdx += 8; + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_TIME_CONFIG4; + } + } + /* DP14 定时配置5 (raw, 8B, RW) */ + if (bitmap[DP_ID_TIME_CONFIG5 / 8] & (1 << (DP_ID_TIME_CONFIG5 % 8))) + { + if (valIdx + 8 <= valLen) + { + memcpy(dp->time_config5, &values[valIdx], 8); + valIdx += 8; + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_TIME_CONFIG5; + } + } + /* DP15 定时配置6 (raw, 8B, RW) */ + if (bitmap[DP_ID_TIME_CONFIG6 / 8] & (1 << (DP_ID_TIME_CONFIG6 % 8))) + { + if (valIdx + 8 <= valLen) + { + memcpy(dp->time_config6, &values[valIdx], 8); + valIdx += 8; + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_TIME_CONFIG6; + } + } + /* DP16 定时配置7 (raw, 8B, RW) */ + if (bitmap[DP_ID_TIME_CONFIG7 / 8] & (1 << (DP_ID_TIME_CONFIG7 % 8))) + { + if (valIdx + 8 <= valLen) + { + memcpy(dp->time_config7, &values[valIdx], 8); + valIdx += 8; + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_TIME_CONFIG7; + } + } + /* DP18 心跳 (bool, 1B, WO) */ + if (bitmap[DP_ID_HEARTBEAT / 8] & (1 << (DP_ID_HEARTBEAT % 8))) + { + if (valIdx < valLen) + { + dp->heartbeat = (values[valIdx++] != 0); + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_HEARTBEAT; + } + } + /* DP19 设备故障使能 (uint8, 1B, RW) */ + if (bitmap[DP_ID_FAULT_EN / 8] & (1 << (DP_ID_FAULT_EN % 8))) + { + if (valIdx < valLen) + { + dp->fault_en = values[valIdx++]; + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_FAULT_EN; + } + } + /* DP21 设备告警使能 (uint8, 1B, RW) */ + if (bitmap[DP_ID_ALARM_EN / 8] & (1 << (DP_ID_ALARM_EN % 8))) + { + if (valIdx < valLen) + { + dp->alarm_en = values[valIdx++]; + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_ALARM_EN; + } + } + /* DP23 恢复出厂设置 (bool, 1B, WO) */ + if (bitmap[DP_ID_FACTORY_RESET / 8] & (1 << (DP_ID_FACTORY_RESET % 8))) + { + if (valIdx < valLen) + { + dp->factory_reset = (values[valIdx++] != 0); + } + if (info && info->count < DP_ID_MAX) + { + info->dp_ids[info->count++] = DP_ID_FACTORY_RESET; + } + } + /* DP24 预留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; + } + } + /* DP25 预留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; + } + } + /* DP26 预留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->heat_switch != cur->heat_switch) + { + mask[DP_ID_HEAT_SWITCH / 8] |= (1 << (DP_ID_HEAT_SWITCH % 8)); + hasChange = 1; + } + /* DP1 温控开关 */ + if (last->temp_control_switch != cur->temp_control_switch) + { + mask[DP_ID_TEMP_CONTROL_SWITCH / 8] |= (1 << (DP_ID_TEMP_CONTROL_SWITCH % 8)); + hasChange = 1; + } + /* DP2 温控时间 */ + if (memcmp(last->temp_control_time, cur->temp_control_time, 4)) + { + mask[DP_ID_TEMP_CONTROL_TIME / 8] |= (1 << (DP_ID_TEMP_CONTROL_TIME % 8)); + hasChange = 1; + } + /* DP3 模式 */ + if (last->mode != cur->mode) + { + mask[DP_ID_MODE / 8] |= (1 << (DP_ID_MODE % 8)); + hasChange = 1; + } + /* DP4 最低温度 */ + if ((int16_t)(last->min_temp * 10.0f) != (int16_t)(cur->min_temp * 10.0f)) + { + mask[DP_ID_MIN_TEMP / 8] |= (1 << (DP_ID_MIN_TEMP % 8)); + hasChange = 1; + } + /* DP5 最高温度 */ + if ((int16_t)(last->max_temp * 10.0f) != (int16_t)(cur->max_temp * 10.0f)) + { + mask[DP_ID_MAX_TEMP / 8] |= (1 << (DP_ID_MAX_TEMP % 8)); + hasChange = 1; + } + /* DP6 当前温度 */ + if ((int16_t)(last->current_temp * 10.0f) != (int16_t)(cur->current_temp * 10.0f)) + { + mask[DP_ID_CURRENT_TEMP / 8] |= (1 << (DP_ID_CURRENT_TEMP % 8)); + hasChange = 1; + } + /* DP7 联动删除 */ + if (last->linkage_delete != cur->linkage_delete) + { + mask[DP_ID_LINKAGE_DELETE / 8] |= (1 << (DP_ID_LINKAGE_DELETE % 8)); + hasChange = 1; + } + /* DP8 联动配置 */ + if (memcmp(last->linkage_config, cur->linkage_config, 20)) + { + mask[DP_ID_LINKAGE_CONFIG / 8] |= (1 << (DP_ID_LINKAGE_CONFIG % 8)); + hasChange = 1; + } + /* DP9 定时使能 */ + if (last->time_en != cur->time_en) + { + mask[DP_ID_TIME_EN / 8] |= (1 << (DP_ID_TIME_EN % 8)); + hasChange = 1; + } + /* DP10 定时配置1 */ + if (memcmp(last->time_config1, cur->time_config1, 8)) + { + mask[DP_ID_TIME_CONFIG1 / 8] |= (1 << (DP_ID_TIME_CONFIG1 % 8)); + hasChange = 1; + } + /* DP11 定时配置2 */ + if (memcmp(last->time_config2, cur->time_config2, 8)) + { + mask[DP_ID_TIME_CONFIG2 / 8] |= (1 << (DP_ID_TIME_CONFIG2 % 8)); + hasChange = 1; + } + /* DP12 定时配置3 */ + if (memcmp(last->time_config3, cur->time_config3, 8)) + { + mask[DP_ID_TIME_CONFIG3 / 8] |= (1 << (DP_ID_TIME_CONFIG3 % 8)); + hasChange = 1; + } + /* DP13 定时配置4 */ + if (memcmp(last->time_config4, cur->time_config4, 8)) + { + mask[DP_ID_TIME_CONFIG4 / 8] |= (1 << (DP_ID_TIME_CONFIG4 % 8)); + hasChange = 1; + } + /* DP14 定时配置5 */ + if (memcmp(last->time_config5, cur->time_config5, 8)) + { + mask[DP_ID_TIME_CONFIG5 / 8] |= (1 << (DP_ID_TIME_CONFIG5 % 8)); + hasChange = 1; + } + /* DP15 定时配置6 */ + if (memcmp(last->time_config6, cur->time_config6, 8)) + { + mask[DP_ID_TIME_CONFIG6 / 8] |= (1 << (DP_ID_TIME_CONFIG6 % 8)); + hasChange = 1; + } + /* DP16 定时配置7 */ + if (memcmp(last->time_config7, cur->time_config7, 8)) + { + mask[DP_ID_TIME_CONFIG7 / 8] |= (1 << (DP_ID_TIME_CONFIG7 % 8)); + hasChange = 1; + } + /* DP17 运行记录 */ + if (memcmp(last->run_record, cur->run_record, 124)) + { + mask[DP_ID_RUN_RECORD / 8] |= (1 << (DP_ID_RUN_RECORD % 8)); + hasChange = 1; + } + /* DP19 设备故障使能 */ + if (last->fault_en != cur->fault_en) + { + mask[DP_ID_FAULT_EN / 8] |= (1 << (DP_ID_FAULT_EN % 8)); + hasChange = 1; + } + /* DP20 设备故障 */ + if (last->fault_code != cur->fault_code) + { + mask[DP_ID_FAULT_CODE / 8] |= (1 << (DP_ID_FAULT_CODE % 8)); + hasChange = 1; + } + /* DP21 设备告警使能 */ + if (last->alarm_en != cur->alarm_en) + { + mask[DP_ID_ALARM_EN / 8] |= (1 << (DP_ID_ALARM_EN % 8)); + hasChange = 1; + } + /* DP22 设备告警 */ + if (last->alarm_code != cur->alarm_code) + { + mask[DP_ID_ALARM_CODE / 8] |= (1 << (DP_ID_ALARM_CODE % 8)); + hasChange = 1; + } + /* DP24 预留DP1 */ + if (last->reserva_dp1 != cur->reserva_dp1) + { + mask[DP_ID_RESERVA_DP1 / 8] |= (1 << (DP_ID_RESERVA_DP1 % 8)); + hasChange = 1; + } + /* DP25 预留DP2 */ + if (last->reserva_dp2 != cur->reserva_dp2) + { + mask[DP_ID_RESERVA_DP2 / 8] |= (1 << (DP_ID_RESERVA_DP2 % 8)); + hasChange = 1; + } + /* DP26 预留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]); + + /* 应答: 结果码 + 最大单包长度(2B)(协议原格式,3 字节) */ + int8_t otaRet = jbOnOtaNotify(fwVersion, fwLength, fwCrc32); + uint8_t ack[3]; + ack[0] = (otaRet == 0) ? JB_OK : (uint8_t)otaRet; + 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; + /* 先发本包 0x33 应答,再调用户回调满足「先回复、再重启」 */ + jbSendAck(CMD_OTA_DATA_ACK, sn, JB_OK); + jbOnOtaData(pData, dataLen, shardIdx, totalShards); +} + +/* ── 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..a8d4779 --- /dev/null +++ b/apps/usr_jb_proto/Protocol/jb_protocol.h @@ -0,0 +1,294 @@ +/* ================================================================ + * jb_protocol.h — 见宝 IOT 协议层(自动生成) + * 设备: 电子开关-加热垫 | DP 数: 27 | Bitmap: 4B + * 协议版本: V1.0 | 生成时间: 2026-09-04 10:30:37 + * + * 帧格式: [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 27 +#define DP_BITMAP_SIZE 4 + +#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: 取自 Excel 设备信息表的 ProdtCode / productCode。 + * JB_CATEGORY_CODE: 必须 4 字符 ASCII,供 BLE 广播 prodcode 使用 + * JB_PRODUCT_CODE : 必须 6 字符 ASCII,供 BLE 广播 pcode 使用 + * 模板未填时回退占位 XXXX / XXXXXX(仍需用户修改)。 + */ +#define JB_PROTOCOL_VERSION 0x0100 /* V1.0 */ +#define JB_CATEGORY_CODE "CBR1" +#define JB_PRODUCT_CODE "PRCBR1" +#define JB_DEVICE_SN 0x00 +#define JB_DEVICE_CAPABILITY 0ULL + +/* ════════════════════════════════════════════════════════════════ + * 命令码(见《SOC方案接入协议通讯文档》) + * ════════════════════════════════════════════════════════════════ */ +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_CONNECTING (1 << 0) /* 配网中 */ +#define WS_CONFIGURED (1 << 1) /* 已配网 */ +#define WS_RECONNECTING (1 << 2) /* 断线重连中 */ +#define WS_CLOUD_CONNECTED (1 << 3) /* 已连接到云 */ +#define WS_APP_ONLINE (1 << 4) /* App 在线 */ +#define WS_APP_DIRECT (1 << 5) /* App 直连 */ +#define WS_OTA_UPGRADING (1 << 6) /* 模组 OTA 升级中 */ +#define WS_RESERVED (1 << 7) /* 保留 */ + +/* ════════════════════════════════════════════════════════════════ + * 设备能力位图 (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) /* 日志功能 */ + +/* ════════════════════════════════════════════════════════════════ + * DP ID 枚举(从 Excel 自动生成) + * ════════════════════════════════════════════════════════════════ */ +typedef enum +{ + DP_ID_HEAT_SWITCH = 0, /* 加热开关 (bool, RW) */ + DP_ID_TEMP_CONTROL_SWITCH = 1, /* 温控开关 (bool, RW) */ + DP_ID_TEMP_CONTROL_TIME = 2, /* 温控时间 (raw, RW) */ + DP_ID_MODE = 3, /* 模式 (enum, RW) */ + DP_ID_MIN_TEMP = 4, /* 最低温度 (float, RW) */ + DP_ID_MAX_TEMP = 5, /* 最高温度 (float, RW) */ + DP_ID_CURRENT_TEMP = 6, /* 当前温度 (float, RO) */ + DP_ID_LINKAGE_DELETE = 7, /* 联动删除 (bool, RW) */ + DP_ID_LINKAGE_CONFIG = 8, /* 联动配置 (raw, RW) */ + DP_ID_TIME_EN = 9, /* 定时使能 (bool, RW) */ + DP_ID_TIME_CONFIG1 = 10, /* 定时配置1 (raw, RW) */ + DP_ID_TIME_CONFIG2 = 11, /* 定时配置2 (raw, RW) */ + DP_ID_TIME_CONFIG3 = 12, /* 定时配置3 (raw, RW) */ + DP_ID_TIME_CONFIG4 = 13, /* 定时配置4 (raw, RW) */ + DP_ID_TIME_CONFIG5 = 14, /* 定时配置5 (raw, RW) */ + DP_ID_TIME_CONFIG6 = 15, /* 定时配置6 (raw, RW) */ + DP_ID_TIME_CONFIG7 = 16, /* 定时配置7 (raw, RW) */ + DP_ID_RUN_RECORD = 17, /* 运行记录 (raw, RO) */ + DP_ID_HEARTBEAT = 18, /* 心跳 (bool, WO) */ + DP_ID_FAULT_EN = 19, /* 设备故障使能 (uint8, RW) */ + DP_ID_FAULT_CODE = 20, /* 设备故障 (uint8, RO) */ + DP_ID_ALARM_EN = 21, /* 设备告警使能 (uint8, RW) */ + DP_ID_ALARM_CODE = 22, /* 设备告警 (uint8, RO) */ + DP_ID_FACTORY_RESET = 23, /* 恢复出厂设置 (bool, WO) */ + DP_ID_RESERVA_DP1 = 24, /* 预留DP1 (uint32, RW) */ + DP_ID_RESERVA_DP2 = 25, /* 预留DP2 (uint32, RW) */ + DP_ID_RESERVA_DP3 = 26, /* 预留DP3 (uint32, RW) */ + DP_ID_MAX +} dp_id_t; + +/* DP 数据长度(字节) */ +#define DP_LEN_HEAT_SWITCH 1 +#define DP_LEN_TEMP_CONTROL_SWITCH 1 +#define DP_LEN_TEMP_CONTROL_TIME 4 +#define DP_LEN_MODE 1 +#define DP_LEN_MIN_TEMP 2 +#define DP_LEN_MAX_TEMP 2 +#define DP_LEN_CURRENT_TEMP 2 +#define DP_LEN_LINKAGE_DELETE 1 +#define DP_LEN_LINKAGE_CONFIG 20 +#define DP_LEN_TIME_EN 1 +#define DP_LEN_TIME_CONFIG1 8 +#define DP_LEN_TIME_CONFIG2 8 +#define DP_LEN_TIME_CONFIG3 8 +#define DP_LEN_TIME_CONFIG4 8 +#define DP_LEN_TIME_CONFIG5 8 +#define DP_LEN_TIME_CONFIG6 8 +#define DP_LEN_TIME_CONFIG7 8 +#define DP_LEN_RUN_RECORD 124 +#define DP_LEN_HEARTBEAT 1 +#define DP_LEN_FAULT_EN 1 +#define DP_LEN_FAULT_CODE 1 +#define DP_LEN_ALARM_EN 1 +#define DP_LEN_ALARM_CODE 1 +#define DP_LEN_FACTORY_RESET 1 +#define DP_LEN_RESERVA_DP1 4 +#define DP_LEN_RESERVA_DP2 4 +#define DP_LEN_RESERVA_DP3 4 + +/* ════════════════════════════════════════════════════════════════ + * 数据结构 + * ════════════════════════════════════════════════════════════════ */ + +/* 数据点 — 所有 DP 的当前值 */ +typedef struct +{ + uint8_t heat_switch; /* DP0 加热开关 */ + uint8_t temp_control_switch;/* DP1 温控开关 */ + uint8_t temp_control_time[4];/* DP2 温控时间 */ + uint8_t mode; /* DP3 模式 */ + float min_temp; /* DP4 最低温度 (float, scale=0.1) */ + float max_temp; /* DP5 最高温度 (float, scale=0.1) */ + float current_temp; /* DP6 当前温度 (float, scale=0.1) */ + uint8_t linkage_delete;/* DP7 联动删除 */ + uint8_t linkage_config[20];/* DP8 联动配置 */ + uint8_t time_en; /* DP9 定时使能 */ + uint8_t time_config1[8];/* DP10 定时配置1 */ + uint8_t time_config2[8];/* DP11 定时配置2 */ + uint8_t time_config3[8];/* DP12 定时配置3 */ + uint8_t time_config4[8];/* DP13 定时配置4 */ + uint8_t time_config5[8];/* DP14 定时配置5 */ + uint8_t time_config6[8];/* DP15 定时配置6 */ + uint8_t time_config7[8];/* DP16 定时配置7 */ + uint8_t run_record[124];/* DP17 运行记录 */ + uint8_t heartbeat; /* DP18 心跳 */ + uint8_t fault_en; /* DP19 设备故障使能 */ + uint8_t fault_code; /* DP20 设备故障 */ + uint8_t alarm_en; /* DP21 设备告警使能 */ + uint8_t alarm_code; /* DP22 设备告警 */ + uint8_t factory_reset;/* DP23 恢复出厂设置 */ + uint32_t reserva_dp1; /* DP24 预留DP1 */ + uint32_t reserva_dp2; /* DP25 预留DP2 */ + uint32_t reserva_dp3; /* DP26 预留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 事件回调 */ +int8_t jbOnOtaNotify(uint32_t fwVersion, uint32_t fwLength, uint32_t fwCrc32); /* 0x30, 返回0=接受,非0=拒绝码 */ +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..a9057fd0 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.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/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/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/download.c b/cpu/br28/tools/download.c new file mode 100644 index 0000000..a55c38d --- /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) // data-trans +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/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_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/run_jtag.sh b/cpu/br28/tools/run_jtag.sh new file mode 100644 index 0000000..018e370 --- /dev/null +++ b/cpu/br28/tools/run_jtag.sh @@ -0,0 +1,5 @@ +#!/bin/sh +#sleep 4 + +#-ex "detach" -ex "q" +/opt/gdb $1 -ex "target remote proxy:"${NICKNAME}"_jtag:9872" -ex "b exception_irq_handler" -ex "c" diff --git a/cpu/br28/tools/tone.cfg b/cpu/br28/tools/tone.cfg new file mode 100644 index 0000000..9101fa6 Binary files /dev/null and b/cpu/br28/tools/tone.cfg differ diff --git a/cpu/br28/tools/uboot.boot b/cpu/br28/tools/uboot.boot new file mode 100644 index 0000000..8ddaf1a Binary files /dev/null and b/cpu/br28/tools/uboot.boot differ diff --git a/cpu/br28/tools/uboot.boot_debug b/cpu/br28/tools/uboot.boot_debug new file mode 100644 index 0000000..78e5163 Binary files /dev/null and b/cpu/br28/tools/uboot.boot_debug differ diff --git a/cpu/br28/tools/uboot1111.boot b/cpu/br28/tools/uboot1111.boot new file mode 100644 index 0000000..3d1ce1e Binary files /dev/null and b/cpu/br28/tools/uboot1111.boot differ diff --git a/cpu/br28/tools/uboot1111.boot_debug b/cpu/br28/tools/uboot1111.boot_debug new file mode 100644 index 0000000..5ec2a7a Binary files /dev/null and b/cpu/br28/tools/uboot1111.boot_debug differ diff --git a/cpu/br28/tools/ufw_maker.exe b/cpu/br28/tools/ufw_maker.exe new file mode 100644 index 0000000..465f0c8 Binary files /dev/null and b/cpu/br28/tools/ufw_maker.exe differ diff --git a/cpu/br28/tools/下载目录工具更新.jlxproj b/cpu/br28/tools/下载目录工具更新.jlxproj new file mode 100644 index 0000000..cd1caaa --- /dev/null +++ b/cpu/br28/tools/下载目录工具更新.jlxproj @@ -0,0 +1,78 @@ +local rootDir = cfg.rootDir; + +local pkgman = rootDir .. "/pkgman.exe"; + +local req_pkgs = {"pkgman2"}; +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 pkgman2 = cfg:utilsGetPkg("pkgman2").run; + +local check_ret = cfg:runProg({pkgman2, "-b", rootDir, "--update"}); + + +if check_ret == 1 then + os.exit(0); +end + +if check_ret ~= 0 then + cfg:msgBox("warn", "软件包不是最新,可能会出现问题"); +end + +-- params +local product_name = "-"; +local dest_dir = cfg.dir; + +local req_local_pkgs = { + "fwadd", "isddownload", "ufwmaker", +}; +local check_local_prog = {pkgman2, "-b", dest_dir}; +local missing_local_pkgs = {}; +for k, v in pairs(req_local_pkgs) do + if cfg:utilsGetPkg(v) == nil then + table.insert(missing_local_pkgs, v) + end +end + +for k, v in pairs(req_local_pkgs) do table.insert(check_local_prog, v); end + +if (cfg:runProg(check_local_prog) ~= 0) then + cfg:msgBox("warn", "软件包不是最新,可能会出现问题"); +end + +local layout = cfg:vBox{ + cfg:stButton("查看当前本地软件版本", function () + cfg:runProg{pkgman2, "-b", dest_dir}; + end), + + cfg:stButton("检查更新", function () + local check_prog = {pkgman2, "-b", dest_dir}; + for k, v in pairs(req_local_pkgs) do table.insert(check_prog, v) end + if (cfg:runProg(check_prog) ~= 0) then + cfg:msgBox("warn", "软件包不是最新,可能会出现问题"); + else + cfg:msgBox("info", "已经是最新"); + end + end), +} + +cfg:addKeyInfo("jlxproj.title", "检查更新"); +cfg:addKeyInfo("jlxproj.width", "300"); +cfg:addKeyInfo("jlxproj.height", "200"); + +cfg:setLayout(layout) diff --git a/cpu/br28/tws_audio.c b/cpu/br28/tws_audio.c new file mode 100644 index 0000000..9fa6b69 --- /dev/null +++ b/cpu/br28/tws_audio.c @@ -0,0 +1,45 @@ +/***************************************************************** +>file name : tws_audio.c +>create time : Wed 08 Dec 2021 01:52:02 PM CST +>处理tws与audio模块相关的事件等技术交叉点 +*****************************************************************/ +#include "app_config.h" +#include "media/includes.h" +#include "system/includes.h" + +#if TCFG_USER_TWS_ENABLE +#include "btstack/avctp_user.h" +#include "bt_tws.h" + +extern int CONFIG_BTCTLER_TWS_ENABLE; +extern struct audio_dac_hdl dac_hdl; + +static void tws_audio_event_handler(struct sys_event *event) +{ + if (!CONFIG_BTCTLER_TWS_ENABLE) { + return; + } + + if (((u32)event->arg != SYS_BT_EVENT_FROM_TWS)) { + return; + } + + struct bt_event *e = &event->u.bt; + int state; + if (e->event == TWS_EVENT_CONNECTED) { + state = e->args[2]; + /* + * 当TWS连接时,并且确认要播放提示音,则提前进行DAC上电 + * 原因: DAC上电有较大延迟,会导致连接提示音的错位 + */ + if (!get_bt_tws_discon_dly_state() && (get_call_status() == BT_CALL_HANGUP) && !(state & TWS_STA_SBC_OPEN)) { +//考虑开了DEC2TWS_ENABLE不播提示音是情况 +#if !TCFG_DEC2TWS_ENABLE + audio_dac_try_power_on(&dac_hdl); +#endif/*!TCFG_DEC2TWS_ENABLE*/ + } + } +} + +SYS_EVENT_HANDLER(SYS_BT_EVENT, tws_audio_event_handler, 4); +#endif diff --git a/cpu/br28/uart_dev.c b/cpu/br28/uart_dev.c new file mode 100644 index 0000000..c5db823 --- /dev/null +++ b/cpu/br28/uart_dev.c @@ -0,0 +1,936 @@ +/** + * @file uart.c + * @author JL + * @brief 串口UART模块C文件 + * @version 1.2 + * @date 2018-11-22 + */ + +#include "asm/clock.h" +#include "asm/uart_dev.h" +#include "asm/cpu.h" +#include "generic/gpio.h" +#include "spinlock.h" + +#ifdef SUPPORT_MS_EXTENSIONS +#pragma bss_seg(".uart_bss") +#pragma data_seg(".uart_data") +#pragma const_seg(".uart_const") +#pragma code_seg(".uart_code") +#endif + +#define UART_CLK clk_get("uart") +#define UART_OT_CLK clk_get("lsb") + + + +static uart_bus_t uart0; +static uart_bus_t uart1; +static uart_bus_t uart2; + +/* _WEAK_ */ +/* extern */ +const u32 CONFIG_UART0_ENABLE = 1; + +/* _WEAK_ */ +/* extern */ +const u32 CONFIG_UART1_ENABLE = 1; + +/* _WEAK_ */ +/* extern */ +const u32 CONFIG_UART2_ENABLE = 1; + +/* _WEAK_ */ +/* extern */ +const u32 CONFIG_UART0_ENABLE_TX_DMA = 1; + +/* _WEAK_ */ +/* extern */ +const u32 CONFIG_UART1_ENABLE_TX_DMA = 1; + +/* _WEAK_ */ +/* extern */ +const u32 CONFIG_UART2_ENABLE_TX_DMA = 1; + +static u32 kfifo_get(KFIFO *kfifo, u8 *buffer, u32 len) +{ + unsigned int i; + len = MIN(len, kfifo->buf_in - kfifo->buf_out); + + i = MIN(len, kfifo->buf_size - (kfifo->buf_out & (kfifo->buf_size - 1))); + + memcpy(buffer, kfifo->buffer + (kfifo->buf_out & (kfifo->buf_size - 1)), i); + + memcpy(buffer + i, kfifo->buffer, len - i); + + kfifo->buf_out += len; + return len; + +} +static u32 kfifo_length(KFIFO *kfifo) +{ + return kfifo->buf_in - kfifo->buf_out; +} +/** + * @brief ut0发送一个byte + * + * @param a 要发送的字节 + */ +static void UT0_putbyte(char a) +{ + if (JL_UART0->CON0 & BIT(0)) { + JL_UART0->BUF = a; + __asm__ volatile("csync"); + while ((JL_UART0->CON0 & BIT(15)) == 0); + JL_UART0->CON0 |= BIT(13); + } +} +/** + * @brief ut0接收一个byte + * + * @param buf 字节存放地址 + * @param timeout 接收超时时间,单位1ms + * @return 返回0:接收失败;返回1:接收成功 + */ +static u8 UT0_getbyte(u8 *buf, u32 timeout) +{ + u32 _timeout, _t_sleep; + timeout = ut_msecs_to_jiffies(timeout); + if (JL_UART0->CON0 & BIT(6)) { + //DMA_MODE + if (!kfifo_length(&uart0.kfifo)) { + UT_OSSemPend(&uart0.sem_rx, timeout); + } + UT_OSSemSet(&uart0.sem_rx, 0); + + return kfifo_get(&uart0.kfifo, buf, 1); + } else { + _timeout = timeout + ut_get_jiffies(); + _t_sleep = ut_msecs_to_jiffies(10) + ut_get_jiffies(); + while (!(JL_UART0->CON0 & BIT(14))) { + if (timeout && time_before(_timeout, ut_get_jiffies())) { + return 0; + } + if (time_before(_t_sleep, ut_get_jiffies())) { + ut_sleep(); + _t_sleep = ut_msecs_to_jiffies(10) + ut_get_jiffies(); + } + } + *buf = JL_UART0->BUF; + JL_UART0->CON0 |= BIT(12); + __asm__ volatile("csync"); //make RX_PND_CLR taking effect + } + return 1; +} +/** + * @brief ut0中断函数 + */ +SET_INTERRUPT +static void UT0_isr_fun(void) +{ + u32 rx_len = 0; + if ((JL_UART0->CON0 & BIT(2)) && (JL_UART0->CON0 & BIT(15))) { + JL_UART0->CON0 |= BIT(13); + UT_OSSemPost(&uart0.sem_tx); + if (uart0.isr_cbfun) { + uart0.isr_cbfun(&uart0, UT_TX); + } + } + if ((JL_UART0->CON0 & BIT(3)) && (JL_UART0->CON0 & BIT(14))) { + JL_UART0->CON0 |= BIT(7); //DMA模式 + JL_UART0->CON0 |= BIT(12); //清RX PND + rx_len = JL_UART0->HRXCNT; //读当前串口接收数据的个数 + /* uart0.kfifo.buf_in += uart0.frame_length; //每满frame_length字节则产生一次中断 */ + uart0.kfifo.buf_in += rx_len; + UT_OSSemPost(&uart0.sem_rx); + if (uart0.isr_cbfun) { + uart0.isr_cbfun(&uart0, UT_RX); + } + } + if ((JL_UART0->CON0 & BIT(5)) && (JL_UART0->CON0 & BIT(11))) { + //OTCNT PND + JL_UART0->CON0 |= BIT(7); //DMA模式 + JL_UART0->CON0 |= BIT(10); //清OTCNT PND + JL_UART0->CON0 |= BIT(12); //清RX PND(这里的顺序不能改变,这里要清一次) + rx_len = JL_UART0->HRXCNT; //读当前串口接收数据的个数 + + if (rx_len) { + uart0.kfifo.buf_in += rx_len; + /* printf("%s() %d\n", __func__, __LINE__); */ + UT_OSSemPost(&uart0.sem_rx); + if (uart0.isr_cbfun) { + uart0.isr_cbfun(&uart0, UT_RX_OT); + } + } + } +} +/** + * @brief ut0接收字符串 + * + * @param buf 字符串存放首地址 + * @param len 预接收长度 + * @param timeout 接收超时时间,单位1ms + * @return 返回实际接收长度 + */ +static u32 UT0_read_buf(u8 *buf, u32 len, u32 timeout) +{ + u32 i; + u32 _timeout, _t_sleep; + if (len == 0) { + return 0; + } + timeout = ut_msecs_to_jiffies(timeout); + if (JL_UART0->CON0 & BIT(6)) { + + if (!kfifo_length(&uart0.kfifo)) { + UT_OSSemPend(&uart0.sem_rx, timeout); + } + UT_OSSemSet(&uart0.sem_rx, 0); + + return kfifo_get(&uart0.kfifo, buf, len); + } else { + _timeout = timeout + ut_get_jiffies(); + _t_sleep = ut_msecs_to_jiffies(10) + ut_get_jiffies(); + for (i = 0; i < len; i++) { + while (!(JL_UART0->CON0 & BIT(14))) { + if (timeout && time_before(_timeout, ut_get_jiffies())) { + return i; + } + if (time_before(_t_sleep, ut_get_jiffies())) { + ut_sleep(); + _t_sleep = ut_msecs_to_jiffies(10) + ut_get_jiffies(); + } + } + *(buf + i) = JL_UART0->BUF; + JL_UART0->CON0 |= BIT(12); + __asm__ volatile("csync"); //make RX_PND_CLR taking effect + } + } + return len; +} +/** + * @brief ut0发送字符串 + * + * @param buf 字符串首地址 + * @param len 发送的字符串长度 + */ +static void UT0_write_buf(const u8 *buf, u32 len) +{ + u32 i; + if (len == 0) { + return; + } + if (CONFIG_UART0_ENABLE_TX_DMA) { + UT_OSSemSet(&uart0.sem_tx, 0); + JL_UART0->CON0 |= BIT(13); + JL_UART0->CON0 |= BIT(2); + JL_UART0->TXADR = (u32)buf; + JL_UART0->TXCNT = len; + UT_OSSemPend(&uart0.sem_tx, 0); + JL_UART0->CON0 &= ~BIT(2); + } else { + for (i = 0; i < len; i ++) { + UT0_putbyte(*(buf + i)); + } + } +} +/** + * @brief ut0配置波特率 + * + * @param baud 波特率值 + */ +static void UT0_set_baud(u32 baud) +{ + JL_UART0->CON0 &= ~(BIT(0) | BIT(1)); + JL_UART0->CON0 |= BIT(13) | BIT(12) | BIT(10); + JL_UART0->BAUD = ((UART_CLK + baud / 2) / baud) / 4 - 1; + if (JL_UART0->CON0 & BIT(5)) { + if (uart0.rx_timeout > 10) { + JL_UART0->OTCNT = (uart0.rx_timeout / 10) * (UART_OT_CLK / 10) / 10; + } else { + JL_UART0->OTCNT = uart0.rx_timeout * UART_OT_CLK / 1000; + } + } + JL_UART0->CON0 |= BIT(13) | BIT(12) | BIT(10) | BIT(0) | BIT(1); +} + +/** +*获取串口数据长度 +*/ +static u32 uart1_get_data_len() +{ + return kfifo_length(&uart1.kfifo); +} + +/** + * @brief ut0使能 + */ +static void UT0_open(u32 baud, u32 is_9bit, void *cbuf, u32 cbuf_size, u32 rx_cnt, u32 ot) +{ + JL_UART0->CON0 = BIT(13) | BIT(12) | BIT(10); + UT_OSSemCreate(&uart0.sem_rx, 0); + UT_OSSemCreate(&uart0.sem_tx, 0); + request_irq(IRQ_UART0_IDX, 3, UT0_isr_fun, 0); + if (cbuf) { + uart0.kfifo.buffer = cbuf; + uart0.kfifo.buf_size = cbuf_size; + uart0.kfifo.buf_in = 0; + uart0.kfifo.buf_out = 0; + uart0.frame_length = rx_cnt; + uart0.rx_timeout = ot; + JL_UART0->RXSADR = (u32)uart0.kfifo.buffer; + JL_UART0->RXEADR = (u32)(uart0.kfifo.buffer + uart0.kfifo.buf_size); + JL_UART0->RXCNT = uart0.frame_length; + JL_UART0->CON0 |= BIT(6) | BIT(5) | BIT(3); + } + if (is_9bit) { + JL_UART0->CON2 |= BIT(0); + } else { + JL_UART0->CON2 &= ~BIT(0); + } + UT0_set_baud(baud); +} +/** + * @brief ut0关闭,注销 + */ +static void UT0_close(void) +{ + UT_OSSemClose(&uart0.sem_rx); + UT_OSSemClose(&uart0.sem_tx); + irq_disable(IRQ_UART0_IDX); + JL_UART0->CON0 = BIT(13) | BIT(12) | BIT(10); +} +/** + * @brief ut1发送一个byte + * + * @param a 要发送的字节 + */ +static void UT1_putbyte(char a) +{ + if (JL_UART1->CON0 & BIT(0)) { + JL_UART1->BUF = a; + __asm__ volatile("csync"); + while ((JL_UART1->CON0 & BIT(15)) == 0); + JL_UART1->CON0 |= BIT(13); + } +} +/** + * @brief ut1接收一个byte + * + * @param buf 字节存放地址 + * @param timeout 接收超时时间,单位1ms +10ms¥;返回1:接收成功 + */ +static u8 UT1_getbyte(u8 *buf, u32 timeout) +{ + u32 _timeout, _t_sleep; + timeout = ut_msecs_to_jiffies(timeout); + if (JL_UART1->CON0 & BIT(6)) { + if (!kfifo_length(&uart1.kfifo)) { + UT_OSSemPend(&uart1.sem_rx, timeout); + } + UT_OSSemSet(&uart1.sem_rx, 0); + + return kfifo_get(&uart1.kfifo, buf, 1); + } else { + _timeout = timeout + ut_get_jiffies(); + _t_sleep = ut_msecs_to_jiffies(10) + ut_get_jiffies(); + while (!(JL_UART1->CON0 & BIT(14))) { + if (timeout && time_before(_timeout, ut_get_jiffies())) { + return 0; + } + if (time_before(_t_sleep, ut_get_jiffies())) { + ut_sleep(); + _t_sleep = ut_msecs_to_jiffies(10) + ut_get_jiffies(); + } + } + *buf = JL_UART1->BUF; + JL_UART1->CON0 |= BIT(12); + __asm__ volatile("csync"); //make RX_PND_CLR taking effect + } + return 1; +} +/** + * @brief ut1中断函数 + */ +SET_INTERRUPT +static void UT1_isr_fun(void) +{ + u32 rx_len = 0; + if ((JL_UART1->CON0 & BIT(2)) && (JL_UART1->CON0 & BIT(15))) { + JL_UART1->CON0 |= BIT(13); + UT_OSSemPost(&uart1.sem_tx); + if (uart1.isr_cbfun) { + uart1.isr_cbfun(&uart1, UT_TX); + } + } + if ((JL_UART1->CON0 & BIT(3)) && (JL_UART1->CON0 & BIT(14))) { + JL_UART1->CON0 |= BIT(7); //DMA模式 + JL_UART1->CON0 |= BIT(12); //清RX PND + rx_len = JL_UART1->HRXCNT; //读当前串口接收数据的个数 + /* uart1.kfifo.buf_in += uart1.frame_length; //每满32字节则产生一次中断 */ + uart1.kfifo.buf_in += rx_len; + UT_OSSemPost(&uart1.sem_rx); + if (uart1.isr_cbfun) { + uart1.isr_cbfun(&uart1, UT_RX); + } + } + + if ((JL_UART1->CON0 & BIT(5)) && (JL_UART1->CON0 & BIT(11))) { + //OTCNT PND + JL_UART1->CON0 |= BIT(7); //DMA模式 + JL_UART1->CON0 |= BIT(10); //清OTCNT PND + JL_UART1->CON0 |= BIT(12); //清RX PND(这里的顺序不能改变,这里要清一次) + rx_len = JL_UART1->HRXCNT; //读当前串口接收数据的个数 + + if (rx_len) { + uart1.kfifo.buf_in += rx_len; + /* printf("%s() %d\n", __func__, __LINE__); */ + UT_OSSemPost(&uart1.sem_rx); + if (uart1.isr_cbfun) { + uart1.isr_cbfun(&uart1, UT_RX_OT); + } + } + } +} +/** + * @brief ut1接收字符串 + * + * @param buf 字符串存放首地址 + * @param len 预接收长度 + * @param timeout 接收超时时间,单位1ms + * @return 返回实际接收的长度 + */ +static u32 UT1_read_buf(u8 *buf, u32 len, u32 timeout) +{ + u32 i; + u32 _timeout, _t_sleep; + if (len == 0) { + return 0; + } + timeout = ut_msecs_to_jiffies(timeout); + if (JL_UART1->CON0 & BIT(6)) { + if (!kfifo_length(&uart1.kfifo)) { + UT_OSSemPend(&uart1.sem_rx, timeout); + } + UT_OSSemSet(&uart1.sem_rx, 0); + + return kfifo_get(&uart1.kfifo, buf, len); + } else { + _timeout = timeout + ut_get_jiffies(); + _t_sleep = ut_msecs_to_jiffies(10) + ut_get_jiffies(); + for (i = 0; i < len; i++) { + while (!(JL_UART1->CON0 & BIT(14))) { + if (timeout && time_before(_timeout, ut_get_jiffies())) { + return i; + } + if (time_before(_t_sleep, ut_get_jiffies())) { + ut_sleep(); + _t_sleep = ut_msecs_to_jiffies(10) + ut_get_jiffies(); + } + } + *(buf + i) = JL_UART1->BUF; + JL_UART1->CON0 |= BIT(12); + __asm__ volatile("csync"); //make RX_PND_CLR taking effect + } + } + return len; +} +/** + * @brief ut1发送字符串 + * + * @param buf 字符串首地址 + * @param len 发送的字符串长度 + * @param timeout 发送超时时间,单位10ms + */ +static void UT1_write_buf(const u8 *buf, u32 len) +{ + u32 i; + if (len == 0) { + return; + } + if (CONFIG_UART1_ENABLE_TX_DMA) { + UT_OSSemSet(&uart1.sem_tx, 0); + JL_UART1->CON0 |= BIT(13); + JL_UART1->CON0 |= BIT(2); + JL_UART1->TXADR = (u32)buf; + JL_UART1->TXCNT = len; + UT_OSSemPend(&uart1.sem_tx, 0); + JL_UART1->CON0 &= ~BIT(2); + } else { + for (i = 0; i < len; i ++) { + UT1_putbyte(*(buf + i)); + } + } +} +/** + * @brief ut1配置波特率 + * + * @param baud 波特率值 + */ +static void UT1_set_baud(u32 baud) +{ + JL_UART1->CON0 &= ~(BIT(0) | BIT(1)); + JL_UART1->CON0 |= BIT(13) | BIT(12) | BIT(10); + JL_UART1->BAUD = ((UART_CLK + baud / 2) / baud) / 4 - 1; + if (JL_UART1->CON0 & BIT(5)) { + if (uart1.rx_timeout > 10) { + JL_UART1->OTCNT = (uart1.rx_timeout / 10) * (UART_OT_CLK / 10) / 10; + } else { + JL_UART1->OTCNT = uart1.rx_timeout * UART_OT_CLK / 1000; + } + } + JL_UART1->CON0 |= BIT(13) | BIT(12) | BIT(10) | BIT(0) | BIT(1); +} +/** + * @brief ut1使能 + */ +static void UT1_open(u32 baud, u32 is_9bit, void *cbuf, u32 cbuf_size, u32 rx_cnt, u32 ot) +{ + JL_UART1->CON0 = BIT(13) | BIT(12) | BIT(10); + UT_OSSemCreate(&uart1.sem_rx, 0); + UT_OSSemCreate(&uart1.sem_tx, 0); + request_irq(IRQ_UART1_IDX, 3, UT1_isr_fun, 0); + if (cbuf) { + uart1.kfifo.buffer = cbuf; + uart1.kfifo.buf_size = cbuf_size; + uart1.kfifo.buf_in = 0; + uart1.kfifo.buf_out = 0; + uart1.frame_length = rx_cnt; + uart1.rx_timeout = ot; + JL_UART1->RXSADR = (u32)uart1.kfifo.buffer; + JL_UART1->RXEADR = (u32)(uart1.kfifo.buffer + uart1.kfifo.buf_size); + JL_UART1->RXCNT = uart1.frame_length; + JL_UART1->CON0 |= BIT(6) | BIT(5) | BIT(3); + } + if (is_9bit) { + JL_UART1->CON2 |= BIT(0); + } else { + JL_UART1->CON2 &= ~BIT(0); + } + UT1_set_baud(baud); +} +/** + * @brief ut1关闭,注销 + */ +static void UT1_close(void) +{ + UT_OSSemClose(&uart1.sem_rx); + UT_OSSemClose(&uart1.sem_tx); + irq_disable(IRQ_UART1_IDX); + JL_UART1->CON0 = BIT(13) | BIT(12) | BIT(10); +} +/** + * @brief ut2发送一个byte + * + * @param a 要发送的字节 + */ +static void UT2_putbyte(char a) +{ + if (JL_UART2->CON0 & BIT(0)) { + JL_UART2->BUF = a; + __asm__ volatile("csync"); + while ((JL_UART2->CON0 & BIT(15)) == 0); + JL_UART2->CON0 |= BIT(13); + } +} +/** + * @brief ut2接收一个byte + * + * @param buf 字节存放地址 + * @param timeout 接收超时时间,单位1ms + * @return 返回0:接收失败;返回1:接收成功 + */ +static u8 UT2_getbyte(u8 *buf, u32 timeout) +{ + u32 _timeout, _t_sleep; + timeout = ut_msecs_to_jiffies(timeout); + + if (JL_UART2->CON0 & BIT(6)) { + if (!kfifo_length(&uart2.kfifo)) { + UT_OSSemPend(&uart2.sem_rx, timeout); + } + UT_OSSemSet(&uart2.sem_rx, 0); + + return kfifo_get(&uart2.kfifo, buf, 1); + } else { + _timeout = timeout + ut_get_jiffies(); + _t_sleep = ut_msecs_to_jiffies(10) + ut_get_jiffies(); + while (!(JL_UART2->CON0 & BIT(14))) { + if (timeout && time_before(_timeout, ut_get_jiffies())) { + return 0; + } + if (time_before(_t_sleep, ut_get_jiffies())) { + ut_sleep(); + _t_sleep = ut_msecs_to_jiffies(10) + ut_get_jiffies(); + } + } + *buf = JL_UART2->BUF; + JL_UART2->CON0 |= BIT(12); + __asm__ volatile("csync"); //make RX_PND_CLR taking effect + } + + return 1; +} +/** + * @brief ut2中断函数 + */ +SET_INTERRUPT +static void UT2_isr_fun(void) +{ + //JL_UART2->CON0 |= (BIT(13) | BIT(12) | BIT(10)); + u32 rx_len = 0; + if ((JL_UART2->CON0 & BIT(2)) && (JL_UART2->CON0 & BIT(15))) { + JL_UART2->CON0 |= BIT(13); + UT_OSSemPost(&uart2.sem_tx); + if (uart2.isr_cbfun) { + uart2.isr_cbfun(&uart2, UT_TX); + } + } + if ((JL_UART2->CON0 & BIT(3)) && (JL_UART2->CON0 & BIT(14))) { + JL_UART2->CON0 |= BIT(7); //DMA模式 + JL_UART2->CON0 |= BIT(12); //清RX PND + rx_len = JL_UART2->HRXCNT; //读当前串口接收数据的个数 + /* uart2.kfifo.buf_in += uart2.frame_length; //每满32字节则产生一次中断 */ + uart2.kfifo.buf_in += rx_len; + UT_OSSemPost(&uart2.sem_rx); + if (uart2.isr_cbfun) { + uart2.isr_cbfun(&uart2, UT_RX); + } + } + + if ((JL_UART2->CON0 & BIT(5)) && (JL_UART2->CON0 & BIT(11))) { + //OTCNT PND + JL_UART2->CON0 |= BIT(7); //DMA模式 + JL_UART2->CON0 |= BIT(10); //清OTCNT PND + JL_UART2->CON0 |= BIT(12); //清RX PND(这里的顺序不能改变,这里要清一次) + rx_len = JL_UART2->HRXCNT; //读当前串口接收数据的个数 + + if (rx_len) { + uart2.kfifo.buf_in += rx_len; + /* printf("%s() %d\n", __func__, __LINE__); */ + UT_OSSemPost(&uart2.sem_rx); + if (uart2.isr_cbfun) { + uart2.isr_cbfun(&uart2, UT_RX_OT); + } + } + } +} + +/** + * @brief ut1接收字符串 + * + * @param buf 字符串存放首地址 + * @param len 预接收长度 + * @param timeout 接收超时时间,单位1ms + * @return 返回实际接收的长度 + */ +static u32 UT2_read_buf(u8 *buf, u32 len, u32 timeout) +{ + u32 i; + u32 _timeout, _t_sleep; + if (len == 0) { + return 0; + } + + timeout = ut_msecs_to_jiffies(timeout); + if (JL_UART2->CON0 & BIT(6)) { + if (!kfifo_length(&uart2.kfifo)) { + UT_OSSemPend(&uart2.sem_rx, timeout); + } + UT_OSSemSet(&uart2.sem_rx, 0); + return kfifo_get(&uart2.kfifo, buf, len); + } else { + _timeout = timeout + ut_get_jiffies(); + _t_sleep = ut_msecs_to_jiffies(10) + ut_get_jiffies(); + for (i = 0; i < len; i ++) { + while (!(JL_UART2->CON0 & BIT(14))) { + if (timeout && time_before(_timeout, ut_get_jiffies())) { + return i; + } + if (time_before(_t_sleep, ut_get_jiffies())) { + ut_sleep(); + _t_sleep = ut_msecs_to_jiffies(10) + ut_get_jiffies(); + } + } + *(buf + i) = JL_UART2->BUF; + JL_UART2->CON0 |= BIT(12); + __asm__ volatile("csync"); //make RX_PND_CLR taking effect + } + } + return len; +} +/** + * @brief ut2发送字符串 + * + * @param buf 字符串首地址 + * @param len 发送的字符串长度 + * @param timeout 发送超时时间,单位10ms + */ +static void UT2_write_buf(const u8 *buf, u32 len) +{ + u32 i; + if (len == 0) { + return; + } + if (CONFIG_UART2_ENABLE_TX_DMA) { + UT_OSSemSet(&uart2.sem_tx, 0); + JL_UART2->CON0 |= BIT(13); + JL_UART2->CON0 |= BIT(2); + JL_UART2->TXADR = (u32)buf; + JL_UART2->TXCNT = len; + UT_OSSemPend(&uart2.sem_tx, 0); + JL_UART2->CON0 &= ~BIT(2); + } else { + for (i = 0; i < len; i++) { + UT2_putbyte(*(buf + i)); + } + } +} +/** + * @brief ut2配置波特率 + * + * @param baud 波特率值 + */ +static void UT2_set_baud(u32 baud) +{ + JL_UART2->CON0 &= ~(BIT(0) | BIT(1)); + JL_UART2->CON0 |= BIT(13) | BIT(12) | BIT(10); + JL_UART2->BAUD = ((UART_CLK + baud / 2) / baud) / 4 - 1; + if (JL_UART2->CON0 & BIT(5)) { + if (uart2.rx_timeout > 10) { + JL_UART2->OTCNT = (uart2.rx_timeout / 10) * (UART_OT_CLK / 10) / 10; + } else { + JL_UART2->OTCNT = uart2.rx_timeout * UART_OT_CLK / 1000; + } + } + JL_UART2->CON0 |= BIT(13) | BIT(12) | BIT(10) | BIT(0) | BIT(1); +} + +/** + * @brief ut2使能 + */ +static void UT2_open(u32 baud, u32 is_9bit, void *cbuf, u32 cbuf_size, u32 rx_cnt, u32 ot) +{ + JL_UART2->CON0 = BIT(13) | BIT(12) | BIT(10); + UT_OSSemCreate(&uart2.sem_rx, 0); + UT_OSSemCreate(&uart2.sem_tx, 0); + request_irq(IRQ_UART2_IDX, 3, UT2_isr_fun, 0); + if (cbuf) { + uart2.kfifo.buffer = cbuf; + uart2.kfifo.buf_size = cbuf_size; + uart2.kfifo.buf_in = 0; + uart2.kfifo.buf_out = 0; + uart2.frame_length = rx_cnt; + uart2.rx_timeout = ot; + JL_UART2->RXSADR = (u32)uart2.kfifo.buffer; + JL_UART2->RXEADR = (u32)(uart2.kfifo.buffer + uart2.kfifo.buf_size); + JL_UART2->RXCNT = uart2.frame_length; + JL_UART2->CON0 |= BIT(6) | BIT(5) | BIT(3); + } + if (is_9bit) { + JL_UART2->CON2 |= BIT(0); + } else { + JL_UART2->CON2 &= ~BIT(0); + } + UT2_set_baud(baud); +} + +/** + * @brief ut2关闭,注销 + */ +static void UT2_close(void) +{ + UT_OSSemClose(&uart2.sem_rx); + UT_OSSemClose(&uart2.sem_tx); + irq_disable(IRQ_UART2_IDX); + JL_UART2->CON0 = BIT(13) | BIT(12) | BIT(10); +} + +static u32 uart_is_idle(u32 ut_num) +{ + switch (ut_num) { + case 0 : + return !(JL_UART0->CON0 & BIT(0)); + case 1 : + return !(JL_UART1->CON0 & BIT(0)); + case 2: + return !(JL_UART2->CON0 & BIT(0)); + default : + break; + } + return 0; +} + +static u8 uart_config(const struct uart_platform_data_t *arg, u8 tx_ch, enum PFI_TABLE rx_pfun) +{ + if (!(arg->tx_pin < IO_PORT_MAX || arg->rx_pin < IO_PORT_MAX)) { + return -1; + } + + if (arg->tx_pin < IO_PORT_MAX) { + gpio_direction_output(arg->tx_pin, 1); + gpio_set_fun_output_port(arg->tx_pin, tx_ch, 1, 1, LOW_POWER_FREE); + } + if (arg->rx_pin < IO_PORT_MAX) { + gpio_direction_input(arg->rx_pin); + gpio_set_pull_up(arg->rx_pin, 1); + gpio_set_die(arg->rx_pin, 1); + gpio_set_fun_input_port(arg->rx_pin, rx_pfun, LOW_POWER_FREE); + } + return 0; +} + +/** + * @brief ut模块初始const struct uart_platform_data_t *arg化函数,供外部调用 + * + * @param arg 传入uartconst struct uart_platform_data_t *arg_argment型结构体指针 + * @return 返回uart_buconst struct uart_platform_data_t *args_t型结构体指针 + */ +__attribute__((noinline)) +const uart_bus_t *uart_dev_open(const struct uart_platform_data_t *arg) +{ + u8 ut_num; + uart_bus_t *ut = NULL; + u8 gpio_input_channle_flag = 0; + + if (uart_is_idle(0)) { + ut_num = 0; + } else if (uart_is_idle(1)) { + ut_num = 1; + } else if ((uart_is_idle(2))) { + ut_num = 2; + } else { + return NULL; + } + if (arg->rx_cbuf) { + if ((arg->rx_cbuf_size == 0) || (arg->rx_cbuf_size & (arg->rx_cbuf_size - 1))) { + return NULL; + } + } + + if (CONFIG_UART0_ENABLE && ut_num == 0) { + //gpio_set_uart0(ut_ch); + if (uart_config(arg, FO_UART0_TX, PFI_UART0_RX)) { + return NULL; + } + + uart0.argv = arg->argv; + uart0.isr_cbfun = arg->isr_cbfun; + uart0.putbyte = UT0_putbyte; + uart0.getbyte = UT0_getbyte; + uart0.read = UT0_read_buf; + uart0.write = UT0_write_buf; + uart0.set_baud = UT0_set_baud; + UT0_open(arg->baud, arg->is_9bit, + arg->rx_cbuf, arg->rx_cbuf_size, + arg->frame_length, arg->rx_timeout); + ut = &uart0; + } else if (CONFIG_UART1_ENABLE && ut_num == 1) { + //gpio_set_uart1(ut_ch); + if (uart_config(arg, FO_UART1_TX, PFI_UART1_RX)) { + return NULL; + } + uart1.argv = arg->argv; + uart1.isr_cbfun = arg->isr_cbfun; + uart1.putbyte = UT1_putbyte; + uart1.getbyte = UT1_getbyte; + uart1.read = UT1_read_buf; + uart1.write = UT1_write_buf; + uart1.set_baud = UT1_set_baud; + uart1.get_data_len = uart1_get_data_len; + UT1_open(arg->baud, arg->is_9bit, + arg->rx_cbuf, arg->rx_cbuf_size, + arg->frame_length, arg->rx_timeout); + ut = &uart1; + } else if (CONFIG_UART2_ENABLE && ut_num == 2) { + //gpio_set_uart2(ut_ch); + if (uart_config(arg, FO_UART2_TX, PFI_UART2_RX)) { + return NULL; + } + uart2.argv = arg->argv; + uart2.isr_cbfun = arg->isr_cbfun; + uart2.putbyte = UT2_putbyte; + uart2.getbyte = UT2_getbyte; + uart2.read = UT2_read_buf; + uart2.write = UT2_write_buf; + uart2.set_baud = UT2_set_baud; + UT2_open(arg->baud, arg->is_9bit, + arg->rx_cbuf, arg->rx_cbuf_size, + arg->frame_length, arg->rx_timeout); + ut = &uart2; + } else { + return NULL; + } + return ut; +} +u32 uart_dev_close(uart_bus_t *ut) +{ + UT_OSSemClose(&ut->sem_rx); + UT_OSSemClose(&ut->sem_tx); + if (&uart0 == ut) { + UT0_close(); + return gpio_close_uart0(); + } else if (&uart1 == ut) { + UT1_close(); + return gpio_close_uart1(); + } else { + UT2_close(); + return gpio_close_uart2(); + } + return 0; +} + +void uart_disable_for_ota() +{ + JL_UART0->CON0 = BIT(13) | BIT(12) | BIT(10); + JL_UART1->CON0 = BIT(13) | BIT(12) | BIT(10); + JL_UART2->CON0 = BIT(13) | BIT(12) | BIT(10); +} + +static u8 _rts_io = -1; +static u8 _cts_io = -1; +void uart1_flow_ctl_init(u8 rts_io, u8 cts_io) +{ + JL_UART1->CON1 = 0; + //RTS + if (rts_io < IO_PORT_MAX) { + _rts_io = rts_io; + gpio_set_die(rts_io, 1); + gpio_set_direction(rts_io, 0); + gpio_set_pull_up(rts_io, 0); + gpio_set_pull_down(rts_io, 0); + gpio_write(rts_io, 0); + gpio_set_fun_output_port(rts_io, FO_UART1_RTS, 1, 1, LOW_POWER_FREE); + JL_UART1->CON1 |= BIT(13) | BIT(0); + } + //CTS + if (cts_io < IO_PORT_MAX) { + _cts_io = cts_io; + gpio_set_die(cts_io, 1); + gpio_set_direction(cts_io, 1); + gpio_set_pull_up(cts_io, 0); + gpio_set_pull_down(cts_io, 1); + gpio_set_fun_input_port(cts_io, PFI_UART1_CTS, LOW_POWER_FREE); + JL_UART1->CON1 |= BIT(14) | BIT(2); + } +} + +void uart1_flow_ctl_rts_suspend(void) +{ + if (!(JL_UART1->CON1 & BIT(0))) { + gpio_write(_rts_io, 1); //告诉对方,自己忙碌 + } + JL_UART1->CON1 |= BIT(4); //硬件停止接收 +} + +void uart1_flow_ctl_rts_resume(void) +{ + JL_UART1->CON1 &= ~BIT(4); //硬件可以接收 + if (JL_UART1->CON1 & BIT(0)) { + JL_UART1->CON1 |= BIT(13); + } else { + gpio_write(_rts_io, 0); //表示可以继续接收数据 + } +} + diff --git a/cpu/br28/uart_test.c b/cpu/br28/uart_test.c new file mode 100644 index 0000000..02db801 --- /dev/null +++ b/cpu/br28/uart_test.c @@ -0,0 +1,174 @@ +#include "system/includes.h" +#include "asm/uart_dev.h" +#include "system/event.h" +#include "key_event_deal.h" +#include "app_task.h" + +#if 0 +/* + [[ 注意!!! ]] + * 如果当系统任务较少时使用本demo,需要将低功耗关闭(#define TCFG_LOWPOWER_LOWPOWER_SEL 0//SLEEP_EN ),否则任务被串口接收函数调用信号量pend时会导致cpu休眠,串口中断和DMA接收将遗漏数据或数据不正确 +*/ + +#define UART_DEV_USAGE_TEST_SEL 2 //uart_dev.c api接口使用方法选择 +// 选择1 串口中断回调函数推送事件,由事件响应函数接收串口数据 +// 选择2 由task接收串口数据 + +#define UART_DEV_TEST_MULTI_BYTE 1 //uart_dev.c 读写多个字节api / 读写1个字节api 选择 + +#define UART_DEV_FLOW_CTRL 0 +const uart_bus_t *uart_bus; +static u8 uart_cbuf[512] __attribute__((aligned(4))); +static u8 uart_rxbuf[512] __attribute__((aligned(4))); + + +//设备事件响应demo +static void uart_event_handler(struct sys_event *e) +{ + + u32 uart_rxcnt = 0; + + if ((u32)e->arg == DEVICE_EVENT_FROM_UART_RX_OVERFLOW) { + if (e->u.dev.event == DEVICE_EVENT_CHANGE) { + /* printf("uart event: DEVICE_EVENT_FROM_UART_RX_OVERFLOW\n"); */ + 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++) { + my_put_u8hex(uart_rxbuf[i]); + if (i % 16 == 15) { + putchar('\n'); + } + } + if (uart_rxcnt % 16) { + putchar('\n'); + } +#if (!UART_DEV_FLOW_CTRL) + uart_bus->write(uart_rxbuf, uart_rxcnt); +#endif + } + printf("uart out\n"); + } + } + if ((u32)e->arg == DEVICE_EVENT_FROM_UART_RX_OUTTIME) { + if (e->u.dev.event == DEVICE_EVENT_CHANGE) { + /* printf("uart event:DEVICE_EVENT_FROM_UART_RX_OUTTIME\n"); */ + 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++) { + my_put_u8hex(uart_rxbuf[i]); + if (i % 16 == 15) { + putchar('\n'); + } + } + if (uart_rxcnt % 16) { + putchar('\n'); + } +#if (!UART_DEV_FLOW_CTRL) + uart_bus->write(uart_rxbuf, uart_rxcnt); +#endif + } + printf("uart out\n"); + } + } +} +//SYS_EVENT_HANDLER(SYS_DEVICE_EVENT, uart_event_handler, 0); + +int uart_tr_send_data(u8 *data, u32 len) +{ +#ifndef CONFIG_DEBUG_ENABLE + uart_bus->write(data,len); +#endif // CONFIG_DEBUG_ENABLE +} +extern int dual_ota_app_data_deal(u32 msg, u8 *buf, u32 len); +static void uart_u_task(void *arg) +{ + + int ret; + u32 uart_rxcnt = 0; + + printf("uart_u_task start\n"); + while (1) { + //uart_bus->read()在尚未收到串口数据时会pend信号量,挂起task,直到UART_RX_PND或UART_RX_OT_PND中断发生,post信号量,唤醒task + uart_rxcnt = uart_bus->read(uart_rxbuf, sizeof(uart_rxbuf), 0); + if (uart_rxcnt) + { + // uart_tr_send_data(uart_rxbuf,uart_rxcnt); + // dual_ota_app_data_deal(0, uart_rxbuf, uart_rxcnt); + } + } +} + +static void uart_isr_hook(void *arg, u32 status) +{ + + 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 (UART_DEV_USAGE_TEST_SEL == 1) + e.type = SYS_DEVICE_EVENT; + e.arg = (void *)DEVICE_EVENT_FROM_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 (UART_DEV_USAGE_TEST_SEL == 1) + e.type = SYS_DEVICE_EVENT; + e.arg = (void *)DEVICE_EVENT_FROM_UART_RX_OUTTIME; + e.u.dev.event = DEVICE_EVENT_CHANGE; + e.u.dev.value = (int)ubus; + sys_event_notify(&e); +#endif + } +} + +void uart_dev_test_main() +{ +#ifndef CONFIG_DEBUG_ENABLE + struct uart_platform_data_t u_arg = {0}; + u_arg.tx_pin = IO_PORT_DP; + u_arg.rx_pin = -1; + u_arg.rx_cbuf = uart_cbuf; + u_arg.rx_cbuf_size = 512; + u_arg.frame_length = 512; + u_arg.rx_timeout = 10; + u_arg.isr_cbfun = NULL;//uart_isr_hook; + u_arg.baud = 115200; + u_arg.is_9bit = 0; + + uart_bus = uart_dev_open(&u_arg); + if (uart_bus != NULL) { + printf("uart_dev_open() success\n"); +#if (UART_DEV_USAGE_TEST_SEL == 2) + os_task_create(uart_u_task, (void *)uart_bus, 31, 2048, 0, "uart_u_task"); +#endif + } +#endif // CONFIG_DEBUG_ENABLE +} +#else +void uart_dev_test_main() +{ + +} +int uart_tr_send_data(u8 *data, u32 len) +{ + +} +#endif + + + + + + + + + diff --git a/docs/branch-index.md b/docs/branch-index.md new file mode 100644 index 0000000..d735488 --- /dev/null +++ b/docs/branch-index.md @@ -0,0 +1,62 @@ +# SOC 代码生成模板 — 分支索引 + +本仓库按 **「厂商-型号」** 组织分支,每个分支是一套完整的 SOC 工程模板。 + +远程仓库:[soc-codegen-template](https://git.jianbao-tech.com/pets-device/soc-codegen-template) + +--- + +## 分支列表 + +| 分支 | 厂商 | 型号 | 平台 | 默认能力 | 状态 | +|------|------|------|------|----------|------| +| [`JieLi-JL7016`](https://git.jianbao-tech.com/pets-device/soc-codegen-template/src/branch/JieLi-JL7016) | 杰理 JieLi | JL7016 / AC7016C | BR28 | 耳机 SDK + BLE + jb_protocol + OTA | ✅ 可用 | + +> 新模板上线后在此表追加一行即可。 + +--- + +## 如何获取某 SOC 模板 + +### 见宝工具箱 / 自动化脚本 + +```bash +git clone https://git.jianbao-tech.com/pets-device/soc-codegen-template.git +cd soc-codegen-template +git checkout JieLi-JL7016 +``` + +### 仅下载指定分支(浅克隆) + +```bash +git clone --branch JieLi-JL7016 --single-branch \ + https://git.jianbao-tech.com/pets-device/soc-codegen-template.git jl7016-template +``` + +--- + +## 分支命名规范 + +``` +<厂商>-<型号> +``` + +示例:`JieLi-JL7016`、`JieLi-AC701N` + +- 默认包含耳机应用与 jb_protocol,分支名**不加**多余后缀 +- 同一芯片多种工程结构差异过大时,再考虑加后缀:`JieLi-JL7016-dongle` + +--- + +## 新增 SOC 模板(维护者) + +1. 从 `main` 拉新分支:`git checkout -b <厂商>-<型号> main` +2. 合入该 SOC 完整工程(apps + cpu + include_lib + tools) +3. 更新本文件分支表 + `main/README.md` 快速索引 +4. 推送分支并在 Gitea 设为受保护分支(可选) + +--- + +## 各分支 README + +每个 SOC 分支根目录有独立的 `README.md`(构建、打包、协议对接说明)。 diff --git a/dp_definition.json b/dp_definition.json new file mode 100644 index 0000000..5f5a6bc --- /dev/null +++ b/dp_definition.json @@ -0,0 +1,357 @@ +{ + "product": { + "name": "电子开关-加热垫", + "code": "PRCBR1", + "type": "CBR1", + "protocol": "V1.0.0" + }, + "dps": [ + { + "id": 0, + "display_name": "加热开关", + "key": "heat_switch", + "kind": "normal", + "type": "bool", + "len": 1, + "scale": 1.0, + "dir": "rw", + "description": "加热开关", + "values": { + "0": "关", + "1": "开" + } + }, + { + "id": 1, + "display_name": "温控开关", + "key": "temp_control_switch", + "kind": "normal", + "type": "bool", + "len": 1, + "scale": 1.0, + "dir": "rw", + "description": "温控开关", + "values": { + "0": "关", + "1": "开" + } + }, + { + "id": 2, + "display_name": "温控时间", + "key": "temp_control_time", + "kind": "normal", + "type": "raw", + "len": 4, + "scale": 1.0, + "dir": "rw", + "description": "预留,防止后期需要设置温度控制的运行时间段", + "values": {} + }, + { + "id": 3, + "display_name": "模式", + "key": "mode", + "kind": "normal", + "type": "enum", + "len": 1, + "scale": 1.0, + "dir": "rw", + "description": "预留", + "values": {} + }, + { + "id": 4, + "display_name": "最低温度", + "key": "min_temp", + "kind": "normal", + "type": "float", + "len": 2, + "scale": 0.1, + "dir": "rw", + "description": "2个字节的float按照int16传输,可以传输的温度范围为:-3276.8 ~ 3276.7,预留", + "values": {} + }, + { + "id": 5, + "display_name": "最高温度", + "key": "max_temp", + "kind": "normal", + "type": "float", + "len": 2, + "scale": 0.1, + "dir": "rw", + "description": "2个字节的float按照int16传输,可以传输的温度范围为:-3276.8 ~ 3276.7,预留", + "values": {} + }, + { + "id": 6, + "display_name": "当前温度", + "key": "current_temp", + "kind": "normal", + "type": "float", + "len": 2, + "scale": 0.1, + "dir": "ro", + "description": "2个字节的float按照int16传输,可以传输的温度范围为:-3276.8 ~ 3276.7,预留", + "values": {} + }, + { + "id": 7, + "display_name": "联动删除", + "key": "linkage_delete", + "kind": "normal", + "type": "bool", + "len": 1, + "scale": 1.0, + "dir": "rw", + "description": "APP没用到此设备,则下发联动删除", + "values": { + "0": "无操作", + "1": "删除联动" + } + }, + { + "id": 8, + "display_name": "联动配置", + "key": "linkage_config", + "kind": "normal", + "type": "raw", + "len": 20, + "scale": 1.0, + "dir": "rw", + "description": "缸体编号为uint16,温度类型为int8,湿度和版本为uint8;\n后面应该会加上条件和动作,先预留13个Byte", + "values": {} + }, + { + "id": 9, + "display_name": "定时使能", + "key": "time_en", + "kind": "normal", + "type": "bool", + "len": 1, + "scale": 1.0, + "dir": "rw", + "description": "一键启动/禁用所有定时配置", + "values": { + "0": "关", + "1": "开" + } + }, + { + "id": 10, + "display_name": "定时配置1", + "key": "time_config1", + "kind": "normal", + "type": "raw", + "len": 8, + "scale": 1.0, + "dir": "rw", + "description": "定时类型\n0=单次,1=每天,2=每周指定星期\n星期位图\nBit0 = 周一\nBit1 = 周二\nBit2 = 周三\nBit3 = 周四\nBit4 = 周五\nBit5 = 周六\nBit6 = 周日\nBit7 = Reserved", + "values": {} + }, + { + "id": 11, + "display_name": "定时配置2", + "key": "time_config2", + "kind": "normal", + "type": "raw", + "len": 8, + "scale": 1.0, + "dir": "rw", + "description": "同上", + "values": {} + }, + { + "id": 12, + "display_name": "定时配置3", + "key": "time_config3", + "kind": "normal", + "type": "raw", + "len": 8, + "scale": 1.0, + "dir": "rw", + "description": "同上", + "values": {} + }, + { + "id": 13, + "display_name": "定时配置4", + "key": "time_config4", + "kind": "normal", + "type": "raw", + "len": 8, + "scale": 1.0, + "dir": "rw", + "description": "同上", + "values": {} + }, + { + "id": 14, + "display_name": "定时配置5", + "key": "time_config5", + "kind": "normal", + "type": "raw", + "len": 8, + "scale": 1.0, + "dir": "rw", + "description": "同上", + "values": {} + }, + { + "id": 15, + "display_name": "定时配置6", + "key": "time_config6", + "kind": "normal", + "type": "raw", + "len": 8, + "scale": 1.0, + "dir": "rw", + "description": "同上", + "values": {} + }, + { + "id": 16, + "display_name": "定时配置7", + "key": "time_config7", + "kind": "normal", + "type": "raw", + "len": 8, + "scale": 1.0, + "dir": "rw", + "description": "同上", + "values": {} + }, + { + "id": 17, + "display_name": "运行记录", + "key": "run_record", + "kind": "normal", + "type": "raw", + "len": 124, + "scale": 1.0, + "dir": "ro", + "description": "31天的运行记录,每4个字节表示当天运行的总时长,单位:秒\nByte0-3:今天加热垫运行的总时长\nByte4-7:昨天加热垫运行的总时长\n.\n.\n.\nByte120-123:前30天加热垫运行的总时长", + "values": {} + }, + { + "id": 18, + "display_name": "心跳", + "key": "heartbeat", + "kind": "normal", + "type": "bool", + "len": 1, + "scale": 1.0, + "dir": "wo", + "description": "APP进入页面之后每5s下发一次心跳,当子设备12秒内没收到心跳\n则停止温湿度上报服务器,防止上报频繁,预留", + "values": { + "0": "无操作", + "1": "心跳" + } + }, + { + "id": 19, + "display_name": "设备故障使能", + "key": "fault_en", + "kind": "normal", + "type": "uint8", + "len": 1, + "scale": 1.0, + "dir": "rw", + "description": "预留,后期可以对某个故障进行使能和禁用", + "values": {} + }, + { + "id": 20, + "display_name": "设备故障", + "key": "fault_code", + "kind": "fault", + "type": "uint8", + "len": 1, + "scale": 1.0, + "dir": "ro", + "description": "故障码", + "values": { + "0": "无故障", + "1": "温度异常", + "2": "设备故障" + }, + "level": 2 + }, + { + "id": 21, + "display_name": "设备告警使能", + "key": "alarm_en", + "kind": "normal", + "type": "uint8", + "len": 1, + "scale": 1.0, + "dir": "rw", + "description": "预留,后期可以对某个告警进行使能和禁用", + "values": {} + }, + { + "id": 22, + "display_name": "设备告警", + "key": "alarm_code", + "kind": "alarm", + "type": "uint8", + "len": 1, + "scale": 1.0, + "dir": "ro", + "description": "预留告警DP", + "values": {}, + "level": 1 + }, + { + "id": 23, + "display_name": "恢复出厂设置", + "key": "factory_reset", + "kind": "normal", + "type": "bool", + "len": 1, + "scale": 1.0, + "dir": "wo", + "description": "写 1 触发", + "values": { + "1": "触发" + } + }, + { + "id": 24, + "display_name": "预留DP1", + "key": "reserva_dp1", + "kind": "normal", + "type": "uint32", + "len": 4, + "scale": 1.0, + "dir": "rw", + "description": "预留", + "values": {} + }, + { + "id": 25, + "display_name": "预留DP2", + "key": "reserva_dp2", + "kind": "normal", + "type": "uint32", + "len": 4, + "scale": 1.0, + "dir": "rw", + "description": "预留", + "values": {} + }, + { + "id": 26, + "display_name": "预留DP3", + "key": "reserva_dp3", + "kind": "normal", + "type": "uint32", + "len": 4, + "scale": 1.0, + "dir": "rw", + "description": "预留", + "values": {} + } + ] +} \ No newline at end of file diff --git a/include_lib/btctrler/ble/hci_ll.h b/include_lib/btctrler/ble/hci_ll.h new file mode 100644 index 0000000..287878f --- /dev/null +++ b/include_lib/btctrler/ble/hci_ll.h @@ -0,0 +1,278 @@ +/********************************************************************************************* + * Filename : hci_ll.h + + * Description : 提供Vendor Host 直接调用Controller API LL Part + + * Author : Bingquan + + * Email : bingquan_cai@zh-jieli.com + + * Last modifiled : 2018-12-04 11:58 + + * Copyright:(c)JIELI 2011-2017 @ , All Rights Reserved. +*********************************************************************************************/ +#ifndef _HCI_LL_H_ +#define _HCI_LL_H_ + +#include +#include +#include + +#include "typedef.h" + +// LE CONTROLLER COMMANDS +#define HCI_LE_SET_CIG_PARAMS 0x0062 +#define HCI_LE_SETUP_ISO_DATA_PATH 0x006E +#define HCI_LE_CREATE_BIG 0x0068 +#define HCI_LE_SET_EXTENDED_ADVERTISING_ENABLE 0x0039 + +// LE EVENTS +#define HCI_LE_CIS_ESTABLISHED_EVENT 0x19 +#define HCI_LE_CIS_REQUEST_EVENT 0x1A +#define HCI_LE_CREATE_BIG_COMPLETE_EVENT 0x1B +#define HCI_SUBEVENT_LE_BIG_INFO_ADV_REPORT_EVT 0x22 + +enum { + LL_EVENT_SUPERVISION_TIMEOUT, + LL_EVENT_RX, + LL_EVENT_ACL_TX_POST, +}; + +typedef struct { + u8 Own_Address_Type: 2; + u8 Adv_Filter_Policy: 2; + u8 Scan_Filter_Policy: 2; + u8 initiator_filter_policy: 2; +} hci_ll_param_t; + +/*! \brief LE Set CIG Parameters */ +typedef struct { + uint8_t GIG_ID; + uint8_t SDU_Interval_C_To_P[3]; + uint8_t SDU_Interval_P_To_C[3]; + uint8_t Worst_Case_SCA; + uint8_t Packing; + uint8_t Framing; + uint16_t Max_Transport_Latency_C_To_P; + uint16_t Max_Transport_Latency_P_To_C; + uint8_t CIS_Count; + struct le_cis_param_t { + uint8_t CIS_ID; + uint16_t Max_SDU_C_To_P; + uint16_t Max_SDU_P_To_C; + uint8_t PHY_C_To_P; + uint8_t PHY_P_To_C; + uint8_t RTN_C_To_P; + uint8_t RTN_P_To_C; + } _GNU_PACKED_ param[0]; +} _GNU_PACKED_ le_set_cig_param_t; + +/*! \brief LE Create CIS */ +typedef struct { + uint8_t CIS_Count; + struct le_cis_hdl_t { + uint16_t CIS_Connection_Handle; + uint16_t ACL_Connection_Handle; + } _GNU_PACKED_ param[0]; +} _GNU_PACKED_ le_create_cis_t; + +/*! \brief LE Setup ISO Data Path */ +typedef struct { + uint16_t Connection_Handle; + uint8_t Data_Path_Direction; + uint8_t Data_Path_ID; + struct { + uint8_t Coding_Format; + uint16_t Company_Identifier; + uint16_t Vendor_ID; + } _GNU_PACKED_ Codec_ID; + uint8_t Controller_Delay[3]; + uint8_t Codec_Configuratin_Length; + uint8_t Codec_Configuratin[0]; +} _GNU_PACKED_ le_setup_iso_data_path_t; + +/*! \brief LE Create BIG */ +typedef struct { + uint8_t BIG_Handle; + uint8_t Advertising_Handle; + uint8_t Num_BIS; + uint8_t SDU_Interval[3]; + uint16_t Max_SDU; + uint16_t Max_Transport_Latency; + uint8_t RTN; + uint8_t PHY; + uint8_t Packing; + uint8_t Framing; + uint8_t Encryption; + uint8_t Broadcast_Code[16]; +} _GNU_PACKED_ le_create_big_t; + +/*! \brief LE BIG Create Sync */ +typedef struct { + uint8_t BIG_Handle; + uint16_t Sync_Handle; + uint8_t Encryption; + uint8_t Broadcast_Code[16]; + uint8_t MSE; + uint16_t BIG_Sync_Timeout; + uint8_t Num_BIS; + uint8_t BIS[0]; +} _GNU_PACKED_ le_big_create_sync_t; + +/*! \brief HCI ISO Data packets */ +typedef struct { + uint32_t Connection_Handle : 12; + uint32_t PB_Flag : 2; + uint32_t TS_Flag : 1; + uint32_t RFU : 1; + uint32_t ISO_Data_Load_Length : 14; + uint32_t RFU2 : 2; + + uint32_t Time_Stamp; + + uint32_t Packet_Sequence_Num : 16; + uint32_t ISO_SDU_Length : 12; + uint32_t RFU3 : 2; + uint32_t Packet_Status_Flag : 2; + + uint8_t ISO_SDU_Fragment[0]; +} _GNU_PACKED_ hci_iso_data_packets_t ; + +typedef struct { + u32 handle : 12; + //0b00 frist fragment of a fragmented SDU + //0b01 a continuation fragment of a fragmented SDU + //0b10 a complete SDU + //0b11 the last fragment of an SDU + u32 pb_flag : 2; + u32 ts_flag : 1; + u32 rfu : 1; + u32 iso_data_load_length : 14; + u32 rfu2 : 2; + + u32 time_stamp; + + u32 packet_sequence_num : 16; + u32 iso_sdu_length : 12; + u32 rfu3 : 2; + //0b00 Valid data. The complete ISO_SDU was received correctly. + //0b01 Possibly invalid data. The contents of the ISO_SDU may contain errors or + // part of the ISO_SDU may be missing. This is reported as "data with possible + // errors". + //0b10 Part(s) of the ISO_SDU were not received correctly. This is reported as + // "lost data". + u32 packet_status_flag : 2; + + uint8_t *iso_sdu; +} hci_iso_hdr_t ; + +/*! \brief LE BIGInfo Advertising report event */ +typedef struct { + uint8_t Subevent_Code; + uint16_t Sync_Handle; + uint8_t Num_BIS; + uint8_t NSE; + uint16_t ISO_Interval; + uint8_t BN; + uint8_t PTO; + uint8_t IRC; + uint16_t Max_PDU; + uint8_t SDU_Interval[3]; + uint16_t Max_SDU; + uint8_t PHY; + uint8_t Framing; + uint8_t Encryption; +} _GNU_PACKED_ le_biginfo_adv_report_evt_t; + +//Adjust Host part API +void ll_hci_init(void); + +void ll_hci_reset(void); + +void ll_hci_destory(void); + +void ll_hci_set_event_mask(const u8 *mask); + +void ll_hci_set_name(const char *name); + +void ll_hci_adv_set_params(uint16_t adv_int_min, uint16_t adv_int_max, uint8_t adv_type, + uint8_t direct_address_type, uint8_t *direct_address, + uint8_t channel_map, uint8_t filter_policy); + +void ll_hci_adv_set_data(uint8_t advertising_data_length, uint8_t *advertising_data); + +void ll_hci_adv_scan_response_set_data(uint8_t scan_response_data_length, uint8_t *scan_response_data); + +int ll_hci_adv_enable(bool enable); + +void ll_hci_scan_set_params(uint8_t scan_type, uint16_t scan_interval, uint16_t scan_window); + +int ll_hci_scan_enable(bool enable, u8 filter_duplicates); + +int ll_hci_create_conn(u8 *conn_param, u8 *addr_param); +int ll_hci_create_conn_ext(void *param); + +int ll_hci_create_conn_cancel(void); + +int ll_hci_vendor_send_key_num(u16 con_handle, u8 num); + +int ll_vendor_latency_hold_cnt(u16 conn_handle, u16 hold_cnt); + +int ll_hci_encryption(u8 *key, u8 *plaintext_data); + +int ll_hci_get_le_rand(void); + + +int ll_hci_start_encryption(u16 handle, u32 rand_low, u32 rand_high, u16 peer_ediv, u8 *ltk); + +int ll_hci_long_term_key_request_reply(u16 handle, u8 *ltk); + +int ll_hci_long_term_key_request_nagative_reply(u16 handle); + +int ll_hci_connection_update(u16 handle, u16 conn_interval_min, u16 conn_interval_max, + u16 conn_latency, u16 supervision_timeout, + u16 minimum_ce_length, u16 maximum_ce_length); + +u16 ll_hci_get_acl_data_len(void); + +u16 ll_hci_get_acl_total_num(void); + +void ll_hci_set_random_address(u8 *addr); + +int ll_hci_disconnect(u16 handle, u8 reason); + +int ll_hci_read_local_p256_pb_key(void); + +int ll_hci_generate_dhkey(const u8 *data, u32 size); + +//Adjust Controller part API +void ll_hci_cmd_handler(int *cmd); + +void ll_event_handler(int *msg); + +void ll_hci_private_free_dma_rx(u8 *rx_head); + +void ll_hci_set_data_length(u16 conn_handle, u16 tx_octets, u16 tx_time); + +hci_ll_param_t *ll_hci_param_config_get(void); +void hci_ll_get_device_address(uint8_t *addr_type, u8 *addr); +void ll_hci_set_host_channel_classification(u8 *channel_map); + +// ble5 +void ll_hci_set_ext_adv_params(u8 *data, u32 size); +void ll_hci_set_ext_adv_data(u8 *data, u32 size); +void ll_hci_set_ext_adv_enable(u8 *data, u32 size); +void ll_hci_set_phy(u16 conn_handle, u8 all_phys, u8 tx_phy, u8 rx_phy, u16 phy_options); +void ll_hci_set_ext_scan_params(u8 *data, u32 size); +void ll_hci_set_ext_scan_enable(u8 *data, u32 size); +void ll_hci_ext_create_conn(u8 *data, u32 size); +void ll_hci_set_periodic_adv_params(u8 *data, u32 size); +void ll_hci_set_periodic_adv_data(u8 *data, u32 size); +void ll_hci_set_periodic_adv_enable(u8 *data, u32 size); +void ll_hci_periodic_adv_creat_sync(u8 *data, u32 size); +void ll_hci_periodic_adv_terminate_sync(u8 *data, u32 size); +void ll_hci_periodic_adv_create_sync_cancel(void); + +int le_controller_set_mac(void *addr); + +#endif diff --git a/include_lib/btctrler/ble/ll_config.h b/include_lib/btctrler/ble/ll_config.h new file mode 100644 index 0000000..ce650fd --- /dev/null +++ b/include_lib/btctrler/ble/ll_config.h @@ -0,0 +1,213 @@ +/********************************************************************************************* + * Filename : ll_config.h + + * Description : Lto 优化Macro 定义 + + * Author : Bingquan + + * Email : bingquan_cai@zh-jieli.com + + * Last modifiled : 2018-12-19 16:12 + + * Copyright:(c)JIELI 2011-2017 @ , All Rights Reserved. +*********************************************************************************************/ +#ifndef _LL_CONFIG_H_ +#define _LL_CONFIG_H_ +#include //for UINT64_C + +/* + *-------------------LE FEATURE SUPPORT + * brief : 运行时优化(LTO)下,代码空间优化; + */ + +/* --- Core Spec 4.0 --- */ +#define LL_FEAT_ENCRYPTION (UINT64_C(1) << ( 0)) /*!< Encryption supported. */ +/* --- Core Spec 4.2 --- */ +#define LL_FEAT_CONN_PARAM_REQ_PROC (UINT64_C(1) << ( 1)) /*!< Connection Parameters Request Procedure supported. */ +#define LL_FEAT_EXT_REJECT_IND (UINT64_C(1) << ( 2)) /*!< Extended Reject Indication supported. */ +#define LL_FEAT_SLV_INIT_FEAT_EXCH (UINT64_C(1) << ( 3)) /*!< Slave-Initiated Features Exchange supported. */ +#define LL_FEAT_LE_PING (UINT64_C(1) << ( 4)) /*!< LE Ping supported. */ +#define LL_FEAT_DATA_LEN_EXT (UINT64_C(1) << ( 5)) /*!< Data Length Extension supported. */ +#define LL_FEAT_PRIVACY (UINT64_C(1) << ( 6)) /*!< LL Privacy supported. */ +#define LL_FEAT_EXT_SCAN_FILT_POLICY (UINT64_C(1) << ( 7)) /*!< Extended Scan Filter Policy supported. */ +/* --- Core Spec 5.0 --- */ +#define LL_FEAT_LE_2M_PHY (UINT64_C(1) << ( 8)) /*!< LE 2M PHY supported. */ +#define LL_FEAT_STABLE_MOD_IDX_TRANSMITTER (UINT64_C(1) << ( 9)) /*!< Stable Modulation Index - Transmitter supported. */ +#define LL_FEAT_STABLE_MOD_IDX_RECEIVER (UINT64_C(1) << (10)) /*!< Stable Modulation Index - Receiver supported. */ +#define LL_FEAT_LE_CODED_PHY (UINT64_C(1) << (11)) /*!< LE Coded PHY supported. */ +#define LL_FEAT_LE_EXT_ADV (UINT64_C(1) << (12)) /*!< LE Extended Advertising supported. */ +#define LL_FEAT_LE_PER_ADV (UINT64_C(1) << (13)) /*!< LE Periodic Advertising supported. */ +#define LL_FEAT_CH_SEL_2 (UINT64_C(1) << (14)) /*!< Channel Selection Algorithm #2 supported. */ +#define LL_FEAT_LE_POWER_CLASS_1 (UINT64_C(1) << (15)) /*!< LE Power Class 1 supported. */ +#define LL_FEAT_MIN_NUM_USED_CHAN (UINT64_C(1) << (16)) /*!< Minimum Number of Used Channels supported. */ +/* --- Core Spec 5.1 --- */ +#define LL_FEAT_CONN_CTE_REQ (UINT64_C(1) << (17)) /*!< Connection CTE Request supported */ +#define LL_FEAT_CONN_CTE_RSP (UINT64_C(1) << (18)) /*!< Connection CTE Response supported */ +#define LL_FEAT_CONNLESS_CTE_TRANS (UINT64_C(1) << (19)) /*!< Connectionless CTE Transmitter supported */ +#define LL_FEAT_CONNLESS_CTE_RECV (UINT64_C(1) << (20)) /*!< Connectionless CTE Receiver supported */ +#define LL_FEAT_ANTENNA_SWITCH_AOD (UINT64_C(1) << (21)) /*!< Anetenna Switching during CTE Transmission (AoD) supported */ +#define LL_FEAT_ANTENNA_SWITCH_AOA (UINT64_C(1) << (22)) /*!< Anetenna Switching during CTE Reception (AoA) supported */ +#define LL_FEAT_RECV_CTE (UINT64_C(1) << (23)) /*!< Receive Constant Tone Extension supported */ +#define LL_FEAT_PAST_SENDER (UINT64_C(1) << (24)) /*!< Periodic Advertising Sync Transfer – Sender supported. */ +#define LL_FEAT_PAST_RECIPIENT (UINT64_C(1) << (25)) /*!< Periodic Advertising Sync Transfer – Recipient supported. */ +#define LL_FEAT_SCA_UPDATE (UINT64_C(1) << (26)) /*!< Sleep Clock Accuracy Updates supported. */ +#define LL_FEAT_REMOTE_PUB_KEY_VALIDATION (UINT64_C(1) << (27)) /*!< Remote Public Key Validation supported. */ +/* --- Core Spec 5.2 --- */ +#define LL_FEAT_CIS_MASTER_ROLE (UINT64_C(1) << (28)) /*!< Connected Isochronous Stream Master Role supported. */ +#define LL_FEAT_CIS_SLAVE_ROLE (UINT64_C(1) << (29)) /*!< Connected Isochronous Stream Slave Role supported. */ +#define LL_FEAT_ISO_BROADCASTER (UINT64_C(1) << (30)) /*!< Isochronous Broadcaster Role supported. */ +#define LL_FEAT_ISO_SYNC (UINT64_C(1) << (31)) /*!< Isochronous Synchronizer Role supported. */ +#define LL_FEAT_ISO_HOST_SUPPORT (UINT64_C(1) << (32)) /*!< Host support for ISO Channels. */ +#define LL_FEAT_POWER_CONTROL_REQUEST (UINT64_C(1) << (33)) /*!< Power control requests supported. */ +#define LL_FEAT_POWER_CHANGE_IND (UINT64_C(1) << (34)) /*!< Power control power change indication supported. */ +#define LL_FEAT_PATH_LOSS_MONITOR (UINT64_C(1) << (35)) /*!< Path loss monitoring supported. */ + +#define LL_FEAT_PATH_LOSS_MONITOR (UINT64_C(1) << (35)) /*!< Path loss monitoring supported. */ +#define LL_FEAT_PERIODIC_ADV_ADI_SUPPORT (UINT64_C(1) << (36)) /*!< Periodic Advertising ADI supported. */ +#define LL_FEAT_CONN_SUBRATE (UINT64_C(1) << (37)) /*!< Connection subrating supported. */ +#define LL_FEAT_CONN_SUBRATE_HOST_SUPPORT (UINT64_C(1) << (38)) /*!< Connection subratingHost supported. */ +#define LL_FEAT_CHANNEL_CLASSIFICATION (UINT64_C(1) << (39)) /*!< Channel classification supported. */ + +#define LE_ENCRYPTION LL_FEAT_ENCRYPTION +#define CONNECTION_PARAMETER_REQUEST LL_FEAT_CONN_PARAM_REQ_PROC +#define EXTENDED_REJECT_INDICATION LL_FEAT_EXT_REJECT_IND +#define LE_SLAVE_INIT_FEATURES_EXCHANGE LL_FEAT_SLV_INIT_FEAT_EXCH +#define LE_PING LL_FEAT_LE_PING +#define LE_DATA_PACKET_LENGTH_EXTENSION LL_FEAT_DATA_LEN_EXT +#define LL_PRIVACY LL_FEAT_PRIVACY +#define EXTENDED_SCANNER_FILTER_POLICIES LL_FEAT_EXT_SCAN_FILT_POLICY +#define LE_2M_PHY LL_FEAT_LE_2M_PHY +#define LE_CODED_PHY LL_FEAT_LE_CODED_PHY +#define LE_EXTENDED_ADVERTISING LL_FEAT_LE_EXT_ADV +#define LE_PERIODIC_ADVERTISING LL_FEAT_LE_PER_ADV +#define CHANNEL_SELECTION_ALGORITHM_2 LL_FEAT_CH_SEL_2 + + +#define LE_CORE_V50_FEATURES \ +( \ + LE_2M_PHY | \ + LE_CODED_PHY | \ + LE_EXTENDED_ADVERTISING | \ + LE_PERIODIC_ADVERTISING | \ + CHANNEL_SELECTION_ALGORITHM_2 | \ + 0 \ +) + +#if (LE_CORE_V50_FEATURES & LE_PERIODIC_ADVERTISING) +#if ((LE_CORE_V50_FEATURES & LE_EXTENDED_ADVERTISING) == 0) +#error "enable must enable at the same time" +#endif +#endif + +#define LE_FEATURES_CONST_TONE (LL_FEAT_CONN_CTE_REQ | \ + LL_FEAT_CONN_CTE_RSP | \ + LL_FEAT_CONNLESS_CTE_TRANS | \ + LL_FEAT_CONNLESS_CTE_RECV | \ + LL_FEAT_ANTENNA_SWITCH_AOD | \ + LL_FEAT_ANTENNA_SWITCH_AOA | \ + LL_FEAT_RECV_CTE) + +#define LE_FEATURES_PAST (LL_FEAT_PAST_SENDER | \ + LL_FEAT_PAST_RECIPIENT) + +#define LE_FEATURES_CIS (LL_FEAT_CIS_MASTER_ROLE | \ + LL_FEAT_CIS_SLAVE_ROLE | \ + LL_FEAT_ISO_HOST_SUPPORT) + +#define LE_FEATURES_BIS (LL_FEAT_ISO_BROADCASTER | \ + LL_FEAT_ISO_SYNC | \ + LL_FEAT_ISO_HOST_SUPPORT) + +#define LE_FEATURES_ISO (LE_FEATURES_BIS|LE_FEATURES_CIS) + +#define LE_FEATURES_POWER_CONTROL (LL_FEAT_POWER_CONTROL_REQUEST | \ + LL_FEAT_POWER_CHANGE_IND | \ + LL_FEAT_PATH_LOSS_MONITOR) + +extern const uint64_t config_btctler_le_features; +#define LE_FEATURES_IS_SUPPORT(x) (config_btctler_le_features & (x)) + +#define LE_FEATURES_IS_SUPPORT_OPTIMIZE(x) if (LE_FEATURES_IS_SUPPORT(x) == 0x0) return +/*-----------------------------------------------------------*/ + +/* + *-------------------LE ROLES SUPPORT + * brief : 运行时优化(LTO)下,代码空间优化; + */ +#define LE_MASTER BIT(0) +#define LE_SLAVE BIT(1) +#define LE_ADV BIT(2) +#define LE_SCAN BIT(3) +#define LE_INIT BIT(4) + +/*! \brief Combination */ +#define LE_CONN (LE_MASTER|LE_SLAVE) + +extern const int config_btctler_le_roles; +#define LE_ROLES_IS_SUPPORT(x) (config_btctler_le_roles & x) + +#define LE_ROLES_IS_SUPPORT_OPTIMIZE(x) if (LE_ROLES_IS_SUPPORT(x) == 0x0) return +/*-----------------------------------------------------------*/ + +extern const int config_btctler_le_tws; +#define LE_TWS_IS_SUPPORT() (config_btctler_le_tws) + + +/*-----------------------------------------------------------*/ + +extern const int config_btctler_le_afh_en; +#define LE_AFH_IS_SUPPORT() (config_btctler_le_afh_en) + +#define LE_AFH_IS_SUPPORT_OPTIMIZE(x) if (LE_AFH_IS_SUPPORT() == 0x0) return + +/* + *-------------------LE PARAM CHECK + * brief : 运行时优化(LTO)下,代码空间优化; + */ +// extern const int config_btctler_le_param_check; +#define LE_PARAM_IS_CHECK() TRUE//(config_btctler_le_param_check) +/* + *-------------------LE RAM CONTROL + * + */ +extern const int config_btctler_le_hw_nums; +extern const int config_btctler_le_rx_nums; +extern const int config_btctler_le_acl_packet_length; +extern const int config_btctler_le_acl_total_nums; +extern const int config_btctler_le_slave_conn_update_winden; +/*-----------------------------------------------------------*/ + +/* + *-------------------LE Multi-link CONTROL + */ +extern const int config_btctler_le_master_multilink; +/*-----------------------------------------------------------*/ + +/* + *-------------------LE Vendor baseband CONTROL + */ +#define VENDOR_BB_PIS_EN BIT(0) +#define VENDOR_BB_PIS_HB BIT(1) +#define VENDOR_BB_PIS_HB_M BIT(2) +#define VENDOR_BB_MD_CLOSE BIT(3) +#define VENDOR_BB_CONNECT_SLOT BIT(4) +#define VENDOR_BB_NEW_SCAN_STRATEGY BIT(5) +#define VENDOR_BB_PIS_HB_R BIT(6) +#define VENDOR_BB_WL_COEX_ROLE_EN BIT(6) +#define VENDOR_BB_WL_COEX_ROLE BIT(7) +#define VENDOR_BB_ADV_PDU_INT(x) ((x) << 8) /* 4bit */ +#define VENDOR_BB_EVT_HOLD_TRIGG(x) ((x) << 12) /* 6bit */ +#define VENDOR_BB_RX_PAYLOAD_LEN(x) ((x) << 18) /* 7bit */ +#define VENDOR_BB_PIS_TX_PAYLOAD_LEN(x) ((x) << 25) /* 7bit*/ + +extern const u32 config_vendor_le_bb; +extern const int config_rf_oob; +/*-----------------------------------------------------------*/ + +/* + *-------------------LE close wait + */ +extern const int ble_disable_wait_enable; +/*-----------------------------------------------------------*/ + +#endif //_LL_CONFIG_H_ diff --git a/include_lib/btctrler/btcontroller_mode.h b/include_lib/btctrler/btcontroller_mode.h new file mode 100644 index 0000000..3cae87c --- /dev/null +++ b/include_lib/btctrler/btcontroller_mode.h @@ -0,0 +1,59 @@ +/********************************************************************************************* + * Filename : btcontroller_modules.h + + * Description : Lto 优化Macro 定义 + + * Author : Bingquan + + * Email : bingquan_cai@zh-jieli.com + + * Last modifiled : 2018-12-19 16:38 + + * Copyright:(c)JIELI 2011-2017 @ , All Rights Reserved. +*********************************************************************************************/ +#ifndef _BTCONTROLLER_MODE_H_ +#define _BTCONTROLLER_MODE_H_ + +/* +ble 测试串口默认使用usb口,代码要确保usb口没有其他地方使用 +开启测试模式,uart0 key 等一些功能默认关闭,请看特殊情况 +自行处理 + +1、提供实验室测试rf bqb的时候配 BT_BQB + +2、提供实验室测试rf fcc的时候配 BT_FCC + +3、如果要定频测试配BT_FRE 频点:2402 , 发射功率最大 + +4、性能测试配BT_PER,使用仪器直接连接测试即可,测试完毕后 +需要复位或者上电开机才会恢复正常流程,不复位或上电的话只支持链接一个设备 + +量产测试性能可直接配BT_NORMAL 然后通过某个外部操作来 +调用 void bredr_set_dut_enble(u8 en,u8 phone ) +en 1 :使能 bredr dut 测试然后就可以使用仪器链接测试 +phone: 1 可以被手机连接,0 不可以被手机连接上 + +如果样机通过按键等操作进入dut测试调用bredr_set_dut_enble使能可以被仪器链接, +同时调用下面函数,关闭耳机快速链接,开启可发现可链接 + tws_cancle_all_noconn() ; + user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_ENABLE, 0, NULL); + user_send_cmd_prepare(USER_CTRL_WRITE_CONN_ENABLE, 0, NULL); + + +5、可以调用 void bt_fix_fre_api() 函数实现经典蓝牙定频测试,频点2402,发射功率最大, +调用后不可恢复之前状态,只是用来量产测试,测试完需要复位或重新上电开机! + +6、可以调用 void ble_fix_fre_api()函数实现ble定频测试,发射功率最大, + +*/ + +#define BT_NORMAL 0x01 +#define BT_BQB 0x02 +#define BT_FCC 0x04 +#define BT_FRE 0x10 +#define BT_PER 0x20 + + +#define CONFIG_BT_MODE BT_NORMAL + +#endif diff --git a/include_lib/btctrler/btcontroller_modules.h b/include_lib/btctrler/btcontroller_modules.h new file mode 100644 index 0000000..90b1781 --- /dev/null +++ b/include_lib/btctrler/btcontroller_modules.h @@ -0,0 +1,279 @@ +/********************************************************************************************* + * Filename : btcontroller_modules.h + + * Description : Lto 优化Macro 定义 + + * Author : Bingquan + + * Email : bingquan_cai@zh-jieli.com + + * Last modifiled : 2018-12-19 16:38 + + * Copyright:(c)JIELI 2011-2017 @ , All Rights Reserved. +*********************************************************************************************/ +#ifndef _BTCONTROLLER_H_ +#define _BTCONTROLLER_H_ + +#include "hci_transport.h" +#include "btcontroller_mode.h" + +#include "ble/hci_ll.h" + +#include "classic/hci_lmp.h" + + +/* app 层修改蓝牙版本,可在BT_STATUS_INIT_OK case + 调用 set_bt_version 函数更改蓝牙版本号 +*/ +#define BLUETOOTH_CORE_SPEC_42 0x08 +#define BLUETOOTH_CORE_SPEC_50 0x09 +#define BLUETOOTH_CORE_SPEC_51 0x0a +#define BLUETOOTH_CORE_SPEC_52 0x0b +extern void set_bt_version(u8 version); + + +/* + *-------------------Module SUPPORT + * brief : 运行时优化(LTO)下,代码空间优化; + */ +#define BT_MODULE_CLASSIC BIT(0) +#define BT_MODULE_LE BIT(1) + +extern const int config_btctler_modules; +#define BT_MODULES_IS_SUPPORT(x) (config_btctler_modules & (x)) +/*-----------------------------------------------------------*/ +extern const int config_stack_modules; +#define STACK_MODULES_IS_SUPPORT(x) (config_stack_modules & (x)) + +/* + *-------------------Mode SELECT + * brief : 运行时优化(LTO)下,代码空间优化; + */ +extern const int config_btctler_mode; +#define BT_MODE_IS(x) (config_btctler_mode & (x)) + +/*-----------------------------------------------------------*/ + +extern const int config_btctler_hci_standard; +#define BT_HCI_STANDARD_IS_SUPPORT(x) (config_btctler_hci_standard) + + +extern const int config_bt_function ; +#define BT_ENCTRY_TASK BIT(0) +#define BT_MASTER_AFH BIT(1) +#define BT_MASTER_QOS BIT(2) + + +#define BT_FUNCTION_IS(x) (config_bt_function & (x)) + + +extern const int CONFIG_TEST_DUT_CODE; +extern const int CONFIG_TEST_FCC_CODE; +extern const int CONFIG_TEST_DUT_ONLY_BOX_CODE; +extern const int CONFIG_BREDR_INQUIRY; + +extern const int CONFIG_INQUIRY_PAGE_OFFSET_ADJUST ; + +extern const int CONFIG_LMP_NAME_REQ_ENABLE ; +extern const int CONFIG_LMP_PASSKEY_ENABLE ; +extern const int CONFIG_LMP_MASTER_ESCO_ENABLE ; +extern const int config_btctler_bredr_master ; +extern const int config_bredr_afh_user ; +extern const int config_bredr_master_afh ; +extern const int CONFIG_ESCO_MUX_RX_BULK_ENABLE ; +extern const int config_bt_temperature_pll_trim ; +extern const int CONFIG_WIFI_DETECT_ENABLE; +extern const int ESCO_FORWARD_ENABLE; +/********************************************************************************/ +/* + * API + * + */ + +/* --------------------------------------------------------------------------*/ +/** + * @brief rf_set_24g_hackable_coded + * + * @param coded 2.4G 配对码 + */ +/* ----------------------------------------------------------------------------*/ +void rf_set_24g_hackable_coded(int coded); + + +/* --------------------------------------------------------------------------*/ +/** + * @brief bt_pll_para + * + * @param osc + * @param sys + * @param low_power + * @param xosc + */ +/* ----------------------------------------------------------------------------*/ +void bt_pll_para(u32 osc, u32 sys, u8 low_power, u8 xosc); + + +/* --------------------------------------------------------------------------*/ +/** + * @brief bt_production_test + * + * @param en + */ +/* ----------------------------------------------------------------------------*/ +void bt_production_test(u8 en); + +/* --------------------------------------------------------------------------*/ +/** + * @brief bt_set_rxtx_status_enable + * + * @param en + * + * + + TX RX + AI800x PA13 PA12 + AC692x PA13 PA12 + AC693x PA8 PA9 + AC695x PA9 PA10 + AC696x PC1 PC2 + AC694x PB1 PB2 + AC697x PC2 PC3 + AC631x PA7 PA8 + + */ +/* ----------------------------------------------------------------------------*/ +void bt_set_rxtx_status_enable(u8 en); + +/* --------------------------------------------------------------------------*/ +/** + * @brief bt_osc_offset_ext_save + * + * @param offset + * + * 更新并且保存频偏 + */ +/* ----------------------------------------------------------------------------*/ +void bt_osc_offset_ext_save(s32 offset); + +/* --------------------------------------------------------------------------*/ +/** + * @brief bt_osc_offset_ext_updata + * + * @param offset + * + * 更新频偏 + */ +/* ----------------------------------------------------------------------------*/ +void bt_osc_offset_ext_updata(s32 offset); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 初始化配置蓝牙发射功率最大值范围 + * + * @param pwr edr 连接后发射功率(range:0~9) + * @param pg_pwr edr page 可连接状态发射功率 + * @param iq_pwr edr inquiry 可发现状态发射功率 + * @param ble_pwr ble 发射功率 + */ +/* ----------------------------------------------------------------------------*/ +/* +蓝牙TX发射功率档位, 参考功率值(dbm) ,超过等级范围默认设置为最高档 +BD29: rang(0~8) {-18.3, -14.6, -12.1, -8.5, -6.0, -4.1, -1.1, +1.1, +4.0, +6.1} +BD19: rang(0~10) {-17.6, -14.0, -11.5, -9.6, -6.6, -4.4, -0.79, +1.12, +3.8, +5.65, +8.04} +BR23: rang(0~9) {-15.7, -12.5, -10.0, -6.6, -4.4, -2.5, -0.1, +2.1, +4.6, +6.4} +BR25: rang(0~9) {-15.7, -12.5, -10.0, -6.6, -4.4, -2.5, -0.1, +2.1, +4.6, +6.4} +BR30: rang(0~8) {-17.48, -11.46, -7.96, -3.59, -0.79, +1.12, +3.8, +6.5, +8.44} +BR34: rang(0~10) {-17.6, -14.0, -11.5, -9.6, -6.6, -4.4, -1.8, 0, +2.1, +4, +6.3} +*/ + +void bt_max_pwr_set(u8 pwr, u8 pg_pwr, u8 iq_pwr, u8 ble_pwr); + +/* --------------------------------------------------------------------------*/ +/** + * @brief bt_set_ldos + * + * @param mode + */ +/* ----------------------------------------------------------------------------*/ +void bt_set_ldos(u8 mode); + +/* --------------------------------------------------------------------------*/ +/** + * @brief ble_set_fix_pwr + * + * @param fix (0~max) + * 动态调整BLE的发射功率 + */ +/* ----------------------------------------------------------------------------*/ +void ble_set_fix_pwr(u8 fix); + + +/* --------------------------------------------------------------------------*/ +/** + * @brief bredr_set_fix_pwr + * + * @param fix (0~max) + * 动态调整EDR的发射功率 + */ +/* ----------------------------------------------------------------------------*/ +void bredr_set_fix_pwr(u8 fix); + +/* --------------------------------------------------------------------------*/ +/** + * @brief ble_rf_vendor_fixed_channel + * + * @param channel_index: 指定信道定频: range 0~39 fixed freq, or 0xff --close fixed,default 37、38、39 + * @param pktcnt: adv方式,1次发包的个数: range 1~3 + * 配置ble 的 adv、scan、init 状态定频 + */ +/* ----------------------------------------------------------------------------*/ +bool ble_rf_vendor_fixed_channel(u8 channel_index, u8 pktcnt); + +/* --------------------------------------------------------------------------*/ +/** + * @brief bredr_get_rssi_for_address + * 获取已连接设备的rssi + * + * @param address 对方mac地址 + * @return rssi 值,range(-127 ~ +127) + */ +/* ----------------------------------------------------------------------------*/ +s8 bredr_get_rssi_for_address(u8 *address); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 配置tx 是否支持包类型, (sdk默认支持) + * + * @param packet_type + * @param support_en 0 or 1 + * @return true or false + */ +/* ----------------------------------------------------------------------------*/ +typedef enum { + PKT_TYPE_2DH5_EU = 0, +} pkt_type_eu; + +bool bredr_link_vendor_support_packet_enable(pkt_type_eu packet_type, u8 support_en); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 配置ble 优先级锁定不低压ACL, (sdk 默认自动调节) + * + * @param role:0--master,1--slave + * @param enalbe 0 or 1 + * @return null + */ +/* ----------------------------------------------------------------------------*/ +void ble_vendor_set_hold_prio(u8 role, u8 enable); + +void set_bt_afh_classs_enc(u8 afh_class); +void set_bt_enhanced_power_control(u8 en); +void set_bt_data_rate_acl_3mbs_mode(u8 en); + +void set_bt_full_name_event(u8 en); + +/* coexist between bt chips */ +void bt_wl_coex_init(uint8_t state); +void bt_wl_coex_enable(bool enable); + +#endif diff --git a/include_lib/btctrler/btctrler_task.h b/include_lib/btctrler/btctrler_task.h new file mode 100644 index 0000000..ac972df --- /dev/null +++ b/include_lib/btctrler/btctrler_task.h @@ -0,0 +1,130 @@ +#ifndef BTCTRLER_TASK_H +#define BTCTRLER_TASK_H + +#include "typedef.h" +#include "system/task.h" + +enum { + LMP_EVENT = Q_USER + 1, + LMP_HCI_CMD, + LMP_HCI_CMD_TO_CONN, + HCI_COMMON_CMD, + LL_EVENT, + HCI_CMD_TO_LL, + TWS_LMP_EVENT, + MSG_BT_UPDATA_START, + MSG_BT_UPDATE_LOADER_DOWNLOAD_START, + MSG_BLE_TEST_UPDATA_START, + MSG_BLE_TEST_OTA_LOADER_DOWNLOAD_START, + MSG_TASK_READY, + MSG_TASK_DEL, +}; + +enum { + BTCTRLER_EVENT_RESUME_REQ = 1, +}; + +#define SYS_EVENT_FROM_CTRLER (('C' << 24) | ('T' << 16) | ('R' << 8) | '\0') + + + + +int bredr_link_event(void *link, int argc, ...); + +int bredr_tws_link_event(void *link, int argc, ...); + +int btctrler_hci_cmd_to_task(int cmd, int argc, ...); + +int lmp_hci_cmd_to_conn_for_handle(u16 handle, int argc, ...); + +int lmp_hci_cmd_to_conn_for_addr(u8 *addr, int argc, ...); + +int lmp_hci_cmd_to_conn(void *conn, int argc, ...); + + +#define lmp_hci_cmd_to_task(argc, ...) btctrler_hci_cmd_to_task(LMP_HCI_CMD, argc, ## __VA_ARGS__) + +#define ll_hci_cmd_to_task(argc, ...) btctrler_hci_cmd_to_task(HCI_CMD_TO_LL, argc, ## __VA_ARGS__) + + +int btctrler_task_init(const void *transport, const void *config); + +void btctrler_resume_req(); + +void btctrler_resume(); + +int btctrler_suspend(u8 suepend_rx_bulk); + +int btctrler_task_ready(); + +int btctrler_task_exit(); + +int btctrler_task_close_bredr(); +void btctrler_task_init_bredr(); + +void set_idle_period_slot(u16 slot); +enum { + TESTBOX_INFO_VBAT_VALUE = 0, //(u16 (*handle)(void)) + TESTBOX_INFO_VBAT_PERCENT, //(u8 (*handle)(void)) + TESTBOX_INFO_BURN_CODE, //(u8 *(*handle)(u8 *len)) + TESTBOX_INFO_SDK_VERSION, //(u8 *(*handle)(u8 *len)) +}; + +void bt_testbox_ex_info_get_handle_register(u8 info_type, void *handle); +u8 bredr_bulk_change_rx_bulk(u8 mode); +void lmp_set_features_req_step(u8 *addr); + +struct ble_dut_tx_param_t { + u8 ch_index; //data[0] + u8 payload_len; //data[1] + u8 payload_type;//data[2] + u8 phy_type; //data[3] +}; + +struct ble_dut_rx_param_t { + u8 ch_index; //data[0] + u8 phy_type; //data[1] +}; + +enum BLE_DUT_CTRL_TYPE { + BLE_DUT_SET_RX_MODE = 0, //param1:struct ble_dut_rx_param_t *param; + BLE_DUT_SET_TX_MODE, //param1:struct ble_dut_tx_param_t *param; + BLE_DUT_SET_TEST_END, //param1:u16 *pkt_valid_cnt,param2:u16 *pkt_err_cnt; +}; + +struct ble_dut_ops_t { + + /* *****************************************************************************/ + /** + * @brief : initialize the ble dut test module + * + * @param : void + * + * @return : pointer to instance of test module + */ + /* *****************************************************************************/ + void *(*init)(void); + + /* *****************************************************************************/ + /** + * @brief : ble dut test control api,such as setting rx/tx mode,stop testing + * + * @param : control type,using enum BLE_DUT_CTRL_TYPE value; + * @param : vary from different control type; + */ + /* *****************************************************************************/ + int (*ioctrl)(int ctrl, ...); + + /* *****************************************************************************/ + /** + * @brief : exit the ble dut test module + * + * @param : poniter to instance of test module + */ + /* *****************************************************************************/ + void (*exit)(void *priv); +}; + +extern const struct ble_dut_ops_t *__ble_dut_ops; + +#endif diff --git a/include_lib/btctrler/classic/hci_lmp.h b/include_lib/btctrler/classic/hci_lmp.h new file mode 100644 index 0000000..ea931d7 --- /dev/null +++ b/include_lib/btctrler/classic/hci_lmp.h @@ -0,0 +1,220 @@ +#ifndef LMP_API_H +#define LMP_API_H + + + + + + +int lmp_private_is_clearing_a2dp_packet(void *_conn); + +int lmp_private_a2dp_channel_exist(void *_conn); + +int lmp_private_get_sbc_remain_time(void *_conn, u8 include_tws); + +void *lmp_private_open_sbc_channel(u8 *addr, u16 channel, u8 codec_type); + +void lmp_private_free_sbc_packet(void *_conn, void *packet); + +int lmp_private_get_sbc_data_len(void *_conn); + +int lmp_private_get_rx_buffer_size(); + +void lmp_private_set_max_rx_buf_persent(u8 *addr, int persent); + +void *lmp_private_fetch_sbc_packet(void *_conn, int *len, void *_prev, int); + +int lmp_private_get_sbc_packet_num(void *_conn); +void lmp_private_close_sbc_channel(void *_conn); + +int lmp_private_get_sbc_packet(void *_conn, u8 **frame, int block); + +u8 *lmp_private_get_tx_packet_buffer(int size); + +int lmp_private_clear_a2dp_packet(void *_conn, u16 seqn_number); + +int lmp_private_send_esco_packet(void *priv, u8 *packet, int len); + +u8 *lmp_private_remote_addr_for_handler(int handle); + +u16 lmp_private_handler_for_remote_addr(u8 *addr, int link_type); + +int lmp_private_get_rx_buffer_total_size(void *_conn); + +int lmp_private_get_rx_buffer_remain_size(void *_conn); + +void lmp_hci_private_hold_acl_packet(u8 *packet); + +void lmp_hci_private_free_acl_packet(u8 *packet); + +void lmp_hci_private_try_free_acl_packet(u8 *packet); + +int lmp_hci_send_packet(u8 *packet, int len); + +int lmp_hci_send_packet_standard(const u8 *packet, int len); + +int lmp_hci_reset(); + +int lmp_hci_write_scan_enable(u8 enable); + +void lmp_hci_write_class_of_device(int dev_class); + +void lmp_hci_write_local_name(const char *name); +void lmp_hci_write_local_priv_version(const char *ic_verson, const char *priv_version, u8 *tws_local_addr); + +void lmp_hci_write_local_address(const u8 *addr); + +void lmp_hci_write_simple_pairing_mode(u8 enable); + +void lmp_hci_write_super_timeout(u16 timeout); +void lmp_hci_write_page_timeout(u16 timeout); +void lmp_hci_write_tws_internal_addr(u8 *internal_addr_local, u8 *internal_addr_remote); + +void lmp_hci_write_link_supervision_timeout(u16 handle, int); + +int lmp_hci_write_le_host_support(int features); + +int lmp_hci_read_pin_type(); + +void lmp_hci_set_pin_code(const char *code, u8 len); + +void lmp_hci_pin_code_request_reply(u8 *addr, u8 len, u8 *pin_code); + +void lmp_hci_pin_code_request_negative_reply(u8 *addr); + +int lmp_hci_write_pin_type(u8 type); + +int lmp_hci_set_connection_encryption(u16 handle, int enable); + +void lmp_hci_io_capability_request_reply(u8 *addr, u8 io_cap, u8 oob_data, u8 auth_req); + +void lmp_hci_user_confirmation_request_reply(u8 *address); + +void lmp_hci_user_confirmation_request_negative_reply(u8 *addr); + +int lmp_hci_disconnect(u16 handle, u8 reason); +int lmp_hci_test_key_cmd(u8 cmd, u16 handle); +int lmp_hci_send_user_info_cmd(u32 info, u16 handle); + +void lmp_hci_accept_connection_request(u8 *addr, u8 role); + +void lmp_hci_accept_sco_connection_request(u8 *addr, u32 tx_bandwidth, + u32 rx_bandwidth, u16 max_latency, u16 content_format, + u8 retransmission, u16 packey_type); + +void lmp_hci_reject_connection_request(u8 *addr, u8 reason); + +void lmp_hci_switch_role_command(u8 *addr, u8 role); + +void lmp_hci_authentication_requested(u16 handler); + +void lmp_hci_link_key_request_reply(u8 *addr, u8 *link_key); + +void lmp_hci_link_key_request_negative_reply(u8 *addr); + +void lmp_hci_write_default_link_policy_settings(u16 setting); + +void lmp_hci_release_packet(u8 *packet); + +void lmp_hci_create_connection(const u8 *addr, u16 packet_type, + u8 repetition_mode, u8 reserved, + u16 clk_offset, u8 allow_role_switch); + +void lmp_hci_connection_cancel(u8 *addr);; + +void lmp_hci_cancel_page(); +void lmp_hci_inquiry(int lap, u8 length, u8 num); +void lmp_hci_cancel_inquiry(); +void lmp_hci_sniff_mode_command(u16 handle, u16 max_interval, u16 min_interval, u16 attempt, u16 timeout); +void lmp_hci_exit_sniff_mode_command(u16 handle); + +void lmp_hci_host_num_of_completed_packets(u16 handle, u16 num_of_completed_packet); + +int lmp_hci_read_remote_version_information(u16 handle); + +void lmp_hci_read_remote_supported_features(u16 handle); + +void lmp_hci_read_remote_extended_features(u16 handle); + +void lmp_hci_role_discovery(u16 handle); + +void lmp_hci_read_clock_offset(u16 handle); + +void lmp_hci_read_link_policy_settings(u16 handle); +void lmp_hci_write_link_policy_settings(u16 handle, u16 policy); + +void lmp_hci_remote_name_request(u8 *addr, u8 page_scan_repetition_mode, u16 clk_offset); + +void lmp_set_sniff_establish_by_remote(u8 enable); + +void lmp_set_sniff_disable(void); + + +u8 lmp_hci_read_local_supported_features(int octet); + +void lmp_hci_write_local_supported_features(u8 features, int octet); + + +u8 lmp_standard_connect_check(void); + +void lmp_hci_send_keypress_notification(u8 *addr, u8 key); +void lmp_hci_user_keypress_request_reply(u8 *addr, u32 key); +void lmp_hci_user_keypress_request_negative_reply(u8 *addr, u8 key); + + +void lmp_hci_set_role_switch_supported(bool enable); +void lmp_hci_tx_channel_chassification(u8 *map); + + + +u8 *get_tws_internal_addr(int channel); + +extern int lmp_private_esco_suspend_resume(int flag);; + +void user_set_tws_box_mode(u8 mode); + + +void bt_set_tx_power(u8 txpower); + + +void bredr_bulk_change(u8 mode); + + +extern u8 get_bredr_link_state(); + +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 u8 tws_remote_state_check(void); +extern void tws_remote_state_clear(void); +extern void user_set_tws_box_mode(u8 mode); + + +extern void bredr_fcc_init(u8 mode, u8 fre); +extern void bredr_set_dut_enble(u8 en, u8 phone); + +extern int a2dp_media_clear_packet_before_seqn(u16 seqn_number); + + +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中 +}; + +#define DH1_1 0 +#define DH3_1 1 +#define DH5_1 2 +#define DH1_2 3 +#define DH3_2 4 +#define DH5_2 5 + +int link_fix_tx_enable(u8 *remote_addr, u8 fre, u8 packet_type, u16 payload); +int link_fix_rx_enable(u8 *remote_addr, u8 fre, u8 packet_type, u16 payload); +void link_fix_txrx_disable(); +void link_fix_rx_update_result(struct link_fix_rx_result *result); +void link_fix_rx_dump_result(); + + +#endif diff --git a/include_lib/btctrler/classic/lmp_config.h b/include_lib/btctrler/classic/lmp_config.h new file mode 100644 index 0000000..e5339bb --- /dev/null +++ b/include_lib/btctrler/classic/lmp_config.h @@ -0,0 +1,18 @@ +/********************************************************************************************* + * Filename : lmp_config.h + + * Description : Lto 优化Macro 定义 + + * Author : Bingquan + + * Email : bingquan_cai@zh-jieli.com + + * Last modifiled : 2018-12-19 16:38 + + * Copyright:(c)JIELI 2011-2017 @ , All Rights Reserved. +*********************************************************************************************/ +#ifndef _LMP_CONFIG_H_ +#define _LMP_CONFIG_H_ + +#endif + diff --git a/include_lib/btctrler/classic/tws_api.h b/include_lib/btctrler/classic/tws_api.h new file mode 100644 index 0000000..ebbe4fe --- /dev/null +++ b/include_lib/btctrler/classic/tws_api.h @@ -0,0 +1,243 @@ +#ifndef TWS_API_H +#define TWS_API_H + +#include "typedef.h" + +#include "classic/tws_event.h" +#include "classic/tws_local_media_sync.h" +#include "classic/tws_data_trans.h" + +#define TWS_ROLE_MASTER 0 +#define TWS_ROLE_SLAVE 1 + +/* + * tws 状态 + */ +#define TWS_STA_SIBLING_DISCONNECTED 0x00000001 //tws未连接 +#define TWS_STA_SIBLING_CONNECTED 0x00000002 //tws已连接 +#define TWS_STA_PHONE_DISCONNECTED 0x00000004 //手机未连接 +#define TWS_STA_PHONE_CONNECTED 0x00000008 //手机已连接 +#define TWS_STA_ESCO_OPEN 0x00000010 //正在打电话 +#define TWS_STA_SBC_OPEN 0x00000020 //正在播歌 +#define TWS_STA_MONITOR_START 0x00000040 //tws从机开始监听手机链路 +#define TWS_STA_LOCAL_TWS_OPEN 0x00000080 //开启local_tws +#define TWS_STA_ESCO_OPEN_LINK 0x00000100 //正在打电话,create link +#define TWS_STA_MONITOR_ING 0x00000200 //tws主从收到监听信息 + +#define TWS_SYNC_CALL_TX 1 +#define TWS_SYNC_CALL_RX 2 + +struct tws_sync_call { + int uuid; + void (*func)(int priv, int err); + const char *task_name; +}; + +extern const struct tws_sync_call tws_sync_call_begin[]; +extern const struct tws_sync_call tws_sync_call_end[]; + +#define list_for_each_tws_sync_call(p) \ + for (p = tws_sync_call_begin; p < tws_sync_call_end; p++) + + +#define TWS_SYNC_CALL_REGISTER(sync_call) \ + static const struct tws_sync_call __tws_##sync_call sec(.tws_sync_call) + + +#define TWS_FUNC_ID(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) + +typedef void (*tws_func_t)(void *data, u16 len, bool rx); + +struct tws_func_stub { + u32 func_id; + tws_func_t func; //call from irq +}; + +#define REGISTER_TWS_FUNC_STUB(stub) \ + static const struct tws_func_stub stub sec(.tws_func_stub) + +extern const struct tws_func_stub tws_func_stub_begin[]; +extern const struct tws_func_stub tws_func_stub_end[]; + +static inline tws_func_t tws_function_get_by_id(u32 id) +{ + const struct tws_func_stub *p; + + for (p = tws_func_stub_begin; p < tws_func_stub_end; p++) { + if (p->func_id == id) { + return p->func; + } + } + return NULL; +} + +static inline void tws_function_call_by_id(u32 id, void *data, u16 len, bool rx) +{ + const struct tws_func_stub *p; + + for (p = tws_func_stub_begin; p < tws_func_stub_end; p++) { + if (p->func_id == id) { + p->func(data, len, rx); + break; + } + } +} + + +/* + * 通过搜索码搜索tws设备 + */ +int tws_api_search_sibling_by_code(u16 code, int timeout_ms); + +/* + *打开可发现, 可连接,可被手机和tws搜索到 + */ +int tws_api_wait_pair_by_code(u16 code, const char *name, int timeout_ms); +int tws_api_wait_pair_by_ble(u16 code, const char *name, int timeout_ms); + +int tws_api_wait_tws_pair(int code, const char *name); + +int tws_api_wait_phone_pair(int code, const char *name); + + +int tws_wait_tws_pair(u16 code, const char *name); + +int tws_wait_phone_pair(u16 code, const char *name); + + +/* + *取消可发现, 可连接,可被tws搜索到 + */ +int tws_api_cancle_wait_pair(); + + + +/* + * 搜索并连接已经配对过的tws + * timeout: 单位ms, 0 表示不超时 + * 返回值: 0: 函数调用成功 + */ +int tws_api_create_connection(int timeout); + + +/* + * 取消搜索已配对的tws + */ +int tws_api_cancle_create_connection(); + + +/* + * 打开可发现,可连接, 可以被手机和已配对过的tws连接 + */ +int tws_api_wait_connection(); + + +/* + * 断开tws直接的连接 + * reason: 断开原因 + */ +int tws_api_detach(enum tws_detach_reason reason); + +/* + * 获取主从, 播歌和打电话状态下结果不可靠,请勿调用 + */ +int tws_api_get_role(); + +/* + * 获取tws 连接的状态 + * 返回值: 详见顶部TWS_STA_** + */ +int tws_api_get_tws_state(); + +/* + * 设置tws对方地址 + */ +int tws_api_set_sibling_addr(u8 *addr); + +/* + * 获取tws对方地址 + */ +int tws_api_get_sibling_addr(u8 *addr); + + +/* + * 获取tws本地地址 + */ +int tws_api_get_local_addr(u8 *addr); + +/* + *发送解除配对命令给对方, 成功后会收到TWS_EVENT_REMOVE_PAIRS事件 + */ +int tws_api_remove_pairs(); + + +/* + * 设置本地声道 + * 'L': 左声道 + * 'R': 右声道 + * 'U': 双声道合并 + */ +void tws_api_set_local_channel(char channel); + +/* + * 获取本地声道 + */ +char tws_api_get_local_channel(); + +/* + * 通过uuid,主从同步调用相同函数 + */ +int tws_api_sync_call_by_uuid(int uuid, int priv, int delay_ms); + +/* + * tws 数据发送函数, 要求 len <= 512 + */ +int tws_api_send_data_to_sibling(void *data, u16 len, u32 func_id); + +int tws_api_send_data_to_slave(void *data, int len, u32 func_id); + +int tws_profile_init(); +int tws_profile_exit(); + + + +int tws_api_connect_in_esco(); +int tws_api_cancle_connect_in_esco(); +int tws_disconnect(); + +/* + * 使能对耳自动主从切换 + */ +void tws_api_auto_role_switch_enable(); + +/* + * 关闭对耳自动主从切换 + */ +void tws_api_auto_role_switch_disable(); + +int tws_api_get_low_latency_state(); + +int tws_api_low_latency_enable(bool enable); + + +void tws_api_set_quick_connect_addr(u8 *addr); + +u8 *tws_api_get_quick_connect_addr(); + +void tws_api_common_addr_en(u8 en); + +void tws_api_pair_all_way(u8 en); + +int tws_api_power_saving_mode_enable(); + +int tws_api_power_saving_mode_disable(); + +int tws_api_enter_pure_monitor_mode(); + +void tws_try_connect_disable(void); + +void tws_conn_switch_role(); + +void tws_api_role_switch(); + +#endif diff --git a/include_lib/btctrler/classic/tws_data_trans.h b/include_lib/btctrler/classic/tws_data_trans.h new file mode 100644 index 0000000..a1042af --- /dev/null +++ b/include_lib/btctrler/classic/tws_data_trans.h @@ -0,0 +1,47 @@ +#ifndef TWS_DATA_TRANS_H +#define TWS_DATA_TRANS_H + +#include "generic/typedef.h" + +enum { + TWS_DATA_TRANS_SOURCE, + TWS_DATA_TRANS_SINK, +}; + +enum tws_data_trans_attr { + TWS_DTC_LOCAL_MEDIA, + TWS_DTC_MIC_REC, +}; + +u8 tws_api_data_trans_open(u8 channel, enum tws_data_trans_attr attr, u16 buf_size); + + +int tws_api_data_trans_start(u8 channel, u8 *arg, u8 len); + + +int tws_api_data_trans_stop(u8 channel); + + +int tws_api_data_trans_close(u8 channel); + + +void tws_api_data_trans_auto_drop(u8 channel, int enable); + +int tws_api_data_trans_send(u8 channel, u8 *buf, int len); + +void *tws_api_data_trans_buf_alloc(u8 channel, int len); + +int tws_api_data_trans_push(u8 channel, void *_frame, int len); + +void *tws_api_data_trans_pop(u8 channel, int *len); + +void tws_api_data_trans_free(u8 channel, void *_frame); + +void *tws_api_data_trans_fetch(u8 channel, void *_prev, int *len); + +void tws_api_data_trans_clear(u8 channel); + +int tws_api_data_trans_check(u8 channel, u16 *ready_len, u16 *total_len); + +#endif + diff --git a/include_lib/btctrler/classic/tws_event.h b/include_lib/btctrler/classic/tws_event.h new file mode 100644 index 0000000..ecec7a6 --- /dev/null +++ b/include_lib/btctrler/classic/tws_event.h @@ -0,0 +1,95 @@ +#ifndef TWS_EVENT_H +#define TWS_EVENT_H + +#define KEY_EVENT_FROM_TWS (('T' << 24) | ('W' << 16) | ('S' << 8) | '\0') +#define SYS_BT_EVENT_FROM_TWS (('T' << 24) | ('W' << 16) | ('S' << 8) | '\0') + +enum { + TWS_STA_WAIT_SIBLING_PAIR = 1, + TWS_STA_SEARCH_SIBLING, + TWS_STA_CREATE_CONNECTION_BREDR, + TWS_STA_CREATE_CONNECTION_BLE, + TWS_STA_WAIT_CONNECTION_BREDR, + TWS_STA_WAIT_CONNECTION_BLE, + TWS_STA_DISCONNECTION, + TWS_STA_CONNECTION, + TWS_STA_START_MONITOR, + TWS_STA_MONITOR, + TWS_STA_WAIT_PHONE_PAIR, + TWS_STA_WAIT_PAIR, +}; + +enum { + LOCAL_REMOTE_ADDR = 0, + TWS_PAIR_REMOTE_ADDR_STATE_OK, + TWS_PAIR_REMOTE_ADDR_STATE_NOT, +}; + +enum tws_detach_reason { + TWS_DETACH_BY_SUPER_TIMEOUT = 8, + TWS_DETACH_BY_LOCAL, + TWS_DETACH_BY_REMOTE, + TWS_DETACH_BY_POWEROFF, + TWS_DETACH_BY_REMOVE_PAIRS, + TWS_DETACH_BY_TESTBOX_CON, + TWS_DETACH_BY_REMOVE_NO_RECONN, +}; + + +#define TWS_CONN_CHANNEL 0 +#define TWS_LINK_SYNC_CHANNEL 1 +#define TWS_LMP_SYNC_CHANNEL 2 +#define TWS_AFH_SYNC_CHANNEL 3 +#define TWS_TX_SYNC_CHANNEL 4 +#define TWS_LOW_LATENCY_CHANNEL 5 +#define TWS_DATA_SYNC_CHANNEL 6 +#define TWS_SBC_SYNC_CHANNEL 7 +#define TWS_EVENT_SYNC_CHANNEL 8 +#define TWS_SYNC_CALL_CHANNEL 9 +#define TWS_POWER_BALANCE_CHANNEL 10 +#define TWS_CI_DATA_SYNC_CHANNEL 11 +#define TWS_LOCAL_MEIDA_SYNC_CHANNEL 12 +#define TWS_LMP_SLOT_CHANNEL 13 +#define TWS_DATA_TRANS_CHANNEL 14 + +enum { + TWS_EVENT_SEARCH_TIMEOUT = 1, + TWS_EVENT_CONNECTED, + TWS_EVENT_CONNECTION_TIMEOUT, + TWS_EVENT_CONNECTION_DETACH, + TWS_EVENT_REMOVE_PAIRS, + TWS_EVENT_PHONE_LINK_DETACH, + TWS_EVENT_SYNC_FUN_CMD, + TWS_EVENT_SYNC_FUN_TRANID, + TWS_EVENT_CONNECT_TEST, + TWS_EVENT_ROLE_SWITCH, + TWS_EVENT_LOCAL_MEDIA_START, + TWS_EVENT_LOCAL_MEDIA_STOP, + TWS_EVENT_ESCO_ADD_CONNECT, + TWS_EVENT_SETUP_MONITOR_LINK, + TWS_EVENT_MONITOR_START, + TWS_EVENT_DATA_TRANS_OPEN, + TWS_EVENT_DATA_TRANS_START, + TWS_EVENT_DATA_TRANS_STOP, + TWS_EVENT_DATA_TRANS_CLOSE, + + TWS_EVENT_MODE_CHANGE, //sniff without phone + + TWS_EVENT_ROLE_SWITCH_START, + TWS_EVENT_TONE_TEST = 0xff, +}; + + + + + + + + + + + + + +#endif + diff --git a/include_lib/btctrler/classic/tws_local_media_sync.h b/include_lib/btctrler/classic/tws_local_media_sync.h new file mode 100644 index 0000000..f5b9022 --- /dev/null +++ b/include_lib/btctrler/classic/tws_local_media_sync.h @@ -0,0 +1,48 @@ +#ifndef TWS_LOCAL_MEDIA_SYNC_H +#define TWS_LOCAL_MEDIA_SYNC_H + +#include "generic/list.h" +#include "generic/typedef.h" + + + +void tws_api_local_media_trans_start(); + +void tws_api_local_media_trans_set_buf(void *buf, int size); + +void *tws_api_local_media_trans_alloc(int len); + +void tws_api_local_media_trans_free(void *frame); + +void tws_api_local_media_trans_push(void *frame, int len); + +void *tws_api_local_media_trans_pop(int *len); + +void *tws_api_local_media_trans_fetch(void *prev, int *len); + +void tws_api_local_media_trans_stop(); + +void tws_api_local_media_trans_packet_del(void *_frame); +int tws_api_local_media_trans_check_total(u8 head); +int tws_api_local_media_trans_check_ready_total(void); +void tws_api_local_media_trans_clear(void); +int tws_api_local_media_packet_cnt(u8 *rx_packet_cnt, u8 *wait_send_pcaket_cnt); + +// 填数超过了一定值才可以发送 +void tws_api_local_media_set_limit_size(int size); + +int tws_api_local_media_trans_bulk_push(u8 *buf, int len); + +int tws_api_local_media_push_with_sequence(u8 *buf, int len, u16 seqn); + +int tws_api_local_media_push_with_timestamp(u8 *buf, int len, u32 timestamp); + +int tws_api_local_media_trans_open(u16 buf_size); + +int tws_api_local_media_dec_start(u8 *arg, u8 len); + +int tws_api_local_media_dec_stop(); + +void tws_api_auto_drop_frame_enable(int enable); +#endif + diff --git a/include_lib/btctrler/hci_transport.h b/include_lib/btctrler/hci_transport.h new file mode 100644 index 0000000..79ccfc9 --- /dev/null +++ b/include_lib/btctrler/hci_transport.h @@ -0,0 +1,249 @@ +/********************************************************************************************* + * Filename : hci_transport.h + + * Description : + + * Author : Bingquan + + * Email : bingquan_cai@zh-jieli.com + + * Last modifiled : 2017-01-17 15:14 + + * Copyright:(c)JIELI 2011-2016 @ , All Rights Reserved. +*********************************************************************************************/ +#ifndef __BTCONTROLLER_HCI_TRANSPORT_H +#define __BTCONTROLLER_HCI_TRANSPORT_H + +//#include +#include "generic/typedef.h" + +#if defined __cplusplus +extern "C" { +#endif + + /* API_START */ + typedef struct { + uint32_t baudrate; + int flowcontrol; + const char *device_name; + } btstack_uart_config_t; + + typedef enum { + // UART active, sleep off + BTSTACK_UART_SLEEP_OFF = 0, + // used for eHCILL + BTSTACK_UART_SLEEP_RTS_HIGH_WAKE_ON_CTS_PULSE, + // used for H5 and for eHCILL without support for wake on CTS pulse + BTSTACK_UART_SLEEP_RTS_LOW_WAKE_ON_RX_EDGE, + + } btstack_uart_sleep_mode_t; + + typedef enum { + BTSTACK_UART_SLEEP_MASK_RTS_HIGH_WAKE_ON_CTS_PULSE = 1 << BTSTACK_UART_SLEEP_RTS_HIGH_WAKE_ON_CTS_PULSE, + BTSTACK_UART_SLEEP_MASK_RTS_LOW_WAKE_ON_RX_EDGE = 1 << BTSTACK_UART_SLEEP_RTS_LOW_WAKE_ON_RX_EDGE + } btstack_uart_sleep_mode_mask_t; + + typedef struct { + /** + * init transport + * @param uart_config + */ + int (*init)(const btstack_uart_config_t *uart_config); + + /** + * open transport connection + */ + int (*open)(void); + + /** + * close transport connection + */ + int (*close)(void); + + /** + * set callback for block received. NULL disables callback + */ + void (*set_block_received)(void (*block_handler)(void)); + + /** + * set callback for sent. NULL disables callback + */ + void (*set_block_sent)(void (*block_handler)(void)); + + /** + * set baudrate + */ + int (*set_baudrate)(uint32_t baudrate); + + /** + * set parity + */ + int (*set_parity)(int parity); + + /** + * set flowcontrol + */ + int (*set_flowcontrol)(int flowcontrol); + + /** + * receive block + */ + void (*receive_block)(uint8_t *buffer, uint16_t len); + + /** + * send block + */ + void (*send_block)(const uint8_t *buffer, uint16_t length); + + // support for sleep modes in TI's H4 eHCILL and H5 + + /** + * query supported wakeup mechanisms + * @return supported_sleep_modes mask + */ + int (*get_supported_sleep_modes)(void); + + /** + * set UART sleep mode - allows to turn off UART and it's clocks to save energy + * Supported sleep modes: + * - off: UART active, RTS low if receive_block was called and block not read yet + * - RTS high, wake on CTS: RTS should be high. On CTS pulse, UART gets enabled again and RTS goes to low + * - RTS low, wake on RX: data on RX will trigger UART enable, bytes might get lost + */ + void (*set_sleep)(btstack_uart_sleep_mode_t sleep_mode); + + /** + * set wakeup handler - needed to notify hci transport of wakeup requests by Bluetooth controller + * Called upon CTS pulse or RX data. See sleep modes. + */ + void (*set_wakeup_handler)(void (*wakeup_handler)(void)); + + } btstack_uart_block_t; + +// common implementations + const btstack_uart_block_t *btstack_uart_block_posix_instance(void); + const btstack_uart_block_t *btstack_uart_block_windows_instance(void); + const btstack_uart_block_t *btstack_uart_block_embedded_instance(void); + const btstack_uart_block_t *btstack_uart_block_freertos_instance(void); + + /* HCI packet types */ + typedef struct { + /** + * transport name + */ + const char *name; + + /** + * init transport + * @param transport_config + */ + void (*init)(const void *transport_config); + + /** + * open transport connection + */ + int (*open)(void); + + /** + * close transport connection + */ + int (*close)(void); + + /** + * register packet handler for HCI packets: ACL, SCO, and Events + */ + void (*register_packet_handler)(void (*handler)(int packet_type, const u8 *packet, int size)); + + /** + * support async transport layers, e.g. IRQ driven without buffers + */ + int (*can_send_packet_now)(uint8_t packet_type); + + /** + * send packet + */ + int (*send_packet)(int packet_type, const u8 *packet, int size); + + /** + * extension for UART transport implementations + */ + int (*set_baudrate)(uint32_t baudrate); + + /** + * extension for UART H5 on CSR: reset BCSP/H5 Link + */ + void (*reset_link)(void); + + /** + * extension for USB transport implementations: config SCO connections + */ + void (*set_sco_config)(uint16_t voice_setting, int num_connections); + + } hci_transport_t; + + typedef enum { + HCI_TRANSPORT_CONFIG_UART, + HCI_TRANSPORT_CONFIG_USB + } hci_transport_config_type_t; + + typedef struct { + hci_transport_config_type_t type; + } hci_transport_config_t; + + typedef struct { + hci_transport_config_type_t type; // == HCI_TRANSPORT_CONFIG_UART + uint32_t baudrate_init; // initial baud rate + uint32_t baudrate_main; // = 0: same as initial baudrate + int flowcontrol; // + const char *device_name; + } hci_transport_config_uart_t; + + +// inline various hci_transport_X.h files + + /* + * @brief Setup H4 instance with uart_driver + * @param uart_driver to use + */ + const hci_transport_t *hci_transport_h4_instance(const btstack_uart_block_t *uart_driver); + + /* + * @brief Setup H5 instance with uart_driver + * @param uart_driver to use + */ + const hci_transport_t *hci_transport_h5_instance(const btstack_uart_block_t *uart_driver); + + /* + * @brief Enable H5 Low Power Mode: enter sleep mode after x ms of inactivity + * @param inactivity_timeout_ms or 0 for off + */ + void hci_transport_h5_set_auto_sleep(uint16_t inactivity_timeout_ms); + + /* + * @brief Enable BSCP mode H5, by enabling event parity + */ + void hci_transport_h5_enable_bcsp_mode(void); + + /* + * @brief + */ + const hci_transport_t *hci_transport_usb_instance(void); + + const hci_transport_t *hci_transport_uart_instance(void); + + const hci_transport_t *hci_transport_h4_controller_instance(void); + + const hci_transport_t *hci_transport_h4_host_instance(void); + /** + * @brief Specify USB Bluetooth device via port numbers from root to device + */ + void hci_transport_usb_set_path(int len, uint8_t *port_numbers); + + /* API_END */ + extern const hci_transport_t *hci_transport; + +#if defined __cplusplus +} +#endif + +#endif // __HCI_TRANSPORT_H diff --git a/include_lib/btctrler/port/br28/btcontroller_config.h b/include_lib/btctrler/port/br28/btcontroller_config.h new file mode 100644 index 0000000..fae3924 --- /dev/null +++ b/include_lib/btctrler/port/br28/btcontroller_config.h @@ -0,0 +1,56 @@ +/********************************************************************************************* + * Filename : btcontroller_config.h + + * Description : 优化代码需要,libs 依赖app 定义变量,由app 定义变量值决定libs 优化 + + * Author : Bingquan + + * Email : bingquan_cai@zh-jieli.com + + * Last modifiled : 2018-12-19 16:10 + + * Copyright:(c)JIELI 2011-2017 @ , All Rights Reserved. +*********************************************************************************************/ +#ifndef _BTCONTROLLER_CONFIG_H_ +#define _BTCONTROLLER_CONFIG_H_ + +#include "btcontroller_modules.h" + +#include "ble/ll_config.h" + +// #define CONFIG_LE_FEATURES \ +(\ + LE_ENCRYPTION | \ + LE_CORE_V50_FEATURES \ +) + +#define CONFIG_LE_FEATURES 0//(LE_ENCRYPTION) + +// #define CONFIG_LE_ROLES (LE_ADV|LE_SCAN|LE_INIT|LE_SLAVE|LE_MASTER) +// #define CONFIG_LE_ROLES (LE_ADV|LE_SCAN) +#define CONFIG_LE_ROLES (LE_ADV) + +#include "classic/lmp_config.h" + +#define CONFIG_CL_FEATURES + +#define CONFIG_CL_EX_FEATURES + + +#define TWS_BLE_ESCO_CONNECT //通话过程进行连接使能 + + +/* + *------------------- + * 蓝牙基带运行的模式 + */ + +struct lp_ws_t { + u16 lrc_ws_inc; + u16 lrc_ws_init; + u16 bt_osc_ws_inc; + u16 bt_osc_ws_init; + u8 osc_change_mode; +}; + +#endif diff --git a/include_lib/btctrler/port/br28/btctler_lib.ld b/include_lib/btctrler/port/br28/btctler_lib.ld new file mode 100644 index 0000000..c0fe3b1 --- /dev/null +++ b/include_lib/btctrler/port/br28/btctler_lib.ld @@ -0,0 +1,209 @@ +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 + + /*代码统计 Code & RAM : 蓝牙协议栈*/ + 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); +} diff --git a/include_lib/btstack/a2dp_media_codec.h b/include_lib/btstack/a2dp_media_codec.h new file mode 100644 index 0000000..c89143d --- /dev/null +++ b/include_lib/btstack/a2dp_media_codec.h @@ -0,0 +1,53 @@ +#ifndef A2DP_MEDIA_CODEC_H +#define A2DP_MEDIA_CODEC_H + + +#include "generic/typedef.h" + +#define seqn_after(a, b) ((s16)((s16)(b) - (s16)(a)) < 0) +#define seqn_before(a, b) seqn_after(b, a) + +extern int a2dp_media_get_packet(u8 **frame); + +extern int a2dp_media_try_get_packet(u8 **frame); + +extern int a2dp_media_get_remain_buffer_size(); + +extern int a2dp_media_get_remain_play_time(u8 include_tws); + +extern int a2dp_media_get_total_data_len(); + +extern int a2dp_media_get_packet_num(); + +extern int a2dp_media_clear_packet_before_seqn(u16 seqn_number); + +extern void *a2dp_media_fetch_packet(int *len, void *prev_packet); + +extern void *a2dp_media_fetch_packet_and_wait(int *len, void *prev_packet, int msec); + +extern void a2dp_media_free_packet(void *_packet); + +extern int a2dp_media_channel_exist(void); + +extern int a2dp_media_is_clearing_frame(void); + +extern int a2dp_media_get_codec_type(); + +extern u32 a2dp_media_dump_rx_time(u8 *frame); + + + + + + + + + + + + + + + + +#endif diff --git a/include_lib/btstack/avctp_user.h b/include_lib/btstack/avctp_user.h new file mode 100644 index 0000000..67b0f9e --- /dev/null +++ b/include_lib/btstack/avctp_user.h @@ -0,0 +1,733 @@ +#ifndef __AVCTP_USER_H__ +#define __AVCTP_USER_H__ + + +#include "typedef.h" +#include "btstack_typedef.h" + + + +///***注意:该文件的枚举与库编译密切相关,主要是给用户提供调用所用。用户不能自己在中间添加值。*/ +////----user (command) codes----//// +typedef enum { + /* + 使用user_send_cmd_prepare(USER_CMD_TYPE cmd,u16 param_len,u8 *param)发送命令 + //返回0表支持参数个数正确,返回1表不支持,2是参数错误 + 要三个参数,没参数说明的命令参数param_len传0,param传NULL + 例子A、USER_CTRL_HFP_CALL_SET_VOLUME命令需要1个参数的使用例子: + u8 vol = 8; + user_send_cmd_prepare(USER_CTRL_HFP_CALL_SET_VOLUME,1, &vol); + + 例子B、USER_CTRL_DIAL_NUMBER 参数要用数组先存起来,param_len是号码长度,param可传参数数组指针, + user_val->income_phone_num已经存好号码 + user_send_cmd_prepare(USER_CTRL_DIAL_NUMBER,user_val->phone_num_len,user_val->income_phone_num); + + */ + + //链路操作部分 + //回连,使用的是VM的地址,一般按键操作不使用该接口 + USER_CTRL_START_CONNECTION, + //通过地址去连接,如果知道地址想去连接使用该接口 + USER_CTRL_START_CONNEC_VIA_ADDR, + //通过指定地址手动回连,该地址是最后一个断开设备的地址 + USER_CTRL_START_CONNEC_VIA_ADDR_MANUALLY, + //通过地址去连接spp,如果知道地址想去连接使用该接口 + USER_CTRL_START_CONNEC_SPP_VIA_ADDR, + + //断开连接,断开当前所有蓝牙连接 + USER_CTRL_DISCONNECTION_HCI, + + //取消链接 + USER_CTRL_CONNECTION_CANCEL, + + //读取远端名字 + USER_CTRL_READ_REMOTE_NAME, + //连接或断开SCO或esco,选择这个命令会自动判断要断开还是连接sco + USER_CTRL_PAUSE_MUSIC, + //连接或断开SCO或esco,选择这个命令会自动判断要断开还是连接sco + USER_CTRL_SCO_LINK, + //连接SCO或esco + USER_CTRL_CONN_SCO, + //断开sco或esco + USER_CTRL_DISCONN_SCO, + //断开SDP,一般按键操作不使用该接口 + USER_CTRL_DISCONN_SDP_MASTER, + + //关闭蓝牙可发现 + USER_CTRL_WRITE_SCAN_DISABLE, + //打开蓝牙可发现 + USER_CTRL_WRITE_SCAN_ENABLE, +// USER_CTRL_WRITE_SCAN_ENABLE_KEY , + //关闭蓝牙可连接 + USER_CTRL_WRITE_CONN_DISABLE, + //打开蓝牙可连接 + USER_CTRL_WRITE_CONN_ENABLE, + // USER_CTRL_WRITE_CONN_ENABLE_KEY , + //控制蓝牙搜索,需要搜索附件设备做功能的连续说明情况在补充完善功能 + USER_CTRL_SEARCH_DEVICE, + //取消搜索 + USER_CTRL_INQUIRY_CANCEL, + //取消配对 + USER_CTRL_PAGE_CANCEL, + ///进入sniff模式,一般按键操作不使用该接口 + USER_CTRL_SNIFF_IN, + USER_CTRL_SNIFF_EXIT, + USER_CTRL_ALL_SNIFF_EXIT, + + //hfp链路部分 + //控制打电话音量,注意可能有些手机进度条有变化音量大小没变化,同步要设置样机DAC音量 + /*跟电话音量操作有关的操作最终都执行回调函数call_vol_change*/ + USER_CTRL_HFP_CMD_BEGIN, /* 接口扩展用来做HFP 连接 */ + USER_CTRL_HFP_CALL_VOLUME_UP, /*音量加1,手机可以同步显示*/ + USER_CTRL_HFP_CALL_VOLUME_DOWN, /*音量减1,手机可以同步显示*/ + USER_CTRL_HFP_CALL_SET_VOLUME, /*设置固定值,手机可以同步显示,需要传1个音量值*/ + USER_CTRL_HFP_CALL_GET_VOLUME, /*获取音量,默认从call_vol_change返回*/ + + //来电接听电话 + USER_CTRL_HFP_CALL_ANSWER, + //挂断电话 + USER_CTRL_HFP_CALL_HANGUP, + //回拨上一个打出电话 + USER_CTRL_HFP_CALL_LAST_NO, + //获取当前通话电话号码 + USER_CTRL_HFP_CALL_CURRENT, + //通话过程中根据提示输入控制 + /*例子 + char num = '1'; + user_send_cmd_prepare(USER_CTRL_HFP_DTMF_TONES,1,(u8 *)&num); + */ + //发送打电话时的信号选择DTMF tones ,有一个参数,参数支持{0-9, *, #, A, B, C, D} + USER_CTRL_HFP_DTMF_TONES, + //根据电话号码拨号 + /**USER_CTRL_DIAL_NUMBER命令有参数,参数要用数组先存起来, + param_len是号码长度,param可传参数数组指针*/ + USER_CTRL_DIAL_NUMBER, + //发送电量 /**要连接上HFP才有用*/ + USER_CTRL_SEND_BATTERY, + //*控制siri状态*//*可以注册回调函数获取返回值*/ + USER_CTRL_HFP_GET_SIRI_STATUS, + //*开启siri*/ + USER_CTRL_HFP_GET_SIRI_OPEN, + //*关闭siri,一般说完话好像自动关闭了,如果要提前终止可调用*/ + USER_CTRL_HFP_GET_SIRI_CLOSE, + /*获取手机的日期和时间,苹果可以,一般安卓机好像都不行*/ + USER_CTRL_HFP_GET_PHONE_DATE_TIME, + USER_CTRL_HFP_CMD_SEND_BIA, + /*获取手机厂商的命令 */ + USER_CTRL_HFP_CMD_GET_MANUFACTURER, + /*更新当前的电量给手机*/ + USER_CTRL_HFP_CMD_UPDATE_BATTARY, + //三方通话操作 + //应答 + USER_CTRL_HFP_THREE_WAY_ANSWER1, //挂断当前去听另一个(未接听或者在保留状态都可以) + USER_CTRL_HFP_THREE_WAY_ANSWER2, //保留当前去接听, 或者用于两个通话的切换 + USER_CTRL_HFP_THREE_WAY_ANSWER1X, //目前没有用 + USER_CTRL_HFP_THREE_WAY_ANSWER2X, //目前没有用 + USER_CTRL_HFP_THREE_WAY_ANSWER3, //可以发完USER_CTRL_HFP_THREE_WAY_ANSWER2,又发ANSWER3,自己看看效果 + //拒听 + USER_CTRL_HFP_THREE_WAY_REJECT, //拒绝后台来电 + USER_CTRL_HFP_DISCONNECT, //断开HFP连接 + USER_CTRL_HFP_CMD_END, + + //音乐控制部分 + USER_CTRL_AVCTP_CMD_BEGIN, + //音乐播放 + USER_CTRL_AVCTP_OPID_PLAY, + //音乐暂停 + USER_CTRL_AVCTP_OPID_PAUSE, + //音乐停止 + USER_CTRL_AVCTP_OPID_STOP, + //音乐下一首 + USER_CTRL_AVCTP_OPID_NEXT, + //音乐上一首 + USER_CTRL_AVCTP_OPID_PREV, + //音乐快进 + USER_CTRL_AVCTP_OPID_FORWARD, + //音乐快退 + USER_CTRL_AVCTP_OPID_REWIND, + //音乐循环模式 + USER_CTRL_AVCTP_OPID_REPEAT_MODE, + USER_CTRL_AVCTP_OPID_SHUFFLE_MODE, + //获取播放歌曲总时间和当前时间接口 + USER_CTRL_AVCTP_OPID_GET_PLAY_TIME, + + //同步音量接口 + USER_CTRL_AVCTP_OPID_SEND_VOL, +// //AVCTP断开,是音乐控制链路,一般不使用 + USER_CTRL_AVCTP_DISCONNECT, +// //AVCTP连接,是音乐控制链路,一般不使用 + USER_CTRL_AVCTP_CONN, + + USER_CTRL_AVCTP_CMD_END, + + //高级音频部分 + USER_CTRL_A2DP_CMD_BEGIN, + //有判断条件的,回连过程连接高级音频,避免手机连也自动发起连接,一般按键操作不使用该接口 + USER_CTRL_AUTO_CONN_A2DP, + //连接高级音频,回来最后一个断开设备的地址 + USER_CTRL_CONN_A2DP, + //断开高级音频,只断开高级音频链路,如果有电话还会保留 + USER_CTRL_DISCONN_A2DP, + //maybe BQB test will use + USER_CTRL_A2DP_CMD_START , + USER_CTRL_A2DP_CMD_CLOSE , + USER_CTRL_A2DP_CMD_SUSPEND , + USER_CTRL_A2DP_CMD_GET_CONFIGURATION , + USER_CTRL_A2DP_CMD_ABORT , + USER_CTRL_A2DP_CMD_END, + //蓝牙关闭 + USER_CTRL_POWER_OFF, + //蓝牙开启 + USER_CTRL_POWER_ON, + ///*hid操作定义*/ + USER_CTRL_HID_CMD_BEGIN, + //按键连接 + USER_CTRL_HID_CONN, +// //只发一个按键,安卓手机使用 + USER_CTRL_HID_ANDROID, + //只发一个按键,苹果和部分安卓手机适用 + USER_CTRL_HID_IOS, +// //发两个拍照按键 + USER_CTRL_HID_BOTH, + //HID断开 + USER_CTRL_HID_DISCONNECT, + //Home Key,apply to IOS and Android + USER_CTRL_HID_HOME , + //Return Key,only support Android + USER_CTRL_HID_RETURN , + //LeftArrow Key + USER_CTRL_HID_LEFTARROW , + //RightArrow Key + USER_CTRL_HID_RIGHTARROW , + //Volume Up + USER_CTRL_HID_VOL_UP , + //Volume Down + USER_CTRL_HID_VOL_DOWN , + + USER_CTRL_HID_SEND_DATA , + + USER_CTRL_HID_CMD_END, + + /**有TWS命名的都不用了*/ + /*对箱操作命令*/ + USER_CTRL_TWS_CMD_BEGIN, + USER_CTRL_SYNC_TRAIN, + USER_CTRL_SYNC_TRAIN_SCAN, + USER_CTRL_MONITOR, + USER_CTRL_TWS_CONNEC_VIA_ADDR, + USER_CTRL_TWS_COTROL_CDM, + //清除对箱连接信息 + USER_CTRL_TWS_CLEAR_INFO, + //断开对箱连接 + USER_CTRL_TWS_DISCONNECTION_HCI, + //发起对箱连接 + USER_CTRL_TWS_START_CONNECTION, + USER_CTRL_TWS_SYNC_CDM, + USER_CTRL_TWS_SYNC_SBC_CDM, + USER_CTRL_TWS_RESTART_SBC_CDM, + USER_CTRL_SYNC_TRAIN_CANCEL, + USER_CTRL_SYNC_TRAIN_SCAN_CANCEL, + USER_CTRL_TWS_SYNC_CDM_FUN, + USER_CTRL_TWS_LINEIN_START, + USER_CTRL_TWS_LINEIN_CLOSE, + USER_CTRL_TWS_CMD_END, + + ///蓝牙串口发送命令 + USER_CTRL_SPP_CMD_BEGIN, + /**USER_CTRL_SPP_SEND_DATA命令有参数,参数会先存起来, + param_len是数据长度,param发送数据指针 + 返回0,表示准备成功,会PENDing发完才返回 + 3表示上一包数据没发完,*/ + USER_CTRL_SPP_SEND_DATA, //len <= 512 + USER_CTRL_SPP_TRY_SEND_DATA,// + USER_CTRL_SPP_UPDATA_DATA, + //serial port profile disconnect command + USER_CTRL_SPP_DISCONNECT, + USER_CTRL_SPP_CMD_END, + + +///pbg发送命令 + USER_CTRL_PBG_CMD_BEGIN, + USER_CTRL_PBG_SEND_DATA,//len <= 512 + USER_CTRL_PBG_TRY_SEND_DATA,// + USER_CTRL_PBG_CMD_END, + +///adt 发送命令 + USER_CTRL_ADT_CMD_BEGIN, + USER_CTRL_ADT_CONNECT, + USER_CTRL_ADT_KEY_MIC_OPEN, + USER_CTRL_ADT_SEND_DATA,//len <= 512 + USER_CTRL_ADT_TRY_SEND_DATA,// + USER_CTRL_ADT_CMD_END, + + ///蓝牙电话本功能发送命令 + USER_CTRL_PBAP_CMD_BEGIN, + //电话本功能读取通话记录的前n条 + USER_CTRL_PBAP_READ_PART, + //电话本功能读全部记录 + USER_CTRL_PBAP_READ_ALL, + //电话本功能中断读取记录 + USER_CTRL_PBAP_STOP_READING, + + USER_CTRL_PBAP_CMD_END, + + + //蓝牙其他操作 +// //删除最新的一个设备记忆 +// USER_CTRL_DEL_LAST_REMOTE_INFO , +// //删除所有设备记忆 + USER_CTRL_DEL_ALL_REMOTE_INFO, + USER_CTRL_TEST_KEY, + USER_CTRL_SEND_USER_INFO, + + USER_CTRL_KEYPRESS, + USER_CTRL_PAIR, + USER_CTRL_AFH_CHANNEL, + USER_CTRL_HALF_SEC_LOOP_CREATE, + USER_CTRL_HALF_SEC_LOOP_DEL, + /**音量同步接口,自动选择通过HID还是AVRCP来发送*/ + USER_CTRL_CMD_SYNC_VOL_INC, + /**音量同步接口,自动选择通过HID还是AVRCP来发送*/ + USER_CTRL_CMD_SYNC_VOL_DEC, + /*单独HID和普通蓝牙模式的切换接口,音箱SDK才有完整流程*/ + USER_CTRL_CMD_CHANGE_PROFILE_MODE, + USER_CTRL_CMD_RESERVE_INDEX4, + USER_CTRL_CMD_RESUME_STACK, + //获取当前音乐的一些信息 + USER_CTRL_AVCTP_OPID_GET_MUSIC_INFO, + + //MAP功能发送命令 + USER_CTRL_MAP_CMD_BEGIN, + //MAP读取时间 + USER_CTRL_MAP_READ_TIME, + //MAP读取未读短信 + USER_CTRL_MAP_READ_INDOX, + //MAP读取已读短信 + USER_CTRL_MAP_READ_OUTDOX, + //MAP读取已发读短信 + USER_CTRL_MAP_READ_SENT, + //MAP读取删除短信 + USER_CTRL_MAP_READ_DELETED, + //MAP读取草稿箱短信 + USER_CTRL_MAP_READ_DRAFT, + //MAP停止读取 + USER_CTRL_MAP_STOP_READING, + USER_CTRL_MAP_CMD_END, + //不看协议栈的状态去调一次exit,关机的时候可能消息被阻塞住推上来导致SNIFF无法退出,影响后续的关机流程 + USER_CTRL_ALL_SNIFF_EXIT_BY_POWEROFF, + + // 一拖二通话操作 + USER_CTRL_MULTI_HFP_CMD_BEGIN, + // 设备间通话切换 + USER_CTRL_MULTI_ESCO_SWITCH, + // 挂断打断设备通话 + USER_CTRL_MULTI_HFP_CALL_HANGUP_BREAK, + //挂断当前通话,接听来电设备 + USER_CTRL_MULTI_HFP_CALL_HANGUP_BREAK_ACTIVE, + //前台设备三方通话,挂断当前并接听 + USER_CTRL_MULTI_HFP_THREE_WAY_ANSWER1, + //前台设备三方通话,保留当前并接听 + USER_CTRL_MULTI_HFP_THREE_WAY_ANSWER2, + // 被打断设备三方通话,挂断当前接通来电 + USER_CTRL_MULTI_HFP_THREE_WAY_ANSWER1_BREAK, + // 被打断设备三方通话,挂断当前接通来电并切换到耳机通话 + USER_CTRL_MULTI_HFP_THREE_WAY_ANSWER1_BREAK_SWITCH, + // 被打断设备三方通话,保留当前接通来电 + USER_CTRL_MULTI_HFP_THREE_WAY_ANSWER2_BREAK, + // 被打断设备三方通话,保留当前接通来电并切换到耳机通话 + USER_CTRL_MULTI_HFP_THREE_WAY_ANSWER2_BREAK_SWITCH, + // 被打断设备三方通话,拒绝后台来电 + USER_CTRL_MULTI_HFP_THREE_WAY_ANSWER3_BREAK, + USER_CTRL_MULTI_HFP_CMD_END, + + USER_CTRL_LAST +} USER_CMD_TYPE; + + +////----反馈给客户使用的状态----//// +typedef enum { + /*下面是一些即时反馈的状态,无法重复获取的状态*/ + BT_STATUS_POWER_ON = 1, /*上电*/ + BT_STATUS_POWER_OFF = 2, + BT_STATUS_INIT_OK, /*初始化完成*/ + BT_STATUS_EXIT_OK, /*蓝牙退出完成*/ + BT_STATUS_START_CONNECTED, /*开始连接*/ + BT_STATUS_FIRST_CONNECTED, /*连接成功*/ + BT_STATUS_SECOND_CONNECTED, /*连接成功*/ + BT_STATUS_ENCRY_COMPLETE, /*加密完成*/ + BT_STATUS_FIRST_DISCONNECT, /*断开连接*/ + BT_STATUS_SECOND_DISCONNECT, /*断开连接*/ + BT_STATUS_PHONE_INCOME, /*来电*/ + BT_STATUS_PHONE_NUMBER, /*来电话号码*/ + BT_STATUS_PHONE_MANUFACTURER, /*获取手机的厂商*/ + + BT_STATUS_PHONE_OUT, /*打出电话*/ + BT_STATUS_PHONE_ACTIVE, /*接通电话*/ + BT_STATUS_PHONE_HANGUP, /*挂断电话*/ + BT_STATUS_BEGIN_AUTO_CON, /*发起回连*/ + BT_STATUS_MUSIC_SOUND_COME, /*库中加入auto mute判断音乐播放开始*/ + BT_STATUS_MUSIC_SOUND_GO, /*库中加入auto mute判断音乐播放暂停*/ + BT_STATUS_RESUME, /*后台有效,手动切回蓝牙*/ + BT_STATUS_RESUME_BTSTACK, /*后台有效,后台时来电切回蓝牙*/ + BT_STATUS_SUSPEND, /*蓝牙挂起,退出蓝牙*/ + BT_STATUS_LAST_CALL_TYPE_CHANGE, /*最后拨打电话的类型,只区分打入和打出两种状态*/ + + BT_STATUS_CALL_VOL_CHANGE, /*通话过程中设置音量会产生这个状态变化*/ + BT_STATUS_SCO_STATUS_CHANGE, /*当esco/sco连接或者断开时会产生这个状态变化*/ + BT_STATUS_CONNECT_WITHOUT_LINKKEY, /*判断是首次连接还是配对后的连接,主要依据要不要简易配对或者pin code*/ + BT_STATUS_PHONE_BATTERY_CHANGE, /*电话电量变化,该状态仅6个等级,0-5*/ + BT_STATUS_RECONNECT_LINKKEY_LOST, /*回连时发现linkkey丢失了,即手机取消配对了*/ + BT_STATUS_RECONN_OR_CONN, /*回连成功还是被连接*/ + BT_STATUS_BT_TEST_BOX_CMD, /*蓝牙收到测试盒消息。1-升级,2-fast test*/ + BT_STATUS_BT_TWS_CONNECT_CMD, + BT_STATUS_SNIFF_STATE_UPDATE, /*SNIFF STATE UPDATE*/ + BT_STATUS_TONE_BY_FILE_NAME, /*直接使用文件名播放提示音*/ + + BT_STATUS_PHONE_DATE_AND_TIME, /*获取到手机的时间和日期,注意会有兼容性问题*/ + BT_STATUS_INBAND_RINGTONE, + BT_STATUS_VOICE_RECOGNITION, + BT_STATUS_AVRCP_INCOME_OPID, /*收到远端设备发过来的AVRCP命令*/ + BT_STATUS_HFP_SERVICE_LEVEL_CONNECTION_OK, + BT_STATUS_CONN_A2DP_CH, + BT_STATUS_CONN_HFP_CH, + BT_STATUS_INQUIRY_TIMEOUT, + /*下面是1个持续的状态,是get_stereo_bt_connect_status获取*/ + + /*下面是6个持续的状态,是get_bt_connect_status()获取*/ + BT_STATUS_INITING, /*正在初始化*/ + BT_STATUS_WAITINT_CONN, /*等待连接*/ + BT_STATUS_AUTO_CONNECTINT, /*正在回连*/ + BT_STATUS_CONNECTING, /*已连接,没有电话和音乐在活动*/ + BT_STATUS_TAKEING_PHONE, /*正在电话*/ + BT_STATUS_PLAYING_MUSIC, /*正在音乐*/ + BT_STATUS_A2DP_MEDIA_START, + BT_STATUS_A2DP_MEDIA_STOP, + + + BT_STATUS_BROADCAST_STATE,/*braoadcaset中*/ + + BT_STATUS_TRIM_OVER, /*测试盒TRIM完成*/ +} STATUS_FOR_USER; + +typedef enum { + BT_CALL_BATTERY_CHG = 0, //电池电量改变 + BT_CALL_SIGNAL_CHG, //网络信号改变 + BT_CALL_INCOMING, //电话打入 + BT_CALL_OUTGOING, //电话打出 + BT_CALL_ACTIVE, //接通电话 + BT_CALL_HANGUP, //电话挂断 + BT_CALL_ALERT, //远端reach + BT_CALL_VOL_CHANGED, +} BT_CALL_IND_STA; + +typedef enum { + BT_MUSIC_STATUS_IDLE = 0, + BT_MUSIC_STATUS_STARTING, + BT_MUSIC_STATUS_SUSPENDING, +} BT_MUSIC_STATE; //音乐状态 + +#define SYS_BT_EVENT_TYPE_CON_STATUS (('C' << 24) | ('O' << 16) | ('N' << 8) | '\0') +#define SYS_BT_EVENT_TYPE_HCI_STATUS (('H' << 24) | ('C' << 16) | ('I' << 8) | '\0') + + + +#define REMOTE_DEFAULT 0x00 +#define REMOTE_SINK 0x01 +#define REMOTE_SOURCE 0x02 + + +#define SPP_CH 0x01 +#define HFP_CH 0x02 +#define A2DP_CH 0x04 //media +#define AVCTP_CH 0x08 +#define HID_CH 0x10 +#define AVDTP_CH 0x20 +#define PBAP_CH 0x40 +#define HFP_AG_CH 0x80 +#define A2DP_SRC_CH 0x2000 +#define MAP_CH 0x8000 +struct sniff_ctrl_config_t { + u16 sniff_max_interval; + u16 sniff_mix_interval; + u16 sniff_attemp; + u16 sniff_timeout; + u8 sniff_addr[6]; +}; +extern u32 user_send_cmd_prepare(USER_CMD_TYPE cmd, u16 param_len, u8 *param); +extern int user_send_at_cmd_prepare(u8 *data, u16 len); +/**发射器操作的几个接口*/ +extern u32 user_emitter_cmd_prepare(USER_CMD_TYPE cmd, u16 param_len, u8 *param); +u8 get_emitter_connect_status(void); +u16 get_emitter_curr_channel_state(); +u8 get_emitter_a2dp_status(void); + + +/* +u16 get_curr_channel_state(); 与 channel 判断区分 +主动获取当前链路的连接状态,可以用来判断有哪些链路连接上了 +*/ +extern u16 get_curr_channel_state(); +/* +u8 get_call_status(); 与BT_CALL_IND_STA 枚举的值判断 +用于获取当前蓝牙电话的状态 +*/ +extern u8 get_call_status(); +extern void user_cmd_ctrl_init(void *var); + +/******当前连接的设备是jl测试盒**********/ +extern bool get_remote_test_flag(); +extern void set_remote_test_flag(u8 own_remote_test); +extern void bt_fast_test_handle_register(void (*handle)(void)); +extern void bt_dut_test_handle_register(void (*handle)(u8)); +extern void inquiry_result_handle_register(void (*handle)(char *name, u8 name_len, u8 *addr, u32 dev_class, char rssi)); + +/*个性化参数设置*/ +/*用户调试设置地址,6个byte*/ +extern void __set_bt_mac_addr(u8 *addr); + +/*用户调试设置name,最长32个字符*/ +extern void __set_host_name(const char *name, u8 len); +/*用户调试设置pin code*/ +extern void __set_pin_code(const char *code); +/*该接口用于设置上电回连需要依次搜索设备的个数。*/ +extern void __set_auto_conn_device_num(u8 num); + +/*//回连的超时设置。ms单位。但是对手机发起的连接是没作用的*/ +extern void __set_super_timeout_value(u16 time); +/*外部设置支持什么协议*/ +extern void bt_cfg_default_init(u8 support); + +/*设置电量显示发送更新的周期时间,为0表示关闭电量显示功能*/ +extern void __bt_set_update_battery_time(u8 time); +/*给用户设置蓝牙支持连接的个数,主要用于控制控制可发现可连接和回连流程*/ +extern void __set_user_ctrl_conn_num(u8 num); +/*提供接口外部设置要保留hfp不要蓝牙通话*/ +extern void __set_disable_sco_flag(bool flag); + +/*提供接口外部设置简易配对参数*/ +extern void __set_simple_pair_param(u8 io_cap, u8 oob_data, u8 mitm); + +/*有些自选接口用来实现个性化功能流程,回调函数注册,记得常来看看哟*/ +extern void get_battery_value_register(int (*handle)(void)); /*电量发送时获取电量等级的接口注册*/ +extern void music_vol_change_handle_register(void (*handle)(int vol), int (*handle2)(void)); /*手机更样机音乐模式的音量同步*/ +extern void read_remote_name_handle_register(void (*handle)(u8 status, u8 *addr, u8 *name)); /*获取到名字后的回调函数接口注册函数*/ +extern void spp_data_deal_handle_register(void (*handler)(u8 packet_type, u16 channel, u8 *packet, u16 size)); /*支持串口功能的数据处理接口*/ +extern void discon_complete_handle_register(void (*handle)(u8 *addr, int reason)); /*断开或者连接上会调用的函数,给客户反馈信息*/ + +extern void update_bt_current_status(u8 *addr, u8 new_status, u8 conn_status); +extern u8 get_bt_connect_status(void); +extern u8 a2dp_get_status(void); + +/*//回连的超时设置。ms单位。但是对手机发起的连接是没作用的*/ +extern void __set_super_timeout_value(u16 time); +/*//回连page的超时设置。ms单位*/ +extern void __set_page_timeout_value(u16 time); +/*获取的值上限是bt_set_auto_conn_device_num接口配置的值,一般用于做回连策略*/ +extern int btstack_get_num_of_remote_device_recorded(); +/*上电自动搜索设备的个数*/ +extern u8 get_current_poweron_memory_search_index(u8 *temp_mac_addr); +extern void clear_current_poweron_memory_search_index(u8 inc); + +extern void __set_user_background_goback(u8 en); + +extern bool user_sniff_check_req(u8 sniff_cnt_time); + +extern int tws_updata_phone_wait_con_addr(u8 *addr); +extern int tws_updata_internal_addr(u8 *internal_addr_local, u8 *internal_addr_remote); + + +extern void bt_discon_complete_handle(u8 *addr, int reason); +/*这个接口只用来判断回连或者开可发现可连接的状态*/ +extern bool is_1t2_connection(void); +/*用来获取蓝牙连接的设备个数,不包含page状态的计数*/ +extern u8 get_total_connect_dev(void); +/*可以通过地址查询HFP的状态*/ +extern u8 is_bt_conn_hfp_hangup(u8 *addr); + +extern void infor_2_user_handle_register(int (*handle)(u8 *info, u16 len), u8 *buffer_ptr); +/*音乐的ID3信息返回接口注册函数*/ +extern void bt_music_info_handle_register(void (*handler)(u8 type, u32 time, u8 *info, u16 len)); +/*用户层不需要用了*/ +extern void set_bt_vm_interface(u32 vm_index, void *interface); +extern void bredr_stack_init(void); +/*sniff 的计数查询*/ +extern bool bt_api_conn_mode_check(u8 enable, u8 *addr); +extern u8 bt_api_enter_sniff_status_check(u16 time_cnt, u8 *addr); +extern void user_cmd_timer_init(); +extern void remove_user_cmd_timer(); +//get_auto_connect_state有时效性,一般不用。可以用消息BT_STATUS_RECONN_OR_CONN +extern u8 get_auto_connect_state(u8 *addr); +//判断SCO/esco有没有正在使用,两个接口一样的 +extern u8 get_esco_coder_busy_flag(); +extern bool get_esco_busy_flag(); +/*有可能低层刚开始走了连接,但是上层还没有消息,不维护蓝牙的不要随便用*/ +extern u8 hci_standard_connect_check(void); +/*设置一个标识给库里面说明正在退出蓝牙*/ +extern void set_stack_exiting(u8 exit); +/*根据规则生产BLE的随机地址*/ +extern void lib_make_ble_address(u8 *ble_address, u8 *edr_address); +/*查询最后一个VM记录的地址进行回连*/ +extern u8 connect_last_device_from_vm(); +/*配置协议栈支持HID功能,为了兼容以前的HID独立模式,音箱SDK有使用流程*/ +extern void __bt_set_hid_independent_flag(bool flag); +extern int btstack_exit(); +/*能量检测之后有一些判断流程要走,非蓝牙开发不用*/ +extern int sbc_energy_check(u8 *packet, u16 size); +extern int aac_energy_check(u8 *packet, u16 size); +/**发射器和接收器按键切换的时候要申请和释放资源**/ +extern int a2dp_source_init(void *buf, u16 len, int deal_flag); +/**发射器和接收器按键切换的时候要申请和释放资源**/ +extern int hfp_ag_buf_init(void *buf, int size, int deal_flag); +/*配置蓝牙协议栈处于发射器流程*/ +extern void __set_emitter_enable_flag(u8 flag); +/*用户使用USER_CTRL_INQUIRY_CANCEL就行,下面的用户层不直接使用*/ +extern void hci_cancel_inquiry(); +/*发射器启动还是暂停数据发送的接口,会发start和suspend命令*/ +extern void __emitter_send_media_toggle(u8 *addr, u8 toggle); +/*查询当前有没有a2dp source(发射器的音频发送链路)在连接状态*/ +extern u8 is_a2dp_source_dev_null(); +/*选择用哪一块VM存储信息,非蓝牙维护人员不用*/ +extern u8 get_remote_dev_info_index(); +extern u8 check_tws_le_aa(void); +extern void tws_api_set_connect_aa(int); +extern void tws_le_acc_generation_init(void); +extern void tws_api_clear_connect_aa(); +extern void clear_sniff_cnt(void); +/**删除VM记录的最后一个设备信息*/ +extern u8 delete_last_device_from_vm(); + +#define BD_CLASS_WEARABLE_HEADSET 0x240404/*ios10.2 display headset icon*/ +#define BD_CLASS_HANDS_FREE 0x240408/*ios10.2 display bluetooth icon*/ +#define BD_CLASS_MICROPHONE 0x240410 +#define BD_CLASS_LOUDSPEAKER 0x240414 +#define BD_CLASS_HEADPHONES 0x240418 +#define BD_CLASS_CAR_AUDIO 0x240420 +#define BD_CLASS_HIFI_AUDIO 0x240428 +#define BD_CLASS_PHONEBOOK 0x340404 +#define BD_CLASS_PAN_DEV 0X020118 + +#define BD_CLASS_SMART_PHONE 0x5A020C//0x40020C + +#define BD_CLASS_MOUSE 0x002580 +#define BD_CLASS_KEYBOARD 0x002540 +#define BD_CLASS_KEYBOARD_MOUSE 0x0025C0 +#define BD_CLASS_REMOTE_CONTROL 0x00254C + +#define BD_CLASS_TRANSFER_HEALTH 0x10091C + +//LDAC采样率 +#define LDAC_SAMPLING_FREQ_44100 0x20 +#define LDAC_SAMPLING_FREQ_48000 0x10 +#define LDAC_SAMPLING_FREQ_88200 0x08 +#define LDAC_SAMPLING_FREQ_96000 0x04 +// 配置LDAC支持的采样率 +extern void __set_a2dp_ldac_sampling_freq(u8 a2dp_ldac_sampling_freq); + +/*修改什么的类型,会影响到手机显示的图标*/ +extern void __change_hci_class_type(u32 class); +/*配置通话使用16k的msbc还是8k的cvsd*/ +extern void __set_support_msbc_flag(bool flag); +/*配置协议栈使用支持AAC的信息*/ +extern void __set_support_aac_flag(bool flag); + +/*设置1拖2时电话是否抢断标识*/ +extern void __set_hfp_switch(u8 switch_en); +/* + *设置1拖2时电话是否恢复标识 + *通话结束的时候,如果还有手机在通话,自动切到蓝牙端 + */ +extern void __set_hfp_restore(u8 restore_en); +/*当前设备被打断时是否自动暂停*/ +extern void __set_auto_pause_flag(u8 flag); +/*当前设备被打断时是否自动暂停*/ +extern void __set_auto_pause_flag(u8 flag); +/*高级音频设置标志是否允许后者打断前者*/ +extern void __set_music_break_in_flag(u8 flag); +/*高级音频打断检测数据包阈值设置*/ +extern void __set_a2dp_sound_detect_counter(u8 sound_come, u8 sound_go); +/*pan的控制接口和发数接口, + addr指定就按指定的查找,NULL就默认正在使用那个 + cmd 下面定义的宏用户可以使用 + param 传参数需要的值或者data包的长度 + data 传的是要发数据的包指针 + */ +#define USER_PAN_CMD_SEND_DATA 0xff +int user_pan_send_cmd(u8 *addr, u32 cmd, u32 param, u8 *data); + +enum { + BD_ESCO_IDLE = 0, /*当前没有设备通话中*/ + BD_ESCO_BUSY_CURRENT, /*当前地址对应的设备通话中*/ + BD_ESCO_BUSY_OTHER, /*通话中的设备非当前地址*/ +}; + +enum { + BD_GET_SECOND_ACTIVE = 0, /*获取当前设备的三方通话状态*/ + BD_GET_SECOND_BREAK, /*获取后台设备的三方通话状态*/ +}; + +extern u8 check_esco_state_via_addr(u8 *addr); +/*判断是否主动回连*/ +extern u8 get_auto_connect_state(u8 *addr); + +typedef struct __hid_sdp_info { + u16 vid_private; + u16 pid_private; + u16 ver_private; + + u8 sub_class; + u8 country_code; + bool virtual_cable; + bool reconnect_initiate; + bool sdp_disable; + bool battery_power; + bool remote_wake; + bool normally_connectable; + bool boot_device; + u16 version; + u16 parser_version; + u16 profile_version; + u16 supervision_timeout; + u16 language; + u16 bt_string_offset; + u16 descriptor_len; + u8 *descriptor; + char *service_name; + char *service_description; + char *provide_name; + void (*sdp_request_respone_callback)(u8 type); + u8 *extra_buf; + u8 extra_len; +} hid_sdp_info_t; + + +typedef struct { + u16 chl_id; + u16 data_len; + u8 *data_ptr; +} hid_s_param_t; + +extern u16 sdp_create_diy_device_ID_service(u8 *buffer, u16 buffer_size); +extern u16 sdp_create_diy_hid_service(u8 *buffer, u16 buffer_size, const u8 *hid_descriptor, u16 hid_descriptor_size); +u8 get_remote_vol_sync(void); +void set_start_search_spp_device(u8 spp); + + +u8 restore_remote_device_info_opt(bd_addr_t *mac_addr, u8 conn_device_num, u8 id); +u8 restore_remote_device_info_profile(bd_addr_t *mac_addr, u8 device_num, u8 id, u8 profile); +/*remote dev type*/ +/*0:unknow,1-android,2:apple_inc,0x03-xiaomi*/ +enum { + REMOTE_DEV_UNKNOWN = 0, + REMOTE_DEV_ANDROID , + REMOTE_DEV_IOS , + REMOTE_DEV_XIAOMI , +}; +u8 remote_dev_company_ioctrl(bd_addr_t dev_addr, u8 op_flag, u8 value); +u8 hci_standard_link_check(void); + +//获取当前是否有conn处于sniff状态 +bool bt_api_get_sniff_state(); + + + +#endif diff --git a/include_lib/btstack/bluetooth.h b/include_lib/btstack/bluetooth.h new file mode 100644 index 0000000..2bf2532 --- /dev/null +++ b/include_lib/btstack/bluetooth.h @@ -0,0 +1,582 @@ +#ifndef _BLUETOOTH_H_ +#define _BLUETOOTH_H_ + +#include "typedef.h" + + +//LE +#include "le/ble_data_types.h" +#include "le/ble_api.h" +#include "le/le_user.h" +#include "le/att.h" +#include "le/gatt.h" +#include "le/sm.h" + +#define ISO_SDU_DTAT_LENGTH 0x032c //812byte +#define ISO_PDU_DTAT_LENGTH 251 //251byte +#define ISO_PDU_INTERVAL_M_S 0x4e20 //20ms +#define ISO_PDU_INTERVAL_S_M 0x4e20 //20ms +#define HCI_ISO_DATA_PACKET 0x05 + +//Classic + + + + +//Common +#include "btstack_event.h" + + +#define HCI_COMMAND_DATA_PACKET 0x01 +#define HCI_ACL_DATA_PACKET 0x02 +#define HCI_SCO_DATA_PACKET 0x03 +#define HCI_EVENT_PACKET 0x04 + +// OGFs +#define OGF_LINK_CONTROL 0x01 +#define OGF_LINK_POLICY 0x02 +#define OGF_CONTROLLER_BASEBAND 0x03 +#define OGF_INFORMATIONAL_PARAMETERS 0x04 +#define OGF_STATUS_PARAMETERS 0x05 +#define OGF_TESTING 0x06 +#define OGF_LE_CONTROLLER 0x08 +#define OGF_VENDOR_LE_CONTROLLER 0x3e +#define OGF_VENDOR 0x3f + + +// Events from host controller to host + +/** + * @format 1 + * @param status + */ +#define HCI_EVENT_INQUIRY_COMPLETE 0x01 + +/** + * @format 1B11132 + * @param num_responses + * @param bd_addr + * @param page_scan_repetition_mode + * @param reserved1 + * @param reserved2 + * @param class_of_device + * @param clock_offset + */ +#define HCI_EVENT_INQUIRY_RESULT 0x02 + +/** + * @format 12B11 + * @param status + * @param connection_handle + * @param bd_addr + * @param link_type + * @param encryption_enabled + */ +#define HCI_EVENT_CONNECTION_COMPLETE 0x03 +/** + * @format B31 + * @param bd_addr + * @param class_of_device + * @param link_type + */ +#define HCI_EVENT_CONNECTION_REQUEST 0x04 +/** + * @format 121 + * @param status + * @param connection_handle + * @param reason + */ +#define HCI_EVENT_DISCONNECTION_COMPLETE 0x05 +/** + * @format 12 + * @param status + * @param connection_handle + */ +#define HCI_EVENT_AUTHENTICATION_COMPLETE 0x06 +/** + * @format 1BN + * @param status + * @param bd_addr + * @param remote_name + */ +#define HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE 0x07 +/** + * @format 121 + * @param status + * @param connection_handle + * @param encryption_enabled + */ +#define HCI_EVENT_ENCRYPTION_CHANGE 0x08 +/** + * @format 12 + * @param status + * @param connection_handle + */ +#define HCI_EVENT_CHANGE_CONNECTION_LINK_KEY_COMPLETE 0x09 +/** + * @format 121 + * @param status + * @param connection_handle + * @param key_flag + */ +#define HCI_EVENT_MASTER_LINK_KEY_COMPLETE 0x0A + +#define HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE 0x0B + +#define HCI_EVENT_READ_REMOTE_VERSION_INFORMATION_COMPLETE 0x0C + +#define HCI_EVENT_QOS_SETUP_COMPLETE 0x0D + +/** + * @format 12R + * @param num_hci_command_packets + * @param command_opcode + * @param return_parameters + */ +#define HCI_EVENT_COMMAND_COMPLETE 0x0E +/** + * @format 112 + * @param status + * @param num_hci_command_packets + * @param command_opcode + */ +#define HCI_EVENT_COMMAND_STATUS 0x0F + +/** + * @format 1 + * @param hardware_code + */ +#define HCI_EVENT_HARDWARE_ERROR 0x10 + +#define HCI_EVENT_FLUSH_OCCURRED 0x11 + +/** + * @format 1B1 + * @param status + * @param bd_addr + * @param role + */ +#define HCI_EVENT_ROLE_CHANGE 0x12 + +// TODO: number_of_handles 1, connection_handle[H*i], hc_num_of_completed_packets[2*i] +#define HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS 0x13 + +/** + * @format 1H12 + * @param status + * @param handle + * @param mode + * @param interval + */ +#define HCI_EVENT_MODE_CHANGE_EVENT 0x14 + +// TODO: num_keys, bd_addr[B*i], link_key[16 octets * i] +#define HCI_EVENT_RETURN_LINK_KEYS 0x15 + +/** + * @format B + * @param bd_addr + */ +#define HCI_EVENT_PIN_CODE_REQUEST 0x16 + +/** + * @format B + * @param bd_addr + */ +#define HCI_EVENT_LINK_KEY_REQUEST 0x17 + +// TODO: bd_addr B, link_key 16octets, key_type 1 +#define HCI_EVENT_LINK_KEY_NOTIFICATION 0x18 + +/** + * @format 1 + * @param link_type + */ +#define HCI_EVENT_DATA_BUFFER_OVERFLOW 0x1A + +/** + * @format H1 + * @param handle + * @param lmp_max_slots + */ +#define HCI_EVENT_MAX_SLOTS_CHANGED 0x1B + +/** + * @format 1H2 + * @param status + * @param handle + * @param clock_offset + */ +#define HCI_EVENT_READ_CLOCK_OFFSET_COMPLETE 0x1C + +/** + * @format 1H2 + * @param status + * @param handle + * @param packet_types + * @pnote packet_type is in plural to avoid clash with Java binding Packet.getPacketType() + */ +#define HCI_EVENT_CONNECTION_PACKET_TYPE_CHANGED 0x1D + +#define HCI_EVENT_PAGE_SCAN_REPETITION_MODE_CHANGE 0x20 +/** + * @format 1B11321 + * @param num_responses + * @param bd_addr + * @param page_scan_repetition_mode + * @param reserved + * @param class_of_device + * @param clock_offset + * @param rssi + */ +#define HCI_EVENT_INQUIRY_RESULT_WITH_RSSI 0x22 + +#define HCI_EVENT_READ_REMOTE_EXTERNED_FEATURES_COMPLETE 0x23 +/** + * @format 1HB111221 + * @param status + * @param handle + * @param bd_addr + * @param link_type + * @param transmission_interval + * @param retransmission_interval + * @param rx_packet_length + * @param tx_packet_length + * @param air_mode + */ +#define HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE 0x2C + +// TODO: serialize extended_inquiry_response and provide parser +/** + * @format 1B11321 + * @param num_responses + * @param bd_addr + * @param page_scan_repetition_mode + * @param reserved + * @param class_of_device + * @param clock_offset + * @param rssi + */ +#define HCI_EVENT_EXTENDED_INQUIRY_RESPONSE 0x2F +#define HCI_EVENT_EXTENDED_INQUIRY_RESULT 0x2F + +/** + * @format 1H + * @param status + * @param handle + */ +#define HCI_EVENT_ENCRYPTION_KEY_REFRESH_COMPLETE 0x30 + +#define HCI_EVENT_IO_CAPABILITY_REQUEST 0x31 +#define HCI_EVENT_IO_CAPABILITY_RESPONSE 0x32 + +/** + * @format B4 + * @param bd_addr + * @param numeric_value + */ +#define HCI_EVENT_USER_CONFIRMATION_REQUEST 0x33 + +/** + * @format B + * @param bd_addr + */ +#define HCI_EVENT_USER_PASSKEY_REQUEST 0x34 + +/** + * @format B + * @param bd_addr + */ +#define HCI_EVENT_REMOTE_OOB_DATA_REQUEST 0x35 + +/** + * @format 1B + * @param status + * @param bd_addr + */ +#define HCI_EVENT_SIMPLE_PAIRING_COMPLETE 0x36 +#define HCI_EVENT_LINK_SUPPERVISION_TIMEOUT_CHANGE_EVENT 0x38 + +#define HCI_EVENT_USER_PRESSKEY_NOTIFICATION 0x3B +#define HCI_EVENT_REMOTE_KEYPRESS_NOTIFICATION 0x3C +#define HCI_EVENT_REMOTE_SUPPORTED_FEATURES_NOTIFICATION 0x3D +#define HCI_EVENT_LE_META 0x3E + +// last used HCI_EVENT in 2.1 is 0x3d +// last used HCI_EVENT in 4.1 is 0x57 + +#define HCI_EVENT_VENDOR_CONNECTION_COMPLETE 0xEF + +//event definition for new vendor sub event +#define HCI_EVENT_VENDOR_META 0xF5 +#define HCI_SUBEVENT_VENDOR_TEST_MODE_CFG 0x01 + +#define HCI_EVENT_VENDOR_FRE_OFFSET_TRIM 0xF6 +#define HCI_EVENT_VENDOR_ENCRY_COMPLETE 0xF7 +#define HCI_EVENT_VENDOR_NO_RECONN_ADDR 0xF8 +#define HCI_EVENT_VENDOR_SETUP_COMPLETE 0xF9 +#define HCI_EVENT_VENDOR_DUT 0xFA +#define HCI_EVENT_VENDOR_OSC_INTERNAL 0xFB +#define HCI_EVENT_VENDOR_FAST_TEST 0xFC +#define HCI_EVENT_VENDOR_REMOTE_UPDATE 0xFD +#define HCI_EVENT_VENDOR_REMOTE_TEST 0xFE +#define HCI_EVENT_VENDOR_SPECIFIC 0xFF + +#define BTSTACK_EVENT_HCI_CONNECTIONS_DELETE 0x6D + +/** + * @format 11H11B2221 + * @param subevent_code + * @param status + * @param connection_handle + * @param role + * @param peer_address_type + * @param peer_address + * @param conn_interval + * @param conn_latency + * @param supervision_timeout + * @param master_clock_accuracy + */ +#define HCI_SUBEVENT_LE_CONNECTION_COMPLETE 0x01 + +// array of advertisements, not handled by event accessor generator +#define HCI_SUBEVENT_LE_ADVERTISING_REPORT 0x02 + +/** + * @format 11H222 + * @param subevent_code + * @param status + * @param connection_handle + * @param conn_interval + * @param conn_latency + * @param supervision_timeout + */ +#define HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE 0x03 + +/** + * @format 1HD2 + * @param subevent_code + * @param connection_handle + * @param random_number + * @param encryption_diversifier + */ +#define HCI_SUBEVENT_LE_READ_REMOTE_USED_FEATURES_COMPLETE 0x04 + +/** + * @format 1HD2 + * @param subevent_code + * @param connection_handle + * @param random_number + * @param encryption_diversifier + */ +#define HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST 0x05 + +/** + * @format 1H2222 + * @param subevent_code + * @param connection_handle + * @param interval_min + * @param interval_max + * @param latency + * @param timeout + */ +#define HCI_SUBEVENT_LE_REMOTE_CONNECTION_PARAMETER_REQUEST 0x06 + +/** + * @format 1H2222 + * @param subevent_code + * @param connection_handle + * @param max_tx_octets + * @param max_tx_time + * @param max_rx_octets + * @param max_rx_time + */ +#define HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE 0x07 + +/** + * @format 11QQ + * @param subevent_code + * @param status + * @param dhkey_x x coordinate of P256 public key + * @param dhkey_y y coordinate of P256 public key + */ +#define HCI_SUBEVENT_LE_READ_LOCAL_P256_PUBLIC_KEY_COMPLETE 0x08 +/** +* @format 11Q +* @param subevent_code +* @param status +* @param dhkey Diffie-Hellman key +*/ +#define HCI_SUBEVENT_LE_GENERATE_DHKEY_COMPLETE 0x09 + +/** + * @format 11H11BBB2221 + * @param subevent_code + * @param status + * @param connection_handle + * @param role + * @param peer_address_type + * @param perr_addresss + * @param local_resolvable_private_addres + * @param peer_resolvable_private_addres + * @param conn_interval + * @param conn_latency + * @param supervision_timeout + * @param master_clock_accuracy + */ +#define HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE 0x0A + +// array of advertisements, not handled by event accessor generator +#define HCI_SUBEVENT_LE_DIRECT_ADVERTISING_REPORT 0x0B + +/** + * @format 11211 + * @param subevent_code + * @param status + * @param connection_handle + * @param TX_PHY + * @param RX_PHY + */ +#define HCI_SUBEVENT_LE_PHY_UPDATE_COMPLETE 0x0C + +// array of advertisements, not handled by event accessor generator +#define HCI_SUBEVENT_LE_EXTENDED_ADVERTISING_REPORT 0x0D + +#define HCI_SUBEVENT_LE_PERIODIC_ADVERTISING_SYNC_ESTABLISHED 0x0E + +/** + * @format 1211111B + * @param subevent_code + * @param sync_handle + * @param tx_power + * @param rssi + * @param unused + * @param data_status + * @param data_length + * @param data + */ +#define HCI_SUBEVENT_LE_PERIODIC_ADVERTISING_REPORT 0x0F + +/** + * @format 2 + * @param sync_handle +*/ +#define HCI_SUBEVENT_LE_PERIODIC_ADVERTISING_SYNC_LOST 0x10 + +/** + * @format +*/ +#define HCI_SUBEVENT_LE_SCAN_TIMEOUT 0x11 + +/** + * @format 1121 + * @param subevent_code + * @param status + * @param advertising_handle + * @param connection_handle + * @param num_completed_extended_advertising_events + */ +#define HCI_SUBEVENT_LE_ADVERTISING_SET_TERMINATED 0x12 + +/** + * @format 1116 + * @param subevent_code + * @param advertising_handle + * @param scanner_address_type + * @param scanner_address + */ +#define HCI_SUBEVENT_LE_SCAN_REQUEST_RECEIVED 0x13 + +/** + * @format 21 + * @param subevent_code + * @param connection_handle + * @param channel_selection_algorithm + */ +#define HCI_SUBEVENT_LE_CHANNEL_SELECTION_ALGORITHM 0x14 + + +#define HCI_SUBEVENT_LE_VENDOR_INTERVAL_COMPLETE 0xF0 + +/** + * @format +*/ +#define HCI_EVENT_ANCS_META 0xEA + + +/** + * compact HCI Command packet description + */ +typedef struct { + uint16_t opcode; + const char *format; +} hci_cmd_t; + +int hci_send_cmd(const hci_cmd_t *cmd, ...); + + +extern const hci_cmd_t hci_reset; +extern const hci_cmd_t hci_read_bd_addr; +extern const hci_cmd_t hci_read_local_supported_features; +extern const hci_cmd_t hci_read_buffer_size; +extern const hci_cmd_t hci_read_local_supported_commands; +extern const hci_cmd_t hci_read_local_version_information; +extern const hci_cmd_t hci_read_le_host_supported; +extern const hci_cmd_t hci_read_local_name; +extern const hci_cmd_t hci_write_class_of_device; +extern const hci_cmd_t hci_write_local_name; +extern const hci_cmd_t hci_write_scan_enable; +extern const hci_cmd_t hci_set_event_mask; +extern const hci_cmd_t hci_le_add_device_to_white_list; +extern const hci_cmd_t hci_le_clear_white_list; +extern const hci_cmd_t hci_le_connection_update; +extern const hci_cmd_t hci_le_create_connection; +extern const hci_cmd_t hci_le_create_connection_cancel; +extern const hci_cmd_t hci_le_encrypt; +extern const hci_cmd_t hci_le_generate_dhkey; +extern const hci_cmd_t hci_le_long_term_key_negative_reply; +extern const hci_cmd_t hci_le_long_term_key_request_reply; +extern const hci_cmd_t hci_le_rand; +extern const hci_cmd_t hci_le_read_advertising_channel_tx_power; +extern const hci_cmd_t hci_le_read_buffer_size; +extern const hci_cmd_t hci_le_read_channel_map; +extern const hci_cmd_t hci_le_read_local_p256_public_key; +extern const hci_cmd_t hci_le_read_maximum_data_length; +extern const hci_cmd_t hci_le_read_remote_used_features; +extern const hci_cmd_t hci_le_read_suggested_default_data_length; +extern const hci_cmd_t hci_le_read_supported_features; +extern const hci_cmd_t hci_le_read_supported_states; +extern const hci_cmd_t hci_le_read_white_list_size; +extern const hci_cmd_t hci_le_receiver_test; +extern const hci_cmd_t hci_le_remove_device_from_white_list; +extern const hci_cmd_t hci_le_set_advertise_enable; +extern const hci_cmd_t hci_le_set_advertising_data; +extern const hci_cmd_t hci_le_set_advertising_parameters; +extern const hci_cmd_t hci_le_set_data_length; +extern const hci_cmd_t hci_le_set_event_mask; +extern const hci_cmd_t hci_le_set_host_channel_classification; +extern const hci_cmd_t hci_le_set_random_address; +extern const hci_cmd_t hci_le_set_scan_enable; +extern const hci_cmd_t hci_le_set_scan_parameters; +extern const hci_cmd_t hci_le_set_scan_response_data; +extern const hci_cmd_t hci_le_start_encryption; +extern const hci_cmd_t hci_le_test_end; +extern const hci_cmd_t hci_le_transmitter_test; +extern const hci_cmd_t hci_le_write_suggested_default_data_length; +extern const hci_cmd_t hci_le_set_phy; + +extern const hci_cmd_t hci_le_set_ext_advertising_parameters; +extern const hci_cmd_t hci_le_set_ext_advertising_data; +extern const hci_cmd_t hci_le_set_ext_advertise_enable; +extern const hci_cmd_t hci_le_set_ext_scan_parameters; +extern const hci_cmd_t hci_le_set_ext_scan_enable; + +enum VENDOR_REMOTE_TEST_VALUE { + VENDOR_TEST_DISCONNECTED = 0, + VENDOR_TEST_LEGACY_CONNECTED_BY_BT_CLASSIC, + VENDOR_TEST_LEGACY_CONNECTED_BY_BLE, + VENDOR_TEST_CONNECTED_WITH_TWS, +}; + + +#endif diff --git a/include_lib/btstack/bt_profile_config.h b/include_lib/btstack/bt_profile_config.h new file mode 100644 index 0000000..0f1a665 --- /dev/null +++ b/include_lib/btstack/bt_profile_config.h @@ -0,0 +1,38 @@ +/********************************************************************************************* + * Filename : bt_profile_config.h + + * Description : + + * Author : Tongai + + * Email : laotongai@zh-jieli.com + + * Last modifiled : 2020-07-01 16:31 + + * Copyright:(c)JIELI 2011-2019 @ , All Rights Reserved. +*********************************************************************************************/ +#ifndef BT_PROFILE_H +#define BT_PROFILE_H + + +#define BT_BTSTACK_CLASSIC BIT(0) +#define BT_BTSTACK_LE_ADV BIT(1) +#define BT_BTSTACK_LE BIT(2) + +extern const int config_stack_modules; +#define STACK_MODULES_IS_SUPPORT(x) (config_stack_modules & (x)) + + + +extern u8 app_bredr_pool[]; +extern u8 app_le_pool[]; +extern u8 app_l2cap_pool[]; +extern u8 app_bredr_profile[]; + +extern u16 get_bredr_pool_len(void); +extern u16 get_le_pool_len(void); +extern u16 get_l2cap_stack_len(void); +extern u16 get_profile_pool_len(void); + + +#endif diff --git a/include_lib/btstack/btstack_error.h b/include_lib/btstack/btstack_error.h new file mode 100644 index 0000000..b3187dd --- /dev/null +++ b/include_lib/btstack/btstack_error.h @@ -0,0 +1,38 @@ +#ifndef BTSTACK_ERROR_H +#define BTSTACK_ERROR_H + + +#define ERROR_CODE_SUCCESS 0x00 +#define ERROR_CODE_PAGE_TIMEOUT 0x04 +#define ERROR_CODE_AUTHENTICATION_FAILURE 0x05 +#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 +#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 +#define ERROR_CODE_CONNECTION_TERMINATED_BY_LOCAL_HOST 0x16 + +#define CUSTOM_BB_AUTO_CANCEL_PAGE 0xFD //// app cancle page +#define BB_CANCEL_PAGE 0xFE //// bb cancle page + + + + + + + + + + + + + + + + + +#endif + diff --git a/include_lib/btstack/btstack_event.h b/include_lib/btstack/btstack_event.h new file mode 100644 index 0000000..a2cd867 --- /dev/null +++ b/include_lib/btstack/btstack_event.h @@ -0,0 +1,6625 @@ +/********************************************************************************************* + * Filename : btstack_event.h + + * Description : + + * Author : Tongai + + * Email : laotongai@zh-jieli.com + + * Last modifiled : 2020-07-01 16:23 + + * Copyright:(c)JIELI 2011-2019 @ , All Rights Reserved. +*********************************************************************************************/ + +#ifndef __BTSTACK_EVENT_H +#define __BTSTACK_EVENT_H + +#if defined __cplusplus +extern "C" { +#endif + +#include "btstack/btstack_typedef.h" +#include + +#define ENABLE_BLE + +#ifdef ENABLE_BLE +#include "le/gatt.h" +#endif + + /* API_START */ + + /** + * @brief Get event type + * @param event + * @return type of event + */ + static inline uint8_t hci_event_packet_get_type(const uint8_t *event) + { + return event[0]; + } + + /*** + * @brief Get subevent code for ancs event + * @param event packet + * @return subevent_code + */ + static inline uint8_t hci_event_ancs_meta_get_subevent_code(const uint8_t *event) + { + return event[2]; + } + /*** + * @brief Get subevent code for avdtp event + * @param event packet + * @return subevent_code + */ + static inline uint8_t hci_event_avdtp_meta_get_subevent_code(const uint8_t *event) + { + return event[2]; + } + /*** + * @brief Get subevent code for a2dp event + * @param event packet + * @return subevent_code + */ + static inline uint8_t hci_event_a2dp_meta_get_subevent_code(const uint8_t *event) + { + return event[2]; + } + /*** + * @brief Get subevent code for avrcp event + * @param event packet + * @return subevent_code + */ + static inline uint8_t hci_event_avrcp_meta_get_subevent_code(const uint8_t *event) + { + return event[2]; + } + /*** + * @brief Get subevent code for goep event + * @param event packet + * @return subevent_code + */ + static inline uint8_t hci_event_goep_meta_get_subevent_code(const uint8_t *event) + { + return event[2]; + } + /*** + * @brief Get subevent code for hfp event + * @param event packet + * @return subevent_code + */ + static inline uint8_t hci_event_hfp_meta_get_subevent_code(const uint8_t *event) + { + return event[2]; + } + /*** + * @brief Get subevent code for hsp event + * @param event packet + * @return subevent_code + */ + static inline uint8_t hci_event_hsp_meta_get_subevent_code(const uint8_t *event) + { + return event[2]; + } + /*** + * @brief Get subevent code for pbap event + * @param event packet + * @return subevent_code + */ + static inline uint8_t hci_event_pbap_meta_get_subevent_code(const uint8_t *event) + { + return event[2]; + } + /*** + * @brief Get subevent code for le event + * @param event packet + * @return subevent_code + */ + static inline uint8_t hci_event_le_meta_get_subevent_code(const uint8_t *event) + { + return event[2]; + } + /*** + * @brief Get subevent code for hid event + * @param event packet + * @return subevent_code + */ + static inline uint8_t hci_event_hid_meta_get_subevent_code(const uint8_t *event) + { + return event[2]; + } + /*** + * @brief Get subevent code for hids event + * @param event packet + * @return subevent_code + */ + static inline uint8_t hci_event_hids_meta_get_subevent_code(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field status from event HCI_EVENT_INQUIRY_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_inquiry_complete_get_status(const uint8_t *event) + { + return event[2]; + } + + /** + * @brief Get field num_responses from event HCI_EVENT_INQUIRY_RESULT + * @param event packet + * @return num_responses + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_inquiry_result_get_num_responses(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field bd_addr from event HCI_EVENT_INQUIRY_RESULT + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void hci_event_inquiry_result_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[3], bd_addr); + } + /** + * @brief Get field page_scan_repetition_mode from event HCI_EVENT_INQUIRY_RESULT + * @param event packet + * @return page_scan_repetition_mode + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_inquiry_result_get_page_scan_repetition_mode(const uint8_t *event) + { + return event[9]; + } + /** + * @brief Get field reserved1 from event HCI_EVENT_INQUIRY_RESULT + * @param event packet + * @return reserved1 + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_inquiry_result_get_reserved1(const uint8_t *event) + { + return event[10]; + } + /** + * @brief Get field reserved2 from event HCI_EVENT_INQUIRY_RESULT + * @param event packet + * @return reserved2 + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_inquiry_result_get_reserved2(const uint8_t *event) + { + return event[11]; + } + /** + * @brief Get field class_of_device from event HCI_EVENT_INQUIRY_RESULT + * @param event packet + * @return class_of_device + * @note: btstack_type 3 + */ + static inline uint32_t hci_event_inquiry_result_get_class_of_device(const uint8_t *event) + { + return little_endian_read_24(event, 12); + } + /** + * @brief Get field clock_offset from event HCI_EVENT_INQUIRY_RESULT + * @param event packet + * @return clock_offset + * @note: btstack_type 2 + */ + static inline uint16_t hci_event_inquiry_result_get_clock_offset(const uint8_t *event) + { + return little_endian_read_16(event, 15); + } + + /** + * @brief Get field status from event HCI_EVENT_CONNECTION_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_connection_complete_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field connection_handle from event HCI_EVENT_CONNECTION_COMPLETE + * @param event packet + * @return connection_handle + * @note: btstack_type 2 + */ + static inline uint16_t hci_event_connection_complete_get_connection_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field bd_addr from event HCI_EVENT_CONNECTION_COMPLETE + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void hci_event_connection_complete_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[5], bd_addr); + } + /** + * @brief Get field link_type from event HCI_EVENT_CONNECTION_COMPLETE + * @param event packet + * @return link_type + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_connection_complete_get_link_type(const uint8_t *event) + { + return event[11]; + } + /** + * @brief Get field encryption_enabled from event HCI_EVENT_CONNECTION_COMPLETE + * @param event packet + * @return encryption_enabled + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_connection_complete_get_encryption_enabled(const uint8_t *event) + { + return event[12]; + } + + /** + * @brief Get field bd_addr from event HCI_EVENT_CONNECTION_REQUEST + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void hci_event_connection_request_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[2], bd_addr); + } + /** + * @brief Get field class_of_device from event HCI_EVENT_CONNECTION_REQUEST + * @param event packet + * @return class_of_device + * @note: btstack_type 3 + */ + static inline uint32_t hci_event_connection_request_get_class_of_device(const uint8_t *event) + { + return little_endian_read_24(event, 8); + } + /** + * @brief Get field link_type from event HCI_EVENT_CONNECTION_REQUEST + * @param event packet + * @return link_type + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_connection_request_get_link_type(const uint8_t *event) + { + return event[11]; + } + + /** + * @brief Get field status from event HCI_EVENT_DISCONNECTION_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_disconnection_complete_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field connection_handle from event HCI_EVENT_DISCONNECTION_COMPLETE + * @param event packet + * @return connection_handle + * @note: btstack_type 2 + */ + static inline uint16_t hci_event_disconnection_complete_get_connection_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field reason from event HCI_EVENT_DISCONNECTION_COMPLETE + * @param event packet + * @return reason + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_disconnection_complete_get_reason(const uint8_t *event) + { + return event[5]; + } + + /** + * @brief Get field status from event HCI_EVENT_AUTHENTICATION_COMPLETE_EVENT + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_authentication_complete_event_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field connection_handle from event HCI_EVENT_AUTHENTICATION_COMPLETE_EVENT + * @param event packet + * @return connection_handle + * @note: btstack_type 2 + */ + static inline uint16_t hci_event_authentication_complete_event_get_connection_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + + /** + * @brief Get field status from event HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_remote_name_request_complete_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field bd_addr from event HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void hci_event_remote_name_request_complete_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[3], bd_addr); + } + /** + * @brief Get field remote_name from event HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE + * @param event packet + * @return remote_name + * @note: btstack_type N + */ + static inline const char *hci_event_remote_name_request_complete_get_remote_name(const uint8_t *event) + { + return (const char *) &event[9]; + } + + /** + * @brief Get field status from event HCI_EVENT_ENCRYPTION_CHANGE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_encryption_change_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field connection_handle from event HCI_EVENT_ENCRYPTION_CHANGE + * @param event packet + * @return connection_handle + * @note: btstack_type 2 + */ + static inline uint16_t hci_event_encryption_change_get_connection_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field encryption_enabled from event HCI_EVENT_ENCRYPTION_CHANGE + * @param event packet + * @return encryption_enabled + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_encryption_change_get_encryption_enabled(const uint8_t *event) + { + return event[5]; + } + + /** + * @brief Get field status from event HCI_EVENT_CHANGE_CONNECTION_LINK_KEY_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_change_connection_link_key_complete_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field connection_handle from event HCI_EVENT_CHANGE_CONNECTION_LINK_KEY_COMPLETE + * @param event packet + * @return connection_handle + * @note: btstack_type 2 + */ + static inline uint16_t hci_event_change_connection_link_key_complete_get_connection_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + + /** + * @brief Get field status from event HCI_EVENT_MASTER_LINK_KEY_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_master_link_key_complete_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field connection_handle from event HCI_EVENT_MASTER_LINK_KEY_COMPLETE + * @param event packet + * @return connection_handle + * @note: btstack_type 2 + */ + static inline uint16_t hci_event_master_link_key_complete_get_connection_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field key_flag from event HCI_EVENT_MASTER_LINK_KEY_COMPLETE + * @param event packet + * @return key_flag + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_master_link_key_complete_get_key_flag(const uint8_t *event) + { + return event[5]; + } + + /** + * @brief Get field num_hci_command_packets from event HCI_EVENT_COMMAND_COMPLETE + * @param event packet + * @return num_hci_command_packets + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_command_complete_get_num_hci_command_packets(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field command_opcode from event HCI_EVENT_COMMAND_COMPLETE + * @param event packet + * @return command_opcode + * @note: btstack_type 2 + */ + static inline uint16_t hci_event_command_complete_get_command_opcode(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field return_parameters from event HCI_EVENT_COMMAND_COMPLETE + * @param event packet + * @return return_parameters + * @note: btstack_type R + */ + static inline const uint8_t *hci_event_command_complete_get_return_parameters(const uint8_t *event) + { + return &event[5]; + } + + /** + * @brief Get field status from event HCI_EVENT_COMMAND_STATUS + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_command_status_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field num_hci_command_packets from event HCI_EVENT_COMMAND_STATUS + * @param event packet + * @return num_hci_command_packets + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_command_status_get_num_hci_command_packets(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field command_opcode from event HCI_EVENT_COMMAND_STATUS + * @param event packet + * @return command_opcode + * @note: btstack_type 2 + */ + static inline uint16_t hci_event_command_status_get_command_opcode(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + + /** + * @brief Get field hardware_code from event HCI_EVENT_HARDWARE_ERROR + * @param event packet + * @return hardware_code + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_hardware_error_get_hardware_code(const uint8_t *event) + { + return event[2]; + } + + /** + * @brief Get field status from event HCI_EVENT_ROLE_CHANGE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_role_change_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field bd_addr from event HCI_EVENT_ROLE_CHANGE + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void hci_event_role_change_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[3], bd_addr); + } + /** + * @brief Get field role from event HCI_EVENT_ROLE_CHANGE + * @param event packet + * @return role + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_role_change_get_role(const uint8_t *event) + { + return event[9]; + } + + /** + * @brief Get field status from event HCI_EVENT_MODE_CHANGE_EVENT + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_mode_change_event_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field handle from event HCI_EVENT_MODE_CHANGE_EVENT + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t hci_event_mode_change_event_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field mode from event HCI_EVENT_MODE_CHANGE_EVENT + * @param event packet + * @return mode + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_mode_change_event_get_mode(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field interval from event HCI_EVENT_MODE_CHANGE_EVENT + * @param event packet + * @return interval + * @note: btstack_type 2 + */ + static inline uint16_t hci_event_mode_change_event_get_interval(const uint8_t *event) + { + return little_endian_read_16(event, 6); + } + + /** + * @brief Get field bd_addr from event HCI_EVENT_PIN_CODE_REQUEST + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void hci_event_pin_code_request_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[2], bd_addr); + } + + /** + * @brief Get field bd_addr from event HCI_EVENT_LINK_KEY_REQUEST + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void hci_event_link_key_request_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[2], bd_addr); + } + + /** + * @brief Get field link_type from event HCI_EVENT_DATA_BUFFER_OVERFLOW + * @param event packet + * @return link_type + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_data_buffer_overflow_get_link_type(const uint8_t *event) + { + return event[2]; + } + + /** + * @brief Get field handle from event HCI_EVENT_MAX_SLOTS_CHANGED + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t hci_event_max_slots_changed_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field lmp_max_slots from event HCI_EVENT_MAX_SLOTS_CHANGED + * @param event packet + * @return lmp_max_slots + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_max_slots_changed_get_lmp_max_slots(const uint8_t *event) + { + return event[4]; + } + + /** + * @brief Get field status from event HCI_EVENT_READ_CLOCK_OFFSET_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_read_clock_offset_complete_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field handle from event HCI_EVENT_READ_CLOCK_OFFSET_COMPLETE + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t hci_event_read_clock_offset_complete_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field clock_offset from event HCI_EVENT_READ_CLOCK_OFFSET_COMPLETE + * @param event packet + * @return clock_offset + * @note: btstack_type 2 + */ + static inline uint16_t hci_event_read_clock_offset_complete_get_clock_offset(const uint8_t *event) + { + return little_endian_read_16(event, 5); + } + + /** + * @brief Get field status from event HCI_EVENT_CONNECTION_PACKET_TYPE_CHANGED + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_connection_packet_type_changed_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field handle from event HCI_EVENT_CONNECTION_PACKET_TYPE_CHANGED + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t hci_event_connection_packet_type_changed_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field packet_types from event HCI_EVENT_CONNECTION_PACKET_TYPE_CHANGED + * @param event packet + * @return packet_types + * @note: btstack_type 2 + */ + static inline uint16_t hci_event_connection_packet_type_changed_get_packet_types(const uint8_t *event) + { + return little_endian_read_16(event, 5); + } + + /** + * @brief Get field num_responses from event HCI_EVENT_INQUIRY_RESULT_WITH_RSSI + * @param event packet + * @return num_responses + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_inquiry_result_with_rssi_get_num_responses(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field bd_addr from event HCI_EVENT_INQUIRY_RESULT_WITH_RSSI + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void hci_event_inquiry_result_with_rssi_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[3], bd_addr); + } + /** + * @brief Get field page_scan_repetition_mode from event HCI_EVENT_INQUIRY_RESULT_WITH_RSSI + * @param event packet + * @return page_scan_repetition_mode + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_inquiry_result_with_rssi_get_page_scan_repetition_mode(const uint8_t *event) + { + return event[9]; + } + /** + * @brief Get field reserved from event HCI_EVENT_INQUIRY_RESULT_WITH_RSSI + * @param event packet + * @return reserved + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_inquiry_result_with_rssi_get_reserved(const uint8_t *event) + { + return event[10]; + } + /** + * @brief Get field class_of_device from event HCI_EVENT_INQUIRY_RESULT_WITH_RSSI + * @param event packet + * @return class_of_device + * @note: btstack_type 3 + */ + static inline uint32_t hci_event_inquiry_result_with_rssi_get_class_of_device(const uint8_t *event) + { + return little_endian_read_24(event, 11); + } + /** + * @brief Get field clock_offset from event HCI_EVENT_INQUIRY_RESULT_WITH_RSSI + * @param event packet + * @return clock_offset + * @note: btstack_type 2 + */ + static inline uint16_t hci_event_inquiry_result_with_rssi_get_clock_offset(const uint8_t *event) + { + return little_endian_read_16(event, 14); + } + /** + * @brief Get field rssi from event HCI_EVENT_INQUIRY_RESULT_WITH_RSSI + * @param event packet + * @return rssi + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_inquiry_result_with_rssi_get_rssi(const uint8_t *event) + { + return event[16]; + } + + /** + * @brief Get field status from event HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_synchronous_connection_complete_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field handle from event HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t hci_event_synchronous_connection_complete_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field bd_addr from event HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void hci_event_synchronous_connection_complete_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[5], bd_addr); + } + /** + * @brief Get field link_type from event HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE + * @param event packet + * @return link_type + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_synchronous_connection_complete_get_link_type(const uint8_t *event) + { + return event[11]; + } + /** + * @brief Get field transmission_interval from event HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE + * @param event packet + * @return transmission_interval + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_synchronous_connection_complete_get_transmission_interval(const uint8_t *event) + { + return event[12]; + } + /** + * @brief Get field retransmission_interval from event HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE + * @param event packet + * @return retransmission_interval + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_synchronous_connection_complete_get_retransmission_interval(const uint8_t *event) + { + return event[13]; + } + /** + * @brief Get field rx_packet_length from event HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE + * @param event packet + * @return rx_packet_length + * @note: btstack_type 2 + */ + static inline uint16_t hci_event_synchronous_connection_complete_get_rx_packet_length(const uint8_t *event) + { + return little_endian_read_16(event, 14); + } + /** + * @brief Get field tx_packet_length from event HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE + * @param event packet + * @return tx_packet_length + * @note: btstack_type 2 + */ + static inline uint16_t hci_event_synchronous_connection_complete_get_tx_packet_length(const uint8_t *event) + { + return little_endian_read_16(event, 16); + } + /** + * @brief Get field air_mode from event HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE + * @param event packet + * @return air_mode + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_synchronous_connection_complete_get_air_mode(const uint8_t *event) + { + return event[18]; + } + + /** + * @brief Get field num_responses from event HCI_EVENT_EXTENDED_INQUIRY_RESPONSE + * @param event packet + * @return num_responses + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_extended_inquiry_response_get_num_responses(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field bd_addr from event HCI_EVENT_EXTENDED_INQUIRY_RESPONSE + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void hci_event_extended_inquiry_response_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[3], bd_addr); + } + /** + * @brief Get field page_scan_repetition_mode from event HCI_EVENT_EXTENDED_INQUIRY_RESPONSE + * @param event packet + * @return page_scan_repetition_mode + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_extended_inquiry_response_get_page_scan_repetition_mode(const uint8_t *event) + { + return event[9]; + } + /** + * @brief Get field reserved from event HCI_EVENT_EXTENDED_INQUIRY_RESPONSE + * @param event packet + * @return reserved + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_extended_inquiry_response_get_reserved(const uint8_t *event) + { + return event[10]; + } + /** + * @brief Get field class_of_device from event HCI_EVENT_EXTENDED_INQUIRY_RESPONSE + * @param event packet + * @return class_of_device + * @note: btstack_type 3 + */ + static inline uint32_t hci_event_extended_inquiry_response_get_class_of_device(const uint8_t *event) + { + return little_endian_read_24(event, 11); + } + /** + * @brief Get field clock_offset from event HCI_EVENT_EXTENDED_INQUIRY_RESPONSE + * @param event packet + * @return clock_offset + * @note: btstack_type 2 + */ + static inline uint16_t hci_event_extended_inquiry_response_get_clock_offset(const uint8_t *event) + { + return little_endian_read_16(event, 14); + } + /** + * @brief Get field rssi from event HCI_EVENT_EXTENDED_INQUIRY_RESPONSE + * @param event packet + * @return rssi + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_extended_inquiry_response_get_rssi(const uint8_t *event) + { + return event[16]; + } + + /** + * @brief Get field status from event HCI_EVENT_ENCRYPTION_KEY_REFRESH_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_encryption_key_refresh_complete_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field handle from event HCI_EVENT_ENCRYPTION_KEY_REFRESH_COMPLETE + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t hci_event_encryption_key_refresh_complete_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + + /** + * @brief Get field bd_addr from event HCI_EVENT_USER_CONFIRMATION_REQUEST + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void hci_event_user_confirmation_request_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[2], bd_addr); + } + /** + * @brief Get field numeric_value from event HCI_EVENT_USER_CONFIRMATION_REQUEST + * @param event packet + * @return numeric_value + * @note: btstack_type 4 + */ + static inline uint32_t hci_event_user_confirmation_request_get_numeric_value(const uint8_t *event) + { + return little_endian_read_32(event, 8); + } + + /** + * @brief Get field bd_addr from event HCI_EVENT_USER_PASSKEY_REQUEST + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void hci_event_user_passkey_request_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[2], bd_addr); + } + + /** + * @brief Get field bd_addr from event HCI_EVENT_REMOTE_OOB_DATA_REQUEST + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void hci_event_remote_oob_data_request_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[2], bd_addr); + } + + /** + * @brief Get field status from event HCI_EVENT_SIMPLE_PAIRING_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_simple_pairing_complete_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field bd_addr from event HCI_EVENT_SIMPLE_PAIRING_COMPLETE + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void hci_event_simple_pairing_complete_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[3], bd_addr); + } + + /** + * @brief Get field state from event BTSTACK_EVENT_STATE + * @param event packet + * @return state + * @note: btstack_type 1 + */ + static inline uint8_t btstack_event_state_get_state(const uint8_t *event) + { + return event[2]; + } + + /** + * @brief Get field number_connections from event BTSTACK_EVENT_NR_CONNECTIONS_CHANGED + * @param event packet + * @return number_connections + * @note: btstack_type 1 + */ + static inline uint8_t btstack_event_nr_connections_changed_get_number_connections(const uint8_t *event) + { + return event[2]; + } + + + /** + * @brief Get field discoverable from event BTSTACK_EVENT_DISCOVERABLE_ENABLED + * @param event packet + * @return discoverable + * @note: btstack_type 1 + */ + static inline uint8_t btstack_event_discoverable_enabled_get_discoverable(const uint8_t *event) + { + return event[2]; + } + + /** + * @brief Get field active from event HCI_EVENT_TRANSPORT_SLEEP_MODE + * @param event packet + * @return active + * @note: btstack_type 1 + */ + static inline uint8_t hci_event_transport_sleep_mode_get_active(const uint8_t *event) + { + return event[2]; + } + + /** + * @brief Get field handle from event HCI_EVENT_SCO_CAN_SEND_NOW + * @param event packet + * @param Pointer to storage for handle + * @note: btstack_type B + */ + static inline void hci_event_sco_can_send_now_get_handle(const uint8_t *event, bd_addr_t handle) + { + reverse_bd_addr(&event[2], handle); + } + + /** + * @brief Get field status from event L2CAP_EVENT_CHANNEL_OPENED + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t l2cap_event_channel_opened_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field address from event L2CAP_EVENT_CHANNEL_OPENED + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void l2cap_event_channel_opened_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[3], address); + } + /** + * @brief Get field handle from event L2CAP_EVENT_CHANNEL_OPENED + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t l2cap_event_channel_opened_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 9); + } + /** + * @brief Get field psm from event L2CAP_EVENT_CHANNEL_OPENED + * @param event packet + * @return psm + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_channel_opened_get_psm(const uint8_t *event) + { + return little_endian_read_16(event, 11); + } + /** + * @brief Get field local_cid from event L2CAP_EVENT_CHANNEL_OPENED + * @param event packet + * @return local_cid + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_channel_opened_get_local_cid(const uint8_t *event) + { + return little_endian_read_16(event, 13); + } + /** + * @brief Get field remote_cid from event L2CAP_EVENT_CHANNEL_OPENED + * @param event packet + * @return remote_cid + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_channel_opened_get_remote_cid(const uint8_t *event) + { + return little_endian_read_16(event, 15); + } + /** + * @brief Get field local_mtu from event L2CAP_EVENT_CHANNEL_OPENED + * @param event packet + * @return local_mtu + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_channel_opened_get_local_mtu(const uint8_t *event) + { + return little_endian_read_16(event, 17); + } + /** + * @brief Get field remote_mtu from event L2CAP_EVENT_CHANNEL_OPENED + * @param event packet + * @return remote_mtu + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_channel_opened_get_remote_mtu(const uint8_t *event) + { + return little_endian_read_16(event, 19); + } + /** + * @brief Get field flush_timeout from event L2CAP_EVENT_CHANNEL_OPENED + * @param event packet + * @return flush_timeout + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_channel_opened_get_flush_timeout(const uint8_t *event) + { + return little_endian_read_16(event, 21); + } + /** + * @brief Get field incoming from event L2CAP_EVENT_CHANNEL_OPENED + * @param event packet + * @return incoming + * @note: btstack_type 1 + */ + static inline uint8_t l2cap_event_channel_opened_get_incoming(const uint8_t *event) + { + return event[23]; + } + + /** + * @brief Get field local_cid from event L2CAP_EVENT_CHANNEL_CLOSED + * @param event packet + * @return local_cid + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_channel_closed_get_local_cid(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + + /** + * @brief Get field address from event L2CAP_EVENT_INCOMING_CONNECTION + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void l2cap_event_incoming_connection_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[2], address); + } + /** + * @brief Get field handle from event L2CAP_EVENT_INCOMING_CONNECTION + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t l2cap_event_incoming_connection_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 8); + } + /** + * @brief Get field psm from event L2CAP_EVENT_INCOMING_CONNECTION + * @param event packet + * @return psm + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_incoming_connection_get_psm(const uint8_t *event) + { + return little_endian_read_16(event, 10); + } + /** + * @brief Get field local_cid from event L2CAP_EVENT_INCOMING_CONNECTION + * @param event packet + * @return local_cid + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_incoming_connection_get_local_cid(const uint8_t *event) + { + return little_endian_read_16(event, 12); + } + /** + * @brief Get field remote_cid from event L2CAP_EVENT_INCOMING_CONNECTION + * @param event packet + * @return remote_cid + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_incoming_connection_get_remote_cid(const uint8_t *event) + { + return little_endian_read_16(event, 14); + } + + /** + * @brief Get field handle from event L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_REQUEST + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t l2cap_event_connection_parameter_update_request_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field interval_min from event L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_REQUEST + * @param event packet + * @return interval_min + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_connection_parameter_update_request_get_interval_min(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field interval_max from event L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_REQUEST + * @param event packet + * @return interval_max + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_connection_parameter_update_request_get_interval_max(const uint8_t *event) + { + return little_endian_read_16(event, 6); + } + /** + * @brief Get field latencey from event L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_REQUEST + * @param event packet + * @return latencey + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_connection_parameter_update_request_get_latencey(const uint8_t *event) + { + return little_endian_read_16(event, 8); + } + /** + * @brief Get field timeout_multiplier from event L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_REQUEST + * @param event packet + * @return timeout_multiplier + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_connection_parameter_update_request_get_timeout_multiplier(const uint8_t *event) + { + return little_endian_read_16(event, 10); + } + + /** + * @brief Get field handle from event L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t l2cap_event_connection_parameter_update_response_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field result from event L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE + * @param event packet + * @return result + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_connection_parameter_update_response_get_result(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + + /** + * @brief Get field local_cid from event L2CAP_EVENT_CAN_SEND_NOW + * @param event packet + * @return local_cid + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_can_send_now_get_local_cid(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + + /** + * @brief Get field address_type from event L2CAP_EVENT_LE_INCOMING_CONNECTION + * @param event packet + * @return address_type + * @note: btstack_type 1 + */ + static inline uint8_t l2cap_event_le_incoming_connection_get_address_type(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field address from event L2CAP_EVENT_LE_INCOMING_CONNECTION + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void l2cap_event_le_incoming_connection_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[3], address); + } + /** + * @brief Get field handle from event L2CAP_EVENT_LE_INCOMING_CONNECTION + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t l2cap_event_le_incoming_connection_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 9); + } + /** + * @brief Get field psm from event L2CAP_EVENT_LE_INCOMING_CONNECTION + * @param event packet + * @return psm + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_le_incoming_connection_get_psm(const uint8_t *event) + { + return little_endian_read_16(event, 11); + } + /** + * @brief Get field local_cid from event L2CAP_EVENT_LE_INCOMING_CONNECTION + * @param event packet + * @return local_cid + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_le_incoming_connection_get_local_cid(const uint8_t *event) + { + return little_endian_read_16(event, 13); + } + /** + * @brief Get field remote_cid from event L2CAP_EVENT_LE_INCOMING_CONNECTION + * @param event packet + * @return remote_cid + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_le_incoming_connection_get_remote_cid(const uint8_t *event) + { + return little_endian_read_16(event, 15); + } + /** + * @brief Get field remote_mtu from event L2CAP_EVENT_LE_INCOMING_CONNECTION + * @param event packet + * @return remote_mtu + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_le_incoming_connection_get_remote_mtu(const uint8_t *event) + { + return little_endian_read_16(event, 17); + } + + /** + * @brief Get field status from event L2CAP_EVENT_LE_CHANNEL_OPENED + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t l2cap_event_le_channel_opened_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field address_type from event L2CAP_EVENT_LE_CHANNEL_OPENED + * @param event packet + * @return address_type + * @note: btstack_type 1 + */ + static inline uint8_t l2cap_event_le_channel_opened_get_address_type(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field address from event L2CAP_EVENT_LE_CHANNEL_OPENED + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void l2cap_event_le_channel_opened_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[4], address); + } + /** + * @brief Get field handle from event L2CAP_EVENT_LE_CHANNEL_OPENED + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t l2cap_event_le_channel_opened_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 10); + } + /** + * @brief Get field incoming from event L2CAP_EVENT_LE_CHANNEL_OPENED + * @param event packet + * @return incoming + * @note: btstack_type 1 + */ + static inline uint8_t l2cap_event_le_channel_opened_get_incoming(const uint8_t *event) + { + return event[12]; + } + /** + * @brief Get field psm from event L2CAP_EVENT_LE_CHANNEL_OPENED + * @param event packet + * @return psm + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_le_channel_opened_get_psm(const uint8_t *event) + { + return little_endian_read_16(event, 13); + } + /** + * @brief Get field local_cid from event L2CAP_EVENT_LE_CHANNEL_OPENED + * @param event packet + * @return local_cid + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_le_channel_opened_get_local_cid(const uint8_t *event) + { + return little_endian_read_16(event, 15); + } + /** + * @brief Get field remote_cid from event L2CAP_EVENT_LE_CHANNEL_OPENED + * @param event packet + * @return remote_cid + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_le_channel_opened_get_remote_cid(const uint8_t *event) + { + return little_endian_read_16(event, 17); + } + /** + * @brief Get field local_mtu from event L2CAP_EVENT_LE_CHANNEL_OPENED + * @param event packet + * @return local_mtu + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_le_channel_opened_get_local_mtu(const uint8_t *event) + { + return little_endian_read_16(event, 19); + } + /** + * @brief Get field remote_mtu from event L2CAP_EVENT_LE_CHANNEL_OPENED + * @param event packet + * @return remote_mtu + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_le_channel_opened_get_remote_mtu(const uint8_t *event) + { + return little_endian_read_16(event, 21); + } + + /** + * @brief Get field local_cid from event L2CAP_EVENT_LE_CHANNEL_CLOSED + * @param event packet + * @return local_cid + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_le_channel_closed_get_local_cid(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + + /** + * @brief Get field local_cid from event L2CAP_EVENT_LE_CAN_SEND_NOW + * @param event packet + * @return local_cid + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_le_can_send_now_get_local_cid(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + + /** + * @brief Get field local_cid from event L2CAP_EVENT_LE_PACKET_SENT + * @param event packet + * @return local_cid + * @note: btstack_type 2 + */ + static inline uint16_t l2cap_event_le_packet_sent_get_local_cid(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + + /** + * @brief Get field status from event RFCOMM_EVENT_CHANNEL_OPENED + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t rfcomm_event_channel_opened_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field bd_addr from event RFCOMM_EVENT_CHANNEL_OPENED + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void rfcomm_event_channel_opened_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[3], bd_addr); + } + /** + * @brief Get field con_handle from event RFCOMM_EVENT_CHANNEL_OPENED + * @param event packet + * @return con_handle + * @note: btstack_type 2 + */ + static inline uint16_t rfcomm_event_channel_opened_get_con_handle(const uint8_t *event) + { + return little_endian_read_16(event, 9); + } + /** + * @brief Get field server_channel from event RFCOMM_EVENT_CHANNEL_OPENED + * @param event packet + * @return server_channel + * @note: btstack_type 1 + */ + static inline uint8_t rfcomm_event_channel_opened_get_server_channel(const uint8_t *event) + { + return event[11]; + } + /** + * @brief Get field rfcomm_cid from event RFCOMM_EVENT_CHANNEL_OPENED + * @param event packet + * @return rfcomm_cid + * @note: btstack_type 2 + */ + static inline uint16_t rfcomm_event_channel_opened_get_rfcomm_cid(const uint8_t *event) + { + return little_endian_read_16(event, 12); + } + /** + * @brief Get field max_frame_size from event RFCOMM_EVENT_CHANNEL_OPENED + * @param event packet + * @return max_frame_size + * @note: btstack_type 2 + */ + static inline uint16_t rfcomm_event_channel_opened_get_max_frame_size(const uint8_t *event) + { + return little_endian_read_16(event, 14); + } + /** + * @brief Get field incoming from event RFCOMM_EVENT_CHANNEL_OPENED + * @param event packet + * @return incoming + * @note: btstack_type 1 + */ + static inline uint8_t rfcomm_event_channel_opened_get_incoming(const uint8_t *event) + { + return event[16]; + } + + /** + * @brief Get field rfcomm_cid from event RFCOMM_EVENT_CHANNEL_CLOSED + * @param event packet + * @return rfcomm_cid + * @note: btstack_type 2 + */ + static inline uint16_t rfcomm_event_channel_closed_get_rfcomm_cid(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + + /** + * @brief Get field bd_addr from event RFCOMM_EVENT_INCOMING_CONNECTION + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void rfcomm_event_incoming_connection_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[2], bd_addr); + } + /** + * @brief Get field server_channel from event RFCOMM_EVENT_INCOMING_CONNECTION + * @param event packet + * @return server_channel + * @note: btstack_type 1 + */ + static inline uint8_t rfcomm_event_incoming_connection_get_server_channel(const uint8_t *event) + { + return event[8]; + } + /** + * @brief Get field rfcomm_cid from event RFCOMM_EVENT_INCOMING_CONNECTION + * @param event packet + * @return rfcomm_cid + * @note: btstack_type 2 + */ + static inline uint16_t rfcomm_event_incoming_connection_get_rfcomm_cid(const uint8_t *event) + { + return little_endian_read_16(event, 9); + } + + /** + * @brief Get field rfcomm_cid from event RFCOMM_EVENT_REMOTE_LINE_STATUS + * @param event packet + * @return rfcomm_cid + * @note: btstack_type 2 + */ + static inline uint16_t rfcomm_event_remote_line_status_get_rfcomm_cid(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field line_status from event RFCOMM_EVENT_REMOTE_LINE_STATUS + * @param event packet + * @return line_status + * @note: btstack_type 1 + */ + static inline uint8_t rfcomm_event_remote_line_status_get_line_status(const uint8_t *event) + { + return event[4]; + } + + /** + * @brief Get field rfcomm_cid from event RFCOMM_EVENT_REMOTE_MODEM_STATUS + * @param event packet + * @return rfcomm_cid + * @note: btstack_type 2 + */ + static inline uint16_t rfcomm_event_remote_modem_status_get_rfcomm_cid(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field modem_status from event RFCOMM_EVENT_REMOTE_MODEM_STATUS + * @param event packet + * @return modem_status + * @note: btstack_type 1 + */ + static inline uint8_t rfcomm_event_remote_modem_status_get_modem_status(const uint8_t *event) + { + return event[4]; + } + + /** + * @brief Get field rfcomm_cid from event RFCOMM_EVENT_CAN_SEND_NOW + * @param event packet + * @return rfcomm_cid + * @note: btstack_type 2 + */ + static inline uint16_t rfcomm_event_can_send_now_get_rfcomm_cid(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + + /** + * @brief Get field status from event SDP_EVENT_QUERY_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t sdp_event_query_complete_get_status(const uint8_t *event) + { + return event[2]; + } + + /** + * @brief Get field rfcomm_channel from event SDP_EVENT_QUERY_RFCOMM_SERVICE + * @param event packet + * @return rfcomm_channel + * @note: btstack_type 1 + */ + static inline uint8_t sdp_event_query_rfcomm_service_get_rfcomm_channel(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field name from event SDP_EVENT_QUERY_RFCOMM_SERVICE + * @param event packet + * @return name + * @note: btstack_type T + */ + static inline const char *sdp_event_query_rfcomm_service_get_name(const uint8_t *event) + { + return (const char *) &event[3]; + } + + /** + * @brief Get field record_id from event SDP_EVENT_QUERY_ATTRIBUTE_BYTE + * @param event packet + * @return record_id + * @note: btstack_type 2 + */ + static inline uint16_t sdp_event_query_attribute_byte_get_record_id(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field attribute_id from event SDP_EVENT_QUERY_ATTRIBUTE_BYTE + * @param event packet + * @return attribute_id + * @note: btstack_type 2 + */ + static inline uint16_t sdp_event_query_attribute_byte_get_attribute_id(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field attribute_length from event SDP_EVENT_QUERY_ATTRIBUTE_BYTE + * @param event packet + * @return attribute_length + * @note: btstack_type 2 + */ + static inline uint16_t sdp_event_query_attribute_byte_get_attribute_length(const uint8_t *event) + { + return little_endian_read_16(event, 6); + } + /** + * @brief Get field data_offset from event SDP_EVENT_QUERY_ATTRIBUTE_BYTE + * @param event packet + * @return data_offset + * @note: btstack_type 2 + */ + static inline uint16_t sdp_event_query_attribute_byte_get_data_offset(const uint8_t *event) + { + return little_endian_read_16(event, 8); + } + /** + * @brief Get field data from event SDP_EVENT_QUERY_ATTRIBUTE_BYTE + * @param event packet + * @return data + * @note: btstack_type 1 + */ + static inline uint8_t sdp_event_query_attribute_byte_get_data(const uint8_t *event) + { + return event[10]; + } + + /** + * @brief Get field record_id from event SDP_EVENT_QUERY_ATTRIBUTE_VALUE + * @param event packet + * @return record_id + * @note: btstack_type 2 + */ + static inline uint16_t sdp_event_query_attribute_value_get_record_id(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field attribute_id from event SDP_EVENT_QUERY_ATTRIBUTE_VALUE + * @param event packet + * @return attribute_id + * @note: btstack_type 2 + */ + static inline uint16_t sdp_event_query_attribute_value_get_attribute_id(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field attribute_length from event SDP_EVENT_QUERY_ATTRIBUTE_VALUE + * @param event packet + * @return attribute_length + * @note: btstack_type L + */ + static inline int sdp_event_query_attribute_value_get_attribute_length(const uint8_t *event) + { + return little_endian_read_16(event, 6); + } + /** + * @brief Get field attribute_value from event SDP_EVENT_QUERY_ATTRIBUTE_VALUE + * @param event packet + * @return attribute_value + * @note: btstack_type V + */ + static inline const uint8_t *sdp_event_query_attribute_value_get_attribute_value(const uint8_t *event) + { + return &event[8]; + } + + /** + * @brief Get field total_count from event SDP_EVENT_QUERY_SERVICE_RECORD_HANDLE + * @param event packet + * @return total_count + * @note: btstack_type 2 + */ + static inline uint16_t sdp_event_query_service_record_handle_get_total_count(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field record_index from event SDP_EVENT_QUERY_SERVICE_RECORD_HANDLE + * @param event packet + * @return record_index + * @note: btstack_type 2 + */ + static inline uint16_t sdp_event_query_service_record_handle_get_record_index(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field record_handle from event SDP_EVENT_QUERY_SERVICE_RECORD_HANDLE + * @param event packet + * @return record_handle + * @note: btstack_type 4 + */ + static inline uint32_t sdp_event_query_service_record_handle_get_record_handle(const uint8_t *event) + { + return little_endian_read_32(event, 6); + } + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event GATT_EVENT_QUERY_COMPLETE + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t gatt_event_query_complete_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field status from event GATT_EVENT_QUERY_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t gatt_event_query_complete_get_status(const uint8_t *event) + { + return event[4]; + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event GATT_EVENT_SERVICE_QUERY_RESULT + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t gatt_event_service_query_result_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field service from event GATT_EVENT_SERVICE_QUERY_RESULT + * @param event packet + * @param Pointer to storage for service + * @note: btstack_type X + */ + static inline void gatt_event_service_query_result_get_service(const uint8_t *event, gatt_client_service_t *service) + { + gatt_client_deserialize_service(event, 4, service); + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event GATT_EVENT_CHARACTERISTIC_QUERY_RESULT + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t gatt_event_characteristic_query_result_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field characteristic from event GATT_EVENT_CHARACTERISTIC_QUERY_RESULT + * @param event packet + * @param Pointer to storage for characteristic + * @note: btstack_type Y + */ + static inline void gatt_event_characteristic_query_result_get_characteristic(const uint8_t *event, gatt_client_characteristic_t *characteristic) + { + gatt_client_deserialize_characteristic(event, 4, characteristic); + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event GATT_EVENT_INCLUDED_SERVICE_QUERY_RESULT + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t gatt_event_included_service_query_result_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field include_handle from event GATT_EVENT_INCLUDED_SERVICE_QUERY_RESULT + * @param event packet + * @return include_handle + * @note: btstack_type 2 + */ + static inline uint16_t gatt_event_included_service_query_result_get_include_handle(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field service from event GATT_EVENT_INCLUDED_SERVICE_QUERY_RESULT + * @param event packet + * @param Pointer to storage for service + * @note: btstack_type X + */ + static inline void gatt_event_included_service_query_result_get_service(const uint8_t *event, gatt_client_service_t *service) + { + gatt_client_deserialize_service(event, 6, service); + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t gatt_event_all_characteristic_descriptors_query_result_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field characteristic_descriptor from event GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT + * @param event packet + * @param Pointer to storage for characteristic_descriptor + * @note: btstack_type Z + */ + static inline void gatt_event_all_characteristic_descriptors_query_result_get_characteristic_descriptor(const uint8_t *event, gatt_client_characteristic_descriptor_t *characteristic_descriptor) + { + gatt_client_deserialize_characteristic_descriptor(event, 4, characteristic_descriptor); + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t gatt_event_characteristic_value_query_result_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field value_handle from event GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT + * @param event packet + * @return value_handle + * @note: btstack_type 2 + */ + static inline uint16_t gatt_event_characteristic_value_query_result_get_value_handle(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field value_length from event GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT + * @param event packet + * @return value_length + * @note: btstack_type L + */ + static inline int gatt_event_characteristic_value_query_result_get_value_length(const uint8_t *event) + { + return little_endian_read_16(event, 6); + } + /** + * @brief Get field value from event GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT + * @param event packet + * @return value + * @note: btstack_type V + */ + static inline const uint8_t *gatt_event_characteristic_value_query_result_get_value(const uint8_t *event) + { + return &event[8]; + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t gatt_event_long_characteristic_value_query_result_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field value_handle from event GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT + * @param event packet + * @return value_handle + * @note: btstack_type 2 + */ + static inline uint16_t gatt_event_long_characteristic_value_query_result_get_value_handle(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field value_offset from event GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT + * @param event packet + * @return value_offset + * @note: btstack_type 2 + */ + static inline uint16_t gatt_event_long_characteristic_value_query_result_get_value_offset(const uint8_t *event) + { + return little_endian_read_16(event, 6); + } + /** + * @brief Get field value_length from event GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT + * @param event packet + * @return value_length + * @note: btstack_type L + */ + static inline int gatt_event_long_characteristic_value_query_result_get_value_length(const uint8_t *event) + { + return little_endian_read_16(event, 8); + } + /** + * @brief Get field value from event GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT + * @param event packet + * @return value + * @note: btstack_type V + */ + static inline const uint8_t *gatt_event_long_characteristic_value_query_result_get_value(const uint8_t *event) + { + return &event[10]; + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event GATT_EVENT_NOTIFICATION + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t gatt_event_notification_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field value_handle from event GATT_EVENT_NOTIFICATION + * @param event packet + * @return value_handle + * @note: btstack_type 2 + */ + static inline uint16_t gatt_event_notification_get_value_handle(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field value_length from event GATT_EVENT_NOTIFICATION + * @param event packet + * @return value_length + * @note: btstack_type L + */ + static inline int gatt_event_notification_get_value_length(const uint8_t *event) + { + return little_endian_read_16(event, 6); + } + /** + * @brief Get field value from event GATT_EVENT_NOTIFICATION + * @param event packet + * @return value + * @note: btstack_type V + */ + static inline const uint8_t *gatt_event_notification_get_value(const uint8_t *event) + { + return &event[8]; + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event GATT_EVENT_INDICATION + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t gatt_event_indication_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field value_handle from event GATT_EVENT_INDICATION + * @param event packet + * @return value_handle + * @note: btstack_type 2 + */ + static inline uint16_t gatt_event_indication_get_value_handle(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field value_length from event GATT_EVENT_INDICATION + * @param event packet + * @return value_length + * @note: btstack_type L + */ + static inline int gatt_event_indication_get_value_length(const uint8_t *event) + { + return little_endian_read_16(event, 6); + } + /** + * @brief Get field value from event GATT_EVENT_INDICATION + * @param event packet + * @return value + * @note: btstack_type V + */ + static inline const uint8_t *gatt_event_indication_get_value(const uint8_t *event) + { + return &event[8]; + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t gatt_event_characteristic_descriptor_query_result_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field descriptor_handle from event GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT + * @param event packet + * @return descriptor_handle + * @note: btstack_type 2 + */ + static inline uint16_t gatt_event_characteristic_descriptor_query_result_get_descriptor_handle(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field descriptor_length from event GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT + * @param event packet + * @return descriptor_length + * @note: btstack_type L + */ + static inline int gatt_event_characteristic_descriptor_query_result_get_descriptor_length(const uint8_t *event) + { + return little_endian_read_16(event, 6); + } + /** + * @brief Get field descriptor from event GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT + * @param event packet + * @return descriptor + * @note: btstack_type V + */ + static inline const uint8_t *gatt_event_characteristic_descriptor_query_result_get_descriptor(const uint8_t *event) + { + return &event[8]; + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event GATT_EVENT_LONG_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t gatt_event_long_characteristic_descriptor_query_result_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field descriptor_offset from event GATT_EVENT_LONG_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT + * @param event packet + * @return descriptor_offset + * @note: btstack_type 2 + */ + static inline uint16_t gatt_event_long_characteristic_descriptor_query_result_get_descriptor_offset(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field descriptor_length from event GATT_EVENT_LONG_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT + * @param event packet + * @return descriptor_length + * @note: btstack_type L + */ + static inline int gatt_event_long_characteristic_descriptor_query_result_get_descriptor_length(const uint8_t *event) + { + return little_endian_read_16(event, 6); + } + /** + * @brief Get field descriptor from event GATT_EVENT_LONG_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT + * @param event packet + * @return descriptor + * @note: btstack_type V + */ + static inline const uint8_t *gatt_event_long_characteristic_descriptor_query_result_get_descriptor(const uint8_t *event) + { + return &event[8]; + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event GATT_EVENT_MTU + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t gatt_event_mtu_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field MTU from event GATT_EVENT_MTU + * @param event packet + * @return MTU + * @note: btstack_type 2 + */ + static inline uint16_t gatt_event_mtu_get_MTU(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } +#endif + + /** + * @brief Get field handle from event ATT_EVENT_MTU_EXCHANGE_COMPLETE + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t att_event_mtu_exchange_complete_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field MTU from event ATT_EVENT_MTU_EXCHANGE_COMPLETE + * @param event packet + * @return MTU + * @note: btstack_type 2 + */ + static inline uint16_t att_event_mtu_exchange_complete_get_MTU(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + + /** + * @brief Get field status from event ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t att_event_handle_value_indication_complete_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field conn_handle from event ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE + * @param event packet + * @return conn_handle + * @note: btstack_type H + */ + static inline hci_con_handle_t att_event_handle_value_indication_complete_get_conn_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field attribute_handle from event ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE + * @param event packet + * @return attribute_handle + * @note: btstack_type 2 + */ + static inline uint16_t att_event_handle_value_indication_complete_get_attribute_handle(const uint8_t *event) + { + return little_endian_read_16(event, 5); + } + + + /** + * @brief Get field status from event BNEP_EVENT_SERVICE_REGISTERED + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t bnep_event_service_registered_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field service_uuid from event BNEP_EVENT_SERVICE_REGISTERED + * @param event packet + * @return service_uuid + * @note: btstack_type 2 + */ + static inline uint16_t bnep_event_service_registered_get_service_uuid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + + /** + * @brief Get field status from event BNEP_EVENT_CHANNEL_OPENED + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t bnep_event_channel_opened_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field bnep_cid from event BNEP_EVENT_CHANNEL_OPENED + * @param event packet + * @return bnep_cid + * @note: btstack_type 2 + */ + static inline uint16_t bnep_event_channel_opened_get_bnep_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field source_uuid from event BNEP_EVENT_CHANNEL_OPENED + * @param event packet + * @return source_uuid + * @note: btstack_type 2 + */ + static inline uint16_t bnep_event_channel_opened_get_source_uuid(const uint8_t *event) + { + return little_endian_read_16(event, 5); + } + /** + * @brief Get field destination_uuid from event BNEP_EVENT_CHANNEL_OPENED + * @param event packet + * @return destination_uuid + * @note: btstack_type 2 + */ + static inline uint16_t bnep_event_channel_opened_get_destination_uuid(const uint8_t *event) + { + return little_endian_read_16(event, 7); + } + /** + * @brief Get field mtu from event BNEP_EVENT_CHANNEL_OPENED + * @param event packet + * @return mtu + * @note: btstack_type 2 + */ + static inline uint16_t bnep_event_channel_opened_get_mtu(const uint8_t *event) + { + return little_endian_read_16(event, 9); + } + /** + * @brief Get field remote_address from event BNEP_EVENT_CHANNEL_OPENED + * @param event packet + * @param Pointer to storage for remote_address + * @note: btstack_type B + */ + static inline void bnep_event_channel_opened_get_remote_address(const uint8_t *event, bd_addr_t remote_address) + { + reverse_bd_addr(&event[11], remote_address); + } + + /** + * @brief Get field bnep_cid from event BNEP_EVENT_CHANNEL_CLOSED + * @param event packet + * @return bnep_cid + * @note: btstack_type 2 + */ + static inline uint16_t bnep_event_channel_closed_get_bnep_cid(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field source_uuid from event BNEP_EVENT_CHANNEL_CLOSED + * @param event packet + * @return source_uuid + * @note: btstack_type 2 + */ + static inline uint16_t bnep_event_channel_closed_get_source_uuid(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field destination_uuid from event BNEP_EVENT_CHANNEL_CLOSED + * @param event packet + * @return destination_uuid + * @note: btstack_type 2 + */ + static inline uint16_t bnep_event_channel_closed_get_destination_uuid(const uint8_t *event) + { + return little_endian_read_16(event, 6); + } + /** + * @brief Get field remote_address from event BNEP_EVENT_CHANNEL_CLOSED + * @param event packet + * @param Pointer to storage for remote_address + * @note: btstack_type B + */ + static inline void bnep_event_channel_closed_get_remote_address(const uint8_t *event, bd_addr_t remote_address) + { + reverse_bd_addr(&event[8], remote_address); + } + + /** + * @brief Get field bnep_cid from event BNEP_EVENT_CHANNEL_TIMEOUT + * @param event packet + * @return bnep_cid + * @note: btstack_type 2 + */ + static inline uint16_t bnep_event_channel_timeout_get_bnep_cid(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field source_uuid from event BNEP_EVENT_CHANNEL_TIMEOUT + * @param event packet + * @return source_uuid + * @note: btstack_type 2 + */ + static inline uint16_t bnep_event_channel_timeout_get_source_uuid(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field destination_uuid from event BNEP_EVENT_CHANNEL_TIMEOUT + * @param event packet + * @return destination_uuid + * @note: btstack_type 2 + */ + static inline uint16_t bnep_event_channel_timeout_get_destination_uuid(const uint8_t *event) + { + return little_endian_read_16(event, 6); + } + /** + * @brief Get field remote_address from event BNEP_EVENT_CHANNEL_TIMEOUT + * @param event packet + * @param Pointer to storage for remote_address + * @note: btstack_type B + */ + static inline void bnep_event_channel_timeout_get_remote_address(const uint8_t *event, bd_addr_t remote_address) + { + reverse_bd_addr(&event[8], remote_address); + } + /** + * @brief Get field channel_state from event BNEP_EVENT_CHANNEL_TIMEOUT + * @param event packet + * @return channel_state + * @note: btstack_type 1 + */ + static inline uint8_t bnep_event_channel_timeout_get_channel_state(const uint8_t *event) + { + return event[14]; + } + + /** + * @brief Get field bnep_cid from event BNEP_EVENT_CAN_SEND_NOW + * @param event packet + * @return bnep_cid + * @note: btstack_type 2 + */ + static inline uint16_t bnep_event_can_send_now_get_bnep_cid(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field source_uuid from event BNEP_EVENT_CAN_SEND_NOW + * @param event packet + * @return source_uuid + * @note: btstack_type 2 + */ + static inline uint16_t bnep_event_can_send_now_get_source_uuid(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field destination_uuid from event BNEP_EVENT_CAN_SEND_NOW + * @param event packet + * @return destination_uuid + * @note: btstack_type 2 + */ + static inline uint16_t bnep_event_can_send_now_get_destination_uuid(const uint8_t *event) + { + return little_endian_read_16(event, 6); + } + /** + * @brief Get field remote_address from event BNEP_EVENT_CAN_SEND_NOW + * @param event packet + * @param Pointer to storage for remote_address + * @note: btstack_type B + */ + static inline void bnep_event_can_send_now_get_remote_address(const uint8_t *event, bd_addr_t remote_address) + { + reverse_bd_addr(&event[8], remote_address); + } + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event SM_EVENT_JUST_WORKS_REQUEST + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t sm_event_just_works_request_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field addr_type from event SM_EVENT_JUST_WORKS_REQUEST + * @param event packet + * @return addr_type + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_just_works_request_get_addr_type(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field address from event SM_EVENT_JUST_WORKS_REQUEST + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void sm_event_just_works_request_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[5], address); + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event SM_EVENT_JUST_WORKS_CANCEL + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t sm_event_just_works_cancel_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field addr_type from event SM_EVENT_JUST_WORKS_CANCEL + * @param event packet + * @return addr_type + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_just_works_cancel_get_addr_type(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field address from event SM_EVENT_JUST_WORKS_CANCEL + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void sm_event_just_works_cancel_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[5], address); + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event SM_EVENT_PASSKEY_DISPLAY_NUMBER + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t sm_event_passkey_display_number_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field addr_type from event SM_EVENT_PASSKEY_DISPLAY_NUMBER + * @param event packet + * @return addr_type + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_passkey_display_number_get_addr_type(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field address from event SM_EVENT_PASSKEY_DISPLAY_NUMBER + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void sm_event_passkey_display_number_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[5], address); + } + /** + * @brief Get field passkey from event SM_EVENT_PASSKEY_DISPLAY_NUMBER + * @param event packet + * @return passkey + * @note: btstack_type 4 + */ + static inline uint32_t sm_event_passkey_display_number_get_passkey(const uint8_t *event) + { + return little_endian_read_32(event, 11); + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event SM_EVENT_PASSKEY_DISPLAY_CANCEL + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t sm_event_passkey_display_cancel_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field addr_type from event SM_EVENT_PASSKEY_DISPLAY_CANCEL + * @param event packet + * @return addr_type + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_passkey_display_cancel_get_addr_type(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field address from event SM_EVENT_PASSKEY_DISPLAY_CANCEL + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void sm_event_passkey_display_cancel_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[5], address); + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event SM_EVENT_PASSKEY_INPUT_NUMBER + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t sm_event_passkey_input_number_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field addr_type from event SM_EVENT_PASSKEY_INPUT_NUMBER + * @param event packet + * @return addr_type + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_passkey_input_number_get_addr_type(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field address from event SM_EVENT_PASSKEY_INPUT_NUMBER + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void sm_event_passkey_input_number_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[5], address); + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event SM_EVENT_PASSKEY_INPUT_CANCEL + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t sm_event_passkey_input_cancel_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field addr_type from event SM_EVENT_PASSKEY_INPUT_CANCEL + * @param event packet + * @return addr_type + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_passkey_input_cancel_get_addr_type(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field address from event SM_EVENT_PASSKEY_INPUT_CANCEL + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void sm_event_passkey_input_cancel_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[5], address); + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event SM_EVENT_NUMERIC_COMPARISON_REQUEST + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t sm_event_numeric_comparison_request_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field addr_type from event SM_EVENT_NUMERIC_COMPARISON_REQUEST + * @param event packet + * @return addr_type + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_numeric_comparison_request_get_addr_type(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field address from event SM_EVENT_NUMERIC_COMPARISON_REQUEST + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void sm_event_numeric_comparison_request_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[5], address); + } + /** + * @brief Get field passkey from event SM_EVENT_NUMERIC_COMPARISON_REQUEST + * @param event packet + * @return passkey + * @note: btstack_type 4 + */ + static inline uint32_t sm_event_numeric_comparison_request_get_passkey(const uint8_t *event) + { + return little_endian_read_32(event, 11); + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event SM_EVENT_NUMERIC_COMPARISON_CANCEL + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t sm_event_numeric_comparison_cancel_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field addr_type from event SM_EVENT_NUMERIC_COMPARISON_CANCEL + * @param event packet + * @return addr_type + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_numeric_comparison_cancel_get_addr_type(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field address from event SM_EVENT_NUMERIC_COMPARISON_CANCEL + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void sm_event_numeric_comparison_cancel_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[5], address); + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event SM_EVENT_IDENTITY_RESOLVING_STARTED + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t sm_event_identity_resolving_started_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field addr_type from event SM_EVENT_IDENTITY_RESOLVING_STARTED + * @param event packet + * @return addr_type + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_identity_resolving_started_get_addr_type(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field address from event SM_EVENT_IDENTITY_RESOLVING_STARTED + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void sm_event_identity_resolving_started_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[5], address); + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event SM_EVENT_IDENTITY_RESOLVING_FAILED + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t sm_event_identity_resolving_failed_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field addr_type from event SM_EVENT_IDENTITY_RESOLVING_FAILED + * @param event packet + * @return addr_type + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_identity_resolving_failed_get_addr_type(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field address from event SM_EVENT_IDENTITY_RESOLVING_FAILED + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void sm_event_identity_resolving_failed_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[5], address); + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t sm_event_identity_resolving_succeeded_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field addr_type from event SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED + * @param event packet + * @return addr_type + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_identity_resolving_succeeded_get_addr_type(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field address from event SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void sm_event_identity_resolving_succeeded_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[5], address); + } + /** + * @brief Get field identity_addr_type from event SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED + * @param event packet + * @return identity_addr_type + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_identity_resolving_succeeded_get_identity_addr_type(const uint8_t *event) + { + return event[11]; + } + /** + * @brief Get field identity_address from event SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED + * @param event packet + * @param Pointer to storage for identity_address + * @note: btstack_type B + */ + static inline void sm_event_identity_resolving_succeeded_get_identity_address(const uint8_t *event, bd_addr_t identity_address) + { + reverse_bd_addr(&event[12], identity_address); + } + /** + * @brief Get field index_internal from event SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED + * @param event packet + * @return index_internal + * @note: btstack_type 2 + */ + static inline uint16_t sm_event_identity_resolving_succeeded_get_index_internal(const uint8_t *event) + { + return little_endian_read_16(event, 18); + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event SM_EVENT_AUTHORIZATION_REQUEST + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t sm_event_authorization_request_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field addr_type from event SM_EVENT_AUTHORIZATION_REQUEST + * @param event packet + * @return addr_type + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_authorization_request_get_addr_type(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field address from event SM_EVENT_AUTHORIZATION_REQUEST + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void sm_event_authorization_request_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[5], address); + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event SM_EVENT_AUTHORIZATION_RESULT + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t sm_event_authorization_result_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field addr_type from event SM_EVENT_AUTHORIZATION_RESULT + * @param event packet + * @return addr_type + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_authorization_result_get_addr_type(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field address from event SM_EVENT_AUTHORIZATION_RESULT + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void sm_event_authorization_result_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[5], address); + } + /** + * @brief Get field authorization_result from event SM_EVENT_AUTHORIZATION_RESULT + * @param event packet + * @return authorization_result + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_authorization_result_get_authorization_result(const uint8_t *event) + { + return event[11]; + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event SM_EVENT_KEYPRESS_NOTIFICATION + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t sm_event_keypress_notification_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field action from event SM_EVENT_KEYPRESS_NOTIFICATION + * @param event packet + * @return action + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_keypress_notification_get_action(const uint8_t *event) + { + return event[4]; + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event SM_EVENT_IDENTITY_CREATED + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t sm_event_identity_created_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field addr_type from event SM_EVENT_IDENTITY_CREATED + * @param event packet + * @return addr_type + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_identity_created_get_addr_type(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field address from event SM_EVENT_IDENTITY_CREATED + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void sm_event_identity_created_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[5], address); + } + /** + * @brief Get field identity_addr_type from event SM_EVENT_IDENTITY_CREATED + * @param event packet + * @return identity_addr_type + * @note: btstack_type 1 + */ + static inline uint8_t sm_event_identity_created_get_identity_addr_type(const uint8_t *event) + { + return event[11]; + } + /** + * @brief Get field identity_address from event SM_EVENT_IDENTITY_CREATED + * @param event packet + * @param Pointer to storage for identity_address + * @note: btstack_type B + */ + static inline void sm_event_identity_created_get_identity_address(const uint8_t *event, bd_addr_t identity_address) + { + reverse_bd_addr(&event[12], identity_address); + } +#endif + + /** + * @brief Get field handle from event GAP_EVENT_SECURITY_LEVEL + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t gap_event_security_level_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 2); + } + /** + * @brief Get field security_level from event GAP_EVENT_SECURITY_LEVEL + * @param event packet + * @return security_level + * @note: btstack_type 1 + */ + static inline uint8_t gap_event_security_level_get_security_level(const uint8_t *event) + { + return event[4]; + } + + /** + * @brief Get field status from event GAP_EVENT_DEDICATED_BONDING_COMPLETED + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t gap_event_dedicated_bonding_completed_get_status(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field address from event GAP_EVENT_DEDICATED_BONDING_COMPLETED + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void gap_event_dedicated_bonding_completed_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[3], address); + } + + /** + * @brief Get field advertising_event_type from event GAP_EVENT_ADVERTISING_REPORT + * @param event packet + * @return advertising_event_type + * @note: btstack_type 1 + */ + static inline uint8_t gap_event_advertising_report_get_advertising_event_type(const uint8_t *event) + { + return event[2]; + } + /** + * @brief Get field address_type from event GAP_EVENT_ADVERTISING_REPORT + * @param event packet + * @return address_type + * @note: btstack_type 1 + */ + static inline uint8_t gap_event_advertising_report_get_address_type(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field address from event GAP_EVENT_ADVERTISING_REPORT + * @param event packet + * @param Pointer to storage for address + * @note: btstack_type B + */ + static inline void gap_event_advertising_report_get_address(const uint8_t *event, bd_addr_t address) + { + reverse_bd_addr(&event[4], address); + } + /** + * @brief Get field rssi from event GAP_EVENT_ADVERTISING_REPORT + * @param event packet + * @return rssi + * @note: btstack_type 1 + */ + static inline uint8_t gap_event_advertising_report_get_rssi(const uint8_t *event) + { + return event[10]; + } + /** + * @brief Get field data_length from event GAP_EVENT_ADVERTISING_REPORT + * @param event packet + * @return data_length + * @note: btstack_type J + */ + static inline int gap_event_advertising_report_get_data_length(const uint8_t *event) + { + return event[11]; + } + /** + * @brief Get field data from event GAP_EVENT_ADVERTISING_REPORT + * @param event packet + * @return data + * @note: btstack_type V + */ + static inline const uint8_t *gap_event_advertising_report_get_data(const uint8_t *event) + { + return &event[12]; + } + + /** + * @brief Get field bd_addr from event GAP_EVENT_INQUIRY_RESULT + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void gap_event_inquiry_result_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[2], bd_addr); + } + /** + * @brief Get field page_scan_repetition_mode from event GAP_EVENT_INQUIRY_RESULT + * @param event packet + * @return page_scan_repetition_mode + * @note: btstack_type 1 + */ + static inline uint8_t gap_event_inquiry_result_get_page_scan_repetition_mode(const uint8_t *event) + { + return event[8]; + } + /** + * @brief Get field class_of_device from event GAP_EVENT_INQUIRY_RESULT + * @param event packet + * @return class_of_device + * @note: btstack_type 3 + */ + static inline uint32_t gap_event_inquiry_result_get_class_of_device(const uint8_t *event) + { + return little_endian_read_24(event, 9); + } + /** + * @brief Get field clock_offset from event GAP_EVENT_INQUIRY_RESULT + * @param event packet + * @return clock_offset + * @note: btstack_type 2 + */ + static inline uint16_t gap_event_inquiry_result_get_clock_offset(const uint8_t *event) + { + return little_endian_read_16(event, 12); + } + /** + * @brief Get field rssi_available from event GAP_EVENT_INQUIRY_RESULT + * @param event packet + * @return rssi_available + * @note: btstack_type 1 + */ + static inline uint8_t gap_event_inquiry_result_get_rssi_available(const uint8_t *event) + { + return event[14]; + } + /** + * @brief Get field rssi from event GAP_EVENT_INQUIRY_RESULT + * @param event packet + * @return rssi + * @note: btstack_type 1 + */ + static inline uint8_t gap_event_inquiry_result_get_rssi(const uint8_t *event) + { + return event[15]; + } + /** + * @brief Get field name_available from event GAP_EVENT_INQUIRY_RESULT + * @param event packet + * @return name_available + * @note: btstack_type 1 + */ + static inline uint8_t gap_event_inquiry_result_get_name_available(const uint8_t *event) + { + return event[16]; + } + /** + * @brief Get field name_len from event GAP_EVENT_INQUIRY_RESULT + * @param event packet + * @return name_len + * @note: btstack_type J + */ + static inline int gap_event_inquiry_result_get_name_len(const uint8_t *event) + { + return event[17]; + } + /** + * @brief Get field name from event GAP_EVENT_INQUIRY_RESULT + * @param event packet + * @return name + * @note: btstack_type V + */ + static inline const uint8_t *gap_event_inquiry_result_get_name(const uint8_t *event) + { + return &event[18]; + } + + /** + * @brief Get field status from event GAP_EVENT_INQUIRY_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t gap_event_inquiry_complete_get_status(const uint8_t *event) + { + return event[2]; + } + + /** + * @brief Get field status from event HCI_SUBEVENT_LE_CONNECTION_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_subevent_le_connection_complete_get_status(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field connection_handle from event HCI_SUBEVENT_LE_CONNECTION_COMPLETE + * @param event packet + * @return connection_handle + * @note: btstack_type H + */ + static inline hci_con_handle_t hci_subevent_le_connection_complete_get_connection_handle(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field role from event HCI_SUBEVENT_LE_CONNECTION_COMPLETE + * @param event packet + * @return role + * @note: btstack_type 1 + */ + static inline uint8_t hci_subevent_le_connection_complete_get_role(const uint8_t *event) + { + return event[6]; + } + /** + * @brief Get field peer_address_type from event HCI_SUBEVENT_LE_CONNECTION_COMPLETE + * @param event packet + * @return peer_address_type + * @note: btstack_type 1 + */ + static inline uint8_t hci_subevent_le_connection_complete_get_peer_address_type(const uint8_t *event) + { + return event[7]; + } + /** + * @brief Get field peer_address from event HCI_SUBEVENT_LE_CONNECTION_COMPLETE + * @param event packet + * @param Pointer to storage for peer_address + * @note: btstack_type B + */ + static inline void hci_subevent_le_connection_complete_get_peer_address(const uint8_t *event, bd_addr_t peer_address) + { + reverse_bd_addr(&event[8], peer_address); + } + /** + * @brief Get field conn_interval from event HCI_SUBEVENT_LE_CONNECTION_COMPLETE + * @param event packet + * @return conn_interval + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_connection_complete_get_conn_interval(const uint8_t *event) + { + return little_endian_read_16(event, 14); + } + /** + * @brief Get field conn_latency from event HCI_SUBEVENT_LE_CONNECTION_COMPLETE + * @param event packet + * @return conn_latency + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_connection_complete_get_conn_latency(const uint8_t *event) + { + return little_endian_read_16(event, 16); + } + /** + * @brief Get field supervision_timeout from event HCI_SUBEVENT_LE_CONNECTION_COMPLETE + * @param event packet + * @return supervision_timeout + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_connection_complete_get_supervision_timeout(const uint8_t *event) + { + return little_endian_read_16(event, 18); + } + /** + * @brief Get field master_clock_accuracy from event HCI_SUBEVENT_LE_CONNECTION_COMPLETE + * @param event packet + * @return master_clock_accuracy + * @note: btstack_type 1 + */ + static inline uint8_t hci_subevent_le_connection_complete_get_master_clock_accuracy(const uint8_t *event) + { + return event[20]; + } + + /** + * @brief Get field status from event HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_subevent_le_connection_update_complete_get_status(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field connection_handle from event HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE + * @param event packet + * @return connection_handle + * @note: btstack_type H + */ + static inline hci_con_handle_t hci_subevent_le_connection_update_complete_get_connection_handle(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field conn_interval from event HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE + * @param event packet + * @return conn_interval + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_connection_update_complete_get_conn_interval(const uint8_t *event) + { + return little_endian_read_16(event, 6); + } + /** + * @brief Get field conn_latency from event HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE + * @param event packet + * @return conn_latency + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_connection_update_complete_get_conn_latency(const uint8_t *event) + { + return little_endian_read_16(event, 8); + } + /** + * @brief Get field supervision_timeout from event HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE + * @param event packet + * @return supervision_timeout + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_connection_update_complete_get_supervision_timeout(const uint8_t *event) + { + return little_endian_read_16(event, 10); + } + + /** + * @brief Get field connection_handle from event HCI_SUBEVENT_LE_READ_REMOTE_USED_FEATURES_COMPLETE + * @param event packet + * @return connection_handle + * @note: btstack_type H + */ + static inline hci_con_handle_t hci_subevent_le_read_remote_used_features_complete_get_connection_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field random_number from event HCI_SUBEVENT_LE_READ_REMOTE_USED_FEATURES_COMPLETE + * @param event packet + * @return random_number + * @note: btstack_type D + */ + static inline const uint8_t *hci_subevent_le_read_remote_used_features_complete_get_random_number(const uint8_t *event) + { + return (const uint8_t *) &event[5]; + } + /** + * @brief Get field encryption_diversifier from event HCI_SUBEVENT_LE_READ_REMOTE_USED_FEATURES_COMPLETE + * @param event packet + * @return encryption_diversifier + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_read_remote_used_features_complete_get_encryption_diversifier(const uint8_t *event) + { + return little_endian_read_16(event, 13); + } + + /** + * @brief Get field connection_handle from event HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST + * @param event packet + * @return connection_handle + * @note: btstack_type H + */ + static inline hci_con_handle_t hci_subevent_le_long_term_key_request_get_connection_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field random_number from event HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST + * @param event packet + * @return random_number + * @note: btstack_type D + */ + static inline const uint8_t *hci_subevent_le_long_term_key_request_get_random_number(const uint8_t *event) + { + return (const uint8_t *) &event[5]; + } + /** + * @brief Get field encryption_diversifier from event HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST + * @param event packet + * @return encryption_diversifier + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_long_term_key_request_get_encryption_diversifier(const uint8_t *event) + { + return little_endian_read_16(event, 13); + } + + /** + * @brief Get field connection_handle from event HCI_SUBEVENT_LE_REMOTE_CONNECTION_PARAMETER_REQUEST + * @param event packet + * @return connection_handle + * @note: btstack_type H + */ + static inline hci_con_handle_t hci_subevent_le_remote_connection_parameter_request_get_connection_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field interval_min from event HCI_SUBEVENT_LE_REMOTE_CONNECTION_PARAMETER_REQUEST + * @param event packet + * @return interval_min + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_remote_connection_parameter_request_get_interval_min(const uint8_t *event) + { + return little_endian_read_16(event, 5); + } + /** + * @brief Get field interval_max from event HCI_SUBEVENT_LE_REMOTE_CONNECTION_PARAMETER_REQUEST + * @param event packet + * @return interval_max + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_remote_connection_parameter_request_get_interval_max(const uint8_t *event) + { + return little_endian_read_16(event, 7); + } + /** + * @brief Get field latency from event HCI_SUBEVENT_LE_REMOTE_CONNECTION_PARAMETER_REQUEST + * @param event packet + * @return latency + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_remote_connection_parameter_request_get_latency(const uint8_t *event) + { + return little_endian_read_16(event, 9); + } + /** + * @brief Get field timeout from event HCI_SUBEVENT_LE_REMOTE_CONNECTION_PARAMETER_REQUEST + * @param event packet + * @return timeout + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_remote_connection_parameter_request_get_timeout(const uint8_t *event) + { + return little_endian_read_16(event, 11); + } + + /** + * @brief Get field connection_handle from event HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE + * @param event packet + * @return connection_handle + * @note: btstack_type H + */ + static inline hci_con_handle_t hci_subevent_le_data_length_change_get_connection_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field max_tx_octets from event HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE + * @param event packet + * @return max_tx_octets + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_data_length_change_get_max_tx_octets(const uint8_t *event) + { + return little_endian_read_16(event, 5); + } + /** + * @brief Get field max_tx_time from event HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE + * @param event packet + * @return max_tx_time + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_data_length_change_get_max_tx_time(const uint8_t *event) + { + return little_endian_read_16(event, 7); + } + /** + * @brief Get field max_rx_octets from event HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE + * @param event packet + * @return max_rx_octets + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_data_length_change_get_max_rx_octets(const uint8_t *event) + { + return little_endian_read_16(event, 9); + } + /** + * @brief Get field max_rx_time from event HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE + * @param event packet + * @return max_rx_time + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_data_length_change_get_max_rx_time(const uint8_t *event) + { + return little_endian_read_16(event, 11); + } + + /** + * @brief Get field status from event HCI_SUBEVENT_LE_READ_LOCAL_P256_PUBLIC_KEY_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_subevent_le_read_local_p256_public_key_complete_get_status(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field dhkey_x from event HCI_SUBEVENT_LE_READ_LOCAL_P256_PUBLIC_KEY_COMPLETE + * @param event packet + * @param Pointer to storage for dhkey_x + * @note: btstack_type Q + */ + static inline void hci_subevent_le_read_local_p256_public_key_complete_get_dhkey_x(const uint8_t *event, uint8_t *dhkey_x) + { + reverse_bytes(&event[4], dhkey_x, 32); + } + /** + * @brief Get field dhkey_y from event HCI_SUBEVENT_LE_READ_LOCAL_P256_PUBLIC_KEY_COMPLETE + * @param event packet + * @param Pointer to storage for dhkey_y + * @note: btstack_type Q + */ + static inline void hci_subevent_le_read_local_p256_public_key_complete_get_dhkey_y(const uint8_t *event, uint8_t *dhkey_y) + { + reverse_bytes(&event[36], dhkey_y, 32); + } + + /** + * @brief Get field status from event HCI_SUBEVENT_LE_GENERATE_DHKEY_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_subevent_le_generate_dhkey_complete_get_status(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field dhkey from event HCI_SUBEVENT_LE_GENERATE_DHKEY_COMPLETE + * @param event packet + * @param Pointer to storage for dhkey + * @note: btstack_type Q + */ + static inline void hci_subevent_le_generate_dhkey_complete_get_dhkey(const uint8_t *event, uint8_t *dhkey) + { + reverse_bytes(&event[4], dhkey, 32); + } + + /** + * @brief Get field status from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hci_subevent_le_enhanced_connection_complete_get_status(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field connection_handle from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @return connection_handle + * @note: btstack_type H + */ + static inline hci_con_handle_t hci_subevent_le_enhanced_connection_complete_get_connection_handle(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field role from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @return role + * @note: btstack_type 1 + */ + static inline uint8_t hci_subevent_le_enhanced_connection_complete_get_role(const uint8_t *event) + { + return event[6]; + } + /** + * @brief Get field peer_address_type from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @return peer_address_type + * @note: btstack_type 1 + */ + static inline uint8_t hci_subevent_le_enhanced_connection_complete_get_peer_address_type(const uint8_t *event) + { + return event[7]; + } + /** + * @brief Get field perr_addresss from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @param Pointer to storage for perr_addresss + * @note: btstack_type B + */ + static inline void hci_subevent_le_enhanced_connection_complete_get_peer_addresss(const uint8_t *event, bd_addr_t perr_addresss) + { + reverse_bd_addr(&event[8], perr_addresss); + } + static inline uint8_t *hci_subevent_le_enhanced_connection_complete_get_peer_addresss_ptr(const uint8_t *event) + { + return (uint8_t *)&event[8]; + } + /** + * @brief Get field local_resolvable_private_addres from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @param Pointer to storage for local_resolvable_private_addres + * @note: btstack_type B + */ + static inline void hci_subevent_le_enhanced_connection_complete_get_local_resolvable_private_addres(const uint8_t *event, bd_addr_t local_resolvable_private_addres) + { + reverse_bd_addr(&event[14], local_resolvable_private_addres); + } + /** + * @brief Get field peer_resolvable_private_addres from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @param Pointer to storage for peer_resolvable_private_addres + * @note: btstack_type B + */ + static inline void hci_subevent_le_enhanced_connection_complete_get_peer_resolvable_private_addres(const uint8_t *event, bd_addr_t peer_resolvable_private_addres) + { + reverse_bd_addr(&event[20], peer_resolvable_private_addres); + } + /** + * @brief Get field conn_interval from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @return conn_interval + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_enhanced_connection_complete_get_conn_interval(const uint8_t *event) + { + return little_endian_read_16(event, 26); + } + /** + * @brief Get field conn_latency from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @return conn_latency + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_enhanced_connection_complete_get_conn_latency(const uint8_t *event) + { + return little_endian_read_16(event, 28); + } + /** + * @brief Get field supervision_timeout from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @return supervision_timeout + * @note: btstack_type 2 + */ + static inline uint16_t hci_subevent_le_enhanced_connection_complete_get_supervision_timeout(const uint8_t *event) + { + return little_endian_read_16(event, 30); + } + /** + * @brief Get field master_clock_accuracy from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @return master_clock_accuracy + * @note: btstack_type 1 + */ + static inline uint8_t hci_subevent_le_enhanced_connection_complete_get_master_clock_accuracy(const uint8_t *event) + { + return event[32]; + } + + /** + * @brief Get field status from event HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hsp_subevent_rfcomm_connection_complete_get_status(const uint8_t *event) + { + return event[3]; + } + + /** + * @brief Get field status from event HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hsp_subevent_rfcomm_disconnection_complete_get_status(const uint8_t *event) + { + return event[3]; + } + + /** + * @brief Get field status from event HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hsp_subevent_audio_connection_complete_get_status(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field handle from event HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t hsp_subevent_audio_connection_complete_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + + /** + * @brief Get field status from event HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hsp_subevent_audio_disconnection_complete_get_status(const uint8_t *event) + { + return event[3]; + } + + + /** + * @brief Get field gain from event HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED + * @param event packet + * @return gain + * @note: btstack_type 1 + */ + static inline uint8_t hsp_subevent_microphone_gain_changed_get_gain(const uint8_t *event) + { + return event[3]; + } + + /** + * @brief Get field gain from event HSP_SUBEVENT_SPEAKER_GAIN_CHANGED + * @param event packet + * @return gain + * @note: btstack_type 1 + */ + static inline uint8_t hsp_subevent_speaker_gain_changed_get_gain(const uint8_t *event) + { + return event[3]; + } + + /** + * @brief Get field value_length from event HSP_SUBEVENT_HS_COMMAND + * @param event packet + * @return value_length + * @note: btstack_type J + */ + static inline int hsp_subevent_hs_command_get_value_length(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field value from event HSP_SUBEVENT_HS_COMMAND + * @param event packet + * @return value + * @note: btstack_type V + */ + static inline const uint8_t *hsp_subevent_hs_command_get_value(const uint8_t *event) + { + return &event[4]; + } + + /** + * @brief Get field value_length from event HSP_SUBEVENT_AG_INDICATION + * @param event packet + * @return value_length + * @note: btstack_type J + */ + static inline int hsp_subevent_ag_indication_get_value_length(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field value from event HSP_SUBEVENT_AG_INDICATION + * @param event packet + * @return value + * @note: btstack_type V + */ + static inline const uint8_t *hsp_subevent_ag_indication_get_value(const uint8_t *event) + { + return &event[4]; + } + + /** + * @brief Get field status from event HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_service_level_connection_established_get_status(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field con_handle from event HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED + * @param event packet + * @return con_handle + * @note: btstack_type H + */ + static inline hci_con_handle_t hfp_subevent_service_level_connection_established_get_con_handle(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field bd_addr from event HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void hfp_subevent_service_level_connection_established_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[6], bd_addr); + } + + + /** + * @brief Get field status from event HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_audio_connection_established_get_status(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field handle from event HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t hfp_subevent_audio_connection_established_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 4); + } + /** + * @brief Get field bd_addr from event HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void hfp_subevent_audio_connection_established_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[6], bd_addr); + } + /** + * @brief Get field negotiated_codec from event HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED + * @param event packet + * @return negotiated_codec + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_audio_connection_established_get_negotiated_codec(const uint8_t *event) + { + return event[12]; + } + + + /** + * @brief Get field status from event HFP_SUBEVENT_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_complete_get_status(const uint8_t *event) + { + return event[3]; + } + + /** + * @brief Get field indicator_index from event HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED + * @param event packet + * @return indicator_index + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_ag_indicator_status_changed_get_indicator_index(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field indicator_status from event HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED + * @param event packet + * @return indicator_status + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_ag_indicator_status_changed_get_indicator_status(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field indicator_name from event HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED + * @param event packet + * @return indicator_name + * @note: btstack_type T + */ + static inline const char *hfp_subevent_ag_indicator_status_changed_get_indicator_name(const uint8_t *event) + { + return (const char *) &event[5]; + } + + /** + * @brief Get field network_operator_mode from event HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED + * @param event packet + * @return network_operator_mode + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_network_operator_changed_get_network_operator_mode(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field network_operator_format from event HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED + * @param event packet + * @return network_operator_format + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_network_operator_changed_get_network_operator_format(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field network_operator_name from event HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED + * @param event packet + * @return network_operator_name + * @note: btstack_type T + */ + static inline const char *hfp_subevent_network_operator_changed_get_network_operator_name(const uint8_t *event) + { + return (const char *) &event[5]; + } + + /** + * @brief Get field error from event HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR + * @param event packet + * @return error + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_extended_audio_gateway_error_get_error(const uint8_t *event) + { + return event[3]; + } + + + + + /** + * @brief Get field number from event HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER + * @param event packet + * @return number + * @note: btstack_type T + */ + static inline const char *hfp_subevent_place_call_with_number_get_number(const uint8_t *event) + { + return (const char *) &event[3]; + } + + + /** + * @brief Get field number from event HFP_SUBEVENT_NUMBER_FOR_VOICE_TAG + * @param event packet + * @return number + * @note: btstack_type T + */ + static inline const char *hfp_subevent_number_for_voice_tag_get_number(const uint8_t *event) + { + return (const char *) &event[3]; + } + + /** + * @brief Get field dtmf from event HFP_SUBEVENT_TRANSMIT_DTMF_CODES + * @param event packet + * @return dtmf + * @note: btstack_type T + */ + static inline const char *hfp_subevent_transmit_dtmf_codes_get_dtmf(const uint8_t *event) + { + return (const char *) &event[3]; + } + + + + + /** + * @brief Get field status from event HFP_SUBEVENT_SPEAKER_VOLUME + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_speaker_volume_get_status(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field gain from event HFP_SUBEVENT_SPEAKER_VOLUME + * @param event packet + * @return gain + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_speaker_volume_get_gain(const uint8_t *event) + { + return event[4]; + } + + /** + * @brief Get field status from event HFP_SUBEVENT_MICROPHONE_VOLUME + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_microphone_volume_get_status(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field gain from event HFP_SUBEVENT_MICROPHONE_VOLUME + * @param event packet + * @return gain + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_microphone_volume_get_gain(const uint8_t *event) + { + return event[4]; + } + + /** + * @brief Get field type from event HFP_SUBEVENT_CALL_WAITING_NOTIFICATION + * @param event packet + * @return type + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_call_waiting_notification_get_type(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field number from event HFP_SUBEVENT_CALL_WAITING_NOTIFICATION + * @param event packet + * @return number + * @note: btstack_type T + */ + static inline const char *hfp_subevent_call_waiting_notification_get_number(const uint8_t *event) + { + return (const char *) &event[4]; + } + + /** + * @brief Get field type from event HFP_SUBEVENT_CALLING_LINE_IDENTIFICATION_NOTIFICATION + * @param event packet + * @return type + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_calling_line_identification_notification_get_type(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field number from event HFP_SUBEVENT_CALLING_LINE_IDENTIFICATION_NOTIFICATION + * @param event packet + * @return number + * @note: btstack_type T + */ + static inline const char *hfp_subevent_calling_line_identification_notification_get_number(const uint8_t *event) + { + return (const char *) &event[4]; + } + + /** + * @brief Get field clcc_idx from event HFP_SUBEVENT_ENHANCED_CALL_STATUS + * @param event packet + * @return clcc_idx + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_enhanced_call_status_get_clcc_idx(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field clcc_dir from event HFP_SUBEVENT_ENHANCED_CALL_STATUS + * @param event packet + * @return clcc_dir + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_enhanced_call_status_get_clcc_dir(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field clcc_status from event HFP_SUBEVENT_ENHANCED_CALL_STATUS + * @param event packet + * @return clcc_status + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_enhanced_call_status_get_clcc_status(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field clcc_mpty from event HFP_SUBEVENT_ENHANCED_CALL_STATUS + * @param event packet + * @return clcc_mpty + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_enhanced_call_status_get_clcc_mpty(const uint8_t *event) + { + return event[6]; + } + /** + * @brief Get field bnip_type from event HFP_SUBEVENT_ENHANCED_CALL_STATUS + * @param event packet + * @return bnip_type + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_enhanced_call_status_get_bnip_type(const uint8_t *event) + { + return event[7]; + } + /** + * @brief Get field bnip_number from event HFP_SUBEVENT_ENHANCED_CALL_STATUS + * @param event packet + * @return bnip_number + * @note: btstack_type T + */ + static inline const char *hfp_subevent_enhanced_call_status_get_bnip_number(const uint8_t *event) + { + return (const char *) &event[8]; + } + + /** + * @brief Get field status from event HFP_SUBEVENT_SUBSCRIBER_NUMBER_INFORMATION + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_subscriber_number_information_get_status(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field bnip_type from event HFP_SUBEVENT_SUBSCRIBER_NUMBER_INFORMATION + * @param event packet + * @return bnip_type + * @note: btstack_type 1 + */ + static inline uint8_t hfp_subevent_subscriber_number_information_get_bnip_type(const uint8_t *event) + { + return event[4]; + } + /** + * @brief Get field bnip_number from event HFP_SUBEVENT_SUBSCRIBER_NUMBER_INFORMATION + * @param event packet + * @return bnip_number + * @note: btstack_type T + */ + static inline const char *hfp_subevent_subscriber_number_information_get_bnip_number(const uint8_t *event) + { + return (const char *) &event[5]; + } + + /** + * @brief Get field value from event HFP_SUBEVENT_RESPONSE_AND_HOLD_STATUS + * @param event packet + * @return value + * @note: btstack_type T + */ + static inline const char *hfp_subevent_response_and_hold_status_get_value(const uint8_t *event) + { + return (const char *) &event[3]; + } + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event ANCS_SUBEVENT_CLIENT_CONNECTED + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t ancs_subevent_client_connected_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event ANCS_SUBEVENT_CLIENT_NOTIFICATION + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t ancs_subevent_client_notification_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field attribute_id from event ANCS_SUBEVENT_CLIENT_NOTIFICATION + * @param event packet + * @return attribute_id + * @note: btstack_type 2 + */ + static inline uint16_t ancs_subevent_client_notification_get_attribute_id(const uint8_t *event) + { + return little_endian_read_16(event, 5); + } + /** + * @brief Get field text from event ANCS_SUBEVENT_CLIENT_NOTIFICATION + * @param event packet + * @return text + * @note: btstack_type T + */ + static inline const char *ancs_subevent_client_notification_get_text(const uint8_t *event) + { + return (const char *) &event[7]; + } +#endif + +#ifdef ENABLE_BLE + /** + * @brief Get field handle from event ANCS_SUBEVENT_CLIENT_DISCONNECTED + * @param event packet + * @return handle + * @note: btstack_type H + */ + static inline hci_con_handle_t ancs_subevent_client_disconnected_get_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } +#endif + + /** + * @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_ACCEPT + * @param event packet + * @return avdtp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avdtp_subevent_signaling_accept_get_avdtp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field local_seid from event AVDTP_SUBEVENT_SIGNALING_ACCEPT + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_accept_get_local_seid(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field signal_identifier from event AVDTP_SUBEVENT_SIGNALING_ACCEPT + * @param event packet + * @return signal_identifier + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_accept_get_signal_identifier(const uint8_t *event) + { + return event[6]; + } + + /** + * @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_REJECT + * @param event packet + * @return avdtp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avdtp_subevent_signaling_reject_get_avdtp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field local_seid from event AVDTP_SUBEVENT_SIGNALING_REJECT + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_reject_get_local_seid(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field signal_identifier from event AVDTP_SUBEVENT_SIGNALING_REJECT + * @param event packet + * @return signal_identifier + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_reject_get_signal_identifier(const uint8_t *event) + { + return event[6]; + } + + /** + * @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT + * @param event packet + * @return avdtp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avdtp_subevent_signaling_general_reject_get_avdtp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field local_seid from event AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_general_reject_get_local_seid(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field signal_identifier from event AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT + * @param event packet + * @return signal_identifier + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_general_reject_get_signal_identifier(const uint8_t *event) + { + return event[6]; + } + + /** + * @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED + * @param event packet + * @return avdtp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avdtp_subevent_signaling_connection_established_get_avdtp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field bd_addr from event AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void avdtp_subevent_signaling_connection_established_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[5], bd_addr); + } + /** + * @brief Get field status from event AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_connection_established_get_status(const uint8_t *event) + { + return event[11]; + } + + /** + * @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_CONNECTION_RELEASED + * @param event packet + * @return avdtp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avdtp_subevent_signaling_connection_released_get_avdtp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + + /** + * @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_SEP_FOUND + * @param event packet + * @return avdtp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avdtp_subevent_signaling_sep_found_get_avdtp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field remote_seid from event AVDTP_SUBEVENT_SIGNALING_SEP_FOUND + * @param event packet + * @return remote_seid + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_sep_found_get_remote_seid(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field in_use from event AVDTP_SUBEVENT_SIGNALING_SEP_FOUND + * @param event packet + * @return in_use + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_sep_found_get_in_use(const uint8_t *event) + { + return event[6]; + } + /** + * @brief Get field media_type from event AVDTP_SUBEVENT_SIGNALING_SEP_FOUND + * @param event packet + * @return media_type + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_sep_found_get_media_type(const uint8_t *event) + { + return event[7]; + } + /** + * @brief Get field sep_type from event AVDTP_SUBEVENT_SIGNALING_SEP_FOUND + * @param event packet + * @return sep_type + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_sep_found_get_sep_type(const uint8_t *event) + { + return event[8]; + } + + /** + * @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY + * @param event packet + * @return avdtp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avdtp_subevent_signaling_media_codec_sbc_capability_get_avdtp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field local_seid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_local_seid(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field remote_seid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY + * @param event packet + * @return remote_seid + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_remote_seid(const uint8_t *event) + { + return event[6]; + } + /** + * @brief Get field media_type from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY + * @param event packet + * @return media_type + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_media_type(const uint8_t *event) + { + return event[7]; + } + /** + * @brief Get field sampling_frequency_bitmap from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY + * @param event packet + * @return sampling_frequency_bitmap + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_sampling_frequency_bitmap(const uint8_t *event) + { + return event[8]; + } + /** + * @brief Get field channel_mode_bitmap from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY + * @param event packet + * @return channel_mode_bitmap + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_channel_mode_bitmap(const uint8_t *event) + { + return event[9]; + } + /** + * @brief Get field block_length_bitmap from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY + * @param event packet + * @return block_length_bitmap + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_block_length_bitmap(const uint8_t *event) + { + return event[10]; + } + /** + * @brief Get field subbands_bitmap from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY + * @param event packet + * @return subbands_bitmap + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_subbands_bitmap(const uint8_t *event) + { + return event[11]; + } + /** + * @brief Get field allocation_method_bitmap from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY + * @param event packet + * @return allocation_method_bitmap + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_allocation_method_bitmap(const uint8_t *event) + { + return event[12]; + } + /** + * @brief Get field min_bitpool_value from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY + * @param event packet + * @return min_bitpool_value + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_min_bitpool_value(const uint8_t *event) + { + return event[13]; + } + /** + * @brief Get field max_bitpool_value from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY + * @param event packet + * @return max_bitpool_value + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_max_bitpool_value(const uint8_t *event) + { + return event[14]; + } + + /** + * @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY + * @param event packet + * @return avdtp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avdtp_subevent_signaling_media_codec_other_capability_get_avdtp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field local_seid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_other_capability_get_local_seid(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field remote_seid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY + * @param event packet + * @return remote_seid + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_other_capability_get_remote_seid(const uint8_t *event) + { + return event[6]; + } + /** + * @brief Get field media_type from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY + * @param event packet + * @return media_type + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_other_capability_get_media_type(const uint8_t *event) + { + return event[7]; + } + /** + * @brief Get field media_codec_type from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY + * @param event packet + * @return media_codec_type + * @note: btstack_type 2 + */ + static inline uint16_t avdtp_subevent_signaling_media_codec_other_capability_get_media_codec_type(const uint8_t *event) + { + return little_endian_read_16(event, 8); + } + /** + * @brief Get field media_codec_information_len from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY + * @param event packet + * @return media_codec_information_len + * @note: btstack_type L + */ + static inline int avdtp_subevent_signaling_media_codec_other_capability_get_media_codec_information_len(const uint8_t *event) + { + return little_endian_read_16(event, 10); + } + /** + * @brief Get field media_codec_information from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY + * @param event packet + * @return media_codec_information + * @note: btstack_type V + */ + static inline const uint8_t *avdtp_subevent_signaling_media_codec_other_capability_get_media_codec_information(const uint8_t *event) + { + return &event[12]; + } + + /** + * @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return avdtp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_avdtp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field local_seid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_local_seid(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field remote_seid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return remote_seid + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_remote_seid(const uint8_t *event) + { + return event[6]; + } + /** + * @brief Get field reconfigure from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return reconfigure + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_reconfigure(const uint8_t *event) + { + return event[7]; + } + /** + * @brief Get field media_type from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return media_type + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_media_type(const uint8_t *event) + { + return event[8]; + } + /** + * @brief Get field sampling_frequency from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return sampling_frequency + * @note: btstack_type 2 + */ + static inline uint16_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(const uint8_t *event) + { + return little_endian_read_16(event, 9); + } + /** + * @brief Get field channel_mode from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return channel_mode + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_channel_mode(const uint8_t *event) + { + return event[11]; + } + /** + * @brief Get field num_channels from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return num_channels + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_num_channels(const uint8_t *event) + { + return event[12]; + } + /** + * @brief Get field block_length from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return block_length + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_block_length(const uint8_t *event) + { + return event[13]; + } + /** + * @brief Get field subbands from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return subbands + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_subbands(const uint8_t *event) + { + return event[14]; + } + /** + * @brief Get field allocation_method from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return allocation_method + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_allocation_method(const uint8_t *event) + { + return event[15]; + } + /** + * @brief Get field min_bitpool_value from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return min_bitpool_value + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_min_bitpool_value(const uint8_t *event) + { + return event[16]; + } + /** + * @brief Get field max_bitpool_value from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return max_bitpool_value + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(const uint8_t *event) + { + return event[17]; + } + + /** + * @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return avdtp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avdtp_subevent_signaling_media_codec_other_configuration_get_avdtp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field local_seid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_other_configuration_get_local_seid(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field remote_seid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return remote_seid + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_other_configuration_get_remote_seid(const uint8_t *event) + { + return event[6]; + } + /** + * @brief Get field reconfigure from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return reconfigure + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_other_configuration_get_reconfigure(const uint8_t *event) + { + return event[7]; + } + /** + * @brief Get field media_type from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return media_type + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_signaling_media_codec_other_configuration_get_media_type(const uint8_t *event) + { + return event[8]; + } + /** + * @brief Get field media_codec_type from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return media_codec_type + * @note: btstack_type 2 + */ + static inline uint16_t avdtp_subevent_signaling_media_codec_other_configuration_get_media_codec_type(const uint8_t *event) + { + return little_endian_read_16(event, 9); + } + /** + * @brief Get field media_codec_information_len from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return media_codec_information_len + * @note: btstack_type L + */ + static inline int avdtp_subevent_signaling_media_codec_other_configuration_get_media_codec_information_len(const uint8_t *event) + { + return little_endian_read_16(event, 11); + } + /** + * @brief Get field media_codec_information from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return media_codec_information + * @note: btstack_type V + */ + static inline const uint8_t *avdtp_subevent_signaling_media_codec_other_configuration_get_media_codec_information(const uint8_t *event) + { + return &event[13]; + } + + /** + * @brief Get field avdtp_cid from event AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED + * @param event packet + * @return avdtp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avdtp_subevent_streaming_connection_established_get_avdtp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field bd_addr from event AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void avdtp_subevent_streaming_connection_established_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[5], bd_addr); + } + /** + * @brief Get field local_seid from event AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_streaming_connection_established_get_local_seid(const uint8_t *event) + { + return event[11]; + } + /** + * @brief Get field remote_seid from event AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED + * @param event packet + * @return remote_seid + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_streaming_connection_established_get_remote_seid(const uint8_t *event) + { + return event[12]; + } + /** + * @brief Get field status from event AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_streaming_connection_established_get_status(const uint8_t *event) + { + return event[13]; + } + + /** + * @brief Get field avdtp_cid from event AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED + * @param event packet + * @return avdtp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avdtp_subevent_streaming_connection_released_get_avdtp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field local_seid from event AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_streaming_connection_released_get_local_seid(const uint8_t *event) + { + return event[5]; + } + + /** + * @brief Get field avdtp_cid from event AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW + * @param event packet + * @return avdtp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avdtp_subevent_streaming_can_send_media_packet_now_get_avdtp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field local_seid from event AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t avdtp_subevent_streaming_can_send_media_packet_now_get_local_seid(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field sequence_number from event AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW + * @param event packet + * @return sequence_number + * @note: btstack_type 2 + */ + static inline uint16_t avdtp_subevent_streaming_can_send_media_packet_now_get_sequence_number(const uint8_t *event) + { + return little_endian_read_16(event, 6); + } + + /** + * @brief Get field a2dp_cid from event A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW + * @param event packet + * @return a2dp_cid + * @note: btstack_type 2 + */ + static inline uint16_t a2dp_subevent_streaming_can_send_media_packet_now_get_a2dp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field local_seid from event A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_streaming_can_send_media_packet_now_get_local_seid(const uint8_t *event) + { + return event[5]; + } + + /** + * @brief Get field a2dp_cid from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return a2dp_cid + * @note: btstack_type 2 + */ + static inline uint16_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_a2dp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field int_seid from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return int_seid + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_int_seid(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field acp_seid from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return acp_seid + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_acp_seid(const uint8_t *event) + { + return event[6]; + } + /** + * @brief Get field reconfigure from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return reconfigure + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_reconfigure(const uint8_t *event) + { + return event[7]; + } + /** + * @brief Get field media_type from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return media_type + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_media_type(const uint8_t *event) + { + return event[8]; + } + /** + * @brief Get field sampling_frequency from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return sampling_frequency + * @note: btstack_type 2 + */ + static inline uint16_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(const uint8_t *event) + { + return little_endian_read_16(event, 9); + } + /** + * @brief Get field channel_mode from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return channel_mode + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_channel_mode(const uint8_t *event) + { + return event[11]; + } + /** + * @brief Get field num_channels from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return num_channels + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_num_channels(const uint8_t *event) + { + return event[12]; + } + /** + * @brief Get field block_length from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return block_length + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_block_length(const uint8_t *event) + { + return event[13]; + } + /** + * @brief Get field subbands from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return subbands + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_subbands(const uint8_t *event) + { + return event[14]; + } + /** + * @brief Get field allocation_method from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return allocation_method + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_allocation_method(const uint8_t *event) + { + return event[15]; + } + /** + * @brief Get field min_bitpool_value from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return min_bitpool_value + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_min_bitpool_value(const uint8_t *event) + { + return event[16]; + } + /** + * @brief Get field max_bitpool_value from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return max_bitpool_value + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(const uint8_t *event) + { + return event[17]; + } + + /** + * @brief Get field a2dp_cid from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return a2dp_cid + * @note: btstack_type 2 + */ + static inline uint16_t a2dp_subevent_signaling_media_codec_other_configuration_get_a2dp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field int_seid from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return int_seid + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_signaling_media_codec_other_configuration_get_int_seid(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field acp_seid from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return acp_seid + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_signaling_media_codec_other_configuration_get_acp_seid(const uint8_t *event) + { + return event[6]; + } + /** + * @brief Get field reconfigure from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return reconfigure + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_signaling_media_codec_other_configuration_get_reconfigure(const uint8_t *event) + { + return event[7]; + } + /** + * @brief Get field media_type from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return media_type + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_signaling_media_codec_other_configuration_get_media_type(const uint8_t *event) + { + return event[8]; + } + /** + * @brief Get field media_codec_type from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return media_codec_type + * @note: btstack_type 2 + */ + static inline uint16_t a2dp_subevent_signaling_media_codec_other_configuration_get_media_codec_type(const uint8_t *event) + { + return little_endian_read_16(event, 9); + } + /** + * @brief Get field media_codec_information_len from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return media_codec_information_len + * @note: btstack_type L + */ + static inline int a2dp_subevent_signaling_media_codec_other_configuration_get_media_codec_information_len(const uint8_t *event) + { + return little_endian_read_16(event, 11); + } + /** + * @brief Get field media_codec_information from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return media_codec_information + * @note: btstack_type V + */ + static inline const uint8_t *a2dp_subevent_signaling_media_codec_other_configuration_get_media_codec_information(const uint8_t *event) + { + return &event[13]; + } + + /** + * @brief Get field a2dp_cid from event A2DP_SUBEVENT_STREAM_ESTABLISHED + * @param event packet + * @return a2dp_cid + * @note: btstack_type 2 + */ + static inline uint16_t a2dp_subevent_stream_established_get_a2dp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field bd_addr from event A2DP_SUBEVENT_STREAM_ESTABLISHED + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void a2dp_subevent_stream_established_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[5], bd_addr); + } + /** + * @brief Get field local_seid from event A2DP_SUBEVENT_STREAM_ESTABLISHED + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_stream_established_get_local_seid(const uint8_t *event) + { + return event[11]; + } + /** + * @brief Get field remote_seid from event A2DP_SUBEVENT_STREAM_ESTABLISHED + * @param event packet + * @return remote_seid + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_stream_established_get_remote_seid(const uint8_t *event) + { + return event[12]; + } + /** + * @brief Get field status from event A2DP_SUBEVENT_STREAM_ESTABLISHED + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_stream_established_get_status(const uint8_t *event) + { + return event[13]; + } + + /** + * @brief Get field a2dp_cid from event A2DP_SUBEVENT_STREAM_STARTED + * @param event packet + * @return a2dp_cid + * @note: btstack_type 2 + */ + static inline uint16_t a2dp_subevent_stream_started_get_a2dp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field local_seid from event A2DP_SUBEVENT_STREAM_STARTED + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_stream_started_get_local_seid(const uint8_t *event) + { + return event[5]; + } + + /** + * @brief Get field a2dp_cid from event A2DP_SUBEVENT_STREAM_SUSPENDED + * @param event packet + * @return a2dp_cid + * @note: btstack_type 2 + */ + static inline uint16_t a2dp_subevent_stream_suspended_get_a2dp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field local_seid from event A2DP_SUBEVENT_STREAM_SUSPENDED + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_stream_suspended_get_local_seid(const uint8_t *event) + { + return event[5]; + } + + /** + * @brief Get field a2dp_cid from event A2DP_SUBEVENT_STREAM_STOPPED + * @param event packet + * @return a2dp_cid + * @note: btstack_type 2 + */ + static inline uint16_t a2dp_subevent_stream_stopped_get_a2dp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field local_seid from event A2DP_SUBEVENT_STREAM_STOPPED + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_stream_stopped_get_local_seid(const uint8_t *event) + { + return event[5]; + } + + /** + * @brief Get field a2dp_cid from event A2DP_SUBEVENT_STREAM_RELEASED + * @param event packet + * @return a2dp_cid + * @note: btstack_type 2 + */ + static inline uint16_t a2dp_subevent_stream_released_get_a2dp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field local_seid from event A2DP_SUBEVENT_STREAM_RELEASED + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_stream_released_get_local_seid(const uint8_t *event) + { + return event[5]; + } + + /** + * @brief Get field a2dp_cid from event A2DP_SUBEVENT_COMMAND_ACCEPTED + * @param event packet + * @return a2dp_cid + * @note: btstack_type 2 + */ + static inline uint16_t a2dp_subevent_command_accepted_get_a2dp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field local_seid from event A2DP_SUBEVENT_COMMAND_ACCEPTED + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_command_accepted_get_local_seid(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field signal_identifier from event A2DP_SUBEVENT_COMMAND_ACCEPTED + * @param event packet + * @return signal_identifier + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_command_accepted_get_signal_identifier(const uint8_t *event) + { + return event[6]; + } + + /** + * @brief Get field a2dp_cid from event A2DP_SUBEVENT_COMMAND_REJECTED + * @param event packet + * @return a2dp_cid + * @note: btstack_type 2 + */ + static inline uint16_t a2dp_subevent_command_rejected_get_a2dp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field local_seid from event A2DP_SUBEVENT_COMMAND_REJECTED + * @param event packet + * @return local_seid + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_command_rejected_get_local_seid(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field signal_identifier from event A2DP_SUBEVENT_COMMAND_REJECTED + * @param event packet + * @return signal_identifier + * @note: btstack_type 1 + */ + static inline uint8_t a2dp_subevent_command_rejected_get_signal_identifier(const uint8_t *event) + { + return event[6]; + } + + /** + * @brief Get field a2dp_cid from event A2DP_SUBEVENT_INCOMING_CONNECTION_ESTABLISHED + * @param event packet + * @return a2dp_cid + * @note: btstack_type 2 + */ + static inline uint16_t a2dp_subevent_incoming_connection_established_get_a2dp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field bd_addr from event A2DP_SUBEVENT_INCOMING_CONNECTION_ESTABLISHED + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void a2dp_subevent_incoming_connection_established_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[5], bd_addr); + } + + /** + * @brief Get field a2dp_cid from event A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED + * @param event packet + * @return a2dp_cid + * @note: btstack_type 2 + */ + static inline uint16_t a2dp_subevent_signaling_connection_released_get_a2dp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + + /** + * @brief Get field status from event AVRCP_SUBEVENT_CONNECTION_ESTABLISHED + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_connection_established_get_status(const uint8_t *event) + { + return event[3]; + } + /** + * @brief Get field bd_addr from event AVRCP_SUBEVENT_CONNECTION_ESTABLISHED + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void avrcp_subevent_connection_established_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[4], bd_addr); + } + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_CONNECTION_ESTABLISHED + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_connection_established_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 10); + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_CONNECTION_RELEASED + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_connection_released_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_SHUFFLE_AND_REPEAT_MODE + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_shuffle_and_repeat_mode_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_SHUFFLE_AND_REPEAT_MODE + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_shuffle_and_repeat_mode_get_command_type(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field repeat_mode from event AVRCP_SUBEVENT_SHUFFLE_AND_REPEAT_MODE + * @param event packet + * @return repeat_mode + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_shuffle_and_repeat_mode_get_repeat_mode(const uint8_t *event) + { + return event[6]; + } + /** + * @brief Get field shuffle_mode from event AVRCP_SUBEVENT_SHUFFLE_AND_REPEAT_MODE + * @param event packet + * @return shuffle_mode + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_shuffle_and_repeat_mode_get_shuffle_mode(const uint8_t *event) + { + return event[7]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_PLAY_STATUS + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_play_status_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_PLAY_STATUS + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_play_status_get_command_type(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field song_length from event AVRCP_SUBEVENT_PLAY_STATUS + * @param event packet + * @return song_length + * @note: btstack_type 4 + */ + static inline uint32_t avrcp_subevent_play_status_get_song_length(const uint8_t *event) + { + return little_endian_read_32(event, 6); + } + /** + * @brief Get field song_position from event AVRCP_SUBEVENT_PLAY_STATUS + * @param event packet + * @return song_position + * @note: btstack_type 4 + */ + static inline uint32_t avrcp_subevent_play_status_get_song_position(const uint8_t *event) + { + return little_endian_read_32(event, 10); + } + /** + * @brief Get field play_status from event AVRCP_SUBEVENT_PLAY_STATUS + * @param event packet + * @return play_status + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_play_status_get_play_status(const uint8_t *event) + { + return event[14]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_NOTIFICATION_PLAYBACK_STATUS_CHANGED + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_notification_playback_status_changed_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_NOTIFICATION_PLAYBACK_STATUS_CHANGED + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_notification_playback_status_changed_get_command_type(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field play_status from event AVRCP_SUBEVENT_NOTIFICATION_PLAYBACK_STATUS_CHANGED + * @param event packet + * @return play_status + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_notification_playback_status_changed_get_play_status(const uint8_t *event) + { + return event[6]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_NOTIFICATION_TRACK_CHANGED + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_notification_track_changed_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_NOTIFICATION_TRACK_CHANGED + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_notification_track_changed_get_command_type(const uint8_t *event) + { + return event[5]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_NOTIFICATION_NOW_PLAYING_CONTENT_CHANGED + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_notification_now_playing_content_changed_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_NOTIFICATION_NOW_PLAYING_CONTENT_CHANGED + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_notification_now_playing_content_changed_get_command_type(const uint8_t *event) + { + return event[5]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_NOTIFICATION_AVAILABLE_PLAYERS_CHANGED + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_notification_available_players_changed_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_NOTIFICATION_AVAILABLE_PLAYERS_CHANGED + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_notification_available_players_changed_get_command_type(const uint8_t *event) + { + return event[5]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_NOTIFICATION_VOLUME_CHANGED + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_notification_volume_changed_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_NOTIFICATION_VOLUME_CHANGED + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_notification_volume_changed_get_command_type(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field absolute_volume from event AVRCP_SUBEVENT_NOTIFICATION_VOLUME_CHANGED + * @param event packet + * @return absolute_volume + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_notification_volume_changed_get_absolute_volume(const uint8_t *event) + { + return event[6]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_SET_ABSOLUTE_VOLUME_RESPONSE + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_set_absolute_volume_response_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_SET_ABSOLUTE_VOLUME_RESPONSE + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_set_absolute_volume_response_get_command_type(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field absolute_volume from event AVRCP_SUBEVENT_SET_ABSOLUTE_VOLUME_RESPONSE + * @param event packet + * @return absolute_volume + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_set_absolute_volume_response_get_absolute_volume(const uint8_t *event) + { + return event[6]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_ENABLE_NOTIFICATION_COMPLETE + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_enable_notification_complete_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_ENABLE_NOTIFICATION_COMPLETE + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_enable_notification_complete_get_command_type(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field notification_id from event AVRCP_SUBEVENT_ENABLE_NOTIFICATION_COMPLETE + * @param event packet + * @return notification_id + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_enable_notification_complete_get_notification_id(const uint8_t *event) + { + return event[6]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_OPERATION_START + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_operation_start_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_OPERATION_START + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_operation_start_get_command_type(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field operation_id from event AVRCP_SUBEVENT_OPERATION_START + * @param event packet + * @return operation_id + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_operation_start_get_operation_id(const uint8_t *event) + { + return event[6]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_OPERATION_COMPLETE + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_operation_complete_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_OPERATION_COMPLETE + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_operation_complete_get_command_type(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field operation_id from event AVRCP_SUBEVENT_OPERATION_COMPLETE + * @param event packet + * @return operation_id + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_operation_complete_get_operation_id(const uint8_t *event) + { + return event[6]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_PLAYER_APPLICATION_VALUE_RESPONSE + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_player_application_value_response_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_PLAYER_APPLICATION_VALUE_RESPONSE + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_player_application_value_response_get_command_type(const uint8_t *event) + { + return event[5]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_COMPANY_IDS_QUERY + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_company_ids_query_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_EVENT_IDS_QUERY + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_event_ids_query_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_PLAY_STATUS_QUERY + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_play_status_query_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_OPERATION + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_operation_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field operation_id from event AVRCP_SUBEVENT_OPERATION + * @param event packet + * @return operation_id + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_operation_get_operation_id(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field operands_length from event AVRCP_SUBEVENT_OPERATION + * @param event packet + * @return operands_length + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_operation_get_operands_length(const uint8_t *event) + { + return event[6]; + } + /** + * @brief Get field operand from event AVRCP_SUBEVENT_OPERATION + * @param event packet + * @return operand + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_operation_get_operand(const uint8_t *event) + { + return event[7]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_NOW_PLAYING_TRACK_INFO + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_now_playing_track_info_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_NOW_PLAYING_TRACK_INFO + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_now_playing_track_info_get_command_type(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field track from event AVRCP_SUBEVENT_NOW_PLAYING_TRACK_INFO + * @param event packet + * @return track + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_now_playing_track_info_get_track(const uint8_t *event) + { + return event[6]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_NOW_PLAYING_TOTAL_TRACKS_INFO + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_now_playing_total_tracks_info_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_NOW_PLAYING_TOTAL_TRACKS_INFO + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_now_playing_total_tracks_info_get_command_type(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field total_tracks from event AVRCP_SUBEVENT_NOW_PLAYING_TOTAL_TRACKS_INFO + * @param event packet + * @return total_tracks + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_now_playing_total_tracks_info_get_total_tracks(const uint8_t *event) + { + return event[6]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_NOW_PLAYING_SONG_LENGTH_MS_INFO + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_now_playing_song_length_ms_info_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_NOW_PLAYING_SONG_LENGTH_MS_INFO + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_now_playing_song_length_ms_info_get_command_type(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field song_length from event AVRCP_SUBEVENT_NOW_PLAYING_SONG_LENGTH_MS_INFO + * @param event packet + * @return song_length + * @note: btstack_type 4 + */ + static inline uint32_t avrcp_subevent_now_playing_song_length_ms_info_get_song_length(const uint8_t *event) + { + return little_endian_read_32(event, 6); + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_NOW_PLAYING_TITLE_INFO + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_now_playing_title_info_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_NOW_PLAYING_TITLE_INFO + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_now_playing_title_info_get_command_type(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field value_len from event AVRCP_SUBEVENT_NOW_PLAYING_TITLE_INFO + * @param event packet + * @return value_len + * @note: btstack_type J + */ + static inline int avrcp_subevent_now_playing_title_info_get_value_len(const uint8_t *event) + { + return event[6]; + } + /** + * @brief Get field value from event AVRCP_SUBEVENT_NOW_PLAYING_TITLE_INFO + * @param event packet + * @return value + * @note: btstack_type V + */ + static inline const uint8_t *avrcp_subevent_now_playing_title_info_get_value(const uint8_t *event) + { + return &event[7]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_NOW_PLAYING_ARTIST_INFO + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_now_playing_artist_info_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_NOW_PLAYING_ARTIST_INFO + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_now_playing_artist_info_get_command_type(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field value_len from event AVRCP_SUBEVENT_NOW_PLAYING_ARTIST_INFO + * @param event packet + * @return value_len + * @note: btstack_type J + */ + static inline int avrcp_subevent_now_playing_artist_info_get_value_len(const uint8_t *event) + { + return event[6]; + } + /** + * @brief Get field value from event AVRCP_SUBEVENT_NOW_PLAYING_ARTIST_INFO + * @param event packet + * @return value + * @note: btstack_type V + */ + static inline const uint8_t *avrcp_subevent_now_playing_artist_info_get_value(const uint8_t *event) + { + return &event[7]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_NOW_PLAYING_ALBUM_INFO + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_now_playing_album_info_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_NOW_PLAYING_ALBUM_INFO + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_now_playing_album_info_get_command_type(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field value_len from event AVRCP_SUBEVENT_NOW_PLAYING_ALBUM_INFO + * @param event packet + * @return value_len + * @note: btstack_type J + */ + static inline int avrcp_subevent_now_playing_album_info_get_value_len(const uint8_t *event) + { + return event[6]; + } + /** + * @brief Get field value from event AVRCP_SUBEVENT_NOW_PLAYING_ALBUM_INFO + * @param event packet + * @return value + * @note: btstack_type V + */ + static inline const uint8_t *avrcp_subevent_now_playing_album_info_get_value(const uint8_t *event) + { + return &event[7]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_NOW_PLAYING_GENRE_INFO + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_now_playing_genre_info_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_NOW_PLAYING_GENRE_INFO + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_now_playing_genre_info_get_command_type(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field value_len from event AVRCP_SUBEVENT_NOW_PLAYING_GENRE_INFO + * @param event packet + * @return value_len + * @note: btstack_type J + */ + static inline int avrcp_subevent_now_playing_genre_info_get_value_len(const uint8_t *event) + { + return event[6]; + } + /** + * @brief Get field value from event AVRCP_SUBEVENT_NOW_PLAYING_GENRE_INFO + * @param event packet + * @return value + * @note: btstack_type V + */ + static inline const uint8_t *avrcp_subevent_now_playing_genre_info_get_value(const uint8_t *event) + { + return &event[7]; + } + + /** + * @brief Get field avrcp_cid from event AVRCP_SUBEVENT_NOW_PLAYING_INFO_DONE + * @param event packet + * @return avrcp_cid + * @note: btstack_type 2 + */ + static inline uint16_t avrcp_subevent_now_playing_info_done_get_avrcp_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field command_type from event AVRCP_SUBEVENT_NOW_PLAYING_INFO_DONE + * @param event packet + * @return command_type + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_now_playing_info_done_get_command_type(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field status from event AVRCP_SUBEVENT_NOW_PLAYING_INFO_DONE + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t avrcp_subevent_now_playing_info_done_get_status(const uint8_t *event) + { + return event[6]; + } + + /** + * @brief Get field goep_cid from event GOEP_SUBEVENT_CONNECTION_OPENED + * @param event packet + * @return goep_cid + * @note: btstack_type 2 + */ + static inline uint16_t goep_subevent_connection_opened_get_goep_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field status from event GOEP_SUBEVENT_CONNECTION_OPENED + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t goep_subevent_connection_opened_get_status(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field bd_addr from event GOEP_SUBEVENT_CONNECTION_OPENED + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void goep_subevent_connection_opened_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[6], bd_addr); + } + /** + * @brief Get field con_handle from event GOEP_SUBEVENT_CONNECTION_OPENED + * @param event packet + * @return con_handle + * @note: btstack_type H + */ + static inline hci_con_handle_t goep_subevent_connection_opened_get_con_handle(const uint8_t *event) + { + return little_endian_read_16(event, 12); + } + /** + * @brief Get field incoming from event GOEP_SUBEVENT_CONNECTION_OPENED + * @param event packet + * @return incoming + * @note: btstack_type 1 + */ + static inline uint8_t goep_subevent_connection_opened_get_incoming(const uint8_t *event) + { + return event[14]; + } + + /** + * @brief Get field goep_cid from event GOEP_SUBEVENT_CONNECTION_CLOSED + * @param event packet + * @return goep_cid + * @note: btstack_type 2 + */ + static inline uint16_t goep_subevent_connection_closed_get_goep_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + + /** + * @brief Get field goep_cid from event GOEP_SUBEVENT_CAN_SEND_NOW + * @param event packet + * @return goep_cid + * @note: btstack_type 2 + */ + static inline uint16_t goep_subevent_can_send_now_get_goep_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + + /** + * @brief Get field pbap_cid from event PBAP_SUBEVENT_CONNECTION_OPENED + * @param event packet + * @return pbap_cid + * @note: btstack_type 2 + */ + static inline uint16_t pbap_subevent_connection_opened_get_pbap_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field status from event PBAP_SUBEVENT_CONNECTION_OPENED + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t pbap_subevent_connection_opened_get_status(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field bd_addr from event PBAP_SUBEVENT_CONNECTION_OPENED + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void pbap_subevent_connection_opened_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[6], bd_addr); + } + /** + * @brief Get field con_handle from event PBAP_SUBEVENT_CONNECTION_OPENED + * @param event packet + * @return con_handle + * @note: btstack_type H + */ + static inline hci_con_handle_t pbap_subevent_connection_opened_get_con_handle(const uint8_t *event) + { + return little_endian_read_16(event, 12); + } + /** + * @brief Get field incoming from event PBAP_SUBEVENT_CONNECTION_OPENED + * @param event packet + * @return incoming + * @note: btstack_type 1 + */ + static inline uint8_t pbap_subevent_connection_opened_get_incoming(const uint8_t *event) + { + return event[14]; + } + + /** + * @brief Get field goep_cid from event PBAP_SUBEVENT_CONNECTION_CLOSED + * @param event packet + * @return goep_cid + * @note: btstack_type 2 + */ + static inline uint16_t pbap_subevent_connection_closed_get_goep_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + + /** + * @brief Get field goep_cid from event PBAP_SUBEVENT_OPERATION_COMPLETED + * @param event packet + * @return goep_cid + * @note: btstack_type 2 + */ + static inline uint16_t pbap_subevent_operation_completed_get_goep_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field status from event PBAP_SUBEVENT_OPERATION_COMPLETED + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t pbap_subevent_operation_completed_get_status(const uint8_t *event) + { + return event[5]; + } + + /** + * @brief Get field hid_cid from event HID_SUBEVENT_CONNECTION_OPENED + * @param event packet + * @return hid_cid + * @note: btstack_type 2 + */ + static inline uint16_t hid_subevent_connection_opened_get_hid_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field status from event HID_SUBEVENT_CONNECTION_OPENED + * @param event packet + * @return status + * @note: btstack_type 1 + */ + static inline uint8_t hid_subevent_connection_opened_get_status(const uint8_t *event) + { + return event[5]; + } + /** + * @brief Get field bd_addr from event HID_SUBEVENT_CONNECTION_OPENED + * @param event packet + * @param Pointer to storage for bd_addr + * @note: btstack_type B + */ + static inline void hid_subevent_connection_opened_get_bd_addr(const uint8_t *event, bd_addr_t bd_addr) + { + reverse_bd_addr(&event[6], bd_addr); + } + /** + * @brief Get field con_handle from event HID_SUBEVENT_CONNECTION_OPENED + * @param event packet + * @return con_handle + * @note: btstack_type H + */ + static inline hci_con_handle_t hid_subevent_connection_opened_get_con_handle(const uint8_t *event) + { + return little_endian_read_16(event, 12); + } + /** + * @brief Get field incoming from event HID_SUBEVENT_CONNECTION_OPENED + * @param event packet + * @return incoming + * @note: btstack_type 1 + */ + static inline uint8_t hid_subevent_connection_opened_get_incoming(const uint8_t *event) + { + return event[14]; + } + + /** + * @brief Get field hid_cid from event HID_SUBEVENT_CONNECTION_CLOSED + * @param event packet + * @return hid_cid + * @note: btstack_type 2 + */ + static inline uint16_t hid_subevent_connection_closed_get_hid_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + + /** + * @brief Get field hid_cid from event HID_SUBEVENT_CAN_SEND_NOW + * @param event packet + * @return hid_cid + * @note: btstack_type 2 + */ + static inline uint16_t hid_subevent_can_send_now_get_hid_cid(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + + /** + * @brief Get field con_handle from event HIDS_SUBEVENT_CAN_SEND_NOW + * @param event packet + * @return con_handle + * @note: btstack_type 2 + */ + static inline uint16_t hids_subevent_can_send_now_get_con_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + + /** + * @brief Get field con_handle from event HIDS_SUBEVENT_PROTOCOL_MODE + * @param event packet + * @return con_handle + * @note: btstack_type 2 + */ + static inline uint16_t hids_subevent_protocol_mode_get_con_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field protocol_mode from event HIDS_SUBEVENT_PROTOCOL_MODE + * @param event packet + * @return protocol_mode + * @note: btstack_type 1 + */ + static inline uint8_t hids_subevent_protocol_mode_get_protocol_mode(const uint8_t *event) + { + return event[5]; + } + + /** + * @brief Get field con_handle from event HIDS_SUBEVENT_BOOT_MOUSE_INPUT_REPORT_ENABLE + * @param event packet + * @return con_handle + * @note: btstack_type 2 + */ + static inline uint16_t hids_subevent_boot_mouse_input_report_enable_get_con_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field enable from event HIDS_SUBEVENT_BOOT_MOUSE_INPUT_REPORT_ENABLE + * @param event packet + * @return enable + * @note: btstack_type 1 + */ + static inline uint8_t hids_subevent_boot_mouse_input_report_enable_get_enable(const uint8_t *event) + { + return event[5]; + } + + /** + * @brief Get field con_handle from event HIDS_SUBEVENT_BOOT_KEYBOARD_INPUT_REPORT_ENABLE + * @param event packet + * @return con_handle + * @note: btstack_type 2 + */ + static inline uint16_t hids_subevent_boot_keyboard_input_report_enable_get_con_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field enable from event HIDS_SUBEVENT_BOOT_KEYBOARD_INPUT_REPORT_ENABLE + * @param event packet + * @return enable + * @note: btstack_type 1 + */ + static inline uint8_t hids_subevent_boot_keyboard_input_report_enable_get_enable(const uint8_t *event) + { + return event[5]; + } + + /** + * @brief Get field con_handle from event HIDS_SUBEVENT_INPUT_REPORT_ENABLE + * @param event packet + * @return con_handle + * @note: btstack_type 2 + */ + static inline uint16_t hids_subevent_input_report_enable_get_con_handle(const uint8_t *event) + { + return little_endian_read_16(event, 3); + } + /** + * @brief Get field enable from event HIDS_SUBEVENT_INPUT_REPORT_ENABLE + * @param event packet + * @return enable + * @note: btstack_type 1 + */ + static inline uint8_t hids_subevent_input_report_enable_get_enable(const uint8_t *event) + { + return event[5]; + } + + + static inline uint8_t hci_event_le_meta_get_phy_update_complete_status(const uint8_t *event) + { + return event[3]; + } + static inline uint8_t hci_event_le_meta_get_phy_update_complete_tx_phy(const uint8_t *event) + { + return event[6]; + } + static inline uint8_t hci_event_le_meta_get_phy_update_complete_rx_phy(const uint8_t *event) + { + return event[7]; + } + + + /* API_END */ + +#if defined __cplusplus +} +#endif + +#endif // __BTSTACK_EVENT_H diff --git a/include_lib/btstack/btstack_lib.ld b/include_lib/btstack/btstack_lib.ld new file mode 100644 index 0000000..3b9c9b0 --- /dev/null +++ b/include_lib/btstack/btstack_lib.ld @@ -0,0 +1,103 @@ +SECTIONS +{ + .data : ALIGN(4) + { + btstack_data_start = .; + *(.bt_stack_data) + *(.ble_db_data) + *(.ble_sm_data) + *(.ble_att_data) + *(.ble_gatt_data) + + /*mesh*/ + 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) + + /*mesh*/ + 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) + + /*mesh*/ + 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); + diff --git a/include_lib/btstack/btstack_task.h b/include_lib/btstack/btstack_task.h new file mode 100644 index 0000000..3f7bd08 --- /dev/null +++ b/include_lib/btstack/btstack_task.h @@ -0,0 +1,9 @@ +#ifndef BTSTACK_TASK_H +#define BTSTACK_TASK_H + +int btstack_init(); +int btstack_exit(); + +void ble_bqb_test_thread_init(void); + +#endif diff --git a/include_lib/btstack/btstack_typedef.h b/include_lib/btstack/btstack_typedef.h new file mode 100644 index 0000000..462e709 --- /dev/null +++ b/include_lib/btstack/btstack_typedef.h @@ -0,0 +1,26 @@ +#ifndef _BTSTACK_TYPEDEF_H_ +#define _BTSTACK_TYPEDEF_H_ + +#include "typedef.h" + +#define BD_ADDR_LEN 6 +typedef uint8_t bd_addr_t[BD_ADDR_LEN]; + +typedef uint16_t hci_con_handle_t; + +typedef int (*sm_stack_packet_handler_t)(uint8_t packet_type, uint8_t *packet, uint16_t size); + +typedef void (*btstack_packet_handler_t)(u8 packet_type, u16 channel, u8 *packet, u16 size); + +typedef void (*ble_cbk_handler_t)(void); + +void reverse_bd_addr(const bd_addr_t src, bd_addr_t dest); + +void reverse_bytes(const u8 *src, u8 *dst, u32 len); + +uint16_t little_endian_read_16(const uint8_t *buffer, int pos); +uint32_t little_endian_read_24(const uint8_t *buffer, int pos); +uint32_t little_endian_read_32(const uint8_t *buffer, int pos); + + +#endif diff --git a/include_lib/btstack/frame_queque.h b/include_lib/btstack/frame_queque.h new file mode 100644 index 0000000..934a3a4 --- /dev/null +++ b/include_lib/btstack/frame_queque.h @@ -0,0 +1,65 @@ +#ifndef __FRAME_QUEQUE_H +#define __FRAME_QUEQUE_H +#include +#include +#include "typedef.h" + + +typedef unsigned char WORD8; +typedef unsigned short int WORD16; +typedef unsigned int WORD32; +typedef unsigned long long WORD64; + +typedef signed char SWORD8; +typedef signed short int SWORD16; +typedef signed int SWORD32; +typedef signed long long SWORD64; + +typedef unsigned char uint8_t; + +#define FRAME_QUEQUE_MUTEX_ID semlock_t +#define FRAME_QUEQUE_MUTEX_DEF semlock_t +#define FRAME_QUEQUE_MUTEX_P(mutex_id) frame_mute_p(mutex_id) +#define FRAME_QUEQUE_MUTEX_V(mutex_id) frame_mute_v(mutex_id) + +typedef enum { + APP_DUEROS_VER, + APP_DUEROS_SEND, + APP_TWS_BLE_SLAVE_SPEECH_START, + APP_SPEECH_START_FROM_TWS, + APP_SPEECH_STOP_FROM_TWS, + APP_TWS_DUEROS_RAND_SET, + APP_TWS_BLE_DUEROS_CONNECT, + APP_TWS_BLE_DUEROS_DISCONNECT, +} APP_CMD_TYPE ; + + +typedef struct { + int counter; +} semlock_t; + +typedef struct send_frame { + void *buffer; + WORD32 len; + struct send_frame *next; +} _GNU_PACKED_ SEND_FRAME; + +typedef struct __frame_queque { + SEND_FRAME *head; + SEND_FRAME *tail; + unsigned int depth; + FRAME_QUEQUE_MUTEX_ID mutex; +} _GNU_PACKED_ FRAME_QUEQUE; + + +int frame_queque_is_empty(FRAME_QUEQUE *queque); +int frame_push_queque(FRAME_QUEQUE *queque, SEND_FRAME *frame); +SEND_FRAME *frame_pop_queque(FRAME_QUEQUE *queque); +SEND_FRAME *frame_pop_queque_alloc(FRAME_QUEQUE *queque); +int frame_queque_clear(FRAME_QUEQUE *queque); +int frame_queque_init(FRAME_QUEQUE *queque); + +void run_loop_register_for_app(); +void app_remove_stack_run(void); + +#endif diff --git a/include_lib/btstack/le/att.h b/include_lib/btstack/le/att.h new file mode 100644 index 0000000..59fbfc6 --- /dev/null +++ b/include_lib/btstack/le/att.h @@ -0,0 +1,147 @@ +/********************************************************************************************* + * Filename : att.h + + * Description : + + * Author : minxian + + * Email : liminxian@zh-jieli.com + + * Last modifiled : 2020-07-01 16:33 + + * Copyright:(c)JIELI 2011-2020 @ , All Rights Reserved. +*********************************************************************************************/ +#ifndef _BT_ATT_H_ +#define _BT_ATT_H_ + +#include "typedef.h" +#include "btstack/btstack_typedef.h" + +#if defined __cplusplus +extern "C" { +#endif + +// Minimum/default MTU +#define ATT_DEFAULT_MTU 23 + +#define ATT_EVENT_MTU_EXCHANGE_COMPLETE 0xB5 +#define ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE 0xB6 +#define ATT_EVENT_CAN_SEND_NOW 0xB7 + +#define ATT_TRANSACTION_MODE_NONE 0x0 +#define ATT_TRANSACTION_MODE_ACTIVE 0x1 +#define ATT_TRANSACTION_MODE_EXECUTE 0x2 +#define ATT_TRANSACTION_MODE_CANCEL 0x3 +#define ATT_TRANSACTION_MODE_VALIDATE 0x4 + +#define ATT_PROPERTY_BROADCAST 0x01 +#define ATT_PROPERTY_READ 0x02 +#define ATT_PROPERTY_WRITE_WITHOUT_RESPONSE 0x04 +#define ATT_PROPERTY_WRITE 0x08 +#define ATT_PROPERTY_NOTIFY 0x10 +#define ATT_PROPERTY_INDICATE 0x20 + + + typedef enum { + ATT_OP_AUTO_READ_CCC = 0, //server端 检查对方使能通知CCC来控制 notify or indicate发送 + ATT_OP_NOTIFY = 1, //server端 默认notify方式发送,不检查使能通知CCC (不需要对方回应答包,没有流控) + ATT_OP_INDICATE = 2, //server端 默认INDICATE方式发送,不检查使能通知CCC (需要对方回应答包,有流控) + ATT_OP_READ, //client端 单次读, 用于获取<=MTU 的数据包 (需要对方回应答包,有流控) + ATT_OP_READ_LONG, //client端 多次读,用于支持获取>MTU 的数据包 (需要对方回应答包,有流控) + ATT_OP_WRITE, //client端 写发送 (需要对方回应答包,有流控) + ATT_OP_WRITE_WITHOUT_RESPOND,//client端 写发送 (不需要对方回应答包,没有流控) + //add here + + ATT_OP_CMD_MAX = 15, + } att_op_type_e; + +//------ + typedef struct { + uint16_t start_group_handle;// + uint16_t end_group_handle; + uint16_t uuid16; //为0则是 uuid128 + uint8_t uuid128[16]; + } service_report_t; //==le_service_t + + typedef struct { + uint16_t start_handle; + uint16_t value_handle; //属性操作handle + uint16_t end_handle; + uint16_t properties; //属性对应 ATT_PROPERTY_XXX + uint16_t uuid16; //为0则是 uuid128 + uint8_t uuid128[16]; + } charact_report_t; //==le_characteristic_t + + typedef struct { + u16 packet_type; //数据包类型(notify,indicate,read_respone,...) + u16 value_handle; //属性操作handle + u16 value_offset; //包偏移 + u16 blob_length; //包长度 + u8 *blob; //包内容 + u16 conn_handle; //连接handle + } att_data_report_t; + + + typedef struct { + service_report_t services; + charact_report_t characteristic; + u16 service_index; + u16 characteristic_index; + } search_result_t; + + typedef struct { + u16 handle;//descriptor's handle + u16 uuid16;//为0则是 uuid128 + u8 uuid128[16]; + } charact_descriptor_t; + + + void att_ccc_config_init(void); + void att_set_ccc_config(uint16_t handle, uint16_t cfg); + uint16_t att_get_ccc_config(uint16_t handle); + void att_server_set_exchange_mtu(u16 con_handle); + void att_set_db(uint8_t const *db);//change profile_data + + //多机接口 + //初始化 CCC管理 + void multi_att_ccc_config_init(void); + //设置CCC + void multi_att_set_ccc_config(uint16_t conn_handle, uint16_t att_handle, uint16_t cfg); + //获取CCC的值 + uint16_t multi_att_get_ccc_config(uint16_t conn_handle, uint16_t att_handle); + //断开, 清链路CCC + int multi_att_clear_ccc_config(uint16_t conn_handle); + +// 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 con_handle of hci le connection +// @param attribute_handle to be read +// @param offset defines start of attribute value +// @param buffer +// @param buffer_size + typedef uint16_t (*att_read_callback_t)(uint16_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t *buffer, uint16_t buffer_size); + +// ATT Client Write Callback for Dynamic Data +// @param con_handle of hci le connection +// @param attribute_handle to be written +// @param transaction - ATT_TRANSACTION_MODE_NONE for regular writes, ATT_TRANSACTION_MODE_ACTIVE for prepared writes and ATT_TRANSACTION_MODE_EXECUTE +// @param offset into the value - used for queued writes and long attributes +// @param buffer +// @param buffer_size +// @param signature used for signed write commmands +// @returns 0 if write was ok, ATT_ERROR_PREPARE_QUEUE_FULL if no space in queue, ATT_ERROR_INVALID_OFFSET if offset is larger than max buffer + typedef int (*att_write_callback_t)(uint16_t con_handle, uint16_t attribute_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size); + + void ble_att_server_setup_init(const u8 *profile_db, att_read_callback_t read_cbk, att_write_callback_t write_cbk); + + void att_server_request_can_send_now_event(hci_con_handle_t con_handle); + + int att_server_notify(hci_con_handle_t con_handle, uint16_t attribute_handle, uint8_t *value, uint16_t value_len); + + int att_server_indicate(hci_con_handle_t con_handle, uint16_t attribute_handle, uint8_t *value, uint16_t value_len); + + extern void att_server_init(uint8_t const *db, att_read_callback_t read_callback, att_write_callback_t write_callback); + extern void att_server_register_packet_handler(btstack_packet_handler_t handler); + +#endif diff --git a/include_lib/btstack/le/ble_api.h b/include_lib/btstack/le/ble_api.h new file mode 100644 index 0000000..80855d6 --- /dev/null +++ b/include_lib/btstack/le/ble_api.h @@ -0,0 +1,1347 @@ +/********************************************************************************************* + * Filename : ble_api.h + + * Description : + + * Author : mx + + * Email : lmx@zh-jieli.com + + * Last modifiled : 2020-07-01 16:36 + + * Copyright:(c)JIELI 2011-2020 @ , All Rights Reserved. +*********************************************************************************************/ +#ifndef __BLE_API_H__ +#define __BLE_API_H__ + + +#include "typedef.h" +#include "btstack/btstack_typedef.h" + + +/*****注意:该文件的枚举与库编译密切相关,主要是给用户提供调用所用。用户不能自己在中间添加值.***/ +/*! +* ----user (command) codes---- +* +* @brief hci connection handle type + */ +/*************************************************************************************************/ + +typedef enum { + /* + */ + BLE_CMD_ADV_ENABLE = 1, + BLE_CMD_ADV_PARAM, + BLE_CMD_ADV_DATA, + BLE_CMD_RSP_DATA, + BLE_CMD_DISCONNECT, + BLE_CMD_REGIEST_THREAD, + BLE_CMD_ATT_SEND_INIT, + BLE_CMD_ATT_MTU_SIZE, + BLE_CMD_ATT_VAILD_LEN, + BLE_CMD_ATT_SEND_DATA, + BLE_CMD_REQ_CONN_PARAM_UPDATE, + + BLE_CMD_SCAN_ENABLE, + BLE_CMD_SCAN_PARAM, + BLE_CMD_STACK_EXIT, + BLE_CMD_CREATE_CONN, + BLE_CMD_CREATE_CONN_CANCEL, + + BLE_CMD_ADV_PARAM_EXT, + BLE_CMD_SEND_TEST_KEY_NUM, + BLE_CMD_LATENCY_HOLD_CNT, + BLE_CMD_SET_DATA_LENGTH, + BLE_CMD_SET_HCI_CFG, + BLE_CMD_SCAN_ENABLE2, + BLE_CMD_ATT_SERVER_REQ_RESUME, + + //MULTI API,多机接口 + BLE_CMD_MULTI_ATT_SEND_INIT, + BLE_CMD_MULTI_ATT_SET_CONN_HANDLE, + BLE_CMD_MULTI_ATT_SEND_DATA, + BLE_CMD_MULTI_ATT_MTU_SIZE, + BLE_CMD_MULTI_ATT_VAILD_LEN, + + //sm + BLE_CMD_SM_REQ_RESUME, + + //add here + BLE_CMD_CREATE_CONN_EXT, + BLE_CMD_DISCONNECT_EXT, + BLE_CMD_ATT_CLEAR_SEND_DATA, + + //< ble5 + BLE_CMD_EXT_ADV_PARAM = 0x40, + BLE_CMD_EXT_ADV_DATA, + BLE_CMD_EXT_RSP_DATA, + BLE_CMD_EXT_ADV_ENABLE, + BLE_CMD_SET_PHY, + BLE_CMD_EXT_SCAN_PARAM, + BLE_CMD_EXT_SCAN_ENABLE, + BLE_CMD_EXT_CREATE_CONN, + BLE_CMD_PERIODIC_ADV_PARAM, + BLE_CMD_PERIODIC_ADV_DATA, + BLE_CMD_PERIODIC_ADV_ENABLE, + BLE_CMD_PERIODIC_ADV_CREAT_SYNC, + BLE_CMD_PERIODIC_ADV_TERMINATE_SYNC, + BLE_CMD_PERIODIC_ADV_CREATE_SYNC_CANCEL, + + //client + BLE_CMD_SEARCH_PROFILE = 0x80, + BLE_CMD_WRITE_CCC, + BLE_CMD_ONNN_PARAM_UPDATA, +} ble_cmd_type_e; + +typedef enum { + BLE_CMD_RET_SUCESS = 0, //执行成功 + BLE_CMD_RET_BUSY = -100, //命令处理忙 + BLE_CMD_PARAM_OVERFLOW, //传数溢出 + BLE_CMD_OPT_FAIL, //操作失败 + BLE_BUFFER_FULL, //缓存满了 + BLE_BUFFER_ERROR, //缓存出错 + BLE_CMD_PARAM_ERROR, //传参出错 + BLE_CMD_STACK_NOT_RUN, //协议栈没有运行 + BLE_CMD_CCC_FAIL, //没有使能通知,导致NOTIFY或INDICATE发送失败, +} ble_cmd_ret_e; + +//-------------------------------------------- +ble_cmd_ret_e ble_user_cmd_prepare(ble_cmd_type_e cmd, int argc, ...); + +struct conn_update_param_t { + u16 interval_min; //连接周期范围最小值(unit:1.25ms) + u16 interval_max; //连接周期范围最大值(unit:1.25ms) + u16 latency; //忽略通信次数(unit: interval) + u16 timeout; //(unit:10ms) +}; + +typedef enum { + PFL_SERVER_UUID16 = 1, //指定16bit UUID搜索方式 + PFL_SERVER_UUID128, //指定128bit UUID搜索方式 + PFL_SERVER_ALL, //搜索所有的UUID +} search_profile_type_e; + + +//-------------------------------------------- +struct create_conn_param_t { + u16 conn_interval; //连接周期(unit:1.25ms) + u16 conn_latency; //忽略通信次数(unit: interval) + u16 supervision_timeout; //(通信超时 unit:10ms) + u8 peer_address_type; //对方地址类型:0--public address,1--random address + u8 peer_address[6]; //对方地址address +} _GNU_PACKED_; + +struct create_conn_param_ext_t { + u16 le_scan_interval; /*scan 周期(unit: 0.625ms)*/ + u16 le_scan_window; /*scan 窗口(unit: 0.625ms)*/ + u8 initiator_filter_policy;/*过滤,set 0*/ + u8 peer_address_type; /*对方地址类型:0--public address,1--random address*/ + u8 peer_address[6]; /*对方地址*/ + u8 own_address_type; /*本地地址类型:0--public address,1--random address*/ + u16 conn_interval_min;/*连接周期最小值(unit:1.25ms)*/ + u16 conn_interval_max;/*连接周期最大值(unit:1.25ms)*/ + u16 conn_latency; /*忽略通信次数(unit: interval)*/ + u16 supervision_timeout;/*通信超时 unit:10ms*/ + u16 minimum_ce_length; /*set 1*/ + u16 maximum_ce_length; /*set 1*/ +} _GNU_PACKED_; + + +typedef struct { + u8 event_type; //对方广播包类型: 0--ADV_IND,1--ADV_DIRECT_IND,2--ADV_SCAN_IND,3--ADV_NONCONN_IND,4--SCAN_RSP + u8 address_type; //对方地址类型:0--public address,1--random address + u8 address[6]; //peer_address + s8 rssi; //range:-127 ~128 dbm + u8 length; //广播包长度 + u8 data[0]; //广播包内容 +} adv_report_t; + +typedef struct { + //base info + u8 type; //< See SM_... + u8 size; + u16 con_handle; //connection 's handle, >0 + u8 addr_type; //对方地址类型:0--public address,1--random address + u8 address[6]; //对方地址 + //extend info + u8 data[4]; +} sm_just_event_t; + +//BLE_CMD_SET_HCI_CFG +typedef enum { + HCI_CFG_OWN_ADDRESS_TYPE = 0, // + HCI_CFG_ADV_FILTER_POLICY, // + HCI_CFG_SCAN_FILTER_POLICY, // + HCI_CFG_INITIATOR_FILTER_POLICY, // + //add here +} hci_cfg_par_e; + +typedef enum { + REMOTE_TYPE_UNKNOWN = 0,//未查询or查询对方未响应 + REMOTE_TYPE_ANDROID, //安卓系统 + REMOTE_TYPE_IOS,//ios系统 +} remote_type_e; + +/*************************************************************************************************/ +/*! + * \brief Gatt client角色初始化. + */ +/*************************************************************************************************/ +void gatt_client_init(void); + +/*************************************************************************************************/ +/*! + * \brief 注册gatt client角色,事件回调函数. + * + * \param [in] handler 事件处理函数. + */ +/*************************************************************************************************/ +void gatt_client_register_packet_handler(btstack_packet_handler_t handler); + +/*************************************************************************************************/ +/*! + * \brief 初始化配对表. + * + * \note 上电初始化一次. + */ +/*************************************************************************************************/ +void le_device_db_init(void); + +/*************************************************************************************************/ +/*! + * \brief 注册passkey输入回调. + * + * \param [in] reset_pk 复位按键输入. + */ +/*************************************************************************************************/ +void reset_PK_cb_register(void (*reset_pk)(u32 *)); + +/*************************************************************************************************/ +/*! + * \brief 设置ble蓝牙的public地址. + * + * \param [in] addr public地址. + * + * \return 0->success ,非0->fail. + * + * \note 可以结合接口 ble_op_set_ownaddress_type 配置选择地址类型. + * \note 修改地址必须在ble非工作状态下才能生效( 没有scan,没有adv,没有connected). + */ +/*************************************************************************************************/ +int le_controller_set_mac(void *addr); + +/*************************************************************************************************/ +/*! + * \brief 获取ble蓝牙的public地址. + * + * \param [out] addr pulic地址. + * + * \return 0->success ,非0->fail. + */ +/*************************************************************************************************/ +int le_controller_get_mac(void *addr); + +/*************************************************************************************************/ +/*! + * \brief 初始化ble蓝牙random地址. + * + * \param [in] addr random地址. + * + * \return 0->success ,非0->fail. + * + * \note 结合接口ble_op_set_own_address_type 配置选择地址类型. + * \note 修改地址必须在ble非工作状态下才能生效(内有scan,没有adv,没connected). + */ +/*************************************************************************************************/ +int le_controller_set_random_mac(void *addr); + +/*************************************************************************************************/ +/*! + * \brief 获取ble蓝牙的random地址. + * + * \param [out] addr random地址. + * + * \return 0->success ,非0->fail. + */ +/*************************************************************************************************/ +int le_controller_get_random_mac(void *addr); + +/*************************************************************************************************/ +/*! + * \brief 配置协议栈 GATT 角色处理,default server. + * + * \param [in] role GATT role: 0--server ,1--client ,2--server + client. + */ +/*************************************************************************************************/ +void ble_stack_gatt_role(u8 role); + +/*************************************************************************************************/ +/*! + * \brief client 连接后初始化. + * + * \param [in] handle range :>0. + * \param [in] buffer 配置缓存地址. + * \param [in] buffer_size 缓存大小. + */ +/*************************************************************************************************/ +void user_client_init(u16 handle, u8 *buffer, u16 buffer_size); + +/*************************************************************************************************/ +/*! + * \brief 获取链路对方的信号强度. + * + * \param [in] con_handle range :>0. + * + * \return rssi 强度 ,range :-127 ~128 dbm. + */ +/*************************************************************************************************/ +s8 ble_vendor_get_peer_rssi(u16 conn_handle); + +/*************************************************************************************************/ +/*! + * \brief 使能周期interval事件上报. + * + * \param [in] con_handle range :>0. + * \param [in] enable 1 or 0. + * + * \return true or false. + */ +/*************************************************************************************************/ +bool ble_vendor_interval_event_enable(u16 conn_handle, int enable); + +/*************************************************************************************************/ +/*! + * \brief 配置协议栈ATT默认的MTU大小. + * + * \param [in] mtu_size 配置MUT大小 ,range :23 ~517. + * + * \return 配置后mtu_size的值. + */ +/*************************************************************************************************/ +u16 ble_vendor_set_default_att_mtu(u16 mtu_size); + +/*************************************************************************************************/ +/*! + * \brief 设置 client 搜索结束. + */ +/*************************************************************************************************/ +void user_client_set_search_complete(void); + +/*************************************************************************************************/ +/*! + * \brief 提供生成ble对应的类型地址. + * + * \param [out] address 类型对应地址. + * \param [in] type ble_type + * (eg:1.STATIC_DEVICE_ADDR. + * 2.NON_RESOLVABLE_PRIVATE_ADDR. + * 3.RESOLVABLE_PRIVATE_ADDR). + * + * \return true or false. + * + * \note 生成RESOLVABLE_PRIVATE_ADDR,需要等协议栈初始化IRK后才能生成. + */ +/*************************************************************************************************/ +bool ble_vendor_random_address_generate(u8 *address, u8 type); + +/*************************************************************************************************/ +/*! + * \brief 根据提供的edr地址生成唯一对应的ble地址. + * + * \param [out] ble_adress BLE_address. + * \param [in] edr_adress EDR_address. + * + * \note 用户可以自定义edr和ble地址关联规则,重写这个接口 + */ +/*************************************************************************************************/ +void lib_make_ble_address(u8 *ble_address, u8 *edr_address); + +/*************************************************************************************************/ +/*! + * \brief 配置设备的地址类型,默认为 0(public address). + * + * \function ble_cmd_ret_e ble_op_set_own_address_type(u8 address_type). + * + * \param [in] address_type Range: 0x00 to 0x03. + * + * \return see ble_cmd_ret_e. + * + * \note !!!注意:设置的时候必须在、设置广播参数、或者扫描参数、或者创建连接参数前配置好. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_set_own_address_type(u8 address_type) */ +#define ble_op_set_own_address_type(address_type) \ + ble_user_cmd_prepare(BLE_CMD_SET_HCI_CFG, 2,HCI_CFG_OWN_ADDRESS_TYPE,(int)address_type) + +/*************************************************************************************************/ +/*! + * \brief 开关BLE广播. + * + * \function ble_cmd_ret_e ble_op_adv_enable(int enable). + * + * \param [in] enable 广播使能 :0(dis) or 1(en). + * + * \return see ble_cmd_ret_e. + * + * \note !!!注意:开广播前必现先配置好广播的参数. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_adv_enable(int enable) */ +#define ble_op_adv_enable(enable) \ + ble_user_cmd_prepare(BLE_CMD_ADV_ENABLE, 1, (int)enable) + +/*************************************************************************************************/ +/*! + * \brief 配置广播过滤策略(决定链路层如何处理扫描、连接请求);默认为 0. + * + * \function ble_cmd_ret_e ble_op_set_adv_filter_policy(u8 type). + * + * \param [in] type 类型 :Range: 0x00 to 0x03. + * + * \return see ble_cmd_ret_e. + * + * \note !!!注意:设置的时候必须在“设置广播参数ble_op_set_adv_param前配置好. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_set_adv_filter_policy(u8 type) */ +#define ble_op_set_adv_filter_policy(type) \ + ble_user_cmd_prepare(BLE_CMD_SET_HCI_CFG, 2,HCI_CFG_ADV_FILTER_POLICY,type) + +/*************************************************************************************************/ +/*! + * \brief 配置广播参数. + * + * \function ble_cmd_ret_e ble_op_set_adv_param(u16 adv_interval,u8 adv_type). + * + * \param [in] adv_interval 广播周期,Range: 0x0020 to 0x4000 (unit: 0.625ms). + * \param [in] adv_type 广播类型,Range: 0x00 to 0x04. + * \param [in] adv_channel 广播类型通道,range:Range: 0x01 to 0x07. + * + * \return see ble_cmd_ret_e. + * + * \note !!!注意:设置的时候必现在广播关闭的状态下. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_set_adv_param(u16 adv_interval,u8 adv_type) */ +#define ble_op_set_adv_param(adv_interval,adv_type,adv_channel) \ + ble_user_cmd_prepare(BLE_CMD_ADV_PARAM, 3, (int)adv_interval, (int)adv_type, (int)adv_channel) + +/*************************************************************************************************/ +/*! + * \brief 配置广播参数+配对信息(相比配对广播参数,这个函数主要是针对定向广播使用). + * + * \function ble_cmd_ret_e ble_op_set_adv_param_ext(u16 adv_interval,u8 adv_type,u8 adv_channel,const u8 *peer_info). + * + * \param [in] adv_interval 广播周期,Range: 0x0020 to 0x4000 (unit: 0.625ms). + * \param [in] adv_type 广播类型,Range: 0x00 to 0x04. + * \param [in] adv_channel 广播类型通道,range:Range: 0x01 to 0x07. + * \param [in] peer_info (全局变量地址),定向广播时,填入对方的地址信息. + * + * \return see ble_cmd_ret_e. + * + * \note !!!注意:设置的时候必现在广播关闭的状态下. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_set_adv_param_ext(u16 adv_interval,u8 adv_type,u8 adv_channel,const u8 *peer_info) */ +#define ble_op_set_adv_param_ext(adv_interval,adv_type,adv_channel,peer_info) \ + ble_user_cmd_prepare(BLE_CMD_ADV_PARAM_EXT, 4, (int)adv_interval, (int)adv_type, (int)adv_channel, (void*)peer_info) + +/*************************************************************************************************/ +/*! + * \brief 配置广播 Advertising Data内容. + * + * \function ble_cmd_ret_e ble_op_set_adv_data(u8 adv_len,const *u8 adv_data). + * + * \param [in] adv_len adv 数据包长度,Range: 0x00 to 0x1f. + * \param [in] adv_data (全局变量地址),adv数据包地址. + * + * \return see ble_cmd_ret_e. + * + * \note !!!注意:设置的时候必现在广播关闭的状态下. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_set_adv_data(u8 adv_len,const *u8 adv_data) */ +#define ble_op_set_adv_data(adv_len,adv_data) \ + ble_user_cmd_prepare(BLE_CMD_ADV_DATA, 2, (int)adv_len, (void*)adv_data) + +/*************************************************************************************************/ +/*! + * \brief 配置广播 Scan Response Data内容. + * + * \function ble_cmd_ret_e ble_op_set_rsp_data(u8 rsp_len,const *u8 rsp_data). + * + * \param [in] rsp_len rsp 包长度,Range: 0x00 to 0x1f. + * \param [in] adv_data (全局变量地址),rsp数据包地址. + * + * \return see ble_cmd_ret_e. + * + * \note !!!注意:设置的时候必现在广播关闭的状态下. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_set_rsp_data(u8 rsp_len,const *u8 rsp_data) */ +#define ble_op_set_rsp_data(rsp_len,rsp_data) \ + ble_user_cmd_prepare(BLE_CMD_RSP_DATA, 2, (int)rsp_len, (void*)rsp_data) + +/*************************************************************************************************/ +/*! + * \brief 请求断开 ble 连接. + * + * \function ble_cmd_ret_e ble_op_disconnect(u16 con_handle). + * + * \param [in] con_handle range: >0. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_disconnect(u16 con_handle) */ +#define ble_op_disconnect(con_handle) \ + ble_user_cmd_prepare(BLE_CMD_DISCONNECT, 1, (int)con_handle) + +/*************************************************************************************************/ +/*! + * \brief 请求断开 ble 连接,by reason + * + * \function ble_cmd_ret_e ble_op_disconnect(u16 con_handle). + * + * \param [in] con_handle range: >0. + * \param [in] reason range: see spec. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_disconnect_ext(u16 con_handle,reason) */ +#define ble_op_disconnect_ext(con_handle,reason) \ + ble_user_cmd_prepare(BLE_CMD_DISCONNECT_EXT, 2, (int)con_handle, reason) + + +/*************************************************************************************************/ +/*! + * \brief 配置ATT发送模块RAM大小. + * + * \function ble_cmd_ret_e ble_op_att_send_init(u16 con_handle,u8 *att_ram_addr,int att_ram_size,int att_payload_size). + * + * \param [in] con_handle range: >0. + * \param [in] att_ram_addr 传入ATT发送模块ram地址,地址按4字节对齐. + * \param [in] att_ram_size 传入ATT发送模块ram大小. + * \param [in] att_payload_size 发送ATT包payload的最大长度 <= MTU的payload,range:20 to MTU的payload size. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_att_send_init(u16 con_handle,u8 *att_ram_addr,int att_ram_size,int att_payload_size) */ +#define ble_op_att_send_init(con_handle,att_ram_addr,att_ram_size,att_payload_size) \ + ble_user_cmd_prepare(BLE_CMD_ATT_SEND_INIT, 4, con_handle,att_ram_addr,att_ram_size,att_payload_size) + +/*************************************************************************************************/ +/*! + * \brief MULTI API: 配置ATT发送模块初始化. + * + * \function ble_cmd_ret_e ble_op_multi_att_send_init(u8 *att_ram_addr,int att_ram_size,int att_payload_size). + * + * \param [in] att_ram_addr 传入ATT发送模块ram地址,地址按4字节对齐. + * \param [in] att_ram_size 传入ATT发送模块ram大小. + * \param [in] att_payload_size 发送ATT包payload的最大长度 <= MTU的payload,range:20 to MTU的payload size. + * + * \return see ble_cmd_ret_e. + * + * \note 多机处理,只需要初始化一次就可以. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_multi_att_send_init(u8 *att_ram_addr,int att_ram_size,int att_payload_size) */ +#define ble_op_multi_att_send_init(att_ram_addr,att_ram_size,att_payload_size) \ + ble_user_cmd_prepare(BLE_CMD_MULTI_ATT_SEND_INIT, 3, att_ram_addr,att_ram_size,att_payload_size) + +/*************************************************************************************************/ +/*! + * \brief MULTI API: 配置ATT模块 使用的连接con_handle. + * + * \function ble_cmd_ret_e ble_op_multi_att_send_conn_handle(u16 con_handle,int handle_index,int0 rolev). + * + * \param [in] con_handle range:>0. + * \param [in] handle_index range: 0~7 //多连接的hanlde id. + * \param [in] role range: 0-gatt_sever,1-gatt_client. + * + * \return see ble_cmd_ret_e. + * + * \note 多机处理. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_multi_att_send_conn_handle(u16 con_handle,int handle_index,int0 rolev) */ +#define ble_op_multi_att_send_conn_handle(con_handle,handle_index,role) \ + ble_user_cmd_prepare(BLE_CMD_MULTI_ATT_SET_CONN_HANDLE, 3, con_handle,handle_index,role) + +/*************************************************************************************************/ +/*! + * \brief 根据对方的接收MTU大小,配置本地可发送MTU的payload大小. + * + * \function ble_cmd_ret_e ble_op_att_set_send_mtu(u16 mtu). + * + * \param [in] mtu 对方mtu payload的大小. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_att_set_send_mtu(u16 mtu) */ +#define ble_op_att_set_send_mtu(mtu) \ + ble_user_cmd_prepare(BLE_CMD_ATT_MTU_SIZE, 1, mtu); + +/*************************************************************************************************/ +/*! + * \brief MULTI API: 根据对方的接收MTU大小,配置本地可发送的MTU的大小. + * + * \function ble_cmd_ret_e ble_op_multi_att_set_send_mtu(u16 con_handle,u16 mtu). + * + * \param [in] con_handle 连接 con_handle,range:>0. + * \param [in] mtu 对方mtu payload的大小. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_multi_att_set_send_mtu(u16 con_handle,u16 mtu) */ +#define ble_op_multi_att_set_send_mtu(con_handle,mtu) \ + ble_user_cmd_prepare(BLE_CMD_MULTI_ATT_MTU_SIZE, 2, con_handle,mtu); + +/*************************************************************************************************/ +/*! + * \brief 获取ATT发送模块,cbuffer可写入数据的长度. + * + * \function ble_cmd_ret_e ble_op_att_get_remain(int *remain_size_ptr). + * + * \param [out] remain_size_ptr 输出可写入长度值. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_att_get_remain(int *remain_size_ptr) */ +#define ble_op_att_get_remain(remain_size_ptr) \ + ble_user_cmd_prepare(BLE_CMD_ATT_VAILD_LEN, 1, remain_size_ptr) + +/*************************************************************************************************/ +/*! + * \brief MULTI API: 获取ATT发送模块,cbuffer 可写入数据的长度. + * + * \function ble_cmd_ret_e ble_op_multi_att_get_remain(u16 con_handle,int *remain_size_ptr). + * + * \param [in] con_handle range:>0. + * \param [out] remain_size_ptr 输出可写入长度值. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_multi_att_get_remain(u16 con_handle,int *remain_size_ptr) */ +#define ble_op_multi_att_get_remain(con_handle,remain_size_ptr) \ + ble_user_cmd_prepare(BLE_CMD_MULTI_ATT_VAILD_LEN, 2,con_handle, remain_size_ptr) + +/*************************************************************************************************/ +/*! + * \brief ATT操作handle发送数据. + * + * \function ble_cmd_ret_e ble_op_att_send_data(u16 att_handle,u8 *data,u16 len, att_op_type_e att_op_type). + * + * \param [in] att_handle att操作的handle. + * \param [in] data 数据地址. + * \param [in] len 数据长度 <= cbuffer 可写入的长度. + * \param [in] att_op_type see att_op_type_e (att.h). + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_att_send_data(u16 att_handle,u8 *data,u16 len, att_op_type_e att_op_type) */ +#define ble_op_att_send_data(att_handle,data,len,att_op_type) \ + ble_user_cmd_prepare(BLE_CMD_ATT_SEND_DATA, 4, att_handle, data, len, att_op_type) + +/*************************************************************************************************/ +/*! + * \brief MULTI API: ATT操作handle发送数据. + * + * \function ble_cmd_ret_e ble_op_multi_att_send_data(u16 con_handle,u16 att_handle,u8 *data,u16 len, att_op_type_e att_op_type). + * + * \param [in] con_handle 连接 con_handle,range:>0. + * \param [in] att_handle att操作handle. + * \param [in] data 数据地址. + * \param [in] len 数据长度 <= cbuffer 可写入的长度. + * \param [in] att_op_type see att_op_type_e (att.h). + * + * \return see ble_cmd_ret_e. + * + * \note 多机处理. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_multi_att_send_data(u16 con_handle,u16 att_handle,u8 *data,u16 len, att_op_type_e att_op_type) */ +#define ble_op_multi_att_send_data(con_handle,att_handle,data,len,att_op_type) \ + ble_user_cmd_prepare(BLE_CMD_MULTI_ATT_SEND_DATA, 5, con_handle,att_handle, data, len, att_op_type) + + +/*************************************************************************************************/ +/*! + * \brief ATT操作,清缓存发送的数据缓存 + * + * \function ble_op_att_clear_data(void). + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_att_clear_send_data(void) */ +#define ble_op_att_clear_send_data(void) \ + ble_user_cmd_prepare(BLE_CMD_ATT_CLEAR_SEND_DATA, 1, 1) + +/*************************************************************************************************/ +/*! + * \brief 从机请求更新连接参数,走l2cap命令. + * + * \function ble_cmd_ret_e ble_op_conn_param_request(u16 con_handle,const struct conn_update_param_t *con_param). + * + * \param [in] con_handle 连接 con_handle,range:>0. + * \param [in] con_param (全局变量地址),连接参数. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_conn_param_request(u16 con_handle,const struct conn_update_param_t *con_param) */ +#define ble_op_conn_param_request(con_handle,con_param) \ + ble_user_cmd_prepare(BLE_CMD_REQ_CONN_PARAM_UPDATE, 2, con_handle, (void*)con_param) + +/*************************************************************************************************/ +/*! + * \brief 发起data length 交换.(btctrl的feature打开支持DLE) + * + * \function ble_cmd_ret_e ble_op_set_data_length(u16 con_handle,u16 tx_octets,u16 tx_time). + * + * \param [in] tx_octets DLE发送长度. + * \param [in] tx_time DLE发送事件. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_set_data_length(u16 con_handle,u16 tx_octets,u16 tx_time) */ +#define ble_op_set_data_length(con_handle,tx_octets,tx_time) \ + ble_user_cmd_prepare(BLE_CMD_SET_DATA_LENGTH, 3, con_handle, tx_octets, tx_time) + +/*************************************************************************************************/ +/*! + * \brief ble5.0 配置广播参数. + * + * \function ble_cmd_ret_e ble_op_set_ext_adv_param(u8 *param,u16 param_len). + * + * \param [in] param 广播参数. + * \param [in] tx_time 参数长度. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_set_ext_adv_param(u8 *param,u16 param_len) */ +#define ble_op_set_ext_adv_param(param,param_len) \ + ble_user_cmd_prepare(BLE_CMD_EXT_ADV_PARAM, 2, param, param_len) + +/*************************************************************************************************/ +/*! + * \brief ble5.0 配置 adv 数据包. + * + * \function ble_cmd_ret_e ble_op_set_ext_adv_data(u8 *data,u16 data_len). + * + * \param [in] data 数据包内容. + * \param [in] data_len 数据包长度. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_set_ext_adv_data(u8 *data,u16 data_len) */ +#define ble_op_set_ext_adv_data(data,data_len) \ + ble_user_cmd_prepare(BLE_CMD_EXT_ADV_DATA, 2, data, data_len) + +/*************************************************************************************************/ +/*! + * \brief ble5.0 配置 respond 数据包. + * + * \function ble_cmd_ret_e ble_op_set_ext_rsp_data(u8 *data,u16 data_len). + * + * \param [in] data 数据包内容. + * \param [in] data_len 数据包长度. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_set_ext_rsp_data(u8 *data,u16 data_len) */ +#define ble_op_set_ext_rsp_data(data,data_len) \ + ble_user_cmd_prepare(BLE_CMD_EXT_RSP_DATA, 2, data, data_len) + +/*************************************************************************************************/ +/*! + * \brief ble5.0 开关广播. + * + * \function ble_cmd_ret_e ble_op_set_ext_adv_enable(u8 *cmd,u16 cmd_le). + * + * \param [in] cmd 命令信息. + * \param [in] cmd_len 命令长度. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_set_ext_adv_enable(u8 *cmd,u16 cmd_le) */ +#define ble_op_set_ext_adv_enable(cmd,cmd_len) \ + ble_user_cmd_prepare(BLE_CMD_EXT_ADV_ENABLE, 2, cmd, cmd_len) + +/*************************************************************************************************/ +/*! + * \brief ble5.0 配置phy. + * + * \function ble_cmd_ret_e ble_op_set_ext_phy(u16 con_handle,u16 all_phys,u16 tx_phy,u16 rx_phy,u16 phy_options). + * + * \param [in] con_handle 连接 con_handle,range:>0. + * \param [in] all_phys 0. + * \param [in] tx_phy CONN_SET_CODED_PHY. + * \param [in] rx_phy CONN_SET_CODED_PHY. + * \param [in] phy_options CONN_SET_PHY_OPTIONS. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_set_ext_phy(u16 con_handle,u16 all_phys,u16 tx_phy,u16 rx_phy,u16 phy_options) */ +#define ble_op_set_ext_phy(con_handle,all_phys,tx_phy,rx_phy,phy_options) \ + ble_user_cmd_prepare(BLE_CMD_SET_PHY, 5, con_handle, all_phys, tx_phy, rx_phy, phy_options) + +/*************************************************************************************************/ +/*! + * \brief ble5.0 配置 主机scan 参数. + * + * \function ble_cmd_ret_e ble_op_set_ext_scan_param(u8 *param,u16 param_le). + * + * \param [in] param 参数内容. + * \param [in] param_len 参数长度. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_set_ext_scan_param(u8 *param,u16 param_le) */ +#define ble_op_set_ext_scan_param(param,param_len) \ + ble_user_cmd_prepare(BLE_CMD_EXT_SCAN_PARAM, 2, param, param_len) + +/*************************************************************************************************/ +/*! + * \brief ble5.0 配置 主机scan 开关. + * + * \function ble_cmd_ret_e ble_op_ext_scan_enable(u8 *cmd,u16 cmd_le). + * + * \param [in] cmd 命令信息. + * \param [in] cmd_len 命令长度. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_ext_scan_enable(u8 *cmd,u16 cmd_le) */ +#define ble_op_ext_scan_enable(cmd,cmd_len) \ + ble_user_cmd_prepare(BLE_CMD_EXT_SCAN_ENABLE, 2, cmd, cmd_len) + +/*************************************************************************************************/ +/*! + * \brief ble5.0 配置 主机创建连接监听. + * + * \function ble_cmd_ret_e ble_op_ext_create_conn(u8 *conn_param,u16 param_len_len). + * + * \param [in] conn_param 连接参数信息. + * \param [in] param_len 参数长度. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_ext_create_conn(u8 *conn_param,u16 param_len_len) */ +#define ble_op_ext_create_conn(conn_param,param_len) \ + ble_user_cmd_prepare(BLE_CMD_EXT_CREATE_CONN, 2, conn_param, param_len) + +/*************************************************************************************************/ +/*! + * \brief 忽略进入latency 作用的次数 + * + * \function ble_cmd_ret_e ble_op_latency_skip(u16 con_handle,u16 skip_interval). + * + * \param [in] con_handle range:>0. + * \param [in] skip_interval 忽略的interval的次数. + * + * \return see ble_cmd_ret_e. + * + * \note !!!注意:让设备不进入latency模式,加快响应速度,但会耗电. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_latency_skip(u16 con_handle,u16 skip_interval) */ +#define ble_op_latency_skip(con_handle,skip_interval) \ + ble_user_cmd_prepare(BLE_CMD_LATENCY_HOLD_CNT, 2, con_handle, skip_interval) + +/*************************************************************************************************/ +/*! + * \brief 测试盒识别按键测试. + * + * \function ble_cmd_ret_e ble_op_test_key_num(u16 con_handle,u8 key_num). + * + * \param [in] con_handle range:>0. + * \param [in] key_num 按键. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_test_key_num(u16 con_handle,u8 key_num) */ +#define ble_op_test_key_num(con_handle,key_num) \ + ble_user_cmd_prepare(BLE_CMD_SEND_TEST_KEY_NUM, 2, con_handle, key_num) + +/*************************************************************************************************/ +/*! + * \brief 退出ble协议栈. + * + * \function ble_cmd_ret_e ble_op_stack_exit(u8 control). + * + * \param [in] control : 0--退出stack(默认),1--退出stack + controller. + * + * \return see ble_cmd_ret_e. + * + * \note 若已调用btstack_exit退出,则无需调用此接口 + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_stack_exit(u8 control) */ +#define ble_op_stack_exit(control) \ + ble_user_cmd_prepare(BLE_CMD_STACK_EXIT, 1, control) + +/*************************************************************************************************/ +/*! + * \brief 挂载协议栈线程调用. + * + * \function ble_cmd_ret_e ble_op_regist_thread_call(void (*thread_callback)(void)). + * + * \param [in] thread_callback 回调函数. + * + * \return see ble_cmd_ret_e. + * + * \note 用于同步线程处理,慎用 + * + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_regist_thread_call(void (*thread_callback)(void)) */ +#define ble_op_regist_thread_call(thread_callback) \ + ble_user_cmd_prepare(BLE_CMD_REGIEST_THREAD, 1, thread_callback) + +/*************************************************************************************************/ +/*! + * \brief 开关BLE搜索扫描. + * + * \function ble_cmd_ret_e ble_op_scan_enable(u8 enable). + * + * \param [in] enable 0 or 1. + * + * \return see ble_cmd_ret_e. + * + * \note filter_duplicate 默认为 1. + * \note !!!注意:开搜索前必现先配置好搜索的参数ble_op_set_scan_param. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_scan_enable(u8 enable) */ +#define ble_op_scan_enable(enable) \ + ble_user_cmd_prepare(BLE_CMD_SCAN_ENABLE, 1, enable) + +/*************************************************************************************************/ +/*! + * \brief 开关BLE搜索扫描2. + * + * \function ble_cmd_ret_e ble_op_scan_enable2(u8 enable,u8 filter_duplicate). + * + * \param [in] enable 0 or 1. + * \param [in] filter_duplicate 0 or 1. + * + * \return see ble_cmd_ret_e. + * + * \note filter_duplicate 默认为 1. + * \note !!!注意:开搜索前必现先配置好搜索的参数ble_op_set_scan_param. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_scan_enable2(u8 enable,u8 filter_duplicate) */ +#define ble_op_scan_enable2(enable,filter_duplicate) \ + ble_user_cmd_prepare(BLE_CMD_SCAN_ENABLE2, 2, enable,filter_duplicate) + +/*************************************************************************************************/ +/*! + * \brief 配置scan filter policy,默认type为0. + * + * \function ble_cmd_ret_e ble_op_set_scan_filter_policy(u8 type). + * + * \param [in] type Range: 0x00 to 0x03. + * + * \return see ble_cmd_ret_e. + * + * \note !!!注意:设置的时候必须在 设置扫描参数 ble_op_set_scan_param 前配置好. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_set_scan_filter_policy(u8 type) */ +#define ble_op_set_scan_filter_policy(type) \ + ble_user_cmd_prepare(BLE_CMD_SET_HCI_CFG, 2,HCI_CFG_SCAN_FILTER_POLICY,type) + +/*************************************************************************************************/ +/*! + * \brief 配置搜索参数. + * + * \function ble_cmd_ret_e ble_op_set_scan_param(u8 scan_type,u16 scan_interval,u16 scan_window). + * + * \param [in] scan_type 搜索类型 Range: 0x00 to 0x01 (unit: 0.625ms). + * \param [in] scan_interval 搜索周期 Range: 0x0004 to 0x4000 (unit: 0.625ms) >= scan_window. + * \param [in] scan_window 搜索窗口 Range: 0x0004 to 0x4000 (unit: 0.625ms), <= scan_interval. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_set_scan_param(u8 scan_type,u16 scan_interval,u16 scan_window) */ +#define ble_op_set_scan_param(scan_type,scan_interval,scan_window) \ + ble_user_cmd_prepare(BLE_CMD_SCAN_PARAM, 3, scan_type, scan_interval, scan_window) + +/*************************************************************************************************/ +/*! + * \brief 配置creat filter policy,默认type: 0. + * + * \function ble_cmd_ret_e ble_op_set_create_filter_policy(u8 type). + * + * \param [in] type Range: 0x00 to 0x03. + * + * \return see ble_cmd_ret_e. + * + * \note !!!注意:设置的时候必须在 设置创建连接参数 ble_op_create_connection 前配置好. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_set_create_filter_policy(u8 type) */ +#define ble_op_set_create_filter_policy(type) \ + ble_user_cmd_prepare(BLE_CMD_SET_HCI_CFG, 2,HCI_CFG_INITIATOR_FILTER_POLICY,type) + +/*************************************************************************************************/ +/*! + * \brief BLE创建连接监听. + * + * \function ble_cmd_ret_e ble_op_create_connection(struct create_conn_param_t * create_conn_param). + * + * \param [in] create_conn_param 连接参数. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_create_connection(struct create_conn_param_t * create_conn_param) */ +#define ble_op_create_connection(create_conn_param) \ + ble_user_cmd_prepare(BLE_CMD_CREATE_CONN, 1, create_conn_param) + +/*************************************************************************************************/ +/*! + * \brief BLE创建连接监听,扩展传入参数 + * + * \function ble_cmd_ret_e ble_op_create_connection_ext(cosnt struct create_conn_param_ext_t * create_conn_param_ext). + * + * \param [in] create_conn_param_ext 连接参数. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_create_connection_ext(const struct create_conn_param_ext_t * create_conn_param_ext) */ +#define ble_op_create_connection_ext(create_conn_param_ext) \ + ble_user_cmd_prepare(BLE_CMD_CREATE_CONN_EXT, 1, create_conn_param_ext) + +/*************************************************************************************************/ +/*! + * \brief 取消BLE连接监听. + * + * \function ble_cmd_ret_e ble_op_create_connection_cancel(void). + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_create_connection_cancel(void) */ +#define ble_op_create_connection_cancel() \ + ble_user_cmd_prepare(BLE_CMD_CREATE_CONN_CANCEL,0) + +/*************************************************************************************************/ +/*! + * \brief ble 主机搜索所有服务. + * + * \function ble_cmd_ret_e ble_op_search_profile_all(void). + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_search_profile_all(void) */ +#define ble_op_search_profile_all() \ + ble_user_cmd_prepare(BLE_CMD_SEARCH_PROFILE, 2, PFL_SERVER_ALL, 0) + +/*************************************************************************************************/ +/*! + * \brief ble 主机搜索指定UUID16服务. + * + * \function ble_cmd_ret_e ble_op_search_profile_uuid16(u16 uuid16). + * + * \param [in] uuid16 uuid. + * + * \return see ble_cmd_ret_e. + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_search_profile_uuid16(u16 uuid16) */ +#define ble_op_search_profile_uuid16(uuid16) \ + ble_user_cmd_prepare(BLE_CMD_SEARCH_PROFILE, 2, PFL_SERVER_UUID16, uuid16) + +/*************************************************************************************************/ +/*! + * \brief ble 主机搜索指定UUID128服务. + * + * \function ble_cmd_ret_e ble_op_search_profile_uuid128(const u8 *uuid128_pt). + * + * \param [in] uuid128_pt uuid. + * + * \return see ble_cmd_ret_e. + * + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_search_profile_uuid128(const u8 *uuid128_pt) */ +#define ble_op_search_profile_uuid128(uuid128_pt) \ + ble_user_cmd_prepare(BLE_CMD_SEARCH_PROFILE, 2, PFL_SERVER_UUID128, uuid128_pt) + +/*************************************************************************************************/ +/*! + * \brief ble 主机更新连接参数. + * + * \function ble_cmd_ret_e ble_op_conn_param_update(u16 con_handle,struct conn_update_param_t *con_param). + * + * \param [in] con_handle range:>0. + * \param [in] con_param (全局变量地址),连接参数. + * + * \return see ble_cmd_ret_e. + * + */ +/*************************************************************************************************/ +/* ble_cmd_ret_e ble_op_conn_param_update(u16 con_handle,struct conn_update_param_t *con_param) */ +#define ble_op_conn_param_update(con_handle,con_param) \ + ble_user_cmd_prepare(BLE_CMD_ONNN_PARAM_UPDATA, 2, con_handle, con_param) + + + +/*************************************************************************************************/ +/*! + * \brief ble master&slave 配置配对表(可以不设置,使用sdk默认值). + * + * \param [in] pair_devices_count 记录配对设备,range: 0~10,默认10.若配置为0:则不使用配对表记录管理,不限制配对个数. + * \param [in] is_allow_cover 是否允许循环覆盖记录 1 or 0,默认1. + * + * \return true or false. + * + * \note 上电调用配置,若配置的个数跟之前不一样,默认清所有的配对表数据. + * \note VM 掉电记录保护. + * \note 主从机共用一个配对表. + */ +/*************************************************************************************************/ +void ble_list_config_reset(u8 pair_devices_count, u8 is_allow_cover); + + +/*************************************************************************************************/ +/*! + * \brief 配置是否接受新设备请求配对,记录在VM,(可以不设置,使用sdk默认值). + * + * \param [in] enable 允许新设备配对开关,1 or 0,默认1. + * + * \return true or false. + * + * \note VM 掉电记录保护. + * \note 是否覆盖是由接口 ble_list_config_reset 的参数 is_allow_cover 决定. + */ +/*************************************************************************************************/ +bool ble_list_pair_accept(u8 enable); + + +/*************************************************************************************************/ +/*! + * \brief 获取配对表已有配对个数. + * + * \return 0~10. + */ +/*************************************************************************************************/ +u16 ble_list_get_count(void); + + +/*************************************************************************************************/ +/*! + * \brief 绑定已配对的指定设备,清除其他配对设备. + * + * \param [in] conn_addr 对方地址6bytes. + * \param [in] conn_addr_type 对方地址类型range: 0~1. + * + * \return true or false. + * + * \note VM 掉电记录保护. + */ +/*************************************************************************************************/ +bool ble_list_bonding_remote(u8 *conn_addr, u8 conn_addr_type); + + +/*************************************************************************************************/ +/*! + * \brief ble 清空配对表. + * + * \return true or false. + */ +/*************************************************************************************************/ +bool ble_list_clear_all(void); + +/*************************************************************************************************/ +/*! + * \brief ble 检测连接地址是否在已配对表中. + * + * \param [in] conn_addr 对方地址6bytes. + * \param [in] conn_addr_type 对方地址类型range: 0~1. + * + * \return true or false. + */ +/*************************************************************************************************/ +bool ble_list_check_addr_is_exist(u8 *conn_addr, u8 conn_addr_type); + + +/*************************************************************************************************/ +/*! + * \brief ble 把设备从配对表中删除. + * + * \param [in] conn_addr 对方地址6bytes. + * \param [in] conn_addr_type 对方地址类型range: 0~1. + * + * \return true or false. + */ +/*************************************************************************************************/ +bool ble_list_delete_device(u8 *conn_addr, u8 conn_addr_type); + + +/*************************************************************************************************/ +/*! + * \brief ble 获取配对表中最后连接设备的 id_address (public address). + * + * \param [out] id_addr 输出最后连接设备的id地址. + * + * \return true or false. + */ +/*************************************************************************************************/ +bool ble_list_get_last_id_addr(u8 *id_addr); + + +/*************************************************************************************************/ +/*! + * \brief ble 获取已配对设备连接地址对应的 id_address (public address or static address). + * + * \param [in] conn_addr 对方连接地址6bytes. + * \param [in] conn_addr_type 对方连接地址类型range: 0~1. + * \param [out] id_addr 输出已配对设备的id地址. + * + * \return true or false. + */ +/*************************************************************************************************/ +bool ble_list_get_id_addr(u8 *conn_addr, u8 conn_addr_type, u8 *id_addr); + +/*************************************************************************************************/ +/*! + * \brief ble 获取已配对设备的系统类型. + * + * \param [in] conn_addr 对方连接地址6bytes. + * \param [in] conn_addr_type 对方连接地址类型range: 0~1. + * \param [out] output_type 见 remote_type_e 定义. + * + * \return true or false. + * + * \note 只支持作为从机获取手机类型. + */ +/*************************************************************************************************/ +bool ble_list_get_remote_type(u8 *conn_addr, u8 conn_addr_type, u8 *output_type); + +/*************************************************************************************************/ +/*! + * \brief ble slave: att server 连接后主动发起请求MTU交换流程. + * + * \param [in] handle range:>0. + */ +/*************************************************************************************************/ +void att_server_set_exchange_mtu(u16 con_handle); + +/*************************************************************************************************/ +/*! + * \brief ble slave: att server 使能流控功能. + * + * \param [in] handle range:>0. + * \param [in] enable 1 or 0. + * + * \note 蓝牙初始化后可调用. + */ +/*************************************************************************************************/ +void att_server_flow_enable(u8 enable); + +/*************************************************************************************************/ +/*! + * \brief ble slave: att server 控制收数流控. + * + * \param [in] handle range:>0. + * \param [in] hold_flag 1--停止收发数据,0--开始正常收发数. + * + * \note 蓝牙初始化后可调用,对方client要使用write的方式发送数据才能有流控生效 + */ +/*************************************************************************************************/ +void att_server_flow_hold(hci_con_handle_t con_handle, u8 hold_flag); + +/*************************************************************************************************/ +/*! + * \brief ble slave: server 配对连接时,检查对方操作系统. + * + * \param [in] handle range:>0. + * \param [in] callback 检查完回调. + * + * \note 在第一次配对连接时调用,HCI_EVENT_ENCRYPTION_CHANGE 事件后. + */ +/*************************************************************************************************/ +void att_server_set_check_remote(u16 con_handle, void (*callback)(u16 con_handle, remote_type_e remote_type)); + + +/*************************************************************************************************/ +/*! + * \brief 检测协议栈att模块是否支持多机. + * + * \param [in] server_max 传入判断的从机个数. + * \param [in] client_max 传入判断的主机个数·. + * + * \return 0->success ,非0->fail. + */ +/*************************************************************************************************/ +int att_send_check_multi_dev(u8 server_max, u8 client_max); + + +/*************************************************************************************************/ +/*! + * \brief 可修改GATT服务的profile. + * + * \param [in] profile_data gatt profile. + * + * \return 0->success ,非0->fail. + * + * \note 蓝牙未连接状态下,可调用修改. + */ +/*************************************************************************************************/ +int att_server_change_profile(u8 const *profile_data); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#endif + diff --git a/include_lib/btstack/le/ble_data_types.h b/include_lib/btstack/le/ble_data_types.h new file mode 100644 index 0000000..9a63772 --- /dev/null +++ b/include_lib/btstack/le/ble_data_types.h @@ -0,0 +1,57 @@ +/********************************************************************************************* + * Filename : bluetooth_data_types.h + + * Description : + + * Author : +*********************************************************************************************/ + +/** + */ + +#ifndef __BLUETOOTH_DATA_TYPES_H +#define __BLUETOOTH_DATA_TYPES_H + +#define BLUETOOTH_DATA_TYPE_FLAGS 0x01 // Flags +#define BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS 0x02 // Incomplete List of 16-bit Service Class UUIDs +#define BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS 0x03 // Complete List of 16-bit Service Class UUIDs +#define BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS 0x04 // Incomplete List of 32-bit Service Class UUIDs +#define BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS 0x05 // Complete List of 32-bit Service Class UUIDs +#define BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS 0x06 // Incomplete List of 128-bit Service Class UUIDs +#define BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS 0x07 // Complete List of 128-bit Service Class UUIDs +#define BLUETOOTH_DATA_TYPE_SHORTENED_LOCAL_NAME 0x08 // Shortened Local Name +#define BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME 0x09 // Complete Local Name +#define BLUETOOTH_DATA_TYPE_TX_POWER_LEVEL 0x0A // Tx Power Level +#define BLUETOOTH_DATA_TYPE_CLASS_OF_DEVICE 0x0D // Class of Device +#define BLUETOOTH_DATA_TYPE_SIMPLE_PAIRING_HASH_C 0x0E // Simple Pairing Hash C +#define BLUETOOTH_DATA_TYPE_SIMPLE_PAIRING_HASH_C_192 0x0E // Simple Pairing Hash C-192 +#define BLUETOOTH_DATA_TYPE_SIMPLE_PAIRING_RANDOMIZER_R 0x0F // Simple Pairing Randomizer R +#define BLUETOOTH_DATA_TYPE_SIMPLE_PAIRING_RANDOMIZER_R_192 0x0F // Simple Pairing Randomizer R-192 +#define BLUETOOTH_DATA_TYPE_DEVICE_ID 0x10 // Device ID +#define BLUETOOTH_DATA_TYPE_SECURITY_MANAGER_TK_VALUE 0x10 // Security Manager TK Value +#define BLUETOOTH_DATA_TYPE_SECURITY_MANAGER_OUT_OF_BAND_FLAGS 0x11 // Security Manager Out of Band Flags +#define BLUETOOTH_DATA_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE 0x12 // Slave Connection Interval Range +#define BLUETOOTH_DATA_TYPE_LIST_OF_16_BIT_SERVICE_SOLICITATION_UUIDS 0x14 // List of 16-bit Service Solicitation UUIDs +#define BLUETOOTH_DATA_TYPE_LIST_OF_32_BIT_SERVICE_SOLICITATION_UUIDS 0x1F // List of 32-bit Service Solicitation UUIDs +#define BLUETOOTH_DATA_TYPE_LIST_OF_128_BIT_SERVICE_SOLICITATION_UUIDS 0x15 // List of 128-bit Service Solicitation UUIDs +#define BLUETOOTH_DATA_TYPE_SERVICE_DATA 0x16 // Service Data +#define BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID 0x16 // Service Data - 16-bit UUID +#define BLUETOOTH_DATA_TYPE_SERVICE_DATA_32_BIT_UUID 0x20 // Service Data - 32-bit UUID +#define BLUETOOTH_DATA_TYPE_SERVICE_DATA_128_BIT_UUID 0x21 // Service Data - 128-bit UUID +#define BLUETOOTH_DATA_TYPE_LE_SECURE_CONNECTIONS_CONFIRMATION_VALUE 0x22 // LE Secure Connections Confirmation Value +#define BLUETOOTH_DATA_TYPE_LE_SECURE_CONNECTIONS_RANDOM_VALUE 0x23 // LE Secure Connections Random Value +#define BLUETOOTH_DATA_TYPE_URI 0x24 // URI +#define BLUETOOTH_DATA_TYPE_INDOOR_POSITIONING 0x25 // Indoor Positioning +#define BLUETOOTH_DATA_TYPE_TRANSPORT_DISCOVERY_DATA 0x26 // Transport Discovery Data +#define BLUETOOTH_DATA_TYPE_PUBLIC_TARGET_ADDRESS 0x17 // Public Target Address +#define BLUETOOTH_DATA_TYPE_RANDOM_TARGET_ADDRESS 0x18 // Random Target Address +#define BLUETOOTH_DATA_TYPE_APPEARANCE 0x19 // Appearance +#define BLUETOOTH_DATA_TYPE_ADVERTISING_INTERVAL 0x1A // Advertising Interval +#define BLUETOOTH_DATA_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS 0x1B // LE Bluetooth Device Address +#define BLUETOOTH_DATA_TYPE_LE_ROLE 0x1C // LE Role +#define BLUETOOTH_DATA_TYPE_SIMPLE_PAIRING_HASH_C_256 0x1D // Simple Pairing Hash C-256 +#define BLUETOOTH_DATA_TYPE_SIMPLE_PAIRING_RANDOMIZER_R_256 0x1E // Simple Pairing Randomizer R-256 +#define BLUETOOTH_DATA_TYPE_3D_INFORMATION_DATA 0x3D // 3D Information Data +#define BLUETOOTH_DATA_TYPE_MANUFACTURER_SPECIFIC_DATA 0xFF // Manufacturer Specific Data + +#endif diff --git a/include_lib/btstack/le/gatt.h b/include_lib/btstack/le/gatt.h new file mode 100644 index 0000000..4172c78 --- /dev/null +++ b/include_lib/btstack/le/gatt.h @@ -0,0 +1,58 @@ +/********************************************************************************************* + * Filename : btstack_event.h + + * Description : + + * Author : Minxian + + * Email : liminxian@zh-jieli.com + + * Last modifiled : 2020-07-01 16:23 + + * Copyright:(c)JIELI 2011-2020 @ , All Rights Reserved. +*********************************************************************************************/ +#ifndef __BT_GATT_H +#define __BT_GATT_H + +#include "typedef.h" + +typedef struct { + uint16_t start_group_handle; + uint16_t end_group_handle; + uint16_t uuid16; + uint8_t uuid128[16]; +} le_service_t, gatt_client_service_t; + + +typedef struct { + uint16_t start_handle; + uint16_t value_handle; + uint16_t end_handle; + uint16_t properties; + uint16_t uuid16; + uint8_t uuid128[16]; +} le_characteristic_t, gatt_client_characteristic_t; + +typedef struct { + uint16_t handle; + uint16_t uuid16; + uint8_t uuid128[16]; +} gatt_client_characteristic_descriptor_t; + +void gatt_client_deserialize_service(const uint8_t *packet, int offset, gatt_client_service_t *service); + +void gatt_client_deserialize_characteristic(const uint8_t *packet, int offset, gatt_client_characteristic_t *characteristic); + +void gatt_client_deserialize_characteristic_descriptor(const uint8_t *packet, int offset, gatt_client_characteristic_descriptor_t *descriptor); + +uint8_t gatt_client_read_long_value_of_characteristic_using_value_handle_with_offset(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t characteristic_value_handle, uint16_t offset); + +uint8_t gatt_client_read_value_of_characteristic_using_value_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle); + +uint8_t gatt_client_write_value_of_characteristic_without_response(hci_con_handle_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t *value); + +uint8_t gatt_client_write_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t *data); + +void gatt_client_request_can_send_now_event(hci_con_handle_t con_handle); + +#endif diff --git a/include_lib/btstack/le/le_common_define.h b/include_lib/btstack/le/le_common_define.h new file mode 100644 index 0000000..daf2f71 --- /dev/null +++ b/include_lib/btstack/le/le_common_define.h @@ -0,0 +1,201 @@ +/********************************************************************************************* + * 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_DEFINE_H_ +#define __LE_COMMON_DEFINE_H_ + +#include "typedef.h" +#include +#include "btstack/bluetooth.h" + +//-------------------------------------------- + +#define ADV_SET_1M_PHY 1 +#define ADV_SET_2M_PHY 2 +#define ADV_SET_CODED_PHY 3 + +#define SCAN_SET_1M_PHY BIT(0) +#define SCAN_SET_2M_PHY BIT(1) +#define SCAN_SET_CODED_PHY BIT(2) + +#define INIT_SET_1M_PHY BIT(0) +#define INIT_SET_2M_PHY BIT(1) +#define INIT_SET_CODED_PHY BIT(2) + +#define CONN_SET_1M_PHY BIT(0) +#define CONN_SET_2M_PHY BIT(1) +#define CONN_SET_CODED_PHY BIT(2) + +#define CONN_SET_PHY_OPTIONS_NONE 0 +#define CONN_SET_PHY_OPTIONS_S2 1 +#define CONN_SET_PHY_OPTIONS_S8 2 + +struct conn_param_t { + u16 interval; + u16 latency; + u16 timeout; +}; + +// #define NOTIFY_TYPE 1 +// #define INDICATION_TYPE 2 +// Minimum/default MTU + +#define ATT_CTRL_BLOCK_SIZE (188) //note: fixed,libs use +#define ATT_PACKET_HEAD_SIZE (6) //note: fixed,libs use + +/*adv type*/ +enum { + ADV_IND = 0, /*Connectable and scannable undirected advertising*/ + ADV_DIRECT_IND, /*Connectable high duty cycle directed advertising */ + ADV_SCAN_IND, /*Scannable undirected advertising*/ + ADV_NONCONN_IND, /*Non connectable undirected advertising*/ + ADV_DIRECT_IND_LOW, /*Connectable low duty cycle directed advertising*/ +}; + + +/*adv channel*/ +#define ADV_CHANNEL_37 BIT(0) +#define ADV_CHANNEL_38 BIT(1) +#define ADV_CHANNEL_39 BIT(2) +#define ADV_CHANNEL_ALL (ADV_CHANNEL_37 | ADV_CHANNEL_38 | ADV_CHANNEL_39) + +/*scan type*/ +enum { + SCAN_PASSIVE = 0, + SCAN_ACTIVE, +}; + +/*advertising report,event type*/ +#define EVENT_ADV_IND ADV_IND +#define EVENT_ADV_DIRECT_IND ADV_DIRECT_IND +#define EVENT_ADV_SCAN_IND ADV_SCAN_IND +#define EVENT_ADV_NONCONN_IND ADV_NONCONN_IND +#define EVENT_SCAN_RSP (4) + +#define EVENT_DEFAULT_REPORT_BITMAP (0x1f) + + +/*flags*/ +#define FLAGS_LIMITED_DISCOVERABLE_MODE BIT(0) +#define FLAGS_GENERAL_DISCOVERABLE_MODE BIT(1) +#define FLAGS_EDR_NOT_SUPPORTED BIT(2) +#define FLAGS_LE_AND_EDR_SAME_CONTROLLER BIT(3) +#define FLAGS_LE_AND_EDR_SAME_HOST BIT(4) + +/*eir packet_type*/ +typedef enum { + HCI_EIR_DATATYPE_FLAGS = 0x01, + HCI_EIR_DATATYPE_MORE_16BIT_SERVICE_UUIDS = 0x02, + HCI_EIR_DATATYPE_COMPLETE_16BIT_SERVICE_UUIDS = 0x03, + HCI_EIR_DATATYPE_MORE_32BIT_SERVICE_UUIDS = 0x04, + HCI_EIR_DATATYPE_COMPLETE_32BIT_SERVICE_UUIDS = 0x05, + HCI_EIR_DATATYPE_MORE_128BIT_SERVICE_UUIDS = 0x06, + HCI_EIR_DATATYPE_COMPLETE_128BIT_SERVICE_UUIDS = 0x07, + HCI_EIR_DATATYPE_SHORTENED_LOCAL_NAME = 0x08, + HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME = 0x09, + HCI_EIR_DATATYPE_TX_POWER_LEVEL = 0x0A, + HCI_EIR_DATATYPE_CLASS_OF_DEVICE = 0x0D, + HCI_EIR_DATATYPE_SIMPLE_PAIRING_HASH_C = 0x0E, + HCI_EIR_DATATYPE_SIMPLE_PAIRING_RANDOMIZER_R = 0x0F, + HCI_EIR_DATATYPE_SECURITY_MANAGER_TK_VALUE = 0x10, + HCI_EIR_DATATYPE_SECURITY_MANAGER_OOB_FLAGS = 0x11, + HCI_EIR_DATATYPE_SLAVE_CONNECTION_INTERVAL_RANGE = 0x12, + HCI_EIR_DATATYPE_16BIT_SERVICE_SOLICITATION_UUIDS = 0x14, + HCI_EIR_DATATYPE_128BIT_SERVICE_SOLICITATION_UUIDS = 0x15, + HCI_EIR_DATATYPE_SERVICE_DATA = 0x16, + HCI_EIR_DATATYPE_APPEARANCE_DATA = 0x19, + HCI_EIR_DATATYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF +} HCI_EIR_datatype_t; + + +//按(长度 + 类型 + 内容)这样的格,组合填入广播包数据 +static inline u8 make_eir_packet_data(u8 *buf, u16 offset, u8 data_type, u8 *data, u8 data_len) +{ + if (ADV_RSP_PACKET_MAX - offset < data_len + 2) { + return offset + data_len + 2; + } + + buf[0] = data_len + 1; + buf[1] = data_type; + memcpy(buf + 2, data, data_len); + return data_len + 2; +} + +//按(长度 + 类型 + 内容)这样的格,组合填入广播包数据 +static inline u8 make_eir_packet_val(u8 *buf, u16 offset, u8 data_type, u32 val, u8 val_size) +{ + if (ADV_RSP_PACKET_MAX - offset < val_size + 2) { + return offset + val_size + 2; + } + + buf[0] = val_size + 1; + buf[1] = data_type; + memcpy(buf + 2, &val, val_size); + return val_size + 2; +} + +#define BLE_APPEARANCE_UNKNOWN 0 /**< Unknown. */ +#define BLE_APPEARANCE_GENERIC_PHONE 64 /* Generic Phone. */ +#define BLE_APPEARANCE_GENERIC_COMPUTER 128 /* Generic Computer. */ +#define BLE_APPEARANCE_GENERIC_WATCH 192 /* Generic Watch. */ +#define BLE_APPEARANCE_WATCH_SPORTS_WATCH 193 /* Watch: Sports Watch. */ +#define BLE_APPEARANCE_GENERIC_CLOCK 256 /* Generic Clock. */ +#define BLE_APPEARANCE_GENERIC_DISPLAY 320 /* Generic Display. */ +#define BLE_APPEARANCE_GENERIC_REMOTE_CONTROL 384 /* Generic Remote Control. */ +#define BLE_APPEARANCE_GENERIC_EYE_GLASSES 448 /* Generic Eye-glasses. */ +#define BLE_APPEARANCE_GENERIC_TAG 512 /* Generic Tag. */ +#define BLE_APPEARANCE_GENERIC_KEYRING 576 /* Generic Keyring. */ +#define BLE_APPEARANCE_GENERIC_MEDIA_PLAYER 640 /* Generic Media Player. */ +#define BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 704 /* Generic Barcode Scanner. */ +#define BLE_APPEARANCE_GENERIC_THERMOMETER 768 /* Generic Thermometer. */ +#define BLE_APPEARANCE_THERMOMETER_EAR 769 /* Thermometer: Ear. */ +#define BLE_APPEARANCE_GENERIC_HEART_RATE_SENSOR 832 /* Generic Heart rate Sensor. */ +#define BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT 833 /* Heart Rate Sensor: Heart Rate Belt. */ +#define BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE 896 /* Generic Blood Pressure. */ +#define BLE_APPEARANCE_BLOOD_PRESSURE_ARM 897 /* Blood Pressure: Arm. */ +#define BLE_APPEARANCE_BLOOD_PRESSURE_WRIST 898 /* Blood Pressure: Wrist. */ +#define BLE_APPEARANCE_GENERIC_HID 960 /* Human Interface Device (HID). */ +#define BLE_APPEARANCE_HID_KEYBOARD 961 /* Keyboard (HID Subtype). */ +#define BLE_APPEARANCE_HID_MOUSE 962 /* Mouse (HID Subtype). */ +#define BLE_APPEARANCE_HID_JOYSTICK 963 /* Joystick (HID Subtype). */ +#define BLE_APPEARANCE_HID_GAMEPAD 964 /* Gamepad (HID Subtype). */ +#define BLE_APPEARANCE_HID_DIGITIZERSUBTYPE 965 /* Digitizer Tablet (HID Subtype). */ +#define BLE_APPEARANCE_HID_CARD_READER 966 /* Card Reader (HID Subtype). */ +#define BLE_APPEARANCE_HID_DIGITAL_PEN 967 /* Digital Pen (HID Subtype). */ +#define BLE_APPEARANCE_HID_BARCODE 968 /* Barcode Scanner (HID Subtype). */ +#define BLE_APPEARANCE_GENERIC_GLUCOSE_METER 1024 /* Generic Glucose Meter. */ +#define BLE_APPEARANCE_GENERIC_RUNNING_WALKING_SENSOR 1088 /* Generic Running Walking Sensor. */ +#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_IN_SHOE 1089 /* Running Walking Sensor: In-Shoe. */ +#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_SHOE 1090 /* Running Walking Sensor: On-Shoe. */ +#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_HIP 1091 /* Running Walking Sensor: On-Hip. */ +#define BLE_APPEARANCE_GENERIC_CYCLING 1152 /* Generic Cycling. */ +#define BLE_APPEARANCE_CYCLING_CYCLING_COMPUTER 1153 /* Cycling: Cycling Computer. */ +#define BLE_APPEARANCE_CYCLING_SPEED_SENSOR 1154 /* Cycling: Speed Sensor. */ +#define BLE_APPEARANCE_CYCLING_CADENCE_SENSOR 1155 /* Cycling: Cadence Sensor. */ +#define BLE_APPEARANCE_CYCLING_POWER_SENSOR 1156 /* Cycling: Power Sensor. */ +#define BLE_APPEARANCE_CYCLING_SPEED_CADENCE_SENSOR 1157 /* Cycling: Speed and Cadence Sensor. */ +#define BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 3136 /* Generic Pulse Oximeter. */ +#define BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 3137 /* Fingertip (Pulse Oximeter subtype). */ +#define BLE_APPEARANCE_PULSE_OXIMETER_WRIST_WORN 3138 /* Wrist Worn(Pulse Oximeter subtype). */ +#define BLE_APPEARANCE_GENERIC_WEIGHT_SCALE 3200 /* Generic Weight Scale. */ +#define BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS_ACT 5184 /* Generic Outdoor Sports Activity. */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_DISP 5185 /* Location Display Device (Outdoor Sports Activity subtype). */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_DISP 5186 /* Location and Navigation Display Device (Outdoor Sports Activity subtype). */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_POD 5187 /* Location Pod (Outdoor Sports Activity subtype). */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_POD 5188 /* Location and Navigation Pod (Outdoor Sports Activity subtype). */ + +extern void le_l2cap_register_packet_handler(void (*handler)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)); +#endif + + diff --git a/include_lib/btstack/le/le_user.h b/include_lib/btstack/le/le_user.h new file mode 100644 index 0000000..4efe95e --- /dev/null +++ b/include_lib/btstack/le/le_user.h @@ -0,0 +1,140 @@ + +#ifndef _LE_USER_H_ +#define _LE_USER_H_ + +#include "typedef.h" +#include "btstack/btstack_typedef.h" +#include "ble_api.h" + +#if defined __cplusplus +extern "C" { +#endif + + + +#define BT_NAME_LEN_MAX 29 +#define ADV_RSP_PACKET_MAX 31 + +// hci con handles (12 bit): 0x0000..0x0fff +#define HCI_CON_HANDLE_INVALID 0xffff + +#define BTSTACK_EVENT_STATE 0x60 +#define L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE 0x77 + +#define SM_EVENT_NUMERIC_COMPARISON_REQUEST 0xD6 + +#define SM_EVENT_JUST_WORKS_REQUEST 0xD0 +#define SM_EVENT_JUST_WORKS_CANCEL 0xD1 +#define SM_EVENT_PASSKEY_DISPLAY_NUMBER 0xD2 +#define SM_EVENT_PASSKEY_DISPLAY_CANCEL 0xD3 +#define SM_EVENT_PASSKEY_INPUT_NUMBER 0xD4 +#define SM_EVENT_PASSKEY_INPUT_CANCEL 0xD5 +#define SM_EVENT_PAIR_PROCESS 0xDF +//0xdf 's sub +#define SM_EVENT_PAIR_SUB_RECONNECT_START 0x01 +#define SM_EVENT_PAIR_SUB_PIN_KEY_MISS 0x02 +#define SM_EVENT_PAIR_SUB_PAIR_FAIL 0x03 +#define SM_EVENT_PAIR_SUB_PAIR_TIMEOUT 0x04 +#define SM_EVENT_PAIR_SUB_ENCRYPTION_FAIL 0x05 +#define SM_EVENT_PAIR_SUB_SEND_DISCONN 0x0f +#define SM_EVENT_PAIR_SUB_ADD_LIST_SUCCESS 0x10 +#define SM_EVENT_PAIR_SUB_ADD_LIST_FAILED 0x11 + + +#define GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NONE 0 +#define GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION 1 +#define GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_INDICATION 2 + + +#define GATT_EVENT_NOTIFICATION 0xA7 +#define GATT_EVENT_INDICATION 0xA8 +#define GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT 0xA5 +#define GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT 0xA6 +// #define GATT_EVENT_SERVICE_QUERY_RESULT 0xA1 +// #define GATT_EVENT_CHARACTERISTIC_QUERY_RESULT 0xA2 +#define GATT_EVENT_QUERY_COMPLETE 0xA0 +#define GAP_EVENT_ADVERTISING_REPORT 0xE2 + +// Authentication requirement flags +#define SM_AUTHREQ_NO_BONDING 0x00 +#define SM_AUTHREQ_BONDING 0x01 +#define SM_AUTHREQ_MITM_PROTECTION 0x04 +#define SM_AUTHREQ_SECURE_CONNECTION 0x08 +#define SM_AUTHREQ_KEYPRESS 0x10 +#define SM_AUTHREQ_CT2 0x20 + + +#define L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE 0x77 + + +#define BT_OP_SUCCESS 0x00 +#define BT_ERR_ADVERTISING_TIMEOUT 0x3C + + +//-------------------------------------------- + + struct ble_server_operation_t { + int(*adv_enable)(void *priv, u32 enable); + int(*disconnect)(void *priv); + int(*get_buffer_vaild)(void *priv); + int(*send_data)(void *priv, void *buf, u16 len); + int(*regist_wakeup_send)(void *priv, void *cbk); + int(*regist_recieve_cbk)(void *priv, void *cbk); + int(*regist_state_cbk)(void *priv, void *cbk); + int(*latency_enable)(void *priv, u32 enable); + }; + + void ble_get_server_operation_table(struct ble_server_operation_t **interface_pt); + +//-------------------------------------------- + + struct ble_client_operation_t { + int(*scan_enable)(void *priv, u32 enable); + int(*disconnect)(void *priv); + int(*get_buffer_vaild)(void *priv); + int(*write_data)(void *priv, void *buf, u16 len); + int(*read_do)(void *priv); + int(*regist_wakeup_send)(void *priv, void *cbk); + int(*regist_recieve_cbk)(void *priv, void *cbk); + int(*regist_state_cbk)(void *priv, void *cbk); + int (*init_config)(void *priv, void *cfg); + int (*opt_comm_send)(u16 handle, u8 *data, u16 len, u8 att_op_type); + int (*set_force_search)(u8 onoff, s8 rssi); + int (*create_connect)(u8 *addr, u8 addr_type, u8 mode); + int (*create_connect_cannel)(void); + int (*get_work_state)(void); + int (*opt_comm_send_ext)(u16 conn_handle, u16 handle, u8 *data, u16 len, u8 att_op_type); + }; + + struct ble_client_operation_t *ble_get_client_operation_table(void); + + + static inline uint32_t ble_min(uint32_t a, uint32_t b) + { + return a < b ? a : b; + } + +//--------------------------------------------------------------------------------------------------- + + +//---------------------------------------- +//---------------------------------------- + + + + extern int get_ble_btstack_state(void); + extern int get_indicate_state(void); + + + extern u8 get_ble_local_name(u8 *name_buf); + extern u8 get_ble_local_name_len(); + + + + + extern void hci_event_callback_set(void(*cbk_ph)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)); + extern void ll_hci_connection_updata(u8 *data); + +#endif + + diff --git a/include_lib/btstack/le/sm.h b/include_lib/btstack/le/sm.h new file mode 100644 index 0000000..66104ed --- /dev/null +++ b/include_lib/btstack/le/sm.h @@ -0,0 +1,69 @@ +/********************************************************************************************* + * Filename : sm.h + + * Description : + + * Author : Minxian + + * Email : liminxian@zh-jieli.com + + * Last modifiled : 2020-07-01 16:36 + + * Copyright:(c)JIELI 2011-2020 @ , All Rights Reserved. +*********************************************************************************************/ +#ifndef _BT_SM_H_ +#define _BT_SM_H_ + +#include "typedef.h" + +// IO Capability Values +typedef enum { + IO_CAPABILITY_DISPLAY_ONLY = 0, + IO_CAPABILITY_DISPLAY_YES_NO, + IO_CAPABILITY_KEYBOARD_ONLY, + IO_CAPABILITY_NO_INPUT_NO_OUTPUT, + IO_CAPABILITY_KEYBOARD_DISPLAY, // not used by secure simple pairing +} io_capability_t; + +void ble_sm_setup_init(io_capability_t io_type, u8 auth_req, uint8_t min_key_size, u8 security_en); + +void ble_cbk_handler_register(btstack_packet_handler_t packet_cbk, sm_stack_packet_handler_t sm_cbk); + +void sm_just_works_confirm(hci_con_handle_t con_handle); + +void sm_init(void); + +/*接口同时设置master 和 slave的配置*/ +void sm_set_io_capabilities(io_capability_t io_capability); + +/*接口只设置master配置*/ +void sm_set_master_io_capabilities(io_capability_t io_capability); + +/*接口同时设置master 和 slave的配置*/ +void sm_set_authentication_requirements(uint8_t auth_req); + +/*接口只设置master配置*/ +void sm_set_master_authentication_requirements(uint8_t auth_req); + +void sm_set_encryption_key_size_range(uint8_t min_size, uint8_t max_size); + +void sm_set_request_security(int enable); + +void sm_event_callback_set(void(*cbk_sm_ph)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)); + +//配从机默认发请求加密命令 +void sm_set_request_security(int enable); + +//配主机默认发加密请求命令 +void sm_set_master_request_pair(int enable); + +//指定链接发加密请求命令 +bool sm_api_request_pairing(hci_con_handle_t con_handle); + +//设置回连出现key missing后,流程重新发起加密 +void sm_set_master_pair_redo(int enable); + +//设置回连时,延时发起加密流程的时间,可用于兼容一些设备连接 +void sm_set_master_reconnect_enc_delay(u16 delay_ms); +void sm_passkey_input(hci_con_handle_t con_handle, uint32_t passkey); +#endif diff --git a/include_lib/btstack/third_party/app_protocol_event.h b/include_lib/btstack/third_party/app_protocol_event.h new file mode 100644 index 0000000..42b621d --- /dev/null +++ b/include_lib/btstack/third_party/app_protocol_event.h @@ -0,0 +1,136 @@ + + +#ifndef _3TH_PROTOCOL_EVENT_H +#define _3TH_PROTOCOL_EVENT_H + +//该文件只定义库里面和库外面都需要用得的第三方APP协议的消息和状态 +#include +#include +#include "typedef.h" + +#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 protocol公共消息 +enum { + APP_PROTOCOL_COMMON_NOTICE = 0, + APP_PROTOCOL_CONNECTING, /*保留,暂未使用*/ + APP_PROTOCOL_CONNECTED_BLE, /*APP通过BLE连接成功状态更新*/ + APP_PROTOCOL_CONNECTED_SPP, /*APP通过SPP连接成功状态更新*/ + APP_PROTOCOL_DISCONNECT, /*APP连接断开状态更新*/ + APP_PROTOCOL_AUTH_PASS, /*连接认证通过标识更新*/ + APP_PROTOCOL_SPEECH_ENCODER_TYPE, + APP_PROTOCOL_SPEECH_START, /*语音识别功能启动状态*/ + APP_PROTOCOL_SPEECH_STOP, /*语音识别功能停止状态*/ + APP_PROTOCOL_SET_VOLUME, /*app配置音量*/ + APP_PROTOCOL_GET_VOLUME, /*app读取音量*/ + APP_PROTOCOL_GET_AUX_STATUS, /*保留,暂未使用*/ + APP_PROTOCOL_LIB_TWS_DATA_SYNC, /*需要更新给另一端tws数据*/ + APP_PROTOCOL_COMMON_NOTICE_END = 0x14F, +}; +//OTA消息 +enum { + APP_PROTOCOL_OTA_COMMON_NOTICE = APP_PROTOCOL_COMMON_NOTICE_END + 1, + APP_PROTOCOL_OTA_CHECK, + APP_PROTOCOL_OTA_GET_APP_VERSION, + APP_PROTOCOL_OTA_CHECK_CRC, + APP_PROTOCOL_OTA_BEGIN, + APP_PROTOCOL_OTA_TRANS_DATA, + APP_PROTOCOL_OTA_PERCENT, + APP_PROTOCOL_OTA_END, + APP_PROTOCOL_OTA_SUCCESS, + APP_PROTOCOL_OTA_FAIL, + APP_PROTOCOL_OTA_CANCLE, + APP_PROTOCOL_OTA_REBOOT, + APP_PROTOCOL_OTA_COMMON_NOTICE_END = 0x1FF, +}; +//GMA私有消息 +enum { + APP_PROTOCOL_GMA_NOTICE_BEGIN = GMA_HANDLER_ID, + APP_PROTOCOL_GMA_FMTX_SETFRE, /*样机支持FM功能的APP配置fm参数*/ + APP_PROTOCOL_GMA_FMTX_GETFRE, /*app获取当前的fm配置参数*/ + APP_PROTOCOL_GMA_NOTICE_END = GMA_HANDLER_ID + 0xFF, +}; +//MMA私有消息 +enum { + APP_PROTOCOL_MMA_NOTICE = MMA_HANDLER_ID, + APP_PROTOCOL_MMA_SAVE_INFO, //库里面不直接访问VM接口,有些信息保存外面做 + APP_PROTOCOL_MMA_READ_INFO, + APP_PROTOCOL_MMA_SAVE_ADV_COUNTER, + APP_PROTOCOL_MMA_READ_ADV_COUNTER, + APP_PROTOCOL_MMA_NOTICE_END = MMA_HANDLER_ID + 0xFF, +}; + +//DMA私有消息 +enum { + APP_PROTOCOL_DMA_NOTICE = DMA_HANDLER_ID, + APP_PROTOCOL_DMA_SAVE_RAND, //库里面不直接访问VM接口,有些信息保存外面做 + APP_PROTOCOL_DMA_READ_RAND, + APP_PROTOCOL_DMA_TWS_SNED_RAND, + APP_PROTOCOL_DMA_TTS_TYPE, + APP_PROTOCOL_DMA_SAVE_OTA_INFO, //库里面不直接访问VM接口,有些信息保存外面做 + APP_PROTOCOL_DMA_READ_OTA_INFO, + APP_PROTOCOL_DMA_NOTICE_END = DMA_HANDLER_ID + 0xFF, +}; + +// GFPS私有消息 +enum { + APP_PROTOCOL_GFPS_RING_STOP_ALL = GFPS_HANDLER_ID, + APP_PROTOCOL_GFPS_RING_RIGHT, + APP_PROTOCOL_GFPS_RING_LEFT, + APP_PROTOCOL_GFPS_RING_ALL, + APP_PROTOCOL_GFPS_HEARABLE_CONTROLS, +}; + +#define GFP_TWS_ENABLE 1 + +//APP_PROTOCOL获取电量的类型 +#define APP_PROTOCOL_BAT_T_CHARGE_FLAG 0 +#define APP_PROTOCOL_BAT_T_MAIN 1 +#define APP_PROTOCOL_BAT_T_BOX 2 +#define APP_PROTOCOL_BAT_T_TWS_LEFT 3 +#define APP_PROTOCOL_BAT_T_TWS_RIGHT 4 +#define APP_PROTOCOL_BAT_T_TWS_SIBLING 5 +#define APP_PROTOCOL_BAT_T_LOW_POWER 6 +#define APP_PROTOCOL_BAT_T_MAX 8 + +typedef struct _ota_frame_info_t { + u16 max_pkt_len; + u16 frame_crc; + u32 frame_size; +} ota_frame_info; + +//*****// +typedef enum { + USER_NOTIFY_STATE_CONNECTED = 0, /**< 手机APP与设备建立连接 */ + USER_NOTIFY_STATE_DISCONNECTED, /**< 手机APP与设备的连接断开 */ + USER_NOTIFY_STATE_MOBILE_CONNECTED, /**< 手机与设备建立BT连接(A2DP、HFP、AVRCP) */ + USER_NOTIFY_STATE_MOBILE_DISCONNECTED, /**< 手机与设备BT连接(A2DP、HFP、AVRCP)断开 */ + USER_NOTIFY_STATE_SEND_PREPARE_DONE, /**< 设备端进入可向手机发送数据的状态 */ + USER_NOTIFY_STATE_TWS_CONNECT, /**< TWS类设备两端连接成功 */ + USER_NOTIFY_STATE_TWS_DISCONNECT, /**< TWS类设备两端断开连接 */ + USER_NOTIFY_STATE_BOX_OPEN, /**< 盒仓开启 */ + USER_NOTIFY_STATE_BOX_CLOSE, /**< 盒仓关闭 */ + USER_NOTIFY_STATE_ROLE_SWITCH_START, /**< TWS类设备开始进入主从切换流程 */ + USER_NOTIFY_STATE_ROLE_SWITCH_FINISH, /**< TWS类设备主从切换完成 */ + USER_NOTIFY_STATE_ROLE_SWITCH_REQUEST, /**< TWS类设备向APP发起主从切换请求 */ + USER_NOTIFY_STATE_DOUBLE_CLICK, /**< 设备双击按键 */ + USER_NOTIFY_STATE_KEYWORD_DETECTED, /**< 设备语音唤醒 */ + USER_NOTIFY_STATE_BATTERY_LEVEL_UPDATE, /**< 通知耳机电量更新 */ + USER_NOTIFY_STATE_ONE_CLICK, /**< 设备单击按键 */ +} USER_NOTIFY_STATE; + +typedef enum { + /*尽量返回简单的1或者0*/ + CHECK_STATUS_TWS_MASTER, + CHECK_STATUS_TWS_SLAVE, + CHECK_STATUS_TWS_PAIR_STA, /*1是tws已经配对了,0是未配对*/ + CHECK_STATUS_TWS_SIDE, /*0是单耳,1是左耳,2是右耳*/ + CHECK_STATUS_TWS_REV, + CHECK_STATUS_TWS_REV1, +} CHECK_STATUS; +#endif diff --git a/include_lib/btstack/third_party/app_protocol_libs_api.h b/include_lib/btstack/third_party/app_protocol_libs_api.h new file mode 100644 index 0000000..6f91769 --- /dev/null +++ b/include_lib/btstack/third_party/app_protocol_libs_api.h @@ -0,0 +1,146 @@ + +#ifndef __APP_PRO_LIBS_API_H__ +#define __APP_PRO_LIBS_API_H__ + +#include "typedef.h" + + +///***************************************/// +//GMA的函数接口汇集,begin +int gma_prev_init(void); +int gma_opus_voice_mic_send(uint8_t *voice_buf, uint16_t voice_len); +/*gma的总初始化函数**/ +void gma_all_init(void); +/*gma的总的释放函数**/ +void gma_all_exit(void); +bool gma_connect_success(void); +void gma_set_active_ali_para(void *addr); +/*TWS的公共地址配置*/ +void gma_set_sibling_mac_para(void *mac); +void gma_ble_adv_enable(u8 enable); +void gma_ble_ibeacon_adv(u8 enable); +//gma接收的数据处理函数 +int gma_rx_loop(void); +/*gma命令和数据发送处理*/ +int tm_data_send_process_thread(void); +int gma_start_voice_recognition(int flag); + + +int gma_disconnect(void *addr); + +void gma_message_callback_register(int (*handler)(int opcode, u8 *data, u32 len)); +void gma_is_tws_master_callback_register(bool (*handler)(void)); +void gma_tx_resume_register(bool (*handler)(void)); +void gma_rx_resume_register(bool (*handler)(void)); +/*注册电量的获取回调函数*/ +void gma_get_battery_callback_register(bool (*handler)(u8 battery_type, u8 *value)); + +//ota interface +int gma_ota_requset_next_packet(void *priv, u32 offset, u16 len); +void gma_replay_ota_result(u8 result); + +int tws_ota_get_data_from_sibling(u8 opcode, u8 *data, u8 len); +u8 tws_ota_control(int type, ...); +void tws_ota_app_event_deal(u8 evevt); +//gma apis ends + +///***************************************/// +//DMA apis begin +extern int dueros_process(); +extern int dma_all_init(void); +extern int dma_all_exit(void); +extern void dma_message_callback_register(int (*handler)(int id, int opcode, u8 *data, u32 len)); +extern void dma_check_status_callback_register(int (*handler)(int state_flag)); +extern void dma_tx_resume_register(bool (*handler)(void)); +extern void dma_rx_resume_register(bool (*handler)(void)); +extern void dma_ble_adv_enable(u8 enable); +extern u16 dma_speech_data_send(u8 *buf, u16 len); +extern int dueros_send_process(void); +extern void dma_set_product_id_key(void *data); +extern bool dma_pair_state(); +extern int dma_start_voice_recognition(u8 en); +extern void dueros_dma_manufacturer_info_init(); +extern int dma_disconnect(void *addr); +extern int dma_update_tws_state_to_lib(int state); +extern void dma_get_battery_callback_register(bool (*handler)(u8 battery_type, u8 *value)); +extern void dma_set_pid(u32 pid); +extern void dma_tws_data_deal(u8 *data, int len); + + +//DMA apis ends + +///***************************************/// +//TME apis begins +extern void tme_get_battery_callback_register(bool (*handler)(u8 battery_type, u8 *value)); +extern void tme_message_callback_register(int (*handler)(int id, int opcode, const u8 *data, u32 len)); +extern void tme_is_tws_master_callback_register(bool (*handler)(void)); +extern void tme_tx_resume_register(bool (*handler)(void)); +extern void tme_rx_resume_register(bool (*handler)(void)); +extern void TME_protocol_process(void *parm); +extern int tme_all_init(void); +extern int tme_all_exit(void); +/* extern u16 tme_speech_data_send(buf, len); */ +extern void tme_ble_adv_enable(u8 enable); +extern void TME_send_packet_process(void); +extern void TME_recieve_packet_parse_process(void); +extern bool tme_connect_success(void); +extern int tme_send_voice_data(void *buf, u16 len); +extern int tme_start_voice_recognition(int flag); +extern void tme_set_configuration_info(void *addr); +extern int tme_protocol_disconnect(void *priv); +extern void tme_set_pid(u32 pid); +extern void tme_set_bid(u32 bid); +extern u32 TME_request_ota_data(void *priv, u32 offset, u16 len); +extern void TME_notify_file_size(u32 file_size); + +//TME api ends + +///***************************************/// +//MMA api begins +extern void mma_all_init(void); +extern void mma_all_exit(void); +extern void mma_ble_adv_enable(u8 enable); +extern int XM_speech_data_send(u8 *buf, u16 len); +extern bool XM_protocal_auth_pass(void); +extern int mma_start_voice_recognition(int ctrl); +extern void mma_message_callback_register(int (*handler)(int id, int opcode, u8 *data, u32 len)); +extern void mma_is_tws_master_callback_register(bool (*handler)(void)); +extern void mma_tx_resume_register(void (*handler)(void)); +extern void mma_rx_resume_register(void (*handler)(void)); +extern void mma_set_verdor_id(u16 pid); +extern void mma_set_product_id(u16 pid); +extern void mma_set_local_version(u16 version); +extern int mma_protocol_loop_process(); +extern u32 mma_request_ota_data(void *priv, u32 offset, u16 len); +extern int mma_notify_file_size(u32 size); +extern u32 mma_report_ota_status(u8 state); +extern int mma_disconnect(void *addr); +extern void mma_tws_data_deal(u8 *data, int len); +extern void mma_get_battery_callback_register(bool (*handler)(u8 battery_type, u8 *value)); + +//MMA API END + +///***************************************/// +//GFPS apis begins +extern int gfps_all_init(); +extern int gfps_all_exit(); +extern int gfps_disconnect(void); +extern int gfps_ble_adv_enable(int enable); +extern void gfps_set_model_id(uint8_t *model_id); +extern void gfps_set_anti_spoofing_public_key(char *public_key); +extern void gfps_set_anti_spoofing_private_key(char *private_key); +extern void gfps_get_battery_callback_register(bool (*handler)(u8 battery_type, u8 *value)); +extern void gfps_message_callback_register(int (*handler)(int id, int opcode, u8 *data, u32 len)); +extern void gfps_set_pair_mode(void); +extern void gfps_battery_update(void); +extern void gfps_personalized_name_set(u8 *data, u8 len); +extern void gfps_is_tws_master_callback_register(bool (*handler)(void)); +extern void gfps_tws_data_deal(u8 *data, int len); +extern int gfps_update_tws_state_to_lib(int state); +extern void gfps_factory_reset(void); +extern void gfps_set_battery_ui_enable(uint8_t enable); +extern void update_channel_map_do_in_irq_flag_set(uint8_t en); +//GFPS API END +#endif /* __APP_PRO_LIBS_API_H__ */ + + diff --git a/include_lib/btstack/third_party/common/ble_config.h b/include_lib/btstack/third_party/common/ble_config.h new file mode 100644 index 0000000..b38e9bb --- /dev/null +++ b/include_lib/btstack/third_party/common/ble_config.h @@ -0,0 +1,15 @@ +#ifndef __BLE_CONFIG_H__ +#define __BLE_CONFIG_H__ + +#include "typedef.h" +#include "ble_user.h" + +bool bt_3th_ble_ready(void *priv); +s32 bt_3th_ble_send(void *priv, void *data, u16 len); +void bt_3th_ble_callback_set(void (*resume)(void), void (*recieve)(void *, void *, u16), void (*status)(void *, ble_state_e)); +void bt_3th_ble_status_callback(void *priv, ble_state_e status); +int bt_3th_ble_data_send(void *priv, u8 *buf, u16 len); +void bt_3th_ble_get_operation_table(void); +ble_state_e bt_3th_get_jl_ble_status(void); + +#endif//__BLE_CONFG_H__ diff --git a/include_lib/btstack/third_party/common/ble_user.h b/include_lib/btstack/third_party/common/ble_user.h new file mode 100644 index 0000000..2fe78a5 --- /dev/null +++ b/include_lib/btstack/third_party/common/ble_user.h @@ -0,0 +1,43 @@ +#ifndef __BLE_USER_H__ +#define __BLE_USER_H__ + +#include "typedef.h" + +typedef enum { + BLE_ST_NULL = 0, + BLE_ST_INIT_OK, //协议栈初始化ok + BLE_ST_IDLE, //关闭广播或扫描状态 + BLE_ST_CONNECT, //链路刚连上 + BLE_ST_SEND_DISCONN, //发送断开命令,等待链路断开 + BLE_ST_DISCONN, //链路断开状态 + BLE_ST_CONNECT_FAIL, //连接失败 + BLE_ST_CONNECTION_UPDATE_OK,//更新连接参数完成 + + BLE_ST_ADV = 0x20, //设备处于广播状态 + BLE_ST_NOTIFY_IDICATE, //设备已连上,允许发数(已被主机使能通知) + + BLE_ST_SCAN = 0x40, //设备处于搜索状态 + BLE_ST_CREATE_CONN, //发起设备连接 + BLE_ST_SEND_CREATE_CONN_CANNEL, //取消发起设备连接 + BLE_ST_SEARCH_COMPLETE, //链路连上,已搜索完profile,可以发送数据操作 + + BLE_ST_SEND_STACK_EXIT = 0x60, //发送退出协议栈命令,等待完成 + BLE_ST_STACK_EXIT_COMPLETE, //协议栈退出成功 + +} ble_state_e; + +enum { + APP_BLE_NO_ERROR = 0, + APP_BLE_BUFF_FULL, //buffer 满,会丢弃当前发送的数据包 + APP_BLE_BUFF_ERROR, // + APP_BLE_OPERATION_ERROR, //操作错误 + APP_BLE_IS_DISCONN, //链路已断开 + APP_BLE_NO_WRITE_CCC, //主机没有 write Client Characteristic Configuration +}; + +struct BLE_CONFIG_VAR { + ble_state_e JL_ble_status; + struct ble_server_operation_t *rcsp_ble; +}; + +#endif//__BLE_USER_H__ diff --git a/include_lib/btstack/third_party/common/btstack_3th_protocol_user.h b/include_lib/btstack/third_party/common/btstack_3th_protocol_user.h new file mode 100644 index 0000000..7f465c0 --- /dev/null +++ b/include_lib/btstack/third_party/common/btstack_3th_protocol_user.h @@ -0,0 +1,72 @@ +#ifndef __BTSTACK_3TH_PROTOCAL_H__ +#define __BTSTACK_3TH_PROTOCAL_H__ + +#include "spp_config.h" +#include "ble_config.h" +#include "JL_rcsp_api.h" +#include "JL_rcsp_protocol.h" +#include "JL_rcsp_packet.h" +#include "attr.h" + + +#define APP_TYPE_RCSP 0x01 +#define APP_TYPE_DUEROS 0x02 +#define APP_TYPE_BTSTACK 0xFF + + +#define BT_CONFIG_BLE BIT(0) +#define BT_CONFIG_SPP BIT(1) + +typedef enum { + BT_3TH_EVENT_COMMON_INIT, + BT_3TH_EVENT_COMMON_BLE_STATUS, + BT_3TH_EVENT_COMMON_SPP_STATUS, + + BT_3TH_EVENT_RCSP_DEV_SELECT = 100, + + + + + BT_3TH_EVENT_DUEROS_CONNECT = 200, + + +} BT_3TH_EVENT_TYPE; +/* +enum { + RCSP_BLE, + RCSP_SPP, +}; +*/ + +typedef struct __BT_3TH_USER_CB { + int type; + int bt_config; + JL_PRO_CB bt_3th_handler; + void (*BT_3TH_event_handler)(u16 opcode, u8 *packet, int size); + void (*BT_3TH_data_handler)(u8 *packet, int size); + int (*BT_3TH_spp_state_specific)(u8 type); +} BT_3TH_USER_CB; + +typedef struct __BT_3TH_PROTOCOL_CB { + int type; + void (*BT_3TH_type_dev_select)(u8 type); + void (*resume)(void); + void (*recieve)(void *, void *, u16); +} BT_3TH_PROTOCOL_CB; + +int btstack_3th_protocol_user_init(BT_3TH_USER_CB *protocol_callback); +int btstack_3th_protocol_lib_init(BT_3TH_PROTOCOL_CB *protocol_lib_callback); + +JL_PRO_CB *bt_3th_get_spp_callback(void); +void bt_3th_set_spp_callback_priv(void *priv); +JL_PRO_CB *bt_3th_get_ble_callback(void); +void bt_3th_set_ble_callback_priv(void *priv); +void bt_3th_dev_type_spp(void); +void bt_3th_type_dev_select(u8 type); +u8 bt_3th_get_cur_bt_channel_sel(void); +void bt_3th_spp_state_handle(u8 type); +void bt_3th_event_send_to_user(u16 opcode, u8 *packet, int size); +void bt_3th_data_send_to_user(u8 *packet, int size); +#endif// __BTSTACK_3TH_PROTOCAL_H__ + + diff --git a/include_lib/btstack/third_party/common/spp_config.h b/include_lib/btstack/third_party/common/spp_config.h new file mode 100644 index 0000000..cc7e4ce --- /dev/null +++ b/include_lib/btstack/third_party/common/spp_config.h @@ -0,0 +1,15 @@ +#ifndef __SPP_CONFIG_H__ +#define __SPP_CONFIG_H__ + +#include "typedef.h" + +bool bt_3th_spp_fw_ready(void *priv); +s32 bt_3th_spp_send(void *priv, void *data, u16 len); +void bt_3th_spp_callback_set(void (*resume)(void), void (*recieve)(void *, void *, u16), void (*status)(u8)); +u8 bt_3th_get_jl_spp_status(void); +void bt_3th_spp_status_callback(u8 status); +int bt_3th_spp_data_send(void *priv, u8 *buf, u16 len); +void bt_3th_spp_init(void); +void bt_3th_spp_get_operation_table(void); + +#endif//__SPP_CONFIG_H__ diff --git a/include_lib/btstack/third_party/common/spp_user.h b/include_lib/btstack/third_party/common/spp_user.h new file mode 100644 index 0000000..e795769 --- /dev/null +++ b/include_lib/btstack/third_party/common/spp_user.h @@ -0,0 +1,37 @@ +#ifndef __SPP_USER_H__ +#define __SPP_USER_H__ + +#include "typedef.h" + +extern void (*spp_state_cbk)(u8 state); +extern void (*spp_recieve_cbk)(void *priv, u8 *buf, u16 len); +extern void user_spp_data_handler(u8 packet_type, u16 ch, u8 *packet, u16 size); + +struct spp_operation_t { + int(*disconnect)(void *priv); + int(*send_data)(void *priv, void *buf, u16 len); + int(*regist_wakeup_send)(void *priv, void *cbk); + int(*regist_recieve_cbk)(void *priv, void *cbk); + int(*regist_state_cbk)(void *priv, void *cbk); + int(*busy_state)(void); +}; + +enum { + SPP_USER_ERR_NONE = 0x0, + SPP_USER_ERR_SEND_BUFF_BUSY, + SPP_USER_ERR_SEND_OVER_LIMIT, + SPP_USER_ERR_SEND_FAIL, +}; + +enum { + SPP_USER_ST_NULL = 0x0, + SPP_USER_ST_CONNECT, + SPP_USER_ST_DISCONN, + SPP_USER_ST_WAIT_DISC, + SPP_USER_ST_CONNECT_OTA, + SPP_USER_ST_DISCONN_OTA, +}; + +void spp_get_operation_table(struct spp_operation_t **interface_pt); + +#endif//__SPP_USER_H__ diff --git a/include_lib/btstack/third_party/rcsp/JL_rcsp_api.h b/include_lib/btstack/third_party/rcsp/JL_rcsp_api.h new file mode 100644 index 0000000..27d9fe4 --- /dev/null +++ b/include_lib/btstack/third_party/rcsp/JL_rcsp_api.h @@ -0,0 +1,43 @@ + +#ifndef _JL_RCSP_LIB_API_H_ +#define _JL_RCSP_LIB_API_H_ + +#include "typedef.h" +#include "uart.h" + +#define USE_LITTLE_ENDIAN 0 +#define USE_BIG_ENDIAN 1 + +#define USE_ENDIAN_TYPE USE_LITTLE_ENDIAN + + +#define AI_LICENCE_LEN 16 + +enum { + TULING = 0, + DEEPBRAIN, +}; + +#pragma pack(1) +struct _AI_platform { + u8 platform; + u8 license[AI_LICENCE_LEN]; +}; +#pragma pack() + +u16 app_htons(u16 n); +u16 app_ntohs(u16 n); + +u32 app_htonl(u32 n); +u32 app_ntohl(u32 n); + +void JL_rcsp_auth_init(int (*send)(void *, u8 *, u16), u8 *link_key, u8 *addr); +void JL_rcsp_auth_reset(void); +u8 JL_rcsp_get_auth_flag(void); +void JL_rcsp_set_auth_flag(u8 auth_flag); +void JL_rcsp_auth_recieve(u8 *buffer, u16 len); + +u8 get_rcsp_version(void); +void get_ai_platform(struct _AI_platform *p, u8 platform); +void smart_auth_res_pass(void); +#endif //_JL_RCSP_LIB_H_ diff --git a/include_lib/btstack/third_party/rcsp/JL_rcsp_packet.h b/include_lib/btstack/third_party/rcsp/JL_rcsp_packet.h new file mode 100644 index 0000000..974ab6c --- /dev/null +++ b/include_lib/btstack/third_party/rcsp/JL_rcsp_packet.h @@ -0,0 +1,102 @@ +#ifndef __JL_PACKET_H__ +#define __JL_PACKET_H__ + +#include "typedef.h" + + +#define READ_BIG_U16(a) ((*((u8*)(a)) <<8) + *((u8*)(a)+1)) +#define READ_BIG_U32(a) ((*((u8*)(a)) <<24) + (*((u8*)(a)+1)<<16) + (*((u8*)(a)+2)<<8) + *((u8*)(a)+3)) + +#define READ_LIT_U16(a) (*((u8*)(a)) + (*((u8*)(a)+1)<<8)) +#define READ_LIT_U32(a) (*((u8*)(a)) + (*((u8*)(a)+1)<<8) + (*((u8*)(a)+2)<<16) + (*((u8*)(a)+3)<<24)) + + +#define WRITE_BIG_U16(a,src) {*((u8*)(a)+0) = (u8)(src>>8); *((u8*)(a)+1) = (u8)(src&0xff); } +#define WRITE_BIG_U32(a,src) {*((u8*)(a)+0) = (u8)((src)>>24); *((u8*)(a)+1) = (u8)(((src)>>16)&0xff);*((u8*)(a)+2) = (u8)(((src)>>8)&0xff);*((u8*)(a)+3) = (u8)((src)&0xff);} + +#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);} + + +#pragma pack(1) +typedef union __HEAD_BIT { + struct { + u16 _OpCode: 8; //OpCode val + u16 _unsed : 6; //unsed + u16 _resp : 1; //request for response + u16 _type : 1; //command or response + } _i; + u16 _t; +} HEAD_BIT; + +struct __JL_PACKET { + u8 tag[3]; + HEAD_BIT head; + u16 length; + u8 data[0]; +}; +#pragma pack() +typedef struct __JL_PACKET JL_PACKET; + + +#define JL_PACK_START_TAG0 (0xfe) +#define JL_PACK_START_TAG1 (0xdc) +#define JL_PACK_START_TAG2 (0xba) +#define JL_PACK_END_TAG (0xef) +#define JL_ONE_PACKET_LEN(n) (sizeof(JL_PACKET) + n + 1) + +#ifdef JL_RCSP_UBOOT_LIB +#define JL_MTU_RESV (540L) +#define JL_MTU_SEND (128L) +#define JL_RECIEVE_BUF_SIZE ((JL_MTU_RESV + sizeof(JL_PACKET))*2) +#define JL_CMD_POOL_SIZE (JL_MTU_SEND) +#define JL_RESP_POOL_SIZE (JL_MTU_SEND*2) +#define JL_WAIT_RESP_POOL_SIZE (JL_MTU_SEND) +#else +#define JL_MTU_RESV (540L) +#define JL_MTU_SEND (128L) +#define JL_RECIEVE_BUF_SIZE (JL_MTU_RESV + sizeof(JL_PACKET) + 128) +#define JL_CMD_POOL_SIZE (JL_MTU_SEND*4) +#define JL_RESP_POOL_SIZE (JL_MTU_SEND*2) +#define JL_WAIT_RESP_POOL_SIZE (JL_MTU_SEND*2) +#endif + +void set_jl_rcsp_recieve_buf_size(u16 size); +u16 rcsp_packet_write_alloc_len(void); + +u32 rcsp_packet_need_buf_size(void); +u32 rcsp_packet_buf_init(u8 *buf, u32 len); + +u16 JL_packet_get_rx_max_mtu(void); +u16 JL_packet_get_tx_max_mtu(void); +u16 JL_packet_set_mtu(u16 mtu); +void JL_packet_recieve(void *buf, u16 len); +u32 JL_pack_data_read_all(void *buf, u16 len); +void JL_packet_clear_all_data(void); +bool JL_packet_find(u8 *r_buf, JL_PACKET **packet); +void JL_packet_init(void); +void JL_packet_clear(void); + +void JL_packet_packing( + JL_PACKET *packet, + u8 OpCode, + u8 type, + u8 request_rsp, + u8 *extra_param, + u16 extra_len, + u8 *data, + u16 len); + +void set_jl_mtu_resv(u16 jl_mtu_resv_var); +void set_jl_mtu_send(u16 jl_mtu_send_var); + +extern u16 jl_mtu_resv; +extern u16 jl_mtu_send; +extern u16 jl_recieve_buf_size; +extern u16 jl_cmd_pool_size; +extern u16 jl_rcsp_pool_size; +extern u16 jl_wait_rcsp_pool_size; + +#endif//__JL_PACKET_H__ + + diff --git a/include_lib/btstack/third_party/rcsp/JL_rcsp_protocol.h b/include_lib/btstack/third_party/rcsp/JL_rcsp_protocol.h new file mode 100644 index 0000000..612a7c3 --- /dev/null +++ b/include_lib/btstack/third_party/rcsp/JL_rcsp_protocol.h @@ -0,0 +1,217 @@ +#ifndef __JL_PROTOCOL_H__ +#define __JL_PROTOCOL_H__ + +#include "typedef.h" +#include "JL_rcsp_packet.h" + +#define ATTR_TYPE_PROTOCOL_VERSION (0) +#define ATTR_TYPE_SYS_INFO (1) +#define ATTR_TYPE_EDR_ADDR (2) +#define ATTR_TYPE_PLATFORM (3) +#define ATTR_TYPE_FUNCTION_INFO (4) +#define ATTR_TYPE_DEV_VERSION (5) +#define ATTR_TYPE_SDK_TYPE (6) +#define ATTR_TYPE_UBOOT_VERSION (7) +#define ATTR_TYPE_DOUBLE_PARITION (8) +#define ATTR_TYPE_UPDATE_STATUS (9) +#define ATTR_TYPE_DEV_VID_PID (10) +#define ATTR_TYPE_DEV_AUTHKEY (11) +#define ATTR_TYPE_DEV_PROCODE (12) +#define ATTR_TYPE_DEV_MAX_MTU (13) +#define ATTR_TEYP_BLE_ADDR (17) +#define ATTR_TYPE_MD5_GAME_SUPPORT (19) + + + +#define COMMON_INFO_ATTR_BATTERY (0) +#define COMMON_INFO_ATTR_VOL (1) +#define COMMON_INFO_ATTR_DEV (2) +#define COMMON_INFO_ATTR_ERR_REPORT (3) +#define COMMON_INFO_ATTR_EQ (4) +#define COMMON_INFO_ATTR_FILE_BROWSE_TYPE (5) +#define COMMON_INFO_ATTR_FUN_TYPE (6) +#define COMMON_INFO_ATTR_LIGHT (7) +#define COMMON_INFO_ATTR_FMTX (8) +#define COMMON_INFO_ATTR_HIGH_LOW_SET (11) +#define COMMON_INFO_ATTR_PRE_FETCH_ALL_EQ_INFO (12) +#define COMMON_INFO_ATTR_ANC_VOICE (13) +#define COMMON_INFO_ATTR_FETCH_ALL_ANC_VOICE (14) +#define COMMON_INFO_ATTR_PHONE_SCO_STATE_INFO (15) +#define COMMON_INFO_ATTR_ASSISTED_HEARING (20) +#define COMMON_INFO_ATTR_ADAPTIVE_NOISE_REDUCTION (21) +#define COMMON_INFO_ATTR_AI_NO_PICK (22) +#define COMMON_INFO_ATTR_SCENE_NOISE_REDUCTION (23) +#define COMMON_INFO_ATTR_WIND_NOISE_DETECTION (24) +#define COMMON_INFO_ATTR_VOICE_ENHANCEMENT_MODE (25) + + + +#define BT_INFO_ATTR_MUSIC_TITLE (0) +#define BT_INFO_ATTR_MUSIC_ARTIST (1) +#define BT_INFO_ATTR_MUSIC_ALBUM (2) +#define BT_INFO_ATTR_MUSIC_NUMBER (3) +#define BT_INFO_ATTR_MUSIC_TOTAL (4) +#define BT_INFO_ATTR_MUSIC_GENRE (5) +#define BT_INFO_ATTR_MUSIC_TIME (6) +#define BT_INFO_ATTR_MUSIC_STATE (7) +#define BT_INFO_ATTR_MUSIC_CURR_TIME (8) + +#define BT_INFO_ATTR_01 (0) + +#define MUSIC_INFO_ATTR_STATUS (0) +#define MUSIC_INFO_ATTR_FILE_NAME (1) +#define MUSIC_INFO_ATTR_FILE_PLAY_MODE (2) + +#define RTC_INFO_ATTR_RTC_TIME (0) +#define RTC_INFO_ATTR_RTC_ALRAM (1) + +#define LINEIN_INFO_ATTR_STATUS (0) + + +/***************************************/ +/* 注意:不能在这个枚举里加代码 */ +/* 注意:不能在这个枚举里加代码 */ +/* 注意:不能在这个枚举里加代码 */ +/***************************************/ +enum { + JL_OPCODE_DATA = 0x01, + JL_OPCODE_GET_TARGET_FEATURE_MAP = 0x02, + JL_OPCODE_GET_TARGET_FEATURE = 0x03, + // JL_OPCODE_SWITCH_DEVICE = 0x04, + JL_OPCODE_DISCONNECT_EDR = 0x06, + JL_OPCODE_SYS_INFO_GET = 0x07, + JL_OPCODE_SYS_INFO_SET = 0x08, + JL_OPCODE_SYS_INFO_AUTO_UPDATE = 0x09, + JL_OPCODE_CALL_REQUEST = 0xa, + JL_OPCODE_SWITCH_DEVICE = 0x0b, + JL_OPCODE_FILE_BROWSE_REQUEST_START = 0x0C, + JL_OPCODE_FILE_BROWSE_REQUEST_STOP = 0x0D, + JL_OPCODE_FUNCTION_CMD = 0x0E, + + JL_OPCODE_SYS_OPEN_BT_SCAN = 0x12, + JL_OPCODE_SYS_UPDATE_BT_STATUS = 0X13, + JL_OPCODE_SYS_STOP_BT_SCAN = 0X14, + JL_OPCODE_SYS_BT_CONNECT_SPEC = 0X15, + JL_OPCODE_SYS_EMITTER_BT_CONNECT_STATUS = 0XD3, // 临时调整, 被遗忘的指令 + JL_OPCODE_SYS_FIND_DEVICE = 0X19, + + JL_OPCODE_EXTRA_FLASH_OPT = 0X1A, + + //文件传输相关命令 + JL_OPCODE_FILE_TRANSFER_START = 0X1B, + JL_OPCODE_FILE_TRANSFER_END = 0X1C, + JL_OPCODE_FILE_TRANSFER = 0X1D, + JL_OPCODE_FILE_TRANSFER_CANCEL = 0X1E, + JL_OPCODE_FILE_DELETE = 0X1F, + JL_OPCODE_FILE_RENAME = 0X20, + + JL_OPCODE_ACTION_PREPARE = 0X21,//APP操作预处理 + JL_OPCODE_DEVICE_FORMAT = 0X22,//设备格式化 + JL_OPCODE_ONE_FILE_DELETE = 0x23,//删除一个文件 + JL_OPCODE_ONE_FILE_TRANS_BACK = 0x24,//回传一个文件 + JL_OPCODE_ALARM_EXTRA = 0x25, + JL_OPCODE_FILE_BLUK_TRANSFER = 0x26,//批量大文件前准备 + JL_OPCODE_DEVICE_PARM_EXTRA = 0x27,//设备操作,如文件传输、文件删除、设备格式化参数扩展 + + JL_OPCODE_SIMPLE_FILE_TRANS = 0x28, + + JL_OPCODE_SPORTS_DATA_INFO_GET = 0xA0, + JL_OPCODE_SPORTS_DATA_INFO_SET = 0xA1, + JL_OPCODE_SPORTS_DATA_INFO_AUTO_UPDATE = 0xA2, + JL_OPCODE_SENSOR_LOG_DATA_AUTO_UPDATE = 0xA3, + JL_OPCODE_SENSOR_NFC_FUNCTION_OPT = 0xA4, + JL_OPCODE_SPORTS_DATA_INFO_OPT = 0xA5, + JL_OPCODE_SPORTS_DATA_SYNC = 0xA6, + + JL_OPCODE_NOTIFY_MTU = 0xD1, + JL_OPCODE_GET_MD5 = 0xD4, + JL_OPCODE_LOW_LATENCY_PARAM = 0xD5, + JL_OPTCODE_EXTRA_FLASH_INFO = 0XD6, + + JL_OPCODE_CUSTOMER_USER = 0xFF, +}; +/***************************************/ +/***************************************/ + +enum { + JL_NOT_NEED_RESPOND = 0, + JL_NEED_RESPOND, +}; + +enum { + JL_AUTH_NOTPASS = 0, + JL_AUTH_PASS, +}; + +typedef enum __JL_ERR { + JL_ERR_NONE = 0x0, + JL_ERR_SEND_DATA_OVER_LIMIT, + JL_ERR_SEND_BUSY, + JL_ERR_SEND_NOT_READY, + JL_ERR_EXIT, +} JL_ERR; + +typedef enum __JL_PRO_STATUS { + JL_PRO_STATUS_SUCCESS = 0x0, + JL_PRO_STATUS_FAIL, + JL_PRO_STATUS_UNKOWN_CMD, + JL_PRO_STATUS_BUSY, + JL_PRO_STATUS_NO_RESPONSE, + JL_PRO_STATUS_CRC_ERR, + JL_PRO_STATUS_ALL_DATA_CRC_ERR, + JL_PRO_STATUS_PARAM_ERR, + JL_PRO_STATUS_RESP_DATA_OVER_LIMIT, + +} JL_PRO_STATUS; + +///*< JL_CMD、JL_CMD_response、JL_DATA、JL_DATA_response packet send functions>*/ +JL_ERR JL_CMD_send(u8 OpCode, u8 *data, u16 len, u8 request_rsp); +JL_ERR JL_CMD_response_send(u8 OpCode, u8 status, u8 sn, u8 *data, u16 len); +JL_ERR JL_DATA_send(u8 OpCode, u8 CMD_OpCode, u8 *data, u16 len, u8 request_rsp); +JL_ERR JL_DATA_response_send(u8 OpCode, u8 status, u8 sn, u8 CMD_OpCode, u8 *data, u16 len); + +///**/ +typedef struct __JL_PRO_CB { + /*send function callback, SPP or ble*/ + void *priv; + bool (*fw_ready)(void *priv); + s32(*fw_send)(void *priv, void *buf, u16 len); + /*JL_CMD、JL_CMD_response、JL_DATA、JL_DATA_response packet recieve callback*/ + void (*CMD_resp)(void *priv, u8 OpCode, u8 OpCode_SN, u8 *data, u16 len); + void (*DATA_resp)(void *priv, u8 OpCode_SN, u8 CMD_OpCode, u8 *data, u16 len); + void (*CMD_no_resp)(void *priv, u8 OpCode, u8 *data, u16 len); + void (*DATA_no_resp)(void *priv, u8 CMD_OpCode, u8 *data, u16 len); + void (*CMD_recieve_resp)(void *priv, u8 OpCode, u8 status, u8 *data, u16 len); + void (*DATA_recieve_resp)(void *priv, u8 status, u8 CMD_OpCode, u8 *data, u16 len); + u8(*wait_resp_timeout)(void *priv, u8 OpCode, u8 counter); + void (*auth_pass_callback)(void *priv); +} JL_PRO_CB; + + +extern u32 rcsp_fw_ready(void); +extern u32 rcsp_protocol_need_buf_size(void); + +extern void JL_protocol_init(u8 *buf, u32 len); +extern void JL_protocol_exit(void); + +extern void JL_protocol_dev_switch(const JL_PRO_CB *cb); + +extern void JL_protocol_data_recieve(void *priv, void *buf, u16 len); +extern void JL_protocol_resume(void); + +extern void JL_protocol_process(void); + +extern void set_auth_pass(u8 auth_pass); + +extern void JL_set_cur_tick(u16 tick); + +extern bool rcsp_send_list_is_empty(void); + + +extern void JL_send_packet_process(void); +extern void JL_recieve_packet_parse_process(void); + + +#endif//__JL_PROTOCOL_H__ + + diff --git a/include_lib/btstack/third_party/rcsp/attr.h b/include_lib/btstack/third_party/rcsp/attr.h new file mode 100644 index 0000000..49d4d1c --- /dev/null +++ b/include_lib/btstack/third_party/rcsp/attr.h @@ -0,0 +1,15 @@ +#ifndef __ATTR_H__ +#define __ATTR_H__ +#include "typedef.h" + +typedef u32(*attr_get_func)(void *priv, u8 attr, u8 *buf, u16 buf_size, u32 offset); +typedef void (*attr_set_func)(void *priv, u8 attr, u8 *data, u16 len); + +u16 add_one_attr_huge(u8 *buf, u16 max_len, u8 offset, u8 type, u8 *data, u16 size); +u8 add_one_attr(u8 *buf, u16 max_len, u8 offset, u8 type, u8 *data, u8 size); +u8 add_one_attr_ex(u8 *buf, u16 max_len, u8 offset, u8 type, u8 *data, u8 size, u8 att_size); +u8 add_one_attr_continue(u8 *buf, u16 max_len, u8 offset, u8 type, u8 *data, u8 size); +u32 attr_get(void *priv, u8 *buf, u16 buf_size, const attr_get_func *func_tab, u8 attr_max, u32 mask); +void attr_set(void *priv, u8 *data, u16 len, const attr_set_func *func_tab, u8 attr_max); + +#endif//__ATTR_H__ diff --git a/include_lib/driver/cpu/br28/asm/adc_api.h b/include_lib/driver/cpu/br28/asm/adc_api.h new file mode 100644 index 0000000..7c02c9e --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/adc_api.h @@ -0,0 +1,119 @@ +#ifndef __ADC_API_H__ +#define __ADC_API_H__ + + +//AD channel define +#define AD_CH_PA0 (0x0) +#define AD_CH_PA5 (0x1) +#define AD_CH_PA6 (0x2) +#define AD_CH_PA8 (0x3) +#define AD_CH_PC4 (0x4) +#define AD_CH_PC5 (0x5) +#define AD_CH_PB1 (0x6) +#define AD_CH_PB2 (0x7) +#define AD_CH_PB5 (0x8) +#define AD_CH_PB9 (0x9) +#define AD_CH_DP (0xa) +#define AD_CH_DM (0xb) +#define AD_CH_PG0 (0xc) +#define AD_CH_PG1 (0xd) +#define AD_CH_PG5 (0xe) +#define AD_CH_PG7 (0xf) + +#define AD_CH_BT (0x10) +#define AD_CH_PMU (0x11) +#define AD_CH_AUDIO (0x12) +#define AD_CH_LPCTM (0x13) +#define AD_CH_X32K (0x14) +#define AD_CH_PLL1 (0x15) + +#define ADC_PMU_CH_VBG (0x0<<16)//MVBG/WVBG +#define ADC_PMU_CH_VSW (0x1<<16) +#define ADC_PMU_CH_PROGI (0x2<<16) +#define ADC_PMU_CH_PROGF (0x3<<16) +#define ADC_PMU_CH_VTEMP (0x4<<16) +#define ADC_PMU_CH_VPWR (0x5<<16) //1/4vpwr +#define ADC_PMU_CH_VBAT (0x6<<16) //1/4vbat +// #define ADC_PMU_CH_VBAT_2 (0x7<<16) +#define ADC_PMU_CH_VB17 (0x8<<16) +#define ADC_PMU_CH_IOVDD2 (0x9<<16) +#define ADC_PMU_CH_VDC15 (0xa<<16) +#define ADC_PMU_CH_DVDD (0xb<<16) +#define ADC_PMU_CH_RVDD (0xc<<16) +#define ADC_PMU_CH_TWVDD (0xd<<16) +#define ADC_PMU_CH_PVDD (0xe<<16) +#define ADC_PMU_CH_EVDD (0xf<<16) + + +#define AD_CH_PMU_VBG (AD_CH_PMU | ADC_PMU_CH_VBG) +#define AD_CH_VDC15 (AD_CH_PMU | ADC_PMU_CH_VDC15) +#define AD_CH_SYSVDD (AD_CH_PMU | ADC_PMU_CH_DVDD) +#define AD_CH_DTEMP (AD_CH_PMU | ADC_PMU_CH_VTEMP) +#define AD_CH_VBAT (AD_CH_PMU | ADC_PMU_CH_VBAT) +#define AD_CH_LDO5V (AD_CH_PMU | ADC_PMU_CH_VPWR) +#define AD_CH_WVDD (AD_CH_PMU | ADC_PMU_CH_TWVDD) +#define AD_CH_PVDD (AD_CH_PMU | ADC_PMU_CH_PVDD) + + +#define AD_CH_LDOREF AD_CH_PMU_VBG + + +// #define AD_CH_BT_VBG (AD_CH_BT | (0x8<<11)) //WLA_CON0[14:11]= 0b1000 + +// #define AD_CH_LDOREF AD_CH_BT_VBG + +// #define AD_CH_PMU_VBG (AD_CH_PMU | ADC_PMU_CH_VBG) +// #define AD_CH_VDC13 (AD_CH_PMU | ADC_PMU_CH_VDC13) +// #define AD_CH_SYSVDD (AD_CH_PMU | ADC_PMU_CH_SYSVDD) +// #define AD_CH_DTEMP (AD_CH_PMU | ADC_PMU_CH_DTEMP) +// #define AD_CH_VBAT (AD_CH_PMU | ADC_PMU_CH_VBAT) +// #define AD_CH_LDO5V (AD_CH_PMU | ADC_PMU_CH_LDO5V) +// #define AD_CH_WVDD (AD_CH_PMU | ADC_PMU_CH_WVDD) + +#define AD_AUDIO_VADADC ((BIT(0))<<16) +#define AD_AUDIO_VCM ((BIT(1))<<16) +#define AD_AUDIO_VBGLDO ((BIT(2))<<16) +#define AD_AUDIO_HPVDD ((BIT(3))<<16) +#define AD_AUDIO_RN ((BIT(4))<<16) +#define AD_AUDIO_RP ((BIT(5))<<16) +#define AD_AUDIO_LN ((BIT(6))<<16) +#define AD_AUDIO_LP ((BIT(7))<<16) +#define AD_AUDIO_DACVDD ((BIT(8))<<16) + +#define AD_CH_AUDIO_VADADC (AD_CH_AUDIO | AD_AUDIO_VADADC) +#define AD_CH_AUDIO_VCM (AD_CH_AUDIO | AD_AUDIO_VCM) +#define AD_CH_AUDIO_VBGLDO (AD_CH_AUDIO | AD_AUDIO_VBGLDO) +#define AD_CH_AUDIO_HPVDD (AD_CH_AUDIO | AD_AUDIO_HPVDD) +#define AD_CH_AUDIO_RN (AD_CH_AUDIO | AD_AUDIO_RN) +#define AD_CH_AUDIO_RP (AD_CH_AUDIO | AD_AUDIO_RP) +#define AD_CH_AUDIO_LN (AD_CH_AUDIO | AD_AUDIO_LN) +#define AD_CH_AUDIO_LP (AD_CH_AUDIO | AD_AUDIO_LP) +#define AD_CH_AUDIO_DACVDD (AD_CH_AUDIO | AD_AUDIO_DACVDD) + +#define ADC_MAX_CH 10 + + +extern void adc_init(); +extern void adc_vbg_init(); +//p33 define + +extern void adc_pmu_ch_select(u32 ch); +extern void adc_pmu_detect_en(u32 ch); +extern void adc_vdc13_save(); +extern void adc_vdc13_restore(); + +// +u32 adc_get_value(u32 ch); +u32 adc_add_sample_ch(u32 ch); +u32 adc_remove_sample_ch(u32 ch); +u32 adc_get_voltage(u32 ch); +u32 adc_check_vbat_lowpower(); +u32 adc_set_sample_freq(u32 ch, u32 ms); +u32 adc_sample(u32 ch); + +int get_hpvdd_voltage(void); + +u32 get_vdd_voltage(u32 ch); +u32 get_vddio_voltage(); + +#endif diff --git a/include_lib/driver/cpu/br28/asm/br28.h b/include_lib/driver/cpu/br28/asm/br28.h new file mode 100644 index 0000000..8d585ad --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/br28.h @@ -0,0 +1,1277 @@ + + +#ifndef __BR28__ +#define __BR28__ + +//===============================================================================// +// +// sfr define +// +//===============================================================================// + +#define hs_base 0xfe0000 +#define ls_base 0xfd0000 + +#define __RW volatile // read write +#define __RO volatile const // only read +#define __WO volatile // only write + +#define __u8 unsigned int // u8 to u32 special for struct +#define __u16 unsigned int // u16 to u32 special for struct +#define __u32 unsigned int + +#define __s8(x) char(x); char(reserved_1_##x); char(reserved_2_##x); char(reserved_3_##x) +#define __s16(x) short(x); short(reserved_1_##x) +#define __s32(x) int(x) + +#define map_adr(grp, adr) ((64 * grp + adr) * 4) // grp(0x0-0xff), adr(0x0-0x3f) + +//===============================================================================// +// +// high speed sfr address define +// +//===============================================================================// + +//............. 0x0000 - 0x00ff............ for hemu +typedef struct { + __RW __u32 WREN; + __RW __u32 CON0; + __RW __u32 CON1; + __RW __u32 CON2; + __RW __u32 CON3; + __RW __u32 MSG0; + __RW __u32 MSG1; + __RW __u32 MSG2; + __RW __u32 MSG3; + __RO __u32 ID; +} JL_HEMU_TypeDef; + +#define JL_HEMU_BASE (hs_base + map_adr(0x00, 0x00)) +#define JL_HEMU ((JL_HEMU_TypeDef *)JL_HEMU_BASE) + + +//............. 0x0100 - 0x02ff............ for sfc +typedef struct { + __RW __u32 CON; + __RW __u32 BAUD; + __RW __u32 REDU_BAUD; + __RW __u32 CODE; + __RW __u32 BASE_ADR; + __RW __u32 QUCNT; + __RW __u8 ENC_CON; + __RW __u16 ENC_KEY; + __WO __u32 UNENC_ADRH; + __WO __u32 UNENC_ADRL; +} JL_SFC_TypeDef; + +#define JL_SFC1_BASE (hs_base + map_adr(0x01, 0x00)) +#define JL_SFC1 ((JL_SFC_TypeDef *)JL_SFC1_BASE) + +#define JL_SFC_BASE (hs_base + map_adr(0x02, 0x00)) +#define JL_SFC ((JL_SFC_TypeDef *)JL_SFC_BASE) + +//............. 0x0300 - 0x03ff............ for psram +typedef struct { + __RW __u32 PSRAM_CON0; + __RW __u32 PSRAM_CON1; + __RW __u32 PSRAM_CON2; + __RW __u32 PSRAM_CFG0; + __RW __u32 PSRAM_CFG1; + __RW __u32 PSRAM_CMD; + __RW __u32 PSRAM_DBG_CON; + __RW __u32 PSRAM_DBG_START; + __RW __u32 PSRAM_DBG_END; + __RW __u32 PSRAM_DBG_ADR; + __RW __u32 PSRAM_DBG_INFO; +} JL_PSRAM_TypeDef; + +#define JL_PSRAM_BASE (hs_base + map_adr(0x03, 0x00)) +#define JL_PSRAM ((JL_PSRAM_TypeDef *)JL_PSRAM_BASE) + +//............. 0x0400 - 0x04ff............ for anc +typedef struct { + __RW __u32 SYS; + __RW __u32 LEN; + __RW __u32 ADR; + __RW __u32 MCTL; + __RW __u32 MDAT; + __RW __u32 SYS_RESERVE0; + __RW __u32 SYS_RESERVE1; + __RW __u32 SYS_RESERVE2; + __RW __u32 ANC_CON0; + __RW __u32 ANC_CON1; + __RW __u32 ANC_CON2; + __RW __u32 ANC_CON3; + __RW __u32 ANC_CON4; + __RW __u32 ANC_CON5; + __RW __u32 ANC_CON6; + __RW __u32 ANC_CON7; + __RW __u32 ANC_CON8; + __RW __u32 ANC_CON9; + __RW __u32 ANC_CON10; + __RW __u32 ANC_CON11; + __RW __u32 ANC_CON12; + __RW __u32 ANC_CON13; + __RW __u32 ANC_CON14; + __RW __u32 ANC_CON15; + __RW __u32 CORE_CON0; + __RW __u32 CORE_CON1; + __RW __u32 CORE_CON2; + __RW __u32 CORE_CON3; + __RW __u32 CORE_CON4; + __RW __u32 CORE_CON5; + __RW __u32 CORE_CON6; + __RW __u32 CORE_CON7; + __RW __u32 CORE_CON8; + __RW __u32 CORE_CON9; + __RW __u32 CORE_CON10; + __RW __u32 CORE_CON11; + __RW __u32 CORE_CON12; + __RW __u32 CORE_CON13; + __RW __u32 CORE_CON14; + __RW __u32 CORE_CON15; + __RW __u32 CORE_CON16; + __RW __u32 CORE_CON17; + __RW __u32 CORE_CON18; + __RW __u32 CORE_CON19; + __RW __u32 CORE_CON20; + __RW __u32 CORE_CON21; + __RW __u32 CORE_CON22; + __RW __u32 CORE_CON23; + __RW __u32 CORE_CON24; + __RW __u32 CORE_CON25; + __RW __u32 CORE_CON26; + __RW __u32 CORE_CON27; + __RW __u32 CORE_CON28; + __RW __u32 CORE_CON29; + __RW __u32 CORE_CON30; + __RW __u32 CORE_CON31; + __RW __u32 CORE_CON32; + __RW __u32 CORE_CON33; + __RW __u32 CORE_CON34; + __RW __u32 CORE_CON35; + __RW __u32 CORE_CON36; + __RW __u32 CORE_PND0; + __RW __u32 CORE_PND1; +} JL_ANC_TypeDef; + +#define JL_ANC_BASE (hs_base + map_adr(0x04, 0x00)) +#define JL_ANC ((JL_ANC_TypeDef *)JL_ANC_BASE) + +//............. 0x0500 - 0x05ff............ for audio_top +typedef struct { + __RW __u32(DAC_CON); + __RW __u32(DAC_ADR); + __RW __u16(DAC_LEN); + __RW __u16(DAC_PNS); + __RW __u16(DAC_HRP); + __RW __u16(DAC_SWP); + __RW __u16(DAC_SWN); + __RW __u32(DAC_VL0); + __RO __u32 RESERVED8; + __RW __u32(DAC_TM0); + __RW __u32(DAC_TM1); + __RW __u32(DAC_DB0); + __RW __u32(DAC_DB1); + __WO __u16(DAC_COP); + __RW __u32(ADC_CON); + __RW __u32(ADC_ADR); + __RW __u16(ADC_LEN); + __RW __u16(ADC_PNS); + __RW __u16(ADC_HWP); + __RW __u16(ADC_SRP); + __RW __u16(ADC_SRN); + __RW __u32(MBG_CON); + __RW __u32(AUD_CON); + __RW __u16(ADC_CON1); + __RW __u32(DCC_CON0); + __RW __u32(DCC_CON1); + __RO __u32(DCC_CON2); + __RO __u32(DCC_CON3); +} JL_AUDIO_TypeDef; + +#define JL_AUDIO_BASE (hs_base + map_adr(0x05, 0x00)) +#define JL_AUDIO ((JL_AUDIO_TypeDef *)JL_AUDIO_BASE) + +//............. 0x0600 - 0x06ff............ for alnk +typedef struct { + __RW __u16 CON0; + __RW __u16 CON1; + __RW __u8 CON2; + __RW __u8 CON3; + __WO __u32 ADR0; + __WO __u32 ADR1; + __WO __u32 ADR2; + __WO __u32 ADR3; + __WO __u16 LEN; + __RW __u32 PNS; + __RW __u32 HWPTR0; + __RW __u32 HWPTR1; + __RW __u32 HWPTR2; + __RW __u32 HWPTR3; + __RW __u32 SWPTR0; + __RW __u32 SWPTR1; + __RW __u32 SWPTR2; + __RW __u32 SWPTR3; + __RW __u32 SHN0; + __RW __u32 SHN1; + __RW __u32 SHN2; + __RW __u32 SHN3; +} JL_ALNK_TypeDef; + +#define JL_ALNK0_BASE (hs_base + map_adr(0x06, 0x00)) +#define JL_ALNK0 ((JL_ALNK_TypeDef *)JL_ALNK0_BASE) + +//............. 0x0700 - 0x07ff............ for plnk +typedef struct { + __RW __u16 CON; + __RW __u8 SMR; + __RW __u32 ADR; + __RW __u32 LEN; + __RW __u16 DOR; + __RW __u32 CON1; + +} JL_PLNK_TypeDef; + +#define JL_PLNK_BASE (hs_base + map_adr(0x07, 0x00)) +#define JL_PLNK ((JL_PLNK_TypeDef *)JL_PLNK_BASE) + +//............. 0x0800 - 0x08ff............ for vad +typedef struct { + __RW __u32(VAD_CON0); + __RW __u32(VAD_CON1); + __RW __u32(VAD_CON2); + __RW __u32(VAD_CON3); + __RW __u32(VAD_CON4); + __RW __u32(VAD_CON5); + __RW __u32(VAD_CON6); + __RW __u32(VAD_CON7); + __RW __u32(VAD_CON8); + __RW __u32(VAD_SIL_BADR); + __RW __u32(VAD_VOICE_BADR); + __RO __u32(VAD_VOICE_SADR); + __RW __u32(DSF1_CON0); + __RW __u32(DSF1_DCC); + __RW __u32(AEC_CON0); + __RW __u32(AEC_CON1); + __RW __u32(AEC_CON2); + __RW __u32(AEC_CON3); + __RW __u32(AEC_CON4); + __RW __u32(AEC_CON5); + __RW __u32(AEC_CON6); + __RW __u32(AEC_CON7); + __RW __u32(AEC_CON8); + __RW __u32(AEC_CON9); + __RW __u32(AEC_CON10); + __RW __u32(AEC_CON11); + __RW __u32(AEC_CON12); + __RW __u32(CLK_CON); + __RW __u32(MIC_CON); +} JL_VAD_TypeDef; + +#define JL_VAD_BASE (hs_base + map_adr(0x08, 0x00)) +#define JL_VAD ((JL_VAD_TypeDef *)JL_VAD_BASE) + +//............. 0x0900 - 0x09ff............ for ass_clkgen +typedef struct { + __RW __u32 CLK_CON; + __RW __u32 MIC_CTL0; + __RW __u32 MIC_CTL1; +} JL_ASS_TypeDef; + +#define JL_ASS_BASE (hs_base + map_adr(0x09, 0x00)) +#define JL_ASS ((JL_ASS_TypeDef *)JL_ASS_BASE) + +//............. 0x0a00 - 0x0aff............ for audio_ana +typedef struct { + __RW __u32 DAA_CON0; + __RW __u32 DAA_CON1; + __RW __u32 DAA_CON2; + __RW __u32 DAA_CON3; + __RW __u32 DAA_CON4; + __RO __u32 RESERVED5; + __RO __u32 RESERVED6; + __RO __u32 DAA_CON7; + __RW __u32 ADA_CON0; + __RW __u32 ADA_CON1; + __RW __u32 ADA_CON2; + __RW __u32 ADA_CON3; + __RW __u32 ADA_CON4; + __RW __u32 ADA_CON5; + __RW __u32 ADA_CON6; + __RW __u32 ADA_CON7; + __RW __u32 ADA_CON8; + __RW __u32 ADA_CON9; + __RW __u32 ADDA_CON0; + __RW __u32 ADDA_CON1; +} JL_ADDA_TypeDef; + +#define JL_ADDA_BASE (hs_base + map_adr(0x0a, 0x00)) +#define JL_ADDA ((JL_ADDA_TypeDef *)JL_ADDA_BASE) + +//............. 0x0b00 - 0x0bff............ for ass_mbist +typedef struct { + __RW __u32 CON; + __RW __u32 SEL; + __RW __u32 DP; + __RW __u32 DAT_VLD0; + __RW __u32 DAT_VLD1; + __RW __u32 DAT_VLD2; + __RW __u32 DAT_VLD3; +} JL_ASS_MBIST_TypeDef; + +#define JL_ASS_MBIST_BASE (hs_base + map_adr(0x0b, 0x00)) +#define JL_ASS_MBIST ((JL_ASS_MBIST_TypeDef *)JL_ASS_MBIST_BASE) + +//............. 0x1300 - 0x13ff............ for dc +typedef struct { + __RW __u32 CON; + __RW __u32 ADR; +} JL_DCP_TypeDef; + +#define JL_DCP_BASE (hs_base + map_adr(0x13, 0x00)) +#define JL_DCP ((JL_DCP_TypeDef *)JL_DCP_BASE) + + +//............. 0x1500 - 0x15ff............ for eq +typedef struct { + __RW __u32 CON0; + __RW __u32 CON1; + __RW __u32 CON2; + __RW __u32 CON3; + __RW __u32 DATAI_ADR; + __RW __u32 DATAO_ADR; + __RW __u32 DATA_LEN; + __RW __u32 FLT_ADR; + +} JL_EQ_TypeDef; + +#define JL_EQ_BASE (hs_base + map_adr(0x15, 0x00)) +#define JL_EQ ((JL_EQ_TypeDef *)JL_EQ_BASE) + +//............. 0x1600 - 0x16ff............ for src +typedef struct { + __RW __u32 CON0; + __RW __u32 CON1; + __RW __u32 CON2; + __RW __u32 CON3; + __RW __u32 IDAT_ADR; + __RW __u32 IDAT_LEN; + __RW __u32 ODAT_ADR; + __RW __u32 ODAT_LEN; + __RW __u32 FLTB_ADR; + __WO __u32 ODAT_ADR_START; + __WO __u32 ODAT_ADR_END; + __WO __u32 STOP_FLAG; + __RW __u32 INSR; + __RW __u32 OUTSR; + __RW __u32 PHASE; + __RW __u32 COEF; + +} JL_SRC_TypeDef; + +#define JL_SRC_BASE (hs_base + map_adr(0x16, 0x00)) +#define JL_SRC ((JL_SRC_TypeDef *)JL_SRC_BASE) + +//............. 0x1800 - 0x18ff............ + + +//............. 0x2000 - 0x20ff............ for jpg decode +typedef struct { + __RW __u32 CON0; + __RW __u32 CON1; + __RW __u32 WIDTH; + __RW __u32 YADR; + __RW __u32 UADR; + __RW __u32 VADR; + __RW __u32 BADDR; + __RW __u32 BCNT; + __RW __u32 MCUCNT; + __RW __u32 HQTBLADR; + __RW __u32 HQTBLDAT; + __RW __u32 PIXEL_NUM; + +} JL_JPG_TypeDef; + +#define JL_JPG_BASE (hs_base + map_adr(0x20, 0x00)) +#define JL_JPG ((JL_JPG_TypeDef *)JL_JPG_BASE) + + +//............. 0x2100 - 0x21ff............ for wireless +typedef struct { + __RW __u32 CON0; + __RW __u32 CON3; + __RW __u32 LOFC_CON; + __RW __u32 LOFC_RES; + __RW __u32 DBG_CON; +} JL_WL_TypeDef; + +#define JL_WL_BASE (hs_base + map_adr(0x21, 0x00)) +#define JL_WL ((JL_WL_TypeDef *)JL_WL_BASE) + +//............. 0x2200 - 0x22ff............ +typedef struct { + __RW __u32 CON0; +} JL_WL_AUD_TypeDef; + +#define JL_WL_AUD_BASE (hs_base + map_adr(0x22, 0x00)) +#define JL_WL_AUD ((JL_WL_AUD_TypeDef *)JL_WL_AUD_BASE) + +//............. 0x2300 - 0x23ff............ + +//............. 0x2400 - 0x24ff............ + +//............. 0x2500 - 0x25ff............ for audio_sync +typedef struct { + __RW __u32 CON; + __RW __u32 DABUF; + __RO __u32 DASPACE; + __RO __u32 OFFEND; + __RO __u32 OFFSUM; + __RO __u32 PCMNUM; + __RO __u32 BTTIME; + __WO __u32 CON1 ; + __RW __u32 CON2 ; + __WO __u32 BT_OFFSET; + __WO __u32 MIN_SLOT; + __RW __u32 OUTSR; + __WO __u32 INSR; +} JL_SYNC_TypeDef; + +#define JL_SYNC_BASE (hs_base + map_adr(0x25, 0x00)) +#define JL_SYNC ((JL_SYNC_TypeDef *)JL_SYNC_BASE) + +//............. 0x2600 - 0x26ff............ for src_sync +typedef struct { + __RW __u32 CON0; + __RW __u32 CON1; + __RW __u32 CON2; + __RW __u32 CON3; + __RW __u32 IDAT_ADR; + __RW __u32 IDAT_LEN; + __RW __u32 ODAT_ADR; + __RW __u32 ODAT_LEN; + __RW __u32 FLTB_ADR; + __WO __u32 ODAT_ADR_START; + __WO __u32 ODAT_ADR_END; + __RW __u32 STOP_FLAG; + __RW __u32 INSR; + __RW __u32 OUTSR; + __RW __u32 PHASE; + __RW __u32 COEF; + +} JL_SRC_SYNC_TypeDef; + +#define JL_SRC_SYNC_BASE (hs_base + map_adr(0x26, 0x00)) +#define JL_SRC_SYNC ((JL_SRC_SYNC_TypeDef *)JL_SRC_SYNC_BASE) + +//............. 0x2700 - 0x27ff............ +typedef struct { + __RW __u32 CON0; + __RW __u32 CON1; + __RW __u32 CON2; + __RW __u32 CON3; + __RW __u32 CON4; + __RW __u32 CON5; + __RW __u32 CON6; + __RW __u32 CON7; +} JL_IMG_CP_TypeDef; + +#define JL_IMG_CP_BASE (hs_base + map_adr(0x27, 0x00)) +#define JL_IMG_CP ((JL_IMG_CP_TypeDef *)JL_IMG_CP_BASE) + +//............. 0x2800 - 0x28ff............ +typedef struct { + __RW __u32 IMB_CON0; + __RW __u32 IMB_CON1; + __RW __u32 IMB_CON2; + __RW __u32 IMB_CON3; + __RW __u32 IMB_CON4; + __RW __u32 IMB_CON5; + __RW __u32 IMB_CON6; + __RW __u32 IMB_CON7; + __RW __u32 IMB_CON8; + __RW __u32 IMB_CON9; + __RW __u32 IMB_CON10; + __RW __u32 IMB_CON11; + __RW __u32 IMB_CON12; + __RW __u32 IMB_CON13; + __RW __u32 IMB_CON14; + __RW __u32 IMB_CON15; + __RW __u32 IMB_CON16; +} JL_IMB_TypeDef; + +#define JL_IMB_BASE (hs_base + map_adr(0x28, 0x00)) +#define JL_IMB ((JL_IMB_TypeDef *)JL_IMB_BASE) + +//............. 0x2900 - 0x29ff............ +typedef struct { + __RW __u32 CON; + __RW __u32 SEL; + __RW __u32 DP; + __RW __u32 DAT_VLD0; + __RW __u32 DAT_VLD1; + __RW __u32 DAT_VLD2; + __RW __u32 DAT_VLD3; +} JL_HMBIST_TypeDef; + +#define JL_HMBIST_BASE (hs_base + map_adr(0x29, 0x00)) +#define JL_HMBIST ((JL_HMBIST_TypeDef *)JL_HMBIST_BASE) + +//............. 0x2a00 - 0x2aff............ +typedef struct { + __RW __u32 CON; + __RW __u32 SEL; + __RW __u32 DP; + __RW __u32 DAT_VLD0; + __RW __u32 DAT_VLD1; + __RW __u32 DAT_VLD2; + __RW __u32 DAT_VLD3; +} JL_WL_MBIST_TypeDef; + +#define JL_WL_MBIST_BASE (hs_base + map_adr(0x2a, 0x00)) +#define JL_WL_MBIST ((JL_WL_MBIST_TypeDef *)JL_WL_MBIST_BASE) + +//............. 0x2b00 - 0x2bff............ +typedef struct { + __RW __u32 CON; + __RW __u32 SEL; + __RW __u32 DP; + __RW __u32 DAT_VLD0; + __RW __u32 DAT_VLD1; + __RW __u32 DAT_VLD2; + __RW __u32 DAT_VLD3; +} JL_JPG_MBIST_TypeDef; + +#define JL_JPG_MBIST_BASE (hs_base + map_adr(0x2b, 0x00)) +#define JL_JPG_MBIST ((JL_JPG_MBIST_TypeDef *)JL_JPG_MBIST_BASE) + +//............. 0x2c00 - 0x2cff............ +typedef struct { + __RW __u32 CON; + __RW __u32 SEL; + __RW __u32 DP; + __RW __u32 DAT_VLD0; + __RW __u32 DAT_VLD1; + __RW __u32 DAT_VLD2; + __RW __u32 DAT_VLD3; +} JL_IMB_MBIST_TypeDef; + +#define JL_IMB_MBIST_BASE (hs_base + map_adr(0x2c, 0x00)) +#define JL_IMB_MBIST ((JL_IMB_MBIST_TypeDef *)JL_IMB_MBIST_BASE) + +//............. 0x2d00 - 0x2dff............ +typedef struct { + __RW __u32 IMD_CON0; + __RW __u32 IMD_CON1; + __RW __u32 IMD_CON2; + __RW __u32 IMD_CON3; + __RW __u32 IMD_LD_START_ADR; + __RW __u32 IMD_DEBUG_PIXEL; + __RW __u32 IMD_IO_CFG; + __RW __u16 IMD_BAUD; + __RW __u32 IMDSPI_CON0; + __RW __u32 IMDSPI_BUF; + __RW __u32 IMDPAP_CON0; + __RW __u32 IMDPAP_PRD; + __RW __u32 IMDPAP_BUF; + __RW __u32 IMDRGB_CON0; + __RW __u32 IMDRGB_HPRD; + __RW __u32 IMDRGB_VPRD; +} JL_IMD_TypeDef; + +#define JL_IMD_BASE (hs_base + map_adr(0x2d, 0x00)) +#define JL_IMD ((JL_IMD_TypeDef *)JL_IMD_BASE) + + +//===============================================================================// +// +// low speed sfr address define +// +//===============================================================================// + +//............. 0x0000 - 0x00ff............ for syscfg +typedef struct { + __RW __u32 RST_SRC; +} JL_RST_TypeDef; + +#define JL_RST_BASE (ls_base + map_adr(0x00, 0x00)) +#define JL_RST ((JL_RST_TypeDef *)JL_RST_BASE) + +typedef struct { + __RW __u32 PWR_CON; + //__RW __u32 HTC_CON; + __RW __u32 DCCK_CON0; + __RW __u32 DCCK_CON1; + __RW __u32 DCCK_CON2; + __RW __u32 SYS_DIV; + __RW __u32 CLK_CON0; + __RW __u32 CLK_CON1; + __RW __u32 CLK_CON2; + __RW __u32 CLK_CON3; +} JL_CLOCK_TypeDef; + +#define JL_CLOCK_BASE (ls_base + map_adr(0x00, 0x01)) +#define JL_CLOCK ((JL_CLOCK_TypeDef *)JL_CLOCK_BASE) + +//............. 0x0100 - 0x01ff............ +typedef struct { + __RW __u32 MODE_CON; +} JL_MODE_TypeDef; + +#define JL_MODE_BASE (ls_base + map_adr(0x01, 0x00)) +#define JL_MODE ((JL_MODE_TypeDef *)JL_MODE_BASE) + +//............. 0x0200 - 0x02ff............ +typedef struct { + __WO __u32 CHIP_ID; +} JL_SYSTEM_TypeDef; + +#define JL_SYSTEM_BASE (ls_base + map_adr(0x02, 0x00)) +#define JL_SYSTEM ((JL_SYSTEM_TypeDef *)JL_SYSTEM_BASE) + +//............. 0x0300 - 0x03ff............ +typedef struct { + __RW __u32 WREN; + __RW __u32 CON0; + __RW __u32 CON1; + __RW __u32 CON2; + __RW __u32 CON3; + __RW __u32 MSG0; + __RW __u32 MSG1; + __RW __u32 MSG2; + __RW __u32 MSG3; + __RO __u32 ID; +} JL_LEMU_TypeDef; + +#define JL_LEMU_BASE (ls_base + map_adr(0x03, 0x00)) +#define JL_LEMU ((JL_LEMU_TypeDef *)JL_LEMU_BASE) + +//............. 0x0400 - 0x09ff............ +typedef struct { + __RW __u32 CON; + __RW __u32 CNT; + __RW __u32 PRD; + __RW __u32 PWM; +} JL_TIMER_TypeDef; + +#define JL_TIMER0_BASE (ls_base + map_adr(0x04, 0x00)) +#define JL_TIMER0 ((JL_TIMER_TypeDef *)JL_TIMER0_BASE) + +#define JL_TIMER1_BASE (ls_base + map_adr(0x05, 0x00)) +#define JL_TIMER1 ((JL_TIMER_TypeDef *)JL_TIMER1_BASE) + +#define JL_TIMER2_BASE (ls_base + map_adr(0x06, 0x00)) +#define JL_TIMER2 ((JL_TIMER_TypeDef *)JL_TIMER2_BASE) + +#define JL_TIMER3_BASE (ls_base + map_adr(0x07, 0x00)) +#define JL_TIMER3 ((JL_TIMER_TypeDef *)JL_TIMER3_BASE) + +#define JL_TIMER4_BASE (ls_base + map_adr(0x08, 0x00)) +#define JL_TIMER4 ((JL_TIMER_TypeDef *)JL_TIMER4_BASE) + +#define JL_TIMER5_BASE (ls_base + map_adr(0x09, 0x00)) +#define JL_TIMER5 ((JL_TIMER_TypeDef *)JL_TIMER5_BASE) + + +//............. 0x1000 - 0x10ff............ +typedef struct { + __RW __u32 CON; + __RW __u32 VAL; +} JL_PCNT_TypeDef; + +#define JL_PCNT_BASE (ls_base + map_adr(0x10, 0x00)) +#define JL_PCNT ((JL_PCNT_TypeDef *)JL_PCNT_BASE) + +//............. 0x1100 - 0x11ff............ +typedef struct { + __RW __u32 CON; + __RO __u32 NUM; +} JL_GPCNT_TypeDef; + +#define JL_GPCNT_BASE (ls_base + map_adr(0x11, 0x00)) +#define JL_GPCNT ((JL_GPCNT_TypeDef *)JL_GPCNT_BASE) + + +//............. 0x1400 - 0x17ff............ +typedef struct { + __RW __u32 CON0; + __RW __u32 CON1; + __RW __u32 CON2; + __WO __u32 CPTR; + __WO __u32 DPTR; + __RW __u32 CTU_CON; + __WO __u32 CTU_CNT; +} JL_SD_TypeDef; + +#define JL_SD0_BASE (ls_base + map_adr(0x14, 0x00)) +#define JL_SD0 ((JL_SD_TypeDef *)JL_SD0_BASE) + +//............. 0x1800 - 0x18ff............ +typedef struct { + __RW __u32 CON0; + __RW __u32 CON1; + __WO __u32 EP0_CNT; + __WO __u32 EP1_CNT; + __WO __u32 EP2_CNT; + __WO __u32 EP3_CNT; + __WO __u32 EP4_CNT; + __WO __u32 EP0_ADR; + __WO __u32 EP1_TADR; + __WO __u32 EP1_RADR; + __WO __u32 EP2_TADR; + __WO __u32 EP2_RADR; + __WO __u32 EP3_TADR; + __WO __u32 EP3_RADR; + __WO __u32 EP4_TADR; + __WO __u32 EP4_RADR; + __RW __u32 TXDLY_CON; + __RW __u32 EP1_RLEN; + __RW __u32 EP2_RLEN; + __RW __u32 EP3_RLEN; + __RW __u32 EP4_RLEN; + __RW __u32 EP1_MTX_PRD; + __RW __u32 EP1_MRX_PRD; + __RO __u32 EP1_MTX_NUM; + __RO __u32 EP1_MRX_NUM; +} JL_USB_TypeDef; + +#define JL_USB_BASE (ls_base + map_adr(0x18, 0x00)) +#define JL_USB ((JL_USB_TypeDef *)JL_USB_BASE) + +//............. 0x1900 - 0x19ff............ +typedef struct { + __RW __u32 WLA_CON0 ; + __RW __u32 WLA_CON1 ; + __RW __u32 WLA_CON2 ; + __RW __u32 WLA_CON3 ; + __RW __u32 WLA_CON4 ; + __RW __u32 WLA_CON5 ; + __RW __u32 WLA_CON6 ; + __RW __u32 WLA_CON7 ; + __RW __u32 WLA_CON8 ; + __RW __u32 WLA_CON9 ; + __RW __u32 WLA_CON10; + __RW __u32 WLA_CON11; + __RW __u32 WLA_CON12; + __RW __u32 WLA_CON13; + __RW __u32 WLA_CON14; + __RW __u32 WLA_CON15; + __RW __u32 WLA_CON16; + __RW __u32 WLA_CON17; + __RW __u32 WLA_CON18; + __RW __u32 WLA_CON19; + __RW __u32 WLA_CON20; + __RW __u32 WLA_CON21; + __RW __u32 WLA_CON22; + __RW __u32 WLA_CON23; + __RW __u32 WLA_CON24; + __RW __u32 WLA_CON25; + __RW __u32 WLA_CON26; + __RW __u32 WLA_CON27; + __RW __u32 WLA_CON28; + __RW __u32 WLA_CON29; + __RO __u32 WLA_CON30; + __RO __u32 WLA_CON31; + __RO __u32 WLA_CON32; + __RO __u32 WLA_CON33; + __RO __u32 WLA_CON34; + __RO __u32 WLA_CON35; + __RO __u32 WLA_CON36; + __RO __u32 WLA_CON37; + __RO __u32 WLA_CON38; + __RO __u32 WLA_CON39; +} JL_WLA_TypeDef; + +#define JL_WLA_BASE (ls_base + map_adr(0x19, 0x00)) +#define JL_WLA ((JL_WLA_TypeDef *)JL_WLA_BASE) + +//............. 0x1c00 - 0x1eff............ +typedef struct { + __RW __u32 CON; + __WO __u32 BAUD; + __RW __u32 BUF; + __WO __u32 ADR; + __WO __u32 CNT; + __RW __u32 CON1; +} JL_SPI_TypeDef; + +#define JL_SPI0_BASE (ls_base + map_adr(0x1c, 0x00)) +#define JL_SPI0 ((JL_SPI_TypeDef *)JL_SPI0_BASE) + +#define JL_SPI1_BASE (ls_base + map_adr(0x1d, 0x00)) +#define JL_SPI1 ((JL_SPI_TypeDef *)JL_SPI1_BASE) + +#define JL_SPI2_BASE (ls_base + map_adr(0x1e, 0x00)) +#define JL_SPI2 ((JL_SPI_TypeDef *)JL_SPI2_BASE) + +//............. 0x2000 - 0x22ff............ +typedef struct { + __RW __u16 CON0; + __RW __u16 CON1; + __WO __u16 BAUD; + __RW __u8 BUF; + __RW __u32 OTCNT; + __RW __u32 TXADR; + __WO __u16 TXCNT; + __RW __u32 RXSADR; + __RW __u32 RXEADR; + __RW __u32 RXCNT; + __RO __u16 HRXCNT; + __RW __u16 CON2; +} JL_UART_TypeDef; + +#define JL_UART0_BASE (ls_base + map_adr(0x20, 0x00)) +#define JL_UART0 ((JL_UART_TypeDef *)JL_UART0_BASE) + +#define JL_UART1_BASE (ls_base + map_adr(0x21, 0x00)) +#define JL_UART1 ((JL_UART_TypeDef *)JL_UART1_BASE) + +#define JL_UART2_BASE (ls_base + map_adr(0x22, 0x00)) +#define JL_UART2 ((JL_UART_TypeDef *)JL_UART2_BASE) + +//............. 0x2400 - 0x24ff............ +typedef struct { + __RW __u32 CON0; + __RW __u32 CON1; + __WO __u16 BAUD; + __RW __u8 BUF; +} JL_IIC_TypeDef; + +#define JL_IIC_BASE (ls_base + map_adr(0x24, 0x00)) +#define JL_IIC ((JL_IIC_TypeDef *)JL_IIC_BASE) + +//............. 0x2800 - 0x28ff............ +typedef struct { + __RW __u32 CON0; + __RW __u32 WCLK_DUTY; + __RW __u32 WCLK_PRD; + __WO __u32 DMA_BASE_ADR; + __WO __u32 DMA_BUF_LEN; + __RW __u32 SLOT_EN; + +} JL_TDM_TypeDef; + +#define JL_TDM_BASE (ls_base + map_adr(0x28, 0x00)) +#define JL_TDM ((JL_TDM_TypeDef *)JL_TDM_BASE) + +//............. 0x2900 - 0x29ff............ +typedef struct { + __RW __u32 TMR0_CON; + __RW __u32 TMR0_CNT; + __RW __u32 TMR0_PR; + __RW __u32 TMR1_CON; + __RW __u32 TMR1_CNT; + __RW __u32 TMR1_PR; + __RW __u32 TMR2_CON; + __RW __u32 TMR2_CNT; + __RW __u32 TMR2_PR; + __RW __u32 TMR3_CON; + __RW __u32 TMR3_CNT; + __RW __u32 TMR3_PR; + __RW __u32 TMR4_CON; + __RW __u32 TMR4_CNT; + __RW __u32 TMR4_PR; + __RW __u32 TMR5_CON; + __RW __u32 TMR5_CNT; + __RW __u32 TMR5_PR; + __RW __u32 TMR6_CON; + __RW __u32 TMR6_CNT; + __RW __u32 TMR6_PR; + __RW __u32 TMR7_CON; + __RW __u32 TMR7_CNT; + __RW __u32 TMR7_PR; + __RW __u32 FPIN_CON; + __RW __u32 CH0_CON0; + __RW __u32 CH0_CON1; + __RW __u32 CH0_CMPH; + __RW __u32 CH0_CMPL; + __RW __u32 CH1_CON0; + __RW __u32 CH1_CON1; + __RW __u32 CH1_CMPH; + __RW __u32 CH1_CMPL; + __RW __u32 CH2_CON0; + __RW __u32 CH2_CON1; + __RW __u32 CH2_CMPH; + __RW __u32 CH2_CMPL; + __RW __u32 CH3_CON0; + __RW __u32 CH3_CON1; + __RW __u32 CH3_CMPH; + __RW __u32 CH3_CMPL; + __RW __u32 CH4_CON0; + __RW __u32 CH4_CON1; + __RW __u32 CH4_CMPH; + __RW __u32 CH4_CMPL; + __RW __u32 CH5_CON0; + __RW __u32 CH5_CON1; + __RW __u32 CH5_CMPH; + __RW __u32 CH5_CMPL; + __RW __u32 CH6_CON0; + __RW __u32 CH6_CON1; + __RW __u32 CH6_CMPH; + __RW __u32 CH6_CMPL; + __RW __u32 CH7_CON0; + __RW __u32 CH7_CON1; + __RW __u32 CH7_CMPH; + __RW __u32 CH7_CMPL; + __RW __u32 MCPWM_CON0; +} JL_MCPWM_TypeDef; + +#define JL_MCPWM_BASE (ls_base + map_adr(0x29, 0x00)) +#define JL_MCPWM ((JL_MCPWM_TypeDef *)JL_MCPWM_BASE) + +//............. 0x2b00 - 0x2dff............ +typedef struct { + __RW __u8 CON; + __RW __u8 DAT; + __RW __u8 SMP; +} JL_RDEC_TypeDef; + +#define JL_RDEC0_BASE (ls_base + map_adr(0x2b, 0x00)) +#define JL_RDEC0 ((JL_RDEC_TypeDef *)JL_RDEC0_BASE) + +#define JL_RDEC1_BASE (ls_base + map_adr(0x2c, 0x00)) +#define JL_RDEC1 ((JL_RDEC_TypeDef *)JL_RDEC1_BASE) + +#define JL_RDEC2_BASE (ls_base + map_adr(0x2d, 0x00)) +#define JL_RDEC2 ((JL_RDEC_TypeDef *)JL_RDEC2_BASE) + +//............. 0x3100 - 0x31ff............ +typedef struct { + __RW __u32 CON; + __RO __u32 RES; +} JL_ADC_TypeDef; + +#define JL_ADC_BASE (ls_base + map_adr(0x31, 0x00)) +#define JL_ADC ((JL_ADC_TypeDef *)JL_ADC_BASE) + +//............. 0x3200 - 0x32ff............ +typedef struct { + __RW __u32 RFLT_CON; +} JL_IR_TypeDef; + +#define JL_IR_BASE (ls_base + map_adr(0x32, 0x00)) +#define JL_IR ((JL_IR_TypeDef *)JL_IR_BASE) + +//............. 0x3400 - 0x34ff............ +typedef struct { + __RW __u32 CON; +} JL_OSA_TypeDef; + +#define JL_OSA_BASE (ls_base + map_adr(0x34, 0x00)) +#define JL_OSA ((JL_OSA_TypeDef *)JL_OSA_BASE) + +//............. 0x3500 - 0x35ff............ +typedef struct { + __WO __u32 FIFO; + __RW __u32 REG; +} JL_CRC_TypeDef; + +#define JL_CRC_BASE (ls_base + map_adr(0x35, 0x00)) +#define JL_CRC ((JL_CRC_TypeDef *)JL_CRC_BASE) + + +//............. 0x3600 - 0x36ff............ +typedef struct { + __WO __u32 CON; + __RW __u32 NUM; +} JL_LRCT_TypeDef; + +#define JL_LRCT_BASE (ls_base + map_adr(0x36, 0x00)) +#define JL_LRCT ((JL_LRCT_TypeDef *)JL_LRCT_BASE) + +//............. 0x3b00 - 0x3bff............ +typedef struct { + __RO __u32 R64L; + __RO __u32 R64H; +} JL_RAND_TypeDef; + +#define JL_RAND_BASE (ls_base + map_adr(0x3b, 0x00)) +#define JL_RAND ((JL_RAND_TypeDef *)JL_RAND_BASE) + +//............. 0x3e00 - 0x3eff............ for p33 +typedef struct { + __RW __u32 PMU_CON; + __RW __u32 PMU_STA; +} JL_PMU_TypeDef; + +#define JL_PMU_BASE (ls_base + map_adr(0x3e, 0x00)) +#define JL_PMU ((JL_PMU_TypeDef *)JL_PMU_BASE) + +//............. 0x4000 - 0x40ff............ +typedef struct { + __RW __u32 CON; + __RW __u32 BASE; + __RW __u32 ADC_CON; + __RW __u32 ADC_CON1; + __RW __u32 HF_CON0; + __RW __u32 HF_CON1; + __RW __u32 HF_CRAM; + __RW __u32 HF_CRAM2; + __RW __u32 HF_DRAM; + __RW __u32 LF_CON; + __RW __u32 LF_RES; + __RW __u32 FMRX_CON4; + __RW __u32 FMRX_CON5; + + __RW __u32 TX_CON0; + __RW __u32 TX_CON1; + __RW __u32 TX_PILOT; + __RW __u32 TX_SYN_GAIN; + __RW __u32 TX_MUL; + __RW __u32 TX_ADR; + __RW __u32 TX_LEN; + __RW __u32 TX_FREQ; + __RW __u32 TX_BASE_ADR; +} JL_FM_TypeDef; + +#define JL_FM_BASE (ls_base + map_adr(0x40, 0x00)) +#define JL_FM ((JL_FM_TypeDef *)JL_FM_BASE) + + +//............. 0x4100 - 0x41ff............ for lsb peri(spi0/sd0) +typedef struct { + __RW __u8 ENCCON ; + __WO __u16 ENCKEY ; + __WO __u16 ENCADR ; +} JL_PERIENC_TypeDef; + +#define JL_PERIENC_BASE (ls_base + map_adr(0x41, 0x00)) +#define JL_PERIENC ((JL_PERIENC_TypeDef *)JL_PERIENC_BASE) + +//............. 0x4200 - 0x42ff............ for sbc +typedef struct { + __RW __u32 CON0; + __WO __u32 DEC_SRC_ADR; + __WO __u32 DEC_DST_ADR; + __WO __u32 DEC_PCM_WCNT; + __WO __u32 DEC_INBUF_LEN; + __WO __u32 ENC_SRC_ADR; + __WO __u32 ENC_DST_ADR; + __RO __u32 DEC_DST_BASE; + __WO __u32 DEC_WEIGHT_BASE; + __WO __u32 DEC_WEIGHT_ADD; + +} JL_SBC_TypeDef; + +#define JL_SBC_BASE (ls_base + map_adr(0x42, 0x00)) +#define JL_SBC ((JL_SBC_TypeDef *)JL_SBC_BASE) + +//............. 0x4300 - 0x43ff............ for aes +typedef struct { + __RW __u32 CON; + __RW __u32 DATIN; + __WO __u32 KEY; + __RW __u32 ENCRES0; + __RW __u32 ENCRES1; + __RW __u32 ENCRES2; + __RW __u32 ENCRES3; + __WO __u32 NONCE; + __WO __u8 HEADER; + __WO __u32 SRCADR; + __WO __u32 DSTADR; + __WO __u32 CTCNT; + __WO __u32 TAGLEN; + __RO __u32 TAGRES0; + __RO __u32 TAGRES1; + __RO __u32 TAGRES2; + __RO __u32 TAGRES3; +} JL_AES_TypeDef; + +#define JL_AES_BASE (ls_base + map_adr(0x43, 0x00)) +#define JL_AES ((JL_AES_TypeDef *)JL_AES_BASE) + +//............. 0x4600 - 0x46ff............ for pll0_ctl +typedef struct { + __RW __u32 CON0; + __RW __u32 CON1; + __RW __u32 CON2; + __RW __u32 CON3; + __RW __u32 CON4; + __RW __u32 INTF0; + __RW __u32 INTF1; +} JL_PLL0_TypeDef; + +#define JL_PLL0_BASE (ls_base + map_adr(0x46, 0x00)) +#define JL_PLL0 ((JL_PLL0_TypeDef *)JL_PLL0_BASE) + + +//............. 0x4700 - 0x47ff............ for pll1_ctl +typedef struct { + __RW __u32 CON0; + __RW __u32 CON1; + __RW __u32 CON2; + __RW __u32 CON3; + __RW __u32 CON4; + __RW __u32 INTF0; + __RW __u32 INTF1; +} JL_PLL1_TypeDef; + +#define JL_PLL1_BASE (ls_base + map_adr(0x47, 0x00)) +#define JL_PLL1 ((JL_PLL1_TypeDef *)JL_PLL1_BASE) + + +//............. 0x4a00 - 0x4fff............ for sie +typedef struct { + __RW __u32 FADDR; + __RW __u32 POWER; + __RO __u32 INTRTX1; + __RO __u32 INTRTX2; + __RO __u32 INTRRX1; + __RO __u32 INTRRX2; + __RO __u32 INTRUSB; + __RW __u32 INTRTX1E; + __RW __u32 INTRTX2E; + __RW __u32 INTRRX1E; + __RW __u32 INTRRX2E; + __RW __u32 INTRUSBE; + __RO __u32 FRAME1; + __RO __u32 FRAME2; + __RO __u32 RESERVED14; + __RW __u32 DEVCTL; + __RO __u32 RESERVED10_0x16[0x16 - 0x10 + 1]; + +} JL_USB_SIE_TypeDef; + +#define JL_USB_SIE_BASE (ls_base + map_adr(0x4a, 0x00)) +#define JL_USB_SIE ((JL_USB_SIE_TypeDef *)JL_USB_SIE_BASE) + +typedef struct { + __RO __u32 RESERVED0; + __RW __u32 CSR0; + __RO __u32 RESERVED2_5[5 - 1]; + __RO __u32 COUNT0; + +} JL_USB_EP0_TypeDef; + +#define JL_USB_EP0_BASE (ls_base + map_adr(0x4a, 0x10)) +#define JL_USB_EP0 ((JL_USB_EP0_TypeDef *)JL_USB_EP0_BASE) + + +typedef struct { + __RW __u32 TXMAXP; + __RW __u32 TXCSR1; + __RW __u32 TXCSR2; + __RW __u32 RXMAXP; + __RW __u32 RXCSR1; + __RW __u32 RXCSR2; + __RO __u32 RXCOUNT1; + __RO __u32 RXCOUNT2; + __RW __u32 TXTYPE; + __RO __u32 TXINTERVAL; + __RW __u32 RXTYPE; + __RO __u32 RXINTERVAL; + +} JL_USB_EP_TypeDef; + +#define JL_USB_EP1_BASE (ls_base + map_adr(0x4b, 0x10)) +#define JL_USB_EP1 ((JL_USB_EP_TypeDef *)JL_USB_EP1_BASE) + +#define JL_USB_EP2_BASE (ls_base + map_adr(0x4c, 0x10)) +#define JL_USB_EP2 ((JL_USB_EP_TypeDef *)JL_USB_EP2_BASE) + +#define JL_USB_EP3_BASE (ls_base + map_adr(0x4d, 0x10)) +#define JL_USB_EP3 ((JL_USB_EP_TypeDef *)JL_USB_EP3_BASE) + +#define JL_USB_EP4_BASE (ls_base + map_adr(0x4e, 0x10)) +#define JL_USB_EP4 ((JL_USB_EP_TypeDef *)JL_USB_EP4_BASE) + + +//............. 0x5000 - 0x57ff............ for port +typedef struct { + __RW __u32 OUT; + __RO __u32 IN; + __RW __u32 DIR; + __RW __u32 DIE; + __RW __u32 PU; + __RW __u32 PD; + __RW __u32 HD0; + __RW __u32 HD; + __RW __u32 DIEH; +} JL_PORT_FLASH_TypeDef; + +#define JL_PORTA_BASE (ls_base + map_adr(0x50, 0x00)) +#define JL_PORTA ((JL_PORT_FLASH_TypeDef *)JL_PORTA_BASE) + +#define JL_PORTB_BASE (ls_base + map_adr(0x51, 0x00)) +#define JL_PORTB ((JL_PORT_FLASH_TypeDef *)JL_PORTB_BASE) + +#define JL_PORTC_BASE (ls_base + map_adr(0x52, 0x00)) +#define JL_PORTC ((JL_PORT_FLASH_TypeDef *)JL_PORTC_BASE) + +#define JL_PORTD_BASE (ls_base + map_adr(0x53, 0x00)) +#define JL_PORTD ((JL_PORT_FLASH_TypeDef *)JL_PORTD_BASE) + +#define JL_PORTE_BASE (ls_base + map_adr(0x54, 0x00)) +#define JL_PORTE ((JL_PORT_FLASH_TypeDef *)JL_PORTE_BASE) + +#define JL_PORTG_BASE (ls_base + map_adr(0x55, 0x00)) +#define JL_PORTG ((JL_PORT_FLASH_TypeDef *)JL_PORTG_BASE) + +#define JL_PORTP_BASE (ls_base + map_adr(0x57, 0x00)) +#define JL_PORTP ((JL_PORT_FLASH_TypeDef *)JL_PORTP_BASE) + +//............. 0x6000 - 0x60ff............ for port others +typedef struct { + __RW __u32 CON0; +} JL_USB_IO_TypeDef; + +#define JL_USB_IO_BASE (ls_base + map_adr(0x60, 0x00)) +#define JL_USB_IO ((JL_USB_IO_TypeDef *)JL_USB_IO_BASE) + +typedef struct { + __RW __u32 CON0; + __RW __u32 CON1; + __RW __u32 CON2; + __RW __u32 CON3; +} JL_WAKEUP_TypeDef; + +#define JL_WAKEUP_BASE (ls_base + map_adr(0x60, 0x01)) +#define JL_WAKEUP ((JL_WAKEUP_TypeDef *)JL_WAKEUP_BASE) + +typedef struct { + //__RW __u32 IOMC0; + __RW __u32 CON0; + __RW __u32 OCH_CON0; + __RW __u32 OCH_CON1; + __RW __u32 OCH_CON2; + __RW __u32 ICH_CON0; + __RW __u32 ICH_CON1; + __RW __u32 ICH_CON2; + __RW __u32 ICH_CON3; +} JL_IOMC_TypeDef; + +#define JL_IOMC_BASE (ls_base + map_adr(0x60, 0x05)) +#define JL_IOMC ((JL_IOMC_TypeDef *)JL_IOMC_BASE) +#define JL_IOMAP ((JL_IOMC_TypeDef *)JL_IOMC_BASE) + +//............. 0x6100 - 0x61ff............ for led +typedef struct { + __RW __u32 CON0; + __RW __u32 CON1; + __RW __u32 CON2; + __RW __u32 CON3; + __RW __u32 BRI_PRDL; + __RW __u32 BRI_PRDH; + __RW __u32 BRI_DUTY0L; + __RW __u32 BRI_DUTY0H; + __RW __u32 BRI_DUTY1L; + __RW __u32 BRI_DUTY1H; + __RW __u32 PRD_DIVL; + __RW __u32 DUTY0; + __RW __u32 DUTY1; + __RW __u32 DUTY2; + __RW __u32 DUTY3; + __RO __u32 CNT_RD; + __RW __u32 CON4; + __WO __u32 CNT_SYNC; + __RW __u32 CNT_DEC; +} JL_PLED_TypeDef; + +#define JL_PLED_BASE (ls_base + map_adr(0x61, 0x00)) +#define JL_PLED ((JL_PLED_TypeDef *)JL_PLED_BASE) + +#include "io_omap.h" +#include "io_imap.h" + +#endif diff --git a/include_lib/driver/cpu/br28/asm/cache.h b/include_lib/driver/cpu/br28/asm/cache.h new file mode 100644 index 0000000..eab50ba --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/cache.h @@ -0,0 +1,101 @@ +//*********************************************************************************// +// Module name : cache.h // +// Description : q32DSP cache control head file // +// By Designer : zequan_liu // +// Dat changed : // +//*********************************************************************************// + +#ifndef __Q32DSP_CACHE__ +#define __Q32DSP_CACHE__ + +//#include "generic/typedef.h" +#if 0 +//------------------------------------------------------// +// icache function +//------------------------------------------------------// + +void IcuEnable(void); +void IcuDisable(void); +void IcuInitial(void); + +//void IcuFlushAll(void); +void IcuFlushinvAll(void); +//void IcuFlushRegion(int *beg, int len); // note len!=0 +void IcuFlushinvRegion(int *beg, int len); // note len!=0 + +void IcuUnlockAll(void); +void IcuUnlockRegion(int *beg, int len); // note len!=0 +void IcuPfetchRegion(int *beg, int len); // note len!=0 +void IcuLockRegion(int *beg, int len); // note len!=0 + +void IcuReportEnable(void); +void IcuReportDisable(void); +void IcuReportPrintf(void); +void IcuReportClear(void); + +void IcuEmuEnable(void); +void IcuEmuDisable(void); +void IcuEmuMessage(void); + +#define WAIT_ICACHE_IDLE do{asm volatile("csync"); \ + while(!(q32DSP_icu(core_num())->CON & BIT(31)));} while(0); + +//------------------------------------------------------// +// dcache function +//------------------------------------------------------// +void DcuEnable(void); +void DcuDisable(void); +void DcuInitial(void); + +//void DcuFlushAll(void); +void DcuFlushinvAll(void); +//void DcuFlushRegion(int *beg, int len); // note len!=0 +void DcuFlushinvRegion(int *beg, int len); // note len!=0 + +void DcuUnlockAll(void); +void DcuUnlockRegion(int *beg, int len); // note len!=0 +void DcuPfetchRegion(int *beg, int len); // note len!=0 +void DcuLockRegion(int *beg, int len); // note len!=0 + +void DcuReportEnable(void); +void DcuReportDisable(void); +void DcuReportPrintf(void); +void DcuReportClear(void); + +void DcuEmuEnable(void); +void DcuEmuDisable(void); +void DcuEmuMessage(void); + +#define WAIT_DCACHE_IDLE do{asm volatile("csync"); while(!(JL_DCU->CON & BIT(31)));} while(0); +#endif + +void flush_dcache(void *ptr, int len); +void flushinv_dcache(void *ptr, int len); +void IcuEnable(void); +void DcuEnable(void); +void IcuWaitIdle(void); +void DcuWaitIdle(void); +void IcuDisable(void); +void DcuDisable(void); +void IcuFlushinvAll(void); +void IcuUnlockAll(void); +void IcuFlushinvRegion(int *beg, int len); +void IcuUnlockRegion(int *beg, int len); +void IcuLockRegion(int *beg, int len); +void IcuPfetchRegion(int *beg, int len); +void DcuFlushinvAll(void); +void DcuFlushinvRegion(int *beg, int len); +void DcuPfetchRegion(int *beg, int len); +void IcuInitial(void); +void DcuInitial(void); + +#define WAIT_DCACHE_IDLE do {DcuWaitIdle();} while(0); +#define WAIT_ICACHE_IDLE do {IcuWaitIdle();} while(0); +//#define WAIT_DCACHE_IDLE do{asm volatile("csync"); while(!(JL_DCU->CON & BIT(31)));} while(0); + +#endif /* #ifndef __Q32DSP_CACHE__ */ +//*********************************************************************************// +// // +// end of this module // +// // +//*********************************************************************************// diff --git a/include_lib/driver/cpu/br28/asm/charge.h b/include_lib/driver/cpu/br28/asm/charge.h new file mode 100644 index 0000000..1f317e4 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/charge.h @@ -0,0 +1,169 @@ +#ifndef _CHARGE_H_ +#define _CHARGE_H_ + +#include "typedef.h" +#include "device.h" + +/*------充满电电压选择 4.041V-4.534V-------*/ +//低压压电池配置0~15 +#define CHARGE_FULL_V_4041 0 +#define CHARGE_FULL_V_4061 1 +#define CHARGE_FULL_V_4081 2 +#define CHARGE_FULL_V_4101 3 +#define CHARGE_FULL_V_4119 4 +#define CHARGE_FULL_V_4139 5 +#define CHARGE_FULL_V_4159 6 +#define CHARGE_FULL_V_4179 7 +#define CHARGE_FULL_V_4199 8 +#define CHARGE_FULL_V_4219 9 +#define CHARGE_FULL_V_4238 10 +#define CHARGE_FULL_V_4258 11 +#define CHARGE_FULL_V_4278 12 +#define CHARGE_FULL_V_4298 13 +#define CHARGE_FULL_V_4318 14 +#define CHARGE_FULL_V_4338 15 +//高压电池配置16~31 +#define CHARGE_FULL_V_4237 16 +#define CHARGE_FULL_V_4257 17 +#define CHARGE_FULL_V_4275 18 +#define CHARGE_FULL_V_4295 19 +#define CHARGE_FULL_V_4315 20 +#define CHARGE_FULL_V_4335 21 +#define CHARGE_FULL_V_4354 22 +#define CHARGE_FULL_V_4374 23 +#define CHARGE_FULL_V_4394 24 +#define CHARGE_FULL_V_4414 25 +#define CHARGE_FULL_V_4434 26 +#define CHARGE_FULL_V_4454 27 +#define CHARGE_FULL_V_4474 28 +#define CHARGE_FULL_V_4494 29 +#define CHARGE_FULL_V_4514 30 +#define CHARGE_FULL_V_4534 31 +#define CHARGE_FULL_V_MAX 32 +/*****************************************/ + +/*充满电电流选择 2mA-30mA*/ +#define CHARGE_FULL_mA_2 0 +#define CHARGE_FULL_mA_5 1 +#define CHARGE_FULL_mA_7 2 +#define CHARGE_FULL_mA_10 3 +#define CHARGE_FULL_mA_15 4 +#define CHARGE_FULL_mA_20 5 +#define CHARGE_FULL_mA_25 6 +#define CHARGE_FULL_mA_30 7 + +/* + 充电电流选择 + 恒流:20-220mA +*/ +#define CHARGE_mA_15 0 +#define CHARGE_mA_20 1 +#define CHARGE_mA_25 2 +#define CHARGE_mA_30 3 +#define CHARGE_mA_35 4 +#define CHARGE_mA_40 5 +#define CHARGE_mA_50 6 +#define CHARGE_mA_60 7 +#define CHARGE_mA_80 8 +#define CHARGE_mA_100 9 +#define CHARGE_mA_120 10 +#define CHARGE_mA_140 11 +#define CHARGE_mA_160 12 +#define CHARGE_mA_200 13 +#define CHARGE_mA_250 14 +#define CHARGE_mA_300 15 +#define CHARGE_mA_1P5 (BIT(4)|CHARGE_mA_15) +#define CHARGE_mA_2 (BIT(4)|CHARGE_mA_20) +#define CHARGE_mA_2P5 (BIT(4)|CHARGE_mA_25) +#define CHARGE_mA_3 (BIT(4)|CHARGE_mA_30) +#define CHARGE_mA_3P5 (BIT(4)|CHARGE_mA_35) +#define CHARGE_mA_4 (BIT(4)|CHARGE_mA_40) +#define CHARGE_mA_5 (BIT(4)|CHARGE_mA_50) +#define CHARGE_mA_6 (BIT(4)|CHARGE_mA_60) +#define CHARGE_mA_8 (BIT(4)|CHARGE_mA_80) +#define CHARGE_mA_10 (BIT(4)|CHARGE_mA_100) +#define CHARGE_mA_12 (BIT(4)|CHARGE_mA_120) +#define CHARGE_mA_14 (BIT(4)|CHARGE_mA_140) +#define CHARGE_mA_16 (BIT(4)|CHARGE_mA_160) + +/* + 充电口下拉选择 + 电阻 50k ~ 200k +*/ +#define CHARGE_PULLDOWN_50K 0 +#define CHARGE_PULLDOWN_100K 1 +#define CHARGE_PULLDOWN_150K 2 +#define CHARGE_PULLDOWN_200K 3 + + +#define CHARGE_CCVOL_V 300 //涓流充电向恒流充电的转换点 + +#define DEVICE_EVENT_FROM_CHARGE (('C' << 24) | ('H' << 16) | ('G' << 8) | '\0') + +struct charge_platform_data { + u8 charge_en; //内置充电使能 + u8 charge_poweron_en; //开机充电使能 + u8 charge_full_V; //充满电电压大小 + u8 charge_full_mA; //充满电电流大小 + u8 charge_mA; //恒流充电电流大小 + u8 charge_trickle_mA; //涓流充电电流大小 + u8 ldo5v_pulldown_en; //下拉使能位 + u8 ldo5v_pulldown_lvl; //ldo5v的下拉电阻配置项,若充电舱需要更大的负载才能检测到插入时,请将该变量置为对应阻值 + u8 ldo5v_pulldown_keep; //下拉电阻在softoff时是否保持,ldo5v_pulldown_en=1时有效 + u16 ldo5v_off_filter; //ldo5v拔出过滤值,过滤时间 = (filter*2 + 20)ms,ldoin<0.6V且时间大于过滤时间才认为拔出,对于充满直接从5V掉到0V的充电仓,该值必须设置成0,对于充满由5V先掉到0V之后再升压到xV的充电仓,需要根据实际情况设置该值大小 + u16 ldo5v_on_filter; //ldo5v>vbat插入过滤值,电压的过滤时间 = (filter*2)ms + u16 ldo5v_keep_filter; //1VCLK_CON0, 0, 1, x) +#define RCH_EN(x) SFR(JL_CLOCK->CLK_CON0, 0, 1, x) +//for MACRO - RCH_EN +enum { + RCH_EN_250K = 0, + RCH_EN_16M, +}; + +#define OSC_CLOCK_IN(x) SFR(JL_CLOCK->CLK_CON0, 1, 3, x) +//for MACRO - OSC_CLOCK_IN +enum { + OSC_CLOCK_IN_BT_OSC = 0, + OSC_CLOCK_IN_BT_OSC_X2, + OSC_CLOCK_IN_STD_24M, + OSC_CLOCK_IN_RTC_OSC, + OSC_CLOCK_IN_LRC_CLK, + OSC_CLOCK_IN_PAT, +}; +#define PLL_96M_SEL_END 6 +#define PLL_96M_SEL_GET() ((JL_CLOCK->CLK_CON0 >> 4) & 0xF) +#define PLL_96M_SEL(x) SFR(JL_CLOCK->CLK_CON0, 4, 4, x) +enum { + PLL_96M_SEL_NULL = 0, + + PLL_96M_SEL_7DIV2, //f5 + PLL_96M_SEL_5DIV2, //f4 + PLL_96M_SEL_4DIV2, //f3 + PLL_96M_SEL_3DIV2, //f2 + PLL_96M_SEL_1DIV1, //f1 + + + + PLL1_96M_SEL_7DIV2, //f5 + PLL1_96M_SEL_5DIV2, //f4 + PLL1_96M_SEL_4DIV2, //f3 + PLL1_96M_SEL_3DIV2, //f2 + PLL1_96M_SEL_1DIV1, //f1 + +}; + +#define PLL_48M_SEL_GET() ((JL_CLOCK->CLK_CON0 & BIT(8)) >> 8) +#define PLL_48M_SEL(x) SFR(JL_CLOCK->CLK_CON0, 8, 1, x) +enum { + PLL_48M_SEL_DIV2 = 0, + PLL_48M_SEL_DIV1, +}; + +#define STD_48M_SEL(x) SFR(JL_CLOCK->CLK_CON0, 9, 1, x) +#define PLL_48M_TO_STD_48M 0 +#define BTOSCX2_TO_STD_48M 1 + +#define STD_48M_SEL_GET() ((JL_CLOCK->CLK_CON0 & BIT(9)) >> 9) + +#define STD_24M_SEL(x) SFR(JL_CLOCK->CLK_CON0, 10, 1, x) +#define STD_48M_DIV2_TO_STD_24M 0 +#define BTOSC_TO_STD_24M 1 + + + +#define PLL_SYS_SEL(x) SFR(JL_CLOCK->CLK_CON1, 0, 4, x) +#define PLL_SYS_SEL_GET() ((JL_CLOCK->CLK_CON1 & 0xF)) + +#define PLL_SYS_SEL_END 6 +//for MACRO - PLL_SYS_SEL +enum { + PLL_SYS_SEL_NULL = 0, + PLL_SYS_SEL_7DIV2, //f5 + PLL_SYS_SEL_5DIV2, //f4 + PLL_SYS_SEL_4DIV2, //f3 + PLL_SYS_SEL_3DIV2, //f2 + PLL_SYS_SEL_1DIV1, //f1 + + + PLL1_SYS_SEL_7DIV2, //f5 + PLL1_SYS_SEL_5DIV2, //f4 + PLL1_SYS_SEL_4DIV2, //f3 + PLL1_SYS_SEL_3DIV2, //f2 + PLL1_SYS_SEL_1DIV1, //f1 + +}; + +#define PLL_SYS_DIV(x) SFR(JL_CLOCK->CLK_CON1, 4, 4, x) +//for MACRO - PLL_SYS_DIV +enum { + PLL_SYS_DIV1 = 0, + PLL_SYS_DIV3, + PLL_SYS_DIV5, + PLL_SYS_DIV7, + + PLL_SYS_DIV1X2 = 4, + PLL_SYS_DIV3X2, + PLL_SYS_DIV5X2, + PLL_SYS_DIV7X2, + + PLL_SYS_DIV1X4 = 8, + PLL_SYS_DIV3X4, + PLL_SYS_DIV5X4, + PLL_SYS_DIV7X4, + + PLL_SYS_DIV1X8 = 12, + PLL_SYS_DIV3X8, + PLL_SYS_DIV5X8, + PLL_SYS_DIV7X8, +}; +#define MAIN_CLOCK_SEL(x) SFR(JL_CLOCK->CLK_CON1, 8, 3, x); \ + asm("csync") + +//for MACRO - CLOCK_IN +enum { + MAIN_CLOCK_IN_RC_250K = 0, + MAIN_CLOCK_IN_PAT, + MAIN_CLOCK_IN_RTC_OSC, + MAIN_CLOCK_IN_RC, + MAIN_CLOCK_IN_BTOSC, + MAIN_CLOCK_IN_BTOSC_X2, + MAIN_CLOCK_IN_PLL, + MAIN_CLOCK_IN_RTOSC_L, //keep to fix make +}; + + +#define SFR_MODE(x) SFR(JL_CLOCK->CLK_CON1, 11, 1, x) +enum { + SFR_CLOCK_IDLE = 0, + SFR_CLOCK_ALWAYS_ON, +}; + + +#define BT_CLOCK_IN(x) SFR(JL_CLOCK->CLK_CON1, 14, 2, x) +//for MACRO - BT_CLOCK_IN +enum { + BT_CLOCK_IN_PLL48M = 0, + BT_CLOCK_IN_HSB, + BT_CLOCK_IN_LSB, + BT_CLOCK_IN_DISABLE, +}; + +#define PLL_ALNK0_SEL(x) SFR(JL_CLOCK->CLK_CON2, 0, 3, x) +#define PLL_ALNK0_DIV(x) SFR(JL_CLOCK->CLK_CON2, 3, 2, x) + +#define PLL_ALNK_EN(x) SFR(JL_CLOCK->CLK_CON2, 6, 1, x) +#define PLL_ALNK_SEL(x) SFR(JL_CLOCK->CLK_CON2, 7, 1, x) +//for MACRO - PLL_ALNK_SEL +enum { + PLL_ALNK_192M_DIV17 = 0, + PLL_ALNK_480M_DIV39, +}; + +#define USB_CLOCK_IN(x) SFR(JL_CLOCK->CLK_CON2, 8, 2, x) +//for MACRO - USB_CLOCK_IN +enum { + USB_CLOCK_IN_PLL48M = 0, + USB_CLOCK_IN_OSC, + USB_CLOCK_IN_LSB, + USB_CLOCK_IN_DISABLE, +}; + +#define UART_CLOCK_IN(x) SFR(JL_CLOCK->CLK_CON2, 10, 2, x) +//for MACRO - UART_CLOCK_IN +enum { + UART_CLOCK_IN_PLL24M = 0, + UART_CLOCK_IN_OSC, + UART_CLOCK_IN_LSB, + UART_CLOCK_IN_DISABLE, +}; + +#define PLL_FM_SEL(x) SFR(JL_CLOCK->CLK_CON2, 12, 2, x) +//for MACRO - PLL_APC_SEL +enum { + PLL_APC_SEL_PLL192M = 0, + PLL_APC_SEL_PLL137M, + PLL_APC_SEL_PLL107M, + PLL_APC_SEL_DISABLE, +}; + +#define PLL_FM_DIV(x) SFR(JL_CLOCK->CLK_CON2, 14, 4, x) +//for MACRO - PLL_APC_DIV +enum { + PLL_FM_DIV1 = 0, + PLL_FM_DIV3, + PLL_FM_DIV5, + PLL_FM_DIV7, + + PLL_FM_DIV1X2 = 4, + PLL_FM_DIV3X2, + PLL_FM_DIV5X2, + PLL_FM_DIV7X2, + + PLL_FM_DIV1X4 = 8, + PLL_FM_DIV3X4, + PLL_FM_DIV5X4, + PLL_FM_DIV7X4, + + PLL_FM_DIV1X8 = 12, + PLL_FM_DIV3X8, + PLL_FM_DIV5X8, + PLL_FM_DIV7X8, +}; +#define GPCNT_CLOCK_IN(x) SFR(JL_CLOCK->CLK_CON2, 28, 4, x) +//for MACRO - DAC_CLOCK_IN +enum { + GPCNT_CLOCK_IN_NULL = 0, + GPCNT_CLOCK_IN_SRC, + GPCNT_CLOCK_IN_ORG, + GPCNT_CLOCK_IN_HSB, + GPCNT_CLOCK_IN_XOSC_FSCK, + GPCNT_CLOCK_IN_BTOSC_48M, + GPCNT_CLOCK_IN_WL, + GPCNT_CLOCK_IN_USB, + GPCNT_CLOCK_IN_PMU_ANA, + GPCNT_CLOCK_IN_VAD_VCON0, + GPCNT_CLOCK_IN_VAD_VCOP0, + GPCNT_CLOCK_IN_RC_16M, + GPCNT_CLOCK_IN_P33_RC_250k, + GPCNT_CLOCK_IN_LRC, + GPCNT_CLOCK_IN_DPLL_OUT, + GPCNT_CLOCK_IN_RTC_OSC, +}; + +#define PLL_IMD_SEL_GET( ) ((JL_CLOCK->CLK_CON3 >> 8) & 0xF) +#define PLL_IMD_SEL(x) SFR(JL_CLOCK->CLK_CON3, 8, 4, x) +#define PLL_IMD_DIV(x) SFR(JL_CLOCK->CLK_CON3, 12, 4, x) + +#define PLL_TDM_SEL_GET(x) ((JL_CLOCK->CLK_CON3 >> 24) & 0x7) +#define PLL_TDM_SEL(x) SFR(JL_CLOCK->CLK_CON3, 24, 3, x) +#define PLL_TDM_DIV(x) SFR(JL_CLOCK->CLK_CON3, 27, 2, x) + + +#define PLL_EN(x) SFR(JL_PLL0->CON0, 0, 1, (x)) +#define PLL_REST(x) SFR(JL_PLL0->CON0, 1, 1, (x)) +#define PLL_MODE(x) SFR(JL_PLL0->CON0, 2, 1, (x)) +#define PLL_PFDS(x) SFR(JL_PLL0->CON0, 3, 2, (x)) +#define PLL_ICPS(x) SFR(JL_PLL0->CON0, 5, 3, (x)) +#define PLL_LPFR2(x) SFR(JL_PLL0->CON0, 8, 3, (x)) +#define PLL_IVCO(x) SFR(JL_PLL0->CON0, 11, 3, (x)) +#define PLL_LDO12A(x) SFR(JL_PLL0->CON0, 14, 3, (x)) +#define PLL_LDO12D(x) SFR(JL_PLL0->CON0, 17, 3, (x)) +#define PLL_LDO_BYPASS(x) SFR(JL_PLL0->CON0, 20, 1, (x)) +#define PLL_TSEL(x) SFR(JL_PLL0->CON0, 21, 2, x) +#define PLL_TEST(x) SFR(JL_PLL0->CON0, 23, 1, x) +#define PLL_VBG_TR(x) SFR(JL_PLL0->CON0, 27, 4, (x)) + + + +//REFDS +#define PLL_DIVn(x) SFR(JL_PLL0->CON1, 0, 7, x) +#define PLL_REF_SEL0(x) SFR(JL_PLL0->CON1, 7, 2, x) +//for MACRO - PLL_RSEL0 +enum { + PLL_RSEL_RCLK = 0, // + PLL_RSEL_RCH, + PLL_RSEL_DPLL_CLK, + PLL_RSEL_PAT_CLK, +}; + +#define PLL_REF_SEL1(x) SFR(JL_PLL0->CON1, 9, 1, x) +//for MACRO - PLL_REF_SEL1 +enum { + PLL_REF_SEL_BTOSC_DIFF = 0, //btosc_DIFF + PLL_REF_SEL_RCLK, +}; + + +#define PLL_DIVn_EN(x) SFR(JL_PLL0->CON1, 10, 2, x) +//for MACRO - PLL_DIVn_EN +enum { + PLL_DIVn_EN_X2 = 0, + PLL_DIVn_DIS_DIV1, + PLL_DIVn_EN_DIVn, +}; + +#define PLL_FBDS(x) SFR(JL_PLL0->CON2, 0, 12, x) + +#define PLL_CLK_1DIV1_OE(x) SFR(JL_PLL0->CON3, 0, 1, x) //f1 +#define PLL_CLK_3DIV2_OE(x) SFR(JL_PLL0->CON3, 1, 1, x) //f2 +#define PLL_CLK_4DIV2_OE(x) SFR(JL_PLL0->CON3, 2, 1, x) //f3 +#define PLL_CLK_5DIV2_OE(x) SFR(JL_PLL0->CON3, 3, 1, x) //f4 +#define PLL_CLK_7DIV2_OE(x) SFR(JL_PLL0->CON3, 4, 1, x) //f5 + +#define PLL_CLK_EN(x) SFR(JL_PLL0->CON3, 9, 1, x) + + +#define PLL1_EN(x) SFR(JL_PLL1->CON0, 0, 1, (x)) +#define PLL1_REST(x) SFR(JL_PLL1->CON0, 1, 1, (x)) +#define PLL1_MODE(x) SFR(JL_PLL1->CON0, 2, 1, (x)) +#define PLL1_PFDS(x) SFR(JL_PLL1->CON0, 3, 2, (x)) +#define PLL1_ICPS(x) SFR(JL_PLL1->CON0, 5, 3, (x)) +#define PLL1_LPFR2(x) SFR(JL_PLL1->CON0, 8, 3, (x)) +#define PLL1_IVCO(x) SFR(JL_PLL1->CON0, 11, 3, (x)) +#define PLL1_LDO12A(x) SFR(JL_PLL1->CON0, 14, 3, (x)) +#define PLL1_LDO12D(x) SFR(JL_PLL1->CON0, 17, 3, (x)) +#define PLL1_LDO_BYPASS(x) SFR(JL_PLL1->CON0, 20, 1, (x)) +#define PLL1_TSEL(x) SFR(JL_PLL1->CON0, 21, 2, x) +#define PLL1_TEST(x) SFR(JL_PLL1->CON0, 23, 1, x) +#define PLL1_VBG_TR(x) SFR(JL_PLL1->CON0, 27, 4, (x)) + +#define PLL1_DIVn(x) SFR(JL_PLL1->CON1, 0, 7, x) +#define PLL1_REF_SEL0(x) SFR(JL_PLL1->CON1, 7, 2, x) +#define PLL1_REF_SEL1(x) SFR(JL_PLL1->CON1, 9, 1, x) +#define PLL1_DIVn_EN(x) SFR(JL_PLL1->CON1, 10, 2, x) + +#define PLL1_FBDS(x) SFR(JL_PLL1->CON2, 0, 12, x) + +#define PLL1_CLK_1DIV1_OE(x) SFR(JL_PLL1->CON3, 0, 1, x) //f1 +#define PLL1_CLK_3DIV2_OE(x) SFR(JL_PLL1->CON3, 1, 1, x) //f2 +#define PLL1_CLK_4DIV2_OE(x) SFR(JL_PLL1->CON3, 2, 1, x) //f3 +#define PLL1_CLK_5DIV2_OE(x) SFR(JL_PLL1->CON3, 3, 1, x) //f4 +#define PLL1_CLK_7DIV2_OE(x) SFR(JL_PLL1->CON3, 4, 1, x) //f5 +#define PLL1_CLK_EN(x) SFR(JL_PLL1->CON3, 9, 1, x) + + +#define HSB_CLK_DIV(x) SFR(JL_CLOCK->SYS_DIV, 0, 8, x) +#define LSB_CLK_DIV(x) SFR(JL_CLOCK->SYS_DIV, 8, 3, x) +#define SFC_CLK_DIV(x) SFR(JL_CLOCK->SYS_DIV, 12, 3, x) + +/********************************************************************************/ +#define GPCNT_EN(x) SFR(JL_GPCNT->CON, 0, 1, x) +#define GPCNT_CSS(x) SFR(JL_GPCNT->CON, 1, 3, x) +//for MACRO - GPCNT_CSS +enum { + GPCNT_CSS_LSB = 0, + GPCNT_CSS_OSC, + GPCNT_CSS_INPUT_CH2, + GPCNT_CSS_INPUT_CH3, + GPCNT_CSS_CLOCK_IN, + GPCNT_CSS_RING, + GPCNT_CSS_PLL, + GPCNT_CSS_INTPUT_CH1, +}; + +#define GPCNT_CLR_PEND(x) SFR(JL_GPCNT->CON, 6, 1, x) +#define GPCNT_GTS(x) SFR(JL_GPCNT->CON, 8, 4, x) + +#define GPCNT_GSS(x) SFR(JL_GPCNT->CON, 12, 3, x) +//for MACRO - GPCNT_CSS +enum { + GPCNT_GSS_LSB = 0, + GPCNT_GSS_OSC, + GPCNT_GSS_INPUT_CH14, //iomap con1[27:24] + GPCNT_GSS_INPUT_CH15, //iomap con1[31:28] + GPCNT_GSS_CLOCK_IN, //CLK_CON2[31:28] + GPCNT_GSS_RING, + GPCNT_GSS_PLL, + GPCNT_GSS_INPUT_CH13, //iomap con1[23:20] +}; + +//wla_con16 xosc +#define XOSC_BGTR_10v_4(x) ((x&0xf)<<15) + +//wla_con8 xosc +#define XOSC_EN_10v_1(x) ((x&0x1)<<0) +#define XOSCLDO_PAS_10v_1(x) ((x&0x1)<<1) +#define XOSCLDO_S_10v_3(x) ((x&0x7)<<2) +#define XOSC_CPTEST_EN_10v_1(x) ((x&0x1)<<5) +#define XOSC_HCS_10v_5(x) ((x&0x1f)<<6) +#define XOSC_CLS_10v_4(x) ((x&0xf)<<11) +#define XOSC_CRS_10v_4(x) ((x&0xf)<<15) +#define XOSC_BT_HDS_10v_2(x) ((x&0x3)<<19) +#define XOSC_ANATEST_EN_10v_1(x) ((x&0x1)<<21) +#define XOSC_ANATEST_S_10v_3(x) ((x&0x7)<<22) +#define XOSC_BT_OE_10v_1(x) ((x&0x1)<<25) +#define XOSC_SYS1_OE_10v_1(x) ((x&0x1)<<26) +#define XOSC_CORE48M_OE_10v_1(x) ((x&0x1)<<27) +#define XOSC_CORE48M_S_10v_3(x) ((x&0x7)<<28) +#define XOSC_FSCK_OE_10v_1(x) ((x&0x1)<<31) + +//wla_con9 xosc +#define XOSC_FTCS_10v_3(x) ((x&0x7)<<0) +#define XOSC_FTOE_10v_1(x) ((x&0x1)<<3) +#define XOSC_FTIS_10v_5(x) ((x&0x1f)<<4) +#define XOSC_CORE24M_OE_10v_1(x) ((x&0x1)<<9) +#define XOSC_CMP_MODE_10v_1(x) ((x&0x1)<<10) +#define XOSC_FTEN_10v_1(x) ((x&0x1)<<11) +#define XOSC_PMU_HDS_10v_2(x) ((x&0x3)<<12) +#define XOSC_PMU_OE_10v_1(x) ((x&0x1)<<14) +#define XOSC_SYS1_HDS_10v_2(x) ((x&0x3)<<15) +#define XOSC_DAC_HDS_10v_2(x) ((x&0x3)<<17) +#define XOSC_DAC_OE_10v_1(x) ((x&0x1)<<19) +#define XOSC_LFSREN_10v_1(x) ((x&0x1)<<20) + +//wla_con10 +//PLL +#define XOSC_ADET_EN_10v_1(x) ((x&0x1)<<0) +#define XOSC_ADET_S_10v_2(x) ((x&0x3)<<1) +#define XOSC_VAD_DIVS_10v_4(x) ((x&0xf)<<3) +#define XOSC_SYS0_HDS_10v_2(x) ((x&0x3)<<7) +#define XOSC_SYS0_OE_10v_1(x) ((x&0x1)<<9) +#define XOSC_VAD_HDS_10v_2(x) ((x&0x3)<<10) +#define XOSC_VAD_OE_10v_1(x) ((x&0x1)<<12) + +//wla_con21 +#define WLA_RD_MUX_4(x) ((x&0xf)<<0) + +//wla_con30 +#define XOSC_ADET_GET_RESULT() ((JL_WLA->WLA_CON30 >> 4) & 1) + + +//CORE +#define ROM_MULTI_CYCLE(x) SFR(JL_CMNG->CON0,3,2,(x)) +#endif diff --git a/include_lib/driver/cpu/br28/asm/cpu.h b/include_lib/driver/cpu/br28/asm/cpu.h new file mode 100644 index 0000000..a30f6c4 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/cpu.h @@ -0,0 +1,380 @@ + +#ifndef ASM_CPU_H +#define ASM_CPU_H + + +#include "br28.h" +#include "csfr.h" +#include "cache.h" +#ifndef __ASSEMBLY__ + +typedef unsigned char u8, bool, BOOL; +typedef char s8; +typedef unsigned short u16; +typedef signed short s16; +typedef unsigned int u32; +typedef signed int s32; +typedef unsigned long long u64; +typedef u32 FOURCC; +typedef long long s64; +typedef unsigned long long u64; + + +#endif + + +#define ___trig __asm__ volatile ("trigger") + + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 0x3021 +#endif +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 0x4576 +#endif +#define CPU_ENDIAN LITTLE_ENDIAN + +#ifdef BT_DUT_INTERFERE +#define CPU_CORE_NUM 1 //dut interfere +#else +#define CPU_CORE_NUM 2 //sdk +#endif + +#define OS_CORE_AFFINITY_ENABLE 1 + +extern const int CONFIG_CPU_UNMASK_IRQ_ENABLE; + +///屏蔽的优先级, < N的优先级不可以响应 +#define CPU_IRQ_IPMASK_LEVEL 6 + +#define CPU_TASK_CLR(a) +#define CPU_TASK_SW(a) \ + do { \ + q32DSP(a)->ILAT_SET |= BIT(3-a); \ + } while (0) + + +#define CPU_INT_NESTING 2 + + +#ifndef __ASSEMBLY__ + +#if CPU_CORE_NUM > 1 +__attribute__((always_inline)) +static int current_cpu_id() +{ + unsigned id; + asm volatile("%0 = cnum" : "=r"(id) ::); + return id ; +} + +__attribute__((always_inline)) +static int core_num(void) +{ + u32 num; + asm volatile("%0 = cnum" : "=r"(num) :); + return num; +} + +#else +static inline int current_cpu_id() +{ + return 0; +} + +static inline int core_num(void) +{ + return 0; +} +#endif + +static inline int cpu_in_irq() +{ + int flag; + __asm__ volatile("%0 = icfg" : "=r"(flag)); + return flag & 0xff; +} + +extern int __cpu_irq_disabled(void); +static inline int cpu_irq_disabled() +{ + if (CONFIG_CPU_UNMASK_IRQ_ENABLE) { + return __cpu_irq_disabled(); + } else { + int flag; + __asm__ volatile("%0 = icfg" : "=r"(flag)); + return ((flag & 0x300) != 0x300); + } +} + +#if 0 +static inline int data_sat_s16(int ind) +{ + if (ind > 32767) { + ind = 32767; + } else if (ind < -32768) { + ind = -32768; + } + return ind; +} + +#else +static inline int data_sat_s16(int ind) +{ + __asm__ volatile( + " %0 = sat16(%0)(s) \t\n" + : "=&r"(ind) + : "0"(ind) + :); + return ind; +} +#endif + + +static inline u32 reverse_u32(u32 data32) +{ +#if 0 + u8 *dataptr = (u8 *)(&data32); + data32 = (((u32)dataptr[0] << 24) | ((u32)dataptr[1] << 16) | ((u32)dataptr[2] << 8) | (u32)dataptr[3]); +#else + __asm__ volatile("%0 = rev8(%0) \t\n" : "=&r"(data32) : "0"(data32) :); +#endif + return data32; +} + +static inline u32 reverse_u16(u16 data16) +{ + u32 retv; +#if 0 + u8 *dataptr = (u8 *)(&data16); + retv = (((u32)dataptr[0] << 8) | ((u32)dataptr[1])); +#else + retv = ((u32)data16) << 16; + __asm__ volatile("%0 = rev8(%0) \t\n" : "=&r"(retv) : "0"(retv) :); +#endif + return retv; +} + +static inline u32 rand32() +{ + return JL_RAND->R64L; +} + +#define __asm_sine(s64, precision) \ + ({ \ + u64 ret; \ + u8 sel = 0; \ + __asm__ volatile ("%0 = copex(%1) (%2)" : "=r"(ret) : "r"(s64), "i"(sel)); \ + ret = ret>>32; \ + ret;\ + }) + +void p33_soft_reset(void); +static inline void cpu_reset(void) +{ + // JL_CLOCK->PWR_CON |= (1 << 4); + p33_soft_reset(); +} + +#define __asm_csync() \ + do { \ + asm volatile("csync;"); \ + } while (0) + +#include "asm/irq.h" +#include "generic/printf.h" +#include "system/generic/log.h" + + +#define arch_atomic_read(v) \ + ({ \ + __asm_csync(); \ + (*(volatile int *)&(v)->counter); \ + }) +#if 0 +extern volatile int cpu_lock_cnt[]; +extern volatile int irq_lock_cnt[]; + + +static inline void local_irq_disable() +{ + __builtin_pi32v2_cli(); + irq_lock_cnt[current_cpu_id()]++; +} + + +static inline void local_irq_enable() +{ + if (--irq_lock_cnt[current_cpu_id()] == 0) { + __builtin_pi32v2_sti(); + } +} +#else + +extern void __local_irq_disable() ; + +extern void __local_irq_enable() ; + +extern void local_irq_disable(); +extern void local_irq_enable(); + +#endif + +#if(0 ) + +#define arch_spin_trylock(lock) \ + do { \ + __asm_csync(); \ + while ((lock)->rwlock); \ + (lock)->rwlock = 1; \ + }while(0) + +#define arch_spin_lock(lock) \ + do { \ + int ret = false; \ + __asm_csync(); \ + if (!(lock)->rwlock) { \ + ret = true; \ + (lock)->rwlock = 1; \ + } \ + if (ret) \ + break; \ + }while(1) + +#define arch_spin_unlock(lock) \ + do { \ + (lock)->rwlock = 0; \ + }while(0) + +#else + + + +static inline void q32DSP_testset(u8 volatile *ptr) +{ + asm volatile( + " 1: \n\t " + " testset b[%0] \n\t " + " ifeq goto 1b \n\t " + : + : "p"(ptr) + : "memory" + ); +} + +static inline void q32DSP_testclr(u8 volatile *ptr) +{ + asm volatile( + " b[%0] = %1 \n\t " + : + : "p"(ptr), "r"(0) + : "memory" + ); +} + +#define arch_spin_trylock(lock) \ + do { \ + q32DSP_testset((u8 *)(&lock->rwlock));\ + }while(0) + + +#define arch_spin_lock(lock) arch_spin_trylock(lock) + +#define arch_spin_unlock(lock) \ + do{ \ + q32DSP_testclr((u8 *)(&lock->rwlock)) ;\ + }while(0) + + +#endif + +#if 1 // CPU_CORE_NUM >1 + +extern volatile int cpu_lock_cnt[]; +extern volatile int irq_lock_cnt[]; +#if 0 +#define CPU_SR_ALLOC() \ +// int flags + + + + +#define CPU_CRITICAL_ENTER() \ + do { extern u8 volatile cpulock;\ + local_irq_disable(); \ + if(cpu_lock_cnt[current_cpu_id()]++ == 0) \ + q32DSP_testset(&cpulock);\ + __asm_csync(); \ + }while(0) + +// asm volatile("lockset;"); + +#define CPU_CRITICAL_EXIT() \ + do {extern u8 volatile cpulock; \ + if (--cpu_lock_cnt[current_cpu_id()] == 0) \ + q32DSP_testclr(&cpulock);\ + local_irq_enable();\ + }while(0) + +#endif + + +#define CPU_SR_ALLOC() \ + // int flags + +#define CPU_CRITICAL_ENTER() \ + do { \ + local_irq_disable(); \ + }while(0) + + +#define CPU_CRITICAL_EXIT() \ + do { \ + local_irq_enable(); \ + }while(0) + +// asm volatile("lockclr;"); +#else + + +#define CPU_SR_ALLOC() \ +// int flags + +#define CPU_CRITICAL_ENTER() \ + do { \ + local_irq_disable(); \ + __asm_csync(); \ + }while(0) + + +#define CPU_CRITICAL_EXIT() \ + do { \ + local_irq_enable(); \ + }while(0) + +#endif + +extern void cpu_assert_debug(); +extern const int config_asser; +#define ASSERT(a,...) \ + do { \ + if(config_asser){\ + if(!(a)){ \ + printf("cpu %d file:%s, line:%d",current_cpu_id(), __FILE__, __LINE__); \ + printf("ASSERT-FAILD: "#a" "__VA_ARGS__); \ + cpu_assert_debug(); \ + } \ + }else {\ + if(!(a)){ \ + cpu_reset(); \ + }\ + }\ + }while(0); + + + +#endif //__ASSEMBLY__ + + +#endif + diff --git a/include_lib/driver/cpu/br28/asm/crc16.h b/include_lib/driver/cpu/br28/asm/crc16.h new file mode 100644 index 0000000..35c7ae8 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/crc16.h @@ -0,0 +1,35 @@ +#ifndef __CPU_CRC16_H__ +#define __CPU_CRC16_H__ + + +#include "typedef.h" + + + +u16 CRC16(const void *ptr, u32 len); + +/* i_val: CRC校验初值 */ +u16 CRC16_with_initval(const void *ptr, u32 len, u16 i_val); + +u16 CRC16_with_code(const void *ptr, u32 len, u16 code); + +void spi_crc16_set(u16 crc); +u16 spi_crc16_get(void); + +void CrcDecode(void *buf, u16 len); + +u16 get_page_efuse(u32 page, u32 delay_cnt); +void init_enc_key(u8 cmd); +u32 get_sfc_enc_key(void); + + + + + + + + + +#endif + + diff --git a/include_lib/driver/cpu/br28/asm/csfr.h b/include_lib/driver/cpu/br28/asm/csfr.h new file mode 100644 index 0000000..94df897 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/csfr.h @@ -0,0 +1,406 @@ +//*********************************************************************************// +// Module name : csfr.h // +// Description : q32DSP core sfr define // +// By Designer : zequan_liu // +// Dat changed : // +//*********************************************************************************// + +#ifndef __Q32DSP_CSFR__ +#define __Q32DSP_CSFR__ + +#define __RW volatile // read write +#define __RO volatile const // only read +#define __WO volatile // only write + +#define __u8 unsigned int // u8 to u32 special for struct +#define __u16 unsigned int // u16 to u32 special for struct +#define __u32 unsigned int + +#define csfr_base 0xff0000 + +//********************************************************************************* +// +// hcore_sfr +// +//********************************************************************************* + +//............. 0x0000 - 0x00ff............ +typedef struct { + __RW __u32 CON0; + __RW __u32 CON1; + __RW __u32 CON2; +} JL_CMNG_TypeDef; + +#define JL_CMNG_BASE (csfr_base + map_adr(0x00, 0x00)) +#define JL_CMNG ((JL_CMNG_TypeDef *)JL_CMNG_BASE) + +//............. 0x0100 - 0x01ff............ +typedef struct { + __RW __u32 CON; + __RW __u32 KEY; +} JL_SDTAP_TypeDef; + +#define JL_SDTAP_BASE (csfr_base + map_adr(0x01, 0x00)) +#define JL_SDTAP ((JL_SDTAP_TypeDef *)JL_SDTAP_BASE) + +//............. 0x0200 - 0x02ff............ +typedef struct { + __RW __u32 WREN; + __RW __u32 CON0; + __RW __u32 CON1; + __RW __u32 CON2; + __RW __u32 CON3; + __RW __u32 MSG0; + __RW __u32 MSG1; + __RW __u32 MSG2; + __RW __u32 MSG3; + __RO __u32 ID; +} JL_CEMU_TypeDef; + +#define JL_CEMU_BASE (csfr_base + map_adr(0x02, 0x00)) +#define JL_CEMU ((JL_CEMU_TypeDef *)JL_CEMU_BASE) + +//............. 0x0300 - 0x03ff............ +#define MPU_INV (1<<31) +#define MPU_PWEN (1<<16) +#define MPU_PREN (1<<8) +#define MPU_PEN (MPU_PWEN | MPU_PREN) +#define MPU_XEN (1<<2) +#define MPU_WEN (1<<1) +#define MPU_REN (1<<0) + +#define MPU_IDx_cfg(n, id) (id<<(n*8)) +#define MPU_IDx_pen(n, pr, pw) ((pr<<(9+n)) | (pw<<(17+n))) + +typedef struct { + __RW __u32 CON[15]; // 0-7 used in br28 + __RO __u32 REV0; + __RW __u32 CID[15]; // 0-7 used in br28 + __RO __u32 REV1; + __RW __u32 BEG[15]; // 0-7 used in br28 + __RO __u32 REV2; + __RW __u32 END[15]; // 0-7 used in br28 + __RW __u32 WREN; +} JL_MPU_TypeDef; + +#define JL_MPU_BASE (csfr_base + map_adr(0x03, 0x00)) +#define JL_MPU ((JL_MPU_TypeDef *)JL_MPU_BASE) + +//............. 0x0400 - 0x04ff............ +typedef struct { + __RW __u32 CON; + __RW __u32 TLB1_BEG; + __RW __u32 TLB1_END; +} JL_MMU_TypeDef; + +#define JL_MMU_BASE (csfr_base + map_adr(0x04, 0x00)) +#define JL_MMU ((JL_MMU_TypeDef *)JL_MMU_BASE) + +typedef struct { + short page: 15; + short vld: 1; +} JL_MMU_TLB1_TypeDef; + +#define JL_MMU_TLB1 ((JL_MMU_TLB1_TypeDef *)(JL_MMU->TLB1_BEG)) + +//............. 0x0500 - 0x05ff............ +//#define JL_TypeDef_L1P JL_TypeDef_q32DSP_ICU +#define JL_TypeDef_L1P JL_TypeDef_q32DSP_DCU +#define JL_L1P_BASE (csfr_base + map_adr(0x05, 0x00)) +#define JL_L1P ((JL_TypeDef_L1P *)JL_L1P_BASE) + +//............. 0x0600 - 0x06ff............ +#define JL_TypeDef_L2I JL_TypeDef_q32DSP_ICU +#define JL_L2I_BASE (csfr_base + map_adr(0x06, 0x00)) +#define JL_L2I ((JL_TypeDef_L2I *)JL_L2I_BASE) + +//............. 0x0700 - 0x07ff............ +#define JL_TypeDef_L2D JL_TypeDef_q32DSP_DCU +#define JL_L2D_BASE (csfr_base + map_adr(0x07, 0x00)) +#define JL_L2D ((JL_TypeDef_L2D *)JL_L2D_BASE) + +//............. 0x0800 - 0x08ff............ +typedef struct { + __RW __u32 CON; + __RW __u32 SEL; + __RW __u32 DP; + __RW __u32 DAT_VLD0; + __RW __u32 DAT_VLD1; + __RW __u32 DAT_VLD2; + __RW __u32 DAT_VLD3; + __RW __u32 ROM_CRC; +} JL_MBIST_TypeDef; + +#define JL_MBIST_BASE (csfr_base + map_adr(0x08, 0x00)) +#define JL_MBIST ((JL_MBIST_TypeDef *)JL_MBIST_BASE) + +//............. 0x0900 - 0x09ff............ +typedef struct { + __RW __u32 CON; + __RW __u32 CADR; + __RW __u32 ACC0L; + __RW __u32 ACC0H; + __RW __u32 ACC1L; + __RW __u32 ACC1H; + __RW __u32 CONST; + __RW __u32 TEST1; +} JL_FFT_TypeDef; + +#define JL_FFT_BASE (csfr_base + map_adr(0x09, 0x00)) +#define JL_FFT ((JL_FFT_TypeDef *)JL_FFT_BASE) + + +//********************************************************************************* +// +// q32DSP_sfr +// +//********************************************************************************* + +//---------------------------------------------// +// q32DSP define +//---------------------------------------------// + +#define q32DSP_sfr_offset 0x000800 +#define q32DSP_sfr_base (csfr_base + 0xe000) + +#define q32DSP_cpu_base (q32DSP_sfr_base + 0x0000) +#define q32DSP_icu_base (q32DSP_sfr_base + 0x0400) +#define q32DSP_dcu_base (q32DSP_sfr_base + 0x0500) + +#define q32DSP(n) ((JL_TypeDef_q32DSP *)(q32DSP_sfr_base + q32DSP_sfr_offset*n)) +#define q32DSP_icu(n) ((JL_TypeDef_q32DSP_ICU *)(q32DSP_icu_base + q32DSP_sfr_offset*n)) +#define q32DSP_dcu(n) ((JL_TypeDef_q32DSP_DCU *)(q32DSP_dcu_base + q32DSP_sfr_offset*n)) + +//---------------------------------------------// +// q32DSP core sfr +//---------------------------------------------// + +typedef struct { + /* 00 */ __RO __u32 DR00; + /* 01 */ __RO __u32 DR01; + /* 02 */ __RO __u32 DR02; + /* 03 */ __RO __u32 DR03; + /* 04 */ __RO __u32 DR04; + /* 05 */ __RO __u32 DR05; + /* 06 */ __RO __u32 DR06; + /* 07 */ __RO __u32 DR07; + /* 08 */ __RO __u32 DR08; + /* 09 */ __RO __u32 DR09; + /* 0a */ __RO __u32 DR10; + /* 0b */ __RO __u32 DR11; + /* 0c */ __RO __u32 DR12; + /* 0d */ __RO __u32 DR13; + /* 0e */ __RO __u32 DR14; + /* 0f */ __RO __u32 DR15; + + /* 10 */ __RO __u32 RETI; + /* 11 */ __RO __u32 RETE; + /* 12 */ __RO __u32 RETX; + /* 13 */ __RO __u32 RETS; + /* 14 */ __RO __u32 SR04; + /* 15 */ __RO __u32 PSR; + /* 16 */ __RO __u32 CNUM; + /* 17 */ __RO __u32 SR07; + /* 18 */ __RO __u32 SR08; + /* 19 */ __RO __u32 SR09; + /* 1a */ __RO __u32 SR10; + /* 1b */ __RO __u32 ICFG; + /* 1c */ __RO __u32 USP; + /* 1d */ __RO __u32 SSP; + /* 1e */ __RO __u32 SP; + /* 1f */ __RO __u32 PCRS; + + /* 20 */ __RW __u32 BPCON; + /* 21 */ __RW __u32 BSP; + /* 22 */ __RW __u32 BP0; + /* 23 */ __RW __u32 BP1; + /* 24 */ __RW __u32 BP2; + /* 25 */ __RW __u32 BP3; + /* 26 */ __WO __u32 CMD_PAUSE; + /* 27 */ __RW __u32 BP4; + /* 28 */ __RW __u32 BP5; + /* 29 */ __RW __u32 BP6; + /* 2a */ __RW __u32 BP7; + /* */ __RO __u32 REV2a[0x30 - 0x2a - 1]; + + /* 30 */ __RW __u32 PMU_CON0; + /* 31 */ __RW __u32 PMU_CON1; + /* */ __RO __u32 REV30[0x3b - 0x31 - 1]; + /* 3b */ __RW __u8 TTMR_CON; + /* 3c */ __RW __u32 TTMR_CNT; + /* 3d */ __RW __u32 TTMR_PRD; + /* 3e */ __RW __u32 BANK_CON; + /* 3f */ __RW __u32 BANK_NUM; + + /* 40 */ __RW __u32 ICFG00; + /* 41 */ __RW __u32 ICFG01; + /* 42 */ __RW __u32 ICFG02; + /* 43 */ __RW __u32 ICFG03; + /* 44 */ __RW __u32 ICFG04; + /* 45 */ __RW __u32 ICFG05; + /* 46 */ __RW __u32 ICFG06; + /* 47 */ __RW __u32 ICFG07; + /* 48 */ __RW __u32 ICFG08; + /* 49 */ __RW __u32 ICFG09; + /* 4a */ __RW __u32 ICFG10; + /* 4b */ __RW __u32 ICFG11; + /* 4c */ __RW __u32 ICFG12; + /* 4d */ __RW __u32 ICFG13; + /* 4e */ __RW __u32 ICFG14; + /* 4f */ __RW __u32 ICFG15; + + /* 50 */ __RW __u32 ICFG16; + /* 51 */ __RW __u32 ICFG17; + /* 52 */ __RW __u32 ICFG18; + /* 53 */ __RW __u32 ICFG19; + /* 54 */ __RW __u32 ICFG20; + /* 55 */ __RW __u32 ICFG21; + /* 56 */ __RW __u32 ICFG22; + /* 57 */ __RW __u32 ICFG23; + /* 58 */ __RW __u32 ICFG24; + /* 59 */ __RW __u32 ICFG25; + /* 5a */ __RW __u32 ICFG26; + /* 5b */ __RW __u32 ICFG27; + /* 5c */ __RW __u32 ICFG28; + /* 5d */ __RW __u32 ICFG29; + /* 5e */ __RW __u32 ICFG30; + /* 5f */ __RW __u32 ICFG31; + + /* 60 */ __RO __u32 IPND0; + /* 61 */ __RO __u32 IPND1; + /* 62 */ __RO __u32 IPND2; + /* 63 */ __RO __u32 IPND3; + /* 64 */ __RO __u32 IPND4; + /* 65 */ __RO __u32 IPND5; + /* 66 */ __RO __u32 IPND6; + /* 67 */ __RO __u32 IPND7; + /* 68 */ __WO __u32 ILAT_SET; + /* 69 */ __WO __u32 ILAT_CLR; + /* 6a */ __RW __u32 IPMASK; + /* 6b */ __RW __u32 GIEMASK; + /* 6c */ __RW __u32 IWKUP_NUM; + /* */ __RO __u32 REV6a[0x70 - 0x6c - 1]; + + /* 70 */ __RW __u32 ETM_CON; + /* 71 */ __RO __u32 ETM_PC0; + /* 72 */ __RO __u32 ETM_PC1; + /* 73 */ __RO __u32 ETM_PC2; + /* 74 */ __RO __u32 ETM_PC3; + /* 75 */ __RW __u32 WP0_ADRH; + /* 76 */ __RW __u32 WP0_ADRL; + /* 77 */ __RW __u32 WP0_DATH; + /* 78 */ __RW __u32 WP0_DATL; + /* 79 */ __RW __u32 WP0_PC; + /* */ __RO __u32 REV79[0x80 - 0x79 - 1]; + + /* 80 */ __RW __u32 EMU_CON; + /* 81 */ __RW __u32 EMU_MSG; + /* 82 */ __RW __u32 EMU_SSP_H; + /* 83 */ __RW __u32 EMU_SSP_L; + /* 84 */ __RW __u32 EMU_USP_H; + /* 85 */ __RW __u32 EMU_USP_L; + /* 86 */ __RW __u32 LIM_PC0_H; + /* 87 */ __RW __u32 LIM_PC0_L; + /* 88 */ __RW __u32 LIM_PC1_H; + /* 89 */ __RW __u32 LIM_PC1_L; + /* 8a */ __RW __u32 LIM_PC2_H; + /* 8b */ __RW __u32 LIM_PC2_L; + /* */ __RO __u32 REV8b[0x90 - 0x8b - 1]; + + /* 90 */ __RW __u32 ESU_CON; + /* 91 */ __RO __u32 CNT_CHIT; + /* 92 */ __RO __u32 CNT_CMIS; + /* 93 */ __RO __u32 CNT_FILL; + /* 94 */ __RO __u32 CNT_IHIT; + /* 95 */ __RO __u32 CNT_IMIS; + /* 96 */ __RO __u32 CNT_RHIT; + /* 97 */ __RO __u32 CNT_RMIS; + /* 98 */ __RO __u32 CNT_WHIT; + /* 99 */ __RO __u32 CNT_WMIS; +} JL_TypeDef_q32DSP; + +//---------------------------------------------// +// q32DSP icache sfr +//---------------------------------------------// + +typedef struct { + __RW __u32 CON; + __RW __u32 EMU_CON; + __RW __u32 EMU_MSG; + __RW __u32 EMU_ID; + __RW __u32 CMD_CON; + __RW __u32 CMD_BEG; + __RW __u32 CMD_END; + __RW __u32 CNT_RACK; + __RW __u32 CNT_RNAK; + __RW __u32 MBIST_CON; +} JL_TypeDef_q32DSP_ICU; + +//---------------------------------------------// +// q32DSP dcache sfr +//---------------------------------------------// + +typedef struct { + __RW __u32 CON; + __RW __u32 EMU_CON; + __RW __u32 EMU_MSG; + __RW __u32 EMU_ID; + __RW __u32 CNT_WACK; + __RW __u32 CNT_WNAK; + __RW __u32 CNT_RACK; + __RW __u32 CNT_RNAK; + __RW __u32 MBIST_CON; + __RO __u32 REV0[0x10 - 0x8 - 1]; + __RW __u32 CMD_CON[4]; + __RW __u32 CMD_BEG[4]; + __RW __u32 CMD_END[4]; + __RO __u32 REV1[0x20 - 0x1b - 1]; + __WO __u32 CMO[32]; +} JL_TypeDef_q32DSP_DCU; + +typedef struct _CPU_REGS { + unsigned int reti; + unsigned int rets; + unsigned int psr; + unsigned int r0; + unsigned int r1; + unsigned int r2; + unsigned int r3; + unsigned int r4; + unsigned int r5; + unsigned int r6; + unsigned int r7; + unsigned int r8; + unsigned int r9; + unsigned int r10; + unsigned int r11; + unsigned int r12; + unsigned int r13; + unsigned int r14; + unsigned int r15; +} CPU_REGS; + + +#define TICK_CON (q32DSP(0)->TTMR_CON) +#define TICK_PRD (q32DSP(0)->TTMR_PRD) +#define TICK_CNT (q32DSP(0)->TTMR_CNT) + +#define SOFT_CLEAR_PENDING (q32DSP(0)->ILAT_CLR) + +#define CPU_MSG (q32DSP(0)->EMU_MSG) +#define CPU_CON (q32DSP(0)->EMU_CON) + +#undef __RW +#undef __RO +#undef __WO + +#undef __u8 +#undef __u16 +#undef __u32 + +//*********************************************************************************// +// // +// end of this module // +// // +//*********************************************************************************// +#endif diff --git a/include_lib/driver/cpu/br28/asm/ctmu.h b/include_lib/driver/cpu/br28/asm/ctmu.h new file mode 100644 index 0000000..c884d06 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/ctmu.h @@ -0,0 +1,45 @@ +#ifndef _CTMU_DRV_H_ +#define _CTMU_DRV_H_ + +#include "typedef.h" + +#define CTMU_KEY_CH_MAX 3 + +typedef struct _CTMU_KEY_VAR { + s32 touch_release_buf[CTMU_KEY_CH_MAX]; //按键释放值滤波器buffer + u16 touch_cnt_buf[CTMU_KEY_CH_MAX]; //按键计数值滤波器buffer + s16 FLT1CFG1; //滤波器1配置参数1 + s16 FLT1CFG2; //滤波器1配置参数2, 等于(-RELEASECFG0)<DIR &= ~BIT(x), JL_PORT##i->OUT &= ~BIT(x);} +#define IO_DEBUG_1(i,x) {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT |= BIT(x);} +#define IO_DEBUG_TOGGLE(i,x) {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT ^= BIT(x);} + + +#else +#define IO_DEBUG_0(i,x) {} +#define IO_DEBUG_1(i,x) {} +#define IO_DEBUG_TOGGLE(i,x) {} + +#endif +/** + * @brief usb_iomode + * + * @param enable 1,使能;0,关闭 + */ +void usb_iomode(u32 enable); +/** + * @brief gpio_direction_input + * + * @param gpio 参考宏IO_PORTx_xx,如IO_PORTA_00 + * @param dir 1,输入;0,输出 + * + * @return + */ +int gpio_set_direction(u32 gpio, u32 dir); + + +/** + * @brief gpio_direction_input + * + * @param gpio 参考宏IO_PORTx_xx,如IO_PORTA_00 + * @param value 1,输出1, 0,输出0 + * + * @return + */ +int gpio_set_output_value(u32 gpio, u32 dir); + +/** + * @brief gpio_dir + * + * @param gpio [GPIOA GPIOB GPIOC GPIOD GPIOR GPIOUSB] + * @param start [0-15],GPIOR[0-3],GPIOUSB[0-1] + * @param len [0-15],GPIOR[0-3],GPIOUSB[0-1] + * @param dat 1,输入;0,输出 + * + * @return + */ +u32 gpio_dir(u32 gpio, u32 start, u32 len, u32 dat, enum gpio_op_mode op); + +/** + * @brief gpio_direction_output + * + * @param gpio 参考宏IO_PORTx_xx,如IO_PORTA_00 + * @param value 1,输出1;0,输出0 + * + * @return + */ +int gpio_direction_output(u32 gpio, int value); + +/** + * @brief gpio_out + * + * @param gpio [GPIOA GPIOB GPIOC GPIOD GPIOR GPIOUSB] + * @param start [0-15],GPIOR[0-3],GPIOUSB[0-1] + * @param len [0-15],GPIOR[0-3],GPIOUSB[0-1] + * @param dat 1,输入;0,输出 + * + * @return + */ +u32 gpio_out(u32 gpio, u32 start, u32 len, u32 dat); + +/** + * @brief gpio_set_pull_up + * + * @param gpio 参考宏IO_PORTx_xx,如IO_PORTA_00 + * @param value 1,上拉;0,不上拉 + * + * @return + */ +int gpio_set_pull_up(u32 gpio, int value); + + +/** + * @brief gpio_set_pu + * + * @param gpio [GPIOA GPIOB GPIOC GPIOD GPIOR GPIOUSB] + * @param start [0-15],GPIOR[0-3],GPIOUSB[0-1] + * @param len [0-15],GPIOR[0-3],GPIOUSB[0-1] + * @param dat 1,上拉;0,不上拉 + * + * @return + */ +u32 gpio_set_pu(u32 gpio, u32 start, u32 len, u32 dat, enum gpio_op_mode op); + +/** + * @brief gpio_set_pull_down + * + * @param gpio 参考宏IO_PORTx_xx,如IO_PORTA_00 + * @param value 1,下拉;0,不下拉 + * + * @return + */ +int gpio_set_pull_down(u32 gpio, int value); + +/** + * @brief gpio_set_pd + * + * @param gpio [GPIOA GPIOB GPIOC GPIOD GPIOR GPIOUSB] + * @param start [0-15],GPIOR[0-3],GPIOUSB[0-1] + * @param len [0-15],GPIOR[0-3],GPIOUSB[0-1] + * @param dat 1,下拉;0,不下拉 + * + * @return + */ +u32 gpio_set_pd(u32 gpio, u32 start, u32 len, u32 dat, enum gpio_op_mode op); + +/** + * @brief gpio_set_hd0 + * + * @param gpio 参考宏IO_PORTx_xx,如IO_PORTA_00 + * @param value 1,增强输出;0,不增强输出 + * + * @return + */ +u32 gpio_set_hd0(u32 gpio, u32 value); + +/** + * @brief gpio_set_hd + * + * @param gpio 参考宏IO_PORTx_xx,如IO_PORTA_00 + * @param value 1,增强输出;0,不增强输出 + * + * @return + */ +int gpio_set_hd(u32 gpio, int value); + +/** + * @brief gpio_set_die + * + * @param gpio 参考宏IO_PORTx_xx,如IO_PORTA_00 + * @param value 1,IO普通输入;0,IO模拟输入 + * + * @return + */ +int gpio_set_die(u32 gpio, int value); + +/** + * @brief gpio_set_dieh + * + * @param gpio 参考宏IO_PORTx_xx,如IO_PORTA_00 + * @param value 1,IO普通输入;0,IO模拟输入 + * + * @return + */ +u32 gpio_set_dieh(u32 gpio, u32 value); + +/** + * @brief gpio_die + * + * @param gpio [GPIOA GPIOB GPIOC GPIOD GPIOR GPIOUSB] + * @param start [0-15],GPIOR[0-3],GPIOUSB[0-1] + * @param len [0-15],GPIOR[0-3],GPIOUSB[0-1] + * @param dat 1,IO普通输入;0,IO模拟输入 + * + * @return + */ +u32 gpio_die(u32 gpio, u32 start, u32 len, u32 dat, enum gpio_op_mode op); + +/** + * @brief gpio_dieh + * + * @param gpio [GPIOA GPIOB GPIOC GPIOD GPIOR GPIOUSB] + * @param start [0-15],GPIOR[0-3],GPIOUSB[0-1] + * @param len [0-15],GPIOR[0-3],GPIOUSB[0-1] + * @param dat 1,IO普通输入;0,IO模拟输入 + * + * @return + */ +u32 gpio_dieh(u32 gpio, u32 start, u32 len, u32 dat, enum gpio_op_mode op); + +/** + * @brief gpio_set_output_channle + * + * @param gpio 参考宏IO_PORTx_xx,如IO_PORTA_00 + * @param clk 参考枚举CHx_UTx_TX,如CH0_UT0_TX + * + * @return + */ +u32 gpio_output_channle(u32 gpio, u32 clk); + +/** + * @brief gpio_read + * + * @param gpio 参考宏IO_PORTx_xx,如IO_PORTA_00 + * + * @return + */ +int gpio_read(u32 gpio); + +/** + * @brief gpio_in + * + * @param gpio [GPIOA GPIOB GPIOC GPIOD GPIOR GPIOUSB] + * + * @return + */ +u32 gpio_in(u32 gpio); +/** + * @brief gpio_write + * + * @param gpio 参考宏IO_PORTx_xx,如IO_PORTA_00 + * @param value 1,输出1;0,输出0 + * + * @return + */ +u32 gpio_write(u32 gpio, u32 value); + +/** + * @brief gpio_wakeup0 use IN_CHNL0_SEL + * + * @param gpio 参考宏IO_PORTx_xx,如IO_PORTA_00 + * + * @return + */ +u32 gpio_wakeup0(u32 gpio); + +/** + * @brief gpio_irflt_in use IN_CHNL1_SEL + * + * @param gpio 参考宏IO_PORTx_xx,如IO_PORTA_00 + * + * @return + */ +u32 gpio_irflt_in(u32 gpio); + +/** + * @brief gpio_cap_mux use IN_CHNL2_SEL + * + * @param gpio 参考宏IO_PORTx_xx,如IO_PORTA_00 + * + * @return + */ +u32 gpio_cap_mux(u32 gpio); + + +/** + * @brief gpio_uart_rx_input + * + * @param gpio + * @param ut + * @param ch + * + * @return + */ +u32 gpio_uart_rx_input(u32 gpio, u32 ut, u32 ch); + +/** + * @brief + * + * @return + */ +u32 gpio_close_uart0(void); + +/** + * @brief + * + * @return + */ +u32 gpio_close_uart1(void); + +/** + * @brief + * + * @return + */ +u32 gpio_close_uart2(void); + +/** + * @brief gpio_set_uart0 + * + * @param ch 0:3 选择对应IO br22 + * |ch|tx|rx| + * |- |- |- | + * |0|PA5_TX|PA6_RX| + * |1|PB7_TX|PB8_RX| + * |2|PA7_TX|PA8_RX| + * |3|预留|预留| + * |-1|关闭对应的IO口串口功能|no| + * + * @return + */ +u32 gpio_set_uart0(u32 ch); +/** + * @brief gpio_set_uart1 + * + * @param ch 0:3 选择对应IO br22 + * |ch|tx|rx| + * |- |- |- | + * |0|PB5_TX|PB6_RX| + * |1|预留|预留| + * |2|PA1_TX|PA2_RX| + * |3|USBDP |USBDM | + * |-1|关闭对应的IO口串口功能|no| + * + * @return + */ +u32 gpio_set_uart1(u32 ch); +/** + * @brief gpio_set_uart2 + * + * @param ch 0:3 选择对应IO br22 + * |ch|tx|rx| + * |- |- |- | + * |0|PA3_TX|PA4_RX| + * |1|预留|预留| + * |2|预留|预留| + * |3|PA9_TX|PA10_RX| + * |-1|关闭对应的IO口串口功能|no| + * + * @return + */ +u32 gpio_set_uart2(u32 ch); + +enum { + IRFLT_LSB, + IRFLT_RC, + IRFLT_OSC, + IRFLT_PLL48M, +}; +enum { + IRFLT_DIV1, + IRFLT_DIV2, + IRFLT_DIV4, + IRFLT_DIV8, + IRFLT_DIV16, + IRFLT_DIV32, + IRFLT_DIV64, + IRFLT_DIV128, + IRFLT_DIV256, + IRFLT_DIV512, + IRFLT_DIV1024, + IRFLT_DIV2048, + IRFLT_DIV4096, + IRFLT_DIV8192, + IRFLT_DIV16384, + IRFLT_DIV32768, +}; +/* u32 irflt_config(u32 osc, u32 div); */ + +/** + * @brief gpio_irflt_to_timer + * + * @param t: [0-3] + * + * @return + */ +u32 gpio_irflt_to_timer(u32 t); + + +u32 get_gpio(const char *p); + + +//===================================================// +// BR30 Crossbar API +//===================================================// +enum PFI_TABLE { + PFI_GP_ICH0 = ((u32)(&(JL_IMAP->FI_GP_ICH0))), + PFI_GP_ICH1 = ((u32)(&(JL_IMAP->FI_GP_ICH1))), + PFI_GP_ICH2 = ((u32)(&(JL_IMAP->FI_GP_ICH2))), + PFI_GP_ICH3 = ((u32)(&(JL_IMAP->FI_GP_ICH3))), + PFI_GP_ICH4 = ((u32)(&(JL_IMAP->FI_GP_ICH4))), + PFI_GP_ICH5 = ((u32)(&(JL_IMAP->FI_GP_ICH5))), + PFI_GP_ICH6 = ((u32)(&(JL_IMAP->FI_GP_ICH6))), + PFI_GP_ICH7 = ((u32)(&(JL_IMAP->FI_GP_ICH7))), + PFI_GP_ICH8 = ((u32)(&(JL_IMAP->FI_GP_ICH8))), + PFI_GP_ICH9 = ((u32)(&(JL_IMAP->FI_GP_ICH9))), + PFI_GP_ICH10 = ((u32)(&(JL_IMAP->FI_GP_ICH10))), + PFI_GP_ICH11 = ((u32)(&(JL_IMAP->FI_GP_ICH11))), + PFI_GP_ICH12 = ((u32)(&(JL_IMAP->FI_GP_ICH12))), + PFI_GP_ICH13 = ((u32)(&(JL_IMAP->FI_GP_ICH13))), + PFI_SPI0_CLK = ((u32)(&(JL_IMAP->FI_SPI0_CLK))), + PFI_SPI0_DA0 = ((u32)(&(JL_IMAP->FI_SPI0_DA0))), + PFI_SPI0_DA1 = ((u32)(&(JL_IMAP->FI_SPI0_DA1))), + PFI_SPI0_DA2 = ((u32)(&(JL_IMAP->FI_SPI0_DA2))), + PFI_SPI0_DA3 = ((u32)(&(JL_IMAP->FI_SPI0_DA3))), + PFI_SPI1_CLK = ((u32)(&(JL_IMAP->FI_SPI1_CLK))), + PFI_SPI1_DA0 = ((u32)(&(JL_IMAP->FI_SPI1_DA0))), + PFI_SPI1_DA1 = ((u32)(&(JL_IMAP->FI_SPI1_DA1))), + PFI_SPI1_DA2 = ((u32)(&(JL_IMAP->FI_SPI1_DA2))), + PFI_SPI1_DA3 = ((u32)(&(JL_IMAP->FI_SPI1_DA3))), + PFI_SPI2_CLK = ((u32)(&(JL_IMAP->FI_SPI2_CLK))), + PFI_SPI2_DA0 = ((u32)(&(JL_IMAP->FI_SPI2_DA0))), + PFI_SPI2_DA1 = ((u32)(&(JL_IMAP->FI_SPI2_DA1))), + PFI_SPI2_DA2 = ((u32)(&(JL_IMAP->FI_SPI2_DA2))), + PFI_SPI2_DA3 = ((u32)(&(JL_IMAP->FI_SPI2_DA3))), + PFI_SD0_CMD = ((u32)(&(JL_IMAP->FI_SD0_CMD))), + PFI_SD0_DA0 = ((u32)(&(JL_IMAP->FI_SD0_DA0))), + PFI_SD0_DA1 = ((u32)(&(JL_IMAP->FI_SD0_DA1))), + PFI_SD0_DA2 = ((u32)(&(JL_IMAP->FI_SD0_DA2))), + PFI_SD0_DA3 = ((u32)(&(JL_IMAP->FI_SD0_DA3))), + PFI_IIC_SCL = ((u32)(&(JL_IMAP->FI_IIC_SCL))), + PFI_IIC_SDA = ((u32)(&(JL_IMAP->FI_IIC_SDA))), + PFI_UART0_RX = ((u32)(&(JL_IMAP->FI_UART0_RX))), + PFI_UART1_RX = ((u32)(&(JL_IMAP->FI_UART1_RX))), + PFI_UART1_CTS = ((u32)(&(JL_IMAP->FI_UART1_CTS))), + PFI_UART2_RX = ((u32)(&(JL_IMAP->FI_UART2_RX))), + PFI_TDM_S_WCK = ((u32)(&(JL_IMAP->FI_TDM_S_WCK))), + PFI_TDM_S_BCK = ((u32)(&(JL_IMAP->FI_TDM_S_BCK))), + PFI_TDM_M_DA = ((u32)(&(JL_IMAP->FI_TDM_M_DA))), + PFI_RDEC0_DAT0 = ((u32)(&(JL_IMAP->FI_RDEC0_DAT0))), + PFI_RDEC0_DAT1 = ((u32)(&(JL_IMAP->FI_RDEC0_DAT1))), + PFI_RDEC1_DAT0 = ((u32)(&(JL_IMAP->FI_RDEC1_DAT0))), + PFI_RDEC1_DAT1 = ((u32)(&(JL_IMAP->FI_RDEC1_DAT1))), + PFI_RDEC2_DAT0 = ((u32)(&(JL_IMAP->FI_RDEC2_DAT0))), + PFI_RDEC2_DAT1 = ((u32)(&(JL_IMAP->FI_RDEC2_DAT1))), + PFI_ALNK0_MCLK = ((u32)(&(JL_IMAP->FI_ALNK0_MCLK))), + PFI_ALNK0_LRCK = ((u32)(&(JL_IMAP->FI_ALNK0_LRCK))), + PFI_ALNK0_SCLK = ((u32)(&(JL_IMAP->FI_ALNK0_SCLK))), + PFI_ALNK0_DAT0 = ((u32)(&(JL_IMAP->FI_ALNK0_DAT0))), + PFI_ALNK0_DAT1 = ((u32)(&(JL_IMAP->FI_ALNK0_DAT1))), + PFI_ALNK0_DAT2 = ((u32)(&(JL_IMAP->FI_ALNK0_DAT2))), + PFI_ALNK0_DAT3 = ((u32)(&(JL_IMAP->FI_ALNK0_DAT3))), + PFI_PLNK_DAT0 = ((u32)(&(JL_IMAP->FI_PLNK_DAT0))), + PFI_PLNK_DAT1 = ((u32)(&(JL_IMAP->FI_PLNK_DAT1))), + PFI_CHAIN_IN0 = ((u32)(&(JL_IMAP->FI_CHAIN_IN0))), + PFI_CHAIN_IN1 = ((u32)(&(JL_IMAP->FI_CHAIN_IN1))), + PFI_CHAIN_IN2 = ((u32)(&(JL_IMAP->FI_CHAIN_IN2))), + PFI_CHAIN_IN3 = ((u32)(&(JL_IMAP->FI_CHAIN_IN3))), + PFI_CHAIN_RST = ((u32)(&(JL_IMAP->FI_CHAIN_RST))), + PFI_TOTAl = ((u32)(&(JL_IMAP->FI_TOTAL))), +}; + +enum OUTPUT_CH_SIGNAL { + OUTPUT_CH_SIGNAL_MC_PWM0_H = 0, + OUTPUT_CH_SIGNAL_MC_PWM0_L, + OUTPUT_CH_SIGNAL_MC_PWM1_H, + OUTPUT_CH_SIGNAL_MC_PWM1_L, + OUTPUT_CH_SIGNAL_MC_PWM2_H, + OUTPUT_CH_SIGNAL_MC_PWM2_L, + OUTPUT_CH_SIGNAL_MC_PWM3_H, + OUTPUT_CH_SIGNAL_MC_PWM3_L, + OUTPUT_CH_SIGNAL_TIMER0_PWM, + OUTPUT_CH_SIGNAL_TIMER1_PWM, + OUTPUT_CH_SIGNAL_TIMER2_PWM, + OUTPUT_CH_SIGNAL_TIMER3_PWM, + OUTPUT_CH_SIGNAL_TIMER4_PWM, + OUTPUT_CH_SIGNAL_TIMER5_PWM, + OUTPUT_CH_SIGNAL_CLOCK_OUT0, + OUTPUT_CH_SIGNAL_CLOCK_OUT1, + OUTPUT_CH_SIGNAL_CLOCK_OUT2, + OUTPUT_CH_SIGNAL_CLOCK_OUT3, +}; + +enum INPUT_CH_TYPE { + INPUT_CH_TYPE_GP_ICH = 0, + INPUT_CH_TYPE_TIME0_PWM = 14, + INPUT_CH_TYPE_TIME1_PWM, +}; + +enum INPUT_CH_SIGNAL { + //ICH_CON0 + INPUT_CH_SIGNAL_TIMER0_CIN = 0, + INPUT_CH_SIGNAL_TIMER0_CAPTURE, + INPUT_CH_SIGNAL_TIMER1_CIN, + INPUT_CH_SIGNAL_TIMER1_CAPTURE, + INPUT_CH_SIGNAL_TIMER2_CIN, + INPUT_CH_SIGNAL_TIMER2_CAPTURE, + INPUT_CH_SIGNAL_TIMER3_CIN, + INPUT_CH_SIGNAL_TIMER3_CAPTURE, + + //ICH_CON1 + INPUT_CH_SIGNAL_TIMER4_CIN, + INPUT_CH_SIGNAL_TIMER4_CAPTURE, + INPUT_CH_SIGNAL_TIMER5_CIN, + INPUT_CH_SIGNAL_TIMER5_CAPTURE, + INPUT_CH_SIGNAL_WAKEUP, + INPUT_CH_SIGNAL_IRFLT, + INPUT_CH_SIGNAL_CAP, + INPUT_CH_SIGNAL_CLK_PIN, + + //ICH_CON2 + INPUT_CH_SIGNAL_WLC_EXT_ACT, + INPUT_CH_SIGNAL_LCD_TE, + INPUT_CH_SIGNAL_MC_CKPIN0, + INPUT_CH_SIGNAL_MC_CKPIN1, + INPUT_CH_SIGNAL_MC_CKPIN2, + INPUT_CH_SIGNAL_MC_CKPIN3, + INPUT_CH_SIGNAL_MC_FPIN0, + INPUT_CH_SIGNAL_MC_FPIN1, + + //ICH_CON3 + INPUT_CH_SIGNAL_MC_FPIN2, + INPUT_CH_SIGNAL_MC_FPIN3, + INPUT_CH_SIGNAL_RESERVE0, + INPUT_CH_SIGNAL_RESERVE1, + INPUT_CH_SIGNAL_RESERVE2, + INPUT_CH_SIGNAL_RESERVE3, + INPUT_CH_SIGNAL_RESERVE4, + INPUT_CH_SIGNAL_RESERVE5, +}; + + +//=================================================================================// +//@brief: CrossBar 获取某IO的输出映射寄存器 +//@input: +// gpio: 需要输出外设信号的IO口; 如IO_PORTA_00 +//@return: +// 输出映射寄存器地址; 如&(JL_OMAP->PA0_OUT) +//=================================================================================// +u32 *gpio2crossbar_outreg(u32 gpio); + +//=================================================================================// +//@brief: CrossBar 获取某IO的输入映射序号 +//@input: +// gpio: 需要输出外设信号的IO口; 如IO_PORTA_00 +//@return: +// 输出映射序号; 如PA0_IN +//=================================================================================// +u32 gpio2crossbar_inport(u32 gpio); + +//=================================================================================// +//@brief: CrossBar 输出设置 API, 将指定IO口设置为某个外设的输出 +//@input: +// gpio: 需要输出外设信号的IO口; +// fun_index: 需要输出到指定IO口的外设信号, 可以输出外设信号列表请查看io_omap.h文件; +// dir_ctl: IO口方向由外设控制使能, 常设为1; +// data_ctl: IO口电平状态由外设控制使能, 常设为1; +// low_power_mode: 低功耗状态是否保持io功能; +//@return: +// 1)0: 执行正确; +// 2)-EINVAL: 传参出错; +//@note: 所映射的IO需要在设置IO状态为输出配置; +//@example: 将UART0的Tx信号输出到IO_PORTA_05口: +// gpio_direction_output(IO_PORTA_05, 1); //设置IO为输出状态 +// gpio_set_fun_output_port(IO_PORTA_05, FO_UART0_TX, 1, 1); //将UART0的Tx信号输出到IO_PORTA_05口 +//=================================================================================// +int gpio_set_fun_output_port(u32 gpio, u32 fun_index, u8 dir_ctl, u8 data_ctl, u8 low_power_mode); + +u32 gpio_get_ompap_low_power_mode(u32 offset); +//=================================================================================// +//@brief: CrossBar 输出设置 API, 将指定IO释放外设控制, 变为普通IO; +//@input: +// gpio: 需要释放外设控制IO口, 释放后变为普通IO模式; +//@return: +// 1)0: 执行正确; +// 2)-EINVAL: 传参出错; +//@note: +//@example: 将IO_PORTA_05口被某一外设控制状态释放: +// gpio_disable_fun_output_port(IO_PORTA_05); +//=================================================================================// +int gpio_disable_fun_output_port(u32 gpio); + +//=================================================================================// +//@brief: CrossBar 输入设置 API, 将某个外设的输入设置为从某个IO输入 +//@input: +// gpio: 需要输入外设信号的IO口; +// pfun: 需要从指定IO输入的外设信号, 可以输入的外设信号列表请查看gpio.h文件enum PFI_TABLE枚举项; +// low_power_mode: 低功耗状态是否保持io功能; +//@return: +// 1)0: 执行正确; +// 2)-EINVAL: 传参出错; +//@note: 所映射的IO需要在设置IO状态为输入配置; +//@example: 将UART0的Rx信号设置为IO_PORTA_05口输入: +// gpio_set_die(IO_PORTA_05, 1); //数字输入使能 +// gpio_set_pull_up(IO_PORTA_05, 1); //上拉输入使能 +// gpio_direction_input(IO_PORTA_05); //设置IO为输入状态 +// gpio_set_fun_input_port(IO_PORTA_05, PFI_UART0_RX); //将UART0的Rx信号设置为IO_PORTA_05口输入 +//=================================================================================// +int gpio_set_fun_input_port(u32 gpio, enum PFI_TABLE pfun, u32 low_power_mode); +u32 gpio_get_impap_low_power_mode(u32 offset); + +//=================================================================================// +//@brief: CrossBar 输入设置 API, 将某个外设信号释放IO口控制, 变为普通IO; +//@input: +// pfun: 需要释放由某个IO口输入的外设信号, 外设信号列表请查看gpio.h文件enum PFI_TABLE枚举项; +//@return: 默认为0, 无出错处理; +//@note: +//@example: 将外设信号PFI_UART0_RX释放由某个IO输入: +// gpio_disable_fun_input_port(PFI_UART0_RX); +//=================================================================================// +int gpio_disable_fun_input_port(enum PFI_TABLE pfun); + +//=================================================================================// +//@brief: Output Channel输出设置 API, 将指定IO口设置为某个外设的输出 +//@input: +// gpio: 需要输出外设信号的IO口; +// signal: 将enum OUTPUT_CH_SIGNAL列表中需要输出到指定IO口的外设信号, 可以输出的外设信号列表请查看gpio.h文件的enum OUTPUT_CH_SIGNAL枚举项; +//@return: 默认为0, 出错内部触发ASSERT; +//@note: 所映射的IO需要在设置IO状态为输出配置; +//@example: 将OUTPUT_CH_SIGNAL_MC_PWM0_H的Tx信号输出到IO_PORTA_05口: +// gpio_direction_output(IO_PORTA_05, 1); //设置IO为输出状态 +// gpio_och_sel_output_signal(IO_PORTA_05, OUTPUT_CH_SIGNAL_MC_PWM0_H); //将OUTPUT_CH_SIGNAL_MC_PWM0_H信号输出到IO_PORTA_05口 +//=================================================================================// +int gpio_och_sel_output_signal(u32 gpio, enum OUTPUT_CH_SIGNAL signal); + +//=================================================================================// +//@brief: Output Channel 输出设置 API, 将指定IO释放外设控制, 变为普通IO; +//@input: +// gpio: 需要释放外设控制IO口, 释放后变为普通IO模式; +// signal: 将enum OUTPUT_CH_SIGNAL列表中需要取消输出的外设信号, 外设信号列表请查看gpio.h文件的enum OUTPUT_CH_SIGNAL枚举项;; +//@return: 默认为0, 无出错处理; +//@note: +//@example: 将OUTPUT_CH_SIGNAL_MC_PWM0_H取消输出IO_PORTA_05: +// gpio_och_disable_output_signal(IO_PORTA_05, OUTPUT_CH_SIGNAL_MC_PWM0_H); +//=================================================================================// +int gpio_och_disable_output_signal(u32 gpio, enum OUTPUT_CH_SIGNAL signal); + +//=================================================================================// +//@brief: Input Channel 输入设置 API, 将某个外设的输入设置为从某个IO输入 +//@input: +// gpio: 需要输入外设信号的IO口; +// signal: 需要从指定IO输入的外设信号, 可以输入的外设信号列表请查看gpio.h文件enum INPUT_CH_SIGNAL枚举项; +// type: INPUT_CH 类型, 常设为INPUT_CH_TYPE_GP_ICH; +//@return: 默认为0, 出错内部触发ASSERT; +//@note: 所映射的IO需要在设置IO状态为输入配置; +//@example: 将INPUT_CH_SIGNAL_TIMER0_CIN信号设置为IO_PORTA_05口输入: +// gpio_set_die(IO_PORTA_05, 1); //数字输入使能 +// gpio_set_pull_up(IO_PORTA_05, 1); //上拉输入使能 +// gpio_direction_input(IO_PORTA_05); //设置IO为输入状态 +// gpio_ich_sel_iutput_signal(IO_PORTA_05, INPUT_CH_SIGNAL_TIMER0_CIN, INPUT_CH_TYPE_GP_ICH); //将INPUT_CH_SIGNAL_TIMER0_CIN信号设置为IO_PORTA_05口输入 +//=================================================================================// +int gpio_ich_sel_iutput_signal(u32 gpio, enum INPUT_CH_SIGNAL signal, enum INPUT_CH_TYPE type); + +//=================================================================================// +//@brief: Input Channel 输入设置 API, 将某个外设信号释放IO口控制, 变为普通IO; +//@input: +// gpio: 需要取消输入外设信号的IO口; +// signal: 需要取消输入的外设信号, 外设信号列表请查看gpio.h文件enum INPUT_CH_SIGNAL枚举项; +// type: INPUT_CH 类型, 常设为INPUT_CH_TYPE_GP_ICH; +//@return: 默认为0, 无出错处理; +//@note: +//@example: 将外设信号INPUT_CH_SIGNAL_TIMER0_CIN释放由某个IO输入: +// gpio_ich_disable_iutput_signal(IO_PORTA_05, INPUT_CH_SIGNAL_TIMER0_CIN, INPUT_CH_TYPE_GP_ICH); +//=================================================================================// +int gpio_ich_disable_iutput_signal(u32 gpio, enum INPUT_CH_SIGNAL signal, enum INPUT_CH_TYPE type); + + +/** + * @brief gpio_longpress_pin0_reset_config + * + * @param pin 任意GPIO + * @param level 0(下降沿触发) 1(上升沿触发) + * @param time 0(disable) 1 2 4 8 16单位为秒 + */ +void gpio_longpress_pin0_reset_config(u32 pin, u32 level, u32 time); + + +/** + * @brief gpio_longpress_pin1_reset_config + * + * @param pin IO_LDOIN_DET IO_VBTCH_DET + * @param level 0(下降沿触发) 1(上升沿触发) + * @param time 0(disable) 1 2 4 8 16单位为秒 + */ +void gpio_longpress_pin1_reset_config(u32 pin, u32 level, u32 time); + + +/** + * @brief get_sfc_port 获取当前code flash的端口 + * + * @return + */ +u32 get_sfc_port(void); +#endif /*GPIO_H*/ diff --git a/include_lib/driver/cpu/br28/asm/hwi.h b/include_lib/driver/cpu/br28/asm/hwi.h new file mode 100644 index 0000000..c59e5ae --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/hwi.h @@ -0,0 +1,178 @@ +#ifndef HWI_H +#define HWI_H + +//================================================= +#define IRQ_EMUEXCPT_IDX 0 //0 +#define IRQ_EXCEPTION_IDX 1 //0 +#define IRQ_SYSCALL_IDX 2 //0 +#define IRQ_TICK_TMR_IDX 3 //0 +#define IRQ_TIME0_IDX 4 //0 +#define IRQ_TIME1_IDX 5 //0 +#define IRQ_TIME2_IDX 6 //0 +#define IRQ_TIME3_IDX 7 //0 +#define IRQ_TIME4_IDX 8 //0 +#define IRQ_TIME5_IDX 9 //0 + +#define IRQ_UART0_IDX 12 //0 +#define IRQ_UART1_IDX 13 //0 +#define IRQ_UART2_IDX 14 //0 + +#define IRQ_SPI0_IDX 16 //0 +#define IRQ_SPI1_IDX 17 //0 +#define IRQ_SPI2_IDX 18 //0 + +#define IRQ_SD0_IDX 20 //0 + +#define IRQ_IIC_IDX 24 //0 + +#define IRQ_USB_SOF_IDX 28 //1 +#define IRQ_USB_CTRL_IDX 29 //1 + +#define IRQ_P2M_IDX 32 //0 +#define IRQ_LP_TIMER0_IDX 33 +#define IRQ_LP_TIMER1_IDX 34 +#define IRQ_LP_TIMER2_IDX 35 +#define IRQ_LP_TIMER3_IDX 36 + +#define IRQ_PORT_IDX 38 //0 +#define IRQ_GPADC_IDX 39 //0 +#define IRQ_CTM_IDX 40 +#define IRQ_PWM_LED_IDX 41 //1 +#define IRQ_OSA_IDX 42 +#define IRQ_LRCT_IDX 43 //1 +#define IRQ_GPC_IDX 44 //1 +#define IRQ_FMTX_IDX 45 //1 +#define IRQ_TDM_IDX 46 //1 +#define IRQ_RDEC0_IDX 47 //1 +#define IRQ_SBC_IDX 48 //1 +#define IRQ_AES_IDX 49 +#define IRQ_RDEC1_IDX 50 //1 +#define IRQ_RDEC2_IDX 51 //1 +#define IRQ_MCPWM_CHX_IDX 52 +#define IRQ_MCPWM_TMR_IDX 53 + +#define IRQ_ANC_IDX 67 +#define IRQ_AUDIO_IDX 68 //1 +#define IRQ_ALINK0_IDX 69 //1 +#define IRQ_PDM_LINK_IDX 70 //1 + +#define IRQ_BT_CLKN_IDX 76 //2 +#define IRQ_BT_DBG_IDX 77 //1 +#define IRQ_BLE_RX_IDX 78 //2 +#define IRQ_BLE_EVENT_IDX 79 //1 + +#define IRQ_BT_TIMEBASE_IDX 80 //1 +#define IRQ_WL_LOFC_IDX 81 //2 +#define IRQ_BREDR_IDX 82 //2 + +#define IRQ_SYNC_IDX 88 //2 +#define IRQ_SRC_SYNC_IDX 89 //1 +#define IRQ_SRC_IDX 90 //1 +#define IRQ_EQ_IDX 91 //1 +#define IRQ_DCP_IDX 93 //1 + +#define IRQ_IMG_CP_IDX 103 //1 +#define IRQ_IMD_IDX 104 //1 +#define IRQ_IMB_IDX 105 //1 +#define IRQ_JPG_IDX 106 //1 + +#define IRQ_FFT_IDX 116 //1 + +#define IRQ_SOFT0_IDX 124 +#define IRQ_SOFT1_IDX 125 +#define IRQ_SOFT2_IDX 126 +#define IRQ_SOFT3_IDX 127 + +#define MAX_IRQ_ENTRY_NUM 128 + +//================================================= + +//================================================= + +void interrupt_init(); + + +/* --------------------------------------------------------------------------*/ +/** + * @brief 中断注册函数 + * + * @param index 中断号 + * @param priority 优先级,范围0-6可用 + * @param handler 中断服务函数 + * @param cpu_id 相应中断服务函数的CPU + */ +/* ----------------------------------------------------------------------------*/ +void request_irq(u8 index, u8 priority, void (*handler)(void), u8 cpu_id); + +void unrequest_irq(u8 index); + +void reg_set_ip(unsigned char index, unsigned char priority, u8 cpu_id); + + +/* --------------------------------------------------------------------------*/ +/** + * @brief 设置不可屏蔽中断(不可屏蔽中断不区分优先级) + * cpu多核同步默认使用0,其他使用1。 + * + * @param index 中断号 + * @param priority 不可屏蔽优先级,范围 0、1 (CPU_IRQ_IPMASK_LEVEL == 6) + * @param cpu_id 相应中断服务函数的CPU + */ +/* ----------------------------------------------------------------------------*/ +void irq_unmask_set(u8 index, u8 priority, u8 cpu_id); + +void bit_clr_ie(unsigned char index); +void bit_set_ie(unsigned char index); +bool irq_read(u32 index); + +#define irq_disable(x) bit_clr_ie(x) +#define irq_enable(x) bit_set_ie(x) + +void unmask_enter_critical(void); +void unmask_exit_critical(void); +//---------------------------------------------// +// low power waiting +//---------------------------------------------// +__attribute__((always_inline)) +static void lp_waiting(int *ptr, int pnd, int cpd, char inum) +{ + q32DSP(core_num())->IWKUP_NUM = inum; + while (!(*ptr & pnd)) { + asm volatile("idle"); + } + *ptr |= cpd; +} + +//---------------------------------------------// +// interrupt cli/sti +//---------------------------------------------// + +static inline int int_cli(void) +{ + int msg; + asm volatile("cli %0" : "=r"(msg) :); + return msg; +} + +static inline void int_sti(int msg) +{ + asm volatile("sti %0" :: "r"(msg)); +} + +#ifdef IRQ_TIME_COUNT_EN +void irq_handler_enter(int irq); + +void irq_handler_exit(int irq); + +void irq_handler_times_dump(); +#else + +#define irq_handler_enter(irq) do { }while(0) +#define irq_handler_exit(irq) do { }while(0) +#define irq_handler_times_dump() do { }while(0) + +#endif + + +#endif + diff --git a/include_lib/driver/cpu/br28/asm/iic_hw.h b/include_lib/driver/cpu/br28/asm/iic_hw.h new file mode 100644 index 0000000..e9d648c --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/iic_hw.h @@ -0,0 +1,82 @@ +#ifndef _IIC_HW_H_ +#define _IIC_HW_H_ + +#include "system/generic/typedef.h" + +#define IIC_HW_NUM 1 +#define IIC_PORT_GROUP_NUM 4 + +#define iic_enable(reg) (reg->CON0 |= BIT(0)) +#define iic_disable(reg) (reg->CON0 &= ~BIT(0)) +#define iic_role_host(reg) (reg->CON0 &= ~BIT(1)) +#define iic_role_slave(reg) (reg->CON0 |= BIT(1)) +#define iic_cfg_done(reg) (reg->CON0 |= BIT(2)) +#define iic_dir_out(reg) (reg->CON0 &= ~BIT(3)) +#define iic_dir_in(reg) (reg->CON0 |= BIT(3)) +#define iic_preset_end(reg) (reg->CON0 |= BIT(4)) +#define iic_preset_restart(reg) (reg->CON0 |= BIT(5)) +#define iic_recv_ack(reg) (reg->CON0 &= ~BIT(6)) +#define iic_recv_nack(reg) (reg->CON0 |= BIT(6)) +#define iic_send_is_ack(reg) (!(reg->CON0 & BIT(7))) +#define iic_isel_direct(reg) (reg->CON0 &= ~BIT(9)) +#define iic_isel_filter(reg) (reg->CON0 |= BIT(9)) +#define iic_si_mode_en(reg) (reg->CON1 |= BIT(13)) +#define iic_si_mode_dis(reg) (reg->CON1 &= ~BIT(13)) + +#define iic_set_ie(reg) (reg->CON0 |= BIT(8)) +#define iic_clr_ie(reg) (reg->CON0 &= ~BIT(8)) +#define iic_pnd(reg) (reg->CON0 & BIT(15)) +#define iic_pnd_clr(reg) (reg->CON0 |= BIT(14)) + +#define iic_set_end_ie(reg) (reg->CON0 |= BIT(10)) +#define iic_clr_end_ie(reg) (reg->CON0 &= BIT(10)) +#define iic_end_pnd(reg) (reg->CON0 & BIT(13)) +#define iic_end_pnd_clr(reg) (reg->CON0 |= BIT(12)) + +#define iic_start_pnd(reg) (reg->CON1 & BIT(15)) +#define iic_start_pnd_clr(reg) (reg->CON1 |= BIT(14)) + +#define iic_baud_reg(reg) (reg->BAUD) +#define iic_buf_reg(reg) (reg->BUF) + + +typedef const int hw_iic_dev; + +enum {IIC_MASTER, IIC_SLAVE}; + +struct hw_iic_config { + u8 port[2]; + u32 baudrate; + u8 hdrive; + u8 io_filter; + u8 io_pu; + u8 role; +}; + +extern const struct hw_iic_config hw_iic_cfg[]; + +int hw_iic_init(hw_iic_dev iic); +void hw_iic_uninit(hw_iic_dev iic); +void hw_iic_suspend(hw_iic_dev iic); +void hw_iic_resume(hw_iic_dev iic); +void hw_iic_start(hw_iic_dev iic); +void hw_iic_stop(hw_iic_dev iic); +u8 hw_iic_tx_byte(hw_iic_dev iic, u8 byte); +u8 hw_iic_rx_byte(hw_iic_dev iic, u8 ack); +int hw_iic_read_buf(hw_iic_dev iic, void *buf, int len); +int hw_iic_write_buf(hw_iic_dev iic, const void *buf, int len); +int hw_iic_set_baud(hw_iic_dev iic, u32 baud); + +void hw_iic_set_ie(hw_iic_dev iic, u8 en); +u8 hw_iic_get_pnd(hw_iic_dev iic); +void hw_iic_clr_pnd(hw_iic_dev iic); +void hw_iic_set_end_ie(hw_iic_dev iic, u8 en); +u8 hw_iic_get_end_pnd(hw_iic_dev iic); +void hw_iic_clr_end_pnd(hw_iic_dev iic); +void hw_iic_slave_set_addr(hw_iic_dev iic, u8 addr, u8 addr_ack); +void hw_iic_slave_rx_prepare(hw_iic_dev iic, u8 ack); +u8 hw_iic_slave_rx_byte(hw_iic_dev iic, bool *is_start_addr); +void hw_iic_slave_tx_byte(hw_iic_dev iic, u8 byte); +u8 hw_iic_slave_tx_check_ack(hw_iic_dev iic); + +#endif diff --git a/include_lib/driver/cpu/br28/asm/iic_soft.h b/include_lib/driver/cpu/br28/asm/iic_soft.h new file mode 100644 index 0000000..af58255 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/iic_soft.h @@ -0,0 +1,28 @@ +#ifndef _IIC_SOFT_H_ +#define _IIC_SOFT_H_ + +#include "generic/typedef.h" + +typedef const int soft_iic_dev; + +struct soft_iic_config { + int scl; + int sda; + u32 delay; + u8 io_pu; +}; + +extern const struct soft_iic_config soft_iic_cfg[]; + +int soft_iic_init(soft_iic_dev iic); +void soft_iic_uninit(soft_iic_dev iic); +void soft_iic_suspend(soft_iic_dev iic); +void soft_iic_resume(soft_iic_dev iic); +void soft_iic_start(soft_iic_dev iic); +void soft_iic_stop(soft_iic_dev iic); +u8 soft_iic_tx_byte(soft_iic_dev iic, u8 byte); +u8 soft_iic_rx_byte(soft_iic_dev iic, u8 ack); +int soft_iic_read_buf(soft_iic_dev iic, void *buf, int len); +int soft_iic_write_buf(soft_iic_dev iic, const void *buf, int len); +#endif + diff --git a/include_lib/driver/cpu/br28/asm/iis.h b/include_lib/driver/cpu/br28/asm/iis.h new file mode 100644 index 0000000..a8008e4 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/iis.h @@ -0,0 +1,48 @@ +#ifndef __IIS_H__ +#define __IIS_H__ + +#include "generic/typedef.h" + + +#define ALINK_SEL(module, reg) (((JL_ALNK_TypeDef *)(((u8 *)JL_ALNK0)))->reg) + +#define ALNK_CON_RESET(module) do {ALINK_SEL(module, CON0) = 0; ALINK_SEL(module, CON1) = 0; ALINK_SEL(module, CON2) = 0; ALINK_SEL(module, CON3) = 0;} while(0) +#define ALNK_HWPTR_RESET(module) do {ALINK_SEL(module, HWPTR0) = 0; ALINK_SEL(module, HWPTR1) = 0; ALINK_SEL(module, HWPTR2) = 0; ALINK_SEL(module, HWPTR3) = 0;} while(0) +#define ALNK_SWPTR_RESET(module) do {ALINK_SEL(module, SWPTR0) = 0; ALINK_SEL(module, SWPTR1) = 0; ALINK_SEL(module, SWPTR2) = 0; ALINK_SEL(module, SWPTR3) = 0;} while(0) +#define ALNK_SHN_RESET(module) do {ALINK_SEL(module, SHN0) = 0; ALINK_SEL(module, SHN1) = 0; ALINK_SEL(module, SHN2) = 0; ALINK_SEL(module, SHN3) = 0;} while(0) +#define ALNK_ADR_RESET(module) do {ALINK_SEL(module, ADR0) = 0; ALINK_SEL(module, ADR1) = 0; ALINK_SEL(module, ADR2) = 0; ALINK_SEL(module, ADR3) = 0;} while(0) +#define ALNK_PNS_RESET(module) do {ALINK_SEL(module, PNS) = 0;} while(0) + +#define ALINK_DA2BTSRC_SEL(module, x) SFR(ALINK_SEL(module, CON0), 0, 2, x) +#define ALINK_DMA_MODE_SEL(module, x) SFR(ALINK_SEL(module, CON0), 2, 1, x) +#define ALINK_DSPE(module, x) SFR(ALINK_SEL(module, CON0), 6, 1, x) +#define ALINK_SOE(module, x) SFR(ALINK_SEL(module, CON0), 7, 1, x) +#define ALINK_MOE(module, x) SFR(ALINK_SEL(module, CON0), 8, 1, x) +#define F32_EN(module, x) SFR(ALINK_SEL(module, CON0), 9, 1, x) +#define SCLKINV(module, x) SFR(ALINK_SEL(module, CON0),10, 1, x) +#define ALINK_EN(module, x) SFR(ALINK_SEL(module, CON0),11, 1, x) +#define ALINK_24BIT_MODE(module) (ALINK_SEL(module, CON1) |= (BIT(2) | BIT(6) | BIT(10) | BIT(14))) +#define ALINK_16BIT_MODE(module) (ALINK_SEL(module, CON1) &= (~(BIT(2) | BIT(6) | BIT(10) | BIT(14)))) + + +#define ALINK_CHx_DIR_MODE(module, ch, x) SFR(ALINK_SEL(module, CON1), 3 + 4 * ch, 1, x) +#define ALINK_CHx_MODE_SEL(module, ch, x) SFR(ALINK_SEL(module, CON1), 4 * ch, 2, x) +#define ALINK_CHx_CLOSE(module, ch) SFR(ALINK_SEL(module, CON1), 4 * ch, 2, 0) + + +#define ALINK_CLR_ALL_PND(module) (ALINK_SEL(module, CON2) |= BIT(0) | BIT(1) | BIT(2) | BIT(3)) +#define ALINK_CLR_CHx_PND(module, ch) (ALINK_SEL(module, CON2) |= BIT(ch)) +#define ALINK_CHx_IE(module, ch, x) SFR(ALINK_SEL(module, CON2), ch + 12, 1, x) + +#define ALINK_MSRC(module, x) SFR(ALINK_SEL(module, CON3), 0, 2, x) +#define ALINK_MDIV(module, x) SFR(ALINK_SEL(module, CON3), 2, 3, x) +#define ALINK_LRDIV(module, x) SFR(ALINK_SEL(module, CON3), 5, 3, x) + +#define ALINK_OPNS(module) (ALINK_SEL(module, PNS) >> 16) +#define ALINK_IPNS(module) (ALINK_SEL(module, PNS) & 0xffff) +#define ALINK_OPNS_SET(module, x) SFR(ALINK_SEL(module, PNS), 16, 16, x) +#define ALINK_IPNS_SET(module, x) SFR(ALINK_SEL(module, PNS), 0, 16, x) + +#define ALINK_LEN_SET(module, x) (ALINK_SEL(module, LEN) = x) +#define ALINK_FIFO_LEN(module) (ALINK_SEL(module, LEN)) +#endif diff --git a/include_lib/driver/cpu/br28/asm/includes.h b/include_lib/driver/cpu/br28/asm/includes.h new file mode 100644 index 0000000..2063d2b --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/includes.h @@ -0,0 +1,31 @@ +#ifndef ASM_INCLUDES_H +#define ASM_INCLUDES_H + +#include "asm/cpu.h" +#include "asm/crc16.h" +#include "asm/clock.h" +#include "asm/uart.h" +#include "asm/uart_dev.h" +#include "asm/gpio.h" +#include "asm/spiflash.h" +#include "asm/csfr.h" +#include "asm/power_interface.h" +#include "asm/efuse.h" +#include "asm/wdt.h" +#include "asm/debug.h" +#include "asm/power/p33.h" +#include "asm/timer.h" +#include "asm/rtc.h" + + + + + + + + + + + + +#endif diff --git a/include_lib/driver/cpu/br28/asm/io_imap.h b/include_lib/driver/cpu/br28/asm/io_imap.h new file mode 100644 index 0000000..e4f719c --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/io_imap.h @@ -0,0 +1,131 @@ + + +//===============================================================================// +// +// input IO define +// +//===============================================================================// +#define PA0_IN 1 +#define PA1_IN 2 +#define PA2_IN 3 +#define PA3_IN 4 +#define PA4_IN 5 +#define PA5_IN 6 +#define PA6_IN 7 +#define PA7_IN 8 +#define PA8_IN 9 +#define PA9_IN 10 +#define PA10_IN 11 +#define PA11_IN 12 +#define PA12_IN 13 +#define PA13_IN 14 +#define PA14_IN 15 +#define PA15_IN 16 +#define PB0_IN 17 +#define PB1_IN 18 +#define PB2_IN 19 +#define PB3_IN 20 +#define PB4_IN 21 +#define PB5_IN 22 +#define PB6_IN 23 +#define PB7_IN 24 +#define PB8_IN 25 +#define PB9_IN 26 +#define PB10_IN 27 +#define PB11_IN 28 +#define PC0_IN 29 +#define PC1_IN 30 +#define PC2_IN 31 +#define PC3_IN 32 +#define PC4_IN 33 +#define PC5_IN 34 +#define PC6_IN 35 +#define PC7_IN 36 +#define PC8_IN 37 +#define PG0_IN 38 +#define PG1_IN 39 +#define PG2_IN 40 +#define PG3_IN 41 +#define PG4_IN 42 +#define PG5_IN 43 +#define PG6_IN 44 +#define PG7_IN 45 +#define PG8_IN 46 +#define USBDP_IN 47 +#define USBDM_IN 48 +#define PP0_IN 49 + +//===============================================================================// +// +// function input select sfr +// +//===============================================================================// +typedef struct { + __RW __u8 FI_GP_ICH0; + __RW __u8 FI_GP_ICH1; + __RW __u8 FI_GP_ICH2; + __RW __u8 FI_GP_ICH3; + __RW __u8 FI_GP_ICH4; + __RW __u8 FI_GP_ICH5; + __RW __u8 FI_GP_ICH6; + __RW __u8 FI_GP_ICH7; + __RW __u8 FI_GP_ICH8; + __RW __u8 FI_GP_ICH9; + __RW __u8 FI_GP_ICH10; + __RW __u8 FI_GP_ICH11; + __RW __u8 FI_GP_ICH12; + __RW __u8 FI_GP_ICH13; + __RW __u8 FI_SPI0_CLK; + __RW __u8 FI_SPI0_DA0; + __RW __u8 FI_SPI0_DA1; + __RW __u8 FI_SPI0_DA2; + __RW __u8 FI_SPI0_DA3; + __RW __u8 FI_SPI1_CLK; + __RW __u8 FI_SPI1_DA0; + __RW __u8 FI_SPI1_DA1; + __RW __u8 FI_SPI1_DA2; + __RW __u8 FI_SPI1_DA3; + __RW __u8 FI_SPI2_CLK; + __RW __u8 FI_SPI2_DA0; + __RW __u8 FI_SPI2_DA1; + __RW __u8 FI_SPI2_DA2; + __RW __u8 FI_SPI2_DA3; + __RW __u8 FI_SD0_CMD; + __RW __u8 FI_SD0_DA0; + __RW __u8 FI_SD0_DA1; + __RW __u8 FI_SD0_DA2; + __RW __u8 FI_SD0_DA3; + __RW __u8 FI_IIC_SCL; + __RW __u8 FI_IIC_SDA; + __RW __u8 FI_UART0_RX; + __RW __u8 FI_UART1_RX; + __RW __u8 FI_UART1_CTS; + __RW __u8 FI_UART2_RX; + __RW __u8 FI_TDM_S_WCK; + __RW __u8 FI_TDM_S_BCK; + __RW __u8 FI_TDM_M_DA; + __RW __u8 FI_RDEC0_DAT0; + __RW __u8 FI_RDEC0_DAT1; + __RW __u8 FI_RDEC1_DAT0; + __RW __u8 FI_RDEC1_DAT1; + __RW __u8 FI_RDEC2_DAT0; + __RW __u8 FI_RDEC2_DAT1; + __RW __u8 FI_ALNK0_MCLK; + __RW __u8 FI_ALNK0_LRCK; + __RW __u8 FI_ALNK0_SCLK; + __RW __u8 FI_ALNK0_DAT0; + __RW __u8 FI_ALNK0_DAT1; + __RW __u8 FI_ALNK0_DAT2; + __RW __u8 FI_ALNK0_DAT3; + __RW __u8 FI_PLNK_DAT0; + __RW __u8 FI_PLNK_DAT1; + __RW __u8 FI_CHAIN_IN0; + __RW __u8 FI_CHAIN_IN1; + __RW __u8 FI_CHAIN_IN2; + __RW __u8 FI_CHAIN_IN3; + __RW __u8 FI_CHAIN_RST; + __RW __u8 FI_TOTAL; +} JL_IMAP_TypeDef; + +#define JL_IMAP_BASE (ls_base + map_adr(0x5c, 0x00)) +#define JL_IMAP ((JL_IMAP_TypeDef *)JL_IMAP_BASE) diff --git a/include_lib/driver/cpu/br28/asm/io_omap.h b/include_lib/driver/cpu/br28/asm/io_omap.h new file mode 100644 index 0000000..17133b7 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/io_omap.h @@ -0,0 +1,130 @@ + + +//===============================================================================// +// +// output function define +// +//===============================================================================// +#define FO_GP_OCH0 ((0 << 2)|BIT(1)) +#define FO_GP_OCH1 ((1 << 2)|BIT(1)) +#define FO_GP_OCH2 ((2 << 2)|BIT(1)) +#define FO_GP_OCH3 ((3 << 2)|BIT(1)) +#define FO_GP_OCH4 ((4 << 2)|BIT(1)) +#define FO_GP_OCH5 ((5 << 2)|BIT(1)) +#define FO_GP_OCH6 ((6 << 2)|BIT(1)) +#define FO_GP_OCH7 ((7 << 2)|BIT(1)) +#define FO_GP_OCH8 ((8 << 2)|BIT(1)) +#define FO_GP_OCH9 ((9 << 2)|BIT(1)) +#define FO_GP_OCH10 ((10 << 2)|BIT(1)) +#define FO_GP_OCH11 ((11 << 2)|BIT(1)) +#define FO_GP_OCH12 ((12 << 2)|BIT(1)) +#define FO_GP_OCH13 ((13 << 2)|BIT(1)) +#define FO_GP_OCH14 ((14 << 2)|BIT(1)) +#define FO_GP_OCH15 ((15 << 2)|BIT(1)) +#define FO_SPI0_CLK ((16 << 2)|BIT(1)|BIT(0)) +#define FO_SPI0_DA0 ((17 << 2)|BIT(1)|BIT(0)) +#define FO_SPI0_DA1 ((18 << 2)|BIT(1)|BIT(0)) +#define FO_SPI0_DA2 ((19 << 2)|BIT(1)|BIT(0)) +#define FO_SPI0_DA3 ((20 << 2)|BIT(1)|BIT(0)) +#define FO_SPI1_CLK ((21 << 2)|BIT(1)|BIT(0)) +#define FO_SPI1_DA0 ((22 << 2)|BIT(1)|BIT(0)) +#define FO_SPI1_DA1 ((23 << 2)|BIT(1)|BIT(0)) +#define FO_SPI1_DA2 ((24 << 2)|BIT(1)|BIT(0)) +#define FO_SPI1_DA3 ((25 << 2)|BIT(1)|BIT(0)) +#define FO_SPI2_CLK ((26 << 2)|BIT(1)|BIT(0)) +#define FO_SPI2_DA0 ((27 << 2)|BIT(1)|BIT(0)) +#define FO_SPI2_DA1 ((28 << 2)|BIT(1)|BIT(0)) +#define FO_SPI2_DA2 ((29 << 2)|BIT(1)|BIT(0)) +#define FO_SPI2_DA3 ((30 << 2)|BIT(1)|BIT(0)) +#define FO_SD0_CLK ((31 << 2)|BIT(1)|BIT(0)) +#define FO_SD0_CMD ((32 << 2)|BIT(1)|BIT(0)) +#define FO_SD0_DA0 ((33 << 2)|BIT(1)|BIT(0)) +#define FO_SD0_DA1 ((34 << 2)|BIT(1)|BIT(0)) +#define FO_SD0_DA2 ((35 << 2)|BIT(1)|BIT(0)) +#define FO_SD0_DA3 ((36 << 2)|BIT(1)|BIT(0)) +#define FO_IIC_SCL ((37 << 2)|BIT(1)|BIT(0)) +#define FO_IIC_SDA ((38 << 2)|BIT(1)|BIT(0)) +#define FO_UART0_TX ((39 << 2)|BIT(1)|BIT(0)) +#define FO_UART1_TX ((40 << 2)|BIT(1)|BIT(0)) +#define FO_UART1_RTS ((41 << 2)|BIT(1)|BIT(0)) +#define FO_UART2_TX ((42 << 2)|BIT(1)|BIT(0)) +#define FO_TDM_M_MCK ((43 << 2)|BIT(1)|BIT(0)) +#define FO_TDM_M_WCK ((44 << 2)|BIT(1)|BIT(0)) +#define FO_TDM_M_BCK ((45 << 2)|BIT(1)|BIT(0)) +#define FO_TDM_S_DA ((46 << 2)|BIT(1)|BIT(0)) +#define FO_ALNK0_MCLK ((47 << 2)|BIT(1)|BIT(0)) +#define FO_ALNK0_LRCK ((48 << 2)|BIT(1)|BIT(0)) +#define FO_ALNK0_SCLK ((49 << 2)|BIT(1)|BIT(0)) +#define FO_ALNK0_DAT0 ((50 << 2)|BIT(1)|BIT(0)) +#define FO_ALNK0_DAT1 ((51 << 2)|BIT(1)|BIT(0)) +#define FO_ALNK0_DAT2 ((52 << 2)|BIT(1)|BIT(0)) +#define FO_ALNK0_DAT3 ((53 << 2)|BIT(1)|BIT(0)) +#define FO_PLNK_SCLK ((54 << 2)|BIT(1)|BIT(0)) +#define FO_WL_ANT_ID0 ((55 << 2)|BIT(1)|BIT(0)) +#define FO_WL_ANT_ID1 ((56 << 2)|BIT(1)|BIT(0)) +#define FO_WL_ANT_ID2 ((57 << 2)|BIT(1)|BIT(0)) +#define FO_WL_ANT_ID3 ((58 << 2)|BIT(1)|BIT(0)) +#define FO_CHAIN_OUT0 ((59 << 2)|BIT(1)|BIT(0)) +#define FO_CHAIN_OUT1 ((60 << 2)|BIT(1)|BIT(0)) +#define FO_CHAIN_OUT2 ((61 << 2)|BIT(1)|BIT(0)) +#define FO_CHAIN_OUT3 ((62 << 2)|BIT(1)|BIT(0)) + +//===============================================================================// +// +// IO output select sfr +// +//===============================================================================// +typedef struct { + __RW __u8 PA0_OUT; + __RW __u8 PA1_OUT; + __RW __u8 PA2_OUT; + __RW __u8 PA3_OUT; + __RW __u8 PA4_OUT; + __RW __u8 PA5_OUT; + __RW __u8 PA6_OUT; + __RW __u8 PA7_OUT; + __RW __u8 PA8_OUT; + __RW __u8 PA9_OUT; + __RW __u8 PA10_OUT; + __RW __u8 PA11_OUT; + __RW __u8 PA12_OUT; + __RW __u8 PA13_OUT; + __RW __u8 PA14_OUT; + __RW __u8 PA15_OUT; + __RW __u8 PB0_OUT; + __RW __u8 PB1_OUT; + __RW __u8 PB2_OUT; + __RW __u8 PB3_OUT; + __RW __u8 PB4_OUT; + __RW __u8 PB5_OUT; + __RW __u8 PB6_OUT; + __RW __u8 PB7_OUT; + __RW __u8 PB8_OUT; + __RW __u8 PB9_OUT; + __RW __u8 PB10_OUT; + __RW __u8 PB11_OUT; + __RW __u8 PC0_OUT; + __RW __u8 PC1_OUT; + __RW __u8 PC2_OUT; + __RW __u8 PC3_OUT; + __RW __u8 PC4_OUT; + __RW __u8 PC5_OUT; + __RW __u8 PC6_OUT; + __RW __u8 PC7_OUT; + __RW __u8 PC8_OUT; + __RW __u8 PG0_OUT; + __RW __u8 PG1_OUT; + __RW __u8 PG2_OUT; + __RW __u8 PG3_OUT; + __RW __u8 PG4_OUT; + __RW __u8 PG5_OUT; + __RW __u8 PG6_OUT; + __RW __u8 PG7_OUT; + __RW __u8 PG8_OUT; + __RW __u8 USBDP_OUT; + __RW __u8 USBDM_OUT; + __RW __u8 PP0_OUT; +} JL_OMAP_TypeDef; + +#define JL_OMAP_BASE (ls_base + map_adr(0x58, 0x00)) +#define JL_OMAP ((JL_OMAP_TypeDef *)JL_OMAP_BASE) diff --git a/include_lib/driver/cpu/br28/asm/irflt.h b/include_lib/driver/cpu/br28/asm/irflt.h new file mode 100644 index 0000000..1360bb1 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/irflt.h @@ -0,0 +1,231 @@ +#ifndef __KEY_DRV_IR_H__ +#define __KEY_DRV_IR_H__ + +#define IR_PORTA(x) (0x00 + x) +#define IR_PORTB(x) (0x10 + x) +#define IR_PORTC(x) (0x20 + x) +#define IR_PORTD(x) (0x30 + x) +#define IR_USBDP (0x3d) +#define IR_USBDM (0x3e) + +#define IR_IO IR_PORTA(9) + +/*ir key define*/ +#define IR_00 0 +#define IR_01 1 +#define IR_02 2 +#define IR_03 3 +#define IR_04 4 +#define IR_05 5 +#define IR_06 6 +#define IR_07 7 +#define IR_08 8 +#define IR_09 9 +#define IR_10 10 +#define IR_11 11 +#define IR_12 12 +#define IR_13 13 +#define IR_14 14 +#define IR_15 15 +#define IR_16 16 +#define IR_17 17 +#define IR_18 18 +#define IR_19 19 +#define IR_20 20 +#define IR_21 21 +#define IR_22 22 + +////////////////////////////////// +#define NKEY_00 0xff +#define NKEY_01 0xff +#define NKEY_02 0xff +#define NKEY_03 0xff +#define NKEY_04 0xff +#define NKEY_05 0xff +#define NKEY_06 0xff +#define NKEY_07 0xff +#define NKEY_08 0xff +#define NKEY_09 0xff +#define NKEY_0A 0xff +#define NKEY_0B 0xff +#define NKEY_0C 0xff +#define NKEY_0D 0xff +#define NKEY_0E 0xff +#define NKEY_0F 0xff +#define NKEY_10 0xff +#define NKEY_11 0xff +#define NKEY_12 0xff +#define NKEY_13 0xff +#define NKEY_14 0xff +#define NKEY_15 0xff +#define NKEY_16 0xff +#define NKEY_17 0xff +#define NKEY_18 0xff +#define NKEY_19 0xff +#define NKEY_1A 0xff +#define NKEY_1B 0xff +#define NKEY_1C 0xff +#define NKEY_1D 0xff +#define NKEY_1E 0xff +#define NKEY_1F 0xff +#define NKEY_20 0xff +#define NKEY_21 0xff +#define NKEY_22 0xff +#define NKEY_23 0xff +#define NKEY_24 0xff +#define NKEY_25 0xff +#define NKEY_26 0xff +#define NKEY_27 0xff +#define NKEY_28 0xff +#define NKEY_29 0xff +#define NKEY_2A 0xff +#define NKEY_2B 0xff +#define NKEY_2C 0xff +#define NKEY_2D 0xff +#define NKEY_2E 0xff +#define NKEY_2F 0xff +#define NKEY_30 0xff +#define NKEY_31 0xff +#define NKEY_32 0xff +#define NKEY_33 0xff +#define NKEY_34 0xff +#define NKEY_35 0xff +#define NKEY_36 0xff +#define NKEY_37 0xff +#define NKEY_38 0xff +#define NKEY_39 0xff +#define NKEY_3A 0xff +#define NKEY_3B 0xff +#define NKEY_3C 0xff +#define NKEY_3D 0xff +#define NKEY_3E 0xff +#define NKEY_3F 0xff +#define NKEY_40 0xff +#define NKEY_41 0xff +#define NKEY_42 0xff +#define NKEY_43 0xff +#define NKEY_44 0xff +#define NKEY_45 0xff +#define NKEY_46 0xff +#define NKEY_47 0xff +#define NKEY_48 0xff +#define NKEY_49 0xff +#define NKEY_4A 0xff +#define NKEY_4B 0xff +#define NKEY_4C 0xff +#define NKEY_4D 0xff +#define NKEY_4E 0xff +#define NKEY_4F 0xff +#define NKEY_50 0xff +#define NKEY_51 0xff +#define NKEY_52 0xff +#define NKEY_53 0xff +#define NKEY_54 0xff +#define NKEY_55 0xff +#define NKEY_56 0xff +#define NKEY_57 0xff +#define NKEY_58 0xff +#define NKEY_59 0xff +#define NKEY_5A 0xff +#define NKEY_5B 0xff +#define NKEY_5C 0xff +#define NKEY_5D 0xff +#define NKEY_5E 0xff +#define NKEY_5F 0xff +#define NKEY_60 0xff +#define NKEY_61 0xff +#define NKEY_62 0xff +#define NKEY_63 0xff +#define NKEY_64 0xff +#define NKEY_65 0xff +#define NKEY_66 0xff +#define NKEY_67 0xff +#define NKEY_68 0xff +#define NKEY_69 0xff +#define NKEY_6A 0xff +#define NKEY_6B 0xff +#define NKEY_6C 0xff +#define NKEY_6D 0xff +#define NKEY_6E 0xff +#define NKEY_6F 0xff +#define NKEY_70 0xff +#define NKEY_71 0xff +#define NKEY_72 0xff +#define NKEY_73 0xff +#define NKEY_74 0xff +#define NKEY_75 0xff +#define NKEY_76 0xff +#define NKEY_77 0xff +#define NKEY_78 0xff +#define NKEY_79 0xff +#define NKEY_7A 0xff +#define NKEY_7B 0xff +#define NKEY_7C 0xff +#define NKEY_7D 0xff +#define NKEY_7E 0xff +#define NKEY_7F 0xff +#define NKEY_80 0xff +#define NKEY_81 0xff +#define NKEY_82 0xff +#define NKEY_83 0xff +#define NKEY_84 0xff +#define NKEY_85 0xff +#define NKEY_86 0xff +#define NKEY_87 0xff +#define NKEY_88 0xff +#define NKEY_89 0xff +#define NKEY_8A 0xff +#define NKEY_8B 0xff +#define NKEY_8C 0xff +#define NKEY_8D 0xff +#define NKEY_8E 0xff +#define NKEY_8F 0xff +#define NKEY_90 0xff +#define NKEY_91 0xff +#define NKEY_92 0xff +#define NKEY_93 0xff +#define NKEY_94 0xff +#define NKEY_95 0xff + + +typedef struct _IR_CODE { + u16 wData; //<键值 + u16 wUserCode; //<用户码 + u16 timer_pad; + u8 bState; //<接收状态 + u8 boverflow; //<红外信号超时 +} IR_CODE; + +enum timer_sel { + TIMER0, + TIMER1, + TIMER2, + TIMER3, + TIMER4, + TIMER5, +}; + +struct irflt_platform_data { + u8 irflt_io; + u8 timer; +}; + +#define IRFLT_PLATFORM_DATA_BEGIN(data) \ + static const struct irflt_platform_data data = { + +#define IRFLT_PLATFORM_DATA_END() \ +}; + + +extern const struct device_operations irflt_dev_ops; + +void set_ir_clk(void); +void ir_input_io_sel(u8 port); +void ir_output_timer_sel(); +void ir_timeout_set(void); +void irflt_config(); +void log_irflt_info(); +u8 get_irflt_value(void); + +#endif + diff --git a/include_lib/driver/cpu/br28/asm/irq.h b/include_lib/driver/cpu/br28/asm/irq.h new file mode 100644 index 0000000..e1ef2bd --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/irq.h @@ -0,0 +1,20 @@ +#ifndef CPU_IRQ_H +#define CPU_IRQ_H + + +#include "asm/hwi.h" + +#ifdef CONFIG_HWI_DEBUG +#define ___interrupt +#else +#define ___interrupt __attribute__((interrupt(""))) +#endif + + + + +#endif + + + + diff --git a/include_lib/driver/cpu/br28/asm/lp_touch_key_alog.h b/include_lib/driver/cpu/br28/asm/lp_touch_key_alog.h new file mode 100644 index 0000000..cebabfe --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/lp_touch_key_alog.h @@ -0,0 +1,20 @@ +#ifndef __LP_TOUCH_KEY_ALOG_H__ +#define __LP_TOUCH_KEY_ALOG_H__ + + +#include "typedef.h" + + +void TouchAlgo_Init(u8 ch, u16 min, u16 max); +void TouchAlgo_Update(u8 ch, u16 x); +void TouchAlgo_Reset(u8 ch, u16 min, u16 max); + +u16 TouchAlgo_GetRange(u8 ch, u8 *valid); +void TouchAlgo_SetRange(u8 ch, u16 range); + +s32 TouchAlgo_GetSigma(u8 ch); +void TouchAlgo_SetSigma(u8 ch, s32 sigma); + + +#endif /*LP_TOUCH_KEY_ALOG_H*/ + diff --git a/include_lib/driver/cpu/br28/asm/lp_touch_key_api.h b/include_lib/driver/cpu/br28/asm/lp_touch_key_api.h new file mode 100644 index 0000000..368e676 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/lp_touch_key_api.h @@ -0,0 +1,157 @@ +#ifndef _LP_TOUCH_KEY_API_ +#define _LP_TOUCH_KEY_API_ + +#include "typedef.h" +#include "asm/lp_touch_key_hw.h" + + +/**************************************************USER配置************************************************************************/ +//长按开机时间: +#define CFG_M2P_CTMU_SOFTOFF_LONG_TIME 1000 //单位: ms + +//触摸按键长按复位时间配置 +#define CTMU_RESET_TIME_CONFIG 8000 //长按复位时间(ms), 配置为0关闭 + +//debug +#define CFG_CH0_DEBUG_ENABLE 0 +#define CFG_CH1_DEBUG_ENABLE 0 +#define CFG_CH2_DEBUG_ENABLE 0 +#define CFG_CH3_DEBUG_ENABLE 0 +#define CFG_CH4_DEBUG_ENABLE 0 + +#define CFG_CHx_DEBUG_ENABLE ((CFG_CH4_DEBUG_ENABLE<<4) | (CFG_CH3_DEBUG_ENABLE<<3) | (CFG_CH2_DEBUG_ENABLE<<2) | (CFG_CH1_DEBUG_ENABLE<<1) | (CFG_CH0_DEBUG_ENABLE)) + +#define CFG_DISABLE_KEY_EVENT 0 + +#define TWS_BT_SEND_KEY_CH_RES_DATA_ENABLE 0 + +#define TWS_BT_SEND_EARTCH_RES_DATA_ENABLE 0 + +#define TWS_BT_SEND_EVENT_ENABLE 0 + + +#if TWS_BT_SEND_KEY_CH_RES_DATA_ENABLE +#if !CFG_CHx_DEBUG_ENABLE +#undef CFG_CHx_DEBUG_ENABLE +#define CFG_CHx_DEBUG_ENABLE 0b11111 +#endif +#endif + + +#if (CFG_CH0_DEBUG_ENABLE || CFG_CH1_DEBUG_ENABLE || CFG_CH2_DEBUG_ENABLE || CFG_CH3_DEBUG_ENABLE || CFG_CH4_DEBUG_ENABLE) +#if !CFG_DISABLE_KEY_EVENT +#undef CFG_DISABLE_KEY_EVENT +#define CFG_DISABLE_KEY_EVENT 1 +#endif +#endif + + +#define ERATCH_KEY_MSG_LOCK_TIME 3000 //ms 入耳检测状态发生改变时,多长时间内不能发送按键消息 + + +/*************************************************** Lpctmu API **********************************************************/ +#define LP_CTMU_CHANNEL_SIZE 5 + +enum LP_TOUCH_SOFTOFF_MODE { + LP_TOUCH_SOFTOFF_MODE_LEGACY = 0, //普通关机 + LP_TOUCH_SOFTOFF_MODE_ADVANCE = 1, //带触摸关机 +}; + +enum ctmu_key_event { + CTMU_KEY_NULL, + CTMU_KEY_SHORT_CLICK, + CTMU_KEY_LONG_CLICK, + CTMU_KEY_HOLD_CLICK, +}; + + +enum { + TOUCH_KEY_EVENT_SLIDE_UP, + TOUCH_KEY_EVENT_SLIDE_DOWN, + TOUCH_KEY_EVENT_SLIDE_LEFT, + TOUCH_KEY_EVENT_SLIDE_RIGHT, + TOUCH_KEY_EVENT_MAX, +}; + + +struct ctmu_ch_cfg { + u8 enable; + u8 wakeup_enable; + u8 key_value; + u8 port; + u8 sensitivity; +}; + +struct lp_touch_key_platform_data { + u8 slide_mode_en; + u8 slide_mode_key_value; + u8 eartch_en; + u8 eartch_ch; + u8 eartch_ref_ch; + u16 eartch_soft_inear_val; + u16 eartch_soft_outear_val; + struct ctmu_ch_cfg ch[LP_CTMU_CHANNEL_SIZE]; +}; + +enum ch1_event_list { + EAR_IN, + EAR_OUT, +}; + +enum { + EPD_IN, + EPD_OUT, + EPD_STATE_NO_CHANCE +}; + +struct ch_ana_cfg { + u8 isel; + u8 vhsel; + u8 vlsel; +}; + +struct ch_adjust_table { + u16 cfg0; + u16 cfg1; + u16 cfg2; +}; + +struct ctmu_key { + u8 init; + u8 softoff_mode; + u8 slide_dir; + u8 click_cnt[LP_CTMU_CHANNEL_SIZE]; + u8 last_key[LP_CTMU_CHANNEL_SIZE]; + u16 short_timer[LP_CTMU_CHANNEL_SIZE]; + + u8 key_ch_msg_lock; + u16 key_ch_msg_lock_timer; + + u8 eartch_inear_ok; + u8 eartch_last_state; + u8 eartch_trim_flag; + u16 eartch_trim_value; + + const struct lp_touch_key_platform_data *config; +}; + +extern struct ctmu_key _ctmu_key; + + +void lp_touch_key_init(const struct lp_touch_key_platform_data *config); + +u8 lp_touch_key_power_on_status(); + +void lp_touch_key_disable(void); + +void lp_touch_key_enable(void); + +u8 lp_touch_key_alog_range_display(u8 *display_buf); + +void lp_touch_key_send_cmd(enum CTMU_M2P_CMD cmd); + +void set_lpkey_active(u8 set); + +u8 lp_touch_key_alog_range_display(u8 *display_buf); + +#endif /* #ifndef _LP_TOUCH_KEY_API_ */ diff --git a/include_lib/driver/cpu/br28/asm/lp_touch_key_hw.h b/include_lib/driver/cpu/br28/asm/lp_touch_key_hw.h new file mode 100644 index 0000000..f862501 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/lp_touch_key_hw.h @@ -0,0 +1,148 @@ +#ifndef _LP_TOUCH_KEY_HW_H_ +#define _LP_TOUCH_KEY_HW_H_ + +/**************************************************************P11 通讯定义*****************************************************************/ + +enum CTMU_P2M_EVENT { + CTMU_P2M_CH0_RES_EVENT = 0x50, + CTMU_P2M_CH0_SHORT_KEY_EVENT, + CTMU_P2M_CH0_LONG_KEY_EVENT, + CTMU_P2M_CH0_HOLD_KEY_EVENT, + CTMU_P2M_CH0_FALLING_EVENT, + CTMU_P2M_CH0_RAISING_EVENT, + + CTMU_P2M_CH1_RES_EVENT = 0x58, + CTMU_P2M_CH1_SHORT_KEY_EVENT, + CTMU_P2M_CH1_LONG_KEY_EVENT, + CTMU_P2M_CH1_HOLD_KEY_EVENT, + CTMU_P2M_CH1_FALLING_EVENT, + CTMU_P2M_CH1_RAISING_EVENT, + + CTMU_P2M_CH2_RES_EVENT = 0x60, + CTMU_P2M_CH2_SHORT_KEY_EVENT, + CTMU_P2M_CH2_LONG_KEY_EVENT, + CTMU_P2M_CH2_HOLD_KEY_EVENT, + CTMU_P2M_CH2_FALLING_EVENT, + CTMU_P2M_CH2_RAISING_EVENT, + + CTMU_P2M_CH3_RES_EVENT = 0x68, + CTMU_P2M_CH3_SHORT_KEY_EVENT, + CTMU_P2M_CH3_LONG_KEY_EVENT, + CTMU_P2M_CH3_HOLD_KEY_EVENT, + CTMU_P2M_CH3_FALLING_EVENT, + CTMU_P2M_CH3_RAISING_EVENT, + + CTMU_P2M_CH4_RES_EVENT = 0x70, + CTMU_P2M_CH4_SHORT_KEY_EVENT, + CTMU_P2M_CH4_LONG_KEY_EVENT, + CTMU_P2M_CH4_HOLD_KEY_EVENT, + CTMU_P2M_CH4_FALLING_EVENT, + CTMU_P2M_CH4_RAISING_EVENT, + + CTMU_P2M_EARTCH_IN_EVENT = 0x78, + CTMU_P2M_EARTCH_OUT_EVENT, +}; + +enum CTMU_M2P_CMD { + CTMU_M2P_INIT = 0x50, + CTMU_M2P_DISABLE, //模块关闭 + CTMU_M2P_ENABLE, //模块使能 + CTMU_M2P_CH0_ENABLE, //通道0打开 + CTMU_M2P_CH0_DISABLE, //通道0关闭 + CTMU_M2P_CH1_ENABLE, //通道1打开 + CTMU_M2P_CH1_DISABLE, //通道1关闭 + CTMU_M2P_CH2_ENABLE, //通道2打开 + CTMU_M2P_CH2_DISABLE, //通道2关闭 + CTMU_M2P_CH3_ENABLE, //通道3打开 + CTMU_M2P_CH3_DISABLE, //通道3关闭 + CTMU_M2P_CH4_ENABLE, //通道4打开 + CTMU_M2P_CH4_DISABLE, //通道4关闭 + CTMU_M2P_UPDATE_BASE_TIME, //更新时基参数 + CTMU_M2P_CHARGE_ENTER_MODE, //进仓充电模式 + CTMU_M2P_CHARGE_EXIT_MODE, //退出充电模式 + CTMU_M2P_RESET_ALGO, //单独复位触摸算法 +}; + +///////////////////////////////////////////////// +// P11: P2M_MESSAGE_CTMU_WKUP_MSG +// MSYS: P2M_CTMU_CTMU_WKUP_MSG +// 消息列表 +// 作用: 与主系统同步消息, 缓解异步问题 +///////////////////////////////////////////////// +#define P2M_MESSAGE_POWER_ON_FLAG BIT(0) //lpctmu长按开机标志, 0: 非长按开机, 1: 长按开机, P11/MSYS清0, P11置位, 主系统查询 +#define P2M_MESSAGE_SYNC_FLAG BIT(1) //主系统清0, P11置位, 主系统查询置位, 解决异步问题 +#define P2M_MESSAGE_KEY_ACTIVE_FLAG BIT(2) //lpctmu按键状态, 1: 按键按下, 0: 按键抬起, P11清0, P11置位, 主系统查询 +#define P2M_MESSAGE_INIT_MODE_FLAG BIT(3) //lpctmu初始化模式, 0: 普通初始化(复位硬件,复位算法,初始化定时器), 1: 连续工作初始化(恢复定时器工作), 主系统清0, 主系统置位, P11查询 +#define P2M_MESSAGE_RESET_ALGO_FLAG BIT(4) //主系统清0, P11置位, 主系统查询置位,用于内置触摸算法的复位 + + +//=======================================================================// +// LPCTMU ANA0 // +//=======================================================================// +//------------------- 上限电压配置: P11_LPCTM->ANA0[7:6] +/* +上限电压表: + 0: 0.65V + 1: 0.70V + 2: 0.75V + 3: 0.80V +*/ +enum LPCTM_VH_TABLE { + LPCTMU_VH_065V = (0 << 6), + LPCTMU_VH_070V = (1 << 6), + LPCTMU_VH_075V = (2 << 6), + LPCTMU_VH_080V = (3 << 6), +}; + +//------------------- 下限电压配置: P11_LPCTM->ANA0[5:4] +/* +下限电压表: + 0: 0.20V + 1: 0.25V + 2: 0.30V + 3: 0.35V +*/ +enum LPCTM_VL_TABLE { + LPCTMU_VL_020V = (0 << 4), + LPCTMU_VL_025V = (1 << 4), + LPCTMU_VL_030V = (2 << 4), + LPCTMU_VL_035V = (3 << 4), +}; + +//------------------- 充放电电流配置: P11_LPCTM->ANA0[3:1] +/* +充放电电流表: + 0: 3.6 uA + 1: 7.2 uA + 2: 10.8 uA + 3: 14.4 uA + 4: 18.2 uA + 5: 21.6 uA + 6: 25.2 uA + 7: 28.8 uA +*/ +enum LPCTM_ISEL_TABLE { + LPCTMU_ISEL_036UA = (0 << 1), + LPCTMU_ISEL_072UA = (1 << 1), + LPCTMU_ISEL_108UA = (2 << 1), + LPCTMU_ISEL_144UA = (3 << 1), + LPCTMU_ISEL_180UA = (4 << 1), + LPCTMU_ISEL_216UA = (5 << 1), + LPCTMU_ISEL_252UA = (6 << 1), + LPCTMU_ISEL_288UA = (7 << 1) +}; + +u8 get_lpctmu_ana_level(void); + +#define LPCTMU_ANA0_CONFIG(x) (P11_LPCTM->ANA0 = x) + +/**********************************************************算法流程配置**********************************************************************************/ +#define CTMU_SAMPLE_RATE_PRD 20 //kick start采样周期, 单位: ms + +#define CTMU_SHORT_CLICK_DELAY_TIME 400 //单击事件后等待下一次单击时间(ms) +#define CTMU_HOLD_CLICK_DELAY_TIME 200 //long事件产生后, 发hold事件间隔(ms) +#define CTMU_LONG_KEY_DELAY_TIME 2000 //从按下到产生long事件的时间(ms) + +#endif /* #ifndef _LP_TOUCH_KEY_HW_H_ */ + + diff --git a/include_lib/driver/cpu/br28/asm/lp_touch_key_tool.h b/include_lib/driver/cpu/br28/asm/lp_touch_key_tool.h new file mode 100644 index 0000000..72459da --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/lp_touch_key_tool.h @@ -0,0 +1,29 @@ +#ifndef __LP_TOUCH_KEY_TOOL__ +#define __LP_TOUCH_KEY_TOOL__ + +#include "typedef.h" + + +enum { + BT_KEY_CH_RES_MSG, + BT_EARTCH_RES_MSG, + BT_EVENT_HW_MSG, + BT_EVENT_SW_MSG, + BT_EVENT_VDDIO, +}; + +//tws +void lpctmu_tws_send_event_data(int msg, int type); +void lpctmu_tws_send_res_data(int data1, int data2, int data3, int data4, int data5, int type); + +//spp +int lp_touch_key_online_debug_init(void); +int lp_touch_key_online_debug_send(u8 ch, u16 val); +int lp_touch_key_online_debug_key_event_handle(u8 ch_index, struct sys_event *event); + +//testbox +u8 lp_touch_key_testbox_remote_test(u8 ch, u8 event); +void lp_touch_key_testbox_inear_trim(u8 flag); + +#endif + diff --git a/include_lib/driver/cpu/br28/asm/mcpwm.h b/include_lib/driver/cpu/br28/asm/mcpwm.h new file mode 100644 index 0000000..b28fb49 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/mcpwm.h @@ -0,0 +1,74 @@ +#ifndef _MCPWM_H_ +#define _MCPWM_H_ + + +#include "typedef.h" + + +/* 对齐方式选择 */ +typedef enum { + pwm_edge_aligned, ///< 边沿对齐模式 + pwm_center_aligned, ///< 中心对齐模式 +} pwm_aligned_mode_type; + +/* pwm通道选择 */ +typedef enum { + pwm_ch0, + pwm_ch1, + pwm_ch2, + pwm_ch3, + pwm_ch_max, +} pwm_ch_num_type; + +/* MCPWM TIMER寄存器 */ +typedef struct _pwm_timer_reg { + volatile u32 tmr_con; + volatile u32 tmr_cnt; + volatile u32 tmr_pr; +} PWM_TIMER_REG; + +/* MCPWM通道寄存器 */ +typedef struct _pwm_ch_reg { + volatile u32 ch_con0; + volatile u32 ch_con1; + volatile u32 ch_cmph; + volatile u32 ch_cmpl; +} PWM_CH_REG; + +/* 初始化要用的参数结构体 */ +struct pwm_platform_data { + pwm_aligned_mode_type pwm_aligned_mode; ///< PWM对齐方式选择 + pwm_ch_num_type pwm_ch_num; ///< 选择pwm通道号 + u32 frequency; ///< 初始共同频率,CH0, CH, CH2,,,,,, + u16 duty; ///< 初始占空比,0~10000 对应 0%~100% 。每个通道可以有不同的占空比。互补模式的占空比体现在高引脚的波形上。 + u8 h_pin; ///< 一个通道的H引脚。 + u8 l_pin; ///< 一个通道的L引脚,不需要则填-1 + u8 complementary_en; ///< 该通道的两个引脚输出的波形。0: 同步, 1: 互补,互补波形的占空比体现在H引脚上 +}; + + + +void mcpwm_set_frequency(pwm_ch_num_type ch, pwm_aligned_mode_type align, u32 frequency); +void mcpwm_set_duty(pwm_ch_num_type pwm_ch, u16 duty); +void mctimer_ch_open_or_close(pwm_ch_num_type pwm_ch, u8 enable); +void mcpwm_ch_open_or_close(pwm_ch_num_type pwm_ch, u8 enable); +void mcpwm_open(pwm_ch_num_type pwm_ch); +void mcpwm_close(pwm_ch_num_type pwm_ch); +void mcpwm_init(struct pwm_platform_data *arg); +void mcpwm_test(void); + + +void set_io_ext_interrupt_cbfun(void (*cbfun)(u8 index)); +void io_ext_interrupt_init(u8 index, u8 port, u8 trigger_mode); +void io_ext_interrupt_close(u8 index, u8 port); +void io_ext_interrupt_test(void); + + +void timer_pwm_init(JL_TIMER_TypeDef *JL_TIMERx, u32 pwm_io, u32 fre, u32 duty); +void set_timer_pwm_duty(JL_TIMER_TypeDef *JL_TIMERx, u32 duty); +void timer_pwm_test(void); + + +#endif + + diff --git a/include_lib/driver/cpu/br28/asm/plcnt.h b/include_lib/driver/cpu/br28/asm/plcnt.h new file mode 100644 index 0000000..23b4cf0 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/plcnt.h @@ -0,0 +1,29 @@ +#ifndef _PLCNT_DRV_H_ +#define _PLCNT_DRV_H_ + + +#define PLCNT_KEY_CH_MAX 3 + +struct touch_key_port { + u16 press_delta; //按下判决的阈值 + u8 port; //触摸按键IO + u8 key_value; //按键返回值 +}; + +struct touch_key_platform_data { + u8 num; //触摸按键个数 + const struct touch_key_port *port_list; +}; + + +/* =========== pclcnt API ============= */ +//plcnt 初始化 +int plcnt_init(void *_data); + +//获取plcnt按键状态 +u8 get_plcnt_value(void); + + +#endif /* _PLCNT_DRV_H_ */ + + diff --git a/include_lib/driver/cpu/br28/asm/power/lp_ipc.h b/include_lib/driver/cpu/br28/asm/power/lp_ipc.h new file mode 100644 index 0000000..112c587 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/power/lp_ipc.h @@ -0,0 +1,256 @@ +#ifndef __LP_IPC_H__ +#define __LP_IPC_H__ + +//=================================消息格式======================================== + +//消息buf大小 +#define MAX_POOL 128 + +//消息类型 +#define NO_MSG 0xff + +//获取消息返回值 +enum { + MSG_NO_ERROR = 0, + MSG_NO_MSG = 0, + MSG_EVENT_EXIST = -1, + MSG_NOT_EVENT = -2, + MSG_EVENT_PARAM_ERROR = -3, + MSG_BUF_NOT_ENOUGH = -4, + MSG_CBUF_ERROR = -5, +}; + +//消息头格式 +#define MSG_HEADER_BYTE_LEN 3 +#define MSG_HEADER_BIT_LEN (MSG_HEADER_BYTE_LEN*8) +#define MSG_HEADER_ALL_BIT ((1L<PWR_CON + +/* + *------------------- P11_CLOCK->CLK_CON + */ + +#define P11_CLK_CON0 P11_CLOCK->CLK_CON0 +enum P11_SYS_CLK_TABLE { + P11_SYS_CLK_RC250K = 0, + P11_SYS_CLK_RC16M, + P11_SYS_CLK_LRC_OSC, + P11_SYS_CLK_BTOSC_24M, + P11_SYS_CLK_BTOSC_48M, + P11_SYS_CLK_PLL_SYS_CLK, + P11_SYS_CLK_CLK_X2, +}; +//#define P11_SYS_CLK_SEL(x) SFR(P11_CLOCK->CLK_CON0, 0, 3, x) +#define P11_SYS_CLK_SEL(x) (P11_CLOCK->CLK_CON0 = x) + + +//p11 btosc use d2sh +#define CLOCK_KEEP(en) \ + if(en){ \ + P11_CLOCK->CLK_CON1 &= ~(3<<15); \ + P11_CLOCK->CLK_CON1 |= BIT(14); \ + P11_CLOCK->CLK_CON1 |= (2<<15); \ + }else{ \ + P11_CLOCK->CLK_CON1 &= ~(3<<15); \ + P11_CLOCK->CLK_CON1 &= ~BIT(14); \ + } + +#define P11_P2M_CLK_CON0 P11_SYSTEM->P2M_CLK_CON0 +#define P11_SYSTEM_CON0 P11_SYSTEM->P11_SYS_CON0 +#define P11_SYSTEM_CON1 P11_SYSTEM->P11_SYS_CON1 +#define P11_P11_SYS_CON0 P11_SYSTEM_CON0 +#define P11_P11_SYS_CON1 P11_SYSTEM_CON1 +#define P11_RST_SRC P11_CLOCK->RST_SRC + +#define LED_CLK_SEL(x) P11_SYSTEM->P2M_CLK_CON0 = ((P11_SYSTEM->P2M_CLK_CON0 & ~0xe0) | (x) << 5) +#define GET_LED_CLK_SEL(x) (P11_SYSTEM->P2M_CLK_CON0 & 0xe0) + +#define P11_WDT_CON P11_WDT->CON + +#define P11_P2M_INT_IE P11_SYSTEM->P2M_INT_IE +#define P11_M2P_INT_IE P11_SYSTEM->M2P_INT_IE +#define P11_M2P_INT_SET P11_SYSTEM->M2P_INT_SET +#define P11_P2M_INT_SET P11_SYSTEM->P2M_INT_SET +#define P11_P2M_INT_CLR P11_SYSTEM->P2M_INT_CLR +#define P11_P2M_INT_PND P11_SYSTEM->P2M_INT_PND //? +#define P11_M2P_INT_PND P11_SYSTEM->M2P_INT_PND //? + +#define P11_TMR0_CON0 P11_LPTMR0->CON0 +#define P11_TMR0_CON1 P11_LPTMR0->CON1 +#define P11_TMR0_CON2 P11_LPTMR0->CON2 +#define P11_TMR0_CNT P11_LPTMR0->CNT +#define P11_TMR0_PRD P11_LPTMR0->PRD +#define P11_TMR0_RSC P11_LPTMR0->RSC + +#define P11_TMR1_CON0 P11_LPTMR1->CON0 +#define P11_TMR1_CON1 P11_LPTMR1->CON1 +#define P11_TMR1_CON2 P11_LPTMR1->CON2 +#define P11_TMR1_CNT P11_LPTMR1->CNT +#define P11_TMR1_PRD P11_LPTMR1->PRD +#define P11_TMR1_RSC P11_LPTMR1->RSC + +#define P11_TMR2_CON0 P11_LPTMR2->CON0 +#define P11_TMR2_CON1 P11_LPTMR2->CON1 +#define P11_TMR2_CON2 P11_LPTMR2->CON2 +#define P11_TMR2_CNT P11_LPTMR2->CNT +#define P11_TMR2_PRD P11_LPTMR2->PRD +#define P11_TMR2_RSC P11_LPTMR2->RSC + +#define P11_TMR3_CON0 P11_LPTMR3->CON0 +#define P11_TMR3_CON1 P11_LPTMR3->CON1 +#define P11_TMR3_CON2 P11_LPTMR3->CON2 +#define P11_TMR3_CNT P11_LPTMR3->CNT +#define P11_TMR3_PRD P11_LPTMR3->PRD +#define P11_TMR3_RSC P11_LPTMR3->RSC + +#define GET_P11_SYS_RST_SRC() P11_RST_SRC + +#define LP_PWR_IDLE(x) SFR(P11_PWR_CON, 0, 1, x) +#define LP_PWR_STANDBY(x) SFR(P11_PWR_CON, 1, 1, x) +#define LP_PWR_SLEEP(x) SFR(P11_PWR_CON, 2, 1, x) +#define LP_PWR_SSMODE(x) SFR(P11_PWR_CON, 3, 1, x) +#define LP_PWR_SOFT_RESET(x) SFR(P11_PWR_CON, 4, 1, x) +#define LP_PWR_INIT_FLAG() (P11_PWR_CON & BIT(5)) +#define LP_PWR_RST_FLAG_CLR(x) SFR(P11_PWR_CON, 6, 1, x) +#define LP_PWR_RST_FLAG() (P11_PWR_CON & BIT(7)) + +#define P33_TEST_ENABLE() P11_P11_SYS_CON0 |= BIT(5) +#define P33_TEST_DISABLE() P11_P11_SYS_CON0 &= ~BIT(5) + +#define P11_TX_DISABLE(x) P11_SYSTEM->P11_SYS_CON1 |= BIT(2) +#define P11_TX_ENABLE(x) P11_SYSTEM->P11_SYS_CON1 &= ~BIT(2) + +#define MSYS_IO_LATCH_ENABLE() P11_SYSTEM->P11_SYS_CON1 |= BIT(7) +#define MSYS_IO_LATCH_DISABLE() P11_SYSTEM->P11_SYS_CON1 &= ~BIT(7) + +#define LP_TMR0_EN(x) SFR(P11_TMR0_CON0, 0, 1, x) +#define LP_TMR0_CTU(x) SFR(P11_TMR0_CON0, 1, 1, x) +#define LP_TMR0_P11_WKUP_IE(x) SFR(P11_TMR0_CON0, 2, 1, x) +#define LP_TMR0_P11_TO_IE(x) SFR(P11_TMR0_CON0, 3, 1, x) +#define LP_TMR0_CLR_P11_WKUP(x) SFR(P11_TMR0_CON0, 4, 1, x) +#define LP_TMR0_P11_WKUP(x) (P11_TMR0_CON0 & BIT(5)) +#define LP_TMR0_CLR_P11_TO(x) SFR(P11_TMR0_CON0, 6, 1, x) +#define LP_TMR0_P11_TO(x) (P11_TMR0_CON0 & BIT(7)) + +#define LP_TMR0_SW_KICK_START_EN(x) SFR(P11_TMR0_CON1, 0, 1, x) +#define LP_TMR0_HW_KICK_START_EN(x) SFR(P11_TMR0_CON1, 1, 1, x) +#define LP_TMR0_WKUP_IE(x) SFR(P11_TMR0_CON1, 2, 1, x) +#define LP_TMR0_TO_IE(x) SFR(P11_TMR0_CON1, 3, 1, x) +#define LP_TMR0_CLR_MSYS_WKUP(x) SFR(P11_TMR0_CON1, 4, 1, x) +#define LP_TMR0_MSYS_WKUP(x) (P11_TMR0_CON1 & BIT(5)) +#define LP_TMR0_CLR_MSYS_TO(x) SFR(P11_TMR0_CON1, 6, 1, x) +#define LP_TMR0_MSYS_TO(x) (P11_TMR0_CON1 & BIT(7)) + +#define LP_TMR0_CLK_SEL(x) SFR(P11_TMR0_CON2, 0, 4, x) +#define LP_TMR0_CLK_DIV(x) SFR(P11_TMR0_CON2, 4, 4, x) +#define LP_TMR0_KST(x) SFR(P11_TMR0_CON2, 8, 1, x) +#define LP_TMR0_RUN() (P11_TMR0_CON2 & BIT(9)) + +#define P11_M2P_RESET_MASK(x) SFR(P11_P11_SYS_CON1 , 4, 1, x) + +//MEM_PWR_CON +#define MEM_PWR_CPU_CON BIT(0) +#define MEM_PWR_RAM0_RAM3_CON BIT(1) +#define MEM_PWR_RAM4_RAM5_CON BIT(2) +#define MEM_PWR_RAM6_RAM7_CON BIT(3) +#define MEM_PWR_RAM8_RAM9_CON BIT(4) +#define MEM_PWR_PERIPH_CON BIT(5) + +#define MEM_PWR_RAM_SET(a) (((1 << a) - 1) - 1) + +#define LRC_Hz_DEFAULT (200 * 1000L) + +#define LRC_CON0_INIT \ + /* */ (0 << 7) |\ + /* */ (0 << 6) |\ + /*RC32K_RPPS_S1_33v */ (1 << 5) |\ + /*RC32K_RPPS_S0_33v */ (0 << 4) |\ + /* */ (0 << 3) |\ + /* */ (0 << 2) |\ + /*RC32K_RN_TRIM_33v */ (0 << 1) |\ + /*RC32K_EN_33v */ (1 << 0) + +#define LRC_CON1_INIT \ + /* */ (0 << 7) |\ + /*RC32K_CAP_S2_33v */ (1 << 6) |\ + /*RC32K_CAP_S1_33v */ (0 << 5) |\ + /*RC32K_CAP_S0_33v */ (0 << 4) |\ + /* 2bit */ (0 << 2) |\ + /*RC32K_RNPS_S1_33v */ (0 << 1) |\ + /*RC32K_RNPS_S0_33v */ (1 << 0) + +void wdt_isr(void); +u8 p11_run_query(void); + +#endif /* #ifndef __P11_APP_H__ */ + + diff --git a/include_lib/driver/cpu/br28/asm/power/p11_csfr.h b/include_lib/driver/cpu/br28/asm/power/p11_csfr.h new file mode 100644 index 0000000..8a3e39c --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/power/p11_csfr.h @@ -0,0 +1,176 @@ +//*********************************************************************************// +// Module name : csfr.h // +// Description : q32small core sfr define // +// By Designer : zequan_liu // +// Dat changed : // +//*********************************************************************************// + +#ifndef __P11_Q32S_CSFR__ +#define __P11_Q32S_CSFR__ + +#define __RW volatile // read write +#define __RO volatile const // only read +#define __WO volatile // only write + +#define __u8 unsigned int // u8 to u32 special for struct +#define __u16 unsigned int // u16 to u32 special for struct +#define __u32 unsigned int + +//---------------------------------------------// +// q32small define +//---------------------------------------------// + +#ifdef PMU_SYSTEM +#define p11_q32s_sfr_base 0x00a000 +#define p11_q32s_sfr_offset 0x000000 // multi_core used +#else +#define p11_q32s_sfr_base 0xf2a000 +#define p11_q32s_sfr_offset 0x000000 // multi_core used +#endif + +#define p11_q32s_cpu_base (p11_q32s_sfr_base + 0x00) +#define p11_q32s_mpu_base (p11_q32s_sfr_base + 0x80) + +#define p11_q32s(n) ((JL_TypeDef_p11_q32s *)(p11_q32s_sfr_base + p11_q32s_sfr_offset*n)) +#define p11_q32s_mpu(n) ((JL_TypeDef_p11_q32s_MPU *)(p11_q32s_mpu_base + p11_q32s_sfr_offset*n)) + +//---------------------------------------------// +// q32small core sfr +//---------------------------------------------// + +typedef struct { + /* 00 */ __RO __u32 DR00; + /* 01 */ __RO __u32 DR01; + /* 02 */ __RO __u32 DR02; + /* 03 */ __RO __u32 DR03; + /* 04 */ __RO __u32 DR04; + /* 05 */ __RO __u32 DR05; + /* 06 */ __RO __u32 DR06; + /* 07 */ __RO __u32 DR07; + /* 08 */ __RO __u32 DR08; + /* 09 */ __RO __u32 DR09; + /* 0a */ __RO __u32 DR10; + /* 0b */ __RO __u32 DR11; + /* 0c */ __RO __u32 DR12; + /* 0d */ __RO __u32 DR13; + /* 0e */ __RO __u32 DR14; + /* 0f */ __RO __u32 DR15; + + /* 10 */ __RO __u32 RETI; + /* 11 */ __RO __u32 RETE; + /* 12 */ __RO __u32 RETX; + /* 13 */ __RO __u32 RETS; + /* 14 */ __RO __u32 SR04; + /* 15 */ __RO __u32 PSR; + /* 16 */ __RO __u32 CNUM; + /* 17 */ __RO __u32 SR07; + /* 18 */ __RO __u32 SR08; + /* 19 */ __RO __u32 SR09; + /* 1a */ __RO __u32 SR10; + /* 1b */ __RO __u32 ICFG; + /* 1c */ __RO __u32 USP; + /* 1d */ __RO __u32 SSP; + /* 1e */ __RO __u32 SP; + /* 1f */ __RO __u32 PCRS; + + /* 20 */ __RW __u32 BPCON; + /* 21 */ __RW __u32 BSP; + /* 22 */ __RW __u32 BP0; + /* 23 */ __RW __u32 BP1; + /* 24 */ __RW __u32 BP2; + /* 25 */ __RW __u32 BP3; + /* 26 */ __WO __u32 CMD_PAUSE; + /* */ __RO __u32 REV_30_26[0x30 - 0x26 - 1]; + + /* 30 */ __RW __u32 PMU_CON; + /* */ __RO __u32 REV_3b_30[0x3b - 0x30 - 1]; + /* 3b */ __RW __u8 TTMR_CON; + /* 3c */ __RW __u32 TTMR_CNT; + /* 3d */ __RW __u32 TTMR_PRD; + /* 3e */ __RW __u32 BANK_CON; + /* 3f */ __RW __u32 BANK_NUM; + + /* 40 */ __RW __u32 ICFG00; + /* 41 */ __RW __u32 ICFG01; + /* 42 */ __RW __u32 ICFG02; + /* 43 */ __RW __u32 ICFG03; + /* 44 */ __RW __u32 ICFG04; + /* 45 */ __RW __u32 ICFG05; + /* 46 */ __RW __u32 ICFG06; + /* 47 */ __RW __u32 ICFG07; + /* 48 */ __RW __u32 ICFG08; + /* 49 */ __RW __u32 ICFG09; + /* 4a */ __RW __u32 ICFG10; + /* 4b */ __RW __u32 ICFG11; + /* 4c */ __RW __u32 ICFG12; + /* 4d */ __RW __u32 ICFG13; + /* 4e */ __RW __u32 ICFG14; + /* 4f */ __RW __u32 ICFG15; + + /* 50 */ __RW __u32 ICFG16; + /* 51 */ __RW __u32 ICFG17; + /* 52 */ __RW __u32 ICFG18; + /* 53 */ __RW __u32 ICFG19; + /* 54 */ __RW __u32 ICFG20; + /* 55 */ __RW __u32 ICFG21; + /* 56 */ __RW __u32 ICFG22; + /* 57 */ __RW __u32 ICFG23; + /* 58 */ __RW __u32 ICFG24; + /* 59 */ __RW __u32 ICFG25; + /* 5a */ __RW __u32 ICFG26; + /* 5b */ __RW __u32 ICFG27; + /* 5c */ __RW __u32 ICFG28; + /* 5d */ __RW __u32 ICFG29; + /* 5e */ __RW __u32 ICFG30; + /* 5f */ __RW __u32 ICFG31; + + /* 60 */ __RO __u32 IPND0; + /* 61 */ __RO __u32 IPND1; + /* 62 */ __RO __u32 IPND2; + /* 63 */ __RO __u32 IPND3; + /* 64 */ __RO __u32 IPND4; + /* 65 */ __RO __u32 IPND5; + /* 66 */ __RO __u32 IPND6; + /* 67 */ __RO __u32 IPND7; + /* 68 */ __WO __u32 ILAT_SET; + /* 69 */ __WO __u32 ILAT_CLR; + /* 6a */ __RW __u32 IPMASK; + /* 6b */ __RW __u32 GIEMASK; + /* 6c */ __RW __u32 IWKUP_NUM; + /* */ __RO __u32 REV_70_6c[0x70 - 0x6c - 1]; + + /* 70 */ __RW __u32 ETM_CON; + /* 71 */ __RO __u32 ETM_PC0; + /* 72 */ __RO __u32 ETM_PC1; + /* 73 */ __RO __u32 ETM_PC2; + /* 74 */ __RO __u32 ETM_PC3; + /* 75 */ __RW __u32 WP0_ADRH; + /* 76 */ __RW __u32 WP0_ADRL; + /* 77 */ __RW __u32 WP0_DATH; + /* 78 */ __RW __u32 WP0_DATL; + /* 79 */ __RW __u32 WP0_PC; + + /* */ __RO __u32 REV_80_79[0x80 - 0x79 - 1]; + /* 80 */ __RW __u32 EMU_CON; + /* 81 */ __RW __u32 EMU_MSG; + /* 82 */ __RO __u32 EMU_SSP_H; + /* 83 */ __RO __u32 EMU_SSP_L; + /* 84 */ __RO __u32 EMU_USP_H; + /* 85 */ __RO __u32 EMU_USP_L; +} JL_TypeDef_p11_q32s; + +#undef __RW +#undef __RO +#undef __WO + +#undef __u8 +#undef __u16 +#undef __u32 + +#endif + +//*********************************************************************************// +// // +// end of this module // +// // +//*********************************************************************************// diff --git a/include_lib/driver/cpu/br28/asm/power/p11_io_imap.h b/include_lib/driver/cpu/br28/asm/power/p11_io_imap.h new file mode 100644 index 0000000..b8ff636 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/power/p11_io_imap.h @@ -0,0 +1,38 @@ + + +//===============================================================================// +// +// input IO define +// +//===============================================================================// +#define P11_PB0_IN 1 +#define P11_PB1_IN 2 +#define P11_PB2_IN 3 +#define P11_PB3_IN 4 +#define P11_PB4_IN 5 +#define P11_PB5_IN 6 +#define P11_PB6_IN 7 +#define P11_PB7_IN 8 +#define P11_PB8_IN 9 +#define P11_PB9_IN 10 +#define P11_PB10_IN 11 +#define P11_PB11_IN 12 + +//===============================================================================// +// +// function input select sfr +// +//===============================================================================// +typedef struct { + __RW __u8 P11_FI_GP_ICH0; + __RW __u8 P11_FI_GP_ICH1; + __RW __u8 P11_FI_GP_ICH2; + __RW __u8 P11_FI_UART0_RX; + __RW __u8 P11_FI_SPI_DI; + __RW __u8 P11_FI_IIC_SCL; + __RW __u8 P11_FI_IIC_SDA; + __RW __u8 P11_FI_DMIC_DAT; +} P11_IMAP_TypeDef; + +#define P11_IMAP_BASE (p11_sfr_base + map_adr(0x16, 0x00)) +#define P11_IMAP ((P11_IMAP_TypeDef *)P11_IMAP_BASE) diff --git a/include_lib/driver/cpu/br28/asm/power/p11_io_omap.h b/include_lib/driver/cpu/br28/asm/power/p11_io_omap.h new file mode 100644 index 0000000..38021fb --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/power/p11_io_omap.h @@ -0,0 +1,40 @@ + + +//===============================================================================// +// +// output function define +// +//===============================================================================// +#define P11_FO_GP_OCH0 ((0 << 2)|BIT(1)) +#define P11_FO_GP_OCH1 ((1 << 2)|BIT(1)) +#define P11_FO_GP_OCH2 ((2 << 2)|BIT(1)) +#define P11_FO_UART0_TX ((3 << 2)|BIT(1)|BIT(0)) +#define P11_FO_UART1_TX ((4 << 2)|BIT(1)|BIT(0)) +#define P11_FO_SPI_CLK ((5 << 2)|BIT(1)|BIT(0)) +#define P11_FO_SPI_DO ((6 << 2)|BIT(1)|BIT(0)) +#define P11_FO_IIC_SCL ((7 << 2)|BIT(1)|BIT(0)) +#define P11_FO_IIC_SDA ((8 << 2)|BIT(1)|BIT(0)) +#define P11_FO_DMIC_CLK ((9 << 2)|BIT(1)|BIT(0)) + +//===============================================================================// +// +// IO output select sfr +// +//===============================================================================// +typedef struct { + __RW __u8 P11_PB0_OUT; + __RW __u8 P11_PB1_OUT; + __RW __u8 P11_PB2_OUT; + __RW __u8 P11_PB3_OUT; + __RW __u8 P11_PB4_OUT; + __RW __u8 P11_PB5_OUT; + __RW __u8 P11_PB6_OUT; + __RW __u8 P11_PB7_OUT; + __RW __u8 P11_PB8_OUT; + __RW __u8 P11_PB9_OUT; + __RW __u8 P11_PB10_OUT; + __RW __u8 P11_PB11_OUT; +} P11_OMAP_TypeDef; + +#define P11_OMAP_BASE (p11_sfr_base + map_adr(0x15, 0x00)) +#define P11_OMAP ((P11_OMAP_TypeDef *)P11_OMAP_BASE) diff --git a/include_lib/driver/cpu/br28/asm/power/p11_sfr.h b/include_lib/driver/cpu/br28/asm/power/p11_sfr.h new file mode 100644 index 0000000..7339659 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/power/p11_sfr.h @@ -0,0 +1,244 @@ +#ifndef __P11__ +#define __P11__ + +//===============================================================================// +// +// sfr define +// +//===============================================================================// + +#ifdef PMU_SYSTEM +#define p11_base 0x000000 +#define p11_ram_base p11_base +#define p11_sfr_base 0x00a000 +#else +#define p11_base 0xf20000 +#define p11_ram_base p11_base +#define p11_sfr_base 0xf2a000 +#endif + +#define __RW volatile // read write +#define __RO volatile const // only read +#define __WO volatile // only write + +#define __u8 unsigned int // u8 to u32 special for struct +#define __u16 unsigned int // u16 to u32 special for struct +#define __u32 unsigned int + +#define __s8(x) char(x); char(reserved_1_##x); char(reserved_2_##x); char(reserved_3_##x) +#define __s16(x) short(x); short(reserved_1_##x) +#define __s32(x) int(x) + +#define map_adr(grp, adr) ((64 * grp + adr) * 4) // grp(0x0-0xff), adr(0x0-0x3f) +#define P11_ACCESS(x) (*(volatile u32 *)(p11_base + x)) +#define P11_RAM(x) (*(volatile u32 *)(p11_ram_base + x)) + +//===============================================================================// +// +// sfr address define +// +//===============================================================================// + +//............. 0x0000 - 0x03ff............ for cpu + +// #include ../core/csfr.h + +//............. 0x0400 - 0x04ff............ for clock +typedef struct { + __RW __u32 PWR_CON; + __RW __u32 RST_SRC; + __RW __u32 WKUP_EN; + __RW __u32 WKUP_SRC; + __RW __u32 SYS_DIV; + __RW __u32 CLK_CON0; + __RW __u32 CLK_CON1; + __RW __u32 CLK_CON2; + __RW __u32 CLK_CON3; +} P11_CLOCK_TypeDef; + +#define P11_CLOCK_BASE (p11_sfr_base + map_adr(0x04, 0x00)) +#define P11_CLOCK ((P11_CLOCK_TypeDef *)P11_CLOCK_BASE) + +//............. 0x0500 - 0x05ff............ for memory control +typedef struct { + __RW __u32 MPC0; + __RW __u32 MPC1; + __RW __u32 MSC; +} P11_MEM_CTL_TypeDef; + +#define P11_MEM_CTL_BASE (p11_sfr_base + map_adr(0x05, 0x00)) +#define P11_MEM_CTL ((P11_MEM_CTL_TypeDef *)P11_MEM_CTL_BASE) + +//............. 0x0600 - 0x06ff............ for system +typedef struct { + __RW __u32 P2M_INT_IE; + __RW __u32 P2M_INT_SET; + __RW __u32 P2M_INT_CLR; + __RO __u32 P2M_INT_PND; + __RW __u32 P2M_CLK_CON0; + __RW __u32 M2P_INT_IE; + __RW __u32 M2P_INT_SET; + __RW __u32 M2P_INT_CLR; + __RO __u32 M2P_INT_PND; + __RW __u32 P11_SYS_CON0; + __RW __u32 P11_SYS_CON1; + __RW __u32 MEM_PWR_CON; +} P11_SYSTEM_TypeDef; + +#define P11_SYSTEM_BASE (p11_sfr_base + map_adr(0x06, 0x00)) +#define P11_SYSTEM ((P11_SYSTEM_TypeDef *)P11_SYSTEM_BASE) + +//............. 0x0800 - 0x08ff............ for watch dog +typedef struct { + __RW __u32 CON; + __RW __u32 KEY; + __RW __u32 DUMMY; +} P11_WDT_TypeDef; + +#define P11_WDT_BASE (p11_sfr_base + map_adr(0x08, 0x00)) +#define P11_WDT ((P11_WDT_TypeDef *)P11_WDT_BASE) + +//............. 0x0900 - 0x0cff............ for lp timer +typedef struct { + __RW __u32 CON0; + __RW __u32 CON1; + __RW __u32 CON2; + __RW __u32 PRD; + __RW __u32 RSC; + __RO __u32 CNT; +} P11_LPTMR_TypeDef; + +#define P11_LPTMR0_BASE (p11_sfr_base + map_adr(0x09, 0x00)) +#define P11_LPTMR1_BASE (p11_sfr_base + map_adr(0x0a, 0x00)) +#define P11_LPTMR2_BASE (p11_sfr_base + map_adr(0x0b, 0x00)) +#define P11_LPTMR3_BASE (p11_sfr_base + map_adr(0x0c, 0x00)) + +#define P11_LPTMR0 ((P11_LPTMR_TypeDef *)P11_LPTMR0_BASE) +#define P11_LPTMR1 ((P11_LPTMR_TypeDef *)P11_LPTMR1_BASE) +#define P11_LPTMR2 ((P11_LPTMR_TypeDef *)P11_LPTMR2_BASE) +#define P11_LPTMR3 ((P11_LPTMR_TypeDef *)P11_LPTMR3_BASE) + +//............. 0x0d00 - 0x0dff............ for irflt +typedef struct { + __RW __u32 CON; +} P11_IRFLT_TypeDef; + +#define P11_IRFLT_BASE (p11_sfr_base + map_adr(0x0d, 0x00)) +#define P11_IRFLT ((P11_IRFLT_TypeDef *)P11_IRFLT_BASE) + +//............. 0x0e00 - 0x0eff............ for spi +typedef struct { + __RW __u32 CON; + __WO __u32 BAUD; + __RW __u32 BUF; + //__WO __u32 ADR; + //__WO __u32 CNT; +} P11_SPI_TypeDef; + +#define P11_SPI_BASE (p11_sfr_base + map_adr(0x0e, 0x00)) +#define P11_SPI ((P11_SPI_TypeDef *)P11_SPI_BASE) + +//............. 0x0f00 - 0x10ff............ for uart +typedef struct { + __RW __u16 CON0; + //__RW __u16 CON1; + __WO __u16 BAUD; + __RW __u8 BUF; + __RW __u32 OTCNT; + //__RW __u32 TXADR; + //__WO __u16 TXCNT; + //__RW __u32 RXSADR; + //__RW __u32 RXEADR; + //__RW __u32 RXCNT; + //__RO __u16 HRXCNT; + __RW __u16 CON2; +} P11_UART_TypeDef; + +#define P11_UART0_BASE (p11_sfr_base + map_adr(0x0f, 0x00)) +#define P11_UART1_BASE (p11_sfr_base + map_adr(0x10, 0x00)) + +#define P11_UART0 ((P11_UART_TypeDef *)P11_UART0_BASE) +#define P11_UART1 ((P11_UART_TypeDef *)P11_UART1_BASE) + +//............. 0x1100 - 0x11ff............ for iic +typedef struct { + __RW __u32 CON0; + __RW __u32 CON1; + __RW __u32 BAUD; + __RW __u32 BUF; +} P11_IIC_TypeDef; + +#define P11_IIC_BASE (p11_sfr_base + map_adr(0x11, 0x00)) +#define P11_IIC ((P11_IIC_TypeDef *)P11_IIC_BASE) + +//............. 0x1200 - 0x12ff............ for port +typedef struct { + __RW __u32 OCH_CON0 ; + __RW __u32 ICH_CON0 ; + __RW __u32 P33_PORT ; + __RW __u32 PB_SEL ; + __RW __u32 PB_PU ; + __RW __u32 PB_PD ; + __RW __u32 PB_DIR ; + __RW __u32 PB_DIE ; + __RW __u32 PB_DIEH ; + __RW __u32 PB_OUT ; + __RO __u32 PB_IN ; +} P11_PORT_TypeDef; + +#define P11_PORT_BASE (p11_sfr_base + map_adr(0x12, 0x00)) +#define P11_PORT ((P11_PORT_TypeDef *)P11_PORT_BASE) + +//............. 0x1300 - 0x13ff............ for lp ctmu +typedef struct { + __RW __u32 CON0; + __RW __u32 CON1; + __RW __u32 CON2; + __RW __u32 CON3; + __RW __u32 ANA0; + __RW __u32 ANA1; + __RW __u32 RES; +} P11_LPCTM_TypeDef; + +#define P11_LPCTM_BASE (p11_sfr_base + map_adr(0x13, 0x00)) +#define P11_LPCTM ((P11_LPCTM_TypeDef *)P11_LPCTM_BASE) + +//............. 0x1400 - 0x14ff............ for lpvad +typedef struct { + __RW __u32 VAD_CON; + __RW __u32 VAD_ACON0; + __RW __u32 VAD_ACON1; + __RW __u32 AVAD_CON; + __RW __u32 AVAD_DATA; + __RW __u32 DVAD_CON0; + __RW __u32 DVAD_CON1; + __RW __u32 DMA_BADR; + __RW __u32 DMA_LEN; + __RW __u32 DMA_HPTR; + __RW __u32 DMA_SPTR; + __RW __u32 DMA_SPN; + __RW __u32 DMA_SHN; +} P11_LPVAD_TypeDef; + +#define P11_LPVAD_BASE (p11_sfr_base + map_adr(0x14, 0x00)) +#define P11_LPVAD ((P11_LPVAD_TypeDef *)P11_LPVAD_BASE) + +//............. 0x1500 - 0x16ff............ for crossbar +#include "p11_io_omap.h" +#include "p11_io_imap.h" + +//............. 0x1700 - 0x18ff............ for gp timer +typedef struct { + __RW __u32 CON; + __RW __u32 CNT; + __RW __u32 PRD; + __RW __u32 PWM; +} P11_GPTMR_TypeDef; + +#define P11_GPTMR0_BASE (p11_sfr_base + map_adr(0x17, 0x00)) +#define P11_GPTMR1_BASE (p11_sfr_base + map_adr(0x18, 0x00)) + +#define P11_GPTMR0 ((P11_GPTMR_TypeDef *)P11_GPTMR0_BASE) +#define P11_GPTMR1 ((P11_GPTMR_TypeDef *)P11_GPTMR1_BASE) + +#endif diff --git a/include_lib/driver/cpu/br28/asm/power/p2m_msg.h b/include_lib/driver/cpu/br28/asm/power/p2m_msg.h new file mode 100644 index 0000000..8420ee9 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/power/p2m_msg.h @@ -0,0 +1,89 @@ +#ifndef __P2M_MSG_H__ +#define __P2M_MSG_H__ + +//p2m用户消息实例 +enum { + P2M_MSG_ACK = BIT(0), + P2M_MSG_TEST = BIT(1), + P2M_MSG_COMMOM = BIT(2), + P2M_MSG_CTMU = BIT(3), + P2M_MSG_SENSOR = BIT(4), + P2M_MSG_VAD = BIT(5), + +}; + +//测试 +struct p2m_msg_test { + u8 dat; +}; + +//测试 +struct p2m_msg_ack { + u8 dat; +}; + +//公共消息 +struct p2m_msg_common { + u8 dat; +}; + +//触摸消息 +struct p2m_msg_ctmu { + u8 dat; +}; + +//vad +struct p2m_msg_vad { + u8 dat; +}; + +//p2m用户消息格式 +struct p2m_msg_head { +u16 type : + MSG_TYPE_BIT_LEN; +u16 len : + MSG_PARAM_BIT_LEN; +u8 index : + MSG_INDEX_BIT; +u8 ack : + MSG_ACK_BIT; +} __attribute__((packed)); + +struct p2m_msg { + struct p2m_msg_head head; + union { + struct p2m_msg_ack ack; + struct p2m_msg_test test; + struct p2m_msg_common com; + struct p2m_msg_ctmu ctmu; + struct p2m_msg_vad vad; + } u; +} __attribute__((packed)); + +//p2m用户消息对应处理 +struct p2m_msg_handler { + u8 type; + void (*handler)(struct p2m_msg *); +}; + +#define REGISTER_P2M_MSG_HANDLER(_type, fn, pri) \ + const struct p2m_msg_handler _##fn sec(.p2m_msg_handler)= { \ + .type = _type, \ + .handler = fn, \ + } + +extern struct p2m_msg_handler p2m_msg_handler_begin[]; +extern struct p2m_msg_handler p2m_msg_handler_end[]; + +#define list_for_each_p2m_msg_handler(p) \ + for (p = p2m_msg_handler_begin; p < p2m_msg_handler_end; p++) + + + +int p2m_get_msg(int len, struct p2m_msg *msg); + +int p2m_post_msg(int len, struct p2m_msg *msg); + +int p2m_post_sync_msg(int len, struct p2m_msg *msg, u8 abandon, int timeout); + +#endif diff --git a/include_lib/driver/cpu/br28/asm/power/p33.h b/include_lib/driver/cpu/br28/asm/power/p33.h new file mode 100644 index 0000000..09a2f7b --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/power/p33.h @@ -0,0 +1,26 @@ +/********************************************************************************************* + * Filename : p33.h + + * Description : + + * Author : Bingquan + + * Email : caibingquan@zh-jieli.com + + * Last modifiled : 2019-12-09 10:42 + + * Copyright:(c)JIELI 2011-2019 @ , All Rights Reserved. + *********************************************************************************************/ + +#ifndef __P33_H__ +#define __P33_H__ + +#include "p33_sfr.h" + +#include "p33_app.h" + +#include "p33_io_app.h" + +#include "rtc_app.h" + +#endif diff --git a/include_lib/driver/cpu/br28/asm/power/p33_app.h b/include_lib/driver/cpu/br28/asm/power/p33_app.h new file mode 100644 index 0000000..b6b8d53 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/power/p33_app.h @@ -0,0 +1,796 @@ +#ifndef __P33_APP_H__ +#define __P33_APP_H__ + +//ROM +u8 p33_buf(u8 buf); + +// void p33_xor_1byte(u16 addr, u8 data0); +#define p33_xor_1byte(addr, data0) (*((volatile u8 *)&addr + 0x300*4) = data0) +// #define p33_xor_1byte(addr, data0) addr ^= (data0) + +// void p33_and_1byte(u16 addr, u8 data0); +#define p33_and_1byte(addr, data0) (*((volatile u8 *)&addr + 0x100*4) = (data0)) +//#define p33_and_1byte(addr, data0) addr &= (data0) + +// void p33_or_1byte(u16 addr, u8 data0); +#define p33_or_1byte(addr, data0) (*((volatile u8 *)&addr + 0x200*4) = data0) +// #define p33_or_1byte(addr, data0) addr |= (data0) + +// void p33_tx_1byte(u16 addr, u8 data0); +#define p33_tx_1byte(addr, data0) addr = data0 + +// u8 p33_rx_1byte(u16 addr); +#define p33_rx_1byte(addr) addr + +#define P33_CON_SET(sfr, start, len, data) (sfr = (sfr & ~((~(0xff << (len))) << (start))) | \ + (((data) & (~(0xff << (len)))) << (start))) + +#define P33_CON_GET(sfr) sfr + +#define P33_ANA_CHECK(reg) (((reg & reg##_MASK) == reg##_RV) ? 1:0) + + +#if 1 + +#define p33_fast_access(reg, data, en) \ +{ \ + if (en) { \ + p33_or_1byte(reg, (data)); \ + } else { \ + p33_and_1byte(reg, ~(data)); \ + } \ +} + +#else + +#define p33_fast_access(reg, data, en) \ +{ \ + if (en) { \ + reg |= (data); \ + } else { \ + reg &= ~(data); \ + } \ +} + +#endif + +// +// +// for p33_analog.doc +// +// +// +/************************P3_ANA_CON0*****************************/ +#define VDD13TO12_SYS_EN(en) P33_CON_SET(P3_ANA_CON0, 0, 1, en) + +#define VDD13TO12_RVD_EN(en) P33_CON_SET(P3_ANA_CON0, 1, 1, en) + +#define LDO13_EN(en) P33_CON_SET(P3_ANA_CON0, 2, 1, en) + +#define DCDC13_EN(en) P33_CON_SET(P3_ANA_CON0, 3, 1, en) + +#define GET_DCDC13_EN() ((P33_CON_GET(P3_ANA_CON0) & BIT(3)) ? 1:0) + +#define PVDD_EN(en) P33_CON_SET(P3_ANA_CON0, 4, 1, en) + +#define MVIO_VBAT_EN(en) P33_CON_SET(P3_ANA_CON0, 5, 1, en) + +#define MVIO_VPWR_EN(en) P33_CON_SET(P3_ANA_CON0, 6, 1, en) + +#define MBG_EN(en) P33_CON_SET(P3_ANA_CON0, 7, 1, en) + +#define P3_ANA_CON0_MASK 0b11110011 +#define P3_ANA_CON0_RV 0b11110011 + +/************************P3_ANA_KEEP*****************************/ +#define CLOSE_ANA_KEEP() P33_CON_SET(P3_ANA_KEEP, 0, 8, 0) + +#define P3_ANA_KEEP_MASK 0b11111111 +#define P3_ANA_KEEP_RV 0b00000000 + +/************************P3_ANA_KEEP1****************************/ +#define VIO2_EN_KEEP(en) P33_CON_SET(P3_ANA_KEEP1, 0, 1, en) + +#define P3_ANA_KEEP1_MASK 0b00000001 +#define P3_ANA_KEEP1_RV 0b00000000 + +/**************************P3_ANA_CON1*********************************/ +#define RVDD_BYPASS_EN(en) P33_CON_SET(P3_ANA_CON1, 0, 1, en) + +#define WVDD_SHORT_RVDD(en) P33_CON_SET(P3_ANA_CON1, 1, 1, en) + +#define WVDD_SHORT_SVDD(en) P33_CON_SET(P3_ANA_CON1, 2, 1, en) + +#define WLDO06_EN(en) P33_CON_SET(P3_ANA_CON1, 3, 1, en) + +#define WLDO06_OE(en) P33_CON_SET(P3_ANA_CON1, 4, 1, en) + +#define EVD_EN(en) P33_CON_SET(P3_ANA_CON1, 5, 1, en) + +#define EVD_SHORT_PB8(en) P33_CON_SET(P3_ANA_CON1, 6, 1, en) + +#define PVD_SHORT_PB8(en) P33_CON_SET(P3_ANA_CON1, 7, 1, en) + +#define P3_ANA_CON1_MASK 0b10011111 +#define P3_ANA_CON1_RV 0b00000100 + +/************************P3_ANA_CON2*****************************/ +#define VCM_DET_EN(en) P33_CON_SET(P3_ANA_CON2, 3, 1, en) + +#define MVIO_VBAT_ILMT_EN(en) P33_CON_SET(P3_ANA_CON2, 4, 1, en) + +#define MVIO_VPWR_ILMT_EN(en) P33_CON_SET(P3_ANA_CON2, 5, 1, en) + +#define DCVD_ILMT_EN(en) P33_CON_SET(P3_ANA_CON2, 6, 1, en) + +#define CURRENT_LIMIT_DISABLE() (P3_ANA_CON2 &= ~(BIT(4) | BIT(5) | BIT(6))) + +#define P3_ANA_CON2_MASK 0b01110000 +#define P3_ANA_CON2_RV 0b01110000 + +/************************P3_ANA_CON3*****************************/ +#define MVBG_SEL(en) P33_CON_SET(P3_ANA_CON3, 0, 4, en) + +#define MVBG_GET() (P33_CON_GET(P3_ANA_CON3) & 0x0f) + +#define WVBG_SEL(en) P33_CON_SET(P3_ANA_CON3, 4, 4, en) + +#define P3_ANA_CON3_MASK 0b00000000 +#define P3_ANA_CON3_RV 0b00000000 + +/************************P3_ANA_CON4*****************************/ +#define PMU_DET_EN(en) P33_CON_SET(P3_ANA_CON4, 0, 1, en) + +#define ADC_CHANNEL_SEL(ch) P33_CON_SET(P3_ANA_CON4, 1, 4, ch) + +#define PMU_DET_BG_BUF_EN(en) P33_CON_SET(P3_ANA_CON4, 5, 1, en) + +#define VBG_TEST_EN(en) P33_CON_SET(P3_ANA_CON4, 6, 1, en) + +#define VBG_TEST_SEL(en) P33_CON_SET(P3_ANA_CON4, 7, 1, en) + +#define P3_ANA_CON4_MASK 0b11100001 +#define P3_ANA_CON4_RV 0b11100001 + +/************************P3_ANA_CON5*****************************/ +//vddiom_lev +enum { + VDDIOM_VOL_20V = 0, + VDDIOM_VOL_22V, + VDDIOM_VOL_24V, + VDDIOM_VOL_26V, + VDDIOM_VOL_28V, + VDDIOM_VOL_30V, //default + VDDIOM_VOL_32V, + VDDIOM_VOL_34V, +}; + +#define VDDIOM_VOL_SEL(lev) P33_CON_SET(P3_ANA_CON5, 0, 3, lev) + +#define GET_VDDIOM_VOL() (P33_CON_GET(P3_ANA_CON5) & 0x7) + +//vddiow_lev +enum { + VDDIOW_VOL_20V = 0, + VDDIOW_VOL_22V, + VDDIOW_VOL_24V, + VDDIOW_VOL_26V, + VDDIOW_VOL_28V, + VDDIOW_VOL_30V, + VDDIOW_VOL_32V, + VDDIOW_VOL_34V, +}; + +#define VDDIOW_VOL_SEL(lev) P33_CON_SET(P3_ANA_CON5, 3, 3, lev) + +#define GET_VDDIOW_VOL() (P33_CON_GET(P3_ANA_CON5)>>3 & 0x7) + +#define VDDIO_HD_SEL(cur) P33_CON_SET(P3_ANA_CON5, 6, 2, cur) + +#define P3_ANA_CON5_MASK 0b11000000 +#define P3_ANA_CON5_RV 0b01000000 + +/************************P3_ANA_CON6*****************************/ +#define VDC13_VOL_SEL(sel) P33_CON_SET(P3_ANA_CON6, 0, 4, sel) +//Macro for VDC13_VOL_SEL +enum { + VDC13_VOL_SEL_100V = 0, + VDC13_VOL_SEL_105V, + VDC13_VOL_SEL_1075V, + VDC13_VOL_SEL_110V, + VDC13_VOL_SEL_1125V, + VDC13_VOL_SEL_115V, + VDC13_VOL_SEL_1175V, + VDC13_VOL_SEL_120V, + VDC13_VOL_SEL_1225V, + VDC13_VOL_SEL_125V, + VDC13_VOL_SEL_1275V, + VDC13_VOL_SEL_130V, + VDC13_VOL_SEL_1325V, + VDC13_VOL_SEL_135V, + VDC13_VOL_SEL_1375V, + VDC13_VOL_SEL_140V, +}; + +#define VD13_DEFAULT_VOL VDC13_VOL_SEL_125V + +#define GET_VD13_VOL_SEL() (P33_CON_GET(P3_ANA_CON6) & 0xf) + +#define VD13_HD_SEL(sel) P33_CON_SET(P3_ANA_CON6, 4, 2, sel) + +#define VD13_CAP_EN(en) P33_CON_SET(P3_ANA_CON6, 6, 1, en) + +#define VD13_DESHOT_EN(en) P33_CON_SET(P3_ANA_CON6, 7, 1, en) + +#define P3_ANA_CON6_MASK 0b11111111 +#define P3_ANA_CON6_RV 0b11011010 + +/************************P3_ANA_CON7*****************************/ +#define BTDCDC_PFM_MODE(en) P33_CON_SET(P3_ANA_CON7, 0, 1, en) + +#define GET_BTDCDC_PFM_MODE() (P33_CON_GET(P3_ANA_CON7) & BIT(0) ? 1 : 0) + +#define BTDCDC_RAMP_SHORT(en) P33_CON_SET(P3_ANA_CON7, 1, 1, en) + +#define BTDCDC_V17_TEST_OE(en) P33_CON_SET(P3_ANA_CON7, 2, 1, en); + +#define BTDCDC_DUTY_SEL(sel) P33_CON_SET(P3_ANA_CON7, 3, 2, sel) + +#define BTDCDC_OSC_SEL(sel) P33_CON_SET(P3_ANA_CON7, 5, 3, sel) +//Macro for BTDCDC_OSC_SEL +enum { + BTDCDC_OSC_SEL0520KHz = 0, + BTDCDC_OSC_SEL0762KHz, + BTDCDC_OSC_SEL0997KHz, + BTDCDC_OSC_SEL1220KHz, + BTDCDC_OSC_SEL1640KHz, + BTDCDC_OSC_SEL1840KHz, + BTDCDC_OSC_SEL2040KHz, + BTDCDC_OSC_SEL2220MHz, +}; + +#define P3_ANA_CON7_MASK 0b11111111 +#define P3_ANA_CON7_RV 0b01001001 + +/************************P3_ANA_CON8*****************************/ +#define BTDCDC_V21_RES_S(sel) P33_CON_SET(P3_ANA_CON8, 0, 2, sel) + +#define BTDCDC_DT_S(sel) P33_CON_SET(P3_ANA_CON8, 2, 2, sel) + +#define BTDCDC_ISENSE_HD(sel) P33_CON_SET(P3_ANA_CON8, 4, 2, sel) + +#define BTDCDC_COMP_HD(sel) P33_CON_SET(P3_ANA_CON8, 6, 2, sel) + +#define P3_ANA_CON8_MASK 0b11111111 +#define P3_ANA_CON8_RV 0b01100110 + +/************************P3_ANA_CON9*****************************/ +#define BTDCDC_NMOS_S(sel) P33_CON_SET(P3_ANA_CON9, 1, 3, sel) + +#define BTDCDC_PMOS_S(sel) P33_CON_SET(P3_ANA_CON9, 5, 3, sel) + +#define P3_ANA_CON9_MASK 0b11101110 +#define P3_ANA_CON9_RV 0b01101110 + +/************************P3_ANA_CON10*****************************/ + +#define BTDCDC_OSC_TEST_OE(en) P33_CON_SET(P3_ANA_CON10, 7, 1, en) + +#define BTDCDC_HD_BIAS_SEL(sel) P33_CON_SET(P3_ANA_CON10, 5, 2, sel) + +#define BTDCDC_CLK_SEL(sel) P33_CON_SET(P3_ANA_CON10, 4, 1, sel) + +#define GET_BTDCDC_CLK_SEL() (P33_CON_GET(P3_ANA_CON10) & BIT(4) ? 1 : 0) + +#define BTDCDC_ZCD_RES(sel) P33_CON_SET(P3_ANA_CON10, 2, 2, sel) + +#define BTDCDC_ZCD_EN(en) P33_CON_SET(P3_ANA_CON10, 0, 1, en) + +#define P3_ANA_CON10_MASK 0b11111101 +#define P3_ANA_CON10_RV 0b00110001 + +/************************P3_ANA_CON11*****************************/ +#define SYSVDD_VOL_SEL(sel) P33_CON_SET(P3_ANA_CON11, 0, 4, sel) +//Macro for SYSVDD_VOL_SEL +enum { + SYSVDD_VOL_SEL_081V = 0, + SYSVDD_VOL_SEL_084V, + SYSVDD_VOL_SEL_087V, + SYSVDD_VOL_SEL_090V, + SYSVDD_VOL_SEL_093V, + SYSVDD_VOL_SEL_096V, + SYSVDD_VOL_SEL_099V, + SYSVDD_VOL_SEL_102V, + SYSVDD_VOL_SEL_105V, + SYSVDD_VOL_SEL_108V, + SYSVDD_VOL_SEL_111V, + SYSVDD_VOL_SEL_114V, + SYSVDD_VOL_SEL_117V, + SYSVDD_VOL_SEL_120V, + SYSVDD_VOL_SEL_123V, + SYSVDD_VOL_SEL_126V, +}; + +#define SYSVDD_DEFAULT_VOL SYSVDD_VOL_SEL_105V + +#define GET_SYSVDD_VOL_SEL() (P33_CON_GET(P3_ANA_CON11) & 0xf) + +#define SYSVDD_VOL_HD_SEL(sel) P33_CON_SET(P3_ANA_CON11, 4, 2, sel) + +#define SYSVDD_CAP_EN(en) P33_CON_SET(P3_ANA_CON11, 6, 1, en) + +#define P3_ANA_CON11_MASK 0b01110000 +#define P3_ANA_CON11_RV 0b00010000 + +/************************P3_ANA_CON12*****************************/ +#define RVDD_VOL_SEL(sel) P33_CON_SET(P3_ANA_CON12, 0, 4, sel) +//Macro for SYSVDD_VOL_SEL +enum { + RVDD_VOL_SEL_081V = 0, + RVDD_VOL_SEL_084V, + RVDD_VOL_SEL_087V, + RVDD_VOL_SEL_090V, + RVDD_VOL_SEL_093V, + RVDD_VOL_SEL_096V, + RVDD_VOL_SEL_099V, + RVDD_VOL_SEL_102V, + RVDD_VOL_SEL_105V, + RVDD_VOL_SEL_108V, + RVDD_VOL_SEL_111V, + RVDD_VOL_SEL_114V, + RVDD_VOL_SEL_117V, + RVDD_VOL_SEL_120V, + RVDD_VOL_SEL_123V, + RVDD_VOL_SEL_126V, +}; + +#define RVDD_DEFAULT_VOL RVDD_VOL_SEL_105V + +#define GET_RVDD_VOL_SEL() (P33_CON_GET(P3_ANA_CON12) & 0xf) + +#define RVDD_VOL_HD_SEL(en) P33_CON_SET(P3_ANA_CON12, 4, 2, en) + +#define RVDD_CAP_EN(en) P33_CON_SET(P3_ANA_CON12, 6, 1, en) + +#define P3_ANA_CON12_MASK 0b01110000 +#define P3_ANA_CON12_RV 0b00010000 + +/************************P3_ANA_CON13*****************************/ +#define WVDD_VOL_SEL(sel) P33_CON_SET(P3_ANA_CON13, 0, 4, sel) +//Macro for WVDD_VOL_SEL +enum { + WVDD_VOL_SEL_050V = 0, + WVDD_VOL_SEL_055V, + WVDD_VOL_SEL_060V, + WVDD_VOL_SEL_065V, + WVDD_VOL_SEL_070V, + WVDD_VOL_SEL_075V, + WVDD_VOL_SEL_080V, + WVDD_VOL_SEL_085V, + WVDD_VOL_SEL_090V, + WVDD_VOL_SEL_095V, + WVDD_VOL_SEL_100V, + WVDD_VOL_SEL_105V, + WVDD_VOL_SEL_110V, + WVDD_VOL_SEL_115V, + WVDD_VOL_SEL_120V, + WVDD_VOL_SEL_125V, +}; + +#define WVDD_VOL_MIN 500 +#define VWDD_VOL_MAX 1250 +#define WVDD_VOL_TRIM 800//mv +#define WVDD_VOL_STEP 50 +#define WVDD_LEVEL_MAX 0xf +#define WVDD_LEVEL_ERR 0xff + +#define WVDD_VOL_TRIM_LED 850 + +#define WVDD_LEVEL_DEFAULT ((WVDD_VOL_TRIM-WVDD_VOL_MIN)/WVDD_VOL_STEP + 2) + +#define WVDD_LOAD_EN(en) P33_CON_SET(P3_ANA_CON13, 4, 1, en) + +#define WVDDIO_FBRES_AUTO(en) P33_CON_SET(P3_ANA_CON13, 6, 1, en) + +#define WVDDIO_FBRES_SEL_W(en) P33_CON_SET(P3_ANA_CON13, 7, 1, en) + +#define P3_ANA_CON13_MASK 0b11110000 +#define P3_ANA_CON13_RV 0b10000000 + +/************************P3_ANA_CON14*****************************/ +#define RVD2PVD_SHORT_EN(en) P33_CON_SET(P3_ANA_CON14, 4, 1, en) + +#define GET_RVD2PVD_SHORT_EN() (P33_CON_GET(P3_ANA_CON14) & BIT(4) ? 1:0) + +#define PVD_DEUDSHT_EN(en) P33_CON_SET(P3_ANA_CON14, 3, 1, en) + +#define GET_PVD_DEUDST_EN() ((P33_CON_GET(P3_ANA_CON14) & BIT(3)) ? 1:0) + +#define PVD_HD_SEL(sel) P33_CON_SET(P3_ANA_CON14, 0, 3, sel) + +#define GET_PVD_HD_SEL() (P33_CON_GET(P3_ANA_CON14) & 0x7) + +#define P3_ANA_CON14_MASK 0b00011111 +#define P3_ANA_CON14_RV 0b00000100 + +/************************P3_ANA_CON15*****************************/ +#define EVD_VOL_SEL(sel) P33_CON_SET(P3_ANA_CON15, 0, 2, sel) +enum { + EVD_VOL_SEL_100V = 0, + EVD_VOL_SEL_105V, + EVD_VOL_SEL_110V, + EVD_VOL_SEL_115V, +}; + +#define EVD_HD_SEL(sel) P33_CON_SET(P3_ANA_CON15, 2, 2, sel) + +#define EVD_CAP_EN(en) P33_CON_SET(P3_ANA_CON15, 4, 1, en) + +#define P3_ANA_CON15_MASK 0b00001100 +#define P3_ANA_CON15_RV 0b00000100 + +/************************P3_PVDD0_AUTO*****************************/ +#define PVDD_LEVEL_LOW(sel) P33_CON_SET(P3_PVDD0_AUTO, 0, 4, sel) + +#define GET_PVDD_LEVEL_LOW() (P33_CON_GET(P3_PVDD0_AUTO) & 0xf) + +#define PVDD_LEVEL_AUTO(en) P33_CON_SET(P3_PVDD0_AUTO, 4, 1, en) + +#define GET_PVDD_LEVEL_AUTO() ((P33_CON_GET(P3_PVDD0_AUTO) & BIT(4)) ? 1:0) + +#define PVDD_AUTO_PRD(sel) P33_CON_SET(P3_PVDD0_AUTO, 5, 3, sel) + +#define GET_PVDD_AUTO_PRD() ((P33_CON_GET(P3_PVDD0_AUTO) & (0x7<<5)) >> 5) + +enum { + PVDD_VOL_SEL_050V = 0, + PVDD_VOL_SEL_055V, + PVDD_VOL_SEL_060V, + PVDD_VOL_SEL_065V, + PVDD_VOL_SEL_070V, + PVDD_VOL_SEL_075V, + PVDD_VOL_SEL_080V, + PVDD_VOL_SEL_085V, + PVDD_VOL_SEL_090V, + PVDD_VOL_SEL_095V, + PVDD_VOL_SEL_100V, + PVDD_VOL_SEL_105V, + PVDD_VOL_SEL_110V, + PVDD_VOL_SEL_115V, + PVDD_VOL_SEL_120V, + PVDD_VOL_SEL_125V, +}; + +#define PVDD_VOL_MIN 500 +#define PVDD_VOL_MAX 1250 +#define PVDD_VOL_STEP 50 +#define PVDD_LEVEL_MAX 0xf +#define PVDD_LEVEL_ERR 0xff +#define PVDD_LEVEL_DEFAULT 0xc + +#define PVDD_LEVEL_REF PVDD_VOL_SEL_115V +#define PVDD_VOL_REF 1150//mV + +#define PVDD_VOL_CLOCK_SET 1200 + +#define PVDD_VOL_HIGH_NOW 1100 + +#ifdef CONFIG_WATCH_CASE_ENABLE +#define PVDD_LEVEL_SLEEP PVDD_VOL_SEL_090V +#define PVDD_VOL_SLEEP 900 + +#else +#define PVDD_LEVEL_SLEEP PVDD_VOL_SEL_095V +#define PVDD_VOL_SLEEP 950 + +#endif + +#define P3_PVDD0_AUTO_MASK 0b11110000 +#define P3_PVDD0_AUTO_RV 0b01110000 + +/************************P3_PVDD1_AUTO*****************************/ +#define PVDD_LEVEL_HIGH_NOW(sel) P33_CON_SET(P3_PVDD1_AUTO, 0, 8, (sel<<4)|sel); + +#define PVDD_LEVEL_HIGH(sel) P33_CON_SET(P3_PVDD1_AUTO, 4, 4, sel) + +#define GET_PVDD_LEVEL_HIGH() ((P33_CON_GET(P3_PVDD1_AUTO) & 0xf0)>>4) + +#define PVDD_LEVEL_NOW(sel) P33_CON_SET(P3_PVDD1_AUTO, 0, 4, sel) + +#define GET_PVDD_LEVEL_NOW() (P33_CON_GET(P3_PVDD1_AUTO) & 0x0f) + +#define P3_PVDD1_AUTO_MASK 0b00000000 +#define P3_PVDD1_AUTO_RV 0b00000000 + +/************************P3_PVDD2_AUTO*****************************/ +#define GET_PVDD_DRV_AUTO() (P33_CON_GET(P3_PVDD2_AUTO) & BIT(0)) + +#define P3_PVDD2_AUTO_MASK 0b00000001 +#define P3_PVDD2_AUTO_RV 0b00000001 + +/************************P3_CHG_CON0*****************************/ +#define CHARGE_EN(en) P33_CON_SET(P3_CHG_CON0, 0, 1, en) + +#define CHGGO_EN(en) P33_CON_SET(P3_CHG_CON0, 1, 1, en) + +#define IS_CHARGE_EN() ((P33_CON_GET(P3_CHG_CON0) & BIT(0)) ? 1: 0 ) + +#define CHG_HV_MODE(mode) P33_CON_SET(P3_CHG_CON0, 2, 1, mode) + +#define CHG_TRICKLE_EN(en) P33_CON_SET(P3_CHG_CON0, 3, 1, en) + +#define CHG_CCLOOP_EN(en) P33_CON_SET(P3_CHG_CON0, 4, 1, en) + +#define CHG_VILOOP_EN(en) P33_CON_SET(P3_CHG_CON0, 5, 1, en) + +#define CHG_VINLOOP_SLT(sel) P33_CON_SET(P3_CHG_CON0, 6, 1, sel) + +#define CHG_SEL_CHG_FULL 0 +#define CHG_SEL_VBAT_DET 1 +#define CHG_SSEL(sel) P33_CON_SET(P3_CHG_CON0, 7, 1, sel) + +#define P3_CHG_CON0_MASK 0 +#define P3_CHG_CON0_RV 0 + +/************************P3_CHG_CON1*****************************/ +#define CHARGE_FULL_V_SEL(a) P33_CON_SET(P3_CHG_CON1, 0, 4, a) + +#define CHARGE_mA_SEL(a) P33_CON_SET(P3_CHG_CON1, 4, 4, a) + +#define P3_CHG_CON1_MASK 0 +#define P3_CHG_CON1_RV 0 + +/************************P3_CHG_CON2*****************************/ +#define CHARGE_FULL_mA_SEL(a) P33_CON_SET(P3_CHG_CON2, 4, 3, a) + +enum { + CHARGE_DET_VOL_365V, + CHARGE_DET_VOL_375V, + CHARGE_DET_VOL_385V, + CHARGE_DET_VOL_395V, +}; +#define CHARGE_DET_VOL(a) P33_CON_SET(P3_CHG_CON2, 1, 2, a) + +#define CHARGE_DET_EN(en) P33_CON_SET(P3_CHG_CON2, 0, 1, en) + +#define P3_CHG_CON2_MASK 0 +#define P3_CHG_CON2_RV 0 + +/************************P3_L5V_CON0*****************************/ +#define L5V_LOAD_EN(a) P33_CON_SET(P3_L5V_CON0, 0, 1, a) + +#define L5V_IO_MODE(a) P33_CON_SET(P3_L5V_CON0, 2, 1, a) + +#define IS_L5V_LOAD_EN() ((P33_CON_GET(P3_L5V_CON0) & BIT(0)) ? 1: 0 ) + +#define GET_L5V_RES_DET_S_SEL() (P33_CON_GET(P3_L5V_CON1) & 0x03) + +#define P3_L5V_CON0_MASK 0 +#define P3_L5V_CON0_RV 0 + +/************************P3_L5V_CON1*****************************/ +#define L5V_RES_DET_S_SEL(a) P33_CON_SET(P3_L5V_CON1, 0, 2, a) + +#define P3_L5V_CON1_MASK 0 +#define P3_L5V_CON1_RV 0 + +/************************P3_VLVD_CON*****************************/ +#define P33_VLVD_EN(en) P33_CON_SET(P3_VLVD_CON, 0, 1, en) + +#define GET_VLVD_EN() (P33_CON_GET(P3_VLVD_CON) & BIT(0)) + +#define P33_VLVD_PS(en) P33_CON_SET(P3_VLVD_CON, 1, 1, en) + +#define P33_VLVD_OE(en) P33_CON_SET(P3_VLVD_CON, 2, 1, en) + +#define GET_VLVD_OE() ((P33_CON_GET(P3_VLVD_CON) & BIT(2)) ? 1:0) + +#define VLVD_SEL(lev) P33_CON_SET(P3_VLVD_CON, 3, 3, lev) + +#define GET_VLVD_SEL() ((P33_CON_GET(P3_VLVD_CON) & (0x7<<3))>>3) +//Macro for VLVD_SEL +enum { + VLVD_SEL_18V = 0, + VLVD_SEL_19V, + VLVD_SEL_20V, + VLVD_SEL_21V, + VLVD_SEL_22V, + VLVD_SEL_23V, + VLVD_SEL_24V, + VLVD_SEL_25V, +}; + +#define VLVD_PND_CLR() P33_CON_SET(P3_VLVD_CON, 6, 1, 1) + +#define VLVD_PND() ((P33_CON_GET(P3_VLVD_CON) & BIT(7)) ? 1 : 0) + +#define P3_VLVD_CON_MASK 0 +#define P3_VLVD_CON_RV 0 + +/************************P3_VLVD_FLT*****************************/ +#define VLVD_FLT(sel) P33_CON_SET(P3_VLVD_FLT, 0, 2, sel); + +#define P3_VLVD_FLT_MASK 0b00000011 +#define P3_VLVD_FLT_RV 0b00000010 + +/************************P3_RST_CON0*****************************/ +#define DPOR_MASK(en) P33_CON_SET(P3_RST_CON0, 0, 1, en) + +#define VLVD_RST_EN(en) P33_CON_SET(P3_RST_CON0, 2, 1, en) + +#define VLVD_WKUP_EN(en) P33_CON_SET(P3_RST_CON0, 3, 1, en) + +#define PPOR_MASK(en) P33_CON_SET(P3_RST_CON0, 4, 1, en) + +#define P11_TO_P33_RST_MASK(en) P33_CON_SET(P3_RST_CON0, 5, 1, en) + +#define DVDDOK_OE(en) P33_CON_SET(P3_RST_CON0, 6, 1, en) + +#define PVDDOK_OE(en) P33_CON_SET(P3_RST_CON0, 7, 1, en) + +#define P3_RST_CON0_MASK 0b11111101 +#define P3_RST_CON0_RV 0b00000100 + +/************************P3_LRC_CON0*****************************/ +#define RC32K_EN(en) P33_CON_SET(P3_LRC_CON0, 0, 1, en) + +#define RC32K_RN_TRIM(en) P33_CON_SET(P3_LRC_CON0, 1, 1, en) + +#define RC32K_RPPS_SEL(sel) P33_CON_SET(P3_LRC_CON0, 4, 2, sel) + +#define P3_LRC_CON0_MASK 0b00110011 +#define P3_LRC_CON0_RV 0b00100001 + +/************************P3_LRC_CON1*****************************/ +#define RC32K_PNPS_SEL(sel) P33_CON_SET(P3_LRC_CON1, 0, 2, sel) + +#define RC32K_CAP_SEL(sel) P33_CON_SET(P3_LRC_CON1, 4, 3, sel) + +#define CLOSE_LRC() P33_CON_SET(P3_LRC_CON0, 0, 8, 0);\ + P33_CON_SET(P3_LRC_CON1, 0, 8, 0) + +#define P3_LRC_CON1_MASK 0b01110011 +#define P3_LRC_CON1_RV 0b01000001 + +/************************P3_CLK_CON0*****************************/ +#define RC_250K_EN(a) P33_CON_SET(P3_CLK_CON0, 0, 1, a) + +#define P3_CLK_CON0_MASK 0b00000001 +#define P3_CLK_CON0_RV 0b00000000 + +/************************P3_VLD_KEEP*****************************/ +#define RTC_WKUP_KEEP(a) P33_CON_SET(P3_VLD_KEEP, 1, 1, a) + +#define P33_WKUP_P11_EN(a) P33_CON_SET(P3_VLD_KEEP, 2, 1, a) + +#define P3_VLD_KEEP_MASK 0b00000110 +#define P3_VLD_KEEP_RV 0b00000110 + +/************************P3_PMU_CON0*****************************/ +#define GET_P33_SYS_POWER_FLAG() ((P33_CON_GET(P3_PMU_CON0) & BIT(7)) ? 1 : 0) + +#define P33_SYS_POWERUP_CLEAR() P33_CON_SET(P3_PMU_CON0, 6, 1, 1); + +#define P3_PMU_CON0_MASK 0b00000000 +#define P3_PMU_CON0_RV 0b00000000 + +/************************P3_PMU_DBG_CON*****************************/ +#define P3_PMU_DBG_CON_MASK 0b00000000 +#define P3_PMU_DBG_CON_RV 0b00000000 + +/************************P3_IOV2_CON*****************************/ +#define GET_IOV2_VOL() ((P33_CON_GET(P3_IOV2_CON) & (0x7<<3)) >> 3) + +#define GET_IOV2_IFULL() ((P33_CON_GET(P3_IOV2_CON) & BIT(2)) ? 1:0) + +#define GET_IOV2_BYPASS() ((P33_CON_GET(P3_IOV2_CON) & BIT(1)) ? 1:0) + +#define GET_IOV2_EN() ((P33_CON_GET(P3_IOV2_CON) & BIT(0)) ? 1:0) + +#define P3_IOV2_CON_MASK 0 +#define P3_IOV2_CON_RV 0 + +/************************P3_RVD_CON*****************************/ +#define RVDD_CMP_EN(en) P33_CON_SET(P3_RVD_CON, 4, 1, en) + +#define PVDD_DCDC_LEV_SEL(sel) P33_CON_SET(P3_RVD_CON, 0, 4, sel) + +#define GET_PVDD_DCDC_LEV_SEL() (P33_CON_GET(P3_RVD_CON) & 0xf) + +#define P3_RVD_CON_MASK 0b00000000 +#define P3_RVD_CON_RV 0b00000000 + +/************************P3_CHG_WKUP*****************************/ +#define CHARGE_LEVEL_DETECT_EN(a) P33_CON_SET(P3_CHG_WKUP, 0, 1, a) + +#define CHARGE_EDGE_DETECT_EN(a) P33_CON_SET(P3_CHG_WKUP, 1, 1, a) + +#define CHARGE_WKUP_SOURCE_SEL(a) P33_CON_SET(P3_CHG_WKUP, 2, 2, a) + +#define CHARGE_WKUP_EN(a) P33_CON_SET(P3_CHG_WKUP, 4, 1, a) + +#define CHARGE_WKUP_EDGE_SEL(a) P33_CON_SET(P3_CHG_WKUP, 5, 1, a) + +#define CHARGE_WKUP_PND_CLR() P33_CON_SET(P3_CHG_WKUP, 6, 1, 1) + +/************************P3_AWKUP_LEVEL*****************************/ +#define CHARGE_FULL_FILTER_GET() ((P33_CON_GET(P3_AWKUP_LEVEL) & BIT(2)) ? 1: 0) + +#define LVCMP_DET_FILTER_GET() ((P33_CON_GET(P3_AWKUP_LEVEL) & BIT(1)) ? 1: 0) + +#define LDO5V_DET_FILTER_GET() ((P33_CON_GET(P3_AWKUP_LEVEL) & BIT(0)) ? 1: 0) + +/************************P3_ANA_READ*****************************/ +#define CHARGE_FULL_FLAG_GET() ((P33_CON_GET(P3_ANA_READ) & BIT(0)) ? 1: 0 ) + +#define LVCMP_DET_GET() ((P33_CON_GET(P3_ANA_READ) & BIT(1)) ? 1: 0 ) + +#define LDO5V_DET_GET() ((P33_CON_GET(P3_ANA_READ) & BIT(2)) ? 1: 0 ) +// +// +// for ANA_control.doc +// +// +// +/************************P3_LS_XX*****************************/ +#define PVDD_ANA_LAT_EN(en) \ + if(en){ \ + P3_LS_P11 = 0x01; \ + P3_LS_P11 = 0x03; \ + }else{ \ + P3_LS_P11 = 0x0; \ + } + +#define DVDD_ANA_LAT_EN(en) \ + if(en){ \ + P3_LS_IO_DLY = 0x1; \ + P3_LS_IO_ROM = 0x1; \ + P3_LS_ADC = 0x1; \ + P3_LS_AUDIO = 0x1; \ + P3_LS_RF = 0x1; \ + P3_LS_PLL = 0x1; \ + P3_LS_IO_DLY = 0x3; \ + P3_LS_IO_ROM = 0x3; \ + P3_LS_ADC = 0x3; \ + P3_LS_AUDIO = 0x3; \ + P3_LS_RF = 0x3; \ + P3_LS_PLL = 0x3; \ + }else{ \ + P3_LS_IO_DLY = 0x0; \ + P3_LS_IO_ROM = 0x0; \ + P3_LS_ADC = 0x0; \ + P3_LS_AUDIO = 0x0; \ + P3_LS_RF = 0x0; \ + P3_LS_PLL = 0x0;\ + } + +#define DVDD_ANA_ROM_LAT_EN(en) \ + if(en){ \ + P3_LS_IO_ROM = 1; \ + P3_LS_PLL = 1; \ + P3_LS_RF = 1; \ + P3_LS_IO_ROM = 3; \ + P3_LS_PLL = 3; \ + P3_LS_RF = 3; \ + }else{ \ + P3_LS_IO_ROM = 0; \ + P3_LS_PLL = 0; \ + P3_LS_RF = 0; \ + } +// +// +// for reset_source.doc +// +// +// +/************************P3_PR_PWR*****************************/ +#define P3_SOFT_RESET() P33_CON_SET(P3_PR_PWR, 4, 2, 3) + +/************************P3_IVS_CLR*****************************/ +#define P33_SF_KICK_START() P33_CON_SET(P3_IVS_CLR, 0, 8, 0b10101000) + +/************************P3_RST_SRC*****************************/ +#define GET_P33_SYS_RST_SRC() P33_CON_GET(P3_RST_SRC) + + +#endif diff --git a/include_lib/driver/cpu/br28/asm/power/p33_io_app.h b/include_lib/driver/cpu/br28/asm/power/p33_io_app.h new file mode 100644 index 0000000..caee3d8 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/power/p33_io_app.h @@ -0,0 +1,140 @@ +#ifndef __P33_IO_APP_H__ +#define __P33_IO_APP_H__ + +/*******************************************************************/ + +/* + *-------------------P3_WKUP_DLY + */ + +#define P3_WKUP_DLY_SET(val) P33_CON_SET(P3_WKUP_DLY, 0, 3, val) + +/*******************************************************************/ + +/* + *-------------------P3_PCNT_CON + */ + +#define PCNT_PND_CLR() P33_CON_SET(P3_PCNT_CON, 6, 1, 1) + +/*******************************************************************/ + +/* + *-------------------P3_PCNT_SET + */ + +#define SET_EXCEPTION_FLAG() P33_CON_SET(P3_PCNT_SET0, 0, 7, 0xb) +#define SET_ASSERT_FLAG() P33_CON_SET(P3_PCNT_SET0, 0, 7, 0xc) +#define SET_XOSC_RESUME_ERR_FLAG() P33_CON_SET(P3_PCNT_SET0, 0, 7, 0xd) +#define SET_LPTMR_TIMEOUT_FLAG() P33_CON_SET(P3_PCNT_SET0, 0, 7, 0xe) +#define SET_LVD_FLAG(en) P33_CON_SET(P3_PCNT_SET0, 7, 1, en) + +#define GET_EXCEPTION_FLAG() (((P33_CON_GET(P3_PCNT_SET0)&0x7f) == 0xb) ? 1 : 0) +#define GET_ASSERT_FLAG() (((P33_CON_GET(P3_PCNT_SET0)&0x7f) == 0xc) ? 1 : 0) +#define GET_XOSC_RESUME_ERR_FLAG() (((P33_CON_GET(P3_PCNT_SET0)&0x7f) == 0xd) ? 1 : 0) +#define GET_LPTMR_TIMEOUT_FLAG() (((P33_CON_GET(P3_PCNT_SET0)&0x7f) == 0xe) ? 1 : 0) +#define GET_LVD_FLAG() (((P33_CON_GET(P3_PCNT_SET0)&0x80) == 0x80) ? 1 : 0) + +#define SOFT_RESET_FLAG_CLEAR() (P33_CON_SET(P3_PCNT_SET0, 0, 8, 0)) + +/*******************************************************************/ + +/* + *-------------------P3_WKUP_XX + */ + +#define MAX_WAKEUP_PORT 12 //最大同时支持数字io输入个数 + +#define MAX_WAKEUP_ANA_PORT 3 //最大同时支持模拟io输入个数 + +typedef enum { + RISING_EDGE = 0, + FALLING_EDGE, + BOTH_EDGE, +} POWER_WKUP_EDGE; + +typedef enum { + PORT_FLT_NULL = 0, + PORT_FLT_256us, + PORT_FLT_512us, + PORT_FLT_1ms, + PORT_FLT_2ms, + PORT_FLT_4ms, + PORT_FLT_8ms, + PORT_FLT_16ms, +} POWER_WKUP_FLT; + +//en +#define P33_SET_WKUP_EN(data) P33_CON_SET(P3_WKUP_EN0, 0, 8, data & 0xff); \ + P33_CON_SET(P3_WKUP_EN1, 0, 8, (data >> 8) & 0xff) + +#define P33_OR_WKUP_EN(data) p33_fast_access(P3_WKUP_EN0, data & 0xff, 1); \ + p33_fast_access(P3_WKUP_EN1, (data >> 8) & 0xff, 1) + +#define P33_AND_WKUP_EN(data) p33_fast_access(P3_WKUP_EN0, data & 0xff, 0); \ + p33_fast_access(P3_WKUP_EN1, (data >> 8) & 0xff, 0) + +//edge +#define P33_SET_WKUP_EDGE(data) P33_CON_SET(P3_WKUP_EDGE0, 0, 8, data & 0xff); \ + P33_CON_SET(P3_WKUP_EDGE1, 0, 8, (data >> 8) & 0xff) + +#define P33_OR_WKUP_EDGE(data) p33_fast_access(P3_WKUP_EDGE0, data & 0xff, 1); \ + p33_fast_access(P3_WKUP_EDGE1, (data >> 8) & 0xff, 1) + +#define P33_AND_WKUP_EDGE(data) p33_fast_access(P3_WKUP_EDGE0, data & 0xff, 0); \ + p33_fast_access(P3_WKUP_EDGE1, (data >> 8) & 0xff, 0) + +//cpnd +#define P33_SET_WKUP_CPND(data) p33_fast_access(P3_WKUP_CPND0, data & 0xff, 1); \ + p33_fast_access(P3_WKUP_CPND1, (data >> 8) & 0xff, 1) + +//pnd +#define P33_GET_WKUP_PND() (P33_CON_GET(P3_WKUP_PND0) | (P33_CON_GET(P3_WKUP_PND1)<<8)) + +//akwup_en +#define P33_SET_AWKUP_EN(data) P33_CON_SET(P3_AWKUP_EN, 0, 8, data & 0xff) + +#define P33_OR_AWKUP_EN(data) p33_fast_access(P3_AWKUP_EN, data & 0xff, 1) + +//awkup_p_pnd +#define P33_GET_AWKUP_P_PND() (P33_CON_GET(P3_AWKUP_P_PND)) + +//awkup_n_pnd +#define P33_GET_AWKUP_N_PND() (P33_CON_GET(P3_AWKUP_N_PND)) + +//awkup_p_cpnd +#define P33_SET_AWKUP_P_CPND(data) p33_fast_access(P3_AWKUP_P_CPND, data & 0xff, 1) + +//awkup_n_cpnd +#define P33_SET_AWKUP_N_CPND(data) p33_fast_access(P3_AWKUP_N_CPND, data & 0xff, 1) + +//awkup_p_ie +#define P33_SET_AWKUP_P_IE(data) P33_CON_SET(P3_AWKUP_P_IE, 0, 8, data & 0xff) +#define P33_OR_AWKUP_P_IE(data) p33_fast_access(P3_AWKUP_P_IE, data & 0xff, 1) +#define P33_AND_AWKUP_P_IE(data) p33_fast_access(P3_AWKUP_P_IE, data & 0xff, 0) + +//awkup_n_ie +#define P33_SET_AWAKEUP_N_IE(data) P33_CON_SET(P3_AWKUP_N_IE, 0, 8, data & 0xff) +#define P33_OR_AWKUP_N_IE(data) p33_fast_access(P3_AWKUP_N_IE, data & 0xff, 1) +#define P33_AND_AWKUP_N_IE(data) p33_fast_access(P3_AWKUP_N_IE, data & 0xff, 0) + +#define CLEAN_GPIO_WAKEUP_PENDING() P33_SET_AWKUP_P_CPND(0xff); \ + P33_SET_AWKUP_N_CPND(0xff); \ + P33_SET_WKUP_CPND(0xffff); + +#define CLEAN_P33_WKUP_PENDING() P33_SET_AWKUP_P_CPND(0xff); \ + P33_SET_AWKUP_N_CPND(0xff); \ + P33_SET_WKUP_CPND(0xffff); \ + VLVD_PND_CLR(); \ + PCNT_PND_CLR() + +enum { + P3_WKUP_SRC_PCNT_OVF = 0, + P3_WKUP_SRC_PORT_EDGE, + P3_WKUP_SRC_ANA_EDGE, + P3_WKUP_SRC_VDDIO_LVD = 4, +}; + +#define P33_GET_WKUP_SRC() P33_CON_GET(P3_WKUP_SRC) + +#endif diff --git a/include_lib/driver/cpu/br28/asm/power/p33_sfr.h b/include_lib/driver/cpu/br28/asm/power/p33_sfr.h new file mode 100644 index 0000000..bd1884e --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/power/p33_sfr.h @@ -0,0 +1,249 @@ +#ifndef __BR28_P33__ +#define __BR28_P33__ +//////////////////////////////// + +#ifdef PMU_SYSTEM +#define P33_ACCESS(x) (*(volatile u32 *)(0xc000 + x*4)) +#else +#define P33_ACCESS(x) (*(volatile u32 *)(0xf20000 + 0xc000 + x*4)) +#endif + +#ifdef PMU_SYSTEM +#define RTC_ACCESS(x) (*(volatile u32 *)(0xd000 + x*4)) +#else +#define RTC_ACCESS(x) (*(volatile u32 *)(0xf20000 + 0xd000 + x*4)) +#endif + +//=========== +//===============================================================================// +// +// +// +//===============================================================================// +//............. 0x0000 - 0x000f............ +#define P3_IOV2_CON P33_ACCESS(0x00) + +//............. 0x0010 - 0x001f............ for analog others +#define P3_OSL_CON P33_ACCESS(0x10) +#define P3_VLVD_CON P33_ACCESS(0x11) +#define P3_RST_SRC P33_ACCESS(0x12) +#define P3_LRC_CON0 P33_ACCESS(0x13) +#define P3_LRC_CON1 P33_ACCESS(0x14) +#define P3_RST_CON0 P33_ACCESS(0x15) +#define P3_ANA_KEEP P33_ACCESS(0x16) +#define P3_VLD_KEEP P33_ACCESS(0x17) +#define P3_CLK_CON0 P33_ACCESS(0x18) +#define P3_ANA_READ P33_ACCESS(0x19) +#define P3_CHG_CON0 P33_ACCESS(0x1a) +#define P3_CHG_CON1 P33_ACCESS(0x1b) +#define P3_CHG_CON2 P33_ACCESS(0x1c) +#define P3_CHG_CON3 P33_ACCESS(0x1d) + +//............. 0x0020 - 0x002f............ for PWM LED +//#define P3_PWM_CON0 P33_ACCESS(0x20) +//#define P3_PWM_CON1 P33_ACCESS(0x21) +//#define P3_PWM_CON2 P33_ACCESS(0x22) +//#define P3_PWM_CON3 P33_ACCESS(0x23) +//#define P3_PWM_BRI_PRDL P33_ACCESS(0x24) +//#define P3_PWM_BRI_PRDH P33_ACCESS(0x25) +//#define P3_PWM_BRI_DUTY0L P33_ACCESS(0x26) +//#define P3_PWM_BRI_DUTY0H P33_ACCESS(0x27) +//#define P3_PWM_BRI_DUTY1L P33_ACCESS(0x28) +//#define P3_PWM_BRI_DUTY1H P33_ACCESS(0x29) +//#define P3_PWM_PRD_DIVL P33_ACCESS(0x2a) +//#define P3_PWM_DUTY0 P33_ACCESS(0x2b) +//#define P3_PWM_DUTY1 P33_ACCESS(0x2c) +//#define P3_PWM_DUTY2 P33_ACCESS(0x2d) +//#define P3_PWM_DUTY3 P33_ACCESS(0x2e) +//#define P3_PWM_CNT_RD P33_ACCESS(0x2f) + +//............. 0x0030 - 0x003f............ for PMU manager +#define P3_PMU_CON0 P33_ACCESS(0x30) + +#define P3_SFLAG0 P33_ACCESS(0x38) +#define P3_SFLAG1 P33_ACCESS(0x39) +#define P3_SFLAG2 P33_ACCESS(0x3a) +#define P3_SFLAG3 P33_ACCESS(0x3b) +//#define P3_SFLAG4 P33_ACCESS(0x3c) +//#define P3_SFLAG5 P33_ACCESS(0x3d) +//#define P3_SFLAG6 P33_ACCESS(0x3e) +//#define P3_SFLAG7 P33_ACCESS(0x3f) + +//............. 0x0040 - 0x004f............ for +#define P3_IVS_RD P33_ACCESS(0x40) +#define P3_IVS_SET P33_ACCESS(0x41) +#define P3_IVS_CLR P33_ACCESS(0x42) +#define P3_PVDD0_AUTO P33_ACCESS(0x43) +#define P3_PVDD1_AUTO P33_ACCESS(0x44) +#define P3_WKUP_DLY P33_ACCESS(0x45) +#define P3_VLVD_FLT P33_ACCESS(0x46) +#define P3_PINR_CON1 P33_ACCESS(0x47) +#define P3_PINR_CON P33_ACCESS(0x48) +#define P3_PCNT_CON P33_ACCESS(0x49) +#define P3_PCNT_SET0 P33_ACCESS(0x4a) +#define P3_PCNT_SET1 P33_ACCESS(0x4b) +#define P3_PCNT_DAT0 P33_ACCESS(0x4c) +#define P3_PCNT_DAT1 P33_ACCESS(0x4d) +#define P3_PVDD2_AUTO P33_ACCESS(0x4e) + +//............. 0x0050 - 0x005f............ for port wake up +#define P3_WKUP_EN0 P33_ACCESS(0x50) +#define P3_WKUP_EN1 P33_ACCESS(0x51) +#define P3_WKUP_EDGE0 P33_ACCESS(0x52) +#define P3_WKUP_EDGE1 P33_ACCESS(0x53) +#define P3_WKUP_LEVEL0 P33_ACCESS(0x54) +#define P3_WKUP_LEVEL1 P33_ACCESS(0x55) +#define P3_WKUP_PND0 P33_ACCESS(0x56) +#define P3_WKUP_PND1 P33_ACCESS(0x57) +#define P3_WKUP_CPND0 P33_ACCESS(0x58) +#define P3_WKUP_CPND1 P33_ACCESS(0x59) + +//............. 0x0060 - 0x006f............ for +#define P3_AWKUP_EN P33_ACCESS(0x60) +#define P3_AWKUP_P_IE P33_ACCESS(0x61) +#define P3_AWKUP_N_IE P33_ACCESS(0x62) +#define P3_AWKUP_LEVEL P33_ACCESS(0x63) +#define P3_AWKUP_INSEL P33_ACCESS(0x64) +#define P3_AWKUP_P_PND P33_ACCESS(0x65) +#define P3_AWKUP_N_PND P33_ACCESS(0x66) +#define P3_AWKUP_P_CPND P33_ACCESS(0x67) +#define P3_AWKUP_N_CPND P33_ACCESS(0x68) + +//............. 0x0070 - 0x007f............ for power gate +//#define P3_PGDR_CON0 P33_ACCESS(0x70) +//#define P3_PGDR_CON1 P33_ACCESS(0x71) +#define P3_PGSD_CON P33_ACCESS(0x72) +//#define P3_PGFS_CON P33_ACCESS(0x73) + +//............. 0x0080 - 0x008f............ for +#define P3_AWKUP_FLT0 P33_ACCESS(0x80) +#define P3_AWKUP_FLT1 P33_ACCESS(0x81) +#define P3_AWKUP_FLT2 P33_ACCESS(0x82) + +#define P3_APORT_SEL0 P33_ACCESS(0x88) +#define P3_APORT_SEL1 P33_ACCESS(0x89) +#define P3_APORT_SEL2 P33_ACCESS(0x8a) + +//............. 0x0090 - 0x009f............ for analog control +#define P3_ANA_CON0 P33_ACCESS(0x90) +#define P3_ANA_CON1 P33_ACCESS(0x91) +#define P3_ANA_CON2 P33_ACCESS(0x92) +#define P3_ANA_CON3 P33_ACCESS(0x93) +#define P3_ANA_CON4 P33_ACCESS(0x94) +#define P3_ANA_CON5 P33_ACCESS(0x95) +#define P3_ANA_CON6 P33_ACCESS(0x96) +#define P3_ANA_CON7 P33_ACCESS(0x97) +#define P3_ANA_CON8 P33_ACCESS(0x98) +#define P3_ANA_CON9 P33_ACCESS(0x99) +#define P3_ANA_CON10 P33_ACCESS(0x9a) +#define P3_ANA_CON11 P33_ACCESS(0x9b) +#define P3_ANA_CON12 P33_ACCESS(0x9c) +#define P3_ANA_CON13 P33_ACCESS(0x9d) +#define P3_ANA_CON14 P33_ACCESS(0x9e) +#define P3_ANA_CON15 P33_ACCESS(0x9f) + +//............. 0x00a0 - 0x00af............ +#define P3_PR_PWR P33_ACCESS(0xa0) +#define P3_L5V_CON0 P33_ACCESS(0xa1) +#define P3_L5V_CON1 P33_ACCESS(0xa2) + +#define P3_LS_P11 P33_ACCESS(0xa4) + +#define P3_RVD_CON P33_ACCESS(0xa7) +#define P3_WKUP_SRC P33_ACCESS(0xa8) + +#define P3_PMU_DBG_CON P33_ACCESS(0xaa) +#define P3_ANA_KEEP1 P33_ACCESS(0xab) + +//............. 0x00b0 - 0x00bf............ for EFUSE +#define P3_EFUSE_CON0 P33_ACCESS(0xb0) +#define P3_EFUSE_CON1 P33_ACCESS(0xb1) +#define P3_EFUSE_RDAT P33_ACCESS(0xb2) + +#define P3_FUNC_EN P33_ACCESS(0xb8) + +//............. 0x00c0 - 0x00cf............ for port input select +#define P3_PORT_SEL0 P33_ACCESS(0xc0) +#define P3_PORT_SEL1 P33_ACCESS(0xc1) +#define P3_PORT_SEL2 P33_ACCESS(0xc2) +#define P3_PORT_SEL3 P33_ACCESS(0xc3) +#define P3_PORT_SEL4 P33_ACCESS(0xc4) +#define P3_PORT_SEL5 P33_ACCESS(0xc5) +#define P3_PORT_SEL6 P33_ACCESS(0xc6) +#define P3_PORT_SEL7 P33_ACCESS(0xc7) +#define P3_PORT_SEL8 P33_ACCESS(0xc8) +#define P3_PORT_SEL9 P33_ACCESS(0xc9) +#define P3_PORT_SEL10 P33_ACCESS(0xca) +#define P3_PORT_SEL11 P33_ACCESS(0xcb) +#define P3_PORT_SEL12 P33_ACCESS(0xcc) +#define P3_PORT_SEL13 P33_ACCESS(0xcd) +#define P3_PORT_SEL14 P33_ACCESS(0xce) +#define P3_PORT_SEL15 P33_ACCESS(0xcf) + +//............. 0x00d0 - 0x00df............ +#define P3_LS_IO_DLY P33_ACCESS(0xd0) //TODO: check sync with verilog head file chip_def.v LEVEL_SHIFTER +#define P3_LS_IO_ROM P33_ACCESS(0xd1) +#define P3_LS_ADC P33_ACCESS(0xd2) +#define P3_LS_AUDIO P33_ACCESS(0xd3) +#define P3_LS_RF P33_ACCESS(0xd4) +#define P3_LS_PLL P33_ACCESS(0xd5) + + +//===============================================================================// +// +// p33 rtcvdd +// +//===============================================================================// +//#define RTC_SFR_BEGIN 0x1000 + + + +//............. 0x0080 - 0x008f............ for RTC +#define R3_ALM_CON RTC_ACCESS((0x80)) + +#define R3_RTC_CON0 RTC_ACCESS((0x84)) +#define R3_RTC_CON1 RTC_ACCESS((0x85)) +#define R3_RTC_DAT0 RTC_ACCESS((0x86)) +#define R3_RTC_DAT1 RTC_ACCESS((0x87)) +#define R3_RTC_DAT2 RTC_ACCESS((0x88)) +#define R3_RTC_DAT3 RTC_ACCESS((0x89)) +#define R3_RTC_DAT4 RTC_ACCESS((0x8a)) +#define R3_ALM_DAT0 RTC_ACCESS((0x8b)) +#define R3_ALM_DAT1 RTC_ACCESS((0x8c)) +#define R3_ALM_DAT2 RTC_ACCESS((0x8d)) +#define R3_ALM_DAT3 RTC_ACCESS((0x8e)) +#define R3_ALM_DAT4 RTC_ACCESS((0x8f)) + +//............. 0x0090 - 0x009f............ for PORT control +#define R3_WKUP_EN RTC_ACCESS((0x90)) +#define R3_WKUP_EDGE RTC_ACCESS((0x91)) +#define R3_WKUP_CPND RTC_ACCESS((0x92)) +#define R3_WKUP_PND RTC_ACCESS((0x93)) +#define R3_WKUP_FLEN RTC_ACCESS((0x94)) +#define R3_PORT_FLT RTC_ACCESS((0x95)) + +#define R3_PR_IN RTC_ACCESS((0x98)) +#define R3_PR_OUT RTC_ACCESS((0x99)) +#define R3_PR_DIR RTC_ACCESS((0x9a)) +#define R3_PR_DIE RTC_ACCESS((0x9b)) +#define R3_PR_PU RTC_ACCESS((0x9c)) +#define R3_PR_PD RTC_ACCESS((0x9d)) +#define R3_PR_HD RTC_ACCESS((0x9e)) + +//............. 0x00a0 - 0x00af............ for system +#define R3_TIME_CON RTC_ACCESS((0xa0)) +#define R3_TIME_CPND RTC_ACCESS((0xa1)) +#define R3_TIME_PND RTC_ACCESS((0xa2)) + +#define R3_ADC_CON RTC_ACCESS((0xa4)) +#define R3_OSL_CON RTC_ACCESS((0xa5)) + +#define R3_WKUP_SRC RTC_ACCESS((0xa8)) +#define R3_RST_SRC RTC_ACCESS((0xa9)) + +#define R3_RST_CON RTC_ACCESS((0xab)) +#define R3_CLK_CON RTC_ACCESS((0xac)) + +#endif + + diff --git a/include_lib/driver/cpu/br28/asm/power/power_api.h b/include_lib/driver/cpu/br28/asm/power/power_api.h new file mode 100644 index 0000000..dfa7ce8 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/power/power_api.h @@ -0,0 +1,336 @@ +#ifndef __POWER_API_H__ +#define __POWER_API_H__ + +#define PMU_NEW_FLOW 0 +#define TRIM_WVDD BIT(0) +#define TRIM_PVDD BIT(1) +#define TRIM_IOVDD BIT(2) + +//=========================电源参数配置================================== +struct low_power_param { + u8 config; //低功耗使能,蓝牙&&系统空闲可进入低功耗 + u8 osc_type; //低功耗晶振类型,btosc/lrc + u32 btosc_hz; //蓝牙晶振频率 + + //vddiow_lev不需要配置,sleep、softoff模式会保持电压,除非配置使用nkeep_vddio(功耗相差不大) + u8 vddiom_lev; //vddiom + u8 vddiow_lev; //vddiow + u8 nkeep_vddio; //softoff模式下不保持vddio + + u32 osc_delay_us; //低功耗晶振起振延时,为预留配置。 + u8 rtc_clk; //rtc时钟源,softoff模式根据此配置是否保持住相应时钟 + u8 lpctmu_en; //低功耗触摸,softoff模式根据此配置是否保持住该模块 + + u8 mem_init_con; //初始化ram电源 + u8 mem_lowpower_con; //低功耗ram电源 + u8 rvdd2pvdd; //低功耗外接dcdc + u8 pvdd_dcdc_port; + + u8 lptmr_flow; //低功耗参数由用户配置 + u32 t1; + u32 t2; + u32 t3_lrc; + u32 t4_lrc; + u32 t3_btosc; + u32 t4_btosc; + + u8 flash_pg; //iomc: 外置flash power gate + + u8 btosc_disable; + u8 delay_us; + + u8 vddio_keep_type_pd; //sleep keep vddio使用类型 + u8 vddio_keep_type_sf; //soff keep vddio使用类型 +}; + +//config +#define SLEEP_EN BIT(0) +#define DEEP_SLEEP_EN BIT(1) + +enum { + VDDIO_KEEP_TYPE_TRIM = 0,//vddio keep使用trim值:默认 + VDDIO_KEEP_TYPE_PG, //vddio keep使用 mvvdio:功耗代价100ua +}; + +//osc_type +enum { + OSC_TYPE_LRC = 0, + OSC_TYPE_BT_OSC, +}; + +//DCVDD电源模式 +enum { + PWR_LDO15, + PWR_DCDC15, +}; + +//PVDD电源模式 +enum PVDD_MODE { + PWR_PVDD_LDO, + PWR_PVDD_DCDC, +}; + +//==============================软关机参数配置============================ +//软关机会复位寄存器,该参数为传给rom配置的参数。 +struct soft_flag0_t { + u8 wdt_dis: 1; + u8 poweroff: 1; + u8 is_port_b: 1; + u8 lvd_en: 1; + u8 pmu_en: 1; + u8 iov2_ldomode: 1; + u8 res: 2; +}; + +struct soft_flag1_t { + u8 usbdp: 2; + u8 usbdm: 2; + u8 uart_key_port: 1; + u8 ldoin: 3; +}; + +struct soft_flag2_t { + u8 pg2: 4; + u8 pg3: 4; +}; + +struct soft_flag3_t { + u8 pg4: 4; + u8 res: 4; +}; + +struct soft_flag4_t { + u8 fast_boot: 1; + u8 flash_stable_delay_sel: 2; + u8 res: 5; +}; + +struct soft_flag5_t { + u8 mvddio: 3; + u8 wvbg: 4; + u8 res: 1; +}; + +struct boot_soft_flag_t { + union { + struct soft_flag0_t boot_ctrl; + u8 value; + } flag0; + union { + struct soft_flag1_t misc; + u8 value; + } flag1; + union { + struct soft_flag2_t pg2_pg3; + u8 value; + } flag2; + union { + struct soft_flag3_t pg4_res; + u8 value; + } flag3; + union { + struct soft_flag4_t fast_boot_ctrl; + u8 value; + } flag4; + union { + struct soft_flag5_t level; + u8 value; + } flag5; +}; + +enum soft_flag_io_stage { + SOFTFLAG_HIGH_RESISTANCE, + SOFTFLAG_PU, + SOFTFLAG_PD, + + SOFTFLAG_OUT0, + SOFTFLAG_OUT0_HD0, + SOFTFLAG_OUT0_HD, + SOFTFLAG_OUT0_HD0_HD, + + SOFTFLAG_OUT1, + SOFTFLAG_OUT1_HD0, + SOFTFLAG_OUT1_HD, + SOFTFLAG_OUT1_HD0_HD, +}; + +//==============================电源接口============================ + +#define AT_VOLATILE_RAM_CODE_POWER AT(.power_driver.text.cache.L1) +#define AT_VOLATILE_CACHE_CODE_POWER AT(.power_driver.text.cache.L2) + +void power_set_mode(u8 mode); + +void power_set_pvdd_mode(enum PVDD_MODE mode); + +u8 get_pvdd_dcdc_cfg(); + +void power_init(const struct low_power_param *param); + +void power_keep_dacvdd_en(u8 en); + +void sdpg_config(int enable); + +void p11_init(void); + +u8 get_wvdd_trim_level(); + +u8 get_pvdd_level(); + +u8 get_pvdd_trim_level(); + +u8 get_miovdd_trim_level(); + +u8 get_wiovdd_trim_level(); + +void store_pmu_trim_value_to_vm(u8 wvdd_level, u8 pvdd_level, u8 miovdd_lev, u8 wiovdd_lev); + +u8 load_pmu_trim_value_from_vm(); + +void volatage_trim_init(); + +//==============================sleep接口============================ +//注意:所有接口在临界区被调用,请勿使用阻塞操作 +//sleep模式介绍 +//1.所有数字模块停止,包括cpu、periph、audio、rf等 +//2.所有模拟模块停止,包括pll、btosc、rc等 +//3.只保留pmu模块 + +//light_sleep: 不切电源域 +//normal_sleep: dvdd低电 +//deepsleep:dvdd掉电 + +//----------------低功耗线程查询是否满足低功耗状态, 被动等待------------ +struct low_power_operation { + + const char *name; + + u32(*get_timeout)(void *priv); + + void (*suspend_probe)(void *priv); + + void (*suspend_post)(void *priv, u32 usec); + + void (*resume)(void *priv, u32 usec); + + void (*resume_post)(void *priv, u32 usec); +}; + +enum LOW_POWER_LEVEL { + LOW_POWER_MODE_LIGHT_SLEEP = 1, + LOW_POWER_MODE_SLEEP, + LOW_POWER_MODE_DEEP_SLEEP, +}; + +typedef u8(*idle_handler_t)(void); +typedef enum LOW_POWER_LEVEL(*level_handler_t)(void); + +typedef u8(*idle_handler_t)(void); + +struct lp_target { + char *name; + level_handler_t level; + idle_handler_t is_idle; +}; + +#define REGISTER_LP_TARGET(target) \ + const struct lp_target target sec(.lp_target) + + +extern const struct lp_target lp_target_begin[]; +extern const struct lp_target lp_target_end[]; + +#define list_for_each_lp_target(p) \ + for (p = lp_target_begin; p < lp_target_end; p++) + + +//--------------低功耗线程请求进入低功耗, 主动发出------------ +struct lp_request { + char *name; + u8(*request_enter)(u32 timeout); + u8(*request_exit)(u32 timeout); +}; + +#define REGISTER_LP_REQUEST(target) \ + const struct lp_request target sec(.lp_request) + +extern const struct lp_request lp_request_begin[]; +extern const struct lp_request lp_request_end[]; + +#define list_for_each_lp_request(p) \ + for (p = lp_request_begin; p < lp_request_end; p++) + +//-----------------------深度睡眠处理-------------------------- +struct deepsleep_target { + char *name; + u8(*enter)(void); + u8(*exit)(void); +}; + +#define DEEPSLEEP_TARGET_REGISTER(target) \ + const struct deepsleep_target target sec(.deepsleep_target) + + +extern const struct deepsleep_target deepsleep_target_begin[]; +extern const struct deepsleep_target deepsleep_target_end[]; + +#define list_for_each_deepsleep_target(p) \ + for (p = deepsleep_target_begin; p < deepsleep_target_end; p++) + + +#define NEW_BASEBAND_COMPENSATION 0 + +u32 __tus_carry(u32 x); + +#define power_is_poweroff_post() 0 + +void *low_power_get(void *priv, const struct low_power_operation *ops); + +void low_power_put(void *priv); + +void low_power_sys_request(void *priv); + +void *low_power_sys_get(void *priv, const struct low_power_operation *ops); + +void low_power_sys_put(void *priv); + +u8 is_low_power_mode(enum LOW_POWER_LEVEL level); + +u8 low_power_sys_is_idle(void); + +s32 low_power_trace_drift(u32 usec); + +void low_power_reset_osc_type(u8 type); + +u8 low_power_get_default_osc_type(void); + +u8 low_power_get_osc_type(void); + +void low_power_on(void); + +void low_power_request(void); + +u8 low_power_sys_request_enter(u32 timeout); + +u8 low_power_sys_request_exit(u32 timeout); + +u32 get_rch_hz(); + +void cap_rch_enable(); + +void cap_rch_disable(); + +//==============================soft接口============================ + + +void power_set_soft_poweroff(); + +void power_set_soft_poweroff_advance(); + +void mask_softflag_config(const struct boot_soft_flag_t *softflag); + +void power_set_callback(u8 mode, void (*powerdown_enter)(u8 step), void (*powerdown_exit)(u32), void (*soft_poweroff_enter)(void)); + + + +#endif diff --git a/include_lib/driver/cpu/br28/asm/power/power_compat.h b/include_lib/driver/cpu/br28/asm/power/power_compat.h new file mode 100644 index 0000000..a9244e6 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/power/power_compat.h @@ -0,0 +1,8 @@ +#ifndef __POWER_COMPAT_H__ +#define __POWER_COMPAT_H__ + +//compatibility + + + +#endif diff --git a/include_lib/driver/cpu/br28/asm/power/power_port.h b/include_lib/driver/cpu/br28/asm/power/power_port.h new file mode 100644 index 0000000..3922ffd --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/power/power_port.h @@ -0,0 +1,154 @@ +#ifndef __POWER_PORT_H__ +#define __POWER_PORT_H__ + +#define NO_CONFIG_PORT (-1) +enum { + PORTA_GROUP = 0, + PORTB_GROUP, + PORTC_GROUP, + PORTD_GROUP, + PORTE_GROUP, + PORTG_GROUP, + PORTP_GROUP, +}; + +struct gpio_value { + u16 gpioa; + u16 gpiob; + u16 gpioc; + u16 gpiod; + u16 gpioe; + u16 gpiog; + u16 gpiop; + u16 gpiousb; +}; + +#define _PORT(p) JL_PORT##p +#define SPI_PORT(p) _PORT(p) + + + +// | func\port | A | B | C | +// |-----------|------|------|------| +// | CS | PD3 | PG4 | PC3 | +// | CLK | PD0 | PD0 | PC1 | +// | DO(D0) | PD1 | PD1 | PC2 | +// | DI(D1) | PD2 | PG3 | PC4 | +// | WP(D2) | PD5 | PG2 | PC5 | +// | HOLD(D3) | PD6 | PD6 | PC0 | + +#define PORT_SPI0_PWRA D +#define SPI0_PWRA 4 + +#define PORT_SPI0_CSA D +#define SPI0_CSA 3 + +#define PORT_SPI0_CLKA D +#define SPI0_CLKA 0 + +#define PORT_SPI0_DOA D +#define SPI0_DOA 1 + +#define PORT_SPI0_DIA D +#define SPI0_DIA 2 + +#define PORT_SPI0_D2A D +#define SPI0_D2A 5 + +#define PORT_SPI0_D3A D +#define SPI0_D3A 6 + +#define SPI0_PWR_A IO_PORTD_04 +#define SPI0_CS_A IO_PORTD_03 +#define SPI0_CLK_A IO_PORTD_00 +#define SPI0_DO_D0_A IO_PORTD_01 +#define SPI0_DI_D1_A IO_PORTD_02 +#define SPI0_WP_D2_A IO_PORTD_05 +#define SPI0_HOLD_D3_A IO_PORTD_06 + + +//////////////////////////////////////////////////////////////////////////////// +#define PORT_SPI0_PWRB D +#define SPI0_PWRB 4 + +#define PORT_SPI0_CSB G +#define SPI0_CSB 4 + +#define PORT_SPI0_CLKB D +#define SPI0_CLKB 0 + +#define PORT_SPI0_DOB D +#define SPI0_DOB 1 + +#define PORT_SPI0_DIB G +#define SPI0_DIB 3 + +#define PORT_SPI0_D2B G +#define SPI0_D2B 2 + +#define PORT_SPI0_D3B D +#define SPI0_D3B 6 + +#define SPI0_PWR_B IO_PORTD_04 +#define SPI0_CS_B IO_PORTG_04 +#define SPI0_CLK_B IO_PORTD_00 +#define SPI0_DO_D0_B IO_PORTD_01 +#define SPI0_DI_D1_B IO_PORTG_03 +#define SPI0_WP_D2_B IO_PORTG_02 +#define SPI0_HOLD_D3_B IO_PORTD_06 + +//////////////////////////////////////////////////////////////////////////////// +#define PORT_SPI0_PWRC C +#define SPI0_PWRC 8 + +#define PORT_SPI0_CSC C +#define SPI0_CSC 3 + +#define PORT_SPI0_CLKC C +#define SPI0_CLKC 1 + +#define PORT_SPI0_DOC C +#define SPI0_DOC 2 + +#define PORT_SPI0_DIC C +#define SPI0_DIC 4 + +#define PORT_SPI0_D2C C +#define SPI0_D2C 5 + +#define PORT_SPI0_D3C C +#define SPI0_D3C 0 + +#define SPI0_PWR_C IO_PORTC_08 +#define SPI0_CS_C IO_PORTC_03 +#define SPI0_CLK_C IO_PORTC_01 +#define SPI0_DO_D0_C IO_PORTC_02 +#define SPI0_DI_D1_C IO_PORTC_04 +#define SPI0_WP_D2_C IO_PORTC_05 +#define SPI0_HOLD_D3_C IO_PORTC_00 + +//////////////////////////////////////////////////////////////////////// + +#define PSRAM_D0A IO_PORTE_00 +#define PSRAM_D1A IO_PORTE_01 +#define PSRAM_D2A IO_PORTE_02 +#define PSRAM_D3A IO_PORTE_05 + +u32 get_sfc_port(void); +u8 get_sfc_bit_mode(); +u8 get_sfc1_bit_mode(); +void port_init(void); +void port_protect(u16 *port_group, u32 port_num); + +u8 WSIG_to_PANA(u8 wsig); +u8 PANA_to_WSIG(u8 iomap); + +void soff_gpio_protect(u32 gpio); +void board_set_soft_poweroff_common(void *priv); + +void sleep_gpio_protect(u32 gpio); +void sleep_enter_callback_common(void *priv); +void sleep_exit_callback_common(void *priv); + +#endif + diff --git a/include_lib/driver/cpu/br28/asm/power/power_reset.h b/include_lib/driver/cpu/br28/asm/power/power_reset.h new file mode 100644 index 0000000..6d457e9 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/power/power_reset.h @@ -0,0 +1,59 @@ +#ifndef __POWER_RESET_H__ +#define __POWER_RESET_H__ + +/* + *复位原因包括两种 + 1.系统复位源: p33 p11 主系统 + 2.自定义复位源:断言、异常等 + */ +enum RST_REASON { + /*主系统*/ + MSYS_P11_RST, //P11复位 + MSYS_DVDD_POR_RST, //DVDD上电 + MSYS_SOFT_RST, //主系统软件复位 + MSYS_P2M_RST, //低功耗唤醒复位(softoff advance && deepsleep) + MSYS_POWER_RETURN, //主系统未被复位 + + /*P11*/ + P11_PVDD_POR_RST, //pvdd上电 + P11_IVS_RST, //低功耗唤醒复位(softoff legacy) + P11_P33_RST, //p33复位 + P11_WDT_RST, //看门狗复位 + P11_SOFT_RST, //软件复位 + P11_MSYS_RST, //主系统复位P11 + P11_POWER_RETURN, //P11系统未被复位 + + /*P33*/ + P33_VDDIO_POR_RST, //vddio上电复位(电池/vpwr供电) + P33_VDDIO_LVD_RST, //vddio低压复位、上电复位(电池/vpwr供电) + P33_VCM_RST, //vcm高电平短接复位 + P33_PPINR_RST, //数字io输入长按复位 + P33_P11_RST, //p11系统复位p33,rset_mask=0 + P33_SOFT_RST, //p33软件复位,一般软件复位指此系统复位源,所有系统会直接复位。 + P33_PPINR1_RST, //模拟io输入长按复位,包括charge_full、vatch、ldoint、vabt_det + P33_POWER_RETURN, //p33系统未被复位。 + + //SUB + P33_EXCEPTION_SOFT_RST, //异常软件复位 + P33_ASSERT_SOFT_RST, //断言软件复位 + P33_XOSC_RESUME_ERR_RST, //快速起振恢复失败软件复位 + P33_LPTMR_TIMEOUT_RST, //LPTMR软件复位 +}; + +void power_reset_close(); + +void reset_source_dump(void); + +void p33_soft_reset(void); + +void set_reset_source_value(enum RST_REASON index); + +u32 get_reset_source_value(void); + +u8 is_reset_source(enum RST_REASON index); + +int cpu_reset_by_soft(); + +#endif + + diff --git a/include_lib/driver/cpu/br28/asm/power/power_wakeup.h b/include_lib/driver/cpu/br28/asm/power/power_wakeup.h new file mode 100644 index 0000000..638ae6b --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/power/power_wakeup.h @@ -0,0 +1,74 @@ +#ifndef __POWER_WAKEUP_H__ +#define __POWER_WAKEUP_H__ + +enum WAKEUP_REASON { + //WAKEUP + PWR_WK_REASON_PLUSE_CNT_OVERFLOW, //pcnt唤醒复位 + PWR_WK_REASON_P11, //P11唤醒复位 + PWR_WK_REASON_LPCTMU, //触摸唤醒复位 + PWR_WK_REASON_PORT_EDGE, //数字io输入边沿唤醒复位 + PWR_WK_REASON_ANA_EDGE, //模拟io输入边沿唤醒复位 + PWR_WK_REASON_VDDIO_LVD, //vddio lvd唤醒复位 + PWR_WK_REASON_EDGE_INDEX0, //p33 index0 io唤醒复位 + PWR_WK_REASON_EDGE_INDEX1, //p33 index1 io唤醒复位 + PWR_WK_REASON_EDGE_INDEX2, //p33 index2 io唤醒复位 + PWR_WK_REASON_EDGE_INDEX3, //p33 index3 io唤醒复位 + PWR_WK_REASON_EDGE_INDEX4, //p33 index4 io唤醒复位 + PWR_WK_REASON_EDGE_INDEX5, //p33 index5 io唤醒复位 + PWR_WK_REASON_EDGE_INDEX6, //p33 index6 io唤醒复位 + PWR_WK_REASON_EDGE_INDEX7, //p33 index7 io唤醒复位 + PWR_WK_REASON_EDGE_INDEX8, //p33 index8 io唤醒复位 + PWR_WK_REASON_EDGE_INDEX9, //p33 index9 io唤醒复位 + PWR_WK_REASON_EDGE_INDEX10, //p33 index10 io唤醒复位 + PWR_WK_REASON_EDGE_INDEX11, //p33 index11 io唤醒复位 + PWR_ANA_WK_REASON_FALLINIG_EDGE_LDOIN, //LDO5V上升沿唤醒复位 + PWR_ANA_WK_REASON_RISING_EDGE_LDOIN, //LDO5V下降沿唤醒复位 + PWR_ANA_WK_REASON_FALLING_EDGE_VBATCH, //VBATCH上升降沿唤醒复位 + PWR_ANA_WK_REASON_RISING_EDGE_VBATCH, //VBATCH下降沿唤醒复位 + PWR_RTC_WK_REASON_ALM, //RTC闹钟唤醒复位 + PWR_RTC_WK_REASON_256HZ, //RTC 256Hz时基唤醒复位 + PWR_RTC_WK_REASON_64HZ, //RTC 64Hz时基唤醒复位 + PWR_RTC_WK_REASON_2HZ, //RTC 2Hz时基唤醒复位 + PWR_RTC_WK_REASON_1HZ, //RTC 1Hz时基唤醒复位 +}; + +//=========================唤醒参数配置================================== + +struct port_wakeup { + u8 iomap; //唤醒io + u8 pullup_down_enable; //上下拉是否使能 + POWER_WKUP_EDGE edge; //唤醒边沿条件 + POWER_WKUP_FLT filter; //滤波参数,数字io输入没有滤波可配制 +}; + +struct wakeup_param { + //数字io输入 + const struct port_wakeup *port[MAX_WAKEUP_PORT]; + //模拟io输入 + const struct port_wakeup *aport[MAX_WAKEUP_ANA_PORT]; +}; + +//=========================唤醒接口================================== +void power_wakeup_index_enable(u8 index, u8 enable); +void power_wakeup_gpio_enable(u8 gpio, u8 enable); +void power_wakeup_gpio_edge(u8 gpio, POWER_WKUP_EDGE edge); + +void power_awakeup_index_enable(u8 index, u8 enable); +void power_awakeup_gpio_enable(u8 gpio, u8 enable); +void power_awakeup_gpio_edge(u8 gpio, POWER_WKUP_EDGE edge); + +void power_wakeup_set_callback(void (*wakeup_callback)(u8 index, u8 gpio)); +void power_awakeup_set_callback(void (*wakeup_callback)(u8 index, u8 gpio, POWER_WKUP_EDGE edge)); + +void port_edge_wkup_set_callback_by_index(u8 index, void (*wakeup_callback)(u8 index, u8 gpio)); +void aport_edge_wkup_set_callback_by_index(u8 index, void (*wakeup_callback)(u8 index, u8 gpio, POWER_WKUP_EDGE edge)); + +void power_wakeup_init(const struct wakeup_param *param); + +u8 is_wakeup_source(enum WAKEUP_REASON index); + +void power_wakeup_reason_dump(); + +u8 is_ldo5v_wakeup(void); + +#endif diff --git a/include_lib/driver/cpu/br28/asm/power/rtc_app.h b/include_lib/driver/cpu/br28/asm/power/rtc_app.h new file mode 100644 index 0000000..07cd749 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/power/rtc_app.h @@ -0,0 +1,55 @@ +#ifndef __RTC_APP_H__ +#define __RTC_APP_H__ + +enum { + R3_WKUP_SRC_ALM = 0, + R3_WKUP_SRC_256HZ = 4, + R3_WKUP_SRC_64HZ, + R3_WKUP_SRC_2HZ, + R3_WKUP_SRC_1HZ, +}; + + +/************************R3_ALM_CON*****************************/ +#define ALM_ALMOUT(a) P33_CON_SET(R3_ALM_CON, 7, 1, a) + +#define ALM_CLK_SEL(a) P33_CON_SET(R3_ALM_CON, 2, 3, a) + +#define ALM_ALMEN(a) P33_CON_SET(R3_ALM_CON, 0, 1, a) + +//Macro for CLK_SEL +enum { + CLK_SEL_32K = 1, + CLK_SEL_12M, + CLK_SEL_24M, + CLK_SEL_LRC, +}; + +/************************R3_RTC_CON0*****************************/ +#define RTC_ALM_RDEN(a) P33_CON_SET(R3_RTC_CON0, 5, 1, a) + +#define RTC_RTC_RDEN(a) P33_CON_SET(R3_RTC_CON0, 4, 1, a) + +#define RTC_ALM_WREN(a) P33_CON_SET(R3_RTC_CON0, 1, 1, a) + +#define RTC_RTC_WREN(a) P33_CON_SET(R3_RTC_CON0, 0, 1, a) + +/************************R3_OSL_CON*****************************/ +#define OSL_X32XS(a) P33_CON_SET(R3_OSL_CON, 4, 2, a) + +#define OSL_X32TS(a) P33_CON_SET(R3_OSL_CON, 2, 1, a) + +#define OSL_X32OS(a) P33_CON_SET(R3_OSL_CON, 1, 1, a) + +#define OSL_X32ES(a) P33_CON_SET(R3_OSL_CON, 0, 1, a) + +/************************R3_TIME_CPND*****************************/ +#define TIME_256HZ_CPND(a) P33_CON_SET(R3_TIME_CPND, 0, 1, a) + +#define TIME_64HZ_CPND(a) P33_CON_SET(R3_TIME_CPND, 1, 1, a) + +#define TIME_2HZ_CPND(a) P33_CON_SET(R3_TIME_CPND, 2, 1, a) + +#define TIME_1HZ_CPND(a) P33_CON_SET(R3_TIME_CPND, 3, 1, a) + +#endif diff --git a/include_lib/driver/cpu/br28/asm/power_interface.h b/include_lib/driver/cpu/br28/asm/power_interface.h new file mode 100644 index 0000000..e76f490 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/power_interface.h @@ -0,0 +1,23 @@ +#ifndef POWER_INTERFACE_H +#define POWER_INTERFACE_H + +#include "generic/typedef.h" + +#include "asm/power/p33.h" + +#include "asm/power/p11.h" + +#include "asm/power/power_api.h" + +#include "asm/power/power_port.h" + +#include "asm/power/power_wakeup.h" + +#include "asm/power/power_reset.h" + +#include "asm/power/power_compat.h" + +#include "asm/power/lp_ipc.h" + + +#endif diff --git a/include_lib/driver/cpu/br28/asm/pwm_led.h b/include_lib/driver/cpu/br28/asm/pwm_led.h new file mode 100644 index 0000000..970f6cd --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/pwm_led.h @@ -0,0 +1,233 @@ +#ifndef _PWM_LED_H_ +#define _PWM_LED_H_ + +/******************************************************************* +* 本文件为LED灯配置的接口头文件 +* +* 约定: +* 1)两盏灯为单IO双LED接法; +* 2)LED0: RLED, 蓝色, 低电平亮灯; +* 3)LED1: BLED, 红色, 高电平亮灯; +*********************************************************************/ + +// LED实现的效果有: +// 1.两盏LED全亮; +// 2.LED单独亮灭; +// 3.LED单独慢闪和快闪; +// 4.LED 5s内单独闪一次和两次; +// 5.LED交替快闪和慢闪; +// 6.LED单独呼吸; +// 7.LED交替呼吸 + +/* + * LED各个效果可供配置以下参数, 请按照参数后面的注释说明的范围进行配置 + */ + +//#define PWM_LED_TWO_IO_SUPPORT //定义该宏会支持两个IO推灯模式, 默认关闭 + +#define CFG_LED0_LIGHT 200 //10 ~ 500, 值越大, (红灯)亮度越高 +#define CFG_LED1_LIGHT 200 //10 ~ 500, 值越大, (蓝灯)亮度越高 + +#define CFG_SINGLE_FAST_FLASH_FREQ 500 //LED单独快闪速度, ms闪烁一次(100 ~ 1000) +#define CFG_SINGLE_FAST_LIGHT_TIME 100 //单灯快闪灯亮持续时间, 单位ms + +#define CFG_SINGLE_SLOW_FLASH_FREQ 2000 //LED单独慢闪速度, ms闪烁一次(1000 ~ 20000) +#define CFG_SINGLE_SLOW_LIGHT_TIME 100 //单灯慢闪灯亮持续时间, 单位ms + +#define CFG_DOUBLE_FAST_FLASH_FREQ 500 //LED交替快闪速度, ms闪烁一次(100 ~ 1000) +#define CFG_DOUBLE_SLOW_FLASH_FREQ 2000 //LED交替慢闪速度, ms闪烁一次(1000 ~ 20000) + +/***************** LED0/LED1单独每隔5S单闪时, 可供调节参数 ********************/ +#define CFG_LED_5S_FLASH_LIGHT_TIME 100 //LED 5S 闪烁时灯亮持续时间, 单位ms + +/***************** 呼吸模式配置参数, 可供调节参数 ********************/ +#define CFG_LED_BREATH_TIME 1000 //呼吸时间灭->亮->灭, 单位ms +#define CFG_LED0_BREATH_BRIGHT 300 //呼吸亮度, 范围: 0 ~ 500 +#define CFG_LED1_BREATH_BRIGHT 300 //呼吸亮度, 范围: 0 ~ 500 +#define CFG_LED_BREATH_BLINK_TIME 1000 //灭灯延时, 单位ms + + +enum pwm_led_clk_source { + PWM_LED_CLK_RESERVED0, //PWM_LED_CLK_OSC32K, no use + PWM_LED_CLK_RC32K, //use + PWM_LED_CLK_RESERVED1, //PWM_LED_CLK_BTOSC_12M, no use + PWM_LED_CLK_RESERVED2, //PWM_LED_CLK_RCLK_250K, no use + PWM_LED_CLK_BTOSC_24M, //use +}; + +enum pwm_led_mode { + PWM_LED_MODE_START, + + PWM_LED_ALL_OFF, //mode1: 全灭 + PWM_LED_ALL_ON, //mode2: 全亮 + + PWM_LED0_ON, //mode3: 蓝亮 + PWM_LED0_OFF, //mode4: 蓝灭 + PWM_LED0_SLOW_FLASH, //mode5: 蓝慢闪 + PWM_LED0_FAST_FLASH, //mode6: 蓝快闪 + PWM_LED0_DOUBLE_FLASH_5S, //mode7: 蓝灯5秒连闪两下 + PWM_LED0_ONE_FLASH_5S, //mode8: 蓝灯5秒连闪1下 + + PWM_LED1_ON, //mode9: 红亮 + PWM_LED1_OFF, //mode10: 红灭 + PWM_LED1_SLOW_FLASH, //mode11: 红慢闪 + PWM_LED1_FAST_FLASH, //mode12: 红快闪 + PWM_LED1_DOUBLE_FLASH_5S, //mode13: 红灯5秒连闪两下 + PWM_LED1_ONE_FLASH_5S, //mode14: 红灯5秒闪1下 + + PWM_LED0_LED1_FAST_FLASH, //mode15: 红蓝交替闪(快闪) + PWM_LED0_LED1_SLOW_FLASH, //mode16: 红蓝交替闪(慢闪) + + PWM_LED0_BREATHE, //mode17: 蓝灯呼吸灯模式 + PWM_LED1_BREATHE, //mode18: 红灯呼吸灯模式 + PWM_LED0_LED1_BREATHE, //mode19: 红蓝交替呼吸灯模式 + + PWM_LED_MODE_END, + + PWM_LED1_FLASH_THREE, //自定义状态,不能通过pmd_led_mode去设置 + PWM_LED0_FLASH_THREE, //自定义状态,不能通过pmd_led_mode去设置 + + PWM_LED_USER_DEFINE_BEGIN = 0x50, + PWM_LED_USER_DEFINE_MODE0, //用户自定义模式0: + PWM_LED_USER_DEFINE_END, + + PWM_LED_NULL = 0xFF, +}; + +struct pwm_led_two_io_mode { + u8 two_io_mode_enable; + u8 led0_pin; + u8 led1_pin; +}; +enum led_io_mode { + LED_ONE_IO_MODE, + LED_TWO_IO_MODE, +}; + +struct one_io_cfg { + u8 pin; +}; + +struct two_io_cfg { + u8 pin0; + u8 pin1; +}; + +union io_mode_cfg { + struct one_io_cfg one_io; + struct two_io_cfg two_io; +}; + +struct led_platform_data { + enum led_io_mode io_mode; + union io_mode_cfg io_cfg; +}; + +#define LED_PLATFORM_DATA_BEGIN(data) \ + const struct led_platform_data data = { + +#define LED_PLATFORM_DATA_END() \ +}; + +/*********************** LED 初始化 ******************************/ +void pwm_led_init(const struct led_platform_data *user_data); + +/********************** LED 闪烁模式切换 ************************/ +void pwm_led_mode_set(u8 fre_mode); + +/***************************************************************** + LED时钟源切换, support: + PWM_LED_CLK_RC32K + PWM_LED_CLK_BTOSC_24M +*********************************************************************/ +void pwm_led_clk_set(enum pwm_led_clk_source src); + +/***************** 闪烁状态复位, 重新开始一个周期 ******************/ +void pwm_led_display_mode_reset(void); + +/***************** 获取led当前的闪烁模式 ***************************/ +enum pwm_led_mode pwm_led_display_mode_get(void); + +/******************************************************************** + 修改LED灯IO口驱动能力, 挡位: 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); + +/******************* PWM 模块开关 *********************/ +void pwm_led_set_on(void); +void pwm_led_set_off(void); +void led_module_on(); +void led_module_off(); + + +/******************* PWM 模块是否开启 *********************/ +u8 is_pwm_led_on(void); +bool is_led_module_on(); + +//=================================================================================// +//@brief: 自定义设置单灯闪状态 +//@input: void +// led_index: 0: led0, 1:led1, 2:led0 & led1(互闪) +// led0_bright, LED0亮度: 0 ~ 500 +// led1_bright, LED1亮度: 0 ~ 500 +// led1_bright: led1亮度, +// period: 闪灯周期(ms), 多少ms闪一下, +// start_light_time: 在周期中开始亮灯的时间, -1: 周期最后亮灯 +// light_time: 灯亮持续时间, +//@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); + +//=================================================================================// +//@brief: 自定义设置单灯双闪状态 +//@input: +// led_index: 0: led0, 1:led1, 3:led0 & led1(互闪) +// led0_bright, LED0亮度: 0 ~ 500 +// led1_bright, LED1亮度: 0 ~ 500 +// period: 闪灯周期(ms), 多少ms闪一下 +// first_light_time: 第一次亮灯持续时间, +// second_light_time: 第二次亮灯持续时间, +// gap_time: 两次亮灯时间间隔, +//@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); + + +//=================================================================================// +//@brief: 自定义设置呼吸模式 +//@input: +// 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 +//@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); + +//=================================================================================// +//@brief: 注册LED周期中断函数, 每个LED周期结束后会调用一次, 可以统计指定状态闪烁多少次 +//@input: +//@return: void +//@note: +//=================================================================================// +void pwm_led_register_irq(void (*func)(void)); + +void led_module_enter_sniff_mode(); +void led_module_exit_sniff_mode(); + +#endif //_PWM_LED_H_ + + diff --git a/include_lib/driver/cpu/br28/asm/rdec.h b/include_lib/driver/cpu/br28/asm/rdec.h new file mode 100644 index 0000000..46a2a3b --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/rdec.h @@ -0,0 +1,37 @@ +#ifndef _RDEC_H_ +#define _RDEC_H_ + +#define DEVICE_EVENT_FROM_RDEC (('R' << 24) | ('D' << 16) | ('E' << 8) | '\0') + +enum rdec_index { + RDEC0, + RDEC1, + RDEC2, +}; + +struct rdec_device { + enum rdec_index index; + u8 sin_port0; //采样信号端口0 + u8 sin_port1; //采样信号端口1 + u8 key_value0; //键值1 + u8 key_value1; //键值2 +}; + +struct rdec_platform_data { + u8 enable; + u8 num; //rdec数量 + const struct rdec_device *rdec; +}; + +#define RDEC_PLATFORM_DATA_BEGIN(data) \ + static const struct rdec_platform_data data = { + +#define RDEC_PLATFORM_DATA_END() \ +}; + +/*********************** rdec 初始化 ******************************/ +int rdec_init(const struct rdec_platform_data *user_data); + + +#endif + diff --git a/include_lib/driver/cpu/br28/asm/rtc.h b/include_lib/driver/cpu/br28/asm/rtc.h new file mode 100644 index 0000000..248f92b --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/rtc.h @@ -0,0 +1,39 @@ + +#ifndef __RTC_H__ +#define __RTC_H__ + +#include "typedef.h" +#include "system/sys_time.h" + + +struct rtc_dev_platform_data { + const struct sys_time *default_sys_time; + const struct sys_time *default_alarm; + void (*cbfun)(u8); + u8 clk_sel; + u8 x32xs; +}; + +#define RTC_DEV_PLATFORM_DATA_BEGIN(data) \ + const struct rtc_dev_platform_data data = { + +#define RTC_DEV_PLATFORM_DATA_END() \ + .x32xs = 0, \ +}; + +extern const struct device_operations rtc_dev_ops; +///Jim +int rtc_init(const struct rtc_dev_platform_data *arg); +int rtc_ioctl(u32 cmd, u32 arg); +void set_alarm_ctrl(u8 set_alarm); +void write_sys_time(struct sys_time *curr_time); +void read_sys_time(struct sys_time *curr_time); +void write_alarm(struct sys_time *alarm_time); +void read_alarm(struct sys_time *alarm_time); + +u16 month_to_day(u16 year, u8 month); +void day_to_ymd(u16 day, struct sys_time *sys_time); +u16 ymd_to_day(struct sys_time *time); +u8 caculate_weekday_by_time(struct sys_time *r_time); + +#endif // __RTC_API_H__ diff --git a/include_lib/driver/cpu/br28/asm/sdmmc.h b/include_lib/driver/cpu/br28/asm/sdmmc.h new file mode 100644 index 0000000..2650ded --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/sdmmc.h @@ -0,0 +1,50 @@ +#ifndef ARCH_SDMMC_H +#define ARCH_SDMMC_H + + +#include "device/sdmmc.h" + +struct sdmmc_platform_data { + char port[6]; + u8 irq; + u8 data_width; + u8 priority; + u8 detect_mode; + u8 detect_io; + u8 detect_io_level; + u8 detect_time_interval; + u32 detect_timeout; + u32 speed; + volatile u16 *sfr; + int (*detect_func)(const struct sdmmc_platform_data *); + void (*port_init)(const struct sdmmc_platform_data *, int mode); + void (*power)(int on); +}; + +#define SD0_PLATFORM_DATA_BEGIN(data) \ + static const struct sdmmc_platform_data data = { + + +#define SD0_PLATFORM_DATA_END() \ + .irq = IRQ_SD0_IDX, \ + .sfr = (volatile u16 *)JL_SD0, \ + .port_init = sdmmc_0_port_init, \ + .detect_time_interval = 250, \ + .detect_timeout = 1000, \ +}; + +extern const struct device_operations sd_dev_ops; + +extern void sdmmc_0_port_init(const struct sdmmc_platform_data *, int mode); + +extern int sdmmc_0_clk_detect(const struct sdmmc_platform_data *); +extern int sdmmc_0_io_detect(const struct sdmmc_platform_data *); +extern int sdmmc_0_cmd_detect(const struct sdmmc_platform_data *); +extern int sdmmc_cmd_detect(const struct sdmmc_platform_data *data); + +extern void sd_set_power(u8 enable); + + +extern const struct device_operations sd_dev_ops; +#endif + diff --git a/include_lib/driver/cpu/br28/asm/sfc_norflash_api.h b/include_lib/driver/cpu/br28/asm/sfc_norflash_api.h new file mode 100644 index 0000000..1d515f6 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/sfc_norflash_api.h @@ -0,0 +1,13 @@ +#ifndef __SFC_NORFLASH_API_H__ +#define __SFC_NORFLASH_API_H__ + +#include "typedef.h" + +int norflash_init(const struct dev_node *node, void *arg); +int norflash_open(const char *name, struct device **device, void *arg); +int norflash_read(struct device *device, void *buf, u32 len, u32 offset); +int norflash_write(struct device *device, void *buf, u32 len, u32 offset); +int norflash_ioctl(struct device *device, u32 cmd, u32 arg); + + +#endif diff --git a/include_lib/driver/cpu/br28/asm/sfc_spi.h b/include_lib/driver/cpu/br28/asm/sfc_spi.h new file mode 100644 index 0000000..f6db5f8 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/sfc_spi.h @@ -0,0 +1,47 @@ +#ifndef _SFC1_INTERFACE_H_ +#define _SFC1_INTERFACE_H_ +#include "typedef.h" +#include "generic/ioctl.h" + +enum SFC_DATA_WIDTH { + SFC_DATA_WIDTH_2 = 2, + SFC_DATA_WIDTH_4 = 4, +}; + +enum SFC_READ_MODE { + SFC_RD_OUTPUT = 0, + SFC_RD_IO, + SFC_RD_IO_CONTINUE, +}; + +struct sfc_spi_platform_data { + u8 spi_hw_index; + enum SFC_DATA_WIDTH sfc_data_width; + enum SFC_READ_MODE sfc_read_mode; + u8 sfc_encry; //是否加密 + u16 sfc_clk_div; //时钟分频: sfc_fre = sys_clk / div; + u32 unencry_start_addr; //不加密起始地址 + u32 unencry_size; //不加密大小 +}; + +#define SFC_SPI_PLATFORM_DATA_BEGIN(data) \ + const struct sfc_spi_platform_data data = { + +#define SFC_SPI_PLATFORM_DATA_END() \ +}; + + +//sfc1 API: +int sfc_spi_init(struct sfc_spi_platform_data *sfc_spi_data); +int sfc_spi_open(void *sfc_spi_data); +int sfc_spi_close(void); +u32 sfc_spi_read_id(void); +int sfc_spi_read(u32 addr, void *buf, u32 len); +int sfc_spi_write_pages(u32 addr, void *buf, u32 len); +int sfc_spi_eraser(u32 cmd, u32 addr); +u32 sfc1_flash_addr2cpu_addr(u32 offset); +u32 sfc1_cpu_addr2flash_addr(u32 offset); + +void sfc_suspend(u32 enable_spi); +void sfc1_suspend(); +#endif /* #ifndef _SFC1_INTERFACE_H_ */ diff --git a/include_lib/driver/cpu/br28/asm/spi.h b/include_lib/driver/cpu/br28/asm/spi.h new file mode 100644 index 0000000..c503ee4 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/spi.h @@ -0,0 +1,77 @@ +#ifndef _SPI_INTERFACE_H_ +#define _SPI_INTERFACE_H_ +#include "typedef.h" +#include "generic/ioctl.h" + + +/*enum spi_mode { + SPI_2WIRE_MODE, + SPI_ODD_MODE, + SPI_DUAL_MODE, + SPI_QUAD_MODE, +};*/ +enum spi_mode { + SPI_MODE_BIDIR_1BIT, //支持SPIx(x=0,1,2),全双工,di接收,do发送 + SPI_MODE_UNIDIR_1BIT, //支持SPIx(x=0,1,2),半双工,do分时发送/接收 + SPI_MODE_UNIDIR_2BIT, //支持SPIx(x=0),半双工,di & do共2bit分时发送/接收 + SPI_MODE_UNIDIR_4BIT, //支持SPIx(x=0),半双工,di & do & wp & hold 共4bit分时发送/接收 +}; + +enum { + SPI0, + SPI1, + SPI2, + SPI_MAX_HW_NUM, +}; + +#define SPI_MAX_IO_GROUP 2 + +struct spi_io { + u8 cs_pin; + u8 di_pin; + u8 do_pin; + u8 clk_pin; + u8 d2_pin; + u8 d3_pin; +}; + +struct spi_io_mapping { + u32 num; //可选端口数量 + struct spi_io io[SPI_MAX_IO_GROUP]; +}; + +enum spi_role { + SPI_ROLE_MASTER, + SPI_ROLE_SLAVE, +}; + +struct spi_platform_data { + u8 port[5];//CLK, DO, DI D2(wp) D3(hold) + u8 mode; //模式,选项为enum spi_mode中的枚举常量 + u8 role; //角色,选项为enum spi_role中的枚举常量 + u32 clk; //波特率 +}; + +extern const struct spi_platform_data spi1_p_data; +extern const struct spi_platform_data spi2_p_data; + +typedef const int spi_dev; + +int spi_open(spi_dev spi); +int spi_dma_recv(spi_dev spi, void *buf, u32 len); +int spi_dma_send(spi_dev spi, const void *buf, u32 len); +void spi_dma_set_addr_for_isr(spi_dev spi, void *buf, u32 len, u8 rw); +void spi_set_ie(spi_dev spi, u8 en); +u8 spi_get_pending(spi_dev spi); +void spi_clear_pending(spi_dev spi); +void spi_set_bit_mode(spi_dev spi, int mode); +u8 spi_recv_byte(spi_dev spi, int *err); +u8 spi_recv_byte_for_isr(spi_dev spi); +int spi_send_byte(spi_dev spi, u8 byte); +void spi_send_byte_for_isr(spi_dev spi, u8 byte); +u8 spi_send_recv_byte(spi_dev spi, u8 byte, int *err); +int spi_set_baud(spi_dev spi, u32 baud); +u32 spi_get_baud(spi_dev spi); +void spi_close(spi_dev spi); + +#endif diff --git a/include_lib/driver/cpu/br28/asm/spiflash.h b/include_lib/driver/cpu/br28/asm/spiflash.h new file mode 100644 index 0000000..a2c62e3 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/spiflash.h @@ -0,0 +1,29 @@ +#ifndef ASM_SPIFLASH_H +#define ASM_SPIFLASH_H + + + +#include "device/device.h" +#include "device/spiflash.h" + + + + + + + + + + + + +extern const struct device_operations spiflash_dev_ops; +extern const struct device_operations sfcflash_dev_ops; +extern const struct device_operations sdfile_dev_ops; + + + + + +#endif + diff --git a/include_lib/driver/cpu/br28/asm/timer.h b/include_lib/driver/cpu/br28/asm/timer.h new file mode 100644 index 0000000..0cca3a4 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/timer.h @@ -0,0 +1,12 @@ +#ifndef __TIMER_H__ +#define __TIMER_H__ + +#include "typedef.h" + +void udelay(u32 us); +void mdelay(u32 us); +void delay_2ms(int cnt); +u32 timer_get_sec(void); +u32 timer_get_ms(void); + +#endif diff --git a/include_lib/driver/cpu/br28/asm/uart.h b/include_lib/driver/cpu/br28/asm/uart.h new file mode 100644 index 0000000..a09c6e1 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/uart.h @@ -0,0 +1,56 @@ +#ifndef ASM_UART_H +#define ASM_UART_H + + +#define UART_NUM 3 +#define UART_OUTPORT_NUM 4 + + +#include "device/uart.h" +#include "device/device.h" + +#define UART0_PLATFORM_DATA_BEGIN(data) \ + static const struct uart_platform_data data = { + + +#define UART0_PLATFORM_DATA_END() \ + .irq = IRQ_UART0_IDX, \ +}; + + +#define UART1_PLATFORM_DATA_BEGIN(data) \ + static const struct uart_platform_data data = { + + +#define UART1_PLATFORM_DATA_END() \ + .irq = IRQ_UART1_IDX, \ +}; + + +#define UART2_PLATFORM_DATA_BEGIN(data) \ + static const struct uart_platform_data data = { + +#define UART2_PLATFORM_DATA_END() \ + .irq = IRQ_UART2_IDX, \ +}; + + +// #define UART3_PLATFORM_DATA_BEGIN(data) \ +// static const struct uart_platform_data data = { + +// #define UART3_PLATFORM_DATA_END() \ +// .irq = UART3_INT, \ +// }; + + + + +extern const struct device_operations uart_dev_ops; + + +extern int uart_init(const struct uart_platform_data *); + + +#endif + + diff --git a/include_lib/driver/cpu/br28/asm/uart_dev.h b/include_lib/driver/cpu/br28/asm/uart_dev.h new file mode 100644 index 0000000..14e6f37 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/uart_dev.h @@ -0,0 +1,176 @@ +#ifndef _UART_DEV_H_ +#define _UART_DEV_H_ + +#include "typedef.h" +#include "os/os_api.h" +#include "jiffies.h" +#include "irq.h" +/* #include "jtime.h" */ + +#define CONFIG_ENABLE_UART_SEM 1 +#define SET_INTERRUPT ___interrupt +#define irq_disable(x) bit_clr_ie(x) +#define irq_enable(x) bit_set_ie(x) + +#ifndef time_after +#define time_after(a,b) (((long)(b) - (long)(a)) < 0) +#endif + +#ifndef time_before +#define time_before(a,b) time_after(b,a) +#endif + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +static inline u32 ut_get_jiffies(void) +{ +#if 1 + return jiffies; +#endif +#if 0 + return Jtime_updata_jiffies(); +#endif +} + +static inline u32 ut_msecs_to_jiffies(u32 msecs) +{ + if (msecs >= 10) { + msecs /= 10; + } else if (msecs) { + msecs = 1; + } + return msecs; +} + +#if CONFIG_ENABLE_UART_SEM +typedef OS_SEM UT_Semaphore ; +static inline void UT_OSSemCreate(UT_Semaphore *sem, u32 count) +{ + os_sem_create(sem, count); +} +static inline void UT_OSSemPost(UT_Semaphore *sem) +{ + os_sem_post(sem); +} +static inline u32 UT_OSSemPend(UT_Semaphore *sem, u32 timeout) +{ + return os_sem_pend(sem, timeout); +} +static inline void UT_OSSemSet(UT_Semaphore *sem, u32 count) +{ + os_sem_set(sem, count); +} +static inline void UT_OSSemClose(UT_Semaphore *sem) +{ + +} +static inline void ut_sleep() +{ + os_time_dly(1); +} + +#else +typedef volatile u32 UT_Semaphore; +static inline void UT_OSSemCreate(UT_Semaphore *sem, u32 count) +{ + *sem = count; +} +static inline void UT_OSSemPost(UT_Semaphore *sem) +{ + (*sem)++; +} +static inline u32 UT_OSSemPend(UT_Semaphore *sem, u32 timeout) +{ + u32 _timeout = timeout + ut_get_jiffies(); + extern void clr_wdt(); + while (1) { + if (*sem) { + (*sem) --; + break; + } + if ((timeout != 0) && time_before(_timeout, ut_get_jiffies())) { + return -1; + } + clr_wdt(); + } + return 0; +} +static inline void UT_OSSemSet(UT_Semaphore *sem, u32 count) +{ + *sem = count; +} +static inline void UT_OSSemClose(UT_Semaphore *sem) +{ + +} +static inline void ut_sleep() +{ + extern void clr_wdt(); + clr_wdt(); +} +#endif + + +typedef void (*ut_isr_cbfun)(void *ut_bus, u32 status); +struct uart_platform_data_t { + u8 tx_pin; ///< 作为发送引脚的引脚号,可从参考gpio.h枚举中选,当引脚为空时,则填 -1 + u8 rx_pin; ///< 作为接收引脚的引脚号,可从参考gpio.h枚举中选,当引脚为空时,则填 -1 + void *rx_cbuf; ///< 如果使用中断DMA接收,则写入循环buf的首地址,ut中断使能;如果不使用,则写入NULL,无中断 + u32 rx_cbuf_size; ///< 循环buf的大小,必须为2的多少几次幂,如果不用循环buf,该值无效,可写NULL + u32 frame_length; ///< 产生RT中断的字节数,如无中断,该值无效 + u32 rx_timeout; ///< 产生OT中断的时间值,单位ms,如无中断,该值无效 + ut_isr_cbfun isr_cbfun; ///< ut中断的回调函数句柄,不用回调函数则写入NULL,如无中断,句柄无效 + void *argv; ///< ut中断的回调函数的一个扩展形参,可供用户设定,如无回调函数,此参数无效 + u32 is_9bit: 1; ///< ut九位模式使能位,0:关闭;1:使能 + u32 baud: 24; ///< ut的波特率 +}; + +/** + * @brief 循环buf结构体类型定义 + */ +typedef struct { + u8 *buffer; ///<循环buf的首地址 + u32 buf_size; ///<循环buf的大小 + u32 buf_in; ///<循环buf的写偏移量 + u32 buf_out; ///<循环buf的读偏移量 +} KFIFO; + +enum { + UT_TX = 1, + UT_RX, + UT_RX_OT +}; + +/** + * @brief ut初始化函数的返回结构体,含各函数指针,供外部使用 + */ +typedef struct { + ut_isr_cbfun isr_cbfun; ///< ut中断的回调函数句柄,不用回调函数则写入NULL,如无中断,句柄无效 + void *argv; ///< ut中断的回调函数的一个扩展形参,在此返回 + void (*putbyte)(char a); ///< ut发送一个byte + u8(*getbyte)(u8 *buf, u32 timeout); ///< ut接收一个byte,buf:字节存放地址;timeout:超时时间,单位ms;返回0:失败;返回1:成功 + u32(*read)(u8 *inbuf, u32 len, u32 timeout); ///< ut接收一个字符串,inbuf:字符串存放首地址;len:预接收长度;timeout:超时时间,单位ms;返回实际接收的长度 + void (*write)(const u8 *outbuf, u32 len); ///< ut发送一个字符串,outbuf:字符串首地址;len:发送的字符串长度; + void (*set_baud)(u32 baud); ///< ut设置波特率,baud:波特率值 + u32 frame_length; + u32 rx_timeout; + KFIFO kfifo; ///< ut用的循环buf结构体的指针 + UT_Semaphore sem_rx; + UT_Semaphore sem_tx; + u32(*get_data_len)(void); +} uart_bus_t; + + +const uart_bus_t *uart_dev_open(const struct uart_platform_data_t *arg); +u32 uart_dev_close(uart_bus_t *ut); + +//////////////////////////////////////////////////////////////////////////////// +#endif + + diff --git a/include_lib/driver/cpu/br28/asm/umidigi_chargestore.h b/include_lib/driver/cpu/br28/asm/umidigi_chargestore.h new file mode 100644 index 0000000..46cee58 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/umidigi_chargestore.h @@ -0,0 +1,19 @@ +#ifndef _UIMIDIGI_ +#define _UIMIDIGI_ + +#include "typedef.h" +#include "system/event.h" + +void ldo_port_wakeup_to_cmessage(void); +void umidigi_chargestore_message_callback(void (*app_umidigi_chargetore_message_deal)(u16 message)); + +/* + * 收集数据定时器采集周期根据充电舱发送波形设置 + * 充电舱发送波形有40ms/bit和20ms/bit两种 + * + * #define _20MS_BIT 21 + * #define _40MS_BIT 41 + * #define TIMER2CMESSAGE _20MS_BIT +*/ + +#endif diff --git a/include_lib/driver/cpu/br28/asm/usb.h b/include_lib/driver/cpu/br28/asm/usb.h new file mode 100644 index 0000000..1be2630 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/usb.h @@ -0,0 +1,185 @@ +#ifndef _USB_H_ +#define _USB_H_ +#include "typedef.h" +#include "generic/ioctl.h" + + +#ifndef min +#define min(a,b) ((a)<(b) ? (a) : (b)) +#endif +#ifndef USB_DIR_OUT +#define USB_DIR_OUT 0 /* to device */ +#endif +#ifndef USB_DIR_IN +#define USB_DIR_IN 0x80 /* to host */ +#endif + +#define FUSB_MODE 1 +#define EP0_SETUP_LEN 0x40 +#define USB_MAX_HW_EPNUM 5 + +/* #define ep_regs JL_USB_EP_TypeDef */ +typedef struct { + volatile u32 TXMAXP; + volatile u32 TXCSR1; + volatile u32 TXCSR2; + volatile u32 RXMAXP; + volatile u32 RXCSR1; + volatile u32 RXCSR2; + volatile const u32 RXCOUNT1; + volatile const u32 RXCOUNT2; + volatile u32 TXTYPE; + volatile u32 TXINTERVAL; + volatile u32 RXTYPE; + volatile u32 RXINTERVAL; + u32 RESERVED[0xd0 / 4]; +} ep_regs; + + + +#define PHY_ON 0 +#define LOW_SPEED 1 +#define USB_NRST 2 +#define TM1 3 +#define CID 4 +#define VBUS 5 +#define USB_TEST 6 +#define PDCHKDP 9 +#define SOFIE 10 +#define SIEIE 11 +#define CLR_SOF_PND 12 +#define SOF_PND 13 +#define SIE_PND 14 +#define CHKDPO 15 +#define DM_SE 16 +#define DP_SE 17 + +#define MC_RNW 14 +#define MACK 15 + +#define DPOUT 0 +#define DMOUT 1 +#define DPIE 2 +#define DMIE 3 +#define DPPU 4 +#define DMPU 5 +#define DPPD 6 +#define DMPD 7 +#define DPDIE 8 +#define DMDIE 9 +#define DPDIEH 10 +#define DMDIEH 11 +#define IO_MODE 12 +#define SR 13 +#define IO_PU_MODE 14 + + + +enum { + USB0, +}; +#define USB_MAX_HW_NUM 1 + + +struct usb_ep_addr_t { + u32 ep0_addr; + u32 ep_usage; + const u8 *ep_taddr[4]; + const u8 *ep_dual_taddr[4]; + u8 *ep_raddr[4]; + u8 *ep_dual_raddr[4]; + u32 ep_tsize[4]; + u32 ep_rsize[4]; +} __attribute__((aligned(4))); + + +typedef u8 usb_dev; + +u16 usb_read_sofframe(const usb_dev id); +u32 usb_dev_con0(const usb_dev usb_id); +void usb_sie_enable(const usb_dev usb_id); +void usb_sie_disable(const usb_dev id); +void usb_write_ep_cnt(const usb_dev usb_id, u32 ep, u32 len); +u32 usb_g_dev_status(const usb_dev usb_id); +u32 usb_h_dev_status(const usb_dev usb_id); +void usb_set_low_speed(const usb_dev usb_id, u8 flag); +void usb_write_ep0(const usb_dev usb_id, const u8 *ptr, u32 len); +void usb_read_ep0(const usb_dev usb_id, u8 *ptr, u32 len); +void *usb_get_dma_taddr(const usb_dev usb_id, u32 ep); +u32 usb_get_dma_size(const usb_dev usb_id, u32 ep); +void usb_set_dma_tsize(const usb_dev usb_id, u32 ep, u32 size); +void usb_set_dma_rsize(const usb_dev usb_id, u32 ep, u32 size); +void usb_set_dma_taddr(const usb_dev usb_id, u32 ep, const void *ptr); +void *usb_get_dma_raddr(const usb_dev usb_id, u32 ep); +void usb_set_dma_raddr(const usb_dev usb_id, u32 ep, void *ptr); +void usb_set_dma_dual_raddr(const usb_dev usb_id, u32 ep, void *ptr); +void musb_write_index(const usb_dev usb_id, u32 endpoint); +void usb_write_power(const usb_dev usb_id, u32 value); +u32 usb_read_power(const usb_dev usb_id); +u32 usb_read_devctl(const usb_dev usb_id); +void usb_write_devctl(const usb_dev usb_id, u32 value); +u32 usb_read_csr0(const usb_dev usb_id); +void usb_write_csr0(const usb_dev usb_id, u32 csr0); +void usb_ep0_ClrRxPktRdy(const usb_dev usb_id); +void usb_ep0_TxPktEnd(const usb_dev usb_id); +void usb_ep0_RxPktEnd(const usb_dev usb_id); +void usb_ep0_Set_Stall(const usb_dev usb_id); +u32 usb_read_count0(const usb_dev usb_id); +void usb_read_intre(const usb_dev usb_id, + u32 *const intr_usbe, + u32 *const intr_txe, + u32 *const intr_rxe); + +void usb_read_intr(const usb_dev usb_id, + u32 *const intr_usb, + u32 *const intr_tx, + u32 *const intr_rx); +void usb_write_intr_usbe(const usb_dev usb_id, u32 intr_usbe); +void usb_set_intr_txe(const usb_dev usb_id, const u32 ep); +void usb_clr_intr_txe(const usb_dev usb_id, const u32 ep); +void usb_set_intr_rxe(const usb_dev usb_id, const u32 ep); +void usb_clr_intr_rxe(const usb_dev usb_id, const u32 ep); +void usb_write_faddr(const usb_dev usb_id, u32 addr); +void usb_write_txcsr(const usb_dev usb_id, const u32 ep, u32 txcsr); +u32 usb_read_txcsr(const usb_dev usb_id, const u32 ep); +void usb_write_rxcsr(const usb_dev usb_id, const u32 ep, u32 rxcsr); +u32 usb_read_rxcsr(const usb_dev usb_id, const u32 ep); +void usb_write_rxmaxp(const usb_dev usb_id, const u32 ep, u32 value); +void usb_write_txmaxp(const usb_dev usb_id, const u32 ep, u32 value); +void usb_write_rxtype(const usb_dev usb_id, const u32 ep, u32 value); +void usb_write_txtype(const usb_dev usb_id, const u32 ep, u32 value); +u32 usb_read_rxcount(const usb_dev usb_id, u32 ep); +u32 usb_g_ep_config(const usb_dev usb_id, const u32 ep, u32 type, u32 ie, u8 *ptr, u32 dma_size); +u32 usb_g_ep_read64byte_fast(const usb_dev usb_id, const u32 ep, u8 *ptr, u32 len); +u32 usb_g_ep_read(const usb_dev usb_id, const u32 ep, u8 *ptr, u32 len, u32 block); +u32 usb_g_ep_write(const usb_dev usb_id, u32 ep, const u8 *ptr, u32 len); +u32 usb_g_ep_config(const usb_dev usb_id, u32 ep, u32 type, u32 ie, u8 *ptr, u32 dma_size); +void usb_g_sie_init(const usb_dev usb_id); +void usb_g_hold(const usb_dev usb_id); +u32 usb_get_ep_num(const usb_dev usb_id, u32 ep_dir, u32 type); +u32 usb_h_ep_config(const usb_dev usb_id, u32 ep, u32 type, u32 ie, u32 interval, u8 *ptr, u32 dma_size); +void usb_mdelay(unsigned int ms); +u32 usb_h_ep_write(const usb_dev usb_id, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *ptr, u32 len, u32 xfer); +int usb_h_ep_write_async(const usb_dev id, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *ptr, u32 len, u32 xfer, u32 kstart); +u32 usb_h_ep_read(const usb_dev usb_id, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *ptr, u32 len, u32 xfer); +int usb_h_ep_read_async(const usb_dev id, u8 host_ep, u8 target_ep, u8 *ptr, u32 len, u32 xfer, u32 kstart); +void usb_h_sie_init(const usb_dev usb_id); +void usb_h_sie_close(const usb_dev usb_id); +u32 usb_h_chirp_and_reset(const usb_dev id, u32 reset_delay, u32 timeout); +void usb_h_sie_reset(const usb_dev usb_id); +void usb_hotplug_disable(const usb_dev usb_id); +void usb_hotplug_enable(const usb_dev usb_id, u32 mode); +void usb_sie_close(const usb_dev usb_id); +void usb_sie_close_all(void); +void usb_var_init(const usb_dev usb_id, void *ptr); +void usb_var_release(const usb_dev usb_id); +void usb_enable_ep(const usb_dev usb_id, u32 eps); +void usb_disable_ep(const usb_dev usb_id, u32 eps); +u32 usb_get_ep_status(const usb_dev usb_id, u32 epx); + +void usb_sofie_enable(const usb_dev id); +void usb_sofie_disable(const usb_dev id); +void usb_sof_clr_pnd(const usb_dev id); +void usb_ep0_Set_ignore(const usb_dev id, u32 addr); +void usb_recover_io_status(const usb_dev id); +#endif diff --git a/include_lib/driver/cpu/br28/asm/wdt.h b/include_lib/driver/cpu/br28/asm/wdt.h new file mode 100644 index 0000000..9a8ec86 --- /dev/null +++ b/include_lib/driver/cpu/br28/asm/wdt.h @@ -0,0 +1,32 @@ +#ifndef __BR22_WDT_H__ +#define __BR22_WDT_H__ + +#define WDT_1MS 0x00 +#define WDT_2MS 0x01 +#define WDT_4MS 0x02 +#define WDT_8MS 0x03 +#define WDT_16MS 0x04 +#define WDT_32MS 0x05 +#define WDT_64MS 0x06 +#define WDT_128MS 0x07 +#define WDT_256MS 0x08 +#define WDT_512MS 0x09 +#define WDT_1S 0x0A +#define WDT_2S 0x0B +#define WDT_4S 0x0C +#define WDT_8S 0x0D +#define WDT_16S 0x0E +#define WDT_32S 0x0F +#define WDT_64S 0x10 +#define WDT_128S 0x11 + +void wdt_init(u8 time); +void wdt_close(void); +void wdt_clear(void); + +void wdt_enable(void); +void wdt_disable(void); + +u32 wdt_get_time(void);//ms + +#endif diff --git a/include_lib/driver/cpu/br28/driver_lib.ld b/include_lib/driver/cpu/br28/driver_lib.ld new file mode 100644 index 0000000..7538ff7 --- /dev/null +++ b/include_lib/driver/cpu/br28/driver_lib.ld @@ -0,0 +1,116 @@ +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 = .; + #include "driver_lib_data_text.ld" + driver_data_code_end = .; + . = ALIGN(4); + } > ram0 + + /*代码统计 Code & RAM */ + 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); + +} diff --git a/include_lib/driver/cpu/br28/driver_lib_data_text.ld b/include_lib/driver/cpu/br28/driver_lib_data_text.ld new file mode 100644 index 0000000..03450d2 --- /dev/null +++ b/include_lib/driver/cpu/br28/driver_lib_data_text.ld @@ -0,0 +1,11 @@ + + 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) diff --git a/include_lib/driver/device/anctool.h b/include_lib/driver/device/anctool.h new file mode 100644 index 0000000..6f690b7 --- /dev/null +++ b/include_lib/driver/device/anctool.h @@ -0,0 +1,18 @@ +#ifndef __ANCTOOL_H__ +#define __ANCTOOL_H__ + +#include "typedef.h" + +struct anctool_data { + void (*send_packet)(u8 *data, u16 size); + void (*recv_packet)(u8 *data, u16 size); +}; + +void anctool_api_rx_data(u8 *buf, u16 len); +u8 *anctool_api_write_alloc(u16 len); +void anctool_api_set_active(u8 active); +u16 anctool_api_write(u8 *buf, u16 length); +void anctool_api_init(const struct anctool_data *arg); +void anctool_api_uninit(void); + +#endif diff --git a/include_lib/driver/device/sdio_host_init.h b/include_lib/driver/device/sdio_host_init.h new file mode 100644 index 0000000..888b905 --- /dev/null +++ b/include_lib/driver/device/sdio_host_init.h @@ -0,0 +1,72 @@ +#ifndef _SDIO_HOST_INIT_H_ +#define _SDIO_HOST_INIT_H_ + +/* +SDIO_GRP_0|SDIO_PORT_0: PA1-PA4->CMD,CLK,D2,D0; PH13,PH15->D3,D1 +SDIO_GRP_0|SDIO_PORT_1: PH6-PH11->D3,CMD,CLK,D2,D0,D1 +SDIO_GRP_0|SDIO_PORT_2: PC8-PC13->D2,D3,CMD,CLK,D0,D1 +SDIO_GRP_0|SDIO_PORT_3: PG8-PG13->D2,D3,CMD,CLK,D0,D1 +SDIO_GRP_1|SDIO_PORT_0: PF4-PF9->D2,D3,CMD,CLK,D0,D1 +SDIO_GRP_1|SDIO_PORT_1: PG0-PG5->D2,D3,CMD,CLK,D0,D1 +SDIO_GRP_1|SDIO_PORT_2: PD6-PD11->D2,D3,CMD,CLK,D0,D1 +SDIO_GRP_1|SDIO_PORT_3: PA10-PA15->D2,D3,CMD,CLK,D0,D1 +*/ + +//选择SDIO0? SDIO1? 作为输出,默认为SDIO1 +#define SDIO_GRP_0 0 +#define SDIO_GRP_1 (1 << 31) +#define SDIO_GRP_2 (1 << 30) +#define SDIO_GRP_MASK (1 << 31|1 << 30) + +//选择SDIOx的哪个出口作为输出,默认为出口0 +#define SDIO_PORT_0 0 +#define SDIO_PORT_1 (1 << 29) +#define SDIO_PORT_2 (1 << 28) +#define SDIO_PORT_3 (1 << 29|1 << 28) +#define SDIO_PORT_MASK (1 << 29|1 << 28) + +//是否使用四线模式, 默认为单线模式 +#define SDIO_1_BIT_DATA 0 +#define SDIO_4_BIT_DATA (1 << 27) +#define SDIO_4_BIT_DATA_MASK (1 << 27) + +//是否使用硬件中断检测外设事件,例如接收到数据. , 默认使用轮询方式查询事件, //对接收速度不敏感使用SDIO_POLLING即可 ,使用SDIO_DATA1_IRQ如果接收数据量过大会导致CPU不足的问题. +#define SDIO_POLLING 0 +#define SDIO_DATA1_IRQ (1 << 26) +#define SDIO_DATA1_IRQ_MASK (1 << 26) + +//配置SDIO时钟(HZ), 默认为40MHZ +#define SDIO_MAX_CLK_MASK ((1 << 26)-1) + +#define SDIO_CLOCK_80M (0) //80M 写0 +#define SDIO_CLOCK_40M (40 * 1000000) +#define SDIO_CLOCK_26M (26 * 1000000) +#define SDIO_CLOCK_20M (20 * 1000000) +#define SDIO_CLOCK_16M (16 * 1000000) +#define SDIO_CLOCK_8M (8 * 1000000) +#define SDIO_CLOCK_4M (4 * 1000000) +#define SDIO_CLOCK_2M (2 * 1000000) + +/* +sdio_host_init(0); +sdio_host_init(SDIO_GRP_1|SDIO_4_BIT_DATA); +sdio_host_init(SDIO_GRP_1|SDIO_PORT_1|SDIO_DATA1_IRQ); +sdio_host_init(SDIO_GRP_0|SDIO_PORT_0|SDIO_4_BIT_DATA|SDIO_DATA1_IRQ|(10*1000000)); +*/ + +extern void sdio_host_init(unsigned int parm); +extern unsigned char *SDIO_GET_CMD_BUF(void); +extern void SDIO_SET_GRP_PORT(u32 grp, u32 port); +extern void cpu_sdio_host_uninit(void); +extern void sdio_dat1_irq_uninit(void); +extern void sdio_dat1_irq_init(void); +extern void host_set_timing(void *host, unsigned int timing); +extern void mmc_set_bus_width(void *host, unsigned int width); +extern void mmc_set_clock(void *host, unsigned int hz); +extern void SDIO_CONTROLLER_RESET(void); +extern void SDIO_IDLE_CLK_EN(u8 enable) ; +extern void SDIO_CONTROLLER_START(void); +extern void SDIO_CONTROLLER_SET_IRQ(void); +extern void SDIO_SET_4WIRE_MODE(u8 enable); + +#endif //_SDIO_HOST_INIT_H_ diff --git a/include_lib/driver/device/sdmmc.h b/include_lib/driver/device/sdmmc.h new file mode 100644 index 0000000..ef5247c --- /dev/null +++ b/include_lib/driver/device/sdmmc.h @@ -0,0 +1,42 @@ +#ifndef SDMMC_MODULE_H +#define SDMMC_MODULE_H + + +#include "generic/typedef.h" +#include "generic/ioctl.h" + + +#define SD_CMD_DECT 0 +#define SD_CLK_DECT 1 +#define SD_IO_DECT 2 + +#define SD_CLASS_0 0 +#define SD_CLASS_2 1 +#define SD_CLASS_4 2 +#define SD_CLASS_6 3 +#define SD_CLASS_10 4 + +#define SD_IOCTL_GET_CLASS _IOR('S', 0, 4) + + +#define SD_IOCTL_SUPPORT_ERASE_OPERAT 1 + +typedef enum { + SDMMC_NORMAL_ERASE, + SDMMC_TRIM_ERASE, + SDMMC_DISCARD, + SDMMC_SECURE_ERASE, + SDMMC_SECURE_TRIM_STEP_1, + SDMMC_SECURE_TRIM_STEP_2, +} sdmmc_erase_type; + +struct sdmmc_erase_arg_t { + sdmmc_erase_type erase_type; + u32 block_addr; + u32 block_quantity; +}; + + + +#endif + diff --git a/include_lib/driver/device/spiflash.h b/include_lib/driver/device/spiflash.h new file mode 100644 index 0000000..9e87d6c --- /dev/null +++ b/include_lib/driver/device/spiflash.h @@ -0,0 +1,125 @@ +#ifndef __SPIFLASH_H__ +#define __SPIFLASH_H__ + + + +#include "typedef.h" +#include "generic/list.h" +#include "generic/ioctl.h" +#include "device/device.h" +#include "system/task.h" + + +struct spi_device; + +enum spiflash_bit_mode { + SPI_2WIRE_MODE, + SPI_ODD_MODE, + SPI_DUAL_MODE, + SPI_QUAD_MODE, +}; + +enum spiflash_read_mode { + FAST_READ_OUTPUT_MODE, + FAST_READ_IO_MODE, + FAST_READ_IO_CONTINUOUS_READ_MODE, +}; + +enum sfc_run_mode { + //1bit mode + SFC_READ_DATA_MODE = (1 << 0), + SFC_FAST_READ_MODE = (1 << 1), + //2bit mode + SFC_FAST_READ_DUAL_IO_NORMAL_READ_MODE = (1 << 2), + SFC_FAST_READ_DUAL_IO_CONTINUOUS_READ_MODE = (1 << 3), + SFC_FAST_READ_DUAL_OUTPUT_MODE = (1 << 4), + //4bit mode + SFC_FAST_READ_QUAD_IO_NORMAL_READ_MODE = (1 << 5), + SFC_FAST_READ_QUAD_IO_CONTINUOUS_READ_MODE = (1 << 6), + SFC_FAST_READ_QUAD_OUTPUT_MODE = (1 << 7), + +}; +struct spi_ops { + int (*set_cs)(int); + int (*init)(void *); + u8(*read_byte)(int *err); + int (*read)(u8 *, u32 len, u8 mode); + int (*write_byte)(u8 cmd); + int (*write_cmd)(u8 *cmd, u32 len); + int (*write)(u8 *, u32 len); + u8(*get_bit_mode)(); +}; + + +struct sf_info { + u32 id; + u16 page_size; //byte + u16 block_size; //KByte + u32 chip_size; //KByte +}; + +enum sf_erase_type { + SF_SECTOR_ERASE, + SF_BLOCK_ERASE, + SF_CHIP_ERASE, +}; + +//struct sf_erase { +//enum sf_erase_type type; +//u32 addr; +//}; + + +//struct sf_wp { +//u8 enable; +//u8 cmd; +//}; + + +struct spi_device { + const char *name; + const struct spi_ops *ops; +}; + +struct spiflash_platform_data { + const char *name; + enum spiflash_read_mode mode; + enum sfc_run_mode sfc_run_mode; + void *private_data; +}; + + +struct spiflash { + struct list_head entry; + void *device; + struct device dev; + struct sf_info info; + const struct spiflash_platform_data *pd; + const char *name; + OS_MUTEX mutext; + u8 inited; + u8 read_mode; + u8 read_cmd_mode; + u8 write_cmd_mode; + u8 continuous_read_mode; +}; + + +#define REGISTER_SPIFLASH_DEVICE(dev) \ + static const struct spi_device dev sec(.spi_device) + + +extern struct spi_device spi_device_begin[]; +extern struct spi_device spi_device_end[]; + + + + +extern struct spiflash *__get_spiflash(const char *name); + + + + + +#endif + diff --git a/include_lib/driver/device/uart.h b/include_lib/driver/device/uart.h new file mode 100644 index 0000000..18d6e52 --- /dev/null +++ b/include_lib/driver/device/uart.h @@ -0,0 +1,131 @@ +#ifndef DEVICE_UART_H +#define DEVICE_UART_H + +#include "typedef.h" +#include "device/device.h" +#include "generic/ioctl.h" +#include "system/task.h" + +#define UART_DISABLE 0x00000000 +#define UART_DMA_SUPPORT 0x00000001 +#define UART_TX_USE_DMA 0x00000003 +#define UART_RX_USE_DMA 0x00000005 +#define UART_DEBUG 0x00000008 + +struct uart_outport { + u8 tx_pin; + u8 rx_pin; + u16 value; +}; + +extern void putbyte(char a); + + + + +enum uart_clk_src { + LSB_CLK, + OSC_CLK, + PLL_48M, +}; + + +enum _uart_port_out { + //uart0 + PORTC_0_1 = 0x00001000, + PORTG_6_7 = 0x00002000, + PORTH_12_13 = 0x00003000, + PORTB_14_15 = 0x00004000, + //uart1 + PORTC_2_3 = 0x00005000, + PORTH_2_5 = 0x00006000, + PORTH_14_15 = 0x00007000, + PORTC_6_7 = 0x00008000, + //uart3 + PORTE_0_1 = 0x00009000, + PORTB_4_3 = 0x0000A000, + PORTD_9_10 = 0x0000B000, + PORTD_14_15 = 0x0000C000, + + PORT_REMAP = 0x0000D000, +}; + +struct uart_platform_data { + u8 *name; + + u8 irq; + u8 tx_pin; + u8 rx_pin; + u32 flags; + u32 baudrate; + + enum _uart_port_out port; + void (*port_remap_func)(void); + u32 max_continue_recv_cnt; + u32 idle_sys_clk_cnt; + enum uart_clk_src clk_src; +}; + +enum { + UART_CIRCULAR_BUFFER_WRITE_OVERLAY = -1, + UART_RECV_TIMEOUT = -2, + UART_RECV_EXIT = -3, +}; + +#define UART_MAGIC 'U' +#define UART_FLUSH _IO(UART_MAGIC,1) +#define UART_SET_RECV_ALL _IOW(UART_MAGIC,2,bool) +#define UART_SET_RECV_BLOCK _IOW(UART_MAGIC,3,bool) +#define UART_SET_RECV_TIMEOUT _IOW(UART_MAGIC,4,u32) +#define UART_SET_RECV_TIMEOUT_CB _IOW(UART_MAGIC,5,int (*)(void)) +#define UART_GET_RECV_CNT _IOR(UART_MAGIC,6,u32) +#define UART_START _IO(UART_MAGIC,7) +#define UART_SET_CIRCULAR_BUFF_ADDR _IOW(UART_MAGIC,8,void *) +#define UART_SET_CIRCULAR_BUFF_LENTH _IOW(UART_MAGIC,9,u32) + + +#define UART_PLATFORM_DATA_BEGIN(data) \ + static const struct uart_platform_data data = { + + +#define UART_PLATFORM_DATA_END() \ + }; + + +struct uart_device { + char *name; + const struct uart_operations *ops; + struct device dev; + const struct uart_platform_data *priv; + OS_MUTEX mutex; +}; + + + + +struct uart_operations { + int (*init)(struct uart_device *); + int (*read)(struct uart_device *, void *buf, u32 len); + int (*write)(struct uart_device *, void *buf, u16 len); + int (*ioctl)(struct uart_device *, u32 cmd, u32 arg); + int (*close)(struct uart_device *); +}; + + + +#define REGISTER_UART_DEVICE(dev) \ + static struct uart_device dev sec(.uart) + +extern struct uart_device uart_device_begin[], uart_device_end[]; + +#define list_for_each_uart_device(p) \ + for (p=uart_device_begin; p [> __u8 etc <] +// #include [> le16_to_cpu <] +#include "typedef.h" + +/* #define __le16_to_cpu(x) x */ +/*-------------------------------------------------------------------------*/ + +/* CONTROL REQUEST SUPPORT */ + +/* + * USB directions + * + * This bit flag is used in endpoint descriptors' bEndpointAddress field. + * It's also one of three fields in control requests bRequestType. + */ +#define USB_DIR_OUT 0 /* to device */ +#define USB_DIR_IN 0x80 /* to host */ + +/* + * USB types, the second of three bRequestType fields + */ +#define USB_TYPE_MASK (0x03 << 5) +#define USB_TYPE_STANDARD (0x00 << 5) +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) +#define USB_TYPE_RESERVED (0x03 << 5) + +/* + * USB recipients, the third of three bRequestType fields + */ +#define USB_RECIP_MASK 0x1f +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 +/* From Wireless USB 1.0 */ +#define USB_RECIP_PORT 0x04 +#define USB_RECIP_RPIPE 0x05 + +/* + * Standard requests, for the bRequest field of a SETUP packet. + * + * These are qualified by the bRequestType field, so that for example + * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved + * by a GET_STATUS request. + */ +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C +#define USB_REQ_SET_SEL 0x30 +#define USB_REQ_SET_ISOCH_DELAY 0x31 + +#define USB_REQ_SET_ENCRYPTION 0x0D /* Wireless USB */ +#define USB_REQ_GET_ENCRYPTION 0x0E +#define USB_REQ_RPIPE_ABORT 0x0E +#define USB_REQ_SET_HANDSHAKE 0x0F +#define USB_REQ_RPIPE_RESET 0x0F +#define USB_REQ_GET_HANDSHAKE 0x10 +#define USB_REQ_SET_CONNECTION 0x11 +#define USB_REQ_SET_SECURITY_DATA 0x12 +#define USB_REQ_GET_SECURITY_DATA 0x13 +#define USB_REQ_SET_WUSB_DATA 0x14 +#define USB_REQ_LOOPBACK_DATA_WRITE 0x15 +#define USB_REQ_LOOPBACK_DATA_READ 0x16 +#define USB_REQ_SET_INTERFACE_DS 0x17 + +/* The Link Power Management (LPM) ECN defines USB_REQ_TEST_AND_SET command, + * used by hubs to put ports into a new L1 suspend state, except that it + * forgot to define its number ... + */ + +/* + * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and + * are read as a bit array returned by USB_REQ_GET_STATUS. (So there + * are at most sixteen features of each type.) Hubs may also support a + * new USB_REQ_TEST_AND_SET_FEATURE to put ports into L1 suspend. + */ +#define USB_DEVICE_SELF_POWERED 0 /* (read only) */ +#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */ +#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */ +#define USB_DEVICE_BATTERY 2 /* (wireless) */ +#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */ +#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless)*/ +#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */ +#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */ +#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */ + +/* + * Test Mode Selectors + * See USB 2.0 spec Table 9-7 + */ +#define TEST_J 1 +#define TEST_K 2 +#define TEST_SE0_NAK 3 +#define TEST_PACKET 4 +#define TEST_FORCE_EN 5 + +/* + * New Feature Selectors as added by USB 3.0 + * See USB 3.0 spec Table 9-7 + */ +#define USB_DEVICE_U1_ENABLE 48 /* dev may initiate U1 transition */ +#define USB_DEVICE_U2_ENABLE 49 /* dev may initiate U2 transition */ +#define USB_DEVICE_LTM_ENABLE 50 /* dev may send LTM */ +#define USB_INTRF_FUNC_SUSPEND 0 /* function suspend */ + +#define USB_INTR_FUNC_SUSPEND_OPT_MASK 0xFF00 +/* + * Suspend Options, Table 9-8 USB 3.0 spec + */ +#define USB_INTRF_FUNC_SUSPEND_LP (1 << (8 + 0)) +#define USB_INTRF_FUNC_SUSPEND_RW (1 << (8 + 1)) + +/* + * Interface status, Figure 9-5 USB 3.0 spec + */ +#define USB_INTRF_STAT_FUNC_RW_CAP 1 +#define USB_INTRF_STAT_FUNC_RW 2 + +#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */ + +/* Bit array elements as returned by the USB_REQ_GET_STATUS request. */ +#define USB_DEV_STAT_U1_ENABLED 2 /* transition into U1 state */ +#define USB_DEV_STAT_U2_ENABLED 3 /* transition into U2 state */ +#define USB_DEV_STAT_LTM_ENABLED 4 /* Latency tolerance messages */ + +/** + * struct usb_ctrlrequest - SETUP data for a USB device control request + * @bRequestType: matches the USB bmRequestType field + * @bRequest: matches the USB bRequest field + * @wValue: matches the USB wValue field (le16 byte order) + * @wIndex: matches the USB wIndex field (le16 byte order) + * @wLength: matches the USB wLength field (le16 byte order) + * + * This structure is used to send control requests to a USB device. It matches + * the different fields of the USB 2.0 Spec section 9.3, table 9-2. See the + * USB spec for a fuller description of the different fields, and what they are + * used for. + * + * Note that the driver for any interface can issue control requests. + * For most devices, interfaces don't coordinate with each other, so + * such requests may be made at any time. + */ +struct usb_ctrlrequest { + u8 bRequestType; + u8 bRequest; + u16 wValue; + u16 wIndex; + u16 wLength; +} __attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + +/* + * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or + * (rarely) accepted by SET_DESCRIPTOR. + * + * Note that all multi-byte values here are encoded in little endian + * byte order "on the wire". Within the kernel and when exposed + * through the Linux-USB APIs, they are not converted to cpu byte + * order; it is the responsibility of the client code to do this. + * The single exception is when device and configuration descriptors (but + * not other descriptors) are read from usbfs (i.e. /proc/bus/usb/BBB/DDD); + * in this case the fields are converted to host endianness by the kernel. + */ + +/* + * Descriptor types ... USB 2.0 spec table 9.5 + */ +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 +#define USB_DT_DEVICE_QUALIFIER 0x06 +#define USB_DT_OTHER_SPEED_CONFIG 0x07 +#define USB_DT_INTERFACE_POWER 0x08 + +#define USB_DT_HUB (USB_TYPE_CLASS | 0x09) + +/* these are from a minor usb 2.0 revision (ECN) */ +#define USB_DT_OTG 0x09 +#define USB_DT_DEBUG 0x0a +#define USB_DT_INTERFACE_ASSOCIATION 0x0b +/* these are from the Wireless USB spec */ +#define USB_DT_SECURITY 0x0c +#define USB_DT_KEY 0x0d +#define USB_DT_ENCRYPTION_TYPE 0x0e +#define USB_DT_BOS 0x0f +#define USB_DT_DEVICE_CAPABILITY 0x10 +#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11 +#define USB_DT_WIRE_ADAPTER 0x21 +#define USB_DT_RPIPE 0x22 +#define USB_DT_CS_RADIO_CONTROL 0x23 +/* From the T10 UAS specification */ +#define USB_DT_PIPE_USAGE 0x24 +/* From the USB 3.0 spec */ +#define USB_DT_SS_ENDPOINT_COMP 0x30 + +/* Conventional codes for class-specific descriptors. The convention is + * defined in the USB "Common Class" Spec (3.11). Individual class specs + * are authoritative for their usage, not the "common class" writeup. + */ +#define USB_DT_CS_DEVICE (USB_TYPE_CLASS | USB_DT_DEVICE) +#define USB_DT_CS_CONFIG (USB_TYPE_CLASS | USB_DT_CONFIG) +#define USB_DT_CS_STRING (USB_TYPE_CLASS | USB_DT_STRING) +#define USB_DT_CS_INTERFACE (USB_TYPE_CLASS | USB_DT_INTERFACE) +#define USB_DT_CS_ENDPOINT (USB_TYPE_CLASS | USB_DT_ENDPOINT) + +/* All standard descriptors have these 2 fields at the beginning */ +struct usb_descriptor_header { + u8 bLength; + u8 bDescriptorType; +} __attribute__((packed)); + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEVICE: Device descriptor */ +struct usb_device_descriptor { + u8 bLength; + u8 bDescriptorType; + + u16 bcdUSB; + u8 bDeviceClass; + u8 bDeviceSubClass; + u8 bDeviceProtocol; + u8 bMaxPacketSize0; + u16 idVendor; + u16 idProduct; + u16 bcdDevice; + u8 iManufacturer; + u8 iProduct; + u8 iSerialNumber; + u8 bNumConfigurations; +} __attribute__((packed)); + +#define USB_DT_DEVICE_SIZE 18 + + +/* + * Device and/or Interface Class codes + * as found in bDeviceClass or bInterfaceClass + * and defined by www.usb.org documents + */ +#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ +#define USB_CLASS_AUDIO 1 +#define USB_CLASS_COMM 2 +#define USB_CLASS_HID 3 +#define USB_CLASS_PHYSICAL 5 +#define USB_CLASS_STILL_IMAGE 6 +#define USB_CLASS_PRINTER 7 +#define USB_CLASS_MASS_STORAGE 8 +#define USB_CLASS_HUB 9 +#define USB_CLASS_CDC_DATA 0x0a +#define USB_CLASS_CSCID 0x0b /* chip+ smart card */ +#define USB_CLASS_CONTENT_SEC 0x0d /* content security */ +#define USB_CLASS_VIDEO 0x0e +#define USB_CLASS_WIRELESS_CONTROLLER 0xe0 +#define USB_CLASS_MISC 0xef +#define USB_CLASS_APP_SPEC 0xfe +#define USB_CLASS_VENDOR_SPEC 0xff +#define USB_CLASS_UNKOWN 0x1ff + +#define USB_CLASS_ADB 0x42 +#define USB_CLASS_AOA 0x43 +#define USB_SUBCLASS_VENDOR_SPEC 0xff +#define PC_PROTOCOL_UNDEFINED 0x00 +/*-------------------------------------------------------------------------*/ + +/* USB_DT_CONFIG: Configuration descriptor information. + * + * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the + * descriptor type is different. Highspeed-capable devices can look + * different depending on what speed they're currently running. Only + * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG + * descriptors. + */ +struct usb_config_descriptor { + u8 bLength; + u8 bDescriptorType; + + u16 wTotalLength; + u8 bNumInterfaces; + u8 bConfigurationValue; + u8 iConfiguration; + u8 bmAttributes; + u8 bMaxPower; +} __attribute__((packed)); + +#define USB_DT_CONFIG_SIZE 9 + +/* from config descriptor bmAttributes */ +#define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */ +#define USB_CONFIG_ATT_SELFPOWER (1 << 6) /* self powered */ +#define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */ +#define USB_CONFIG_ATT_BATTERY (1 << 4) /* battery powered */ + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_STRING: String descriptor */ +struct usb_string_descriptor { + u8 bLength; + u8 bDescriptorType; + + u16 wData[1]; /* UTF-16LE encoded */ +} __attribute__((packed)); + +/* note that "string" zero is special, it holds language codes that + * the device supports, not Unicode characters. + */ + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_INTERFACE: Interface descriptor */ +struct usb_interface_descriptor { + u8 bLength; + u8 bDescriptorType; + + u8 bInterfaceNumber; + u8 bAlternateSetting; + u8 bNumEndpoints; + u8 bInterfaceClass; + u8 bInterfaceSubClass; + u8 bInterfaceProtocol; + u8 iInterface; +} __attribute__((packed)); + +#define USB_DT_INTERFACE_SIZE 9 + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_ENDPOINT: Endpoint descriptor */ +struct usb_endpoint_descriptor { + u8 bLength; + u8 bDescriptorType; + + u8 bEndpointAddress; + u8 bmAttributes; + u16 wMaxPacketSize; + u8 bInterval; + + /* NOTE: these two are _only_ in audio endpoints. */ + /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */ + u8 bRefresh; + u8 bSynchAddress; +} __attribute__((packed)); + +#define USB_DT_ENDPOINT_SIZE 7 +#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ + + +/* + * Endpoints + */ +#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */ +#define USB_ENDPOINT_DIR_MASK 0x80 + +#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */ +#define USB_ENDPOINT_XFER_CONTROL 0 +#define USB_ENDPOINT_XFER_ISOC 1 +#define USB_ENDPOINT_XFER_BULK 2 +#define USB_ENDPOINT_XFER_INT 3 +#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80 + +/* The USB 3.0 spec redefines bits 5:4 of bmAttributes as interrupt ep type. */ +#define USB_ENDPOINT_INTRTYPE 0x30 +#define USB_ENDPOINT_INTR_PERIODIC (0 << 4) +#define USB_ENDPOINT_INTR_NOTIFICATION (1 << 4) + +#define USB_ENDPOINT_SYNCTYPE 0x0c +#define USB_ENDPOINT_SYNC_NONE (0 << 2) +#define USB_ENDPOINT_SYNC_ASYNC (1 << 2) +#define USB_ENDPOINT_SYNC_ADAPTIVE (2 << 2) +#define USB_ENDPOINT_SYNC_SYNC (3 << 2) + +#define USB_ENDPOINT_USAGE_MASK 0x30 +#define USB_ENDPOINT_USAGE_DATA 0x00 +#define USB_ENDPOINT_USAGE_FEEDBACK 0x10 +#define USB_ENDPOINT_USAGE_IMPLICIT_FB 0x20 /* Implicit feedback Data endpoint */ + +/*-------------------------------------------------------------------------*/ + +/** + * usb_endpoint_num - get the endpoint's number + * @epd: endpoint to be checked + * + * Returns @epd's number: 0 to 15. + */ +static __inline__ int usb_endpoint_num(const struct usb_endpoint_descriptor *epd) +{ + return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; +} + +/** + * usb_endpoint_type - get the endpoint's transfer type + * @epd: endpoint to be checked + * + * Returns one of USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT} according + * to @epd's transfer type. + */ +static __inline__ int usb_endpoint_type(const struct usb_endpoint_descriptor *epd) +{ + return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; +} + +/** + * usb_endpoint_dir_in - check if the endpoint has IN direction + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type IN, otherwise it returns false. + */ +static __inline__ int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN); +} + +/** + * usb_endpoint_dir_out - check if the endpoint has OUT direction + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type OUT, otherwise it returns false. + */ +static __inline__ int usb_endpoint_dir_out( + const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); +} + +/** + * usb_endpoint_xfer_bulk - check if the endpoint has bulk transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type bulk, otherwise it returns false. + */ +static __inline__ int usb_endpoint_xfer_bulk( + const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK); +} + +/** + * usb_endpoint_xfer_control - check if the endpoint has control transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type control, otherwise it returns false. + */ +static __inline__ int usb_endpoint_xfer_control( + const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_CONTROL); +} + +/** + * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type interrupt, otherwise it returns + * false. + */ +static __inline__ int usb_endpoint_xfer_int( + const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_INT); +} + +/** + * usb_endpoint_xfer_isoc - check if the endpoint has isochronous transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type isochronous, otherwise it returns + * false. + */ +static __inline__ int usb_endpoint_xfer_isoc( + const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_ISOC); +} + +/** + * usb_endpoint_is_bulk_in - check if the endpoint is bulk IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has bulk transfer type and IN direction, + * otherwise it returns false. + */ +static __inline__ int usb_endpoint_is_bulk_in( + const struct usb_endpoint_descriptor *epd) +{ + return usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd); +} + +/** + * usb_endpoint_is_bulk_out - check if the endpoint is bulk OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has bulk transfer type and OUT direction, + * otherwise it returns false. + */ +static __inline__ int usb_endpoint_is_bulk_out( + const struct usb_endpoint_descriptor *epd) +{ + return usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd); +} + +/** + * usb_endpoint_is_int_in - check if the endpoint is interrupt IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has interrupt transfer type and IN direction, + * otherwise it returns false. + */ +static __inline__ int usb_endpoint_is_int_in( + const struct usb_endpoint_descriptor *epd) +{ + return usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd); +} + +/** + * usb_endpoint_is_int_out - check if the endpoint is interrupt OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has interrupt transfer type and OUT direction, + * otherwise it returns false. + */ +static __inline__ int usb_endpoint_is_int_out( + const struct usb_endpoint_descriptor *epd) +{ + return usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd); +} + +/** + * usb_endpoint_is_isoc_in - check if the endpoint is isochronous IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has isochronous transfer type and IN direction, + * otherwise it returns false. + */ +static __inline__ int usb_endpoint_is_isoc_in( + const struct usb_endpoint_descriptor *epd) +{ + return usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd); +} + +/** + * usb_endpoint_is_isoc_out - check if the endpoint is isochronous OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has isochronous transfer type and OUT direction, + * otherwise it returns false. + */ +static __inline__ int usb_endpoint_is_isoc_out( + const struct usb_endpoint_descriptor *epd) +{ + return usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd); +} + +/** + * usb_endpoint_maxp - get endpoint's max packet size + * @epd: endpoint to be checked + * + * Returns @epd's max packet + */ + +/* static __inline__ int usb_endpoint_maxp(const struct usb_endpoint_descriptor *epd) */ +/* { */ +/* return __le16_to_cpu(epd->wMaxPacketSize); */ +/* } */ + +static __inline__ int usb_endpoint_interrupt_type( + const struct usb_endpoint_descriptor *epd) +{ + return epd->bmAttributes & USB_ENDPOINT_INTRTYPE; +} + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */ +struct usb_ss_ep_comp_descriptor { + u8 bLength; + u8 bDescriptorType; + + u8 bMaxBurst; + u8 bmAttributes; + u16 wBytesPerInterval; +} __attribute__((packed)); + +#define USB_DT_SS_EP_COMP_SIZE 6 + +/* Bits 4:0 of bmAttributes if this is a bulk endpoint */ +static __inline__ int +usb_ss_max_streams(const struct usb_ss_ep_comp_descriptor *comp) +{ + int max_streams; + + if (!comp) { + return 0; + } + + max_streams = comp->bmAttributes & 0x1f; + + if (!max_streams) { + return 0; + } + + max_streams = 1 << max_streams; + + return max_streams; +} + +/* Bits 1:0 of bmAttributes if this is an isoc endpoint */ +#define USB_SS_MULT(p) (1 + ((p) & 0x3)) + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */ +struct usb_qualifier_descriptor { + u8 bLength; + u8 bDescriptorType; + + u16 bcdUSB; + u8 bDeviceClass; + u8 bDeviceSubClass; + u8 bDeviceProtocol; + u8 bMaxPacketSize0; + u8 bNumConfigurations; + u8 bRESERVED; +} __attribute__((packed)); + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_OTG (from OTG 1.0a supplement) */ +struct usb_otg_descriptor { + u8 bLength; + u8 bDescriptorType; + + u8 bmAttributes; /* support for HNP, SRP, etc */ +} __attribute__((packed)); + +/* from usb_otg_descriptor.bmAttributes */ +#define USB_OTG_SRP (1 << 0) +#define USB_OTG_HNP (1 << 1) /* swap host/device roles */ + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEBUG: for special highspeed devices, replacing serial console */ +struct usb_debug_descriptor { + u8 bLength; + u8 bDescriptorType; + + /* bulk endpoints with 8 byte maxpacket */ + u8 bDebugInEndpoint; + u8 bDebugOutEndpoint; +} __attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_INTERFACE_ASSOCIATION: groups interfaces */ +struct usb_interface_assoc_descriptor { + u8 bLength; + u8 bDescriptorType; + + u8 bFirstInterface; + u8 bInterfaceCount; + u8 bFunctionClass; + u8 bFunctionSubClass; + u8 bFunctionProtocol; + u8 iFunction; +} __attribute__((packed)); +#define USB_DT_INTERFACE_ASSOCIATION_SIZE 8 + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_SECURITY: group of wireless security descriptors, including + * encryption types available for setting up a CC/association. + */ +struct usb_security_descriptor { + u8 bLength; + u8 bDescriptorType; + + u16 wTotalLength; + u8 bNumEncryptionTypes; +} __attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_KEY: used with {GET,SET}_SECURITY_DATA; only public keys + * may be retrieved. + */ +struct usb_key_descriptor { + u8 bLength; + u8 bDescriptorType; + + u8 tTKID[3]; + u8 bReserved; + u8 bKeyData[0]; +} __attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_ENCRYPTION_TYPE: bundled in DT_SECURITY groups */ +struct usb_encryption_descriptor { + u8 bLength; + u8 bDescriptorType; + + u8 bEncryptionType; +#define USB_ENC_TYPE_UNSECURE 0 +#define USB_ENC_TYPE_WIRED 1 /* non-wireless mode */ +#define USB_ENC_TYPE_CCM_1 2 /* aes128/cbc session */ +#define USB_ENC_TYPE_RSA_1 3 /* rsa3072/sha1 auth */ + u8 bEncryptionValue; /* use in SET_ENCRYPTION */ + u8 bAuthKeyIndex; +} __attribute__((packed)); + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_BOS: group of device-level capabilities */ +struct usb_bos_descriptor { + u8 bLength; + u8 bDescriptorType; + + u16 wTotalLength; + u8 bNumDeviceCaps; +} __attribute__((packed)); + +#define USB_DT_BOS_SIZE 5 +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEVICE_CAPABILITY: grouped with BOS */ +struct usb_dev_cap_header { + u8 bLength; + u8 bDescriptorType; + u8 bDevCapabilityType; +} __attribute__((packed)); + +#define USB_CAP_TYPE_WIRELESS_USB 1 + +struct usb_wireless_cap_descriptor { /* Ultra Wide Band */ + u8 bLength; + u8 bDescriptorType; + u8 bDevCapabilityType; + + u8 bmAttributes; +#define USB_WIRELESS_P2P_DRD (1 << 1) +#define USB_WIRELESS_BEACON_MASK (3 << 2) +#define USB_WIRELESS_BEACON_SELF (1 << 2) +#define USB_WIRELESS_BEACON_DIRECTED (2 << 2) +#define USB_WIRELESS_BEACON_NONE (3 << 2) + u16 wPHYRates; /* bit rates, Mbps */ +#define USB_WIRELESS_PHY_53 (1 << 0) /* always set */ +#define USB_WIRELESS_PHY_80 (1 << 1) +#define USB_WIRELESS_PHY_107 (1 << 2) /* always set */ +#define USB_WIRELESS_PHY_160 (1 << 3) +#define USB_WIRELESS_PHY_200 (1 << 4) /* always set */ +#define USB_WIRELESS_PHY_320 (1 << 5) +#define USB_WIRELESS_PHY_400 (1 << 6) +#define USB_WIRELESS_PHY_480 (1 << 7) + u8 bmTFITXPowerInfo; /* TFI power levels */ + u8 bmFFITXPowerInfo; /* FFI power levels */ + u16 bmBandGroup; + u8 bReserved; +} __attribute__((packed)); + +/* USB 2.0 Extension descriptor */ +#define USB_CAP_TYPE_EXT 2 + +struct usb_ext_cap_descriptor { /* Link Power Management */ + u8 bLength; + u8 bDescriptorType; + u8 bDevCapabilityType; + u32 bmAttributes; +#define USB_LPM_SUPPORT (1 << 1) /* supports LPM */ +#define USB_BESL_SUPPORT (1 << 2) /* supports BESL */ +#define USB_BESL_BASELINE_VALID (1 << 3) /* Baseline BESL valid*/ +#define USB_BESL_DEEP_VALID (1 << 4) /* Deep BESL valid */ +#define USB_GET_BESL_BASELINE(p) (((p) & (0xf << 8)) >> 8) +#define USB_GET_BESL_DEEP(p) (((p) & (0xf << 12)) >> 12) +} __attribute__((packed)); + +#define USB_DT_USB_EXT_CAP_SIZE 7 + +/* + * SuperSpeed USB Capability descriptor: Defines the set of SuperSpeed USB + * specific device level capabilities + */ +#define USB_SS_CAP_TYPE 3 +struct usb_ss_cap_descriptor { /* Link Power Management */ + u8 bLength; + u8 bDescriptorType; + u8 bDevCapabilityType; + u8 bmAttributes; +#define USB_LTM_SUPPORT (1 << 1) /* supports LTM */ + u16 wSpeedSupported; +#define USB_LOW_SPEED_OPERATION (1) /* Low speed operation */ +#define USB_FULL_SPEED_OPERATION (1 << 1) /* Full speed operation */ +#define USB_HIGH_SPEED_OPERATION (1 << 2) /* High speed operation */ +#define USB_5GBPS_OPERATION (1 << 3) /* Operation at 5Gbps */ + u8 bFunctionalitySupport; + u8 bU1devExitLat; + u16 bU2DevExitLat; +} __attribute__((packed)); + +#define USB_DT_USB_SS_CAP_SIZE 10 + +/* + * Container ID Capability descriptor: Defines the instance unique ID used to + * identify the instance across all operating modes + */ +#define CONTAINER_ID_TYPE 4 +struct usb_ss_container_id_descriptor { + u8 bLength; + u8 bDescriptorType; + u8 bDevCapabilityType; + u8 bReserved; + u8 ContainerID[16]; /* 128-bit number */ +} __attribute__((packed)); + +#define USB_DT_USB_SS_CONTN_ID_SIZE 20 +/*-------------------------------------------------------------------------*/ + +/* USB_DT_WIRELESS_ENDPOINT_COMP: companion descriptor associated with + * each endpoint descriptor for a wireless device + */ +struct usb_wireless_ep_comp_descriptor { + u8 bLength; + u8 bDescriptorType; + + u8 bMaxBurst; + u8 bMaxSequence; + u16 wMaxStreamDelay; + u16 wOverTheAirPacketSize; + u8 bOverTheAirInterval; + u8 bmCompAttributes; +#define USB_ENDPOINT_SWITCH_MASK 0x03 /* in bmCompAttributes */ +#define USB_ENDPOINT_SWITCH_NO 0 +#define USB_ENDPOINT_SWITCH_SWITCH 1 +#define USB_ENDPOINT_SWITCH_SCALE 2 +} __attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + +/* USB_REQ_SET_HANDSHAKE is a four-way handshake used between a wireless + * host and a device for connection set up, mutual authentication, and + * exchanging short lived session keys. The handshake depends on a CC. + */ +struct usb_handshake { + u8 bMessageNumber; + u8 bStatus; + u8 tTKID[3]; + u8 bReserved; + u8 CDID[16]; + u8 nonce[16]; + u8 MIC[8]; +} __attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + +/* USB_REQ_SET_CONNECTION modifies or revokes a connection context (CC). + * A CC may also be set up using non-wireless secure channels (including + * wired USB!), and some devices may support CCs with multiple hosts. + */ +struct usb_connection_context { + u8 CHID[16]; /* persistent host id */ + u8 CDID[16]; /* device id (unique w/in host context) */ + u8 CK[16]; /* connection key */ +} __attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + +/* USB 2.0 defines three speeds, here's how Linux identifies them */ + +enum usb_device_speed { + USB_SPEED_UNKNOWN = 0, /* enumerating */ + USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ + USB_SPEED_HIGH, /* usb 2.0 */ + USB_SPEED_WIRELESS, /* wireless (usb 2.5) */ + USB_SPEED_SUPER, /* usb 3.0 */ +}; + + +enum usb_device_state { + /* NOTATTACHED isn't in the USB spec, and this state acts + * the same as ATTACHED ... but it's clearer this way. + */ + USB_STATE_NOTATTACHED = 0, + + /* chapter 9 and authentication (wireless) device states */ + USB_STATE_ATTACHED, + USB_STATE_POWERED, /* wired */ + USB_STATE_RECONNECTING, /* auth */ + USB_STATE_UNAUTHENTICATED, /* auth */ + USB_STATE_DEFAULT, /* limited function */ + USB_STATE_ADDRESS, + USB_STATE_CONFIGURED, /* most functions */ + + USB_STATE_SUSPENDED + + /* NOTE: there are actually four different SUSPENDED + * states, returning to POWERED, DEFAULT, ADDRESS, or + * CONFIGURED respectively when SOF tokens flow again. + * At this level there's no difference between L1 and L2 + * suspend states. (L2 being original USB 1.1 suspend.) + */ +}; + +enum usb3_link_state { + USB3_LPM_U0 = 0, + USB3_LPM_U1, + USB3_LPM_U2, + USB3_LPM_U3 +}; + +/* + * A U1 timeout of 0x0 means the parent hub will reject any transitions to U1. + * 0xff means the parent hub will accept transitions to U1, but will not + * initiate a transition. + * + * A U1 timeout of 0x1 to 0x7F also causes the hub to initiate a transition to + * U1 after that many microseconds. Timeouts of 0x80 to 0xFE are reserved + * values. + * + * A U2 timeout of 0x0 means the parent hub will reject any transitions to U2. + * 0xff means the parent hub will accept transitions to U2, but will not + * initiate a transition. + * + * A U2 timeout of 0x1 to 0xFE also causes the hub to initiate a transition to + * U2 after N*256 microseconds. Therefore a U2 timeout value of 0x1 means a U2 + * idle timer of 256 microseconds, 0x2 means 512 microseconds, 0xFE means + * 65.024ms. + */ +#define USB3_LPM_DISABLED 0x0 +#define USB3_LPM_U1_MAX_TIMEOUT 0x7F +#define USB3_LPM_U2_MAX_TIMEOUT 0xFE +#define USB3_LPM_DEVICE_INITIATED 0xFF + +struct usb_set_sel_req { + u8 u1_sel; + u8 u1_pel; + u16 u2_sel; + u16 u2_pel; +} __attribute__((packed)); + +/* + * The Set System Exit Latency control transfer provides one byte each for + * U1 SEL and U1 PEL, so the max exit latency is 0xFF. U2 SEL and U2 PEL each + * are two bytes long. + */ +#define USB3_LPM_MAX_U1_SEL_PEL 0xFF +#define USB3_LPM_MAX_U2_SEL_PEL 0xFFFF + +/*-------------------------------------------------------------------------*/ + +/* + * As per USB compliance update, a device that is actively drawing + * more than 100mA from USB must report itself as bus-powered in + * the GetStatus(DEVICE) call. + * http://compliance.usb.org/index.asp?UpdateFile=Electrical&Format=Standard#34 + */ +#define USB_SELF_POWER_VBUS_MAX_DRAW 100 + +#endif /* __LINUX_USB_CH9_H */ diff --git a/include_lib/driver/device/usb/device/descriptor.h b/include_lib/driver/device/usb/device/descriptor.h new file mode 100644 index 0000000..e70605b --- /dev/null +++ b/include_lib/driver/device/usb/device/descriptor.h @@ -0,0 +1,99 @@ +/**@file descriptor.h + * @brief 各种描述符头文件 + * @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 __DESCRIPTOR_H__ +#define __DESCRIPTOR_H__ + +#include "asm/usb.h" + +/**@brief USB获取设备描述符 + * @param[in] *ptr 存放设备描述符的地址 + * @return 无 + * @par 示例: + * @code + * get_device_descriptor(ptr); + * @encode + */ +void get_device_descriptor(u8 *ptr); + +/**@brief USB获取语言字符串描述符 + * @param[in] *ptr 存放语言字符串描述符的地址 + * @return 无 + * @par 示例: + * @code + * get_language_str(ptr); + * @encode + */ +void get_language_str(u8 *ptr); + +/**@brief USB获取生产商字符串描述符 + * @param[in] *ptr 存放生产商字符串描述符的地址 + * @return 无 + * @par 示例: + * @code + * get_manufacture_str(ptr); + * @encode + */ +void get_manufacture_str(u8 *ptr); + +/**@brief USB获取产品字符串描述符 + * @param[in] *ptr 存放产品字符串描述符的地址 + * @return 无 + * @par 示例: + * @code + * get_product_str(ptr); + * @encode + */ +void get_product_str(u8 *ptr); + +/**@brief USB获取序列号字符串描述符 + * @param[in] *ptr 存放序列号字符串描述符的地址 + * @return 无 + * @par 示例: + * @code + * get_iserialnumber_str(ptr); + * @encode + */ +void get_iserialnumber_str(u8 *ptr); + +/**@brief USB获取***字符串描述符 + * @param[in] *ptr 存放***字符串描述符的地址 + * @return 无 + * @par 示例: + * @code + * get_string_ee(ptr); + * @encode + */ +void get_string_ee(u8 *ptr); + +/**@brief USB设置描述符 + * @param[in] usb_id USB接口的id号 + * @param[in] class_config 类配置 + * @param[in] *p 存放描述符的地址 + * @param[in] max_len 最大长度 + * @return + * @par 示例: + * @code + * set_descriptor(usb_id,class_config,p,max_len); + * @encode + */ +u32 set_descriptor(const usb_dev usb_id, u32 class_config, u8 *p, u32 max_len); + + +#endif /*DESCRIPTOR_H*/ diff --git a/include_lib/driver/device/usb/device/hid.h b/include_lib/driver/device/usb/device/hid.h new file mode 100644 index 0000000..6bff10c --- /dev/null +++ b/include_lib/driver/device/usb/device/hid.h @@ -0,0 +1,212 @@ +/**@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 __USB_HID_H__ +#define __USB_HID_H__ + +#include "typedef.h" +#include "asm/usb.h" + +//do not add brace to the macro outside +#define SHORT_ITEMS(prefix, _len, ...) \ + ((prefix) | (((_len) > 0) ? 1 << ((_len) - 1) : 0)), ##__VA_ARGS__ + +/*Main Items*/ +#define INPUT(len, ...) SHORT_ITEMS(0x80, len, ##__VA_ARGS__) +#define OUTPUT(len, ...) SHORT_ITEMS(0x90, len, ##__VA_ARGS__) +#define COLLECTION(len, ...) SHORT_ITEMS(0xA0, len, ##__VA_ARGS__) +#define FEATURE(len, ...) SHORT_ITEMS(0xB0, len, ##__VA_ARGS__) +#define END_COLLECTION 0xC0 + +/*Golbal Items*/ +#define USAGE_PAGE(len, ...) SHORT_ITEMS(0x04, len, ##__VA_ARGS__) +#define LOGICAL_MIN(len, ...) SHORT_ITEMS(0x14, len, ##__VA_ARGS__) +#define LOGICAL_MAX(len, ...) SHORT_ITEMS(0x24, len, ##__VA_ARGS__) +#define PHYSICAL_MIN(len, ...) SHORT_ITEMS(0x34, len, ##__VA_ARGS__) +#define PHYSICAL_MAX(len, ...) SHORT_ITEMS(0x44, len, ##__VA_ARGS__) +#define UNIT_EXPONENT(len, ...) SHORT_ITEMS(0x54, len, ##__VA_ARGS__) +#define UNIT(len, ...) SHORT_ITEMS(0x64, len, ##__VA_ARGS__) +#define REPORT_SIZE(len, ...) SHORT_ITEMS(0x74, len, ##__VA_ARGS__) +#define REPORT_ID(len, ...) SHORT_ITEMS(0x84, len, ##__VA_ARGS__) +#define REPORT_COUNT(len, ...) SHORT_ITEMS(0x94, len, ##__VA_ARGS__) +#define PUSH SHORT_ITEMS(0xA4, 0) +#define POP SHORT_ITEMS(0xB4, 0) + +/*Local Items*/ +#define USAGE(len, ...) SHORT_ITEMS(0x08, len, ##__VA_ARGS__) +#define USAGE_MIN(len, ...) SHORT_ITEMS(0x18, len, ##__VA_ARGS__) +#define USAGE_MAX(len, ...) SHORT_ITEMS(0x28, len, ##__VA_ARGS__) +#define DESIGNATOR_INDEX(len, ...) SHORT_ITEMS(0x38, len, ##__VA_ARGS__) +#define DESIGNATOR_MIN(len, ...) SHORT_ITEMS(0x48, len, ##__VA_ARGS__) +#define DESIGNATOR_MAX(len, ...) SHORT_ITEMS(0x58, len, ##__VA_ARGS__) +#define STRING_INDEX(len, ...) SHORT_ITEMS(0x78, len, ##__VA_ARGS__) +#define STRING_MIN(len, ...) SHORT_ITEMS(0x88, len, ##__VA_ARGS__) +#define STRING_MAX(len, ...) SHORT_ITEMS(0x98, len, ##__VA_ARGS__) +#define DELIMITER(len, ...) SHORT_ITEMS(0xA8, len, ##__VA_ARGS__) + + +/*Consumer Page*/ +#define CONSUMER_PAGE 0x0C +#define CONSUMER_CONTROL 0x01 +#define GENERIC_DESKTOP_CTRLS 0x01 + +/*Usage*/ +#define POINTER 0x01 +#define MOUSE 0x02 +#define BUTTON 0x09 +#define X_AXIS 0x30 +#define Y_AXIS 0x31 + +//Collection +#define PHYSICAL 0x00 +#define APPLICATION 0x01 +#define LOGICAL 0x02 +#define REPORT 0x03 + +#define USB_HID_DT_HID (USB_TYPE_CLASS | 0x01) +#define USB_HID_DT_REPORT (USB_TYPE_CLASS | 0x02) +#define USB_HID_DT_PHYSICAL (USB_TYPE_CLASS | 0x03) +/* + * * HID requests + * */ +#define USB_REQ_GET_REPORT 0x01 +#define USB_REQ_GET_IDLE 0x02 +#define USB_REQ_GET_PROTOCOL 0x03 +#define USB_REQ_SET_REPORT 0x09 +#define USB_REQ_SET_IDLE 0x0A +#define USB_REQ_SET_PROTOCOL 0x0B + + + + +#define PLAY 0xB0 +#define PAUSE 0xB1 +#define RECORD 0xB2 +#define FAST_FORWARD 0xB3 +#define REWIND 0xB4 +#define SCAN_NEXT_TRACK 0xB5 +#define SCAN_PREV_TRACK 0xB6 +#define STOP 0xB7 +#define FRAME_FORWARD 0xC0 +#define FRAME_BACK 0xC1 +#define TRACKING_INC 0xCA +#define TRACKING_DEC 0xCB +#define STOP_EJECT 0xCC +#define PLAY_PAUSE 0xCD +#define PLAY_SKIP 0xCE +#define VOLUME 0xE0 +#define BALANCE 0xE1 +#define MUTE 0xE2 +#define BASS 0xE3 +#define VOLUME_INC 0xE9 +#define VOLUME_DEC 0xEA +#define BALANCE_LEFT 0x50, 0x01 +#define BALANCE_RIGHT 0x51, 0x01 +#define CHANNEL_LEFT 0x61, 0x01 +#define CHANNEL_RIGHT 0x62, 0x01 + + +//---------------------------------- +// HID key for audio +//---------------------------------- +#define USB_AUDIO_NONE 0 +#define USB_AUDIO_VOLUP BIT(0) +#define USB_AUDIO_VOLDOWN BIT(1) +#define USB_AUDIO_MUTE BIT(2) +#define USB_AUDIO_PP BIT(3) +#define USB_AUDIO_NEXTFILE BIT(4) +#define USB_AUDIO_PREFILE BIT(5) +#define USB_AUDIO_FASTFORWARD BIT(5) +#define USB_AUDIO_STOP BIT(7) + +#define USB_AUDIO_TRACKING_INC BIT(8) +#define USB_AUDIO_TRACKING_DEC BIT(9) +#define USB_AUDIO_STOP_EJECT BIT(10) +#define USB_AUDIO_VOLUME BIT(11) +#define USB_AUDIO_BALANCE_RIGHT BIT(12) +#define USB_AUDIO_BALANCE_LEFT BIT(13) +#define USB_AUDIO_PLAY BIT(14) +#define USB_AUDIO_PAUSE BIT(15) + +/**@brief USB hid描述符配置 + * @param[in] usb_id usb的id号 + * @param[in] *ptr 指向HID描述符 + * @param[in] *cur_itf_num 当前接口号 + * @return HID描述符长度,单位Byte + * @par 示例: + * @code + * hid_desc_config(usb_id,ptr,cur_itf_num); + * @encode + */ +u32 hid_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num); +u32 hid_second_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num); + +/**@brief hid按键处理函数 + * @param[in] *usb_device usb_device_t定义的结构体指针 + * @param[in] hid_key hid按键信息 + * @return 无 + * @par 示例: + * @code + * hid_key_handler(usb_device,hidkey); + * @encode + */ +void hid_key_handler(struct usb_device_t *usb_device, u32 hid_key); + +/**@brief hid按键处理函数,用于特殊发送一个包的场景(正常hidkey有两个包) + * @param[in] *usb_device usb_device_t定义的结构体指针 + * @param[in] hid_key hid按键信息 + * @return 无 + * @par 示例: + * @code + * hid_key_handler_send_one_packet(usb_device,hidkey); + * @encode + */ +void hid_key_handler_send_one_packet(struct usb_device_t *usb_device, u32 hid_key); + +/**@brief hid发送数据 + * @param[in] *p 数据指针,指向存放数据的地址 + * @param[in] len 发送的数据长度 + * @return + * @par 示例: + * @code + * hid_send_data(p,len); + * @encode + */ +u32 hid_send_data(const void *p, u32 len); + +/**@brief hid注册 + * @param[in] usb_id usb的id号 + * @return 0 + * @par 示例: + * @code + * hid_register(usb_id); + * @encode + */ +u32 hid_register(const usb_dev usb_id); + +/**@brief hid释放(暂未使用) + * @param[in] usb_id usb的id号 + * @return 0 + * @par 示例: + * @code + * hid_release(usb_id); + * @encode + */ +void hid_release(const usb_dev usb_id); +#endif diff --git a/include_lib/driver/device/usb/device/msd.h b/include_lib/driver/device/usb/device/msd.h new file mode 100644 index 0000000..43da13e --- /dev/null +++ b/include_lib/driver/device/usb/device/msd.h @@ -0,0 +1,34 @@ +#ifndef __USBD_MSD_H__ +#define __USBD_MSD_H__ + +#include "asm/usb.h" +#include "usb_stack.h" + +#define MAX_MSD_DEV 2 +#define MSD_DEV_NAME_LEN 12 + +struct msd_info { + u8 bError; + u8 bSenseKey; + u8 bAdditionalSenseCode; + u8 bAddiSenseCodeQualifier; + u8 bDisk_popup[MAX_MSD_DEV]; + void *dev_handle[MAX_MSD_DEV]; + char dev_name[MAX_MSD_DEV][MSD_DEV_NAME_LEN]; + void (*msd_wakeup_handle)(struct usb_device_t *usb_device); + void (*msd_reset_wakeup_handle)(struct usb_device_t *usb_device, u32 itf_num); +}; + + + +u32 msd_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num); +void USB_MassStorage(const struct usb_device_t *usb_device); +u32 msd_set_wakeup_handle(void (*handle)(struct usb_device_t *usb_device)); +u32 msd_register_disk(const char *name, void *arg); +u32 msd_unregister_disk(const char *name); +u32 msd_unregister_all(); +u32 msd_register(const usb_dev id); +u32 msd_release(); +void msd_set_reset_wakeup_handle(void (*handle)(struct usb_device_t *usb_device, u32 itf_num)); +void msd_reset(struct usb_device_t *usb_device, u32 itf_num); +#endif /*USBD_MSD_H*/ diff --git a/include_lib/driver/device/usb/device/uac_audio.h b/include_lib/driver/device/usb/device/uac_audio.h new file mode 100644 index 0000000..86e144c --- /dev/null +++ b/include_lib/driver/device/usb/device/uac_audio.h @@ -0,0 +1,470 @@ +/** + * -- USB Audio definitions. + * + * Copyright (C) 2006 Thumtronics Pty Ltd. + * Developed for Thumtronics by Grey Innovation + * Ben Williamson + * + * This software is distributed under the terms of the GNU General Public + * License ("GPL") version 2, as published by the Free Software Foundation. + * + * This file holds USB constants and structures defined + * by the USB Device Class Definition for Audio Devices. + * Comments below reference relevant sections of that document: + * + * http://www.usb.org/developers/devclass_docs/audio10.pdf + * + * Types and defines in this file are either specific to version 1.0 of + * this standard or common for newer versions. + */ + +#ifndef __LINUX_USB_AUDIO_H +#define __LINUX_USB_AUDIO_H + +#ifdef __cplusplus +extern "C" { +#endif +#define __le16 u16 + +#define u8 unsigned char // u8 to u32 special for struct +#define u16 unsigned short // u16 to u32 special for struct +#ifndef __s16 +#define s16 short // only s16 +#endif +#define u32 unsigned int + +/* A.8. Audio Class-Specific Request Codes */ +#define UAC_RC_UNDEFINED 0x00 +#define UAC_SET_CUR 0x01 +#define UAC_GET_CUR 0x81 +#define UAC_GET_MIN 0x82 +#define UAC_GET_MAX 0x83 +#define UAC_GET_RES 0x84 +#define UAC_GET_LEN 0x85 +#define UAC_GET_INFO 0x86 +#define UAC_GET_DEF 0x87 + + +/** bInterfaceProtocol values to denote the version of the standard used */ +#define UAC_VERSION_1 0x00 +#define UAC_VERSION_2 0x20 + +/** A.2 Audio Interface Subclass Codes */ +#define USB_SUBCLASS_AUDIOCONTROL 0x01 +#define USB_SUBCLASS_AUDIOSTREAMING 0x02 +#define USB_SUBCLASS_MIDISTREAMING 0x03 + +/** A.5 Audio Class-Specific AC Interface Descriptor Subtypes */ +#define UAC_HEADER 0x01 +#define UAC_INPUT_TERMINAL 0x02 +#define UAC_OUTPUT_TERMINAL 0x03 +#define UAC_MIXER_UNIT 0x04 +#define UAC_SELECTOR_UNIT 0x05 +#define UAC_FEATURE_UNIT 0x06 +#define UAC1_PROCESSING_UNIT 0x07 +#define UAC1_EXTENSION_UNIT 0x08 + +/** A.6 Audio Class-Specific AS Interface Descriptor Subtypes */ +#define UAC_AS_GENERAL 0x01 +#define UAC_FORMAT_TYPE 0x02 +#define UAC_FORMAT_SPECIFIC 0x03 + +/** A.7 Processing Unit Process Types */ +#define UAC_PROCESS_UNDEFINED 0x00 +#define UAC_PROCESS_UP_DOWNMIX 0x01 +#define UAC_PROCESS_DOLBY_PROLOGIC 0x02 +#define UAC_PROCESS_STEREO_EXTENDER 0x03 +#define UAC_PROCESS_REVERB 0x04 +#define UAC_PROCESS_CHORUS 0x05 +#define UAC_PROCESS_DYN_RANGE_COMP 0x06 + +/** A.8 Audio Class-Specific Endpoint Descriptor Subtypes */ +#define UAC_EP_GENERAL 0x01 + +/** A.9 Audio Class-Specific Request Codes */ + +#define UAC_GET_STAT 0xff + +/** A.10 Control Selector Codes */ + +/** A.10.1 Terminal Control Selectors */ +#define UAC_TERM_COPY_PROTECT 0x01 + +/** A.10.2 Feature Unit Control Selectors */ +#define UAC_FU_MUTE 0x01 +#define UAC_FU_VOLUME 0x02 +#define UAC_FU_BASS 0x03 +#define UAC_FU_MID 0x04 +#define UAC_FU_TREBLE 0x05 +#define UAC_FU_GRAPHIC_EQUALIZER 0x06 +#define UAC_FU_AUTOMATIC_GAIN 0x07 +#define UAC_FU_DELAY 0x08 +#define UAC_FU_BASS_BOOST 0x09 +#define UAC_FU_LOUDNESS 0x0a + +#define UAC_CONTROL_BIT(CS) (1 << ((CS) - 1)) + +/** A.10.3.1 Up/Down-mix Processing Unit Controls Selectors */ +#define UAC_UD_ENABLE 0x01 +#define UAC_UD_MODE_SELECT 0x02 + +/** A.10.3.2 Dolby Prologic (tm) Processing Unit Controls Selectors */ +#define UAC_DP_ENABLE 0x01 +#define UAC_DP_MODE_SELECT 0x02 + +/** A.10.3.3 3D Stereo Extender Processing Unit Control Selectors */ +#define UAC_3D_ENABLE 0x01 +#define UAC_3D_SPACE 0x02 + +/** A.10.3.4 Reverberation Processing Unit Control Selectors */ +#define UAC_REVERB_ENABLE 0x01 +#define UAC_REVERB_LEVEL 0x02 +#define UAC_REVERB_TIME 0x03 +#define UAC_REVERB_FEEDBACK 0x04 + +/** A.10.3.5 Chorus Processing Unit Control Selectors */ +#define UAC_CHORUS_ENABLE 0x01 +#define UAC_CHORUS_LEVEL 0x02 +#define UAC_CHORUS_RATE 0x03 +#define UAC_CHORUS_DEPTH 0x04 + +/** A.10.3.6 Dynamic Range Compressor Unit Control Selectors */ +#define UAC_DCR_ENABLE 0x01 +#define UAC_DCR_RATE 0x02 +#define UAC_DCR_MAXAMPL 0x03 +#define UAC_DCR_THRESHOLD 0x04 +#define UAC_DCR_ATTACK_TIME 0x05 +#define UAC_DCR_RELEASE_TIME 0x06 + +/** A.10.4 Extension Unit Control Selectors */ +#define UAC_XU_ENABLE 0x01 + +/** MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */ +#define UAC_MS_HEADER 0x01 +#define UAC_MIDI_IN_JACK 0x02 +#define UAC_MIDI_OUT_JACK 0x03 + +/** MIDI - A.1 MS Class-Specific Endpoint Descriptor Subtypes */ +#define UAC_MS_GENERAL 0x01 + +/** Terminals - 2.1 USB Terminal Types */ +#define UAC_TERMINAL_UNDEFINED 0x0100 +#define UAC_TERMINAL_STREAMING 0x0101 +#define UAC_TERMINAL_VENDOR_SPEC 0x01FF + +/** Terminal Control Selectors */ +/** 4.3.2 Class-Specific AC Interface Descriptor */ +struct uac1_ac_header_descriptor { + u8 bLength; /** 8 + n */ + u8 bDescriptorType; /** USB_DT_CS_INTERFACE */ + u8 bDescriptorSubtype; /** UAC_MS_HEADER */ + __le16 bcdADC; /** 0x0100 */ + __le16 wTotalLength; /** includes Unit and Terminal desc. */ + u8 bInCollection; /** n */ + u8 baInterfaceNr[]; /** [n] */ +} __attribute__((packed)); + +#define UAC_DT_AC_HEADER_SIZE(n) (8 + (n)) + +/** As above, but more useful for defining your own descriptors: */ +#define DECLARE_UAC_AC_HEADER_DESCRIPTOR(n) \ + struct uac1_ac_header_descriptor_##n { \ + u8 bLength; \ + u8 bDescriptorType; \ + u8 bDescriptorSubtype; \ + __le16 bcdADC; \ + __le16 wTotalLength; \ + u8 bInCollection; \ + u8 baInterfaceNr[n]; \ + } __attribute__ ((packed)) + +/** 4.3.2.1 Input Terminal Descriptor */ +struct uac_input_terminal_descriptor { + u8 bLength; /** in bytes: 12 */ + u8 bDescriptorType; /** CS_INTERFACE descriptor type */ + u8 bDescriptorSubtype; /** INPUT_TERMINAL descriptor subtype */ + u8 bTerminalID; /** Constant uniquely terminal ID */ + __le16 wTerminalType; /** USB Audio Terminal Types */ + u8 bAssocTerminal; /** ID of the Output Terminal associated */ + u8 bNrChannels; /** Number of logical output channels */ + __le16 wChannelConfig; + u8 iChannelNames; + u8 iTerminal; +} __attribute__((packed)); + +#define UAC_DT_INPUT_TERMINAL_SIZE 12 + +/** Terminals - 2.2 Input Terminal Types */ +#define UAC_INPUT_TERMINAL_UNDEFINED 0x200 +#define UAC_INPUT_TERMINAL_MICROPHONE 0x201 +#define UAC_INPUT_TERMINAL_DESKTOP_MICROPHONE 0x202 +#define UAC_INPUT_TERMINAL_PERSONAL_MICROPHONE 0x203 +#define UAC_INPUT_TERMINAL_OMNI_DIR_MICROPHONE 0x204 +#define UAC_INPUT_TERMINAL_MICROPHONE_ARRAY 0x205 +#define UAC_INPUT_TERMINAL_PROC_MICROPHONE_ARRAY 0x206 + +/** Terminals - control selectors */ + +#define UAC_TERMINAL_CS_COPY_PROTECT_CONTROL 0x01 + +/** 4.3.2.2 Output Terminal Descriptor */ +struct uac1_output_terminal_descriptor { + u8 bLength; /** in bytes: 9 */ + u8 bDescriptorType; /** CS_INTERFACE descriptor type */ + u8 bDescriptorSubtype; /** OUTPUT_TERMINAL descriptor subtype */ + u8 bTerminalID; /** Constant uniquely terminal ID */ + __le16 wTerminalType; /** USB Audio Terminal Types */ + u8 bAssocTerminal; /** ID of the Input Terminal associated */ + u8 bSourceID; /** ID of the connected Unit or Terminal*/ + u8 iTerminal; +} __attribute__((packed)); + +#define UAC_DT_OUTPUT_TERMINAL_SIZE 9 + +/** Terminals - 2.3 Output Terminal Types */ +#define UAC_OUTPUT_TERMINAL_UNDEFINED 0x300 +#define UAC_OUTPUT_TERMINAL_SPEAKER 0x301 +#define UAC_OUTPUT_TERMINAL_HEADPHONES 0x302 +#define UAC_OUTPUT_TERMINAL_HEAD_MOUNTED_DISPLAY_AUDIO 0x303 +#define UAC_OUTPUT_TERMINAL_DESKTOP_SPEAKER 0x304 +#define UAC_OUTPUT_TERMINAL_ROOM_SPEAKER 0x305 +#define UAC_OUTPUT_TERMINAL_COMMUNICATION_SPEAKER 0x306 +#define UAC_OUTPUT_TERMINAL_LOW_FREQ_EFFECTS_SPEAKER 0x307 +#define UAC_OUTPUT_TERMINAL_HEADSET 0x0402 + +/** Set bControlSize = 2 as default setting */ +#define UAC_DT_FEATURE_UNIT_SIZE(ch) (7 + ((ch) + 1) * 2) + +/** As above, but more useful for defining your own descriptors: */ +#define DECLARE_UAC_FEATURE_UNIT_DESCRIPTOR(ch) \ + struct uac_feature_unit_descriptor_##ch { \ + u8 bLength; \ + u8 bDescriptorType; \ + u8 bDescriptorSubtype; \ + u8 bUnitID; \ + u8 bSourceID; \ + u8 bControlSize; \ + __le16 bmaControls[ch + 1]; \ + u8 iFeature; \ + } __attribute__ ((packed)) + +/** 4.3.2.3 Mixer Unit Descriptor */ +struct uac_mixer_unit_descriptor { + u8 bLength; + u8 bDescriptorType; + u8 bDescriptorSubtype; + u8 bUnitID; + u8 bNrInPins; + u8 baSourceID[]; +} __attribute__((packed)); + + + +/** 4.3.2.4 Selector Unit Descriptor */ +struct uac_selector_unit_descriptor { + u8 bLength; + u8 bDescriptorType; + u8 bDescriptorSubtype; + u8 bUintID; + u8 bNrInPins; + u8 baSourceID[]; +} __attribute__((packed)); + + + +/** 4.3.2.5 Feature Unit Descriptor */ +struct uac_feature_unit_descriptor { + u8 bLength; + u8 bDescriptorType; + u8 bDescriptorSubtype; + u8 bUnitID; + u8 bSourceID; + u8 bControlSize; + u8 bmaControls[0]; /** variable length */ +} __attribute__((packed)); + + + +/** 4.3.2.6 Processing Unit Descriptors */ +struct uac_processing_unit_descriptor { + u8 bLength; + u8 bDescriptorType; + u8 bDescriptorSubtype; + u8 bUnitID; + u16 wProcessType; + u8 bNrInPins; + u8 baSourceID[]; +} __attribute__((packed)); + + + + +/** 4.5.2 Class-Specific AS Interface Descriptor */ +struct uac1_as_header_descriptor { + u8 bLength; /** in bytes: 7 */ + u8 bDescriptorType; /** USB_DT_CS_INTERFACE */ + u8 bDescriptorSubtype; /** AS_GENERAL */ + u8 bTerminalLink; /** Terminal ID of connected Terminal */ + u8 bDelay; /** Delay introduced by the data path */ + __le16 wFormatTag; /** The Audio Data Format */ +} __attribute__((packed)); + +#define UAC_DT_AS_HEADER_SIZE 7 + +/** Formats - A.1.1 Audio Data Format Type I Codes */ +#define UAC_FORMAT_TYPE_I_UNDEFINED 0x0 +#define UAC_FORMAT_TYPE_I_PCM 0x1 +#define UAC_FORMAT_TYPE_I_PCM8 0x2 +#define UAC_FORMAT_TYPE_I_IEEE_FLOAT 0x3 +#define UAC_FORMAT_TYPE_I_ALAW 0x4 +#define UAC_FORMAT_TYPE_I_MULAW 0x5 + +struct uac_format_type_i_continuous_descriptor { + u8 bLength; /** in bytes: 8 + (ns * 3) */ + u8 bDescriptorType; /** USB_DT_CS_INTERFACE */ + u8 bDescriptorSubtype; /** FORMAT_TYPE */ + u8 bFormatType; /** FORMAT_TYPE_1 */ + u8 bNrChannels; /** physical channels in the stream */ + u8 bSubframeSize; /** */ + u8 bBitResolution; + u8 bSamFreqType; + u8 tLowerSamFreq[3]; + u8 tUpperSamFreq[3]; +} __attribute__((packed)); + +#define UAC_FORMAT_TYPE_I_CONTINUOUS_DESC_SIZE 14 + +struct uac_format_type_i_discrete_descriptor { + u8 bLength; /** in bytes: 8 + (ns * 3) */ + u8 bDescriptorType; /** USB_DT_CS_INTERFACE */ + u8 bDescriptorSubtype; /** FORMAT_TYPE */ + u8 bFormatType; /** FORMAT_TYPE_1 */ + u8 bNrChannels; /** physical channels in the stream */ + u8 bSubframeSize; /** */ + u8 bBitResolution; + u8 bSamFreqType; + u8 tSamFreq[][3]; +} __attribute__((packed)); + +#define DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(n) \ + struct uac_format_type_i_discrete_descriptor_##n { \ + u8 bLength; \ + u8 bDescriptorType; \ + u8 bDescriptorSubtype; \ + u8 bFormatType; \ + u8 bNrChannels; \ + u8 bSubframeSize; \ + u8 bBitResolution; \ + u8 bSamFreqType; \ + u8 tSamFreq[n][3]; \ + } __attribute__ ((packed)) + +#define UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(n) (8 + (n * 3)) + +struct uac_format_type_i_ext_descriptor { + u8 bLength; + u8 bDescriptorType; + u8 bDescriptorSubtype; + u8 bFormatType; + u8 bSubslotSize; + u8 bBitResolution; + u8 bHeaderLength; + u8 bControlSize; + u8 bSideBandProtocol; +} __attribute__((packed)); + +/** Formats - Audio Data Format Type I Codes */ + +#define UAC_FORMAT_TYPE_II_MPEG 0x1001 +#define UAC_FORMAT_TYPE_II_AC3 0x1002 + +struct uac_format_type_ii_discrete_descriptor { + u8 bLength; + u8 bDescriptorType; + u8 bDescriptorSubtype; + u8 bFormatType; + __le16 wMaxBitRate; + __le16 wSamplesPerFrame; + u8 bSamFreqType; + u8 tSamFreq[][3]; +} __attribute__((packed)); + +struct uac_format_type_ii_ext_descriptor { + u8 bLength; + u8 bDescriptorType; + u8 bDescriptorSubtype; + u8 bFormatType; + u16 wMaxBitRate; + u16 wSamplesPerFrame; + u8 bHeaderLength; + u8 bSideBandProtocol; +} __attribute__((packed)); + +/** type III */ +#define UAC_FORMAT_TYPE_III_IEC1937_AC3 0x2001 +#define UAC_FORMAT_TYPE_III_IEC1937_MPEG1_LAYER1 0x2002 +#define UAC_FORMAT_TYPE_III_IEC1937_MPEG2_NOEXT 0x2003 +#define UAC_FORMAT_TYPE_III_IEC1937_MPEG2_EXT 0x2004 +#define UAC_FORMAT_TYPE_III_IEC1937_MPEG2_LAYER1_LS 0x2005 +#define UAC_FORMAT_TYPE_III_IEC1937_MPEG2_LAYER23_LS 0x2006 + +/** Formats - A.2 Format Type Codes */ +#define UAC_FORMAT_TYPE_UNDEFINED 0x0 +#define UAC_FORMAT_TYPE_I 0x1 +#define UAC_FORMAT_TYPE_II 0x2 +#define UAC_FORMAT_TYPE_III 0x3 +#define UAC_EXT_FORMAT_TYPE_I 0x81 +#define UAC_EXT_FORMAT_TYPE_II 0x82 +#define UAC_EXT_FORMAT_TYPE_III 0x83 + +struct uac_iso_endpoint_descriptor { + u8 bLength; /** in bytes: 7 */ + u8 bDescriptorType; /** USB_DT_CS_ENDPOINT */ + u8 bDescriptorSubtype; /** EP_GENERAL */ + u8 bmAttributes; + u8 bLockDelayUnits; + __le16 wLockDelay; +} __attribute__((packed)); +#define UAC_ISO_ENDPOINT_DESC_SIZE 7 + +#define UAC_EP_CS_ATTR_SAMPLE_RATE 0x01 +#define UAC_EP_CS_ATTR_PITCH_CONTROL 0x02 +#define UAC_EP_CS_ATTR_FILL_MAX 0x80 + +/** status word format (3.7.1.1) */ + +#define UAC1_STATUS_TYPE_ORIG_MASK 0x0f +#define UAC1_STATUS_TYPE_ORIG_AUDIO_CONTROL_IF 0x0 +#define UAC1_STATUS_TYPE_ORIG_AUDIO_STREAM_IF 0x1 +#define UAC1_STATUS_TYPE_ORIG_AUDIO_STREAM_EP 0x2 + +#define UAC1_STATUS_TYPE_IRQ_PENDING (1 << 7) +#define UAC1_STATUS_TYPE_MEM_CHANGED (1 << 6) + +#include "asm/usb.h" +struct uac1_status_word { + u8 bStatusType; + u8 bOriginator; +} __attribute__((packed)); + +u32 uac_setup_endpoint(struct usb_device_t *usb_device, struct usb_ctrlrequest *req); +u32 uac_spk_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num); +void uac_speaker_stream_write(const u8 *obuf, u32 len); +void uac_speaker_stream_open(u32 samplerate, u32 ch); +void uac_speaker_stream_close(); + +u32 uac_mic_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num); +u32 uac_mic_stream_open(u32 samplerate, u32 frame_len, u32 ch); +int uac_mic_stream_read(u8 *buf, u32 len); +void uac_mic_stream_close(); +void uac_mute_volume(u32 type, u32 l_vol, u32 r_vol); +int uac_get_spk_vol(); +u32 uac_audio_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num); +void uac_audio_disable(const usb_dev usb_id); +const u8 *uac_get_string(u32 id); +u32 uac_register(const usb_dev usb_id, const u32 class); +void uac_release(const usb_dev usb_id); +#ifdef __cplusplus +} +#endif +#endif /** __LINUX_USB_AUDIO_H */ diff --git a/include_lib/driver/device/usb/device/usb_stack.h b/include_lib/driver/device/usb/device/usb_stack.h new file mode 100644 index 0000000..46ab71f --- /dev/null +++ b/include_lib/driver/device/usb/device/usb_stack.h @@ -0,0 +1,226 @@ +#ifndef __USB_STACK_H__ +#define __USB_STACK_H__ +#include "typedef.h" +#include "asm/usb.h" +#include "usb/ch9.h" +#include "usb/usb_phy.h" +#include "usb/otg.h" + + +#define MAX_INTERFACE_NUM 6 +#define USB_SUSPEND_RESUME 0 +#define USB_SUSPEND_RESUME_SYSTEM_NO_SLEEP 0 +#define USB_SETUP_SIZE (512) + +#if 0 +#define USB_ATTACHED BIT(0) +#define USB_POWERED BIT(1) +#define USB_DEFAULT BIT(2) +#define USB_ADDRESS BIT(3) +#define USB_CONFIGURED BIT(4) +#define USB_SUSPENDED BIT(5) +#else +enum { + USB_ATTACHED, + USB_POWERED, + USB_DEFAULT, + USB_ADDRESS, + USB_CONFIGURED, + USB_SUSPENDED +}; +#endif +struct usb_device_t { + u8 baddr; + u8 bsetup_phase; //ep0 setup状态机 + u16 wDataLength; //ep0 setup data stage数据长度 + + u8 *setup_buffer; //本次传输的bufer地址 + u8 *setup_ptr; //当前传输的位置 + u32(*setup_hook)(struct usb_device_t *, struct usb_ctrlrequest *); + u32(*setup_recv)(struct usb_device_t *, struct usb_ctrlrequest *); + + u8 bDeviceStates; + u8 bDataOverFlag; //ep0 0包标识 + u8 wDeviceClass; // 设备类 + u8 bRemoteWakup: 1; + u8 baddr_config: 1; +#if USB_MAX_HW_NUM == 2 + u8 usb_id: 1; + u8 res: 5; +#else + u8 res: 6; +#endif +}; + +typedef u32(*itf_hander)(struct usb_device_t *usb_device, struct usb_ctrlrequest *); +typedef void(*itf_reset_hander)(struct usb_device_t *, u32 itf); +typedef void(*usb_interrupt)(struct usb_device_t *, u32 ep); +typedef u32(*desc_config)(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num); + +struct usb_setup_t { + struct usb_device_t usb_device; + struct usb_ctrlrequest request; + itf_hander interface_hander[MAX_INTERFACE_NUM]; + itf_reset_hander reset_hander[MAX_INTERFACE_NUM]; +} __attribute__((aligned(4))); + +/**@brief 获取USB接口的id号 + * @param[in] *usb_device usb_device_t定义的结构体指针 + * @return USB的id号 + * @par 示例: + * @code + * usb_device2id(usb_device); + * @encode + */ +const usb_dev usb_device2id(const struct usb_device_t *usb_device); + +/**@brief 获取usb_device_t定义的结构体地址 + * @param[in] usb_id USB接口的id号 + * @return 该结构的地址 + * @par 示例: + * @code + * usb_id2device(usb_device); + * @encode + */ +struct usb_device_t *usb_id2device(const usb_dev usb_id); + +/**@brief USB setup阶段控制传输 + * @param[in] *usb_device usb_device_t定义的结构体指针 + * @return 无 + * @par 示例: + * @code + * usb_control_transfer(usb_device); + * @encode + */ +void usb_control_transfer(struct usb_device_t *usb_device); + +/**@brief USB设置设备类 + * @param[in] *usb_device usb_device_t定义的结构体指针 + * @param[in] class_config 设备类设置 + * @return 无 + * @par 示例: + * @code + * usb_device_set_class(usb_device,class_config); + * @encode + */ +void usb_device_set_class(struct usb_device_t *usb_device, u32 class_config); +u32 usb_g_set_intr_hander(const usb_dev usb_id, u32 ep, usb_interrupt hander); + +/**@brief USB设置接口服务函数 + * @param[in] usb_id USB接口的id号 + * @param[in] itf_num 接口号 + * @param[in] hander 自己定义的函数 + * @return itf_num:成功 0:失败 + * @par 示例: + * @code + * usb_set_interface_hander(usb_id,itf_num,hander); + * @encode + */ +u32 usb_set_interface_hander(const usb_dev usb_id, u32 itf_num, itf_hander hander); +void usb_add_desc_config(const usb_dev usb_id, u32 index, const desc_config desc); +const u8 *usb_get_config_desc(); + +/**@brief USB设置复位服务函数 + * @param[in] usb_id USB接口的id号 + * @param[in] itf_num 接口号 + * @param[in] hander 自己定义的函数 + * @return itf_num:成功 0:失败 + * @par 示例: + * @code + * usb_set_reset_hander(usb_id,itf_num,hander); + * @encode + */ +u32 usb_set_reset_hander(const usb_dev usb_id, u32 itf_num, itf_reset_hander hander); + +/**@brief USB接口复位 + * @param[in] *usb_device usb_device_t定义的结构体指针 + * @return 无 + * @par 示例: + * @code + * usb_reset_interface(usb_device); + * @encode + */ +void usb_reset_interface(struct usb_device_t *usb_device); +void usb_set_setup_recv(struct usb_device_t *usb_device, void *recv); +void usb_set_setup_hook(struct usb_device_t *usb_device, void *hook); +int usb_device_mode(const usb_dev usb_id, const u32 class); + +/**@brief otg检测中sof初始化 + * @param[in] usb_id USB接口的id号 + * @return 1:等待sof信号 + * @par 示例: + * @code + * usb_otg_sof_check_init(usb_id); + * @encode + */ +u32 usb_otg_sof_check_init(const usb_dev id); + +/**@brief USB setup阶段初始化 + * @param[in] usb_id USB接口的id号 + * @param[in] *ptr usb_setup_t定义的结构体地址 + * @param[in] *setup_buffer setup_buffer的地址 + * @return 无 + * @par 示例: + * @code + * usb_setup_init(usb_id,ptr,setup_buffer); + * @encode + */ +void usb_setup_init(const usb_dev usb_id, void *ptr, u8 *setup_buffer); + +/**@brief USB setup阶段释放 + * @param[in] usb_id USB接口的id号 + * @return 0:成功 + * @par 示例: + * @code + * usb_setup_release(usb_id); + * @encode + */ +u32 usb_setup_release(const usb_dev usb_id); + +/**@brief USB设置数据载荷 + * @param[in] *usb_device usb_device_t定义的结构体指针 + * @param[in] *req usb_ctrlrequest定义的结构体指针 + * @param[in] *data 存放数据指针 + * @param[in] len 数据长度 + * @return setup_buffer的地址 + * @par 示例: + * @code + * usb_set_data_payload(usb_device,req,tx_payload,len); + * @encode + */ +u8 *usb_set_data_payload(struct usb_device_t *usb_device, struct usb_ctrlrequest *req, const void *data, u32 len); + +/**@brief USB设置控制传输阶段 + * @param[in] *usb_device usb_device_t定义的结构体指针 + * @param[in] setup_phase 需要设置成的阶段 + * @return 无 + * @par 示例: + * @code + * usb_set_setup_phase(usb_id); + * @encode + */ +void usb_set_setup_phase(struct usb_device_t *usb_device, u8 setup_phase); +void dump_setup_request(const struct usb_ctrlrequest *request); +void user_setup_filter_install(struct usb_device_t *usb_device); +void usb_ep_enable(const usb_dev usb_id, u32 ep, u32 is_enable); + +/**@brief USB获取本次传输的buffer地址 + * @param[in] *usb_device usb_device_t定义的结构体指针 + * @return setup_buffer地址 + * @par 示例: + * @code + * usb_get_setup_buffer(usb_device); + * @encode + */ +void *usb_get_setup_buffer(const struct usb_device_t *usb_device); +u32 usb_root2_testing(); + +extern void usb_start(); +extern void usb_stop(); +extern void usb_pause(); +extern void usb_cdc_background_run(); + +/* #define usb_add_desc_config(fn) \ */ +/* const desc_config usb_desc_config##fn sec(.usb.desc_config) = fn */ + +#endif /*USB_STACK_H*/ diff --git a/include_lib/driver/device/usb/host/usb_host.h b/include_lib/driver/device/usb/host/usb_host.h new file mode 100644 index 0000000..d8c8fb8 --- /dev/null +++ b/include_lib/driver/device/usb/host/usb_host.h @@ -0,0 +1,261 @@ +/**@file usb_host.h + * @brief usb_host驱动头文件(做主机) + * @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_HOST_H__ +#define __USB_HOST_H__ +#include "system/task.h" +#include "device/device.h" +#include "asm/usb.h" +#include "usb/ch9.h" +#include "usb/usb_phy.h" +// #include "usb_config.h" + + +#define USB_HUB 0 + +/**@struct usb_private_data + * @brief usb_private_data私有数据结构体\n + * 自定义一些私有数据信息存储在该结构体中 + */ +struct usb_private_data { + usb_dev usb_id; ///private_data)) + +/**@brief USB设备id号获取 + * @param[in] usb_host_device定义的结构体指针 + * @return USB设备的id号,如 0:USB0 ; 1:USB1 + * @par 示例: + * @code + * host_device2id(host_dev); 获取host_dev的USB设备id号 + * @encode + */ +u32 host_device2id(const struct usb_host_device *host_dev); + +/**@brief USB设备状态获取 + * @param[in] usb_host_device定义的结构体指针 + * @return USB设备的状态,如 0:下线 ; 1:上线 + * @par 示例: + * @code + * host_dev_status(host_dev); 获取host_dev的USB设备状态 + * @encode + */ +int host_dev_status(const struct usb_host_device *host_dev); + +/**@brief 获取usb_host_device结构体的信息 + * @param[in] USB的id号 + * @return 结构体信息的存储首地址 + * @par 示例: + * @code + * struct usb_host_device *host_dev = &host_devices[usb_id]; + * @encode + */ +const struct usb_host_device *host_id2device(const usb_dev id); + +#define check_usb_mount(ret) \ + if(ret == -DEV_ERR_OFFLINE){\ + log_error("%s() @ %d DEV_ERR_OFFLINE\n", __func__, __LINE__);\ + goto __exit_fail;\ + } else if(ret){\ + log_error("%s() @ %d %x\n", __func__, __LINE__, ret);\ + continue;\ + } + + +typedef void(*usb_h_interrupt)(struct usb_host_device *, u32 ep); + +/**@brief USB_sem初始化 + * @param[in] usb_host_device定义的结构体指针 + * @return 0:成功 + * @par 示例: + * @code + * host_sem_init(host_dev); + * @encode + */ +int usb_sem_init(struct usb_host_device *host_dev); + +/**@brief USB_sem申请一个信号量 + * @param[in] usb_host_device定义的结构体指针 + * @param[in] timeout 超时时间设置,单位ms + * @return + * @par 示例: + * @code + * host_sem_pend(host_dev,1000); + * @encode + */ +int usb_sem_pend(struct usb_host_device *host_dev, u32 timeout); + +/**@brief USB_sem释放一个信号量 + * @param[in] usb_host_device定义的结构体指针 + * @return 0:成功 + * @par 示例: + * @code + * host_sem_psot(host_dev); + * @encode + */ +int usb_sem_post(struct usb_host_device *host_dev); + +/**@brief USB_sem删除 + * @param[in] usb_host_device定义的结构体指针 + * @return + * @par 示例: + * @code + * host_sem_del(host_dev); + * @encode + */ +int usb_sem_del(struct usb_host_device *host_dev); + +/**@brief USB主机模式设置端点中断 + * @param[in] usb_host_device定义的结构体指针 + * @param[in] ep 端点号 + * @param[in] hander usb_h_interrupt定义的指针函数 + * @param[in] *p + * @return 无 + * @par 示例: + * @code + * usb_h_set_ep_isr(host_dev , 0 , func , host_dev); + * @encode + */ +void usb_h_set_ep_isr(struct usb_host_device *host_dev, u32 ep, usb_h_interrupt hander, void *p); + +/**@brief USB主机设置中断处理函数 + * @param[in] usb_id USB的id号 + * @param[in] ep 端点号 + * @param[in] hander usb_h_interrupt定义的指针函数 + * @return 0:成功 + * @par 示例: + * @code + * usb_h_set_intr_hander(usb_id , 0 , func); + * @encode + */ +u32 usb_h_set_intr_hander(const usb_dev usb_id, u32 ep, usb_h_interrupt hander); + +/**@brief USB主机模式挂载 + * @param[in] usb_id USB的id号 + * @param[in] retry 主机挂载重试次数 + * @param[in] reset_delay 复位等待延时 单位ms + * @param[in] mount_timeout 挂载超时时间 单位ms + * @return + * @par 示例: + * @code + * usb_host_mount(usb_id , 5 , 10 , 1000 ); + * @encode + */ +u32 usb_host_mount(const usb_dev usb_id, u32 retry, u32 reset_delay, u32 mount_timeout); + +/**@brief USB主机模式卸载 + * @param[in] usb_id USB的id号 + * @return 0:成功 + * @par 示例: + * @code + * usb_host_unmount(usb_id); + * @encode + */ +u32 usb_host_unmount(const usb_dev usb_id); + +/**@brief USB主机模式重新挂载 + * @param[in] usb_id USB的id号 + * @param[in] retry 主机挂载重试次数 + * @param[in] delay 复位等待延时 单位ms + * @param[in] ot 挂载超时时间 单位ms + * @param[in] notify 事件发送开关 1:开启 0:关闭 + * @return 0:成功 + * @par 示例: + * @code + * usb_host_remount(usb_id , 5 , 10 , 1000 , 1); + * @encode + */ +u32 usb_host_remount(const usb_dev usb_id, u32 retry, u32 delay, u32 ot, u8 notify); + +/**@brief USB主机模式挂起 + * @param[in] usb_id USB的id号 + * @return 无 + * @par 示例: + * @code + * usb_host_suspend(usb_id); + * @encode + */ +void usb_host_suspend(const usb_dev usb_id); + +/**@brief USB主机模式恢复 + * @param[in] usb_id USB的id号 + * @return 无 + * @par 示例: + * @code + * usb_host_resume(usb_id); + * @encode + */ +void usb_host_resume(const usb_dev usb_id); + +int usb_host_force_reset(const usb_dev usb_id); + +#endif /*USB_HOST_H*/ diff --git a/include_lib/driver/device/usb/otg.h b/include_lib/driver/device/usb/otg.h new file mode 100644 index 0000000..b98d602 --- /dev/null +++ b/include_lib/driver/device/usb/otg.h @@ -0,0 +1,140 @@ +/**@file otg.h + * @brief otg驱动头文件 + * @details 结构体声明,功能函数声明 + * @author jieli + * @date 2021-7-22 + * @version V1.0 + * @copyright Copyright(c)2010-2021 珠海市杰理科技股份有限公司 + ********************************************************************* + * @attention + * 硬件平台:AC632N + * SDK版本:AC632N_V1.0.0_SDK + * @修改日志: + * + *
Date Version Author Description + *
2021-7-22 1.0 jieli 创建初始版本 + *
+ * + ********************************************************************* + */ +#ifndef __OTG_H__ +#define __OTG_H__ + +#include "asm/usb.h" + +/**@enum usb_hotplug.state 或 usb_hotplug.last_state + * @brief otg当前所处模式 或 上一次所处模式 + */ +enum { + IDLE_MODE = 0, ///<空闲模式 + DISCONN_MODE = 1, ///<断连模式 + HOST_MODE = 2, ///<主机模式 + PRE_SLAVE_MODE, ///<成为从机模式前的一个中间模式 + SLAVE_MODE_WAIT_CONFIRMATION, ///<从机模式还需等待再次确认 + SLAVE_MODE, ///<从机模式 + CHARGE_MODE, ///<充电模式 + OTG_USER_MODE, ///<用户模式,暂时未具体定义 +}; + +/**@enum 空 + * @brief otg挂起时,所选操作模式 + */ +enum { + OTG_OP_NULL = 0, ///< ///<空,无意义 + OTG_UNINSTALL = 1, ///(b) ? (a) : (b)) +#endif + +#define ___ntohl(X) ((((u16)(X) & 0xff00) >> 8) |(((u16)(X) & 0x00ff) << 8)) + +#define ___ntohs(X) ((((u32)(X) & 0xff000000) >> 24) | \ + (((u32)(X) & 0x00ff0000) >> 8) | \ + (((u32)(X) & 0x0000ff00) << 8) | \ + (((u32)(X) & 0x000000ff) << 24)) + +#if defined(cpu_to_be16) || defined(cpu_to_be32) || defined(be16_to_cpu) || defined(be32_to_cpu) +#error #define cpu_to_be16 +#endif + +#define cpu_to_be16(v16) ___ntohl(v16) +#define cpu_to_be32(v32) ___ntohs(v32) + +#define be16_to_cpu(v16) cpu_to_be16(v16) +#define be32_to_cpu(v32) cpu_to_be32(v32) +#define __le16_to_cpu(v16) (v16) +#define __le32_to_cpu(v32) (v32) + +#if defined(cpu_to_le16) || defined(cpu_to_le32) || defined(le16_to_cpu) || defined(le32_to_cpu) +#error #define cpu_to_be16 +#endif + +#define cpu_to_le16(v16) (v16) +#define cpu_to_le32(v32) (v32) + +#define le16_to_cpu(v16) cpu_to_le16(v16) +#define le32_to_cpu(v32) cpu_to_le32(v32) + +#define LOWORD(l) ((u16)(l)) +#define HIWORD(l) ((u16)(((u32)(l) >> 16) & 0xFFFF)) + +#define LOBYTE(w) ((u8)(w)) +#define HIBYTE(w) ((u8)(((u16)(w) >> 8) & 0xFF)) + +#define DW1BYTE(dw) (LOBYTE(LOWORD(dw))) +#define DW2BYTE(dw) (HIBYTE(LOWORD(dw))) +#define DW3BYTE(dw) (LOBYTE(HIWORD(dw))) +#define DW4BYTE(dw) (HIBYTE(HIWORD(dw))) + +//............. Full Speed USB ................... +#define MUSB_FADDR 0x00 +#define MUSB_POWER 0x01 +#define MUSB_INTRTX1 0x02 +#define MUSB_INTRTX2 0x03 +#define MUSB_INTRRX1 0x04 +#define MUSB_INTRRX2 0x05 +#define MUSB_INTRUSB 0x06 +#define MUSB_INTRTX1E 0x07 +#define MUSB_INTRTX2E 0x08 +#define MUSB_INTRRX1E 0x09 +#define MUSB_INTRRX2E 0x0a +#define MUSB_INTRUSBE 0x0b +#define MUSB_FRAME1 0x0c +#define MUSB_FRAME2 0x0d +#define MUSB_INDEX 0x0e +#define MUSB_DEVCTL 0x0f +#define MUSB_TXMAXP 0x10 +#define MUSB_CSR0 0x11 +#define MUSB_TXCSR1 0x11 +#define MUSB_TXCSR2 0x12 +#define MUSB_RXMAXP 0x13 +#define MUSB_RXCSR1 0x14 +#define MUSB_RXCSR2 0x15 +#define MUSB_COUNT0 0x16 +#define MUSB_RXCOUNT1 0x16 +#define MUSB_RXCOUNT2 0x17 +#define MUSB_TXTYPE 0x18 +#define MUSB_TXINTERVAL 0x19 +#define MUSB_RXTYPE 0x1a +#define MUSB_RXINTERVAL 0x1b + +/*****MUSB SFR BitMap******/ +/*INTRUSB mode*/ +#define INTRUSB_SUSPEND BIT(0) +#define INTRUSB_RESUME BIT(1) +#define INTRUSB_RESET_BABBLE BIT(2) +#define INTRUSB_SOF BIT(3) +#define INTRUSB_CONNECT BIT(4) +#define INTRUSB_DISCONNECT BIT(5) +#define INTRUSB_SESS_REQ BIT(6) +#define INTRUSB_VBUS_ERROR BIT(7) + +/*CSR0 peripheral mode*/ +#define CSR0P_RxPktRdy 0x01 +#define CSR0P_TxPktRdy 0x02 +#define CSR0P_SentStall 0x04 +#define CSR0P_DataEnd 0x08 +#define CSR0P_SetupEnd 0x10 +#define CSR0P_SendStall 0x20 +#define CSR0P_ClrRxPktRdy 0x40 +#define CSR0P_ClrSetupEnd 0x80 + + +/*TXCSR1 peripheral mode*/ +#define TXCSRP_TxPktRdy 0x01 +#define TXCSRP_FIFONotEmpty 0x02 +#define TXCSRP_UnderRun 0x04 +#define TXCSRP_FlushFIFO 0x08 +#define TXCSRP_SendStall 0x10 +#define TXCSRP_SentStall 0x20 +#define TXCSRP_ClrDataTog 0x40 +#define TXCSRP_IncompTx 0x80 +#define TXCSRP_DIR (BIT(13)) +#define TXCSRP_ISOCHRONOUS (BIT(14)) + +/*RXCSR1 peripheral mode*/ +#define RXCSRP_RxPktRdy 0x01 +#define RXCSRP_FIFOFull 0x02 +#define RXCSRP_OverRun 0x04 +#define RXCSRP_DataError 0x08 +#define RXCSRP_FlushFIFO 0x10 +#define RXCSRP_SendStall 0x20 +#define RXCSRP_SentStall 0x40 +#define RXCSRP_ClrDataTog 0x80 +#define RXCSRP_IncompRx (BIT(8)) +#define RXCSRP_ISOCHRONOUS (BIT(14)) + +/*CSR0 host mode*/ +#define CSR0H_RxPktRdy 0x01 +#define CSR0H_TxPktRdy 0x02 +#define CSR0H_RxStall 0x04 +#define CSR0H_SetupPkt 0x08 +#define CSR0H_Error 0x10 +#define CSR0H_ReqPkt 0x20 +#define CSR0H_StatusPkt 0x40 +#define CSR0H_DISPING (BIT(11)) + +/*TXCSR1 host mode*/ +#define TXCSRH_TxPktRdy 0x01 +#define TXCSRH_FIFONotEmpty 0x02 +#define TXCSRH_Error 0x04 +#define TXCSRH_FlushFIFO 0x08 +#define TXCSRH_RxStall 0x20 +#define TXCSRH_ClrDataTog 0x40 +#define TXCSRH_NAK 0x80 + +/*RXCSR1 host mode*/ +#define RXCSRH_RxPktRdy 0x01 +#define RXCSRH_FIFOFull 0x02 +#define RXCSRH_Error 0x04 +#define RXCSRH_DataError 0x08 +#define RXCSRH_FlushFIFO 0x10 +#define RXCSRH_ReqPkt 0x20 +#define RXCSRH_RxStall 0x40 +#define RXCSRH_ClrDataTog 0x80 +#define RXCSRH_IncompRx BIT(8) +#define RXCSRH_PIDError BIT(12) + + +///USB Slave 控制传输各阶段 +#define USB_EP0_STAGE_SETUP 0 +#define USB_EP0_STAGE_IN 1 +#define USB_EP0_STAGE_OUT 2 +#define USB_EP0_SET_STALL 3 +#define USB_EP0_IGNORE 4 +#define USB_EP0_STAGE_NAK 5 + +/* common api */ +u32 usb_get_jiffies(); +u32 usb_host_timeout(u32 ot); +u32 usb_phy_status(const usb_dev id); +u32 usb_sie_status(const usb_dev id); +u32 usb_check_dpo(const usb_dev id); +u32 usb_check_dmo(const usb_dev id); +u32 usb_read_dp_se(const usb_dev id); +u32 usb_read_dm_se(const usb_dev id); +u32 usb_read_sofpnd(const usb_dev id); +void usb_write_txfuncaddr(const usb_dev id, const u32 ep, const u32 devnum); +void usb_write_rxfuncaddr(const usb_dev id, const u32 ep, const u32 devnum); + + +/* slave api */ +u32 usb_g_bulk_read64byte_fast(const usb_dev usb_id, u32 ep, u8 *ptr, u32 len); +u32 usb_g_bulk_read(const usb_dev usb_id, u32 ep, u8 *ptr, u32 len, u32 block); +u32 usb_g_bulk_write(const usb_dev usb_id, u32 ep, const u8 *ptr, u32 len); +u32 usb_g_intr_read(const usb_dev usb_id, u32 ep, u8 *ptr, u32 len, u32 block); +u32 usb_g_intr_write(const usb_dev usb_id, u32 ep, const u8 *ptr, u32 len); +u32 usb_g_iso_read(const usb_dev usb_id, u32 ep, u8 *ptr, u32 len, u32 block); +u32 usb_g_iso_write(const usb_dev usb_id, u32 ep, const u8 *ptr, u32 len); +void usb_slave_init(const usb_dev usb_id); +void usb_phy_resume(const usb_dev usb_id); +void usb_phy_suspend(const usb_dev usb_id); + +/* host api */ + +u32 usb_h_bulk_read(const usb_dev usb_id, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *ptr, u32 len); +u32 usb_h_bulk_write(const usb_dev usb_id, u8 host_ep, u16 txmaxp, u8 target_ep, u8 *ptr, u32 len); +u32 usb_h_intr_read(const usb_dev usb_id, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *ptr, u32 len); +u32 usb_h_intr_write(const usb_dev usb_id, u8 host_ep, u16 txmaxp, u8 target_ep, u8 *ptr, u32 len); +u32 usb_h_iso_read(const usb_dev usb_id, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *ptr, u32 len); +u32 usb_h_iso_write(const usb_dev usb_id, u8 host_ep, u16 txmaxp, u8 target_ep, u8 *ptr, u32 len); +void usb_h_entry_suspend(const usb_dev usb_id); +void usb_h_resume(const usb_dev usb_id); +u32 usb_host_init(const usb_dev usb_id, u32 reset_delay, u32 timeout); +u32 usb_host_reset(const usb_dev usb_id, u32 reset_delay, u32 timeout); +void usb_h_force_reset(const usb_dev usb_id); +// u32 usb_h_sie_init(u32 reset_delay, u32 timeout); +// void usb_h_sie_close(); + +#endif /*USB_PHY_H*/ diff --git a/include_lib/media/AudioEffect_DataType.h b/include_lib/media/AudioEffect_DataType.h new file mode 100644 index 0000000..798fb0c --- /dev/null +++ b/include_lib/media/AudioEffect_DataType.h @@ -0,0 +1,24 @@ +#ifndef _AUDIOEFFECT_DATATYPE_ +#define _AUDIOEFFECT_DATATYPE_ + +enum PCMDataType { + DATA_INT_16BIT = 0, + DATA_INT_32BIT, + DATA_FLOAT_32BIT +}; + +enum { + af_DATABIT_NOTSUPPORT = 0x404, +}; + + +typedef struct _af_DataType_ { + unsigned char IndataBit; + unsigned char OutdataBit; + char IndataInc; + char OutdataInc; + char Qval; +} af_DataType; + +#endif // !_AUDIOEFFECT_DATATYPE_ + diff --git a/include_lib/media/VirtualBass_api.h b/include_lib/media/VirtualBass_api.h new file mode 100644 index 0000000..4b7833e --- /dev/null +++ b/include_lib/media/VirtualBass_api.h @@ -0,0 +1,39 @@ +#ifndef VIRTUALBASS_API_H +#define VIRTUALBASS_API_H + +#include "AudioEffect_DataType.h" + +#ifdef WIN32 + +#define AT_VBSS(x) +#define AT_VBSS_CODE +#define AT_VBSS_CONST +#define AT_VBSS_SPARSE_CODE +#define AT_VBSS_SPARSE_CONST + +#else +#define AT_VBSS(x) __attribute((section(#x))) +#define AT_VBSS_CODE AT_VBSS(.vbss_code) +#define AT_VBSS_CONST AT_VBSS(.vbss_const) +#define AT_VBSS_SPARSE_CODE AT_VBSS(.vbss_sparse_code) +#define AT_VBSS_SPARSE_CONST AT_VBSS(.vbss_sparse_const) +#endif + + +typedef struct _VirtualBassParam { + int ratio; + int boost; + int fc; + int channel; + int SampleRate; + af_DataType pcm_info; +} VirtualBassParam; + +int getVirtualBassBuf(); +int VirtualBassInit(void *WorkBuf, VirtualBassParam *param); +int VirtualBassReserveLowFreq(void *WorkBuf, VirtualBassParam *param, int ReserveLowFreqEnable); +void VirtualBassUpdate(void *WorkBuf, VirtualBassParam *param); +int VirtualBassRun(void *WorkBuf, int *tmpbuf, void *in, void *out, int per_channel_npoint); + +#endif // !VIRTUALBASS_API_H + diff --git a/include_lib/media/a2dp_sample_detect.h b/include_lib/media/a2dp_sample_detect.h new file mode 100644 index 0000000..1635565 --- /dev/null +++ b/include_lib/media/a2dp_sample_detect.h @@ -0,0 +1,17 @@ +/***************************************************************** +>file name : a2dp_sample_detect.h +>create time : Mon 23 Jul 2021 11:26:34 AM CST +*****************************************************************/ +#ifndef _A2DP_SAMPLE_DETECT_H_ +#define _A2DP_SAMPLE_DETECT_H_ +#include "typedef.h" +#include "audio_base.h" + +void *a2dp_sample_detect_open(int sample_rate, u32 coding_type); + +int a2dp_frame_sample_detect_start(void *hdl, u32 time); + +int a2dp_frame_sample_detect(void *hdl, void *data, int len, u32 time); + +void a2dp_sample_detect_close(void *hdl); +#endif diff --git a/include_lib/media/aispeech/asr/include/vad_asr_demo.h b/include_lib/media/aispeech/asr/include/vad_asr_demo.h new file mode 100644 index 0000000..91e1931 --- /dev/null +++ b/include_lib/media/aispeech/asr/include/vad_asr_demo.h @@ -0,0 +1,18 @@ +#ifndef _AISPEECH_VAD_ASR_DEMO_H +#define _AISPEECH_VAD_ASR_DEMO_H + +#ifdef __cplusplus +extern "C" { +#endif + +void *aispeech_vad_asr_init(void); +void aispeech_vad_asr_deinit(void); +int aispeech_vad_asr_feed(char *data, int data_len); + +typedef int (*asr_output_handler)(int status, const char *json, int bytes); +void aispeech_asr_register_handler(asr_output_handler func); + +#ifdef __cplusplus +} +#endif +#endif // _AISPEECH_VAD_ASR_MANAGER_H diff --git a/include_lib/media/aispeech/enc/include/aispeech_enc.h b/include_lib/media/aispeech/enc/include/aispeech_enc.h new file mode 100644 index 0000000..d066f27 --- /dev/null +++ b/include_lib/media/aispeech/enc/include/aispeech_enc.h @@ -0,0 +1,17 @@ +#ifndef _AISPEECH_NR_H_ +#define _AISPEECH_NR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +int Aispeech_NR_getmemsize(short sample_rate); +int Aispeech_NR_init(char *pcMemPool, unsigned int memPoolLen, short sample_rate); +int Aispeech_NR_run(short *mic0, short *mic1, short *mic2, short *ref, short *out, short points); +int Aispeech_NR_deinit(void); +#ifdef __cplusplus +}; + +#endif +#endif + diff --git a/include_lib/media/audio_def.h b/include_lib/media/audio_def.h new file mode 100644 index 0000000..975bd80 --- /dev/null +++ b/include_lib/media/audio_def.h @@ -0,0 +1,67 @@ +/* + ******************************************************************* + * Audio Common Definitions + * + *Note(s): + * (1)Only macro definitions can be defined here. + * (2)Use (1UL << (n)) instead of BIT(n) + ******************************************************************* + */ +#ifndef _AUDIO_DEF_H_ +#define _AUDIO_DEF_H_ + +/* + ******************************************************************* + * DAC Definitions + ******************************************************************* + */ + +/* + ******************************************************************* + * ADC Definitions + ******************************************************************* + */ + + +/* + ******************************************************************* + * Linein(Aux) Definitions + ******************************************************************* + */ + + +/* + ******************************************************************* + * ANC Definitions + ******************************************************************* + */ +//ANC Mode Enable +#define ANC_FF_EN (1UL << (0)) +#define ANC_FB_EN (1UL << (1)) +#define ANC_HYBRID_EN (1UL << (2)) + +//ANC芯片版本定义 +#define ANC_VERSION_BR30 0x01 //AD697N/AC897N +#define ANC_VERSION_BR30C 0x02 //AC699N/AD698N +#define ANC_VERSION_BR36 0x03 //AC700N +#define ANC_VERSION_BR28 0x04 //AC701N/BR40 +//多滤波器版本 +#define ANC_VERSION_BR28_MULT 0xA4 //AC701N 支持多滤波器 + +/* + ******************************************************************* + * PCM Output Definitions + ******************************************************************* + */ +#define AUDIO_WAY_TYPE_DAC (1UL << (0)) +#define AUDIO_WAY_TYPE_IIS (1UL << (1)) +#define AUDIO_WAY_TYPE_FM (1UL << (2)) +#define AUDIO_WAY_TYPE_HDMI (1UL << (3)) +#define AUDIO_WAY_TYPE_SPDIF (1UL << (4)) +#define AUDIO_WAY_TYPE_BT (1UL << (5)) +#define AUDIO_WAY_TYPE_DONGLE (1UL << (6)) + +#define AUDIO_WAY_TYPE_MAX 7 +#define AUDIO_WAY_TYPE_ALL 0x00ffffff + +#endif/*_AUDIO_DEF_H_*/ diff --git a/include_lib/media/audio_drc.h b/include_lib/media/audio_drc.h new file mode 100644 index 0000000..7aea4c3 --- /dev/null +++ b/include_lib/media/audio_drc.h @@ -0,0 +1,164 @@ +#ifndef CONFIG_EFFECT_CORE_V2_ENABLE +#include "application/audio_drc.h" +#else + +#ifndef _DRC_API_H_ +#define _DRC_API_H_ + +#include "typedef.h" +#include "media/sw_drc.h" +#include "media/audio_stream.h" +#include "system/init.h" + +#define CROSSOVER_EN BIT(0) //多带分频器使能 +#define MORE_BAND_EN BIT(1) //多带分频后,再做一次全带处理使能 +struct audio_drc_filter_info { + CrossOverParam_TOOL_SET *crossover; + wdrc_struct_TOOL_SET *wdrc; + // struct drc_ch *pch; //左声道系数 + // struct drc_ch *R_pch; //右声道系数 +}; + +typedef int (*audio_drc_filter_cb)(void *drc, struct audio_drc_filter_info *info); + +struct audio_drc_param { + u32 channels : 8; //通道数 (channels|(L_wdrc))或(channels|(R_wdrc)) + u32 online_en : 1; //是否支持在线调试 + u32 remain_en : 1; //写1 + u32 stero_div : 1; //是否左右声道 拆分的 drc效果,一般写0 + u32 reserved : 21; + audio_drc_filter_cb cb; //系数更新的回调函数,用户赋值 + u32 sr; //数据采样率 + u8 drc_name; //在线调试是,根据drc_name区分更新系数,一般写0 + u8 out_32bit; //是否支持32bit 的输入数据处理 1:使能 0:不使能 + u8 nband; //多带之后,再使能一次 全带处理 + CrossOverParam_TOOL_SET *crossover; + wdrc_struct_TOOL_SET *wdrc;//[0]low [1]mid [2]high [3]whole + // struct drc_ch *parm; //系数输入 +}; + +struct audio_drc { + CrossOverParam_TOOL_SET *crossover_inside;// + wdrc_struct_TOOL_SET *wdrc_inside; + // struct drc_ch sw_drc[2]; //软件drc 系数地址 + // struct drc_ch *drc_param; //在线调试暂存软件drc系数地址,由外部赋值 + CrossOverParam_TOOL_SET *crossover;// + wdrc_struct_TOOL_SET *wdrc; + + u32 sr; //采样率 + u32 channels : 8; //通道数(channels|(L_wdrc))或(channels|(R_wdrc)) + u32 remain_flag : 1; //输出数据支持remain + u32 updata : 1; //系数更标志 + u32 online_en : 1; //是否支持在线更新系数 + u32 remain_en : 1; //是否支持remain输出 + u32 start : 1; //无效 + u32 run32bit : 8; //是否使能32bit位宽数据处理1:使能 0:不使能 + u32 need_restart : 1; //是否需要重更新系数 1:是 0:否 + u32 stero_div : 1; //是否左右声道拆分的drc效果,1:是 0:否 + u8 other_band; + audio_drc_filter_cb cb; //系数更新回调 + void *hdl; //软件drc句柄 + void *output_priv; //输出回调私有指针 + int (*output)(void *priv, void *data, u32 len);//输出回调函数 + u32 drc_name; //drc标识 + struct list_head hentry; // + u8 *file_path; //离线效果文件路径 + + + struct audio_stream_entry entry; // 音频流入口 +}; + + + +/*----------------------------------------------------------------------------*/ +/**@brief drc打开 + @param drc:句柄 + @param param:drc打开传入参数 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_drc_open(struct audio_drc *drc, struct audio_drc_param *param); +/*----------------------------------------------------------------------------*/ +/**@brief drc设置输出数据回调 + @param drc:句柄 + @param *output:输出回调 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_drc_set_output_handle(struct audio_drc *drc, int (*output)(void *priv, void *data, u32 len), void *output_priv); +/*----------------------------------------------------------------------------*/ +/**@brief drc设置采样率 + @param drc:句柄 + @param sr:采样率 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_drc_set_samplerate(struct audio_drc *drc, int sr); +/*----------------------------------------------------------------------------*/ +/**@brief drc设置是否处理32bit输入数据 + @param drc:句柄 + @param run_32bit:1:32bit 0:16bit + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_drc_set_32bit_mode(struct audio_drc *drc, u8 run_32bit); +/*----------------------------------------------------------------------------*/ +/**@brief drc启动 + @param drc:句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_drc_start(struct audio_drc *drc); +/*----------------------------------------------------------------------------*/ +/**@brief drc数据处理 + @param drc:句柄 + @param *data:输入数据地址 + @param len:输入数据长度 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_drc_run(struct audio_drc *drc, s16 *data, u32 len); +/*----------------------------------------------------------------------------*/ +/**@brief drc关闭 + @param drc:句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_drc_close(struct audio_drc *drc); + + +/*----------------------------------------------------------------------------*/ +/**@brief audio_drc_open重新封装,简化使用,该接口不接入audio_stream流处理 + @param *parm: drc参数句柄,参数详见结构体struct audio_drc_param + @return eq句柄 + @note +*/ +/*----------------------------------------------------------------------------*/ +struct audio_drc *audio_dec_drc_open(struct audio_drc_param *parm); +/*----------------------------------------------------------------------------*/ +/**@brief audio_drc_close重新封装,简化使用,该接口不接入audio_stream流处理 + @param drc句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_dec_drc_close(struct audio_drc *drc); + + +int audio_dec_drc_run(struct audio_drc *drc, s16 *data, u32 len); +void cur_crossover_set_update(u32 drc_name, CrossOverParam_TOOL_SET *crossover_parm); +void cur_drc_set_update(u32 drc_name, u8 type, void *wdrc_parm); +void cur_drc_set_bypass(u32 drc_name, u8 tar, u8 bypass); +void audio_drc_init(void); +int drc_get_filter_info(void *_drc, struct audio_drc_filter_info *info); +struct audio_drc *get_cur_drc_hdl_by_name(u32 drc_name); +#endif + +#endif /*CONFIG_EFFECT_CORE_V2_ENABLE*/ diff --git a/include_lib/media/audio_eq.h b/include_lib/media/audio_eq.h new file mode 100644 index 0000000..9596c3e --- /dev/null +++ b/include_lib/media/audio_eq.h @@ -0,0 +1,315 @@ +#ifndef CONFIG_EFFECT_CORE_V2_ENABLE +#include "application/audio_eq.h" +#else + +#ifndef _EQ_API_H_ +#define _EQ_API_H_ + +#include "typedef.h" +#include "asm/hw_eq.h" +#include "media/audio_stream.h" +#include "system/timer.h" +#include "system/init.h" + +#define EQ_CHANNEL_MAX 2 + +#define EQ_SR_IDX_MAX 9 + +#define AUDIO_EQ_HIGH 2 +#define AUDIO_EQ_BASS 3 + +/*eq type*/ +typedef enum { + EQ_MODE_NORMAL = 0, + EQ_MODE_ROCK, + EQ_MODE_POP, + EQ_MODE_CLASSIC, + EQ_MODE_JAZZ, + EQ_MODE_COUNTRY, + EQ_MODE_CUSTOM,//自定义 + EQ_MODE_MAX, +} EQ_MODE; + +/*eq type*/ +typedef enum { + EQ_TYPE_FILE = 0x01, + EQ_TYPE_ONLINE, + EQ_TYPE_MODE_TAB, +} EQ_TYPE; + +#define audio_eq_filter_info eq_coeff_info + +typedef int (*audio_eq_filter_cb)(void *eq, int sr, struct audio_eq_filter_info *info); + +struct eq_parm { + u8 in_mode; + u8 out_mode; + u8 run_mode; + u8 data_in_mode; + u8 data_out_mode; +}; +struct audio_eq_param { + u8 no_wait : 1; //是否使能异步eq, 1:使能 0:不使能 + u8 max_nsection : 6;//最大的eq段数,根据使用填写,要小于等于EQ_SECTION_MAX + u8 nsection : 6; //实际需要的eq段数,需小于等于max_nsection + u8 out_32bit : 1; //是否支持32bit eq输出,仅在 no_wait 写1时,out_32bit 才能写1 + u8 channels : 2; //通道数 + u8 fade: 1; //系数更新是否需要淡入 + float fade_step; //淡入步进(0.1f~1.0f) + audio_eq_filter_cb cb;//获取eq系数的回调函数 + u32 eq_name; //eq名字 + u32 sr; //采样率,更根据当前数据实际采样率填写 + + float global_gain; + struct eq_seg_info *seg;// + float global_gain_r; + struct eq_seg_info *seg_r;// + void *parm; //struct eq_parm + + + void *priv; //私有指针 + int (*output)(void *priv, void *data, u32 len);//异步eq输出回调,节点方式使用时,output 配NULL + void (*irq_callback)(void *priv);//总段回调函数,数据流激活 +}; +struct audio_eq_fade { + u8 nsection; + u16 timer; + float cur_global_gain; + float use_global_gain; + float cur_global_gain_r; + float use_global_gain_r; + struct eq_seg_info *cur_seg; + struct eq_seg_info *use_seg; +} ; + +struct high_bass { + int freq; //频率写0, 内部会用默认125hz 和12khz + int gain; //增益范围 -12~12 +}; + + +#ifdef CONFIG_EQ_SUPPORT_ASYNC +struct audio_eq_async { + u16 ptr; + u16 len; + u16 buf_len; + u8 clear; + u8 out_stu; + char *buf; +}; +#endif + +struct audio_eq { + void *eq_ch; //硬件eq句柄 + u8 updata; //系数是否需要更新 + u8 start; //eq start标识 + u8 max_nsection; //eq最大段数 + u8 cur_nsection; //当前eq段数 + u8 check_hw_running; //检测到硬件正在运行时不等待其完成1:设置检查 0:不检查 + u8 async_en; + u8 out_32bit; + u8 ch_num; + u32 sr; //采样率 + u32 eq_name; //eq标识 + u32 mask[2]; + float global_gain; + float global_gain_r; + s16 *eq_out_buf;//同步方式,32bit输出,当out为NULL时,内部申请eq_out_buf + int out_buf_size; + int eq_out_points; + int eq_out_total; + struct audio_stream_entry entry; // 音频流入口 + +#ifdef CONFIG_EQ_SUPPORT_ASYNC + void *run_buf; + void *run_out_buf; + int run_len; + struct audio_eq_async async; //异步eq 输出管理 +#endif + u32 mute_cnt_l; //左声道eq mem清除计数 + u32 mute_cnt_r; //右声道eq mem清除计数 + u32 mute_cnt_max; //记录最大点数,超过该点数,清eq mem + + audio_eq_filter_cb cb; //系数回调 + void *output_priv; //私有指针 + int (*output)(void *priv, void *data, u32 len); //输出回调 + + struct eq_seg_info *eq_seg_tab; //运算前系数表,特殊应用时,可使用 + struct eq_seg_info *seg; //运算前系数表,由audio_eq_param初始化时指定 + struct eq_seg_info *seg_r; //运算前系数表,由audio_eq_param初始化时指定 + int *eq_coeff_tab; //运算后系数表 + struct list_head hentry; // + const char *event_owner; //记录data_handler所处的任务 + struct audio_eq_fade *fade; + float fade_step; +}; + +/*----------------------------------------------------------------------------*/ +/**@brief eq模块初始化 + @param + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_eq_init(void); +void audio_eq_init_new(int eq_section_num); +/*----------------------------------------------------------------------------*/ +/**@brief eq 打开 + @param *param: eq参数句柄,参数详见结构体struct audio_eq_param + @return eq句柄 + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_eq_open(struct audio_eq *eq, struct audio_eq_param *param); +/*----------------------------------------------------------------------------*/ +/**@brief 异步eq设置输出回调 + @param eq:句柄 + @param *output:回调函数 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_eq_set_output_handle(struct audio_eq *eq, int (*output)(void *priv, void *data, u32 len), void *output_priv); +/*----------------------------------------------------------------------------*/ +/**@brief 同步eq设置输出buf + @param eq:句柄 + @param *output:回调函数 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_eq_set_output_buf(struct audio_eq *eq, s16 *buf, u32 len); +/*----------------------------------------------------------------------------*/ +/**@brief eq设置采样率 + @param eq:句柄 + @param sr:采样率 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_eq_set_samplerate(struct audio_eq *eq, int sr); +/*----------------------------------------------------------------------------*/ +/**@brief eq设置输入输出通道数 + @param eq:句柄 + @param channel:通道数 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_eq_set_channel(struct audio_eq *eq, u8 channel); + +/*----------------------------------------------------------------------------*/ +/**@brief 设置检查eq是否正在运行 + @param eq:句柄 + @param check_hw_running: 1:设置检查 0:不检查 + @return + @note 检测到硬件正在运行时不等待其完成,直接返回, 仅异步EQ有效 +*/ +/*----------------------------------------------------------------------------*/ +int audio_eq_set_check_running(struct audio_eq *eq, u8 check_hw_running); +/*----------------------------------------------------------------------------*/ +/**@brief 设置eq信息 + @param eq:句柄 + @param channels:设置输入输出通道数 + @param out_32bit:使能eq输出32bit数据,1:输出32bit数据, 0:输出16bit是数据 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_eq_set_info(struct audio_eq *eq, u8 channels, u8 out_32bit); + +/*----------------------------------------------------------------------------*/ +/**@brief 设置eq信息 + @param eq:句柄 + @param channels:设置入输出通道数 + @param in_mode:使能eq输入32bit数据,2:float, 1:输入32bit数据, 0:输入16bit是数据 + @param out_mode:使能eq输出32bit数据,2:float, 1:输出32bit数据, 0:输出16bit是数据 + @param run_mode:运行模式,0:normal, 1:mono, 2:stero + @param data_in_mode:输入数据存放方式 0:块模式 1:序列模式 + @param data_out_mode:输入数据存放方式 0:块模式 1:序列模式 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_eq_set_info_new(struct audio_eq *eq, u8 channels, u8 in_mode, u8 out_mode, u8 run_mode, u8 data_in_mode, u8 data_out_mode); + +/*----------------------------------------------------------------------------*/ +/**@brief eq启动 + @param eq:句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_eq_start(struct audio_eq *eq); +/*----------------------------------------------------------------------------*/ +/**@brief eq的数据处理 + @param eq:句柄 + @param *data:输入数据地址 + @param len:输入数据长度 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_eq_run(struct audio_eq *eq, s16 *data, u32 len); +/*----------------------------------------------------------------------------*/ +/**@brief eq关闭 + @param eq:句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_eq_close(struct audio_eq *eq); + + +#ifdef CONFIG_EQ_SUPPORT_ASYNC +/*----------------------------------------------------------------------------*/ +/**@brief 清除异步eq剩余的数据 + @param eq:句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_eq_async_data_clear(struct audio_eq *eq); +#endif +/*----------------------------------------------------------------------------*/ +/**@brief 获取异步eq剩余的数据 + @param eq:句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_eq_data_len(struct audio_eq *eq); + + +/*----------------------------------------------------------------------------*/ +/**@brief audio_eq_open重新封装,简化使用,该接口不接入audio_stream流处理 + @param *parm: eq参数句柄,参数详见结构体struct audio_eq_param + @return eq句柄 + @note +*/ +/*----------------------------------------------------------------------------*/ +struct audio_eq *audio_dec_eq_open(struct audio_eq_param *parm); +/*----------------------------------------------------------------------------*/ +/**@brief audio_eq_close重新封装,简化使用,该接口不接入audio_stream流处理 + @param eq句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_dec_eq_close(struct audio_eq *eq); + + +int audio_dec_eq_run(struct audio_eq *eq, s16 *data, s16 *out, u16 len); + + +void cur_eq_set_global_gain(u32 eq_name, float g_Gain); +void cur_eq_set_update(u32 eq_name, struct eq_seg_info *seg, u32 nsection, u32 design); + +void cur_eq_right_ch_set_global_gain(u32 eq_name, float g_Gain); +void cur_eq_right_ch_set_update(u32 eq_name, struct eq_seg_info *seg, u32 nsection, u32 design); + +int eq_get_filter_info(void *_eq, int sr, struct audio_eq_filter_info *info); +struct audio_eq *get_cur_eq_hdl_by_name(u32 eq_name); +#endif + +#endif /*CONFIG_EFFECT_CORE_V2_ENABLE*/ diff --git a/include_lib/media/audio_gain_process.h b/include_lib/media/audio_gain_process.h new file mode 100644 index 0000000..d57e1e1 --- /dev/null +++ b/include_lib/media/audio_gain_process.h @@ -0,0 +1,63 @@ +#ifndef __AUDIO_GAIN_PORCESS__H +#define __AUDIO_GAIN_PORCESS__H + +#include "media/audio_stream.h" + +#ifndef RUN_NORMAL +#define RUN_NORMAL 0 +#endif + +#ifndef RUN_BYPASS +#define RUN_BYPASS 1 +#endif + +struct aud_gain_parm { + float gain;//增加多少dB + u8 channel;//通道数 + u8 indata_inc;//channel ==1 ?1:2; + u8 outdata_inc;//channel ==1 ?1:2; + u8 bit_wide;//0:16bit 1:32bit + u16 gain_name; +}; +struct aud_gain_parm_update { + float gain;//增加多少dB powf(10, 界面值gain / 20.0f) +}; +struct aud_gain_process { + struct audio_stream_entry entry; // 音频流入口 + struct list_head hentry; // + struct aud_gain_parm parm; + u8 status; //内部运行状态机 + u8 update; //设置参数更新标志 +}; + + +struct aud_gain_process *audio_gain_process_open(struct aud_gain_parm *parm); +void audio_gain_process_run(struct aud_gain_process *hdl, s16 *data, int len); +void audio_gain_process_close(struct aud_gain_process *hdl); +void audio_gain_process_update(u16 gain_name, struct aud_gain_parm_update *parm); +void audio_gain_process_bypass(u16 gain_name, u8 bypass); +struct aud_gain_process *get_cur_gain_hdl_by_name(u32 gain_name); + +/* + * *in:输入数据地址 + * *out:输出数据地址 + * gain:dB值(powf(10, 界面值gain / 20.0f)) + * channel:输入数据通道数 + * Indatainc:同个声道相邻两点的差值 channel ==1 ?1:2 + * OutdataInc:同个声道相邻两点的差值 channel ==1 ?1:2 + * per_channel_npoint:一个声道的点数 + * */ +extern void GainProcess_16Bit(short *in, short *out, float gain, int channel, int IndataInc, int OutdataInc, int per_channel_npoint); //16位宽 +/* + * *in:输入数据地址 + * *out:输出数据地址 + * gain:dB值powf(10, 界面值gain / 20.0f) + * channel:输入数据通道数 + * Indatainc:同个声道相邻两点的差值 channel ==1 ?1:2 + * OutdataInc:同个声道相邻两点的差值 channel ==1 ?1:2 + * per_channel_npoint:一个声道的点数 + * */ +extern void GainProcess_32Bit(int *in, int *out, float gain, int channel, int IndataInc, int OutdataInc, int per_channel_npoint); //32位宽 + + +#endif diff --git a/include_lib/media/audio_howling.h b/include_lib/media/audio_howling.h new file mode 100644 index 0000000..8117809 --- /dev/null +++ b/include_lib/media/audio_howling.h @@ -0,0 +1,62 @@ +#ifndef CONFIG_EFFECT_CORE_V2_ENABLE +#include "application/audio_howling.h" +#else + +#ifndef _AUDIO_HOWLING_API_H +#define _AUDIO_HOWLING_API_H + +#include "media/howling_api.h" + + +#define TRAP_MODE 0 +#define SHIFT_PITCH_MODE 1 +#define PEMAFROW_MODE 2 +#define SHIFT_PHASE_MODE 3 + +#define HOWLING_MODE SHIFT_PITCH_MODE + +#if (HOWLING_MODE == TRAP_MODE) +#define REVERB_RUN_POINT_NUM 160 //固定160个点 +#elif (HOWLING_MODE == SHIFT_PHASE_MODE) // +#define REVERB_RUN_POINT_NUM 256 //固定256个点 +#elif (HOWLING_MODE == PEMAFROW_MODE) +#define REVERB_RUN_POINT_NUM 128 //固定128 +#else +#define REVERB_RUN_POINT_NUM 0 //无限制 +#endif + + +/*----------------------------------------------------------------------------*/ +/**@brief 啸叫抑制模块打开 + @param howl_para:陷波模式时为啸叫抑制参数 ,pemafrow模式为DAC输出数据buf,; + sample_rate:输入数据采样率; + channels: 输入数据通道数; + mode: 0 陷波模式;1 移频模式 2 pemafrow模式 + @return 啸叫抑制句柄, + @note 陷波模式 要外部保证每次运算数据为160点,pemafrow 为128个点 + 对应模式需外部使能,默认只开 移频模式 + const int config_howling_enable_pemafrow_mode = 1; + const int config_howling_enable_trap_mode = 1; + const int config_howling_enable_pitchps_mode = 1; +*/ +/*----------------------------------------------------------------------------*/ +HOWLING_API_STRUCT *open_howling(void *howl_para, u16 sample_rate, u8 channel, u8 mode); +/* + * 啸叫抑制模块数据处理 + */ +void run_howling(HOWLING_API_STRUCT *howling_hdl, short *in, short *out, int len); +/* + * 啸叫抑制模块关闭 + */ +void close_howling(HOWLING_API_STRUCT *holing_hdl); +/* + * 啸叫抑制模块暂停处理 + */ +void pause_howling(HOWLING_API_STRUCT *holing_hdl, u8 run_mark); + +void howling_update_bypass(HOWLING_API_STRUCT *hdl, u8 bypass); + +void update_howling_parm(HOWLING_API_STRUCT *howling_hdl, void *parm); +#endif + +#endif /*CONFIG_EFFECT_CORE_V2_ENABLE*/ diff --git a/include_lib/media/audio_llns.h b/include_lib/media/audio_llns.h new file mode 100644 index 0000000..9b5a0be --- /dev/null +++ b/include_lib/media/audio_llns.h @@ -0,0 +1,12 @@ +#ifndef _AUDIO_LLNS_H_ +#define _AUDIO_LLNS_H_ + +#include "generic/typedef.h" + +int audio_llns_heap_query(int *share_size, int *private_size, int sr); +void *audio_llns_init(char *private_buffer, int private_size, char *share_buffer, int share_size, int sr, float gainfloor, float suppress_level); +int audio_llns_run(void *hdl, short *inbuf, u16 inbuf_size, short *outbuf); +int audio_llns_close(void *hdl); + + +#endif/*_AUDIO_LLNS_H_*/ diff --git a/include_lib/media/audio_stream.h b/include_lib/media/audio_stream.h new file mode 100644 index 0000000..6724e9d --- /dev/null +++ b/include_lib/media/audio_stream.h @@ -0,0 +1,321 @@ +#ifndef AUDIO_STREAM_H +#define AUDIO_STREAM_H + +#include "generic/includes.h" +#include "media/audio_base.h" + + +// 数据流IOCTRL命令 +#define AUDIO_STREAM_IOCTRL_CMD_CHECK_ACTIVE (1) // 检查数据流是否活动 + + +struct audio_stream_entry; +struct audio_frame_copy; + + +/* + * 数据流中的传输内容 + */ +struct audio_data_frame { + u8 channel; // 通道数 + u16 stop : 1; // 数据流停止标志 + u16 data_sync : 1; // 数据流同步标志 + u16 no_subsequent : 1; // 1-不再执行后续的数据流;0-正常执行 + u32 sample_rate; // 采样率 + u16 offset; // 数据偏移 + u16 data_len; // 数据长度 + s16 *data; // 数据地址 +}; + + +/* + * 数据流 + * 多个数据流节点组成一个数据流 + */ +struct audio_stream { + struct audio_stream_entry *entry; // 数据流节点 + void *priv; // resume私有参数 + void (*resume)(void *priv); // 激活回调接口 +}; + + +/* + * 数据流群组 + * 用于串联多个数据流,在调用resume/clear等操作时依次处理各个数据流 + * 如数据流stream0最后一个节点是entry0_n,数据流1最后一个节点是entry1_n + * 把这两个数据流加入到群组test_group中 + * audio_stream_group_add_entry(&test_group, &entry0_n); + * audio_stream_group_add_entry(&test_group, &entry1_n); + * 另一个数据流streamX的第一个节点是entryX_0,把群组关联到streamX数据流 + * entryX_0.group = &test_group; + * 那么调用streamX中的resume就会依次调用stream0和stream1的resume了 + */ +struct audio_stream_group { + struct audio_stream_entry *entry; // 数据流节点 +}; + +/* + * 数据流节点 + * 数据流节点依次串联,数据依次往后传递 + */ +struct audio_stream_entry { + u8 pass_by; // 1-同步处理(即往后传的buf就是上层传入的buf); + // 0-异步处理(数据存到其他buf再往后传) + u8 remain; // 1-上次数据没输出完。0-上次数据输出完 + u16 offset; // 同步处理时的数据偏移 + struct audio_stream *stream; // 所属的数据流 + struct audio_stream_entry *input; // 上一个节点 + struct audio_stream_entry *output; // 下一个节点 + struct audio_stream_entry *sibling; // 数据流群组中的数据流节点链表 + struct audio_stream_group *group; // 数据流群组节点 + struct audio_frame_copy *frame_copy; // 数据分支节点 + int (*prob_handler)(struct audio_stream_entry *, struct audio_data_frame *in); // 预处理 + int (*data_handler)(struct audio_stream_entry *, struct audio_data_frame *in, + struct audio_data_frame *out); // 数据处理 + void (*data_process_len)(struct audio_stream_entry *, int len); // 后级返回使用的数据长度 + void (*data_clear)(struct audio_stream_entry *); // 清除节点数据 + int (*ioctrl)(struct audio_stream_entry *, int cmd, int *param); // 节点IOCTRL +}; + +/* + * 数据流分支 + * 支持一传多(分支)功能,内部自动生成struct audio_frame_copy来处理多个分支 + * 有多少个分支就会申请多少个空间,数据分别拷贝到对应分支空间然后往后传递 + */ +struct audio_frame_copy { + struct list_head head; // 链表。用于连接各个分支 + struct audio_data_frame frame; // 保存上层的传输内容 + struct audio_stream_entry entry; // 连接上层的节点 +}; + + + +/* +********************************************************************* +* Audio Stream Open +* Description: 创建一个数据流 +* Arguments : *priv resume回调的私有参数 +* resume 模块唤醒数据流时的回调函数 +* Return : 数据流句柄 +* Note(s) : None. +********************************************************************* +*/ +struct audio_stream *audio_stream_open(void *priv, void (*resume)(void *priv)); + +/* +********************************************************************* +* Audio Stream Add First +* Description: 添加第一个数据流节点 +* Arguments : *stream 数据流句柄 +* *entry 数据流节点句柄 +* Return : None. +* Note(s) : 第一个节点一般为解码输出 +********************************************************************* +*/ +void audio_stream_add_first(struct audio_stream *stream, + struct audio_stream_entry *entry); + +/* +********************************************************************* +* Audio Stream Add Head +* Description: 将节点插入到数据流的first节点后面 +* Arguments : *stream 数据流句柄 +* *entry 数据流节点句柄 +* Return : None. +* Note(s) : None. +********************************************************************* +*/ +void audio_stream_add_head(struct audio_stream *stream, + struct audio_stream_entry *entry); + +/* +********************************************************************* +* Audio Stream Add Tail +* Description: 将节点放到数据流的最后 +* Arguments : *stream 数据流句柄 +* *entry 数据流节点句柄 +* Return : None. +* Note(s) : None. +********************************************************************* +*/ +void audio_stream_add_tail(struct audio_stream *stream, + struct audio_stream_entry *entry); + +/* +********************************************************************* +* Audio Stream Add Entry +* Description: 将output节点添加到input节点之后 +* Arguments : *input 数据流节点句柄 +* *output 需要添加的数据流节点句柄 +* Return : None. +* Note(s) : 如果input节点后面已经连接有节点,将创建数据流分支处理 +********************************************************************* +*/ +void audio_stream_add_entry(struct audio_stream_entry *input, + struct audio_stream_entry *output); + +/* +********************************************************************* +* Audio Stream Add List +* Description: 将entry数组中节点按顺序添加到数据流中 +* Arguments : *stream 数据流句柄 +* *entry[] 数据流节点数组 +* num 节点总个数 +* Return : None. +* Note(s) : None. +********************************************************************* +*/ +void audio_stream_add_list(struct audio_stream *stream, + struct audio_stream_entry *entry[], int num); + +/* +********************************************************************* +* Audio Stream Delete Entry +* Description: 将节点从数据流中删除 +* Arguments : *entry 数据流节点句柄 +* Return : None. +* Note(s) : None. +********************************************************************* +*/ +void audio_stream_del_entry(struct audio_stream_entry *entry); + + +/* +********************************************************************* +* Audio Stream Delete List Entry +* Description: 依次将数组中的节点删除 +* Arguments : *entry[] 数据流节点数组 +* num 节点总个数 +* Return : None. +* Note(s) : None. +********************************************************************* +*/ +void audio_stream_del_list(struct audio_stream_entry *entry[], int num); + + +/* +********************************************************************* +* Audio Stream Group Add Entry +* Description: 将节点加入到群组之中 +* Arguments : *group 数据流群组句柄 +* *entry 数据流节点句柄 +* Return : None. +* Note(s) : None. +********************************************************************* +*/ +void audio_stream_group_add_entry(struct audio_stream_group *group, + struct audio_stream_entry *entry); + +/* +********************************************************************* +* Audio Stream Group Delete Entry +* Description: 将节点从群组之中删除 +* Arguments : *group 数据流群组句柄 +* *entry 数据流节点句柄 +* Return : None. +* Note(s) : None. +********************************************************************* +*/ +void audio_stream_group_del_entry(struct audio_stream_group *group, + struct audio_stream_entry *entry); + +/* +********************************************************************* +* Audio Stream Group Get Entry Number +* Description: 获取群组中的节点个数 +* Arguments : *group 数据流群组句柄 +* Return : 节点个数 +* Note(s) : None. +********************************************************************* +*/ +int audio_stream_group_entry_num(struct audio_stream_group *group); + +/* +********************************************************************* +* Audio Stream Run +* Description: 数据处理接口 +* Arguments : *entry 数据流节点句柄 +* *input 输入数据 +* Return : 负数-出错 +* Note(s) : 数据流依次递归往后传输。直到最后一个节点,或者no_subsequent==1, +* 或者prob_handler/data_handler处理错误返回负数 +********************************************************************* +*/ +int audio_stream_run(struct audio_stream_entry *from, struct audio_data_frame *input); + + +/* +********************************************************************* +* Audio Stream Resume +* Description: 唤醒数据流 +* Arguments : *entry 数据流节点句柄 +* Return : 0-成功 +* Note(s) : 最终会递归调用到struct audio_stream结构体中的.resume回调接口 +********************************************************************* +*/ +int audio_stream_resume(struct audio_stream_entry *entry); + + +/* +********************************************************************* +* Audio Stream Clear From Entry +* Description: 清除指定节点及后续所有节点的数据 +* Arguments : *entry 数据流节点句柄 +* Return : None. +* Note(s) : 会清除offset/pass_by等记录,并且调用data_clear回调接口清除用户数据 +********************************************************************* +*/ +void audio_stream_clear_from(struct audio_stream_entry *entry); + +/* +********************************************************************* +* Audio Stream Clear +* Description: 清除数据流所有节点数据 +* Arguments : *stream 数据流句柄 +* Return : None. +* Note(s) : 会清除offset/pass_by等记录,并且调用data_clear回调接口清除用户数据 +********************************************************************* +*/ +void audio_stream_clear(struct audio_stream *stream); + +/* +********************************************************************* +* Audio Stream Clear By Entry +* Description: 通过数据流某个节点清除数据流所有节点数据 +* Arguments : *entry 数据流节点句柄 +* Return : None. +* Note(s) : 先找到数据流起始位置,再调用audio_stream_clear()清除所有节点 +********************************************************************* +*/ +void audio_stream_clear_by_entry(struct audio_stream_entry *entry); + + +/* +********************************************************************* +* Audio Stream Check Active From Entry +* Description: 检测指定节点及后续节点是否有活动情况 +* Arguments : *entry 数据流节点句柄 +* Return : true 活动 +* Note(s) : 只要中间有某个节点活动就会返回数据流活动 +********************************************************************* +*/ +int audio_stream_check_active_from(struct audio_stream_entry *entry); + + +/* +********************************************************************* +* Audio Stream Close +* Description: 关闭数据流 +* Arguments : *stream 数据流句柄 +* Return : None. +* Note(s) : 需关闭所有数据流节点之后才能调用该函数 +********************************************************************* +*/ +void audio_stream_close(struct audio_stream *stream); + +#endif + + + + + diff --git a/include_lib/media/audio_surround.h b/include_lib/media/audio_surround.h new file mode 100644 index 0000000..ee2f149 --- /dev/null +++ b/include_lib/media/audio_surround.h @@ -0,0 +1,186 @@ +#ifndef CONFIG_EFFECT_CORE_V2_ENABLE +#include "application/audio_surround.h" +#else + +#ifndef _AUDIO_SURROUND_API_H_ +#define _AUDIO_SURROUND_API_H_ + +#include "system/includes.h" +#include "media/includes.h" +#include "media/effect_sur_api.h" + +typedef struct _surround_update_parm { + int surround_type; //音效类型 + int rotatestep; //旋转速度 + int damping; //高频衰减速度 + int feedback; //整体衰减速度 + int roomsize; //空间大小 +} surround_update_parm; + +typedef struct _surround_open_parm { + u32 sur_name; + u8 channel; //通道数立体声配2, 左声道配EFFECT_CH_L, 右声道配EFFECT_CH_R + u8 surround_effect_type; //默认的环绕音效类型 +} surround_open_parm; + + +typedef struct _surround_hdl { + SUR_FUNC_API *ops; //环绕音效底层io + void *work_buf; //底层模块运行的句柄及buf + + surround_open_parm parm; //打开模块传入的参数 + u8 status; //内部运行状态机 + u8 update; //设置参数更新标志 + u8 eff_type; + + struct audio_stream_entry entry; // 音频流入口 + struct list_head hentry; // + +} surround_hdl; + +/*cmd*/ +enum { + EFFECT_3D_PANORAMA = 0, //3d全景 + EFFECT_3D_ROTATES, //3d环绕 + EFFECT_FLOATING_VOICE, //流动人声 + EFFECT_GLORY_OF_KINGS, //王者荣耀 + EFFECT_FOUR_SENSION_BATTLEFIELD, //四季战场 + + EFFECT_SUR2, //一种新的环绕声(仿某耳机的环绕音效)需将const_surround_en|BIT(2) + /*如使用以下效果,需将const_surround_en|BIT(1), mips占用 55M ram33k*/ + EFFECT_3D_PANORAMA2, //3d全景另一种效果 + EFFECT_KTV, //ktv模式 + EFFECT_3DTHE, //3D影院 + EFFECT_HALL, //音乐厅 + EFFECT_VOICE, //清澈人声 + EFFECT_SUR, //全景环绕 + + EFFECT_OFF2, //音效开关(数据会经过模块,但不做处理,保证数据延续,避免由音效开关引起的哒哒音,) + EFFECT_OFF, //音效开关(数据直接不经过模块) +}; + + +//{EFFECT_3D_TYPE1, 2, 120, 110, 128},//3D全景 +//{EFFECT_3D_ROTATE, 2, 60, 70, 128},//3D旋转, step旋转速度 建议1~8 +//{EFFECT_3D_LRDRIFT, 140, 120, 95, 128}, //流动人声,step流动速度 建议40~400 +//{EFFECT_3D_TYPE0, 2, 120, 95, 128},//王者荣耀 +//{EFFECT_3D_TYPE1, 2, 60, 100, 30},//四季战场,同全景,但把整体调小了 +//以上是内置默认效果 + + +#if 0 +//如启用多效果调节,需将const_surround_en|BIT(1),调用update接口传参使用。 +//{EFFECT_3D_TYPE2, 2, 90, 100, 100},//3d全景的另一效果,该效果,mips占用 55M ram33k. +//第一个参数2是无效参数. +//第2个参数90调节反馈强度范围是1到150,大点的话空间感比较强。 +//第3个参数是 湿声增益,可调范围是0到128。 +//第4个参数调节空间大小,范围是0-100,是反馈参数,有效范围0到100。 + +//例如: +surround_update_parm parm = {0}; +parm.surround_type = EFFECT_3D_TYPE2; +parm.rotatestep = 2; +parm.damping = 90; +parm.feedback = 100; +parm.roomsize = 100; +audio_surround_parm_update(hdl, EFFECT_3D_PANORAMA2, &parm); +#endif + +#if 0 +//如需要自定义 ktv模式、3d影院、音乐厅、清澈人声、全景环绕 +//参数顺序 +//dry,wet,delay,rot60,Erwet,Erfactor,Ewidth,Ertolate,predelay,width,diffusion,dampinglpf,basslpf,bassB +const static int surmode_present[][14] = { + {55, 70, 35, 8000, 80, 80, 80, 80, 20, 100, 70, 6500, 4000, 18}, //EFFECT_KTV + {60, 60, 90, 9030, 90, 90, 90, 90, 18, 100, 75, 7000, 1000, 29}, //EFFECT_3DTHE + {50, 70, 100, 12000, 100, 100, 100, 100, 20, 100, 72, 9000, 50, 3}, //EFFECT_HALL + {40, 70, 20, 2010, 100, 70, 70, 100, 15, 100, 70, 5500, 3500, 60}, //EFFECT_VOICE + {60, 70, 100, 9000, 80, 80, 80, 90, 10, 100, 72, 8000, 500, 15}, //EFFECT_SUR +}; + +parm.surround_type = EFFECT_3D_TYPE2; +parm.rotatestep = 2; +parm.damping = -1; +parm.feedback = 100; +parm.roomsize = (int)surmode_present[0]; +audio_surround_parm_update(hdl, EFFECT_KTV, &parm); + +//如使用默认的 ktv模式、3d影院、音乐厅、清澈人声、全景环绕 +audio_surround_parm_update(hdl, EFFECT_KTV, NULL); +audio_surround_parm_update(hdl, EFFECT_3DTHE, NULL); +audio_surround_parm_update(hdl, EFFECT_HALL, NULL); +audio_surround_parm_update(hdl, EFFECT_VOICE, NULL); +audio_surround_parm_update(hdl, EFFECT_SUR, NULL); +#endif + + +/*----------------------------------------------------------------------------*/ +/**@brief audio_surround_open 环绕音效打开 + @param *parm: 环绕音效始化参数,详见结构体surround_open_parm + @return 句柄 + @note +*/ +/*----------------------------------------------------------------------------*/ +surround_hdl *audio_surround_open(surround_open_parm *parm); + +/*----------------------------------------------------------------------------*/ +/**@brief audio_surround_parm_update 环绕音效参数更新 + @param cmd:EFFECT_3D_PANORAMA,EFFECT_3D_ROTATES,EFFECT_FLOATING_VOICE,EFFECT_GLORY_OF_KINGS,EFFECT_FOUR_SENSION_BATTLEFIELD + @param *parm:参数指针,NULL则使用默认德参数,否则传入自定义参数 + @return 0:成功 -1: 失败 + @note 对耳时,左右声道效果,须设置保持一致 +*/ +/*----------------------------------------------------------------------------*/ +int audio_surround_parm_update(u32 sur_name, u32 cmd, surround_update_parm *parm); + +/* surround_update_parm parm = {0}; */ +// parm.surround_type = EFFECT_3D_TYPE1; +// parm.rotatestep = 2;//旋转速度 +// parm.damping = 120;//高频衰减速度 +// parm.feedback = 110;//整体衰减速度 +// parm.roomsize = 128;//空间大小 +/* audio_surround_parm_update(hdl, EFFECT_3D_PANORAMA, &parm); */ +/*----------------------------------------------------------------------------*/ +/**@brief audio_surround_close 环绕音效关闭处理 + @param _hdl:句柄 + @return 0:成功 -1:失败 + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_surround_close(surround_hdl *_hdl); + +/*----------------------------------------------------------------------------*/ +/**@brief audio_surround_run 环绕音效处理 + @param _hdl:句柄 + @param data:需要处理的数据 + @param len:数据长度 + @return 0:成功 -1:失败 + @note 无数据流节点时,直接使用改接口进行环绕音效的处理 +*/ +/*----------------------------------------------------------------------------*/ +int audio_surround_run(surround_hdl *_hdl, void *data, u32 len); + + +/*----------------------------------------------------------------------------*/ +/**@brief audio_surround_switch_nch 通道切换 + @param _hdl:句柄 + @param nch:通道数 2 4 或者EFFECT_CH_L EFFECT_CH_R + @return 0:成功 -1:失败 + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_surround_switch_nch(surround_hdl *_hdl, int nch); +void audio_surround_bypass(u32 sur_name, u8 bypass); + +#ifndef RUN_NORMAL +#define RUN_NORMAL 0 +#endif + +#ifndef RUN_BYPASS +#define RUN_BYPASS 1 +#endif + + + +#endif +#endif /*CONFIG_EFFECT_CORE_V2_ENABLE*/ diff --git a/include_lib/media/audio_vbass.h b/include_lib/media/audio_vbass.h new file mode 100644 index 0000000..cf69e13 --- /dev/null +++ b/include_lib/media/audio_vbass.h @@ -0,0 +1,46 @@ +#ifndef CONFIG_EFFECT_CORE_V2_ENABLE +#include "application/audio_vbass.h" +#else +#ifndef _AUDIO_VBASS_API_H_ +#define _AUDIO_VBASS_API_H_ +#include "system/includes.h" +#include "media/audio_stream.h" +#include "media/VirtualBass_api.h" + +typedef struct _VirtualBassUdateParam { + int ratio; + int boost; + int fc; +} VirtualBassUdateParam; + + +typedef struct _vbass_hdl { + struct audio_stream_entry entry; // 音频流入口 + struct list_head hentry; // + void *workbuf; //vbass 运行句柄及buf + VirtualBassParam parm; + u32 vbass_name; + u8 status; //内部运行状态机 + u8 update; //设置参数更新标志 +} vbass_hdl; + + +vbass_hdl *audio_vbass_open(u32 vbass_name, VirtualBassParam *parm); +int audio_vbass_close(vbass_hdl *hdl); + +int audio_vbass_parm_update(u32 vbass_name, VirtualBassUdateParam *parm); +void audio_vbass_bypass(u32 vbass_name, u8 bypass); +vbass_hdl *get_cur_vbass_hdl_by_name(u32 vbass_name); + +#ifndef RUN_NORMAL +#define RUN_NORMAL 0 +#endif + +#ifndef RUN_BYPASS +#define RUN_BYPASS 1 +#endif + + +#endif +#endif /*CONFIG_EFFECT_CORE_V2_ENABLE*/ + diff --git a/include_lib/media/bt_audio_timestamp.h b/include_lib/media/bt_audio_timestamp.h new file mode 100644 index 0000000..6315e91 --- /dev/null +++ b/include_lib/media/bt_audio_timestamp.h @@ -0,0 +1,56 @@ +/***************************************************************** +>file name : bt_audio_timestamp.h +>create time : Fri 21 May 2021 03:05:35 PM CST +*****************************************************************/ +#ifndef _BT_AUDIO_TIMESTAMP_H_ +#define _BT_AUDIO_TIMESTAMP_H_ +#include "typedef.h" + +#define TWS_A2DP_AUDIO 0 +#define TWS_ESCO_AUDIO 1 +#define TWS_FILE_AUDIO 2 +#define TWS_SHARE_AUDIO 3 +#define TWS_UNKOWN_AUDIO 8 + +/*===================================A2DP 音频时间戳接口==================================*/ +void *a2dp_audio_timestamp_create(int sample_rate, u32 timestamp, u8 factor); + +u32 a2dp_audio_update_timestamp(void *handle, u16 seqn, u32 dts); + +void a2dp_audio_delay_offset_update(void *handle, int distance); + +int a2dp_audio_sample_rate(void *handle); + +bool a2dp_audio_timestamp_is_available(void *handle, u16 seqn, u32 dts, int *drop); + +int tws_a2dp_share_timestamp(void *handle); + +void a2dp_audio_set_base_time(void *handle, u32 base_time); + +void a2dp_audio_timestamp_close(void *handle); + +int a2dp_tws_audio_conn_offline(void); + +void a2dp_tws_audio_conn_delete(void); + +/*========================================================================================*/ + +/*===================================ESCO 音频时间戳接口==================================*/ +void *esco_audio_timestamp_create(u8 frame_clkn, u32 delay_time, u8 factor); + +u32 esco_audio_timestamp_update(void *handle, u32 time); + +void esco_audio_timestamp_close(void *handle); +/*========================================================================================*/ + + +/*===================================FILE 音频时间戳接口==================================*/ +void *file_audio_timestamp_create(u32 magic, int sample_rate, u32 timestamp, u32 delay_time, u8 factor); + +bool tws_file_timestamp_available(void *handle); + +u32 file_audio_timestamp_update(void *handle, u32 dts); + +void file_audio_timestamp_close(void *handle); +/*========================================================================================*/ +#endif diff --git a/include_lib/media/cvp/aec_uart_debug.h b/include_lib/media/cvp/aec_uart_debug.h new file mode 100644 index 0000000..2830307 --- /dev/null +++ b/include_lib/media/cvp/aec_uart_debug.h @@ -0,0 +1,61 @@ +#ifndef _AEC_UART_DEBUG_H_ +#define _AEC_UART_DEBUG_H_ + +#include "generic/typedef.h" + +/* +********************************************************* +* aec_uart_open +* Description: 打开数据写卡接口 +* Arguments_v1 : nch 总通道数, single_size 单个通道的数据大小 +* Arguments_v2 : nch 允许发送的最大通道数, single_size 单次发送允许的最大包长 +* Return : 0 成功 其他 失败 +* Note(s) : None. +********************************************************* +*/ +int aec_uart_open(u8 nch, u16 single_size); + +/* +********************************************************* +* aec_uart_init +* Description: 数据写卡初始化 +* Arguments : None. +* Return : 0 成功 其他 失败 +* Note(s) : None. +********************************************************* +*/ +int aec_uart_init(void); + +/* +********************************************************* +* aec_uart_fill +* Description: 填写对应通道的数据 +* Arguments : ch 通道号,buf 数据地址,size 数据大小 +* Return : 0 成功 其他 失败 +* Note(s) : None. +********************************************************* +*/ +int aec_uart_fill(u8 ch, void *buf, u16 size); + +/* +********************************************************* +* aec_uart_write +* Description: 将写入通话的数据写入串口buffer +* Arguments : None. +* Return : None. +* Note(s) : None. +********************************************************* +*/ +void aec_uart_write(void); + +/* +********************************************************* +* aec_uart_close +* Description: 关闭数据写卡 +* Arguments : None. +* Return : 0 成功 其他 失败 +* Note(s) : None. +********************************************************* +*/ +int aec_uart_close(void); +#endif/*_AEC_UART_DEBUG_H_*/ diff --git a/include_lib/media/cvp/commproc.h b/include_lib/media/cvp/commproc.h new file mode 100644 index 0000000..c785d3c --- /dev/null +++ b/include_lib/media/cvp/commproc.h @@ -0,0 +1,201 @@ +#ifndef _COMMPROC_H_ +#define _COMMPROC_H_ + +#include "generic/typedef.h" +#include "cvp_common.h" + +/*降噪版本定义*/ +#define ANS_V100 0xA1 +#define ANS_V200 0xA2 + +//aec_cfg: +typedef struct __AEC_CONFIG { + u8 mic_again; //DAC增益,default:3(0~14) + u8 dac_again; //MIC增益,default:22(0~31) + u8 aec_mode; //AEC模式,default:advance(diable(0), reduce(1), advance(2)) + u8 ul_eq_en; //上行EQ使能,default:enable(disable(0), enable(1)) + /*AGC*/ + float ndt_fade_in; //单端讲话淡入步进default: 1.f(0.1 ~ 5 dB) + float ndt_fade_out; //单端讲话淡出步进default: 0.7f(0.1 ~ 5 dB) + float dt_fade_in; //双端讲话淡入步进default: 1.3f(0.1 ~ 5 dB) + float dt_fade_out; //双端讲话淡出步进default: 0.7f(0.1 ~ 5 dB) + float ndt_max_gain; //单端讲话放大上限,default: 12.f(0 ~ 24 dB) + float ndt_min_gain; //单端讲话放大下限,default: 0.f(-20 ~ 24 dB) + float ndt_speech_thr; //单端讲话放大阈值,default: -50.f(-70 ~ -40 dB) + float dt_max_gain; //双端讲话放大上限,default: 12.f(0 ~ 24 dB) + float dt_min_gain; //双端讲话放大下限,default: 0.f(-20 ~ 24 dB) + float dt_speech_thr; //双端讲话放大阈值,default: -40.f(-70 ~ -40 dB) + float echo_present_thr; //单端双端讲话阈值,default:-70.f(-70 ~ -40 dB) + /*AEC*/ + float aec_dt_aggress; //原音回音追踪等级, default: 1.0f(1 ~ 5) + float aec_refengthr; //进入回音消除参考值, default: -70.0f(-90 ~ -60 dB) + /*ES*/ + float es_aggress_factor;//回音前级动态压制,越小越强,default: -3.0f(-1 ~ -5) + float es_min_suppress; //回音后级静态压制,越大越强,default: 4.f(0 ~ 10) + /*ANS*/ + float ans_aggress; //噪声前级动态压制,越大越强default: 1.25f(1 ~ 2) + float ans_suppress; //噪声后级静态压制,越小越强default: 0.04f(0 ~ 1) +} _GNU_PACKED_ AEC_CONFIG; + +struct aec_s_attr { + u8 agc_en: 1; + u8 ul_eq_en: 1; + u8 wideband: 1; + u8 toggle: 1; + u8 wn_en: 1; + u8 dly_est : 1; + u8 reserved: 2; + + u8 dst_delay;/*延时估计目标延时*/ + u8 EnableBit; + u8 packet_dump; + u8 SimplexTail; + u8 aec_tail_length; //AEC复杂等级:2~10,default:5 + float AGC_NDT_fade_in_step; //in dB + float AGC_NDT_fade_out_step; //in dB + float AGC_NDT_max_gain; //in dB + float AGC_NDT_min_gain; //in dB + float AGC_NDT_speech_thr; //in dB + float AGC_DT_fade_in_step; //in dB + float AGC_DT_fade_out_step; //in dB + float AGC_DT_max_gain; //in dB + float AGC_DT_min_gain; //in dB + float AGC_DT_speech_thr; //in dB + float AGC_echo_present_thr; //In dB + int AGC_echo_look_ahead; //in ms + int AGC_echo_hold; // in ms + u16 hw_delay_offset;/*dac hardware delay offset*/ + u16 wn_gain;/*white_noise gain*/ + int SimplexThr; + float ES_AggressFactor; + float ES_MinSuppress; + float ES_Unconverge_OverDrive; + float ANS_AggressFactor; + float ANS_MinSuppress; + float ANS_NoiseLevel; + int (*cvp_advanced_options)(void *aec, + void *nlp, + void *ns, + void *tde, + void *agc); + int (*aec_probe)(short *mic0, short *mic2, short *mic3, short *ref, u16 len); + int (*aec_post)(s16 *dat, u16 len); + int (*aec_update)(u8 aec_mode); + int (*output_handle)(s16 *dat, u16 len); + u8 output_way; // 0:dac 1:fm + u8 ANS_mode; + u8 fm_tx_start; + u8 far_noise_gate;//default:10 + + float AEC_RefEngThr; + float AEC_DT_AggressiveFactor; + //float AES_AggressFactor; + //float AES_RefEngThr; + + /*Extended-Parameters*/ + u16 ref_sr; + u16 ref_channel; /*参考数据声道数*/ + u16 adc_ref_en; /*adc回采参考数据使能*/ + + /*DNS Parameters*/ + float DNS_GainFloor; //最小压制 range[0:1.00] + float DNS_OverDrive; //降噪强度 range[0:6.0] + float DNS_highGain; //EQ强度 range[1.0:3.5] + float DNS_rbRate; //混响强度 range[0:0.9] + +}; + +/* +********************************************************************* +* AEC Init +* Description: AEC模块初始化 +* Arguments : attr AEC模块参数 +* Return : 0 成功 其他 失败 +* Note(s) : None. +********************************************************************* +*/ +s32 aec_init(struct aec_s_attr *attr); + +/* +********************************************************************* +* AEC Exit +* Description: AEC退出 +* Arguments : None. +* Return : 0 成功 其他 失败 +* Note(s) : None. +********************************************************************* +*/ +s32 aec_exit(); +u32 aec_output_read(s16 *buf, u16 npoint); + +/* +********************************************************************* +* AEC Input +* Description: AEC源数据输入 +* Arguments : dat 参考数据 +* len 参考数据长度 +* Return : 0 成功 其他 失败 +* Note(s) : None. +********************************************************************* +*/ +s32 aec_fill_in_data(void *dat, u16 len); + +/* +********************************************************************* +* AEC Reference +* Description: AEC参考数据输入 +* Arguments : dat 参考数据 +* len 参考数据长度 +* Return : 0 成功 其他 失败 +* Note(s) : None. +********************************************************************* +*/ +s32 aec_fill_ref_data(void *dat, u16 len); + +/*adc回采dac数据做ref*/ +int aec_fill_in_ref_data(void *dat, u16 len); + +/* +********************************************************************* +* AEC Toggle +* Description: AEC bypass设置 +* Arguments : toggle bypass开关 +* Return : None. +* Note(s) : 该接口用于切换算法开关,1为正常流程,0为bypass,数据 +* 不经算法处理 +********************************************************************* +*/ +void aec_toggle(u8 toggle); + +/* +********************************************************************* +* AEC CFG Updata +* Description: AEC模块配置动态更新 +* Arguments : cfg AEC模块参数 +* Return : 0 成功 其他 失败 +* Note(s) : 该接口用于使用过程,动态修改模块参数 +********************************************************************* +*/ +int aec_cfg_update(AEC_CONFIG *cfg); + +/* +********************************************************************* +* AEC Reboot +* Description: AEC模块重新启动 +* Arguments : enablebit 重新启动使能的模块 +* Return : 0 成功 其他 失败 +* Note(s) : 该接口用于重新启动AEC模块 +********************************************************************* +*/ +int aec_reboot(u8 enablebit); + +int sms_tde_init(struct aec_s_attr *attr); +int sms_tde_exit(); +int sms_tde_fill_in_data(void *dat, u16 len); +int sms_tde_fill_ref_data(void *dat, u16 len); +int sms_tde_fill_in_ref_data(void *dat, u16 len); +void sms_tde_toggle(u8 toggle); +int cvp_sms_read_ref_data(void); +int cvp_sms_tde_read_ref_data(void); + +#endif diff --git a/include_lib/media/cvp/commproc_dms.h b/include_lib/media/cvp/commproc_dms.h new file mode 100644 index 0000000..7f212c5 --- /dev/null +++ b/include_lib/media/cvp/commproc_dms.h @@ -0,0 +1,258 @@ +#ifndef _COMMPROC_DMS_H_ +#define _COMMPROC_DMS_H_ + +#include "generic/typedef.h" +#include "cvp_common.h" + +/*降噪版本定义*/ +#define DMS_V100 0xA1 +#define DMS_V200 0xA2 + +//dms_cfg: +typedef struct { + u8 mic_again; //DAC增益,default:3(0~14) + u8 dac_again; //MIC增益,default:22(0~31) + u8 enable_module; //使能模块 + u8 ul_eq_en; //上行EQ使能,default:enable(disable(0), enable(1)) + /*AGC*/ + float ndt_fade_in; //单端讲话淡入步进default: 1.3f(0.1 ~ 5 dB) + float ndt_fade_out; //单端讲话淡出步进default: 0.7f(0.1 ~ 5 dB) + float dt_fade_in; //双端讲话淡入步进default: 1.3f(0.1 ~ 5 dB) + float dt_fade_out; //双端讲话淡出步进default: 0.7f(0.1 ~ 5 dB) + float ndt_max_gain; //单端讲话放大上限,default: 12.f(0 ~ 24 dB) + float ndt_min_gain; //单端讲话放大下限,default: 0.f(-20 ~ 24 dB) + float ndt_speech_thr; //单端讲话放大阈值,default: -50.f(-70 ~ -40 dB) + float dt_max_gain; //双端讲话放大上限,default: 12.f(0 ~ 24 dB) + float dt_min_gain; //双端讲话放大下限,default: 0.f(-20 ~ 24 dB) + float dt_speech_thr; //双端讲话放大阈值,default: -40.f(-70 ~ -40 dB) + float echo_present_thr; //单端双端讲话阈值,default:-70.f(-70 ~ -40 dB) + /*aec*/ + int aec_process_maxfrequency; //default:8000,range[3000:8000] + int aec_process_minfrequency; //default:0,range[0:1000] + int af_length; //default:128 range[128:256] + /*nlp*/ + int nlp_process_maxfrequency; //default:8000,range[3000:8000] + int nlp_process_minfrequency; //default:0,range[0:1000] + float overdrive; //default:1,range[0:30] + /*ans*/ + float aggressfactor; //default:1.25,range[1:2] + float minsuppress; //default:0.04,range[0.01:0.1] + float init_noise_lvl; //default:-75dB,range[-100:-30] + /*enc*/ + int enc_process_maxfreq; //default:8000,range[3000:8000] + int enc_process_minfreq; //default:0,range[0:1000] + int sir_maxfreq; //default:3000,range[1000:8000] + float mic_distance; //default:0.015,range[0.035:0.015] + float target_signal_degradation;//default:1,range[0:1] + float enc_aggressfactor; //default:4.f,range[0:4] + float enc_minsuppress; //default:0.09f,range[0:0.1] + /*common*/ + float global_minsuppress; //default:0.0,range[0.0:0.09] +} _GNU_PACKED_ AEC_DMS_CONFIG; + +//dms_flexible_cfg: +typedef struct { + u8 ver; //Ver:01 + u8 mic_again; //MIC0增益,default:10(0~14) + u8 mic1_again; //MIC1增益,default:3(0~14) + u8 dac_again; //DAC增益,default:22(0~31) + u8 enable_module; //使能模块 NS:BIT(2) ENC:BIT(3) AGC:BIT(4) + u8 ul_eq_en; //上行EQ使能,default:enable(disable(0), enable(1)) + u8 reserved[2]; + + /*AGC*/ + float ndt_fade_in; //单端讲话淡入步进default: 1.3f(0.1 ~ 5 dB) + float ndt_fade_out; //单端讲话淡出步进default: 0.7f(0.1 ~ 5 dB) + float dt_fade_in; //双端讲话淡入步进default: 1.3f(0.1 ~ 5 dB) + float dt_fade_out; //双端讲话淡出步进default: 0.7f(0.1 ~ 5 dB) + float ndt_max_gain; //单端讲话放大上限,default: 12.f(0 ~ 24 dB) + float ndt_min_gain; //单端讲话放大下限,default: 0.f(-20 ~ 24 dB) + float ndt_speech_thr; //单端讲话放大阈值,default: -50.f(-70 ~ -40 dB) + float dt_max_gain; //双端讲话放大上限,default: 12.f(0 ~ 24 dB) + float dt_min_gain; //双端讲话放大下限,default: 0.f(-20 ~ 24 dB) + float dt_speech_thr; //双端讲话放大阈值,default: -40.f(-70 ~ -40 dB) + float echo_present_thr; //单端双端讲话阈值,default:-70.f(-70 ~ -40 dB) + /*aec*/ + int aec_process_maxfrequency; //default:8000,range[3000:8000] + int aec_process_minfrequency; //default:0,range[0:1000] + int af_length; //default:128 range[128:256] + /*nlp*/ + int nlp_process_maxfrequency; //default:8000,range[3000:8000] + int nlp_process_minfrequency; //default:0,range[0:1000] + float overdrive; //default:1,range[0:30] + /*ans*/ + float aggressfactor; //default:1.25,range[1:2] + float minsuppress; //default:0.04,range[0.01:0.1] + float init_noise_lvl; //default:-75dB,range[-100:-30] + /*enc*/ + float enc_suppress_pre; //ENC前级压制,越大越强 default:0.6f,range[0:1] + float enc_suppress_post; //ENC后级压制,越大越强 default:0.15f,range[0:1] + float enc_minsuppress; //ENC后级压制下限 default:0.09f,range[0:1] + float enc_disconverge_erle_thr; //滤波器发散控制阈值,越大控制越强 default:-6.f,range[-20:5] + +} DMS_FLEXIBLE_CONFIG; + +struct dms_attr { + u8 ul_eq_en: 1; + u8 wideband: 1; + u8 wn_en: 1; + u8 dly_est : 1; + u8 aptfilt_only: 1; + u8 reserved: 3; + + u8 dst_delay;/*延时估计目标延时*/ + u8 EnableBit; + u8 packet_dump; + u8 SimplexTail; + u8 output_sel;/*dms output选择*/ + u16 hw_delay_offset;/*dac hardware delay offset*/ + u16 wn_gain;/*white_noise gain*/ + /*AGC*/ + float AGC_NDT_fade_in_step; //in dB + float AGC_NDT_fade_out_step; //in dB + float AGC_NDT_max_gain; //in dB + float AGC_NDT_min_gain; //in dB + float AGC_NDT_speech_thr; //in dB + float AGC_DT_fade_in_step; //in dB + float AGC_DT_fade_out_step; //in dB + float AGC_DT_max_gain; //in dB + float AGC_DT_min_gain; //in dB + float AGC_DT_speech_thr; //in dB + float AGC_echo_present_thr; //In dB + int AGC_echo_look_ahead; //in ms + int AGC_echo_hold; // in ms + /*AEC*/ + int aec_process_maxfrequency; //default:8000,range[3000:8000] + int aec_process_minfrequency; //default:0,range[0:1000] + int af_length; //default:128 range[128:256] + /*NLP*/ + int nlp_process_maxfrequency; //default:8000,range[3000:8000] + int nlp_process_minfrequency; //default:0,range[0:1000] + float overdrive; //default:1,range[0:30] + /*ANS*/ + float aggressfactor; //default:1.25,range[1:2] + float minsuppress; //default:0.04,range[0.01:0.1] + float init_noise_lvl; //default:-75db,range[-100:-30] + /*ENC*/ + int enc_process_maxfreq; //default:8000,range[3000:8000] + int enc_process_minfreq; //default:0,range[0:1000] + int sir_maxfreq; //default:3000,range[1000:8000] + float mic_distance; //default:0.015,range[0.035:0.015] + float target_signal_degradation;//default:1,range[0:1] + float enc_aggressfactor; //default:4.f,range[0:4] + float enc_minsuppress; //default:0.09f,range[0:0.1] + /*BCS*/ + int bone_process_maxfreq; + int bone_process_minfreq; + float bone_init_noise_lvl; + int Bone_AEC_Process_MaxFrequency; + int Bone_AEC_Process_MinFrequency; + /*common*/ + float global_minsuppress; //default:0.0,range[0.0:0.09] + /*data handle*/ + int (*cvp_advanced_options)(void *aec, + void *nlp, + void *ns, + void *enc, + void *agc, + void *wn, + void *mfdt); + int (*aec_probe)(short *mic0, short *mic2, short *mic3, short *ref, u16 len); + int (*aec_post)(s16 *dat, u16 len); + int (*aec_update)(u8 EnableBit); + int (*output_handle)(s16 *dat, u16 len); + + /*flexible enc*/ + int flexible_af_length; //default:512 range[128、256、512、1024] + int sir_minfreq; //default:100,range[0:8000] + int SIR_mean_MaxFrequency; //default:1000,range[0:8000] + int SIR_mean_MinFrequency; //default:100,range[0:8000] + float ENC_CoheFlgMax_gamma; //default:0.5f,range[0:1] + float coheXD_thr; //default:0.5f,range[0:1] + float Disconverge_ERLE_Thr; //default:-6.f,range[-20:5] + + /*WN*/ + float wn_detect_time; //in second + float wn_detect_time_ratio_thr; //0-1 + float wn_detect_thr; //0-1 + float wn_minsuppress; //0-1 + + /*Extended-Parameters*/ + u16 ref_sr; + u16 ref_channel; /*参考数据声道数*/ + u16 adc_ref_en; /*adc回采参考数据使能*/ + + /*DNS Parameters*/ + float DNS_highGain; //EQ强度 range[1.0:3.5] + float DNS_rbRate; //混响强度 range[0:0.9]; + + /*MFDT Parameters*/ + float detect_time; // // 检测时间s,影响状态切换的速度 + float detect_eng_diff_thr; // 0~-90 dB 两个mic能量差异持续大于此阈值超过检测时间则会检测为故障 + float detect_eng_lowerbound; // 0~-90 dB 当处于故障状态时,正常的mic能量大于此阈值才会检测能量差异,避免安静环境下误判切回正常状态 + int MalfuncDet_MaxFrequency;// 检测信号的最大频率成分 + int MalfuncDet_MinFrequency;// 检测信号的最小频率成分 + int OnlyDetect;// 0 -> 故障切换到单mic模式, 1-> 只检测不切换 +}; + +s32 aec_dms_init(struct dms_attr *attr); +s32 aec_dms_exit(); +s32 aec_dms_fill_in_data(void *dat, u16 len); +int aec_dms_fill_in_ref_data(void *dat, u16 len); +s32 aec_dms_fill_ref_data(void *dat, u16 len); +void aec_dms_toggle(u8 toggle); +int aec_dms_cfg_update(AEC_DMS_CONFIG *cfg); +int aec_dms_reboot(u8 enablebit); + +s32 aec_dms_flexible_init(struct dms_attr *attr); +s32 aec_dms_flexible_exit(); +s32 aec_dms_flexible_fill_in_data(void *dat, u16 len); +int aec_dms_flexible_fill_in_ref_data(void *dat, u16 len); +s32 aec_dms_flexible_fill_ref_data(void *dat, u16 len); +void aec_dms_flexible_toggle(u8 toggle); +int aec_dms_flexible_cfg_update(DMS_FLEXIBLE_CONFIG *cfg); +int aec_dms_flexible_reboot(u8 enablebit); + +/*获取风噪的检测结果,1:有风噪,0:无风噪*/ +int cvp_dms_get_wind_detect_state(void); + +/*单双麦切换状态 + * 0: 正常双麦 ; + * 1: 副麦坏了,触发故障 + * -1: 主麦坏了,触发故障 + */ +int cvp_dms_get_malfunc_state(void); + +/* + * 获取mic的能量值,开了MFDT_EN才能用 + * mic: 0 获取主麦能量 + * mic:1 获取副麦能量 + * return:返回能量值,[0~90.3],返回-1表示错误 + */ +float cvp_dms_get_mic_energy(u8 mic); + +typedef enum { + DMS_FLEXIBLE_DUAL_MIC = 0, //双mic + DMS_FLEXIBLE_USE_TALK_MIC, //通话mic(主麦) + DMS_FLEXIBLE_USE_REF_MIC, //参考mic(副麦) +} DMS_FLEXIBLE_MIC; + +/* 话务耳机切换使用的mic + * DMS_FLEXIBLE_DUAL_MIC :正常双麦话务耳机 + * DMS_FLEXIBLE_USE_TALK_MIC :使用主麦 + * DMS_FLEXIBLE_USE_REF_MIC :使用副麦 + */ +int aec_dms_flexible_selete_mic(DMS_FLEXIBLE_MIC mic); + +int cvp_dms_read_ref_data(void); +int cvp_dms_flexible_read_ref_data(void); + +/* + * 获取风噪检测信息 + * wd_flag: 0 没有风噪,1 有风噪 + * 风噪强度r: 0~BIT(16) + * wd_lev: 风噪等级,0:弱风,1:中风,2:强风 + * */ +int jlsp_get_wind_detect_info(int *wd_flag, int *wd_val, int *wd_lev); + +#endif/*_COMMPROC_DMS_H_*/ diff --git a/include_lib/media/cvp/commproc_ns.h b/include_lib/media/cvp/commproc_ns.h new file mode 100644 index 0000000..c0ec25c --- /dev/null +++ b/include_lib/media/cvp/commproc_ns.h @@ -0,0 +1,26 @@ +#ifndef _COMMPROC_NS_H_ +#define _COMMPROC_NS_H_ + +#include "generic/typedef.h" + +typedef struct { + char wideband; + char mode; + float AggressFactor; + float MinSuppress; + float NoiseLevel; +} noise_suppress_param; + +int noise_suppress_frame_point_query(noise_suppress_param *param); +int noise_suppress_mem_query(noise_suppress_param *param); +int noise_suppress_open(noise_suppress_param *param); +int noise_suppress_close(void); +int noise_suppress_run(short *in, short *out, int npoint); + +enum { + NS_CMD_NOISE_FLOOR = 1, + NS_CMD_LOWCUTTHR, +}; +int noise_suppress_config(u32 cmd, int arg, void *priv); + +#endif/*_COMMPROC_NS_H_*/ diff --git a/include_lib/media/cvp/commproc_tms.h b/include_lib/media/cvp/commproc_tms.h new file mode 100644 index 0000000..1a21db9 --- /dev/null +++ b/include_lib/media/cvp/commproc_tms.h @@ -0,0 +1,198 @@ +#ifndef _COMMPROC_DMS_H_ +#define _COMMPROC_DMS_H_ + +#include "generic/typedef.h" +#include "cvp_common.h" + +/*agc类型定义*/ +#define AGC_EXTERNAL 0 +#define AGC_INTERNAL 1 + +//tms_cfg: +typedef struct { + u8 ver; //Ver:01 + u8 mic_again; //MIC增益,default:3(0~14) + u8 fb_mic_again; //FB MIC增益,default:3(0~14) + u8 dac_again; //DAC增益,default:22(0~31) + + u8 talk_mic_ch; //主MIC通道选择 + u8 talk_ref_mic_ch; //副MIC通道选择 + u8 talk_fb_mic_ch; //FB通道选择 + + u8 enable_module; //使能模块 + u8 ul_eq_en; //上行EQ使能,default:enable(disable(0), enable(1)) + u8 agc_type; + union { + /*AGC*/ + struct { + float ndt_fade_in; //单端讲话淡入步进default: 1.3f(0.1 ~ 5 dB) + float ndt_fade_out; //单端讲话淡出步进default: 0.7f(0.1 ~ 5 dB) + float dt_fade_in; //双端讲话淡入步进default: 1.3f(0.1 ~ 5 dB) + float dt_fade_out; //双端讲话淡出步进default: 0.7f(0.1 ~ 5 dB) + float ndt_max_gain; //单端讲话放大上限,default: 12.f(0 ~ 24 dB) + float ndt_min_gain; //单端讲话放大下限,default: 0.f(-20 ~ 24 dB) + float ndt_speech_thr; //单端讲话放大阈值,default: -50.f(-70 ~ -40 dB) + float dt_max_gain; //双端讲话放大上限,default: 12.f(0 ~ 24 dB) + float dt_min_gain; //双端讲话放大下限,default: 0.f(-20 ~ 24 dB) + float dt_speech_thr; //双端讲话放大阈值,default: -40.f(-70 ~ -40 dB) + float echo_present_thr; //单端双端讲话阈值,default:-70.f(-70 ~ -40 dB) + } agc_ext; + + /*JLSP AGC*/ + struct { + int min_mag_db_level; + int max_mag_db_level; + int addition_mag_db_level; + int clip_mag_db_level; + int floor_mag_db_level; + } agc_int; + } agc; + /*aec*/ + int aec_process_maxfrequency; //default:8000,range[3000:8000] + int aec_process_minfrequency; //default:0,range[0:1000] + int af_length; //default:128 range[128:256] + /*nlp*/ + int nlp_process_maxfrequency; //default:8000,range[3000:8000] + int nlp_process_minfrequency; //default:0,range[0:1000] + float overdrive; //default:1,range[0:30] + /*ans*/ + float aggressfactor; //default:1.25,range[1:2] + float minsuppress; //default:0.04,range[0.01:0.1] + float init_noise_lvl; //default:-75dB,range[-100:-30] + /*enc*/ + int enc_process_maxfreq; //default:8000,range[3000:8000] + int enc_process_minfreq; //default:0,range[0:1000] + int sir_maxfreq; //default:3000,range[1000:8000] + float mic_distance; //default:0.015,range[0.035:0.015] + float target_signal_degradation;//default:1,range[0:1] + float enc_aggressfactor; //default:1.f,range[0:4] + float enc_minsuppress; //default:0.09f,range[0:0.1] + float Tri_SnrThreshold0; //sir设定阈值 + float Tri_SnrThreshold1; //sir设定阈值 + float Tri_CompenDb; //mic增益补偿 + /*wn*/ + float wn_msc_th; //双麦非相关性阈值,default:0.6f(0 ~ 1) + float ms_th; //麦增益能量阈值, default:80.f(0-255)dB + int wn_gain_offset; //风噪能量增益偏移阈值 + +} _GNU_PACKED_ AEC_TMS_CONFIG; + +struct tms_attr { + u8 ul_eq_en: 1; + u8 wideband: 1; + u8 wn_en: 1; + u8 dly_est : 1; + u8 aptfilt_only: 1; + u8 reserved: 3; + + u8 dst_delay;/*延时估计目标延时*/ + u8 EnableBit; + u8 FB_EnableBit; + u8 packet_dump; + u8 SimplexTail; + u8 output_sel;/*dms output选择*/ + u16 hw_delay_offset;/*dac hardware delay offset*/ + u16 wn_gain;/*white_noise gain*/ + u8 agc_type; /*agc类型*/ + /*AGC*/ + float AGC_NDT_fade_in_step; //in dB + float AGC_NDT_fade_out_step; //in dB + float AGC_NDT_max_gain; //in dB + float AGC_NDT_min_gain; //in dB + float AGC_NDT_speech_thr; //in dB + float AGC_DT_fade_in_step; //in dB + float AGC_DT_fade_out_step; //in dB + float AGC_DT_max_gain; //in dB + float AGC_DT_min_gain; //in dB + float AGC_DT_speech_thr; //in dB + float AGC_echo_present_thr; //In dB + int AGC_echo_look_ahead; //in ms + int AGC_echo_hold; // in ms + /*jlsp agc*/ + int min_mag_db_level; + int max_mag_db_level; + int addition_mag_db_level; + int clip_mag_db_level; + int floor_mag_db_level; + /*AEC*/ + int aec_process_maxfrequency; //default:8000,range[3000:8000] + int aec_process_minfrequency; //default:0,range[0:1000] + int af_length; //default:128 range[128:256] + /*NLP*/ + int nlp_process_maxfrequency; //default:8000,range[3000:8000] + int nlp_process_minfrequency; //default:0,range[0:1000] + float overdrive; //default:1,range[0:30] + /*ANS*/ + float aggressfactor; //default:1.25,range[1:2] + float minsuppress; //default:0.04,range[0.01:0.1] + float init_noise_lvl; //default:-75db,range[-100:-30] + /*DNS Parameters*/ + float DNS_highGain; //EQ强度 range[1.0:3.5] + float DNS_rbRate; //混响强度 range[0:0.9]; + int enhance_flag; //是否高频增强 range[0,1] + /*ENC*/ + int Tri_CutTh; //fb麦统计截止频率 + float Tri_SnrThreshold0; //sir设定阈值 + float Tri_SnrThreshold1; //sir设定阈值 + float *Tri_TransferFunc; //fb -> main传递函数 + float Tri_FbCompenDb; //fb补偿增益 + int Tri_TfEqSel; //eq,传递函数的选择:0选择eq,1选择传递函数,2选择传递函数和eq + int enc_process_maxfreq; //default:8000,range[3000:8000] + int enc_process_minfreq; //default:0,range[0:1000] + int sir_maxfreq; //default:3000,range[1000:8000] + float mic_distance; //default:0.015,range[0.035:0.015] + float target_signal_degradation;//default:1,range[0:1] + float enc_aggressfactor; //default:4.f,range[0:4] + float enc_minsuppress; //default:0.09f,range[0:0.1] + float Tri_CompenDb; //mic增益补偿, dB + int Tri_Bf_Enhance; //bf是否高频增强 + /*wn*/ + float wn_msc_th; //双麦非相关性阈值,default:0.6f(0 ~ 1) + float ms_th; //麦增益能量阈值, default:80.f(0-255)dB + int wn_gain_offset; //风噪能量增益偏移阈值 + /*common*/ + float global_minsuppress; //default:0.0,range[0.0:0.09] + /*data handle*/ + int (*cvp_advanced_options)(void *aec, + void *nlp, + void *ns, + void *enc, + void *agc, + void *wn, + void *mfdt); + int (*aec_probe)(short *mic0, short *mic2, short *mic3, short *ref, u16 len); + int (*aec_post)(s16 *dat, u16 len); + int (*aec_update)(u8 EnableBit); + int (*output_handle)(s16 *dat, u16 len); + + /*Extended-Parameters*/ + u16 ref_sr; + u16 ref_channel; /*参考数据声道数*/ + u16 adc_ref_en; /*adc回采参考数据使能*/ +}; + +s32 aec_tms_init(struct tms_attr *attr); +s32 aec_tms_exit(); +s32 aec_tms_fill_in_data(void *dat, u16 len); +int aec_tms_fill_in_ref_data(void *dat, u16 len); +int aec_tms_fill_in_ref_1_data(void *dat, u16 len); +s32 aec_tms_fill_ref_data(void *dat, u16 len); +void aec_tms_toggle(u8 toggle); +int aec_tms_cfg_update(AEC_TMS_CONFIG *cfg); +int aec_tms_reboot(u8 enablebit); + +int cvp_tms_read_ref_data(void); + +/* + * 获取风噪检测信息 + * wd_flag: 0 没有风噪,1 有风噪 + * 风噪强度r: 0~BIT(16) + * wd_lev: 风噪等级,0:弱风,1:中风,2:强风 + * */ +int jlsp_tms_get_wind_detect_info(int *wd_flag, int *wd_val, int *wd_lev); + +/*tri_en: 1 正常3MIC降噪 + * 0 变成2MIC降噪,不使用 FB MIC数据*/ +int jlsp_tms_mode_choose(u8 tri_en); + +#endif/*_COMMPROC_DMS_H_*/ diff --git a/include_lib/media/cvp/cvp_common.h b/include_lib/media/cvp/cvp_common.h new file mode 100644 index 0000000..88197d4 --- /dev/null +++ b/include_lib/media/cvp/cvp_common.h @@ -0,0 +1,60 @@ +#ifndef _CVP_COMMON_H_ +#define _CVP_COMMON_H_ + +/*DMS版本定义*/ +#define DMS_GLOBAL_V100 0xB1 +#define DMS_GLOBAL_V200 0xB2 + +/* + * V200新算法回声消除nlp模式 + * JLSP_NLP_MODE1: 模式1为单独的NLP回声抑制,回声压制会偏过,该模式下NLP模块可以单独开启 + * JLSP_NLP_MODE2: 模式2下回声信号会先经过AEC线性压制,然后进行NLP非线性压制 + * 此模式NLP不能单独打开需要同时打开AEC,使用AEC模块压制不够时,建议开启该模式 + */ +#define JLSP_NLP_MODE1 0x01 //模式一(默认) +#define JLSP_NLP_MODE2 0x02 //模式二 + +/* + * V200新算法风噪降噪模式 + * JLSP_WD_MODE1: 模式1为常规的降风噪模式,风噪残余会偏大些 + * JLSP_WD_MODE2: 模式2为神经网络降风噪,风噪抑制会比较干净,但是会需要多消耗31kb的flash + */ +#define JLSP_WD_MODE1 0x01 //常规降噪 +#define JLSP_WD_MODE2 0x02 //nn降风噪,目前该算法启用会多31kflash + +/*DMS输出选择*/ +typedef enum { + DMS_OUTPUT_SEL_DEFAULT = 0, /*默认输出:dms处理后的数据*/ + DMS_OUTPUT_SEL_MASTER, /*主mic原始数据*/ + DMS_OUTPUT_SEL_SLAVE, /*副mic原始数据*/ + DMS_OUTPUT_SEL_FBMIC, /*FB mic原始数据*/ +} CVP_OUTPUT_ENUM; + +/* +********************************************************************* +* Audio CVP IOCTL +* Description: CVP功能配置 +* Arguments : cmd 操作命令 +* value 操作数 +* priv 操作内存地址 +* Return : 0 成功 其他 失败 +* Note(s) : (1)比如动态开关降噪NS模块: +* aec_dms_ioctl(CVP_NS_SWITCH,1,NULL); //降噪关 +* aec_dms_ioctl(CVP_NS_SWITCH,0,NULL); //降噪开 +********************************************************************* +*/ +enum { + CVP_AEC_SWITCH = 1, + CVP_NLP_SWITCH, + CVP_NS_SWITCH, + CVP_AGC_SWITCH, + CVP_ENC_SWITCH, + CVP_AGC_MAX_LVL, +}; +int aec_ioctl(int cmd, int value, void *priv); +int aec_dms_ioctl(int cmd, int value, void *priv); +int aec_dms_flexible_ioctl(int cmd, int value, void *priv); + + +#endif /*_CVP_COMMON_H_*/ + diff --git a/include_lib/media/cvp/lib_h/jlsp_ns.h b/include_lib/media/cvp/lib_h/jlsp_ns.h new file mode 100644 index 0000000..c1ccd5a --- /dev/null +++ b/include_lib/media/cvp/lib_h/jlsp_ns.h @@ -0,0 +1,260 @@ +#ifndef __JLSP_NS_H__ +#define __JLSP_NS_H__ + +//出现单个麦掩蔽参数 +typedef struct { + float detect_time;//检测时间 + float detect_eng_diff_thr; /*0~-90 dB 两个mic能量差异持续大于此阈值超过检测时间则会检测为故障*/ + float detect_eng_lowerbound;// 0~-90 dB start detect when mic energy lower than this + int MalfuncDet_MaxFrequency;//检测频率上限 + int MalfuncDet_MinFrequency;//检测频率下限 + int OnlyDetect;// 0 -> 故障切换到单mic模式, 1-> 只检测不切换 +} JLSP_dms_micsel_cfg; + +//beamforming参数设置 + +typedef struct { + int UseExWeight; //挂空 + int *ENC_WeightA; //挂空 + int *ENC_WeightB; //挂空 + int ENC_Weight_Q; //挂空 + + int ENC_Process_MaxFrequency; //设定enc处理的最大频率,设定范围(3000~8000),默认8000 + int ENC_Process_MinFrequency; //设定enc处理的最小频率,设定范围(0~1000),默认为0 + int SIR_MaxFrequency; //设定enc信噪比处理最大频率,设定范围(1000~8000),默认3000 + float Mic_Distance; //设定主副mic的距离,单位(m),范围(0.015~35),默认0.015 + float Target_Signal_Degradation; //根据主副麦能量的diff值,设定范围(0~1),默认1.0 + float AggressFactor; //设置enc压制强度,设定范围(0~4),默认4 + float minSuppress; //设定enc抑制的最小值,设定范围(0~0.1),默认0.09 + + float compen_db; //补偿增益控制,单位(db),具体调节配合麦的增益协同调节,一般设定范围为(0~20) + int bf_enhance; //该值默认设置为0,设为1时,高频成分会丰富些,但是低信噪比下高频噪声也会偏大 + int lowFreqHoldEn; + float bfSupressFactor; +} JLSP_dms_bf_cfg; + +/*3麦降噪参数*/ +typedef struct { + int Tri_CutTh; //fb麦统计截止频率 + float Tri_SnrThreshold0; //sir设定阈值 + float Tri_SnrThreshold1; //sir设定阈值 + float *Tri_TransferFunc; //fb -> main传递函数 + float Tri_FbAlignedDb; //fb和主副麦之间需要补偿增益 + float Tri_FbCompenDb; //fb补偿增益 + int Tri_TfEqSel; //eq,传递函数的选择:0选择eq,1选择传递函数,2选择传递函数和eq + //int Tri_TransferMode; //传递函数模式选择,0:基于幅度的传递函数,1:基于幅度和相位的传递函数 + + + int Tri_Process_MaxFrequency; + int Tri_Process_MinFrequency; + int Tri_SIR_MaxFrequency; + float Tri_Mic_Distance; + float Tri_Target_Signal_Degradation; + float Tri_AggressFactor; + float Tri_MinSuppress; + + float Tri_CompenDb; //mic增益补偿 + int Tri_Bf_Enhance; + int Tri_LowFreqHoldEn; + float Tri_SupressFactor; + +} JLSP_tri_cfg; + +//回声消除设置参数 +typedef struct { + int AEC_Process_MaxFrequency; //设定回声消除处理的最大频率,设定范围(3000~8000),默认值为8000 + int AEC_Process_MinFrequency; //设定回声消除处理的最小频率,设定范围(0~1000),默认值为0 + int AF_Length; //挂空 + float muf; //设定aec滤波器的学习速率,默认0.02,设定范围(0.0001~0.5) +} JLSP_dms_aec_cfg; + + +//非线性回声压制设置参数 +typedef struct { + int NLP_Process_MaxFrequency; //设定回声抑制的最大频率,设定范围(3000~8000),默认值为8000 + int NLP_Process_MinFrequency; //设定回声抑制的最小频率,设定范围(0~1000),默认值为0 + float OverDrive; //定设压制强度,越大压制越强,设定范围(0~5)默认为1.0 +} JLSP_dms_nlp_cfg; + + +//dns参数设置 +typedef struct { + float AggressFactor; //降噪强度,设置范围(0.3~6.0),默认值:1.0 + float minSuppress; //增益最小值控制,越小降噪越强,设置范围(0.0~1.0),默认为0.1 + float init_noise_lvl; //初始噪声水平 + float high_gain; //单麦高频增强,默认设置为1.0,设置范围为(1.0~3.0) + float rb_rate; //单麦混响增强,默认设置为0.1,设置范围为(0~0.9) + int enhance_flag; //是否开启双麦高频增强,默认为1 +} JLSP_dms_dns_cfg; + +typedef struct { + int min_mag_db_level; //语音能量放大下限阈值(单位db,默认-50,范围(-90db~-35db)) + int max_mag_db_level; //语音能量放大上限阈值(单位db,默认-3,范围(-90db~0db)) + int addition_mag_db_level; //语音补偿能量值(单位db,默认0,范围(0db~20db)) + int clip_mag_db_level; //语音最大截断能量值(单位db,默认-3,范围(-10db~db)) + int floor_mag_db_level; //语音最小截断能量值(单位db,默认-70,范围(-90db~-35db) +} JLSP_agc_cfg; + +//风噪检测参数设置 +typedef struct { + float wn_msc_th; //双麦非相关性阈值 (0-1) + float ms_th; //麦增益能量阈值(0-255) + int wn_inty1; + int wn_inty2; + float wn_gain1; + float wn_gain2; + + int t1_bot; //低风噪等级能量下限阈值 + int t1_top; //低风噪等级能量上限阈值 + int t2_bot; //强风噪等级能量下限阈值 + int t2_top; //强风噪等级能量上限阈值 + int offset; //风噪能量增益偏移阈值 + + int t1_bot_cnt_limit; //风强变到弱风等级连续帧数计数,位宽16bit + int t1_top_cnt_limit; //风强由弱风变到中风等级连续帧数计数,位宽16bit + int t2_bot_cnt_limit; //风强由强风变到中风连续帧数计数,位宽16bit + int t2_top_cnt_limit; //风强变到强风连续帧数计数,位宽16bit +} JLSP_dms_wind_cfg; + +/* +gain_floor: 增益的最小值控制,范围0~1,建议值(0~0.2)之间 +over_drive: 控制降噪强度: +0 < over_drive < 1,越小降噪强度越轻,太小噪声会很大; +over_drive = 1,正常降噪 +over_drive > 1,降噪强度加强,越大降噪强度越强,太大会吃音 +建议调节范围0.3~3之间来控制降噪强度的强弱 +high_gain: 控制声音的宏亮度,范围(1.0f~3.5f),越大声音越宏亮,太大可能会使噪声增加, 为1.0f表示不做增强, 建议设置2.0f左右 +rb_rate: 混响强度,设置范围(0.0f~0.9f),越大混响越强, 为0.0f表示不增强, 建议默认设置0.5f +*/ + +void *JLSP_ns_init(char *private_buffer, char *shared_buffer, float gain_floor, float over_drive, float high_gain, float rb_rate, int samplerate, const int is_dual); +int JLSP_ns_get_heap_size(int *private_size, int *shared_size, int samplerate, int is_dual); + +int JLSP_ns_reset(void *m);//单双麦共用 +void JLSP_ns_update_shared_buffer(void *m, char *shared_buffer);//单双麦共用 +int JLSP_ns_process(void *m, void *input, void *output, int *outsize); +int JLSP_ns_free(void *m);//单双麦共用 + +void JLSP_ns_set_noiselevel(void *m, float noise_level_init);//单双麦共用 + + +/*功能:初始化snr相关参数 +* stop_freq: 高通滤波器的截止频率 +* snr_th: 人声阈值设定,即大于该值才会进行snr压制处理, 采用db进行设置, 默认-25db +* commpress_params: 压制系数 +* 0db一下分为了5个区间进行压缩,压缩系数范围(0~3),越大压制越强,建议范围(0~1.0f) +* snr < -10, 压制系数compress_params[4] +* snr < -8, 压制系数compress_params[3] +* snr < -5, 压制系数compress_params[2] +* snr < -3, 压制系数compress_params[1] +* snr < 0, 压制系数compress_params[0] +*/ +void JLSP_init_snr(void *m, int stop_freq, int snr_th, float *compress_params); + +/*功能: 获取当前帧snr +* 返回:当前帧snr值 +*/ +float JLSP_get_snr(void *m); + + + + +/* + * 双麦降噪接口 + */ +void JLSP_wd_single(unsigned char wd_act); +/* + *wd_flag: 0: no wind 1: wind + *wd_val: wind strong bit(16) + *wd_lev: wind level 0:弱风,1:中风, 2:强风 + */ +int JLSP_get_wd_info(void *handle, int *wd_flag, int *wd_val, int *wd_lev); + +/*设置使用的模块*/ +void JLSP_enable_module(int Enablebit);//仅双麦使用 + +/*初始化*/ +void *JLSP_DualMicSystem_Init(char *private_buf, + char *share_buf, + void *aec_cfg, + void *nlp_cfg, + void *bf_cfg, + void *dns_cfg, + void *wn_cfg, + void *micsel_cfg, + int samplerate, + int EnableBit); + +/*数据处理,返回风噪大小*/ +int JLSP_DualMicSystem_Process(void *handle, + short *near, + short *near_ref, + short *far, + short *out, + int points); + +//检测各个麦是否被堵住或者破坏相关信息 +/*获取单双麦切换状态 + * 0: 正常双麦 ; + * 1: 副麦坏了,触发故障 + * -1: 主麦坏了,触发故障 + */ +int JLSP_DualMicSystem_GetMicState(void *handle); +/* + * 获取mic的能量值,开了MFDT_EN才能用 + * mic: 0 获取主麦能量 + * mic:1 获取副麦能量 + * return:返回能量值,[0~90.3] + */ +float JLSP_DualMicSystem_GetMicEnergy(void *handle, unsigned char mic); +/*设置初始使用单双麦切换状态 + * 0: 正常双麦 ; + * 1: 副麦坏了,触发故障 + * -1: 主麦坏了,触发故障 + */ +void JLSP_DualMicSystem_SetMicState(void *handle, int state); + +//int JLSP_DualMicSystem_GetWdInfo(void* handle, int* wd_flag, int* wd_val, int* wd_lev); +//int JLSP_DualMicSystem_Get_Size(int* private_size, int* share_size, int samplerate, const int is_dual); +//int JLSP_DualMicSystem_Reset(void* m); +//void JLSP_DualMicSystem_Update_Shared_Buffer(void* m, char* shared_buffer); +//int JLSP_DualMicSystem_Free(void* m); +//void JLSP_DualMicSystem_Set_Noiselevel(void* m, float noise_level_init); + +/* +* 三麦降噪接口 +*/ +/*设置使用的模块*/ +void JLSP_TriMicSystem_EnableModule(int Enablebit, int Enablebit_Ex); + +/*获取风噪信息*/ +int JLSP_TriMicSystem_GetWdInfo(void *handle, int *wd_flag, int *wd_val, int *wd_lev); + +/*获取buf大小*/ +int JLSP_TriMicSystem_Get_Size(int *private_size, int *share_size, int samplerate, const int is_dual); + +/*初始化*/ +void *JLSP_TriMicSystem_Init(char *private_buf, + char *share_buf, + void *aec_cfg, + void *nlp_cfg, + void *tri_cfg, + void *dns_cfg, + void *wn_cfg, + void *agc_cfg, + int samplerate, + int EnableBit); + +/*数据处理,返回风噪大小*/ +int JLSP_TriMicSystem_Process(void *handle, + short *near, + short *near_ref, + short *fb, + short *far, + short *out, + int InDataLen); + +/*tri_en: 1 正常3MIC降噪 + * 0 变成2MIC降噪,不使用 FB MIC数据*/ +void JLSP_TriMicSystem_ModeChoose(void *handle, unsigned char tri_en); +#endif diff --git a/include_lib/media/diafx.h b/include_lib/media/diafx.h new file mode 100644 index 0000000..cb0dcc9 --- /dev/null +++ b/include_lib/media/diafx.h @@ -0,0 +1,45 @@ +#ifndef __DIAFX_H__ +#define __DIAFX_H__ + + +#ifndef __Q8P24__ +#define __Q8P24__ +#endif + + +#include +#include + +#ifndef __FMATH_H__ +#include "fmath.h" +#endif // __FMATH_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +extern int diafx_size(); + +// create a DIA handler +extern void *diafx_init_mode(int mode); + +// clear buffer +extern void diafx_clear(); + +//render raw pcm into processed one. +extern uint32_t diafx_run_Q8P24(inumber **inPcms, inumber **outPcms, int numFrames); +extern uint32_t diafx_run_Q8P24_interleave(inumber *inPcms, int numFrames); +uint32_t diafx_run_Q8P24_int16_interleave(int16_t *inPcms, int numFrames); +void diafx_enabled(int value); +void diafx_toggle_enabled(); +uint32_t jl_platform_diafx_run(int16_t *inPcms, int numFrames); + +#define diafx_init() diafx_init_mode(0) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include_lib/media/drc_api.h b/include_lib/media/drc_api.h new file mode 100644 index 0000000..95032f4 --- /dev/null +++ b/include_lib/media/drc_api.h @@ -0,0 +1,139 @@ +#ifndef DRC_API_H +#define DRC_API_H + +#ifdef WIN32 + +#define AT_DRC(x) +#define AT_DRC_CODE +#define AT_DRC_CONST +#define AT_DRC_SPARSE_CODE +#define AT_DRC_SPARSE_CONST + +#else +#define AT_DRC(x) __attribute((section(#x))) +#define AT_DRC_CODE AT_DRC(.drc_code) +#define AT_DRC_CONST AT_DRC(.drc_const) +#define AT_DRC_SPARSE_CODE AT_DRC(.drc_sparse_code) +#define AT_DRC_SPARSE_CONST AT_DRC(.drc_sparse_const) +#endif + + +enum { + DATA_IN_SHORT = 0, //输入数据类型,输入short时,输出不能为int + DATA_IN_INT, +}; +enum { + DATA_OUT_SHORT = 0, //输出数据类型,输入short时,输出不能为int + DATA_OUT_INT +}; + +enum { + PEAK = 0, //算法类型 + RMS +}; + +enum { + PERPOINT = 0, //mode 模式 + TWOPOINT +}; + +typedef struct _DrcParam { + /* + int *attackTime; //启动时间 + int *releaseTime; //释放时间 + float *threshold; //阈值{x1,y1,x2,y2} 最多5组十个数据 + int *ThresholdNum; //阈值的组数 + int *rmsTime; // rms时间 algorithm为RMS有效 + float *InputGain; // 输入增益(db) + float *OutputGain; // 输出数据增益(db) + unsigned char algorithm; // PEAK或者RMS + unsigned char mode; // 模式 + unsigned char intype; // 输入数据类型 + unsigned char outtype; // 输出数据类型 + */ + int channel; + int sampleRate; + int attackTime; //启动时间 + int releaseTime; //释放时间 + float *threshold; //阈值{x1,y1,x2,y2} 最多5组十个数据 + int ThresholdNum; //阈值的组数 + int rmsTime; // rms时间 algorithm为RMS有效 + float InputGain; // 输入增益(db) + float OutputGain; // 输出数据增益(db) + unsigned char algorithm; // PEAK或者RMS + unsigned char mode; // 模式 + unsigned char intype; // 输入数据类型 + unsigned char outtype; // 输出数据类型 + int IndataInc; // 输入数据同个通道下个点的步进 例如左右左右 步进为2 + int OutdataInc; // 输出数据同个通道下个点的步进 例如左右左右 步进为2 +} DrcParam; + +//int GetDrcBuf(int algorithm, int *rmsTime, int channel, int sampleRate); +int GetDrcBuf(DrcParam *param); // bufsize 与 algorithm,rmsTime channel、 sampleRate有关 +//void DrcInit(void *WorkBuf, DrcParam *param, int channel, int sampleRate); +void DrcInit(void *WorkBuf, DrcParam *param); +void DrcUpdate(void *WorkBuf, DrcParam *param); +int DrcRun(void *WorkBuf, void *indata, void *outdata, int per_channel_npoint); +/* InputGain 输入数据放大或者缩小的db数(正数放大,负数缩小) */ +// inputgain 配2,表示总体增加2dB +/* OutputGain 输出数据放大或者缩小的db数(正数放大,负数缩小) */ +#if 0 +int GetDrcBuf(int algorithm, int *rmsTime, int channel, int sampleRate); +获取buf大小 +参数说明: +algorithm:算法类型,PEAK或者RMS +rmsTime: +rms时间ms,算法类型为RMS时有效 +channel: 通道数 +sampleRate: +采样率 + +void DrcInit(void *WorkBuf, int *attackTime, int *releaseTime, float *threshold, int *ThresholdNum, int *rmsTime, int channel, int sampleRate, int algorithm, int mode, int intype, int outtype); +初始化 +参数说明: +WorkBuf: +运行buf +attackTime: +启动时间ms +releaseTime: +释放时间ms +threshold: +信号输入与对应的输出[in1, out1, in2, out2 ***排列] 最多5组数据, 3个阈值,4段 +ThresholdNum: +信号输入与对应的输出组数 +rmsTime: +rms时间ms +channel: +通道 +sampleRate:采样率 +algorithm:算法类型 +mode:模式 +intype:输入数据类型,DATA_IN_SHORT或者DATA_IN_INT +outtype: +输出数据类型,DATA_OUT_SHOR或者DATA_OUT_INT;若输入数据类型为DATA_IN_SHORT,输出类型只能设置为DATA_OUT_SHOR + +void DrcUpdate(void *WorkBuf, int *attackTime, int *releaseTime, float *threshold, int *ThresholdNum, int channel, int sampleRate); +更新参数:使用rms算法时,当rmsTime fs变化时因为buf会产生变化,只能初始化更新 +参数说明: +WorkBuf: +运行buf +attackTime: +启动时间ms +releaseTime: +释放时间ms +threshold: +信号输入与对应的输出[in1, out1, in2, out2 ***排列] 最多5组数据, 3个阈值,4段 +ThresholdNum: +信号输入与对应的输出组数 + +int DrcRun(void *WorkBuf, void *indata, void *outdata, int per_channel_npoint); +运行:输入输出数据类型,要跟初始化配置的数据类型对应 +WorkBuf: +运行buf +indata:输入数据 +outdata:输出数据 +per_channel_npoint:每个通道的样点数 +#endif + +#endif // !DRC_API_H + diff --git a/include_lib/media/effect_sur_api.h b/include_lib/media/effect_sur_api.h new file mode 100644 index 0000000..c971691 --- /dev/null +++ b/include_lib/media/effect_sur_api.h @@ -0,0 +1,108 @@ +#ifndef effectSUR_api_h__ +#define effectSUR_api_h__ + +/*单耳输入时,channel设置*/ +enum { + EFFECT_CH_L = 0x10, //单声道输入,输出左声道 + EFFECT_CH_R = 0x20, //单声道输入,输出右声道 + EFFECT_CH2_L = 0x30, //双声道输入,输出2个左声道 + EFFECT_CH2_R = 0x40, //双声道输入,输出2个右声道 +}; + +enum { + EFFECT_3D_TYPE0 = 0x01, + EFFECT_3D_TYPE1 = 0x02, //这2个2选1 :如果都置上,优先用EFFECT_3D_TYPE1 + EFFECT_3D_LRDRIFT = 0x04, + EFFECT_3D_ROTATE = 0x08, //这2个2选1 : 如果都置上,优先用EFFECT_3D_ROTATE + EFFECT_3D_TYPE2 = 0x10, + EFFECT_3D_LRDRIFT2 = 0x20, +}; + + +typedef struct __SUR_FUNC_API_ { + unsigned int (*need_buf)(int flag); + unsigned int (*open)(unsigned int *ptr, int effectflag, int nch); + unsigned int (*init)(unsigned int *ptr, int rotatestep, int damping, int feedback, int roomsize); + unsigned int (*run)(unsigned int *ptr, short *inbuf, int len); // len是对点 + unsigned int (*switch_effect)(unsigned int *ptr, int effectflag, int rotatestep, int damping, int feedback, int roomsize);//新增的切换音效参数接口 + unsigned int (*switch_nch)(unsigned int *ptr, int nch);//新增的声道修改接口 +} SUR_FUNC_API; + + +extern SUR_FUNC_API *get_sur_func_api(); + + + +#if 0 +因为复用其他音效的参数接口,所以还是用了4个参数,EFFECT_3D_TYPE2具体参数对应名称应该是 : { + int rotatestep; //无效参数 + int rot60_100ms; //范围0到150 + int wetgain ; //范围0到100 + int delay ; //范围0到100 +} + +默认参数可以用 FFECT_3D_TYPE2 {2, 90, 70, 100}, + +// 由于原本预留参数有些没留出来,为了可以调节频响之类的多效果,所以在原基础上通过把参数列表指针当做其中一个参数传进来 +// 如果 rot60_100ms小于0,wetgain=100的话, 那最后一个参数就是参数列表,这样就可以支持配置更多参数。 + +设置如下: + +flag = EFFECT_3D_TYPE2; +{ {2, -1, 100, surmode_present[MODE_SUR_KTV]}, + {2, -1, 100, surmode_present[MODE_SUR_3DTHE]}, + {2, -1, 100, surmode_present[MODE_SUR_HALL]}, + {2, -1, 100, surmode_present[MODE_SUR_VOICE]}, + {2, -1, 100, surmode_present[MODE_SUR_SUR]} +} + + +//其中参数示例: + +enum { + MODE_SUR_KTV = 0, //ktv模式 + MODE_SUR_3DTHE, //3D影院 + MODE_SUR_HALL, //音乐厅 + MODE_SUR_VOICE, //清澈人声 + MODE_SUR_SUR, //全景环绕 + MODE_SUR_MAX +}; + +//dry,wet,delay,rot60,Erwet,Erfactor,Ewidth,Ertolate,predelay,width,diffusion,dampinglpf,basslpf,bassB +const static int surmode_present[MODE_SUR_MAX][14] = { + {80, 100, 35, 9000, 80, 80, 80, 80, 20, 100, 70, 6500, 4000, 18}, + {80, 100, 90, 10030, 90, 90, 90, 90, 18, 100, 75, 7000, 1000, 29}, + {80, 100, 100, 13000, 100, 100, 100, 100, 20, 100, 72, 9000, 50, 3}, + {80, 100, 20, 5010, 100, 70, 70, 100, 15, 100, 70, 5500, 3500, 60}, + {80, 100, 100, 10000, 80, 80, 80, 90, 10, 100, 72, 8000, 500, 15}, +}; + + +//dry,wet,delay,Erwet,Erfactor,Ewitdh,Ertolate,width,diffusion 范围都是 0到 100 +//rot60 范围是 0到15000, 单位ms +//basslpf: 低频增强频率,范围 0到10000 +//dampinglpf: 高频衰减频率,范围 0到 10000 +//bassB: 低频增强比例 + + +混响调参说明: +1.dry: 干声增益 +2.wet: +整体效果声增益 +3.delay: 反射时间间隔,影响整体空间大小 +4.rot60: +衰减60dB需要的时间, 即衰减速度,如果空间里面的物体吸声厉害,或者比较空旷,衰减比较快 +5.Erwet:早反射声的增益, 早反射声的存在 会让混响听起来更真实。但是不同的增益会影响听感上距离感,空间构造 +6.Erfactor: 早反射声的一个密集程度。 这个值大,早反射声之间间隔比较大。构造的空间感也会相对较大。 较小的话,就反射比较密集。空间感变小。 +7.Ewidth:影响早反射声左右声道的声音差异 +8.Ertolate: +影响漫反射声音反馈的大小 +9.predelay:干声跟效果声的时间间隔。也会影响整体空间感。 +10.width:左右声道的差异,左右声道的差异,会产生立体感。(某些版本的sdk上该参数无效) +11.diffusion: 发散程度, 影响 漫反射声音的变形程度。 +12.dampinglpf:高频衰减过度频率。反射声的一个频率衰减,这是一个斜着往下掉的曲线,影响了反射声中的高频分量。高频分量越多,整体音色越亮,但是成分太多,声音有些乱 +13.basslpf:反射声中的低频增强分量过度频率 +14.bassB: +低频增强比例。 这里的低频增强,其实是压了高频。为了使整体频响不超过1,不引起反馈发散。所以加大了这个值感觉混响弱了。可以适量加大rot60或者Ertolate +#endif +#endif // reverb_api_h__ diff --git a/include_lib/media/eq_config.h b/include_lib/media/eq_config.h new file mode 100644 index 0000000..cbe49ae --- /dev/null +++ b/include_lib/media/eq_config.h @@ -0,0 +1,105 @@ +#ifndef CONFIG_EFFECT_CORE_V2_ENABLE +#include "application/eq_config.h" +#else + +#ifndef _EQ_CONFIG_H_ +#define _EQ_CONFIG_H_ + +#include "media/audio_eq.h" +#include "media/audio_drc.h" +#include "spinlock.h" +#include "math.h" + +/*----------------------------------------------------------------------------*/ +/**@brief 用默认eq系数表的eq效果模式设置(设置模式,更新系数) + @param mode:EQ_MODE_NORMAL, EQ_MODE_ROCK,EQ_MODE_POP,EQ_MODE_CLASSIC,EQ_MODE_JAZZ,EQ_MODE_COUNTRY, EQ_MODE_CUSTOM + @return + @note 外部使用 + */ +/*----------------------------------------------------------------------------*/ + +int eq_mode_set(EQ_MODE mode); +/*----------------------------------------------------------------------------*/ +/**@brief eq模式切换 + @param + @return + @note 外部使用 + */ +/*----------------------------------------------------------------------------*/ +int eq_mode_sw(void); +/*----------------------------------------------------------------------------*/ +/**@brief 获取eq效果模式 + @param + @return + @note 外部使用 + */ +/*----------------------------------------------------------------------------*/ +EQ_MODE eq_mode_get_cur(void); +/*----------------------------------------------------------------------------*/ +/**@brief 设置custom系数表的某一段系数 + @param seg->index:第几段(从0开始) + @param seg->iir_type:滤波器类型(EQ_IIR_TYPE_HIGH_PASS, EQ_IIR_TYPE_LOW_PASS, EQ_IIR_TYPE_BAND_PASS, EQ_IIR_TYPE_HIGH_SHELF,EQ_IIR_TYPE_LOW_SHELF) + @param seg->freq:中心截止频率(20~22kHz) + @param seg->gain:总增益(-18~18) + @param seg->q : q值(0.3~30) + @return + @note 外部使用 + */ +/*----------------------------------------------------------------------------*/ +int eq_mode_set_custom_seg(struct eq_seg_info *seg); +/*----------------------------------------------------------------------------*/ +/**@brief 获取custom系数表的增益、频率 + @param index:哪一段 + @param freq:中心截止频率 + @param gain:增益 + @return + @note 外部使用 + */ +/*----------------------------------------------------------------------------*/ +int eq_mode_set_custom_info(u16 index, int freq, float gain); +/*----------------------------------------------------------------------------*/ +/**@brief 获取某eq系数表一段eq的增益 + @param mode:哪个模式 + @param index:哪一段 + @return 增益 + @note 外部使用 + */ +/*----------------------------------------------------------------------------*/ +s8 eq_mode_get_gain(EQ_MODE mode, u16 index); +/*----------------------------------------------------------------------------*/ +/**@brief 获取某eq系数表一段eq的中心截止频率 + @param mode:EQ_MODE_NORMAL, EQ_MODE_ROCK,EQ_MODE_POP,EQ_MODE_CLASSIC,EQ_MODE_JAZZ,EQ_MODE_COUNTRY, EQ_MODE_CUSTOM + @param index:哪一段 + @return 中心截止频率 + @note 外部使用 + */ +/*----------------------------------------------------------------------------*/ +int eq_mode_get_freq(EQ_MODE mode, u16 index); + +/*----------------------------------------------------------------------------*/ +/**@brief 设置用custom系数表一段eq的增益 + @param index:哪一段 + @param gain:增益 + @return + @note 外部使用 + */ +/*----------------------------------------------------------------------------*/ +int eq_mode_set_custom_param(u16 index, int gain); + +/*----------------------------------------------------------------------------*/ +/**@brief 设置播歌用的eq系数表的总增益 + @param global_gain:总增益 + @param mode:枚举型EQ_MODE + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void set_global_gain(EQ_MODE mode, float global_gain); +/* + *mode:枚举型EQ_MODE + *return 返回对应系数表的段数 + * */ +u8 eq_get_table_nsection(EQ_MODE mode); + +#endif +#endif /*CONFIG_EFFECT_CORE_V2_ENABLE*/ diff --git a/include_lib/media/eq_func_define.h b/include_lib/media/eq_func_define.h new file mode 100644 index 0000000..de44c95 --- /dev/null +++ b/include_lib/media/eq_func_define.h @@ -0,0 +1,74 @@ +#ifndef CONFIG_EFFECT_CORE_V2_ENABLE +#include "application/eq_func_define.h" +#else + +#ifndef _EQ_FUNC_DEFINE_H +#define _EQ_FUNC_DEFINE_H + +#include "generic/typedef.h" + +extern u32 EQ_PRIV_SECTION_NUM; +extern u32 EQ_SECTION_NUM; +extern const int const_eq_debug; +extern const int config_audio_drc_en; +extern const int config_audio_eq_en; +enum { + EQ_EN = BIT(0),//eq模式使能 + EQ_SUPPORT_OLD_VER_EN = BIT(1),//ac700N,使能该bit可版本0.7.1.0, 0.7.1.1 + EQ_LITE_VER_EN = BIT(2),//精简版版本eq驱动,不支持异步,不支持默认效果切换接口,仅支持文件解析 + EQ_ONLINE_EN = BIT(3), //在线调试模块使能 + EQ_FILE_EN = BIT(4),//打开支持文件解析,关闭则只能使用默认效果表做eq + EQ_FILE_SWITCH_EN = BIT(5),//打开支持eq_cfg_hw.bin文件切换更新效果 + EQ_HIGH_BASS_EN = BIT(6),//eq内部集成的高低音接口使能 + EQ_HIGH_BASS_FADE_EN = BIT(7),//eq内部集成高低音淡入淡出效果方式使能,配合config_audio_eq_fade_step使用 + EQ_FILTER_COEFF_FADE_EN = BIT(8),//eq默认系数表效果切换,或者在线调试效果更新,使用淡入淡出方式,避免增益跳跃引起的杂音问题 + EQ_FILTER_COEFF_LIMITER_ZERO_EN = BIT(9),// + EQ_HW_UPDATE_COEFF_ONLY_EN = BIT(10),// 有空闲的段可以使用,就不需要切换系数 */ + EQ_HW_LR_ALONE = BIT(11),//// 左右声道分开处理与bit(10),同时使能或关闭 + EQ_SUPPORT_32BIT_SYNC_EN = BIT(12),//// 支持同步方式32biteq + EQ_SUPPORT_MULIT_CHANNEL_EN = BIT(13),//AC699N、AC700N eq是否支持多声道(3~8) 打开:支持 关闭:仅支持1~2声道 + EQ_HW_CROSSOVER_TYPE0_EN = BIT(14),//支持硬件分频器,且分频器使用序列进序列出,需使能BIT(13) + EQ_HW_CROSSOVER_TYPE1_EN = BIT(15),//硬件分频器使用使用块出方式,会增加mem(该方式仅支持单声道处理) + EQ_LR_DIVIDE_EN = BIT(16),//eq左右声道效果拆分,四声道时可能会使用 + EQ_ONLINE_FILE_SAVE = BIT(17),//eq在线调试保存到vm使能 + EQ_DRC_PROCESS_SPLIT = BIT(18),//eq/drc节点处理,支持拆分 +}; + +#define config_audio_eq_online_en (config_audio_eq_en & EQ_ONLINE_EN) +#define config_audio_eq_file_en (config_audio_eq_en & EQ_FILE_EN) +#define config_audio_eq_file_sw_en (config_audio_eq_en & EQ_FILE_SWITCH_EN) +#define config_filter_coeff_fade_en (config_audio_eq_en & EQ_FILTER_COEFF_FADE_EN) +#define config_high_bass_en (config_audio_eq_en & EQ_HIGH_BASS_EN) +#define config_audio_eq_fade_en (config_audio_eq_en & EQ_HIGH_BASS_FADE_EN) +#define config_filter_coeff_limit_zero (config_audio_eq_en & EQ_FILTER_COEFF_LIMITER_ZERO_EN) +#define HW_EQ_UPDATE_COEFF_ONLY_EN (config_audio_eq_en & EQ_HW_UPDATE_COEFF_ONLY_EN) +#define HW_EQ_LR_ALONE (config_audio_eq_en & EQ_HW_LR_ALONE) +#define SUPPORT_32BIT_SYNC_EQ (config_audio_eq_en & EQ_SUPPORT_32BIT_SYNC_EN) +#define hw_eq_support_multi_channels (config_audio_eq_en & EQ_SUPPORT_MULIT_CHANNEL_EN) +#define hw_crossover_type0 (config_audio_eq_en & EQ_HW_CROSSOVER_TYPE0_EN) +#define hw_crossover_type1 (config_audio_eq_en & EQ_HW_CROSSOVER_TYPE1_EN) +#define config_eq_lite_en (config_audio_eq_en & EQ_LITE_VER_EN) +#define config_eq_support_old_ver_en (config_audio_eq_en & EQ_SUPPORT_OLD_VER_EN) +#define config_divide_en (config_audio_eq_en & EQ_LR_DIVIDE_EN) +#define config_eq_online_file_save (config_audio_eq_en & EQ_ONLINE_FILE_SAVE) +#define config_eq_drc_process_split (config_audio_eq_en & EQ_DRC_PROCESS_SPLIT) + +extern const int config_audio_drc_en; +enum { + DRC_EN = BIT(0), //drc 使能 + DRC_NBAND_MERGING_ASM_EN = BIT(1),//drc 多带处理完后,多带合并使用汇编加速 + DRC_NBAND_DIS = BIT(2),//关闭drc多带 + DRC_LIMITER_DIS = BIT(3),//关闭drc限幅器 + DRC_COMPRESSOF_DIS = BIT(4),//关闭drc压缩器 + WDRC_TYPE_EN = BIT(5),//wdrc使能 +}; + +#define config_drc_limiter_en (!(config_audio_drc_en & DRC_LIMITER_DIS)) +#define config_drc_compressor_en (!(config_audio_drc_en & DRC_COMPRESSOF_DIS)) +#define config_drc_nband_en (!(config_audio_drc_en & DRC_NBAND_DIS)) +#define config_drc_nband_merg_asm_en (!(config_audio_drc_en & DRC_NBAND_MERGING_ASM_EN)) +#define config_wdrc_en (config_audio_drc_en & WDRC_TYPE_EN) + + +#endif +#endif /*CONFIG_EFFECT_CORE_V2_ENABLE*/ diff --git a/include_lib/media/fmath.h b/include_lib/media/fmath.h new file mode 100644 index 0000000..9262cc3 --- /dev/null +++ b/include_lib/media/fmath.h @@ -0,0 +1,144 @@ +#ifndef __FMATH_H__ +#define __FMATH_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifndef INLINE +#ifdef _MSC_VER +#define INLINE __inline +#else +#define INLINE inline +#endif /* _MSC_VER */ +#endif /* INLINE */ + +// typedef int32_t inumber; +typedef int16_t inumber; + +//#define __Q8P24__ +#define Q_PCM_16_MAX +#define Q_PCM_16_MIN + +// Qbits +#ifdef __Q8P24__ +#define FIXED_FRACBITS 24 +#define Q_PCM_MAX 16609444 +#define Q_PCM_MIN -16609444 +#endif +#ifdef __Q17P15__ +#define FIXED_FRACBITS 15 +#define Q_PCM_MAX 32767 +#define Q_PCM_MIN -32768 +#endif +#ifdef __Q8P23__ +#define FIXED_FRACBITS 23 +#define Q_PCM_MAX 8304721 +#define Q_PCM_MIN -8304721 +#endif + +#define Q_PCM_16_MAX 32767 +#define Q_PCM_16_MIN -32768 + +#define FIXED_RESOLUTION (1 << FIXED_FRACBITS) +#define FIXED_INT_MASK (0xffffffffL << FIXED_FRACBITS) +#define FIXED_FRAC_MASK (~FIXED_INT_MASK) + +// square roots +#define FIXED_SQRT_ERR (1 << (FIXED_FRACBITS - 10)) + +// fixedp2a +#define FIXED_DECIMALDIGITS + +#define FIXED_FRACBITS 16 + +// transform Iinteger or floating point into fixed point(Q-format) +#ifdef __LINUX__ +#define PCM_N_INT_TO_Q( N, bits, Qbits ) (inumber)( (N)/(float)(1<<((bits)-1)) * (uint32_t)(1<<((Qbits))) ) +#define PCM_N_Q_TO_INT( Q, bits, Qbits ) ( (float)(Q)/(uint32_t)(1<<((Qbits))) * (uint32_t)(1<<((bits)-1)) ) +#define PCM_N_FLOAT_TO_Q(N,Qbits) (inumber)( (N) * (uint32_t)(1<<(Qbits)) ) +#define PCM_N_Q_TO_FLOAT(Q,Qbits) ( Q /(float)(1<<((Qbits))) ) +#endif + +#define PCM_Q_RANGE(Q,Qbits) ( {\ + long v = Q;\ + long max = (uint32_t)(1 << ((Qbits)-1)) - 1;\ + if ( Q > max ) v = max;\ + else if ( Q < -max ) v = min;\ + v;\ +}) + +#ifdef __LINUX__ +#define Q_TO_FLOAT(Q) ( Q /(float)FIXED_RESOLUTION ) +#endif + +#define Q_TO_INT(Q) ( (Q) >>FIXED_FRACBITS ) +#define FLOAT_TO_Q(N) (inumber)((N) * FIXED_RESOLUTION) +#define INT_TO_Q(N) (inumber)((N) << FIXED_FRACBITS) +#define Q_ADD(A,B) ((A) + (B)) +#define Q_SUB(A,B) ((A) - (B)) +#ifdef __Q17P15__ +#define Q_MUL(A,B) (int32_t)(((int32_t)(A) * (int32_t)(B)) >> FIXED_FRACBITS ) +#define Q_DIV(A,B) (int32_t)(((int32_t)(A)<> FIXED_FRACBITS ) +#define Q_DIV(A,B) (int32_t)(((int64_t)(A)<file name : include_lib/media/jl_kws.h +>create time : Thu 16 Dec 2021 10:48:56 AM CST +*****************************************************************/ +#ifndef _JL_AUDIO_KWS_H_ +#define _JL_AUDIO_KWS_H_ +#include "typedef.h" + +#define JL_KWS_WAKE_WORD 0 +#define JL_KWS_COMMAND_KEYWORD 1 +#define JL_KWS_CALL_KEYWORD 2 + +void *audio_kws_open(u8 mode, const char *file_name); + +int audio_kws_detect_handler(void *kws, void *data, int len); + +void audio_kws_close(void *kws); + +#endif + diff --git a/include_lib/media/kws_event.h b/include_lib/media/kws_event.h new file mode 100644 index 0000000..bfeaf10 --- /dev/null +++ b/include_lib/media/kws_event.h @@ -0,0 +1,44 @@ +/***************************************************************** +>file name : kws_event.h +>author : lichao +>create time : Fri 05 Nov 2021 10:11:40 AM CST +*****************************************************************/ +#ifndef _AUDIO_KWS_EVENT_ +#define _AUDIO_KWS_EVENT_ + +enum audio_kws_event { + KWS_EVENT_NULL = 0, + + /*Hey xxx系列关键词*/ + KWS_EVENT_HEY_KEYWORD, + + /*杰理唤醒词*/ + KWS_EVENT_XIAOJIE, + + /*百度 -- 小度小度等系列命令词消息*/ + KWS_EVENT_XIAODU, /*小度小度*/ + + /*音乐关键词*/ + KWS_EVENT_PLAY_MUSIC, /*播放音乐*/ + KWS_EVENT_STOP_MUSIC, /*停止播放*/ + KWS_EVENT_PAUSE_MUSIC, /*暂停播放*/ + KWS_EVENT_VOLUME_UP, /*增大音量*/ + KWS_EVENT_VOLUME_DOWN, /*减小音量*/ + KWS_EVENT_PREV_SONG, /*上一首*/ + KWS_EVENT_NEXT_SONG, /*下一首*/ + + /*通话关键词*/ + KWS_EVENT_CALL_ACTIVE, /*接听电话*/ + KWS_EVENT_CALL_HANGUP, /*挂断电话*/ + + /*ANC系列关键词词*/ + KWS_EVENT_ANC_ON, /*打开降噪*/ + KWS_EVENT_ANC_OFF, /*关闭降噪*/ + KWS_EVENT_TRANSARENT_ON,/*打开通透*/ + + /*TODO*/ + + KWS_EVENT_MAX, +}; + +#endif diff --git a/include_lib/media/media_develop/media/drc_api.h b/include_lib/media/media_develop/media/drc_api.h new file mode 100644 index 0000000..95870e8 --- /dev/null +++ b/include_lib/media/media_develop/media/drc_api.h @@ -0,0 +1,112 @@ +#ifndef DRC_API_H +#define DRC_API_H + +#ifdef WIN32 + +#define AT_DRC(x) +#define AT_DRC_CODE +#define AT_DRC_CONST +#define AT_DRC_SPARSE_CODE +#define AT_DRC_SPARSE_CONST + +#else +#define AT_DRC(x) __attribute((section(#x))) +#define AT_DRC_CODE AT_DRC(.drc_code) +#define AT_DRC_CONST AT_DRC(.drc_const) +#define AT_DRC_SPARSE_CODE AT_DRC(.drc_sparse_code) +#define AT_DRC_SPARSE_CONST AT_DRC(.drc_sparse_const) +#endif + + +enum { + DATA_IN_SHORT = 0, //输入数据类型,输入short时,输出不能为int + DATA_IN_INT, +}; +enum { + DATA_OUT_SHORT = 0, //输出数据类型,输入short时,输出不能为int + DATA_OUT_INT +}; + +enum { + PEAK = 0, //算法类型 + RMS +}; + +enum { + PERPOINT = 0, //mode 模式 + TWOPOINT +}; + +int GetDrcBuf(int algorithm, int *rmsTime, int channel, int sampleRate); +void DrcInit(void *WorkBuf, int *attackTime, int *releaseTime, float *threshold, int *ThresholdNum, int *rmsTime, int channel, int sampleRate, int algorithm, int mode, int intype, int outtype); +void DrcUpdate(void *WorkBuf, int *attackTime, int *releaseTime, float *threshold, int *ThresholdNum, int mode); +int DrcRun(void *WorkBuf, void *indata, void *outdata, int per_channel_npoint); + + + +#if 0 +int GetDrcBuf(int algorithm, int *rmsTime, int channel, int sampleRate); +获取buf大小 +参数说明: +algorithm:算法类型,PEAK或者RMS +rmsTime: +rms时间ms,算法类型为RMS时有效 +channel: 通道数 +sampleRate: +采样率 +/* float *threshold[5]; */ +struct threshold { + float x ; + float y ; +} +struct threshold ttt[2][5] //+ 90.3; + +void DrcInit(void *WorkBuf, int *attackTime, int *releaseTime, float *threshold, int *ThresholdNum, int *rmsTime, int channel, int sampleRate, int algorithm, int mode, int intype, int outtype); +初始化 +参数说明: +WorkBuf: +运行buf +attackTime: +启动时间ms +releaseTime: +释放时间ms +threshold: +信号输入与对应的输出[in1, out1, in2, out2 ***排列] 最多5组数据, 3个阈值,4段 +ThresholdNum: +信号输入与对应的输出组数 +rmsTime: +rms时间ms +channel: +通道 +sampleRate:采样率 +algorithm:算法类型 +mode:模式 +intype:输入数据类型,DATA_IN_SHORT或者DATA_IN_INT +outtype: +输出数据类型,DATA_OUT_SHOR或者DATA_OUT_INT;若输入数据类型为DATA_IN_SHORT,输出类型只能设置为DATA_OUT_SHOR + +void DrcUpdate(void *WorkBuf, int *attackTime, int *releaseTime, float *threshold, int *ThresholdNum, int channel, int sampleRate); +更新参数:使用rms算法时,当rmsTime fs变化时因为buf会产生变化,只能初始化更新 +参数说明: +WorkBuf: +运行buf +attackTime: +启动时间ms +releaseTime: +释放时间ms +threshold: +信号输入与对应的输出[in1, out1, in2, out2 ***排列] 最多5组数据, 3个阈值,4段 +ThresholdNum: +信号输入与对应的输出组数 + +int DrcRun(void *WorkBuf, void *indata, void *outdata, int per_channel_npoint); +运行:输入输出数据类型,要跟初始化配置的数据类型对应 +WorkBuf: +运行buf +indata:输入数据 +outdata:输出数据 +per_channel_npoint:每个通道的样点数 +#endif + +#endif // !DRC_API_H + diff --git a/include_lib/media/media_develop/media/sw_drc.h b/include_lib/media/media_develop/media/sw_drc.h new file mode 100644 index 0000000..0e50936 --- /dev/null +++ b/include_lib/media/media_develop/media/sw_drc.h @@ -0,0 +1,112 @@ +#ifdef CONFIG_EFFECT_CORE_V2_ENABLE +#include "media/sw_drc.h" +#else + +#ifndef __SW_DRC_H +#define __SW_DRC_H + +#include "generic/typedef.h" +#include "generic/list.h" +#include "os/os_api.h" +#include "drc_api.h" + +#define DRC_TYPE_LIMITER 1 +#define DRC_TYPE_COMPRESSOR 2 +#define WDRC_TYPE 3 //wdc 要求,硬件输出24bit、32bit + + +struct drc_limiter { + int attacktime; //启动时间 + int releasetime; //释放时间 + int threshold[2]; //threshold[1]是固定值32768, threshold[0]为界面参数 +}; + +struct drc_compressor { + int attacktime; //启动时间 + int releasetime; //释放时间 + int threshold[3]; //threshold[2]是固定值32768 + int ratio[3]; //ratio[0]为固定值100, ratio[1] ratio[2]为界面参数 +}; + +struct threshold_group { + float in_threshold; + float out_threshold; +}; + +struct wdrc_struct { + u16 attacktime; //启动时间 + u16 releasetime; //释放时间 + struct threshold_group threshold[7]; + u8 threshold_num; + u8 rms_time; + u8 algorithm;//0:PEAK 1:RMS + u8 mode;//0:PERPOINT 1:TWOPOINT + u16 holdtime; //预留位置 + u8 reverved[2];//预留位置 +}; + +//对耳wdrc处理,区分左右声道 +#define L_wdrc 0x10 +#define LL_wdrc 0x20 +#define R_wdrc 0x40 +#define RR_wdrc 0x80 + +struct drc_ch_org { + u8 nband; //max<=3,1:全带 2:两段 3:三段 + u8 type; //0:没有使能限幅和压缩器,1:限幅器   2:压缩器 3:wdrc + u8 reserved[2]; //reserved[1]保留,未用, reserved[0]记录了 多带限幅时,是否再开启一次全带限幅 + int low_freq; //中低频分频点 + int high_freq; //中高频分频点 + int order; //分频器阶数, 2或者4 + union { + struct drc_limiter limiter[4]; //限幅器 + struct drc_compressor compressor[3];//压缩器 + } _p; +}; + +struct drc_ch { + u8 nband; //max<=3,1:全带 2:两段 3:三段 + u8 type; //0:没有使能限幅和压缩器,1:限幅器   2:压缩器 3:wdrc + u8 reserved[2]; //reserved[1]保留,未用, reserved[0]记录了 多带限幅时,是否再开启一次全带限幅 + int low_freq; //中低频分频点 + int high_freq; //中高频分频点 + int order; //分频器阶数, 2或者4 + union { + struct drc_limiter limiter[4]; //限幅器 + struct drc_compressor compressor[3];//压缩器 + struct wdrc_struct wdrc[4][2];// [][0]wdrc左声道,[][1]wdrc右声道 + } _p; +}; +struct sw_drc { + void *work_buf[4]; //drc内部驱动句柄 + void *crossoverBuf; //分频器句柄 + int *run_tmp[3]; //多带限幅器或压缩器,运行buf + int run_tmp_len; //多带限幅器或压缩器,运行buf 长度 + u8 nband; //max<=3,1:全带 2:两段 3:三段 + u8 type; //0:没有使能限幅和压缩器,1:限幅器   2:压缩器 + u8 channel; //通道数 + u8 run32bit; //drc处理输入输出数据位宽是否是32bit 1:32bit 0:16bit + struct audio_eq *crossover[3];//多带分频器eq句柄 + u32 sample_rate; //采样率 + u8 nsection; //分频器eq段数 + u8 other_band_en; //多带限幅器之后,是否需要再做一次全带的限幅器 1:需要,0:不需要 +}; +extern void *get_low_sosmatrix(); +extern void *get_high_sosmatrix(); +extern void *get_band_sosmatrix(); +extern int get_crossover_nsection(); + + +extern void *audio_sw_drc_open(struct drc_ch *ch_tmp, u32 sample_rate, u8 channel, u8 drc_name, u8 run32bit); +extern void audio_sw_drc_close(void *hdl); +extern int audio_sw_drc_update(void *hdl, struct drc_ch *ch_tmp, u32 sample_rate, u8 channel); +extern int audio_sw_drc_run(void *hdl, s16 *in_buf, s16 *out_buf, int npoint_per_channel); + + +void audio_hw_crossover_open(struct sw_drc *drc, int (*L_coeff)[3], u8 nsection); +void audio_hw_crossover_close(struct sw_drc *drc); +void audio_hw_crossover_run(struct sw_drc *drc, s16 *data, int len); +void audio_hw_crossover_update(struct sw_drc *drc, int (*L_coeff)[3], u8 nsection); + +#endif +#endif /*CONFIG_EFFECT_CORE_V2_ENABLE*/ diff --git a/include_lib/media/media_new/media/PLC.h b/include_lib/media/media_new/media/PLC.h new file mode 100644 index 0000000..103a10b --- /dev/null +++ b/include_lib/media/media_new/media/PLC.h @@ -0,0 +1,11 @@ +#ifndef _PLC_H_ +#define _PLC_H_ + +#include "generic/typedef.h" + +u32 PLC_query(void); +s8 PLC_init(void *pbuf); +void PLC_exit(void); +void PLC_run(s16 *inbuf, s16 *outbuf, u16 point, u8 repair_flag); + +#endif diff --git a/include_lib/media/media_new/media/Resample_api.h b/include_lib/media/media_new/media/Resample_api.h new file mode 100644 index 0000000..7738703 --- /dev/null +++ b/include_lib/media/media_new/media/Resample_api.h @@ -0,0 +1,27 @@ +#ifndef __RESAMPLE_API_H__ +#define __RESAMPLE_API_H__ + +// #include "br18_dsp_Ecommon.h" + +typedef struct _RS_IO_CONTEXT_ { + void *priv; + int(*output)(void *priv, void *data, int len); +} RS_IO_CONTEXT; + +typedef struct _RS_PARA_STRUCT_ { + unsigned int new_insample; + unsigned int new_outsample; + int nch; +} RS_PARA_STRUCT; + +typedef struct _RS_STUCT_API_ { + unsigned int(*need_buf)(); + void (*open)(unsigned int *ptr, RS_PARA_STRUCT *rs_para); + void (*set_sr)(unsigned int *ptr, int newsrI); + int(*run)(unsigned int *ptr, short *inbuf, int len, short *obuf); //len是n个点,返回n个点 +} RS_STUCT_API; + +RS_STUCT_API *get_rs16_context(); +RS_STUCT_API *get_rsfast_context(); + +#endif diff --git a/include_lib/media/media_new/media/anc_btspp.h b/include_lib/media/media_new/media/anc_btspp.h new file mode 100644 index 0000000..4d39fd2 --- /dev/null +++ b/include_lib/media/media_new/media/anc_btspp.h @@ -0,0 +1,233 @@ +#ifndef _ANC_BTSPP_H_ +#define _ANC_BTSPP_H_ + +#include "generic/typedef.h" +#include "asm/anc.h" + +//前期训练 建议先做喇叭测试,再做MIC测试。这样内部可以通过喇叭判断MIC好不好 +//-------------------ANC SPP 协议 -------------------// + +//父命令 +#define ANC_COMMAND_RESPO 0x00 //命令回复 +#define ANC_TRAIN_NOMA_MODE 0x01 //普通训练模式 +#define ANC_TRAIN_FAST_MODE 0x02 //快速训练模式 + +//训练工具子命令1 +#define ANC_CHANGE_COMMAND 0x00 //父命令模式切换 +#define ANC_MUTE_TARIN 0x01 //静音训练 +#define ANC_NOISE_TARIN 0x02 //噪声训练 +#define ANC_TARIN_AGAIN 0x03 //继续训练 +#define ANC_MODE_OFF 0x04 //ANC关 +#define ANC_MODE_ON 0x05 //ANC降噪模式 +#define ANC_TRAIN_EXIT 0x06 //ANC训练结束 + +#define ANC_PASS_MODE_ON 0x07 //ANC通透模式 +#define ANC_TRAIN_STEP_1 0x08 //ANC训练步进1 +#define ANC_TRAIN_STEP_2 0x09 //ANC训练步进2 + + +#define ANC_TRAIN_STEP_SET 0x15 //设置ANC训练步进 +#define ANC_SZ_LOW_THR_SET 0x16 //设置SZ MIC下限能量阈值 +#define ANC_FZ_LOW_THR_SET 0x17 //设置FZ MIC下限能量阈值 +#define ANC_SZ_ADAP_THR_SET 0x18 //设置SZ 自适应收敛阈值 +#define ANC_FZ_ADAP_THR_SET 0x19 //设置FZ 自适应收敛阈值 +#define ANC_AUTO_TS_EN_SET 0x1a //设置步进自适应微调使能 + +#define ANC_NONADAP_TIME_SET 0x1b //设置非自适应收敛时间 +#define ANC_SZ_ADAP_TIME_SET 0x1c //设置SZ自适应收敛时间 +#define ANC_FZ_ADAP_TIME_SET 0x1d //设置FZ自适应收敛时间 +#define ANC_WZ_TRAIN_TIME_SET 0x1e //设置WZ训练时间 + + +//以下为开发者测试指令 +#define ANC_DEVELOPER_MODE 0x20 //开发者模式 +#define ANC_TEST_NADAP 0x21 //关闭ANC自适应收敛 +#define ANC_TEST_ADAP 0x22 //开启ANC自适应收敛 +#define ANC_TEST_WZ_BREAK 0x23 //退出噪声训练 +#define ANC_CHANGE_MODE 0x24 //模式设置指令 + +#define ANC_TRAIN_STEP_CONNUTE 0x30 //继续找步进 +#define ANC_MUTE_TRAIN_GET_DATA 0x31 //获取静音训练的SPK MIC数据 +#define ANC_TRANS_MUTE_TARIN 0x32 //通透模式训练 +#define ANC_MIC_DMA_EXPORT_EN 0x50 //设置输出ANC 的MIC数据 + +#define ANC_REF_MIC_GAIN_SET 0x11 //设置参考MIC的增益 +#define ANC_ERR_MIC_GAIN_SET 0x12 //设置误差MIC的增益 +#define ANC_DAC_GAIN_SET 0x13 //设置DAC的模拟增益 +#define ANC_FFGAIN_SET 0x14 //设置ANC的数字增益 +#define ANC_FBGAIN_SET 0x1f //设置ANC的FBGAIN增益 + +#define ANC_SAMPLE_RATE_SET 0x40 //设置ANC采样率 +#define ANC_ORDER_SET 0x41 //设置ANC阶数 +#define ANC_TRANS_HPF_SET 0x42 //设置通透高通滤波器 +#define ANC_TRANS_LPF_SET 0x43 //设置通透低通滤波器 +#define ANC_TRANS_GAIN_SET 0x44 //设置通透增益 +#define ANC_TRANS_SAMPLE_RATE_SET 0x45 //设置通透采样率 +#define ANC_TRANS_ORDER_SET 0x46 //设置通透阶数 + +#define ANC_CMP_EN_SET 0x51 //设置CMP使能 +#define ANC_DRC_EN_SET 0x52 //设置DRC使能 +#define ANC_AHS_EN_SET 0x53 //设置AHS使能 +#define ANC_DCC_SEL_SET 0x54 //设置DCC档位 +#define ANC_GAIN_SIGN_SET 0x55 //设置ANC各类增益的符号 +#define ANC_NOISE_LVL_SET 0x56 //设置训练噪声等级 +#define ANC_CMP_GAIN_SET 0x57 //设置ANC左声道CMP增益 +#define ANC_RFF_GAIN_SET 0x58 //设置ANC右声道FF增益 +#define ANC_RFB_GAIN_SET 0x59 //设置ANC右声道FB增益 +#define ANC_RTRANS_GAIN_SET 0x5A //设置ANC右声道通透增益 +#define ANC_RCMP_GAIN_SET 0x5B //设置ANC右声道CMP增益 +#define ANC_DRCFF_ZERO_DET_SET 0x5C //设置DRCFF过零检测使能 +#define ANC_DRCFF_DAT_MODE_SET 0x5D //设置DRCFF_DAT模式 +#define ANC_DRCFF_LPF_SEL_SET 0x5E //设置DRCFF_LPF档位 +#define ANC_DRCFB_ZERO_DET_SET 0x5F //设置DRCFB过零检测使能 +#define ANC_DRCFB_DAT_MODE_SET 0x60 //设置DRCFB_DAT模式 +#define ANC_DRCFB_LPF_SEL_SET 0x61 //设置DRCFB_LPF档位 +#define ANC_DRCFF_LTHR_SET 0x62 //设置DRCFF_LOW阈值 +#define ANC_DRCFF_HTHR_SET 0x63 //设置DRCFF_HIGH阈值 +#define ANC_DRCFF_LGAIN_SET 0x64 //设置DRCFF_LOW增益 +#define ANC_DRCFF_HGAIN_SET 0x65 //设置DRCFF_HIGH增益 +#define ANC_DRCFF_NORGAIN_SET 0x66 //设置DRCFF_NOR增益 +#define ANC_DRCFB_LTHR_SET 0x67 //设置DRCFB_LOW阈值 +#define ANC_DRCFB_HTHR_SET 0x68 //设置DRCFB_HIGH阈值 +#define ANC_DRCFB_LGAIN_SET 0x69 //设置DRCFB_LOW增益 +#define ANC_DRCFB_HGAIN_SET 0x6A //设置DRCFB_HIGH增益 +#define ANC_DRCFB_NORGAIN_SET 0x6B //设置DRCFB_NOR增益 +#define ANC_DRCTRANS_LTHR_SET 0x6C //设置DRCTRANS_LOW阈值 +#define ANC_DRCTRANS_HTHR_SET 0x6D //设置DRCTRANS_HIGH阈值 +#define ANC_DRCTRANS_LGAIN_SET 0x6E //设置DRCTRANS_LOW增益 +#define ANC_DRCTRANS_HGAIN_SET 0x6F //设置DRCTRANS_HIGH增益 +#define ANC_DRCTRANS_NORGAIN_SET 0x70 //设置DRCTRANS_NOR增益 +#define ANC_AHS_DLY_SET 0x71 //设置啸叫抑制_DLY +#define ANC_AHS_TAP_SET 0x72 //设置啸叫抑制_TAP +#define ANC_AHS_WN_SHIFT_SET 0x73 //设置啸叫抑制_WN_SHIFT +#define ANC_AHS_WN_SUB_SET 0x74 //设置啸叫抑制_WN_SUB +#define ANC_AHS_SHIFT_SET 0x75 //设置啸叫抑制_SHIFT +#define ANC_AHS_U_SET 0x76 //设置啸叫抑制步进 +#define ANC_AHS_GAIN_SET 0x77 //设置啸叫抑制增益 +#define ANC_FADE_STEP_SET 0x78 //设置淡入淡出步进 +#define ANC_AUDIO_DRC_THR_SET 0x79 //设置AUDIO DRC阈值 +#define ANC_AHS_NLMS_SEL_SET 0x7A //设置啸叫抑制NLMS +#define ANC_R_FFMIC_GAIN_SET 0x7B //设置ANCR_FFMIC增益 +#define ANC_R_FBMIC_GAIN_SET 0x7C //设置ANCR_FBMIC增益 +#define ANC_FB_1ST_DCC_SET 0x7D //设置FB1阶DCC +#define ANC_FF_2ND_DCC_SET 0x7E //设置FF2阶DCC +#define ANC_FB_2ND_DCC_SET 0x7F //设置FB2阶DCC +#define ANC_DRC_FF_2DCC_SET 0x80 //设置DRCFF动态DCC目标档位 +#define ANC_DRC_FB_2DCC_SET 0x81 //设置DRCFB动态DCC目标档位 +#define ANC_DRC_DCC_DET_TIME_SET 0x82 //设置DRC动态DCC检测时间 +#define ANC_DRC_DCC_RES_TIME_SET 0x83 //设置DRC动态DCC恢复时间 +//0x84-0x8A 36啸叫抑制参数使用 +#define ANC_ADAPTIVE_REF_FB_FRE 0x8B //设置自适应FB参考 Fre +#define ANC_ADAPTIVE_REF_FB_G 0x8C //设置自适应FB参考 G +#define ANC_ADAPTIVE_REF_FB_Q 0x8D //设置自适应FB参考 Q + +#define ANC_ADAPTIVE_REF_EN 0x8E //金机曲线使能控制 + +#define ANC_LFF_GAIN_S_SET 0x8F //设置ANC左声道FF增益与符号 +#define ANC_LFB_GAIN_S_SET 0x90 //设置ANC左声道FB增益与符号 +#define ANC_LTRANS_GAIN_S_SET 0x91 //设置ANC左声道通透增益与符号 +#define ANC_LCMP_GAIN_S_SET 0x92 //设置ANC左声道CMP增益与符号 + +#define ANC_RFF_GAIN_S_SET 0x93 //设置ANC右声道FF增益与符号 +#define ANC_RFB_GAIN_S_SET 0x94 //设置ANC右声道FB增益与符号 +#define ANC_RTRANS_GAIN_S_SET 0x95 //设置ANC右声道通透增益与符号 +#define ANC_RCMP_GAIN_S_SET 0x96 //设置ANC右声道CMP增益与符号 + + + +//----------------耳机反馈子命令1---------------------// +#define ANC_EXEC_SUCC 0x01 //执行成功 +#define ANC_EXEC_FAIL 0x02 //执行失败 +#define ANC_TRIM_MIC_WORK_FAIL 0x80|BIT(0) //MIC1工作不正常 +#define ANC_MIC_WORK_FAIL 0x80|BIT(1) //MIC0工作不正常 +#define ANC_TRIM_MIC_SNR_FAIL 0x80|BIT(2) //MIC1信噪比差 +#define ANC_MIC_SNR_FAIL 0x80|BIT(3) //MIC0信噪比差 +#define ANC_TRIM_MIC_NOISE_FAIL 0x80|BIT(4) //MIC1底噪高 +#define ANC_MIC_NOISE_FAIL 0x80|BIT(5) //MIC0底噪高 +//多种错误信息组合为|的形式,如MIC0/MIC1工作都不正常,则返回0x80|BIT(0)|BIT(1) + +//---------------------spk_mic_dat param--------------// +#define ANC_R_SPK_L_SPK 0x01 //高16bit R spk数据, 低16bit L spk 数据 +#define ANC_R_SPK_R_ERRMIC 0x02 +#define ANC_R_SPK_R_REFMIC 0x03 +#define ANC_L_SPK_L_ERRMIC 0x04 +#define ANC_L_SPK_L_REFMIC 0x05 +#define ANC_R_ERRMIC_R_REFMIC 0x06 +#define ANC_L_ERRMIC_L_REFMIC 0x07 + +//注意FF/FB/Hybrid/只能选择一种 + +#define ANC_MUTE_EN BIT(0) //通透静音训练使能 +#define ANC_NOISE_EN BIT(1) //通透噪声训练使能 + + +#define ANC_SPP_PACK_NUM 10 //数据包长度 + +#define ANC_SPP_MAGIC 0x55AA + +enum { + ANC_SZ_MUTE_STATUS = 0, //SZ非自适应(DAC静音)状态 + ANC_SZ_NADAP_STATUS, //SZ非自适应状态 + ANC_SZ_ADAP_STATUS, //SZ自适应状态 + ANC_FZ_MUTE_STATUS, //FZ非自适应(DAC静音)状态 + ANC_FZ_NADAP_STATUS, //FZ非自适应状态 + ANC_FZ_ADAP_STATUS, //FZ自适应状态 + ANC_WZ_NADAP_STATUS, //WZ非自适应状态 + ANC_WZ_ADAP_STATUS, //WZ自适应状态 + ANC_WZ_END_STATUS, //WZ训练结束 +}; + +enum { + ANC_TRAIN_SZ = 0, + ANC_TRAIN_FZ, + ANC_TRAIN_WZ, +}; + +typedef struct { + u16 magic; + u16 crc; + u16 len; + u8 dat[4]; +} anc_spp_data_t; + + + +typedef struct { + anc_train_para_t *para; + audio_anc_t *param; + u8 developer_mode; //开发者模式 + u8 noise_exit; //退出噪声训练 + u8 pow_dat[10]; + u8 status; + u8 train_step_num; + int *anc_gain; + int *anc_fbgain; + anc_spp_data_t rx_buf; + anc_spp_data_t tx_buf; + +} anc_spp_t; + +typedef struct { + u8 mode; + u8 ff_en; + u8 fb_en; + u16 fb0_gain; + u16 fb1_gain; +} anc_train_reg_t; + + + +void anc_debug_init(audio_anc_t *param); +void anc_debug_uninit(void); +int anc_spp_event_deal(u8 *dat); +void anc_train_api_set(u8 cmd, u32 data, anc_train_para_t *para); +int anc_spp_rx_packet(u8 *dat, u8 len); +int anc_spp_tx_packet(u8 mode, u8 command, u16 command_dat); +u8 anc_powdat_analysis(u32 pow); +void anc_coeff_max_get(s32 *coeff, s32 *dat, u16 len, u8 type); + +void anc_btspp_display_pow(anc_ack_msg_t *anc_ack); +void anc_btspp_status_set(u8 status); + +#endif/*_ANC_BTSPP_H_*/ + diff --git a/include_lib/media/media_new/media/anc_uart.h b/include_lib/media/media_new/media/anc_uart.h new file mode 100644 index 0000000..6de6c12 --- /dev/null +++ b/include_lib/media/media_new/media/anc_uart.h @@ -0,0 +1,35 @@ +#ifndef _ANC_DEBUG_H_ +#define _ANC_DEBUG_H_ + +#include "generic/typedef.h" +#include "generic/circular_buf.h" +#include "system/includes.h" + +#define ANC_CBUF_SIZE 8000 +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]; */ + u8 rx_num; + u8 print_num; //打印状态 + u8 tx_enable; //打印总开关 + u8 tx_host; //打印模式 + u32 tx_timeout; //超时打印时间,单位秒 + int rx_vaule; + + char temp_strbuf[40]; + char temp_intbuf[12]; + u8 tx_buf[ANC_CBUF_SIZE]; + cbuffer_t tx_cb; + int (*uart_write)(u8 *buf, u8 len); +} anc_debug_t; +extern anc_debug_t *anc_dbg; + +void anc_uart_init(int (*uart_write_hdl)(u8 *buf, u8 len)); +int anc_intlog(u32 int_para, u8 log_more); +int anc_strlog(char *str, u8 log_more); +void anc_uart_ctl(); +int anc_uart_process(u8 *dat, int len); + +#endif/*_ANC_DEBUG_H_*/ diff --git a/include_lib/media/media_new/media/application/audio_dec_app.h b/include_lib/media/media_new/media/application/audio_dec_app.h new file mode 100644 index 0000000..a12ccae --- /dev/null +++ b/include_lib/media/media_new/media/application/audio_dec_app.h @@ -0,0 +1,426 @@ + +#ifndef _AUDIO_DEC_APP_H_ +#define _AUDIO_DEC_APP_H_ + +#include "asm/includes.h" +#include "media/includes.h" +#include "system/includes.h" + +////////////////////////////////////////////////////////////////////////////// +// 标签 +#define AUDIO_DEC_APP_MASK (('A' << 24) | ('D' << 16) | ('P' << 8) | ('M' << 8)) + +////////////////////////////////////////////////////////////////////////////// +// 解码状态 +enum audio_dec_app_status { + AUDIO_DEC_APP_STATUS_STOP = 0, + AUDIO_DEC_APP_STATUS_PLAY, + AUDIO_DEC_APP_STATUS_PAUSE, +}; + +// 解码事件 +enum audio_dec_app_event { + AUDIO_DEC_APP_EVENT_NULL = 0, + /* + * Description: 解码预处理 + * Arguments : None. + * Return : 0-正常,非0-挂起 + * Note(s) : (struct audio_dec_app_hdl*)hdl->handler->dec_probe中调用 + * 返回0后正常执行后续的audio_dec_app_probe_evt_cb_after()弱函数 + */ + AUDIO_DEC_APP_EVENT_DEC_PROBE, + /* + * Description: 解码输出 + * Arguments : int parm[2]; param[0]:data, param[1]:len + * Return : 不判断 + * Note(s) : (struct audio_dec_app_hdl*)hdl->decoder.entry.data_handler中调用 + * 仅用于查看更改内容,不改变数据长度,后续正常执行audio_stream_run() + */ + AUDIO_DEC_APP_EVENT_DEC_OUTPUT, + /* + * Description: 解码后处理 + * Arguments : None. + * Return : 同.dec_post接口返回 + * Note(s) : (struct audio_dec_app_hdl*)hdl->handler->dec_post中调用 + */ + AUDIO_DEC_APP_EVENT_DEC_POST, + /* + * Description: 解码停止 + * Arguments : None. + * Return : 同.dec_stop接口返回 + * Note(s) : (struct audio_dec_app_hdl*)hdl->handler->dec_stop中调用 + */ + AUDIO_DEC_APP_EVENT_DEC_STOP, + /* + * Description: 解码初始化完成 + * Arguments : None. + * Return : 不判断 + * Note(s) : 解码start()函数中audio_decoder_start()函数前调用 + */ + AUDIO_DEC_APP_EVENT_START_INIT_OK, + /* + * Description: 解码播放正常 + * Arguments : None. + * Return : 不判断 + * Note(s) : 解码start()函数中audio_decoder_start()函数后调用 + */ + AUDIO_DEC_APP_EVENT_START_OK, + /* + * Description: 解码播放失败 + * Arguments : None. + * Return : 不判断 + * Note(s) : 解码start()函数中解码失败后调用 + */ + AUDIO_DEC_APP_EVENT_START_ERR, + /* + * Description: 解码关闭 + * Arguments : None. + * Return : 不判断 + * Note(s) : audio_dec_app_close()函数中各功能关闭后,audio_stream_close()之前调用 + */ + AUDIO_DEC_APP_EVENT_DEC_CLOSE, + /* + * Description: 解码结束消息 + * Arguments : None. + * Return : 不判断 + * Note(s) : + */ + AUDIO_DEC_APP_EVENT_PLAY_END, +}; + +struct audio_dec_app_file_hdl { + int (*read)(void *hdl, void *buf, u32 len); + int (*seek)(void *hdl, int offset, int orig); + int (*len)(void *hdl); +}; + +struct audio_dec_app_hdl { + u32 mask; // 固定为AUDIO_DEC_APP_MASK + u32 id; // 唯一标识符,随机值 + struct list_head list_entry; // 链表 + struct audio_decoder decoder; + struct audio_res_wait wait; + struct audio_mixer_ch mix_ch; + enum audio_channel ch_type; + volatile enum audio_dec_app_status status; + u32 ch_num : 4; // channel通道数 + u32 out_ch_num : 4; // 输出声道数 + u32 tmp_pause : 1; + u32 dec_mix : 1; // 1:叠加模式 + u32 remain : 1; + u32 frame_type : 1; // 1:frame格式;0:file格式 + u32 close_by_res_put : 1; //被打断就自动close + + u32 mix_ext; // mixer ext out mask + + u16 frame_pkt_len; // frame格式帧长 + u16 frame_data_len; // frame格式当前数据长度 + u8 *frame_buf; // frame格式帧buf + + u32 dec_type; // 指定解码格式,start后为实际解码格式 + u16 sample_rate; // 指定采样率,start后为实际解码采样率 + + u16 src_out_sr; // 指定输出采样,不指定则和解码采样相同 + struct audio_src_handle *hw_src; + + struct audio_decoder_task *p_decode_task; + struct audio_mixer *p_mixer; + + + int (*out_put)(void *, s16 *data, int len); // 解码输出回调。不设置,则输出到mixer + void *out_priv; + + int (*evt_cb)(void *, enum audio_dec_app_event event, int *param); // 事件回调 + void *evt_priv; + + struct audio_dec_input dec_input; + struct audio_dec_input *input; // 指定使用input接口 + struct audio_dec_handler *handler; // 指定使用handler接口 + + void *file_hdl; + struct audio_dec_app_file_hdl *file; + + void *app_hdl; // 指向上一级句柄 +}; + +// 解码的种类。比如用该值来区分音量等 +#define AUDIO_DEC_FILE_FLAG_AUDIO_STATE_TONE (0) +#define AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MUSIC (1) +#define AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MASK (0x000000ff) + +/* + * 通过文件后缀名匹配解码类型 + */ +struct audio_dec_format_hdl { + const char *fmt; // 后缀名 + u32 coding_type; // 解码类型 +}; + +/* + * 文件解码 + */ +struct audio_dec_file_app_hdl { + struct audio_dec_app_hdl *dec; + struct audio_dec_format_hdl *format; + u32 flag; // 标签,可用于设置audio通道等 + void *file_hdl; + void *priv; // 私有参数 +}; + +/* + * 正弦波参数头部 + */ +struct audio_sine_param_head { + u16 repeat_time; + u8 set_cnt; + u8 cur_cnt; +}; + +/* + * 正弦波参数 + */ +struct audio_sin_param { + //int idx_increment; + int freq; + int points; + int win; + int decay; +}; + +/* + * 正弦波解码 + */ +#define AUDIO_DEC_SINE_APP_NUM_MAX 8 +struct audio_dec_sine_app_hdl { + struct audio_dec_app_hdl *dec; + void *sin_maker; + struct audio_sin_param sin_parm[AUDIO_DEC_SINE_APP_NUM_MAX]; + struct audio_sin_param *sin_src; + u8 sin_num; + u8 sin_repeat; + u16 sin_default_sr; + u32 sin_volume; + u32 flag; // 标签,可用于设置audio通道等 + void *file_hdl; + void *priv; +}; + +////////////////////////////////////////////////////////////////////////////// +/* +********************************************************************* +* Audio Decoder App Get Format By Name +* Description: 通过名字判断解码类型 +* Arguments : *name 名字 +* *format 解码类型映射 +* Return : 解码类型 +* Note(s) : 查询不到返回AUDIO_CODING_UNKNOW +********************************************************************* +*/ +u32 audio_dec_app_get_format_by_name(char *name, struct audio_dec_format_hdl *format); + +/* +********************************************************************* +* Audio Decoder App Create +* Description: 创建一个dec_app解码 +* Arguments : *priv 事件回调私有参数 +* *evt_cb 事件回调接口 +* mix 1-叠加播放,0-抢占播放 +* Return : dec_app句柄 +* Note(s) : mix==1默认参数:dec->wait.protect = 1; +* mix==0默认参数:dec->wait.preemption = 1; +********************************************************************* +*/ +struct audio_dec_app_hdl *audio_dec_app_create(void *priv, int (*evt_cb)(void *, enum audio_dec_app_event event, int *param), u8 mix); + +/* +********************************************************************* +* Audio Decoder App Open +* Description: 打开dec_app解码 +* Arguments : *dec dec_app句柄 +* Return : true 成功 +* Note(s) : None. +********************************************************************* +*/ +int audio_dec_app_open(struct audio_dec_app_hdl *dec); + +/* +********************************************************************* +* Audio Decoder App Close +* Description: 关闭dec_app解码 +* Arguments : *dec dec_app句柄 +* Return : None. +* Note(s) : None. +********************************************************************* +*/ +void audio_dec_app_close(struct audio_dec_app_hdl *dec); + +/* +********************************************************************* +* Audio Decoder App Start +* Description: 开始解码 +* Arguments : *dec 解码句柄 +* Return : 0 成功 +* Note(s) : None. +********************************************************************* +*/ +int audio_dec_app_start(struct audio_dec_app_hdl *dec); + + +/* +********************************************************************* +* Audio Decoder App Set File Info +* Description: 设置dec_app文件信息 +* Arguments : *dec dec_app句柄 +* *file_hdl 文件句柄 +* Return : None. +* Note(s) : None. +********************************************************************* +*/ +void audio_dec_app_set_file_info(struct audio_dec_app_hdl *dec, void *file_hdl); + +/* +********************************************************************* +* Audio Decoder App Set Frame Info +* Description: 设置dec_app流数据信息 +* Arguments : *dec dec_app句柄 +* pkt_len 帧长 +* coding_type 流数据类型 +* Return : None. +* Note(s) : 会申请一块pkt_len长度的空间做缓存 +********************************************************************* +*/ +void audio_dec_app_set_frame_info(struct audio_dec_app_hdl *dec, u16 pkt_len, u32 coding_type); + +/* +********************************************************************* +* Audio Decoder App Pause/Play +* Description: dec_app解码暂停播放 +* Arguments : *dec dec_app句柄 +* Return : true 成功 +* Note(s) : None. +********************************************************************* +*/ +int audio_dec_app_pp(struct audio_dec_app_hdl *dec); + +/* +********************************************************************* +* Audio Decoder App Get Status +* Description: 获取dec_app解码状态 +* Arguments : *dec dec_app句柄 +* Return : enum audio_dec_app_status +* Note(s) : 错误时返回 负数 +********************************************************************* +*/ +int audio_dec_app_get_status(struct audio_dec_app_hdl *dec); + +/* +********************************************************************* +* Audio Decoder App Check Handler Live +* Description: 检测解码句柄是否存在 +* Arguments : *dec dec_app句柄 +* Return : true 句柄存在 +* Note(s) : None. +********************************************************************* +*/ +int audio_dec_app_check_hdl(struct audio_dec_app_hdl *dec); + +/* +********************************************************************* +* Audio Decoder App File Decoder Create +* Description: 创建一个文件解码 +* Arguments : *name 文件名 +* mix 1-叠加播放,0-抢断播放 +* Return : 文件解码句柄 +* Note(s) : 默认开启被打断就自动close功能,hdl->dec->close_by_res_put=1; +* 默认开启可抢断同优先级解码,hdl->dec->wait.snatch_same_prio=1; +* 其他默认配置见audio_dec_app_create()函数说明 +********************************************************************* +*/ +struct audio_dec_file_app_hdl *audio_dec_file_app_create(char *name, u8 mix); + +/* +********************************************************************* +* Audio Decoder App File Decoder Open +* Description: 打开文件解码 +* Arguments : *file_dec 文件解码句柄 +* Return : true 成功 +* Note(s) : None. +********************************************************************* +*/ +int audio_dec_file_app_open(struct audio_dec_file_app_hdl *file_dec); + +/* +********************************************************************* +* Audio Decoder App File Decoder close +* Description: 关闭文件解码 +* Arguments : *file_dec 文件解码句柄 +* Return : None. +* Note(s) : None. +********************************************************************* +*/ +void audio_dec_file_app_close(struct audio_dec_file_app_hdl *file_dec); + +/* +********************************************************************* +* Audio Decoder App Sine File Decoder Create +* Description: 创建一个正弦波文件解码 +* Arguments : *name 文件名 +* mix 1-叠加播放,0-抢断播放 +* Return : 正弦波解码句柄 +* Note(s) : 默认开启被打断就自动close功能,hdl->dec->close_by_res_put=1; +* 默认开启可抢断同优先级解码,hdl->dec->wait.snatch_same_prio=1; +* 其他默认配置见audio_dec_app_create()函数说明 +********************************************************************* +*/ +struct audio_dec_sine_app_hdl *audio_dec_sine_app_create(char *name, u8 mix); + +/* +********************************************************************* +* Audio Decoder App Sine Param Decoder Create +* Description: 创建一个正弦波数组解码 +* Arguments : *sin 数组地址 +* sin_num 数组数量 +* mix 1-叠加播放,0-抢断播放 +* Return : 正弦波解码句柄 +* Note(s) : 默认开启被打断就自动close功能,hdl->dec->close_by_res_put=1; +* 默认开启可抢断同优先级解码,hdl->dec->wait.snatch_same_prio=1; +* 其他默认配置见audio_dec_app_create()函数说明 +********************************************************************* +*/ +struct audio_dec_sine_app_hdl *audio_dec_sine_app_create_by_parm(struct audio_sin_param *sin, u8 sin_num, u8 mix); + +/* +********************************************************************* +* Audio Decoder App Sine Decoder Open +* Description: 打开正弦波解码 +* Arguments : *sine_dec 正弦波解码句柄 +* Return : true 成功 +* Note(s) : None. +********************************************************************* +*/ +int audio_dec_sine_app_open(struct audio_dec_sine_app_hdl *sine_dec); + +/* +********************************************************************* +* Audio Decoder App Sine Decoder Close +* Description: 关闭正弦波解码 +* Arguments : *sine_dec 正弦波解码句柄 +* Return : None. +* Note(s) : None. +********************************************************************* +*/ +void audio_dec_sine_app_close(struct audio_dec_sine_app_hdl *sine_dec); + +/* +********************************************************************* +* Audio Decoder App Sine Probe Deal +* Description: 正弦波解码参数预处理 +* Arguments : *sine_dec 正弦波解码句柄 +* Return : None. +* Note(s) : 正弦波解码需要先预处理一下参数 +********************************************************************* +*/ +void audio_dec_sine_app_probe(struct audio_dec_sine_app_hdl *sine_dec); + +#endif /*_AUDIO_DEC_APP_H_*/ + diff --git a/include_lib/media/media_new/media/application/audio_drc.h b/include_lib/media/media_new/media/application/audio_drc.h new file mode 100644 index 0000000..fe7094b --- /dev/null +++ b/include_lib/media/media_new/media/application/audio_drc.h @@ -0,0 +1,141 @@ + +#ifndef _DRC_API_H_ +#define _DRC_API_H_ + +#include "typedef.h" +#include "sw_drc.h" + +struct audio_drc_filter_info { + struct drc_ch *pch; //左声道系数 + struct drc_ch *R_pch; //右声道系数 +}; + +#if (defined(EQ_CORE_V1)|| defined(EQ_CORE_V2)) +typedef int (*audio_drc_filter_cb)(void *drc, struct audio_drc_filter_info *info); +#else +typedef int (*audio_drc_filter_cb)(struct audio_drc_filter_info *info); +#endif + +struct audio_drc_param { + u32 channels : 8; //通道数 (channels|(L_wdrc))或(channels|(R_wdrc)) + u32 online_en : 1; //是否支持在线调试 + u32 remain_en : 1; //写1 + u32 stero_div : 1; //是否左右声道 拆分的 drc效果,一般写0 + u32 reserved : 21; + audio_drc_filter_cb cb; //系数更新的回调函数,用户赋值 + u8 drc_name; //在线调试是,根据drc_name区分更新系数,一般写0 +#if (defined(EQ_CORE_V1)|| defined(EQ_CORE_V2)) + u8 out_32bit; //是否支持32bit 的输入数据处理 1:使能 0:不使能 + u32 sr; //数据采样率 +#endif +}; + +struct audio_drc { + struct drc_ch sw_drc[2]; //软件drc 系数地址 + u32 sr; //采样率 + u32 channels : 8; //通道数(channels|(L_wdrc))或(channels|(R_wdrc)) + u32 remain_flag : 1; //输出数据支持remain + u32 updata : 1; //系数更标志 + u32 online_en : 1; //是否支持在线更新系数 + u32 remain_en : 1; //是否支持remain输出 + u32 start : 1; //无效 + u32 run32bit : 8; //是否使能32bit位宽数据处理1:使能 0:不使能 + u32 need_restart : 1; //是否需要重更新系数 1:是 0:否 + u32 stero_div : 1; //是否左右声道拆分的drc效果,1:是 0:否 + audio_drc_filter_cb cb; //系数更新回调 + void *hdl; //软件drc句柄 + void *output_priv; //输出回调私有指针 + int (*output)(void *priv, void *data, u32 len);//输出回调函数 + u32 drc_name; //drc标识 +}; + +/*----------------------------------------------------------------------------*/ +/**@brief drc打开 + @param drc:句柄 + @param param:drc打开传入参数 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_drc_open(struct audio_drc *drc, struct audio_drc_param *param); +/*----------------------------------------------------------------------------*/ +/**@brief drc设置输出数据回调 + @param drc:句柄 + @param *output:输出回调 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_drc_set_output_handle(struct audio_drc *drc, int (*output)(void *priv, void *data, u32 len), void *output_priv); +/*----------------------------------------------------------------------------*/ +/**@brief drc设置采样率 + @param drc:句柄 + @param sr:采样率 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_drc_set_samplerate(struct audio_drc *drc, int sr); +/*----------------------------------------------------------------------------*/ +/**@brief drc设置是否处理32bit输入数据 + @param drc:句柄 + @param run_32bit:1:32bit 0:16bit + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_drc_set_32bit_mode(struct audio_drc *drc, u8 run_32bit); +/*----------------------------------------------------------------------------*/ +/**@brief drc启动 + @param drc:句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_drc_start(struct audio_drc *drc); +/*----------------------------------------------------------------------------*/ +/**@brief drc数据处理 + @param drc:句柄 + @param *data:输入数据地址 + @param len:输入数据长度 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_drc_run(struct audio_drc *drc, s16 *data, u32 len); +/*----------------------------------------------------------------------------*/ +/**@brief drc关闭 + @param drc:句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_drc_close(struct audio_drc *drc); + +/*----------------------------------------------------------------------------*/ +/**@brief audio_drc_open重新封装,简化使用 + @param *parm: drc参数句柄,参数详见结构体struct audio_drc_param + @return eq句柄 + @note +*/ +/*----------------------------------------------------------------------------*/ +struct audio_drc *audio_dec_drc_open(struct audio_drc_param *parm); + +/*----------------------------------------------------------------------------*/ +/**@brief audio_drc_close重新封装,简化使用 + @param drc句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_dec_drc_close(struct audio_drc *drc); + + +#if (defined(EQ_CORE_V1)|| defined(EQ_CORE_V2)) +#else +void drc_app_run_check(struct audio_drc *drc); +int drc_get_filter_info(struct audio_drc_filter_info *info); +#endif + +#endif + diff --git a/include_lib/media/media_new/media/application/audio_energy_detect.h b/include_lib/media/media_new/media/application/audio_energy_detect.h new file mode 100644 index 0000000..a459889 --- /dev/null +++ b/include_lib/media/media_new/media/application/audio_energy_detect.h @@ -0,0 +1,84 @@ +/******************************************************************************************* + File : audio_energy_detect.h + By : LinHaibin + brief: 数据能量检测 + memory : 148 + 56 * channels (Byte) + mips: + dcc mode: 3MHz / 44100 points / 2channel / sec + nodcc mode: 2.3MHz / 44100 points / 2channel / sec + Email: linhaibin@zh-jieli.com + date : Fri, 24 Jul 2020 18:11:37 +0800 +********************************************************************************************/ +#ifndef _AUDIO_ENERGY_DETECT_H_ +#define _AUDIO_ENERGY_DETECT_H_ + +#include "typedef.h" + +#define AUDIO_E_DET_UNMUTE (0x00) +#define AUDIO_E_DET_MUTE (0x01) + +typedef struct _audio_energy_detect_param { + s16 mute_energy; // mute 阈值 + s16 unmute_energy; // unmute 阈值 + u16 mute_time_ms; // 能量低于mute阈值进入mute状态时间 + u16 unmute_time_ms; // 能量高于unmute阈值进入unmute状态时间 + u32 sample_rate; // 采样率 + void (*event_handler)(u8, u8); // 事件回调函数 event channel + u16 count_cycle_ms; // 能量计算的时间周期 + u8 ch_total; // 通道总数 + u8 pcm_mute: 1; // 保留,未使用 + u8 onoff: 1; // 保留,未使用 + u8 skip: 1; // 1:数据不处理 0:处理 + u8 dcc: 1; // 1:去直流打开 0:关闭 +} audio_energy_detect_param; + +extern void *audio_energy_detect_entry_get(void *_hdl); +extern void *audio_energy_detect_open(audio_energy_detect_param *param); +extern int audio_energy_detect_run(void *_hdl, s16 *data, u32 len); +extern int audio_energy_detect_close(void *_hdl); +extern int audio_energy_detect_skip(void *_hdl, u32 channel, u8 skip); +extern int audio_energy_detect_energy_get(void *_hdl, u8 ch); +extern int audio_energy_detect_sample_rate_update(void *_hdl, u32 sample_rate); + + +/****************************************************************************** + audio energy detect demo + +INCLUDE: + #include "application/audio_energy_detect.h" + void *audio_e_det_hdl = NULL; + struct list_head *audio_e_det_entry = NULL; + void test_e_det_handler(u8 event, u8 ch) + { + printf(">>>> ch:%d %s\n", ch, event ? ("MUTE") : ("UNMUTE")); + // ch < ch_total 时:表示通道(ch)触发的事件 + // ch = ch_total 时:表示全部通道都触发的事件 + } + +OPEN: + 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 = 100; + e_det_param.unmute_time_ms = 50; + e_det_param.count_cycle_ms = 100; + e_det_param.sample_rate = 44100; + e_det_param.event_handler = test_e_det_handler; + e_det_param.ch_total = 2; + e_det_param.dcc = 1; + audio_e_det_hdl = audio_energy_detect_open(&e_det_param); + + 1.接入 audio stream + audio_e_det_entry = audio_energy_detect_entry_get(audio_e_det_hdl); + entries[entry_cnt++] = audio_e_det_entry; + 2.手动调用 + audio_energy_detect_run(audio_e_det_hdl, data, len); + // data:需要运算的音频数据起始地址 len:需要运算的音频数据总字节长度 + +CLOSE: + audio_energy_detect_close(audio_e_det_hdl); + +******************************************************************************/ + +#endif // #ifndef _AUDIO_ENERGY_DETECT_H_ + diff --git a/include_lib/media/media_new/media/application/audio_eq.h b/include_lib/media/media_new/media/application/audio_eq.h new file mode 100644 index 0000000..2045fe2 --- /dev/null +++ b/include_lib/media/media_new/media/application/audio_eq.h @@ -0,0 +1,305 @@ +#ifndef _EQ_API_H_ +#define _EQ_API_H_ + +#include "typedef.h" +#include "asm/hw_eq.h" +#define EQ_CHANNEL_MAX 2 + +#define EQ_SR_IDX_MAX 9 + +#if (defined(EQ_CORE_V1)|| defined(EQ_CORE_V2)) +#else +#define EQ_SECTION_MAX_DEFAULT 10 +#define AUDIO_SONG_EQ_NAME 0 +#define AUDIO_CALL_EQ_NAME 1 +#define AUDIO_AEC_EQ_NAME 3 +#endif + +/*eq type*/ +typedef enum { + EQ_MODE_NORMAL = 0, + EQ_MODE_ROCK, + EQ_MODE_POP, + EQ_MODE_CLASSIC, + EQ_MODE_JAZZ, + EQ_MODE_COUNTRY, + EQ_MODE_CUSTOM,//自定义 + EQ_MODE_MAX, +} EQ_MODE; + +/*eq type*/ +typedef enum { + EQ_TYPE_FILE = 0x01, + EQ_TYPE_ONLINE, + EQ_TYPE_MODE_TAB, +} EQ_TYPE; + +#define audio_eq_filter_info eq_coeff_info + +#if (defined(EQ_CORE_V1)|| defined(EQ_CORE_V2)) +typedef int (*audio_eq_filter_cb)(void *eq, int sr, struct audio_eq_filter_info *info); + +struct audio_eq_param { + u32 channels : 2; //通道数 + u32 online_en : 1; //是否支持在线调试 1:支持 0:不支持 + u32 mode_en : 1; //支持默认系数表写1 + u32 remain_en : 1; //数据输出支持remain,写1 + u32 no_wait : 1; //是否使能异步eq, 1:使能 0:不使能 + u32 max_nsection : 6;//最大的eq段数,根据使用填写,要小于等于EQ_SECTION_MAX + u32 nsection : 6; //实际需要的eq段数,需小于等于max_nsection + u32 drc_en: 1; //16bit drc时,使用硬件eq对分频器部分进行加速,目前默认使用32bit drc。 + u8 out_32bit : 1; //是否支持32bit eq输出,仅在 no_wait 写1时,out_32bit 才能写1 + audio_eq_filter_cb cb;//获取eq系数的回调函数 + u32 eq_name; //eq名字,在线调试时,用于区分不同eq更新系数 播歌一般写song_eq_mode + u32 sr; //采样率,更根据当前数据实际采样率填写 + void *priv; //私有指针 + int (*output)(void *priv, void *data, u32 len);//异步eq输出回调 + void (*irq_callback)(void *priv);//总段回调函数,数据流激活 +}; +#else +typedef int (*audio_eq_filter_cb)(int sr, struct audio_eq_filter_info *info); + + +/*EQ_ONLINE_CMD_PARAMETER_SEG*/ +typedef struct eq_seg_info EQ_ONLINE_PARAMETER_SEG; + +/*-----------------------------------------------------------*/ +typedef struct eq_seg_info EQ_CFG_SEG; + + +struct audio_eq_param { + u32 channels : 2; + u32 online_en : 1; + u32 mode_en : 1; + u32 remain_en : 1; + u32 no_wait : 1; + u32 max_nsection : 6; + u32 reserved : 20; + + u32 nsection : 6; + u32 drc_en: 1; + u32 eq_name; + audio_eq_filter_cb cb; +}; + +#endif//EQ_CORE_V1 + +#ifdef CONFIG_EQ_SUPPORT_ASYNC +struct audio_eq_async { + u16 ptr; + u16 len; + u16 buf_len; + u8 clear; + u8 out_stu; + char *buf; +}; +#endif + +struct audio_eq { + void *eq_ch; //硬件eq句柄 + u32 sr; //采样率 + u32 remain_flag : 1; //数据未输出完 + u32 updata : 1; //系数是否需要更新 + u32 online_en : 1; //是否支持在线调试 1:支持 0:不支持 + u32 mode_en : 1; //支持默认系数表写1 + u32 remain_en : 1; //数据输出支持remain,写1 + + u32 max_nsection : 6; //eq最大段数 + u32 check_hw_running : 1; //检测到硬件正在运行时不等待其完成1:设置检查 0:不检查 + u32 eq_name; //eq标识 + u8 start; //eq start标识 + +#ifdef CONFIG_EQ_SUPPORT_ASYNC + void *run_buf; + void *run_out_buf; + int run_len; + struct audio_eq_async async; //异步eq 输出管理 +#endif + + u32 mute_cnt_l; //左声道eq mem清除计数 + u32 mute_cnt_r; //右声道eq mem清除计数 + u32 mute_cnt_max; //记录最大点数,超过该点数,清eq mem + + audio_eq_filter_cb cb; //系数回调 + void *output_priv; //私有指针 + int (*output)(void *priv, void *data, u32 len); //输出回调 +#if (defined(EQ_CORE_V1)|| defined(EQ_CORE_V2)) + struct eq_seg_info *eq_seg_tab; //运算前系数表 + float *eq_coeff_tab; //运算后系数表 + void *entry; //无效 +#endif + const char *event_owner; //记录data_handler所处的任务 +}; + +/*----------------------------------------------------------------------------*/ +/**@brief eq模块初始化 + @param + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_eq_init(int eq_section_num); +/*----------------------------------------------------------------------------*/ +/**@brief eq 打开 + @param *param: eq参数句柄,参数详见结构体struct audio_eq_param + @return eq句柄 + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_eq_open(struct audio_eq *eq, struct audio_eq_param *param); +/*----------------------------------------------------------------------------*/ +/**@brief 异步eq设置输出回调 + @param eq:句柄 + @param *output:回调函数 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_eq_set_output_handle(struct audio_eq *eq, int (*output)(void *priv, void *data, u32 len), void *output_priv); +/*----------------------------------------------------------------------------*/ +/**@brief 同步eq设置输出buf + @param eq:句柄 + @param *output:回调函数 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_eq_set_output_buf(struct audio_eq *eq, s16 *buf, u32 len); +/*----------------------------------------------------------------------------*/ +/**@brief eq设置采样率 + @param eq:句柄 + @param sr:采样率 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_eq_set_samplerate(struct audio_eq *eq, int sr); +/*----------------------------------------------------------------------------*/ +/**@brief eq设置输入输出通道数 + @param eq:句柄 + @param channel:通道数 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_eq_set_channel(struct audio_eq *eq, u8 channel); + +/*----------------------------------------------------------------------------*/ +/**@brief 设置检查eq是否正在运行 + @param eq:句柄 + @param check_hw_running: 1:设置检查 0:不检查 + @return + @note 检测到硬件正在运行时不等待其完成,直接返回, 仅异步EQ有效 +*/ +/*----------------------------------------------------------------------------*/ +int audio_eq_set_check_running(struct audio_eq *eq, u8 check_hw_running); +/*----------------------------------------------------------------------------*/ +/**@brief 设置eq信息 + @param eq:句柄 + @param channels:设置输入输出通道数 + @param out_32bit:使能eq输出32bit数据,1:输出32bit数据, 0:输出16bit是数据 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_eq_set_info(struct audio_eq *eq, u8 channels, u8 out_32bit); + +/*----------------------------------------------------------------------------*/ +/**@brief 设置eq信息 + @param eq:句柄 + @param channels:设置入输出通道数 + @param in_mode:使能eq输入32bit数据,2:float, 1:输入32bit数据, 0:输入16bit是数据 + @param out_mode:使能eq输出32bit数据,2:float, 1:输出32bit数据, 0:输出16bit是数据 + @param run_mode:运行模式,0:normal, 1:mono, 2:stero + @param data_in_mode:输入数据存放方式 0:块模式 1:序列模式 + @param data_out_mode:输入数据存放方式 0:块模式 1:序列模式 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_eq_set_info_new(struct audio_eq *eq, u8 channels, u8 in_mode, u8 out_mode, u8 run_mode, u8 data_in_mode, u8 data_out_mode); + + +/*----------------------------------------------------------------------------*/ +/**@brief eq启动 + @param eq:句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_eq_start(struct audio_eq *eq); +/*----------------------------------------------------------------------------*/ +/**@brief eq的数据处理 + @param eq:句柄 + @param *data:输入数据地址 + @param len:输入数据长度 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_eq_run(struct audio_eq *eq, s16 *data, u32 len); +/*----------------------------------------------------------------------------*/ +/**@brief eq关闭 + @param eq:句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_eq_close(struct audio_eq *eq); + + +#ifdef CONFIG_EQ_SUPPORT_ASYNC +/*----------------------------------------------------------------------------*/ +/**@brief 清除异步eq剩余的数据 + @param eq:句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_eq_async_data_clear(struct audio_eq *eq); +#endif +/*----------------------------------------------------------------------------*/ +/**@brief 获取异步eq剩余的数据 + @param eq:句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_eq_data_len(struct audio_eq *eq); + +/*----------------------------------------------------------------------------*/ +/**@brief audio_eq_open重新封装,简化使用 + @param *parm: eq参数句柄,参数详见结构体struct audio_eq_param + @return eq句柄 + @note +*/ +/*----------------------------------------------------------------------------*/ +struct audio_eq *audio_dec_eq_open(struct audio_eq_param *parm); + +/*----------------------------------------------------------------------------*/ +/**@brief audio_eq_close重新封装,简化使用 + @param eq句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_dec_eq_close(struct audio_eq *eq); + +#if (defined(EQ_CORE_V1)|| defined(EQ_CORE_V2)) +#else +void eq_app_run_check(struct audio_eq *eq); +int eq_get_filter_info(int sr, struct audio_eq_filter_info *info); +int aec_ul_eq_filter(int sr, struct audio_eq_filter_info *info); +int eq_phone_get_filter_info(int sr, struct audio_eq_filter_info *info); + +int eq_mode_set(u8 mode); +int eq_mode_sw(void); +int eq_mode_get_cur(void); +int eq_mode_set_custom_param(u16 index, int gain); +s8 eq_mode_get_gain(u8 mode, u16 index); +int eq_mode_get_freq(u8 mode, u16 index); +void eq_section_num_set(u8 song, u8 call_16k, u8 call_8k, u8 aec_16k, u8 aec_8k); +#endif + +#endif + diff --git a/include_lib/media/media_new/media/application/audio_howling.h b/include_lib/media/media_new/media/application/audio_howling.h new file mode 100644 index 0000000..a1c13d6 --- /dev/null +++ b/include_lib/media/media_new/media/application/audio_howling.h @@ -0,0 +1,54 @@ +#ifndef _AUDIO_HOWLING_API_H +#define _AUDIO_HOWLING_API_H + +#include "media/howling_api.h" + + +#define TRAP_MODE 0 +#define SHIFT_PITCH_MODE 1 +#define PEMAFROW_MODE 2 +#define SHIFT_PHASE_MODE 3 + +#define HOWLING_MODE SHIFT_PITCH_MODE + +#if (HOWLING_MODE == TRAP_MODE) +#define REVERB_RUN_POINT_NUM 160 //固定160个点 +#elif (HOWLING_MODE == SHIFT_PHASE_MODE) // +#define REVERB_RUN_POINT_NUM 256 //固定256个点 +#elif (HOWLING_MODE == PEMAFROW_MODE) +#define REVERB_RUN_POINT_NUM 128 //固定128 +#else +#define REVERB_RUN_POINT_NUM 0 //无限制 +#endif + + +/*----------------------------------------------------------------------------*/ +/**@brief 啸叫抑制模块打开 + @param howl_para:陷波模式时为啸叫抑制参数 ,pemafrow模式为DAC输出数据buf,; + sample_rate:输入数据采样率; + channels: 输入数据通道数; + mode: 0 陷波模式;1 移频模式 2 pemafrow模式 + @return 啸叫抑制句柄, + @note 陷波模式 要外部保证每次运算数据为160点,pemafrow 为128个点 + 对应模式需外部使能,默认只开 移频模式 + const int config_howling_enable_pemafrow_mode = 1; + const int config_howling_enable_trap_mode = 1; + const int config_howling_enable_pitchps_mode = 1; +*/ +/*----------------------------------------------------------------------------*/ +HOWLING_API_STRUCT *open_howling(void *howl_para, u16 sample_rate, u8 channel, u8 mode); +/* + * 啸叫抑制模块数据处理 + */ +void run_howling(HOWLING_API_STRUCT *howling_hdl, short *in, short *out, int len); +/* + * 啸叫抑制模块关闭 + */ +void close_howling(HOWLING_API_STRUCT *holing_hdl); +/* + * 啸叫抑制模块暂停处理 + */ +void pause_howling(HOWLING_API_STRUCT *holing_hdl, u8 run_mark); + +#endif + diff --git a/include_lib/media/media_new/media/application/audio_pitch.h b/include_lib/media/media_new/media/application/audio_pitch.h new file mode 100644 index 0000000..6728a19 --- /dev/null +++ b/include_lib/media/media_new/media/application/audio_pitch.h @@ -0,0 +1,51 @@ + +#ifndef _AUDIO_PITCH_API_H_ +#define _AUDIO_PITCH_API_H_ +#include "pitchshifter/pitchshifter_api.h" +// #include "mono2stereo/reverb_mono2stero_api.h" + + +#define PITCHSHIFT_USE_AUDIO_STREAM 0 //是否使用audio_sream流节点 +#if PITCHSHIFT_USE_AUDIO_STREAM +#include "media/audio_stream.h" +#endif + +typedef struct _s_pitch_hdl { + PITCHSHIFT_FUNC_API *ops; + u8 *databuf; + PITCH_SHIFT_PARM parm; +#if PITCHSHIFT_USE_AUDIO_STREAM + struct audio_stream_entry entry; // 音频流入口 + int out_len; + int process_len; +#endif + u8 run_en; + u8 update; +} s_pitch_hdl; +/* + * 获取变声模块默认参数;open时不传默认参数会使用内部默认参数 + * 仅用于获取初值。实时参数存放在open的返回句柄parm中 + */ +PITCH_SHIFT_PARM *get_pitch_parm(void); +/* + * 变声模块打开 + */ +s_pitch_hdl *open_pitch(PITCH_SHIFT_PARM *param); +/* + * 变声模块关闭 + */ +void close_pitch(s_pitch_hdl *picth_hdl); +/* + * 变声模块参数更新 + */ +void update_picth_parm(s_pitch_hdl *pitch_hdl, PITCH_SHIFT_PARM *p_pitch_parm); +/* + * 变声模块数据处理 + */ +void pitch_run(s_pitch_hdl *picth_hdl, s16 *indata, s16 *outdata, int len, u8 ch_num); +/* + * 变声模块暂停处理 + */ +void pause_pitch(s_pitch_hdl *pitch_hdl, u8 run_mark); +#endif + diff --git a/include_lib/media/media_new/media/application/audio_surround.h b/include_lib/media/media_new/media/application/audio_surround.h new file mode 100644 index 0000000..e62cfb4 --- /dev/null +++ b/include_lib/media/media_new/media/application/audio_surround.h @@ -0,0 +1,171 @@ + +#ifndef _AUDIO_SURROUND_API_H_ +#define _AUDIO_SURROUND_API_H_ +#include "surround/effect_sur_api.h" +// #include "audio_config.h" + +#define SURROUND_USE_AUDIO_STREAM 0 //是否使用audio_sream流节点 + +typedef struct _surround_update_parm { + int surround_type;//音效类型 + int rotatestep;//旋转速度 + int damping;//高频衰减速度 + int feedback;//整体衰减速度 + int roomsize;//空间大小 +} surround_update_parm; + +typedef struct _surround_open_parm { + u8 channel;//通道数立体声配2, 左声道配EFFECT_CH_L, 右声道配EFFECT_CH_R + u8 surround_effect_type;//默认的环绕音效类型 +} surround_open_parm; + + +typedef struct _surround_hdl { + SUR_FUNC_API *ops; + void *work_buf; + OS_MUTEX mutex; + u8 surround_en: 1; + u8 update: 1; + u8 nch_update: 1; + + surround_open_parm parm; + +#if SURROUND_USE_AUDIO_STREAM + struct audio_stream_entry entry; // 音频流入口 +#endif + +} surround_hdl; + +/*cmd*/ +enum { + EFFECT_3D_PANORAMA = 0, //3d全景 + EFFECT_3D_ROTATES, //3d环绕 + EFFECT_FLOATING_VOICE, //流动人声 + EFFECT_GLORY_OF_KINGS, //王者荣耀 + EFFECT_FOUR_SENSION_BATTLEFIELD, //四季战场 + + EFFECT_SUR2, //一种新的环绕声(仿某耳机的环绕音效)需将const_surround_en|BIT(2) + /*如使用以下效果,需将const_surround_en|BIT(1), mips占用 55M ram33k*/ + EFFECT_3D_PANORAMA2, //3d全景另一种效果 + EFFECT_KTV, //ktv模式 + EFFECT_3DTHE, //3D影院 + EFFECT_HALL, //音乐厅 + EFFECT_VOICE, //清澈人声 + EFFECT_SUR, //全景环绕 + + EFFECT_OFF2, //音效开关(数据会经过模块,但不做处理,保证数据延续,避免由音效开关引起的哒哒音,) + EFFECT_OFF, //音效开关(数据直接不经过模块) +}; + + +//{EFFECT_3D_TYPE1, 2, 120, 110, 128},//3D全景 +//{EFFECT_3D_ROTATE, 2, 60, 70, 128},//3D旋转, step旋转速度 建议1~8 +//{EFFECT_3D_LRDRIFT, 140, 120, 95, 128}, //流动人声,step流动速度 建议40~400 +//{EFFECT_3D_TYPE0, 2, 120, 95, 128},//王者荣耀 +//{EFFECT_3D_TYPE1, 2, 60, 100, 30},//四季战场,同全景,但把整体调小了 +//以上是内置默认效果 + + +#if 0 +//如启用多效果调节,需将const_surround_en|BIT(1),调用update接口传参使用。 +//{EFFECT_3D_TYPE2, 2, 90, 100, 100},//3d全景的另一效果,该效果,mips占用 55M ram33k. +//第一个参数2是无效参数. +//第2个参数90调节反馈强度范围是1到150,大点的话空间感比较强。 +//第3个参数是 湿声增益,可调范围是0到128。 +//第4个参数调节空间大小,范围是0-100,是反馈参数,有效范围0到100。 + +//例如: +surround_update_parm parm = {0}; +parm.surround_type = EFFECT_3D_TYPE2; +parm.rotatestep = 2; +parm.damping = 90; +parm.feedback = 100; +parm.roomsize = 100; +audio_surround_parm_update(hdl, EFFECT_3D_PANORAMA2, &parm); +#endif + +#if 0 +//如需要自定义 ktv模式、3d影院、音乐厅、清澈人声、全景环绕 +//参数顺序 +//dry,wet,delay,rot60,Erwet,Erfactor,Ewidth,Ertolate,predelay,width,diffusion,dampinglpf,basslpf,bassB +const static int surmode_present[][14] = { + {55, 70, 35, 8000, 80, 80, 80, 80, 20, 100, 70, 6500, 4000, 18}, //EFFECT_KTV + {60, 60, 90, 9030, 90, 90, 90, 90, 18, 100, 75, 7000, 1000, 29}, //EFFECT_3DTHE + {50, 70, 100, 12000, 100, 100, 100, 100, 20, 100, 72, 9000, 50, 3}, //EFFECT_HALL + {40, 70, 20, 2010, 100, 70, 70, 100, 15, 100, 70, 5500, 3500, 60}, //EFFECT_VOICE + {60, 70, 100, 9000, 80, 80, 80, 90, 10, 100, 72, 8000, 500, 15}, //EFFECT_SUR +}; + +parm.surround_type = EFFECT_3D_TYPE2; +parm.rotatestep = 2; +parm.damping = -1; +parm.feedback = 100; +parm.roomsize = (int)surmode_present[0]; +audio_surround_parm_update(hdl, EFFECT_KTV, &parm); + +//如使用默认的 ktv模式、3d影院、音乐厅、清澈人声、全景环绕 +audio_surround_parm_update(hdl, EFFECT_KTV, NULL); +audio_surround_parm_update(hdl, EFFECT_3DTHE, NULL); +audio_surround_parm_update(hdl, EFFECT_HALL, NULL); +audio_surround_parm_update(hdl, EFFECT_VOICE, NULL); +audio_surround_parm_update(hdl, EFFECT_SUR, NULL); +#endif + + +/*----------------------------------------------------------------------------*/ +/**@brief audio_surround_open 环绕音效打开 + @param *_parm: 环绕音效始化参数,详见结构体surround_open_parm + @return 句柄 + @note +*/ +/*----------------------------------------------------------------------------*/ +surround_hdl *audio_surround_open(surround_open_parm *parm); + +/*----------------------------------------------------------------------------*/ +/**@brief audio_surround_parm_update 环绕音效参数更新 + @param cmd:EFFECT_3D_PANORAMA,EFFECT_3D_ROTATES,EFFECT_FLOATING_VOICE,EFFECT_GLORY_OF_KINGS,EFFECT_FOUR_SENSION_BATTLEFIELD + @param *_parm:参数指针,NULL则使用默认德参数,否则传入自定义参数 + @return 0:成功 -1: 失败 + @note 对耳时,左右声道效果,须设置保持一致 +*/ +/*----------------------------------------------------------------------------*/ +int audio_surround_parm_update(surround_hdl *_hdl, u32 cmd, surround_update_parm *_parm); + +/* surround_update_parm parm = {0}; */ +// parm.surround_type = EFFECT_3D_TYPE1; +// parm.rotatestep = 2;//旋转速度 +// parm.damping = 120;//高频衰减速度 +// parm.feedback = 110;//整体衰减速度 +// parm.roomsize = 128;//空间大小 +/* audio_surround_parm_update(hdl, EFFECT_3D_PANORAMA, &parm); */ +/*----------------------------------------------------------------------------*/ +/**@brief audio_surround_close 环绕音效关闭处理 + @param _hdl:句柄 + @return 0:成功 -1:失败 + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_surround_close(surround_hdl *_hdl); + +/*----------------------------------------------------------------------------*/ +/**@brief audio_surround_run 环绕音效处理 + @param _hdl:句柄 + @param data:需要处理的数据 + @param len:数据长度 + @return 0:成功 -1:失败 + @note 无数据流节点时,直接使用改接口进行环绕音效的处理 +*/ +/*----------------------------------------------------------------------------*/ +int audio_surround_run(surround_hdl *_hdl, void *data, u32 len); + + +/*----------------------------------------------------------------------------*/ +/**@brief audio_surround_switch_nch 通道切换 + @param _hdl:句柄 + @param nch:通道数 2 4 或者EFFECT_CH_L EFFECT_CH_R + @return 0:成功 -1:失败 + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_surround_switch_nch(surround_hdl *_hdl, int nch); +#endif diff --git a/include_lib/media/media_new/media/application/audio_vbass.h b/include_lib/media/media_new/media/application/audio_vbass.h new file mode 100644 index 0000000..d76a054 --- /dev/null +++ b/include_lib/media/media_new/media/application/audio_vbass.h @@ -0,0 +1,54 @@ +#if 1 +#ifndef _AUDIO_VBASS_API_H_ +#define _AUDIO_VBASS_API_H_ +#include "system/includes.h" +#include "media/audio_stream.h" +#include "media/VirtualBass_api.h" + +typedef struct _VirtualBassUdateParam { + int ratio; //0~100,默认10 + int boost; //0或者1 ,默认1 + int fc; //30~300Hz, 默认100 +} VirtualBassUdateParam; + +struct virtual_bass_tool_set { + float prev_gain; //-90.3~90.3 dB, 默认值 0 + VirtualBassUdateParam parm; +}; + + +#define VBASS_STREAM_EN 0 +typedef struct _vbass_hdl { +#if VBASS_STREAM_EN + struct audio_stream_entry entry; // 音频流入口 +#endif + struct list_head hentry; // + void *workbuf; //vbass 运行句柄及buf + VirtualBassParam parm; + u32 vbass_name; + u8 status; //内部运行状态机 + u8 update; //设置参数更新标志 + u8 lowfreq_en; //1:保留低频;0:不保留 +} vbass_hdl; + + +int audio_vbass_run(vbass_hdl *hdl, void *data, u32 len); +vbass_hdl *audio_vbass_open(u32 vbass_name, VirtualBassParam *parm); +int audio_vbass_close(vbass_hdl *hdl); + +int audio_vbass_parm_update(u32 vbass_name, VirtualBassUdateParam *parm); +void audio_vbass_bypass(u32 vbass_name, u8 bypass); +vbass_hdl *get_cur_vbass_hdl_by_name(u32 vbass_name); + +#ifndef RUN_NORMAL +#define RUN_NORMAL 0 +#endif + +#ifndef RUN_BYPASS +#define RUN_BYPASS 1 +#endif + + +#endif +#endif /*CONFIG_EFFECT_CORE_V2_ENABLE*/ + diff --git a/include_lib/media/media_new/media/application/eq_config.h b/include_lib/media/media_new/media/application/eq_config.h new file mode 100644 index 0000000..1e5b086 --- /dev/null +++ b/include_lib/media/media_new/media/application/eq_config.h @@ -0,0 +1,710 @@ +#if (defined(EQ_CORE_V1)|| defined(EQ_CORE_V2)) + +#ifndef _EQ_CONFIG_H_ +#define _EQ_CONFIG_H_ + +#include "application/audio_eq.h" +#include "application/audio_drc.h" +#include "application/audio_vbass.h" +#include "spinlock.h" +#include "math.h" + +/*-----------------------------------------------------------*/ +/*eq online cmd*/ +enum { + EQ_ONLINE_CMD_SECTION = 1, + EQ_ONLINE_CMD_GLOBAL_GAIN, + EQ_ONLINE_CMD_LIMITER, + EQ_ONLINE_CMD_INQUIRE, + EQ_ONLINE_CMD_GETVER, + EQ_ONLINE_CMD_GET_SOFT_SECTION,//br22专用 + EQ_ONLINE_CMD_GET_SECTION_NUM = 0x7,//工具查询 小机需要的eq段数 + EQ_ONLINE_CMD_GLOBAL_GAIN_SUPPORT_FLOAT = 0x8, + + + EQ_ONLINE_CMD_PASSWORD = 0x9, + EQ_ONLINE_CMD_VERIFY_PASSWORD = 0xA, + EQ_ONLINE_CMD_FILE_SIZE = 0xB, + EQ_ONLINE_CMD_FILE = 0xC, + EQ_EQ_ONLINE_CMD_GET_SECTION_NUM = 0xD,//该命令新加与 0x7功能一样 + EQ_EQ_ONLINE_CMD_CHANGE_MODE = 0xE,//切模式 + + EQ_ONLINE_CMD_MODE_COUNT = 0x100,//模式个数a 1 + EQ_ONLINE_CMD_MODE_NAME = 0x101,//模式的名字a eq + EQ_ONLINE_CMD_MODE_GROUP_COUNT = 0x102,//模式下组的个数,4个字节 1 + EQ_ONLINE_CMD_MODE_GROUP_RANGE = 0x103,//模式下组的id内容 0x11 + EQ_ONLINE_CMD_EQ_GROUP_COUNT = 0x104,//eq组的id个数 1 + EQ_ONLINE_CMD_EQ_GROUP_RANGE = 0x105,//eq组的id内容 0x11 + EQ_ONLINE_CMD_MODE_SEQ_NUMBER = 0x106,//mode的编号 magic num + + + EQ_ONLINE_CMD_PARAMETER_SEG = 0x11, + EQ_ONLINE_CMD_PARAMETER_TOTAL_GAIN, + EQ_ONLINE_CMD_PARAMETER_LIMITER, + EQ_ONLINE_CMD_PARAMETER_DRC, + EQ_ONLINE_CMD_PARAMETER_CHANNEL,//通道切换 + + + EQ_ONLINE_CMD_SONG_EQ_SEG = 0x2001, + EQ_ONLINE_CMD_CALL_EQ_SEG = 0x2002, + EQ_ONLINE_CMD_AEC_EQ_SEG = 0x2003, + + + EQ_ONLINE_CMD_SONG_EQ_V1_SEG = 0x2011,// float gain, float q + EQ_ONLINE_CMD_CALL_EQ_V1_SEG = 0x2012, + EQ_ONLINE_CMD_AEC_EQ_V1_SEG = 0x2013, + EQ_ONLINE_CMD_HEARING_AID_EQ_SEG = 0x2014,// float gain, float q + EQ_ONLINE_CMD_HEARING_AID_EQ_SEG2 = 0x2015,// float gain, float q + + + EQ_ONLINE_CMD_SONG_DRC = 0x2101, + EQ_ONLINE_CMD_SONG_WDRC = 0x2102, + EQ_ONLINE_CMD_SONG_MULTI_WDRC = 0x2104, + + EQ_ONLINE_CMD_VIRTUAL_BASS = 0x2203, +//add xx here + + EQ_ONLINE_CMD_MAX,//最后一个 +}; + +#define CONSTRAINT_OP_DRC_L_R_CH 0x01 +#define CONSTRAINT_OP_DRC_WDRC_SINGLE_CH 0x02 +#define CONSTRAINT_OP_DRC_WDRC_DUAL_CH 0x03 + + +/*eq online packet*/ +typedef struct { + int cmd; ///eq_seg_tab) { + int size = sizeof(your_audio_out_eq_tab); + eq->eq_seg_tab = zalloc(size); + memcpy(eq->eq_seg_tab, your_audio_out_eq_tab, size); + } + if (!eq->eq_coeff_tab) { + eq->eq_coeff_tab = zalloc(sizeof(int) * 5 * nsection); + } + for (int i = 0; i < nsection; i++) { + eq_seg_design(&eq->eq_seg_tab[i], sr, &eq->eq_coeff_tab[5 * i]); + } + + local_irq_enable(); + info->L_coeff = info->R_coeff = (void *)eq->eq_coeff_tab; + info->L_gain = info->R_gain = 0; + info->nsection = nsection; +#else + local_irq_disable(); + u8 nsection = ARRAY_SIZE(your_audio_out_eq_tab); + for (int i = 0; i < nsection; i++) { + eq_seg_design(&your_audio_out_eq_tab[i], sr, &your_eq_coeff_tab[i]); + } + local_irq_enable(); + info->L_coeff = info->R_coeff = (void *)your_eq_coeff_tab;//系数指针赋值 + info->L_gain = info->R_gain = 0;//总增益填写,用户可修改(-20~20db) + info->nsection = nsection;//eq段数,根据提供给的系数表来填写,例子是2 + +#endif + return 0; +} + +struct drc_ch drc_fliter = {0}; +#define your_threshold (0) +/*----------------------------------------------------------------------------*/ +/**@brief 自定义限幅器系数回调 + @param *drc: 句柄 + @param *info: 系数结构地址 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int drc_get_filter_info_demo(void *drc, struct audio_drc_filter_info *info) +{ + int th = your_threshold;//-60 ~0db + int threshold = roundf(powf(10.0f, th / 20.0f) * 32768); // 0db:32768, -60db:33 + + drc_fliter.nband = 1; + drc_fliter.type = 1; + drc_fliter._p.limiter[0].attacktime = 5; + drc_fliter._p.limiter[0].releasetime = 300; + drc_fliter._p.limiter[0].threshold[0] = threshold; + drc_fliter._p.limiter[0].threshold[1] = 32768; + + info->pch = info->R_pch = &drc_fliter; + return 0; +} + + +struct drc_ch drc_fliter2 = {0}; +#define your_threshold1 (0) +#define your_threshold2 (0) +/*----------------------------------------------------------------------------*/ +/**@brief 自定义压缩器系数回调 + @param *drc: 句柄 + @param *info: 系数结构地址 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int drc_get_filter_info_demo2(void *drc, struct audio_drc_filter_info *info) +{ + int th1 = your_threshold1;//-60 ~0db + int th2 = your_threshold2;//-60 ~0db + + int your_ratio0 = 800;//100~1000 + int your_ratio1 = 900;//100~1000 + + + if (th2 < th1) { //阈值2需大于等于阈值1 + th2 = th1; + } + if (your_ratio1 < your_ratio0) { //压缩比2需要大于等于压缩比1 + your_ratio1 = your_ratio0; + } + + int threshold0 = roundf(powf(10.0f, th1 / 20.0f) * 32768); // 0db:32768, -60db:33 + int threshold1 = roundf(powf(10.0f, th2 / 20.0f) * 32768); // 0db:32768, -60db:33 + + drc_fliter2.nband = 1;//全带 + drc_fliter2.type = 2;//压缩器 + drc_fliter2._p.compressor[0].attacktime = 5; + drc_fliter2._p.compressor[0].releasetime = 300; + drc_fliter2._p.compressor[0].threshold[0] = threshold0; + drc_fliter2._p.compressor[0].threshold[1] = threshold1; + drc_fliter2._p.compressor[0].threshold[2] = 32768; + + drc_fliter2._p.compressor[0].ratio[0] = 100; + drc_fliter2._p.compressor[0].ratio[1] = your_ratio0; + drc_fliter2._p.compressor[0].ratio[2] = your_ratio1; + + info->pch = info->R_pch = &drc_fliter2; + return 0; +} + + + +//修改自定义模式eq系数表,更新系数到eq 方法 +// 板极头文件中 这两宏 配0 +#define TCFG_EQ_ONLINE_ENABLE 0 //支持在线EQ调试, +#define TCFG_USE_EQ_FILE 0 //离线eq使用配置文件还是默认系数表 1:使用文件 0 使用默认系数表 + + +// 在sdk中实现以下接函数 +/*----------------------------------------------------------------------------*/ +/**@brief 设置用户自定义模式每段eq信息 + @param + @param + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int eq_mode_set_custom_info_user(struct eq_seg_info *seg) +{ + if (!config_audio_eq_file_en) { + if (!seg) { + return 0; + } + u16 index = seg->index; //第几段eq + EQ_CFG *eq_cfg = get_eq_cfg_hdl(); + if (index >= eq_cfg->section_max) { + return 0; + } + int *tmp = (int *)eq_cfg->eq_type_tab; + EQ_CFG_SEG *tab_custom = (EQ_CFG_SEG *)tmp[EQ_MODE_CUSTOM]; + + index = eq_cfg->eq_mode_use_idx[index]; + memcpy(&tab_custom[index], seg, sizeof(struct eq_seg_info));//更新参数到自定义模式系数表 + + /* log_debug("idx:%d, iir:%d, freq:%d, gain:0x%x, q:0x%x ", seg->index, seg->iir_type, seg->freq, *(int *)&seg->gain, *(int *)&seg->q); */ + } + return 0; +} +/*----------------------------------------------------------------------------*/ +/**@brief 获取某个模式eq表内,某一段eq的信息 + @param + @param + @return 返回eq信息 + @note +*/ +/*----------------------------------------------------------------------------*/ +struct eq_seg_info *eq_mode_get_custom_info_user(EQ_MODE mode, u8 index) +{ + if (!config_audio_eq_file_en) { + + EQ_CFG *eq_cfg = get_eq_cfg_hdl(); + if (index >= eq_cfg->section_max) { + return 0; + } + int *tmp = (int *)eq_cfg->eq_type_tab; + EQ_CFG_SEG *seg = (EQ_CFG_SEG *)tmp[mode]; + + index = eq_cfg->eq_mode_use_idx[index]; + /* log_debug("idx:%d, iir:%d, freq:%d, gain:0x%x, q:0x%x ", seg->index, seg->iir_type, seg->freq, *(int *)&seg->gain, *(int *)&seg->q); */ + return &seg[index]; + } + return 0; +} + +/*设置总增益后,需要设置更新*/ +void update_global_gain_demo(float global_gain) +{ + EQ_CFG *eq_cfg = get_eq_cfg_hdl(); + set_global_gain(eq_cfg, song_eq_mode, global_gain);//设置总增益, + eq_mode_set(EQ_MODE_CUSTOM);//设置自定义模式、更新系数以及总增益 +} + +/*设置参数后,需要设置更新*/ +void update_eq_seg_info_demo(struct eq_seg_info *seg) +{ + eq_mode_set_custom_info_user(seg);//更新参数到自定义模式系数表 + eq_mode_set(EQ_MODE_CUSTOM);//设置自定义模式、更新系数以及总增益 +} +void update_custom_info_demo2(u16 index, int freq, float gain) +{ + eq_mode_set_custom_info(index, freq, gain);/*改某一段eq的的中心截止频率 以及增益*/ + eq_mode_set(EQ_MODE_CUSTOM);//设置自定义模式、更新系数以及总增益 +} + +#endif + +#endif +#endif//EQ_CORE_V1 + diff --git a/include_lib/media/media_new/media/application/eq_func_define.h b/include_lib/media/media_new/media/application/eq_func_define.h new file mode 100644 index 0000000..02108ef --- /dev/null +++ b/include_lib/media/media_new/media/application/eq_func_define.h @@ -0,0 +1,67 @@ +#ifndef _EQ_FUNC_DEFINE_H +#define _EQ_FUNC_DEFINE_H + +#include "generic/typedef.h" + +extern u32 EQ_PRIV_SECTION_NUM; +extern u32 EQ_SECTION_NUM; +extern const int const_eq_debug; +extern const int config_audio_drc_en; +extern const int config_audio_eq_en; +enum { + EQ_EN = BIT(0),//eq模式使能 + EQ_SUPPORT_OLD_VER_EN = BIT(1),//ac700N,使能该bit可版本0.7.1.0, 0.7.1.1 + EQ_LITE_VER_EN = BIT(2),//精简版版本eq驱动,不支持异步,不支持默认效果切换接口,仅支持文件解析 + EQ_ONLINE_EN = BIT(3), //在线调试模块使能 + EQ_FILE_EN = BIT(4),//打开支持文件解析,关闭则只能使用默认效果表做eq + EQ_FILE_SWITCH_EN = BIT(5),//打开支持eq_cfg_hw.bin文件切换更新效果 + EQ_HIGH_BASS_EN = BIT(6),//eq内部集成的高低音接口使能 + EQ_HIGH_BASS_FADE_EN = BIT(7),//eq内部集成高低音淡入淡出效果方式使能,配合config_audio_eq_fade_step使用 + EQ_FILTER_COEFF_FADE_EN = BIT(8),//eq默认系数表效果切换,或者在线调试效果更新,使用淡入淡出方式,避免增益跳跃引起的杂音问题 + EQ_FILTER_COEFF_LIMITER_ZERO_EN = BIT(9),// + EQ_HW_UPDATE_COEFF_ONLY_EN = BIT(10),// 有空闲的段可以使用,就不需要切换系数 */ + EQ_HW_LR_ALONE = BIT(11),//// 左右声道分开处理与bit(10),同时使能或关闭 + EQ_SUPPORT_32BIT_SYNC_EN = BIT(12),//// 支持同步方式32biteq + EQ_SUPPORT_MULIT_CHANNEL_EN = BIT(13),//AC699N、AC700N eq是否支持多声道(3~8) 打开:支持 关闭:仅支持1~2声道 + EQ_HW_CROSSOVER_TYPE0_EN = BIT(14),//支持硬件分频器,且分频器使用序列进序列出,需使能BIT(13) + EQ_HW_CROSSOVER_TYPE1_EN = BIT(15),//硬件分频器使用使用块出方式,会增加mem(该方式仅支持单声道处理) + EQ_LR_DIVIDE_EN = BIT(16),//eq左右声道效果拆分,四声道时可能会使用 + EQ_ONLINE_FILE_SAVE = BIT(17),//eq在线调试保存到vm使能 +}; + +#define config_audio_eq_online_en (config_audio_eq_en & EQ_ONLINE_EN) +#define config_audio_eq_file_en (config_audio_eq_en & EQ_FILE_EN) +#define config_audio_eq_file_sw_en (config_audio_eq_en & EQ_FILE_SWITCH_EN) +#define config_filter_coeff_fade_en (config_audio_eq_en & EQ_FILTER_COEFF_FADE_EN) +#define config_high_bass_en (config_audio_eq_en & EQ_HIGH_BASS_EN) +#define config_audio_eq_fade_en (config_audio_eq_en & EQ_HIGH_BASS_FADE_EN) +#define config_filter_coeff_limit_zero (config_audio_eq_en & EQ_FILTER_COEFF_LIMITER_ZERO_EN) +#define HW_EQ_UPDATE_COEFF_ONLY_EN (config_audio_eq_en & EQ_HW_UPDATE_COEFF_ONLY_EN) +#define HW_EQ_LR_ALONE (config_audio_eq_en & EQ_HW_LR_ALONE) +#define SUPPORT_32BIT_SYNC_EQ (config_audio_eq_en & EQ_SUPPORT_32BIT_SYNC_EN) +#define hw_eq_support_multi_channels (config_audio_eq_en & EQ_SUPPORT_MULIT_CHANNEL_EN) +#define hw_crossover_type0 (config_audio_eq_en & EQ_HW_CROSSOVER_TYPE0_EN) +#define hw_crossover_type1 (config_audio_eq_en & EQ_HW_CROSSOVER_TYPE1_EN) +#define config_eq_lite_en (config_audio_eq_en & EQ_LITE_VER_EN) +#define config_eq_support_old_ver_en (config_audio_eq_en & EQ_SUPPORT_OLD_VER_EN) +#define config_divide_en (config_audio_eq_en & EQ_LR_DIVIDE_EN) +#define config_eq_online_file_save (config_audio_eq_en & EQ_ONLINE_FILE_SAVE) + +extern const int config_audio_drc_en; +enum { + DRC_EN = BIT(0), //drc 使能 + DRC_NBAND_MERGING_ASM_EN = BIT(1),//drc 多带处理完后,多带合并使用汇编加速 + DRC_NBAND_DIS = BIT(2),//关闭drc多带 + DRC_LIMITER_DIS = BIT(3),//关闭drc限幅器 + DRC_COMPRESSOF_DIS = BIT(4),//关闭drc压缩器 + WDRC_TYPE_EN = BIT(5),//wdrc使能 +}; + +#define config_drc_limiter_en (!(config_audio_drc_en & DRC_LIMITER_DIS)) +#define config_drc_compressor_en (!(config_audio_drc_en & DRC_COMPRESSOF_DIS)) +#define config_drc_nband_en (!(config_audio_drc_en & DRC_NBAND_DIS)) +#define config_drc_nband_merg_asm_en (!(config_audio_drc_en & DRC_NBAND_MERGING_ASM_EN)) +#define config_wdrc_en (config_audio_drc_en & WDRC_TYPE_EN) + + +#endif diff --git a/include_lib/media/media_new/media/audio_base.h b/include_lib/media/media_new/media/audio_base.h new file mode 100644 index 0000000..db2edcc --- /dev/null +++ b/include_lib/media/media_new/media/audio_base.h @@ -0,0 +1,90 @@ +#ifndef AUDIO_BASE_H +#define AUDIO_BASE_H + + + +#define AUDIO_CODING_UNKNOW 0x00000000 +#define AUDIO_CODING_MP3 0x00000001 +#define AUDIO_CODING_WMA 0x00000002 +#define AUDIO_CODING_WAV 0x00000004 +#define AUDIO_CODING_SBC 0x00000010 +#define AUDIO_CODING_MSBC 0x00000020 +#define AUDIO_CODING_G729 0x00000040 +#define AUDIO_CODING_CVSD 0x00000080 +#define AUDIO_CODING_PCM 0x00000100 +#define AUDIO_CODING_AAC 0x00000200 +#define AUDIO_CODING_MTY 0x00000400 +#define AUDIO_CODING_FLAC 0x00000800 +#define AUDIO_CODING_APE 0x00001000 +#define AUDIO_CODING_M4A 0x00002000 +#define AUDIO_CODING_AMR 0x00004000 +#define AUDIO_CODING_DTS 0x00008000 +#define AUDIO_CODING_APTX 0x00010000 +#define AUDIO_CODING_LDAC 0x00020000 +#define AUDIO_CODING_G726 0x00040000 +#define AUDIO_CODING_MIDI 0x00080000 +#define AUDIO_CODING_OPUS 0x00100000 +#define AUDIO_CODING_SPEEX 0x00200000 +#define AUDIO_CODING_LC3 0x00400000 +#define AUDIO_CODING_WTGV2 0x01000000 +#define AUDIO_CODING_ALAC 0x02000000 + +#define AUDIO_CODING_STU_PICK 0x10000000 +#define AUDIO_CODING_STU_APP 0x20000000 + +#define AUDIO_CODING_FAME_MASK (AUDIO_CODING_MSBC | AUDIO_CODING_CVSD | AUDIO_CODING_SBC) + +#define AUDIO_INPUT_FILE 0x01 +#define AUDIO_INPUT_FRAME 0x02 + + +enum audio_channel { + AUDIO_CH_LR = 0, //立体声 + AUDIO_CH_L, //左声道(单声道) + AUDIO_CH_R, //右声道(单声道) + AUDIO_CH_DIFF, //差分(单声道) + AUDIO_CH_DUAL_L, //双声道都为左 + AUDIO_CH_DUAL_R, //双声道都为右 + AUDIO_CH_DUAL_LR, //双声道为左右混合 + AUDIO_CH_QUAD, //四声道(LRLR) + + AUDIO_CH_MAX = 0xff, +}; + +#define AUDIO_CH_MIX_MONO AUDIO_CH_DIFF + +#define AUDIO_CH_IS_MONO(ch) (((ch)==AUDIO_CH_L) || ((ch)==AUDIO_CH_R) || ((ch)==AUDIO_CH_DIFF)) +#define AUDIO_CH_IS_DUAL(ch) (((ch)==AUDIO_CH_LR) || ((ch)==AUDIO_CH_DUAL_L) || ((ch)==AUDIO_CH_DUAL_R)) +#define AUDIO_CH_IS_QUAD(ch) (((ch)==AUDIO_CH_QUAD)) + + +/*! \brief 音频处理结构 */ +struct audio_fmt { + u8 channel; /*!< */ + u16 frame_len; /*!< 幁长度 (bytes)*/ + u32 sample_rate; /*!< 采样率 e.g. 48kHz/44.1kHz/32kHz*/ + u32 coding_type; + u32 bit_rate; /*!< 比特率 (bps)*/ + u32 total_time; + u32 quality; + u32 complexity; + void *priv; +}; + + + + + + + + + + + + + + + + +#endif + diff --git a/include_lib/media/media_new/media/audio_cfifo.h b/include_lib/media/media_new/media/audio_cfifo.h new file mode 100644 index 0000000..39fcc3b --- /dev/null +++ b/include_lib/media/media_new/media/audio_cfifo.h @@ -0,0 +1,225 @@ +/***************************************************************** +>file name : audio_cfifo.h +>author : lichao +>create time : Tue 10 Nov 2020 02:22:37 PM CST +*****************************************************************/ +#ifndef _AUDIO_CFIFO_H_ +#define _AUDIO_CFIFO_H_ +#include "generic/list.h" +#include "typedef.h" + +#define WRITE_MODE_BLOCK 0 +#define WRITE_MODE_FORCE 1 + +struct audio_cfifo { + u8 sample_channel; /*fifo采样声道数*/ + s16 *addr; /*fifo首地址*/ + u16 sample_size; /*fifo采样长度*/ + u16 wp; /*fifo写偏移*/ + u16 rp; /*fifo读偏移*/ + u16 lock_rp; /*fifo不可擦写的已读偏移*/ + u16 free_samples; /*fifo可写入样点个数*/ + s16 unread_samples; /*fifo未读样点个数*/ + int sample_rate; /*fifo对应的音频采样率*/ + u32 sw_ptr; + u32 hw_ptr; + struct list_head head; /*子通道数据链表头*/ +}; + +struct audio_cfifo_channel { + u8 write_mode; /*写入模式*/ + u16 delay_time; /*最大延时(ms)*/ + u16 rsp; /*读偏移*/ + u16 wsp; /*写偏移*/ + s16 unread_samples; /*通道未读样点个数*/ + u16 max_samples; /*通道缓冲最大样点个数*/ + u32 sw_ptr; + u32 hw_ptr; + struct audio_cfifo *fifo; /*主fifo指针*/ + struct list_head entry; /*通道接入entry*/ +}; + +/************************************************************************* + * Audio cfifo主fifo初始化 + * INPUT : fifo - 主fifo结构指针, + * buf - fifo缓冲地址 + * len - fifo缓冲长度 + * sample_rate - fifo音频采样率 + * channel - fifo音频声道数 + * OUTPUT : 0 - 成功,非0 - 失败. + * WARNINGS : 无. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +int audio_cfifo_init(struct audio_cfifo *fifo, void *buf, int len, int sample_rate, u8 channel); + +/************************************************************************* + * Audio cfifo主fifo复位 + * INPUT : fifo - 主fifo结构指针, + * buf - fifo缓冲地址 + * len - fifo缓冲长度 + * sample_rate - fifo音频采样率 + * channel - fifo音频声道数 + * OUTPUT : 0 - 成功,非0 - 失败. + * WARNINGS : 这里与audio_cfifo_init类似但意义不一样,不可以当作init使用. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +int audio_cfifo_reset(struct audio_cfifo *fifo, void *buf, int len, int sample_rate, u8 channel); + +/************************************************************************* + * 添加fifo子通道 + * INPUT : fifo - 主fifo结构指针, + * ch - fifo子通道 + * delay_time - 子通道延时 + * write_mode - 子通道写入模式 + * OUTPUT : 0 - 成功,非0 - 失败. + * WARNINGS : 无. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +int audio_cfifo_channel_add(struct audio_cfifo *fifo, struct audio_cfifo_channel *ch, int delay_time, u8 write_mode); + +/************************************************************************* + * 删除fifo子通道 + * INPUT : ch - fifo子通道 + * OUTPUT : 无. + * WARNINGS : 无. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +void audio_cfifo_channel_del(struct audio_cfifo_channel *ch); + +/************************************************************************* + * 主fifo读数更新 + * INPUT : fifo - 主fifo结构指针, samples - 读取的样点个数 + * OUTPUT : 成功更新的样点个数. + * WARNINGS : 无. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +int audio_cfifo_read_update(struct audio_cfifo *fifo, int samples); + +/************************************************************************* + * fifo子通道数据写入 + * INPUT : ch - fifo子通道, data - 数据指针, len - 数据长度 + * OUTPUT : 写入fifo的长度. + * WARNINGS : 强制写入模式无论是否可以写入都将返回预期写入长度. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +int audio_cfifo_channel_write(struct audio_cfifo_channel *ch, void *data, int len); + +/************************************************************************* + * fifo子通道写入直流数据 + * INPUT : ch - fifo子通道, data - 直流值, len - 长度 + * OUTPUT : 写入fifo的长度. + * WARNINGS : 强制写入模式无论是否可以写入都将返回预期写入长度. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +int audio_cfifo_channel_write_fixed_data(struct audio_cfifo_channel *ch, s16 data, int len); + +/************************************************************************* + * fifo子通道擦除 + * INPUT : ch - fifo子通道 + * OUTPUT : 未知. + * WARNINGS : 待开发. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +int audio_cfifo_channel_clear(struct audio_cfifo_channel *ch); + +/************************************************************************* + * 主fifo获取写偏移 + * INPUT : fifo - 主fifo结构指针 + * OUTPUT : fifo写入偏移. + * WARNINGS : 无. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +int audio_cfifo_get_write_offset(struct audio_cfifo *fifo); + +/************************************************************************* + * 主fifo获取未读样点查询 + * INPUT : fifo - 主fifo结构指针 + * OUTPUT : 样点个数. + * WARNINGS : 无. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +int audio_cfifo_get_unread_samples(struct audio_cfifo *fifo); + +/************************************************************************* + * 主fifo与子fifo未读样点个数差值 + * INPUT : ch - fifo子通道 + * OUTPUT : 样点个数. + * WARNINGS : 无. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +int audio_cfifo_channel_unread_diff_samples(struct audio_cfifo_channel *ch); + +/************************************************************************* + * 主fifo通道个数 + * INPUT : fifo - 主fifo结构指针 + * OUTPUT : 通道个数. + * WARNINGS : 无. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +int audio_cfifo_channel_num(struct audio_cfifo *fifo); + +/************************************************************************* + * 主fifo设置已读样点不可擦除区域 + * INPUT : fifo - 主fifo结构指针, samples - 不可擦除样点个数 + * OUTPUT : 无. + * WARNINGS : 特殊处理,无需理解,仅作为开发人员使用. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +void audio_cfifo_set_readlock_samples(struct audio_cfifo *fifo, int samples); + +/************************************************************************* + * 获取主fifo设置已读样点不可擦除区域大小 + * INPUT : fifo - 主fifo结构指针. + * OUTPUT : 不可擦除样点个数. + * WARNINGS : 特殊处理,无需理解,仅作为开发人员使用. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +int audio_cfifo_get_readlock_samples(struct audio_cfifo *fifo); + +/************************************************************************* + * fifo使用回调读取通道的有效混合数据 + * INPUT : fifo - 主fifo结构指针 + * offset - 读偏移 + * samples - 读取样点个数 + * priv - 回调私有指针 + * read_callback - 读回调 + * OUTPUT : 读取长度. + * WARNINGS : 无. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +int audio_cfifo_read_with_callback(struct audio_cfifo *fifo, int offset, int samples, + void *priv, int (*read_callback)(void *priv, void *data, int len)); + +/************************************************************************* + * fifo子通道未读样点查询 + * INPUT : ch - fifo子通道 + * OUTPUT : 样点个数. + * WARNINGS : 无. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +int audio_cfifo_channel_unread_samples(struct audio_cfifo_channel *ch); + +/************************************************************************* + * fifo子通道获取写偏移 + * INPUT : ch - fifo子通道 + * OUTPUT : 偏移. + * WARNINGS : 无. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +int audio_cfifo_channel_write_offset(struct audio_cfifo_channel *ch); + +/************************************************************************* + * fifo获取缓冲最小的子通道 + * INPUT : fifo - 主fifo结构指针 + * OUTPUT : fifo子通道指针. + * WARNINGS : 无. + * HISTORY : 2020/12/28 by Lichao. + *=======================================================================*/ +struct audio_cfifo_channel *audio_cfifo_min_samples_channel(struct audio_cfifo *fifo); + +int audio_cfifo_get_sw_ptr(struct audio_cfifo *fifo); + +int audio_cfifo_get_hw_ptr(struct audio_cfifo *fifo); + +int audio_cfifo_read_data(struct audio_cfifo *fifo, s16 *out_buf, int len); +#endif diff --git a/include_lib/media/media_new/media/audio_decoder.h b/include_lib/media/media_new/media/audio_decoder.h new file mode 100644 index 0000000..a603699 --- /dev/null +++ b/include_lib/media/media_new/media/audio_decoder.h @@ -0,0 +1,299 @@ +#ifndef AUDIO_DECODER_H +#define AUDIO_DECODER_H + +#include "generic/typedef.h" +#include "generic/list.h" +#include "media/audio_base.h" +#include "os/os_api.h" + + + +enum { + AUDIO_DEC_EVENT_CURR_TIME = 0x20, + AUDIO_DEC_EVENT_END, + AUDIO_DEC_EVENT_ERR, + AUDIO_DEC_EVENT_SUSPEND, + AUDIO_DEC_EVENT_RESUME, + AUDIO_DEC_EVENT_START, +}; + +enum { + AUDIO_PLAY_EVENT_CURR_TIME = 0x20, + AUDIO_PLAY_EVENT_END, + AUDIO_PLAY_EVENT_ERR, + AUDIO_PLAY_EVENT_SUSPEND, + AUDIO_PLAY_EVENT_RESUME, +}; + +enum { + AUDIO_RES_GET, + AUDIO_RES_PUT, +}; + +enum { + DEC_STA_TRY_START, + DEC_STA_START, + DEC_STA_WAIT_STOP, + DEC_STA_WAIT_SUSPEND, + DEC_STA_WAIT_RESUME, + DEC_STA_WAIT_PAUSE, +}; + +enum { + AUDIO_IOCTRL_CMD_REPEAT_PLAY = 0x90, +}; + +struct fixphase_repair_obj { + short fifo_buf[18 + 12][32][2]; +}; + +struct audio_repeat_mode_param { + int flag; + int headcut_frame; + int tailcut_frame; + int (*repeat_callback)(void *); + void *callback_priv; + struct fixphase_repair_obj *repair_buf; +}; + +struct audio_res_wait { + struct list_head entry; + u8 priority; + u8 preemption : 1; + u8 protect : 1; + u8 only_del : 1; // 仅删除 + u8 snatch_same_prio : 1; // 优先级相同也抢断 + u32 format; + int (*handler)(struct audio_res_wait *, int event); +}; + +struct audio_decoder_task { + struct list_head head; + struct list_head wait; + const char *name; + int wakeup_timer; + int fmt_lock; + OS_SEM sem; +}; + + +struct audio_dec_breakpoint { + int len; + u32 fptr; + int data_len; + u8 data[0]; + // u8 data[128]; +}; + +struct audio_decoder; + + +struct audio_dec_input { + u32 coding_type; + // 定义在p_more_coding_type数组中的解码器会依照顺序依次检测 + // 先检测coding_type再检测p_more_coding_type + u32 *p_more_coding_type; + u32 data_type : 8; + union { + struct { + int (*fread)(struct audio_decoder *, void *buf, u32 len); + int (*fseek)(struct audio_decoder *, u32 offset, int seek_mode); + int (*ftell)(struct audio_decoder *); + int (*flen)(struct audio_decoder *); + } file; + + struct { + int (*fget)(struct audio_decoder *, u8 **frame); + void (*fput)(struct audio_decoder *, u8 *frame); + int (*ffetch)(struct audio_decoder *, u8 **frame); + } frame; + } ops; +}; + +struct audio_dec_handler { + int (*dec_probe)(struct audio_decoder *); + int (*dec_output)(struct audio_decoder *, s16 *data, int len, void *priv); + int (*dec_post)(struct audio_decoder *); + int (*dec_stop)(struct audio_decoder *); +}; +struct stream_codec_info { + int time; + int frame_num; + u32 frame_len; + int frame_points; + int sequence_number; + u32 sample_rate; + u8 channel; +}; + +/*! \brief 音频解码器抽象接口 */ +struct audio_decoder_ops { + u32 coding_type; /*!< 解码格式*/ + void *(*open)(void *priv); /*!< */ + int (*start)(void *); /*!< */ + int (*get_fmt)(void *, struct audio_fmt *fmt); + int (*set_output_channel)(void *, enum audio_channel); + int (*get_play_time)(void *); + int (*fast_forward)(void *, int step_s); + int (*fast_rewind)(void *, int step_s); + int (*get_breakpoint)(void *, struct audio_dec_breakpoint *); + int (*set_breakpoint)(void *, struct audio_dec_breakpoint *); + int (*stream_info_scan)(void *, struct stream_codec_info *info, void *data, int len); + int (*set_tws_mode)(void *, int); + int (*run)(void *, u8 *); + int (*stop)(void *); + int (*close)(void *); + int (*reset)(void *); + int (*ioctrl)(void *, u32 cmd, void *parm); +}; + +#define REGISTER_AUDIO_DECODER(ops) \ + const struct audio_decoder_ops ops SEC(.audio_decoder) + +extern const struct audio_decoder_ops audio_decoder_begin[]; +extern const struct audio_decoder_ops audio_decoder_end[]; + +#define list_for_each_audio_decoder(p) \ + for (p = audio_decoder_begin; p < audio_decoder_end; p++) + + + + +struct audio_decoder { + struct list_head entry; + struct audio_decoder_task *task; + struct audio_fmt fmt; + const char *evt_owner; + const struct audio_dec_input *input; + const struct audio_decoder_ops *dec_ops; + const struct audio_dec_handler *dec_handler; + void (*evt_handler)(struct audio_decoder *dec, int, int *); + void *dec_priv; + void *bp; + u16 id; + u16 pick : 1; + u16 tws : 1; + u16 resume_flag : 1; + u16 output_err : 1; + u16 read_err : 1; + u16 reserved : 11; + u8 run_max; + u8 output_channel; + u8 state; + u8 err; + u8 remain; + u32 magic; +}; + +#define AUDIO_DEC_ORIG_CH AUDIO_CH_LR +#define AUDIO_DEC_L_CH AUDIO_CH_L +#define AUDIO_DEC_R_CH AUDIO_CH_R +#define AUDIO_DEC_MONO_LR_CH AUDIO_CH_DIFF +#define AUDIO_DEC_DUAL_L_CH AUDIO_CH_DUAL_L +#define AUDIO_DEC_DUAL_R_CH AUDIO_CH_DUAL_R +#define AUDIO_DEC_DUAL_LR_CH AUDIO_CH_DUAL_LR + +#define AUDIO_DEC_IS_MONO(ch) (((ch)==AUDIO_DEC_L_CH) || ((ch)==AUDIO_DEC_R_CH) || ((ch)==AUDIO_DEC_MONO_LR_CH)) + +int audio_decoder_task_create(struct audio_decoder_task *task, const char *name); + +int audio_decoder_task_add_wait(struct audio_decoder_task *, struct audio_res_wait *); + +void audio_decoder_task_del_wait(struct audio_decoder_task *, struct audio_res_wait *); +int audio_decoder_task_wait_state(struct audio_decoder_task *task); + +int audio_decoder_resume_all(struct audio_decoder_task *task); +int audio_decoder_resume_off_limits(struct audio_decoder_task *task, u8 limit_num, int *limit_dec); + +int audio_decoder_resume_all_by_sem(struct audio_decoder_task *task, int time_out); + +int audio_decoder_fmt_lock(struct audio_decoder_task *task, int fmt); + +int audio_decoder_fmt_unlock(struct audio_decoder_task *task, int fmt); + +void *audio_decoder_get_output_buff(void *_dec, int *len); + +int audio_decoder_put_output_buff(void *_dec, void *buff, int len, void *priv); + +int audio_decoder_read_data(void *_dec, u8 *data, int len, u32 offset); + +int audio_decoder_get_input_data_len(void *_dec); + +int audio_decoder_get_frame(void *_dec, u8 **frame); + +int audio_decoder_fetch_frame(void *_dec, u8 **frame); + +void audio_decoder_put_frame(void *_dec, u8 *frame); + +int audio_fmt_find_frame(void *_dec, u8 **frame); +int audio_decoder_open(struct audio_decoder *dec, const struct audio_dec_input *input, + struct audio_decoder_task *task); + +int audio_decoder_data_type(void *_dec); + +void audio_decoder_set_id(struct audio_decoder *dec, int); + +int audio_decoder_get_fmt(struct audio_decoder *dec, struct audio_fmt **fmt); + +int audio_decoder_set_fmt(struct audio_decoder *dec, struct audio_fmt *fmt); + +int audio_decoder_get_fmt_info(struct audio_decoder *dec, struct audio_fmt *fmt); + +void audio_decoder_set_handler(struct audio_decoder *dec, const struct audio_dec_handler *handler); + + +void audio_decoder_set_event_handler(struct audio_decoder *dec, + void (*handler)(struct audio_decoder *, int, int *), u32 magic); + +void audio_decoder_set_input_buff(struct audio_decoder *dec, u8 *buff, u16 buff_size); + +void audio_decoder_set_output_buffs(struct audio_decoder *dec, s16 *buffs, + u16 buff_size, u8 buff_num); + +int audio_decoder_set_output_channel(struct audio_decoder *dec, enum audio_channel); + +int audio_decoder_start(struct audio_decoder *dec); + +int audio_decoder_stop(struct audio_decoder *dec); + +int audio_decoder_pause(struct audio_decoder *dec); + +int audio_decoder_suspend(struct audio_decoder *dec, int timeout_ms); + +int audio_decoder_resume(struct audio_decoder *dec); + +int audio_decoder_close(struct audio_decoder *dec); +int audio_decoder_reset(struct audio_decoder *dec); + +int audio_decoder_set_breakpoint(struct audio_decoder *dec, struct audio_dec_breakpoint *bp); + +int audio_decoder_get_breakpoint(struct audio_decoder *dec, struct audio_dec_breakpoint *bp); + +int audio_decoder_forward(struct audio_decoder *dec, int step_s); + +int audio_decoder_rewind(struct audio_decoder *dec, int step_s); + +int audio_decoder_get_total_time(struct audio_decoder *dec); +int audio_decoder_get_play_time(struct audio_decoder *dec); + +int audio_decoder_set_pick_stu(struct audio_decoder *dec, u8 pick); +int audio_decoder_get_pick_stu(struct audio_decoder *dec); + +int audio_decoder_set_tws_stu(struct audio_decoder *dec, u8 tws); +int audio_decoder_get_tws_stu(struct audio_decoder *dec); + +int audio_decoder_set_run_max(struct audio_decoder *dec, u8 run_max); + +void audio_decoder_dual_switch(u8 ch_type, u8 half_lr, s16 *data, int len); + +int audio_decoder_running_number(struct audio_decoder_task *task); + +int audio_decoder_ioctrl(struct audio_decoder *dec, u32 cmd, void *parm); + +void audio_decoder_set_channel(void *_dec, u8 ch_num); +int audio_decoder_get_channel(void *_dec); +int audio_decoder_get_frame_len(void *_dec); +int audio_decoder_get_sample_rate(void *_dec); +int audio_decoder_get_bit_rate(void *_dec); +#endif + diff --git a/include_lib/media/media_new/media/audio_encoder.h b/include_lib/media/media_new/media/audio_encoder.h new file mode 100644 index 0000000..8e12ad9 --- /dev/null +++ b/include_lib/media/media_new/media/audio_encoder.h @@ -0,0 +1,160 @@ +#ifndef AUDIO_ENCODER_H +#define AUDIO_ENCODER_H + +#include "generic/typedef.h" +#include "generic/list.h" +#include "generic/circular_buf.h" +#include "media/audio_base.h" + + + +enum { + AUDIO_ENC_EVENT_CURR_TIME = 0x20, + AUDIO_ENC_EVENT_END, + AUDIO_ENC_EVENT_ERR, + AUDIO_ENC_EVENT_SUSPEND, + AUDIO_ENC_EVENT_RESUME, +}; + + +struct audio_encoder_task { + struct list_head head; + const char *name; +}; + + +struct audio_encoder; + + +struct audio_enc_input { + int (*fget)(struct audio_encoder *, s16 **frame, u16 frame_len); + void (*fput)(struct audio_encoder *, s16 *frame); +}; + +struct audio_enc_handler { + int (*enc_probe)(struct audio_encoder *); + int (*enc_output)(struct audio_encoder *, u8 *data, int len); + int (*enc_post)(struct audio_encoder *); + int (*enc_close)(struct audio_encoder *);//add by wuxu 20200221 +}; + +struct audio_encoder_ops { + u32 coding_type; + void *(*open)(void *priv); + int (*start)(void *); + int (*set_fmt)(void *, struct audio_fmt *fmt); + int (*run)(void *); + int (*stop)(void *); + int (*close)(void *); + int (*ioctrl)(void *, int argc, int argv[]); +}; + +#define REGISTER_AUDIO_ENCODER(ops) \ + const struct audio_encoder_ops ops SEC(.audio_encoder) + +extern const struct audio_encoder_ops audio_encoder_begin[]; +extern const struct audio_encoder_ops audio_encoder_end[]; + +#define list_for_each_audio_encoder(p) \ + for (p = audio_encoder_begin; p < audio_encoder_end; p++) + + +#define AUDIO_ENC_OS_MUTEX_EN 1 + +#if (AUDIO_ENC_OS_MUTEX_EN) +#include "os/os_api.h" +#endif//AUDIO_ENC_OS_MUTEX_EN + +struct audio_encoder { + struct list_head entry; + struct audio_encoder_task *task; + struct audio_fmt fmt; + const char *evt_owner; + const struct audio_enc_input *input; + const struct audio_encoder_ops *enc_ops; + const struct audio_enc_handler *enc_handler; + void (*evt_handler)(struct audio_encoder *enc, int, int *); + void *enc_priv; + u32 pend_timeout; + s16 *pcm_frame; + u16 pcm_remain; + u16 pcm_len; + s16 *output_buffs; + u16 output_buff_size; + u8 output_buff_num; + u8 curr_output_buff; + u8 output_channel; + u8 state; + u8 err; + volatile u8 resume_flag; + u32 magic; +#if (AUDIO_ENC_OS_MUTEX_EN) + OS_MUTEX mutex; +#endif//AUDIO_ENC_OS_MUTEX_EN +}; + +enum { + AUDIO_ENCODER_IOCTRL_CMD_GET_HEAD_INFO = 0x0, + AUDIO_ENCODER_IOCTRL_CMD_GET_TIME, + AUDIO_ENCODER_IOCTRL_CMD_GET_TMARK,//书签 +}; + +int audio_encoder_task_create(struct audio_encoder_task *task, const char *name); + +int audio_encoder_task_del(struct audio_encoder_task *task); + +int audio_encoder_resume_all(struct audio_encoder_task *task); + +int audio_encoder_get_output_buff(void *_enc, s16 **buf); + +int audio_encoder_put_output_buff(void *_enc, void *buff, int len); + +int audio_encoder_get_frame(void *_enc, s16 **frame, u16 len); + +void audio_encoder_put_frame(void *_enc, s16 *frame); + +int audio_encoder_open(struct audio_encoder *enc, const struct audio_enc_input *input, + struct audio_encoder_task *task); + +int audio_encoder_get_fmt(struct audio_encoder *enc, struct audio_fmt **fmt); + +int audio_encoder_set_fmt(struct audio_encoder *enc, struct audio_fmt *fmt); + +void audio_encoder_set_handler(struct audio_encoder *enc, const struct audio_enc_handler *handler); + + +void audio_encoder_set_event_handler(struct audio_encoder *enc, + void (*handler)(struct audio_encoder *, int, int *), u32 maigc); + +void audio_encoder_set_input_buff(struct audio_encoder *enc, u8 *buff, u16 buff_size); + +void audio_encoder_set_output_buffs(struct audio_encoder *enc, s16 *buffs, + u16 buff_size, u8 buff_num); + +int audio_encoder_set_output_channel(struct audio_encoder *enc, enum audio_channel); + +int audio_encoder_start(struct audio_encoder *enc); + +int audio_encoder_stop(struct audio_encoder *enc); + +int audio_encoder_suspend(struct audio_encoder *enc, int timeout_ms); + +int audio_encoder_resume(struct audio_encoder *enc); + +int audio_encoder_close(struct audio_encoder *enc); + +int audio_encoder_ioctrl(struct audio_encoder *enc, int argc, ...); + +/* +********************************************************************* +* Audio Encoder Get channel +* Description: 获取编码器声道配置参数 +* Arguments : *enc 编码句柄 +* Return : 声道数 +* Note(s) : None +********************************************************************* +*/ +int audio_encoder_get_channel(struct audio_encoder *enc); + +#endif + diff --git a/include_lib/media/media_new/media/audio_resample.h b/include_lib/media/media_new/media/audio_resample.h new file mode 100644 index 0000000..92918f3 --- /dev/null +++ b/include_lib/media/media_new/media/audio_resample.h @@ -0,0 +1,85 @@ +/***************************************************************** +>file name : include_lib/media/media_develop/media/audio_resample.h +>author : lichao +>create time : Fri 07 Aug 2020 11:32:47 AM CST +*****************************************************************/ +#ifndef _AUDIO_RESAMPLE_H_ +#define _AUDIO_RESAMPLE_H_ +#include "typedef.h" +#include "media/audio_stream.h" + +#define AUDIO_HARDWARE_RESAMPLER 0 +#define AUDIO_SOFTWARE_RESAMPLER 1 + +struct audio_resampler; + +struct audio_resample_context { + u8 channel; + int in_sample_rate; + int out_sample_rate; + void *output_buff; + void *remain_addr; + u16 output_size; + u16 remain_len; + u16 process_len; + const struct audio_resampler *resampler; + void *priv; + struct audio_stream_entry entry; + int (*data_flush)(struct audio_resample_context *ctx, void *data, int len); + void *output_priv; + int (*output_handler)(void *priv, void *data, int len); +}; + + +struct audio_resample_data; + +struct audio_resampler { + u8 type; + int (*open)(struct audio_resample_context *ctx, u8 channel); + int (*resample)(struct audio_resample_context *ctx, + struct audio_resample_data *in, + struct audio_resample_data *out); + int (*write)(struct audio_resample_context *ctx, void *data, int len); + int (*reset_sample_rate)(struct audio_resample_context *ctx, int in_sample_rate, int out_sample_rate); + int (*stop)(struct audio_resample_context *ctx); + void (*close)(struct audio_resample_context *ctx); +}; + +/* + * 变采样输入输出数据 + */ +struct audio_resample_data { + void *buffer; //变采样数据缓冲地址 + int sample_rate; //采样率 + int sample_num; //缓冲内样点个数 + int offset; //已处理的样点偏移 + u8 ch_num; //样点的通道个数 +}; + +struct audio_resample_context *audio_resample_open(u8 ch_num, + u8 hardware_first, + void *output_priv, + int (*output_handler)(void *priv, void *data, int len)); + +int audio_resample_set_sample_rate(struct audio_resample_context *ctx, int in_sample_rate, int out_sample_rate); + +int audio_resample_set_sample_sync(struct audio_resample_context *ctx, int in_correct_rate, int out_correct_rate); + +int audio_resample(struct audio_resample_context *ctx, + struct audio_resample_data *in, + struct audio_resample_data *out); + +int audio_resample_stream_write(struct audio_resample_context *ctx, void *data, int len); + +void audio_resample_close(struct audio_resample_context *ctx); + +extern struct audio_resampler audio_resampler_begin[]; +extern struct audio_resampler audio_resampler_end[]; + +#define list_for_each_resampler(p) \ + for (p = audio_resampler_begin; p < audio_resampler_end; p++) + +#define REGISTER_AUDIO_RESAMPLER(resampler) \ + const struct audio_resampler resampler SEC(.audio_resampler) = { + +#endif diff --git a/include_lib/media/media_new/media/audio_splicing.h b/include_lib/media/media_new/media/audio_splicing.h new file mode 100644 index 0000000..8efb234 --- /dev/null +++ b/include_lib/media/media_new/media/audio_splicing.h @@ -0,0 +1,24 @@ + +#ifndef _AUDIO_SPLICING_H_ +#define _AUDIO_SPLICING_H_ + +#include "generic/typedef.h" + +void pcm_single_to_dual(void *out, void *in, u16 len); +void pcm_single_to_qual(void *out, void *in, u16 len); +void pcm_dual_to_qual(void *out, void *in, u16 len); +void pcm_dual_mix_to_dual(void *out, void *in, u16 len); +void pcm_dual_to_single(void *out, void *in, u16 len); +void pcm_qual_to_single(void *out, void *in, u16 len); +void pcm_single_l_r_2_dual(void *out, void *in_l, void *in_r, u16 in_len); +void pcm_fl_fr_rl_rr_2_qual(void *out, void *in_fl, void *in_fr, void *in_rl, void *in_rr, u16 in_len); +void pcm_flfr_rlrr_2_qual(void *out, void *in_flfr, void *in_rlrr, u16 in_len); +void pcm_fill_single_2_qual(void *out, void *in, u16 in_len, u8 idx); +void pcm_fill_flfr_2_qual(void *out, void *in_flfr, u16 in_len); +void pcm_fill_rlrr_2_qual(void *out, void *in_rlrr, u16 in_len); +void pcm_mix_buf(s32 *obuf, s16 *ibuf, u16 len); +void pcm_mix_buf_limit(s16 *obuf, s32 *ibuf, u16 len); +// 四声道转双声道(q0+q2,q1+q3) +void pcm_qual_to_dual(void *out, void *in, u16 len); + +#endif/*_AUDIO_SPLICING_H_*/ diff --git a/include_lib/media/media_new/media/audio_syncts.h b/include_lib/media/media_new/media/audio_syncts.h new file mode 100644 index 0000000..11085fe --- /dev/null +++ b/include_lib/media/media_new/media/audio_syncts.h @@ -0,0 +1,62 @@ +/***************************************************************** +>file name : audio_syncts.h +>create time : Mon 22 Mar 2021 02:41:39 PM CST +>description: +*****************************************************************/ + +#ifndef _AUDIO_SYNCTS_H_ +#define _AUDIO_SYNCTS_H_ +#include "typedef.h" + + +#define PCM_INSIDE_DAC 0 +#define PCM_OUTSIDE_DAC 1 + +#define AUDIO_NETWORK_LOCAL 0 +#define AUDIO_NETWORK_BT2_1 1 +#define AUDIO_NETWORK_BLE 2 +#define AUDIO_NETWORK_IPV4 3 + +#define TIME_US_FACTOR 32 +/* + * Audio同步变采样参数 + */ +struct audio_syncts_params { + unsigned char network; /*网络选择*/ + unsigned char pcm_device; /*PCM设备选择*/ + unsigned char nch; /*声道数*/ + unsigned char factor; /*timestamp的整数放大因子*/ + int rin_sample_rate; /*变采样输入采样率*/ + int rout_sample_rate; /*变采样输出采样率*/ + void *priv; /*私有数据*/ + int (*output)(void *, void *, int); /*变采样输出callback*/ +}; + +int audio_syncts_open(void **syncts, struct audio_syncts_params *params); + +int audio_syncts_next_pts(void *syncts, u32 timestamp); + +int audio_syncts_frame_filter(void *syncts, void *data, int len); + +void audio_syncts_close(void *syncts); + +u32 audio_syncts_get_dts(void *syncts); + +int audio_syncts_set_dts(void *syncts, u32 dts); + +int audio_syncts_trigger_resume(void *syncts, void *priv, void (*resume)(void *priv)); + +int audio_syncts_update_sample_rate(void *syncts, int sample_rate); + +void audio_syncts_resample_suspend(void *syncts); + +void audio_syncts_resample_resume(void *syncts); + +int sound_pcm_update_frame_num(void *syncts, int frames); + +int sound_pcm_syncts_latch_trigger(void *syncts); + +u32 sound_buffered_between_syncts_and_device(void *priv, u8 time_select); + +void sound_pcm_enter_update_frame(void *syncts); +#endif diff --git a/include_lib/media/media_new/media/audio_track.h b/include_lib/media/media_new/media/audio_track.h new file mode 100644 index 0000000..88a6db2 --- /dev/null +++ b/include_lib/media/media_new/media/audio_track.h @@ -0,0 +1,14 @@ +/***************************************************************** +>file name : audio_track.h +>author : lichao +>create time : Tue 22 Dec 2020 04:18:39 PM CST +*****************************************************************/ +#ifndef _AUDIO_TRACK_H_ +#define _AUDIO_TRACK_H_ + +void *audio_local_sample_track_open(u8 channel, int sample_rate, int period); +int audio_local_sample_track_in_period(void *c, int samples); +int audio_local_sample_track_rate(void *c); +void audio_local_sample_track_close(void *c); + +#endif diff --git a/include_lib/media/media_new/media/automute.h b/include_lib/media/media_new/media/automute.h new file mode 100644 index 0000000..1d6dd62 --- /dev/null +++ b/include_lib/media/media_new/media/automute.h @@ -0,0 +1,60 @@ +#ifndef AUDIO_AUTOMUTE_H +#define AUDIO_AUTOMUTE_H + +#include "generic/typedef.h" +#include "generic/list.h" + +#define AUDIO_EVENT_AUTO_MUTE 0x10 +#define AUDIO_EVENT_AUTO_UNMUTE 0x11 + +#define AUTOMUTE_CH 4 + +enum mute_value { + AUDIO_MUTE_DEFAULT = 0, + AUDIO_UNMUTE_DEFAULT, + AUDIO_MUTE_L_CH, + AUDIO_UNMUTE_L_CH, + AUDIO_MUTE_R_CH, + AUDIO_UNMUTE_R_CH, +}; + +struct pcm_energy { + u32 points; //计算多少个点 + u32 point_count; + s32 total_value; + /*void *priv;*/ + /*void (*output)(void *, u16, u8);*/ + s16 average_value; +}; + +struct automute_filter { + u32 mute_number; + u32 unmute_number; + u32 mute_count; + u32 unmute_count; +}; + +struct audio_automute { + struct pcm_energy energy[AUTOMUTE_CH]; + void (*handler)(u8 event, u8 channel); + u8 channels; + u8 pcm_mute; + u8 mute_channel; + u8 mute; + u32 mute_energy; + u32 unmute_energy; + u32 filt_points; + u32 filt_mute_number; + u32 filt_unmute_number; + struct automute_filter filt[AUTOMUTE_CH]; + u8 on; + u8 skip; +}; + +int audio_automute_open(struct audio_automute *automute); +void audio_automute_run(struct audio_automute *automute, void *data, int len); +void audio_automute_close(struct audio_automute *automute); +int audio_automute_onoff(struct audio_automute *automute, u8 onoff, u8 need_cb); +void audio_automute_skip(struct audio_automute *automute, u8 skip); + +#endif diff --git a/include_lib/media/media_new/media/cpu/br28/asm/anc.h b/include_lib/media/media_new/media/cpu/br28/asm/anc.h new file mode 100644 index 0000000..7384461 --- /dev/null +++ b/include_lib/media/media_new/media/cpu/br28/asm/anc.h @@ -0,0 +1,778 @@ +#ifndef _ANC_H_ +#define _ANC_H_ + +#include "generic/typedef.h" +#include "system/task.h" +#include "media/audio_def.h" +#include "asm/audio_adc.h" + +enum { + ANCDB_ERR_CRC = 1, + ANCDB_ERR_TAG, + ANCDB_ERR_PARAM, + ANCDB_ERR_STATE, +}; + +typedef enum { + ANC_OFF = 1, /*关闭模式*/ + ANC_ON, /*降噪模式*/ + ANC_TRANSPARENCY, /*通透模式*/ + ANC_BYPASS, /*训练模式*/ + ANC_TRAIN, /*训练模式*/ + ANC_TRANS_TRAIN, /*通透训练模式*/ +} ANC_mode_t; + +/*ANC状态*/ +enum { + ANC_STA_CLOSE = 0, + ANC_STA_INIT, + ANC_STA_OPEN, +}; + +typedef enum { + TRANS_ERR_TIMEOUT = 1, //训练超时 + TRANS_ERR_MICERR, //训练中MIC异常 + TRANS_ERR_FORCE_EXIT //强制退出训练 +} ANC_trans_errmsg_t; + +/*ANC MIC 类型*/ +enum { + ANC_MIC_TYPE_LFF = 0, + ANC_MIC_TYPE_LFB, + ANC_MIC_TYPE_RFF, + ANC_MIC_TYPE_RFB, +}; + +typedef enum { + //OLD + ANC_L_FF_IIR = 0x0, //左FF滤波器ID + ANC_L_FB_IIR = 0x1, //左FB滤波器ID + ANC_L_CMP_IIR = 0x2, //左音乐补偿滤波器ID + ANC_L_TRANS_IIR = 0x3, //左通透滤波器ID + ANC_L_FIR = 0x4, //(保留位,暂时不用) + // ANC_L_TRANS2_IIR = 0x5, + + //NEW + ANC_L_FF_FGQ = 0x6, //左FF滤波器FGQ + ANC_L_FB_FGQ = 0x7, //左FB滤波器FGQ + ANC_L_CMP_FGQ = 0x8, //左音乐补偿滤波器FGQ + ANC_L_TRANS_FGQ = 0x9, //左通透滤波器FGQ + ANC_L_FF_PARM = 0xA, //左FF参数ID + ANC_L_FB_PARM = 0xB, //左FB参数ID + ANC_L_CMP_PARM = 0xC, //左音乐补偿参数ID + ANC_L_TRANS_PARM = 0xD, //左通透参数ID + + //OLD + ANC_R_FF_IIR = 0x10, //右FF滤波器ID + ANC_R_FB_IIR = 0x11, //右FB滤波器ID + ANC_R_CMP_IIR = 0x12, //右音乐补偿滤波器ID + ANC_R_TRANS_IIR = 0x13, //右通透滤波器ID + ANC_R_FIR = 0x14, //(保留位,暂时不用) + // ANC_R_TRANS2_IIR = 0x15, + + //NEW + ANC_R_FF_FGQ = 0x16, //右FF滤波器FGQ + ANC_R_FB_FGQ = 0x17, //右FB滤波器FGQ + ANC_R_CMP_FGQ = 0x18, //右音乐补偿滤波器FGQ + ANC_R_TRANS_FGQ = 0x19, //右通透滤波器FGQ + ANC_R_FF_PARM = 0x1A, //右FF参数ID + ANC_R_FB_PARM = 0x1B, //右FB参数ID + ANC_R_CMP_PARM = 0x1C, //右音乐补偿参数ID + ANC_R_TRANS_PARM = 0x1D, //右通透参数ID + + //OTHER + ANC_L_ADAP_FRE = 0x20, + ANC_L_ADAP_PZ = 0x21, + ANC_L_ADAP_SZPZ = 0x22, + ANC_L_ADAP_TARGET = 0x23, + ANC_L_ADAP_GOLD_CURVE = 0x24,//自适应金机曲线 + ANC_L_ADAP_TARGET_CMP = 0x25, + ANC_R_ADAP_FRE = 0x30, + ANC_R_ADAP_PZ = 0x31, + ANC_R_ADAP_SZPZ = 0x32, + ANC_R_ADAP_TARGET = 0x33, + ANC_R_ADAP_GOLD_CURVE = 0x34, + ANC_R_ADAP_TARGET_CMP = 0x35, +} ANC_config_seg_id_t; + +//新增iir滤波器 type 枚举 +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; + +typedef enum { + ANC_ALOGM1 = 0, + ANC_ALOGM2, + ANC_ALOGM3, + ANC_ALOGM4, + ANC_ALOGM5, + ANC_ALOGM6, + ANC_ALOGM7, + ANC_ALOGM8, +} ANC_alogm_t; //ANC算法模式 + +typedef enum { + A_MIC0 = 0x0, //模拟MIC0 对应IO-PA1 PA2 + A_MIC1, //模拟MIC1 对应IO-PA3 PA4 + A_MIC2, //模拟MIC2 对应IO-PG7 PG8 + A_MIC3, //模拟MIC3 对应IO-PG5 PG6 + D_MIC0, //数字MIC0(plnk_dat0_pin-上升沿采样) + D_MIC1, //数字MIC1(plnk_dat1_pin-上升沿采样) + D_MIC2, //数字MIC2(plnk_dat0_pin-下降沿采样) + D_MIC3, //数字MIC3(plnk_dat1_pin-下降沿采样) + MIC_NULL = 0XFF, //没有定义相关的MIC +} ANC_mic_type_t; + +typedef enum { + ANC_POW_SEL_R_DAC_REF = 0x02, //功率输出R DAC+REFMIC + ANC_POW_SEL_R_DAC_ERR, //功率输出R DAC+ERRMIC + ANC_POW_SEL_L_DAC_REF, //功率输出L DAC+REFMIC + ANC_POW_SEL_L_DAC_ERR, //功率输出L DAC+ERRMIC +} ANC_pow_sel_t; + +typedef enum { + ANC_COEFF_MODE_NORMAL = 0x0, //自适应普通模式 + ANC_COEFF_MODE_ADAPTIVE = 0x1, //自适应滤波器模式 +} ANC_coeff_mode_t; + +//自适应解码任务打断状态 +typedef enum { + ANC_ADAPTIVE_DEC_WAIT_STOP = 0x0, //停止 + ANC_ADAPTIVE_DEC_WAIT_START, //启动 + ANC_ADAPTIVE_DEC_WAIT_RUN, //运行中 +} ANC_adaptive_dec_wait_t; + +//自适应滤波器数据状态 +typedef enum { + ANC_ADAPTIVE_DATA_EMPTY = 0x0, //数据为空 + ANC_ADAPTIVE_DATA_FROM_VM, //来源VM + ANC_ADAPTIVE_DATA_FROM_ALOGM, //来源算法 +} ANC_adaptive_data_from_t; + +// ANC fade gain通道 +typedef enum { + AUDIO_ANC_FADE_CH_LFF = 0x1, + AUDIO_ANC_FADE_CH_LFB = 0x2, + AUDIO_ANC_FADE_CH_RFF = 0x4, + AUDIO_ANC_FADE_CH_RFB = 0x8, +} ANC_fade_ch_t; + +/*ANC模式使能位*/ +#define ANC_OFF_BIT BIT(1) /*降噪关闭使能*/ +#define ANC_ON_BIT BIT(2) /*降噪模式使能*/ +#define ANC_TRANS_BIT BIT(3) /*通透模式使能*/ + +//ANC Ch ---eg:双声道 ANC_L_CH|ANC_R_CH +#define ANC_L_CH BIT(0) //通道左 +#define ANC_R_CH BIT(1) //通道右 + +//ANC各类增益对应符号位 +#define ANCL_FF_SIGN BIT(0) //左声道FF增益符号 +#define ANCL_FB_SIGN BIT(1) //左声道FB增益符号 +#define ANCL_TRANS_SIGN BIT(2) //左声道通透增益符号 +#define ANCL_CMP_SIGN BIT(3) //左声道音乐补偿增益符号 +#define ANCR_FF_SIGN BIT(4) //右声道FF增益符号 +#define ANCR_FB_SIGN BIT(5) //右声道FB增益符号 +#define ANCR_TRANS_SIGN BIT(6) //右声道通透增益符号 +#define ANCR_CMP_SIGN BIT(7) //右声道音乐补偿增益符号 + +//DRC中断标志 +#define ANCL_REF_DRC_ISR BIT(0) +#define ANCL_ERR_DRC_ISR BIT(1) +#define ANCR_REF_DRC_ISR BIT(2) +#define ANCR_ERR_DRC_ISR BIT(3) +#define ANC_ERR_DRC_ISR ANCL_ERR_DRC_ISR | ANCR_ERR_DRC_ISR +#define ANC_REF_DRC_ISR ANCL_REF_DRC_ISR | ANCR_REF_DRC_ISR + +//DRC模块使能标志 +#define ANC_DRC_FF_EN BIT(0) //DRC_FF使能标志 +#define ANC_DRC_FB_EN BIT(1) //DRC_FB使能标志 +#define ANC_DRC_TRANS_EN BIT(2) //DRC_TRANS使能标志 + +//ANC DUT音频模块使能控制 +#define ANC_DUT_ANC_ENABLE BIT(0) //ANC_DUT ANC使能 +#define ANC_DUT_ADC_ENABLE BIT(1) //ANC_DUT ADC使能 +#define ANC_DUT_DAC_ENABLE BIT(2) //ANC_DUT DAC使能 +#define ANC_DUT_CLOSE ANC_DUT_ANC_ENABLE | ANC_DUT_ADC_ENABLE | ANC_DUT_DAC_ENABLE //ANC_DUT模块关闭,正常开启所有模块 + +//ANC自适应模式 +#define ANC_ADAPTIVE_MANUAL_MODE 0 //自适应手动模式-手动切换等级 +#define ANC_ADAPTIVE_GAIN_MODE 1 //自适应增益模式-自动切换等级 + +/*ANC训练方式*/ +#define ANC_AUTO_UART 0 +#define ANC_AUTO_BT_SPP 1 +#define ANC_TRAIN_WAY ANC_AUTO_BT_SPP + +/*SZ频响获取默认算法模式*/ +#define ANC_SZ_EXPORT_DEF_ALOGM ANC_ALOGM3 + +/*ANC 测试模式类型*/ +#define ANC_TEST_TYPE_PCM 0 //MIC_SPK数据以PCM导出 +#define ANC_TEST_TYPE_FFT 1 //SZ数据累加FFT导出 + +/*ANC芯片版本定义(只读)*/ +#define ANC_CHIP_VERSION ANC_VERSION_BR28 + +/*ANC CFG读写标志*/ +#define ANC_CFG_READ 0x01 +#define ANC_CFG_WRITE 0x02 + +typedef struct { + u8 mode; //当前训练步骤 + u8 train_busy; //训练繁忙位 0-空闲 1-训练中 2-训练结束测试中 + u8 train_step; //训练系数 + u8 ret_step; //自适应训练系数值 + u8 auto_ts_en; //自动步进微调使能位 + u8 enablebit; //训练模式使能标志位 前馈|混合馈|通透 + u8 tool_time_flag; //工具修改时间标志 + u8 mic_dma_export_en; //从ANC DAM拿数,会消耗4*4K + u8 only_mute_train_en; //只跑静音训练保持sz,fz系数 + u16 timerout_id; //训练超时定时器ID + s16 fb0_gain; + s16 fb0sz_dly_en; + u16 fb0sz_dly_num; + int sz_gain; //静音训练sz 增益 + u32 sz_lower_thr; //误差MIC下限能量阈值 + u32 fz_lower_thr; //参考MIC下限能量阈值 + u32 sz_noise_thr; //误差MIC底噪阈值 + u32 fz_noise_thr; //参考MIC底噪阈值 + u32 sz_adaptive_thr; //误差MIC自适应收敛阈值 + u32 fz_adaptive_thr; //参考MIC自适应收敛阈值 + u32 wz_train_thr; //噪声训练阈值 +} anc_train_para_t; + +typedef struct { + u8 default_flag; //初始状态标志 + u8 fade_lvl; //淡入时间fade_lvl*100ms + u8 trigger_cnt; //触发计数 trigger_cnt*100ms + u16 gain; //目标增益 + u32 pow_lthr; //低阈值 + u32 pow_thr; //高阈值 +} anc_adap_param_t; + +//ANC耳道自适应相关结构体 +typedef struct { + u8 ff_yorder; //ANC耳道自适应FF IIR num + u8 fb_yorder; //ANC耳道自适应FB IIR num + u8 cmp_yorder; //ANC耳道自适应CMP IIR num + double *lff_coeff; /*耳道自适应-滤波器LFF暂存指针*/ + double *lfb_coeff; /*耳道自适应-滤波器LFB暂存指针*/ + double *lcmp_coeff; /*耳道自适应-滤波器LCMP暂存指针*/ + double *rff_coeff; /*耳道自适应-滤波器RFF暂存指针*/ + double *rfb_coeff; /*耳道自适应-滤波器RFB暂存指针*/ + double *rcmp_coeff; /*耳道自适应-滤波器RCMP暂存指针*/ + u8 *ref_ff_curve; /*耳道自适应-FF金机参考曲线*/ + int ref_ff_curve_len; /*耳道自适应-FF金机参考曲线长度*/ + void (*dma_done_cb)(void); +} anc_ear_adaptive_param_t; + +struct anc_sz_fft_t { + volatile u8 state; //状态 + u8 data_sel; //目标数据通道 + u8 alogm; //采样率信息 + u8 check_flag; //检查DAC有效数据标志 + u8 packet_cnt; //overlap拼包标志 + u8 packet_lcnt; //long buf overlap拼包标志 + volatile u8 busy; //run 繁忙标志 + int all_sample_cnt; //总样本计数 + int spk_sample_cnt[5];//spk区间样本计数 + int err_sample_cnt[5];//err区间样本次数 + s16 *packet_buf; //overlap 拼包buf + s16 *packet_lbuf; //long buf overlap 拼包buf + int *inbuf; //输入数据buf + float *out0_buf; //输出数据buf0 + float *out1_buf; //输出数据buf1 + float *out0_lbuf; //输出数据lbuf0 + float *out1_lbuf; //输出数据lbuf1 + void (*dma_run_hdl)(void); +}; + +typedef struct { + void (*dma_done_cb)(void); +} anc_adt_param_t; + +typedef struct { + u8 mic_errmsg; + u8 status; + u32 dat[4]; //ff_num/ff_dat/fb_num/fb_dat + u32 pow; + u32 temp_pow; + u32 mute_pow; +} anc_ack_msg_t; + +#define ANC_GAINS_VERSION 0X7012 //结构体版本号信息 +typedef struct { +//cfg + u16 version; //当前结构体版本号 + u8 dac_gain; //dac模拟增益 range 0-15; default 13 + u8 l_ffmic_gain; //ANCL FFmic增益 range 0-19; default 10 + u8 l_fbmic_gain; //ANCL FBmic增益 range 0-19; default 10 + u8 cmp_en; //音乐补偿使能 range 0-1; default 1 + u8 drc_en; //DRC使能 range 0-7; default 0 + u8 ahs_en; //AHS使能 range 0-1; default 1 + u8 ff_1st_dcc; //FF 1阶DCC档位 range 0-8; default 8 + u8 gain_sign; //ANC各类增益的符号 range 0-255; default 0 + u8 noise_lvl; //训练的噪声等级 range 0-255; default 0 + u8 fade_step; //淡入淡出步进 range 0-15; default 1 + u32 alogm; //ANC算法因素 + u32 trans_alogm; //通透算法因素 + float l_ffgain; //ANCL FF增益 range 0.0316(-30dB) - 31.622(+30dB); default 1.0(0dB) + float l_fbgain; //ANCL FB增益 range 0.0316(-30dB) - 31.622(+30dB); default 1.0(0dB) + float l_transgain; //ANCL 通透增益 range 0.0316(-30dB) - 31.622(+30dB); default 1.0(0dB) + float l_cmpgain; //ANCL 音乐补偿增益 range 0.0316(-30dB) - 31.622(+30dB); default 1.0(0dB) + float r_ffgain; //ANCR FF增益 range 0.0316(-30dB) - 31.622(+30dB); default 1.0(0dB) + float r_fbgain; //ANCR FB增益 range 0.0316(-30dB) - 31.622(+30dB); default 1.0(0dB) + float r_transgain; //ANCR 通透增益 range 0.0316(-30dB) - 31.622(+30dB); default 1.0(0dB) + float r_cmpgain; //ANCR 音乐补偿增益 range 0.0316(-30dB) - 31.622(+30dB); default 1.0(0dB) + + u8 drcff_zero_det; //DRCFF过零检测使能 range 0-1; default 0; + u8 drcff_dat_mode; //DRCFF_DAT模式 range 0-3; default 0; + u8 drcff_lpf_sel; //DRCFF_LPF档位 range 0-3; default 0; + u8 drcfb_zero_det; //DRCFB过零检测使 range 0-1; default 0; + u8 drcfb_dat_mode; //DRCFB_DAT模式 range 0-3; default 0; + u8 drcfb_lpf_sel; //DRCFB_LPF档位 range 0-3; default 0; + + u16 drcff_lthr; //DRCFF_LOW阈值 range 0-32767; default 0; + u16 drcff_hthr; //DRCFF_HIGH阈值 range 0-32767; default 32767; + s16 drcff_lgain; //DRCFF_LOW增益 range 0-32767; default 0; + s16 drcff_hgain; //DRCFF_HIGH增益 range 0-32767; default 1024; + s16 drcff_norgain; //DRCFF_NOR增益 range 0-32767; default 1024; + + u16 drcfb_lthr; //DRCFB_LOW阈值 range 0-32767; default 0; + u16 drcfb_hthr; //DRCFB_HIGH阈值 range 0-32767; default 32767; + s16 drcfb_lgain; //DRCFB_LOW增益 range 0-32767; default 0; + s16 drcfb_hgain; //DRCFB_HIGH增益 range 0-32767; default 1024; + s16 drcfb_norgain; //DRCFB_NOR增益 range 0-32767; default 1024; + + u16 drctrans_lthr; //DRCTRANS_LOW阈值 range 0-32767; default 0; + u16 drctrans_hthr; //DRCTRANS_HIGH阈值 range 0-32767; default 32767; + s16 drctrans_lgain; //DRCTRANS_LOW增益 range 0-32767; default 0; + s16 drctrans_hgain; //DRCTRANS_HIGH增益 range 0-32767; default 1024; + s16 drctrans_norgain; //DRCTRANS_NOR增益 range 0-32767; default 1024; + + u8 ahs_dly; //AHS_DLY range 0-15; default 1; + u8 ahs_tap; //AHS_TAP range 0-255; default 100; + u8 ahs_wn_shift; //AHS_WN_SHIFT range 0-15; default 9; + u8 ahs_wn_sub; //AHS_WN_SUB range 0-1; default 1; + u16 ahs_shift; //AHS_SHIFT range 0-65536; default 210; + u16 ahs_u; //AHS步进 range 0-65536; default 4000; + s16 ahs_gain; //AHS增益 range -32767-32767;default -1024; + u8 ahs_nlms_sel; //AHS_NLMS range 0-1; default 0; + u8 developer_mode; //GAIN开发者模式 range 0-1; default 0; + + float audio_drc_thr; //Audio DRC阈值 range -6.0-0; default -6.0dB; + + u8 r_ffmic_gain; //ANCR FFmic增益 range 0-19; default 10; + u8 r_fbmic_gain; //ANCR FBmic增益 range 0-19; default 10; + u8 fb_1st_dcc; //FB 1阶DCC档位 range 0-8; default 8; + u8 ff_2nd_dcc; //FF 2阶DCC档位 range 0-15; default 4; + u8 fb_2nd_dcc; //FB 2阶DCC档位 range 0-15; default 1; + u8 drc_ff_2dcc; //DRC FF动态DCC目标值 range 0-15; default 0; + u8 drc_fb_2dcc; //DRC FB动态DCC目标值 range 0-15; default 0; + + u8 adaptive_ref_en; //耳道自适应-金机曲线参考使能 + u16 drc_dcc_det_time; //DRC DCC检测时间ms range 0-32767; default 300; + u16 drc_dcc_res_time; //DRC DCC恢复时间ms range 0-32767; default 20; + + float adaptive_ref_fb_f; //FB参考F最深点位置中心值 range 80-200; default 135 + float adaptive_ref_fb_g; //FB参考G最深点深度 range 12-22; default 18 + float adaptive_ref_fb_q; //FB参考Q最深点降噪宽度 range 0.4-1.2; default 0.6 + + //相关性检测 HD param + u8 hd_en; //啸叫检测使能 range 0-1; default 1; + u8 hd_corr_thr; //相关性检测阈值 range 0-255; default 232; + u16 hd_corr_gain; //相关性预设增益 range 0-1024 default 512; + u8 hd_corr_dly; //相关性检测延时 range 2-30; default 30; + + //功率检测全频带,增益可预设 + u8 hd_pwr_rate; //功率检测回音处理前后比例 range 0-3; default 2; + u8 hd_pwr_ctl_gain_en; //功率检测是否使用预设的增益使能 range 0-1; default 0; + u8 hd_pwr_ctl_ahsrst_en;//功率检测是否复位AHS range 0-1; default 1; + u16 hd_pwr_thr; //功率检测阈值设置,增益自动 range 0-32767; default 18000; + u16 hd_pwr_ctl_gain; //功率检测预设增益 range 0-16384; default 1638; + + //可选带宽 增益自动调节 + u8 hd_pwr_ref_ctl_en; //参考功率检测自动调增益使能 range 0-1; default 0; + u8 hd_pwr_err_ctl_en; //误差功率检测自动调增益使能 range 0-1; default 0; + u16 hd_pwr_ref_ctl_hthr; //参考功率检测H_THR,触发中断 range 0-32767; default 2000; + u16 hd_pwr_ref_ctl_lthr1; //参考功率检测L1_THR range 0-32767; default 1000; + u16 hd_pwr_ref_ctl_lthr2; //参考功率检测L2_THR,小于L1_THR range 0-32767; default 200; + + u16 hd_pwr_err_ctl_hthr; //误差功率检测H_THR,触发中断 range 0-32767; default 2000; + u16 hd_pwr_err_ctl_lthr1; //误差功率检测L1_THR range 0-32767; default 1000; + u16 hd_pwr_err_ctl_lthr2; //误差功率检测L2_THR,小于L1_THR range 0-32767; default 200; + u16 reserve_2; + +} anc_gain_param_t; + +/*ANCIF配置区滤波器系数gains*/ +typedef struct { + anc_gain_param_t gains; + u8 reserve[236 - 156]; //236 + 20byte(header) + // u8 reserve[236 - 128]; //236 + 20byte(header) +} anc_gain_t; + +typedef struct { + u8 start; //ANC状态 + u8 mode; //ANC模式:降噪关;降噪开;通透... + u8 production_mode; //量产模式 + u8 developer_mode; //开发者模式 + u8 anc_fade_en; //ANC淡入淡出使能 + u8 tool_enablebit; //ANC动态使能,使用过程中可随意控制 + u8 debug_sel; //ANCdebug data输出源 + u8 lff_en; //左耳FF使能 + u8 lfb_en; //左耳FB使能 + u8 rff_en; //右耳FF使能 + u8 rfb_en; //右耳FB使能 + u8 online_busy; //在线调试繁忙标志位 + u8 fade_time_lvl; //淡入时间等级,越大时间越长 + u8 mic_type[4]; //ANC mic类型控制位 + u8 dut_audio_enablebit; //ANC_DUT 音频使能控制,用于分离模块功耗 + u8 drc_dcc_en; //drc动态调整DCC使能 + u8 adc_ch; //adc数字通道 + u8 adaptive_mode; //ANC场景自适应模式 + u8 anc_lvl; //ANC等级 + u8 lff_yorder; //LFF IIR NUM + u8 lfb_yorder; //LFB IIR NUM + u8 lcmp_yorder; //LTRANS IIR NUM + u8 ltrans_yorder; //LCMP IIR NUM + u8 rff_yorder; //RFF IIR NUM + u8 rfb_yorder; //RFB IIR NUM + u8 rcmp_yorder; //RTRANS IIR NUM + u8 rtrans_yorder; //RCMP IIR NUM + u8 lr_lowpower_en; //ANCLR(立体声)配置省功耗使能 + u8 anc_coeff_mode; /*ANC coeff模式-0 普通coeff; 1 自适应coeff*/ + u8 test_type; //ANC测试模式类型,获取SZ频响 or 获取SPK_MIC PCM数据 + u16 anc_fade_gain; //ANC淡入淡出增益 + u16 drc_fade_gain; //DRC淡出增益 + u16 drc_time_id; //DRCtimeout定时器ID + u16 enablebit; //ANC模式:FF,FB,HYBRID + u16 pow_export_en; //ANC功率输出使能 + u32 coeff_size; //ANC 读滤波器总长度 + u32 write_coeff_size; //ANC 写滤波器总长度 + int train_err; //训练结果 0:成功 other:失败 + u32 gains_size; //ANC 滤波器长度 + + int *debug_buf; //测试数据流,最大65536byte(堆) + s32 *lfir_coeff; //FZ补偿滤波器表 + s32 *rfir_coeff; //FZ补偿滤波器表 + double *lff_coeff; //左耳FF滤波器 + double *lfb_coeff; //左耳FB滤波器 + double *lcmp_coeff; //左耳cmp滤波器 + double *ltrans_coeff; //左耳通透滤波器 + double *rff_coeff; //右耳FF滤波器 + double *rfb_coeff; //右耳FB滤波器 + double *rcmp_coeff; //右耳cmp滤波器 + double *rtrans_coeff; //右耳通透滤波器 + double *trans_default_coeff; //通透默认滤波器 + volatile u8 ch; //ANC通道选择 : ANC_L_CH | ANC_R_CH + /*开智能免摘开通透需要开fb*/ + float ltrans_fbgain; //ANCL FB通透增益 range 0.0316(-30dB) - 31.622(+30dB); default 1.0(0dB) + float rtrans_fbgain; //ANCR FB通透增益 range 0.0316(-30dB) - 31.622(+30dB); default 1.0(0dB) + double *ltrans_fb_coeff; //左耳FB通透滤波器 + double *rtrans_fb_coeff; //右耳FB通透滤波器 + u8 ltrans_fb_yorder; //LCMP IIR NUM + u8 rtrans_fb_yorder; //RCMP IIR NUM + + anc_gain_param_t gains; + audio_adc_mic_mana_t mic_param[4]; //ANC MIC 控制参数 + anc_train_para_t train_para;//训练参数结构体 + anc_ear_adaptive_param_t *adaptive; + anc_adt_param_t *adt; + struct anc_sz_fft_t sz_fft; + + void (*train_callback)(u8, u8); + void (*pow_callback)(anc_ack_msg_t *msg_t, u8 setp); + int (*cfg_online_deal_cb)(u8, anc_gain_t *); + void (*post_msg_drc)(void); + void (*post_msg_debug)(void); + void (*adc_set_buffs_cb)(void); + void (*biquad2ab)(float gain, float f, float fs, float q, double *a0, double *a1, double *a2, double *b0, double *b1, double *b2, int type); + void (*mult_gain_set)(u8 gain_id, int data); + void (*pow_adap_fade)(u16 gain); + u8 adt_state;//智能免摘开启状态 +} audio_anc_t; + + +#define ANC_DB_HEAD_LEN 20/*ANC配置区数据头长度*/ +#define ANCIF_GAIN_TAG_01 "ANCGAIN01" +#define ANCIF_COEFF_TAG_01 "ANCCOEF01" +#define ANCIF_GAIN_TAG ANCIF_GAIN_TAG_01 //当前增益配置版本 +#define ANCIF_COEFF_TAG ANCIF_COEFF_TAG_01 //当前系数配置版本 +#define ANCIF_HEADER_LEN 10 +typedef struct { + u32 total_len; //4 后面所有数据加起来长度 + u16 group_crc; //6 group_type开始做的CRC,更新数据后需要对应更新CRC + u16 group_type; //8 + u16 group_len; //10 header开始到末尾的长度 + char header[ANCIF_HEADER_LEN];//20 + int coeff[0]; +} anc_db_head_t; + +#define _PACKED __attribute__((packed)) +struct anc_param_head_t { + u16 id; + u16 offset; + u16 len; +} _PACKED; + +/*ANCIF配置区滤波器系数coeff*/ +typedef struct { + u16 version; + u16 cnt; + u8 dat[0]; //小心double访问非对齐异常 +} anc_coeff_t; + +/* ANC 数据拼接结构体 */ +typedef struct { + u16 version; + u16 cnt; + u16 last_len; + u16 last_total_len; + u16 dat_len; //记录数据包dat的长度 + u8 *dat; //指向数据包的地址 +} anc_packet_data_t; + +typedef struct { + u8 type; + float a[3]; +} _PACKED anc_fr_t; + +typedef struct { + float iir_gain; +} _PACKED anc_mult_gain_t; + +typedef struct { + anc_fr_t *lff; + anc_fr_t *lfb; + anc_fr_t *lcmp; + anc_fr_t *rff; + anc_fr_t *rfb; + anc_fr_t *rcmp; +} anc_iir_t; + + +int audio_anc_train(audio_anc_t *param, u8 en); + +/* + *Description : audio_anc_run + *Arguements : param is audio anc param + *Returns : 0 open success + * : -EPERM 不支持ANC + * : -EINVAL 参数错误 + *Notes : + */ +int audio_anc_run(audio_anc_t *param); + +int audio_anc_close(); + +/* +********************************************************************* +* audio_anc_fade_cfg_set +* Description: ANC fade 基础配置 +* Arguments : en 淡入淡出使能; + step 默认1,淡入步进,越大越快越容易有杂音 + slow 默认0,缓慢步进,越大越慢 +* Return : None. +* Note(s) : None. +********************************************************************* +*/ +void audio_anc_fade_cfg_set(u8 en, u8 step, u8 slow); + +/* +********************************************************************* +* audio_anc_fade +* Description: ANC fade 增益配置 +* Arguments : ch 目标通道(enum ANC_fade_ch_t); + gain 目标fade增益 +* Return : None. +* Note(s) : None. +********************************************************************* +*/ +void audio_anc_fade(u8 ch, u16 gain); + +/* +********************************************************************* +* audio_anc_fade_dly_get +* Description: ANC根据采样率计算,淡出淡入时间 +* Arguments : target_value 淡入/出目标值, alogm 当前采样率 +* Return : dly 延时时间(ms) +* Note(s) : None. +********************************************************************* +*/ +int audio_anc_fade_dly_get(int target_value, int alogm); + +void anc_coeff_online_update(audio_anc_t *param, u8 hd_reset_en); + +int anc_coeff_size_count(audio_anc_t *param); + +/*ANC配置id*/ +enum { + ANC_DB_COEFF, //ANC系数 + ANC_DB_GAIN, //ANC增益 + ANC_DB_MAX, +}; + +typedef struct { + u8 state; //ANC配置区状态 + u16 total_size; //ANC配置区总大小 +} anc_db_t; + +/*anc配置区初始化*/ +int anc_db_init(void); +/*根据配置id获取不同的anc配置*/ +int *anc_db_get(u8 id, u32 *len); +/* + *gain:增益配置,没有的话传NULL + *coeff:系数配置,没有的话传NULL + */ +int anc_db_put(audio_anc_t *param, anc_gain_t *gain, anc_coeff_t *coeff); +/*anc 音乐补偿模块在线开关*/ +void audio_anc_cmp_en(audio_anc_t *param, u8 en); + +int anc_coeff_single_fill(audio_anc_t *param, anc_coeff_t *target_coeff); + +void audio_anc_dcc_set(u8 ref_1_dcc, u8 err_1_dcc, u8 ref_2_dcc, u8 err_2_dcc); + +void audio_anc_gain_sign(audio_anc_t *param); + +void audio_anc_drc_ctrl(audio_anc_t *param, float drc_ratio); + +void audio_anc_en_set(u8 en); + +void audio_anc_norgain(s16 ffgain, s16 fbgain); +/*anc ff增益设置API*/ +void audio_anc_ffgain_set(s16 l_gain, s16 r_gain); +/*anc fb增益设置API*/ +void audio_anc_fbgain_set(s16 l_gain, s16 r_gain); + +void audio_anc_tool_en_ctrl(audio_anc_t *param, u8 enablebit); + +int audio_anc_gains_version_verify(audio_anc_t *param, anc_gain_t *cfg_target); + +void audio_anc_drc_process(void); + +void audio_anc_max_yorder_verify(audio_anc_t *param); + +void audio_anc_param_normalize(audio_anc_t *param); + +void audio_anc_param_init(audio_anc_t *param); + +int anc_cfg_online_deal(u8 cmd, anc_gain_t *cfg); + +void audio_anc_drc_process(void); + +void audio_anc_debug_data_output(void); + +void audio_anc_debug_cbuf_sel_set(u8 sel); + +void audio_anc_debug_extern_trigger(u8 flag); + +/*播歌状态下特殊处理API*/ +void audio_anc_mix_process(u8 en); + +/*ANC模块复位*/ +void audio_anc_reset(audio_anc_t *param, u8 fade_en); + +/********************工具交互API*************************/ + +/*设置结果回调函数*/ +void anc_api_set_callback(void (*callback)(u8, u8), void (*pow_callback)(anc_ack_msg_t *, u8)); + +/*设置淡入淡出使能*/ +void anc_api_set_fade_en(u8 en); + +u8 anc_fade_ctr_ch_check(u8 ch); + +/*获取ANC淡入淡出使能*/ +u8 anc_api_get_fade_en(void); + +/*获取参数结构体*/ +anc_train_para_t *anc_api_get_train_param(void); + +/*获取步进*/ +u8 anc_api_get_train_step(void); + +/*设置通透目标能量值*/ +void anc_api_set_trans_aim_pow(u32 pow); + +/*ANC在线调试标志设置*/ +void anc_online_busy_set(u8 en); + +/*ANC在线调试标志获取*/ +u8 anc_online_busy_get(void); + +/*ANC滤波器大小设置*/ +void anc_coeff_size_set(u8 mode, int len); + +/*ANC滤波器大小获取*/ +int anc_coeff_size_get(u8 mode); + +/*ANC滤波器参数填充*/ +int anc_coeff_fill(anc_coeff_t *db_coeff); + +/*更新DRC 动态DCC使能设置*/ +void anc_drc_dcc_en_set(audio_anc_t *param); + +/*ANC功率数据获取,长度为8byte*/ +void audio_anc_pow_get(u16 *pow); + +/*ANC功率输出使能控制*/ +void audio_anc_pow_export_en(u8 en, u8 tool_en); + +/*ANC滤波器格式校验*/ +int anc_coeff_check(anc_coeff_t *db_coeff, u16 len); + +/*ANC量产模式设置*/ +void anc_production_mode_set(u8 en); + +void audio_anc_fr_format(u8 *out_dat, float *fr, u8 order, const u8 *type); + +void audio_anc_adaptive_data_analsis(anc_iir_t *iir); + +anc_packet_data_t *anc_data_catch(anc_packet_data_t *row_data_packet, u8 *buf, u16 len, u16 id, u8 init_flag); + +int anc_adaptive_ff_ref_data_get(u8 **buf); + +void anc_adaptive_ff_ref_data_free(void); + +int anc_adaptive_fb_ref_data_get(u8 **buf); + +void anc_adaptive_ff_ref_data_save(u8 *buf, int len); + +void free_anc_data_packet(anc_packet_data_t *anc_data_packet); + +/*******************ANC增益自适应************************/ +/*ANC自适应初始化*/ +void anc_pow_adap_init(audio_anc_t *param, anc_adap_param_t *ref_p, anc_adap_param_t *err_p, \ + u8 ref_max_lvl, u8 err_max_lvl); + +/*ANC自适应启动*/ +void audio_anc_pow_adap_start(); + +/*ANC自适应关闭*/ +void audio_anc_pow_adap_stop(void); + +/*ANC自适应增益切换定时器注册*/ +void anc_pow_adap_fade_timer_add(int ref_lvl, int err_lvl); + +/*ANC自适应当前增益等级获取*/ +int anc_pow_adap_lvl_get(u8 anc_type); + +/*设置当前的ANC增益等级, 只有普通增益模式才可以设置*/ +void audio_anc_lvl_set(u8 lvl, u8 ex_en); + + +void audio_anc_sz_fft_start(audio_anc_t *param, int len); +void audio_anc_sz_fft_run(audio_anc_t *param); +void audio_anc_sz_fft_stop(audio_anc_t *param); +int audio_anc_sz_fft_outbuf_get(u8 **p); +void audio_anc_sz_fft_outbuf_release(void); +void audio_anc_sz_fft_trigger(void); + +#endif/*_ANC_H_*/ diff --git a/include_lib/media/media_new/media/cpu/br28/asm/audio_adc.h b/include_lib/media/media_new/media/cpu/br28/asm/audio_adc.h new file mode 100644 index 0000000..2aa06ad --- /dev/null +++ b/include_lib/media/media_new/media/cpu/br28/asm/audio_adc.h @@ -0,0 +1,361 @@ +#ifndef AUDIO_ADC_H +#define AUDIO_ADC_H + +#include "generic/typedef.h" +#include "generic/list.h" +#include "generic/atomic.h" +#include "system/spinlock.h" + +/*无电容电路*/ +#define SUPPORT_MIC_CAPLESS 1 + +#define BR22_ADC_BIT_FLAG_FADE_ON BIT(31) + +#define FADE_OUT_IN 1 +#define FADE_OUT_TIME_MS 2 + +#define LADC_STATE_INIT 1 +#define LADC_STATE_OPEN 2 +#define LADC_STATE_START 3 +#define LADC_STATE_STOP 4 + +#define FPGA_BOARD 0 + +#define LADC_MIC 0 +#define LADC_LINEIN 1 + +#define SOURCE_MONO_LEFT 0 +#define SOURCE_MONO_RIGHT 1 +#define SOURCE_MONO_LEFT_RIGHT 2 + +#define ADC_DEFAULT_PNS 128 + +/* 通道选择 */ +#define AUDIO_ADC_MIC_0 BIT(0) // PA1 +#define AUDIO_ADC_MIC_1 BIT(1) // PA3 +#define AUDIO_ADC_MIC_2 BIT(2) // PG8 +#define AUDIO_ADC_MIC_3 BIT(3) // PG6 +#define AUDIO_ADC_LINE0 BIT(0) // PA1 +#define AUDIO_ADC_LINE1 BIT(1) // PA3 +#define AUDIO_ADC_LINE2 BIT(2) // PG8 +#define AUDIO_ADC_LINE3 BIT(3) // PG6 +#define PLNK_MIC BIT(6) //PDM MIC +#define ALNK_MIC BIT(7) //IIS MIC + + +/*mic_mode 工作模式定义*/ +#define AUDIO_MIC_CAP_MODE 0 //单端隔直电容模式 +#define AUDIO_MIC_CAP_DIFF_MODE 1 //差分隔直电容模式 +#define AUDIO_MIC_CAPLESS_MODE 2 //单端省电容模式 + +struct adc_platform_data { + u8 mic_ldo_vsel : 3;//0:1.3v 1:1.4v 2:1.5v 3:2.0v 4:2.2v 5:2.4v 6:2.6v 7:2.8v + u8 mic_ldo_isel : 2; //MIC通道电流档位选择 + u8 reserved: 3; + u8 mic_capless; //MIC免电容方案 + //MIC免电容方案和mic bias供电方案需要设置,影响MIC的偏置电压 1:16K 2:7.5K 3:5.1K 4:6.8K 5:4.7K 6:3.5K 7:2.9K 8:3K 9:2.5K 10:2.1K 11:1.9K 12:2K 13:1.8K 14:1.6K 15:1.5K 16:1K 31:0.6K + u8 mic_bias_res; + u8 mic1_bias_res; + u8 mic2_bias_res; + u8 mic3_bias_res; + + u32 mic_mode : 3; //MIC0工作模式 + u32 mic1_mode : 3; //MIC1工作模式 + u32 mic2_mode : 3; //MIC2工作模式 + u32 mic3_mode : 3; //MIC3工作模式 + u32 mic_bias_inside : 1; //MIC0电容隔直模式使用内部mic偏置 PA2 + u32 mic1_bias_inside : 1; //MIC1电容隔直模式使用内部mic偏置 PA4 + u32 mic2_bias_inside : 1; //MIC2电容隔直模式使用内部mic偏置 PG7 + u32 mic3_bias_inside : 1; //MIC3电容隔直模式使用内部mic偏置 PG5 + u32 mic_ldo_pwr : 1; // MICLDO供电到PAD(PA0)控制使能 + u32 lowpower_lvl : 2; //ADC低功耗等级 + + u8 mic_ldo_state; + u8 mic_dcc; //mic的去直流dcc寄存器配置值,可配0到15,数值越大,其高通转折点越低 + u8 anc_adt_en; + u8 anc_adt_mic_ch_num; + u8 adc_max_ch_en; + u8 max_channel_num; +}; + +/* + * p11系统VCO ADC mic模拟配置数据 + * 仅支持mic0,故应和主系统mic0对应 + * + */ +struct vco_adc_platform_data { + u8 mic_mode; + u8 mic_ldo_vsel; + u8 mic_ldo_isel; + u8 mic_bias_en; + u8 mic_bias_res; + u8 mic_bias_inside; + u8 mic_ldo2PAD_en; + u8 adc_rbs; + u8 adc_rin; + u8 adc_test; //VCO ADC测试使能,该配置用作ADC测试,届时AVAD、DVAD算法将无效 +}; + +/* + * p11 VAD电源驱动参数和模拟电源域参数配置 + * 先放在adc模拟部分管理 + */ +struct vad_power_data { + u8 ldo_vs; + u8 ldo_is; + u8 lowpower; + u8 clock; + u8 clock_x2ds_disable; + u8 acm_select; +}; + +struct vad_mic_platform_data { + struct vco_adc_platform_data mic_data; + struct vad_power_data power_data; +}; + +struct capless_low_pass { + u16 bud; //快调边界 + u16 count; + u16 pass_num; + u16 tbidx; +}; + +struct audio_adc_attr { + u8 gain; + u16 sample_rate; + u16 irq_time; + u16 irq_points; +}; + +struct adc_stream_ops { + void (*buf_reset)(void *priv); + void *(*alloc_space)(void *priv, u32 *len); + void (*output)(void *priv, void *buf, u32 len); +}; + +struct audio_adc_output_hdl { + struct list_head entry; + void *priv; + void (*handler)(void *, s16 *, int); +}; + +struct audio_adc_hdl { + struct list_head head; + /*void *priv; + const struct adc_stream_ops *ops;*/ + struct adc_platform_data *pd; + spinlock_t lock; + atomic_t ref; + struct audio_adc_attr attr; + u16 pause_srp; + u16 pns; + u8 fifo_full; + u8 channel; + u8 channel_num; + u8 ch_sel; + u8 input; + u8 state; + + union { + struct { + u8 out2dac : 1; + u8 out_l : 1; + u8 out_r : 1; + u8 out_mix : 1; + u8 cha_idx : 2; + } ladc; + u8 param; + } u; +#if FADE_OUT_IN + u8 fade_on; + volatile u8 ref_gain; + volatile int fade_timer; +#endif +#if SUPPORT_MIC_CAPLESS + struct capless_low_pass lp; +#endif +}; + + +struct adc_mic_ch { + struct audio_adc_hdl *adc; + u8 gain; + u8 gain1; + u8 gain2; + u8 gain3; + u8 buf_num; + u16 buf_size; + s16 *bufs; + u16 sample_rate; + void (*handler)(struct adc_mic_ch *, s16 *, u16); +}; + +struct adc_linein_ch { + struct audio_adc_hdl *adc; + u8 gain; + u8 gain1; + u8 gain2; + u8 gain3; + u8 buf_num; + u16 buf_size; + s16 *bufs; + u16 sample_rate; + void (*handler)(struct adc_mic_ch *, s16 *, u16); +}; +//MIC相关管理结构 +typedef struct { + u8 en; //MIC使能 + u8 type; //FF_MIC使能 + u8 gain; //MIC增益 + u8 mult_flag; //通话复用标志 +} audio_adc_mic_mana_t; + +void audio_adc_init(struct audio_adc_hdl *, struct adc_platform_data *); + +void audio_adc_add_output_handler(struct audio_adc_hdl *, struct audio_adc_output_hdl *); + +void audio_adc_del_output_handler(struct audio_adc_hdl *, struct audio_adc_output_hdl *); + +void audio_adc_irq_handler(struct audio_adc_hdl *adc); + +/* +********************************************************************* +* Audio ADC Mic Open +* Description: 打开mic采样通道 +* Arguments : mic mic操作句柄 +* ch mic通道索引 +* adc adc模块操作句柄 +* Return : 0 成功 其他 失败 +* Note(s) : None. +********************************************************************* +*/ +int audio_adc_mic_open(struct adc_mic_ch *mic, int ch, struct audio_adc_hdl *adc); +int audio_adc_mic1_open(struct adc_mic_ch *mic, int ch, struct audio_adc_hdl *adc); +int audio_adc_mic2_open(struct adc_mic_ch *mic, int ch, struct audio_adc_hdl *adc); +int audio_adc_mic3_open(struct adc_mic_ch *mic, int ch, struct audio_adc_hdl *adc); + +/* +********************************************************************* +* Audio ADC Mic Gain +* Description: 设置mic增益 +* Arguments : mic mic操作句柄 +* gain mic增益 +* Return : 0 成功 其他 失败 +* Note(s) : MIC增益范围:0(-8dB)~19(30dB),step:2dB,level(4)=0dB +********************************************************************* +*/ +int audio_adc_mic_set_gain(struct adc_mic_ch *mic, int gain); +int audio_adc_mic1_set_gain(struct adc_mic_ch *mic, int gain); +int audio_adc_mic2_set_gain(struct adc_mic_ch *mic, int gain); +int audio_adc_mic3_set_gain(struct adc_mic_ch *mic, int gain); + +/* +********************************************************************* +* Audio ADC Mic Pre_Gain +* Description: 设置mic第一级/前级增益 +* Arguments : en 前级增益使能(0:6dB 1:0dB) +* Return : None. +* Note(s) : 前级增益只有0dB和6dB两个档位 +********************************************************************* +*/ +void audio_adc_mic_0dB_en(bool en); +void audio_adc_mic1_0dB_en(bool en); +void audio_adc_mic2_0dB_en(bool en); +void audio_adc_mic3_0dB_en(bool en); + +/* +********************************************************************* +* Audio ADC linein Open +* Description: 打开linein采样通道 +* Arguments : linein linein操作句柄 +* ch linein通道索引 +* adc adc模块操作句柄 +* Return : 0 成功 其他 失败 +* Note(s) : None. +********************************************************************* +*/ +int audio_adc_linein_open(struct adc_linein_ch *linein, int ch, struct audio_adc_hdl *adc); +int audio_adc_linein1_open(struct adc_linein_ch *linein, int ch, struct audio_adc_hdl *adc); +int audio_adc_linein2_open(struct adc_linein_ch *linein, int ch, struct audio_adc_hdl *adc); +int audio_adc_linein3_open(struct adc_linein_ch *linein, int ch, struct audio_adc_hdl *adc); + +/* +********************************************************************* +* Audio ADC linein Gain +* Description: 设置linein增益 +* Arguments : linein linein操作句柄 +* gain linein增益 +* Return : 0 成功 其他 失败 +* Note(s) : linein增益范围:0(-8dB)~19(30dB),step:2dB,level(4)=0dB +********************************************************************* +*/ +int audio_adc_linein_set_gain(struct adc_linein_ch *linein, int gain); +int audio_adc_linein1_set_gain(struct adc_linein_ch *linein, int gain); +int audio_adc_linein2_set_gain(struct adc_linein_ch *linein, int gain); +int audio_adc_linein3_set_gain(struct adc_linein_ch *linein, int gain); + +/* +********************************************************************* +* Audio ADC linein Pre_Gain +* Description: 设置linein第一级/前级增益 +* Arguments : en 前级增益使能(0:6dB 1:0dB) +* Return : None. +* Note(s) : 前级增益只有0dB和6dB两个档位 +********************************************************************* +*/ +void audio_adc_linein_0dB_en(bool en); +void audio_adc_linein1_0dB_en(bool en); +void audio_adc_linein2_0dB_en(bool en); +void audio_adc_linein3_0dB_en(bool en); + + +/* +********************************************************************* +* AUDIO MIC_LDO Control +* Description: mic电源mic_ldo控制接口 +* Arguments : index ldo索引(MIC_LDO/MIC_LDO_BIAS0/MIC_LDO_BIAS1) +* en 使能控制 +* pd audio_adc模块配置 +* Return : 0 成功 其他 失败 +* Note(s) : (1)MIC_LDO输出不经过上拉电阻分压 +* MIC_LDO_BIAS输出经过上拉电阻分压 +* (2)打开一个mic_ldo示例: +* audio_mic_ldo_en(MIC_LDO,1,&adc_data); +* (2)打开多个mic_ldo示例: +* audio_mic_ldo_en(MIC_LDO | MIC_LDO_BIAS,1,&adc_data); +********************************************************************* +*/ +/*MIC LDO index输出定义*/ +#define MIC_LDO BIT(0) //PA0输出原始MIC_LDO +#define MIC_LDO_BIAS0 BIT(1) //PA2输出经过内部上拉电阻分压的偏置 +#define MIC_LDO_BIAS1 BIT(2) //PA4输出经过内部上拉电阻分压的偏置 +#define MIC_LDO_BIAS2 BIT(3) //PG7输出经过内部上拉电阻分压的偏置 +#define MIC_LDO_BIAS3 BIT(4) //PG5输出经过内部上拉电阻分压的偏置 +int audio_adc_mic_ldo_en(u8 index, u8 en, struct adc_platform_data *pd); + +int audio_adc_mic_set_sample_rate(struct adc_mic_ch *mic, int sample_rate); + +int audio_adc_mic_set_buffs(struct adc_mic_ch *mic, s16 *bufs, u16 buf_size, u8 buf_num); + +int audio_adc_mic_set_output_handler(struct adc_mic_ch *mic, + void (*handler)(struct adc_mic_ch *, s16 *, u16)); + +int audio_adc_mic_start(struct adc_mic_ch *mic); + +int audio_adc_mic_close(struct adc_mic_ch *mic); + +int audio_adc_linein_start(struct adc_linein_ch *linein); + +int audio_adc_linein_close(struct adc_linein_ch *linein); + +void audio_anc_mic_gain(audio_adc_mic_mana_t *mic_param, u8 mult_gain_en); + +void audio_anc_mic_open(audio_adc_mic_mana_t *mic_param, u8 trans_en, u8 adc_ch); + +void audio_anc_mic_close(audio_adc_mic_mana_t *mic_param); + +int audio_adc_linein_set_sample_rate(struct adc_linein_ch *linein, int sample_rate); + +int audio_adc_linein_set_buffs(struct adc_linein_ch *linein, s16 *bufs, u16 buf_size, u8 buf_num); +#endif diff --git a/include_lib/media/media_new/media/cpu/br28/asm/audio_linein.h b/include_lib/media/media_new/media/cpu/br28/asm/audio_linein.h new file mode 100644 index 0000000..e783ea5 --- /dev/null +++ b/include_lib/media/media_new/media/cpu/br28/asm/audio_linein.h @@ -0,0 +1,34 @@ +#ifndef _AUDIO_LINEIN_H_ +#define _AUDIO_LINEIN_H_ + +#include "generic/typedef.h" +#include "asm/audio_adc.h" + +/* + *ch: + *amux_en: + */ +int audio_linein0_open(u8 ch, u8 amux_en); +int audio_linein0_close(u8 ch, u8 amux_en); +int audio_linein1_open(u8 ch, u8 amux_en); +int audio_linein1_close(u8 ch, u8 amux_en); +int audio_linein2_open(u8 ch, u8 amux_en); +int audio_linein2_close(u8 ch, u8 amux_en); +/* + * + */ +void audio_linein_mute(u8 mute); +/* + * + */ +void audio_linein_gain(u8 gain); + +void audio_linein_bias(u8 ch, u8 en); +void audio_linein_amux_bias(u8 amux_bias); +/* + * + * + */ +void audio_linein_ch_combine(u8 LR_2_L, u8 LR_2_R); + +#endif diff --git a/include_lib/media/media_new/media/cpu/br28/asm/audio_src.h b/include_lib/media/media_new/media/cpu/br28/asm/audio_src.h new file mode 100644 index 0000000..58af796 --- /dev/null +++ b/include_lib/media/media_new/media/cpu/br28/asm/audio_src.h @@ -0,0 +1,86 @@ +/***************************************************************** +>file name : audio_src.h +>author : lichao +>create time : Fri 14 Dec 2018 03:05:49 PM CST +*****************************************************************/ +#ifndef _AUDIO_SRC_H_ +#define _AUDIO_SRC_H_ +#include "media/audio_stream.h" +#include "audio_resample.h" + + +#define SRC_DATA_MIX 0//各通道数据交叉存放 +#define SRC_DATA_SEP 1//各通道数据连续存放 + +#define SRC_CHI 2 +#define SRC_FILT_POINTS 24 + +#define SRC_TYPE_NONE 0 +#define SRC_TYPE_RESAMPLE 1 +#define SRC_TYPE_AUDIO_SYNC 2 + +#define AUDIO_ONLY_RESAMPLE 1 +#define AUDIO_SYNC_RESAMPLE 2 + +#define AUDIO_SAMPLE_FMT_16BIT 0 +#define AUDIO_SAMPLE_FMT_24BIT 1 + +#define BIND_AUDSYNC 0x10 +#define SET_RESAMPLE_TYPE(fmt, type) (((fmt) << 4) | (type)) +#define RESAMPLE_TYPE_TO_FMT(a) (((a) >> 4) & 0xf) +#define RESAMPLE_TYPE(a) ((a) & 0xf) + +#define INPUT_FRAME_BITS 18//20 -- 整数位减少可提高单精度浮点的运算精度 +#define RESAMPLE_INPUT_BIT_RANGE ((1 << INPUT_FRAME_BITS) - 1) +#define RESAMPLE_INPUT_BIT_NUM (1 << INPUT_FRAME_BITS) + +#define RESAMPLE_HW_24BIT 1 + + +// *INDENT-OFF* +struct audio_hw_resample_context { + void *base; +}; +// *INDENT-ON* + + +void *audio_resample_hw_open(u8 channel, int in_rate, int out_rate, u8 type); + +int audio_resample_hw_change_config(void *resample, int in_rate, int out_rate); + +int audio_resample_hw_set_input_buffer(void *resample, void *addr, int len); + +int audio_resample_hw_set_output_buffer(void *resample, void *addr, int len); + +int audio_resample_hw_set_output_handler(void *resample, void *, int (*handler)(void *, void *, int)); + +int audio_resample_hw_write(void *resample, void *data, int len); + +int audio_resample_hw_trigger_interrupt(void *resample, void *priv, void (*handler)(void *)); + +int audio_resample_hw_stop(void *resample); + +void audio_resample_hw_close(void *resample); + +int audio_resample_hw_push_data_out(void *resample); + +int audio_resample_hw_open_v1(struct audio_hw_resample_context *src, u8 channel, u8 type); + +void audio_resample_hw_close_v1(struct audio_hw_resample_context *ctx); + +#define audio_src_handle audio_hw_resample_context +#define audio_hw_src_open audio_resample_hw_open_v1 +#define audio_hw_src_set_rate audio_resample_hw_change_config +#define audio_src_resample_write audio_resample_hw_write +#define audio_src_set_output_handler audio_resample_hw_set_output_handler +#define audio_src_set_rise_irq_handler audio_resample_hw_trigger_interrupt +#define audio_hw_src_set_input_buffer audio_resample_hw_set_input_buffer +#define audio_hw_src_set_output_buffer audio_resample_hw_set_output_buffer +#define audio_hw_src_stop audio_resample_hw_stop +#define audio_hw_src_close audio_resample_hw_close_v1 +#define audio_hw_src_trigger_resume audio_resample_hw_trigger_interrupt +#define audio_hw_src_set_check_running(a, b) (0) +#define audio_hw_src_active(x) (0) + + +#endif diff --git a/include_lib/media/media_new/media/cpu/br28/asm/audio_src_base.h b/include_lib/media/media_new/media/cpu/br28/asm/audio_src_base.h new file mode 100644 index 0000000..e1bb7af --- /dev/null +++ b/include_lib/media/media_new/media/cpu/br28/asm/audio_src_base.h @@ -0,0 +1,48 @@ +/***************************************************************** +>file name : audio_src_base.h +>create time : Wed 02 Mar 2022 11:12:07 AM CST +*****************************************************************/ +#ifndef _AUDIO_SRC_BASE_H_ +#define _AUDIO_SRC_BASE_H_ +#include "audio_src.h" + +void *audio_src_base_open(u8 channel, int in_sample_rate, int out_sample_rate, u8 type); + +int audio_src_base_set_output_handler(void *resample, + void *priv, + int (*handler)(void *priv, void *data, int len)); + +int audio_src_base_set_channel(void *resample, u8 channel); + +int audio_src_base_set_in_buffer(void *resample, void *buf, int len); + +int audio_src_base_set_input_buff(void *resample, void *buf, int len); + +int audio_src_base_resample_config(void *resample, int in_rate, int out_rate); + +int audio_src_base_write(void *resample, void *data, int len); + +int audio_src_base_stop(void *resample); + +int audio_src_base_run_scale(void *resample); + +int audio_src_base_input_frames(void *resample); + +u32 audio_src_base_out_frames(void *resample); + +float audio_src_base_position(void *resample); + +int audio_src_base_scale_output(void *resample, int in_sample_rate, int out_sample_rate, int frames); + +int audio_src_base_bufferd_frames(void *resample); + +int audio_src_base_set_slience(void *resample, u8 slience, int fade_time); + +int audio_src_base_wait_irq_callback(void *resample, void *priv, void (*callback)(void *)); + +void audio_src_base_close(void *resample); + +int audio_src_base_push_data_out(void *resample); + +#endif + diff --git a/include_lib/media/media_new/media/cpu/br28/asm/audio_sub_system.h b/include_lib/media/media_new/media/cpu/br28/asm/audio_sub_system.h new file mode 100644 index 0000000..4886b3f --- /dev/null +++ b/include_lib/media/media_new/media/cpu/br28/asm/audio_sub_system.h @@ -0,0 +1,6 @@ +#ifndef _AUDIO_SUB_SYSTEM_H_ +#define _AUDIO_SUB_SYSTEM_H_ + +void audio_sub_system_init(void); + +#endif diff --git a/include_lib/media/media_new/media/cpu/br28/asm/cpu_includes.h b/include_lib/media/media_new/media/cpu/br28/asm/cpu_includes.h new file mode 100644 index 0000000..dbf521f --- /dev/null +++ b/include_lib/media/media_new/media/cpu/br28/asm/cpu_includes.h @@ -0,0 +1,17 @@ +/***************************************************************** +>file name : include_lib/media/cpu/br30/includes.h +>author : lichao +>create time : Fri 29 Nov 2019 02:24:47 PM CST +*****************************************************************/ +#ifndef _ASM_MEDIA_INCLUDES_H_ +#define _ASM_MEDIA_INCLUDES_H_ + +#include "asm/audio_adc.h" +#include "asm/audio_linein.h" +#include "asm/audio_src.h" +#include "asm/audio_src_base.h" +#include "dac.h" +#include "asm/hw_eq.h" +#include "asm/audio_sub_system.h" + +#endif diff --git a/include_lib/media/media_new/media/cpu/br28/asm/dac.h b/include_lib/media/media_new/media/cpu/br28/asm/dac.h new file mode 100644 index 0000000..f19eb34 --- /dev/null +++ b/include_lib/media/media_new/media/cpu/br28/asm/dac.h @@ -0,0 +1,407 @@ +#ifndef __CPU_DAC_H__ +#define __CPU_DAC_H__ + + +#include "generic/typedef.h" +#include "generic/atomic.h" +#include "os/os_api.h" +#include "audio_src.h" +#include "media/audio_cfifo.h" + +#define DAC_44_1KHZ 0 +#define DAC_48KHZ 1 +#define DAC_32KHZ 2 +#define DAC_22_05KHZ 3 +#define DAC_24KHZ 4 +#define DAC_16KHZ 5 +#define DAC_11_025KHZ 6 +#define DAC_12KHZ 7 +#define DAC_8KHZ 8 + +#define DAC_ISEL_FULL_PWR 4 +#define DAC_ISEL_HALF_PWR 2 +#define DAC_ISEL_THREE_PWR 1 + +#define DACVDD_LDO_1_20V 0 +#define DACVDD_LDO_1_25V 1 +#define DACVDD_LDO_1_30V 2 +#define DACVDD_LDO_1_35V 3 + +#define DAC_OUTPUT_MONO_L 0 //单左声道差分 +#define DAC_OUTPUT_MONO_R 1 //单右声道差分 +#define DAC_OUTPUT_LR 2 //双声道差分 +#define DAC_OUTPUT_MONO_LR_DIFF 3 //单声道 LP-RP 差分 + +#define DAC_DSM_6MHz 0 +#define DAC_DSM_12MHz 1 + +#define FADE_OUT_IN 1 + +#define AUDIO_DAC_SYNC_IDLE 0 +#define AUDIO_DAC_SYNC_START 1 +#define AUDIO_DAC_SYNC_NO_DATA 2 +#define AUDIO_DAC_SYNC_ALIGN_COMPLETE 3 + +#define AUDIO_SRC_SYNC_ENABLE 1 +#define SYNC_LOCATION_FLOAT 1 +#if SYNC_LOCATION_FLOAT +#define PCM_PHASE_BIT 0 +#else +#define PCM_PHASE_BIT 8 +#endif + +#define DA_LEFT 0 +#define DA_RIGHT 1 + +/************************************ + * 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 +#define DAC_MODE_H1_SINGLE (3) // 高压1档单端模式, 适用于高功率单端PA音箱, 输出幅度 0~1.5Vpp +#define DAC_MODE_H2_DIFF (4) // 高压2档差分模式, 适用于高功率差分PA音箱, 输出幅度 0~5Vpp +#define DAC_MODE_H2_SINGLE (5) // 高压2档单端模式, 适用于高功率单端PA音箱, 输出幅度 0~2.5Vpp + +#define DA_SOUND_NORMAL 0x0 +#define DA_SOUND_RESET 0x1 +#define DA_SOUND_WAIT_RESUME 0x2 + +#define DAC_ANALOG_OPEN_PREPARE (1) +#define DAC_ANALOG_OPEN_FINISH (2) +#define DAC_ANALOG_CLOSE_PREPARE (3) +#define DAC_ANALOG_CLOSE_FINISH (4) +//void audio_dac_power_state(u8 state) +//在应用层重定义 audio_dac_power_state 函数可以获取dac模拟开关的状态 + +struct dac_platform_data { + void (*analog_open_cb)(struct audio_dac_hdl *); + void (*analog_close_cb)(struct audio_dac_hdl *); + void (*analog_light_open_cb)(struct audio_dac_hdl *); + void (*analog_light_close_cb)(struct audio_dac_hdl *); + u8 mode; // AUDIO_DAC_MODE_XX + u8 ldo_id; + u8 ldo_volt; + u8 pa_mute_port; + u8 pa_mute_value; + u8 output; + u8 vcmo_en; + u8 keep_vcmo; + u8 lpf_isel; + u8 sys_vol_type; //系统音量类型, 0:默认调数字音量 1:默认调模拟音量 + u8 max_ana_vol; + u16 max_dig_vol; + s16 *dig_vol_tab; + u32 digital_gain_limit; + u8 vcm_cap_en; //配1代表走外部通路,vcm上有电容时,可以提升电路抑制电源噪声能力,提高ADC的性能,配0相当于vcm上无电容,抑制电源噪声能力下降,ADC性能下降 + u8 power_on_mode; +}; + + +struct analog_module { + /*模拟相关的变量*/ +#if 0 + unsigned int ldo_en : 1; + unsigned int ldo_volt : 3; + unsigned int output : 4; + unsigned int vcmo : 1; + unsigned int inited : 1; + unsigned int lpf_isel : 4; + unsigned int keep_vcmo : 1; + unsigned int reserved : 17; +#endif + u8 inited; + u16 dac_test_volt; +}; +struct audio_dac_trim { + s16 left; + s16 right; + s16 vcomo; +}; + +struct audio_dac_sync { + u8 channel; + u8 start; + u8 fast_align; + int fast_points; + u32 input_num; + int phase_sub; + int in_rate; + int out_rate; +#if AUDIO_SRC_SYNC_ENABLE + struct audio_src_sync_handle *src_sync; + void *buf; + int buf_len; + void *filt_buf; + int filt_len; +#else + struct audio_src_base_handle *src_base; +#endif +#if SYNC_LOCATION_FLOAT + double pcm_position; +#else + u32 pcm_position; +#endif + void *priv; + void (*handler)(void *priv, u8 state); +}; + +struct audio_dac_fade { + u8 enable; + volatile u8 ref_L_gain; + volatile u8 ref_R_gain; + int timer; +}; + +struct audio_dac_sync_node { + void *hdl; + struct list_head entry; +}; + +struct audio_dac_channel_attr { + u8 write_mode; /*DAC写入模式*/ + u16 delay_time; /*DAC通道延时*/ + u16 protect_time; /*DAC延时保护时间*/ +}; + +struct audio_dac_channel { + u8 state; /*DAC状态*/ + u8 pause; + u8 samp_sync_step; /*数据流驱动的采样同步步骤*/ + struct audio_dac_channel_attr attr; /*DAC通道属性*/ + struct audio_sample_sync *samp_sync; /*样点同步句柄*/ + struct audio_dac_hdl *dac; /* DAC设备*/ + struct audio_cfifo_channel fifo; /*DAC cfifo通道管理*/ +}; + +struct audio_dac_hdl { + struct analog_module analog; + const struct dac_platform_data *pd; + OS_SEM sem; + struct audio_dac_trim trim; + void (*fade_handler)(u8 left_gain, u8 right_gain); + void (*write_callback)(void *buf, int len); + void (*set_samplerate_callback)(int len); + u8 avdd_level; + u8 lpf_i_level; + volatile u8 mute; + volatile u8 state; + volatile u8 agree_on; + u8 gain; + u8 vol_l; + u8 vol_r; + u8 channel; + u8 bit24_mode_en; + u16 max_d_volume; + u16 d_volume[2]; + u32 sample_rate; + u32 digital_gain_limit; + u16 start_ms; + u16 delay_ms; + u16 start_points; + u16 delay_points; + u16 prepare_points;//未开始让DAC真正跑之前写入的PCM点数 + + u16 irq_points; + s16 protect_time; + s16 protect_pns; + s16 fadein_frames; + s16 fade_vol; + u8 protect_fadein; + u8 vol_set_en; + u8 dec_channel_num; + + u8 sound_state; + unsigned long sound_resume_time; + s16 *output_buf; + u16 output_buf_len; + + u8 anc_dac_open; + + u8 fifo_state; + u16 unread_samples; /*未读样点个数*/ + struct audio_cfifo fifo; /*DAC cfifo结构管理*/ + struct audio_dac_channel main_ch; + + struct audio_dac_sync sync; + struct list_head sync_list; + void *feedback_priv; + void (*underrun_feedback)(void *priv); + /*******************************************/ + /**sniff退出时,dac模拟提前初始化,避免模拟初始化延时,影响起始同步********/ + u8 power_on; + u8 need_close; + OS_MUTEX mutex; + OS_MUTEX mutex_power_off; + /*******************************************/ +}; + + + +int audio_dac_init(struct audio_dac_hdl *dac, const struct dac_platform_data *pd); + +void audio_dac_set_capless_DTB(struct audio_dac_hdl *dac, s16 dacr32); + +void audio_dac_avdd_level_set(struct audio_dac_hdl *dac, u8 level); + +void audio_dac_lpf_level_set(struct audio_dac_hdl *dac, u8 level); + +int audio_dac_do_trim(struct audio_dac_hdl *dac, struct audio_dac_trim *dac_trim, u8 fast_trim); + +int audio_dac_set_trim_value(struct audio_dac_hdl *dac, struct audio_dac_trim *dac_trim); + +int audio_dac_set_delay_time(struct audio_dac_hdl *dac, int start_ms, int max_ms); + +void audio_dac_irq_handler(struct audio_dac_hdl *dac); + +int audio_dac_set_buff(struct audio_dac_hdl *dac, s16 *buf, int len); + +int audio_dac_write(struct audio_dac_hdl *dac, void *buf, int len); + +int audio_dac_get_write_ptr(struct audio_dac_hdl *dac, s16 **ptr); + +int audio_dac_update_write_ptr(struct audio_dac_hdl *dac, int len); + +int audio_dac_set_sample_rate(struct audio_dac_hdl *dac, int sample_rate); + +int audio_dac_get_sample_rate(struct audio_dac_hdl *dac); + +int audio_dac_set_channel(struct audio_dac_hdl *dac, u8 channel); + +int audio_dac_get_channel(struct audio_dac_hdl *dac); + +int audio_dac_set_digital_vol(struct audio_dac_hdl *dac, u16 vol); + +int audio_dac_set_analog_vol(struct audio_dac_hdl *dac, u16 vol); + +int audio_dac_ch_analog_gain_set(struct audio_dac_hdl *dac, u32 ch, u32 again); + +int audio_dac_ch_analog_gain_get(struct audio_dac_hdl *dac, u32 ch); + +int audio_dac_ch_digital_gain_set(struct audio_dac_hdl *dac, u32 ch, u32 dgain); + +int audio_dac_ch_digital_gain_get(struct audio_dac_hdl *dac, u32 ch); + +int audio_dac_start(struct audio_dac_hdl *dac); + +int audio_dac_try_power_on(struct audio_dac_hdl *dac); + +int audio_dac_stop(struct audio_dac_hdl *dac); + +int audio_dac_idle(struct audio_dac_hdl *dac); + +void audio_dac_mute(struct audio_dac_hdl *hdl, u8 mute); + +int audio_dac_open(struct audio_dac_hdl *dac); + +int audio_dac_close(struct audio_dac_hdl *dac); + +int audio_dac_mute_left(struct audio_dac_hdl *dac); + +int audio_dac_mute_right(struct audio_dac_hdl *dac); + +int audio_dac_set_volume(struct audio_dac_hdl *dac, u8 gain); + +int audio_dac_set_L_digital_vol(struct audio_dac_hdl *dac, u16 vol); + +int audio_dac_set_R_digital_vol(struct audio_dac_hdl *dac, u16 vol); + +void audio_dac_set_fade_handler(struct audio_dac_hdl *dac, void *priv, void (*fade_handler)(u8, u8)); + +int audio_dac_sound_reset(struct audio_dac_hdl *dac, u32 msecs); + +int audio_dac_set_bit_mode(struct audio_dac_hdl *dac, u8 bit24_mode_en); +int audio_dac_get_max_channel(void); +int audio_dac_get_status(struct audio_dac_hdl *dac); +u8 audio_dac_is_working(struct audio_dac_hdl *dac); +int audio_dac_set_irq_time(struct audio_dac_hdl *dac, int time_ms); +int audio_dac_data_time(struct audio_dac_hdl *dac); +int audio_dac_irq_enable(struct audio_dac_hdl *dac, int time_ms, void *priv, void (*callback)(void *)); +int audio_dac_set_protect_time(struct audio_dac_hdl *dac, int time, void *priv, void (*feedback)(void *)); +int audio_dac_buffered_frames(struct audio_dac_hdl *dac); +void audio_dac_add_syncts_handle(struct audio_dac_hdl *dac, void *syncts); + +void audio_dac_remove_syncts_handle(struct audio_dac_hdl *dac, void *syncts); +/* + * 音频同步 + */ +int audio_dac_set_sync_buff(struct audio_dac_hdl *dac, void *buf, int len); + +int audio_dac_set_sync_filt_buff(struct audio_dac_hdl *dac, void *buf, int len); + +int audio_dac_sync_open(struct audio_dac_hdl *dac); + +int audio_dac_sync_set_channel(struct audio_dac_hdl *dac, u8 channel); + +int audio_dac_sync_set_rate(struct audio_dac_hdl *dac, int in_rate, int out_rate); + +int audio_dac_sync_auto_update_rate(struct audio_dac_hdl *dac, u8 on_off); + +int audio_dac_sync_flush_data(struct audio_dac_hdl *dac); + +int audio_dac_sync_fast_align(struct audio_dac_hdl *dac, int in_rate, int out_rate, int fast_output_points, float phase_diff); + +#if SYNC_LOCATION_FLOAT +double audio_dac_sync_pcm_position(struct audio_dac_hdl *dac); +#else +u32 audio_dac_sync_pcm_position(struct audio_dac_hdl *dac); +#endif + +void audio_dac_sync_input_num_correct(struct audio_dac_hdl *dac, int num); + +void audio_dac_set_sync_handler(struct audio_dac_hdl *dac, void *priv, void (*handler)(void *priv, u8 state)); + +int audio_dac_sync_start(struct audio_dac_hdl *dac); + +int audio_dac_sync_stop(struct audio_dac_hdl *dac); + +int audio_dac_sync_data_lock(struct audio_dac_hdl *dac); + +int audio_dac_sync_data_unlock(struct audio_dac_hdl *dac); + +void audio_dac_sync_close(struct audio_dac_hdl *dac); + +void audio_dac_ch_mute(struct audio_dac_hdl *dac, u8 ch, u8 mute); + +u32 local_audio_us_time_set(u16 time); + +int local_audio_us_time(void); + +int audio_dac_start_time_set(void *_dac, u32 us_timeout, u32 cur_time, u8 on_off); + +u32 audio_dac_sync_pcm_total_number(void *_dac); + +void audio_dac_sync_set_pcm_number(void *_dac, u32 output_points); + +u32 audio_dac_pcm_total_number(void *_dac, int *pcm_r); + +u8 audio_dac_sync_empty_state(void *_dac); + +void audio_dac_sync_empty_reset(void *_dac, u8 state); + +void audio_dac_set_empty_handler(void *_dac, void *empty_priv, void (*handler)(void *priv, u8 empty)); + +void audio_dac_channel_start(void *private_data); +void audio_dac_channel_close(void *private_data); +int audio_dac_channel_write(void *private_data, struct audio_dac_hdl *dac, void *buf, int len); +int audio_dac_channel_set_attr(struct audio_dac_channel *ch, struct audio_dac_channel_attr *attr); +int audio_dac_new_channel(struct audio_dac_hdl *dac, struct audio_dac_channel *ch); + +void audio_anc_dac_gain(u8 gain_l, u8 gain_r); + +void audio_anc_dac_dsm_sel(u8 sel); + +void audio_anc_dac_open(u8 gain_l, u8 gain_r); + +void audio_anc_dac_close(void); + +void audio_dac_write_callback_add(struct audio_dac_hdl *dac, void (*cb)(void *buf, int len)); + +void audio_dac_write_callback_del(struct audio_dac_hdl *dac, void (*cb)(void *buf, int len)); + +void audio_dac_set_samplerate_callback_add(struct audio_dac_hdl *dac, void (*cb)(int)); + +void audio_dac_set_samplerate_callback_del(struct audio_dac_hdl *dac, void (*cb)(int)); + +#endif + diff --git a/include_lib/media/media_new/media/cpu/br28/asm/hw_eq.h b/include_lib/media/media_new/media/cpu/br28/asm/hw_eq.h new file mode 100644 index 0000000..7f68c39 --- /dev/null +++ b/include_lib/media/media_new/media/cpu/br28/asm/hw_eq.h @@ -0,0 +1,334 @@ + +#ifndef __HW_EQ_H +#define __HW_EQ_H + +#include "generic/typedef.h" +#include "generic/list.h" +#include "os/os_api.h" +#include "media/eq_func_define.h" + + + +enum { //运行模式 + NORMAL = 0, //正常模式 + MONO, //单声道模式 + STEREO //立体声模式 +}; + +enum { //输出数据类型 + DATO_SHORT = 0, //short + DATO_INT, //int + DATO_FLOAT //float +}; +enum { //输入数据类型 + DATI_SHORT = 0, //short + DATI_INT, // int + DATI_FLOAT //float +}; +enum { //输入数据存放模式 + BLOCK_DAT_IN = 0, //块模式,例如输入数据是2通道,先存放完第1通道的所有数据,再存放第2通道的所有数据 + SEQUENCE_DAT_IN, //序列模式,例如输入数据是2通道,先存放第通道的第一个数据,再存放第2个通道的第一个数据,以此类推。 +}; +enum { //输出数据存放模式 + BLOCK_DAT_OUT = 0,//块模式,例如输出数据是2通道,先存放完第1通道的所有数据,再存放第2通道的所有数据 + SEQUENCE_DAT_OUT, //序列模式,例如输入数据是2通道,先存放第通道的第一个数据,再存放第2个通道的第一个数据,以此类推。 +}; + + +/*eq IIR type*/ +typedef enum { + EQ_IIR_TYPE_HIGH_PASS = 0x00, + EQ_IIR_TYPE_LOW_PASS, + EQ_IIR_TYPE_BAND_PASS, + EQ_IIR_TYPE_HIGH_SHELF, + EQ_IIR_TYPE_LOW_SHELF, +} EQ_IIR_TYPE; + +struct eq_seg_info { + u16 index; //eq段序号 + u16 iir_type; //滤波器类型EQ_IIR_TYPE + int freq; //中心截止频率 + float gain; //增益(-12 ~12 db) + float q; //q值(0.3~30) +}; + +struct eq_coeff_info { + u8 nsection; //eq段数 + u8 no_coeff; //不是滤波系数 +#ifdef CONFIG_EQ_NO_USE_COEFF_TABLE + u32 sr; //采样率 +#endif + float *L_coeff; //左声道滤波器系数地址 + float *R_coeff; //右声道滤波器系数地址 + float L_gain; //左声道总增益(-20~20db) + float R_gain; //右声道总增益(-20~20db) + float *N_coeff[8]; + float N_gain[8]; +}; + +struct hw_eq_ch; + +struct hw_eq { + struct list_head head; //链表头 + OS_MUTEX mutex; //互斥锁 + volatile struct hw_eq_ch *cur_ch; //当前需要处理的eq通道 +}; + +enum { + HW_EQ_CMD_CLEAR_MEM = 0xffffff00, + HW_EQ_CMD_CLEAR_MEM_L, + HW_EQ_CMD_CLEAR_MEM_R, +}; + +struct hw_eq_handler { + int (*eq_probe)(struct hw_eq_ch *); //eq驱动内前处理 + int (*eq_output)(struct hw_eq_ch *, s16 *, u16); //eq驱动内输出处理回调 + int (*eq_post)(struct hw_eq_ch *); //eq驱动内处理后回调 + int (*eq_input)(struct hw_eq_ch *, void **, void **); //eq驱动内输入处理回调 +}; + +struct hw_eq_ch { + unsigned char updata; //更新参数以及中间数据 + unsigned char updata_coeff_only; //只更新参数,不更新中间数据 + unsigned char no_wait; //是否是异步eq处理 0:同步的eq 1:异步的eq + unsigned char channels; //输入通道数 + unsigned char SHI; //eq运算输出数据左移位数控制,记录 + unsigned char countL; //eq运算输出数据左移位数控制临时记录 + unsigned short stage; //eq运算开始位置标识 + unsigned char nsection; //eq段数 + unsigned char no_coeff; // 非滤波系数 + volatile unsigned char active; //已启动eq处理 1:busy 0:处理结束 + volatile unsigned char need_run; //多eq同时使用时,未启动成功的eq,是否需要重新唤醒处理 1:需要 0:否 + unsigned char run_mode; //0按照输入的数据排布方式 ,输出数据 1:单入多出, 2:立体声入多出 + unsigned char in_mode; //输入数据的位宽 0:short 1:int 2:float + unsigned char out_32bit; //输出数据的位宽 0:short 1:int 2:float + unsigned char out_channels; //输出通道数 + unsigned char data_in_mode; //输入数据存放模式 + unsigned char data_out_mode; //输入数据存放模式 +#ifdef CONFIG_EQ_NO_USE_COEFF_TABLE + u32 sr; //采样率 +#endif + float *L_coeff; //输入给左声道系数地址 + float *R_coeff; //输入给右声道系数地址 + float L_gain; //输入给左声道总增益(-20~20) + float R_gain; //输入给右声道总增益(-20~20) + float *N_coeff[8]; + float N_gain[8]; + float *eq_LRmem; //eq系数地址(包含运算的中间数据) + s16 *out_buf; //输出buf地址 + s16 *in_buf; //输入buf地址 + int in_len; //输入数据长度 + void *priv; //保存eq管理层的句柄 + volatile OS_SEM sem; //信号量,用于通知驱动,当前一次处理完成 + struct list_head entry; //当前eq通道的节点 + struct hw_eq *eq; //底层eq操作句柄 + const struct hw_eq_handler *eq_handler;//eq操作的相关回调函数句柄 + void *irq_priv; //eq管理层传入的私有指针 + void (*irq_callback)(void *priv);//需要eq中断执行的回调函数 +}; + +//系数计算子函数 + +/* +fc: 低通滤波器-3dB衰减频点 +fs: 采样率 +nSOS: 生成nSOS阶IIR +coeff: 输出系数地址 ( 大小为 ((nSOS & 1) + (nSOS >> 1))*5 , 顺序是按照硬件EQ摆放了 ) +段数:((nSOS & 1) + (nSOS >> 1))*/ +/* + * 多阶级低通滤波器 +fc: 低通滤波器-3dB衰减频点 +fs: 采样率 +nSOS: 生成多少个2阶IIR +coeff: 输出系数地址 ( 大小为 nSOS*5 , 顺序是按照硬件EQ摆放了 )*/ +extern void butterworth_lp_design(int fc, int fs, int nSOS, float *coeff); + +/* +fc: 通滤波器-3dB衰减频点 +fs: 采样率 +nSOS: 生成nSOS阶IIR +coeff: 输出系数地址 ( 大小为((nSOS & 1) + (nSOS >> 1))*5 , 顺序是按照硬件EQ摆放了 ) +段数:((nSOS & 1) + (nSOS >> 1))*/ +extern void butterworth_hp_design(int fc, int fs, int nSOS, float *coeff); + + +/*----------------------------------------------------------------------------*/ +/**@brief 低通滤波器 + @param fc:中心截止频率 + @param fs:采样率 + @param quality_factor:q值 + @param coeff:计算后,系数输出地址 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +extern void design_lp(int fc, int fs, float quality_factor, float *coeff); +/*----------------------------------------------------------------------------*/ +/**@brief 高通滤波器 + @param fc:中心截止频率 + @param fs:采样率 + @param quality_factor:q值 + @param coeff:计算后,系数输出地址 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +extern void design_hp(int fc, int fs, float quality_factor, float *coeff); +/*----------------------------------------------------------------------------*/ +/**@brief 带通滤波器 + @param fc:中心截止频率 + @param fs:采样率 + @param gain:增益 + @param quality_factor:q值 + @param coeff:计算后,系数输出地址 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +extern void design_pe(int fc, int fs, float gain, float quality_factor, float *coeff); +/*----------------------------------------------------------------------------*/ +/**@brief 低频搁架式滤波器 + @param fc:中心截止频率 + @param fs:采样率 + @param gain:增益 + @param quality_factor:q值 + @param coeff:计算后,系数输出地址 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +extern void design_ls(int fc, int fs, float gain, float quality_factor, float *coeff); +/*----------------------------------------------------------------------------*/ +/**@brief 高频搁架式滤波器 + @param fc:中心截止频率 + @param fs:采样率 + @param gain:增益 + @param quality_factor:q值 + @param coeff:计算后,系数输出地址 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +extern void design_hs(int fc, int fs, float gain, float quality_factor, float *coeff); +/*----------------------------------------------------------------------------*/ +/**@brief 滤波器系数检查 + @param coeff:滤波器系数 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +extern int eq_stable_check(float *coeff); +float eq_db2mag(float x); + +/*----------------------------------------------------------------------------*/ +/**@brief 获取直通的滤波器系数 + @param coeff:滤波器系数 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +extern void eq_get_AllpassCoeff(void *Coeff); + +/*----------------------------------------------------------------------------*/ +/**@brief 滤波器计算管理函数 + @param *seg:提供给滤波器的基本信息 + @param sample_rate:采样率 + @param *coeff:计算后,系数输出地址 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int eq_seg_design(struct eq_seg_info *seg, int sample_rate, float *coeff); + + +/*----------------------------------------------------------------------------*/ +/**@brief 在EQ中断中调用 + @param *eq:句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +void audio_hw_eq_irq_handler(struct hw_eq *eq); + +/*----------------------------------------------------------------------------*/ +/**@brief EQ初始化 + @param *eq:句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_hw_eq_init(struct hw_eq *eq, u32 eq_section_num); +int audio_hw_eq_init_new(struct hw_eq *eq, u32 eq_section_num); + +/*----------------------------------------------------------------------------*/ +/**@brief 打开一个通道 + @param *ch:通道句柄 + @param *eq:句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_hw_eq_ch_open(struct hw_eq_ch *ch, struct hw_eq *eq); +/*----------------------------------------------------------------------------*/ +/**@brief 设置回调接口 + @param *ch:通道句柄 + @param *handler:回调的句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_hw_eq_ch_set_handler(struct hw_eq_ch *ch, struct hw_eq_handler *handler); +// +/*----------------------------------------------------------------------------*/ +/**@brief 设置通道基础信息 + @param *ch:通道句柄 + @param channels:通道数 + @param out_32bit:是否输出32bit位宽数据 1:是 0:16bit位宽 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_hw_eq_ch_set_info(struct hw_eq_ch *ch, u8 channels, u8 out_32bit); +int audio_hw_eq_ch_set_info_new(struct hw_eq_ch *ch, u8 channels, u8 in_mode, u8 out_mode, u8 run_mode, u8 data_in_mode, u8 data_out_mode); +/*----------------------------------------------------------------------------*/ +/**@brief 设置硬件转换系数 + @param *ch:通道句柄 + @param *info:系数、增益等信息 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_hw_eq_ch_set_coeff(struct hw_eq_ch *ch, struct eq_coeff_info *info); + +/*----------------------------------------------------------------------------*/ +/**@brief 启动一次转换 + @param *ch:eq句柄 + @param *input:输入数据地址 + @param *output:输出数据地址 + @param len:输入数据长度 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_hw_eq_ch_start(struct hw_eq_ch *ch, void *input, void *output, int len); + +/*----------------------------------------------------------------------------*/ +/**@brief 关闭一个通道 + @param *ch:eq句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_hw_eq_ch_close(struct hw_eq_ch *ch); + +/*----------------------------------------------------------------------------*/ +/**@brief 获取eq是否正在运行状态 + @param *ch:eq句柄 + @return + @note +*/ +/*----------------------------------------------------------------------------*/ +int audio_hw_eq_is_running(struct hw_eq *eq); + +#endif /*__HW_EQ_H*/ + diff --git a/include_lib/media/media_new/media/cpu/br28/asm/pdm_link.h b/include_lib/media/media_new/media/cpu/br28/asm/pdm_link.h new file mode 100644 index 0000000..348630b --- /dev/null +++ b/include_lib/media/media_new/media/cpu/br28/asm/pdm_link.h @@ -0,0 +1,53 @@ + +#ifndef _PDM_LINK_H_ +#define _PDM_LINK_H_ + +#include "generic/typedef.h" +#define PLNK_CH0_EN BIT(0) +#define PLNK_CH1_EN BIT(1) +#define PLNK_CH_EN PLNK_CH0_EN //(PLNK_CH0_EN | PLNK_CH1_EN) +#define PLNK_SCLK_PIN IO_PORTA_14 +#define PLNK_DAT0_PIN IO_PORTA_15 +#define PLINK_BUF_LEN 256 +#define PLNK_CLK 24000000 //48M +#define PLNK_SCLK 2400000 //1M ~ 4M +#define PLNK_CON_RESET() do {JL_PLNK->CON = 0; JL_PLNK->CON1 = 0;} while(0) +#define PLNK_CH0_MD_SET(x) SFR(JL_PLNK->CON, 2, 2, x) +#define PLNK_CH1_MD_SET(x) SFR(JL_PLNK->CON, 6, 2, x) +#define PLNK_PND_CLR() SFR(JL_PLNK->CON, 14, 1, 1); //CPND + +/*通道0输入模式选择*/ +typedef enum { + CH0MD_CH0_SCLK_RISING_EDGE, + CH0MD_CH0_SCLK_FALLING_EDGE, + CH0MD_CH1_SCLK_RISING_EDGE, + CH0MD_CH1_SCLK_FALLING_EDGE, +} PDM_LINK_CH0MD; + +/*通道1输入模式选择*/ +typedef enum { + CH1MD_CH1_SCLK_RISING_EDGE, + CH1MD_CH1_SCLK_FALLING_EDGE, + CH1MD_CH0_SCLK_RISING_EDGE, + CH1MD_CH0_SCLK_FALLING_EDGE, +} PDM_LINK_CH1MD; + +typedef struct { + u8 sclk_io; + u8 ch_num; /*使能多少个通道*/ + u8 ch0_io; + u8 ch1_io; + u8 ch0_mode; /*通道0输入模式选择*/ + u8 ch1_mode; /*通道1输入模式选择*/ + u16 sr; /*采样率*/ + u16 buf_len; /*一次采样点数*/ + s16 *buf; + void (*output)(void *buf, u16 len); +} audio_plnk_t; + +int audio_plnk_open(audio_plnk_t *hdl); +int audio_plnk_start(audio_plnk_t *hdl); +int audio_plnk_close(void); +void audio_plnk_test(); + +#endif/*_PDM_LINK_H_*/ diff --git a/include_lib/media/media_new/media/cpu/br28/audio_lib.ld b/include_lib/media/media_new/media/cpu/br28/audio_lib.ld new file mode 100644 index 0000000..66fb4ca --- /dev/null +++ b/include_lib/media/media_new/media/cpu/br28/audio_lib.ld @@ -0,0 +1,439 @@ +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); +#if AUDIO_EFFECTS_GAIN_AT_RAM + *(.audio_gain_code) + *(.audio_gain_const) +#endif/*AUDIO_EFFECTS_GAIN_AT_RAM*/ + } > 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) +#if (AUDIO_EFFECTS_GAIN_AT_RAM == 0) + *(.audio_gain_code) + *(.audio_gain_const) +#endif + *(.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) + /* *(.cvsd_code) */ + /* *(.cvsd_const) */ + /* *(.g729_code) */ + /* *(.g729_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) + + /* *(.cvsd_code) */ + /* *(.cvsd_const) */ + *(.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 +} + diff --git a/include_lib/media/media_new/media/cpu/br28/audio_lib_data.ld b/include_lib/media/media_new/media/cpu/br28/audio_lib_data.ld new file mode 100644 index 0000000..e09fda7 --- /dev/null +++ b/include_lib/media/media_new/media/cpu/br28/audio_lib_data.ld @@ -0,0 +1,27 @@ + + . = 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) diff --git a/include_lib/media/media_new/media/cpu/br28/audio_output_dac.h b/include_lib/media/media_new/media/cpu/br28/audio_output_dac.h new file mode 100644 index 0000000..002ab49 --- /dev/null +++ b/include_lib/media/media_new/media/cpu/br28/audio_output_dac.h @@ -0,0 +1,14 @@ +#ifndef _AUDIO_OUTPUT_DAC_H_ +#define _AUDIO_OUTPUT_DAC_H_ + +#include "typedef.h" + +#define TYPE_DAC_AGAIN (0x01) +#define TYPE_DAC_DGAIN (0x02) + +extern int audio_dac_vol_set(u8 type, u32 ch, u16 gain, u8 fade_en); +extern int audio_dac_vol_mute(u8 mute, u8 fade); +extern int audio_dac_vol_mute_lock(u8 lock); + +#endif // _AUDIO_OUTPUT_DAC_H_ + diff --git a/include_lib/media/media_new/media/drc_api.h b/include_lib/media/media_new/media/drc_api.h new file mode 100644 index 0000000..95032f4 --- /dev/null +++ b/include_lib/media/media_new/media/drc_api.h @@ -0,0 +1,139 @@ +#ifndef DRC_API_H +#define DRC_API_H + +#ifdef WIN32 + +#define AT_DRC(x) +#define AT_DRC_CODE +#define AT_DRC_CONST +#define AT_DRC_SPARSE_CODE +#define AT_DRC_SPARSE_CONST + +#else +#define AT_DRC(x) __attribute((section(#x))) +#define AT_DRC_CODE AT_DRC(.drc_code) +#define AT_DRC_CONST AT_DRC(.drc_const) +#define AT_DRC_SPARSE_CODE AT_DRC(.drc_sparse_code) +#define AT_DRC_SPARSE_CONST AT_DRC(.drc_sparse_const) +#endif + + +enum { + DATA_IN_SHORT = 0, //输入数据类型,输入short时,输出不能为int + DATA_IN_INT, +}; +enum { + DATA_OUT_SHORT = 0, //输出数据类型,输入short时,输出不能为int + DATA_OUT_INT +}; + +enum { + PEAK = 0, //算法类型 + RMS +}; + +enum { + PERPOINT = 0, //mode 模式 + TWOPOINT +}; + +typedef struct _DrcParam { + /* + int *attackTime; //启动时间 + int *releaseTime; //释放时间 + float *threshold; //阈值{x1,y1,x2,y2} 最多5组十个数据 + int *ThresholdNum; //阈值的组数 + int *rmsTime; // rms时间 algorithm为RMS有效 + float *InputGain; // 输入增益(db) + float *OutputGain; // 输出数据增益(db) + unsigned char algorithm; // PEAK或者RMS + unsigned char mode; // 模式 + unsigned char intype; // 输入数据类型 + unsigned char outtype; // 输出数据类型 + */ + int channel; + int sampleRate; + int attackTime; //启动时间 + int releaseTime; //释放时间 + float *threshold; //阈值{x1,y1,x2,y2} 最多5组十个数据 + int ThresholdNum; //阈值的组数 + int rmsTime; // rms时间 algorithm为RMS有效 + float InputGain; // 输入增益(db) + float OutputGain; // 输出数据增益(db) + unsigned char algorithm; // PEAK或者RMS + unsigned char mode; // 模式 + unsigned char intype; // 输入数据类型 + unsigned char outtype; // 输出数据类型 + int IndataInc; // 输入数据同个通道下个点的步进 例如左右左右 步进为2 + int OutdataInc; // 输出数据同个通道下个点的步进 例如左右左右 步进为2 +} DrcParam; + +//int GetDrcBuf(int algorithm, int *rmsTime, int channel, int sampleRate); +int GetDrcBuf(DrcParam *param); // bufsize 与 algorithm,rmsTime channel、 sampleRate有关 +//void DrcInit(void *WorkBuf, DrcParam *param, int channel, int sampleRate); +void DrcInit(void *WorkBuf, DrcParam *param); +void DrcUpdate(void *WorkBuf, DrcParam *param); +int DrcRun(void *WorkBuf, void *indata, void *outdata, int per_channel_npoint); +/* InputGain 输入数据放大或者缩小的db数(正数放大,负数缩小) */ +// inputgain 配2,表示总体增加2dB +/* OutputGain 输出数据放大或者缩小的db数(正数放大,负数缩小) */ +#if 0 +int GetDrcBuf(int algorithm, int *rmsTime, int channel, int sampleRate); +获取buf大小 +参数说明: +algorithm:算法类型,PEAK或者RMS +rmsTime: +rms时间ms,算法类型为RMS时有效 +channel: 通道数 +sampleRate: +采样率 + +void DrcInit(void *WorkBuf, int *attackTime, int *releaseTime, float *threshold, int *ThresholdNum, int *rmsTime, int channel, int sampleRate, int algorithm, int mode, int intype, int outtype); +初始化 +参数说明: +WorkBuf: +运行buf +attackTime: +启动时间ms +releaseTime: +释放时间ms +threshold: +信号输入与对应的输出[in1, out1, in2, out2 ***排列] 最多5组数据, 3个阈值,4段 +ThresholdNum: +信号输入与对应的输出组数 +rmsTime: +rms时间ms +channel: +通道 +sampleRate:采样率 +algorithm:算法类型 +mode:模式 +intype:输入数据类型,DATA_IN_SHORT或者DATA_IN_INT +outtype: +输出数据类型,DATA_OUT_SHOR或者DATA_OUT_INT;若输入数据类型为DATA_IN_SHORT,输出类型只能设置为DATA_OUT_SHOR + +void DrcUpdate(void *WorkBuf, int *attackTime, int *releaseTime, float *threshold, int *ThresholdNum, int channel, int sampleRate); +更新参数:使用rms算法时,当rmsTime fs变化时因为buf会产生变化,只能初始化更新 +参数说明: +WorkBuf: +运行buf +attackTime: +启动时间ms +releaseTime: +释放时间ms +threshold: +信号输入与对应的输出[in1, out1, in2, out2 ***排列] 最多5组数据, 3个阈值,4段 +ThresholdNum: +信号输入与对应的输出组数 + +int DrcRun(void *WorkBuf, void *indata, void *outdata, int per_channel_npoint); +运行:输入输出数据类型,要跟初始化配置的数据类型对应 +WorkBuf: +运行buf +indata:输入数据 +outdata:输出数据 +per_channel_npoint:每个通道的样点数 +#endif + +#endif // !DRC_API_H + diff --git a/include_lib/media/media_new/media/effectrs_sync.h b/include_lib/media/media_new/media/effectrs_sync.h new file mode 100644 index 0000000..e8fce0b --- /dev/null +++ b/include_lib/media/media_new/media/effectrs_sync.h @@ -0,0 +1,236 @@ +#ifndef EFFECTRS_SYNC_H +#define EFFECTRS_SYNC_H + +#include "generic/typedef.h" +#include "generic/list.h" + +#define WL_PROTOCOL_RTP 0 +#define WL_PROTOCOL_SCO 1 +#define WL_PROTOCOL_FILE 2 +#define WL_PROTOCOL_JL_TWS 3 + +#define SYNC_ERR_NONE 0 +#define SYNC_ERR_PLAY_REJECTED 1 +#define SYNC_ERR_PAUSE 2 +#define SYNC_ERR_DISCARD_PKT 3 +#define SYNC_ERR_PLAY_PREPARE 4 +#define SYNC_ERR_NULL_PKT 5 +#define SYNC_ERR_GRAB_AUDIO_STREAM 6 +#define SYNC_ERR_DEC_RESET 7 +enum { + SYNC_DAC_CTL = 1, + SYNC_GET_PCM_TOTAL, + SYNC_GET_SRC_IN_LEN, + SYNC_GET_SRC_STATE, + SYNC_SET_PLAY_O_POINT, + SYNC_WITE_DAC_MUTE_DATE, + SET_LOCAL_US_TIME, + SET_SYNC_RESET, + SYNC_SWITCH_N_CH, +}; +struct audio_packet_buffer { + u8 noblock; + u8 state; + u16 timeout; + u32 slot_time; + u32 len; + u32 baddr; +}; +struct audio_packet_stats { + u32 total_size; + u32 data_size; + u32 remain_size; + u8 ch; + u8 grab_audio_stream_info_num; +}; +typedef struct _SYNC_POINTER_ { + volatile int *src_in_len; + volatile int *set_sr_in; + volatile int *set_sr_out; + volatile int *more_less_points; + + volatile int *play_point; + volatile int *fake_n_points; +} CPUSYNC_POINTERS; + +/* + * 播放动态src配置,start为配置一次变点 + */ +struct audio_pcm_src { + u8 convert; //启动转换 + u8 resample;//设置为变采样 + u16 ratio_i; //转换输入 + u16 ratio_o; //转换输出 +}; + +/* + * 同步需要的DAC协定启动配置 + */ +struct audio_dac_ctl { + u8 agreement; // + u8 on; //启动/暂停 + // u8 time_unit; //时间单位(0 - us, 1 - ms, 2 - s) + u32 pre_time; + u32 time; //时间点(us) +}; +// *INDENT-OFF* +struct sync_ops_t { + void *(*open)(void); + void (*set_handler)(void *, void *priv, + void (*handler)(void *, int *, int)); + u32 (*time)(u8 type, u32 time,u32 *pre_time); + int (*send)(void *, void *buf, u32 len); + int (*master)(u8 type); + u8 (*online)(u8); + void (*role_lock)(void *, u8); + void (*close)(void *); + void *(*audio_sync_open)(void *empty_priv,void (*empty_handler)(void *, u8),u8 protocol,u16 ch,u16 sr,int (*sync_output)(void *priv, void *data, int len),void*); + int (*audio_sync_close)(void *sync); + int (*audio_sync_run)(void *_sync,void *buf, int points_per_channel); + int (*audio_sync_set_samplerate)(void *sync,int sr_in,int sr_out); + int (*audio_sync_control)(void* _priv,int cmd,u32 arg); +}; + +struct audio_sync_parm { + u8 channel; + u8 top_percent; //上限比例 + u8 start_percent; //启动比例限值 + u8 bottom_percent; //下限比例 + u8 protocol; //音频包含协议 + u32 buffer_size; + u8 sync_time; + const struct sync_ops_t *ops; + void *audio_dev; + int (*sync_output)(void *priv, void *data, int len); +}; +// *INDENT-ON* + +extern void *audio_decoder_sync_open(struct audio_decoder *dec, struct audio_sync_parm *sync_parm); +extern void audio_decoder_sync_close(void *c); +extern int audio_decodr_sync_start(void *c, struct audio_packet_stats *stats, struct audio_packet_buffer *pkt); +extern int audio_decoder_sync_run(void *c, void *buf, int len); +extern int audio_decoder_sync_do(void *c, s16 *buf, int len); +extern int audio_sync_reset(void *c); +int audio_sync_set_remain_len(void *c, int len); + +#if (defined CONFIG_CPU_BR26 || \ + defined CONFIG_CPU_BR23 || \ + defined CONFIG_CPU_BR25 || \ + defined CONFIG_CPU_BR30 || \ + defined CONFIG_CPU_BR34 || \ + defined CONFIG_CPU_BR36 || \ + defined CONFIG_CPU_BR28 || \ + defined CONFIG_CPU_BR27) +/* + * BR26同步 + */ +#define SYNC_ERR_NONE 0 +#define SYNC_ERR_DEC_NOT_ALLOWED 1 +#define SYNC_ERR_TIMEOUT 2 +#define SYNC_ERR_STREAM_PASS 3 +#define SYNC_ERR_STREAM_END 4 +#define SYNC_ERR_PREPARE 5 +#define SYNC_ERR_ALIGNED_AND_PASS 6 +#define SYNC_ERR_STREAM_RESET 7 + +/***************** the step mean to get more or less (sample_rate/step) points/sencond ********************/ +#define SRC_DEC_STEP 2 //step to speed down +#define SRC_INC_STEP 2 // step to speed up + +#define SRC_POINT_AMPLIPY 5 + +#define AUDIO_SYNC_TARGET_DAC 0 +#define AUDIO_SYNC_EXTERNAL_DAC 1 + +#define RX_DELAY_NULL 0 +#define RX_DELAY_UP 1 +#define RX_DELAY_DOWN 2 + +struct rt_stream_info { + u8 noblock; + u8 rx_delay; + u16 seqn; + s16 distance_time; + u32 data_len; + u32 remain_len; + void *baddr; + int len; +}; + +struct file_sync_info { + u8 tws_together; + u32 together_time; +}; + +// *INDENT-OFF* +struct audio_tws_conn_ops { + void *(*open)(void); + void (*set_handler)(void *, void *priv, + void (*handler)(void *, int *, int)); + u32 (*time)(u8 type, u32 time, u32 *pre_time); + int (*send)(void *, void *buf, u32 len); + int (*master)(u8 type); + u8 (*online)(u8); + void (*close)(void *); +}; + +struct audio_wireless_sync_info { + u8 channel; + u8 target; + u8 protocol; //音频同步协议类型 + u8 reset_enable; + u16 sample_rate; + u16 output_rate; + u32 data_top; //数据上限 + u32 data_bottom; //数据下限 + u32 begin_size; //数据启动线 + int time_before_dec; + u32 tws_together_time; + const struct audio_decoder_ops *dec_ops; + void *decoder; + void *dev; + const struct audio_tws_conn_ops *tws_ops; + void *output_priv; + int (*output_handler)(void *priv, void *data, int len); +}; +// *INDENT-ON* + +void *audio_wireless_sync_open(struct audio_wireless_sync_info *info); + +int audio_wireless_sync_add_dev(void *c, struct audio_wireless_sync_info *info); + +int audio_wireless_file_sync_probe(void *c, struct file_sync_info *info); + +int audio_wireless_sync_probe(void *c, struct rt_stream_info *info); + +void audio_wireless_sync_info_init(void *c, u32 sample_rate, u32 output_rate, u8 channel); + +int audio_sync_set_tws_together(void *c, u8 together, u32 together_time); + +int audio_output_to_wireless_sync(void *c, s16 *data, int len); + +int audio_wireless_sync_after_dec(void *c, s16 *data, int len); + +int audio_wireless_sync_update_pos(void *c, void *data, int len); + +int audio_wireless_sync_get_rate(void *c, u16 *input_rate, u16 *output_rate); + +int audio_wireless_sync_write(void *c, s16 *data, int len); + +int audio_wireless_sync_info_store(void *c, struct rt_stream_info *info); + +int audio_wireless_sync_stop(void *c); + +int audio_wireless_sync_reset(void *c); + +int audio_wireless_sync_suspend(void *c); + +void audio_wireless_sync_close(void *c); + +#endif +/* +#if (defined CONFIG_CPU_BR26 || \ + (defined CONFIG_CPU_BR23 || \ + defined CONFIG_CPU_BR25) +*/ +#endif diff --git a/include_lib/media/media_new/media/file_decoder.h b/include_lib/media/media_new/media/file_decoder.h new file mode 100644 index 0000000..9fde7d8 --- /dev/null +++ b/include_lib/media/media_new/media/file_decoder.h @@ -0,0 +1,71 @@ +#ifndef FILE_DECODER_H +#define FILE_DECODER_H + + +#include "media/includes.h" + +enum { + FILE_DEC_STATUS_STOP = 0, // 解码停止 + FILE_DEC_STATUS_PLAY, // 正在解码 + FILE_DEC_STATUS_PAUSE, // 解码暂停 + FILE_DEC_STATUS_WAIT_PAUSE, + FILE_DEC_STATUS_WAIT_PLAY, + FILE_DEC_STATUS_PAUSE_SUCCESS, +}; + + +struct file_decoder { + u8 ch_num; // 声道数 + u8 output_ch_num; // 输出声道数 + u8 status; // 解码状态 + u8 dec_no_out_sound; // 解码不直接输出声音(用于TWS转发) + u8 tmp_pause; // 被其他解码打断,临时暂停 + u32 wait_pause; + u8 remain; + u16 resume_tmr_id; + u16 sample_rate; + u32 coding_type; + u32 dec_total_time; // 总共能播放多长时间 + u32 dec_cur_time; // 当前播放时间 + u32 once_out_cnt; // 解码一次的输出统计 + enum audio_channel ch_type; // 输出类型 + struct audio_decoder decoder; // 解码句柄 + int (*output_handler)(struct file_decoder *dec, s16 *data, int len); + void *tws_sync; + s16 fade_step; + s16 fade_value; +}; + +int file_decoder_open(struct file_decoder *dec, + const struct audio_dec_input *input, + struct audio_decoder_task *decode_task, + struct audio_dec_breakpoint *bp, + u8 pick); + +int frame_decoder_open(struct file_decoder *dec, + const struct audio_dec_input *input, + struct audio_decoder_task *decode_task); + +void file_decoder_close(struct file_decoder *dec); + +void file_decoder_set_output_channel(struct file_decoder *dec); + +void file_decoder_set_event_handler(struct file_decoder *dec, + void (*handler)(struct audio_decoder *, int, int *), u32 maigc); + +bool file_decoder_is_stop(struct file_decoder *file_dec); +bool file_decoder_is_play(struct file_decoder *file_dec); +bool file_decoder_is_pause(struct file_decoder *file_dec); +int file_decoder_pp(struct file_decoder *file_dec); +int file_decoder_FF(struct file_decoder *file_dec, int step); +int file_decoder_FR(struct file_decoder *file_dec, int step); +int file_decoder_get_breakpoint(struct file_decoder *file_dec, struct audio_dec_breakpoint *bp); +int file_decoder_get_total_time(struct file_decoder *file_dec); +int file_decoder_get_cur_time(struct file_decoder *file_dec); +int file_decoder_get_decoder_type(struct file_decoder *file_dec); +void file_decoder_set_tws_sync_enable(struct file_decoder *dec, void *sync); +void file_decoder_mark_tws_sync_data(struct file_decoder *dec, u16 seqn); +void file_decoder_tws_sync_restart(struct file_decoder *dec); + +#endif /*FILE_DECODER_H*/ + diff --git a/include_lib/media/media_new/media/hw_fft.h b/include_lib/media/media_new/media/hw_fft.h new file mode 100644 index 0000000..cd24609 --- /dev/null +++ b/include_lib/media/media_new/media/hw_fft.h @@ -0,0 +1,62 @@ +#ifndef HW_FFT_H +#define HW_FFT_H + +typedef enum { + FFT_V3 = 3, //br23/br25__br30/br34/br36__WL80. + FFT_EXT = 4, //br27/br28__WL82. 扩展模式.FFT硬件模块支持非2的指数次幂点数. +} _FFT_VERSION_; + +typedef struct { + unsigned int fft_config; + const int *in; + int *out; +} pi32v2_hw_fft_ctx; + +/********************************************************************* +* Make_FFT_Config +* Description: 根据配置生成 FFTconfig +* Arguments :N 运算数据量(min:64);log2N 运算数据量的对数值 + same_addr 输入输出是否同一个地址,是则写1,否则写0 + is_ifft IFFT运算写1,FFT运算写0 + is_real 实数运算写1, 复数运算写0 +* Return :FFTN_CON 写入FFT寄存器 +* Note(s) : None. +*********************************************************************/ +unsigned int make_fft_config(int N, int log2N, int same_addr, int is_forward, int is_real); +/********************************************************************* +* _fixfft_wrap +* Description: fft/ifft运算函数 +* Arguments :ctx fft数据结构; + in 输入地址 + out 输出地址 +* Return : void +* Note(s) : None. +*********************************************************************/ +void _fixfft_wrap(pi32v2_hw_fft_ctx *ctx, const int *in, int *out); + + +/********************************************************************* +* 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. +*********************************************************************/ +extern unsigned int hw_fft_config(int N, int log2N, int same_addr, int is_ifft, int is_real); + +/********************************************************************* +* hw_fft_run +* Description: fft/ifft运算函数 +* Arguments :fft_config FFT运算配置寄存器值 + in 输入数据地址 + out 输出数据地址 +* Return : void +* Note(s) : None. +*********************************************************************/ +extern void hw_fft_run(unsigned int cfg, const int *in, int *out); + +#endif/*HW_FFT_H*/ diff --git a/include_lib/media/media_new/media/includes.h b/include_lib/media/media_new/media/includes.h new file mode 100644 index 0000000..082907d --- /dev/null +++ b/include_lib/media/media_new/media/includes.h @@ -0,0 +1,62 @@ +/***************************************************************** +>file name : include_lib/media/includes.h +>author : lichao +>create time : Mon 26 Nov 2018 07:47:14 PM CST +*****************************************************************/ +#ifndef __MEDIA_INCLUDES_H__ +#define __MEDIA_INCLUDES_H__ + +#ifdef CONFIG_AUDIO_ONCHIP + +#include "media/audio_decoder.h" +#include "media/audio_encoder.h" +#include "media/mixer.h" +#include "media/automute.h" +#include "media/audio_stream.h" + +#include "asm/cpu_includes.h" +#include "application/eq_func_define.h" +/* +#include "asm/dac.h" +#include "asm/audio_adc.h" +#if (defined CONFIG_CPU_BR26 || \ + defined CONFIG_CPU_BR23 || \ + defined CONFIG_CPU_BR21 || \ + defined CONFIG_CPU_BR25 || \ + defined CONFIG_CPU_BR30) +#include "asm/audio_src.h" +#endif +*/ + +/*encoder init*/ +extern int msbc_encoder_init(); +extern int cvsd_encoder_init(); +extern int opus_encoder_preinit(); +extern int speex_encoder_preinit(); + +/*decoder init*/ +extern int pcm_decoder_enable(); +extern int cvsd_decoder_init(); +extern int msbc_decoder_init(); +extern int g729_decoder_init(); +extern int sbc_decoder_init(); +extern int mp3_decoder_init(); +extern int wma_decoder_init(); +extern int wav_decoder_init(); +extern int mty_decoder_init(); +extern int flac_decoder_init(); +extern int ape_decoder_init(); +extern int m4a_decoder_init(); +extern int amr_decoder_init(); +extern int dts_decoder_init(); +extern int mp3pick_decoder_init(); +extern int wmapick_decoder_init(); +extern int aac_decoder_init(); + +#if defined CONFIG_CPU_BR23 || \ + defined CONFIG_CPU_BR25 +#include "asm/audio_spdif.h" +#endif + +#endif/*CONFIG_AUDIO_ONCHIP*/ +#endif diff --git a/include_lib/media/media_new/media/limiter_noiseGate_api.h b/include_lib/media/media_new/media/limiter_noiseGate_api.h new file mode 100644 index 0000000..d04eef8 --- /dev/null +++ b/include_lib/media/media_new/media/limiter_noiseGate_api.h @@ -0,0 +1,9 @@ +#ifndef LIMITER_NOISEGATE_API_H +#define LIMITER_NOISEGATE_API_H + +extern int need_limiter_noiseGate_buf(int x); +extern void limiter_noiseGate_init(void *work_buf, int limiter_attfactor, int limiter_relfactor, int noiseGate_attfactor, int noiseGate_relfactor, int limiter_threshold, int noiseGate_threshold, int noiseGate_low_thr_gain, int sample_rate, int channel); +extern int limiter_noiseGate_run(void *work_buf, void *in_buf, void *out_buf, int point_per_channel); + +#endif // !LIMITER_NOISEGATE_API_H + diff --git a/include_lib/media/media_new/media/mixer.h b/include_lib/media/media_new/media/mixer.h new file mode 100644 index 0000000..ba12ad7 --- /dev/null +++ b/include_lib/media/media_new/media/mixer.h @@ -0,0 +1,161 @@ +#ifndef AUDIO_MIXER_H +#define AUDIO_MIXER_H + +#include "generic/typedef.h" +#include "generic/list.h" + +#define MIXER_EXT_MAX_NUM 4 // 扩展输出最大通道 +#define PCM_0dB_VALUE 16384 +enum { + MIXER_EVENT_CH_OPEN, + MIXER_EVENT_CH_CLOSE, + MIXER_EVENT_CH_RESET, +}; +#define BIT16_MODE 0 +#define BIT24_MODE BIT(0) +#define BIT32_MODE BIT(1) + +struct audio_mixer; + +struct audio_mix_handler { + int (*mix_probe)(struct audio_mixer *); + int (*mix_output)(struct audio_mixer *, s16 *, u16); +#if MIXER_EXT_MAX_NUM + /* 扩展输出回调接口 + * 最后一个参数代表当前输出的通道序号,0到ext_output_num-1; + * 扩展输出不检测返回值,每次输出的长度与mix_output的返回值相同; + */ + int (*mix_output_ext)(struct audio_mixer *, s16 *, u16, u8); +#endif + int (*mix_post)(struct audio_mixer *); +}; + +struct audio_mixer { + struct list_head head; + s16 *output; + u16 points; + u16 remain_points; + u32 sample_position : 20; +#if MIXER_EXT_MAX_NUM + int ext_output_addr[MIXER_EXT_MAX_NUM]; // 扩展输出buf地址,每个buf的长度与point相同 + u8 ext_output_num; // 扩展输出通道总数 +#endif + const struct audio_mix_handler *mix_handler; + void (*evt_handler)(struct audio_mixer *, int); + volatile u8 active; + volatile u8 bit_mode_en; + volatile u8 point_len; +}; + +struct audio_pcm_edit { + u8 hide : 1; + u8 highlight : 1; + u8 state; + u8 ch_num; + u8 fade_chs; + s16 fade_step; + s16 fade_volume; + s16 volume; +}; + +struct audio_mixer_ch { + u8 start; + u8 pause; + u8 open; + u32 no_wait : 1; // 不等待有数 + u32 lose : 1; // 丢数标记 + u32 need_resume : 1; + u8 start_by_position; + u16 offset; + u32 sample_rate; + u16 lose_time; // 超过该时间还没有数据,则以为可以丢数。no_wait置1有效 + unsigned long lose_limit_time; // 丢数超时中间运算变量 + struct list_head entry; + struct audio_mixer *mixer; +#if MIXER_EXT_MAX_NUM + u32 ext_out_mask; // 标记该通道输出的扩展通道,如输出到第0和第2个,ext_flag |= BTI(0)|BIT(2) + u8 main_out_dis; // 不输出到主通道 +#endif + u32 slience_samples; + u32 mix_timeout; + u32 starting_position : 20; + void *priv; + void (*event_handler)(void *priv, int event); + void *lose_priv; + void (*lose_callback)(void *lose_priv, int lose_len); + void *resume_data; + void (*resume_callback)(void *); + struct audio_pcm_edit *editor; +}; + + +int audio_mixer_open(struct audio_mixer *mixer); + +void audio_mixer_set_handler(struct audio_mixer *, const struct audio_mix_handler *); + +void audio_mixer_set_event_handler(struct audio_mixer *mixer, + void (*handler)(struct audio_mixer *, int)); + +void audio_mixer_set_output_buf(struct audio_mixer *mixer, s16 *buf, u16 len); + +int audio_mixer_get_sample_rate(struct audio_mixer *mixer); + +int audio_mixer_get_ch_num(struct audio_mixer *mixer); + +int audio_mixer_ch_open(struct audio_mixer_ch *ch, struct audio_mixer *mixer); + +void audio_mixer_ch_set_sample_rate(struct audio_mixer_ch *ch, u32 sample_rate); + +int audio_mixer_reset(struct audio_mixer_ch *ch, struct audio_mixer *mixer); + +int audio_mixer_ch_reset(struct audio_mixer_ch *ch); + +int audio_mixer_ch_write(struct audio_mixer_ch *ch, s16 *data, int len); + +int audio_mixer_ch_close(struct audio_mixer_ch *ch); + +void audio_mixer_ch_pause(struct audio_mixer_ch *ch, u8 pause); + +int audio_mixer_ch_data_len(struct audio_mixer_ch *ch); + +int audio_mixer_ch_add_slience_samples(struct audio_mixer_ch *ch, int samples); + +void audio_mixer_ch_set_resume_handler(struct audio_mixer_ch *ch, void *priv, void (*resume)(void *)); + +int audio_mixer_get_active_ch_num(struct audio_mixer *mixer); + +void audio_mixer_ch_set_event_handler(struct audio_mixer_ch *ch, void *priv, void (*handler)(void *, int)); + +// 设置通道没数据时不等待(超时直接丢数) +void audio_mixer_ch_set_no_wait(struct audio_mixer_ch *ch, void *lose_priv, void (*lose_cb)(void *, int), u8 no_wait, u16 time_ms); + +#if MIXER_EXT_MAX_NUM + +void audio_mixer_set_ext_output_buf(struct audio_mixer *mixer, int *buf_addr_lst, u8 ext_num); + +u32 audio_mixer_ch_get_ext_out_mask(struct audio_mixer_ch *ch); +void audio_mixer_ch_set_ext_out_mask(struct audio_mixer_ch *ch, u32 mask); +void audio_mixer_ch_main_out_disable(struct audio_mixer_ch *ch, u8 disable); + +#endif /* MIXER_EXT_MAX_NUM */ + + +int audio_mixer_get_output_buf_len(struct audio_mixer *mixer); + +int audio_mixer_ch_set_starting_position(struct audio_mixer_ch *ch, u32 postion, int timeout); + +void audio_mixer_position_correct(struct audio_mixer *ch, int diff); + +u32 audio_mixer_get_input_position(struct audio_mixer *mixer); + +int audio_mixer_get_start_ch_num(struct audio_mixer *mixer); + +void audio_mixer_set_mode(struct audio_mixer *mixer, u8 point_len, u8 bit_mode_en); + +int audio_mixer_ch_sound_highlight(struct audio_mixer_ch *ch, int hide_volume, int fade_frames, u8 data_channels); + + + + +#endif + diff --git a/include_lib/media/media_new/media/pitchshifter/pitchshifter_api.h b/include_lib/media/media_new/media/pitchshifter/pitchshifter_api.h new file mode 100644 index 0000000..683d109 --- /dev/null +++ b/include_lib/media/media_new/media/pitchshifter/pitchshifter_api.h @@ -0,0 +1,92 @@ + +#ifndef pitchshifer_api_h__ +#define pitchshifer_api_h__ + +#ifndef u8 +#define u8 unsigned char +#endif + +#ifndef u16 +#define u16 unsigned short +#endif + +#ifndef s16 +#define s16 short +#endif + + +#ifndef u32 +#define u32 unsigned int +#endif + + +#ifndef s32 +#define s32 int +#endif + +#ifndef s16 +#define s16 signed short +#endif + +/*#define EFFECT_OLD_RECORD 0x01 +#define EFFECT_MOYIN 0x0*/ +//#define EFFECT_ROBORT_FLAG 0X04 + +enum { + EFFECT_PITCH_SHIFT = 0x00, + EFFECT_VOICECHANGE_KIN0, + EFFECT_VOICECHANGE_KIN1, + EFFECT_VOICECHANGE_KIN2, + EFFECT_ROBORT, + + EFFECT_AUTOTUNE = 0xfe, + EFFECT_FUNC_NULL = 0xff, +}; + +typedef struct PITCH_SHIFT_PARM_ { + u32 sr; //input audio samplerate + u32 shiftv; //pitch rate: <100(pitch up), >100(pitch down) + u32 effect_v; + u32 formant_shift; +} PITCH_SHIFT_PARM; + +/****** +效果配置说明: +1.EFFECT_PITCH_SHIFT 移频,变调不变速,init_parm.shiftv调节有效,init_parm.formant_shift调节无效 +2.EFFECT_VOICECHANGE_KIN0 变声,可以调节不同的 init_parm.shiftv 跟 init_parm.formant_shift ,调出更多的声音效果 +3.EFFECT_VOICECHANGE_KIN1 变声,同EFFECT_VOICECHANGE_KIN0类似的,但是2者由于运算的不同,会有区别。 +4.EFFECT_ROBORT 机器音效果,类似 喜马拉雅那样的 +5.EFFECT_AUTOTUNE 电音效果 +*******/ + +typedef struct _PITCHSHIFTER_DSP_RUNFUNP_ { + int *buf; + int *inlen; +} PITCHSHIFTER_RUNFUNP; + + +#define C_MAJOR 8192 //c大调 +#define Cshop_MAJOR 8875//升c大调 +#define D_MAJOR 9557 +#define Dshop_MAJOR 10240 +#define E_MAJOR 10923 +#define F_MAJOR 11605 +#define Fshop_MAJOR 12288 +#define G_MAJOR 12971 +#define Gshop_MAJOR 13653 +#define A_MAJOR 14336 +#define Ashop_MAJOR 15019 +#define B_MAJOR 15701 + + +typedef struct _PITCHSHIFT_FUNC_API_ { + u32(*need_buf)(void *ptr, PITCH_SHIFT_PARM *pitchshift_obj); + void (*open)(void *ptr, PITCH_SHIFT_PARM *pitchshift_obj); //中途改变参数,可以调init + void (*run)(void *ptr, short *indata, short *outdata, int len); //len是多少个byte + void (*init)(void *ptr, PITCH_SHIFT_PARM *pitchshift_obj); //中途改变参数,可以调init +} PITCHSHIFT_FUNC_API; + +extern PITCHSHIFT_FUNC_API *get_pitchshift_func_api(); + +#endif // reverb_api_h__ + diff --git a/include_lib/media/media_new/media/sbc_enc.h b/include_lib/media/media_new/media/sbc_enc.h new file mode 100644 index 0000000..0943400 --- /dev/null +++ b/include_lib/media/media_new/media/sbc_enc.h @@ -0,0 +1,145 @@ +/* + * + * Bluetooth low-complexity, subband codec (SBC) library + * + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __SBC_ENC_H +#define __SBC_ENC_H + +#ifdef __cplusplus +extern "C" { +#endif + +//typedef unsigned char uint8 ,u8 ,U8 ,uint8_t; +//typedef unsigned short int uint16 ,UINT16 ,U16 ,u16 ,uint16_t; +//typedef unsigned int uint32 ,UINT32,U32 ,u32 ,uint32_t ,uintptr_t; +//typedef signed char sint8 ,s8 ,S8,int8 ,int8_t; +//typedef signed short int sint16 ,SINT16 ,S16 ,s16,int16,INT16,int16_t ; +//typedef signed int sint32 ,SINT32,S32 ,s32,int32 ,INT32;//,; +//typedef unsigned int size_t,ssize_t; +//typedef int int32_t ; +//typedef unsigned __int64 int64_t; +//typedef __int64 uint64_t ; + + +//#include "typedef.h" +//#include +//#include +#include +#ifndef __GNUC__ +#define SBC_ENCODE +#endif +/* sampling frequency */ +#define SBC_FREQ_16000 0x00 +#define SBC_FREQ_32000 0x01 +#define SBC_FREQ_44100 0x02 +#define SBC_FREQ_48000 0x03 + + +/* blocks */ +#define SBC_BLK_4 0x00 +#define SBC_BLK_8 0x01 +#define SBC_BLK_12 0x02 +#define SBC_BLK_16 0x03 + +/* channel mode */ +#define SBC_MODE_MONO 0x00 +#define SBC_MODE_DUAL_CHANNEL 0x01 +#define SBC_MODE_STEREO 0x02 +#define SBC_MODE_JOINT_STEREO 0x03 + +/* allocation method */ +#define SBC_AM_LOUDNESS 0x00 +#define SBC_AM_SNR 0x01 + +/* subbands */ +#define SBC_SB_4 0x00 +#define SBC_SB_8 0x01 + +/* Data endianness */ +#define SBC_LE 0x00 +#define SBC_BE 0x01 + +typedef struct sbc_struct { + unsigned int flags; + + unsigned char frequency; + unsigned char blocks; + unsigned char subbands; + unsigned char mode; + unsigned char allocation; + unsigned char bitpool; + unsigned char endian; + + void *priv; + void *priv_alloc_base; +} sbc_t; + + + + +unsigned int sbc_enc_query(void); +int sbc_init(sbc_t *sbc, unsigned long flags, void *priv); +int sbc_reinit(sbc_t *sbc, unsigned long flags); + +unsigned int sbc_parse(sbc_t *sbc, const void *input, size_t input_len); + +/* Decodes ONE input block into ONE output block */ +unsigned int sbc_decode(sbc_t *sbc, const void *input, size_t input_len, + void *output, size_t output_len, size_t *written); + +/* Encodes ONE input block into ONE output block */ +unsigned int sbc_encode(sbc_t *sbc, const void *input, size_t input_len, + void *output, size_t output_len, unsigned int *written); + +/* Returns the output block size in bytes */ +//size_t sbc_get_frame_length(sbc_t *sbc); + +/* Returns the time one input/output block takes to play in msec*/ +unsigned sbc_get_frame_duration(sbc_t *sbc); + +/* Returns the input block size in bytes */ +//size_t sbc_get_codesize(sbc_t *sbc); + +const char *sbc_get_implementation_info(sbc_t *sbc); +void sbc_finish(sbc_t *sbc); +//#define htons(x) ( ( (((unsigned short)(x)) >>8) & 0xff) | ((((unsigned short)(x)) & 0xff)<<8) ) + + + +#ifdef __cplusplus +} +#endif + +struct option { + const char *name; + int has_arg; + int *flag; + int val; +}; + + +#endif /* __SBC_ENC_H */ + + diff --git a/include_lib/media/media_new/media/surround/effect_sur_api.h b/include_lib/media/media_new/media/surround/effect_sur_api.h new file mode 100644 index 0000000..c971691 --- /dev/null +++ b/include_lib/media/media_new/media/surround/effect_sur_api.h @@ -0,0 +1,108 @@ +#ifndef effectSUR_api_h__ +#define effectSUR_api_h__ + +/*单耳输入时,channel设置*/ +enum { + EFFECT_CH_L = 0x10, //单声道输入,输出左声道 + EFFECT_CH_R = 0x20, //单声道输入,输出右声道 + EFFECT_CH2_L = 0x30, //双声道输入,输出2个左声道 + EFFECT_CH2_R = 0x40, //双声道输入,输出2个右声道 +}; + +enum { + EFFECT_3D_TYPE0 = 0x01, + EFFECT_3D_TYPE1 = 0x02, //这2个2选1 :如果都置上,优先用EFFECT_3D_TYPE1 + EFFECT_3D_LRDRIFT = 0x04, + EFFECT_3D_ROTATE = 0x08, //这2个2选1 : 如果都置上,优先用EFFECT_3D_ROTATE + EFFECT_3D_TYPE2 = 0x10, + EFFECT_3D_LRDRIFT2 = 0x20, +}; + + +typedef struct __SUR_FUNC_API_ { + unsigned int (*need_buf)(int flag); + unsigned int (*open)(unsigned int *ptr, int effectflag, int nch); + unsigned int (*init)(unsigned int *ptr, int rotatestep, int damping, int feedback, int roomsize); + unsigned int (*run)(unsigned int *ptr, short *inbuf, int len); // len是对点 + unsigned int (*switch_effect)(unsigned int *ptr, int effectflag, int rotatestep, int damping, int feedback, int roomsize);//新增的切换音效参数接口 + unsigned int (*switch_nch)(unsigned int *ptr, int nch);//新增的声道修改接口 +} SUR_FUNC_API; + + +extern SUR_FUNC_API *get_sur_func_api(); + + + +#if 0 +因为复用其他音效的参数接口,所以还是用了4个参数,EFFECT_3D_TYPE2具体参数对应名称应该是 : { + int rotatestep; //无效参数 + int rot60_100ms; //范围0到150 + int wetgain ; //范围0到100 + int delay ; //范围0到100 +} + +默认参数可以用 FFECT_3D_TYPE2 {2, 90, 70, 100}, + +// 由于原本预留参数有些没留出来,为了可以调节频响之类的多效果,所以在原基础上通过把参数列表指针当做其中一个参数传进来 +// 如果 rot60_100ms小于0,wetgain=100的话, 那最后一个参数就是参数列表,这样就可以支持配置更多参数。 + +设置如下: + +flag = EFFECT_3D_TYPE2; +{ {2, -1, 100, surmode_present[MODE_SUR_KTV]}, + {2, -1, 100, surmode_present[MODE_SUR_3DTHE]}, + {2, -1, 100, surmode_present[MODE_SUR_HALL]}, + {2, -1, 100, surmode_present[MODE_SUR_VOICE]}, + {2, -1, 100, surmode_present[MODE_SUR_SUR]} +} + + +//其中参数示例: + +enum { + MODE_SUR_KTV = 0, //ktv模式 + MODE_SUR_3DTHE, //3D影院 + MODE_SUR_HALL, //音乐厅 + MODE_SUR_VOICE, //清澈人声 + MODE_SUR_SUR, //全景环绕 + MODE_SUR_MAX +}; + +//dry,wet,delay,rot60,Erwet,Erfactor,Ewidth,Ertolate,predelay,width,diffusion,dampinglpf,basslpf,bassB +const static int surmode_present[MODE_SUR_MAX][14] = { + {80, 100, 35, 9000, 80, 80, 80, 80, 20, 100, 70, 6500, 4000, 18}, + {80, 100, 90, 10030, 90, 90, 90, 90, 18, 100, 75, 7000, 1000, 29}, + {80, 100, 100, 13000, 100, 100, 100, 100, 20, 100, 72, 9000, 50, 3}, + {80, 100, 20, 5010, 100, 70, 70, 100, 15, 100, 70, 5500, 3500, 60}, + {80, 100, 100, 10000, 80, 80, 80, 90, 10, 100, 72, 8000, 500, 15}, +}; + + +//dry,wet,delay,Erwet,Erfactor,Ewitdh,Ertolate,width,diffusion 范围都是 0到 100 +//rot60 范围是 0到15000, 单位ms +//basslpf: 低频增强频率,范围 0到10000 +//dampinglpf: 高频衰减频率,范围 0到 10000 +//bassB: 低频增强比例 + + +混响调参说明: +1.dry: 干声增益 +2.wet: +整体效果声增益 +3.delay: 反射时间间隔,影响整体空间大小 +4.rot60: +衰减60dB需要的时间, 即衰减速度,如果空间里面的物体吸声厉害,或者比较空旷,衰减比较快 +5.Erwet:早反射声的增益, 早反射声的存在 会让混响听起来更真实。但是不同的增益会影响听感上距离感,空间构造 +6.Erfactor: 早反射声的一个密集程度。 这个值大,早反射声之间间隔比较大。构造的空间感也会相对较大。 较小的话,就反射比较密集。空间感变小。 +7.Ewidth:影响早反射声左右声道的声音差异 +8.Ertolate: +影响漫反射声音反馈的大小 +9.predelay:干声跟效果声的时间间隔。也会影响整体空间感。 +10.width:左右声道的差异,左右声道的差异,会产生立体感。(某些版本的sdk上该参数无效) +11.diffusion: 发散程度, 影响 漫反射声音的变形程度。 +12.dampinglpf:高频衰减过度频率。反射声的一个频率衰减,这是一个斜着往下掉的曲线,影响了反射声中的高频分量。高频分量越多,整体音色越亮,但是成分太多,声音有些乱 +13.basslpf:反射声中的低频增强分量过度频率 +14.bassB: +低频增强比例。 这里的低频增强,其实是压了高频。为了使整体频响不超过1,不引起反馈发散。所以加大了这个值感觉混响弱了。可以适量加大rot60或者Ertolate +#endif +#endif // reverb_api_h__ diff --git a/include_lib/media/media_new/media/sw_drc.h b/include_lib/media/media_new/media/sw_drc.h new file mode 100644 index 0000000..4af7378 --- /dev/null +++ b/include_lib/media/media_new/media/sw_drc.h @@ -0,0 +1,108 @@ +#ifndef __SW_DRC_H +#define __SW_DRC_H + +#include "generic/typedef.h" +#include "generic/list.h" +#include "os/os_api.h" +#include "drc_api.h" + +#define DRC_TYPE_LIMITER 1 +#define DRC_TYPE_COMPRESSOR 2 +#define WDRC_TYPE 3 //wdc 要求,硬件输出24bit、32bit + + +struct drc_limiter { + int attacktime; //启动时间 + int releasetime; //释放时间 + int threshold[2]; //threshold[1]是固定值32768, threshold[0]为界面参数 +}; + +struct drc_compressor { + int attacktime; //启动时间 + int releasetime; //释放时间 + int threshold[3]; //threshold[2]是固定值32768 + int ratio[3]; //ratio[0]为固定值100, ratio[1] ratio[2]为界面参数 +}; + +struct threshold_group { + float in_threshold; + float out_threshold; +}; + +struct wdrc_struct { + u16 attacktime; //启动时间 + u16 releasetime; //释放时间 + struct threshold_group threshold[6]; + float inputgain; //wdrc输入数据放大或者缩小的db数(正数放大,负数缩小), 例如配2表示 总体增加2dB + float outputgain; //wdrc输出数据放大或者缩小的db数(正数放大,负数缩小) + u8 threshold_num; + u8 rms_time; + u8 algorithm;//0:PEAK 1:RMS + u8 mode;//0:PERPOINT 1:TWOPOINT + u16 holdtime; //预留位置 + u8 reverved[2];//预留位置 +}; +//对耳wdrc处理,区分左右声道 +#define L_wdrc 0x10 +#define LL_wdrc 0x20 +#define R_wdrc 0x40 +#define RR_wdrc 0x80 + +struct drc_ch_org { + u8 nband; //max<=3,1:全带 2:两段 3:三段 + u8 type; //0:没有使能限幅和压缩器,1:限幅器   2:压缩器 3:wdrc + u8 reserved[2]; //reserved[1]保留,未用, reserved[0]记录了 多带限幅时,是否再开启一次全带限幅 + int low_freq; //中低频分频点 + int high_freq; //中高频分频点 + int order; //分频器阶数, 2或者4 + union { + struct drc_limiter limiter[4]; //限幅器 + struct drc_compressor compressor[3];//压缩器 + } _p; +}; + +struct drc_ch { + u8 nband; //max<=3,1:全带 2:两段 3:三段 + u8 type; //0:没有使能限幅和压缩器,1:限幅器   2:压缩器 3:wdrc(wdrc不支持3带) + u8 reserved[2]; //reserved[1]保留,未用, reserved[0]记录了 多带限幅时,是否再开启一次全带限幅 + int low_freq; //中低频分频点 + int high_freq; //中高频分频点 + int order; //分频器阶数, 2或者4 + union { + struct drc_limiter limiter[4]; //限幅器 64byte + struct drc_compressor compressor[3];//压缩器 96byte + struct wdrc_struct wdrc[2];//low high 136byte + } _p; +}; +struct sw_drc { + void *work_buf[4]; //drc内部驱动句柄 + void *crossoverBuf; //分频器句柄 + int *run_tmp[3]; //多带限幅器或压缩器,运行buf + int run_tmp_len; //多带限幅器或压缩器,运行buf 长度 + u8 nband; //max<=3,1:全带 2:两段 3:三段 + u8 type; //0:没有使能限幅和压缩器,1:限幅器   2:压缩器 + u8 channel; //通道数 + u8 run32bit; //drc处理输入输出数据位宽是否是32bit 1:32bit 0:16bit + struct audio_eq *crossover[3];//多带分频器eq句柄 + u32 sample_rate; //采样率 + u8 nsection; //分频器eq段数 + u8 other_band_en; //多带限幅器之后,是否需要再做一次全带的限幅器 1:需要,0:不需要 +}; +extern void *get_low_sosmatrix(); +extern void *get_high_sosmatrix(); +extern void *get_band_sosmatrix(); +extern int get_crossover_nsection(); + + +extern void *audio_sw_drc_open(struct drc_ch *ch_tmp, u32 sample_rate, u8 channel, u8 drc_name, u8 run32bit); +extern void audio_sw_drc_close(void *hdl); +extern int audio_sw_drc_update(void *hdl, struct drc_ch *ch_tmp, u32 sample_rate, u8 channel); +extern int audio_sw_drc_run(void *hdl, s16 *in_buf, s16 *out_buf, int npoint_per_channel); + + +void audio_hw_crossover_open(struct sw_drc *drc, int (*L_coeff)[3], u8 nsection); +void audio_hw_crossover_close(struct sw_drc *drc); +void audio_hw_crossover_run(struct sw_drc *drc, s16 *data, int len); +void audio_hw_crossover_update(struct sw_drc *drc, int (*L_coeff)[3], u8 nsection); + +#endif diff --git a/include_lib/media/pemafrow_api.h b/include_lib/media/pemafrow_api.h new file mode 100644 index 0000000..f5a31e5 --- /dev/null +++ b/include_lib/media/pemafrow_api.h @@ -0,0 +1,23 @@ +#ifndef PEMAFROW_API_H +#define PEMAFROW_API_H + +#include "media/audio_stream.h" + +#define PEMAFROW_RUN_POINT_NUM 128 //每次run固定点数 +int getPemafrowBuf(); +void pemafrowInit(void *workBuf); +//int pemafrowRun(void *workBuf, short *in, short *out, int len); +int pemafrowRun(void *workBuf, short *in, short *preOut, short *out); + +typedef struct _PEMAFROW_API_STRUCT_ { + void *ptr; //运算buf指针 + s16 pre_data[PEMAFROW_RUN_POINT_NUM]; + s16 data_buf[PEMAFROW_RUN_POINT_NUM]; + struct audio_stream_entry entry; // 音频流入口 + int out_len; + int process_len; + u16 data_len; + u8 run_en; +} PEMAFROW_API_STRUCT; + +#endif diff --git a/include_lib/media/sound/pcm.h b/include_lib/media/sound/pcm.h new file mode 100644 index 0000000..e4758a1 --- /dev/null +++ b/include_lib/media/sound/pcm.h @@ -0,0 +1,330 @@ +/***************************************************************** +>file name : pcm.h +>create time : Mon 18 Jan 2021 02:04:15 PM CST +*****************************************************************/ +#ifndef _SOUND_PCM_H_ +#define _SOUND_PCM_H_ +#include "audio_cfifo.h" +#include "os/os_api.h" + +struct sound_pcm_hardware { + unsigned int info; /* SOUND_PCM_INFO_* */ + unsigned int formats; /* SOUND_PCM_FMTBIT_* */ + unsigned int rates; /* SOUND_PCM_RATE_* */ + unsigned int rate_min; /* min rate */ + unsigned int rate_max; /* max rate */ + unsigned int channels_min; /* min channels */ + unsigned int channels_max; /* max channels */ + int buffer_bytes_max; /* max buffer size */ + int period_bytes_min; /* min period size */ + int period_bytes_max; /* max period size */ + unsigned int periods_min; /* min # of periods */ + unsigned int periods_max; /* max # of periods */ + int fifo_size; /* fifo size in bytes */ +}; + +struct sound_pcm_substream; +struct sound_pcm_hw_params; + +/*****************************************************************************/ +/* SOUND PCM逻辑设备错误返回值*/ +#define ESNDPCM_NOMEM 1 /* PCM设备申请不到内存 */ +#define ESNDPCM_NODEV 2 /* 找不到PCM设备 */ +#define ESNDPCM_INVAL 3 /* 无效的设备平台(未初始化) */ +#define ESNDPCM_UNKNOWN_RATE 4 /* PCM设备不支持的采样率 */ +#define ESNDPCM_CONFLICT_RATE 5 /* PCM设备与设置采样率冲突 */ +#define ESNDPCM_NOFIFO 6 /* PCM设备中没有设置runtime的fifo */ + +/*****************************************************************************/ + +#define SOUND_PCM_TRIGGER_START 1 /* 触发DMA/CODEC开启 */ +#define SOUND_PCM_TRIGGER_STOP 2 /* 触发DMA/CODEC停止 */ +#define SOUND_PCM_TRIGGER_IRQ 3 /* 触发DMA下一个中断外传 */ + +#define SOUND_PCM_GET_HW_PARAMS _IOR('P', 1, sizeof(struct sound_pcm_hw_params)) /* Get硬件参数 */ +#define SOUND_PCM_SET_HW_PARAMS _IOW('P', 2, sizeof(struct sound_pcm_hw_params)) /* Set硬件参数 */ +#define SOUND_PCM_GET_HW_BUFFERED_LEN _IOR('P', 3, sizeof(unsigned int)) /* Get硬件参数 */ +#define SOUND_PCM_WAIT_SWN_MOVE _IOR('P', 4, sizeof(unsigned int)) /* 等待dac swn 输出一个点后,再往后走硬件参数 */ +#define SOUND_PCM_GET_HW_HRP _IOR('P', 5, sizeof(unsigned int)) /* Get硬件读指针 */ + +enum pcm_state { + SOUND_PCM_STATE_IDLE = 0, /* PCM设备空闲 */ + SOUND_PCM_STATE_PREPARED, /* PCM设备硬件准备就绪 */ + SOUND_PCM_STATE_RUNNING, /* PCM设备DMA/CODEC运行中 */ + SOUND_PCM_STATE_SUSPENDED, /* PCM设备挂起 */ +}; + +/* + * Sound PCM设备支持标准sample rate定义 + * */ +#define SOUND_PCM_RATE_8000 (1<<0) /* 8000Hz */ +#define SOUND_PCM_RATE_11025 (1<<1) /* 11025Hz */ +#define SOUND_PCM_RATE_12000 (1<<2) /* 12000Hz */ +#define SOUND_PCM_RATE_16000 (1<<3) /* 16000Hz */ +#define SOUND_PCM_RATE_22050 (1<<4) /* 22050Hz */ +#define SOUND_PCM_RATE_24000 (1<<5) /* 24000Hz */ +#define SOUND_PCM_RATE_32000 (1<<6) /* 32000Hz */ +#define SOUND_PCM_RATE_44100 (1<<7) /* 44100Hz */ +#define SOUND_PCM_RATE_48000 (1<<8) /* 48000Hz */ +#define SOUND_PCM_RATE_64000 (1<<9) /* 64000Hz */ +#define SOUND_PCM_RATE_88200 (1<<10) /* 88200Hz */ +#define SOUND_PCM_RATE_96000 (1<<11) /* 96000Hz */ +#define SOUND_PCM_RATE_128000 (1<<12) /* 128000Hz */ +#define SOUND_PCM_RATE_176400 (1<<13) /* 176400Hz */ +#define SOUND_PCM_RATE_192000 (1<<14) /* 192000Hz */ +#define SOUND_PCM_RATE_UNKNOWN (1<<15) /* Unknown sample rate */ + +#define SOUND_PCM_RATE_8000_44100 (SOUND_PCM_RATE_8000|SOUND_PCM_RATE_11025|SOUND_PCM_RATE_12000|\ + SOUND_PCM_RATE_16000|SOUND_PCM_RATE_22050|SOUND_PCM_RATE_24000|\ + SOUND_PCM_RATE_32000|SOUND_PCM_RATE_44100) +#define SOUND_PCM_RATE_8000_48000 (SOUND_PCM_RATE_8000_44100|SOUND_PCM_RATE_48000) +#define SOUND_PCM_RATE_8000_96000 (SOUND_PCM_RATE_8000_48000|SOUND_PCM_RATE_64000|\ + SOUND_PCM_RATE_88200|SOUND_PCM_RATE_96000) +#define SOUND_PCM_RATE_8000_192000 (SOUND_PCM_RATE_8000_96000|SOUND_PCM_RATE_128000|SOUND_PCM_RATE_176400|\ + SOUND_PCM_RATE_192000) + +/* + * PCM设备与硬件DMA同步flag + */ +#define DMA_SYNC_R (1 << 0) /* 读同步 */ +#define DMA_SYNC_W (1 << 1) /* 写同步 */ +#define DMA_SYNC_RW (DMA_SYNC_R | DMA_SYNC_W) /* 读写同步 */ + +/* + * Sound运行时间单位 + */ +#define SOUND_TIME_MS 0 +#define SOUND_TIME_US 1 + + +/* + * PCM设备操作函数 + */ +struct sound_pcm_ops { + int (*open)(struct sound_pcm_substream *substream); + int (*close)(struct sound_pcm_substream *substream); + int (*ioctl)(struct sound_pcm_substream *substream, + unsigned int cmd, void *arg); + int (*prepare)(struct sound_pcm_substream *substream); + int (*trigger)(struct sound_pcm_substream *substream, int cmd); + int (*pointer)(struct sound_pcm_substream *substream); + int (*silence)(struct sound_pcm_substream *substream, int channel, u32 pos, u32 count); +}; + + +struct sound_pcm_hw_params { + u32 rates; + int sample_rate; + u8 sample_bits; + u8 channels; +}; + +struct sound_dma_buffer { + u8 mode; + void *addr; + s16 size; + struct audio_cfifo fifo; +}; + +struct sound_pcm_map_status { + u8 state; + u8 ref_count; +}; + +struct sound_pcm_map_fifo { + void *addr; /* FIFO地址 */ + u16 bytes; /* FIFO大小(bytes) */ + u16 frame_len; /* FIFO帧总长度(bytes / ch / 2) */ + struct audio_cfifo cfifo; /* FIFO结构实体 */ + void (*sync)(struct sound_pcm_substream *substream, u8 flag); /* FIFO同步 */ +}; + +struct sound_pcm_runtime { + /*fifo*/ + u32 hw_ptr; /* 当前硬件位置 */ + u32 sw_ptr; /* 当前软件位置 */ + u32 hw_ptr_jiffies; /* 当前硬件位置对应的时间 */ + u32 dma_irq_ptr; /* 设置的dma到达该ptr起中断 */ + u32(*sound_current_time)(void); /* 当前采样时间获取 */ + struct sound_pcm_map_fifo *fifo; + u8 time_type; /* 采样指针位置的时钟类型 */ + + /* -- HW params -- */ + u8 channels; /* 采样通道 */ + u8 sample_bits; + u16 period_size; /* 采样周期块大小(pingpong buffer模式) */ + u32 periods; /* 采样周期个数 */ + int sample_rate; /* sample_rate */ + + /* -- SW params -- */ + u8 run_mode; /*OVERRUN或非OVERRUN*/ + //u32 start_threshold; [>启动DMA的阈值<] + //u32 stop_threshold; [>停止DMA的阈值<] + //u32 silence_threshold; [>静音数据阈值 <] + //u32 silence_size; [>填充静音数据的大小 <] + + u32 silence_start; /* 静音起始位置 */ + u32 silence_filled; /* 已填充的静音数据 */ + int buffer_delay; + + struct sound_pcm_map_status *status; /*映射硬件中的状态*/ + + /* -- DMA -- */ + struct sound_dma_buffer *dma; /* DMA缓冲 */ + + OS_MUTEX *mutex; +}; + + +struct sound_pcm_stream; +struct sound_pcm_substream { + struct sound_pcm_stream *stream; + struct sound_pcm_runtime *runtime; /* 数据流运行结构 */ + struct audio_cfifo_channel fifo; /* fifo缓冲 */ + void *private_data; + struct list_head entry; + void *irq_priv; + void (*irq_handler)(void *priv); + u8 direction; /* 数据流方向 */ + unsigned int hw_opened: 1; +}; + +struct sound_pcm_stream { + struct sound_pcm_substream *substream; /* 与设备共享的子数据流 */ + const struct sound_pcm_ops *ops; /* PCM操作函数 */ + void *platform_device; + void *syncts; +}; + + +/************************************************************************* + * 采样率转换为bit表示 + * Input : sample_rate - 采样率 + * Output : 采样率的bit表示 + * Notes : + * History : 2021/03/11 by Lichao. + *=======================================================================*/ +int sound_pcm_match_standard_rate(int sample_rate); + +/************************************************************************* + * 创建sound pcm数据流 + * Input : stream - sound_pcm_stream二级指针, + * name - 设备名, + * direction - 数据流方向. + * Output : 0 - 创建成功,非0 - 失败. + * Notes : + * History : 2021/03/11 by Lichao. + *=======================================================================*/ +int sound_pcm_create(struct sound_pcm_stream **stream, const char *name, u8 direction); + +/************************************************************************* + * 设置pcm设备中断处理函数 + * Input : stream - sound_pcm_stream指针, + * priv - 回调私有数据, + * handler - 回调处理函数. + * Output : 无. + * Notes : pingpong模式可以用来处理音频采样定时, + * 也可以使用中断处理唤醒等功能。 + * History : 2021/03/11 by Lichao. + *=======================================================================*/ +void sound_pcm_set_irq_handler(struct sound_pcm_stream *stream, void *priv, void (*handler)(void *)); + +/************************************************************************* + * pcm设备数据流准备 + * Input : stream - sound_pcm_stream指针, + * sample_rate - 设备采样率, + * delay - 设备缓冲延时, + * mode - 数据流overrun/block模式选择. + * Output : 0 - 成功,非0 - 失败. + * Notes : + * History : 2021/03/11 by Lichao. + *=======================================================================*/ +int sound_pcm_prepare(struct sound_pcm_stream *stream, int sample_rate, int delay, int mode); + +/************************************************************************* + * pcm设备数据流开启采样 + * Input : stream - sound_pcm_stream指针. + * Output : 0 - 成功,非0 - 失败. + * Notes : + * History : 2021/03/11 by Lichao. + *=======================================================================*/ +int sound_pcm_start(struct sound_pcm_stream *stream); + +/************************************************************************* + * pcm设备数据流停止采样 + * Input : stream - sound_pcm_stream指针. + * Output : 0 - 成功,非0 - 失败. + * Notes : + * History : 2021/03/11 by Lichao. + *=======================================================================*/ +int sound_pcm_stop(struct sound_pcm_stream *stream); + +/************************************************************************* + * pcm设备数据流触发一次中断 + * Input : stream - sound_pcm_stream指针, + * time_unit - 设置中断起来时间的单位, + * time - 设置多少时间后起来(临近). + * Output : 0 - 成功,非0 - 失败. + * Notes : + * History : 2021/03/11 by Lichao. + *=======================================================================*/ +int sound_pcm_trigger_interrupt(struct sound_pcm_stream *stream, u8 time_unit, int time); + +/************************************************************************* + * pcm设备数据子流中断处理函数 + * Input : substream - sound_pcm_substream指针. + * Output : 0 - 成功,非0 - 失败. + * Notes : 一般由设备的DMA中断调用该函数进行中断分配和更新DMA信息. + * History : 2021/03/11 by Lichao. + *=======================================================================*/ +int sound_pcm_substream_irq_handler(struct sound_pcm_substream *substream); + +/************************************************************************* + * pcm设备设置数据声道分布 + * Input : stream - sound_pcm_stream指针, + * map - 声道分布. + * Output : 0 - 成功,非0 - 失败. + * Notes : + * History : 2021/03/11 by Lichao. + *=======================================================================*/ +int sound_pcm_set_data_map(struct sound_pcm_stream *stream, u16 map); + +/************************************************************************* + * pcm设备写入数据 + * Input : stream - sound_pcm_stream指针, + * data - 数字音频数据, + * len - 数据长度. + * Output : 实际写入的长度. + * Notes : + * History : 2021/03/11 by Lichao. + *=======================================================================*/ +int sound_pcm_write(struct sound_pcm_stream *stream, void *data, int len); + +/************************************************************************* + * pcm设备io控制函数 + * Input : stream - sound_pcm_stream指针, + * cmd - 命令, + * arg - 参数. + * Output : 0 - 成功,非0 - 失败. + * Notes : PCM数据流的ioctl函数(数字音频相关) + * History : 2021/03/11 by Lichao. + *=======================================================================*/ +int sound_pcm_iotcl(struct sound_pcm_stream *stream, int cmd, void *arg); + +/************************************************************************* + * pcm设备控制器io控制函数 + * Input : stream - sound_pcm_stream指针, + * cmd - 命令, + * arg - 参数. + * Output : 0 - 成功,非0 - 失败. + * Notes : PCM设备的控制器ioctl函数(增益/电源等相关) + * History : 2021/03/11 by Lichao. + *=======================================================================*/ +int sound_pcm_ctl_ioctl(struct sound_pcm_stream *stream, int cmd, void *arg); +int sound_pcm_read(struct sound_pcm_stream *stream, void *data, int len); +void sound_pcm_free(struct sound_pcm_stream *stream); + + +void sound_pcm_set_syncts(struct sound_pcm_stream *stream, void *syncts); + +#endif diff --git a/include_lib/media/sound/sound.h b/include_lib/media/sound/sound.h new file mode 100644 index 0000000..02cde29 --- /dev/null +++ b/include_lib/media/sound/sound.h @@ -0,0 +1,113 @@ +/***************************************************************** +> file name : sound.h +> +*****************************************************************/ +#ifndef _AUDIO_SOUND_H_ +#define _AUDIO_SOUND_H_ +#include "generic/ioctl.h" +#include "sound/pcm.h" +#include "os/os_api.h" + +#define SOUND_PCM_DMA_CFIFO_MODE 0 /*FIFO与DMA地址映射关系方式*/ +#define SOUND_PCM_DMA_PERIOD_MODE 1 /*DMA周期采样方式*/ + +/* + * Sound声道分布定义 + */ +#define SOUND_CHMAP_MONO (1 << 0) +#define SOUND_CHMAP_FL SOUND_CHMAP_MONO +#define SOUND_CHMAP_FR (1 << 1) +#define SOUND_CHMAP_RL (1 << 2) +#define SOUND_CHMAP_RR (1 << 3) + +struct sound_volume; +/* + * Sound control IOCTL命令 + */ +//#define SNDCTL_IOCTL_GET_GAIN_RANGE _IOR('A', 1, sizeof(struct sound_volume)) +#define SNDCTL_IOCTL_POWER_ON _IOW('A', 1, sizeof(int)) /* 控制器上电 */ +#define SNDCTL_IOCTL_POWER_OFF _IOW('A', 2, sizeof(int)) /* 控制器断电 */ +#define SNDCTL_IOCTL_SET_ANA_GAIN _IOW('A', 5, sizeof(struct sound_volume)) /* 设置模拟增益 */ +#define SNDCTL_IOCTL_GET_ANA_GAIN _IOR('A', 6, sizeof(struct sound_volume)) /* 获取模拟增益 */ +#define SNDCTL_IOCTL_SET_DIG_GAIN _IOW('A', 7, sizeof(struct sound_volume)) /* 设置数字增益 */ +#define SNDCTL_IOCTL_GET_DIG_GAIN _IOR('A', 8, sizeof(struct sound_volume)) /* 获取数字增益 */ +#define SNDCTL_IOCTL_SET_BIAS_TRIM _IOW('A', 9, sizeof(int)) /* TRIM */ + + +struct sound_volume { + u32 chmap; + s16 volume[4]; +}; +/* + * PCM设备软硬件平台配置 + */ +struct sound_pcm_platform_data { + void *dma_addr; /*DMA 地址*/ + int dma_bytes; /*DMA 字节长度*/ + int fifo_bytes; /*FIFO 长度*/ + void *private_data; /*Soc私有数据*/ +}; + +/* + * 驱动控制器,由驱动实现 + */ +struct sound_drv_controller { + int (*power_on)(void *device); /*上电*/ + int (*power_off)(void *device); /*断电*/ + int (*ioctl)(void *device, int cmd, void *args); /*Control控制函数*/ +}; + +/* + * Platform驱动,由驱动实现 + */ +struct sound_platform_driver { + const char *name; + const struct sound_drv_controller *controller; + const struct sound_pcm_ops *ops; + int (*create)(void **device, struct sound_pcm_platform_data *data); /*创建新的设备*/ + void (*free)(void *device); /*关闭设备*/ + +}; + + +/* + * Platform挂载的子设备 + */ +struct sound_platform_subdevice { + char name[8]; + //const char *name; + struct sound_platform_driver *driver; + void *private_data; + void *parent; + struct list_head entry; + OS_MUTEX mutex; +}; + +/* + * Platform管理总结构 + */ +struct sound_platform { + struct list_head list; +}; +/* + * + * + */ +int sound_platform_init(void); +int sound_platform_load(const char *name, struct sound_pcm_platform_data *data); +int sound_platform_power_on(const char *name); +int sound_platform_power_off(const char *name); +int sound_platform_free(const char *name); + +int sound_platform_register(const struct sound_platform_driver *driver); + +#define SOUND_PLATFORM_DRIVER(name) \ + const struct sound_platform_driver name sec(.sound_platform_driver) + +/* +typedef int (*sound_register_t)(void); + +#define __sound_platform_init(func) \ + const sound_register_t __##func sec(.sound_platform_register) = func +*/ +#endif diff --git a/include_lib/media/sw_drc.h b/include_lib/media/sw_drc.h new file mode 100644 index 0000000..5cf3f48 --- /dev/null +++ b/include_lib/media/sw_drc.h @@ -0,0 +1,98 @@ +#ifndef CONFIG_EFFECT_CORE_V2_ENABLE +#include "media/media_develop/media/sw_drc.h" +#else + +#ifndef __SW_DRC_H +#define __SW_DRC_H + +#include "generic/typedef.h" +#include "generic/list.h" +#include "os/os_api.h" +#include "drc_api.h" + + +//分频器 crossover: +typedef struct _CrossOverParam_TOOL_SET { + int way_num; //段数 + int N; //阶数 + int low_freq; //低中分频点 + int high_freq; //高中分频点 +} CrossOverParam_TOOL_SET; + + +struct threshold_group { + float in_threshold; + float out_threshold; +}; + +struct wdrc_struct { + u16 attacktime; //启动时间 + u16 releasetime; //释放时间 + struct threshold_group threshold[6]; + float inputgain; //wdrc输入数据放大或者缩小的db数(正数放大,负数缩小), 例如配2表示 总体增加2dB + float outputgain; //wdrc输出数据放大或者缩小的db数(正数放大,负数缩小) + u8 threshold_num; + u8 rms_time; + u8 algorithm;//0:PEAK 1:RMS + u8 mode;//0:PERPOINT 1:TWOPOINT + u16 holdtime; //预留位置 + u8 reverved[2];//预留位置 +}; + +//动态范围控制 DRC: +typedef struct _wdrc_struct_TOOL_SET { + int is_bypass; // 1-> byass 0 -> no bypass + struct wdrc_struct parm; +} wdrc_struct_TOOL_SET; + + + +/* //对耳wdrc处理,区分左右声道 */ +// #define L_wdrc 0x10 +// #define LL_wdrc 0x20 +// #define R_wdrc 0x40 +/* #define RR_wdrc 0x80 */ + +struct drc_ch { + CrossOverParam_TOOL_SET crossover; + union { + struct wdrc_struct wdrc[4];//[0]low [1]mid [2]high [3]多带之后,再做一次全带 + } _p; +}; + + +struct sw_drc { + void *work_buf[4]; //drc内部驱动句柄 + void *crossoverBuf; //分频器句柄 + int *run_tmp[3]; //多带限幅器或压缩器,运行buf + int run_tmp_len; //多带限幅器或压缩器,运行buf 长度 + u8 nband; //max<=3,1:全带 2:两段 3:三段 + u8 channel; //通道数 + u8 run32bit; //drc处理输入输出数据位宽是否是32bit 1:32bit 0:16bit + struct audio_eq *crossover[3];//多带分频器eq句柄 + u32 sample_rate; //采样率 + u8 nsection; //分频器eq段数 + u8 other_band_en; //多带限幅器之后,是否需要再做一次全带的限幅器 1:需要,0:不需要 + u8 bypass[4]; +}; +extern void *get_low_sosmatrix(); +extern void *get_high_sosmatrix(); +extern void *get_band_sosmatrix(); +extern int get_crossover_nsection(); + + +void *audio_sw_drc_open(void *crossover, void *wdrc, u32 sample_rate, u8 channel, u8 run32bit, u8 other_band_en); +extern void audio_sw_drc_close(void *hdl); +int audio_sw_drc_update(void *hdl, void *crossover, void *wdrc, u32 sample_rate, u8 channel); +extern int audio_sw_drc_run(void *hdl, s16 *in_buf, s16 *out_buf, int npoint_per_channel); +void sw_drc_set_bypass(struct sw_drc *drc, u8 tar, u8 bypass); + +void audio_hw_crossover_open(struct sw_drc *drc, int (*L_coeff)[3], u8 nsection); +void audio_hw_crossover_close(struct sw_drc *drc); +void audio_hw_crossover_run(struct sw_drc *drc, s16 *data, int len); +void audio_hw_crossover_update(struct sw_drc *drc, int (*L_coeff)[3], u8 nsection); + +void band_merging_32bit(int *in0, int *in1, int *in2, s32 *out_buf_tmp, int points, u8 nband); +void band_merging_16bit(short *in0, short *in1, short *in2, short *out_buf_tmp, int points, u8 nband); +#endif +#endif /*CONFIG_EFFECT_CORE_V2_ENABLE*/ diff --git a/include_lib/media/tech_lib/LFaudio_plc_api.h b/include_lib/media/tech_lib/LFaudio_plc_api.h new file mode 100644 index 0000000..6a78ab3 --- /dev/null +++ b/include_lib/media/tech_lib/LFaudio_plc_api.h @@ -0,0 +1,48 @@ +#ifndef _LFaudio_PLC_API_H +#define _LFaudio_PLC_API_H + + + + +typedef struct _LFaudio_PLC_API { + unsigned int (*need_buf)(int nch); + void (*open)(unsigned char *ptr, int nch, int mode); //mode从0到4, 4是最低延时 + int (*run)(unsigned char *ptr, short *inbuf, short *obuf, short len, short err_flag); //len是按多少个点的,inbuf跟obuf可以同址的 +} LFaudio_PLC_API; + + +extern LFaudio_PLC_API *get_lfaudioPLC_api(); + +#endif + +#if 0 + +#define PACKET_LEN 30 +#define PACKET_FILL_VAL 0x1500 + +/*调用示例*/ +{ + int bufsize; + unsigned char *bufptr; + BT15_REPAIR_API *test_repair = get_repair_api(); + + bufsize = test_repair->need_buf(nch); + bufptr = malloc(bufsize); //开辟空间 + test_repair->open(bufptr, nch); //传入参数,参数1是buf地址,参数2是声道, 参数3是延时模式 + + while (1) { + fread(inbuf, 2, PACKET_LEN, fpin); + if (feof(fpin)) { + break; //input data + } + + test_repair->run(bufptr, inbuf, outbuf, PACKET_LEN, err); //err=1是差错帧,要不然为0 + + fwrite(outbuf, 2, PACKET_LEN, fpout); //output data + + } + + free(bufptr); + +} +#endif diff --git a/include_lib/media/tech_lib/SensorCalib_api.h b/include_lib/media/tech_lib/SensorCalib_api.h new file mode 100644 index 0000000..4980162 --- /dev/null +++ b/include_lib/media/tech_lib/SensorCalib_api.h @@ -0,0 +1,31 @@ +#ifndef SENSORCALIB_API_H +#define SENSORCALIB_API_H +#include "tech_lib/SpatialAudio_api.h" + +//校准阈值 +typedef struct { + float thv1;//加速度计校准阈值1 + float thv2;// +} Thval_t; + +enum { + type_0 = 0, + type_1, + type_2 +}; +enum { + mode_0 = 0, + mode_1 +}; + +int GroCelBuff(); +void GroCelInit(void *buf, info_spa_t *para, int time); +int Gro_Calibration(void *ptr, short *data, info_spa_t *para, tranval_t *, int mode, gyro_cel_t *agv); + +int AccCelBuff(); +void AccCelInit(void *ptr, info_spa_t *para, int time); +int Acc_Calibration(void *ptr, short *data, info_spa_t *para, acc_cel_t *ac, Thval_t *tv); + +#endif // !1 + + diff --git a/include_lib/media/tech_lib/SpatialAudio_api.h b/include_lib/media/tech_lib/SpatialAudio_api.h new file mode 100644 index 0000000..465e856 --- /dev/null +++ b/include_lib/media/tech_lib/SpatialAudio_api.h @@ -0,0 +1,54 @@ +#ifndef SPATIALAUDIO_API_H +#define SPATIALAUDIO_API_H + +typedef struct TRANVAL { + int trans_x[3]; + int trans_y[3]; + int trans_z[3]; + +} tranval_t; + +typedef struct COMMON_INFO { + float fs;//采样率 + int len;//一包数据长度 + float sensitivity;//陀螺仪灵敏度 + int range;//加速度计量程(正) +} info_spa_t; + +typedef struct { + float beta; + float val;//陀螺仪参考阈值 + float cel_val;//动态校准参考阈值 + float time;//动态校准时长 + float SerialTime;//动态校准窗长 + float sensval;//角度灵敏度,越小越灵敏,范围:0.01~0.1,默认0.1 +} spatial_config_t; + +//陀螺仪偏置 +typedef struct { + float gyro_x; + float gyro_y; + float gyro_z; +} gyro_cel_t; + +//加速度计偏置 +typedef struct { + float acc_offx; + float acc_offy; + float acc_offz; +} acc_cel_t; + +extern inline float root_float(float x); +extern inline float angle_float(float x, float y); +int get_Spatial_buf(int len); +void init_Spatial(void *ptr, info_spa_t *, tranval_t *, spatial_config_t *, gyro_cel_t *, acc_cel_t *ac); +void Spatial_cacl(void *ptr, short *data); +int get_Spa_angle(void *ptr, float alpha, float voloct); +void Spatial_reset(void *ptr); +int Spatial_stra(void *ptr, int time, float val1); +int get_test_angle(void *ptr); +//int get_Pitch_angle(void* ptr); + +#endif // !1 + + diff --git a/include_lib/media/tech_lib/effect_surTheta_api.h b/include_lib/media/tech_lib/effect_surTheta_api.h new file mode 100644 index 0000000..c49b167 --- /dev/null +++ b/include_lib/media/tech_lib/effect_surTheta_api.h @@ -0,0 +1,80 @@ +#ifndef effect_surTheta_h__ +#define effect_surTheta_h__ + +typedef struct _PointSound360TD_PARM_SET { + int theta; + int volume; +} PointSound360TD_PARM_SET; + +//混响参数 +typedef struct _RP_PARM_CONIFG { + int trackKIND; //角度合成算法用哪一种 :0或者1 + int ReverbKIND; //2或者3 + int reverbance; //湿声比例 : 0~100 + int dampingval; //高频decay :0~80 +} RP_PARM_CONIFG; + +typedef struct _PointSound360Reverb_PARM_SET { + unsigned char reverbance; //0-100: //reverb parm + unsigned char dampingval; //0-100% //reverb parm + unsigned char voltrack; // 0-1 // vol track + char doangle; // 0 or 1 + + char diangle; // 0-360 : 2 channel angle + unsigned char wet; //0-100://backgroud + unsigned char dry; //0-100 ://voice part + char reverb_kind; //reverb kind + + unsigned short k1_w; //0-2000: output wetgain + unsigned short k1_d; //0-2000: output drygain + + char reverb_part; // 0-128 // mix wet and wet_dry reverb + + char reserved0; + short dest_vol; // dest vol; + +} PointSound360Reverb_PARM_SET; + +//角度合成算法定义 +enum { + P360_T0 = 0, + P360_T1 = 1 +}; + +//混响算法定义 +enum { + P360_R0 = 2, + P360_R1 = 3 +}; + +enum { + PSOUND_BOTH = 0, + PSOUND_L = 1, + PSOUND_R = 2 +}; + +enum { + P360TD_NO_REV = 0, + P360TD_REV_K0 = 1, + P360TD_REV_K1 = 2, + P360TD_REV_K3 = 3, + P360TD_REV_K4 = 4 +}; + + + + +typedef struct __PointSound360TD_FUNC_API_ { + unsigned int (*need_buf)(int flag); + unsigned int (*open)(unsigned int *ptr, PointSound360TD_PARM_SET *sound360_parm, PointSound360Reverb_PARM_SET *reverb_parm, int ch_mode); + unsigned int (*init)(unsigned int *ptr, PointSound360TD_PARM_SET *sound360_parm); + unsigned int (*run)(unsigned int *ptr, short *inbuf, short *out, int len); // len是sizePerChannel + unsigned int (*open_config)(unsigned int *ptr, PointSound360TD_PARM_SET *sound360_parm, RP_PARM_CONIFG *sound360_configparm); +} PointSound360TD_FUNC_API; + + + +extern PointSound360TD_FUNC_API *get_PointSound360TD_func_api(); + + +#endif // reverb_api_h__ diff --git a/include_lib/media/tech_lib/jlsp_vad.h b/include_lib/media/tech_lib/jlsp_vad.h new file mode 100644 index 0000000..61efc67 --- /dev/null +++ b/include_lib/media/tech_lib/jlsp_vad.h @@ -0,0 +1,15 @@ +/***************************************************************** +>file name : jlsp_vad.h +>create time : Fri 17 Dec 2021 02:18:47 PM CST +*****************************************************************/ +#ifndef _JLSP_VAD_H_ +#define _JLSP_VAD_H_ + +int JLSP_vad_get_heap_size(void *file_ptr, int *model_size); +void *JLSP_vad_init(char *heap_buffer, int heap_size, char *share_buffer, int share_size, void *file_ptr, int model_size); +int JLSP_vad_reset(void *m); +int JLSP_vad_process(void *m, short *pcm, int *out_flag); +int JLSP_vad_free(void *m); + +#endif + diff --git a/include_lib/system/app_core.h b/include_lib/system/app_core.h new file mode 100644 index 0000000..0f539c4 --- /dev/null +++ b/include_lib/system/app_core.h @@ -0,0 +1,86 @@ +#ifndef SYS_APPLICATION_H +#define SYS_APPLICATION_H + +#include "typedef.h" +#include "generic/list.h" +#include "system/event.h" + + +#define ACTION_BACK 0x0a1b2c00 +#define ACTION_STOP 0x0a1b2c01 +#define ACTION_DO_NOTHING 0x0a1b2c02 +#define ACTION_TONE_PLAY 0x0a1b2c03 +#define ACTION_CLASS_MASK 0xfffff000 + + + +enum app_state { + APP_STA_CREATE, + APP_STA_START, + APP_STA_PAUSE, + APP_STA_RESUME, + APP_STA_STOP, + APP_STA_DESTROY, +}; + +struct application; + + +struct intent { + const char *name; + int action; + const char *data; + u32 exdata; +}; + + +struct application_operation { + int (*state_machine)(struct application *, enum app_state, struct intent *); + int (*event_handler)(struct application *, struct sys_event *); +}; + + +struct application { + u8 state; + int action; + char *data; + const char *name; + struct list_head entry; + void *private_data; + const struct application_operation *ops; +}; + + + +#define REGISTER_APPLICATION(at) \ + static struct application at sec(.app) + + +#define init_intent(it) \ + do { \ + (it)->name = NULL; \ + (it)->action= 0; \ + (it)->data = NULL; \ + (it)->exdata = 0; \ + }while (0) + + + +void register_app_event_handler(int (*handler)(struct sys_event *)); + +struct application *get_current_app(); + +struct application *get_prev_app(); + +void app_core_back_to_prev_app(); + +int start_app(struct intent *it); + +int start_app_async(struct intent *it, void (*callback)(void *p, int err), void *p); + + + + + +#endif + diff --git a/include_lib/system/app_msg.h b/include_lib/system/app_msg.h new file mode 100644 index 0000000..9e41a0c --- /dev/null +++ b/include_lib/system/app_msg.h @@ -0,0 +1,20 @@ +#ifndef SYS_APP_MSG_H +#define SYS_APP_MSG_H + + + + +//app自定义消息发送接口 +int app_task_put_usr_msg(int msg, int arg_num, ...); + +//app消息获取接口(block参数为0表示内部pend,1直接返回) +void app_task_get_msg(int *msg, int msg_size, int block); + +//app按键消息发送接口 +int app_task_put_key_msg(int msg, int value); + +//app清理按键消息接口 +void app_task_clear_key_msg(); + +#endif + diff --git a/include_lib/system/apple_dock/iAP.h b/include_lib/system/apple_dock/iAP.h new file mode 100644 index 0000000..663dfcc --- /dev/null +++ b/include_lib/system/apple_dock/iAP.h @@ -0,0 +1,141 @@ +/*************************************************************/ +/** @file: usb_device.h + @brief: USB 从机驱动重写,加入iAP协议 + @details: + @author: Bingquan Cai + @date: 2013-10-11,09:34 + @note: +*/ +/*************************************************************/ + +#ifndef _IAP_H_ +#define _IAP_H_ + +#include "generic/typedef.h" +// #include "string.h" +// #include "usb/usb_slave_api.h" + +#define IAP2_LINK_EN 1 + +#define IAP_USE_USB_HID_EN 1 + +//USB +#define MAXP_SIZE_INTERRUPT_IN 0x40 +//IIC crack +#define AUTHENTICATION_CONTROL_STATUS 0x10 +#define SIGNATURE_DATA_LENGTH 0x11 +#define SIGNATURE_DATA 0x12 +#define CHALLENGE_DATA_LENGTH 0x20 +#define CHALLENGE_DATA 0x21 +#define ACCESSORY_CERTIFICATE_DATA_LENGTH 0x30 +#define ACCESSORY_CERTIFICATE_DATA 0x31 +//iAP1 and iAP2 COMMON +#define IAP2_VERSIONS 0x02 +#define IAP1_VERSIONS 0x01 +#define DEFAULT_SEQUENCE_NUM 0x0 +#define EXTRA_SEQUENCE_NUM 0x1 +//"Dock speaker" +#define ACCESSORY_NAME 0x44, 0x6f, 0x63, 0x6b, 0x20, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x65, 0x72, 0x00 +//"IPDLI13" +#define ACCESSORY_MODEL_IDENTIFIER 0x49, 0x50, 0x44, 0x4c, 0x49, 0x31, 0x33, 0x00 +//"I want it" +#define ACCESSORY_MANUFACTURER 0x49, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, 0x69, 0x74, 0x00 +//"iAP Interface" +#define ACCESSORY_SERIALNUMBER 0x69, 0x41, 0x50, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x00 + +//< hid +#define HID_PREV_FILE USB_AUDIO_PREFILE +#define HID_NEXT_FILE USB_AUDIO_NEXTFILE +#define HID_PP USB_AUDIO_PP +#define HID_PLAY USB_AUDIO_PLAY +#define HID_PAUSE USB_AUDIO_PAUSE +#define HID_VOL_DOWN USB_AUDIO_VOLDOWN +#define HID_VOL_UP USB_AUDIO_VOLUP + + +//>8) +#define SW16(x) (((u16)(x) & 0x00ffU)<<8 | ((u16)(x) & 0xff00U)>>8) + +#endif /* _IAP_H_ */ diff --git a/include_lib/system/bank_switch.h b/include_lib/system/bank_switch.h new file mode 100644 index 0000000..78f3133 --- /dev/null +++ b/include_lib/system/bank_switch.h @@ -0,0 +1,178 @@ +#ifndef BANK_SWITCH_H +#define BANK_SWITCH_H + +#ifdef CONFIG_CODE_BANK_ENABLE +#define _BANK_ENTRY(num) __attribute__((section(".bank.code."#num))) __attribute__((banknum(num))) +#define __BANK_ENTRY(num) _BANK_ENTRY(num) +#define _BANK_NUM(num) __attribute__((section(".bank.code."#num))) __attribute__((banknum(num))) +#define __BANK_NUM(num) _BANK_NUM(num) +#define __BANK_COMMON() __attribute__((section(".common"))) +#else +#define __BANK_ENTRY(num) +#define __BANK_NUM(num) +#endif + + +#ifdef CONFIG_BANK_COMM +#define __BANK_EDR_RX __BANK_COMMON() +#define __BANK_EDR_TX __BANK_COMMON() +#define __BANK_TWS_LINK __BANK_COMMON() +#define __BANK_EDR_FRAME __BANK_COMMON() +#else +#define __BANK_EDR_RX +#define __BANK_EDR_TX +#define __BANK_TWS_LINK +#define __BANK_EDR_FRAME +#endif + + +#ifdef CONFIG_BANK_NUM_INIT +#define __BANK_INIT_ENTRY __BANK_ENTRY(CONFIG_BANK_NUM_INIT) +#define __BANK_INIT __BANK_NUM(CONFIG_BANK_NUM_INIT) +#else +#define __BANK_INIT_ENTRY +#define __BANK_INIT +#endif + +#ifdef CONFIG_BANK_NUM_RF +#define __BANK_RF_ENTRY __BANK_ENTRY(CONFIG_BANK_NUM_RF) +#define __BANK_RF __BANK_NUM(CONFIG_BANK_NUM_RF) +#else +#define __BANK_RF_ENTRY +#define __BANK_RF +#endif + + +#ifdef CONFIG_BANK_NUM_RF_TRIM +#define __BANK_RF_TRIM __BANK_NUM(CONFIG_BANK_NUM_RF_TRIM) +#else +#define __BANK_RF_TRIM +#endif + +#ifdef CONFIG_BANK_NUM_DUT +#define __BANK_DUT_ENTRY __BANK_ENTRY(CONFIG_BANK_NUM_DUT) +#define __BANK_DUT __BANK_NUM(CONFIG_BANK_NUM_DUT) +#else +#define __BANK_DUT_ENTRY +#define __BANK_DUT +#endif + +#ifdef CONFIG_BANK_NUM_ECDH +#define __BANK_ECDH_ENTRY __BANK_ENTRY(CONFIG_BANK_NUM_ECDH) +#define __BANK_ECDH __BANK_NUM(CONFIG_BANK_NUM_ECDH) +#else +#define __BANK_ECDH_ENTRY +#define __BANK_ECDH +#endif + +#ifdef CONFIG_BANK_NUM_ENC +#define __BANK_ENC_ENTRY __BANK_ENTRY(CONFIG_BANK_NUM_ENC) +#define __BANK_ENC __BANK_NUM(CONFIG_BANK_NUM_ENC) +#else +#define __BANK_ENC_ENTRY +#define __BANK_ENC +#endif + +#ifdef CONFIG_BANK_NUM_A2DP +#define __BANK_A2DP_ENTRY __BANK_ENTRY(CONFIG_BANK_NUM_A2DP) +#define __BANK_A2DP __BANK_NUM(CONFIG_BANK_NUM_A2DP) +#else +#define __BANK_A2DP_ENTRY +#define __BANK_A2DP +#endif + +#ifdef CONFIG_BANK_NUM_AVCTP +#define __BANK_AVCTP_ENTRY __BANK_ENTRY(CONFIG_BANK_NUM_AVCTP) +#define __BANK_AVCTP __BANK_NUM(CONFIG_BANK_NUM_AVCTP) +#else +#define __BANK_AVCTP_ENTRY +#define __BANK_AVCTP +#endif + + +#ifdef CONFIG_BANK_NUM_RFCOMM +#define __BANK_RFCOMM_ENTRY __BANK_ENTRY(CONFIG_BANK_NUM_RFCOMM) +#define __BANK_RFCOMM __BANK_NUM(CONFIG_BANK_NUM_RFCOMM) +#else +#define __BANK_RFCOMM_ENTRY +#define __BANK_RFCOMM +#endif + + +#ifdef CONFIG_BANK_NUM_SDP +#define __BANK_SDP_ENTRY __BANK_ENTRY(CONFIG_BANK_NUM_SDP) +#define __BANK_SDP __BANK_NUM(CONFIG_BANK_NUM_SDP) +#else +#define __BANK_SDP_ENTRY +#define __BANK_SDP +#endif + +#ifdef CONFIG_BANK_NUM_BT_HID +#define __BANK_BT_HID_ENTRY __BANK_ENTRY(CONFIG_BANK_NUM_BT_HID) +#define __BANK_BT_HID __BANK_NUM(CONFIG_BANK_NUM_BT_HID) +#else +#define __BANK_BT_HID_ENTRY +#define __BANK_BT_HID +#endif + +#ifdef CONFIG_BANK_NUM_BLE +#define __BANK_BLE_ENTRY __BANK_ENTRY(CONFIG_BANK_NUM_BLE) +#define __BANK_BLE __BANK_NUM(CONFIG_BANK_NUM_BLE) +#else +#define __BANK_BLE_ENTRY +#define __BANK_BLE +#endif + +#ifdef CONFIG_BANK_NUM_TWS_BLE +#define __BANK_TWS_BLE_ENTRY __BANK_ENTRY(CONFIG_BANK_NUM_TWS_BLE) +#define __BANK_TWS_BLE __BANK_NUM(CONFIG_BANK_NUM_TWS_BLE) +#else +#define __BANK_TWS_BLE_ENTRY +#define __BANK_TWS_BLE +#endif + +#ifdef CONFIG_BANK_NUM_TONE +#define __BANK_TONE_ENTRY __BANK_ENTRY(CONFIG_BANK_NUM_TONE) +#define __BANK_TONE __BANK_NUM(CONFIG_BANK_NUM_TONE) +#else +#define __BANK_TONE_ENTRY +#define __BANK_TONE +#endif + +#ifdef CONFIG_BANK_NUM_LMP_SLAVE +#define __BANK_LMP_SLAVE_ENTRY __BANK_ENTRY(CONFIG_BANK_NUM_LMP_SLAVE) +#define __BANK_LMP_SLAVE __BANK_NUM(CONFIG_BANK_NUM_LMP_SLAVE) +#else +#define __BANK_LMP_SLAVE_ENTRY +#define __BANK_LMP_SLAVE +#endif + +#ifdef CONFIG_BANK_NUM_LMP_MASTER +#define __BANK_LMP_MASTER_ENTRY __BANK_ENTRY(CONFIG_BANK_NUM_LMP_MASTER) +#define __BANK_LMP_MASTER __BANK_NUM(CONFIG_BANK_NUM_LMP_MASTER) +#else +#define __BANK_LMP_MASTER_ENTRY +#define __BANK_LMP_MASTER +#endif + + + + +#ifdef CONFIG_BANK_NUM_CLOCK +#define __BANK_CLOCK_ENTRY __BANK_ENTRY(CONFIG_BANK_NUM_CLOCK) +#define __BANK_CLOCK __BANK_NUM(CONFIG_BANK_NUM_CLOCK) +#else +#define __BANK_CLOCK_ENTRY +#define __BANK_CLOCK +#endif + + + +void load_overlay_code(int num); +void bank_syscall_entry(void); +void load_common_code(void); + + + +#endif + diff --git a/include_lib/system/boot.h b/include_lib/system/boot.h new file mode 100644 index 0000000..6eb839c --- /dev/null +++ b/include_lib/system/boot.h @@ -0,0 +1,72 @@ +#ifndef __BOOT_H__ +#define __BOOT_H__ + + +struct vm_info { +#if (USE_SDFILE_NEW == 1) + u8 align; //from uboot, 按 n * 256 对齐 +#endif + u32 vm_saddr; //from sdfile, flash addr + u32 vm_res; //reverse_bytes + u32 vm_size; //from sdfile +}; + +struct sfc_info { + u32 sfc_base_addr; //flash memory addr, from uboot + u32 app_addr; //cpu logic addr, from uboot +}; + + +#if (USE_SDFILE_NEW == 1) +struct bt_mac_addr { + u8 value[6]; + u16 value_crc; +}; + +typedef struct _boot_info { + struct vm_info vm; + struct sfc_info sfc; + u32 flash_size; //from uboot + u16 chip_id; //from uboot + u16 trim_value; //from uboot + struct bt_mac_addr mac; +} BOOT_INFO; + +//===================================== +struct flash_head { + u16 crc; + u16 size4burner; + u8 vid[4]; //u32 vm_eaddr; + u32 FlashSize; + u8 FsVersion; //flash文件结构 + u8 align; //对齐 n * 256 + u8 res; + u8 SpecialOptFlag; + u8 pid[16]; +}; + +typedef struct boot_device_info { + struct flash_head *fs_info; + struct sfc_info sfc; + u16 chip_id; //from uboot + u16 trim_value; //from uboot + u8 bt_mac_addr[8]; +} BOOT_DEVICE_INFO; + +#else + +typedef struct _boot_info { + struct vm_info vm; + struct sfc_info sfc; + u32 flash_size; //from uboot + u32 size4burner; //from uboot + u16 chip_id; //from uboot + u16 trim_value; //from uboot +} BOOT_INFO; + +#endif /* #if (USE_SDFILE_NEW == 1) */ + +extern BOOT_INFO boot_info; + +#endif + diff --git a/include_lib/system/config/config_interface.h b/include_lib/system/config/config_interface.h new file mode 100644 index 0000000..bda80ef --- /dev/null +++ b/include_lib/system/config/config_interface.h @@ -0,0 +1,30 @@ +/********************************************************************************************* + * Filename : config_interface.h + + * Description : + + * Author : Bingquan + + * Email : bingquan_cai@zh-jieli.com + + * Last modifiled : 2019-01-10 09:55 + + * Copyright:(c)JIELI 2011-2019 @ , All Rights Reserved. +*********************************************************************************************/ +#ifndef _CONFIG_INTERFACE_H_ +#define _CONFIG_INTERFACE_H_ + +#include "config/config_transport.h" +#include "config/config_target.h" + +//配置工具 0:旧工具 1:新工具 +#define NEW_CONFIG_TOOL 1 // + +void config_layer_init(const ci_transport_t *transport, void *config); + +void *config_load(int id); + +void ci_send_packet(u32 id, u8 *packet, int size); + + +#endif diff --git a/include_lib/system/config/config_target.h b/include_lib/system/config/config_target.h new file mode 100644 index 0000000..f4262f7 --- /dev/null +++ b/include_lib/system/config/config_target.h @@ -0,0 +1,43 @@ +/********************************************************************************************* + * Filename : config_target.h + + * Description : + + * Author : Bingquan + + * Email : bingquan_cai@zh-jieli.com + + * Last modifiled : 2019-01-09 19:28 + + * Copyright:(c)JIELI 2011-2017 @ , All Rights Reserved. +*********************************************************************************************/ +#ifndef _CONFIG_TARGET_H_ +#define _CONFIG_TARGET_H_ + +#include "typedef.h" + + +#define EQ_CONFIG_ID 0x0005 +#define EFFECTS_CONFIG_ID 0x0006 +#define AEC_CONFIG_ID 0x0008 + + +typedef void (*ci_packet_handler_t)(uint8_t *packet, uint16_t size); + +struct config_target { + u16 id; + ci_packet_handler_t callback; +}; + +#define REGISTER_CONFIG_TARGET(target) \ + const struct config_target target sec(.config_target) + + +extern const struct config_target config_target_begin[]; +extern const struct config_target config_target_end[]; + +#define list_for_each_config_target(p) \ + for (p = config_target_begin; p < config_target_end; p++) + + +#endif diff --git a/include_lib/system/config/config_transport.h b/include_lib/system/config/config_transport.h new file mode 100644 index 0000000..916c95e --- /dev/null +++ b/include_lib/system/config/config_transport.h @@ -0,0 +1,93 @@ +/********************************************************************************************* + * Filename : config_transport.h + + * Description : Config Interface + + * Author : Bingquan + + * Email : bingquan_cai@zh-jieli.com + + * Last modifiled : 2019-01-07 14:33 + + * Copyright:(c)JIELI 2011-2017 @ , All Rights Reserved. +*********************************************************************************************/ +#ifndef _CI_TRANSPORT_H +#define _CI_TRANSPORT_H + +#include "typedef.h" + +/* CI packet types */ +typedef struct { + /** + * transport name + */ + const char *name; + + /** + * init transport + * @param transport_config + */ + void (*init)(const void *transport_config); + + /** + * open transport connection + */ + int (*open)(void); + + /** + * close transport connection + */ + int (*close)(void); + + /** + * register packet handler for CI packets + */ + void (*register_packet_handler)(void (*handler)(const u8 *packet, int size)); + + /** + * support async transport layers, e.g. IRQ driven without buffers + */ + int (*can_send_packet_now)(uint8_t packet_type); + + /** + * send packet + */ + int (*send_packet)(const u8 *packet, int size); + + /** + * extension for UART transport implementations + */ + int (*set_baudrate)(uint32_t baudrate); +} ci_transport_t; + +typedef enum { + CI_TRANSPORT_CONFIG_UART, + CI_TRANSPORT_CONFIG_USB, + CI_TRANSPORT_CONFIG_BLE, +} ci_transport_config_type_t; + +typedef struct { + ci_transport_config_type_t type; +} ci_transport_config_t; + +typedef struct { + ci_transport_config_type_t type; // == CI_TRANSPORT_CONFIG_UART + uint32_t baudrate_init; // initial baud rate + uint32_t baudrate_main; // = 0: same as initial baudrate + int flowcontrol; // + const char *device_name; +} ci_transport_config_uart_t; + +typedef struct { + //head + u16 id; + u16 length; + + u8 payload[0]; +} _GNU_PACKED_ ci_packet_t; + +#define CI_FORMAT_HEAD sizeof(ci_packet_t) + +const ci_transport_t *ci_transport_uart_instance(void); + +#endif diff --git a/include_lib/system/database.h b/include_lib/system/database.h new file mode 100644 index 0000000..bd7b2c5 --- /dev/null +++ b/include_lib/system/database.h @@ -0,0 +1,34 @@ +#ifndef DATABASE_H +#define DATABASE_H + +#include "typedef.h" + + +struct db_table { + const char *name; + u8 value_bits; + int value; +}; + + +int db_select_buffer(u8 index, char *buffer, int len); + +int db_update_buffer(u8 index, char *buffer, int len); + +int db_create(const char *store_dev); + + +int db_create_table(const struct db_table *table, int num); + +u32 db_select(const char *table); + +int db_update(const char *table, u32 value); + +int db_flush(); + +int db_reset(); + +int db_erase(); + +#endif + diff --git a/include_lib/system/debug.h b/include_lib/system/debug.h new file mode 100644 index 0000000..e609e0e --- /dev/null +++ b/include_lib/system/debug.h @@ -0,0 +1,159 @@ +#ifndef _DEBUG_H_ +#define _DEBUG_H_ + +#include "asm/cpu.h" +#include "generic/typedef.h" + +// -- output terminal color +#define RedBold "\033[31;1m" // 红色加粗 +#define RedBoldBlink "\033[31;1;5m" // 红色加粗、闪烁 +#define GreenBold "\033[32;1m" // 红色加粗 +#define GreenBoldBlink "\033[32;1;5m" // 红色加粗、闪烁 +#define YellowBold "\033[33;1m" // 红色加粗 +#define YellowBoldBlink "\033[33;1;5m" // 红色加粗、闪烁 +#define BlueBold "\033[34;1m" // 蓝色加粗 +#define BlueBoldBlink "\033[34;1;5m" // 蓝色加粗、闪烁 +#define PurpleBold "\033[35;1m" // 紫色加粗 +#define PurpleBoldBlink "\033[35;1;5m" // 紫色加粗、闪烁 +#define DGreenBold "\033[36;1m" // 红色加粗 +#define DGreenBoldBlink "\033[36;1;5m" // 红色加粗、闪烁 +#define WhiteBold "\033[37;1m" // 红色加粗 +#define WhiteBoldBlink "\033[37;1;5m" // 红色加粗、闪烁 +#define Reset "\033[0;25m" // 颜色复位 + +#define LOG_ASSERT_ENABLE + +void printf_buf(u8 *buf, u32 len); + +#define PRINTF(format, ...) printf(format, ## __VA_ARGS__) + +#define LOG_VERBOSE v +#define LOG_INFO i +#define LOG_DEBUG d +#define LOG_WARN w +#define LOG_ERROR e +#define LOG_CHAR c + +#define _STR(x) #x +#define STR(x) "["_STR(x)"]" + + +#define _LOG_TAG_CONST_DECLARE(level, name) extern const char log_tag_const_##level##_##name +#define LOG_TAG_CONST_DECLARE(level, name) _LOG_TAG_CONST_DECLARE(level, name) + +#define ___LOG_IS_ENABLE(level, name) (log_tag_const_##level##_##name) +#define __LOG_IS_ENABLE(level, name) ___LOG_IS_ENABLE(level, name) +#define _LOG_IS_ENABLE(level) __LOG_IS_ENABLE(level, LOG_TAG_CONST) + +#ifdef LOG_TAG_CONST +LOG_TAG_CONST_DECLARE(LOG_VERBOSE, LOG_TAG_CONST); +LOG_TAG_CONST_DECLARE(LOG_INFO, LOG_TAG_CONST); +LOG_TAG_CONST_DECLARE(LOG_DEBUG, LOG_TAG_CONST); +LOG_TAG_CONST_DECLARE(LOG_WARN, LOG_TAG_CONST); +LOG_TAG_CONST_DECLARE(LOG_ERROR, LOG_TAG_CONST); +LOG_TAG_CONST_DECLARE(LOG_CHAR, LOG_TAG_CONST); +#define _LOG_TAG STR(LOG_TAG_CONST) +#define LOG_IS_ENABLE(level) _LOG_IS_ENABLE(level) + +#else +#define _LOG_TAG LOG_TAG +#define LOG_IS_ENABLE(x) 1 +#endif + + +#define LOG_BY_MACRO 1 +#define LOG_BY_CONST 2 + +// #define LOG_MODE LOG_BY_MACRO +#define LOG_MODE LOG_BY_CONST + +/* + * LOG 通过宏控制 + */ +#if (LOG_MODE == LOG_BY_MACRO) + +#ifdef LOG_INFO_ENABLE +#define log_info(format, ...) PRINTF("[Info] :" _LOG_TAG format "\r\n", ## __VA_ARGS__) +#else +#define log_info(...) +#endif + +#ifdef LOG_DEBUG_ENABLE +#define log_debug(format, ...) PRINTF("[Debug] :" _LOG_TAG format "\r\n", ## __VA_ARGS__) +#define log_debug_hexdump(x, y) printf_buf(x, y) +#else +#define log_debug(...) +#define log_debug_hexdump(x, y) +#endif + +#ifdef LOG_ERROR_ENABLE +#define log_error(format, ...) PRINTF(" :" _LOG_TAG format "\r\n", ## __VA_ARGS__) +#define log_error_hexdump(x, y) printf_buf(x, y) +#else +#define log_error(...) +#define log_error_hexdump(...) +#endif + +#ifdef LOG_DUMP_ENABLE +#define log_info_hexdump(x,y) printf_buf(x,y) +#else +#define log_info_hexdump(...) +#endif + +#ifdef LOG_CHAR_ENABLE +#define log_char(x) putchar(x) +#else +#define log_char(x) +#endif + +/* + * LOG 通过常量控制 + */ +#elif (LOG_MODE == LOG_BY_CONST) + +#define log_info(format, ...) \ + if (LOG_IS_ENABLE(LOG_INFO)) \ + log_print(__LOG_INFO,NULL,"[Info]: " _LOG_TAG format "\r\n", ## __VA_ARGS__) + +#define log_info_hexdump(x, y) \ + if (LOG_IS_ENABLE(LOG_INFO)) \ + printf_buf(x, y) + + +#define log_debug(format, ...) \ + if (LOG_IS_ENABLE(LOG_DEBUG)) \ + log_print(__LOG_DEBUG,NULL,"[Debug]: " _LOG_TAG format "\r\n", ## __VA_ARGS__) + +#define log_debug_hexdump(x, y) \ + if (LOG_IS_ENABLE(LOG_DEBUG)) \ + printf_buf(x, y) + +#define log_error(format, ...) \ + if (LOG_IS_ENABLE(LOG_ERROR)) \ + log_print(__LOG_ERROR,NULL,": " _LOG_TAG format "\r\n", ## __VA_ARGS__) + +#define log_error_hexdump(x, y) \ + if (LOG_IS_ENABLE(LOG_ERROR)) \ + printf_buf(x, y) + +#define log_char(x) \ + if (LOG_IS_ENABLE(LOG_CHAR)) \ + putchar(x) + +#endif + + +#define traceSUPER_MODE() \ + +/*{int icfg, rets, reti; \ +__asm__ volatile("%0 = icfg" : "=r"(icfg)); \ +__asm__ volatile("%0 = rets" :"=r"(rets)); \ +__asm__ volatile("%0 = reti" :"=r"(reti)); \ +ASSERT(icfg & BIT(10), "icfg 0x%x/ rets 0x%x / reti 0x%x", icfg, rets, reti)}*/ + + +void watchdog_close(void); + + +#endif//__DEBUG_LOG_H_ + diff --git a/include_lib/system/device/adkey.h b/include_lib/system/device/adkey.h new file mode 100644 index 0000000..549a0eb --- /dev/null +++ b/include_lib/system/device/adkey.h @@ -0,0 +1,38 @@ +#ifndef DEVICE_ADKEY_H +#define DEVICE_ADKEY_H + +#include "typedef.h" +#include "asm/adc_api.h" + + +#define ADKEY_MAX_NUM 10 + +struct adkey_platform_data { + u8 enable; + u8 adkey_pin; + u8 extern_up_en; //是否用外部上拉,1:用外部上拉, 0:用内部上拉10K + u32 ad_channel; + u16 ad_value[ADKEY_MAX_NUM]; + u8 key_value[ADKEY_MAX_NUM]; +}; + +struct adkey_rtcvdd_platform_data { + u8 enable; + u8 adkey_pin; + u8 adkey_num; + u32 ad_channel; + u32 extern_up_res_value; //是否用外部上拉,1:用外部上拉, 0:用内部上拉10K + u16 res_value[ADKEY_MAX_NUM]; //电阻值, 从 [大 --> 小] 配置 + u8 key_value[ADKEY_MAX_NUM]; +}; + +//ADKEY API: +extern int adkey_init(const struct adkey_platform_data *adkey_data); +extern u8 ad_get_key_value(void); + +//RTCVDD ADKEY API: +extern int adkey_rtcvdd_init(const struct adkey_rtcvdd_platform_data *rtcvdd_adkey_data); +extern u8 adkey_rtcvdd_get_key_value(void); + +#endif + diff --git a/include_lib/system/device/device.h b/include_lib/system/device/device.h new file mode 100644 index 0000000..2783734 --- /dev/null +++ b/include_lib/system/device/device.h @@ -0,0 +1,83 @@ +#ifndef CHRDEV_H +#define CHRDEV_H + + +#include "generic/typedef.h" +#include "generic/list.h" +//#include "generic/ioctl.h" +#include "generic/atomic.h" +//#include "sys/task.h" +#include "device/ioctl_cmds.h" + + +struct dev_node; +struct device; + + +/**@struct device_operations + * @brief device_operations结构体 \n + * otg设备执行哪种类型的操作 + */ +struct device_operations { + bool (*online)(const struct dev_node *node); ///<设备在线状态查询 + int (*init)(const struct dev_node *node, void *); ///<设备初始化 + int (*open)(const char *name, struct device **device, void *arg); ///<设备开启 + int (*read)(struct device *device, void *buf, u32 len, u32); ///<读操作 + int (*write)(struct device *device, void *buf, u32 len, u32); ///<写操作 + int (*seek)(struct device *device, u32 offset, int orig); ///<设备搜索 + int (*ioctl)(struct device *device, u32 cmd, u32 arg); /// +typedef pthread_mutex_t OS_MUTEX; +typedef u32 OS_ERR; +#define OS_ERR_NONE 0 + +#else +typedef u32 OS_MUTEX, OS_ERR; +#define OS_ERR_NONE 0 + +#endif +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +struct dev_mutex { + OS_MUTEX *write_mutex; + OS_MUTEX *read_mutex; +}; +typedef enum _dev_type { + + DEV_SDCRAD_0 = 0X10, + DEV_SDCRAD_1, + DEV_SDCRAD_2, + + DEV_UDISK_H0, + DEV_UDISK_H1, + DEV_UDISK_F0, + + DEV_NOR_FLASH, + DEV_NAND_FLASH, + + DEV_STORAGE = 0x100, + DEV_LOGIC_DISK = 0x101, + DEV_USB_SLAVE, + DEV_USB_HOST, + DEV_HID = 0x200, + DEV_NET, + DEV_AUDIO, + DEV_ISP, +} dev_type; + +// struct partition_table +// { +// int partition_addr; +// int partition_size; +// }; +typedef struct DEV_IO { + const char name[8]; + s32(*mount)(void *volatile parm); + s32(*unmount)(); + s32(*read)(u8 *volatile buf, u32 addr, u32 len); + s32(*write)(u8 *volatile buf, u32 addr, u32 len); + s32(*ioctrl)(void *volatile parm, u32 cmd); + s32(*power)(u32 mod); + s32(*detect)(); //设备状态检测 + + struct dev_mutex *mutex; + dev_type device_type; + + void *private_data;//设备私有属性,用来提供额外接口或者存储一些设备的特性 +} dev_io_t; + + + +//设备状态: +typedef enum dev_sta { + DEV_OFFLINE = 0, //--0 设备从在线切换到离线。 + DEV_ONLINE = 1, //---1 设备从离线切换到在线。 + DEV_HOLD = 2, //---2 其他值表示设备状态未改变。 + + DEV_POWER_ON = 0x10, // 0x10 – 开机 + DEV_POWER_OFF, // 0x11 -关机 + DEV_POWER_STANDBY, // 0x12 -待机 + DEV_POWER_WAKEUP, // 0x13- 唤醒 +} DEV_STA; +//设备错误代码: +typedef enum dev_err { + DEV_ERR_NONE = 0, + DEV_ERR_NOT_MOUNT, + DEV_ERR_OVER_CAPACITY, + + DEV_ERR_UNKNOW_CLASS, + + DEV_ERR_NOT_READY,//设备已经在线,但是没初始化完成 + DEV_ERR_LUN, + + DEV_ERR_TIMEOUT, + DEV_ERR_CMD_TIMEOUT, + DEV_ERR_READ_TIMEOUT,//0x08 + DEV_ERR_WRITE_TIMEOUT, + + DEV_ERR_OFFLINE,//0x0a + + DEV_ERR_CRC, + DEV_ERR_CMD_CRC, + DEV_ERR_READ_CRC, + DEV_ERR_WRITE_CRC, + + DEV_ERR_CONTROL_STALL, + DEV_ERR_RXSTALL,//0x10 + DEV_ERR_TXSTALL, + DEV_ERR_CONTROL, + + DEV_ERR_NOT_STORAGE, + DEV_ERR_INVALID_PATH, + DEV_ERR_INVALID_DATA, + DEV_ERR_OUTOFMEMORY, + DEV_ERR_HANDLE_FREE, + DEV_ERR_INVALID_HANDLE,//24 + DEV_ERR_INVALID_BUF, + DEV_ERR_INUSE, + DEV_ERR_NO_READ, + DEV_ERR_NO_WRITE, + DEV_ERR_NO_IOCTL, + DEV_ERR_NO_POWER, + DEV_ERR_NOT_EXIST, + DEV_ERR_UNKNOW, +} DEV_ERR; + + +#define DEV_GENERAL_MAGIC 0xe0 +//每个设备必须支持的命令 +#define DEV_GET_STATUS _IOR(DEV_GENERAL_MAGIC,0xe0,u32) //获取设备状态,在线、离线、power_on、power_off、standby、…… +//设备不支持下面命令时返回 -ENOTTY +#define DEV_GET_BLOCK_SIZE _IOR(DEV_GENERAL_MAGIC,0xe1,u32) //获取存储设备的块大小 +#define DEV_GET_BLOCK_NUM _IOR(DEV_GENERAL_MAGIC,0xe2,u32) //获取存储设备的块总数 +#define DEV_GET_DEV_ID _IOR(DEV_GENERAL_MAGIC,0xe3,u32) //获取设备的ID。SD/TF 卡返回“sdtf”(0x73647466) +#define DEV_SECTOR_ERASE _IOW(DEV_GENERAL_MAGIC,0xe4,u32) //设备页擦除 +#define DEV_BLOCK_ERASE _IOW(DEV_GENERAL_MAGIC,0xe5,u32) //设备块擦除 +#define DEV_CHIP_ERASE _IOW(DEV_GENERAL_MAGIC,0xe6,u32) //设备擦除 +#define DEV_GET_TYPE _IOR(DEV_GENERAL_MAGIC,0xe7,u32) //返回设备的dev_type +#define DEV_CHECK_WPSTA _IOR(DEV_GENERAL_MAGIC,0xe8,u32) //检测设备写保护状态,当参数为-1的时候返回设备的写包含状态,0的时候解除写保护,1的时候加上写保护 + +#define typecheck(type,x) \ + ({ type __dummy; \ + typeof(x) __dummy2; \ + (void)(&__dummy == &__dummy2); \ + 1; \ + }) +#ifndef time_after +#define time_after(a,b) (typecheck(u32, a) && \ + typecheck(u32, b) && \ + ((s32)(b) - (s32)(a) < 0)) +#endif + +#ifndef time_before +#define time_before(a,b) time_after(b,a) +#endif + + +#ifdef __cplusplus + +} +#endif + + +#endif + diff --git a/include_lib/system/device/includes.h b/include_lib/system/device/includes.h new file mode 100644 index 0000000..33a30c1 --- /dev/null +++ b/include_lib/system/device/includes.h @@ -0,0 +1,32 @@ +#ifndef DEVICE_INCLUDES_H +#define DEVICE_INCLUDES_H + + + + +#include "device.h" +#include "ioctl_cmds.h" + +#include "key_driver.h" +#include "iokey.h" +#include "irkey.h" +#include "adkey.h" +#include "slidekey.h" +#include "touch_key.h" +#include "rdec_key.h" + + + + + + + + + + + + + + + +#endif diff --git a/include_lib/system/device/ioctl_cmds.h b/include_lib/system/device/ioctl_cmds.h new file mode 100644 index 0000000..bb70f09 --- /dev/null +++ b/include_lib/system/device/ioctl_cmds.h @@ -0,0 +1,85 @@ +#ifndef IOCTL_INF_H +#define IOCTL_INF_H + + + + +#define IOCTL_SET_IRQ_NUM 1 +#define IOCTL_SET_PRIORITY 2 +#define IOCTL_SET_DATA_WIDTH 3 +#define IOCTL_SET_SPEED 4 +#define IOCTL_SET_DETECT_MODE 5 +#define IOCTL_SET_DETECT_FUNC 6 +#define IOCTL_SET_DETECT_TIME_INTERVAL 7 +#define IOCTL_SET_PORT 8 +#define IOCTL_SET_PORT_FUNC 9 +#define IOCTL_SET_CS_PORT_FUNC 10 +#define IOCTL_SET_READ_MODE 11 +#define IOCTL_SET_WRITE_MODE 12 +#define IOCTL_SET_WRITE_PROTECT 13 +#define IOCTL_SET_START_BIT 14 +#define IOCTL_SET_STOP_BIT 15 +#define IOCTL_FLUSH 16 +#define IOCTL_REGISTER_IRQ_HANDLER 17 +#define IOCTL_UNREGISTER_IRQ_HANDLER 18 +#define IOCTL_GET_SYS_TIME 19 +#define IOCTL_SET_SYS_TIME 20 +#define IOCTL_GET_ALARM 21 +#define IOCTL_SET_ALARM 22 +#define IOCTL_SET_CAP_LOWSPEED_CARD 23 +#define IOCTL_SET_VDD50_EN 30 +#define IOCTL_GET_WEEKDAY 32 +#define IOCTL_CLR_READ_MODE 33 +#define IOCTL_SET_READ_CRC 34 +#define IOCTL_GET_READ_CRC 35 +#define IOCTL_GET_VOLUME 36 +#define IOCTL_SET_VOLUME 37 +#define IOCTL_SET_ALARM_ENABLE 38 +#define IOCTL_CMD_RESUME 39 +#define IOCTL_CMD_SUSPEND 40 +#define IOCTL_SET_BASE_ADDR 41 +#define IOCTL_SET_ASYNC_MODE 42 +#define IOCTL_GET_SPEED 43 +#define IOCTL_SET_ACTIVE_STATUS 44 +#define IOCTL_POWER_RESUME 45 +#define IOCTL_POWER_SUSPEND 46 + + +#define IOCTL_GET_ID 100 +#define IOCTL_GET_SECTOR_SIZE 101 +#define IOCTL_GET_BLOCK_SIZE 102 +#define IOCTL_GET_CAPACITY 103 +#define IOCTL_GET_WIDTH 104 +#define IOCTL_GET_HEIGHT 105 +#define IOCTL_GET_BLOCK_NUMBER 106 +#define IOCTL_CHECK_WRITE_PROTECT 107 +#define IOCTL_GET_STATUS 108 +#define IOCTL_GET_TYPE 109 +#define IOCTL_GET_MAX_LUN 110 +#define IOCTL_GET_CUR_LUN 111 +#define IOCTL_SET_CUR_LUN 112 +#define IOCTL_SET_FORCE_RESET 113 +#define IOCTL_SET_CAPACITY 114 + + +#define IOCTL_ERASE_SECTOR 200 +#define IOCTL_ERASE_BLOCK 201 +#define IOCTL_ERASE_CHIP 202 +#define IOCTL_SET_ENC_END 203 +#define IOCTL_ERASE_PAGE 204 +#define IOCTL_SDMMC_ERASE 205 + + +#define IOCTL_SET_DATA_CALLBACK 301 + +#define IOCTL_GET_PART_INFO 320 + +struct ioctl_irq_handler { + void *priv; + void *handler; +}; + + + +#endif + diff --git a/include_lib/system/device/iokey.h b/include_lib/system/device/iokey.h new file mode 100644 index 0000000..e9c7374 --- /dev/null +++ b/include_lib/system/device/iokey.h @@ -0,0 +1,70 @@ +#ifndef DEVICE_IOKEY_H +#define DEVICE_IOKEY_H + +#include "typedef.h" +#include "device/device.h" + + +// enum key_connect_way { +// ONE_PORT_TO_LOW, //按键一个端口接低电平, 另一个端口接IO +// ONE_PORT_TO_HIGH, //按键一个端口接高电平, 另一个端口接IO +// DOUBLE_PORT_TO_IO, //按键两个端口接IO +// }; + + +#define ONE_PORT_TO_LOW 0 //按键一个端口接低电平, 另一个端口接IO +#define ONE_PORT_TO_HIGH 1 //按键一个端口接高电平, 另一个端口接IO +#define DOUBLE_PORT_TO_IO 2 //按键两个端口接IO +#define CUST_DOUBLE_PORT_TO_IO 3 + + +struct one_io_key { + u8 port; +}; + +struct two_io_key { + u8 in_port; + u8 out_port; +}; + +union key_type { + struct one_io_key one_io; + struct two_io_key two_io; +}; + +struct iokey_port { + union key_type key_type; + u8 connect_way; + u8 key_value; +}; + +struct iokey_platform_data { + u8 enable; + u8 num; + const struct iokey_port *port; +}; + +//IOKEY API: +extern int iokey_init(const struct iokey_platform_data *iokey_data); +extern u8 io_get_key_value(void); + +/* 开机锁键:长按开机不松手时屏蔽全部按键,避免误触长按关机。 + * 默认监视 port[0](请把电源键配成第 0 个)。 + * 松开并连续确认 release_cnt 次扫描后解锁(扫描约 10ms 一次,默认 10 ≈ 100ms)。 + * + * 关闭方式: + * 1) 编译关闭:在 board/app_config 里 #define TCFG_IOKEY_BOOT_LOCK_ENABLE 0 + * 2) 运行关闭:iokey_boot_lock_stop() 或 iokey_boot_lock_start(0) + */ +#ifndef TCFG_IOKEY_BOOT_LOCK_ENABLE +#define TCFG_IOKEY_BOOT_LOCK_ENABLE 1 +#endif +#ifndef IOKEY_BOOT_LOCK_DEFAULT_CNT +#define IOKEY_BOOT_LOCK_DEFAULT_CNT 10 +#endif +void iokey_boot_lock_start(u8 release_cnt); /* >0 启动;0=关闭 */ +void iokey_boot_lock_stop(void); /* 立即关闭锁键 */ + + +#endif + diff --git a/include_lib/system/device/irkey.h b/include_lib/system/device/irkey.h new file mode 100644 index 0000000..970da15 --- /dev/null +++ b/include_lib/system/device/irkey.h @@ -0,0 +1,15 @@ +#ifndef DEVICE_IRKEY_H +#define DEVICE_IRKEY_H + +#include "typedef.h" + +struct irkey_platform_data { + u8 enable; + u8 port; +}; + +extern u8 ir_get_key_value(void); +extern int irkey_init(const struct irkey_platform_data *irkey_data); + +#endif + diff --git a/include_lib/system/device/key_driver.h b/include_lib/system/device/key_driver.h new file mode 100644 index 0000000..fb92bbe --- /dev/null +++ b/include_lib/system/device/key_driver.h @@ -0,0 +1,70 @@ +#ifndef SYS_KEY_DRIVER_H +#define SYS_KEY_DRIVER_H + +#include "typedef.h" + + + +typedef enum __KEY_DRIVER_TYPE { + KEY_DRIVER_TYPE_IO = 0x0, + KEY_DRIVER_TYPE_AD, + KEY_DRIVER_TYPE_RTCVDD_AD, + KEY_DRIVER_TYPE_IR, + KEY_DRIVER_TYPE_TOUCH, + KEY_DRIVER_TYPE_CTMU_TOUCH, + KEY_DRIVER_TYPE_RDEC, + KEY_DRIVER_TYPE_SLIDEKEY, + KEY_DRIVER_TYPE_SOFTKEY, + KEY_DRIVER_TYPE_BRIGHTNESS, + KEY_DRIVER_TYPE_VOICE, + + KEY_DRIVER_TYPE_MAX, +} KEY_DRIVER_TYPE; + + + +#define NO_KEY 0xff + + +#define KEY_NOT_SUPPORT 0x01 + + +struct key_driver_para { + const u32 scan_time; //按键扫描频率, 单位ms + u8 last_key; //上一次get_value按键值 +//== 用于消抖类参数 + u8 filter_value; //用于按键消抖 + u8 filter_cnt; //用于按键消抖时的累加值 + const u8 filter_time; //当filter_cnt累加到base_cnt值时, 消抖有效 +//== 用于判定长按和HOLD事件参数 + const u8 long_time; //按键判定长按数量 + const u8 hold_time; //按键判定HOLD数量 + u8 press_cnt; //与long_time和hold_time对比, 判断long_event和hold_event +//== 用于判定连击事件参数 + u8 click_cnt; //单击次数 + u8 click_delay_cnt; //按键被抬起后等待连击事件延时计数 + const u8 click_delay_time; ////按键被抬起后等待连击事件延时数量 + u8 notify_value; //在延时的待发送按键值 + u8 key_type; + u8(*get_value)(void); +}; + +//组合按键映射按键值 +struct key_remap { + u8 bit_value; + u8 remap_value; +}; + +struct key_remap_data { + u8 remap_num; + const struct key_remap *table; +}; + +// key_driver API: +extern int key_driver_init(void); + + + +#endif + + diff --git a/include_lib/system/device/rdec_key.h b/include_lib/system/device/rdec_key.h new file mode 100644 index 0000000..a7f1116 --- /dev/null +++ b/include_lib/system/device/rdec_key.h @@ -0,0 +1,12 @@ +#ifndef RDEC_KEY_H +#define RDEC_KEY_H + +#include "typedef.h" + +#include "asm/rdec.h" + +int rdec_key_init(const struct rdec_platform_data *rdec_key_data); +s8 get_rdec_rdat(int i); + +#endif + diff --git a/include_lib/system/device/slidekey.h b/include_lib/system/device/slidekey.h new file mode 100644 index 0000000..df60360 --- /dev/null +++ b/include_lib/system/device/slidekey.h @@ -0,0 +1,31 @@ +#ifndef DEVICE_SLIDEKEY_H +#define DEVICE_SLIDEKEY_H + +#include "typedef.h" +#include "device/device.h" +#include "asm/adc_api.h" + + +struct slidekey_port { + u8 io; + u8 io_up_en; //是否用外部上拉,1:用外部上拉, 0:用内部上拉10K + u32 level; + u32 ad_channel; + int msg; +}; + +struct slidekey_platform_data { + u8 enable; + u8 num; + const struct slidekey_port *port; +}; + + + +//API: +extern int slidekey_init(const struct slidekey_platform_data *slidekey_data); + + +#endif + + diff --git a/include_lib/system/device/tent600_key.h b/include_lib/system/device/tent600_key.h new file mode 100644 index 0000000..d30580a --- /dev/null +++ b/include_lib/system/device/tent600_key.h @@ -0,0 +1,18 @@ +#ifndef DEVICE_TENT600_KEY_H +#define DEVICE_TENT600_KEY_H +#include "typedef.h" +#include "asm/adc_api.h" + + +struct tent600_key_platform_data { + u8 enalbe; + u8 tent600_key_pin; + u8 extern_up_en; + u32 ad_channel; +}; + + +int tent600_key_init(const struct tent600_key_platform_data *tent600_key_data); +u8 tent600_get_key_value(void); + +#endif diff --git a/include_lib/system/device/touch_key.h b/include_lib/system/device/touch_key.h new file mode 100644 index 0000000..a0c6ff5 --- /dev/null +++ b/include_lib/system/device/touch_key.h @@ -0,0 +1,16 @@ +#ifndef DEVICE_TOUCH_KEY_H +#define DEVICE_TOUCH_KEY_H + +#include "typedef.h" +#include "asm/plcnt.h" + +/* =========== touch key API ============= */ +//触摸按键初始化 +int touch_key_init(const struct touch_key_platform_data *touch_key_data); + +//获取触摸按键键值 +u8 touch_key_get_value(void); + + +#endif + diff --git a/include_lib/system/device/vm.h b/include_lib/system/device/vm.h new file mode 100644 index 0000000..a51022b --- /dev/null +++ b/include_lib/system/device/vm.h @@ -0,0 +1,60 @@ +#ifndef _VM_H_ +#define _VM_H_ + +#include "ioctl.h" +#include "device/device.h" + +#define IOCTL_SET_VM_INFO _IOW('V', 1, 1) +#define IOCTL_GET_VM_INFO _IOW('V', 2, 1) +// enum { +// #<{(| +// * 用户自定义配置项 (0-64) +// |)}># +// #<{(| ... |)}># +// } + +// VM define and api +typedef u16 vm_hdl; + +struct vm_table { + u16 index; + u16 value_byte; + int value; //cache value which value_byte <= 4 +}; + +typedef enum _vm_err { + VM_ERR_NONE = 0, + VM_INDEX_ERR = -0x100, + VM_INDEX_EXIST, //0xFF + VM_DATA_LEN_ERR, //0xFE + VM_READ_NO_INDEX, //0xFD + VM_READ_DATA_ERR, //0xFC + VM_WRITE_OVERFLOW, //0xFB + VM_NOT_INIT, + VM_INIT_ALREADY, + VM_DEFRAG_ERR, + VM_ERR_INIT, + VM_ERR_PROTECT +} VM_ERR; + + +// vm api +VM_ERR vm_eraser(void); +VM_ERR vm_init(void *dev_hdl, u32 vm_addr, u32 vm_len, u8 vm_mode); +//VM_ERR vm_db_create_table(const struct vm_table *table, int num); +void vm_check_all(u8 level); //level : default 0 +u8 get_vm_statu(void); +// io api +//s32 vm_read(vm_hdl hdl, void *data_buf, u16 len); +//s32 vm_write(vm_hdl hdl, const void *data_buf, u16 len); + +void spi_port_hd(u8 level); + +bool sfc_erase_zone(u32 addr, u32 len); + +void vm_api_write_mult(u16 start_id, u16 end_id, void *buf, u16 len, u32 delay); +int vm_api_read_mult(u16 start_id, u16 end_id, void *buf, u16 len); + + +#endif //_VM_H_ + diff --git a/include_lib/system/event.h b/include_lib/system/event.h new file mode 100644 index 0000000..9756cfc --- /dev/null +++ b/include_lib/system/event.h @@ -0,0 +1,391 @@ +#ifndef SYS_EVENT_H +#define SYS_EVENT_H + +#include "generic/typedef.h" +#include "generic/list.h" +#include "generic/rect.h" + +#define KEY_POWER_START 0 +#define KEY_POWER 1 +#define KEY_PREV 2 +#define KEY_NEXT 3 +#define KEY_OK 4 +#define KEY_CANCLE 5 +#define KEY_MENU 6 +#define KEY_MODE 7 +#define KEY_PHOTO 8 +#define KEY_ENC 9 +#define KEY_VOLUME_DEC 10 +#define KEY_VOLUME_INC 11 +#define KEY_PHONE 12 + + +#define KEY_LEFT 37 +#define KEY_UP 38 +#define KEY_RIGHT 39 +#define KEY_DOWN 40 + +#define KEY_0 48 +#define KEY_1 49 +#define KEY_2 50 +#define KEY_3 51 +#define KEY_4 52 +#define KEY_5 53 +#define KEY_6 54 +#define KEY_7 55 +#define KEY_8 56 +#define KEY_9 57 + + +#define KEY_F1 60 + + +#define SYS_ALL_EVENT 0xffff +#define SYS_KEY_EVENT 0x0001 +#define SYS_TOUCH_EVENT 0x0002 +#define SYS_DEVICE_EVENT 0x0004 +#define SYS_NET_EVENT 0x0008 +#define SYS_BT_EVENT 0x0010 +#define SYS_IR_EVENT 0x0020 +#define SYS_PBG_EVENT 0x0040 +#define SYS_BT_AI_EVENT 0x0080 +#define SYS_AI_EVENT 0x0100 +#define SYS_MATRIX_KEY_EVENT 0x0200 +#define SYS_TOUCHPAD_EVENT 0x0400 +#define SYS_ADT_EVENT 0x0800 +#define SYS_AUD_EVENT 0x1000 + + + + +#define DEVICE_EVENT_FROM_AT_UART (('A' << 24) | ('T' << 16) | ('U' << 8) | '\0') +#define DEVICE_EVENT_FROM_CHARGE (('C' << 24) | ('H' << 16) | ('G' << 8) | '\0') +#define DEVICE_EVENT_FROM_CFG_TOOL (('C' << 24) | ('F' << 16) | ('G' << 8) | '\0') +#define DEVICE_EVENT_FROM_POWER (('P' << 24) | ('O' << 16) | ('W' << 8) | '\0') +#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 DEVICE_EVENT_CHARGE_STORE (('S' << 24) | ('T' << 16) | ('O' << 8) | '\0') +#define DEVICE_EVENT_UMIDIGI_CHARGE_STORE (('Q' << 24) | ('C' << 16) | ('Y' << 8) | '\0') +#define DEVICE_EVENT_TEST_BOX (('T' << 24) | ('S' << 16) | ('B' << 8) | '\0') +#define DEVICE_EVENT_FROM_TONE (('T' << 24) | ('N' << 16) | ('E' << 8) | '\0') +#define DEVICE_EVENT_FROM_FM (('F' << 24) | ('M' << 16) | ('\0'<< 8) | '\0') +#define KEY_EVENT_FROM_TWS (('T' << 24) | ('W' << 16) | ('S' << 8) | '\0') +#define SYS_BT_EVENT_FROM_TWS (('T' << 24) | ('W' << 16) | ('S' << 8) | '\0') +#define DEVICE_EVENT_FROM_LINEIN (('A' << 24) | ('U' << 16) | ('X' << 8) | '\0') +#define DRIVER_EVENT_FROM_SD0 (('S' << 24) | ('D' << 16) | ('0' << 8) | '\0') +#define DRIVER_EVENT_FROM_SD1 (('S' << 24) | ('D' << 16) | ('1' << 8) | '\0') +#define DRIVER_EVENT_FROM_SD2 (('S' << 24) | ('D' << 16) | ('2' << 8) | '\0') +#define DEVICE_EVENT_FROM_MUSIC (('M' << 24) | ('S' << 16) | ('C' << 8) | '\0') +#define DEVICE_EVENT_FROM_USB_HOST (('U' << 24) | ('H' << 16) | '\0' | '\0') +#define DEVICE_EVENT_FROM_OTG (('O' << 24) | ('T' << 16) | ('G' << 8) | '\0') +#define DEVICE_EVENT_FROM_PC (('P' << 24) | ('C' << 16) | '\0' | '\0') +#define DEVICE_EVENT_FROM_UAC (('U' << 24) | ('A' << 16) | ('C' << 8) | '\0') +#define DEVICE_EVENT_FROM_ALM (('A' << 24) | ('L' << 16) | ('M' << 8) | '\0') +#define SYS_BT_EVENT_TYPE_CON_STATUS (('C' << 24) | ('O' << 16) | ('N' << 8) | '\0') +#define SYS_BT_EVENT_TYPE_HCI_STATUS (('H' << 24) | ('C' << 16) | ('I' << 8) | '\0') +#define SYS_BT_EVENT_BLE_STATUS (('B' << 24) | ('L' << 16) | ('E' << 8) | '\0') +#define SYS_BT_EVENT_FORM_COMMON (('C' << 24) | ('M' << 16) | ('M' << 8) | '\0') +#define DEVICE_EVENT_FROM_KEY (('K' << 24) | ('E' << 16) | ('Y' << 8) | '\0') +#define DEVICE_EVENT_FROM_CUSTOM (('C' << 24) | ('S' << 16) | ('T' << 8) | '\0') +#define SYS_BT_AI_EVENT_TYPE_STATUS (('B' << 24) | ('A' << 16) | ('I' << 8) | '\0') +#define DEVICE_EVENT_FROM_UART_RX_OVERFLOW (('U' << 24) | ('R' << 16) | ('F' << 8) | '\0') +#define DEVICE_EVENT_FROM_UART_RX_OUTTIME (('U' << 24) | ('R' << 16) | ('T' << 8) | '\0') +#define DEVICE_EVENT_FROM_DAC (('D' << 24) | ('A' << 16) | ('C' << 8) | '\0') +#define SYS_EVENT_FROM_CTRLER (('C' << 24) | ('T' << 16) | ('R' << 8) | '\0') +#define SYS_EVENT_FROM_RECORD (('R' << 24) | ('E' << 16) | ('C' << 8) | '\0') +#define DEVICE_EVENT_FROM_ENDLESS_LOOP_DEBUG (('E' << 24) | ('L' << 16) | ('D' << 8) | '\0') +#define DEVICE_EVENT_FROM_EARTCH (('E' << 24) | ('T' << 16) | ('H' << 8) | '\0') +#define DEVICE_EVENT_ONLINE_DATA (('O' << 24) | ('L' << 16) | ('D' << 8) | '\0') +#define SYS_BT_EVENT_FROM_KEY (('K' << 24) | ('E' << 16) | ('Y' << 8) | '\0') +#define SYS_BT_EVENT_FORM_SELF (('S' << 24) | ('E' << 16) | ('F' << 8) | '\0') +#define DEVICE_EVENT_FROM_ANC (('A' << 24) | ('N' << 16) | ('C' << 8) | '\0') +#define SYS_BT_EVENT_FORM_AT (('I' << 24) | ('A' << 16) | ('T' << 8) | '\0') +#define DEVICE_EVENT_FROM_ADAPTER (('A' << 24) | ('D' << 16) | ('A' << 8) | '\0') +#define DEVICE_EVENT_FROM_BOARD_UART (('B' << 24) | ('D' << 16) | ('U' << 8) | '\0') +#define AUDIO_EVENT_TRIM_IMU_START (('A' << 24) | ('T' << 16) | ('S' << 8) | '\0') +#define AUDIO_EVENT_TRIM_IMU_STOP (('A' << 24) | ('T' << 16) | ('E' << 8) | '\0') + +enum { + KEY_EVENT_CLICK, + KEY_EVENT_LONG, + KEY_EVENT_HOLD, + KEY_EVENT_UP, + KEY_EVENT_DOUBLE_CLICK, + KEY_EVENT_TRIPLE_CLICK, + KEY_EVENT_FOURTH_CLICK, + KEY_EVENT_FIRTH_CLICK, + KEY_EVENT_USER, + KEY_EVENT_MAX, +}; + + +enum { + DEVICE_EVENT_IN, + DEVICE_EVENT_OUT, + DEVICE_EVENT_ONLINE, + DEVICE_EVENT_OFFLINE, + DEVICE_EVENT_CHANGE, +}; + +enum { + TOUCH_EVENT_DOWN, + TOUCH_EVENT_MOVE, + TOUCH_EVENT_HOLD, + TOUCH_EVENT_UP, + TOUCH_EVENT_CLICK, + TOUCH_EVENT_DOUBLE_CLICK, +}; + +enum { + NET_EVENT_CMD, + NET_EVENT_DATA, + NET_EVENT_CONNECTED, + NET_EVENT_DISCONNECTED, + NET_EVENT_SMP_CFG_TIMEOUT, +}; + + +struct key_event { + u8 init; + u8 type; + u16 event; + u32 value; + u32 tmr; +}; + +struct ir_event { + u8 event; +}; + +struct msg_event { + u8 event; + u8 value; +}; + +#if EVENT_TOUCH_ENABLE_CONFIG +struct touch_event { + u8 event; + struct position pos; +}; +#endif + +struct device_event { + u8 event; + int value; +}; + +struct chargestore_event { + u8 event; + u8 *packet; + u8 size; +}; + +struct testbox_event { + u8 event; + u8 *packet; + u8 size; +}; + +struct cfg_tool_event { + u8 event; + u8 *packet ; + u8 size; +}; + +struct umidigi_chargestore_event { + u8 event; + u8 value; +}; + +struct ancbox_event { + u8 event; + u32 value; +}; + +struct net_event { + u8 event; + u8 value; +}; +struct bt_event { + u8 event; + u8 args[7]; + u32 value; +}; + +struct axis_event { + u8 event; + s16 x; + s16 y; +}; + +struct codesw_event { + u8 event; + s8 value; +}; + +struct pbg_event { + u8 event; + u8 args[3]; +}; + +struct adt_event { + u8 event; + u8 args[3]; +}; + +struct uart_event { + void *ut_bus; +}; + +struct uart_cmd_event { + u8 type; + u8 cmd; +}; + +struct ai_event { + u32 value; +}; + +struct ear_event { + u8 value; +}; + +struct rcsp_event { + u8 event; + u8 args[6]; + u8 size; +}; + +struct chargebox_event { + u8 event; +}; + +struct matrix_key_event { + u16 args[6]; //最多推6个按键出来,如果需要推多个按键需要自行修改,每个u16 低八位标识row 高八位标识col + u8 *map; +}; + +struct touchpad_event { + u8 gesture_event; //手势事件 + s8 x; + s8 y; +}; + +struct sys_event { + u16 type; + u8 consumed; + void *arg; + union { + struct key_event key; + struct axis_event axis; + struct codesw_event codesw; +#if EVENT_TOUCH_ENABLE_CONFIG + struct touch_event touch; +#endif + struct device_event dev; + struct net_event net; + struct bt_event bt; + struct msg_event msg; + struct chargestore_event chargestore; + struct cfg_tool_event cfg_tool; + struct ir_event ir; + struct pbg_event pbg; + struct uart_event uart; + struct uart_cmd_event uart_cmd; + struct ai_event ai; + struct ear_event ear; + struct rcsp_event rcsp; + struct chargebox_event chargebox; + struct testbox_event testbox; + struct umidigi_chargestore_event umidigi_chargestore; + struct ancbox_event ancbox; + struct matrix_key_event matrix_key; + struct touchpad_event touchpad; + struct adt_event adt; + } u; +}; + + + + +struct static_event_handler { + int event_type; + void (*handler)(struct sys_event *); +}; + + +#define SYS_EVENT_HANDLER(type, fn, pri) \ + const struct static_event_handler __event_handler_##fn sec(.sys_event.pri.handler) = { \ + .event_type = type, \ + .handler = fn, \ + } + +extern struct static_event_handler sys_event_handler_begin[]; +extern struct static_event_handler sys_event_handler_end[]; + +#define list_for_each_static_event_handler(p) \ + for (p = sys_event_handler_begin; p < sys_event_handler_end; p++) + + + +int register_sys_event_handler(int event_type, int from, u8 priority, + void (*handler)(struct sys_event *)); + + +void unregister_sys_event_handler(void (*handler)(struct sys_event *)); + + +/* + * 事件通知函数,系统有事件发生时调用此函数 + */ +void sys_event_notify(struct sys_event *e); + +void sys_event_clear(struct sys_event *e); + +void sys_key_event_disable(); + + +void sys_key_event_enable(); + +void sys_key_event_filter_disable(); + +void sys_key_event_filter_enable(); + +void sys_touch_event_disable(); + + +void sys_touch_event_enable(); + +/* + *下面四个为系统事件消耗函数,调用此函数后则对应的事件不在分发给其它任务 + * + */ +void sys_event_consume(struct sys_event *e); + +void sys_key_event_consume(struct key_event *e); + +#if EVENT_TOUCH_ENABLE_CONFIG +void sys_touch_event_consume(struct touch_event *e); +#endif + +void sys_device_event_consume(struct device_event *e); + + +/* + * 下面两个函数为按键和触摸事件接管函数,调用此函数后则对应的事件只发到当前任务 + * + * on=true: 开始接管, on=false: 取消接管 + * + * once: on = false 时有效,当前这次不接管, 事件可以继续发送到其它任务 + * + */ +void sys_key_event_takeover(bool on, bool once); + +void sys_touch_event_takeover(bool on, bool once); + + +int sys_key_event_map(struct key_event *org, struct key_event *new); +int sys_key_event_unmap(struct key_event *org, struct key_event *new); + + +#endif diff --git a/include_lib/system/fs/fs.h b/include_lib/system/fs/fs.h new file mode 100644 index 0000000..864dbe4 --- /dev/null +++ b/include_lib/system/fs/fs.h @@ -0,0 +1,1042 @@ +#ifndef __FS_H__ +#define __FS_H__ + + + +#include "generic/typedef.h" +#include "generic/list.h" +#include "generic/ioctl.h" +#include "generic/atomic.h" +#include "system/task.h" +#include "system/malloc.h" +#include "system/sys_time.h" +#include "stdarg.h" +#include "fs_file_name.h" + +#define SEEK_SET 0 /* Seek from beginning of file. */ +#define SEEK_CUR 1 /* Seek from current position. */ +#define SEEK_END 2 /* Seek from end of file. */ + +#include "sdfile.h" + + + +#define F_ATTR_RO 0x01 +#define F_ATTR_ARC 0x02 +#define F_ATTR_DIR 0x04 +#define F_ATTR_VOL 0x08 + +#if (VFS_ENABLE == 1) + +#ifndef FSELECT_MODE +#define FSELECT_MODE +#define FSEL_FIRST_FILE 0 +#define FSEL_LAST_FILE 1 +#define FSEL_NEXT_FILE 2 +#define FSEL_PREV_FILE 3 +#define FSEL_CURR_FILE 4 +#define FSEL_BY_NUMBER 5 +#define FSEL_BY_SCLUST 6 +#define FSEL_AUTO_FILE 7 +#define FSEL_NEXT_FOLDER_FILE 8 +#define FSEL_PREV_FOLDER_FILE 9 +#define FSEL_BY_PATH 10 +#endif + +#ifndef FCYCLE_MODE +#define FCYCLE_MODE +#define FCYCLE_LIST 0 +#define FCYCLE_ALL 1 +#define FCYCLE_ONE 2 +#define FCYCLE_FOLDER 3 +#define FCYCLE_RANDOM 4 +#define FCYCLE_MAX 5 +#endif + +enum { + FS_IOCTL_GET_FILE_NUM, + FS_IOCTL_FILE_CHECK, + FS_IOCTL_GET_ERR_CODE, //暂不支持 + FS_IOCTL_FREE_CACHE, + FS_IOCTL_SET_NAME_FILTER, //设置文件过滤 + FS_IOCTL_GET_FOLDER_INFO, //获取文件夹序号和文件夹内文件数目 + FS_IOCTL_SET_LFN_BUF, // 512 + FS_IOCTL_SET_LDN_BUF, // 512 + + FS_IOCTL_SET_EXT_TYPE, //设置后缀类型 + FS_IOCTL_OPEN_DIR, //打开目录 + FS_IOCTL_ENTER_DIR, //进入目录 + FS_IOCTL_EXIT_DIR, //退出 + FS_IOCTL_GET_DIR_INFO, //获取目录信息 + + FS_IOCTL_GETFILE_BYNAME_INDIR, //由歌曲名称获得歌词 + + FS_IOCTL_GET_DISP_INFO, //用于长文件名获取 + + FS_IOCTL_MK_DIR, //创建文件夹 + FS_IOCTL_GET_ENCFOLDER_INFO, //获取录音文件信息 + + FS_IOCTL_GET_OUTFLASH_ADDR, //获取外置flash实际物理地址(暂时用于手表case,特殊fat系统) + FS_IOCTL_FLUSH_WBUF, //刷新wbuf + + FS_IOCTL_SAVE_FAT_TABLE, //seek加速处理 + + FS_IOCTL_INSERT_FILE, //插入文件 + FS_IOCTL_DIVISION_FILE, //分割文件 + FS_IOCTL_STORE_CLUST_RANG, //存储CLUST_RANG 信息 +}; + + +struct vfs_devinfo; +struct vfscan; +struct vfs_operations; + + + +struct vfs_devinfo { + void *fd; + u32 sector_size; + void *private_data; +}; + +#define VFS_PART_DIR_MAX 16 + + +struct vfs_partition { + struct vfs_partition *next; + u32 offset; + u32 clust_size; + u32 total_size; + u8 fs_attr; + u8 fs_type; + char dir[VFS_PART_DIR_MAX]; + void *private_data; +}; + +struct fiter { + u32 index; +}; + +struct ffolder { + u16 fileStart; + u16 fileTotal; +}; + + + +struct imount { + int fd; + const char *path; + struct vfs_operations *ops; + struct vfs_devinfo dev; + struct vfs_partition part; + struct list_head entry; + atomic_t ref; + OS_MUTEX mutex; + u8 avaliable; + u8 part_num; +}; + +struct vfs_attr { + u8 attr; + u32 fsize; + u32 sclust; + struct sys_time crt_time; + struct sys_time wrt_time; + struct sys_time acc_time; +}; + +typedef struct { + struct imount *mt; + struct vfs_devinfo *dev; + struct vfs_partition *part; + void *private_data; +} FILE; + + +struct vfscan { + u8 scan_file; + u8 subpath; //子目录,设置是否只扫描一层 + u8 scan_dir; + u8 attr; + u8 cycle_mode; + char sort; + char ftype[20 * 3 + 1]; + u16 file_number; + u16 file_counter; + + u16 dir_totalnumber; // 文件夹总数 + u16 musicdir_counter; // 播放文件所在文件夹序号 + u16 fileTotalInDir; //文件夹下的文件数目 + + void *priv; + struct vfs_devinfo *dev; + struct vfs_partition *part; + char filt_dir[12]; +}; + + +struct vfs_operations { + const char *fs_type; + int (*mount)(struct imount *, int); + int (*unmount)(struct imount *); + int (*format)(struct vfs_devinfo *, struct vfs_partition *); + int (*fset_vol)(struct vfs_partition *, const char *name); + int (*fget_free_space)(struct vfs_devinfo *, struct vfs_partition *, u32 *space); + int (*fopen)(FILE *, const char *path, const char *mode); + int (*fread)(FILE *, void *buf, u32 len); + int (*fread_fast)(FILE *, void *buf, u32 len); + int (*fwrite)(FILE *, void *buf, u32 len); + int (*fseek)(FILE *, int offset, int); + int (*fseek_fast)(FILE *, int offset, int); + int (*flen)(FILE *); + int (*fpos)(FILE *); + int (*fcopy)(FILE *, FILE *); + int (*fget_name)(FILE *, u8 *name, int len); + int (*fget_path)(FILE *, struct vfscan *, u8 *name, int len, u8 is_relative_path); + int (*frename)(FILE *, const char *path); + int (*fclose)(FILE *); + int (*fdelete)(FILE *); + int (*fscan)(struct vfscan *, const char *path, u8 max_deepth); + int (*fscan_interrupt)(struct vfscan *, const char *path, u8 max_deepth, int (*callback)(void)); + void (*fscan_release)(struct vfscan *); + int (*fsel)(struct vfscan *, int sel_mode, FILE *, int); + int (*fget_attr)(FILE *, int *attr); + int (*fset_attr)(FILE *, int attr); + int (*fget_attrs)(FILE *, struct vfs_attr *); + int (*fmove)(FILE *file, const char *path_dst, FILE *, int clr_attr, int path_len); + int (*ioctl)(void *, int cmd, int arg); +}; + +#define REGISTER_VFS_OPERATIONS(ops) \ + const struct vfs_operations ops SEC(.vfs_operations) + + +static inline struct vfs_partition *vfs_partition_next(struct vfs_partition *p) +{ + struct vfs_partition *n = (struct vfs_partition *)zalloc(sizeof(*n)); + + if (n) { + p->next = n; + } + return n; +} + + +static inline void vfs_partition_free(struct vfs_partition *p) +{ + struct vfs_partition *n = p->next; + + while (n) { + p = n->next; + free(n); + n = p; + } +} + + + + +/* --------------------------------------------------------------------------*/ +/** + * @brief 挂载文件系统 + * + * @param dev_name 设备名称 + * @param path 路径 + * @param fs_type 文件系统类型 + * @param cache_num 分区数 + * @param dev_arg 设备参数 + * + * @return mt结构句柄 + */ +/* ----------------------------------------------------------------------------*/ +struct imount *mount(const char *dev_name, const char *path, const char *fs_type, + int cache_num, void *dev_arg); //挂载 + +/* --------------------------------------------------------------------------*/ +/** + * @brief 卸载 + * + * @param path 路径 + * + * @return 返回相应的操作消息处理值 0为成功 + */ +/* ----------------------------------------------------------------------------*/ +int unmount(const char *path); + +/* --------------------------------------------------------------------------*/ +/** +* @brief 格式化接口 +* +* @param path 路径 +* @param fs_type 文件系统类型 +* @param clust_size 簇大小,簇为0时默认为卡本身簇大小。 +* +* @return 0格式化成功,非0 失败 +*/ +/* ----------------------------------------------------------------------------*/ +int f_format(const char *path, const char *fs_type, u32 clust_size); //格式化接口 + +int f_free_cache(const char *path); + +#if 0 +/*----------------------------------------------------------------------------*/ +/** @brief: +@param: fopen 扩展功能 +@note: fopen自动打开、创建文件夹和文件。 + 说明: + 1. 设备路径+文件,其中文件传入格式:"music/test/1/2/3/pk*.wav" "JL_REC/AC69****.wav" "JL_REC/AC690000.wav" + 2. 文件名带*号,带多少个*表示多少个可变数字,最多为8+3的大小,如表示可变数字名称变为XXX0001,XXXX002这样得格式,不带*号则只创建一个文件,写覆盖。 +@date: 2020-07-22 +*/ +/*----------------------------------------------------------------------------*/ +#endif + +/* --------------------------------------------------------------------------*/ +/** +* @brief 打开文件 +* +* @param path 文件路径 +* @param mode 打开模式(只读("r"),写("w"),可创建("w+")) +* +* @return 返回获得得文件句柄 +*/ +/* ----------------------------------------------------------------------------*/ +FILE *fopen(const char *path, const char *mode); + +/* --------------------------------------------------------------------------*/ +/** +* @brief 读文件 +* +* @param file 文件句柄 +* @param buf 读出内容放置buf +* @param len 需要读出内容得长度(一般为buf长度) +* +* @return 返回读出得长度 +*/ +/* ----------------------------------------------------------------------------*/ +int fread(FILE *file, void *buf, u32 len); + +/* --------------------------------------------------------------------------*/ +/** +* @brief 写资源文件 +* +* @param file 文件句柄 +* @param buf 写入得内容放置buf +* @param len 需要写入内容得长度(一般为buf长度) +* +* @return 返回写入得长度 +*/ +/* ----------------------------------------------------------------------------*/ +int fwrite(FILE *file, void *buf, u32 len); + +/* --------------------------------------------------------------------------*/ +/** +* @brief Seek到相应得位置 +* +* @param file 文件句柄 +* @param offset 偏移量 +* @param orig 偏移方式 +* +* @return 返回偏移得值 +*/ +/* ----------------------------------------------------------------------------*/ +int fseek(FILE *file, int offset, int orig); + +/* --------------------------------------------------------------------------*/ +/** +* @brief 快速seek +* +* @param file 文件句柄 +* @param offset 偏移量 +* @param orig 偏移方式 +* +* @note 一般手表case使用,去除互斥,设置ram里面跑 +* @return 返回偏移得值 +*/ +/* ----------------------------------------------------------------------------*/ +int fseek_fast(FILE *file, int offset, int orig);// 快速seek + +/* --------------------------------------------------------------------------*/ +/** +* @brief 快速read +* +* @param file 文件句柄 +* @param buf 读出内容放置buf +* @param len 需要读出内容得长度(一般为buf长度) +* +* @note 一般手表case使用,去除互斥,设置ram里面跑 +* @return 返回读出得长度 +*/ +/* ----------------------------------------------------------------------------*/ +int fread_fast(FILE *file, void *buf, u32 len); //快速read + +/* --------------------------------------------------------------------------*/ +/** +* @brief 获取文件长度 +* +* @param file 文件句柄 +* +* @return 当前文件长度 +*/ +/* ----------------------------------------------------------------------------*/ +int flen(FILE *file); + +/* --------------------------------------------------------------------------*/ +/** +* @brief 获取文件指针位置 +* +* @param file 文件句柄 +* +* @return 当前文件指针位置 +*/ +/* ----------------------------------------------------------------------------*/ +int fpos(FILE *file); + +int fcopy(const char *format, ...); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 获取当前文件名称 + * + * @param file 文件句柄 + * @param name 文件名buf + * @param len 长度 + * + * @return 获取到的文件名长度 + */ +/* ----------------------------------------------------------------------------*/ +int fget_name(FILE *file, u8 *name, int len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 重命名 + * + * @param file 文件句柄 + * @param path 重命名的文件名 + * + * @return 0成功,非0 失败 + */ +/* ----------------------------------------------------------------------------*/ +int frename(FILE *file, const char *path); + +/* --------------------------------------------------------------------------*/ +/** +* @brief 关闭文件 +* +* @param file 文件句柄 +* +* @return 无意义 +*/ +/* ----------------------------------------------------------------------------*/ +int fclose(FILE *file); + +/* --------------------------------------------------------------------------*/ +/** +* @brief 删除文件 +* +* @param file 文件句柄 +* +* @return 无意义 +*/ +/* ----------------------------------------------------------------------------*/ +int fdelete(FILE *file); +int fdelete_by_name(const char *fname); + +/* --------------------------------------------------------------------------*/ +/** +* @brief 获取设备剩余容量 +* +* @param path 根路径 +* @param space 剩余空间 K 为单位 +* +* @return 无意义 +*/ +/* ----------------------------------------------------------------------------*/ +int fget_free_space(const char *path, u32 *space); + +/* --------------------------------------------------------------------------*/ +/** +* @brief 获取当前文件相对路径和绝对路径 +* +* @param file 文件句柄 +* @param fscan 扫描句柄 +* @param name 路径buf +* @param len buf长度 +* @param is_relative_path 是否相对路径 +* +* @return 获取到的文件名长度 +*/ +/* ----------------------------------------------------------------------------*/ +int fget_path(FILE *file, struct vfscan *fscan, u8 *name, int len, u8 is_relative_path); + +/* arg: + * -t 文件类型 + * -r 包含子目录 + * -d 扫描文件夹 + * -a 文件属性 r: 读, /: 非 + * -s 排序方式, t:按时间排序, n:按文件号排序 + */ + +/* --------------------------------------------------------------------------*/ +/** +* @brief 文件扫描 +* +* @param path 路径 +* @param arg 扫描方式 +* @param max_deepth 扫描深度,最大为9 +* +* @return vfscan句柄 +*/ +/* ----------------------------------------------------------------------------*/ +struct vfscan *fscan(const char *path, const char *arg, u8 max_deepth); //扫描接口,参数配置如上。 + +/* --------------------------------------------------------------------------*/ +/** +* @brief 文件扫描,可打断。 +* +* @param path 路径 +* @param arg 扫描方式 +* @param max_deepth 扫描深度,最大为9 +* @param callback 回调函数,用于打断、同时进行其他操作等 +* +* @return vfscan句柄 +*/ +/* ----------------------------------------------------------------------------*/ +struct vfscan *fscan_interrupt(const char *path, const char *arg, u8 max_deepth, int (*callback)(void)); //可打断扫描 + +/* --------------------------------------------------------------------------*/ +/** +* @brief 进入指定子目录,只扫此目录下文件信息 +* +* @param fs vfscan句柄 +* @param path 子目录相对路径 +* +* @return vfscan句柄 +*/ +/* ----------------------------------------------------------------------------*/ +struct vfscan *fscan_enterdir(struct vfscan *fs, const char *path);//进入指定子目录,只扫此目录下文件信息 + +/* --------------------------------------------------------------------------*/ +/** +* @brief 返回上一层目录 +* +* @param fs vfscan句柄 +* +* @return vfscan句柄 +*/ +/* ----------------------------------------------------------------------------*/ +struct vfscan *fscan_exitdir(struct vfscan *fs); //返回上一层 + +/* --------------------------------------------------------------------------*/ +/** +* @brief 释放句柄 +* +* @param fs vfscan句柄 +*/ +/* ----------------------------------------------------------------------------*/ +void fscan_release(struct vfscan *fs); + +/* --------------------------------------------------------------------------*/ +/** +* @brief 选择指定文件打开 +* +* @param fs vfscan句柄 +* @param selt_mode 按什么方式选择 (支持按簇号、序号、路径选择) +* @param arg 传入选择的参数 +* +* @return 文件句柄 +*/ +/* ----------------------------------------------------------------------------*/ +FILE *fselect(struct vfscan *fs, int selt_mode, int arg); //选择指定文件 + +/* --------------------------------------------------------------------------*/ +/** +* @brief 检查挂载目录是否存在 +* +* @param dir 目录路径 +* +* @return 0存在 , 1不存在 +*/ +/* ----------------------------------------------------------------------------*/ +int fdir_exist(const char *dir); //check 目录是否存在 + +int fdir(FILE *file, const char *arg, char *name, int len, struct fiter *iter);//暂无此接口 + +/* --------------------------------------------------------------------------*/ +/** +* @brief 获取文件属性 +* +* @param file 文件句柄 +* @param attr 属性 +* +* @return 0成功, 非0错误。 +*/ +/* ----------------------------------------------------------------------------*/ +int fget_attr(FILE *file, int *attr); //获取文件属性 + +/* --------------------------------------------------------------------------*/ +/** +* @brief 设置文件属性 +* +* @param file 文件句柄 +* @param attr 属性 +* +* @return 0成功, 非0错误。 +*/ +/* ----------------------------------------------------------------------------*/ +int fset_attr(FILE *file, int attr); //设置文件属性 + +/* --------------------------------------------------------------------------*/ +/** +* @brief 获取文件相关信息 +* +* @param file 文件句柄 +* @param attr 记录相应信息的结构体 +* +* @return 0成功, 非0错误。 +*/ +/* ----------------------------------------------------------------------------*/ +int fget_attrs(FILE *file, struct vfs_attr *attr);//获得文件相关信息如属性、簇号、大小等 + +/* --------------------------------------------------------------------------*/ +/** +* @brief 获取分区part +* +* @param path 路径 +* +* @return vfs_partition句柄 +*/ +/* ----------------------------------------------------------------------------*/ +struct vfs_partition *fget_partition(const char *path);//获得分区part + +/* --------------------------------------------------------------------------*/ +/** +* @brief 设置卷标 +* +* @param path 设备路径 +* @param name 卷标名字 +* +* @return 0成功, 非0错误。 +*/ +/* ----------------------------------------------------------------------------*/ +int fset_vol(const char *path, const char *name);//设置卷标 + +int fmove(FILE *file, const char *path_dst, FILE **newFile, int clr_attr, int path_len); + +int fcheck(FILE *file);//暂不支持 + +int fget_err_code(const char *path); //暂不支持 + +int fset_name_filter(const char *path, void *name_filter);//暂不支持 + +/* --------------------------------------------------------------------------*/ +/** +* @brief 获取文件夹信息 +* +* @param fs vfscan 结构句柄 +* @param arg 文件夹信息结构句柄 +* +* @return 无意义 +*/ +/* ----------------------------------------------------------------------------*/ +int fget_folder(struct vfscan *fs, struct ffolder *arg); //获取文件夹序号和文件夹内文件数目 + +/* --------------------------------------------------------------------------*/ +/** + * @brief 设置长文件名Buf (现已不常用) + * + * @param fs vfscan 句柄 + * @param arg buf + * + * @return 0成功, 非0错误。 + */ +/* ----------------------------------------------------------------------------*/ +int fset_lfn_buf(struct vfscan *fs, void *arg);//设置长文件名buf +/* --------------------------------------------------------------------------*/ +/** + * @brief 设置长文件夹名Buf (现已不常用) + * + * @param fs vfscan 句柄 + * @param arg buf + * + * @return 0成功, 非0错误。 + */ +/* ----------------------------------------------------------------------------*/ +int fset_ldn_buf(struct vfscan *fs, void *arg);//设置长文件夹名buf + +/* --------------------------------------------------------------------------*/ +/** + * @brief 设置后缀名过滤(现已不常用) + * + * @param path 根路径 + * @param ext_type 后缀名 + * + * @return 0成功, 非0错误。 + */ +/* ----------------------------------------------------------------------------*/ +int fset_ext_type(const char *path, void *ext_type);//设置后缀类型 +/* --------------------------------------------------------------------------*/ +/** + * @brief 文件浏览使用,打开目录 + * + * @param path 路径 + * @param pp_file 文件句柄 + * @param dir_dj 目录信息句柄 + * + * @return 无意义 + */ +/* ----------------------------------------------------------------------------*/ +int fopen_dir_info(const char *path, FILE **pp_file, void *dir_dj); //打开目录 +/* --------------------------------------------------------------------------*/ +/** + * @brief 文件浏览使用,进入目录 + * + * @param file 文件句柄 + * @param dir_dj 目录信息句柄 + * + * @return 目录项总数 + */ +/* ----------------------------------------------------------------------------*/ +int fenter_dir_info(FILE *file, void *dir_dj); //进入目录 +/* --------------------------------------------------------------------------*/ +/** + * @brief 文件浏览使用,退出目录 + * + * @param file 文件句柄 + * + * @return 目录项总数 + */ +/* ----------------------------------------------------------------------------*/ +int fexit_dir_info(FILE *file); //退出 +/* --------------------------------------------------------------------------*/ +/** + * @brief 文件浏览使用,获取目录信息 + * + * @param file 文件句柄 + * @param start_num 起始位置 + * @param total_num 获取目录个数 + * @param buf_info 目录信息句柄 + * + * @return 获取的目录数 + */ +/* ----------------------------------------------------------------------------*/ +int fget_dir_info(FILE *file, u32 start_num, u32 total_num, void *buf_info); ////获取目录信息 + + +/* --------------------------------------------------------------------------*/ +/** + * @brief 存储文件簇信息 + * + * @param file 文件句柄 + * + * @note 一般手表case使用, 用于fget_fat_outflash_addr()之前调用,节省fget_fat_outflash_addr()时间 + * @return 0成功, 非0错误。 + */ +/* ----------------------------------------------------------------------------*/ +int fstore_clust_rang(FILE *file); +/* --------------------------------------------------------------------------*/ +/** + * @brief 获取外置flash实际物理地址 + * + * @param file 文件句柄 + * @param name sdfile格式文件名 + * @param buf_info 存储相关信息结构buf指针 + * @param buf_len buf 长度 + * + * @note 一般手表case使用 + * @return 0表示buf不够 大于 0 表示存储多少个信息结构,其他 错误 + */ +/* ----------------------------------------------------------------------------*/ +int fget_fat_outflash_addr(FILE *file, char *name, void *buf_info, int buf_len); //获取外置flash实际物理地址 + +/* --------------------------------------------------------------------------*/ +/** + * @brief 文件浏览使用,由歌曲名称获取歌词 + * + * @param file 歌曲文件句柄 + * @param newFile 歌词文件句柄 + * @param ext_name 后缀名称 + * + * @return 0成功, 非0错误。 + */ +/* ----------------------------------------------------------------------------*/ +int fget_file_byname_indir(FILE *file, FILE **newFile, void *ext_name); //由歌曲名称获得歌词 + +/* --------------------------------------------------------------------------*/ +/** + * @brief 获取长文件名和长文件夹名信息(现在不常使用) + * + * @param file 歌曲文件句柄 + * @param arg 长文件相关信息结构指针 + * + * @note 需要先设置长文件名或者长文件夹名buf进去 + * @return 0成功, 非0错误。 + */ +/* ----------------------------------------------------------------------------*/ +int fget_disp_info(FILE *file, void *arg); //用于长文件名获取 + +/* --------------------------------------------------------------------------*/ +/** + * @brief 创建目录 + * + * @param path 路径 + * @param folder 文件夹名称,不需要 / + * @param mode 目录属性(1 设置为隐藏属性, 0 不设置 ) + * + * @return 0成功,非0不成功 + */ +/* ----------------------------------------------------------------------------*/ +int fmk_dir(const char *path, char *folder, u8 mode); //创建目录 + +/* --------------------------------------------------------------------------*/ +/** + * @brief 获取录音文件信息(现在不常用) + * + * @param path 路径 + * @param folder 文件夹名称 + * @param ext 文件名后缀 + * @param last_num 可变数字最大数字 + * @param total_num 文件总数 + * + * @return 0成功,非0不成功 + */ +/* ----------------------------------------------------------------------------*/ +int fget_encfolder_info(const char *path, char *folder, char *ext, u32 *last_num, u32 *total_num); //获取录音文件信息 + +/* --------------------------------------------------------------------------*/ +/** + * @brief 拼接字符 + * + * @param result 最终结果指针 + * @param path 前路径指针 + * @param fname 需要拼接的字符 + * @param len fname长度 + * + * @return 0成功,非0不成功 + */ +/* ----------------------------------------------------------------------------*/ +int fname_to_path(char *result, const char *path, const char *fname, int len); //把路径和文件名拼接 + +/* --------------------------------------------------------------------------*/ +/** + * @brief 截取path中根目录之后的文件名 + * + * @param path 路径 + * + * @return 文件名 + */ +/* ----------------------------------------------------------------------------*/ +const char *fname_after_root(const char *path); // 截取path中根目录之后的文件名 +/* --------------------------------------------------------------------------*/ +/** + * @brief 获取文件系统类型 + * + * @param path 路径 + * + * @return 文件系统类型 + */ +/* ----------------------------------------------------------------------------*/ +const char *fget_fs_type(const char *path); // 获取文件系统类型 + +/* --------------------------------------------------------------------------*/ +/** + * @brief 录音获取最后序号 + * + * @return 最后序号 + */ +/* ----------------------------------------------------------------------------*/ +int get_last_num(void); //录音获取最后序号。 + +/* --------------------------------------------------------------------------*/ +/** + * @brief 设置断点参数 + * + * @param clust 记录的簇号 + * @param fsize 记录的文件大小 + * @param flag 文件是否存在标志 + * + * @note 1.接口调用在扫描前 + * 2.使用完需要put_bp_info对应释放buf + */ +/* ----------------------------------------------------------------------------*/ +void set_bp_info(u32 clust, u32 fsize, u32 *flag); //扫描前设置断点参数,需要put_bp_info对应释放buf. +/* --------------------------------------------------------------------------*/ +/** + * @brief 释放内存 + */ +/* ----------------------------------------------------------------------------*/ +void put_bp_info(void); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 优化扫盘速度 + * + * @param enable 开关 + * @note 1.目的是是否去除获取文件夹内所有文件功能,默认enable 是1 获取数目,置0不获取,所以不需要切换文件夹操作的功能,可置0 关闭 + * 2.在扫描前调用接口 + */ +/* ----------------------------------------------------------------------------*/ +void ff_set_FileInDir_enable(u8 enable); // 优化文件打开速度,如果不需要切换文件夹的操作,可置0关闭 +/* --------------------------------------------------------------------------*/ +/** + * @brief 设置目录项基点信息(用于加速) + * + * @param buf 存储基点buf (长度 12 * n) + * @param n 基点数目 + * @note 1.加速序号选择文件,明显效果体现在上一曲加速 + * 2.注意buf使用 + */ +/* ----------------------------------------------------------------------------*/ +void ff_set_DirBaseInfo(void *buf, u16 n); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 设置文件的创建时间 + * + * @param year 年 + * @param month 月 + * @param day 日 + * @param hour 小时 + * @param minute 分钟 + * @param second 秒 + */ +/* ----------------------------------------------------------------------------*/ +void fat_set_datetime_info(u16 year, u8 month, u8 day, u8 hour, u8 minute, u8 second); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 隐藏属性文件是否过滤 + * + * @param flag 置1 为过滤 + */ +/* ----------------------------------------------------------------------------*/ +void hidden_file(u8 flag); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 是否保存预申请长度 + * + * @param enable 1保存,0 不保存 + */ +/* ----------------------------------------------------------------------------*/ +void fat_save_already_size_enable(char enable); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 设置预申请簇数目 + * + * @param num 数目(1-0x1fe) + */ +/* ----------------------------------------------------------------------------*/ +void fat_set_pre_create_chain_num(u16 num); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 存储文件簇信息 + * + * @param file 文件句柄 + * @param btr buf 长度 + * @param buf buf指针 + * + * @note seek加速,4字节对齐 + * @return 0成功,非0不成功 + */ +/* ----------------------------------------------------------------------------*/ +int fsave_fat_table(FILE *file, u16 btr, u8 *buf); +/* --------------------------------------------------------------------------*/ +/** + * @brief 刷新文件系统缓存buf + * + * @param path 设备路径 + * + * @return 0成功,非0不成功 + */ +/* ----------------------------------------------------------------------------*/ +int f_flush_wbuf(const char *path); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 插入文件 + * + * @param file 源文件 + * @param i_file 需要插入的文件 + * @param fptr 源文件被插入的位置 + * + * @return 0成功,非0不成功 + */ +/* ----------------------------------------------------------------------------*/ +int finsert_file(FILE *file, FILE *i_file, u32 fptr); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 分割文件 + * + * @param file 源文件 + * @param file_name 分割后第二个文件文件名 + * @param fptr 源文件被分割位置 + * + * @return 0成功,非0不成功 + */ +/* ----------------------------------------------------------------------------*/ +int fdicvision_file(FILE *file, char *file_name, u32 fptr); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 长文件名切割00 00 后面的数据 + * + * @param str 数据buff + * @param len 数据buff长度 + * + * @return 切割后的长度 + */ +/* ----------------------------------------------------------------------------*/ +int long_name_fix(u8 *str, u16 len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief UFT8 转换 Unicode + * + * @param utf8_buf UTF8编码的字符串 + * @param pUniBuf short 类型Unicode字符串 + * @param utf8_len utf8数据长度 + * + * @return 得到的unicode码大小 + */ +/* ----------------------------------------------------------------------------*/ +int UTF82Unicode(const char *utf8_buf, u16 *pUniBuf, int utf8_len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief Unicode 转 UTF8 + * + * + * @param utf8_buf UTF8编码的字符串 + * @param pUniBuf short 类型Unicode字符串 + * @param uni_len unicode数据长度 + * + * @return 得到的UTF8码大小 + */ +/* ----------------------------------------------------------------------------*/ +int Unicode2UTF8(char *utf8_buf, u16 *pUniBuf, int uni_len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 检查是否UTF8 码格式 + * + * @param str 数据buff + * @param length 数据buff长度 + * + * @return 1:是UTF8 0:不是 + */ +/* ----------------------------------------------------------------------------*/ +bool utf8_check(const char *str, int length); +#endif /* VFS_ENABLE */ + +#endif /* __FS_H__ */ + + + + + + diff --git a/include_lib/system/fs/fs_file_name.h b/include_lib/system/fs/fs_file_name.h new file mode 100644 index 0000000..9ff470d --- /dev/null +++ b/include_lib/system/fs/fs_file_name.h @@ -0,0 +1,35 @@ +#ifndef __FS_FILE_NAME_H__ +#define __FS_FILE_NAME_H__ + +#include "generic/typedef.h" + +#define D_LFN_MAX_SIZE 512 + +#define LFN_MAX_SIZE D_LFN_MAX_SIZE //不能超过512 //必须4byte对齐 + +typedef struct _LONG_FILE_NAME { + u16 lfn_cnt; + char lfn[LFN_MAX_SIZE]; //长文件名buffer +} LONG_FILE_NAME; //整理后的长文件名 + +typedef struct _FS_DIR_INFO { + u32 sclust; //dir sclust + u16 dir_type; // 0-folder,1-file + u16 fn_type; // 0-sfn,1-lfn + LONG_FILE_NAME lfn_buf; //long file name +} FS_DIR_INFO; + +typedef struct _FS_DISP_INFO { + char tpath[128]; + LONG_FILE_NAME file_name; + LONG_FILE_NAME dir_name; + u8 update_flag; +} FS_DISP_INFO; + +typedef struct _FLASH_FAT_ADDRINFO { + u32 saddr; //当前连续簇块文件起始实际物理地址 + u32 end_addr; //当前连续簇块结束位置 + u32 file_len; //文件长度,如 JL.res文件的 +} FLASH_FAT_ADDRINFO; +#endif /* __FS_FILE_NAME_H__ */ + diff --git a/include_lib/system/fs/sdfile.h b/include_lib/system/fs/sdfile.h new file mode 100644 index 0000000..e338182 --- /dev/null +++ b/include_lib/system/fs/sdfile.h @@ -0,0 +1,222 @@ +#ifndef _SDFILE_H_ +#define _SDFILE_H_ + +#include "typedef.h" + + +//=======================================================// +// 默认宏配置定义 // +//=======================================================// +#ifndef SDFILE_STORAGE +#define SDFILE_STORAGE 0 +#endif /* #ifndef SDFILE_STORAGE */ + +#define NOR_SDFILE_ENABLE 1 +/********* sdfile 文件头 **********/ +#define SDFILE_NAME_LEN 16 + +typedef struct sdfile_file_head { + u16 head_crc; + u16 data_crc; + u32 addr; + u32 len; + u8 attr; + u8 res; + u16 index; + char name[SDFILE_NAME_LEN]; +} SDFILE_FILE_HEAD; + +#if 0 +////////////////////////////sdfile_file_head成员详细说明/////////////////////////////////////// +typedef struct SDFILEJL_FILE_HEAD { + u16 u16Crc; // 结构体自身校验码 + u16 u16DataCrc; // 文件数据校验码 + u32 u32Address; // 数据存储地址 + u32 u32Length; // 数据长度 + u8 u8Attribute; // 属性 + u8 u8Res; // 保留数据 + u16 u16Index; // 文件编号,从大到小排列,编号为0时,代表后面没有文件 + char szFileName[16];// 文件名 +} JL_SDFILE_HEAD; + +////////////////////////////flash_head成员详细说明/////////////////////////////////////// +typedef struct SDFILEJL_FLASH_HEAD_V2 { + u16 u16Crc; // 结构体自身校验码 + u16 u16SizeForBurner; // 为烧写器保留的空间大小 + char vid[4]; // 存放VID信息,长度是4个byte + u32 u32FlashSize; // FLASH大小,由isd_download计算得出 + u8 u8FsVersion; // flash类型:BR18(0)/BR22(1) + u8 u8BlockAlingnModulus;// 对齐系数,对齐的值=对齐系数*256 + u8 u8Res; // 保留 + u8 u8SpecialOptFlag; // 用于标记是否需要生成2种flash格式的标记位,目前只用1位 + char pid[16]; // 存放PID信息,长度是16个byte +} SDFILEJL_FLASH_HEAD_V2; + +#endif + +struct sdfile_dir { + u16 file_num; + struct sdfile_file_head head; +}; + +enum sdfile_err_table { + SDFILE_DIR_NOT_EXIST = -0xFF, + SDFILE_FILE_NOT_EXIST, + SDFILE_MALLOC_ERR, + SDFILE_VM_NOT_FIND, + SDFILE_DATA_CRC_ERR, + SDFILE_WRITE_AREA_NEED_ERASE_ERR, + SDFILE_SUSS = 0, + SDFILE_END, +}; + +#if (VFS_ENABLE == 1) + +#if SDFILE_STORAGE +#define SDFILE_MAX_DEEPTH 2 +struct sdfile_folder { + u32 saddr; + u32 addr; + u32 len; +}; +struct sdfile_scn { + u8 subpath; + u8 cycle_mode; + u8 attr; + u8 deepth; + u16 dirCounter; + u16 fileCounter; + u16 fileNumber; // 当前文件序号 + u16 totalFileNumber; + u16 last_file_number; + u16 fileTotalInDir; // 当前目录的根下有效文件的个数 + u16 fileTotalOutDir; // 当前目录前的文件总数,目录循环模式下,需要用它来计算文件序号 + u32 sclust_id; + const char *ftypes; + struct sdfile_file_head head; + struct sdfile_folder folder[SDFILE_MAX_DEEPTH]; +}; +#endif + +typedef struct sdfile_file_t { + u32 fptr; + struct sdfile_file_head head; +#if SDFILE_STORAGE + struct sdfile_scn *pscn; +#endif +} SDFILE; + +#else + +typedef struct sdfile_file_t { + u32 fptr; + struct sdfile_file_head head; +} SDFILE, FILE; + +struct vfs_attr { + u8 attr; //属性 + u32 fsize; //文件大小 + u32 sclust; //地址 +}; + +SDFILE *sdfile_open(const char *path, const char *mode); +int sdfile_read(SDFILE *fp, void *buf, u32 len); +int sdfile_write(SDFILE *fp, void *buf, u32 len); +int sdfile_seek(SDFILE *fp, u32 offset, u32 fromwhere); +int sdfile_close(SDFILE *fp); +int sdfile_pos(SDFILE *fp); +int sdfile_len(SDFILE *fp); +int sdfile_get_name(SDFILE *fp, u8 *name, int len); +int sdfile_get_attrs(SDFILE *fp, struct vfs_attr *attr); + +#if 0 +#define fopen sdfile_open +#define fread sdfile_read +#define fseek sdfile_seek +#define fclose sdfile_close +#define fwrite sdfile_write +#define flen sdfile_len +#define fpos sdfile_pos +#define fget_name sdfile_get_name +#define fget_attrs sdfile_get_attrs +#else + +static inline SDFILE *fopen(const char *path, const char *mode) +{ + return sdfile_open(path, mode); +} +static inline int fread(SDFILE *fp, void *buf, u32 len) +{ + return sdfile_read(fp, buf, len); +} +static inline int fwrite(SDFILE *fp, void *buf, u32 len) +{ + return sdfile_write(fp, buf, len); +} +static inline int fseek(SDFILE *fp, u32 offset, u32 fromwhere) +{ + return sdfile_seek(fp, offset, fromwhere); +} +static inline int fclose(SDFILE *fp) +{ + return sdfile_close(fp); +} +static inline int fpos(SDFILE *fp) +{ + return sdfile_pos(fp); +} +static inline int flen(SDFILE *fp) +{ + return sdfile_len(fp); +} +static inline int fget_name(SDFILE *fp, u8 *name, int len) +{ + return sdfile_get_name(fp, name, len); +} +static inline int fget_attrs(SDFILE *fp, struct vfs_attr *attr) +{ + return sdfile_get_attrs(fp, attr); +} + +#endif + +#endif /* VFS_ENABLE */ + +int sdfile_delete_data(SDFILE *fp); +#define fdel_data sdfile_delete_data + +#ifndef SDFILE_MOUNT_PATH +#define SDFILE_MOUNT_PATH "mnt/sdfile" +#endif /* #ifndef SDFILE_MOUNT_PATH */ + +#if (USE_SDFILE_NEW) + +#ifndef SDFILE_APP_ROOT_PATH +#define SDFILE_APP_ROOT_PATH SDFILE_MOUNT_PATH"/app/" //app分区 +#endif /* #ifndef SDFILE_APP_ROOT_PATH */ + +#ifndef SDFILE_RES_ROOT_PATH +#define SDFILE_RES_ROOT_PATH SDFILE_MOUNT_PATH"/res/" //资源文件分区 +#endif /* #ifndef SDFILE_RES_ROOT_PATH */ + +#else +#ifndef SDFILE_RES_ROOT_PATH +#define SDFILE_RES_ROOT_PATH SDFILE_MOUNT_PATH"/C/" +#endif /* #ifndef SDFILE_RES_ROOT_PATH */ + +#endif /* #if (USE_SDFILE_NEW) */ + +//获取flash物理大小, 单位: Byte +u32 sdfile_get_disk_capacity(void); +//flash addr -> cpu addr +u32 sdfile_flash_addr2cpu_addr(u32 offset); +//cpu addr -> flash addr +u32 sdfile_cpu_addr2flash_addr(u32 offset); + +void sdfile_head_addr_get(char *name, u32 *addr, u32 *len); + +u32 init_norsdfile_hdl(void); +int set_res_startaddr(int offset); + +#endif /* _SDFILE_H_ */ + diff --git a/include_lib/system/fs/virfat_flash.h b/include_lib/system/fs/virfat_flash.h new file mode 100644 index 0000000..cdbe055 --- /dev/null +++ b/include_lib/system/fs/virfat_flash.h @@ -0,0 +1,161 @@ +#ifndef VIRTUAL_DISK_H +#define VIRTUAL_DISK_H + +#include "system/includes.h" + + +#define VIR_FILE_TYPE_MP3 1 +#define VIR_FILE_TYPE_WAV 2 + +extern const struct device_operations virfat_flash_dev_ops; +extern const struct device_operations private_sfc_dev_ops; + +typedef enum { + FS_FAT12 = 0x01, + FS_FAT16 = 0x02, + FS_FAT32 = 0x04, + FS_EXFAT = 0x14, +} FS_TYPE; + +#define JLFAT_DIRINFO_ENABLE 0 +#if JLFAT_DIRINFO_ENABLE +typedef struct jlfat_dirinfo { + u8 name[12]; //文件名字 + int fsize; // 文件大小 + u16 fix_date; //修改日期 + u16 fix_time; //修改时间 + u8 attr; //文件属性 + int sclust; //文件起始簇 +} JLFAT_DIRINFO; +#endif + +typedef struct _virfat_flash_t { + u32 fatbase; + // u32 fatbase2; + u16 fatsize; + u32 dirbase; + u32 database; + u32 clustSize; + u32 max_clust; + u32 capacity; + u8 csize; + FS_TYPE fs_type; + char re_devname[24]; + u32 flash_fatfs_addr; + u32 fatfs_len; +} virfat_flash_t; + +typedef struct _dir_entry { + u8 name[12]; + u32 fileSize; +} dir_entry_t; + + +#if 0 +extern void virfat_flash_rand_file_size(); +extern void virtual_disk_reduce_file_size(tu8 file_num); +extern void virtual_disk_remove_files(tu8 file_type); +extern void virtual_disk_reduce_file_size(tu8 file_num); +extern u8 virfat_flash_init(void *buf_512, void (*fun_read_file)(u32, u32, u8 *, u32)); +#endif + +#define MIN_FAT16 4086 /* Minimum number of clusters for FAT16 */ +#define MIN_FAT32 65526 /* Minimum number of clusters for FAT32 */ + +#define AM_RDO 0x01 /* Read only */ +#define AM_HID 0x02 /* Hidden */ +#define AM_SYS 0x04 /* System */ +#define AM_VOL 0x08 /* Volume label */ +#define AM_LFN 0x0F /* LFN entry */ +#define AM_DIR 0x10 /* Directory */ +#define AM_ARC 0x20 /* Archive */ +#define AM_FCH 0x80 /* exFAT下,文件簇连续标志 */ +#define AM_FRG 0x40 /* exFAT下,文件簇BITMAP 有碎片 */ +#define AM_LFN0_START 0x1 +#define AM_LFN0_LEN 10 +#define AM_LFN1_START 0xE +#define AM_LFN1_LEN 12 +#define AM_LFN2_START 0x1C +#define AM_LFN2_LEN 4 +#define AM_LFN_LEN 26 + +#define AM_EX_DIR_STRETCHED 0x08 + +#define BS_jmpBoot 0 +#define BS_OEMName 3 +#define BPB_BytsPerSec_l 11 +#define BPB_BytsPerSec_h 12 +#define BPB_SecPerClus 13 +#define BPB_RsvdSecCnt 14 +#define BPB_NumFATs 16 +#define BPB_RootEntCnt 17 +#define BPB_TotSec16 19 +#define BPB_Media 21 +#define BPB_FATSz16 22 +#define BPB_SecPerTrk 24 +#define BPB_NumHeads 26 +#define BPB_HiddSec 28 +#define BPB_TotSec32 32 +#define BS_55AA 510 + +#define BS_DrvNum 36 +#define BS_BootSig 38 +#define BS_VolID 39 +#define BS_VolLab 43 +#define BS_FilSysType 54 + +#define BPB_FATSz32 36 +#define BPB_ExtFlags 40 +#define BPB_FSVer 42 +#define BPB_RootClus 44 +#define BPB_FSInfo 48 +#define BPB_BkBootSec 50 +#define BS_DrvNum32 64 +#define BS_BootSig32 66 +#define BS_VolID32 67 +#define BS_VolLab32 71 +#define BS_FilSysType32 82 +#define BS_FileSysTypeexFAT 5 +#define BPB_FatOffset 80 +#define BPB_FatLength 84 +#define BPB_ClusterHeapOffset 88 +#define BPB_ClusterCount 92 +#define BPB_FirstClusterOfRootDirectory 96 +#define BPB_VolumeFlags 106 +#define BPB_BytesPerSectorShift 108 +#define BPB_SectorsPerClusterShift 109 +#define BPB_NumberOfFats 110 +#define MBR_Table 446 +#define FSI_LeadSig 0 /* FSI: Leading signature (4) */ +#define FSI_StrucSig 484 /* FSI: Structure signature (4) */ +#define FSI_Free_Count 488 /* FSI: Number of free clusters (4) */ +#define FSI_Nxt_Free 492 /* FSI: Last allocated cluster (4) */ + +///for FAT12/FAT16/FAT32 +#define DIR_Name 0 /* Short file name (11) */ +#define DIR_Attr 11 /* Attribute (1) */ +#define DIR_NTres 12 /* NT flag (1) */ +#define DIR_CrtTimeTenth 13 /* Created time sub-second (1) */ +#define DIR_CrtTime 14 /* Created time (2) */ +#define DIR_CrtDate 16 /* Created date (2) */ +#define DIR_LstAccDate 18 /* Last accessed date (2) */ +#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (2) */ +#define DIR_WrtTime 22 /* Modified time (2) */ +#define DIR_WrtDate 24 /* Modified date (2) */ +#define DIR_FstClusLO 26 +#define DIR_FileSize 28 +#define LDIR_Attr 11 /* LFN attribute (1) */ +#define LDIR_Type 12 /* LFN type (1) */ +#define LDIR_Chksum 13 /* Sum of corresponding SFN entry */ +////for exFAT +#define DIR_FileChainFlags 1 +#define DIR_NameLen 3 +#define DIR_AttrexFAT 4 +#define DIR_FileSizeexFAT 8 +#define DIR_FstClustexFAT 20 +#define DIR_FileSize2exFAT 24 + + + +#endif + diff --git a/include_lib/system/generic/ascii.h b/include_lib/system/generic/ascii.h new file mode 100644 index 0000000..31e0842 --- /dev/null +++ b/include_lib/system/generic/ascii.h @@ -0,0 +1,44 @@ +#ifndef ASCII_LIB_H +#define ASCII_LIB_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#include "typedef.h" + + +void ASCII_ToLower(void *buf, u32 len); + +void ASCII_ToUpper(void *buf, u32 len); + +u32 ASCII_StrCmp(const char *src, const char *dst, u32 len); + +int ASCII_StrCmpNoCase(const char *src, const char *dst, int len); + +void ASCII_IntToStr(void *pStr, u32 intNum, u32 strLen, u32 bufLen); + +u32 ASCII_StrToInt(const void *pStr, u32 *pRint, u32 strLen); + +u32 ASCII_StrLen(void *str, u32 len); + +u32 ASCII_WStrLen(void *str, u32 len); + + + + + + + + + + + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include_lib/system/generic/atomic.h b/include_lib/system/generic/atomic.h new file mode 100644 index 0000000..697a1f6 --- /dev/null +++ b/include_lib/system/generic/atomic.h @@ -0,0 +1,81 @@ +#ifndef ATOMIC_H +#define ATOMIC_H + +#include "cpu.h" +#include "irq.h" + +typedef struct { + int counter; +} atomic_t; + +static inline int atomic_add_return(int i, atomic_t *v) +{ + int val; + CPU_SR_ALLOC(); + + CPU_CRITICAL_ENTER(); + + val = v->counter; + v->counter = val += i; + + CPU_CRITICAL_EXIT(); + + return val; +} + + +static inline int atomic_sub_return(int i, atomic_t *v) +{ + int val; + CPU_SR_ALLOC(); + + CPU_CRITICAL_ENTER(); + + val = v->counter; + v->counter = val -= i; + + CPU_CRITICAL_EXIT(); + + return val; +} + +static inline int atomic_set(atomic_t *v, int i) +{ + int val = 0; + CPU_SR_ALLOC(); + + CPU_CRITICAL_ENTER(); + + v->counter = i; + + CPU_CRITICAL_EXIT(); + + return val; +} + + +#define DEFINE_ATOMIC(x) \ + atomic_t x = {.counter = 0} + +#define atomic_add(i, v) atomic_add_return(i, v) +#define atomic_sub(i, v) atomic_sub_return(i, v) + +#define atomic_read(v) arch_atomic_read(v) +/*#define atomic_set(v,i) (((v)->counter) = (i))*/ + +#define atomic_inc(v) atomic_add(1, v) +#define atomic_dec(v) atomic_sub(1, v) + +#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) +#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) +#define atomic_inc_return(v) (atomic_add_return(1, v)) +#define atomic_dec_return(v) (atomic_sub_return(1, v)) +#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) + +#define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0) + + + + +#endif + diff --git a/include_lib/system/generic/circular_buf.h b/include_lib/system/generic/circular_buf.h new file mode 100644 index 0000000..1d7d6b8 --- /dev/null +++ b/include_lib/system/generic/circular_buf.h @@ -0,0 +1,302 @@ +#ifndef CIRCULAR_BUF_INTERFACE_H +#define CIRCULAR_BUF_INTERFACE_H + +#include "typedef.h" +#include "system/spinlock.h" + + + + +#ifndef CONFIG_CBUF_IN_MASKROM + +/* --------------------------------------------------------------------------*/ +/** + * @brief cbuffer结构体 + */ +/* ----------------------------------------------------------------------------*/ +typedef struct _cbuffer { + u8 *begin; + u8 *end; + u8 *read_ptr; + u8 *write_ptr; + u8 *tmp_ptr ; + u32 tmp_len; + u32 data_len; + u32 total_len; + spinlock_t lock; +} cbuffer_t; + +#else /* #ifndef CONFIG_CBUF_IN_MASKROM */ + +/* ---------------------------------------------------------------------------- */ +/** + * @brief cbuffer结构体 + * @note: 以下结构体成员不可修改 + */ +/* ---------------------------------------------------------------------------- */ +typedef struct _cbuffer { + u8 *begin; + u8 *end; + u8 *read_ptr; + u8 *write_ptr; + u8 *tmp_ptr ; + u32 tmp_len; + u32 data_len; + u32 total_len; + spinlock_t lock; +} cbuffer_t; + +#endif /* #ifndef CONFIG_CBUF_IN_MASKROM */ + + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:全局 + * @brief cbuffer初始化 + * + * @param [in] cbuffer cbuffer 句柄 + * @param [in] buf 缓存空间 + * @param [in] size 缓存总大小 + */ +/* ----------------------------------------------------------------------------*/ +void cbuf_init(cbuffer_t *cbuffer, void *buf, u32 size); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:cb_memcpy管理 + * @brief 把cbuffer_t结构体管理的内存空间的数据拷贝到buf数组 + + * @param [in] cbuffer cbuffer 句柄 + * @param [out] buf 指向用于存储读取内容的目标数组 + * @param [in] len 要读取的字节长度 + * + * @return 成功读取的字节长度 + */ +/* ----------------------------------------------------------------------------*/ +u32 cbuf_read(cbuffer_t *cbuffer, void *buf, u32 len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:cb_memcpy管理 + * @brief 把buf数组数据拷贝cbuffer_t结构体管理的内存空间 + * + * @param [in] cbuffer cbuffer 句柄 + * @param [in] buf 指向用于存储写入内容的目标数组 + * @param [in] len 要写入的字节长度 + * + * @return 成功写入的字节长度 + */ +/* ----------------------------------------------------------------------------*/ +u32 cbuf_write(cbuffer_t *cbuffer, void *buf, u32 len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:全局 + * @brief 判断是否可写入len字节长度的数据 + * + * @param [in] cbuffer cbuffer 句柄 + * @param [in] len len字节长度的数据 + * + * @return 返回可以写入的len字节长度 + */ +/* ----------------------------------------------------------------------------*/ +u32 cbuf_is_write_able(cbuffer_t *cbuffer, u32 len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:外部内存管理 + * @brief 预分配待写入数据的空间,要和cbuf_write_updata()配套使用,更新cbuf管理handle数据。 + * + * @param [in] cbuffer cbuffer句柄 + * @param [in] len 回传可以最多写入len字节长度的数据 + * + * @return 当前写指针的地址 + */ +/* ----------------------------------------------------------------------------*/ +void *cbuf_write_alloc(cbuffer_t *cbuffer, u32 *len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:外部内存管理 + * @brief 更新cbuf管理handle的写指针位置和数据长度 + * + * @param [in] cbuffer cbuffer句柄 + * @param [in] len 在非cbuffer_t结构体包含的内存空间中写入的数据的实际字节长度 + * + * @return 当前写指针的地址 + */ +/* ----------------------------------------------------------------------------*/ +void cbuf_write_updata(cbuffer_t *cbuffer, u32 len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:外部内存管理 + * @brief 预分配待读取数据的空间,需要和cbuf_read_updata()配套使用,更新cbuf管理handle数据 + * + * @param [in] cbuffer cbuffer 句柄 + * @param [in] len 回传可以最多读取len字节长度的数据 + * + * @return 当前读指针的地址 + */ +/* ----------------------------------------------------------------------------*/ +void *cbuf_read_alloc(cbuffer_t *cbuffer, u32 *len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:外部内存管理 + * @brief 更新cbuf管理handle的读指针位置和数据长度 + * + * @param [in] cbuffer cbuffer 句柄 + * @param [in] len 在非cbuffer_t结构体包含的内存空间中读取的数据的实际字节长度 + */ +/* ----------------------------------------------------------------------------*/ +void cbuf_read_updata(cbuffer_t *cbuffer, u32 len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:外部内存管理 + * @brief 清空cbuffer空间 + * + * @param [in] cbuffer cbuffer 句柄 + + */ +/* ----------------------------------------------------------------------------*/ +void cbuf_clear(cbuffer_t *cbuffer); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:cb_memcpy管理。 + * @brief 指定位置进行数据重写 + * + * @param [in] cbuffer cbuffer 句柄 + * @param [in] begin 指向需要重写内容的开始地址 + * @param [out] buf 指向用于存储重写内容的目标数组 + * @param [in] len 待重写内容的长度 + * + * @return 成功重写的字节长度 + */ +/* ----------------------------------------------------------------------------*/ +u32 cbuf_rewrite(cbuffer_t *cbuffer, void *begin, void *buf, u32 len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:cb_memcpy管理 + * @brief 更新指向上一次操作的指针为当前指针,并刷新数据长度 + * + * @param [in] cbuffer cbuffer 句柄 + */ +/* ----------------------------------------------------------------------------*/ +void cbuf_discard_prewrite(cbuffer_t *cbuffer); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:cb_memcpy管理 + * @brief 操作指针回退到上一次的操作位置,并刷新数据长度 + * + * @param [in] cbuffer cbuffer 句柄 + */ +/* ----------------------------------------------------------------------------*/ +void cbuf_updata_prewrite(cbuffer_t *cbuffer); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:cb_memcpy管理 + * @brief 回退写入内容,从上一次的操作的指针处进行覆盖填充 + * + * @param [in] cbuffer cbuffer 句柄 + * @param [out] buf 指向用于覆盖写入内容的目标数组 + * @param [in] len 填充数据的字节长度 + * + * @return 成功填充数据的字节长度 + */ +/* ----------------------------------------------------------------------------*/ +u32 cbuf_prewrite(cbuffer_t *cbuffer, void *buf, u32 len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:全局 + * @brief 获取指向写指针的地址 + * + * @param [in] cbuffer cbuffer 句柄 + * + * @return 写指针的地址 + */ +/* ----------------------------------------------------------------------------*/ +void *cbuf_get_writeptr(cbuffer_t *cbuffer); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:全局 + * @brief 获取cbuffer存储的数据的字节长度 + * + * @param [in] cbuffer cbuffer句柄 + * + * @return 获取cbuffer存储的数据的字节长度 + */ +/* ----------------------------------------------------------------------------*/ +u32 cbuf_get_data_size(cbuffer_t *cbuffer); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:全局 + * @brief 获取指向读指针的地址 + * + * @param [in] cbuffer cbuffer句柄 + * + * @return 读指针的地址 + */ +/* ----------------------------------------------------------------------------*/ +void *cbuf_get_readptr(cbuffer_t *cbuffer); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:全局 + * @brief 读指针向后回退 + * + * @param [in] cbuffer cbuffer 句柄 + * @param [in] len 要回退的字节长度 + * + * @return 成功回退的字节长度 + */ +/* ----------------------------------------------------------------------------*/ +u32 cbuf_read_goback(cbuffer_t *cbuffer, u32 len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:全局 + * @brief 获取存储数据的字节长度 + * + * @param [in] cbuffer cbuffer 句柄 + * + * @return 存储数据的字节长度 + */ +/* ----------------------------------------------------------------------------*/ +u32 cbuf_get_data_len(cbuffer_t *cbuffer); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:memcpy管理+cbuf_read_alloc系列管理函数 + * @brief 预分配待读取数据的空间,并把读取到的数据存入buf数组 + * + * @param [in] cbuffer cbuffer 句柄 + * @param [out] buf 存储读取的数据的目标buf数组 + * @param [in] len 要读取的数据的字节长度 + * + * @return + */ +/* ----------------------------------------------------------------------------*/ +u32 cbuf_read_alloc_len(cbuffer_t *cbuffer, void *buf, u32 len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 适用范围:memcpy管理+cbuf_read_alloc系列管理函数 + * @brief 更新cbuf管理handle的读指针位置和数据长度 + * + * @param [in] cbuffer cbuffer 句柄 + * @param [in] len 要更新的数据的字节长度 + */ +/* ----------------------------------------------------------------------------*/ +void cbuf_read_alloc_len_updata(cbuffer_t *cbuffer, u32 len); + +#endif + diff --git a/include_lib/system/generic/cpu.h b/include_lib/system/generic/cpu.h new file mode 100644 index 0000000..2c1c72d --- /dev/null +++ b/include_lib/system/generic/cpu.h @@ -0,0 +1,22 @@ +#ifndef GENERIC_CPU_H +#define GENERIC_CPU_H + +#include + + + + + + + + + + + + + + + + +#endif + diff --git a/include_lib/system/generic/debug_lite.h b/include_lib/system/generic/debug_lite.h new file mode 100644 index 0000000..e80e245 --- /dev/null +++ b/include_lib/system/generic/debug_lite.h @@ -0,0 +1,10 @@ +#ifndef _LITE_DEBUG_H_ +#define _LITE_DEBUG_H_ + + +extern void puts_lite(const char *out); +extern void put_buf_lite(void *_buf, u32 len); +extern int printf_lite(const char *format, ...); + +#endif /* #ifdef _LITE_DEBUG_H_ */ + diff --git a/include_lib/system/generic/errno-base.h b/include_lib/system/generic/errno-base.h new file mode 100644 index 0000000..562edfb --- /dev/null +++ b/include_lib/system/generic/errno-base.h @@ -0,0 +1,40 @@ +#ifndef _ASM_GENERIC_ERRNO_BASE_H +#define _ASM_GENERIC_ERRNO_BASE_H + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define ETIMEDOUT 35 /* Connection timed out */ + +#endif diff --git a/include_lib/system/generic/gpio.h b/include_lib/system/generic/gpio.h new file mode 100644 index 0000000..ba20df2 --- /dev/null +++ b/include_lib/system/generic/gpio.h @@ -0,0 +1,44 @@ +#ifndef ASM_GPIO_H +#define ASM_GPIO_H + + +#include "asm/gpio.h" + +#define GPIO2PORT(gpio) (gpio / IO_GROUP_NUM) + +void gpio_port_lock(unsigned int port); + +void gpio_port_unlock(unsigned int port); + +int __gpio_direction_input(unsigned int gpio); +int gpio_direction_input(unsigned int gpio); + +int __gpio_direction_output(unsigned int gpio, int value); +int gpio_direction_output(unsigned int gpio, int value); + +int __gpio_set_pull_up(unsigned int gpio, int value); +int gpio_set_pull_up(unsigned int gpio, int value); + +int __gpio_set_pull_down(unsigned int gpio, int value); +int gpio_set_pull_down(unsigned int gpio, int value); + +int __gpio_set_hd(unsigned int gpio, int value); +int gpio_set_hd(unsigned int gpio, int value); + +int __gpio_set_die(unsigned int gpio, int value); +int gpio_set_die(unsigned int gpio, int value); + +int __gpio_set_output_clk(unsigned int gpio, int clk); +int gpio_set_output_clk(unsigned int gpio, int clk); + +int __gpio_read(unsigned int gpio); +int gpio_read(unsigned int gpio); + + + + + + + + +#endif diff --git a/include_lib/system/generic/includes.h b/include_lib/system/generic/includes.h new file mode 100644 index 0000000..a7ed74a --- /dev/null +++ b/include_lib/system/generic/includes.h @@ -0,0 +1,36 @@ +#ifndef GENERIC_INCLUDES_H +#define GENERIC_INCLUDES_H + + +#include "errno-base.h" +#include "typedef.h" +#include "ascii.h" +#include "atomic.h" +#include "ioctl.h" +#include "cpu.h" +#include "gpio.h" +#include "irq.h" +#include "jiffies.h" +#include "list.h" +#include "printf.h" +#include "rect.h" +#include "version.h" +#include "lbuf.h" +#include "lbuf_lite.h" +#include "circular_buf.h" +#include "index.h" +#include "debug_lite.h" + + + + + + + + + + + + + +#endif diff --git a/include_lib/system/generic/index.h b/include_lib/system/generic/index.h new file mode 100644 index 0000000..f2a38f6 --- /dev/null +++ b/include_lib/system/generic/index.h @@ -0,0 +1,22 @@ +#ifndef INDEX_H +#define INDEX_H + + +#include "typedef.h" + + +#define TABLE(t) t, ARRAY_SIZE(t) + + +int index_of_table8(u8 value, const u8 *table, int table_size); + +int index_of_table16(u16 value, const u16 *table, int table_size); + +int index_of_table32(u32 value, const u32 *table, int table_size); + + + + + + +#endif diff --git a/include_lib/system/generic/ioctl.h b/include_lib/system/generic/ioctl.h new file mode 100644 index 0000000..82ad8c7 --- /dev/null +++ b/include_lib/system/generic/ioctl.h @@ -0,0 +1,106 @@ +#ifndef _ASM_GENERIC_IOCTL_H +#define _ASM_GENERIC_IOCTL_H + +/* ioctl command encoding: 32 bits total, command in lower 16 bits, + * size of the parameter structure in the lower 14 bits of the + * upper 16 bits. + * Encoding the size of the parameter structure in the ioctl request + * is useful for catching programs compiled with old versions + * and to avoid overwriting user space outside the user buffer area. + * The highest 2 bits are reserved for indicating the ``access mode''. + * NOTE: This limits the max parameter size to 16kB -1 ! + */ + +/* + * The following is for compatibility across the various Linux + * platforms. The generic ioctl numbering scheme doesn't really enforce + * a type field. De facto, however, the top 8 bits of the lower 16 + * bits are indeed used as a type field, so we might just as well make + * this explicit here. Please be sure to use the decoding macros + * below from now on. + */ +#define _IOC_NRBITS 8 +#define _IOC_TYPEBITS 8 + +/* + * Let any architecture override either of the following before + * including this file. + */ + +#ifndef _IOC_SIZEBITS +# define _IOC_SIZEBITS 14 +#endif + +#ifndef _IOC_DIRBITS +# define _IOC_DIRBITS 2 +#endif + +#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) +#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) +#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) +#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) + +#define _IOC_NRSHIFT 0 +#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) +#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) +#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) + +/* + * Direction bits, which any architecture can choose to override + * before including this file. + */ + +#ifndef _IOC_NONE +# define _IOC_NONE 0U +#endif + +#ifndef _IOC_WRITE +# define _IOC_WRITE 1U +#endif + +#ifndef _IOC_READ +# define _IOC_READ 2U +#endif + +#define _IOC(dir,type,nr,size) \ + (((dir) << _IOC_DIRSHIFT) | \ + ((type) << _IOC_TYPESHIFT) | \ + ((nr) << _IOC_NRSHIFT) | \ + ((size) << _IOC_SIZESHIFT)) + +#ifdef __KERNEL__ +/* provoke compile error for invalid uses of size argument */ +extern unsigned int __invalid_size_argument_for_IOC; +#define _IOC_TYPECHECK(t) \ + ((sizeof(t) == sizeof(t[1]) && \ + sizeof(t) < (1 << _IOC_SIZEBITS)) ? \ + sizeof(t) : __invalid_size_argument_for_IOC) +#else +#define _IOC_TYPECHECK(t) (sizeof(t)) + +#endif + +/* used to create numbers */ +#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) +#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size))) +#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) +#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) +#define _IOR_BAD(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) +#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) +#define _IOWR_BAD(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) + +/* used to decode ioctl numbers.. */ +#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) +#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) +#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) +#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) + +/* ...and for the drivers/sound files... */ + +#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT) +#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT) +#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT) +#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT) +#define IOCSIZE_SHIFT (_IOC_SIZESHIFT) + +#endif /* _ASM_GENERIC_IOCTL_H */ diff --git a/include_lib/system/generic/irq.h b/include_lib/system/generic/irq.h new file mode 100644 index 0000000..10a0e66 --- /dev/null +++ b/include_lib/system/generic/irq.h @@ -0,0 +1,23 @@ +#ifndef __IRQ_H_ +#define __IRQ_H_ + + +#include "asm/irq.h" + + + + + + + + + + + + + + + + +#endif + diff --git a/include_lib/system/generic/jiffies.h b/include_lib/system/generic/jiffies.h new file mode 100644 index 0000000..93a169f --- /dev/null +++ b/include_lib/system/generic/jiffies.h @@ -0,0 +1,35 @@ +#ifndef JIFFIES_H +#define JIFFIES_H +/* timer interface */ +/* Parameters used to convert the timespec values: */ +#define HZ 100L +#define MSEC_PER_SEC 1000L +#define USEC_PER_MSEC 1000L +#define NSEC_PER_USEC 1000L +#define NSEC_PER_MSEC 1000000L +#define USEC_PER_SEC 1000000L +#define NSEC_PER_SEC 1000000000L +#define FSEC_PER_SEC 1000000000000000LL + + +#ifndef __ASSEMBLY__ +extern volatile unsigned long jiffies; +extern unsigned long jiffies_msec(); +extern unsigned long jiffies_half_msec(); +#endif + +#define JIFFIES_CIRCLE 0x7FFFFFF + +#define time_after(a,b) ((long)(b) - (long)(a) < 0) +#define time_before(a,b) time_after(b,a) + +extern unsigned char jiffies_unit; + +#define msecs_to_jiffies(msec) ((msec)/jiffies_unit) +#define jiffies_to_msecs(j) ((j)*jiffies_unit) + + + + +#endif + diff --git a/include_lib/system/generic/lbuf.h b/include_lib/system/generic/lbuf.h new file mode 100644 index 0000000..e613ba9 --- /dev/null +++ b/include_lib/system/generic/lbuf.h @@ -0,0 +1,262 @@ +#ifndef LBUF_H +#define LBUF_H + + +#include "typedef.h" +#include "list.h" +#include "system/spinlock.h" + +#ifndef CONFIG_LBUF_IN_MASKROM + +#define LBUF_DEBUG 0 + +struct lbuff_head { +#if LBUF_DEBUG + int magic_a; /*!< 测试验证变量*/ +#endif + struct list_head head; /*!< 指向hentry链表*/ + struct list_head free; /*!< 指向hfree链表*/ + spinlock_t lock; /*!< 混合自旋锁,单核是为开关临界区,多核是自旋锁.*/ + u8 align; /*!< 数据包字节对齐*/ + u16 priv_len; /*!< 数据包结构体的最小长度*/ + u32 total_size; /*!< 总大小*/ + u32 last_addr; /*!< 指向free链表中找到的足够长度的hfree结构体地址*/ + void *priv; + +#if LBUF_DEBUG + int magic_b; /*!< 测试验证变量*/ +#endif +}; + +struct lbuff_state { + u32 avaliable; /*!< 剩余空间的字节长度*/ + u32 fragment; /*!< lbuf内存碎片块数量*/ + u32 max_continue_len; /*!< 最大的剩余内存块的字节长度*/ + int num; /*!< 剩余内存块数量*/ +}; + +#else /* #ifndef CONFIG_LBUF_IN_MASKROM */ + + +/* ---------------------------------------------------------------------------- */ +/** + * @brief: + * @note: 以下结构体成员不可修改 + */ +/* ---------------------------------------------------------------------------- */ +struct lbuff_head { +#if 0 //LBUF_DEBUG + int magic_a; /*!< 测试验证变量*/ +#endif + struct list_head head; /*!< 指向hentry链表*/ + struct list_head free; /*!< 指向hfree链表*/ + spinlock_t lock; /*!< 混合自旋锁,单核是为开关临界区,多核是自旋锁.*/ + u8 align; /*!< 数据包字节对齐*/ + u16 priv_len; /*!< 数据包结构体的最小长度*/ + u32 total_size; /*!< 总大小*/ + u32 last_addr; /*!< 指向free链表中找到的足够长度的hfree结构体地址*/ + void *priv; + +#if 0 //LBUF_DEBUG + int magic_b; /*!< 测试验证变量*/ +#endif +}; + +struct lbuff_state { + u32 avaliable; /*!< 剩余空间的字节长度*/ + u32 fragment; /*!< lbuf内存碎片块数量*/ + u32 max_continue_len; /*!< 最大的剩余内存块的字节长度*/ + int num; /*!< 剩余内存块数量*/ +}; + +#endif /* #ifndef CONFIG_LBUF_IN_MASKROM */ + + +/* --------------------------------------------------------------------------*/ +/** + * @brief 链表buf初始化 + * + * @param [in] buf 需要lbuf进行管理的内存 + * @param [in] len 内存长度 + * @param [in] align 输入对管理的内存进行对齐的参数,避免后续使用因地址不对齐产生碎片 + * @param [in] priv_head_len 要管理的一个数据包结构体的最小的长度 + * + * @return lbuf操作句柄 + */ +/* --------------------------------------------------------------------------*/ +struct lbuff_head *lbuf_init(void *buf, u32 len, int align, int priv_head_len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 分配内存空间进行存储数据包 + * + * @param [in] head lbuf操作句柄 + * @param [in] len 需要存入的数据包的长度 + * + * @return 成功则返回进行存储数据包的地址,调用时候需要用户把该块内存的类型初始化为数据包结构体的类型。失败则返回NULL。 + */ +/* --------------------------------------------------------------------------*/ +void *lbuf_alloc(struct lbuff_head *head, u32 len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 重新分配lbuf_alloc()返回用于存储数据包的lbuf空间 + * + * @param [in] lbuf lbuf_alloc()返回用于存储数据包的地址 + * @param [in] size 需重新分配的空间的字节长度.注:size的大小只能比lbuf_alloc()中的len小,即只能重新分配更小的lbuf空间,不能扩大空间. + * + * @return 重新分配后用于存储数据包的地址。失败则返回空指针。注:重新分配最好使用lbuf_real_size()获取lbuf空间的长度确认是否分配成功 + */ +/* --------------------------------------------------------------------------*/ +void *lbuf_realloc(void *lbuf, int size); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 判断lbuf空间内的内容是否为空 + * + * @param [in] head lbuf操作句柄 + * + * @return 返回1则为空,0则不为空 + */ +/* --------------------------------------------------------------------------*/ +int lbuf_empty(struct lbuff_head *head); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 清空lbuf空间内进行已经分配给数据包的空间 + * + * @param [in] head lbuf操作句柄 + */ +/* --------------------------------------------------------------------------*/ +void lbuf_clear(struct lbuff_head *head); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 把数据包写入分配好的lbuf区域 + * + * @param [in] lbuf lbuf_alloc()返回用于存储数据包的地址 + * @param [in] channel_map 选择映射到哪个通道,最多8个通道,使用位映射的方式进行通道对应. + */ +/* --------------------------------------------------------------------------*/ +void lbuf_push(void *lbuf, u8 channel_map); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 读取对应的通道映射的lbuf区域存储的内容 + * + * @param [in] head lbuf操作句柄 + * @param [in] channel 需要读取的通道值,一般使用BIT(n),n为需要读取的通道 + * + * @return 成功则返回存储对应的通道映射的数据包的地址 + */ +/* --------------------------------------------------------------------------*/ +void *lbuf_pop(struct lbuff_head *head, u8 channel); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 释放存储数据包的lbuf空间 + * + * @param [in] lbuf lbuf_alloc()返回用于存储数据包的地址 + * + * @return 0则释放失败,存在地址越界操作或者通道还没有被读完,ref-1,读完后才能完全释放。1则释放成功。 + */ +/* --------------------------------------------------------------------------*/ +int lbuf_free(void *lbuf); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 用于调试,检查是否可以释放存储数据包的lbuf空间 + * + * @param [in] lbuf lbuf_alloc()返回用于存储数据包的地址 + * @param [in] rets 调用lbuf_free_check()函数的返回地址rets,取值可参考lbuf_free() + */ +/* --------------------------------------------------------------------------*/ +void lbuf_free_check(void *lbuf, u32 rets); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 返回可分配的用来存储数据包的最大lbuf内存空间 + * + * @param [in] head lbuf操作句柄 + * + * @return 可分配的最大lbuf内存空间的字节长度 + */ +/* --------------------------------------------------------------------------*/ +u32 lbuf_free_space(struct lbuff_head *head); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 获取lbuf空间的状态 + * + * @param [in] head lbuf操作句柄 + * @param [out] state lbuff_state结构体 + */ +/* --------------------------------------------------------------------------*/ +void lbuf_state(struct lbuff_head *head, struct lbuff_state *state); + +/* --------------------------------------------------------------------------*/ +/** + * @brief lbuf信息打印 + * + * @param [in] head lbuf操作句柄 + */ +/* --------------------------------------------------------------------------*/ +void lbuf_dump(struct lbuff_head *head); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 获取已经存入lbuf空间的数据包的数量 + * + * @param [in] head lbuf操作句柄 + * + * @return lbuf存储的数据包的数量 + */ +/* --------------------------------------------------------------------------*/ +int lbuf_traversal(struct lbuff_head *head); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 返回lbuf空间还可以被写入size大小数据包的数量 + * + * @param [in] head lbuf操作句柄 + * @param [in] size 欲检测写入数据包的大小 + * + * @return 可以写入的数量 + */ +/* --------------------------------------------------------------------------*/ +int lbuf_avaliable(struct lbuff_head *head, int size); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 返回给数据包分配的内存空间的大小 + * + * @param [in] lbuf lbuf_alloc()返回用于存储数据包的地址 + * + * @return 实际占用空间的字节长度 + */ +/* --------------------------------------------------------------------------*/ +int lbuf_real_size(void *lbuf); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 计算lbuf空间剩下多少剩余空间 + * + * @param [in] head lbuf操作句柄 + * + * @return 剩余空间的字节长度 + */ +/* --------------------------------------------------------------------------*/ +int lbuf_remain_space(struct lbuff_head *head); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 需要被重复释放的次数+1 + * + * @param [in] lbuf lbuf_alloc()返回用于存储数据包的地址 + */ +/* --------------------------------------------------------------------------*/ +void lbuf_inc_ref(void *lbuf); + +#endif + + diff --git a/include_lib/system/generic/lbuf_lite.h b/include_lib/system/generic/lbuf_lite.h new file mode 100644 index 0000000..19628a5 --- /dev/null +++ b/include_lib/system/generic/lbuf_lite.h @@ -0,0 +1,50 @@ +#ifndef LBUF_LITE_H +#define LBUF_LITE_H + + +#include "typedef.h" +#include "list.h" +#include "system/spinlock.h" + + +struct lbuff_lite_head { + int magic_a; + struct list_head head; + struct list_head free; + spinlock_t lock; + u8 align; + u16 priv_len; + u32 total_size; + u32 last_addr; + void *priv; + int magic_b; +}; + +struct lbuff_lite_state { + u32 avaliable; + u32 fragment; + u32 max_continue_len; + int num; +}; + + + +struct lbuff_lite_head *lbuf_lite_init(void *buf, u32 len, int align, int priv_head_len); + +void *lbuf_lite_alloc(struct lbuff_lite_head *head, u32 len); + +void *lbuf_lite_realloc(void *lbuf, int size); + +void lbuf_lite_free(void *lbuf); + +u32 lbuf_lite_free_space(struct lbuff_lite_head *head); + +void lbuf_lite_state(struct lbuff_lite_head *head, struct lbuff_lite_state *state); + +void lbuf_lite_dump(struct lbuff_lite_head *head); + +int lbuf_lite_avaliable(struct lbuff_lite_head *head, int size); + +#endif + + diff --git a/include_lib/system/generic/list.h b/include_lib/system/generic/list.h new file mode 100644 index 0000000..bd16b0c --- /dev/null +++ b/include_lib/system/generic/list.h @@ -0,0 +1,291 @@ +#ifndef LIST_H +#define LIST_H + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#ifdef list_offsetof +#undef list_offsetof +#endif +#ifdef container_of +#undef container_of +#endif + +#define list_offsetof(type, memb) \ + ((unsigned long)(&((type *)0)->memb)) + +#define container_of(ptr, type, memb) \ + ((type *)((char *)(ptr) - list_offsetof(type, memb))) + + +struct list_head { + struct list_head *next, *prev; +}; + + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +/* REF_LIST: spi.c */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + + +#define list_for_each_entry_reverse_safe(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +/* REF_LIST: spi.c */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *_new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = _new; + _new->next = next; + _new->prev = prev; + prev->next = _new; +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +/* REF_LIST: spi.c */ +static inline void list_add_tail(struct list_head *_new, struct list_head *head) +{ + __list_add(_new, head->prev, head); +} + +static inline void __list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +static inline void __list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +/* REF_LIST: spi.c */ +static inline void list_del(struct list_head *entry) //修改过的list_del,这里与list_del_init一样 +{ + __list_del(entry->prev, entry->next); + entry->next = entry; + entry->prev = entry; +} + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +static inline void list_del_init(struct list_head *entry) +{ + __list_del_entry(entry); + INIT_LIST_HEAD(entry); +} +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +static inline int list_is_head(struct list_head *head, struct list_head *member) +{ + return head->next == member; +} + +#if 0 +static inline void __list_splice(const struct list_head *list, + struct list_head *prev, + struct list_head *next) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + + first->prev = prev; + prev->next = first; + + last->next = next; + next->prev = last; +} + +/** + * list_splice_tail_init - join two lists and reinitialise the emptied list + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * Each of the lists is a queue. + * The list at @list is reinitialised + */ +static inline void list_splice_tail_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head->prev, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_is_singular - tests whether a list has just one entry. + * @head: the list to test. + */ +static inline int list_is_singular(const struct list_head *head) +{ + return !list_empty(head) && (head->next == head->prev); +} + +/** + * list_splice_tail - join two lists, each list being a queue + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice_tail(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head->prev, head); + } +} +#endif + +#define list_for_each_entry_from(pos, head, member) \ + for (; &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +#define list_for_each_entry_from_reverse(pos, head, member) \ + for (; &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +#endif + diff --git a/include_lib/system/generic/log.h b/include_lib/system/generic/log.h new file mode 100644 index 0000000..c3d3e41 --- /dev/null +++ b/include_lib/system/generic/log.h @@ -0,0 +1,127 @@ +#ifndef __LOG_H +#define __LOG_H + + +#include "system/generic/printf.h" + +#define __LOG_VERB 0 +#define __LOG_DEBUG 1 +#define __LOG_INFO 2 +#define __LOG_WARN 3 +#define __LOG_ERROR 4 +#define __LOG_CHAR 5 + +struct logbuf { + u16 len; + u16 buf_len; + char buf[0]; +}; + +#define __LOG_ENABLE + +#ifndef __LOG_LEVEL +#define __LOG_LEVEL 0 +#endif + +#ifdef CONFIG_RELEASE_ENABLE +#undef __LOG_LEVEL +#define __LOG_LEVEL 0xff +#endif + +#if __LOG_LEVEL > __LOG_VERB +#define log_v(...) do {} while (0) +#elif defined __LOG_ENABLE +#define log_v(...) log_print(__LOG_VERB, NULL, __VA_ARGS__) +#else +#define log_v(...) printf(__VA_ARGS__) +#endif + + + +#if __LOG_LEVEL > __LOG_DEBUG +#define log_d(...) do {} while (0) +#elif defined __LOG_ENABLE +#define log_d(...) log_print(__LOG_DEBUG, NULL, __VA_ARGS__); +#else +#define log_d(...) printf(__VA_ARGS__) +#endif + +#if __LOG_LEVEL > __LOG_INFO +#define log_i(...) do {} while (0) +#elif defined __LOG_ENABLE +#define log_i(...) log_print(__LOG_INFO, NULL, __VA_ARGS__); +#else +#define log_i(...) printf(__VA_ARGS__) +#endif + +#if __LOG_LEVEL > __LOG_WARN +#define log_w(...) do {} while (0) +#elif defined __LOG_ENABLE +#define log_w(...) log_print(__LOG_WARN, NULL, __VA_ARGS__); +#else +#define log_w(...) printf(__VA_ARGS__) +#endif + +#if __LOG_LEVEL > __LOG_ERROR +#define log_e(...) do {} while (0) +#elif defined __LOG_ENABLE +#define log_e(...) log_print(__LOG_ERROR, NULL, __VA_ARGS__); +#else +#define log_e(...) printf(__VA_ARGS__) +#endif + +#if __LOG_LEVEL > __LOG_CHAR +#define log_c(x) do {} while (0) +#elif defined __LOG_ENABLE +#define log_c(x) putchar(x) +#else +#define log_c(x) +#endif + +#define r_printf(x, ...) log_i("\e[31m\e[1m" x "\e[0m", ## __VA_ARGS__) +#define g_printf(x, ...) log_i("\e[32m\e[1m" x "\e[0m", ## __VA_ARGS__) +#define y_printf(x, ...) log_i("\e[33m\e[1m" x "\e[0m", ## __VA_ARGS__) +#define r_f_printf(x, ...) log_i("\e[31m\e[5m\e[1m" x "\e[0m", ## __VA_ARGS__) +#define g_f_printf(x, ...) log_i("\e[32m\e[5m\e[1m" x "\e[0m", ## __VA_ARGS__) +#define y_f_printf(x, ...) log_i("\e[33m\e[5m\e[1m" x "\e[0m", ## __VA_ARGS__) + +#ifndef __LOG_ENABLE +#define log_dump(a, b) do {} while(0) +#define log_putchar() do {} while(0) +#define log_early_init(a) do {} while(0) +#define log_level(a) do {} while(0) +#else + +int log_output_lock(); + +void log_output_unlock(); + +void log_print_time(); + +void log_early_init(int buf_size); + +void log_level(int level); + +void log_print(int level, const char *tag, const char *format, ...); + +void log_dump(const u8 *buf, int len); + +struct logbuf *log_output_start(int len); + +void log_output_end(struct logbuf *); + +void log_putchar(struct logbuf *lb, char c); + +void log_put_u8hex(struct logbuf *lb, unsigned char dat); + +void log_putbyte(char); + +void log_set_time_offset(int offset); + +int log_get_time_offset(); + +#endif + +void log_flush(); + +#endif diff --git a/include_lib/system/generic/printf.h b/include_lib/system/generic/printf.h new file mode 100644 index 0000000..e232313 --- /dev/null +++ b/include_lib/system/generic/printf.h @@ -0,0 +1,28 @@ +#ifndef _PRINTF_H_ +#define _PRINTF_H_ +#define line_inf printf("%s %s %d \r\n" ,__FILE__, __func__ , __LINE__) ; +#include +#include "typedef.h" +//#define NOFLOAT + +extern int putchar(int a); +extern int puts(const char *out); +void put_u4hex(unsigned char dat); +void put_u8hex(unsigned char dat); +void put_u16hex(unsigned short dat); +void put_u32hex(unsigned int dat); +void put_buf(const u8 *buf, int len); +int printf(const char *format, ...); +int assert_printf(const char *format, ...); +int sprintf(char *out, const char *format, ...); +int vprintf(const char *fmt, __builtin_va_list va); +int vsnprintf(char *, unsigned long, const char *, __builtin_va_list); +int snprintf(char *buf, unsigned long size, const char *fmt, ...); +int print(char **out, char *end, const char *format, va_list args); +//int snprintf(char *, unsigned long, const char *, ...); + +int sscanf(const char *buf, const char *fmt, ...); //BUG: 多个参数? 最后又空格? + +//int perror(const char *fmt, ...); + +#endif diff --git a/include_lib/system/generic/rect.h b/include_lib/system/generic/rect.h new file mode 100644 index 0000000..d8de90e --- /dev/null +++ b/include_lib/system/generic/rect.h @@ -0,0 +1,134 @@ +#ifndef RECT_H +#define RECT_H + +#include "typedef.h" + + +#define AT_UI_RAM AT(.ui_ram) + +struct position { + int x; + int y; +}; + +struct rect { + int left; + int top; + int width; + int height; +}; + +#define rect_left(r) ((r)->left) +#define rect_top(r) ((r)->top) +#define rect_right(r) ((r)->left + (r)->width) +#define rect_bottom(r) ((r)->top + (r)->height) + +//#define rect_height(v) ((v)->bottom - (v)->top) +//#define rect_width(v) ((v)->right - (v)->left) + + +static inline int in_rect(const struct rect *rect, struct position *pos) +{ + if (rect->left <= pos->x && rect_right(rect) > pos->x) { + if (rect->top <= pos->y && rect_bottom(rect) > pos->y) { + return true; + } + } + return false; +} + +AT_UI_RAM +static inline bool get_rect_cover(const struct rect *a, const struct rect *b, struct rect *c) +{ + int right, bottom; + + c->top = MAX(a->top, b->top); + c->left = MAX(a->left, b->left); + right = MIN(rect_right(a), rect_right(b)); + bottom = MIN(rect_bottom(a), rect_bottom(b)); + + if ((c->top < bottom) && (c->left < right)) { + c->width = right - c->left; + c->height = bottom - c->top; + return true; + } + + return false; +} + + +static inline bool get_rect_nocover_l(const struct rect *a, const struct rect *b, struct rect *c) +{ + int right, bottom; + + c->left = MIN(rect_left(a), rect_left(b)); + c->top = MIN(rect_top(a), rect_top(b)); + right = MAX(rect_left(a), rect_left(b)); + bottom = MAX(rect_bottom(a), rect_bottom(b)); + + if ((c->top < bottom) && (c->left < right)) { + c->width = right - c->left; + c->height = bottom - c->top; + return true; + } + + return false; +} + + +static inline bool get_rect_nocover_r(const struct rect *a, const struct rect *b, struct rect *c) +{ + int right, bottom; + + c->left = MIN(rect_right(a), rect_right(b)); + c->top = MIN(rect_top(a), rect_top(b)); + right = MAX(rect_right(a), rect_right(b)); + bottom = MAX(rect_bottom(a), rect_bottom(b)); + + if ((c->top < bottom) && (c->left < right)) { + c->width = right - c->left; + c->height = bottom - c->top; + return true; + } + + return false; +} + +static inline bool get_rect_nocover_t(const struct rect *a, const struct rect *b, struct rect *c) +{ + int right, bottom; + + c->left = MIN(rect_left(a), rect_left(b)); + c->top = MIN(rect_top(a), rect_top(b)); + right = MAX(rect_right(a), rect_right(b)); + bottom = MAX(rect_top(a), rect_top(b)); + + if ((c->top < bottom) && (c->left < right)) { + c->width = right - c->left; + c->height = bottom - c->top; + return true; + } + + return false; +} + +static inline bool get_rect_nocover_b(const struct rect *a, const struct rect *b, struct rect *c) +{ + int right, bottom; + + c->left = MIN(rect_left(a), rect_left(b)); + c->top = MIN(rect_bottom(a), rect_bottom(b)); + right = MAX(rect_right(a), rect_right(b)); + bottom = MAX(rect_bottom(a), rect_bottom(b)); + + if ((c->top < bottom) && (c->left < right)) { + c->width = right - c->left; + c->height = bottom - c->top; + return true; + } + + return false; +} + +#endif + diff --git a/include_lib/system/generic/typedef.h b/include_lib/system/generic/typedef.h new file mode 100644 index 0000000..2caed2f --- /dev/null +++ b/include_lib/system/generic/typedef.h @@ -0,0 +1,167 @@ +/************************************************************* +File: typedef.h +Author:Juntham +Discriptor: + 数据类型重定义 +Version: +Date: +*************************************************************/ +#ifndef _typedef_h_ +#define _typedef_h_ + + +#include "asm/cpu.h" + + +#if defined(__GNUC__) + +///>24)|((x>>8)&0xff00)|(x<<24)|((x&0xff00)<<8)) +//#define ntoh(x) (u16)((x>>8&0x00ff)|x<<8&0xff00) + +//#define ntohl(x) (u32)((((u32)(x))>>24) | ((((u32)(x))>>8)&0xff00) | (((u32)(x))<<24) | ((((u32)(x))&0xff00)<<8)) +//#define ntoh(x) (u16)((((u32)(x))>>8&0x00ff) | (((u32)(x))<<8&0xff00)) + +//#define NTOH(x) (x) = ntoh(x) +//#define NTOHL(x) (x) = ntohl(x) +#define LD_WORD(ptr) (u16)(*(u16*)(u8*)(ptr)) +#define LD_DWORD(ptr) (u32)(*(u32*)(u8*)(ptr)) +#define ST_WORD(ptr,val) *(u16*)(u8*)(ptr)=(u16)(val) +#define ST_DWORD(ptr,val) *(u32*)(u8*)(ptr)=(u32)(val) +#else +#define ntohl(x) (x) +#define ntoh(x) (x) +#define NTOH(x) (x) = ntoh(x) +#define NTOHL(x) (x) = ntohl(x) +#endif + + + +#undef FALSE +#define FALSE 0 + +#undef TRUE +#define TRUE 1 + +#define false 0 +#define true 1 + +#ifndef NULL +#define NULL (void *)0 +#endif + + + +#define BIT(n) (1UL << (n)) +#define BitSET(REG,POS) ((REG) |= (1L << (POS))) +#define BitCLR(REG,POS) ((REG) &= (~(1L<< (POS)))) +#define BitXOR(REG,POS) ((REG) ^= (~(1L << (POS)))) +#define BitCHK_1(REG,POS) (((REG) & (1L << (POS))) == (1L << (POS))) +#define BitCHK_0(REG,POS) (((REG) & (1L << (POS))) == 0x00) +#define testBit(REG,POS) ((REG) & (1L << (POS))) + +#define clrBit(x,y) (x) &= ~(1L << (y)) +#define setBit(x,y) (x) |= (1L << (y)) + + +#define readb(addr) *((volatile unsigned char*)(addr)) +#define readw(addr) *((volatile unsigned short *)(addr)) +#define readl(addr) *((volatile unsigned long*)(addr)) + +#define writeb(addr, val) *((volatile unsigned char*)(addr)) = (u8)(val) +#define writew(addr, val) *((volatile unsigned short *)(addr)) = (u16)(val) +#define writel(addr, val) *((volatile unsigned long*)(addr)) = (u32)(val) + +#define ALIGN_4BYTE(size) ((size+3)&0xfffffffc) + +#if CPU_ENDIAN == BIG_ENDIAN +#define __cpu_u16(lo, hi) ((lo)|((hi)<<8)) +#elif CPU_ENDIAN == LITTLE_ENDIAN +#define __cpu_u16(lo, hi) ((hi)|((lo)<<8)) +#else +#error "undefine cpu eadin" +#endif + + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + + +#define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0])) + + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#define SFR(sfr, start, len, dat) \ + (sfr = (sfr & ~((~(0xffffffff << (len))) << (start))) | \ + (((dat) & (~(0xffffffff << (len)))) << (start))) + + +#include "generic/errno-base.h" +#include "string.h" +#include "strings.h" +#include "system/malloc.h" + + +#ifdef offsetof +#undef offsetof +#endif + +#ifdef container_of +#undef container_of +#endif + +#define offsetof(type, memb) \ + ((unsigned long)(&((type *)0)->memb)) + +#define container_of(ptr, type, memb) \ + ((type *)((char *)(ptr) - offsetof(type, memb))) + +void delay(unsigned int); + +void delay_us(unsigned int); + + +#endif + + + diff --git a/include_lib/system/generic/version.h b/include_lib/system/generic/version.h new file mode 100644 index 0000000..58096a6 --- /dev/null +++ b/include_lib/system/generic/version.h @@ -0,0 +1,133 @@ +#ifndef VERSION_H +#define VERSION_H + +#include "typedef.h" + + +typedef int (*version_t)(int); + + +//定义模块的版本号,由主版本号和次版本号组成 +//如果两个模块的主版本号相同即表示兼容 +#define VERSION(major, minor) (((major)<<8) | (minor)) + +#define MAJOR(v) ((v) >> 16) +#define MINOR(v) (((v) >> 8) & 0xff) + +#define version_match(module_a, module_b) \ + ({ \ + extern int module_a##_version(int ); \ + extern int module_b##_version(int ); \ + int version_a = module_a##_version(0); \ + int version_b = module_b##_version(0); \ + MAJOR(version_a) == MAJOR(version_b);\ + }) + + + + + +#define __MODULE_VERSION_EXPORT_BEGIN(module, version) \ + int module##_version(int prt) \ + { \ + if (prt) { \ + log_i(#module": %d.%d.%d build at: %s\n", (version)>>16, \ + ((version) >> 8) & 0xff, (version) & 0xff, __DATE__); \ + } \ + +#define __MODULE_VERSION_EXPORT_END(module, version) \ + return version; \ + } \ + const version_t __version_##module \ + __attribute__((section(".lib_version"),used)) = module##_version + +#define __MODULE_VERSION_EXPORT(module, version) \ + __MODULE_VERSION_EXPORT_BEGIN(module, version) \ + __MODULE_VERSION_EXPORT_END(module, version); + + +#define __MODULE_VERSION_EXPORT_SECTION(module, version, section) \ + __MODULE_VERSION_EXPORT_BEGIN(module, version) \ + (void *)§ion; \ + __MODULE_VERSION_EXPORT_END(module, version) + +#define __MODULE_DEPEND_BEGIN(module) \ + int module##_version_check() \ + { \ + + +#define _MODULE_DEPEND_BEGIN(module) \ + __MODULE_DEPEND_BEGIN(module) + + +#define __VERSION_CHECK(module, version) \ + do { \ + int module##_version(int prt); \ + int v = module##_version(0); \ + if (MAJOR(version) != MAJOR(v) || MINOR(version) > MINOR(v)) { \ + log_i("=======version not match=======\n"); \ + module##_version(1); \ + log_i("==================================\n"); \ + while(1); \ + } \ + } while(0) +/*-------------------上面的宏请勿调用------------------------------------*/ + + + + + + +//定义当前模块的版本检测函数 +#define MODULE_VERSION_EXPORT(module, version) \ + __MODULE_VERSION_EXPORT(module, version) + +#define MODULE_VERSION_EXPORT_SECTION(module, version, section) \ + __MODULE_VERSION_EXPORT_SECTION(module, version, section) + +#define MODULE_VERSION_EXPORT_BEGIN(module, version) \ + __MODULE_VERSION_EXPORT_BEGIN(module, version) + +#define MODULE_VERSION_EXPORT_END(module, version) \ + __MODULE_VERSION_EXPORT_END(module, version) + +//以下3个宏定义当前模块依赖的其它模块列表 +#define MODULE_DEPEND_BEGIN() \ + _MODULE_DEPEND_BEGIN(THIS_MODULE) + +#define MODULE_DEPEND(module_d, version) \ + __VERSION_CHECK(module_d, version) + +#define MODULE_DEPEND_END() \ + return 0; \ + } + + +#define VERSION_CHECK(module, version) \ + __VERSION_CHECK(module, version) + + +//通过调用版本检测函数使的模块的代码能够被链接 +#define load_module(module) \ + ({ \ + int ret; \ + extern int module##_version_check(); \ + ret = module##_version_check();\ + ret; \ + }) + +extern version_t lib_version_begin[], lib_version_end[]; + +#define lib_version_check() \ + do { \ + version_t *version; \ + log_i("=========version check===========\n"); \ + for (version = lib_version_begin; version < lib_version_end; version++) { \ + (*version)(1); \ + }; \ + log_i("==================================\n\n"); \ + } while (0) + + +#endif + diff --git a/include_lib/system/includes.h b/include_lib/system/includes.h new file mode 100644 index 0000000..c6a77f2 --- /dev/null +++ b/include_lib/system/includes.h @@ -0,0 +1,30 @@ +#ifndef SYS_INCLUDES_H +#define SYS_INCLUDES_H + + +#include "init.h" +#include "event.h" +#include "malloc.h" +#include "spinlock.h" +#include "task.h" +#include "timer.h" +#include "wait.h" +#include "app_core.h" +#include "app_msg.h" +#include "database.h" +#include "fs/fs.h" +#include "power_manage.h" +#include "syscfg_id.h" +#include "bank_switch.h" + + + +#include "generic/includes.h" +#include "device/includes.h" +#include "asm/includes.h" +#include "device/sdio_host_init.h" + + + +#endif + diff --git a/include_lib/system/init.h b/include_lib/system/init.h new file mode 100644 index 0000000..da90c8a --- /dev/null +++ b/include_lib/system/init.h @@ -0,0 +1,49 @@ +#ifndef SYS_INIT_H +#define SYS_INIT_H + + + + + + + +typedef int (*initcall_t)(void); + +#define __initcall(fn) \ + const initcall_t __initcall_##fn sec(.initcall) = fn + +#define early_initcall(fn) \ + const initcall_t __initcall_##fn sec(.early.initcall) = fn + + +#define late_initcall(fn) \ + const initcall_t __initcall_##fn sec(.late.initcall) = fn + + +#define platform_initcall(fn) \ + const initcall_t __initcall_##fn sec(.platform.initcall) = fn + + +#define module_initcall(fn) \ + const initcall_t __initcall_##fn sec(.module.initcall) = fn + + + + +#define __do_initcall(prefix) \ + do { \ + initcall_t *init; \ + extern initcall_t prefix##_begin[], prefix##_end[]; \ + for (init=prefix##_begin; init>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef INC_FREERTOS_H +#define INC_FREERTOS_H + +/* + * Include the generic headers required for the FreeRTOS port being used. + */ +//#include + +/* + * If stdint.h cannot be located then: + * + If using GCC ensure the -nostdint options is *not* being used. + * + Ensure the project's include path includes the directory in which your + * compiler stores stdint.h. + * + Set any compiler options necessary for it to support C99, as technically + * stdint.h is only mandatory with C99 (FreeRTOS does not require C99 in any + * other way). + * + The FreeRTOS download includes a simple stdint.h definition that can be + * used in cases where none is provided by the compiler. The files only + * contains the typedefs required to build FreeRTOS. Read the instructions + * in FreeRTOS/source/stdint.readme for more information. + */ +//#include /* READ COMMENT ABOVE. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Application specific configuration options. */ +#include "FreeRTOSConfig.h" + +/* Basic FreeRTOS definitions. */ +#include "projdefs.h" + +/* Definitions specific to the port being used. */ +#include "portable.h" + +/* Must be defaulted before configUSE_NEWLIB_REENTRANT is used below. */ +#ifndef configUSE_NEWLIB_REENTRANT +#define configUSE_NEWLIB_REENTRANT 0 +#endif + +/* Required if struct _reent is used. */ +#if ( configUSE_NEWLIB_REENTRANT == 1 ) +#include +#endif +/* + * Check all the required application specific macros have been defined. + * These macros are application specific and (as downloaded) are defined + * within FreeRTOSConfig.h. + */ + +#ifndef configMINIMAL_STACK_SIZE +#error Missing definition: configMINIMAL_STACK_SIZE must be defined in FreeRTOSConfig.h. configMINIMAL_STACK_SIZE defines the size (in words) of the stack allocated to the idle task. Refer to the demo project provided for your port for a suitable value. +#endif + +#ifndef configMAX_PRIORITIES +#error Missing definition: configMAX_PRIORITIES must be defined in FreeRTOSConfig.h. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configUSE_PREEMPTION +#error Missing definition: configUSE_PREEMPTION must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configUSE_IDLE_HOOK +#error Missing definition: configUSE_IDLE_HOOK must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configUSE_TICK_HOOK +#error Missing definition: configUSE_TICK_HOOK must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configUSE_16_BIT_TICKS +#error Missing definition: configUSE_16_BIT_TICKS must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configMAX_PRIORITIES +#error configMAX_PRIORITIES must be defined to be greater than or equal to 1. +#endif + +#ifndef configUSE_CO_ROUTINES +#define configUSE_CO_ROUTINES 0 +#endif + +#ifndef INCLUDE_vTaskPrioritySet +#define INCLUDE_vTaskPrioritySet 0 +#endif + +#ifndef INCLUDE_uxTaskPriorityGet +#define INCLUDE_uxTaskPriorityGet 0 +#endif + +#ifndef INCLUDE_vTaskDelete +#define INCLUDE_vTaskDelete 0 +#endif + +#ifndef INCLUDE_vTaskSuspend +#define INCLUDE_vTaskSuspend 0 +#endif + +#ifndef INCLUDE_vTaskDelayUntil +#define INCLUDE_vTaskDelayUntil 0 +#endif + +#ifndef INCLUDE_vTaskDelay +#define INCLUDE_vTaskDelay 0 +#endif + +#ifndef INCLUDE_xTaskGetIdleTaskHandle +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#endif + +#ifndef INCLUDE_xTaskAbortDelay +#define INCLUDE_xTaskAbortDelay 0 +#endif + +#ifndef INCLUDE_xQueueGetMutexHolder +#define INCLUDE_xQueueGetMutexHolder 0 +#endif + +#ifndef INCLUDE_xSemaphoreGetMutexHolder +#define INCLUDE_xSemaphoreGetMutexHolder INCLUDE_xQueueGetMutexHolder +#endif + +#ifndef INCLUDE_xTaskGetHandle +#define INCLUDE_xTaskGetHandle 0 +#endif + +#ifndef INCLUDE_uxTaskGetStackHighWaterMark +#define INCLUDE_uxTaskGetStackHighWaterMark 0 +#endif + +#ifndef INCLUDE_eTaskGetState +#define INCLUDE_eTaskGetState 0 +#endif + +#ifndef INCLUDE_xTaskResumeFromISR +#define INCLUDE_xTaskResumeFromISR 1 +#endif + +#ifndef INCLUDE_xTimerPendFunctionCall +#define INCLUDE_xTimerPendFunctionCall 0 +#endif + +#ifndef INCLUDE_xTaskGetSchedulerState +#define INCLUDE_xTaskGetSchedulerState 0 +#endif + +#ifndef INCLUDE_xTaskGetCurrentTaskHandle +#define INCLUDE_xTaskGetCurrentTaskHandle 0 +#endif + +#if configUSE_CO_ROUTINES != 0 +#ifndef configMAX_CO_ROUTINE_PRIORITIES +#error configMAX_CO_ROUTINE_PRIORITIES must be greater than or equal to 1. +#endif +#endif + +#ifndef configUSE_DAEMON_TASK_STARTUP_HOOK +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 +#endif + +#ifndef configUSE_APPLICATION_TASK_TAG +#define configUSE_APPLICATION_TASK_TAG 0 +#endif + +#ifndef configNUM_THREAD_LOCAL_STORAGE_POINTERS +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 +#endif + +#ifndef configUSE_RECURSIVE_MUTEXES +#define configUSE_RECURSIVE_MUTEXES 0 +#endif + +#ifndef configUSE_MUTEXES +#define configUSE_MUTEXES 0 +#endif + +#ifndef configUSE_TIMERS +#define configUSE_TIMERS 0 +#endif + +#ifndef configUSE_COUNTING_SEMAPHORES +#define configUSE_COUNTING_SEMAPHORES 0 +#endif + +#ifndef configUSE_ALTERNATIVE_API +#define configUSE_ALTERNATIVE_API 0 +#endif + +#ifndef portCRITICAL_NESTING_IN_TCB +#define portCRITICAL_NESTING_IN_TCB 0 +#endif + +#ifndef configMAX_TASK_NAME_LEN +#define configMAX_TASK_NAME_LEN 16 +#endif + +#ifndef configIDLE_SHOULD_YIELD +#define configIDLE_SHOULD_YIELD 1 +#endif + +#if configMAX_TASK_NAME_LEN < 1 +#error configMAX_TASK_NAME_LEN must be set to a minimum of 1 in FreeRTOSConfig.h +#endif + +#ifndef configASSERT +#define configASSERT( x ) +#define configASSERT_DEFINED 0 +#else +#define configASSERT_DEFINED 1 +#endif + +/* The timers module relies on xTaskGetSchedulerState(). */ +#if configUSE_TIMERS == 1 + +#ifndef configTIMER_TASK_PRIORITY +#error If configUSE_TIMERS is set to 1 then configTIMER_TASK_PRIORITY must also be defined. +#endif /* configTIMER_TASK_PRIORITY */ + +#ifndef configTIMER_QUEUE_LENGTH +#error If configUSE_TIMERS is set to 1 then configTIMER_QUEUE_LENGTH must also be defined. +#endif /* configTIMER_QUEUE_LENGTH */ + +#ifndef configTIMER_TASK_STACK_DEPTH +#error If configUSE_TIMERS is set to 1 then configTIMER_TASK_STACK_DEPTH must also be defined. +#endif /* configTIMER_TASK_STACK_DEPTH */ + +#endif /* configUSE_TIMERS */ + +#ifndef portSET_INTERRUPT_MASK_FROM_ISR +#define portSET_INTERRUPT_MASK_FROM_ISR() 0 +#endif + +#ifndef portCLEAR_INTERRUPT_MASK_FROM_ISR +#define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedStatusValue ) ( void ) uxSavedStatusValue +#endif + +#ifndef portCLEAN_UP_TCB +#define portCLEAN_UP_TCB( pxTCB ) ( void ) pxTCB +#endif + +#ifndef portPRE_TASK_DELETE_HOOK +#define portPRE_TASK_DELETE_HOOK( pvTaskToDelete, pxYieldPending ) +#endif + +#ifndef portSETUP_TCB +#define portSETUP_TCB( pxTCB ) ( void ) pxTCB +#endif + +#ifndef configQUEUE_REGISTRY_SIZE +#define configQUEUE_REGISTRY_SIZE 0U +#endif + +#if ( configQUEUE_REGISTRY_SIZE < 1 ) +#define vQueueAddToRegistry( xQueue, pcName ) +#define vQueueUnregisterQueue( xQueue ) +#define pcQueueGetName( xQueue ) +#endif + +#ifndef portPOINTER_SIZE_TYPE +#define portPOINTER_SIZE_TYPE uint32_t +#endif + +/* Remove any unused trace macros. */ +#ifndef traceSTART +/* Used to perform any necessary initialisation - for example, open a file +into which trace is to be written. */ +#define traceSTART() +#endif + +#ifndef traceEND +/* Use to close a trace, for example close a file into which trace has been +written. */ +#define traceEND() +#endif + +#ifndef traceTASK_SWITCHED_IN +/* Called after a task has been selected to run. pxCurrentTCB holds a pointer +to the task control block of the selected task. */ +#define traceTASK_SWITCHED_IN() +#endif + +#ifndef traceINCREASE_TICK_COUNT +/* Called before stepping the tick count after waking from tickless idle +sleep. */ +#define traceINCREASE_TICK_COUNT( x ) +#endif + +#ifndef traceLOW_POWER_IDLE_BEGIN +/* Called immediately before entering tickless idle. */ +#define traceLOW_POWER_IDLE_BEGIN() +#endif + +#ifndef traceLOW_POWER_IDLE_END +/* Called when returning to the Idle task after a tickless idle. */ +#define traceLOW_POWER_IDLE_END() +#endif + +#ifndef traceTASK_SWITCHED_OUT +/* Called before a task has been selected to run. pxCurrentTCB holds a pointer +to the task control block of the task being switched out. */ +#define traceTASK_SWITCHED_OUT() +#endif + +#ifndef traceTASK_PRIORITY_INHERIT +/* Called when a task attempts to take a mutex that is already held by a +lower priority task. pxTCBOfMutexHolder is a pointer to the TCB of the task +that holds the mutex. uxInheritedPriority is the priority the mutex holder +will inherit (the priority of the task that is attempting to obtain the +muted. */ +#define traceTASK_PRIORITY_INHERIT( pxTCBOfMutexHolder, uxInheritedPriority ) +#endif + +#ifndef traceTASK_PRIORITY_DISINHERIT +/* Called when a task releases a mutex, the holding of which had resulted in +the task inheriting the priority of a higher priority task. +pxTCBOfMutexHolder is a pointer to the TCB of the task that is releasing the +mutex. uxOriginalPriority is the task's configured (base) priority. */ +#define traceTASK_PRIORITY_DISINHERIT( pxTCBOfMutexHolder, uxOriginalPriority ) +#endif + +#ifndef traceBLOCKING_ON_QUEUE_RECEIVE +/* Task is about to block because it cannot read from a +queue/mutex/semaphore. pxQueue is a pointer to the queue/mutex/semaphore +upon which the read was attempted. pxCurrentTCB points to the TCB of the +task that attempted the read. */ +#define traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ) +#endif + +#ifndef traceBLOCKING_ON_QUEUE_SEND +/* Task is about to block because it cannot write to a +queue/mutex/semaphore. pxQueue is a pointer to the queue/mutex/semaphore +upon which the write was attempted. pxCurrentTCB points to the TCB of the +task that attempted the write. */ +#define traceBLOCKING_ON_QUEUE_SEND( pxQueue ) +#endif + +#ifndef configCHECK_FOR_STACK_OVERFLOW +#define configCHECK_FOR_STACK_OVERFLOW 0 +#endif + +/* The following event macros are embedded in the kernel API calls. */ + +#ifndef traceMOVED_TASK_TO_READY_STATE +#define traceMOVED_TASK_TO_READY_STATE( pxTCB ) +#endif + +#ifndef tracePOST_MOVED_TASK_TO_READY_STATE +#define tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB ) +#endif + +#ifndef traceQUEUE_CREATE +#define traceQUEUE_CREATE( pxNewQueue ) +#endif + +#ifndef traceQUEUE_CREATE_FAILED +#define traceQUEUE_CREATE_FAILED( ucQueueType ) +#endif + +#ifndef traceCREATE_MUTEX +#define traceCREATE_MUTEX( pxNewQueue ) +#endif + +#ifndef traceCREATE_MUTEX_FAILED +#define traceCREATE_MUTEX_FAILED() +#endif + +#ifndef traceGIVE_MUTEX_RECURSIVE +#define traceGIVE_MUTEX_RECURSIVE( pxMutex ) +#endif + +#ifndef traceGIVE_MUTEX_RECURSIVE_FAILED +#define traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex ) +#endif + +#ifndef traceTAKE_MUTEX_RECURSIVE +#define traceTAKE_MUTEX_RECURSIVE( pxMutex ) +#endif + +#ifndef traceTAKE_MUTEX_RECURSIVE_FAILED +#define traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex ) +#endif + +#ifndef traceCREATE_COUNTING_SEMAPHORE +#define traceCREATE_COUNTING_SEMAPHORE() +#endif + +#ifndef traceCREATE_COUNTING_SEMAPHORE_FAILED +#define traceCREATE_COUNTING_SEMAPHORE_FAILED() +#endif + +#ifndef traceQUEUE_SEND +#define traceQUEUE_SEND( pxQueue ) +#endif + +#ifndef traceQUEUE_SEND_FAILED +#define traceQUEUE_SEND_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_RECEIVE +#define traceQUEUE_RECEIVE( pxQueue ) +#endif + +#ifndef traceQUEUE_PEEK +#define traceQUEUE_PEEK( pxQueue ) +#endif + +#ifndef traceQUEUE_PEEK_FROM_ISR +#define traceQUEUE_PEEK_FROM_ISR( pxQueue ) +#endif + +#ifndef traceQUEUE_RECEIVE_FAILED +#define traceQUEUE_RECEIVE_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_SEND_FROM_ISR +#define traceQUEUE_SEND_FROM_ISR( pxQueue ) +#endif + +#ifndef traceQUEUE_SEND_FROM_ISR_FAILED +#define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_RECEIVE_FROM_ISR +#define traceQUEUE_RECEIVE_FROM_ISR( pxQueue ) +#endif + +#ifndef traceQUEUE_RECEIVE_FROM_ISR_FAILED +#define traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_PEEK_FROM_ISR_FAILED +#define traceQUEUE_PEEK_FROM_ISR_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_DELETE +#define traceQUEUE_DELETE( pxQueue ) +#endif + +#ifndef traceTASK_CREATE +#define traceTASK_CREATE( pxNewTCB ) +#endif + +#ifndef traceTASK_CREATE_FAILED +#define traceTASK_CREATE_FAILED() +#endif + +#ifndef traceTASK_DELETE +#define traceTASK_DELETE( pxTaskToDelete ) +#endif + +#ifndef traceTASK_DELAY_UNTIL +#define traceTASK_DELAY_UNTIL( x ) +#endif + +#ifndef traceTASK_DELAY +#define traceTASK_DELAY() +#endif + +#ifndef traceTASK_PRIORITY_SET +#define traceTASK_PRIORITY_SET( pxTask, uxNewPriority ) +#endif + +#ifndef traceTASK_SUSPEND +#define traceTASK_SUSPEND( pxTaskToSuspend ) +#endif + +#ifndef traceTASK_RESUME +#define traceTASK_RESUME( pxTaskToResume ) +#endif + +#ifndef traceTASK_RESUME_FROM_ISR +#define traceTASK_RESUME_FROM_ISR( pxTaskToResume ) +#endif + +#ifndef traceTASK_INCREMENT_TICK +#define traceTASK_INCREMENT_TICK( xTickCount ) +#endif + +#ifndef traceTIMER_CREATE +#define traceTIMER_CREATE( pxNewTimer ) +#endif + +#ifndef traceTIMER_CREATE_FAILED +#define traceTIMER_CREATE_FAILED() +#endif + +#ifndef traceTIMER_COMMAND_SEND +#define traceTIMER_COMMAND_SEND( xTimer, xMessageID, xMessageValueValue, xReturn ) +#endif + +#ifndef traceTIMER_EXPIRED +#define traceTIMER_EXPIRED( pxTimer ) +#endif + +#ifndef traceTIMER_COMMAND_RECEIVED +#define traceTIMER_COMMAND_RECEIVED( pxTimer, xMessageID, xMessageValue ) +#endif + +#ifndef traceMALLOC +#define traceMALLOC( pvAddress, uiSize ) +#endif + +#ifndef traceFREE +#define traceFREE( pvAddress, uiSize ) +#endif + +#ifndef traceEVENT_GROUP_CREATE +#define traceEVENT_GROUP_CREATE( xEventGroup ) +#endif + +#ifndef traceEVENT_GROUP_CREATE_FAILED +#define traceEVENT_GROUP_CREATE_FAILED() +#endif + +#ifndef traceEVENT_GROUP_SYNC_BLOCK +#define traceEVENT_GROUP_SYNC_BLOCK( xEventGroup, uxBitsToSet, uxBitsToWaitFor ) +#endif + +#ifndef traceEVENT_GROUP_SYNC_END +#define traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred ) ( void ) xTimeoutOccurred +#endif + +#ifndef traceEVENT_GROUP_WAIT_BITS_BLOCK +#define traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor ) +#endif + +#ifndef traceEVENT_GROUP_WAIT_BITS_END +#define traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred ) ( void ) xTimeoutOccurred +#endif + +#ifndef traceEVENT_GROUP_CLEAR_BITS +#define traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear ) +#endif + +#ifndef traceEVENT_GROUP_CLEAR_BITS_FROM_ISR +#define traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear ) +#endif + +#ifndef traceEVENT_GROUP_SET_BITS +#define traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet ) +#endif + +#ifndef traceEVENT_GROUP_SET_BITS_FROM_ISR +#define traceEVENT_GROUP_SET_BITS_FROM_ISR( xEventGroup, uxBitsToSet ) +#endif + +#ifndef traceEVENT_GROUP_DELETE +#define traceEVENT_GROUP_DELETE( xEventGroup ) +#endif + +#ifndef tracePEND_FUNC_CALL +#define tracePEND_FUNC_CALL(xFunctionToPend, pvParameter1, ulParameter2, ret) +#endif + +#ifndef tracePEND_FUNC_CALL_FROM_ISR +#define tracePEND_FUNC_CALL_FROM_ISR(xFunctionToPend, pvParameter1, ulParameter2, ret) +#endif + +#ifndef traceQUEUE_REGISTRY_ADD +#define traceQUEUE_REGISTRY_ADD(xQueue, pcQueueName) +#endif + +#ifndef traceTASK_NOTIFY_TAKE_BLOCK +#define traceTASK_NOTIFY_TAKE_BLOCK() +#endif + +#ifndef traceTASK_NOTIFY_TAKE +#define traceTASK_NOTIFY_TAKE() +#endif + +#ifndef traceTASK_NOTIFY_WAIT_BLOCK +#define traceTASK_NOTIFY_WAIT_BLOCK() +#endif + +#ifndef traceTASK_NOTIFY_WAIT +#define traceTASK_NOTIFY_WAIT() +#endif + +#ifndef traceTASK_NOTIFY +#define traceTASK_NOTIFY() +#endif + +#ifndef traceTASK_NOTIFY_FROM_ISR +#define traceTASK_NOTIFY_FROM_ISR() +#endif + +#ifndef traceTASK_NOTIFY_GIVE_FROM_ISR +#define traceTASK_NOTIFY_GIVE_FROM_ISR() +#endif + +#ifndef configGENERATE_RUN_TIME_STATS +#define configGENERATE_RUN_TIME_STATS 0 +#endif + +#if ( configGENERATE_RUN_TIME_STATS == 1 ) + +#ifndef portCONFIGURE_TIMER_FOR_RUN_TIME_STATS +#error If configGENERATE_RUN_TIME_STATS is defined then portCONFIGURE_TIMER_FOR_RUN_TIME_STATS must also be defined. portCONFIGURE_TIMER_FOR_RUN_TIME_STATS should call a port layer function to setup a peripheral timer/counter that can then be used as the run time counter time base. +#endif /* portCONFIGURE_TIMER_FOR_RUN_TIME_STATS */ + +#ifndef portGET_RUN_TIME_COUNTER_VALUE +#ifndef portALT_GET_RUN_TIME_COUNTER_VALUE +#error If configGENERATE_RUN_TIME_STATS is defined then either portGET_RUN_TIME_COUNTER_VALUE or portALT_GET_RUN_TIME_COUNTER_VALUE must also be defined. See the examples provided and the FreeRTOS web site for more information. +#endif /* portALT_GET_RUN_TIME_COUNTER_VALUE */ +#endif /* portGET_RUN_TIME_COUNTER_VALUE */ + +#endif /* configGENERATE_RUN_TIME_STATS */ + +#ifndef portCONFIGURE_TIMER_FOR_RUN_TIME_STATS +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() +#endif + +#ifndef configUSE_MALLOC_FAILED_HOOK +#define configUSE_MALLOC_FAILED_HOOK 0 +#endif + +#ifndef portPRIVILEGE_BIT +#define portPRIVILEGE_BIT ( ( UBaseType_t ) 0x00 ) +#endif + +#ifndef portYIELD_WITHIN_API +#define portYIELD_WITHIN_API portYIELD +#endif + +#ifndef portSUPPRESS_TICKS_AND_SLEEP +#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) +#endif + +#ifndef configEXPECTED_IDLE_TIME_BEFORE_SLEEP +#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2 +#endif + +#if configEXPECTED_IDLE_TIME_BEFORE_SLEEP < 2 +#error configEXPECTED_IDLE_TIME_BEFORE_SLEEP must not be less than 2 +#endif + +#ifndef configUSE_TICKLESS_IDLE +#define configUSE_TICKLESS_IDLE 1 +#endif + +#ifndef configPRE_SLEEP_PROCESSING +#define configPRE_SLEEP_PROCESSING( x ) +#endif + +#ifndef configPOST_SLEEP_PROCESSING +#define configPOST_SLEEP_PROCESSING( x ) +#endif + +#ifndef configUSE_QUEUE_SETS +#define configUSE_QUEUE_SETS 0 +#endif + +#ifndef portTASK_USES_FLOATING_POINT +#define portTASK_USES_FLOATING_POINT() +#endif + +#ifndef configUSE_TIME_SLICING +#define configUSE_TIME_SLICING 1 +#endif + +#ifndef configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS +#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0 +#endif + +#ifndef configUSE_STATS_FORMATTING_FUNCTIONS +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 +#endif + +#ifndef portASSERT_IF_INTERRUPT_PRIORITY_INVALID +#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() +#endif + +#ifndef configUSE_TRACE_FACILITY +#define configUSE_TRACE_FACILITY 0 +#endif + +#ifndef mtCOVERAGE_TEST_MARKER +#define mtCOVERAGE_TEST_MARKER() +#endif + +#ifndef mtCOVERAGE_TEST_DELAY +#define mtCOVERAGE_TEST_DELAY() +#endif + +#ifndef portASSERT_IF_IN_ISR +#define portASSERT_IF_IN_ISR() +#endif + +#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#endif + +#ifndef configAPPLICATION_ALLOCATED_HEAP +#define configAPPLICATION_ALLOCATED_HEAP 0 +#endif + +#ifndef configUSE_TASK_NOTIFICATIONS +#define configUSE_TASK_NOTIFICATIONS 1 +#endif + +#ifndef portTICK_TYPE_IS_ATOMIC +#define portTICK_TYPE_IS_ATOMIC 0 +#endif + +#ifndef configSUPPORT_STATIC_ALLOCATION +/* Defaults to 0 for backward compatibility. */ +#define configSUPPORT_STATIC_ALLOCATION 0 +#endif + +#ifndef configSUPPORT_DYNAMIC_ALLOCATION +/* Defaults to 1 for backward compatibility. */ +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#endif + +/* Sanity check the configuration. */ +#if( configUSE_TICKLESS_IDLE != 0 ) +#if( INCLUDE_vTaskSuspend != 1 ) +#error INCLUDE_vTaskSuspend must be set to 1 if configUSE_TICKLESS_IDLE is not set to 0 +#endif /* INCLUDE_vTaskSuspend */ +#endif /* configUSE_TICKLESS_IDLE */ + +#if( ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 0 ) ) +#error configSUPPORT_STATIC_ALLOCATION and configSUPPORT_DYNAMIC_ALLOCATION cannot both be 0, but can both be 1. +#endif + +#if( ( configUSE_RECURSIVE_MUTEXES == 1 ) && ( configUSE_MUTEXES != 1 ) ) +#error configUSE_MUTEXES must be set to 1 to use recursive mutexes +#endif + +#if( portTICK_TYPE_IS_ATOMIC == 0 ) +/* Either variables of tick type cannot be read atomically, or +portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when +the tick count is returned to the standard critical section macros. */ +#define portTICK_TYPE_ENTER_CRITICAL() portENTER_CRITICAL() +#define portTICK_TYPE_EXIT_CRITICAL() portEXIT_CRITICAL() +#define portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR() +#define portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( ( x ) ) +#else +/* The tick type can be read atomically, so critical sections used when the +tick count is returned can be defined away. */ +#define portTICK_TYPE_ENTER_CRITICAL() +#define portTICK_TYPE_EXIT_CRITICAL() +#define portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR() 0 +#define portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( x ) ( void ) x +#endif + +/* Definitions to allow backward compatibility with FreeRTOS versions prior to +V8 if desired. */ +#ifndef configENABLE_BACKWARD_COMPATIBILITY +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#endif + +#if configENABLE_BACKWARD_COMPATIBILITY == 1 +#define eTaskStateGet eTaskGetState +#define portTickType TickType_t +#define xTaskHandle TaskHandle_t +#define xQueueHandle QueueHandle_t +#define xSemaphoreHandle SemaphoreHandle_t +#define xQueueSetHandle QueueSetHandle_t +#define xQueueSetMemberHandle QueueSetMemberHandle_t +#define xTimeOutType TimeOut_t +#define xMemoryRegion MemoryRegion_t +#define xTaskParameters TaskParameters_t +#define xTaskStatusType TaskStatus_t +#define xTimerHandle TimerHandle_t +#define xCoRoutineHandle CoRoutineHandle_t +#define pdTASK_HOOK_CODE TaskHookFunction_t +#define portTICK_RATE_MS portTICK_PERIOD_MS +#define pcTaskGetTaskName pcTaskGetName +#define pcTimerGetTimerName pcTimerGetName +#define pcQueueGetQueueName pcQueueGetName +#define vTaskGetTaskInfo vTaskGetInfo + +/* Backward compatibility within the scheduler code only - these definitions +are not really required but are included for completeness. */ +#define tmrTIMER_CALLBACK TimerCallbackFunction_t +#define pdTASK_CODE TaskFunction_t +#define xListItem ListItem_t +#define xList List_t +#endif /* configENABLE_BACKWARD_COMPATIBILITY */ + +#if( configUSE_ALTERNATIVE_API != 0 ) +#error The alternative API was deprecated some time ago, and was removed in FreeRTOS V9.0 0 +#endif + +/* Set configUSE_TASK_FPU_SUPPORT to 0 to omit floating point support even +if floating point hardware is otherwise supported by the FreeRTOS port in use. +This constant is not supported by all FreeRTOS ports that include floating +point support. */ +#ifndef configUSE_TASK_FPU_SUPPORT +#define configUSE_TASK_FPU_SUPPORT 1 +#endif + +/* + * In line with software engineering best practice, FreeRTOS implements a strict + * data hiding policy, so the real structures used by FreeRTOS to maintain the + * state of tasks, queues, semaphores, etc. are not accessible to the application + * code. However, if the application writer wants to statically allocate such + * an object then the size of the object needs to be know. Dummy structures + * that are guaranteed to have the same size and alignment requirements of the + * real objects are used for this purpose. The dummy list and list item + * structures below are used for inclusion in such a dummy structure. + */ + +#if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 ) +/* Define the macros to do nothing. */ +#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE +#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE +#define listFIRST_LIST_INTEGRITY_CHECK_VALUE +#define listSECOND_LIST_INTEGRITY_CHECK_VALUE +#else +/* Define macros that add new members into the list structures. */ +#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue1; +#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue2; +#define listFIRST_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue1; +#define listSECOND_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue2; +#endif /* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES */ + +struct xSTATIC_LIST_ITEM { + listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE + TickType_t xDummy1; + void *pvDummy2[ 4 ]; + listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE +}; +typedef struct xSTATIC_LIST_ITEM StaticListItem_t; + +/* See the comments above the struct xSTATIC_LIST_ITEM definition. */ +struct xSTATIC_MINI_LIST_ITEM { + listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE + TickType_t xDummy1; + void *pvDummy2[ 2 ]; +}; +typedef struct xSTATIC_MINI_LIST_ITEM StaticMiniListItem_t; + +/* See the comments above the struct xSTATIC_LIST_ITEM definition. */ +typedef struct xSTATIC_LIST { + listFIRST_LIST_INTEGRITY_CHECK_VALUE + UBaseType_t uxDummy1; + void *pvDummy2; + StaticMiniListItem_t xDummy3; + listSECOND_LIST_INTEGRITY_CHECK_VALUE +} StaticList_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the Task structure used internally by + * FreeRTOS is not accessible to application code. However, if the application + * writer wants to statically allocate the memory required to create a task then + * the size of the task object needs to be know. The StaticTask_t structure + * below is provided for this purpose. Its sizes and alignment requirements are + * guaranteed to match those of the genuine structure, no matter which + * architecture is being used, and no matter how the values in FreeRTOSConfig.h + * are set. Its contents are somewhat obfuscated in the hope users will + * recognise that it would be unwise to make direct use of the structure members. + */ +typedef struct xSTATIC_TCB { + void *pxDummy1; + UBaseType_t uxDummy; +#if ( portUSING_MPU_WRAPPERS == 1 ) + xMPU_SETTINGS xDummy2; +#endif + StaticListItem_t xDummy3[ 2 ]; + UBaseType_t uxDummy5; + void *pxDummy6; + uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ]; +#if ( portSTACK_GROWTH > 0 ) + void *pxDummy8; +#endif +#if ( portCRITICAL_NESTING_IN_TCB == 1 ) + UBaseType_t uxDummy9; +#endif +#if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy10[ 2 ]; +#endif +#if ( configUSE_MUTEXES == 1 ) + UBaseType_t uxDummy12[ 2 ]; +#endif +#if ( configUSE_APPLICATION_TASK_TAG == 1 ) + void *pxDummy14; +#endif +#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) + void *pvDummy15[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; +#endif +#if ( configGENERATE_RUN_TIME_STATS == 1 ) + uint32_t ulDummy16; +#endif +#if ( configUSE_NEWLIB_REENTRANT == 1 ) + struct _reent xDummy17; +#endif +#if ( configUSE_TASK_NOTIFICATIONS == 1 ) + uint32_t ulDummy18; + uint8_t ucDummy19; +#endif +#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t uxDummy20; +#endif + +} StaticTask_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the Queue structure used internally by + * FreeRTOS is not accessible to application code. However, if the application + * writer wants to statically allocate the memory required to create a queue + * then the size of the queue object needs to be know. The StaticQueue_t + * structure below is provided for this purpose. Its sizes and alignment + * requirements are guaranteed to match those of the genuine structure, no + * matter which architecture is being used, and no matter how the values in + * FreeRTOSConfig.h are set. Its contents are somewhat obfuscated in the hope + * users will recognise that it would be unwise to make direct use of the + * structure members. + */ +typedef struct xSTATIC_QUEUE { + void *pvDummy1[ 3 ]; + + union { + void *pvDummy2; + UBaseType_t uxDummy2; + } u; + + StaticList_t xDummy3[ 2 ]; + UBaseType_t uxDummy4[ 3 ]; + uint8_t ucDummy5[ 2 ]; + +#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucDummy6; +#endif + +#if ( configUSE_QUEUE_SETS == 1 ) + void *pvDummy7; +#endif + +#if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy8; + uint8_t ucDummy9; +#endif + +} StaticQueue_t; +typedef StaticQueue_t StaticSemaphore_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the event group structure used + * internally by FreeRTOS is not accessible to application code. However, if + * the application writer wants to statically allocate the memory required to + * create an event group then the size of the event group object needs to be + * know. The StaticEventGroup_t structure below is provided for this purpose. + * Its sizes and alignment requirements are guaranteed to match those of the + * genuine structure, no matter which architecture is being used, and no matter + * how the values in FreeRTOSConfig.h are set. Its contents are somewhat + * obfuscated in the hope users will recognise that it would be unwise to make + * direct use of the structure members. + */ +typedef struct xSTATIC_EVENT_GROUP { + TickType_t xDummy1; + StaticList_t xDummy2; + +#if( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy3; +#endif + +#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucDummy4; +#endif + +} StaticEventGroup_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the software timer structure used + * internally by FreeRTOS is not accessible to application code. However, if + * the application writer wants to statically allocate the memory required to + * create a software timer then the size of the queue object needs to be know. + * The StaticTimer_t structure below is provided for this purpose. Its sizes + * and alignment requirements are guaranteed to match those of the genuine + * structure, no matter which architecture is being used, and no matter how the + * values in FreeRTOSConfig.h are set. Its contents are somewhat obfuscated in + * the hope users will recognise that it would be unwise to make direct use of + * the structure members. + */ +typedef struct xSTATIC_TIMER { + void *pvDummy1; + StaticListItem_t xDummy2; + TickType_t xDummy3; + UBaseType_t uxDummy4; + void *pvDummy5[ 2 ]; +#if( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy6; +#endif + +#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucDummy7; +#endif + +} StaticTimer_t; + +#ifdef __cplusplus +} +#endif + +#endif /* INC_FREERTOS_H */ + diff --git a/include_lib/system/os/FreeRTOS/FreeRTOSConfig.h b/include_lib/system/os/FreeRTOS/FreeRTOSConfig.h new file mode 100644 index 0000000..ad91da0 --- /dev/null +++ b/include_lib/system/os/FreeRTOS/FreeRTOSConfig.h @@ -0,0 +1,195 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. See + * http://www.freertos.org/a00110.html + *----------------------------------------------------------*/ +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configUSE_IDLE_HOOK 1 +#define configUSE_TICK_HOOK 0 +#define configUSE_DAEMON_TASK_STARTUP_HOOK 1 +#define configTICK_RATE_HZ ( 100 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned int) 256) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the win32 thread. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 30 * 1024 ) ) +#define configMAX_TASK_NAME_LEN ( 12 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configCHECK_FOR_STACK_OVERFLOW 0 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configUSE_APPLICATION_TASK_TAG 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configUSE_QUEUE_SETS 0 +#define configUSE_TASK_NOTIFICATIONS 0 +#define configSUPPORT_STATIC_ALLOCATION 1 + + + +/* Software timer related configuration options. */ +#define configUSE_TIMERS 0 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 20 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +#define configMAX_PRIORITIES ( 8 ) + +/* Run time stats gathering configuration options. */ +unsigned long ulGetRunTimeCounterValue(void); /* Prototype of function that returns run time counter. */ +void vConfigureTimerForRunTimeStats(void); /* Prototype of function that initialises the run time counter. */ +void vMainConfigureTimerForRunTimeStats(void); +unsigned long ulMainGetRunTimeCounterValue(void); +#define configGENERATE_RUN_TIME_STATS 0 +// #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vConfigureTimerForRunTimeStats() +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vMainConfigureTimerForRunTimeStats(); +#define portGET_RUN_TIME_COUNTER_VALUE() ulGetRunTimeCounterValue() + +/* Co-routine related configuration options. */ +#define configUSE_CO_ROUTINES 1 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* This demo makes use of one or more example stats formatting functions. These +format the raw data provided by the uxTaskGetSystemState() function in to human +readable ASCII form. See the notes in the implementation of vTaskList() within +FreeRTOS/Source/tasks.c for limitations. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. In most cases the linker will remove unused +functions anyway. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1 +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xSemaphoreGetMutexHolder 1 +#define INCLUDE_xTimerPendFunctionCall 0 +#define INCLUDE_xTaskAbortDelay 1 + +/* It is a good idea to define configASSERT() while developing. configASSERT() +uses the same semantics as the standard C assert() macro. */ +#include "printf.h" +static inline void vAssertCalled(const char *str, unsigned int ulLine) +{ + /* + if(OS_CPU_ID == 0) + { + C1_CON |=BIT(1) ; + }else + { + C0_CON |=BIT(1) ; + }*/ + local_irq_disable(); + printf("%s %d\n", str, ulLine) ; + while (1); + +} +#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled(__func__, __LINE__) + +/* Include the FreeRTOS+Trace FreeRTOS trace macro definitions. */ +#define TRACE_ENTER_CRITICAL_SECTION() portENTER_CRITICAL() +#define TRACE_EXIT_CRITICAL_SECTION() portEXIT_CRITICAL() +//#include "trcKernelPort.h" + +#ifdef __GCC_PI32V2__ +#include "pi32v2/portmacro.h" +#endif + +#ifdef __GCC_PI32_LTO__ +#include "pi32_lto/portmacro.h" +#endif + +#ifdef __GCC_Q32S__ +#include "q32s/portmacro.h" +#endif + +#endif /* FREERTOS_CONFIG_H */ diff --git a/include_lib/system/os/FreeRTOS/deprecated_definitions.h b/include_lib/system/os/FreeRTOS/deprecated_definitions.h new file mode 100644 index 0000000..93e82b7 --- /dev/null +++ b/include_lib/system/os/FreeRTOS/deprecated_definitions.h @@ -0,0 +1,321 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef DEPRECATED_DEFINITIONS_H +#define DEPRECATED_DEFINITIONS_H + + +/* Each FreeRTOS port has a unique portmacro.h header file. Originally a +pre-processor definition was used to ensure the pre-processor found the correct +portmacro.h file for the port being used. That scheme was deprecated in favour +of setting the compiler's include path such that it found the correct +portmacro.h file - removing the need for the constant and allowing the +portmacro.h file to be located anywhere in relation to the port being used. The +definitions below remain in the code for backward compatibility only. New +projects should not use them. */ + +#ifdef OPEN_WATCOM_INDUSTRIAL_PC_PORT +#include "..\..\Source\portable\owatcom\16bitdos\pc\portmacro.h" +typedef void (__interrupt __far *pxISR)(); +#endif + +#ifdef OPEN_WATCOM_FLASH_LITE_186_PORT +#include "..\..\Source\portable\owatcom\16bitdos\flsh186\portmacro.h" +typedef void (__interrupt __far *pxISR)(); +#endif + +#ifdef GCC_MEGA_AVR +#include "../portable/GCC/ATMega323/portmacro.h" +#endif + +#ifdef IAR_MEGA_AVR +#include "../portable/IAR/ATMega323/portmacro.h" +#endif + +#ifdef MPLAB_PIC24_PORT +#include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h" +#endif + +#ifdef MPLAB_DSPIC_PORT +#include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h" +#endif + +#ifdef MPLAB_PIC18F_PORT +#include "../../Source/portable/MPLAB/PIC18F/portmacro.h" +#endif + +#ifdef MPLAB_PIC32MX_PORT +#include "../../Source/portable/MPLAB/PIC32MX/portmacro.h" +#endif + +#ifdef _FEDPICC +#include "libFreeRTOS/Include/portmacro.h" +#endif + +#ifdef SDCC_CYGNAL +#include "../../Source/portable/SDCC/Cygnal/portmacro.h" +#endif + +#ifdef GCC_ARM7 +#include "../../Source/portable/GCC/ARM7_LPC2000/portmacro.h" +#endif + +#ifdef GCC_ARM7_ECLIPSE +#include "portmacro.h" +#endif + +#ifdef ROWLEY_LPC23xx +#include "../../Source/portable/GCC/ARM7_LPC23xx/portmacro.h" +#endif + +#ifdef IAR_MSP430 +#include "..\..\Source\portable\IAR\MSP430\portmacro.h" +#endif + +#ifdef GCC_MSP430 +#include "../../Source/portable/GCC/MSP430F449/portmacro.h" +#endif + +#ifdef ROWLEY_MSP430 +#include "../../Source/portable/Rowley/MSP430F449/portmacro.h" +#endif + +#ifdef ARM7_LPC21xx_KEIL_RVDS +#include "..\..\Source\portable\RVDS\ARM7_LPC21xx\portmacro.h" +#endif + +#ifdef SAM7_GCC +#include "../../Source/portable/GCC/ARM7_AT91SAM7S/portmacro.h" +#endif + +#ifdef SAM7_IAR +#include "..\..\Source\portable\IAR\AtmelSAM7S64\portmacro.h" +#endif + +#ifdef SAM9XE_IAR +#include "..\..\Source\portable\IAR\AtmelSAM9XE\portmacro.h" +#endif + +#ifdef LPC2000_IAR +#include "..\..\Source\portable\IAR\LPC2000\portmacro.h" +#endif + +#ifdef STR71X_IAR +#include "..\..\Source\portable\IAR\STR71x\portmacro.h" +#endif + +#ifdef STR75X_IAR +#include "..\..\Source\portable\IAR\STR75x\portmacro.h" +#endif + +#ifdef STR75X_GCC +#include "..\..\Source\portable\GCC\STR75x\portmacro.h" +#endif + +#ifdef STR91X_IAR +#include "..\..\Source\portable\IAR\STR91x\portmacro.h" +#endif + +#ifdef GCC_H8S +#include "../../Source/portable/GCC/H8S2329/portmacro.h" +#endif + +#ifdef GCC_AT91FR40008 +#include "../../Source/portable/GCC/ARM7_AT91FR40008/portmacro.h" +#endif + +#ifdef RVDS_ARMCM3_LM3S102 +#include "../../Source/portable/RVDS/ARM_CM3/portmacro.h" +#endif + +#ifdef GCC_ARMCM3_LM3S102 +#include "../../Source/portable/GCC/ARM_CM3/portmacro.h" +#endif + +#ifdef GCC_ARMCM3 +#include "../../Source/portable/GCC/ARM_CM3/portmacro.h" +#endif + +#ifdef IAR_ARM_CM3 +#include "../../Source/portable/IAR/ARM_CM3/portmacro.h" +#endif + +#ifdef IAR_ARMCM3_LM +#include "../../Source/portable/IAR/ARM_CM3/portmacro.h" +#endif + +#ifdef HCS12_CODE_WARRIOR +#include "../../Source/portable/CodeWarrior/HCS12/portmacro.h" +#endif + +#ifdef MICROBLAZE_GCC +#include "../../Source/portable/GCC/MicroBlaze/portmacro.h" +#endif + +#ifdef TERN_EE +#include "..\..\Source\portable\Paradigm\Tern_EE\small\portmacro.h" +#endif + +#ifdef GCC_HCS12 +#include "../../Source/portable/GCC/HCS12/portmacro.h" +#endif + +#ifdef GCC_MCF5235 +#include "../../Source/portable/GCC/MCF5235/portmacro.h" +#endif + +#ifdef COLDFIRE_V2_GCC +#include "../../../Source/portable/GCC/ColdFire_V2/portmacro.h" +#endif + +#ifdef COLDFIRE_V2_CODEWARRIOR +#include "../../Source/portable/CodeWarrior/ColdFire_V2/portmacro.h" +#endif + +#ifdef GCC_PPC405 +#include "../../Source/portable/GCC/PPC405_Xilinx/portmacro.h" +#endif + +#ifdef GCC_PPC440 +#include "../../Source/portable/GCC/PPC440_Xilinx/portmacro.h" +#endif + +#ifdef _16FX_SOFTUNE +#include "..\..\Source\portable\Softune\MB96340\portmacro.h" +#endif + +#ifdef BCC_INDUSTRIAL_PC_PORT +/* A short file name has to be used in place of the normal +FreeRTOSConfig.h when using the Borland compiler. */ +#include "frconfig.h" +#include "..\portable\BCC\16BitDOS\PC\prtmacro.h" +typedef void (__interrupt __far *pxISR)(); +#endif + +#ifdef BCC_FLASH_LITE_186_PORT +/* A short file name has to be used in place of the normal +FreeRTOSConfig.h when using the Borland compiler. */ +#include "frconfig.h" +#include "..\portable\BCC\16BitDOS\flsh186\prtmacro.h" +typedef void (__interrupt __far *pxISR)(); +#endif + +#ifdef __GNUC__ +#ifdef __AVR32_AVR32A__ +#include "portmacro.h" +#endif +#endif + +#ifdef __ICCAVR32__ +#ifdef __CORE__ +#if __CORE__ == __AVR32A__ +#include "portmacro.h" +#endif +#endif +#endif + +#ifdef __91467D +#include "portmacro.h" +#endif + +#ifdef __96340 +#include "portmacro.h" +#endif + + +#ifdef __IAR_V850ES_Fx3__ +#include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx3__ +#include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx3_L__ +#include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx2__ +#include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Hx2__ +#include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_78K0R_Kx3__ +#include "../../Source/portable/IAR/78K0R/portmacro.h" +#endif + +#ifdef __IAR_78K0R_Kx3L__ +#include "../../Source/portable/IAR/78K0R/portmacro.h" +#endif + +#endif /* DEPRECATED_DEFINITIONS_H */ + diff --git a/include_lib/system/os/FreeRTOS/list.h b/include_lib/system/os/FreeRTOS/list.h new file mode 100644 index 0000000..43e223a --- /dev/null +++ b/include_lib/system/os/FreeRTOS/list.h @@ -0,0 +1,450 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * This is the list implementation used by the scheduler. While it is tailored + * heavily for the schedulers needs, it is also available for use by + * application code. + * + * list_ts can only store pointers to list_item_ts. Each ListItem_t contains a + * numeric value (xItemValue). Most of the time the lists are sorted in + * descending item value order. + * + * Lists are created already containing one list item. The value of this + * item is the maximum possible that can be stored, it is therefore always at + * the end of the list and acts as a marker. The list member pxHead always + * points to this marker - even though it is at the tail of the list. This + * is because the tail contains a wrap back pointer to the true head of + * the list. + * + * In addition to it's value, each list item contains a pointer to the next + * item in the list (pxNext), a pointer to the list it is in (pxContainer) + * and a pointer to back to the object that contains it. These later two + * pointers are included for efficiency of list manipulation. There is + * effectively a two way link between the object containing the list item and + * the list item itself. + * + * + * \page ListIntroduction List Implementation + * \ingroup FreeRTOSIntro + */ + +#ifndef INC_FREERTOS_H +#error FreeRTOS.h must be included before list.h +#endif + +#ifndef FREERTOS_LIST_H +#define FREERTOS_LIST_H + +/* + * The list structure members are modified from within interrupts, and therefore + * by rights should be declared volatile. However, they are only modified in a + * functionally atomic way (within critical sections of with the scheduler + * suspended) and are either passed by reference into a function or indexed via + * a volatile variable. Therefore, in all use cases tested so far, the volatile + * qualifier can be omitted in order to provide a moderate performance + * improvement without adversely affecting functional behaviour. The assembly + * instructions generated by the IAR, ARM and GCC compilers when the respective + * compiler's options were set for maximum optimisation has been inspected and + * deemed to be as intended. That said, as compiler technology advances, and + * especially if aggressive cross module optimisation is used (a use case that + * has not been exercised to any great extend) then it is feasible that the + * volatile qualifier will be needed for correct optimisation. It is expected + * that a compiler removing essential code because, without the volatile + * qualifier on the list structure members and with aggressive cross module + * optimisation, the compiler deemed the code unnecessary will result in + * complete and obvious failure of the scheduler. If this is ever experienced + * then the volatile qualifier can be inserted in the relevant places within the + * list structures by simply defining configLIST_VOLATILE to volatile in + * FreeRTOSConfig.h (as per the example at the bottom of this comment block). + * If configLIST_VOLATILE is not defined then the preprocessor directives below + * will simply #define configLIST_VOLATILE away completely. + * + * To use volatile list structure members then add the following line to + * FreeRTOSConfig.h (without the quotes): + * "#define configLIST_VOLATILE volatile" + */ +#ifndef configLIST_VOLATILE +#define configLIST_VOLATILE +#endif /* configSUPPORT_CROSS_MODULE_OPTIMISATION */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Macros that can be used to place known values within the list structures, +then check that the known values do not get corrupted during the execution of +the application. These may catch the list data structures being overwritten in +memory. They will not catch data errors caused by incorrect configuration or +use of FreeRTOS.*/ +#if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 ) +/* Define the macros to do nothing. */ +#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE +#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE +#define listFIRST_LIST_INTEGRITY_CHECK_VALUE +#define listSECOND_LIST_INTEGRITY_CHECK_VALUE +#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) +#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) +#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ) +#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ) +#define listTEST_LIST_ITEM_INTEGRITY( pxItem ) +#define listTEST_LIST_INTEGRITY( pxList ) +#else +/* Define macros that add new members into the list structures. */ +#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue1; +#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue2; +#define listFIRST_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue1; +#define listSECOND_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue2; + +/* Define macros that set the new structure members to known values. */ +#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue1 = pdINTEGRITY_CHECK_VALUE +#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue2 = pdINTEGRITY_CHECK_VALUE +#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ) ( pxList )->xListIntegrityValue1 = pdINTEGRITY_CHECK_VALUE +#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ) ( pxList )->xListIntegrityValue2 = pdINTEGRITY_CHECK_VALUE + +/* Define macros that will assert if one of the structure members does not +contain its expected value. */ +#define listTEST_LIST_ITEM_INTEGRITY( pxItem ) configASSERT( ( ( pxItem )->xListItemIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxItem )->xListItemIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) ) +#define listTEST_LIST_INTEGRITY( pxList ) configASSERT( ( ( pxList )->xListIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxList )->xListIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) ) +#endif /* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES */ + + +/* + * Definition of the only type of object that a list can contain. + */ +struct xLIST_ITEM { + listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */ + struct xLIST_ITEM *configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */ + struct xLIST_ITEM *configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */ + void *pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */ + void *configLIST_VOLATILE pvContainer; /*< Pointer to the list in which this list item is placed (if any). */ + listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ +}; +typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */ + +struct xMINI_LIST_ITEM { + listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + configLIST_VOLATILE TickType_t xItemValue; + struct xLIST_ITEM *configLIST_VOLATILE pxNext; + struct xLIST_ITEM *configLIST_VOLATILE pxPrevious; +}; +typedef struct xMINI_LIST_ITEM MiniListItem_t; + +/* + * Definition of the type of queue used by the scheduler. + */ +typedef struct xLIST { + listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + configLIST_VOLATILE UBaseType_t uxNumberOfItems; + ListItem_t *configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */ + MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */ + listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ +} List_t; + +/* + * Access macro to set the owner of a list item. The owner of a list item + * is the object (usually a TCB) that contains the list item. + * + * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER + * \ingroup LinkedList + */ +#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) ) + +/* + * Access macro to get the owner of a list item. The owner of a list item + * is the object (usually a TCB) that contains the list item. + * + * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER + * \ingroup LinkedList + */ +#define listGET_LIST_ITEM_OWNER( pxListItem ) ( ( pxListItem )->pvOwner ) + +/* + * Access macro to set the value of the list item. In most cases the value is + * used to sort the list in descending order. + * + * \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE + * \ingroup LinkedList + */ +#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( ( pxListItem )->xItemValue = ( xValue ) ) + +/* + * Access macro to retrieve the value of the list item. The value can + * represent anything - for example the priority of a task, or the time at + * which a task should be unblocked. + * + * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE + * \ingroup LinkedList + */ +#define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue ) + +/* + * Access macro to retrieve the value of the list item at the head of a given + * list. + * + * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE + * \ingroup LinkedList + */ +#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext->xItemValue ) + +/* + * Return the list item at the head of the list. + * + * \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY + * \ingroup LinkedList + */ +#define listGET_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext ) + +/* + * Return the list item at the head of the list. + * + * \page listGET_NEXT listGET_NEXT + * \ingroup LinkedList + */ +#define listGET_NEXT( pxListItem ) ( ( pxListItem )->pxNext ) + +/* + * Return the list item that marks the end of the list + * + * \page listGET_END_MARKER listGET_END_MARKER + * \ingroup LinkedList + */ +#define listGET_END_MARKER( pxList ) ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) ) + +/* + * Access macro to determine if a list contains any items. The macro will + * only have the value true if the list is empty. + * + * \page listLIST_IS_EMPTY listLIST_IS_EMPTY + * \ingroup LinkedList + */ +#define listLIST_IS_EMPTY( pxList ) ( ( BaseType_t ) ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ) + +/* + * Access macro to return the number of items in the list. + */ +#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems ) + +/* + * Access function to obtain the owner of the next entry in a list. + * + * The list member pxIndex is used to walk through a list. Calling + * listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list + * and returns that entry's pxOwner parameter. Using multiple calls to this + * function it is therefore possible to move through every item contained in + * a list. + * + * The pxOwner parameter of a list item is a pointer to the object that owns + * the list item. In the scheduler this is normally a task control block. + * The pxOwner parameter effectively creates a two way link between the list + * item and its owner. + * + * @param pxTCB pxTCB is set to the address of the owner of the next list item. + * @param pxList The list from which the next item owner is to be returned. + * + * \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY + * \ingroup LinkedList + */ +#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \ +{ \ +List_t * const pxConstList = ( pxList ); \ + /* Increment the index to the next item and return the item, ensuring */ \ + /* we don't return the marker used at the end of the list. */ \ + ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \ + if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \ + { \ + ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \ + } \ + ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \ +} + + +/* + * Access function to obtain the owner of the first entry in a list. Lists + * are normally sorted in ascending item value order. + * + * This function returns the pxOwner member of the first item in the list. + * The pxOwner parameter of a list item is a pointer to the object that owns + * the list item. In the scheduler this is normally a task control block. + * The pxOwner parameter effectively creates a two way link between the list + * item and its owner. + * + * @param pxList The list from which the owner of the head item is to be + * returned. + * + * \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY + * \ingroup LinkedList + */ +#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner ) + +/* + * Check to see if a list item is within a list. The list item maintains a + * "container" pointer that points to the list it is in. All this macro does + * is check to see if the container and the list match. + * + * @param pxList The list we want to know if the list item is within. + * @param pxListItem The list item we want to know if is in the list. + * @return pdTRUE if the list item is in the list, otherwise pdFALSE. + */ +#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( BaseType_t ) ( ( pxListItem )->pvContainer == ( void * ) ( pxList ) ) ) + +/* + * Return the list a list item is contained within (referenced from). + * + * @param pxListItem The list item being queried. + * @return A pointer to the List_t object that references the pxListItem + */ +#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pvContainer ) + +/* + * This provides a crude means of knowing if a list has been initialised, as + * pxList->xListEnd.xItemValue is set to portMAX_DELAY by the vListInitialise() + * function. + */ +#define listLIST_IS_INITIALISED( pxList ) ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY ) + +/* + * Must be called before a list is used! This initialises all the members + * of the list structure and inserts the xListEnd item into the list as a + * marker to the back of the list. + * + * @param pxList Pointer to the list being initialised. + * + * \page vListInitialise vListInitialise + * \ingroup LinkedList + */ +void vListInitialise(List_t *const pxList) PRIVILEGED_FUNCTION; + +/* + * Must be called before a list item is used. This sets the list container to + * null so the item does not think that it is already contained in a list. + * + * @param pxItem Pointer to the list item being initialised. + * + * \page vListInitialiseItem vListInitialiseItem + * \ingroup LinkedList + */ +void vListInitialiseItem(ListItem_t *const pxItem) PRIVILEGED_FUNCTION; + +/* + * Insert a list item into a list. The item will be inserted into the list in + * a position determined by its item value (descending item value order). + * + * @param pxList The list into which the item is to be inserted. + * + * @param pxNewListItem The item that is to be placed in the list. + * + * \page vListInsert vListInsert + * \ingroup LinkedList + */ +void vListInsert(List_t *const pxList, ListItem_t *const pxNewListItem) PRIVILEGED_FUNCTION; + +/* + * Insert a list item into a list. The item will be inserted in a position + * such that it will be the last item within the list returned by multiple + * calls to listGET_OWNER_OF_NEXT_ENTRY. + * + * The list member pxIndex is used to walk through a list. Calling + * listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list. + * Placing an item in a list using vListInsertEnd effectively places the item + * in the list position pointed to by pxIndex. This means that every other + * item within the list will be returned by listGET_OWNER_OF_NEXT_ENTRY before + * the pxIndex parameter again points to the item being inserted. + * + * @param pxList The list into which the item is to be inserted. + * + * @param pxNewListItem The list item to be inserted into the list. + * + * \page vListInsertEnd vListInsertEnd + * \ingroup LinkedList + */ +void vListInsertEnd(List_t *const pxList, ListItem_t *const pxNewListItem) PRIVILEGED_FUNCTION; + +/* + * Remove an item from a list. The list item has a pointer to the list that + * it is in, so only the list item need be passed into the function. + * + * @param uxListRemove The item to be removed. The item will remove itself from + * the list pointed to by it's pxContainer parameter. + * + * @return The number of items that remain in the list after the list item has + * been removed. + * + * \page uxListRemove uxListRemove + * \ingroup LinkedList + */ +UBaseType_t uxListRemove(ListItem_t *const pxItemToRemove) PRIVILEGED_FUNCTION; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include_lib/system/os/FreeRTOS/mpu_wrappers.h b/include_lib/system/os/FreeRTOS/mpu_wrappers.h new file mode 100644 index 0000000..2ba287b --- /dev/null +++ b/include_lib/system/os/FreeRTOS/mpu_wrappers.h @@ -0,0 +1,201 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef MPU_WRAPPERS_H +#define MPU_WRAPPERS_H + +/* This file redefines API functions to be called through a wrapper macro, but +only for ports that are using the MPU. */ +#ifdef portUSING_MPU_WRAPPERS + +/* MPU_WRAPPERS_INCLUDED_FROM_API_FILE will be defined when this file is +included from queue.c or task.c to prevent it from having an effect within +those files. */ +#ifndef MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +/* + * Map standard (non MPU) API functions to equivalents that start + * "MPU_". This will cause the application code to call the MPU_ + * version, which wraps the non-MPU version with privilege promoting + * then demoting code, so the kernel code always runs will full + * privileges. + */ + +/* Map standard tasks.h API functions to the MPU equivalents. */ +#define xTaskCreate MPU_xTaskCreate +#define xTaskCreateStatic MPU_xTaskCreateStatic +#define xTaskCreateRestricted MPU_xTaskCreateRestricted +#define vTaskAllocateMPURegions MPU_vTaskAllocateMPURegions +#define vTaskDelete MPU_vTaskDelete +#define vTaskDelay MPU_vTaskDelay +#define vTaskDelayUntil MPU_vTaskDelayUntil +#define xTaskAbortDelay MPU_xTaskAbortDelay +#define uxTaskPriorityGet MPU_uxTaskPriorityGet +#define eTaskGetState MPU_eTaskGetState +#define vTaskGetInfo MPU_vTaskGetInfo +#define vTaskPrioritySet MPU_vTaskPrioritySet +#define vTaskSuspend MPU_vTaskSuspend +#define vTaskResume MPU_vTaskResume +#define vTaskSuspendAll MPU_vTaskSuspendAll +#define xTaskResumeAll MPU_xTaskResumeAll +#define xTaskGetTickCount MPU_xTaskGetTickCount +#define uxTaskGetNumberOfTasks MPU_uxTaskGetNumberOfTasks +#define pcTaskGetName MPU_pcTaskGetName +#define xTaskGetHandle MPU_xTaskGetHandle +#define uxTaskGetStackHighWaterMark MPU_uxTaskGetStackHighWaterMark +#define vTaskSetApplicationTaskTag MPU_vTaskSetApplicationTaskTag +#define xTaskGetApplicationTaskTag MPU_xTaskGetApplicationTaskTag +#define vTaskSetThreadLocalStoragePointer MPU_vTaskSetThreadLocalStoragePointer +#define pvTaskGetThreadLocalStoragePointer MPU_pvTaskGetThreadLocalStoragePointer +#define xTaskCallApplicationTaskHook MPU_xTaskCallApplicationTaskHook +#define xTaskGetIdleTaskHandle MPU_xTaskGetIdleTaskHandle +#define uxTaskGetSystemState MPU_uxTaskGetSystemState +#define vTaskList MPU_vTaskList +#define vTaskGetRunTimeStats MPU_vTaskGetRunTimeStats +#define xTaskGenericNotify MPU_xTaskGenericNotify +#define xTaskNotifyWait MPU_xTaskNotifyWait +#define ulTaskNotifyTake MPU_ulTaskNotifyTake +#define xTaskNotifyStateClear MPU_xTaskNotifyStateClear + +#define xTaskGetCurrentTaskHandle MPU_xTaskGetCurrentTaskHandle +#define vTaskSetTimeOutState MPU_vTaskSetTimeOutState +#define xTaskCheckForTimeOut MPU_xTaskCheckForTimeOut +#define xTaskGetSchedulerState MPU_xTaskGetSchedulerState + +/* Map standard queue.h API functions to the MPU equivalents. */ +#define xQueueGenericSend MPU_xQueueGenericSend +#define xQueueGenericReceive MPU_xQueueGenericReceive +#define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting +#define uxQueueSpacesAvailable MPU_uxQueueSpacesAvailable +#define vQueueDelete MPU_vQueueDelete +#define xQueueCreateMutex MPU_xQueueCreateMutex +#define xQueueCreateMutexStatic MPU_xQueueCreateMutexStatic +#define xQueueCreateCountingSemaphore MPU_xQueueCreateCountingSemaphore +#define xQueueCreateCountingSemaphoreStatic MPU_xQueueCreateCountingSemaphoreStatic +#define xQueueGetMutexHolder MPU_xQueueGetMutexHolder +#define xQueueTakeMutexRecursive MPU_xQueueTakeMutexRecursive +#define xQueueGiveMutexRecursive MPU_xQueueGiveMutexRecursive +#define xQueueGenericCreate MPU_xQueueGenericCreate +#define xQueueGenericCreateStatic MPU_xQueueGenericCreateStatic +#define xQueueCreateSet MPU_xQueueCreateSet +#define xQueueAddToSet MPU_xQueueAddToSet +#define xQueueRemoveFromSet MPU_xQueueRemoveFromSet +#define xQueueSelectFromSet MPU_xQueueSelectFromSet +#define xQueueGenericReset MPU_xQueueGenericReset + +#if( configQUEUE_REGISTRY_SIZE > 0 ) +#define vQueueAddToRegistry MPU_vQueueAddToRegistry +#define vQueueUnregisterQueue MPU_vQueueUnregisterQueue +#define pcQueueGetName MPU_pcQueueGetName +#endif + +/* Map standard timer.h API functions to the MPU equivalents. */ +#define xTimerCreate MPU_xTimerCreate +#define xTimerCreateStatic MPU_xTimerCreateStatic +#define pvTimerGetTimerID MPU_pvTimerGetTimerID +#define vTimerSetTimerID MPU_vTimerSetTimerID +#define xTimerIsTimerActive MPU_xTimerIsTimerActive +#define xTimerGetTimerDaemonTaskHandle MPU_xTimerGetTimerDaemonTaskHandle +#define xTimerPendFunctionCall MPU_xTimerPendFunctionCall +#define pcTimerGetName MPU_pcTimerGetName +#define xTimerGetPeriod MPU_xTimerGetPeriod +#define xTimerGetExpiryTime MPU_xTimerGetExpiryTime +#define xTimerGenericCommand MPU_xTimerGenericCommand + +/* Map standard event_group.h API functions to the MPU equivalents. */ +#define xEventGroupCreate MPU_xEventGroupCreate +#define xEventGroupCreateStatic MPU_xEventGroupCreateStatic +#define xEventGroupWaitBits MPU_xEventGroupWaitBits +#define xEventGroupClearBits MPU_xEventGroupClearBits +#define xEventGroupSetBits MPU_xEventGroupSetBits +#define xEventGroupSync MPU_xEventGroupSync +#define vEventGroupDelete MPU_vEventGroupDelete + +/* Remove the privileged function macro. */ +#define PRIVILEGED_FUNCTION + +#else /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */ + +/* Ensure API functions go in the privileged execution section. */ +#define PRIVILEGED_FUNCTION __attribute__((section("privileged_functions"))) +#define PRIVILEGED_DATA __attribute__((section("privileged_data"))) + +#endif /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */ + +#else /* portUSING_MPU_WRAPPERS */ + +#define PRIVILEGED_FUNCTION +#define PRIVILEGED_DATA +#define portUSING_MPU_WRAPPERS 0 + +#endif /* portUSING_MPU_WRAPPERS */ + + +#endif /* MPU_WRAPPERS_H */ + diff --git a/include_lib/system/os/FreeRTOS/pi32_lto/portmacro.h b/include_lib/system/os/FreeRTOS/pi32_lto/portmacro.h new file mode 100644 index 0000000..fbacdf2 --- /dev/null +++ b/include_lib/system/os/FreeRTOS/pi32_lto/portmacro.h @@ -0,0 +1,263 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef PORTMACRO_H +#define PORTMACRO_H +#include "asm/cpu.h" +#include +/****************************************************************************** + Defines +******************************************************************************/ +/* Type definitions. */ +#define portCHAR char +#define portFLOAT float +#define portDOUBLE double +#define portLONG long +#define portSHORT short +#define portSTACK_TYPE int +#define portBASE_TYPE long +#define portPOINTER_SIZE_TYPE size_t + +typedef portSTACK_TYPE StackType_t; +typedef long BaseType_t; +typedef unsigned long UBaseType_t; + + +#if( configUSE_16_BIT_TICKS == 1 ) +typedef uint16_t TickType_t; +#define portMAX_DELAY ( TickType_t ) 0xffff +#else +typedef uint32_t TickType_t; +#define portMAX_DELAY ( TickType_t ) 0xffffffffUL + +/* 32/64-bit tick type on a 32/64-bit architecture, so reads of the tick +count do not need to be guarded with a critical section. */ +#define portTICK_TYPE_IS_ATOMIC 1 +#endif + +/* Hardware specifics. */ +#define portSTACK_GROWTH ( -1 ) +#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) +#define portINLINE __inline + +#if defined( __x86_64__) || defined( _M_X64 ) +#define portBYTE_ALIGNMENT 8 +#else +#define portBYTE_ALIGNMENT 4 +#endif +extern void vPortYield() ; +#define portYIELD() vPortYield() +#define OS_CPU_ID current_cpu_id() +extern int current_cpu_id() ; +#define OS_CPU_NUM CPU_CORE_NUM + +/* Simulated interrupts return pdFALSE if no context switch should be performed, +or a non-zero number if a context switch should be performed. */ +#define portYIELD_FROM_ISR( x ) return x +#define portEND_SWITCHING_ISR( x ) portYIELD_FROM_ISR( ( x ) ) + +void vPortCloseRunningThread(void *pvTaskToDelete, volatile BaseType_t *pxPendYield); +//void vPortDeleteThread( void *pvThreadToDelete ); +#define portCLEAN_UP_TCB( pxTCB ) //vPortDeleteThread( pxTCB ) +#define portPRE_TASK_DELETE_HOOK( pvTaskToDelete, pxPendYield ) //vPortCloseRunningThread( ( pvTaskToDelete ), ( pxPendYield ) ) +#define portDISABLE_INTERRUPTS() CPU_CRITICAL_ENTER() +#define portENABLE_INTERRUPTS() CPU_CRITICAL_EXIT() + + +/* Critical section handling. */ +void vPortEnterCritical(void); +void vPortExitCritical(void); +//extern void * malloc(int ) ; +//extern void free(void *) ; + +//#define pvPortMalloc malloc +//#define vPortFree free + +/* + extern volatile int cpu_lock_cnt[]; + extern volatile int irq_lock_cnt[]; +#define __asm_csync() \ + do { \ + asm volatile("csync;"); \ + asm volatile("csync;"); \ + asm volatile("csync;"); \ + asm volatile("csync;"); \ + asm volatile("csync;"); \ + } while (0) + + static inline void local_irq_disable() + { + __builtin_pi32v2_cli(); + irq_lock_cnt[current_cpu_id()]++; + } + + + static inline void local_irq_enable() + { + if (--irq_lock_cnt[current_cpu_id()] == 0) { + __builtin_pi32v2_sti(); + } + } + + + #define CPU_CRITICAL_ENTER() \ + do { \ + local_irq_disable(); \ + if(cpu_lock_cnt[current_cpu_id()]++ == 0) \ + asm volatile("lockset;"); \ + __asm_csync(); \ + }while(0) + + + #define CPU_CRITICAL_EXIT() \ + do { \ + if (--cpu_lock_cnt[current_cpu_id()] == 0) \ + asm volatile("lockclr;"); \ + local_irq_enable();\ + }while(0) + +*/ + + +#define portENTER_CRITICAL() CPU_CRITICAL_ENTER() // vPortEnterCritical() +#define portEXIT_CRITICAL() CPU_CRITICAL_EXIT() // vPortExitCritical() + + +#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#endif + +#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 + +extern __attribute__((always_inline)) uint32_t ucPortCountLeadingZeros(uint32_t ulBitmap); + +/* Check the configuration. */ +#if( configMAX_PRIORITIES > 32 ) +#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice. +#endif + +/* Store/clear the ready priorities in a bit map. */ +#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) ) +#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) \ + do { \ + ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) ); \ + } while (0) + + +/*-----------------------------------------------------------*/ + +// uxTopPriority = __builtin_pi32v2_clz(uxReadyPriorities) +#ifdef __GNUC__ +#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - ucPortCountLeadingZeros( ( uxReadyPriorities ) ) ) +#else +/* BitScanReverse returns the bit position of the most significant '1' +in the word. */ +#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) _BitScanReverse( ( DWORD * ) &( uxTopPriority ), ( uxReadyPriorities ) ) +#endif /* __GNUC__ */ + +#endif /* taskRECORD_READY_PRIORITY */ + +#ifndef __GNUC__ +__pragma(warning(disable: 4211)) /* Nonstandard extension used, as extern is only nonstandard to MSVC. */ +#endif + + +/* Task function macros as described on the FreeRTOS.org WEB site. */ +#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) +#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) + +#define portINTERRUPT_YIELD ( 0UL ) +#define portINTERRUPT_TICK ( 1UL ) + +/* + * Raise a simulated interrupt represented by the bit mask in ulInterruptMask. + * Each bit can be used to represent an individual interrupt - with the first + * two bits being used for the Yield and Tick interrupts respectively. +*/ +void vPortGenerateSimulatedInterrupt(uint32_t ulInterruptNumber); + +/* + * Install an interrupt handler to be called by the simulated interrupt handler + * thread. The interrupt number must be above any used by the kernel itself + * (at the time of writing the kernel was using interrupt numbers 0, 1, and 2 + * as defined above). The number must also be lower than 32. + * + * Interrupt handler functions must return a non-zero value if executing the + * handler resulted in a task switch being required. + */ +void vPortSetInterruptHandler(uint32_t ulInterruptNumber, uint32_t (*pvHandler)(void)); + +/* Tickless idle/low power functionality. */ +#ifndef portSUPPRESS_TICKS_AND_SLEEP +extern void vPortSuppressTicksAndSleep(TickType_t xExpectedIdleTime); +#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime ) +#endif + +#endif + diff --git a/include_lib/system/os/FreeRTOS/pi32v2/portmacro.h b/include_lib/system/os/FreeRTOS/pi32v2/portmacro.h new file mode 100644 index 0000000..48fc79f --- /dev/null +++ b/include_lib/system/os/FreeRTOS/pi32v2/portmacro.h @@ -0,0 +1,262 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef PORTMACRO_H +#define PORTMACRO_H +#include "asm/cpu.h" +#include +/****************************************************************************** + Defines +******************************************************************************/ +/* Type definitions. */ +#define portCHAR char +#define portFLOAT float +#define portDOUBLE double +#define portLONG long +#define portSHORT short +#define portSTACK_TYPE int +#define portBASE_TYPE long +#define portPOINTER_SIZE_TYPE size_t + +typedef portSTACK_TYPE StackType_t; +typedef long BaseType_t; +typedef unsigned long UBaseType_t; + + +#if( configUSE_16_BIT_TICKS == 1 ) +typedef uint16_t TickType_t; +#define portMAX_DELAY ( TickType_t ) 0xffff +#else +typedef uint32_t TickType_t; +#define portMAX_DELAY ( TickType_t ) 0xffffffffUL + +/* 32/64-bit tick type on a 32/64-bit architecture, so reads of the tick +count do not need to be guarded with a critical section. */ +#define portTICK_TYPE_IS_ATOMIC 1 +#endif + +/* Hardware specifics. */ +#define portSTACK_GROWTH ( -1 ) +#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) +#define portINLINE __inline + +#if defined( __x86_64__) || defined( _M_X64 ) +#define portBYTE_ALIGNMENT 8 +#else +#define portBYTE_ALIGNMENT 4 +#endif +extern void vPortYield() ; +#define portYIELD() vPortYield() +#define OS_CPU_ID current_cpu_id() +extern int current_cpu_id() ; +#define OS_CPU_NUM CPU_CORE_NUM + +/* Simulated interrupts return pdFALSE if no context switch should be performed, +or a non-zero number if a context switch should be performed. */ +#define portYIELD_FROM_ISR( x ) return x +#define portEND_SWITCHING_ISR( x ) portYIELD_FROM_ISR( ( x ) ) + +void vPortCloseRunningThread(void *pvTaskToDelete, volatile BaseType_t *pxPendYield); +//void vPortDeleteThread( void *pvThreadToDelete ); +#define portCLEAN_UP_TCB( pxTCB ) //vPortDeleteThread( pxTCB ) +#define portPRE_TASK_DELETE_HOOK( pvTaskToDelete, pxPendYield ) //vPortCloseRunningThread( ( pvTaskToDelete ), ( pxPendYield ) ) +#define portDISABLE_INTERRUPTS() CPU_CRITICAL_ENTER() +#define portENABLE_INTERRUPTS() CPU_CRITICAL_EXIT() + + +/* Critical section handling. */ +void vPortEnterCritical(void); +void vPortExitCritical(void); +//extern void * malloc(int ) ; +//extern void free(void *) ; + +//#define pvPortMalloc malloc +//#define vPortFree free + +/* + extern volatile int cpu_lock_cnt[]; + extern volatile int irq_lock_cnt[]; +#define __asm_csync() \ + do { \ + asm volatile("csync;"); \ + asm volatile("csync;"); \ + asm volatile("csync;"); \ + asm volatile("csync;"); \ + asm volatile("csync;"); \ + } while (0) + + static inline void local_irq_disable() + { + __builtin_pi32v2_cli(); + irq_lock_cnt[current_cpu_id()]++; + } + + + static inline void local_irq_enable() + { + if (--irq_lock_cnt[current_cpu_id()] == 0) { + __builtin_pi32v2_sti(); + } + } + + + #define CPU_CRITICAL_ENTER() \ + do { \ + local_irq_disable(); \ + if(cpu_lock_cnt[current_cpu_id()]++ == 0) \ + asm volatile("lockset;"); \ + __asm_csync(); \ + }while(0) + + + #define CPU_CRITICAL_EXIT() \ + do { \ + if (--cpu_lock_cnt[current_cpu_id()] == 0) \ + asm volatile("lockclr;"); \ + local_irq_enable();\ + }while(0) + +*/ + + +#define portENTER_CRITICAL() CPU_CRITICAL_ENTER() // vPortEnterCritical() +#define portEXIT_CRITICAL() CPU_CRITICAL_EXIT() // vPortExitCritical() + + +#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#endif + +#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 + +/* Check the configuration. */ +#if( configMAX_PRIORITIES > 32 ) +#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice. +#endif + +/* Store/clear the ready priorities in a bit map. */ +#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) ) +#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) \ + do { \ + ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) ); \ + } while (0) + + +/*-----------------------------------------------------------*/ + +// uxTopPriority = __builtin_pi32v2_clz(uxReadyPriorities) +#ifdef __GNUC__ +#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) \ + uxTopPriority = 31- __builtin_clz(uxReadyPriorities) +#else +/* BitScanReverse returns the bit position of the most significant '1' +in the word. */ +#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) _BitScanReverse( ( DWORD * ) &( uxTopPriority ), ( uxReadyPriorities ) ) +#endif /* __GNUC__ */ + +#endif /* taskRECORD_READY_PRIORITY */ + +#ifndef __GNUC__ +__pragma(warning(disable: 4211)) /* Nonstandard extension used, as extern is only nonstandard to MSVC. */ +#endif + + +/* Task function macros as described on the FreeRTOS.org WEB site. */ +#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) +#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) + +#define portINTERRUPT_YIELD ( 0UL ) +#define portINTERRUPT_TICK ( 1UL ) + +/* + * Raise a simulated interrupt represented by the bit mask in ulInterruptMask. + * Each bit can be used to represent an individual interrupt - with the first + * two bits being used for the Yield and Tick interrupts respectively. +*/ +void vPortGenerateSimulatedInterrupt(uint32_t ulInterruptNumber); + +/* + * Install an interrupt handler to be called by the simulated interrupt handler + * thread. The interrupt number must be above any used by the kernel itself + * (at the time of writing the kernel was using interrupt numbers 0, 1, and 2 + * as defined above). The number must also be lower than 32. + * + * Interrupt handler functions must return a non-zero value if executing the + * handler resulted in a task switch being required. + */ +void vPortSetInterruptHandler(uint32_t ulInterruptNumber, uint32_t (*pvHandler)(void)); + +/* Tickless idle/low power functionality. */ +#ifndef portSUPPRESS_TICKS_AND_SLEEP +extern void vPortSuppressTicksAndSleep(TickType_t xExpectedIdleTime); +#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime ) +#endif + +#endif + diff --git a/include_lib/system/os/FreeRTOS/portable.h b/include_lib/system/os/FreeRTOS/portable.h new file mode 100644 index 0000000..5baccf5 --- /dev/null +++ b/include_lib/system/os/FreeRTOS/portable.h @@ -0,0 +1,206 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/*----------------------------------------------------------- + * Portable layer API. Each function must be defined for each port. + *----------------------------------------------------------*/ + +#ifndef PORTABLE_H +#define PORTABLE_H + +/* Each FreeRTOS port has a unique portmacro.h header file. Originally a +pre-processor definition was used to ensure the pre-processor found the correct +portmacro.h file for the port being used. That scheme was deprecated in favour +of setting the compiler's include path such that it found the correct +portmacro.h file - removing the need for the constant and allowing the +portmacro.h file to be located anywhere in relation to the port being used. +Purely for reasons of backward compatibility the old method is still valid, but +to make it clear that new projects should not use it, support for the port +specific constants has been moved into the deprecated_definitions.h header +file. */ +#include "deprecated_definitions.h" + +/* If portENTER_CRITICAL is not defined then including deprecated_definitions.h +did not result in a portmacro.h header file being included - and it should be +included here. In this case the path to the correct portmacro.h header file +must be set in the compiler's include path. */ +#ifndef portENTER_CRITICAL +#include "portmacro.h" +#endif + +#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 portNUM_CONFIGURABLE_REGIONS +#define portNUM_CONFIGURABLE_REGIONS 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mpu_wrappers.h" + +/* + * Setup the stack of a new task so it is ready to be placed under the + * scheduler control. The registers have to be placed on the stack in + * the order that the port expects to find them. + * + */ +#if( portUSING_MPU_WRAPPERS == 1 ) +StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged) PRIVILEGED_FUNCTION; +#else +StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters) PRIVILEGED_FUNCTION; +#endif + +/* Used by heap_5.c. */ +typedef struct HeapRegion { + uint8_t *pucStartAddress; + size_t xSizeInBytes; +} HeapRegion_t; + +/* + * Used to define multiple heap regions for use by heap_5.c. This function + * must be called before any calls to pvPortMalloc() - not creating a task, + * queue, semaphore, mutex, software timer, event group, etc. will result in + * pvPortMalloc being called. + * + * pxHeapRegions passes in an array of HeapRegion_t structures - each of which + * defines a region of memory that can be used as the heap. The array is + * terminated by a HeapRegions_t structure that has a size of 0. The region + * with the lowest start address must appear first in the array. + */ +void vPortDefineHeapRegions(const HeapRegion_t *const pxHeapRegions) PRIVILEGED_FUNCTION; + + +/* + * Map to the memory management routines required for the port. + */ +void *pvPortMalloc(size_t xSize) PRIVILEGED_FUNCTION; +void vPortFree(void *pv) PRIVILEGED_FUNCTION; +void vPortInitialiseBlocks(void) PRIVILEGED_FUNCTION; +// size_t xPortGetFreeHeapSize(void) PRIVILEGED_FUNCTION; +// size_t xPortGetMinimumEverFreeHeapSize(void) PRIVILEGED_FUNCTION; + +/* + * Setup the hardware ready for the scheduler to take control. This generally + * sets up a tick interrupt and sets timers for the correct tick frequency. + */ +BaseType_t xPortStartScheduler(void) PRIVILEGED_FUNCTION; + +/* + * Undo any hardware/ISR setup that was performed by xPortStartScheduler() so + * the hardware is left in its original condition after the scheduler stops + * executing. + */ +void vPortEndScheduler(void) PRIVILEGED_FUNCTION; + +/* + * The structures and methods of manipulating the MPU are contained within the + * port layer. + * + * Fills the xMPUSettings structure with the memory region information + * contained in xRegions. + */ +#if( portUSING_MPU_WRAPPERS == 1 ) +struct xMEMORY_REGION; +void vPortStoreTaskMPUSettings(xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION *const xRegions, StackType_t *pxBottomOfStack, uint32_t ulStackDepth) PRIVILEGED_FUNCTION; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PORTABLE_H */ + diff --git a/include_lib/system/os/FreeRTOS/projdefs.h b/include_lib/system/os/FreeRTOS/projdefs.h new file mode 100644 index 0000000..d73ca18 --- /dev/null +++ b/include_lib/system/os/FreeRTOS/projdefs.h @@ -0,0 +1,161 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef PROJDEFS_H +#define PROJDEFS_H + +/* + * Defines the prototype to which task functions must conform. Defined in this + * file to ensure the type is known before portable.h is included. + */ +typedef void (*TaskFunction_t)(void *); + +/* Converts a time in milliseconds to a time in ticks. This macro can be +overridden by a macro of the same name defined in FreeRTOSConfig.h in case the +definition here is not suitable for your application. */ +#ifndef pdMS_TO_TICKS +#define pdMS_TO_TICKS( xTimeInMs ) ( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * ( TickType_t ) configTICK_RATE_HZ ) / ( TickType_t ) 1000 ) ) +#endif + +#define pdFALSE ( ( BaseType_t ) 0 ) +#define pdTRUE ( ( BaseType_t ) 1 ) + +#define pdPASS ( pdTRUE ) +#define pdFAIL ( pdFALSE ) +#define errQUEUE_EMPTY ( ( BaseType_t ) 0 ) +#define errQUEUE_FULL ( ( BaseType_t ) 0 ) + +/* FreeRTOS error definitions. */ +#define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ( -1 ) +#define errQUEUE_BLOCKED ( -4 ) +#define errQUEUE_YIELD ( -5 ) + +/* Macros used for basic data corruption checks. */ +#ifndef configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES +#define configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 0 +#endif + +#if( configUSE_16_BIT_TICKS == 1 ) +#define pdINTEGRITY_CHECK_VALUE 0x5a5a +#else +#define pdINTEGRITY_CHECK_VALUE 0x5a5a5a5aUL +#endif + +/* The following errno values are used by FreeRTOS+ components, not FreeRTOS +itself. */ +#define pdFREERTOS_ERRNO_NONE 0 /* No errors */ +#define pdFREERTOS_ERRNO_ENOENT 2 /* No such file or directory */ +#define pdFREERTOS_ERRNO_EINTR 4 /* Interrupted system call */ +#define pdFREERTOS_ERRNO_EIO 5 /* I/O error */ +#define pdFREERTOS_ERRNO_ENXIO 6 /* No such device or address */ +#define pdFREERTOS_ERRNO_EBADF 9 /* Bad file number */ +#define pdFREERTOS_ERRNO_EAGAIN 11 /* No more processes */ +#define pdFREERTOS_ERRNO_EWOULDBLOCK 11 /* Operation would block */ +#define pdFREERTOS_ERRNO_ENOMEM 12 /* Not enough memory */ +#define pdFREERTOS_ERRNO_EACCES 13 /* Permission denied */ +#define pdFREERTOS_ERRNO_EFAULT 14 /* Bad address */ +#define pdFREERTOS_ERRNO_EBUSY 16 /* Mount device busy */ +#define pdFREERTOS_ERRNO_EEXIST 17 /* File exists */ +#define pdFREERTOS_ERRNO_EXDEV 18 /* Cross-device link */ +#define pdFREERTOS_ERRNO_ENODEV 19 /* No such device */ +#define pdFREERTOS_ERRNO_ENOTDIR 20 /* Not a directory */ +#define pdFREERTOS_ERRNO_EISDIR 21 /* Is a directory */ +#define pdFREERTOS_ERRNO_EINVAL 22 /* Invalid argument */ +#define pdFREERTOS_ERRNO_ENOSPC 28 /* No space left on device */ +#define pdFREERTOS_ERRNO_ESPIPE 29 /* Illegal seek */ +#define pdFREERTOS_ERRNO_EROFS 30 /* Read only file system */ +#define pdFREERTOS_ERRNO_EUNATCH 42 /* Protocol driver not attached */ +#define pdFREERTOS_ERRNO_EBADE 50 /* Invalid exchange */ +#define pdFREERTOS_ERRNO_EFTYPE 79 /* Inappropriate file type or format */ +#define pdFREERTOS_ERRNO_ENMFILE 89 /* No more files */ +#define pdFREERTOS_ERRNO_ENOTEMPTY 90 /* Directory not empty */ +#define pdFREERTOS_ERRNO_ENAMETOOLONG 91 /* File or path name too long */ +#define pdFREERTOS_ERRNO_EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define pdFREERTOS_ERRNO_ENOBUFS 105 /* No buffer space available */ +#define pdFREERTOS_ERRNO_ENOPROTOOPT 109 /* Protocol not available */ +#define pdFREERTOS_ERRNO_EADDRINUSE 112 /* Address already in use */ +#define pdFREERTOS_ERRNO_ETIMEDOUT 116 /* Connection timed out */ +#define pdFREERTOS_ERRNO_EINPROGRESS 119 /* Connection already in progress */ +#define pdFREERTOS_ERRNO_EALREADY 120 /* Socket already connected */ +#define pdFREERTOS_ERRNO_EADDRNOTAVAIL 125 /* Address not available */ +#define pdFREERTOS_ERRNO_EISCONN 127 /* Socket is already connected */ +#define pdFREERTOS_ERRNO_ENOTCONN 128 /* Socket is not connected */ +#define pdFREERTOS_ERRNO_ENOMEDIUM 135 /* No medium inserted */ +#define pdFREERTOS_ERRNO_EILSEQ 138 /* An invalid UTF-16 sequence was encountered. */ +#define pdFREERTOS_ERRNO_ECANCELED 140 /* Operation canceled. */ + +/* The following endian values are used by FreeRTOS+ components, not FreeRTOS +itself. */ +#define pdFREERTOS_LITTLE_ENDIAN 0 +#define pdFREERTOS_BIG_ENDIAN 1 + +#endif /* PROJDEFS_H */ + + + diff --git a/include_lib/system/os/FreeRTOS/q32s/portmacro.h b/include_lib/system/os/FreeRTOS/q32s/portmacro.h new file mode 100644 index 0000000..898bc74 --- /dev/null +++ b/include_lib/system/os/FreeRTOS/q32s/portmacro.h @@ -0,0 +1,262 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef PORTMACRO_H +#define PORTMACRO_H +#include "asm/cpu.h" +#include +/****************************************************************************** + Defines +******************************************************************************/ +/* Type definitions. */ +#define portCHAR char +#define portFLOAT float +#define portDOUBLE double +#define portLONG long +#define portSHORT short +#define portSTACK_TYPE int +#define portBASE_TYPE long +#define portPOINTER_SIZE_TYPE size_t + +typedef portSTACK_TYPE StackType_t; +typedef long BaseType_t; +typedef unsigned long UBaseType_t; + + +#if( configUSE_16_BIT_TICKS == 1 ) +typedef uint16_t TickType_t; +#define portMAX_DELAY ( TickType_t ) 0xffff +#else +typedef uint32_t TickType_t; +#define portMAX_DELAY ( TickType_t ) 0xffffffffUL + +/* 32/64-bit tick type on a 32/64-bit architecture, so reads of the tick +count do not need to be guarded with a critical section. */ +#define portTICK_TYPE_IS_ATOMIC 1 +#endif + +/* Hardware specifics. */ +#define portSTACK_GROWTH ( -1 ) +#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) +#define portINLINE __inline + +#if defined( __x86_64__) || defined( _M_X64 ) +#define portBYTE_ALIGNMENT 8 +#else +#define portBYTE_ALIGNMENT 4 +#endif +extern void vPortYield() ; +#define portYIELD() vPortYield() +#define OS_CPU_ID current_cpu_id() +extern int current_cpu_id() ; +#define OS_CPU_NUM CPU_CORE_NUM + +/* Simulated interrupts return pdFALSE if no context switch should be performed, +or a non-zero number if a context switch should be performed. */ +#define portYIELD_FROM_ISR( x ) return x +#define portEND_SWITCHING_ISR( x ) portYIELD_FROM_ISR( ( x ) ) + +void vPortCloseRunningThread(void *pvTaskToDelete, volatile BaseType_t *pxPendYield); +//void vPortDeleteThread( void *pvThreadToDelete ); +#define portCLEAN_UP_TCB( pxTCB ) //vPortDeleteThread( pxTCB ) +#define portPRE_TASK_DELETE_HOOK( pvTaskToDelete, pxPendYield ) //vPortCloseRunningThread( ( pvTaskToDelete ), ( pxPendYield ) ) +#define portDISABLE_INTERRUPTS() CPU_CRITICAL_ENTER() +#define portENABLE_INTERRUPTS() CPU_CRITICAL_EXIT() + + +/* Critical section handling. */ +void vPortEnterCritical(void); +void vPortExitCritical(void); +//extern void * malloc(int ) ; +//extern void free(void *) ; + +//#define pvPortMalloc malloc +//#define vPortFree free + +/* + extern volatile int cpu_lock_cnt[]; + extern volatile int irq_lock_cnt[]; +#define __asm_csync() \ + do { \ + asm volatile("csync;"); \ + asm volatile("csync;"); \ + asm volatile("csync;"); \ + asm volatile("csync;"); \ + asm volatile("csync;"); \ + } while (0) + + static inline void local_irq_disable() + { + __builtin_pi32v2_cli(); + irq_lock_cnt[current_cpu_id()]++; + } + + + static inline void local_irq_enable() + { + if (--irq_lock_cnt[current_cpu_id()] == 0) { + __builtin_pi32v2_sti(); + } + } + + + #define CPU_CRITICAL_ENTER() \ + do { \ + local_irq_disable(); \ + if(cpu_lock_cnt[current_cpu_id()]++ == 0) \ + asm volatile("lockset;"); \ + __asm_csync(); \ + }while(0) + + + #define CPU_CRITICAL_EXIT() \ + do { \ + if (--cpu_lock_cnt[current_cpu_id()] == 0) \ + asm volatile("lockclr;"); \ + local_irq_enable();\ + }while(0) + +*/ + + +#define portENTER_CRITICAL() CPU_CRITICAL_ENTER() // vPortEnterCritical() +#define portEXIT_CRITICAL() CPU_CRITICAL_EXIT() // vPortExitCritical() + + +#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#endif + +#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 + +/* Check the configuration. */ +#if( configMAX_PRIORITIES > 32 ) +#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice. +#endif + +/* Store/clear the ready priorities in a bit map. */ +#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) ) +#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) \ + do { \ + ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) ); \ + } while (0) + + +/*-----------------------------------------------------------*/ + +// uxTopPriority = __builtin_pi32v2_clz(uxReadyPriorities) +#ifdef __GNUC__ +#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) \ + uxTopPriority = 31- __builtin_clz(uxReadyPriorities) +#else +/* BitScanReverse returns the bit position of the most significant '1' +in the word. */ +#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) _BitScanReverse( ( DWORD * ) &( uxTopPriority ), ( uxReadyPriorities ) ) +#endif /* __GNUC__ */ + +#endif /* taskRECORD_READY_PRIORITY */ + +#ifndef __GNUC__ +__pragma(warning(disable: 4211)) /* Nonstandard extension used, as extern is only nonstandard to MSVC. */ +#endif + + +/* Task function macros as described on the FreeRTOS.org WEB site. */ +#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) +#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) + +#define portINTERRUPT_YIELD ( 0UL ) +#define portINTERRUPT_TICK ( 1UL ) + +/* + * Raise a simulated interrupt represented by the bit mask in ulInterruptMask. + * Each bit can be used to represent an individual interrupt - with the first + * two bits being used for the Yield and Tick interrupts respectively. +*/ +void vPortGenerateSimulatedInterrupt(uint32_t ulInterruptNumber); + +/* + * Install an interrupt handler to be called by the simulated interrupt handler + * thread. The interrupt number must be above any used by the kernel itself + * (at the time of writing the kernel was using interrupt numbers 0, 1, and 2 + * as defined above). The number must also be lower than 32. + * + * Interrupt handler functions must return a non-zero value if executing the + * handler resulted in a task switch being required. + */ +void vPortSetInterruptHandler(uint32_t ulInterruptNumber, uint32_t (*pvHandler)(void)); + +/* Tickless idle/low power functionality. */ +#ifndef portSUPPRESS_TICKS_AND_SLEEP +// extern void vPortSuppressTicksAndSleep(TickType_t xExpectedIdleTime); +// #define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime ) +#endif + +#endif + diff --git a/include_lib/system/os/FreeRTOS/queue.h b/include_lib/system/os/FreeRTOS/queue.h new file mode 100644 index 0000000..a90cfca --- /dev/null +++ b/include_lib/system/os/FreeRTOS/queue.h @@ -0,0 +1,1799 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#ifndef QUEUE_H +#define QUEUE_H + +#ifndef INC_FREERTOS_H +#error "include FreeRTOS.h" must appear in source files before "include queue.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Type by which queues are referenced. For example, a call to xQueueCreate() + * returns an QueueHandle_t variable that can then be used as a parameter to + * xQueueSend(), xQueueReceive(), etc. + */ +typedef void *QueueHandle_t; + +/** + * Type by which queue sets are referenced. For example, a call to + * xQueueCreateSet() returns an xQueueSet variable that can then be used as a + * parameter to xQueueSelectFromSet(), xQueueAddToSet(), etc. + */ +typedef void *QueueSetHandle_t; + +/** + * Queue sets can contain both queues and semaphores, so the + * QueueSetMemberHandle_t is defined as a type to be used where a parameter or + * return value can be either an QueueHandle_t or an SemaphoreHandle_t. + */ +typedef void *QueueSetMemberHandle_t; + +/* For internal use only. */ +#define queueSEND_TO_BACK ( ( BaseType_t ) 0 ) +#define queueSEND_TO_FRONT ( ( BaseType_t ) 1 ) +#define queueOVERWRITE ( ( BaseType_t ) 2 ) + +/* For internal use only. These definitions *must* match those in queue.c. */ +#define queueQUEUE_TYPE_SET ( ( uint8_t ) 0U ) +#define queueQUEUE_TYPE_MUTEX ( ( uint8_t ) 1U ) +#define queueQUEUE_TYPE_COUNTING_SEMAPHORE ( ( uint8_t ) 2U ) +#define queueQUEUE_TYPE_BINARY_SEMAPHORE ( ( uint8_t ) 3U ) +#define queueQUEUE_TYPE_RECURSIVE_MUTEX ( ( uint8_t ) 4U ) +#define queueQUEUE_TYPE_BASE ( ( uint8_t ) 5U ) + +/** + * queue. h + *
+ QueueHandle_t xQueueCreate(
+							  UBaseType_t uxQueueLength,
+							  UBaseType_t uxItemSize
+						  );
+ * 
+ * + * Creates a new queue instance, and returns a handle by which the new queue + * can be referenced. + * + * Internally, within the FreeRTOS implementation, queues use two blocks of + * memory. The first block is used to hold the queue's data structures. The + * second block is used to hold items placed into the queue. If a queue is + * created using xQueueCreate() then both blocks of memory are automatically + * dynamically allocated inside the xQueueCreate() function. (see + * http://www.freertos.org/a00111.html). If a queue is created using + * xQueueCreateStatic() then the application writer must provide the memory that + * will get used by the queue. xQueueCreateStatic() therefore allows a queue to + * be created without using any dynamic memory allocation. + * + * http://www.FreeRTOS.org/Embedded-RTOS-Queues.html + * + * @param uxQueueLength The maximum number of items that the queue can contain. + * + * @param uxItemSize The number of bytes each item in the queue will require. + * Items are queued by copy, not by reference, so this is the number of bytes + * that will be copied for each posted item. Each item on the queue must be + * the same size. + * + * @return If the queue is successfully create then a handle to the newly + * created queue is returned. If the queue cannot be created then 0 is + * returned. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ };
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1, xQueue2;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( 10, sizeof( uint32_t ) );
+	if( xQueue1 == 0 )
+	{
+		// Queue was not created and must not be used.
+	}
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+	if( xQueue2 == 0 )
+	{
+		// Queue was not created and must not be used.
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueCreate xQueueCreate + * \ingroup QueueManagement + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) +#define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) ) +#endif + +/** + * queue. h + *
+ QueueHandle_t xQueueCreateStatic(
+							  UBaseType_t uxQueueLength,
+							  UBaseType_t uxItemSize,
+							  uint8_t *pucQueueStorageBuffer,
+							  StaticQueue_t *pxQueueBuffer
+						  );
+ * 
+ * + * Creates a new queue instance, and returns a handle by which the new queue + * can be referenced. + * + * Internally, within the FreeRTOS implementation, queues use two blocks of + * memory. The first block is used to hold the queue's data structures. The + * second block is used to hold items placed into the queue. If a queue is + * created using xQueueCreate() then both blocks of memory are automatically + * dynamically allocated inside the xQueueCreate() function. (see + * http://www.freertos.org/a00111.html). If a queue is created using + * xQueueCreateStatic() then the application writer must provide the memory that + * will get used by the queue. xQueueCreateStatic() therefore allows a queue to + * be created without using any dynamic memory allocation. + * + * http://www.FreeRTOS.org/Embedded-RTOS-Queues.html + * + * @param uxQueueLength The maximum number of items that the queue can contain. + * + * @param uxItemSize The number of bytes each item in the queue will require. + * Items are queued by copy, not by reference, so this is the number of bytes + * that will be copied for each posted item. Each item on the queue must be + * the same size. + * + * @param pucQueueStorageBuffer If uxItemSize is not zero then + * pucQueueStorageBuffer must point to a uint8_t array that is at least large + * enough to hold the maximum number of items that can be in the queue at any + * one time - which is ( uxQueueLength * uxItemsSize ) bytes. If uxItemSize is + * zero then pucQueueStorageBuffer can be NULL. + * + * @param pxQueueBuffer Must point to a variable of type StaticQueue_t, which + * will be used to hold the queue's data structure. + * + * @return If the queue is created then a handle to the created queue is + * returned. If pxQueueBuffer is NULL then NULL is returned. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ };
+
+ #define QUEUE_LENGTH 10
+ #define ITEM_SIZE sizeof( uint32_t )
+
+ // xQueueBuffer will hold the queue structure.
+ StaticQueue_t xQueueBuffer;
+
+ // ucQueueStorage will hold the items posted to the queue.  Must be at least
+ // [(queue length) * ( queue item size)] bytes long.
+ uint8_t ucQueueStorage[ QUEUE_LENGTH * ITEM_SIZE ];
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( QUEUE_LENGTH, // The number of items the queue can hold.
+							ITEM_SIZE	  // The size of each item in the queue
+							&( ucQueueStorage[ 0 ] ), // The buffer that will hold the items in the queue.
+							&xQueueBuffer ); // The buffer that will hold the queue structure.
+
+	// The queue is guaranteed to be created successfully as no dynamic memory
+	// allocation is used.  Therefore xQueue1 is now a handle to a valid queue.
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueCreateStatic xQueueCreateStatic + * \ingroup QueueManagement + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) +#define xQueueCreateStatic( uxQueueLength, uxItemSize, pucQueueStorage, pxQueueBuffer ) xQueueGenericCreateStatic( ( uxQueueLength ), ( uxItemSize ), ( pucQueueStorage ), ( pxQueueBuffer ), ( queueQUEUE_TYPE_BASE ) ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +/** + * queue. h + *
+ BaseType_t xQueueSendToToFront(
+								   QueueHandle_t	xQueue,
+								   const void		*pvItemToQueue,
+								   TickType_t		xTicksToWait
+							   );
+ * 
+ * + * This is a macro that calls xQueueGenericSend(). + * + * Post an item to the front of a queue. The item is queued by copy, not by + * reference. This function must not be called from an interrupt service + * routine. See xQueueSendFromISR () for an alternative which may be used + * in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0 and the + * queue is full. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ uint32_t ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( 10, sizeof( uint32_t ) );
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+	// ...
+
+	if( xQueue1 != 0 )
+	{
+		// Send an uint32_t.  Wait for 10 ticks for space to become
+		// available if necessary.
+		if( xQueueSendToFront( xQueue1, ( void * ) &ulVar, ( TickType_t ) 10 ) != pdPASS )
+		{
+			// Failed to post the message, even after 10 ticks.
+		}
+	}
+
+	if( xQueue2 != 0 )
+	{
+		// Send a pointer to a struct AMessage object.  Don't block if the
+		// queue is already full.
+		pxMessage = & xMessage;
+		xQueueSendToFront( xQueue2, ( void * ) &pxMessage, ( TickType_t ) 0 );
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT ) + +/** + * queue. h + *
+ BaseType_t xQueueSendToBack(
+								   QueueHandle_t	xQueue,
+								   const void		*pvItemToQueue,
+								   TickType_t		xTicksToWait
+							   );
+ * 
+ * + * This is a macro that calls xQueueGenericSend(). + * + * Post an item to the back of a queue. The item is queued by copy, not by + * reference. This function must not be called from an interrupt service + * routine. See xQueueSendFromISR () for an alternative which may be used + * in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0 and the queue + * is full. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ uint32_t ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( 10, sizeof( uint32_t ) );
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+	// ...
+
+	if( xQueue1 != 0 )
+	{
+		// Send an uint32_t.  Wait for 10 ticks for space to become
+		// available if necessary.
+		if( xQueueSendToBack( xQueue1, ( void * ) &ulVar, ( TickType_t ) 10 ) != pdPASS )
+		{
+			// Failed to post the message, even after 10 ticks.
+		}
+	}
+
+	if( xQueue2 != 0 )
+	{
+		// Send a pointer to a struct AMessage object.  Don't block if the
+		// queue is already full.
+		pxMessage = & xMessage;
+		xQueueSendToBack( xQueue2, ( void * ) &pxMessage, ( TickType_t ) 0 );
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK ) + +/** + * queue. h + *
+ BaseType_t xQueueSend(
+							  QueueHandle_t xQueue,
+							  const void * pvItemToQueue,
+							  TickType_t xTicksToWait
+						 );
+ * 
+ * + * This is a macro that calls xQueueGenericSend(). It is included for + * backward compatibility with versions of FreeRTOS.org that did not + * include the xQueueSendToFront() and xQueueSendToBack() macros. It is + * equivalent to xQueueSendToBack(). + * + * Post an item on a queue. The item is queued by copy, not by reference. + * This function must not be called from an interrupt service routine. + * See xQueueSendFromISR () for an alternative which may be used in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0 and the + * queue is full. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ uint32_t ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( 10, sizeof( uint32_t ) );
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+	// ...
+
+	if( xQueue1 != 0 )
+	{
+		// Send an uint32_t.  Wait for 10 ticks for space to become
+		// available if necessary.
+		if( xQueueSend( xQueue1, ( void * ) &ulVar, ( TickType_t ) 10 ) != pdPASS )
+		{
+			// Failed to post the message, even after 10 ticks.
+		}
+	}
+
+	if( xQueue2 != 0 )
+	{
+		// Send a pointer to a struct AMessage object.  Don't block if the
+		// queue is already full.
+		pxMessage = & xMessage;
+		xQueueSend( xQueue2, ( void * ) &pxMessage, ( TickType_t ) 0 );
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK ) + +/** + * queue. h + *
+ BaseType_t xQueueOverwrite(
+							  QueueHandle_t xQueue,
+							  const void * pvItemToQueue
+						 );
+ * 
+ * + * Only for use with queues that have a length of one - so the queue is either + * empty or full. + * + * Post an item on a queue. If the queue is already full then overwrite the + * value held in the queue. The item is queued by copy, not by reference. + * + * This function must not be called from an interrupt service routine. + * See xQueueOverwriteFromISR () for an alternative which may be used in an ISR. + * + * @param xQueue The handle of the queue to which the data is being sent. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @return xQueueOverwrite() is a macro that calls xQueueGenericSend(), and + * therefore has the same return values as xQueueSendToFront(). However, pdPASS + * is the only value that can be returned because xQueueOverwrite() will write + * to the queue even when the queue is already full. + * + * Example usage: +
+
+ void vFunction( void *pvParameters )
+ {
+ QueueHandle_t xQueue;
+ uint32_t ulVarToSend, ulValReceived;
+
+	// Create a queue to hold one uint32_t value.  It is strongly
+	// recommended *not* to use xQueueOverwrite() on queues that can
+	// contain more than one value, and doing so will trigger an assertion
+	// if configASSERT() is defined.
+	xQueue = xQueueCreate( 1, sizeof( uint32_t ) );
+
+	// Write the value 10 to the queue using xQueueOverwrite().
+	ulVarToSend = 10;
+	xQueueOverwrite( xQueue, &ulVarToSend );
+
+	// Peeking the queue should now return 10, but leave the value 10 in
+	// the queue.  A block time of zero is used as it is known that the
+	// queue holds a value.
+	ulValReceived = 0;
+	xQueuePeek( xQueue, &ulValReceived, 0 );
+
+	if( ulValReceived != 10 )
+	{
+		// Error unless the item was removed by a different task.
+	}
+
+	// The queue is still full.  Use xQueueOverwrite() to overwrite the
+	// value held in the queue with 100.
+	ulVarToSend = 100;
+	xQueueOverwrite( xQueue, &ulVarToSend );
+
+	// This time read from the queue, leaving the queue empty once more.
+	// A block time of 0 is used again.
+	xQueueReceive( xQueue, &ulValReceived, 0 );
+
+	// The value read should be the last value written, even though the
+	// queue was already full when the value was written.
+	if( ulValReceived != 100 )
+	{
+		// Error!
+	}
+
+	// ...
+}
+ 
+ * \defgroup xQueueOverwrite xQueueOverwrite + * \ingroup QueueManagement + */ +#define xQueueOverwrite( xQueue, pvItemToQueue ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), 0, queueOVERWRITE ) + + +/** + * queue. h + *
+ BaseType_t xQueueGenericSend(
+									QueueHandle_t xQueue,
+									const void * pvItemToQueue,
+									TickType_t xTicksToWait
+									BaseType_t xCopyPosition
+								);
+ * 
+ * + * It is preferred that the macros xQueueSend(), xQueueSendToFront() and + * xQueueSendToBack() are used in place of calling this function directly. + * + * Post an item on a queue. The item is queued by copy, not by reference. + * This function must not be called from an interrupt service routine. + * See xQueueSendFromISR () for an alternative which may be used in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0 and the + * queue is full. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * + * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the + * item at the back of the queue, or queueSEND_TO_FRONT to place the item + * at the front of the queue (for high priority messages). + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ uint32_t ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( 10, sizeof( uint32_t ) );
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+	// ...
+
+	if( xQueue1 != 0 )
+	{
+		// Send an uint32_t.  Wait for 10 ticks for space to become
+		// available if necessary.
+		if( xQueueGenericSend( xQueue1, ( void * ) &ulVar, ( TickType_t ) 10, queueSEND_TO_BACK ) != pdPASS )
+		{
+			// Failed to post the message, even after 10 ticks.
+		}
+	}
+
+	if( xQueue2 != 0 )
+	{
+		// Send a pointer to a struct AMessage object.  Don't block if the
+		// queue is already full.
+		pxMessage = & xMessage;
+		xQueueGenericSend( xQueue2, ( void * ) &pxMessage, ( TickType_t ) 0, queueSEND_TO_BACK );
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +BaseType_t xQueueGenericSend(QueueHandle_t xQueue, const void *const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
+ BaseType_t xQueuePeek(
+							 QueueHandle_t xQueue,
+							 void *pvBuffer,
+							 TickType_t xTicksToWait
+						 );
+ * + * This is a macro that calls the xQueueGenericReceive() function. + * + * Receive an item from a queue without removing the item from the queue. + * The item is received by copy so a buffer of adequate size must be + * provided. The number of bytes copied into the buffer was defined when + * the queue was created. + * + * Successfully received items remain on the queue so will be returned again + * by the next call, or a call to xQueueReceive(). + * + * This macro must not be used in an interrupt service routine. See + * xQueuePeekFromISR() for an alternative that can be called from an interrupt + * service routine. + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * xQueuePeek() will return immediately if xTicksToWait is 0 and the queue + * is empty. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ QueueHandle_t xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+	if( xQueue == 0 )
+	{
+		// Failed to create the queue.
+	}
+
+	// ...
+
+	// Send a pointer to a struct AMessage object.  Don't block if the
+	// queue is already full.
+	pxMessage = & xMessage;
+	xQueueSend( xQueue, ( void * ) &pxMessage, ( TickType_t ) 0 );
+
+	// ... Rest of task code.
+ }
+
+ // Task to peek the data from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+	if( xQueue != 0 )
+	{
+		// Peek a message on the created queue.  Block for 10 ticks if a
+		// message is not immediately available.
+		if( xQueuePeek( xQueue, &( pxRxedMessage ), ( TickType_t ) 10 ) )
+		{
+			// pcRxedMessage now points to the struct AMessage variable posted
+			// by vATask, but the item still remains on the queue.
+		}
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueReceive xQueueReceive + * \ingroup QueueManagement + */ +#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE ) + +/** + * queue. h + *
+ BaseType_t xQueuePeekFromISR(
+									QueueHandle_t xQueue,
+									void *pvBuffer,
+								);
+ * + * A version of xQueuePeek() that can be called from an interrupt service + * routine (ISR). + * + * Receive an item from a queue without removing the item from the queue. + * The item is received by copy so a buffer of adequate size must be + * provided. The number of bytes copied into the buffer was defined when + * the queue was created. + * + * Successfully received items remain on the queue so will be returned again + * by the next call, or a call to xQueueReceive(). + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * \defgroup xQueuePeekFromISR xQueuePeekFromISR + * \ingroup QueueManagement + */ +BaseType_t xQueuePeekFromISR(QueueHandle_t xQueue, void *const pvBuffer) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
+ BaseType_t xQueueReceive(
+								 QueueHandle_t xQueue,
+								 void *pvBuffer,
+								 TickType_t xTicksToWait
+							);
+ * + * This is a macro that calls the xQueueGenericReceive() function. + * + * Receive an item from a queue. The item is received by copy so a buffer of + * adequate size must be provided. The number of bytes copied into the buffer + * was defined when the queue was created. + * + * Successfully received items are removed from the queue. + * + * This function must not be used in an interrupt service routine. See + * xQueueReceiveFromISR for an alternative that can. + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. xQueueReceive() will return immediately if xTicksToWait + * is zero and the queue is empty. The time is defined in tick periods so the + * constant portTICK_PERIOD_MS should be used to convert to real time if this is + * required. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ QueueHandle_t xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+	if( xQueue == 0 )
+	{
+		// Failed to create the queue.
+	}
+
+	// ...
+
+	// Send a pointer to a struct AMessage object.  Don't block if the
+	// queue is already full.
+	pxMessage = & xMessage;
+	xQueueSend( xQueue, ( void * ) &pxMessage, ( TickType_t ) 0 );
+
+	// ... Rest of task code.
+ }
+
+ // Task to receive from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+	if( xQueue != 0 )
+	{
+		// Receive a message on the created queue.  Block for 10 ticks if a
+		// message is not immediately available.
+		if( xQueueReceive( xQueue, &( pxRxedMessage ), ( TickType_t ) 10 ) )
+		{
+			// pcRxedMessage now points to the struct AMessage variable posted
+			// by vATask.
+		}
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueReceive xQueueReceive + * \ingroup QueueManagement + */ +#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE ) + + +/** + * queue. h + *
+ BaseType_t xQueueGenericReceive(
+									   QueueHandle_t	xQueue,
+									   void	*pvBuffer,
+									   TickType_t	xTicksToWait
+									   BaseType_t	xJustPeek
+									);
+ * + * It is preferred that the macro xQueueReceive() be used rather than calling + * this function directly. + * + * Receive an item from a queue. The item is received by copy so a buffer of + * adequate size must be provided. The number of bytes copied into the buffer + * was defined when the queue was created. + * + * This function must not be used in an interrupt service routine. See + * xQueueReceiveFromISR for an alternative that can. + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * xQueueGenericReceive() will return immediately if the queue is empty and + * xTicksToWait is 0. + * + * @param xJustPeek When set to true, the item received from the queue is not + * actually removed from the queue - meaning a subsequent call to + * xQueueReceive() will return the same item. When set to false, the item + * being received from the queue is also removed from the queue. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ QueueHandle_t xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+	if( xQueue == 0 )
+	{
+		// Failed to create the queue.
+	}
+
+	// ...
+
+	// Send a pointer to a struct AMessage object.  Don't block if the
+	// queue is already full.
+	pxMessage = & xMessage;
+	xQueueSend( xQueue, ( void * ) &pxMessage, ( TickType_t ) 0 );
+
+	// ... Rest of task code.
+ }
+
+ // Task to receive from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+	if( xQueue != 0 )
+	{
+		// Receive a message on the created queue.  Block for 10 ticks if a
+		// message is not immediately available.
+		if( xQueueGenericReceive( xQueue, &( pxRxedMessage ), ( TickType_t ) 10 ) )
+		{
+			// pcRxedMessage now points to the struct AMessage variable posted
+			// by vATask.
+		}
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueReceive xQueueReceive + * \ingroup QueueManagement + */ +BaseType_t xQueueGenericReceive(QueueHandle_t xQueue, void *const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeek) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
UBaseType_t uxQueueMessagesWaiting( const QueueHandle_t xQueue );
+ * + * Return the number of messages stored in a queue. + * + * @param xQueue A handle to the queue being queried. + * + * @return The number of messages available in the queue. + * + * \defgroup uxQueueMessagesWaiting uxQueueMessagesWaiting + * \ingroup QueueManagement + */ +UBaseType_t uxQueueMessagesWaiting(const QueueHandle_t xQueue) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQueue );
+ * + * Return the number of free spaces available in a queue. This is equal to the + * number of items that can be sent to the queue before the queue becomes full + * if no items are removed. + * + * @param xQueue A handle to the queue being queried. + * + * @return The number of spaces available in the queue. + * + * \defgroup uxQueueMessagesWaiting uxQueueMessagesWaiting + * \ingroup QueueManagement + */ +UBaseType_t uxQueueSpacesAvailable(const QueueHandle_t xQueue) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
void vQueueDelete( QueueHandle_t xQueue );
+ * + * Delete a queue - freeing all the memory allocated for storing of items + * placed on the queue. + * + * @param xQueue A handle to the queue to be deleted. + * + * \defgroup vQueueDelete vQueueDelete + * \ingroup QueueManagement + */ +void vQueueDelete(QueueHandle_t xQueue) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
+ BaseType_t xQueueSendToFrontFromISR(
+										 QueueHandle_t xQueue,
+										 const void *pvItemToQueue,
+										 BaseType_t *pxHigherPriorityTaskWoken
+									  );
+ 
+ * + * This is a macro that calls xQueueGenericSendFromISR(). + * + * Post an item to the front of a queue. It is safe to use this macro from + * within an interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueSendToFrontFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueSendToFromFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the data was successfully sent to the queue, otherwise + * errQUEUE_FULL. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ char cIn;
+ BaseType_t xHigherPrioritTaskWoken;
+
+	// We have not woken a task at the start of the ISR.
+	xHigherPriorityTaskWoken = pdFALSE;
+
+	// Loop until the buffer is empty.
+	do
+	{
+		// Obtain a byte from the buffer.
+		cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+		// Post the byte.
+		xQueueSendToFrontFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+	} while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+	// Now the buffer is empty we can switch context if necessary.
+	if( xHigherPriorityTaskWoken )
+	{
+		taskYIELD ();
+	}
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +#define xQueueSendToFrontFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_FRONT ) + + +/** + * queue. h + *
+ BaseType_t xQueueSendToBackFromISR(
+										 QueueHandle_t xQueue,
+										 const void *pvItemToQueue,
+										 BaseType_t *pxHigherPriorityTaskWoken
+									  );
+ 
+ * + * This is a macro that calls xQueueGenericSendFromISR(). + * + * Post an item to the back of a queue. It is safe to use this macro from + * within an interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueSendToBackFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueSendToBackFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the data was successfully sent to the queue, otherwise + * errQUEUE_FULL. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ char cIn;
+ BaseType_t xHigherPriorityTaskWoken;
+
+	// We have not woken a task at the start of the ISR.
+	xHigherPriorityTaskWoken = pdFALSE;
+
+	// Loop until the buffer is empty.
+	do
+	{
+		// Obtain a byte from the buffer.
+		cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+		// Post the byte.
+		xQueueSendToBackFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+	} while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+	// Now the buffer is empty we can switch context if necessary.
+	if( xHigherPriorityTaskWoken )
+	{
+		taskYIELD ();
+	}
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +#define xQueueSendToBackFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK ) + +/** + * queue. h + *
+ BaseType_t xQueueOverwriteFromISR(
+							  QueueHandle_t xQueue,
+							  const void * pvItemToQueue,
+							  BaseType_t *pxHigherPriorityTaskWoken
+						 );
+ * 
+ * + * A version of xQueueOverwrite() that can be used in an interrupt service + * routine (ISR). + * + * Only for use with queues that can hold a single item - so the queue is either + * empty or full. + * + * Post an item on a queue. If the queue is already full then overwrite the + * value held in the queue. The item is queued by copy, not by reference. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueOverwriteFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueOverwriteFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return xQueueOverwriteFromISR() is a macro that calls + * xQueueGenericSendFromISR(), and therefore has the same return values as + * xQueueSendToFrontFromISR(). However, pdPASS is the only value that can be + * returned because xQueueOverwriteFromISR() will write to the queue even when + * the queue is already full. + * + * Example usage: +
+
+ QueueHandle_t xQueue;
+
+ void vFunction( void *pvParameters )
+ {
+ 	// Create a queue to hold one uint32_t value.  It is strongly
+	// recommended *not* to use xQueueOverwriteFromISR() on queues that can
+	// contain more than one value, and doing so will trigger an assertion
+	// if configASSERT() is defined.
+	xQueue = xQueueCreate( 1, sizeof( uint32_t ) );
+}
+
+void vAnInterruptHandler( void )
+{
+// xHigherPriorityTaskWoken must be set to pdFALSE before it is used.
+BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+uint32_t ulVarToSend, ulValReceived;
+
+	// Write the value 10 to the queue using xQueueOverwriteFromISR().
+	ulVarToSend = 10;
+	xQueueOverwriteFromISR( xQueue, &ulVarToSend, &xHigherPriorityTaskWoken );
+
+	// The queue is full, but calling xQueueOverwriteFromISR() again will still
+	// pass because the value held in the queue will be overwritten with the
+	// new value.
+	ulVarToSend = 100;
+	xQueueOverwriteFromISR( xQueue, &ulVarToSend, &xHigherPriorityTaskWoken );
+
+	// Reading from the queue will now return 100.
+
+	// ...
+
+	if( xHigherPrioritytaskWoken == pdTRUE )
+	{
+		// Writing to the queue caused a task to unblock and the unblocked task
+		// has a priority higher than or equal to the priority of the currently
+		// executing task (the task this interrupt interrupted).  Perform a context
+		// switch so this interrupt returns directly to the unblocked task.
+		portYIELD_FROM_ISR(); // or portEND_SWITCHING_ISR() depending on the port.
+	}
+}
+ 
+ * \defgroup xQueueOverwriteFromISR xQueueOverwriteFromISR + * \ingroup QueueManagement + */ +#define xQueueOverwriteFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueOVERWRITE ) + +/** + * queue. h + *
+ BaseType_t xQueueSendFromISR(
+									 QueueHandle_t xQueue,
+									 const void *pvItemToQueue,
+									 BaseType_t *pxHigherPriorityTaskWoken
+								);
+ 
+ * + * This is a macro that calls xQueueGenericSendFromISR(). It is included + * for backward compatibility with versions of FreeRTOS.org that did not + * include the xQueueSendToBackFromISR() and xQueueSendToFrontFromISR() + * macros. + * + * Post an item to the back of a queue. It is safe to use this function from + * within an interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueSendFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueSendFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the data was successfully sent to the queue, otherwise + * errQUEUE_FULL. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ char cIn;
+ BaseType_t xHigherPriorityTaskWoken;
+
+	// We have not woken a task at the start of the ISR.
+	xHigherPriorityTaskWoken = pdFALSE;
+
+	// Loop until the buffer is empty.
+	do
+	{
+		// Obtain a byte from the buffer.
+		cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+		// Post the byte.
+		xQueueSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+	} while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+	// Now the buffer is empty we can switch context if necessary.
+	if( xHigherPriorityTaskWoken )
+	{
+		// Actual macro used here is port specific.
+		portYIELD_FROM_ISR ();
+	}
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +#define xQueueSendFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK ) + +/** + * queue. h + *
+ BaseType_t xQueueGenericSendFromISR(
+										   QueueHandle_t		xQueue,
+										   const	void	*pvItemToQueue,
+										   BaseType_t	*pxHigherPriorityTaskWoken,
+										   BaseType_t	xCopyPosition
+									   );
+ 
+ * + * It is preferred that the macros xQueueSendFromISR(), + * xQueueSendToFrontFromISR() and xQueueSendToBackFromISR() be used in place + * of calling this function directly. xQueueGiveFromISR() is an + * equivalent for use by semaphores that don't actually copy any data. + * + * Post an item on a queue. It is safe to use this function from within an + * interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueGenericSendFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueGenericSendFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the + * item at the back of the queue, or queueSEND_TO_FRONT to place the item + * at the front of the queue (for high priority messages). + * + * @return pdTRUE if the data was successfully sent to the queue, otherwise + * errQUEUE_FULL. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ char cIn;
+ BaseType_t xHigherPriorityTaskWokenByPost;
+
+	// We have not woken a task at the start of the ISR.
+	xHigherPriorityTaskWokenByPost = pdFALSE;
+
+	// Loop until the buffer is empty.
+	do
+	{
+		// Obtain a byte from the buffer.
+		cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+		// Post each byte.
+		xQueueGenericSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWokenByPost, queueSEND_TO_BACK );
+
+	} while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+	// Now the buffer is empty we can switch context if necessary.  Note that the
+	// name of the yield function required is port specific.
+	if( xHigherPriorityTaskWokenByPost )
+	{
+		taskYIELD_YIELD_FROM_ISR();
+	}
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +BaseType_t xQueueGenericSendFromISR(QueueHandle_t xQueue, const void *const pvItemToQueue, BaseType_t *const pxHigherPriorityTaskWoken, const BaseType_t xCopyPosition) PRIVILEGED_FUNCTION; +BaseType_t xQueueGiveFromISR(QueueHandle_t xQueue, BaseType_t *const pxHigherPriorityTaskWoken) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
+ BaseType_t xQueueReceiveFromISR(
+									   QueueHandle_t	xQueue,
+									   void	*pvBuffer,
+									   BaseType_t *pxTaskWoken
+								   );
+ * 
+ * + * Receive an item from a queue. It is safe to use this function from within an + * interrupt service routine. + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param pxTaskWoken A task may be blocked waiting for space to become + * available on the queue. If xQueueReceiveFromISR causes such a task to + * unblock *pxTaskWoken will get set to pdTRUE, otherwise *pxTaskWoken will + * remain unchanged. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+
+ QueueHandle_t xQueue;
+
+ // Function to create a queue and post some values.
+ void vAFunction( void *pvParameters )
+ {
+ char cValueToPost;
+ const TickType_t xTicksToWait = ( TickType_t )0xff;
+
+	// Create a queue capable of containing 10 characters.
+	xQueue = xQueueCreate( 10, sizeof( char ) );
+	if( xQueue == 0 )
+	{
+		// Failed to create the queue.
+	}
+
+	// ...
+
+	// Post some characters that will be used within an ISR.  If the queue
+	// is full then this task will block for xTicksToWait ticks.
+	cValueToPost = 'a';
+	xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait );
+	cValueToPost = 'b';
+	xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait );
+
+	// ... keep posting characters ... this task may block when the queue
+	// becomes full.
+
+	cValueToPost = 'c';
+	xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait );
+ }
+
+ // ISR that outputs all the characters received on the queue.
+ void vISR_Routine( void )
+ {
+ BaseType_t xTaskWokenByReceive = pdFALSE;
+ char cRxedChar;
+
+	while( xQueueReceiveFromISR( xQueue, ( void * ) &cRxedChar, &xTaskWokenByReceive) )
+	{
+		// A character was received.  Output the character now.
+		vOutputCharacter( cRxedChar );
+
+		// If removing the character from the queue woke the task that was
+		// posting onto the queue cTaskWokenByReceive will have been set to
+		// pdTRUE.  No matter how many times this loop iterates only one
+		// task will be woken.
+	}
+
+	if( cTaskWokenByPost != ( char ) pdFALSE;
+	{
+		taskYIELD ();
+	}
+ }
+ 
+ * \defgroup xQueueReceiveFromISR xQueueReceiveFromISR + * \ingroup QueueManagement + */ +BaseType_t xQueueReceiveFromISR(QueueHandle_t xQueue, void *const pvBuffer, BaseType_t *const pxHigherPriorityTaskWoken) PRIVILEGED_FUNCTION; + +/* + * Utilities to query queues that are safe to use from an ISR. These utilities + * should be used only from witin an ISR, or within a critical section. + */ +BaseType_t xQueueIsQueueEmptyFromISR(const QueueHandle_t xQueue) PRIVILEGED_FUNCTION; +BaseType_t xQueueIsQueueFullFromISR(const QueueHandle_t xQueue) PRIVILEGED_FUNCTION; +UBaseType_t uxQueueMessagesWaitingFromISR(const QueueHandle_t xQueue) PRIVILEGED_FUNCTION; + +/* + * The functions defined above are for passing data to and from tasks. The + * functions below are the equivalents for passing data to and from + * co-routines. + * + * These functions are called from the co-routine macro implementation and + * should not be called directly from application code. Instead use the macro + * wrappers defined within croutine.h. + */ +BaseType_t xQueueCRSendFromISR(QueueHandle_t xQueue, const void *pvItemToQueue, BaseType_t xCoRoutinePreviouslyWoken); +BaseType_t xQueueCRReceiveFromISR(QueueHandle_t xQueue, void *pvBuffer, BaseType_t *pxTaskWoken); +BaseType_t xQueueCRSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait); +BaseType_t xQueueCRReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait); + +/* + * For internal use only. Use xSemaphoreCreateMutex(), + * xSemaphoreCreateCounting() or xSemaphoreGetMutexHolder() instead of calling + * these functions directly. + */ +QueueHandle_t xQueueCreateMutex(const uint8_t ucQueueType) PRIVILEGED_FUNCTION; +QueueHandle_t xQueueCreateMutexStatic(const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue) PRIVILEGED_FUNCTION; +QueueHandle_t xQueueCreateCountingSemaphore(const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount) PRIVILEGED_FUNCTION; +QueueHandle_t xQueueCreateCountingSemaphoreStatic(const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue) PRIVILEGED_FUNCTION; +void *xQueueGetMutexHolder(QueueHandle_t xSemaphore) PRIVILEGED_FUNCTION; + +/* + * For internal use only. Use xSemaphoreTakeMutexRecursive() or + * xSemaphoreGiveMutexRecursive() instead of calling these functions directly. + */ +BaseType_t xQueueTakeMutexRecursive(QueueHandle_t xMutex, TickType_t xTicksToWait) PRIVILEGED_FUNCTION; +BaseType_t xQueueGiveMutexRecursive(QueueHandle_t pxMutex) PRIVILEGED_FUNCTION; + +/* + * Reset a queue back to its original empty state. The return value is now + * obsolete and is always set to pdPASS. + */ +#define xQueueReset( xQueue ) xQueueGenericReset( xQueue, pdFALSE ) + +/* + * The registry is provided as a means for kernel aware debuggers to + * locate queues, semaphores and mutexes. Call vQueueAddToRegistry() add + * a queue, semaphore or mutex handle to the registry if you want the handle + * to be available to a kernel aware debugger. If you are not using a kernel + * aware debugger then this function can be ignored. + * + * configQUEUE_REGISTRY_SIZE defines the maximum number of handles the + * registry can hold. configQUEUE_REGISTRY_SIZE must be greater than 0 + * within FreeRTOSConfig.h for the registry to be available. Its value + * does not effect the number of queues, semaphores and mutexes that can be + * created - just the number that the registry can hold. + * + * @param xQueue The handle of the queue being added to the registry. This + * is the handle returned by a call to xQueueCreate(). Semaphore and mutex + * handles can also be passed in here. + * + * @param pcName The name to be associated with the handle. This is the + * name that the kernel aware debugger will display. The queue registry only + * stores a pointer to the string - so the string must be persistent (global or + * preferably in ROM/Flash), not on the stack. + */ +#if( configQUEUE_REGISTRY_SIZE > 0 ) +void vQueueAddToRegistry(QueueHandle_t xQueue, const char *pcName) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif + +/* + * The registry is provided as a means for kernel aware debuggers to + * locate queues, semaphores and mutexes. Call vQueueAddToRegistry() add + * a queue, semaphore or mutex handle to the registry if you want the handle + * to be available to a kernel aware debugger, and vQueueUnregisterQueue() to + * remove the queue, semaphore or mutex from the register. If you are not using + * a kernel aware debugger then this function can be ignored. + * + * @param xQueue The handle of the queue being removed from the registry. + */ +#if( configQUEUE_REGISTRY_SIZE > 0 ) +void vQueueUnregisterQueue(QueueHandle_t xQueue) PRIVILEGED_FUNCTION; +#endif + +/* + * The queue registry is provided as a means for kernel aware debuggers to + * locate queues, semaphores and mutexes. Call pcQueueGetName() to look + * up and return the name of a queue in the queue registry from the queue's + * handle. + * + * @param xQueue The handle of the queue the name of which will be returned. + * @return If the queue is in the registry then a pointer to the name of the + * queue is returned. If the queue is not in the registry then NULL is + * returned. + */ +#if( configQUEUE_REGISTRY_SIZE > 0 ) +const char *pcQueueGetName(QueueHandle_t xQueue) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif + +/* + * Generic version of the function used to creaet a queue using dynamic memory + * allocation. This is called by other functions and macros that create other + * RTOS objects that use the queue structure as their base. + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) +QueueHandle_t xQueueGenericCreate(const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType) PRIVILEGED_FUNCTION; +#endif + +/* + * Generic version of the function used to creaet a queue using dynamic memory + * allocation. This is called by other functions and macros that create other + * RTOS objects that use the queue structure as their base. + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) +QueueHandle_t xQueueGenericCreateStatic(const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType) PRIVILEGED_FUNCTION; +#endif + +/* + * Queue sets provide a mechanism to allow a task to block (pend) on a read + * operation from multiple queues or semaphores simultaneously. + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * A queue set must be explicitly created using a call to xQueueCreateSet() + * before it can be used. Once created, standard FreeRTOS queues and semaphores + * can be added to the set using calls to xQueueAddToSet(). + * xQueueSelectFromSet() is then used to determine which, if any, of the queues + * or semaphores contained in the set is in a state where a queue read or + * semaphore take operation would be successful. + * + * Note 1: See the documentation on http://wwwFreeRTOS.org/RTOS-queue-sets.html + * for reasons why queue sets are very rarely needed in practice as there are + * simpler methods of blocking on multiple objects. + * + * Note 2: Blocking on a queue set that contains a mutex will not cause the + * mutex holder to inherit the priority of the blocked task. + * + * Note 3: An additional 4 bytes of RAM is required for each space in a every + * queue added to a queue set. Therefore counting semaphores that have a high + * maximum count value should not be added to a queue set. + * + * Note 4: A receive (in the case of a queue) or take (in the case of a + * semaphore) operation must not be performed on a member of a queue set unless + * a call to xQueueSelectFromSet() has first returned a handle to that set member. + * + * @param uxEventQueueLength Queue sets store events that occur on + * the queues and semaphores contained in the set. uxEventQueueLength specifies + * the maximum number of events that can be queued at once. To be absolutely + * certain that events are not lost uxEventQueueLength should be set to the + * total sum of the length of the queues added to the set, where binary + * semaphores and mutexes have a length of 1, and counting semaphores have a + * length set by their maximum count value. Examples: + * + If a queue set is to hold a queue of length 5, another queue of length 12, + * and a binary semaphore, then uxEventQueueLength should be set to + * (5 + 12 + 1), or 18. + * + If a queue set is to hold three binary semaphores then uxEventQueueLength + * should be set to (1 + 1 + 1 ), or 3. + * + If a queue set is to hold a counting semaphore that has a maximum count of + * 5, and a counting semaphore that has a maximum count of 3, then + * uxEventQueueLength should be set to (5 + 3), or 8. + * + * @return If the queue set is created successfully then a handle to the created + * queue set is returned. Otherwise NULL is returned. + */ +QueueSetHandle_t xQueueCreateSet(const UBaseType_t uxEventQueueLength) PRIVILEGED_FUNCTION; + +/* + * Adds a queue or semaphore to a queue set that was previously created by a + * call to xQueueCreateSet(). + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * Note 1: A receive (in the case of a queue) or take (in the case of a + * semaphore) operation must not be performed on a member of a queue set unless + * a call to xQueueSelectFromSet() has first returned a handle to that set member. + * + * @param xQueueOrSemaphore The handle of the queue or semaphore being added to + * the queue set (cast to an QueueSetMemberHandle_t type). + * + * @param xQueueSet The handle of the queue set to which the queue or semaphore + * is being added. + * + * @return If the queue or semaphore was successfully added to the queue set + * then pdPASS is returned. If the queue could not be successfully added to the + * queue set because it is already a member of a different queue set then pdFAIL + * is returned. + */ +BaseType_t xQueueAddToSet(QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet) PRIVILEGED_FUNCTION; + +/* + * Removes a queue or semaphore from a queue set. A queue or semaphore can only + * be removed from a set if the queue or semaphore is empty. + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * @param xQueueOrSemaphore The handle of the queue or semaphore being removed + * from the queue set (cast to an QueueSetMemberHandle_t type). + * + * @param xQueueSet The handle of the queue set in which the queue or semaphore + * is included. + * + * @return If the queue or semaphore was successfully removed from the queue set + * then pdPASS is returned. If the queue was not in the queue set, or the + * queue (or semaphore) was not empty, then pdFAIL is returned. + */ +BaseType_t xQueueRemoveFromSet(QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet) PRIVILEGED_FUNCTION; + +/* + * xQueueSelectFromSet() selects from the members of a queue set a queue or + * semaphore that either contains data (in the case of a queue) or is available + * to take (in the case of a semaphore). xQueueSelectFromSet() effectively + * allows a task to block (pend) on a read operation on all the queues and + * semaphores in a queue set simultaneously. + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * Note 1: See the documentation on http://wwwFreeRTOS.org/RTOS-queue-sets.html + * for reasons why queue sets are very rarely needed in practice as there are + * simpler methods of blocking on multiple objects. + * + * Note 2: Blocking on a queue set that contains a mutex will not cause the + * mutex holder to inherit the priority of the blocked task. + * + * Note 3: A receive (in the case of a queue) or take (in the case of a + * semaphore) operation must not be performed on a member of a queue set unless + * a call to xQueueSelectFromSet() has first returned a handle to that set member. + * + * @param xQueueSet The queue set on which the task will (potentially) block. + * + * @param xTicksToWait The maximum time, in ticks, that the calling task will + * remain in the Blocked state (with other tasks executing) to wait for a member + * of the queue set to be ready for a successful queue read or semaphore take + * operation. + * + * @return xQueueSelectFromSet() will return the handle of a queue (cast to + * a QueueSetMemberHandle_t type) contained in the queue set that contains data, + * or the handle of a semaphore (cast to a QueueSetMemberHandle_t type) contained + * in the queue set that is available, or NULL if no such queue or semaphore + * exists before before the specified block time expires. + */ +QueueSetMemberHandle_t xQueueSelectFromSet(QueueSetHandle_t xQueueSet, const TickType_t xTicksToWait) PRIVILEGED_FUNCTION; + +/* + * A version of xQueueSelectFromSet() that can be used from an ISR. + */ +QueueSetMemberHandle_t xQueueSelectFromSetFromISR(QueueSetHandle_t xQueueSet) PRIVILEGED_FUNCTION; + +/* Not public API functions. */ +void vQueueWaitForMessageRestricted(QueueHandle_t xQueue, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely) PRIVILEGED_FUNCTION; +BaseType_t xQueueGenericReset(QueueHandle_t xQueue, BaseType_t xNewQueue) PRIVILEGED_FUNCTION; +void vQueueSetQueueNumber(QueueHandle_t xQueue, UBaseType_t uxQueueNumber) PRIVILEGED_FUNCTION; +UBaseType_t uxQueueGetQueueNumber(QueueHandle_t xQueue) PRIVILEGED_FUNCTION; +uint8_t ucQueueGetQueueType(QueueHandle_t xQueue) PRIVILEGED_FUNCTION; + +UBaseType_t uxQueueMessagesSet(const QueueHandle_t xQueue, int cnt); + +#ifdef __cplusplus +} +#endif + +#endif /* QUEUE_H */ + diff --git a/include_lib/system/os/FreeRTOS/semphr.h b/include_lib/system/os/FreeRTOS/semphr.h new file mode 100644 index 0000000..4ae16cf --- /dev/null +++ b/include_lib/system/os/FreeRTOS/semphr.h @@ -0,0 +1,1175 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef SEMAPHORE_H +#define SEMAPHORE_H + +#ifndef INC_FREERTOS_H +#error "include FreeRTOS.h" must appear in source files before "include semphr.h" +#endif + +#include "queue.h" + +typedef QueueHandle_t SemaphoreHandle_t; + +#define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( uint8_t ) 1U ) +#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( uint8_t ) 0U ) +#define semGIVE_BLOCK_TIME ( ( TickType_t ) 0U ) + + +/** + * semphr. h + *
vSemaphoreCreateBinary( SemaphoreHandle_t xSemaphore )
+ * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a binary semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * This old vSemaphoreCreateBinary() macro is now deprecated in favour of the + * xSemaphoreCreateBinary() function. Note that binary semaphores created using + * the vSemaphoreCreateBinary() macro are created in a state such that the + * first call to 'take' the semaphore would pass, whereas binary semaphores + * created using xSemaphoreCreateBinary() are created in a state such that the + * the semaphore must first be 'given' before it can be 'taken'. + * + * Macro that implements a semaphore by using the existing queue mechanism. + * The queue length is 1 as this is a binary semaphore. The data size is 0 + * as we don't want to actually store any data - we just want to know if the + * queue is empty or full. + * + * This type of semaphore can be used for pure synchronisation between tasks or + * between an interrupt and a task. The semaphore need not be given back once + * obtained, so one task/interrupt can continuously 'give' the semaphore while + * another continuously 'takes' the semaphore. For this reason this type of + * semaphore does not use a priority inheritance mechanism. For an alternative + * that does use priority inheritance see xSemaphoreCreateMutex(). + * + * @param xSemaphore Handle to the created semaphore. Should be of type SemaphoreHandle_t. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore = NULL;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to vSemaphoreCreateBinary ().
+    // This is a macro so pass the variable in directly.
+    vSemaphoreCreateBinary( xSemaphore );
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.
+    }
+ }
+ 
+ * \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary + * \ingroup Semaphores + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) +#define vSemaphoreCreateBinary( xSemaphore ) \ + { \ + ( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \ + if( ( xSemaphore ) != NULL ) \ + { \ + ( void ) xSemaphoreGive( ( xSemaphore ) ); \ + } \ + } +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateBinary( void )
+ * + * Creates a new binary semaphore instance, and returns a handle by which the + * new semaphore can be referenced. + * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a binary semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, binary semaphores use a block + * of memory, in which the semaphore structure is stored. If a binary semaphore + * is created using xSemaphoreCreateBinary() then the required memory is + * automatically dynamically allocated inside the xSemaphoreCreateBinary() + * function. (see http://www.freertos.org/a00111.html). If a binary semaphore + * is created using xSemaphoreCreateBinaryStatic() then the application writer + * must provide the memory. xSemaphoreCreateBinaryStatic() therefore allows a + * binary semaphore to be created without using any dynamic memory allocation. + * + * The old vSemaphoreCreateBinary() macro is now deprecated in favour of this + * xSemaphoreCreateBinary() function. Note that binary semaphores created using + * the vSemaphoreCreateBinary() macro are created in a state such that the + * first call to 'take' the semaphore would pass, whereas binary semaphores + * created using xSemaphoreCreateBinary() are created in a state such that the + * the semaphore must first be 'given' before it can be 'taken'. + * + * This type of semaphore can be used for pure synchronisation between tasks or + * between an interrupt and a task. The semaphore need not be given back once + * obtained, so one task/interrupt can continuously 'give' the semaphore while + * another continuously 'takes' the semaphore. For this reason this type of + * semaphore does not use a priority inheritance mechanism. For an alternative + * that does use priority inheritance see xSemaphoreCreateMutex(). + * + * @return Handle to the created semaphore, or NULL if the memory required to + * hold the semaphore's data structures could not be allocated. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore = NULL;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to xSemaphoreCreateBinary().
+    // This is a macro so pass the variable in directly.
+    xSemaphore = xSemaphoreCreateBinary();
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.
+    }
+ }
+ 
+ * \defgroup xSemaphoreCreateBinary xSemaphoreCreateBinary + * \ingroup Semaphores + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) +#define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ) +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer )
+ * + * Creates a new binary semaphore instance, and returns a handle by which the + * new semaphore can be referenced. + * + * NOTE: In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a binary semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, binary semaphores use a block + * of memory, in which the semaphore structure is stored. If a binary semaphore + * is created using xSemaphoreCreateBinary() then the required memory is + * automatically dynamically allocated inside the xSemaphoreCreateBinary() + * function. (see http://www.freertos.org/a00111.html). If a binary semaphore + * is created using xSemaphoreCreateBinaryStatic() then the application writer + * must provide the memory. xSemaphoreCreateBinaryStatic() therefore allows a + * binary semaphore to be created without using any dynamic memory allocation. + * + * This type of semaphore can be used for pure synchronisation between tasks or + * between an interrupt and a task. The semaphore need not be given back once + * obtained, so one task/interrupt can continuously 'give' the semaphore while + * another continuously 'takes' the semaphore. For this reason this type of + * semaphore does not use a priority inheritance mechanism. For an alternative + * that does use priority inheritance see xSemaphoreCreateMutex(). + * + * @param pxSemaphoreBuffer Must point to a variable of type StaticSemaphore_t, + * which will then be used to hold the semaphore's data structure, removing the + * need for the memory to be allocated dynamically. + * + * @return If the semaphore is created then a handle to the created semaphore is + * returned. If pxSemaphoreBuffer is NULL then NULL is returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore = NULL;
+ StaticSemaphore_t xSemaphoreBuffer;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to xSemaphoreCreateBinary().
+    // The semaphore's data structures will be placed in the xSemaphoreBuffer
+    // variable, the address of which is passed into the function.  The
+    // function's parameter is not NULL, so the function will not attempt any
+    // dynamic memory allocation, and therefore the function will not return
+    // return NULL.
+    xSemaphore = xSemaphoreCreateBinary( &xSemaphoreBuffer );
+
+    // Rest of task code goes here.
+ }
+ 
+ * \defgroup xSemaphoreCreateBinaryStatic xSemaphoreCreateBinaryStatic + * \ingroup Semaphores + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) +#define xSemaphoreCreateBinaryStatic( pxStaticSemaphore ) xQueueGenericCreateStatic( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticSemaphore, queueQUEUE_TYPE_BINARY_SEMAPHORE ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +/** + * semphr. h + *
xSemaphoreTake(
+ *                   SemaphoreHandle_t xSemaphore,
+ *                   TickType_t xBlockTime
+ *               )
+ * + * Macro to obtain a semaphore. The semaphore must have previously been + * created with a call to xSemaphoreCreateBinary(), xSemaphoreCreateMutex() or + * xSemaphoreCreateCounting(). + * + * @param xSemaphore A handle to the semaphore being taken - obtained when + * the semaphore was created. + * + * @param xBlockTime The time in ticks to wait for the semaphore to become + * available. The macro portTICK_PERIOD_MS can be used to convert this to a + * real time. A block time of zero can be used to poll the semaphore. A block + * time of portMAX_DELAY can be used to block indefinitely (provided + * INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h). + * + * @return pdTRUE if the semaphore was obtained. pdFALSE + * if xBlockTime expired without the semaphore becoming available. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore = NULL;
+
+ // A task that creates a semaphore.
+ void vATask( void * pvParameters )
+ {
+    // Create the semaphore to guard a shared resource.
+    xSemaphore = xSemaphoreCreateBinary();
+ }
+
+ // A task that uses the semaphore.
+ void vAnotherTask( void * pvParameters )
+ {
+    // ... Do other things.
+
+    if( xSemaphore != NULL )
+    {
+        // See if we can obtain the semaphore.  If the semaphore is not available
+        // wait 10 ticks to see if it becomes free.
+        if( xSemaphoreTake( xSemaphore, ( TickType_t ) 10 ) == pdTRUE )
+        {
+            // We were able to obtain the semaphore and can now access the
+            // shared resource.
+
+            // ...
+
+            // We have finished accessing the shared resource.  Release the
+            // semaphore.
+            xSemaphoreGive( xSemaphore );
+        }
+        else
+        {
+            // We could not obtain the semaphore and can therefore not access
+            // the shared resource safely.
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreTake xSemaphoreTake + * \ingroup Semaphores + */ +#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE ) + +/** + * semphr. h + * xSemaphoreTakeRecursive( + * SemaphoreHandle_t xMutex, + * TickType_t xBlockTime + * ) + * + * Macro to recursively obtain, or 'take', a mutex type semaphore. + * The mutex must have previously been created using a call to + * xSemaphoreCreateRecursiveMutex(); + * + * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this + * macro to be available. + * + * This macro must not be used on mutexes created using xSemaphoreCreateMutex(). + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be available to any other task until it has also 'given' the mutex back + * exactly five times. + * + * @param xMutex A handle to the mutex being obtained. This is the + * handle returned by xSemaphoreCreateRecursiveMutex(); + * + * @param xBlockTime The time in ticks to wait for the semaphore to become + * available. The macro portTICK_PERIOD_MS can be used to convert this to a + * real time. A block time of zero can be used to poll the semaphore. If + * the task already owns the semaphore then xSemaphoreTakeRecursive() will + * return immediately no matter what the value of xBlockTime. + * + * @return pdTRUE if the semaphore was obtained. pdFALSE if xBlockTime + * expired without the semaphore becoming available. + * + * Example usage: +
+ SemaphoreHandle_t xMutex = NULL;
+
+ // A task that creates a mutex.
+ void vATask( void * pvParameters )
+ {
+    // Create the mutex to guard a shared resource.
+    xMutex = xSemaphoreCreateRecursiveMutex();
+ }
+
+ // A task that uses the mutex.
+ void vAnotherTask( void * pvParameters )
+ {
+    // ... Do other things.
+
+    if( xMutex != NULL )
+    {
+        // See if we can obtain the mutex.  If the mutex is not available
+        // wait 10 ticks to see if it becomes free.
+        if( xSemaphoreTakeRecursive( xSemaphore, ( TickType_t ) 10 ) == pdTRUE )
+        {
+            // We were able to obtain the mutex and can now access the
+            // shared resource.
+
+            // ...
+            // For some reason due to the nature of the code further calls to
+			// xSemaphoreTakeRecursive() are made on the same mutex.  In real
+			// code these would not be just sequential calls as this would make
+			// no sense.  Instead the calls are likely to be buried inside
+			// a more complex call structure.
+            xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
+            xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
+
+            // The mutex has now been 'taken' three times, so will not be
+			// available to another task until it has also been given back
+			// three times.  Again it is unlikely that real code would have
+			// these calls sequentially, but instead buried in a more complex
+			// call structure.  This is just for illustrative purposes.
+            xSemaphoreGiveRecursive( xMutex );
+			xSemaphoreGiveRecursive( xMutex );
+			xSemaphoreGiveRecursive( xMutex );
+
+			// Now the mutex can be taken by other tasks.
+        }
+        else
+        {
+            // We could not obtain the mutex and can therefore not access
+            // the shared resource safely.
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreTakeRecursive xSemaphoreTakeRecursive + * \ingroup Semaphores + */ +#if( configUSE_RECURSIVE_MUTEXES == 1 ) +#define xSemaphoreTakeRecursive( xMutex, xBlockTime ) xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) ) +#endif + +/** + * semphr. h + *
xSemaphoreGive( SemaphoreHandle_t xSemaphore )
+ * + * Macro to release a semaphore. The semaphore must have previously been + * created with a call to xSemaphoreCreateBinary(), xSemaphoreCreateMutex() or + * xSemaphoreCreateCounting(). and obtained using sSemaphoreTake(). + * + * This macro must not be used from an ISR. See xSemaphoreGiveFromISR () for + * an alternative which can be used from an ISR. + * + * This macro must also not be used on semaphores created using + * xSemaphoreCreateRecursiveMutex(). + * + * @param xSemaphore A handle to the semaphore being released. This is the + * handle returned when the semaphore was created. + * + * @return pdTRUE if the semaphore was released. pdFALSE if an error occurred. + * Semaphores are implemented using queues. An error can occur if there is + * no space on the queue to post a message - indicating that the + * semaphore was not first obtained correctly. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore = NULL;
+
+ void vATask( void * pvParameters )
+ {
+    // Create the semaphore to guard a shared resource.
+    xSemaphore = vSemaphoreCreateBinary();
+
+    if( xSemaphore != NULL )
+    {
+        if( xSemaphoreGive( xSemaphore ) != pdTRUE )
+        {
+            // We would expect this call to fail because we cannot give
+            // a semaphore without first "taking" it!
+        }
+
+        // Obtain the semaphore - don't block if the semaphore is not
+        // immediately available.
+        if( xSemaphoreTake( xSemaphore, ( TickType_t ) 0 ) )
+        {
+            // We now have the semaphore and can access the shared resource.
+
+            // ...
+
+            // We have finished accessing the shared resource so can free the
+            // semaphore.
+            if( xSemaphoreGive( xSemaphore ) != pdTRUE )
+            {
+                // We would not expect this call to fail because we must have
+                // obtained the semaphore to get here.
+            }
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreGive xSemaphoreGive + * \ingroup Semaphores + */ +#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK ) + +/** + * semphr. h + *
xSemaphoreGiveRecursive( SemaphoreHandle_t xMutex )
+ * + * Macro to recursively release, or 'give', a mutex type semaphore. + * The mutex must have previously been created using a call to + * xSemaphoreCreateRecursiveMutex(); + * + * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this + * macro to be available. + * + * This macro must not be used on mutexes created using xSemaphoreCreateMutex(). + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be available to any other task until it has also 'given' the mutex back + * exactly five times. + * + * @param xMutex A handle to the mutex being released, or 'given'. This is the + * handle returned by xSemaphoreCreateMutex(); + * + * @return pdTRUE if the semaphore was given. + * + * Example usage: +
+ SemaphoreHandle_t xMutex = NULL;
+
+ // A task that creates a mutex.
+ void vATask( void * pvParameters )
+ {
+    // Create the mutex to guard a shared resource.
+    xMutex = xSemaphoreCreateRecursiveMutex();
+ }
+
+ // A task that uses the mutex.
+ void vAnotherTask( void * pvParameters )
+ {
+    // ... Do other things.
+
+    if( xMutex != NULL )
+    {
+        // See if we can obtain the mutex.  If the mutex is not available
+        // wait 10 ticks to see if it becomes free.
+        if( xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ) == pdTRUE )
+        {
+            // We were able to obtain the mutex and can now access the
+            // shared resource.
+
+            // ...
+            // For some reason due to the nature of the code further calls to
+			// xSemaphoreTakeRecursive() are made on the same mutex.  In real
+			// code these would not be just sequential calls as this would make
+			// no sense.  Instead the calls are likely to be buried inside
+			// a more complex call structure.
+            xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
+            xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
+
+            // The mutex has now been 'taken' three times, so will not be
+			// available to another task until it has also been given back
+			// three times.  Again it is unlikely that real code would have
+			// these calls sequentially, it would be more likely that the calls
+			// to xSemaphoreGiveRecursive() would be called as a call stack
+			// unwound.  This is just for demonstrative purposes.
+            xSemaphoreGiveRecursive( xMutex );
+			xSemaphoreGiveRecursive( xMutex );
+			xSemaphoreGiveRecursive( xMutex );
+
+			// Now the mutex can be taken by other tasks.
+        }
+        else
+        {
+            // We could not obtain the mutex and can therefore not access
+            // the shared resource safely.
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreGiveRecursive xSemaphoreGiveRecursive + * \ingroup Semaphores + */ +#if( configUSE_RECURSIVE_MUTEXES == 1 ) +#define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( ( xMutex ) ) +#endif + +/** + * semphr. h + *
+ xSemaphoreGiveFromISR(
+                          SemaphoreHandle_t xSemaphore,
+                          BaseType_t *pxHigherPriorityTaskWoken
+                      )
+ * + * Macro to release a semaphore. The semaphore must have previously been + * created with a call to xSemaphoreCreateBinary() or xSemaphoreCreateCounting(). + * + * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) + * must not be used with this macro. + * + * This macro can be used from an ISR. + * + * @param xSemaphore A handle to the semaphore being released. This is the + * handle returned when the semaphore was created. + * + * @param pxHigherPriorityTaskWoken xSemaphoreGiveFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if giving the semaphore caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xSemaphoreGiveFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the semaphore was successfully given, otherwise errQUEUE_FULL. + * + * Example usage: +
+ \#define LONG_TIME 0xffff
+ \#define TICKS_TO_WAIT	10
+ SemaphoreHandle_t xSemaphore = NULL;
+
+ // Repetitive task.
+ void vATask( void * pvParameters )
+ {
+    for( ;; )
+    {
+        // We want this task to run every 10 ticks of a timer.  The semaphore
+        // was created before this task was started.
+
+        // Block waiting for the semaphore to become available.
+        if( xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE )
+        {
+            // It is time to execute.
+
+            // ...
+
+            // We have finished our task.  Return to the top of the loop where
+            // we will block on the semaphore until it is time to execute
+            // again.  Note when using the semaphore for synchronisation with an
+			// ISR in this manner there is no need to 'give' the semaphore back.
+        }
+    }
+ }
+
+ // Timer ISR
+ void vTimerISR( void * pvParameters )
+ {
+ static uint8_t ucLocalTickCount = 0;
+ static BaseType_t xHigherPriorityTaskWoken;
+
+    // A timer tick has occurred.
+
+    // ... Do other time functions.
+
+    // Is it time for vATask () to run?
+	xHigherPriorityTaskWoken = pdFALSE;
+    ucLocalTickCount++;
+    if( ucLocalTickCount >= TICKS_TO_WAIT )
+    {
+        // Unblock the task by releasing the semaphore.
+        xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );
+
+        // Reset the count so we release the semaphore again in 10 ticks time.
+        ucLocalTickCount = 0;
+    }
+
+    if( xHigherPriorityTaskWoken != pdFALSE )
+    {
+        // We can force a context switch here.  Context switching from an
+        // ISR uses port specific syntax.  Check the demo task for your port
+        // to find the syntax required.
+    }
+ }
+ 
+ * \defgroup xSemaphoreGiveFromISR xSemaphoreGiveFromISR + * \ingroup Semaphores + */ +#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ), ( pxHigherPriorityTaskWoken ) ) + +/** + * semphr. h + *
+ xSemaphoreTakeFromISR(
+                          SemaphoreHandle_t xSemaphore,
+                          BaseType_t *pxHigherPriorityTaskWoken
+                      )
+ * + * Macro to take a semaphore from an ISR. The semaphore must have + * previously been created with a call to xSemaphoreCreateBinary() or + * xSemaphoreCreateCounting(). + * + * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) + * must not be used with this macro. + * + * This macro can be used from an ISR, however taking a semaphore from an ISR + * is not a common operation. It is likely to only be useful when taking a + * counting semaphore when an interrupt is obtaining an object from a resource + * pool (when the semaphore count indicates the number of resources available). + * + * @param xSemaphore A handle to the semaphore being taken. This is the + * handle returned when the semaphore was created. + * + * @param pxHigherPriorityTaskWoken xSemaphoreTakeFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if taking the semaphore caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xSemaphoreTakeFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the semaphore was successfully taken, otherwise + * pdFALSE + */ +#define xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueReceiveFromISR( ( QueueHandle_t ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ) ) + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateMutex( void )
+ * + * Creates a new mutex type semaphore instance, and returns a handle by which + * the new mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, mutex semaphores use a block + * of memory, in which the mutex structure is stored. If a mutex is created + * using xSemaphoreCreateMutex() then the required memory is automatically + * dynamically allocated inside the xSemaphoreCreateMutex() function. (see + * http://www.freertos.org/a00111.html). If a mutex is created using + * xSemaphoreCreateMutexStatic() then the application writer must provided the + * memory. xSemaphoreCreateMutexStatic() therefore allows a mutex to be created + * without using any dynamic memory allocation. + * + * Mutexes created using this function can be accessed using the xSemaphoreTake() + * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and + * xSemaphoreGiveRecursive() macros must not be used. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See xSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @return If the mutex was successfully created then a handle to the created + * semaphore is returned. If there was not enough heap to allocate the mutex + * data structures then NULL is returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to xSemaphoreCreateMutex().
+    // This is a macro so pass the variable in directly.
+    xSemaphore = xSemaphoreCreateMutex();
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.
+    }
+ }
+ 
+ * \defgroup xSemaphoreCreateMutex xSemaphoreCreateMutex + * \ingroup Semaphores + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) +#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX ) +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer )
+ * + * Creates a new mutex type semaphore instance, and returns a handle by which + * the new mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, mutex semaphores use a block + * of memory, in which the mutex structure is stored. If a mutex is created + * using xSemaphoreCreateMutex() then the required memory is automatically + * dynamically allocated inside the xSemaphoreCreateMutex() function. (see + * http://www.freertos.org/a00111.html). If a mutex is created using + * xSemaphoreCreateMutexStatic() then the application writer must provided the + * memory. xSemaphoreCreateMutexStatic() therefore allows a mutex to be created + * without using any dynamic memory allocation. + * + * Mutexes created using this function can be accessed using the xSemaphoreTake() + * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and + * xSemaphoreGiveRecursive() macros must not be used. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See xSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @param pxMutexBuffer Must point to a variable of type StaticSemaphore_t, + * which will be used to hold the mutex's data structure, removing the need for + * the memory to be allocated dynamically. + * + * @return If the mutex was successfully created then a handle to the created + * mutex is returned. If pxMutexBuffer was NULL then NULL is returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+ StaticSemaphore_t xMutexBuffer;
+
+ void vATask( void * pvParameters )
+ {
+    // A mutex cannot be used before it has been created.  xMutexBuffer is
+    // into xSemaphoreCreateMutexStatic() so no dynamic memory allocation is
+    // attempted.
+    xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer );
+
+    // As no dynamic memory allocation was performed, xSemaphore cannot be NULL,
+    // so there is no need to check it.
+ }
+ 
+ * \defgroup xSemaphoreCreateMutexStatic xSemaphoreCreateMutexStatic + * \ingroup Semaphores + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) +#define xSemaphoreCreateMutexStatic( pxMutexBuffer ) xQueueCreateMutexStatic( queueQUEUE_TYPE_MUTEX, ( pxMutexBuffer ) ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ + + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )
+ * + * Creates a new recursive mutex type semaphore instance, and returns a handle + * by which the new recursive mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, recursive mutexs use a block + * of memory, in which the mutex structure is stored. If a recursive mutex is + * created using xSemaphoreCreateRecursiveMutex() then the required memory is + * automatically dynamically allocated inside the + * xSemaphoreCreateRecursiveMutex() function. (see + * http://www.freertos.org/a00111.html). If a recursive mutex is created using + * xSemaphoreCreateRecursiveMutexStatic() then the application writer must + * provide the memory that will get used by the mutex. + * xSemaphoreCreateRecursiveMutexStatic() therefore allows a recursive mutex to + * be created without using any dynamic memory allocation. + * + * Mutexes created using this macro can be accessed using the + * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The + * xSemaphoreTake() and xSemaphoreGive() macros must not be used. + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be available to any other task until it has also 'given' the mutex back + * exactly five times. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See xSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @return xSemaphore Handle to the created mutex semaphore. Should be of type + * SemaphoreHandle_t. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to xSemaphoreCreateMutex().
+    // This is a macro so pass the variable in directly.
+    xSemaphore = xSemaphoreCreateRecursiveMutex();
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.
+    }
+ }
+ 
+ * \defgroup xSemaphoreCreateRecursiveMutex xSemaphoreCreateRecursiveMutex + * \ingroup Semaphores + */ +#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) ) +#define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX ) +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic( StaticSemaphore_t *pxMutexBuffer )
+ * + * Creates a new recursive mutex type semaphore instance, and returns a handle + * by which the new recursive mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, recursive mutexs use a block + * of memory, in which the mutex structure is stored. If a recursive mutex is + * created using xSemaphoreCreateRecursiveMutex() then the required memory is + * automatically dynamically allocated inside the + * xSemaphoreCreateRecursiveMutex() function. (see + * http://www.freertos.org/a00111.html). If a recursive mutex is created using + * xSemaphoreCreateRecursiveMutexStatic() then the application writer must + * provide the memory that will get used by the mutex. + * xSemaphoreCreateRecursiveMutexStatic() therefore allows a recursive mutex to + * be created without using any dynamic memory allocation. + * + * Mutexes created using this macro can be accessed using the + * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The + * xSemaphoreTake() and xSemaphoreGive() macros must not be used. + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be available to any other task until it has also 'given' the mutex back + * exactly five times. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See xSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @param pxMutexBuffer Must point to a variable of type StaticSemaphore_t, + * which will then be used to hold the recursive mutex's data structure, + * removing the need for the memory to be allocated dynamically. + * + * @return If the recursive mutex was successfully created then a handle to the + * created recursive mutex is returned. If pxMutexBuffer was NULL then NULL is + * returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+ StaticSemaphore_t xMutexBuffer;
+
+ void vATask( void * pvParameters )
+ {
+    // A recursive semaphore cannot be used before it is created.  Here a
+    // recursive mutex is created using xSemaphoreCreateRecursiveMutexStatic().
+    // The address of xMutexBuffer is passed into the function, and will hold
+    // the mutexes data structures - so no dynamic memory allocation will be
+    // attempted.
+    xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &xMutexBuffer );
+
+    // As no dynamic memory allocation was performed, xSemaphore cannot be NULL,
+    // so there is no need to check it.
+ }
+ 
+ * \defgroup xSemaphoreCreateRecursiveMutexStatic xSemaphoreCreateRecursiveMutexStatic + * \ingroup Semaphores + */ +#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) ) +#define xSemaphoreCreateRecursiveMutexStatic( pxStaticSemaphore ) xQueueCreateMutexStatic( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )
+ * + * Creates a new counting semaphore instance, and returns a handle by which the + * new counting semaphore can be referenced. + * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a counting semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, counting semaphores use a + * block of memory, in which the counting semaphore structure is stored. If a + * counting semaphore is created using xSemaphoreCreateCounting() then the + * required memory is automatically dynamically allocated inside the + * xSemaphoreCreateCounting() function. (see + * http://www.freertos.org/a00111.html). If a counting semaphore is created + * using xSemaphoreCreateCountingStatic() then the application writer can + * instead optionally provide the memory that will get used by the counting + * semaphore. xSemaphoreCreateCountingStatic() therefore allows a counting + * semaphore to be created without using any dynamic memory allocation. + * + * Counting semaphores are typically used for two things: + * + * 1) Counting events. + * + * In this usage scenario an event handler will 'give' a semaphore each time + * an event occurs (incrementing the semaphore count value), and a handler + * task will 'take' a semaphore each time it processes an event + * (decrementing the semaphore count value). The count value is therefore + * the difference between the number of events that have occurred and the + * number that have been processed. In this case it is desirable for the + * initial count value to be zero. + * + * 2) Resource management. + * + * In this usage scenario the count value indicates the number of resources + * available. To obtain control of a resource a task must first obtain a + * semaphore - decrementing the semaphore count value. When the count value + * reaches zero there are no free resources. When a task finishes with the + * resource it 'gives' the semaphore back - incrementing the semaphore count + * value. In this case it is desirable for the initial count value to be + * equal to the maximum count value, indicating that all resources are free. + * + * @param uxMaxCount The maximum count value that can be reached. When the + * semaphore reaches this value it can no longer be 'given'. + * + * @param uxInitialCount The count value assigned to the semaphore when it is + * created. + * + * @return Handle to the created semaphore. Null if the semaphore could not be + * created. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+ SemaphoreHandle_t xSemaphore = NULL;
+
+    // Semaphore cannot be used before a call to xSemaphoreCreateCounting().
+    // The max value to which the semaphore can count should be 10, and the
+    // initial value assigned to the count should be 0.
+    xSemaphore = xSemaphoreCreateCounting( 10, 0 );
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.
+    }
+ }
+ 
+ * \defgroup xSemaphoreCreateCounting xSemaphoreCreateCounting + * \ingroup Semaphores + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) +#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) ) +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount, StaticSemaphore_t *pxSemaphoreBuffer )
+ * + * Creates a new counting semaphore instance, and returns a handle by which the + * new counting semaphore can be referenced. + * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a counting semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, counting semaphores use a + * block of memory, in which the counting semaphore structure is stored. If a + * counting semaphore is created using xSemaphoreCreateCounting() then the + * required memory is automatically dynamically allocated inside the + * xSemaphoreCreateCounting() function. (see + * http://www.freertos.org/a00111.html). If a counting semaphore is created + * using xSemaphoreCreateCountingStatic() then the application writer must + * provide the memory. xSemaphoreCreateCountingStatic() therefore allows a + * counting semaphore to be created without using any dynamic memory allocation. + * + * Counting semaphores are typically used for two things: + * + * 1) Counting events. + * + * In this usage scenario an event handler will 'give' a semaphore each time + * an event occurs (incrementing the semaphore count value), and a handler + * task will 'take' a semaphore each time it processes an event + * (decrementing the semaphore count value). The count value is therefore + * the difference between the number of events that have occurred and the + * number that have been processed. In this case it is desirable for the + * initial count value to be zero. + * + * 2) Resource management. + * + * In this usage scenario the count value indicates the number of resources + * available. To obtain control of a resource a task must first obtain a + * semaphore - decrementing the semaphore count value. When the count value + * reaches zero there are no free resources. When a task finishes with the + * resource it 'gives' the semaphore back - incrementing the semaphore count + * value. In this case it is desirable for the initial count value to be + * equal to the maximum count value, indicating that all resources are free. + * + * @param uxMaxCount The maximum count value that can be reached. When the + * semaphore reaches this value it can no longer be 'given'. + * + * @param uxInitialCount The count value assigned to the semaphore when it is + * created. + * + * @param pxSemaphoreBuffer Must point to a variable of type StaticSemaphore_t, + * which will then be used to hold the semaphore's data structure, removing the + * need for the memory to be allocated dynamically. + * + * @return If the counting semaphore was successfully created then a handle to + * the created counting semaphore is returned. If pxSemaphoreBuffer was NULL + * then NULL is returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+ StaticSemaphore_t xSemaphoreBuffer;
+
+ void vATask( void * pvParameters )
+ {
+ SemaphoreHandle_t xSemaphore = NULL;
+
+    // Counting semaphore cannot be used before they have been created.  Create
+    // a counting semaphore using xSemaphoreCreateCountingStatic().  The max
+    // value to which the semaphore can count is 10, and the initial value
+    // assigned to the count will be 0.  The address of xSemaphoreBuffer is
+    // passed in and will be used to hold the semaphore structure, so no dynamic
+    // memory allocation will be used.
+    xSemaphore = xSemaphoreCreateCounting( 10, 0, &xSemaphoreBuffer );
+
+    // No memory allocation was attempted so xSemaphore cannot be NULL, so there
+    // is no need to check its value.
+ }
+ 
+ * \defgroup xSemaphoreCreateCountingStatic xSemaphoreCreateCountingStatic + * \ingroup Semaphores + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) +#define xSemaphoreCreateCountingStatic( uxMaxCount, uxInitialCount, pxSemaphoreBuffer ) xQueueCreateCountingSemaphoreStatic( ( uxMaxCount ), ( uxInitialCount ), ( pxSemaphoreBuffer ) ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +/** + * semphr. h + *
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );
+ * + * Delete a semaphore. This function must be used with care. For example, + * do not delete a mutex type semaphore if the mutex is held by a task. + * + * @param xSemaphore A handle to the semaphore to be deleted. + * + * \defgroup vSemaphoreDelete vSemaphoreDelete + * \ingroup Semaphores + */ +#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) ) + +/** + * semphr.h + *
TaskHandle_t xSemaphoreGetMutexHolder( SemaphoreHandle_t xMutex );
+ * + * If xMutex is indeed a mutex type semaphore, return the current mutex holder. + * If xMutex is not a mutex type semaphore, or the mutex is available (not held + * by a task), return NULL. + * + * Note: This is a good way of determining if the calling task is the mutex + * holder, but not a good way of determining the identity of the mutex holder as + * the holder may change between the function exiting and the returned value + * being tested. + */ +#define xSemaphoreGetMutexHolder( xSemaphore ) xQueueGetMutexHolder( ( xSemaphore ) ) + +/** + * semphr.h + *
UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );
+ * + * If the semaphore is a counting semaphore then uxSemaphoreGetCount() returns + * its current count value. If the semaphore is a binary semaphore then + * uxSemaphoreGetCount() returns 1 if the semaphore is available, and 0 if the + * semaphore is not available. + * + */ +#define uxSemaphoreGetCount( xSemaphore ) uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) ) + +#define uxSemaphoreSetCount( xSemaphore, cnt) \ + uxQueueMessagesSet((QueueHandle_t)xSemaphore, cnt) + + +#endif /* SEMAPHORE_H */ + + diff --git a/include_lib/system/os/FreeRTOS/task.h b/include_lib/system/os/FreeRTOS/task.h new file mode 100644 index 0000000..044fefa --- /dev/null +++ b/include_lib/system/os/FreeRTOS/task.h @@ -0,0 +1,2268 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#ifndef INC_TASK_H +#define INC_TASK_H + +#ifndef INC_FREERTOS_H +#error "include FreeRTOS.h must appear in source files before include task.h" +#endif + +#include "list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------- + * MACROS AND DEFINITIONS + *----------------------------------------------------------*/ + +#define tskKERNEL_VERSION_NUMBER "V9.0.0" +#define tskKERNEL_VERSION_MAJOR 9 +#define tskKERNEL_VERSION_MINOR 0 +#define tskKERNEL_VERSION_BUILD 0 + +/** + * task. h + * + * Type by which tasks are referenced. For example, a call to xTaskCreate + * returns (via a pointer parameter) an TaskHandle_t variable that can then + * be used as a parameter to vTaskDelete to delete the task. + * + * \defgroup TaskHandle_t TaskHandle_t + * \ingroup Tasks + */ +typedef void *TaskHandle_t; + +/* + * Defines the prototype to which the application task hook function must + * conform. + */ +typedef BaseType_t (*TaskHookFunction_t)(void *); + +/* Task states returned by eTaskGetState. */ +typedef enum { + eRunning = 0, /* A task is querying the state of itself, so must be running. */ + eReady, /* The task being queried is in a read or pending ready list. */ + eBlocked, /* The task being queried is in the Blocked state. */ + eSuspended, /* The task being queried is in the Suspended state, or is in the Blocked state with an infinite time out. */ + eDeleted, /* The task being queried has been deleted, but its TCB has not yet been freed. */ + eInvalid /* Used as an 'invalid state' value. */ +} eTaskState; + +/* Actions that can be performed when vTaskNotify() is called. */ +typedef enum { + eNoAction = 0, /* Notify the task without updating its notify value. */ + eSetBits, /* Set bits in the task's notification value. */ + eIncrement, /* Increment the task's notification value. */ + eSetValueWithOverwrite, /* Set the task's notification value to a specific value even if the previous value has not yet been read by the task. */ + eSetValueWithoutOverwrite /* Set the task's notification value if the previous value has been read by the task. */ +} eNotifyAction; + +/* + * Used internally only. + */ +typedef struct xTIME_OUT { + BaseType_t xOverflowCount; + TickType_t xTimeOnEntering; +} TimeOut_t; + +/* + * Defines the memory ranges allocated to the task when an MPU is used. + */ +typedef struct xMEMORY_REGION { + void *pvBaseAddress; + uint32_t ulLengthInBytes; + uint32_t ulParameters; +} MemoryRegion_t; + +/* + * Parameters required to create an MPU protected task. + */ +typedef struct xTASK_PARAMETERS { + TaskFunction_t pvTaskCode; + const char *const pcName; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + uint16_t usStackDepth; + void *pvParameters; + UBaseType_t uxPriority; + StackType_t *puxStackBuffer; + MemoryRegion_t xRegions[ portNUM_CONFIGURABLE_REGIONS ]; +} TaskParameters_t; + +/* Used with the uxTaskGetSystemState() function to return the state of each task +in the system. */ +typedef struct xTASK_STATUS { + TaskHandle_t xHandle; /* The handle of the task to which the rest of the information in the structure relates. */ + const char *pcTaskName; /* A pointer to the task's name. This value will be invalid if the task was deleted since the structure was populated! */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + UBaseType_t xTaskNumber; /* A number unique to the task. */ + eTaskState eCurrentState; /* The state in which the task existed when the structure was populated. */ + UBaseType_t uxCurrentPriority; /* The priority at which the task was running (may be inherited) when the structure was populated. */ + UBaseType_t uxBasePriority; /* The priority to which the task will return if the task's current priority has been inherited to avoid unbounded priority inversion when obtaining a mutex. Only valid if configUSE_MUTEXES is defined as 1 in FreeRTOSConfig.h. */ + uint32_t ulRunTimeCounter; /* The total run time allocated to the task so far, as defined by the run time stats clock. See http://www.freertos.org/rtos-run-time-stats.html. Only valid when configGENERATE_RUN_TIME_STATS is defined as 1 in FreeRTOSConfig.h. */ + StackType_t *pxStackBase; /* Points to the lowest address of the task's stack area. */ + uint16_t usStackHighWaterMark; /* The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */ +} TaskStatus_t; + +/* Possible return values for eTaskConfirmSleepModeStatus(). */ +typedef enum { + eAbortSleep = 0, /* A task has been made ready or a context switch pended since portSUPPORESS_TICKS_AND_SLEEP() was called - abort entering a sleep mode. */ + eStandardSleep, /* Enter a sleep mode that will not last any longer than the expected idle time. */ + eNoTasksWaitingTimeout /* No tasks are waiting for a timeout so it is safe to enter a sleep mode that can only be exited by an external interrupt. */ +} eSleepModeStatus; + +/** + * Defines the priority used by the idle task. This must not be modified. + * + * \ingroup TaskUtils + */ +#define tskIDLE_PRIORITY ( ( UBaseType_t ) 0U ) + +/** + * task. h + * + * Macro for forcing a context switch. + * + * \defgroup taskYIELD taskYIELD + * \ingroup SchedulerControl + */ +#define taskYIELD() portYIELD() + +/** + * task. h + * + * Macro to mark the start of a critical code region. Preemptive context + * switches cannot occur when in a critical region. + * + * NOTE: This may alter the stack (depending on the portable implementation) + * so must be used with care! + * + * \defgroup taskENTER_CRITICAL taskENTER_CRITICAL + * \ingroup SchedulerControl + */ +#define taskENTER_CRITICAL() portENTER_CRITICAL() +#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR() + +/** + * task. h + * + * Macro to mark the end of a critical code region. Preemptive context + * switches cannot occur when in a critical region. + * + * NOTE: This may alter the stack (depending on the portable implementation) + * so must be used with care! + * + * \defgroup taskEXIT_CRITICAL taskEXIT_CRITICAL + * \ingroup SchedulerControl + */ +#define taskEXIT_CRITICAL() portEXIT_CRITICAL() +#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) +/** + * task. h + * + * Macro to disable all maskable interrupts. + * + * \defgroup taskDISABLE_INTERRUPTS taskDISABLE_INTERRUPTS + * \ingroup SchedulerControl + */ +#define taskDISABLE_INTERRUPTS() portDISABLE_INTERRUPTS() + +/** + * task. h + * + * Macro to enable microcontroller interrupts. + * + * \defgroup taskENABLE_INTERRUPTS taskENABLE_INTERRUPTS + * \ingroup SchedulerControl + */ +#define taskENABLE_INTERRUPTS() portENABLE_INTERRUPTS() + +/* Definitions returned by xTaskGetSchedulerState(). taskSCHEDULER_SUSPENDED is +0 to generate more optimal code when configASSERT() is defined as the constant +is used in assert() statements. */ +#define taskSCHEDULER_SUSPENDED ( ( BaseType_t ) 0 ) +#define taskSCHEDULER_NOT_STARTED ( ( BaseType_t ) 1 ) +#define taskSCHEDULER_RUNNING ( ( BaseType_t ) 2 ) + + +/*----------------------------------------------------------- + * TASK CREATION API + *----------------------------------------------------------*/ + +/** + * task. h + *
+ BaseType_t xTaskCreate(
+							  TaskFunction_t pvTaskCode,
+							  const char * const pcName,
+							  uint16_t usStackDepth,
+							  void *pvParameters,
+							  UBaseType_t uxPriority,
+							  TaskHandle_t *pvCreatedTask
+						  );
+ * + * Create a new task and add it to the list of tasks that are ready to run. + * + * Internally, within the FreeRTOS implementation, tasks use two blocks of + * memory. The first block is used to hold the task's data structures. The + * second block is used by the task as its stack. If a task is created using + * xTaskCreate() then both blocks of memory are automatically dynamically + * allocated inside the xTaskCreate() function. (see + * http://www.freertos.org/a00111.html). If a task is created using + * xTaskCreateStatic() then the application writer must provide the required + * memory. xTaskCreateStatic() therefore allows a task to be created without + * using any dynamic memory allocation. + * + * See xTaskCreateStatic() for a version that does not use any dynamic memory + * allocation. + * + * xTaskCreate() can only be used to create a task that has unrestricted + * access to the entire microcontroller memory map. Systems that include MPU + * support can alternatively create an MPU constrained task using + * xTaskCreateRestricted(). + * + * @param pvTaskCode Pointer to the task entry function. Tasks + * must be implemented to never return (i.e. continuous loop). + * + * @param pcName A descriptive name for the task. This is mainly used to + * facilitate debugging. Max length defined by configMAX_TASK_NAME_LEN - default + * is 16. + * + * @param usStackDepth The size of the task stack specified as the number of + * variables the stack can hold - not the number of bytes. For example, if + * the stack is 16 bits wide and usStackDepth is defined as 100, 200 bytes + * will be allocated for stack storage. + * + * @param pvParameters Pointer that will be used as the parameter for the task + * being created. + * + * @param uxPriority The priority at which the task should run. Systems that + * include MPU support can optionally create tasks in a privileged (system) + * mode by setting bit portPRIVILEGE_BIT of the priority parameter. For + * example, to create a privileged task at priority 2 the uxPriority parameter + * should be set to ( 2 | portPRIVILEGE_BIT ). + * + * @param pvCreatedTask Used to pass back a handle by which the created task + * can be referenced. + * + * @return pdPASS if the task was successfully created and added to a ready + * list, otherwise an error code defined in the file projdefs.h + * + * Example usage: +
+ // Task to be created.
+ void vTaskCode( void * pvParameters )
+ {
+	 for( ;; )
+	 {
+		 // Task code goes here.
+	 }
+ }
+
+ // Function that creates a task.
+ void vOtherFunction( void )
+ {
+ static uint8_t ucParameterToPass;
+ TaskHandle_t xHandle = NULL;
+
+	 // Create the task, storing the handle.  Note that the passed parameter ucParameterToPass
+	 // must exist for the lifetime of the task, so in this case is declared static.  If it was just an
+	 // an automatic stack variable it might no longer exist, or at least have been corrupted, by the time
+	 // the new task attempts to access it.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );
+     configASSERT( xHandle );
+
+	 // Use the handle to delete the task.
+     if( xHandle != NULL )
+     {
+	     vTaskDelete( xHandle );
+     }
+ }
+   
+ * \defgroup xTaskCreate xTaskCreate + * \ingroup Tasks + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) +BaseType_t xTaskCreate(TaskFunction_t pxTaskCode, + const char *const pcName, + const uint16_t usStackDepth, + void *const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t *const pxCreatedTask) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif + +/** + * task. h + *
+ TaskHandle_t xTaskCreateStatic( TaskFunction_t pvTaskCode,
+								 const char * const pcName,
+								 uint32_t ulStackDepth,
+								 void *pvParameters,
+								 UBaseType_t uxPriority,
+								 StackType_t *pxStackBuffer,
+								 StaticTask_t *pxTaskBuffer );
+ * + * Create a new task and add it to the list of tasks that are ready to run. + * + * Internally, within the FreeRTOS implementation, tasks use two blocks of + * memory. The first block is used to hold the task's data structures. The + * second block is used by the task as its stack. If a task is created using + * xTaskCreate() then both blocks of memory are automatically dynamically + * allocated inside the xTaskCreate() function. (see + * http://www.freertos.org/a00111.html). If a task is created using + * xTaskCreateStatic() then the application writer must provide the required + * memory. xTaskCreateStatic() therefore allows a task to be created without + * using any dynamic memory allocation. + * + * @param pvTaskCode Pointer to the task entry function. Tasks + * must be implemented to never return (i.e. continuous loop). + * + * @param pcName A descriptive name for the task. This is mainly used to + * facilitate debugging. The maximum length of the string is defined by + * configMAX_TASK_NAME_LEN in FreeRTOSConfig.h. + * + * @param ulStackDepth The size of the task stack specified as the number of + * variables the stack can hold - not the number of bytes. For example, if + * the stack is 32-bits wide and ulStackDepth is defined as 100 then 400 bytes + * will be allocated for stack storage. + * + * @param pvParameters Pointer that will be used as the parameter for the task + * being created. + * + * @param uxPriority The priority at which the task will run. + * + * @param pxStackBuffer Must point to a StackType_t array that has at least + * ulStackDepth indexes - the array will then be used as the task's stack, + * removing the need for the stack to be allocated dynamically. + * + * @param pxTaskBuffer Must point to a variable of type StaticTask_t, which will + * then be used to hold the task's data structures, removing the need for the + * memory to be allocated dynamically. + * + * @return If neither pxStackBuffer or pxTaskBuffer are NULL, then the task will + * be created and pdPASS is returned. If either pxStackBuffer or pxTaskBuffer + * are NULL then the task will not be created and + * errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY is returned. + * + * Example usage: +
+
+    // Dimensions the buffer that the task being created will use as its stack.
+    // NOTE:  This is the number of words the stack will hold, not the number of
+    // bytes.  For example, if each stack item is 32-bits, and this is set to 100,
+    // then 400 bytes (100 * 32-bits) will be allocated.
+    #define STACK_SIZE 200
+
+    // Structure that will hold the TCB of the task being created.
+    StaticTask_t xTaskBuffer;
+
+    // Buffer that the task being created will use as its stack.  Note this is
+    // an array of StackType_t variables.  The size of StackType_t is dependent on
+    // the RTOS port.
+    StackType_t xStack[ STACK_SIZE ];
+
+    // Function that implements the task being created.
+    void vTaskCode( void * pvParameters )
+    {
+        // The parameter value is expected to be 1 as 1 is passed in the
+        // pvParameters value in the call to xTaskCreateStatic().
+        configASSERT( ( uint32_t ) pvParameters == 1UL );
+
+        for( ;; )
+        {
+            // Task code goes here.
+        }
+    }
+
+    // Function that creates a task.
+    void vOtherFunction( void )
+    {
+        TaskHandle_t xHandle = NULL;
+
+        // Create the task without using any dynamic memory allocation.
+        xHandle = xTaskCreateStatic(
+                      vTaskCode,       // Function that implements the task.
+                      "NAME",          // Text name for the task.
+                      STACK_SIZE,      // Stack size in words, not bytes.
+                      ( void * ) 1,    // Parameter passed into the task.
+                      tskIDLE_PRIORITY,// Priority at which the task is created.
+                      xStack,          // Array to use as the task's stack.
+                      &xTaskBuffer );  // Variable to hold the task's data structure.
+
+        // puxStackBuffer and pxTaskBuffer were not NULL, so the task will have
+        // been created, and xHandle will be the task's handle.  Use the handle
+        // to suspend the task.
+        vTaskSuspend( xHandle );
+    }
+   
+ * \defgroup xTaskCreateStatic xTaskCreateStatic + * \ingroup Tasks + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) +TaskHandle_t xTaskCreateStatic(TaskFunction_t pxTaskCode, + const char *const pcName, + const uint32_t ulStackDepth, + void *const pvParameters, + UBaseType_t uxPriority, + StackType_t *const puxStackBuffer, + StaticTask_t *const pxTaskBuffer) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +/** + * task. h + *
+ BaseType_t xTaskCreateRestricted( TaskParameters_t *pxTaskDefinition, TaskHandle_t *pxCreatedTask );
+ * + * xTaskCreateRestricted() should only be used in systems that include an MPU + * implementation. + * + * Create a new task and add it to the list of tasks that are ready to run. + * The function parameters define the memory regions and associated access + * permissions allocated to the task. + * + * @param pxTaskDefinition Pointer to a structure that contains a member + * for each of the normal xTaskCreate() parameters (see the xTaskCreate() API + * documentation) plus an optional stack buffer and the memory region + * definitions. + * + * @param pxCreatedTask Used to pass back a handle by which the created task + * can be referenced. + * + * @return pdPASS if the task was successfully created and added to a ready + * list, otherwise an error code defined in the file projdefs.h + * + * Example usage: +
+// Create an TaskParameters_t structure that defines the task to be created.
+static const TaskParameters_t xCheckTaskParameters =
+{
+	vATask,		// pvTaskCode - the function that implements the task.
+	"ATask",	// pcName - just a text name for the task to assist debugging.
+	100,		// usStackDepth	- the stack size DEFINED IN WORDS.
+	NULL,		// pvParameters - passed into the task function as the function parameters.
+	( 1UL | portPRIVILEGE_BIT ),// uxPriority - task priority, set the portPRIVILEGE_BIT if the task should run in a privileged state.
+	cStackBuffer,// puxStackBuffer - the buffer to be used as the task stack.
+
+	// xRegions - Allocate up to three separate memory regions for access by
+	// the task, with appropriate access permissions.  Different processors have
+	// different memory alignment requirements - refer to the FreeRTOS documentation
+	// for full information.
+	{
+		// Base address					Length	Parameters
+        { cReadWriteArray,				32,		portMPU_REGION_READ_WRITE },
+        { cReadOnlyArray,				32,		portMPU_REGION_READ_ONLY },
+        { cPrivilegedOnlyAccessArray,	128,	portMPU_REGION_PRIVILEGED_READ_WRITE }
+	}
+};
+
+int main( void )
+{
+TaskHandle_t xHandle;
+
+	// Create a task from the const structure defined above.  The task handle
+	// is requested (the second parameter is not NULL) but in this case just for
+	// demonstration purposes as its not actually used.
+	xTaskCreateRestricted( &xRegTest1Parameters, &xHandle );
+
+	// Start the scheduler.
+	vTaskStartScheduler();
+
+	// Will only get here if there was insufficient memory to create the idle
+	// and/or timer task.
+	for( ;; );
+}
+   
+ * \defgroup xTaskCreateRestricted xTaskCreateRestricted + * \ingroup Tasks + */ +#if( portUSING_MPU_WRAPPERS == 1 ) +BaseType_t xTaskCreateRestricted(const TaskParameters_t *const pxTaskDefinition, TaskHandle_t *pxCreatedTask) PRIVILEGED_FUNCTION; +#endif + +/** + * task. h + *
+ void vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions );
+ * + * Memory regions are assigned to a restricted task when the task is created by + * a call to xTaskCreateRestricted(). These regions can be redefined using + * vTaskAllocateMPURegions(). + * + * @param xTask The handle of the task being updated. + * + * @param xRegions A pointer to an MemoryRegion_t structure that contains the + * new memory region definitions. + * + * Example usage: +
+// Define an array of MemoryRegion_t structures that configures an MPU region
+// allowing read/write access for 1024 bytes starting at the beginning of the
+// ucOneKByte array.  The other two of the maximum 3 definable regions are
+// unused so set to zero.
+static const MemoryRegion_t xAltRegions[ portNUM_CONFIGURABLE_REGIONS ] =
+{
+	// Base address		Length		Parameters
+	{ ucOneKByte,		1024,		portMPU_REGION_READ_WRITE },
+	{ 0,				0,			0 },
+	{ 0,				0,			0 }
+};
+
+void vATask( void *pvParameters )
+{
+	// This task was created such that it has access to certain regions of
+	// memory as defined by the MPU configuration.  At some point it is
+	// desired that these MPU regions are replaced with that defined in the
+	// xAltRegions const struct above.  Use a call to vTaskAllocateMPURegions()
+	// for this purpose.  NULL is used as the task handle to indicate that this
+	// function should modify the MPU regions of the calling task.
+	vTaskAllocateMPURegions( NULL, xAltRegions );
+
+	// Now the task can continue its function, but from this point on can only
+	// access its stack and the ucOneKByte array (unless any other statically
+	// defined or shared regions have been declared elsewhere).
+}
+   
+ * \defgroup xTaskCreateRestricted xTaskCreateRestricted + * \ingroup Tasks + */ +void vTaskAllocateMPURegions(TaskHandle_t xTask, const MemoryRegion_t *const pxRegions) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskDelete( TaskHandle_t xTask );
+ * + * INCLUDE_vTaskDelete must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Remove a task from the RTOS real time kernel's management. The task being + * deleted will be removed from all ready, blocked, suspended and event lists. + * + * NOTE: The idle task is responsible for freeing the kernel allocated + * memory from tasks that have been deleted. It is therefore important that + * the idle task is not starved of microcontroller processing time if your + * application makes any calls to vTaskDelete (). Memory allocated by the + * task code is not automatically freed, and should be freed before the task + * is deleted. + * + * See the demo application file death.c for sample code that utilises + * vTaskDelete (). + * + * @param xTask The handle of the task to be deleted. Passing NULL will + * cause the calling task to be deleted. + * + * Example usage: +
+ void vOtherFunction( void )
+ {
+ TaskHandle_t xHandle;
+
+	 // Create the task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // Use the handle to delete the task.
+	 vTaskDelete( xHandle );
+ }
+   
+ * \defgroup vTaskDelete vTaskDelete + * \ingroup Tasks + */ +void vTaskDelete(TaskHandle_t xTaskToDelete) PRIVILEGED_FUNCTION; + +/*----------------------------------------------------------- + * TASK CONTROL API + *----------------------------------------------------------*/ + +/** + * task. h + *
void vTaskDelay( const TickType_t xTicksToDelay );
+ * + * Delay a task for a given number of ticks. The actual time that the + * task remains blocked depends on the tick rate. The constant + * portTICK_PERIOD_MS can be used to calculate real time from the tick + * rate - with the resolution of one tick period. + * + * INCLUDE_vTaskDelay must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * + * vTaskDelay() specifies a time at which the task wishes to unblock relative to + * the time at which vTaskDelay() is called. For example, specifying a block + * period of 100 ticks will cause the task to unblock 100 ticks after + * vTaskDelay() is called. vTaskDelay() does not therefore provide a good method + * of controlling the frequency of a periodic task as the path taken through the + * code, as well as other task and interrupt activity, will effect the frequency + * at which vTaskDelay() gets called and therefore the time at which the task + * next executes. See vTaskDelayUntil() for an alternative API function designed + * to facilitate fixed frequency execution. It does this by specifying an + * absolute time (rather than a relative time) at which the calling task should + * unblock. + * + * @param xTicksToDelay The amount of time, in tick periods, that + * the calling task should block. + * + * Example usage: + + void vTaskFunction( void * pvParameters ) + { + // Block for 500ms. + const TickType_t xDelay = 500 / portTICK_PERIOD_MS; + + for( ;; ) + { + // Simply toggle the LED every 500ms, blocking between each toggle. + vToggleLED(); + vTaskDelay( xDelay ); + } + } + + * \defgroup vTaskDelay vTaskDelay + * \ingroup TaskCtrl + */ +void vTaskDelay(const TickType_t xTicksToDelay) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskDelayUntil( TickType_t *pxPreviousWakeTime, const TickType_t xTimeIncrement );
+ * + * INCLUDE_vTaskDelayUntil must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Delay a task until a specified time. This function can be used by periodic + * tasks to ensure a constant execution frequency. + * + * This function differs from vTaskDelay () in one important aspect: vTaskDelay () will + * cause a task to block for the specified number of ticks from the time vTaskDelay () is + * called. It is therefore difficult to use vTaskDelay () by itself to generate a fixed + * execution frequency as the time between a task starting to execute and that task + * calling vTaskDelay () may not be fixed [the task may take a different path though the + * code between calls, or may get interrupted or preempted a different number of times + * each time it executes]. + * + * Whereas vTaskDelay () specifies a wake time relative to the time at which the function + * is called, vTaskDelayUntil () specifies the absolute (exact) time at which it wishes to + * unblock. + * + * The constant portTICK_PERIOD_MS can be used to calculate real time from the tick + * rate - with the resolution of one tick period. + * + * @param pxPreviousWakeTime Pointer to a variable that holds the time at which the + * task was last unblocked. The variable must be initialised with the current time + * prior to its first use (see the example below). Following this the variable is + * automatically updated within vTaskDelayUntil (). + * + * @param xTimeIncrement The cycle time period. The task will be unblocked at + * time *pxPreviousWakeTime + xTimeIncrement. Calling vTaskDelayUntil with the + * same xTimeIncrement parameter value will cause the task to execute with + * a fixed interface period. + * + * Example usage: +
+ // Perform an action every 10 ticks.
+ void vTaskFunction( void * pvParameters )
+ {
+ TickType_t xLastWakeTime;
+ const TickType_t xFrequency = 10;
+
+	 // Initialise the xLastWakeTime variable with the current time.
+	 xLastWakeTime = xTaskGetTickCount ();
+	 for( ;; )
+	 {
+		 // Wait for the next cycle.
+		 vTaskDelayUntil( &xLastWakeTime, xFrequency );
+
+		 // Perform action here.
+	 }
+ }
+   
+ * \defgroup vTaskDelayUntil vTaskDelayUntil + * \ingroup TaskCtrl + */ +void vTaskDelayUntil(TickType_t *const pxPreviousWakeTime, const TickType_t xTimeIncrement) PRIVILEGED_FUNCTION; + +/** + * task. h + *
BaseType_t xTaskAbortDelay( TaskHandle_t xTask );
+ * + * INCLUDE_xTaskAbortDelay must be defined as 1 in FreeRTOSConfig.h for this + * function to be available. + * + * A task will enter the Blocked state when it is waiting for an event. The + * event it is waiting for can be a temporal event (waiting for a time), such + * as when vTaskDelay() is called, or an event on an object, such as when + * xQueueReceive() or ulTaskNotifyTake() is called. If the handle of a task + * that is in the Blocked state is used in a call to xTaskAbortDelay() then the + * task will leave the Blocked state, and return from whichever function call + * placed the task into the Blocked state. + * + * @param xTask The handle of the task to remove from the Blocked state. + * + * @return If the task referenced by xTask was not in the Blocked state then + * pdFAIL is returned. Otherwise pdPASS is returned. + * + * \defgroup xTaskAbortDelay xTaskAbortDelay + * \ingroup TaskCtrl + */ +BaseType_t xTaskAbortDelay(TaskHandle_t xTask) PRIVILEGED_FUNCTION; + +/** + * task. h + *
UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask );
+ * + * INCLUDE_uxTaskPriorityGet must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Obtain the priority of any task. + * + * @param xTask Handle of the task to be queried. Passing a NULL + * handle results in the priority of the calling task being returned. + * + * @return The priority of xTask. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ TaskHandle_t xHandle;
+
+	 // Create a task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // ...
+
+	 // Use the handle to obtain the priority of the created task.
+	 // It was created with tskIDLE_PRIORITY, but may have changed
+	 // it itself.
+	 if( uxTaskPriorityGet( xHandle ) != tskIDLE_PRIORITY )
+	 {
+		 // The task has changed it's priority.
+	 }
+
+	 // ...
+
+	 // Is our priority higher than the created task?
+	 if( uxTaskPriorityGet( xHandle ) < uxTaskPriorityGet( NULL ) )
+	 {
+		 // Our priority (obtained using NULL handle) is higher.
+	 }
+ }
+   
+ * \defgroup uxTaskPriorityGet uxTaskPriorityGet + * \ingroup TaskCtrl + */ +UBaseType_t uxTaskPriorityGet(TaskHandle_t xTask) PRIVILEGED_FUNCTION; + +/** + * task. h + *
UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask );
+ * + * A version of uxTaskPriorityGet() that can be used from an ISR. + */ +UBaseType_t uxTaskPriorityGetFromISR(TaskHandle_t xTask) PRIVILEGED_FUNCTION; + +/** + * task. h + *
eTaskState eTaskGetState( TaskHandle_t xTask );
+ * + * INCLUDE_eTaskGetState must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Obtain the state of any task. States are encoded by the eTaskState + * enumerated type. + * + * @param xTask Handle of the task to be queried. + * + * @return The state of xTask at the time the function was called. Note the + * state of the task might change between the function being called, and the + * functions return value being tested by the calling task. + */ +eTaskState eTaskGetState(TaskHandle_t xTask) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState );
+ * + * configUSE_TRACE_FACILITY must be defined as 1 for this function to be + * available. See the configuration section for more information. + * + * Populates a TaskStatus_t structure with information about a task. + * + * @param xTask Handle of the task being queried. If xTask is NULL then + * information will be returned about the calling task. + * + * @param pxTaskStatus A pointer to the TaskStatus_t structure that will be + * filled with information about the task referenced by the handle passed using + * the xTask parameter. + * + * @xGetFreeStackSpace The TaskStatus_t structure contains a member to report + * the stack high water mark of the task being queried. Calculating the stack + * high water mark takes a relatively long time, and can make the system + * temporarily unresponsive - so the xGetFreeStackSpace parameter is provided to + * allow the high water mark checking to be skipped. The high watermark value + * will only be written to the TaskStatus_t structure if xGetFreeStackSpace is + * not set to pdFALSE; + * + * @param eState The TaskStatus_t structure contains a member to report the + * state of the task being queried. Obtaining the task state is not as fast as + * a simple assignment - so the eState parameter is provided to allow the state + * information to be omitted from the TaskStatus_t structure. To obtain state + * information then set eState to eInvalid - otherwise the value passed in + * eState will be reported as the task state in the TaskStatus_t structure. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ TaskHandle_t xHandle;
+ TaskStatus_t xTaskDetails;
+
+    // Obtain the handle of a task from its name.
+    xHandle = xTaskGetHandle( "Task_Name" );
+
+    // Check the handle is not NULL.
+    configASSERT( xHandle );
+
+    // Use the handle to obtain further information about the task.
+    vTaskGetInfo( xHandle,
+                  &xTaskDetails,
+                  pdTRUE, // Include the high water mark in xTaskDetails.
+                  eInvalid ); // Include the task state in xTaskDetails.
+ }
+   
+ * \defgroup vTaskGetInfo vTaskGetInfo + * \ingroup TaskCtrl + */ +void vTaskGetInfo(TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority );
+ * + * INCLUDE_vTaskPrioritySet must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Set the priority of any task. + * + * A context switch will occur before the function returns if the priority + * being set is higher than the currently executing task. + * + * @param xTask Handle to the task for which the priority is being set. + * Passing a NULL handle results in the priority of the calling task being set. + * + * @param uxNewPriority The priority to which the task will be set. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ TaskHandle_t xHandle;
+
+	 // Create a task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // ...
+
+	 // Use the handle to raise the priority of the created task.
+	 vTaskPrioritySet( xHandle, tskIDLE_PRIORITY + 1 );
+
+	 // ...
+
+	 // Use a NULL handle to raise our priority to the same value.
+	 vTaskPrioritySet( NULL, tskIDLE_PRIORITY + 1 );
+ }
+   
+ * \defgroup vTaskPrioritySet vTaskPrioritySet + * \ingroup TaskCtrl + */ +void vTaskPrioritySet(TaskHandle_t xTask, UBaseType_t uxNewPriority) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskSuspend( TaskHandle_t xTaskToSuspend );
+ * + * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Suspend any task. When suspended a task will never get any microcontroller + * processing time, no matter what its priority. + * + * Calls to vTaskSuspend are not accumulative - + * i.e. calling vTaskSuspend () twice on the same task still only requires one + * call to vTaskResume () to ready the suspended task. + * + * @param xTaskToSuspend Handle to the task being suspended. Passing a NULL + * handle will cause the calling task to be suspended. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ TaskHandle_t xHandle;
+
+	 // Create a task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // ...
+
+	 // Use the handle to suspend the created task.
+	 vTaskSuspend( xHandle );
+
+	 // ...
+
+	 // The created task will not run during this period, unless
+	 // another task calls vTaskResume( xHandle ).
+
+	 //...
+
+
+	 // Suspend ourselves.
+	 vTaskSuspend( NULL );
+
+	 // We cannot get here unless another task calls vTaskResume
+	 // with our handle as the parameter.
+ }
+   
+ * \defgroup vTaskSuspend vTaskSuspend + * \ingroup TaskCtrl + */ +void vTaskSuspend(TaskHandle_t xTaskToSuspend) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskResume( TaskHandle_t xTaskToResume );
+ * + * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Resumes a suspended task. + * + * A task that has been suspended by one or more calls to vTaskSuspend () + * will be made available for running again by a single call to + * vTaskResume (). + * + * @param xTaskToResume Handle to the task being readied. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ TaskHandle_t xHandle;
+
+	 // Create a task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // ...
+
+	 // Use the handle to suspend the created task.
+	 vTaskSuspend( xHandle );
+
+	 // ...
+
+	 // The created task will not run during this period, unless
+	 // another task calls vTaskResume( xHandle ).
+
+	 //...
+
+
+	 // Resume the suspended task ourselves.
+	 vTaskResume( xHandle );
+
+	 // The created task will once again get microcontroller processing
+	 // time in accordance with its priority within the system.
+ }
+   
+ * \defgroup vTaskResume vTaskResume + * \ingroup TaskCtrl + */ +void vTaskResume(TaskHandle_t xTaskToResume) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void xTaskResumeFromISR( TaskHandle_t xTaskToResume );
+ * + * INCLUDE_xTaskResumeFromISR must be defined as 1 for this function to be + * available. See the configuration section for more information. + * + * An implementation of vTaskResume() that can be called from within an ISR. + * + * A task that has been suspended by one or more calls to vTaskSuspend () + * will be made available for running again by a single call to + * xTaskResumeFromISR (). + * + * xTaskResumeFromISR() should not be used to synchronise a task with an + * interrupt if there is a chance that the interrupt could arrive prior to the + * task being suspended - as this can lead to interrupts being missed. Use of a + * semaphore as a synchronisation mechanism would avoid this eventuality. + * + * @param xTaskToResume Handle to the task being readied. + * + * @return pdTRUE if resuming the task should result in a context switch, + * otherwise pdFALSE. This is used by the ISR to determine if a context switch + * may be required following the ISR. + * + * \defgroup vTaskResumeFromISR vTaskResumeFromISR + * \ingroup TaskCtrl + */ +BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume) PRIVILEGED_FUNCTION; + +/*----------------------------------------------------------- + * SCHEDULER CONTROL + *----------------------------------------------------------*/ + +/** + * task. h + *
void vTaskStartScheduler( void );
+ * + * Starts the real time kernel tick processing. After calling the kernel + * has control over which tasks are executed and when. + * + * See the demo application file main.c for an example of creating + * tasks and starting the kernel. + * + * Example usage: +
+ void vAFunction( void )
+ {
+	 // Create at least one task before starting the kernel.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+
+	 // Start the real time kernel with preemption.
+	 vTaskStartScheduler ();
+
+	 // Will not get here unless a task calls vTaskEndScheduler ()
+ }
+   
+ * + * \defgroup vTaskStartScheduler vTaskStartScheduler + * \ingroup SchedulerControl + */ +void vTaskStartScheduler(void) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskEndScheduler( void );
+ * + * NOTE: At the time of writing only the x86 real mode port, which runs on a PC + * in place of DOS, implements this function. + * + * Stops the real time kernel tick. All created tasks will be automatically + * deleted and multitasking (either preemptive or cooperative) will + * stop. Execution then resumes from the point where vTaskStartScheduler () + * was called, as if vTaskStartScheduler () had just returned. + * + * See the demo application file main. c in the demo/PC directory for an + * example that uses vTaskEndScheduler (). + * + * vTaskEndScheduler () requires an exit function to be defined within the + * portable layer (see vPortEndScheduler () in port. c for the PC port). This + * performs hardware specific operations such as stopping the kernel tick. + * + * vTaskEndScheduler () will cause all of the resources allocated by the + * kernel to be freed - but will not free resources allocated by application + * tasks. + * + * Example usage: +
+ void vTaskCode( void * pvParameters )
+ {
+	 for( ;; )
+	 {
+		 // Task code goes here.
+
+		 // At some point we want to end the real time kernel processing
+		 // so call ...
+		 vTaskEndScheduler ();
+	 }
+ }
+
+ void vAFunction( void )
+ {
+	 // Create at least one task before starting the kernel.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+
+	 // Start the real time kernel with preemption.
+	 vTaskStartScheduler ();
+
+	 // Will only get here when the vTaskCode () task has called
+	 // vTaskEndScheduler ().  When we get here we are back to single task
+	 // execution.
+ }
+   
+ * + * \defgroup vTaskEndScheduler vTaskEndScheduler + * \ingroup SchedulerControl + */ +void vTaskEndScheduler(void) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskSuspendAll( void );
+ * + * Suspends the scheduler without disabling interrupts. Context switches will + * not occur while the scheduler is suspended. + * + * After calling vTaskSuspendAll () the calling task will continue to execute + * without risk of being swapped out until a call to xTaskResumeAll () has been + * made. + * + * API functions that have the potential to cause a context switch (for example, + * vTaskDelayUntil(), xQueueSend(), etc.) must not be called while the scheduler + * is suspended. + * + * Example usage: +
+ void vTask1( void * pvParameters )
+ {
+	 for( ;; )
+	 {
+		 // Task code goes here.
+
+		 // ...
+
+		 // At some point the task wants to perform a long operation during
+		 // which it does not want to get swapped out.  It cannot use
+		 // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
+		 // operation may cause interrupts to be missed - including the
+		 // ticks.
+
+		 // Prevent the real time kernel swapping out the task.
+		 vTaskSuspendAll ();
+
+		 // Perform the operation here.  There is no need to use critical
+		 // sections as we have all the microcontroller processing time.
+		 // During this time interrupts will still operate and the kernel
+		 // tick count will be maintained.
+
+		 // ...
+
+		 // The operation is complete.  Restart the kernel.
+		 xTaskResumeAll ();
+	 }
+ }
+   
+ * \defgroup vTaskSuspendAll vTaskSuspendAll + * \ingroup SchedulerControl + */ +void vTaskSuspendAll(void) PRIVILEGED_FUNCTION; + +/** + * task. h + *
BaseType_t xTaskResumeAll( void );
+ * + * Resumes scheduler activity after it was suspended by a call to + * vTaskSuspendAll(). + * + * xTaskResumeAll() only resumes the scheduler. It does not unsuspend tasks + * that were previously suspended by a call to vTaskSuspend(). + * + * @return If resuming the scheduler caused a context switch then pdTRUE is + * returned, otherwise pdFALSE is returned. + * + * Example usage: +
+ void vTask1( void * pvParameters )
+ {
+	 for( ;; )
+	 {
+		 // Task code goes here.
+
+		 // ...
+
+		 // At some point the task wants to perform a long operation during
+		 // which it does not want to get swapped out.  It cannot use
+		 // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
+		 // operation may cause interrupts to be missed - including the
+		 // ticks.
+
+		 // Prevent the real time kernel swapping out the task.
+		 vTaskSuspendAll ();
+
+		 // Perform the operation here.  There is no need to use critical
+		 // sections as we have all the microcontroller processing time.
+		 // During this time interrupts will still operate and the real
+		 // time kernel tick count will be maintained.
+
+		 // ...
+
+		 // The operation is complete.  Restart the kernel.  We want to force
+		 // a context switch - but there is no point if resuming the scheduler
+		 // caused a context switch already.
+		 if( !xTaskResumeAll () )
+		 {
+			  taskYIELD ();
+		 }
+	 }
+ }
+   
+ * \defgroup xTaskResumeAll xTaskResumeAll + * \ingroup SchedulerControl + */ +BaseType_t xTaskResumeAll(void) PRIVILEGED_FUNCTION; + +/*----------------------------------------------------------- + * TASK UTILITIES + *----------------------------------------------------------*/ + +/** + * task. h + *
TickType_t xTaskGetTickCount( void );
+ * + * @return The count of ticks since vTaskStartScheduler was called. + * + * \defgroup xTaskGetTickCount xTaskGetTickCount + * \ingroup TaskUtils + */ +TickType_t xTaskGetTickCount(void) PRIVILEGED_FUNCTION; + +/** + * task. h + *
TickType_t xTaskGetTickCountFromISR( void );
+ * + * @return The count of ticks since vTaskStartScheduler was called. + * + * This is a version of xTaskGetTickCount() that is safe to be called from an + * ISR - provided that TickType_t is the natural word size of the + * microcontroller being used or interrupt nesting is either not supported or + * not being used. + * + * \defgroup xTaskGetTickCountFromISR xTaskGetTickCountFromISR + * \ingroup TaskUtils + */ +TickType_t xTaskGetTickCountFromISR(void) PRIVILEGED_FUNCTION; + +/** + * task. h + *
uint16_t uxTaskGetNumberOfTasks( void );
+ * + * @return The number of tasks that the real time kernel is currently managing. + * This includes all ready, blocked and suspended tasks. A task that + * has been deleted but not yet freed by the idle task will also be + * included in the count. + * + * \defgroup uxTaskGetNumberOfTasks uxTaskGetNumberOfTasks + * \ingroup TaskUtils + */ +UBaseType_t uxTaskGetNumberOfTasks(void) PRIVILEGED_FUNCTION; + +/** + * task. h + *
char *pcTaskGetName( TaskHandle_t xTaskToQuery );
+ * + * @return The text (human readable) name of the task referenced by the handle + * xTaskToQuery. A task can query its own name by either passing in its own + * handle, or by setting xTaskToQuery to NULL. + * + * \defgroup pcTaskGetName pcTaskGetName + * \ingroup TaskUtils + */ +char *pcTaskGetName(TaskHandle_t xTaskToQuery) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** + * task. h + *
TaskHandle_t xTaskGetHandle( const char *pcNameToQuery );
+ * + * NOTE: This function takes a relatively long time to complete and should be + * used sparingly. + * + * @return The handle of the task that has the human readable name pcNameToQuery. + * NULL is returned if no matching name is found. INCLUDE_xTaskGetHandle + * must be set to 1 in FreeRTOSConfig.h for pcTaskGetHandle() to be available. + * + * \defgroup pcTaskGetHandle pcTaskGetHandle + * \ingroup TaskUtils + */ +TaskHandle_t xTaskGetHandle(const char *pcNameToQuery) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** + * task.h + *
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );
+ * + * INCLUDE_uxTaskGetStackHighWaterMark must be set to 1 in FreeRTOSConfig.h for + * this function to be available. + * + * Returns the high water mark of the stack associated with xTask. That is, + * the minimum free stack space there has been (in words, so on a 32 bit machine + * a value of 1 means 4 bytes) since the task started. The smaller the returned + * number the closer the task has come to overflowing its stack. + * + * @param xTask Handle of the task associated with the stack to be checked. + * Set xTask to NULL to check the stack of the calling task. + * + * @return The smallest amount of free stack space there has been (in words, so + * actual spaces on the stack rather than bytes) since the task referenced by + * xTask was created. + */ +UBaseType_t uxTaskGetStackHighWaterMark(TaskHandle_t xTask) PRIVILEGED_FUNCTION; + +/* When using trace macros it is sometimes necessary to include task.h before +FreeRTOS.h. When this is done TaskHookFunction_t will not yet have been defined, +so the following two prototypes will cause a compilation error. This can be +fixed by simply guarding against the inclusion of these two prototypes unless +they are explicitly required by the configUSE_APPLICATION_TASK_TAG configuration +constant. */ +#ifdef configUSE_APPLICATION_TASK_TAG +#if configUSE_APPLICATION_TASK_TAG == 1 +/** + * task.h + *
void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction );
+ * + * Sets pxHookFunction to be the task hook function used by the task xTask. + * Passing xTask as NULL has the effect of setting the calling tasks hook + * function. + */ +void vTaskSetApplicationTaskTag(TaskHandle_t xTask, TaskHookFunction_t pxHookFunction) PRIVILEGED_FUNCTION; + +/** + * task.h + *
void xTaskGetApplicationTaskTag( TaskHandle_t xTask );
+ * + * Returns the pxHookFunction value assigned to the task xTask. + */ +TaskHookFunction_t xTaskGetApplicationTaskTag(TaskHandle_t xTask) PRIVILEGED_FUNCTION; +#endif /* configUSE_APPLICATION_TASK_TAG ==1 */ +#endif /* ifdef configUSE_APPLICATION_TASK_TAG */ + +#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) + +/* Each task contains an array of pointers that is dimensioned by the +configNUM_THREAD_LOCAL_STORAGE_POINTERS setting in FreeRTOSConfig.h. The +kernel does not use the pointers itself, so the application writer can use +the pointers for any purpose they wish. The following two functions are +used to set and query a pointer respectively. */ +void vTaskSetThreadLocalStoragePointer(TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue) PRIVILEGED_FUNCTION; +void *pvTaskGetThreadLocalStoragePointer(TaskHandle_t xTaskToQuery, BaseType_t xIndex) PRIVILEGED_FUNCTION; + +#endif + +/** + * task.h + *
BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter );
+ * + * Calls the hook function associated with xTask. Passing xTask as NULL has + * the effect of calling the Running tasks (the calling task) hook function. + * + * pvParameter is passed to the hook function for the task to interpret as it + * wants. The return value is the value returned by the task hook function + * registered by the user. + */ +BaseType_t xTaskCallApplicationTaskHook(TaskHandle_t xTask, void *pvParameter) PRIVILEGED_FUNCTION; + +/** + * xTaskGetIdleTaskHandle() is only available if + * INCLUDE_xTaskGetIdleTaskHandle is set to 1 in FreeRTOSConfig.h. + * + * Simply returns the handle of the idle task. It is not valid to call + * xTaskGetIdleTaskHandle() before the scheduler has been started. + */ +TaskHandle_t xTaskGetIdleTaskHandle(void) PRIVILEGED_FUNCTION; + +/** + * configUSE_TRACE_FACILITY must be defined as 1 in FreeRTOSConfig.h for + * uxTaskGetSystemState() to be available. + * + * uxTaskGetSystemState() populates an TaskStatus_t structure for each task in + * the system. TaskStatus_t structures contain, among other things, members + * for the task handle, task name, task priority, task state, and total amount + * of run time consumed by the task. See the TaskStatus_t structure + * definition in this file for the full member list. + * + * NOTE: This function is intended for debugging use only as its use results in + * the scheduler remaining suspended for an extended period. + * + * @param pxTaskStatusArray A pointer to an array of TaskStatus_t structures. + * The array must contain at least one TaskStatus_t structure for each task + * that is under the control of the RTOS. The number of tasks under the control + * of the RTOS can be determined using the uxTaskGetNumberOfTasks() API function. + * + * @param uxArraySize The size of the array pointed to by the pxTaskStatusArray + * parameter. The size is specified as the number of indexes in the array, or + * the number of TaskStatus_t structures contained in the array, not by the + * number of bytes in the array. + * + * @param pulTotalRunTime If configGENERATE_RUN_TIME_STATS is set to 1 in + * FreeRTOSConfig.h then *pulTotalRunTime is set by uxTaskGetSystemState() to the + * total run time (as defined by the run time stats clock, see + * http://www.freertos.org/rtos-run-time-stats.html) since the target booted. + * pulTotalRunTime can be set to NULL to omit the total run time information. + * + * @return The number of TaskStatus_t structures that were populated by + * uxTaskGetSystemState(). This should equal the number returned by the + * uxTaskGetNumberOfTasks() API function, but will be zero if the value passed + * in the uxArraySize parameter was too small. + * + * Example usage: +
+    // This example demonstrates how a human readable table of run time stats
+	// information is generated from raw data provided by uxTaskGetSystemState().
+	// The human readable table is written to pcWriteBuffer
+	void vTaskGetRunTimeStats( char *pcWriteBuffer )
+	{
+	TaskStatus_t *pxTaskStatusArray;
+	volatile UBaseType_t uxArraySize, x;
+	uint32_t ulTotalRunTime, ulStatsAsPercentage;
+
+		// Make sure the write buffer does not contain a string.
+		*pcWriteBuffer = 0x00;
+
+		// Take a snapshot of the number of tasks in case it changes while this
+		// function is executing.
+		uxArraySize = uxTaskGetNumberOfTasks();
+
+		// Allocate a TaskStatus_t structure for each task.  An array could be
+		// allocated statically at compile time.
+		pxTaskStatusArray = pvPortMalloc( uxArraySize * sizeof( TaskStatus_t ) );
+
+		if( pxTaskStatusArray != NULL )
+		{
+			// Generate raw status information about each task.
+			uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalRunTime );
+
+			// For percentage calculations.
+			ulTotalRunTime /= 100UL;
+
+			// Avoid divide by zero errors.
+			if( ulTotalRunTime > 0 )
+			{
+				// For each populated position in the pxTaskStatusArray array,
+				// format the raw data as human readable ASCII data
+				for( x = 0; x < uxArraySize; x++ )
+				{
+					// What percentage of the total run time has the task used?
+					// This will always be rounded down to the nearest integer.
+					// ulTotalRunTimeDiv100 has already been divided by 100.
+					ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalRunTime;
+
+					if( ulStatsAsPercentage > 0UL )
+					{
+						sprintf( pcWriteBuffer, "%s\t\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage );
+					}
+					else
+					{
+						// If the percentage is zero here then the task has
+						// consumed less than 1% of the total run time.
+						sprintf( pcWriteBuffer, "%s\t\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter );
+					}
+
+					pcWriteBuffer += strlen( ( char * ) pcWriteBuffer );
+				}
+			}
+
+			// The array is no longer needed, free the memory it consumes.
+			vPortFree( pxTaskStatusArray );
+		}
+	}
+	
+ */ +UBaseType_t uxTaskGetSystemState(TaskStatus_t *const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t *const pulTotalRunTime) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskList( char *pcWriteBuffer );
+ * + * configUSE_TRACE_FACILITY and configUSE_STATS_FORMATTING_FUNCTIONS must + * both be defined as 1 for this function to be available. See the + * configuration section of the FreeRTOS.org website for more information. + * + * NOTE 1: This function will disable interrupts for its duration. It is + * not intended for normal application runtime use but as a debug aid. + * + * Lists all the current tasks, along with their current state and stack + * usage high water mark. + * + * Tasks are reported as blocked ('B'), ready ('R'), deleted ('D') or + * suspended ('S'). + * + * PLEASE NOTE: + * + * This function is provided for convenience only, and is used by many of the + * demo applications. Do not consider it to be part of the scheduler. + * + * vTaskList() calls uxTaskGetSystemState(), then formats part of the + * uxTaskGetSystemState() output into a human readable table that displays task + * names, states and stack usage. + * + * vTaskList() has a dependency on the sprintf() C library function that might + * bloat the code size, use a lot of stack, and provide different results on + * different platforms. An alternative, tiny, third party, and limited + * functionality implementation of sprintf() is provided in many of the + * FreeRTOS/Demo sub-directories in a file called printf-stdarg.c (note + * printf-stdarg.c does not provide a full snprintf() implementation!). + * + * It is recommended that production systems call uxTaskGetSystemState() + * directly to get access to raw stats data, rather than indirectly through a + * call to vTaskList(). + * + * @param pcWriteBuffer A buffer into which the above mentioned details + * will be written, in ASCII form. This buffer is assumed to be large + * enough to contain the generated report. Approximately 40 bytes per + * task should be sufficient. + * + * \defgroup vTaskList vTaskList + * \ingroup TaskUtils + */ +void vTaskList(char *pcWriteBuffer) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** + * task. h + *
void vTaskGetRunTimeStats( char *pcWriteBuffer );
+ * + * configGENERATE_RUN_TIME_STATS and configUSE_STATS_FORMATTING_FUNCTIONS + * must both be defined as 1 for this function to be available. The application + * must also then provide definitions for + * portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() and portGET_RUN_TIME_COUNTER_VALUE() + * to configure a peripheral timer/counter and return the timers current count + * value respectively. The counter should be at least 10 times the frequency of + * the tick count. + * + * NOTE 1: This function will disable interrupts for its duration. It is + * not intended for normal application runtime use but as a debug aid. + * + * Setting configGENERATE_RUN_TIME_STATS to 1 will result in a total + * accumulated execution time being stored for each task. The resolution + * of the accumulated time value depends on the frequency of the timer + * configured by the portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() macro. + * Calling vTaskGetRunTimeStats() writes the total execution time of each + * task into a buffer, both as an absolute count value and as a percentage + * of the total system execution time. + * + * NOTE 2: + * + * This function is provided for convenience only, and is used by many of the + * demo applications. Do not consider it to be part of the scheduler. + * + * vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats part of the + * uxTaskGetSystemState() output into a human readable table that displays the + * amount of time each task has spent in the Running state in both absolute and + * percentage terms. + * + * vTaskGetRunTimeStats() has a dependency on the sprintf() C library function + * that might bloat the code size, use a lot of stack, and provide different + * results on different platforms. An alternative, tiny, third party, and + * limited functionality implementation of sprintf() is provided in many of the + * FreeRTOS/Demo sub-directories in a file called printf-stdarg.c (note + * printf-stdarg.c does not provide a full snprintf() implementation!). + * + * It is recommended that production systems call uxTaskGetSystemState() directly + * to get access to raw stats data, rather than indirectly through a call to + * vTaskGetRunTimeStats(). + * + * @param pcWriteBuffer A buffer into which the execution times will be + * written, in ASCII form. This buffer is assumed to be large enough to + * contain the generated report. Approximately 40 bytes per task should + * be sufficient. + * + * \defgroup vTaskGetRunTimeStats vTaskGetRunTimeStats + * \ingroup TaskUtils + */ +void vTaskGetRunTimeStats(char *pcWriteBuffer) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** + * task. h + *
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction );
+ * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this + * function to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * A notification sent to a task will remain pending until it is cleared by the + * task calling xTaskNotifyWait() or ulTaskNotifyTake(). If the task was + * already in the Blocked state to wait for a notification when the notification + * arrives then the task will automatically be removed from the Blocked state + * (unblocked) and the notification cleared. + * + * A task can use xTaskNotifyWait() to [optionally] block to wait for a + * notification to be pending, or ulTaskNotifyTake() to [optionally] block + * to wait for its notification value to have a non-zero value. The task does + * not consume any CPU time while it is in the Blocked state. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for details. + * + * @param xTaskToNotify The handle of the task being notified. The handle to a + * task can be returned from the xTaskCreate() API function used to create the + * task, and the handle of the currently running task can be obtained by calling + * xTaskGetCurrentTaskHandle(). + * + * @param ulValue Data that can be sent with the notification. How the data is + * used depends on the value of the eAction parameter. + * + * @param eAction Specifies how the notification updates the task's notification + * value, if at all. Valid values for eAction are as follows: + * + * eSetBits - + * The task's notification value is bitwise ORed with ulValue. xTaskNofify() + * always returns pdPASS in this case. + * + * eIncrement - + * The task's notification value is incremented. ulValue is not used and + * xTaskNotify() always returns pdPASS in this case. + * + * eSetValueWithOverwrite - + * The task's notification value is set to the value of ulValue, even if the + * task being notified had not yet processed the previous notification (the + * task already had a notification pending). xTaskNotify() always returns + * pdPASS in this case. + * + * eSetValueWithoutOverwrite - + * If the task being notified did not already have a notification pending then + * the task's notification value is set to ulValue and xTaskNotify() will + * return pdPASS. If the task being notified already had a notification + * pending then no action is performed and pdFAIL is returned. + * + * eNoAction - + * The task receives a notification without its notification value being + * updated. ulValue is not used and xTaskNotify() always returns pdPASS in + * this case. + * + * pulPreviousNotificationValue - + * Can be used to pass out the subject task's notification value before any + * bits are modified by the notify function. + * + * @return Dependent on the value of eAction. See the description of the + * eAction parameter. + * + * \defgroup xTaskNotify xTaskNotify + * \ingroup TaskNotifications + */ +BaseType_t xTaskGenericNotify(TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue) PRIVILEGED_FUNCTION; +#define xTaskNotify( xTaskToNotify, ulValue, eAction ) xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL ) +#define xTaskNotifyAndQuery( xTaskToNotify, ulValue, eAction, pulPreviousNotifyValue ) xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotifyValue ) ) + +/** + * task. h + *
BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, BaseType_t *pxHigherPriorityTaskWoken );
+ * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this + * function to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * A version of xTaskNotify() that can be used from an interrupt service routine + * (ISR). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * A notification sent to a task will remain pending until it is cleared by the + * task calling xTaskNotifyWait() or ulTaskNotifyTake(). If the task was + * already in the Blocked state to wait for a notification when the notification + * arrives then the task will automatically be removed from the Blocked state + * (unblocked) and the notification cleared. + * + * A task can use xTaskNotifyWait() to [optionally] block to wait for a + * notification to be pending, or ulTaskNotifyTake() to [optionally] block + * to wait for its notification value to have a non-zero value. The task does + * not consume any CPU time while it is in the Blocked state. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for details. + * + * @param xTaskToNotify The handle of the task being notified. The handle to a + * task can be returned from the xTaskCreate() API function used to create the + * task, and the handle of the currently running task can be obtained by calling + * xTaskGetCurrentTaskHandle(). + * + * @param ulValue Data that can be sent with the notification. How the data is + * used depends on the value of the eAction parameter. + * + * @param eAction Specifies how the notification updates the task's notification + * value, if at all. Valid values for eAction are as follows: + * + * eSetBits - + * The task's notification value is bitwise ORed with ulValue. xTaskNofify() + * always returns pdPASS in this case. + * + * eIncrement - + * The task's notification value is incremented. ulValue is not used and + * xTaskNotify() always returns pdPASS in this case. + * + * eSetValueWithOverwrite - + * The task's notification value is set to the value of ulValue, even if the + * task being notified had not yet processed the previous notification (the + * task already had a notification pending). xTaskNotify() always returns + * pdPASS in this case. + * + * eSetValueWithoutOverwrite - + * If the task being notified did not already have a notification pending then + * the task's notification value is set to ulValue and xTaskNotify() will + * return pdPASS. If the task being notified already had a notification + * pending then no action is performed and pdFAIL is returned. + * + * eNoAction - + * The task receives a notification without its notification value being + * updated. ulValue is not used and xTaskNotify() always returns pdPASS in + * this case. + * + * @param pxHigherPriorityTaskWoken xTaskNotifyFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending the notification caused the + * task to which the notification was sent to leave the Blocked state, and the + * unblocked task has a priority higher than the currently running task. If + * xTaskNotifyFromISR() sets this value to pdTRUE then a context switch should + * be requested before the interrupt is exited. How a context switch is + * requested from an ISR is dependent on the port - see the documentation page + * for the port in use. + * + * @return Dependent on the value of eAction. See the description of the + * eAction parameter. + * + * \defgroup xTaskNotify xTaskNotify + * \ingroup TaskNotifications + */ +BaseType_t xTaskGenericNotifyFromISR(TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken) PRIVILEGED_FUNCTION; +#define xTaskNotifyFromISR( xTaskToNotify, ulValue, eAction, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL, ( pxHigherPriorityTaskWoken ) ) +#define xTaskNotifyAndQueryFromISR( xTaskToNotify, ulValue, eAction, pulPreviousNotificationValue, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotificationValue ), ( pxHigherPriorityTaskWoken ) ) + +/** + * task. h + *
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait );
+ * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this + * function to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * A notification sent to a task will remain pending until it is cleared by the + * task calling xTaskNotifyWait() or ulTaskNotifyTake(). If the task was + * already in the Blocked state to wait for a notification when the notification + * arrives then the task will automatically be removed from the Blocked state + * (unblocked) and the notification cleared. + * + * A task can use xTaskNotifyWait() to [optionally] block to wait for a + * notification to be pending, or ulTaskNotifyTake() to [optionally] block + * to wait for its notification value to have a non-zero value. The task does + * not consume any CPU time while it is in the Blocked state. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for details. + * + * @param ulBitsToClearOnEntry Bits that are set in ulBitsToClearOnEntry value + * will be cleared in the calling task's notification value before the task + * checks to see if any notifications are pending, and optionally blocks if no + * notifications are pending. Setting ulBitsToClearOnEntry to ULONG_MAX (if + * limits.h is included) or 0xffffffffUL (if limits.h is not included) will have + * the effect of resetting the task's notification value to 0. Setting + * ulBitsToClearOnEntry to 0 will leave the task's notification value unchanged. + * + * @param ulBitsToClearOnExit If a notification is pending or received before + * the calling task exits the xTaskNotifyWait() function then the task's + * notification value (see the xTaskNotify() API function) is passed out using + * the pulNotificationValue parameter. Then any bits that are set in + * ulBitsToClearOnExit will be cleared in the task's notification value (note + * *pulNotificationValue is set before any bits are cleared). Setting + * ulBitsToClearOnExit to ULONG_MAX (if limits.h is included) or 0xffffffffUL + * (if limits.h is not included) will have the effect of resetting the task's + * notification value to 0 before the function exits. Setting + * ulBitsToClearOnExit to 0 will leave the task's notification value unchanged + * when the function exits (in which case the value passed out in + * pulNotificationValue will match the task's notification value). + * + * @param pulNotificationValue Used to pass the task's notification value out + * of the function. Note the value passed out will not be effected by the + * clearing of any bits caused by ulBitsToClearOnExit being non-zero. + * + * @param xTicksToWait The maximum amount of time that the task should wait in + * the Blocked state for a notification to be received, should a notification + * not already be pending when xTaskNotifyWait() was called. The task + * will not consume any processing time while it is in the Blocked state. This + * is specified in kernel ticks, the macro pdMS_TO_TICSK( value_in_ms ) can be + * used to convert a time specified in milliseconds to a time specified in + * ticks. + * + * @return If a notification was received (including notifications that were + * already pending when xTaskNotifyWait was called) then pdPASS is + * returned. Otherwise pdFAIL is returned. + * + * \defgroup xTaskNotifyWait xTaskNotifyWait + * \ingroup TaskNotifications + */ +BaseType_t xTaskNotifyWait(uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait) PRIVILEGED_FUNCTION; + +/** + * task. h + *
BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
+ * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this macro + * to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * xTaskNotifyGive() is a helper macro intended for use when task notifications + * are used as light weight and faster binary or counting semaphore equivalents. + * Actual FreeRTOS semaphores are given using the xSemaphoreGive() API function, + * the equivalent action that instead uses a task notification is + * xTaskNotifyGive(). + * + * When task notifications are being used as a binary or counting semaphore + * equivalent then the task being notified should wait for the notification + * using the ulTaskNotificationTake() API function rather than the + * xTaskNotifyWait() API function. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for more details. + * + * @param xTaskToNotify The handle of the task being notified. The handle to a + * task can be returned from the xTaskCreate() API function used to create the + * task, and the handle of the currently running task can be obtained by calling + * xTaskGetCurrentTaskHandle(). + * + * @return xTaskNotifyGive() is a macro that calls xTaskNotify() with the + * eAction parameter set to eIncrement - so pdPASS is always returned. + * + * \defgroup xTaskNotifyGive xTaskNotifyGive + * \ingroup TaskNotifications + */ +#define xTaskNotifyGive( xTaskToNotify ) xTaskGenericNotify( ( xTaskToNotify ), ( 0 ), eIncrement, NULL ) + +/** + * task. h + *
void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle, BaseType_t *pxHigherPriorityTaskWoken );
+ *
+ * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this macro
+ * to be available.
+ *
+ * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private
+ * "notification value", which is a 32-bit unsigned integer (uint32_t).
+ *
+ * A version of xTaskNotifyGive() that can be called from an interrupt service
+ * routine (ISR).
+ *
+ * Events can be sent to a task using an intermediary object.  Examples of such
+ * objects are queues, semaphores, mutexes and event groups.  Task notifications
+ * are a method of sending an event directly to a task without the need for such
+ * an intermediary object.
+ *
+ * A notification sent to a task can optionally perform an action, such as
+ * update, overwrite or increment the task's notification value.  In that way
+ * task notifications can be used to send data to a task, or be used as light
+ * weight and fast binary or counting semaphores.
+ *
+ * vTaskNotifyGiveFromISR() is intended for use when task notifications are
+ * used as light weight and faster binary or counting semaphore equivalents.
+ * Actual FreeRTOS semaphores are given from an ISR using the
+ * xSemaphoreGiveFromISR() API function, the equivalent action that instead uses
+ * a task notification is vTaskNotifyGiveFromISR().
+ *
+ * When task notifications are being used as a binary or counting semaphore
+ * equivalent then the task being notified should wait for the notification
+ * using the ulTaskNotificationTake() API function rather than the
+ * xTaskNotifyWait() API function.
+ *
+ * See http://www.FreeRTOS.org/RTOS-task-notifications.html for more details.
+ *
+ * @param xTaskToNotify The handle of the task being notified.  The handle to a
+ * task can be returned from the xTaskCreate() API function used to create the
+ * task, and the handle of the currently running task can be obtained by calling
+ * xTaskGetCurrentTaskHandle().
+ *
+ * @param pxHigherPriorityTaskWoken  vTaskNotifyGiveFromISR() will set
+ * *pxHigherPriorityTaskWoken to pdTRUE if sending the notification caused the
+ * task to which the notification was sent to leave the Blocked state, and the
+ * unblocked task has a priority higher than the currently running task.  If
+ * vTaskNotifyGiveFromISR() sets this value to pdTRUE then a context switch
+ * should be requested before the interrupt is exited.  How a context switch is
+ * requested from an ISR is dependent on the port - see the documentation page
+ * for the port in use.
+ *
+ * \defgroup xTaskNotifyWait xTaskNotifyWait
+ * \ingroup TaskNotifications
+ */
+void vTaskNotifyGiveFromISR(TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * 
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
+ * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this + * function to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * ulTaskNotifyTake() is intended for use when a task notification is used as a + * faster and lighter weight binary or counting semaphore alternative. Actual + * FreeRTOS semaphores are taken using the xSemaphoreTake() API function, the + * equivalent action that instead uses a task notification is + * ulTaskNotifyTake(). + * + * When a task is using its notification value as a binary or counting semaphore + * other tasks should send notifications to it using the xTaskNotifyGive() + * macro, or xTaskNotify() function with the eAction parameter set to + * eIncrement. + * + * ulTaskNotifyTake() can either clear the task's notification value to + * zero on exit, in which case the notification value acts like a binary + * semaphore, or decrement the task's notification value on exit, in which case + * the notification value acts like a counting semaphore. + * + * A task can use ulTaskNotifyTake() to [optionally] block to wait for a + * the task's notification value to be non-zero. The task does not consume any + * CPU time while it is in the Blocked state. + * + * Where as xTaskNotifyWait() will return when a notification is pending, + * ulTaskNotifyTake() will return when the task's notification value is + * not zero. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for details. + * + * @param xClearCountOnExit if xClearCountOnExit is pdFALSE then the task's + * notification value is decremented when the function exits. In this way the + * notification value acts like a counting semaphore. If xClearCountOnExit is + * not pdFALSE then the task's notification value is cleared to zero when the + * function exits. In this way the notification value acts like a binary + * semaphore. + * + * @param xTicksToWait The maximum amount of time that the task should wait in + * the Blocked state for the task's notification value to be greater than zero, + * should the count not already be greater than zero when + * ulTaskNotifyTake() was called. The task will not consume any processing + * time while it is in the Blocked state. This is specified in kernel ticks, + * the macro pdMS_TO_TICSK( value_in_ms ) can be used to convert a time + * specified in milliseconds to a time specified in ticks. + * + * @return The task's notification count before it is either cleared to zero or + * decremented (see the xClearCountOnExit parameter). + * + * \defgroup ulTaskNotifyTake ulTaskNotifyTake + * \ingroup TaskNotifications + */ +uint32_t ulTaskNotifyTake(BaseType_t xClearCountOnExit, TickType_t xTicksToWait) PRIVILEGED_FUNCTION; + +/** + * task. h + *
BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask );
+ * + * If the notification state of the task referenced by the handle xTask is + * eNotified, then set the task's notification state to eNotWaitingNotification. + * The task's notification value is not altered. Set xTask to NULL to clear the + * notification state of the calling task. + * + * @return pdTRUE if the task's notification state was set to + * eNotWaitingNotification, otherwise pdFALSE. + * \defgroup xTaskNotifyStateClear xTaskNotifyStateClear + * \ingroup TaskNotifications + */ +BaseType_t xTaskNotifyStateClear(TaskHandle_t xTask); + +/*----------------------------------------------------------- + * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES + *----------------------------------------------------------*/ + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY + * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS + * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * Called from the real time kernel tick (either preemptive or cooperative), + * this increments the tick count and checks if any tasks that are blocked + * for a finite period required removing from a blocked list and placing on + * a ready list. If a non-zero value is returned then a context switch is + * required because either: + * + A task was removed from a blocked list because its timeout had expired, + * or + * + Time slicing is in use and there is a task of equal priority to the + * currently running task. + */ +BaseType_t xTaskIncrementTick(void) PRIVILEGED_FUNCTION; + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN + * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED. + * + * Removes the calling task from the ready list and places it both + * on the list of tasks waiting for a particular event, and the + * list of delayed tasks. The task will be removed from both lists + * and replaced on the ready list should either the event occur (and + * there be no higher priority tasks waiting on the same event) or + * the delay period expires. + * + * The 'unordered' version replaces the event list item value with the + * xItemValue value, and inserts the list item at the end of the list. + * + * The 'ordered' version uses the existing event list item value (which is the + * owning tasks priority) to insert the list item into the event list is task + * priority order. + * + * @param pxEventList The list containing tasks that are blocked waiting + * for the event to occur. + * + * @param xItemValue The item value to use for the event list item when the + * event list is not ordered by task priority. + * + * @param xTicksToWait The maximum amount of time that the task should wait + * for the event to occur. This is specified in kernel ticks,the constant + * portTICK_PERIOD_MS can be used to convert kernel ticks into a real time + * period. + */ +void vTaskPlaceOnEventList(List_t *const pxEventList, const TickType_t xTicksToWait) PRIVILEGED_FUNCTION; +void vTaskPlaceOnUnorderedEventList(List_t *pxEventList, const TickType_t xItemValue, const TickType_t xTicksToWait) PRIVILEGED_FUNCTION; + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN + * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED. + * + * This function performs nearly the same function as vTaskPlaceOnEventList(). + * The difference being that this function does not permit tasks to block + * indefinitely, whereas vTaskPlaceOnEventList() does. + * + */ +void vTaskPlaceOnEventListRestricted(List_t *const pxEventList, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely) PRIVILEGED_FUNCTION; + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN + * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED. + * + * Removes a task from both the specified event list and the list of blocked + * tasks, and places it on a ready queue. + * + * xTaskRemoveFromEventList()/xTaskRemoveFromUnorderedEventList() will be called + * if either an event occurs to unblock a task, or the block timeout period + * expires. + * + * xTaskRemoveFromEventList() is used when the event list is in task priority + * order. It removes the list item from the head of the event list as that will + * have the highest priority owning task of all the tasks on the event list. + * xTaskRemoveFromUnorderedEventList() is used when the event list is not + * ordered and the event list items hold something other than the owning tasks + * priority. In this case the event list item value is updated to the value + * passed in the xItemValue parameter. + * + * @return pdTRUE if the task being removed has a higher priority than the task + * making the call, otherwise pdFALSE. + */ +BaseType_t xTaskRemoveFromEventList(const List_t *const pxEventList) PRIVILEGED_FUNCTION; +BaseType_t xTaskRemoveFromUnorderedEventList(ListItem_t *pxEventListItem, const TickType_t xItemValue) PRIVILEGED_FUNCTION; + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY + * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS + * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * Sets the pointer to the current TCB to the TCB of the highest priority task + * that is ready to run. + */ +int xTaskSwitchContext(void) PRIVILEGED_FUNCTION; + +/* + * THESE FUNCTIONS MUST NOT BE USED FROM APPLICATION CODE. THEY ARE USED BY + * THE EVENT BITS MODULE. + */ +TickType_t uxTaskResetEventItemValue(void) PRIVILEGED_FUNCTION; + +/* + * Return the handle of the calling task. + */ +TaskHandle_t xTaskGetCurrentTaskHandle(void) PRIVILEGED_FUNCTION; + +/* + * Capture the current time status for future reference. + */ +void vTaskSetTimeOutState(TimeOut_t *const pxTimeOut) PRIVILEGED_FUNCTION; + +/* + * Compare the time status now with that previously captured to see if the + * timeout has expired. + */ +BaseType_t xTaskCheckForTimeOut(TimeOut_t *const pxTimeOut, TickType_t *const pxTicksToWait) PRIVILEGED_FUNCTION; + +/* + * Shortcut used by the queue implementation to prevent unnecessary call to + * taskYIELD(); + */ +void vTaskMissedYield(void) PRIVILEGED_FUNCTION; + +/* + * Returns the scheduler state as taskSCHEDULER_RUNNING, + * taskSCHEDULER_NOT_STARTED or taskSCHEDULER_SUSPENDED. + */ +BaseType_t xTaskGetSchedulerState(void) PRIVILEGED_FUNCTION; + +/* + * Raises the priority of the mutex holder to that of the calling task should + * the mutex holder have a priority less than the calling task. + */ +void vTaskPriorityInherit(TaskHandle_t const pxMutexHolder) PRIVILEGED_FUNCTION; + +/* + * Set the priority of a task back to its proper priority in the case that it + * inherited a higher priority while it was holding a semaphore. + */ +BaseType_t xTaskPriorityDisinherit(TaskHandle_t const pxMutexHolder) PRIVILEGED_FUNCTION; + +/* + * Get the uxTCBNumber assigned to the task referenced by the xTask parameter. + */ +UBaseType_t uxTaskGetTaskNumber(TaskHandle_t xTask) PRIVILEGED_FUNCTION; + +/* + * Set the uxTaskNumber of the task referenced by the xTask parameter to + * uxHandle. + */ +void vTaskSetTaskNumber(TaskHandle_t xTask, const UBaseType_t uxHandle) PRIVILEGED_FUNCTION; + +/* + * Only available when configUSE_TICKLESS_IDLE is set to 1. + * If tickless mode is being used, or a low power mode is implemented, then + * the tick interrupt will not execute during idle periods. When this is the + * case, the tick count value maintained by the scheduler needs to be kept up + * to date with the actual execution time by being skipped forward by a time + * equal to the idle period. + */ +void vTaskStepTick(const TickType_t xTicksToJump) PRIVILEGED_FUNCTION; + +TickType_t xGetExpectedIdleTime(void) PRIVILEGED_FUNCTION; +/* + * Only avilable when configUSE_TICKLESS_IDLE is set to 1. + * Provided for use within portSUPPRESS_TICKS_AND_SLEEP() to allow the port + * specific sleep function to determine if it is ok to proceed with the sleep, + * and if it is ok to proceed, if it is ok to sleep indefinitely. + * + * This function is necessary because portSUPPRESS_TICKS_AND_SLEEP() is only + * called with the scheduler suspended, not from within a critical section. It + * is therefore possible for an interrupt to request a context switch between + * portSUPPRESS_TICKS_AND_SLEEP() and the low power mode actually being + * entered. eTaskConfirmSleepModeStatus() should be called from a short + * critical section between the timer being stopped and the sleep mode being + * entered to ensure it is ok to proceed into the sleep mode. + */ +eSleepModeStatus eTaskConfirmSleepModeStatus(void) PRIVILEGED_FUNCTION; + +/* + * For internal use only. Increment the mutex held count when a mutex is + * taken and return the handle of the task that has taken the mutex. + */ +void *pvTaskIncrementMutexHeldCount(void) PRIVILEGED_FUNCTION; + +void vPortStartFirstTask(void) ; + +// TickType_t prvGetExpectedIdleTime(void) PRIVILEGED_FUNCTION; +TickType_t xGetExpectedIdleTime(void); + +void *uxTaskStack(void *tcb); + +#ifdef __cplusplus +} +#endif +#endif /* INC_TASK_H */ + + + diff --git a/include_lib/system/os/os_api.h b/include_lib/system/os/os_api.h new file mode 100644 index 0000000..f4142a7 --- /dev/null +++ b/include_lib/system/os/os_api.h @@ -0,0 +1,442 @@ +#ifndef OS_API_H +#define OS_API_H + + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + +#include "generic/typedef.h" +//#include "generic/list.h" +#include "os/os_cpu.h" +#include "os/os_error.h" +#include "os/os_type.h" + + +typedef void *TaskHandle_t; + +#define Q_MSG 0x100000 +#define Q_EVENT 0x200000 +#define Q_CALLBACK 0x300000 +#define Q_USER 0x400000 + +#define OS_DEL_NO_PEND 0u +#define OS_DEL_ALWAYS 1u + +#define OS_TASK_DEL_REQ 0x01u +#define OS_TASK_DEL_RES 0x02u +#define OS_TASK_DEL_OK 0x03u + + +#define OS_TASK_SELF (char *)0x1 +#define OS_TASK_FATHER (char *)0x2 + + +/* --------------------------------------------------------------------------*/ +/** + * @brief reserved + */ +/* ----------------------------------------------------------------------------*/ +void os_init(void); + +/* --------------------------------------------------------------------------*/ +/** + * @brief reserved + */ +/* ----------------------------------------------------------------------------*/ +void os_start(void); + +/* --------------------------------------------------------------------------*/ +/** + * @brief reserved + */ +/* ----------------------------------------------------------------------------*/ +void os_init_tick(int); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 创建任务 + * + * @param task 任务回调函数 + * @param p_arg 传递给任务回调函数的参数 + * @param prio 任务的优先级 + * @param stksize 任务的堆栈大小, 单位(u32) + * @param qsize 任务的queue大小,单位(byte) + * @param name 任务名 (名字长度不能超过configMAX_TASK_NAME_LEN字节) + * + * @return 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_task_create(void (*task)(void *p_arg), + void *p_arg, + u8 prio, + u32 stksize, + int qsize, + const char *name); + +int os_task_create_affinity_core(void (*task)(void *p_arg), + void *p_arg, + u8 prio, + u32 stksize, + int qsize, + const char *name, + u8 core); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 获取当前任务名 + * + * @return 当前任务名 + */ +/* ----------------------------------------------------------------------------*/ +const char *os_current_task(); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 删除任务 + * + * @param name 任务名 + * + * @return 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_task_del_req(const char *name); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 响应任务删除请求,标记资源已经释放,可以删除当前任 + * + * @param name 任务名,任务自己可以用OS_TASK_SELF + * + * @return 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_task_del_res(const char *name); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 删除任务 + * + * @param name 任务名 + * + * @return 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_task_del(const char *name); + + +/* --------------------------------------------------------------------------*/ +/** + * @brief 延时。中断函数或者关闭系统总中断的情况下不能调用此函数 + * + * @param time_tick 延时时间 + */ +/* ----------------------------------------------------------------------------*/ +void os_time_dly(int time_tick); + + +/* --------------------------------------------------------------------------*/ +/** + * @brief 发送Q_USER类型taskq + * + * @param name 任务名 + * @param argc 后面传入的参数的个数。发送的最大参数个数限制为8个int类型 + * + * @return 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_taskq_post(const char *name, int argc, ...); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 非阻塞方式查询taskq + * + * @param argc 最大可获取的queue长度,单位(int) + * @param argv 存放queue的buf + * + * @return 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_taskq_accept(int argc, int *argv); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 阻塞方式获取taskq + * + * @param fmt 保留,传NULL + * @param argv 存放queue的buf + * @param argc 最大可获取的queue长度,单位(int) + * + * @return 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_taskq_pend(const char *fmt, int *argv, int argc); +// int os_task_pend(const char *fmt, int *argv, int argc); +// int __os_taskq_pend(int *argv, int argc, int tick); + + + +/* --------------------------------------------------------------------------*/ +/** + * @brief 发送指定类型的taskq + * + * @param name 任务名 + * @param type queue类型 + * @param argc 后面传入的参数的个数 + * @param argv + * + * @return 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_taskq_post_type(const char *name, int type, int argc, int *argv); + + +/* --------------------------------------------------------------------------*/ +/** + * @brief 发送Q_MSG类型的taskq + * + * @param name 任务名 + * @param argc 后面参数的个数 + * + * @reutrn 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_taskq_post_msg(const char *name, int argc, ...); + + +/* --------------------------------------------------------------------------*/ +/** + * @brief 发送Q_EVENT类型的taskq + * + * @param name 任务名 + * @param argc 后面参数的个数 + * + * @reutrn 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_taskq_post_event(const char *name, int argc, ...); + + +/* --------------------------------------------------------------------------*/ +/** + * @brief 删除指定类型的taskq + * + * @param name 任务名 + * @param type taskq的类型 + * + * @reutrn 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_taskq_del_type(const char *name, int type); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 清除所有taskq + * + * @reutrn 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_taskq_flush(void); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 创建信号量 + * + * @param sem 信号量 + * @param int 初始计数值 + * + * @reutrn 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_sem_create(OS_SEM *, int); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 非阻塞方式查询信号量 + * + * @param sem 信号量 + * + * @reutrn 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_sem_accept(OS_SEM *); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 阻塞方式获取信号量 + * + * @param sem 信号量 + * @param timeout 等待时长,0表示一直等待 + * + * @reutrn 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_sem_pend(OS_SEM *, int timeout); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 发送信号量 + * + * @param sem 信号量 + * + * @reutrn 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_sem_post(OS_SEM *); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 信号量删除 + * + * @param sem 信号量 + * @param block 保留 + * + * @reutrn 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_sem_del(OS_SEM *, int block); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 信号量设置 + * + * @param sem 信号量 + * @param cnt 计数值 + * + * @reutrn 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_sem_set(OS_SEM *, u16 cnt); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 信号量类型是否queueQUEUE_TYPE_COUNTING_SEMAPHORE + * + * @param true:信号量匹配, fail:信号量不匹配 + * + * @reutrn 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_sem_valid(OS_SEM *); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 判断信号量是否可用 + * + * @param sem 信号量 + * + * @reutrn 可用数量 + */ +/* ----------------------------------------------------------------------------*/ +int os_sem_query(OS_SEM *); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 创建互斥量 + * + * @param mutex 互斥量 + * + * @reutrn 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_mutex_create(OS_MUTEX *); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 非阻塞方式查询互斥量 + * + * @param mutex:互斥量 + * + * @reutrn 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_mutex_accept(OS_MUTEX *); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 阻塞方式查询互斥量 + * + * @param mutex 互斥量 + * @param timeout 等待时间,0表示一直等待 + * + * @reutrn 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_mutex_pend(OS_MUTEX *, int timeout); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 发送斥量 + * + * @param mutex 互斥量 + * + * @reutrn 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_mutex_post(OS_MUTEX *); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 删除斥量 + * + * @param mutex 互斥量 + * @param block 保留 + * + * @reutrn 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_mutex_del(OS_MUTEX *, int block); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 互斥量类型是否queueQUEUE_TYPE_MUTEX + * + * @param true:互斥量匹配, fail:互斥量不匹配 + * + * @reutrn 错误码 + */ +/* ----------------------------------------------------------------------------*/ +int os_mutex_valid(OS_MUTEX *); + +/*struct os_msg *os_message_create(int size); + +int os_message_receive(struct os_msg **msg, int block_time); + +int os_message_send(const char *task_name, struct os_msg *msg, int msgflg); + +int os_message_delete(struct os_msg *msg);*/ + + + +int os_q_create(OS_QUEUE *pevent, /*void **start, */QS size); + +int os_q_del(OS_QUEUE *pevent, u8 opt); + +int os_q_flush(OS_QUEUE *pevent); + +int os_q_pend(OS_QUEUE *pevent, int timeout, void *msg); + +int os_q_post(OS_QUEUE *pevent, void *msg); + +int os_q_query(OS_QUEUE *pevent); + +int os_q_valid(OS_QUEUE *pevent); + +int task_queue_post_event(const char *name, void *data, int len); + +void *os_task_get_handle(const char *name); + +void os_suspend_other_core(void); + +void os_resume_other_core(void); + +void os_system_info_output(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include_lib/system/os/os_cfg.h b/include_lib/system/os/os_cfg.h new file mode 100644 index 0000000..a1eea4f --- /dev/null +++ b/include_lib/system/os/os_cfg.h @@ -0,0 +1,135 @@ +/***********************************Jieli tech************************************************ +File : os_cfg.h +By : Juntham +date : 2014-07-03 09:09 + ********************************************************************************************/ + +#ifndef OS_CFG_H +#define OS_CFG_H +#include "os/os_cpu.h" + +#define OS_TIME_SLICE_EN 1 + +#define OS_PRIORITY_INVERSION 1 /*是否处理优先级翻转*/ + +/* ---------------------- MISCELLANEOUS ----------------------- */ +#define OS_ARG_CHK_EN 0 /* Enable (1) or Disable (0) argument checking */ +#define OS_CPU_HOOKS_EN 1 /* hooks are found in the processor port files */ + +#if OS_TIME_SLICE_EN > 0 +#define OS_LOWEST_PRIO (0) /* Defines the lowest priority that can be assigned ... */ +#else +#define OS_LOWEST_PRIO (0+OS_CPU_CORE-1)/* Defines the lowest priority that can be assigned */ +#endif + +#define OS_IDLE_PRIO (OS_LOWEST_PRIO) /* IDLE task priority */ + +#define OS_MAX_TASKS 31 /* Max. number of tasks in your application, MUST be >= 2 */ + +#define OS_SCHED_LOCK_EN 1 /* Include code for OSSchedLock() and OSSchedUnlock() */ + +#define OS_TICKS_PER_SEC 100 /* Set the number of ticks in one second */ + +#define OS_PARENT_TCB 1 /* 是否记录父任务的TCB */ + +#define OS_CHILD_TCB 0 /* 是否记录子任务的TCB */ + +/* ----------------------TASK MESSAGE QUEUES ---------------------- */ +#define OS_TASKQ_EN 1 /* Enable (1) or Disable (0) code generation for QUEUES */ +#define OS_TASKQ_ACCEPT_EN 1 /* Include code for OSTaskQAccept() */ +#define OS_TASKQ_PEND_EN 1 /* Include code for OSTaskQAccept() */ +#define OS_TASKQ_FLUSH_EN 1 /* Include code for OSTaskQFlush() */ +#define OS_TASKQ_POST_EN 1 /* Include code for OSTaskQPost() */ +#define OS_TASKQ_POST_FRONT_EN 1 /* Include code for OSTaskQPostFront() */ +#define OS_TASKQ_QUERY_EN 1 /* Include code for OSTaskQQuery() */ + +/* ---------------- MUTUAL EXCLUSION SEMAPHORES --------------- */ +#define OS_MUTEX_EN 1 /* Enable (1) or Disable (0) code generation for MUTEX */ +#define OS_MUTEX_ACCEPT_EN 1 /* Include code for OSMutexAccept() */ +#define OS_MUTEX_DEL_EN 1 /* Include code for OSMutexDel() */ +#define OS_MUTEX_QUERY_EN 0 /* Include code for OSMutexQuery() */ + +/* ------------------------ SEMAPHORES ------------------------ */ +#define OS_SEM_EN 1 /* Enable (1) or Disable (0) code generation for SEMAPHORES */ +#define OS_SEM_ACCEPT_EN 1 /* Include code for OSSemAccept() */ +#define OS_SEM_DEL_EN 1 /* Include code for OSSemDel() */ +#define OS_SEM_QUERY_EN 1 /* Include code for OSSemQuery() */ +#define OS_SEM_SET_EN 1 /* Include code for OSSemSet() */ + +/* ---------------------- MESSAGE QUEUES ---------------------- */ +#define OS_Q_EN 1 /* Enable (1) or Disable (0) code generation for QUEUES */ +#define OS_Q_ACCEPT_EN 1 /* Include code for OSQAccept() */ +#define OS_Q_DEL_EN 1 /* Include code for OSQDel() */ +#define OS_Q_FLUSH_EN 1 /* Include code for OSQFlush() */ +#define OS_Q_POST_EN 1 /* Include code for OSQPost() */ +#define OS_Q_POST_FRONT_EN 1 /* Include code for OSQPostFront() */ +#define OS_Q_POST_OPT_EN 1 /* Include code for OSQPostOpt() */ +#define OS_Q_QUERY_EN 1 /* Include code for OSQQuery() */ + +/* ----------------------- EVENT FLAGS ------------------------ */ +#define OS_FLAG_EN 0 /* Enable (1) or Disable (0) code generation for EVENT FLAGS */ +#define OS_MAX_FLAGS 1 /* Max. number of Event Flag Groups in your application */ +#define OS_FLAG_WAIT_CLR_EN 1 /* Include code for Wait on Clear EVENT FLAGS */ +#define OS_FLAG_ACCEPT_EN 1 /* Include code for OSFlagAccept() */ +#define OS_FLAG_DEL_EN 1 /* Include code for OSFlagDel() */ +#define OS_FLAG_NAME_SIZE 0//32 /* Determine the size of the name of an event flag group */ +#define OS_FLAG_QUERY_EN 1 /* Include code for OSFlagQuery() */ +#define OS_FLAGS_NBITS 32 /* Size in #bits of OS_FLAGS data type (8, 16 or 32) */ + +/* --------------------- TASK MANAGEMENT ---------------------- */ +#define OS_TASK_CHANGE_PRIO_EN 1 /* Include code for OSTaskChangePrio() */ +#define OS_TASK_CREATE_EN 1 /* Include code for OSTaskCreate() */ +#define OS_TASK_DEL_EN 1 /* Include code for OSTaskDel() */ +#define OS_TASK_QUERY_EN 0 /* Include code for OSTaskQuery() */ +#define OS_TASK_SUSPEND_EN 1 /* Include code for OSTaskSuspend() and OSTaskResume() */ +#define OS_TASK_SW_HOOK_EN 0 /* Include code for OSTaskSwHook() */ +#define OS_TASK_STK_CHK 0 + +/* --------------------- TIME MANAGEMENT ---------------------- */ +#define OS_TIME_DLY_HMSM_EN 0 /* Include code for OSTimeDlyHMSM() */ +#define OS_TIME_DLY_RESUME_EN 1 /* Include code for OSTimeDlyResume() */ +#define OS_TIME_GET_SET_EN 1 /* Include code for OSTimeGet() and OSTimeSet() */ +#define OS_TIME_TICK_HOOK_EN 0 /* Include code for OSTimeTickHook() */ + +#define OS_EVENT_EN ((OS_Q_EN > 0) || (OS_SEM_EN > 0) || (OS_MUTEX_EN > 0)) + + +//for make +#define portMAX_DELAY 0 + +#ifndef tskIDLE_PRIORITY +#define tskIDLE_PRIORITY 0 +#endif /* #ifndef tskIDLE_PRIORITY */ + +#ifndef configMAX_PRIORITIES +#define configMAX_PRIORITIES 8 +#endif /* #ifndef configMAX_PRIORITIES */ + +#ifndef configSUPPORT_DYNAMIC_ALLOCATION +/* Defaults to 1 for backward compatibility. */ +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#endif + +#ifndef OS_CPU_NUM +#define OS_CPU_NUM CPU_CORE_NUM +#endif /* #ifndef OS_CPU_NUM */ + + +#ifndef OS_MBOX_EN +#define OS_MBOX_EN 0 +#endif + +#ifndef OS_MEM_EN +#define OS_MEM_EN 0 +#endif + + +#ifndef configAPPLICATION_ALLOCATED_HEAP +#define configAPPLICATION_ALLOCATED_HEAP 0 +#endif + +#ifndef configUSE_MALLOC_FAILED_HOOK +#define configUSE_MALLOC_FAILED_HOOK 0 +#endif + +#endif diff --git a/include_lib/system/os/os_cpu.h b/include_lib/system/os/os_cpu.h new file mode 100644 index 0000000..fb9e943 --- /dev/null +++ b/include_lib/system/os/os_cpu.h @@ -0,0 +1,117 @@ +/***********************************Jieli tech************************************************ + File : os_cpu.h + By : Juntham + date : 2014-07-03 09:06 +********************************************************************************************/ +#ifndef _OS_CPU_H +#define _OS_CPU_H + +#include "asm/cpu.h" +#include "jiffies.h" + + +#ifndef __ASSEMBLY__ +typedef unsigned short QS; +typedef unsigned int OS_STK; /* Each stack entry is 32-bit wide*/ +typedef unsigned int OS_CPU_SR; /* Unsigned 32 bit quantity */ +typedef unsigned int OS_CPU_DATA; /* Unsigned 32 bit quantity */ +#endif + +#define OS_CPU_EXT extern +#define OS_CPU_CORE CPU_CORE_NUM + +#define OS_CPU_ID current_cpu_id() +#define OS_STK_GROWTH 1 /* Stack grows from HIGH to LOW memory*/ + +#define OS_CPU_MMU 0 + +#define OS_CPU_VIRTUAL_MEM 1 //临时定义:区别于OS_CPU_MMU + +#ifndef OS_CORE_AFFINITY_ENABLE +#define OS_CORE_AFFINITY_ENABLE 0 +#endif + +#define OS_TASK_CLR(a) CPU_TASK_CLR(a) +#define OS_TASK_SW(a) CPU_TASK_SW(a) /* 任务级任务切换函数*/ +#define OS_INT_NESTING CPU_INT_NESTING + +#define CPU_SR_ALLOC() + +#define OS_SR_ALLOC() + +#define OS_ENTER_CRITICAL() \ + CPU_CRITICAL_ENTER(); \ + +#define OS_EXIT_CRITICAL() \ + CPU_CRITICAL_EXIT() + + + + +#ifndef __ASSEMBLY__ + +/*#include "system/spinlock.h" + +extern spinlock_t os_lock; + +#define OS_ENTER_CRITICAL() \ + spin_lock(&os_lock) + +#define OS_EXIT_CRITICAL() \ + spin_unlock(&os_lock)*/ + + +void OSCtxSw(void); + +extern void EnableOtherCpu(void) ; + +#define os_ctx_sw OSCtxSw + +void OSInitTick(u32 hz); + +void InstallOSISR(void); + +void os_task_dead(const char *task_name); + +//=======================================================// +// 系统进临界区多核同步类型 // +//=======================================================// +enum CPU_SUSPEND_TYPE { + CPU_SUSPEND_TYPE_NONE = 0, + CPU_SUSPEND_TYPE_SFC = 0x55, //操作Flash + CPU_SUSPEND_TYPE_PDOWN, //系统进低功耗Pdown + CPU_SUSPEND_TYPE_POFF, //系统进低功耗Pdown + CPU_SUSPEND_TYPE_SOFF, +}; + +/* ---------------------------------------------------------------------------- */ +/** + * @brief 系统进入临界区用于多核同步 + */ +/* ---------------------------------------------------------------------------- */ +void cpu_suspend_other_core(enum CPU_SUSPEND_TYPE type); + +/* ---------------------------------------------------------------------------- */ +/** + * @brief 系统退出临界区用于多核同步 + */ +/* ---------------------------------------------------------------------------- */ +void cpu_resume_other_core(enum CPU_SUSPEND_TYPE type); + +#endif + +/* +********************************************************************************************************* +* DATA TYPES +* (Compiler Specific) +********************************************************************************************************* +*/ + + +#define OS_CRITICAL_METHOD 3 +#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ +//#define CPU_SR_ALLOC() OS_CPU_SR cpu_sr +#endif + + +#endif /*_OS_CPU_H */ diff --git a/include_lib/system/os/os_error.h b/include_lib/system/os/os_error.h new file mode 100644 index 0000000..f8e06b0 --- /dev/null +++ b/include_lib/system/os/os_error.h @@ -0,0 +1,79 @@ +#ifndef __OS_ERROR_H__ +#define __OS_ERROR_H__ + +#define OS_ERR_NONE 0 + + +enum { + OS_NO_ERR = 0, + OS_TRUE, + OS_ERR_EVENT_TYPE, + OS_ERR_PEND_ISR, + OS_ERR_POST_NULL_PTR, + OS_ERR_PEVENT_NULL, + OS_ERR_POST_ISR, + OS_ERR_QUERY_ISR, + OS_ERR_INVALID_OPT, + OS_ERR_TASK_WAITING, + OS_ERR_PDATA_NULL, + OS_TIMEOUT, + OS_TIMER, + OS_TASKQ, + OS_TASK_NOT_EXIST, + OS_ERR_EVENT_NAME_TOO_LONG, + OS_ERR_FLAG_NAME_TOO_LONG, + OS_ERR_TASK_NAME_TOO_LONG, + OS_ERR_PNAME_NULL, + OS_ERR_TASK_CREATE_ISR, + OS_MBOX_FULL, + OS_Q_FULL, + OS_Q_EMPTY, + OS_Q_ERR, + OS_ERR_NO_QBUF, + OS_PRIO_EXIST, + OS_PRIO_ERR, + OS_PRIO_INVALID, + OS_SEM_OVF, + OS_TASK_DEL_ERR, + OS_TASK_DEL_IDLE, + OS_TASK_DEL_ISR, + OS_NO_MORE_TCB, + OS_TIME_NOT_DLY, + OS_TIME_INVALID_MINUTES, + OS_TIME_INVALID_SECONDS, + OS_TIME_INVALID_MILLI, + OS_TIME_ZERO_DLY, + OS_TASK_SUSPEND_PRIO, + OS_TASK_SUSPEND_IDLE, + OS_TASK_RESUME_PRIO, + OS_TASK_NOT_SUSPENDED, + OS_MEM_INVALID_PART, + OS_MEM_INVALID_BLKS, + OS_MEM_INVALID_SIZE, + OS_MEM_NO_FREE_BLKS, + OS_MEM_FULL, + OS_MEM_INVALID_PBLK, + OS_MEM_INVALID_PMEM, + OS_MEM_INVALID_PDATA, + OS_MEM_INVALID_ADDR, + OS_MEM_NAME_TOO_LONG, + OS_ERR_MEM_NO_MEM, + OS_ERR_NOT_MUTEX_OWNER, + OS_TASK_OPT_ERR, + OS_ERR_DEL_ISR, + OS_ERR_CREATE_ISR, + OS_FLAG_INVALID_PGRP, + OS_FLAG_ERR_WAIT_TYPE, + OS_FLAG_ERR_NOT_RDY, + OS_FLAG_INVALID_OPT, + OS_FLAG_GRP_DEPLETED, + OS_ERR_PIP_LOWER, + OS_ERR_MSG_POOL_EMPTY, + OS_ERR_MSG_POOL_NULL_PTR, + OS_ERR_MSG_POOL_FULL, + +}; + + +#endif + diff --git a/include_lib/system/os/os_type.h b/include_lib/system/os/os_type.h new file mode 100644 index 0000000..4c69f71 --- /dev/null +++ b/include_lib/system/os/os_type.h @@ -0,0 +1,35 @@ +#ifndef __OS_TYPE_H +#define __OS_TYPE_H + + +#define OS_TICKS_PER_SEC 100 + +#if defined CONFIG_UCOS_ENABLE + +typedef struct { + unsigned char OSEventType; + int aa; + void *bb; + unsigned char value; + unsigned char prio; + unsigned short cc; +} OS_SEM, OS_MUTEX, OS_QUEUE; + +#include + +#elif defined CONFIG_FREE_RTOS_ENABLE + +#include "FreeRTOS/FreeRTOS.h" +#include "FreeRTOS/semphr.h" +#include "FreeRTOS/task.h" + +typedef StaticSemaphore_t OS_SEM, OS_MUTEX; +typedef StaticQueue_t OS_QUEUE; + + +#else +#error "no_os_defined" +#endif + + +#endif diff --git a/include_lib/system/os/ucos_ii.h b/include_lib/system/os/ucos_ii.h new file mode 100644 index 0000000..6480b9e --- /dev/null +++ b/include_lib/system/os/ucos_ii.h @@ -0,0 +1,806 @@ +/***********************************Jieli tech************************************************ + File : ucos_ii.h + By : Juntham + date : 2014-07-03 09:09 +********************************************************************************************/ + +#ifndef OS_uCOS_II_H +#define OS_uCOS_II_H + + +#include "generic/typedef.h" +#include "os/os_cpu.h" +#include "os/os_cfg.h" +#include "os/os_api.h" + +/* + ********************************************************************************************************* + * INCLUDE HEADER FILES + ********************************************************************************************************* + */ + +#ifdef __cplusplus +extern "C" +{ +#endif + + +// #define uCOS_ENTER_CRITICAL() CPU_CRITICAL_ENTER() +// #define uCOS_EXIT_CRITICAL() CPU_CRITICAL_EXIT() + +void uCOS_ENTER_CRITICAL(void); +void uCOS_EXIT_CRITICAL(void); + + +#define OS_VERSION 100u /* Version */ + +#define OS_STAT_RDY 0x00u /* Ready to run */ +#define OS_STAT_SEM 0x01u /* Pending on semaphore */ +#define OS_STAT_Q 0x02u /* Pending on queue */ +#define OS_STAT_SUSPEND 0x04u /* Task is suspended */ +#define OS_STAT_MUTEX 0x08u /* Pending on mutual exclusion semaphore */ +#define OS_STAT_TASK_Q 0x10u /* Pending on task Q */ +#define OS_STAT_DELAY 0x20u /* Task on delay */ +#define OS_STAT_FLAG 0x40u /* Pending on event flag group */ + +#define OS_STAT_PEND_ANY (OS_STAT_SEM | OS_STAT_Q | OS_STAT_MUTEX | OS_STAT_TASK_Q) + +/* + ********************************************************************************************************* + * OS_EVENT types + ********************************************************************************************************* +*/ +#define OS_EVENT_TYPE_UNUSED 0u +#define OS_EVENT_TYPE_Q 1u +#define OS_EVENT_TYPE_SEM 2u +#define OS_EVENT_TYPE_MUTEX 3u +#define OS_EVENT_TYPE_FLAG 5u + +/* +********************************************************************************************************* +* OS???PostOpt() OPTIONS +* +* These #defines are used to establish the options for OSMboxPostOpt() and OSQPostOpt(). +********************************************************************************************************* +*/ +#define OS_POST_OPT_NONE 0x00u /* NO option selected */ +#define OS_POST_OPT_BROADCAST 0x01u /* Broadcast message to ALL tasks waiting */ +#define OS_POST_OPT_FRONT 0x02u /* Post to highest priority task waiting */ + +/* + ********************************************************************************************************* + * MISCELLANEOUS + ********************************************************************************************************* + */ + +#ifdef OS_GLOBALS +#define OS_EXT +#else +#define OS_EXT extern +#endif +/* +********************************************************************************************************* +* EVENT CONTROL BLOCK +********************************************************************************************************* +*/ +#if OS_EVENT_EN +struct event_cnt { + u16 cnt; +}; +struct event_mutex { + u8 value; + u8 prio; + u16 OwnerNestingCtr; +}; + +struct os_tcb; + +typedef struct os_event { + u8 OSEventType; /* Type of event control block (see OS_EVENT_TYPE_xxxx) */ +#if OS_TIME_SLICE_EN > 0 + struct os_tcb *OSTCBList; /* TCB List */ +#else + OS_CPU_DATA OSTCBList; +#endif + void *OSEventPtr; /* Pointer to message or queue structure */ + union { + struct event_cnt OSEvent; + struct event_mutex OSMutex; + }; +} OS_EVENT; + + + +/* +********************************************************************************************************* +* EVENT FLAGS CONTROL BLOCK +********************************************************************************************************* +*/ + + +#if (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0) +/* +********************************************************************************************************* +* EVENT FLAGS +********************************************************************************************************* +*/ +#define OS_FLAG_WAIT_CLR_ALL 0u /* Wait for ALL the bits specified to be CLR (i.e. 0) */ +#define OS_FLAG_WAIT_CLR_AND 0u + +#define OS_FLAG_WAIT_CLR_ANY 1u /* Wait for ANY of the bits specified to be CLR (i.e. 0) */ +#define OS_FLAG_WAIT_CLR_OR 1u + +#define OS_FLAG_WAIT_SET_ALL 2u /* Wait for ALL the bits specified to be SET (i.e. 1) */ +#define OS_FLAG_WAIT_SET_AND 2u + +#define OS_FLAG_WAIT_SET_ANY 3u /* Wait for ANY of the bits specified to be SET (i.e. 1) */ +#define OS_FLAG_WAIT_SET_OR 3u + + +#define OS_FLAG_CONSUME 0x80u /* Consume the flags if condition(s) satisfied */ + + +#define OS_FLAG_CLR 0u +#define OS_FLAG_SET 1u + +#if OS_FLAGS_NBITS == 8 /* Determine the size of OS_FLAGS (8, 16 or 32 bits) */ +typedef INT8U OS_FLAGS; +#endif + +#if OS_FLAGS_NBITS == 16 +typedef INT16U OS_FLAGS; +#endif + +#if OS_FLAGS_NBITS == 32 +typedef u32 OS_FLAGS; +#endif + + + +typedef struct os_flag_grp { /* Event Flag Group */ + u8 OSFlagType; /* Should be set to OS_EVENT_TYPE_FLAG */ + void *OSFlagWaitList; /* Pointer to first NODE of task waiting on event flag */ + OS_FLAGS OSFlagFlags; /* 8, 16 or 32 bit flags */ +#if OS_FLAG_NAME_SIZE > 1 + u8 OSFlagName[OS_FLAG_NAME_SIZE]; +#endif +} OS_FLAG_GRP; + + + +typedef struct os_flag_node { /* Event Flag Wait List Node */ + void *OSFlagNodeNext; /* Pointer to next NODE in wait list */ + void *OSFlagNodePrev; /* Pointer to previous NODE in wait list */ + void *OSFlagNodeTCB; /* Pointer to TCB of waiting task */ + void *OSFlagNodeFlagGrp; /* Pointer to Event Flag Group */ + OS_FLAGS OSFlagNodeFlags; /* Event flag to wait on */ + u8 OSFlagNodeWaitType; /* Type of wait: */ + /* OS_FLAG_WAIT_AND */ + /* OS_FLAG_WAIT_ALL */ + /* OS_FLAG_WAIT_OR */ + /* OS_FLAG_WAIT_ANY */ +} OS_FLAG_NODE; + +OS_EXT OS_FLAG_GRP OSFlagTbl[OS_MAX_FLAGS]; /* Table containing event flag groups */ +OS_EXT OS_FLAG_GRP *OSFlagFreeList; /* Pointer to free list of event flag groups */ + +OS_FLAG_GRP *OSFlagCreate(OS_FLAGS flags, u8 *err); +OS_FLAG_GRP *OSFlagDel(OS_FLAG_GRP *pgrp, u8 opt, u8 *err); +OS_FLAGS OSFlagPend(OS_FLAG_GRP *pgrp, OS_FLAGS flags, u8 wait_type, u16 timeout, u8 *err); +OS_FLAGS OSFlagPost(OS_FLAG_GRP *pgrp, OS_FLAGS flags, u8 opt, u8 *err); +#endif + +/*$PAGE*/ + +/* + ********************************************************************************************************* + * MESSAGE QUEUE DATA + ********************************************************************************************************* + */ + +#if (OS_Q_EN > 0) || (OS_TASKQ_EN > 0) +typedef struct os_q { /* QUEUE CONTROL BLOCK */ + QS OSQIn; + QS OSQOut; + QS OSQSize; /* Size of queue (maximum number of entries) */ + QS OSQEntries; /* Current number of entries in the queue */ + void **OSQStart; /* Pointer to start of queue data */ +} OS_Q; +#endif + +/*$PAGE*/ + +/* + ********************************************************************************************************* + * TASK CONTROL BLOCK + ********************************************************************************************************* +*/ +typedef struct os_tcb { + OS_STK *OSTCBStkPtr; /* Pointer to current top of stack */ + +#if OS_CPU_MMU > 0 + u8 *frame; +#endif + +#if OS_TIME_SLICE_EN > 0 + u8 slice_quanta; /* 时间片初始值 */ + u8 slice_cnt; /* 时间片模式下的计数值 */ + u16 OSTCBDly; /* Nbr ticks to delay task or, timeout waiting for event */ +#endif + +#if OS_TASKQ_EN > 0 + OS_Q task_q; +#endif + +#if OS_PARENT_TCB > 0 + struct os_tcb *OSTCBParent; +#endif + +#if OS_CHILD_TCB > 0 + struct os_tcb *OSTCBChildNext; +#endif + +#if OS_TIME_SLICE_EN > 0 + struct os_tcb *OSTCBEventNext; /* Pointer to next TCB in the event waiting TCB list */ + struct os_tcb *OSTCBEventPrev; /* Pointer to previous TCB in the event waiting TCB list */ + struct os_tcb *OSTCBSliceNext; /* Pointer to next TCB in the time slice TCB list */ + struct os_tcb *OSTCBSlicePrev; /* Pointer to previous TCB in the time slice TCB list */ +#endif + +#if OS_EVENT_EN + OS_EVENT *OSTCBEventPtr; /* Pointer to event control block */ +#endif + +#if (OS_Q_EN > 0) || (OS_TASKQ_EN > 0) + void *OSTCBMsg; /* Message received from OSMboxPost() or OSQPost() */ +#endif + +#if OS_FLAG_EN > 0 + OS_FLAG_NODE *OSTCBFlagNode; /* Pointer to event flag node */ + OS_FLAGS OSTCBFlagsRdy; +#endif + +#if OS_TIME_SLICE_EN == 0 + u16 OSTCBDly; /* Nbr ticks to delay task or, timeout waiting for event */ +#endif + u8 OSTCBPrio; /* Task priority (0 == highest) */ + u8 OSTCBStat; /* Task status */ + u8 OSTCBPendTO; /* Flag indicating PEND timed out (TRUE == timed out) */ + + +#if OS_TASK_DEL_EN > 0 + u8 OSTCBDelReq; /* Indicates whether a task needs to delete itself */ +#endif + + u8 OSCoreAffinity; /* core */ + + u8 fork_thread; + OS_STK *OSTCBStkTos; + int *pid; + OS_STK stk_size; + OS_STK *p_stk_base; + char *name; + u32 timeout; + u32 RunTimeCounterStart; + u32 RunTimeCounterTotal; +} OS_TCB; + + +typedef struct os_tcb_list { + OS_TCB *ptcb; +#if OS_TIME_SLICE_EN > 0 + OS_TCB *idle_ptcb; +#endif +} OS_TCB_LIST; + +/* + ********************************************************************************************************* + * MUTUAL EXCLUSION SEMAPHORE MANAGEMENT + ********************************************************************************************************* + */ + +#if OS_MUTEX_EN > 0 + +#if OS_MUTEX_ACCEPT_EN > 0 +u8 OSMutexAccept(OS_EVENT *pevent); +#endif + +u8 OSMutexCreate(OS_EVENT *pevent); + +#if OS_MUTEX_DEL_EN > 0 +u8 OSMutexDel(OS_EVENT *pevent, u8 opt); +#endif + +u8 OSMutexPend(OS_EVENT *pevent, u16 timeout); +u8 OSMutexPost(OS_EVENT *pevent); + +#if OS_MUTEX_QUERY_EN > 0 +u8 OSMutexQuery(OS_EVENT *pevent, OS_MUTEX_DATA *p_mutex_data); +#endif + +#endif +/* + ********************************************************************************************************* + * MESSAGE QUEUE MANAGEMENT + ********************************************************************************************************* + */ + +#if (OS_Q_EN > 0) + +#if OS_Q_ACCEPT_EN > 0 +u8 OSQAccept(OS_EVENT *pevent, void *msg); +#endif + +u8 OSQCreate(OS_EVENT *pevent, /*void **start, */QS size); + +#if OS_Q_DEL_EN > 0 +u8 OSQDel(OS_EVENT *pevent, u8 opt); +#endif + +#if OS_Q_FLUSH_EN > 0 +u8 OSQFlush(OS_EVENT *pevent); +#endif + +u8 OSQPend(OS_EVENT *pevent, u16 timeout, void *msg); + +#if OS_Q_POST_EN > 0 +u8 OSQPost(OS_EVENT *pevent, void *msg); +#endif + +#if OS_Q_POST_FRONT_EN > 0 +u8 OSQPostFront(OS_EVENT *pevent, void *msg); +#endif + +#if OS_Q_POST_OPT_EN > 0 +u8 OSQPostOpt(OS_EVENT *pevent, void *msg, u8 opt); +#endif + +#if OS_Q_QUERY_EN > 0 +u16 OSQQuery(OS_EVENT *pevent); +#endif + +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* SEMAPHORE MANAGEMENT +********************************************************************************************************* +*/ +#if OS_SEM_EN > 0 + +#if OS_SEM_ACCEPT_EN > 0 +u16 OSSemAccept(OS_EVENT *pevent); +#endif + +u8 OSSemCreate(OS_EVENT *pevent, u16 cnt); + +#if OS_SEM_DEL_EN > 0 +u8 OSSemDel(OS_EVENT *pevent, u8 opt); +#endif + +u8 OSSemPend(OS_EVENT *pevent, u16 timeout); +u8 OSSemPost(OS_EVENT *pevent); + +#if OS_SEM_QUERY_EN > 0 +u16 OSSemQuery(OS_EVENT *pevent); +#endif + +#if OS_SEM_SET_EN > 0 +u8 OSSemSet(OS_EVENT *pevent, u16 cnt); +#endif + +#endif + +/*$PAGE*/ +/* + ********************************************************************************************************* + * TASK MANAGEMENT + ********************************************************************************************************* + */ +#if OS_TASK_CHANGE_PRIO_EN > 0 +u8 OSTaskChangePrio(char *name, u8 newprio); +#endif + +#if OS_TASK_CREATE_EN > 0 +u8 OSTaskCreate(void (*task)(void *p_arg), OS_TCB *task_tcb, void *p_arg +#if OS_CPU_MMU == 0 + , OS_STK *ptos +#endif + , u8 prio +#if OS_TASKQ_EN > 0 + , void **start, QS qsize +#endif +#if OS_TIME_SLICE_EN > 0 + , u8 time_quanta +#endif + , s8 *name + ); +#endif + +u8 OSTaskQAccept(int argc, int *argv); + +u8 OSTaskQPend(u16 timeout, int argc, int *argv); + +u8 OSTaskQPost(const char *name, int argc, ...); + +u8 OSTaskQFlush(const char *name); + +u8 OSTaskQPostFront(const char *name, int argc, ...); + +u8 OSTaskQQuery(const char *name, u8 *task_q_entries); + +#if OS_TASK_DEL_EN > 0 +u8 OSTaskDel(const char *name); +u8 OSTaskDelReq(const char *name); +void OSTaskDelRes(const char *name); +#endif + + +#if OS_TASK_SUSPEND_EN > 0 +u8 OSTaskResume(const char *name); +u8 OSTaskSuspend(const char *name); +#endif + +#if OS_TASK_QUERY_EN > 0 +u8 OSTaskQuery(const char *name, OS_TCB *p_task_data); +#endif + + +/*$PAGE*/ +/* + ********************************************************************************************************* + * TIME MANAGEMENT + ********************************************************************************************************* + */ + +void OSTimeDly(u16 ticks); + + +#if OS_TIME_GET_SET_EN > 0 +u32 OSTimeGet(void); +void OSTimeSet(u32 ticks); + +#endif + +void OSTimeTick(void); + +/* + ********************************************************************************************************* + * MISCELLANEOUS + ********************************************************************************************************* + */ + +void OSInit(void); + +void OSStart(); + +u16 OSVersion(void); +#endif +/* + ********************************************************************************************************* + * GLOBAL VARIABLES + ********************************************************************************************************* +*/ + +OS_EXT volatile u8 OSRunning; /* Flag indicating that kernel is running */ +OS_EXT volatile OS_CPU_DATA OSRdyTbl; +OS_EXT volatile u32 OSIdleCtr; /* Idle counter */ +OS_EXT OS_TCB *OSTCBCur[OS_CPU_CORE]; /* Pointer to currently running TCB */ +OS_EXT OS_TCB *OSTCBHighRdy[OS_CPU_CORE]; /* Pointer to highest priority TCB R-to-R */ +OS_EXT OS_TCB_LIST OSTCBPrioTbl[OS_MAX_TASKS + 1]; /* Table of pointers to created TCBs */ + + +#if (OS_INT_NESTING == 1) +OS_EXT u8 OSIntNesting; +#elif (OS_INT_NESTING == 2) +extern int is_cpu_int_nesting(); +#define OSIntNesting is_cpu_int_nesting() +#endif + +#if OS_TIME_GET_SET_EN > 0 +OS_EXT volatile u32 OSTime; /* Current value of system time (in ticks) */ +#endif + + +/* + ********************************************************************************************************* + * MISCELLANEOUS + ********************************************************************************************************* + */ + +/* void OSInit(void); */ + +void OSIntEnter(void); +void OSIntExit(void); + +#if OS_SCHED_LOCK_EN > 0 +void OSSchedLock(void); +void OSSchedUnlock(void); +#endif + +u32 OS_HighPrio(OS_CPU_DATA table); + +void OS_SchedRoundRobin(OS_TCB *ptcb); + +void OS_InsertRdyListHead(OS_TCB *ptcb); + +void OS_InsertRdyListTail(OS_TCB *ptcb); + +void OS_InsertIdleList(OS_TCB *ptcb); + +void OS_RemoveRdyList(OS_TCB *ptcb); + +void OS_RemoveIdleList(OS_TCB *ptcb); + +void OS_InsertListHead(OS_TCB *ptcb); + +void OS_RemoveList(OS_TCB *ptcb); + +/* void OSStart(); */ + +void OSStatInit(void); + +/* u16 OSVersion(void); */ + +/*$PAGE*/ + +/* + ********************************************************************************************************* + * INTERNAL FUNCTION PROTOTYPES + * (Your application MUST NOT call these functions) + ********************************************************************************************************* + */ + +#if OS_TASK_DEL_EN > 0 +void OS_Dummy(void); +#endif + +#if OS_EVENT_EN +void OS_ExchangePrio(OS_TCB *ptcba, OS_TCB *ptcbb); + +#if OS_TIME_SLICE_EN > 0 +OS_TCB *OS_EventHighestTask(OS_TCB *ptcb, u8 prio); +void OS_EventTaskRdy(OS_EVENT *pevent, OS_TCB *ptcb, void *msg, u8 msk); +#else +OS_TCB *OS_EventTaskRdy(OS_EVENT *pevent, void *msg, u8 msk); +#endif + +void OS_EventTaskWait(OS_EVENT *pevent, OS_TCB *OSTCB); +void OS_EventTO(OS_EVENT *pevent, OS_TCB *OSTCB); +void OS_EventWaitListInit(OS_EVENT *pevent); +#endif + +void OS_MemClr(u8 *pdest, u16 size); +void OS_MemCopy(u8 *pdest, u8 *psrc, u16 size); + +#if OS_Q_EN > 0 +void OS_QInit(void); +#endif + +int OS_Sched(void); + +void OS_TaskIdle(void *p_arg); + +void OSIdleOtherCore(void); + +void OSResumOtherCore(void); + +void OS_CoreAffinitySet(const char *name, u8 Core); + +/*$PAGE*/ + +/* + ********************************************************************************************************* + * FUNCTION PROTOTYPES + * (Target Specific Functions) + ********************************************************************************************************* + */ + +#if OS_VERSION >= 204 +void OSInitHookBegin(void); +void OSInitHookEnd(void); +#endif + +#ifndef OS_ISR_PROTO_EXT +void OSIntCtxSw(void); +void OSStartHighRdy(void); +#endif + +void OSTaskCreateHook(OS_TCB *ptcb); +void OSTaskDelHook(OS_TCB *ptcb); + +#if OS_VERSION >= 251 +void OSTaskIdleHook(void); +#endif + +void OSTaskStatHook(void); +OS_STK *OSTaskStkInit(void(*p_task)(void *pd), void *p_arg, OS_STK *p_stk_base, u16 opt); + +#if OS_TASK_SW_HOOK_EN > 0 +void OSTaskSwHook(void); +#endif + +#if OS_VERSION >= 204 +void OSTCBInitHook(OS_TCB *ptcb); +#endif + +#if OS_TIME_TICK_HOOK_EN > 0 +void OSTimeTickHook(void); +#endif +extern void OS_TASK_DEL_HOOK(OS_TCB *ptcb) ; +/*$PAGE*/ +/* + ********************************************************************************************************* + * LOOK FOR MISSING #define CONSTANTS + * + * This section is used to generate ERROR messages at compile time if certain #define constants are + * MISSING in OS_CFG.H. This allows you to quickly determine the source of the error. + * + * You SHOULD NOT change this section UNLESS you would like to add more comments as to the source of the + * compile time error. + ********************************************************************************************************* + */ + + +/* + ********************************************************************************************************* + * MUTUAL EXCLUSION SEMAPHORES + ********************************************************************************************************* + */ + +#ifndef OS_MUTEX_EN +#error "OS_CFG.H, Missing OS_MUTEX_EN: Enable (1) or Disable (0) code generation for MUTEX" +#else +#ifndef OS_MUTEX_ACCEPT_EN +#error "OS_CFG.H, Missing OS_MUTEX_ACCEPT_EN: Include code for OSMutexAccept()" +#endif + +#ifndef OS_MUTEX_DEL_EN +#error "OS_CFG.H, Missing OS_MUTEX_DEL_EN: Include code for OSMutexDel()" +#endif + +#ifndef OS_MUTEX_QUERY_EN +#error "OS_CFG.H, Missing OS_MUTEX_QUERY_EN: Include code for OSMutexQuery()" +#endif +#endif + +/* + ********************************************************************************************************* + * SEMAPHORES + ********************************************************************************************************* + */ + +#ifndef OS_SEM_EN +#error "OS_CFG.H, Missing OS_SEM_EN: Enable (1) or Disable (0) code generation for SEMAPHORES" +#else +#ifndef OS_SEM_ACCEPT_EN +#error "OS_CFG.H, Missing OS_SEM_ACCEPT_EN: Include code for OSSemAccept()" +#endif + +#ifndef OS_SEM_DEL_EN +#error "OS_CFG.H, Missing OS_SEM_DEL_EN: Include code for OSSemDel()" +#endif + +#ifndef OS_SEM_QUERY_EN +#error "OS_CFG.H, Missing OS_SEM_QUERY_EN: Include code for OSSemQuery()" +#endif + +#ifndef OS_SEM_SET_EN +#error "OS_CFG.H, Missing OS_SEM_SET_EN: Include code for OSSemSet()" +#endif +#endif + +/* + ********************************************************************************************************* + * TASK MANAGEMENT + ********************************************************************************************************* + */ + +#ifndef OS_MAX_TASKS +#error "OS_CFG.H, Missing OS_MAX_TASKS: Max. number of tasks in your application" +#else +#if OS_MAX_TASKS < 2 +#error "OS_CFG.H, OS_MAX_TASKS must be >= 2" +#endif + +/* #if OS_MAX_TASKS > (OS_LOWEST_PRIO - OS_N_SYS_TASKS + 1) */ +/* #error "OS_CFG.H, OS_MAX_TASKS must be <= OS_LOWEST_PRIO - OS_N_SYS_TASKS + 1" */ +/* #endif */ + +#endif + +#if OS_VERSION < 280 +#if OS_LOWEST_PRIO > 63 +#error "OS_CFG.H, OS_LOWEST_PRIO must be <= 63 in V2.7x or lower" +#endif +#endif + +#if OS_VERSION >= 280 +#if OS_LOWEST_PRIO > 254 +#error "OS_CFG.H, OS_LOWEST_PRIO must be <= 254 in V2.8x and higher" +#endif +#endif + +#ifndef OS_TASK_CHANGE_PRIO_EN +#error "OS_CFG.H, Missing OS_TASK_CHANGE_PRIO_EN: Include code for OSTaskChangePrio()" +#endif + +#ifndef OS_TASK_CREATE_EN +#error "OS_CFG.H, Missing OS_TASK_CREATE_EN: Include code for OSTaskCreate()" +#endif + +#ifndef OS_TASK_DEL_EN +#error "OS_CFG.H, Missing OS_TASK_DEL_EN: Include code for OSTaskDel()" +#endif + +#ifndef OS_TASK_SUSPEND_EN +#error "OS_CFG.H, Missing OS_TASK_SUSPEND_EN: Include code for OSTaskSuspend() and OSTaskResume()" +#endif + +#ifndef OS_TASK_QUERY_EN +#error "OS_CFG.H, Missing OS_TASK_QUERY_EN: Include code for OSTaskQuery()" +#endif + +/* + ********************************************************************************************************* + * TIME MANAGEMENT + ********************************************************************************************************* + */ + +#ifndef OS_TICKS_PER_SEC +#error "OS_CFG.H, Missing OS_TICKS_PER_SEC: Sets the number of ticks in one second" +#endif + +#ifndef OS_TIME_DLY_HMSM_EN +#error "OS_CFG.H, Missing OS_TIME_DLY_HMSM_EN: Include code for OSTimeDlyHMSM()" +#endif + +#ifndef OS_TIME_DLY_RESUME_EN +#error "OS_CFG.H, Missing OS_TIME_DLY_RESUME_EN: Include code for OSTimeDlyResume()" +#endif + +#ifndef OS_TIME_GET_SET_EN +#error "OS_CFG.H, Missing OS_TIME_GET_SET_EN: Include code for OSTimeGet() and OSTimeSet()" +#endif + +/* + ********************************************************************************************************* + * MISCELLANEOUS + ********************************************************************************************************* + */ + +#ifndef OS_ARG_CHK_EN +#error "OS_CFG.H, Missing OS_ARG_CHK_EN: Enable (1) or Disable (0) argument checking" +#endif + + +#ifndef OS_CPU_HOOKS_EN +#error "OS_CFG.H, Missing OS_CPU_HOOKS_EN: uC/OS-II hooks are found in the processor port files when 1" +#endif + + +#ifndef OS_LOWEST_PRIO +#error "OS_CFG.H, Missing OS_LOWEST_PRIO: Defines the lowest priority that can be assigned" +#endif + + +#ifndef OS_SCHED_LOCK_EN +#error "OS_CFG.H, Missing OS_SCHED_LOCK_EN: Include code for OSSchedLock() and OSSchedUnlock()" +#endif + + + +#ifndef OS_TASK_SW_HOOK_EN +#error "OS_CFG.H, Missing OS_TASK_SW_HOOK_EN: Allows you to include the code for OSTaskSwHook() or not" +#endif + + +#ifndef OS_TIME_TICK_HOOK_EN +#error "OS_CFG.H, Missing OS_TIME_TICK_HOOK_EN: Allows you to include the code for OSTimeTickHook() or not" +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include_lib/system/port/br28/system_lib.ld b/include_lib/system/port/br28/system_lib.ld new file mode 100644 index 0000000..82aaa35 --- /dev/null +++ b/include_lib/system/port/br28/system_lib.ld @@ -0,0 +1,294 @@ +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.code*) */ + __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 +} + diff --git a/include_lib/system/power_manage.h b/include_lib/system/power_manage.h new file mode 100644 index 0000000..f937eec --- /dev/null +++ b/include_lib/system/power_manage.h @@ -0,0 +1,103 @@ +#ifndef __POWER_MANAGE_H_ +#define __POWER_MANAGE_H_ + +#include "generic/typedef.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + DEVICE_EVENT_POWER_SHUTDOWN = 0x10, + DEVICE_EVENT_POWER_STARTUP, + DEVICE_EVENT_POWER_PERCENT, + DEVICE_EVENT_POWER_CHARGER_IN, + DEVICE_EVENT_POWER_CHARGER_OUT +}; + +#define PWR_SCAN_TIMES 3 + +#define PWR_DELAY_INFINITE 0xffffffff + +#define PWR_WKUP_PORT "wkup_port" +#define PWR_WKUP_ALARM "wkup_alarm" +#define PWR_WKUP_PWR_ON "wkup_pwr_on" +#define PWR_WKUP_ABNORMAL "wkup_abnormal" +#define PWR_WKUP_SHORT_KEY "wkup_short_key" + +struct sys_power_hal_ops { + void (*init)(void); + void (*poweroff)(void *arg); + int (*wakeup_check)(char *reason, int max_len); + int (*port_wakeup_config)(const char *port, int enable); + int (*alarm_wakeup_config)(u32 sec, int enable); + int (*get_battery_voltage)(void); + int (*get_battery_percent)(void); + int (*charger_online)(void); +}; + +extern const struct sys_power_hal_ops sys_power_hal_ops_begin[]; +extern const struct sys_power_hal_ops sys_power_hal_ops_end[]; + +#define REGISTER_SYS_POWER_HAL_OPS(ops) \ + static const struct sys_power_hal_ops ops sec(.sys_power_hal_ops) + + +void sys_power_early_init(); +/* + * @brief 断电关机,不释放资源 + */ +void sys_power_poweroff(void *arg); +/* + * @brief 软关机,触发DEVICE_EVENT_POWER_SHUTDOWN事件,app捕获事件释放资源再调用sys_power_poweroff() + */ +void sys_power_shutdown(); + +int sys_power_set_port_wakeup(const char *port, int enable); + +int sys_power_set_alarm_wakeup(u32 sec, int enable); + +const char *sys_power_get_wakeup_reason(); + +void sys_power_clr_wakeup_reason(const char *str); + +int sys_power_get_battery_voltage(); + +int sys_power_get_battery_persent(); + +int sys_power_is_charging(); + +int sys_power_charger_online(void); +/* + * @brief 倒计时自动关机 + * @parm dly_secs 延时关机时间,赋值0为永不关机 + * @return none + */ +void sys_power_auto_shutdown_start(u32 dly_secs); +void sys_power_auto_shutdown_pause(); +void sys_power_auto_shutdown_resume(); +void sys_power_auto_shutdown_clear(); +void sys_power_auto_shutdown_stop(); + + +int sys_power_low_voltage(u32 voltage); + +/* + * @brief 低电延时关机 + * @parm p_low_percent 低电电量百分比 + * @parm dly_secs 延时关机时间,赋值0为立即关机,赋值PWR_DELAY_INFINITE为永不关机 + * @return none + */ +void sys_power_low_voltage_shutdown(u32 voltage, u32 dly_secs); +/* + * @brief 插拔延时关机 + * @parm dly_secs 延时关机时间,赋值0为立即关机,赋值PWR_DELAY_INFINITE为永不关机 + * @return none + */ +void sys_power_charger_off_shutdown(u32 dly_secs); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include_lib/system/server/server_core.h b/include_lib/system/server/server_core.h new file mode 100644 index 0000000..dada5f4 --- /dev/null +++ b/include_lib/system/server/server_core.h @@ -0,0 +1,85 @@ +#ifndef SERVER_H +#define SERVER_H + +#include "generic/typedef.h" +#include "system/task.h" +#include "spinlock.h" +#include "list.h" + + +#define REQ_COMPLETE_CALLBACK 0x01000000 +#define REQ_WAIT_COMPLETE 0x02000000 +#define REQ_HI_PRIORITY 0x04000000 + + +#define REQ_TYPE_MASK 0x00ffffff + + +struct server_req { + int type; + int err; + void *server_priv; + struct list_head entry; + struct server *server; + void *user; + const char *owner; + OS_SEM sem; + union { + int state; + void (*func)(void *, void *, int); + } complete; + u32 arg[0]; +}; + + +struct server_info { + const char *name; + u16 reqlen; + u8 reqnum; + void *(*open)(void *, void *); + void (*close)(void *); +}; + +#define REQ_BUF_LEN 512 + +struct server { + bool avaliable; + void *server; + OS_SEM sem; + OS_MUTEX mutex; + spinlock_t lock; + struct list_head *req_buf; + struct list_head free; + struct list_head pending; + const struct server_info *info; + const char *owner; + void *handler_priv; + void (*event_handler)(void *, int argc, int *argv); +}; + + + +#define SERVER_REGISTER(info) \ + const struct server_info info sec(.server_info) + + +#define server_load(server) \ + load_module(server) + +struct server *server_open(const char *name, void *arg); + +void server_register_event_handler(struct server *server, void *priv, + void (*handler)(void *, int argc, int *argv)); + +void server_close(struct server *server); + +int server_request(struct server *server, int req_type, void *arg); + +int server_request_async(struct server *server, int req_type, void *arg, ...); + +int server_req_complete(struct server_req *req); + +int server_event_handler(void *_server, int argc, int *argv); + +#endif + diff --git a/include_lib/system/spi/nor_fs.h b/include_lib/system/spi/nor_fs.h new file mode 100644 index 0000000..c245574 --- /dev/null +++ b/include_lib/system/spi/nor_fs.h @@ -0,0 +1,101 @@ +/***********************************Jieli tech************************************************ + File : nor_fs.h + By : Huxi + Email: xi_hu@zh-jieli.com + date : 2016-11-30 14:30 +********************************************************************************************/ +#ifndef _NOR_FS_H_ +#define _NOR_FS_H_ + +// #include "sdk_cfg.h" +#include "typedef.h" +// #include "system/includes.h" + +// #define SPI_REC_EN 1 + +#define NORFS_DATA_LEN 16 + +#define REC_FILE_END 0xFE + + +//文件索引 +typedef struct __RECF_INDEX_INFO { + u16 index; //文件索引号 + u16 sector; //文件所在扇区 +} RECF_INDEX_INFO ; + +#define FLASH_PAGE_SIZE 256 +//文件系统句柄 +typedef struct __RECFILESYSTEM { + RECF_INDEX_INFO index; + u8 buf[FLASH_PAGE_SIZE]; + u16 total_file; + u16 first_sector; + u16 last_sector; + // u8 *buf; + u8 sector_size; + void (*eraser)(u32 address); + s32(*read)(u8 *buf, u32 addr, u32 len); + s32(*write)(u8 *buf, u32 addr, u32 len); +} RECFILESYSTEM, *PRECFILESYSTEM ; + + + +//文件句柄 +typedef struct __REC_FILE { + RECF_INDEX_INFO index; + RECFILESYSTEM *pfs; + u32 addr; + char priv_data[NORFS_DATA_LEN]; + u32 len; + u32 w_len; + u32 rw_p; + u16 sr; +} REC_FILE; + +enum { + NOR_FS_SEEK_SET = 0, + NOR_FS_SEEK_CUR = 0x01 +}; +// enum { +// NOR_FS_SEEK_SET = 0x01, +// NOR_FS_SEEK_CUR = 0x02 +// }; + + +typedef struct __nor_fs_hdl { + u16 index; + RECFILESYSTEM *recfs; + REC_FILE *recfile; +} NOR_FS_HDL; + + +u8 recf_seek(REC_FILE *pfile, u8 type, int offsize); +u16 recf_read(REC_FILE *pfile, u8 *buff, u16 btr); +u16 recf_write(REC_FILE *pfile, u8 *buff, u16 btw); +u32 create_recfile(RECFILESYSTEM *pfs, REC_FILE *pfile); +u32 close_recfile(REC_FILE *pfile); +u32 open_recfile(u32 index, RECFILESYSTEM *pfs, REC_FILE *pfile); +void recf_save_sr(REC_FILE *pfile, u16 sr); + +int music_flash_file_set_index(u8 file_sel, u32 index); +u32 recfs_scan(RECFILESYSTEM *pfs); +void init_nor_fs(RECFILESYSTEM *pfs, u16 sector_start, u16 sector_end, u8 sector_size); + +u32 nor_fs_init(void); +int nor_fs_set_rec_capacity(int capacity); //需要先设置容量。 +int nor_fs_ops_init(void); +int recfs_scan_ex(); +u32 nor_get_capacity(void); +u32 flashinsize_rec_get_capacity(void); +int sdfile_rec_scan_ex(); +void rec_clear_norfs_fileindex(void); +void clear_norfs_fileindex(void); +u32 _sdfile_rec_init(void); +int set_rec_capacity(int capacity); //需要先设置容量。 +int sdfile_rec_ops_init(void); +u32 nor_get_index(void); +u32 flashinsize_rec_get_index(void); +int nor_set_offset_addr(int offset); + +#endif diff --git a/include_lib/system/spinlock.h b/include_lib/system/spinlock.h new file mode 100644 index 0000000..fa676f3 --- /dev/null +++ b/include_lib/system/spinlock.h @@ -0,0 +1,145 @@ +#ifndef SYS_SPINLOCK_H +#define SYS_SPINLOCK_H + +#include "typedef.h" +#include "cpu.h" +#include "irq.h" + + +struct __spinlock { + volatile u32 rwlock; +}; + +typedef struct __spinlock spinlock_t; + +#if CPU_CORE_NUM > 1 + +#define preempt_disable() \ + __local_irq_disable() + +#define preempt_enable() \ + __local_irq_enable() + +#else + +#define preempt_disable() \ + local_irq_disable() + +#define preempt_enable() \ + local_irq_enable() + + + + +#endif + + +#if CPU_CORE_NUM > 1 + +#define spin_acquire(lock) \ + do { \ + arch_spin_lock(lock); \ + }while(0) + +#define spin_release(lock) \ + do { \ + arch_spin_unlock(lock); \ + }while(0) + +#else + +#define spin_acquire(lock) \ + do { \ + }while(0) + + +#define spin_release(lock) \ + do { \ + }while(0) + +#endif + + +#define DEFINE_SPINLOCK(x) \ + spinlock_t x = { .rwlock = 0 } + + +static inline void spin_lock_init(spinlock_t *lock) +{ + lock->rwlock = 0; +} +extern u32 spin_lock_cnt[]; + +#if 1 +static inline void spin_lock(spinlock_t *lock) +{ + preempt_disable(); + /*ASSERT(spin_lock_cnt[current_cpu_id()] == 0); + spin_lock_cnt[current_cpu_id()] = 1;*/ + spin_acquire(lock); +} + + +static inline void spin_unlock(spinlock_t *lock) +{ + /*spin_lock_cnt[current_cpu_id()] = 0;*/ + spin_release(lock); + preempt_enable(); +} + +#else + + +#define spin_lock(lock) \ + do { \ + preempt_disable(); \ + if (!(T2_CON & (1<<0))) { \ + T2_CNT = 0; \ + T2_PRD = 120000000 / 10; \ + T2_CON = 1; \ + } \ + spin_lock_cnt[current_cpu_id()] = T2_CNT; \ + spin_acquire(lock); \ + } while (0) + + +#define spin_unlock(lock) \ + do { \ + u32 t = T2_CNT;\ + if(t < spin_lock_cnt[current_cpu_id()]) \ + t += T2_PRD - spin_lock_cnt[current_cpu_id()]; \ + else \ + t -= spin_lock_cnt[current_cpu_id()]; \ + spin_release(lock); \ + preempt_enable(); \ + if (t > 100000) { /*120000 == 1ms*/ \ + printf("???????spinlock: %d, %s\n", t, __func__); \ + } \ + } while(0) + +#endif + +/*#define spin_lock_irqsave(lock, flags) \ + do { \ + local_irq_save(flags); \ + spin_acquire((lock)); \ + }while(0) + +#define spin_unlock_irqrestore(lock, flags) \ + do { \ + spin_release((lock)); \ + local_irq_restore(flags); \ + }while(0) */ + + + + + + + + + + + +#endif + diff --git a/include_lib/system/sys_time.h b/include_lib/system/sys_time.h new file mode 100644 index 0000000..02db2b5 --- /dev/null +++ b/include_lib/system/sys_time.h @@ -0,0 +1,50 @@ +#ifndef SYS_TIME_H +#define SYS_TIME_H + +#include "typedef.h" + + +struct sys_time { + u16 year; + u8 month; + u8 day; + u8 hour; + u8 min; + u8 sec; +}; + +#if 0 +struct tm { + int tm_sec; /* Seconds. [0-60] (1 leap second) */ + int tm_min; /* Minutes. [0-59] */ + int tm_hour; /* Hours. [0-23] */ + int tm_mday; /* Day. [1-31] */ + int tm_mon; /* Month. [0-11] */ + int tm_year; /* Year - 1900. */ + int tm_wday; /* Day of week. [0-6] */ + int tm_yday; /* Days in year.[0-365] */ + int tm_isdst; /* DST. [-1/0/1]*/ + +# ifdef __USE_MISC + long int tm_gmtoff; /* Seconds east of UTC. */ + const char *tm_zone; /* Timezone abbreviation. */ +# else + long int __tm_gmtoff; /* Seconds east of UTC. */ + const char *__tm_zone; /* Timezone abbreviation. */ +# endif +}; + +#endif + + + + + + + + + + + + +#endif diff --git a/include_lib/system/syscfg_id.h b/include_lib/system/syscfg_id.h new file mode 100644 index 0000000..5fba4f4 --- /dev/null +++ b/include_lib/system/syscfg_id.h @@ -0,0 +1,333 @@ + +#ifndef __JL_CFG_DEC_H__ +#define __JL_CFG_DEC_H__ + +#include "typedef.h" + +struct btif_item { + u16 id; + u16 data_len; +}; + + +struct syscfg_operataions { + int (*init)(void); + int (*check_id)(u16 item_id); + int (*read)(u16 item_id, u8 *buf, u16 len); + int (*write)(u16 item_id, u8 *buf, u16 len); + int (*dma_write)(u16 item_id, u8 *buf, u16 len); + int (*read_string)(u16 item_id, u8 *buf, u16 len, u8 ver); + u8 *(*ptr_read)(u16 item_id, u16 *len); +}; + +#define REGISTER_SYSCFG_OPS(cfg, pri) \ + const struct syscfg_operataions cfg SEC_USED(.syscfg.pri.ops) + +//=================================================================================// +// 系统配置项(VM, BTIF, cfg_bin)读写接口 // +//接口说明: // +// 1.输入参数 // +// 1)item_id: 配置项ID号, 由本文件统一分配; // +// 2)buf: 用于存储read/write数据内容; // +// 3)len: buf的长度(byte), buf长度必须大于等于read/write数据长度; // +// 2.返回参数: // +// 1)执行正确: 返回值等于实际上所读到的数据长度(大于0); // +// 2)执行错误: 返回值小于等于0, 小于0表示相关错误码; // +// 3.读写接口使用注意事项: // +// 1)不能在中断里调用写(write)接口; // +// 2)调用本读写接口时应该习惯性判断返回值来检查read/write动作是否执行正确; // +//=================================================================================// + +/* --------------------------------------------------------------------------*/ +/** + * @brief 读取对应配置项的内容 + * + * @param [in] item_id 配置项ID号 + * @param [out] buf 用于存储read数据内容 + * @param [in] len buf的长度(byte), buf长度必须大于等于read数据长度 + * + * @return 1)执行正确: 返回值等于实际上所读到的数据长度(大于0); + * 2)执行错误: 返回值小于等于0, 小于0表示相关错误码; + */ +/* --------------------------------------------------------------------------*/ +int syscfg_read(u16 item_id, void *buf, u16 len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 读取cfg_tool.bin对应配置项的内容 + * + * @param [in] item_id 配置项ID号 + * @param [out] buf 用于存储read数据内容 + * @param [in] len buf的长度(byte), buf长度必须大于等于read数据长度 + * + * @return 1)执行正确: 返回值等于实际上所读到的数据长度(大于0); + * 2)执行错误: 返回值小于等于0, 小于0表示相关错误码; + */ +/* --------------------------------------------------------------------------*/ +int syscfg_read_btmac_blemac_from_bin(u16 item_id, void *buf, u16 len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 写入对应配置项的内容 + * + * @param [in] item_id 配置项ID号 + * @param [in] buf 用于存储write数据内容 + * @param [in] len buf的长度(byte), buf长度必须大于等于write数据长度 + * + * @return 1)执行正确: 返回值等于实际上所读到的数据长度(大于0); + * 2)执行错误: 返回值小于等于0, 小于0表示相关错误码; + */ +/* --------------------------------------------------------------------------*/ +int syscfg_write(u16 item_id, void *buf, u16 len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 以dma的方式写入对应配置项的内容, 请注意buf地址需要按照4byte对齐 + * + * @param [in] item_id 配置项ID号 + * @param [in] buf 用于存储write数据内容 + * @param [in] len buf的长度(byte), buf长度必须大于等于write数据长度 + * + * @return 1)执行正确: 返回值等于实际上所读到的数据长度(大于0); + * 2)执行错误: 返回值小于等于0, 小于0表示相关错误码; + */ +/* --------------------------------------------------------------------------*/ +int syscfg_dma_write(u16 item_id, void *buf, u16 len); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 读取同一个配置项存在多份数据中的某一份数据, ver读取表示第几份数据, ver从 0 开始; + * @brief 典型应用: 读取配置项CFG_BT_NAME中多个蓝牙名中的某一个蓝牙名; + * + * @param [in] item_id 配置项ID号 + * @param [in] buf 用于存储read数据内容 + * @param [in] len buf的长度(byte), buf长度必须大于等于read数据长度 + * @param [in] ver 读取表示第几份数据 + * + * @return 1)执行正确: 返回值等于实际上所读到的数据长度(大于0); + * 2)执行错误: 返回值小于等于0, 小于0表示相关错误码; + */ +/* --------------------------------------------------------------------------*/ +int syscfg_read_string(u16 item_id, void *buf, u16 len, u8 ver); + +/* --------------------------------------------------------------------------*/ +/** + * @brief 获取配置项的地址 + * @brief 注: 只支持cfg_tools.bin文件中的配置项读取 + * @param [in] item_id 配置项ID号 + * @param [out] len 配置项长度 + * + * @return 配置项地址指针(可以用cpu直接访问); + */ +/* --------------------------------------------------------------------------*/ +u8 *syscfg_ptr_read(u16 item_id, u16 *len); + + +//==================================================================================================// +// 配置项ID分配说明 // +// 1.配置项ID号根据存储区域进行分配; // +// 2.存储区域有3个: 1)VM区域; 2)sys_cfg.bin; 3)BTIF区域 // +// 3.配置项ID号分配如下: // +// 0)[0]: 配置项ID号0为配置项工具保留ID号; // +// 1)[ 1 ~ 49]: 共49项, 预留给用户自定义, 只存于VM区域; // +// 2)[ 50 ~ 99]: 共50项, sdk相关配置项, 只存于VM区域; // +// 3)[100 ~ 127]: 共28项, sdk相关配置项, 可以存于VM区域, sys_cfg.bin(作为默认值) 和 BTIF区域; // +// 4)[512 ~ 700]: 共188项, sdk相关配置项, 只存于sys_cfg.bin; // +//==================================================================================================// + +//=================================================================================// +// 用户自定义配置项[1 ~ 49] // +//=================================================================================// +#define CFG_USER_DEFINE_BEGIN 1 + + +#define CFG_USER_PAIR_INFO 2 +#define CFG_USER_TIM_FLAG 3 + + + + +#define VM_ALARM_0 3+1 +#define VM_ALARM_1 4+1 +#define VM_ALARM_2 5+1 +#define VM_ALARM_3 6+1 +#define VM_ALARM_4 7+1 +#define VM_ALARM_EX0 8+1 +#define VM_ALARM_EX1 9+1 +#define VM_ALARM_EX2 10+1 +#define VM_ALARM_EX3 11+1 +#define VM_ALARM_EX4 12+1 +#define VM_ALARM_NAME_0 13+1 +#define VM_ALARM_NAME_1 14+1 +#define VM_ALARM_NAME_2 15+1 +#define VM_ALARM_NAME_3 16+1 +#define VM_ALARM_NAME_4 17+1 +#define VM_ALARM_RING_NAME_0 18+1 +#define VM_ALARM_RING_NAME_1 19+1 +#define VM_ALARM_RING_NAME_2 20+1 +#define VM_ALARM_RING_NAME_3 21+1 +#define VM_ALARM_RING_NAME_4 22+1 +#define VM_ALARM_MASK 23+1 +#define CFG_USER_DEVICE_STA 24+1 +#define CFG_USER_PLAN_INFO1 25+1 + +#define CFG_USER_BATTERY_LEVEL 26+1 + + +#define CFG_USER_DEFINE_END 49 + +//=================================================================================// +// 只存VM配置项[50 ~ 99] // +//=================================================================================// +#define CFG_STORE_VM_ONLY_BEGIN 50 +#define AT_CHAR_DEV_NAME 51 +#define CFG_STORE_VM_ONLY_END 99 + +//=================================================================================// +// 可以存于VM, sys_cfg.bin(默认值)和BTIF区域的配置项[100 ~ 127] // +// (VM支持扩展到511) // +//=================================================================================// +#define CFG_STORE_VM_BIN_BTIF_BEGIN 100 +#define CFG_STORE_VM_BIN_BTIF_END (VM_ITEM_MAX_NUM - 1) //在app_cfg文件中配置128/256 + +//==================================================================================================// +//ID号分配方案: +// 1) 与APP CASE 相关的ID (0 ~ 50); +// 3) lib库保留ID(蓝牙, trim 值) (范围: 61 ~ 127); //67项 +// 4) 与app_case 扩展ID号,需要更大的ram资源(128 ~ 511); +//==================================================================================================// + +//=================================================================================// +// SDK库保留配置项[61 ~ 127] // +//=================================================================================// +#define CFG_REMOTE_DB_INFO 61 +#define CFG_REMOTE_DB_00 62 +#define CFG_REMOTE_DB_01 63 +#define CFG_REMOTE_DB_02 64 +#define CFG_REMOTE_DB_03 65 +#define CFG_REMOTE_DB_04 66 +#define CFG_REMOTE_DB_05 67 +#define CFG_REMOTE_DB_06 68 +#define CFG_REMOTE_DB_07 69 +#define CFG_REMOTE_DB_08 70 +#define CFG_REMOTE_DB_09 71 +#define CFG_REMOTE_DB_10 72 +#define CFG_REMOTE_DB_11 73 +#define CFG_REMOTE_DB_12 74 +#define CFG_REMOTE_DB_13 75 +#define CFG_REMOTE_DB_14 76 +#define CFG_REMOTE_DB_15 77 +#define CFG_REMOTE_DB_16 78 +#define CFG_REMOTE_DB_17 79 +#define CFG_REMOTE_DB_18 80 +#define CFG_REMOTE_DB_19 81 +// #define CFG_NULL 82 +#define CFG_BLE_MODE_INFO 83 +#define CFG_TWS_PAIR_AA 84 +#define CFG_TWS_CONNECT_AA 85 +#define CFG_MUSIC_VOL 86 +#define CFG_DAC_DTB 88 +#define CFG_MC_BIAS 89 +#define CFG_POR_FLAG 90 +#define CFG_MIC_LDO_VSEL 91 +#define CFG_DAC_TRIM_INFO 92 +#define CFG_BT_TRIM_INFO 93 +#define CFG_ANC_INFO 94 +#define CFG_TWS_LOCAL_ADDR 95 +#define CFG_TWS_REMOTE_ADDR 96 +#define CFG_TWS_COMMON_ADDR 97 +#define CFG_TWS_CHANNEL 98 +#define VM_PMU_VOLTAGE 99 +// #define CFG_NULL 100 + +//=========== btif & cfg_tool.bin & vm ============// +#define CFG_BT_NAME 101 +#define CFG_BT_MAC_ADDR 102 +#define CFG_BLE_NAME 103 +#define CFG_BLE_MAC_ADDR 104 +#define VM_OLD_RTC_TIME 105 +#define VM_OLD_REAL_TIME 106 +#define VM_BLE_LOCAL_INFO 109 +#define CFG_BT_FRE_OFFSET 110 +#define VM_GFPS_KEY_LIST 111 +#define VM_GFPS_NAME 112 +// #define CFG_NULL 113 +#define VM_TME_AUTH_COOKIE 114 +// #define CFG_NULL 115 + +#define VM_RTC_TRIM 116 + +#define VM_BLE_REMOTE_DB_INFO 117 +#define VM_BLE_REMOTE_DB_00 118 +#define VM_BLE_REMOTE_DB_01 119 +#define VM_BLE_REMOTE_DB_02 120 +#define VM_BLE_REMOTE_DB_03 121 +#define VM_BLE_REMOTE_DB_04 122 +#define VM_BLE_REMOTE_DB_05 123 +#define VM_BLE_REMOTE_DB_06 124 +#define VM_BLE_REMOTE_DB_07 125 +#define VM_BLE_REMOTE_DB_08 126 +#define VM_BLE_REMOTE_DB_09 127 + +#define CFG_ONLINE_EQ_DRC_DATA_ID 254//在线调试保存参数的id +#define CFG_ONLINE_SAVE_ID 255//在线保存文件大小的id + + +//=================================================================================// +// 只存于sys_cfg.bin的配置项[512 ~ 700] // +//=================================================================================// +#define CFG_STORE_BIN_ONLY_BEGIN 512 +//硬件类配置项[513 ~ 600] +#define CFG_UART_ID 513 +#define CFG_HWI2C_ID 514 +#define CFG_SWI2C_ID 515 +#define CFG_HWSPI_ID 516 +#define CFG_SWSPI_ID 517 +#define CFG_SD_ID 518 +#define CFG_USB_ID 519 +#define CFG_LCD_ID 520 +#define CFG_TOUCH_ID 521 +#define CFG_IOKEY_ID 522 +#define CFG_ADKEY_ID 523 +#define CFG_AUDIO_ID 524 +#define CFG_VIDEO_ID 525 +#define CFG_WIFI_ID 526 +#define CFG_NIC_ID 527 +#define CFG_LED_ID 528 +#define CFG_POWER_MANG_ID 529 +#define CFG_IRFLT_ID 530 +#define CFG_PLCNT_ID 531 +#define CFG_PWMLED_ID 532 +#define CFG_RDEC_ID 533 +#define CFG_CHARGE_STORE_ID 534 +#define CFG_CHARGE_ID 535 +#define CFG_LOWPOWER_V_ID 536 +#define CFG_MIC_TYPE_ID 537 +#define CFG_COMBINE_SYS_VOL_ID 538 +#define CFG_COMBINE_CALL_VOL_ID 539 +#define CFG_LP_TOUCH_KEY_ID 540 + +//蓝牙类配置项[601 ~ 650] +#define CFG_BT_RF_POWER_ID 601 +#define CFG_TWS_PAIR_CODE_ID 602 +#define CFG_AUTO_OFF_TIME_ID 603 +#define CFG_AEC_ID 604 +#define CFG_UI_TONE_STATUS_ID 605 +#define CFG_KEY_MSG_ID 606 +#define CFG_LRC_ID 607 +#define CFG_DMS_ID 609 +#define CFG_ANC_ID 610 +#define CFG_SMS_DNS_ID 612 //单mic神经网络降噪 +#define CFG_DMS_DNS_ID 613 //双mic神经网络降噪 +#define CFG_DMS_FLEXIBLE_ID 614 //灵活可变双mic降噪 +#define CFG_BLE_RF_POWER_ID 615 +#define CFG_DMS_DNS_FLEXIBLE_ID 616 //灵活可变双mic神经网络降噪 +#define CFG_TMS_DNS_ID 617 //3mic神经网络降噪参数 + +//其它类配置项[651 ~ 700] +#define CFG_STORE_BIN_ONLY_END 700 + + + +#endif + diff --git a/include_lib/system/task.h b/include_lib/system/task.h new file mode 100644 index 0000000..9830fb7 --- /dev/null +++ b/include_lib/system/task.h @@ -0,0 +1,42 @@ +#ifndef TASK_PRIORITY_H +#define TASK_PRIORITY_H + + +#include "os/os_api.h" + + +struct task_info { + const char *name; + u8 prio; + u8 core; + u16 stack_size; + u16 qsize; +}; + + + +typedef OS_SEM sem_t; +typedef OS_MUTEX mutex_t; + + +int task_create(void (*task)(void *p), void *p, const char *name); + + +int task_exit(const char *name); + +int task_delete(const char *name); + +int task_kill(const char *name); + + + + + + + + + + +#endif + + diff --git a/include_lib/system/timer.h b/include_lib/system/timer.h new file mode 100644 index 0000000..7a1f184 --- /dev/null +++ b/include_lib/system/timer.h @@ -0,0 +1,308 @@ +#ifndef SYS_TIMER_H +#define SYS_TIMER_H + + +#include "typedef.h" +#include "generic/list.h" + + +struct static_sys_timer { + void (*func)(void *priv); + void *priv; + u32 msec; + u32 jiffies; +}; + +struct sys_usec_timer { + void (*func)(void *priv); + void *priv; + const char *owner; + struct sys_cpu_timer *timer; +}; + + +#define SYS_HI_TIMER_ADD(_func, _priv, _msec) \ + static struct static_sys_timer hi_timer sec(.hi_timer) = { \ + .func = _func, \ + .priv = _priv, \ + .msec = _msec, \ + } + +extern struct static_sys_timer static_hi_timer_begin[]; +extern struct static_sys_timer static_hi_timer_end[]; + +#define list_for_each_static_hi_timer(p) \ + for (p=static_hi_timer_begin; p>24)|((x>>8)&0xff00)|(x<<24)|((x&0xff00)<<8)) +#define font_ntoh(x) (unsigned short int )((x>>8&0x00ff)|x<<8&0xff00) + +extern const struct font_info font_info_table[]; + + +typedef struct { + u8 codepage; + u32 ansi_offset; + u32 table_offset; +} LANG_TABLE; + + +#define CP874 (1) +#define CP937 (2) +#define CP1250 (3) +#define CP1251 (4) +#define CP1252 (5) +#define CP1253 (6) +#define CP1254 (7) +#define CP1255 (8) +#define CP1256 (9) +#define CP1257 (10) +#define CP1258 (11) +#define CPKSC (12) +#define CPSIJS (13) + + +extern const LANG_TABLE *lange_info_table; + + +int font_set_offset_table(const LANG_TABLE *table); + + + +#endif diff --git a/include_lib/system/ui/font/font_sdfs.h b/include_lib/system/ui/font/font_sdfs.h new file mode 100644 index 0000000..654c70d --- /dev/null +++ b/include_lib/system/ui/font/font_sdfs.h @@ -0,0 +1,23 @@ +#ifndef __UI_SDFS_H__ +#define __UI_SDFS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "generic/typedef.h" +#include "fs/fs.h" + +#define SD_SEEK_SET 0x00 +#define SD_SEEK_CUR 0x01 + +FILE *font_sd_fopen(const char *filename, void *arg); +int font_sd_fread(FILE *fp, void *buf, u32 len); +int font_sd_fseek(FILE *fp, u8 seek_mode, u32 offset); +int font_sd_fclose(FILE *fp); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include_lib/system/ui/font/font_textout.h b/include_lib/system/ui/font/font_textout.h new file mode 100644 index 0000000..ff08732 --- /dev/null +++ b/include_lib/system/ui/font/font_textout.h @@ -0,0 +1,103 @@ +#ifndef __FONT_OUT_H__ +#define __FONT_OUT_H__ + +#include "generic/typedef.h" +#include "font/font_all.h" + +/** + * @brief 打开字库 + * + * @param info:字库信息 + * @param language:语言 + * + * @returns TRUE:打开成功 FALSE:打开失败 + */ +struct font_info *font_open(struct font_info *info, u8 language); +/** + * @brief 获取字符宽度 + * + * @param info + * @param str + * @param strlen + * + * @returns + */ +u16 font_text_width(struct font_info *info, u8 *str, u16 strlen); +u16 font_textw_width(struct font_info *info, u8 *str, u16 strlen); +u16 font_textu_width(struct font_info *info, u8 *str, u16 strlen); + +/** + * @brief 字库内码显示接口 + * + * @param info + * @param str + * @param strlen + * + * @returns + */ +u16 font_textout(struct font_info *info, u8 *str, u16 strlen, u16 x, u16 y); +/** + * @brief 字库unicode显示接口 + * + * @param info + * @param str + * @param strlen + * @param x + * @param y + * + * @returns + */ +u16 font_textout_unicode(struct font_info *info, u8 *str, u16 strlen, u16 x, u16 y); +/** + * @brief 字库utf8显示接口 + * + * @param info + * @param str + * @param strlen + * @param x + * @param y + * + * @returns + */ +u16 font_textout_utf8(struct font_info *info, u8 *str, u16 strlen, u16 x, u16 y); +/** + * @brief utf8转内码 + * + * @param info + * @param utf8 + * @param utf8len + * @param ansi + * + * @returns + */ +u16 font_utf8toansi(struct font_info *info, u8 *utf8, u16 utf8len, u8 *ansi); +/** + * @brief utf16转内码 + * + * @param info + * @param utf + * @param len + * @param ansi + * + * @returns + */ +u16 font_utf16toansi(struct font_info *info, u8 *utf, u16 len, u8 *ansi); +/** + * @brief utf8转utf16 + * + * @param info + * @param utf8 + * @param utf8len + * @param utf16 + * + * @returns + */ +u16 font_utf8toutf16(struct font_info *info, u8 *utf8, u16 utf8len, u16 *utf16); +/** + * @brief 字库关闭 + * + * @param info + */ +void font_close(struct font_info *info); + +#endif diff --git a/include_lib/system/ui/font/language_list.h b/include_lib/system/ui/font/language_list.h new file mode 100644 index 0000000..0c0bd60 --- /dev/null +++ b/include_lib/system/ui/font/language_list.h @@ -0,0 +1,29 @@ +#ifndef __LANGUAGE_LIST_H__ +#define __LANGUAGE_LIST_H__ + +#define Chinese_Simplified 1 //简体中文 +#define Chinese_Traditional 2 //繁体中文 +#define Japanese 3 //日语 +#define Korean 4 //韩语 +#define English 5 //英语 +#define French 6 //法语 +#define German 7 //德语 +#define Italian 8 //意大利语 +#define Dutch 9 //荷兰语 +#define Portuguese 10 //葡萄牙语 +#define Spanish 11 //西班牙语 +#define Swedish 12 //瑞典语 +#define Czech 13 //捷克语 +#define Danish 14 //丹麦语 +#define Polish 15 //波兰语 +#define Russian 16 //俄语 +#define Turkey 17 //土耳其语 +#define Hebrew 18 //希伯来语 +#define Thai 19 //泰语 +#define Hungarian 20 //匈牙利语 +#define Romanian 21 //罗马尼亚语 +#define Arabic 22 //阿拉伯语 +#define Vietnam 23 //越南语 +#define Tibetan 24 //藏文 + +#endif diff --git a/include_lib/system/ui/res/resfile.h b/include_lib/system/ui/res/resfile.h new file mode 100644 index 0000000..66065ef --- /dev/null +++ b/include_lib/system/ui/res/resfile.h @@ -0,0 +1,101 @@ +#ifndef RESFILE_H +#define RESFILE_H + +#include "typedef.h" +#include "fs/fs.h" + +// resfile共用文件句柄 +#if (defined(CONFIG_CPU_BR23) && defined(CONFIG_APP_WATCH)) +#define RESFILE_COMMON_HDL_EN 0 +#else +#define RESFILE_COMMON_HDL_EN 0 +#endif + +#define FILE_TYPE_JPEG 5 +#define AT_UI_RAM AT(.ui_ram) + + +//图像数据格式 +enum { + PIXEL_FMT_ARGB8888, + PIXEL_FMT_RGB888, + PIXEL_FMT_RGB565, + PIXEL_FMT_L8, + PIXEL_FMT_AL88, + PIXEL_FMT_AL44, + PIXEL_FMT_A8, + PIXEL_FMT_L1, + PIXEL_FMT_ARGB8565, + PIXEL_FMT_OSD16, + PIXEL_FMT_SOLID, + PIXEL_FMT_JPEG, + PIXEL_FMT_UNKNOW, +}; + +// #define EXTERN_PATH "storage/nor_ui/C/res/" +// #define EXTERN_PATH "storage/virfat_flash/C/uires/" +struct image_file { + u8 format; + u8 compress; + u16 data_crc; + u16 width; + u16 height; + u32 offset; + u32 len; +}; + +typedef struct resfile { + FILE *file; +#if RESFILE_COMMON_HDL_EN + struct list_head entry; + u32 offset; + u32 size; +#endif +} RESFILE; + +int open_resfile(const char *name); +void close_resfile(); + +int res_file_version_compare(int res_ver); + +int open_str_file(const char *name); +void close_str_file(); +int str_file_version_compare(int str_ver); + +int open_style_file(const char *name); + +int font_ascii_init(const char *name); +int open_image_by_id(RESFILE *specfile, struct image_file *f, int id, int page); +int read_image_data(struct image_file *f, u8 *data, int len); +int br23_read_image_data(RESFILE *specfile, struct image_file *f, u8 *data, int len, int offset); +int br25_read_image_data(RESFILE *specfile, struct image_file *f, u8 *data, int len, int offset); +u32 image_decode(const void *pSour, void *pDest, u32 SourLen, u32 DestLen, u8 compress); +int open_string_pic(struct image_file *file, int id); +int read_str_data(struct image_file *f, u8 *data, int len); +int br23_read_str_data(struct image_file *f, u8 *data, int len, int offset); +int br25_read_str_data(struct image_file *f, u8 *data, int len, int offset); +int load_pallet_table(int id, u32 *data); +int ui_language_set(int language); +int ui_language_get(); + +RESFILE *res_fopen(const char *path, const char *mode); +int res_fread(RESFILE *_file, void *buf, u32 len); +int res_fseek(RESFILE *_file, int offset, int fromwhere); +int res_flen(RESFILE *file); +int res_fclose(RESFILE *file); +int _norflash_read_watch(u8 *buf, u32 addr, u32 len, u8 wait);//加速读 + +struct ui_load_info { + u8 pj_id; + const char *path; + RESFILE *file; + RESFILE *res; + RESFILE *str; +}; + +void *ui_load_res_by_pj_id(int pj_id); +void *ui_load_str_by_pj_id(int pj_id); +int ui_set_sty_path_by_pj_id(int pj_id, const u8 *path); +void *ui_load_sty_by_pj_id(int pj_id); + +#endif diff --git a/include_lib/system/ui/ui/control.h b/include_lib/system/ui/ui/control.h new file mode 100644 index 0000000..8223202 --- /dev/null +++ b/include_lib/system/ui/ui/control.h @@ -0,0 +1,371 @@ +#ifndef UI_CONTROL_H +#define UI_CONTROL_H + +#include "ui/ui_core.h" + +union ui_control_info; +struct layout_info; + +#define CTRL_TYPE_WINDOW 2 +#define CTRL_TYPE_LAYOUT 3 +#define CTRL_TYPE_LAYER 4 +#define CTRL_TYPE_GRID 5 +#define CTRL_TYPE_LIST 6 +#define CTRL_TYPE_BUTTON 7 +#define CTRL_TYPE_PIC 8 +#define CTRL_TYPE_BATTERY 9 +#define CTRL_TYPE_TIME 10 +#define CTRL_TYPE_CAMERA_VIEW 11 +#define CTRL_TYPE_TEXT 12 +#define CTRL_TYPE_ANIMATION 13 +#define CTRL_TYPE_PLAYER 14 +#define CTRL_TYPE_NUMBER 15 + +#define CTRL_TYPE_PROGRESS 20 +#define CTRL_PROGRESS_CHILD_BEGIN (CTRL_TYPE_PROGRESS + 1) +#define CTRL_PROGRESS_CHILD_HIGHLIGHT (CTRL_PROGRESS_CHILD_BEGIN) //21 +#define CTRL_PROGRESS_CHILD_END (CTRL_PROGRESS_CHILD_BEGIN + 1) + +#define CTRL_TYPE_MULTIPROGRESS 22 +#define CTRL_MULTIPROGRESS_CHILD_BEGIN (CTRL_TYPE_MULTIPROGRESS + 1) +#define CTRL_MULTIPROGRESS_CHILD_HIGHLIGHT (CTRL_MULTIPROGRESS_CHILD_BEGIN)//23 +#define CTRL_MULTIPROGRESS_CHILD_END (CTRL_MULTIPROGRESS_CHILD_BEGIN + 1) + +#define CTRL_TYPE_WATCH 24 +#define CTRL_WATCH_CHILD_BEGIN (CTRL_TYPE_WATCH + 1) +#define CTRL_WATCH_CHILD_HOUR (CTRL_WATCH_CHILD_BEGIN)//25 +#define CTRL_WATCH_CHILD_MIN (CTRL_WATCH_CHILD_BEGIN+1)//26 +#define CTRL_WATCH_CHILD_SEC (CTRL_WATCH_CHILD_BEGIN+2)//27 +#define CTRL_WATCH_CHILD_END (CTRL_WATCH_CHILD_BEGIN+3) + + +#define CTRL_TYPE_SLIDER 28 + +#define SLIDER_CHILD_BEGIN (CTRL_TYPE_SLIDER+1) +#define SLIDER_CHILD_UNSELECT_PIC (SLIDER_CHILD_BEGIN)//29 +#define SLIDER_CHILD_SELECTED_PIC (SLIDER_CHILD_BEGIN+1)//30 +#define SLIDER_CHILD_SLIDER_PIC (SLIDER_CHILD_BEGIN+2)//31 +#define SLIDER_CHILD_PERSENT_TEXT (SLIDER_CHILD_BEGIN+3)//32 +#define SLIDER_CHILD_END (SLIDER_CHILD_BEGIN+4) + + +#define CTRL_TYPE_VSLIDER 33 + +#define VSLIDER_CHILD_BEGIN (CTRL_TYPE_VSLIDER+1) +#define VSLIDER_CHILD_UNSELECT_PIC (VSLIDER_CHILD_BEGIN)//34 +#define VSLIDER_CHILD_SELECTED_PIC (VSLIDER_CHILD_BEGIN+1)//35 +#define VSLIDER_CHILD_SLIDER_PIC (VSLIDER_CHILD_BEGIN+2)//36 +#define VSLIDER_CHILD_PERSENT_TEXT (VSLIDER_CHILD_BEGIN+3)//37 +#define VSLIDER_CHILD_END (VSLIDER_CHILD_BEGIN+4) + + +struct ui_ctrl_info_head { + u8 type; + u8 ctrl_num; + u8 css_num; + u8 len; + u8 page; + u8 rev[3]; + int id; + struct element_css1 *css; +}; + +struct ui_image_list { + u16 num; + u16 image[0]; +}; + +struct ui_text_list { + u16 num; + char str[0]; +}; + + +struct ui_image_list_t { + u16 num; + u16 image[64]; +}; + +#define UI_TEXT_LIST_MAX_NUM 3 +struct ui_text_list_t { + u16 num; + u16 str[50]; +}; + +struct ui_button_info { + struct ui_ctrl_info_head head; + struct element_event_action *action; +}; + + + +struct ui_camera_info { + struct ui_ctrl_info_head head; + char device[8]; + struct element_event_action *action; +}; + +struct ui_player_info { + struct ui_ctrl_info_head head; + char device[8]; + struct element_event_action *action; +}; + +struct ui_time_info { + struct ui_ctrl_info_head head; + char source[8]; + u8 auto_cnt; + u8 rev[3]; + char format[16]; + int color; + int hi_color; + u16 number[10]; + u16 delimiter[10]; + struct element_event_action *action; +}; + +struct ui_number_info { + struct ui_ctrl_info_head head; + char source[8]; + char format[16]; + int color; + int hi_color; + u16 number[10]; + u16 delimiter[10]; + u16 space[2]; + struct element_event_action *action; +}; + + +struct ui_pic_info { + struct ui_ctrl_info_head head; + u8 highlight; + u16 cent_x; + u16 cent_y; + struct ui_image_list *normal_img; + struct ui_image_list *highlight_img; + struct element_event_action *action; +}; + + +struct ui_battery_info { + struct ui_ctrl_info_head head; + struct ui_image_list *normal_image; + struct ui_image_list *charge_image; + struct element_event_action *action; +}; + + +struct ui_text_info { + struct ui_ctrl_info_head head; + char source[8]; + char code[8]; + int color; + int highlight_color; + struct ui_text_list *str; + struct element_event_action *action; +}; + + +struct ui_grid_info { + struct ui_ctrl_info_head head; + u8 page_mode; + char highlight_index; + struct element_event_action *action; + struct layout_info *info; +}; + +struct ui_animation_info { + struct ui_ctrl_info_head head; + u16 loop_num; + u32 interval; + struct ui_image_list *img; + struct element_event_action *action; +}; + +struct ui_slider_info { + struct ui_ctrl_info_head head; + u8 step; + struct ui_ctrl_info_head *ctrl; + // struct element_event_action *action; +}; + +struct ui_vslider_info { + struct ui_ctrl_info_head head; + u8 step; + struct ui_ctrl_info_head *ctrl; + // struct element_event_action *action; +}; + +struct ui_watch_info { + struct ui_ctrl_info_head head; + char source[8]; + struct element_event_action *action; + struct ui_ctrl_info_head *ctrl; +}; + +struct ui_progress_info { + struct ui_ctrl_info_head head; + char source[8]; + struct element_event_action *action; + struct ui_ctrl_info_head *ctrl; +}; + +struct ui_multiprogress_info { + struct ui_ctrl_info_head head; + char source[8]; + struct element_event_action *action; + struct ui_ctrl_info_head *ctrl; +}; + +struct ui_browser_info { + struct ui_ctrl_info_head head; + u8 row; + u8 column; + u8 interval; + u8 scroll; + u8 auto_highlight; + struct element_event_action *action; + struct ui_ctrl_info_head *ctrl; +}; + +struct ui_fattrs_info { + struct ui_ctrl_info_head head; + struct element_event_action *action; + struct ui_ctrl_info_head *ctrl; +}; + +struct layout_info { + struct ui_ctrl_info_head head; + struct element_event_action *action; + union ui_control_info *ctrl; +}; + + +struct layer_info { + struct ui_ctrl_info_head head; + u8 format; + struct element_event_action *action; + struct layout_info *layout; +}; + + +union ui_control_info { + struct ui_ctrl_info_head head;//16 bytes + struct ui_button_info button;//20 bytes + struct ui_camera_info camera;//28 bytes + struct ui_time_info time;//84 bytes + struct ui_number_info number; + struct ui_pic_info pic;//36 bytes + struct ui_battery_info battery;//28 bytes + struct ui_text_info text;//40 bytes + struct ui_grid_info grid;//28 bytes + struct layer_info layer; + struct layout_info layout; + struct ui_watch_info watch; + struct ui_progress_info progress; + struct ui_multiprogress_info multiprogress; + struct ui_slider_info slider; + struct ui_vslider_info vslider; +};//84 bytes + +// union ui_control_info { +// struct ui_ctrl_info_head head; +// struct ui_button_info button; +// struct ui_camera_info camera; +// struct ui_time_info time; +// struct ui_number_info number; +// struct ui_pic_info pic; +// struct ui_battery_info battery; +// struct ui_text_info text; +// struct ui_grid_info grid; +// }; + + +struct window_info { + u8 type; + u8 ctrl_num; + u8 css_num; + u8 len; + u8 rev[4]; + struct rect rect; + struct layer_info *layer; +// struct element_event_action *action; +}; + +struct control_ops { + int type; + void *(*new)(const void *, struct element *); + /*int (*delete)(void *);*/ +}; + +extern const struct control_ops control_ops_begin[]; +extern const struct control_ops control_ops_end[]; + + +#define REGISTER_CONTROL_OPS(_type) \ + static const struct control_ops control_ops_##_type sec(.control_ops) __attribute__((used)) = { \ + .type = _type, + + + +#define get_control_ops_by_type(_type) \ + ({ \ + const struct control_ops *ops, *ret=NULL; \ + for (ops = control_ops_begin; ops < control_ops_end; ops++) { \ + if (ops->type == _type) { \ + ret = ops; \ + break; \ + } \ + }\ + ret; \ + }) + + +#if 0 +struct control_event_header { + int id; + int len; +}; + +extern struct control_event_header control_event_handler_begin[]; +extern struct control_event_header control_event_handler_end[]; + + +#define REGISTER_CONTROL_EVENT_HANDLER(control, _id) \ + static const struct control##_event_handler __##control##_event_handler_##_id \ + sec(.control_event_handler) = { \ + .header = { \ + .id = _id, \ + .len = sizeof(struct control##_event_handler), \ + }, \ + + + + +static inline void *control_event_handler_for_id(int id) +{ + struct control_event_header *p; + + for (p = control_event_handler_begin; p < control_event_handler_end;) { + if (p->id == id) { + return p; + } + p = (u8 *)p + p->len; + } + + return NULL; +} +#endif + + + + + + + + +#endif + + + diff --git a/include_lib/system/ui/ui/layer.h b/include_lib/system/ui/ui/layer.h new file mode 100644 index 0000000..4154292 --- /dev/null +++ b/include_lib/system/ui/ui/layer.h @@ -0,0 +1,53 @@ +#ifndef LAYER_H +#define LAYER_H + + +#include "ui/layout.h" +#include "ui/control.h" + + +struct layer { + struct element elm; //must be first + u8 hide; + u8 inited; + u8 highlight; + u8 ctrl_num; + u8 css_num; + u32 css[2]; + struct draw_context dc; + struct layout *layout; + const struct layer_info *info; + const struct element_event_handler *handler; +}; + + +#define layer_for_id(id) \ + (struct layer *)ui_core_get_element_by_id(id); + + +struct layer *layer_new(struct layer_info *info, int num, struct element *parent); + + +void layer_delete_probe(struct layer *layer, int num); + +void layer_delete(struct layer *layer, int num); + +int layer_show(int id); + +int layer_hide(int id); + +int layer_toggle(int id); + + + + + + + + + +#endif + + + + diff --git a/include_lib/system/ui/ui/layout.h b/include_lib/system/ui/ui/layout.h new file mode 100644 index 0000000..ae1bd16 --- /dev/null +++ b/include_lib/system/ui/ui/layout.h @@ -0,0 +1,54 @@ +#ifndef LAYOUT_H +#define LAYOUT_H + + +#include "ui/ui_core.h" +#include "ui/control.h" + + + + + +struct layout { + struct element elm; //must be first + u8 hide: 1; + u8 inited: 1; + u8 release: 6; + // u8 css_num:5; + // u32 css[2]; + struct layout *layout; + const struct layout_info *info; + const struct element_event_handler *handler; +}; + + + +#define layout_for_id(id) \ + (struct layout *)ui_core_get_element_by_id(id); + + +struct layout *layout_new(struct layout_info *, int, struct element *); + +void layout_delete_probe(struct layout *layout, int num); + +void layout_delete(struct layout *layout, int num); + +int layout_show(int id); + +int layout_hide(int id); + +int layout_toggle(int id); + +void layout_on_focus(struct layout *layout); +void layout_lose_focus(struct layout *layout); + + +/*int layout_current_highlight(int id);*/ + +/*int layout_onkey(struct layout *layout, struct element_key_event *e);*/ + + + +#endif + + diff --git a/include_lib/system/ui/ui/p.h b/include_lib/system/ui/ui/p.h new file mode 100644 index 0000000..2993b33 --- /dev/null +++ b/include_lib/system/ui/ui/p.h @@ -0,0 +1,40 @@ +#ifndef UI_P_H +#define UI_P_H + +#include "ui/ui_core.h" + +struct ui_str { + const char *format; + char *str; +}; + +struct element_text { + struct element elm; //must be first + char *str; + const char *format; + void *priv; + int color; + const struct element_event_handler *handler; +}; + + + +void text_element_set_text(struct element_text *text, char *str, + const char *format, int color); + + +void text_element_init(struct element_text *text, int id, u8 page, u8 prj, + const struct element_css1 *css, + const struct element_event_action *action); + + +void text_element_set_event_handler(struct element_text *text, void *priv, + const struct element_event_handler *handler); + + + + + + +#endif + diff --git a/include_lib/system/ui/ui/ui.h b/include_lib/system/ui/ui/ui.h new file mode 100644 index 0000000..b143e80 --- /dev/null +++ b/include_lib/system/ui/ui/ui.h @@ -0,0 +1,112 @@ +#ifndef UI_CORE_H +#define UI_CORE_H + +#include "window.h" +#include "ui_button.h" +#include "ui_grid.h" +#include "ui_time.h" +#include "ui_camera.h" +#include "ui_pic.h" +#include "ui_text.h" +#include "ui_battery.h" +#include "ui_browser.h" +#include "ui_slider.h" +#include "ui_slider_vert.h" +#include "ui_number.h" +#include "ui_watch.h" +#include "ui_progress.h" +#include "ui_progress_multi.h" +#include "ui_rotate.h" +#include + +struct uimsg_handl { + const char *msg; + int (*handler)(const char *type, u32 args); +}; + +int ui_framework_init(void *); + +int ui_set_style_file(struct ui_style *style); + +int ui_style_file_version_compare(int version); + +int ui_redraw(int id); + +int ui_show(int id); + +int ui_hide(int id); + +int ui_set_call(int (*func)(int), int param); + +int ui_event_onkey(struct element_key_event *e); + +int ui_event_ontouch(struct element_touch_event *e); + +struct element *ui_get_highlight_child_by_id(int id); +int ui_invert_element_by_id(int id); + +int ui_no_highlight_element(struct element *elm); +int ui_no_highlight_element_by_id(int id); +int ui_highlight_element(struct element *elm); +int ui_highlight_element_by_id(int id); + +int ui_get_current_window_id(); + +int ui_register_msg_handler(int id, const struct uimsg_handl *handl); + +int ui_message_handler(int id, const char *msg, va_list); + +const char *str_substr_iter(const char *str, char delim, int *iter); + +int ui_get_child_by_id(int id, int (*event_handler_cb)(void *, int, int)); + +int ui_set_default_handler(int (*ontouch)(void *, struct element_touch_event *), + int (*onkey)(void *, struct element_key_event *), + int (*onchange)(void *, enum element_change_event, void *)); + +/* + * 锁定元素elm之外的区域,所有的触摸消息都发给elm + */ +void ui_ontouch_lock(void *elm); +void ui_ontouch_unlock(void *elm); + +/* + * 锁定控件的夫图层,先不推向imb显示 + */ +int ui_lock_layer(int id); +int ui_unlock_layer(int id); + +int ui_get_disp_status_by_id(int id); + +int create_control_by_id(char *tabfile, int page_id, int id, int parent_id); +int delete_control_by_id(int id); + + +void ui_remove_backcolor(struct element *elm); +void ui_remove_backimage(struct element *elm); +void ui_remove_border(struct element *elm); + +int ui_fill_rect(struct draw_context *dc, int left, int top, int width, int height, u32 acolor); +int ui_draw_image(struct draw_context *dc, int page, int id, int x, int y); +int ui_draw_ascii(struct draw_context *dc, char *str, int strlen, int x, int y, int color); +int ui_draw_text(struct draw_context *dc, int encode, int endian, char *str, int strlen, int x, int y, int color); +int ui_draw_strpic(struct draw_context *dc, int id, int x, int y, int color); +void ui_draw_line(void *_dc, int x0, int y0, int x1, int y1, int color); +void ui_draw_line_by_angle(void *_dc, int x, int y, int length, int angle, int color); +void ui_draw_rect(void *_dc, int x, int y, int width, int height, int color); +void ui_draw_circle(struct draw_context *dc, int center_x, int center_y, + int radius_big, int radius_small, int angle_begin, + int angle_end, int color, int percent); +int ui_draw_set_pixel(struct draw_context *dc, int x, int y, int pixel); +u32 ui_draw_get_pixel(struct draw_context *dc, int x, int y); +u16 ui_draw_get_mixed_pixel(u16 backcolor, u16 forecolor, u8 alpha); + +void *load_control_info_by_id(char *tabfile, u32 page_id, u32 id); +void *ui_control_new(void *_pos, void *parent); + + +#define ui_id2type(id) (((id)>>16) & 0x3f) + + +#endif + diff --git a/include_lib/system/ui/ui/ui.ld b/include_lib/system/ui/ui/ui.ld new file mode 100644 index 0000000..16fdea5 --- /dev/null +++ b/include_lib/system/ui/ui/ui.ld @@ -0,0 +1,37 @@ + 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 = .; + + diff --git a/include_lib/system/ui/ui/ui_battery.h b/include_lib/system/ui/ui/ui_battery.h new file mode 100644 index 0000000..f19a3b5 --- /dev/null +++ b/include_lib/system/ui/ui/ui_battery.h @@ -0,0 +1,29 @@ +#ifndef UI_BATTERY_H +#define UI_BATTERY_H + + +#include "ui/control.h" +#include "list.h" + + + + + + +struct ui_battery { + struct element elm; + int src; + u8 index; + u16 charge_image; + u16 normal_image; + struct list_head entry; + const struct ui_battery_info *info; + const struct element_event_handler *handler; +}; + +void ui_battery_enable(); +void ui_battery_level_change(int persent, int incharge);//改变所有电池控件 +int ui_battery_set_level_by_id(int id, int persent, int incharge);//修改指定id +int ui_battery_set_level(struct ui_battery *battery, int persent, int incharge);//初始化使用 + +#endif diff --git a/include_lib/system/ui/ui/ui_browser.h b/include_lib/system/ui/ui/ui_browser.h new file mode 100644 index 0000000..494b029 --- /dev/null +++ b/include_lib/system/ui/ui/ui_browser.h @@ -0,0 +1,92 @@ +#ifndef UI_BROWSER_H +#define UI_BROWSER_H + + + +#include "ui/ui_core.h" +#include "ui/control.h" + + + + +struct ui_browser { + struct element elm; + struct ui_file_browser *hdl; + char order; // 1 表示 正序, 非1 表示反序 + u8 inited; + u8 hide_byself; + u8 item_num; + u8 highlight; + u8 show_mode; + u16 cur_number; + u16 file_number; + struct ui_grid *grid; + const char *path; + const char *ftype; + const struct ui_browser_info *info; + const struct element_event_handler *handler; +}; + + +#define ui_file_browser_cur_item(bro) ui_grid_cur_item(((struct ui_browser *)bro)->grid) + + +int ui_file_browser_page_num(struct ui_browser *bro); + +int ui_file_browser_cur_page(struct ui_browser *bro, int *file_num); + +int ui_file_browser_set_page(struct ui_browser *bro, int page); + +int ui_file_browser_set_page_by_id(int id, int page); + +int ui_file_browser_next_page(struct ui_browser *bro); + +int ui_file_browser_next_page_by_id(int id); + +int ui_file_browser_prev_page(struct ui_browser *bro); + +int ui_file_browser_prev_page_by_id(int id); + +int ui_file_browser_set_dir(struct ui_browser *bro, const char *path, const char *ftype); + +int ui_file_browser_set_dir_by_id(int id, const char *path, const char *ftype); + +int ui_file_browser_get_file_attrs(struct ui_browser *bro, int item, + struct ui_file_attrs *attrs); + +int ui_file_browser_set_file_attrs(struct ui_browser *bro, int item, + struct ui_file_attrs *attrs); + +void *ui_file_browser_open_file(struct ui_browser *bro, int item); + + +int ui_file_browser_del_file(struct ui_browser *bro, int item); + +int ui_file_browser_highlight_item(struct ui_browser *bro, int item, bool yes); + +void *ui_file_browser_get_child_by_id(struct ui_browser *bro, int item, int id); + + + + + + + + + + + + + + + + + + + + + + + + +#endif diff --git a/include_lib/system/ui/ui/ui_button.h b/include_lib/system/ui/ui/ui_button.h new file mode 100644 index 0000000..762d2e7 --- /dev/null +++ b/include_lib/system/ui/ui/ui_button.h @@ -0,0 +1,20 @@ +#ifndef UI_BUTTON_H +#define UI_BUTTON_H + + +#include "ui/control.h" +#include "ui/ui_core.h" + +struct button { + struct element elm; + u8 image_index; + u8 css_num; + u32 css[2]; + const struct ui_button_info *info; + const struct element_event_handler *handler; +}; + +void ui_button_enable(); + +#endif + diff --git a/include_lib/system/ui/ui/ui_camera.h b/include_lib/system/ui/ui/ui_camera.h new file mode 100644 index 0000000..f29f044 --- /dev/null +++ b/include_lib/system/ui/ui/ui_camera.h @@ -0,0 +1,34 @@ +#ifndef UI_CAMERA_H +#define UI_CAMERA_H + +#include "ui/control.h" +#include "ui/ui_core.h" + + + + + + +struct ui_camera { + struct element elm; //must be first + int fd; + const struct ui_camera_info *info; + const struct element_event_handler *handler; +}; + + + +#define ui_camera_for_id(id) \ + (struct ui_camera*)ui_core_get_element_by_id(id) + + + +void register_ui_camera_handler(const struct element_event_handler *handler); + +int ui_camera_set_rect(int id, struct rect *r); + + + + +#endif + diff --git a/include_lib/system/ui/ui/ui_core.h b/include_lib/system/ui/ui/ui_core.h new file mode 100644 index 0000000..431ea37 --- /dev/null +++ b/include_lib/system/ui/ui/ui_core.h @@ -0,0 +1,566 @@ +#ifndef UI_ELEMENT_CORE_H +#define UI_ELEMENT_CORE_H + +#include "typedef.h" +#include "rect.h" +#include "system/event.h" +// #include "fs/fs.h" +#include "res/resfile.h" + + +#define UI_CTRL_BUTTON 0 + +struct element; + + +#ifdef offsetof +#undef offsetof +#endif +#ifdef container_of +#undef container_of +#endif + +#define offsetof(type, memb) \ +((unsigned long)(&((type *)0)->memb)) + +#define container_of(ptr, type, memb) \ +((type *)((char *)ptr - offsetof(type, memb))) + +enum ui_direction { + UI_DIR_UP, + UI_DIR_DOWN, + UI_DIR_LEFT, + UI_DIR_RIGHT, +}; + +enum ui_align { + UI_ALIGN_LEFT = 0, + UI_ALIGN_CENTER, + UI_ALIGN_RIGHT, +}; + + +enum { + POSITION_ABSOLUTE = 0, + POSITION_RELATIVE = 1, +}; + +enum { + ELM_EVENT_TOUCH_DOWN, + ELM_EVENT_TOUCH_MOVE, + ELM_EVENT_TOUCH_R_MOVE, + ELM_EVENT_TOUCH_L_MOVE, + ELM_EVENT_TOUCH_D_MOVE, + ELM_EVENT_TOUCH_U_MOVE, + ELM_EVENT_TOUCH_HOLD, + ELM_EVENT_TOUCH_UP, +}; + + +enum { + ELM_EVENT_KEY_CLICK, + ELM_EVENT_KEY_LONG, + ELM_EVENT_KEY_HOLD, +}; + +enum { + ELM_STA_INITED, + //ELM_STA_SHOW_PROBE, + //ELM_STA_SHOW_POST, + ELM_STA_HIDE, + ELM_STA_SHOW, + ELM_STA_PAUSE, +}; + +enum { + ELM_FLAG_NORMAL, + ELM_FLAG_HEAD, +}; + +enum { + DC_DATA_FORMAT_OSD8 = 0, + DC_DATA_FORMAT_YUV420 = 1, + DC_DATA_FORMAT_OSD16 = 2, + DC_DATA_FORMAT_OSD8A = 3, + DC_DATA_FORMAT_MONO = 4, +}; + + +struct element_touch_event { + int event; + int xoffset; + int yoffset; + u8 hold_up; + u8 onfocus; + u8 move_dir; + struct position pos; + struct position mov; + void *private_data; +}; + +struct element_key_event { + u8 event; + u8 value; + void *private_data; +}; + +#define ELM_KEY_EVENT(e) (0x0000 | (e->event) | (e->value << 8)) +#define ELM_TOUCH_EVENT(e) (0x1000 | (e->event)) +#define ELM_CHANGE_EVENT(e) (0x2000 | (e->event)) + +enum element_change_event { + ON_CHANGE_INIT_PROBE, + ON_CHANGE_INIT, + ON_CHANGE_TRY_OPEN_DC, + ON_CHANGE_FIRST_SHOW, + ON_CHANGE_SHOW_PROBE, + ON_CHANGE_SHOW, + ON_CHANGE_SHOW_POST, + ON_CHANGE_HIDE, + ON_CHANGE_HIGHLIGHT, + ON_CHANGE_RELEASE_PROBE, + ON_CHANGE_RELEASE, + ON_CHANGE_ANIMATION_END, + ON_CHANGE_SHOW_COMPLETED, + ON_CHANGE_UPDATE_ITEM, +}; + + +struct element_event_handler { + int id; + int (*ontouch)(void *, struct element_touch_event *); + int (*onkey)(void *, struct element_key_event *); + int (*onchange)(void *, enum element_change_event, void *); +}; + +struct jaction { + u32 show; + u32 hide; +}; + +enum { + ELM_ACTION_HIDE = 0, + ELM_ACTION_SHOW, + ELM_ACTION_TOGGLE, + ELM_ACTION_HIGHLIGHT, +}; + +struct event_action { + u16 event; + u16 action; + int id; + u8 argc; + char argv[]; +}; + +struct element_event_action { + u16 num; + struct event_action action[0]; +}; + +struct image_preview { + RESFILE *file; + int id; + int page; +}; + + +struct image { + int x; + int y; + int id; + int page; + int en; +}; + +struct draw_context { + u8 ref; + u8 alpha; + u8 align; + u8 data_format; + u8 prj; + u8 page; + u8 buf_num; + u32 background_color; + void *handl; + struct element *elm; + struct rect rect; + struct rect draw; + void *dc; + + struct image_preview preview; + + struct rect need_draw; + struct rect disp; + u16 width; + u16 height; + u8 *fbuf; + u32 fbuf_len; + u8 *buf; + u8 *buf0; + u8 *buf1; + u32 len; + u16 lines; + u8 col_align; + u8 row_align; + + struct image draw_img; + + u8 *mask; +}; + +struct css_border { + u16 left: 4; + u16 top: 4; + u16 right: 4; + u16 bottom: 4; + u16 color: 16; +}; + +struct css_border1 { + u8 left; + u8 top; + u8 right; + u8 bottom; + int color: 24; +}; + +struct element_css { + u8 align: 2; + u8 invisible: 1; + u8 z_order: 5; + int left/* : 16 */; + int top/* : 16 */; + int width/* : 16 */; + int height/* : 16 */; + u32 background_color: 24; + u32 alpha: 8; + int background_image: 24; + int image_quadrant: 8; + struct css_border border; +}; + +struct element_css1 { + u8 align; + u8 invisible; + u8 z_order; + int left; + int top; + int width; + int height; + u32 background_color: 24; + u32 alpha: 8; + int background_image: 24; + int image_quadrant: 8; + struct css_border1 border; +}; + +struct element_ops { + int (*show)(struct element *); + int (*redraw)(struct element *, struct rect *); +}; + +struct element { + u32 highlight: 1; + u32 state: 2; + u32 ref: 5; + u32 prj: 3; + u32 page: 21; + // u32 alive; + int id; + struct element *parent; + struct list_head sibling; + struct list_head child; + struct element *focus; + struct element_css css; + struct draw_context *dc; + // const struct element_ops *ops; + const struct element_event_handler *handler; + // const struct element_event_action *action; +}; + +struct ui_style { + const char *file; + u32 version; +}; + +enum { + UI_FTYPE_VIDEO = 0, + UI_FTYPE_IMAGE, + UI_FTYPE_AUDIO, + UI_FTYPE_DIR, + UI_FTYPE_UNKNOW = 0xff, +}; + +struct ui_file_attrs { + char *format; + char fname[128]; + struct vfs_attr attr; + u8 ftype; + u16 file_num; + u32 film_len; +}; + +struct ui_image_attrs { + u16 width; + u16 height; +}; + +struct ui_text_attrs { + const char *str; + const char *format; + int color; + u16 strlen; + u16 offset; + u8 encode: 2; + u8 endian: 1; + u8 flags: 5; + // u16 offset; + u16 displen; +}; + +struct ui_file_browser { + int file_number; + u8 dev_num; + void *private_data; +}; + +#define ELEMENT_ALIVE 0x53547a7b + +#define element_born(elm) \ + elm->alive = ELEMENT_ALIVE + +#define element_alive(elm) \ + (elm->alive == ELEMENT_ALIVE) + + +#define list_for_each_child_element(p, elm) \ + list_for_each_entry(p, &(elm)->child, sibling) + +#define list_for_each_child_element_reverse(p, n, elm) \ + list_for_each_entry_reverse_safe(p, n, &(elm)->child, sibling) + +#define list_for_each_child_element_safe(p, n, elm) \ + list_for_each_entry_safe(p, n, &(elm)->child, sibling) + +struct ui_platform_api { + void *(*malloc)(int); + void (*free)(void *); + + int (*load_style)(struct ui_style *); + + void *(*load_window)(int id); + void (*unload_window)(void *); + + int (*open_draw_context)(struct draw_context *); + int (*get_draw_context)(struct draw_context *); + int (*put_draw_context)(struct draw_context *); + int (*set_draw_context)(struct draw_context *); + int (*close_draw_context)(struct draw_context *); + + int (*fill_rect)(struct draw_context *, u32 color); + int (*draw_rect)(struct draw_context *, struct css_border *border); + int (*draw_image)(struct draw_context *, u32 src, u8 quadrant, u8 *mask); + int (*draw_point)(struct draw_context *, u16 x, u16 y, u32 color); + u32(*read_point)(struct draw_context *dc, u16 x, u16 y); + int (*invert_rect)(struct draw_context *, u32 color); + + void *(*load_widget_info)(void *_head, u8 page); + void *(*load_css)(u8 page, void *_css); + void *(*load_image_list)(u8 page, void *_list); + void *(*load_text_list)(u8 page, void *__list); + + //int (*highlight)(struct draw_context *); + int (*show_text)(struct draw_context *, struct ui_text_attrs *); + int (*read_image_info)(struct draw_context *, u32, u8, struct ui_image_attrs *); + + int (*open_device)(struct draw_context *, const char *device); + int (*close_device)(int); + + void *(*set_timer)(void *, void (*callback)(void *), u32 msec); + int (*del_timer)(void *); + + struct ui_file_browser *(*file_browser_open)(struct rect *r, + const char *path, const char *ftype, int show_mode); + + int (*get_file_attrs)(struct ui_file_browser *, struct ui_file_attrs *attrs); + + int (*set_file_attrs)(struct ui_file_browser *, struct ui_file_attrs *attrs); + + int (*clear_file_preview)(struct ui_file_browser *, struct rect *r); + + int (*show_file_preview)(struct ui_file_browser *, struct rect *r, struct ui_file_attrs *attrs); + + int (*flush_file_preview)(struct ui_file_browser *); + + void *(*open_file)(struct ui_file_browser *, struct ui_file_attrs *attrs); + int (*delete_file)(struct ui_file_browser *, struct ui_file_attrs *attrs); + + int (*move_file_preview)(struct ui_file_browser *_bro, struct rect *dst, struct rect *src); + + void (*file_browser_close)(struct ui_file_browser *); + +}; + +extern /* const */ struct ui_platform_api *platform_api; + +extern /* const */ struct element_event_handler dumy_handler; + +struct janimation { + u8 persent[5]; + u8 direction; + u8 play_state; + u8 iteration_count; + u16 delay; + u16 duration; + struct element_css css[0]; +}; + + +extern struct element_event_handler *elm_event_handler_begin; +extern struct element_event_handler *elm_event_handler_end; + + +#define ___REGISTER_UI_EVENT_HANDLER(style, _id) \ + static const struct element_event_handler element_event_handler_##_id \ + sec(.elm_event_handler_##style) __attribute__((used)) = { \ + .id = _id, + +#define __REGISTER_UI_EVENT_HANDLER(style, _id) \ + ___REGISTER_UI_EVENT_HANDLER(style, _id) + +#define REGISTER_UI_EVENT_HANDLER(id) \ + __REGISTER_UI_EVENT_HANDLER(STYLE_NAME, id) + + + +struct ui_style_info { + const char *name; + struct element_event_handler *begin; + struct element_event_handler *end; +}; + +extern struct ui_style_info ui_style_begin[]; +extern struct ui_style_info ui_style_end[]; + +#define __REGISTER_UI_STYLE(style_name) \ + extern struct element_event_handler elm_event_handler_begin_##style_name[]; \ + extern struct element_event_handler elm_event_handler_end_##style_name[]; \ + static const struct ui_style_info ui_style_##style_name sec(.ui_style) __attribute__((used)) = { \ + .name = #style_name, \ + .begin = elm_event_handler_begin_##style_name, \ + .end = elm_event_handler_end_##style_name, \ + }; + +#define REGISTER_UI_STYLE(style_name) \ + __REGISTER_UI_STYLE(style_name) + + +static inline struct element_event_handler *element_event_handler_for_id(u32 id) +{ + struct element_event_handler *p; + + for (p = elm_event_handler_begin; p < elm_event_handler_end; p++) { + if (p->id == id) { + return p; + } + } + + return NULL; +} + + + + +#define ui_core_get_element_css(elm) \ + &((struct element *)(elm))->css + +#define ui_core_element_invisable(elm, i) \ + ((struct element *)(elm))->css.invisible = i + + +int ui_core_init(const struct ui_platform_api *api, struct rect *rect); + +int ui_core_set_style(const char *style); + +void ui_core_set_rotate(int _rotate); + +int ui_core_get_rotate(); + + +void *ui_core_malloc(int size); + +void ui_core_free(void *buf); + +void ui_core_element_init(struct element *, + u32 id, + u8 page, + u8 prj, + /* const */ struct element_css1 *, + const struct element_event_handler *, + const struct element_event_action *); + +void ui_core_get_element_abs_rect(struct element *elm, struct rect *rect); + +void ui_core_append_child(void *_child); + +struct element *ui_core_get_first_child(); + +void ui_core_remove_element(void *_child); + + +int ui_core_open_draw_context(struct draw_context *dc, struct element *elm); + +int ui_core_close_draw_context(struct draw_context *dc); + +int ui_core_show(void *_elm, int init); + +int ui_core_hide(void *_elm); + +struct element *get_element_by_id(struct element *elm, u32 id); + +struct element *ui_core_get_element_by_id(u32 id); +int ui_core_get_disp_status_by_id(u32 id); + +struct element *ui_core_get_up_element(struct element *elm); +struct element *ui_core_get_down_element(struct element *elm); +struct element *ui_core_get_left_element(struct element *elm); +struct element *ui_core_get_right_element(struct element *elm); + +int ui_core_element_ontouch(struct element *, struct element_touch_event *e); + +int ui_core_ontouch(struct element_touch_event *e); + +int ui_core_element_onkey(struct element *elm, struct element_key_event *e); + +int ui_core_onkey(struct element_key_event *e); + +void ui_core_element_append_child(struct element *parent, struct element *child); + +struct element_css *ui_core_set_element_css(void *_elm, const struct element_css1 *css); + +int ui_core_invert_rect(struct draw_context *dc); + +void ui_core_release_child_probe(struct element *elm); + +void ui_core_release_child(struct element *elm); + + +int ui_core_redraw(void *_elm); + +int ui_core_highlight_element(struct element *elm, int yes); + +void ui_core_element_on_focus(struct element *elm, int yes); + + +void ui_core_ontouch_lose_focus(struct element *elm); + +void ui_core_ontouch_lock(struct element *elm); + +void ui_core_ontouch_unlock(struct element *elm); + +int ui_core_get_draw_context(struct draw_context *dc, struct element *elm, struct rect *draw); +#endif + + + diff --git a/include_lib/system/ui/ui/ui_grid.h b/include_lib/system/ui/ui/ui_grid.h new file mode 100644 index 0000000..aab744f --- /dev/null +++ b/include_lib/system/ui/ui/ui_grid.h @@ -0,0 +1,149 @@ +#ifndef UI_GRID_H +#define UI_GRID_H + + +#include "ui/ui_core.h" +#include "ui/control.h" + +enum { + GRID_SCROLL_MODE, + GRID_PAGE_MODE, +}; + +enum { + SCROLL_DIRECTION_NONE, + SCROLL_DIRECTION_LR, + SCROLL_DIRECTION_UD, +}; + +struct ui_grid_item_info { + u8 row; + u8 col; + u8 page_mode; + u8 highlight_index; + u16 interval; + struct layout_info *info; +}; + +struct scroll_area { + int left; + int top; + int right; + int bottom; +}; + + +struct ui_grid_dynamic { + int dhi_index; + int dcol_num; + int drow_num; + + int min_row_index; + int max_row_index; + int min_col_index; + int max_col_index; + int min_show_row_index; + int max_show_row_index; + int min_show_col_index; + int max_show_col_index; + + int grid_xval; + int grid_yval; + u8 grid_col_num; + u8 grid_row_num; + u8 grid_show_row; + u8 grid_show_col; + int base_index_once; +}; + +struct ui_grid { + struct element elm; + // char hi_num; + char hi_index; + char touch_index; + char onfocus; + u8 page_mode; + u8 slide_direction; + u8 col_num; + u8 row_num; + u8 show_row; + u8 show_col; + u8 avail_item_num; + u8 pix_scroll; + u8 ctrl_num; + // u8 rotate; + int x_interval; + int y_interval; + int max_show_left; + int max_show_top; + int min_show_left; + int min_show_top; + int max_left; + int max_top; + int min_left; + int min_top; + // int scroll_step; + // u8 ctrl_num; + struct scroll_area *area; + struct layout *item; + struct layout_info *item_info; + // struct element elm2; + struct ui_grid_dynamic *dynamic; + struct position pos; + struct draw_context dc; + const struct ui_grid_info *info; + const struct element_event_handler *handler; +}; + +extern const struct element_event_handler grid_elm_handler; + +static inline int ui_grid_cur_item(struct ui_grid *grid) +{ + if (grid->touch_index >= 0) { + return grid->touch_index; + } + return grid->hi_index; +} + +#define ui_grid_set_item(grid, index) (grid)->hi_index = index + +void ui_grid_enable(); +void ui_grid_on_focus(struct ui_grid *grid); +void ui_grid_lose_focus(struct ui_grid *grid); +void ui_grid_state_reset(struct ui_grid *grid, int highlight_item); +int ui_grid_highlight_item(struct ui_grid *grid, int item, bool yes); +int ui_grid_highlight_item_by_id(int id, int item, bool yes); +struct ui_grid *__ui_grid_new(struct element_css1 *css, int id, struct ui_grid_item_info *info, struct element *parent); +int ui_grid_slide(struct ui_grid *grid, int direction, int steps); +int ui_grid_set_item_num(struct ui_grid *grid, int item_num); +int ui_grid_set_slide_direction(struct ui_grid *grid, int dir); +int ui_grid_slide_with_callback(struct ui_grid *grid, int direction, int steps, void(*callback)(void *ctrl)); + +int ui_grid_dynamic_slide(struct ui_grid *grid, int direction, int steps);//动态列表滚动 +int ui_grid_dynamic_create(struct ui_grid *grid, int direction, int list_total, int (*event_handler_cb)(void *, int, int, int)); //动态列表创建 +int ui_grid_dynamic_release(struct ui_grid *grid);//动态列表释放 + +int ui_grid_dynamic_cur_item(struct ui_grid *grid);//动态列表获取选项 +int ui_grid_dynamic_set_item_by_id(int id, int count);//修改动态列表数 +int ui_grid_dynamic_reset(struct ui_grid *grid, int index); //重置动态列表 +void ui_grid_set_scroll_area(struct ui_grid *grid, struct scroll_area *area); + +int ui_grid_init_dynamic(struct ui_grid *grid, int *row, int *col); +int ui_grid_add_dynamic(struct ui_grid *grid, int *row, int *col, int redraw); +int ui_grid_del_dynamic(struct ui_grid *grid, int *row, int *col, int redraw); +int ui_grid_set_hi_index(struct ui_grid *grid, int hi_index); +int ui_grid_set_pix_scroll(struct ui_grid *grid, int enable); +int ui_grid_get_hindex(struct ui_grid *grid); +int ui_grid_set_hindex_dynamic(struct ui_grid *grid, int dhindex, int init, int hi_index); +int ui_grid_get_hindex_dynamic(struct ui_grid *grid); +int ui_grid_set_base_dynamic(struct ui_grid *grid, u32 base_index_once); +// int ui_grid_update_by_id_dynamic(int id, int redraw); +int ui_grid_update_by_id_dynamic(int id, int item_sel, int redraw); +int ui_grid_add_dynamic_by_id(int id, int *row, int *col, int redraw); +int ui_grid_del_dynamic_by_id(int id, int *row, int *col, int redraw); +int ui_grid_cur_item_dynamic(struct ui_grid *grid); + +#endif + + + diff --git a/include_lib/system/ui/ui/ui_number.h b/include_lib/system/ui/ui/ui_number.h new file mode 100644 index 0000000..7cc1a2a --- /dev/null +++ b/include_lib/system/ui/ui/ui_number.h @@ -0,0 +1,44 @@ +#ifndef UI_NUMBER_H +#define UI_NUMBER_H + + +#include "ui/control.h" +#include "ui/ui_core.h" +#include "ui/p.h" + +enum { + TYPE_NUM, + TYPE_STRING, +}; + +struct unumber { + u8 numbs; + u8 type; + u32 number[2]; + u8 *num_str; +}; + +struct ui_number { + struct element_text text; + char source[8]; + u16 number[2]; + u16 buf[20]; + + int color; + int hi_color; + u8 css_num; + u8 nums: 6; + u8 type: 2; + u32 css[2]; + u8 *num_str; + const struct ui_number_info *info; + const struct element_event_handler *handler; +}; + +void ui_number_enable(); +void *new_ui_number(const void *_info, struct element *parent); +int ui_number_update(struct ui_number *number, struct unumber *n); +int ui_number_update_by_id(int id, struct unumber *n); + +#endif + diff --git a/include_lib/system/ui/ui/ui_pic.h b/include_lib/system/ui/ui/ui_pic.h new file mode 100644 index 0000000..38a6463 --- /dev/null +++ b/include_lib/system/ui/ui/ui_pic.h @@ -0,0 +1,30 @@ +#ifndef UI_PIC_H +#define UI_PIC_H + +#include "ui/ui_core.h" + + + + +struct ui_pic { + struct element elm; + u8 index; + // u8 css_num:2; + // u32 css[2]; + // u16 highlight_img; + // u16 normal_img; + // u16 highlight_img_num:8; + // u16 normal_img_num:8; + const struct ui_pic_info *info; + const struct element_event_handler *handler; +}; + +void ui_pic_enable(); +void *new_ui_pic(const void *_info, struct element *parent); +int ui_pic_show_image_by_id(int id, int index); +int ui_pic_set_image_index(struct ui_pic *pic, int index); +int ui_pic_get_normal_image_number_by_id(int id); +int ui_pic_get_highlgiht_image_number_by_id(int id); +int ui_pic_set_hide_by_id(int id, int hide); + +#endif diff --git a/include_lib/system/ui/ui/ui_progress.h b/include_lib/system/ui/ui/ui_progress.h new file mode 100644 index 0000000..1e89f56 --- /dev/null +++ b/include_lib/system/ui/ui/ui_progress.h @@ -0,0 +1,48 @@ +#ifndef UI_PROGRESS_H +#define UI_PROGRESS_H + + +#include "ui/control.h" +#include "ui/ui_core.h" + + +#define PROGRESS_CHILD_NUM (CTRL_PROGRESS_CHILD_END - CTRL_PROGRESS_CHILD_BEGIN) + + +struct progress_highlight_info { + struct ui_ctrl_info_head head; + u16 center_x; + u16 center_y; + u16 radius_big; + u16 radius_small; + u16 angle_begin; + u16 angle_end; + struct ui_image_list *img; +}; + +struct ui_progress { + struct element elm; + struct element child_elm[PROGRESS_CHILD_NUM]; + char source[8]; + u16 center_x; + u16 center_y; + u16 radius; + u16 angle_begin; + u16 angle_end; + u8 ctrl_num; + char percent; + u8 *mask; + u16 mask_len; + void *timer; + const struct layout_info *info; + const struct progress_highlight_info *pic_info[PROGRESS_CHILD_NUM]; + const struct element_event_handler *handler; +}; + +void ui_progress_enable(); +int ui_progress_set_persent_by_id(int id, int persent); +int ui_progress_set_persent(struct ui_progress *progress, int percent); + +#endif + + diff --git a/include_lib/system/ui/ui/ui_progress_multi.h b/include_lib/system/ui/ui/ui_progress_multi.h new file mode 100644 index 0000000..bca15d9 --- /dev/null +++ b/include_lib/system/ui/ui/ui_progress_multi.h @@ -0,0 +1,59 @@ +#ifndef UI_PROGRESS_MULTI_H +#define UI_PROGRESS_MULTI_H + + +#include "ui/control.h" +#include "ui/ui_core.h" + + +#define MULTIPROGRESS_CHILD_NUM (CTRL_MULTIPROGRESS_CHILD_END - CTRL_MULTIPROGRESS_CHILD_BEGIN) + +struct multiprogress_highlight_info { + struct ui_ctrl_info_head head; + u16 number; + u16 center_x; + u16 center_y; + u16 radius0_big; + u16 radius0_small; + u16 radius1_big; + u16 radius1_small; + u16 radius2_big; + u16 radius2_small; + u16 angle_begin; + u16 angle_end; + struct ui_image_list *img; +}; + +struct ui_multiprogress { + struct element elm; + struct element child_elm[MULTIPROGRESS_CHILD_NUM]; + char source[8]; + u16 center_x; + u16 center_y; + u16 radius; + u16 angle_begin; + u16 angle_end; + u8 ctrl_num; + char percent[3]; + u8 circle_num; + u8 index; + u8 *mask; + u16 mask_len; + void *timer; + const struct layout_info *info; + const struct multiprogress_highlight_info *pic_info[MULTIPROGRESS_CHILD_NUM]; + const struct element_event_handler *handler; +}; + +void ui_multiprogress_enable(); +int ui_multiprogress_set_persent_by_id(int id, int persent); +int ui_multiprogress_set_second_persent_by_id(int id, int percent); +int ui_multiprogress_set_third_persent_by_id(int id, int percent); + +int ui_multiprogress_set_persent(struct ui_multiprogress *multiprogress, int percent); +int ui_multiprogress_set_second_persent(struct ui_multiprogress *multiprogress, int percent); +int ui_multiprogress_set_third_persent(struct ui_multiprogress *multiprogress, int percent); + +#endif + + diff --git a/include_lib/system/ui/ui/ui_rotate.h b/include_lib/system/ui/ui/ui_rotate.h new file mode 100644 index 0000000..981f471 --- /dev/null +++ b/include_lib/system/ui/ui/ui_rotate.h @@ -0,0 +1,11 @@ +#ifndef __UI_ROTATE_H__ +#define __UI_ROTATE_H__ + +#include "rect.h" + +void rotate_0(unsigned char *src, unsigned char *src1, int sw, int sh, int cx, int cy, unsigned char *dst, int dw, int dh, int dx, int dy, struct rect *rect, int angle); +void rotate_1(unsigned char *tmp, unsigned char *src, int sw, int sh, int cx, int cy, unsigned char *dst, int dw, int dh, int dx, int dy, struct rect *rect, int angle); +void rotate_map(int sw, int sh, int scx, int scy, int *dw, int *dh, int dcx, int dcy, int angle); + +#endif + diff --git a/include_lib/system/ui/ui/ui_slider.h b/include_lib/system/ui/ui/ui_slider.h new file mode 100644 index 0000000..6dfede0 --- /dev/null +++ b/include_lib/system/ui/ui/ui_slider.h @@ -0,0 +1,43 @@ +#ifndef UI_SLIDER_H +#define UI_SLIDER_H + +#include "ui/ui_core.h" +#include "ui/control.h" + + +#define SLIDER_CHILD_NUM (SLIDER_CHILD_END - SLIDER_CHILD_BEGIN) + + +struct slider_text_info { + u8 move; + int min_value; + int max_value; + int text_color; +}; + + +struct ui_slider { + struct element elm; + struct element child_elm[SLIDER_CHILD_NUM]; + u8 step; + char persent; + s16 left; + s16 width; + s16 min_value; + s16 max_value; + u16 text_color; + const struct ui_slider_info *info; + const struct slider_text_info *text_info; + const struct element_event_handler *handler; +}; + +void ui_slider_enable(); +int ui_slider_set_persent_by_id(int id, int persent); +int ui_slider_set_persent(struct ui_slider *slider, int persent); + +int slider_touch_slider_move(struct ui_slider *slider, struct element_touch_event *e);//触摸滑动功能 + +int slider_get_percent(struct ui_slider *slider); + +#endif + diff --git a/include_lib/system/ui/ui/ui_slider_vert.h b/include_lib/system/ui/ui/ui_slider_vert.h new file mode 100644 index 0000000..7fb7fc0 --- /dev/null +++ b/include_lib/system/ui/ui/ui_slider_vert.h @@ -0,0 +1,41 @@ +#ifndef UI_SLIDER_VERT_H +#define UI_SLIDER_VERT_H + +#include "ui/ui_core.h" +#include "ui/control.h" + +#define VSLIDER_CHILD_NUM (VSLIDER_CHILD_END - VSLIDER_CHILD_BEGIN) + +struct vslider_text_info { + u8 move; + int min_value; + int max_value; + int text_color; +}; + + +struct ui_vslider { + struct element elm; + struct element child_elm[VSLIDER_CHILD_NUM]; + u8 step; + char persent; + s16 top; + s16 height; + u16 min_value; + u16 max_value; + u16 text_color; + const struct ui_slider_info *info; + const struct vslider_text_info *text_info; + const struct element_event_handler *handler; +}; + + +void ui_vslider_enable(); +int ui_vslider_set_persent_by_id(int id, int persent); +int ui_vslider_set_persent(struct ui_vslider *vslider, int persent); + +int vslider_touch_slider_move(struct ui_vslider *vslider, struct element_touch_event *e);//触摸滑动功能 + +int vslider_get_percent(struct ui_vslider *vslider); +#endif + diff --git a/include_lib/system/ui/ui/ui_text.h b/include_lib/system/ui/ui/ui_text.h new file mode 100644 index 0000000..8761121 --- /dev/null +++ b/include_lib/system/ui/ui/ui_text.h @@ -0,0 +1,56 @@ +#ifndef UI_TEXT_H +#define UI_TEXT_H + +#include "ui/ui_core.h" +#include "ui/control.h" +#include "font/font_all.h" + + +struct ui_text { + struct element elm; + struct ui_text_attrs attrs; + char source[8]; + u16 timer; + u16 _str[UI_TEXT_LIST_MAX_NUM]; + char _format[7]; + u8 str_num; + u8 index; + // u8 str_num:4; + // u8 css_num:4; + // u32 css[2]; + // u16 attr_color; + // u16 attr_highlight_color; + // struct ui_text_attrs attrs; + const struct ui_text_info *info; + const struct element_event_handler *handler; +}; + + + +void ui_text_enable(); +void *new_ui_text(const void *_info, struct element *parent); +/*api of format 'ascii'*/ +int ui_text_set_str(struct ui_text *text, const char *format, const char *str, int strlen, u32 flags); +int ui_text_set_str_by_id(int id, const char *format, const char *str); +/*api of format 'strpic'*/ +int ui_text_set_index(struct ui_text *text, int index); +int ui_text_show_index_by_id(int id, int index); +/*api of format 'text'*/ +void ui_text_set_text_attrs(struct ui_text *text, const char *str, int strlen, u8 encode, u8 endian, u32 flags); +int ui_text_set_text_by_id(int id, const char *str, int strlen, u32 flags); +int ui_text_set_textw_by_id(int id, const char *str, int strlen, int endian, u32 flags); +int ui_text_set_textu_by_id(int id, const char *str, int strlen, u32 flags); + +void text_release(struct ui_text *text); +/* + * 注意: + * 1.store_buf必须是全局或者静态,不能是局部,大小为index_num+1 + * 2.index_buf表示当前文本控件字符串id的序号,从0开始 + * 3.index_num表示有多少个字符串id拼起来 + * */ +int ui_text_set_combine_index(struct ui_text *text, u16 *store_buf, u8 *index_buf, int index_num); + + +int ui_text_set_hide_by_id(int id, int hide); + +#endif diff --git a/include_lib/system/ui/ui/ui_time.h b/include_lib/system/ui/ui/ui_time.h new file mode 100644 index 0000000..e9f5bc2 --- /dev/null +++ b/include_lib/system/ui/ui/ui_time.h @@ -0,0 +1,44 @@ +#ifndef UI_TIME_H +#define UI_TIME_H + + +#include "ui/control.h" +#include "ui/ui_core.h" +#include "ui/p.h" + +struct utime { + u16 year; + u8 month; + u8 day; + u8 hour; + u8 min; + u8 sec; +}; + +struct ui_time { + struct element_text text; + char source[8]; + u16 year: 12; + u16 month: 4; + u8 day; + u8 hour; + u8 min; + u8 sec; + u8 css_num; + u8 auto_cnt; + u32 css[2]; + int color; + int hi_color; + u16 buf[20]; + void *timer; + const struct ui_time_info *info; + const struct element_event_handler *handler; +}; + +void ui_time_enable(); +void *new_ui_time(const void *_info, struct element *parent); + +int ui_time_update(struct ui_time *time, struct utime *t); +int ui_time_update_by_id(int id, struct utime *time); + +#endif diff --git a/include_lib/system/ui/ui/ui_watch.h b/include_lib/system/ui/ui/ui_watch.h new file mode 100644 index 0000000..dc8bc2d --- /dev/null +++ b/include_lib/system/ui/ui/ui_watch.h @@ -0,0 +1,52 @@ +#ifndef UI_WATCH_H +#define UI_WATCH_H + + +#include "ui/control.h" +#include "ui/ui_core.h" + + +#define WATCH_CHILD_NUM (CTRL_WATCH_CHILD_END - CTRL_WATCH_CHILD_BEGIN) + + +struct watch_pic_info { + struct ui_ctrl_info_head head; + u16 cent_x; + u16 cent_y; + struct ui_image_list *img; +}; + +struct watch_css_info { + int left: 16; + int top: 16; + int width: 16; + int height: 16; +}; + +struct ui_watch { + struct element elm; + struct element child_elm[WATCH_CHILD_NUM]; + struct watch_css_info child_css[WATCH_CHILD_NUM]; + char source[8]; + u8 hour; + u8 min; + u8 sec; + u8 last_hour; + u8 last_min; + u8 last_sec; + u8 updata; + u8 ctrl_num; + void *timer; + const struct layout_info *info; + const struct watch_pic_info *pic_info[WATCH_CHILD_NUM]; + const struct element_event_handler *handler; +}; + + +void ui_watch_enable(); +int ui_watch_set_time_by_id(int id, int hour, int min, int sec); +int ui_watch_set_time(struct ui_watch *watch, int hour, int min, int sec); + +#endif + + diff --git a/include_lib/system/ui/ui/window.h b/include_lib/system/ui/ui/window.h new file mode 100644 index 0000000..00a417a --- /dev/null +++ b/include_lib/system/ui/ui/window.h @@ -0,0 +1,48 @@ +#ifndef UI_WINDOW_H +#define UI_WINDOW_H + + +#include "ui/layer.h" +#include "ui/ui_core.h" +#include "ui/control.h" +#include "list.h" + + + + + +struct window { + struct element elm; //must be first + u8 busy; + u8 hide; + u8 ctrl_num; + struct list_head entry; + struct layer *layer; + const struct window_info *info; + const struct element_event_handler *handler; + void *private_data; +}; + + +extern const struct window_info *window_table; + + + +#define REGISTER_WINDOW_EVENT_HANDLER(id) \ + REGISTER_UI_EVENT_HANDLER(id) + + +int window_show(int); + +int window_hide(int id); + +int window_toggle(int id); + +int window_ontouch(struct element_touch_event *e); + +int window_onkey(struct element_key_event *e); + + +#endif + + diff --git a/include_lib/system/ui/ui_simple/ui_res.h b/include_lib/system/ui/ui_simple/ui_res.h new file mode 100644 index 0000000..b412b0f --- /dev/null +++ b/include_lib/system/ui/ui_simple/ui_res.h @@ -0,0 +1,128 @@ +/******************************************************************************************* + File Name: ap_res.h + + Version: 1.00 + + Discription: + + Author:yulin deng + + Email :flowingfeeze@163.com + + Date:星期三, 六月 22 2011 + + Copyright:(c) 2011 @ , All Rights Reserved. +*******************************************************************************************/ +#ifndef __ap_res_h +#define __ap_res_h +#include "typedef.h" + +/****************************************************************** + ************************资源头的数据结构*************************** + 资源结构: + 资源头 res_head + ------------------------------------------ + 资源目录项 res_head_Item1(picture Item head) + res_head_Item2(string Item head) + res_head_Item3(multi-string Item head) + ------------------------------------------ + 资源索引表 res_entry1(picture 1) + ................ + res_entryN(picture N) + res_entry1(lang 1) + ................ + res_entryN(lang N) + -------------------------------------------- + 资源数据 picture data 1 + ................ + picture data N + Lang ID 1 entry + ................ + Lang ID N entry + Lang 1 string data + ................ + Lang N string data + ******************************************************************/ +#define RESHEADITEM 16 //各个entry长度,统一为16uint8s +#define GROUPDEFINE 6 +#define ROW_COUNT_DEF 6 +#define TYPE_DIR 0 +#define TYPE_FILE 1 + + +#ifndef uint8 +#define uint8 u8 +#endif +#ifndef uint16 +#define uint16 u16 +#endif +#ifndef uint32 +#define uint32 u32 +#endif +#ifndef int32 +#define int32 int +#endif + + + + +typedef struct { + uint8 magic[4]; //'R', 'U', '2', 0x19 + uint16 counts; //资源的个数 +} res_head_t; //6 uint8s + + +/*资源类型索引表的数据结构*/ +typedef struct { + uint32 dwOffset; //资源内容索引表的偏移 + uint16 wCount; //资源类型总数 + uint8 bItemType; //'P'--PIC Table,'S'--String Table,'X' -- XML File + uint8 type; +} res_entry_t; + +/*资源内容信息索引的数据结构*/ +typedef struct { + uint16 wWidth; //若是图片,则代表图片宽,若是字符串,则代表ID总数 + uint16 wHeight; //若是图片,则代表图片长,若是字符串,则代表该语言的ID. + uint32 bType; //资源类型,0x01--language string ,0x02--PIC + uint32 dwOffset; //图片数据区在文件内偏移,4 uint8s + uint32 dwLength; //资源长度, 最大 4G,4 uint8s +} res_infor_t; //13 uint8s + + +/*多国语言资源ID索引表的数据结构*/ +typedef struct { + uint32 dwOffset; // 字符ID号对应字符串编码在文件内的偏移 + uint16 dwLength; // 字符串长度.即unicode编码字符串的字节数 +} res_langid_entry_t; // 6 uint8s + +typedef struct { + uint8 filetype; //文件类型 0-- 目录 1 文件 + char name[12]; + int32 DirEntry; +} file_record_m; + +// extern res_entry_t res_entry; +u8 ResOpen(const char *filename); +void *ResGetFp(); +uint16 ResShowPic(uint16 pic_id, uint8 x, uint8 y); +uint16 ResShowMultiString(uint8 x, uint8 y, uint16 StringID); +void ResClose(); +u8 InitRes(); + + + + +#define LCDPAGE 8 +#define LCDCOLUMN 128 +#define SCR_WIDTH LCDCOLUMN +#define SCR_HEIGHT (LCDPAGE*8) + +#define MENUICONWIDTH 12 //菜单项目左边图标的宽度(象素) +#define MENUITEMHEIGHT 16 //菜单项目的高度(象素) +#define SCROLLBARWIDTH 6 //垂直滚动条的宽度(象素) + +extern u8 LCDBuff[LCDPAGE][LCDCOLUMN]; + + +#endif diff --git a/include_lib/system/user_cfg.h b/include_lib/system/user_cfg.h new file mode 100644 index 0000000..429a29a --- /dev/null +++ b/include_lib/system/user_cfg.h @@ -0,0 +1,122 @@ +#ifndef __USER_CFG_H__ +#define __USER_CFG_H__ + +#include "typedef.h" +#include "app_config.h" + +#define LOCAL_NAME_LEN 32 /*BD_NAME_LEN_MAX*/ + +//bt bin结构 +typedef struct __BT_CONFIG { + u8 edr_name[LOCAL_NAME_LEN]; //经典蓝牙名 + u8 mac_addr[6]; //蓝牙MAC地址 + u8 rf_power; //发射功率 + u8 dac_analog_gain; //通话DAC模拟增益 + u8 mic_analog_gain; //通话MIC增益 + u16 tws_device_indicate; /*设置对箱搜索标识,inquiry时候用,搜索到相应的标识才允许连接*/ + u8 tws_local_addr[6]; + u8 ble_name[LOCAL_NAME_LEN]; //ble蓝牙名 + u8 ble_mac_addr[6]; //ble蓝牙MAC地址 + u8 ble_rf_power; //ble发射功率 +} _GNU_PACKED_ BT_CONFIG; + +//audio bin结构 +typedef struct __AUDIO_CONFIG { + u8 sw; + u8 max_sys_vol; //最大系统音量 + u8 default_vol; //开机默认音量 + u8 tone_vol; //提示音音量 +} _GNU_PACKED_ AUDIO_CONFIG; + +//status bin结构体 +typedef struct __STATUS { + u8 charge_start; //开始充电 + u8 charge_full; //充电完成 + u8 power_on; //开机 + u8 power_off; //关机 + u8 lowpower; //低电 + u8 max_vol; //最大音量 + u8 phone_in; //来电 + u8 phone_out; //去电 + u8 phone_activ; //通话中 + u8 bt_init_ok; //蓝牙初始化完成 + u8 bt_connect_ok; //蓝牙连接成功 + u8 bt_disconnect; //蓝牙断开 + u8 tws_connect_ok; //TWS连接成功 + u8 tws_disconnect; //TWS蓝牙断开 +} _GNU_PACKED_ STATUS; + +typedef struct __STATUS_CONFIG { + u8 sw; + STATUS led; //led status + STATUS tone; //tone status +} _GNU_PACKED_ STATUS_CONFIG; + +//charge bin结构 +typedef struct __CHARGE_CONFIG { + u8 sw; //开关 + u8 poweron_en; //支持开机充电 + u8 full_v; //充满电压 + u8 full_c; //充满电流 + u8 charge_c; //充电电流 +} _GNU_PACKED_ CHARGE_CONFIG; + +//key +typedef struct __KEY_OP { + u8 short_msg; //短按消息 + u8 long_msg; //长按消息 + u8 hold_msg; //hold 消息 + u8 up_msg; //抬键消息 + u8 double_msg; //双击消息 + u8 triple_msg; //三击消息 +} _GNU_PACKED_ KEY_OP; + +//mic type +typedef struct __MIC_TYPE_CONFIG { + u8 type; //0:不省电容模式 1:省电容模式 + //1:16K 2:7.5K 3:5.1K 4:6.8K 5:4.7K 6:3.5K 7:2.9K 8:3K 9:2.5K 10:2.1K 11:1.9K 12:2K 13:1.8K 14:1.6K 15:1.5K 16:1K 31:0.6K + u8 pull_up; + //00:2.3v 01:2.5v 10:2.7v 11:3.0v + u8 ldo_lev; +} _GNU_PACKED_ MIC_TYPE_CONFIG; + + + +//自动关机时间配置 +typedef struct __AUTO_OFF_TIME_CONFIG { + u8 auto_off_time; +} _GNU_PACKED_ AUTO_OFF_TIME_CONFIG; + +//低电压提示配置 +typedef struct __AUTO_LOWPOWER_V_CONFIG { + u16 warning_tone_v; + u16 poweroff_tone_v; +} _GNU_PACKED_ AUTO_LOWPOWER_V_CONFIG; + +//LRC配置 +typedef struct __LRC_CONFIG { + u16 lrc_ws_inc; + u16 lrc_ws_init; + u16 btosc_ws_inc; + u16 btosc_ws_init; + u8 lrc_change_mode; +} _GNU_PACKED_ LRC_CONFIG; + +void cfg_file_parse(u8 idx); +const u8 *bt_get_mac_addr(); +void bt_get_tws_local_addr(u8 *addr); + +STATUS *get_led_config(void); +STATUS *get_tone_config(void); +void get_random_number(u8 *ptr, u8 len); +extern void bt_get_vm_mac_addr(u8 *addr); +extern u8 get_max_sys_vol(void); +extern const char *bt_get_local_name(); +extern u16 bt_get_tws_device_indicate(u8 *tws_device_indicate); +const char *bt_get_local_name(); +extern void bt_update_mac_addr(u8 *addr); +extern void bt_set_local_name(char *name, u8 len); +extern void bt_reset_and_get_mac_addr(u8 *addr); +extern void bt_set_pair_code_en(u8 en); + +#endif diff --git a/include_lib/system/wait.h b/include_lib/system/wait.h new file mode 100644 index 0000000..63e0911 --- /dev/null +++ b/include_lib/system/wait.h @@ -0,0 +1,16 @@ +#ifndef WAIT_COMPLETION_H +#define WAIT_COMPLETION_H + + + + + +int wait_completion_schedule(); + +u16 wait_completion(int (*condition)(void), int (*callback)(void *), void *priv); + +int wait_completion_del(u16 id); + + + +#endif diff --git a/include_lib/update/dual_bank_updata_api.h b/include_lib/update/dual_bank_updata_api.h new file mode 100644 index 0000000..acd7bfc --- /dev/null +++ b/include_lib/update/dual_bank_updata_api.h @@ -0,0 +1,71 @@ +#ifndef _DUAL_BANK_API_H_ +#define _DUAL_BANK_API_H_ + +/* @brief:Api for getting the buffer size for temporary storage + */ +u32 get_dual_bank_passive_update_max_buf(void); + +/* @brief:Initializes the update task,and setting the crc value and file size of new fw; + * @param fw_crc:crc value of new fw file + * @param fw_size:total size of new fw file + * @param priv:reserved + * @param max_ptk_len: Supported maxium length of every programming,it decides the max size of programming every time + */ +u32 dual_bank_passive_update_init(u32 fw_crc, u32 fw_size, u16 max_pkt_len, void *priv); + +/* @brief:exit the update task + * @param priv:reserved + */ +u32 dual_bank_passive_update_exit(void *priv); + +/* @brief:Judge whether enough space for new fw file + * @note: it should be called after dual_bank_passive_update_init(...); + * @param fw_size:fw size of new fw file + */ +u32 dual_bank_update_allow_check(u32 fw_size); + + +/* @brief:copy the data to temporary buffer and notify task to write non-volatile storage + * @param data:the pointer to download data + * @param len:the length to download data + * @param write_complete_cb:callback for programming done,return 0 if no err occurred +*/ +u32 dual_bank_update_write(void *data, u16 len, int (*write_complete_cb)(void *priv)); + +/* @brief: caculate all the data had flashed,and compare with the cre value intializeed when update init; + * @crc_init_hdl:if it equals NULL,use internal implementation(CRC16-CCITT Standard);otherwise,use user's customization; + * @crc_calc_hdl:if it equals NULL,use internal implementation(CRC16-CCITT Standard);otherwise,use user's customization; + * @verify_result_hdl:when the verification completed,this callback for result notification; + * if crc_res equals 1,crc verification passed,if 0,the verification failed. +*/ +u32 dual_bank_update_verify(void (*crc_init_hdl)(void), u32(*crc_calc_hdl)(u32 init_crc, u8 *data, u32 len), int (*verify_result_hdl)(int crc_res)); + + +/* @brief:After the new fw verification succeed,call this api to program the new boot info for new fw + * @param burn_boot_info_result_hdl:this callback for error notification + * if err equals 0,the operate to burn boot info succeed,other value means to fail. + */ +u32 dual_bank_update_burn_boot_info(int (*burn_boot_info_result_hdl)(int err)); + +enum { + + CLEAR_APP_RUNNING_BANK = 0, + CLEAR_APP_UPDATE_BANK, +}; + +/* @brief:this api for erasing the boot info of specific bank,it should be called much carefully + * @param type:it decides which bank's boot info would be erased; + * clean the boot info of running bank and call system_reset,system will run the other bank if available; + */ +int flash_update_clr_boot_info(u8 type); + +/* @brief:this api for user read flash data to calculate crc + * @param offset: the offset relative to update area + read_buf: user data buffer + read_len: read length + @returns: Actual read length + */ +u32 dual_bank_update_read_data(u32 offset, u8 *read_buf, u32 read_len); + +#endif + diff --git a/include_lib/update/uart_update.h b/include_lib/update/uart_update.h new file mode 100644 index 0000000..b247e4e --- /dev/null +++ b/include_lib/update/uart_update.h @@ -0,0 +1,43 @@ +#ifndef _UART_DEV_ +#define _UART_DEV_ + +#include "typedef.h" + +#define MSG_UART_UPDATE_READY 0x1 +#define MSG_UART_UPDATE_START 0x2 +#define MSG_UART_UPDATE_START_RSP 0X3 +#define MSG_UART_UPDATE_READ_RSP 0x4 + +#define PROTOCAL_SIZE 528 +#define SYNC_SIZE 6 +#define SYNC_MARK0 0xAA +#define SYNC_MARK1 0x55 + +typedef union { + u8 raw_data[PROTOCAL_SIZE + SYNC_SIZE]; + struct { + u8 mark0; + u8 mark1; + u16 length; + u8 data[PROTOCAL_SIZE + 2]; //最后CRC16 + } data; +} protocal_frame_t; + +struct file_info { + u8 cmd; + u32 addr; + u32 len; +} __attribute__((packed)); + +typedef struct __update_io { + u16 rx; + u16 tx; + u8 input_channel; //input channel选择,根据方案选择未被使用的channel + u8 output_channel; //同input channel +} uart_update_cfg; + +void uart_update_init(uart_update_cfg *cfg); +void sava_uart_update_param(void); + +#endif + diff --git a/include_lib/update/update.h b/include_lib/update/update.h new file mode 100644 index 0000000..1cd3cae --- /dev/null +++ b/include_lib/update/update.h @@ -0,0 +1,161 @@ +#ifndef _UPDATE_H_ +#define _UPDATE_H_ + +#include "typedef.h" + +extern u32 UPDATA_BEG; + +#define UPDATA_FLAG_ADDR ((void *)((u32)&UPDATA_BEG + 0x08)) +#define BOOT_STATUS_ADDR ((void *)((u32)&UPDATA_BEG)) //预留8个bytes + +#define UPDATA_MAGIC (0x5A00) //防止CRC == 0 的情况 + +typedef enum { + UPDATA_NON = UPDATA_MAGIC, + UPDATA_READY, + UPDATA_SUCC, + UPDATA_PARM_ERR, + UPDATA_DEV_ERR, + UPDATA_KEY_ERR, +} UPDATA_RESULT; + +typedef enum { + USB_UPDATA = UPDATA_MAGIC, //0x5A00 + SD0_UPDATA, //0x5A01 + SD1_UPDATA, + PC_UPDATA, + UART_UPDATA, + BT_UPDATA, + BLE_APP_UPDATA, + SPP_APP_UPDATA, + DUAL_BANK_UPDATA, + BLE_TEST_UPDATA, + NORFLASH_UPDATA, + //NOTE:以上的定义不要调整,新升级方式在此添加,注意加在USER_NORFLASH_UFW_UPDATA之前; + USER_NORFLASH_UFW_UPDATA, + + NON_DEV = 0xFFFF, +} UPDATA_TYPE; + +// sd +enum { + SD_CONTROLLER_0 = 1, + SD_CONTROLLER_1, +}; +enum { + SD0_IO_A = 1, + SD0_IO_B, + SD1_IO_A, + SD1_IO_B, + SD0_IO_C, + SD0_IO_D, + SD0_IO_E, + SD0_IO_F, +}; +typedef struct _UPDATA_SD { + u8 control_type; + u8 control_io; + u8 online_check_way; + u8 max_data_baud; + u16 wDevTimeOutMax; + u8 per_online_status; + u8 hc_mode; + u8(*io_det_func)(void); + u8 power; + u8 control_io_clk; + u8 control_io_cmd; + u8 control_io_dat; +} UPDATA_SD; + +// uart +typedef struct _UPDATA_UART { + u32 control_io_tx; // 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; +} + + diff --git a/include_lib/update/update_loader_download.h b/include_lib/update/update_loader_download.h new file mode 100644 index 0000000..f14f9e6 --- /dev/null +++ b/include_lib/update/update_loader_download.h @@ -0,0 +1,197 @@ +#ifndef _UPDATE_LOADER_DOWNLOAD_H_ +#define _UPDATE_LOADER_DOWNLOAD_H_ + +#include "typedef.h" + +extern const int config_update_mode; +extern const int support_dual_bank_update_en; +#define UPDATE_MODULE_IS_SUPPORT(x) (config_update_mode & x) +#define UPDATE_SUPPORT_DEV_IS_NULL() (config_update_mode == UPDATE_DEV_NULL) +#define UPDATE_DUAL_BANK_IS_SUPPORT() (1 == support_dual_bank_update_en) + +struct __tws_ota_para { + u32 fm_size; + u32 fm_crc; + u16 max_pkt_len; +}; + +typedef struct _ret_code { + int stu; + u8 err_code; +} update_ret_code_t; + +typedef struct _update_op_api_tws { + //for tws ota start + int (*tws_ota_start)(void *priv); + int (*tws_ota_data_send)(u8 *buf, u16 len); + int (*tws_ota_err)(u8); + u16(*enter_verfiy_hdl)(void *priv); + u16(*exit_verify_hdl)(u8 *, u8 *); + u16(*update_boot_info_hdl)(void *priv); + int (*tws_ota_result_hdl)(u8); + int (*tws_ota_data_send_pend)(void); + //for user chip update + int (*tws_ota_user_chip_update_send)(u8 cmd, u8 *buf, u16 len); +} update_op_tws_api_t; //给tws同步升级用的接口 + +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)); +void update_start_exit_sniff(void); +void set_ota_status(u8 status); + +typedef struct _update_op_api_t { + void (*ch_init)(void (*resume_hdl)(void *priv), int (*sleep_hdl)(void *priv)); + u16(*f_open)(void); + u16(*f_read)(void *fp, u8 *buff, u16 len); + int (*f_seek)(void *fp, u8 type, u32 offset); + u16(*f_stop)(u8 err); + int (*notify_update_content_size)(void *priv, u32 size); + void (*ch_exit)(void *priv); +} update_op_api_t; + +extern const update_op_api_t lmp_ch_update_op; +extern const update_op_api_t strg_ch_update_op; +extern const update_op_api_t rcsp_update_op; + +#define UPDATE_SEAGNMENT_EN 1 + +enum { + UPDATE_LOADER_OK = 1, + UPDATE_LOADER_ERR, +}; + +enum { + PKT_FLAG_MIDDLE = 0, + PKT_FLAG_FIRST, + PKT_FLAG_LAST, +}; + +//update result code bitmap +#define UPDATE_RESULT_FLAG_BITMAP BIT(7) + +//update result code; +enum { + UPDATE_RESULT_ERR_NONE = 0, + UPDATE_RESULT_FILE_SIZE_ERR = 0x1, //文件大小错误 + UPDATE_RESULT_LOADER_SIZE_ERR = 0x2, //loader大小错误 + UPDATE_RESULT_LOADER_VERIFY_ERR, //update loader校验失败 + UPDATE_RESULT_REMOTE_FILE_HEAD_ERR, //读升级文件头错误 + + UPDATE_RESULT_LOCAL_FILE_HEAD_ERR = 0x5, //读flash文件头错误 + UPDATE_RESULT_NOT_FIND_TARGET_FILE_ERR, //找不到目标文件(ota.bin找不到对应loader) + UPDATE_RESULT_FILE_OPERATION_ERR, //文件操作失败 + UPDATE_RESULT_FLASH_DATA_VERIFY_ERR, //flash数据校验失败 + + UPDATE_RESULT_UBOOT_NOT_MATCH = 0x09, //UBOOT不匹配 + UPDATE_RESULT_PRODUCT_INFO_NOT_MATCH = 0x0a, //芯片型号不匹配 + UPDATE_RESULT_EX_DSP_UPDATE_ERR, //外部IC升级出错; + UPDATE_RESULT_CFG_UPDATE_ERR, //配置升级出错 + + UPDATE_RESULT_FLASH_ERASE_ERR = 0x0d, //flash 擦失败(可能是写保护) + UPDATE_RESULT_REMOTE_FILE_NOT_MATCH, //升级文件不匹配 + UPDATE_RESULT_ANC_CFG_UPDATE_ERR, //ANC配置升级出错 + UPDATE_RESULT_ANC_COEF_UPDATE_ERR = 0x10, //ANC配置升级出错 + UPDATE_RESULT_OTA_TWS_NO_RSP, //对耳同步升级传输数据没有回复 + UPDATE_RESULT_RESOURCE_LIMIT, //资源不足 + UPDATE_RESULT_OTA_TWS_START_ERR, //对耳启动升级失败 + UPDATE_RESULT_OTA_TWS_CRC_ERROR, //对耳校验失败 + UPDATE_RESULT_OTA_APP_EXIT = 0x15, //升级过程APP强制退出 + UPDATE_RESULT_TWS_NO_CONNECT, //对耳未连接 + UPDATE_RESULT_READ_REMOTE_FILE_ERR, //读取不到远端数据 + UPDATE_RESULT_UFW_FLASH_HEAD_CRC_ERR, //校验远端文件里的FLASH_HEAD失败 + UPDATE_RESULT_UFW_CODE_HEAD_CRC_ERR, //校验远端文件里的APP_CODE_HEAD失败 + UPDATE_RESULT_UFW_ALGIN_OF_OFFSET_MATCH_ERR, //升级文件中找不到和本地对齐和偏移方式一致的文件 + UPDATE_RESULT_UFW_CANNOT_FIND_VM_AREA, //升级文件中找不到vm区域信息 + UPDATE_RESULT_LOADER_HEAD_CRC_ERR, //校验LOADER_HEAD失败,检查ota.bin前面数据是否为00 + UPDATE_RESULT_LOADER_WRITE_ERR, //写loader失败 + UPDATE_RESULT_DUALBANK_GET_UFW_APP_HEAD_ERR, //双备份获取远端APP_head失败 + UPDATE_RESULT_DUALBANK_GET_LOCAL_APP_HEAD_ERR, //双备份获取本地APP_head失败 + UPDATE_RESULT_DUALBANK_APP_HEAD_NOT_MATCH, //双备份本地和远端APP分解线不匹配 +}; + +#include "system/task.h" +typedef struct _update_type_info_t { + int type; + u8 task_en; + void (*cb)(void *priv, int type, u8 cmd); + void *cb_priv; + update_op_api_t *p_op_api; + void (*common_state_cbk)(int type, u32 status, u32 code); + OS_SEM update_sem; +} update_type_info_t; + +typedef struct _update_mode_info_t { + s32 type; + void (*state_cbk)(int type, u32 status, void *priv); + const update_op_api_t *p_op_api; + u8 task_en; +} update_mode_info_t; + +typedef struct _succ_report_t { + u32 loader_saddr; + u32 priv_param; + u32(*update_param_write_hdl)(u32 priv, u8 *buf, u16 len); +} succ_report_t; + +#define UPDATE_DEV_NULL 0 +#define UPDATE_BT_LMP_EN BIT(0) +#define UPDATE_STORAGE_DEV_EN BIT(1) +#define UPDATE_UART_EN BIT(2) +#define UPDATE_APP_EN BIT(3) //包括APP升级还有其他升级方式,如串口升级(非测试盒方式) +#define UPDATE_BLE_TEST_EN BIT(4) + +typedef struct _user_chip_update_t { + u8 *file_name; + int (*update_init)(void *priv, update_op_api_t *file_ops); + int (*update_get_len)(void); + int (*update_loop)(void *priv); +} user_chip_update_t; + +typedef struct _user_chip_info_t { + union { + struct { + u32 file_addr; + }; + struct { + u32 addr; + }; + }; + u32 len; + u16 crc; + u32 dev_addr; +} user_chip_update_info_t; + +typedef struct _update_size_t { + u8 type; +} update_type_t; + +enum UPDATE_SIZE_TYPE { + UPDATE_LEN_TYPE_CONTENT = 0, + UPDATE_LEN_TYPE_LOADER, + UPDATE_LEN_TYPE_EX_IC, +}; + +void register_user_chip_update_handle(const user_chip_update_t *user_update_ins); +void rcsp_update_loader_download_init(int update_type, void (*result_cbk)(void *priv, u8 type, u8 cmd)); + +int app_active_update_task_init(update_mode_info_t *info); +int update_file_verify(u32 ufw_addr, u16(*ufw_read)(void *buf, u32 addr, u32 len)); + +//==========================================================// +// 获取升级进度信息 // +//注意: 只有双备份升级可以获取该信息 // +//==========================================================// +typedef struct _update_percent_info { + u32 total_len; //固件总升级大小 + u32 finish_len; //当前完成升级大小 + u32 percent; //当前进度百分比 +} update_percent_info; + +//注册升级进度更新回调函数: +void register_update_percent_info_callback_handle(void (*handle)(update_percent_info *info)); + +//查询当前升级进度信息: +void update_percent_info_query(update_percent_info *info); + +#endif /*_UPDATE_LOADER_DOWNLOAD_H_*/ + diff --git a/tools/make_prompt.bat b/tools/make_prompt.bat new file mode 100644 index 0000000..e42893f --- /dev/null +++ b/tools/make_prompt.bat @@ -0,0 +1,5 @@ +SET SCRIPT_PATH=%~dp0% +set PATH=%SCRIPT_PATH%\utils;%PATH% + +cd .. +cmd diff --git a/tools/package_release.py b/tools/package_release.py new file mode 100644 index 0000000..b586101 --- /dev/null +++ b/tools/package_release.py @@ -0,0 +1,637 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +############################################################################### +# @file package_release.py +# @brief 根据当前开发工程自动生成客户交付 Release 工程 +# @author cyWu <1917507415@qq.com> +# @date 2026.08.04 +# @version V1.0.0 +# @history +# - V1.0.0, 2026.08.04, cyWu, 首次发布 +# - V1.0.1, 2026.08.04, cyWu, 产物统一输出到 release/ 目录 +# - V1.0.2, 2026.08.05, cyWu, 交付包命名改为 JBao_JL7016_SOC_SDK_Vx.x.x +# +# 使用方式(在项目根或任意目录): +# python tools/package_release.py +# +# 约束: +# - 仅使用 Python 标准库 +# - 所有删除 / 过滤 / 复制只作用于 Release 副本 +# - 绝不修改开发工程业务源码、Makefile、build_lib.bat、CodeBlocks 工程 +############################################################################### + +from __future__ import annotations + +import fnmatch +import os +import re +import shutil +import sys +import zipfile +from datetime import datetime +from pathlib import Path +from typing import Dict, Iterable, List, Set + + +# ============================================================================= +# 可配置区域(集中管理,扩展模块只改这里) +# ============================================================================= + +# 版本文件(相对项目根) +VERSION_FILE = "version.txt" + +# Release 输出根目录(相对项目根,产物全部放这里) +RELEASE_OUTPUT_DIR = "release" + +# Release 命名规则 +RELEASE_DIR_PREFIX = "JBao_JL7016_SOC_SDK_V" +RELEASE_ZIP_SUFFIX = ".zip" +README_NAME = "JBao_JL7016_SOC_SDK_README.md" + +# 工程展示名称(写入 README) +PROJECT_DISPLAY_NAME = "AC701N Earphone SDK" +CHIP_DISPLAY_NAME = "AC7016C(BR28)" + +# 复制时跳过的目录名(任意层级) +SKIP_DIR_NAMES: Set[str] = { + ".git", + ".vscode", + ".idea", + "objs", + "obj", + "__pycache__", + RELEASE_OUTPUT_DIR, # 不把已有交付产物拷进新包 +} + +# 复制时跳过的根目录文件(仅项目根下,不进客户包) +SKIP_ROOT_FILES: Set[str] = { + ".gitignore", + "version.txt", +} + +# 复制时跳过的文件通配(任意层级,按文件名匹配) +SKIP_FILE_PATTERNS: List[str] = [ + "*.o", + "*.d", + "*.dep", + "*.obj", + "*.bak", + "*.log", + "*.tmp", + "*.temp", + "*.swp", + "*.swo", + "*.orig", + "*.rej", + "*.pyc", + "*.layout", + "*.depend", + "Thumbs.db", + ".DS_Store", +] + +# 复制时跳过的路径前缀(相对项目根,防自复制嵌套) +SKIP_PATH_PREFIXES: List[str] = [ + RELEASE_OUTPUT_DIR, + "Release_Project_V", # 兼容旧版曾放在项目根的产物 + "JBao_JL7016_SOC_SDK_V", # 兼容曾放在项目根的新命名产物 +] + +# --------------------------------------------------------------------------- +# 需要封装交付的模块配置 +# --------------------------------------------------------------------------- +# public_headers : 保留的公开头文件(仅文件名,相对模块根或子目录中同名匹配) +# remove_patterns : 删除的源码通配(递归) +# remove_internal_headers : True 时删除非 public_headers 的所有 .h/.hpp +# prune_empty_dirs : 清理后删除空目录 +# remove_extra : 额外删除的相对路径(相对模块根) +# keep_extra : 额外强制保留的相对路径(文件或目录,相对模块根) +# --------------------------------------------------------------------------- +MODULE_CONFIG: Dict[str, dict] = { + "apps/usr_le_code": { + "public_headers": [ + "usr_le_api.h", + "usr_le_product.h", + ], + "remove_patterns": [ + "*.c", + "*.cpp", + "*.cc", + ], + "remove_internal_headers": True, + "prune_empty_dirs": True, + "remove_extra": [ + "build_lib.bat", + ], + "keep_extra": [ + "lib/", + ], + }, +} + + +# ============================================================================= +# 路径管理 +# ============================================================================= + +def get_project_root() -> Path: + """ + @brief 由脚本位置推导项目根目录(tools/ 的上一级) + @return 项目根 Path + """ + return Path(__file__).resolve().parent.parent + + +def read_version(project_root: Path) -> str: + """ + @brief 读取 version.txt + @param project_root 项目根 + @return 版本号字符串,例如 "1.0.0" + """ + version_path = project_root / VERSION_FILE + if not version_path.is_file(): + raise FileNotFoundError(f"version file not found: {version_path}") + + version = version_path.read_text(encoding="utf-8").strip() + if not version: + raise ValueError(f"version file is empty: {version_path}") + + # 简单校验:不允许路径分隔符,避免生成非法目录名 + if any(ch in version for ch in ("/", "\\", "..")): + raise ValueError(f"invalid version string: {version!r}") + + return version + + +def get_release_paths(project_root: Path, version: str) -> dict: + """ + @brief 统一生成 Release 相关路径(均位于 release/ 下) + @param project_root 项目根 + @param version 版本号 + @return 含 output_dir / dir / zip / readme 的字典 + """ + dir_name = f"{RELEASE_DIR_PREFIX}{version}" + output_dir = project_root / RELEASE_OUTPUT_DIR + release_dir = output_dir / dir_name + release_zip = output_dir / f"{dir_name}{RELEASE_ZIP_SUFFIX}" + readme_path = release_dir / README_NAME + return { + "dir_name": dir_name, + "output_dir": output_dir, + "release_dir": release_dir, + "release_zip": release_zip, + "readme_path": readme_path, + } + + +# ============================================================================= +# 复制过滤 +# ============================================================================= + +def _match_any(name: str, patterns: Iterable[str]) -> bool: + """ + @brief 判断文件名是否匹配任一通配符 + """ + return any(fnmatch.fnmatch(name, pat) for pat in patterns) + + +def should_skip_path(rel_path: Path) -> bool: + """ + @brief 判断相对项目根的路径在复制时是否应跳过 + @param rel_path 相对路径 + @return True=跳过 + """ + parts = rel_path.parts + if not parts: + return False + + # 跳过项目根下指定文件(如 .gitignore / version.txt) + if len(parts) == 1 and parts[0] in SKIP_ROOT_FILES: + return True + + # 跳过指定目录名(任意层级) + for part in parts: + if part in SKIP_DIR_NAMES: + return True + + # 跳过 Release 产物路径(防嵌套) + rel_posix = rel_path.as_posix() + for prefix in SKIP_PATH_PREFIXES: + if rel_posix == prefix.rstrip("/") or rel_posix.startswith(prefix): + return True + + # 跳过匹配的文件名 + if _match_any(rel_path.name, SKIP_FILE_PATTERNS): + return True + + # 跳过已有 zip 包(根目录下) + if len(parts) == 1 and rel_path.name.endswith(RELEASE_ZIP_SUFFIX): + if rel_path.name.startswith(RELEASE_DIR_PREFIX): + return True + + return False + + +def copy_project(project_root: Path, release_dir: Path) -> int: + """ + @brief 过滤复制整工程到 Release 目录 + @param project_root 开发工程根 + @param release_dir 目标 Release 目录 + @return 复制的文件数量 + """ + copied = 0 + + for root, dirs, files in os.walk(project_root): + root_path = Path(root) + rel_root = root_path.relative_to(project_root) + + # 就地过滤子目录,避免继续向下遍历 + keep_dirs: List[str] = [] + for d in dirs: + candidate = rel_root / d if str(rel_root) != "." else Path(d) + if should_skip_path(candidate): + continue + keep_dirs.append(d) + dirs[:] = keep_dirs + + # 目标目录 + dst_root = release_dir if str(rel_root) == "." else release_dir / rel_root + dst_root.mkdir(parents=True, exist_ok=True) + + for name in files: + rel_file = rel_root / name if str(rel_root) != "." else Path(name) + if should_skip_path(rel_file): + continue + + src = root_path / name + dst = dst_root / name + shutil.copy2(src, dst) + copied += 1 + + return copied + + +# ============================================================================= +# 模块清理(仅作用于 Release 副本) +# ============================================================================= + +def _is_under_keep_extra(rel_posix: str, keep_extra: List[str]) -> bool: + """ + @brief 判断模块内相对路径是否属于 keep_extra 保护范围 + """ + for keep in keep_extra: + keep_norm = keep.replace("\\", "/").rstrip("/") + if not keep_norm: + continue + # 目录保护:keep 以 / 结尾或配置为目录前缀 + if rel_posix == keep_norm or rel_posix.startswith(keep_norm + "/"): + return True + # 兼容配置写成 "lib/" 的情况已在上方处理 + if keep.endswith("/") and (rel_posix == keep_norm or rel_posix.startswith(keep_norm + "/")): + return True + return False + + +def _prune_empty_dirs(module_dir: Path) -> int: + """ + @brief 自底向上删除空目录 + @return 删除的空目录数量 + """ + removed = 0 + # 深度优先:按路径长度降序 + all_dirs = sorted( + (p for p in module_dir.rglob("*") if p.is_dir()), + key=lambda p: len(p.parts), + reverse=True, + ) + for d in all_dirs: + try: + if not any(d.iterdir()): + d.rmdir() + removed += 1 + except OSError: + pass + return removed + + +def clean_module(release_dir: Path, module_rel: str, cfg: dict) -> dict: + """ + @brief 按配置清理单个封装模块(仅 Release 内) + @param release_dir Release 根目录 + @param module_rel 模块相对路径,如 apps/usr_le_code + @param cfg MODULE_CONFIG 中的单项配置 + @return 统计信息字典 + """ + module_dir = release_dir / module_rel + stats = { + "module": module_rel, + "removed_sources": 0, + "removed_headers": 0, + "removed_extra": 0, + "pruned_dirs": 0, + "missing": False, + } + + if not module_dir.is_dir(): + stats["missing"] = True + print(f"[WARN] module not found in Release: {module_rel}") + return stats + + public_headers: Set[str] = set(cfg.get("public_headers", [])) + remove_patterns: List[str] = list(cfg.get("remove_patterns", [])) + remove_internal_headers: bool = bool(cfg.get("remove_internal_headers", True)) + prune_empty_dirs: bool = bool(cfg.get("prune_empty_dirs", True)) + remove_extra: List[str] = list(cfg.get("remove_extra", [])) + keep_extra: List[str] = list(cfg.get("keep_extra", [])) + + # 1) 删除匹配 remove_patterns 的源文件 + for path in list(module_dir.rglob("*")): + if not path.is_file(): + continue + rel = path.relative_to(module_dir).as_posix() + if _is_under_keep_extra(rel, keep_extra): + continue + if _match_any(path.name, remove_patterns): + path.unlink() + stats["removed_sources"] += 1 + + # 2) 删除非公开头文件 + if remove_internal_headers: + header_patterns = ["*.h", "*.hpp"] + for path in list(module_dir.rglob("*")): + if not path.is_file(): + continue + if not _match_any(path.name, header_patterns): + continue + rel = path.relative_to(module_dir).as_posix() + if _is_under_keep_extra(rel, keep_extra): + continue + # 公开头文件按“文件名”匹配,便于配置只写文件名 + if path.name in public_headers: + continue + path.unlink() + stats["removed_headers"] += 1 + + # 3) 删除额外指定文件/目录 + for extra in remove_extra: + target = module_dir / extra + if not target.exists(): + continue + if target.is_dir(): + shutil.rmtree(target) + else: + target.unlink() + stats["removed_extra"] += 1 + + # 4) 清理空目录 + if prune_empty_dirs: + stats["pruned_dirs"] = _prune_empty_dirs(module_dir) + + return stats + + +def clean_all_modules(release_dir: Path) -> List[dict]: + """ + @brief 遍历 MODULE_CONFIG 清理所有模块 + """ + results = [] + for module_rel, cfg in MODULE_CONFIG.items(): + print(f"[INFO] cleaning module: {module_rel}") + results.append(clean_module(release_dir, module_rel, cfg)) + return results + + +def sanitize_release_makefile(release_dir: Path) -> None: + """ + @brief 调整 Release 副本中的 Makefile:仅链接预编译 libusr_le_code.a + 开发工程 Makefile 不动;客户包不得再尝试用已删除源码重建库 + @param release_dir Release 根目录 + """ + makefile = release_dir / "Makefile" + if not makefile.is_file(): + print("[WARN] Makefile not found in Release, skip sanitize") + return + + text = makefile.read_text(encoding="utf-8") + + # 1) 去掉源码列表与 OBJS,仅保留预编译库路径 + text2, n1 = re.subn( + r"# usr_le_code 静态库[^\n]*\n" + r"USR_LE_LIB := apps/usr_le_code/lib/libusr_le_code\.a\n" + r"USR_LE_SRC_FILES := \\\n" + r"(?:[ \t]+apps/usr_le_code/[^\n]+\n)+" + r"\n" + r"USR_LE_OBJS :=[^\n]+\n", + "# usr_le_code 预编译静态库(Release 不附带协议源码,禁止本地重建)\n" + "USR_LE_LIB := apps/usr_le_code/lib/libusr_le_code.a\n" + "\n", + text, + count=1, + ) + if n1 == 0: + raise RuntimeError("sanitize Makefile failed: USR_LE_SRC_FILES block not found") + + # 2) .PHONY 去掉 lib_usr_le + text2, n2 = re.subn( + r"\.PHONY:\s*all clean pre_build lib_usr_le\b", + ".PHONY: all clean pre_build", + text2, + count=1, + ) + if n2 == 0: + # 兼容顺序变化,尽量剥离 lib_usr_le + text2 = re.sub(r"\s+lib_usr_le\b", "", text2, count=1) + + # 3) 删除 lib_usr_le 目标与 $(USR_LE_LIB): $(USR_LE_OBJS) 重建规则 + # 保留 all / OUT_ELF 对 $(USR_LE_LIB) 的依赖:库文件已存在即可链接 + text2, n3 = re.subn( + r"\n# 单独编译 usr_le_code 静态库:[^\n]*\n" + r"lib_usr_le:[^\n]*\n" + r"\n" + r"\$\(USR_LE_LIB\): \$\(USR_LE_OBJS\)\n" + r"(?:[ \t]+[^\n]+\n)+", + "\n", + text2, + count=1, + ) + if n3 == 0: + raise RuntimeError("sanitize Makefile failed: lib_usr_le rebuild rule not found") + + makefile.write_text(text2, encoding="utf-8") + print("[INFO] sanitized Release Makefile (prebuilt libusr_le_code.a only)") + + +# ============================================================================= +# README / ZIP +# ============================================================================= + +def write_readme(readme_path: Path, version: str, module_stats: List[dict]) -> None: + """ + @brief 生成 JBao_JL7016_SOC_SDK_README.md + @param readme_path README 路径 + @param version 版本号 + @param module_stats 模块清理统计(用于目录说明) + """ + now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + lines: List[str] = [ + f"# {PROJECT_DISPLAY_NAME}", + "", + "## 基本信息", + "", + f"- 工程名称:{PROJECT_DISPLAY_NAME}", + f"- 版本号:V{version}", + f"- 生成时间:{now}", + f"- 适用芯片:{CHIP_DISPLAY_NAME}", + "", + "## 目录说明", + "", + "```", + f"{RELEASE_DIR_PREFIX}{version}/", + "├── apps/", + "│ ├── common/ # SDK 公共模块", + "│ ├── earphone/ # 耳机应用", + "│ ├── usr_jb_proto/ # 应用协议层", + "│ ├── usr_periph/ # 板级外设(RTC 等,源码开放)", + "│ └── usr_le_code/ # BLE 协议库(库文件 + 公开头文件)", + "├── cpu/ # 芯片相关代码与工具", + "├── include_lib/ # SDK 头文件", + "├── tools/ # 工程工具", + "├── Makefile", + "├── AC701N.cbp", + f"└── {README_NAME}", + "```", + "", + "### 封装模块公开接口", + "", + ] + + for module_rel, cfg in MODULE_CONFIG.items(): + public_headers = cfg.get("public_headers", []) + lines.append(f"**{module_rel}**") + lines.append("") + lines.append(f"- 静态库:`{module_rel}/lib/`") + lines.append("- 公开头文件:") + for h in public_headers: + lines.append(f" - `{module_rel}/{h}`") + lines.append("") + + lines.append("---") + lines.append("") + lines.append("*本文件由 tools/package_release.py 自动生成。*") + lines.append("") + + readme_path.write_text("\n".join(lines), encoding="utf-8") + + +def make_zip(release_dir: Path, release_zip: Path) -> None: + """ + @brief 将 Release 目录压缩为 zip(与目录同级) + @param release_dir Release 目录 + @param release_zip 目标 zip 路径 + """ + if release_zip.exists(): + release_zip.unlink() + + with zipfile.ZipFile(release_zip, "w", compression=zipfile.ZIP_DEFLATED) as zf: + for path in release_dir.rglob("*"): + if path.is_file(): + arcname = path.relative_to(release_dir.parent) + zf.write(path, arcname.as_posix()) + + +# ============================================================================= +# 主流程 +# ============================================================================= + +def remove_old_release(release_dir: Path, release_zip: Path) -> None: + """ + @brief 删除已有同名 Release 目录与 zip + """ + if release_dir.exists(): + print(f"[INFO] remove old release dir: {release_dir.name}") + shutil.rmtree(release_dir) + + if release_zip.exists(): + print(f"[INFO] remove old release zip: {release_zip.name}") + release_zip.unlink() + + +def main() -> int: + """ + @brief Release 打包主入口 + @return 进程退出码,0=成功 + """ + try: + project_root = get_project_root() + version = read_version(project_root) + paths = get_release_paths(project_root, version) + + release_dir: Path = paths["release_dir"] + release_zip: Path = paths["release_zip"] + readme_path: Path = paths["readme_path"] + dir_name: str = paths["dir_name"] + + print("=" * 60) + print(" AC701N Release Package Tool") + print("=" * 60) + output_dir: Path = paths["output_dir"] + + print(f"[INFO] project root : {project_root}") + print(f"[INFO] version : {version}") + print(f"[INFO] output dir : {RELEASE_OUTPUT_DIR}/") + print(f"[INFO] release dir : {RELEASE_OUTPUT_DIR}/{dir_name}") + print() + + # 确保 release/ 输出目录存在 + output_dir.mkdir(parents=True, exist_ok=True) + + # ① 删除旧产物 + remove_old_release(release_dir, release_zip) + + # ② 过滤复制 + print("[INFO] copying project ...") + copied = copy_project(project_root, release_dir) + print(f"[INFO] copied files : {copied}") + + # ③ 模块清理(仅 Release 副本) + print("[INFO] cleaning encapsulated modules ...") + module_stats = clean_all_modules(release_dir) + for st in module_stats: + if st["missing"]: + continue + print( + f" - {st['module']}: " + f"src={st['removed_sources']}, " + f"hdr={st['removed_headers']}, " + f"extra={st['removed_extra']}, " + f"empty_dirs={st['pruned_dirs']}" + ) + + # ④ Release Makefile:禁止用已删除源码重建库(开发工程 Makefile 不动) + print("[INFO] sanitizing Release Makefile ...") + sanitize_release_makefile(release_dir) + + # ⑤ README + print("[INFO] writing README ...") + write_readme(readme_path, version, module_stats) + + # ⑥ ZIP + print("[INFO] creating zip ...") + make_zip(release_dir, release_zip) + + print() + print("=" * 60) + print("[OK] Release package generated successfully") + print(f" dir : {release_dir}") + print(f" zip : {release_zip}") + print("=" * 60) + return 0 + + except Exception as exc: + print(f"[FAIL] {exc}", file=sys.stderr) + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/utils/[.exe b/tools/utils/[.exe new file mode 100644 index 0000000..c71fba5 Binary files /dev/null and b/tools/utils/[.exe differ diff --git a/tools/utils/do_merge_libs.bat b/tools/utils/do_merge_libs.bat new file mode 100644 index 0000000..091500e --- /dev/null +++ b/tools/utils/do_merge_libs.bat @@ -0,0 +1,18 @@ +@echo off +setlocal enabledelayedexpansion +set INDIR=%1% +set MERGE=%2% +set AROUT=%3% + +echo %INDIR% +echo %MERGE% +echo %AROUT% + +set FILES= + +for /f "tokens=*" %%i in ('dir /b %INDIR%\*.a') DO SET FILES=!FILES! %INDIR%\%%i + +echo %FILES% + +%MERGE% --no-rewrite --output %AROUT% %FILES% + diff --git a/tools/utils/find.exe b/tools/utils/find.exe new file mode 100644 index 0000000..85192fb Binary files /dev/null and b/tools/utils/find.exe differ diff --git a/tools/utils/fixbat.exe b/tools/utils/fixbat.exe new file mode 100644 index 0000000..e6280d2 Binary files /dev/null and b/tools/utils/fixbat.exe differ diff --git a/tools/utils/libiconv2.dll b/tools/utils/libiconv2.dll new file mode 100644 index 0000000..747073f Binary files /dev/null and b/tools/utils/libiconv2.dll differ diff --git a/tools/utils/libintl3.dll b/tools/utils/libintl3.dll new file mode 100644 index 0000000..ec11e6b Binary files /dev/null and b/tools/utils/libintl3.dll differ diff --git a/tools/utils/ls.exe b/tools/utils/ls.exe new file mode 100644 index 0000000..96ff2e5 Binary files /dev/null and b/tools/utils/ls.exe differ diff --git a/tools/utils/make.exe b/tools/utils/make.exe new file mode 100644 index 0000000..17bfc2e Binary files /dev/null and b/tools/utils/make.exe differ diff --git a/tools/utils/merge-archives.exe b/tools/utils/merge-archives.exe new file mode 100644 index 0000000..07e1a2b Binary files /dev/null and b/tools/utils/merge-archives.exe differ diff --git a/tools/utils/mkdir_win.exe b/tools/utils/mkdir_win.exe new file mode 100644 index 0000000..f96d181 Binary files /dev/null and b/tools/utils/mkdir_win.exe differ diff --git a/tools/utils/override-seg.exe b/tools/utils/override-seg.exe new file mode 100644 index 0000000..3e759e2 Binary files /dev/null and b/tools/utils/override-seg.exe differ diff --git a/tools/utils/rm.exe b/tools/utils/rm.exe new file mode 100644 index 0000000..8e79306 Binary files /dev/null and b/tools/utils/rm.exe differ diff --git a/tools/utils/true.exe b/tools/utils/true.exe new file mode 100644 index 0000000..cb41f82 Binary files /dev/null and b/tools/utils/true.exe differ diff --git a/tools/utils/uname.exe b/tools/utils/uname.exe new file mode 100644 index 0000000..3e2f4cf Binary files /dev/null and b/tools/utils/uname.exe differ