266 lines
8.5 KiB
C
266 lines
8.5 KiB
C
/****************************************************************************
|
|
* Copyright (C) 2023 Xiaomi Corporation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
***************************************************************************/
|
|
#define LOG_TAG "hid_device_api"
|
|
|
|
#include <stdint.h>
|
|
|
|
#include "bt_hid_device.h"
|
|
#include "bt_profile.h"
|
|
#include "bt_socket.h"
|
|
#include "hid_device_service.h"
|
|
#include "service_manager.h"
|
|
#include "utils/log.h"
|
|
|
|
static bt_status_t safety_assemble_sdp_array(uint8_t** sdp_ptr, size_t* remaining_space, const char* src)
|
|
{
|
|
uint32_t src_len = strlen(src);
|
|
if (src_len + 1 > *remaining_space) {
|
|
return BT_STATUS_NO_RESOURCES;
|
|
}
|
|
|
|
memcpy(*sdp_ptr, src, src_len);
|
|
(*sdp_ptr)[src_len] = '\0';
|
|
*sdp_ptr += (src_len + 1);
|
|
*remaining_space -= (src_len + 1);
|
|
|
|
return BT_STATUS_SUCCESS;
|
|
}
|
|
|
|
static bt_status_t safety_assemble_hid_info(uint8_t** sdp_ptr, size_t* remaining_space, const hid_info_t* hid_info)
|
|
{
|
|
uint32_t info_len = offsetof(hid_info_t, dsc_list);
|
|
|
|
if (info_len + hid_info->dsc_list_length > *remaining_space) {
|
|
return BT_STATUS_NO_RESOURCES;
|
|
}
|
|
|
|
memcpy(*sdp_ptr, hid_info, info_len);
|
|
*sdp_ptr += info_len;
|
|
*remaining_space -= info_len;
|
|
|
|
memcpy(*sdp_ptr, hid_info->dsc_list, hid_info->dsc_list_length);
|
|
*sdp_ptr += hid_info->dsc_list_length;
|
|
*remaining_space -= hid_info->dsc_list_length;
|
|
|
|
return BT_STATUS_SUCCESS;
|
|
}
|
|
|
|
void* bt_hid_device_register_callbacks(bt_instance_t* ins, const hid_device_callbacks_t* callbacks)
|
|
{
|
|
bt_message_packet_t packet;
|
|
bt_status_t status;
|
|
void* cookie;
|
|
|
|
BT_SOCKET_INS_VALID(ins, NULL);
|
|
|
|
if (ins->hidd_callbacks != NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
ins->hidd_callbacks = bt_callbacks_list_new(1);
|
|
|
|
cookie = bt_remote_callbacks_register(ins->hidd_callbacks, NULL, (void*)callbacks);
|
|
if (cookie == NULL) {
|
|
bt_callbacks_list_free(ins->hidd_callbacks);
|
|
ins->hidd_callbacks = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
status = bt_socket_client_sendrecv(ins, &packet, BT_HID_DEVICE_REGISTER_CALLBACK);
|
|
if (status != BT_STATUS_SUCCESS || packet.hidd_r.status != BT_STATUS_SUCCESS) {
|
|
bt_callbacks_list_free(ins->hidd_callbacks);
|
|
ins->hidd_callbacks = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
return cookie;
|
|
}
|
|
|
|
bool bt_hid_device_unregister_callbacks(bt_instance_t* ins, void* cookie)
|
|
{
|
|
bt_message_packet_t packet;
|
|
bt_status_t status;
|
|
callbacks_list_t* cbsl;
|
|
|
|
BT_SOCKET_INS_VALID(ins, false);
|
|
|
|
if (!ins->hidd_callbacks)
|
|
return false;
|
|
|
|
bt_remote_callbacks_unregister(ins->hidd_callbacks, NULL, cookie);
|
|
|
|
cbsl = ins->hidd_callbacks;
|
|
ins->hidd_callbacks = NULL;
|
|
bt_socket_client_free_callbacks(ins, cbsl);
|
|
|
|
status = bt_socket_client_sendrecv(ins, &packet, BT_HID_DEVICE_UNREGISTER_CALLBACK);
|
|
if (status != BT_STATUS_SUCCESS || packet.hidd_r.status != BT_STATUS_SUCCESS)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bt_status_t bt_hid_device_register_app(bt_instance_t* ins, hid_device_sdp_settings_t* sdp, bool le_hid)
|
|
{
|
|
bt_message_packet_t packet;
|
|
bt_status_t status;
|
|
|
|
BT_SOCKET_INS_VALID(ins, BT_STATUS_PARM_INVALID);
|
|
|
|
packet.hidd_pl._bt_hid_device_register_app.le_hid = le_hid;
|
|
uint8_t* sdp_ptr = packet.hidd_pl._bt_hid_device_register_app.sdp;
|
|
size_t remaining_space = sizeof(packet.hidd_pl._bt_hid_device_register_app.sdp);
|
|
|
|
if (BT_STATUS_SUCCESS != safety_assemble_sdp_array(&sdp_ptr, &remaining_space, sdp->name)) {
|
|
return BT_STATUS_NO_RESOURCES;
|
|
}
|
|
|
|
if (BT_STATUS_SUCCESS != safety_assemble_sdp_array(&sdp_ptr, &remaining_space, sdp->description)) {
|
|
return BT_STATUS_NO_RESOURCES;
|
|
}
|
|
|
|
if (BT_STATUS_SUCCESS != safety_assemble_sdp_array(&sdp_ptr, &remaining_space, sdp->provider)) {
|
|
return BT_STATUS_NO_RESOURCES;
|
|
}
|
|
|
|
if (BT_STATUS_SUCCESS != safety_assemble_hid_info(&sdp_ptr, &remaining_space, &sdp->hids_info)) {
|
|
return BT_STATUS_NO_RESOURCES;
|
|
}
|
|
|
|
status = bt_socket_client_sendrecv(ins, &packet, BT_HID_DEVICE_REGISTER_APP);
|
|
if (status != BT_STATUS_SUCCESS)
|
|
return status;
|
|
|
|
return packet.hidd_r.status;
|
|
}
|
|
|
|
bt_status_t bt_hid_device_unregister_app(bt_instance_t* ins)
|
|
{
|
|
bt_message_packet_t packet;
|
|
bt_status_t status;
|
|
|
|
BT_SOCKET_INS_VALID(ins, BT_STATUS_PARM_INVALID);
|
|
|
|
status = bt_socket_client_sendrecv(ins, &packet, BT_HID_DEVICE_UNREGISTER_APP);
|
|
if (status != BT_STATUS_SUCCESS)
|
|
return status;
|
|
|
|
return packet.hidd_r.status;
|
|
}
|
|
|
|
bt_status_t bt_hid_device_connect(bt_instance_t* ins, bt_address_t* addr)
|
|
{
|
|
bt_message_packet_t packet;
|
|
bt_status_t status;
|
|
|
|
BT_SOCKET_INS_VALID(ins, BT_STATUS_PARM_INVALID);
|
|
|
|
memcpy(&packet.hidd_pl._bt_hid_device_connect.addr, addr, sizeof(bt_address_t));
|
|
status = bt_socket_client_sendrecv(ins, &packet, BT_HID_DEVICE_CONNECT);
|
|
if (status != BT_STATUS_SUCCESS)
|
|
return status;
|
|
|
|
return packet.hidd_r.status;
|
|
}
|
|
|
|
bt_status_t bt_hid_device_disconnect(bt_instance_t* ins, bt_address_t* addr)
|
|
{
|
|
bt_message_packet_t packet;
|
|
bt_status_t status;
|
|
|
|
BT_SOCKET_INS_VALID(ins, BT_STATUS_PARM_INVALID);
|
|
|
|
memcpy(&packet.hidd_pl._bt_hid_device_disconnect.addr, addr, sizeof(bt_address_t));
|
|
status = bt_socket_client_sendrecv(ins, &packet, BT_HID_DEVICE_DISCONNECT);
|
|
if (status != BT_STATUS_SUCCESS)
|
|
return status;
|
|
|
|
return packet.hidd_r.status;
|
|
}
|
|
|
|
bt_status_t bt_hid_device_send_report(bt_instance_t* ins, bt_address_t* addr, uint8_t rpt_id, uint8_t* rpt_data, int rpt_size)
|
|
{
|
|
bt_message_packet_t packet;
|
|
bt_status_t status;
|
|
|
|
BT_SOCKET_INS_VALID(ins, BT_STATUS_PARM_INVALID);
|
|
|
|
if (rpt_size > sizeof(packet.hidd_pl._bt_hid_device_send_report.rpt_data))
|
|
return BT_STATUS_PARM_INVALID;
|
|
|
|
memcpy(&packet.hidd_pl._bt_hid_device_send_report.addr, addr, sizeof(bt_address_t));
|
|
packet.hidd_pl._bt_hid_device_send_report.rpt_id = rpt_id;
|
|
packet.hidd_pl._bt_hid_device_send_report.rpt_size = rpt_size;
|
|
memcpy(packet.hidd_pl._bt_hid_device_send_report.rpt_data, rpt_data, rpt_size);
|
|
status = bt_socket_client_sendrecv(ins, &packet, BT_HID_DEVICE_SEND_REPORT);
|
|
if (status != BT_STATUS_SUCCESS)
|
|
return status;
|
|
|
|
return packet.hidd_r.status;
|
|
}
|
|
|
|
bt_status_t bt_hid_device_response_report(bt_instance_t* ins, bt_address_t* addr, uint8_t rpt_type, uint8_t* rpt_data, int rpt_size)
|
|
{
|
|
bt_message_packet_t packet;
|
|
bt_status_t status;
|
|
|
|
BT_SOCKET_INS_VALID(ins, BT_STATUS_PARM_INVALID);
|
|
|
|
if (rpt_size > sizeof(packet.hidd_pl._bt_hid_device_response_report.rpt_data))
|
|
return BT_STATUS_PARM_INVALID;
|
|
|
|
memcpy(&packet.hidd_pl._bt_hid_device_response_report.addr, addr, sizeof(bt_address_t));
|
|
packet.hidd_pl._bt_hid_device_response_report.rpt_type = rpt_type;
|
|
packet.hidd_pl._bt_hid_device_response_report.rpt_size = rpt_size;
|
|
memcpy(packet.hidd_pl._bt_hid_device_response_report.rpt_data, rpt_data, rpt_size);
|
|
status = bt_socket_client_sendrecv(ins, &packet, BT_HID_DEVICE_RESPONSE_REPORT);
|
|
if (status != BT_STATUS_SUCCESS)
|
|
return status;
|
|
|
|
return packet.hidd_r.status;
|
|
}
|
|
|
|
bt_status_t bt_hid_device_report_error(bt_instance_t* ins, bt_address_t* addr, hid_status_error_t error)
|
|
{
|
|
bt_message_packet_t packet;
|
|
bt_status_t status;
|
|
|
|
BT_SOCKET_INS_VALID(ins, BT_STATUS_PARM_INVALID);
|
|
|
|
memcpy(&packet.hidd_pl._bt_hid_device_report_error.addr, addr, sizeof(bt_address_t));
|
|
packet.hidd_pl._bt_hid_device_report_error.error = error;
|
|
status = bt_socket_client_sendrecv(ins, &packet, BT_HID_DEVICE_REPORT_ERROR);
|
|
if (status != BT_STATUS_SUCCESS)
|
|
return status;
|
|
|
|
return packet.hidd_r.status;
|
|
}
|
|
|
|
bt_status_t bt_hid_device_virtual_unplug(bt_instance_t* ins, bt_address_t* addr)
|
|
{
|
|
bt_message_packet_t packet;
|
|
bt_status_t status;
|
|
|
|
BT_SOCKET_INS_VALID(ins, BT_STATUS_PARM_INVALID);
|
|
|
|
memcpy(&packet.hidd_pl._bt_hid_device_virtual_unplug.addr, addr, sizeof(bt_address_t));
|
|
status = bt_socket_client_sendrecv(ins, &packet, BT_HID_DEVICE_VIRTUAL_UNPLUG);
|
|
if (status != BT_STATUS_SUCCESS)
|
|
return status;
|
|
|
|
return packet.hidd_r.status;
|
|
}
|