summaryrefslogtreecommitdiff
path: root/system/gd/rust/stack/src/hal/hidl_hal.rs
blob: bb9daa23f8e352efed8758def12c5ac4e7139c4c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! Implementation of the HAl that talks to BT controller over Android's HIDL
use crate::hal::internal::{InnerHal, RawHal};
use bt_packets::hci::{AclPacket, CommandPacket, EventPacket, IsoPacket, Packet, ScoPacket};
use gddi::{module, provides};
use std::sync::Arc;
use std::sync::Mutex;
use tokio::runtime::Runtime;
use tokio::select;
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};

module! {
    hidl_hal_module,
    providers {
        RawHal => provide_hidl_hal,
    }
}

#[provides]
async fn provide_hidl_hal(rt: Arc<Runtime>) -> RawHal {
    let (raw_hal, inner_hal) = InnerHal::new();
    let (init_tx, mut init_rx) = unbounded_channel();
    *CALLBACKS.lock().unwrap() = Some(Callbacks {
        init_tx,
        evt_tx: inner_hal.evt_tx,
        acl_tx: inner_hal.acl_tx,
        iso_tx: inner_hal.iso_tx,
        sco_tx: inner_hal.sco_tx,
    });
    ffi::start_hal();
    init_rx.recv().await.unwrap();

    rt.spawn(dispatch_outgoing(
        inner_hal.cmd_rx,
        inner_hal.acl_rx,
        inner_hal.iso_rx,
        inner_hal.sco_rx,
    ));

    raw_hal
}

#[cxx::bridge(namespace = bluetooth::hal)]
// TODO Either use or remove these functions, this shouldn't be the long term state
#[allow(dead_code)]
mod ffi {
    unsafe extern "C++" {
        include!("src/hal/ffi/hidl.h");
        fn start_hal();
        fn stop_hal();
        fn send_command(data: &[u8]);
        fn send_acl(data: &[u8]);
        fn send_sco(data: &[u8]);
        fn send_iso(data: &[u8]);
    }

    extern "Rust" {
        fn on_init_complete();
        fn on_event(data: &[u8]);
        fn on_acl(data: &[u8]);
        fn on_sco(data: &[u8]);
        fn on_iso(data: &[u8]);
    }
}

struct Callbacks {
    init_tx: UnboundedSender<()>,
    evt_tx: UnboundedSender<EventPacket>,
    acl_tx: UnboundedSender<AclPacket>,
    iso_tx: UnboundedSender<IsoPacket>,
    sco_tx: UnboundedSender<ScoPacket>,
}

lazy_static! {
    static ref CALLBACKS: Mutex<Option<Callbacks>> = Mutex::new(None);
}

fn on_init_complete() {
    let callbacks = CALLBACKS.lock().unwrap();
    callbacks.as_ref().unwrap().init_tx.send(()).unwrap();
}

fn on_event(data: &[u8]) {
    log::error!("got event: {:02x?}", data);
    let callbacks = CALLBACKS.lock().unwrap();
    match EventPacket::parse(data) {
        Ok(p) => callbacks.as_ref().unwrap().evt_tx.send(p).unwrap(),
        Err(e) => log::error!("failure to parse event: {:?} data: {:02x?}", e, data),
    }
}

fn on_acl(data: &[u8]) {
    let callbacks = CALLBACKS.lock().unwrap();
    match AclPacket::parse(data) {
        Ok(p) => callbacks.as_ref().unwrap().acl_tx.send(p).unwrap(),
        Err(e) => log::error!("failure to parse incoming ACL: {:?} data: {:02x?}", e, data),
    }
}

fn on_sco(data: &[u8]) {
    let callbacks = CALLBACKS.lock().unwrap();
    match ScoPacket::parse(data) {
        Ok(p) => callbacks.as_ref().unwrap().sco_tx.send(p).unwrap(),
        Err(e) => log::error!("failure to parse incoming SCO: {:?} data: {:02x?}", e, data),
    }
}

fn on_iso(data: &[u8]) {
    let callbacks = CALLBACKS.lock().unwrap();
    match IsoPacket::parse(data) {
        Ok(p) => callbacks.as_ref().unwrap().iso_tx.send(p).unwrap(),
        Err(e) => log::error!("failure to parse incoming ISO: {:?} data: {:02x?}", e, data),
    }
}

async fn dispatch_outgoing(
    mut cmd_rx: UnboundedReceiver<CommandPacket>,
    mut acl_rx: UnboundedReceiver<AclPacket>,
    mut iso_rx: UnboundedReceiver<IsoPacket>,
    mut sco_rx: UnboundedReceiver<ScoPacket>,
) {
    loop {
        select! {
            Some(cmd) = cmd_rx.recv() => ffi::send_command(&cmd.to_bytes()),
            Some(acl) = acl_rx.recv() => ffi::send_acl(&acl.to_bytes()),
            Some(iso) = iso_rx.recv() => ffi::send_iso(&iso.to_bytes()),
            Some(sco) = sco_rx.recv() => ffi::send_sco(&sco.to_bytes()),
            else => break,
        }
    }
}