mirror of
https://github.com/Ai-Thinker-Open/Ai-Thinker-Open_RTL8710BX_ALIOS_SDK.git
synced 2025-07-31 19:31:05 +00:00
rel_1.6.0 init
This commit is contained in:
commit
27b3e2883d
19359 changed files with 8093121 additions and 0 deletions
|
|
@ -0,0 +1,39 @@
|
|||
zephyr_library()
|
||||
zephyr_library_sources(
|
||||
util/mem.c
|
||||
util/memq.c
|
||||
util/mayfly.c
|
||||
util/util.c
|
||||
hal/nrf5/cntr.c
|
||||
hal/nrf5/rand.c
|
||||
hal/nrf5/ecb.c
|
||||
hal/nrf5/radio.c
|
||||
ticker/ticker.c
|
||||
ll_sw/ctrl.c
|
||||
ll_sw/crypto.c
|
||||
ll_sw/ll.c
|
||||
ll_sw/ll_filter.c
|
||||
hci/hci_driver.c
|
||||
hci/hci.c
|
||||
)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_BROADCASTER ll_sw/ll_adv.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_OBSERVER ll_sw/ll_scan.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_CENTRAL ll_sw/ll_master.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_CTLR_DTM ll_sw/ll_test.c)
|
||||
|
||||
zephyr_library_include_directories(
|
||||
.
|
||||
util
|
||||
hal
|
||||
ticker
|
||||
ll
|
||||
include
|
||||
)
|
||||
|
||||
zephyr_library_compile_options_ifdef(
|
||||
CONFIG_BT_CTLR_FAST_ENC
|
||||
-Ofast
|
||||
)
|
||||
|
||||
zephyr_library_link_libraries(subsys__bluetooth)
|
||||
494
Living_SDK/kernel/protocols/bluetooth/controller/Kconfig
Normal file
494
Living_SDK/kernel/protocols/bluetooth/controller/Kconfig
Normal file
|
|
@ -0,0 +1,494 @@
|
|||
# Kconfig - Bluetooth Controller configuration options
|
||||
#
|
||||
# Copyright (c) 2016-2017 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
comment "BLE Controller support"
|
||||
|
||||
config BT_CTLR
|
||||
bool "Bluetooth Controller"
|
||||
select BT_RECV_IS_RX_THREAD
|
||||
help
|
||||
Enables support for SoC native controller implementations.
|
||||
|
||||
if BT_CTLR
|
||||
|
||||
choice
|
||||
prompt "Bluetooth Link Layer Selection"
|
||||
default BT_LL_SW
|
||||
help
|
||||
Select the Bluetooth Link Layer to compile.
|
||||
|
||||
config BT_LL_SW
|
||||
bool "Use the software-based BLE Link Layer"
|
||||
help
|
||||
Use Zephyr software BLE Link Layer implementation.
|
||||
|
||||
endchoice
|
||||
|
||||
comment "BLE Controller configuration"
|
||||
|
||||
config BT_CTLR_HCI_VS_BUILD_INFO
|
||||
string "Zephyr HCI VS Build Info string"
|
||||
default ""
|
||||
depends on BT_HCI_VS_EXT
|
||||
help
|
||||
User-defined string that will be returned by the Zephyr VS Read Build
|
||||
Information command after the Zephyr version and build time. When
|
||||
setting this to a value different from an empty string, a space
|
||||
character is required at the beginning to separate it from the
|
||||
already included information.
|
||||
|
||||
config BT_CTLR_DUP_FILTER_LEN
|
||||
prompt "Number of addresses in the scan duplicate filter"
|
||||
int
|
||||
depends on BT_OBSERVER
|
||||
default 16
|
||||
help
|
||||
Set the number of unique BLE addresses that can be filtered as
|
||||
duplicates while scanning.
|
||||
|
||||
config BT_CTLR_RX_BUFFERS
|
||||
prompt "Number of Rx buffers"
|
||||
int
|
||||
default 1
|
||||
default 6 if BT_HCI_RAW
|
||||
range 1 18
|
||||
help
|
||||
Set the number of Rx PDUs to be buffered in the controller. In a 7.5ms
|
||||
connection interval and 2M PHY, maximum 18 packets with L2CAP payload
|
||||
size of 1 byte can be received.
|
||||
|
||||
config BT_CTLR_TX_BUFFERS
|
||||
prompt "Number of Tx buffers"
|
||||
int
|
||||
default 2
|
||||
default 7 if BT_HCI_RAW
|
||||
range 1 19
|
||||
help
|
||||
Set the number of Tx PDUs to be queued for transmission in the
|
||||
controller. In a 7.5ms connection interval and 2M PHY, maximum 19
|
||||
packets can be enqueued, with 18 packets with L2CAP payload size of 1
|
||||
byte can be acknowledged.
|
||||
|
||||
config BT_CTLR_TX_BUFFER_SIZE
|
||||
prompt "Tx buffer size"
|
||||
int
|
||||
range 27 16384
|
||||
default 27
|
||||
help
|
||||
Size of the Tx buffers and the value returned in HCI LE Read Buffer
|
||||
Size command response. If this size if greater than effective PDU size
|
||||
then controller will perform fragmentation before transmitting on the
|
||||
the packet on air.
|
||||
Maximum is set to 16384 due to implementation limitations (use of
|
||||
u16_t for size/length variables).
|
||||
|
||||
config BT_CTLR_COMPANY_ID
|
||||
prompt "Company Id"
|
||||
hex
|
||||
default 0xFFFF
|
||||
range 0x0000 0xFFFF
|
||||
help
|
||||
Set the Company Id that will be used in VERSION_IND PDU.
|
||||
|
||||
config BT_CTLR_SUBVERSION_NUMBER
|
||||
prompt "Subversion Number"
|
||||
hex
|
||||
default 0xFFFF
|
||||
range 0x0000 0xFFFF
|
||||
help
|
||||
Set the Subversion Number that will be used in VERSION_IND PDU.
|
||||
|
||||
config BT_CTLR_RX_PRIO_STACK_SIZE
|
||||
int
|
||||
default 448
|
||||
|
||||
config BT_CTLR_RX_PRIO
|
||||
# Hidden option for Controller's Co-Operative high priority Rx thread
|
||||
# priority.
|
||||
int
|
||||
default 6
|
||||
|
||||
comment "BLE Controller features"
|
||||
|
||||
if BT_CONN
|
||||
|
||||
config BT_CTLR_LE_ENC
|
||||
bool
|
||||
depends on !BT_CTLR_DATA_LENGTH_CLEAR && !BT_CTLR_PHY_2M_NRF
|
||||
default y
|
||||
# Enable support for Bluetooth v4.0 LE Encryption feature in the
|
||||
# Controller.
|
||||
|
||||
config BT_CTLR_CONN_PARAM_REQ
|
||||
bool "Connection Parameter Request"
|
||||
default y
|
||||
help
|
||||
Enable support for Bluetooth v4.1 Connection Parameter Request feature
|
||||
in the Controller.
|
||||
|
||||
config BT_CTLR_LE_PING
|
||||
bool "LE Ping"
|
||||
default y
|
||||
help
|
||||
Enable support for Bluetooth v4.1 LE Ping feature in the Controller.
|
||||
|
||||
config BT_CTLR_PRIVACY
|
||||
bool "LE Controller-based Privacy"
|
||||
depends on !SOC_SERIES_NRF51X
|
||||
default y
|
||||
select BT_RPA
|
||||
help
|
||||
Enable support for Bluetooth v4.2 LE Controller-based Privacy feature
|
||||
in the Controller.
|
||||
|
||||
config BT_CTLR_RL_SIZE
|
||||
prompt "LE Controller-based Privacy Resolving List size"
|
||||
depends on BT_CTLR_PRIVACY
|
||||
int
|
||||
default 8
|
||||
range 1 8 if SOC_FAMILY_NRF5
|
||||
help
|
||||
Set the size of the Resolving List for LE Controller-based Privacy.
|
||||
On nRF5x-based controllers, the hardware imposes a limit of 8 devices.
|
||||
|
||||
config BT_CTLR_EXT_SCAN_FP
|
||||
bool "LE Extended Scanner Filter Policies"
|
||||
default y
|
||||
help
|
||||
Enable support for Bluetooth v4.2 LE Extended Scanner Filter Policies
|
||||
in the Controller.
|
||||
|
||||
config BT_CTLR_DATA_LENGTH
|
||||
bool "Data Length Update"
|
||||
default y if SOC_SERIES_NRF52X
|
||||
help
|
||||
Enable support for Bluetooth v4.2 LE Data Length Update procedure in
|
||||
the Controller.
|
||||
|
||||
config BT_CTLR_DATA_LENGTH_MAX
|
||||
prompt "Maximum data length supported"
|
||||
depends on BT_CTLR_DATA_LENGTH
|
||||
int
|
||||
default 27
|
||||
range 27 251 if SOC_SERIES_NRF52X || BT_CTLR_DATA_LENGTH_CLEAR
|
||||
range 27 27
|
||||
help
|
||||
Set the maximum data length of PDU supported in the Controller.
|
||||
|
||||
config BT_CTLR_PHY
|
||||
bool "PHY Update"
|
||||
default y if SOC_SERIES_NRF52X
|
||||
help
|
||||
Enable support for Bluetooth 5.0 PHY Update Procedure in the
|
||||
Controller.
|
||||
|
||||
endif # BT_CONN
|
||||
|
||||
config BT_CTLR_CHAN_SEL_2
|
||||
bool "Channel Selection Algorithm #2"
|
||||
default y
|
||||
help
|
||||
Enable support for Bluetooth 5.0 LE Channel Selection Algorithm #2 in
|
||||
the Controller.
|
||||
|
||||
config BT_CTLR_MIN_USED_CHAN
|
||||
bool "Minimum Number of Used Channels"
|
||||
default y
|
||||
help
|
||||
Enable support for Bluetooth 5.0 Minimum Number of Used Channels
|
||||
Procedure in the Controller.
|
||||
|
||||
config BT_CTLR_ADV_EXT
|
||||
bool "LE Advertising Extensions"
|
||||
select BT_CTLR_SCAN_REQ_NOTIFY
|
||||
select BT_CTLR_CHAN_SEL_2
|
||||
default y
|
||||
help
|
||||
Enable support for Bluetooth 5.0 LE Advertising Extensions in the
|
||||
Controller.
|
||||
|
||||
config BT_CTLR_DTM
|
||||
bool
|
||||
help
|
||||
Enable support for Direct Test Mode in the Controller.
|
||||
|
||||
config BT_CTLR_DTM_HCI
|
||||
bool "Direct Test Mode over HCI"
|
||||
select BT_CTLR_DTM
|
||||
help
|
||||
Enable support for Direct Test Mode over the HCI transport.
|
||||
|
||||
config BT_CTLR_ADVANCED_FEATURES
|
||||
bool "Show advanced features"
|
||||
help
|
||||
Makes advanced features visible to controller developers.
|
||||
|
||||
menu "Advanced features"
|
||||
visible if BT_CTLR_ADVANCED_FEATURES
|
||||
|
||||
config BT_CTLR_DATA_LENGTH_CLEAR
|
||||
bool "Data Length Support (Cleartext only)"
|
||||
depends on BT_CTLR_DATA_LENGTH && SOC_SERIES_NRF51X
|
||||
help
|
||||
Enable support for Bluetooth v4.2 LE Data Length Update procedure, up to
|
||||
251 byte cleartext payloads in the Controller. Encrypted connections
|
||||
are not supported.
|
||||
|
||||
if BT_CTLR_PHY
|
||||
|
||||
config BT_CTLR_PHY_2M
|
||||
bool "2Mbps PHY Support"
|
||||
depends on !SOC_SERIES_NRF51X || BT_CTLR_PHY_2M_NRF
|
||||
default y
|
||||
help
|
||||
Enable support for Bluetooth 5.0 2Mbps PHY in the Controller.
|
||||
|
||||
config BT_CTLR_PHY_2M_NRF
|
||||
bool "2Mbps Nordic Semiconductor PHY Support (Cleartext only)"
|
||||
depends on SOC_SERIES_NRF51X
|
||||
select BT_CTLR_PHY_2M
|
||||
help
|
||||
Enable support for Nordic Semiconductor proprietary 2Mbps PHY in the
|
||||
Controller. Encrypted connections are not supported.
|
||||
|
||||
config BT_CTLR_PHY_CODED
|
||||
bool "Coded PHY Support"
|
||||
depends on SOC_NRF52840
|
||||
default y
|
||||
help
|
||||
Enable support for Bluetooth 5.0 Coded PHY in the Controller.
|
||||
|
||||
endif # BT_CTLR_PHY
|
||||
|
||||
config BT_CTLR_WORKER_PRIO
|
||||
prompt "Radio and Ticker's Worker IRQ priority"
|
||||
int
|
||||
range 0 3 if SOC_SERIES_NRF51X
|
||||
range 0 6 if SOC_SERIES_NRF52X
|
||||
default 0
|
||||
help
|
||||
The interrupt priority for event preparation and radio IRQ. This value
|
||||
shall be less than or equal to the Ticker's Job priority value.
|
||||
|
||||
config BT_CTLR_JOB_PRIO
|
||||
prompt "Ticker's JOB IRQ priority"
|
||||
int
|
||||
range BT_CTLR_WORKER_PRIO 3 if SOC_SERIES_NRF51X
|
||||
range BT_CTLR_WORKER_PRIO 6 if SOC_SERIES_NRF52X
|
||||
default 0
|
||||
help
|
||||
The interrupt priority for Ticker's Job (SWI4) IRQ. This value shall
|
||||
be greater than or equal to the Ticker's Worker IRQ priority value.
|
||||
|
||||
config BT_CTLR_XTAL_ADVANCED
|
||||
bool "Advanced event preparation"
|
||||
default y
|
||||
help
|
||||
Enables advanced event preparation offset ahead of radio tx/rx, taking
|
||||
into account predictive processing time requirements in preparation to
|
||||
the event, like control procedure handling and CPU execution speeds.
|
||||
Crystal oscillator is retained between closely spaced consecutive
|
||||
radio events to reduce the overall number of crystal settling current
|
||||
consumptions.
|
||||
|
||||
This feature maximizes radio utilization in an average role event
|
||||
timeslice when they are closely spaced by using a reduced offset
|
||||
between preparation and radio event.
|
||||
|
||||
By disabling this feature, the controller will use a constant offset
|
||||
between the preparation and radio event. The controller will toggle
|
||||
crystal oscillator between two closely spaced radio events leading to
|
||||
higher average current due to increased number of crystal settling
|
||||
current consumptions.
|
||||
|
||||
config BT_CTLR_XTAL_THRESHOLD
|
||||
prompt "Crystal shutdown threshold in uS"
|
||||
depends on BT_CTLR_XTAL_ADVANCED
|
||||
int
|
||||
default 5168
|
||||
help
|
||||
Configure the optimal delta in micro seconds between two consecutive
|
||||
radio events below which (active clock) crystal will be retained. This
|
||||
value is board dependent. The value 5168 is based on crude calculation
|
||||
for nRF51 current versus startup time of high frequency crystal.
|
||||
|
||||
config BT_CTLR_SCHED_ADVANCED
|
||||
bool "Advanced scheduling"
|
||||
depends on (BT_MAX_CONN != 0)
|
||||
default y
|
||||
default n if BT_PERIPHERAL && !BT_CENTRAL
|
||||
help
|
||||
Enable non-overlapping placement of observer, initiator and master
|
||||
roles in timespace. Uses window offset in connection updates and uses
|
||||
connection parameter request in slave role to negotiate
|
||||
non-overlapping placement with active master roles to avoid slave
|
||||
roles drifting into active master roles in the local controller.
|
||||
|
||||
This feature maximizes the average data transmission amongst active
|
||||
concurrent master and slave connections while other observer,
|
||||
initiator, master or slave roles are active in the local controller.
|
||||
|
||||
Disabling this feature will lead to overlapping role in timespace
|
||||
leading to skipped events amongst active roles.
|
||||
|
||||
config BT_CTLR_RADIO_ENABLE_FAST
|
||||
bool "Use tTXEN/RXEN,FAST ramp-up"
|
||||
depends on SOC_SERIES_NRF52X
|
||||
default y
|
||||
help
|
||||
Enable use of fast radio ramp-up mode.
|
||||
|
||||
config BT_CTLR_TIFS_HW
|
||||
bool "H/w Accelerated tIFS Trx switching"
|
||||
depends on !BT_CTLR_RADIO_ENABLE_FAST
|
||||
default y
|
||||
help
|
||||
Enable use of hardware accelerated tIFS Trx switching.
|
||||
|
||||
if BT_CONN
|
||||
|
||||
config BT_CTLR_FAST_ENC
|
||||
bool "Fast Encryption Setup"
|
||||
depends on BT_CTLR_LE_ENC
|
||||
help
|
||||
Enable connection encryption setup in 3 connection intervals.
|
||||
Peripheral will respond to Encryption Request with Encryption Response
|
||||
in the same connection interval, and also, will respond with Start
|
||||
Encryption Response PDU in the 3rd connection interval, hence
|
||||
completing encryption setup in 3 connection intervals. Encrypted data
|
||||
would be transmitted as fast as in 3rd connection interval from the
|
||||
connection establishment.
|
||||
Maximum CPU time in Radio ISR will increase if this feature is
|
||||
selected.
|
||||
|
||||
config BT_CTLR_CONN_RSSI
|
||||
bool "Connection RSSI"
|
||||
help
|
||||
Enable connection RSSI measurement.
|
||||
|
||||
endif # BT_CONN
|
||||
|
||||
config BT_CTLR_ADV_INDICATION
|
||||
bool "Advertisement indications"
|
||||
help
|
||||
Generate events indicating on air advertisement events.
|
||||
|
||||
config BT_CTLR_SCAN_REQ_NOTIFY
|
||||
bool "Scan Request Notifications"
|
||||
help
|
||||
Generate events notifying the on air scan requests received.
|
||||
|
||||
config BT_CTLR_SCAN_REQ_RSSI
|
||||
bool "Measure Scan Request RSSI"
|
||||
depends on BT_CTLR_SCAN_REQ_NOTIFY
|
||||
help
|
||||
Measure RSSI of the on air scan requests received.
|
||||
|
||||
endmenu
|
||||
|
||||
comment "BLE Controller hardware configuration"
|
||||
|
||||
menuconfig BT_CTLR_GPIO_PA
|
||||
bool "Power Amplifier GPIO interface"
|
||||
depends on !SOC_SERIES_NRF51X
|
||||
help
|
||||
Enable GPIO interface to a Power Amplifier. This allows hardware
|
||||
designs using PA to let the Controller toggle their state based on
|
||||
radio activity.
|
||||
|
||||
if BT_CTLR_GPIO_PA
|
||||
|
||||
config BT_CTLR_GPIO_PA_PIN
|
||||
prompt "Power Amplifier GPIO pin number"
|
||||
int
|
||||
help
|
||||
GPIO Pin number connected to a Power Amplifier.
|
||||
|
||||
config BT_CTLR_GPIO_PA_POL_INV
|
||||
bool "Inverted polarity for the PA pin"
|
||||
help
|
||||
Enable inverted polarity (active low) for the PA pin.
|
||||
|
||||
config BT_CTLR_GPIO_PA_OFFSET
|
||||
prompt "Time from PA ON to Tx ready"
|
||||
int
|
||||
default 5
|
||||
range 0 10
|
||||
help
|
||||
Time before Tx ready to turn on PA.
|
||||
|
||||
endif # BT_CTLR_GPIO_PA
|
||||
|
||||
menuconfig BT_CTLR_GPIO_LNA
|
||||
bool "Low Noise Amplifier GPIO interface"
|
||||
depends on !SOC_SERIES_NRF51X
|
||||
help
|
||||
Enable GPIO interface to a Low Noise Amplifier. This allows hardware
|
||||
designs using LNAs to let the Controller toggle their state based on
|
||||
radio activity.
|
||||
|
||||
if BT_CTLR_GPIO_LNA
|
||||
|
||||
config BT_CTLR_GPIO_LNA_PIN
|
||||
prompt "Low Noise Amplifier GPIO pin number"
|
||||
int
|
||||
help
|
||||
GPIO Pin number connected to a Low Noise Amplifier.
|
||||
|
||||
config BT_CTLR_GPIO_LNA_POL_INV
|
||||
bool "Inverted polarity for the LNA pin"
|
||||
help
|
||||
Enable inverted polarity (active low) for the LNA pin.
|
||||
|
||||
config BT_CTLR_GPIO_LNA_OFFSET
|
||||
prompt "Time from LNA ON to Rx ready"
|
||||
int
|
||||
default 5
|
||||
range 0 10
|
||||
help
|
||||
Time before Rx ready to turn on LNA.
|
||||
|
||||
endif # BT_CTLR_GPIO_LNA
|
||||
|
||||
config BT_CTLR_PA_LNA_GPIOTE_CHAN
|
||||
# Hidden "nRF5 GPIO PA/LNA GPIOTE Channel"
|
||||
depends on SOC_FAMILY_NRF5 && (BT_CTLR_GPIO_PA || BT_CTLR_GPIO_LNA)
|
||||
int
|
||||
default 3
|
||||
help
|
||||
Select the nRF5 GPIOTE channel to use for PA/LNA GPIO feature.
|
||||
|
||||
comment "BLE Controller debug configuration"
|
||||
|
||||
config BT_CTLR_ASSERT_HANDLER
|
||||
bool "Bluetooth Controller Assertion Handler"
|
||||
depends on BT_HCI_RAW
|
||||
help
|
||||
This option enables an application-defined sink for the
|
||||
controller assertion mechanism. This must be defined in
|
||||
application code as void \"bt_controller_assert_handle(char \*, int)\"
|
||||
and will be invoked whenever the controller code encounters
|
||||
an unrecoverable error.
|
||||
|
||||
config BT_CTLR_PROFILE_ISR
|
||||
bool "Profile radio ISR"
|
||||
help
|
||||
Turn on measurement of radio ISR latency, CPU usage and generation of
|
||||
controller event with these profiling data. The controller event
|
||||
contains current, minimum and maximum ISR entry latencies; and
|
||||
current, minimum and maximum ISR CPU use in micro-seconds.
|
||||
|
||||
config BT_CTLR_DEBUG_PINS
|
||||
bool "Bluetooth Controller Debug Pins"
|
||||
depends on BOARD_NRF51_PCA10028 || BOARD_NRF52_PCA10040 || BOARD_NRF52840_PCA10056
|
||||
help
|
||||
Turn on debug GPIO toggling for the BLE Controller. This is useful
|
||||
when debugging with a logic analyzer or profiling certain sections of
|
||||
the code. When enabled, pins P0.16 to P0.25 are taken over exclusively
|
||||
by the controller and cannot be used outside of it.
|
||||
|
||||
endif # BT_CTLR
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
NAME := controller
|
||||
|
||||
$(NAME)_TYPE := kernel
|
||||
$(NAME)_MBINS_TYPE := kernel
|
||||
|
||||
GLOBAL_INCLUDES += .
|
||||
|
||||
$(NAME)_INCLUDES += ../common \
|
||||
. \
|
||||
hal/nrf5 \
|
||||
hci \
|
||||
include \
|
||||
ll_sw \
|
||||
ticker \
|
||||
util
|
||||
|
||||
$(NAME)_SOURCES += hal/nrf5/cntr.c \
|
||||
hal/nrf5/ecb.c \
|
||||
hal/nrf5/radio.c \
|
||||
hal/nrf5/rand.c \
|
||||
hci/hci.c \
|
||||
hci/hci_driver.c \
|
||||
ll_sw/ctrl.c \
|
||||
ll_sw/ll.c \
|
||||
ll_sw/ll_adv.c \
|
||||
ll_sw/ll_filter.c \
|
||||
ll_sw/ll_master.c \
|
||||
ll_sw/ll_scan.c \
|
||||
ll_sw/crypto.c \
|
||||
ticker/ticker.c \
|
||||
util/mayfly.c \
|
||||
util/mem.c \
|
||||
util/memq.c \
|
||||
util/util.c \
|
||||
hal/device.c \
|
||||
../common/irq_manage.c
|
||||
|
||||
GLOBAL_DEFINES += CONFIG_BT_OBSERVER
|
||||
GLOBAL_DEFINES += CONFIG_BT_BROADCASTER
|
||||
GLOBAL_DEFINES += CONFIG_DEVICE_POWER_MANAGEMENT
|
||||
GLOBAL_DEFINES += CONFIG_BT_CTLR_LE_ENC
|
||||
#GLOBAL_DEFINES += CONFIG_BT_CTLR_PHY_2M
|
||||
GLOBAL_DEFINES += CONFIG_BT_CTLR_MIN_USED_CHAN
|
||||
GLOBAL_DEFINES += CONFIG_BT_CTLR_PHY
|
||||
GLOBAL_DEFINES += CONFIG_BT_CTLR_CHAN_SEL_2
|
||||
GLOBAL_DEFINES += CONFIG_BT_CTLR_CONN_PARAM_REQ
|
||||
19
Living_SDK/kernel/protocols/bluetooth/controller/hal/ccm.h
Normal file
19
Living_SDK/kernel/protocols/bluetooth/controller/hal/ccm.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _CCM_H_
|
||||
#define _CCM_H_
|
||||
|
||||
struct ccm {
|
||||
u8_t key[16];
|
||||
u64_t counter;
|
||||
u8_t direction:1;
|
||||
u8_t resv1:7;
|
||||
u8_t iv[8];
|
||||
} __packed;
|
||||
|
||||
#endif /* _CCM_H_ */
|
||||
19
Living_SDK/kernel/protocols/bluetooth/controller/hal/cntr.h
Normal file
19
Living_SDK/kernel/protocols/bluetooth/controller/hal/cntr.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _CNTR_H_
|
||||
#define _CNTR_H_
|
||||
|
||||
#include <net/buf.h>
|
||||
|
||||
void cntr_init(void);
|
||||
u32_t cntr_start(void);
|
||||
u32_t cntr_stop(void);
|
||||
u32_t cntr_cnt_get(void);
|
||||
void cntr_cmp_set(u8_t cmp, u32_t value);
|
||||
|
||||
#endif /* _CNTR_H_ */
|
||||
21
Living_SDK/kernel/protocols/bluetooth/controller/hal/cpu.h
Normal file
21
Living_SDK/kernel/protocols/bluetooth/controller/hal/cpu.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _CPU_H_
|
||||
#define _CPU_H_
|
||||
|
||||
#include "nrf.h"
|
||||
|
||||
|
||||
static inline void cpu_sleep(void)
|
||||
{
|
||||
__WFE();
|
||||
__SEV();
|
||||
__WFE();
|
||||
}
|
||||
|
||||
#endif /* _CPU_H_ */
|
||||
23
Living_SDK/kernel/protocols/bluetooth/controller/hal/debug.h
Normal file
23
Living_SDK/kernel/protocols/bluetooth/controller/hal/debug.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _HAL_DEBUG_H_
|
||||
#define _HAL_DEBUG_H_
|
||||
|
||||
#ifdef CONFIG_BT_CTLR_ASSERT_HANDLER
|
||||
void bt_ctlr_assert_handle(char *file, u32_t line);
|
||||
#define LL_ASSERT(cond) if (!(cond)) { \
|
||||
bt_ctlr_assert_handle(__FILE__, \
|
||||
__LINE__); \
|
||||
}
|
||||
#else
|
||||
#define LL_ASSERT(cond) BT_ASSERT(cond)
|
||||
#endif
|
||||
|
||||
#include "nrf5/debug.h"
|
||||
|
||||
#endif /* _HAL_DEBUG_H_ */
|
||||
137
Living_SDK/kernel/protocols/bluetooth/controller/hal/device.c
Normal file
137
Living_SDK/kernel/protocols/bluetooth/controller/hal/device.c
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <device.h>
|
||||
#include <misc/util.h>
|
||||
#include <atomic.h>
|
||||
#include "linker-defs.h"
|
||||
|
||||
extern struct device __device_init_start[];
|
||||
extern struct device __device_PRE_KERNEL_1_start[];
|
||||
extern struct device __device_PRE_KERNEL_2_start[];
|
||||
extern struct device __device_POST_KERNEL_start[];
|
||||
extern struct device __device_APPLICATION_start[];
|
||||
extern struct device __device_init_end[];
|
||||
|
||||
static struct device *config_levels[] = {
|
||||
__device_PRE_KERNEL_1_start,
|
||||
__device_PRE_KERNEL_2_start,
|
||||
__device_POST_KERNEL_start,
|
||||
__device_APPLICATION_start,
|
||||
/* End marker */
|
||||
__device_init_end,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
|
||||
extern u32_t __device_busy_start[];
|
||||
extern u32_t __device_busy_end[];
|
||||
#define DEVICE_BUSY_SIZE (__device_busy_end - __device_busy_start)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Execute all the device initialization functions at a given level
|
||||
*
|
||||
* @details Invokes the initialization routine for each device object
|
||||
* created by the DEVICE_INIT() macro using the specified level.
|
||||
* The linker script places the device objects in memory in the order
|
||||
* they need to be invoked, with symbols indicating where one level leaves
|
||||
* off and the next one begins.
|
||||
*
|
||||
* @param level init level to run.
|
||||
*/
|
||||
void _sys_device_do_config_level(int level)
|
||||
{
|
||||
struct device *info;
|
||||
|
||||
for (info = config_levels[level]; info < config_levels[level+1];
|
||||
info++) {
|
||||
struct device_config *device = info->config;
|
||||
|
||||
device->init(info);
|
||||
_k_object_init(info);
|
||||
}
|
||||
}
|
||||
|
||||
struct device *device_get_binding(const char *name)
|
||||
{
|
||||
struct device *info;
|
||||
|
||||
for (info = __device_init_start; info != __device_init_end; info++) {
|
||||
if (!info->driver_api) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (name == info->config->name) {
|
||||
return info;
|
||||
}
|
||||
|
||||
if (!strcmp(name, info->config->name)) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
|
||||
int device_pm_control_nop(struct device *unused_device,
|
||||
u32_t unused_ctrl_command, void *unused_context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void device_list_get(struct device **device_list, int *device_count)
|
||||
{
|
||||
|
||||
*device_list = __device_init_start;
|
||||
*device_count = __device_init_end - __device_init_start;
|
||||
}
|
||||
|
||||
|
||||
int device_any_busy_check(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < DEVICE_BUSY_SIZE; i++) {
|
||||
if (__device_busy_start[i] != 0) {
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int device_busy_check(struct device *chk_dev)
|
||||
{
|
||||
if (atomic_test_bit((const atomic_t *)__device_busy_start,
|
||||
(chk_dev - __device_init_start))) {
|
||||
return -EBUSY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void device_busy_set(struct device *busy_dev)
|
||||
{
|
||||
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
|
||||
atomic_set_bit((atomic_t *) __device_busy_start,
|
||||
(busy_dev - __device_init_start));
|
||||
#else
|
||||
ARG_UNUSED(busy_dev);
|
||||
#endif
|
||||
}
|
||||
|
||||
void device_busy_clear(struct device *busy_dev)
|
||||
{
|
||||
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
|
||||
atomic_clear_bit((atomic_t *) __device_busy_start,
|
||||
(busy_dev - __device_init_start));
|
||||
#else
|
||||
ARG_UNUSED(busy_dev);
|
||||
#endif
|
||||
}
|
||||
34
Living_SDK/kernel/protocols/bluetooth/controller/hal/ecb.h
Normal file
34
Living_SDK/kernel/protocols/bluetooth/controller/hal/ecb.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _ECB_H_
|
||||
#define _ECB_H_
|
||||
|
||||
typedef void (*ecb_fp) (u32_t status, u8_t *cipher_be, void *context);
|
||||
|
||||
struct ecb {
|
||||
u8_t in_key_be[16];
|
||||
u8_t in_clear_text_be[16];
|
||||
u8_t out_cipher_text_be[16];
|
||||
/* if not null reverse copy into in_key_be */
|
||||
u8_t *in_key_le;
|
||||
/* if not null reverse copy into in_clear_text_be */
|
||||
u8_t *in_clear_text_le;
|
||||
ecb_fp fp_ecb;
|
||||
void *context;
|
||||
};
|
||||
|
||||
void ecb_encrypt_be(u8_t const *const key_be, u8_t const *const clear_text_be,
|
||||
u8_t * const cipher_text_be);
|
||||
void ecb_encrypt(u8_t const *const key_le, u8_t const *const clear_text_le,
|
||||
u8_t * const cipher_text_le, u8_t * const cipher_text_be);
|
||||
u32_t ecb_encrypt_nonblocking(struct ecb *ecb);
|
||||
void isr_ecb(void *param);
|
||||
|
||||
u32_t ecb_ut(void);
|
||||
|
||||
#endif /* _ECB_H_ */
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <soc.h>
|
||||
#include "hal/cntr.h"
|
||||
|
||||
#include "common/log.h"
|
||||
#include "hal/debug.h"
|
||||
|
||||
|
||||
#ifndef NRF_RTC
|
||||
#define NRF_RTC NRF_RTC0
|
||||
#endif
|
||||
|
||||
static u8_t _refcount;
|
||||
|
||||
void cntr_init(void)
|
||||
{
|
||||
NRF_RTC->PRESCALER = 0;
|
||||
NRF_RTC->EVTENSET = (RTC_EVTENSET_COMPARE0_Msk |
|
||||
RTC_EVTENSET_COMPARE1_Msk);
|
||||
NRF_RTC->INTENSET = (RTC_INTENSET_COMPARE0_Msk |
|
||||
RTC_INTENSET_COMPARE1_Msk);
|
||||
}
|
||||
|
||||
u32_t cntr_start(void)
|
||||
{
|
||||
if (_refcount++) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
NRF_RTC->TASKS_START = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32_t cntr_stop(void)
|
||||
{
|
||||
LL_ASSERT(_refcount);
|
||||
|
||||
if (--_refcount) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
NRF_RTC->TASKS_STOP = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32_t cntr_cnt_get(void)
|
||||
{
|
||||
return NRF_RTC->COUNTER;
|
||||
}
|
||||
|
||||
void cntr_cmp_set(u8_t cmp, u32_t value)
|
||||
{
|
||||
NRF_RTC->CC[cmp] = value;
|
||||
}
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2017 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _DEBUG_H_
|
||||
#define _DEBUG_H_
|
||||
|
||||
#include "nrf.h"
|
||||
|
||||
#ifdef CONFIG_BT_CTLR_DEBUG_PINS
|
||||
#if defined(CONFIG_BOARD_NRF52840_PCA10056)
|
||||
#define DEBUG_PORT NRF_P1
|
||||
#define DEBUG_PIN0 BIT(1)
|
||||
#define DEBUG_PIN1 BIT(2)
|
||||
#define DEBUG_PIN2 BIT(3)
|
||||
#define DEBUG_PIN3 BIT(4)
|
||||
#define DEBUG_PIN4 BIT(5)
|
||||
#define DEBUG_PIN5 BIT(6)
|
||||
#define DEBUG_PIN6 BIT(7)
|
||||
#define DEBUG_PIN7 BIT(8)
|
||||
#define DEBUG_PIN8 BIT(10)
|
||||
#define DEBUG_PIN9 BIT(11)
|
||||
#elif defined(CONFIG_BOARD_NRF52_PCA10040)
|
||||
#define DEBUG_PORT NRF_GPIO
|
||||
#define DEBUG_PIN0 BIT(11)
|
||||
#define DEBUG_PIN1 BIT(12)
|
||||
#define DEBUG_PIN2 BIT(13)
|
||||
#define DEBUG_PIN3 BIT(14)
|
||||
#define DEBUG_PIN4 BIT(15)
|
||||
#define DEBUG_PIN5 BIT(16)
|
||||
#define DEBUG_PIN6 BIT(17)
|
||||
#define DEBUG_PIN7 BIT(18)
|
||||
#define DEBUG_PIN8 BIT(19)
|
||||
#define DEBUG_PIN9 BIT(20)
|
||||
#elif defined(CONFIG_BOARD_NRF51_PCA10028)
|
||||
#define DEBUG_PORT NRF_GPIO
|
||||
#define DEBUG_PIN0 BIT(12)
|
||||
#define DEBUG_PIN1 BIT(13)
|
||||
#define DEBUG_PIN2 BIT(14)
|
||||
#define DEBUG_PIN3 BIT(15)
|
||||
#define DEBUG_PIN4 BIT(16)
|
||||
#define DEBUG_PIN5 BIT(17)
|
||||
#define DEBUG_PIN6 BIT(18)
|
||||
#define DEBUG_PIN7 BIT(19)
|
||||
#define DEBUG_PIN8 BIT(20)
|
||||
#define DEBUG_PIN9 BIT(23)
|
||||
#else
|
||||
#error BT_CTLR_DEBUG_PINS not supported on this board.
|
||||
#endif
|
||||
|
||||
#define DEBUG_PIN_MASK (DEBUG_PIN0 | DEBUG_PIN1 | DEBUG_PIN2 | DEBUG_PIN3 | \
|
||||
DEBUG_PIN4 | DEBUG_PIN5 | DEBUG_PIN6 | DEBUG_PIN7 | \
|
||||
DEBUG_PIN8 | DEBUG_PIN9)
|
||||
#define DEBUG_CLOSE_MASK (DEBUG_PIN3 | DEBUG_PIN4 | DEBUG_PIN5 | DEBUG_PIN6)
|
||||
|
||||
/* below are some interesting macros referenced by controller
|
||||
* which can be defined to SoC's GPIO toggle to observe/debug the
|
||||
* controller's runtime behavior.
|
||||
*/
|
||||
#define DEBUG_INIT() do { \
|
||||
DEBUG_PORT->DIRSET = DEBUG_PIN_MASK; \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN_MASK; } \
|
||||
while (0)
|
||||
|
||||
#define DEBUG_CPU_SLEEP(flag) do { \
|
||||
if (flag) { \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN0; \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN0; } \
|
||||
else { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN0; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN0; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_TICKER_ISR(flag) do { \
|
||||
if (flag) { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN1; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN1; } \
|
||||
else { \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN1; \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN1; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_TICKER_TASK(flag) do { \
|
||||
if (flag) { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN1; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN1; } \
|
||||
else { \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN1; \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN1; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_TICKER_JOB(flag) do { \
|
||||
if (flag) { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN2; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN2; } \
|
||||
else { \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN2; \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN2; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_ISR(flag) do { \
|
||||
if (flag) { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN7; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN7; } \
|
||||
else { \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN7; \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN7; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_XTAL(flag) do { \
|
||||
if (flag) { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN8; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN8; } \
|
||||
else { \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN8; \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN8; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_ACTIVE(flag) do { \
|
||||
if (flag) { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN9; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN9; } \
|
||||
else { \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN9; \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN9; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_CLOSE(flag) do { \
|
||||
if (flag) { \
|
||||
DEBUG_PORT->OUTCLR = 0x00000000; \
|
||||
DEBUG_PORT->OUTSET = 0x00000000; } \
|
||||
else { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_CLOSE_MASK; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_PREPARE_A(flag) do { \
|
||||
if (flag) { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN3; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN3; } \
|
||||
else { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN3; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN3; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_START_A(flag) do { \
|
||||
if (flag) { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN3; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN3; } \
|
||||
else { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN3; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN3; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_PREPARE_S(flag) do { \
|
||||
if (flag) { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN4; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN4; } \
|
||||
else { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN4; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN4; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_START_S(flag) do { \
|
||||
if (flag) { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN4; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN4; } \
|
||||
else { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN4; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN4; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_PREPARE_O(flag) do { \
|
||||
if (flag) { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN5; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN5; } \
|
||||
else { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN5; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN5; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_START_O(flag) do { \
|
||||
if (flag) { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN5; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN5; } \
|
||||
else { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN5; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN5; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_PREPARE_M(flag) do { \
|
||||
if (flag) { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN6; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN6; } \
|
||||
else { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN6; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN6; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_START_M(flag) do { \
|
||||
if (flag) { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN6; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN6; } \
|
||||
else { \
|
||||
DEBUG_PORT->OUTCLR = DEBUG_PIN6; \
|
||||
DEBUG_PORT->OUTSET = DEBUG_PIN6; } \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
#define DEBUG_INIT()
|
||||
|
||||
#define DEBUG_CPU_SLEEP(flag)
|
||||
|
||||
#define DEBUG_TICKER_ISR(flag)
|
||||
|
||||
#define DEBUG_TICKER_TASK(flag)
|
||||
|
||||
#define DEBUG_TICKER_JOB(flag)
|
||||
|
||||
#define DEBUG_RADIO_ISR(flag)
|
||||
|
||||
#define DEBUG_RADIO_HCTO(flag)
|
||||
|
||||
#define DEBUG_RADIO_XTAL(flag)
|
||||
|
||||
#define DEBUG_RADIO_ACTIVE(flag)
|
||||
|
||||
#define DEBUG_RADIO_CLOSE(flag)
|
||||
|
||||
#define DEBUG_RADIO_PREPARE_A(flag)
|
||||
|
||||
#define DEBUG_RADIO_START_A(flag)
|
||||
|
||||
#define DEBUG_RADIO_PREPARE_S(flag)
|
||||
|
||||
#define DEBUG_RADIO_START_S(flag)
|
||||
|
||||
#define DEBUG_RADIO_PREPARE_O(flag)
|
||||
|
||||
#define DEBUG_RADIO_START_O(flag)
|
||||
|
||||
#define DEBUG_RADIO_PREPARE_M(flag)
|
||||
|
||||
#define DEBUG_RADIO_START_M(flag)
|
||||
|
||||
#endif /* CONFIG_BT_CTLR_DEBUG_PINS */
|
||||
|
||||
#endif /* _DEBUG_H_ */
|
||||
197
Living_SDK/kernel/protocols/bluetooth/controller/hal/nrf5/ecb.c
Normal file
197
Living_SDK/kernel/protocols/bluetooth/controller/hal/nrf5/ecb.c
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <soc.h>
|
||||
//#include <arch/arm/cortex_m/cmsis.h>
|
||||
|
||||
#include "util/mem.h"
|
||||
#include "hal/ecb.h"
|
||||
#include "nrf.h"
|
||||
|
||||
#include "common/log.h"
|
||||
#include "hal/debug.h"
|
||||
|
||||
struct ecb_param {
|
||||
u8_t key[16];
|
||||
u8_t clear_text[16];
|
||||
u8_t cipher_text[16];
|
||||
} __packed;
|
||||
|
||||
static void do_ecb(struct ecb_param *ecb)
|
||||
{
|
||||
do {
|
||||
NRF_ECB->TASKS_STOPECB = 1;
|
||||
NRF_ECB->ECBDATAPTR = (u32_t)ecb;
|
||||
NRF_ECB->EVENTS_ENDECB = 0;
|
||||
NRF_ECB->EVENTS_ERRORECB = 0;
|
||||
NRF_ECB->TASKS_STARTECB = 1;
|
||||
while ((NRF_ECB->EVENTS_ENDECB == 0) &&
|
||||
(NRF_ECB->EVENTS_ERRORECB == 0) &&
|
||||
(NRF_ECB->ECBDATAPTR != 0)) {
|
||||
/*__WFE();*/
|
||||
}
|
||||
NRF_ECB->TASKS_STOPECB = 1;
|
||||
} while ((NRF_ECB->EVENTS_ERRORECB != 0) || (NRF_ECB->ECBDATAPTR == 0));
|
||||
|
||||
NRF_ECB->ECBDATAPTR = 0;
|
||||
}
|
||||
|
||||
void ecb_encrypt_be(u8_t const *const key_be, u8_t const *const clear_text_be,
|
||||
u8_t * const cipher_text_be)
|
||||
{
|
||||
struct ecb_param ecb;
|
||||
|
||||
memcpy(&ecb.key[0], key_be, sizeof(ecb.key));
|
||||
memcpy(&ecb.clear_text[0], clear_text_be, sizeof(ecb.clear_text));
|
||||
|
||||
do_ecb(&ecb);
|
||||
|
||||
memcpy(cipher_text_be, &ecb.cipher_text[0], sizeof(ecb.cipher_text));
|
||||
}
|
||||
|
||||
void ecb_encrypt(u8_t const *const key_le, u8_t const *const clear_text_le,
|
||||
u8_t * const cipher_text_le, u8_t * const cipher_text_be)
|
||||
{
|
||||
struct ecb_param ecb;
|
||||
|
||||
mem_rcopy(&ecb.key[0], key_le, sizeof(ecb.key));
|
||||
mem_rcopy(&ecb.clear_text[0], clear_text_le, sizeof(ecb.clear_text));
|
||||
|
||||
do_ecb(&ecb);
|
||||
|
||||
if (cipher_text_le) {
|
||||
mem_rcopy(cipher_text_le, &ecb.cipher_text[0],
|
||||
sizeof(ecb.cipher_text));
|
||||
}
|
||||
|
||||
if (cipher_text_be) {
|
||||
memcpy(cipher_text_be, &ecb.cipher_text[0],
|
||||
sizeof(ecb.cipher_text));
|
||||
}
|
||||
}
|
||||
|
||||
u32_t ecb_encrypt_nonblocking(struct ecb *ecb)
|
||||
{
|
||||
/* prepare to be used in a BE AES h/w */
|
||||
if (ecb->in_key_le) {
|
||||
mem_rcopy(&ecb->in_key_be[0], ecb->in_key_le,
|
||||
sizeof(ecb->in_key_be));
|
||||
}
|
||||
if (ecb->in_clear_text_le) {
|
||||
mem_rcopy(&ecb->in_clear_text_be[0],
|
||||
ecb->in_clear_text_le,
|
||||
sizeof(ecb->in_clear_text_be));
|
||||
}
|
||||
|
||||
/* setup the encryption h/w */
|
||||
NRF_ECB->ECBDATAPTR = (u32_t)ecb;
|
||||
NRF_ECB->EVENTS_ENDECB = 0;
|
||||
NRF_ECB->EVENTS_ERRORECB = 0;
|
||||
NRF_ECB->INTENSET = ECB_INTENSET_ERRORECB_Msk | ECB_INTENSET_ENDECB_Msk;
|
||||
|
||||
/* enable interrupt */
|
||||
NVIC_ClearPendingIRQ(ECB_IRQn);
|
||||
irq_enable(ECB_IRQn);
|
||||
|
||||
/* start the encryption h/w */
|
||||
NRF_ECB->TASKS_STARTECB = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ecb_cleanup(void)
|
||||
{
|
||||
/* stop h/w */
|
||||
NRF_ECB->TASKS_STOPECB = 1;
|
||||
|
||||
/* cleanup interrupt */
|
||||
irq_disable(ECB_IRQn);
|
||||
}
|
||||
|
||||
void isr_ecb(void *param)
|
||||
{
|
||||
ARG_UNUSED(param);
|
||||
|
||||
if (NRF_ECB->EVENTS_ERRORECB) {
|
||||
struct ecb *ecb = (struct ecb *)NRF_ECB->ECBDATAPTR;
|
||||
|
||||
ecb_cleanup();
|
||||
|
||||
ecb->fp_ecb(1, NULL, ecb->context);
|
||||
}
|
||||
|
||||
else if (NRF_ECB->EVENTS_ENDECB) {
|
||||
struct ecb *ecb = (struct ecb *)NRF_ECB->ECBDATAPTR;
|
||||
|
||||
ecb_cleanup();
|
||||
|
||||
ecb->fp_ecb(0, &ecb->out_cipher_text_be[0],
|
||||
ecb->context);
|
||||
}
|
||||
|
||||
else {
|
||||
LL_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
struct ecb_ut_context {
|
||||
u32_t volatile done;
|
||||
u32_t status;
|
||||
u8_t cipher_text[16];
|
||||
};
|
||||
|
||||
static void ecb_cb(u32_t status, u8_t *cipher_be, void *context)
|
||||
{
|
||||
struct ecb_ut_context *ecb_ut_context =
|
||||
(struct ecb_ut_context *)context;
|
||||
|
||||
ecb_ut_context->done = 1;
|
||||
ecb_ut_context->status = status;
|
||||
if (!status) {
|
||||
mem_rcopy(ecb_ut_context->cipher_text, cipher_be,
|
||||
sizeof(ecb_ut_context->cipher_text));
|
||||
}
|
||||
}
|
||||
|
||||
u32_t ecb_ut(void)
|
||||
{
|
||||
u8_t key[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
|
||||
0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
|
||||
u8_t clear_text[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44,
|
||||
0x55 };
|
||||
u8_t cipher_text[16];
|
||||
u32_t status = 0;
|
||||
struct ecb ecb;
|
||||
struct ecb_ut_context context;
|
||||
|
||||
ecb_encrypt(key, clear_text, cipher_text, NULL);
|
||||
|
||||
context.done = 0;
|
||||
ecb.in_key_le = key;
|
||||
ecb.in_clear_text_le = clear_text;
|
||||
ecb.fp_ecb = ecb_cb;
|
||||
ecb.context = &context;
|
||||
status = ecb_encrypt_nonblocking(&ecb);
|
||||
do {
|
||||
__WFE();
|
||||
__SEV();
|
||||
__WFE();
|
||||
} while (!context.done);
|
||||
|
||||
if (context.status != 0) {
|
||||
return context.status;
|
||||
}
|
||||
|
||||
status = memcmp(cipher_text, context.cipher_text, sizeof(cipher_text));
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
1093
Living_SDK/kernel/protocols/bluetooth/controller/hal/nrf5/radio.c
Normal file
1093
Living_SDK/kernel/protocols/bluetooth/controller/hal/nrf5/radio.c
Normal file
File diff suppressed because it is too large
Load diff
209
Living_SDK/kernel/protocols/bluetooth/controller/hal/nrf5/rand.c
Normal file
209
Living_SDK/kernel/protocols/bluetooth/controller/hal/nrf5/rand.c
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <soc.h>
|
||||
#include <debug.h>
|
||||
#include "hal/rand.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include "common/log.h"
|
||||
#include "hal/debug.h"
|
||||
|
||||
struct rand {
|
||||
u8_t count;
|
||||
u8_t threshold;
|
||||
u8_t first;
|
||||
u8_t last;
|
||||
u8_t rand[1];
|
||||
};
|
||||
|
||||
static struct rand *rng_isr;
|
||||
static struct rand *rng_thr;
|
||||
|
||||
static void init(struct rand **rng, u8_t *context, u8_t len, u8_t threshold)
|
||||
{
|
||||
struct rand *p;
|
||||
|
||||
LL_ASSERT(len > (offsetof(struct rand, rand) + threshold));
|
||||
|
||||
*rng = (struct rand *)context;
|
||||
|
||||
p = *rng;
|
||||
p->count = len - offsetof(struct rand, rand);
|
||||
p->threshold = threshold;
|
||||
p->first = p->last = 0;
|
||||
|
||||
if (!rng_isr || !rng_thr) {
|
||||
NRF_RNG->CONFIG = RNG_CONFIG_DERCEN_Msk;
|
||||
NRF_RNG->EVENTS_VALRDY = 0;
|
||||
NRF_RNG->INTENSET = RNG_INTENSET_VALRDY_Msk;
|
||||
|
||||
NRF_RNG->TASKS_START = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void rand_init(u8_t *context, u8_t context_len, u8_t threshold)
|
||||
{
|
||||
init(&rng_thr, context, context_len, threshold);
|
||||
}
|
||||
|
||||
void rand_isr_init(u8_t *context, u8_t context_len, u8_t threshold)
|
||||
{
|
||||
init(&rng_isr, context, context_len, threshold);
|
||||
}
|
||||
|
||||
static size_t get(struct rand *rng, size_t octets, u8_t *rand)
|
||||
{
|
||||
u8_t first, last, remaining;
|
||||
|
||||
LL_ASSERT(rng);
|
||||
|
||||
first = rng->first;
|
||||
last = rng->last;
|
||||
|
||||
if (first <= last) {
|
||||
u8_t *d, *s;
|
||||
u8_t avail;
|
||||
|
||||
d = &rand[octets];
|
||||
s = &rng->rand[first];
|
||||
|
||||
avail = last - first;
|
||||
if (octets < avail) {
|
||||
remaining = avail - octets;
|
||||
avail = octets;
|
||||
} else {
|
||||
remaining = 0;
|
||||
}
|
||||
|
||||
first += avail;
|
||||
octets -= avail;
|
||||
|
||||
while (avail--) {
|
||||
*(--d) = *s++;
|
||||
}
|
||||
|
||||
rng->first = first;
|
||||
} else {
|
||||
u8_t *d, *s;
|
||||
u8_t avail;
|
||||
|
||||
d = &rand[octets];
|
||||
s = &rng->rand[first];
|
||||
|
||||
avail = rng->count - first;
|
||||
if (octets < avail) {
|
||||
remaining = avail + last - octets;
|
||||
avail = octets;
|
||||
first += avail;
|
||||
} else {
|
||||
remaining = last;
|
||||
first = 0;
|
||||
}
|
||||
|
||||
octets -= avail;
|
||||
|
||||
while (avail--) {
|
||||
*(--d) = *s++;
|
||||
}
|
||||
|
||||
if (octets && last) {
|
||||
s = &rng->rand[0];
|
||||
|
||||
if (octets < last) {
|
||||
remaining = last - octets;
|
||||
last = octets;
|
||||
} else {
|
||||
remaining = 0;
|
||||
}
|
||||
|
||||
first = last;
|
||||
octets -= last;
|
||||
|
||||
while (last--) {
|
||||
*(--d) = *s++;
|
||||
}
|
||||
}
|
||||
|
||||
rng->first = first;
|
||||
}
|
||||
|
||||
if (remaining < rng->threshold) {
|
||||
NRF_RNG->TASKS_START = 1;
|
||||
}
|
||||
|
||||
return octets;
|
||||
}
|
||||
|
||||
size_t rand_get(size_t octets, u8_t *rand)
|
||||
{
|
||||
return get(rng_thr, octets, rand);
|
||||
}
|
||||
|
||||
size_t rand_isr_get(size_t octets, u8_t *rand)
|
||||
{
|
||||
return get(rng_isr, octets, rand);
|
||||
}
|
||||
|
||||
static int isr(struct rand *rng, bool store)
|
||||
{
|
||||
u8_t last;
|
||||
|
||||
if (!rng) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
last = rng->last + 1;
|
||||
if (last == rng->count) {
|
||||
last = 0;
|
||||
}
|
||||
|
||||
if (last == rng->first) {
|
||||
/* this condition should not happen, but due to probable race,
|
||||
* new value could be generated before NRF_RNG task is stopped.
|
||||
*/
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
if (!store) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
rng->rand[rng->last] = NRF_RNG->VALUE;
|
||||
rng->last = last;
|
||||
|
||||
last = rng->last + 1;
|
||||
if (last == rng->count) {
|
||||
last = 0;
|
||||
}
|
||||
|
||||
if (last == rng->first) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
void isr_rand(void *param)
|
||||
{
|
||||
ARG_UNUSED(param);
|
||||
|
||||
if (NRF_RNG->EVENTS_VALRDY) {
|
||||
int ret;
|
||||
|
||||
ret = isr(rng_isr, true);
|
||||
if (ret != -EBUSY) {
|
||||
ret = isr(rng_thr, (ret == -ENOBUFS));
|
||||
}
|
||||
|
||||
NRF_RNG->EVENTS_VALRDY = 0;
|
||||
|
||||
if (ret != -EBUSY) {
|
||||
NRF_RNG->TASKS_STOP = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
101
Living_SDK/kernel/protocols/bluetooth/controller/hal/radio.h
Normal file
101
Living_SDK/kernel/protocols/bluetooth/controller/hal/radio.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _RADIO_H_
|
||||
#define _RADIO_H_
|
||||
|
||||
typedef void (*radio_isr_fp) (void);
|
||||
|
||||
void isr_radio(void);
|
||||
void radio_isr_set(radio_isr_fp fp_radio_isr);
|
||||
|
||||
void radio_setup(void);
|
||||
void radio_reset(void);
|
||||
void radio_phy_set(u8_t phy, u8_t flags);
|
||||
void radio_tx_power_set(u32_t power);
|
||||
void radio_freq_chan_set(u32_t chan);
|
||||
void radio_whiten_iv_set(u32_t iv);
|
||||
void radio_aa_set(u8_t *aa);
|
||||
void radio_pkt_configure(u8_t bits_len, u8_t max_len, u8_t flags);
|
||||
void radio_pkt_rx_set(void *rx_packet);
|
||||
void radio_pkt_tx_set(void *tx_packet);
|
||||
u32_t radio_tx_ready_delay_get(u8_t phy, u8_t flags);
|
||||
u32_t radio_tx_chain_delay_get(u8_t phy, u8_t flags);
|
||||
u32_t radio_rx_ready_delay_get(u8_t phy);
|
||||
u32_t radio_rx_chain_delay_get(u8_t phy, u8_t flags);
|
||||
void radio_rx_enable(void);
|
||||
void radio_tx_enable(void);
|
||||
void radio_disable(void);
|
||||
|
||||
void radio_status_reset(void);
|
||||
u32_t radio_is_ready(void);
|
||||
u32_t radio_is_done(void);
|
||||
u32_t radio_has_disabled(void);
|
||||
u32_t radio_is_idle(void);
|
||||
|
||||
void radio_crc_configure(u32_t polynomial, u32_t iv);
|
||||
u32_t radio_crc_is_valid(void);
|
||||
|
||||
void *radio_pkt_empty_get(void);
|
||||
void *radio_pkt_scratch_get(void);
|
||||
|
||||
void radio_switch_complete_and_rx(u8_t phy_rx);
|
||||
void radio_switch_complete_and_tx(u8_t phy_rx, u8_t flags_rx, u8_t phy_tx,
|
||||
u8_t flags_tx);
|
||||
void radio_switch_complete_and_disable(void);
|
||||
|
||||
void radio_rssi_measure(void);
|
||||
u32_t radio_rssi_get(void);
|
||||
void radio_rssi_status_reset(void);
|
||||
u32_t radio_rssi_is_ready(void);
|
||||
|
||||
void radio_filter_configure(u8_t bitmask_enable, u8_t bitmask_addr_type,
|
||||
u8_t *bdaddr);
|
||||
void radio_filter_disable(void);
|
||||
void radio_filter_status_reset(void);
|
||||
u32_t radio_filter_has_match(void);
|
||||
u32_t radio_filter_match_get(void);
|
||||
|
||||
void radio_bc_configure(u32_t n);
|
||||
void radio_bc_status_reset(void);
|
||||
u32_t radio_bc_has_match(void);
|
||||
|
||||
void radio_tmr_status_reset(void);
|
||||
void radio_tmr_tifs_set(u32_t tifs);
|
||||
u32_t radio_tmr_start(u8_t trx, u32_t ticks_start, u32_t remainder);
|
||||
void radio_tmr_start_us(u8_t trx, u32_t us);
|
||||
u32_t radio_tmr_start_now(u8_t trx);
|
||||
void radio_tmr_stop(void);
|
||||
void radio_tmr_hcto_configure(u32_t hcto);
|
||||
void radio_tmr_aa_capture(void);
|
||||
u32_t radio_tmr_aa_get(void);
|
||||
void radio_tmr_aa_save(u32_t aa);
|
||||
u32_t radio_tmr_aa_restore(void);
|
||||
u32_t radio_tmr_ready_get(void);
|
||||
void radio_tmr_end_capture(void);
|
||||
u32_t radio_tmr_end_get(void);
|
||||
void radio_tmr_sample(void);
|
||||
u32_t radio_tmr_sample_get(void);
|
||||
|
||||
void radio_gpio_pa_setup(void);
|
||||
void radio_gpio_lna_setup(void);
|
||||
void radio_gpio_lna_on(void);
|
||||
void radio_gpio_lna_off(void);
|
||||
void radio_gpio_pa_lna_enable(u32_t trx_us);
|
||||
void radio_gpio_pa_lna_disable(void);
|
||||
|
||||
void *radio_ccm_rx_pkt_set(struct ccm *ccm, u8_t phy, void *pkt);
|
||||
void *radio_ccm_tx_pkt_set(struct ccm *ccm, void *pkt);
|
||||
u32_t radio_ccm_is_done(void);
|
||||
u32_t radio_ccm_mic_is_valid(void);
|
||||
|
||||
void radio_ar_configure(u32_t nirk, void *irk);
|
||||
u32_t radio_ar_match_get(void);
|
||||
void radio_ar_status_reset(void);
|
||||
u32_t radio_ar_has_match(void);
|
||||
|
||||
#endif
|
||||
20
Living_SDK/kernel/protocols/bluetooth/controller/hal/rand.h
Normal file
20
Living_SDK/kernel/protocols/bluetooth/controller/hal/rand.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _RAND_H_
|
||||
#define _RAND_H_
|
||||
|
||||
#include <net/buf.h>
|
||||
|
||||
|
||||
void rand_init(u8_t *context, u8_t context_len, u8_t threshold);
|
||||
void rand_isr_init(u8_t *context, u8_t context_len, u8_t threshold);
|
||||
size_t rand_get(size_t octets, u8_t *rand);
|
||||
size_t rand_isr_get(size_t octets, u8_t *rand);
|
||||
void isr_rand(void *param);
|
||||
|
||||
#endif /* _RAND_H_ */
|
||||
2956
Living_SDK/kernel/protocols/bluetooth/controller/hci/hci.c
Normal file
2956
Living_SDK/kernel/protocols/bluetooth/controller/hci/hci.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,479 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <soc.h>
|
||||
//#include <init.h>
|
||||
#include <device.h>
|
||||
#include <clock_control.h>
|
||||
#include <atomic.h>
|
||||
|
||||
#include <misc/util.h>
|
||||
#include <misc/stack.h>
|
||||
#include <misc/byteorder.h>
|
||||
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/hci.h>
|
||||
#include <drivers/bluetooth/hci_driver.h>
|
||||
|
||||
#ifdef CONFIG_CLOCK_CONTROL_NRF5
|
||||
#include <drivers/clock_control/nrf5_clock_control.h>
|
||||
#endif
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
|
||||
#include "common/log.h"
|
||||
|
||||
#include "util/util.h"
|
||||
#include "hal/ccm.h"
|
||||
#include "hal/radio.h"
|
||||
#include "ll_sw/pdu.h"
|
||||
#include "ll_sw/ctrl.h"
|
||||
#include "ll.h"
|
||||
#include "hci_internal.h"
|
||||
#include "init.h"
|
||||
#include "hal/debug.h"
|
||||
|
||||
#define NODE_RX(_node) CONTAINER_OF(_node, struct radio_pdu_node_rx, \
|
||||
hdr.onion.node)
|
||||
|
||||
static K_SEM_DEFINE(sem_prio_recv, 0, UINT_MAX);
|
||||
|
||||
static K_FIFO_DEFINE(recv_fifo);
|
||||
|
||||
struct k_thread prio_recv_thread_data;
|
||||
static BT_STACK_NOINIT(prio_recv_thread_stack,
|
||||
CONFIG_BT_CTLR_RX_PRIO_STACK_SIZE);
|
||||
struct k_thread recv_thread_data;
|
||||
static BT_STACK_NOINIT(recv_thread_stack, CONFIG_BT_RX_STACK_SIZE);
|
||||
|
||||
#if defined(CONFIG_INIT_STACKS)
|
||||
static u32_t prio_ts;
|
||||
static u32_t rx_ts;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
|
||||
static struct k_poll_signal hbuf_signal =
|
||||
K_POLL_SIGNAL_INITIALIZER(hbuf_signal);
|
||||
static sys_slist_t hbuf_pend;
|
||||
static s32_t hbuf_count;
|
||||
#endif
|
||||
|
||||
static void prio_recv_thread(void *p1, void *p2, void *p3)
|
||||
{
|
||||
while (1) {
|
||||
struct radio_pdu_node_rx *node_rx;
|
||||
u8_t num_cmplt;
|
||||
u16_t handle;
|
||||
|
||||
while ((num_cmplt = radio_rx_get(&node_rx, &handle))) {
|
||||
#if defined(CONFIG_BT_CONN)
|
||||
struct net_buf *buf;
|
||||
|
||||
buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER);
|
||||
hci_num_cmplt_encode(buf, handle, num_cmplt);
|
||||
BT_DBG("Num Complete: 0x%04x:%u", handle, num_cmplt);
|
||||
bt_recv_prio(buf);
|
||||
k_yield();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (node_rx) {
|
||||
|
||||
radio_rx_dequeue();
|
||||
|
||||
BT_DBG("RX node enqueue");
|
||||
k_fifo_put(&recv_fifo, node_rx);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
BT_DBG("sem take...");
|
||||
k_sem_take(&sem_prio_recv, K_FOREVER);
|
||||
BT_DBG("sem taken");
|
||||
|
||||
#if defined(CONFIG_INIT_STACKS)
|
||||
if (k_uptime_get_32() - prio_ts > K_SECONDS(5)) {
|
||||
STACK_ANALYZE("prio recv thread stack",
|
||||
prio_recv_thread_stack);
|
||||
prio_ts = k_uptime_get_32();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static inline struct net_buf *encode_node(struct radio_pdu_node_rx *node_rx,
|
||||
s8_t class)
|
||||
{
|
||||
struct net_buf *buf = NULL;
|
||||
|
||||
/* Check if we need to generate an HCI event or ACL data */
|
||||
switch (class) {
|
||||
case HCI_CLASS_EVT_DISCARDABLE:
|
||||
case HCI_CLASS_EVT_REQUIRED:
|
||||
case HCI_CLASS_EVT_CONNECTION:
|
||||
if (class == HCI_CLASS_EVT_DISCARDABLE) {
|
||||
buf = bt_buf_get_rx(BT_BUF_EVT, K_NO_WAIT);
|
||||
} else {
|
||||
buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER);
|
||||
}
|
||||
if (buf) {
|
||||
hci_evt_encode(node_rx, buf);
|
||||
}
|
||||
break;
|
||||
#if defined(CONFIG_BT_CONN)
|
||||
case HCI_CLASS_ACL_DATA:
|
||||
/* generate ACL data */
|
||||
buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER);
|
||||
hci_acl_encode(node_rx, buf);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
LL_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
radio_rx_fc_set(node_rx->hdr.handle, 0);
|
||||
node_rx->hdr.onion.next = 0;
|
||||
radio_rx_mem_release(&node_rx);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static inline struct net_buf *process_node(struct radio_pdu_node_rx *node_rx)
|
||||
{
|
||||
s8_t class = hci_get_class(node_rx);
|
||||
struct net_buf *buf = NULL;
|
||||
|
||||
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
|
||||
if (hbuf_count != -1) {
|
||||
bool pend = !sys_slist_is_empty(&hbuf_pend);
|
||||
|
||||
/* controller to host flow control enabled */
|
||||
switch (class) {
|
||||
case HCI_CLASS_EVT_DISCARDABLE:
|
||||
case HCI_CLASS_EVT_REQUIRED:
|
||||
break;
|
||||
case HCI_CLASS_EVT_CONNECTION:
|
||||
/* for conn-related events, only pend is relevant */
|
||||
hbuf_count = 1;
|
||||
/* fallthrough */
|
||||
case HCI_CLASS_ACL_DATA:
|
||||
if (pend || !hbuf_count) {
|
||||
sys_slist_append(&hbuf_pend,
|
||||
&node_rx->hdr.onion.node);
|
||||
BT_DBG("FC: Queuing item: %d", class);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LL_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* process regular node from radio */
|
||||
buf = encode_node(node_rx, class);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
|
||||
static inline struct net_buf *process_hbuf(struct radio_pdu_node_rx *n)
|
||||
{
|
||||
/* shadow total count in case of preemption */
|
||||
struct radio_pdu_node_rx *node_rx = NULL;
|
||||
s32_t hbuf_total = hci_hbuf_total;
|
||||
struct net_buf *buf = NULL;
|
||||
sys_snode_t *node = NULL;
|
||||
s8_t class;
|
||||
int reset;
|
||||
|
||||
reset = atomic_test_and_clear_bit(&hci_state_mask, HCI_STATE_BIT_RESET);
|
||||
if (reset) {
|
||||
/* flush queue, no need to free, the LL has already done it */
|
||||
sys_slist_init(&hbuf_pend);
|
||||
}
|
||||
|
||||
if (hbuf_total <= 0) {
|
||||
hbuf_count = -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* available host buffers */
|
||||
hbuf_count = hbuf_total - (hci_hbuf_sent - hci_hbuf_acked);
|
||||
|
||||
/* host acked ACL packets, try to dequeue from hbuf */
|
||||
node = sys_slist_peek_head(&hbuf_pend);
|
||||
if (!node) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return early if this iteration already has a node to process */
|
||||
node_rx = NODE_RX(node);
|
||||
class = hci_get_class(node_rx);
|
||||
if (n) {
|
||||
if (class == HCI_CLASS_EVT_CONNECTION ||
|
||||
(class == HCI_CLASS_ACL_DATA && hbuf_count)) {
|
||||
/* node to process later, schedule an iteration */
|
||||
BT_DBG("FC: signalling");
|
||||
k_poll_signal(&hbuf_signal, 0x0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (class) {
|
||||
case HCI_CLASS_EVT_CONNECTION:
|
||||
BT_DBG("FC: dequeueing event");
|
||||
(void) sys_slist_get(&hbuf_pend);
|
||||
break;
|
||||
case HCI_CLASS_ACL_DATA:
|
||||
if (hbuf_count) {
|
||||
BT_DBG("FC: dequeueing ACL data");
|
||||
(void) sys_slist_get(&hbuf_pend);
|
||||
} else {
|
||||
/* no buffers, HCI will signal */
|
||||
node = NULL;
|
||||
}
|
||||
break;
|
||||
case HCI_CLASS_EVT_DISCARDABLE:
|
||||
case HCI_CLASS_EVT_REQUIRED:
|
||||
default:
|
||||
LL_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (node) {
|
||||
buf = encode_node(node_rx, class);
|
||||
/* Update host buffers after encoding */
|
||||
hbuf_count = hbuf_total - (hci_hbuf_sent - hci_hbuf_acked);
|
||||
/* next node */
|
||||
node = sys_slist_peek_head(&hbuf_pend);
|
||||
if (node) {
|
||||
node_rx = NODE_RX(node);
|
||||
class = hci_get_class(node_rx);
|
||||
|
||||
if (class == HCI_CLASS_EVT_CONNECTION ||
|
||||
(class == HCI_CLASS_ACL_DATA && hbuf_count)) {
|
||||
/* more to process, schedule an
|
||||
* iteration
|
||||
*/
|
||||
BT_DBG("FC: signalling");
|
||||
k_poll_signal(&hbuf_signal, 0x0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void recv_thread(void *p1, void *p2, void *p3)
|
||||
{
|
||||
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
|
||||
/* @todo: check if the events structure really needs to be static */
|
||||
static struct k_poll_event events[2] = {
|
||||
K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_SIGNAL,
|
||||
K_POLL_MODE_NOTIFY_ONLY,
|
||||
&hbuf_signal, 0),
|
||||
K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_FIFO_DATA_AVAILABLE,
|
||||
K_POLL_MODE_NOTIFY_ONLY,
|
||||
&recv_fifo, 0),
|
||||
};
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
struct radio_pdu_node_rx *node_rx = NULL;
|
||||
struct net_buf *buf = NULL;
|
||||
|
||||
BT_DBG("blocking");
|
||||
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
|
||||
int err;
|
||||
|
||||
err = k_poll(events, 2, K_FOREVER);
|
||||
LL_ASSERT(err == 0);
|
||||
if (events[0].state == K_POLL_STATE_SIGNALED) {
|
||||
events[0].signal->signaled = 0;
|
||||
} else if (events[1].state ==
|
||||
K_POLL_STATE_FIFO_DATA_AVAILABLE) {
|
||||
node_rx = k_fifo_get(events[1].fifo, 0);
|
||||
}
|
||||
|
||||
events[0].state = K_POLL_STATE_NOT_READY;
|
||||
events[1].state = K_POLL_STATE_NOT_READY;
|
||||
|
||||
/* process host buffers first if any */
|
||||
buf = process_hbuf(node_rx);
|
||||
|
||||
#else
|
||||
node_rx = k_fifo_get(&recv_fifo, K_FOREVER);
|
||||
#endif
|
||||
BT_DBG("unblocked");
|
||||
|
||||
if (node_rx && !buf) {
|
||||
/* process regular node from radio */
|
||||
buf = process_node(node_rx);
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
if (buf->len) {
|
||||
BT_DBG("Packet in: type:%u len:%u",
|
||||
bt_buf_get_type(buf), buf->len);
|
||||
bt_recv(buf);
|
||||
} else {
|
||||
net_buf_unref(buf);
|
||||
}
|
||||
}
|
||||
|
||||
k_yield();
|
||||
|
||||
#if defined(CONFIG_INIT_STACKS)
|
||||
if (k_uptime_get_32() - rx_ts > K_SECONDS(5)) {
|
||||
STACK_ANALYZE("recv thread stack", recv_thread_stack);
|
||||
rx_ts = k_uptime_get_32();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static int cmd_handle(struct net_buf *buf)
|
||||
{
|
||||
struct net_buf *evt;
|
||||
|
||||
evt = hci_cmd_handle(buf);
|
||||
if (evt) {
|
||||
BT_DBG("Replying with event of %u bytes", evt->len);
|
||||
bt_recv_prio(evt);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CONN)
|
||||
static int acl_handle(struct net_buf *buf)
|
||||
{
|
||||
struct net_buf *evt;
|
||||
int err;
|
||||
|
||||
err = hci_acl_handle(buf, &evt);
|
||||
if (evt) {
|
||||
BT_DBG("Replying with event of %u bytes", evt->len);
|
||||
bt_recv_prio(evt);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_CONN */
|
||||
|
||||
static int hci_driver_send(struct net_buf *buf)
|
||||
{
|
||||
u8_t type;
|
||||
int err;
|
||||
|
||||
BT_DBG("enter");
|
||||
|
||||
if (!buf->len) {
|
||||
BT_ERR("Empty HCI packet");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
type = bt_buf_get_type(buf);
|
||||
switch (type) {
|
||||
#if defined(CONFIG_BT_CONN)
|
||||
case BT_BUF_ACL_OUT:
|
||||
err = acl_handle(buf);
|
||||
break;
|
||||
#endif /* CONFIG_BT_CONN */
|
||||
case BT_BUF_CMD:
|
||||
err = cmd_handle(buf);
|
||||
|
||||
break;
|
||||
default:
|
||||
BT_ERR("Unknown HCI type %u", type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
|
||||
net_buf_unref(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
BT_DBG("exit: %d", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int hci_driver_open(void)
|
||||
{
|
||||
u32_t err;
|
||||
|
||||
DEBUG_INIT();
|
||||
|
||||
k_sem_init(&sem_prio_recv, 0, UINT_MAX);
|
||||
|
||||
err = ll_init(&sem_prio_recv);
|
||||
if (err) {
|
||||
BT_ERR("LL initialization failed: %u", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
|
||||
hci_init(&hbuf_signal);
|
||||
#else
|
||||
hci_init(NULL);
|
||||
#endif
|
||||
|
||||
k_fifo_init(&recv_fifo);
|
||||
|
||||
k_thread_create(&prio_recv_thread_data, prio_recv_thread_stack,
|
||||
K_THREAD_STACK_SIZEOF(prio_recv_thread_stack),
|
||||
prio_recv_thread, NULL, NULL, NULL,
|
||||
K_PRIO_COOP(CONFIG_BT_CTLR_RX_PRIO), 0, K_NO_WAIT);
|
||||
|
||||
k_thread_create(&recv_thread_data, recv_thread_stack,
|
||||
K_THREAD_STACK_SIZEOF(recv_thread_stack),
|
||||
recv_thread, NULL, NULL, NULL,
|
||||
K_PRIO_COOP(CONFIG_BT_RX_PRIO), 0, K_NO_WAIT);
|
||||
|
||||
BT_DBG("Success.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct bt_hci_driver drv = {
|
||||
.name = "Controller",
|
||||
.bus = BT_HCI_DRIVER_BUS_VIRTUAL,
|
||||
.open = hci_driver_open,
|
||||
.send = hci_driver_send,
|
||||
};
|
||||
|
||||
static int _hci_driver_init(struct device *unused)
|
||||
{
|
||||
ARG_UNUSED(unused);
|
||||
|
||||
bt_hci_driver_register(&drv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hci_driver_init()
|
||||
{
|
||||
|
||||
bt_hci_driver_register(&drv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
SYS_INIT(_hci_driver_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _HCI_CONTROLLER_H_
|
||||
#define _HCI_CONTROLLER_H_
|
||||
|
||||
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
|
||||
extern s32_t hci_hbuf_total;
|
||||
extern u32_t hci_hbuf_sent;
|
||||
extern u32_t hci_hbuf_acked;
|
||||
extern atomic_t hci_state_mask;
|
||||
|
||||
#define HCI_STATE_BIT_RESET 0
|
||||
#endif
|
||||
|
||||
#define HCI_CLASS_EVT_REQUIRED 0
|
||||
#define HCI_CLASS_EVT_DISCARDABLE 1
|
||||
#define HCI_CLASS_EVT_CONNECTION 2
|
||||
#define HCI_CLASS_ACL_DATA 3
|
||||
|
||||
#if defined(CONFIG_SOC_FAMILY_NRF5)
|
||||
#define BT_HCI_VS_HW_PLAT BT_HCI_VS_HW_PLAT_NORDIC
|
||||
#if defined(CONFIG_SOC_SERIES_NRF51X)
|
||||
#define BT_HCI_VS_HW_VAR BT_HCI_VS_HW_VAR_NORDIC_NRF51X;
|
||||
#elif defined(CONFIG_SOC_SERIES_NRF52X)
|
||||
#define BT_HCI_VS_HW_VAR BT_HCI_VS_HW_VAR_NORDIC_NRF52X;
|
||||
#endif
|
||||
#else
|
||||
#define BT_HCI_VS_HW_PLAT 0
|
||||
#define BT_HCI_VS_HW_VAR 0
|
||||
#endif /* CONFIG_SOC_FAMILY_NRF5 */
|
||||
|
||||
void hci_init(struct k_poll_signal *signal_host_buf);
|
||||
struct net_buf *hci_cmd_handle(struct net_buf *cmd);
|
||||
void hci_evt_encode(struct radio_pdu_node_rx *node_rx, struct net_buf *buf);
|
||||
s8_t hci_get_class(struct radio_pdu_node_rx *node_rx);
|
||||
#if defined(CONFIG_BT_CONN)
|
||||
int hci_acl_handle(struct net_buf *acl, struct net_buf **evt);
|
||||
void hci_acl_encode(struct radio_pdu_node_rx *node_rx, struct net_buf *buf);
|
||||
void hci_num_cmplt_encode(struct net_buf *buf, u16_t handle, u8_t num);
|
||||
#endif
|
||||
#endif /* _HCI_CONTROLLER_H_ */
|
||||
|
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2014, Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* DESCRIPTION
|
||||
* Platform independent, commonly used macros and defines related to linker
|
||||
* script.
|
||||
*
|
||||
* This file may be included by:
|
||||
* - Linker script files: for linker section declarations
|
||||
* - C files: for external declaration of address or size of linker section
|
||||
* - Assembly files: for external declaration of address or size of linker
|
||||
* section
|
||||
*/
|
||||
|
||||
#ifndef _LINKERDEFS_H
|
||||
#define _LINKERDEFS_H
|
||||
|
||||
#include <toolchain.h>
|
||||
#include <linker/sections.h>
|
||||
#include <misc/util.h>
|
||||
|
||||
/* include platform dependent linker-defs */
|
||||
#ifdef CONFIG_X86
|
||||
/* Nothing yet to include */
|
||||
#elif defined(CONFIG_ARM)
|
||||
/* Nothing yet to include */
|
||||
#elif defined(CONFIG_ARC)
|
||||
/* Nothing yet to include */
|
||||
#elif defined(CONFIG_NIOS2)
|
||||
/* Nothing yet to include */
|
||||
#elif defined(CONFIG_RISCV32)
|
||||
/* Nothing yet to include */
|
||||
#elif defined(CONFIG_XTENSA)
|
||||
/* Nothing yet to include */
|
||||
#else
|
||||
#error Arch not supported.
|
||||
#endif
|
||||
|
||||
#ifdef _LINKER
|
||||
|
||||
|
||||
/*
|
||||
* Space for storing per device busy bitmap. Since we do not know beforehand
|
||||
* the number of devices, we go through the below mechanism to allocate the
|
||||
* required space.
|
||||
*/
|
||||
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
|
||||
#define DEVICE_COUNT \
|
||||
((__device_init_end - __device_init_start) / _DEVICE_STRUCT_SIZE)
|
||||
#define DEV_BUSY_SZ (((DEVICE_COUNT + 31) / 32) * 4)
|
||||
#define DEVICE_BUSY_BITFIELD() \
|
||||
FILL(0x00) ; \
|
||||
__device_busy_start = .; \
|
||||
. = . + DEV_BUSY_SZ; \
|
||||
__device_busy_end = .;
|
||||
#else
|
||||
#define DEVICE_BUSY_BITFIELD()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* generate a symbol to mark the start of the device initialization objects for
|
||||
* the specified level, then link all of those objects (sorted by priority);
|
||||
* ensure the objects aren't discarded if there is no direct reference to them
|
||||
*/
|
||||
|
||||
#define DEVICE_INIT_LEVEL(level) \
|
||||
__device_##level##_start = .; \
|
||||
KEEP(*(SORT(.init_##level[0-9]))); \
|
||||
KEEP(*(SORT(.init_##level[1-9][0-9]))); \
|
||||
|
||||
/*
|
||||
* link in device initialization objects for all devices that are automatically
|
||||
* initialized by the kernel; the objects are sorted in the order they will be
|
||||
* initialized (i.e. ordered by level, sorted by priority within a level)
|
||||
*/
|
||||
|
||||
#define DEVICE_INIT_SECTIONS() \
|
||||
__device_init_start = .; \
|
||||
DEVICE_INIT_LEVEL(PRE_KERNEL_1) \
|
||||
DEVICE_INIT_LEVEL(PRE_KERNEL_2) \
|
||||
DEVICE_INIT_LEVEL(POST_KERNEL) \
|
||||
DEVICE_INIT_LEVEL(APPLICATION) \
|
||||
__device_init_end = .; \
|
||||
DEVICE_BUSY_BITFIELD() \
|
||||
|
||||
|
||||
/* define a section for undefined device initialization levels */
|
||||
#define DEVICE_INIT_UNDEFINED_SECTION() \
|
||||
KEEP(*(SORT(.init_[_A-Z0-9]*))) \
|
||||
|
||||
/*
|
||||
* link in shell initialization objects for all modules that use shell and
|
||||
* their shell commands are automatically initialized by the kernel.
|
||||
*/
|
||||
|
||||
#define SHELL_INIT_SECTIONS() \
|
||||
__shell_cmd_start = .; \
|
||||
KEEP(*(".shell_*")); \
|
||||
__shell_cmd_end = .;
|
||||
|
||||
#ifdef CONFIG_APPLICATION_MEMORY
|
||||
|
||||
#ifndef NUM_KERNEL_OBJECT_FILES
|
||||
#error "Expected NUM_KERNEL_OBJECT_FILES to be defined"
|
||||
#elif NUM_KERNEL_OBJECT_FILES > 19
|
||||
#error "Max supported kernel objects is 19."
|
||||
/* TODO: Using the preprocessor to do this was a mistake. Rewrite to
|
||||
scale better. e.g. by aggregating the kernel objects into two
|
||||
archives like KBuild did.*/
|
||||
#endif
|
||||
|
||||
#define X(i, j) KERNEL_OBJECT_FILE_##i (j)
|
||||
#define Y(i, j) *KERNEL_OBJECT_FILE_##i
|
||||
|
||||
#define KERNEL_INPUT_SECTION(sect) \
|
||||
UTIL_LISTIFY(NUM_KERNEL_OBJECT_FILES, X, sect)
|
||||
#define APP_INPUT_SECTION(sect) \
|
||||
*(EXCLUDE_FILE (UTIL_LISTIFY(NUM_KERNEL_OBJECT_FILES, Y, ~)) sect)
|
||||
|
||||
#else
|
||||
#define KERNEL_INPUT_SECTION(sect) *(sect)
|
||||
#define APP_INPUT_SECTION(sect) *(sect)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_X86 /* LINKER FILES: defines used by linker script */
|
||||
/* Should be moved to linker-common-defs.h */
|
||||
#if defined(CONFIG_XIP)
|
||||
#define ROMABLE_REGION ROM
|
||||
#else
|
||||
#define ROMABLE_REGION RAM
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If image is loaded via kexec Linux system call, then program
|
||||
* headers need to be page aligned.
|
||||
* This can be done by section page aligning.
|
||||
*/
|
||||
#ifdef CONFIG_BOOTLOADER_KEXEC
|
||||
#define KEXEC_PGALIGN_PAD(x) . = ALIGN(x);
|
||||
#else
|
||||
#define KEXEC_PGALIGN_PAD(x)
|
||||
#endif
|
||||
|
||||
#elif defined(_ASMLANGUAGE)
|
||||
|
||||
/* Assembly FILES: declaration defined by the linker script */
|
||||
GDATA(__bss_start)
|
||||
GDATA(__bss_num_words)
|
||||
#ifdef CONFIG_XIP
|
||||
GDATA(__data_rom_start)
|
||||
GDATA(__data_ram_start)
|
||||
GDATA(__data_num_words)
|
||||
#endif
|
||||
|
||||
#else /* ! _ASMLANGUAGE */
|
||||
|
||||
#include <zephyr/types.h>
|
||||
|
||||
#ifdef CONFIG_APPLICATION_MEMORY
|
||||
/* Memory owned by the application. Start and end will be aligned for memory
|
||||
* management/protection hardware for the target architecture.
|
||||
|
||||
* The policy for this memory will be to configure all of it as user thread
|
||||
* accessible. It consists of all non-kernel globals.
|
||||
*/
|
||||
extern char __app_ram_start[];
|
||||
extern char __app_ram_end[];
|
||||
extern char __app_ram_size[];
|
||||
#endif
|
||||
|
||||
/* Memory owned by the kernel. Start and end will be aligned for memory
|
||||
* management/protection hardware for the target architecture..
|
||||
*
|
||||
* Consists of all kernel-side globals, all kernel objects, all thread stacks,
|
||||
* and all currently unused RAM. If CONFIG_APPLICATION_MEMORY is not enabled,
|
||||
* has all globals, not just kernel side.
|
||||
*
|
||||
* Except for the stack of the currently executing thread, none of this memory
|
||||
* is normally accessible to user threads unless specifically granted at
|
||||
* runtime.
|
||||
*/
|
||||
extern char __kernel_ram_start[];
|
||||
extern char __kernel_ram_end[];
|
||||
extern char __kernel_ram_size[];
|
||||
|
||||
/* Used by _bss_zero or arch-specific implementation */
|
||||
extern char __bss_start[];
|
||||
extern char __bss_end[];
|
||||
#ifdef CONFIG_APPLICATION_MEMORY
|
||||
extern char __app_bss_start[];
|
||||
extern char __app_bss_end[];
|
||||
#endif
|
||||
|
||||
/* Used by _data_copy() or arch-specific implementation */
|
||||
#ifdef CONFIG_XIP
|
||||
extern char __data_rom_start[];
|
||||
extern char __data_ram_start[];
|
||||
extern char __data_ram_end[];
|
||||
#ifdef CONFIG_APPLICATION_MEMORY
|
||||
extern char __app_data_rom_start[];
|
||||
extern char __app_data_ram_start[];
|
||||
extern char __app_data_ram_end[];
|
||||
#endif /* CONFIG_APPLICATION_MEMORY */
|
||||
#endif /* CONFIG_XIP */
|
||||
|
||||
/* Includes text and rodata */
|
||||
extern char _image_rom_start[];
|
||||
extern char _image_rom_end[];
|
||||
extern char _image_rom_size[];
|
||||
|
||||
/* datas, bss, noinit */
|
||||
extern char _image_ram_start[];
|
||||
extern char _image_ram_end[];
|
||||
|
||||
extern char _image_text_start[];
|
||||
extern char _image_text_end[];
|
||||
|
||||
extern char _image_rodata_start[];
|
||||
extern char _image_rodata_end[];
|
||||
|
||||
extern char _vector_start[];
|
||||
extern char _vector_end[];
|
||||
|
||||
/* end address of image, used by newlib for the heap */
|
||||
extern char _end[];
|
||||
|
||||
#endif /* ! _ASMLANGUAGE */
|
||||
|
||||
#endif /* _LINKERDEFS_H */
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _LL_H_
|
||||
#define _LL_H_
|
||||
|
||||
int ll_init(struct k_sem *sem_rx);
|
||||
void ll_reset(void);
|
||||
void ll_radio_state_abort(void);
|
||||
u32_t ll_radio_state_is_idle(void);
|
||||
u8_t *ll_addr_get(u8_t addr_type, u8_t *p_bdaddr);
|
||||
void ll_addr_set(u8_t addr_type, u8_t const *const p_bdaddr);
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
||||
u32_t ll_adv_params_set(u8_t handle, u16_t evt_prop, u32_t interval,
|
||||
u8_t adv_type, u8_t own_addr_type,
|
||||
u8_t direct_addr_type, u8_t const *const direct_addr,
|
||||
u8_t chan_map, u8_t filter_policy, u8_t *tx_pwr,
|
||||
u8_t phy_p, u8_t skip, u8_t phy_s, u8_t sid, u8_t sreq);
|
||||
#else /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
u32_t ll_adv_params_set(u16_t interval, u8_t adv_type,
|
||||
u8_t own_addr_type, u8_t direct_addr_type,
|
||||
u8_t const *const direct_addr, u8_t chan_map,
|
||||
u8_t filter_policy);
|
||||
#endif /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
|
||||
void ll_adv_data_set(u8_t len, u8_t const *const p_data);
|
||||
void ll_scan_data_set(u8_t len, u8_t const *const p_data);
|
||||
u32_t ll_adv_enable(u8_t enable);
|
||||
u32_t ll_scan_params_set(u8_t type, u16_t interval, u16_t window,
|
||||
u8_t own_addr_type, u8_t filter_policy);
|
||||
u32_t ll_scan_enable(u8_t enable);
|
||||
|
||||
u32_t ll_wl_size_get(void);
|
||||
u32_t ll_wl_clear(void);
|
||||
u32_t ll_wl_add(bt_addr_le_t *addr);
|
||||
u32_t ll_wl_remove(bt_addr_le_t *addr);
|
||||
|
||||
void ll_rl_id_addr_get(u8_t rl_idx, u8_t *id_addr_type, u8_t *id_addr);
|
||||
u32_t ll_rl_size_get(void);
|
||||
u32_t ll_rl_clear(void);
|
||||
u32_t ll_rl_add(bt_addr_le_t *id_addr, const u8_t pirk[16],
|
||||
const u8_t lirk[16]);
|
||||
u32_t ll_rl_remove(bt_addr_le_t *id_addr);
|
||||
void ll_rl_crpa_set(u8_t id_addr_type, u8_t *id_addr, u8_t rl_idx, u8_t *crpa);
|
||||
u32_t ll_rl_crpa_get(bt_addr_le_t *id_addr, bt_addr_t *crpa);
|
||||
u32_t ll_rl_lrpa_get(bt_addr_le_t *id_addr, bt_addr_t *lrpa);
|
||||
u32_t ll_rl_enable(u8_t enable);
|
||||
void ll_rl_timeout_set(u16_t timeout);
|
||||
u32_t ll_priv_mode_set(bt_addr_le_t *id_addr, u8_t mode);
|
||||
|
||||
u32_t ll_create_connection(u16_t scan_interval, u16_t scan_window,
|
||||
u8_t filter_policy, u8_t peer_addr_type,
|
||||
u8_t *p_peer_addr, u8_t own_addr_type,
|
||||
u16_t interval, u16_t latency,
|
||||
u16_t timeout);
|
||||
u32_t ll_connect_disable(void);
|
||||
u32_t ll_conn_update(u16_t handle, u8_t cmd, u8_t status,
|
||||
u16_t interval, u16_t latency,
|
||||
u16_t timeout);
|
||||
u32_t ll_chm_update(u8_t *chm);
|
||||
u32_t ll_chm_get(u16_t handle, u8_t *chm);
|
||||
u32_t ll_enc_req_send(u16_t handle, u8_t *rand, u8_t *ediv,
|
||||
u8_t *ltk);
|
||||
u32_t ll_start_enc_req_send(u16_t handle, u8_t err_code,
|
||||
u8_t const *const ltk);
|
||||
u32_t ll_feature_req_send(u16_t handle);
|
||||
u32_t ll_version_ind_send(u16_t handle);
|
||||
u32_t ll_terminate_ind_send(u16_t handle, u8_t reason);
|
||||
void ll_timeslice_ticker_id_get(u8_t * const instance_index, u8_t * const user_id);
|
||||
u32_t ll_rssi_get(u16_t handle, u8_t *rssi);
|
||||
u32_t ll_tx_power_level_get(u16_t handle, u8_t type, s8_t *tx_power_level);
|
||||
void ll_tx_power_get(s8_t *min, s8_t *max);
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_LE_PING)
|
||||
u32_t ll_apto_get(u16_t handle, u16_t *apto);
|
||||
u32_t ll_apto_set(u16_t handle, u16_t apto);
|
||||
#endif /* CONFIG_BT_CTLR_LE_PING */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
u32_t ll_length_req_send(u16_t handle, u16_t tx_octets, u16_t tx_time);
|
||||
void ll_length_default_get(u16_t *max_tx_octets, u16_t *max_tx_time);
|
||||
u32_t ll_length_default_set(u16_t max_tx_octets, u16_t max_tx_time);
|
||||
void ll_length_max_get(u16_t *max_tx_octets, u16_t *max_tx_time,
|
||||
u16_t *max_rx_octets, u16_t *max_rx_time);
|
||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
u32_t ll_phy_get(u16_t handle, u8_t *tx, u8_t *rx);
|
||||
u32_t ll_phy_default_set(u8_t tx, u8_t rx);
|
||||
u32_t ll_phy_req_send(u16_t handle, u8_t tx, u8_t flags, u8_t rx);
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
|
||||
#endif /* _LL_H_ */
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2017 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <soc.h>
|
||||
#include "zephyr.h"
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
|
||||
#include "common/log.h"
|
||||
|
||||
#include "hal/cpu.h"
|
||||
#include "hal/rand.h"
|
||||
#include "hal/ecb.h"
|
||||
#include "kport.h"
|
||||
|
||||
|
||||
K_MUTEX_DEFINE(mutex_rand);
|
||||
struct k_mutex mutex_rand;
|
||||
|
||||
|
||||
int bt_rand_c(void *buf, size_t len)
|
||||
{
|
||||
while (len) {
|
||||
k_mutex_lock(&mutex_rand, K_FOREVER);
|
||||
len = rand_get(len, buf);
|
||||
k_mutex_unlock(&mutex_rand);
|
||||
if (len) {
|
||||
cpu_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_encrypt_le_c(const u8_t key[16], const u8_t plaintext[16],
|
||||
u8_t enc_data[16])
|
||||
{
|
||||
BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16));
|
||||
|
||||
ecb_encrypt(key, plaintext, enc_data, NULL);
|
||||
|
||||
BT_DBG("enc_data %s", bt_hex(enc_data, 16));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_encrypt_be_c(const u8_t key[16], const u8_t plaintext[16],
|
||||
u8_t enc_data[16])
|
||||
{
|
||||
BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16));
|
||||
|
||||
ecb_encrypt_be(key, plaintext, enc_data);
|
||||
|
||||
BT_DBG("enc_data %s", bt_hex(enc_data, 16));
|
||||
|
||||
return 0;
|
||||
}
|
||||
11287
Living_SDK/kernel/protocols/bluetooth/controller/ll_sw/ctrl.c
Normal file
11287
Living_SDK/kernel/protocols/bluetooth/controller/ll_sw/ctrl.c
Normal file
File diff suppressed because it is too large
Load diff
384
Living_SDK/kernel/protocols/bluetooth/controller/ll_sw/ctrl.h
Normal file
384
Living_SDK/kernel/protocols/bluetooth/controller/ll_sw/ctrl.h
Normal file
|
|
@ -0,0 +1,384 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _CTRL_H_
|
||||
#define _CTRL_H_
|
||||
|
||||
/*****************************************************************************
|
||||
* Zephyr Kconfig defined
|
||||
****************************************************************************/
|
||||
#ifdef CONFIG_BT_MAX_CONN
|
||||
#define RADIO_CONNECTION_CONTEXT_MAX CONFIG_BT_MAX_CONN
|
||||
#else
|
||||
#define RADIO_CONNECTION_CONTEXT_MAX 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_CTLR_RX_BUFFERS
|
||||
#define RADIO_PACKET_COUNT_RX_MAX CONFIG_BT_CTLR_RX_BUFFERS
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_CTLR_TX_BUFFERS
|
||||
#define RADIO_PACKET_COUNT_TX_MAX CONFIG_BT_CTLR_TX_BUFFERS
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_CTLR_TX_BUFFER_SIZE
|
||||
#define RADIO_PACKET_TX_DATA_SIZE CONFIG_BT_CTLR_TX_BUFFER_SIZE
|
||||
#endif
|
||||
|
||||
#define BIT64(n) (1ULL << (n))
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_LE_ENC)
|
||||
#define RADIO_BLE_FEAT_BIT_ENC BIT64(BT_LE_FEAT_BIT_ENC)
|
||||
#else /* !CONFIG_BT_CTLR_LE_ENC */
|
||||
#define RADIO_BLE_FEAT_BIT_ENC 0
|
||||
#endif /* !CONFIG_BT_CTLR_LE_ENC */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
|
||||
#define RADIO_BLE_FEAT_BIT_CONN_PARAM_REQ BIT64(BT_LE_FEAT_BIT_CONN_PARAM_REQ)
|
||||
#else /* !CONFIG_BT_CTLR_CONN_PARAM_REQ */
|
||||
#define RADIO_BLE_FEAT_BIT_CONN_PARAM_REQ 0
|
||||
#endif /* !CONFIG_BT_CTLR_CONN_PARAM_REQ */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_LE_PING)
|
||||
#define RADIO_BLE_FEAT_BIT_PING BIT64(BT_LE_FEAT_BIT_PING)
|
||||
#else /* !CONFIG_BT_CTLR_LE_PING */
|
||||
#define RADIO_BLE_FEAT_BIT_PING 0
|
||||
#endif /* !CONFIG_BT_CTLR_LE_PING */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH_MAX)
|
||||
#define RADIO_BLE_FEAT_BIT_DLE BIT64(BT_LE_FEAT_BIT_DLE)
|
||||
#define RADIO_LL_LENGTH_OCTETS_RX_MAX CONFIG_BT_CTLR_DATA_LENGTH_MAX
|
||||
#else
|
||||
#define RADIO_BLE_FEAT_BIT_DLE 0
|
||||
#define RADIO_LL_LENGTH_OCTETS_RX_MAX 27
|
||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH_MAX */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
#define RADIO_BLE_FEAT_BIT_PRIVACY BIT64(BT_LE_FEAT_BIT_PRIVACY)
|
||||
#else /* !CONFIG_BT_CTLR_PRIVACY */
|
||||
#define RADIO_BLE_FEAT_BIT_PRIVACY 0
|
||||
#endif /* !CONFIG_BT_CTLR_PRIVACY */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_EXT_SCAN_FP)
|
||||
#define RADIO_BLE_FEAT_BIT_EXT_SCAN BIT64(BT_LE_FEAT_BIT_EXT_SCAN)
|
||||
#else /* !CONFIG_BT_CTLR_EXT_SCAN_FP */
|
||||
#define RADIO_BLE_FEAT_BIT_EXT_SCAN 0
|
||||
#endif /* !CONFIG_BT_CTLR_EXT_SCAN_FP */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_CHAN_SEL_2)
|
||||
#define RADIO_BLE_FEAT_BIT_CHAN_SEL_2 BIT64(BT_LE_FEAT_BIT_CHAN_SEL_ALGO_2)
|
||||
#else /* !CONFIG_BT_CTLR_CHAN_SEL_2 */
|
||||
#define RADIO_BLE_FEAT_BIT_CHAN_SEL_2 0
|
||||
#endif /* !CONFIG_BT_CTLR_CHAN_SEL_2 */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_MIN_USED_CHAN)
|
||||
#define RADIO_BLE_FEAT_BIT_MIN_USED_CHAN \
|
||||
BIT64(BT_LE_FEAT_BIT_MIN_USED_CHAN_PROC)
|
||||
#else /* !CONFIG_BT_CTLR_MIN_USED_CHAN */
|
||||
#define RADIO_BLE_FEAT_BIT_MIN_USED_CHAN 0
|
||||
#endif /* !CONFIG_BT_CTLR_MIN_USED_CHAN */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY_2M)
|
||||
#define RADIO_BLE_FEAT_BIT_PHY_2M BIT64(BT_LE_FEAT_BIT_PHY_2M)
|
||||
#else /* !CONFIG_BT_CTLR_PHY_2M */
|
||||
#define RADIO_BLE_FEAT_BIT_PHY_2M 0
|
||||
#endif /* !CONFIG_BT_CTLR_PHY_2M */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY_CODED)
|
||||
#define RADIO_BLE_FEAT_BIT_PHY_CODED BIT64(BT_LE_FEAT_BIT_PHY_CODED)
|
||||
#else /* !CONFIG_BT_CTLR_PHY_CODED */
|
||||
#define RADIO_BLE_FEAT_BIT_PHY_CODED 0
|
||||
#endif /* !CONFIG_BT_CTLR_PHY_CODED */
|
||||
|
||||
/*****************************************************************************
|
||||
* Timer Resources (Controller defined)
|
||||
****************************************************************************/
|
||||
#define RADIO_TICKER_ID_EVENT 0
|
||||
#define RADIO_TICKER_ID_MARKER_0 1
|
||||
#define RADIO_TICKER_ID_PRE_EMPT 2
|
||||
#define RADIO_TICKER_ID_ADV_STOP 3
|
||||
#define RADIO_TICKER_ID_SCAN_STOP 4
|
||||
#define RADIO_TICKER_ID_ADV 5
|
||||
#define RADIO_TICKER_ID_SCAN 6
|
||||
#define RADIO_TICKER_ID_FIRST_CONNECTION 7
|
||||
|
||||
#define RADIO_TICKER_INSTANCE_ID_RADIO 0
|
||||
#define RADIO_TICKER_INSTANCE_ID_APP 1
|
||||
|
||||
#define RADIO_TICKER_USERS 3
|
||||
|
||||
#define RADIO_TICKER_USER_ID_WORKER MAYFLY_CALL_ID_0
|
||||
#define RADIO_TICKER_USER_ID_JOB MAYFLY_CALL_ID_1
|
||||
#define RADIO_TICKER_USER_ID_APP MAYFLY_CALL_ID_PROGRAM
|
||||
|
||||
#define RADIO_TICKER_USER_WORKER_OPS (7 + 1)
|
||||
#define RADIO_TICKER_USER_JOB_OPS (2 + 1)
|
||||
#define RADIO_TICKER_USER_APP_OPS (1 + 1)
|
||||
#define RADIO_TICKER_USER_OPS (RADIO_TICKER_USER_WORKER_OPS \
|
||||
+ RADIO_TICKER_USER_JOB_OPS \
|
||||
+ RADIO_TICKER_USER_APP_OPS \
|
||||
)
|
||||
|
||||
#define RADIO_TICKER_NODES (RADIO_TICKER_ID_FIRST_CONNECTION \
|
||||
+ RADIO_CONNECTION_CONTEXT_MAX \
|
||||
)
|
||||
|
||||
/*****************************************************************************
|
||||
* Controller Interface Defines
|
||||
****************************************************************************/
|
||||
#define RADIO_BLE_VERSION_NUMBER BT_HCI_VERSION_5_0
|
||||
#if defined(CONFIG_BT_CTLR_COMPANY_ID)
|
||||
#define RADIO_BLE_COMPANY_ID CONFIG_BT_CTLR_COMPANY_ID
|
||||
#else
|
||||
#define RADIO_BLE_COMPANY_ID 0xFFFF
|
||||
#endif
|
||||
#if defined(CONFIG_BT_CTLR_SUBVERSION_NUMBER)
|
||||
#define RADIO_BLE_SUB_VERSION_NUMBER \
|
||||
CONFIG_BT_CTLR_SUBVERSION_NUMBER
|
||||
#else
|
||||
#define RADIO_BLE_SUB_VERSION_NUMBER 0xFFFF
|
||||
#endif
|
||||
|
||||
#define RADIO_BLE_FEAT_BIT_MASK 0x1FFFF
|
||||
#define RADIO_BLE_FEAT_BIT_MASK_VALID 0x1CF2F
|
||||
#define RADIO_BLE_FEAT (RADIO_BLE_FEAT_BIT_ENC | \
|
||||
RADIO_BLE_FEAT_BIT_CONN_PARAM_REQ | \
|
||||
BIT(BT_LE_FEAT_BIT_EXT_REJ_IND) | \
|
||||
BIT(BT_LE_FEAT_BIT_SLAVE_FEAT_REQ) | \
|
||||
RADIO_BLE_FEAT_BIT_PING | \
|
||||
RADIO_BLE_FEAT_BIT_DLE | \
|
||||
RADIO_BLE_FEAT_BIT_PRIVACY | \
|
||||
RADIO_BLE_FEAT_BIT_EXT_SCAN | \
|
||||
RADIO_BLE_FEAT_BIT_PHY_2M | \
|
||||
RADIO_BLE_FEAT_BIT_PHY_CODED | \
|
||||
RADIO_BLE_FEAT_BIT_CHAN_SEL_2 | \
|
||||
RADIO_BLE_FEAT_BIT_MIN_USED_CHAN)
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_WORKER_PRIO)
|
||||
#define RADIO_TICKER_USER_ID_WORKER_PRIO CONFIG_BT_CTLR_WORKER_PRIO
|
||||
#else
|
||||
#define RADIO_TICKER_USER_ID_WORKER_PRIO 0
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_JOB_PRIO)
|
||||
#define RADIO_TICKER_USER_ID_JOB_PRIO CONFIG_BT_CTLR_JOB_PRIO
|
||||
#else
|
||||
#define RADIO_TICKER_USER_ID_JOB_PRIO 0
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* Controller Reference Defines (compile time override-able)
|
||||
****************************************************************************/
|
||||
/* Minimum LL Payload support (Dont change). */
|
||||
#define RADIO_LL_LENGTH_OCTETS_RX_MIN 27
|
||||
|
||||
/* Maximum LL Payload support (27 to 251). */
|
||||
#ifndef RADIO_LL_LENGTH_OCTETS_RX_MAX
|
||||
#define RADIO_LL_LENGTH_OCTETS_RX_MAX 251
|
||||
#endif
|
||||
|
||||
/* Implementation default L2CAP MTU */
|
||||
#ifndef RADIO_L2CAP_MTU_MAX
|
||||
#define RADIO_L2CAP_MTU_MAX (RADIO_LL_LENGTH_OCTETS_RX_MAX - 4)
|
||||
#endif
|
||||
|
||||
/* Maximise L2CAP MTU to LL data PDU size */
|
||||
#if (RADIO_L2CAP_MTU_MAX < (RADIO_LL_LENGTH_OCTETS_RX_MAX - 4))
|
||||
#undef RADIO_L2CAP_MTU_MAX
|
||||
#define RADIO_L2CAP_MTU_MAX (RADIO_LL_LENGTH_OCTETS_RX_MAX - 4)
|
||||
#endif
|
||||
|
||||
/* Maximum LL PDU Receive pool size. */
|
||||
#ifndef RADIO_PACKET_COUNT_RX_MAX
|
||||
#define RADIO_PACKET_COUNT_RX ((RADIO_L2CAP_MTU_MAX + \
|
||||
RADIO_LL_LENGTH_OCTETS_RX_MAX \
|
||||
+ 3) \
|
||||
/ \
|
||||
RADIO_LL_LENGTH_OCTETS_RX_MAX \
|
||||
)
|
||||
#define RADIO_PACKET_COUNT_RX_MAX (RADIO_PACKET_COUNT_RX + \
|
||||
((RADIO_CONNECTION_CONTEXT_MAX - 1) * \
|
||||
(RADIO_PACKET_COUNT_RX - 1)) \
|
||||
)
|
||||
#endif /* RADIO_PACKET_COUNT_RX_MAX */
|
||||
|
||||
/* Maximum LL PDU Transmit pool size and application tx count. */
|
||||
#ifndef RADIO_PACKET_COUNT_TX_MAX
|
||||
#define RADIO_PACKET_COUNT_APP_TX_MAX (RADIO_CONNECTION_CONTEXT_MAX)
|
||||
#define RADIO_PACKET_COUNT_TX_MAX (RADIO_PACKET_COUNT_RX_MAX + \
|
||||
RADIO_PACKET_COUNT_APP_TX_MAX \
|
||||
)
|
||||
#else
|
||||
#define RADIO_PACKET_COUNT_APP_TX_MAX (RADIO_PACKET_COUNT_TX_MAX)
|
||||
#endif
|
||||
|
||||
/* Tx Data Size */
|
||||
#if !defined(RADIO_PACKET_TX_DATA_SIZE) || \
|
||||
(RADIO_PACKET_TX_DATA_SIZE < RADIO_LL_LENGTH_OCTETS_RX_MIN)
|
||||
#define RADIO_PACKET_TX_DATA_SIZE RADIO_LL_LENGTH_OCTETS_RX_MIN
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* Controller Interface Structures
|
||||
****************************************************************************/
|
||||
struct radio_adv_data {
|
||||
u8_t data[DOUBLE_BUFFER_SIZE][PDU_AC_SIZE_MAX];
|
||||
u8_t first;
|
||||
u8_t last;
|
||||
};
|
||||
|
||||
struct radio_pdu_node_tx {
|
||||
void *next;
|
||||
u8_t pdu_data[1];
|
||||
};
|
||||
|
||||
enum radio_pdu_node_rx_type {
|
||||
NODE_RX_TYPE_NONE,
|
||||
NODE_RX_TYPE_DC_PDU,
|
||||
NODE_RX_TYPE_REPORT,
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
||||
NODE_RX_TYPE_EXT_1M_REPORT,
|
||||
NODE_RX_TYPE_EXT_CODED_REPORT,
|
||||
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY)
|
||||
NODE_RX_TYPE_SCAN_REQ,
|
||||
#endif /* CONFIG_BT_CTLR_SCAN_REQ_NOTIFY */
|
||||
|
||||
NODE_RX_TYPE_CONNECTION,
|
||||
NODE_RX_TYPE_TERMINATE,
|
||||
NODE_RX_TYPE_CONN_UPDATE,
|
||||
NODE_RX_TYPE_ENC_REFRESH,
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_LE_PING)
|
||||
NODE_RX_TYPE_APTO,
|
||||
#endif /* CONFIG_BT_CTLR_LE_PING */
|
||||
|
||||
NODE_RX_TYPE_CHAN_SEL_ALGO,
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
NODE_RX_TYPE_PHY_UPDATE,
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_CONN_RSSI)
|
||||
NODE_RX_TYPE_RSSI,
|
||||
#endif /* CONFIG_BT_CTLR_CONN_RSSI */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PROFILE_ISR)
|
||||
NODE_RX_TYPE_PROFILE,
|
||||
#endif /* CONFIG_BT_CTLR_PROFILE_ISR */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ADV_INDICATION)
|
||||
NODE_RX_TYPE_ADV_INDICATION,
|
||||
#endif /* CONFIG_BT_CTLR_ADV_INDICATION */
|
||||
};
|
||||
|
||||
struct radio_le_conn_cmplt {
|
||||
u8_t status;
|
||||
u8_t role;
|
||||
u8_t peer_addr_type;
|
||||
u8_t peer_addr[BDADDR_SIZE];
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
u8_t peer_rpa[BDADDR_SIZE];
|
||||
u8_t own_addr_type;
|
||||
u8_t own_addr[BDADDR_SIZE];
|
||||
#endif /* CONFIG_BT_CTLR_PRIVACY */
|
||||
u16_t interval;
|
||||
u16_t latency;
|
||||
u16_t timeout;
|
||||
u8_t mca;
|
||||
} __packed;
|
||||
|
||||
struct radio_le_conn_update_cmplt {
|
||||
u8_t status;
|
||||
u16_t interval;
|
||||
u16_t latency;
|
||||
u16_t timeout;
|
||||
} __packed;
|
||||
|
||||
struct radio_le_chan_sel_algo {
|
||||
u8_t chan_sel_algo;
|
||||
} __packed;
|
||||
|
||||
struct radio_le_phy_upd_cmplt {
|
||||
u8_t status;
|
||||
u8_t tx;
|
||||
u8_t rx;
|
||||
} __packed;
|
||||
|
||||
struct radio_pdu_node_rx_hdr {
|
||||
union {
|
||||
sys_snode_t node; /* used by slist */
|
||||
void *next; /* used also by k_fifo once pulled */
|
||||
void *link;
|
||||
u8_t packet_release_last;
|
||||
} onion;
|
||||
|
||||
enum radio_pdu_node_rx_type type;
|
||||
u16_t handle;
|
||||
};
|
||||
|
||||
struct radio_pdu_node_rx {
|
||||
struct radio_pdu_node_rx_hdr hdr;
|
||||
u8_t pdu_data[1];
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* Controller Interface Functions
|
||||
****************************************************************************/
|
||||
/* Downstream */
|
||||
u32_t radio_init(void *hf_clock, u8_t sca, u8_t connection_count_max,
|
||||
u8_t rx_count_max, u8_t tx_count_max,
|
||||
u16_t packet_data_octets_max,
|
||||
u16_t packet_tx_data_size, u8_t *mem_radio,
|
||||
u16_t mem_size);
|
||||
struct device *radio_hf_clock_get(void);
|
||||
void radio_ticks_active_to_start_set(u32_t ticks_active_to_start);
|
||||
/* Downstream - Advertiser */
|
||||
struct radio_adv_data *radio_adv_data_get(void);
|
||||
struct radio_adv_data *radio_scan_data_get(void);
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
||||
u32_t radio_adv_enable(u8_t phy_p, u16_t interval, u8_t chan_map,
|
||||
u8_t filter_policy, u8_t rl_idx);
|
||||
#else /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
u32_t radio_adv_enable(u16_t interval, u8_t chan_map, u8_t filter_policy,
|
||||
u8_t rl_idx);
|
||||
#endif /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
|
||||
u32_t radio_adv_disable(void);
|
||||
u32_t radio_adv_is_enabled(void);
|
||||
u32_t radio_adv_filter_pol_get(void);
|
||||
/* Downstream - Scanner */
|
||||
u32_t radio_scan_enable(u8_t type, u8_t init_addr_type, u8_t *init_addr,
|
||||
u16_t interval, u16_t window, u8_t filter_policy,
|
||||
u8_t rpa_gen, u8_t rl_idx);
|
||||
u32_t radio_scan_disable(void);
|
||||
u32_t radio_scan_is_enabled(void);
|
||||
u32_t radio_scan_filter_pol_get(void);
|
||||
|
||||
u32_t radio_connect_enable(u8_t adv_addr_type, u8_t *adv_addr,
|
||||
u16_t interval, u16_t latency,
|
||||
u16_t timeout);
|
||||
/* Upstream */
|
||||
u8_t radio_rx_get(struct radio_pdu_node_rx **radio_pdu_node_rx,
|
||||
u16_t *handle);
|
||||
void radio_rx_dequeue(void);
|
||||
void radio_rx_mem_release(struct radio_pdu_node_rx **radio_pdu_node_rx);
|
||||
u8_t radio_rx_fc_set(u16_t handle, u8_t fc);
|
||||
u8_t radio_rx_fc_get(u16_t *handle);
|
||||
struct radio_pdu_node_tx *radio_tx_mem_acquire(void);
|
||||
void radio_tx_mem_release(struct radio_pdu_node_tx *pdu_data_node_tx);
|
||||
u32_t radio_tx_mem_enqueue(u16_t handle,
|
||||
struct radio_pdu_node_tx *pdu_data_node_tx);
|
||||
/* Callbacks */
|
||||
extern void radio_active_callback(u8_t active);
|
||||
extern void radio_event_callback(void);
|
||||
extern void ll_adv_scan_state_cb(u8_t bm);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
enum llcp {
|
||||
LLCP_NONE,
|
||||
LLCP_CONN_UPD,
|
||||
LLCP_CHAN_MAP,
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_LE_ENC)
|
||||
LLCP_ENCRYPTION,
|
||||
#endif /* CONFIG_BT_CTLR_LE_ENC */
|
||||
|
||||
LLCP_FEATURE_EXCHANGE,
|
||||
LLCP_VERSION_EXCHANGE,
|
||||
/* LLCP_TERMINATE, */
|
||||
LLCP_CONNECTION_PARAM_REQ,
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_LE_PING)
|
||||
LLCP_PING,
|
||||
#endif /* CONFIG_BT_CTLR_LE_PING */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
LLCP_PHY_UPD,
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
};
|
||||
|
||||
|
||||
struct shdr {
|
||||
u32_t ticks_xtal_to_start;
|
||||
u32_t ticks_active_to_start;
|
||||
u32_t ticks_preempt_to_start;
|
||||
u32_t ticks_slot;
|
||||
};
|
||||
|
||||
struct connection {
|
||||
struct shdr hdr;
|
||||
|
||||
u8_t access_addr[4];
|
||||
u8_t crc_init[3];
|
||||
u8_t data_chan_map[5];
|
||||
u8_t chm_update;
|
||||
|
||||
u8_t data_chan_count:6;
|
||||
u8_t data_chan_sel:1;
|
||||
u8_t role:1;
|
||||
|
||||
union {
|
||||
struct {
|
||||
u8_t data_chan_hop;
|
||||
u8_t data_chan_use;
|
||||
};
|
||||
|
||||
u16_t data_chan_id;
|
||||
};
|
||||
|
||||
u16_t handle;
|
||||
u16_t event_counter;
|
||||
u16_t conn_interval;
|
||||
u16_t latency;
|
||||
u16_t latency_prepare;
|
||||
u16_t latency_event;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
u16_t default_tx_octets;
|
||||
u16_t max_tx_octets;
|
||||
u16_t max_rx_octets;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
u16_t default_tx_time;
|
||||
u16_t max_tx_time;
|
||||
u16_t max_rx_time;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
u8_t phy_pref_tx:3;
|
||||
u8_t phy_tx:3;
|
||||
u8_t phy_pref_flags:1;
|
||||
u8_t phy_flags:1;
|
||||
u8_t phy_tx_time:3;
|
||||
|
||||
u8_t phy_pref_rx:3;
|
||||
u8_t phy_rx:3;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
|
||||
u16_t connect_expire;
|
||||
u16_t supervision_reload;
|
||||
u16_t supervision_expire;
|
||||
u16_t procedure_reload;
|
||||
u16_t procedure_expire;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_LE_PING)
|
||||
u16_t appto_reload;
|
||||
u16_t appto_expire;
|
||||
u16_t apto_reload;
|
||||
u16_t apto_expire;
|
||||
#endif /* CONFIG_BT_CTLR_LE_PING */
|
||||
|
||||
union {
|
||||
struct {
|
||||
u8_t reserved:5;
|
||||
u8_t fex_valid:1;
|
||||
} common;
|
||||
|
||||
struct {
|
||||
u8_t terminate_ack:1;
|
||||
u8_t rfu:4;
|
||||
u8_t fex_valid:1;
|
||||
} master;
|
||||
|
||||
struct {
|
||||
u8_t latency_enabled:1;
|
||||
u8_t latency_cancel:1;
|
||||
u8_t sca:3;
|
||||
u8_t fex_valid:1;
|
||||
u32_t window_widening_periodic_us;
|
||||
u32_t window_widening_max_us;
|
||||
u32_t window_widening_prepare_us;
|
||||
u32_t window_widening_event_us;
|
||||
u32_t window_size_prepare_us;
|
||||
u32_t window_size_event_us;
|
||||
u32_t force;
|
||||
u32_t ticks_to_offset;
|
||||
} slave;
|
||||
};
|
||||
|
||||
u8_t llcp_req;
|
||||
u8_t llcp_ack;
|
||||
enum llcp llcp_type;
|
||||
union {
|
||||
struct {
|
||||
enum {
|
||||
LLCP_CUI_STATE_INPROG,
|
||||
LLCP_CUI_STATE_USE,
|
||||
LLCP_CUI_STATE_SELECT
|
||||
} state:2 __packed;
|
||||
u8_t is_internal:1;
|
||||
u16_t interval;
|
||||
u16_t latency;
|
||||
u16_t timeout;
|
||||
u16_t instant;
|
||||
u32_t win_offset_us;
|
||||
u8_t win_size;
|
||||
u16_t *pdu_win_offset;
|
||||
u32_t ticks_anchor;
|
||||
} conn_upd;
|
||||
struct {
|
||||
u8_t initiate;
|
||||
u8_t chm[5];
|
||||
u16_t instant;
|
||||
} chan_map;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
struct {
|
||||
u8_t initiate:1;
|
||||
u8_t cmd:1;
|
||||
u8_t tx:3;
|
||||
u8_t rx:3;
|
||||
u16_t instant;
|
||||
} phy_upd_ind;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
|
||||
struct {
|
||||
u8_t initiate;
|
||||
u8_t error_code;
|
||||
u8_t rand[8];
|
||||
u8_t ediv[2];
|
||||
u8_t ltk[16];
|
||||
u8_t skd[16];
|
||||
} encryption;
|
||||
} llcp;
|
||||
|
||||
u32_t llcp_features;
|
||||
|
||||
struct {
|
||||
u8_t tx:1;
|
||||
u8_t rx:1;
|
||||
u8_t version_number;
|
||||
u16_t company_id;
|
||||
u16_t sub_version_number;
|
||||
} llcp_version;
|
||||
|
||||
struct {
|
||||
u8_t req;
|
||||
u8_t ack;
|
||||
u8_t reason_own;
|
||||
u8_t reason_peer;
|
||||
struct {
|
||||
struct radio_pdu_node_rx_hdr hdr;
|
||||
u8_t reason;
|
||||
} radio_pdu_node_rx;
|
||||
} llcp_terminate;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
|
||||
struct {
|
||||
u8_t req;
|
||||
u8_t ack;
|
||||
enum {
|
||||
LLCP_CPR_STATE_REQ,
|
||||
LLCP_CPR_STATE_RSP,
|
||||
LLCP_CPR_STATE_APP_REQ,
|
||||
LLCP_CPR_STATE_APP_WAIT,
|
||||
LLCP_CPR_STATE_RSP_WAIT,
|
||||
LLCP_CPR_STATE_UPD
|
||||
} state:3 __packed;
|
||||
u8_t cmd:1;
|
||||
u8_t status;
|
||||
u16_t interval;
|
||||
u16_t latency;
|
||||
u16_t timeout;
|
||||
u8_t preferred_periodicity;
|
||||
u16_t reference_conn_event_count;
|
||||
u16_t offset0;
|
||||
u16_t offset1;
|
||||
u16_t offset2;
|
||||
u16_t offset3;
|
||||
u16_t offset4;
|
||||
u16_t offset5;
|
||||
u16_t *pdu_win_offset0;
|
||||
u32_t ticks_ref;
|
||||
u32_t ticks_to_offset_next;
|
||||
} llcp_conn_param;
|
||||
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
struct {
|
||||
u8_t req;
|
||||
u8_t ack;
|
||||
u8_t state:2;
|
||||
#define LLCP_LENGTH_STATE_REQ 0
|
||||
#define LLCP_LENGTH_STATE_ACK_WAIT 1
|
||||
#define LLCP_LENGTH_STATE_RSP_WAIT 2
|
||||
#define LLCP_LENGTH_STATE_RESIZE 3
|
||||
u16_t rx_octets;
|
||||
u16_t tx_octets;
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
u16_t rx_time;
|
||||
u16_t tx_time;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
} llcp_length;
|
||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
struct {
|
||||
u8_t req;
|
||||
u8_t ack;
|
||||
u8_t state:2;
|
||||
#define LLCP_PHY_STATE_REQ 0
|
||||
#define LLCP_PHY_STATE_ACK_WAIT 1
|
||||
#define LLCP_PHY_STATE_RSP_WAIT 2
|
||||
#define LLCP_PHY_STATE_UPD 3
|
||||
u8_t tx:3;
|
||||
u8_t rx:3;
|
||||
u8_t flags:1;
|
||||
u8_t cmd:1;
|
||||
} llcp_phy;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
|
||||
u8_t sn:1;
|
||||
u8_t nesn:1;
|
||||
u8_t pause_rx:1;
|
||||
u8_t pause_tx:1;
|
||||
u8_t enc_rx:1;
|
||||
u8_t enc_tx:1;
|
||||
u8_t refresh:1;
|
||||
u8_t empty:1;
|
||||
|
||||
struct ccm ccm_rx;
|
||||
struct ccm ccm_tx;
|
||||
|
||||
struct radio_pdu_node_tx *pkt_tx_head;
|
||||
struct radio_pdu_node_tx *pkt_tx_ctrl;
|
||||
struct radio_pdu_node_tx *pkt_tx_ctrl_last;
|
||||
struct radio_pdu_node_tx *pkt_tx_data;
|
||||
struct radio_pdu_node_tx *pkt_tx_last;
|
||||
u8_t packet_tx_head_len;
|
||||
u8_t packet_tx_head_offset;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_CONN_RSSI)
|
||||
u8_t rssi_latest;
|
||||
u8_t rssi_reported;
|
||||
u8_t rssi_sample_count;
|
||||
#endif /* CONFIG_BT_CTLR_CONN_RSSI */
|
||||
};
|
||||
#define CONNECTION_T_SIZE MROUND(sizeof(struct connection))
|
||||
|
||||
struct pdu_data_q_tx {
|
||||
u16_t handle;
|
||||
struct radio_pdu_node_tx *node_tx;
|
||||
};
|
||||
|
||||
/* Extra bytes for enqueued rx_node metadata: rssi (always) and resolving
|
||||
* index and directed adv report (with privacy or extended scanner filter
|
||||
* policies enabled).
|
||||
* Note: to simplify the code, both bytes are allocated even if only one of
|
||||
* the options is selected.
|
||||
*/
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY) || defined(CONFIG_BT_CTLR_EXT_SCAN_FP)
|
||||
#define PDU_AC_SIZE_EXTRA 3
|
||||
#else
|
||||
#define PDU_AC_SIZE_EXTRA 1
|
||||
#endif /* CONFIG_BT_CTLR_PRIVACY */
|
||||
|
||||
/* Minimum Rx Data allocation size */
|
||||
#define PACKET_RX_DATA_SIZE_MIN \
|
||||
MROUND(offsetof(struct radio_pdu_node_rx, pdu_data) + \
|
||||
(PDU_AC_SIZE_MAX + PDU_AC_SIZE_EXTRA))
|
||||
|
||||
/* Minimum Tx Ctrl allocation size */
|
||||
#define PACKET_TX_CTRL_SIZE_MIN \
|
||||
MROUND(offsetof(struct radio_pdu_node_tx, pdu_data) + \
|
||||
offsetof(struct pdu_data, payload) + 27)
|
||||
|
||||
/** @todo fix starvation when ctrl rx in radio ISR
|
||||
* for multiple connections needs to tx back to peer.
|
||||
*/
|
||||
#define PACKET_MEM_COUNT_TX_CTRL 2
|
||||
|
||||
#define LL_MEM_CONN (sizeof(struct connection) * RADIO_CONNECTION_CONTEXT_MAX)
|
||||
|
||||
#define LL_MEM_RXQ (sizeof(void *) * (RADIO_PACKET_COUNT_RX_MAX + 4))
|
||||
#define LL_MEM_TXQ (sizeof(struct pdu_data_q_tx) * \
|
||||
(RADIO_PACKET_COUNT_TX_MAX + 2))
|
||||
|
||||
#define LL_MEM_RX_POOL_SZ (MROUND(offsetof(struct radio_pdu_node_rx,\
|
||||
pdu_data) + ((\
|
||||
(PDU_AC_SIZE_MAX + PDU_AC_SIZE_EXTRA) < \
|
||||
(offsetof(struct pdu_data, payload) + \
|
||||
RADIO_LL_LENGTH_OCTETS_RX_MAX)) ? \
|
||||
(offsetof(struct pdu_data, payload) + \
|
||||
RADIO_LL_LENGTH_OCTETS_RX_MAX) \
|
||||
: \
|
||||
(PDU_AC_SIZE_MAX + PDU_AC_SIZE_EXTRA))) * \
|
||||
(RADIO_PACKET_COUNT_RX_MAX + 3))
|
||||
|
||||
#define LL_MEM_RX_LINK_POOL (sizeof(void *) * 2 * ((RADIO_PACKET_COUNT_RX_MAX +\
|
||||
4) + RADIO_CONNECTION_CONTEXT_MAX))
|
||||
|
||||
#define LL_MEM_TX_CTRL_POOL (PACKET_TX_CTRL_SIZE_MIN * PACKET_MEM_COUNT_TX_CTRL)
|
||||
#define LL_MEM_TX_DATA_POOL ((MROUND(offsetof( \
|
||||
struct radio_pdu_node_tx, pdu_data) + \
|
||||
offsetof(struct pdu_data, payload) + \
|
||||
RADIO_PACKET_TX_DATA_SIZE)) \
|
||||
* (RADIO_PACKET_COUNT_TX_MAX + 1))
|
||||
|
||||
#define LL_MEM_TOTAL (LL_MEM_CONN + LL_MEM_RXQ + (LL_MEM_TXQ * 2) + \
|
||||
LL_MEM_RX_POOL_SZ + \
|
||||
LL_MEM_RX_LINK_POOL + LL_MEM_TX_CTRL_POOL + LL_MEM_TX_DATA_POOL)
|
||||
333
Living_SDK/kernel/protocols/bluetooth/controller/ll_sw/ll.c
Normal file
333
Living_SDK/kernel/protocols/bluetooth/controller/ll_sw/ll.c
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2017 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <string.h>
|
||||
#include "errno.h"
|
||||
#include <soc.h>
|
||||
#include <device.h>
|
||||
#include <clock_control.h>
|
||||
#ifdef CONFIG_CLOCK_CONTROL_NRF5
|
||||
#include <drivers/clock_control/nrf5_clock_control.h>
|
||||
#endif
|
||||
#include <bluetooth/hci.h>
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
|
||||
#include "common/log.h"
|
||||
|
||||
#include "hal/cpu.h"
|
||||
#include "hal/cntr.h"
|
||||
#include "hal/rand.h"
|
||||
#include "hal/ccm.h"
|
||||
#include "hal/radio.h"
|
||||
#include "hal/debug.h"
|
||||
|
||||
#include "util/util.h"
|
||||
#include "util/mem.h"
|
||||
#include "util/memq.h"
|
||||
#include "util/mayfly.h"
|
||||
|
||||
#include "ticker/ticker.h"
|
||||
|
||||
#include "pdu.h"
|
||||
#include "ctrl.h"
|
||||
#include "ctrl_internal.h"
|
||||
#include "ll.h"
|
||||
#include "ll_filter.h"
|
||||
#include "irq.h"
|
||||
#include <arch_isr.h>
|
||||
#include "kport.h"
|
||||
|
||||
|
||||
|
||||
/* Global singletons */
|
||||
|
||||
/* memory for storing Random number */
|
||||
#define RAND_THREAD_THRESHOLD 4 /* atleast access address */
|
||||
#define RAND_ISR_THRESHOLD 12 /* atleast encryption div. and iv */
|
||||
static u8_t MALIGN(4) rand_context[4 + RAND_THREAD_THRESHOLD + 1];
|
||||
static u8_t MALIGN(4) rand_isr_context[4 + RAND_ISR_THRESHOLD + 1];
|
||||
|
||||
#if defined(CONFIG_SOC_FLASH_NRF5_RADIO_SYNC)
|
||||
#define FLASH_TICKER_NODES 1 /* No. of tickers reserved for flashing */
|
||||
#define FLASH_TICKER_USER_APP_OPS 1 /* No. of additional ticker operations */
|
||||
#else
|
||||
#define FLASH_TICKER_NODES 0
|
||||
#define FLASH_TICKER_USER_APP_OPS 0
|
||||
#endif
|
||||
|
||||
#define TICKER_NODES (RADIO_TICKER_NODES + FLASH_TICKER_NODES)
|
||||
#define TICKER_USER_APP_OPS (RADIO_TICKER_USER_APP_OPS + \
|
||||
FLASH_TICKER_USER_APP_OPS)
|
||||
#define TICKER_USER_OPS (RADIO_TICKER_USER_OPS + \
|
||||
FLASH_TICKER_USER_APP_OPS)
|
||||
|
||||
/* memory for ticker nodes/instances */
|
||||
static u8_t MALIGN(4) _ticker_nodes[TICKER_NODES][TICKER_NODE_T_SIZE];
|
||||
|
||||
/* memory for users/contexts operating on ticker module */
|
||||
static u8_t MALIGN(4) _ticker_users[MAYFLY_CALLER_COUNT][TICKER_USER_T_SIZE];
|
||||
|
||||
/* memory for user/context simultaneous API operations */
|
||||
static u8_t MALIGN(4) _ticker_user_ops[TICKER_USER_OPS][TICKER_USER_OP_T_SIZE];
|
||||
|
||||
/* memory for Bluetooth Controller (buffers, queues etc.) */
|
||||
static u8_t MALIGN(4) _radio[LL_MEM_TOTAL];
|
||||
|
||||
static struct k_sem *sem_recv;
|
||||
|
||||
static struct {
|
||||
u8_t pub_addr[BDADDR_SIZE];
|
||||
u8_t rnd_addr[BDADDR_SIZE];
|
||||
} _ll_context;
|
||||
|
||||
void mayfly_enable_cb(u8_t caller_id, u8_t callee_id, u8_t enable)
|
||||
{
|
||||
(void)caller_id;
|
||||
|
||||
LL_ASSERT(callee_id == MAYFLY_CALL_ID_1);
|
||||
|
||||
if (enable) {
|
||||
irq_enable(SWI4_IRQn);
|
||||
} else {
|
||||
irq_disable(SWI4_IRQn);
|
||||
}
|
||||
}
|
||||
|
||||
u32_t mayfly_is_enabled(u8_t caller_id, u8_t callee_id)
|
||||
{
|
||||
(void)caller_id;
|
||||
|
||||
if (callee_id == MAYFLY_CALL_ID_0) {
|
||||
return irq_is_enabled(RTC0_IRQn);
|
||||
} else if (callee_id == MAYFLY_CALL_ID_1) {
|
||||
return irq_is_enabled(SWI4_IRQn);
|
||||
}
|
||||
|
||||
LL_ASSERT(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32_t mayfly_prio_is_equal(u8_t caller_id, u8_t callee_id)
|
||||
{
|
||||
#if (RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
|
||||
return (caller_id == callee_id) ||
|
||||
((caller_id == MAYFLY_CALL_ID_0) &&
|
||||
(callee_id == MAYFLY_CALL_ID_1)) ||
|
||||
((caller_id == MAYFLY_CALL_ID_1) &&
|
||||
(callee_id == MAYFLY_CALL_ID_0));
|
||||
#else
|
||||
return caller_id == callee_id;
|
||||
#endif
|
||||
}
|
||||
|
||||
void mayfly_pend(u8_t caller_id, u8_t callee_id)
|
||||
{
|
||||
(void)caller_id;
|
||||
|
||||
switch (callee_id) {
|
||||
case MAYFLY_CALL_ID_0:
|
||||
NVIC_SetPendingIRQ(RTC0_IRQn);
|
||||
break;
|
||||
|
||||
case MAYFLY_CALL_ID_1:
|
||||
NVIC_SetPendingIRQ(SWI4_IRQn);
|
||||
break;
|
||||
|
||||
case MAYFLY_CALL_ID_PROGRAM:
|
||||
default:
|
||||
LL_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void radio_active_callback(u8_t active)
|
||||
{
|
||||
}
|
||||
|
||||
void radio_event_callback(void)
|
||||
{
|
||||
k_sem_give(sem_recv);
|
||||
}
|
||||
/*
|
||||
ISR_DIRECT_DECLARE(radio_nrf5_isr)
|
||||
{
|
||||
isr_radio();
|
||||
|
||||
ISR_DIRECT_PM();
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
void RADIO_IRQHandler(void *arg)
|
||||
{
|
||||
krhino_intrpt_enter();
|
||||
isr_radio();
|
||||
|
||||
krhino_intrpt_exit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RTC0_IRQHandler(void *arg)
|
||||
{
|
||||
u32_t compare0, compare1;
|
||||
|
||||
krhino_intrpt_enter();
|
||||
|
||||
/* store interested events */
|
||||
compare0 = NRF_RTC0->EVENTS_COMPARE[0];
|
||||
compare1 = NRF_RTC0->EVENTS_COMPARE[1];
|
||||
|
||||
/* On compare0 run ticker worker instance0 */
|
||||
if (compare0) {
|
||||
NRF_RTC0->EVENTS_COMPARE[0] = 0;
|
||||
|
||||
ticker_trigger(0);
|
||||
}
|
||||
|
||||
/* On compare1 run ticker worker instance1 */
|
||||
if (compare1) {
|
||||
NRF_RTC0->EVENTS_COMPARE[1] = 0;
|
||||
|
||||
ticker_trigger(1);
|
||||
}
|
||||
|
||||
mayfly_run(MAYFLY_CALL_ID_0);
|
||||
|
||||
krhino_intrpt_exit();
|
||||
}
|
||||
|
||||
void RNG_IRQHandler(void *arg)
|
||||
{
|
||||
krhino_intrpt_enter();
|
||||
|
||||
isr_rand(arg);
|
||||
|
||||
krhino_intrpt_exit();
|
||||
}
|
||||
|
||||
void SWI4_EGU4_IRQHandler(void *arg)
|
||||
{
|
||||
krhino_intrpt_enter();
|
||||
|
||||
mayfly_run(MAYFLY_CALL_ID_1);
|
||||
|
||||
krhino_intrpt_exit();
|
||||
}
|
||||
|
||||
int ll_init(struct k_sem *sem_rx)
|
||||
{
|
||||
struct device *clk_k32;
|
||||
struct device *clk_m16;
|
||||
u32_t err;
|
||||
|
||||
sem_recv = sem_rx;
|
||||
extern struct k_mutex mutex_rand;
|
||||
k_mutex_init(&mutex_rand);
|
||||
|
||||
/* TODO: bind and use RNG driver */
|
||||
rand_init(rand_context, sizeof(rand_context), RAND_THREAD_THRESHOLD);
|
||||
rand_isr_init(rand_isr_context, sizeof(rand_isr_context),
|
||||
RAND_ISR_THRESHOLD);
|
||||
|
||||
clk_k32 = device_get_binding(CONFIG_CLOCK_CONTROL_NRF5_K32SRC_DRV_NAME);
|
||||
if (!clk_k32) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
clock_control_on(clk_k32, (void *)CLOCK_CONTROL_NRF5_K32SRC);
|
||||
|
||||
/* TODO: bind and use counter driver */
|
||||
cntr_init();
|
||||
|
||||
mayfly_init();
|
||||
|
||||
_ticker_users[MAYFLY_CALL_ID_0][0] = RADIO_TICKER_USER_WORKER_OPS;
|
||||
_ticker_users[MAYFLY_CALL_ID_1][0] = RADIO_TICKER_USER_JOB_OPS;
|
||||
_ticker_users[MAYFLY_CALL_ID_2][0] = 0;
|
||||
_ticker_users[MAYFLY_CALL_ID_PROGRAM][0] = TICKER_USER_APP_OPS;
|
||||
|
||||
ticker_init(RADIO_TICKER_INSTANCE_ID_RADIO, TICKER_NODES,
|
||||
&_ticker_nodes[0], MAYFLY_CALLER_COUNT, &_ticker_users[0],
|
||||
TICKER_USER_OPS, &_ticker_user_ops[0]);
|
||||
|
||||
clk_m16 = device_get_binding(CONFIG_CLOCK_CONTROL_NRF5_M16SRC_DRV_NAME);
|
||||
if (!clk_m16) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
err = radio_init(clk_m16, CLOCK_CONTROL_NRF5_K32SRC_ACCURACY,
|
||||
RADIO_CONNECTION_CONTEXT_MAX,
|
||||
RADIO_PACKET_COUNT_RX_MAX,
|
||||
RADIO_PACKET_COUNT_TX_MAX,
|
||||
RADIO_LL_LENGTH_OCTETS_RX_MAX,
|
||||
RADIO_PACKET_TX_DATA_SIZE, &_radio[0], sizeof(_radio));
|
||||
if (err) {
|
||||
BT_ERR("Required RAM size: %d, supplied: %u.", err,
|
||||
sizeof(_radio));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ll_filter_reset(true);
|
||||
|
||||
IRQ_DIRECT_CONNECT(NRF5_IRQ_RADIO_IRQn, CONFIG_BT_CTLR_WORKER_PRIO,
|
||||
RADIO_IRQHandler, 0);
|
||||
IRQ_CONNECT(NRF5_IRQ_RTC0_IRQn, CONFIG_BT_CTLR_WORKER_PRIO,
|
||||
RTC0_IRQHandler, NULL, 0);
|
||||
IRQ_CONNECT(NRF5_IRQ_SWI4_IRQn, CONFIG_BT_CTLR_JOB_PRIO, SWI4_EGU4_IRQHandler,
|
||||
NULL, 0);
|
||||
IRQ_CONNECT(NRF5_IRQ_RNG_IRQn, 1, RNG_IRQHandler, NULL, 0);
|
||||
|
||||
irq_enable(NRF5_IRQ_RADIO_IRQn);
|
||||
|
||||
irq_enable(NRF5_IRQ_RTC0_IRQn);
|
||||
|
||||
irq_enable(NRF5_IRQ_SWI4_IRQn);
|
||||
|
||||
irq_enable(NRF5_IRQ_RNG_IRQn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ll_timeslice_ticker_id_get(u8_t * const instance_index, u8_t * const user_id)
|
||||
{
|
||||
*user_id = (TICKER_NODES - FLASH_TICKER_NODES); /* The last index in the total tickers */
|
||||
*instance_index = RADIO_TICKER_INSTANCE_ID_RADIO;
|
||||
}
|
||||
|
||||
u8_t *ll_addr_get(u8_t addr_type, u8_t *bdaddr)
|
||||
{
|
||||
if (addr_type > 1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (addr_type) {
|
||||
if (bdaddr) {
|
||||
memcpy(bdaddr, _ll_context.rnd_addr, BDADDR_SIZE);
|
||||
}
|
||||
|
||||
return _ll_context.rnd_addr;
|
||||
}
|
||||
|
||||
if (bdaddr) {
|
||||
memcpy(bdaddr, _ll_context.pub_addr, BDADDR_SIZE);
|
||||
}
|
||||
|
||||
return _ll_context.pub_addr;
|
||||
}
|
||||
|
||||
void ll_addr_set(u8_t addr_type, u8_t const *const bdaddr)
|
||||
{
|
||||
if (addr_type) {
|
||||
memcpy(_ll_context.rnd_addr, bdaddr, BDADDR_SIZE);
|
||||
} else {
|
||||
memcpy(_ll_context.pub_addr, bdaddr, BDADDR_SIZE);
|
||||
}
|
||||
}
|
||||
425
Living_SDK/kernel/protocols/bluetooth/controller/ll_sw/ll_adv.c
Normal file
425
Living_SDK/kernel/protocols/bluetooth/controller/ll_sw/ll_adv.c
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2017 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <bluetooth/hci.h>
|
||||
|
||||
#include "util/util.h"
|
||||
|
||||
#include "pdu.h"
|
||||
#include "ctrl.h"
|
||||
#include "ll.h"
|
||||
|
||||
#include "hal/debug.h"
|
||||
|
||||
#include "ll_filter.h"
|
||||
#include "ll_adv.h"
|
||||
|
||||
static struct ll_adv_set ll_adv;
|
||||
|
||||
struct ll_adv_set *ll_adv_set_get(void)
|
||||
{
|
||||
return &ll_adv;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
||||
u32_t ll_adv_params_set(u8_t handle, u16_t evt_prop, u32_t interval,
|
||||
u8_t adv_type, u8_t own_addr_type,
|
||||
u8_t direct_addr_type, u8_t const *const direct_addr,
|
||||
u8_t chan_map, u8_t filter_policy, u8_t *tx_pwr,
|
||||
u8_t phy_p, u8_t skip, u8_t phy_s, u8_t sid, u8_t sreq)
|
||||
{
|
||||
u8_t const pdu_adv_type[] = {PDU_ADV_TYPE_ADV_IND,
|
||||
PDU_ADV_TYPE_DIRECT_IND,
|
||||
PDU_ADV_TYPE_SCAN_IND,
|
||||
PDU_ADV_TYPE_NONCONN_IND,
|
||||
PDU_ADV_TYPE_DIRECT_IND,
|
||||
PDU_ADV_TYPE_EXT_IND};
|
||||
#else /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
u32_t ll_adv_params_set(u16_t interval, u8_t adv_type,
|
||||
u8_t own_addr_type, u8_t direct_addr_type,
|
||||
u8_t const *const direct_addr, u8_t chan_map,
|
||||
u8_t filter_policy)
|
||||
{
|
||||
u8_t const pdu_adv_type[] = {PDU_ADV_TYPE_ADV_IND,
|
||||
PDU_ADV_TYPE_DIRECT_IND,
|
||||
PDU_ADV_TYPE_SCAN_IND,
|
||||
PDU_ADV_TYPE_NONCONN_IND,
|
||||
PDU_ADV_TYPE_DIRECT_IND};
|
||||
#endif /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
|
||||
struct radio_adv_data *radio_adv_data;
|
||||
struct pdu_adv *pdu;
|
||||
|
||||
if (radio_adv_is_enabled()) {
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
||||
/* TODO: check and fail (0x12, invalid HCI cmd param) if invalid
|
||||
* evt_prop bits.
|
||||
*/
|
||||
|
||||
ll_adv.phy_p = BIT(0);
|
||||
|
||||
/* extended */
|
||||
if (adv_type > 0x04) {
|
||||
/* legacy */
|
||||
if (evt_prop & BIT(4)) {
|
||||
u8_t const leg_adv_type[] = { 0x03, 0x04, 0x02, 0x00};
|
||||
|
||||
adv_type = leg_adv_type[evt_prop & 0x03];
|
||||
|
||||
/* high duty cycle directed */
|
||||
if (evt_prop & BIT(3)) {
|
||||
adv_type = 0x01;
|
||||
}
|
||||
} else {
|
||||
/* - Connectable and scannable not allowed;
|
||||
* - High duty cycle directed connectable not allowed
|
||||
*/
|
||||
if (((evt_prop & 0x03) == 0x03) ||
|
||||
((evt_prop & 0x0C) == 0x0C)) {
|
||||
return 0x12; /* invalid HCI cmd param */
|
||||
}
|
||||
|
||||
adv_type = 0x05; /* PDU_ADV_TYPE_EXT_IND */
|
||||
|
||||
ll_adv.phy_p = phy_p;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
||||
|
||||
/* remember params so that set adv/scan data and adv enable
|
||||
* interface can correctly update adv/scan data in the
|
||||
* double buffer between caller and controller context.
|
||||
*/
|
||||
/* Set interval for Undirected or Low Duty Cycle Directed Advertising */
|
||||
if (adv_type != 0x01) {
|
||||
ll_adv.interval = interval;
|
||||
} else {
|
||||
ll_adv.interval = 0;
|
||||
}
|
||||
ll_adv.chan_map = chan_map;
|
||||
ll_adv.filter_policy = filter_policy;
|
||||
|
||||
/* update the "current" primary adv data */
|
||||
radio_adv_data = radio_adv_data_get();
|
||||
pdu = (struct pdu_adv *)&radio_adv_data->data[radio_adv_data->last][0];
|
||||
pdu->type = pdu_adv_type[adv_type];
|
||||
pdu->rfu = 0;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_CHAN_SEL_2) &&
|
||||
((pdu->type == PDU_ADV_TYPE_ADV_IND) ||
|
||||
(pdu->type == PDU_ADV_TYPE_DIRECT_IND))) {
|
||||
pdu->chan_sel = 1;
|
||||
} else {
|
||||
pdu->chan_sel = 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
ll_adv.own_addr_type = own_addr_type;
|
||||
if (ll_adv.own_addr_type == BT_ADDR_LE_PUBLIC_ID ||
|
||||
ll_adv.own_addr_type == BT_ADDR_LE_RANDOM_ID) {
|
||||
ll_adv.id_addr_type = direct_addr_type;
|
||||
memcpy(&ll_adv.id_addr, direct_addr, BDADDR_SIZE);
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_PRIVACY */
|
||||
pdu->tx_addr = own_addr_type & 0x1;
|
||||
pdu->rx_addr = 0;
|
||||
if (pdu->type == PDU_ADV_TYPE_DIRECT_IND) {
|
||||
pdu->rx_addr = direct_addr_type;
|
||||
memcpy(&pdu->payload.direct_ind.tgt_addr[0], direct_addr,
|
||||
BDADDR_SIZE);
|
||||
pdu->len = sizeof(struct pdu_adv_payload_direct_ind);
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
||||
} else if (pdu->type == PDU_ADV_TYPE_EXT_IND) {
|
||||
struct pdu_adv_payload_com_ext_adv *p;
|
||||
struct ext_adv_hdr *h;
|
||||
u8_t *ptr;
|
||||
u8_t len;
|
||||
|
||||
p = (void *)&pdu->payload.adv_ext_ind;
|
||||
h = (void *)p->ext_hdr_adi_adv_data;
|
||||
ptr = (u8_t *)h + sizeof(*h);
|
||||
|
||||
/* No ACAD and no AdvData */
|
||||
p->ext_hdr_len = 0;
|
||||
p->adv_mode = evt_prop & 0x03;
|
||||
|
||||
/* Zero-init header flags */
|
||||
*(u8_t *)h = 0;
|
||||
|
||||
/* AdvA flag */
|
||||
if (!(evt_prop & BIT(5)) && !p->adv_mode && (phy_p != BIT(2))) {
|
||||
/* TODO: optional on 1M */
|
||||
h->adv_addr = 1;
|
||||
|
||||
/* NOTE: AdvA is filled at enable */
|
||||
ptr += BDADDR_SIZE;
|
||||
}
|
||||
|
||||
/* TODO: TargetA flag */
|
||||
|
||||
/* TODO: ADI flag */
|
||||
|
||||
/* TODO: AuxPtr flag */
|
||||
|
||||
/* TODO: SyncInfo flag */
|
||||
|
||||
/* Tx Power flag */
|
||||
if (evt_prop & BIT(6)) {
|
||||
h->tx_pwr = 1;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
/* Calc primary PDU len */
|
||||
len = ptr - (u8_t *)p;
|
||||
if (len > (offsetof(struct pdu_adv_payload_com_ext_adv,
|
||||
ext_hdr_adi_adv_data) + sizeof(*h))) {
|
||||
p->ext_hdr_len = len -
|
||||
offsetof(struct pdu_adv_payload_com_ext_adv,
|
||||
ext_hdr_adi_adv_data);
|
||||
pdu->len = len;
|
||||
} else {
|
||||
pdu->len = offsetof(struct pdu_adv_payload_com_ext_adv,
|
||||
ext_hdr_adi_adv_data);
|
||||
}
|
||||
|
||||
/* Start filling primary PDU payload based on flags */
|
||||
|
||||
/* TODO: AdvData */
|
||||
|
||||
/* TODO: ACAD */
|
||||
|
||||
/* Tx Power */
|
||||
if (h->tx_pwr) {
|
||||
u8_t _tx_pwr;
|
||||
|
||||
_tx_pwr = 0;
|
||||
if (tx_pwr) {
|
||||
if (*tx_pwr != 0x7F) {
|
||||
_tx_pwr = *tx_pwr;
|
||||
} else {
|
||||
*tx_pwr = _tx_pwr;
|
||||
}
|
||||
}
|
||||
|
||||
ptr--;
|
||||
*ptr = _tx_pwr;
|
||||
}
|
||||
|
||||
/* TODO: SyncInfo */
|
||||
|
||||
/* TODO: AuxPtr */
|
||||
|
||||
/* TODO: ADI */
|
||||
|
||||
/* NOTE: TargetA, filled at enable and RPA timeout */
|
||||
|
||||
/* NOTE: AdvA, filled at enable and RPA timeout */
|
||||
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
||||
|
||||
} else if (pdu->len == 0) {
|
||||
pdu->len = BDADDR_SIZE;
|
||||
}
|
||||
|
||||
/* update the current scan data */
|
||||
radio_adv_data = radio_scan_data_get();
|
||||
pdu = (struct pdu_adv *)&radio_adv_data->data[radio_adv_data->last][0];
|
||||
pdu->type = PDU_ADV_TYPE_SCAN_RSP;
|
||||
pdu->rfu = 0;
|
||||
pdu->chan_sel = 0;
|
||||
pdu->tx_addr = own_addr_type & 0x1;
|
||||
pdu->rx_addr = 0;
|
||||
if (pdu->len == 0) {
|
||||
pdu->len = BDADDR_SIZE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ll_adv_data_set(u8_t len, u8_t const *const data)
|
||||
{
|
||||
struct radio_adv_data *radio_adv_data;
|
||||
struct pdu_adv *prev;
|
||||
struct pdu_adv *pdu;
|
||||
u8_t last;
|
||||
|
||||
/* Dont update data if directed or extended advertising. */
|
||||
radio_adv_data = radio_adv_data_get();
|
||||
prev = (struct pdu_adv *)&radio_adv_data->data[radio_adv_data->last][0];
|
||||
if ((prev->type == PDU_ADV_TYPE_DIRECT_IND) ||
|
||||
(IS_ENABLED(CONFIG_BT_CTLR_ADV_EXT) &&
|
||||
(prev->type == PDU_ADV_TYPE_EXT_IND))) {
|
||||
/* TODO: remember data, to be used if type is changed using
|
||||
* parameter set function ll_adv_params_set afterwards.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/* use the last index in double buffer, */
|
||||
if (radio_adv_data->first == radio_adv_data->last) {
|
||||
last = radio_adv_data->last + 1;
|
||||
if (last == DOUBLE_BUFFER_SIZE) {
|
||||
last = 0;
|
||||
}
|
||||
} else {
|
||||
last = radio_adv_data->last;
|
||||
}
|
||||
|
||||
/* update adv pdu fields. */
|
||||
pdu = (struct pdu_adv *)&radio_adv_data->data[last][0];
|
||||
pdu->type = prev->type;
|
||||
pdu->rfu = 0;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_CHAN_SEL_2)) {
|
||||
pdu->chan_sel = prev->chan_sel;
|
||||
} else {
|
||||
pdu->chan_sel = 0;
|
||||
}
|
||||
|
||||
pdu->tx_addr = prev->tx_addr;
|
||||
pdu->rx_addr = prev->rx_addr;
|
||||
memcpy(&pdu->payload.adv_ind.addr[0],
|
||||
&prev->payload.adv_ind.addr[0], BDADDR_SIZE);
|
||||
memcpy(&pdu->payload.adv_ind.data[0], data, len);
|
||||
pdu->len = BDADDR_SIZE + len;
|
||||
|
||||
/* commit the update so controller picks it. */
|
||||
radio_adv_data->last = last;
|
||||
}
|
||||
|
||||
void ll_scan_data_set(u8_t len, u8_t const *const data)
|
||||
{
|
||||
struct radio_adv_data *radio_scan_data;
|
||||
struct pdu_adv *prev;
|
||||
struct pdu_adv *pdu;
|
||||
u8_t last;
|
||||
|
||||
/* use the last index in double buffer, */
|
||||
radio_scan_data = radio_scan_data_get();
|
||||
if (radio_scan_data->first == radio_scan_data->last) {
|
||||
last = radio_scan_data->last + 1;
|
||||
if (last == DOUBLE_BUFFER_SIZE) {
|
||||
last = 0;
|
||||
}
|
||||
} else {
|
||||
last = radio_scan_data->last;
|
||||
}
|
||||
|
||||
/* update scan pdu fields. */
|
||||
prev = (struct pdu_adv *)
|
||||
&radio_scan_data->data[radio_scan_data->last][0];
|
||||
pdu = (struct pdu_adv *)&radio_scan_data->data[last][0];
|
||||
pdu->type = PDU_ADV_TYPE_SCAN_RSP;
|
||||
pdu->rfu = 0;
|
||||
pdu->chan_sel = 0;
|
||||
pdu->tx_addr = prev->tx_addr;
|
||||
pdu->rx_addr = 0;
|
||||
pdu->len = BDADDR_SIZE + len;
|
||||
memcpy(&pdu->payload.scan_rsp.addr[0],
|
||||
&prev->payload.scan_rsp.addr[0], BDADDR_SIZE);
|
||||
memcpy(&pdu->payload.scan_rsp.data[0], data, len);
|
||||
|
||||
/* commit the update so controller picks it. */
|
||||
radio_scan_data->last = last;
|
||||
}
|
||||
|
||||
u32_t ll_adv_enable(u8_t enable)
|
||||
{
|
||||
struct radio_adv_data *radio_scan_data;
|
||||
struct radio_adv_data *radio_adv_data;
|
||||
u8_t rl_idx = FILTER_IDX_NONE;
|
||||
struct pdu_adv *pdu_scan;
|
||||
struct pdu_adv *pdu_adv;
|
||||
u32_t status;
|
||||
|
||||
if (!enable) {
|
||||
return radio_adv_disable();
|
||||
} else if (radio_adv_is_enabled()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: move the addr remembered into controller
|
||||
* this way when implementing Privacy 1.2, generated
|
||||
* new resolvable addresses can be used instantly.
|
||||
*/
|
||||
|
||||
/* remember addr to use and also update the addr in
|
||||
* both adv and scan response PDUs.
|
||||
*/
|
||||
radio_adv_data = radio_adv_data_get();
|
||||
radio_scan_data = radio_scan_data_get();
|
||||
pdu_adv = (struct pdu_adv *)&radio_adv_data->data
|
||||
[radio_adv_data->last][0];
|
||||
pdu_scan = (struct pdu_adv *)&radio_scan_data->data
|
||||
[radio_scan_data->last][0];
|
||||
|
||||
if (0) {
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
||||
} else if (pdu_adv->type == PDU_ADV_TYPE_EXT_IND) {
|
||||
struct pdu_adv_payload_com_ext_adv *p;
|
||||
struct ext_adv_hdr *h;
|
||||
u8_t *ptr;
|
||||
|
||||
p = (void *)&pdu_adv->payload.adv_ext_ind;
|
||||
h = (void *)p->ext_hdr_adi_adv_data;
|
||||
ptr = (u8_t *)h + sizeof(*h);
|
||||
|
||||
/* AdvA, fill here at enable */
|
||||
if (h->adv_addr) {
|
||||
memcpy(ptr, ll_addr_get(pdu_adv->tx_addr, NULL),
|
||||
BDADDR_SIZE);
|
||||
}
|
||||
|
||||
/* TODO: TargetA, fill here at enable */
|
||||
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
||||
} else {
|
||||
bool priv = false;
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
/* Prepare whitelist and optionally resolving list */
|
||||
ll_filters_adv_update(ll_adv.filter_policy);
|
||||
|
||||
if (ll_adv.own_addr_type == BT_ADDR_LE_PUBLIC_ID ||
|
||||
ll_adv.own_addr_type == BT_ADDR_LE_RANDOM_ID) {
|
||||
/* Look up the resolving list */
|
||||
rl_idx = ll_rl_find(ll_adv.id_addr_type,
|
||||
ll_adv.id_addr, NULL);
|
||||
|
||||
if (rl_idx != FILTER_IDX_NONE) {
|
||||
/* Generate RPAs if required */
|
||||
ll_rl_rpa_update(false);
|
||||
}
|
||||
|
||||
ll_rl_pdu_adv_update(rl_idx, pdu_adv);
|
||||
ll_rl_pdu_adv_update(rl_idx, pdu_scan);
|
||||
priv = true;
|
||||
}
|
||||
#endif /* !CONFIG_BT_CTLR_PRIVACY */
|
||||
if (!priv) {
|
||||
memcpy(&pdu_adv->payload.adv_ind.addr[0],
|
||||
ll_addr_get(pdu_adv->tx_addr, NULL), BDADDR_SIZE);
|
||||
memcpy(&pdu_scan->payload.scan_rsp.addr[0],
|
||||
ll_addr_get(pdu_adv->tx_addr, NULL), BDADDR_SIZE);
|
||||
}
|
||||
}
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
||||
status = radio_adv_enable(ll_adv.phy_p, ll_adv.interval,
|
||||
ll_adv.chan_map, ll_adv.filter_policy,
|
||||
rl_idx);
|
||||
#else /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
status = radio_adv_enable(ll_adv.interval, ll_adv.chan_map,
|
||||
ll_adv.filter_policy, rl_idx);
|
||||
#endif /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
struct ll_adv_set {
|
||||
u8_t chan_map:3;
|
||||
u8_t filter_policy:2;
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
u8_t own_addr_type:2;
|
||||
u8_t id_addr_type:1;
|
||||
u8_t rl_idx;
|
||||
u8_t id_addr[BDADDR_SIZE];
|
||||
#endif /* CONFIG_BT_CTLR_PRIVACY */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
||||
u8_t phy_p:3;
|
||||
u32_t interval;
|
||||
#else /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
u16_t interval;
|
||||
#endif /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
};
|
||||
|
||||
struct ll_adv_set *ll_adv_set_get(void);
|
||||
|
|
@ -0,0 +1,938 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <misc/byteorder.h>
|
||||
#include <bluetooth/hci.h>
|
||||
|
||||
#include "util/util.h"
|
||||
#include "util/mem.h"
|
||||
|
||||
#include "pdu.h"
|
||||
#include "ctrl.h"
|
||||
#include "ll.h"
|
||||
#include "ll_adv.h"
|
||||
#include "ll_filter.h"
|
||||
|
||||
#define ADDR_TYPE_ANON 0xFF
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
|
||||
#include "common/log.h"
|
||||
|
||||
#include "hal/debug.h"
|
||||
#include "pdu.h"
|
||||
|
||||
/* Hardware whitelist */
|
||||
static struct ll_filter wl_filter;
|
||||
u8_t wl_anon;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
#include "common/rpa.h"
|
||||
|
||||
/* Whitelist peer list */
|
||||
static struct {
|
||||
u8_t taken:1;
|
||||
u8_t id_addr_type:1;
|
||||
u8_t rl_idx;
|
||||
bt_addr_t id_addr;
|
||||
} wl[WL_SIZE];
|
||||
|
||||
static u8_t rl_enable;
|
||||
static struct rl_dev {
|
||||
u8_t taken:1;
|
||||
u8_t rpas_ready:1;
|
||||
u8_t pirk:1;
|
||||
u8_t lirk:1;
|
||||
u8_t dev:1;
|
||||
u8_t wl:1;
|
||||
|
||||
u8_t id_addr_type:1;
|
||||
bt_addr_t id_addr;
|
||||
|
||||
u8_t local_irk[16];
|
||||
u8_t pirk_idx;
|
||||
bt_addr_t curr_rpa;
|
||||
bt_addr_t peer_rpa;
|
||||
bt_addr_t *local_rpa;
|
||||
|
||||
} rl[CONFIG_BT_CTLR_RL_SIZE];
|
||||
|
||||
static u8_t peer_irks[CONFIG_BT_CTLR_RL_SIZE][16];
|
||||
static u8_t peer_irk_rl_ids[CONFIG_BT_CTLR_RL_SIZE];
|
||||
static u8_t peer_irk_count;
|
||||
|
||||
static bt_addr_t local_rpas[CONFIG_BT_CTLR_RL_SIZE];
|
||||
|
||||
BUILD_ASSERT(ARRAY_SIZE(wl) < FILTER_IDX_NONE);
|
||||
BUILD_ASSERT(ARRAY_SIZE(rl) < FILTER_IDX_NONE);
|
||||
|
||||
/* Hardware filter for the resolving list */
|
||||
static struct ll_filter rl_filter;
|
||||
|
||||
#define DEFAULT_RPA_TIMEOUT_MS (900 * 1000)
|
||||
u32_t rpa_timeout_ms;
|
||||
s64_t rpa_last_ms;
|
||||
|
||||
struct k_delayed_work rpa_work;
|
||||
|
||||
#define LIST_MATCH(list, i, type, addr) (list[i].taken && \
|
||||
(list[i].id_addr_type == (type & 0x1)) && \
|
||||
!memcmp(list[i].id_addr.val, addr, BDADDR_SIZE))
|
||||
|
||||
static void wl_clear(void)
|
||||
{
|
||||
for (int i = 0; i < WL_SIZE; i++) {
|
||||
wl[i].taken = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static u8_t wl_find(u8_t addr_type, u8_t *addr, u8_t *free)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (free) {
|
||||
*free = FILTER_IDX_NONE;
|
||||
}
|
||||
|
||||
for (i = 0; i < WL_SIZE; i++) {
|
||||
if (LIST_MATCH(wl, i, addr_type, addr)) {
|
||||
return i;
|
||||
} else if (free && !wl[i].taken && (*free == FILTER_IDX_NONE)) {
|
||||
*free = i;
|
||||
}
|
||||
}
|
||||
|
||||
return FILTER_IDX_NONE;
|
||||
}
|
||||
|
||||
static u32_t wl_add(bt_addr_le_t *id_addr)
|
||||
{
|
||||
u8_t i, j;
|
||||
|
||||
i = wl_find(id_addr->type, id_addr->a.val, &j);
|
||||
|
||||
/* Duplicate check */
|
||||
if (i < ARRAY_SIZE(wl)) {
|
||||
return BT_HCI_ERR_INVALID_PARAM;
|
||||
} else if (j >= ARRAY_SIZE(wl)) {
|
||||
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
|
||||
}
|
||||
|
||||
i = j;
|
||||
|
||||
wl[i].id_addr_type = id_addr->type & 0x1;
|
||||
bt_addr_copy(&wl[i].id_addr, &id_addr->a);
|
||||
/* Get index to Resolving List if applicable */
|
||||
j = ll_rl_find(id_addr->type, id_addr->a.val, NULL);
|
||||
if (j < ARRAY_SIZE(rl)) {
|
||||
wl[i].rl_idx = j;
|
||||
rl[j].wl = 1;
|
||||
} else {
|
||||
wl[i].rl_idx = FILTER_IDX_NONE;
|
||||
}
|
||||
wl[i].taken = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32_t wl_remove(bt_addr_le_t *id_addr)
|
||||
{
|
||||
/* find the device and mark it as empty */
|
||||
u8_t i = wl_find(id_addr->type, id_addr->a.val, NULL);
|
||||
|
||||
if (i < ARRAY_SIZE(wl)) {
|
||||
u8_t j = wl[i].rl_idx;
|
||||
|
||||
if (j < ARRAY_SIZE(rl)) {
|
||||
rl[j].wl = 0;
|
||||
}
|
||||
wl[i].taken = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return BT_HCI_ERR_UNKNOWN_CONN_ID;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_CTLR_PRIVACY */
|
||||
|
||||
static void filter_clear(struct ll_filter *filter)
|
||||
{
|
||||
filter->enable_bitmask = 0;
|
||||
filter->addr_type_bitmask = 0;
|
||||
}
|
||||
|
||||
static void filter_insert(struct ll_filter *filter, int index, u8_t addr_type,
|
||||
u8_t *bdaddr)
|
||||
{
|
||||
filter->enable_bitmask |= BIT(index);
|
||||
filter->addr_type_bitmask |= ((addr_type & 0x01) << index);
|
||||
memcpy(&filter->bdaddr[index][0], bdaddr, BDADDR_SIZE);
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
static u32_t filter_add(struct ll_filter *filter, u8_t addr_type, u8_t *bdaddr)
|
||||
{
|
||||
int index;
|
||||
|
||||
if (filter->enable_bitmask == 0xFF) {
|
||||
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
|
||||
}
|
||||
|
||||
for (index = 0;
|
||||
(filter->enable_bitmask & BIT(index));
|
||||
index++) {
|
||||
}
|
||||
|
||||
filter_insert(filter, index, addr_type, bdaddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32_t filter_remove(struct ll_filter *filter, u8_t addr_type,
|
||||
u8_t *bdaddr)
|
||||
{
|
||||
int index;
|
||||
|
||||
if (!filter->enable_bitmask) {
|
||||
return BT_HCI_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
index = 8;
|
||||
while (index--) {
|
||||
if ((filter->enable_bitmask & BIT(index)) &&
|
||||
(((filter->addr_type_bitmask >> index) & 0x01) ==
|
||||
(addr_type & 0x01)) &&
|
||||
!memcmp(filter->bdaddr[index], bdaddr, BDADDR_SIZE)) {
|
||||
filter->enable_bitmask &= ~BIT(index);
|
||||
filter->addr_type_bitmask &= ~BIT(index);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return BT_HCI_ERR_INVALID_PARAM;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
bt_addr_t *ctrl_lrpa_get(u8_t rl_idx)
|
||||
{
|
||||
if ((rl_idx >= ARRAY_SIZE(rl)) || !rl[rl_idx].lirk ||
|
||||
!rl[rl_idx].rpas_ready) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rl[rl_idx].local_rpa;
|
||||
}
|
||||
|
||||
u8_t *ctrl_irks_get(u8_t *count)
|
||||
{
|
||||
*count = peer_irk_count;
|
||||
return (u8_t *)peer_irks;
|
||||
}
|
||||
|
||||
u8_t ctrl_rl_idx(bool whitelist, u8_t devmatch_id)
|
||||
{
|
||||
u8_t i;
|
||||
|
||||
if (whitelist) {
|
||||
LL_ASSERT(devmatch_id < ARRAY_SIZE(wl));
|
||||
LL_ASSERT(wl[devmatch_id].taken);
|
||||
i = wl[devmatch_id].rl_idx;
|
||||
} else {
|
||||
LL_ASSERT(devmatch_id < ARRAY_SIZE(rl));
|
||||
i = devmatch_id;
|
||||
LL_ASSERT(rl[i].taken);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
u8_t ctrl_rl_irk_idx(u8_t irkmatch_id)
|
||||
{
|
||||
u8_t i;
|
||||
|
||||
LL_ASSERT(irkmatch_id < peer_irk_count);
|
||||
i = peer_irk_rl_ids[irkmatch_id];
|
||||
LL_ASSERT(i < CONFIG_BT_CTLR_RL_SIZE);
|
||||
LL_ASSERT(rl[i].taken);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
bool ctrl_irk_whitelisted(u8_t rl_idx)
|
||||
{
|
||||
if (rl_idx >= ARRAY_SIZE(rl)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LL_ASSERT(rl[rl_idx].taken);
|
||||
|
||||
return rl[rl_idx].wl;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct ll_filter *ctrl_filter_get(bool whitelist)
|
||||
{
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
if (whitelist) {
|
||||
return &wl_filter;
|
||||
}
|
||||
return &rl_filter;
|
||||
#else
|
||||
LL_ASSERT(whitelist);
|
||||
return &wl_filter;
|
||||
#endif
|
||||
}
|
||||
|
||||
u32_t ll_wl_size_get(void)
|
||||
{
|
||||
return WL_SIZE;
|
||||
}
|
||||
|
||||
u32_t ll_wl_clear(void)
|
||||
{
|
||||
if (radio_adv_filter_pol_get() || (radio_scan_filter_pol_get() & 0x1)) {
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
wl_clear();
|
||||
#else
|
||||
filter_clear(&wl_filter);
|
||||
#endif /* CONFIG_BT_CTLR_PRIVACY */
|
||||
wl_anon = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32_t ll_wl_add(bt_addr_le_t *addr)
|
||||
{
|
||||
if (radio_adv_filter_pol_get() || (radio_scan_filter_pol_get() & 0x1)) {
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
}
|
||||
|
||||
if (addr->type == ADDR_TYPE_ANON) {
|
||||
wl_anon = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
return wl_add(addr);
|
||||
#else
|
||||
return filter_add(&wl_filter, addr->type, addr->a.val);
|
||||
#endif /* CONFIG_BT_CTLR_PRIVACY */
|
||||
}
|
||||
|
||||
u32_t ll_wl_remove(bt_addr_le_t *addr)
|
||||
{
|
||||
if (radio_adv_filter_pol_get() || (radio_scan_filter_pol_get() & 0x1)) {
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
}
|
||||
|
||||
if (addr->type == ADDR_TYPE_ANON) {
|
||||
wl_anon = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
return wl_remove(addr);
|
||||
#else
|
||||
return filter_remove(&wl_filter, addr->type, addr->a.val);
|
||||
#endif /* CONFIG_BT_CTLR_PRIVACY */
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
|
||||
static void filter_wl_update(void)
|
||||
{
|
||||
u8_t i;
|
||||
|
||||
/* Populate filter from wl peers */
|
||||
filter_clear(&wl_filter);
|
||||
|
||||
for (i = 0; i < WL_SIZE; i++) {
|
||||
u8_t j;
|
||||
|
||||
if (!wl[i].taken) {
|
||||
continue;
|
||||
}
|
||||
|
||||
j = wl[i].rl_idx;
|
||||
|
||||
if (!rl_enable || j >= ARRAY_SIZE(rl) || !rl[j].pirk ||
|
||||
rl[j].dev) {
|
||||
filter_insert(&wl_filter, i, wl[i].id_addr_type,
|
||||
wl[i].id_addr.val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void filter_rl_update(void)
|
||||
{
|
||||
u8_t i;
|
||||
|
||||
/* No whitelist: populate filter from rl peers */
|
||||
filter_clear(&rl_filter);
|
||||
|
||||
for (i = 0; i < CONFIG_BT_CTLR_RL_SIZE; i++) {
|
||||
if (rl[i].taken) {
|
||||
filter_insert(&rl_filter, i, rl[i].id_addr_type,
|
||||
rl[i].id_addr.val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ll_filters_adv_update(u8_t adv_fp)
|
||||
{
|
||||
/* enabling advertising */
|
||||
if (adv_fp && !(radio_scan_filter_pol_get() & 0x1)) {
|
||||
/* whitelist not in use, update whitelist */
|
||||
filter_wl_update();
|
||||
}
|
||||
|
||||
if (rl_enable && !radio_scan_is_enabled()) {
|
||||
/* rl not in use, update resolving list LUT */
|
||||
filter_rl_update();
|
||||
}
|
||||
}
|
||||
|
||||
void ll_filters_scan_update(u8_t scan_fp)
|
||||
{
|
||||
/* enabling advertising */
|
||||
if ((scan_fp & 0x1) && !radio_adv_filter_pol_get()) {
|
||||
/* whitelist not in use, update whitelist */
|
||||
filter_wl_update();
|
||||
}
|
||||
|
||||
if (rl_enable && !radio_adv_is_enabled()) {
|
||||
/* rl not in use, update resolving list LUT */
|
||||
filter_rl_update();
|
||||
}
|
||||
}
|
||||
|
||||
u8_t ll_rl_find(u8_t id_addr_type, u8_t *id_addr, u8_t *free)
|
||||
{
|
||||
u8_t i;
|
||||
|
||||
if (free) {
|
||||
*free = FILTER_IDX_NONE;
|
||||
}
|
||||
|
||||
for (i = 0; i < CONFIG_BT_CTLR_RL_SIZE; i++) {
|
||||
if (LIST_MATCH(rl, i, id_addr_type, id_addr)) {
|
||||
return i;
|
||||
} else if (free && !rl[i].taken && (*free == FILTER_IDX_NONE)) {
|
||||
*free = i;
|
||||
}
|
||||
}
|
||||
|
||||
return FILTER_IDX_NONE;
|
||||
}
|
||||
|
||||
bool ctrl_rl_idx_allowed(u8_t irkmatch_ok, u8_t rl_idx)
|
||||
{
|
||||
/* If AR is disabled or we don't know the device or we matched an IRK
|
||||
* then we're all set.
|
||||
*/
|
||||
if (!rl_enable || rl_idx >= ARRAY_SIZE(rl) || irkmatch_ok) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LL_ASSERT(rl_idx < CONFIG_BT_CTLR_RL_SIZE);
|
||||
LL_ASSERT(rl[rl_idx].taken);
|
||||
|
||||
return !rl[rl_idx].pirk || rl[rl_idx].dev;
|
||||
}
|
||||
|
||||
void ll_rl_id_addr_get(u8_t rl_idx, u8_t *id_addr_type, u8_t *id_addr)
|
||||
{
|
||||
LL_ASSERT(rl_idx < CONFIG_BT_CTLR_RL_SIZE);
|
||||
LL_ASSERT(rl[rl_idx].taken);
|
||||
|
||||
*id_addr_type = rl[rl_idx].id_addr_type;
|
||||
memcpy(id_addr, rl[rl_idx].id_addr.val, BDADDR_SIZE);
|
||||
}
|
||||
|
||||
bool ctrl_rl_addr_allowed(u8_t id_addr_type, u8_t *id_addr, u8_t *rl_idx)
|
||||
{
|
||||
u8_t i, j;
|
||||
|
||||
/* If AR is disabled or we matched an IRK then we're all set. No hw
|
||||
* filters are used in this case.
|
||||
*/
|
||||
if (!rl_enable || *rl_idx != FILTER_IDX_NONE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (i = 0; i < CONFIG_BT_CTLR_RL_SIZE; i++) {
|
||||
if (rl[i].taken && (rl[i].id_addr_type == id_addr_type)) {
|
||||
u8_t *addr = rl[i].id_addr.val;
|
||||
for (j = 0; j < BDADDR_SIZE; j++) {
|
||||
if (addr[j] != id_addr[j]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j == BDADDR_SIZE) {
|
||||
*rl_idx = i;
|
||||
return !rl[i].pirk || rl[i].dev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ctrl_rl_addr_resolve(u8_t id_addr_type, u8_t *id_addr, u8_t rl_idx)
|
||||
{
|
||||
/* Unable to resolve if AR is disabled, no RL entry or no local IRK */
|
||||
if (!rl_enable || rl_idx >= ARRAY_SIZE(rl) || !rl[rl_idx].lirk) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((id_addr_type != 0) && ((id_addr[5] & 0xc0) == 0x40)) {
|
||||
return bt_rpa_irk_matches(rl[rl_idx].local_irk,
|
||||
(bt_addr_t *)id_addr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ctrl_rl_enabled(void)
|
||||
{
|
||||
return rl_enable;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_BROADCASTER)
|
||||
void ll_rl_pdu_adv_update(u8_t idx, struct pdu_adv *pdu)
|
||||
{
|
||||
u8_t *adva = pdu->type == PDU_ADV_TYPE_SCAN_RSP ?
|
||||
&pdu->payload.scan_rsp.addr[0] :
|
||||
&pdu->payload.adv_ind.addr[0];
|
||||
|
||||
struct ll_adv_set *ll_adv = ll_adv_set_get();
|
||||
|
||||
/* AdvA */
|
||||
if (idx < ARRAY_SIZE(rl) && rl[idx].lirk) {
|
||||
LL_ASSERT(rl[idx].rpas_ready);
|
||||
pdu->tx_addr = 1;
|
||||
memcpy(adva, rl[idx].local_rpa->val, BDADDR_SIZE);
|
||||
} else {
|
||||
pdu->tx_addr = ll_adv->own_addr_type & 0x1;
|
||||
ll_addr_get(ll_adv->own_addr_type & 0x1, adva);
|
||||
}
|
||||
|
||||
/* TargetA */
|
||||
if (pdu->type == PDU_ADV_TYPE_DIRECT_IND) {
|
||||
if (idx < ARRAY_SIZE(rl) && rl[idx].pirk) {
|
||||
pdu->rx_addr = 1;
|
||||
memcpy(&pdu->payload.direct_ind.tgt_addr[0],
|
||||
rl[idx].peer_rpa.val, BDADDR_SIZE);
|
||||
} else {
|
||||
pdu->rx_addr = ll_adv->id_addr_type;
|
||||
memcpy(&pdu->payload.direct_ind.tgt_addr[0],
|
||||
ll_adv->id_addr, BDADDR_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rpa_adv_refresh(void)
|
||||
{
|
||||
struct radio_adv_data *radio_adv_data;
|
||||
struct ll_adv_set *ll_adv;
|
||||
struct pdu_adv *prev;
|
||||
struct pdu_adv *pdu;
|
||||
u8_t last;
|
||||
u8_t idx;
|
||||
|
||||
ll_adv = ll_adv_set_get();
|
||||
|
||||
if (ll_adv->own_addr_type != BT_ADDR_LE_PUBLIC_ID &&
|
||||
ll_adv->own_addr_type != BT_ADDR_LE_RANDOM_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
radio_adv_data = radio_adv_data_get();
|
||||
prev = (struct pdu_adv *)&radio_adv_data->data[radio_adv_data->last][0];
|
||||
/* use the last index in double buffer, */
|
||||
if (radio_adv_data->first == radio_adv_data->last) {
|
||||
last = radio_adv_data->last + 1;
|
||||
if (last == DOUBLE_BUFFER_SIZE) {
|
||||
last = 0;
|
||||
}
|
||||
} else {
|
||||
last = radio_adv_data->last;
|
||||
}
|
||||
|
||||
/* update adv pdu fields. */
|
||||
pdu = (struct pdu_adv *)&radio_adv_data->data[last][0];
|
||||
pdu->type = prev->type;
|
||||
pdu->rfu = 0;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_CHAN_SEL_2)) {
|
||||
pdu->chan_sel = prev->chan_sel;
|
||||
} else {
|
||||
pdu->chan_sel = 0;
|
||||
}
|
||||
|
||||
idx = ll_rl_find(ll_adv->id_addr_type, ll_adv->id_addr, NULL);
|
||||
LL_ASSERT(idx < ARRAY_SIZE(rl));
|
||||
ll_rl_pdu_adv_update(idx, pdu);
|
||||
|
||||
memcpy(&pdu->payload.adv_ind.data[0], &prev->payload.adv_ind.data[0],
|
||||
prev->len - BDADDR_SIZE);
|
||||
pdu->len = prev->len;
|
||||
|
||||
/* commit the update so controller picks it. */
|
||||
radio_adv_data->last = last;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void rl_clear(void)
|
||||
{
|
||||
for (u8_t i = 0; i < CONFIG_BT_CTLR_RL_SIZE; i++) {
|
||||
rl[i].taken = 0;
|
||||
}
|
||||
|
||||
peer_irk_count = 0;
|
||||
}
|
||||
|
||||
static int rl_access_check(bool check_ar)
|
||||
{
|
||||
if (check_ar) {
|
||||
/* If address resolution is disabled, allow immediately */
|
||||
if (!rl_enable) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return (radio_adv_is_enabled() || radio_scan_is_enabled()) ? 0 : 1;
|
||||
}
|
||||
|
||||
void ll_rl_rpa_update(bool timeout)
|
||||
{
|
||||
u8_t i;
|
||||
int err;
|
||||
s64_t now = k_uptime_get();
|
||||
bool all = timeout || (rpa_last_ms == -1) ||
|
||||
(now - rpa_last_ms >= rpa_timeout_ms);
|
||||
BT_DBG("");
|
||||
|
||||
for (i = 0; i < CONFIG_BT_CTLR_RL_SIZE; i++) {
|
||||
if ((rl[i].taken) && (all || !rl[i].rpas_ready)) {
|
||||
|
||||
if (rl[i].pirk) {
|
||||
u8_t irk[16];
|
||||
|
||||
/* TODO: move this swap to the driver level */
|
||||
sys_memcpy_swap(irk, peer_irks[rl[i].pirk_idx],
|
||||
16);
|
||||
err = bt_rpa_create(irk, &rl[i].peer_rpa);
|
||||
LL_ASSERT(!err);
|
||||
}
|
||||
|
||||
if (rl[i].lirk) {
|
||||
bt_addr_t rpa;
|
||||
|
||||
err = bt_rpa_create(rl[i].local_irk, &rpa);
|
||||
LL_ASSERT(!err);
|
||||
/* pointer read/write assumed to be atomic
|
||||
* so that if ISR fires the local_rpa pointer
|
||||
* will always point to a valid full RPA
|
||||
*/
|
||||
rl[i].local_rpa = &rpa;
|
||||
bt_addr_copy(&local_rpas[i], &rpa);
|
||||
rl[i].local_rpa = &local_rpas[i];
|
||||
}
|
||||
|
||||
rl[i].rpas_ready = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (all) {
|
||||
rpa_last_ms = now;
|
||||
}
|
||||
|
||||
if (timeout) {
|
||||
#if defined(CONFIG_BT_BROADCASTER)
|
||||
if (radio_adv_is_enabled()) {
|
||||
rpa_adv_refresh();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void rpa_timeout(struct k_work *work)
|
||||
{
|
||||
ll_rl_rpa_update(true);
|
||||
k_delayed_work_submit(&rpa_work, rpa_timeout_ms);
|
||||
}
|
||||
|
||||
static void rpa_refresh_start(void)
|
||||
{
|
||||
if (!rl_enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
BT_DBG("");
|
||||
k_delayed_work_submit(&rpa_work, rpa_timeout_ms);
|
||||
}
|
||||
|
||||
static void rpa_refresh_stop(void)
|
||||
{
|
||||
if (!rl_enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
k_delayed_work_cancel(&rpa_work);
|
||||
}
|
||||
|
||||
void ll_adv_scan_state_cb(u8_t bm)
|
||||
{
|
||||
if (bm) {
|
||||
rpa_refresh_start();
|
||||
} else {
|
||||
rpa_refresh_stop();
|
||||
}
|
||||
}
|
||||
|
||||
u32_t ll_rl_size_get(void)
|
||||
{
|
||||
return CONFIG_BT_CTLR_RL_SIZE;
|
||||
}
|
||||
|
||||
u32_t ll_rl_clear(void)
|
||||
{
|
||||
if (!rl_access_check(false)) {
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
}
|
||||
|
||||
rl_clear();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32_t ll_rl_add(bt_addr_le_t *id_addr, const u8_t pirk[16],
|
||||
const u8_t lirk[16])
|
||||
{
|
||||
u8_t i, j;
|
||||
|
||||
if (!rl_access_check(false)) {
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
}
|
||||
|
||||
i = ll_rl_find(id_addr->type, id_addr->a.val, &j);
|
||||
|
||||
/* Duplicate check */
|
||||
if (i < ARRAY_SIZE(rl)) {
|
||||
return BT_HCI_ERR_INVALID_PARAM;
|
||||
} else if (j >= ARRAY_SIZE(rl)) {
|
||||
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
|
||||
}
|
||||
|
||||
/* Device not found but empty slot found */
|
||||
i = j;
|
||||
|
||||
bt_addr_copy(&rl[i].id_addr, &id_addr->a);
|
||||
rl[i].id_addr_type = id_addr->type & 0x1;
|
||||
rl[i].pirk = mem_nz((u8_t *)pirk, 16);
|
||||
rl[i].lirk = mem_nz((u8_t *)lirk, 16);
|
||||
if (rl[i].pirk) {
|
||||
/* cross-reference */
|
||||
rl[i].pirk_idx = peer_irk_count;
|
||||
peer_irk_rl_ids[peer_irk_count] = i;
|
||||
/* AAR requires big-endian IRKs */
|
||||
sys_memcpy_swap(peer_irks[peer_irk_count++], pirk, 16);
|
||||
}
|
||||
if (rl[i].lirk) {
|
||||
memcpy(rl[i].local_irk, lirk, 16);
|
||||
rl[i].local_rpa = NULL;
|
||||
}
|
||||
memset(rl[i].curr_rpa.val, 0x00, sizeof(rl[i].curr_rpa));
|
||||
rl[i].rpas_ready = 0;
|
||||
/* Default to Network Privacy */
|
||||
rl[i].dev = 0;
|
||||
/* Add reference to a whitelist entry */
|
||||
j = wl_find(id_addr->type, id_addr->a.val, NULL);
|
||||
if (j < ARRAY_SIZE(wl)) {
|
||||
wl[j].rl_idx = i;
|
||||
rl[i].wl = 1;
|
||||
} else {
|
||||
rl[i].wl = 0;
|
||||
}
|
||||
rl[i].taken = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32_t ll_rl_remove(bt_addr_le_t *id_addr)
|
||||
{
|
||||
u8_t i;
|
||||
|
||||
if (!rl_access_check(false)) {
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
}
|
||||
|
||||
/* find the device and mark it as empty */
|
||||
i = ll_rl_find(id_addr->type, id_addr->a.val, NULL);
|
||||
if (i < ARRAY_SIZE(rl)) {
|
||||
u8_t j, k;
|
||||
|
||||
if (rl[i].pirk) {
|
||||
/* Swap with last item */
|
||||
u8_t pi = rl[i].pirk_idx, pj = peer_irk_count - 1;
|
||||
|
||||
if (pj && pi != pj) {
|
||||
memcpy(peer_irks[pi], peer_irks[pj], 16);
|
||||
for (k = 0;
|
||||
k < CONFIG_BT_CTLR_RL_SIZE;
|
||||
k++) {
|
||||
|
||||
if (rl[k].taken && rl[k].pirk &&
|
||||
rl[k].pirk_idx == pj) {
|
||||
rl[k].pirk_idx = pi;
|
||||
peer_irk_rl_ids[pi] = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
peer_irk_count--;
|
||||
}
|
||||
|
||||
/* Check if referenced by a whitelist entry */
|
||||
j = wl_find(id_addr->type, id_addr->a.val, NULL);
|
||||
if (j < ARRAY_SIZE(wl)) {
|
||||
wl[j].rl_idx = FILTER_IDX_NONE;
|
||||
}
|
||||
rl[i].taken = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return BT_HCI_ERR_UNKNOWN_CONN_ID;
|
||||
}
|
||||
|
||||
void ll_rl_crpa_set(u8_t id_addr_type, u8_t *id_addr, u8_t rl_idx, u8_t *crpa)
|
||||
{
|
||||
if ((crpa[5] & 0xc0) == 0x40) {
|
||||
|
||||
if (id_addr) {
|
||||
/* find the device and return its RPA */
|
||||
rl_idx = ll_rl_find(id_addr_type, id_addr, NULL);
|
||||
}
|
||||
|
||||
if (rl_idx < ARRAY_SIZE(rl) && rl[rl_idx].taken) {
|
||||
memcpy(rl[rl_idx].curr_rpa.val, crpa,
|
||||
sizeof(bt_addr_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32_t ll_rl_crpa_get(bt_addr_le_t *id_addr, bt_addr_t *crpa)
|
||||
{
|
||||
u8_t i;
|
||||
|
||||
/* find the device and return its RPA */
|
||||
i = ll_rl_find(id_addr->type, id_addr->a.val, NULL);
|
||||
if (i < ARRAY_SIZE(rl) &&
|
||||
mem_nz(rl[i].curr_rpa.val, sizeof(rl[i].curr_rpa.val))) {
|
||||
bt_addr_copy(crpa, &rl[i].curr_rpa);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return BT_HCI_ERR_UNKNOWN_CONN_ID;
|
||||
}
|
||||
|
||||
u32_t ll_rl_lrpa_get(bt_addr_le_t *id_addr, bt_addr_t *lrpa)
|
||||
{
|
||||
u8_t i;
|
||||
|
||||
/* find the device and return the local RPA */
|
||||
i = ll_rl_find(id_addr->type, id_addr->a.val, NULL);
|
||||
if (i < ARRAY_SIZE(rl)) {
|
||||
bt_addr_copy(lrpa, rl[i].local_rpa);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return BT_HCI_ERR_UNKNOWN_CONN_ID;
|
||||
}
|
||||
|
||||
u32_t ll_rl_enable(u8_t enable)
|
||||
{
|
||||
if (!rl_access_check(false)) {
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
}
|
||||
|
||||
switch (enable) {
|
||||
case BT_HCI_ADDR_RES_DISABLE:
|
||||
rl_enable = 0;
|
||||
break;
|
||||
case BT_HCI_ADDR_RES_ENABLE:
|
||||
rl_enable = 1;
|
||||
break;
|
||||
default:
|
||||
return BT_HCI_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ll_rl_timeout_set(u16_t timeout)
|
||||
{
|
||||
rpa_timeout_ms = timeout * 1000;
|
||||
}
|
||||
|
||||
u32_t ll_priv_mode_set(bt_addr_le_t *id_addr, u8_t mode)
|
||||
{
|
||||
u8_t i;
|
||||
|
||||
if (!rl_access_check(false)) {
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
}
|
||||
|
||||
/* find the device and mark it as empty */
|
||||
i = ll_rl_find(id_addr->type, id_addr->a.val, NULL);
|
||||
if (i < ARRAY_SIZE(rl)) {
|
||||
switch (mode) {
|
||||
case BT_HCI_LE_PRIVACY_MODE_NETWORK:
|
||||
rl[i].dev = 0;
|
||||
break;
|
||||
case BT_HCI_LE_PRIVACY_MODE_DEVICE:
|
||||
rl[i].dev = 1;
|
||||
break;
|
||||
default:
|
||||
return BT_HCI_ERR_INVALID_PARAM;
|
||||
}
|
||||
} else {
|
||||
return BT_HCI_ERR_UNKNOWN_CONN_ID;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_CTLR_PRIVACY */
|
||||
|
||||
void ll_filter_reset(bool init)
|
||||
{
|
||||
wl_anon = 0;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
wl_clear();
|
||||
|
||||
rl_enable = 0;
|
||||
rpa_timeout_ms = DEFAULT_RPA_TIMEOUT_MS;
|
||||
rpa_last_ms = -1;
|
||||
rl_clear();
|
||||
if (init) {
|
||||
k_delayed_work_init(&rpa_work, rpa_timeout);
|
||||
} else {
|
||||
k_delayed_work_cancel(&rpa_work);
|
||||
}
|
||||
#else
|
||||
filter_clear(&wl_filter);
|
||||
#endif /* CONFIG_BT_CTLR_PRIVACY */
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define WL_SIZE 8
|
||||
|
||||
#define FILTER_IDX_NONE 0xFF
|
||||
|
||||
struct ll_filter {
|
||||
u8_t enable_bitmask;
|
||||
u8_t addr_type_bitmask;
|
||||
u8_t bdaddr[WL_SIZE][BDADDR_SIZE];
|
||||
};
|
||||
|
||||
void ll_filter_reset(bool init);
|
||||
void ll_filters_adv_update(u8_t adv_fp);
|
||||
void ll_filters_scan_update(u8_t scan_fp);
|
||||
|
||||
struct ll_filter *ctrl_filter_get(bool whitelist);
|
||||
bt_addr_t *ctrl_lrpa_get(u8_t rl_idx);
|
||||
u8_t *ctrl_irks_get(u8_t *count);
|
||||
u8_t ctrl_rl_idx(bool whitelist, u8_t devmatch_id);
|
||||
u8_t ctrl_rl_irk_idx(u8_t irkmatch_id);
|
||||
bool ctrl_irk_whitelisted(u8_t rl_idx);
|
||||
|
||||
bool ctrl_rl_enabled(void);
|
||||
void ll_rl_rpa_update(bool timeout);
|
||||
|
||||
u8_t ll_rl_find(u8_t id_addr_type, u8_t *id_addr, u8_t *free);
|
||||
bool ctrl_rl_addr_allowed(u8_t id_addr_type, u8_t *id_addr, u8_t *rl_idx);
|
||||
bool ctrl_rl_addr_resolve(u8_t id_addr_type, u8_t *id_addr, u8_t rl_idx);
|
||||
bool ctrl_rl_idx_allowed(u8_t irkmatch_ok, u8_t rl_idx);
|
||||
void ll_rl_pdu_adv_update(u8_t idx, struct pdu_adv *pdu);
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2017 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <bluetooth/hci.h>
|
||||
|
||||
#include "util/util.h"
|
||||
|
||||
#include "pdu.h"
|
||||
#include "ctrl.h"
|
||||
#include "ll.h"
|
||||
#include "ll_filter.h"
|
||||
|
||||
u32_t ll_create_connection(u16_t scan_interval, u16_t scan_window,
|
||||
u8_t filter_policy, u8_t peer_addr_type,
|
||||
u8_t *peer_addr, u8_t own_addr_type,
|
||||
u16_t interval, u16_t latency,
|
||||
u16_t timeout)
|
||||
{
|
||||
u32_t status;
|
||||
u8_t rpa_gen = 0;
|
||||
u8_t rl_idx = FILTER_IDX_NONE;
|
||||
|
||||
if (radio_scan_is_enabled()) {
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
}
|
||||
|
||||
status = radio_connect_enable(peer_addr_type, peer_addr, interval,
|
||||
latency, timeout);
|
||||
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
ll_filters_scan_update(filter_policy);
|
||||
|
||||
if (!filter_policy && ctrl_rl_enabled()) {
|
||||
/* Look up the resolving list */
|
||||
rl_idx = ll_rl_find(peer_addr_type, peer_addr, NULL);
|
||||
}
|
||||
|
||||
if (own_addr_type == BT_ADDR_LE_PUBLIC_ID ||
|
||||
own_addr_type == BT_ADDR_LE_RANDOM_ID) {
|
||||
|
||||
/* Generate RPAs if required */
|
||||
ll_rl_rpa_update(false);
|
||||
own_addr_type &= 0x1;
|
||||
rpa_gen = 1;
|
||||
}
|
||||
#endif
|
||||
return radio_scan_enable(0, own_addr_type,
|
||||
ll_addr_get(own_addr_type, NULL),
|
||||
scan_interval, scan_window,
|
||||
filter_policy, rpa_gen, rl_idx);
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2017 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <bluetooth/hci.h>
|
||||
|
||||
#include "util/util.h"
|
||||
|
||||
#include "pdu.h"
|
||||
#include "ctrl.h"
|
||||
#include "ll.h"
|
||||
#include "ll_filter.h"
|
||||
|
||||
static struct {
|
||||
u16_t interval;
|
||||
u16_t window;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
||||
u8_t type:4;
|
||||
#else /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
u8_t type:1;
|
||||
#endif /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
|
||||
u8_t own_addr_type:2;
|
||||
u8_t filter_policy:2;
|
||||
} ll_scan;
|
||||
|
||||
u32_t ll_scan_params_set(u8_t type, u16_t interval, u16_t window,
|
||||
u8_t own_addr_type, u8_t filter_policy)
|
||||
{
|
||||
if (radio_scan_is_enabled()) {
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
}
|
||||
|
||||
/* type value:
|
||||
* 0000b - legacy 1M passive
|
||||
* 0001b - legacy 1M active
|
||||
* 0010b - Ext. 1M passive
|
||||
* 0011b - Ext. 1M active
|
||||
* 0100b - invalid
|
||||
* 0101b - invalid
|
||||
* 0110b - invalid
|
||||
* 0111b - invalid
|
||||
* 1000b - Ext. Coded passive
|
||||
* 1001b - Ext. Coded active
|
||||
*/
|
||||
ll_scan.type = type;
|
||||
ll_scan.interval = interval;
|
||||
ll_scan.window = window;
|
||||
ll_scan.own_addr_type = own_addr_type;
|
||||
ll_scan.filter_policy = filter_policy;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32_t ll_scan_enable(u8_t enable)
|
||||
{
|
||||
u32_t status;
|
||||
u8_t rpa_gen = 0;
|
||||
|
||||
if (!enable) {
|
||||
return radio_scan_disable();
|
||||
} else if (radio_scan_is_enabled()) {
|
||||
/* Duplicate filtering is processed in the HCI layer */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
ll_filters_scan_update(ll_scan.filter_policy);
|
||||
|
||||
if ((ll_scan.type & 0x1) &&
|
||||
(ll_scan.own_addr_type == BT_ADDR_LE_PUBLIC_ID ||
|
||||
ll_scan.own_addr_type == BT_ADDR_LE_RANDOM_ID)) {
|
||||
/* Generate RPAs if required */
|
||||
ll_rl_rpa_update(false);
|
||||
rpa_gen = 1;
|
||||
}
|
||||
#endif
|
||||
status = radio_scan_enable(ll_scan.type, ll_scan.own_addr_type & 0x1,
|
||||
ll_addr_get(ll_scan.own_addr_type & 0x1,
|
||||
NULL),
|
||||
ll_scan.interval, ll_scan.window,
|
||||
ll_scan.filter_policy, rpa_gen,
|
||||
FILTER_IDX_NONE);
|
||||
|
||||
return status;
|
||||
}
|
||||
345
Living_SDK/kernel/protocols/bluetooth/controller/ll_sw/ll_test.c
Normal file
345
Living_SDK/kernel/protocols/bluetooth/controller/ll_sw/ll_test.c
Normal file
|
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <toolchain.h>
|
||||
#include <zephyr/types.h>
|
||||
#include <soc.h>
|
||||
#include <clock_control.h>
|
||||
|
||||
#include "hal/cpu.h"
|
||||
#include "hal/cntr.h"
|
||||
#include "hal/ccm.h"
|
||||
#include "hal/radio.h"
|
||||
|
||||
#include "util/util.h"
|
||||
#include "ll_sw/pdu.h"
|
||||
#include "ll_sw/ctrl.h"
|
||||
|
||||
#include "ll_test.h"
|
||||
|
||||
#define CNTR_MIN_DELTA 3
|
||||
|
||||
static const u32_t test_sync_word = 0x71764129;
|
||||
static u8_t test_phy;
|
||||
static u8_t test_phy_flags;
|
||||
static u16_t test_num_rx;
|
||||
static bool started;
|
||||
|
||||
/* NOTE: The PRBS9 sequence used as packet payload.
|
||||
* The bytes in the sequence are in the right order, but the bits of each byte
|
||||
* in the array are reverse from that found by running the PRBS9 algorithm. This
|
||||
* is done to transmit MSbit first on air.
|
||||
*/
|
||||
|
||||
static const u8_t prbs9[] = {
|
||||
0xFF, 0xC1, 0xFB, 0xE8, 0x4C, 0x90, 0x72, 0x8B,
|
||||
0xE7, 0xB3, 0x51, 0x89, 0x63, 0xAB, 0x23, 0x23,
|
||||
0x02, 0x84, 0x18, 0x72, 0xAA, 0x61, 0x2F, 0x3B,
|
||||
0x51, 0xA8, 0xE5, 0x37, 0x49, 0xFB, 0xC9, 0xCA,
|
||||
0x0C, 0x18, 0x53, 0x2C, 0xFD, 0x45, 0xE3, 0x9A,
|
||||
0xE6, 0xF1, 0x5D, 0xB0, 0xB6, 0x1B, 0xB4, 0xBE,
|
||||
0x2A, 0x50, 0xEA, 0xE9, 0x0E, 0x9C, 0x4B, 0x5E,
|
||||
0x57, 0x24, 0xCC, 0xA1, 0xB7, 0x59, 0xB8, 0x87,
|
||||
0xFF, 0xE0, 0x7D, 0x74, 0x26, 0x48, 0xB9, 0xC5,
|
||||
0xF3, 0xD9, 0xA8, 0xC4, 0xB1, 0xD5, 0x91, 0x11,
|
||||
0x01, 0x42, 0x0C, 0x39, 0xD5, 0xB0, 0x97, 0x9D,
|
||||
0x28, 0xD4, 0xF2, 0x9B, 0xA4, 0xFD, 0x64, 0x65,
|
||||
0x06, 0x8C, 0x29, 0x96, 0xFE, 0xA2, 0x71, 0x4D,
|
||||
0xF3, 0xF8, 0x2E, 0x58, 0xDB, 0x0D, 0x5A, 0x5F,
|
||||
0x15, 0x28, 0xF5, 0x74, 0x07, 0xCE, 0x25, 0xAF,
|
||||
0x2B, 0x12, 0xE6, 0xD0, 0xDB, 0x2C, 0xDC, 0xC3,
|
||||
0x7F, 0xF0, 0x3E, 0x3A, 0x13, 0xA4, 0xDC, 0xE2,
|
||||
0xF9, 0x6C, 0x54, 0xE2, 0xD8, 0xEA, 0xC8, 0x88,
|
||||
0x00, 0x21, 0x86, 0x9C, 0x6A, 0xD8, 0xCB, 0x4E,
|
||||
0x14, 0x6A, 0xF9, 0x4D, 0xD2, 0x7E, 0xB2, 0x32,
|
||||
0x03, 0xC6, 0x14, 0x4B, 0x7F, 0xD1, 0xB8, 0xA6,
|
||||
0x79, 0x7C, 0x17, 0xAC, 0xED, 0x06, 0xAD, 0xAF,
|
||||
0x0A, 0x94, 0x7A, 0xBA, 0x03, 0xE7, 0x92, 0xD7,
|
||||
0x15, 0x09, 0x73, 0xE8, 0x6D, 0x16, 0xEE, 0xE1,
|
||||
0x3F, 0x78, 0x1F, 0x9D, 0x09, 0x52, 0x6E, 0xF1,
|
||||
0x7C, 0x36, 0x2A, 0x71, 0x6C, 0x75, 0x64, 0x44,
|
||||
0x80, 0x10, 0x43, 0x4E, 0x35, 0xEC, 0x65, 0x27,
|
||||
0x0A, 0xB5, 0xFC, 0x26, 0x69, 0x3F, 0x59, 0x99,
|
||||
0x01, 0x63, 0x8A, 0xA5, 0xBF, 0x68, 0x5C, 0xD3,
|
||||
0x3C, 0xBE, 0x0B, 0xD6, 0x76, 0x83, 0xD6, 0x57,
|
||||
0x05, 0x4A, 0x3D, 0xDD, 0x81, 0x73, 0xC9, 0xEB,
|
||||
0x8A, 0x84, 0x39, 0xF4, 0x36, 0x0B, 0xF7};
|
||||
|
||||
/* TODO: fill correct prbs15 */
|
||||
static const u8_t prbs15[255] = { 0x00, };
|
||||
|
||||
static u8_t tx_req;
|
||||
static u8_t volatile tx_ack;
|
||||
|
||||
static void isr_tx(void)
|
||||
{
|
||||
u32_t l, i, s, t;
|
||||
|
||||
/* Clear radio status and events */
|
||||
radio_status_reset();
|
||||
radio_tmr_status_reset();
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
|
||||
radio_gpio_pa_lna_disable();
|
||||
#endif /* CONFIG_BT_CTLR_GPIO_PA_PIN */
|
||||
|
||||
/* Exit if radio disabled */
|
||||
if (((tx_req - tx_ack) & 0x01) == 0) {
|
||||
tx_ack = tx_req;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* LE Test Packet Interval */
|
||||
l = radio_tmr_end_get() - radio_tmr_ready_get();
|
||||
i = ((l + 249 + 624) / 625) * 625;
|
||||
t = radio_tmr_end_get() - l + i;
|
||||
t -= radio_tx_ready_delay_get(test_phy, test_phy_flags);
|
||||
|
||||
/* Set timer capture in the future. */
|
||||
radio_tmr_sample();
|
||||
s = radio_tmr_sample_get();
|
||||
while (t < s) {
|
||||
t += 625;
|
||||
}
|
||||
|
||||
/* Setup next Tx */
|
||||
radio_switch_complete_and_disable();
|
||||
radio_tmr_start_us(1, t);
|
||||
radio_tmr_aa_capture();
|
||||
radio_tmr_end_capture();
|
||||
|
||||
/* TODO: check for probable stale timer capture being set */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
|
||||
radio_gpio_pa_setup();
|
||||
radio_gpio_pa_lna_enable(t + radio_tx_ready_delay_get(test_phy,
|
||||
test_phy_flags) -
|
||||
CONFIG_BT_CTLR_GPIO_PA_OFFSET);
|
||||
#endif /* CONFIG_BT_CTLR_GPIO_PA_PIN */
|
||||
}
|
||||
|
||||
static void isr_rx(void)
|
||||
{
|
||||
u8_t crc_ok = 0;
|
||||
u8_t trx_done;
|
||||
|
||||
/* Read radio status and events */
|
||||
trx_done = radio_is_done();
|
||||
if (trx_done) {
|
||||
crc_ok = radio_crc_is_valid();
|
||||
}
|
||||
|
||||
/* Clear radio status and events */
|
||||
radio_status_reset();
|
||||
radio_tmr_status_reset();
|
||||
|
||||
/* Exit if radio disabled */
|
||||
if (!trx_done) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Setup next Rx */
|
||||
radio_switch_complete_and_rx(test_phy);
|
||||
|
||||
/* Count Rx-ed packets */
|
||||
if (crc_ok) {
|
||||
test_num_rx++;
|
||||
}
|
||||
}
|
||||
|
||||
static u32_t init(u8_t chan, u8_t phy, void (*isr)(void))
|
||||
{
|
||||
struct device *hf_clock;
|
||||
|
||||
if (started) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* start coarse timer */
|
||||
cntr_start();
|
||||
|
||||
/* Setup resources required by Radio */
|
||||
hf_clock = radio_hf_clock_get();
|
||||
clock_control_on(hf_clock, (void *)1); /* start clock, blocking. */
|
||||
|
||||
/* Reset Radio h/w */
|
||||
radio_reset();
|
||||
radio_isr_set(isr);
|
||||
|
||||
/* Store value needed in Tx/Rx ISR */
|
||||
if (phy < 0x04) {
|
||||
test_phy = BIT(phy - 1);
|
||||
test_phy_flags = 1;
|
||||
} else {
|
||||
test_phy = BIT(2);
|
||||
test_phy_flags = 0;
|
||||
}
|
||||
|
||||
/* Setup Radio in Tx/Rx */
|
||||
/* NOTE: No whitening in test mode. */
|
||||
radio_phy_set(test_phy, test_phy_flags);
|
||||
radio_tmr_tifs_set(150);
|
||||
radio_tx_power_set(0);
|
||||
radio_freq_chan_set((chan << 1) + 2);
|
||||
radio_aa_set((u8_t *)&test_sync_word);
|
||||
radio_crc_configure(0x65b, 0x555555);
|
||||
radio_pkt_configure(8, 255, (test_phy << 1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32_t ll_test_tx(u8_t chan, u8_t len, u8_t type, u8_t phy)
|
||||
{
|
||||
u32_t start_us;
|
||||
u8_t *payload;
|
||||
u8_t *pdu;
|
||||
u32_t err;
|
||||
|
||||
if ((type > 0x07) || !phy || (phy > 0x04)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = init(chan, phy, isr_tx);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
tx_req++;
|
||||
|
||||
pdu = radio_pkt_scratch_get();
|
||||
payload = &pdu[2];
|
||||
|
||||
switch (type) {
|
||||
case 0x00:
|
||||
memcpy(payload, prbs9, len);
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
memset(payload, 0x0f, len);
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
memset(payload, 0x55, len);
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
memcpy(payload, prbs15, len);
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
memset(payload, 0xff, len);
|
||||
break;
|
||||
|
||||
case 0x05:
|
||||
memset(payload, 0x00, len);
|
||||
break;
|
||||
|
||||
case 0x06:
|
||||
memset(payload, 0xf0, len);
|
||||
break;
|
||||
|
||||
case 0x07:
|
||||
memset(payload, 0xaa, len);
|
||||
break;
|
||||
}
|
||||
|
||||
pdu[0] = type;
|
||||
pdu[1] = len;
|
||||
|
||||
radio_pkt_tx_set(pdu);
|
||||
radio_switch_complete_and_disable();
|
||||
start_us = radio_tmr_start(1, cntr_cnt_get() + CNTR_MIN_DELTA, 0);
|
||||
radio_tmr_aa_capture();
|
||||
radio_tmr_end_capture();
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
|
||||
radio_gpio_pa_setup();
|
||||
radio_gpio_pa_lna_enable(start_us +
|
||||
radio_tx_ready_delay_get(test_phy,
|
||||
test_phy_flags) -
|
||||
CONFIG_BT_CTLR_GPIO_PA_OFFSET);
|
||||
#else /* !CONFIG_BT_CTLR_GPIO_PA_PIN */
|
||||
ARG_UNUSED(start_us);
|
||||
#endif /* !CONFIG_BT_CTLR_GPIO_PA_PIN */
|
||||
|
||||
started = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32_t ll_test_rx(u8_t chan, u8_t phy, u8_t mod_idx)
|
||||
{
|
||||
u32_t err;
|
||||
|
||||
if (!phy || (phy > 0x03)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = init(chan, phy, isr_rx);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
radio_pkt_rx_set(radio_pkt_scratch_get());
|
||||
radio_switch_complete_and_rx(test_phy);
|
||||
radio_tmr_start(0, cntr_cnt_get() + CNTR_MIN_DELTA, 0);
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_GPIO_LNA_PIN)
|
||||
radio_gpio_lna_on();
|
||||
#endif /* !CONFIG_BT_CTLR_GPIO_LNA_PIN */
|
||||
|
||||
started = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32_t ll_test_end(u16_t *num_rx)
|
||||
{
|
||||
struct device *hf_clock;
|
||||
u8_t ack;
|
||||
|
||||
if (!started) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return packets Rx-ed/Completed */
|
||||
*num_rx = test_num_rx;
|
||||
test_num_rx = 0;
|
||||
|
||||
/* Disable Radio, if in Rx test */
|
||||
ack = tx_ack;
|
||||
if (tx_req == ack) {
|
||||
radio_disable();
|
||||
} else {
|
||||
/* Wait for Tx to complete */
|
||||
tx_req = ack + 2;
|
||||
while (tx_req != tx_ack) {
|
||||
cpu_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
/* Stop packet timer */
|
||||
radio_tmr_stop();
|
||||
|
||||
/* Release resources acquired for Radio */
|
||||
hf_clock = radio_hf_clock_get();
|
||||
clock_control_off(hf_clock, NULL);
|
||||
|
||||
/* Stop coarse timer */
|
||||
cntr_stop();
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_GPIO_LNA_PIN)
|
||||
radio_gpio_lna_off();
|
||||
#endif /* !CONFIG_BT_CTLR_GPIO_LNA_PIN */
|
||||
|
||||
started = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
u32_t ll_test_tx(u8_t chan, u8_t len, u8_t type, u8_t phy);
|
||||
u32_t ll_test_rx(u8_t chan, u8_t phy, u8_t mod_idx);
|
||||
u32_t ll_test_end(u16_t *num_rx);
|
||||
371
Living_SDK/kernel/protocols/bluetooth/controller/ll_sw/pdu.h
Normal file
371
Living_SDK/kernel/protocols/bluetooth/controller/ll_sw/pdu.h
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _PDU_H_
|
||||
#define _PDU_H_
|
||||
|
||||
#define BDADDR_SIZE 6
|
||||
|
||||
/* PDU Sizes */
|
||||
#define PDU_AC_PAYLOAD_SIZE_MAX 37
|
||||
#define PDU_AC_SIZE_MAX (offsetof(struct pdu_adv, payload) + \
|
||||
PDU_AC_PAYLOAD_SIZE_MAX)
|
||||
#define PDU_EM_SIZE_MAX offsetof(struct pdu_data, payload)
|
||||
|
||||
struct pdu_adv_payload_adv_ind {
|
||||
u8_t addr[BDADDR_SIZE];
|
||||
u8_t data[31];
|
||||
} __packed;
|
||||
|
||||
struct pdu_adv_payload_direct_ind {
|
||||
u8_t adv_addr[BDADDR_SIZE];
|
||||
u8_t tgt_addr[BDADDR_SIZE];
|
||||
} __packed;
|
||||
|
||||
struct pdu_adv_payload_scan_rsp {
|
||||
u8_t addr[BDADDR_SIZE];
|
||||
u8_t data[31];
|
||||
} __packed;
|
||||
|
||||
struct pdu_adv_payload_scan_req {
|
||||
u8_t scan_addr[BDADDR_SIZE];
|
||||
u8_t adv_addr[BDADDR_SIZE];
|
||||
} __packed;
|
||||
|
||||
struct pdu_adv_payload_connect_ind {
|
||||
u8_t init_addr[BDADDR_SIZE];
|
||||
u8_t adv_addr[BDADDR_SIZE];
|
||||
struct {
|
||||
u8_t access_addr[4];
|
||||
u8_t crc_init[3];
|
||||
u8_t win_size;
|
||||
u16_t win_offset;
|
||||
u16_t interval;
|
||||
u16_t latency;
|
||||
u16_t timeout;
|
||||
u8_t chan_map[5];
|
||||
u8_t hop:5;
|
||||
u8_t sca:3;
|
||||
} __packed lldata;
|
||||
} __packed;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
||||
struct pdu_adv_payload_com_ext_adv {
|
||||
u8_t ext_hdr_len:6;
|
||||
u8_t adv_mode:2;
|
||||
u8_t ext_hdr_adi_adv_data[254];
|
||||
} __packed;
|
||||
|
||||
enum ext_adv_mode {
|
||||
EXT_ADV_MODE_NON_CONN_NON_SCAN = 0x00,
|
||||
EXT_ADV_MODE_CONN_NON_SCAN = 0x01,
|
||||
EXT_ADV_MODE_NON_CONN_SCAN = 0x02,
|
||||
};
|
||||
|
||||
struct ext_adv_hdr {
|
||||
u8_t adv_addr:1;
|
||||
u8_t tgt_addr:1;
|
||||
u8_t rfu0:1;
|
||||
u8_t adi:1;
|
||||
u8_t aux_ptr:1;
|
||||
u8_t sync_info:1;
|
||||
u8_t tx_pwr:1;
|
||||
u8_t rfu1:1;
|
||||
} __packed;
|
||||
|
||||
struct ext_adv_adi {
|
||||
u16_t did:12;
|
||||
u16_t sid:4;
|
||||
} __packed;
|
||||
|
||||
struct ext_adv_aux_ptr {
|
||||
u8_t chan_idx:6;
|
||||
u8_t ca:1;
|
||||
u8_t offs_units:1;
|
||||
u16_t offs:13;
|
||||
u16_t phy:3;
|
||||
} __packed;
|
||||
|
||||
enum ext_adv_aux_ptr_ca {
|
||||
EXT_ADV_AUX_PTR_CA_500_PPM = 0x00,
|
||||
EXT_ADV_AUX_PTR_CA_50_PPM = 0x01,
|
||||
};
|
||||
|
||||
enum ext_adv_offs_units {
|
||||
EXT_ADV_AUX_PTR_OFFS_UNITS_30 = 0x00,
|
||||
EXT_ADV_AUX_PTR_OFFS_UNITS_300 = 0x01,
|
||||
};
|
||||
|
||||
enum ext_adv_aux_phy {
|
||||
EXT_ADV_AUX_PHY_LE_1M = 0x00,
|
||||
EXT_ADV_AUX_PHY_LE_2M = 0x01,
|
||||
EXT_ADV_AUX_PHY_LE_COD = 0x02,
|
||||
};
|
||||
|
||||
struct ext_adv_sync_info {
|
||||
u16_t sync_pkt_offs:13;
|
||||
u16_t offs_units:1;
|
||||
u16_t rfu:2;
|
||||
u16_t interval;
|
||||
u8_t sca_chm[5];
|
||||
u32_t aa;
|
||||
u8_t crc_init[3];
|
||||
u16_t evt_cntr;
|
||||
} __packed;
|
||||
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
||||
|
||||
enum pdu_adv_type {
|
||||
PDU_ADV_TYPE_ADV_IND = 0x00,
|
||||
PDU_ADV_TYPE_DIRECT_IND = 0x01,
|
||||
PDU_ADV_TYPE_NONCONN_IND = 0x02,
|
||||
PDU_ADV_TYPE_SCAN_REQ = 0x03,
|
||||
PDU_ADV_TYPE_AUX_SCAN_REQ = PDU_ADV_TYPE_SCAN_REQ,
|
||||
PDU_ADV_TYPE_SCAN_RSP = 0x04,
|
||||
PDU_ADV_TYPE_CONNECT_IND = 0x05,
|
||||
PDU_ADV_TYPE_AUX_CONNECT_REQ = PDU_ADV_TYPE_CONNECT_IND,
|
||||
PDU_ADV_TYPE_SCAN_IND = 0x06,
|
||||
PDU_ADV_TYPE_EXT_IND = 0x07,
|
||||
PDU_ADV_TYPE_AUX_ADV_IND = PDU_ADV_TYPE_EXT_IND,
|
||||
PDU_ADV_TYPE_AUX_SCAN_RSP = PDU_ADV_TYPE_EXT_IND,
|
||||
PDU_ADV_TYPE_AUX_SYNC_IND = PDU_ADV_TYPE_EXT_IND,
|
||||
PDU_ADV_TYPE_AUX_CHAIN_IND = PDU_ADV_TYPE_EXT_IND,
|
||||
PDU_ADV_TYPE_AUX_CONNECT_RSP = 0x08,
|
||||
} __packed;
|
||||
|
||||
struct pdu_adv {
|
||||
u8_t type:4;
|
||||
u8_t rfu:1;
|
||||
u8_t chan_sel:1;
|
||||
u8_t tx_addr:1;
|
||||
u8_t rx_addr:1;
|
||||
|
||||
u8_t len:8;
|
||||
|
||||
union {
|
||||
struct pdu_adv_payload_adv_ind adv_ind;
|
||||
struct pdu_adv_payload_direct_ind direct_ind;
|
||||
struct pdu_adv_payload_scan_req scan_req;
|
||||
struct pdu_adv_payload_scan_rsp scan_rsp;
|
||||
struct pdu_adv_payload_connect_ind connect_ind;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
||||
struct pdu_adv_payload_com_ext_adv adv_ext_ind;
|
||||
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
||||
} __packed payload;
|
||||
} __packed;
|
||||
|
||||
enum pdu_data_llid {
|
||||
PDU_DATA_LLID_RESV = 0x00,
|
||||
PDU_DATA_LLID_DATA_CONTINUE = 0x01,
|
||||
PDU_DATA_LLID_DATA_START = 0x02,
|
||||
PDU_DATA_LLID_CTRL = 0x03,
|
||||
};
|
||||
|
||||
enum pdu_data_llctrl_type {
|
||||
PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND = 0x00,
|
||||
PDU_DATA_LLCTRL_TYPE_CHAN_MAP_IND = 0x01,
|
||||
PDU_DATA_LLCTRL_TYPE_TERMINATE_IND = 0x02,
|
||||
PDU_DATA_LLCTRL_TYPE_ENC_REQ = 0x03,
|
||||
PDU_DATA_LLCTRL_TYPE_ENC_RSP = 0x04,
|
||||
PDU_DATA_LLCTRL_TYPE_START_ENC_REQ = 0x05,
|
||||
PDU_DATA_LLCTRL_TYPE_START_ENC_RSP = 0x06,
|
||||
PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP = 0x07,
|
||||
PDU_DATA_LLCTRL_TYPE_FEATURE_REQ = 0x08,
|
||||
PDU_DATA_LLCTRL_TYPE_FEATURE_RSP = 0x09,
|
||||
PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_REQ = 0x0A,
|
||||
PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_RSP = 0x0B,
|
||||
PDU_DATA_LLCTRL_TYPE_VERSION_IND = 0x0C,
|
||||
PDU_DATA_LLCTRL_TYPE_REJECT_IND = 0x0D,
|
||||
PDU_DATA_LLCTRL_TYPE_SLAVE_FEATURE_REQ = 0x0E,
|
||||
PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ = 0x0F,
|
||||
PDU_DATA_LLCTRL_TYPE_CONN_PARAM_RSP = 0x10,
|
||||
PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND = 0x11,
|
||||
PDU_DATA_LLCTRL_TYPE_PING_REQ = 0x12,
|
||||
PDU_DATA_LLCTRL_TYPE_PING_RSP = 0x13,
|
||||
PDU_DATA_LLCTRL_TYPE_LENGTH_REQ = 0x14,
|
||||
PDU_DATA_LLCTRL_TYPE_LENGTH_RSP = 0x15,
|
||||
PDU_DATA_LLCTRL_TYPE_PHY_REQ = 0x16,
|
||||
PDU_DATA_LLCTRL_TYPE_PHY_RSP = 0x17,
|
||||
PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND = 0x18,
|
||||
PDU_DATA_LLCTRL_TYPE_MIN_USED_CHAN_IND = 0x19,
|
||||
};
|
||||
|
||||
struct pdu_data_llctrl_conn_update_ind {
|
||||
u8_t win_size;
|
||||
u16_t win_offset;
|
||||
u16_t interval;
|
||||
u16_t latency;
|
||||
u16_t timeout;
|
||||
u16_t instant;
|
||||
} __packed;
|
||||
|
||||
struct pdu_data_llctrl_chan_map_ind {
|
||||
u8_t chm[5];
|
||||
u16_t instant;
|
||||
} __packed;
|
||||
|
||||
struct pdu_data_llctrl_terminate_ind {
|
||||
u8_t error_code;
|
||||
} __packed;
|
||||
|
||||
struct pdu_data_llctrl_enc_req {
|
||||
u8_t rand[8];
|
||||
u8_t ediv[2];
|
||||
u8_t skdm[8];
|
||||
u8_t ivm[4];
|
||||
} __packed;
|
||||
|
||||
struct pdu_data_llctrl_enc_rsp {
|
||||
u8_t skds[8];
|
||||
u8_t ivs[4];
|
||||
} __packed;
|
||||
|
||||
struct pdu_data_llctrl_unknown_rsp {
|
||||
u8_t type;
|
||||
} __packed;
|
||||
|
||||
struct pdu_data_llctrl_feature_req {
|
||||
u8_t features[8];
|
||||
} __packed;
|
||||
|
||||
struct pdu_data_llctrl_feature_rsp {
|
||||
u8_t features[8];
|
||||
} __packed;
|
||||
|
||||
struct pdu_data_llctrl_version_ind {
|
||||
u8_t version_number;
|
||||
u16_t company_id;
|
||||
u16_t sub_version_number;
|
||||
} __packed;
|
||||
|
||||
struct pdu_data_llctrl_reject_ind {
|
||||
u8_t error_code;
|
||||
} __packed;
|
||||
|
||||
struct pdu_data_llctrl_conn_param_req {
|
||||
u16_t interval_min;
|
||||
u16_t interval_max;
|
||||
u16_t latency;
|
||||
u16_t timeout;
|
||||
u8_t preferred_periodicity;
|
||||
u16_t reference_conn_event_count;
|
||||
u16_t offset0;
|
||||
u16_t offset1;
|
||||
u16_t offset2;
|
||||
u16_t offset3;
|
||||
u16_t offset4;
|
||||
u16_t offset5;
|
||||
} __packed;
|
||||
|
||||
struct pdu_data_llctrl_conn_param_rsp {
|
||||
u16_t interval_min;
|
||||
u16_t interval_max;
|
||||
u16_t latency;
|
||||
u16_t timeout;
|
||||
u8_t preferred_periodicity;
|
||||
u16_t reference_conn_event_count;
|
||||
u16_t offset0;
|
||||
u16_t offset1;
|
||||
u16_t offset2;
|
||||
u16_t offset3;
|
||||
u16_t offset4;
|
||||
u16_t offset5;
|
||||
} __packed;
|
||||
|
||||
struct pdu_data_llctrl_reject_ext_ind {
|
||||
u8_t reject_opcode;
|
||||
u8_t error_code;
|
||||
} __packed;
|
||||
|
||||
struct pdu_data_llctrl_length_req_rsp {
|
||||
u16_t max_rx_octets;
|
||||
u16_t max_rx_time;
|
||||
u16_t max_tx_octets;
|
||||
u16_t max_tx_time;
|
||||
} __packed;
|
||||
|
||||
struct pdu_data_llctrl_phy_req_rsp {
|
||||
u8_t tx_phys;
|
||||
u8_t rx_phys;
|
||||
} __packed;
|
||||
|
||||
struct pdu_data_llctrl_phy_upd_ind {
|
||||
u8_t m_to_s_phy;
|
||||
u8_t s_to_m_phy;
|
||||
u16_t instant;
|
||||
} __packed;
|
||||
|
||||
struct pdu_data_llctrl_min_used_chans_ind {
|
||||
u8_t phys;
|
||||
u8_t min_used_chans;
|
||||
} __packed;
|
||||
|
||||
struct pdu_data_llctrl {
|
||||
u8_t opcode;
|
||||
union {
|
||||
struct pdu_data_llctrl_conn_update_ind conn_update_ind;
|
||||
struct pdu_data_llctrl_chan_map_ind chan_map_ind;
|
||||
struct pdu_data_llctrl_terminate_ind terminate_ind;
|
||||
struct pdu_data_llctrl_enc_req enc_req;
|
||||
struct pdu_data_llctrl_enc_rsp enc_rsp;
|
||||
struct pdu_data_llctrl_unknown_rsp unknown_rsp;
|
||||
struct pdu_data_llctrl_feature_req feature_req;
|
||||
struct pdu_data_llctrl_feature_rsp feature_rsp;
|
||||
struct pdu_data_llctrl_version_ind version_ind;
|
||||
struct pdu_data_llctrl_reject_ind reject_ind;
|
||||
struct pdu_data_llctrl_feature_req slave_feature_req;
|
||||
struct pdu_data_llctrl_conn_param_req conn_param_req;
|
||||
struct pdu_data_llctrl_conn_param_rsp conn_param_rsp;
|
||||
struct pdu_data_llctrl_reject_ext_ind reject_ext_ind;
|
||||
struct pdu_data_llctrl_length_req_rsp length_req;
|
||||
struct pdu_data_llctrl_length_req_rsp length_rsp;
|
||||
struct pdu_data_llctrl_phy_req_rsp phy_req;
|
||||
struct pdu_data_llctrl_phy_req_rsp phy_rsp;
|
||||
struct pdu_data_llctrl_phy_upd_ind phy_upd_ind;
|
||||
struct pdu_data_llctrl_min_used_chans_ind min_used_chans_ind;
|
||||
} __packed ctrldata;
|
||||
} __packed;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PROFILE_ISR)
|
||||
struct profile {
|
||||
u8_t lcur;
|
||||
u8_t lmin;
|
||||
u8_t lmax;
|
||||
u8_t cur;
|
||||
u8_t min;
|
||||
u8_t max;
|
||||
} __packed;
|
||||
#endif /* CONFIG_BT_CTLR_PROFILE_ISR */
|
||||
|
||||
struct pdu_data {
|
||||
u8_t ll_id:2;
|
||||
u8_t nesn:1;
|
||||
u8_t sn:1;
|
||||
u8_t md:1;
|
||||
u8_t rfu:3;
|
||||
|
||||
u8_t len:8;
|
||||
|
||||
#if !defined(CONFIG_BT_CTLR_DATA_LENGTH_CLEAR)
|
||||
u8_t resv:8; /* TODO: remove nRF specific code */
|
||||
#endif /* !CONFIG_BT_CTLR_DATA_LENGTH_CLEAR */
|
||||
|
||||
union {
|
||||
u8_t lldata[1];
|
||||
struct pdu_data_llctrl llctrl;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_CONN_RSSI)
|
||||
u8_t rssi;
|
||||
#endif /* CONFIG_BT_CTLR_CONN_RSSI */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PROFILE_ISR)
|
||||
struct profile profile;
|
||||
#endif /* CONFIG_BT_CTLR_PROFILE_ISR */
|
||||
} __packed payload;
|
||||
} __packed;
|
||||
|
||||
#endif /* _PDU_H_ */
|
||||
1727
Living_SDK/kernel/protocols/bluetooth/controller/ticker/ticker.c
Normal file
1727
Living_SDK/kernel/protocols/bluetooth/controller/ticker/ticker.c
Normal file
File diff suppressed because it is too large
Load diff
122
Living_SDK/kernel/protocols/bluetooth/controller/ticker/ticker.h
Normal file
122
Living_SDK/kernel/protocols/bluetooth/controller/ticker/ticker.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _TICKER_H_
|
||||
#define _TICKER_H_
|
||||
|
||||
/** \brief Macro to translate microseconds to tick units.
|
||||
*
|
||||
* \note This returns the floor value.
|
||||
*/
|
||||
#define TICKER_US_TO_TICKS(x) \
|
||||
( \
|
||||
((u32_t)(((u64_t) (x) * 1000000000UL) / 30517578125UL)) \
|
||||
& 0x00FFFFFF \
|
||||
)
|
||||
|
||||
/** \brief Macro returning remainder in nanoseconds over-and-above a tick unit.
|
||||
*/
|
||||
#define TICKER_REMAINDER(x) \
|
||||
( \
|
||||
( \
|
||||
((u64_t) (x) * 1000000000UL) \
|
||||
- ((u64_t) TICKER_US_TO_TICKS(x) * 30517578125UL) \
|
||||
) \
|
||||
/ 1000UL \
|
||||
)
|
||||
|
||||
/** \brief Macro to translate tick units to microseconds.
|
||||
*/
|
||||
#define TICKER_TICKS_TO_US(x) \
|
||||
((u32_t)(((u64_t) (x) * 30517578125UL) / 1000000000UL))
|
||||
|
||||
/** \defgroup Timer API return codes.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#define TICKER_STATUS_SUCCESS 0 /**< Success. */
|
||||
#define TICKER_STATUS_FAILURE 1 /**< Failure. */
|
||||
#define TICKER_STATUS_BUSY 2 /**< Busy, requested feature will
|
||||
* complete later in time as job is
|
||||
* disabled or at lower execution
|
||||
* priority than the caller.
|
||||
*/
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** \defgroup Timer API common defaults parameter values.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#define TICKER_NULL ((u8_t)((u8_t)0 - 1))
|
||||
#define TICKER_NULL_REMAINDER 0
|
||||
#define TICKER_NULL_PERIOD 0
|
||||
#define TICKER_NULL_SLOT 0
|
||||
#define TICKER_NULL_LAZY 0
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** \brief Timer node type size.
|
||||
*/
|
||||
#define TICKER_NODE_T_SIZE 36
|
||||
|
||||
/** \brief Timer user type size.
|
||||
*/
|
||||
#define TICKER_USER_T_SIZE 8
|
||||
|
||||
/** \brief Timer user operation type size.
|
||||
*/
|
||||
#define TICKER_USER_OP_T_SIZE 44
|
||||
|
||||
/** \brief Timer timeout function type.
|
||||
*/
|
||||
typedef void (*ticker_timeout_func) (u32_t ticks_at_expire, u32_t remainder,
|
||||
u16_t lazy, void *context);
|
||||
|
||||
/** \brief Timer operation complete function type.
|
||||
*/
|
||||
typedef void (*ticker_op_func) (u32_t status, void *op_context);
|
||||
|
||||
/** \brief Timer module initialization.
|
||||
*
|
||||
* \param[in] instance_index Timer mode instance 0 or 1 (uses RTC0 CMP0 or
|
||||
* CMP1 respectively).
|
||||
* \param[in] count_node Max. no. of ticker nodes to initialize.
|
||||
* \param[in] node
|
||||
* \param[in] count_user
|
||||
* \param[in] user
|
||||
* \param[in] count_op
|
||||
* \param[in] user_op
|
||||
*/
|
||||
u32_t ticker_init(u8_t instance_index, u8_t count_node, void *node,
|
||||
u8_t count_user, void *user, u8_t count_op, void *user_op);
|
||||
bool ticker_is_initialized(u8_t instance_index);
|
||||
void ticker_trigger(u8_t instance_index);
|
||||
u32_t ticker_start(u8_t instance_index, u8_t user_id, u8_t ticker_id,
|
||||
u32_t ticks_anchor, u32_t ticks_first, u32_t ticks_periodic,
|
||||
u32_t remainder_periodic, u16_t lazy, u16_t ticks_slot,
|
||||
ticker_timeout_func ticker_timeout_func, void *context,
|
||||
ticker_op_func fp_op_func, void *op_context);
|
||||
u32_t ticker_update(u8_t instance_index, u8_t user_id, u8_t ticker_id,
|
||||
u16_t ticks_drift_plus, u16_t ticks_drift_minus,
|
||||
u16_t ticks_slot_plus, u16_t ticks_slot_minus, u16_t lazy,
|
||||
u8_t force, ticker_op_func fp_op_func, void *op_context);
|
||||
u32_t ticker_stop(u8_t instance_index, u8_t user_id, u8_t ticker_id,
|
||||
ticker_op_func fp_op_func, void *op_context);
|
||||
u32_t ticker_next_slot_get(u8_t instance_index, u8_t user_id,
|
||||
u8_t *ticker_id_head, u32_t *ticks_current,
|
||||
u32_t *ticks_to_expire,
|
||||
ticker_op_func fp_op_func, void *op_context);
|
||||
u32_t ticker_job_idle_get(u8_t instance_index, u8_t user_id,
|
||||
ticker_op_func fp_op_func, void *op_context);
|
||||
void ticker_job_sched(u8_t instance_index, u8_t user_id);
|
||||
u32_t ticker_ticks_now_get(void);
|
||||
u32_t ticker_ticks_diff_get(u32_t ticks_now, u32_t ticks_old);
|
||||
|
||||
#endif
|
||||
199
Living_SDK/kernel/protocols/bluetooth/controller/util/mayfly.c
Normal file
199
Living_SDK/kernel/protocols/bluetooth/controller/util/mayfly.c
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2017 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include "memq.h"
|
||||
#include "mayfly.h"
|
||||
|
||||
static struct {
|
||||
memq_link_t *head;
|
||||
memq_link_t *tail;
|
||||
u8_t enable_req;
|
||||
u8_t enable_ack;
|
||||
u8_t disable_req;
|
||||
u8_t disable_ack;
|
||||
} mft[MAYFLY_CALLEE_COUNT][MAYFLY_CALLER_COUNT];
|
||||
|
||||
static memq_link_t mfl[MAYFLY_CALLEE_COUNT][MAYFLY_CALLER_COUNT];
|
||||
|
||||
void mayfly_init(void)
|
||||
{
|
||||
u8_t callee_id;
|
||||
|
||||
callee_id = MAYFLY_CALLEE_COUNT;
|
||||
while (callee_id--) {
|
||||
u8_t caller_id;
|
||||
|
||||
caller_id = MAYFLY_CALLER_COUNT;
|
||||
while (caller_id--) {
|
||||
memq_init(&mfl[callee_id][caller_id],
|
||||
&mft[callee_id][caller_id].head,
|
||||
&mft[callee_id][caller_id].tail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mayfly_enable(u8_t caller_id, u8_t callee_id, u8_t enable)
|
||||
{
|
||||
if (enable) {
|
||||
if (mft[callee_id][caller_id].enable_req ==
|
||||
mft[callee_id][caller_id].enable_ack) {
|
||||
mft[callee_id][caller_id].enable_req++;
|
||||
}
|
||||
|
||||
mayfly_enable_cb(caller_id, callee_id, enable);
|
||||
} else {
|
||||
if (mft[callee_id][caller_id].disable_req ==
|
||||
mft[callee_id][caller_id].disable_ack) {
|
||||
mft[callee_id][caller_id].disable_req++;
|
||||
|
||||
mayfly_pend(caller_id, callee_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32_t mayfly_enqueue(u8_t caller_id, u8_t callee_id, u8_t chain,
|
||||
struct mayfly *m)
|
||||
{
|
||||
u8_t state;
|
||||
u8_t ack;
|
||||
|
||||
chain = chain || !mayfly_prio_is_equal(caller_id, callee_id) ||
|
||||
!mayfly_is_enabled(caller_id, callee_id) ||
|
||||
(mft[callee_id][caller_id].disable_req !=
|
||||
mft[callee_id][caller_id].disable_ack);
|
||||
|
||||
/* shadow the ack */
|
||||
ack = m->_ack;
|
||||
|
||||
/* already in queue */
|
||||
state = (m->_req - ack) & 0x03;
|
||||
if (state != 0) {
|
||||
if (chain) {
|
||||
if (state != 1) {
|
||||
/* mark as ready in queue */
|
||||
m->_req = ack + 1;
|
||||
|
||||
/* pend the callee for execution */
|
||||
mayfly_pend(caller_id, callee_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* already ready */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* mark as done in queue, and fall thru */
|
||||
m->_req = ack + 2;
|
||||
}
|
||||
|
||||
/* handle mayfly(s) that can be inline */
|
||||
if (!chain) {
|
||||
/* call fp */
|
||||
m->fp(m->param);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* new, add as ready in the queue */
|
||||
m->_req = ack + 1;
|
||||
memq_enqueue(m->_link, m, &mft[callee_id][caller_id].tail);
|
||||
|
||||
/* pend the callee for execution */
|
||||
mayfly_pend(caller_id, callee_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mayfly_run(u8_t callee_id)
|
||||
{
|
||||
u8_t disable = 0;
|
||||
u8_t enable = 0;
|
||||
u8_t caller_id;
|
||||
|
||||
/* iterate through each caller queue to this callee_id */
|
||||
caller_id = MAYFLY_CALLER_COUNT;
|
||||
while (caller_id--) {
|
||||
memq_link_t *link;
|
||||
struct mayfly *m = 0;
|
||||
|
||||
/* fetch mayfly in callee queue, if any */
|
||||
link = memq_peek(mft[callee_id][caller_id].head,
|
||||
mft[callee_id][caller_id].tail,
|
||||
(void **)&m);
|
||||
while (link) {
|
||||
u8_t state;
|
||||
u8_t req;
|
||||
|
||||
/* execute work if ready */
|
||||
req = m->_req;
|
||||
state = (req - m->_ack) & 0x03;
|
||||
if (state == 1) {
|
||||
/* mark mayfly as ran */
|
||||
m->_ack--;
|
||||
|
||||
/* call the mayfly function */
|
||||
m->fp(m->param);
|
||||
}
|
||||
|
||||
/* dequeue if not re-pended */
|
||||
req = m->_req;
|
||||
if (((req - m->_ack) & 0x03) != 1) {
|
||||
memq_dequeue(mft[callee_id][caller_id].tail,
|
||||
&mft[callee_id][caller_id].head,
|
||||
0);
|
||||
|
||||
/* release link into dequeued mayfly struct */
|
||||
m->_link = link;
|
||||
|
||||
/* reset mayfly state to idle */
|
||||
m->_ack = req;
|
||||
}
|
||||
|
||||
/* fetch next mayfly in callee queue, if any */
|
||||
link = memq_peek(mft[callee_id][caller_id].head,
|
||||
mft[callee_id][caller_id].tail,
|
||||
(void **)&m);
|
||||
|
||||
/* yield out of mayfly_run if a mayfly function was
|
||||
* called.
|
||||
*/
|
||||
if (state == 1) {
|
||||
/* pend callee (tailchain) if mayfly queue is
|
||||
* not empty or all caller queues are not
|
||||
* processed.
|
||||
*/
|
||||
if (caller_id || link) {
|
||||
mayfly_pend(callee_id, callee_id);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mft[callee_id][caller_id].disable_req !=
|
||||
mft[callee_id][caller_id].disable_ack) {
|
||||
disable = 1;
|
||||
|
||||
mft[callee_id][caller_id].disable_ack =
|
||||
mft[callee_id][caller_id].disable_req;
|
||||
}
|
||||
|
||||
if (mft[callee_id][caller_id].enable_req !=
|
||||
mft[callee_id][caller_id].enable_ack) {
|
||||
enable = 1;
|
||||
|
||||
mft[callee_id][caller_id].enable_ack =
|
||||
mft[callee_id][caller_id].enable_req;
|
||||
}
|
||||
}
|
||||
|
||||
if (disable && !enable) {
|
||||
mayfly_enable_cb(callee_id, callee_id, 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2017 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _MAYFLY_H_
|
||||
#define _MAYFLY_H_
|
||||
|
||||
#define MAYFLY_CALL_ID_0 0
|
||||
#define MAYFLY_CALL_ID_1 1
|
||||
#define MAYFLY_CALL_ID_2 2
|
||||
#define MAYFLY_CALL_ID_PROGRAM 3
|
||||
#define MAYFLY_CALLER_COUNT 4
|
||||
#define MAYFLY_CALLEE_COUNT 4
|
||||
|
||||
struct mayfly {
|
||||
u8_t volatile _req;
|
||||
u8_t _ack;
|
||||
memq_link_t *_link;
|
||||
void *param;
|
||||
void (*fp)(void *);
|
||||
};
|
||||
|
||||
void mayfly_init(void);
|
||||
void mayfly_enable(u8_t caller_id, u8_t callee_id, u8_t enable);
|
||||
u32_t mayfly_enqueue(u8_t caller_id, u8_t callee_id, u8_t chain,
|
||||
struct mayfly *m);
|
||||
void mayfly_run(u8_t callee_id);
|
||||
|
||||
extern void mayfly_enable_cb(u8_t caller_id, u8_t callee_id, u8_t enable);
|
||||
extern u32_t mayfly_is_enabled(u8_t caller_id, u8_t callee_id);
|
||||
extern u32_t mayfly_prio_is_equal(u8_t caller_id, u8_t callee_id);
|
||||
extern void mayfly_pend(u8_t caller_id, u8_t callee_id);
|
||||
|
||||
#endif /* _MAYFLY_H_ */
|
||||
187
Living_SDK/kernel/protocols/bluetooth/controller/util/mem.c
Normal file
187
Living_SDK/kernel/protocols/bluetooth/controller/util/mem.c
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include "mem.h"
|
||||
|
||||
void mem_init(void *mem_pool, u16_t mem_size, u16_t mem_count,
|
||||
void **mem_head)
|
||||
{
|
||||
*mem_head = mem_pool;
|
||||
|
||||
/* Store free mem_count after the list's next pointer at an aligned
|
||||
* memory location to ensure atomic read/write (in ARM for now).
|
||||
*/
|
||||
*((u16_t *)MROUND((u8_t *)mem_pool + sizeof(mem_pool))) = mem_count;
|
||||
|
||||
/* Initialize next pointers to form a free list,
|
||||
* next pointer is stored in the first 32-bit of each block
|
||||
*/
|
||||
memset(((u8_t *)mem_pool + (mem_size * (--mem_count))), 0,
|
||||
sizeof(mem_pool));
|
||||
while (mem_count--) {
|
||||
u32_t next;
|
||||
|
||||
next = (u32_t)((u8_t *) mem_pool +
|
||||
(mem_size * (mem_count + 1)));
|
||||
memcpy(((u8_t *)mem_pool + (mem_size * mem_count)),
|
||||
(void *)&next, sizeof(next));
|
||||
}
|
||||
}
|
||||
|
||||
void *mem_acquire(void **mem_head)
|
||||
{
|
||||
if (*mem_head) {
|
||||
u16_t free_count;
|
||||
void *head;
|
||||
void *mem;
|
||||
|
||||
/* Get the free count from the list and decrement it */
|
||||
free_count = *((u16_t *)MROUND((u8_t *)*mem_head +
|
||||
sizeof(mem_head)));
|
||||
free_count--;
|
||||
|
||||
mem = *mem_head;
|
||||
memcpy(&head, mem, sizeof(head));
|
||||
|
||||
/* Store free mem_count after the list's next pointer */
|
||||
if (head) {
|
||||
*((u16_t *)MROUND((u8_t *)head + sizeof(head))) =
|
||||
free_count;
|
||||
}
|
||||
|
||||
*mem_head = head;
|
||||
return mem;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void mem_release(void *mem, void **mem_head)
|
||||
{
|
||||
u16_t free_count = 0;
|
||||
|
||||
/* Get the free count from the list and increment it */
|
||||
if (*mem_head) {
|
||||
free_count = *((u16_t *)MROUND((u8_t *)*mem_head +
|
||||
sizeof(mem_head)));
|
||||
}
|
||||
free_count++;
|
||||
|
||||
memcpy(mem, mem_head, sizeof(mem));
|
||||
|
||||
/* Store free mem_count after the list's next pointer */
|
||||
*((u16_t *)MROUND((u8_t *)mem + sizeof(mem))) = free_count;
|
||||
|
||||
*mem_head = mem;
|
||||
}
|
||||
|
||||
u16_t mem_free_count_get(void *mem_head)
|
||||
{
|
||||
u16_t free_count = 0;
|
||||
|
||||
/* Get the free count from the list */
|
||||
if (mem_head) {
|
||||
free_count = *((u16_t *)MROUND((u8_t *)mem_head +
|
||||
sizeof(mem_head)));
|
||||
}
|
||||
|
||||
return free_count;
|
||||
}
|
||||
|
||||
void *mem_get(void *mem_pool, u16_t mem_size, u16_t index)
|
||||
{
|
||||
return ((void *)((u8_t *)mem_pool + (mem_size * index)));
|
||||
}
|
||||
|
||||
u16_t mem_index_get(void *mem, void *mem_pool, u16_t mem_size)
|
||||
{
|
||||
return ((u16_t)((u8_t *)mem - (u8_t *)mem_pool) / mem_size);
|
||||
}
|
||||
|
||||
void mem_rcopy(u8_t *dst, u8_t const *src, u16_t len)
|
||||
{
|
||||
src += len;
|
||||
while (len--) {
|
||||
*dst++ = *--src;
|
||||
}
|
||||
}
|
||||
|
||||
u8_t mem_nz(u8_t *src, u16_t len)
|
||||
{
|
||||
while (len--) {
|
||||
if (*src++) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32_t mem_ut(void)
|
||||
{
|
||||
#define BLOCK_SIZE MROUND(10)
|
||||
#define BLOCK_COUNT 10
|
||||
u8_t MALIGN(4) pool[BLOCK_COUNT][BLOCK_SIZE];
|
||||
void *mem_free;
|
||||
void *mem_used;
|
||||
u16_t mem_free_count;
|
||||
void *mem;
|
||||
|
||||
mem_init(pool, BLOCK_SIZE, BLOCK_COUNT, &mem_free);
|
||||
|
||||
mem_free_count = mem_free_count_get(mem_free);
|
||||
if (mem_free_count != BLOCK_COUNT) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
mem_used = 0;
|
||||
while (mem_free_count--) {
|
||||
u16_t mem_free_count_current;
|
||||
|
||||
mem = mem_acquire(&mem_free);
|
||||
mem_free_count_current = mem_free_count_get(mem_free);
|
||||
if (mem_free_count != mem_free_count_current) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
memcpy(mem, &mem_used, sizeof(mem));
|
||||
mem_used = mem;
|
||||
}
|
||||
|
||||
mem = mem_acquire(&mem_free);
|
||||
if (mem) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
while (++mem_free_count < BLOCK_COUNT) {
|
||||
u16_t mem_free_count_current;
|
||||
|
||||
mem = mem_used;
|
||||
memcpy(&mem_used, mem, sizeof(void *));
|
||||
mem_release(mem, &mem_free);
|
||||
|
||||
mem_free_count_current = mem_free_count_get(mem_free);
|
||||
if ((mem_free_count + 1) != mem_free_count_current) {
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (mem != mem_free) {
|
||||
return 5;
|
||||
}
|
||||
|
||||
if (mem_free_count_get(mem_free) != BLOCK_COUNT) {
|
||||
return 6;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
35
Living_SDK/kernel/protocols/bluetooth/controller/util/mem.h
Normal file
35
Living_SDK/kernel/protocols/bluetooth/controller/util/mem.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _MEM_H_
|
||||
#define _MEM_H_
|
||||
|
||||
#include <net/buf.h>
|
||||
|
||||
|
||||
#ifndef MALIGN
|
||||
#define MALIGN(x) __attribute__((aligned(x)))
|
||||
#endif
|
||||
|
||||
#ifndef MROUND
|
||||
#define MROUND(x) (((u32_t)(x)+3) & (~((u32_t)3)))
|
||||
#endif
|
||||
|
||||
void mem_init(void *mem_pool, u16_t mem_size, u16_t mem_count, void **mem_head);
|
||||
void *mem_acquire(void **mem_head);
|
||||
void mem_release(void *mem, void **mem_head);
|
||||
|
||||
u16_t mem_free_count_get(void *mem_head);
|
||||
void *mem_get(void *mem_pool, u16_t mem_size, u16_t index);
|
||||
u16_t mem_index_get(void *mem, void *mem_pool, u16_t mem_size);
|
||||
|
||||
void mem_rcopy(u8_t *dst, u8_t const *src, u16_t len);
|
||||
u8_t mem_nz(u8_t *src, u16_t len);
|
||||
|
||||
u32_t mem_ut(void);
|
||||
|
||||
#endif /* _MEM_H_ */
|
||||
66
Living_SDK/kernel/protocols/bluetooth/controller/util/memq.c
Normal file
66
Living_SDK/kernel/protocols/bluetooth/controller/util/memq.c
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2017 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "memq.h"
|
||||
|
||||
inline memq_link_t *memq_peek(memq_link_t *head, memq_link_t *tail, void **mem);
|
||||
|
||||
memq_link_t *memq_init(memq_link_t *link, memq_link_t **head, memq_link_t **tail)
|
||||
{
|
||||
/* head and tail pointer to the initial link */
|
||||
*head = *tail = link;
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
memq_link_t *memq_enqueue(memq_link_t *link, void *mem, memq_link_t **tail)
|
||||
{
|
||||
/* make the current tail link's next point to new link */
|
||||
(*tail)->next = link;
|
||||
|
||||
/* assign mem to current tail link's mem */
|
||||
(*tail)->mem = mem;
|
||||
|
||||
/* increment the tail! */
|
||||
*tail = link;
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
memq_link_t *memq_peek(memq_link_t *head, memq_link_t *tail, void **mem)
|
||||
{
|
||||
/* if head and tail are equal, then queue empty */
|
||||
if (head == tail) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* extract the link's mem */
|
||||
if (mem) {
|
||||
*mem = head->mem;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
memq_link_t *memq_dequeue(memq_link_t *tail, memq_link_t **head, void **mem)
|
||||
{
|
||||
memq_link_t *link;
|
||||
|
||||
/* use memq peek to get the link and mem */
|
||||
link = memq_peek(*head, tail, mem);
|
||||
if (!link) {
|
||||
return link;
|
||||
}
|
||||
|
||||
/* increment the head to next link node */
|
||||
*head = link->next;
|
||||
|
||||
return link;
|
||||
}
|
||||
24
Living_SDK/kernel/protocols/bluetooth/controller/util/memq.h
Normal file
24
Living_SDK/kernel/protocols/bluetooth/controller/util/memq.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2017 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _MEMQ_H_
|
||||
#define _MEMQ_H_
|
||||
|
||||
struct _memq_link {
|
||||
struct _memq_link *next;
|
||||
void *mem;
|
||||
};
|
||||
|
||||
typedef struct _memq_link memq_link_t;
|
||||
|
||||
memq_link_t *memq_init(memq_link_t *link, memq_link_t **head,
|
||||
memq_link_t **tail);
|
||||
memq_link_t *memq_enqueue(memq_link_t *link, void *mem, memq_link_t **tail);
|
||||
memq_link_t *memq_peek(memq_link_t *head, memq_link_t *tail, void **mem);
|
||||
memq_link_t *memq_dequeue(memq_link_t *tail, memq_link_t **head, void **mem);
|
||||
|
||||
#endif /* _MEMQ_H_ */
|
||||
27
Living_SDK/kernel/protocols/bluetooth/controller/util/util.c
Normal file
27
Living_SDK/kernel/protocols/bluetooth/controller/util/util.c
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include "util.h"
|
||||
|
||||
u8_t util_ones_count_get(u8_t *octets, u8_t octets_len)
|
||||
{
|
||||
u8_t one_count = 0;
|
||||
|
||||
while (octets_len--) {
|
||||
u8_t bite;
|
||||
|
||||
bite = *octets;
|
||||
while (bite) {
|
||||
bite &= (bite - 1);
|
||||
one_count++;
|
||||
}
|
||||
octets++;
|
||||
}
|
||||
|
||||
return one_count;
|
||||
}
|
||||
21
Living_SDK/kernel/protocols/bluetooth/controller/util/util.h
Normal file
21
Living_SDK/kernel/protocols/bluetooth/controller/util/util.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _UTIL_H_
|
||||
#define _UTIL_H_
|
||||
|
||||
#ifndef DOUBLE_BUFFER_SIZE
|
||||
#define DOUBLE_BUFFER_SIZE 2
|
||||
#endif
|
||||
|
||||
#ifndef TRIPLE_BUFFER_SIZE
|
||||
#define TRIPLE_BUFFER_SIZE 3
|
||||
#endif
|
||||
|
||||
u8_t util_ones_count_get(u8_t *octets, u8_t octets_len);
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue