diff options
Diffstat (limited to 'platform/atm2/ATM22xx-x1x/examples/HID_remote')
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 |