diff --git a/core/SConscript.prodtest b/core/SConscript.prodtest index dd9e46e312..d5f6106cb9 100644 --- a/core/SConscript.prodtest +++ b/core/SConscript.prodtest @@ -109,6 +109,7 @@ SOURCE_PRODTEST = [ 'embed/projects/prodtest/cmd/prodtest_haptic.c', 'embed/projects/prodtest/cmd/prodtest_help.c', 'embed/projects/prodtest/cmd/prodtest_nfc.c', + 'embed/projects/prodtest/cmd/prodtest_nrf.c', 'embed/projects/prodtest/cmd/prodtest_optiga.c', 'embed/projects/prodtest/cmd/prodtest_otp_batch.c', 'embed/projects/prodtest/cmd/prodtest_otp_variant.c', diff --git a/core/embed/io/nrf/crc8.h b/core/embed/io/nrf/crc8.h index f26e33730a..e8df6d64ec 100644 --- a/core/embed/io/nrf/crc8.h +++ b/core/embed/io/nrf/crc8.h @@ -17,12 +17,9 @@ * along with this program. If not, see . */ -#ifndef TREZORHAL_NRF_CRC8_H -#define TREZORHAL_NRF_CRC8_H +#pragma once #include uint8_t crc8(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value, bool reversed); - -#endif diff --git a/core/embed/io/nrf/inc/io/nrf.h b/core/embed/io/nrf/inc/io/nrf.h index 73c4c04439..c903362744 100644 --- a/core/embed/io/nrf/inc/io/nrf.h +++ b/core/embed/io/nrf/inc/io/nrf.h @@ -17,8 +17,7 @@ * along with this program. If not, see . */ -#ifndef TREZORHAL_NRF_H -#define TREZORHAL_NRF_H +#pragma once #include @@ -28,6 +27,8 @@ typedef enum { NRF_SERVICE_BLE = 0, NRF_SERVICE_BLE_MANAGER = 1, + NRF_SERVICE_MANAGEMENT = 2, + NRF_SERVICE_PRODTEST = 3, NRF_SERVICE_CNT // Number of services } nrf_service_id_t; @@ -39,6 +40,18 @@ typedef enum { NRF_STATUS_ABORTED = 3, // Packet was aborted } nrf_status_t; +typedef struct { + uint8_t version_major; + uint8_t version_minor; + uint8_t version_patch; + uint8_t version_tweak; + + bool in_trz_ready; + bool in_stay_in_bootloader; + bool out_nrf_ready; + bool out_reserved; +} nrf_info_t; + typedef void (*nrf_rx_callback_t)(const uint8_t *data, uint32_t len); typedef void (*nrf_tx_callback_t)(nrf_status_t status, void *context); @@ -74,4 +87,23 @@ int32_t nrf_send_msg(nrf_service_id_t service, const uint8_t *data, // the message is being sent, it will be sent. The callback will not be called. bool nrf_abort_msg(int32_t id); -#endif +// Reads version and other info from NRF application. +// Blocking function. +bool nrf_get_info(nrf_info_t *info); + +// TEST only functions + +// Test SPI communication with NRF +bool nrf_test_spi_comm(void); + +// Test UART communication with NRF +bool nrf_test_uart_comm(void); + +// Test reboot to bootloader +bool nrf_test_reboot_to_bootloader(void); + +bool nrf_test_gpio_trz_ready(void); + +bool nrf_test_gpio_stay_in_bld(void); + +bool nrf_test_gpio_reserved(void); diff --git a/core/embed/io/nrf/nrf_internal.h b/core/embed/io/nrf/nrf_internal.h index c6bdc2b1b5..870d621ac8 100644 --- a/core/embed/io/nrf/nrf_internal.h +++ b/core/embed/io/nrf/nrf_internal.h @@ -17,11 +17,19 @@ * along with this program. If not, see . */ -#ifndef TREZORHAL_NRF_INTERNAL_H -#define TREZORHAL_NRF_INTERNAL_H +#pragma once #include +typedef enum { + MGMT_CMD_SYSTEM_OFF = 0x00, + MGMT_CMD_INFO = 0x01, +} management_cmd_t; + +typedef enum { + MGMT_RESP_INFO = 0, +} management_resp_t; + void nrf_dfu_comm_send(const uint8_t *data, uint32_t len); uint32_t nrf_dfu_comm_receive(uint8_t *data, uint32_t len); @@ -36,4 +44,5 @@ bool nrf_reboot_to_bootloader(void); void nrf_signal_running(void); void nrf_signal_off(void); -#endif +void nrf_stay_in_bootloader(bool set); +bool nrf_in_reserved_gpio(void); diff --git a/core/embed/io/nrf/stm32u5/nrf.c b/core/embed/io/nrf/stm32u5/nrf.c index bf22ab84fd..ccdc750c63 100644 --- a/core/embed/io/nrf/stm32u5/nrf.c +++ b/core/embed/io/nrf/stm32u5/nrf.c @@ -83,6 +83,8 @@ typedef struct { nrf_rx_callback_t service_listeners[NRF_SERVICE_CNT]; + bool info_valid; + nrf_info_t info; } nrf_driver_t; static nrf_driver_t g_nrf_driver = {0}; @@ -142,6 +144,22 @@ static void nrf_stop(void) { irq_unlock(key); } +void nrf_management_rx_cb(const uint8_t *data, uint32_t len) { + nrf_driver_t *drv = &g_nrf_driver; + if (!drv->initialized) { + return; + } + + switch (data[0]) { + case MGMT_RESP_INFO: + drv->info_valid = true; + memcpy(&drv->info, &data[1], sizeof(drv->info)); + break; + default: + break; + } +} + void nrf_init(void) { nrf_driver_t *drv = &g_nrf_driver; @@ -307,6 +325,8 @@ void nrf_init(void) { drv->tx_request_id = -1; drv->initialized = true; + nrf_register_listener(NRF_SERVICE_MANAGEMENT, nrf_management_rx_cb); + nrf_start(); } @@ -694,11 +714,25 @@ bool nrf_reboot_to_bootloader(void) { HAL_GPIO_WritePin(NRF_OUT_RESET_PORT, NRF_OUT_RESET_PIN, GPIO_PIN_SET); - systick_delay_ms(1000); + systick_delay_ms(100); return true; } +void nrf_stay_in_bootloader(bool set) { + if (set) { + HAL_GPIO_WritePin(NRF_OUT_STAY_IN_BLD_PORT, NRF_OUT_STAY_IN_BLD_PIN, + GPIO_PIN_SET); + } else { + HAL_GPIO_WritePin(NRF_OUT_STAY_IN_BLD_PORT, NRF_OUT_STAY_IN_BLD_PIN, + GPIO_PIN_RESET); + } +} + +bool nrf_in_reserved_gpio(void) { + return HAL_GPIO_ReadPin(NRF_IN_GPIO0_PORT, NRF_IN_GPIO0_PIN) != 0; +} + bool 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, @@ -735,6 +769,31 @@ bool nrf_is_running(void) { return drv->comm_running; } +bool nrf_get_info(nrf_info_t *info) { + nrf_driver_t *drv = &g_nrf_driver; + if (!drv->initialized) { + return false; + } + + drv->info_valid = false; + + uint8_t data[1] = {MGMT_CMD_INFO}; + if (!nrf_send_msg(NRF_SERVICE_MANAGEMENT, data, 1, NULL, NULL)) { + return false; + } + + uint32_t timeout = ticks_timeout(100); + + while (!ticks_expired(timeout)) { + if (drv->info_valid) { + memcpy(info, &drv->info, sizeof(nrf_info_t)); + return true; + } + } + + return false; +} + void nrf_set_dfu_mode(void) { nrf_driver_t *drv = &g_nrf_driver; diff --git a/core/embed/io/nrf/stm32u5/nrf_test.c b/core/embed/io/nrf/stm32u5/nrf_test.c new file mode 100644 index 0000000000..ff5ea5e54a --- /dev/null +++ b/core/embed/io/nrf/stm32u5/nrf_test.c @@ -0,0 +1,249 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#ifdef KERNEL_MODE + +#include +#include + +#include + +#include "../nrf_internal.h" + +typedef enum { + PRODTEST_CMD_SPI_DATA = 0x00, + PRODTEST_CMD_UART_DATA = 0x01, + PRODTEST_CMD_SET_OUTPUT = 0x02, +} prodtest_cmd_t; + +typedef enum { + PRODTEST_RESP_SPI = 0x00, + PRODTEST_RESP_UART = 0x01, +} prodtest_resp_t; + +typedef struct { + bool answered_spi; + bool answered_uart; + +} nrf_test_t; + +static nrf_test_t g_nrf_test; + +void nrf_test_cb(const uint8_t *data, uint32_t len) { + switch (data[0]) { + case PRODTEST_RESP_SPI: + g_nrf_test.answered_spi = true; + break; + case PRODTEST_RESP_UART: + g_nrf_test.answered_uart = true; + break; + default: + break; + } +} + +bool nrf_test_spi_comm(void) { + nrf_register_listener(NRF_SERVICE_PRODTEST, nrf_test_cb); + + g_nrf_test.answered_spi = false; + + uint8_t data[1] = {PRODTEST_CMD_SPI_DATA}; + + if (!nrf_send_msg(NRF_SERVICE_PRODTEST, data, 1, NULL, NULL)) { + return false; + } + + uint32_t timeout = ticks_timeout(100); + + while (!ticks_expired(timeout)) { + if (g_nrf_test.answered_spi) { + return true; + } + } + + return false; +} + +bool nrf_test_uart_comm(void) { + nrf_register_listener(NRF_SERVICE_PRODTEST, nrf_test_cb); + + g_nrf_test.answered_uart = false; + + uint8_t data[1] = {PRODTEST_CMD_UART_DATA}; + + if (!nrf_send_msg(NRF_SERVICE_PRODTEST, data, 1, NULL, NULL)) { + return false; + } + + uint32_t timeout = ticks_timeout(100); + + while (!ticks_expired(timeout)) { + if (g_nrf_test.answered_uart) { + return true; + } + } + + return false; +} + +bool nrf_test_reboot_to_bootloader(void) { + bool result = false; + + if (!nrf_firmware_running()) { + return false; + } + + if (!nrf_reboot_to_bootloader()) { + return false; + } + + uint32_t timeout = ticks_timeout(10); + + while (!ticks_expired(timeout)) { + if (!nrf_firmware_running()) { + result = true; + break; + } + } + + systick_delay_ms(10); + + // todo test UART communication with MCUboot + + if (!nrf_reboot()) { + return false; + } + + timeout = ticks_timeout(1000); + while (!ticks_expired(timeout)) { + if (nrf_firmware_running()) { + return result; + } + } + + return false; +} + +bool nrf_test_gpio_trz_ready(void) { + bool result = false; + nrf_signal_running(); + systick_delay_ms(10); + + nrf_info_t info = {0}; + if (!nrf_get_info(&info)) { + result = false; + goto cleanup; + } + + if (!info.in_trz_ready) { + result = false; + goto cleanup; + } + + nrf_signal_off(); + systick_delay_ms(10); + if (!nrf_get_info(&info)) { + result = false; + goto cleanup; + } + + if (info.in_trz_ready) { + result = false; + goto cleanup; + } + + result = true; + +cleanup: + nrf_signal_running(); + return result; +} + +bool nrf_test_gpio_stay_in_bld(void) { + bool result = false; + nrf_stay_in_bootloader(false); + systick_delay_ms(10); + + nrf_info_t info = {0}; + if (!nrf_get_info(&info)) { + result = false; + goto cleanup; + } + + if (info.in_stay_in_bootloader) { + result = false; + goto cleanup; + } + + nrf_stay_in_bootloader(true); + systick_delay_ms(10); + if (!nrf_get_info(&info)) { + result = false; + goto cleanup; + } + + if (!info.in_stay_in_bootloader) { + result = false; + goto cleanup; + } + + result = true; + +cleanup: + nrf_stay_in_bootloader(false); + return result; +} + +bool nrf_test_gpio_reserved(void) { + bool result = false; + uint8_t data[2] = {PRODTEST_CMD_SET_OUTPUT, 0}; + if (!nrf_send_msg(NRF_SERVICE_PRODTEST, data, sizeof(data), NULL, NULL)) { + return false; + } + + systick_delay_ms(10); + + if (nrf_in_reserved_gpio()) { + result = false; + goto cleanup; + } + + data[1] = 1; + if (!nrf_send_msg(NRF_SERVICE_PRODTEST, data, sizeof(data), NULL, NULL)) { + result = false; + goto cleanup; + } + + systick_delay_ms(10); + + if (!nrf_in_reserved_gpio()) { + result = false; + goto cleanup; + } + + result = true; + +cleanup: + data[1] = 0; + nrf_send_msg(NRF_SERVICE_PRODTEST, data, sizeof(data), NULL, NULL); + return result; +} + +#endif diff --git a/core/embed/projects/prodtest/README.md b/core/embed/projects/prodtest/README.md index eb614133b8..4026a03fb6 100644 --- a/core/embed/projects/prodtest/README.md +++ b/core/embed/projects/prodtest/README.md @@ -268,6 +268,30 @@ haptic-test 3000 OK ``` +### nrf-communication +Tests the internal communication between the main MCU and NRF MCU. The command returns `OK` if the communication is successful. + +Example: +``` +nrf-communication +# Testing SPI communication... +# Testing UART communication... +# Testing reboot to bootloader... +# Testing GPIO TRZ ready... +# Testing GPIO stay in bootloader... +# Testing GPIO reserved... +OK +``` + +### nrf-version +Retrieves the version of the NRF52 MCU. The command returns `OK` followed by the version in the format `...`. + +Example: +``` +nrf-version +OK 0.1.2.3 +``` + ### touch-draw Starts a drawing canvas, where user can draw with finger on pen. Canvas is exited by sending CTRL+C command. ``` diff --git a/core/embed/projects/prodtest/cmd/prodtest_nrf.c b/core/embed/projects/prodtest/cmd/prodtest_nrf.c new file mode 100644 index 0000000000..32542fa019 --- /dev/null +++ b/core/embed/projects/prodtest/cmd/prodtest_nrf.c @@ -0,0 +1,94 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef USE_BLE + +#include + +#include +#include + +static void prodtest_nrf_communication(cli_t* cli) { + cli_trace(cli, "Testing SPI communication..."); + if (!nrf_test_spi_comm()) { + cli_error(cli, CLI_ERROR, "SPI communication failed."); + return; + } + + cli_trace(cli, "Testing UART communication..."); + if (!nrf_test_uart_comm()) { + cli_error(cli, CLI_ERROR, "UART communication failed."); + return; + } + + cli_trace(cli, "Testing reboot to bootloader..."); + if (!nrf_test_reboot_to_bootloader()) { + cli_error(cli, CLI_ERROR, "Reboot to bootloader failed."); + return; + } + + cli_trace(cli, "Testing GPIO TRZ ready..."); + if (!nrf_test_gpio_trz_ready()) { + cli_error(cli, CLI_ERROR, "TRZ ready GPIO failed."); + return; + } + + cli_trace(cli, "Testing GPIO stay in bootloader..."); + if (!nrf_test_gpio_stay_in_bld()) { + cli_error(cli, CLI_ERROR, "Stay in bootloader GPIO failed."); + return; + } + + cli_trace(cli, "Testing GPIO reserved..."); + if (!nrf_test_gpio_reserved()) { + cli_error(cli, CLI_ERROR, "Reserved GPIO failed."); + return; + } + + cli_ok(cli, ""); +} + +static void prodtest_nrf_version(cli_t* cli) { + nrf_info_t info = {0}; + if (!nrf_get_info(&info)) { + cli_error(cli, CLI_ERROR, "Could not read version."); + return; + } + + cli_ok(cli, "%d.%d.%d.%d", info.version_major, info.version_minor, + info.version_patch, info.version_tweak); +} + +// clang-format off + +PRODTEST_CLI_CMD( + .name = "nrf-communication", + .func = prodtest_nrf_communication, + .info = "Tests NRF communication and GPIOs", + .args = "" +); + +PRODTEST_CLI_CMD( + .name = "nrf-version", + .func = prodtest_nrf_version, + .info = "Reads NRF firmware version", + .args = "" +); + +#endif diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revB.py b/core/site_scons/models/T3W1/trezor_t3w1_revB.py index 31f3d08867..f4e118b8f2 100644 --- a/core/site_scons/models/T3W1/trezor_t3w1_revB.py +++ b/core/site_scons/models/T3W1/trezor_t3w1_revB.py @@ -84,6 +84,7 @@ def configure( features_available.append("ble") defines += [("USE_BLE", "1")] sources += ["embed/io/nrf/stm32u5/nrf.c"] + sources += ["embed/io/nrf/stm32u5/nrf_test.c"] sources += ["embed/io/nrf/crc8.c"] paths += ["embed/io/nrf/inc"] sources += [ diff --git a/nordic/trezor/boards/arm/t3w1_revA_nrf52832/t3w1_revA_nrf52832.dts b/nordic/trezor/boards/arm/t3w1_revA_nrf52832/t3w1_revA_nrf52832.dts index bc700d196e..23fa72dcd7 100644 --- a/nordic/trezor/boards/arm/t3w1_revA_nrf52832/t3w1_revA_nrf52832.dts +++ b/nordic/trezor/boards/arm/t3w1_revA_nrf52832/t3w1_revA_nrf52832.dts @@ -28,11 +28,11 @@ compatible = "gpio-leds"; led0: led_0 { gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>; - label = "Green LED 0"; + label = "Reserved output"; }; led1: led_1 { gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; - label = "Green LED 1"; + label = "NRF ready"; }; }; @@ -40,7 +40,7 @@ compatible = "gpio-keys"; button0: button_0 { gpios = <&gpio0 14 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; - label = "Push button switch 0"; + label = "Stay in bootloader"; zephyr,code = ; }; trezor_ready: trezor_ready { diff --git a/nordic/trezor/trezor-ble/CMakeLists.txt b/nordic/trezor/trezor-ble/CMakeLists.txt index 81e6f3e8c4..45b0e9dc90 100644 --- a/nordic/trezor/trezor-ble/CMakeLists.txt +++ b/nordic/trezor/trezor-ble/CMakeLists.txt @@ -18,7 +18,8 @@ target_sources(app PRIVATE src/ble/bonds.c src/ble/pairing.c src/ble/ble.c - src/power_management/power_management.c + src/management/management.c + src/prodtest/prodtest.c src/trz_comm/uart.c src/trz_comm/spi.c src/trz_comm/trz_comm.c @@ -28,7 +29,8 @@ target_sources(app PRIVATE include_directories(src/signals/inc) include_directories(src/trz_comm/inc) include_directories(src/ble/inc) -include_directories(src/power_management/inc) +include_directories(src/management/inc) +include_directories(src/prodtest/inc) # NORDIC SDK APP END diff --git a/nordic/trezor/trezor-ble/src/ble/pairing.c b/nordic/trezor/trezor-ble/src/ble/pairing.c index 91c034b3fc..1c79898340 100644 --- a/nordic/trezor/trezor-ble/src/ble/pairing.c +++ b/nordic/trezor/trezor-ble/src/ble/pairing.c @@ -54,9 +54,9 @@ void auth_passkey_confirm(struct bt_conn *conn, unsigned int passkey) { uint8_t passkey_str[6]; passkey_to_str(passkey_str, passkey); - management_send_pairing_request_event(passkey_str, 6); + ble_management_send_pairing_request_event(passkey_str, 6); - management_send_status_event(); + ble_management_send_status_event(); } void pairing_auth_cancel(struct bt_conn *conn) { @@ -66,8 +66,8 @@ void pairing_auth_cancel(struct bt_conn *conn) { connection_disconnect(); - management_send_pairing_cancelled_event(); - management_send_status_event(); + ble_management_send_pairing_cancelled_event(); + ble_management_send_status_event(); LOG_INF("Pairing cancelled: %s", addr); } diff --git a/nordic/trezor/trezor-ble/src/main.c b/nordic/trezor/trezor-ble/src/main.c index 10ee4e1412..b260901456 100644 --- a/nordic/trezor/trezor-ble/src/main.c +++ b/nordic/trezor/trezor-ble/src/main.c @@ -39,7 +39,8 @@ #include #include -#include +#include +#include #include #include @@ -55,9 +56,11 @@ int main(void) { ble_init(); - power_management_init(); + management_init(); - signals_fw_running(true); + prodtest_init(); + + signals_nrf_ready(true); for (;;) { k_sleep(K_FOREVER); diff --git a/nordic/trezor/trezor-ble/src/power_management/inc/power_management/power_management.h b/nordic/trezor/trezor-ble/src/management/inc/management/management.h similarity index 90% rename from nordic/trezor/trezor-ble/src/power_management/inc/power_management/power_management.h rename to nordic/trezor/trezor-ble/src/management/inc/management/management.h index 492b4ad478..f64d52b9d4 100644 --- a/nordic/trezor/trezor-ble/src/power_management/inc/power_management/power_management.h +++ b/nordic/trezor/trezor-ble/src/management/inc/management/management.h @@ -19,5 +19,5 @@ #pragma once -// Initialize the power management module -void power_management_init(void); +// Initialize the management module +void management_init(void); diff --git a/nordic/trezor/trezor-ble/src/power_management/power_management.c b/nordic/trezor/trezor-ble/src/management/management.c similarity index 54% rename from nordic/trezor/trezor-ble/src/power_management/power_management.c rename to nordic/trezor/trezor-ble/src/management/management.c index a779eb2bba..7656a5a747 100644 --- a/nordic/trezor/trezor-ble/src/power_management/power_management.c +++ b/nordic/trezor/trezor-ble/src/management/management.c @@ -23,45 +23,72 @@ #include #include +#include #include #include #include +#include #include -#define LOG_MODULE_NAME power_manangement +#define LOG_MODULE_NAME manangement LOG_MODULE_REGISTER(LOG_MODULE_NAME); -static K_SEM_DEFINE(power_management_ok, 0, 1); +static K_SEM_DEFINE(management_ok, 0, 1); typedef enum { - PWR_CMD_SYSTEM_OFF = 0x00, -} power_management_cmd_t; + MGMT_CMD_SYSTEM_OFF = 0x00, + MGMT_CMD_INFO = 0x01, +} management_cmd_t; -void power_management_init(void) { k_sem_give(&power_management_ok); } +typedef enum { + MGMT_RESP_INFO = 0, +} management_resp_t; + +void management_init(void) { k_sem_give(&management_ok); } + +static void send_info(void) { + uint8_t data[9] = {0}; + + data[0] = MGMT_RESP_INFO; + data[1] = APP_VERSION_MAJOR; + data[2] = APP_VERSION_MINOR; + data[3] = APP_PATCHLEVEL; + data[4] = APP_TWEAK; + data[5] = signals_is_trz_ready(); + data[6] = signals_is_stay_in_bootloader(); + data[7] = signals_out_get_nrf_ready(); + data[8] = signals_out_get_reserved(); + + trz_comm_send_msg(NRF_SERVICE_MANAGEMENT, data, sizeof(data)); +} static void process_command(uint8_t *data, uint16_t len) { uint8_t cmd = data[0]; switch (cmd) { - case PWR_CMD_SYSTEM_OFF: + case MGMT_CMD_SYSTEM_OFF: LOG_INF("System off"); sys_poweroff(); break; + case MGMT_CMD_INFO: + LOG_INF("Info command"); + send_info(); + break; default: break; } } -void power_management_thread(void) { +void management_thread(void) { /* Don't go any further until BLE is initialized */ - k_sem_take(&power_management_ok, K_FOREVER); + k_sem_take(&management_ok, K_FOREVER); for (;;) { - trz_packet_t *buf = trz_comm_poll_data(NRF_SERVICE_POWER_MANAGEMENT); + trz_packet_t *buf = trz_comm_poll_data(NRF_SERVICE_MANAGEMENT); process_command(buf->data, buf->len); k_free(buf); } } -K_THREAD_DEFINE(power_management_thread_id, CONFIG_DEFAULT_THREAD_STACK_SIZE, - power_management_thread, NULL, NULL, NULL, 7, 0, 0); +K_THREAD_DEFINE(management_thread_id, CONFIG_DEFAULT_THREAD_STACK_SIZE, + management_thread, NULL, NULL, NULL, 7, 0, 0); diff --git a/nordic/trezor/trezor-ble/src/prodtest/inc/prodtest/prodtest.h b/nordic/trezor/trezor-ble/src/prodtest/inc/prodtest/prodtest.h new file mode 100644 index 0000000000..3d7de7c387 --- /dev/null +++ b/nordic/trezor/trezor-ble/src/prodtest/inc/prodtest/prodtest.h @@ -0,0 +1,23 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +// Initialize the prodtest module +void prodtest_init(void); diff --git a/nordic/trezor/trezor-ble/src/prodtest/prodtest.c b/nordic/trezor/trezor-ble/src/prodtest/prodtest.c new file mode 100644 index 0000000000..26f8666da8 --- /dev/null +++ b/nordic/trezor/trezor-ble/src/prodtest/prodtest.c @@ -0,0 +1,81 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include + +#include + +#include +#include + +#define LOG_MODULE_NAME prodtest +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +static K_SEM_DEFINE(prodtest_ok, 0, 1); + +typedef enum { + PRODTEST_CMD_SPI_DATA = 0x00, + PRODTEST_CMD_UART_DATA = 0x01, + PRODTEST_CMD_SET_OUTPUT = 0x02, +} prodtest_cmd_t; + +typedef enum { + PRODTEST_RESP_SPI = 0x00, + PRODTEST_RESP_UART = 0x01, +} prodtest_resp_t; + +void prodtest_init(void) { k_sem_give(&prodtest_ok); } + +static void process_command(uint8_t *data, uint16_t len) { + uint8_t resp_data[244] = {0}; + uint8_t cmd = data[0]; + switch (cmd) { + case PRODTEST_CMD_SPI_DATA: + resp_data[0] = PRODTEST_RESP_SPI; + trz_comm_send_msg(NRF_SERVICE_PRODTEST, resp_data, 244); + break; + case PRODTEST_CMD_UART_DATA: + resp_data[0] = PRODTEST_RESP_UART; + trz_comm_send_msg(NRF_SERVICE_PRODTEST, resp_data, 64); + break; + case PRODTEST_CMD_SET_OUTPUT: + signals_reserved(data[1]); + break; + default: + break; + } +} + +void prodtest_thread(void) { + /* Don't go any further until module is initialized */ + k_sem_take(&prodtest_ok, K_FOREVER); + + for (;;) { + trz_packet_t *buf = trz_comm_poll_data(NRF_SERVICE_PRODTEST); + process_command(buf->data, buf->len); + k_free(buf); + } +} + +K_THREAD_DEFINE(prodtest_thread_id, CONFIG_DEFAULT_THREAD_STACK_SIZE, + prodtest_thread, NULL, NULL, NULL, 7, 0, 0); diff --git a/nordic/trezor/trezor-ble/src/signals/inc/signals/signals.h b/nordic/trezor/trezor-ble/src/signals/inc/signals/signals.h index 1766d38b4f..22cff327b3 100644 --- a/nordic/trezor/trezor-ble/src/signals/inc/signals/signals.h +++ b/nordic/trezor/trezor-ble/src/signals/inc/signals/signals.h @@ -24,8 +24,24 @@ // Initializes the Signals module bool signals_init(void); +// INPUTS + // Checks if the TRZ is ready to communicate bool signals_is_trz_ready(void); +// Checks if the device should stay in the bootloader +bool signals_is_stay_in_bootloader(void); + +// OUTPUTS + // Signals that NRF firmware is running and initialized -void signals_fw_running(bool set); +void signals_nrf_ready(bool set); + +// Sets the reserved output +void signals_reserved(bool set); + +// Reads the current output setting +bool signals_out_get_nrf_ready(void); + +// Reads the current output setting +bool signals_out_get_reserved(void); diff --git a/nordic/trezor/trezor-ble/src/signals/signals.c b/nordic/trezor/trezor-ble/src/signals/signals.c index 141359a2ec..49ded9bb11 100644 --- a/nordic/trezor/trezor-ble/src/signals/signals.c +++ b/nordic/trezor/trezor-ble/src/signals/signals.c @@ -28,12 +28,16 @@ #define LOG_MODULE_NAME signals LOG_MODULE_REGISTER(LOG_MODULE_NAME); -#define RUN_STATUS_LED DK_LED1 -#define RUN_LED_BLINK_INTERVAL 1000 +#define OUT_RESERVED DK_LED1 +#define OUT_NRF_READY DK_LED2 -#define FW_RUNNING_SIG DK_LED2 +#define IN_STAY_IN_BOOTLOADER DK_BTN1_MSK +#define IN_TRZ_READY DK_BTN2_MSK -static K_SEM_DEFINE(led_init_ok, 0, 1); +static K_SEM_DEFINE(signals_ok, 0, 1); + +static bool out_nrf_ready = false; +static bool out_reserved = false; void button_changed(uint32_t button_state, uint32_t has_changed) {} @@ -52,44 +56,31 @@ static void configure_gpio(void) { } bool signals_is_trz_ready(void) { - return (dk_get_buttons() & DK_BTN2_MSK) != 0; + return (dk_get_buttons() & IN_TRZ_READY) != 0; +} + +bool signals_is_stay_in_bootloader(void) { + return (dk_get_buttons() & IN_STAY_IN_BOOTLOADER) != 0; } bool signals_init(void) { configure_gpio(); - k_sem_give(&led_init_ok); + k_sem_give(&signals_ok); return true; } -void signals_fw_running(bool set) { dk_set_led(FW_RUNNING_SIG, set); } - -void led_thread(void) { - // bool connected = false; - int blink_status = 0; - /* Don't go any further until BLE is initialized */ - k_sem_take(&led_init_ok, K_FOREVER); - - for (;;) { - blink_status++; - dk_set_led(RUN_STATUS_LED, (blink_status) % 2); - - // connected = is_connected(); - // - // if (connected) { - // dk_set_led_on(CON_STATUS_LED); - // } else { - // if (is_advertising() && !is_advertising_whitelist()) { - // dk_set_led(CON_STATUS_LED, (blink_status) % 2); - // } else { - // dk_set_led_off(CON_STATUS_LED); - // } - // } - - k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL)); - } +void signals_nrf_ready(bool set) { + out_nrf_ready = set; + dk_set_led(OUT_NRF_READY, set); } -K_THREAD_DEFINE(led_thread_id, CONFIG_DEFAULT_THREAD_STACK_SIZE, led_thread, - NULL, NULL, NULL, 7, 0, 0); +bool signals_out_get_nrf_ready(void) { return out_nrf_ready; } + +void signals_reserved(bool set) { + out_reserved = set; + dk_set_led(OUT_RESERVED, set); +} + +bool signals_out_get_reserved(void) { return out_reserved; } diff --git a/nordic/trezor/trezor-ble/src/trz_comm/inc/trz_comm/trz_comm.h b/nordic/trezor/trezor-ble/src/trz_comm/inc/trz_comm/trz_comm.h index d2c9037ce7..2f26f6a9a8 100644 --- a/nordic/trezor/trezor-ble/src/trz_comm/inc/trz_comm/trz_comm.h +++ b/nordic/trezor/trezor-ble/src/trz_comm/inc/trz_comm/trz_comm.h @@ -27,7 +27,8 @@ typedef enum { NRF_SERVICE_BLE = 0, NRF_SERVICE_BLE_MANAGER = 1, - NRF_SERVICE_POWER_MANAGEMENT = 2, + NRF_SERVICE_MANAGEMENT = 2, + NRF_SERVICE_PRODTEST = 3, NRF_SERVICE_CNT // Number of services } nrf_service_id_t; diff --git a/nordic/trezor/trezor-ble/src/trz_comm/trz_comm.c b/nordic/trezor/trezor-ble/src/trz_comm/trz_comm.c index 77837c89d3..412d8da342 100644 --- a/nordic/trezor/trezor-ble/src/trz_comm/trz_comm.c +++ b/nordic/trezor/trezor-ble/src/trz_comm/trz_comm.c @@ -34,7 +34,8 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); static K_FIFO_DEFINE(fifo_uart_rx_ble); static K_FIFO_DEFINE(fifo_uart_rx_ble_manager); -static K_FIFO_DEFINE(fifo_uart_rx_power_management); +static K_FIFO_DEFINE(fifo_uart_rx_management); +static K_FIFO_DEFINE(fifo_uart_rx_prodtest); void trz_comm_init(void) { spi_init(); @@ -62,15 +63,23 @@ void process_rx_msg(uint8_t service_id, uint8_t *data, uint32_t len) { buf->len = len; memcpy(buf->data, data, len); - if (service_id == NRF_SERVICE_BLE) { - k_fifo_put(&fifo_uart_rx_ble, buf); - } else if (service_id == NRF_SERVICE_BLE_MANAGER) { - k_fifo_put(&fifo_uart_rx_ble_manager, buf); - } else if (service_id == NRF_SERVICE_POWER_MANAGEMENT) { - k_fifo_put(&fifo_uart_rx_power_management, buf); - } else { - LOG_WRN("UART_RX unknown service"); - k_free(buf); + switch (service_id) { + case NRF_SERVICE_BLE: + k_fifo_put(&fifo_uart_rx_ble, buf); + break; + case NRF_SERVICE_BLE_MANAGER: + k_fifo_put(&fifo_uart_rx_ble_manager, buf); + break; + case NRF_SERVICE_MANAGEMENT: + k_fifo_put(&fifo_uart_rx_management, buf); + break; + case NRF_SERVICE_PRODTEST: + k_fifo_put(&fifo_uart_rx_prodtest, buf); + break; + default: + LOG_WRN("UART_RX unknown service"); + k_free(buf); + break; } } @@ -80,8 +89,10 @@ trz_packet_t *trz_comm_poll_data(nrf_service_id_t service) { return k_fifo_get(&fifo_uart_rx_ble, K_FOREVER); case NRF_SERVICE_BLE_MANAGER: return k_fifo_get(&fifo_uart_rx_ble_manager, K_FOREVER); - case NRF_SERVICE_POWER_MANAGEMENT: - return k_fifo_get(&fifo_uart_rx_power_management, K_FOREVER); + case NRF_SERVICE_MANAGEMENT: + return k_fifo_get(&fifo_uart_rx_management, K_FOREVER); + case NRF_SERVICE_PRODTEST: + return k_fifo_get(&fifo_uart_rx_prodtest, K_FOREVER); default: LOG_WRN("UART_RX unknown service"); return NULL;