Bluetooth: Controller: Hardware abstraction layer for nRF5x radio
The drivers/bluetooth/controller path adds a native BLE Link Layer (controller and HCI) to the Bluetooth subsystem. This first implementation adds support for the nRF5x series of devices from Nordic Semiconductor. The hal/ folder inside the controller contains all IC-specific code to interface with the radio and baseband. Jira: ZEP-702 Origin: Original Change-Id: I4ed61d5f67af6b4735d746a38a5b55f054521075 Signed-off-by: Vinayak Chettimada <vinayak.kariappa.chettimada@nordicsemi.no> Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
This commit is contained in:
parent
02c11b501f
commit
87d4d27731
|
@ -58,6 +58,12 @@ config BLUETOOTH_H5
|
|||
Bluetooth three-wire (H:5) UART driver. Implementation of HCI
|
||||
Three-Wire UART Transport Layer.
|
||||
|
||||
config BLUETOOTH_CONTROLLER
|
||||
bool "Controller"
|
||||
select BLUETOOTH_HOST_BUFFERS
|
||||
help
|
||||
Enables support for SoC native controller implementation.
|
||||
|
||||
config BLUETOOTH_NO_DRIVER
|
||||
bool "No default HCI driver"
|
||||
help
|
||||
|
@ -80,7 +86,7 @@ config BLUETOOTH_HOST_BUFFERS
|
|||
|
||||
config BLUETOOTH_DEBUG_DRIVER
|
||||
bool "Bluetooth driver debug"
|
||||
depends on BLUETOOTH_DEBUG && BLUETOOTH_UART
|
||||
depends on BLUETOOTH_DEBUG && (BLUETOOTH_UART || BLUETOOTH_CONTROLLER)
|
||||
default n
|
||||
help
|
||||
This option enables debug support for the chosen
|
||||
|
@ -119,6 +125,8 @@ endif # BLUETOOTH_STACK_HCI
|
|||
|
||||
source "drivers/bluetooth/nble/Kconfig"
|
||||
|
||||
source "drivers/bluetooth/controller/Kconfig"
|
||||
|
||||
config BLUETOOTH_NRF51_PM
|
||||
bool "nRF51 Power Management [EXPERIMENTAL]"
|
||||
depends on BLUETOOTH_H4 || NBLE
|
||||
|
@ -128,6 +136,7 @@ config BLUETOOTH_NRF51_PM
|
|||
|
||||
config BLUETOOTH_WAIT_NOP
|
||||
bool "Wait for \"NOP\" Command Complete event during init"
|
||||
depends on !BLUETOOTH_CONTROLLER
|
||||
help
|
||||
Some controllers emit a Command Complete event for the NOP
|
||||
opcode to indicate that they're ready to receive commands.
|
||||
|
|
|
@ -2,3 +2,4 @@ obj-$(CONFIG_BLUETOOTH_H4) += h4.o
|
|||
obj-$(CONFIG_BLUETOOTH_H5) += h5.o
|
||||
obj-$(CONFIG_NBLE) += nble/
|
||||
obj-$(CONFIG_BLUETOOTH_NRF51_PM) += nrf51_pm.o
|
||||
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += controller/
|
||||
|
|
30
drivers/bluetooth/controller/Kconfig
Normal file
30
drivers/bluetooth/controller/Kconfig
Normal file
|
@ -0,0 +1,30 @@
|
|||
if BLUETOOTH_CONTROLLER
|
||||
|
||||
comment "BLE Controller configuration"
|
||||
|
||||
config BLUETOOTH_CONTROLLER_DATA_LENGTH
|
||||
prompt "Maximum data length supported"
|
||||
int
|
||||
default 27
|
||||
range 27 251
|
||||
help
|
||||
Set the maximum data length of PDU supported in the stack.
|
||||
|
||||
config BLUETOOTH_CONTROLLER_RX_BUFFERS
|
||||
prompt "Number of Rx buffers"
|
||||
int
|
||||
default 1
|
||||
range 1 10
|
||||
help
|
||||
Set the number of Rx PDUs to be buffered in the controller.
|
||||
|
||||
config BLUETOOTH_CONTROLLER_TX_BUFFERS
|
||||
prompt "Number of Tx buffers"
|
||||
int
|
||||
default 1
|
||||
range 1 10
|
||||
help
|
||||
Set the number of Tx PDUs to be queued for transmission
|
||||
in the controller.
|
||||
|
||||
endif # BLUETOOTH_CONTROLLER
|
7
drivers/bluetooth/controller/Makefile
Normal file
7
drivers/bluetooth/controller/Makefile
Normal file
|
@ -0,0 +1,7 @@
|
|||
ccflags-$(CONFIG_BLUETOOTH_CONTROLLER) += -I$(srctree)/drivers/bluetooth/controller/hal
|
||||
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/irq.o
|
||||
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/clock.o
|
||||
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/rtc.o
|
||||
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/rand.o
|
||||
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/ecb.o
|
||||
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/radio.o
|
31
drivers/bluetooth/controller/hal/ccm.h
Normal file
31
drivers/bluetooth/controller/hal/ccm.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _CCM_H_
|
||||
#define _CCM_H_
|
||||
|
||||
#include <toolchain.h>
|
||||
|
||||
struct __packed ccm {
|
||||
uint8_t key[16];
|
||||
uint64_t counter;
|
||||
uint8_t direction:1;
|
||||
uint8_t resv1:7;
|
||||
uint8_t iv[8];
|
||||
};
|
||||
|
||||
#endif /* _CCM_H_ */
|
230
drivers/bluetooth/controller/hal/clock.c
Normal file
230
drivers/bluetooth/controller/hal/clock.c
Normal file
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "nrf.h"
|
||||
|
||||
#include "clock.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
static inline void hal_nop(void)
|
||||
{
|
||||
__asm__ volatile ("mov r0,r0");
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define NOP() hal_nop()
|
||||
#else
|
||||
#define NOP __nop
|
||||
#endif
|
||||
|
||||
static struct {
|
||||
uint8_t m16src_refcount;
|
||||
} clock_instance;
|
||||
|
||||
uint32_t clock_m16src_start(uint32_t async)
|
||||
{
|
||||
/* if clock is already started then just increment refcount.
|
||||
* refcount can handle 255 (uint8_t) requests, if the start
|
||||
* and stop dont happen in pairs, a rollover will be caught
|
||||
* and system should assert.
|
||||
*/
|
||||
if (clock_instance.m16src_refcount++) {
|
||||
goto hf_start_return;
|
||||
}
|
||||
|
||||
DEBUG_RADIO_XTAL(1);
|
||||
|
||||
NRF_CLOCK->TASKS_HFCLKSTOP = 1;
|
||||
|
||||
if (!async) {
|
||||
uint32_t intenset;
|
||||
|
||||
NVIC_DisableIRQ(POWER_CLOCK_IRQn);
|
||||
|
||||
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
|
||||
|
||||
intenset = NRF_CLOCK->INTENSET;
|
||||
NRF_CLOCK->INTENSET = CLOCK_INTENSET_HFCLKSTARTED_Msk;
|
||||
|
||||
NRF_CLOCK->TASKS_HFCLKSTART = 1;
|
||||
NOP();
|
||||
NOP();
|
||||
NOP();
|
||||
NOP();
|
||||
|
||||
while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) {
|
||||
__WFE();
|
||||
}
|
||||
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
|
||||
|
||||
if (!(intenset & CLOCK_INTENSET_HFCLKSTARTED_Msk)) {
|
||||
NRF_CLOCK->INTENCLR = CLOCK_INTENCLR_HFCLKSTARTED_Msk;
|
||||
}
|
||||
|
||||
NVIC_ClearPendingIRQ(POWER_CLOCK_IRQn);
|
||||
NVIC_EnableIRQ(POWER_CLOCK_IRQn);
|
||||
} else {
|
||||
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
|
||||
NRF_CLOCK->TASKS_HFCLKSTART = 1;
|
||||
NOP();
|
||||
NOP();
|
||||
NOP();
|
||||
NOP();
|
||||
}
|
||||
|
||||
hf_start_return:
|
||||
|
||||
/* rollover should not happen as start and stop shall be
|
||||
* called in pairs.
|
||||
*/
|
||||
ASSERT(clock_instance.m16src_refcount);
|
||||
|
||||
return (((NRF_CLOCK->HFCLKSTAT & CLOCK_HFCLKSTAT_STATE_Msk)) ? 1 : 0);
|
||||
}
|
||||
|
||||
void clock_m16src_stop(void)
|
||||
{
|
||||
ASSERT(clock_instance.m16src_refcount);
|
||||
|
||||
if (--clock_instance.m16src_refcount) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_RADIO_XTAL(0);
|
||||
|
||||
NRF_CLOCK->TASKS_HFCLKSTOP = 1;
|
||||
}
|
||||
|
||||
uint32_t clock_k32src_start(uint32_t src)
|
||||
{
|
||||
uint32_t intenset;
|
||||
|
||||
if ((NRF_CLOCK->LFCLKSTAT & CLOCK_LFCLKSTAT_STATE_Msk)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
NRF_CLOCK->TASKS_LFCLKSTOP = 1;
|
||||
|
||||
NVIC_DisableIRQ(POWER_CLOCK_IRQn);
|
||||
|
||||
NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
|
||||
|
||||
intenset = NRF_CLOCK->INTENSET;
|
||||
NRF_CLOCK->INTENSET = CLOCK_INTENSET_LFCLKSTARTED_Msk;
|
||||
|
||||
NRF_CLOCK->LFCLKSRC = src;
|
||||
NRF_CLOCK->TASKS_LFCLKSTART = 1;
|
||||
|
||||
while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) {
|
||||
__WFE();
|
||||
}
|
||||
NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
|
||||
|
||||
if (!(intenset & CLOCK_INTENSET_LFCLKSTARTED_Msk)) {
|
||||
NRF_CLOCK->INTENCLR = CLOCK_INTENCLR_LFCLKSTARTED_Msk;
|
||||
}
|
||||
|
||||
NVIC_ClearPendingIRQ(POWER_CLOCK_IRQn);
|
||||
NVIC_EnableIRQ(POWER_CLOCK_IRQn);
|
||||
|
||||
/* Calibrate RC, and start timer for consecutive calibrations */
|
||||
NRF_CLOCK->TASKS_CTSTOP = 1;
|
||||
NRF_CLOCK->INTENCLR = CLOCK_INTENCLR_DONE_Msk | CLOCK_INTENCLR_CTTO_Msk;
|
||||
NRF_CLOCK->EVENTS_DONE = 0;
|
||||
NRF_CLOCK->EVENTS_CTTO = 0;
|
||||
if (!src) {
|
||||
/* Set the Calibration Timer initial value */
|
||||
NRF_CLOCK->CTIV = 16; /* 4s in 0.25s units */
|
||||
|
||||
/* Enable DONE and CTTO IRQs */
|
||||
NRF_CLOCK->INTENSET =
|
||||
CLOCK_INTENSET_DONE_Msk | CLOCK_INTENSET_CTTO_Msk;
|
||||
|
||||
/* Start HF clock, if already started then explicitly
|
||||
* assert IRQ
|
||||
*/
|
||||
NRF_CLOCK->INTENSET = CLOCK_INTENSET_HFCLKSTARTED_Msk;
|
||||
if (clock_m16src_start(1)) {
|
||||
NVIC_ClearPendingIRQ(POWER_CLOCK_IRQn);
|
||||
}
|
||||
}
|
||||
|
||||
return ((NRF_CLOCK->LFCLKSTAT & CLOCK_LFCLKSTAT_STATE_Msk)) ? 1 : 0;
|
||||
}
|
||||
|
||||
void power_clock_isr(void)
|
||||
{
|
||||
uint8_t pof, hf_intenset, hf_stat, hf, lf, done, ctto;
|
||||
|
||||
pof = (NRF_POWER->EVENTS_POFWARN != 0);
|
||||
|
||||
hf_intenset =
|
||||
((NRF_CLOCK->INTENSET & CLOCK_INTENSET_HFCLKSTARTED_Msk) != 0);
|
||||
hf_stat = ((NRF_CLOCK->HFCLKSTAT & CLOCK_HFCLKSTAT_STATE_Msk) != 0);
|
||||
hf = (NRF_CLOCK->EVENTS_HFCLKSTARTED != 0);
|
||||
|
||||
lf = (NRF_CLOCK->EVENTS_LFCLKSTARTED != 0);
|
||||
|
||||
done = (NRF_CLOCK->EVENTS_DONE != 0);
|
||||
ctto = (NRF_CLOCK->EVENTS_CTTO != 0);
|
||||
|
||||
ASSERT(pof || hf || lf || done || ctto);
|
||||
|
||||
if (pof) {
|
||||
NRF_POWER->EVENTS_POFWARN = 0;
|
||||
}
|
||||
|
||||
if (hf) {
|
||||
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
|
||||
}
|
||||
|
||||
if (hf_intenset && hf_stat) {
|
||||
NRF_CLOCK->INTENCLR = CLOCK_INTENCLR_HFCLKSTARTED_Msk;
|
||||
|
||||
/* Start Calibration */
|
||||
NRF_CLOCK->TASKS_CAL = 1;
|
||||
}
|
||||
|
||||
if (lf) {
|
||||
NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
|
||||
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
if (done) {
|
||||
NRF_CLOCK->EVENTS_DONE = 0;
|
||||
|
||||
/* Calibration done, stop 16M Xtal. */
|
||||
clock_m16src_stop();
|
||||
|
||||
/* Start timer for next calibration. */
|
||||
NRF_CLOCK->TASKS_CTSTART = 1;
|
||||
}
|
||||
|
||||
if (ctto) {
|
||||
NRF_CLOCK->EVENTS_CTTO = 0;
|
||||
|
||||
/* Start HF clock, if already started
|
||||
* then explicitly assert IRQ
|
||||
*/
|
||||
NRF_CLOCK->INTENSET = CLOCK_INTENSET_HFCLKSTARTED_Msk;
|
||||
if (clock_m16src_start(1)) {
|
||||
NVIC_ClearPendingIRQ(POWER_CLOCK_IRQn);
|
||||
}
|
||||
}
|
||||
}
|
26
drivers/bluetooth/controller/hal/clock.h
Normal file
26
drivers/bluetooth/controller/hal/clock.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _CLOCK_H_
|
||||
#define _CLOCK_H_
|
||||
|
||||
uint32_t clock_m16src_start(uint32_t async);
|
||||
void clock_m16src_stop(void);
|
||||
uint32_t clock_k32src_start(uint32_t src);
|
||||
void power_clock_isr(void);
|
||||
|
||||
#endif
|
30
drivers/bluetooth/controller/hal/cpu.h
Normal file
30
drivers/bluetooth/controller/hal/cpu.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _CPU_H_
|
||||
#define _CPU_H_
|
||||
|
||||
#include "nrf.h"
|
||||
|
||||
static inline void cpu_sleep(void)
|
||||
{
|
||||
__WFE();
|
||||
__SEV();
|
||||
__WFE();
|
||||
}
|
||||
|
||||
#endif /* _CPU_H_ */
|
233
drivers/bluetooth/controller/hal/debug.h
Normal file
233
drivers/bluetooth/controller/hal/debug.h
Normal file
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _DEBUG_H_
|
||||
#define _DEBUG_H_
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define ASSERT(x) do { \
|
||||
if (!(x)) { \
|
||||
__asm__ volatile (".inst 0xde00\n"); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
static __asm void _udf(void)
|
||||
{
|
||||
UND #0;
|
||||
}
|
||||
|
||||
#define ASSERT(x) do { \
|
||||
if (!(x)) { \
|
||||
_udf(); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if (DEBUG == 1)
|
||||
/*
|
||||
* P2 is outgoing debug pins.
|
||||
* Debug pins are initialized to low.
|
||||
*/
|
||||
#define DEBUG_INIT() do { \
|
||||
NRF_GPIO->DIRSET = 0x03FF0000; \
|
||||
NRF_GPIO->OUTCLR = 0x03FF0000; } \
|
||||
while (0)
|
||||
|
||||
#define DEBUG_CPU_SLEEP(flag) do { \
|
||||
if (flag) { \
|
||||
NRF_GPIO->OUTSET = 0x00010000; \
|
||||
NRF_GPIO->OUTCLR = 0x00010000; } \
|
||||
else { \
|
||||
NRF_GPIO->OUTCLR = 0x00010000; \
|
||||
NRF_GPIO->OUTSET = 0x00010000; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_TICKER_ISR(flag) do { \
|
||||
if (flag) { \
|
||||
NRF_GPIO->OUTCLR = 0x00020000; \
|
||||
NRF_GPIO->OUTSET = 0x00020000; } \
|
||||
else { \
|
||||
NRF_GPIO->OUTSET = 0x00020000; \
|
||||
NRF_GPIO->OUTCLR = 0x00020000; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_TICKER_TASK(flag) do { \
|
||||
if (flag) { \
|
||||
NRF_GPIO->OUTCLR = 0x00020000; \
|
||||
NRF_GPIO->OUTSET = 0x00020000; } \
|
||||
else { \
|
||||
NRF_GPIO->OUTSET = 0x00020000; \
|
||||
NRF_GPIO->OUTCLR = 0x00020000; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_TICKER_JOB(flag) do { \
|
||||
if (flag) { \
|
||||
NRF_GPIO->OUTCLR = 0x00040000; \
|
||||
NRF_GPIO->OUTSET = 0x00040000; } \
|
||||
else { \
|
||||
NRF_GPIO->OUTSET = 0x00040000; \
|
||||
NRF_GPIO->OUTCLR = 0x00040000; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_ISR(flag) do { \
|
||||
if (flag) { \
|
||||
NRF_GPIO->OUTCLR = 0x00800000; \
|
||||
NRF_GPIO->OUTSET = 0x00800000; } \
|
||||
else { \
|
||||
NRF_GPIO->OUTSET = 0x00800000; \
|
||||
NRF_GPIO->OUTCLR = 0x00800000; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_XTAL(flag) do { \
|
||||
if (flag) { \
|
||||
NRF_GPIO->OUTCLR = 0x01000000; \
|
||||
NRF_GPIO->OUTSET = 0x01000000; } \
|
||||
else { \
|
||||
NRF_GPIO->OUTSET = 0x01000000; \
|
||||
NRF_GPIO->OUTCLR = 0x01000000; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_ACTIVE(flag) do { \
|
||||
if (flag) { \
|
||||
NRF_GPIO->OUTCLR = 0x02000000; \
|
||||
NRF_GPIO->OUTSET = 0x02000000; } \
|
||||
else { \
|
||||
NRF_GPIO->OUTSET = 0x02000000; \
|
||||
NRF_GPIO->OUTCLR = 0x02000000; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_CLOSE(flag) do { \
|
||||
if (flag) { \
|
||||
NRF_GPIO->OUTCLR = 0x00000000; \
|
||||
NRF_GPIO->OUTSET = 0x00000000; } \
|
||||
else { \
|
||||
NRF_GPIO->OUTCLR = 0x00780000; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_PREPARE_A(flag) do { \
|
||||
if (flag) { \
|
||||
NRF_GPIO->OUTCLR = 0x00080000; \
|
||||
NRF_GPIO->OUTSET = 0x00080000; } \
|
||||
else { \
|
||||
NRF_GPIO->OUTCLR = 0x00080000; \
|
||||
NRF_GPIO->OUTSET = 0x00080000; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_START_A(flag) do { \
|
||||
if (flag) { \
|
||||
NRF_GPIO->OUTCLR = 0x00080000; \
|
||||
NRF_GPIO->OUTSET = 0x00080000; } \
|
||||
else { \
|
||||
NRF_GPIO->OUTCLR = 0x00080000; \
|
||||
NRF_GPIO->OUTSET = 0x00080000; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_PREPARE_S(flag) do { \
|
||||
if (flag) { \
|
||||
NRF_GPIO->OUTCLR = 0x00100000; \
|
||||
NRF_GPIO->OUTSET = 0x00100000; } \
|
||||
else { \
|
||||
NRF_GPIO->OUTCLR = 0x00100000; \
|
||||
NRF_GPIO->OUTSET = 0x00100000; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_START_S(flag) do { \
|
||||
if (flag) { \
|
||||
NRF_GPIO->OUTCLR = 0x00100000; \
|
||||
NRF_GPIO->OUTSET = 0x00100000; } \
|
||||
else { \
|
||||
NRF_GPIO->OUTCLR = 0x00100000; \
|
||||
NRF_GPIO->OUTSET = 0x00100000; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_PREPARE_O(flag) do { \
|
||||
if (flag) { \
|
||||
NRF_GPIO->OUTCLR = 0x00200000; \
|
||||
NRF_GPIO->OUTSET = 0x00200000; } \
|
||||
else { \
|
||||
NRF_GPIO->OUTCLR = 0x00200000; \
|
||||
NRF_GPIO->OUTSET = 0x00200000; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_START_O(flag) do { \
|
||||
if (flag) { \
|
||||
NRF_GPIO->OUTCLR = 0x00200000; \
|
||||
NRF_GPIO->OUTSET = 0x00200000; } \
|
||||
else { \
|
||||
NRF_GPIO->OUTCLR = 0x00200000; \
|
||||
NRF_GPIO->OUTSET = 0x00200000; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_PREPARE_M(flag) do { \
|
||||
if (flag) { \
|
||||
NRF_GPIO->OUTCLR = 0x00400000; \
|
||||
NRF_GPIO->OUTSET = 0x00400000; } \
|
||||
else { \
|
||||
NRF_GPIO->OUTCLR = 0x00400000; \
|
||||
NRF_GPIO->OUTSET = 0x00400000; } \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_RADIO_START_M(flag) do { \
|
||||
if (flag) { \
|
||||
NRF_GPIO->OUTCLR = 0x00400000; \
|
||||
NRF_GPIO->OUTSET = 0x00400000; } \
|
||||
else { \
|
||||
NRF_GPIO->OUTCLR = 0x00400000; \
|
||||
NRF_GPIO->OUTSET = 0x00400000; } \
|
||||
} 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 /* DEBUG */
|
||||
|
||||
#endif /* _DEBUG_H_ */
|
188
drivers/bluetooth/controller/hal/ecb.c
Normal file
188
drivers/bluetooth/controller/hal/ecb.c
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <toolchain.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nrf.h"
|
||||
#include "mem.h"
|
||||
|
||||
#include "ecb.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
void ecb_encrypt(uint8_t const *const key_le,
|
||||
uint8_t const *const clear_text_le,
|
||||
uint8_t * const cipher_text_le,
|
||||
uint8_t * const cipher_text_be)
|
||||
{
|
||||
struct __packed {
|
||||
uint8_t key[16];
|
||||
uint8_t clear_text[16];
|
||||
uint8_t cipher_text[16];
|
||||
} 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 {
|
||||
NRF_ECB->TASKS_STOPECB = 1;
|
||||
NRF_ECB->ECBDATAPTR = (uint32_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;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
uint32_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 = (uint32_t)ecb;
|
||||
NRF_ECB->EVENTS_ENDECB = 0;
|
||||
NRF_ECB->EVENTS_ERRORECB = 0;
|
||||
NRF_ECB->INTENSET = ECB_INTENSET_ERRORECB_Msk | ECB_INTENSET_ENDECB_Msk;
|
||||
|
||||
/* setup interrupt */
|
||||
NVIC_SetPriority(ECB_IRQn, 2);
|
||||
NVIC_ClearPendingIRQ(ECB_IRQn);
|
||||
NVIC_EnableIRQ(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 */
|
||||
NVIC_DisableIRQ(ECB_IRQn);
|
||||
}
|
||||
|
||||
void ecb_isr(void)
|
||||
{
|
||||
if (NRF_ECB->EVENTS_ERRORECB) {
|
||||
struct ecb *ecb = (struct ecb *)NRF_ECB->ECBDATAPTR;
|
||||
|
||||
ecb_cleanup();
|
||||
|
||||
ecb->fp_ecb(1, 0, 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 {
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
struct ecb_ut_context {
|
||||
uint32_t volatile done;
|
||||
uint32_t status;
|
||||
uint8_t cipher_text[16];
|
||||
};
|
||||
|
||||
static void ecb_cb(uint32_t status, uint8_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));
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ecb_ut(void)
|
||||
{
|
||||
uint8_t key[16] = {
|
||||
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
|
||||
0x11, 0x22, 0x33, 0x44, 0x55 };
|
||||
uint8_t clear_text[16] = {
|
||||
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
|
||||
0x11, 0x22, 0x33, 0x44, 0x55 };
|
||||
uint8_t cipher_text[16];
|
||||
uint32_t status = 0;
|
||||
struct ecb ecb;
|
||||
struct ecb_ut_context context;
|
||||
|
||||
ecb_encrypt(key, clear_text, cipher_text, 0);
|
||||
|
||||
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;
|
||||
}
|
45
drivers/bluetooth/controller/hal/ecb.h
Normal file
45
drivers/bluetooth/controller/hal/ecb.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _ECB_H_
|
||||
#define _ECB_H_
|
||||
|
||||
typedef void (*ecb_fp) (uint32_t status, uint8_t *cipher_be,
|
||||
void *context);
|
||||
|
||||
struct ecb {
|
||||
uint8_t in_key_be[16];
|
||||
uint8_t in_clear_text_be[16];
|
||||
uint8_t out_cipher_text_be[16];
|
||||
/* if not null reverse copy into in_key_be */
|
||||
uint8_t *in_key_le;
|
||||
/* if not null reverse copy into in_clear_text_be */
|
||||
uint8_t *in_clear_text_le;
|
||||
ecb_fp fp_ecb;
|
||||
void *context;
|
||||
};
|
||||
|
||||
void ecb_encrypt(uint8_t const *const key_le,
|
||||
uint8_t const *const clear_text_le,
|
||||
uint8_t * const cipher_text_le,
|
||||
uint8_t * const cipher_text_be);
|
||||
uint32_t ecb_encrypt_nonblocking(struct ecb *ecb);
|
||||
void ecb_isr(void);
|
||||
|
||||
uint32_t ecb_ut(void);
|
||||
|
||||
#endif /* _ECB_H_ */
|
27
drivers/bluetooth/controller/hal/hal_irq.h
Normal file
27
drivers/bluetooth/controller/hal/hal_irq.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _IRQ_H_
|
||||
#define _IRQ_H_
|
||||
|
||||
void irq_enable(uint8_t irq);
|
||||
void irq_disable(uint8_t irq);
|
||||
void irq_pending_set(uint8_t irq);
|
||||
uint8_t irq_enabled(uint8_t irq);
|
||||
uint8_t irq_priority_equal(uint8_t irq);
|
||||
|
||||
#endif /* _IRQ_H_ */
|
27
drivers/bluetooth/controller/hal/hal_rtc.h
Normal file
27
drivers/bluetooth/controller/hal/hal_rtc.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _RTC_H_
|
||||
#define _RTC_H_
|
||||
|
||||
void rtc_init(void);
|
||||
uint32_t rtc_start(void);
|
||||
uint32_t rtc_stop(void);
|
||||
uint32_t rtc_tick_get(void);
|
||||
uint32_t rtc_compare_set(uint8_t instance, uint32_t value);
|
||||
|
||||
#endif /* _RTC_H_ */
|
33
drivers/bluetooth/controller/hal/hal_work.h
Normal file
33
drivers/bluetooth/controller/hal/hal_work.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _HAL_WORK_H_
|
||||
#define _HAL_WORK_H_
|
||||
|
||||
#include "nrf.h"
|
||||
|
||||
#define WORK_TICKER_WORKER0_IRQ RTC0_IRQn
|
||||
#define WORK_TICKER_JOB0_IRQ SWI4_IRQn
|
||||
#define WORK_TICKER_WORKER1_IRQ SWI5_IRQn
|
||||
#define WORK_TICKER_JOB1_IRQ SWI5_IRQn
|
||||
|
||||
#define WORK_TICKER_WORKER0_IRQ_PRIORITY 0
|
||||
#define WORK_TICKER_JOB0_IRQ_PRIORITY 0
|
||||
#define WORK_TICKER_WORKER1_IRQ_PRIORITY 2
|
||||
#define WORK_TICKER_JOB1_IRQ_PRIORITY 2
|
||||
|
||||
#endif /* _HAL_WORK_H_ */
|
53
drivers/bluetooth/controller/hal/irq.c
Normal file
53
drivers/bluetooth/controller/hal/irq.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "nrf.h"
|
||||
#include "hal_irq.h"
|
||||
|
||||
void irq_enable(uint8_t irq)
|
||||
{
|
||||
NVIC_EnableIRQ((IRQn_Type) irq);
|
||||
}
|
||||
|
||||
void irq_disable(uint8_t irq)
|
||||
{
|
||||
NVIC_DisableIRQ((IRQn_Type) irq);
|
||||
}
|
||||
|
||||
void irq_pending_set(uint8_t irq)
|
||||
{
|
||||
NVIC_SetPendingIRQ((IRQn_Type) irq);
|
||||
}
|
||||
|
||||
uint8_t irq_enabled(uint8_t irq)
|
||||
{
|
||||
return ((NVIC->ISER[0] & (1 << ((uint32_t) (irq) & 0x1F))) != 0);
|
||||
}
|
||||
|
||||
uint8_t irq_priority_equal(uint8_t irq)
|
||||
{
|
||||
uint32_t irq_current = SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk;
|
||||
uint32_t irq_priority_current = 4;
|
||||
|
||||
if (irq_current > 16) {
|
||||
irq_priority_current =
|
||||
NVIC_GetPriority((IRQn_Type) (irq_current - 16)) & 0xFF;
|
||||
}
|
||||
|
||||
return ((NVIC_GetPriority((IRQn_Type) irq) & 0xFF) ==
|
||||
irq_priority_current);
|
||||
}
|
552
drivers/bluetooth/controller/hal/radio.c
Normal file
552
drivers/bluetooth/controller/hal/radio.c
Normal file
|
@ -0,0 +1,552 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <misc/util.h>
|
||||
|
||||
#include "nrf.h"
|
||||
|
||||
#include "hal_work.h"
|
||||
|
||||
#include "defines.h"
|
||||
#include "ccm.h"
|
||||
#include "radio.h"
|
||||
|
||||
#if defined(NRF51)
|
||||
#define RADIO_PDU_LEN_MAX (BIT(5) - 1)
|
||||
#elif defined(NRF52)
|
||||
#define RADIO_PDU_LEN_MAX (BIT(8) - 1)
|
||||
#else
|
||||
#error "Platform not defined."
|
||||
#endif
|
||||
|
||||
static radio_isr_fp sfp_radio_isr;
|
||||
|
||||
void radio_isr(void)
|
||||
{
|
||||
if (sfp_radio_isr) {
|
||||
sfp_radio_isr();
|
||||
}
|
||||
}
|
||||
|
||||
void radio_isr_set(radio_isr_fp fp_radio_isr)
|
||||
{
|
||||
sfp_radio_isr = fp_radio_isr; /* atomic assignment of 32-bit word */
|
||||
|
||||
NRF_RADIO->INTENSET = (0 |
|
||||
/* RADIO_INTENSET_READY_Msk |
|
||||
* RADIO_INTENSET_ADDRESS_Msk |
|
||||
* RADIO_INTENSET_PAYLOAD_Msk |
|
||||
* RADIO_INTENSET_END_Msk |
|
||||
*/
|
||||
RADIO_INTENSET_DISABLED_Msk
|
||||
/* | RADIO_INTENSET_RSSIEND_Msk |
|
||||
*/
|
||||
);
|
||||
|
||||
NVIC_SetPriority(RADIO_IRQn, WORK_TICKER_WORKER0_IRQ_PRIORITY);
|
||||
NVIC_ClearPendingIRQ(RADIO_IRQn);
|
||||
NVIC_EnableIRQ(RADIO_IRQn);
|
||||
}
|
||||
|
||||
void radio_reset(void)
|
||||
{
|
||||
NVIC_DisableIRQ(RADIO_IRQn);
|
||||
|
||||
NRF_RADIO->POWER =
|
||||
((RADIO_POWER_POWER_Disabled << RADIO_POWER_POWER_Pos) &
|
||||
RADIO_POWER_POWER_Msk);
|
||||
NRF_RADIO->POWER =
|
||||
((RADIO_POWER_POWER_Enabled << RADIO_POWER_POWER_Pos) &
|
||||
RADIO_POWER_POWER_Msk);
|
||||
}
|
||||
|
||||
void radio_phy_set(uint8_t phy)
|
||||
{
|
||||
NRF_RADIO->MODE =
|
||||
(((phy) ? (uint32_t)phy : RADIO_MODE_MODE_Ble_1Mbit) <<
|
||||
RADIO_MODE_MODE_Pos) & RADIO_MODE_MODE_Msk;
|
||||
}
|
||||
|
||||
void radio_tx_power_set(uint32_t power)
|
||||
{
|
||||
/* TODO map power to h/w values. */
|
||||
NRF_RADIO->TXPOWER = power;
|
||||
}
|
||||
|
||||
void radio_freq_chnl_set(uint32_t chnl)
|
||||
{
|
||||
NRF_RADIO->FREQUENCY = chnl;
|
||||
}
|
||||
|
||||
void radio_whiten_iv_set(uint32_t iv)
|
||||
{
|
||||
NRF_RADIO->DATAWHITEIV = iv;
|
||||
}
|
||||
|
||||
void radio_aa_set(uint8_t *aa)
|
||||
{
|
||||
NRF_RADIO->TXADDRESS =
|
||||
(((0UL) << RADIO_TXADDRESS_TXADDRESS_Pos) &
|
||||
RADIO_TXADDRESS_TXADDRESS_Msk);
|
||||
NRF_RADIO->RXADDRESSES =
|
||||
((RADIO_RXADDRESSES_ADDR0_Enabled) << RADIO_RXADDRESSES_ADDR0_Pos);
|
||||
NRF_RADIO->PREFIX0 = aa[3];
|
||||
NRF_RADIO->BASE0 = (aa[2] << 24) | (aa[1] << 16) | (aa[0] << 8);
|
||||
}
|
||||
|
||||
void radio_pkt_configure(uint8_t preamble16, uint8_t bits_len, uint8_t max_len)
|
||||
{
|
||||
#if defined(NRF51)
|
||||
if (bits_len == 8) {
|
||||
bits_len = 5;
|
||||
}
|
||||
#endif
|
||||
|
||||
NRF_RADIO->PCNF0 = ((((1UL) << RADIO_PCNF0_S0LEN_Pos) &
|
||||
RADIO_PCNF0_S0LEN_Msk) |
|
||||
((((uint32_t)bits_len) << RADIO_PCNF0_LFLEN_Pos) &
|
||||
RADIO_PCNF0_LFLEN_Msk) |
|
||||
((((uint32_t)8-bits_len) <<
|
||||
RADIO_PCNF0_S1LEN_Pos) &
|
||||
RADIO_PCNF0_S1LEN_Msk) |
|
||||
(((RADIO_PCNF0_S1INCL_Include) <<
|
||||
RADIO_PCNF0_S1INCL_Pos) &
|
||||
RADIO_PCNF0_S1INCL_Msk) |
|
||||
((((preamble16) ? RADIO_PCNF0_PLEN_16bit :
|
||||
RADIO_PCNF0_PLEN_8bit) << RADIO_PCNF0_PLEN_Pos) &
|
||||
RADIO_PCNF0_PLEN_Msk));
|
||||
|
||||
NRF_RADIO->PCNF1 = (((((uint32_t)max_len) << RADIO_PCNF1_MAXLEN_Pos) &
|
||||
RADIO_PCNF1_MAXLEN_Msk) |
|
||||
(((0UL) << RADIO_PCNF1_STATLEN_Pos) &
|
||||
RADIO_PCNF1_STATLEN_Msk) |
|
||||
(((3UL) << RADIO_PCNF1_BALEN_Pos) &
|
||||
RADIO_PCNF1_BALEN_Msk) |
|
||||
(((RADIO_PCNF1_ENDIAN_Little) <<
|
||||
RADIO_PCNF1_ENDIAN_Pos) &
|
||||
RADIO_PCNF1_ENDIAN_Msk) |
|
||||
(((1UL) << RADIO_PCNF1_WHITEEN_Pos) &
|
||||
RADIO_PCNF1_WHITEEN_Msk));
|
||||
}
|
||||
|
||||
void radio_pkt_rx_set(void *rx_packet)
|
||||
{
|
||||
NRF_RADIO->PACKETPTR = (uint32_t)rx_packet;
|
||||
}
|
||||
|
||||
void radio_pkt_tx_set(void *tx_packet)
|
||||
{
|
||||
NRF_RADIO->PACKETPTR = (uint32_t)tx_packet;
|
||||
}
|
||||
|
||||
void radio_rx_enable(void)
|
||||
{
|
||||
NRF_RADIO->TASKS_RXEN = 1;
|
||||
}
|
||||
|
||||
void radio_tx_enable(void)
|
||||
{
|
||||
NRF_RADIO->TASKS_TXEN = 1;
|
||||
}
|
||||
|
||||
void radio_disable(void)
|
||||
{
|
||||
NRF_RADIO->SHORTS = 0;
|
||||
NRF_RADIO->TASKS_DISABLE = 1;
|
||||
}
|
||||
|
||||
void radio_status_reset(void)
|
||||
{
|
||||
NRF_RADIO->EVENTS_READY = 0;
|
||||
NRF_RADIO->EVENTS_ADDRESS = 0;
|
||||
NRF_RADIO->EVENTS_PAYLOAD = 0;
|
||||
NRF_RADIO->EVENTS_END = 0;
|
||||
NRF_RADIO->EVENTS_DISABLED = 0;
|
||||
}
|
||||
|
||||
uint32_t radio_is_ready(void)
|
||||
{
|
||||
return NRF_RADIO->EVENTS_READY;
|
||||
}
|
||||
|
||||
uint32_t radio_is_done(void)
|
||||
{
|
||||
return NRF_RADIO->EVENTS_END;
|
||||
}
|
||||
|
||||
uint32_t radio_has_disabled(void)
|
||||
{
|
||||
return NRF_RADIO->EVENTS_DISABLED;
|
||||
}
|
||||
|
||||
uint32_t radio_is_idle(void)
|
||||
{
|
||||
return (NRF_RADIO->STATE == 0);
|
||||
}
|
||||
|
||||
void radio_crc_configure(uint32_t polynomial, uint32_t iv)
|
||||
{
|
||||
NRF_RADIO->CRCCNF =
|
||||
(((RADIO_CRCCNF_SKIPADDR_Skip) << RADIO_CRCCNF_SKIPADDR_Pos) &
|
||||
RADIO_CRCCNF_SKIPADDR_Msk) |
|
||||
(((RADIO_CRCCNF_LEN_Three) << RADIO_CRCCNF_LEN_Pos) &
|
||||
RADIO_CRCCNF_LEN_Msk);
|
||||
NRF_RADIO->CRCPOLY = polynomial;
|
||||
NRF_RADIO->CRCINIT = iv;
|
||||
}
|
||||
|
||||
uint32_t radio_crc_is_valid(void)
|
||||
{
|
||||
return NRF_RADIO->CRCSTATUS;
|
||||
}
|
||||
|
||||
static uint8_t ALIGNED(4) _pkt_empty[RADIO_EMPDU_SIZE_MAX];
|
||||
static uint8_t ALIGNED(4) _pkt_scratch[
|
||||
((RADIO_PDU_LEN_MAX + 3) > RADIO_ACPDU_SIZE_MAX) ?
|
||||
(RADIO_PDU_LEN_MAX + 3) : RADIO_ACPDU_SIZE_MAX];
|
||||
|
||||
void *radio_pkt_empty_get(void)
|
||||
{
|
||||
return _pkt_empty;
|
||||
}
|
||||
|
||||
void *radio_pkt_scratch_get(void)
|
||||
{
|
||||
return _pkt_scratch;
|
||||
}
|
||||
|
||||
void radio_switch_complete_and_rx(void)
|
||||
{
|
||||
NRF_RADIO->SHORTS =
|
||||
(RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk |
|
||||
RADIO_SHORTS_DISABLED_RXEN_Msk);
|
||||
}
|
||||
|
||||
void radio_switch_complete_and_tx(void)
|
||||
{
|
||||
NRF_RADIO->SHORTS =
|
||||
(RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk |
|
||||
RADIO_SHORTS_DISABLED_TXEN_Msk);
|
||||
}
|
||||
|
||||
void radio_switch_complete_and_disable(void)
|
||||
{
|
||||
NRF_RADIO->SHORTS =
|
||||
(RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk);
|
||||
}
|
||||
|
||||
void radio_rssi_measure(void)
|
||||
{
|
||||
NRF_RADIO->SHORTS |=
|
||||
(RADIO_SHORTS_ADDRESS_RSSISTART_Msk |
|
||||
RADIO_SHORTS_DISABLED_RSSISTOP_Msk);
|
||||
}
|
||||
|
||||
uint32_t radio_rssi_get(void)
|
||||
{
|
||||
return NRF_RADIO->RSSISAMPLE;
|
||||
}
|
||||
|
||||
void radio_rssi_status_reset(void)
|
||||
{
|
||||
NRF_RADIO->EVENTS_RSSIEND = 0;
|
||||
}
|
||||
|
||||
uint32_t radio_rssi_is_ready(void)
|
||||
{
|
||||
return NRF_RADIO->EVENTS_RSSIEND;
|
||||
}
|
||||
|
||||
void radio_filter_configure(uint8_t bitmask_enable,
|
||||
uint8_t bitmask_addr_type,
|
||||
uint8_t *bdaddr)
|
||||
{
|
||||
uint8_t index = 8;
|
||||
|
||||
while (index--) {
|
||||
NRF_RADIO->DAB[index] = ((uint32_t)bdaddr[3] << 24) |
|
||||
((uint32_t)bdaddr[2] << 16) |
|
||||
((uint32_t)bdaddr[1] << 8) |
|
||||
bdaddr[0];
|
||||
NRF_RADIO->DAP[index] = ((uint32_t)bdaddr[5] << 8) | bdaddr[4];
|
||||
bdaddr += BDADDR_SIZE;
|
||||
}
|
||||
|
||||
NRF_RADIO->DACNF = ((uint32_t)bitmask_addr_type << 8) | bitmask_enable;
|
||||
}
|
||||
|
||||
void radio_filter_disable(void)
|
||||
{
|
||||
NRF_RADIO->DACNF &= ~(0x000000FF);
|
||||
}
|
||||
|
||||
void radio_filter_status_reset(void)
|
||||
{
|
||||
NRF_RADIO->EVENTS_DEVMATCH = 0;
|
||||
NRF_RADIO->EVENTS_DEVMISS = 0;
|
||||
}
|
||||
|
||||
uint32_t radio_filter_has_match(void)
|
||||
{
|
||||
return NRF_RADIO->EVENTS_DEVMATCH;
|
||||
}
|
||||
|
||||
void radio_bc_configure(uint32_t n)
|
||||
{
|
||||
NRF_RADIO->BCC = n;
|
||||
NRF_RADIO->SHORTS |= RADIO_SHORTS_ADDRESS_BCSTART_Msk;
|
||||
}
|
||||
|
||||
void radio_bc_status_reset(void)
|
||||
{
|
||||
NRF_RADIO->EVENTS_BCMATCH = 0;
|
||||
}
|
||||
|
||||
uint32_t radio_bc_has_match(void)
|
||||
{
|
||||
return NRF_RADIO->EVENTS_BCMATCH;
|
||||
}
|
||||
|
||||
void radio_tmr_status_reset(void)
|
||||
{
|
||||
NRF_RTC0->EVTENCLR = RTC_EVTENCLR_COMPARE2_Msk;
|
||||
NRF_PPI->CHENCLR =
|
||||
(PPI_CHEN_CH0_Msk | PPI_CHEN_CH1_Msk | PPI_CHEN_CH2_Msk |
|
||||
PPI_CHEN_CH3_Msk | PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk |
|
||||
PPI_CHEN_CH6_Msk);
|
||||
}
|
||||
|
||||
void radio_tmr_tifs_set(uint32_t tifs)
|
||||
{
|
||||
NRF_RADIO->TIFS = tifs;
|
||||
}
|
||||
|
||||
uint32_t radio_tmr_start(uint8_t trx, uint32_t ticks_start, uint32_t remainder)
|
||||
{
|
||||
if ((!(remainder / 1000000UL)) || (remainder & 0x80000000)) {
|
||||
ticks_start--;
|
||||
remainder += 30517578UL;
|
||||
}
|
||||
remainder /= 1000000UL;
|
||||
|
||||
NRF_TIMER0->TASKS_CLEAR = 1;
|
||||
NRF_TIMER0->MODE = 0;
|
||||
NRF_TIMER0->PRESCALER = 4;
|
||||
NRF_TIMER0->BITMODE = 2; /* 24 - bit */
|
||||
|
||||
NRF_TIMER0->CC[0] = remainder;
|
||||
NRF_TIMER0->EVENTS_COMPARE[0] = 0;
|
||||
|
||||
NRF_RTC0->CC[2] = ticks_start;
|
||||
NRF_RTC0->EVTENSET = RTC_EVTENSET_COMPARE2_Msk;
|
||||
NRF_RTC0->EVENTS_COMPARE[2] = 0;
|
||||
|
||||
NRF_PPI->CH[1].EEP = (uint32_t)&(NRF_RTC0->EVENTS_COMPARE[2]);
|
||||
NRF_PPI->CH[1].TEP = (uint32_t)&(NRF_TIMER0->TASKS_START);
|
||||
NRF_PPI->CHENSET = PPI_CHEN_CH1_Msk;
|
||||
|
||||
if (trx) {
|
||||
NRF_PPI->CH[0].EEP =
|
||||
(uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[0]);
|
||||
NRF_PPI->CH[0].TEP =
|
||||
(uint32_t)&(NRF_RADIO->TASKS_TXEN);
|
||||
NRF_PPI->CHENSET = PPI_CHEN_CH0_Msk;
|
||||
} else {
|
||||
NRF_PPI->CH[0].EEP =
|
||||
(uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[0]);
|
||||
NRF_PPI->CH[0].TEP =
|
||||
(uint32_t)&(NRF_RADIO->TASKS_RXEN);
|
||||
NRF_PPI->CHENSET = PPI_CHEN_CH0_Msk;
|
||||
}
|
||||
|
||||
return remainder;
|
||||
}
|
||||
|
||||
void radio_tmr_stop(void)
|
||||
{
|
||||
NRF_TIMER0->TASKS_STOP = 1;
|
||||
NRF_TIMER0->TASKS_SHUTDOWN = 1;
|
||||
}
|
||||
|
||||
void radio_tmr_hcto_configure(uint32_t hcto)
|
||||
{
|
||||
NRF_TIMER0->CC[2] = hcto;
|
||||
NRF_TIMER0->EVENTS_COMPARE[2] = 0;
|
||||
|
||||
NRF_PPI->CH[4].EEP = (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS);
|
||||
NRF_PPI->CH[4].TEP = (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[2]);
|
||||
NRF_PPI->CH[5].EEP = (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[2]);
|
||||
NRF_PPI->CH[5].TEP = (uint32_t)&(NRF_RADIO->TASKS_DISABLE);
|
||||
NRF_PPI->CHENSET = (PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk);
|
||||
}
|
||||
|
||||
void radio_tmr_aa_capture(void)
|
||||
{
|
||||
NRF_PPI->CH[2].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY);
|
||||
NRF_PPI->CH[2].TEP = (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[0]);
|
||||
NRF_PPI->CH[3].EEP = (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS);
|
||||
NRF_PPI->CH[3].TEP = (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[1]);
|
||||
NRF_PPI->CHENSET = (PPI_CHEN_CH2_Msk | PPI_CHEN_CH3_Msk);
|
||||
}
|
||||
|
||||
uint32_t radio_tmr_aa_get(void)
|
||||
{
|
||||
return (NRF_TIMER0->CC[1] - NRF_TIMER0->CC[0]);
|
||||
}
|
||||
|
||||
void radio_tmr_end_capture(void)
|
||||
{
|
||||
NRF_PPI->CH[2].EEP = (uint32_t)&(NRF_RADIO->EVENTS_END);
|
||||
NRF_PPI->CH[2].TEP = (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[2]);
|
||||
NRF_PPI->CHENSET = PPI_CHEN_CH2_Msk;
|
||||
}
|
||||
|
||||
uint32_t radio_tmr_end_get(void)
|
||||
{
|
||||
return NRF_TIMER0->CC[2];
|
||||
}
|
||||
|
||||
static uint8_t ALIGNED(4) _ccm_scratch[(RADIO_PDU_LEN_MAX - 4) + 16];
|
||||
|
||||
void *radio_ccm_rx_pkt_set(struct ccm *ccm, void *pkt)
|
||||
{
|
||||
NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Disabled;
|
||||
NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Enabled;
|
||||
NRF_CCM->MODE =
|
||||
((CCM_MODE_MODE_Decryption << CCM_MODE_MODE_Pos) &
|
||||
CCM_MODE_MODE_Msk) |
|
||||
((CCM_MODE_LENGTH_Extended << CCM_MODE_LENGTH_Pos) &
|
||||
CCM_MODE_LENGTH_Msk);
|
||||
NRF_CCM->CNFPTR = (uint32_t)ccm;
|
||||
NRF_CCM->INPTR = (uint32_t)_pkt_scratch;
|
||||
NRF_CCM->OUTPTR = (uint32_t)pkt;
|
||||
NRF_CCM->SCRATCHPTR = (uint32_t)_ccm_scratch;
|
||||
NRF_CCM->SHORTS = 0;
|
||||
NRF_CCM->EVENTS_ENDKSGEN = 0;
|
||||
NRF_CCM->EVENTS_ENDCRYPT = 0;
|
||||
NRF_CCM->EVENTS_ERROR = 0;
|
||||
|
||||
NRF_PPI->CH[6].EEP = (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS);
|
||||
NRF_PPI->CH[6].TEP = (uint32_t)&(NRF_CCM->TASKS_CRYPT);
|
||||
NRF_PPI->CHENSET = PPI_CHEN_CH6_Msk;
|
||||
|
||||
NRF_CCM->TASKS_KSGEN = 1;
|
||||
|
||||
return _pkt_scratch;
|
||||
}
|
||||
|
||||
void *radio_ccm_tx_pkt_set(struct ccm *ccm, void *pkt)
|
||||
{
|
||||
NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Disabled;
|
||||
NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Enabled;
|
||||
NRF_CCM->MODE =
|
||||
((CCM_MODE_MODE_Encryption << CCM_MODE_MODE_Pos) &
|
||||
CCM_MODE_MODE_Msk) |
|
||||
((CCM_MODE_LENGTH_Extended << CCM_MODE_LENGTH_Pos) &
|
||||
CCM_MODE_LENGTH_Msk);
|
||||
NRF_CCM->CNFPTR = (uint32_t)ccm;
|
||||
NRF_CCM->INPTR = (uint32_t)pkt;
|
||||
NRF_CCM->OUTPTR = (uint32_t)_pkt_scratch;
|
||||
NRF_CCM->SCRATCHPTR = (uint32_t)_ccm_scratch;
|
||||
NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk;
|
||||
NRF_CCM->EVENTS_ENDKSGEN = 0;
|
||||
NRF_CCM->EVENTS_ENDCRYPT = 0;
|
||||
NRF_CCM->EVENTS_ERROR = 0;
|
||||
|
||||
#if NRF51
|
||||
/* set up PPI to enable CCM */
|
||||
NRF_PPI->CH[6].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY);
|
||||
NRF_PPI->CH[6].TEP = (uint32_t)&(NRF_CCM->TASKS_KSGEN);
|
||||
NRF_PPI->CHENSET = PPI_CHEN_CH6_Msk;
|
||||
#elif 0
|
||||
/* encrypt tx packet */
|
||||
NRF_CCM->INTENSET = CCM_INTENSET_ENDCRYPT_Msk;
|
||||
NRF_CCM->TASKS_KSGEN = 1;
|
||||
while (NRF_CCM->EVENTS_ENDCRYPT == 0) {
|
||||
__WFE();
|
||||
__SEV();
|
||||
__WFE();
|
||||
}
|
||||
NRF_CCM->INTENCLR = CCM_INTENCLR_ENDCRYPT_Msk;
|
||||
NVIC_ClearPendingIRQ(CCM_AAR_IRQn);
|
||||
|
||||
ASSERT(NRF_CCM->EVENTS_ERROR == 0);
|
||||
#else
|
||||
/* start KSGEN early, but dont wait for ENDCRYPT */
|
||||
NRF_CCM->TASKS_KSGEN = 1;
|
||||
#endif
|
||||
|
||||
return _pkt_scratch;
|
||||
}
|
||||
|
||||
uint32_t radio_ccm_is_done(void)
|
||||
{
|
||||
NRF_CCM->INTENSET = CCM_INTENSET_ENDCRYPT_Msk;
|
||||
while (NRF_CCM->EVENTS_ENDCRYPT == 0) {
|
||||
__WFE();
|
||||
__SEV();
|
||||
__WFE();
|
||||
}
|
||||
NRF_CCM->INTENCLR = CCM_INTENCLR_ENDCRYPT_Msk;
|
||||
NVIC_ClearPendingIRQ(CCM_AAR_IRQn);
|
||||
|
||||
return (NRF_CCM->EVENTS_ERROR == 0);
|
||||
}
|
||||
|
||||
uint32_t radio_ccm_mic_is_valid(void)
|
||||
{
|
||||
return NRF_CCM->MICSTATUS;
|
||||
}
|
||||
|
||||
static uint8_t ALIGNED(4) _aar_scratch[3];
|
||||
|
||||
void radio_ar_configure(uint32_t nirk, void *irk)
|
||||
{
|
||||
NRF_AAR->ENABLE = 1;
|
||||
NRF_AAR->NIRK = nirk;
|
||||
NRF_AAR->IRKPTR = (uint32_t)irk;
|
||||
NRF_AAR->ADDRPTR = (uint32_t)NRF_RADIO->PACKETPTR;
|
||||
NRF_AAR->SCRATCHPTR = (uint32_t)_aar_scratch[0];
|
||||
|
||||
radio_bc_configure(64);
|
||||
|
||||
NRF_PPI->CH[6].EEP = (uint32_t)&(NRF_RADIO->EVENTS_BCMATCH);
|
||||
NRF_PPI->CH[6].TEP = (uint32_t)&(NRF_AAR->TASKS_START);
|
||||
NRF_PPI->CHENSET = PPI_CHEN_CH6_Msk;
|
||||
}
|
||||
|
||||
uint32_t radio_ar_match_get(void)
|
||||
{
|
||||
return NRF_AAR->STATUS;
|
||||
}
|
||||
|
||||
void radio_ar_status_reset(void)
|
||||
{
|
||||
if (radio_bc_has_match()) {
|
||||
NRF_AAR->EVENTS_END = 0;
|
||||
NRF_AAR->EVENTS_RESOLVED = 0;
|
||||
NRF_AAR->EVENTS_NOTRESOLVED = 0;
|
||||
}
|
||||
|
||||
radio_bc_status_reset();
|
||||
}
|
||||
|
||||
uint32_t radio_ar_has_match(void)
|
||||
{
|
||||
return (radio_bc_has_match() &&
|
||||
(NRF_AAR->EVENTS_END) &&
|
||||
(NRF_AAR->EVENTS_RESOLVED));
|
||||
}
|
108
drivers/bluetooth/controller/hal/radio.h
Normal file
108
drivers/bluetooth/controller/hal/radio.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _RADIO_H_
|
||||
#define _RADIO_H_
|
||||
|
||||
/* Ramp up times from OPS.
|
||||
*/
|
||||
#define RADIO_TX_READY_DELAY_US 140
|
||||
#define RADIO_RX_READY_DELAY_US 138
|
||||
|
||||
/* Chain delays from OPS.
|
||||
* nRF51: Tx= 1us, Rx= 3us;
|
||||
* nRF52: Tx= 0.6us, Rx= 9.4us.
|
||||
*/
|
||||
#define RADIO_TX_CHAIN_DELAY_US 1
|
||||
#define RADIO_RX_CHAIN_DELAY_US 10
|
||||
|
||||
/* Radio Pkt Size */
|
||||
#define RADIO_EMPDU_SIZE_MAX 3
|
||||
#define RADIO_ACPDU_SIZE_OVERHEAD 3
|
||||
#define RADIO_ACPDU_SIZE_MAX (37 + RADIO_ACPDU_SIZE_OVERHEAD)
|
||||
|
||||
typedef void (*radio_isr_fp) (void);
|
||||
|
||||
void radio_isr(void);
|
||||
void radio_isr_set(radio_isr_fp fp_radio_isr);
|
||||
|
||||
void radio_reset(void);
|
||||
void radio_phy_set(uint8_t phy);
|
||||
void radio_tx_power_set(uint32_t power);
|
||||
void radio_freq_chnl_set(uint32_t chnl);
|
||||
void radio_whiten_iv_set(uint32_t iv);
|
||||
void radio_aa_set(uint8_t *aa);
|
||||
void radio_pkt_configure(uint8_t preamble16, uint8_t bits_len, uint8_t max_len);
|
||||
void radio_pkt_rx_set(void *rx_packet);
|
||||
void radio_pkt_tx_set(void *tx_packet);
|
||||
void radio_rx_enable(void);
|
||||
void radio_tx_enable(void);
|
||||
void radio_disable(void);
|
||||
|
||||
void radio_status_reset(void);
|
||||
uint32_t radio_is_ready(void);
|
||||
uint32_t radio_is_done(void);
|
||||
uint32_t radio_has_disabled(void);
|
||||
uint32_t radio_is_idle(void);
|
||||
|
||||
void radio_crc_configure(uint32_t polynomial, uint32_t iv);
|
||||
uint32_t radio_crc_is_valid(void);
|
||||
|
||||
void *radio_pkt_empty_get(void);
|
||||
void *radio_pkt_scratch_get(void);
|
||||
|
||||
void radio_switch_complete_and_rx(void);
|
||||
void radio_switch_complete_and_tx(void);
|
||||
void radio_switch_complete_and_disable(void);
|
||||
|
||||
void radio_rssi_measure(void);
|
||||
uint32_t radio_rssi_get(void);
|
||||
void radio_rssi_status_reset(void);
|
||||
uint32_t radio_rssi_is_ready(void);
|
||||
|
||||
void radio_filter_configure(uint8_t bitmask_enable,
|
||||
uint8_t bitmask_addr_type,
|
||||
uint8_t *bdaddr);
|
||||
void radio_filter_disable(void);
|
||||
void radio_filter_status_reset(void);
|
||||
uint32_t radio_filter_has_match(void);
|
||||
|
||||
void radio_bc_configure(uint32_t n);
|
||||
void radio_bc_status_reset(void);
|
||||
uint32_t radio_bc_has_match(void);
|
||||
|
||||
void radio_tmr_status_reset(void);
|
||||
void radio_tmr_tifs_set(uint32_t tifs);
|
||||
uint32_t radio_tmr_start(uint8_t trx, uint32_t ticks_start, uint32_t remainder);
|
||||
void radio_tmr_stop(void);
|
||||
void radio_tmr_hcto_configure(uint32_t hcto);
|
||||
void radio_tmr_aa_capture(void);
|
||||
uint32_t radio_tmr_aa_get(void);
|
||||
void radio_tmr_end_capture(void);
|
||||
uint32_t radio_tmr_end_get(void);
|
||||
|
||||
void *radio_ccm_rx_pkt_set(struct ccm *ccm, void *pkt);
|
||||
void *radio_ccm_tx_pkt_set(struct ccm *ccm, void *pkt);
|
||||
uint32_t radio_ccm_is_done(void);
|
||||
uint32_t radio_ccm_mic_is_valid(void);
|
||||
|
||||
void radio_ar_configure(uint32_t nirk, void *irk);
|
||||
uint32_t radio_ar_match_get(void);
|
||||
void radio_ar_status_reset(void);
|
||||
uint32_t radio_ar_has_match(void);
|
||||
|
||||
#endif
|
125
drivers/bluetooth/controller/hal/rand.c
Normal file
125
drivers/bluetooth/controller/hal/rand.c
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "nrf.h"
|
||||
|
||||
#include "rand.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define RAND_RESERVED (4)
|
||||
|
||||
struct rand {
|
||||
uint8_t count;
|
||||
uint8_t first;
|
||||
uint8_t last;
|
||||
uint8_t rand[1];
|
||||
};
|
||||
|
||||
static struct rand *_rand;
|
||||
|
||||
void rand_init(uint8_t *context, uint8_t context_len)
|
||||
{
|
||||
ASSERT(context_len > sizeof(struct rand));
|
||||
|
||||
_rand = (struct rand *)context;
|
||||
_rand->count = context_len - sizeof(struct rand) + 1;
|
||||
_rand->first = _rand->last = 0;
|
||||
|
||||
NRF_RNG->CONFIG = RNG_CONFIG_DERCEN_Msk;
|
||||
NRF_RNG->EVENTS_VALRDY = 0;
|
||||
NRF_RNG->INTENSET = RNG_INTENSET_VALRDY_Msk;
|
||||
|
||||
NVIC_SetPriority(RNG_IRQn, 2);
|
||||
NVIC_EnableIRQ(RNG_IRQn);
|
||||
|
||||
NRF_RNG->TASKS_START = 1;
|
||||
}
|
||||
|
||||
uint32_t rand_get(uint8_t octets, uint8_t *rand)
|
||||
{
|
||||
uint8_t reserved;
|
||||
uint8_t first;
|
||||
|
||||
while (octets) {
|
||||
if (_rand->first == _rand->last) {
|
||||
break;
|
||||
}
|
||||
|
||||
rand[--octets] = _rand->rand[_rand->first];
|
||||
|
||||
first = _rand->first + 1;
|
||||
if (first == _rand->count) {
|
||||
first = 0;
|
||||
}
|
||||
_rand->first = first;
|
||||
}
|
||||
|
||||
reserved = RAND_RESERVED;
|
||||
first = _rand->first;
|
||||
while (reserved--) {
|
||||
if (first == _rand->last) {
|
||||
NRF_RNG->TASKS_START = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
first++;
|
||||
if (first == _rand->count) {
|
||||
first = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return octets;
|
||||
}
|
||||
|
||||
void rng_isr(void)
|
||||
{
|
||||
if (NRF_RNG->EVENTS_VALRDY) {
|
||||
uint8_t last;
|
||||
|
||||
last = _rand->last + 1;
|
||||
if (last == _rand->count) {
|
||||
last = 0;
|
||||
}
|
||||
|
||||
if (last == _rand->first) {
|
||||
/* this condition should not happen
|
||||
* , but due to probable bug in HW
|
||||
* , new value could be generated
|
||||
* before task is stopped.
|
||||
*/
|
||||
NRF_RNG->TASKS_STOP = 1;
|
||||
NRF_RNG->EVENTS_VALRDY = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_rand->rand[_rand->last] = NRF_RNG->VALUE;
|
||||
_rand->last = last;
|
||||
|
||||
last = _rand->last + 1;
|
||||
if (last == _rand->count) {
|
||||
last = 0;
|
||||
}
|
||||
|
||||
NRF_RNG->EVENTS_VALRDY = 0;
|
||||
|
||||
if (last == _rand->first) {
|
||||
NRF_RNG->TASKS_STOP = 1;
|
||||
}
|
||||
}
|
||||
}
|
25
drivers/bluetooth/controller/hal/rand.h
Normal file
25
drivers/bluetooth/controller/hal/rand.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _RAND_H_
|
||||
#define _RAND_H_
|
||||
|
||||
void rand_init(uint8_t *context, uint8_t context_len);
|
||||
uint32_t rand_get(uint8_t octets, uint8_t *rand);
|
||||
void rng_isr(void);
|
||||
|
||||
#endif /* _RAND_H_ */
|
68
drivers/bluetooth/controller/hal/rtc.c
Normal file
68
drivers/bluetooth/controller/hal/rtc.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "nrf.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/* RTC instance to use */
|
||||
#define NRF_RTC NRF_RTC0
|
||||
|
||||
static uint8_t _rtc_refcount;
|
||||
|
||||
void rtc_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);
|
||||
}
|
||||
|
||||
uint32_t rtc_start(void)
|
||||
{
|
||||
if (_rtc_refcount++) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
NRF_RTC->TASKS_START = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t rtc_stop(void)
|
||||
{
|
||||
ASSERT(_rtc_refcount);
|
||||
|
||||
if (--_rtc_refcount) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
NRF_RTC->TASKS_STOP = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t rtc_tick_get(void)
|
||||
{
|
||||
return NRF_RTC->COUNTER;
|
||||
}
|
||||
|
||||
void rtc_compare_set(uint8_t instance, uint32_t value)
|
||||
{
|
||||
NRF_RTC->CC[instance] = value;
|
||||
}
|
Loading…
Reference in a new issue