summaryrefslogtreecommitdiff
path: root/nrf-softdevice/src/ble/gap_central.rs
blob: 3b38ff6a0d24bc79e3dcff71b681c6068725a44a (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
use core::mem;
use core::ptr;

use crate::ble::types::*;
use crate::error::Error;
use crate::raw;
use crate::util::*;
use crate::{Connection, ConnectionState, Role};


pub(crate) unsafe fn on_adv_report(_ble_evt: *const raw::ble_evt_t, _gap_evt: &raw::ble_gap_evt_t) {
}

pub(crate) unsafe fn on_qos_channel_survey_report(
    _ble_evt: *const raw::ble_evt_t,
    _gap_evt: &raw::ble_gap_evt_t,
) {
}

pub(crate) unsafe fn on_conn_param_update_request(
    _ble_evt: *const raw::ble_evt_t,
    _gap_evt: &raw::ble_gap_evt_t,
) {
}

#[derive(defmt::Format)]
pub enum ConnectError {
    Stopped,
    Raw(Error),
}

impl From<Error> for ConnectError {
    fn from(err: Error) -> Self {
        ConnectError::Raw(err)
    }
}

pub(crate) static CONNECT_SIGNAL: Signal<Result<Connection, ConnectError>> = Signal::new();

pub async fn connect(whitelist: &[Address]) -> Result<Connection, ConnectError> {
    let (addr, fp) = match whitelist.len() {
        0 => depanic!("zero-length whitelist"),
        1 => (
            &whitelist[0] as *const Address as *const raw::ble_gap_addr_t,
            raw::BLE_GAP_SCAN_FP_ACCEPT_ALL as u8,
        ),
        _ => depanic!("todo"),
    };

    // in units of 625us
    let scan_interval: u32 = 2732;
    let scan_window: u32 = 500;

    // TODO make configurable
    let mut scan_params: raw::ble_gap_scan_params_t = unsafe { mem::zeroed() };
    scan_params.set_extended(1);
    scan_params.set_active(1);
    scan_params.scan_phys = raw::BLE_GAP_PHY_1MBPS as u8;
    scan_params.set_filter_policy(fp);
    scan_params.timeout = 123;

    // s122 has these in us instead of 625us :shrug:
    #[cfg(not(feature="s122"))]
    {
        scan_params.interval = scan_interval as u16;
        scan_params.window = scan_interval as u16;
    }
    #[cfg(feature="s122")]
    {
        scan_params.interval_us = scan_interval * 625;
        scan_params.window_us = scan_interval * 625;
    }

    // TODO make configurable
    let mut conn_params: raw::ble_gap_conn_params_t = unsafe { mem::zeroed() };
    conn_params.min_conn_interval = 50;
    conn_params.max_conn_interval = 200;
    conn_params.slave_latency = 4;
    conn_params.conn_sup_timeout = 400; // 4 s

    let ret = unsafe { raw::sd_ble_gap_connect(addr, &mut scan_params, &mut conn_params, 1) };
    match Error::convert(ret) {
        Ok(()) => {}
        Err(err) => {
            warn!("sd_ble_gap_connect err {:?}", err);
            return Err(ConnectError::Raw(err));
        }
    }

    info!("connect started");

    // TODO handle future drop

    CONNECT_SIGNAL.wait().await
}

#[derive(defmt::Format)]
pub enum ConnectStopError {
    NotRunning,
    Raw(Error),
}

impl From<Error> for ConnectStopError {
    fn from(err: Error) -> Self {
        ConnectStopError::Raw(err)
    }
}

pub fn connect_stop() -> Result<(), ConnectStopError> {
    let ret = unsafe { raw::sd_ble_gap_connect_cancel() };
    match Error::convert(ret).dewarn(intern!("sd_ble_gap_connect_cancel")) {
        Ok(()) => Ok(()),
        Err(Error::InvalidState) => Err(ConnectStopError::NotRunning),
        Err(e) => Err(e.into()),
    }
}