mirror of
https://github.com/trezor/trezor-firmware.git
synced 2026-02-20 00:33:30 +01:00
feat(nordic): add support for direct test mode
[no changelog]
This commit is contained in:
33
nordic/trezor/direct_test_mode/CMakeLists.txt
Normal file
33
nordic/trezor/direct_test_mode/CMakeLists.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
#
|
||||
# Copyright (c) 2020 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)
|
||||
|
||||
target_include_directories(app PRIVATE ./src)
|
||||
|
||||
target_sources_ifndef(CONFIG_DTM_TRANSPORT_HCI app PRIVATE
|
||||
src/transport/dtm_uart_twowire.c
|
||||
src/transport/dtm_uart_wait.c
|
||||
)
|
||||
|
||||
target_sources_ifdef(CONFIG_DTM_TRANSPORT_HCI app PRIVATE src/transport/dtm_hci.c)
|
||||
|
||||
if(CONFIG_DTM_TRANSPORT_HCI AND "${BOARD}" STREQUAL "nrf5340dk")
|
||||
target_sources(app PRIVATE src/transport/hci_uart_remote.c)
|
||||
target_include_directories(app PRIVATE ./rpc)
|
||||
else()
|
||||
target_sources_ifdef(CONFIG_DTM_TRANSPORT_HCI app PRIVATE src/transport/hci_uart.c)
|
||||
endif()
|
||||
|
||||
# NORDIC SDK APP START
|
||||
target_sources(app PRIVATE
|
||||
src/dtm.c
|
||||
src/dtm_hw.c
|
||||
src/main.c
|
||||
)
|
||||
# NORDIC SDK APP END
|
||||
103
nordic/trezor/direct_test_mode/Kconfig
Normal file
103
nordic/trezor/direct_test_mode/Kconfig
Normal file
@@ -0,0 +1,103 @@
|
||||
#
|
||||
# Copyright (c) 2020 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
mainmenu "Nordic DTM sample"
|
||||
|
||||
config DTM_RADIO_IRQ_PRIORITY
|
||||
int "Radio interrupt priority"
|
||||
range 0 5 if ZERO_LATENCY_IRQS
|
||||
range 0 6
|
||||
default 2
|
||||
help
|
||||
Sets Radio interrupt priority.
|
||||
Levels are from 0 (highest priority) to 6 (lowest priority)
|
||||
|
||||
config DTM_TIMER_IRQ_PRIORITY
|
||||
int "DTM timer interrupt priority"
|
||||
range 0 5 if ZERO_LATENCY_IRQS
|
||||
range 0 6
|
||||
default 3
|
||||
help
|
||||
Sets DTM timer interrupt priority.
|
||||
Levels are from 0 (highest priority) to 6 (lowest priority)
|
||||
|
||||
config ANOMALY_172_TIMER_IRQ_PRIORITY
|
||||
int "Anomaly 172 timer interrupt priority"
|
||||
depends on SOC_NRF52840
|
||||
range 0 5 if ZERO_LATENCY_IRQS
|
||||
range 0 6
|
||||
default 2
|
||||
help
|
||||
Sets anomaly 172 timer interrupt priority.
|
||||
Levels are from 0 (highest priority) to 6 (lowest priority)
|
||||
|
||||
config DTM_USB
|
||||
bool "DTM over USB CDC ACM class"
|
||||
depends on SOC_NRF5340_CPUNET && !DTM_TRANSPORT_HCI
|
||||
select EXPERIMENTAL
|
||||
help
|
||||
Use USB instead of UART as the DTM interface. For nRF5340 the USB from application core
|
||||
is used as communication interface.
|
||||
|
||||
config DTM_TRANSPORT_HCI
|
||||
bool "DTM over HCI UART [EXPERIMENTAL]"
|
||||
depends on SERIAL
|
||||
depends on NET_BUF
|
||||
select EXPERIMENTAL
|
||||
help
|
||||
Use the HCI UART transport interface as the DTM transport layer.
|
||||
This option is inherited from SB_CONFIG_DTM_TRANSPORT_HCI.
|
||||
|
||||
if DTM_TRANSPORT_HCI
|
||||
|
||||
config DTM_HCI_QUEUE_COUNT
|
||||
int "Count of HCI RX/TX queues"
|
||||
default 16
|
||||
help
|
||||
Maximum depth of the HCI RX/TX queues.
|
||||
|
||||
config DTM_HCI_QUEUE_SIZE
|
||||
int "Size of HCI RX/TX queue buffer"
|
||||
default 1024
|
||||
help
|
||||
Maximum size of the HCI RX/TX queue element.
|
||||
|
||||
config DTM_HCI_TX_THREAD_STACK_SIZE
|
||||
int "Stack size of TX thread"
|
||||
default 2048
|
||||
help
|
||||
Stack size of the TX thread.
|
||||
|
||||
config DTM_HCI_TX_THREAD_PRIORITY
|
||||
int "TX thread priority"
|
||||
default 7
|
||||
help
|
||||
Priority of the TX thread.
|
||||
|
||||
endif # DTM_TRANSPORT_HCI
|
||||
|
||||
config DTM_POWER_CONTROL_AUTOMATIC
|
||||
bool "Automatic power control"
|
||||
depends on FEM
|
||||
default y
|
||||
help
|
||||
Set the SoC output power and the front-end module gain to achieve the TX output power
|
||||
requested by user. If the exact value cannot be achieved, power is set to the closest
|
||||
possible value. If this option is disabled, user can set the SoC output power and the
|
||||
front-end module gain with the separate vendor specific commands.
|
||||
|
||||
config DTM_FAST_RAMP_UP
|
||||
bool "Enable radio fast ramp up mode"
|
||||
default y
|
||||
help
|
||||
Do fast ramp up when starting the radio peripheral. This mode will significancy reduce
|
||||
the ramp up time and makes it almost the same on all supported chips.
|
||||
|
||||
module = DTM_TRANSPORT
|
||||
module-str = "DTM_transport"
|
||||
source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config"
|
||||
|
||||
source "Kconfig.zephyr"
|
||||
50
nordic/trezor/direct_test_mode/Kconfig.sysbuild
Normal file
50
nordic/trezor/direct_test_mode/Kconfig.sysbuild
Normal file
@@ -0,0 +1,50 @@
|
||||
#
|
||||
# Copyright (c) 2024 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
choice APPCORE
|
||||
default APPCORE_REMOTE_HCI if DTM_TRANSPORT_HCI
|
||||
default APPCORE_REMOTE_SHELL if SOC_NRF5340_CPUNET
|
||||
depends on SUPPORT_APPCORE
|
||||
|
||||
config APPCORE_REMOTE_HCI
|
||||
bool "remote_hci"
|
||||
depends on SOC_NRF5340_CPUNET
|
||||
help
|
||||
Include remote_hci as the appcore image to use
|
||||
|
||||
endchoice
|
||||
|
||||
config APPCORE_IMAGE_NAME
|
||||
default "remote_hci" if APPCORE_REMOTE_HCI
|
||||
|
||||
config APPCORE_IMAGE_PATH
|
||||
default "${ZEPHYR_NRF_MODULE_DIR}/samples/bluetooth/direct_test_mode/remote_hci" if APPCORE_REMOTE_HCI
|
||||
|
||||
choice DTM_TRANSPORT
|
||||
default DTM_TRANSPORT_TWOWIRE
|
||||
prompt "Transport layer to use with DTM"
|
||||
help
|
||||
Transport interface to use with the DTM.
|
||||
|
||||
config DTM_TRANSPORT_TWOWIRE
|
||||
bool "DTM over 2-wire UART"
|
||||
help
|
||||
Use the 2-wire transport interface as the DTM transport layer.
|
||||
|
||||
config DTM_TRANSPORT_HCI
|
||||
bool "DTM over HCI UART [EXPERIMENTAL]"
|
||||
select EXPERIMENTAL
|
||||
help
|
||||
Use the HCI UART transport interface as the DTM transport layer.
|
||||
|
||||
endchoice # DTM_TRANSPORT
|
||||
|
||||
config DTM_NO_DFE
|
||||
bool "Disable direction finding"
|
||||
help
|
||||
Disable direction finding feature.
|
||||
|
||||
source "${ZEPHYR_BASE}/share/sysbuild/Kconfig"
|
||||
623
nordic/trezor/direct_test_mode/README.rst
Normal file
623
nordic/trezor/direct_test_mode/README.rst
Normal file
@@ -0,0 +1,623 @@
|
||||
.. _direct_test_mode:
|
||||
|
||||
Bluetooth: Direct Test Mode
|
||||
###########################
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 2
|
||||
|
||||
This sample enables the Direct Test Mode functions described in `Bluetooth® Core Specification <Bluetooth Core Specification_>`_ (Vol. 6, Part F).
|
||||
|
||||
Requirements
|
||||
************
|
||||
|
||||
The sample supports the following development kits:
|
||||
|
||||
.. table-from-sample-yaml::
|
||||
|
||||
Additionally, the sample requires one of the following testing devices:
|
||||
|
||||
* Dedicated test equipment, like an Anritsu MT8852 tester.
|
||||
See :ref:`direct_test_mode_testing_anritsu`.
|
||||
* Another development kit with the same sample.
|
||||
See :ref:`direct_test_mode_testing_board`.
|
||||
* A computer with the `Direct Test Mode app`_ available in the `nRF Connect for Desktop`_.
|
||||
See :ref:`direct_test_mode_testing_app`.
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
The sample uses Direct Test Mode (DTM) to test the operation of the following features of the radio:
|
||||
|
||||
* Transmission power and receiver sensitivity
|
||||
* Frequency offset and drift
|
||||
* Modulation characteristics
|
||||
* Packet error rate
|
||||
* Intermodulation performance
|
||||
|
||||
Test procedures are defined in the document `Bluetooth Low Energy RF PHY Test Specification <Bluetooth Low Energy RF PHY Test Specification_>`_: Document number RF-PHY.TS.p15
|
||||
|
||||
You can carry out conformance tests using dedicated test equipment, such as the Anritsu MT8852 or similar, with an nRF5 running the DTM sample set as device under test (DUT).
|
||||
|
||||
Implementation
|
||||
==============
|
||||
|
||||
The DTM sample includes two parts:
|
||||
|
||||
* The Direct Test Mode library that manages the nRF radio and controls the standard DTM procedures.
|
||||
* A sample that provides an external interface to the library.
|
||||
|
||||
You can find the source code of both parts in :file:`samples/bluetooth/direct_test_mode/src`.
|
||||
If you use the experimental HCI interface on the |nRF5340DKnoref|, you can find additional source code in :file:`samples/bluetooth/direct_test_mode/remote_hci/src` and :file:`samples/bluetooth/direct_test_mode/rpc`.
|
||||
|
||||
This sample contains a driver for a 2-wire UART interface and an experimental HCI UART interface.
|
||||
Unless otherwise stated, all following commands and references describe the 2-wire interface.
|
||||
The 2-wire driver maps two-octet commands and events to the DTM library, as specified by the Bluetooth Low Energy DTM specification.
|
||||
The HCI driver accepts HCI commands in H4 format and implements a minimal set of HCI commands usually sufficient to run DTM testing.
|
||||
|
||||
.. figure:: /images/bt_dtm_dut.svg
|
||||
:alt: nRF5 with DTM as a DUT
|
||||
|
||||
The implementation is self-contained and requires no Bluetooth Low Energy protocol stack for its operation.
|
||||
The MPU is initialized in the standard way.
|
||||
The DTM library function :c:func:`dtm_init` configures all interrupts, timers, and the radio.
|
||||
|
||||
This sample may be extended with other interface implementations, such as an HCI interface, USB, or another interface required by the Upper Tester.
|
||||
The extension should be done by adding an appropriate interface implementation in the :file:`transport` directory.
|
||||
The transports must conform to the interface specified in the :file:`transport/dtm_transport.h` file.
|
||||
|
||||
The interface to the Lower Tester uses the antenna connector of the chosen development kit.
|
||||
While in principle an aerial connection might be used, conformance tests cover the reading of the transmission power delivered by the DUT.
|
||||
For this reason, a coaxial connection between the DUT and the Lower Tester is employed for all conformance testing.
|
||||
|
||||
DTM module interface
|
||||
====================
|
||||
|
||||
The DTM module interface can be divided into the following three parts:
|
||||
|
||||
* The :c:func:`dtm_init` initialization function
|
||||
* Setup functions:
|
||||
|
||||
* :c:func:`dtm_setup_reset`
|
||||
* :c:func:`dtm_setup_set_phy`
|
||||
* :c:func:`dtm_setup_set_modulation`
|
||||
* :c:func:`dtm_setup_read_features`
|
||||
* :c:func:`dtm_setup_read_max_supported_value`
|
||||
* :c:func:`dtm_setup_set_cte_mode`
|
||||
* :c:func:`dtm_setup_set_cte_slot`
|
||||
* :c:func:`dtm_setup_set_antenna_params`
|
||||
* :c:func:`dtm_setup_set_transmit_power`
|
||||
|
||||
* Test functions:
|
||||
|
||||
* :c:func:`dtm_test_receive`
|
||||
* :c:func:`dtm_test_transmit`
|
||||
* :c:func:`dtm_test_end`
|
||||
|
||||
The setup functions implement the DTM setup required by the Bluetooth Low Energy standard.
|
||||
The test functions implement the tests defined by the Bluetooth Low Energy standard.
|
||||
|
||||
The sample is required to perform the following tasks:
|
||||
|
||||
* To parse the relevant encoding format - UART or HCI - for the command, and to use the DTM module interface accordingly.
|
||||
* To interpret the return values of interface functions used in the DTM module, and to respond to the tester in the correct format.
|
||||
|
||||
.. figure:: /images/bt_dtm_engine.svg
|
||||
:alt: State machine overview of the DTM
|
||||
|
||||
Supported PHYs
|
||||
==============
|
||||
|
||||
The DTM sample supports all four PHYs specified in DTM, but not all devices support all the PHYs.
|
||||
|
||||
.. list-table:: Supported PHYs
|
||||
:header-rows: 1
|
||||
|
||||
* - PHY
|
||||
- nRF5340
|
||||
* - LE 1M
|
||||
- Yes
|
||||
* - LE 2M
|
||||
- Yes
|
||||
* - LE Coded S=8
|
||||
- Yes
|
||||
* - LE Coded S=2
|
||||
- Yes
|
||||
|
||||
TX output power
|
||||
===============
|
||||
|
||||
This sample has several ways to set the device output power.
|
||||
The behavior of the commands vary depending on the hardware configuration and Kconfig options as follows:
|
||||
|
||||
* DTM without front-end module support:
|
||||
|
||||
* The official ``0x09`` DTM command sets the SoC TX output power closest to the requested one when the exact power level is not supported.
|
||||
* The ``SET_TX_POWER`` vendor-specific command sets the SoC TX output power.
|
||||
You must use only the TX power values supported by your SoC.
|
||||
See the actual values in the SoC Product Specification.
|
||||
|
||||
* DTM with front-end module support:
|
||||
|
||||
* When the :ref:`CONFIG_DTM_POWER_CONTROL_AUTOMATIC <CONFIG_DTM_POWER_CONTROL_AUTOMATIC>` Kconfig option is enabled (default), the official ``0x09`` DTM command sets the final output power to the desired, or the closest available value by configuring the SoC output power and the front-end module gain automatically.
|
||||
|
||||
.. note::
|
||||
The returned output power using this command is valid only for channel 0.
|
||||
If you perform the test on a different channel than the real output power measured by your tester device, it can be equal or less than the returned one.
|
||||
This is because the DTM specification has a limitation when it assumes that output power is the same for all channels.
|
||||
That is why the chosen output power might not be available for the given channel.
|
||||
|
||||
* When the :ref:`CONFIG_DTM_POWER_CONTROL_AUTOMATIC <CONFIG_DTM_POWER_CONTROL_AUTOMATIC>` Kconfig option is disabled, the official ``0x09`` DTM command sets only the SoC output power.
|
||||
These commands behave in the same way for the DTM without front-end module support.
|
||||
Additionally, you can use following vendor-specific commands:
|
||||
|
||||
* The ``SET_TX_POWER`` command sets the SoC TX output power.
|
||||
* The ``FEM_TX_POWER_CONTROL_SET`` command sets the front-end module gain.
|
||||
|
||||
Bluetooth Direction Finding support
|
||||
===================================
|
||||
|
||||
The DTM sample supports all Bluetooth Direction Finding modes specified in DTM.
|
||||
|
||||
.. list-table:: Supported Bluetooth Direction Finding modes
|
||||
:header-rows: 1
|
||||
|
||||
* - Direction Finding mode
|
||||
- nRF5340
|
||||
* - AoD 1 us slot
|
||||
- Yes
|
||||
* - AoD 2 us slot
|
||||
- Yes
|
||||
* - AoA
|
||||
- Yes
|
||||
|
||||
The following antenna switching patterns are possible:
|
||||
|
||||
* 1, 2, 3, ..., N
|
||||
* 1, 2, 3, ..., N, N - 1, N - 2, ..., 1
|
||||
|
||||
The application supports a maximum of 19 antennas in the direction finding mode.
|
||||
The radio can control up to eight GPIO pins for the purpose of controlling the external antenna switches used in direction finding.
|
||||
|
||||
Antenna matrix configuration
|
||||
----------------------------
|
||||
|
||||
To use this sample to test the Bluetooth Direction Finding feature, additional configuration of GPIOs is required to control the antenna array.
|
||||
An example of such configuration is provided in a devicetree overlay file :file:`nrf5340dk_nrf5340_cpunet.overlay`.
|
||||
|
||||
The overlay file provides the information about of the GPIOs to be used by the Radio peripheral to switch between antenna patches during the Constant Tone Extension (CTE) reception or transmission.
|
||||
At least one GPIO must be provided to enable antenna switching.
|
||||
|
||||
The GPIOs are used by the radio peripheral in the order provided by the ``dfegpio#-gpios`` properties.
|
||||
The order is important because it has an impact to the mapping of the antenna switching patterns to GPIOs (see `Antenna patterns`_).
|
||||
|
||||
To test Direction Finding, provide the following data related to antenna matrix design:
|
||||
|
||||
* GPIO pins to ``dfegpio#-gpios`` properties in the :file:`nrf5340dk_nrf5340_cpunet.overlay` file.
|
||||
* The default antenna to be used to receive the PDU ``dfe-pdu-antenna`` property in the :file:`nrf5340dk_nrf5340_cpunet.overlay` file.
|
||||
|
||||
.. note::
|
||||
The PDU antenna is also used for the reference period transmission and reception.
|
||||
|
||||
Antenna patterns
|
||||
----------------
|
||||
|
||||
The antenna switching pattern is a binary number where each bit is applied to a particular antenna GPIO pin.
|
||||
For example, the pattern ``0x3`` means that antenna GPIOs at index ``0,1`` is set, while the next ones are left unset.
|
||||
|
||||
This also means that, for example, when using four GPIOs, the pattern count cannot be greater than 16 and the maximum allowed value is 15.
|
||||
|
||||
If the number of switch-sample periods is greater than the number of stored switching patterns, the radio loops back to the first pattern.
|
||||
|
||||
The following table presents the patterns that you can use to switch antennas on the Nordic-designed antenna matrix:
|
||||
|
||||
+--------+--------------+
|
||||
|Antenna | PATTERN[3:0] |
|
||||
+========+==============+
|
||||
| ANT_12 | 0 (0b0000) |
|
||||
+--------+--------------+
|
||||
| ANT_10 | 1 (0b0001) |
|
||||
+--------+--------------+
|
||||
| ANT_11 | 2 (0b0010) |
|
||||
+--------+--------------+
|
||||
| RFU | 3 (0b0011) |
|
||||
+--------+--------------+
|
||||
| ANT_3 | 4 (0b0100) |
|
||||
+--------+--------------+
|
||||
| ANT_1 | 5 (0b0101) |
|
||||
+--------+--------------+
|
||||
| ANT_2 | 6 (0b0110) |
|
||||
+--------+--------------+
|
||||
| RFU | 7 (0b0111) |
|
||||
+--------+--------------+
|
||||
| ANT_6 | 8 (0b1000) |
|
||||
+--------+--------------+
|
||||
| ANT_4 | 9 (0b1001) |
|
||||
+--------+--------------+
|
||||
| ANT_5 | 10 (0b1010) |
|
||||
+--------+--------------+
|
||||
| RFU | 11 (0b1011) |
|
||||
+--------+--------------+
|
||||
| ANT_9 | 12 (0b1100) |
|
||||
+--------+--------------+
|
||||
| ANT_7 | 13 (0b1101) |
|
||||
+--------+--------------+
|
||||
| ANT_8 | 14 (0b1110) |
|
||||
+--------+--------------+
|
||||
| RFU | 15 (0b1111) |
|
||||
+--------+--------------+
|
||||
|
||||
nRF21540 front-end module
|
||||
=========================
|
||||
|
||||
.. include:: /includes/sample_dtm_radio_test_fem.txt
|
||||
|
||||
You can configure the transmitted power gain, antenna output and activation delay in nRF21540 using vendor-specific commands, see `Vendor-specific packet payload`_.
|
||||
|
||||
Skyworks front-end module
|
||||
=========================
|
||||
|
||||
.. include:: /includes/sample_dtm_radio_test_skyworks.txt
|
||||
|
||||
You can configure the antenna output and activation delay for the Skyworks front-end module (FEM) using vendor-specific commands, see `Vendor-specific packet payload`_.
|
||||
|
||||
Vendor-specific packet payload
|
||||
==============================
|
||||
|
||||
The Bluetooth Low Energy 2-wire UART DTM interface standard reserves the Packet Type, also called payload parameter, with binary value ``11`` for a Vendor Specific packet payload.
|
||||
|
||||
The DTM command is interpreted as vendor-specific when both of the following conditions are met:
|
||||
|
||||
* Its CMD field is set to Transmitter Test, binary ``10``.
|
||||
* Its PKT field is set to vendor-specific, binary ``11``.
|
||||
|
||||
Vendor-specific commands can be divided into different categories as follows:
|
||||
|
||||
* If the **Length** field is set to ``0`` (symbol ``CARRIER_TEST``), an unmodulated carrier is turned on at the channel indicated by the **Frequency** field.
|
||||
It remains turned on until a ``TEST_END`` or ``RESET`` command is issued.
|
||||
* If the **Length** field is set to ``1`` (symbol ``CARRIER_TEST_STUDIO``), the field value is used by the nRFgo Studio to indicate that an unmodulated carrier is turned on at the channel.
|
||||
It remains turned on until a ``TEST_END`` or ``RESET`` command is issued.
|
||||
* If the **Length** field is set ``2`` (symbol ``SET_TX_POWER``), the **Frequency** field sets the TX power in dBm.
|
||||
The valid TX power values are specified in the product specification ranging from -40 to +4, where ``0`` dBm is the reset value.
|
||||
Only the six least significant bits will fit in the **Length** field.
|
||||
The two most significant bits are calculated by the DTM module.
|
||||
This is possible because the six least significant bits of all valid TX power values are unique.
|
||||
The TX power can be modified only when no Transmitter Test or Receiver Test is running.
|
||||
* If the **Length** field is set to ``3`` (symbol ``FEM_ANTENNA_SELECT``), the **Frequency** field sets the front-end module (FEM) antenna output.
|
||||
The valid values are:
|
||||
|
||||
* ``0`` - ANT1 enabled, ANT2 disabled
|
||||
* ``1`` - ANT1 disabled, ANT2 enabled
|
||||
|
||||
* If the **Length** field is set to ``4`` (symbol ``FEM_TX_POWER_CONTROL_SET``), the **Frequency** field sets the front-end module (FEM) TX power control value and is specific to the FEM type in use.
|
||||
The valid gain values are specified in your product-specific front-end module (FEM).
|
||||
For example, in the nRF21540 front-end module with GPIO interface, the tx power control range is 0 (POUTA) to 1 (POUTB).
|
||||
For example, in the nRF21540 front-end module with GPIO/SPI, the tx power control range is 0 - 31 and is the value of TX_GAIN field of CONFREG0 register.
|
||||
* If the **Length** field is set to ``5`` (symbol ``FEM_ACTIVE_DELAY_SET``), the **Frequency** field sets the front-end module (FEM) activation delay in microseconds relative to the radio start.
|
||||
By default, this value is set to ``radio ramp-up time - front-end module (FEM) TX/RX settling time``.
|
||||
* If the **Length** field is set to ``6`` (symbol ``FEM_DEFAULT_PARAMS_SET``) and the **Frequency** field to any value, the front-end module parameters, such as ``antenna output``, ``gain``, and ``delay``, are set to their default values.
|
||||
* All other values of **Frequency** and **Length** field are reserved.
|
||||
|
||||
.. note::
|
||||
Front-end module configuration parameters, such as ``antenna output``, ``gain``, and ``active delay``, are not set to their default values after the DTM reset command.
|
||||
Testers, for example Anritsu MT8852, issue a reset command at the beginning of every test.
|
||||
Therefore, you cannot run automated test scripts for front-end modules with other than the default parameters.
|
||||
|
||||
If you have changed the default parameters of the front-end module, you can restore them.
|
||||
You can either send the ``FEM_DEFAULT_PARAMS_SET`` command or power cycle the front-end module.
|
||||
|
||||
.. note::
|
||||
When you build the DTM sample with support for front-end modules and the :ref:`CONFIG_DTM_POWER_CONTROL_AUTOMATIC <CONFIG_DTM_POWER_CONTROL_AUTOMATIC>` Kconfig option is enabled, the following vendor-specific command are not available:
|
||||
|
||||
* ``SET_TX_POWER``
|
||||
* ``FEM_TX_POWER_CONTROL_SET``
|
||||
|
||||
You can disable the :ref:`CONFIG_DTM_POWER_CONTROL_AUTOMATIC <CONFIG_DTM_POWER_CONTROL_AUTOMATIC>` Kconfig option if you want to set the SoC output power and the front-end module gain by separate commands.
|
||||
The official DTM command ``0x09`` for setting power level takes into account the SoC output power and the front-end module gain to set the total requested output power.
|
||||
|
||||
The DTM-to-Serial adaptation layer
|
||||
==================================
|
||||
|
||||
The :file:`dtm_uart_twowire.c` file is an implementation of the UART interface specified in the `Bluetooth Core Specification`_, Volume 6, Part F, Chapter 3.
|
||||
|
||||
The :file:`dtm_hci.c` and :file:`hci_uart.c` files are an implementation of the HCI UART interface specified in the `Bluetooth Core Specification`_, Volume 4, Part A (the flow control can be configured by an overlay file).
|
||||
|
||||
The default selection of UART pins is defined in :file:`zephyr/boards/arm/board_name/board_name.dts`.
|
||||
You can change the defaults using the symbols ``tx-pin`` and ``rx-pin`` in the DTS overlay file of the child image at the project level.
|
||||
The configuration files for the :ref:`nrf5340_remote_shell` subimage are located in the :file:`child_image/remote_shell` or :file:`sysbuild/remote_shell` directory.
|
||||
The HCI interface allows for a custom ``remote_hci`` image to be used with |nRF5340DKnoref|.
|
||||
|
||||
.. note::
|
||||
On the nRF5340 development kit, the physical UART interface of the application core is used for communication with the tester device.
|
||||
This sample uses the :ref:`uart_ipc` for sending responses and receiving commands through the UART interface of the application core.
|
||||
|
||||
Debugging
|
||||
*********
|
||||
|
||||
In this sample, the UART console is used to exchange commands and events defined in the DTM specification.
|
||||
Debug messages are not displayed in the 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`.
|
||||
For more information about debugging in the |NCS|, see :ref:`debugging`.
|
||||
|
||||
Configuration
|
||||
*************
|
||||
|config|
|
||||
|
||||
Configuration options
|
||||
=====================
|
||||
|
||||
The following configuration parameters are associated with this sample:
|
||||
|
||||
.. _CONFIG_DTM_POWER_CONTROL_AUTOMATIC:
|
||||
|
||||
CONFIG_DTM_POWER_CONTROL_AUTOMATIC - Automatic power control
|
||||
Sets the SoC output power and the front-end module gain to achieve the TX output power requested by the user.
|
||||
If the exact value cannot be achieved, power is set to the closest possible value.
|
||||
If this option is disabled, you can set the SoC output power and the front-end module gain with the separate vendor-specific commands.
|
||||
|
||||
Building and running
|
||||
********************
|
||||
|
||||
.. |sample path| replace:: :file:`samples/bluetooth/direct_test_mode`
|
||||
|
||||
.. include:: /includes/build_and_run.txt
|
||||
|
||||
.. include:: /includes/nRF54H20_erase_UICR.txt
|
||||
|
||||
.. note::
|
||||
On the nRF5340 development kit, this sample requires the :ref:`nrf5340_remote_shell` sample on the application core.
|
||||
The Remote IPC shell sample is built and programmed automatically by default.
|
||||
|
||||
Disabling Direction Finding feature
|
||||
===================================
|
||||
|
||||
To build the sample without support for the Direction Finding feature, use the following command for the correct *board_target*:
|
||||
|
||||
.. parsed-literal::
|
||||
:class: highlight
|
||||
|
||||
west build samples/bluetooth/direct_test_mode -b *board_target* -- -DSB_CONFIG_DTM_NO_DFE=y
|
||||
|
||||
Experimental HCI interface
|
||||
==========================
|
||||
|
||||
To build the sample with an HCI interface, use the following command for the correct *board_target*:
|
||||
|
||||
.. parsed-literal::
|
||||
:class: highlight
|
||||
|
||||
west build samples/bluetooth/direct_test_mode -b *board_target* -- -DFILE_SUFFIX=hci
|
||||
|
||||
On the |nRF5340DKnoref|, you can build the sample with HCI interface with the ``remote_hci`` image using the same command.
|
||||
|
||||
USB CDC ACM transport variant
|
||||
=============================
|
||||
|
||||
On the nRF5340 development kit, you can build this sample configured to use the USB interface as a communication interface with the tester.
|
||||
Use the following command:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
west build samples/bluetooth/direct_test_mode -b nrf5340dk/nrf5340/cpunet -- -DFILE_SUFFIX=usb
|
||||
|
||||
You can also build this sample with support for the front-end module.
|
||||
Use the following command:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
west build samples/bluetooth/direct_test_mode -b nrf5340dk/nrf5340/cpunet -- -DSHIELD=nrf21540ek -DFILE_SUFFIX=usb
|
||||
|
||||
.. _dtm_testing:
|
||||
|
||||
Testing
|
||||
=======
|
||||
|
||||
After programming the sample to your development kit, you can test it in three ways, as described in the following chapters.
|
||||
|
||||
.. note::
|
||||
For the |nRF5340DKnoref|, see :ref:`logging_cpunet` for information about the COM terminals on which the logging output is available.
|
||||
|
||||
.. note::
|
||||
|54H_engb_2_8|
|
||||
|
||||
.. _direct_test_mode_testing_anritsu:
|
||||
|
||||
Testing with a certified tester
|
||||
-------------------------------
|
||||
|
||||
Conformance testing is performed using a certified tester.
|
||||
The setup depends on the tester used, and details about the test operation must be found in the tester documentation.
|
||||
|
||||
The Application note `nAN34`_ describes two alternatives for setting up a production test with DTM using one of our old devices.
|
||||
|
||||
.. _direct_test_mode_testing_board:
|
||||
|
||||
Testing with another development kit
|
||||
------------------------------------
|
||||
|
||||
1. Connect both development kits to the computer using a USB cable.
|
||||
The computer assigns to the development kit a COM port on Windows or a ttyACM device on Linux, which is visible in the Device Manager.
|
||||
#. Connect to both kits with a terminal emulator.
|
||||
See `Direct Test Mode terminal connection`_ for the required settings.
|
||||
#. Start ``TRANSMITTER_TEST`` by sending the ``0x80 0x96`` DTM command to one of the connected development kits.
|
||||
This command will trigger TX activity on the 2402 MHz frequency (1st channel) with ``10101010`` packet pattern and 37-byte packet length.
|
||||
#. Observe that you received the ``TEST_STATUS_EVENT`` packet in response with the SUCCESS status field: ``0x00 0x00``.
|
||||
#. Start ``RECEIVER_TEST`` by sending the ``0x40 0x96`` DTM command to the second development kit.
|
||||
Command parameters are identical to the ones used for the ``TRANSMITTER_TEST`` command.
|
||||
#. Observe that you received the ``TEST_STATUS_EVENT`` packet in response with the SUCCESS status field: ``0x00 0x00``.
|
||||
#. Finish RX testing using the ``TEST_END DTM`` command by sending the ``0xC0 0x00`` packet.
|
||||
#. Observe that you received the ``PACKET_REPORTING_EVENT`` packet in response.
|
||||
For example, the ``0xD6 0xAC`` message indicates that 22188 Radio packets have been received.
|
||||
#. Experiment with other combinations of commands and their parameters.
|
||||
|
||||
.. _direct_test_mode_testing_app:
|
||||
|
||||
Testing with Direct Test Mode app
|
||||
---------------------------------
|
||||
|
||||
1. |connect_kit|
|
||||
#. Connect the kit with a terminal emulator that supports encoding and decoding in the HEX format.
|
||||
See `Direct Test Mode terminal connection`_ for the required settings.
|
||||
#. Start the ``TRANSMITTER_TEST`` by sending the ``0x80 0x96`` DTM command to the connected development kit.
|
||||
This command triggers TX activity on 2402 MHz frequency (1st channel) with ``10101010`` packet pattern and 37-byte packet length.
|
||||
#. Observe that you received the ``TEST_STATUS_EVENT`` packet in response with the SUCCESS status field: ``0x00 0x00``.
|
||||
#. Start the `Direct Test Mode app`_ in `nRF Connect for Desktop`_ and select the development kit to communicate with.
|
||||
#. Set the Receiver mode and 37th channel in the test configuration menu.
|
||||
#. Start the test.
|
||||
#. On the application chart, observe that the number of RX packets is increasing for the 2402 MHz channel.
|
||||
#. Stop the test.
|
||||
#. Swap roles.
|
||||
Set the application to the RX mode and the connected development kit to the TX mode.
|
||||
|
||||
Direct Test Mode terminal connection
|
||||
------------------------------------
|
||||
|
||||
To send commands to and receive responses from the development kit that runs the Direct Test Mode sample, connect to it with RealTerm in Windows or Minicom in Linux.
|
||||
|
||||
The Bluetooth Low Energy DTM UART interface standard specifies the following configuration:
|
||||
|
||||
* Eight data bits
|
||||
* No parity
|
||||
* One stop bit
|
||||
* No hardware flow control
|
||||
* A selection of bit rates from 9600 to 1000000, one of which must be supported by the DUT.
|
||||
It might be possible to run other bit rates by experimenting with parameters.
|
||||
|
||||
.. note::
|
||||
The default bit rate of the DTM UART driver is 19200 bps, which is supported by most certified testers.
|
||||
|
||||
When using a 2-wire interface, you must send all commands as two-byte HEX numbers.
|
||||
The responses must have the same format.
|
||||
|
||||
Connect with RealTerm (Windows)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The RealTerm terminal program offers a graphical interface for setting up your connection.
|
||||
|
||||
.. figure:: /images/realterm.png
|
||||
:alt: RealTerm start window
|
||||
|
||||
The RealTerm start window
|
||||
|
||||
To test DTM with RealTerm, complete the following steps:
|
||||
|
||||
1. On the :guilabel:`Display` tab, set **Display As** to **Hex[space]**.
|
||||
|
||||
.. figure:: /images/realterm_hex_display.png
|
||||
:alt: Set the RealTerm display format
|
||||
|
||||
#. Open the :guilabel:`Port` tab and configure the serial port parameters:
|
||||
|
||||
a. Set the **Baud** to ``19200`` **(1)**.
|
||||
#. Select your J-Link serial port from the **Port** list **(2)**.
|
||||
#. Set the port status to ``Open`` **(3)**.
|
||||
|
||||
.. figure:: /images/real_term_serial_port.png
|
||||
:alt: RealTerm serial port settings
|
||||
|
||||
#. Open the :guilabel:`Send` tab:
|
||||
|
||||
a. Write the command as a hexadecimal number in the field **(1)**.
|
||||
For example, write ``0x00 0x00`` to send a **Reset** command.
|
||||
#. Click the :guilabel:`Send Numbers` button **(2)** to send the command.
|
||||
#. Observe the response in the DTM in area **(3)**.
|
||||
The response is encoded as hexadecimal numbers.
|
||||
|
||||
.. figure:: /images/realterm_commands.png
|
||||
:alt: RealTerm commands sending
|
||||
|
||||
Connect with Minicom (Linux)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Minicom is a serial communication program that connects to the DTM device.
|
||||
|
||||
On the Linux operating system, install a Minicom terminal.
|
||||
On Ubuntu, run:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
sudo apt-get install minicom
|
||||
|
||||
1. Run the Minicom terminal:
|
||||
|
||||
.. parsed-literal::
|
||||
:class: highlight
|
||||
|
||||
sudo minicom -D *DTM serial port* -s
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
sudo minicom -D /dev/serial/by-id/usb-SEGGER_J-Link_000683580193-if00 -s
|
||||
|
||||
The **-s** option switches you to Minicom setup mode.
|
||||
|
||||
#. Configure the Minicom terminal:
|
||||
|
||||
.. figure:: /images/minicom_setup_window.png
|
||||
:alt: minicom configuration window
|
||||
|
||||
Configuration window
|
||||
|
||||
a. Select :guilabel:`Serial port setup` and set UART baudrate to ``19200``.
|
||||
|
||||
.. figure:: /images/minicom_serial_port.png
|
||||
:alt: minicom serial port settings
|
||||
|
||||
#. Select :guilabel:`Screen and keyboard` and press S on the keyboard to enable the **Hex Display**.
|
||||
#. Press Q on the keyboard to enable **Local echo**.
|
||||
|
||||
.. figure:: /images/minicom_terminal_cfg.png
|
||||
:alt: minicom terminal screen and keyboard settings
|
||||
|
||||
Minicom is now configured for receiving data.
|
||||
However, you cannot use it for sending DTM commands.
|
||||
|
||||
#. Send DTM commands:
|
||||
|
||||
To send DTM commands, use ``echo`` with ``-ne`` options in another terminal.
|
||||
You must encode the data as hexadecimal numbers (\xHH, byte with hexadecimal value HH, 1 to 2 digits).
|
||||
|
||||
.. parsed-literal::
|
||||
:class: highlight
|
||||
|
||||
sudo echo -ne "*encoded command*" > *DTM serial port*
|
||||
|
||||
To send a **Reset** command, for example, run the following command:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
sudo echo -ne "\x00\x00" > /dev/serial/by-id/usb-SEGGER_J-Link_000683580193-if00
|
||||
|
||||
Dependencies
|
||||
************
|
||||
|
||||
This sample uses the following |NCS| library:
|
||||
|
||||
* :ref:`fem_al_lib`
|
||||
|
||||
This sample uses the following |NCS| driver:
|
||||
|
||||
* :ref:`uart_ipc`
|
||||
|
||||
This sample has the following nrfx dependencies:
|
||||
|
||||
* :file:`nrfx/drivers/include/nrfx_timer.h`
|
||||
* :file:`nrfx/hal/nrf_nvmc.h`
|
||||
* :file:`nrfx/hal/nrf_radio.h`
|
||||
* :file:`nrfx/helpers/nrfx_gppi.h`
|
||||
|
||||
The sample also has the following nrfxlib dependency:
|
||||
|
||||
* :ref:`nrfxlib:mpsl_fem`
|
||||
|
||||
In addition, it has the following Zephyr dependencies:
|
||||
|
||||
* :ref:`zephyr:device_model_api`:
|
||||
|
||||
* :file:`drivers/clock_control.h`
|
||||
* :file:`drivers/uart.h`
|
||||
5
nordic/trezor/direct_test_mode/VERSION
Normal file
5
nordic/trezor/direct_test_mode/VERSION
Normal file
@@ -0,0 +1,5 @@
|
||||
VERSION_MAJOR = 0
|
||||
VERSION_MINOR = 1
|
||||
PATCHLEVEL = 0
|
||||
VERSION_TWEAK = 0
|
||||
EXTRAVERSION =
|
||||
10
nordic/trezor/direct_test_mode/app.overlay
Normal file
10
nordic/trezor/direct_test_mode/app.overlay
Normal file
@@ -0,0 +1,10 @@
|
||||
/ {
|
||||
chosen {
|
||||
ncs,dtm-uart = &uart0;
|
||||
};
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
status = "okay";
|
||||
current-speed = <19200>;
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Copyright (c) 2021 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
# Use an additional timer for Anomaly 172
|
||||
CONFIG_NRFX_TIMER3=y
|
||||
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Copyright (c) 2021 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
# Use an additional timer for Anomaly 172
|
||||
CONFIG_NRFX_TIMER3=y
|
||||
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# Copyright (c) 2021 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
CONFIG_IPC_UART=y
|
||||
CONFIG_IPC_SERVICE=y
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG=y
|
||||
CONFIG_MBOX=y
|
||||
|
||||
CONFIG_NRFX_GPPI=y
|
||||
|
||||
CONFIG_HEAP_MEM_POOL_SIZE=4096
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
ncs,dtm-uart = &uart_ipc;
|
||||
};
|
||||
|
||||
uart_ipc: uart_ipc {
|
||||
status = "okay";
|
||||
compatible = "nordic,nrf-ipc-uart";
|
||||
ipc = <&ipc0>;
|
||||
ept-name = "remote shell";
|
||||
current-speed = <19200>;
|
||||
};
|
||||
};
|
||||
|
||||
&radio {
|
||||
status = "okay";
|
||||
/* This is a number of antennas that are available on antenna matrix
|
||||
* designed by Nordic. For more information see README.rst.
|
||||
*/
|
||||
dfe-antenna-num = <12>;
|
||||
/* This is a setting that enables antenna 12 (in antenna matrix designed
|
||||
* by Nordic) for PDU. For more information see README.rst.
|
||||
*/
|
||||
dfe-pdu-antenna = <0x0>;
|
||||
|
||||
/* These are GPIO pin numbers that are provided to
|
||||
* Radio peripheral. The pins will be acquired by Radio to
|
||||
* drive antenna switching.
|
||||
* Pin numbers are selected to drive switches on antenna matrix
|
||||
* desinged by Nordic. For more information see README.rst.
|
||||
*/
|
||||
dfegpio0-gpios = <&gpio0 4 0>;
|
||||
dfegpio1-gpios = <&gpio0 5 0>;
|
||||
dfegpio2-gpios = <&gpio0 6 0>;
|
||||
dfegpio3-gpios = <&gpio0 7 0>;
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# Copyright (c) 2021 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
CONFIG_IPC_SERVICE=y
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG=y
|
||||
CONFIG_MBOX=y
|
||||
|
||||
CONFIG_NRFX_GPPI=y
|
||||
|
||||
CONFIG_HEAP_MEM_POOL_SIZE=4096
|
||||
|
||||
CONFIG_NRF_RPC=y
|
||||
CONFIG_NRF_RPC_CBOR=y
|
||||
|
||||
CONFIG_NET_BUF=y
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
&radio {
|
||||
status = "okay";
|
||||
/* This is a number of antennas that are available on antenna matrix
|
||||
* designed by Nordic. For more information see README.rst.
|
||||
*/
|
||||
dfe-antenna-num = <12>;
|
||||
/* This is a setting that enables antenna 12 (in antenna matrix designed
|
||||
* by Nordic) for PDU. For more information see README.rst.
|
||||
*/
|
||||
dfe-pdu-antenna = <0x0>;
|
||||
|
||||
/* These are GPIO pin numbers that are provided to
|
||||
* Radio peripheral. The pins will be acquired by Radio to
|
||||
* drive antenna switching.
|
||||
* Pin numbers are selected to drive switches on antenna matrix
|
||||
* desinged by Nordic. For more information see README.rst.
|
||||
*/
|
||||
dfegpio0-gpios = <&gpio0 4 0>;
|
||||
dfegpio1-gpios = <&gpio0 5 0>;
|
||||
dfegpio2-gpios = <&gpio0 6 0>;
|
||||
dfegpio3-gpios = <&gpio0 7 0>;
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# Copyright (c) 2024 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
# Disable the unsupported driver
|
||||
CONFIG_NRFX_TIMER0=n
|
||||
CONFIG_NRFX_TIMER1=n
|
||||
CONFIG_NRFX_TIMER2=n
|
||||
|
||||
# Use necessary peripherals
|
||||
CONFIG_NRFX_TIMER020=y
|
||||
CONFIG_NRFX_TIMER021=y
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
ncs,dtm-uart = &uart136;
|
||||
};
|
||||
};
|
||||
|
||||
&uart135 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&uart136 {
|
||||
status = "okay";
|
||||
memory-regions = <&cpurad_dma_region>;
|
||||
current-speed = <19200>;
|
||||
};
|
||||
|
||||
&dppic020 {
|
||||
status = "okay";
|
||||
source-channels = < 0 1 >;
|
||||
sink-channels = < 2 3 >;
|
||||
};
|
||||
|
||||
&radio {
|
||||
status = "okay";
|
||||
/* This is a number of antennas that are available on antenna matrix
|
||||
* designed by Nordic. For more information see README.rst.
|
||||
*/
|
||||
dfe-antenna-num = <12>;
|
||||
/* This is a setting that enables antenna 12 (in antenna matrix designed
|
||||
* by Nordic) for PDU. For more information see README.rst.
|
||||
*/
|
||||
dfe-pdu-antenna = <0x0>;
|
||||
|
||||
/* These are GPIO pin numbers that are provided to
|
||||
* Radio peripheral. The pins will be acquired by Radio to
|
||||
* drive antenna switching.
|
||||
* Pin numbers are selected to drive switches on antenna matrix
|
||||
* desinged by Nordic. For more information see README.rst.
|
||||
*/
|
||||
dfegpio0-gpios = <&gpio0 4 0>;
|
||||
dfegpio1-gpios = <&gpio0 5 0>;
|
||||
dfegpio2-gpios = <&gpio0 6 0>;
|
||||
dfegpio3-gpios = <&gpio0 7 0>;
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
#
|
||||
# Copyright (c) 2024 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
# Disable the unsupported driver
|
||||
CONFIG_NRFX_TIMER0=n
|
||||
CONFIG_NRFX_TIMER1=n
|
||||
CONFIG_NRFX_TIMER2=n
|
||||
|
||||
# Use necessary peripherals
|
||||
CONFIG_NRFX_TIMER20=y
|
||||
CONFIG_NRFX_TIMER10=y
|
||||
CONFIG_NRFX_GPPI=y
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
ncs,dtm-uart = &uart20;
|
||||
};
|
||||
};
|
||||
|
||||
&uart20 {
|
||||
status = "okay";
|
||||
current-speed = <19200>;
|
||||
};
|
||||
|
||||
&radio {
|
||||
status = "okay";
|
||||
/* This is a number of antennas that are available on antenna matrix
|
||||
* designed by Nordic. For more information see README.rst.
|
||||
*/
|
||||
dfe-antenna-num = <12>;
|
||||
/* This is a setting that enables antenna 12 (in antenna matrix designed
|
||||
* by Nordic) for PDU. For more information see README.rst.
|
||||
*/
|
||||
dfe-pdu-antenna = <0x0>;
|
||||
|
||||
/* These are GPIO pin numbers that are provided to
|
||||
* Radio peripheral. The pins will be acquired by Radio to
|
||||
* drive antenna switching.
|
||||
* Pin numbers are selected to drive switches on antenna matrix
|
||||
* desinged by Nordic. For more information see README.rst.
|
||||
*/
|
||||
dfegpio0-gpios = <&gpio0 4 0>;
|
||||
dfegpio1-gpios = <&gpio0 5 0>;
|
||||
dfegpio2-gpios = <&gpio0 6 0>;
|
||||
dfegpio3-gpios = <&gpio0 7 0>;
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
#
|
||||
# Copyright (c) 2024 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
# Disable the unsupported driver
|
||||
CONFIG_NRFX_TIMER0=n
|
||||
CONFIG_NRFX_TIMER1=n
|
||||
CONFIG_NRFX_TIMER2=n
|
||||
|
||||
# Use necessary peripherals
|
||||
CONFIG_NRFX_TIMER20=y
|
||||
CONFIG_NRFX_TIMER10=y
|
||||
CONFIG_NRFX_GPPI=y
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
ncs,dtm-uart = &uart20;
|
||||
};
|
||||
};
|
||||
|
||||
&uart20 {
|
||||
status = "okay";
|
||||
current-speed = <19200>;
|
||||
};
|
||||
|
||||
&radio {
|
||||
status = "okay";
|
||||
/* This is a number of antennas that are available on antenna matrix
|
||||
* designed by Nordic. For more information see README.rst.
|
||||
*/
|
||||
dfe-antenna-num = <12>;
|
||||
/* This is a setting that enables antenna 12 (in antenna matrix designed
|
||||
* by Nordic) for PDU. For more information see README.rst.
|
||||
*/
|
||||
dfe-pdu-antenna = <0x0>;
|
||||
|
||||
/* These are GPIO pin numbers that are provided to
|
||||
* Radio peripheral. The pins will be acquired by Radio to
|
||||
* drive antenna switching.
|
||||
* Pin numbers are selected to drive switches on antenna matrix
|
||||
* desinged by Nordic. For more information see README.rst.
|
||||
*/
|
||||
dfegpio0-gpios = <&gpio0 4 0>;
|
||||
dfegpio1-gpios = <&gpio0 5 0>;
|
||||
dfegpio2-gpios = <&gpio0 6 0>;
|
||||
dfegpio3-gpios = <&gpio0 7 0>;
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
#
|
||||
# Copyright (c) 2024 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
# Disable the unsupported driver
|
||||
CONFIG_NRFX_TIMER0=n
|
||||
CONFIG_NRFX_TIMER1=n
|
||||
CONFIG_NRFX_TIMER2=n
|
||||
|
||||
# Use necessary peripherals
|
||||
CONFIG_NRFX_TIMER20=y
|
||||
CONFIG_NRFX_TIMER10=y
|
||||
CONFIG_NRFX_GPPI=y
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
ncs,dtm-uart = &uart20;
|
||||
};
|
||||
};
|
||||
|
||||
&uart20 {
|
||||
status = "okay";
|
||||
current-speed = <19200>;
|
||||
};
|
||||
|
||||
&radio {
|
||||
status = "okay";
|
||||
/* This is a number of antennas that are available on antenna matrix
|
||||
* designed by Nordic. For more information see README.rst.
|
||||
*/
|
||||
dfe-antenna-num = <12>;
|
||||
/* This is a setting that enables antenna 12 (in antenna matrix designed
|
||||
* by Nordic) for PDU. For more information see README.rst.
|
||||
*/
|
||||
dfe-pdu-antenna = <0x0>;
|
||||
|
||||
/* These are GPIO pin numbers that are provided to
|
||||
* Radio peripheral. The pins will be acquired by Radio to
|
||||
* drive antenna switching.
|
||||
* Pin numbers are selected to drive switches on antenna matrix
|
||||
* desinged by Nordic. For more information see README.rst.
|
||||
*/
|
||||
dfegpio0-gpios = <&gpio0 4 0>;
|
||||
dfegpio1-gpios = <&gpio0 5 0>;
|
||||
dfegpio2-gpios = <&gpio0 6 0>;
|
||||
dfegpio3-gpios = <&gpio0 7 0>;
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
#
|
||||
# Copyright (c) 2023 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
# Disable the unsupported driver
|
||||
CONFIG_NRFX_TIMER0=n
|
||||
CONFIG_NRFX_TIMER1=n
|
||||
CONFIG_NRFX_TIMER2=n
|
||||
|
||||
# Use necessary peripherals
|
||||
CONFIG_NRFX_TIMER20=y
|
||||
CONFIG_NRFX_TIMER10=y
|
||||
CONFIG_NRFX_GPPI=y
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
ncs,dtm-uart = &uart20;
|
||||
};
|
||||
};
|
||||
|
||||
&uart20 {
|
||||
status = "okay";
|
||||
current-speed = <19200>;
|
||||
};
|
||||
|
||||
&radio {
|
||||
status = "okay";
|
||||
/* This is a number of antennas that are available on antenna matrix
|
||||
* designed by Nordic. For more information see README.rst.
|
||||
*/
|
||||
dfe-antenna-num = <12>;
|
||||
/* This is a setting that enables antenna 12 (in antenna matrix designed
|
||||
* by Nordic) for PDU. For more information see README.rst.
|
||||
*/
|
||||
dfe-pdu-antenna = <0x0>;
|
||||
|
||||
/* These are GPIO pin numbers that are provided to
|
||||
* Radio peripheral. The pins will be acquired by Radio to
|
||||
* drive antenna switching.
|
||||
* Pin numbers are selected to drive switches on antenna matrix
|
||||
* desinged by Nordic. For more information see README.rst.
|
||||
*/
|
||||
dfegpio0-gpios = <&gpio0 4 0>;
|
||||
dfegpio1-gpios = <&gpio0 5 0>;
|
||||
dfegpio2-gpios = <&gpio0 6 0>;
|
||||
dfegpio3-gpios = <&gpio0 7 0>;
|
||||
};
|
||||
17
nordic/trezor/direct_test_mode/debug.conf
Normal file
17
nordic/trezor/direct_test_mode/debug.conf
Normal file
@@ -0,0 +1,17 @@
|
||||
# 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_RTT_CONSOLE=y
|
||||
CONFIG_USE_SEGGER_RTT=y
|
||||
CONFIG_LOG_BACKEND_RTT=y
|
||||
|
||||
|
||||
CONFIG_ASSERT=y
|
||||
9
nordic/trezor/direct_test_mode/no-dfe.overlay
Normal file
9
nordic/trezor/direct_test_mode/no-dfe.overlay
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
&radio {
|
||||
/delete-property/ dfe-supported;
|
||||
};
|
||||
29
nordic/trezor/direct_test_mode/pm_static.yml
Normal file
29
nordic/trezor/direct_test_mode/pm_static.yml
Normal file
@@ -0,0 +1,29 @@
|
||||
mcuboot:
|
||||
address: 0x0
|
||||
size: 0xc000
|
||||
custom_data:
|
||||
address: 0xc000
|
||||
size: 0x2000
|
||||
mcuboot_pad:
|
||||
address: 0xe000
|
||||
size: 0x200
|
||||
app:
|
||||
address: 0xe200
|
||||
size: 0x6be00
|
||||
mcuboot_primary:
|
||||
orig_span: &id001
|
||||
- mcuboot_pad
|
||||
- app
|
||||
span: *id001
|
||||
address: 0xe000
|
||||
size: 0x6c000
|
||||
mcuboot_primary_app:
|
||||
orig_span: &id002
|
||||
- app
|
||||
span: *id002
|
||||
address: 0xe200
|
||||
size: 0x6be00
|
||||
settings_storage:
|
||||
address: 0x7a000
|
||||
size: 0x6000
|
||||
|
||||
36
nordic/trezor/direct_test_mode/prj.conf
Normal file
36
nordic/trezor/direct_test_mode/prj.conf
Normal file
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# Copyright (c) 2020 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_K32SRC_500PPM=y
|
||||
CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_PERIOD=4000
|
||||
|
||||
CONFIG_NFCT_PINS_AS_GPIOS=y
|
||||
|
||||
# Configure assertions
|
||||
CONFIG_ASSERT=y
|
||||
CONFIG_ASSERT_NO_COND_INFO=y
|
||||
CONFIG_ASSERT_NO_MSG_INFO=y
|
||||
|
||||
CONFIG_HW_STACK_PROTECTION=y
|
||||
|
||||
CONFIG_CONSOLE=n
|
||||
CONFIG_UART_CONSOLE=n
|
||||
|
||||
CONFIG_LOG=y
|
||||
CONFIG_LOG_PRINTK=y
|
||||
CONFIG_USE_SEGGER_RTT=y
|
||||
CONFIG_LOG_BACKEND_RTT=y
|
||||
|
||||
# Use necessary peripherals
|
||||
CONFIG_NRFX_TIMER0=y
|
||||
CONFIG_NRFX_TIMER1=y
|
||||
CONFIG_NRFX_TIMER2=y
|
||||
CONFIG_CLOCK_CONTROL=y
|
||||
|
||||
CONFIG_FEM_AL_LIB=y
|
||||
32
nordic/trezor/direct_test_mode/prj_hci.conf
Normal file
32
nordic/trezor/direct_test_mode/prj_hci.conf
Normal file
@@ -0,0 +1,32 @@
|
||||
#
|
||||
# Copyright (c) 2020 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
# Configure assertions
|
||||
CONFIG_ASSERT=y
|
||||
CONFIG_ASSERT_NO_COND_INFO=y
|
||||
CONFIG_ASSERT_NO_MSG_INFO=y
|
||||
|
||||
CONFIG_HW_STACK_PROTECTION=y
|
||||
|
||||
CONFIG_CONSOLE=n
|
||||
CONFIG_UART_CONSOLE=n
|
||||
|
||||
CONFIG_LOG=y
|
||||
CONFIG_LOG_PRINTK=y
|
||||
CONFIG_USE_SEGGER_RTT=y
|
||||
CONFIG_LOG_BACKEND_RTT=y
|
||||
|
||||
# Use necessary peripherals
|
||||
CONFIG_NRFX_TIMER0=y
|
||||
CONFIG_NRFX_TIMER1=y
|
||||
CONFIG_NRFX_TIMER2=y
|
||||
CONFIG_CLOCK_CONTROL=y
|
||||
|
||||
CONFIG_FEM_AL_LIB=y
|
||||
|
||||
CONFIG_DTM_TRANSPORT_HCI=y
|
||||
CONFIG_NET_BUF=y
|
||||
CONFIG_UART_ASYNC_API=y
|
||||
30
nordic/trezor/direct_test_mode/prj_usb.conf
Normal file
30
nordic/trezor/direct_test_mode/prj_usb.conf
Normal file
@@ -0,0 +1,30 @@
|
||||
#
|
||||
# Copyright (c) 2020 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
# Configure assertions
|
||||
CONFIG_ASSERT=y
|
||||
CONFIG_ASSERT_NO_COND_INFO=y
|
||||
CONFIG_ASSERT_NO_MSG_INFO=y
|
||||
|
||||
CONFIG_HW_STACK_PROTECTION=y
|
||||
|
||||
CONFIG_CONSOLE=n
|
||||
CONFIG_UART_CONSOLE=n
|
||||
|
||||
CONFIG_LOG=y
|
||||
CONFIG_LOG_PRINTK=y
|
||||
CONFIG_USE_SEGGER_RTT=y
|
||||
CONFIG_LOG_BACKEND_RTT=y
|
||||
|
||||
# Use necessary peripherals
|
||||
CONFIG_NRFX_TIMER0=y
|
||||
CONFIG_NRFX_TIMER1=y
|
||||
CONFIG_NRFX_TIMER2=y
|
||||
CONFIG_CLOCK_CONTROL=y
|
||||
|
||||
CONFIG_FEM_AL_LIB=y
|
||||
|
||||
CONFIG_DTM_USB=y
|
||||
20
nordic/trezor/direct_test_mode/remote_hci/CMakeLists.txt
Normal file
20
nordic/trezor/direct_test_mode/remote_hci/CMakeLists.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(remote_hci)
|
||||
|
||||
target_include_directories(app PRIVATE ./../rpc)
|
||||
target_include_directories(app PRIVATE ./../src/transport)
|
||||
|
||||
# NORDIC SDK APP START
|
||||
target_sources(app PRIVATE
|
||||
src/main.c
|
||||
../src/transport/hci_uart.c
|
||||
)
|
||||
# NORDIC SDK APP END
|
||||
53
nordic/trezor/direct_test_mode/remote_hci/Kconfig
Normal file
53
nordic/trezor/direct_test_mode/remote_hci/Kconfig
Normal file
@@ -0,0 +1,53 @@
|
||||
#
|
||||
# Copyright (c) 2023 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
mainmenu "Nordic Remote HCI DTM"
|
||||
|
||||
config DTM_REMOTE_HCI_CHILD
|
||||
bool
|
||||
default y
|
||||
|
||||
config DTM_PUT_THREAD_STACK_SIZE
|
||||
int "dtm_put thread stack size"
|
||||
default 2048
|
||||
help
|
||||
Stack size of the dtm_put thread.
|
||||
|
||||
config DTM_PUT_THREAD_PRIORITY
|
||||
int "dtm_put thread priority"
|
||||
default 7
|
||||
help
|
||||
Priority of the dtm_put thread.
|
||||
|
||||
config REMOTE_HCI_QUEUE_COUNT
|
||||
int "Count of HCI RX/TX queues"
|
||||
default 16
|
||||
help
|
||||
Maximum depth of the HCI RX/TX queues.
|
||||
|
||||
config REMOTE_HCI_QUEUE_SIZE
|
||||
int "Size of HCI RX/TX queue buffer"
|
||||
default 1024
|
||||
help
|
||||
Maximum size of the HCI RX/TX queue element.
|
||||
|
||||
config REMOTE_HCI_TX_THREAD_STACK_SIZE
|
||||
int "Stack size of TX thread"
|
||||
default 2048
|
||||
help
|
||||
Stack size of the TX thread.
|
||||
|
||||
config REMOTE_HCI_TX_THREAD_PRIORITY
|
||||
int "TX thread priority"
|
||||
default 7
|
||||
help
|
||||
Priority of the TX thread.
|
||||
|
||||
module = DTM_REMOTE_HCI
|
||||
module-str = "DTM_remote_hci"
|
||||
source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config"
|
||||
|
||||
source "Kconfig.zephyr"
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
ncs,dtm-uart = &uart0;
|
||||
};
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
status = "okay";
|
||||
current-speed = <115200>;
|
||||
};
|
||||
|
||||
&gpio_fwd {
|
||||
dfe-radio {
|
||||
gpios = <&gpio0 4 0>,
|
||||
<&gpio0 5 0>,
|
||||
<&gpio0 6 0>,
|
||||
<&gpio0 7 0>;
|
||||
};
|
||||
};
|
||||
26
nordic/trezor/direct_test_mode/remote_hci/prj.conf
Normal file
26
nordic/trezor/direct_test_mode/remote_hci/prj.conf
Normal file
@@ -0,0 +1,26 @@
|
||||
#
|
||||
# Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
CONFIG_ASSERT=y
|
||||
CONFIG_ASSERT_NO_COND_INFO=y
|
||||
CONFIG_ASSERT_NO_MSG_INFO=y
|
||||
|
||||
CONFIG_HW_STACK_PROTECTION=y
|
||||
|
||||
CONFIG_CONSOLE=n
|
||||
CONFIG_UART_CONSOLE=n
|
||||
CONFIG_LOG=y
|
||||
CONFIG_LOG_PRINTK=y
|
||||
CONFIG_USE_SEGGER_RTT=y
|
||||
CONFIG_LOG_BACKEND_RTT=y
|
||||
CONFIG_UART_ASYNC_API=y
|
||||
|
||||
CONFIG_NRF_RPC=y
|
||||
CONFIG_NRF_RPC_CBOR=y
|
||||
CONFIG_IDLE_STACK_SIZE=2048
|
||||
|
||||
CONFIG_NET_BUF=y
|
||||
|
||||
CONFIG_SOC_NRF53_CPUNET_ENABLE=y
|
||||
169
nordic/trezor/direct_test_mode/remote_hci/src/main.c
Normal file
169
nordic/trezor/direct_test_mode/remote_hci/src/main.c
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/net_buf.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <nrf_rpc/nrf_rpc_ipc.h>
|
||||
#include <nrf_rpc_cbor.h>
|
||||
|
||||
#include "hci_uart.h"
|
||||
#include "dtm_serialization.h"
|
||||
|
||||
LOG_MODULE_REGISTER(serialization_layer, CONFIG_DTM_REMOTE_HCI_LOG_LEVEL);
|
||||
|
||||
NRF_RPC_IPC_TRANSPORT(hci_group_tr, DEVICE_DT_GET(DT_NODELABEL(ipc0)), "dtm_ept");
|
||||
NRF_RPC_GROUP_DEFINE(hci_group, "hci_remote", &hci_group_tr, NULL, NULL, NULL);
|
||||
|
||||
static K_FIFO_DEFINE(dtm_put_queue);
|
||||
|
||||
static void dtm_hci_put_wrapper(struct net_buf *buf);
|
||||
|
||||
static void rsp_error_code_send(const struct nrf_rpc_group *group, int err_code)
|
||||
{
|
||||
struct nrf_rpc_cbor_ctx ctx;
|
||||
size_t buffer_size_max = 5;
|
||||
|
||||
NRF_RPC_CBOR_ALLOC(group, ctx, buffer_size_max);
|
||||
|
||||
if (!zcbor_int32_put(ctx.zs, err_code)) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
nrf_rpc_cbor_rsp_no_err(group, &ctx);
|
||||
|
||||
return;
|
||||
|
||||
error_exit:
|
||||
__ASSERT_NO_MSG(false);
|
||||
}
|
||||
|
||||
/* Outgoing event dtm_hci_put to network core (DTM). */
|
||||
static void dtm_hci_put_remote(struct net_buf *buf)
|
||||
{
|
||||
struct nrf_rpc_cbor_ctx ctx;
|
||||
size_t buffer_size_max = 10;
|
||||
|
||||
LOG_DBG("Call to dtm_hci_put");
|
||||
|
||||
buffer_size_max += buf->len;
|
||||
|
||||
NRF_RPC_CBOR_ALLOC(&hci_group, ctx, buffer_size_max);
|
||||
|
||||
if (!zcbor_uint_encode(ctx.zs, &buf->user_data[0], sizeof(buf->user_data[0]))) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if (!zcbor_bstr_encode_ptr(ctx.zs, buf->data, buf->len)) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
nrf_rpc_cbor_evt(&hci_group, RPC_DTM_HCI_PUT_EVT, &ctx);
|
||||
|
||||
return;
|
||||
|
||||
error_exit:
|
||||
__ASSERT_NO_MSG(false);
|
||||
}
|
||||
|
||||
/* Incoming hci_uart_write command from network core (DTM) */
|
||||
static void hci_uart_write_handler(const struct nrf_rpc_group *group, struct nrf_rpc_cbor_ctx *ctx,
|
||||
void *handler_data)
|
||||
{
|
||||
int err;
|
||||
uint8_t type;
|
||||
struct zcbor_string hdr;
|
||||
struct zcbor_string pld;
|
||||
|
||||
LOG_DBG("Call from hci_uart_write");
|
||||
|
||||
if (!zcbor_uint_decode(ctx->zs, &type, sizeof(type))) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if (!zcbor_bstr_decode(ctx->zs, &hdr)) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if (!zcbor_bstr_decode(ctx->zs, &pld)) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
err = hci_uart_write(type, hdr.value, hdr.len, pld.value, pld.len);
|
||||
nrf_rpc_cbor_decoding_done(group, ctx);
|
||||
rsp_error_code_send(group, err);
|
||||
|
||||
return;
|
||||
|
||||
error_exit:
|
||||
__ASSERT_NO_MSG(false);
|
||||
}
|
||||
|
||||
NRF_RPC_CBOR_CMD_DECODER(hci_group, hci_uart_write, RPC_HCI_UART_WRITE_CMD,
|
||||
hci_uart_write_handler, NULL);
|
||||
|
||||
/* Incoming command hci_uart_init from network core (DTM). */
|
||||
static void hci_uart_init_handler(const struct nrf_rpc_group *group, struct nrf_rpc_cbor_ctx *ctx,
|
||||
void *handler_data)
|
||||
{
|
||||
int err;
|
||||
|
||||
LOG_DBG("Call from hci_uart_init");
|
||||
nrf_rpc_cbor_decoding_done(group, ctx);
|
||||
|
||||
err = hci_uart_init(dtm_hci_put_wrapper);
|
||||
rsp_error_code_send(group, err);
|
||||
}
|
||||
|
||||
NRF_RPC_CBOR_CMD_DECODER(hci_group, hci_uart_init, RPC_HCI_UART_INIT_CMD,
|
||||
hci_uart_init_handler, NULL);
|
||||
|
||||
static void dtm_hci_put_wrapper(struct net_buf *buf)
|
||||
{
|
||||
k_fifo_put(&dtm_put_queue, buf);
|
||||
}
|
||||
|
||||
static void dtm_put_thread(void)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
|
||||
for (;;) {
|
||||
buf = k_fifo_get(&dtm_put_queue, K_FOREVER);
|
||||
|
||||
__ASSERT_NO_MSG(buf != NULL);
|
||||
|
||||
dtm_hci_put_remote(buf);
|
||||
net_buf_unref(buf);
|
||||
}
|
||||
}
|
||||
|
||||
K_THREAD_DEFINE(dtm_put_thread_id, CONFIG_DTM_PUT_THREAD_STACK_SIZE, dtm_put_thread,
|
||||
NULL, NULL, NULL,
|
||||
CONFIG_DTM_PUT_THREAD_PRIORITY, 0, 0);
|
||||
|
||||
static void err_handler(const struct nrf_rpc_err_report *report)
|
||||
{
|
||||
LOG_ERR("nRF RPC error %d ocurred. See nRF RPC logs for more details.", report->code);
|
||||
k_oops();
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
LOG_INF("RPC init begin");
|
||||
|
||||
err = nrf_rpc_init(err_handler);
|
||||
if (err) {
|
||||
LOG_ERR("nrf_rpc_init failed: %d", err);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
LOG_INF("RPC init done");
|
||||
|
||||
return 0;
|
||||
}
|
||||
14
nordic/trezor/direct_test_mode/rpc/dtm_serialization.h
Normal file
14
nordic/trezor/direct_test_mode/rpc/dtm_serialization.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#ifndef DTM_SETIALIZATION_H_
|
||||
#define DTM_SETIALIZATION_H_
|
||||
|
||||
#define RPC_HCI_UART_INIT_CMD 0
|
||||
#define RPC_HCI_UART_WRITE_CMD 1
|
||||
#define RPC_DTM_HCI_PUT_EVT 2
|
||||
|
||||
#endif /* DTM_SETIALIZATION_H_ */
|
||||
74
nordic/trezor/direct_test_mode/sample.yaml
Normal file
74
nordic/trezor/direct_test_mode/sample.yaml
Normal file
@@ -0,0 +1,74 @@
|
||||
sample:
|
||||
description: Bluetooth Low Energy Direct Test Mode sample
|
||||
name: Bluetooth LE Direct Test Mode
|
||||
tests:
|
||||
sample.bluetooth.direct_test_mode:
|
||||
sysbuild: true
|
||||
build_only: true
|
||||
integration_platforms:
|
||||
- nrf5340dk/nrf5340/cpunet
|
||||
- nrf21540dk/nrf52840
|
||||
- nrf52840dk/nrf52840
|
||||
- nrf54l15dk/nrf54l05/cpuapp
|
||||
- nrf54l15dk/nrf54l10/cpuapp
|
||||
- nrf54l15dk/nrf54l15/cpuapp
|
||||
- nrf54h20dk/nrf54h20/cpurad
|
||||
platform_allow: nrf5340dk/nrf5340/cpunet nrf21540dk/nrf52840 nrf52840dk/nrf52840
|
||||
nrf54l15dk/nrf54l05/cpuapp nrf54l15dk/nrf54l10/cpuapp
|
||||
nrf54l15dk/nrf54l15/cpuapp nrf54h20dk/nrf54h20/cpurad
|
||||
tags: bluetooth ci_build sysbuild
|
||||
sample.bluetooth.direct_test_mode.hci:
|
||||
sysbuild: true
|
||||
build_only: true
|
||||
extra_args: FILE_SUFFIX=hci
|
||||
integration_platforms:
|
||||
- nrf5340dk/nrf5340/cpunet
|
||||
- nrf21540dk/nrf52840
|
||||
- nrf52840dk/nrf52840
|
||||
- nrf54l15dk/nrf54l15/cpuapp
|
||||
- nrf54h20dk/nrf54h20/cpurad
|
||||
platform_allow: nrf5340dk/nrf5340/cpunet nrf21540dk/nrf52840 nrf52840dk/nrf52840
|
||||
nrf54l15dk/nrf54l15/cpuapp nrf54h20dk/nrf54h20/cpurad
|
||||
tags: bluetooth ci_build sysbuild
|
||||
sample.bluetooth.direct_test_mode.nrf5340_nrf21540:
|
||||
sysbuild: true
|
||||
build_only: true
|
||||
extra_args: SHIELD=nrf21540ek
|
||||
integration_platforms:
|
||||
- nrf5340dk/nrf5340/cpunet
|
||||
platform_allow: nrf5340dk/nrf5340/cpunet
|
||||
tags: bluetooth ci_build sysbuild
|
||||
sample.bluetooth.direct_test_mode.nrf5340_usb:
|
||||
sysbuild: true
|
||||
build_only: true
|
||||
extra_args: FILE_SUFFIX=usb
|
||||
integration_platforms:
|
||||
- nrf5340dk/nrf5340/cpunet
|
||||
platform_allow: nrf5340dk/nrf5340/cpunet
|
||||
tags: bluetooth ci_build sysbuild
|
||||
sample.bluetooth.direct_test_mode.nrf5340_nrf21540_usb:
|
||||
sysbuild: true
|
||||
build_only: true
|
||||
extra_args: SHIELD=nrf21540ek FILE_SUFFIX=usb
|
||||
integration_platforms:
|
||||
- nrf5340dk/nrf5340/cpunet
|
||||
platform_allow: nrf5340dk/nrf5340/cpunet
|
||||
tags: bluetooth ci_build sysbuild
|
||||
sample.bluetooth.direct_test_mode.nrf5340_nrf21540.no_automatic_power:
|
||||
sysbuild: true
|
||||
build_only: true
|
||||
extra_args: SHIELD=nrf21540ek
|
||||
extra_configs:
|
||||
- CONFIG_DTM_POWER_CONTROL_AUTOMATIC=n
|
||||
integration_platforms:
|
||||
- nrf5340dk/nrf5340/cpunet
|
||||
platform_allow: nrf5340dk/nrf5340/cpunet
|
||||
tags: bluetooth ci_build sysbuild
|
||||
sample.bluetooth.direct_test_mode.nrf5340_no_dfe:
|
||||
sysbuild: true
|
||||
build_only: true
|
||||
extra_args: DSB_CONFIG_DTM_NO_DFE=y
|
||||
integration_platforms:
|
||||
- nrf5340dk/nrf5340/cpunet
|
||||
platform_allow: nrf5340dk/nrf5340/cpunet
|
||||
tags: bluetooth ci_build sysbuild
|
||||
2592
nordic/trezor/direct_test_mode/src/dtm.c
Normal file
2592
nordic/trezor/direct_test_mode/src/dtm.c
Normal file
File diff suppressed because it is too large
Load Diff
367
nordic/trezor/direct_test_mode/src/dtm.h
Normal file
367
nordic/trezor/direct_test_mode/src/dtm.h
Normal file
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#ifndef DTM_H_
|
||||
#define DTM_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <zephyr/types.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NRF_IQ_SAMPLE_INVALID -32768
|
||||
|
||||
/** @brief DTM PHY mode */
|
||||
enum dtm_phy {
|
||||
/** Bluetooth Low Energy 1 Mbps PHY. */
|
||||
DTM_PHY_1M,
|
||||
|
||||
/** Bluetooth Low Energy 2 Mbps PHY. */
|
||||
DTM_PHY_2M,
|
||||
|
||||
/** Bluetooth Low Energy Coded S=8 PHY. */
|
||||
DTM_PHY_CODED_S8,
|
||||
|
||||
/** Bluetooth Low Energy Coded S=2 PHY. */
|
||||
DTM_PHY_CODED_S2
|
||||
};
|
||||
|
||||
/** @brief DTM modulation index. */
|
||||
enum dtm_modulation {
|
||||
/** Standard modulation index. */
|
||||
DTM_MODULATION_STANDARD,
|
||||
|
||||
/** Stable modulation index. */
|
||||
DTM_MODULATION_STABLE
|
||||
};
|
||||
|
||||
/** @brief DTM maximum supported values. */
|
||||
enum dtm_max_supported {
|
||||
/** Maximum supported TX octets. */
|
||||
DTM_MAX_SUPPORTED_TX_OCTETS,
|
||||
|
||||
/** Maximum supported TX time. */
|
||||
DTM_MAX_SUPPORTED_TX_TIME,
|
||||
|
||||
/** Maximum supported RX octets. */
|
||||
DTM_MAX_SUPPORTED_RX_OCTETS,
|
||||
|
||||
/** Maximum supported RX time. */
|
||||
DTM_MAX_SUPPORTED_RX_TIME,
|
||||
|
||||
/** Maximum supported Constant Tone Extension length. */
|
||||
DTM_MAX_SUPPORTED_CTE_LENGTH
|
||||
};
|
||||
|
||||
/** @brief Constant Tone Extension type. */
|
||||
enum dtm_cte_type {
|
||||
/** Do not use Constant Tone Extension. */
|
||||
DTM_CTE_TYPE_NONE,
|
||||
|
||||
/** Angle of Arrival. */
|
||||
DTM_CTE_TYPE_AOA,
|
||||
|
||||
/** Angle of Departure 1 us slots. */
|
||||
DTM_CTE_TYPE_AOD_1US,
|
||||
|
||||
/** Angle of Departure 2 us slots. */
|
||||
DTM_CTE_TYPE_AOD_2US
|
||||
};
|
||||
|
||||
/** @brief DTM Constant Tone Extension slot duration. */
|
||||
enum dtm_cte_slot_duration {
|
||||
/** CTE 1 us slots duration. */
|
||||
DTM_CTE_SLOT_DURATION_1US,
|
||||
|
||||
/** CTE 2 us slots duration. */
|
||||
DTM_CTE_SLOT_DURATION_2US
|
||||
};
|
||||
|
||||
/** @brief DTM transmit power request. */
|
||||
enum dtm_tx_power_request {
|
||||
/** Request minimum power. */
|
||||
DTM_TX_POWER_REQUEST_MIN,
|
||||
|
||||
/** Request maximum power. */
|
||||
DTM_TX_POWER_REQUEST_MAX,
|
||||
|
||||
/** Request power by value. */
|
||||
DTM_TX_POWER_REQUEST_VAL
|
||||
};
|
||||
|
||||
/** @brief DTM packet type. */
|
||||
enum dtm_packet {
|
||||
/** Packet filled with PRBS9 stream as payload. */
|
||||
DTM_PACKET_PRBS9,
|
||||
|
||||
/** Packet with 0x0F bytes as payload. */
|
||||
DTM_PACKET_0F,
|
||||
|
||||
/** Packet with 0x55 bytes as payload. */
|
||||
DTM_PACKET_55,
|
||||
|
||||
/** Packet filled with PRBS15 stream as payload. */
|
||||
DTM_PACKET_PRBS15,
|
||||
|
||||
/** Packet with 0xFF bytes as payload or vendor specific packet. */
|
||||
DTM_PACKET_FF_OR_VENDOR,
|
||||
|
||||
/** Packet with 0xFF bytes as payload. */
|
||||
DTM_PACKET_FF,
|
||||
|
||||
/** Packet with 0x00 bytes as payload. */
|
||||
DTM_PACKET_00,
|
||||
|
||||
/** Packet with 0xF0 bytes as payload. */
|
||||
DTM_PACKET_F0,
|
||||
|
||||
/** Packet with 0xAA bytes as payload. */
|
||||
DTM_PACKET_AA,
|
||||
|
||||
/** Vendor-specific packet. */
|
||||
DTM_PACKET_VENDOR
|
||||
};
|
||||
|
||||
/** @brief DTM supported features. */
|
||||
struct dtm_supp_features {
|
||||
/** Support for Data Packet Length Extension. */
|
||||
bool data_len_ext;
|
||||
|
||||
/** Support for Bluetooth Low Energy 2 Mbps PHY. */
|
||||
bool phy_2m;
|
||||
|
||||
/** Support for Stable Modulation Index. */
|
||||
bool stable_mod;
|
||||
|
||||
/** Support for Bluetooth Low Energy Coded PHY. */
|
||||
bool coded_phy;
|
||||
|
||||
/** Support for Constant Tone Extension. */
|
||||
bool cte;
|
||||
|
||||
/** Support for Antenna switching. */
|
||||
bool ant_switching;
|
||||
|
||||
/** Support for AoD transmission 1 us switching. */
|
||||
bool aod_1us_tx;
|
||||
|
||||
/** Support for AoD reception 1 us switching. */
|
||||
bool aod_1us_rx;
|
||||
|
||||
/** Support for AoA reception 1 us switching and sampling. */
|
||||
bool aoa_1us_rx;
|
||||
};
|
||||
|
||||
/** @brief DTM transmit power. */
|
||||
struct dtm_tx_power {
|
||||
/** Actual power in dBm. */
|
||||
int8_t power;
|
||||
|
||||
/** Power at minimum level. */
|
||||
bool min;
|
||||
|
||||
/** Power at maximum level. */
|
||||
bool max;
|
||||
};
|
||||
|
||||
/** @brief DTM Packet status for IQ Sample report. */
|
||||
enum dtm_packet_status {
|
||||
/** Packet received with proper CRC. */
|
||||
DTM_PACKET_STATUS_CRC_OK,
|
||||
|
||||
/** Packet received with invalid CRC.
|
||||
* The Length and CTEInfo was used to calculate sampling points.
|
||||
*/
|
||||
DTM_PACKET_STATUS_CRC_ERR_TIME,
|
||||
|
||||
/** Packet received with invalid CRC.
|
||||
* The sampling points were calculated in another way.
|
||||
*/
|
||||
DTM_PACKET_STATUS_CRC_ERR_OTHER,
|
||||
|
||||
/** Packet received with invalid CRC.
|
||||
* Insufficient resources to sample.
|
||||
*/
|
||||
DTM_PACKET_STATUS_CRC_ERR_INSUFFICIENT
|
||||
};
|
||||
|
||||
/** @brief IQ sample format. */
|
||||
struct dtm_iq_sample {
|
||||
/** I sample value. */
|
||||
int16_t i;
|
||||
|
||||
/** Q sample value. */
|
||||
int16_t q;
|
||||
};
|
||||
|
||||
/** @brief DTM IQ sampling data with additional information. */
|
||||
struct dtm_iq_data {
|
||||
/** Channel number. */
|
||||
uint8_t channel;
|
||||
|
||||
/** RSSI value of received packet. */
|
||||
int16_t rssi;
|
||||
|
||||
/** Antenna number used to measure RSSI. */
|
||||
uint8_t rssi_ant;
|
||||
|
||||
/** CTE type. */
|
||||
enum dtm_cte_type type;
|
||||
|
||||
/** CTE slot duration. */
|
||||
enum dtm_cte_slot_duration slot;
|
||||
|
||||
/** Packet status. */
|
||||
enum dtm_packet_status status;
|
||||
|
||||
/** IQ sample count. */
|
||||
uint8_t sample_cnt;
|
||||
|
||||
/** IQ samples. */
|
||||
struct dtm_iq_sample *samples;
|
||||
};
|
||||
|
||||
/** @brief Callback to report received IQ samples.
|
||||
*
|
||||
* @note The callback is used only with direction finding.
|
||||
*
|
||||
* @param[in] data Pointer to dtm_iq_data structure.
|
||||
*/
|
||||
typedef void (*dtm_iq_report_callback_t)(struct dtm_iq_data *data);
|
||||
|
||||
/** @brief Initialize the DTM module.
|
||||
*
|
||||
* This function initializes the DTM module and registers the IQ sampling callback.
|
||||
* If the callback is not needed, the pointer can be NULL.
|
||||
*
|
||||
* @param[in] iq_callback Function pointer to the IQ report callback, can be NULL.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int dtm_init(dtm_iq_report_callback_t callback);
|
||||
|
||||
/** @brief Prepare DTM for setup.
|
||||
*
|
||||
* @note This function should be called before setup functions.
|
||||
* The function can be called once before a block of setup functions.
|
||||
*/
|
||||
void dtm_setup_prepare(void);
|
||||
|
||||
/** @brief Reset the DTM state.
|
||||
*
|
||||
* The PHY is set to Bluetooth Low Energy 1M mode.
|
||||
* The modulation index is set to standard.
|
||||
* The CTE is turned off.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int dtm_setup_reset(void);
|
||||
|
||||
/** @brief Set the PHY for DTM.
|
||||
*
|
||||
* @param[in] phy The PHY to be used.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int dtm_setup_set_phy(enum dtm_phy phy);
|
||||
|
||||
/** @brief Set the modulation for DTM.
|
||||
*
|
||||
* @param[in] modulation The modulation to be used.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int dtm_setup_set_modulation(enum dtm_modulation modulation);
|
||||
|
||||
/** @brief Read supported BLE features.
|
||||
*
|
||||
* @return Features supported by the device.
|
||||
*/
|
||||
struct dtm_supp_features dtm_setup_read_features(void);
|
||||
|
||||
/** @brief Read the maximum supported parameter value by DTM.
|
||||
*
|
||||
* @param[in] parameter Value to be read.
|
||||
* @param[out] max_val The pointer to the maximum value.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int dtm_setup_read_max_supported_value(enum dtm_max_supported parameter, uint16_t *max_val);
|
||||
|
||||
/** @brief Setup the CTE for DTM.
|
||||
*
|
||||
* @param[in] type The CTE type to be used.
|
||||
* @param[in] time The time of CTE in 8 us units.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int dtm_setup_set_cte_mode(enum dtm_cte_type type, uint8_t time);
|
||||
|
||||
/** @brief Set the CTE slots duration for DTM.
|
||||
*
|
||||
* @param[in] slot The CTE slots duration.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int dtm_setup_set_cte_slot(enum dtm_cte_slot_duration slot);
|
||||
|
||||
/** @brief Set the antenna parameters for DTM.
|
||||
*
|
||||
* @param[in] count The antenna count.
|
||||
* @param[in] pattern The antenna switching pattern.
|
||||
* @param[in] pattern_len The length of the pattern.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int dtm_setup_set_antenna_params(uint8_t count, uint8_t *pattern, uint8_t pattern_len);
|
||||
|
||||
/** @brief Set the transmit power for DTM.
|
||||
*
|
||||
* @param[in] power The transmit power request.
|
||||
* @param[in] val TX power value (in dBm) in case of DTM_TX_POWER_REQUEST_VAL request.
|
||||
* @param[in] channel The channel to adjust power (set to 0 if unknown).
|
||||
*
|
||||
* @return The actual TX power set by the function.
|
||||
*/
|
||||
struct dtm_tx_power dtm_setup_set_transmit_power(enum dtm_tx_power_request power, int8_t val,
|
||||
uint8_t channel);
|
||||
|
||||
/** @brief Start the DTM reception test.
|
||||
*
|
||||
* @param[in] channel The reception channel.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int dtm_test_receive(uint8_t channel);
|
||||
|
||||
/** @brief Start the DTM transmission test.
|
||||
*
|
||||
* @param[in] channel The transmission channel.
|
||||
* @param[in] length The packet length.
|
||||
* @param[in] pkt The packet type.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int dtm_test_transmit(uint8_t channel, uint8_t length, enum dtm_packet pkt);
|
||||
|
||||
/** @brief Stop the DTM test.
|
||||
*
|
||||
* Stop current DTM test and return the number of received packets.
|
||||
*
|
||||
* @param[out] pack_cnt The pointer to the received packet count.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int dtm_test_end(uint16_t *pack_cnt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DTM_H_ */
|
||||
266
nordic/trezor/direct_test_mode/src/dtm_hw.c
Normal file
266
nordic/trezor/direct_test_mode/src/dtm_hw.c
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#include "nrf.h"
|
||||
|
||||
#include "dtm_hw.h"
|
||||
#include "dtm_hw_config.h"
|
||||
|
||||
/* All valid power levels (in dBm) supported by the SoC. */
|
||||
const int8_t nrf_power_value[] = {
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Neg100dBm)
|
||||
-100,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Neg100dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Neg70dBm)
|
||||
-70,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Neg70dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Neg46dBm)
|
||||
-46,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Neg46dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Neg40dBm)
|
||||
-40,
|
||||
#endif /* RADIO_TXPOWER_TXPOWER_Neg40dBm */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Neg30dBm)
|
||||
-30,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Neg30dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Neg28dBm)
|
||||
-28,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Neg28dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Neg22dBm)
|
||||
-22,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Neg22dBm) */
|
||||
-20,
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Neg18dBm)
|
||||
-18,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Neg18dBm) */
|
||||
-16,
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Neg14dBm)
|
||||
-14,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Neg14dBm) */
|
||||
-12,
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Neg10dBm)
|
||||
-10,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Neg10dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Neg9dBm)
|
||||
-9,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Neg9dBm) */
|
||||
-8,
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Neg7dBm)
|
||||
-7,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Neg7dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Neg6dBm)
|
||||
-6,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Neg6dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Neg5dBm)
|
||||
-5,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Neg5dBm) */
|
||||
-4,
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Neg3dBm)
|
||||
-3,
|
||||
#endif /* defined (RADIO_TXPOWER_TXPOWER_Neg3dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Neg2dBm)
|
||||
-2,
|
||||
#endif /* defined (RADIO_TXPOWER_TXPOWER_Neg2dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Neg1dBm)
|
||||
-1,
|
||||
#endif /* defined (RADIO_TXPOWER_TXPOWER_Neg1dBm) */
|
||||
0,
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Pos1dBm)
|
||||
1,
|
||||
#endif /* RADIO_TXPOWER_TXPOWER_Pos1dBm */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Pos2dBm)
|
||||
2,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Pos2dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Pos3dBm)
|
||||
3,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Pos3dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Pos4dBm)
|
||||
4,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Pos4dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Pos5dBm)
|
||||
5,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Pos5dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Pos6dBm)
|
||||
6,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Pos6dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Pos7dBm)
|
||||
7,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Pos7dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Pos8dBm)
|
||||
8,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Pos8dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Pos9dBm)
|
||||
9,
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Pos9dBm) */
|
||||
#if defined(RADIO_TXPOWER_TXPOWER_Pos10dBm)
|
||||
10
|
||||
#endif /* defined(RADIO_TXPOWER_TXPOWER_Pos10dBm) */
|
||||
};
|
||||
|
||||
#if DIRECTION_FINDING_SUPPORTED
|
||||
|
||||
#define DTM_MAX_ANTENNA_NUMBER 19
|
||||
|
||||
#define DFE_GPIO_PIN_DISCONNECT (RADIO_PSEL_DFEGPIO_CONNECT_Disconnected << \
|
||||
RADIO_PSEL_DFEGPIO_CONNECT_Pos)
|
||||
|
||||
#define HAS_DFE_GPIO(idx) DT_NODE_HAS_PROP(RADIO_NODE, dfegpio##idx##_gpios)
|
||||
|
||||
/* Run a macro 'fn' on each available DFE GPIO index, from 0 to
|
||||
* MAX_DFE_GPIO-1, with the given parenthesized separator.
|
||||
*/
|
||||
#define FOR_EACH_DFE_GPIO(fn, sep) \
|
||||
FOR_EACH(fn, sep, 0, 1, 2, 3, 4, 5, 6, 7)
|
||||
|
||||
/* The number of dfegpio[n]-gpios properties which are set. */
|
||||
#define DFE_GPIO_NUM (FOR_EACH_DFE_GPIO(HAS_DFE_GPIO, (+)))
|
||||
|
||||
#define PDU_ANTENNA DT_PROP(RADIO_NODE, dfe_pdu_antenna)
|
||||
|
||||
/* The minimum number of antennas required to enable antenna switching. */
|
||||
#define MIN_ANTENNA_NUM 1
|
||||
|
||||
/* The maximum number of antennas supported by the number of
|
||||
* dfegpio[n]-gpios properties which are set.
|
||||
*/
|
||||
#if (DFE_GPIO_NUM > 0)
|
||||
#define MAX_ANTENNA_NUM BIT(DFE_GPIO_NUM)
|
||||
#else
|
||||
#define MAX_ANTENNA_NUM 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check that the number of antennas has been set, and that enough
|
||||
* pins are configured to represent each pattern for the given number
|
||||
* of antennas.
|
||||
*/
|
||||
#define HAS_ANTENNA_NUM DT_NODE_HAS_PROP(RADIO_NODE, dfe_antenna_num)
|
||||
|
||||
BUILD_ASSERT(HAS_ANTENNA_NUM,
|
||||
"You must set the dfe-antenna-num property in the radio node "
|
||||
"to enable antenna switching.");
|
||||
|
||||
#define ANTENNA_NUM DT_PROP_OR(RADIO_NODE, dfe_antenna_num, 0)
|
||||
|
||||
|
||||
BUILD_ASSERT(!HAS_ANTENNA_NUM || (ANTENNA_NUM <= MAX_ANTENNA_NUM),
|
||||
"Insufficient number of GPIO pins configured. "
|
||||
"Set more dfegpio[n]-gpios properties.");
|
||||
BUILD_ASSERT(!HAS_ANTENNA_NUM || (ANTENNA_NUM >= MIN_ANTENNA_NUM),
|
||||
"Insufficient number of antennas provided. "
|
||||
"Increase the dfe-antenna-num property.");
|
||||
|
||||
#define HAS_PDU_ANTENNA DT_NODE_HAS_PROP(RADIO_NODE, dfe_pdu_antenna)
|
||||
|
||||
BUILD_ASSERT(HAS_PDU_ANTENNA,
|
||||
"Missing antenna pattern used to select antenna for PDU Tx "
|
||||
"during the CTE Idle state. "
|
||||
"Set the dfe-pdu-antenna devicetree property.");
|
||||
|
||||
/*
|
||||
* Check that each dfegpio[n]-gpios property has a zero flags cell.
|
||||
*/
|
||||
#define ASSERT_DFE_GPIO_FLAGS_ARE_ZERO(idx) \
|
||||
BUILD_ASSERT(DT_GPIO_FLAGS(RADIO_NODE, dfegpio##idx##_gpios) == 0, \
|
||||
"The flags cell in each dfegpio[n]-gpios " \
|
||||
"property must be zero.")
|
||||
|
||||
FOR_EACH_DFE_GPIO(ASSERT_DFE_GPIO_FLAGS_ARE_ZERO, (;));
|
||||
|
||||
#define DFE_GPIO_PSEL(idx) \
|
||||
NRF_DT_GPIOS_TO_PSEL_OR(RADIO_NODE, dfegpio##idx##_gpios, \
|
||||
DTM_HW_DFE_PSEL_NOT_SET)
|
||||
|
||||
static const struct dtm_ant_cfg {
|
||||
uint8_t ant_num;
|
||||
/* Selection of GPIOs to be used to switch antennas by Radio */
|
||||
uint8_t dfe_gpio[DTM_HW_MAX_DFE_GPIO];
|
||||
} ant_cfg = {
|
||||
.ant_num = (ANTENNA_NUM > DTM_MAX_ANTENNA_NUMBER) ? DTM_MAX_ANTENNA_NUMBER : ANTENNA_NUM,
|
||||
.dfe_gpio = { FOR_EACH_DFE_GPIO(DFE_GPIO_PSEL, (,)) }
|
||||
};
|
||||
#endif /* DIRECTION_FINDING_SUPPORTED */
|
||||
|
||||
bool dtm_hw_radio_validate(int8_t tx_power,
|
||||
nrf_radio_mode_t radio_mode)
|
||||
{
|
||||
/* Initializing code below is quite generic - for BLE, the values are
|
||||
* fixed, and expressions are constant. Non-constant values are
|
||||
* essentially set in radio_prepare().
|
||||
*/
|
||||
|
||||
if (!(
|
||||
#if CONFIG_HAS_HW_NRF_RADIO_BLE_CODED
|
||||
radio_mode == NRF_RADIO_MODE_BLE_LR125KBIT ||
|
||||
radio_mode == NRF_RADIO_MODE_BLE_LR500KBIT ||
|
||||
#endif /* CONFIG_HAS_HW_NRF_RADIO_BLE_CODED */
|
||||
radio_mode == NRF_RADIO_MODE_BLE_1MBIT ||
|
||||
radio_mode == NRF_RADIO_MODE_BLE_2MBIT
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(nrf_power_value); i++) {
|
||||
if (tx_power == nrf_power_value[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool dtm_hw_radio_lr_check(nrf_radio_mode_t radio_mode)
|
||||
{
|
||||
#if CONFIG_HAS_HW_NRF_RADIO_BLE_CODED
|
||||
if (radio_mode == NRF_RADIO_MODE_BLE_LR125KBIT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (radio_mode == NRF_RADIO_MODE_BLE_LR500KBIT) {
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_HAS_HW_NRF_RADIO_BLE_CODED */
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t dtm_hw_radio_min_power_get(void)
|
||||
{
|
||||
return nrf_power_value[0];
|
||||
}
|
||||
|
||||
uint32_t dtm_hw_radio_max_power_get(void)
|
||||
{
|
||||
return nrf_power_value[ARRAY_SIZE(nrf_power_value) - 1];
|
||||
}
|
||||
|
||||
size_t dtm_hw_radio_power_array_size_get(void)
|
||||
{
|
||||
return ARRAY_SIZE(nrf_power_value);
|
||||
}
|
||||
|
||||
const int8_t *dtm_hw_radio_power_array_get(void)
|
||||
{
|
||||
return nrf_power_value;
|
||||
}
|
||||
|
||||
#if DIRECTION_FINDING_SUPPORTED
|
||||
size_t dtm_hw_radio_antenna_number_get(void)
|
||||
{
|
||||
return ant_cfg.ant_num;
|
||||
}
|
||||
|
||||
const uint8_t *dtm_hw_radio_antenna_pin_array_get(void)
|
||||
{
|
||||
return ant_cfg.dfe_gpio;
|
||||
}
|
||||
|
||||
uint8_t dtm_hw_radio_pdu_antenna_get(void)
|
||||
{
|
||||
return PDU_ANTENNA;
|
||||
}
|
||||
#endif /* DIRECTION_FINDING_SUPPORTED */
|
||||
98
nordic/trezor/direct_test_mode/src/dtm_hw.h
Normal file
98
nordic/trezor/direct_test_mode/src/dtm_hw.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#ifndef DTM_HW_H_
|
||||
#define DTM_HW_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <zephyr/types.h>
|
||||
|
||||
#include <hal/nrf_radio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Number of PSEL_DFEGPIO[n] registers in the radio peripheral. */
|
||||
#define DTM_HW_MAX_DFE_GPIO 8
|
||||
|
||||
/* Indicates that GPIO pin is not connected to the radio */
|
||||
#define DTM_HW_DFE_PSEL_NOT_SET 0xFF
|
||||
|
||||
/* Disconnect pin from the RADIO DFGPIO register. */
|
||||
#define DTM_HW_DFE_GPIO_PIN_DISCONNECT (RADIO_PSEL_DFEGPIO_CONNECT_Disconnected << \
|
||||
RADIO_PSEL_DFEGPIO_CONNECT_Pos)
|
||||
|
||||
/**@brief Function for validating tx power and radio mode settings.
|
||||
* @param[in] tx_power TX power for transmission test in dBm.
|
||||
* @param[in] radio_mode Radio mode value.
|
||||
*
|
||||
* @retval true If validation was successful
|
||||
* @retval false Otherwise
|
||||
*/
|
||||
bool dtm_hw_radio_validate(int8_t tx_power,
|
||||
nrf_radio_mode_t radio_mode);
|
||||
|
||||
/**@brief Function for checking if Radio operates in Long Range mode.
|
||||
* @param[in] radio_mode Radio mode value.
|
||||
*
|
||||
* @retval true If Long Range Radio mode is set
|
||||
* @retval false Otherwise
|
||||
*/
|
||||
bool dtm_hw_radio_lr_check(nrf_radio_mode_t radio_mode);
|
||||
|
||||
/**@brief Function for getting minimum tx power.
|
||||
*
|
||||
* @retval Minimum tx power value.
|
||||
*/
|
||||
uint32_t dtm_hw_radio_min_power_get(void);
|
||||
|
||||
/**@brief Function for getting maximum tx power.
|
||||
*
|
||||
* @retval Maximum tx power value.
|
||||
*/
|
||||
uint32_t dtm_hw_radio_max_power_get(void);
|
||||
|
||||
/**@brief Function for getting power array size. This array contains all
|
||||
* possible tx power values for given divice sorted in ascending
|
||||
* order.
|
||||
*
|
||||
* @reval Size of the tx power array.
|
||||
*/
|
||||
size_t dtm_hw_radio_power_array_size_get(void);
|
||||
|
||||
/**@brief Function for getting tx power array. This array contains all
|
||||
* possible tx power values for given divice sorted in ascending
|
||||
* order.
|
||||
*
|
||||
* @retval Size of the tx power array.
|
||||
*/
|
||||
const int8_t *dtm_hw_radio_power_array_get(void);
|
||||
|
||||
/**@brief Function for getting antenna pins array. This array contains
|
||||
* all antenna pins data.
|
||||
*
|
||||
* @retval Pointer to the first element in antenna pins array.
|
||||
*/
|
||||
const uint8_t *dtm_hw_radio_antenna_pin_array_get(void);
|
||||
|
||||
/**@brief Function for getting available antenna number.
|
||||
*
|
||||
* @retval Maximum antenna number that DTM can use.
|
||||
*/
|
||||
size_t dtm_hw_radio_antenna_number_get(void);
|
||||
|
||||
/**@brief Function for getting the PDU antenna.
|
||||
*
|
||||
* @retval The PDU antenna.
|
||||
*/
|
||||
uint8_t dtm_hw_radio_pdu_antenna_get(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DTM_HW_H_ */
|
||||
57
nordic/trezor/direct_test_mode/src/dtm_hw_config.h
Normal file
57
nordic/trezor/direct_test_mode/src/dtm_hw_config.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#ifndef DTM_HW_CONFIG_H_
|
||||
#define DTM_HW_CONFIG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Devicetree node identifier for the radio node. */
|
||||
#define RADIO_NODE DT_NODELABEL(radio)
|
||||
|
||||
#if DT_PROP(DT_NODELABEL(radio), dfe_supported) && \
|
||||
DT_NODE_HAS_STATUS(RADIO_NODE, okay)
|
||||
#define DIRECTION_FINDING_SUPPORTED 1
|
||||
#else
|
||||
#define DIRECTION_FINDING_SUPPORTED 0
|
||||
#endif /* DT_PROP(DT_NODELABEL(radio), dfe_supported) && \
|
||||
* DT_NODE_HAS_STATUS(RADIO_NODE, okay)
|
||||
*/
|
||||
|
||||
/* Maximum transmit or receive time, in microseconds, that the local
|
||||
* Controller supports for transmission of a single
|
||||
* Link Layer Data Physical Channel PDU, divided by 2.
|
||||
*/
|
||||
#if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || \
|
||||
defined(NRF52811_XXAA) || defined(NRF52820_XXAA)
|
||||
#define NRF_MAX_RX_TX_TIME 0x2148
|
||||
#else
|
||||
#define NRF_MAX_RX_TX_TIME 0x424
|
||||
#endif /* defined(NRF52840_XXAA) || defined(NRF52833_XXAA) ||
|
||||
* defined(NRF52811_XXAA) || defined(NRF52820_XXAA)
|
||||
*/
|
||||
|
||||
#ifdef NRF53_SERIES
|
||||
#ifndef RADIO_TXPOWER_TXPOWER_Pos3dBm
|
||||
#define RADIO_TXPOWER_TXPOWER_Pos3dBm (0x03UL)
|
||||
#endif /* RADIO_TXPOWER_TXPOWER_Pos3dBm */
|
||||
|
||||
#ifndef RADIO_TXPOWER_TXPOWER_Pos2dBm
|
||||
#define RADIO_TXPOWER_TXPOWER_Pos2dBm (0x02UL)
|
||||
#endif /* RADIO_TXPOWER_TXPOWER_Pos2dBm */
|
||||
|
||||
#ifndef RADIO_TXPOWER_TXPOWER_Pos1dBm
|
||||
#define RADIO_TXPOWER_TXPOWER_Pos1dBm (0x01UL)
|
||||
#endif /* RADIO_TXPOWER_TXPOWER_Pos1dBm */
|
||||
#endif /* NRF53_SERIES */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DTM_HW_CONFIG_H_ */
|
||||
33
nordic/trezor/direct_test_mode/src/main.c
Normal file
33
nordic/trezor/direct_test_mode/src/main.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/sys/printk.h>
|
||||
|
||||
#include "transport/dtm_transport.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int err;
|
||||
union dtm_tr_packet cmd;
|
||||
|
||||
printk("Starting Direct Test Mode example\n");
|
||||
|
||||
err = dtm_tr_init();
|
||||
if (err) {
|
||||
printk("Error initializing DTM transport: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
cmd = dtm_tr_get();
|
||||
err = dtm_tr_process(cmd);
|
||||
if (err) {
|
||||
printk("Error processing command: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
772
nordic/trezor/direct_test_mode/src/transport/dtm_hci.c
Normal file
772
nordic/trezor/direct_test_mode/src/transport/dtm_hci.c
Normal file
@@ -0,0 +1,772 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/drivers/uart.h>
|
||||
#include <zephyr/net_buf.h>
|
||||
#include <zephyr/bluetooth/hci_types.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include <dtm.h>
|
||||
|
||||
#include "hci_uart.h"
|
||||
#include "dtm_transport.h"
|
||||
|
||||
LOG_MODULE_REGISTER(dtm_hci_tr, CONFIG_DTM_TRANSPORT_LOG_LEVEL);
|
||||
|
||||
#define BT_LE_FEAT_SET(feat, n) (feat[(n) >> 3] |= BIT((n) & 7))
|
||||
|
||||
#define MAX_ANT_PATTERN_LENGTH 0x4B
|
||||
#define SYNC_HANDLE_RECEIVER_TEST 0x0FFF
|
||||
|
||||
#define CONNECTIONLESS_IQ_REPORT_MAX_SIZE (sizeof(struct hci_connectionless_iq_report_evt) + \
|
||||
(B_HCI_LE_CTE_REPORT_SAMPLE_COUNT_MAX * sizeof(struct bt_hci_le_iq_sample)))
|
||||
|
||||
/* HCI_Command_Complete with status only */
|
||||
struct hci_base_cc_evt {
|
||||
struct bt_hci_evt_cmd_complete evt;
|
||||
struct bt_hci_evt_cc_status ret;
|
||||
} __packed;
|
||||
|
||||
/* HCI_Command_Complete for Test End */
|
||||
struct hci_test_end_cc_evt {
|
||||
struct bt_hci_evt_cmd_complete evt;
|
||||
struct bt_hci_rp_le_test_end ret;
|
||||
} __packed;
|
||||
|
||||
/* HCI_Command_Complete for Read BD Addr */
|
||||
struct hci_read_bd_addr_evt {
|
||||
struct bt_hci_evt_cmd_complete evt;
|
||||
struct bt_hci_rp_read_bd_addr ret;
|
||||
} __packed;
|
||||
|
||||
/* HCI_Command_Complete for Read Local Features */
|
||||
struct hci_read_local_feat_evt {
|
||||
struct bt_hci_evt_cmd_complete evt;
|
||||
struct bt_hci_rp_le_read_local_features ret;
|
||||
} __packed;
|
||||
|
||||
/* HCI Connectionless IQ report */
|
||||
struct hci_connectionless_iq_report_evt {
|
||||
struct bt_hci_evt_le_meta_event evt;
|
||||
struct bt_hci_evt_le_connectionless_iq_report report;
|
||||
} __packed;
|
||||
|
||||
/* HCI RX Test all versions params */
|
||||
union rx_params {
|
||||
struct bt_hci_cp_le_rx_test v1;
|
||||
struct bt_hci_cp_le_enh_rx_test v2;
|
||||
struct bt_hci_cp_le_rx_test_v3 v3;
|
||||
};
|
||||
|
||||
/* HCI TX Test all versions params */
|
||||
union tx_params {
|
||||
struct bt_hci_cp_le_tx_test v1;
|
||||
struct bt_hci_cp_le_enh_tx_test v2;
|
||||
struct bt_hci_cp_le_tx_test_v3 v3;
|
||||
struct bt_hci_cp_le_tx_test_v4 v4;
|
||||
};
|
||||
|
||||
static K_FIFO_DEFINE(hci_rx_queue);
|
||||
|
||||
static int hci_to_dtm_payload(uint8_t hci_pld, enum dtm_packet *dtm_pld)
|
||||
{
|
||||
if (!dtm_pld) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (hci_pld) {
|
||||
case BT_HCI_TEST_PKT_PAYLOAD_PRBS9:
|
||||
*dtm_pld = DTM_PACKET_PRBS9;
|
||||
break;
|
||||
|
||||
case BT_HCI_TEST_PKT_PAYLOAD_11110000:
|
||||
*dtm_pld = DTM_PACKET_0F;
|
||||
break;
|
||||
|
||||
case BT_HCI_TEST_PKT_PAYLOAD_10101010:
|
||||
*dtm_pld = DTM_PACKET_55;
|
||||
break;
|
||||
|
||||
case BT_HCI_TEST_PKT_PAYLOAD_PRBS15:
|
||||
*dtm_pld = DTM_PACKET_PRBS15;
|
||||
break;
|
||||
|
||||
case BT_HCI_TEST_PKT_PAYLOAD_11111111:
|
||||
*dtm_pld = DTM_PACKET_FF;
|
||||
break;
|
||||
|
||||
case BT_HCI_TEST_PKT_PAYLOAD_00000000:
|
||||
*dtm_pld = DTM_PACKET_00;
|
||||
break;
|
||||
|
||||
case BT_HCI_TEST_PKT_PAYLOAD_00001111:
|
||||
*dtm_pld = DTM_PACKET_F0;
|
||||
break;
|
||||
|
||||
case BT_HCI_TEST_PKT_PAYLOAD_01010101:
|
||||
*dtm_pld = DTM_PACKET_AA;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int phy_set(uint8_t phy)
|
||||
{
|
||||
switch (phy) {
|
||||
case BT_HCI_LE_TX_PHY_1M:
|
||||
return dtm_setup_set_phy(DTM_PHY_1M);
|
||||
|
||||
case BT_HCI_LE_TX_PHY_2M:
|
||||
return dtm_setup_set_phy(DTM_PHY_2M);
|
||||
|
||||
case BT_HCI_LE_TX_PHY_CODED_S8:
|
||||
return dtm_setup_set_phy(DTM_PHY_CODED_S8);
|
||||
|
||||
case BT_HCI_LE_TX_PHY_CODED_S2:
|
||||
return dtm_setup_set_phy(DTM_PHY_CODED_S2);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int mod_set(uint8_t mod)
|
||||
{
|
||||
switch (mod) {
|
||||
case BT_HCI_LE_MOD_INDEX_STANDARD:
|
||||
return dtm_setup_set_modulation(DTM_MODULATION_STANDARD);
|
||||
|
||||
case BT_HCI_LE_MOD_INDEX_STABLE:
|
||||
return dtm_setup_set_modulation(DTM_MODULATION_STABLE);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int cte_set(uint8_t cte_len, uint8_t cte_type,
|
||||
uint8_t pattern_len, uint8_t *pattern)
|
||||
{
|
||||
static uint8_t cur_pattern[MAX_ANT_PATTERN_LENGTH];
|
||||
int err;
|
||||
|
||||
/* Check if CTE is used at all */
|
||||
if (!cte_len) {
|
||||
return dtm_setup_set_cte_mode(DTM_CTE_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
if (pattern_len > MAX_ANT_PATTERN_LENGTH) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (cte_type) {
|
||||
case BT_HCI_LE_AOA_CTE:
|
||||
err = dtm_setup_set_cte_mode(DTM_CTE_TYPE_AOA, cte_len);
|
||||
break;
|
||||
|
||||
case BT_HCI_LE_AOD_CTE_1US:
|
||||
err = dtm_setup_set_cte_mode(DTM_CTE_TYPE_AOD_1US, cte_len);
|
||||
break;
|
||||
|
||||
case BT_HCI_LE_AOD_CTE_2US:
|
||||
err = dtm_setup_set_cte_mode(DTM_CTE_TYPE_AOD_2US, cte_len);
|
||||
break;
|
||||
|
||||
default:
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
memcpy(cur_pattern, pattern, pattern_len);
|
||||
|
||||
return dtm_setup_set_antenna_params(0, cur_pattern, pattern_len);
|
||||
}
|
||||
|
||||
static int tx_power_set(int8_t power, uint8_t channel)
|
||||
{
|
||||
switch (power) {
|
||||
case BT_HCI_TX_TEST_POWER_MIN_SET:
|
||||
dtm_setup_set_transmit_power(DTM_TX_POWER_REQUEST_MIN, 0, channel);
|
||||
break;
|
||||
|
||||
case BT_HCI_TX_TEST_POWER_MAX_SET:
|
||||
dtm_setup_set_transmit_power(DTM_TX_POWER_REQUEST_MAX, 0, channel);
|
||||
break;
|
||||
|
||||
case BT_HCI_TX_TEST_POWER_MIN ... BT_HCI_TX_TEST_POWER_MAX:
|
||||
dtm_setup_set_transmit_power(DTM_TX_POWER_REQUEST_VAL, power, channel);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int base_cc_evt(uint16_t opcode, uint8_t status)
|
||||
{
|
||||
struct hci_base_cc_evt tmp;
|
||||
struct bt_hci_evt_hdr hdr;
|
||||
|
||||
hdr.evt = BT_HCI_EVT_CMD_COMPLETE;
|
||||
hdr.len = sizeof(tmp);
|
||||
|
||||
tmp.evt.ncmd = 1;
|
||||
sys_put_le16(opcode, (uint8_t *)&tmp.evt.opcode);
|
||||
|
||||
tmp.ret.status = status;
|
||||
|
||||
LOG_INF("Responding to opcode %x, with status %d", opcode, status);
|
||||
return hci_uart_write(H4_TYPE_EVT, (uint8_t *)&hdr, sizeof(hdr), (uint8_t *)&tmp, hdr.len);
|
||||
}
|
||||
|
||||
static int test_end_cc_evt(uint8_t status, uint16_t cnt)
|
||||
{
|
||||
struct hci_test_end_cc_evt tmp;
|
||||
struct bt_hci_evt_hdr hdr;
|
||||
|
||||
hdr.evt = BT_HCI_EVT_CMD_COMPLETE;
|
||||
hdr.len = sizeof(tmp);
|
||||
|
||||
tmp.evt.ncmd = 1;
|
||||
sys_put_le16(BT_HCI_OP_LE_TEST_END, (uint8_t *)&tmp.evt.opcode);
|
||||
|
||||
tmp.ret.status = status;
|
||||
sys_put_le16(cnt, (uint8_t *)&tmp.ret.rx_pkt_count);
|
||||
|
||||
LOG_INF("Responding to test end, with status %d and count %d", status, cnt);
|
||||
return hci_uart_write(H4_TYPE_EVT, (uint8_t *)&hdr, sizeof(hdr), (uint8_t *)&tmp, hdr.len);
|
||||
}
|
||||
|
||||
static int read_bd_addr_cc_evt(uint8_t status)
|
||||
{
|
||||
struct hci_read_bd_addr_evt tmp;
|
||||
struct bt_hci_evt_hdr hdr;
|
||||
bt_addr_t bt_addr_zero = { { 0, 0, 0, 0, 0, 0 } };
|
||||
|
||||
hdr.evt = BT_HCI_EVT_CMD_COMPLETE;
|
||||
hdr.len = sizeof(tmp);
|
||||
|
||||
tmp.evt.ncmd = 1;
|
||||
sys_put_le16(BT_HCI_OP_READ_BD_ADDR, (uint8_t *)&tmp.evt.opcode);
|
||||
|
||||
tmp.ret.status = status;
|
||||
memcpy(&tmp.ret.bdaddr, &bt_addr_zero, sizeof(tmp.ret.bdaddr));
|
||||
|
||||
LOG_INF("Responding to address query with status %d", status);
|
||||
return hci_uart_write(H4_TYPE_EVT, (uint8_t *)&hdr, sizeof(hdr), (uint8_t *)&tmp, hdr.len);
|
||||
}
|
||||
|
||||
static int read_local_feat_cc_evt(uint8_t status, uint8_t *features)
|
||||
{
|
||||
struct hci_read_local_feat_evt tmp;
|
||||
struct bt_hci_evt_hdr hdr;
|
||||
|
||||
hdr.evt = BT_HCI_EVT_CMD_COMPLETE;
|
||||
hdr.len = sizeof(tmp);
|
||||
|
||||
tmp.evt.ncmd = 1;
|
||||
sys_put_le16(BT_HCI_OP_LE_READ_LOCAL_FEATURES, (uint8_t *)&tmp.evt.opcode);
|
||||
|
||||
tmp.ret.status = status;
|
||||
memcpy(&tmp.ret.features, features, sizeof(tmp.ret.features));
|
||||
|
||||
LOG_INF("Responding to features query with status %d", status);
|
||||
return hci_uart_write(H4_TYPE_EVT, (uint8_t *)&hdr, sizeof(hdr), (uint8_t *)&tmp, hdr.len);
|
||||
}
|
||||
|
||||
static void iq_report_evt(struct dtm_iq_data *iq_data)
|
||||
{
|
||||
uint8_t buf[CONNECTIONLESS_IQ_REPORT_MAX_SIZE];
|
||||
struct hci_connectionless_iq_report_evt *tmp =
|
||||
(struct hci_connectionless_iq_report_evt *)buf;
|
||||
struct bt_hci_evt_hdr hdr;
|
||||
size_t i;
|
||||
int err;
|
||||
|
||||
hdr.evt = BT_HCI_EVT_LE_META_EVENT;
|
||||
hdr.len = sizeof(*tmp);
|
||||
hdr.len += sizeof(struct bt_hci_le_iq_sample) * iq_data->sample_cnt;
|
||||
|
||||
if (hdr.len > CONNECTIONLESS_IQ_REPORT_MAX_SIZE) {
|
||||
LOG_ERR("Invalid sample count in IQ report callback.");
|
||||
return;
|
||||
}
|
||||
|
||||
tmp->evt.subevent = BT_HCI_EVT_LE_CONNECTIONLESS_IQ_REPORT;
|
||||
|
||||
tmp->report.sync_handle = sys_cpu_to_le16(SYNC_HANDLE_RECEIVER_TEST);
|
||||
tmp->report.chan_idx = iq_data->channel;
|
||||
tmp->report.rssi = iq_data->rssi;
|
||||
tmp->report.rssi_ant_id = iq_data->rssi_ant;
|
||||
|
||||
switch (iq_data->type) {
|
||||
case DTM_CTE_TYPE_AOA:
|
||||
tmp->report.cte_type = BT_HCI_LE_AOA_CTE;
|
||||
break;
|
||||
|
||||
case DTM_CTE_TYPE_AOD_1US:
|
||||
tmp->report.cte_type = BT_HCI_LE_AOD_CTE_1US;
|
||||
break;
|
||||
|
||||
case DTM_CTE_TYPE_AOD_2US:
|
||||
tmp->report.cte_type = BT_HCI_LE_AOD_CTE_2US;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERR("Invalid CTE type in IQ report callback.");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (iq_data->slot) {
|
||||
case DTM_CTE_SLOT_DURATION_1US:
|
||||
tmp->report.slot_durations = BT_HCI_LE_ANTENNA_SWITCHING_SLOT_1US;
|
||||
break;
|
||||
|
||||
case DTM_CTE_SLOT_DURATION_2US:
|
||||
tmp->report.slot_durations = BT_HCI_LE_ANTENNA_SWITCHING_SLOT_2US;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERR("Invalid CTE slot duration in IQ report callback.");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (iq_data->status) {
|
||||
case DTM_PACKET_STATUS_CRC_OK:
|
||||
tmp->report.packet_status = BT_HCI_LE_CTE_CRC_OK;
|
||||
break;
|
||||
|
||||
case DTM_PACKET_STATUS_CRC_ERR_TIME:
|
||||
tmp->report.packet_status = BT_HCI_LE_CTE_CRC_ERR_CTE_BASED_TIME;
|
||||
break;
|
||||
|
||||
case DTM_PACKET_STATUS_CRC_ERR_OTHER:
|
||||
tmp->report.packet_status = BT_HCI_LE_CTE_CRC_ERR_CTE_BASED_OTHER;
|
||||
break;
|
||||
|
||||
case DTM_PACKET_STATUS_CRC_ERR_INSUFFICIENT:
|
||||
tmp->report.packet_status = BT_HCI_LE_CTE_INSUFFICIENT_RESOURCES;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERR("Invalid status in IQ report callback.");
|
||||
return;
|
||||
}
|
||||
|
||||
tmp->report.per_evt_counter = 0;
|
||||
|
||||
tmp->report.sample_count = iq_data->sample_cnt;
|
||||
for (i = 0; i < tmp->report.sample_count; i++) {
|
||||
if (iq_data->samples[i].i == NRF_IQ_SAMPLE_INVALID) {
|
||||
tmp->report.sample[i].i = BT_HCI_LE_CTE_REPORT_NO_VALID_SAMPLE;
|
||||
} else {
|
||||
tmp->report.sample[i].i = (int8_t)(iq_data->samples[i].i >> 4);
|
||||
}
|
||||
|
||||
if (iq_data->samples[i].q == NRF_IQ_SAMPLE_INVALID) {
|
||||
tmp->report.sample[i].q = BT_HCI_LE_CTE_REPORT_NO_VALID_SAMPLE;
|
||||
} else {
|
||||
tmp->report.sample[i].q = (int8_t)(iq_data->samples[i].q >> 4);
|
||||
}
|
||||
}
|
||||
|
||||
err = hci_uart_write(H4_TYPE_EVT, (uint8_t *)&hdr, sizeof(hdr), (uint8_t *)&buf, hdr.len);
|
||||
if (err) {
|
||||
LOG_ERR("Error writing LE Connectionless IQ Report event.");
|
||||
}
|
||||
}
|
||||
|
||||
static int hci_reset(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dtm_setup_reset();
|
||||
if (err) {
|
||||
base_cc_evt(BT_HCI_OP_RESET, BT_HCI_ERR_HW_FAILURE);
|
||||
}
|
||||
|
||||
return base_cc_evt(BT_HCI_OP_RESET, BT_HCI_ERR_SUCCESS);
|
||||
}
|
||||
|
||||
static int hci_read_bd_addr(void)
|
||||
{
|
||||
return read_bd_addr_cc_evt(BT_HCI_ERR_SUCCESS);
|
||||
}
|
||||
|
||||
static int hci_read_local_features(void)
|
||||
{
|
||||
uint8_t hci_features[8] = { 0 };
|
||||
struct dtm_supp_features features;
|
||||
|
||||
features = dtm_setup_read_features();
|
||||
|
||||
if (features.data_len_ext) {
|
||||
BT_LE_FEAT_SET(hci_features, BT_LE_FEAT_BIT_DLE);
|
||||
}
|
||||
|
||||
if (features.phy_2m) {
|
||||
BT_LE_FEAT_SET(hci_features, BT_LE_FEAT_BIT_PHY_2M);
|
||||
}
|
||||
|
||||
if (features.stable_mod) {
|
||||
BT_LE_FEAT_SET(hci_features, BT_LE_FEAT_BIT_SMI_TX);
|
||||
BT_LE_FEAT_SET(hci_features, BT_LE_FEAT_BIT_SMI_RX);
|
||||
}
|
||||
|
||||
if (features.coded_phy) {
|
||||
BT_LE_FEAT_SET(hci_features, BT_LE_FEAT_BIT_PHY_CODED);
|
||||
}
|
||||
|
||||
if (features.cte) {
|
||||
BT_LE_FEAT_SET(hci_features, BT_LE_FEAT_BIT_RX_CTE);
|
||||
}
|
||||
|
||||
if (features.ant_switching) {
|
||||
BT_LE_FEAT_SET(hci_features, BT_LE_FEAT_BIT_ANT_SWITCH_TX_AOD);
|
||||
BT_LE_FEAT_SET(hci_features, BT_LE_FEAT_BIT_ANT_SWITCH_RX_AOA);
|
||||
}
|
||||
|
||||
return read_local_feat_cc_evt(BT_HCI_ERR_SUCCESS, hci_features);
|
||||
}
|
||||
|
||||
static int hci_rx_test(uint16_t opcode, const uint8_t *data)
|
||||
{
|
||||
union rx_params *params = (union rx_params *)data;
|
||||
uint8_t def_pattern[2] = {0, 0};
|
||||
int err;
|
||||
|
||||
uint8_t chan;
|
||||
uint8_t phy = 0x01;
|
||||
uint8_t mod = 0x00;
|
||||
uint8_t cte_len = 0x00;
|
||||
uint8_t cte_type = 0x00;
|
||||
uint8_t slot_durations = 0x01;
|
||||
uint8_t pattern_len = 0x02;
|
||||
uint8_t *pattern = def_pattern;
|
||||
|
||||
switch (opcode) {
|
||||
case BT_HCI_OP_LE_RX_TEST:
|
||||
chan = params->v1.rx_ch;
|
||||
LOG_DBG("RX Test command: v1, chan: %d.", chan);
|
||||
break;
|
||||
|
||||
case BT_HCI_OP_LE_ENH_RX_TEST:
|
||||
chan = params->v2.rx_ch;
|
||||
phy = params->v2.phy;
|
||||
mod = params->v2.mod_index;
|
||||
LOG_DBG("RX Test command: v2, chan: %d, phy: %d, mod: %d.", chan, phy, mod);
|
||||
break;
|
||||
|
||||
case BT_HCI_OP_LE_RX_TEST_V3:
|
||||
chan = params->v3.rx_ch;
|
||||
phy = params->v3.phy;
|
||||
mod = params->v3.mod_index;
|
||||
cte_len = params->v3.expected_cte_len;
|
||||
cte_type = params->v3.expected_cte_type;
|
||||
slot_durations = params->v3.slot_durations;
|
||||
pattern_len = params->v3.switch_pattern_len;
|
||||
pattern = params->v3.ant_ids;
|
||||
LOG_DBG("RX Test command: v3, chan: %d, phy: %d, mod: %d, cte_len: %d,"
|
||||
" cte_type: %d, slot_durations: %d, pattern_len: %d.",
|
||||
chan, phy, mod, cte_len, cte_type, slot_durations, pattern_len);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dtm_setup_prepare();
|
||||
|
||||
err = phy_set(phy);
|
||||
if (err) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL);
|
||||
}
|
||||
|
||||
err = mod_set(mod);
|
||||
if (err == -ENOTSUP) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL);
|
||||
} else if (err) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_HW_FAILURE);
|
||||
}
|
||||
|
||||
if ((cte_len != 0) &&
|
||||
(phy != BT_HCI_LE_TX_PHY_CODED_S8) && (phy != BT_HCI_LE_TX_PHY_CODED_S2)) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_CMD_DISALLOWED);
|
||||
}
|
||||
|
||||
err = cte_set(cte_len, cte_type, pattern_len, pattern);
|
||||
if (err == -ENOTSUP) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL);
|
||||
} else if (err) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_HW_FAILURE);
|
||||
}
|
||||
|
||||
if (cte_len != 0) {
|
||||
err = dtm_setup_set_cte_slot(slot_durations);
|
||||
if (err == -ENOTSUP) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL);
|
||||
} else if (err == -EINVAL) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_INVALID_PARAM);
|
||||
} else if (err != 0) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_HW_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
err = dtm_test_receive(chan);
|
||||
if (err == -EINVAL) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_INVALID_PARAM);
|
||||
} else if (err) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_HW_FAILURE);
|
||||
}
|
||||
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_SUCCESS);
|
||||
}
|
||||
|
||||
static int hci_tx_test(uint16_t opcode, const uint8_t *data)
|
||||
{
|
||||
union tx_params *params = (union tx_params *)data;
|
||||
uint8_t def_pattern[2] = {0, 0};
|
||||
|
||||
uint8_t chan;
|
||||
uint8_t data_len;
|
||||
uint8_t payload;
|
||||
uint8_t phy = BT_HCI_LE_TX_PHY_1M;
|
||||
uint8_t cte_len = 0x00;
|
||||
uint8_t cte_type = 0x00;
|
||||
uint8_t pattern_len = 0x02;
|
||||
uint8_t *pattern = def_pattern;
|
||||
int8_t power = 0x7F;
|
||||
|
||||
enum dtm_packet pld;
|
||||
int err;
|
||||
|
||||
switch (opcode) {
|
||||
case BT_HCI_OP_LE_TX_TEST:
|
||||
chan = params->v1.tx_ch;
|
||||
data_len = params->v1.test_data_len;
|
||||
payload = params->v1.pkt_payload;
|
||||
LOG_DBG("TX Test command: v1, chan: %d, data_len: %d, payload %d.",
|
||||
chan, data_len, payload);
|
||||
break;
|
||||
|
||||
case BT_HCI_OP_LE_ENH_TX_TEST:
|
||||
chan = params->v2.tx_ch;
|
||||
data_len = params->v2.test_data_len;
|
||||
payload = params->v2.pkt_payload;
|
||||
phy = params->v2.phy;
|
||||
LOG_DBG("TX Test command: v2, chan: %d, data_len: %d, payload: %d, phy: %d.",
|
||||
chan, data_len, payload, phy);
|
||||
break;
|
||||
|
||||
case BT_HCI_OP_LE_TX_TEST_V3:
|
||||
chan = params->v3.tx_ch;
|
||||
data_len = params->v3.test_data_len;
|
||||
payload = params->v3.pkt_payload;
|
||||
phy = params->v3.phy;
|
||||
cte_len = params->v3.cte_len;
|
||||
cte_type = params->v3.cte_type;
|
||||
pattern_len = params->v3.switch_pattern_len;
|
||||
pattern = params->v3.ant_ids;
|
||||
LOG_DBG("TX Test command: v3, chan: %d, data_len: %d, payload: %d, phy: %d,"
|
||||
" cte_len: %d, cte_type: %d, pattern_len: %d.",
|
||||
chan, data_len, payload, phy, cte_len, cte_type, pattern_len);
|
||||
break;
|
||||
|
||||
case BT_HCI_OP_LE_TX_TEST_V4:
|
||||
struct bt_hci_cp_le_tx_test_v4_tx_power *tmp;
|
||||
|
||||
chan = params->v4.tx_ch;
|
||||
data_len = params->v4.test_data_len;
|
||||
payload = params->v4.pkt_payload;
|
||||
phy = params->v4.phy;
|
||||
cte_len = params->v4.cte_len;
|
||||
cte_type = params->v4.cte_type;
|
||||
pattern_len = params->v4.switch_pattern_len;
|
||||
pattern = params->v4.ant_ids;
|
||||
tmp = (struct bt_hci_cp_le_tx_test_v4_tx_power *)&(params->v4.ant_ids[pattern_len]);
|
||||
power = tmp->tx_power;
|
||||
LOG_DBG("TX Test command: v3, chan: %d, data_len: %d, payload: %d, phy: %d,"
|
||||
" cte_len: %d, cte_type: %d, pattern_len: %d, power: %d.",
|
||||
chan, data_len, payload, phy, cte_len, cte_type, pattern_len, power);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dtm_setup_prepare();
|
||||
|
||||
err = hci_to_dtm_payload(payload, &pld);
|
||||
if (err) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL);
|
||||
}
|
||||
|
||||
err = phy_set(phy);
|
||||
if (err) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL);
|
||||
}
|
||||
|
||||
if ((cte_len != 0) &&
|
||||
(phy != BT_HCI_LE_TX_PHY_CODED_S8) && (phy != BT_HCI_LE_TX_PHY_CODED_S2)) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_CMD_DISALLOWED);
|
||||
}
|
||||
|
||||
err = cte_set(cte_len, cte_type, pattern_len, pattern);
|
||||
if (err == -ENOTSUP) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL);
|
||||
} else if (err) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_HW_FAILURE);
|
||||
}
|
||||
|
||||
err = tx_power_set(power, chan);
|
||||
if (err) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL);
|
||||
}
|
||||
|
||||
err = dtm_test_transmit(chan, data_len, pld);
|
||||
if (err == -EINVAL) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_INVALID_PARAM);
|
||||
} else if (err) {
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_HW_FAILURE);
|
||||
}
|
||||
|
||||
return base_cc_evt(opcode, BT_HCI_ERR_SUCCESS);
|
||||
}
|
||||
|
||||
static int hci_test_end(void)
|
||||
{
|
||||
uint16_t cnt;
|
||||
int err;
|
||||
|
||||
err = dtm_test_end(&cnt);
|
||||
|
||||
if (err == -EINVAL) {
|
||||
return test_end_cc_evt(BT_HCI_ERR_INVALID_PARAM, cnt);
|
||||
} else if (err) {
|
||||
return test_end_cc_evt(BT_HCI_ERR_HW_FAILURE, cnt);
|
||||
}
|
||||
|
||||
return test_end_cc_evt(BT_HCI_ERR_SUCCESS, cnt);
|
||||
}
|
||||
|
||||
static int hci_cmd(const struct bt_hci_cmd_hdr *hdr, const uint8_t *data)
|
||||
{
|
||||
uint16_t cmd;
|
||||
|
||||
cmd = sys_le16_to_cpu(hdr->opcode);
|
||||
|
||||
LOG_INF("Processing HCI command opcode: 0x%04x", cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case BT_HCI_OP_RESET:
|
||||
LOG_INF("Executing HCI reset command.");
|
||||
return hci_reset();
|
||||
|
||||
case BT_HCI_OP_READ_BD_ADDR:
|
||||
LOG_INF("Executing HCI Read BD_ADDR command.");
|
||||
return hci_read_bd_addr();
|
||||
|
||||
case BT_HCI_OP_LE_READ_LOCAL_FEATURES:
|
||||
LOG_INF("Executing HCI LE Read Local Supported Features command.");
|
||||
return hci_read_local_features();
|
||||
|
||||
case BT_HCI_OP_LE_RX_TEST:
|
||||
case BT_HCI_OP_LE_ENH_RX_TEST:
|
||||
case BT_HCI_OP_LE_RX_TEST_V3:
|
||||
LOG_INF("Executing HCI LE Receiver Test command.");
|
||||
return hci_rx_test(cmd, data);
|
||||
|
||||
case BT_HCI_OP_LE_TX_TEST:
|
||||
case BT_HCI_OP_LE_ENH_TX_TEST:
|
||||
case BT_HCI_OP_LE_TX_TEST_V3:
|
||||
case BT_HCI_OP_LE_TX_TEST_V4:
|
||||
LOG_INF("Executing HCI LE Transmitter Test command.");
|
||||
return hci_tx_test(cmd, data);
|
||||
|
||||
case BT_HCI_OP_LE_TEST_END:
|
||||
LOG_INF("Executing HCI LE Test End command.");
|
||||
return hci_test_end();
|
||||
|
||||
default:
|
||||
LOG_ERR("Unknown HCI command opcode: 0x%04x", cmd);
|
||||
base_cc_evt(cmd, BT_HCI_ERR_UNKNOWN_CMD);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
static void dtm_hci_put(struct net_buf *buf)
|
||||
{
|
||||
k_fifo_put(&hci_rx_queue, buf);
|
||||
}
|
||||
|
||||
int dtm_tr_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = hci_uart_init(dtm_hci_put);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to initialize HCI over UART: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = dtm_init(iq_report_evt);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to initialize DTM: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
union dtm_tr_packet dtm_tr_get(void)
|
||||
{
|
||||
union dtm_tr_packet tmp;
|
||||
|
||||
tmp.hci = k_fifo_get(&hci_rx_queue, K_FOREVER);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int dtm_tr_process(union dtm_tr_packet cmd)
|
||||
{
|
||||
struct net_buf *buf = cmd.hci;
|
||||
const struct bt_hci_cmd_hdr *hdr;
|
||||
const uint8_t *data;
|
||||
uint8_t type;
|
||||
int err;
|
||||
|
||||
if (!buf) {
|
||||
LOG_ERR("Command pointer is NULL.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
type = *(uint8_t *)net_buf_user_data(buf);
|
||||
|
||||
switch (type) {
|
||||
case H4_TYPE_CMD:
|
||||
hdr = (const struct bt_hci_cmd_hdr *)buf->data;
|
||||
data = buf->data + sizeof(*hdr);
|
||||
err = hci_cmd(hdr, data);
|
||||
net_buf_unref(buf);
|
||||
return err;
|
||||
|
||||
default:
|
||||
LOG_ERR("Tried to process unsupported HCI type.");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
64
nordic/trezor/direct_test_mode/src/transport/dtm_transport.h
Normal file
64
nordic/trezor/direct_test_mode/src/transport/dtm_transport.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#ifndef DTM_TRANSPORT_H_
|
||||
#define DTM_TRANSPORT_H_
|
||||
|
||||
#include <zephyr/net_buf.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if (CONFIG_DTM_TRANSPORT_HCI || CONFIG_DTM_REMOTE_HCI_CHILD)
|
||||
#define H4_TYPE_CMD 0x01
|
||||
#define H4_TYPE_ACL 0x02
|
||||
#define H4_TYPE_EVT 0x04
|
||||
#define H4_TYPE_ISO 0x05
|
||||
#endif
|
||||
|
||||
/** @brief DTM transport packet. */
|
||||
union dtm_tr_packet {
|
||||
/** HCI packet buffer. */
|
||||
struct net_buf *hci;
|
||||
|
||||
/** Two-wire uart 2-octet packet. */
|
||||
uint16_t twowire;
|
||||
};
|
||||
|
||||
/** @brief Initialize DTM transport layer.
|
||||
*
|
||||
* @note This function also initializes the DTM module.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int dtm_tr_init(void);
|
||||
|
||||
/** @brief Poll for DTM command.
|
||||
*
|
||||
* This function polls for DTM command.
|
||||
*
|
||||
* @return DTM command.
|
||||
*/
|
||||
union dtm_tr_packet dtm_tr_get(void);
|
||||
|
||||
/** @brief Process DTM command and respond.
|
||||
*
|
||||
* This function processes the DTM command
|
||||
* and responds to the tester.
|
||||
*
|
||||
* @param[in] cmd DTM command.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int dtm_tr_process(union dtm_tr_packet cmd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DTM_TRANSPORT_H_ */
|
||||
809
nordic/trezor/direct_test_mode/src/transport/dtm_uart_twowire.c
Normal file
809
nordic/trezor/direct_test_mode/src/transport/dtm_uart_twowire.c
Normal file
@@ -0,0 +1,809 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <zephyr/drivers/uart.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <dtm.h>
|
||||
|
||||
#include "dtm_uart_wait.h"
|
||||
#include "dtm_transport.h"
|
||||
|
||||
LOG_MODULE_REGISTER(dtm_tw_tr, CONFIG_DTM_TRANSPORT_LOG_LEVEL);
|
||||
|
||||
/* Mask of the CTE type in the CTEInfo. */
|
||||
#define LE_CTE_TYPE_MASK 0x03
|
||||
|
||||
/* Position of the CTE type in the CTEInfo. */
|
||||
#define LE_CTE_TYPE_POS 0x06
|
||||
|
||||
/* Mask of the CTE Time in the CTEInfo. */
|
||||
#define LE_CTE_CTETIME_MASK 0x1F
|
||||
|
||||
/* DTM command parameter: Mask of the Antenna Number. */
|
||||
#define LE_ANTENNA_NUMBER_MASK 0x7F
|
||||
|
||||
/* DTM command parameter: Position of the Antenna switch pattern. */
|
||||
#define LE_ANTENNA_SWITCH_PATTERN_POS 0x07
|
||||
|
||||
/* DTM command parameter: Mask of the Antenna switch pattern. */
|
||||
#define LE_ANTENNA_SWITCH_PATTERN_MASK 0x80
|
||||
|
||||
/* Position of power level in the DTM power level set response. */
|
||||
#define LE_TRANSMIT_POWER_RESPONSE_LVL_POS (0x01)
|
||||
|
||||
/* Mask of the power level in the DTM power level set respose. */
|
||||
#define LE_TRANSMIT_POWER_RESPONSE_LVL_MASK (0x1FE)
|
||||
|
||||
/* Maximum power level bit in the power level set response. */
|
||||
#define LE_TRANSMIT_POWER_MAX_LVL_BIT BIT(0x0A)
|
||||
|
||||
/* Minimum power level bit in the power level set response. */
|
||||
#define LE_TRANSMIT_POWER_MIN_LVL_BIT BIT(0x09)
|
||||
|
||||
/* Response event data shift. */
|
||||
#define DTM_RESPONSE_EVENT_SHIFT 0x01
|
||||
|
||||
/* DTM command parameter: Upper bits mask. */
|
||||
#define LE_UPPER_BITS_MASK 0xC0
|
||||
|
||||
/* DTM command parameter: Upper bits position. */
|
||||
#define LE_UPPER_BITS_POS 0x04
|
||||
|
||||
/* Event status response bits for Read Supported variant of LE Test Setup
|
||||
* command.
|
||||
*/
|
||||
#define LE_TEST_SETUP_DLE_SUPPORTED BIT(1)
|
||||
#define LE_TEST_SETUP_2M_PHY_SUPPORTED BIT(2)
|
||||
#define LE_TEST_STABLE_MODULATION_SUPPORTED BIT(3)
|
||||
#define LE_TEST_CODED_PHY_SUPPORTED BIT(4)
|
||||
#define LE_TEST_CTE_SUPPORTED BIT(5)
|
||||
#define DTM_LE_ANTENNA_SWITCH BIT(6)
|
||||
#define DTM_LE_AOD_1US_TANSMISSION BIT(7)
|
||||
#define DTM_LE_AOD_1US_RECEPTION BIT(8)
|
||||
#define DTM_LE_AOA_1US_RECEPTION BIT(9)
|
||||
|
||||
/* The DTM maximum wait time in milliseconds for the UART command second byte. */
|
||||
#define DTM_UART_SECOND_BYTE_MAX_DELAY 5
|
||||
|
||||
static const struct device *dtm_uart = DEVICE_DT_GET(DTM_UART);
|
||||
|
||||
/* DTM command codes */
|
||||
enum dtm_cmd_code {
|
||||
/* Test Setup Command: Set PHY or modulation, configure upper two bits
|
||||
* of length, request matrix of supported features or request max
|
||||
* values of parameters.
|
||||
*/
|
||||
LE_TEST_SETUP = 0x0,
|
||||
|
||||
/* Receive Command: Start receive test. */
|
||||
LE_RECEIVER_TEST = 0x1,
|
||||
|
||||
/* Transmit Command: Start transmission test. */
|
||||
LE_TRANSMITTER_TEST = 0x2,
|
||||
|
||||
/* Test End Command: End test and send packet report. */
|
||||
LE_TEST_END = 0x3,
|
||||
};
|
||||
|
||||
/* DTM Test Setup Control codes */
|
||||
enum dtm_ctrl_code {
|
||||
/* Reset the packet length upper bits and set the PHY to 1Mbit. */
|
||||
LE_TEST_SETUP_RESET = 0x00,
|
||||
|
||||
/* Set the upper two bits of the length field. */
|
||||
LE_TEST_SETUP_SET_UPPER = 0x01,
|
||||
|
||||
/* Select the PHY to be used for packets. */
|
||||
LE_TEST_SETUP_SET_PHY = 0x02,
|
||||
|
||||
/* Select standard or stable modulation index. Stable modulation index
|
||||
* is not supported.
|
||||
*/
|
||||
LE_TEST_SETUP_SELECT_MODULATION = 0x03,
|
||||
|
||||
/* Read the supported test case features. */
|
||||
LE_TEST_SETUP_READ_SUPPORTED = 0x04,
|
||||
|
||||
/* Read the max supported time and length for packets. */
|
||||
LE_TEST_SETUP_READ_MAX = 0x05,
|
||||
|
||||
/* Set the Constant Tone Extension info. */
|
||||
LE_TEST_SETUP_CONSTANT_TONE_EXTENSION = 0x06,
|
||||
|
||||
/* Set the Constant Tone Extension slot. */
|
||||
LE_TEST_SETUP_CONSTANT_TONE_EXTENSION_SLOT = 0x07,
|
||||
|
||||
/* Set the Antenna number and switch pattern. */
|
||||
LE_TEST_SETUP_ANTENNA_ARRAY = 0x08,
|
||||
|
||||
/* Set the Transmit power. */
|
||||
LE_TEST_SETUP_TRANSMIT_POWER = 0x09
|
||||
};
|
||||
|
||||
/* DTM Test Setup PHY codes */
|
||||
enum dtm_phy_code {
|
||||
/* Set PHY for future packets to use 1MBit PHY.
|
||||
* Minimum parameter value.
|
||||
*/
|
||||
LE_PHY_1M_MIN_RANGE = 0x04,
|
||||
|
||||
/* Set PHY for future packets to use 1MBit PHY.
|
||||
* Maximum parameter value.
|
||||
*/
|
||||
LE_PHY_1M_MAX_RANGE = 0x07,
|
||||
|
||||
/* Set PHY for future packets to use 2MBit PHY.
|
||||
* Minimum parameter value.
|
||||
*/
|
||||
LE_PHY_2M_MIN_RANGE = 0x08,
|
||||
|
||||
/* Set PHY for future packets to use 2MBit PHY.
|
||||
* Maximum parameter value.
|
||||
*/
|
||||
LE_PHY_2M_MAX_RANGE = 0x0B,
|
||||
|
||||
/* Set PHY for future packets to use coded PHY with S=8.
|
||||
* Minimum parameter value.
|
||||
*/
|
||||
LE_PHY_LE_CODED_S8_MIN_RANGE = 0x0C,
|
||||
|
||||
/* Set PHY for future packets to use coded PHY with S=8.
|
||||
* Maximum parameter value.
|
||||
*/
|
||||
LE_PHY_LE_CODED_S8_MAX_RANGE = 0x0F,
|
||||
|
||||
/* Set PHY for future packets to use coded PHY with S=2.
|
||||
* Minimum parameter value.
|
||||
*/
|
||||
LE_PHY_LE_CODED_S2_MIN_RANGE = 0x10,
|
||||
|
||||
/* Set PHY for future packets to use coded PHY with S=2.
|
||||
* Maximum parameter value.
|
||||
*/
|
||||
LE_PHY_LE_CODED_S2_MAX_RANGE = 0x13
|
||||
};
|
||||
|
||||
/* DTM Test Setup Read supported parameters codes. */
|
||||
enum dtm_read_supported_code {
|
||||
/* Read maximum supported Tx Octets. Minimum parameter value. */
|
||||
LE_TEST_SUPPORTED_TX_OCTETS_MIN_RANGE = 0x00,
|
||||
|
||||
/* Read maximum supported Tx Octets. Maximum parameter value. */
|
||||
LE_TEST_SUPPORTED_TX_OCTETS_MAX_RANGE = 0x03,
|
||||
|
||||
/* Read maximum supported Tx Time. Minimum parameter value. */
|
||||
LE_TEST_SUPPORTED_TX_TIME_MIN_RANGE = 0x04,
|
||||
|
||||
/* Read maximum supported Tx Time. Maximum parameter value. */
|
||||
LE_TEST_SUPPORTED_TX_TIME_MAX_RANGE = 0x07,
|
||||
|
||||
/* Read maximum supported Rx Octets. Minimum parameter value. */
|
||||
LE_TEST_SUPPORTED_RX_OCTETS_MIN_RANGE = 0x08,
|
||||
|
||||
/* Read maximum supported Rx Octets. Maximum parameter value. */
|
||||
LE_TEST_SUPPORTED_RX_OCTETS_MAX_RANGE = 0x0B,
|
||||
|
||||
/* Read maximum supported Rx Time. Minimum parameter value. */
|
||||
LE_TEST_SUPPORTED_RX_TIME_MIN_RANGE = 0x0C,
|
||||
|
||||
/* Read maximum supported Rx Time. Maximum parameter value. */
|
||||
LE_TEST_SUPPORTED_RX_TIME_MAX_RANGE = 0x0F,
|
||||
|
||||
/* Read maximum length of the Constant Tone Extension supported. */
|
||||
LE_TEST_SUPPORTED_CTE_LENGTH = 0x10
|
||||
};
|
||||
|
||||
/* DTM Test Setup reset code. */
|
||||
enum dtm_reset_code {
|
||||
/* Reset. Minimum parameter value. */
|
||||
LE_RESET_MIN_RANGE = 0x00,
|
||||
|
||||
/* Reset. Maximum parameter value. */
|
||||
LE_RESET_MAX_RANGE = 0x03
|
||||
};
|
||||
|
||||
/* DTM Test Setup upper bits code. */
|
||||
enum dtm_set_upper_bits_code {
|
||||
/* Set upper bits. Minimum parameter value. */
|
||||
LE_SET_UPPER_BITS_MIN_RANGE = 0x00,
|
||||
|
||||
/* Set upper bits. Maximum parameter value. */
|
||||
LE_SET_UPPER_BITS_MAX_RANGE = 0x0F
|
||||
};
|
||||
|
||||
/* DTM Test Setup modulation code. */
|
||||
enum dtm_modulation_code {
|
||||
/* Set Modulation index to standard. Minimum parameter value. */
|
||||
LE_MODULATION_INDEX_STANDARD_MIN_RANGE = 0x00,
|
||||
|
||||
/* Set Modulation index to standard. Maximum parameter value. */
|
||||
LE_MODULATION_INDEX_STANDARD_MAX_RANGE = 0x03,
|
||||
|
||||
/* Set Modulation index to stable. Minimum parameter value. */
|
||||
LE_MODULATION_INDEX_STABLE_MIN_RANGE = 0x04,
|
||||
|
||||
/* Set Modulation index to stable. Maximum parameter value. */
|
||||
LE_MODULATION_INDEX_STABLE_MAX_RANGE = 0x07
|
||||
};
|
||||
|
||||
/* DTM Test Setup feature read code. */
|
||||
enum dtm_feature_read_code {
|
||||
/* Read test case supported feature. Minimum parameter value. */
|
||||
LE_TEST_FEATURE_READ_MIN_RANGE = 0x00,
|
||||
|
||||
/* Read test case supported feature. Maximum parameter value. */
|
||||
LE_TEST_FEATURE_READ_MAX_RANGE = 0x03
|
||||
};
|
||||
|
||||
/* DTM Test Setup transmit power code. */
|
||||
enum dtm_transmit_power_code {
|
||||
/* Minimum supported transmit power level. */
|
||||
LE_TRANSMIT_POWER_LVL_MIN = -127,
|
||||
|
||||
/* Maximum supported transmit power level. */
|
||||
LE_TRANSMIT_POWER_LVL_MAX = 20,
|
||||
|
||||
/* Set minimum transmit power level. */
|
||||
LE_TRANSMIT_POWER_LVL_SET_MIN = 0x7E,
|
||||
|
||||
/* Set maximum transmit power level. */
|
||||
LE_TRANSMIT_POWER_LVL_SET_MAX = 0x7F
|
||||
};
|
||||
|
||||
/* DTM Test Setup antenna number max values. */
|
||||
enum dtm_antenna_number {
|
||||
/* Minimum antenna number. */
|
||||
LE_TEST_ANTENNA_NUMBER_MIN = 0x01,
|
||||
|
||||
/* Maximum antenna number. */
|
||||
LE_TEST_ANTENNA_NUMBER_MAX = 0x4B
|
||||
};
|
||||
|
||||
enum dtm_antenna_pattern {
|
||||
/* Constant Tone Extension: Antenna switch pattern 1, 2, 3 ...N. */
|
||||
DTM_ANTENNA_PATTERN_123N123N = 0x00,
|
||||
|
||||
/* Constant Tone Extension: Antenna switch pattern
|
||||
* 1, 2, 3 ...N, N - 1, N - 2, ..., 1, ...
|
||||
*/
|
||||
DTM_ANTENNA_PATTERN_123N2123 = 0x01
|
||||
};
|
||||
|
||||
/* DTM Test Setup CTE type code */
|
||||
enum dtm_cte_type_code {
|
||||
/* CTE Type Angle of Arrival. */
|
||||
LE_CTE_TYPE_AOA = 0x00,
|
||||
|
||||
/* CTE Type Angle of Departure with 1 us slot. */
|
||||
LE_CTE_TYPE_AOD_1US = 0x01,
|
||||
|
||||
/* CTE Type Angle of Departure with 2 us slot.*/
|
||||
LE_CTE_TYPE_AOD_2US = 0x02
|
||||
};
|
||||
|
||||
enum dtm_cte_slot_code {
|
||||
/* CTE 1 us slot duration. */
|
||||
LE_CTE_SLOT_1US = 0x01,
|
||||
|
||||
/* CTE 2 us slot duration. */
|
||||
LE_CTE_SLOT_2US = 0x02
|
||||
};
|
||||
|
||||
/* DTM Packet Type field */
|
||||
enum dtm_pkt_type {
|
||||
/* PRBS9 bit pattern */
|
||||
DTM_PKT_PRBS9 = 0x00,
|
||||
|
||||
/* 11110000 bit pattern (LSB is the leftmost bit). */
|
||||
DTM_PKT_0X0F = 0x01,
|
||||
|
||||
/* 10101010 bit pattern (LSB is the leftmost bit). */
|
||||
DTM_PKT_0X55 = 0x02,
|
||||
|
||||
/* 11111111 bit pattern for Coded PHY.
|
||||
* Vendor specific command for Non-Coded PHY.
|
||||
*/
|
||||
DTM_PKT_0XFF_OR_VS = 0x03,
|
||||
};
|
||||
|
||||
/* DTM Test End control code. */
|
||||
enum dtm_test_end_code {
|
||||
/* Test End. Minimum parameter value. */
|
||||
LE_TEST_END_MIN_RANGE = 0x00,
|
||||
|
||||
/* Test End. Maximum parameter value. */
|
||||
LE_TEST_END_MAX_RANGE = 0x03
|
||||
};
|
||||
|
||||
/* DTM events */
|
||||
enum dtm_evt {
|
||||
/* Status event, indicating success. */
|
||||
LE_TEST_STATUS_EVENT_SUCCESS = 0x0000,
|
||||
|
||||
/* Status event, indicating an error. */
|
||||
LE_TEST_STATUS_EVENT_ERROR = 0x0001,
|
||||
|
||||
/* Packet reporting event, returned by the device to the tester. */
|
||||
LE_PACKET_REPORTING_EVENT = 0x8000,
|
||||
};
|
||||
|
||||
/** Upper bits of packet length */
|
||||
static uint8_t upper_len;
|
||||
|
||||
static int reset_dtm(uint8_t parameter)
|
||||
{
|
||||
if (parameter > LE_RESET_MAX_RANGE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
upper_len = 0;
|
||||
return dtm_setup_reset();
|
||||
}
|
||||
|
||||
static int upper_set(uint8_t parameter)
|
||||
{
|
||||
if (parameter > LE_SET_UPPER_BITS_MAX_RANGE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
upper_len = (parameter << LE_UPPER_BITS_POS) & LE_UPPER_BITS_MASK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int phy_set(uint8_t parameter)
|
||||
{
|
||||
switch (parameter) {
|
||||
case LE_PHY_1M_MIN_RANGE ... LE_PHY_1M_MAX_RANGE:
|
||||
return dtm_setup_set_phy(DTM_PHY_1M);
|
||||
|
||||
case LE_PHY_2M_MIN_RANGE ... LE_PHY_2M_MAX_RANGE:
|
||||
return dtm_setup_set_phy(DTM_PHY_2M);
|
||||
|
||||
case LE_PHY_LE_CODED_S8_MIN_RANGE ... LE_PHY_LE_CODED_S8_MAX_RANGE:
|
||||
return dtm_setup_set_phy(DTM_PHY_CODED_S8);
|
||||
|
||||
case LE_PHY_LE_CODED_S2_MIN_RANGE ... LE_PHY_LE_CODED_S2_MAX_RANGE:
|
||||
return dtm_setup_set_phy(DTM_PHY_CODED_S2);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int mod_set(uint8_t parameter)
|
||||
{
|
||||
switch (parameter) {
|
||||
case LE_MODULATION_INDEX_STANDARD_MIN_RANGE ... LE_MODULATION_INDEX_STANDARD_MAX_RANGE:
|
||||
return dtm_setup_set_modulation(DTM_MODULATION_STANDARD);
|
||||
|
||||
case LE_MODULATION_INDEX_STABLE_MIN_RANGE ... LE_MODULATION_INDEX_STABLE_MAX_RANGE:
|
||||
return dtm_setup_set_modulation(DTM_MODULATION_STABLE);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int features_read(uint8_t parameter, uint16_t *ret)
|
||||
{
|
||||
struct dtm_supp_features features;
|
||||
|
||||
if (parameter > LE_TEST_FEATURE_READ_MAX_RANGE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
features = dtm_setup_read_features();
|
||||
|
||||
*ret = 0;
|
||||
*ret |= (features.data_len_ext ? LE_TEST_SETUP_DLE_SUPPORTED : 0);
|
||||
*ret |= (features.phy_2m ? LE_TEST_SETUP_2M_PHY_SUPPORTED : 0);
|
||||
*ret |= (features.stable_mod ? LE_TEST_STABLE_MODULATION_SUPPORTED : 0);
|
||||
*ret |= (features.coded_phy ? LE_TEST_CODED_PHY_SUPPORTED : 0);
|
||||
*ret |= (features.cte ? LE_TEST_CTE_SUPPORTED : 0);
|
||||
*ret |= (features.ant_switching ? DTM_LE_ANTENNA_SWITCH : 0);
|
||||
*ret |= (features.aod_1us_tx ? DTM_LE_AOD_1US_TANSMISSION : 0);
|
||||
*ret |= (features.aod_1us_rx ? DTM_LE_AOD_1US_RECEPTION : 0);
|
||||
*ret |= (features.aoa_1us_rx ? DTM_LE_AOA_1US_RECEPTION : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_max(uint8_t parameter, uint16_t *ret)
|
||||
{
|
||||
int err;
|
||||
|
||||
switch (parameter) {
|
||||
case LE_TEST_SUPPORTED_TX_OCTETS_MIN_RANGE ... LE_TEST_SUPPORTED_TX_OCTETS_MAX_RANGE:
|
||||
err = dtm_setup_read_max_supported_value(DTM_MAX_SUPPORTED_TX_OCTETS, ret);
|
||||
break;
|
||||
|
||||
case LE_TEST_SUPPORTED_TX_TIME_MIN_RANGE ... LE_TEST_SUPPORTED_TX_TIME_MAX_RANGE:
|
||||
err = dtm_setup_read_max_supported_value(DTM_MAX_SUPPORTED_TX_TIME, ret);
|
||||
break;
|
||||
|
||||
case LE_TEST_SUPPORTED_RX_OCTETS_MIN_RANGE ... LE_TEST_SUPPORTED_RX_OCTETS_MAX_RANGE:
|
||||
err = dtm_setup_read_max_supported_value(DTM_MAX_SUPPORTED_RX_OCTETS, ret);
|
||||
break;
|
||||
|
||||
case LE_TEST_SUPPORTED_RX_TIME_MIN_RANGE ... LE_TEST_SUPPORTED_RX_TIME_MAX_RANGE:
|
||||
err = dtm_setup_read_max_supported_value(DTM_MAX_SUPPORTED_RX_TIME, ret);
|
||||
break;
|
||||
|
||||
case LE_TEST_SUPPORTED_CTE_LENGTH:
|
||||
err = dtm_setup_read_max_supported_value(DTM_MAX_SUPPORTED_CTE_LENGTH, ret);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*ret = *ret << DTM_RESPONSE_EVENT_SHIFT;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int cte_set(uint8_t parameter)
|
||||
{
|
||||
enum dtm_cte_type_code type = (parameter & LE_CTE_TYPE_MASK) >> LE_CTE_TYPE_POS;
|
||||
uint8_t time = parameter & LE_CTE_CTETIME_MASK;
|
||||
|
||||
if (!parameter) {
|
||||
return dtm_setup_set_cte_mode(DTM_CTE_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case LE_CTE_TYPE_AOA:
|
||||
return dtm_setup_set_cte_mode(DTM_CTE_TYPE_AOA, time);
|
||||
|
||||
case LE_CTE_TYPE_AOD_1US:
|
||||
return dtm_setup_set_cte_mode(DTM_CTE_TYPE_AOD_1US, time);
|
||||
|
||||
case LE_CTE_TYPE_AOD_2US:
|
||||
return dtm_setup_set_cte_mode(DTM_CTE_TYPE_AOD_2US, time);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int cte_slot_set(uint8_t parameter)
|
||||
{
|
||||
enum dtm_cte_type_code type = (parameter & LE_CTE_TYPE_MASK) >> LE_CTE_TYPE_POS;
|
||||
|
||||
switch (type) {
|
||||
case LE_CTE_SLOT_1US:
|
||||
return dtm_setup_set_cte_slot(DTM_CTE_SLOT_DURATION_1US);
|
||||
|
||||
case LE_CTE_SLOT_2US:
|
||||
return dtm_setup_set_cte_slot(DTM_CTE_SLOT_DURATION_2US);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int antenna_set(uint8_t parameter)
|
||||
{
|
||||
static uint8_t pattern[LE_TEST_ANTENNA_NUMBER_MAX * 2];
|
||||
enum dtm_antenna_pattern type =
|
||||
(parameter & LE_ANTENNA_SWITCH_PATTERN_MASK) >> LE_ANTENNA_SWITCH_PATTERN_POS;
|
||||
uint8_t ant_count = (parameter & LE_ANTENNA_NUMBER_MASK);
|
||||
uint8_t length;
|
||||
size_t i;
|
||||
|
||||
if ((ant_count < LE_TEST_ANTENNA_NUMBER_MIN) || (ant_count > LE_TEST_ANTENNA_NUMBER_MAX)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
length = ant_count;
|
||||
|
||||
switch (type) {
|
||||
case DTM_ANTENNA_PATTERN_123N123N:
|
||||
for (i = 1; i <= length; i++) {
|
||||
pattern[i - 1] = i;
|
||||
}
|
||||
break;
|
||||
|
||||
case DTM_ANTENNA_PATTERN_123N2123:
|
||||
for (i = 1; i <= length; i++) {
|
||||
pattern[i - 1] = i;
|
||||
}
|
||||
for (i = 1; i < length; i++) {
|
||||
pattern[i + length - 1] = length - i;
|
||||
}
|
||||
|
||||
length = (length * 2) - 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return dtm_setup_set_antenna_params(ant_count, pattern, length);
|
||||
}
|
||||
|
||||
static int tx_power_set(int8_t parameter, uint16_t *ret)
|
||||
{
|
||||
struct dtm_tx_power power;
|
||||
|
||||
switch (parameter) {
|
||||
case LE_TRANSMIT_POWER_LVL_SET_MIN:
|
||||
power = dtm_setup_set_transmit_power(DTM_TX_POWER_REQUEST_MIN, 0, 0);
|
||||
break;
|
||||
|
||||
case LE_TRANSMIT_POWER_LVL_SET_MAX:
|
||||
power = dtm_setup_set_transmit_power(DTM_TX_POWER_REQUEST_MAX, 0, 0);
|
||||
break;
|
||||
|
||||
case LE_TRANSMIT_POWER_LVL_MIN ... LE_TRANSMIT_POWER_LVL_MAX:
|
||||
power = dtm_setup_set_transmit_power(DTM_TX_POWER_REQUEST_VAL, parameter, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*ret = (power.power << LE_TRANSMIT_POWER_RESPONSE_LVL_POS) &
|
||||
LE_TRANSMIT_POWER_RESPONSE_LVL_MASK;
|
||||
if (power.max) {
|
||||
*ret |= LE_TRANSMIT_POWER_MAX_LVL_BIT;
|
||||
}
|
||||
if (power.min) {
|
||||
*ret |= LE_TRANSMIT_POWER_MIN_LVL_BIT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint16_t on_test_setup_cmd(enum dtm_ctrl_code control, uint8_t parameter)
|
||||
{
|
||||
uint16_t ret = 0;
|
||||
int err;
|
||||
|
||||
dtm_setup_prepare();
|
||||
|
||||
switch (control) {
|
||||
case LE_TEST_SETUP_RESET:
|
||||
err = reset_dtm(parameter);
|
||||
break;
|
||||
|
||||
case LE_TEST_SETUP_SET_UPPER:
|
||||
err = upper_set(parameter);
|
||||
break;
|
||||
|
||||
case LE_TEST_SETUP_SET_PHY:
|
||||
err = phy_set(parameter);
|
||||
break;
|
||||
|
||||
case LE_TEST_SETUP_SELECT_MODULATION:
|
||||
err = mod_set(parameter);
|
||||
break;
|
||||
|
||||
case LE_TEST_SETUP_READ_SUPPORTED:
|
||||
err = features_read(parameter, &ret);
|
||||
break;
|
||||
|
||||
case LE_TEST_SETUP_READ_MAX:
|
||||
err = read_max(parameter, &ret);
|
||||
break;
|
||||
|
||||
case LE_TEST_SETUP_CONSTANT_TONE_EXTENSION:
|
||||
err = cte_set(parameter);
|
||||
break;
|
||||
|
||||
case LE_TEST_SETUP_CONSTANT_TONE_EXTENSION_SLOT:
|
||||
err = cte_slot_set(parameter);
|
||||
break;
|
||||
|
||||
case LE_TEST_SETUP_ANTENNA_ARRAY:
|
||||
err = antenna_set(parameter);
|
||||
break;
|
||||
|
||||
case LE_TEST_SETUP_TRANSMIT_POWER:
|
||||
err = tx_power_set(parameter, &ret);
|
||||
break;
|
||||
|
||||
default:
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return (err ? LE_TEST_STATUS_EVENT_ERROR : (LE_TEST_STATUS_EVENT_SUCCESS | ret));
|
||||
}
|
||||
|
||||
static uint16_t on_test_end_cmd(enum dtm_ctrl_code control, uint8_t parameter)
|
||||
{
|
||||
uint16_t cnt;
|
||||
int err;
|
||||
|
||||
if (control) {
|
||||
return LE_TEST_STATUS_EVENT_ERROR;
|
||||
}
|
||||
|
||||
if (parameter > LE_TEST_END_MAX_RANGE) {
|
||||
return LE_TEST_STATUS_EVENT_ERROR;
|
||||
}
|
||||
|
||||
err = dtm_test_end(&cnt);
|
||||
|
||||
return err ? LE_TEST_STATUS_EVENT_ERROR : (LE_PACKET_REPORTING_EVENT | cnt);
|
||||
}
|
||||
|
||||
static uint16_t on_test_rx_cmd(uint8_t chan)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dtm_test_receive(chan);
|
||||
|
||||
return err ? LE_TEST_STATUS_EVENT_ERROR : LE_TEST_STATUS_EVENT_SUCCESS;
|
||||
}
|
||||
|
||||
static uint16_t on_test_tx_cmd(uint8_t chan, uint8_t length, enum dtm_pkt_type type)
|
||||
{
|
||||
enum dtm_packet pkt;
|
||||
int err;
|
||||
|
||||
switch (type) {
|
||||
case DTM_PKT_PRBS9:
|
||||
pkt = DTM_PACKET_PRBS9;
|
||||
break;
|
||||
|
||||
case DTM_PKT_0X0F:
|
||||
pkt = DTM_PACKET_0F;
|
||||
break;
|
||||
|
||||
case DTM_PKT_0X55:
|
||||
pkt = DTM_PACKET_55;
|
||||
break;
|
||||
|
||||
case DTM_PKT_0XFF_OR_VS:
|
||||
pkt = DTM_PACKET_FF_OR_VENDOR;
|
||||
break;
|
||||
|
||||
default:
|
||||
return LE_TEST_STATUS_EVENT_ERROR;
|
||||
}
|
||||
|
||||
length = (length & ~LE_UPPER_BITS_MASK) | upper_len;
|
||||
|
||||
err = dtm_test_transmit(chan, length, pkt);
|
||||
|
||||
return err ? LE_TEST_STATUS_EVENT_ERROR : LE_TEST_STATUS_EVENT_SUCCESS;
|
||||
}
|
||||
|
||||
static uint16_t dtm_cmd_put(uint16_t cmd)
|
||||
{
|
||||
enum dtm_cmd_code cmd_code = (cmd >> 14) & 0x03;
|
||||
|
||||
/* RX and TX test commands */
|
||||
uint8_t chan = (cmd >> 8) & 0x3F;
|
||||
uint8_t length = (cmd >> 2) & 0x3F;
|
||||
enum dtm_pkt_type type = (enum dtm_pkt_type)(cmd & 0x03);
|
||||
|
||||
/* Setup and End commands */
|
||||
enum dtm_ctrl_code control = (cmd >> 8) & 0x3F;
|
||||
uint8_t parameter = (uint8_t)cmd;
|
||||
|
||||
switch (cmd_code) {
|
||||
case LE_TEST_SETUP:
|
||||
LOG_DBG("Executing test setup command. Control: %d Parameter: %d", control,
|
||||
parameter);
|
||||
return on_test_setup_cmd(control, parameter);
|
||||
|
||||
case LE_TEST_END:
|
||||
LOG_DBG("Executing test end command. Control: %d Parameter: %d", control,
|
||||
parameter);
|
||||
return on_test_end_cmd(control, parameter);
|
||||
|
||||
case LE_RECEIVER_TEST:
|
||||
LOG_DBG("Executing reception test command. Channel: %d", chan);
|
||||
return on_test_rx_cmd(chan);
|
||||
|
||||
case LE_TRANSMITTER_TEST:
|
||||
LOG_DBG("Executing transmission test command. Channel: %d Length: %d Type: %d",
|
||||
chan, length, type);
|
||||
return on_test_tx_cmd(chan, length, type);
|
||||
|
||||
default:
|
||||
LOG_ERR("Received unknown command code %d", cmd_code);
|
||||
return LE_TEST_STATUS_EVENT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
int dtm_tr_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!device_is_ready(dtm_uart)) {
|
||||
LOG_ERR("UART device not ready");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
err = dtm_init(NULL);
|
||||
if (err) {
|
||||
LOG_ERR("Error during DTM initialization: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = dtm_uart_wait_init();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
union dtm_tr_packet dtm_tr_get(void)
|
||||
{
|
||||
bool is_msb_read = false;
|
||||
union dtm_tr_packet tmp;
|
||||
uint8_t rx_byte;
|
||||
uint16_t dtm_cmd = 0;
|
||||
int64_t msb_time = 0;
|
||||
int err;
|
||||
|
||||
for (;;) {
|
||||
dtm_uart_wait();
|
||||
|
||||
err = uart_poll_in(dtm_uart, &rx_byte);
|
||||
if (err) {
|
||||
if (err != -1) {
|
||||
LOG_ERR("UART polling error: %d", err);
|
||||
}
|
||||
|
||||
/* Nothing read from the UART */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_msb_read) {
|
||||
/* This is first byte of two-byte command. */
|
||||
is_msb_read = true;
|
||||
dtm_cmd = rx_byte << 8;
|
||||
msb_time = k_uptime_get();
|
||||
|
||||
/* Go back and wait for 2nd byte of command word. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This is the second byte read; combine it with the first and
|
||||
* process command.
|
||||
*/
|
||||
if ((k_uptime_get() - msb_time) >
|
||||
DTM_UART_SECOND_BYTE_MAX_DELAY) {
|
||||
/* More than ~5mS after msb: Drop old byte, take the
|
||||
* new byte as MSB. The variable is_msb_read will
|
||||
* remain true.
|
||||
*/
|
||||
dtm_cmd = rx_byte << 8;
|
||||
msb_time = k_uptime_get();
|
||||
/* Go back and wait for 2nd byte of command word. */
|
||||
LOG_DBG("Received byte discarded");
|
||||
continue;
|
||||
} else {
|
||||
dtm_cmd |= rx_byte;
|
||||
LOG_INF("Received 0x%04x command", dtm_cmd);
|
||||
tmp.twowire = dtm_cmd;
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int dtm_tr_process(union dtm_tr_packet cmd)
|
||||
{
|
||||
uint16_t tmp = cmd.twowire;
|
||||
uint16_t ret;
|
||||
|
||||
LOG_INF("Processing 0x%04x command", tmp);
|
||||
|
||||
ret = dtm_cmd_put(tmp);
|
||||
LOG_INF("Sending 0x%04x response", ret);
|
||||
|
||||
uart_poll_out(dtm_uart, (ret >> 8) & 0xFF);
|
||||
uart_poll_out(dtm_uart, ret & 0xFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
100
nordic/trezor/direct_test_mode/src/transport/dtm_uart_wait.c
Normal file
100
nordic/trezor/direct_test_mode/src/transport/dtm_uart_wait.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/drivers/uart.h>
|
||||
#include <nrfx_timer.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include "dtm_uart_wait.h"
|
||||
|
||||
LOG_MODULE_REGISTER(dtm_wait, CONFIG_DTM_TRANSPORT_LOG_LEVEL);
|
||||
|
||||
/* Timer used for measuring UART poll cycle wait time. */
|
||||
#if defined(CONFIG_SOC_SERIES_NRF54HX)
|
||||
#define WAIT_TIMER_INSTANCE 021
|
||||
#elif defined(CONFIG_SOC_SERIES_NRF54LX)
|
||||
#define WAIT_TIMER_INSTANCE 20
|
||||
#else
|
||||
#define WAIT_TIMER_INSTANCE 1
|
||||
#endif /* defined(CONFIG_SOC_SERIES_NRF54HX) */
|
||||
|
||||
#define WAIT_TIMER_IRQ NRFX_CONCAT_3(TIMER, \
|
||||
WAIT_TIMER_INSTANCE, \
|
||||
_IRQn)
|
||||
#define WAIT_TIMER_IRQ_HANDLER NRFX_CONCAT_3(nrfx_timer_, \
|
||||
WAIT_TIMER_INSTANCE, \
|
||||
_irq_handler)
|
||||
|
||||
BUILD_ASSERT(NRFX_CONCAT_3(CONFIG_, NRFX_TIMER, WAIT_TIMER_INSTANCE) == 1,
|
||||
"Wait DTM timer needs additional KConfig configuration");
|
||||
|
||||
#if DT_NODE_HAS_PROP(DTM_UART, current_speed)
|
||||
/* UART Baudrate used to communicate with the DTM library. */
|
||||
#define DTM_UART_BAUDRATE DT_PROP(DTM_UART, current_speed)
|
||||
|
||||
/* The UART poll cycle in micro seconds.
|
||||
* A baud rate of e.g. 19200 bits / second, and 8 data bits, 1 start/stop bit,
|
||||
* no flow control, give the time to transmit a byte:
|
||||
* 10 bits * 1/19200 = approx: 520 us. To ensure no loss of bytes,
|
||||
* the UART should be polled every 260 us.
|
||||
*/
|
||||
#define DTM_UART_POLL_CYCLE ((uint32_t) (10 * 1e6 / DTM_UART_BAUDRATE / 2))
|
||||
#else
|
||||
#error "DTM UART node not found"
|
||||
#endif /* DT_NODE_HAS_PROP(DTM_UART, currrent_speed) */
|
||||
|
||||
/* Timer to be used for measuring UART poll cycle wait time. */
|
||||
static const nrfx_timer_t wait_timer = NRFX_TIMER_INSTANCE(WAIT_TIMER_INSTANCE);
|
||||
|
||||
/* Semaphore for synchronizing UART poll cycle wait time.*/
|
||||
static K_SEM_DEFINE(wait_sem, 0, 1);
|
||||
|
||||
static void wait_timer_handler(nrf_timer_event_t event_type, void *context)
|
||||
{
|
||||
nrfx_timer_disable(&wait_timer);
|
||||
nrfx_timer_clear(&wait_timer);
|
||||
|
||||
k_sem_give(&wait_sem);
|
||||
}
|
||||
|
||||
int dtm_uart_wait_init(void)
|
||||
{
|
||||
nrfx_err_t err;
|
||||
nrfx_timer_config_t timer_cfg = {
|
||||
.frequency = NRFX_MHZ_TO_HZ(1),
|
||||
.mode = NRF_TIMER_MODE_TIMER,
|
||||
.bit_width = NRF_TIMER_BIT_WIDTH_16,
|
||||
};
|
||||
|
||||
err = nrfx_timer_init(&wait_timer, &timer_cfg, wait_timer_handler);
|
||||
if (err != NRFX_SUCCESS) {
|
||||
LOG_ERR("nrfx_timer_init failed with: %d", err);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
IRQ_CONNECT(WAIT_TIMER_IRQ, CONFIG_DTM_TIMER_IRQ_PRIORITY,
|
||||
WAIT_TIMER_IRQ_HANDLER, NULL, 0);
|
||||
|
||||
nrfx_timer_compare(&wait_timer,
|
||||
NRF_TIMER_CC_CHANNEL0,
|
||||
nrfx_timer_us_to_ticks(&wait_timer, DTM_UART_POLL_CYCLE),
|
||||
true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dtm_uart_wait(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
nrfx_timer_enable(&wait_timer);
|
||||
|
||||
err = k_sem_take(&wait_sem, K_FOREVER);
|
||||
if (err) {
|
||||
LOG_ERR("UART wait error: %d", err);
|
||||
}
|
||||
}
|
||||
32
nordic/trezor/direct_test_mode/src/transport/dtm_uart_wait.h
Normal file
32
nordic/trezor/direct_test_mode/src/transport/dtm_uart_wait.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#ifndef DTM_UART_WAIT_H_
|
||||
#define DTM_UART_WAIT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DTM_UART DT_CHOSEN(ncs_dtm_uart)
|
||||
|
||||
/** @brief Initialize wait function.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int dtm_uart_wait_init(void);
|
||||
|
||||
/** @brief Wait for UART poll cycle.
|
||||
*
|
||||
* Wait for half of the UART period used by the DTM.
|
||||
*/
|
||||
void dtm_uart_wait(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DTM_UART_WAIT_H_ */
|
||||
309
nordic/trezor/direct_test_mode/src/transport/hci_uart.c
Normal file
309
nordic/trezor/direct_test_mode/src/transport/hci_uart.c
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/drivers/uart.h>
|
||||
#include <zephyr/net_buf.h>
|
||||
#include <zephyr/bluetooth/hci_types.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
|
||||
#include "dtm_transport.h"
|
||||
#include "hci_uart.h"
|
||||
|
||||
#ifndef CONFIG_DTM_TRANSPORT_LOG_LEVEL
|
||||
#define CONFIG_DTM_TRANSPORT_LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DTM_TRANSPORT_HCI
|
||||
#define QUEUE_COUNT CONFIG_DTM_HCI_QUEUE_COUNT
|
||||
#define QUEUE_SIZE CONFIG_DTM_HCI_QUEUE_SIZE
|
||||
#define TX_THREAD_STACK_SIZE CONFIG_DTM_HCI_TX_THREAD_STACK_SIZE
|
||||
#define TX_THREAD_PRIORITY CONFIG_DTM_HCI_TX_THREAD_PRIORITY
|
||||
#else
|
||||
#define QUEUE_COUNT CONFIG_REMOTE_HCI_QUEUE_COUNT
|
||||
#define QUEUE_SIZE CONFIG_REMOTE_HCI_QUEUE_SIZE
|
||||
#define TX_THREAD_STACK_SIZE CONFIG_REMOTE_HCI_TX_THREAD_STACK_SIZE
|
||||
#define TX_THREAD_PRIORITY CONFIG_REMOTE_HCI_TX_THREAD_PRIORITY
|
||||
#endif
|
||||
|
||||
#define UART_DMA_BUF_SIZE 128
|
||||
#define UART_TIMEOUT_US 10000
|
||||
|
||||
LOG_MODULE_REGISTER(dtm_hci_uart, CONFIG_DTM_TRANSPORT_LOG_LEVEL);
|
||||
|
||||
#define DTM_UART DT_CHOSEN(ncs_dtm_uart)
|
||||
static const struct device *hci_uart_dev = DEVICE_DT_GET(DTM_UART);
|
||||
|
||||
NET_BUF_POOL_DEFINE(hci_tx_buf, QUEUE_COUNT, QUEUE_SIZE, 0, NULL);
|
||||
static K_FIFO_DEFINE(hci_tx_queue);
|
||||
|
||||
NET_BUF_POOL_DEFINE(hci_rx_buf, QUEUE_COUNT, QUEUE_SIZE, sizeof(uint8_t), NULL);
|
||||
|
||||
enum h4_state {
|
||||
S_TYPE,
|
||||
S_HEADER,
|
||||
S_PAYLOAD
|
||||
};
|
||||
|
||||
static hci_uart_read_cb dtm_hci_put;
|
||||
|
||||
static size_t hci_hdr_len(uint8_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case H4_TYPE_CMD:
|
||||
return sizeof(struct bt_hci_cmd_hdr);
|
||||
|
||||
case H4_TYPE_ACL:
|
||||
return sizeof(struct bt_hci_acl_hdr);
|
||||
|
||||
case H4_TYPE_EVT:
|
||||
return sizeof(struct bt_hci_evt_hdr);
|
||||
|
||||
case H4_TYPE_ISO:
|
||||
return sizeof(struct bt_hci_iso_hdr);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t hci_pld_len(uint8_t type, uint8_t *hdr)
|
||||
{
|
||||
switch (type) {
|
||||
case H4_TYPE_CMD:
|
||||
return ((struct bt_hci_cmd_hdr *)hdr)->param_len;
|
||||
|
||||
case H4_TYPE_ACL:
|
||||
return sys_le16_to_cpu(((struct bt_hci_acl_hdr *)hdr)->len);
|
||||
|
||||
case H4_TYPE_ISO:
|
||||
return sys_le16_to_cpu(((struct bt_hci_iso_hdr *)hdr)->len);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool h4_rx_type(uint8_t type)
|
||||
{
|
||||
return ((type == H4_TYPE_CMD) | (type == H4_TYPE_ACL) | (type == H4_TYPE_ISO));
|
||||
}
|
||||
|
||||
static size_t buf_read(struct net_buf *buf, const uint8_t *src, size_t src_len, size_t req_len)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if (req_len > src_len) {
|
||||
len = src_len;
|
||||
} else {
|
||||
len = req_len;
|
||||
}
|
||||
|
||||
if (net_buf_tailroom(buf) < len) {
|
||||
__ASSERT_NO_MSG(false);
|
||||
}
|
||||
net_buf_add_mem(buf, src, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void h4_read(const uint8_t *data, size_t offset, size_t len)
|
||||
{
|
||||
static enum h4_state state = S_TYPE;
|
||||
static struct net_buf *buf;
|
||||
static uint8_t type;
|
||||
static size_t rem;
|
||||
size_t read;
|
||||
|
||||
while (len > 0) {
|
||||
switch (state) {
|
||||
case S_TYPE:
|
||||
type = data[offset];
|
||||
offset += sizeof(type);
|
||||
len -= sizeof(type);
|
||||
|
||||
if (h4_rx_type(type)) {
|
||||
rem = hci_hdr_len(type);
|
||||
buf = net_buf_alloc(&hci_rx_buf, K_NO_WAIT);
|
||||
if (!buf) {
|
||||
__ASSERT_NO_MSG(false);
|
||||
/* Out of buffers condition */
|
||||
}
|
||||
|
||||
*(uint8_t *)net_buf_user_data(buf) = type;
|
||||
state = S_HEADER;
|
||||
} else {
|
||||
/* TODO: Sync failure */
|
||||
}
|
||||
break;
|
||||
|
||||
case S_HEADER:
|
||||
read = buf_read(buf, &data[offset], len, rem);
|
||||
offset += read;
|
||||
len -= read;
|
||||
rem -= read;
|
||||
if (rem == 0) {
|
||||
rem = hci_pld_len(type, buf->data);
|
||||
state = S_PAYLOAD;
|
||||
if (rem == 0) {
|
||||
if (dtm_hci_put) {
|
||||
dtm_hci_put(buf);
|
||||
} else {
|
||||
LOG_ERR("Callback dtm_hci_put is not assigned.");
|
||||
}
|
||||
state = S_TYPE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case S_PAYLOAD:
|
||||
read = buf_read(buf, &data[offset], len, rem);
|
||||
offset += read;
|
||||
len -= read;
|
||||
rem -= read;
|
||||
if (rem == 0) {
|
||||
if (dtm_hci_put) {
|
||||
dtm_hci_put(buf);
|
||||
} else {
|
||||
LOG_ERR("Callback dtm_hci_put is not assigned.");
|
||||
}
|
||||
state = S_TYPE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
state = S_TYPE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t *uart_buf(void)
|
||||
{
|
||||
static uint32_t cur;
|
||||
static uint8_t buf1[UART_DMA_BUF_SIZE];
|
||||
static uint8_t buf2[UART_DMA_BUF_SIZE];
|
||||
|
||||
cur = (cur + 1) % 2;
|
||||
|
||||
if (cur == 0) {
|
||||
return buf1;
|
||||
} else {
|
||||
return buf2;
|
||||
}
|
||||
}
|
||||
|
||||
static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
|
||||
switch (evt->type) {
|
||||
case UART_TX_DONE:
|
||||
LOG_DBG("Uart TX done");
|
||||
/* The pointer to net_buf is the first datum before the uart TX pointer */
|
||||
buf = *(struct net_buf **)(evt->data.tx.buf - sizeof(buf));
|
||||
net_buf_unref(buf);
|
||||
break;
|
||||
|
||||
case UART_TX_ABORTED:
|
||||
LOG_DBG("Uart TX aborted");
|
||||
/* The pointer to net_buf is the first datum before the uart TX pointer */
|
||||
buf = *(struct net_buf **)(evt->data.tx.buf - sizeof(buf));
|
||||
net_buf_unref(buf);
|
||||
break;
|
||||
|
||||
case UART_RX_RDY:
|
||||
LOG_DBG("Uart RX ready");
|
||||
h4_read(evt->data.rx.buf, evt->data.rx.offset, evt->data.rx.len);
|
||||
break;
|
||||
|
||||
case UART_RX_BUF_REQUEST:
|
||||
LOG_DBG("Uart rx buf request");
|
||||
uart_rx_buf_rsp(dev, uart_buf(), UART_DMA_BUF_SIZE);
|
||||
break;
|
||||
|
||||
case UART_RX_BUF_RELEASED:
|
||||
LOG_DBG("Uart rx buf released");
|
||||
break;
|
||||
|
||||
case UART_RX_DISABLED:
|
||||
LOG_DBG("Uart rx disabled");
|
||||
break;
|
||||
|
||||
case UART_RX_STOPPED:
|
||||
LOG_DBG("Uart rx stopped");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void tx_thread(void)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
|
||||
for (;;) {
|
||||
/* The first pointer is discarded as it serves internal purpose
|
||||
* and it's not supposed to be sent over uart.
|
||||
* The pointer is an address to the associated net_buf.
|
||||
*/
|
||||
buf = k_fifo_get(&hci_tx_queue, K_FOREVER);
|
||||
uart_tx(hci_uart_dev, &buf->data[sizeof(buf)],
|
||||
buf->len - sizeof(buf), SYS_FOREVER_US);
|
||||
}
|
||||
}
|
||||
K_THREAD_DEFINE(tx_thread_id, TX_THREAD_STACK_SIZE, tx_thread,
|
||||
NULL, NULL, NULL,
|
||||
TX_THREAD_PRIORITY, 0, 0);
|
||||
|
||||
int hci_uart_init(hci_uart_read_cb cb)
|
||||
{
|
||||
int err;
|
||||
|
||||
dtm_hci_put = cb;
|
||||
|
||||
if (!device_is_ready(hci_uart_dev)) {
|
||||
LOG_ERR("UART device not ready");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
err = uart_callback_set(hci_uart_dev, uart_cb, NULL);
|
||||
if (err) {
|
||||
LOG_ERR("UART callback not set %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = uart_rx_enable(hci_uart_dev, uart_buf(), UART_DMA_BUF_SIZE, UART_TIMEOUT_US);
|
||||
if (err) {
|
||||
LOG_ERR("UART rx not enabled %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hci_uart_write(uint8_t type, const uint8_t *hdr, size_t hdr_len, const uint8_t *pld, size_t len)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
|
||||
buf = net_buf_alloc(&hci_tx_buf, K_NO_WAIT);
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (net_buf_tailroom(buf) < (len + hdr_len + sizeof(type) + sizeof(buf))) {
|
||||
net_buf_unref(buf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Pointer to net_buf is saved in order to unref it in uart callback. */
|
||||
net_buf_add_mem(buf, (uint8_t *)&buf, sizeof(buf));
|
||||
net_buf_add_u8(buf, type);
|
||||
net_buf_add_mem(buf, hdr, hdr_len);
|
||||
net_buf_add_mem(buf, pld, len);
|
||||
|
||||
k_fifo_put(&hci_tx_queue, buf);
|
||||
return 0;
|
||||
}
|
||||
54
nordic/trezor/direct_test_mode/src/transport/hci_uart.h
Normal file
54
nordic/trezor/direct_test_mode/src/transport/hci_uart.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#ifndef HCI_UART_H_
|
||||
#define HCI_UART_H_
|
||||
|
||||
#include <zephyr/net_buf.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Put read HCI packet into the internal DTM buffer.
|
||||
*
|
||||
* This callback puts the HCI packet into the internal buffer
|
||||
* of the DTM module.
|
||||
*
|
||||
* @param[in] buf Buffer containing the HCI packet.
|
||||
*/
|
||||
typedef void (*hci_uart_read_cb)(struct net_buf *buf);
|
||||
|
||||
/** @brief Initialize the HCI UART interface.
|
||||
*
|
||||
* @param[in] cb Pointer to the callback function for
|
||||
* saving the HCI packet into the internal buffer.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int hci_uart_init(hci_uart_read_cb cb);
|
||||
|
||||
/** @brief Transmit an HCI packet.
|
||||
*
|
||||
* This function schedules transmission of an HCI packet.
|
||||
*
|
||||
* @param[in] type Packet type.
|
||||
* @param[in] hdr Packet header.
|
||||
* @param[in] hdr_len Length of the header.
|
||||
* @param[in] pld Packet payload.
|
||||
* @param[in] len Length of the payload.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int hci_uart_write(uint8_t type, const uint8_t *hdr, size_t hdr_len,
|
||||
const uint8_t *pld, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HCI_UART_H_ */
|
||||
155
nordic/trezor/direct_test_mode/src/transport/hci_uart_remote.c
Normal file
155
nordic/trezor/direct_test_mode/src/transport/hci_uart_remote.c
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/net_buf.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <nrf_rpc/nrf_rpc_ipc.h>
|
||||
#include <nrf_rpc_cbor.h>
|
||||
|
||||
#include "hci_uart.h"
|
||||
#include "dtm_serialization.h"
|
||||
|
||||
LOG_MODULE_REGISTER(serialize_layer);
|
||||
|
||||
NRF_RPC_IPC_TRANSPORT(hci_group_tr, DEVICE_DT_GET(DT_NODELABEL(ipc0)), "dtm_ept");
|
||||
NRF_RPC_GROUP_DEFINE(hci_group, "hci_remote", &hci_group_tr, NULL, NULL, NULL);
|
||||
|
||||
NET_BUF_POOL_DEFINE(tx_buf, CONFIG_DTM_HCI_QUEUE_COUNT, CONFIG_DTM_HCI_QUEUE_SIZE, 0, NULL);
|
||||
|
||||
static hci_uart_read_cb callback;
|
||||
|
||||
static void rsp_error_code_handle(const struct nrf_rpc_group *group, struct nrf_rpc_cbor_ctx *ctx,
|
||||
void *handler_data)
|
||||
{
|
||||
int32_t val;
|
||||
|
||||
if (zcbor_int32_decode(ctx->zs, &val)) {
|
||||
*(int *)handler_data = (int)val;
|
||||
} else {
|
||||
*(int *)handler_data = -NRF_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Incoming event from application core (uart) */
|
||||
static void dtm_hci_put_handler(const struct nrf_rpc_group *group, struct nrf_rpc_cbor_ctx *ctx,
|
||||
void *handler_data)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
uint8_t type;
|
||||
struct zcbor_string tmp;
|
||||
|
||||
LOG_DBG("Call from dtm_hci_put");
|
||||
|
||||
if (!zcbor_uint_decode(ctx->zs, &type, sizeof(type))) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if (!zcbor_bstr_decode(ctx->zs, &tmp)) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
buf = net_buf_alloc(&tx_buf, K_NO_WAIT);
|
||||
net_buf_add_mem(buf, tmp.value, tmp.len);
|
||||
buf->user_data[0] = type;
|
||||
|
||||
nrf_rpc_cbor_decoding_done(group, ctx);
|
||||
|
||||
callback(buf);
|
||||
|
||||
return;
|
||||
|
||||
error_exit:
|
||||
__ASSERT_NO_MSG(false);
|
||||
}
|
||||
|
||||
NRF_RPC_CBOR_EVT_DECODER(hci_group, dtm_hci_put, RPC_DTM_HCI_PUT_EVT, dtm_hci_put_handler, NULL);
|
||||
|
||||
/* Outgoing to application core (uart), save callback locally. */
|
||||
int hci_uart_init(hci_uart_read_cb cb)
|
||||
{
|
||||
int result;
|
||||
int err;
|
||||
struct nrf_rpc_cbor_ctx ctx;
|
||||
size_t buffer_size_max = 0;
|
||||
|
||||
LOG_DBG("Call to hci_init");
|
||||
callback = cb;
|
||||
|
||||
NRF_RPC_CBOR_ALLOC(&hci_group, ctx, buffer_size_max);
|
||||
|
||||
err = nrf_rpc_cbor_cmd(&hci_group, RPC_HCI_UART_INIT_CMD, &ctx,
|
||||
rsp_error_code_handle, &result);
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Outgoing to application core (uart) */
|
||||
int hci_uart_write(uint8_t type, const uint8_t *hdr, size_t hdr_len, const uint8_t *pld, size_t len)
|
||||
{
|
||||
int result;
|
||||
int err;
|
||||
struct nrf_rpc_cbor_ctx ctx;
|
||||
size_t buffer_size_max = 20;
|
||||
|
||||
LOG_DBG("Call to hci_uart_write");
|
||||
|
||||
buffer_size_max += hdr_len + len;
|
||||
|
||||
NRF_RPC_CBOR_ALLOC(&hci_group, ctx, buffer_size_max);
|
||||
|
||||
if (!zcbor_uint_encode(ctx.zs, &type, sizeof(type))) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if (!zcbor_bstr_encode_ptr(ctx.zs, hdr, hdr_len)) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if (!zcbor_bstr_encode_ptr(ctx.zs, pld, len)) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
err = nrf_rpc_cbor_cmd(&hci_group, RPC_HCI_UART_WRITE_CMD, &ctx,
|
||||
rsp_error_code_handle, &result);
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
error_exit:
|
||||
__ASSERT_NO_MSG(false);
|
||||
}
|
||||
|
||||
static void err_handler(const struct nrf_rpc_err_report *report)
|
||||
{
|
||||
LOG_ERR("nRF RPC error %d ocurred. See nRF RPC logs for more details.",
|
||||
report->code);
|
||||
k_oops();
|
||||
}
|
||||
|
||||
static int serialization_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
LOG_INF("RPC init begin\n");
|
||||
|
||||
err = nrf_rpc_init(err_handler);
|
||||
if (err) {
|
||||
return -NRF_EINVAL;
|
||||
}
|
||||
|
||||
LOG_INF("RPC init done\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYS_INIT(serialization_init, POST_KERNEL, CONFIG_APPLICATION_INIT_PRIORITY);
|
||||
16
nordic/trezor/direct_test_mode/sysbuild.cmake
Normal file
16
nordic/trezor/direct_test_mode/sysbuild.cmake
Normal file
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# Copyright (c) 2024 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
|
||||
if(SB_CONFIG_DTM_NO_DFE)
|
||||
add_overlay_dts(
|
||||
direct_test_mode
|
||||
${CMAKE_CURRENT_LIST_DIR}/no-dfe.overlay)
|
||||
endif()
|
||||
|
||||
if(SB_CONFIG_DTM_TRANSPORT_HCI)
|
||||
set_config_bool(${DEFAULT_IMAGE} CONFIG_DTM_TRANSPORT_HCI y)
|
||||
else()
|
||||
set_config_bool(${DEFAULT_IMAGE} CONFIG_DTM_TRANSPORT_HCI n)
|
||||
endif()
|
||||
9
nordic/trezor/direct_test_mode/sysbuild.conf
Normal file
9
nordic/trezor/direct_test_mode/sysbuild.conf
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# Copyright (c) 2024 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
# Enable MCUboot
|
||||
SB_CONFIG_BOOTLOADER_MCUBOOT=y
|
||||
SB_CONFIG_MCUBOOT_MODE_SINGLE_APP=y
|
||||
34
nordic/trezor/direct_test_mode/sysbuild/mcuboot.conf
Normal file
34
nordic/trezor/direct_test_mode/sysbuild/mcuboot.conf
Normal file
@@ -0,0 +1,34 @@
|
||||
#CONFIG_PM_PARTITION_SIZE_MCUBOOT=0x10000
|
||||
|
||||
CONFIG_CLOCK_CONTROL=y
|
||||
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y
|
||||
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC_CALIBRATION=y
|
||||
CONFIG_CLOCK_CONTROL_NRF_K32SRC_500PPM=y
|
||||
CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_PERIOD=4000
|
||||
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_UART_LINE_CTRL=y
|
||||
CONFIG_UART_NRFX=y
|
||||
#CONFIG_UART_INTERRUPT_DRIVEN=n
|
||||
|
||||
# MCUBoot serial
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_GPIO_NRFX_INTERRUPT=n
|
||||
CONFIG_MCUBOOT_SERIAL=y
|
||||
CONFIG_BOOT_FIH_PROFILE_MEDIUM=y
|
||||
CONFIG_BOOT_MGMT_ECHO=y
|
||||
CONFIG_BOOT_SERIAL_CDC_ACM=y
|
||||
CONFIG_BOOT_SERIAL_UART=y
|
||||
|
||||
#CONFIG_LOG_BACKEND_UART=y
|
||||
|
||||
#CONFIG_BOOT_SERIAL_DETECT_PIN=11
|
||||
#CONFIG_MCUMGR_SMP_UART=y
|
||||
CONFIG_MCUBOOT_BOOTLOADER_MODE_SINGLE_APP=y
|
||||
CONFIG_SINGLE_APPLICATION_SLOT=y
|
||||
CONFIG_BOOT_VALIDATE_SLOT0=y
|
||||
|
||||
CONFIG_RTT_CONSOLE=n
|
||||
CONFIG_USE_SEGGER_RTT=n
|
||||
CONFIG_UART_CONSOLE=n
|
||||
|
||||
11
nordic/trezor/direct_test_mode/sysbuild/mcuboot_debug.conf
Normal file
11
nordic/trezor/direct_test_mode/sysbuild/mcuboot_debug.conf
Normal file
@@ -0,0 +1,11 @@
|
||||
# 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.
|
||||
|
||||
|
||||
# logging
|
||||
CONFIG_RTT_CONSOLE=y
|
||||
CONFIG_USE_SEGGER_RTT=y
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# 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.
|
||||
|
||||
CONFIG_BOOT_PRODUCTION_KEY=y
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
zephyr,shell-ipc = &ipc0;
|
||||
ncs,remote-shell-uart = &uart0;
|
||||
};
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
status = "okay";
|
||||
current-speed = <19200>;
|
||||
};
|
||||
|
||||
&gpio_fwd {
|
||||
dfe-radio {
|
||||
gpios = <&gpio0 4 0>,
|
||||
<&gpio0 5 0>,
|
||||
<&gpio0 6 0>,
|
||||
<&gpio0 7 0>;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#include "usb.dts"
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
zephyr,shell-ipc = &ipc0;
|
||||
ncs,remote-shell-uart = &cdc_acm0;
|
||||
};
|
||||
};
|
||||
|
||||
&zephyr_udc0 {
|
||||
cdc_acm0: cdc_acm0 {
|
||||
compatible = "zephyr,cdc-acm-uart";
|
||||
};
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
status = "disabled";
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
#
|
||||
# Copyright (c) 2022 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
CONFIG_STDOUT_CONSOLE=y
|
||||
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_UART_INTERRUPT_DRIVEN=y
|
||||
CONFIG_RING_BUFFER=y
|
||||
|
||||
CONFIG_MBOX=y
|
||||
CONFIG_IPC_SERVICE=y
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG=y
|
||||
|
||||
CONFIG_NRFX_UARTE0=y
|
||||
|
||||
CONFIG_HEAP_MEM_POOL_SIZE=4096
|
||||
|
||||
# Config logger
|
||||
CONFIG_LOG=y
|
||||
CONFIG_LOG_PRINTK=y
|
||||
CONFIG_USE_SEGGER_RTT=y
|
||||
CONFIG_LOG_BACKEND_RTT=y
|
||||
CONFIG_LOG_BACKEND_UART=n
|
||||
|
||||
CONFIG_REMOTE_SHELL_TX_RING_BUFFER_SIZE=1024
|
||||
|
||||
CONFIG_SOC_NRF53_CPUNET_ENABLE=y
|
||||
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
CONFIG_CONSOLE=n
|
||||
CONFIG_UART_CONSOLE=n
|
||||
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_UART_INTERRUPT_DRIVEN=y
|
||||
CONFIG_UART_LINE_CTRL=y
|
||||
|
||||
CONFIG_MBOX=y
|
||||
CONFIG_IPC_SERVICE=y
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG=y
|
||||
|
||||
CONFIG_HEAP_MEM_POOL_SIZE=4096
|
||||
|
||||
CONFIG_USB_DEVICE_STACK=y
|
||||
CONFIG_USB_DEVICE_PRODUCT="Nordic Remote Shell sample"
|
||||
CONFIG_USB_DEVICE_VID=0x1915
|
||||
CONFIG_USB_DEVICE_PID=0x53AA
|
||||
|
||||
# Config logger
|
||||
CONFIG_LOG=y
|
||||
CONFIG_LOG_PRINTK=y
|
||||
CONFIG_USE_SEGGER_RTT=y
|
||||
CONFIG_LOG_BACKEND_RTT=y
|
||||
CONFIG_LOG_BACKEND_UART=n
|
||||
CONFIG_USB_DRIVER_LOG_LEVEL_ERR=y
|
||||
CONFIG_USB_DEVICE_LOG_LEVEL_ERR=y
|
||||
|
||||
CONFIG_SOC_NRF53_CPUNET_ENABLE=y
|
||||
8
nordic/trezor/direct_test_mode/sysbuild_hci.conf
Normal file
8
nordic/trezor/direct_test_mode/sysbuild_hci.conf
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Copyright (c) 2024 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
SB_CONFIG_PARTITION_MANAGER=n
|
||||
SB_CONFIG_DTM_TRANSPORT_HCI=y
|
||||
@@ -12,3 +12,4 @@
|
||||
^\./core/embed/sys/systemview/stm32
|
||||
^\./core/embed/io/nfc/rfal
|
||||
^\./nordic/trezor/radio_test
|
||||
^\./nordic/trezor/direct_test_mode
|
||||
|
||||
Reference in New Issue
Block a user