aboutsummaryrefslogtreecommitdiff
path: root/platform/atm2/ATM22xx-x1x/examples/HID_remote
diff options
context:
space:
mode:
Diffstat (limited to 'platform/atm2/ATM22xx-x1x/examples/HID_remote')
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/HID_remote.c27
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/makefile380
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/pinmap/pinmap_m2231_overlay.h34
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/power_coin_none.mk5
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/rc_test_mode.mk3
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/app_config.h366
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/atvrc_custom.c253
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/atvrc_custom.h139
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/atvrc_porting.h29
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_att.c176
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_att.h24
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_audio.c245
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_audio.h147
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_fms.c74
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_fms.h25
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_ir.c120
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_ir.h90
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_timer.c88
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/refdesignrcu.h49
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_atvv.c365
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_atvv.h129
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_gap.h127
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_hidau.h93
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_hogp.h55
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_ota.h22
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_test_mode.h92
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/uuid.h65
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/non_bt/rc_ir.c273
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/non_bt/rc_ir.h59
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/non_bt/rc_keycode.h157
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/non_bt/rc_pdm.h95
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi.c730
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi.h146
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi_vkey.c751
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi_vkey.h50
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi_vkey_m2231.h59
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/01-BD_ADDRESS/user.tds1
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/02-DEVICE_NAME/remote.tds2
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/0d-EXT_WAKEUP_TIME/no_32KHz_xtal.tds1
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/0e-OSC_WAKEUP_TIME/no_32KHz_xtal.tds1
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/11-SLEEP_ENABLE/hib.tds8
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/12-EXT_WAKEUP_ENABLE/enable2.tds4
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/2b-SLEEP_ADJ/no_32KHz_xtal.tds1
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/C1-ATVRC_CUSTOM_DATA/g10.tds53
-rw-r--r--platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/C2-ATVRC_NEC_IR_OVERRIDE/default.tds49
45 files changed, 5662 insertions, 0 deletions
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/HID_remote.c b/platform/atm2/ATM22xx-x1x/examples/HID_remote/HID_remote.c
new file mode 100644
index 0000000..dee755d
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/HID_remote.c
@@ -0,0 +1,27 @@
+/**
+ *******************************************************************************
+ *
+ * @file HID_Remote.c
+ *
+ * @brief HID remote controller
+ *
+ * Copyright (C) Atmosic 2020-2021
+ *
+ *******************************************************************************
+ */
+#include "arch.h"
+#include "rc_mmi.h"
+
+static rep_vec_err_t rc_init(void)
+{
+ rc_mmi_init();
+
+ return RV_DONE;
+}
+
+int main(void)
+{
+ RV_APPM_INIT_ADD_LAST(rc_init);
+
+ return 0;
+}
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/makefile b/platform/atm2/ATM22xx-x1x/examples/HID_remote/makefile
new file mode 100644
index 0000000..30646bd
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/makefile
@@ -0,0 +1,380 @@
+################################################################################
+#
+# @file makefile
+#
+# @brief HID remote controller
+#
+# Copyright (C) Atmosic 2021-2023
+#
+################################################################################
+
+include ../../user/common.mk
+
+DEBUG := 1
+PROFILES := OTAPS DISS BASS HOGPD
+FRAMEWORK_MODULES := \
+ app_batt \
+ app_bass \
+ app_diss \
+ atm_adv \
+ atm_adv_param \
+ atm_asm \
+ atm_common \
+ atm_debug \
+ atm_gap \
+ atm_log \
+ ble_bass \
+ ble_diss \
+ ble_gap \
+ ble_gap_sec \
+ ble_hogpd \
+ ble_otaps \
+
+DRIVERS := \
+ atm_ble \
+ atm_gpio \
+ atm_pm \
+ atm_vkey \
+ batt_model \
+ gadc \
+ interrupt \
+ keyboard \
+ led_blink \
+ pdm \
+ sw_event \
+ sw_timer \
+ trng \
+
+OVERLAY_FILE ?= pinmap_$(BOARD)_overlay.h
+CFLAGS += -DPINMAP_$(BOARD)_OVERLAY="$(OVERLAY_FILE)"
+
+ifdef FLASHROM
+UU_TEST := HID_remote
+endif
+
+ifdef CFG_ATVRC
+CFG_ATVRC_FULL_FEAT := 1
+LPC_RCOS := 1
+FORCE_LPC_RCOS := 1
+BOARD := m2231
+endif
+
+ifdef CFG_ATVRC_BF
+CFG_ATVRC_FULL_FEAT := 1
+BOARD := m3231
+PV_HARV_EN := 1
+endif
+
+ifdef CFG_ATVRC_FULL_FEAT
+CFG_RC_IR := 1
+CFG_ATVRC_ATT := 1
+ifndef CFG_ATVRC_ATM_AUDIO
+CFG_ATVRC_AUDIO := 1
+endif
+CFG_ATVRC_CUSTOM := 1
+CFG_ATVRC_UNI_IR := 1
+CFG_ATVRC_NEC_IR_OVERRIDE := 1
+CFG_ATVRC_WAKEUP := 1
+
+ifdef USE_LIB
+REF_DESIGN_RCU_DIR := ../../../../..
+else
+REF_DESIGN_RCU_DIR := ../../../../../contrib/refDesignRcu
+endif
+SRC_ATVRC := src/atvrc
+INCLUDES += $(REF_DESIGN_RCU_DIR) $(SRC_ATVRC)
+CFLAGS += -DCFG_ATM_SDK -DCFG_VKEY_BUF -DCFG_OTA_SPEEDUP -DCFG_GAP_MAX_LL_MTU=247
+endif
+
+ifdef CFG_ATVRC_ATT
+FRAMEWORK_MODULES += atm_prfs ble_atmprfs
+CFLAGS += -DCFG_ATVRC_ATT
+ATVRC_C_SRCS += \
+ $(REF_DESIGN_RCU_DIR)/vendor/827x_ble_remote/app_att.c \
+ $(SRC_ATVRC)/bridge_att.c \
+ $(SRC_ATVRC)/bridge_timer.c \
+
+endif
+
+ifdef CFG_ATVRC_UNI_IR
+CFLAGS += -DCFG_ATVRC_UNI_IR
+C_SRCS += $(DRIVER_DIR)/ir/uni_ir.c
+ATVRC_C_SRCS += \
+ $(REF_DESIGN_RCU_DIR)/vendor/827x_ble_remote/app_ir.c \
+ $(SRC_ATVRC)/bridge_ir.c \
+
+endif
+
+ifdef CFG_ATVRC_CUSTOM
+CFLAGS += -DCFG_ATVRC_CUSTOM -DCFG_FLEX_VKEY_MAP
+ATVRC_C_SRCS += $(SRC_ATVRC)/atvrc_custom.c
+flash_nvds.data += C1-ATVRC_CUSTOM_DATA/g10
+endif
+
+ifdef CFG_ATVRC_NEC_IR_OVERRIDE
+CFLAGS += -DCFG_NEC_IR_OVERRIDE -DIR_DATA_CONST=
+flash_nvds.data += C2-ATVRC_NEC_IR_OVERRIDE/default
+endif
+
+ifdef CFG_ATVRC_WAKEUP
+CFLAGS += -DCFG_ATVRC_WAKEUP
+endif
+
+ifdef CFG_ATVRC_FIND_ME
+DRIVERS += buzzer
+CFLAGS += -DCFG_ATVRC_FIND_ME
+ATVRC_C_SRCS += \
+ $(REF_DESIGN_RCU_DIR)/vendor/827x_ble_remote/app_find_me/app_fms.c \
+ $(REF_DESIGN_RCU_DIR)/vendor/827x_ble_remote/app_find_me/app_imc.c \
+ $(SRC_ATVRC)/bridge_fms.c \
+
+endif
+
+ifneq (,$(filter -DAUTO_TEST,$(CFLAGS)))
+CFLAGS += -DCFG_PDM_LOCAL_TEST -DSW_TIMER_ID_MAX=13
+else
+ifdef CFG_ATVRC_ATT
+CFLAGS += -DSW_TIMER_ID_MAX=15
+else
+CFLAGS += -DSW_TIMER_ID_MAX=12
+endif
+endif
+
+SRC_TOP = src
+SRC_NONBT = src/non_bt
+SRC_BT = src/bt
+
+# Voice setting
+# HID_MSBC: mSBC over HID
+# HID_ADPCM: ADPCM over HID
+# otherwise: ADPCM over ATVV
+PDM_ADPCM := 1
+ifeq ($(CFG_VOICE),HID_MSBC)
+CFLAGS += -DCFG_VOHID -DCFG_PDM_MSBC -DCFG_PDM_INTP_TABLE_ALLOC
+C_SRCS += $(SRC_BT)/rc_hidau.c $(SRC_NONBT)/sbc_enc_wrapper.c
+override PDM_ADPCM :=
+ifdef FLASHROM
+UU_TEST += sbc_enc_wrapper rc_hidau
+endif
+
+else ifeq ($(CFG_VOICE),HID_ADPCM)
+CFLAGS += -DCFG_VOHID
+C_SRCS += $(SRC_BT)/rc_hidau.c
+
+ifdef FLASHROM
+UU_TEST += rc_hidau
+endif
+
+else # CFG_VOICE
+
+ifdef CFG_ATVRC_AUDIO
+CFLAGS += -DCFG_ATVRC_AUDIO
+ATVRC_C_SRCS += \
+ $(REF_DESIGN_RCU_DIR)/application/audio/gl_audio.c \
+ $(SRC_ATVRC)/bridge_audio.c \
+ $(SRC_BT)/rc_atvv.c \
+
+else
+C_SRCS += $(SRC_BT)/rc_atvv.c
+FRAMEWORK_MODULES += ble_atvvs
+PROFILES += ATVVS
+endif
+
+ifndef CFG_ATVV_VER_004
+CFLAGS += -DCFG_ATVV_VER_100
+endif
+
+ifdef CFG_ATVV_ASST_MODEL
+CFLAGS += -DCFG_ATVV_ASST_MODEL=$(CFG_ATVV_ASST_MODEL)
+endif
+
+ifdef CFG_RF_TEST
+CFLAGS += -DCFG_RF_TEST
+endif
+
+ifdef FLASHROM
+UU_TEST += rc_atvv
+endif
+
+endif # CFG_VOICE
+
+ifdef FLASHROM
+ifndef CFG_PDM_INTP_DISABLE
+UU_TEST += pdm_intp
+endif
+ifdef PDM_ADPCM
+UU_TEST += adpcm_enc
+endif
+endif # FLASHROM
+
+# power plan:
+# power_coin_none.mk
+# power_cone_pv.mk
+# power_hsc_3v3_pv.mk
+# power_hsc_3v8_pv.mk
+CFG_RC_POWER_FILE ?= power_coin_none.mk
+
+ifeq ($(wildcard $(CFG_RC_POWER_FILE)),)
+$(error $(CFG_RC_POWER_FILE) doesn't exist. Use one of [\
+ $(wildcard power*.mk)])
+endif
+
+include $(CFG_RC_POWER_FILE)
+
+ifneq (,$(filter m2202 m3202,$(BOARD)))
+VKEY_MAP_CFG := x202
+FLASH_SIZE = 0x80000
+# Keyboard, IR, PDM and LED
+CFLAGS += \
+ -DLED_UART_MUX \
+
+else ifneq (,$(filter m2221 m3221,$(BOARD)))
+VKEY_MAP_CFG := default
+ifndef FLASHROM
+FLASH_SIZE = 0x40000
+endif
+
+else ifneq (,$(filter m2231 m3231,$(BOARD)))
+VKEY_MAP_CFG := $(BOARD)
+ifndef FLASHROM
+ifdef PUYA_2MB
+FLASH_SIZE = 0x20000
+NVDS_SIZE = 4096
+else
+FLASH_SIZE = 0x40000
+endif
+endif
+OTA_DISCON_BEFORE_REBOOT := 1
+CFLAGS += \
+ -DCFG_ATVRC_MMI \
+ -DNUM_LEDS=2 \
+
+else ifneq (,$(filter x2xx_emu,$(BOARD)))
+VKEY_MAP_CFG := default
+ifndef FLASHROM
+FLASH_SIZE = 0x40000
+endif
+
+else
+$(error "usage: make $(MAKECMDGOALS) \
+ BOARD=<m2202|m3202|m2221|m3221|m2231|m3231>")
+endif
+
+CFLAGS += -DVKEY_MAP_FILE=rc_mmi_vkey_$(VKEY_MAP_CFG).h
+
+ifdef PV_HARV_EN
+$(error "PV_HARV_EN deprecated. Please use CFG_RC_POWER_FILE)
+endif
+
+ifdef CFG_RC_IR
+DRIVERS += ir timer
+C_SRCS += $(DRIVER_DIR)/ir/nec_ir.c $(DRIVER_DIR)/ir/ir_ctl.c
+ifdef CFG_ATVRC_UNI_IR
+ATVRC_C_SRCS += $(SRC_NONBT)/rc_ir.c
+else
+C_SRCS += $(SRC_NONBT)/rc_ir.c
+endif
+ifdef FLASHROM
+UU_TEST += rc_ir nec_ir ir_ctl
+endif
+# disable ATM_SLWTIMER, isr conflicts with pdm
+CFLAGS += \
+ -DCFG_RC_IR \
+ -DCFG_DIS_ATM_SLWTIMER \
+ -DATM_DUAL_TIMER_OVERRIDE_PRI=IRQ_PRI_RT \
+
+ifdef CFG_RC_IR_ON_HID
+CFLAGS += -DCFG_RC_IR_ON_HID
+endif # CFG_RC_IR_ON_HID
+endif
+
+ifdef CFG_ATVRC_FULL_FEAT
+EXCLUDE_APP_LIB_C_SRCS := $(ATVRC_C_SRCS)
+endif
+
+# Keyboard
+CFLAGS += -DCFG_KBD -DKSI_PULLUPS
+
+# Feature: ghostkey filter
+ifdef CFG_EN_GHOSTKEY
+CFLAGS += -DCFG_EN_GHOSTKEY
+DRIVERS += keyboard_ghostkey
+endif
+
+ifdef CFG_GHOSTKEY_MAX_DETECT
+CFLAGS += -DCFG_GHOSTKEY_MAX_DETECT=$(CFG_GHOSTKEY_MAX_DETECT)
+endif
+
+# BT
+CFLAGS += \
+ -DNO_ATM_SCAN \
+ -DNO_GAP_SEC_PASSKEY \
+ -DNO_GAP_SEC_NC \
+ -DCFG_GAP_PARAM_CONST=0 \
+ -DCFG_S_MAX_ENTRY=2 \
+ -DBLE_MSG_HANDLER_LIST_SIZE=10 \
+ -DCFG_RC_BIG_MTU \
+ -DCFG_RC_SLAVE_PARAM_NEGO \
+
+ifneq (,$(filter -DCFG_RC_BIG_MTU,$(CFLAGS)))
+FRAMEWORK_MODULES += ble_gattc
+else
+CFLAGS += -DNO_BLE_GATTC
+endif
+
+INCLUDES += \
+ $(SRC_TOP) \
+ $(SRC_BT) \
+ $(SRC_NONBT) \
+
+# define the files would not include to $(APP).a
+EXCLUDE_APP_LIB_C_SRCS += \
+ $(SRC_TOP)/rc_mmi.c \
+ $(SRC_TOP)/rc_mmi_vkey.c \
+
+ifdef FLASHROM
+UU_TEST += rc_mmi rc_mmi_vkey
+endif
+
+# Others would include to $(APP).a
+# Application : Non-BT part
+C_SRCS += \
+ $(SRC_NONBT)/rc_pdm.c \
+
+CFLAGS += \
+ -DCFG_ADV_DATA_PARAM_CONST=0 \
+
+ifdef FLASHROM
+UU_TEST += rc_pdm
+endif
+
+# Application: BT part
+C_SRCS += \
+ $(SRC_BT)/rc_gap.c \
+ $(SRC_BT)/rc_ota.c \
+ $(SRC_BT)/rc_hogp.c \
+
+ifdef FLASHROM
+UU_TEST += rc_gap rc_ota rc_hogp
+endif
+
+C_SRCS += $(EXCLUDE_APP_LIB_C_SRCS)
+
+CFLAGS += \
+ -DGAP_PARM_NAME="app_config.h" \
+ -DGAP_ADV_PARM_NAME="app_config.h" \
+ -DGAP_SCAN_PARM_NAME="app_config.h" \
+ -DAPP_VERSION=\"1.0.0.0\" \
+
+flash_nvds.data += \
+ 02-DEVICE_NAME/remote \
+ 11-SLEEP_ENABLE/hib \
+ 12-EXT_WAKEUP_ENABLE/enable2 \
+
+ifdef NO_BROWNOUT
+CFLAGS += -DCFG_RC_NO_BROWNOUT
+endif
+include rc_test_mode.mk
+include $(COMMON_USER_DIR)/profiles.mk
+include $(COMMON_USER_DIR)/framework.mk
+
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/pinmap/pinmap_m2231_overlay.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/pinmap/pinmap_m2231_overlay.h
new file mode 100644
index 0000000..fb481d8
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/pinmap/pinmap_m2231_overlay.h
@@ -0,0 +1,34 @@
+/*
+ * This file should be auto-generated using a tool that consumes the pin
+ * selections in the JSON file
+ */
+
+#define PIN_PDM_POWER_SWITCH 22
+#define PIN_LPCOMP_IO 11
+#define PIN_LED0 27
+#define PIN_LED1 28
+#define PIN_IR_IO 26
+#ifdef CFG_ATVRC_FIND_ME
+#define PIN_BUZZER_IO 26 // IR LED
+// #define PIN_BUZZER_IO 27 // GREEN LED
+#endif
+#define PIN_ROW0 23
+#define PIN_ROW1 22
+#define PIN_ROW2 21
+#define PIN_ROW3 13
+#define PIN_ROW4 6
+#define PIN_COL0 29
+#define PIN_COL1 28
+#define PIN_COL2 9
+#define PIN_COL3 8
+#define PIN_COL4 7
+#define ROW0_KSI 0
+#define ROW1_KSI 1
+#define ROW2_KSI 2
+#define ROW3_KSI 6
+#define ROW4_KSI 13
+#define COL0_KSO 2
+#define COL1_KSO 3
+#define COL2_KSO 10
+#define COL3_KSO 11
+#define COL4_KSO 12
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/power_coin_none.mk b/platform/atm2/ATM22xx-x1x/examples/HID_remote/power_coin_none.mk
new file mode 100644
index 0000000..add83b1
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/power_coin_none.mk
@@ -0,0 +1,5 @@
+# PMU configuration
+PMU_CFG := VBAT_GT_1p8V_VDDIO_INT
+
+# battery driver
+DRIVERS += batt_model_coin
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/rc_test_mode.mk b/platform/atm2/ATM22xx-x1x/examples/HID_remote/rc_test_mode.mk
new file mode 100644
index 0000000..e6f34c6
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/rc_test_mode.mk
@@ -0,0 +1,3 @@
+
+CFLAGS += -DCFG_RC_TEST_MODE
+C_SRCS += $(SRC_BT)/rc_test_mode.c
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/app_config.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/app_config.h
new file mode 100644
index 0000000..371c7ef
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/app_config.h
@@ -0,0 +1,366 @@
+/**
+ *******************************************************************************
+ *
+ * @file app_config.h
+ *
+ * @brief Application configuration.
+ *
+ * Copyright (C) Atmosic 2021-2022
+ *
+ *******************************************************************************
+ */
+#pragma once
+
+#include "ble_att.h"
+#include "sw_timer.h"
+
+// Connection Parameters Setting
+// Preferred connection parameter negotiation retry times.
+#ifndef RC_PARAM_NEGO_TIMES
+#define RC_PARAM_NEGO_TIMES 1
+#endif
+// Preferred connection parameter negotiation timeout time.
+#ifndef RC_PARAM_NEGO_TOUT_CS
+#define RC_PARAM_NEGO_TOUT_CS 300
+#endif
+
+// Preferred connection parameter negotiation delay time.
+#ifndef RC_PARAM_NEGO_DELAY_CS
+#define RC_PARAM_NEGO_DELAY_CS 100
+#endif
+
+// Timeout Settings
+
+// Timeout time after HID ready.
+// A timer with this timeout value will be set when link is connected and HID is
+// ready. When this timer occurs, system will disconnect link and go to hibernate.
+// The timer would be reset on any of user input.
+// If this value is zero, the link will always be maintained.
+#ifndef RC_CONN_READY_TOUT_CS
+#define RC_CONN_READY_TOUT_CS 0
+#endif
+
+// Timeout time after connected.
+// A timer with this timeout value will be set when link is connected but HID is
+// not ready. When this timer occurs, system will disconnect link and go to hibernate.
+// This timer will be clear after HID is ready.
+// If this value is zero, the link will always be maintained.
+#ifndef RC_CONN_NOT_READY_TOUT_CS
+#define RC_CONN_NOT_READY_TOUT_CS 0
+#endif
+
+// DISS configuration
+
+// Length of APP_DIS_MANUFACTURER_NAME
+#define APP_DIS_MANUFACTURER_NAME_LEN (sizeof(APP_DIS_MANUFACTURER_NAME) - 1)
+
+// Length of APP_DIS_MANUFACTURER_NAME
+#define APP_DIS_MODEL_NB_STR_LEN (sizeof(APP_DIS_MODEL_NB_STR) - 1)
+
+// Length of APP_DIS_MANUFACTURER_NAME
+#define APP_DIS_SERIAL_NB_STR_LEN (sizeof(APP_DIS_SERIAL_NB_STR) - 1)
+
+// Length of APP_DIS_MANUFACTURER_NAME
+#define APP_DIS_FIRM_REV_STR_LEN (sizeof(APP_DIS_FIRM_REV_STR) - 1)
+
+// Length of APP_DIS_MANUFACTURER_NAME
+#define APP_DIS_SYSTEM_ID_LEN (sizeof(APP_DIS_SYSTEM_ID) - 1)
+
+// Length of APP_DIS_MANUFACTURER_NAME
+#define APP_DIS_HARD_REV_STR_LEN (sizeof(APP_DIS_HARD_REV_STR) - 1)
+
+// Length of APP_DIS_MANUFACTURER_NAME
+#define APP_DIS_SW_REV_STR_LEN (sizeof(APP_DIS_SW_REV_STR) - 1)
+
+// Length of APP_DIS_MANUFACTURER_NAME
+#define APP_DIS_IEEE_LEN (sizeof(APP_DIS_IEEE) - 1)
+
+// Length of APP_DIS_MANUFACTURER_NAME
+#define APP_DIS_PNP_ID_LEN (sizeof(APP_DIS_PNP_ID) - 1)
+
+// Manufacturer Name Value
+#define APP_DIS_MANUFACTURER_NAME "Atmosic Tech."
+
+// Model Number String Value
+#define APP_DIS_MODEL_NB_STR "ATV-RC-01"
+
+// Serial Number
+#define APP_DIS_SERIAL_NB_STR "1.0.0.0"
+
+#ifdef CFG_NONRF_HARV
+// Firmware Revision
+#define APP_DIS_FIRM_REV_STR APP_VERSION"PV"
+// Software Revision String
+#define APP_DIS_SW_REV_STR APP_VERSION"PV"
+#else
+// Firmware Revision
+#define APP_DIS_FIRM_REV_STR APP_VERSION
+// Software Revision String
+#define APP_DIS_SW_REV_STR APP_VERSION
+#endif
+
+// Hardware Revision String
+#define APP_DIS_HARD_REV_STR "1.0.0"
+
+// System ID Value
+#define APP_DIS_SYSTEM_ID "\x12\x34\x56\xFF\xFE\x9A\xBC\xDE"
+
+// IEEE
+#define APP_DIS_IEEE "\xFF\xEE\xDD\xCC\xBB\xAA"
+
+/**
+ * PNP ID Value - LSB -> MSB
+ * Vendor ID Source : 0x01 (bluetooth SIG)
+ * Vendor ID : 0x7545
+ * Product ID : 0x0021
+ * Product Version : 0x0110
+ */
+#define APP_DIS_PNP_ID "\x01\x45\x75\x21\x00\x10\x01"
+
+// Feature enabled
+#define APP_DIS_FEATURES DIS_MANUFACTURER_NAME_CHAR_SUP | \
+ DIS_MODEL_NB_STR_CHAR_SUP | DIS_SERIAL_NB_STR_CHAR_SUP | \
+ DIS_HARD_REV_STR_CHAR_SUP | DIS_FIRM_REV_STR_CHAR_SUP | \
+ DIS_SW_REV_STR_CHAR_SUP | DIS_SYSTEM_ID_CHAR_SUP | \
+ DIS_IEEE_CHAR_SUP | DIS_PNP_ID_CHAR_SUP
+
+// Security level
+#define APP_DIS_SEC_PROPERTY BLE_SEC_PROP_NO_SECURITY
+
+// BASS configuration
+
+// Security level
+#define APP_BASS_SEC_PROPERTY SEC_PROFLE_LEVEL
+
+// OTAP configuration
+
+// OTA board identifier
+#define RC_OTA_BOARD_ID 02
+
+// Atm_gap configuration
+
+// Maximal support BT profiles
+#ifdef CFG_ATVRC_ATT
+#define CFG_GAP_MAX_MODULES 6
+#else
+#define CFG_GAP_MAX_MODULES 5
+#endif
+
+// Appearance Icon
+#define CFG_GAP_APPEARANCE 0x180
+
+// Pairing Mode
+#define CFG_GAP_PAIRING_MODE (BLE_GAP_PAIRING_LEGACY)
+
+// Minimal connection interval
+#define CFG_GAP_CONN_INT_MIN 8
+
+// Maximal connection interval
+#define CFG_GAP_CONN_INT_MAX 8
+
+// Peripheral latency
+#define CFG_GAP_PERIPH_LATENCY 99
+
+// Connection timeout
+#define CFG_GAP_CONN_TIMEOUT 300
+
+// GAP attribute connfiguration
+#ifdef CFG_RC_BIG_MTU
+#define CFG_GAP_ATT_CFG BLE_GAP_ATT_PERIPH_PREF_CON_PAR_EN_MASK \
+ | BLE_GAP_ATT_CLI_AUTO_MTU_EXCH_EN_MASK
+#else
+#define CFG_GAP_ATT_CFG BLE_GAP_ATT_PERIPH_PREF_CON_PAR_EN_MASK
+// Maximal transmit octets
+#define CFG_GAP_MAX_TX_OCTETS BLE_MIN_OCTETS
+// Maximal transmit time
+#define CFG_GAP_MAX_TX_TIME BLE_MIN_TIME
+// Maximize MTU (comply with 4.2)
+#define CFG_GAP_MAX_LL_MTU 247
+#endif
+
+// Atm_adv configuration
+
+// ADV payload - UUID
+#define RC_HID_ADV_DAT_UUID 0x03, 0x03, 0x12, 0x18
+
+// ADV payload - Appearance
+#define RC_HID_ADV_DAT_APPEARANCE 0x03, 0x19, 0x80, 0x01
+
+// ADV payload - Atmosic Vendor Application ID info
+#define RC_HID_ADV_DAT_MANU 0x06, 0xFF, 0x0A, 0x24, 0x01, 0x03, 0x00
+
+// Non constant ADV creation parameter
+#define CFG_ADV_CREATE_PARAM_CONST 0
+
+// Maximal ADV instances
+#ifdef CFG_ATVRC_WAKEUP
+#define CFG_GAP_ADV_MAX_INST 5
+#else
+#define CFG_GAP_ADV_MAX_INST 2
+#endif
+
+// ADV0 configuration (for reconnection)
+
+// Owner address
+#define CFG_ADV0_OWNER_ADDR_TYPE BLE_OWN_STATIC_ADDR
+
+// parameters for creation
+#ifdef CFG_ATVRC_WAKEUP
+#define CFG_ADV0_CREATE_PROPERTY ADV_LEGACY_DIR_CONN_MASK
+#else
+#define CFG_ADV0_CREATE_PROPERTY ADV_LEGACY_DIR_CONN_HDC_MASK
+#endif
+#define CFG_ADV0_CREATE_CHNL_MAP ADV_ALL_CHNLS
+#define CFG_ADV0_CREATE_MAX_TX_POWER 0
+#define CFG_ADV0_CREATE_DISCOVERY_MODE ADV_MODE_NON_DISC
+
+// ADV timeout duration
+#ifdef CFG_ATVRC_WAKEUP
+#define CFG_ADV0_START_DURATION 300
+#else
+#define CFG_ADV0_START_DURATION 12000
+#endif
+
+// ADV data payload
+#define CFG_ADV0_DATA_ADV_PAYLOAD RC_HID_ADV_DAT_UUID, \
+ RC_HID_ADV_DAT_APPEARANCE, RC_HID_ADV_DAT_MANU
+
+// Scan response enabling
+#define CFG_ADV0_DATA_SCANRSP_ENABLE 0
+
+// ADV1 (for pairing)
+
+// Owner address
+#define CFG_ADV1_OWNER_ADDR_TYPE BLE_OWN_STATIC_ADDR
+
+// parameters for creation
+#define CFG_ADV1_CREATE_PROPERTY ADV_LEGACY_UNDIR_CONN_MASK
+#define CFG_ADV1_CREATE_CHNL_MAP ADV_ALL_CHNLS
+#define CFG_ADV1_CREATE_MAX_TX_POWER 0
+#define CFG_ADV1_CREATE_FILTER_POLICY FILTER_SCAN_ANY_CON_ANY
+
+// ADV timeout duration
+#ifdef CFG_ATVRC_MMI
+#define CFG_ADV1_START_DURATION 18000
+#else
+#define CFG_ADV1_START_DURATION 6000
+#endif
+
+#ifdef CFG_ATVRC_WAKEUP
+#define CFG_ADV1_CREATE_DISCOVERY_MODE ADV_MODE_LIM_DISC
+#define UUID_HID 0x12, 0x18
+#define UUID_BATTERY 0x0F, 0x18
+#define RC_SRV_HID_BAT 0x05, 0x02, UUID_HID, UUID_BATTERY
+// ADV data payload
+#define CFG_ADV1_DATA_ADV_PAYLOAD RC_HID_ADV_DAT_APPEARANCE, RC_SRV_HID_BAT
+
+// Scan response enabling
+#define CFG_ADV1_DATA_SCANRSP_ENABLE 0
+
+// Google wake up packet configuration
+#define CFG_ADV2_OWNER_ADDR_TYPE BLE_OWN_STATIC_ADDR
+#define CFG_ADV2_CREATE_TYPE ADV_TYPE_LEGACY
+#define CFG_ADV2_CREATE_PROPERTY ADV_LEGACY_UNDIR_CONN_MASK
+#define CFG_ADV2_CREATE_FILTER_POLICY FILTER_SCAN_ANY_CON_ANY
+#define CFG_ADV2_CREATE_DISCOVERY_MODE ADV_MODE_BEACON
+#define CFG_ADV2_CREATE_CHNL_MAP ADV_ALL_CHNLS
+#define CFG_ADV2_CREATE_PRIM_PHY BLE_GAP_PHY_LE_1MBPS
+#define CFG_ADV2_CREATE_INTERVAL_MIN (ADV_INTERVAL_MIN * 2)
+#define CFG_ADV2_CREATE_INTERVAL_MAX (ADV_INTERVAL_MIN * 2)
+#define CFG_ADV2_CREATE_MAX_TX_POWER 0
+#define CFG_ADV2_CREATE_SEC_MAX_SKIP 0
+#define CFG_ADV2_CREATE_SEC_PHY BLE_GAP_PHY_LE_1MBPS
+#define CFG_ADV2_CREATE_SEC_ADV_SID 0
+#define CFG_ADV2_CREATE_PERI_INTERVAL_MIN 80
+#define CFG_ADV2_CREATE_PERI_INTERVAL_MAX 80
+#define CFG_ADV2_CREATE_PEER_ADDR_TYPE 0
+#define CFG_ADV2_CREATE_PEER_ADDR 0
+
+#define CFG_ADV2_START_DURATION 300
+#define CFG_ADV2_START_MAX_ADV_EVENT 0
+
+#define CFG_ADV2_DATA_ADV_ENABLE 1
+#define CFG_ADV2_DATA_SCANRSP_ENABLE 0
+
+#define UUID_WAKEUP_SRV 0x36, 0xFD
+#define PACKET_FORMAT_VER 0x01
+#define DUMMY_KEY_ID 0xFF
+#define DUMMY_KEY_PRESS_CNT 0xFF
+#define DUMMY_PEER_BD_ADDR 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+
+#define RC_SRV_DATA_WAKEUP_SRV 0x0C, 0x16, UUID_WAKEUP_SRV, PACKET_FORMAT_VER, \
+ DUMMY_KEY_ID, DUMMY_KEY_PRESS_CNT, DUMMY_PEER_BD_ADDR
+#define CFG_ADV2_DATA_ADV_PAYLOAD RC_SRV_DATA_WAKEUP_SRV
+
+// Customized wake up packet configuration
+#define CFG_ADV3_OWNER_ADDR_TYPE BLE_OWN_STATIC_ADDR
+#define CFG_ADV3_CREATE_TYPE ADV_TYPE_LEGACY
+#define CFG_ADV3_CREATE_PROPERTY ADV_LEGACY_UNDIR_CONN_MASK
+#define CFG_ADV3_CREATE_FILTER_POLICY FILTER_SCAN_ANY_CON_ANY
+#define CFG_ADV3_CREATE_DISCOVERY_MODE ADV_MODE_NON_DISC
+#define CFG_ADV3_CREATE_CHNL_MAP ADV_ALL_CHNLS
+#define CFG_ADV3_CREATE_PRIM_PHY BLE_GAP_PHY_LE_1MBPS
+#define CFG_ADV3_CREATE_INTERVAL_MIN (ADV_INTERVAL_MIN * 2)
+#define CFG_ADV3_CREATE_INTERVAL_MAX (ADV_INTERVAL_MIN * 2)
+#define CFG_ADV3_CREATE_MAX_TX_POWER 0
+#define CFG_ADV3_CREATE_SEC_MAX_SKIP 0
+#define CFG_ADV3_CREATE_SEC_PHY BLE_GAP_PHY_LE_1MBPS
+#define CFG_ADV3_CREATE_SEC_ADV_SID 0
+#define CFG_ADV3_CREATE_PERI_INTERVAL_MIN 80
+#define CFG_ADV3_CREATE_PERI_INTERVAL_MAX 80
+#define CFG_ADV3_CREATE_PEER_ADDR_TYPE 0
+#define CFG_ADV3_CREATE_PEER_ADDR 0
+
+#define CFG_ADV3_START_DURATION 300
+#define CFG_ADV3_START_MAX_ADV_EVENT 0
+
+#define CFG_ADV3_DATA_ADV_ENABLE 1
+#define CFG_ADV3_DATA_SCANRSP_ENABLE 0
+#define CFG_ADV3_DATA_ADV_PAYLOAD 0
+
+// MTK wake up packet configuration
+#define CFG_ADV4_OWNER_ADDR_TYPE BLE_OWN_STATIC_ADDR
+#define CFG_ADV4_CREATE_TYPE ADV_TYPE_LEGACY
+#define CFG_ADV4_CREATE_PROPERTY ADV_LEGACY_UNDIR_CONN_MASK
+#define CFG_ADV4_CREATE_FILTER_POLICY FILTER_SCAN_ANY_CON_ANY
+#define CFG_ADV4_CREATE_DISCOVERY_MODE ADV_MODE_NON_DISC
+#define CFG_ADV4_CREATE_CHNL_MAP ADV_ALL_CHNLS
+#define CFG_ADV4_CREATE_PRIM_PHY BLE_GAP_PHY_LE_1MBPS
+#define CFG_ADV4_CREATE_INTERVAL_MIN (ADV_INTERVAL_MIN * 2)
+#define CFG_ADV4_CREATE_INTERVAL_MAX (ADV_INTERVAL_MIN * 2)
+#define CFG_ADV4_CREATE_MAX_TX_POWER 0
+#define CFG_ADV4_CREATE_SEC_MAX_SKIP 0
+#define CFG_ADV4_CREATE_SEC_PHY BLE_GAP_PHY_LE_1MBPS
+#define CFG_ADV4_CREATE_SEC_ADV_SID 0
+#define CFG_ADV4_CREATE_PERI_INTERVAL_MIN 80
+#define CFG_ADV4_CREATE_PERI_INTERVAL_MAX 80
+#define CFG_ADV4_CREATE_PEER_ADDR_TYPE 0
+#define CFG_ADV4_CREATE_PEER_ADDR 0
+
+#define CFG_ADV4_START_DURATION 1000
+#define CFG_ADV4_START_MAX_ADV_EVENT 0
+
+#define CFG_ADV4_DATA_ADV_ENABLE 1
+#define RC_SRV_HID 0x03, 0x02, UUID_HID
+#define KEY_ID_POWER 0xFF, 0xFF
+#define RC_MTK_MANUF_DATA 0x13, 0xFF, 0x46, 0x00, 0x00, DUMMY_PEER_BD_ADDR, \
+ KEY_ID_POWER, 0x00, 0x00, 'C', 'R', 'K', 'T', 'M'
+#define CFG_ADV4_DATA_ADV_PAYLOAD RC_HID_ADV_DAT_APPEARANCE, RC_SRV_HID, \
+ RC_MTK_MANUF_DATA
+
+#define CFG_ADV4_DATA_SCANRSP_ENABLE 1
+#define RC_LOCAL_NAME_MTK_RC 0x0F, 0x09, 'M', 'T', 'K', ' ', 'B', 'L', 'E', \
+ ' ', 'R', 'e', 'm', 'o', 't', 'e'
+#define CFG_ADV4_DATA_SCANRSP_PAYLOAD RC_LOCAL_NAME_MTK_RC
+
+#else // CFG_ATVRC_WAKEUP
+// ADV data payload
+#define CFG_ADV1_DATA_ADV_PAYLOAD RC_HID_ADV_DAT_UUID, \
+ RC_HID_ADV_DAT_APPEARANCE, RC_HID_ADV_DAT_MANU
+
+// Scan response enabling
+#define CFG_ADV1_DATA_SCANRSP_ENABLE 1
+
+// Scan response payload
+#define CFG_ADV1_DATA_SCANRSP_PAYLOAD RC_HID_ADV_DAT_UUID, RC_HID_ADV_DAT_APPEARANCE
+#endif // CFG_ATVRC_WAKEUP
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/atvrc_custom.c b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/atvrc_custom.c
new file mode 100644
index 0000000..93b9da7
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/atvrc_custom.c
@@ -0,0 +1,253 @@
+/**
+ *******************************************************************************
+ *
+ * @file atvrc_custom.c
+ *
+ * @brief Android TV remote customization data management
+ *
+ * Copyright (C) Atmosic 2022
+ *
+ *******************************************************************************
+ */
+
+#include "arch.h"
+#include "atvrc_custom.h"
+#include "gap.h"
+#include "nvds.h"
+#include "rc_gap.h"
+#include "rc_keycode.h"
+#include "timer.h"
+
+#define ATVRC_CUSTOM_WAKE_PACKET_SIZE_MAX (31 - 4)
+#define ATVRC_AUTHENTICATION_KEY_SIZE 16
+#define ATVRC_ENCRYPTION_KEY_SIZE 16
+#define ATVRC_ECDSA_PUBLIC_KEY_SIZE 64
+
+typedef struct
+{
+ uint8_t dev_type;
+ uint8_t pnp_id[ATVRC_PNP_ID_LEN];
+ uint8_t dev_name_len;
+ uint8_t dev_name[ATVRC_DEV_NAME_LEN_MAX];
+ uint8_t dev_ui_layout;
+ uint16_t wake_key_1;
+ uint16_t wake_key_2;
+ uint8_t wake_pkt_len;
+ uint8_t key_id_oft;
+ uint8_t key_cnt_oft;
+ uint8_t peer_addr_oft;
+ uint8_t wake_pkt_data[ATVRC_CUSTOM_WAKE_PACKET_SIZE_MAX];
+ uint16_t period_wake_interval;
+ uint8_t period_wake;
+ uint8_t rpa_switch;
+ uint8_t disable_ble;
+ uint8_t wake_pkt_send_mode;
+ uint8_t cache_pwr;
+ uint8_t auth_key[ATVRC_AUTHENTICATION_KEY_SIZE];
+ uint8_t encrypt_key[ATVRC_ENCRYPTION_KEY_SIZE];
+ uint8_t ecdsa_pub_key[ATVRC_ECDSA_PUBLIC_KEY_SIZE];
+} __PACKED atvrc_custom_data_t;
+
+static atvrc_custom_data_t custom_data;
+static uint8_t fw_rev[ATVRC_FW_REV_STR_LEN] = {'V', '1', '.', '0', '0'};
+
+#define WAKE_KEY_NUM 12
+static uint32_t wake_key_bt_id[WAKE_KEY_NUM] = {
+ BT_ASST,
+ BT_HOME,
+ BT_POWER,
+ BT_INPUT,
+ BT_YOUTUBE,
+ BT_NETFLIX,
+ BT_APP03,
+ BT_APP04,
+ BT_BLUE,
+ BT_GREEN,
+ BT_RED,
+ BT_YELLOW,
+};
+
+#define NVDS_TAG_ATVRC_CUSTOM_DATA 0xC1
+void atvrc_custom_init(void)
+{
+ nvds_tag_len_t len = sizeof(atvrc_custom_data_t);
+ nvds_get(NVDS_TAG_ATVRC_CUSTOM_DATA, &len, (uint8_t*)&custom_data);
+#define FW_REV_MINOR_TEN_DIGIT 3
+#define FW_REV_MINOR_UNIT_DIGIT 4
+#define ASCII_BASE 0x30
+ fw_rev[FW_REV_MINOR_TEN_DIGIT] = custom_data.dev_type + ASCII_BASE;
+ fw_rev[FW_REV_MINOR_UNIT_DIGIT] = custom_data.dev_ui_layout + ASCII_BASE;
+ DEBUG_TRACE("Device type: %d", custom_data.dev_type);
+ DEBUG_TRACE("Vendor source: %d", custom_data.pnp_id[0]);
+ DEBUG_TRACE("VID: %02X%02X", custom_data.pnp_id[2], custom_data.pnp_id[1]);
+ DEBUG_TRACE("PID: %02X%02X", custom_data.pnp_id[4], custom_data.pnp_id[3]);
+ DEBUG_TRACE("PVer: %02X%02X", custom_data.pnp_id[6], custom_data.pnp_id[5]);
+ DEBUG_TRACE("Device name length: %d", custom_data.dev_name_len);
+ DEBUG_TRACE("Device name :");
+#if PLF_DEBUG
+ for (uint8_t i = 0; i < ATVRC_DEV_NAME_LEN_MAX; i++) {
+ printf("%c", custom_data.dev_name[i]);
+ }
+ printf("\n");
+#endif
+ DEBUG_TRACE("UI layout: %d", custom_data.dev_ui_layout);
+ DEBUG_TRACE("Wake key 1: %04X", custom_data.wake_key_1);
+ DEBUG_TRACE("Wake key 2: %04X", custom_data.wake_key_2);
+ DEBUG_TRACE("Wake packet len: %d", custom_data.wake_pkt_len);
+ DEBUG_TRACE("Key ID offset: %d", custom_data.key_id_oft);
+ DEBUG_TRACE("Key press count offset: %d", custom_data.key_cnt_oft);
+ DEBUG_TRACE("Peer Addr. offset: %d", custom_data.peer_addr_oft);
+ DEBUG_TRACE("Customized wakeup packet :");
+#if PLF_DEBUG
+ for (uint8_t i = 0; i < ATVRC_CUSTOM_WAKE_PACKET_SIZE_MAX; i++) {
+ printf("%02X ", custom_data.wake_pkt_data[i]);
+ }
+ printf("\n");
+#endif
+#define PERIOD_WAKE_INTERVEL_MINIMAL_MIN 5
+#define PERIOD_WAKE_INTERVEL_MAXIMAL_MIN 0x5A0
+#define PERIOD_WAKE_INTERVEL_DEFAULT_MIN 30
+ if ((custom_data.period_wake_interval < PERIOD_WAKE_INTERVEL_MINIMAL_MIN) ||
+ (custom_data.period_wake_interval > PERIOD_WAKE_INTERVEL_MAXIMAL_MIN)) {
+ custom_data.period_wake_interval = PERIOD_WAKE_INTERVEL_DEFAULT_MIN;
+ }
+ DEBUG_TRACE("Periodic wakeup interval: %d", custom_data.period_wake_interval);
+ DEBUG_TRACE("Periodic wakeup: %02X", custom_data.period_wake);
+ DEBUG_TRACE("RCU RPA switch: %02X", custom_data.rpa_switch);
+ DEBUG_TRACE("Disable BLE: %02X", custom_data.disable_ble);
+ DEBUG_TRACE("Wakeup sending mode: %02X", custom_data.wake_pkt_send_mode);
+ DEBUG_TRACE("Catch power switch: %02X", custom_data.cache_pwr);
+}
+
+uint8_t atvrc_custom_get_device_type(void)
+{
+ return custom_data.dev_type;
+}
+
+uint8_t *atvrc_custom_get_pnp(void)
+{
+ return custom_data.pnp_id;
+}
+
+uint8_t atvrc_custom_get_dev_name(nvds_tag_len_t *len, uint8_t *name)
+{
+ DEBUG_TRACE("%s: %s", __func__, custom_data.dev_name);
+ if (!custom_data.dev_name_len) {
+ DEBUG_TRACE("%s: FAIL", __func__);
+ return NVDS_FAIL;
+ }
+
+ if (custom_data.dev_name_len > *len) {
+ DEBUG_TRACE("%s: LENGTH_OUT_OF_RANGE", __func__);
+ return NVDS_LENGTH_OUT_OF_RANGE;
+ }
+
+ *len = custom_data.dev_name_len;
+ memcpy(name, custom_data.dev_name, *len);
+ return NVDS_OK;
+}
+
+uint8_t atvrc_custom_get_ui_layout(void)
+{
+ return custom_data.dev_ui_layout;
+}
+
+uint8_t *atvrc_custom_get_fw_rev(void)
+{
+ return fw_rev;
+}
+
+static bool is_mtk_wake(void)
+{
+ uint16_t product_ver = (custom_data.pnp_id[6] << 8) + custom_data.pnp_id[5];
+#define PRODUCT_VER_MTK_FORMAT 0x0101
+ return product_ver == PRODUCT_VER_MTK_FORMAT;
+}
+
+#define FEATURE_DISABLED 0xFFFF
+uint8_t atvrc_custom_check_wake_key(uint32_t bt_key)
+{
+ if (is_mtk_wake()) {
+ if (bt_key == BT_POWER) {
+ return ATVRC_WAKE_MTK_POWER;
+ }
+ if (bt_key == BT_NETFLIX) {
+ return ATVRC_WAKE_MTK_NETFLIX;
+ }
+ return ATVRC_WAKE_NOT_WAKE_KEY;
+ }
+ if (!custom_data.wake_key_1 && !custom_data.wake_key_2 &&
+ (custom_data.wake_key_1 == FEATURE_DISABLED) &&
+ (custom_data.wake_key_2 == FEATURE_DISABLED)) {
+ return ATVRC_WAKE_NOT_WAKE_KEY;
+ }
+ for (uint8_t i = 0; i < WAKE_KEY_NUM; i++) {
+ if (wake_key_bt_id[i] == bt_key) {
+ if (custom_data.wake_key_1 & (1 << i)) {
+ return ATVRC_WAKE_KEY1;
+ }
+ if (custom_data.wake_key_2 & (1 << i)) {
+ return ATVRC_WAKE_KEY2;
+ }
+ }
+ }
+ return ATVRC_WAKE_NOT_WAKE_KEY;
+}
+
+bool atvrc_custom_is_cwake(void)
+{
+ return custom_data.wake_pkt_len;
+}
+
+bool atvrc_custom_is_cwake_only(void)
+{
+ return !custom_data.wake_pkt_send_mode;
+}
+
+#define AD_FLAG_LEN 3
+#define ATVRC_DISABLED 0xFF
+uint8_t atvrc_custom_set_cwake_pkt(uint8_t *data, uint8_t key_id,
+ uint8_t key_cnt, uint8_t const *addr)
+{
+ ASSERT_ERR(custom_data.wake_pkt_len > AD_FLAG_LEN);
+
+ memcpy(data, custom_data.wake_pkt_data + AD_FLAG_LEN,
+ custom_data.wake_pkt_len - AD_FLAG_LEN);
+ if (custom_data.key_id_oft != ATVRC_DISABLED) {
+ data[custom_data.key_id_oft - AD_FLAG_LEN] = key_id;
+ }
+ if (custom_data.key_cnt_oft != ATVRC_DISABLED) {
+ data[custom_data.key_cnt_oft - AD_FLAG_LEN] = key_cnt;
+ }
+ if (custom_data.peer_addr_oft != ATVRC_DISABLED) {
+ memcpy(data + custom_data.peer_addr_oft - AD_FLAG_LEN, addr,
+ GAP_BD_ADDR_LEN);
+ }
+ return custom_data.wake_pkt_len - AD_FLAG_LEN;
+}
+
+#define ATVRC_ENABLED 1
+bool atvrc_custom_is_period_wake(void)
+{
+ return custom_data.period_wake == ATVRC_ENABLED;
+}
+
+uint16_t atvrc_custom_get_wake_interval(void)
+{
+ return custom_data.period_wake_interval;
+}
+
+bool atvrc_custom_is_rpa_enabled(void)
+{
+ return custom_data.rpa_switch == ATVRC_ENABLED;
+}
+
+bool atvrc_custom_is_ble_adv_enabled(void)
+{
+ return custom_data.disable_ble;
+}
+
+bool atvrc_custom_is_cache_pwr(void)
+{
+ return custom_data.cache_pwr;
+}
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/atvrc_custom.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/atvrc_custom.h
new file mode 100644
index 0000000..417da91
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/atvrc_custom.h
@@ -0,0 +1,139 @@
+/**
+ *******************************************************************************
+ *
+ * @file atvrc_custom.c
+ *
+ * @brief Android TV remote customization data interface
+ *
+ * Copyright (C) Atmosic 2022
+ *
+ *******************************************************************************
+ */
+
+#pragma once
+
+#define ATVRC_PNP_ID_LEN 7
+#define ATVRC_DEV_NAME_LEN_MAX 16
+#define ATVRC_FW_REV_STR_LEN 5
+
+#define ATVRC_LED_KEY_CS 10
+#define ATVRC_LED_KEY_BLINK 1
+#define ATVRC_LED_CFM_CS 10
+#define ATVRC_LED_CFM_BLINK 2
+#define ATVRC_LED_ERR_CS 5
+#define ATVRC_LED_ERR_BLINK 4
+
+/**
+ * @brief Customization data initialization.
+ */
+void atvrc_custom_init(void);
+
+/**
+ * @brief Get device type
+ *
+ * @return Device type
+ */
+uint8_t atvrc_custom_get_device_type(void);
+
+/**
+ * @brief Get PNP ID
+ *
+ * @return PNP ID data pointer
+ */
+uint8_t *atvrc_custom_get_pnp(void);
+
+/**
+ * @brief Get device name
+ *
+ * @param[inout] len Input: device name length maximum, Output: actual device
+ * name length
+ * @param[out] name Device name data pointer
+ * @return Status
+ */
+uint8_t atvrc_custom_get_dev_name(uint16_t *len, uint8_t *name);
+
+/**
+ * @brief Get UI layout bitmap
+ *
+ * @return UI layout bitmap
+ */
+uint8_t atvrc_custom_get_ui_layout(void);
+
+/**
+ * @brief Get firmware revision string
+ *
+ * @return Firmware revision string pointer
+ */
+uint8_t *atvrc_custom_get_fw_rev(void);
+
+/**
+ * @brief Check wake up key and set wake up configuration
+ *
+ * @param[in] bt_key BT keycode of pressed key
+ *
+ * @return Wake key ID or not a wake key
+ */
+uint8_t atvrc_custom_check_wake_key(uint32_t bt_key);
+
+/**
+ * @brief Is cutomized wake up
+ *
+ * @return True if customized wake up configuration exists, otherwise false
+ */
+bool atvrc_custom_is_cwake(void);
+
+/**
+ * @brief Is sending customized wake up packet only
+ *
+ * @return True for sending customized wake up packet only, otherwise false
+ */
+bool atvrc_custom_is_cwake_only(void);
+
+/**
+ * @brief Set customzied wake up packet payload
+ *
+ * @param[out] data Configured wake up packet payload
+ * @param[in] key_id Wake key ID
+ * @param[in] key_cnt Pressed key count
+ * @param[in] addr Peer device address
+ *
+ * @return Length of customized wake up packet payload
+ */
+__NONNULL(1,4)
+uint8_t atvrc_custom_set_cwake_pkt(uint8_t *data, uint8_t key_id,
+ uint8_t key_cnt, uint8_t const *addr);
+
+/**
+ * @brief Is periodically wake up
+ *
+ * @return True if periodically wake up enabled, otherwise false
+ */
+bool atvrc_custom_is_period_wake(void);
+
+/**
+ * @brief Get periodically wake up interval
+ *
+ * @return Periodically wake up interval in minute
+ */
+uint16_t atvrc_custom_get_wake_interval(void);
+
+/**
+ * @brief Is remote RPA enabled
+ *
+ * @return True if remote RPA enabled, otherwise false
+ */
+bool atvrc_custom_is_rpa_enabled(void);
+
+/**
+ * @brief Is BLE advertisement enabled
+ *
+ * @return True if BLE advertisement enabled, otherwise false
+ */
+bool atvrc_custom_is_ble_adv_enabled(void);
+
+/**
+ * @brief Is cache power key
+ *
+ * @return True if cache power key enabled, otherwise false
+ */
+bool atvrc_custom_is_cache_pwr(void); \ No newline at end of file
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/atvrc_porting.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/atvrc_porting.h
new file mode 100644
index 0000000..a551c48
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/atvrc_porting.h
@@ -0,0 +1,29 @@
+/**
+ *******************************************************************************
+ *
+ * @file atvrc_porting.h
+ *
+ * @brief Android TV Remote Control porting to use refDesignRcu implementations
+ *
+ * Copyright (C) Atmosic 2022
+ *
+ *******************************************************************************
+ */
+#pragma once
+
+#include "arch.h"
+
+typedef uint64_t u64;
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+typedef int16_t s16;
+typedef int8_t s8;
+
+#define APPLICATION_DONGLE 0
+#define SYSTEM_TIMER_TICK_1US 16
+#define SYSTEM_TIMER_TICK_1S 16000000
+
+void atm_array_printf(uint8_t const *data, uint16_t size);
+
+#define array_printf atm_array_printf \ No newline at end of file
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_att.c b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_att.c
new file mode 100644
index 0000000..06900ce
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_att.c
@@ -0,0 +1,176 @@
+/**
+ *******************************************************************************
+ *
+ * @file bridge_att.c
+ *
+ * @brief Bridge BLE ATT
+ *
+ * Copyright (C) Atmosic 2022
+ *
+ *******************************************************************************
+ */
+
+#include <inttypes.h>
+#include "atvrc_porting.h"
+#include "ble_att.h"
+#include "ble_atmprfs.h"
+#include "bridge_audio.h"
+#include "co_endian.h"
+#include "vendor/827x_ble_remote/app_config.h"
+#include "stack/ble/ble_format.h"
+#include "stack/ble/host/attr/att.h"
+#include "stack/ble/service/uuid.h"
+
+#undef ATT_DEBUG
+
+extern uint8_t device_in_connection_state;
+static attribute_t *att_tbl;
+
+void atm_array_printf(uint8_t const *data, uint16_t size)
+{
+#if PLF_DEBUG
+ for (uint16_t i = 0; i < size; i++) {
+ if (!(i % 16)) {
+ printf("\n");
+ }
+ printf("%02X ", *(data + i));
+ }
+ printf("\n");
+#endif
+}
+
+#ifdef ATT_DEBUG
+#define ATT_TRACE DEBUG_TRACE
+
+static void print_uuid_128(uint8_t *uuid)
+{
+ printf("\t\tUUID: ");
+ for (uint8_t i = 0; i < ATT_UUID_128_LEN; i++) {
+ if (i && !(i % 4)) {
+ printf("-");
+ }
+ printf("%02X", uuid[i]);
+ }
+ printf("\n");
+}
+#else
+#define ATT_TRACE(fmt, ...) DEBUG_TRACE_COND(0, fmt, ##__VA_ARGS__)
+#endif
+
+static uint8_t att_read_req_cb(uint8_t conidx, uint8_t att_idx)
+{
+ ATT_TRACE("%s: att_idx (%d)", __func__, att_idx);
+ ble_atmprfs_gattc_read_cfm(conidx, att_idx, 0, 0);
+ return ATT_ERR_NO_ERROR;
+}
+
+static rf_packet_att_data_t attd;
+static uint8_t att_write_req_cb(uint8_t conidx, uint8_t att_idx,
+ uint8_t const *data, uint16_t size)
+{
+ ATT_TRACE("%s: att_idx(%d) size(%d)", __func__, att_idx, size);
+#ifdef ATT_DEBUG
+ atm_array_printf(data, size);
+#endif
+#define ATT_HANDLE_OFFSET 1
+#define ATT_HEADER_LEN 3
+ attribute_t *att = att_tbl + att_idx + ATT_HANDLE_OFFSET;
+ if (att->w) {
+ attd.handle = att_idx + ATT_HANDLE_OFFSET;
+ attd.l2cap = size + ATT_HEADER_LEN;
+ memcpy(attd.dat, data, size);
+ att->w(&attd);
+ }
+ return ATT_ERR_NO_ERROR;
+}
+
+static ble_atmprfs_cbs_t const cbs = {
+ .read_req = att_read_req_cb,
+ .write_req = att_write_req_cb,
+};
+
+void atm_att_setAttributeTable(uint8_t *atts)
+{
+ DEBUG_TRACE("%s", __func__);
+#define ATT_TBL_NUM_ATTS 0
+ uint8_t num_att = atts[ATT_TBL_NUM_ATTS];
+ att_tbl = (attribute_t*)atts;
+ for (uint8_t i = 0; i <= num_att; i++) {
+ attribute_t *att = att_tbl + i;
+ uint16_t uuid = 0;
+ if (att->uuidLen == sizeof(uint16_t)) {
+ uuid = *((uint16_t*)att->uuid);
+ }
+ if (uuid == GATT_UUID_PRIMARY_SERVICE) {
+ ATT_TRACE("PRIMARY SERVICE (%04hX):", uuid);
+ uint8_t svc_uuid[ATT_UUID_128_LEN] = {0};
+ co_bswap(svc_uuid, att->pAttrValue, ATT_UUID_128_LEN);
+#ifdef ATT_DEBUG
+ print_uuid_128(svc_uuid);
+#endif
+ ble_atmprfs_add_svc(svc_uuid, BLE_SEC_PROP_NO_SECURITY, &cbs);
+ } else if (uuid == GATT_UUID_CHARACTER) {
+#define ATT_CHAR_PROP 0
+#define ATT_CHAR_HANDLE 1
+#define ATT_CHAR_UUID 3
+ uint8_t prop = att->pAttrValue[ATT_CHAR_PROP];
+ ATT_TRACE("\tCharacteristic (%04hX): %s%s%s%s%s", uuid,
+ (prop & CHAR_PROP_READ) ? "READ |" : "",
+ (prop & CHAR_PROP_WRITE_WITHOUT_RSP) ? " WRITE_WO_RSP |" : "",
+ (prop & CHAR_PROP_WRITE) ? " WRITE |" : "",
+ (prop & CHAR_PROP_NOTIFY) ? " NOTIFY |" : "",
+ (prop & CHAR_PROP_INDICATE) ? " INDICATE" : "");
+ uint8_t char_uuid[ATT_UUID_128_LEN] = {0};
+ co_bswap(char_uuid, &(att->pAttrValue[ATT_CHAR_UUID]),
+ ATT_UUID_128_LEN);
+#ifdef ATT_DEBUG
+ printf("\t");
+ print_uuid_128(char_uuid);
+#endif
+ ATT_TRACE("\t\tattribute len: %ld", att->attrLen);
+ uint16_t perm = (att->pAttrValue[ATT_CHAR_PROP] << 8) |
+ ((att->perm & ATT_PERMISSIONS_READ) ? PERM(RP, NO_AUTH) : 0 ) |
+ ((att->perm & ATT_PERMISSIONS_WRITE) ? PERM(WP, NO_AUTH) : 0 );
+ ble_atmprfs_add_char(char_uuid, perm, att->attrLen);
+ } else if (uuid == GATT_UUID_CLIENT_CHAR_CFG) {
+ ATT_TRACE("\t\tClient Characteristic Configuration (%04hX)", uuid);
+ ble_atmprfs_add_client_char_cfg();
+ }
+ }
+}
+
+static void ntf_sent_cb(uint8_t conidx, ble_gattc_cmp_evt_ex_t const *parm,
+ void const *ctx)
+{
+#ifdef CFG_ATVRC_AUDIO
+ bridge_audio_resend_voice();
+#endif
+}
+
+__FAST
+uint8_t atm_att_pushNotifyData(uint16_t attHandle, uint8_t *data, int len)
+{
+#ifdef ATT_DEBUG
+ if (attHandle != AUDIO_GOOGLE_RX_DP_H) {
+ ATT_TRACE("%s attHandle: %d, len: %d", __func__, attHandle, len);
+ atm_array_printf(data, len);
+ }
+#endif
+ if (!device_in_connection_state) {
+ ATT_TRACE("No connection");
+ return 1;
+ }
+ uint8_t conidx = device_in_connection_state - 1;
+ uint8_t status = ble_atmprfs_gattc_send_ntf(conidx,
+ attHandle - ATT_HANDLE_OFFSET, data, len, ntf_sent_cb);
+ if (status) {
+ ATT_TRACE("%s handle: %d error: %02X", __func__, attHandle, status);
+ }
+ return status;
+}
+
+void bridge_att_init(void)
+{
+ extern void my_att_init(void);
+ my_att_init();
+} \ No newline at end of file
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_att.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_att.h
new file mode 100644
index 0000000..b776283
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_att.h
@@ -0,0 +1,24 @@
+/**
+ *******************************************************************************
+ *
+ * @file bridge_att.h
+ *
+ * @brief Bridge BLE ATT
+ *
+ * Copyright (C) Atmosic 2022
+ *
+ *******************************************************************************
+ */
+#pragma once
+
+/**
+ * @brief Bridge BLE ATT initialization.
+ */
+void bridge_att_init(void);
+
+void atm_att_setAttributeTable(uint8_t *atts);
+
+uint8_t atm_att_pushNotifyData(uint16_t attHandle, uint8_t *data, int len);
+
+#define bls_att_setAttributeTable atm_att_setAttributeTable
+#define bls_att_pushNotifyData atm_att_pushNotifyData \ No newline at end of file
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_audio.c b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_audio.c
new file mode 100644
index 0000000..0adf80d
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_audio.c
@@ -0,0 +1,245 @@
+/**
+ *******************************************************************************
+ *
+ * @file bridge_audio.c
+ *
+ * @brief Bridge audio service
+ *
+ * Copyright (C) Atmosic 2022
+ *
+ *******************************************************************************
+ */
+
+#include "arch.h"
+#include "atvrc_porting.h"
+#include "bridge_audio.h"
+#include "rc_atvv.h"
+#include "rc_pdm.h"
+#include "nvds.h"
+#include "sw_event.h"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#include "application/audio/gl_audio.h"
+#pragma GCC diagnostic pop
+#include "stack/ble/ble_format.h"
+#include "vendor/827x_ble_remote/app_audio.h"
+#include "vendor/827x_ble_remote/app_config.h"
+
+extern void google_voice_data_notify_proc(void);
+
+uint8_t app_mtu_size;
+static uint16_t app_pkt_size;
+typedef struct {
+ uint16_t wr_oft;
+ uint16_t rd_oft;
+ uint16_t unsend;
+ bool mic_status;
+} audio_ctl_t;
+
+static audio_ctl_t au_ctl;
+static audio_sync_t au_sync;
+static sw_event_id_t sync_evt;
+extern uint16_t atv_char_ctl_ccc, atv_char_rx_ccc;
+
+__FAST
+audio_sync_t *bridge_audio_get_sync_info(void)
+{
+ return &au_sync;
+}
+
+__FAST
+static void audio_sync(sw_event_id_t event_id, void const *ctx)
+{
+ sw_event_clear(sync_evt);
+ au_sync.codec = google_voice_codec_used;
+ au_sync.frame_no += 1;
+ au_sync.pred_val = rc_atvv_get_pred_val(&(au_sync.step_idx));
+}
+
+#include "ke_mem.h"
+
+#define AUDIO_FRAME_SIZE 120
+#define NUM_AUDIO_BUF 20
+#define AUDIO_BUF_LEN AUDIO_FRAME_SIZE * NUM_AUDIO_BUF
+static uint8_t *audio_buf;
+
+typedef struct {
+ uint16_t rx_ccc;
+ uint16_t ctl_ccc;
+} atvv_ccc_t;
+
+static atvv_ccc_t atvv_ccc;
+
+#define NVDS_TAG_ATVRC_VOICE_CCC_CFG 0xC3
+
+extern void google_cmd_proc(void);
+static rep_vec_err_t bridge_audio_plf_schedule(void)
+{
+ google_cmd_proc();
+ return RV_NEXT;
+}
+
+void bridge_audio_init(void)
+{
+ audio_buf = ke_malloc(AUDIO_BUF_LEN, KE_MEM_ENV);
+ sync_evt = sw_event_alloc(audio_sync, NULL);
+ RV_PLF_SCHEDULE_ADD(bridge_audio_plf_schedule);
+ nvds_tag_len_t len = sizeof(atvv_ccc_t);
+ if (nvds_get(NVDS_TAG_ATVRC_VOICE_CCC_CFG, &len, (uint8_t*)&atvv_ccc)
+ != NVDS_OK) {
+ DEBUG_TRACE("%s: Fail to read ATVRC VOICE CCC NVDS tag", __func__);
+ }
+ atv_char_rx_ccc = atvv_ccc.rx_ccc;
+ atv_char_ctl_ccc = atvv_ccc.ctl_ccc;
+ active_mic_open();
+}
+
+__FAST
+void bridge_audio_write_voice_data(uint8_t data)
+{
+ audio_buf[au_ctl.wr_oft++] = data;
+ if (!(au_ctl.wr_oft % AUDIO_FRAME_SIZE)) {
+ au_ctl.unsend += AUDIO_FRAME_SIZE;
+ if (au_ctl.unsend >= AUDIO_BUF_LEN) {
+ DEBUG_TRACE("Audio buffer overflow: pause PDM");
+ rc_pdm_pause();
+ return;
+ }
+ google_voice_data_notify_proc();
+ sw_event_set(sync_evt);
+ }
+
+ if (au_ctl.wr_oft >= AUDIO_BUF_LEN) {
+ au_ctl.wr_oft = 0;
+ }
+}
+
+__FAST
+void bridge_audio_resend_voice(void)
+{
+ if (au_ctl.unsend > AUDIO_FRAME_SIZE) {
+ google_voice_data_notify_proc();
+ }
+}
+
+extern uint8_t read_assistant_model(void);
+bool bridge_audio_is_legacy_model(void)
+{
+ return read_assistant_model() == REASON_MICOPEN;
+}
+
+bool bridge_audio_is_htt_model(void)
+{
+ return read_assistant_model() == REASON_HTT;
+}
+
+void bridge_audio_start_search(void)
+{
+ google_voice_start();
+ sw_event_set(sync_evt);
+}
+
+void bridge_audio_dpad_select(void)
+{
+ google_voice_dpad_select();
+}
+
+extern uint8_t app_audio_key_stop(uint8_t reason);
+void bridge_audio_stop(void)
+{
+ app_audio_key_stop(bridge_audio_is_htt_model() ? REASON_RELEASE_HTT :
+ REASON_OTHERS);
+}
+
+void bridge_audio_set_mtu(uint8_t mtu)
+{
+ app_mtu_size = mtu;
+ extern void set_audio_frame_size(uint8_t);
+ set_audio_frame_size(mtu);
+}
+
+void bridge_audio_set_pkt_size(uint16_t pkt_size)
+{
+ DEBUG_TRACE("%s: %d", __func__, pkt_size);
+ app_pkt_size = pkt_size;
+}
+
+void bridge_audio_ready_ind(bool ready)
+{
+ rc_atvv_ready(ready);
+}
+
+static void write_atvv_ccc(atvv_ccc_t *ccc)
+{
+ nvds_tag_len_t len = sizeof(atvv_ccc_t);
+ nvds_put(NVDS_TAG_ATVRC_VOICE_CCC_CFG, len, (uint8_t*)ccc);
+}
+
+/// Porting refDesignRcu audio related functions
+int bridge_audio_ccc_write(void* msg)
+{
+ rf_packet_att_data_t *pw = (rf_packet_att_data_t *)msg;
+ uint16_t handle = pw->handle;
+ uint16_t data = (pw->dat[1] << 8) + pw->dat[0];
+ if (handle == AUDIO_GOOGLE_RX_CCC_H) {
+ DEBUG_TRACE("ATVV RX Notify: %s", data ? "Enabled" : "Disabled");
+ atvv_ccc.rx_ccc = atv_char_rx_ccc = data;
+ write_atvv_ccc(&atvv_ccc);
+ }
+
+ if (handle == AUDIO_GOOGLE_CTL_CCC_H) {
+ DEBUG_TRACE("ATVV CTL Notify: %s", data ? "Enabled" : "Disabled");
+ atvv_ccc.ctl_ccc = atv_char_ctl_ccc = data;
+ write_atvv_ccc(&atvv_ccc);
+ }
+
+ rc_atvv_ready(atv_char_ctl_ccc && atv_char_rx_ccc);
+ return 0;
+}
+
+__FAST
+uint8_t *bridge_audio_read_frame(void)
+{
+ if (!au_ctl.unsend) {
+ return NULL;
+ }
+ return audio_buf + au_ctl.rd_oft;
+}
+
+__FAST
+void bridge_audio_sent_frame_ind(void)
+{
+ au_ctl.unsend -= AUDIO_FRAME_SIZE;
+ if (rc_pdm_is_paused() && au_ctl.unsend < (AUDIO_BUF_LEN / 2)) {
+ DEBUG_TRACE("Audio buffer available: resume PDM");
+ rc_pdm_resume();
+ }
+ au_ctl.rd_oft += AUDIO_FRAME_SIZE;
+ if (au_ctl.rd_oft >= AUDIO_BUF_LEN) {
+ au_ctl.rd_oft = 0;
+ }
+
+}
+
+void ui_enable_mic(int en)
+{
+ if (!en) {
+ if (au_ctl.mic_status) {
+ rc_atvv_mic_close();
+ memset(&au_ctl, 0, sizeof(audio_ctl_t));
+ }
+ return;
+ }
+ au_ctl.mic_status = true;
+#ifdef CFG_FORCE_8K_NO_DLE
+ bool is8k = (app_pkt_size >= app_mtu_size) ?
+ !(google_voice_codec_used & CODEC_SUPPORTED_16K) : true;
+ if (is8k) {
+ google_voice_codec_used = CODEC_USED_8K;
+ google_voice_pcm_sample_packet = VOICE_V1P0_ADPCM_UNIT_SIZE * 2;
+ }
+#else
+ bool is8k = !(google_voice_codec_used & CODEC_SUPPORTED_16K);
+#endif
+ rc_atvv_mic_open(is8k);
+}
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_audio.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_audio.h
new file mode 100644
index 0000000..05e4cfb
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_audio.h
@@ -0,0 +1,147 @@
+/**
+ *******************************************************************************
+ *
+ * @file bridge_audio.h
+ *
+ * @brief Bridge audio service
+ *
+ * Copyright (C) Atmosic 2022
+ *
+ *******************************************************************************
+ */
+#pragma once
+
+#define VOICE_V0P4_ADPCM_PACKET_LEN 136
+#define VOICE_V0P4_ADPCM_UNIT_SIZE 256
+#define VOICE_V1P0_ADPCM_PACKET_LEN 128
+#define VOICE_V1P0_ADPCM_UNIT_SIZE 240
+
+typedef struct {
+ uint8_t codec;
+ uint16_t frame_no;
+ uint16_t pred_val;
+ uint8_t step_idx;
+} __PACKED audio_sync_t;
+
+/**
+ * @brief Get audio sync information
+ *
+ * @return Audio sync information
+ */
+audio_sync_t *bridge_audio_get_sync_info(void);
+
+/**
+ * @brief Write voice data to audio buffer
+ *
+ * @param[in] data ADPCM data
+ */
+void bridge_audio_write_voice_data(uint8_t data);
+
+/**
+ * @brief Resend voice packet
+ */
+void bridge_audio_resend_voice(void);
+
+/**
+ * @brief Check legacy model
+ *
+ * @return True if ATVV is using legacy model, otherwise return false
+ */
+bool bridge_audio_is_legacy_model(void);
+
+/**
+ * @brief Check HTT(Hold-to-Talk) model
+ *
+ * @return True if ATVV is using HTT model, otherwise return false
+ */
+bool bridge_audio_is_htt_model(void);
+
+/**
+ * @brief Start voice search
+ */
+void bridge_audio_start_search(void);
+
+/**
+ * @brief D-Pad select to start search
+ */
+void bridge_audio_dpad_select(void);
+
+/**
+ * @brief Stop voice search
+ */
+void bridge_audio_stop(void);
+
+/**
+ * @brief Set MTU
+ *
+ * @param[in] mtu Peer device RX MTU size
+ */
+void bridge_audio_set_mtu(uint8_t mtu);
+
+/**
+ * @brief Set BLE packet size
+ *
+ * @param[in] pkt_size Peer packet size
+ */
+void bridge_audio_set_pkt_size(uint16_t pkt_size);
+
+/**
+ * @brief Bridge audio initialization
+ */
+void bridge_audio_init(void);
+
+/**
+ * @brief Voice service status indication
+ *
+ * @param[in] ready True if voice service is ready, otherwise false
+ */
+void bridge_audio_ready_ind(bool ready);
+
+/**
+ * @brief Read audio frame
+ *
+ * @return The pointer of audio frame data
+ */
+uint8_t *bridge_audio_read_frame(void);
+
+
+/**
+ * @brief Audio frame sent indication
+ */
+void bridge_audio_sent_frame_ind(void);
+
+/// Porting clock time functions for gl_audio use
+#include "timer.h"
+
+/**
+ * @brief Get the current clock time
+ *
+ * @return Current system based on the 32kHz clock
+ */
+inline static uint32_t clock_time(void)
+{
+ return atm_get_sys_time();
+}
+
+/**
+ * @brief Check if clock time exceed
+ *
+ * @param[in] ref Reference clock time
+ * @param[in] us Expected duration in microseconds
+ *
+ * @return True if the delta time is exceeded expected duration.
+ */
+inline static bool clock_time_exceed(uint32_t ref, uint32_t us)
+{
+ return (atm_lpc_to_us(clock_time() - ref) > us);
+}
+
+#define att_ccc_control bridge_audio_ccc_write
+/**
+ * @brief Audio service CCC write indication
+ *
+ * @param[in] msg Write CCC message
+ *
+ * @return Always return 0
+ */
+int bridge_audio_ccc_write(void* msg); \ No newline at end of file
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_fms.c b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_fms.c
new file mode 100644
index 0000000..bbef2a5
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_fms.c
@@ -0,0 +1,74 @@
+/**
+ *******************************************************************************
+ *
+ * @file bridge_fms.c
+ *
+ * @brief Bridge Find Me Service
+ *
+ * Copyright (C) Atmosic 2022
+ *
+ *******************************************************************************
+ */
+
+#include <inttypes.h>
+#include "atm_utils_c.h"
+#include "atvrc_porting.h"
+#include "atvrc_custom.h"
+#include "bridge_fms.h"
+#include "buzzer.h"
+#include "atm_pm.h"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#include "vendor/827x_ble_remote/app_find_me/app_fms.h"
+#include "vendor/827x_ble_remote/app_find_me/app_buzzer.h"
+#pragma GCC diagnostic pop
+
+uint8_t atm_fms_buf[ATM_FMS_BUF_SIZE];
+
+static pm_lock_id_t fms_lock_ret;
+
+#define NOTE_BPM 150 // 400ms for quarter note
+note_t note_seq[] = {
+ {NOTE_C5, QUARTER_NOTE},
+ {NOTE_D5, QUARTER_NOTE},
+ {NOTE_E5, QUARTER_NOTE},
+ {NOTE_F5, QUARTER_NOTE},
+ {NOTE_G5, QUARTER_NOTE},
+ {NOTE_A5, QUARTER_NOTE},
+ {NOTE_B5, QUARTER_NOTE},
+};
+
+static void buzzer_stop_cb(void)
+{
+ atm_pm_unlock(fms_lock_ret);
+}
+
+
+void bridge_fms_init(void)
+{
+ app_fms_buffer_init();
+#define FMS_CTRL_OFFSET 0x24
+ app_fms_ctrl_t *ctrl = (app_fms_ctrl_t*)(atm_fms_buf + FMS_CTRL_OFFSET);
+ ctrl->en_periodic_wakeup = atvrc_custom_is_period_wake();
+ DEBUG_TRACE("%s: en_periodic_wakeup(%p) %d", __func__,
+ &ctrl->en_periodic_wakeup, ctrl->en_periodic_wakeup);
+ fms_lock_ret = atm_pm_alloc(PM_LOCK_RETENTION);
+ buzzer_init(buzzer_stop_cb);
+}
+
+void atm_fms_buzzer_play(uint8_t reason, unsigned char vol_lv)
+{
+ atm_pm_lock(fms_lock_ret);
+ buzzer_play(note_seq, ARRAY_LEN(note_seq), NOTE_BPM, vol_lv);
+}
+
+void atm_fms_buzzer_stop(void)
+{
+ buzzer_stop();
+ atm_pm_unlock(fms_lock_ret);
+}
+
+uint8_t atm_fms_buzzer_is_busy(void)
+{
+ return buzzer_is_playing();
+} \ No newline at end of file
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_fms.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_fms.h
new file mode 100644
index 0000000..05e5c10
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_fms.h
@@ -0,0 +1,25 @@
+/**
+ *******************************************************************************
+ *
+ * @file bridge_fms.h
+ *
+ * @brief Bridge Find Me Service
+ *
+ * Copyright (C) Atmosic 2022
+ *
+ *******************************************************************************
+ */
+#pragma once
+
+#include "arch.h"
+
+#define ATM_FMS_BUF_SIZE 0x30
+
+void bridge_fms_init(void);
+void atm_fms_buzzer_play(uint8_t reason, unsigned char sound_level);
+void atm_fms_buzzer_stop(void);
+uint8_t atm_fms_buzzer_is_busy(void);
+
+#define app_buzzer_play atm_fms_buzzer_play
+#define app_buzzer_stop atm_fms_buzzer_stop
+#define app_buzzer_is_buzy atm_fms_buzzer_is_busy \ No newline at end of file
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_ir.c b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_ir.c
new file mode 100644
index 0000000..f69a5de
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_ir.c
@@ -0,0 +1,120 @@
+/**
+ *******************************************************************************
+ *
+ * @file bridge_ir.c
+ *
+ * @brief Bridge IR service
+ *
+ * Copyright (C) Atmosic 2022
+ *
+ *******************************************************************************
+ */
+#include "arch.h"
+#include "bridge_ir.h"
+#include "nvds.h"
+#include "rc_ir.h"
+#include "rc_gap.h"
+#ifdef CFG_ATVRC_CUSTOM
+#include "atvrc_custom.h"
+#else
+#include "vendor/827x_ble_remote/app_config.h"
+#endif
+
+uint8_t app_custom_get_device_type(void)
+{
+#ifdef CFG_ATVRC_CUSTOM
+ return atvrc_custom_get_device_type();
+#else
+ return REMOTE_G10;
+#endif
+}
+
+void atm_disable_slave_latency(bool disable)
+{
+ rc_gap_local_slave_latency(disable);
+}
+
+void atm_ir_send_key_code(uint16_t key_id, uint8_t const *code, uint16_t size)
+{
+ DEBUG_TRACE("%s key_id: %d", __func__, key_id);
+ rc_ir_send_uni_code(key_id, code, size);
+}
+
+#define NVDS_TAG_ATVRC_IR_CCC_CFG 0xC4
+#define NVDS_TAG_ATVRC_IR_CODE_BASE 0xD0
+
+void atm_ir_write_code(uint8_t ir_idx, uint8_t *data, uint16_t size)
+{
+ DEBUG_TRACE("%s index: %d, size: %d", __func__, ir_idx, size);
+ nvds_tag_len_t len = size;
+ nvds_put(NVDS_TAG_ATVRC_IR_CODE_BASE + ir_idx, len, data);
+}
+
+uint8_t atm_ir_read_code(uint8_t ir_idx, uint8_t *data, uint16_t size)
+{
+ DEBUG_TRACE("%s index: %d, size: %d", __func__, ir_idx, size);
+ nvds_tag_len_t len = size;
+ if (nvds_get(NVDS_TAG_ATVRC_IR_CODE_BASE + ir_idx, &len, data) == NVDS_OK) {
+ return true;
+ }
+ return false;
+}
+
+void atm_ir_write_ccc(uint8_t ccc)
+{
+ DEBUG_TRACE("%s ccc: %d", __func__, ccc);
+ nvds_tag_len_t len = sizeof(uint8_t);
+ nvds_put(NVDS_TAG_ATVRC_IR_CCC_CFG, len, &ccc);
+}
+
+void atm_ir_del_code(void)
+{
+ DEBUG_TRACE("%s", __func__);
+#define NUM_IR_CODE_TAG 5
+ for (uint8_t i = 0; i < NUM_IR_CODE_TAG; i++) {
+ nvds_del(NVDS_TAG_ATVRC_IR_CODE_BASE + i);
+ }
+}
+
+extern uint8_t ir_key_is_suppress(uint8_t idx);
+extern uint8_t ir_fallback_send_key_code(uint8_t button_idx, bool key_down);
+extern void ir_table_init(void);
+extern void ir_flash_factory(void);
+extern int ir_fallback_send(uint8_t idx);
+extern void ir_flash_check(uint32_t addr);
+
+bool bridge_ir_check_key(uint16_t atv_keycode)
+{
+ if (!atv_keycode) {
+ return false;
+ }
+ if (ir_key_is_suppress(atv_keycode)) {
+ return false;
+ }
+ return ir_fallback_send_key_code(atv_keycode, 1);
+}
+
+void bridge_ir_clear(void)
+{
+ ir_table_init();
+ ir_flash_factory();
+}
+
+uint8_t bridge_ir_key_release(void)
+{
+ return ir_fallback_send(0);
+}
+
+extern void ir_init_key_event_notify(uint8_t value);
+void bridge_ir_init(void)
+{
+ uint8_t ccc;
+ nvds_tag_len_t len = sizeof(uint8_t);
+ if (nvds_get(NVDS_TAG_ATVRC_IR_CCC_CFG, &len, &ccc) == NVDS_OK) {
+ DEBUG_TRACE("%s ccc: %d", __func__, ccc);
+ ir_init_key_event_notify(ccc);
+ } else {
+ DEBUG_TRACE("%s: Fail to read ATVRC IR CCC NVDS TAG", __func__);
+ }
+ ir_flash_check(0);
+}
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_ir.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_ir.h
new file mode 100644
index 0000000..b405206
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_ir.h
@@ -0,0 +1,90 @@
+/**
+ *******************************************************************************
+ *
+ * @file bridge_ir.h
+ *
+ * @brief Bridge IR service
+ *
+ * Copyright (C) Atmosic 2022
+ *
+ *******************************************************************************
+ */
+#pragma once
+
+/**
+ * @brief Get device type
+ *
+ * @return REMOTE_G10 or REMOTE_G20, see ATV remote control PRD for details
+ */
+uint8_t app_custom_get_device_type(void);
+
+/**
+ * @brief Send IR key codes
+ *
+ * @param[in] key_id IR key id
+ * @param[in] code Pointer of IR code data
+ * @param[in] size IR code data size
+ */
+void atm_ir_send_key_code(uint16_t key_id, uint8_t const *code, uint16_t size);
+
+/**
+ * @brief Disable slave latency
+ *
+ * @param[in] disable True for disabling slave latency. False for enabling slave
+ * latency;
+ */
+void atm_disable_slave_latency(bool disable);
+
+/**
+ * @brief Write IR code
+ *
+ * @param[in] ir_idx IR key index
+ * @param[in] data Pointer of IR code data
+ * @param[in] size IR code data size
+ */
+void atm_ir_write_code(uint8_t ir_idx, uint8_t *data, uint16_t size);
+
+/**
+ * @brief Read IR code
+ *
+ * @param[in] ir_idx IR key index
+ * @param[out] data Pointer of IR code data
+ * @param[in] size IR code data size
+ */
+uint8_t atm_ir_read_code(uint8_t ir_idx, uint8_t *data, uint16_t size);
+
+/**
+ * @brief Write IR key envet notification
+ *
+ * @param[in] ccc Client characteristic configuration
+ */
+void atm_ir_write_ccc(uint8_t ccc);
+
+/**
+ * @brief Delete all IR code data
+ */
+void atm_ir_del_code(void);
+
+/**
+ * @brief Check ATV keycode and send universal IR key code
+ *
+ * @param[in] atv_keycode Android TV keycode
+ *
+ * @return True if IR code is sent, otherwise return false
+ */
+bool bridge_ir_check_key(uint16_t atv_keycode);
+
+/**
+ * @brief Clear all universal IR code data in flash
+ */
+void bridge_ir_clear(void);
+
+/**
+ * @brief Send universal IR key release
+ */
+uint8_t bridge_ir_key_release(void);
+
+/**
+ * @brief Bridge IR initialization
+ */
+void bridge_ir_init(void); \ No newline at end of file
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_timer.c b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_timer.c
new file mode 100644
index 0000000..0ce590b
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/bridge_timer.c
@@ -0,0 +1,88 @@
+/**
+ *******************************************************************************
+ *
+ * @file bridge_timer.c
+ *
+ * @brief Bridge timer
+ *
+ * Copyright (C) Atmosic 2022
+ *
+ *******************************************************************************
+ */
+
+#include "arch.h"
+#include "atvrc_porting.h"
+#include "sw_timer.h"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-declaration"
+#include "vendor/common/blt_soft_timer.h"
+#pragma GCC diagnostic pop
+
+#define NUM_BLT_TIMER 3
+
+#undef TIMER_DEBUG
+
+#ifdef TIMER_DEBUG
+#define TIMER_TRACE DEBUG_TRACE
+#else
+#define TIMER_TRACE(fmt, ...) DEBUG_TRACE_COND(0, fmt, ##__VA_ARGS__)
+#endif
+
+typedef struct blt_sw_timer_t {
+ sw_timer_id_t tid;
+ blt_timer_callback_t func;
+} blt_sw_timer_t;
+
+static blt_sw_timer_t blt_sw_timer[NUM_BLT_TIMER];
+
+static void blt_sw_timer_timeout(sw_timer_id_t idx, void const *ctx)
+{
+ TIMER_TRACE("%s idx: %d", __func__, idx);
+ blt_timer_callback_t func = (blt_timer_callback_t)(uintptr_t)ctx;
+ if (func) {
+ func();
+ }
+}
+
+static uint8_t get_available_blt_sw_timer(void)
+{
+ for (uint8_t i = 0; i < NUM_BLT_TIMER; i++) {
+ if (!blt_sw_timer[i].tid) {
+ return i;
+ }
+ }
+ DEBUG_TRACE("No available blt_sw_timer, increase NUM_BLT_TIMER");
+ ASSERT_ERR(0);
+ return 0;
+}
+
+int blt_soft_timer_add(blt_timer_callback_t func, u32 interval_us)
+{
+ uint8_t idx = get_available_blt_sw_timer();
+
+ blt_sw_timer[idx].tid = sw_timer_alloc(blt_sw_timer_timeout, func);
+ TIMER_TRACE("%s id: %d tid: %d inv: %lu func: %p", __func__, idx,
+ blt_sw_timer[idx].tid, interval_us, func);
+ blt_sw_timer[idx].func = func;
+#define USEC_TO_CSEC 10000
+ sw_timer_set(blt_sw_timer[idx].tid, interval_us / USEC_TO_CSEC);
+ return idx;
+}
+
+int blt_soft_timer_delete(blt_timer_callback_t func)
+{
+ uint8_t cnt = 0;
+ for (uint8_t i = 0; i < NUM_BLT_TIMER; i++) {
+ if (blt_sw_timer[i].func == func) {
+ TIMER_TRACE("%s id: %d tid: %d cb: %p", __func__, i,
+ blt_sw_timer[i].tid, func);
+ sw_timer_clear(blt_sw_timer[i].tid);
+ sw_timer_free(blt_sw_timer[i].tid);
+ blt_sw_timer[i].tid = 0;
+ blt_sw_timer[i].func = NULL;
+ cnt++;
+ }
+ }
+ TIMER_TRACE("found and deleted %d timer", cnt);
+ return cnt;
+}
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/refdesignrcu.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/refdesignrcu.h
new file mode 100644
index 0000000..3e61642
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/atvrc/refdesignrcu.h
@@ -0,0 +1,49 @@
+/**
+ *******************************************************************************
+ *
+ * @file refdesignrcu.h
+ *
+ * @brief Required header to build refDesignRcu in Atmosic SDK
+ *
+ * Copyright (C) Atmosic 2022
+ *
+ *******************************************************************************
+ */
+#pragma once
+
+#include "atvrc_porting.h"
+
+/// Warning supressions for refDesignRcu codes
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wmissing-prototypes"
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#pragma GCC diagnostic ignored "-Wunused-const-variable="
+#pragma GCC diagnostic ignored "-Wint-conversion"
+#pragma GCC diagnostic ignored "-Wformat="
+#pragma GCC diagnostic ignored "-Wold-style-declaration"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
+#pragma GCC diagnostic ignored "-Wold-style-definition"
+#pragma GCC diagnostic ignored "-Wswitch-enum"
+
+/// Required definitions for refDesignRcu
+#define SUCCESS 0x00
+#define __PROJECT_8258_BLE_REMOTE__ 0
+#define __PROJECT_8258_DRIVER_TEST__ 0
+#define __PROJECT_8278_BLE_REMOTE__ 1
+#define __PROJECT_8278_DRIVER_TEST__ 0
+#define LL_FEATURE_ENABLE_LL_PRIVACY 0
+#define LL_FEATURE_ENABLE_LE_DATA_LENGTH_EXTENSION 0
+#define LL_MASTER_MULTI_CONNECTION 0
+#define _attribute_data_retention_
+#define _attribute_aligned_(s) __attribute__((aligned(s)))
+#define own_addr_type_t u8
+
+#define U16_HI(a) (((a) >> 8) & 0xFF)
+#define U16_LO(a) ((a) & 0xFF)
+#define BIT(n) ( 1<<(n) )
+
+#if !PLF_DEBUG
+#define printf(fmt, ...) do {} while(0)
+#endif \ No newline at end of file
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_atvv.c b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_atvv.c
new file mode 100644
index 0000000..93bd355
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_atvv.c
@@ -0,0 +1,365 @@
+/**
+ *******************************************************************************
+ *
+ * @file rc_atvv.c
+ *
+ * @brief ATVV application part.
+ *
+ * Copyright (C) Atmosic 2021
+ *
+ *******************************************************************************
+ */
+#include "arch.h"
+#include "app_config.h"
+#include "rc_atvv.h"
+#include "rc_gap.h"
+#include <string.h>
+#include "rc_mmi.h"
+#include "atm_debug.h"
+#include "co_endian.h"
+#include "rc_pdm.h"
+#include "sw_event.h"
+#ifdef CFG_ATVRC_AUDIO
+#include "bridge_audio.h"
+
+static bool atvv_is8k;
+#else // CFG_ATVRC_AUDIO
+
+#define RF_BITS 4
+#define RF_SIZE (1 << RF_BITS)
+#define RF_MASK (RF_SIZE - 1)
+#define RF_NEXT(__p) (((__p) + 1) & RF_MASK)
+static ble_atvv_payload_t *report_fifo[RF_SIZE];
+static uint8_t rf_head, rf_tail;
+static uint16_t atvv_seqn;
+static bool atvv_is8k;
+static struct atvv_eid_context {
+ sw_event_id_t id;
+ bool is_first;
+} atvv_eid_ctx;
+#ifdef CFG_PDM_LOCAL_TEST
+bool fake_atvv_bad_link;
+static sw_timer_id_t wait_buffer_tid;
+#endif // CFG_PDM_LOCAL_TEST
+
+// Supply fifo as fast as possible
+__FAST
+static bool pdm_supply_fifo(ble_atvv_payload_t *pre_alloc)
+{
+ for (uint8_t rf_next = RF_NEXT(rf_head); rf_next != rf_tail; rf_next =
+ RF_NEXT(rf_next)) {
+ ble_atvv_payload_t *req;
+#ifdef CFG_PDM_LOCAL_TEST
+ if (fake_atvv_bad_link) {
+ break;
+ }
+#endif // CFG_PDM_LOCAL_TEST
+ if (pre_alloc) {
+ req = pre_alloc;
+ pre_alloc = NULL;
+ } else {
+ req = ble_atvvs_claim_audio_buf();
+ }
+
+ if (!req) {
+ break;
+ }
+
+ req->id = 0;
+
+ report_fifo[rf_head] = req;
+ rf_head = rf_next;
+ }
+
+ if (rf_head == rf_tail) {
+ return false;
+ } else {
+ if (rc_pdm_is_paused()) {
+#ifdef CFG_PDM_LOCAL_TEST
+ DEBUG_TRACE("pdm_resume");
+#endif
+ // Enable data processing
+ rc_pdm_resume();
+ }
+ }
+ return !pre_alloc;
+}
+
+// pdm event:
+// 1. Supply audio packet fifo
+// 2. If pause, checking for possibility of resuming.
+__FAST
+static void atvv_event(sw_event_id_t event_id, void const *ctx)
+{
+ struct atvv_eid_context *eid_ctx = CONTEXT_VOID_P(ctx);
+
+ sw_event_clear(event_id);
+ pdm_supply_fifo(NULL);
+
+ if (eid_ctx->is_first) {
+ eid_ctx->is_first = false;
+ ble_atvv_payload_t *req = report_fifo[rf_tail];
+ req->seqn = co_bswap16(atvv_seqn++);
+ req->prevp = co_bswap16(rc_pdm_get_adpcm_index(&req->idx));
+ }
+}
+
+static void pdm_reset_fifo(void)
+{
+ if (rf_tail != rf_head) {
+ report_fifo[rf_tail]->id = 0;
+ }
+}
+
+#ifdef CFG_PDM_LOCAL_TEST
+static void wait_buffer_ok(sw_timer_id_t tid, void const *ctx)
+{
+ fake_atvv_bad_link = false;
+ sw_event_set(atvv_eid_ctx.id);
+}
+#endif // CFG_PDM_LOCAL_TEST
+#endif // CFG_ATVRC_AUDIO
+
+// INTP on: [Thread context]
+// rc_pdm_event->rc_atvv_fill_pcm
+// INTP off: [IRQ_PRI_UI interrupt context]
+// rc_pdm_pcm_2_atvv->rc_atvv_fill_pcm
+__FAST
+void rc_atvv_fill_pcm(uint8_t pcm)
+{
+#ifdef CFG_ATVRC_AUDIO
+ bridge_audio_write_voice_data(pcm);
+#else
+ ASSERT_ERR(rf_tail != rf_head);
+ ble_atvv_payload_t *req = report_fifo[rf_tail];
+ req->val[req->id++] = pcm;
+ if (req->id == BLE_ATVV_REPORT_SIZE) {
+ rf_tail = RF_NEXT(rf_tail);
+ if (ble_atvvs_state() != BLE_ATVVS_STREAMING) {
+ ble_atvvs_free_audio_buf(req);
+ } else {
+ ble_atvvs_send_audio_buf(req);
+ }
+ sw_event_set(atvv_eid_ctx.id);
+
+ if (rf_tail == rf_head) {
+#ifdef CFG_PDM_LOCAL_TEST
+#define MAX_RECOVER_TIME_CS 1000
+ sw_timer_set(wait_buffer_tid, rand() % MAX_RECOVER_TIME_CS);
+ DEBUG_TRACE("pdm paused");
+#endif
+ rc_pdm_pause();
+ return;
+ } else {
+ req = report_fifo[rf_tail];
+ req->seqn = co_bswap16(atvv_seqn++);
+ req->prevp = co_bswap16(rc_pdm_get_adpcm_index(&req->idx));
+ }
+ }
+#endif // CFG_ATVRC_AUDIO
+}
+
+
+#ifdef CFG_ATVV_VER_100
+#include "nvds.h"
+#define CUST_TAG_ATVV_CONFIGURED 0xC0
+#endif
+
+#ifdef CFG_ATVRC_AUDIO
+void rc_atvv_ready(uint8_t ready)
+{
+ rc_mmi_transition(ready ? MMI_OP_ATVV_READY : MMI_OP_ATVV_UNREADY);
+}
+
+void rc_atvv_mic_open(bool is8k)
+{
+ DEBUG_TRACE("%s 8k: %d", __func__, is8k);
+ atvv_is8k = is8k;
+ rc_mmi_transition(MMI_OP_OPEN_MIC);
+}
+
+void rc_atvv_mic_close(void)
+{
+ if (!rc_atvv_is_htt_model()) {
+ rc_pdm_stop();
+ rc_mmi_transition(MMI_OP_CLOSE_MIC);
+ }
+}
+
+uint16_t rc_atvv_get_pred_val(uint8_t *idx)
+{
+ return rc_pdm_get_adpcm_index(idx);
+}
+
+#else // CFG_ATVRC_AUDIO
+static bool rc_atvv_query_configured(uint8_t conidx)
+{
+#ifdef CFG_ATVV_VER_100
+ // Typically, we should use conidx to get peer's address and compare.
+ // But current design is only support 1 bond.
+ bool atvv_configured;
+ nvds_tag_len_t len = sizeof(bool);
+ if (nvds_get(CUST_TAG_ATVV_CONFIGURED, &len, (uint8_t *)&atvv_configured) !=
+ NVDS_OK) {
+ return false;
+ }
+ return atvv_configured;
+#else
+ return false;
+#endif
+}
+
+static void rc_atvv_ready(uint8_t conidx, uint8_t state)
+{
+ uint8_t is_ready = state == BLE_ATVVS_READY;
+ rc_mmi_transition(is_ready ? MMI_OP_ATVV_READY : MMI_OP_ATVV_UNREADY);
+#ifdef CFG_ATVV_VER_100
+ if (state == BLE_ATVVS_IDLE) {
+ return;
+ }
+ // Typically, we should use conidx to get peer's address and save.
+ // But current design is only support 1 bond.
+ nvds_tag_len_t len = sizeof(bool);
+ nvds_put(CUST_TAG_ATVV_CONFIGURED, len, &is_ready);
+#endif
+}
+
+static void rc_atvv_mic_close_ind(uint8_t conidx)
+{
+ rc_pdm_stop(); // Close pdm earlier
+ rc_mmi_transition(MMI_OP_CLOSE_MIC);
+ pdm_reset_fifo();
+}
+
+static void rc_atvv_mic_open_ind(uint8_t conidx, uint16_t codecs)
+{
+ if (!(codecs & CODEC_ADPCM_8K_16K_16BIT)) {
+ ble_atvvs_mic_open_error(ATVV_ERROR_CODEC_NOT_SUPPORTED);
+ } else {
+ // This state will open mic
+ atvv_seqn = 0;
+ atvv_eid_ctx.is_first = true;
+ sw_event_set(atvv_eid_ctx.id);
+ atvv_is8k = !(codecs & CODEC_ADPCM_16K_16BIT);
+ rc_mmi_transition(MMI_OP_OPEN_MIC);
+ ble_atvvs_audio_start(BLE_ATVV_AUDIO_START_BY_MIC_OPEN, codecs);
+ }
+}
+
+ble_atvvs_param_t const rc_atvvs_parm = {
+ .cb_atvv_mic_close_ind = rc_atvv_mic_close_ind,
+ .cb_atvv_mic_open_ind = rc_atvv_mic_open_ind,
+ .cb_atvv_ready = rc_atvv_ready,
+ .cb_atvv_query_configured = rc_atvv_query_configured,
+};
+
+ble_atvvs_param_t const *rc_atvv_param(void)
+{
+ return &rc_atvvs_parm;
+}
+#endif // CFG_ATVRC_AUDIO
+
+void rc_atvv_start_search(void)
+{
+#ifdef CFG_ATVRC_AUDIO
+ bridge_audio_start_search();
+#else
+ ble_atvvs_start_search();
+#endif
+}
+
+void rc_atvv_dpad_select(void)
+{
+#ifdef CFG_ATVRC_AUDIO
+ bridge_audio_dpad_select();
+#else
+ ble_atvvs_dpad_select();
+#endif
+}
+
+void rc_atvv_stop_search(void)
+{
+ rc_pdm_stop(); // Close pdm earlier
+ rc_mmi_transition(MMI_OP_CLOSE_MIC);
+#ifdef CFG_ATVRC_AUDIO
+ bridge_audio_stop();
+#else
+ pdm_reset_fifo();
+ uint8_t reason = rc_atvv_is_htt_model() ?
+ BLE_ATVV_AUDIO_STOP_BY_HTT_BUTTON : BLE_ATVV_AUDIO_STOP_BY_OTHER_REASON;
+ ble_atvvs_audio_stop(reason);
+#endif
+}
+
+#ifndef CFG_ATVRC_AUDIO
+ble_atvvs_state_t rc_atvv_state(void)
+{
+ return ble_atvvs_state();
+}
+#endif
+
+bool rc_atvv_is8k(void)
+{
+ return atvv_is8k;
+}
+
+bool rc_atvv_is_legacy_model(void)
+{
+#ifdef CFG_ATVRC_AUDIO
+ return bridge_audio_is_legacy_model();
+#else
+ return ble_atvvs_asst_model() == BLE_ATVV_ASST_MODEL_LEGACY;
+#endif
+}
+
+bool rc_atvv_is_htt_model(void)
+{
+#ifdef CFG_ATVRC_AUDIO
+ return bridge_audio_is_htt_model();
+#else
+ return ble_atvvs_asst_model() == BLE_ATVV_ASST_MODEL_HTT;
+#endif
+}
+
+void rc_atvv_init(void)
+{
+#ifndef CFG_ATVRC_AUDIO
+ atvv_eid_ctx.id = sw_event_alloc(atvv_event, &atvv_eid_ctx);
+ ble_atvvs_reg_replish_callback(pdm_supply_fifo);
+#endif
+}
+
+#ifdef CFG_ATVV_VER_100
+void rc_atvv_del_config(void)
+{
+ nvds_del(CUST_TAG_ATVV_CONFIGURED);
+}
+#endif
+
+#ifdef CFG_PDM_LOCAL_TEST
+void rc_atvv_test_start(void)
+{
+ fake_atvv_bad_link = false;
+ atvv_eid_ctx.is_first = true;
+ sw_event_set(atvv_eid_ctx.id);
+}
+
+void rc_atvv_fake_bad_link(void)
+{
+ if (!fake_atvv_bad_link) {
+ fake_atvv_bad_link = rand() & 1;
+ }
+}
+
+static rep_vec_err_t rc_atvv_test_init(void)
+{
+ wait_buffer_tid = sw_timer_alloc(wait_buffer_ok, NULL);
+ return RV_NEXT;
+}
+
+__attribute__((constructor))
+static void rc_atvv_test_init_cstr(void)
+{
+ RV_APPM_INIT_ADD(rc_atvv_test_init);
+}
+#endif // CFG_PDM_LOCAL_TEST
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_atvv.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_atvv.h
new file mode 100644
index 0000000..7432316
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_atvv.h
@@ -0,0 +1,129 @@
+/**
+ *******************************************************************************
+ *
+ * @file rc_atvv.h
+ *
+ * @brief ATVV application part
+ *
+ * Copyright (C) Atmosic 2021
+ *
+ *******************************************************************************
+ */
+#pragma once
+
+#ifdef CFG_ATVRC_AUDIO
+void rc_atvv_ready(uint8_t ready);
+
+void rc_atvv_mic_open(bool is8k);
+
+void rc_atvv_mic_close(void);
+
+uint16_t rc_atvv_get_pred_val(uint8_t *idx);
+#else
+#include "ble_atvvs.h"
+
+/**
+ *******************************************************************************
+ * @brief Get ATVV profile parameter.
+ * This is used for passing parameters to @ref atm_gap_prf_reg.
+ * @return Parameters.
+ *******************************************************************************
+ */
+ble_atvvs_param_t const *rc_atvv_param(void);
+#endif
+
+/**
+ *******************************************************************************
+ * @brief Start ATVV search.
+ *******************************************************************************
+ */
+void rc_atvv_start_search(void);
+
+/**
+ *******************************************************************************
+ * @brief DPAD select to ATVV client.
+ *******************************************************************************
+ */
+void rc_atvv_dpad_select(void);
+
+/**
+ *******************************************************************************
+ * @brief Stop ATVV search.
+ *******************************************************************************
+ */
+void rc_atvv_stop_search(void);
+
+/**
+ *******************************************************************************
+ * @brief provide PCM data
+ * @param[in] pcm PCM data.
+ *******************************************************************************
+ */
+void rc_atvv_fill_pcm(uint8_t pcm);
+
+#ifndef CFG_ATVRC_AUDIO
+/**
+ *******************************************************************************
+ * @brief Get ATVV state
+ * @return ATVV state.
+ *******************************************************************************
+ */
+ble_atvvs_state_t rc_atvv_state(void);
+#endif
+
+/**
+ *******************************************************************************
+ * @brief Check if peer indicated codec is 8Khz.
+ * @return True if codec is 8Khz. Otherwise is 16Khz.
+ *******************************************************************************
+ */
+bool rc_atvv_is8k(void);
+
+/**
+ *******************************************************************************
+ * @brief Check if current assistant model is legacy mode
+ * @return True if using legacy mode
+ *******************************************************************************
+ */
+bool rc_atvv_is_legacy_model(void);
+
+/**
+ *******************************************************************************
+ * @brief Check if current assistant model is hold-to-talk mode(HTT)
+ * @return True if using HTT mode
+ *******************************************************************************
+ */
+bool rc_atvv_is_htt_model(void);
+
+#ifdef CFG_ATVV_VER_100
+/**
+ *******************************************************************************
+ * @brief Delete ATVV configuration
+ *******************************************************************************
+ */
+void rc_atvv_del_config(void);
+#endif
+
+/**
+ *******************************************************************************
+ * @brief Initialize ATVV environment.
+ *******************************************************************************
+ */
+void rc_atvv_init(void);
+
+#ifdef CFG_PDM_LOCAL_TEST
+/**
+ *******************************************************************************
+ * @brief ATVV test start
+ * @note This is used for ATVV flow unit test locally.
+ *******************************************************************************
+ */
+void rc_atvv_test_start(void);
+/**
+ *******************************************************************************
+ * @brief Pretend the bad link situation without allocating buffers.
+ * @note This is used for ATVV flow unit test locally.
+ *******************************************************************************
+ */
+void rc_atvv_fake_bad_link(void);
+#endif // CFG_PDM_LOCAL_TEST
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_gap.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_gap.h
new file mode 100644
index 0000000..95ddded
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_gap.h
@@ -0,0 +1,127 @@
+/**
+ *******************************************************************************
+ *
+ * @file rc_gap.h
+ *
+ * @brief GAP application part
+ *
+ * Copyright (C) Atmosic 2020-2021
+ *
+ *******************************************************************************
+ */
+#pragma once
+
+/// RF test type for @ref rc_gap_rf_test_adjust API.
+typedef enum {
+ /// PHY.
+ RC_RFTEST_PHY,
+ /// Channel.
+ RC_RFTEST_CH,
+ /// Power.
+ RC_RFTEST_PWR,
+} rc_rftest_type_t;
+
+/**
+ *******************************************************************************
+ * @brief Bluetooth initialization.
+ *******************************************************************************
+ */
+void rc_gap_init(void);
+
+/**
+ *******************************************************************************
+ * @brief Disconnect current link if have.
+ *******************************************************************************
+ */
+void rc_gap_disconnect(void);
+
+/**
+ *******************************************************************************
+ * @brief Start or stop device advertisement.
+ * @param[in] en True for enabling, otherwise for disabling.
+ *******************************************************************************
+ */
+void rc_gap_discoverable(bool en);
+
+/**
+ *******************************************************************************
+ * @brief Negotiate current link parameter.
+ *******************************************************************************
+ */
+void rc_gap_nego_parameter(void);
+
+/**
+ *******************************************************************************
+ * @brief Stop all the activities and links and back to idle.
+ *******************************************************************************
+ */
+void rc_gap_stop(void);
+
+/**
+ *******************************************************************************
+ * @brief Enter RF testing mode.
+ *******************************************************************************
+ */
+void rc_gap_enter_rf_test(void);
+
+/**
+ *******************************************************************************
+ * @brief Adjust RF testing parameter.
+ *
+ * @param[in] is_up True for increase parameter value.
+ * @param[in] type Parameter type.
+ *******************************************************************************
+ */
+void rc_gap_rf_test_adjust(bool is_up, rc_rftest_type_t type);
+
+/**
+ *******************************************************************************
+ * @brief Disable slave latency locally
+ * @param[in] disable True for disabling slave latency. False for enabling slave
+ * latency;
+ *******************************************************************************
+ */
+void rc_gap_local_slave_latency(bool disable);
+
+/**
+ *******************************************************************************
+ * @brief Enter pairing after next boot
+ * @param[in] enable True for enable pairing. False disable
+ * @note This switch is across hibernation.
+ *******************************************************************************
+ */
+void rc_gap_enter_pairing_next_boot(bool enable);
+
+/**
+ *******************************************************************************
+ * @brief Remove all bond information
+ *******************************************************************************
+ */
+void rc_gap_remove_all_bond(void);
+
+#ifdef CFG_ATVRC_WAKEUP
+typedef enum {
+ ATVRC_WAKE_NOT_WAKE_KEY,
+ ATVRC_WAKE_KEY1,
+ ATVRC_WAKE_KEY2,
+ ATVRC_WAKE_MTK_POWER,
+ ATVRC_WAKE_MTK_NETFLIX,
+} atvrc_wake_key_t;
+
+/**
+ *******************************************************************************
+ * @brief Start Wake up host
+ * @param[in] id Wake up key ID
+ *******************************************************************************
+ */
+void rc_gap_set_wake(atvrc_wake_key_t key);
+#endif
+
+#ifdef CFG_OTA_SPEEDUP
+/**
+ *******************************************************************************
+ * @brief Negotiate current link parameter for OTA speed up.
+ *******************************************************************************
+ */
+void rc_gap_nego_ota_parameter(void);
+#endif
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_hidau.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_hidau.h
new file mode 100644
index 0000000..17defac
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_hidau.h
@@ -0,0 +1,93 @@
+/**
+ *******************************************************************************
+ *
+ * @file rc_hidau.h
+ *
+ * @brief Voice over HID application part
+ *
+ * Copyright (C) Atmosic 2021
+ *
+ *******************************************************************************
+ */
+
+#pragma once
+
+#ifdef CFG_PDM_MSBC
+#include "sbc_enc_wrapper.h"
+#define HID_AU_REPORT_SIZE (MSBC_ENC_SIZE * 2)
+#else
+#define HID_AU_REPORT_SIZE 128
+#endif
+
+/**
+ *******************************************************************************
+ * @brief Start Audio search.
+ *******************************************************************************
+ */
+void rc_hidau_start_search(void);
+
+/**
+ *******************************************************************************
+ * @brief Stop Audio search.
+ *******************************************************************************
+ */
+void rc_hidau_stop_search(void);
+
+/**
+ *******************************************************************************
+ * @brief Get audio frame
+ *
+ * @param[out] frame Byte point of audio frame
+ * @return Residual number from pointer.
+ *******************************************************************************
+ */
+uint16_t rc_hidau_frame_get(uint8_t **frame);
+
+/**
+ *******************************************************************************
+ * @brief Move audio frame pointer forward
+ *
+ * @param[in] count Byte count to move
+ * @return Actual moved byte count.
+ * @note If reach the end, rc_bta will send it out. If current frame is not
+ * enough, the actual moving count would be the residual number.
+ *******************************************************************************
+ */
+uint16_t rc_hidau_frame_ptr_move(uint16_t count);
+
+/**
+ *******************************************************************************
+ * @brief Fill data to audio frame.
+ *
+ * @param[in] pcm PCM data.
+ * @note If reach the end of frame, rc_bta will send it out.
+ *******************************************************************************
+ */
+void rc_hidau_fill_pcm(uint8_t pcm);
+
+/**
+ *******************************************************************************
+ * @brief Initialize ATVV environment.
+ *******************************************************************************
+ */
+void rc_hidau_init(void);
+
+#ifdef CFG_PDM_LOCAL_TEST
+/**
+ *******************************************************************************
+ * @brief ATVV test start
+ *
+ * @note This is used for ATVV flow unit test locally.
+ *******************************************************************************
+ */
+void rc_hidau_test_start(void);
+/**
+ *******************************************************************************
+ * @brief Pretend the bad link situation without allocating buffers.
+ *
+ * @note This is used for ATVV flow unit test locally.
+ *******************************************************************************
+ */
+void rc_hidau_fake_bad_link(void);
+#endif // CFG_PDM_LOCAL_TEST
+
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_hogp.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_hogp.h
new file mode 100644
index 0000000..737689d
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_hogp.h
@@ -0,0 +1,55 @@
+/**
+ *******************************************************************************
+ *
+ * @file rc_hogp.h
+ *
+ * @brief HOGP application part
+ *
+ * Copyright (C) Atmosic 2020-2022
+ *
+ *******************************************************************************
+ */
+#pragma once
+
+#include "ble_hogpd.h"
+
+/**
+ *******************************************************************************
+ * @brief Get HOGP profile parameter.
+ * This is used for passing parameters to @ref atm_gap_prf_reg.
+ * @return Parameters.
+ *******************************************************************************
+ */
+ble_hogpd_param_t const *rc_hogp_param(void);
+
+/**
+ *******************************************************************************
+ * @brief Send key to peer.
+ *
+ * @param[in] keycode Key code.
+ * @note High 16 bits is usage, low 16 bits is key code.
+ *******************************************************************************
+ */
+void rc_hogp_send_single_key(uint32_t keycode);
+
+/**
+ *******************************************************************************
+ * @brief Get HOGP state
+ *
+ * @return HOGP state.
+ *******************************************************************************
+ */
+ble_hogpd_state_t rc_hogp_state(void);
+
+#ifdef CFG_VOHID
+/**
+ *******************************************************************************
+ * @brief Get audio report buffer index
+ *
+ * @param[in] hogp_cb Callback while sending complete.
+ * @param[in] ctx Application context.
+ * @return HID audio buffer context
+ *******************************************************************************
+ */
+void *rc_hogp_get_audio_buf(ble_hogpd_report_cmp_cb_t hogp_cb, void const *ctx);
+#endif
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_ota.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_ota.h
new file mode 100644
index 0000000..7147b38
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_ota.h
@@ -0,0 +1,22 @@
+/**
+ *******************************************************************************
+ *
+ * @file rc_ota.h
+ *
+ * @brief OTA application part
+ *
+ * Copyright (C) Atmosic 2020-2022
+ *
+ *******************************************************************************
+ */
+#pragma once
+#include "ble_otaps.h"
+
+/**
+ *******************************************************************************
+ * @brief Get OTAP profile parameter.
+ * This is used for passing parameters to @ref atm_gap_prf_reg.
+ * @return Parameters.
+ *******************************************************************************
+ */
+ble_otaps_param_t const *rc_otps_param(void);
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_test_mode.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_test_mode.h
new file mode 100644
index 0000000..a15bb0f
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/rc_test_mode.h
@@ -0,0 +1,92 @@
+/**
+ *******************************************************************************
+ *
+ * @file rc_test_mode.h
+ *
+ * @brief Test mode for fast connection
+ *
+ * Copyright (C) Atmosic 2022
+ *
+ *******************************************************************************
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "atm_adv.h"
+
+// Two continuous test input would cause system reset and
+// enter test mode from index 0 to 15. The direct ADV can be generated right
+// after reset through rc_create_test_mode_adv API. Here is the mapping of
+// input combination and index.
+// |-------+--------|
+// | Index | Inputs |
+// |=======+========|
+// | 0 | U U |
+// | 1 | U D |
+// | 2 | U L |
+// | 3 | U R |
+// | 4 | D U |
+// | 5 | D D |
+// | 6 | D L |
+// | 7 | D R |
+// | 8 | L U |
+// | 9 | L D |
+// | 10 | L L |
+// | 11 | L R |
+// | 12 | R U |
+// | 13 | R D |
+// | 14 | R L |
+// | 15 | R R |
+// |-------+--------|
+
+/// Test input definition.
+typedef enum {
+ // Cancel test
+ RC_TEST_CANCEL,
+ // Up get
+ RC_TEST_U_GOT,
+ // Down get
+ RC_TEST_D_GOT,
+ // Left get
+ RC_TEST_L_GOT,
+ // Right get
+ RC_TEST_R_GOT,
+} rc_test_input_t;
+
+/// NVDS base tag for fasting connection bt address
+#define FAST_CONN_NVDS 0xD0
+
+/// Default address
+#define FAST_CONN_D4ADDR 0x11, 0x18, 0x12, 0x23, 0x01, 0x24
+
+/**
+ *******************************************************************************
+ * @brief Test mode control
+ * @param[in] input Input to trigger state machine. Two continue inputs which
+ * are not RC_TEST_CANCEL will enable test mode with specific index. If the I1 and I2
+ * are first and second input, then the index of test mode is (I1 - 1) * 4 +
+ * (I2 -1).
+ *******************************************************************************
+ */
+void rc_test_mode_control(rc_test_input_t input);
+
+/**
+ *******************************************************************************
+ * @brief Generate test mode direct ADV structure for fast connection.
+ * The target address of direct ADV would get from NVDS tag which tag number is
+ * FAT_CONN_NVDS + test mode index.
+ * @return Data which is used to create direct ADV instance.
+ *******************************************************************************
+ */
+atm_adv_create_t *rc_create_test_mode_adv(void);
+
+/**
+ *******************************************************************************
+ * @brief Query for direct ADV retry left
+ * @param[in] minus_one True if substract the value of retry time by 1.
+ * @return Current value of retry times.
+ *******************************************************************************
+ */
+uint8_t rc_test_mode_adv_times_left(bool minus_one);
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/uuid.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/uuid.h
new file mode 100644
index 0000000..be74840
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/bt/uuid.h
@@ -0,0 +1,65 @@
+/**
+ *******************************************************************************
+ *
+ * @file uuid.h
+ *
+ * @brief Android TV Service UUIDs
+ *
+ * Copyright (C) Atmosic 2022
+ *
+ *******************************************************************************
+ */
+#pragma once
+
+#define GOOGLE_UUID_POSTFIX 0x5A, 0x21, 0x4F, 0x05, 0xBC, 0x7D, 0xAF, 0x01, \
+ 0xF6, 0x17, 0xB6, 0x64
+
+/* Google IR Configuration over BLE Service
+ * UUID : D343BFC0-5A21-4F05-BC7D-AF01F617B664
+ */
+#define SVC_UUID_IR_SERVICE 0xD3, 0x43, 0xBF, 0xC0, GOOGLE_UUID_POSTFIX
+
+/* Control Characteristic
+ * UUID : D343BFC1-5A21-4F05-BC7D-AF01F617B664
+ */
+#define CHAR_UUID_IR_PROG_CONTROL 0xD3, 0x43, 0xBF, 0xC1, GOOGLE_UUID_POSTFIX
+
+/* Key Code Characteristic
+ * UUID : D343BFC2-5A21-4F05-BC7D-AF01F617B664
+ */
+#define CHAR_UUID_IR_KEY_ID 0xD3, 0x43, 0xBF, 0xC2, GOOGLE_UUID_POSTFIX
+
+/* IR Code Characteristic
+ * UUID : D343BFC3-5A21-4F05-BC7D-AF01F617B664
+ */
+#define CHAR_UUID_IR_CODE 0xD3, 0x43, 0xBF, 0xC3, GOOGLE_UUID_POSTFIX
+
+/* IR Suppress Characteristic
+ * UUID : D343BFC4-5A21-4F05-BC7D-AF01F617B664
+ */
+#define CHAR_UUID_IR_SUPPRESS 0xD3, 0x43, 0xBF, 0xC4, GOOGLE_UUID_POSTFIX
+
+/* Key Down Characteristic
+ * UUID : D343BFC5-5A21-4F05-BC7D-AF01F617B664
+ */
+#define CHAR_UUID_IR_KEY_EVENT 0xD3, 0x43, 0xBF, 0xC5, GOOGLE_UUID_POSTFIX
+
+/* Google Voice over BLE Service
+ * UUID : AB5E0001-5A21-4F05-BC7D-AF01F617B664
+ */
+#define SVC_UUID_ATVV_SERVICE 0xAB, 0x5E, 0x00, 0x01, GOOGLE_UUID_POSTFIX
+
+/* ATVV TX Characteristic
+ * UUID : AB5E0002-5A21-4F05-BC7D-AF01F617B664
+ */
+#define CHAR_UUID_ATVV_TX 0xAB, 0x5E, 0x00, 0x02, GOOGLE_UUID_POSTFIX
+
+/* ATVV Audio Characteristic
+ * UUID : AB5E0003-5A21-4F05-BC7D-AF01F617B664
+ */
+#define CHAR_UUID_ATVV_AUDIO 0xAB, 0x5E, 0x00, 0x03, GOOGLE_UUID_POSTFIX
+
+/* ATVV CTL Characteristic
+ * UUID : AB5E0003-5A21-4F05-BC7D-AF01F617B664
+ */
+#define CHAR_UUID_ATVV_CTL 0xAB, 0x5E, 0x00, 0x04, GOOGLE_UUID_POSTFIX \ No newline at end of file
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/non_bt/rc_ir.c b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/non_bt/rc_ir.c
new file mode 100644
index 0000000..f8c490c
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/non_bt/rc_ir.c
@@ -0,0 +1,273 @@
+/**
+ *******************************************************************************
+ *
+ * @file rc_ir.c
+ *
+ * @brief IR application part
+ *
+ * Copyright (C) Atmosic 2020-2021
+ *
+ *******************************************************************************
+ */
+
+#include "arch.h"
+#include <inttypes.h>
+#include "rc_ir.h"
+#include "ir_ctl.h"
+#include "timer.h"
+#include "sw_event.h"
+#include "sw_timer.h"
+#include "atm_pm.h"
+#include "co_list.h"
+#ifdef CFG_ATVRC_UNI_IR
+#include "bridge_ir.h"
+#endif
+
+
+#ifndef CFG_RC_IR_QUEUE_MAX
+#define CFG_RC_IR_QUEUE_MAX 10
+#endif
+
+static struct {
+ co_list_t keys;
+ pm_lock_id_t lock_hib;
+ sw_timer_id_t tid;
+ sw_event_id_t eid;
+ uint8_t count;
+ bool sent;
+ bool pressed;
+#ifdef CFG_ATVRC_UNI_IR
+ bool is_uni;
+ uint16_t last_uni_key;
+ uint32_t last_uni_sent;
+#endif
+} ir_ctx;
+
+typedef struct {
+ co_list_hdr_t hdr;
+ uint32_t address;
+ uint32_t cmd;
+#ifdef CFG_ATVRC_UNI_IR
+ uint16_t uni_key;
+ uint8_t const *uni_code;
+ uint16_t uni_size;
+#endif
+ uint32_t delay_cs;
+} ir_key_t;
+
+static void rc_ir_dispatch(void)
+{
+ ir_key_t const *key = (ir_key_t const *)co_list_pick(&ir_ctx.keys);
+ if (key) {
+ atm_pm_lock(ir_ctx.lock_hib);
+ sw_timer_set(ir_ctx.tid, key->delay_cs);
+ } else if (!sw_timer_active(ir_ctx.tid)) {
+ // Notify upper layer if needed.
+ atm_pm_unlock(ir_ctx.lock_hib);
+ }
+}
+
+static void sw_event_func(sw_event_id_t event_id, void const *ctx)
+{
+ sw_event_clear(event_id);
+ rc_ir_dispatch();
+}
+
+// __FAST because called from interrupt handler.
+__FAST
+static void rc_ir_end(void)
+{
+ sw_event_set(ir_ctx.eid);
+}
+
+static void rc_ir_key_pop_out(void)
+{
+ ir_key_t *key = (ir_key_t *)co_list_pop_front(&ir_ctx.keys);
+ if (key) {
+ ir_ctx.count--;
+ sw_timer_clear(ir_ctx.tid);
+ free(key);
+ }
+}
+
+#ifdef CFG_NEC_IR_OVERRIDE
+#include "rc_keycode.h"
+#include "nvds.h"
+#define OVRD_ENTRY_NUM 48
+#define OVRD_ENTRY_LEN 4
+static uint8_t const ovrd_ir_cmd_map[OVRD_ENTRY_NUM] = {
+ IR_POWER, IR_RIGHT, IR_VOLD, IR_INFO, IR_NUM4, IR_GREEN, IR_INPUT, IR_DOWN,
+ IR_CNLD, IR_NUM0, IR_NUM3, IR_RED, IR_BKMK, IR_BACK, IR_YOUTUBE, IR_SUBT,
+ IR_NUM2, IR_NUM6, IR_ASST, IR_HOME, IR_NETFLIX, IR_NUM9, IR_NUM1, IR_NUM5,
+ IR_DASHB, IR_GUIDE, IR_APP03, IR_NUM8, IR_BLUE, 0, IR_UP, IR_VOLU, IR_APP04,
+ IR_NUM7, IR_YELLOW, 0, IR_LEFT, IR_CNLU, 0, 0, 0, 0, IR_CENTER, IR_MUTE,
+ 0, 0, 0, 0,
+};
+static uint8_t ovrd_val[OVRD_ENTRY_NUM][OVRD_ENTRY_LEN];
+static void nec_ir_override_init(void)
+{
+ nvds_tag_len_t len = sizeof(ovrd_val);
+#define NVDS_TAG_ATVRC_NEC_IR_OVERRIDE 0xC2
+ if (nvds_get(NVDS_TAG_ATVRC_NEC_IR_OVERRIDE, &len, (uint8_t*)&ovrd_val)
+ != NVDS_OK) {
+ memset(ovrd_val, 0xFF, sizeof(ovrd_val));
+ }
+}
+
+static bool nec_ir_override_check(ir_data_t *ir_data)
+{
+ bool is_ovrd = false;
+ for (uint8_t oft = 0; oft < OVRD_ENTRY_NUM; oft++) {
+ if (ir_data->cmd == ovrd_ir_cmd_map[oft]) {
+ uint32_t *data = (uint32_t*)ir_data;
+ for (uint8_t idx = 0; idx < OVRD_ENTRY_LEN; idx++) {
+ if (ovrd_val[oft][idx] != 0xFF) {
+ *(data + idx) = ovrd_val[oft][idx];
+ is_ovrd = true;
+ }
+ }
+ return is_ovrd;
+ }
+ }
+ return is_ovrd;
+}
+#endif
+
+static void rc_ir_send_msg_id(sw_timer_id_t idx, void const *ctx)
+{
+ ir_key_t const *key = (ir_key_t const *)co_list_pick(&ir_ctx.keys);
+ if (key) { // prevent earlier end
+ ir_ctx.sent = true;
+#ifdef CFG_ATVRC_UNI_IR
+ if (key->uni_code) {
+ ir_ctx.is_uni = true;
+ ir_ctx.last_uni_key = key->uni_key;
+ ir_ctx.last_uni_sent = atm_get_sys_time();
+ uni_ir_send(key->uni_code, key->uni_size);
+ rc_ir_key_pop_out();
+ return;
+ }
+#endif
+ DEBUG_TRACE("send %#" PRIx32 " %#" PRIx32, key->address, key->cmd);
+ bool repeat = ir_ctx.pressed && (ir_ctx.count == 1);
+#ifndef IR_DATA_CONST
+#define IR_DATA_CONST const
+#endif
+ ir_data_t IR_DATA_CONST data = {
+ .addr = key->address,
+ .inv_addr = ~key->address,
+ .cmd = key->cmd,
+ .inv_cmd = ~key->cmd
+ };
+#ifdef CFG_NEC_IR_OVERRIDE
+ if (nec_ir_override_check(&data)) {
+ DEBUG_TRACE("override %#" PRIx32 " %#" PRIx32 " %#" PRIx32
+ " %#" PRIx32, data.addr, data.inv_addr, data.cmd, data.inv_cmd);
+ }
+#endif
+ nec_ir_send(&data, repeat);
+ rc_ir_key_pop_out();
+ }
+}
+
+void rc_ir_init(void)
+{
+ ir_ctl_init(rc_ir_end);
+ ir_ctx.eid = sw_event_alloc(sw_event_func, NULL);
+#ifdef CFG_NEC_IR_OVERRIDE
+ nec_ir_override_init();
+#endif
+ ir_ctx.tid = sw_timer_alloc(rc_ir_send_msg_id, &ir_ctx);
+ co_list_init(&ir_ctx.keys);
+ ir_ctx.lock_hib = atm_pm_alloc(PM_LOCK_HIBERNATE);
+}
+
+void rc_ir_send(uint32_t address, uint32_t cmd, uint32_t delay_cs)
+{
+ if (!address || (ir_ctx.count >= CFG_RC_IR_QUEUE_MAX)) {
+ return;
+ }
+
+ ir_key_t *ikey = malloc(sizeof(ir_key_t));
+ if (!ikey) {
+ return;
+ }
+
+ ikey->address = address;
+ ikey->cmd = cmd;
+ ikey->delay_cs = delay_cs;
+
+#ifdef CFG_ATVRC_UNI_IR
+ ikey->uni_code = NULL;
+#endif
+
+ co_list_push_back(&ir_ctx.keys, &ikey->hdr);
+
+ if (!ir_ctx.count++) {
+ rc_ir_dispatch();
+ }
+ ir_ctx.pressed = true;
+}
+
+void rc_ir_repeat_end(void)
+{
+ ir_ctx.pressed = false;
+
+ if (ir_ctx.sent) {
+#ifdef CFG_ATVRC_UNI_IR
+ if(ir_ctx.is_uni) {
+ bridge_ir_key_release();
+ ir_ctx.is_uni = false;
+ }
+#endif
+ // this will trigger callback
+ ir_ctl_stop_rept();
+ ir_ctx.sent = false;
+ } else {
+ rc_ir_dispatch();
+ }
+}
+
+#ifdef CFG_ATVRC_UNI_IR
+bool rc_ir_check_uni_key(uint16_t atv_keycode)
+{
+ return bridge_ir_check_key(atv_keycode);
+}
+
+void rc_ir_send_uni_code(uint16_t key, uint8_t const *code, uint16_t size)
+{
+ if (!code || (ir_ctx.count >= CFG_RC_IR_QUEUE_MAX)) {
+ return;
+ }
+
+ ir_key_t *ikey = malloc(sizeof(ir_key_t));
+ if (!ikey) {
+ return;
+ }
+
+ ikey->uni_key = key;
+ ikey->uni_code = code;
+ ikey->uni_size = size;
+ ikey->delay_cs = 6;
+
+ if (ir_ctx.last_uni_key == key) {
+ uint32_t delay = uni_ir_get_rept_delay(code);
+ uint32_t delta_time = atm_get_sys_time() - ir_ctx.last_uni_sent;
+ if (delay && (atm_lpc_to_us(delta_time) < delay)) {
+ DEBUG_TRACE("repeat delay(%lu) > delta(%lu)", delay, delta_time);
+ ikey->delay_cs = delay / US_PER_CS;
+ }
+ }
+
+ co_list_push_back(&ir_ctx.keys, &ikey->hdr);
+
+ if (!ir_ctx.count++) {
+ rc_ir_dispatch();
+ }
+}
+
+void rc_ir_clear_uni_codes(void)
+{
+ bridge_ir_clear();
+}
+#endif
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/non_bt/rc_ir.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/non_bt/rc_ir.h
new file mode 100644
index 0000000..66ba534
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/non_bt/rc_ir.h
@@ -0,0 +1,59 @@
+/**
+ *******************************************************************************
+ *
+ * @file rc_ir.h
+ *
+ * @brief IR application part
+ *
+ * Copyright (C) Atmosic 2020-2021
+ *
+ *******************************************************************************
+ */
+#pragma once
+
+/**
+ * @brief IR initialization.
+ */
+void rc_ir_init(void);
+
+/**
+ *******************************************************************************
+ * @brief Send IR code.
+ * @param[in] address NEC address
+ * @param[in] cmd NEC command.
+ * @param[in] delay_ds Delay time to send.
+ *******************************************************************************
+ */
+void rc_ir_send(uint32_t address, uint32_t cmd, uint32_t delay_cs);
+
+/**
+ * @brief Stop repeat
+ */
+void rc_ir_repeat_end(void);
+
+#ifdef CFG_ATVRC_UNI_IR
+/**
+ *******************************************************************************
+ * @brief Check universal IR key
+ * @param[in] atv_keycode Android TV keycode
+ *******************************************************************************
+ */
+bool rc_ir_check_uni_key(uint16_t atv_keycode);
+
+/**
+ *******************************************************************************
+ * @brief Send Universal IR code data
+ * @param[in] key Universal IR key id
+ * @param[in] code Pointer of IR code data
+ * @param[in] size IR code data size
+ *******************************************************************************
+ */
+void rc_ir_send_uni_code(uint16_t key, uint8_t const *code, uint16_t size);
+
+/**
+ *******************************************************************************
+ * @brief Clear all Universal IR code data
+ *******************************************************************************
+ */
+void rc_ir_clear_uni_codes(void);
+#endif
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/non_bt/rc_keycode.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/non_bt/rc_keycode.h
new file mode 100644
index 0000000..d584b5b
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/non_bt/rc_keycode.h
@@ -0,0 +1,157 @@
+/**
+ *******************************************************************************
+ *
+ * @file rc_keycode.c
+ *
+ * @brief HID remote keycode definitions
+ *
+ * Copyright (C) Atmosic 2022
+ *
+ *******************************************************************************
+ */
+
+#pragma once
+
+#ifdef CFG_FLEX_VKEY_MAP
+#define __ATM_VKEY_MAP_CONST
+#else
+#define __ATM_VKEY_MAP_CONST const
+#endif
+
+#define CSM_USAGE 0x000C
+#define KBD_USAGE 0x0007
+
+#define CSM(x) ((CSM_USAGE << 16) | x)
+#define KBD(x) ((KBD_USAGE << 16) | x)
+
+#define BT_VOLU CSM(0xE9)
+#define BT_VOLD CSM(0xEA)
+#define BT_PLAY CSM(0xCD)
+#define BT_BACK CSM(0x224)
+#define BT_BW CSM(0xB6)
+#define BT_FW CSM(0xB5)
+#define BT_POWER CSM(0x30)
+#define BT_HOME CSM(0x223)
+#define BT_MENU KBD(0x76)
+#define BT_MIC CSM(0x221)
+#define BT_OK CSM(0x41)
+#define BT_UP CSM(0x42)
+#define BT_DOWN CSM(0x43)
+#define BT_RIGHT CSM(0x45)
+#define BT_LEFT CSM(0x44)
+
+#ifdef CFG_ATVRC_MMI
+#define BT_BKMK CSM(0x22A)
+#define BT_ALAP CSM(0x1A2)
+#define BT_PROF CSM(0x229)
+#define BT_ASST CSM(0x221)
+#define BT_SETT CSM(0x96)
+#define BT_DASHB CSM(0x9F)
+#define BT_CENTER CSM(0x41)
+#define BT_GUIDE CSM(0x8D)
+#define BT_LIVE CSM(0x89)
+#define BT_INPUT CSM(0x1BB)
+#define BT_MUTE CSM(0xE2)
+#define BT_YOUTUBE CSM(0x77)
+#define BT_NETFLIX CSM(0x78)
+#define BT_APP03 CSM(0x79)
+#define BT_APP04 CSM(0x7A)
+#define BT_CNLU CSM(0x9C)
+#define BT_CNLD CSM(0x9D)
+#define BT_FASTR CSM(0xB4)
+#define BT_RECORD CSM(0xCE)
+#define BT_PLAY CSM(0xCD)
+#define BT_FASTF CSM(0xB3)
+#define BT_RED CSM(0x69)
+#define BT_GREEN CSM(0x6A)
+#define BT_YELLOW CSM(0x6C)
+#define BT_BLUE CSM(0x6B)
+#define BT_NUM1 KBD(0x1E)
+#define BT_NUM2 KBD(0x1F)
+#define BT_NUM3 KBD(0x20)
+#define BT_NUM4 KBD(0x21)
+#define BT_NUM5 KBD(0x22)
+#define BT_NUM6 KBD(0x23)
+#define BT_NUM7 KBD(0x24)
+#define BT_NUM8 KBD(0x25)
+#define BT_NUM9 KBD(0x26)
+#define BT_NUM0 KBD(0x27)
+#define BT_INFO CSM(0x1BD)
+#define BT_SUBT CSM(0x61)
+#define BT_TEXT CSM(0x185)
+#endif
+
+#ifdef CFG_ATVRC_UNI_IR
+#define ATV_VOLU 0x18
+#define ATV_VOLD 0x19
+#define ATV_MUTE 0xA4
+#define ATV_POWER 0x1A
+#define ATV_INPUT 0xB2
+#endif
+
+#ifdef CFG_RC_IR
+#ifdef CFG_ATVRC_MMI
+#define IR_ADDR 0x88
+#define IR_POWER 0x21
+#define IR_INPUT 0x60
+#define IR_MUTE 0x25
+#define IR_VOLU 0x23
+#define IR_VOLD 0x24
+#define IR_YOUTUBE 0x63
+#define IR_NETFLIX 0x64
+#define IR_APP03 0x67
+#define IR_APP04 0x68
+#define IR_CNLU 0x33
+#define IR_CNLD 0x34
+#define IR_BKMK 0x74
+#define IR_ALAP 0x57
+#define IR_PROF 0x59
+#define IR_ASST 0x46
+#define IR_SETT 0x0F
+#define IR_DASHB 0x10
+#define IR_UP 0x15
+#define IR_DOWN 0x16
+#define IR_LEFT 0x17
+#define IR_RIGHT 0x18
+#define IR_CENTER 0x19
+#define IR_BACK 0x48
+#define IR_HOME 0x47
+#define IR_GUIDE 0x32
+#define IR_LIVE 0x61
+#define IR_FASTR 0x51
+#define IR_RECORD 0x54
+#define IR_PLAY 0x52
+#define IR_FASTF 0x53
+#define IR_RED 0x4B
+#define IR_GREEN 0x4A
+#define IR_YELLOW 0x49
+#define IR_BLUE 0x4C
+#define IR_NUM1 0x01
+#define IR_NUM2 0x02
+#define IR_NUM3 0x03
+#define IR_NUM4 0x04
+#define IR_NUM5 0x05
+#define IR_NUM6 0x06
+#define IR_NUM7 0x07
+#define IR_NUM8 0x08
+#define IR_NUM9 0x09
+#define IR_NUM0 0x0A
+#define IR_INFO 0x29
+#define IR_SUBT 0x58
+#define IR_TEXT 0x75
+#define IR_BUGR 0x96
+#else
+#define IR_ADDR 0x80
+#define IR_POWER 0x46
+#define IR_UP 0x52
+#define IR_LEFT 0x06
+#define IR_OK 0x0F
+#define IR_RIGHT 0x1A
+#define IR_MENU 0x07
+#define IR_DOWN 0x13
+#define IR_BACK 0x1B
+#define IR_VOLD 0x15
+#define IR_HOME 0x17
+#define IR_VOLU 0x16
+#endif
+#endif // CFG_RC_IR \ No newline at end of file
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/non_bt/rc_pdm.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/non_bt/rc_pdm.h
new file mode 100644
index 0000000..78e099c
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/non_bt/rc_pdm.h
@@ -0,0 +1,95 @@
+/**
+ *******************************************************************************
+ *
+ * @file rc_pdm.h
+ *
+ * @brief PDM application part
+ *
+ * Copyright (C) Atmosic 2020-2021
+ *
+ *******************************************************************************
+ */
+#pragma once
+
+/// PDM operation type
+typedef enum {
+ /// Idle. (Not operation)
+ RC_PDM_IDLE,
+ /// Normal mode. (Sent to peer.)
+ RC_PDM_NORMAL,
+ /// Local test mode. (Drop data.)
+ RC_PDM_LOCAL_TEST_WO_DELAY,
+ /// Local test mode. (Interfere by delay and drop data.)
+ RC_PDM_LOCAL_TEST_WITH_DELAY,
+ /// Local test mode. (No buffer.)
+ RC_PDM_LOCAL_TEST_NO_BUF,
+ RC_PDM_LOCAL_TEST_MAX,
+} rc_pdm_op_t;
+
+/**
+ *******************************************************************************
+ * @brief PDM initialization.
+ *******************************************************************************
+ */
+void rc_pdm_init(void);
+
+/**
+ *******************************************************************************
+ * @brief Power on external PDM audio component.
+ *******************************************************************************
+ */
+void rc_pdm_device_pwr_on(void);
+
+/**
+ *******************************************************************************
+ * @brief Start PDM audio collection.
+ * @param op[in] PDM operation type.
+ * @param is8K[in] True if 8Khz. Otherwise is 16Khz.
+ *******************************************************************************
+ */
+void rc_pdm_start(rc_pdm_op_t op, bool is8K);
+
+/**
+ *******************************************************************************
+ * @brief Stop current PDM audio collection.
+ *******************************************************************************
+ */
+void rc_pdm_stop(void);
+
+/**
+ *******************************************************************************
+ * @brief PDM gain value adjust.
+ * @param[in] add True for increasing. Otherwise is decreasing.
+ *******************************************************************************
+ */
+void rc_pdm_gain_adjust(bool add);
+
+/**
+ *******************************************************************************
+ * @brief Resume paused PDM audio collection.
+ *******************************************************************************
+ */
+void rc_pdm_resume(void);
+
+/**
+ *******************************************************************************
+ * @brief Pause current PDM audio collection.
+ *******************************************************************************
+ */
+void rc_pdm_pause(void);
+
+/**
+ *******************************************************************************
+ * @brief Get ADPCM index and predicted sample.
+ * @param[out] idx Index
+ * @return Predicted sample.
+ *******************************************************************************
+ */
+uint16_t rc_pdm_get_adpcm_index(uint8_t *idx);
+
+/**
+ *******************************************************************************
+ * @brief Check if PDM paused.
+ *******************************************************************************
+ */
+bool rc_pdm_is_paused(void);
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi.c b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi.c
new file mode 100644
index 0000000..6f913c0
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi.c
@@ -0,0 +1,730 @@
+/*
+ *******************************************************************************
+ *
+ * @file rc_mmi.c
+ *
+ * @brief MMI (Man Machine Interface) of Atmosic remote controller reference design.
+ *
+ * Copyright (C) Atmosic 2020-2022
+ *
+ *******************************************************************************
+ */
+
+#include <inttypes.h>
+#include "app_config.h"
+#include "rc_hogp.h"
+#include "rc_gap.h"
+#include "led_blink.h"
+#include "app_bass.h"
+#ifdef CFG_VOHID
+#include "rc_hidau.h"
+#else
+#include "rc_atvv.h"
+#endif
+#include "rc_ir.h"
+#include "rc_pdm.h"
+#include "rc_mmi.h"
+#include "rc_mmi_vkey.h"
+#include "led_blink.h"
+#include "atm_gpio.h"
+#include "atm_debug.h"
+#include "atm_asm.h"
+#include "co_utils.h"
+#include "atm_pm.h"
+#ifdef AUTO_TEST
+#include "uart_stdout.h"
+#endif
+#include "gadc.h"
+#include "rc_keycode.h"
+#include "app_batt.h"
+#ifdef CFG_USB_DET
+#include "interrupt.h"
+#include "pinmux.h"
+#endif
+#ifdef CFG_ATVRC_ATT
+#include "bridge_att.h"
+#ifdef CFG_ATVRC_UNI_IR
+#include "bridge_ir.h"
+#endif
+#ifdef CFG_ATVRC_AUDIO
+#include "bridge_audio.h"
+#endif
+#endif // CFG_ATVRC_ATT
+#ifdef CFG_ATVRC_CUSTOM
+#include "atvrc_custom.h"
+#endif
+#ifdef CFG_ATVRC_FIND_ME
+#include "bridge_fms.h"
+#endif
+
+#define MMI_S_TBL_IDX 0
+
+#define ATVV_PEER_TEST_COUNT 1000
+
+ATM_LOG_LOCAL_SETTING("rc_mmi", V);
+
+#if PLF_DEBUG
+static char const * const mmi_s_str[] = {
+ STR(MMI_S_BOOTED),
+ STR(MMI_S_INITING),
+ STR(MMI_S_IDLE),
+ STR(MMI_S_PAIRING),
+ STR(MMI_S_RECONNING),
+ STR(MMI_S_CONNECTED),
+ #ifdef CFG_VOHID
+ STR(MMI_S_HID_READY),
+ STR(MMI_S_HID_STREAMING),
+ #else
+ STR(MMI_S_ATVV_ONLY),
+ STR(MMI_S_HID_ONLY),
+ STR(MMI_S_HID_ATVV),
+ STR(MMI_S_ATVVING),
+#endif
+ STR(MMI_S_DISCONNING),
+ STR(MMI_S_RF_TEST),
+ STR(MMI_S_PDM_TEST)
+};
+
+static char const *const mmi_op_str[] = {
+ STR(MMI_OP_INITING),
+ STR(MMI_OP_INIT_DONE),
+ STR(MMI_OP_RECONNING),
+ STR(MMI_OP_PAIRING),
+ STR(MMI_OP_PAIR_FAIL),
+ STR(MMI_OP_RECONN_TOUT),
+ STR(MMI_OP_PAIR_TOUT),
+ STR(MMI_OP_PAIR_SUCCESS),
+ STR(MMI_OP_CONNECTED),
+ STR(MMI_OP_DISCONNED),
+ STR(MMI_OP_HID_READY),
+#ifndef CFG_VOHID
+ STR(MMI_OP_ATVV_READY),
+#endif
+ STR(MMI_OP_HID_UNREADY),
+#ifndef CFG_VOHID
+ STR(MMI_OP_ATVV_UNREADY),
+#endif
+ STR(MMI_OP_OPEN_MIC),
+ STR(MMI_OP_CLOSE_MIC),
+ STR(MMI_OP_DISCONNING),
+ STR(MMI_OP_ADV_STOPPED),
+};
+
+STATIC_ASSERT(ARRAY_LEN(mmi_op_str) == MMI_OP_NUM, "Not match");
+
+#endif
+
+
+static uint32_t key_auto_test;
+static sw_timer_id_t rc_tid_mmi_idle;
+#ifndef CFG_VOHID
+static sw_timer_id_t rc_tid_atvv_test;
+#endif
+static sw_timer_id_t rc_tid_key_test;
+static sw_timer_id_t rc_tid_mic_ctl;
+static void (*app_batt_done_cb)(void);
+
+void rc_mmi_transition(mmi_op_t op)
+{
+ atm_asm_move(MMI_S_TBL_IDX, op);
+}
+
+static void rc_s_changed(ASM_S last_s, ASM_O op, ASM_S next_s)
+{
+#if PLF_DEBUG
+ uint8_t nidx = atm_asm_ordinal(next_s);
+ uint8_t oidx = atm_asm_ordinal(op);
+ ATM_LOG(V, ATM_VT_SGR "%s" ATM_VT_SGR " (%s)", ATM_GG_BLUE,
+ mmi_s_str[nidx], ATM_DE_COLOR, mmi_op_str[oidx]);
+#endif // PLF_DEBUG
+ atm_pm_lock_info();
+ rc_mmi_vkey_state_change_notify(next_s);
+}
+
+#define RC_MMI_OPEN_MIC_DELAY_CS 1
+
+static void rc_mmi_open_mic(void)
+{
+ sw_timer_set(rc_tid_mic_ctl, RC_MMI_OPEN_MIC_DELAY_CS);
+}
+
+#ifndef CFG_VOHID
+static uint16_t atvv_test_cnt_left;
+
+#define ATVV_AUTO_TEST_TIMER_CS 700
+
+static void rc_mmi_atvv_test_timer_msg_ind(sw_timer_id_t idx, void const *ctx)
+{
+#ifdef CFG_ATVRC_AUDIO
+ if (atvv_test_cnt_left) {
+#else
+ if ((rc_atvv_state() == BLE_ATVVS_READY) && atvv_test_cnt_left) {
+#endif
+ rc_gap_local_slave_latency(true);
+ rc_hogp_send_single_key(BT_MIC);
+ rc_hogp_send_single_key(0x00);
+ rc_atvv_start_search();
+ rc_pdm_device_pwr_on();
+ rc_mmi_open_mic();
+ ATM_LOG(N, "audio test left = " ATM_VT_SGR "%d" ATM_VT_SGR,
+ ATM_FG_CYAN, atvv_test_cnt_left, ATM_DE_COLOR);
+ atvv_test_cnt_left--;
+ }
+
+ if (atvv_test_cnt_left) {
+ sw_timer_set(rc_tid_atvv_test, ATVV_AUTO_TEST_TIMER_CS);
+ }
+}
+#endif
+#ifdef CFG_PDM_LOCAL_TEST
+static rc_pdm_op_t test_op;
+#endif
+
+static void rc_mmi_idle_timer_msg_ind(sw_timer_id_t idx, void const *ctx)
+{
+
+ if (rc_hogp_state() == BLE_HOGPD_READY) {
+ ATM_LOG(N, "idle too long timeout\n");
+ } else if (rc_hogp_state() == BLE_HOGPD_ENABLED) {
+ ATM_LOG(N, "HID not ready for a long time\n");
+ }
+
+ rc_mmi_transition(MMI_OP_DISCONNING);
+}
+
+
+static void rc_mmi_auto_key_test_timer_msg_ind(sw_timer_id_t idx, void const *ctx)
+{
+ rc_mmi_idle_timer(MMI_TOUT_START);
+ if (key_auto_test) {
+ ATM_LOG(V, "%" PRIu32 "//%d", (uint32_t)(6000-key_auto_test), 6000);
+
+ if (key_auto_test & 1){
+ rc_hogp_send_single_key(BT_UP);
+ rc_hogp_send_single_key(0x00);
+ rc_hogp_send_single_key(BT_DOWN);
+ rc_hogp_send_single_key(0x00);
+ } else {
+ rc_hogp_send_single_key(BT_UP);
+ rc_hogp_send_single_key(0x00);
+ rc_hogp_send_single_key(BT_DOWN);
+ rc_hogp_send_single_key(0x00);
+ }
+ sw_timer_set(rc_tid_key_test, (uint16_t) (50));
+ }
+
+ key_auto_test--;
+}
+
+static void rc_mmi_mic_ctl_timer_msg_ind(sw_timer_id_t idx, void const *ctx)
+{
+#ifdef CFG_PDM_LOCAL_TEST
+ rc_pdm_start(test_op, false);
+ return;
+#endif
+#ifdef CFG_VOHID
+ if (atm_asm_get_current_state(MMI_S_TBL_IDX) == MMI_S_HID_STREAMING) {
+ rc_pdm_start(RC_PDM_NORMAL, false);
+#else
+ if (atm_asm_get_current_state(MMI_S_TBL_IDX) == MMI_S_ATVVING) {
+ rc_pdm_start(RC_PDM_NORMAL, rc_atvv_is8k());
+#endif
+ return;
+ }
+}
+
+#ifdef CFG_USB_DET
+static void usb_det_intr(uint32_t mask)
+{
+ atm_gpio_clear_int_status(PIN_USB_DET);
+ if (!atm_gpio_read_gpio(PIN_USB_DET)) {
+ atm_gpio_int_set_rising(PIN_USB_DET);
+ led_off(LED_0);
+ return;
+ }
+ atm_gpio_int_set_falling(PIN_USB_DET);
+ led_on(LED_0);
+}
+#endif
+
+static void mmi_s_booted_op_initing(void)
+{
+ rc_gap_init();
+ rc_pdm_init();
+#ifdef CFG_VOHID
+ rc_hidau_init();
+#else
+ rc_atvv_init();
+#endif
+#ifdef CFG_RC_IR
+ rc_ir_init();
+#endif //CFG_RC_IR
+
+#ifndef CFG_VOHID
+ rc_tid_atvv_test = sw_timer_alloc(rc_mmi_atvv_test_timer_msg_ind, NULL);
+#endif
+ rc_tid_mmi_idle = sw_timer_alloc(rc_mmi_idle_timer_msg_ind, NULL);
+ rc_tid_key_test = sw_timer_alloc(rc_mmi_auto_key_test_timer_msg_ind, NULL);
+ rc_tid_mic_ctl = sw_timer_alloc(rc_mmi_mic_ctl_timer_msg_ind, NULL);
+
+#ifdef CFG_USB_DET
+ atm_gpio_setup(PIN_USB_DET);
+ atm_gpio_set_input(PIN_USB_DET);
+ atm_gpio_set_pullup(PIN_USB_DET);
+ interrupt_install_gpio(PIN_USB_DET, IRQ_PRI_UI, usb_det_intr);
+ if (!atm_gpio_read_gpio(PIN_USB_DET)) {
+ atm_gpio_int_set_rising(PIN_USB_DET);
+ } else {
+ atm_gpio_int_set_falling(PIN_USB_DET);
+ led_on(LED_0);
+ }
+ atm_gpio_set_int_enable(PIN_USB_DET);
+#endif
+}
+
+static void mmi_s_reconnecting_started(void)
+{
+#ifndef CFG_ATVRC_MMI
+ led_blink(LED_0, 10, 10, 0xffff);
+#endif
+}
+
+static void mmi_s_paring_started(void)
+{
+ led_blink(LED_0, 25, 25, 0xffff);
+#ifdef CFG_VKEY_BUF
+ rc_mmi_vkey_free_buf();
+#else
+ rc_mmi_vkey_clear_saved();
+#endif
+}
+
+static void mmi_pairing_stopped_routine(void)
+{
+ led_off(LED_0);
+#ifdef CFG_VKEY_BUF
+ rc_mmi_vkey_free_buf();
+#else
+ rc_mmi_vkey_clear_saved();
+#endif
+ atm_pm_lock_info();
+}
+
+static void mmi_s_pairing_success_stopped(void)
+{
+#ifdef CFG_ATVV_VER_100
+ rc_atvv_del_config();
+#endif
+ mmi_pairing_stopped_routine();
+}
+
+static void mmi_s_pairing_stopped(void)
+{
+ mmi_pairing_stopped_routine();
+#if (CFG_APP_FEATURE & APP_BATT_AUTO_TIMER_BIT)
+ app_batt_stop();
+#else
+#error "HID_remote only support app_batt with auto timer mode"
+#endif
+#ifdef CFG_ATVRC_MMI
+ led_blink(LED_1, ATVRC_LED_ERR_CS, ATVRC_LED_ERR_CS, ATVRC_LED_ERR_BLINK);
+#endif
+}
+
+static void mmi_s_pairing_disconnected(void)
+{
+ mmi_s_pairing_stopped();
+ sw_timer_clear(rc_tid_mmi_idle);
+}
+
+static void mmi_s_pairing_connected(void)
+{
+ rc_mmi_idle_timer(MMI_TOUT_START);
+#ifdef CFG_ATVRC_CUSTOM
+ led_blink(LED_0, ATVRC_LED_CFM_CS, ATVRC_LED_CFM_CS, ATVRC_LED_CFM_BLINK);
+#endif
+}
+
+static void mmi_s_reconnecting_tout(void)
+{
+ led_off(LED_0);
+#if (CFG_APP_FEATURE & APP_BATT_AUTO_TIMER_BIT)
+ app_batt_stop();
+#endif
+}
+
+static void mmi_s_reconnecting_connected(void)
+{
+ rc_mmi_idle_timer(MMI_TOUT_START);
+#ifdef CFG_ATVRC_CUSTOM
+ led_blink(LED_0, ATVRC_LED_CFM_CS, ATVRC_LED_CFM_CS, ATVRC_LED_CFM_BLINK);
+#else
+ led_off(LED_0);
+#endif
+}
+
+static void mmi_s_initing_op_done(void)
+{
+#ifdef CFG_PDM_LOCAL_TEST
+ rc_mmi_enter_test(MMI_TEST_PDM);
+#endif
+#ifdef CFG_RF_TEST
+ rc_mmi_enter_test(MMI_TEST_RF);
+#endif
+ app_batt_done_cb();
+}
+
+static void mmi_s_close_mic(void)
+{
+ rc_pdm_stop();
+ rc_mmi_idle_timer(MMI_TOUT_START);
+ rc_gap_local_slave_latency(false);
+#ifdef CFG_ATVRC_MMI
+ if (!rc_atvv_is_htt_model()) {
+ led_off(LED_0);
+ }
+#endif
+}
+
+static void mmi_s_streaming_open_mic(void)
+{
+#ifdef CFG_ATVV_VER_100
+ // 4.4
+ // 1. if microphone is open because of a previously
+ // sent MIC_OPEN command, then the Remote should restart an audio
+ // stream and notify Android TV host with AUDIO_START message;
+ ATM_LOG(D, "Mic already opened");
+#else
+ ATM_LOG(E, "Mic already opened");
+#endif
+}
+
+static void mmi_s_open_mic(void)
+{
+ rc_gap_local_slave_latency(true);
+ rc_pdm_device_pwr_on();
+ // wait for device charged.
+ rc_mmi_open_mic();
+}
+
+static void mmi_s_hid_ready(void)
+{
+ rc_mmi_idle_timer(MMI_TOUT_START);
+ rc_gap_nego_parameter();
+#ifdef CFG_VKEY_BUF
+ rc_mmi_vkey_flush_buf();
+#else
+ uint32_t key = rc_mmi_vkey_get_saved();
+ if (key && (key != BT_MIC)) {
+ rc_hogp_send_single_key(key);
+ rc_hogp_send_single_key(0);
+ rc_mmi_vkey_clear_saved();
+ }
+#endif
+}
+
+static void mmi_s_hid_ready_pairing_stopped(void)
+{
+ mmi_s_pairing_stopped();
+ mmi_s_hid_ready();
+ rc_gap_enter_pairing_next_boot(false);
+}
+
+static void mmi_s_disconnecting(void)
+{
+ rc_pdm_stop();
+ rc_gap_disconnect();
+}
+
+static void mmi_s_disconnected(void)
+{
+ led_off(LED_0);
+#ifndef CFG_VOHID
+ sw_timer_clear(rc_tid_atvv_test);
+#endif
+ sw_timer_clear(rc_tid_key_test);
+ sw_timer_clear(rc_tid_mmi_idle);
+#if (CFG_APP_FEATURE & APP_BATT_AUTO_TIMER_BIT)
+ app_batt_stop();
+#endif
+}
+
+static void mmi_s_prf_disconnected(void)
+{
+ mmi_s_disconnected();
+ rc_pdm_stop();
+ key_auto_test = 0;
+}
+
+static void mmi_s_unexp_disconnected(void)
+{
+ ATM_LOG(E, "Unexpected disconnection.");
+#ifdef CFG_VOHID
+ rc_hidau_stop_search();
+#else
+ rc_atvv_stop_search();
+#endif
+ mmi_s_prf_disconnected();
+}
+
+static state_entry const mmi_s_tbl[] = {
+ {MMI_S_BOOTED, MMI_OP_INITING, MMI_S_INITING, mmi_s_booted_op_initing},
+ {MMI_S_IDLE, MMI_OP_RECONNING, MMI_S_RECONNING, mmi_s_reconnecting_started},
+#ifndef CFG_VOHID
+ {MMI_S_IDLE, MMI_OP_ATVV_UNREADY, MMI_S_IDLE, NULL},
+#endif
+ {MMI_S_IDLE, MMI_OP_PAIRING, MMI_S_PAIRING, mmi_s_paring_started},
+ {MMI_S_IDLE, MMI_OP_DISCONNING, MMI_S_IDLE, NULL},
+ {MMI_S_IDLE, MMI_OP_DISCONNED, MMI_S_IDLE, NULL},
+ {MMI_S_IDLE, MMI_OP_PAIR_FAIL, MMI_S_IDLE, NULL},
+ {MMI_S_IDLE, MMI_OP_CLOSE_MIC, MMI_S_IDLE, mmi_s_close_mic},
+ {MMI_S_INITING, MMI_OP_INIT_DONE, MMI_S_IDLE, mmi_s_initing_op_done},
+ {MMI_S_INITING, MMI_OP_RECONNING, MMI_S_RECONNING,
+ mmi_s_reconnecting_started},
+ {MMI_S_INITING, MMI_OP_PAIRING, MMI_S_PAIRING, mmi_s_paring_started},
+ {MMI_S_RECONNING, MMI_OP_CONNECTED, MMI_S_CONNECTED,
+ mmi_s_reconnecting_connected},
+ {MMI_S_RECONNING, MMI_OP_RECONN_TOUT, MMI_S_IDLE, mmi_s_reconnecting_tout},
+ {MMI_S_RECONNING, MMI_OP_ADV_STOPPED, MMI_S_IDLE, NULL},
+ {MMI_S_PAIRING, MMI_OP_CONNECTED, MMI_S_PAIRING, mmi_s_pairing_connected},
+#ifdef CFG_ATVRC_WAKEUP
+ {MMI_S_IDLE, MMI_OP_RECONN_TOUT, MMI_S_IDLE, NULL},
+ {MMI_S_RECONNING, MMI_OP_DISCONNING, MMI_S_IDLE, NULL},
+ {MMI_S_PAIRING, MMI_OP_DISCONNING, MMI_S_PAIRING, NULL},
+#else
+ {MMI_S_PAIRING, MMI_OP_DISCONNING, MMI_S_DISCONNING, mmi_s_disconnecting},
+#endif
+ {MMI_S_PAIRING, MMI_OP_DISCONNED, MMI_S_IDLE, mmi_s_pairing_disconnected},
+ {MMI_S_PAIRING, MMI_OP_PAIR_FAIL, MMI_S_CONNECTED, mmi_s_pairing_stopped},
+ {MMI_S_PAIRING, MMI_OP_PAIR_TOUT, MMI_S_IDLE, mmi_s_pairing_stopped},
+ {MMI_S_PAIRING, MMI_OP_PAIR_SUCCESS, MMI_S_CONNECTED,
+ mmi_s_pairing_success_stopped},
+ {MMI_S_PAIRING, MMI_OP_ADV_STOPPED, MMI_S_IDLE, mmi_s_pairing_stopped},
+#ifdef CFG_VOHID
+ {MMI_S_PAIRING, MMI_OP_HID_READY, MMI_S_HID_READY,
+ mmi_s_hid_ready_pairing_stopped},
+ {MMI_S_CONNECTED, MMI_OP_HID_READY, MMI_S_HID_READY, mmi_s_hid_ready},
+#else
+ {MMI_S_PAIRING, MMI_OP_HID_READY, MMI_S_HID_ONLY,
+ mmi_s_hid_ready_pairing_stopped},
+#ifdef CFG_ATVRC_AUDIO
+ {MMI_S_PAIRING, MMI_OP_ATVV_UNREADY, MMI_S_PAIRING, NULL},
+ {MMI_S_PAIRING, MMI_OP_ATVV_READY, MMI_S_ATVV_ONLY, NULL},
+ {MMI_S_ATVV_ONLY, MMI_OP_PAIR_SUCCESS, MMI_S_ATVV_ONLY, NULL},
+ {MMI_S_ATVV_ONLY, MMI_OP_PAIR_FAIL, MMI_S_ATVV_ONLY, NULL},
+#endif
+ {MMI_S_CONNECTED, MMI_OP_ATVV_READY, MMI_S_ATVV_ONLY, NULL},
+ {MMI_S_CONNECTED, MMI_OP_HID_READY, MMI_S_HID_ONLY, mmi_s_hid_ready},
+#endif
+ {MMI_S_CONNECTED, MMI_OP_DISCONNING, MMI_S_DISCONNING, mmi_s_disconnecting},
+ {MMI_S_CONNECTED, MMI_OP_DISCONNED, MMI_S_IDLE, mmi_s_disconnected},
+#ifndef CFG_VOHID
+ {MMI_S_CONNECTED, MMI_OP_ATVV_UNREADY, MMI_S_CONNECTED, NULL},
+#endif
+ {MMI_S_CONNECTED, MMI_OP_PAIR_SUCCESS, MMI_S_CONNECTED, NULL},
+ {MMI_S_CONNECTED, MMI_OP_PAIR_FAIL, MMI_S_CONNECTED, NULL},
+#ifdef CFG_VOHID
+ {MMI_S_HID_READY, MMI_OP_OPEN_MIC, MMI_S_HID_STREAMING, mmi_s_open_mic},
+ {MMI_S_HID_READY, MMI_OP_DISCONNED, MMI_S_IDLE, mmi_s_prf_disconnected},
+ {MMI_S_HID_READY, MMI_OP_DISCONNING, MMI_S_DISCONNING, mmi_s_disconnecting},
+ {MMI_S_HID_STREAMING, MMI_OP_OPEN_MIC, MMI_S_HID_STREAMING,
+ mmi_s_streaming_open_mic},
+ {MMI_S_HID_STREAMING, MMI_OP_CLOSE_MIC, MMI_S_HID_READY, mmi_s_close_mic},
+ {MMI_S_HID_STREAMING, MMI_OP_DISCONNED, MMI_S_IDLE,
+ mmi_s_unexp_disconnected},
+#else
+ {MMI_S_HID_ONLY, MMI_OP_ATVV_READY, MMI_S_HID_ATVV, mmi_s_hid_ready},
+ {MMI_S_HID_ONLY, MMI_OP_ATVV_UNREADY, MMI_S_HID_ONLY, NULL},
+ {MMI_S_ATVV_ONLY, MMI_OP_ATVV_UNREADY, MMI_S_CONNECTED, NULL},
+ {MMI_S_ATVV_ONLY, MMI_OP_HID_READY, MMI_S_HID_ATVV, mmi_s_hid_ready},
+ {MMI_S_ATVV_ONLY, MMI_OP_ATVV_READY, MMI_S_ATVV_ONLY, NULL},
+ {MMI_S_ATVV_ONLY, MMI_OP_DISCONNED, MMI_S_IDLE, mmi_s_prf_disconnected},
+ {MMI_S_HID_ATVV, MMI_OP_ATVV_READY, MMI_S_HID_ATVV, NULL},
+ {MMI_S_HID_ATVV, MMI_OP_ATVV_UNREADY, MMI_S_HID_ONLY, NULL},
+ {MMI_S_HID_ATVV, MMI_OP_OPEN_MIC, MMI_S_ATVVING, mmi_s_open_mic},
+ {MMI_S_HID_ATVV, MMI_OP_DISCONNED, MMI_S_IDLE, mmi_s_prf_disconnected},
+ {MMI_S_ATVV_ONLY, MMI_OP_DISCONNING, MMI_S_DISCONNING, mmi_s_disconnecting},
+ {MMI_S_HID_ATVV, MMI_OP_DISCONNING, MMI_S_DISCONNING, mmi_s_disconnecting},
+ {MMI_S_HID_ONLY, MMI_OP_DISCONNING, MMI_S_DISCONNING, mmi_s_disconnecting},
+ {MMI_S_HID_ONLY, MMI_OP_DISCONNED, MMI_S_IDLE, mmi_s_prf_disconnected},
+ {MMI_S_ATVVING, MMI_OP_CLOSE_MIC, MMI_S_HID_ATVV, mmi_s_close_mic},
+ {MMI_S_ATVVING, MMI_OP_OPEN_MIC, MMI_S_ATVVING, mmi_s_streaming_open_mic},
+ {MMI_S_ATVVING, MMI_OP_DISCONNED, MMI_S_IDLE, mmi_s_unexp_disconnected},
+ {MMI_S_HID_ATVV, MMI_OP_CLOSE_MIC, MMI_S_HID_ATVV, NULL},
+#endif
+ {MMI_S_DISCONNING, MMI_OP_DISCONNED, MMI_S_IDLE, mmi_s_disconnected},
+ {MMI_S_RF_TEST, MMI_OP_DISCONNED, MMI_S_RF_TEST, NULL},
+};
+
+static void rc_batt_app_start(void (*done)(void))
+{
+ rc_mmi_transition(MMI_OP_INITING);
+
+ app_batt_done_cb = done;
+}
+
+static void rc_batt_app_stop(void (*done)(void))
+{
+ if (atm_asm_get_current_state(MMI_S_TBL_IDX) != MMI_S_BOOTED) {
+ led_off(LED_0);
+ rc_gap_stop();
+ }
+ done();
+}
+
+static rep_vec_err_t rc_mmi_plf_reset(void)
+{
+ led_off(LED_0);
+
+ return (RV_NEXT);
+}
+
+void rc_mmi_init(void)
+{
+ RV_PLF_RESET_ADD(rc_mmi_plf_reset);
+#ifdef CFG_ATVRC_CUSTOM
+ atvrc_custom_init();
+ rc_mmi_vkey_update_ui(atvrc_custom_get_ui_layout());
+#endif
+#if defined(CFG_ATVRC_UNI_IR) || defined(CFG_ATVRC_AUDIO)
+ bridge_att_init();
+#endif
+#ifdef CFG_ATVRC_UNI_IR
+ bridge_ir_init();
+#endif
+#ifdef CFG_ATVRC_AUDIO
+ bridge_audio_init();
+#endif
+#ifdef CFG_ATVRC_FIND_ME
+ bridge_fms_init();
+#endif
+ atm_asm_init_table(MMI_S_TBL_IDX, mmi_s_tbl, ARRAY_LEN(mmi_s_tbl));
+ atm_asm_reg_state_change_cb(MMI_S_TBL_IDX, rc_s_changed);
+ atm_asm_set_current_state(MMI_S_TBL_IDX, MMI_S_BOOTED);
+ static app_batt_cbs_t const cbs = {
+ .app_start = rc_batt_app_start,
+ .app_stop = rc_batt_app_stop,
+ .level_update = app_bass_send_battery_lvl,
+ };
+ app_batt_start(&cbs);
+}
+
+void rc_mmi_idle_timer(mmi_tout_t op)
+{
+ uint8_t state = atm_asm_get_current_state(MMI_S_TBL_IDX);
+ switch (op) {
+ case MMI_TOUT_START: {
+#ifdef CFG_VOHID
+ if (state == MMI_S_HID_READY) {
+#else
+ if (state == MMI_S_HID_ONLY || state == MMI_S_HID_ATVV) {
+#endif
+ if (RC_CONN_READY_TOUT_CS) {
+ sw_timer_set(rc_tid_mmi_idle, RC_CONN_READY_TOUT_CS);
+ } else {
+ sw_timer_clear(rc_tid_mmi_idle);
+ }
+ } else {
+ if (RC_CONN_NOT_READY_TOUT_CS) {
+ sw_timer_set(rc_tid_mmi_idle, RC_CONN_NOT_READY_TOUT_CS);
+ } else {
+ sw_timer_clear(rc_tid_mmi_idle);
+ }
+ }
+ } break;
+ case MMI_TOUT_STOP: {
+ sw_timer_clear(rc_tid_mmi_idle);
+ } break;
+ case MMI_TOUT_FORCE: {
+ sw_timer_set(rc_tid_mmi_idle, 100);
+ } break;
+ default:
+ break;
+ }
+}
+
+#ifdef CFG_PDM_LOCAL_TEST
+#define MAX_TEST_TIME_CS 5000
+#define MIN_TEST_TIME_CS 500
+#ifndef TEST_COUNT
+#define TEST_COUNT 20
+#endif
+
+static char const * const test_type_str [] = {
+ "", "", "Frequency test", "Overflow test", "No buffer test"
+};
+static sw_timer_id_t test_tid;
+static uint16_t test_count;
+static void start_test(void)
+{
+ test_op = (rand() % (RC_PDM_LOCAL_TEST_MAX - 2)) + 2;
+ uint32_t test_time = (rand() % (MAX_TEST_TIME_CS - MIN_TEST_TIME_CS)) +
+ MIN_TEST_TIME_CS;
+ sw_timer_set(test_tid, test_time);
+ sw_timer_clear(rc_tid_mmi_idle);
+ rc_pdm_device_pwr_on();
+#ifdef CFG_VOHID
+ rc_hidau_test_start();
+#else
+ rc_atvv_test_start();
+#endif
+ rc_mmi_open_mic();
+ ATM_LOG(N, "PDM testing[%d] (%" PRIu32 " s): " ATM_VT_SGR "%s" ATM_VT_SGR,
+ test_count, CO_DIVIDE_ROUND(test_time, 100), ATM_FG_CYAN,
+ test_type_str[test_op], ATM_DE_COLOR);
+
+}
+
+static void stop_start(sw_timer_id_t tid, void const *ctx)
+{
+ atm_asm_set_current_state(MMI_S_TBL_IDX, MMI_S_PDM_TEST);
+ static bool not_first_time;
+ if (not_first_time) {
+ rc_pdm_stop();
+ } else {
+ not_first_time = true;
+ }
+
+ if (++test_count == TEST_COUNT) {
+ ATM_LOG(N, "pdm_local_test passed !");
+#ifdef AUTO_TEST
+ UartEndSimulation();
+#endif
+ return;
+ }
+ start_test();
+}
+#endif // CFG_PDM_LOCAL_TEST
+
+void rc_mmi_enter_test(mmi_test_t op)
+{
+ switch(op) {
+ case MMI_TEST_KEY: {
+ ATM_LOG(N, "key current test start!! 6000 times");
+ key_auto_test = 6000;
+ sw_timer_set(rc_tid_key_test, (uint16_t)(50));
+ rc_mmi_idle_timer(MMI_TOUT_STOP);
+ } break;
+ case MMI_TEST_RF: {
+ ATM_LOG(N, "rftest");
+ atm_asm_set_current_state(MMI_S_TBL_IDX, MMI_S_RF_TEST);
+ led_blink(LED_0, 10, 10, 0xffff);
+ rc_gap_enter_rf_test();
+ } break;
+#ifndef CFG_VOHID
+ case MMI_TEST_ATVV: {
+ rc_mmi_idle_timer(MMI_TOUT_STOP);
+ atvv_test_cnt_left = ATVV_PEER_TEST_COUNT;
+ sw_timer_set(rc_tid_atvv_test, (uint16_t)(50));
+ } break;
+#endif
+#ifdef CFG_PDM_LOCAL_TEST
+ case MMI_TEST_PDM: {
+ test_tid = sw_timer_alloc(stop_start, NULL);
+ sw_timer_set(test_tid, 10);
+ } break;
+#endif // CFG_PDM_LOCAL_TEST
+ default:
+ break;
+ }
+}
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi.h
new file mode 100644
index 0000000..57bd473
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi.h
@@ -0,0 +1,146 @@
+/*
+ *******************************************************************************
+ *
+ * @file rc_mmi.c
+ *
+ * @brief MMI of Atmosic remote controller reference design.
+ *
+ * Copyright (C) Atmosic 2020-2021
+ *
+ *******************************************************************************
+ */
+#pragma once
+
+/// MMI states
+typedef enum {
+ /// System booted.
+ MMI_S_BOOTED,
+ /// Initialing.
+ MMI_S_INITING,
+ /// Initialized.
+ MMI_S_IDLE,
+ /// Pairing.
+ MMI_S_PAIRING,
+ /// Reconnecting.
+ MMI_S_RECONNING,
+ /// Connected but no profile ready.
+ MMI_S_CONNECTED,
+#ifdef CFG_VOHID
+ /// HID is ready
+ MMI_S_HID_READY,
+ /// Audio streaming
+ MMI_S_HID_STREAMING,
+#else
+ /// ATVV is ready but HID isn't.
+ MMI_S_ATVV_ONLY,
+ /// HID is ready but ATVV isn't.
+ MMI_S_HID_ONLY,
+ /// HID and ATVV are ready.
+ MMI_S_HID_ATVV,
+ /// ATVV is transferring audio.
+ MMI_S_ATVVING,
+#endif
+ /// Disconnecting.
+ MMI_S_DISCONNING,
+ /// Under RF testing mode.
+ MMI_S_RF_TEST,
+ /// Under PDM local test
+ MMI_S_PDM_TEST,
+ /// Dummy state for marking.
+ MMI_S_END
+} mmi_state_t;
+
+/// MMI operations for MMI state transition
+typedef enum {
+ /// Started initialing.
+ MMI_OP_INITING,
+ /// Initialized.
+ MMI_OP_INIT_DONE,
+ /// Started reconnecting.
+ MMI_OP_RECONNING,
+ /// Started pairing.
+ MMI_OP_PAIRING,
+ /// Pairing failed.
+ MMI_OP_PAIR_FAIL,
+ /// Reconnection timeout.
+ MMI_OP_RECONN_TOUT,
+ /// Pairing timeout.
+ MMI_OP_PAIR_TOUT,
+ /// Pairing success.
+ MMI_OP_PAIR_SUCCESS,
+ /// Connected.
+ MMI_OP_CONNECTED,
+ /// Disconnected.
+ MMI_OP_DISCONNED,
+ /// HOGP became ready.
+ MMI_OP_HID_READY,
+#ifndef CFG_VOHID
+ /// ATVV became ready.
+ MMI_OP_ATVV_READY,
+#endif
+ /// HOGP became unready.
+ MMI_OP_HID_UNREADY,
+#ifndef CFG_VOHID
+ /// ATVV became unready.
+ MMI_OP_ATVV_UNREADY,
+#endif
+ /// Started transferring audio.
+ MMI_OP_OPEN_MIC,
+ /// Stopped transferring audio.
+ MMI_OP_CLOSE_MIC,
+ /// Started disconnecting.
+ MMI_OP_DISCONNING,
+ /// ADV became stopped.
+ MMI_OP_ADV_STOPPED,
+ /// Number of MMI operations
+ MMI_OP_NUM
+} mmi_op_t;
+
+/// MMI timeout setting for @ref rc_mmi_idle_timer API
+typedef enum mmi_tout_s {
+ /// Enable and reset MMI timeout timer.
+ MMI_TOUT_START,
+ /// Disable and clear MMI timeout timer.
+ MMI_TOUT_STOP,
+ /// Force MMI timeout in a short time.
+ MMI_TOUT_FORCE,
+} mmi_tout_t;
+
+/// MMI test mode type for @ref rc_mmi_enter_test API
+typedef enum mmi_test_s {
+#ifndef CFG_VOHID
+ /// ATVV auto test.
+ MMI_TEST_ATVV,
+#endif
+ /// RF test.
+ MMI_TEST_RF,
+ /// KEY auto test.
+ MMI_TEST_KEY,
+#ifdef CFG_PDM_LOCAL_TEST
+ /// PDM local test.
+ MMI_TEST_PDM,
+#endif
+} mmi_test_t;
+
+/**
+ * @brief MMI state machine initialization.
+ */
+void rc_mmi_init(void);
+
+/**
+ * @brief MMI state transition.
+ * @param[in] op Current operation.
+ */
+void rc_mmi_transition(mmi_op_t op);
+
+/**
+ * @brief MMI idle timer setting.
+ * @param[in] op Operation.
+ */
+void rc_mmi_idle_timer(mmi_tout_t op);
+
+/**
+ * @brief Enter test mode.
+ * @param[in] op Test mode.
+ */
+void rc_mmi_enter_test(mmi_test_t op);
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi_vkey.c b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi_vkey.c
new file mode 100644
index 0000000..7211761
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi_vkey.c
@@ -0,0 +1,751 @@
+/*
+ *******************************************************************************
+ *
+ * @file rc_mmi_vkey.c
+ *
+ * @brief VKEY application part.
+ *
+ * Copyright (C) Atmosic 2020-2022
+ *
+ *******************************************************************************
+ */
+
+#include <inttypes.h>
+#include "app_config.h"
+#include "rc_hogp.h"
+
+#ifdef CFG_VOHID
+#include "rc_hidau.h"
+#else
+#include "rc_atvv.h"
+#endif
+#include "rc_gap.h"
+#include "rc_mmi.h"
+#include "rc_mmi_vkey.h"
+#include "led_blink.h"
+#include "rc_pdm.h"
+#include "rc_ir.h"
+#include "atm_debug.h"
+#include "keyboard.h"
+#include "co_utils.h"
+#include "atm_asm.h"
+#include "atm_vkey.h"
+#include "atm_pm.h"
+#if defined(CFG_ATVRC_CUSTOM) && defined(CFG_ATVRC_WAKEUP)
+#include "atvrc_custom.h"
+#endif
+#ifdef LED_UART_MUX
+#include "timer.h"
+#include "at_wrpr.h"
+#include "at_pinmux.h"
+#include "pinmux.h"
+#endif
+#ifdef CFG_EN_GHOSTKEY
+#include "keyboard_ghostkey.h"
+#endif
+#include "rc_keycode.h"
+#include STR(VKEY_MAP_FILE)
+
+#ifdef CFG_ATVRC_FIND_ME
+#include "buzzer.h"
+#endif
+
+#ifdef CFG_ATVRC_MMI
+#include "timer.h"
+#include "sw_timer.h"
+static sw_timer_id_t tid_delay_reset;
+#define VK_MIC VK_ASST
+#define VK_OK VK_CENTER
+static bool wait_comb_key;
+#endif
+
+STATIC_ASSERT(ARRAY_LEN(bt_keycode) <= ATM_VKEY_MAX,
+ "Vkey number exceeds ATM_VKEY_MAX");
+
+#ifndef CFG_VKEY_BUF
+static uint32_t mmi_saved_key;
+#endif
+static pm_lock_id_t rc_vk_lock_hiber;
+
+enum {
+ VKEY_TABLE_HID_NOT_READY,
+ VKEY_TABLE_HID_READY,
+ VKEY_TABLE_RF_TEST,
+ VKEY_TABLE_MAX
+};
+
+typedef struct {
+ void *handle[VKEY_TABLE_MAX];
+ uint8_t cur_state;
+ uint8_t cur_hdl_idx;
+} rc_mmi_vkey_ctx_t;
+
+#ifdef CFG_RC_IR
+#define RC_IR_DELAY_CS 9
+#define RC_IR_DELAY_ON_HID_CS 6
+#endif
+
+// Time for led on while key down
+#define KEY_DOWN_LED_INTERVAL_CS 10
+
+// VKEY_DOWN_FIRST => send key down
+static void send_rpt(atm_vk_idx_t vkey, void const *ctx)
+{
+ rc_mmi_vkey_ctx_t const *context = ctx;
+
+ rc_mmi_idle_timer(MMI_TOUT_START);
+ led_blink(LED_0, KEY_DOWN_LED_INTERVAL_CS, 0, 0x1);
+ if (bt_keycode[vkey] == BT_MIC) {
+#ifdef CFG_VOHID
+ if (context->cur_state == MMI_S_HID_READY) {
+ rc_gap_local_slave_latency(true);
+ rc_hidau_start_search();
+ } else if (context->cur_state == MMI_S_HID_STREAMING) {
+ rc_hidau_stop_search();
+ }
+#else // CFG_VOHID
+ // Dealing with ATVV (only allowed in ATVV ready)
+ if ((context->cur_state == MMI_S_HID_ATVV) ||
+#ifdef CFG_ATVV_VER_100
+ (context->cur_state == MMI_S_ATVVING) ||
+#endif
+ (context->cur_state == MMI_S_ATVV_ONLY)) {
+ rc_gap_local_slave_latency(true);
+ rc_atvv_start_search();
+ } else if (context->cur_state != MMI_S_ATVVING) {
+ DEBUG_TRACE("Peer didn't enable ATVV");
+ }
+ if (rc_atvv_is_legacy_model()) {
+ rc_hogp_send_single_key(BT_MIC);
+ rc_hogp_send_single_key(CSM(0));
+#ifdef CFG_ATVRC_MMI
+ led_on(LED_0);
+#endif
+ } else if (rc_atvv_is_htt_model()) {
+ led_on(LED_0);
+ }
+#ifdef CFG_ATVRC_MMI
+ else {
+ led_blink(LED_0, 50, 50, 0xffff);
+ }
+#endif
+#endif // CFG_VOHID
+ } else {
+#ifdef CFG_ATVRC_UNI_IR
+ if (rc_ir_check_uni_key(atv_keycode[vkey])) {
+ led_blink(LED_0, ATVRC_LED_KEY_CS, 0, ATVRC_LED_KEY_BLINK);
+ led_blink(LED_1, ATVRC_LED_KEY_CS, 0, ATVRC_LED_KEY_BLINK);
+ return;
+ }
+#endif
+ rc_hogp_send_single_key(bt_keycode[vkey]);
+#ifndef CFG_VOHID
+ if (bt_keycode[vkey] == BT_OK) {
+ rc_atvv_dpad_select();
+ }
+#endif
+#ifdef CFG_RC_IR_ON_HID
+ rc_ir_send(ir_addr[vkey], ir_cmd[vkey],
+ RC_IR_DELAY_ON_HID_CS);
+#endif
+ }
+ return;
+}
+
+static void rc_send_rpt(atm_vk_dnup_evt_t const *evt, void const *ctx)
+{
+#ifdef CFG_ATVRC_FIND_ME
+ buzzer_stop();
+#endif
+ send_rpt(evt->top.vkey, ctx);
+}
+
+static bool comb_rpt_sent;
+static void rc_send_comb_rpt(atm_vk_dnup_inter_evt_t const *evt,
+ void const *ctx)
+{
+ if (comb_rpt_sent) {
+ // No more combined reports until release all keys.
+ return;
+ }
+ send_rpt(evt->top.vkey, ctx);
+ comb_rpt_sent = true;
+}
+
+static void rc_sent_up_(atm_vk_dnup_inter_evt_t const *evt, void const *ctx)
+{
+ rc_mmi_idle_timer(MMI_TOUT_START);
+ rc_hogp_send_single_key(bt_keycode[evt->top.vkey] & ~0xFFFF);
+#ifdef CFG_RC_IR_ON_HID
+ rc_ir_repeat_end();
+#endif
+ return;
+}
+
+// VKEY_UP_LAST => send key up
+static void rc_sent_up(atm_vk_dnup_evt_t const *evt, void const *ctx)
+{
+ comb_rpt_sent = false;
+ rc_mmi_idle_timer(MMI_TOUT_START);
+ rc_hogp_send_single_key(bt_keycode[evt->top.vkey] & ~0xFFFF);
+#ifdef CFG_RC_IR_ON_HID
+ rc_ir_repeat_end();
+#endif
+#ifdef CFG_ATVRC_UNI_IR
+ rc_ir_repeat_end();
+#endif
+#ifdef CFG_ATVRC_MMI
+ // static LED during voice search
+ if ((bt_keycode[evt->top.vkey] == BT_MIC) && !rc_atvv_is_htt_model()) {
+ return;
+ }
+#endif
+ led_off(LED_0);
+ return;
+}
+
+static void rc_mic_up(atm_vk_dnup_evt_t const *evt, void const *ctx)
+{
+#ifdef CFG_ATVV_VER_100
+ if (!rc_atvv_is_htt_model()) {
+ return;
+ }
+ rc_mmi_vkey_ctx_t const *context = ctx;
+ if (context->cur_state == MMI_S_ATVVING) {
+ rc_atvv_stop_search();
+ }
+#endif
+}
+
+#ifdef CFG_RC_IR
+static void rc_save_key_up(atm_vk_dnup_evt_t const *evt, void const *ctx)
+{
+ rc_ir_repeat_end();
+ return;
+}
+#endif
+
+static bool rc_hold_test(atm_vk_hd_evt_t const *evt, void const *ctx)
+{
+ return evt->time_ms < 4000;
+}
+
+#ifdef CFG_RC_TEST_MODE
+#include "rc_test_mode.h"
+static void rc_ok_up(atm_vk_dnup_evt_t const *evt, void const *ctx)
+{
+ rc_test_mode_control(RC_TEST_CANCEL);
+}
+
+static void rc_ok_click(atm_vk_hc_evt_t const *evt, void const *ctx)
+{
+ switch (evt->top.u8vkey) {
+ case VK_UP:
+ case VK_DOWN:
+ case VK_RIGHT:
+ case VK_LEFT: {
+ rc_test_input_t num;
+ if (evt->top.u8vkey == VK_UP) {
+ num = RC_TEST_U_GOT;
+ } else if (evt->top.u8vkey == VK_DOWN) {
+ num = RC_TEST_D_GOT;
+ } else if (evt->top.u8vkey == VK_RIGHT) {
+ num = RC_TEST_R_GOT;
+ } else if (evt->top.u8vkey == VK_LEFT) {
+ num = RC_TEST_L_GOT;
+ } else {
+ num = RC_TEST_CANCEL;
+ }
+ rc_test_mode_control(num);
+ } break;
+ default:
+ rc_test_mode_control(RC_TEST_CANCEL);
+ break;
+ }
+}
+
+static bool rc_ok_back(atm_vk_hd_evt_t const *evt, void const *ctx)
+{
+ return false;
+}
+
+static void rc_ok_back_sts(bool pressed, void const *ctx)
+{
+ if (pressed) {
+ rc_test_mode_control(RC_TEST_CANCEL);
+ }
+}
+
+#endif
+
+static bool rc_del_bond(atm_vk_hd_evt_t const *evt, void const *ctx)
+{
+#ifdef CFG_ATVRC_MMI
+ if (sw_timer_active(tid_delay_reset)) {
+ return true;
+ }
+#endif
+ rc_gap_remove_all_bond();
+ led_off(LED_0);
+#ifdef CFG_ATVRC_UNI_IR
+ rc_ir_clear_uni_codes();
+#endif
+#ifdef CFG_ATVRC_MMI
+ atm_timer_mdelay(100);
+ led_blink(LED_0, ATVRC_LED_CFM_CS, ATVRC_LED_CFM_CS, ATVRC_LED_CFM_BLINK);
+ wait_comb_key = false;
+#define ATVRC_LED_CFM_DELAY_CS (ATVRC_LED_CFM_CS * 5)
+ sw_timer_set(tid_delay_reset, ATVRC_LED_CFM_DELAY_CS);
+#else
+ platform_reset(RESET_NO_ERROR);
+#endif
+ return true;
+}
+
+static bool rc_pair_mode(atm_vk_hd_evt_t const *evt, void const *ctx)
+{
+ rc_gap_enter_pairing_next_boot(true);
+ led_off(LED_0);
+ platform_reset(RESET_NO_ERROR);
+ return true;
+}
+
+#ifdef CFG_ATVRC_MMI
+static void rc_comb_key_led_ctl(bool pressed)
+{
+ if (pressed && !wait_comb_key) {
+ wait_comb_key = true;
+ led_on(LED_0);
+ } else if (!pressed && wait_comb_key) {
+ wait_comb_key = false;
+ led_off(LED_0);
+ }
+}
+
+static bool rc_bug_report(atm_vk_hd_evt_t const *evt, void const *ctx)
+{
+ DEBUG_TRACE("BUG_REPORT");
+ wait_comb_key = false;
+ led_blink(LED_0, KEY_DOWN_LED_INTERVAL_CS, KEY_DOWN_LED_INTERVAL_CS, 2);
+#ifdef CFG_RC_IR
+ rc_ir_send(IR_ADDR, IR_BUGR, RC_IR_DELAY_CS);
+#endif
+ return false;
+}
+
+static bool rc_access_shortcut(atm_vk_hd_evt_t const *evt, void const *ctx)
+{
+ DEBUG_TRACE("ACCESS_SHORTCUT");
+ wait_comb_key = false;
+ return false;
+}
+#endif // CFG_ATVRC_MMI
+
+static void rc_atvv_test(atm_vk_hc_evt_t const *evt, void const *ctx)
+{
+ if (evt->top.u8vkey == VK_VOLUP) {
+ rc_pdm_gain_adjust(true);
+ } else if (evt->top.u8vkey == VK_VOLDN) {
+ rc_pdm_gain_adjust(false);
+ } else if (evt->top.u8vkey == VK_MIC) {
+#ifndef CFG_VOHID
+ rc_mmi_enter_test(MMI_TEST_ATVV);
+#endif
+ }
+ return;
+}
+
+static void rc_reset(atm_vk_hc_evt_t const *evt, void const *ctx)
+{
+ platform_reset(RESET_NO_ERROR);
+ return;
+}
+
+static void rc_keytest(atm_vk_hc_evt_t const *evt, void const *ctx)
+{
+ rc_mmi_enter_test(MMI_TEST_KEY);
+ return;
+}
+
+static void rc_disconnect(atm_vk_hc_evt_t const *evt, void const *ctx)
+{
+ rc_mmi_idle_timer(MMI_TOUT_FORCE);
+ led_off(LED_0);
+ return;
+}
+
+static void rc_enter_rftest(atm_vk_hc_evt_t const *evt, void const *ctx)
+{
+ rc_mmi_enter_test(MMI_TEST_RF);
+ return;
+}
+
+#ifdef CFG_VKEY_BUF
+#include "co_list.h"
+#include "ke_mem.h"
+
+/// Report buffer
+static struct co_list vk_buf;
+
+/// Vkey buffer element
+typedef struct {
+ /// list element header
+ struct co_list_hdr hdr;
+ /// report
+ atm_vk_idx_t vkey;
+ /// ctx
+ void const *ctx;
+} vk_elmt_t;
+
+static vk_elmt_t *rc_mmi_vkey_pop_from_buf(void)
+{
+ return (vk_elmt_t *)co_list_pop_front(&vk_buf);
+}
+
+void rc_mmi_vkey_free_buf(void)
+{
+ vk_elmt_t *val;
+
+ while((val = rc_mmi_vkey_pop_from_buf()) != NULL) {
+ ke_free(val);
+ }
+}
+
+static void rc_mmi_vkey_push_to_buf(atm_vk_idx_t vkey, void const *ctx)
+{
+ if (bt_keycode[vkey] == BT_MIC) {
+ return;
+ }
+#define VKEY_BUF_MAX 20
+ if (co_list_size(&vk_buf) > VKEY_BUF_MAX) {
+ rc_mmi_vkey_free_buf();
+ DEBUG_TRACE("Buf-Overflow");
+ } else {
+ vk_elmt_t *val = ke_malloc(sizeof(vk_elmt_t), KE_MEM_ENV);
+
+ val->vkey = vkey;
+ val->ctx = ctx;
+ co_list_push_back(&vk_buf, &val->hdr);
+ }
+}
+
+static vk_elmt_t *rc_mmi_vkey_peek_from_buf(void)
+{
+ return (vk_elmt_t *)(vk_buf.first);
+}
+
+void rc_mmi_vkey_flush_buf(void)
+{
+ DEBUG_TRACE("%s size: %d", __func__, co_list_size(&vk_buf));
+ for (vk_elmt_t *val = rc_mmi_vkey_peek_from_buf(); val;
+ val = rc_mmi_vkey_peek_from_buf()) {
+ send_rpt(val->vkey, val->ctx);
+ ke_free(rc_mmi_vkey_pop_from_buf());
+ }
+}
+#endif
+
+#ifdef LED_UART_MUX
+static uint32_t rc_mmi_vkey_init_ms;
+#endif
+
+static void rc_save_key(atm_vk_dnup_evt_t const *evt, void const *ctx)
+{
+#ifdef CFG_ATVRC_FIND_ME
+ buzzer_stop();
+#endif
+ DEBUG_TRACE("%s key: %d", __func__, evt->top.u8vkey);
+ rc_mmi_vkey_ctx_t const *context = ctx;
+#ifdef LED_UART_MUX
+ if ((evt->top.u8vkey == VK_RICE) && (atm_lpc_to_ms(atm_get_sys_time())
+ - rc_mmi_vkey_init_ms < 1000)) {
+ PINMUX_UART_SET(1, TX);
+ }
+#endif
+#if defined(CFG_ATVRC_CUSTOM) && defined(CFG_ATVRC_WAKEUP)
+ if ((context->cur_state == MMI_S_INITING) || (context->cur_state ==
+ MMI_S_RECONNING) || (context->cur_state == MMI_S_IDLE)) {
+ uint8_t id = atvrc_custom_check_wake_key(bt_keycode[evt->top.u8vkey]);
+ if (id) {
+ rc_gap_set_wake(id);
+ }
+ }
+#endif
+#ifdef CFG_ATVRC_UNI_IR
+ if (rc_ir_check_uni_key(atv_keycode[evt->top.u8vkey])) {
+ led_blink(LED_0, ATVRC_LED_KEY_CS, 0, ATVRC_LED_KEY_BLINK);
+ led_blink(LED_1, ATVRC_LED_KEY_CS, 0, ATVRC_LED_KEY_BLINK);
+ return;
+ }
+#endif
+#ifdef CFG_ATVRC_CUSTOM
+ if ((context->cur_state == MMI_S_PAIRING) &&
+ (bt_keycode[evt->top.u8vkey] == BT_BACK)) {
+ DEBUG_TRACE("Stop pairing");
+ rc_gap_discoverable(false);
+ }
+ led_blink(LED_1, ATVRC_LED_KEY_CS, 0, ATVRC_LED_KEY_BLINK);
+#else
+ if (context->cur_state == MMI_S_IDLE) {
+ rc_gap_discoverable(true);
+ }
+#endif
+#ifdef CFG_RC_IR
+ rc_ir_send(ir_addr[evt->top.vkey], ir_cmd[evt->top.vkey],
+ RC_IR_DELAY_CS);
+#endif
+#ifdef CFG_ATVRC_CUSTOM
+ if (!atvrc_custom_is_cache_pwr() && (evt->top.u8vkey == VK_POWER)) {
+ return;
+ }
+#endif
+#ifdef CFG_VKEY_BUF
+ rc_mmi_vkey_push_to_buf(evt->top.vkey, ctx);
+#else
+ mmi_saved_key = bt_keycode[evt->top.vkey];
+#endif
+ return;
+}
+
+static void rc_rftest(atm_vk_dnup_evt_t const *evt, void const *ctx)
+{
+ switch (bt_keycode[evt->top.vkey]) {
+ case BT_UP: {
+ rc_gap_rf_test_adjust(true, RC_RFTEST_CH);
+ } break;
+ case BT_DOWN: {
+ rc_gap_rf_test_adjust(false, RC_RFTEST_CH);
+ } break;
+ case BT_VOLU: {
+ rc_gap_rf_test_adjust(true, RC_RFTEST_PWR);
+ } break;
+ case BT_VOLD: {
+ rc_gap_rf_test_adjust(false, RC_RFTEST_PWR);
+ } break;
+ default:
+ break;
+ }
+ return;
+}
+
+static void rc_hold_key_status_ind(bool pressed, void const *ctx)
+{
+ if (pressed) {
+ atm_pm_lock(rc_vk_lock_hiber);
+ return;
+ }
+ atm_pm_unlock(rc_vk_lock_hiber);
+}
+
+#ifdef CFG_ATVRC_MMI
+static void rc_hold_key_status_ind_ex(bool pressed, void const *ctx)
+{
+ rc_hold_key_status_ind(pressed, ctx);
+ rc_comb_key_led_ctl(pressed);
+}
+#endif
+
+#define INVOKE(fm, ...) fm(__VA_ARGS__)
+#ifdef CFG_ATVRC_MMI
+#define VK_RICE VK_MUTE
+#define VK_MENU VK_GUIDE
+#define DEL_BOND_CB_KEY VK_CENTER, VK_MUTE
+#define PAIR_MODE_CB_KEY VK_HOME, VK_BACK
+#define SPEC_FUNC_CB_KEY VK_APP03, VK_APP04
+#else
+#define DEL_BOND_CB_KEY VK_OK, VK_MENU
+#define PAIR_MODE_CB_KEY VK_OK, VK_VOLDN
+#define SPEC_FUNC_CB_KEY VK_FW, VK_BW
+#endif
+
+// Key events in HID ready - VKEY_TABLE_HID_READY
+static atm_vk_reg_t const rc_key_event_hid_ready[] = {
+ VKEY_DOWN_FIRST(rc_send_rpt, atm_vk_any),
+ VKEY_DOWN_MORE(rc_send_comb_rpt, atm_vk_any),
+ VKEY_UP_INTER(rc_sent_up_, atm_vk_any),
+ VKEY_UP_LAST(rc_sent_up, atm_vk_any),
+ VKEY_UP_LAST(rc_mic_up, VK_MIC),
+ VKEY_HOLD_1KEY(rc_hold_test, NULL, 2000, VK_RICE),
+ VKEY_HOLD_1KEY_CLICK(rc_atvv_test, atm_vk_any, VK_RICE),
+#ifdef CFG_ATVRC_MMI
+ INVOKE(VKEY_HOLD_2KEY, rc_pair_mode, rc_hold_key_status_ind_ex, 4000,
+ PAIR_MODE_CB_KEY),
+ INVOKE(VKEY_HOLD_2KEY, rc_del_bond, rc_hold_key_status_ind_ex, 4000,
+ DEL_BOND_CB_KEY),
+ INVOKE(VKEY_HOLD_2KEY, rc_bug_report, rc_hold_key_status_ind_ex, 1000,
+ VK_CENTER, VK_BACK),
+ INVOKE(VKEY_HOLD_2KEY, rc_access_shortcut, rc_hold_key_status_ind, 1000,
+ VK_DOWN, VK_BACK),
+#else
+ INVOKE(VKEY_HOLD_2KEY, rc_del_bond, rc_hold_key_status_ind, 4000,
+ DEL_BOND_CB_KEY),
+ INVOKE(VKEY_HOLD_2KEY, rc_pair_mode, rc_hold_key_status_ind, 2000,
+ PAIR_MODE_CB_KEY),
+ INVOKE(VKEY_HOLD_2KEY, rc_pair_mode, rc_hold_key_status_ind, 4000, VK_HOME,
+ VK_BACK),
+#endif
+ INVOKE(VKEY_HOLD_2KEY_CLICK, rc_reset, VK_MENU, SPEC_FUNC_CB_KEY),
+ INVOKE(VKEY_HOLD_2KEY_CLICK, rc_disconnect, VK_VOLUP, SPEC_FUNC_CB_KEY),
+ INVOKE(VKEY_HOLD_2KEY_CLICK, rc_keytest, VK_OK, SPEC_FUNC_CB_KEY),
+ INVOKE(VKEY_HOLD_2KEY_CLICK, rc_enter_rftest, VK_VOLDN, SPEC_FUNC_CB_KEY),
+
+};
+
+// Key events in HID non-ready - VKEY_TABLE_HID_NOT_READY
+static atm_vk_reg_t const rc_key_event_hid_not_ready[] = {
+ VKEY_DOWN_FIRST(rc_save_key, atm_vk_any),
+#ifdef CFG_RC_IR
+ VKEY_UP_LAST(rc_save_key_up, atm_vk_any),
+#endif // CFG_RC_IR
+#ifdef CFG_ATVRC_MMI
+ INVOKE(VKEY_HOLD_2KEY, rc_bug_report, rc_hold_key_status_ind_ex, 1000,
+ VK_CENTER, VK_BACK),
+ INVOKE(VKEY_HOLD_2KEY, rc_pair_mode, rc_hold_key_status_ind_ex, 4000,
+ PAIR_MODE_CB_KEY),
+ INVOKE(VKEY_HOLD_2KEY, rc_del_bond, rc_hold_key_status_ind_ex, 4000,
+ DEL_BOND_CB_KEY),
+ INVOKE(VKEY_HOLD_2KEY, rc_access_shortcut, rc_hold_key_status_ind, 1000,
+ VK_DOWN, VK_BACK),
+#else
+ INVOKE(VKEY_HOLD_2KEY, rc_del_bond, rc_hold_key_status_ind, 4000,
+ DEL_BOND_CB_KEY),
+ INVOKE(VKEY_HOLD_2KEY, rc_pair_mode, rc_hold_key_status_ind, 2000,
+ PAIR_MODE_CB_KEY),
+ INVOKE(VKEY_HOLD_2KEY, rc_pair_mode, rc_hold_key_status_ind, 4000, VK_HOME,
+ VK_BACK),
+#endif
+ INVOKE(VKEY_HOLD_2KEY_CLICK, rc_reset, VK_MENU, SPEC_FUNC_CB_KEY),
+ INVOKE(VKEY_HOLD_2KEY_CLICK, rc_enter_rftest, VK_VOLDN, SPEC_FUNC_CB_KEY),
+#ifdef CFG_RC_TEST_MODE
+ INVOKE(VKEY_HOLD_2KEY, rc_ok_back, rc_ok_back_sts, 0, VK_OK, VK_BACK),
+ VKEY_UP_LAST(rc_ok_up, VK_OK),
+ VKEY_HOLD_1KEY_CLICK(rc_ok_click, atm_vk_any, VK_OK),
+#endif
+};
+
+// Key events in RF test - VKEY_TABLE_RF_TEST
+static atm_vk_reg_t const rc_key_event_rf_test[] = {
+ INVOKE(VKEY_HOLD_2KEY_CLICK, rc_reset, VK_MENU, SPEC_FUNC_CB_KEY),
+ VKEY_UP_LAST(rc_rftest, atm_vk_any),
+};
+
+static void keyboard_callback(ksm_event_t event, uint32_t idx, void const *ctx)
+{
+ rc_mmi_vkey_ctx_t const *context = ctx;
+ bool pressed = (event == KSM_PRESS);
+ if (context->cur_hdl_idx != VKEY_TABLE_MAX) {
+ atm_vkey_feed(context->handle[context->cur_hdl_idx], idx, pressed);
+ }
+}
+
+#ifdef CFG_ATVRC_MMI
+static void rc_mmi_vkey_delay_reset(sw_timer_id_t idx, void const *ctx)
+{
+ platform_reset(RESET_NO_ERROR);
+}
+#endif
+
+void rc_mmi_vkey_state_change_notify(uint8_t next_state)
+{
+ // enclose the context
+ static rc_mmi_vkey_ctx_t context = {.cur_hdl_idx = VKEY_TABLE_MAX};
+ context.cur_state = next_state;
+
+ switch (next_state) {
+ case MMI_S_INITING: {
+ // key scan driver init
+#ifdef CFG_EN_GHOSTKEY
+ keyboard_run_with_ghostkey_filter(keyboard_callback, &context);
+#else
+ keyboard_run(keyboard_callback, &context);
+#endif
+ // vkey modeling
+ rc_vk_lock_hiber = atm_pm_alloc(PM_LOCK_HIBERNATE);
+ context.handle[VKEY_TABLE_HID_NOT_READY] =
+ atm_vkey_add_table(rc_key_event_hid_not_ready,
+ ARRAY_LEN(rc_key_event_hid_not_ready), &context);
+ context.handle[VKEY_TABLE_HID_READY] =
+ atm_vkey_add_table(rc_key_event_hid_ready,
+ ARRAY_LEN(rc_key_event_hid_ready), &context);
+ context.handle[VKEY_TABLE_RF_TEST] =
+ atm_vkey_add_table(rc_key_event_rf_test,
+ ARRAY_LEN(rc_key_event_rf_test), &context);
+#ifdef LED_UART_MUX
+ rc_mmi_vkey_init_ms = atm_lpc_to_ms(atm_get_sys_time());
+#endif
+#ifdef CFG_ATVRC_MMI
+ tid_delay_reset = sw_timer_alloc(rc_mmi_vkey_delay_reset, NULL);
+#endif
+ }
+ case MMI_S_BOOTED:
+ case MMI_S_IDLE:
+ case MMI_S_PAIRING:
+ case MMI_S_RECONNING:
+#ifndef CFG_VOHID
+ case MMI_S_ATVV_ONLY:
+#endif
+ case MMI_S_CONNECTED: {
+ context.cur_hdl_idx = VKEY_TABLE_HID_NOT_READY;
+ } break;
+#ifdef CFG_VOHID
+ case MMI_S_HID_READY:
+ case MMI_S_HID_STREAMING:
+#else
+ case MMI_S_HID_ONLY:
+ case MMI_S_HID_ATVV:
+ case MMI_S_ATVVING:
+#endif
+ {
+ context.cur_hdl_idx = VKEY_TABLE_HID_READY;
+ } break;
+ case MMI_S_RF_TEST: {
+ context.cur_hdl_idx = VKEY_TABLE_RF_TEST;
+ } break;
+ case MMI_S_DISCONNING:
+ default: {
+ context.cur_hdl_idx = VKEY_TABLE_MAX;
+ } break;
+ }
+}
+
+#ifndef CFG_VKEY_BUF
+uint32_t rc_mmi_vkey_get_saved(void)
+{
+ uint32_t key = mmi_saved_key;
+ DEBUG_TRACE("save key = %" PRIu32, mmi_saved_key);
+
+ return key;
+}
+
+void rc_mmi_vkey_clear_saved(void)
+{
+ mmi_saved_key = 0;
+}
+#endif
+
+#ifdef CFG_ATVRC_CUSTOM
+void rc_mmi_vkey_update_ui(uint8_t ui)
+{
+#define UI_LAYOUT_B0_SETT_MASK 0x01
+#define UI_LAYOUT_B1_LIVE_MASK 0x02
+#define UI_LAYOUT_B3_PROF_MASK 0x08
+#define UI_LAYOUT_B4_ALAP_MASK 0x10
+#define UI_LAYOUT_B3_B4_MASK (UI_LAYOUT_B3_PROF_MASK | UI_LAYOUT_B4_ALAP_MASK)
+ if (ui & UI_LAYOUT_B0_SETT_MASK) {
+ bt_keycode[VK_DASHB] = BT_SETT;
+ ir_cmd[VK_DASHB] = IR_SETT;
+ }
+ if (ui & UI_LAYOUT_B1_LIVE_MASK) {
+ bt_keycode[VK_GUIDE] = BT_LIVE;
+ ir_cmd[VK_GUIDE] = IR_LIVE;
+ }
+ if ((ui & UI_LAYOUT_B3_B4_MASK) == UI_LAYOUT_B3_PROF_MASK) {
+ bt_keycode[VK_BKMK] = BT_PROF;
+ ir_cmd[VK_BKMK] = IR_PROF;
+ }
+ if ((ui & UI_LAYOUT_B3_B4_MASK) == UI_LAYOUT_B4_ALAP_MASK) {
+ bt_keycode[VK_BKMK] = BT_ALAP;
+ ir_cmd[VK_BKMK] = IR_ALAP;
+ }
+}
+#endif \ No newline at end of file
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi_vkey.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi_vkey.h
new file mode 100644
index 0000000..319c7c3
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi_vkey.h
@@ -0,0 +1,50 @@
+/*
+ *******************************************************************************
+ *
+ * @file rc_mmi_vkey.h
+ *
+ * @brief VKEY application part.
+ *
+ * Copyright (C) Atmosic 2020-2021
+ *
+ *******************************************************************************
+ */
+#pragma once
+
+/**
+ *******************************************************************************
+ * @brief Notify MMI state has been changed.
+ *******************************************************************************
+ */
+void rc_mmi_vkey_state_change_notify(uint8_t next_state);
+
+/**
+ * @brief Get saved key.
+ *
+ * @return Key saved. O is invalid.
+ */
+uint32_t rc_mmi_vkey_get_saved(void);
+
+/**
+ * @brief Clear saved key.
+ */
+void rc_mmi_vkey_clear_saved(void);
+
+#ifdef CFG_ATVRC_CUSTOM
+/**
+ * @brief Update UI layout configurable keys
+ */
+void rc_mmi_vkey_update_ui(uint8_t ui);
+#endif
+
+#ifdef CFG_VKEY_BUF
+/**
+ * @brief Flush buffered vkey events
+ */
+void rc_mmi_vkey_flush_buf(void);
+
+/**
+ * @brief Free buffered vkeys
+ */
+void rc_mmi_vkey_free_buf(void);
+#endif \ No newline at end of file
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi_vkey_m2231.h b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi_vkey_m2231.h
new file mode 100644
index 0000000..13a680f
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/src/rc_mmi_vkey_m2231.h
@@ -0,0 +1,59 @@
+/**
+ *******************************************************************************
+ *
+ * @file rc_mmi_vkey_m2231.h
+ *
+ * @brief Key definitions for ATV Ref. Remote G10
+ *
+ * @note This file should only be included by rc_mmi_vkey.c
+ * Copyright (C) Atmosic 2022
+ *
+ *******************************************************************************
+ */
+
+#pragma once
+
+// Virtual key definitions
+enum {
+ VK_INPUT, VK_POWER, VK_DOWN, VK_VOLUP, VK_BACK,
+ VK_UP, VK_BKMK, NONE1, VK_HOME, VK_LEFT,
+ VK_DASHB, VK_ASST, VK_APP03, VK_YOUTUBE, VK_VOLDN,
+ NONE2, VK_NETFLIX, VK_APP04, VK_MUTE, VK_CENTER,
+ NONE3, VK_CNLD, VK_GUIDE, VK_CNLU, VK_RIGHT,
+};
+
+static uint32_t __ATM_VKEY_MAP_CONST bt_keycode[] = {
+ BT_INPUT, BT_POWER, BT_DOWN, BT_VOLU, BT_BACK,
+ BT_UP, BT_BKMK, 0, BT_HOME, BT_LEFT,
+ BT_DASHB, BT_ASST, BT_APP03, BT_YOUTUBE, BT_VOLD,
+ 0, BT_NETFLIX, BT_APP04, BT_MUTE, BT_CENTER,
+ 0, BT_CNLD, BT_GUIDE, BT_CNLU, BT_RIGHT,
+};
+
+#ifdef CFG_ATVRC_UNI_IR
+static uint32_t const atv_keycode[] = {
+ ATV_INPUT, ATV_POWER, 0, ATV_VOLU, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, ATV_VOLD,
+ 0, 0, 0, ATV_MUTE, 0,
+ 0, 0, 0, 0, 0,
+};
+#endif
+
+#ifdef CFG_RC_IR
+static uint32_t __ATM_VKEY_MAP_CONST ir_addr[] = {
+ IR_ADDR, IR_ADDR, IR_ADDR, IR_ADDR, IR_ADDR,
+ IR_ADDR, IR_ADDR, 0, IR_ADDR, IR_ADDR,
+ IR_ADDR, IR_ADDR, IR_ADDR, IR_ADDR, IR_ADDR,
+ 0, IR_ADDR, IR_ADDR, IR_ADDR, IR_ADDR,
+ 0, IR_ADDR, IR_ADDR, IR_ADDR, IR_ADDR,
+};
+
+static uint32_t __ATM_VKEY_MAP_CONST ir_cmd[] = {
+ IR_INPUT, IR_POWER, IR_DOWN, IR_VOLU, IR_BACK,
+ IR_UP, IR_BKMK, 0, IR_HOME, IR_LEFT,
+ IR_DASHB, IR_ASST, IR_APP03, IR_YOUTUBE, IR_VOLD,
+ 0, IR_NETFLIX, IR_APP04, IR_MUTE, IR_CENTER,
+ 0, IR_CNLD, IR_GUIDE, IR_CNLU, IR_RIGHT,
+};
+#endif
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/01-BD_ADDRESS/user.tds b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/01-BD_ADDRESS/user.tds
new file mode 100644
index 0000000..0661136
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/01-BD_ADDRESS/user.tds
@@ -0,0 +1 @@
+335566778899
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/02-DEVICE_NAME/remote.tds b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/02-DEVICE_NAME/remote.tds
new file mode 100644
index 0000000..799a3d8
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/02-DEVICE_NAME/remote.tds
@@ -0,0 +1,2 @@
+# Atmosic RCU
+41 74 6d 6f 73 69 63 20 52 43 55
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/0d-EXT_WAKEUP_TIME/no_32KHz_xtal.tds b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/0d-EXT_WAKEUP_TIME/no_32KHz_xtal.tds
new file mode 100644
index 0000000..7a513ec
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/0d-EXT_WAKEUP_TIME/no_32KHz_xtal.tds
@@ -0,0 +1 @@
+28 23
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/0e-OSC_WAKEUP_TIME/no_32KHz_xtal.tds b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/0e-OSC_WAKEUP_TIME/no_32KHz_xtal.tds
new file mode 100644
index 0000000..7a513ec
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/0e-OSC_WAKEUP_TIME/no_32KHz_xtal.tds
@@ -0,0 +1 @@
+28 23
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/11-SLEEP_ENABLE/hib.tds b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/11-SLEEP_ENABLE/hib.tds
new file mode 100644
index 0000000..4ab3050
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/11-SLEEP_ENABLE/hib.tds
@@ -0,0 +1,8 @@
+# 0x00: Sleep disabled
+# 0x01: Deep sleep enabled
+# 0x02: Retain all but DO NOT drop to retention voltage
+# 0x03: Retain all and drop to retention voltage
+# 0x04: Hibernate
+# 0x05: SOC off
+# 0x80: Test mask (roll through modes)
+04
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/12-EXT_WAKEUP_ENABLE/enable2.tds b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/12-EXT_WAKEUP_ENABLE/enable2.tds
new file mode 100644
index 0000000..eb73788
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/12-EXT_WAKEUP_ENABLE/enable2.tds
@@ -0,0 +1,4 @@
+# 0x00: Timer and software wakeup only
+# 0x01: External (from PSEQ) wakeup enabled with limited timeout
+# 0x02: External wakeup enabled with no maximum sleep duration
+02
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/2b-SLEEP_ADJ/no_32KHz_xtal.tds b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/2b-SLEEP_ADJ/no_32KHz_xtal.tds
new file mode 100644
index 0000000..b3fca3c
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/2b-SLEEP_ADJ/no_32KHz_xtal.tds
@@ -0,0 +1 @@
+02 00 00 00
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/C1-ATVRC_CUSTOM_DATA/g10.tds b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/C1-ATVRC_CUSTOM_DATA/g10.tds
new file mode 100644
index 0000000..d6ef7d9
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/C1-ATVRC_CUSTOM_DATA/g10.tds
@@ -0,0 +1,53 @@
+# ATVRC G10 Customization Data
+# Device Type
+01 # 01 = Hobb(short), 02 = Shaw(Long)
+# PNP ID
+01 # Vendor Source
+24 0A # VID
+01 00 # PID
+00 01 # Product version
+
+# Device name
+0D # length
+52 65 6d 6f 74 65 47 31 30 20 41 54 4d 00 00 00 # 'RemoteG10 ATM'
+
+# Device UI layout
+05
+# Wakeup key 1
+0F 00 # Enable wakeup key 1: Assistant, Home, Power, Input
+# Wakeup key 2
+F0 00 # Enable wakeup key 2: Youtube, Netflix, APP03, APP04
+
+# The following configurations are not yet available
+
+# Customized Wakeup Packet
+15 0D 0E 0F 02 01 04 03 03 12 18 0D FF 5D 00 03
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+# Periodically wakeup (FIND_ME_ENABLE)
+0F 00 # interval
+01 # FF: Disable 01: Enable
+
+# RCU RPA switch
+FF # FF: Disable 00: Enable
+
+# Disable BLE
+FF # FF: Enable BLE 00: Disable BLE
+
+# Wakeup packet sending mode
+FF # FF: customized packet 3 sec -> Google packet 3sec 00: customized packet 6 sec
+
+# Cache POWER switch
+FF # FF: Enable cache 00: Disable cache
+
+# Authentication key
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+
+# Encryption password
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+
+# ECDSA Public Key
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF \ No newline at end of file
diff --git a/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/C2-ATVRC_NEC_IR_OVERRIDE/default.tds b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/C2-ATVRC_NEC_IR_OVERRIDE/default.tds
new file mode 100644
index 0000000..66bc7e1
--- /dev/null
+++ b/platform/atm2/ATM22xx-x1x/examples/HID_remote/tag_data/C2-ATVRC_NEC_IR_OVERRIDE/default.tds
@@ -0,0 +1,49 @@
+# NEC IR CODE override table
+FF FF FF FF # 0 POWER
+FF FF FF FF # 1 RIGHT
+FF FF FF FF # 2 VOLUME DOWN
+FF FF FF FF # 3 INFO*
+FF FF FF FF # 4 No.4*
+FF FF FF FF # 5 GREEN*
+FF FF FF FF # 6 INPUT
+FF FF FF FF # 7 DOWN
+FF FF FF FF # 8 CHANNEL DOWN
+FF FF FF FF # 9 No.0*
+FF FF FF FF # 10 No.3*
+FF FF FF FF # 11 RED*
+FF FF FF FF # 12 BOOKMARK
+FF FF FF FF # 13 BACK
+FF FF FF FF # 14 YOUTUBE
+FF FF FF FF # 15 SUBTITLE*
+FF FF FF FF # 16 No.2*
+FF FF FF FF # 17 No.6*
+FF FF FF FF # 18 ASSIST
+FF FF FF FF # 19 HOME
+FF FF FF FF # 20 NETFLIX
+FF FF FF FF # 21 No.9*
+FF FF FF FF # 22 No.1*
+FF FF FF FF # 23 No.5*
+FF FF FF FF # 24 DASHBOARD
+FF FF FF FF # 25 GUIDE
+FF FF FF FF # 26 APP03
+FF FF FF FF # 27 No.8*
+FF FF FF FF # 28 BLUE*
+FF FF FF FF # 29 NONE
+FF FF FF FF # 30 UP
+FF FF FF FF # 31 VOLUME UP
+FF FF FF FF # 32 APP04
+FF FF FF FF # 33 No.7*
+FF FF FF FF # 34 YELLOW*
+FF FF FF FF # 35 NONE
+FF FF FF FF # 36 LEFT
+FF FF FF FF # 37 CHANNEL UP
+FF FF FF FF # 38 NONE
+FF FF FF FF # 39 NONE
+FF FF FF FF # 40 NONE
+FF FF FF FF # 41 NONE
+FF FF FF FF # 42 CENTER
+FF FF FF FF # 43 MUTE
+FF FF FF FF # 44 NONE
+FF FF FF FF # 45 NONE
+FF FF FF FF # 46 NONE
+FF FF FF FF # 48 NONE \ No newline at end of file