Bluetooth B1: HCI protocol types, USB transport, daemon state machine

Add complete HCI protocol module (hci.rs) with packet types, 55+ constants,
command builders (Reset, Read BD Addr, Read Local Version, LE scan/connect),
event parsers, and structured result types. Add USB transport abstraction
(usb_transport.rs) with UsbHciTransport trait and StubTransport for testing.

Wire btusb daemon with endpoint descriptor parsing, HCI init sequence
(Reset → Read BD Addr → Read Local Version), ControllerState state machine,
and enhanced status output. Replace all expect()/unwrap() calls in btctl
and wifictl with proper error handling and graceful fallback.

91 btusb tests, 27 btctl tests, 2 wifictl tests passing.
This commit is contained in:
2026-04-24 22:46:35 +01:00
parent 183354fcb1
commit f392c7bf7d
5 changed files with 2360 additions and 38 deletions
@@ -21,33 +21,44 @@ fn init_logging(level: LevelFilter) {
}
#[cfg(target_os = "redox")]
unsafe fn get_init_notify_fd() -> RawFd {
let fd: RawFd = env::var("INIT_NOTIFY")
.expect("redbear-wifictl: INIT_NOTIFY not set")
.parse()
.expect("redbear-wifictl: INIT_NOTIFY is not a valid fd");
unsafe fn get_init_notify_fd() -> Option<RawFd> {
let Ok(value) = env::var("INIT_NOTIFY") else {
return None;
};
let Ok(fd) = value.parse::<RawFd>() else {
return None;
};
unsafe {
libc::fcntl(fd, libc::F_SETFD, libc::FD_CLOEXEC);
}
fd
Some(fd)
}
#[cfg(target_os = "redox")]
fn notify_scheme_ready(notify_fd: RawFd, socket: &Socket, scheme: &mut WifiCtlScheme) {
let cap_id = scheme
.scheme_root()
.expect("redbear-wifictl: scheme_root failed");
let cap_fd = socket
.create_this_scheme_fd(0, cap_id, 0, 0)
.expect("redbear-wifictl: create_this_scheme_fd failed");
fn notify_scheme_ready(notify_fd: Option<RawFd>, socket: &Socket, scheme: &mut WifiCtlScheme) {
let Some(notify_fd) = notify_fd else {
return;
};
syscall::call_wo(
let Ok(cap_id) = scheme.scheme_root() else {
log::warn!("redbear-wifictl: scheme_root failed; continuing without scheme notification");
return;
};
let Ok(cap_fd) = socket.create_this_scheme_fd(0, cap_id, 0, 0) else {
log::warn!("redbear-wifictl: create_this_scheme_fd failed; continuing without scheme notification");
return;
};
if let Err(err) = syscall::call_wo(
notify_fd as usize,
&libredox::Fd::new(cap_fd).into_raw().to_ne_bytes(),
syscall::CallFlags::FD,
&[],
)
.expect("redbear-wifictl: failed to notify init that scheme is ready");
) {
log::warn!(
"redbear-wifictl: failed to notify init that scheme is ready ({err}); continuing with manual startup"
);
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]