blob: db447be9d247db4a5e71df1969fc6f7f5a588545 [file] [log] [blame]
use crate::bindings::root as bindings;
use crate::btif::{BluetoothInterface, BtStatus, RawAddress, SupportedProfiles};
use crate::profiles::hid_host::bindings::bthh_interface_t;
use crate::topstack::get_dispatchers;
use crate::{cast_to_ffi_address, ccall, deref_ffi_address};
use num_traits::cast::{FromPrimitive, ToPrimitive};
use std::sync::{Arc, Mutex};
use topshim_macros::cb_variant;
#[derive(Debug, FromPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BthhConnectionState {
Connected = 0,
Connecting,
Disconnected,
Disconnecting,
Unknown = 0xff,
}
impl From<bindings::bthh_connection_state_t> for BthhConnectionState {
fn from(item: bindings::bthh_connection_state_t) -> Self {
BthhConnectionState::from_u32(item).unwrap_or_else(|| BthhConnectionState::Unknown)
}
}
#[derive(Debug, FromPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BthhStatus {
Ok = 0,
HsHidNotReady,
HsInvalidRptId,
HsTransNotSpt,
HsInvalidParam,
HsError,
Error,
ErrSdp,
ErrProto,
ErrDbFull,
ErrTodUnspt,
ErrNoRes,
ErrAuthFailed,
ErrHdl,
Unknown,
}
impl From<bindings::bthh_status_t> for BthhStatus {
fn from(item: bindings::bthh_status_t) -> Self {
BthhStatus::from_u32(item).unwrap_or_else(|| BthhStatus::Unknown)
}
}
pub type BthhHidInfo = bindings::bthh_hid_info_t;
#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BthhProtocolMode {
ReportMode = 0,
BootMode = 1,
UnsupportedMode = 0xff,
}
impl From<bindings::bthh_protocol_mode_t> for BthhProtocolMode {
fn from(item: bindings::bthh_protocol_mode_t) -> Self {
BthhProtocolMode::from_u32(item).unwrap_or_else(|| BthhProtocolMode::UnsupportedMode)
}
}
impl From<BthhProtocolMode> for bindings::bthh_protocol_mode_t {
fn from(item: BthhProtocolMode) -> Self {
item.to_u32().unwrap()
}
}
#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BthhReportType {
InputReport = 1,
OutputReport = 2,
FeatureReport = 3,
}
impl From<BthhReportType> for bindings::bthh_report_type_t {
fn from(item: BthhReportType) -> Self {
item.to_u32().unwrap()
}
}
fn convert_report(count: i32, raw: *mut u8) -> Vec<u8> {
let mut v: Vec<u8> = Vec::new();
for i in 0..isize::from_i32(count).unwrap() {
let p: *const u8 = unsafe { raw.offset(i) };
v.push(unsafe { *p });
}
return v;
}
pub enum HHCallbacks {
ConnectionState(RawAddress, BthhConnectionState),
VirtualUnplug(RawAddress, BthhStatus),
HidInfo(RawAddress, BthhHidInfo),
ProtocolMode(RawAddress, BthhStatus, BthhProtocolMode),
IdleTime(RawAddress, BthhStatus, i32),
GetReport(RawAddress, BthhStatus, Vec<u8>, i32),
Handshake(RawAddress, BthhStatus),
}
pub struct HHCallbacksDispatcher {
pub dispatch: Box<dyn Fn(HHCallbacks) + Send>,
}
// Export the raw address type directly from the bindings
type FfiAddress = bindings::RawAddress;
type HHCb = Arc<Mutex<HHCallbacksDispatcher>>;
cb_variant!(HHCb, connection_state_cb -> HHCallbacks::ConnectionState,
*mut FfiAddress, bindings::bthh_connection_state_t -> BthhConnectionState, {
let _0 = unsafe { deref_ffi_address!(_0) };
});
cb_variant!(HHCb, virtual_unplug_cb -> HHCallbacks::VirtualUnplug,
*mut FfiAddress, bindings::bthh_status_t -> BthhStatus, {
let _0 = unsafe { deref_ffi_address!(_0) };
});
cb_variant!(HHCb, hid_info_cb -> HHCallbacks::HidInfo,
*mut FfiAddress, bindings::bthh_hid_info_t -> BthhHidInfo, {
let _0 = unsafe { deref_ffi_address!(_0) };
});
cb_variant!(HHCb, protocol_mode_cb -> HHCallbacks::ProtocolMode,
*mut FfiAddress, bindings::bthh_status_t -> BthhStatus,
bindings::bthh_protocol_mode_t -> BthhProtocolMode, {
let _0 = unsafe { deref_ffi_address!(_0) };
});
cb_variant!(HHCb, idle_time_cb -> HHCallbacks::IdleTime,
*mut FfiAddress, bindings::bthh_status_t -> BthhStatus, i32, {
let _0 = unsafe { deref_ffi_address!(_0) };
});
cb_variant!(HHCb, get_report_cb -> HHCallbacks::GetReport,
*mut FfiAddress, bindings::bthh_status_t -> BthhStatus, *mut u8, i32, {
let _0 = unsafe { deref_ffi_address!(_0) };
let _2 = convert_report(_3, _2);
});
cb_variant!(HHCb, handshake_cb -> HHCallbacks::Handshake,
*mut FfiAddress, bindings::bthh_status_t -> BthhStatus, {
let _0 = unsafe { deref_ffi_address!(_0) };
});
struct RawHHWrapper {
raw: *const bindings::bthh_interface_t,
}
// Pointers unsafe due to ownership but this is a static pointer so Send is ok
unsafe impl Send for RawHHWrapper {}
pub struct HidHost {
internal: RawHHWrapper,
is_init: bool,
// Keep callback object in memory (underlying code doesn't make copy)
callbacks: Option<Box<bindings::bthh_callbacks_t>>,
}
impl HidHost {
pub fn new(intf: &BluetoothInterface) -> HidHost {
let r = intf.get_profile_interface(SupportedProfiles::HidHost);
HidHost {
internal: RawHHWrapper { raw: r as *const bthh_interface_t },
is_init: false,
callbacks: None,
}
}
pub fn is_initialized(&self) -> bool {
self.is_init
}
pub fn initialize(&mut self, callbacks: HHCallbacksDispatcher) -> bool {
// Register dispatcher
if get_dispatchers().lock().unwrap().set::<HHCb>(Arc::new(Mutex::new(callbacks))) {
panic!("Tried to set dispatcher for HHCallbacks but it already existed");
}
let mut callbacks = Box::new(bindings::bthh_callbacks_t {
size: 8 * 8,
connection_state_cb: Some(connection_state_cb),
hid_info_cb: Some(hid_info_cb),
protocol_mode_cb: Some(protocol_mode_cb),
idle_time_cb: Some(idle_time_cb),
get_report_cb: Some(get_report_cb),
virtual_unplug_cb: Some(virtual_unplug_cb),
handshake_cb: Some(handshake_cb),
});
let rawcb = &mut *callbacks;
let init = ccall!(self, init, rawcb);
self.is_init = BtStatus::from(init) == BtStatus::Success;
self.callbacks = Some(callbacks);
return self.is_init;
}
pub fn connect(&self, addr: &mut RawAddress) -> BtStatus {
let ffi_addr = cast_to_ffi_address!(addr as *mut RawAddress);
BtStatus::from(ccall!(self, connect, ffi_addr))
}
pub fn disconnect(&self, addr: &mut RawAddress) -> BtStatus {
let ffi_addr = cast_to_ffi_address!(addr as *mut RawAddress);
BtStatus::from(ccall!(self, disconnect, ffi_addr))
}
pub fn virtual_unplug(&self, addr: &mut RawAddress) -> BtStatus {
let ffi_addr = cast_to_ffi_address!(addr as *mut RawAddress);
BtStatus::from(ccall!(self, virtual_unplug, ffi_addr))
}
pub fn set_info(&self, addr: &mut RawAddress, info: BthhHidInfo) -> BtStatus {
let ffi_addr = cast_to_ffi_address!(addr as *mut RawAddress);
BtStatus::from(ccall!(self, set_info, ffi_addr, info))
}
pub fn get_protocol(&self, addr: &mut RawAddress, mode: BthhProtocolMode) -> BtStatus {
let ffi_addr = cast_to_ffi_address!(addr as *mut RawAddress);
BtStatus::from(ccall!(
self,
get_protocol,
ffi_addr,
bindings::bthh_protocol_mode_t::from(mode)
))
}
pub fn set_protocol(&self, addr: &mut RawAddress, mode: BthhProtocolMode) -> BtStatus {
let ffi_addr = cast_to_ffi_address!(addr as *mut RawAddress);
BtStatus::from(ccall!(
self,
set_protocol,
ffi_addr,
bindings::bthh_protocol_mode_t::from(mode)
))
}
pub fn get_idle_time(&self, addr: &mut RawAddress) -> BtStatus {
let ffi_addr = cast_to_ffi_address!(addr as *mut RawAddress);
BtStatus::from(ccall!(self, get_idle_time, ffi_addr))
}
pub fn set_idle_time(&self, addr: &mut RawAddress, idle_time: u8) -> BtStatus {
let ffi_addr = cast_to_ffi_address!(addr as *mut RawAddress);
BtStatus::from(ccall!(self, set_idle_time, ffi_addr, idle_time))
}
pub fn get_report(
&self,
addr: &mut RawAddress,
report_type: BthhReportType,
report_id: u8,
buffer_size: i32,
) -> BtStatus {
let ffi_addr = cast_to_ffi_address!(addr as *mut RawAddress);
BtStatus::from(ccall!(
self,
get_report,
ffi_addr,
bindings::bthh_report_type_t::from(report_type),
report_id,
buffer_size
))
}
pub fn set_report(
&self,
addr: &mut RawAddress,
report_type: BthhReportType,
report: &mut [u8],
) -> BtStatus {
let ffi_addr = cast_to_ffi_address!(addr as *mut RawAddress);
BtStatus::from(ccall!(
self,
set_report,
ffi_addr,
bindings::bthh_report_type_t::from(report_type),
report.as_mut_ptr() as *mut std::os::raw::c_char
))
}
pub fn cleanup(&self) {
ccall!(self, cleanup)
}
}