Closed HaoboGu closed 4 months ago
The following is the trace log, it seems the bond info has been saved correctly, but the board is disconnected everytime after saving system attributes:
INFO Hello NRF BLE!
└─ rmk_nrf52840::____embassy_main_task::{async_fn#0} @ src\main.rs:32
INFO softdevice RAM: 31496 bytes
└─ nrf_softdevice::softdevice::{impl#0}::enable @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\1a017b4\nrf-softdevice\src\fmt.rs:138
WARN You're giving more RAM to the softdevice than needed. You can change your app's RAM start address to 20007b08
└─ nrf_softdevice::softdevice::{impl#0}::enable @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\1a017b4\nrf-softdevice\src\fmt.rs:151
INFO Loaded bond info: SystemAttribute { length: 13, data: [2, 0, 2, 0, 26, 0, 2, 0, 1, 0, 38, 0, 2, 0, 1, 0, 2, 215, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255] }, loaded length: Ok(())
└─ rmk::initialize_ble_keyboard_with_config_and_run::{async_fn#0} @ E:\Projects\Rust\rmk\rmk\src\lib.rs:264
INFO BLE Advertising
└─ rmk::initialize_ble_keyboard_with_config_and_run::{async_fn#0} @ E:\Projects\Rust\rmk\rmk\src\lib.rs:272
TRACE ble evt 16
└─ nrf_softdevice::ble::on_evt @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\1a017b4\nrf-softdevice\src\fmt.rs:112
DEBUG conn_params conn_sup_timeout=200 max_conn_interval=12 min_conn_interval=12 slave_latency=0
└─ nrf_softdevice::ble::gap::on_evt @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\1a017b4\nrf-softdevice\src\fmt.rs:125
DEBUG connected role=Peripheral peer_addr=Public:[ab, e2, d4, 7d, b2, 7c]
└─ nrf_softdevice::ble::peripheral::advertise_inner::{async_fn#0}::{closure#1} @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\1a017b4\nrf-softdevice\src\fmt.rs:125
TRACE conn 0: connected
└─ nrf_softdevice::ble::connection::{impl#9}::new::{closure#0} @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\1a017b4\nrf-softdevice\src\fmt.rs:112
INFO Starting GATT server
└─ rmk::initialize_ble_keyboard_with_config_and_run::{async_fn#0} @ E:\Projects\Rust\rmk\rmk\src\lib.rs:283
TRACE ble evt 36
└─ nrf_softdevice::ble::on_evt @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\1a017b4\nrf-softdevice\src\fmt.rs:112
DEBUG on_data_length_update conn_handle=3 max_rx_octets=251 max_rx_time_us=2120 max_tx_octets=251 max_tx_time_us=2120
└─ nrf_softdevice::ble::gap::on_evt @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\1a017b4\nrf-softdevice\src\fmt.rs:125
TRACE ble evt 35
└─ nrf_softdevice::ble::on_evt @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\1a017b4\nrf-softdevice\src\fmt.rs:112
TRACE on_data_length_update_request conn_handle=3 max_rx_octets=251 max_rx_time_us=17040 max_tx_octets=251 max_tx_time_us=17040
└─ nrf_softdevice::ble::gap::on_evt @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\1a017b4\nrf-softdevice\src\fmt.rs:112
TRACE ble evt 36
└─ nrf_softdevice::ble::on_evt @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\1a017b4\nrf-softdevice\src\fmt.rs:112
DEBUG on_data_length_update conn_handle=3 max_rx_octets=251 max_rx_time_us=2120 max_tx_octets=251 max_tx_time_us=2120
└─ nrf_softdevice::ble::gap::on_evt @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\1a017b4\nrf-softdevice\src\fmt.rs:125
TRACE ble evt 20
└─ nrf_softdevice::ble::on_evt @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\1a017b4\nrf-softdevice\src\fmt.rs:112
TRACE ble evt sec info request: enc_info=1, id_info=0, sign_info=0, master_id: { ediv: 9d18, rand: [124, 40, 24, 8, 84, 105, 188, 75] }, peer_addr: { addr: [171, 226, 212, 125, 178, 124], addr_id_peer: 0, addr_type: 0 }
└─ nrf_softdevice::ble::gap::on_evt @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\1a017b4\nrf-softdevice\src\fmt.rs:112
INFO Getting bond for: id: MasterId { ediv: 40216, rand: [124, 40, 24, 8, 84, 105, 188, 75] }
└─ rmk::ble::bonder::{impl#4}::get_key @ E:\Projects\Rust\rmk\rmk\src\ble\bonder.rs:140
TRACE ble evt 17
└─ nrf_softdevice::ble::on_evt @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\1a017b4\nrf-softdevice\src\fmt.rs:112
TRACE on_disconnected conn_handle=3
└─ nrf_softdevice::ble::gap::on_evt @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\1a017b4\nrf-softdevice\src\fmt.rs:112
INFO Saving system attributes for: Public:[ab, e2, d4, 7d, b2, 7c]
└─ rmk::ble::bonder::{impl#4}::save_sys_attrs @ E:\Projects\Rust\rmk\rmk\src\ble\bonder.rs:149
TRACE conn 0: disconnected
└─ nrf_softdevice::ble::connection::{impl#6}::on_disconnected @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\1a017b4\nrf-softdevice\src\fmt.rs:112
I also tried to use Nrf-Connected mobile app to test the program, the app always shows the following log:
Scanner On
Device Scanned
Device Appearance switched from Generic to HID
Failed to Connect: Peer removed pairing information
That means that your central device is trying to connect using keys that don't match the keys you're providing as part of the pairing procedure. You need to forget the device on the central and then re-pair to generate new keys. You then need to save those keys after receiving the on_bonded
callback. save_sys_attrs
just stores some state information such as which characteristics the central has requested notifications so that the connection state can be restored on reconnect. It will only be called when the connection is disconnected.
@alexmoon Thanks for the reply! I just made my device reconnect to host by saving keys in on_bonded
. Reconnection is good, but there is another problem: after reconnection, when I try to send HID report to host, gatt_server::notify_value
returns NotifyValueError(Raw(BleGattsSysAttrMissing))
.
This error only occurs after reconnection. If I delete the device from host, connect the device as a new device, all the functions work well, no NotifyValueError
. Do you have any idea of solving it?
In your on_connected
handler you need to call gatt_server::set_sys_attrs()
with the data you saved for that peer in your save_sys_attrs()
impl.
@alexmoon I cannot find any on_connected
handler in the library. Do you mean server_callback
of gatt_server::run
here?
match peripheral::advertise_pairable(sd, adv, &config, bonder).await {
Ok(conn) => {
// Run the GATT server on the connection. This returns when the connection gets disconnected.
let ble_fut = gatt_server::run(&conn, &ble_server, server_callback);
}
Err(e) => {
error!("Advertise error: {}", e)
}
}
Sorry, on_connected
is from my firmware. Basically you just need to call set_sys_attrs
as soon as you're connected (i.e. in the Ok
branch of your match
expression, before you call gatt_server::run
). Note that if your peer is using private resolvable addresses, you will need to use the saved identity key to resolve the address in order to identify the correct saved sys_attrs to use.
Thanks a lot! I've got my project work.
Pairing-bonding and storing keys are quite common in BLE apps. NRF has one already: https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v15.3.0%2Flib_peer_manager.html
Is it possible to have a built-in peer manager in nrf-softdevice
?
That's outside the scope of nrf-softdevice
, which is just trying to provide a safe wrapper around the softdevice library. However, it would be quite useful as a third party crate.
@HaoboGu have you had to go through address resolution as well? The Peer manager in the SDK is quite a complex module, does it really boils down to only a handful of write/fetch from the flash?
Would you be ok with sharing your solution?
The Peer manager in the SDK is quite a complex module, does it really boils down to only a handful of write/fetch from the flash?
NRF's peer manager is quite more complex, I just have a simplest version of it. You can checkout here: https://github.com/HaoboGu/rmk/blob/main/rmk/src/ble/bonder.rs
The Peer manager in the SDK is quite a complex module, does it really boils down to only a handful of write/fetch from the flash?
NRF's peer manager is quite more complex, I just have a simplest version of it. You can checkout here: https://github.com/HaoboGu/rmk/blob/main/rmk/src/ble/bonder.rs
Nice work, impressively simple, thanks for sharing!
I wonder what feature does the SDK Peer manager provide that your approach doesn't? To me it seems to cover all the needs for bonding multiple devices (for a BLE peripheral)...
I wonder what feature does the SDK Peer manager provide that your approach doesn't?
AFAIK, random device addresses is not supported currently.
I just found I didn't really solve the problem. I called load_sys_attrs
after connected:
match peripheral::advertise_pairable(sd, adv, &config, bonder).await {
Ok(conn) => {
info!("Connected to BLE");
bonder.load_sys_attrs(&conn);
let ble_fut = gatt_server::run(&conn, &ble_server, server_callback);
}
Err(e) => {
error!("Advertise error: {}", e)
}
}
where my load_sys_attrs
is:
fn load_sys_attrs(&self, conn: &Connection) {
let addr = conn.peer_address();
info!("Loading system attributes for {}", addr);
let bond_info = self.bond_info.borrow();
let sys_attr = bond_info
.iter()
.filter(|(_, b)| b.sys_attr.length != 0 && b.removed == false)
.find(|(_, b)| b.peer.peer_id.is_match(addr))
.map(|(_, b)| &b.sys_attr.data[0..b.sys_attr.length]);
info!("call set_sys_attrs in load_sys_attrs: {}, {}", sys_attr, sys_attr.unwrap().len());
if let Err(err) = set_sys_attrs(conn, sys_attr) {
warn!("SecurityHandler failed to set sys attrs: {:?}", err);
}
}
The first connection and reconnection are both good, but once I tried to send HID report, the gatt_server::notify_value(self.conn, self.handle, report)
returns a Raw(InvalidState)
error. Here is the full log of the first and second connection:
first(all good):
INFO start!
└─ rmk_nrf52840::____embassy_main_task::{async_fn#0} @ src\main.rs:11
INFO Enabling ext hfosc...
└─ rmk_nrf52840::____embassy_main_task::{async_fn#0} @ src\main.rs:11
INFO softdevice RAM: 29456 bytes
└─ nrf_softdevice::softdevice::{impl#0}::enable @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\cdee83c\nrf-softdevice\src\fmt.rs:138
WARN You're giving more RAM to the softdevice than needed. You can change your app's RAM start address to 20007310
└─ nrf_softdevice::softdevice::{impl#0}::enable @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\cdee83c\nrf-softdevice\src\fmt.rs:151
INFO Loaded saved bond info: 1
└─ rmk::ble::nrf::initialize_nrf_ble_keyboard_with_config_and_run::{async_fn#0} @ E:\rmk\rmk\src\ble\nrf.rs:199
INFO USB suspended, BLE Advertising
└─ rmk::ble::nrf::initialize_nrf_ble_keyboard_with_config_and_run::{async_fn#0} @ E:\rmk\rmk\src\ble\nrf.rs:243
INFO Connected to BLE
└─ rmk::ble::nrf::initialize_nrf_ble_keyboard_with_config_and_run::{async_fn#0} @ E:\rmk\rmk\src\ble\nrf.rs:249
INFO Loading system attributes for Public:[ab, e2, d4, 7d, b2, 7c]
└─ rmk::ble::nrf::bonder::{impl#4}::load_sys_attrs @ E:\rmk\rmk\src\ble\nrf\bonder.rs:210
INFO call set_sys_attrs in load_sys_attrs: Some([13, 0, 2, 0, 0, 0, 26, 0, 2, 0, 0, 0, 38, 0, 2, 0, 0, 0, 45, 0, 2, 0, 0, 0, 49, 0, 2, 0, 0, 0, 53, 0, 2, 0, 0, 0, 57, 0, 2, 0, 0, 0, 78, 188]), 44
└─ rmk::ble::nrf::bonder::{impl#4}::load_sys_attrs @ E:\rmk\rmk\src\ble\nrf\bonder.rs:220
INFO Starting GATT server 200 ms later
└─ rmk::ble::nrf::run_ble_keyboard::{async_fn#0} @ E:\rmk\rmk\src\ble\nrf.rs:333
INFO on_security_update, new security mode: JustWorks
└─ rmk::ble::nrf::bonder::{impl#4}::on_security_update @ E:\rmk\rmk\src\ble\nrf\bonder.rs:94
DEBUG On bonded: storing bond for MasterId { ediv: 25868, rand: [130, 88, 153, 22, 65, 23, 20, 21] }
└─ rmk::ble::nrf::bonder::{impl#4}::on_bonded @ E:\rmk\rmk\src\ble\nrf\bonder.rs:105
INFO ON BOND: get sys attr: [13, 0, 2, 0, 0, 0, 26, 0, 2, 0, 0, 0, 38, 0, 2, 0, 0, 0, 45, 0, 2, 0, 0, 0, 49, 0, 2, 0, 0, 0, 53, 0, 2, 0, 0, 0, 57, 0, 2, 0, 0, 0, 78, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], size:44
└─ rmk::ble::nrf::bonder::{impl#4}::on_bonded @ E:\rmk\rmk\src\ble\nrf\bonder.rs:130
DEBUG Sent bond info to flash channel
└─ rmk::ble::nrf::bonder::{impl#4}::on_bonded @ E:\rmk\rmk\src\ble\nrf\bonder.rs:152
INFO Saving bond info: BondInfo(BondInfo { slot_num: 0, peer: Peer { master_id: MasterId { ediv: 25868, rand: [130, 88, 153, 22, 65, 23, 20, 21] }, key: EncryptionInfo { ltk: [2, 53, 199, 84, 1, 229, 28, 117, 196, 197, 66, 170, 76, 165, 44, 252], flags: 64 }, peer_id: IdentityKey { irk: IdentityResolutionKey { irk: [13, 235, 235, 74, 4, 237, 34, 11, 38, 15, 13, 77, 96, 179, 252, 154] }, addr: Public:[ab, e2, d4, 7d, b2, 7c] } }, sys_attr: SystemAttribute { length: 44, data: [13, 0, 2, 0, 0, 0, 26, 0, 2, 0, 0, 0, 38, 0, 2, 0, 0, 0, 45, 0, 2, 0, 0, 0, 49, 0, 2, 0, 0, 0, 53, 0, 2, 0, 0, 0, 57, 0, 2, 0, 0, 0, 78, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, removed: false })
└─ rmk::storage::{impl#2}::run::{async_fn#0} @ E:\rmk\rmk\src\storage.rs:420
INFO HID input keyboard cccd: [1, 0]
└─ rmk::ble::nrf::hid_service::{impl#0}::on_write @ E:\rmk\rmk\src\ble\nrf\hid_service.rs:201
INFO HID input media keys: [1, 0]
└─ rmk::ble::nrf::hid_service::{impl#0}::on_write @ E:\rmk\rmk\src\ble\nrf\hid_service.rs:211
INFO HID input via keys: [1, 0]
└─ rmk::ble::nrf::hid_service::{impl#0}::on_write @ E:\rmk\rmk\src\ble\nrf\hid_service.rs:209
INFO HID output keyboard: [0]
└─ rmk::ble::nrf::hid_service::{impl#0}::on_write @ E:\rmk\rmk\src\ble\nrf\hid_service.rs:207
DEBUG Sending keyboard report: [0x4, 0x0, 0x0, 0x0, 0x0, 0x0]
└─ rmk::keyboard::{impl#0}::send_keyboard_report::{async_fn#0} @ E:\rmk\rmk\src\keyboard.rs:135
DEBUG Sending keyboard report: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0]
└─ rmk::keyboard::{impl#0}::send_keyboard_report::{async_fn#0} @ E:\rmk\rmk\src\keyboard.rs:135
second(reconnection, notify value error):
INFO start!
└─ rmk_nrf52840::____embassy_main_task::{async_fn#0} @ src\main.rs:11
INFO Enabling ext hfosc...
└─ rmk_nrf52840::____embassy_main_task::{async_fn#0} @ src\main.rs:11
INFO softdevice RAM: 29456 bytes
└─ nrf_softdevice::softdevice::{impl#0}::enable @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\cdee83c\nrf-softdevice\src\fmt.rs:138
WARN You're giving more RAM to the softdevice than needed. You can change your app's RAM start address to 20007310
└─ nrf_softdevice::softdevice::{impl#0}::enable @ C:\Users\haobo\.cargo\git\checkouts\nrf-softdevice-03ef4aef10e777e4\cdee83c\nrf-softdevice\src\fmt.rs:151
INFO Loaded saved bond info: 1
└─ rmk::ble::nrf::initialize_nrf_ble_keyboard_with_config_and_run::{async_fn#0} @ E:\rmk\rmk\src\ble\nrf.rs:199
INFO USB suspended, BLE Advertising
└─ rmk::ble::nrf::initialize_nrf_ble_keyboard_with_config_and_run::{async_fn#0} @ E:\rmk\rmk\src\ble\nrf.rs:243
INFO Connected to BLE
└─ rmk::ble::nrf::initialize_nrf_ble_keyboard_with_config_and_run::{async_fn#0} @ E:\rmk\rmk\src\ble\nrf.rs:249
INFO Loading system attributes for Public:[ab, e2, d4, 7d, b2, 7c]
└─ rmk::ble::nrf::bonder::{impl#4}::load_sys_attrs @ E:\rmk\rmk\src\ble\nrf\bonder.rs:210
INFO call set_sys_attrs in load_sys_attrs: Some([13, 0, 2, 0, 0, 0, 26, 0, 2, 0, 0, 0, 38, 0, 2, 0, 0, 0, 45, 0, 2, 0, 0, 0, 49, 0, 2, 0, 0, 0, 53, 0, 2, 0, 0, 0, 57, 0, 2, 0, 0, 0, 78, 188]), 44
└─ rmk::ble::nrf::bonder::{impl#4}::load_sys_attrs @ E:\rmk\rmk\src\ble\nrf\bonder.rs:220
INFO Starting GATT server 200 ms later
└─ rmk::ble::nrf::run_ble_keyboard::{async_fn#0} @ E:\rmk\rmk\src\ble\nrf.rs:333
DEBUG Getting bond for MasterId { ediv: 25868, rand: [130, 88, 153, 22, 65, 23, 20, 21] }
└─ rmk::ble::nrf::bonder::{impl#4}::get_key @ E:\rmk\rmk\src\ble\nrf\bonder.rs:165
INFO on_security_update, new security mode: JustWorks
└─ rmk::ble::nrf::bonder::{impl#4}::on_security_update @ E:\rmk\rmk\src\ble\nrf\bonder.rs:94
DEBUG Sending keyboard report: [0x4, 0x0, 0x0, 0x0, 0x0, 0x0]
└─ rmk::keyboard::{impl#0}::send_keyboard_report::{async_fn#0} @ E:\rmk\rmk\src\keyboard.rs:135
ERROR Send ble report error: Raw(InvalidState)
└─ rmk::ble::nrf::server::{impl#1}::write::{async_fn#0}::{closure#0} @ E:\rmk\rmk\src\ble\nrf\server.rs:44
And same as before, if I remove bonder.load_sys_attrs(&conn);
, then I get Raw(BleGattsSysAttrMissing)
error.
@alexmoon Do you have any ideas? I'll much appreciate if you can help!
In the bond peripheral example, the bond info is not actually saved and loaded. Is there any concern of not saving the bond info to
nrf_softdevice::Flash
?I tried to save
sys_attr
to flash but had problems, the program was just not work and I don't know why. It would be great if there was a full example of bond peripheral.