393 lines
10 KiB
C
393 lines
10 KiB
C
|
||
/*************************************************************
|
||
此文件函数主要是linein 插入检测
|
||
|
||
支持和sd卡 io复用检测
|
||
|
||
|
||
|
||
**************************************************************/
|
||
#include "app_config.h"
|
||
#include "system/event.h"
|
||
#include "system/init.h"
|
||
#include "system/timer.h"
|
||
#include "asm/power_interface.h"
|
||
#include "asm/adc_api.h"
|
||
#include "lp/lp.h"
|
||
#include "lp/lp_dev.h"
|
||
#include "gpio.h"
|
||
#include "asm/sdmmc.h"
|
||
|
||
#if TCFG_APP_LP_EN
|
||
|
||
#define LP_STU_HOLD 0
|
||
#define LP_STU_ON 1
|
||
#define LP_STU_OFF 2
|
||
|
||
#define LP_DETECT_CNT 3 // 滤波计算
|
||
|
||
#define LOG_TAG_CONST APP_LP
|
||
#define LOG_TAG "[APP_LP_DEV]"
|
||
#define LOG_ERROR_ENABLE
|
||
#define LOG_DEBUG_ENABLE
|
||
#define LOG_INFO_ENABLE
|
||
/*#define LOG_DUMP_ENABLE */
|
||
#define LOG_CLI_ENABLE
|
||
#include "debug.h"
|
||
|
||
struct lp_dev_opr
|
||
{
|
||
struct lp_dev_data *dev;
|
||
u8 cnt; // 滤波计算
|
||
u8 stu; // 当前状态
|
||
u16 timer; // 定时器句柄
|
||
u8 online : 1; // 是否在线
|
||
u8 active : 1; // 进入sniff的判断标志
|
||
u8 init : 1; // 初始化完成标志
|
||
u8 step : 3; // 检测阶段
|
||
};
|
||
static struct lp_dev_opr lp_dev_hdl = {0};
|
||
#define __this (&lp_dev_hdl)
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/*@brief 获取lp是否在线
|
||
@param
|
||
@return 1:在线 0:不在线
|
||
@note app通过这个接口判断lp是否在线
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
u8 lp_is_online(void)
|
||
{
|
||
#if ((defined TCFG_LP_DETECT_ENABLE) && (TCFG_LP_DETECT_ENABLE == 0))
|
||
return 1;
|
||
#else
|
||
return __this->online;
|
||
#endif // TCFG_LP_DETECT_ENABLE
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/*@brief 设置lp是否在线
|
||
@param 1:在线 0:不在线
|
||
@return null
|
||
@note 检测驱动通过这个接口判断lp是否在线
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
void lp_set_online(u8 online)
|
||
{
|
||
__this->online = !!online;
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/*@brief 发布设备上下线消息
|
||
@param 上下线消息
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
void lp_event_notify(u8 arg)
|
||
{
|
||
struct sys_event event = {0};
|
||
event.arg = (void *)DEVICE_EVENT_FROM_LP;
|
||
event.type = SYS_DEVICE_EVENT;
|
||
|
||
if (arg == DEVICE_EVENT_IN)
|
||
{
|
||
event.u.dev.event = DEVICE_EVENT_IN;
|
||
}
|
||
else if (arg == DEVICE_EVENT_OUT)
|
||
{
|
||
event.u.dev.event = DEVICE_EVENT_OUT;
|
||
}
|
||
else
|
||
{
|
||
return;
|
||
}
|
||
sys_event_notify(&event);
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/*@brief 检测前使能io
|
||
@param null
|
||
@return null
|
||
@note 检测驱动检测前使能io ,检测完成后设为高阻 可以节约功耗
|
||
(io检测、sd复用ad检测动态使用,单独ad检测不动态修改)
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
static void lp_io_start(void)
|
||
{
|
||
/* printf("<<<lp_io_start\n"); */
|
||
struct lp_dev_data *lp_dev = (struct lp_dev_data *)__this->dev;
|
||
if (__this->init)
|
||
{
|
||
return;
|
||
}
|
||
__this->init = 1;
|
||
if (lp_dev->down)
|
||
{
|
||
gpio_set_pull_down(lp_dev->port, 1);
|
||
}
|
||
else
|
||
{
|
||
gpio_set_pull_down(lp_dev->port, 0);
|
||
}
|
||
if (lp_dev->up)
|
||
{
|
||
gpio_set_pull_up(lp_dev->port, 1);
|
||
}
|
||
else
|
||
{
|
||
gpio_set_pull_up(lp_dev->port, 0);
|
||
}
|
||
if (lp_dev->ad_channel == (u8)NO_CONFIG_PORT)
|
||
{
|
||
gpio_set_die(lp_dev->port, 1);
|
||
}
|
||
else
|
||
{
|
||
gpio_set_die(lp_dev->port, 0);
|
||
}
|
||
gpio_set_hd(lp_dev->port, 0);
|
||
gpio_set_hd0(lp_dev->port, 0);
|
||
gpio_direction_input(lp_dev->port);
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/*@brief 检测完成关闭使能io
|
||
@param null
|
||
@return null
|
||
@note 检测驱动检测前使能io ,检测完成后设为高阻 可以节约功耗
|
||
(io检测、sd复用ad检测动态使用,单独ad检测不动态修改)
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
static void lp_io_stop(void)
|
||
{
|
||
/* printf("<<<lp_io_stop\n"); */
|
||
struct lp_dev_data *lp_dev = (struct lp_dev_data *)__this->dev;
|
||
if (!__this->init)
|
||
{
|
||
return;
|
||
}
|
||
__this->init = 0;
|
||
gpio_direction_input(lp_dev->port);
|
||
gpio_set_pull_up(lp_dev->port, 0);
|
||
gpio_set_pull_down(lp_dev->port, 0);
|
||
gpio_set_hd(lp_dev->port, 0);
|
||
gpio_set_hd0(lp_dev->port, 0);
|
||
gpio_set_die(lp_dev->port, 0);
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/*@brief 检测是否在线
|
||
@param 驱动句柄
|
||
@return 1:有设备插入 0:没有设备插入
|
||
@note 检测驱动检测前使能io ,检测完成后设为高阻 可以节约功耗
|
||
(io检测、sd复用ad检测动态使用,单独ad检测不动态修改)
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
static int lp_sample_detect(void *arg)
|
||
{
|
||
struct lp_dev_data *lp_dev = (struct lp_dev_data *)arg;
|
||
u8 cur_stu;
|
||
|
||
if (lp_dev->ad_channel == (u8)NO_CONFIG_PORT)
|
||
{
|
||
lp_io_start();
|
||
cur_stu = gpio_read(lp_dev->port) ? false : true;
|
||
lp_io_stop();
|
||
if (!lp_dev->up)
|
||
{
|
||
cur_stu = !cur_stu;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
cur_stu = adc_get_value(lp_dev->ad_channel) > lp_dev->ad_vol ? false : true;
|
||
/* printf("<%d> ", adc_get_value(lp_dev->ad_channel)); */
|
||
}
|
||
/* putchar('A' + cur_stu); */
|
||
return cur_stu;
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/*@brief sd cmd 复用检测是否在线
|
||
@param 驱动句柄
|
||
@return 1:有设备插入 0:没有设备插入
|
||
@note 检测驱动检测前使能io ,检测完成后设为高阻 可以节约功耗
|
||
(io检测、sd复用ad检测动态使用,单独ad检测不动态修改)
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
static int lp_sample_mult_sd(void *arg)
|
||
{
|
||
struct lp_dev_data *lp_dev = (struct lp_dev_data *)arg;
|
||
lp_io_start();
|
||
u16 ad_value = 0;
|
||
u8 cur_stu;
|
||
if (lp_dev->ad_channel == (u8)NO_CONFIG_PORT)
|
||
{
|
||
cur_stu = gpio_read(lp_dev->port) ? false : true;
|
||
}
|
||
else
|
||
{
|
||
adc_enter_occupy_mode(lp_dev->ad_channel);
|
||
if (adc_occupy_run())
|
||
{
|
||
ad_value = adc_get_occupy_value();
|
||
cur_stu = ad_value > lp_dev->ad_vol ? false : true;
|
||
/* printf("\n<%d>\n", ad_value); */
|
||
}
|
||
else
|
||
{
|
||
cur_stu = __this->stu;
|
||
}
|
||
adc_exit_occupy_mode();
|
||
}
|
||
|
||
/* putchar('A'+cur_stu); */
|
||
/* putchar(cur_stu); */
|
||
lp_io_stop();
|
||
return cur_stu;
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/*@brief 注册的定时器回调检测函数
|
||
@param 驱动句柄
|
||
@return null
|
||
@note 定时进行检测
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
static void lp_detect(void *arg)
|
||
{
|
||
int cur_stu;
|
||
struct sys_event event = {0};
|
||
#if ((TCFG_LP_MULTIPLEX_WITH_SD == ENABLE))
|
||
if (sd_io_suspend(TCFG_LP_SD_PORT, 0) == 0)
|
||
{ // 判断sd 看是否空闲
|
||
cur_stu = lp_sample_mult_sd(arg);
|
||
sd_io_resume(TCFG_LP_SD_PORT, 0); // 使用完,回复sd
|
||
}
|
||
else
|
||
{
|
||
return;
|
||
}
|
||
#else
|
||
if (__this->step == 0)
|
||
{
|
||
__this->step = 1;
|
||
sys_timer_modify(__this->timer, 10); // 猜测是检测状态变化的时候改变定时器回调时间
|
||
return;
|
||
}
|
||
cur_stu = lp_sample_detect(arg);
|
||
if (!__this->active)
|
||
{
|
||
__this->step = 0;
|
||
sys_timer_modify(__this->timer, 500); // 猜测是检测状态不变化的时候改变定时器回调时间
|
||
}
|
||
#endif
|
||
|
||
if (cur_stu != __this->stu)
|
||
{
|
||
__this->stu = cur_stu;
|
||
__this->cnt = 0;
|
||
__this->active = 1;
|
||
}
|
||
else
|
||
{
|
||
__this->cnt++;
|
||
}
|
||
|
||
if (__this->cnt < LP_DETECT_CNT)
|
||
{ // 滤波计算
|
||
return;
|
||
}
|
||
|
||
__this->active = 0; // 检测一次完成
|
||
|
||
/* putchar(cur_stu); */
|
||
|
||
if ((lp_is_online()) && (!__this->stu))
|
||
{
|
||
lp_set_online(false);
|
||
lp_event_notify(DEVICE_EVENT_OUT); // 发布下线消息
|
||
}
|
||
else if ((!lp_is_online()) && (__this->stu))
|
||
{
|
||
lp_set_online(true);
|
||
lp_event_notify(DEVICE_EVENT_IN); // 发布上线消息
|
||
}
|
||
return;
|
||
}
|
||
|
||
void lp_detect_timer_add()
|
||
{
|
||
if (!__this || !(__this->dev))
|
||
{
|
||
return;
|
||
}
|
||
if (__this->timer == 0)
|
||
{
|
||
__this->timer = sys_timer_add(__this->dev, lp_detect, 25);
|
||
}
|
||
}
|
||
void lp_detect_timer_del()
|
||
{
|
||
if (__this && __this->timer)
|
||
{
|
||
sys_timer_del(__this->timer);
|
||
__this->timer = 0;
|
||
}
|
||
}
|
||
|
||
static int lp_driver_init(const struct dev_node *node, void *arg)
|
||
{
|
||
struct lp_dev_data *lp_dev = (struct lp_dev_data *)arg;
|
||
if (!lp_dev->enable)
|
||
{
|
||
lp_set_online(true);
|
||
return 0;
|
||
}
|
||
#if ((defined TCFG_LP_DETECT_ENABLE) && (TCFG_LP_DETECT_ENABLE == 0))
|
||
lp_set_online(true); // 没有配置detcct 默认在线
|
||
return 0;
|
||
#endif
|
||
|
||
if (lp_dev->port == (u8)NO_CONFIG_PORT)
|
||
{
|
||
lp_set_online(true); // 配置的io 不在范围 ,默认在线
|
||
return 0;
|
||
}
|
||
lp_set_online(false);
|
||
|
||
#if (!(TCFG_LP_MULTIPLEX_WITH_SD)) // 复用情况和io检测仅在使用的时候配置io
|
||
if (lp_dev->ad_channel != (u8)NO_CONFIG_PORT)
|
||
{
|
||
lp_io_start(); // 初始化io
|
||
adc_add_sample_ch(lp_dev->ad_channel);
|
||
}
|
||
#endif
|
||
|
||
__this->dev = lp_dev;
|
||
__this->timer = sys_timer_add(arg, lp_detect, 50);
|
||
return 0;
|
||
}
|
||
|
||
const struct device_operations lp_dev_ops = {
|
||
.init = lp_driver_init,
|
||
};
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/*@brief 注册的定功耗检测函数
|
||
@param
|
||
@return null
|
||
@note 用于防止检测一次未完成进入了低功耗
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
static u8 lp_dev_idle_query(void)
|
||
{
|
||
return !__this->active;
|
||
}
|
||
|
||
REGISTER_LP_TARGET(lp_dev_lp_target) = {
|
||
.name = "lp_dev",
|
||
.is_idle = lp_dev_idle_query,
|
||
};
|
||
|
||
#endif
|