diff --git a/core/.gitignore b/core/.gitignore index e7d93b2e5..7670e873e 100644 --- a/core/.gitignore +++ b/core/.gitignore @@ -13,3 +13,4 @@ mypy_report tools/gdb_scripts/*.log /embed/ble_bootloader/jlink.jdebug.user /embed/ble_firmware/jlink.jdebug.user +/embed/ble_zephyr_fw/cmake-build-debug/ diff --git a/core/embed/ble_zephyr_fw/CMakeLists.txt b/core/embed/ble_zephyr_fw/CMakeLists.txt new file mode 100644 index 000000000..bd2187f9b --- /dev/null +++ b/core/embed/ble_zephyr_fw/CMakeLists.txt @@ -0,0 +1,30 @@ +# +# Copyright (c) 2018 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# +cmake_minimum_required(VERSION 3.20.0) + +list(APPEND BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(NONE) + +# NORDIC SDK APP START +target_sources(app PRIVATE + src/main.c + src/connection.c + src/advertising.c + src/uart.c + src/spi.c + src/int_comm.c + src/pb_comm.c + src/trz_nus.c + src/protob/messages.pb.c + src/protob/protob_helpers.c +) + + +# NORDIC SDK APP END + +zephyr_library_include_directories(.) diff --git a/core/embed/ble_zephyr_fw/Kconfig b/core/embed/ble_zephyr_fw/Kconfig new file mode 100644 index 000000000..200403dfd --- /dev/null +++ b/core/embed/ble_zephyr_fw/Kconfig @@ -0,0 +1,43 @@ +# +# Copyright (c) 2018 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +source "Kconfig.zephyr" + +menu "Nordic UART BLE GATT service sample" + +config BT_NUS_THREAD_STACK_SIZE + int "Thread stack size" + default 1024 + help + Stack size used in each of the two threads + +config BT_NUS_UART_BUFFER_SIZE + int "UART payload buffer element size" + default 40 + help + Size of the payload buffer in each RX and TX FIFO element + +config BT_NUS_SECURITY_ENABLED + bool "Enable security" + default y + select BT_SMP + help + "Enable BLE security for the UART service" + +config BT_NUS_UART_RX_WAIT_TIME + int "Timeout for UART RX complete event" + default 50000 + help + Wait for RX complete event time in microseconds + +config BT_NUS_UART_ASYNC_ADAPTER + bool "Enable UART async adapter" + select SERIAL_SUPPORT_ASYNC + help + Enables asynchronous adapter for UART drives that supports only + IRQ interface. + +endmenu diff --git a/core/embed/ble_zephyr_fw/Kconfig.sysbuild b/core/embed/ble_zephyr_fw/Kconfig.sysbuild new file mode 100644 index 000000000..3f4664abd --- /dev/null +++ b/core/embed/ble_zephyr_fw/Kconfig.sysbuild @@ -0,0 +1,10 @@ +# +# Copyright (c) 2023 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +source "${ZEPHYR_BASE}/share/sysbuild/Kconfig" + +config NRF_DEFAULT_BLUETOOTH + default y diff --git a/core/embed/ble_zephyr_fw/README.rst b/core/embed/ble_zephyr_fw/README.rst new file mode 100644 index 000000000..d0bd0a433 --- /dev/null +++ b/core/embed/ble_zephyr_fw/README.rst @@ -0,0 +1,244 @@ +.. _peripheral_uart: + +Bluetooth: Peripheral UART +########################## + +.. contents:: + :local: + :depth: 2 + +The Peripheral UART sample demonstrates how to use the :ref:`nus_service_readme`. +It uses the NUS service to send data back and forth between a UART connection and a Bluetooth® LE connection, emulating a serial port over Bluetooth LE. + +Requirements +************ + +The sample supports the following development kits: + +.. table-from-sample-yaml:: + +.. include:: /includes/tfm.txt + +.. note:: + * The boards ``nrf52dk_nrf52810``, ``nrf52840dk_nrf52811``, and ``nrf52833dk_nrf52820`` only support the `Minimal sample variant`_. + * When used with :ref:`zephyr:thingy53_nrf5340`, the sample supports the MCUboot bootloader with serial recovery and SMP DFU over Bluetooth. + Thingy:53 has no built-in SEGGER chip, so the UART 0 peripheral is not gated to a USB CDC virtual serial port. + * When used with :ref:`zephyr:nrf5340dk_nrf5340`, the sample might support the MCUboot bootloader with serial recovery of the networking core image. + +The sample also requires a smartphone or tablet running a compatible application. +The `Testing`_ instructions refer to `nRF Connect for Mobile`_, but you can also use other similar applications (for example, `nRF Blinky`_ or `nRF Toolbox`_). + +You can also test the application with the :ref:`central_uart` sample. +See the documentation for that sample for detailed instructions. + +.. note:: + |thingy53_sample_note| + + The sample also enables an additional USB CDC ACM port that is used instead of UART 0. + Because of that, it uses a separate USB Vendor and Product ID. + +Overview +******** + +When connected, the sample forwards any data received on the RX pin of the UART 0 peripheral to the Bluetooth LE unit. +On Nordic Semiconductor's development kits, the UART 0 peripheral is typically gated through the SEGGER chip to a USB CDC virtual serial port. + +Any data sent from the Bluetooth LE unit is sent out of the UART 0 peripheral's TX pin. + +.. note:: + Thingy:53 uses the second instance of USB CDC ACM class instead of UART 0, because it has no built-in SEGGER chip that could be used to gate UART 0. + +.. _peripheral_uart_debug: + +Debugging +========= + +In this sample, the UART console is used to send and read data over the NUS service. +Debug messages are not displayed in this UART console. +Instead, they are printed by the RTT logger. + +If you want to view the debug messages, follow the procedure in :ref:`testing_rtt_connect`. + +.. note:: + On the Thingy:53, debug logs are provided over the USB CDC ACM class serial port, instead of using RTT. + +For more information about debugging in the |NCS|, see :ref:`debugging`. + +FEM support +*********** + +.. include:: /includes/sample_fem_support.txt + +.. _peripheral_uart_minimal_ext: + +Minimal sample variant +====================== + +You can build the sample with a minimum configuration as a demonstration of how to reduce code size and RAM usage. +This variant is available for resource-constrained boards. + +See :ref:`peripheral_uart_sample_activating_variants` for details. + +.. _peripheral_uart_cdc_acm_ext: + +USB CDC ACM extension +===================== + +For the boards with the USB device peripheral, you can build the sample with support for the USB CDC ACM class serial port instead of the physical UART. +This build uses the sample-specific UART async adapter module that acts as a bridge between USB CDC ACM and Zephyr's UART asynchronous API used by the sample. +See :ref:`peripheral_uart_sample_activating_variants` for details about how to build the sample with this extension using the :file:`prj_cdc.conf`. + +Async adapter experimental module +--------------------------------- + +The default sample configuration uses the UART async API, which is an :ref:`experimental ` module. +The UART async adapter creates and initializes an instance of the async module. +This is needed because the USB CDC ACM implementation provides only the interrupt interface. +The adapter uses data provided in the :c:struct:`uart_async_adapter_data` to connect to the UART device that does not use the asynchronous interface. + +The module requires the :ref:`CONFIG_BT_NUS_UART_ASYNC_ADAPTER ` to be set to ``y``. +For more information about the adapter, see the :file:`uart_async_adapter` source files available in the :file:`peripheral_uart/src` directory. + +MCUboot with serial recovery of the networking core image +========================================================= + +For the ``nrf5340dk_nrf5340_cpuapp``, it is possible to enable serial recovery of the network core while multi-image update is not enabled in the MCUboot. +See :ref:`peripheral_uart_sample_activating_variants` for details on how to build the sample with this feature using the :file:`nrf5340dk_app_sr_net.conf` and :file:`nrf5340dk_mcuboot_sr_net.conf` files. + +User interface +************** + +The user interface of the sample depends on the hardware platform you are using. + +Development kits +================ + +LED 1: + Blinks, toggling on/off every second, when the main loop is running and the device is advertising. + +LED 2: + Lit when connected. + +Button 1: + Confirm the passkey value that is printed in the debug logs to pair/bond with the other device. + +Button 2: + Reject the passkey value that is printed in the debug logs to prevent pairing/bonding with the other device. + +Thingy:53 +========= + +RGB LED: + The RGB LED channels are used independently to display the following information: + + * Red channel blinks with a period of two seconds, duty cycle 50%, when the main loop is running (device is advertising). + * Green channel displays if device is connected. + +Button: + Confirm the passkey value that is printed in the debug logs to pair/bond with the other device. + Thingy:53 has only one button, therefore the passkey value cannot be rejected by pressing a button. + +Configuration +************* + +|config| + +Configuration options +===================== + +Check and configure the following configuration options for the sample: + +.. _CONFIG_BT_NUS_UART_ASYNC_ADAPTER: + +CONFIG_BT_NUS_UART_ASYNC_ADAPTER - Enable UART async adapter + Enables asynchronous adapter for UART drives that supports only IRQ interface. + +Building and running +******************** + +.. |sample path| replace:: :file:`samples/bluetooth/peripheral_uart` + +.. include:: /includes/build_and_run_ns.txt + +.. _peripheral_uart_sample_activating_variants: + +Activating sample extensions +============================ + +To activate the optional extensions supported by this sample, modify :makevar:`OVERLAY_CONFIG` in the following manner: + +* For the minimal build variant, set :file:`prj_minimal.conf`. +* For the USB CDC ACM extension, set :file:`prj_cdc.conf`. + Additionally, you need to set :makevar:`DTC_OVERLAY_FILE` to the :file:`usb.overlay` file. +* For the MCUboot with serial recovery of the networking core image feature, set the :file:`nrf5340dk_app_sr_net.conf` file. + You also need to set the :makevar:`mcuboot_OVERLAY_CONFIG` variant to the :file:`nrf5340dk_mcuboot_sr_net.conf` file. + +See :ref:`cmake_options` for instructions on how to add this option. +For more information about using configuration overlay files, see :ref:`zephyr:important-build-vars` in the Zephyr documentation. + +.. _peripheral_uart_testing: + +Testing +======= + +After programming the sample to your development kit, complete the following steps to test it: + +1. Connect the device to the computer to access UART 0. + If you use a development kit, UART 0 is forwarded as a COM port (Windows) or ttyACM device (Linux) after you connect the development kit over USB. + If you use Thingy:53, you must attach the debug board and connect an external USB to UART converter to it. +#. |connect_terminal| +#. Optionally, you can display debug messages. See :ref:`peripheral_uart_debug` for details. +#. Reset the kit. +#. Observe that **LED 1** is blinking and that the device is advertising with the device name that is configured in :kconfig:option:`CONFIG_BT_DEVICE_NAME`. +#. Observe that the text "Starting Nordic UART service example" is printed on the COM listener running on the computer. +#. Connect to the device using nRF Connect for Mobile. + Observe that **LED 2** is lit. +#. Optionally, pair or bond with the device with MITM protection. + This requires using the passkey value displayed in debug messages. + See :ref:`peripheral_uart_debug` for details on how to access debug messages. + To confirm pairing or bonding, press **Button 1** on the device and accept the passkey value on the smartphone. +#. In the application, observe that the services are shown in the connected device. +#. Select the UART RX characteristic value in nRF Connect for Mobile. + You can write to the UART RX and get the text displayed on the COM listener. +#. Type "0123456789" and tap :guilabel:`SEND`. + Verify that the text "0123456789" is displayed on the COM listener. +#. To send data from the device to your phone or tablet, enter any text, for example, "Hello", and press Enter to see it on the COM listener. + Observe that a notification is sent to the peer. +#. Disconnect the device in nRF Connect for Mobile. + Observe that **LED 2** turns off. + +Dependencies +************ + +This sample uses the following sample-specific library: + +* :file:`uart_async_adapter` at :file:`peripheral_uart/src` + +This sample uses the following |NCS| libraries: + +* :ref:`nus_service_readme` +* :ref:`dk_buttons_and_leds_readme` + +In addition, it uses the following Zephyr libraries: + +* :file:`include/zephyr/types.h` +* :file:`boards/arm/nrf*/board.h` +* :ref:`zephyr:kernel_api`: + + * :file:`include/kernel.h` + +* :ref:`zephyr:api_peripherals`: + + * :file:`include/gpio.h` + * :file:`include/uart.h` + +* :ref:`zephyr:bluetooth_api`: + + * :file:`include/bluetooth/bluetooth.h` + * :file:`include/bluetooth/gatt.h` + * :file:`include/bluetooth/hci.h` + * :file:`include/bluetooth/uuid.h` + +The sample also uses the following secure firmware component: + +* :ref:`Trusted Firmware-M ` diff --git a/core/embed/ble_zephyr_fw/VERSION b/core/embed/ble_zephyr_fw/VERSION new file mode 100644 index 000000000..956d85eaa --- /dev/null +++ b/core/embed/ble_zephyr_fw/VERSION @@ -0,0 +1,5 @@ +VERSION_MAJOR = 2 +VERSION_MINOR = 5 +PATCHLEVEL = 0 +VERSION_TWEAK = 0 +EXTRAVERSION = diff --git a/core/embed/ble_zephyr_fw/app.overlay b/core/embed/ble_zephyr_fw/app.overlay new file mode 100644 index 000000000..a53531d84 --- /dev/null +++ b/core/embed/ble_zephyr_fw/app.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/ { + chosen { + nordic,nus-uart = &uart0; + }; +}; diff --git a/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/Kconfig b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/Kconfig new file mode 100644 index 000000000..648a5c247 --- /dev/null +++ b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/Kconfig @@ -0,0 +1,10 @@ +# nRF52833 DK NRF52833 board configuration + +# Copyright (c) 2019 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ENABLE_DCDC + bool "DCDC mode" + select SOC_DCDC_NRF52X + default y + depends on BOARD_T3W1_NRF52833 diff --git a/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/Kconfig.board b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/Kconfig.board new file mode 100644 index 000000000..0b1e8350f --- /dev/null +++ b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/Kconfig.board @@ -0,0 +1,8 @@ +# nRF52833 DK NRF52833 board configuration + +# Copyright (c) 2019 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_T3W1_NRF52833 + bool "T3W1 NRF52833" + depends on SOC_NRF52833_QIAA diff --git a/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/Kconfig.defconfig b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/Kconfig.defconfig new file mode 100644 index 000000000..f95cacff1 --- /dev/null +++ b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/Kconfig.defconfig @@ -0,0 +1,14 @@ +# nRF52833 DK NRF52833 board configuration + +# Copyright (c) 2019 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_T3W1_NRF52833 + +config BOARD + default "t3w1_nrf52833" + +config BT_CTLR + default BT + +endif # BOARD_T3W1_NRF52833 diff --git a/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/board.cmake b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/board.cmake new file mode 100644 index 000000000..f8c71dc56 --- /dev/null +++ b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/board.cmake @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=nRF52833_xxAA" "--speed=4000") +board_runner_args(pyocd "--target=nrf52833" "--frequency=4000000") +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/nrfutil.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd-nrf5.board.cmake) diff --git a/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/doc/index.rst b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/doc/index.rst new file mode 100644 index 000000000..cb6b6fa4a --- /dev/null +++ b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/doc/index.rst @@ -0,0 +1,217 @@ +.. _nrf52833dk_nrf52833: + +nRF52833 DK +########### + +Overview +******** + +The nRF52833 Development Kit (PCA10100) hardware provides +support for the Nordic Semiconductor nRF52833 ARM Cortex-M4F CPU and +the following devices: + +* :abbr:`ADC (Analog to Digital Converter)` +* CLOCK +* FLASH +* :abbr:`GPIO (General Purpose Input Output)` +* :abbr:`I2C (Inter-Integrated Circuit)` +* :abbr:`MPU (Memory Protection Unit)` +* :abbr:`NVIC (Nested Vectored Interrupt Controller)` +* :abbr:`PWM (Pulse Width Modulation)` +* RADIO (Bluetooth Low Energy and 802.15.4) +* :abbr:`RTC (nRF RTC System Clock)` +* Segger RTT (RTT Console) +* :abbr:`SPI (Serial Peripheral Interface)` +* :abbr:`UART (Universal asynchronous receiver-transmitter)` +* :abbr:`USB (Universal Serial Bus)` +* :abbr:`WDT (Watchdog Timer)` + +More information about the board can be found at the +`nRF52833 DK website`_. The `Nordic Semiconductor Infocenter`_ +contains the processor's information and the datasheet. + + +Hardware +******** + +nRF52833 DK has two external oscillators. The frequency of +the slow clock is 32.768 kHz. The frequency of the main clock +is 32 MHz. + +Supported Features +================== + +The nrf52833dk_nrf52833 board configuration supports the following +hardware features: + ++-----------+------------+----------------------+ +| Interface | Controller | Driver/Component | ++===========+============+======================+ +| ADC | on-chip | adc | ++-----------+------------+----------------------+ +| CLOCK | on-chip | clock_control | ++-----------+------------+----------------------+ +| FLASH | on-chip | flash | ++-----------+------------+----------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+----------------------+ +| I2C(M) | on-chip | i2c | ++-----------+------------+----------------------+ +| MPU | on-chip | arch/arm | ++-----------+------------+----------------------+ +| NVIC | on-chip | arch/arm | ++-----------+------------+----------------------+ +| PWM | on-chip | pwm | ++-----------+------------+----------------------+ +| RADIO | on-chip | Bluetooth, | +| | | ieee802154 | ++-----------+------------+----------------------+ +| RTC | on-chip | system clock | ++-----------+------------+----------------------+ +| RTT | Segger | console | ++-----------+------------+----------------------+ +| SPI(M/S) | on-chip | spi | ++-----------+------------+----------------------+ +| UART | on-chip | serial | ++-----------+------------+----------------------+ +| USB | on-chip | usb | ++-----------+------------+----------------------+ +| WDT | on-chip | watchdog | ++-----------+------------+----------------------+ + +Other hardware features have not been enabled yet for this board. +See `nRF52833 DK website`_ and `Nordic Semiconductor Infocenter`_ +for a complete list of nRF52833 Development Kit board hardware features. + +Connections and IOs +=================== + +LED +--- + +* LED1 (green) = P0.13 +* LED2 (green) = P0.14 +* LED3 (green) = P0.15 +* LED4 (green) = P0.16 + +Push buttons +------------ + +* BUTTON1 = SW1 = P0.11 +* BUTTON2 = SW2 = P0.12 +* BUTTON3 = SW3 = P0.24 +* BUTTON4 = SW4 = P0.25 +* BOOT = SW5 = boot/reset + +Programming and Debugging +************************* + +Applications for the ``nrf52833dk_nrf52833`` board configuration can be built, +flashed, and debugged in the usual way. See :ref:`build_an_application` and +:ref:`application_run` for more details on building and running. + +Flashing +======== + +Follow the instructions in the :ref:`nordic_segger` page to install +and configure all the necessary software. Further information can be +found in :ref:`nordic_segger_flashing`. Then build and flash +applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +Here is an example for the :ref:`hello_world` application. + +First, run your favorite terminal program to listen for output. + +.. code-block:: console + + $ minicom -D -b 115200 + +Replace :code:`` with the port where the board nRF52 DK +can be found. For example, under Linux, :code:`/dev/ttyACM0`. + +Then build and flash the application in the usual way. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: nrf52833dk_nrf52833 + :goals: build flash + +Debugging +========= + +Refer to the :ref:`nordic_segger` page to learn about debugging Nordic boards with a +Segger IC. + + +Testing the LEDs and buttons in the nRF52833 DK +*********************************************** + +There are 2 samples that allow you to test that the buttons (switches) and LEDs on +the board are working properly with Zephyr: + +* :ref:`blinky-sample` +* :ref:`button-sample` + +You can build and flash the examples to make sure Zephyr is running correctly on +your board. The button and LED definitions can be found in +:zephyr_file:`boards/arm/nrf52833dk_nrf52833/nrf52833dk_nrf52833.dts`. + +Changing UART1 pins +******************* + +The following approach can be used when an application needs to use another set +of pins for UART1: + +1. Add devicetree overlay file to the main directory of your application: + + .. code-block:: devicetree + + &pinctrl { + uart1_default_alt: uart1_default_alt { + group1 { + psels = , + ; + }; + }; + /* required if CONFIG_PM_DEVICE=y */ + uart1_sleep_alt: uart1_sleep_alt { + group1 { + psels = , + ; + low-power-enable; + }; + }; + }; + + &uart1 { + pinctrl-0 = <&uart1_default_alt>; + /* if sleep state is not used, use /delete-property/ pinctrl-1; and + * skip the "sleep" entry. + */ + pinctrl-1 = <&uart1_sleep_alt>; + pinctrl-names = "default", "sleep"; + }; + + In the overlay file above, pin P0.16 is used for RX and P0.14 is used for TX + +See :ref:`set-devicetree-overlays` for further details. + +Selecting the pins +================== + +Pins can be configured in the board pinctrl file. To see the available mappings, +open the `nRF52833 Product Specification`_, chapter 7 'Hardware and Layout'. +In the table 7.1.1 'aQFN73 ball assignments' select the pins marked +'General purpose I/O'. Note that pins marked as 'low frequency I/O only' can only be used +in under-10KHz applications. They are not suitable for 115200 speed of UART. + +References +********** + +.. target-notes:: + +.. _nRF52833 DK website: https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52833-DK +.. _Nordic Semiconductor Infocenter: https://infocenter.nordicsemi.com +.. _J-Link Software and documentation pack: https://www.segger.com/jlink-software.html +.. _nRF52833 Product Specification: https://infocenter.nordicsemi.com/pdf/nRF52833_OPS_v0.7.pdf diff --git a/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/pre_dt_board.cmake b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/pre_dt_board.cmake new file mode 100644 index 000000000..3369c21d3 --- /dev/null +++ b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/pre_dt_board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2022 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +# Suppress "unique_unit_address_if_enabled" to handle the following overlaps: +# - power@40000000 & clock@40000000 & bprot@40000000 +# - acl@4001e000 & flash-controller@4001e000 +list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled") diff --git a/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/t3w1_nrf52833-pinctrl.dtsi b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/t3w1_nrf52833-pinctrl.dtsi new file mode 100644 index 000000000..fa0a6e79a --- /dev/null +++ b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/t3w1_nrf52833-pinctrl.dtsi @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + + + spi0_default: spi0_default { + group1 { + psels = , + , + ; + }; + }; + + spi0_sleep: spi0_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; + + +}; diff --git a/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/t3w1_nrf52833.dts b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/t3w1_nrf52833.dts new file mode 100644 index 000000000..8221ec462 --- /dev/null +++ b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/t3w1_nrf52833.dts @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "t3w1_nrf52833-pinctrl.dtsi" +#include + +/ { + model = "T3W1 NRF52833"; + compatible = "nordic,t3w1_nrf52833"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + zephyr,bt-mon-uart = &uart0; + zephyr,bt-c2h-uart = &uart0; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,ieee802154 = &ieee802154; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 22 GPIO_ACTIVE_LOW>; + label = "Green LED 0"; + }; + led1: led_1 { + gpios = <&gpio0 24 GPIO_ACTIVE_LOW>; + label = "Green LED 1"; + }; + out0: out_0 { + gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>; + label = "FW Running"; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio1 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button switch 0"; + zephyr,code = ; + }; + trezor_ready: trezor_ready { + gpios = <&gpio0 30 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; + label = "Trezor ready"; + zephyr,code = ; + }; + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &led0; + led1 = &led1; + sw0 = &button0; + bootloader-led0 = &led0; + mcuboot-button0 = &button0; + mcuboot-led0 = &led0; + watchdog0 = &wdt0; + }; +}; + +&adc { + status = "okay"; +}; + +&uicr { + gpio-as-nreset; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&uart0 { + compatible = "nordic,nrf-uarte"; + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&spi0 { + compatible = "nordic,nrf-spim"; + status = "okay"; + pinctrl-0 = <&spi0_default>; + pinctrl-1 = <&spi0_sleep>; + pinctrl-names = "default", "sleep"; + cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + reg_my_spi_master: spi-dev-a@0 { + reg = <0>; + }; +}; + +&ieee802154 { + status = "okay"; +}; + +&flash0 { + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0xC000>; + }; + slot0_partition: partition@c000 { + label = "image-0"; + reg = <0x0000C000 0x37000>; + }; + slot1_partition: partition@43000 { + label = "image-1"; + reg = <0x00043000 0x37000>; + }; + storage_partition: partition@7a000 { + label = "storage"; + reg = <0x0007A000 0x00006000>; + }; + }; +}; + +zephyr_udc0: &usbd { + compatible = "nordic,nrf-usbd"; + status = "okay"; +}; diff --git a/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/t3w1_nrf52833.yaml b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/t3w1_nrf52833.yaml new file mode 100644 index 000000000..94c97593e --- /dev/null +++ b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/t3w1_nrf52833.yaml @@ -0,0 +1,16 @@ +identifier: t3w1_nrf52833 +name: tw31-NRF52833 +type: mcu +arch: arm +ram: 128 +flash: 512 +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - usb_device + - ble + - gpio + - watchdog + - counter diff --git a/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/t3w1_nrf52833_defconfig b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/t3w1_nrf52833_defconfig new file mode 100644 index 000000000..c4e9380a9 --- /dev/null +++ b/core/embed/ble_zephyr_fw/boards/arm/t3w1_nrf52833/t3w1_nrf52833_defconfig @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52833_QIAA=y +CONFIG_BOARD_T3W1_NRF52833=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable RTT +CONFIG_USE_SEGGER_RTT=y + +# enable GPIO +CONFIG_GPIO=y + +# enable uart driver +CONFIG_SERIAL=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +CONFIG_PINCTRL=y diff --git a/core/embed/ble_zephyr_fw/prj.conf b/core/embed/ble_zephyr_fw/prj.conf new file mode 100644 index 000000000..685acd23f --- /dev/null +++ b/core/embed/ble_zephyr_fw/prj.conf @@ -0,0 +1,69 @@ +# +# Copyright (c) 2018 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +# Enable the UART driver +CONFIG_UART_ASYNC_API=y +CONFIG_NRFX_UARTE0=y +CONFIG_SERIAL=y + +CONFIG_NANOPB=y + +# Enable the SPI driver +CONFIG_SPI=y +CONFIG_NRFX_SPIM0=y + +CONFIG_GPIO=y + + + +CONFIG_HEAP_MEM_POOL_SIZE=2048 + +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_DEVICE_NAME="TrezorZephyr" +CONFIG_BT_DEVICE_APPEARANCE=833 +CONFIG_BT_MAX_CONN=1 +CONFIG_BT_MAX_PAIRED=8 +CONFIG_BT_SMP=y +CONFIG_BT_SMP_SC_ONLY=y +CONFIG_BT_FILTER_ACCEPT_LIST=y +CONFIG_BT_PRIVACY=y +# CONFIG_BT_LL_SW_SPLIT=y + +#PHY update needed for updating PHY request +CONFIG_BT_USER_PHY_UPDATE=y + +# HCI ACL buffers size +# BT_L2CAP_RX_MTU = CONFIG_BT_BUF_ACL_RX_SIZE - BT_L2CAP_HDR_SIZE +CONFIG_BT_BUF_ACL_RX_SIZE=251 + +# L2CAP SDU/PDU TX MTU +CONFIG_BT_L2CAP_TX_MTU=247 + + +# Enable bonding +CONFIG_BT_SETTINGS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_NVS=y +CONFIG_SETTINGS=y + +# Enable DK LED and Buttons library +CONFIG_DK_LIBRARY=y + +# This example requires more stack +CONFIG_MAIN_STACK_SIZE=1152 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 + +# Config logger +CONFIG_LOG=y +CONFIG_USE_SEGGER_RTT=y +CONFIG_LOG_BACKEND_RTT=y +CONFIG_LOG_BACKEND_UART=n +CONFIG_LOG_PRINTK=n + +CONFIG_ASSERT=y diff --git a/core/embed/ble_zephyr_fw/prj_cdc.conf b/core/embed/ble_zephyr_fw/prj_cdc.conf new file mode 100644 index 000000000..cbea30c2c --- /dev/null +++ b/core/embed/ble_zephyr_fw/prj_cdc.conf @@ -0,0 +1,18 @@ +# +# Copyright (c) 2021 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +# Enable the UART driver +CONFIG_UART_LINE_CTRL=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_BT_NUS_UART_ASYNC_ADAPTER=y +CONFIG_USB_DEVICE_STACK=y +CONFIG_USB_DEVICE_REMOTE_WAKEUP=n +CONFIG_USB_CDC_ACM=y +CONFIG_USB_CDC_ACM_LOG_LEVEL_OFF=y + +# Disable the UARTE0 enabled in default project configuration +CONFIG_NRFX_UARTE0=n +CONFIG_UART_NRFX=n diff --git a/core/embed/ble_zephyr_fw/prj_minimal.conf b/core/embed/ble_zephyr_fw/prj_minimal.conf new file mode 100644 index 000000000..00c71da92 --- /dev/null +++ b/core/embed/ble_zephyr_fw/prj_minimal.conf @@ -0,0 +1,131 @@ +# +# Copyright (c) 2021 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +# Enable the UART driver +CONFIG_UART_ASYNC_API=y +CONFIG_NRFX_UARTE0=y +CONFIG_SERIAL=y + +CONFIG_HEAP_MEM_POOL_SIZE=2048 + +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_DEVICE_NAME="Nordic_UART_Service" +CONFIG_BT_DEVICE_APPEARANCE=833 +CONFIG_BT_MAX_CONN=1 +CONFIG_BT_MAX_PAIRED=1 + +# Enable the NUS service +CONFIG_BT_NUS=y + +# Enable bonding +CONFIG_BT_SETTINGS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_NVS=y +CONFIG_SETTINGS=y + +# Enable DK LED and Buttons library +CONFIG_DK_LIBRARY=y + +# Drivers and peripherals +CONFIG_I2C=n +CONFIG_WATCHDOG=n +CONFIG_SPI=n +CONFIG_GPIO=n + +# Power management + +# Interrupts +CONFIG_DYNAMIC_INTERRUPTS=n +CONFIG_IRQ_OFFLOAD=n + +# Memory protection +CONFIG_THREAD_STACK_INFO=n +CONFIG_THREAD_CUSTOM_DATA=n +CONFIG_FPU=n + +# Boot +CONFIG_BOOT_BANNER=n +CONFIG_BOOT_DELAY=0 + +# Console +CONFIG_CONSOLE=n +CONFIG_UART_CONSOLE=n +CONFIG_STDOUT_CONSOLE=n +CONFIG_PRINTK=n +CONFIG_EARLY_CONSOLE=n + +# Build +CONFIG_SIZE_OPTIMIZATIONS=y + +# ARM +CONFIG_ARM_MPU=n + +# In order to correctly tune the stack sizes for the threads the following +# Configurations can enabled to print the current use: +#CONFIG_THREAD_NAME=y +#CONFIG_THREAD_ANALYZER=y +#CONFIG_THREAD_ANALYZER_AUTO=y +#CONFIG_THREAD_ANALYZER_RUN_UNLOCKED=y +#CONFIG_THREAD_ANALYZER_USE_PRINTK=y +#CONFIG_CONSOLE=y +#CONFIG_UART_CONSOLE=y +#CONFIG_SERIAL=y +#CONFIG_PRINTK=y + +# Example output of thread analyzer +#SDC RX : unused 800 usage 224 / 1024 (21 %) +#BT ECC : unused 216 usage 888 / 1104 (80 %) +#BT RX : unused 1736 usage 464 / 2200 (21 %) +#BT TX : unused 1008 usage 528 / 1536 (34 %) +#ble_write_thread_id : unused 688 usage 336 / 1024 (32 %) +#sysworkq : unused 1912 usage 136 / 2048 (6 %) +#MPSL signal : unused 928 usage 96 / 1024 (9 %) +#idle 00 : unused 224 usage 96 / 320 (30 %) +#main : unused 568 usage 456 / 1024 (44 %) +CONFIG_BT_RX_STACK_SIZE=1024 +CONFIG_BT_HCI_TX_STACK_SIZE_WITH_PROMPT=y +CONFIG_BT_HCI_TX_STACK_SIZE=640 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512 +CONFIG_MPSL_WORK_STACK_SIZE=256 +CONFIG_MAIN_STACK_SIZE=864 +CONFIG_IDLE_STACK_SIZE=128 +CONFIG_ISR_STACK_SIZE=1024 +CONFIG_BT_NUS_THREAD_STACK_SIZE=512 + +# Disable features not needed +CONFIG_TIMESLICING=n +CONFIG_MINIMAL_LIBC_MALLOC=n +CONFIG_LOG=n +CONFIG_ASSERT=n + +# Disable Bluetooth features not needed +CONFIG_BT_DEBUG_NONE=y +CONFIG_BT_ASSERT=n +CONFIG_BT_DATA_LEN_UPDATE=n +CONFIG_BT_PHY_UPDATE=n +CONFIG_BT_GATT_CACHING=n +CONFIG_BT_GATT_SERVICE_CHANGED=n +CONFIG_BT_GAP_PERIPHERAL_PREF_PARAMS=n +CONFIG_BT_SETTINGS_CCC_LAZY_LOADING=y +CONFIG_BT_HCI_VS_EXT=n + +# Disable Bluetooth controller features not needed +CONFIG_BT_CTLR_PRIVACY=n +CONFIG_BT_CTLR_PHY_2M=n + +# Reduce Bluetooth buffers +CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT=1 +CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=43 +CONFIG_BT_BUF_EVT_RX_COUNT=2 + +CONFIG_BT_CONN_TX_MAX=2 +CONFIG_BT_L2CAP_TX_BUF_COUNT=2 +CONFIG_BT_CTLR_RX_BUFFERS=1 +CONFIG_BT_BUF_ACL_TX_COUNT=3 +CONFIG_BT_BUF_ACL_TX_SIZE=27 diff --git a/core/embed/ble_zephyr_fw/sample.yaml b/core/embed/ble_zephyr_fw/sample.yaml new file mode 100644 index 000000000..e871af6c4 --- /dev/null +++ b/core/embed/ble_zephyr_fw/sample.yaml @@ -0,0 +1,65 @@ +sample: + description: Bluetooth Low Energy UART service sample + name: BLE UART service +tests: + sample.bluetooth.peripheral_uart: + build_only: true + platform_allow: nrf52dk_nrf52832 nrf52833dk_nrf52833 t3w1_nrf52833 nrf52840dk_nrf52840 + nrf5340dk_nrf5340_cpuapp nrf5340dk_nrf5340_cpuapp_ns thingy53_nrf5340_cpuapp + thingy53_nrf5340_cpuapp_ns nrf21540dk_nrf52840 + integration_platforms: + - nrf52dk_nrf52832 + - nrf52833dk_nrf52833 + - t3w1_nrf52833 + - nrf52840dk_nrf52840 + - nrf5340dk_nrf5340_cpuapp + - nrf5340dk_nrf5340_cpuapp_ns + - thingy53_nrf5340_cpuapp + - thingy53_nrf5340_cpuapp_ns + - nrf21540dk_nrf52840 + tags: bluetooth ci_build + sample.bluetooth.peripheral_uart.sysbuild: + build_only: true + sysbuild: true + platform_allow: nrf52840dk_nrf52840 nrf5340dk_nrf5340_cpuapp + nrf5340dk_nrf5340_cpuapp_ns + integration_platforms: + - nrf52840dk_nrf52840 + - nrf5340dk_nrf5340_cpuapp + - nrf5340dk_nrf5340_cpuapp_ns + tags: bluetooth ci_build sysbuild + sample.bluetooth.peripheral_uart_cdc: + build_only: true + extra_args: OVERLAY_CONFIG=prj_cdc.conf DTC_OVERLAY_FILE="usb.overlay" + integration_platforms: + - nrf52840dk_nrf52840 + - nrf52833dk_nrf52833 + platform_allow: nrf52840dk_nrf52840 nrf52833dk_nrf52833 + tags: bluetooth ci_build + sample.bluetooth.peripheral_uart_minimal: + build_only: true + extra_args: OVERLAY_CONFIG=prj_minimal.conf + integration_platforms: + - nrf52dk_nrf52810 + - nrf52840dk_nrf52811 + - nrf52833dk_nrf52820 + platform_allow: nrf52dk_nrf52810 nrf52840dk_nrf52811 nrf52833dk_nrf52820 + tags: bluetooth ci_build + sample.bluetooth.peripheral_uart_ble_rpc: + build_only: true + extra_configs: + - CONFIG_BT_RPC_STACK=y + integration_platforms: + - nrf5340dk_nrf5340_cpuapp + platform_allow: nrf5340dk_nrf5340_cpuapp + tags: bluetooth ci_build + sample.bluetooth.peripheral_uart.security_disabled: + build_only: true + platform_allow: nrf52dk_nrf52832 nrf52833dk_nrf52833 nrf52840dk_nrf52840 + nrf5340dk_nrf5340_cpuapp nrf5340dk_nrf5340_cpuapp_ns thingy53_nrf5340_cpuapp + thingy53_nrf5340_cpuapp_ns nrf21540dk_nrf52840 + integration_platforms: + - nrf52840dk_nrf52840 + tags: bluetooth ci_build + extra_configs: + - CONFIG_BT_NUS_SECURITY_ENABLED=n diff --git a/core/embed/ble_zephyr_fw/src/advertising.c b/core/embed/ble_zephyr_fw/src/advertising.c new file mode 100644 index 000000000..19a9909fd --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/advertising.c @@ -0,0 +1,138 @@ + +#include +#include + +#include +#include + +#include + +#include "int_comm.h" +#include "connection.h" + + +#define LOG_MODULE_NAME fw_int_advertising +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + + +#define DEVICE_NAME CONFIG_BT_DEVICE_NAME +#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) + +bool advertising = false; +bool advertising_wl = false; +int bond_cnt = 0; + +static const struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), +}; + +static const struct bt_data sd[] = { + BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_NUS_VAL), +}; + + +static void add_to_whitelist(const struct bt_bond_info *info, void *user_data){ + char addr[BT_ADDR_LE_STR_LEN]; + bt_addr_le_to_str(&info->addr, addr, sizeof(addr)); + + int err = bt_le_filter_accept_list_add(&info->addr); + if (err){ + LOG_WRN("whitelist add: %s FAILED!\n", addr); + }else{ + LOG_INF("whitelist add: %s\n", addr); + } + + bond_cnt++; +} + + +void advertising_setup_wl(void) { + bt_le_filter_accept_list_clear(); + bt_foreach_bond(BT_ID_DEFAULT, add_to_whitelist, NULL); +} + +void advertising_start(bool wl){ + + if (advertising) { + if (wl != advertising_wl) { + LOG_WRN("Restarting advertising"); + bt_le_adv_stop(); + }else { + LOG_WRN("Already advertising"); + return; + } + } + + int err; + + if (wl) { + advertising_setup_wl(); + LOG_INF("Advertising with whitelist"); + err = bt_le_adv_start( + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_FILTER_CONN | BT_LE_ADV_OPT_FILTER_SCAN_REQ, + 160, 1600, NULL), + ad, ARRAY_SIZE(ad), + sd, ARRAY_SIZE(sd)); + } + else { + LOG_INF("Advertising no whitelist"); + err = bt_le_adv_start( + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE, + 160, 1600, NULL), + ad, ARRAY_SIZE(ad), + sd, ARRAY_SIZE(sd)); + } + if (err) { + LOG_ERR("Advertising failed to start (err %d)", err); + return; + } + advertising = true; + advertising_wl = wl; + send_status_event(); +} + +void advertising_stop(void){ + + if (!advertising) { + LOG_WRN("Not advertising"); + return; + } + + int err = bt_le_adv_stop(); + if (err) { + LOG_ERR("Advertising failed to stop (err %d)", err); + return; + } + advertising = false; + advertising_wl = false; + send_status_event(); +} + +bool is_advertising(void){ + return advertising; +} + +bool is_advertising_whitelist(void){ + return advertising_wl; +} + + +void advertising_init(void){ + LOG_INF("Advertising init"); + advertising_setup_wl(); +} + +void erase_bonds(void){ + int err = bt_unpair(BT_ID_DEFAULT, BT_ADDR_LE_ANY); + if (err) { + LOG_INF("Cannot delete bond (err: %d)\n", err); + } else { + LOG_INF("Bond deleted successfully \n"); + } +} + +int advertising_get_bond_count(void){ + advertising_setup_wl(); + return bond_cnt; +} diff --git a/core/embed/ble_zephyr_fw/src/advertising.h b/core/embed/ble_zephyr_fw/src/advertising.h new file mode 100644 index 000000000..fe010172a --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/advertising.h @@ -0,0 +1,14 @@ + + + +#include + + +void advertising_start(bool wl); +void advertising_stop(void); +bool is_advertising(void); +bool is_advertising_whitelist(void); +void advertising_init(void); +void advertising_setup_wl(void); +int advertising_get_bond_count(void); +void erase_bonds(void); diff --git a/core/embed/ble_zephyr_fw/src/connection.c b/core/embed/ble_zephyr_fw/src/connection.c new file mode 100644 index 000000000..89222c7b3 --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/connection.c @@ -0,0 +1,170 @@ + +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include "connection.h" +#include "advertising.h" +#include "int_comm.h" +#include "pb_comm.h" + +#define CON_STATUS_LED DK_LED2 + +#define LOG_MODULE_NAME fw_int_connection +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +static struct bt_conn *current_conn; +static struct bt_conn *auth_conn; + +void connected(struct bt_conn *conn, uint8_t err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + if (err) { + LOG_ERR("Connection failed (err %u)", err); + return; + } + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + LOG_INF("Connected %s", addr); + + current_conn = bt_conn_ref(conn); + +// struct bt_le_conn_param params = BT_LE_CONN_PARAM_INIT(6,6,0,400); +// +// bt_conn_le_param_update(conn, ¶ms); + + err = bt_conn_le_phy_update(current_conn, BT_CONN_LE_PHY_PARAM_2M); + if (err) { + LOG_ERR("Phy update request failed: %d", err); + } + + dk_set_led_on(CON_STATUS_LED); + + send_status_event(); +} + +void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + LOG_INF("Disconnected: %s (reason %u)", addr, reason); + + if (auth_conn) { + bt_conn_unref(auth_conn); + auth_conn = NULL; + } + + if (current_conn) { + bt_conn_unref(current_conn); + current_conn = NULL; + dk_set_led_off(CON_STATUS_LED); + } + + send_status_event(); +} + +bool is_connected(void) { + return current_conn != NULL; +} + + +void disconnect(void){ + if (current_conn) { + bt_conn_disconnect(current_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + } +} + +void num_comp_reply(bool accept) +{ + if (accept) { + bt_conn_auth_passkey_confirm(auth_conn); + LOG_INF("Numeric Match, conn %p", (void *)auth_conn); + } else { + bt_conn_auth_cancel(auth_conn); + LOG_INF("Numeric Reject, conn %p", (void *)auth_conn); + } + + bt_conn_unref(auth_conn); + auth_conn = NULL; +} + +void passkey_to_str(uint8_t buf[6], unsigned int passkey) { + buf[5] = (passkey % 10) + '0'; + buf[4] = ((passkey / 10) % 10) + '0'; + buf[3] = ((passkey / 100) % 10) + '0'; + buf[2] = ((passkey / 1000) % 10) + '0'; + buf[1] = ((passkey / 10000) % 10) + '0'; + buf[0] = ((passkey / 100000) % 10) + '0'; +} + +void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + uint8_t passkey_str[6]; + passkey_to_str(passkey_str, passkey); + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + pb_comm_enqueue(PASSKEY_DISPLAY, passkey_str, 6); +} + +void auth_passkey_confirm(struct bt_conn *conn, unsigned int passkey) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + auth_conn = bt_conn_ref(conn); + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + uint8_t passkey_str[6]; + passkey_to_str(passkey_str, passkey); + pb_comm_enqueue(COMPARISON_REQUEST, passkey_str, 6); + + send_status_event(); + +} + + +void auth_cancel(struct bt_conn *conn) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + LOG_INF("Pairing cancelled: %s", addr); +} + + +void pairing_complete(struct bt_conn *conn, bool bonded) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (bonded) { + advertising_setup_wl(); + } + + LOG_INF("Pairing completed: %s, bonded: %d", addr, bonded); +} + + +void pairing_failed(struct bt_conn *conn, enum bt_security_err reason) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + LOG_INF("Pairing failed conn: %s, reason %d", addr, reason); +} diff --git a/core/embed/ble_zephyr_fw/src/connection.h b/core/embed/ble_zephyr_fw/src/connection.h new file mode 100644 index 000000000..7cef4269a --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/connection.h @@ -0,0 +1,29 @@ + + +#include +#include + +#include +#include + +#include +#include +#include +#include + +void connected(struct bt_conn *conn, uint8_t err); + +void disconnect(void); + +void disconnected(struct bt_conn *conn, uint8_t reason); + +bool is_connected(void); + +void num_comp_reply(bool accept); +void auth_passkey_display(struct bt_conn *conn, unsigned int passkey); +void auth_passkey_confirm(struct bt_conn *conn, unsigned int passkey); +void auth_cancel(struct bt_conn *conn); +void pairing_complete(struct bt_conn *conn, bool bonded); +void pairing_failed(struct bt_conn *conn, enum bt_security_err reason); + +void num_comp_reply(bool accept); diff --git a/core/embed/ble_zephyr_fw/src/int_comm.c b/core/embed/ble_zephyr_fw/src/int_comm.c new file mode 100644 index 000000000..5f564a27f --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/int_comm.c @@ -0,0 +1,127 @@ + + +#include +#include + +#include +#include + +#include + +#include "uart.h" +#include "int_comm_defs.h" +#include "connection.h" +#include "advertising.h" +#include "pb_comm.h" + +#define LOG_MODULE_NAME fw_int_comm +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +static K_SEM_DEFINE(int_comm_ok, 0, 1); + + + +void send_packet(uint8_t message_type, const uint8_t *tx_data, uint16_t len) { + uart_data_t *tx = k_malloc(sizeof(*tx)); + + if (!tx) { + LOG_WRN("Not able to allocate UART send data buffer"); + return; + } + + tx->len = len + OVERHEAD_SIZE; + + tx->data[0] = message_type; + tx->data[1] = (tx->len >> 8) & 0xFF; + tx->data[2] = tx->len & 0xFF; + memcpy(&tx->data[3], tx_data, len); + tx->data[tx->len-1] = EOM; + + uart_send(tx); + +} + +void send_status_event(void) { +// ble_version_t version = {0}; +// +// sd_ble_version_get(&version); + + event_status_msg_t msg = {0}; + msg.msg_id = INTERNAL_EVENT_STATUS; + msg.connected = is_connected(); + msg.advertising = is_advertising(); + msg.advertising_whitelist = is_advertising_whitelist(); + msg.peer_count = advertising_get_bond_count(); + msg.sd_version_number = 0; + msg.sd_company_id = 0; + msg.sd_subversion_number = 0; + msg.app_version = 0; + msg.bld_version = 0; + + send_packet(INTERNAL_EVENT, (uint8_t *)&msg, sizeof(msg)); +} + + +void send_success_event(void) { + uint8_t tx_data[] = { + INTERNAL_EVENT_SUCCESS, + }; + send_packet(INTERNAL_EVENT, tx_data, sizeof(tx_data)); +} + +uint16_t get_message_type(const uint8_t *rx_data) { + return (rx_data[3] << 8) | rx_data[4]; +} + + +void process_command(uint8_t *data, uint16_t len) { + uint8_t cmd = data[0]; + switch (cmd) { + case INTERNAL_CMD_SEND_STATE: + send_status_event(); + break; + case INTERNAL_CMD_ADVERTISING_ON: + advertising_start(data[1] != 0); + break; + case INTERNAL_CMD_ADVERTISING_OFF: + advertising_stop(); + break; + case INTERNAL_CMD_ERASE_BONDS: + erase_bonds(); + send_success_event(); + break; + case INTERNAL_CMD_DISCONNECT: + disconnect(); + send_success_event(); + case INTERNAL_CMD_ACK: + pb_msg_ack(); + break; + default: + break; + } +} + + +void int_comm_start(void) +{ + k_sem_give(&int_comm_ok); +} + + +void int_comm_thread(void) +{ + /* Don't go any further until BLE is initialized */ + k_sem_take(&int_comm_ok, K_FOREVER); + + for (;;) { + /* Wait indefinitely for data to process */ + uart_data_t *buf = uart_get_data_int(); + + process_command(buf->data, buf->len); + + k_free(buf); + } +} + +//K_THREAD_DEFINE(int_comm_thread_id, CONFIG_BT_NUS_THREAD_STACK_SIZE, int_comm_thread, NULL, NULL, +// NULL, 7, 0, 0); diff --git a/core/embed/ble_zephyr_fw/src/int_comm.h b/core/embed/ble_zephyr_fw/src/int_comm.h new file mode 100644 index 000000000..a3a31c7dd --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/int_comm.h @@ -0,0 +1,18 @@ +#ifndef INT_COMM__ +#define INT_COMM__ + +#include + +void process_command(uint8_t *data, uint16_t len); + +void send_status_event(void); + +void int_comm_start(void); + +void int_comm_thread(void); + +void send_packet(uint8_t message_type, const uint8_t *tx_data, uint16_t len); + +void pb_msg_ack(void); + +#endif diff --git a/core/embed/ble_zephyr_fw/src/int_comm_defs.h b/core/embed/ble_zephyr_fw/src/int_comm_defs.h new file mode 100644 index 000000000..842af6798 --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/int_comm_defs.h @@ -0,0 +1,50 @@ + +#ifndef __INT_COMM_DEFS__ +#define __INT_COMM_DEFS__ + +#define BLE_PACKET_SIZE (244) +#define USB_DATA_SIZE (64) + +#define COMM_HEADER_SIZE (3) +#define COMM_FOOTER_SIZE (1) +#define OVERHEAD_SIZE (COMM_HEADER_SIZE + COMM_FOOTER_SIZE) +#define UART_PACKET_SIZE (USB_DATA_SIZE + OVERHEAD_SIZE) + +#define EOM (0x55) +#define INTERNAL_EVENT (0xA2) +#define EXTERNAL_MESSAGE (0xA1) +#define INTERNAL_MESSAGE (0xA0) + +typedef struct { + uint8_t msg_id; + uint8_t connected; + uint8_t advertising; + uint8_t advertising_whitelist; + + uint8_t peer_count; + uint8_t reserved[2]; + uint8_t sd_version_number; + + uint16_t sd_company_id; + uint16_t sd_subversion_number; + + uint32_t app_version; + uint32_t bld_version; + +} event_status_msg_t; + +typedef enum { + INTERNAL_EVENT_STATUS = 0x01, + INTERNAL_EVENT_SUCCESS = 0x02, + INTERNAL_EVENT_FAILURE = 0x03, +} InternalEvent_t; + +typedef enum { + INTERNAL_CMD_SEND_STATE = 0x00, + INTERNAL_CMD_ADVERTISING_ON = 0x01, + INTERNAL_CMD_ADVERTISING_OFF = 0x02, + INTERNAL_CMD_ERASE_BONDS = 0x03, + INTERNAL_CMD_DISCONNECT = 0x04, + INTERNAL_CMD_ACK = 0x05, +} InternalCmd_t; +#endif diff --git a/core/embed/ble_zephyr_fw/src/main.c b/core/embed/ble_zephyr_fw/src/main.c new file mode 100644 index 000000000..6b52a11e5 --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/main.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/** @file + * @brief Nordic UART Bridge Service (NUS) sample + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + + +#include + +#include + +#include + +#include "uart.h" +#include "spi.h" +#include "connection.h" +#include "int_comm.h" +#include "pb_comm.h" +#include "advertising.h" +#include "trz_nus.h" + +#define LOG_MODULE_NAME fw +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#define STACKSIZE CONFIG_BT_NUS_THREAD_STACK_SIZE +#define PRIORITY 7 + +#define RUN_STATUS_LED DK_LED1 +#define RUN_LED_BLINK_INTERVAL 1000 + +#define FW_RUNNING_SIG DK_LED3 + + +#define KEY_PASSKEY_ACCEPT DK_BTN1_MSK +#define KEY_PASSKEY_REJECT DK_BTN2_MSK + +static K_SEM_DEFINE(ble_init_ok, 0, 1); +static K_SEM_DEFINE(led_init_ok, 0, 1); + + + + + +static void security_changed(struct bt_conn *conn, bt_security_t level, + enum bt_security_err err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (!err) { + LOG_INF("Security changed: %s level %u", addr, level); + } else { + LOG_WRN("Security failed: %s level %u err %d", addr, + level, err); + } +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, + .security_changed = security_changed, +}; + + +static struct bt_conn_auth_cb conn_auth_callbacks = { + .passkey_display = auth_passkey_display, + .passkey_confirm = auth_passkey_confirm, + .cancel = auth_cancel, +}; + +static struct bt_conn_auth_info_cb conn_auth_info_callbacks = { + .pairing_complete = pairing_complete, + .pairing_failed = pairing_failed +}; + + +static void bt_receive_cb(struct bt_conn *conn, const uint8_t *const data, + uint16_t len) +{ + if ((dk_get_buttons() & DK_BTN2_MSK) == 0){ + LOG_INF("Trezor not ready, rejecting data"); + send_error_response(); + return; + } + + char addr[BT_ADDR_LE_STR_LEN] = {0}; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, ARRAY_SIZE(addr)); + + LOG_INF("Received data from: %s, %d", addr, len); + + spi_send(data, len); +} + +static struct bt_nus_cb nus_cb = { + .received = bt_receive_cb, +}; + +void error(void) +{ + dk_set_leds_state(DK_ALL_LEDS_MSK, DK_NO_LEDS_MSK); + + while (true) { + /* Spin for ever */ + k_sleep(K_MSEC(1000)); + } +} + + +void button_changed(uint32_t button_state, uint32_t has_changed) +{ + +} + +static void configure_gpio(void) +{ + int err; + + err = dk_buttons_init(button_changed); + if (err) { + LOG_ERR("Cannot init buttons (err: %d)", err); + } + + err = dk_leds_init(); + if (err) { + LOG_ERR("Cannot init LEDs (err: %d)", err); + } +} + +int main(void) +{ + int err = 0; + + LOG_INF("Initializing"); + + + configure_gpio(); + + err = uart_init(); + if (err) { + error(); + } + + spi_init(); + + err = bt_conn_auth_cb_register(&conn_auth_callbacks); + if (err) { + printk("Failed to register authorization callbacks.\n"); + return 0; + } + + err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks); + if (err) { + printk("Failed to register authorization info callbacks.\n"); + return 0; + } + + err = bt_enable(NULL); + if (err) { + error(); + } + + LOG_INF("Bluetooth initialized"); + + k_sem_give(&ble_init_ok); + + if (IS_ENABLED(CONFIG_SETTINGS)) { + settings_load(); + } + + err = bt_nus_init(&nus_cb); + if (err) { + LOG_ERR("Failed to initialize UART service (err: %d)", err); + return 0; + } + + bt_set_name("TrezorGAP"); + + advertising_init(); + int_comm_start(); + pb_comm_start(); + dk_set_led(FW_RUNNING_SIG, 1); + send_status_event(); + + k_sem_give(&led_init_ok); + + for (;;) { + int_comm_thread(); + } +} + +void ble_write_thread(void) +{ + /* Don't go any further until BLE is initialized */ + k_sem_take(&ble_init_ok, K_FOREVER); + + for (;;) { + /* Wait indefinitely for data to be sent over bluetooth */ + uart_data_t *buf = uart_get_data_ext(); + + if (bt_nus_send(NULL, buf->data, buf->len)) { + LOG_WRN("Failed to send data over BLE connection"); + } + + k_free(buf); + } +} + +void led_thread(void) +{ + int blink_status = 0; + /* Don't go any further until BLE is initialized */ + k_sem_take(&led_init_ok, K_FOREVER); + + for (;;) { + dk_set_led(RUN_STATUS_LED, (++blink_status) % 2); + k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL)); + } +} + + +K_THREAD_DEFINE(ble_write_thread_id, STACKSIZE, ble_write_thread, NULL, NULL, + NULL, PRIORITY, 0, 0); + + +K_THREAD_DEFINE(led_thread_id, STACKSIZE, led_thread, NULL, NULL, + NULL, PRIORITY, 0, 0); diff --git a/core/embed/ble_zephyr_fw/src/pb_comm.c b/core/embed/ble_zephyr_fw/src/pb_comm.c new file mode 100644 index 000000000..75896b420 --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/pb_comm.c @@ -0,0 +1,390 @@ + +#include +#include + +#include + +#include "protob/protob_helpers.h" +#include "protob/messages.pb.h" + +#include "int_comm.h" +#include "int_comm_defs.h" +#include "uart.h" +#include "pb_comm.h" +#include "connection.h" + + + +typedef struct { + void *fifo_reserved; + uint8_t cmd; + uint8_t data[PB_BUF_SIZE]; + uint16_t len; +}pb_comm_data_t; + + +#define PASSKEY_LEN 6 + +static K_SEM_DEFINE(pb_comm_ok, 0, 1); +static K_SEM_DEFINE(pb_wait_for_ack, 0, 1); + + +static K_FIFO_DEFINE(fifo_pb_tx_in); // data to send to trezor +static K_FIFO_DEFINE(fifo_pb_tx_out); // data to send to host + + +void prepare_response_wait() { + k_sem_reset(&pb_wait_for_ack); +} + + + +bool write_resp(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) { + write_state *state = (write_state *)(stream->state); + + size_t written = 0; + // while we have data left + while (written < count) { + size_t remaining = count - written; + // if all remaining data fit into our packet + if (state->packet_pos + remaining <= USB_PACKET_SIZE) { + // append data from buf to state->buf + memcpy(state->buf + state->packet_pos, buf + written, remaining); + // advance position + state->packet_pos += remaining; + // and return + return true; + } else { + // append data that fits + memcpy(state->buf + state->packet_pos, buf + written, + USB_PACKET_SIZE - state->packet_pos); + written += USB_PACKET_SIZE - state->packet_pos; + + // send packet + uart_data_t * buf = k_malloc(sizeof(uart_data_t)); + buf->len = USB_DATA_SIZE; + memcpy(buf->data, state->buf, USB_DATA_SIZE); + uart_send_ext(buf); + + // prepare new packet + state->packet_index++; + memset(state->buf, 0, USB_PACKET_SIZE); + state->buf[0] = '?'; + state->packet_pos = MSG_HEADER2_LEN; + } + } + + return true; +}; + +void write_resp_flush(write_state *state) { + // if packet is not filled up completely + if (state->packet_pos < USB_PACKET_SIZE) { + // pad it with zeroes + memset(state->buf + state->packet_pos, 0, + USB_PACKET_SIZE - state->packet_pos); + } + // send packet + uart_data_t * buf = k_malloc(sizeof(uart_data_t)); + buf->len = USB_DATA_SIZE; + memcpy(buf->data, state->buf, USB_DATA_SIZE); + uart_send_ext(buf); +} + +bool write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) { + write_state *state = (write_state *)(stream->state); + + size_t written = 0; + // while we have data left + while (written < count) { + size_t remaining = count - written; + // if all remaining data fit into our packet + if (state->packet_pos + remaining <= USB_PACKET_SIZE) { + // append data from buf to state->buf + memcpy(state->buf + state->packet_pos, buf + written, remaining); + // advance position + state->packet_pos += remaining; + // and return + return true; + } else { + // append data that fits + memcpy(state->buf + state->packet_pos, buf + written, + USB_PACKET_SIZE - state->packet_pos); + written += USB_PACKET_SIZE - state->packet_pos; + + // send packet + send_packet(state->iface_num, state->buf, USB_PACKET_SIZE); + + // prepare new packet + state->packet_index++; + memset(state->buf, 0, USB_PACKET_SIZE); + state->buf[0] = '?'; + state->packet_pos = MSG_HEADER2_LEN; + } + } + + return true; +}; + +void write_flush(write_state *state) { + // if packet is not filled up completely + if (state->packet_pos < USB_PACKET_SIZE) { + // pad it with zeroes + memset(state->buf + state->packet_pos, 0, + USB_PACKET_SIZE - state->packet_pos); + } + // send packet + send_packet(state->iface_num, state->buf, USB_PACKET_SIZE); +} + +/* we don't use secbool/sectrue/secfalse here as it is a nanopb api */ +static bool read(pb_istream_t *stream, uint8_t *buf, size_t count) { + read_state *state = (read_state *)(stream->state); + + size_t read = 0; + // while we have data left + while (read < count) { + size_t remaining = count - read; + // if all remaining data fit into our packet + if (state->packet_pos + remaining <= state->packet_size) { + // append data from buf to state->buf + memcpy(buf + read, state->buf + state->packet_pos, remaining); + // advance position + state->packet_pos += remaining; + // and return + return true; + } else { + // append data that fits + memcpy(buf + read, state->buf + state->packet_pos, + state->packet_size - state->packet_pos); + read += state->packet_size - state->packet_pos; + + // read next packet + uart_data_t * data = uart_get_data_pb(); + if (data == NULL) { + return false; + } + memcpy(state->buf, data->data, USB_PACKET_SIZE > data->len ? data->len : USB_PACKET_SIZE); + k_free(data); + + // prepare next packet + state->packet_index++; + state->packet_pos = MSG_HEADER2_LEN; + } + } + + return true; +} + +static void read_flush(read_state *state) { (void)state; } + +#define MSG_SEND_NRF(msg) (MSG_SEND(msg, write, write_flush)) +#define MSG_SEND_NRF_RESPONSE(msg) (MSG_SEND(msg, write_resp, write_resp_flush)) + + + +secbool process_auth_key(uint8_t *data, uint32_t len, void *msg) { + recv_protob_msg(INTERNAL_MESSAGE, len, data, AuthKey_fields, msg, read, + read_flush, USB_PACKET_SIZE); + return sectrue; +} + +secbool process_success(uint8_t *data, uint32_t len, void *msg) { + recv_protob_msg(INTERNAL_MESSAGE, len, data, Success_fields, msg, read, + read_flush, USB_PACKET_SIZE); + return sectrue; +} + +void process_unexpected(uint8_t *data, uint32_t len) {} + + + +secbool await_response(uint16_t expected, + secbool (*process)(uint8_t *data, uint32_t len, + void *msg), + void *msg_recv) { + + if (k_sem_take(&pb_wait_for_ack, K_MSEC(100)) != 0) { + return secfalse; + } + + if ((dk_get_buttons() & DK_BTN2_MSK) == 0) { + return secfalse; + } + + uint16_t id = 0; + uint32_t msg_size = 0; + + uart_data_t * data = uart_get_data_pb(); + while (data == NULL) { + + if ((dk_get_buttons() & DK_BTN2_MSK) == 0) { + return secfalse; + } + + data = uart_get_data_pb(); + } + + msg_parse_header(data->data, &id, &msg_size); + + if (id == expected) { + if (process != NULL) { + return process(data->data, msg_size, msg_recv); + } + return sectrue; + } else { + process_unexpected(data->data, msg_size); + } + return secfalse; +} + + + +static bool read_authkey(pb_istream_t *stream, const pb_field_t *field, + void **arg) { + uint8_t *key_buffer = (uint8_t *)(*arg); + + if (stream->bytes_left > PASSKEY_LEN) { + return false; + } + + memset(key_buffer, 0, PASSKEY_LEN); + + while (stream->bytes_left) { + // read data + if (!pb_read(stream, (pb_byte_t *)(key_buffer), + (stream->bytes_left > PASSKEY_LEN) + ? PASSKEY_LEN + : stream->bytes_left)) { + return false; + } + } + + return true; +} + +static bool write_authkey(pb_ostream_t *stream, const pb_field_t *field, + void *const *arg) { + uint8_t *key = (uint8_t *)(*arg); + if (!pb_encode_tag_for_field(stream, field)) return false; + + return pb_encode_string(stream, (uint8_t *)key, PASSKEY_LEN); +} + +bool send_comparison_request(uint8_t *p_key, int8_t p_key_len) { + prepare_response_wait(); + uint8_t iface_num = INTERNAL_MESSAGE; + MSG_SEND_INIT(ComparisonRequest); + MSG_SEND_CALLBACK(key, write_authkey, p_key); + MSG_SEND_NRF(ComparisonRequest); + + MSG_RECV_INIT(Success); + secbool result = await_response(MessageType_MessageType_Success, + process_success, &msg_recv); + + if (result != sectrue) { + return false; + } + + return true; +} + +bool send_auth_key_request(uint8_t *p_key, uint8_t p_key_len) { + prepare_response_wait(); + uint8_t iface_num = INTERNAL_MESSAGE; + MSG_SEND_INIT(PairingRequest); + MSG_SEND_NRF(PairingRequest); + + uint8_t buffer[PASSKEY_LEN]; + MSG_RECV_INIT(AuthKey); + MSG_RECV_CALLBACK(key, read_authkey, buffer); + secbool result = await_response(MessageType_MessageType_AuthKey, + process_auth_key, &msg_recv); + + if (result != sectrue) { + return false; + } + + memcpy(p_key, buffer, + PASSKEY_LEN > p_key_len ? p_key_len : PASSKEY_LEN); + + return true; +} + +bool send_repair_request(void) { + prepare_response_wait(); + uint8_t iface_num = INTERNAL_MESSAGE; + MSG_SEND_INIT(RepairRequest); + MSG_SEND_NRF(RepairRequest); + + MSG_RECV_INIT(Success); + + secbool result = await_response(MessageType_MessageType_Success, + process_success, &msg_recv); + + return result == sectrue; +} + + +void send_error_response(void) { + // communication with trezor is disabled + uint8_t iface_num = 0; + + MSG_SEND_INIT(Failure); + MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError); + + msg_send.has_message = true; + memset(msg_send.message, 0, sizeof(msg_send.message)); + const char msg[] = "Device Locked or Busy"; + strncpy(msg_send.message, msg, sizeof(msg_send.message) - 1); + MSG_SEND_NRF_RESPONSE(Failure); + +} + + + +void pb_comm_start(void) +{ + k_sem_give(&pb_comm_ok); +} + +void pb_comm_enqueue(uint8_t cmd, uint8_t * data, uint16_t len) +{ + pb_comm_data_t * buf = k_malloc(sizeof(pb_comm_data_t)); + buf->cmd = cmd; + memcpy(buf->data, data, len); + buf->len = len; + k_fifo_put(&fifo_pb_tx_in, buf); +} + + +void pb_comm_thread(void) +{ + /* Don't go any further until BLE is initialized */ + k_sem_take(&pb_comm_ok, K_FOREVER); + + for (;;) { + /* Wait indefinitely for data to process */ + pb_comm_data_t * buf = k_fifo_get(&fifo_pb_tx_in, K_FOREVER); + + switch(buf->cmd) { + case COMPARISON_REQUEST: + if (send_comparison_request(buf->data, buf->len)) { + num_comp_reply(true); + } else { + num_comp_reply(false); + } + break; + } + + k_free(buf); + } +} + +void pb_msg_ack(void) { + k_sem_give(&pb_wait_for_ack); +} + + +K_THREAD_DEFINE(p_comm_thread_id, CONFIG_BT_NUS_THREAD_STACK_SIZE, pb_comm_thread, NULL, NULL, + NULL, 7, 0, 0); diff --git a/core/embed/ble_zephyr_fw/src/pb_comm.h b/core/embed/ble_zephyr_fw/src/pb_comm.h new file mode 100644 index 000000000..efb357310 --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/pb_comm.h @@ -0,0 +1,15 @@ + +#define PB_BUF_SIZE 64 + +typedef enum { + COMPARISON_REQUEST = 0, + AUTH_KEY_REQUEST = 1, + REPAIR_REQUEST = 2, + PASSKEY_DISPLAY = 3, +}pb_comm_cmd_t; + +void pb_comm_start(void); + +void pb_comm_enqueue(pb_comm_cmd_t cmd, uint8_t *data, uint16_t len); + +void send_error_response(void); diff --git a/core/embed/ble_zephyr_fw/src/protob/messages.pb.c b/core/embed/ble_zephyr_fw/src/protob/messages.pb.c new file mode 100644 index 000000000..6a7a8bba6 --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/protob/messages.pb.c @@ -0,0 +1,60 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.5 */ + +#include "messages.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(Initialize, Initialize, AUTO) + + +PB_BIND(GetFeatures, GetFeatures, AUTO) + + +PB_BIND(Features, Features, 2) + + +PB_BIND(Ping, Ping, 2) + + +PB_BIND(Success, Success, 2) + + +PB_BIND(Failure, Failure, 2) + + +PB_BIND(ButtonRequest, ButtonRequest, AUTO) + + +PB_BIND(ButtonAck, ButtonAck, AUTO) + + +PB_BIND(FirmwareErase, FirmwareErase, AUTO) + + +PB_BIND(FirmwareRequest, FirmwareRequest, AUTO) + + +PB_BIND(FirmwareUpload, FirmwareUpload, AUTO) + + +PB_BIND(UnlockBootloader, UnlockBootloader, AUTO) + + +PB_BIND(PairingRequest, PairingRequest, AUTO) + + +PB_BIND(AuthKey, AuthKey, AUTO) + + +PB_BIND(RepairRequest, RepairRequest, AUTO) + + +PB_BIND(ComparisonRequest, ComparisonRequest, AUTO) + + + + + + diff --git a/core/embed/ble_zephyr_fw/src/protob/messages.pb.h b/core/embed/ble_zephyr_fw/src/protob/messages.pb.h new file mode 100644 index 000000000..4666652b7 --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/protob/messages.pb.h @@ -0,0 +1,404 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.5 */ + +#ifndef PB_MESSAGES_PB_H_INCLUDED +#define PB_MESSAGES_PB_H_INCLUDED +#include + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Enum definitions */ +typedef enum _MessageType { + MessageType_MessageType_Initialize = 0, + MessageType_MessageType_Ping = 1, + MessageType_MessageType_Success = 2, + MessageType_MessageType_Failure = 3, + MessageType_MessageType_WipeDevice = 5, + MessageType_MessageType_FirmwareErase = 6, + MessageType_MessageType_FirmwareUpload = 7, + MessageType_MessageType_FirmwareRequest = 8, + MessageType_MessageType_Features = 17, + MessageType_MessageType_ButtonRequest = 26, + MessageType_MessageType_ButtonAck = 27, + MessageType_MessageType_GetFeatures = 55, + MessageType_MessageType_UnlockBootloader = 96, + MessageType_MessageType_PairingRequest = 8003, + MessageType_MessageType_AuthKey = 8004, + MessageType_MessageType_RepairRequest = 8005, + MessageType_MessageType_ComparisonRequest = 8008 +} MessageType; + +typedef enum _FailureType { + FailureType_Failure_UnexpectedMessage = 1, + FailureType_Failure_DataError = 3, + FailureType_Failure_ActionCancelled = 4, + FailureType_Failure_ProcessError = 9 +} FailureType; + +typedef enum _ButtonRequestType { + ButtonRequestType_ButtonRequest_Other = 1 +} ButtonRequestType; + +/* Struct definitions */ +typedef struct _AuthKey { + pb_callback_t key; +} AuthKey; + +typedef struct _ButtonAck { + char dummy_field; +} ButtonAck; + +typedef struct _ComparisonRequest { + pb_callback_t key; +} ComparisonRequest; + +typedef struct _GetFeatures { + char dummy_field; +} GetFeatures; + +typedef struct _Initialize { + char dummy_field; +} Initialize; + +typedef struct _PairingRequest { + char dummy_field; +} PairingRequest; + +typedef struct _RepairRequest { + char dummy_field; +} RepairRequest; + +typedef struct _UnlockBootloader { + char dummy_field; +} UnlockBootloader; + +typedef struct _ButtonRequest { + bool has_code; + ButtonRequestType code; +} ButtonRequest; + +typedef struct _Failure { + bool has_code; + FailureType code; + bool has_message; + char message[256]; +} Failure; + +typedef PB_BYTES_ARRAY_T(20) Features_revision_t; +typedef struct _Features { + bool has_vendor; + char vendor[33]; + uint32_t major_version; + uint32_t minor_version; + uint32_t patch_version; + bool has_bootloader_mode; + bool bootloader_mode; + bool has_device_id; + char device_id[25]; + bool has_language; + char language[17]; + bool has_label; + char label[33]; + bool has_initialized; + bool initialized; + bool has_revision; + Features_revision_t revision; + bool has_firmware_present; + bool firmware_present; + bool has_model; + char model[17]; + bool has_fw_major; + uint32_t fw_major; + bool has_fw_minor; + uint32_t fw_minor; + bool has_fw_patch; + uint32_t fw_patch; + bool has_fw_vendor; + char fw_vendor[256]; + bool has_internal_model; + char internal_model[17]; + bool has_unit_color; + uint32_t unit_color; + bool has_unit_btconly; + bool unit_btconly; + bool has_bootloader_locked; + bool bootloader_locked; +} Features; + +typedef struct _FirmwareErase { + bool has_length; + uint32_t length; +} FirmwareErase; + +typedef struct _FirmwareRequest { + uint32_t offset; + uint32_t length; +} FirmwareRequest; + +typedef PB_BYTES_ARRAY_T(32) FirmwareUpload_hash_t; +typedef struct _FirmwareUpload { + pb_callback_t payload; + bool has_hash; + FirmwareUpload_hash_t hash; +} FirmwareUpload; + +typedef struct _Ping { + bool has_message; + char message[256]; +} Ping; + +typedef struct _Success { + bool has_message; + char message[256]; +} Success; + + +/* Helper constants for enums */ +#define _MessageType_MIN MessageType_MessageType_Initialize +#define _MessageType_MAX MessageType_MessageType_ComparisonRequest +#define _MessageType_ARRAYSIZE ((MessageType)(MessageType_MessageType_ComparisonRequest+1)) + +#define _FailureType_MIN FailureType_Failure_UnexpectedMessage +#define _FailureType_MAX FailureType_Failure_ProcessError +#define _FailureType_ARRAYSIZE ((FailureType)(FailureType_Failure_ProcessError+1)) + +#define _ButtonRequestType_MIN ButtonRequestType_ButtonRequest_Other +#define _ButtonRequestType_MAX ButtonRequestType_ButtonRequest_Other +#define _ButtonRequestType_ARRAYSIZE ((ButtonRequestType)(ButtonRequestType_ButtonRequest_Other+1)) + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initializer values for message structs */ +#define Initialize_init_default {0} +#define GetFeatures_init_default {0} +#define Features_init_default {false, "", 0, 0, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, "", false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0, false, 0} +#define Ping_init_default {false, ""} +#define Success_init_default {false, ""} +#define Failure_init_default {false, _FailureType_MIN, false, ""} +#define ButtonRequest_init_default {false, _ButtonRequestType_MIN} +#define ButtonAck_init_default {0} +#define FirmwareErase_init_default {false, 0} +#define FirmwareRequest_init_default {0, 0} +#define FirmwareUpload_init_default {{{NULL}, NULL}, false, {0, {0}}} +#define UnlockBootloader_init_default {0} +#define PairingRequest_init_default {0} +#define AuthKey_init_default {{{NULL}, NULL}} +#define RepairRequest_init_default {0} +#define ComparisonRequest_init_default {{{NULL}, NULL}} +#define Initialize_init_zero {0} +#define GetFeatures_init_zero {0} +#define Features_init_zero {false, "", 0, 0, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, "", false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0, false, 0} +#define Ping_init_zero {false, ""} +#define Success_init_zero {false, ""} +#define Failure_init_zero {false, _FailureType_MIN, false, ""} +#define ButtonRequest_init_zero {false, _ButtonRequestType_MIN} +#define ButtonAck_init_zero {0} +#define FirmwareErase_init_zero {false, 0} +#define FirmwareRequest_init_zero {0, 0} +#define FirmwareUpload_init_zero {{{NULL}, NULL}, false, {0, {0}}} +#define UnlockBootloader_init_zero {0} +#define PairingRequest_init_zero {0} +#define AuthKey_init_zero {{{NULL}, NULL}} +#define RepairRequest_init_zero {0} +#define ComparisonRequest_init_zero {{{NULL}, NULL}} + +/* Field tags (for use in manual encoding/decoding) */ +#define AuthKey_key_tag 1 +#define ComparisonRequest_key_tag 1 +#define ButtonRequest_code_tag 1 +#define Failure_code_tag 1 +#define Failure_message_tag 2 +#define Features_vendor_tag 1 +#define Features_major_version_tag 2 +#define Features_minor_version_tag 3 +#define Features_patch_version_tag 4 +#define Features_bootloader_mode_tag 5 +#define Features_device_id_tag 6 +#define Features_language_tag 9 +#define Features_label_tag 10 +#define Features_initialized_tag 12 +#define Features_revision_tag 13 +#define Features_firmware_present_tag 18 +#define Features_model_tag 21 +#define Features_fw_major_tag 22 +#define Features_fw_minor_tag 23 +#define Features_fw_patch_tag 24 +#define Features_fw_vendor_tag 25 +#define Features_internal_model_tag 44 +#define Features_unit_color_tag 45 +#define Features_unit_btconly_tag 46 +#define Features_bootloader_locked_tag 49 +#define FirmwareErase_length_tag 1 +#define FirmwareRequest_offset_tag 1 +#define FirmwareRequest_length_tag 2 +#define FirmwareUpload_payload_tag 1 +#define FirmwareUpload_hash_tag 2 +#define Ping_message_tag 1 +#define Success_message_tag 1 + +/* Struct field encoding specification for nanopb */ +#define Initialize_FIELDLIST(X, a) \ + +#define Initialize_CALLBACK NULL +#define Initialize_DEFAULT NULL + +#define GetFeatures_FIELDLIST(X, a) \ + +#define GetFeatures_CALLBACK NULL +#define GetFeatures_DEFAULT NULL + +#define Features_FIELDLIST(X, a) \ +X(a, STATIC, OPTIONAL, STRING, vendor, 1) \ +X(a, STATIC, REQUIRED, UINT32, major_version, 2) \ +X(a, STATIC, REQUIRED, UINT32, minor_version, 3) \ +X(a, STATIC, REQUIRED, UINT32, patch_version, 4) \ +X(a, STATIC, OPTIONAL, BOOL, bootloader_mode, 5) \ +X(a, STATIC, OPTIONAL, STRING, device_id, 6) \ +X(a, STATIC, OPTIONAL, STRING, language, 9) \ +X(a, STATIC, OPTIONAL, STRING, label, 10) \ +X(a, STATIC, OPTIONAL, BOOL, initialized, 12) \ +X(a, STATIC, OPTIONAL, BYTES, revision, 13) \ +X(a, STATIC, OPTIONAL, BOOL, firmware_present, 18) \ +X(a, STATIC, OPTIONAL, STRING, model, 21) \ +X(a, STATIC, OPTIONAL, UINT32, fw_major, 22) \ +X(a, STATIC, OPTIONAL, UINT32, fw_minor, 23) \ +X(a, STATIC, OPTIONAL, UINT32, fw_patch, 24) \ +X(a, STATIC, OPTIONAL, STRING, fw_vendor, 25) \ +X(a, STATIC, OPTIONAL, STRING, internal_model, 44) \ +X(a, STATIC, OPTIONAL, UINT32, unit_color, 45) \ +X(a, STATIC, OPTIONAL, BOOL, unit_btconly, 46) \ +X(a, STATIC, OPTIONAL, BOOL, bootloader_locked, 49) +#define Features_CALLBACK NULL +#define Features_DEFAULT NULL + +#define Ping_FIELDLIST(X, a) \ +X(a, STATIC, OPTIONAL, STRING, message, 1) +#define Ping_CALLBACK NULL +#define Ping_DEFAULT (const pb_byte_t*)"\x0a\x00\x00" + +#define Success_FIELDLIST(X, a) \ +X(a, STATIC, OPTIONAL, STRING, message, 1) +#define Success_CALLBACK NULL +#define Success_DEFAULT (const pb_byte_t*)"\x0a\x00\x00" + +#define Failure_FIELDLIST(X, a) \ +X(a, STATIC, OPTIONAL, UENUM, code, 1) \ +X(a, STATIC, OPTIONAL, STRING, message, 2) +#define Failure_CALLBACK NULL +#define Failure_DEFAULT (const pb_byte_t*)"\x08\x01\x00" + +#define ButtonRequest_FIELDLIST(X, a) \ +X(a, STATIC, OPTIONAL, UENUM, code, 1) +#define ButtonRequest_CALLBACK NULL +#define ButtonRequest_DEFAULT (const pb_byte_t*)"\x08\x01\x00" + +#define ButtonAck_FIELDLIST(X, a) \ + +#define ButtonAck_CALLBACK NULL +#define ButtonAck_DEFAULT NULL + +#define FirmwareErase_FIELDLIST(X, a) \ +X(a, STATIC, OPTIONAL, UINT32, length, 1) +#define FirmwareErase_CALLBACK NULL +#define FirmwareErase_DEFAULT NULL + +#define FirmwareRequest_FIELDLIST(X, a) \ +X(a, STATIC, REQUIRED, UINT32, offset, 1) \ +X(a, STATIC, REQUIRED, UINT32, length, 2) +#define FirmwareRequest_CALLBACK NULL +#define FirmwareRequest_DEFAULT NULL + +#define FirmwareUpload_FIELDLIST(X, a) \ +X(a, CALLBACK, REQUIRED, BYTES, payload, 1) \ +X(a, STATIC, OPTIONAL, BYTES, hash, 2) +#define FirmwareUpload_CALLBACK pb_default_field_callback +#define FirmwareUpload_DEFAULT NULL + +#define UnlockBootloader_FIELDLIST(X, a) \ + +#define UnlockBootloader_CALLBACK NULL +#define UnlockBootloader_DEFAULT NULL + +#define PairingRequest_FIELDLIST(X, a) \ + +#define PairingRequest_CALLBACK NULL +#define PairingRequest_DEFAULT NULL + +#define AuthKey_FIELDLIST(X, a) \ +X(a, CALLBACK, REQUIRED, BYTES, key, 1) +#define AuthKey_CALLBACK pb_default_field_callback +#define AuthKey_DEFAULT NULL + +#define RepairRequest_FIELDLIST(X, a) \ + +#define RepairRequest_CALLBACK NULL +#define RepairRequest_DEFAULT NULL + +#define ComparisonRequest_FIELDLIST(X, a) \ +X(a, CALLBACK, REQUIRED, BYTES, key, 1) +#define ComparisonRequest_CALLBACK pb_default_field_callback +#define ComparisonRequest_DEFAULT NULL + +extern const pb_msgdesc_t Initialize_msg; +extern const pb_msgdesc_t GetFeatures_msg; +extern const pb_msgdesc_t Features_msg; +extern const pb_msgdesc_t Ping_msg; +extern const pb_msgdesc_t Success_msg; +extern const pb_msgdesc_t Failure_msg; +extern const pb_msgdesc_t ButtonRequest_msg; +extern const pb_msgdesc_t ButtonAck_msg; +extern const pb_msgdesc_t FirmwareErase_msg; +extern const pb_msgdesc_t FirmwareRequest_msg; +extern const pb_msgdesc_t FirmwareUpload_msg; +extern const pb_msgdesc_t UnlockBootloader_msg; +extern const pb_msgdesc_t PairingRequest_msg; +extern const pb_msgdesc_t AuthKey_msg; +extern const pb_msgdesc_t RepairRequest_msg; +extern const pb_msgdesc_t ComparisonRequest_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define Initialize_fields &Initialize_msg +#define GetFeatures_fields &GetFeatures_msg +#define Features_fields &Features_msg +#define Ping_fields &Ping_msg +#define Success_fields &Success_msg +#define Failure_fields &Failure_msg +#define ButtonRequest_fields &ButtonRequest_msg +#define ButtonAck_fields &ButtonAck_msg +#define FirmwareErase_fields &FirmwareErase_msg +#define FirmwareRequest_fields &FirmwareRequest_msg +#define FirmwareUpload_fields &FirmwareUpload_msg +#define UnlockBootloader_fields &UnlockBootloader_msg +#define PairingRequest_fields &PairingRequest_msg +#define AuthKey_fields &AuthKey_msg +#define RepairRequest_fields &RepairRequest_msg +#define ComparisonRequest_fields &ComparisonRequest_msg + +/* Maximum encoded size of messages (where known) */ +/* FirmwareUpload_size depends on runtime parameters */ +/* AuthKey_size depends on runtime parameters */ +/* ComparisonRequest_size depends on runtime parameters */ +#define ButtonAck_size 0 +#define ButtonRequest_size 2 +#define Failure_size 260 +#define Features_size 490 +#define FirmwareErase_size 6 +#define FirmwareRequest_size 12 +#define GetFeatures_size 0 +#define Initialize_size 0 +#define PairingRequest_size 0 +#define Ping_size 258 +#define RepairRequest_size 0 +#define Success_size 258 +#define UnlockBootloader_size 0 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/core/embed/ble_zephyr_fw/src/protob/protob_helpers.c b/core/embed/ble_zephyr_fw/src/protob/protob_helpers.c new file mode 100644 index 000000000..c4734bbf9 --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/protob/protob_helpers.c @@ -0,0 +1,87 @@ + + +#include "protob_helpers.h" + +secbool send_protob_msg(uint8_t iface_num, uint16_t msg_id, + const pb_msgdesc_t *fields, const void *msg, + bool (*write)(pb_ostream_t *stream, + const pb_byte_t *buf, size_t count), + void (*write_flush)(write_state *state)) { + // determine message size by serializing it into a dummy stream + pb_ostream_t sizestream = {.callback = NULL, + .state = NULL, + .max_size = SIZE_MAX, + .bytes_written = 0, + .errmsg = NULL}; + if (false == pb_encode(&sizestream, fields, msg)) { + return secfalse; + } + const uint32_t msg_size = sizestream.bytes_written; + + write_state state = { + .iface_num = iface_num, + .packet_index = 0, + .packet_pos = MSG_HEADER1_LEN, + .buf = + { + '?', + '#', + '#', + (msg_id >> 8) & 0xFF, + msg_id & 0xFF, + (msg_size >> 24) & 0xFF, + (msg_size >> 16) & 0xFF, + (msg_size >> 8) & 0xFF, + msg_size & 0xFF, + }, + }; + + pb_ostream_t stream = {.callback = write, + .state = &state, + .max_size = SIZE_MAX, + .bytes_written = 0, + .errmsg = NULL}; + + if (false == pb_encode(&stream, fields, msg)) { + return secfalse; + } + + write_flush(&state); + return secfalse; +} + +secbool recv_protob_msg(uint8_t iface_num, uint32_t msg_size, uint8_t *buf, + const pb_msgdesc_t *fields, void *msg, + bool (*read)(pb_istream_t *stream, pb_byte_t *buf, + size_t count), + void (*read_flush)(read_state *state), + uint16_t packet_size) { + read_state state = {.iface_num = iface_num, + .packet_index = 0, + .packet_pos = MSG_HEADER1_LEN, + .packet_size = packet_size, + .buf = buf}; + + pb_istream_t stream = {.callback = read, + .state = &state, + .bytes_left = msg_size, + .errmsg = NULL}; + + if (false == pb_decode_noinit(&stream, fields, msg)) { + return secfalse; + } + + read_flush(&state); + + return sectrue; +} + +secbool msg_parse_header(const uint8_t *buf, uint16_t *msg_id, + uint32_t *msg_size) { + if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { + return secfalse; + } + *msg_id = (buf[3] << 8) + buf[4]; + *msg_size = (buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8]; + return sectrue; +} diff --git a/core/embed/ble_zephyr_fw/src/protob/protob_helpers.h b/core/embed/ble_zephyr_fw/src/protob/protob_helpers.h new file mode 100644 index 000000000..b960212f3 --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/protob/protob_helpers.h @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include "secbool.h" + +#define USB_PACKET_SIZE 64 +#define MSG_HEADER1_LEN 9 +#define MSG_HEADER2_LEN 1 + +#define MSG_SEND_INIT(TYPE) TYPE msg_send = TYPE##_init_default +#define MSG_SEND_ASSIGN_REQUIRED_VALUE(FIELD, VALUE) \ + { msg_send.FIELD = VALUE; } +#define MSG_SEND_ASSIGN_VALUE(FIELD, VALUE) \ + { \ + msg_send.has_##FIELD = true; \ + msg_send.FIELD = VALUE; \ + } +#define MSG_SEND_ASSIGN_STRING(FIELD, VALUE) \ + { \ + msg_send.has_##FIELD = true; \ + memzero(msg_send.FIELD, sizeof(msg_send.FIELD)); \ + strncpy(msg_send.FIELD, VALUE, sizeof(msg_send.FIELD) - 1); \ + } +#define MSG_SEND_ASSIGN_STRING_LEN(FIELD, VALUE, LEN) \ + { \ + msg_send.has_##FIELD = true; \ + memzero(msg_send.FIELD, sizeof(msg_send.FIELD)); \ + strncpy(msg_send.FIELD, VALUE, MIN(LEN, sizeof(msg_send.FIELD) - 1)); \ + } +#define MSG_SEND_ASSIGN_BYTES(FIELD, VALUE, LEN) \ + { \ + msg_send.has_##FIELD = true; \ + memzero(msg_send.FIELD.bytes, sizeof(msg_send.FIELD.bytes)); \ + memcpy(msg_send.FIELD.bytes, VALUE, \ + MIN(LEN, sizeof(msg_send.FIELD.bytes))); \ + msg_send.FIELD.size = MIN(LEN, sizeof(msg_send.FIELD.bytes)); \ + } +#define MSG_SEND_CALLBACK(FIELD, CALLBACK, ARGUMENT) \ + { \ + msg_send.FIELD.funcs.encode = &CALLBACK; \ + msg_send.FIELD.arg = (void *)ARGUMENT; \ + } +#define MSG_SEND(TYPE, WRITE, WRITE_FLUSH) \ + send_protob_msg(iface_num, MessageType_MessageType_##TYPE, TYPE##_fields, \ + &msg_send, WRITE, WRITE_FLUSH) + +#define MSG_RECV_INIT(TYPE) TYPE msg_recv = TYPE##_init_default +#define MSG_RECV_CALLBACK(FIELD, CALLBACK, ARGUMENT) \ + { \ + msg_recv.FIELD.funcs.decode = &CALLBACK; \ + msg_recv.FIELD.arg = (void *)ARGUMENT; \ + } +#define MSG_RECV(TYPE, READ, READ_FLUSH, PACKET_SIZE) \ + recv_protob_msg(iface_num, msg_size, buf, TYPE##_fields, &msg_recv, READ, \ + READ_FLUSH, PACKET_SIZE) + +typedef struct { + uint8_t iface_num; + uint8_t packet_index; + uint8_t packet_pos; + uint8_t buf[USB_PACKET_SIZE]; +} write_state; + +typedef struct { + uint8_t iface_num; + uint8_t packet_index; + uint8_t packet_pos; + uint16_t packet_size; + uint8_t *buf; +} read_state; + +secbool send_protob_msg(uint8_t iface_num, uint16_t msg_id, + const pb_msgdesc_t *fields, const void *msg, + bool (*write_fnc)(pb_ostream_t *stream, + const pb_byte_t *buf, size_t count), + void (*write_flush)(write_state *state)); + +secbool recv_protob_msg(uint8_t iface_num, uint32_t msg_size, uint8_t *buf, + const pb_msgdesc_t *fields, void *msg, + bool (*read)(pb_istream_t *stream, pb_byte_t *buf, + size_t count), + void (*read_flush)(read_state *state), + uint16_t packet_size); + +secbool msg_parse_header(const uint8_t *buf, uint16_t *msg_id, + uint32_t *msg_size); diff --git a/core/embed/ble_zephyr_fw/src/protob/secbool.h b/core/embed/ble_zephyr_fw/src/protob/secbool.h new file mode 100644 index 000000000..356c71593 --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/protob/secbool.h @@ -0,0 +1,33 @@ +/* + * 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 . + */ + +#ifndef TREZORHAL_SECBOOL_H +#define TREZORHAL_SECBOOL_H + +#include + +typedef uint32_t secbool; +#define sectrue 0xAAAAAAAAU +#define secfalse 0x00000000U + +#ifndef __wur +#define __wur __attribute__((warn_unused_result)) +#endif + +#endif diff --git a/core/embed/ble_zephyr_fw/src/spi.c b/core/embed/ble_zephyr_fw/src/spi.c new file mode 100644 index 000000000..ee069e95e --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/spi.c @@ -0,0 +1,108 @@ + +#include +#include + +#include + +#include + +#include +#include + +#include +#include + +#include "spi.h" + +#define MY_SPI_MASTER DT_NODELABEL(spi0) + +static K_SEM_DEFINE(spi_comm_ok, 0, 1); +static K_FIFO_DEFINE(fifo_spi_tx_data); + +typedef struct { + void *fifo_reserved; + uint8_t data[244]; + uint16_t len; +}spi_data_t; + + +const struct device *spi_dev; +static struct k_poll_signal spi_done_sig = K_POLL_SIGNAL_INITIALIZER(spi_done_sig); + +struct spi_cs_control spim_cs = { + .gpio = SPI_CS_GPIOS_DT_SPEC_GET(DT_NODELABEL(reg_my_spi_master)), + .delay = 0, +}; + +static const struct spi_config spi_cfg = { + .operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB, + .frequency = 8000000, + .slave = 0, + .cs = { + .gpio = SPI_CS_GPIOS_DT_SPEC_GET(DT_NODELABEL(reg_my_spi_master)), + .delay = 0, + }, +}; + +void spi_init(void) +{ + spi_dev = DEVICE_DT_GET(MY_SPI_MASTER); + if(!device_is_ready(spi_dev)) { + printk("SPI master device not ready!\n"); + } + if(!device_is_ready(spim_cs.gpio.port)){ + printk("SPI master chip select device not ready!\n"); + } + + k_sem_give(&spi_comm_ok); +} + + + +void spi_send(const uint8_t * data, uint32_t len) +{ + if (len != 244) { + // unexpected length + return; + } + + spi_data_t * tx = k_malloc(sizeof(*tx)); + + if (!tx) { + printk("Not able to allocate SPI send data buffer\n"); + return; + } + + tx->len = len; + memcpy(tx->data, data, len); + + k_fifo_put(&fifo_spi_tx_data, tx); +} + +void spi_thread(void) +{ + /* Don't go any further until BLE is initialized */ + k_sem_take(&spi_comm_ok, K_FOREVER); + + for (;;) { + /* Wait indefinitely for data to process */ + spi_data_t *buf = k_fifo_get(&fifo_spi_tx_data, K_FOREVER); + + const struct spi_buf tx_buf = { + .buf = buf->data, + .len = buf->len, + }; + + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = 1 + }; + + spi_transceive(spi_dev, &spi_cfg, &tx,NULL); + + k_free(buf); + } +} + +K_THREAD_DEFINE(spi_thread_id, CONFIG_BT_NUS_THREAD_STACK_SIZE, spi_thread, NULL, NULL, + NULL, 7, 0, 0); diff --git a/core/embed/ble_zephyr_fw/src/spi.h b/core/embed/ble_zephyr_fw/src/spi.h new file mode 100644 index 000000000..2d662e4a6 --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/spi.h @@ -0,0 +1,6 @@ + + +#include + +void spi_init(void); +void spi_send(const uint8_t * data, uint32_t len); diff --git a/core/embed/ble_zephyr_fw/src/trz_nus.c b/core/embed/ble_zephyr_fw/src/trz_nus.c new file mode 100644 index 000000000..ef028d914 --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/trz_nus.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include + +#include + +#include "trz_nus.h" + +LOG_MODULE_REGISTER(trznus); + +static struct bt_nus_cb nus_cb; + + +static void nus_ccc_cfg_changed(const struct bt_gatt_attr *attr, + uint16_t value) +{ + if (nus_cb.send_enabled) { + LOG_DBG("Notification has been turned %s", + value == BT_GATT_CCC_NOTIFY ? "on" : "off"); + nus_cb.send_enabled(value == BT_GATT_CCC_NOTIFY ? + BT_NUS_SEND_STATUS_ENABLED : BT_NUS_SEND_STATUS_DISABLED); + } +} + + +static ssize_t on_receive(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, + uint16_t len, + uint16_t offset, + uint8_t flags) +{ + LOG_DBG("Received data, handle %d, conn %p", + attr->handle, (void *)conn); + + if (nus_cb.received) { + nus_cb.received(conn, buf, len); + } + return len; +} + +static void on_sent(struct bt_conn *conn, void *user_data) +{ + ARG_UNUSED(user_data); + + LOG_DBG("Data send, conn %p", (void *)conn); + + if (nus_cb.sent) { + nus_cb.sent(conn); + } +} + +/* UART Service Declaration */ +BT_GATT_SERVICE_DEFINE(nus_svc, + BT_GATT_PRIMARY_SERVICE(BT_UUID_NUS_SERVICE), + BT_GATT_CHARACTERISTIC(BT_UUID_NUS_TX, BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT, NULL, NULL, NULL), + BT_GATT_CCC(nus_ccc_cfg_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_CHARACTERISTIC(BT_UUID_NUS_RX, BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, NULL, on_receive, NULL), +); + +int bt_nus_init(struct bt_nus_cb *callbacks) +{ + if (callbacks) { + nus_cb.received = callbacks->received; + nus_cb.sent = callbacks->sent; + } + + return 0; +} + +int bt_nus_send(struct bt_conn *conn, const uint8_t *data, uint16_t len) +{ + struct bt_gatt_notify_params params = {0}; + const struct bt_gatt_attr *attr = &nus_svc.attrs[2]; + + params.attr = attr; + params.data = data; + params.len = len; + params.func = on_sent; + + if (conn && bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) { + return bt_gatt_notify_cb(conn, ¶ms); + } else { + return -EINVAL; + } +} diff --git a/core/embed/ble_zephyr_fw/src/trz_nus.h b/core/embed/ble_zephyr_fw/src/trz_nus.h new file mode 100644 index 000000000..5284d7754 --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/trz_nus.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef BT_NUS_H_ +#define BT_NUS_H_ + +/** + * @file + * @defgroup bt_nus Nordic UART (NUS) GATT Service + * @{ + * @brief Nordic UART (NUS) GATT Service API. + */ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief UUID of the NUS Service. **/ +#define BT_UUID_NUS_VAL \ + BT_UUID_128_ENCODE(0x6e400001, 0xb5a3, 0xf393, 0xe0a9, 0xe50e24dcca9e) + +/** @brief UUID of the TX Characteristic. **/ +#define BT_UUID_NUS_TX_VAL \ + BT_UUID_128_ENCODE(0x6e400003, 0xb5a3, 0xf393, 0xe0a9, 0xe50e24dcca9e) + +/** @brief UUID of the RX Characteristic. **/ +#define BT_UUID_NUS_RX_VAL \ + BT_UUID_128_ENCODE(0x6e400002, 0xb5a3, 0xf393, 0xe0a9, 0xe50e24dcca9e) + +#define BT_UUID_NUS_SERVICE BT_UUID_DECLARE_128(BT_UUID_NUS_VAL) +#define BT_UUID_NUS_RX BT_UUID_DECLARE_128(BT_UUID_NUS_RX_VAL) +#define BT_UUID_NUS_TX BT_UUID_DECLARE_128(BT_UUID_NUS_TX_VAL) + +/** @brief NUS send status. */ +enum bt_nus_send_status { + /** Send notification enabled. */ + BT_NUS_SEND_STATUS_ENABLED, + /** Send notification disabled. */ + BT_NUS_SEND_STATUS_DISABLED, +}; + +/** @brief Pointers to the callback functions for service events. */ +struct bt_nus_cb { + /** @brief Data received callback. + * + * The data has been received as a write request on the NUS RX + * Characteristic. + * + * @param[in] conn Pointer to connection object that has received data. + * @param[in] data Received data. + * @param[in] len Length of received data. + */ + void (*received)(struct bt_conn *conn, + const uint8_t *const data, uint16_t len); + + /** @brief Data sent callback. + * + * The data has been sent as a notification and written on the NUS TX + * Characteristic. + * + * @param[in] conn Pointer to connection object, or NULL if sent to all + * connected peers. + */ + void (*sent)(struct bt_conn *conn); + + /** @brief Send state callback. + * + * Indicate the + * CCCD descriptor status of the NUS TX characteristic. + * + * @param[in] status Send notification status. + */ + void (*send_enabled)(enum bt_nus_send_status status); + +}; + +/**@brief Initialize the service. + * + * @details This function registers a GATT service with two characteristics, + * TX and RX. A remote device that is connected to this service + * can send data to the RX Characteristic. When the remote enables + * notifications, it is notified when data is sent to the TX + * Characteristic. + * + * @param[in] callbacks Struct with function pointers to callbacks for service + * events. If no callbacks are needed, this parameter can + * be NULL. + * + * @retval 0 If initialization is successful. + * Otherwise, a negative value is returned. + */ +int bt_nus_init(struct bt_nus_cb *callbacks); + +/**@brief Send data. + * + * @details This function sends data to a connected peer, or all connected + * peers. + * + * @param[in] conn Pointer to connection object, or NULL to send to all + * connected peers. + * @param[in] data Pointer to a data buffer. + * @param[in] len Length of the data in the buffer. + * + * @retval 0 If the data is sent. + * Otherwise, a negative value is returned. + */ +int bt_nus_send(struct bt_conn *conn, const uint8_t *data, uint16_t len); + +/**@brief Get maximum data length that can be used for @ref bt_nus_send. + * + * @param[in] conn Pointer to connection Object. + * + * @return Maximum data length. + */ +static inline uint32_t bt_nus_get_mtu(struct bt_conn *conn) +{ + /* According to 3.4.7.1 Handle Value Notification off the ATT protocol. + * Maximum supported notification is ATT_MTU - 3 */ + return bt_gatt_get_mtu(conn) - 3; +} + +#ifdef __cplusplus +} +#endif + +/** + *@} + */ + +#endif /* BT_NUS_H_ */ diff --git a/core/embed/ble_zephyr_fw/src/uart.c b/core/embed/ble_zephyr_fw/src/uart.c new file mode 100644 index 000000000..2dcdb5c43 --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/uart.c @@ -0,0 +1,309 @@ +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include "uart.h" +#include "int_comm.h" +#include "int_comm_defs.h" + +#define LOG_MODULE_NAME fw_uart +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#define UART_WAIT_FOR_BUF_DELAY K_MSEC(50) +#define UART_WAIT_FOR_RX CONFIG_BT_NUS_UART_RX_WAIT_TIME + +static const struct device *uart = DEVICE_DT_GET(DT_CHOSEN(nordic_nus_uart)); + +static K_FIFO_DEFINE(fifo_uart_tx_data); +static K_FIFO_DEFINE(fifo_uart_rx_data); +static K_FIFO_DEFINE(fifo_uart_rx_data_int); +static K_FIFO_DEFINE(fifo_uart_rx_data_pb); + + +static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data) +{ + ARG_UNUSED(dev); + + static size_t aborted_len; + uart_data_t *buf; + static uint8_t *aborted_buf; + static bool disable_req; + static uint8_t rx_phase = 0; + static uint8_t rx_msg_type = 0; + static uint8_t rx_data_len = 0; + static uint8_t rx_len = 0; + + switch (evt->type) { + case UART_TX_DONE: + LOG_DBG("UART_TX_DONE"); + if ((evt->data.tx.len == 0) || + (!evt->data.tx.buf)) { + return; + } + + if (aborted_buf) { + buf = CONTAINER_OF(aborted_buf, uart_data_t, + data); + aborted_buf = NULL; + aborted_len = 0; + } else { + buf = CONTAINER_OF(evt->data.tx.buf, uart_data_t, + data); + } + + k_free(buf); + + buf = k_fifo_get(&fifo_uart_tx_data, K_NO_WAIT); + if (!buf) { + return; + } + + if (uart_tx(uart, buf->data, buf->len, SYS_FOREVER_MS)) { + LOG_WRN("Failed to send data over UART"); + } + + break; + + case UART_RX_RDY: + LOG_DBG("UART_RX_RDY"); + buf = CONTAINER_OF(evt->data.rx.buf, uart_data_t, data); + buf->len += evt->data.rx.len; + + switch(rx_phase) { + case 0: + if (buf->len == 1 && (buf->data[0] == INTERNAL_EVENT || buf->data[0] == INTERNAL_MESSAGE || buf->data[0] == EXTERNAL_MESSAGE) ) { + rx_phase = 1; + rx_msg_type = buf->data[0]; + } else { + rx_phase = 0; + } + break; + case 1: + if (buf->len == 2) { + rx_data_len = buf->data[0] << 8 | buf->data[1]; + rx_phase = 2; + } else{ + rx_phase = 0; + } + break; + case 2: + if (buf->len == rx_data_len - 3) { + rx_phase = 3; + } else { + rx_phase = 0; + } + break; + } + +// if (disable_req) { +// return; +// } + +// if ((evt->data.rx.buf[buf->len - 1] == '\n') || +// (evt->data.rx.buf[buf->len - 1] == '\r')) { +// disable_req = true; +// uart_rx_disable(uart); +// } + + break; + + case UART_RX_DISABLED: + LOG_DBG("UART_RX_DISABLED"); + disable_req = false; + + buf = k_malloc(sizeof(*buf)); + + if (buf) { + + switch (rx_phase) { + case 0: + rx_len = 1; + break; + case 1: + rx_len = 2; + break; + case 2: + rx_len = rx_data_len - 3; + break; + + default: + rx_len = 1; + break; + } + + buf->len = 0; + uart_rx_enable(uart, buf->data, rx_len, SYS_FOREVER_US); + } else { + LOG_WRN("Not able to allocate UART receive buffer"); + } + +// buf = k_malloc(sizeof(*buf)); +// if (buf) { +// buf->len = 0; +// } else { +// LOG_WRN("Not able to allocate UART receive buffer"); +// k_work_reschedule(&uart_work, UART_WAIT_FOR_BUF_DELAY); +// return; +// } +// +// uart_rx_enable(uart, buf->data, sizeof(buf->data), +// UART_WAIT_FOR_RX); + + break; + +// case UART_RX_BUF_REQUEST: +// LOG_INF("UART_RX_BUF_REQUEST"); +// buf = k_malloc(sizeof(*buf)); +// +// +// if (buf) { +// +// switch (rx_phase) { +// case 0: +// rx_len = 1; +// break; +// case 1: +// rx_len = 2; +// break; +// default: +// rx_len = 1; +// break; +// } +// +// buf->len = 0; +// LOG_INF("Providing buf %d", rx_len); +// uart_rx_buf_rsp(uart, buf->data, rx_len); +// } else { +// LOG_WRN("Not able to allocate UART receive buffer"); +// } +// +// break; + + case UART_RX_BUF_RELEASED: + LOG_DBG("UART_RX_BUF_RELEASED"); + buf = CONTAINER_OF(evt->data.rx_buf.buf, uart_data_t, + data); + + if (rx_phase == 3 && buf->len > 0) { + buf->len -= 1; + if (rx_msg_type == EXTERNAL_MESSAGE) { + k_fifo_put(&fifo_uart_rx_data, buf); + } + else if (rx_msg_type == INTERNAL_EVENT) { + k_fifo_put(&fifo_uart_rx_data_int, buf); + } + else { + k_fifo_put(&fifo_uart_rx_data_pb, buf); + } + rx_data_len= 0; + rx_len = 0; + rx_msg_type = 0; + rx_phase = 0; + } else { + k_free(buf); + } + break; + + case UART_TX_ABORTED: + LOG_DBG("UART_TX_ABORTED"); + if (!aborted_buf) { + aborted_buf = (uint8_t *)evt->data.tx.buf; + } + + aborted_len += evt->data.tx.len; + buf = CONTAINER_OF(aborted_buf, uart_data_t, + data); + + uart_tx(uart, &buf->data[aborted_len], + buf->len - aborted_len, SYS_FOREVER_MS); + + break; + + default: + break; + } +} + + +int uart_init(void) +{ + int err; + uart_data_t *rx; + + if (!device_is_ready(uart)) { + return -ENODEV; + } + + struct uart_config cfg = { + .baudrate = 1000000, + .parity = UART_CFG_PARITY_NONE, + .stop_bits = UART_CFG_STOP_BITS_1, + .data_bits = UART_CFG_DATA_BITS_8, + .flow_ctrl = UART_CFG_FLOW_CTRL_RTS_CTS, + + }; + + uart_configure(uart, &cfg); + + rx = k_malloc(sizeof(*rx)); + if (rx) { + rx->len = 0; + } else { + return -ENOMEM; + } + + err = uart_callback_set(uart, uart_cb, NULL); + if (err) { + k_free(rx); + LOG_ERR("Cannot initialize UART callback"); + return err; + } + + // receive message type + err = uart_rx_enable(uart, rx->data, 1, SYS_FOREVER_US); + if (err) { + LOG_ERR("Cannot enable uart reception (err: %d)", err); + /* Free the rx buffer only because the tx buffer will be handled in the callback */ + k_free(rx); + } + + return err; +} + + +void uart_send_ext(uart_data_t *tx) +{ + k_fifo_put(&fifo_uart_rx_data, tx); +} + +uart_data_t *uart_get_data_ext(void) +{ + return k_fifo_get(&fifo_uart_rx_data, K_FOREVER); +} + +uart_data_t *uart_get_data_int(void) +{ + return k_fifo_get(&fifo_uart_rx_data_int, K_FOREVER); +} + +uart_data_t *uart_get_data_pb(void) +{ + return k_fifo_get(&fifo_uart_rx_data_pb, K_MSEC(100)); +} + +void uart_send(uart_data_t *tx) +{ + int err = uart_tx(uart, tx->data, tx->len, SYS_FOREVER_MS); + if (err) { + k_fifo_put(&fifo_uart_tx_data, tx); + } +} + diff --git a/core/embed/ble_zephyr_fw/src/uart.h b/core/embed/ble_zephyr_fw/src/uart.h new file mode 100644 index 000000000..8ab2878b2 --- /dev/null +++ b/core/embed/ble_zephyr_fw/src/uart.h @@ -0,0 +1,21 @@ +#ifndef UART_H +#define UART_H + +#define UART_BUF_SIZE 247 + +typedef struct { + void *fifo_reserved; + uint8_t data[UART_BUF_SIZE]; + uint16_t len; +}uart_data_t; + +int uart_init(void); + +uart_data_t * uart_get_data_ext(void); +uart_data_t * uart_get_data_int(void); +uart_data_t * uart_get_data_pb(void); + +void uart_send(uart_data_t *data); +void uart_send_ext(uart_data_t *tx); + +#endif