Initial commit: TXW82x FPV v2.7.0.7-42229 SDK + project sources

This commit is contained in:
2026-07-06 11:30:13 +08:00
commit e76462eeb7
3451 changed files with 1415300 additions and 0 deletions

125
sdk/lib/key/adkey.c Normal file
View File

@@ -0,0 +1,125 @@
#include "sys_config.h"
#include "typesdef.h"
#include "adkey.h"
#include "keyScan.h"
#include "dev/adc/hgadc_v0.h"
#include "hal/gpio.h"
#ifdef PIN_FROM_PARAM
#include "pin_param.h"
#endif
static adkey_t adkey= {
.priv = NULL,
.pull = GPIO_PULL_NONE,
.pull_level = GPIO_PULL_LEVEL_4_7K,
};
static void key_adkey_init(key_channel_t *key)
{
adkey_t *adkey = (adkey_t *)key->priv;
struct hgadc_v0 *adc = (struct hgadc_v0*)dev_get(HG_ADC0_DEVID);
adkey->pin = MACRO_PIN(PIN_ADKEY1);
adc_open((struct adc_device *)adc);
gpio_set_mode(adkey->pin,adkey->pull,adkey->pull_level);
adc_add_channel((struct adc_device *)adc, adkey->pin);
adkey->priv = (void*)adc;
key->enable = 1;
}
static uint8 key_adkey_scan(key_channel_t *key)
{
adkey_t *adkey = (adkey_t *)key->priv;
uint32 vol;
struct adkey_scan_code *key_scan = (struct adkey_scan_code*)key->key_table;
adc_get_value((struct adc_device *)adkey->priv, adkey->pin, &vol);
// printf("vol:%d\n",vol);
//记录当前adc的值,用与发送到应用层,至于应用层是否需要,由应用层去管理
key->extern_value = vol;
for(;;)
{
if(vol>=key_scan->adc)
{
key_scan++;
}
else
{
key_scan--;
break;
}
}
// printf("key_scan->key:%d\tvol:%d\n",key_scan->key,vol);
return key_scan->key;
}
/*********************************************************
* adkey的参数配置
*
default: 2117
up:910
down:462
left:6
right:1368
press:1826
默认开发板先检查每一个按键的值,然后大概每一个ad-100填到下表
************************************************************/
#ifdef SYS_APP_WALKIE_TALKIE
static const struct adkey_scan_code adkey_table[] =
{
{0, AD_DOWN},
{200, AD_DOWN},
{635, AD_SPEACH},
{1275, AD_UP},
{1620, AD_RIGHT},
{2047, KEY_NONE},
{3200, KEY_NONE},
{3800, KEY_NONE},
{4000, KEY_NONE},
{4096, KEY_NONE},
};
#else
static const struct adkey_scan_code adkey_table[] =
{
{0, AD_LEFT},
{350, AD_DOWN},
{800, AD_UP},
{1200, AD_RIGHT},
{1700, AD_PRESS},
{2000, KEY_NONE},
{3200, KEY_NONE},
{3800, KEY_NONE},
{4000, KEY_NONE},
{4096, KEY_NONE},
};
#endif
static const keys_t adkey_arg =
{
.period_long = 500,
.period_repeat = 1000,
.period_dither = 80,
};
//外部调用
key_channel_t adkey_key =
{
.init = key_adkey_init,
.scan = key_adkey_scan,
.prepare = NULL,
.priv = (void*)&adkey,
.key_arg = &adkey_arg,//按键的参数,可能不同的类型按键,参数不一样
.key_table = &adkey_table,
};

39
sdk/lib/key/adkey.h Normal file
View File

@@ -0,0 +1,39 @@
#ifndef _ADKEY_H
#define _ADKEY_H
#include "sys_config.h"
#include "typesdef.h"
#include "list.h"
#include "dev.h"
#include "devid.h"
#include "hal/gpio.h"
#include "osal/timer.h"
#include "osal/semaphore.h"
#include "osal/mutex.h"
#include "keyScan.h"
struct adkey_t;
struct keys_t;
typedef struct adkey_t adkey_t;
struct adkey_t
{
void *priv;
uint32 pin; //io
uint8 pull; //上拉下拉
uint8 pull_level; //上下拉电阻
};
struct adkey_scan_code
{
int adc;
uint8 key;
};
key_channel_t adkey_key;
#endif

216
sdk/lib/key/keyScan.c Normal file
View File

@@ -0,0 +1,216 @@
#include "keyScan.h"
/*************************************************************************************
* 按键扫描判断的timer事件
* 最终调用key_scan_init来注册事件
*
*
**************************************************************************************/
static void g_key_scan(key_channel_t *ch)
{
const keys_t *arg = ch->key_arg;
uint8 key = ch->scan(ch);
uint8 key_code = KEY_EVENT_MAX;
uint8 key_event = KEY_EVENT_MAX;
//分析按键情况
//按键可能被释放或者说原本就是没有被按下
if(key == 0)
{
//按键没有被按下,无需去管理
if(ch->last_key == 0)
{
goto g_key_scan_end;
}
//按键从被按下到释放,反馈事件,有两种可能:短按释放,长按释放,异常情况则是(消抖没有完成就被释放)
else
{
//异常事件,正常不可能存在,检查程序,可能存在按键抖动情况,不作任何判断
if(ch->last_event == KEY_EVENT_MAX)
{
//printf("%s:%d err,last key:%d,now key:%d\tlast_event:%d\n",__FUNCTION__,__LINE__,ch->last_key,key,ch->last_event );
//printf("last time:%d\tnow time:%d\n",ch->last_time,os_jiffies());
}
else if(ch->last_event == KEY_EVENT_LDOWN || ch->last_event == KEY_EVENT_REPEAT)
{
ch->last_event = KEY_EVENT_MAX;
key_event = KEY_EVENT_LUP;
key_code = ch->last_key;
}
else if(ch->last_event == KEY_EVENT_DOWN)
{
ch->last_event = KEY_EVENT_MAX;
key_event = KEY_EVENT_SUP;
key_code = ch->last_key;
}
ch->last_key = key;
}
}
//有多种情况,key与last key不一样,分两种情况,按键抖动(相隔的时间太短),则以后面的key为准,并且时间清0,另一种则是按键检测的时候,错过了up的事件(因为用软定时,有可能错过,这个时候应该发出一个up事件,但也有可能按键接触不良,可以先发出up事件,key当作没有,等待下次的key再去判断)
else
{
//同样按键,判断时间超出按键抖动范围,如果是,则发出被按下事件
if(key == ch->last_key)
{
//上一次没有事件,则是消抖时间完成,发出按键按下事件
if(ch->last_event == KEY_EVENT_MAX)
{
if(os_jiffies() - ch->last_time > arg->period_dither)
{
ch->last_event = KEY_EVENT_DOWN;
key_event = KEY_EVENT_DOWN;
key_code = ch->last_key;
//无需更新时间,下一次则进入去判断是否长按
ch->last_time = os_jiffies();
}
//消抖时间没有完成
else
{
}
}
//上一次已经有down的事件,则需要继续判断后续的事件(是否为长按或者重复按键)
else
{
//短按,超过长按的时间,发出长按被按下的事件
if(ch->last_event == KEY_EVENT_DOWN )
{
if(os_jiffies() - ch->last_time > arg->period_long)
{
//长按事件被按下
ch->last_event = KEY_EVENT_LDOWN;
key_event = KEY_EVENT_LDOWN;
key_code = ch->last_key;
//用于判断是否是重复按键
ch->last_time = os_jiffies();
}
//不是长按,还在等待时间
else
{
}
}
else
{
if(ch->last_event == KEY_EVENT_LDOWN || ch->last_event == KEY_EVENT_REPEAT)
{
if(os_jiffies() - ch->last_time > arg->period_repeat)
{
ch->last_event = KEY_EVENT_REPEAT;
key_event = KEY_EVENT_REPEAT;
key_code = ch->last_key;
//用于判断下一次判断
ch->last_time = os_jiffies();
}
}
else
{
os_printf("%s:%d err,last key:%d,now key:%d\tlast_event:%d\n",__FUNCTION__,__LINE__,ch->last_key,key,ch->last_event );
}
}
}
}
//刚被按下,则记录时间,等待抖动结束
if(!ch->last_key)
{
ch->last_time = os_jiffies();
ch->last_key = key;
}
//两次按键不一致,那么就要去识别事件,如果last_event没有事件,代表消抖没有完成,则重新计算时间,如果消抖完成,则需要发出up事件,last_key = 0
else if(ch->last_key != key)
{
//消抖没有完成,更新按键的值
if(ch->last_event == KEY_EVENT_MAX)
{
ch->last_time = os_jiffies();
ch->last_key = key;
}
//消抖完成,发出up事件,然后last_key设置为0,等待下次按键判断
else
{
if(ch->last_event == KEY_EVENT_LDOWN || ch->last_event == KEY_EVENT_REPEAT)
{
ch->last_event = KEY_EVENT_MAX;
key_event = KEY_EVENT_LUP;
key_code = ch->last_key;
}
else if(ch->last_event == KEY_EVENT_DOWN)
{
ch->last_event = KEY_EVENT_MAX;
key_event = KEY_EVENT_SUP;
key_code = ch->last_key;
ch->last_time = os_jiffies();
}
ch->last_key = 0;
}
}
}
g_key_scan_end:
if(key_event != KEY_EVENT_MAX)
{
// key_map_t *map = ch->key_table_map;
//uint32 map_msg = map[key_code][key_event];
uint32 map_msg = (key_code<<8 | key_event);
if(map_msg && ch->key_send)
{
ch->key_send(map_msg,ch->extern_value);
}
}
}
//timer事件
static void key_auto_timer_cb(void *arg)
{
key_channel_t **channel = (key_channel_t **)arg;
key_channel_t **ch;
for (ch = &channel[0]; *ch; ++ch)
{
if(!(*ch)->enable)
{
continue;
}
if((*ch)->prepare)
{
(*ch)->prepare(*ch);
}
if((*ch)->scan)
{
g_key_scan(*ch);
}
}
}
static os_timer_t key_timer;
//先初始化,然后注册timer,注册按键的映射表,最后启动timer
void key_button_scan_init(key_channel_t **channel,key_send_msg send)
{
key_channel_t **ch = channel;
for (; *ch; ++ch)
{
(*ch)->last_event = KEY_EVENT_MAX;
(*ch)->last_key = KEY_EVENT_MAX;
(*ch)->last_time = os_jiffies();
(*ch)->key_send = send;
if((*ch)->init)
{
(*ch)->init(*ch);
}
}
os_timer_init(&key_timer, key_auto_timer_cb, OS_TIMER_MODE_PERIODIC, (void*)channel);
os_timer_start(&key_timer, 5);
}

92
sdk/lib/key/keyScan.h Normal file
View File

@@ -0,0 +1,92 @@
#ifndef __KEYSCAN_H
#define __KEYSCAN_H
#include "basic_include.h"
/**************************************************************************
* 按键的事件
* 说明:按键触发可能短时间由多个事件,比如长按:先是有个按键按下->长按按下->长按释放
* 所以要考虑监听哪个事件,比如短按的,最好监听短按释放,毕竟按键按下事件都会有触发的
***************************************************************************/
enum
{
KEY_EVENT_DOWN, //按键按下
KEY_EVENT_SUP, //短按释放
KEY_EVENT_LDOWN, //长按按下
KEY_EVENT_LUP, //长按释放
KEY_EVENT_REPEAT, //一直按住按键
KEY_EVENT_MAX,
};
/***************************************
* 按键值的定义
***************************************/
enum
{
KEY_NONE,
AD_UP,
AD_DOWN,
AD_LEFT,
AD_RIGHT,
AD_PRESS,
AD_A,
AD_B,
AD_C,
AD_SPEACH,
KEY_BACK,
KEY_MAGIC_SWITCH,
KEY_IPF_SWITCH,
KEY_PAIR,
KEY_POWER,
KEY_POWEROFF,
LOWPOWER_CHECK,
KEY_CALLING_START,
KEY_CALLING_STOP,
};
struct key_channel_t ;
struct keys_t ;
typedef struct key_channel_t key_channel_t;
typedef void (*keyinit_func) (struct key_channel_t*);
typedef void (*keyprepare_func) (struct key_channel_t*);
typedef uint8 (*keyscan_func) (struct key_channel_t*);
typedef int32 (*key_send_msg) (uint32 data,uint32_t value);
typedef uint32 key_map_t[KEY_EVENT_MAX];
typedef struct keys_t keys_t;
struct keys_t
{
uint32_t period_long;
uint32_t period_repeat;
uint32_t period_dither;
};
struct key_channel_t
{
keyinit_func init; //初始化
keyprepare_func prepare;//scan之前的准备,可以设置为NULL也可以去设置enable值来作为是否要进行按键检测
keyscan_func scan; //获取按键键值
const void *key_table;//按键表格,scan需要用到,如果是adc需要根据表格获取是哪个按键被按下
const keys_t *key_arg;
void *priv;
key_send_msg key_send;
uint32_t last_key;
uint32_t last_time;
uint32_t last_event;
uint32_t extern_value;
uint8 enable;
};
void key_button_scan_init(key_channel_t **channel,key_send_msg send);
#endif

169
sdk/lib/key/keyWork.c Normal file
View File

@@ -0,0 +1,169 @@
#include "sys_config.h"
#include "typesdef.h"
#include "osal/string.h"
#include "osal/msgqueue.h"
#include "osal/work.h"
#include "osal/string.h"
#include "keyWork.h"
#include "keyScan.h"
#include "adkey.h"
#include "power_checkkey.h"
#include "csi_kernel.h"
/*****************************************
* 按照不同按键,请注册对应按键进来,参看adkey.c
*
*
*
*
* adkey或者ioKey或者touchkey
* 添加多个的例子
* static key_channel_t *button_channels[] = {&adkey_key,&powercheck_key,NULL};
*****************************************/
static key_channel_t *button_channels[] = {&adkey_key,NULL};
//添加其他不同类型的按键头文件
static void *g_key_msgq = NULL;
static struct list_head wait_register_list;
static struct list_head register_list;
static uint8_t key_callback_change = 0;
void *add_keycallback(key_callback callback,void *priv)
{
struct key_callback_list_s *add_list = os_zalloc(sizeof(struct key_callback_list_s));
if(!add_list)
{
return NULL;
}
add_list->priv = priv;
add_list->callback = callback;
add_list->flag = 0;
INIT_LIST_HEAD(&add_list->list);
uint32_t flags;
os_printf("add_list:%X\n",add_list);
flags = disable_irq();
list_add_tail(&add_list->list, &wait_register_list);
key_callback_change = 1;
enable_irq(flags);
return add_list;
}
uint8_t remove_keycallback(struct key_callback_list_s *remove_list)
{
uint32_t flags;
flags = disable_irq();
remove_list->flag = 1;
key_callback_change = 1;
enable_irq(flags);
return 0;
}
//获取按键的workqueue或者任务
static int32 key_read_loop(struct os_work *work)
{
struct key_msg_s key_msg;
struct key_callback_list_s *ptr, *next;
void *msg = g_key_msgq;
int res;
uint32_t val = 0;
uint32_t extern_value = 0;
//判断一下标志位
//可能有链表要移除或者新增加callback
if(key_callback_change)
{
uint32_t flags;
flags = disable_irq();
//先添加,后移除
list_for_each_entry_safe(ptr, next, &wait_register_list, list)
{
list_del(&ptr->list);
list_add_tail(&ptr->list, &register_list);
}
list_for_each_entry_safe(ptr, next, &register_list, list)
{
// 对每个节点执行操作
if(ptr->flag)
{
os_printf("del key_callback:%X\n",ptr);
list_del(&ptr->list); // 从链表中删除节点
os_free(ptr); // 释放节点内存
}
}
key_callback_change = 0;
enable_irq(flags);
}
res = csi_kernel_msgq_get(msg,&key_msg,0);
if(!res)
{
val = key_msg.keycode;
extern_value = key_msg.extern_value;
//os_printf("key:%d\tstatus:%d\textern_value:%d\n",val>>8,val&0xff,extern_value);
list_for_each_entry_safe(ptr, next, &register_list, list)
{
//_os_printf("register ptr:%X\n",ptr);
if(ptr->callback)
{
ptr->callback(ptr,val,extern_value);
}
}
}
//隔1ms读取一次按键,因为用的是workqueue,不能卡住这个任务,这里的1ms也不是准确的,因为按键,所以可以延时,如果延时太大,要检查
//workqueue哪个事件卡住导致的
os_run_work_delay(work, 1);
return 0;
}
//注册的的消息函数
static int32 key_send_msg_func(uint32_t data,uint32_t extern_value)
{
struct key_msg_s key_msg = {data,extern_value};
if(g_key_msgq)
{
return csi_kernel_msgq_put(g_key_msgq,&key_msg,0,0);;
}
return RET_ERR;
}
//初始化函数
static struct os_work key_wk;
int32 keyWork_init(int listen_max)
{
//创建key的信号量
INIT_LIST_HEAD(&wait_register_list);
INIT_LIST_HEAD(&register_list);
void *key_msgq = (void*)csi_kernel_msgq_new(listen_max,sizeof(struct key_msg_s));
if(key_msgq)
{
g_key_msgq = key_msgq;
key_button_scan_init(button_channels,key_send_msg_func);
//使用workqueue去监听按键?如果没有workqueue就使用创建线程吧
OS_WORK_INIT(&key_wk, key_read_loop, 0);
os_run_work_delay(&key_wk, 1);
return RET_OK;
}
return RET_ERR;
}

30
sdk/lib/key/keyWork.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef __KEYWORK_H
#define __KEYWORK_H
#include "sys_config.h"
#include "typesdef.h"
#include "list.h"
struct key_callback_list_s;
//keyvalue:按键的键值和状态
//extern_value:额外参数,根据不同按键传输数据不一样,比如adkey传的是adc的值,如果是powerkey,可以传输对应的电量值
typedef uint32_t (*key_callback)(struct key_callback_list_s *key_callback_list,uint32_t keyvalue,uint32_t extern_value);
struct key_callback_list_s
{
struct list_head list;
key_callback callback;
void *priv;
uint8_t flag; //0正常 1要删除
};
struct key_msg_s
{
uint32_t keycode;
uint32_t extern_value;
};
void *add_keycallback(key_callback callback,void *priv);
uint8_t remove_keycallback(struct key_callback_list_s *remove_list);
int32 keyWork_init(int listen_max);
#endif

View File

@@ -0,0 +1,98 @@
#include "sys_config.h"
#include "typesdef.h"
#include "adkey.h"
#include "keyScan.h"
#include "dev/adc/hgadc_v0.h"
#include "hal/gpio.h"
static void key_powerkey_init(key_channel_t *key)
{
adkey_t *adkey = (adkey_t *)key->priv;
struct hgadc_v0 *adc = (struct hgadc_v0*)dev_get(HG_ADC0_DEVID);
adc_open((struct adc_device *)adc);
gpio_set_mode(adkey->pin,adkey->pull,adkey->pull_level);
adc_add_channel((struct adc_device *)adc, adkey->pin);
adkey->priv = (void*)adc;
key->enable = 1;
}
static uint8 key_powerkey_scan(key_channel_t *key)
{
adkey_t *adkey = (adkey_t *)key->priv;
uint32 vol;
struct adkey_scan_code *key_scan = (struct adkey_scan_code*)key->key_table;
adc_get_value((struct adc_device *)adkey->priv, adkey->pin, &vol);
//记录当前adc的值,用与发送到应用层,至于应用层是否需要,由应用层去管理
key->extern_value = vol;
for(;;)
{
if(vol>=key_scan->adc)
{
key_scan++;
}
else
{
key_scan--;
break;
}
}
return key_scan->key;
}
/*********************************************************
* powerkey的参数配置
*
* 可以配置类似低电量的检测
************************************************************/
static const struct adkey_scan_code powerkey_table[] =
{
{0, LOWPOWER_CHECK},
{400, KEY_NONE},
{4096, KEY_NONE},
};
//配置对应的时间,正常来说,电量检测不需要短按事件,只要设置长按以及repeat的事件就行了,repeat就是
//当前电量
static const keys_t powerkey_arg =
{
.period_long = 500,
.period_repeat = 1000,
.period_dither = 80,
};
static adkey_t powerkey= {
.priv = NULL,
.pin = PA_3,
.pull = GPIO_PULL_NONE,
.pull_level = GPIO_PULL_LEVEL_100K,
};
//这里逻辑与ADKEY一样,因为都是ad检测
key_channel_t powercheck_key =
{
.init = key_powerkey_init,
.scan = key_powerkey_scan,
.prepare = NULL,
.priv = (void*)&powerkey,
.key_arg = &powerkey_arg,//按键的参数,可能不同的类型按键,参数不一样
.key_table = &powerkey_table,
};

View File

@@ -0,0 +1,15 @@
#ifndef __POWER_CHECKKEY_H
#define __POWER_CHECKKEY_H
#include "sys_config.h"
#include "typesdef.h"
#include "list.h"
#include "dev.h"
#include "devid.h"
#include "hal/gpio.h"
#include "osal/timer.h"
#include "osal/semaphore.h"
#include "osal/mutex.h"
#include "keyScan.h"
key_channel_t powercheck_key;
#endif