tychovrahe/T3W1/devkit1_with_zephyr
tychovrahe 3 months ago
parent 1e5701228f
commit c99284043e

1
core/.gitignore vendored

@ -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/

@ -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(.)

@ -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

@ -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

@ -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 <software_maturity>` 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 <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 <ug_tfm>`

@ -0,0 +1,5 @@
VERSION_MAJOR = 2
VERSION_MINOR = 5
PATCHLEVEL = 0
VERSION_TWEAK = 0
EXTRAVERSION =

@ -0,0 +1,11 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
/ {
chosen {
nordic,nus-uart = &uart0;
};
};

@ -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

@ -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

@ -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

@ -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)

@ -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 <tty_device> -b 115200
Replace :code:`<tty_device>` 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 = <NRF_PSEL(UART_TX, 0, 14)>,
<NRF_PSEL(UART_RX, 0, 16)>;
};
};
/* required if CONFIG_PM_DEVICE=y */
uart1_sleep_alt: uart1_sleep_alt {
group1 {
psels = <NRF_PSEL(UART_TX, 0, 14)>,
<NRF_PSEL(UART_RX, 0, 16)>;
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

@ -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")

@ -0,0 +1,48 @@
/*
* Copyright (c) 2022 Nordic Semiconductor
* SPDX-License-Identifier: Apache-2.0
*/
&pinctrl {
uart0_default: uart0_default {
group1 {
psels = <NRF_PSEL(UART_TX, 0, 27)>,
<NRF_PSEL(UART_RTS, 0, 8)>;
};
group2 {
psels = <NRF_PSEL(UART_RX, 0, 26)>,
<NRF_PSEL(UART_CTS, 0, 6)>;
bias-pull-up;
};
};
uart0_sleep: uart0_sleep {
group1 {
psels = <NRF_PSEL(UART_TX, 0, 27)>,
<NRF_PSEL(UART_RX, 0, 26)>,
<NRF_PSEL(UART_RTS, 0, 8)>,
<NRF_PSEL(UART_CTS, 0, 6)>;
low-power-enable;
};
};
spi0_default: spi0_default {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 0, 14)>,
<NRF_PSEL(SPIM_MOSI, 0, 16)>,
<NRF_PSEL(SPIM_MISO, 0, 15)>;
};
};
spi0_sleep: spi0_sleep {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 0, 14)>,
<NRF_PSEL(SPIM_MOSI, 0, 16)>,
<NRF_PSEL(SPIM_MISO, 0, 15)>;
low-power-enable;
};
};
};

@ -0,0 +1,144 @@
/*
* Copyright (c) 2019 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/dts-v1/;
#include <nordic/nrf52833_qiaa.dtsi>
#include "t3w1_nrf52833-pinctrl.dtsi"
#include <zephyr/dt-bindings/input/input-event-codes.h>
/ {
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 = <INPUT_KEY_0>;
};
trezor_ready: trezor_ready {
gpios = <&gpio0 30 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>;
label = "Trezor ready";
zephyr,code = <INPUT_KEY_1>;
};
};
/* 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";
};

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -0,0 +1,138 @@
#include <zephyr/types.h>
#include <zephyr/kernel.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <bluetooth/services/nus.h>
#include <zephyr/logging/log.h>
#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;
}

@ -0,0 +1,14 @@
#include <stdbool.h>
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);

@ -0,0 +1,170 @@
#include <zephyr/types.h>
#include <zephyr/kernel.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/logging/log.h>
#include <dk_buttons_and_leds.h>
#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, &params);
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);
}

@ -0,0 +1,29 @@
#include <stdint.h>
#include <stdbool.h>
#include <zephyr/types.h>
#include <zephyr/kernel.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/hci.h>
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);

@ -0,0 +1,127 @@
#include <stdint.h>
#include <stdbool.h>
#include <zephyr/types.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#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);

@ -0,0 +1,18 @@
#ifndef INT_COMM__
#define INT_COMM__
#include <stdint.h>
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

@ -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

@ -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 <zephyr/types.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <soc.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/hci.h>
#include <dk_buttons_and_leds.h>
#include <zephyr/settings/settings.h>
#include <zephyr/logging/log.h>
#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);

@ -0,0 +1,390 @@
#include <zephyr/types.h>
#include <zephyr/kernel.h>
#include <dk_buttons_and_leds.h>
#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);

@ -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);

@ -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)

@ -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 <pb.h>
#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

@ -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;
}

@ -0,0 +1,87 @@
#include <pb_decode.h>
#include <pb_encode.h>
#include <stdbool.h>
#include <stdint.h>
#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);

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef TREZORHAL_SECBOOL_H
#define TREZORHAL_SECBOOL_H
#include <stdint.h>
typedef uint32_t secbool;
#define sectrue 0xAAAAAAAAU
#define secfalse 0x00000000U
#ifndef __wur
#define __wur __attribute__((warn_unused_result))
#endif
#endif

@ -0,0 +1,108 @@
#include <stdint.h>
#include <stdbool.h>
#include <zephyr/types.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.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[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);

@ -0,0 +1,6 @@
#include <stdint.h>
void spi_init(void);
void spi_send(const uint8_t * data, uint32_t len);

@ -0,0 +1,92 @@
/*
* Copyright (c) 2018 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/logging/log.h>
#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, &params);
} else {
return -EINVAL;
}
}

@ -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 <zephyr/types.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#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_ */

@ -0,0 +1,309 @@
#include <zephyr/types.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <dk_buttons_and_leds.h>
#include <zephyr/settings/settings.h>
#include <zephyr/logging/log.h>
#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);
}
}

@ -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
Loading…
Cancel
Save