diff --git a/core/embed/io/ble/inc/io/ble.h b/core/embed/io/ble/inc/io/ble.h index e52bc3dff1..bed843e1a4 100644 --- a/core/embed/io/ble/inc/io/ble.h +++ b/core/embed/io/ble/inc/io/ble.h @@ -42,6 +42,13 @@ typedef enum { BLE_UNPAIR = 7, // Erase bond for currently connected device } ble_command_type_t; +typedef enum { + BLE_MODE_OFF, + BLE_MODE_CONNECTABLE, + BLE_MODE_PAIRING, + BLE_MODE_DFU, +} ble_mode_t; + typedef struct { uint8_t name[BLE_ADV_NAME_LEN]; bool static_mac; @@ -59,6 +66,12 @@ typedef struct { ble_command_data_t data; } ble_command_t; +typedef struct { + bool accept_msgs; + bool reboot_on_resume; + ble_mode_t mode_requested; +} ble_wakeup_params_t; + typedef enum { BLE_NONE = 0, // No event BLE_CONNECTED = 1, // Connected to a device @@ -97,6 +110,12 @@ bool ble_init(void); // and shuts down the BLE module. void ble_deinit(void); +// Suspends the BLE module +void ble_suspend(ble_wakeup_params_t *wakeup_params); + +// Resumes the BLE module +bool ble_resume(const ble_wakeup_params_t *wakeup_params); + // Starts BLE operations // // Enables reception of messages over BLE diff --git a/core/embed/io/ble/stm32/ble.c b/core/embed/io/ble/stm32/ble.c index 183e2b7aa5..fc4c61a72e 100644 --- a/core/embed/io/ble/stm32/ble.c +++ b/core/embed/io/ble/stm32/ble.c @@ -32,13 +32,6 @@ #include "ble_comm_defs.h" -typedef enum { - BLE_MODE_OFF, - BLE_MODE_CONNECTABLE, - BLE_MODE_PAIRING, - BLE_MODE_DFU, -} ble_mode_t; - // changing value of TX_QUEUE_LEN is not allowed // as it might result in order of messages being changed #define TX_QUEUE_LEN 1 @@ -55,6 +48,7 @@ typedef struct { bool initialized; bool status_valid; bool accept_msgs; + bool reboot_on_resume; uint8_t busy_flag; bool pairing_requested; ble_event_t event_queue_buffers[EVENT_QUEUE_LEN]; @@ -319,6 +313,10 @@ static void ble_process_data(const uint8_t *data, uint32_t len) { return; } + if (!drv->accept_msgs) { + return; + } + if (len != BLE_RX_PACKET_SIZE) { return; } @@ -445,9 +443,7 @@ cleanup: return false; } -void ble_deinit(void) { - ble_driver_t *drv = &g_ble_driver; - +static void ble_deinit_common(ble_driver_t *drv) { if (!drv->initialized) { return; } @@ -463,10 +459,62 @@ void ble_deinit(void) { tsqueue_reset(&drv->event_queue); tsqueue_reset(&drv->rx_queue); tsqueue_reset(&drv->tx_queue); +} - nrf_deinit(); +void ble_deinit(void) { + ble_driver_t *drv = &g_ble_driver; - drv->initialized = false; + if (drv->initialized) { + ble_deinit_common(drv); + nrf_deinit(); + drv->initialized = false; + } +} + +void ble_suspend(ble_wakeup_params_t *wakeup_params) { + ble_driver_t *drv = &g_ble_driver; + + if (drv->initialized) { + bool connected = drv->connected; + wakeup_params->accept_msgs = connected; + wakeup_params->mode_requested = drv->mode_requested; + + ble_deinit_common(drv); + + if (!connected) { + wakeup_params->reboot_on_resume = true; + + // if not connected, we can turn off the radio + nrf_system_off(); + nrf_deinit(); + } else { + nrf_suspend(); + } + + drv->initialized = false; + } +} + +bool ble_resume(const ble_wakeup_params_t *wakeup_params) { + ble_driver_t *drv = &g_ble_driver; + + if (!ble_init()) { + return false; + } + + if (wakeup_params->reboot_on_resume) { + nrf_reboot(); + } + + if (wakeup_params->mode_requested) { + ble_start(); + } + + irq_key_t key = irq_lock(); + drv->mode_requested = wakeup_params->mode_requested; + irq_unlock(key); + + return true; } bool ble_connected(void) { diff --git a/core/embed/io/nrf/inc/io/nrf.h b/core/embed/io/nrf/inc/io/nrf.h index 28535797b4..bfd55b4e98 100644 --- a/core/embed/io/nrf/inc/io/nrf.h +++ b/core/embed/io/nrf/inc/io/nrf.h @@ -62,6 +62,9 @@ void nrf_init(void); // Deinitialize the NRF driver void nrf_deinit(void); +// Suspend NRF driver +void nrf_suspend(void); + // Check that NRF is running bool nrf_is_running(void); @@ -109,3 +112,7 @@ bool nrf_test_gpio_stay_in_bld(void); // Test GPIO reserved bool nrf_test_gpio_reserved(void); + +bool nrf_system_off(void); + +void nrf_reboot(void); diff --git a/core/embed/io/nrf/nrf_internal.h b/core/embed/io/nrf/nrf_internal.h index 8fc36434cd..e442144c4c 100644 --- a/core/embed/io/nrf/nrf_internal.h +++ b/core/embed/io/nrf/nrf_internal.h @@ -41,7 +41,6 @@ uint32_t nrf_dfu_comm_receive(uint8_t *data, uint32_t len); void nrf_int_send(const uint8_t *data, uint32_t len); uint32_t nrf_int_receive(uint8_t *data, uint32_t len); -bool nrf_reboot(void); bool nrf_reboot_to_bootloader(void); void nrf_signal_data_ready(void); diff --git a/core/embed/io/nrf/stm32u5/nrf.c b/core/embed/io/nrf/stm32u5/nrf.c index cd10af556a..83df0187da 100644 --- a/core/embed/io/nrf/stm32u5/nrf.c +++ b/core/embed/io/nrf/stm32u5/nrf.c @@ -77,10 +77,11 @@ typedef struct { DMA_HandleTypeDef spi_tx_dma; spi_packet_t long_rx_buffer; + EXTI_HandleTypeDef exti; + bool comm_running; bool initialized; bool wakeup; - bool pending_request; nrf_rx_callback_t service_listeners[NRF_SERVICE_CNT]; @@ -189,8 +190,6 @@ void nrf_init(void) { __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); - bool tmp_pending_request = drv->pending_request; - memset(drv, 0, sizeof(*drv)); tsqueue_init(&drv->tx_queue, drv->tx_queue_entries, (uint8_t *)drv->tx_buffers, sizeof(nrf_tx_request_t), @@ -235,14 +234,12 @@ void nrf_init(void) { GPIO_InitStructure.Pin = NRF_IN_SPI_REQUEST_PIN; HAL_GPIO_Init(NRF_IN_SPI_REQUEST_PORT, &GPIO_InitStructure); - EXTI_HandleTypeDef EXTI_Handle = {0}; EXTI_ConfigTypeDef EXTI_Config = {0}; EXTI_Config.GPIOSel = NRF_EXTI_INTERRUPT_GPIOSEL; EXTI_Config.Line = NRF_EXTI_INTERRUPT_LINE; EXTI_Config.Mode = EXTI_MODE_INTERRUPT; EXTI_Config.Trigger = EXTI_TRIGGER_RISING; - HAL_EXTI_SetConfigLine(&EXTI_Handle, &EXTI_Config); - NVIC_SetPriority(NRF_EXTI_INTERRUPT_NUM, IRQ_PRI_NORMAL); + HAL_EXTI_SetConfigLine(&drv->exti, &EXTI_Config); __HAL_GPIO_EXTI_CLEAR_FLAG(NRF_EXTI_INTERRUPT_PIN); // UART PINS @@ -338,7 +335,13 @@ void nrf_init(void) { HAL_SPI_Init(&drv->spi); + drv->tx_request_id = -1; + nrf_register_listener(NRF_SERVICE_MANAGEMENT, nrf_management_rx_cb); + + drv->initialized = true; + drv->timer = systimer_create(nrf_timer_callback, drv); + nrf_start(); NVIC_SetPriority(USART3_IRQn, IRQ_PRI_NORMAL); NVIC_EnableIRQ(USART3_IRQn); @@ -348,21 +351,16 @@ void nrf_init(void) { NVIC_EnableIRQ(GPDMA1_Channel2_IRQn); NVIC_SetPriority(SPI1_IRQn, IRQ_PRI_NORMAL); NVIC_EnableIRQ(SPI1_IRQn); + NVIC_SetPriority(NRF_EXTI_INTERRUPT_NUM, IRQ_PRI_NORMAL); NVIC_EnableIRQ(NRF_EXTI_INTERRUPT_NUM); - drv->tx_request_id = -1; - drv->initialized = true; - - nrf_register_listener(NRF_SERVICE_MANAGEMENT, nrf_management_rx_cb); - - nrf_start(); - - if (tmp_pending_request) { + if (HAL_GPIO_ReadPin(NRF_IN_SPI_REQUEST_PORT, NRF_IN_SPI_REQUEST_PIN) == + GPIO_PIN_SET) { nrf_prepare_spi_data(drv); } } -void nrf_deinit(void) { +void nrf_suspend(void) { nrf_driver_t *drv = &g_nrf_driver; nrf_stop(); @@ -373,7 +371,6 @@ void nrf_deinit(void) { NVIC_DisableIRQ(GPDMA1_Channel2_IRQn); NVIC_DisableIRQ(SPI1_IRQn); NVIC_DisableIRQ(USART3_IRQn); - NVIC_DisableIRQ(NRF_EXTI_INTERRUPT_NUM); __HAL_RCC_SPI1_FORCE_RESET(); __HAL_RCC_SPI1_RELEASE_RESET(); @@ -381,10 +378,43 @@ void nrf_deinit(void) { __HAL_RCC_USART3_FORCE_RESET(); __HAL_RCC_USART3_RELEASE_RESET(); + HAL_GPIO_DeInit(NRF_OUT_RESET_PORT, NRF_OUT_RESET_PIN); + HAL_GPIO_DeInit(NRF_OUT_SPI_READY_PORT, NRF_OUT_SPI_READY_PIN); + HAL_GPIO_DeInit(NRF_OUT_STAY_IN_BLD_PORT, NRF_OUT_STAY_IN_BLD_PIN); + HAL_GPIO_DeInit(NRF_IN_RESERVED_PORT, NRF_IN_RESERVED_PIN); + + // UART Pins + + HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10); + HAL_GPIO_DeInit(GPIOB, GPIO_PIN_1); + HAL_GPIO_DeInit(GPIOD, GPIO_PIN_11); + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5); + + // SPI Pins + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1); + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_4); + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_6); + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_7); + drv->initialized = false; + + drv->pending_spi_transaction = false; drv->wakeup = true; } +void nrf_deinit(void) { + nrf_driver_t *drv = &g_nrf_driver; + + if (drv->initialized) { + NVIC_DisableIRQ(NRF_EXTI_INTERRUPT_NUM); + + HAL_GPIO_DeInit(NRF_IN_SPI_REQUEST_PORT, NRF_IN_SPI_REQUEST_PIN); + HAL_EXTI_ClearConfigLine(&drv->exti); + + nrf_suspend(); + } +} + bool nrf_register_listener(nrf_service_id_t service, nrf_rx_callback_t callback) { nrf_driver_t *drv = &g_nrf_driver; @@ -769,7 +799,6 @@ void NRF_EXTI_INTERRUPT_HANDLER(void) { // Inform the powerctl module about nrf/ble wakeup wakeup_flags_set(WAKEUP_FLAG_BLE); drv->wakeup = false; - drv->pending_request = true; } #endif @@ -821,13 +850,12 @@ bool nrf_in_reserved(void) { return HAL_GPIO_ReadPin(NRF_IN_RESERVED_PORT, NRF_IN_RESERVED_PIN) != 0; } -bool nrf_reboot(void) { +void nrf_reboot(void) { HAL_GPIO_WritePin(NRF_OUT_RESET_PORT, NRF_OUT_RESET_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(NRF_OUT_STAY_IN_BLD_PORT, NRF_OUT_STAY_IN_BLD_PIN, GPIO_PIN_RESET); systick_delay_ms(50); HAL_GPIO_WritePin(NRF_OUT_RESET_PORT, NRF_OUT_RESET_PIN, GPIO_PIN_SET); - return true; } void nrf_signal_data_ready(void) { @@ -876,6 +904,31 @@ bool nrf_get_info(nrf_info_t *info) { return false; } +bool nrf_system_off(void) { + nrf_driver_t *drv = &g_nrf_driver; + if (!drv->initialized) { + return false; + } + + uint8_t data[1] = {MGMT_CMD_SYSTEM_OFF}; + if (!nrf_send_msg(NRF_SERVICE_MANAGEMENT, data, 1, NULL, NULL)) { + return false; + } + + uint32_t timeout = ticks_timeout(100); + + bool finished = false; + + while (!ticks_expired(timeout) && !finished) { + irq_key_t key = irq_lock(); + finished = tsqueue_empty(&drv->tx_queue) && !drv->pending_spi_transaction; + irq_unlock(key); + __WFI(); + } + + return true; +} + void nrf_set_dfu_mode(void) { nrf_driver_t *drv = &g_nrf_driver; diff --git a/core/embed/sys/powerctl/stm32u5/powerctl_suspend.c b/core/embed/sys/powerctl/stm32u5/powerctl_suspend.c index 89bc30f7be..2f675fba8a 100644 --- a/core/embed/sys/powerctl/stm32u5/powerctl_suspend.c +++ b/core/embed/sys/powerctl/stm32u5/powerctl_suspend.c @@ -97,7 +97,8 @@ void powerctl_suspend(void) { touch_deinit(); #endif #ifdef USE_BLE - ble_deinit(); + ble_wakeup_params_t ble_wakeup_params = {0}; + ble_suspend(&ble_wakeup_params); #endif int backlight_level = display_get_backlight(); @@ -180,7 +181,7 @@ void powerctl_suspend(void) { tropic_init(); #endif #ifdef USE_BLE - ble_init(); + ble_resume(&ble_wakeup_params); #endif }