AC63_BT_SDK/apps/hid/modules/bt/edr_hid_user.c
2025-02-18 15:40:42 +08:00

741 lines
18 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "app_config.h"
#include "app_action.h"
#include "system/includes.h"
#include "spp_user.h"
#include "string.h"
#include "circular_buf.h"
#include "spp_trans_data.h"
#include "bt_common.h"
#include "btstack/avctp_user.h"
#include "circular_buf.h"
#include "edr_hid_user.h"
#include "standard_hid.h"
#include "app_comm_bt.h"
#if TCFG_USER_EDR_ENABLE && (USER_SUPPORT_PROFILE_HID ==1)
#if 1
//#define log_info y_printf
extern void put_buf(const u8 *buf, int len);
#define log_info(x, ...) printf("[EDR_HID]" x " ", ## __VA_ARGS__)
#define log_info_hexdump put_buf
#else
#define log_info(...)
#define log_info_hexdump(...)
#endif
#define TEST_USER_HID_EN 0
/*message type*/ /*hex*/ /*sent by*/
#define HID_HANDSHAKE 0x00 /*Device*/
#define HID_CONTROL 0x10 /*Device&host*/
/**0x20,0x30 Reserved*/
#define HID_GET_REPORT 0x40 /*host*/
#define HID_SET_REPORT 0x50 /*host*/
#define HID_GET_PROTOCOL 0x60 /*host*/
#define HID_SET_PROTOCOL 0x70 /*host*/
#define HID_GET_IDLE 0x80 /*host DEPRECATED*/
#define HID_SET_IDLE 0x90 /*host DEPRECATED*/
#define HID_DATA 0xA0 /*Device&host*/
#define HID_DATC 0xB0 /*Device&host DEPRECATED*/
/*C-F Reserved*/
#define HID_DATA 0xA0 /*Device&host*/
#define HID_DATC 0xB0 /*Device&host DEPRECATED*/
/*DATA*/
#define DATA_OTHER 0x00
#define DATA_INPUT 0x01
#define DATA_OUTPUT 0x02
#define DATA_FEATURE 0x03
static u8 *report_map;
static u16 report_map_size;
#define HID_REPORT_MAP_DATA report_map
#define HID_REPORT_MAP_SIZE report_map_size
/* #define MOUSE_REPORT_TYPE 0xA1 */
/* #define MOUSE_REPORT_ID 1 */
static void (*user_hid_send_wakeup)(void) = NULL;
static u16 hid_channel;//inter_channel
static u16 hid_ctrl_channel;//ctrl_channel
static volatile u8 hid_run = 0;
static volatile u8 is_hid_active = 0;
static volatile u8 hid_s_step = 0;
/* static int hid_timer_id = 0; */
int hid_timer_id = 0;
int edr_hid_timer_handle = 0;
#define HID_SEND_MAX_SIZE (16) //描述符数据包的长度
/* static u8 edr_hid_one_packet[HID_SEND_MAX_SIZE]; */
/* static volatile u16 edr_send_packet_len = 0; */
static volatile u8 bt_send_busy = 0;
void (*user_led_status_callback)(u8 *buffer, u16 size) = NULL;
#define HID_TMP_BUFSIZE (64*2)
#define cbuf_get_space(a) (a)->total_len
static cbuffer_t user_send_cbuf;
static u8 hid_tmp_buffer[HID_TMP_BUFSIZE];
extern void hid_diy_regiest_callback(void *cb, void *interrupt_cb);
extern void hid_sdp_init(const u8 *hid_descriptor, u16 size);
extern uint16_t little_endian_read_16(const uint8_t *buffer, int pos);
typedef struct {
u8 report_type;
u8 report_id;
u8 data[HID_SEND_MAX_SIZE - 2];
} hid_data_info_t;
//-----------------------------------------------------
/*************************************************************************************************/
/*!
* \brief post event
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
static void edr_bt_evnet_post(u32 arg_type, u8 priv_event, u8 *args, u32 value)
{
struct sys_event e;
e.type = SYS_BT_EVENT;
e.arg = (void *)arg_type;
e.u.bt.event = priv_event;
if (args) {
memcpy(e.u.bt.args, args, 7);
}
e.u.bt.value = value;
sys_event_notify(&e);
}
/*************************************************************************************************/
/*!
* \brief 参考识别手机系统
*
* \param [in]
enum {
REMOTE_DEV_UNKNOWN = 0,
REMOTE_DEV_ANDROID ,
REMOTE_DEV_IOS ,
};
*
* \return
*
* \note
*/
/*************************************************************************************************/
void sdp_callback_remote_type(u8 remote_type)
{
log_info("edr_hid:remote_type= %d\n", remote_type);
edr_bt_evnet_post(SYS_BT_EVENT_FORM_COMMON, COMMON_EVENT_EDR_REMOTE_TYPE, NULL, remote_type);
//to do
}
/*************************************************************************************************/
/*!
* \brief read send data form send_buf
*
* \param [in]
*
* \return len
*
* \note
*/
/*************************************************************************************************/
static u16 user_data_read_sub(u8 *buf, u16 buf_size)
{
u16 ret_len;
if (0 == cbuf_get_data_size(&user_send_cbuf)) {
return 0;
}
OS_ENTER_CRITICAL();
cbuf_read(&user_send_cbuf, &ret_len, 2);
if (ret_len && ret_len <= buf_size) {
cbuf_read(&user_send_cbuf, buf, ret_len);
}
OS_EXIT_CRITICAL();
return ret_len;
}
/*************************************************************************************************/
/*!
* \brief try send
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
static void user_data_try_send(void)
{
u16 send_len;
if (bt_send_busy) {
return;
}
bt_send_busy = 1;//hold
u8 tmp_send_buf[HID_SEND_MAX_SIZE];
send_len = user_data_read_sub(tmp_send_buf, HID_SEND_MAX_SIZE);
if (send_len) {
if (user_hid_send_data(tmp_send_buf, send_len)) {
bt_send_busy = 0;
}
} else {
//not send
bt_send_busy = 0;
}
}
/*************************************************************************************************/
/*!
* \brief write data to send buffer
*
* \param [in]
*
* \return len
*
* \note
*/
/*************************************************************************************************/
static u32 user_data_write_sub(u8 *data, u16 len)
{
u16 wlen = 0;
u16 buf_space = cbuf_get_space(&user_send_cbuf) - cbuf_get_data_size(&user_send_cbuf);
if (len + 2 > buf_space) {
return 0;
}
OS_ENTER_CRITICAL();
wlen = cbuf_write(&user_send_cbuf, &len, 2);
wlen += cbuf_write(&user_send_cbuf, data, len);
OS_EXIT_CRITICAL();
user_data_try_send();
return wlen;
}
/*************************************************************************************************/
/*!
* \brief 设置搜索显示的图标
*
* \param [in]class_type,define in avctp_user.h
*
* \return
*
* \note 协议栈初始化前调用
*/
/*************************************************************************************************/
void user_hid_set_icon(u32 class_type)
{
__change_hci_class_type(class_type);//
}
/*************************************************************************************************/
/*!
* \brief 设置描述符
*
* \param [in]
*
* \return
*
* \note 协议栈初始化前调用
*/
/*************************************************************************************************/
void user_hid_set_ReportMap(u8 *map, u16 size)
{
report_map = map;
report_map_size = size;
if (hid_run) {
hid_sdp_init(HID_REPORT_MAP_DATA, HID_REPORT_MAP_SIZE);
}
}
/* const hid_ctl_info_t test_key[5] = { */
/* {0xA1, 1, 0, 0, 0}, */
/* {0xA1, 1, 0, 100, 0}, */
/* {0xA1, 1, 0, -100, 0}, */
/* }; */
/* static void test_hid_send_step(void) */
/* { */
/* static u8 xy_step = 0; */
/* u8 send_len = 5; */
/* if (!hid_s_step) { */
/* return; */
/* } */
/* xy_step = !xy_step; */
/* if (xy_step) { */
/* hid_s_step = 1; */
/* } else { */
/* hid_s_step = 2; */
/* } */
/* if (0 == user_hid_send_data((u8 *)&test_key[hid_s_step], send_len)) { */
/* hid_s_step = 0; */
/* } */
/* } */
/*************************************************************************************************/
/*!
* \brief timer
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
static void user_hid_timer_handler(void *para)
{
/* static u8 count = 0; */
if (!hid_channel) {
return;
}
/* if (++count > 5) { */
/* count = 0; */
/* hid_s_step = 1; */
/* test_hid_send_step(); */
/* } */
/* hid_key_send(CONSUMER_PLAY_PAUSE); */
}
/*************************************************************************************************/
/*!
* \brief check is idle, enter sleep
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
static u8 user_hid_idle_query(void)
{
return !is_hid_active;
}
REGISTER_LP_TARGET(hid_user_target) = {
.name = "hid_user",
.is_idle = user_hid_idle_query,
};
/*************************************************************************************************/
/*!
* \brief 协议栈发送hid数据包完成 回调
*
* \param [in]
*
* \return
*
* \note 可用于唤醒及时往协议栈发送数据操作
*/
/*************************************************************************************************/
static void user_hid_send_ok_callback(void)
{
/* putchar('K'); */
bt_send_busy = 0;
if (user_hid_send_wakeup) {
user_hid_send_wakeup();
}
user_data_try_send();
/* test_hid_send_step(); */
}
/*************************************************************************************************/
/*!
* \brief 注册唤醒发送回调
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
void user_hid_regiser_wakeup_send(void *cbk)
{
user_hid_send_wakeup = cbk;
}
/*************************************************************************************************/
/*!
* \brief disconnect
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
void user_hid_disconnect(void)
{
if (hid_channel) {
user_send_cmd_prepare(USER_CTRL_HID_DISCONNECT, 0, NULL);
}
}
/*************************************************************************************************/
/*!
* \brief hid channel,send data
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
int user_hid_send_data(u8 *buf, u32 len)
{
int ret;
hid_s_param_t s_par;
if (!hid_channel) {
return -1;
}
s_par.chl_id = hid_channel;
s_par.data_len = len;
s_par.data_ptr = buf;
ret = user_send_cmd_prepare(USER_CTRL_HID_SEND_DATA, sizeof(hid_s_param_t), (u8 *)&s_par);
if (ret) {
log_info("hid send fail!!! %d\n", ret);
}
return ret;
}
/*************************************************************************************************/
/*!
* \brief hid event handle
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
static void user_hid_msg_handler(u32 msg, u8 *packet, u32 packet_size)
{
u16 tmp_chl;
switch (msg) {
case 1: {
hid_ctrl_channel = little_endian_read_16(packet, 0); //ctrl_channel
hid_channel = little_endian_read_16(packet, 2); //inter_channel
bt_send_busy = 0;
log_info("hid connect ########################,%d,%d\n", hid_ctrl_channel, hid_channel);
cbuf_init(&user_send_cbuf, hid_tmp_buffer, HID_TMP_BUFSIZE);
}
break;
case 2:
log_info("hid disconnect ########################\n");
hid_channel = 0;
hid_ctrl_channel = 0;
cbuf_init(&user_send_cbuf, hid_tmp_buffer, HID_TMP_BUFSIZE);
break;
case 3:
if (hid_channel == little_endian_read_16(packet, 0) ||
hid_ctrl_channel == little_endian_read_16(packet, 0)) {
user_hid_send_ok_callback();
}
break;
default:
break;
}
}
/*************************************************************************************************/
/*!
* \brief init
*
* \param [in] output_handle
*
* \return
*
* \note
*/
/*************************************************************************************************/
void user_hid_init(void (*user_hid_output_handler)(u8 *packet, u16 size, u16 channel))
{
log_info("%s\n", __FUNCTION__);
hid_channel = 0;
hid_ctrl_channel = 0;
hid_diy_regiest_callback(user_hid_msg_handler, user_hid_output_handler);
if (!hid_run) {
log_info("hid_sdp_init\n");
hid_sdp_init(HID_REPORT_MAP_DATA, HID_REPORT_MAP_SIZE);
#if TEST_USER_HID_EN
if (!hid_timer_id) {
hid_timer_id = sys_s_hi_timer_add((void *)0, user_hid_timer_handler, 5000);
}
#endif
cbuf_init(&user_send_cbuf, hid_tmp_buffer, HID_TMP_BUFSIZE);
hid_run = 1;
}
}
/*************************************************************************************************/
/*!
* \brief exit
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
void user_hid_exit(void)
{
log_info("%s\n", __FUNCTION__);
if (hid_run) {
log_info("hid free\n");
if (hid_timer_id) {
user_hid_disconnect();
sys_s_hi_timer_del(hid_timer_id);
hid_timer_id = 0;
}
if (edr_hid_timer_handle) {
sys_s_hi_timer_del(edr_hid_timer_handle);
edr_hid_timer_handle = 0;
}
hid_run = 0;
}
}
/*************************************************************************************************/
/*!
* \brief module_enable
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
void user_hid_enable(u8 en)
{
log_info("%s:%d\n", __FUNCTION__, en);
if (en) {
;
} else {
user_hid_disconnect();
}
}
/*************************************************************************************************/
/*!
* \brief hid send report data
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
int edr_hid_data_send_ext(u8 report_type, u8 report_id, u8 *data, u16 len)
{
if (!hid_channel) {
return 1;
}
if (len > HID_SEND_MAX_SIZE - 2) {
log_info("buffer limitp!!!\n");
return 2;
}
bt_comm_edr_sniff_clean();
putchar('@');
hid_data_info_t data_info;
data_info.report_type = report_type;
data_info.report_id = report_id;
memcpy(data_info.data, data, len);
if (!user_data_write_sub((u8 *)&data_info, 2 + len)) {
log_info("hid buffer full!!!\n");
return 3;
}
return 0;
}
/*************************************************************************************************/
/*!
* \brief hid send report data
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
int edr_hid_data_send(u8 report_id, u8 *data, u16 len)
{
return edr_hid_data_send_ext(HID_DATA | DATA_INPUT, report_id, data, len);
}
/*************************************************************************************************/
/*!
* \brief send test key demo
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
void edr_hid_key_deal_test(u16 key_msg)
{
//default report_id 1
edr_hid_data_send(1, (u8 *)&key_msg, 2);
if (key_msg) {
key_msg = 0;
edr_hid_data_send(1, (u8 *)&key_msg, 2);
}
}
/*************************************************************************************************/
/*!
* \brief check connect
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
int edr_hid_is_connected(void)
{
return hid_channel;
}
/*************************************************************************************************/
/*!
* \brief check btstack send busy
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
int edr_hid_is_busy(void)
{
return bt_send_busy;
}
/*************************************************************************************************/
/*!
* \brief check tx buffer
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
extern u32 lmp_private_get_tx_remain_buffer();
int edr_hid_tx_buff_is_ok(void)
{
if (lmp_private_get_tx_remain_buffer() < 0x300) {
putchar('b');
return 0;
}
return 1;
}
/*************************************************************************************************/
/*!
* \brief hook处理ctrl通道命令返回0则由库来处理。非0执行回复命令发送
* \param [in]channel l2cap连接通道
* \param [in]packet 接收命令buffer
* \param [in]size 命令长度
* \param [out] respond_buf_ptr 回复的buf指针
* \return 回复命令的长度
* \note
*/
/*************************************************************************************************/
int hid_ctrl_data_parse_hook(u16 channel, const u8 *packet, int size, int *respond_buf_ptr)
{
int respone_len = 0;
static u8 hid_respone_buffer[8];
switch (packet[0] & 0xf0) {
case HID_GET_REPORT:
if (packet[1] == 0x01) {//report id,应答是对应app_keyboard.c的描述符
hid_respone_buffer[0] = HID_DATA | DATA_INPUT;
//report id + payload;根据描述符来回复长度
hid_respone_buffer[1] = packet[1];
hid_respone_buffer[2] = 0;
hid_respone_buffer[3] = 0;
respone_len = 4;
}
break;
default:
break;
}
if (respone_len) {
*respond_buf_ptr = hid_respone_buffer;
}
return respone_len;
}
#endif