diff --git a/.gitignore b/.gitignore index a2e0a1518d..93ec1aa434 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,12 @@ __pycache__/ proto.gv* .DS_Store crypto/tests/libtrezor-crypto.so.dSYM/ +/west/.west/ +/west/bootloader/ +/west/modules/ +/west/nrf/ +/west/nrfxlib/ +/west/test/ +/west/tools/ +/west/zephyr/ +/west/trezor/build/ diff --git a/.pylintrc b/.pylintrc index cefee09d88..145f3d1177 100644 --- a/.pylintrc +++ b/.pylintrc @@ -8,6 +8,7 @@ ignore-paths= crypto, legacy, storage, + west, fail-under=10.0 jobs=0 load-plugins=trezor_pylint_plugin diff --git a/.yamllint.yml b/.yamllint.yml index db57aa9911..ef13be9ba3 100644 --- a/.yamllint.yml +++ b/.yamllint.yml @@ -5,6 +5,7 @@ ignore: | vendor/ /common/defs/ethereum/chains/ /common/defs/ethereum/tokens/ + /west/ rules: # fix for truthy warning on github action files diff --git a/tools/style.c.include b/tools/style.c.include index 276419c797..553e574026 100644 --- a/tools/style.c.include +++ b/tools/style.c.include @@ -3,3 +3,4 @@ ^\./crypto/ ^\./legacy/ ^\./storage/ +^\./west/workspace/ diff --git a/west/trezor/CMakeLists.txt b/west/trezor/CMakeLists.txt new file mode 100644 index 0000000000..81d178a5d8 --- /dev/null +++ b/west/trezor/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2021 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 +# +# This CMake file is picked by the Zephyr build system because it is defined +# as the module CMake entry point (see zephyr/module.yml). + + +zephyr_include_directories(include) + diff --git a/west/trezor/Kconfig b/west/trezor/Kconfig new file mode 100644 index 0000000000..eb60fc6a61 --- /dev/null +++ b/west/trezor/Kconfig @@ -0,0 +1,7 @@ +# Copyright (c) 2021 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 +# +# This Kconfig file is picked by the Zephyr build system because it is defined +# as the module Kconfig entry point (see zephyr/module.yml). You can browse +# module options by going to Zephyr -> Modules in Kconfig. + diff --git a/west/trezor/README.md b/west/trezor/README.md new file mode 100644 index 0000000000..76a691f0f1 --- /dev/null +++ b/west/trezor/README.md @@ -0,0 +1,72 @@ +# Trezor BLE Gateway + +Welcome to the **Trezor BLE Gateway** project! +This repository contains the source code and instructions to build and flash the application onto the `t3w1_nrf52833` board. + +## Table of Contents + +- [Prerequisites](#prerequisites) +- [Getting Started](#getting-started) + - [Install the toolchain](#install-the-toolchain) + - [Launch the nRF Shell](#launch-the-nrf-shell) + - [Initialize the Workspace](#initialize-the-workspace) + - [Update nRF Connect SDK Modules](#update-nrf-connect-sdk-modules) + - [Build the Application](#build-the-application) + - [Flash the Application](#flash-the-application) +- [Contributing](#contributing) +- [License](#license) + +## Prerequisites + +Before you begin, ensure you have met the following requirements: + +- **nrfutil**: Install [nrfutil](https://docs.nordicsemi.com/bundle/nrfutil/page/README.html). This tool is essential for managing the nRF Connect SDK and toolchains. +- **Git**: Ensure you have Git installed for cloning repositories. + +## Getting Started + +Follow these steps to set up the project on your local machine. + +### Install the toolchain + +Using nrfutil, install the required toolchain for the nRF Connect SDK: +```sh +nrfutil toolchain-manager install --ncs-version v2.6.2 +``` + +### Launch the nRF Shell + +First, launch the nRF shell using the `nrfutil` toolchain manager: + +```sh +nrfutil toolchain-manager launch --shell +``` + +### Initialize the Workspace +Initialize your West workspace for the Trezor BLE Gateway project: +```sh +cd west +west init -l ./trezor +``` + +### Update nRF Connect SDK Modules + +Update the modules: +```sh +west update +``` + + +### Building the Application +Build the application for the t3w1_revA_nrf52832 board: +```sh +cd trezor +west build ./trezor-ble -b t3w1_revA_nrf52832 +``` + + +### Flashing the Application +Flash the compiled application onto the board: +```sh +west flash +``` diff --git a/west/trezor/boards/arm/t3w1_d1_nrf52833/Kconfig.defconfig b/west/trezor/boards/arm/t3w1_d1_nrf52833/Kconfig.defconfig new file mode 100644 index 0000000000..42815d4937 --- /dev/null +++ b/west/trezor/boards/arm/t3w1_d1_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_D1_NRF52833 + +config BOARD + default "t3w1_d1_nrf52833" + +config BT_CTLR + default BT + +endif # BOARD_T3W1_NRF52833 diff --git a/west/trezor/boards/arm/t3w1_d1_nrf52833/Kconfig.t3w1_d1_nrf52833 b/west/trezor/boards/arm/t3w1_d1_nrf52833/Kconfig.t3w1_d1_nrf52833 new file mode 100644 index 0000000000..804354c0a5 --- /dev/null +++ b/west/trezor/boards/arm/t3w1_d1_nrf52833/Kconfig.t3w1_d1_nrf52833 @@ -0,0 +1,7 @@ +# nRF52833 DK NRF52833 board configuration + +# Copyright (c) 2019 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_T3W1_D1_NRF52833 + select SOC_NRF52833_QIAA diff --git a/west/trezor/boards/arm/t3w1_d1_nrf52833/board.cmake b/west/trezor/boards/arm/t3w1_d1_nrf52833/board.cmake new file mode 100644 index 0000000000..f944da5778 --- /dev/null +++ b/west/trezor/boards/arm/t3w1_d1_nrf52833/board.cmake @@ -0,0 +1,12 @@ +# Copyright (c) 2021 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=nRF52833_xxAA" "--speed=4000") +board_runner_args(pyocd "--target=nrf52833" "--frequency=4000000") + +set(OPENOCD_NRF5_SUBFAMILY "nrf52") + +include(${ZEPHYR_BASE}/boards/common/nrfjprog.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/west/trezor/boards/arm/t3w1_d1_nrf52833/board.yml b/west/trezor/boards/arm/t3w1_d1_nrf52833/board.yml new file mode 100644 index 0000000000..6c9ee5b00f --- /dev/null +++ b/west/trezor/boards/arm/t3w1_d1_nrf52833/board.yml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +board: + name: t3w1_d1_nrf52833 + vendor: vendor + socs: + - name: nrf52833 diff --git a/west/trezor/boards/arm/t3w1_d1_nrf52833/pre_dt_board.cmake b/west/trezor/boards/arm/t3w1_d1_nrf52833/pre_dt_board.cmake new file mode 100644 index 0000000000..ded6fc3f7e --- /dev/null +++ b/west/trezor/boards/arm/t3w1_d1_nrf52833/pre_dt_board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2024 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/west/trezor/boards/arm/t3w1_d1_nrf52833/t3w1_d1_nrf52833-pinctrl.dtsi b/west/trezor/boards/arm/t3w1_d1_nrf52833/t3w1_d1_nrf52833-pinctrl.dtsi new file mode 100644 index 0000000000..3edaaf41f6 --- /dev/null +++ b/west/trezor/boards/arm/t3w1_d1_nrf52833/t3w1_d1_nrf52833-pinctrl.dtsi @@ -0,0 +1,47 @@ +/* + * 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/west/trezor/boards/arm/t3w1_d1_nrf52833/t3w1_d1_nrf52833.dts b/west/trezor/boards/arm/t3w1_d1_nrf52833/t3w1_d1_nrf52833.dts new file mode 100644 index 0000000000..4c597fa628 --- /dev/null +++ b/west/trezor/boards/arm/t3w1_d1_nrf52833/t3w1_d1_nrf52833.dts @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "t3w1_d1_nrf52833-pinctrl.dtsi" +#include + +/ { + model = "T3W1 D1 NRF52833"; + compatible = "nordic,t3w1_d1_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 = <1000000>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; +}; + +&spi0 { + compatible = "nordic,nrf-spim"; + status = "okay"; + pinctrl-0 = <&spi0_default>; + pinctrl-1 = <&spi0_sleep>; + pinctrl-names = "default", "sleep"; + cs-gpios = <&gpio0 23 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/west/trezor/boards/arm/t3w1_d1_nrf52833/t3w1_d1_nrf52833.yaml b/west/trezor/boards/arm/t3w1_d1_nrf52833/t3w1_d1_nrf52833.yaml new file mode 100644 index 0000000000..03ae424abd --- /dev/null +++ b/west/trezor/boards/arm/t3w1_d1_nrf52833/t3w1_d1_nrf52833.yaml @@ -0,0 +1,16 @@ +identifier: t3w1_d1_nrf52833 +name: tw31-d1-NRF52833 +type: mcu +arch: arm +ram: 128 +flash: 512 +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - usb_device + - ble + - gpio + - watchdog + - counter diff --git a/west/trezor/boards/arm/t3w1_d1_nrf52833/t3w1_d1_nrf52833_defconfig b/west/trezor/boards/arm/t3w1_d1_nrf52833/t3w1_d1_nrf52833_defconfig new file mode 100644 index 0000000000..9383353073 --- /dev/null +++ b/west/trezor/boards/arm/t3w1_d1_nrf52833/t3w1_d1_nrf52833_defconfig @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Apache-2.0 + +# 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/west/trezor/boards/arm/t3w1_revA_nrf52832/Kconfig.defconfig b/west/trezor/boards/arm/t3w1_revA_nrf52832/Kconfig.defconfig new file mode 100644 index 0000000000..d9c7264ff0 --- /dev/null +++ b/west/trezor/boards/arm/t3w1_revA_nrf52832/Kconfig.defconfig @@ -0,0 +1,14 @@ +# T3W1 REVA NRF52833 board configuration + +# Copyright (c) 2019 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_T3W1_REVA_NRF52832 + +config BOARD + default "t3w1_revA_nrf52832" + +config BT_CTLR + default BT + +endif # BOARD_T3W1_REVA_NRF52832 diff --git a/west/trezor/boards/arm/t3w1_revA_nrf52832/Kconfig.t3w1_revA_nrf52832 b/west/trezor/boards/arm/t3w1_revA_nrf52832/Kconfig.t3w1_revA_nrf52832 new file mode 100644 index 0000000000..ce372e45ac --- /dev/null +++ b/west/trezor/boards/arm/t3w1_revA_nrf52832/Kconfig.t3w1_revA_nrf52832 @@ -0,0 +1,7 @@ +# T3W1 REVA NRF52832 board configuration + +# Copyright (c) 2019 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_T3W1_REVA_NRF52832 + select SOC_NRF52832_CIAA diff --git a/west/trezor/boards/arm/t3w1_revA_nrf52832/board.cmake b/west/trezor/boards/arm/t3w1_revA_nrf52832/board.cmake new file mode 100644 index 0000000000..e9ebf8b758 --- /dev/null +++ b/west/trezor/boards/arm/t3w1_revA_nrf52832/board.cmake @@ -0,0 +1,12 @@ +# Copyright (c) 2021 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=nRF52832_xxAA" "--speed=4000") +board_runner_args(pyocd "--target=nrf52832" "--frequency=4000000") + +set(OPENOCD_NRF5_SUBFAMILY "nrf52") + +include(${ZEPHYR_BASE}/boards/common/nrfjprog.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/west/trezor/boards/arm/t3w1_revA_nrf52832/board.yml b/west/trezor/boards/arm/t3w1_revA_nrf52832/board.yml new file mode 100644 index 0000000000..d8f74ab895 --- /dev/null +++ b/west/trezor/boards/arm/t3w1_revA_nrf52832/board.yml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +board: + name: t3w1_revA_nrf52832 + vendor: vendor + socs: + - name: nrf52832 diff --git a/west/trezor/boards/arm/t3w1_revA_nrf52832/pre_dt_board.cmake b/west/trezor/boards/arm/t3w1_revA_nrf52832/pre_dt_board.cmake new file mode 100644 index 0000000000..ded6fc3f7e --- /dev/null +++ b/west/trezor/boards/arm/t3w1_revA_nrf52832/pre_dt_board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2024 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/west/trezor/boards/arm/t3w1_revA_nrf52832/t3w1_revA_nrf52832-pinctrl.dtsi b/west/trezor/boards/arm/t3w1_revA_nrf52832/t3w1_revA_nrf52832-pinctrl.dtsi new file mode 100644 index 0000000000..4191390621 --- /dev/null +++ b/west/trezor/boards/arm/t3w1_revA_nrf52832/t3w1_revA_nrf52832-pinctrl.dtsi @@ -0,0 +1,47 @@ +/* + * 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/west/trezor/boards/arm/t3w1_revA_nrf52832/t3w1_revA_nrf52832.dts b/west/trezor/boards/arm/t3w1_revA_nrf52832/t3w1_revA_nrf52832.dts new file mode 100644 index 0000000000..0345e59760 --- /dev/null +++ b/west/trezor/boards/arm/t3w1_revA_nrf52832/t3w1_revA_nrf52832.dts @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "t3w1_revA_nrf52832-pinctrl.dtsi" +#include + +/ { + model = "T3W1 REVA NRF52832"; + compatible = "nordic,t3w1_revA_nrf52832"; + + 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; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + label = "Green LED 0"; + }; + led1: led_1 { + gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; + label = "Green LED 1"; + }; + out0: out_0 { + gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>; + label = "FW Running"; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0 27 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button switch 0"; + zephyr,code = ; + }; + trezor_ready: trezor_ready { + gpios = <&gpio0 29 (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; + nfct-pins-as-gpios; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&uart0 { + compatible = "nordic,nrf-uarte"; + status = "okay"; + current-speed = <1000000>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; +}; + +&spi0 { + compatible = "nordic,nrf-spim"; + status = "okay"; + pinctrl-0 = <&spi0_default>; + pinctrl-1 = <&spi0_sleep>; + pinctrl-names = "default", "sleep"; + cs-gpios = <&gpio0 0 GPIO_ACTIVE_LOW>; + reg_my_spi_master: spi-dev-a@0 { + reg = <0>; + }; +}; + +&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>; + }; + }; +}; diff --git a/west/trezor/boards/arm/t3w1_revA_nrf52832/t3w1_revA_nrf52832.yaml b/west/trezor/boards/arm/t3w1_revA_nrf52832/t3w1_revA_nrf52832.yaml new file mode 100644 index 0000000000..6ce3429fb7 --- /dev/null +++ b/west/trezor/boards/arm/t3w1_revA_nrf52832/t3w1_revA_nrf52832.yaml @@ -0,0 +1,15 @@ +identifier: t3w1_revA_nrf52832 +name: tw31-revA-NRF52832 +type: mcu +arch: arm +ram: 64 +flash: 512 +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - ble + - gpio + - watchdog + - counter diff --git a/west/trezor/boards/arm/t3w1_revA_nrf52832/t3w1_revA_nrf52832_defconfig b/west/trezor/boards/arm/t3w1_revA_nrf52832/t3w1_revA_nrf52832_defconfig new file mode 100644 index 0000000000..9383353073 --- /dev/null +++ b/west/trezor/boards/arm/t3w1_revA_nrf52832/t3w1_revA_nrf52832_defconfig @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Apache-2.0 + +# 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/west/trezor/dts/bindings/sensor/zephyr,example-sensor.yaml b/west/trezor/dts/bindings/sensor/zephyr,example-sensor.yaml new file mode 100644 index 0000000000..879fea9ccf --- /dev/null +++ b/west/trezor/dts/bindings/sensor/zephyr,example-sensor.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2021 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: | + An example sensor that reads the GPIO level defined in input-gpios. The + purpose of this sensor is to demonstrate how to create out-of-tree drivers. + + Example definition in devicetree: + + example-sensor { + compatible = "zephyr,example-sensor"; + input-gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + +compatible: "zephyr,example-sensor" + +include: base.yaml + +properties: + input-gpios: + type: phandle-array + required: true + description: Input GPIO to be sensed. diff --git a/west/trezor/scripts/example_west_command.py b/west/trezor/scripts/example_west_command.py new file mode 100644 index 0000000000..7f68d7f4eb --- /dev/null +++ b/west/trezor/scripts/example_west_command.py @@ -0,0 +1,49 @@ +# Copyright (c) 2019 Foundries.io +# Copyright (c) 2022 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +'''example_west_command.py + +Example of a west extension in the example-application repository.''' + +from west.commands import WestCommand # your extension must subclass this +from west import log # use this for user output + +class ExampleWestCommand(WestCommand): + + def __init__(self): + super().__init__( + 'example-west-command', # gets stored as self.name + 'an example west extension command', # self.help + # self.description: + '''\ +A multi-line description of example-west-command. + +You can split this up into multiple paragraphs and they'll get +reflowed for you. You can also pass +formatter_class=argparse.RawDescriptionHelpFormatter when calling +parser_adder.add_parser() below if you want to keep your line +endings.''') + + def do_add_parser(self, parser_adder): + # This is a bit of boilerplate, which allows you full control over the + # type of argparse handling you want. The "parser_adder" argument is + # the return value of an argparse.ArgumentParser.add_subparsers() call. + parser = parser_adder.add_parser(self.name, + help=self.help, + description=self.description) + + # Add some example options using the standard argparse module API. + parser.add_argument('-o', '--optional', help='an optional argument') + parser.add_argument('required', help='a required argument') + + return parser # gets stored as self.parser + + def do_run(self, args, unknown_args): + # This gets called when the user runs the command, e.g.: + # + # $ west my-command-name -o FOO BAR + # --optional is FOO + # required is BAR + log.inf('--optional is', args.optional) + log.inf('required is', args.required) diff --git a/west/trezor/scripts/west-commands.yml b/west/trezor/scripts/west-commands.yml new file mode 100644 index 0000000000..e32692a901 --- /dev/null +++ b/west/trezor/scripts/west-commands.yml @@ -0,0 +1,6 @@ +west-commands: + - file: scripts/example_west_command.py + commands: + - name: example-west-command + class: ExampleWestCommand + help: an example west extension command diff --git a/west/trezor/tests/lib/custom/CMakeLists.txt b/west/trezor/tests/lib/custom/CMakeLists.txt new file mode 100644 index 0000000000..3942740423 --- /dev/null +++ b/west/trezor/tests/lib/custom/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2021, Legrand North America, LLC. +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(app_lib_custom_test) + +target_sources(app PRIVATE src/main.c) diff --git a/west/trezor/tests/lib/custom/prj.conf b/west/trezor/tests/lib/custom/prj.conf new file mode 100644 index 0000000000..512194b109 --- /dev/null +++ b/west/trezor/tests/lib/custom/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_CUSTOM=y diff --git a/west/trezor/tests/lib/custom/src/main.c b/west/trezor/tests/lib/custom/src/main.c new file mode 100644 index 0000000000..c99c798fed --- /dev/null +++ b/west/trezor/tests/lib/custom/src/main.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 Legrand North America, LLC. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * @file test custom_lib library + * + * This suite verifies that the methods provided with the custom_lib + * library works correctly. + */ + +#include + +#include + +#include + +ZTEST(custom_lib, test_get_value) { + /* Verify standard behavior */ + zassert_equal(custom_get_value(INT_MIN), INT_MIN, + "get_value failed input of INT_MIN"); + zassert_equal(custom_get_value(INT_MIN + 1), INT_MIN + 1, + "get_value failed input of INT_MIN + 1"); + zassert_equal(custom_get_value(-1), -1, "get_value failed input of -1"); + zassert_equal(custom_get_value(1), 1, "get_value failed input of 1"); + zassert_equal(custom_get_value(INT_MAX - 1), INT_MAX - 1, + "get_value failed input of INT_MAX - 1"); + zassert_equal(custom_get_value(INT_MAX), INT_MAX, + "get_value failed input of INT_MAX"); + + /* Verify override behavior */ + zassert_equal(custom_get_value(0), CONFIG_CUSTOM_GET_VALUE_DEFAULT, + "get_value failed input of 0"); +} + +ZTEST_SUITE(custom_lib, NULL, NULL, NULL, NULL, NULL); diff --git a/west/trezor/tests/lib/custom/testcase.yaml b/west/trezor/tests/lib/custom/testcase.yaml new file mode 100644 index 0000000000..27f3d8d2c1 --- /dev/null +++ b/west/trezor/tests/lib/custom/testcase.yaml @@ -0,0 +1,9 @@ +common: + tags: extensibility + integration_platforms: + - custom_plank + - qemu_cortex_m0 +tests: + lib.custom: {} + lib.custom.non_default: + extra_args: CONFIG_CUSTOM_GET_VALUE_DEFAULT=6 diff --git a/west/trezor/trezor-ble/CMakeLists.txt b/west/trezor/trezor-ble/CMakeLists.txt new file mode 100644 index 0000000000..77927b7634 --- /dev/null +++ b/west/trezor/trezor-ble/CMakeLists.txt @@ -0,0 +1,26 @@ +# +# Copyright (c) 2018 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# +cmake_minimum_required(VERSION 3.20.0) + +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/events.c + src/uart.c + src/spi.c + src/int_comm.c + src/trz_nus.c +) + + +# NORDIC SDK APP END + +zephyr_library_include_directories(.) diff --git a/west/trezor/trezor-ble/Kconfig b/west/trezor/trezor-ble/Kconfig new file mode 100644 index 0000000000..200403dfdd --- /dev/null +++ b/west/trezor/trezor-ble/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/west/trezor/trezor-ble/VERSION b/west/trezor/trezor-ble/VERSION new file mode 100644 index 0000000000..16a13732e3 --- /dev/null +++ b/west/trezor/trezor-ble/VERSION @@ -0,0 +1,5 @@ +VERSION_MAJOR = 1 +VERSION_MINOR = 0 +PATCHLEVEL = 0 +VERSION_TWEAK = 0 +EXTRAVERSION = diff --git a/west/trezor/trezor-ble/app.yaml b/west/trezor/trezor-ble/app.yaml new file mode 100644 index 0000000000..118be2ca75 --- /dev/null +++ b/west/trezor/trezor-ble/app.yaml @@ -0,0 +1,16 @@ +# This file is provided so that the application can be compiled using Twister, +# the Zephyr testing tool. In this file, multiple combinations can be specified, +# so that you can easily test all of them locally or in CI. +sample: + description: Trezor BLE gateway + name: W001 +common: + sysbuild: true + build_only: true + integration_platforms: + - t3w1_d1_nrf52833, t3w1_revA_nrf52832 +tests: + app.default: {} + app.debug: + extra_overlay_confs: + - debug.conf diff --git a/west/trezor/trezor-ble/boards/t3w1_d1_nrf52833.conf b/west/trezor/trezor-ble/boards/t3w1_d1_nrf52833.conf new file mode 100644 index 0000000000..05717bb035 --- /dev/null +++ b/west/trezor/trezor-ble/boards/t3w1_d1_nrf52833.conf @@ -0,0 +1,6 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + diff --git a/west/trezor/trezor-ble/boards/t3w1_d1_nrf52833.overlay b/west/trezor/trezor-ble/boards/t3w1_d1_nrf52833.overlay new file mode 100644 index 0000000000..5e8b3f1cda --- /dev/null +++ b/west/trezor/trezor-ble/boards/t3w1_d1_nrf52833.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/west/trezor/trezor-ble/boards/t3w1_revA_nrf52832.conf b/west/trezor/trezor-ble/boards/t3w1_revA_nrf52832.conf new file mode 100644 index 0000000000..05717bb035 --- /dev/null +++ b/west/trezor/trezor-ble/boards/t3w1_revA_nrf52832.conf @@ -0,0 +1,6 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + diff --git a/west/trezor/trezor-ble/boards/t3w1_revA_nrf52832.overlay b/west/trezor/trezor-ble/boards/t3w1_revA_nrf52832.overlay new file mode 100644 index 0000000000..5e8b3f1cda --- /dev/null +++ b/west/trezor/trezor-ble/boards/t3w1_revA_nrf52832.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/west/trezor/trezor-ble/debug.conf b/west/trezor/trezor-ble/debug.conf new file mode 100644 index 0000000000..12992cefa0 --- /dev/null +++ b/west/trezor/trezor-ble/debug.conf @@ -0,0 +1,12 @@ +# Copyright (c) 2021 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 +# +# This is a Kconfig fragment which can be used to enable debug-related options +# in the application. See the README for more details. + +# compiler +CONFIG_DEBUG_OPTIMIZATIONS=y + +# logging +CONFIG_LOG=y +CONFIG_APP_LOG_LEVEL_DBG=y diff --git a/west/trezor/trezor-ble/prj.conf b/west/trezor/trezor-ble/prj.conf new file mode 100644 index 0000000000..73820932c1 --- /dev/null +++ b/west/trezor/trezor-ble/prj.conf @@ -0,0 +1,91 @@ +# +# Copyright (c) 2018 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# +CONFIG_CLOCK_CONTROL=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC_CALIBRATION=y +CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_PERIOD=4000 + +# Enable the UART driver +CONFIG_UART_ASYNC_API=y +CONFIG_NRFX_UARTE0=y +CONFIG_SERIAL=y + +# Enable the SPI driver +CONFIG_SPI=y +CONFIG_NRFX_SPIM0=y +CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58=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_APP_PAIRING_ACCEPT=y +CONFIG_BT_SMP_ENFORCE_MITM=y +CONFIG_BT_SMP_SC_ONLY=y +CONFIG_BT_FILTER_ACCEPT_LIST=y +CONFIG_BT_BONDING_REQUIRED=y +CONFIG_BT_PRIVACY=y +CONFIG_BT_TINYCRYPT_ECC=y +CONFIG_BT_LL_SW_SPLIT=y + +#CONFIG_BT_DEBUG_SMP=y + +#PHY update needed for updating PHY request +CONFIG_BT_PHY_UPDATE=y +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=4096 + +# NFC +CONFIG_NFCT_PINS_AS_GPIOS=y + +CONFIG_POLL=y + + +# Config logger +CONFIG_LOG=y +CONFIG_RTT_CONSOLE=y +CONFIG_UART_CONSOLE=n +CONFIG_USE_SEGGER_RTT=y +CONFIG_LOG_BACKEND_RTT=y +CONFIG_LOG_BACKEND_UART=n +CONFIG_LOG_PRINTK=n + +CONFIG_NANOPB=n +CONFIG_ASSERT=y diff --git a/west/trezor/trezor-ble/src/advertising.c b/west/trezor/trezor-ble/src/advertising.c new file mode 100644 index 0000000000..c265373a79 --- /dev/null +++ b/west/trezor/trezor-ble/src/advertising.c @@ -0,0 +1,150 @@ + +#include +#include + +#include + +#include + +#include "connection.h" +#include "int_comm.h" +#include "trz_nus.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; +int bond_cnt_tmp = 0; + +uint8_t manufacturer_data[8] = {0xff, 0xff, 0, 3, 'T', '3', 'W', '1'}; + +static const struct bt_data advertising_data[] = { + 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 scan_response_data[] = { + BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_NUS_VAL), + BT_DATA(BT_DATA_MANUFACTURER_DATA, manufacturer_data, 8), +}; + +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_tmp++; +} + +void advertising_setup_wl(void) { + bt_le_filter_accept_list_clear(); + bond_cnt_tmp = 0; + bt_foreach_bond(BT_ID_DEFAULT, add_to_whitelist, NULL); + bond_cnt = bond_cnt_tmp; +} + +void advertising_start(bool wl) { + if (advertising) { + if (wl != advertising_wl) { + LOG_WRN("Restarting advertising"); + bt_le_adv_stop(); + } else { + LOG_WRN("Already advertising"); + + send_status_event(); + return; + } + } + + int err; + + manufacturer_data[3] = 0x03; // todo color + + if (wl) { + advertising_setup_wl(); + LOG_INF("Advertising with whitelist"); + + manufacturer_data[2] = 0x00; + + err = bt_le_adv_start( + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_SCANNABLE | + BT_LE_ADV_OPT_FILTER_CONN | + BT_LE_ADV_OPT_FILTER_SCAN_REQ, + 160, 1600, NULL), + advertising_data, ARRAY_SIZE(advertising_data), scan_response_data, + ARRAY_SIZE(scan_response_data)); + } else { + LOG_INF("Advertising no whitelist"); + + manufacturer_data[2] = 0x01; + + err = bt_le_adv_start( + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_SCANNABLE, + 160, 1600, NULL), + advertising_data, ARRAY_SIZE(advertising_data), scan_response_data, + ARRAY_SIZE(scan_response_data)); + } + if (err) { + LOG_ERR("Advertising failed to start (err %d)", err); + send_status_event(); + return; + } + advertising = true; + advertising_wl = wl; + + // oob_fetch_addr(); + + send_status_event(); +} + +void advertising_stop(void) { + if (!advertising) { + LOG_WRN("Not advertising"); + + send_status_event(); + return; + } + + int err = bt_le_adv_stop(); + if (err) { + LOG_ERR("Advertising failed to stop (err %d)", err); + send_status_event(); + 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 bonds (err: %d)\n", err); + } else { + bt_le_filter_accept_list_clear(); + bond_cnt = 0; + LOG_INF("Bonds deleted successfully \n"); + } +} + +int advertising_get_bond_count(void) { return bond_cnt; } diff --git a/west/trezor/trezor-ble/src/advertising.h b/west/trezor/trezor-ble/src/advertising.h new file mode 100644 index 0000000000..870bf5e646 --- /dev/null +++ b/west/trezor/trezor-ble/src/advertising.h @@ -0,0 +1,12 @@ + + +#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/west/trezor/trezor-ble/src/connection.c b/west/trezor/trezor-ble/src/connection.c new file mode 100644 index 0000000000..e10ef2c97e --- /dev/null +++ b/west/trezor/trezor-ble/src/connection.c @@ -0,0 +1,169 @@ + +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include "advertising.h" +#include "connection.h" +#include "int_comm.h" + +#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); + // } + + 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; + } + + send_status_event(); +} + +bool is_connected(void) { return current_conn != NULL; } + +void disconnect(void) { + if (current_conn) { + LOG_INF("Remotely disconnected"); + bt_conn_disconnect(current_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + bt_conn_unref(current_conn); + } +} + +void num_comp_reply(bool accept) { + if (auth_conn != NULL) { + 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_disconnect(auth_conn, BT_HCI_ERR_REMOTE_USER_TERM_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); + send_pairing_request_event(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)); + + disconnect(); + + send_pairing_cancelled_event(); + send_status_event(); + + 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)); + + // oob_signal(); + // bt_le_oob_set_sc_flag(false); + // bt_le_oob_set_legacy_flag(false); + + 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)); + + // oob_signal(); + // bt_le_oob_set_sc_flag(false); + // bt_le_oob_set_legacy_flag(false); + + LOG_INF("Pairing failed conn: %s, reason %d", addr, reason); +} + +struct bt_conn *conn_get_current(void) { return current_conn; } diff --git a/west/trezor/trezor-ble/src/connection.h b/west/trezor/trezor-ble/src/connection.h new file mode 100644 index 0000000000..c134392fc8 --- /dev/null +++ b/west/trezor/trezor-ble/src/connection.h @@ -0,0 +1,30 @@ + + +#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); +struct bt_conn *conn_get_current(void); diff --git a/west/trezor/trezor-ble/src/events.c b/west/trezor/trezor-ble/src/events.c new file mode 100644 index 0000000000..a610132ae4 --- /dev/null +++ b/west/trezor/trezor-ble/src/events.c @@ -0,0 +1,13 @@ + + +#include + +#define K_POOL_EVENTS_CNT (4) + +static struct k_poll_event events[K_POOL_EVENTS_CNT]; + +void events_poll(void) { k_poll(events, ARRAY_SIZE(events), K_FOREVER); } + +void events_init(void) {} + +struct k_poll_event* events_get(int idx) { return &events[idx]; } diff --git a/west/trezor/trezor-ble/src/events.h b/west/trezor/trezor-ble/src/events.h new file mode 100644 index 0000000000..c6a83107ef --- /dev/null +++ b/west/trezor/trezor-ble/src/events.h @@ -0,0 +1,11 @@ + + +#include + +#define INT_COMM_EVENT_NUM 3 + +void events_poll(void); + +void events_init(void); + +struct k_poll_event* events_get(int idx); diff --git a/west/trezor/trezor-ble/src/int_comm.c b/west/trezor/trezor-ble/src/int_comm.c new file mode 100644 index 0000000000..bf1798ea39 --- /dev/null +++ b/west/trezor/trezor-ble/src/int_comm.c @@ -0,0 +1,161 @@ + + +#include +#include + +#include +#include + +#include +#include + +#include "advertising.h" +#include "connection.h" +#include "events.h" +#include "int_comm_defs.h" +#include "uart.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, uint8_t len) { + uart_data_t *tx = k_malloc(sizeof(*tx)); + + if (tx == NULL) { + LOG_WRN("Not able to allocate UART send data buffer"); + return; + } + + LOG_DBG("ALLOC: Sending UART data"); + + tx->len = len + OVERHEAD_SIZE; + + tx->data[0] = message_type; + tx->data[1] = tx->len; + memcpy(&tx->data[COMM_HEADER_SIZE], tx_data, len); + + uint8_t crc = crc8(tx->data, tx->len - 1, 0x07, 0x00, false); + + tx->data[tx->len - 1] = crc; + + uart_send(tx); +} + +void send_status_event(void) { + // ble_version_t version = {0}; + // + // sd_ble_version_get(&version); + LOG_WRN( + "Sending status event: connected: %d, advertising: %d, " + "advertising_whitelist: %d, peer_count: %d", + is_connected(), is_advertising(), is_advertising_whitelist(), + advertising_get_bond_count()); + + 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)); +} + +void send_pairing_cancelled_event(void) { + uint8_t tx_data[1] = {0}; + + tx_data[0] = INTERNAL_EVENT_PAIRING_CANCELLED; + + send_packet(INTERNAL_EVENT, tx_data, sizeof(tx_data)); +} + +void send_pairing_request_event(uint8_t *data, uint16_t len) { + uint8_t tx_data[7] = {0}; + + tx_data[0] = INTERNAL_EVENT_PAIRING_REQUEST; + tx_data[1] = data[0]; + tx_data[2] = data[1]; + tx_data[3] = data[2]; + tx_data[4] = data[3]; + tx_data[5] = data[4]; + tx_data[6] = data[5]; + + 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; + case INTERNAL_CMD_ALLOW_PAIRING: + num_comp_reply(true); + send_success_event(); + break; + case INTERNAL_CMD_REJECT_PAIRING: + num_comp_reply(false); + send_success_event(); + 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 (;;) { + // events_poll(); + + // if (events_get(INT_COMM_EVENT_NUM)->state == K_POLL_STATE_SIGNALED) { + + uart_data_t *buf = uart_get_data_int(); + process_command(buf->data, buf->len); + k_free(buf); + + // k_poll_signal_reset(events_get(INT_COMM_EVENT_NUM)->signal); + // events_get(INT_COMM_EVENT_NUM)->state = K_POLL_STATE_NOT_READY; + //} + } +} + +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/west/trezor/trezor-ble/src/int_comm.h b/west/trezor/trezor-ble/src/int_comm.h new file mode 100644 index 0000000000..ace1d2a2b2 --- /dev/null +++ b/west/trezor/trezor-ble/src/int_comm.h @@ -0,0 +1,21 @@ +#ifndef INT_COMM__ +#define INT_COMM__ + +#include + +void process_command(uint8_t *data, uint16_t len); + +void send_status_event(void); + +void send_pairing_request_event(uint8_t *data, uint16_t len); +void send_pairing_cancelled_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/west/trezor/trezor-ble/src/int_comm_defs.h b/west/trezor/trezor-ble/src/int_comm_defs.h new file mode 100644 index 0000000000..dbd9a43ee6 --- /dev/null +++ b/west/trezor/trezor-ble/src/int_comm_defs.h @@ -0,0 +1,52 @@ + +#ifndef __INT_COMM_DEFS__ +#define __INT_COMM_DEFS__ + +#define BLE_PACKET_SIZE (244) +#define USB_DATA_SIZE (64) + +#define COMM_HEADER_SIZE (2) +#define COMM_FOOTER_SIZE (1) +#define OVERHEAD_SIZE (COMM_HEADER_SIZE + COMM_FOOTER_SIZE) +#define UART_PACKET_SIZE (USB_DATA_SIZE + OVERHEAD_SIZE) + +#define EXTERNAL_MESSAGE (0xA0) +#define INTERNAL_EVENT (0xA1) + +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, + INTERNAL_EVENT_PAIRING_REQUEST = 0x04, + INTERNAL_EVENT_PAIRING_CANCELLED = 0x05, +} 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, + INTERNAL_CMD_ALLOW_PAIRING = 0x06, + INTERNAL_CMD_REJECT_PAIRING = 0x07, +} InternalCmd_t; +#endif diff --git a/west/trezor/trezor-ble/src/main.c b/west/trezor/trezor-ble/src/main.c new file mode 100644 index 0000000000..fe4f8d5598 --- /dev/null +++ b/west/trezor/trezor-ble/src/main.c @@ -0,0 +1,263 @@ +/* + * 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 + +#include + +#include "advertising.h" +#include "connection.h" +#include "events.h" +#include "int_comm.h" +#include "spi.h" +#include "trz_nus.h" +#include "uart.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 CON_STATUS_LED DK_LED2 + +static K_SEM_DEFINE(ble_init_ok, 0, 1); +static K_SEM_DEFINE(led_init_ok, 0, 1); + +#define AUTH_SC_FLAG 0x08 + +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 enum bt_security_err pairing_accept(struct bt_conn *conn, +// const struct bt_conn_pairing_feat +// *const feat) +//{ +// if (feat->oob_data_flag && (!(feat->auth_req & AUTH_SC_FLAG))) { +// bt_le_oob_set_legacy_flag(true); +// } +// +// return BT_SECURITY_ERR_SUCCESS; +// +// } + +static struct bt_conn_auth_cb conn_auth_callbacks = { + // .pairing_accept = pairing_accept, + .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_DBG("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"); + + events_init(); + advertising_init(); + int_comm_start(); + + dk_set_led(FW_RUNNING_SIG, 1); + // dk_set_led(FW_RUNNING_SIG, 0); + // while(true) { + // dk_set_led(FW_RUNNING_SIG, 1); + // dk_set_led(FW_RUNNING_SIG, 0); + // } + send_status_event(); + + // oob_init(); + + k_sem_give(&led_init_ok); + + for (;;) { + events_poll(); + printk("Event occurred\n"); + + // oob_process(); + // 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(conn_get_current(), buf)) { + LOG_WRN("Failed to send data over BLE connection: %d", buf->len); + k_free(buf); + } + + LOG_DBG("Freeing UART data"); + } +} + +void led_thread(void) { + bool connected = false; + int blink_status = 0; + /* Don't go any further until BLE is initialized */ + k_sem_take(&led_init_ok, K_FOREVER); + + for (;;) { + blink_status++; + dk_set_led(RUN_STATUS_LED, (blink_status) % 2); + + connected = is_connected(); + + if (connected) { + dk_set_led_on(CON_STATUS_LED); + } else { + if (is_advertising() && !is_advertising_whitelist()) { + dk_set_led(CON_STATUS_LED, (blink_status) % 2); + } else { + dk_set_led_off(CON_STATUS_LED); + } + } + + k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL)); + } +} + +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/west/trezor/trezor-ble/src/oob.c b/west/trezor/trezor-ble/src/oob.c new file mode 100644 index 0000000000..81de6bc732 --- /dev/null +++ b/west/trezor/trezor-ble/src/oob.c @@ -0,0 +1,499 @@ + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "events.h" + +#define NDEF_MSG_BUF_SIZE 256 +#define AUTH_SC_FLAG 0x08 + +// #define NFC_FIELD_LED DK_LED2 +// #define CON_STATUS_LED DK_LED1 +// +// #define KEY_BOND_REMOVE_MASK DK_BTN4_MSK + +#define NFC_NDEF_LE_OOB_REC_PARSER_BUFF_SIZE 150 +#define NFC_TNEP_BUFFER_SIZE 1024 + +static struct bt_le_oob oob_local; +static struct k_work adv_work; +static uint8_t conn_cnt; +static uint8_t tk_value[NFC_NDEF_LE_OOB_REC_TK_LEN]; +static uint8_t remote_tk_value[NFC_NDEF_LE_OOB_REC_TK_LEN]; +static struct bt_le_oob oob_remote; + +/* Bonded address queue. */ +K_MSGQ_DEFINE(bonds_queue, sizeof(bt_addr_le_t), CONFIG_BT_MAX_PAIRED, 4); + +static struct k_poll_signal pair_signal; +static uint8_t tnep_buffer[NFC_TNEP_BUFFER_SIZE]; +static uint8_t tnep_swap_buffer[NFC_TNEP_BUFFER_SIZE]; +static bool use_remote_tk; +static bool adv_permission; + +static int tk_value_generate(void) { + int err; + + err = bt_rand(tk_value, sizeof(tk_value)); + if (err) { + printk("Random TK value generation failed: %d\n", err); + } + + return err; +} + +static void pair_key_generate_init(void) { + k_poll_signal_init(&pair_signal); + k_poll_event_init(events_get(NFC_TNEP_EVENTS_NUMBER), K_POLL_TYPE_SIGNAL, + K_POLL_MODE_NOTIFY_ONLY, &pair_signal); +} + +static int paring_key_generate(void) { + int err; + + printk("Generating new pairing keys\n"); + + err = bt_le_oob_get_local(BT_ID_DEFAULT, &oob_local); + if (err) { + printk("Error while fetching local OOB data: %d\n", err); + } + + return tk_value_generate(); +} + +static void paring_key_process(void) { + int err; + + if (events_get(NFC_TNEP_EVENTS_NUMBER)->state == K_POLL_STATE_SIGNALED) { + err = paring_key_generate(); + if (err) { + printk("Pairing key generation error: %d\n", err); + } + + k_poll_signal_reset(events_get(NFC_TNEP_EVENTS_NUMBER)->signal); + events_get(NFC_TNEP_EVENTS_NUMBER)->state = K_POLL_STATE_NOT_READY; + } +} + +static void bond_find(const struct bt_bond_info *info, void *user_data) { + int err; + struct bt_conn *conn; + + /* Filter already connected peers. */ + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &info->addr); + if (conn) { + bt_conn_unref(conn); + return; + } + + err = k_msgq_put(&bonds_queue, (void *)&info->addr, K_NO_WAIT); + if (err) { + printk("No space in the queue for the bond\n"); + } +} + +/** + * @brief Callback function for handling NFC events. + */ +static void nfc_callback(void *context, nfc_t4t_event_t event, + const uint8_t *data, size_t data_length, + uint32_t flags) { + ARG_UNUSED(context); + ARG_UNUSED(data); + ARG_UNUSED(flags); + + switch (event) { + case NFC_T4T_EVENT_FIELD_ON: + printk("NFC callback 1\n"); + nfc_tnep_tag_on_selected(); + // dk_set_led_on(NFC_FIELD_LED); + + // adv_permission = true; + + break; + + case NFC_T4T_EVENT_FIELD_OFF: + printk("NFC callback 2\n"); + nfc_tnep_tag_on_selected(); + // dk_set_led_off(NFC_FIELD_LED); + break; + + case NFC_T4T_EVENT_NDEF_READ: + printk("NFC callback 3\n"); + // if (adv_permission) { + // advertising_start(); + // adv_permission = false; + // } + + break; + + case NFC_T4T_EVENT_NDEF_UPDATED: + printk("NFC callback 4\n"); + if (data_length > 0) { + nfc_tnep_tag_rx_msg_indicate(nfc_t4t_ndef_file_msg_get(data), + data_length); + } + + default: + break; + } +} + +/** .. include_startingpoint_pair_msg_rst */ +static int tnep_initial_msg_encode(struct nfc_ndef_msg_desc *msg) { + int err; + struct nfc_ndef_ch_msg_records ch_records; + static struct nfc_ndef_le_oob_rec_payload_desc rec_payload; + + NFC_NDEF_LE_OOB_RECORD_DESC_DEF(oob_rec, '0', &rec_payload); + NFC_NDEF_CH_AC_RECORD_DESC_DEF(oob_ac, NFC_AC_CPS_ACTIVE, 1, "0", 0); + NFC_NDEF_CH_HS_RECORD_DESC_DEF(hs_rec, NFC_NDEF_CH_MSG_MAJOR_VER, + NFC_NDEF_CH_MSG_MINOR_VER, 1); + + memset(&rec_payload, 0, sizeof(rec_payload)); + + rec_payload.addr = &oob_local.addr; + rec_payload.le_sc_data = &oob_local.le_sc_data; + rec_payload.tk_value = tk_value; + rec_payload.local_name = bt_get_name(); + rec_payload.le_role = + NFC_NDEF_LE_OOB_REC_LE_ROLE(NFC_NDEF_LE_OOB_REC_LE_ROLE_PERIPH_ONLY); + rec_payload.appearance = + NFC_NDEF_LE_OOB_REC_APPEARANCE(CONFIG_BT_DEVICE_APPEARANCE); + rec_payload.flags = NFC_NDEF_LE_OOB_REC_FLAGS(BT_LE_AD_NO_BREDR); + + ch_records.ac = &NFC_NDEF_CH_AC_RECORD_DESC(oob_ac); + ch_records.carrier = &NFC_NDEF_LE_OOB_RECORD_DESC(oob_rec); + ch_records.cnt = 1; + + err = nfc_ndef_ch_msg_hs_create(msg, &NFC_NDEF_CH_RECORD_DESC(hs_rec), + &ch_records); + + printk("mac0: %X:%X:%X:%X:%X:%X\n", rec_payload.addr->a.val[5], + rec_payload.addr->a.val[4], rec_payload.addr->a.val[3], + rec_payload.addr->a.val[2], rec_payload.addr->a.val[1], + rec_payload.addr->a.val[0]); + + if (err) { + return err; + } + + return nfc_tnep_initial_msg_encode(msg, NULL, 0); +} +/** .. include_endpoint_pair_msg_rst */ + +static int check_oob_carrier(const struct nfc_tnep_ch_record *ch_record, + const struct nfc_ndef_record_desc **oob_data) { + const struct nfc_ndef_ch_ac_rec *ac_rec = NULL; + + for (size_t i = 0; i < ch_record->count; i++) { + if (nfc_ndef_le_oob_rec_check(ch_record->carrier[i])) { + *oob_data = ch_record->carrier[i]; + } + } + + if (!oob_data) { + printk("Connection Handover Requester not supporting OOB BLE\n"); + return -EINVAL; + } + + /* Look for the corresponding Alternative Carrier Record. */ + for (size_t i = 0; i < ch_record->count; i++) { + if (((*oob_data)->id_length == ch_record->ac[i].carrier_data_ref.length) && + (memcmp((*oob_data)->id, ch_record->ac[i].carrier_data_ref.data, + (*oob_data)->id_length) == 0)) { + ac_rec = &ch_record->ac[i]; + } + } + + if (!ac_rec) { + printk("No Alternative Carrier Record for OOB LE carrier\n"); + return -EINVAL; + } + + /* Check carrier state */ + if ((ac_rec->cps != NFC_AC_CPS_ACTIVE) && + (ac_rec->cps != NFC_AC_CPS_ACTIVATING)) { + printk("LE OBB Carrier inactive\n"); + return -EINVAL; + } + + return 0; +} + +static void lesc_oob_data_set(struct bt_conn *conn, + struct bt_conn_oob_info *oob_info) { + int err; + char addr[BT_ADDR_LE_STR_LEN]; + struct bt_conn_info info; + + err = bt_conn_get_info(conn, &info); + if (err) { + return; + } + + struct bt_le_oob_sc_data *oob_data_local = + oob_info->lesc.oob_config != BT_CONN_OOB_REMOTE_ONLY + ? &oob_local.le_sc_data + : NULL; + struct bt_le_oob_sc_data *oob_data_remote = + oob_info->lesc.oob_config != BT_CONN_OOB_LOCAL_ONLY + ? &oob_remote.le_sc_data + : NULL; + + if (oob_data_remote && bt_addr_le_cmp(info.le.remote, &oob_remote.addr)) { + bt_addr_le_to_str(info.le.remote, addr, sizeof(addr)); + printk("No OOB data available for remote %s", addr); + bt_conn_auth_cancel(conn); + return; + } + + if (oob_data_local && bt_addr_le_cmp(info.le.local, &oob_local.addr)) { + bt_addr_le_to_str(info.le.local, addr, sizeof(addr)); + printk("No OOB data available for local %s", addr); + bt_conn_auth_cancel(conn); + return; + } + + err = bt_le_oob_set_sc_data(conn, oob_data_local, oob_data_remote); + if (err) { + printk("Error while setting OOB data: %d\n", err); + } +} + +// static void legacy_tk_value_set(struct bt_conn *conn) +//{ +// int err; +// const uint8_t *tk = use_remote_tk ? remote_tk_value : tk_value; +// +// err = bt_le_oob_set_legacy_tk(conn, tk); +// if (err) { +// printk("TK value set error: %d\n", err); +// } +// +// use_remote_tk = false; +// } + +void auth_oob_data_request(struct bt_conn *conn, + struct bt_conn_oob_info *info) { + printk("OOB data requested\n"); + + if (info->type == BT_CONN_OOB_LE_SC) { + printk("LESC OOB data requested\n"); + lesc_oob_data_set(conn, info); + } + + // if (info->type == BT_CONN_OOB_LE_LEGACY) { + // printk("Legacy TK value requested\n"); + // legacy_tk_value_set(conn); + // } +} + +static int oob_le_data_handle(const struct nfc_ndef_record_desc *rec, + bool request) { + int err; + const struct nfc_ndef_le_oob_rec_payload_desc *oob; + uint8_t desc_buf[NFC_NDEF_LE_OOB_REC_PARSER_BUFF_SIZE]; + uint32_t desc_buf_len = sizeof(desc_buf); + + err = nfc_ndef_le_oob_rec_parse(rec, desc_buf, &desc_buf_len); + if (err) { + printk("Error during NDEF LE OOB Record parsing, err: %d.\n", err); + } + + oob = (struct nfc_ndef_le_oob_rec_payload_desc *)desc_buf; + + nfc_ndef_le_oob_rec_printout(oob); + + if ((*oob->le_role != NFC_NDEF_LE_OOB_REC_LE_ROLE_CENTRAL_ONLY) && + (*oob->le_role != NFC_NDEF_LE_OOB_REC_LE_ROLE_CENTRAL_PREFFERED)) { + printk("Unsupported Device LE Role\n"); + return -EINVAL; + } + + if (oob->le_sc_data) { + bt_le_oob_set_sc_flag(true); + oob_remote.le_sc_data = *oob->le_sc_data; + bt_addr_le_copy(&oob_remote.addr, oob->addr); + } + + if (oob->tk_value) { + bt_le_oob_set_legacy_flag(true); + memcpy(remote_tk_value, oob->tk_value, sizeof(remote_tk_value)); + use_remote_tk = request; + } + + // advertising_start(); + + return 0; +} + +/** .. include_startingpoint_nfc_tnep_ch_tag_rst */ +static int carrier_prepare(void) { + static struct nfc_ndef_le_oob_rec_payload_desc rec_payload; + + NFC_NDEF_LE_OOB_RECORD_DESC_DEF(oob_rec, '0', &rec_payload); + NFC_NDEF_CH_AC_RECORD_DESC_DEF(oob_ac, NFC_AC_CPS_ACTIVE, 1, "0", 0); + + memset(&rec_payload, 0, sizeof(rec_payload)); + + rec_payload.addr = &oob_local.addr; + rec_payload.le_sc_data = &oob_local.le_sc_data; + rec_payload.tk_value = tk_value; + rec_payload.local_name = bt_get_name(); + rec_payload.le_role = + NFC_NDEF_LE_OOB_REC_LE_ROLE(NFC_NDEF_LE_OOB_REC_LE_ROLE_PERIPH_ONLY); + rec_payload.appearance = + NFC_NDEF_LE_OOB_REC_APPEARANCE(CONFIG_BT_DEVICE_APPEARANCE); + rec_payload.flags = NFC_NDEF_LE_OOB_REC_FLAGS(BT_LE_AD_NO_BREDR); + + return nfc_tnep_ch_carrier_set(&NFC_NDEF_CH_AC_RECORD_DESC(oob_ac), + &NFC_NDEF_LE_OOB_RECORD_DESC(oob_rec), 1); +} + +#if defined(CONFIG_NFC_TAG_CH_REQUESTER) +static int tnep_ch_request_prepare(void) { + bt_le_adv_stop(); + return carrier_prepare(); +} + +static int tnep_ch_select_received(const struct nfc_tnep_ch_record *ch_select, + bool inactive) { + int err; + const struct nfc_ndef_record_desc *oob_data = NULL; + + if (!ch_select->count) { + return -EINVAL; + } + + /* All alternative carrier are inactive */ + if (inactive) { + /* Try send request again. */ + return carrier_prepare(); + } + + err = check_oob_carrier(ch_select, &oob_data); + if (err) { + return err; + } + + err = oob_le_data_handle(oob_data, false); + if (err) { + return err; + } + + return 0; +} +#endif /* defined(CONFIG_NFC_TAG_CH_REQUESTER) */ + +static int tnep_ch_request_received(const struct nfc_tnep_ch_request *ch_req) { + int err; + const struct nfc_ndef_record_desc *oob_data = NULL; + + if (!ch_req->ch_record.count) { + return -EINVAL; + } + + err = check_oob_carrier(&ch_req->ch_record, &oob_data); + if (err) { + return err; + } + + bt_le_adv_stop(); + + err = oob_le_data_handle(oob_data, true); + if (err) { + return err; + } + + return carrier_prepare(); +} + +static struct nfc_tnep_ch_cb ch_cb = { +#if defined(CONFIG_NFC_TAG_CH_REQUESTER) + .request_msg_prepare = tnep_ch_request_prepare, + .select_msg_recv = tnep_ch_select_received, +#endif + .request_msg_recv = tnep_ch_request_received}; +/** .. include_endpoint_nfc_tnep_ch_tag_rst */ + +static void nfc_init(void) { + int err; + + /* TNEP init */ + err = nfc_tnep_tag_tx_msg_buffer_register(tnep_buffer, tnep_swap_buffer, + sizeof(tnep_buffer)); + if (err) { + printk("Cannot register tnep buffer, err: %d\n", err); + return; + } + + err = nfc_tnep_tag_init(events_get(0), NFC_TNEP_EVENTS_NUMBER, + nfc_t4t_ndef_rwpayload_set); + if (err) { + printk("Cannot initialize TNEP protocol, err: %d\n", err); + return; + } + + /* Set up NFC */ + err = nfc_t4t_setup(nfc_callback, NULL); + if (err) { + printk("Cannot setup NFC T4T library!\n"); + return; + } + + err = nfc_tnep_tag_initial_msg_create(2, tnep_initial_msg_encode); + if (err) { + printk("Cannot create initial TNEP message, err: %d\n", err); + } + + err = nfc_tnep_ch_service_init(&ch_cb); + if (err) { + printk("TNEP CH Service init error: %d\n", err); + return; + } + + /* Start sensing NFC field */ + err = nfc_t4t_emulation_start(); + if (err) { + printk("Cannot start emulation!\n"); + return; + } + + printk("NFC configuration done\n"); +} + +void oob_init(void) { + paring_key_generate(); + pair_key_generate_init(); + nfc_init(); +} + +void oob_process(void) { + nfc_tnep_tag_process(); + paring_key_process(); +} + +// K_THREAD_DEFINE(oob_thread_id, CONFIG_BT_NUS_THREAD_STACK_SIZE, oob_thread, +// NULL, NULL, +// NULL, 7, 0, 0); + +void oob_signal(void) { k_poll_signal_raise(&pair_signal, 0); } + +void oob_fetch_addr(void) { bt_le_oob_get_local(BT_ID_DEFAULT, &oob_local); } diff --git a/west/trezor/trezor-ble/src/oob.h b/west/trezor/trezor-ble/src/oob.h new file mode 100644 index 0000000000..c3865be55f --- /dev/null +++ b/west/trezor/trezor-ble/src/oob.h @@ -0,0 +1,14 @@ + + +#include +#include + +void auth_oob_data_request(struct bt_conn *conn, struct bt_conn_oob_info *info); + +void oob_init(void); + +void oob_signal(void); + +void oob_process(void); + +void oob_fetch_addr(void); diff --git a/west/trezor/trezor-ble/src/spi.c b/west/trezor/trezor-ble/src/spi.c new file mode 100644 index 0000000000..38b3967577 --- /dev/null +++ b/west/trezor/trezor-ble/src/spi.c @@ -0,0 +1,108 @@ + +#include +#include + +#include + +#include + +#include +#include + +#include +#include +#include + +#include "int_comm_defs.h" +#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[BLE_PACKET_SIZE + 2]; + 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 + 2; + tx->data[0] = EXTERNAL_MESSAGE; + memcpy(&tx->data[1], data, len); + + uint8_t crc = crc8(tx->data, len + 1, 0x07, 0x00, false); + tx->data[len + 1] = crc; + + 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); + printk("SPI Data sent\n"); + + 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/west/trezor/trezor-ble/src/spi.h b/west/trezor/trezor-ble/src/spi.h new file mode 100644 index 0000000000..ab517f8768 --- /dev/null +++ b/west/trezor/trezor-ble/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/west/trezor/trezor-ble/src/trz_nus.c b/west/trezor/trezor-ble/src/trz_nus.c new file mode 100644 index 0000000000..1fb2356052 --- /dev/null +++ b/west/trezor/trezor-ble/src/trz_nus.c @@ -0,0 +1,90 @@ +/* + * 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) { + uart_data_t *data = (uart_data_t *)user_data; + + k_free(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, uart_data_t *data) { + struct bt_gatt_notify_params params = {0}; + const struct bt_gatt_attr *attr = &nus_svc.attrs[2]; + + params.attr = attr; + params.data = data->data; + params.len = data->len; + params.func = on_sent; + params.user_data = (void *)data; + + 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/west/trezor/trezor-ble/src/trz_nus.h b/west/trezor/trezor-ble/src/trz_nus.h new file mode 100644 index 0000000000..3f2f9ba240 --- /dev/null +++ b/west/trezor/trezor-ble/src/trz_nus.h @@ -0,0 +1,137 @@ +/* + * 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 + +#include "uart.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief UUID of the NUS Service. **/ +#define BT_UUID_NUS_VAL \ + BT_UUID_128_ENCODE(0x8c000001, 0xa59b, 0x4d58, 0xa9ad, 0x073df69fa1b1) + +/** @brief UUID of the TX Characteristic. **/ +#define BT_UUID_NUS_TX_VAL \ + BT_UUID_128_ENCODE(0x8c000003, 0xa59b, 0x4d58, 0xa9ad, 0x073df69fa1b1) + +/** @brief UUID of the RX Characteristic. **/ +#define BT_UUID_NUS_RX_VAL \ + BT_UUID_128_ENCODE(0x8c000002, 0xa59b, 0x4d58, 0xa9ad, 0x073df69fa1b1) + +#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] buf Pointer to a data buffer. + * + * @retval 0 If the data is sent. + * Otherwise, a negative value is returned. + */ +int bt_nus_send(struct bt_conn *conn, uart_data_t *data); + +/**@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/west/trezor/trezor-ble/src/uart.c b/west/trezor/trezor-ble/src/uart.c new file mode 100644 index 0000000000..6acf4de7ed --- /dev/null +++ b/west/trezor/trezor-ble/src/uart.c @@ -0,0 +1,360 @@ +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include "events.h" +#include "int_comm.h" +#include "int_comm_defs.h" +#include "uart.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 struct k_work_delayable uart_work; + +static volatile bool g_uart_rx_running = false; + +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; + static uint8_t crc = 0; + + switch (evt->type) { + case UART_TX_DONE: + LOG_DBG("UART_TX_DONE"); + + if (evt->data.tx.buf == NULL) { + return; + } + + if (evt->data.tx.len == 0) { + buf = CONTAINER_OF(evt->data.tx.buf, uart_data_t, data[0]); + + LOG_DBG("Free uart data"); + k_free(buf); + return; + } + + if (aborted_buf) { + buf = CONTAINER_OF(aborted_buf, uart_data_t, data[0]); + aborted_buf = NULL; + aborted_len = 0; + } else { + buf = CONTAINER_OF(evt->data.tx.buf, uart_data_t, data[0]); + } + + LOG_DBG("Free uart 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("FREE: Failed to send data over UART"); + } + + break; + + case UART_RX_RDY: + // LOG_WRN("UART_RX_RDY"); + buf = CONTAINER_OF(evt->data.rx.buf, uart_data_t, data[0]); + buf->len += evt->data.rx.len; + + switch (rx_phase) { + case 0: + if (buf->len == 1 && (buf->data[0] == INTERNAL_EVENT || + buf->data[0] == EXTERNAL_MESSAGE)) { + rx_phase = 1; + rx_msg_type = buf->data[0]; + crc = crc8(buf->data, buf->len, 0x07, 0x00, false); + } else { + rx_phase = 0; + } + break; + case 1: + if (buf->len == 1) { + rx_data_len = buf->data[0]; + crc = crc8(buf->data, buf->len, 0x07, crc, false); + rx_phase = 2; + } else { + rx_phase = 0; + } + break; + case 2: + if (buf->len != rx_data_len - COMM_HEADER_SIZE) { + rx_phase = 0; + } + + crc = crc8(buf->data, buf->len - 1, 0x07, crc, false); + + if (crc != buf->data[buf->len - 1]) { + LOG_WRN("UART_RX CRC ERROR"); + rx_phase = 0; + } + + rx_phase = 3; + 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; + + LOG_DBG("UART_RX_MALLOC"); + buf = k_malloc(sizeof(*buf)); + + if (buf) { + switch (rx_phase) { + case 0: + rx_len = 1; + break; + case 1: + rx_len = 1; + break; + case 2: + rx_len = rx_data_len - COMM_HEADER_SIZE; + 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"); + k_work_reschedule(&uart_work, UART_WAIT_FOR_BUF_DELAY); + g_uart_rx_running = false; + } + + // buf = k_malloc(sizeof(*buf)); + // if (buf) { + // buf->len = 0; + // } else { + // LOG_WRN("Not able to allocate UART receive + // buffer"); + // + // 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[0]); + + if (rx_phase == 3 && buf->len > 0) { + buf->len -= COMM_FOOTER_SIZE; + 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 { + // LOG_WRN("UART_RX BAD MASSAGE TYPE"); + k_free(buf); + } + rx_data_len = 0; + rx_len = 0; + rx_msg_type = 0; + rx_phase = 0; + } else { + k_free(buf); + } + break; + case UART_RX_STOPPED: + LOG_DBG("UART_RX_STOPPED"); + g_uart_rx_running = false; + rx_data_len = 0; + rx_len = 0; + rx_msg_type = 0; + rx_phase = 0; + k_work_reschedule(&uart_work, UART_WAIT_FOR_BUF_DELAY); + 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[0]); + + uart_tx(uart, &buf->data[aborted_len], buf->len - aborted_len, + SYS_FOREVER_MS); + + break; + + default: + break; + } +} + +int uart_start_rx(void) { + int err; + uart_data_t *rx; + + rx = k_malloc(sizeof(*rx)); + if (rx) { + rx->len = 0; + } else { + return -ENOMEM; + } + + // 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); + } else { + g_uart_rx_running = true; + } + + return err; +} + +static void uart_work_handler(struct k_work *item) { + uart_data_t *buf; + + 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, 1, SYS_FOREVER_US); +} + +int uart_init(void) { + int err; + + if (!device_is_ready(uart)) { + return -ENODEV; + } + + k_work_init_delayable(&uart_work, uart_work_handler); + + 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); + + err = uart_callback_set(uart, uart_cb, NULL); + if (err) { + LOG_ERR("Cannot initialize UART callback"); + return err; + } + + return uart_start_rx(); +} + +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_data_pb_flush(void){ +// while(uart_get_data_pb() != NULL); +//} + +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/west/trezor/trezor-ble/src/uart.h b/west/trezor/trezor-ble/src/uart.h new file mode 100644 index 0000000000..5accb06f44 --- /dev/null +++ b/west/trezor/trezor-ble/src/uart.h @@ -0,0 +1,22 @@ +#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_data_pb_flush(void); + +void uart_send(uart_data_t *data); +void uart_send_ext(uart_data_t *tx); + +#endif diff --git a/west/trezor/west.yml b/west/trezor/west.yml new file mode 100644 index 0000000000..0a91db7e95 --- /dev/null +++ b/west/trezor/west.yml @@ -0,0 +1,21 @@ +# Copyright (c) 2021 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +manifest: + self: + west-commands: scripts/west-commands.yml + + remotes: + - name: ncs + url-base: https://github.com/nrfconnect + + projects: + - name: nrf + remote: ncs + repo-path: sdk-nrf + revision: v2.7.0 + import: true + - name: mcuboot + url: https://github.com/hiviah/mcuboot + path: bootloader/mcuboot + revision: edfe1e1465dbc698bf9a195816247913490ab391 diff --git a/west/trezor/zephyr/module.yml b/west/trezor/zephyr/module.yml new file mode 100644 index 0000000000..047032a919 --- /dev/null +++ b/west/trezor/zephyr/module.yml @@ -0,0 +1,20 @@ +# Copyright (c) 2021 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +build: + # Path to the Kconfig file that will be sourced into Zephyr Kconfig tree under + # Zephyr > Modules > example-application. Path is relative from root of this + # repository. + kconfig: Kconfig + # Path to the folder that contains the CMakeLists.txt file to be included by + # Zephyr build system. The `.` is the root of this repository. + cmake: . + settings: + # Additional roots for boards and DTS files. Zephyr will use the + # `/boards` for additional boards. The `.` is the root of this + # repository. + board_root: . + # Zephyr will use the `/dts` for additional dts files and + # `/dts/bindings` for additional dts binding files. The `.` is + # the root of this repository. + dts_root: .