Biu~笔记:高通蓝牙ADK(5)--按键功能之长按开关机

       Biu~小伙伴们大家好,经过了四期按键功能和使用的讲解,应该可能大致maybe了解了按键的处理逻辑吧。这些都是平常开发中会遇到的问题,就统一给大家讲解,而有一些特殊的功能,就具体问题具体分析了,有需要联系我们吧~

       这一期是按键部分的最后一期,和前面的有点不太一样,这一期做的是在按键处理之前实现的。在默认代码中是一上电就开机的,这样的UI可能对一些操作或体验上有点不好,所以很多客户会加上长按开机这个功能,防止一些误触发带来的开机。小编之前在ADK6.x上做过使用默认的按键处理来处理开机动作,但是在新的ADK,小编也尝试过用默认的按键处理来做,但是效果很不理想。因为要把所有东西初始化完成之后才开始处理按键,这里等的时间就太长了,所以小编在前期的初始化加了自定义的按键处理,来单独处理开机动作。另外默认也是没有按键关机的处理的,这个比较简单,直接配个按键事件就可以了。

       那从简单的说起,配一个关机事件。首先我们要有一个触发动作,这个在buttonxml中加入一个即可

然后,我们在table里面加入对应的按键处理

在这里的ui_input_sm_power_off是没有地方处理的,我们根据他的名字和定义来看,可以知道他属于sm,所以我们在sm的处理中把这个处理加进去,长按关机功能就完成了

       
        接下来,了解一下小编想到的长按开机处理逻辑,方法不是唯一,有更好想法的可以留言私信。首先在上电初始化时,加上一个拦截,appInitTable这是一个表格,里面会执行一系列的初始化操作,每一条初始化都有三个参数,第一个是初始化函数;第二个的本条初始化完成要发的消息ID,如果不发就不能继续往下跑,这也是小编用来拦截初始化用到的技巧;第三个额外需要知道初始化成功的回调函数,一般很少用。这里面加入一个自定义的一个初始化函数,在pio检测和电源初始化完成之后,为了保证pio能监测和充电能被识别

这个开机确认的消息是自定义的

然后看看自定义的初始化函数里面做了什么powerOnInit

首先第一条语句是把需要接收初始化完成的task给设置好,这里直接把默认传进来的task用上就好了。下面的if判断是为了区分是哪种开机方式,我们知道有些开机像复位、充电等这些不需要长按就要开机的动作,是要被允许直接开机的(小知识:充电时芯片需要在运行状态的,所以如果不让开机就不能充电了)。appChargerIsConnected是用于判断是否接上了充电器,ReadPoweroffReason是用于判断是否需要长按开机,这个是自己加的函数,在手动关机、无连接超时关机、低电关机等情况下,需要下次开机要长按开机,就要设置这个reason,(SetPoweroffReason)。要把这个函数放在你关机需要下次长按开机的地方!  例如,我在前面关机时调用了这个函数设置关机reason,下次开机就需要长按开机了。

往下看,如果在充电和不需要长按开机就直接开机,

MessageSend(Init_GetInitTask(), POWER_ON_CFM, NULL);

SetPoweroffReason(FALSE) ;

两个函数含义是发送开机允许消息,并清除标志位

如果不是在充电和需要长按开机的,先获取当前按键io的状态,用于后续处理,再设置一个超时消息,在这个时间内没有完成长按的就关机,相当于长按所需要的长按时间,时间在HOLD_FOR_POWERON_TIMEOUT 定义,这是时间会比实际感觉短,因为上电和前期的初始化会需要一段时间,所以这个时间加上1~2s的就等于实际感觉到的长按开机时间。

接下来就是PioMonitorEnableForPoweron是自定义的函数,为了将powerOnHandler注册成开机IO变化的处理函数,用来检测开机IO的电平变化,方便检测长按动作。

而powerOnHandler里面主要处理两个消息,一个是io变化的消息,

从初始开始计时,如果初始化时,开机io是低的,就等待按下并开始重新计时 ;是高的话就等待超时或松开按键。在计时期间开机io松开了,就判断为非长按,如果没有充电和关机reason就直接关机。

另外一个消息是超时消息

已经超时了就不再需要按键识别,就把原先开机io检测给注销掉。再重新判断一下,当前状态是适合开机还是关机,之后就是执行各自的处理就行了,这些都和前面提到的一样。

       另外有点需要注意,在拦截的时候,会常亮led灯,是因为前面有初始化led的io,但是没有将其设成关闭状态,才导致led一直亮着,按照以下修改即可。


以上是本期博文的全部内容,如有疑问请在博文下方评论留言,或者有什么想了解的都可以留言,我会挑选一些做后面几期的博文,还想了解其他按键功能的话,(o´ω`o)و安排上。谢谢大家浏览,我们下期再见。

 

------------- adk/src/domains/peripheral/led_manager/led_manager.c -------------
index adbff5e4..7c955122 100755
@@ -471,10 +471,11 @@ static void ledManager_setupSingleLedPioHw(unsigned led_pio)
unsigned bank = ledManager_getPioBank(led_pio);
unsigned mask = ledManager_getPioMask(led_pio);

PioSetMapPins32Bank(bank, mask, mask);
PioSetDir32Bank(bank, mask, mask);
+ PioSet32Bank(bank, mask, mask);
}

static void ledManager_setupLedPioHw(void)
{
switch (led_mgr.hw_config->number_of_leds)

------------- adk/src/domains/power/power_manager/power_manager.c -------------
index e578c5e0..f5de3e08 100755
@@ -763,5 +763,10 @@ static void powerManager_RegisterMessageGroup(Task task, message_group_t group)
appPowerClientRegister(task);
appPowerClientAllowSleep(task);
}

MESSAGE_BROKER_GROUP_REGISTRATION_MAKE(POWER_APP, powerManager_RegisterMessageGroup, NULL);
+
+void AppPowerDoPowerOff(void)
+{
+ appPowerDoPowerOff();
+}

------------- adk/src/domains/power/power_manager/power_manager.h -------------
index d3c2d5d3..3ebc8268 100755
@@ -86,11 +86,13 @@ enum powerClientMessages
#POWER_SHUTDOWN_PREPARE_IND. No response required. */
APP_POWER_SHUTDOWN_CANCELLED_IND,
/*! Message indicating the application has powered on */
POWER_ON,
/*! Message indicating the application is powering off */
- POWER_OFF
+ POWER_OFF,
+
+ POWER_ON_CFM
};

/*! \brief Power ui provider contexts */
typedef enum
{
@@ -206,6 +208,8 @@ void appPowerPerformanceProfileRelinquish(void);
expected to be called after all power manager clients have registered
their task.
*/
void appPowerInitComplete(void);

+void AppPowerDoPowerOff(void);
+
#endif /* POWER_MANAGER_H_ */

-------------------- adk/src/libs/pio_monitor/pio_monitor.c --------------------
index 086b8ffb..dd9878f4 100755
@@ -352,5 +352,19 @@ void PioMonitorUnregisterTask(Task client, uint8 pio)
{
PIOM_DEBUG(("PIOM: PioMonitorUnregisterTask %d\n",pio));
removeClient(client, pio);
updateDebounced(pio);
}
+
+void PioMonitorEnableForPoweron(bool enable,Task client,uint16 pio)
+{
+ if(enable)
+ {
+ /* Register with the platform to receive PIO events */
+ MessagePioTask(client);
+ updateDebounced(pio);
+ }
+ else
+ /* Unregister with the platform to receive PIO events */
+ MessagePioTask(NULL);
+
+}

-------------------- adk/src/libs/pio_monitor/pio_monitor.h --------------------
index 98544e13..147f59d4 100755
@@ -44,6 +44,8 @@ void PioMonitorSetDebounceParameters(uint16 debounce_reads, uint16 debounce_peri
void PioMonitorRegisterTask(Task client, uint8 pio);

/*! @brief Unregister a task. */
void PioMonitorUnregisterTask(Task client, uint8 pio);

+void PioMonitorEnableForPoweron(bool enable,Task client,uint16 pio);
+
#endif /* PIO_MONITOR_H_ */

--------------------------- earbud/src/earbud_init.c ---------------------------
index 49467e0d..e82ca87a 100755
@@ -115,10 +115,11 @@
#include
#include
#include
#include
#include
+#include

#ifdef INCLUDE_QCOM_CON_MANAGER
#include
#endif

@@ -610,10 +611,103 @@ static bool earbud_AncGaiaPluginRegister(Task init_task)


return TRUE;
}
#endif

+TaskData power_on_task;
+uint32 power_on_pio_state;
+#define POWERON_BUTTON 0
+#define HOLD_FOR_POWERON_TIMEOUT 2000 //2s
+#define POWER_OFF_REASON_KEY 200
+
+static bool ReadPoweroffReason(void)
+{
+ uint16 temp = 0;
+ PsRetrieve(POWER_OFF_REASON_KEY,&temp,sizeof(temp));
+ return temp?TRUE:FALSE;
+}
+void SetPoweroffReason(uint16 reason)
+{
+ PsStore(POWER_OFF_REASON_KEY,&reason,sizeof(reason));
+}
+
+static void powerOnHandler(Task task, MessageId id, Message message)
+{
+ UNUSED(task);
+ switch(id)
+ {
+ case MESSAGE_PIO_CHANGED:
+ {
+ const MessagePioChanged *mpc = (const MessagePioChanged *)message;
+ const uint32 pio_state = (mpc->state) + ((uint32)mpc->state16to31 << 16);
+ DEBUG_LOG_INFO("PIOM: pioHandler state %04x%04x for bank %u\n",
+ mpc->state16to31, mpc->state, mpc->bank);
+ uint16 pio_bank = POWERON_BUTTON/32;
+ uint32 pio_mask = 1<< (POWERON_BUTTON%32) ;
+
+ if((pio_bank == mpc->bank)
+ && power_on_pio_state != (pio_mask & pio_state))
+ {
+ power_on_pio_state = (pio_mask & pio_state);
+ if(power_on_pio_state)
+ {
+ MessageCancelAll(task,0x1234);
+ MessageSendLater(task,0x1234,NULL,HOLD_FOR_POWERON_TIMEOUT);
+ }
+ else
+ {
+ PioMonitorEnableForPoweron(FALSE,NULL,POWERON_BUTTON);
+ if(appChargerIsConnected() || !ReadPoweroffReason())
+ {
+ MessageCancelAll(task,0x1234);
+ MessageSend(Init_GetInitTask(), POWER_ON_CFM, NULL);
+ SetPoweroffReason(FALSE) ;
+ }
+ else
+ AppPowerDoPowerOff();
+ }
+ }
+
+ } break;
+
+ //decide whether power on or not with timeout
+ case 0x1234:
+ PioMonitorEnableForPoweron(FALSE,NULL,POWERON_BUTTON);
+ MessageCancelAll(task,0x1234);
+ if(power_on_pio_state || appChargerIsConnected() || !ReadPoweroffReason())
+ {
+ MessageSend(Init_GetInitTask(), POWER_ON_CFM, NULL);
+ SetPoweroffReason(FALSE) ;
+ }
+ else
+ AppPowerDoPowerOff();
+ break;
+
+ default:break;
+ }
+
+}
+
+static bool powerOnInit(Task init_task)
+{
+ Init_SetInitTask(init_task);
+ if(appChargerIsConnected() || !ReadPoweroffReason())
+ {
+ MessageSend(Init_GetInitTask(), POWER_ON_CFM, NULL);
+ SetPoweroffReason(FALSE) ;
+ }
+ else
+ {
+ power_on_task.handler = powerOnHandler;
+ power_on_pio_state = PioGet32Bank(POWERON_BUTTON/32) & (1<<(POWERON_BUTTON/32));
+ MessageSendLater(&power_on_task,0x1234,NULL,HOLD_FOR_POWERON_TIMEOUT);
+ PioMonitorEnableForPoweron(TRUE,&power_on_task,POWERON_BUTTON);
+ }
+
+ return TRUE;
+}
+
/*! \brief Table of initialisation functions */
static const init_table_entry_t appInitTable[] =
{
#ifdef INIT_DEBUG
{appInitDebug, 0, NULL},
@@ -629,10 +723,11 @@ static const init_table_entry_t appInitTable[] =
#ifdef INCLUDE_CHARGER
{appChargerInit, 0, NULL},
#endif
{LedManager_Init, 0, NULL},
{appPowerInit, APP_POWER_INIT_CFM, NULL},
+ {powerOnInit, POWER_ON_CFM,NULL},
{appConnectionInit, CL_INIT_CFM, NULL},
{appMessageDispatcherRegister, 0, NULL},
#ifdef USE_BDADDR_FOR_LEFT_RIGHT
{appConfigInit, CL_DM_LOCAL_BD_ADDR_CFM, appInitHandleClDmLocalBdAddrCfm},
#endif

--------------------------- earbud/src/earbud_init.h ---------------------------
index a6fc4eaf..5f03f8c4 100755
@@ -40,6 +40,8 @@ void appInit(void);

This should be called on receipt of the #APPS_COMMON_INIT_CFM message.
*/
void appInitSetInitialised(void);

+void SetPoweroffReason(uint16 reason);
+
#endif /* EARBUD_INIT_H */

---------------------------- earbud/src/earbud_sm.c ----------------------------
index 03c2ecdb..5324000b 100755
@@ -2641,10 +2641,14 @@ static void appSmHandleUiInput(MessageId ui_input)
appSmFactoryReset();
break;
case ui_input_dfu_active_when_in_case_request:
appSmEnterDfuModeInCase(TRUE, TRUE);
break;
+ case ui_input_sm_power_off:
+ appPowerOffRequest();
+ SetPoweroffReason(TRUE) ;
+ break;
#ifdef PRODUCTION_TEST_MODE
case ui_input_production_test_mode_request:
appSmEnterProductionTestMode();
break;
#endif

------------------------ earbud/src/earbud_ui_config.c ------------------------
index a085f46c..b06af96c 100755
@@ -154,11 +154,12 @@ const ui_config_table_content_t earbud_ui_config_table[] =

{APP_MFB_BUTTON_HELD_RELEASE_1SEC, ui_provider_hfp, context_hfp_voice_call_sco_active, ui_input_hfp_transfer_to_ag },
{APP_MFB_BUTTON_HELD_RELEASE_1SEC, ui_provider_hfp, context_hfp_voice_call_sco_inactive, ui_input_hfp_transfer_to_headset },
{APP_MFB_BUTTON_HELD_RELEASE_1SEC, ui_provider_hfp, context_hfp_voice_call_incoming, ui_input_voice_call_reject },
{APP_MFB_BUTTON_HELD_RELEASE_1SEC, ui_provider_media_player, context_av_is_streaming, ui_input_stop_av_connection },
-
+ {APP_MFB_BUTTON_HELD_RELEASE_3SEC, ui_provider_device, context_handset_not_connected, ui_input_sm_power_off },
+ {APP_MFB_BUTTON_HELD_RELEASE_3SEC, ui_provider_device, context_handset_connected, ui_input_sm_power_off },
#ifdef PRODUCTION_TEST_MODE
{APP_MFB_BUTTON_HELD_RELEASE_3SEC, ui_provider_phy_state, context_phy_state_out_of_case, ui_input_production_test_mode_request },
#endif

{APP_BUTTON_DFU, ui_provider_phy_state, context_phy_state_out_of_case, ui_input_dfu_active_when_in_case_request },

-------------------- earbud/src/buttons/9_buttons.buttonxml --------------------
index e2f736b5..59babf79 100755
@@ -71,10 +71,17 @@
HELD
SYS_CTRL
3000


+
+ APP_MFB_BUTTON_HELD_RELEASE_3SEC
+ HELD_RELEASE
+ SYS_CTRL
+ 3000
+
+

APP_MFB_BUTTON_HELD_RELEASE_6SEC
HELD_RELEASE
SYS_CTRL
6000



多看文档,多上官网

多看文档,多上官网

多看文档,多上官网

 

 


 

★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★文明上网,请理性发言。内容一周内被举报5次,发文人进小黑屋喔~

评论

袁志文

袁志文

9 个月前
看起来还不错,试试看
1111

1111

2021年4月30日
请教一下单击也开机了,怎么解决
发芽韭菜

发芽韭菜

2021年3月14日
有鱼无渔
访客

访客

2021年1月28日
验证完美
Biu~

Biu~

2020年12月4日
重大事项!!!!!!!!!!!!!!!!!!由于新版本初始化框架的变化,导致部分API不能用,这里做一点小更新。 其中Init_SetInitTask这个函数已经没有了,而他原本在这里也没什么作用,所以就不再需要了,直接删除。 Init_GetInitTask这个是要发回开机确认的消息的task,现在要改为SystemState_GetTransitionTask,其他都不变哦。 换行都没有,那么尴尬的吗ε=(′ο`*)))唉
Biu~

Biu~

2020年12月4日
重大事项!!!!!!!!!!!!!!!!!!由于新版本初始化框架的变化,导致部分API不能用,这里做一点小更新。 其中Init_SetInitTask这个函数已经没有了,而他原本在这里也没什么作用,所以就不再需要了,直接删除 Init_GetInitTask这个是要发回开机确认的消息的task,现在要改为SystemState_GetTransitionTask,其他都不变哦
Biu~

Biu~

2020年12月4日
重大事项!!!!!!!!!!!!!!!!!!由于新版本初始化框架的变化,导致部分API不能用,这里做一点小更新。 其中Init_SetInitTask这个函数已经没有了,而他原本在这里也没什么作用,所以就不再需要了,直接删除 Init_GetInitTask这个是要发回开机确认的消息的task,现在要改为SystemState_GetTransitionTask,其他都不变哦
Biu~

Biu~

2020年12月4日
重大事项!!!!!!!!!!!!!!!!!!由于新版本初始化框架的变化,导致部分API不能用,这里做一点小更新。 其中Init_SetInitTask这个函数已经没有了,而他原本在这里也没什么作用,所以就不再需要了,直接删除 Init_GetInitTask这个是要发回开机确认的消息的task,现在要改为SystemState_GetTransitionTask,其他都不变哦
Biu~

Biu~

2020年11月26日
配对信息包含了linkkey,这个是没办法自己写的
Jack

Jack

2020年11月24日
只有单个耳机清除配对了,怎么写入配对信息