mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-08-05 13:26:57 +00:00
feat(core/bootloader): prepare wireless setup bootloader workflow
[no changelog]
This commit is contained in:
parent
6ba7fa24a2
commit
03fd6a5de8
@ -153,6 +153,9 @@ void ble_event_flush(void);
|
||||
// Obtains the current operational state of the BLE module.
|
||||
void ble_get_state(ble_state_t *state);
|
||||
|
||||
// Retrieves last set advertising name
|
||||
void ble_get_advertising_name(char *name, size_t max_len);
|
||||
|
||||
// Check if write is possible
|
||||
bool ble_can_write(void);
|
||||
|
||||
|
@ -847,6 +847,22 @@ bool ble_get_mac(uint8_t *mac, size_t max_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ble_get_advertising_name(char *name, size_t max_len) {
|
||||
ble_driver_t *drv = &g_ble_driver;
|
||||
|
||||
if (max_len < sizeof(drv->adv_cmd.name)) {
|
||||
memset(name, 0, max_len);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!drv->initialized) {
|
||||
memset(name, 0, max_len);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(name, drv->adv_cmd.name, sizeof(drv->adv_cmd.name));
|
||||
}
|
||||
|
||||
static void on_ble_iface_event_poll(void *context, bool read_awaited,
|
||||
bool write_awaited) {
|
||||
UNUSED(context);
|
||||
|
@ -28,3 +28,7 @@ uint32_t ble_read(uint8_t *data, uint16_t max_len) { return 0; }
|
||||
bool ble_get_mac(uint8_t *mac, size_t max_len) { return false; }
|
||||
|
||||
void ble_event_flush(void) {}
|
||||
|
||||
void ble_get_advertising_name(char *name, size_t max_len) {
|
||||
memset(name, 0, max_len);
|
||||
}
|
||||
|
@ -45,9 +45,13 @@ workflow_result_t workflow_ble_pairing_request(const vendor_header *const vhdr,
|
||||
if (!ble_iface_start_pairing()) {
|
||||
return WF_OK_PAIRING_FAILED;
|
||||
}
|
||||
|
||||
char name[BLE_ADV_NAME_LEN + 1] = {0};
|
||||
ble_get_advertising_name(name, sizeof(name));
|
||||
|
||||
c_layout_t layout;
|
||||
memset(&layout, 0, sizeof(layout));
|
||||
screen_pairing_mode(ui_get_initial_setup(), &layout);
|
||||
screen_pairing_mode(ui_get_initial_setup(), name, strlen(name), &layout);
|
||||
|
||||
uint32_t code = 0;
|
||||
workflow_result_t res =
|
||||
@ -117,4 +121,93 @@ workflow_result_t workflow_ble_pairing_request(const vendor_header *const vhdr,
|
||||
return WF_OK_PAIRING_COMPLETED;
|
||||
}
|
||||
|
||||
workflow_result_t workflow_wireless_setup(const vendor_header *const vhdr,
|
||||
const image_header *const hdr,
|
||||
protob_ios_t *ios) {
|
||||
ble_iface_start_pairing();
|
||||
|
||||
char name[BLE_ADV_NAME_LEN + 1] = {0};
|
||||
ble_get_advertising_name(name, sizeof(name));
|
||||
|
||||
c_layout_t layout;
|
||||
memset(&layout, 0, sizeof(layout));
|
||||
screen_wireless_setup(name, strlen(name), &layout);
|
||||
|
||||
uint32_t code = 0;
|
||||
workflow_result_t res = workflow_host_control(vhdr, hdr, &layout, &code, ios);
|
||||
|
||||
if (res != WF_OK_UI_ACTION) {
|
||||
ble_iface_end_pairing();
|
||||
return res;
|
||||
}
|
||||
|
||||
if (code == WIRELESS_SETUP_CANCEL) {
|
||||
ble_iface_end_pairing();
|
||||
return WF_OK_PAIRING_FAILED;
|
||||
}
|
||||
|
||||
uint32_t result = ui_screen_confirm_pairing(code);
|
||||
|
||||
uint8_t pairing_code[BLE_PAIRING_CODE_LEN] = {0};
|
||||
|
||||
if (result != CONFIRM || !encode_pairing_code(code, pairing_code)) {
|
||||
ble_command_t cmd = {
|
||||
.cmd_type = BLE_REJECT_PAIRING,
|
||||
};
|
||||
ble_issue_command(&cmd);
|
||||
return WF_OK_PAIRING_FAILED;
|
||||
}
|
||||
|
||||
ble_command_t cmd = {
|
||||
.cmd_type = BLE_ALLOW_PAIRING,
|
||||
.data_len = sizeof(pairing_code),
|
||||
};
|
||||
memcpy(cmd.data.raw, pairing_code, sizeof(pairing_code));
|
||||
ble_issue_command(&cmd);
|
||||
|
||||
bool skip_finalization = false;
|
||||
|
||||
sysevents_t awaited = {0};
|
||||
sysevents_t signalled = {0};
|
||||
awaited.read_ready |= 1 << SYSHANDLE_BLE;
|
||||
|
||||
sysevents_poll(&awaited, &signalled, ticks_timeout(500));
|
||||
|
||||
if (signalled.read_ready == 1 << SYSHANDLE_BLE) {
|
||||
ble_event_t event = {0};
|
||||
if (ble_get_event(&event)) {
|
||||
if (event.type == BLE_PAIRING_COMPLETED) {
|
||||
skip_finalization = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!skip_finalization) {
|
||||
pairing_mode_finalization_result_t r =
|
||||
screen_pairing_mode_finalizing(ui_get_initial_setup());
|
||||
if (r == PAIRING_FINALIZATION_FAILED) {
|
||||
ble_iface_end_pairing();
|
||||
return WF_OK_PAIRING_FAILED;
|
||||
}
|
||||
if (r == PAIRING_FINALIZATION_CANCEL) {
|
||||
ble_command_t disconnect = {.cmd_type = BLE_DISCONNECT};
|
||||
ble_issue_command(&disconnect);
|
||||
ble_iface_end_pairing();
|
||||
return WF_OK_PAIRING_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&layout, 0, sizeof(layout));
|
||||
screen_wireless_setup_final(&layout);
|
||||
|
||||
uint32_t ui_result = 0;
|
||||
res = workflow_host_control(vhdr, hdr, &layout, &ui_result, ios);
|
||||
|
||||
if (ui_result == WIRELESS_SETUP_FINAL_CANCEL) {
|
||||
return WF_OK_PAIRING_COMPLETED;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -54,12 +54,13 @@ workflow_result_t workflow_empty_device(void) {
|
||||
res = workflow_host_control(NULL, NULL, &layout, &ui_result, &ios);
|
||||
#ifdef USE_BLE
|
||||
if (res == WF_OK_UI_ACTION && ui_result == WELCOME_PAIRING_MODE) {
|
||||
res = workflow_ble_pairing_request(NULL, NULL);
|
||||
res = workflow_wireless_setup(NULL, NULL, &ios);
|
||||
if (res == WF_OK_PAIRING_COMPLETED || res == WF_OK_PAIRING_FAILED) {
|
||||
res = WF_CANCELLED;
|
||||
ui_result = WELCOME_CANCEL;
|
||||
continue;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
if (res == WF_OK_UI_ACTION && ui_result == WELCOME_MENU) {
|
||||
|
@ -81,6 +81,10 @@ workflow_result_t workflow_auto_update(const vendor_header *const vhdr,
|
||||
#ifdef USE_BLE
|
||||
workflow_result_t workflow_ble_pairing_request(const vendor_header *const vhdr,
|
||||
const image_header *const hdr);
|
||||
|
||||
workflow_result_t workflow_wireless_setup(const vendor_header *const vhdr,
|
||||
const image_header *const hdr,
|
||||
protob_ios_t *ios);
|
||||
#endif
|
||||
|
||||
void workflow_ifaces_init(secbool usb21_landing, protob_ios_t *ios);
|
||||
|
@ -88,4 +88,17 @@ typedef enum {
|
||||
// 0 - 999999 - pairing code
|
||||
PAIRING_MODE_CANCEL = 1000000,
|
||||
} pairing_mode_result_t;
|
||||
void screen_pairing_mode(bool initial_setup, c_layout_t* layout);
|
||||
void screen_pairing_mode(bool initial_setup, const char* name, size_t name_len,
|
||||
c_layout_t* layout);
|
||||
|
||||
typedef enum {
|
||||
// 0 - 999999 - pairing code
|
||||
WIRELESS_SETUP_CANCEL = 1000000,
|
||||
} wireless_setup_result_t;
|
||||
void screen_wireless_setup(const char* name, size_t name_len,
|
||||
c_layout_t* layout);
|
||||
|
||||
typedef enum {
|
||||
WIRELESS_SETUP_FINAL_CANCEL = 1,
|
||||
} wireless_setup_final_result_t;
|
||||
void screen_wireless_setup_final(c_layout_t* layout);
|
||||
|
@ -181,8 +181,39 @@ extern "C" fn screen_confirm_pairing(code: u32, initial_setup: bool) -> u32 {
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_pairing_mode(initial_setup: bool, layout: *mut c_layout_t) {
|
||||
let mut screen = <ModelUI as BootloaderUI>::CLayoutType::init_pairing_mode(initial_setup);
|
||||
extern "C" fn screen_pairing_mode(
|
||||
initial_setup: bool,
|
||||
name: *const cty::c_char,
|
||||
name_len: usize,
|
||||
layout: *mut c_layout_t,
|
||||
) {
|
||||
let name = unsafe { from_c_array(name, name_len).unwrap_or("") };
|
||||
let mut screen = <ModelUI as BootloaderUI>::CLayoutType::init_pairing_mode(initial_setup, name);
|
||||
screen.show();
|
||||
// SAFETY: calling code is supposed to give us exclusive access to the layout
|
||||
let mut layout = unsafe { LayoutBuffer::new(layout) };
|
||||
layout.store(screen);
|
||||
}
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_wireless_setup(
|
||||
name: *const cty::c_char,
|
||||
name_len: usize,
|
||||
layout: *mut c_layout_t,
|
||||
) {
|
||||
let name = unsafe { from_c_array(name, name_len).unwrap_or("") };
|
||||
let mut screen = <ModelUI as BootloaderUI>::CLayoutType::init_wireless_setup(name);
|
||||
screen.show();
|
||||
// SAFETY: calling code is supposed to give us exclusive access to the layout
|
||||
let mut layout = unsafe { LayoutBuffer::new(layout) };
|
||||
layout.store(screen);
|
||||
}
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_wireless_setup_final(layout: *mut c_layout_t) {
|
||||
let mut screen = <ModelUI as BootloaderUI>::CLayoutType::init_wireless_setup_final();
|
||||
screen.show();
|
||||
// SAFETY: calling code is supposed to give us exclusive access to the layout
|
||||
let mut layout = unsafe { LayoutBuffer::new(layout) };
|
||||
|
@ -190,7 +190,7 @@ impl BootloaderLayoutType for BootloaderLayout {
|
||||
}
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
fn init_pairing_mode(initial_setup: bool) -> Self {
|
||||
fn init_pairing_mode(initial_setup: bool, _name: &'static str) -> Self {
|
||||
let bg = if initial_setup { WELCOME_COLOR } else { BLD_BG };
|
||||
|
||||
let btn = if initial_setup {
|
||||
@ -208,6 +208,16 @@ impl BootloaderLayoutType for BootloaderLayout {
|
||||
);
|
||||
Self::PairingMode(frame)
|
||||
}
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
fn init_wireless_setup(_name: &'static str) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
fn init_wireless_setup_final() -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl BootloaderUI for UIBolt {
|
||||
|
@ -136,7 +136,17 @@ impl BootloaderLayoutType for BootloaderLayout {
|
||||
}
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
fn init_pairing_mode(_initial_setup: bool) -> Self {
|
||||
fn init_pairing_mode(_initial_setup: bool, _name: &'static str) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
fn init_wireless_setup(_name: &'static str) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
fn init_wireless_setup_final() -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
@ -171,7 +171,17 @@ impl BootloaderLayoutType for BootloaderLayout {
|
||||
}
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
fn init_pairing_mode(_initial_setup: bool) -> Self {
|
||||
fn init_pairing_mode(_initial_setup: bool, _name: &'static str) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
fn init_wireless_setup(_name: &'static str) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
fn init_wireless_setup_final() -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
use super::{
|
||||
super::{cshape::ScreenBorder, theme},
|
||||
BldActionBar, BldActionBarMsg,
|
||||
};
|
||||
use crate::{
|
||||
strutil::TString,
|
||||
ui::{
|
||||
@ -9,11 +13,6 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
use super::{
|
||||
super::{cshape::ScreenBorder, theme},
|
||||
BldActionBar, BldActionBarMsg,
|
||||
};
|
||||
|
||||
#[repr(u32)]
|
||||
pub enum PairingMsg {
|
||||
Cancel,
|
||||
@ -31,14 +30,16 @@ impl ReturnToC for PairingMsg {
|
||||
|
||||
pub struct PairingModeScreen {
|
||||
message: Label<'static>,
|
||||
name: Label<'static>,
|
||||
action_bar: Option<BldActionBar>,
|
||||
screen_border: ScreenBorder,
|
||||
}
|
||||
|
||||
impl PairingModeScreen {
|
||||
pub fn new(message: TString<'static>) -> Self {
|
||||
pub fn new(message: TString<'static>, name: TString<'static>) -> Self {
|
||||
Self {
|
||||
message: Label::new(message, Alignment::Center, theme::TEXT_NORMAL),
|
||||
name: Label::new(name, Alignment::Center, theme::TEXT_NORMAL),
|
||||
action_bar: None,
|
||||
screen_border: ScreenBorder::new(theme::BLUE),
|
||||
}
|
||||
@ -56,8 +57,9 @@ impl Component for PairingModeScreen {
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
let (_header_area, rest) = bounds.split_top(theme::HEADER_HEIGHT);
|
||||
let (rest, action_bar_area) = rest.split_bottom(theme::ACTION_BAR_HEIGHT);
|
||||
let content_area = rest.inset(theme::SIDE_INSETS);
|
||||
let (content_area, name_area) = rest.inset(theme::SIDE_INSETS).split_top(70);
|
||||
self.message.place(content_area);
|
||||
self.name.place(name_area);
|
||||
self.action_bar.place(action_bar_area);
|
||||
bounds
|
||||
}
|
||||
@ -83,6 +85,7 @@ impl Component for PairingModeScreen {
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.message.render(target);
|
||||
self.name.render(target);
|
||||
self.action_bar.render(target);
|
||||
self.screen_border.render(u8::MAX, target);
|
||||
}
|
||||
@ -93,5 +96,6 @@ impl crate::trace::Trace for PairingModeScreen {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.component("PairingMode");
|
||||
t.string("message", *self.message.text());
|
||||
t.string("name", *self.name.text());
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +93,10 @@ pub enum BootloaderLayout {
|
||||
Connect(ConnectScreen),
|
||||
#[cfg(feature = "ble")]
|
||||
PairingMode(PairingModeScreen),
|
||||
#[cfg(feature = "ble")]
|
||||
WirelessSetup(PairingModeScreen),
|
||||
#[cfg(feature = "ble")]
|
||||
WirelessSetupFinal(ConnectScreen),
|
||||
}
|
||||
|
||||
impl BootloaderLayoutType for BootloaderLayout {
|
||||
@ -103,6 +107,14 @@ impl BootloaderLayoutType for BootloaderLayout {
|
||||
BootloaderLayout::Connect(f) => process_frame_event::<ConnectScreen>(f, event),
|
||||
#[cfg(feature = "ble")]
|
||||
BootloaderLayout::PairingMode(f) => process_frame_event::<PairingModeScreen>(f, event),
|
||||
#[cfg(feature = "ble")]
|
||||
BootloaderLayout::WirelessSetup(f) => {
|
||||
process_frame_event::<PairingModeScreen>(f, event)
|
||||
}
|
||||
#[cfg(feature = "ble")]
|
||||
BootloaderLayout::WirelessSetupFinal(f) => {
|
||||
process_frame_event::<ConnectScreen>(f, event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,10 +125,16 @@ impl BootloaderLayoutType for BootloaderLayout {
|
||||
BootloaderLayout::Connect(f) => show(f, true),
|
||||
#[cfg(feature = "ble")]
|
||||
BootloaderLayout::PairingMode(f) => show(f, true),
|
||||
#[cfg(feature = "ble")]
|
||||
BootloaderLayout::WirelessSetup(f) => show(f, true),
|
||||
#[cfg(feature = "ble")]
|
||||
BootloaderLayout::WirelessSetupFinal(f) => show(f, true),
|
||||
}
|
||||
}
|
||||
|
||||
fn init_welcome() -> Self {
|
||||
// TODO: different UI. needs to decide based on some host already paired:
|
||||
// peer_count() > 0
|
||||
let screen = BldWelcomeScreen::new();
|
||||
Self::Welcome(screen)
|
||||
}
|
||||
@ -138,13 +156,32 @@ impl BootloaderLayoutType for BootloaderLayout {
|
||||
}
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
fn init_pairing_mode(_initial_setup: bool) -> Self {
|
||||
fn init_pairing_mode(_initial_setup: bool, name: &'static str) -> Self {
|
||||
// TODO: different style for initial setup
|
||||
let btn = Button::with_text("Cancel".into()).styled(button_default());
|
||||
let screen = PairingModeScreen::new("Waiting for pairing...".into())
|
||||
let screen = PairingModeScreen::new("Waiting for pairing...".into(), name.into())
|
||||
.with_action_bar(BldActionBar::new_single(btn));
|
||||
Self::PairingMode(screen)
|
||||
}
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
fn init_wireless_setup(name: &'static str) -> Self {
|
||||
// todo implement correct UI
|
||||
let btn = Button::with_text("Cancel".into()).styled(button_default());
|
||||
|
||||
let screen = PairingModeScreen::new("QR_CODE".into(), name.into())
|
||||
.with_action_bar(BldActionBar::new_single(btn));
|
||||
Self::WirelessSetup(screen)
|
||||
}
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
fn init_wireless_setup_final() -> Self {
|
||||
// todo implement correct UI
|
||||
let btn = Button::with_text("Cancel".into()).styled(button_default());
|
||||
let screen =
|
||||
ConnectScreen::new("WAIT".into()).with_action_bar(BldActionBar::new_single(btn));
|
||||
Self::WirelessSetupFinal(screen)
|
||||
}
|
||||
}
|
||||
|
||||
impl BootloaderUI for UIEckhart {
|
||||
|
@ -7,7 +7,12 @@ pub trait BootloaderLayoutType {
|
||||
fn init_menu(initial_setup: bool) -> Self;
|
||||
fn init_connect(initial_setup: bool, auto_update: bool) -> Self;
|
||||
#[cfg(feature = "ble")]
|
||||
fn init_pairing_mode(initial_setup: bool) -> Self;
|
||||
fn init_pairing_mode(initial_setup: bool, name: &'static str) -> Self;
|
||||
#[cfg(feature = "ble")]
|
||||
fn init_wireless_setup(name: &'static str) -> Self;
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
fn init_wireless_setup_final() -> Self;
|
||||
}
|
||||
|
||||
pub trait BootloaderUI {
|
||||
|
Loading…
Reference in New Issue
Block a user