diff options
Diffstat (limited to 'src/libs/mynewt-nimble/nimble/transport')
33 files changed, 3500 insertions, 29 deletions
diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/.gitignore b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/.gitignore new file mode 100644 index 00000000..bba9f995 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/.gitignore @@ -0,0 +1,2 @@ +/src/libble_stack_da1469x.a + diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/diag/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/diag/pkg.yml new file mode 100644 index 00000000..9b9ee83e --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/diag/pkg.yml @@ -0,0 +1,28 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +pkg.name: nimble/transport/dialog_cmac/cmac_driver/diag +pkg.description: Default diag configuration for CMAC +pkg.author: "Apache Mynewt <dev@mynewt.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - dialog + - da1469x + - cmac +pkg.apis: dialog_cmac_diag diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/diag/src/cmac_diag.c b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/diag/src/cmac_diag.c new file mode 100644 index 00000000..4f754706 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/diag/src/cmac_diag.c @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 "syscfg/syscfg.h" +#include "mcu/mcu.h" + +#if MYNEWT_VAL(BLE_HOST) +void +cmac_diag_setup_host(void) +{ + /* Setup pins for diagnostic signals */ + mcu_gpio_set_pin_function(42, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAG0); /* DIAG_0 @ P1.10 */ + mcu_gpio_set_pin_function(43, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAG1); /* DIAG_1 @ P1.11 */ + mcu_gpio_set_pin_function(44, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAG2); /* DIAG_2 @ P1.12 */ + mcu_gpio_set_pin_function(24, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_3 @ P0.24 */ + mcu_gpio_set_pin_function(21, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_4 @ P0.21 */ + mcu_gpio_set_pin_function(20, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_5 @ P0.20 */ + mcu_gpio_set_pin_function(19, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_6 @ P0.19 */ + mcu_gpio_set_pin_function(18, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_7 @ P0.18 */ + mcu_gpio_set_pin_function(31, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_8 @ P0.31 */ + mcu_gpio_set_pin_function(30, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_9 @ P0.30 */ + mcu_gpio_set_pin_function(29, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_10 @ P0.29 */ + mcu_gpio_set_pin_function(28, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_11 @ P0.28 */ + mcu_gpio_set_pin_function(27, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_12 @ P0.27 */ + mcu_gpio_set_pin_function(26, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_13 @ P0.26 */ + mcu_gpio_set_pin_function(38, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_14 @ P1.06 */ + mcu_gpio_set_pin_function(41, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_15 @ P1.09 */ +} +#endif + +#if MYNEWT_VAL(BLE_CONTROLLER) +void +cmac_diag_setup_cmac(void) +{ + MCU_DIAG_MAP( 0, 4, DSER); + MCU_DIAG_MAP( 1, 6, CMAC_ON_ERROR); + MCU_DIAG_MAP( 2, 2, PHY_TX_EN); + MCU_DIAG_MAP( 3, 2, PHY_RX_EN); + MCU_DIAG_MAP( 4, 2, PHY_TXRX_DATA_COMB); + MCU_DIAG_MAP( 5, 2, PHY_TXRX_DATA_EN_COMB); + MCU_DIAG_MAP( 6, 5, EV1US_FRAME_START); + MCU_DIAG_MAP( 7, 5, EV_BS_START); + MCU_DIAG_MAP( 8, 5, EV1C_BS_STOP); + MCU_DIAG_MAP( 9, 5, EV1US_PHY_TO_IDLE); + MCU_DIAG_MAP(10, 9, CALLBACK_IRQ); + MCU_DIAG_MAP(11, 9, FIELD_IRQ); + MCU_DIAG_MAP(12, 9, FRAME_IRQ); + MCU_DIAG_MAP(13, 3, SLP_TIMER_ACTIVE); + MCU_DIAG_MAP(14, 4, SLEEPING); + MCU_DIAG_MAP(15, 8, LL_TIMER1_00); +} +#endif diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_diag.h b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_diag.h new file mode 100644 index 00000000..dc6ee903 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_diag.h @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 __MCU_CMAC_DIAG_H_ +#define __MCU_CMAC_DIAG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void cmac_diag_setup_host(void); +void cmac_diag_setup_cmac(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __MCU_CMAC_DIAG_H_ */ diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_host.h b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_host.h new file mode 100644 index 00000000..50d86755 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_host.h @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 __DA1469X_CMAC_V2_H_ +#define __DA1469X_CMAC_V2_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void cmac_host_init(void); +void cmac_host_signal2cmac(void); +void cmac_host_rf_calibrate(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __DA1469X_CMAC_V2_H_ */ diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_shared.h b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_shared.h new file mode 100644 index 00000000..90b5827d --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_shared.h @@ -0,0 +1,193 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 __MCU_CMAC_SHARED_H_ +#define __MCU_CMAC_SHARED_H_ + +#include <stdint.h> +#include "syscfg/syscfg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CMAC_SHARED_MAGIC_CMAC (0x4C6C) /* "lL" */ +#define CMAC_SHARED_MAGIC_SYS (0x5368) /* "hS" */ + +#define CMAC_SHARED_F_SYS_LPCLK_AVAILABLE (0x0001) + +/* + * Simple circular buffer for storing random numbers generated by M33 + * Empty: cmr_in = cmr_out = 0; + * Full: cmr_in + 1 = cmr_out + * + * cmr_in: used by the M33 to add random numbers to the circular buffer. + * cmr_out: used by CMAC to retrieve random numbers + * + * NOTE: cmr_in and cmr_out are indices. + */ +#define CMAC_RAND_BUF_ELEMS (16) + +struct cmac_rand { + int cmr_active; + int cmr_in; + int cmr_out; + uint32_t cmr_buf[CMAC_RAND_BUF_ELEMS]; +}; + +struct cmac_mbox { + uint16_t rd_off; + uint16_t wr_off; +}; + +struct cmac_dcdc { + uint8_t enabled; + uint32_t v18; + uint32_t v18p; + uint32_t vdd; + uint32_t v14; + uint32_t ctrl1; +}; + +struct cmac_trim { + uint8_t rfcu_len; + uint8_t rfcu_mode1_len; + uint8_t rfcu_mode2_len; + uint8_t synth_len; + uint32_t rfcu[ MYNEWT_VAL(CMAC_TRIM_SIZE_RFCU) ]; + uint32_t rfcu_mode1[2]; + uint32_t rfcu_mode2[2]; + uint32_t synth[ MYNEWT_VAL(CMAC_TRIM_SIZE_SYNTH) ]; +}; + +#if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) +struct cmac_debug { + int8_t last_rx_rssi; + int8_t tx_power_override; + + uint32_t cal_res_1; + uint32_t cal_res_2; + uint32_t trim_val1_tx_1; + uint32_t trim_val1_tx_2; + uint32_t trim_val2_tx; + uint32_t trim_val2_rx; +}; +#endif + +#if MYNEWT_VAL(CMAC_DEBUG_COREDUMP_ENABLE) +struct cmac_coredump { + uint32_t lr; + uint32_t pc; + uint32_t assert; + const char *assert_file; + uint32_t assert_line; + + uint32_t CM_STAT_REG; + uint32_t CM_LL_TIMER1_36_10_REG; + uint32_t CM_LL_TIMER1_9_0_REG; + uint32_t CM_ERROR_REG; + uint32_t CM_EXC_STAT_REG; +}; +#endif + +#define CMAC_PENDING_OP_LP_CLK 0x0001 +#define CMAC_PENDING_OP_RF_CAL 0x0002 + +struct cmac_shared_data { + uint16_t magic_cmac; + uint16_t magic_sys; + uint16_t pending_ops; + uint16_t lp_clock_freq; /* LP clock frequency */ + uint32_t xtal32m_settle_us;/* XTAL32M settling time */ + struct cmac_mbox mbox_s2c; /* SYS2CMAC mailbox */ + struct cmac_mbox mbox_c2s; /* CMAC2SYS mailbox */ + struct cmac_dcdc dcdc; /* DCDC settings */ + struct cmac_trim trim; /* Trim data */ + struct cmac_rand rand; /* Random numbers */ +#if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) + struct cmac_debug debug; /* Extra debug data */ +#endif +#if MYNEWT_VAL(CMAC_DEBUG_COREDUMP_ENABLE) + struct cmac_coredump coredump; +#endif + + uint8_t mbox_s2c_buf[ MYNEWT_VAL(CMAC_MBOX_SIZE_S2C) ]; + uint8_t mbox_c2s_buf[ MYNEWT_VAL(CMAC_MBOX_SIZE_C2S) ]; +}; + +#if MYNEWT_VAL(BLE_HOST) +extern volatile struct cmac_shared_data *g_cmac_shared_data; +#elif MYNEWT_VAL(BLE_CONTROLLER) +extern volatile struct cmac_shared_data g_cmac_shared_data; +#endif + +/* cmac_mbox */ +typedef int (cmac_mbox_read_cb)(const void *data, uint16_t len); +typedef void (cmac_mbox_write_notif_cb)(void); +void cmac_mbox_set_read_cb(cmac_mbox_read_cb *cb); +void cmac_mbox_set_write_notif_cb(cmac_mbox_write_notif_cb *cb); +int cmac_mbox_read(void); +int cmac_mbox_write(const void *data, uint16_t len); + +/* cmac_rand */ +typedef void (*cmac_rand_isr_cb_t)(uint8_t rnum); +void cmac_rand_start(void); +void cmac_rand_stop(void); +void cmac_rand_read(void); +void cmac_rand_write(void); +void cmac_rand_chk_fill(void); +int cmac_rand_get_next(void); +int cmac_rand_is_active(void); +int cmac_rand_is_full(void); +void cmac_rand_fill(uint32_t *buf, int num_words); +void cmac_rand_set_isr_cb(cmac_rand_isr_cb_t cb); + +void cmac_shared_init(void); +void cmac_shared_sync(void); + +#if MYNEWT_VAL(BLE_HOST) +#define CMAC_SHARED_LOCK_VAL 0x40000000 +#elif MYNEWT_VAL(BLE_CONTROLLER) +#define CMAC_SHARED_LOCK_VAL 0xc0000000 +#endif + +static inline void +cmac_shared_lock(void) +{ + volatile uint32_t *bsr_set = (void *)0x50050074; + volatile uint32_t *bsr_stat = (void *)0x5005007c; + + while ((*bsr_stat & 0xc0000000) != CMAC_SHARED_LOCK_VAL) { + *bsr_set = CMAC_SHARED_LOCK_VAL; + } +} + +static inline void +cmac_shared_unlock(void) +{ + volatile uint32_t *bsr_reset = (void *)0x50050078; + + *bsr_reset = CMAC_SHARED_LOCK_VAL; +} + +#ifdef __cplusplus +} +#endif + +#endif /* __MCU_CMAC_SHARED_H_ */ diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/pkg.yml new file mode 100644 index 00000000..5b4a2129 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/pkg.yml @@ -0,0 +1,39 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +pkg.name: nimble/transport/dialog_cmac/cmac_driver +pkg.description: Driver for Dialog CMAC IPC +pkg.author: "Apache Mynewt <dev@mynewt.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - dialog + - da1469x + - cmac + +pkg.req_apis.CMAC_DEBUG_DIAG_ENABLE: + - dialog_cmac_diag + +pkg.ign_files.BLE_CONTROLLER: + - cmac_host.c + +pkg.post_link_cmds.BLE_CONTROLLER: + scripts/create_cmac_bin.sh: 100 + +pkg.pre_link_cmds.BLE_HOST: + scripts/build_libcmac.sh: 100 diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/scripts/build_libcmac.sh b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/scripts/build_libcmac.sh new file mode 100755 index 00000000..bbc822aa --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/scripts/build_libcmac.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +NEWT=${MYNEWT_NEWT_PATH} +OBJCOPY=${MYNEWT_OBJCOPY_PATH} +AR=${MYNEWT_AR_PATH} +LIBCMAC_A=${MYNEWT_USER_SRC_DIR}/libcmac.a + +export WORK_DIR=${MYNEWT_USER_WORK_DIR} +export BASENAME_ROM=cmac.rom +export BASENAME_RAM=cmac.ram + +if [ ${MYNEWT_VAL_CMAC_IMAGE_SINGLE} -eq 0 ]; then + # Create empty binary for ROM image (1 byte required for objcopy) + truncate -s 1 ${WORK_DIR}/${BASENAME_ROM}.bin + # Create fixed size RAM image + truncate -s ${MYNEWT_VAL_CMAC_IMAGE_RAM_SIZE} ${WORK_DIR}/${BASENAME_RAM}.bin +else + ${NEWT} build ${MYNEWT_VAL_CMAC_IMAGE_TARGET_NAME} +fi + +cd ${WORK_DIR} + +# Convert both binaries to objects and create archive to link +${OBJCOPY} -I binary -O elf32-littlearm -B armv8-m.main \ + --rename-section .data=.libcmac.rom ${BASENAME_ROM}.bin ${BASENAME_ROM}.o +${OBJCOPY} -I binary -O elf32-littlearm -B armv8-m.main \ + --rename-section .data=.libcmac.ram ${BASENAME_RAM}.bin ${BASENAME_RAM}.o +${AR} -rcs ${LIBCMAC_A} ${BASENAME_ROM}.o ${BASENAME_RAM}.o diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/scripts/create_cmac_bin.sh b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/scripts/create_cmac_bin.sh new file mode 100755 index 00000000..954d0860 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/scripts/create_cmac_bin.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +OBJCOPY=${MYNEWT_OBJCOPY_PATH} +ELF=${MYNEWT_APP_BIN_DIR}/blehci.elf + +cd ${WORK_DIR} + +# Strip .ram section from ROM image +${OBJCOPY} -R .ram -O binary ${ELF} ${BASENAME_ROM}.bin +# RAM image is the same as binary created by newt +cp ${ELF}.bin ${BASENAME_RAM}.bin + +# Create a copy of ROM image to flash to partition, if required +cp ${BASENAME_ROM}.bin ${ELF}.rom.bin diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/src/cmac_host.c b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/src/cmac_host.c new file mode 100644 index 00000000..df81c582 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/src/cmac_host.c @@ -0,0 +1,326 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 <assert.h> +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +#include "syscfg/syscfg.h" +#include "sysflash/sysflash.h" +#include "os/os.h" +#include "mcu/mcu.h" +#include "mcu/cmsis_nvic.h" +#include "mcu/da1469x_hal.h" +#include "mcu/da1469x_lpclk.h" +#include "mcu/da1469x_clock.h" +#include "mcu/da1469x_trimv.h" +#include "mcu/da1469x_pdc.h" +#include "cmac_driver/cmac_host.h" +#include "cmac_driver/cmac_shared.h" +#include "cmac_driver/cmac_diag.h" +#include "trng/trng.h" +#if MYNEWT_VAL(CMAC_DEBUG_COREDUMP_ENABLE) +#include "console/console.h" +#endif + +/* CMAC data */ +extern char _binary_cmac_rom_bin_start[]; +extern char _binary_cmac_rom_bin_end; +extern char _binary_cmac_ram_bin_start[]; +extern char _binary_cmac_ram_bin_end; + +struct cmac_image_info { + uint32_t magic; + uint32_t size_rom; + uint32_t size_ram; + uint32_t offset_data; + uint32_t offset_shared; +}; + +/* PDC entry for waking up CMAC */ +static int8_t g_cmac_host_pdc_sys2cmac; +/* PDC entry for waking up M33 */ +static int8_t g_cmac_host_pdc_cmac2sys; + +static void cmac_host_rand_fill(struct os_event *ev); +static struct os_event g_cmac_host_rand_ev = { + .ev_cb = cmac_host_rand_fill +}; + +static void cmac_host_rand_chk_fill(void); + +static void +cmac2sys_isr(void) +{ +#if MYNEWT_VAL(CMAC_DEBUG_COREDUMP_ENABLE) + volatile struct cmac_coredump *cd = &g_cmac_shared_data->coredump; + const char *assert_file; +#endif + + os_trace_isr_enter(); + + /* Clear CMAC2SYS interrupt */ + *(volatile uint32_t *)0x40002000 = 2; + + cmac_mbox_read(); + + if (*(volatile uint32_t *)0x40002000 & 0x1c00) { +#if MYNEWT_VAL(CMAC_DEBUG_COREDUMP_ENABLE) + console_blocking_mode(); + console_printf("CMAC error (0x%08lx)\n", *(volatile uint32_t *)0x40002000); + console_printf(" lr:0x%08lx pc:0x%08lx\n", cd->lr, cd->pc); + if (cd->assert) { + console_printf(" assert:0x%08lx\n", cd->assert); + if (cd->assert_file) { + /* Need to translate pointer from M0 code segment to M33 data */ + assert_file = cd->assert_file + MCU_MEM_SYSRAM_START_ADDRESS + + MEMCTRL->CMI_CODE_BASE_REG; + console_printf(" %s:%d\n", + assert_file, (unsigned)cd->assert_line); + } + } + console_printf(" 0x%08lx CM_ERROR_REG\n", cd->CM_ERROR_REG); + console_printf(" 0x%08lx CM_EXC_STAT_REG\n", cd->CM_EXC_STAT_REG); + console_printf(" 0x%08lx CM_LL_TIMER1_36_10_REG\n", cd->CM_LL_TIMER1_36_10_REG); + console_printf(" 0x%08lx CM_LL_TIMER1_9_0_REG\n", cd->CM_LL_TIMER1_9_0_REG); + + /* Spin if debugger is connected to CMAC to avoid resetting it */ + if (cd->CM_STAT_REG & 0x20) { + for (;;); + } +#endif + /* XXX CMAC is in error state, need to recover */ + assert(0); + return; + } + + cmac_host_rand_chk_fill(); + + os_trace_isr_exit(); +} + +static void +cmac_host_rand_fill(struct os_event *ev) +{ + size_t num_bytes; + struct trng_dev *trng; + uint32_t *rnum; + uint32_t rnums[CMAC_RAND_BUF_ELEMS]; + + /* Check if full */ + if (!cmac_rand_is_active() || cmac_rand_is_full()) { + return; + } + + assert(ev->ev_arg != NULL); + + /* Fill buffer with random numbers even though we may not use all of them */ + trng = ev->ev_arg; + rnum = &rnums[0]; + num_bytes = trng_read(trng, rnum, CMAC_RAND_BUF_ELEMS * sizeof(uint32_t)); + + cmac_rand_fill(rnum, num_bytes / 4); + cmac_host_signal2cmac(); +} + +static void +cmac_host_rand_chk_fill(void) +{ + if (cmac_rand_is_active() && !cmac_rand_is_full()) { + os_eventq_put(os_eventq_dflt_get(), &g_cmac_host_rand_ev); + } +} + +void +cmac_host_signal2cmac(void) +{ + da1469x_pdc_set(g_cmac_host_pdc_sys2cmac); +} + +static void +cmac_host_lpclk_cb(uint32_t freq) +{ + /* No need to wakeup CMAC if LP clock frequency did not change */ + if (g_cmac_shared_data->lp_clock_freq == freq) { + return; + } + + cmac_shared_lock(); + g_cmac_shared_data->lp_clock_freq = freq; + g_cmac_shared_data->pending_ops |= CMAC_PENDING_OP_LP_CLK; + cmac_shared_unlock(); + + cmac_host_signal2cmac(); +} + +#if MYNEWT_VAL(CMAC_DEBUG_HOST_PRINT_ENABLE) +static void +cmac_host_print_trim(const char *name, const uint32_t *tv, unsigned len) +{ + console_printf("[CMAC] Trim values for '%s'\n", name); + + while (len) { + console_printf(" 0x%08x = 0x%08x\n", (unsigned)tv[0], (unsigned)tv[1]); + len -= 2; + tv += 2; + } +} +#endif + +void +cmac_host_rf_calibrate(void) +{ + cmac_shared_lock(); + g_cmac_shared_data->pending_ops |= CMAC_PENDING_OP_RF_CAL; + cmac_shared_unlock(); + + cmac_host_signal2cmac(); +} + +void +cmac_host_init(void) +{ + struct trng_dev *trng; + struct cmac_image_info ii; + uint32_t cmac_rom_size; + uint32_t cmac_ram_size; +#if !MYNEWT_VAL(CMAC_IMAGE_SINGLE) + const struct flash_area *fa; + int rc; +#endif + struct cmac_trim *trim; + + /* Get trng os device */ + trng = (struct trng_dev *) os_dev_open("trng", OS_TIMEOUT_NEVER, NULL); + assert(trng); + g_cmac_host_rand_ev.ev_arg = trng; + +#if MYNEWT_VAL(CMAC_DEBUG_DIAG_ENABLE) + cmac_diag_setup_host(); +#endif + +#if MYNEWT_VAL(CMAC_DEBUG_SWD_ENABLE) + /* Enable CMAC debugger */ + CRG_TOP->SYS_CTRL_REG |= 0x40; /* CRG_TOP_SYS_CTRL_REG_CMAC_DEBUGGER_ENABLE_Msk */ +#endif + + /* + * Add PDC entry to wake up CMAC from M33 + * + * XXX if MCU_DEBUG_GPIO_DEEP_SLEEP is enabled on CMAC, this should also + * enable PD_COM so CMAC can access GPIOs after wake up + */ + g_cmac_host_pdc_sys2cmac = da1469x_pdc_add(MCU_PDC_TRIGGER_MAC_TIMER, + MCU_PDC_MASTER_CMAC, + MCU_PDC_EN_XTAL); + da1469x_pdc_set(g_cmac_host_pdc_sys2cmac); + da1469x_pdc_ack(g_cmac_host_pdc_sys2cmac); + + /* Add PDC entry to wake up M33 from CMAC, if does not exist yet */ + g_cmac_host_pdc_cmac2sys = da1469x_pdc_find(MCU_PDC_TRIGGER_COMBO, + MCU_PDC_MASTER_M33, 0); + if (g_cmac_host_pdc_cmac2sys < 0) { + g_cmac_host_pdc_cmac2sys = da1469x_pdc_add(MCU_PDC_TRIGGER_COMBO, + MCU_PDC_MASTER_M33, + MCU_PDC_EN_XTAL); + da1469x_pdc_set(g_cmac_host_pdc_cmac2sys); + da1469x_pdc_ack(g_cmac_host_pdc_cmac2sys); + } + + /* Setup CMAC2SYS interrupt */ + NVIC_SetVector(CMAC2SYS_IRQn, (uint32_t)cmac2sys_isr); + NVIC_SetPriority(CMAC2SYS_IRQn, MYNEWT_VAL(CMAC_CMAC2SYS_IRQ_PRIORITY)); + NVIC_DisableIRQ(CMAC2SYS_IRQn); + + /* Enable Radio LDO */ + CRG_TOP->POWER_CTRL_REG |= CRG_TOP_POWER_CTRL_REG_LDO_RADIO_ENABLE_Msk; + + /* Enable CMAC, but keep it in reset */ + CRG_TOP->CLK_RADIO_REG = (1 << CRG_TOP_CLK_RADIO_REG_RFCU_ENABLE_Pos) | + (1 << CRG_TOP_CLK_RADIO_REG_CMAC_SYNCH_RESET_Pos) | + (0 << CRG_TOP_CLK_RADIO_REG_CMAC_CLK_SEL_Pos) | + (1 << CRG_TOP_CLK_RADIO_REG_CMAC_CLK_ENABLE_Pos) | + (0 << CRG_TOP_CLK_RADIO_REG_CMAC_DIV_Pos); + + /* Calculate size of ROM and RAM area */ + cmac_rom_size = &_binary_cmac_rom_bin_end - &_binary_cmac_rom_bin_start[0]; + cmac_ram_size = &_binary_cmac_ram_bin_end - &_binary_cmac_ram_bin_start[0]; + + /* Load image header and check if image can be loaded */ +#if MYNEWT_VAL(CMAC_IMAGE_SINGLE) + memcpy(&ii, &_binary_cmac_rom_bin_start[128], sizeof(ii)); +#else + rc = flash_area_open(FLASH_AREA_IMAGE_1, &fa); + assert(rc == 0); + rc = flash_area_read(fa, 128, &ii, sizeof(ii)); + assert(rc == 0); +#endif + + assert(ii.magic == 0xC3ACC3AC); + assert(ii.size_rom == cmac_rom_size); + assert(ii.size_ram <= cmac_ram_size); + + /* Copy CMAC image to RAM */ +#if MYNEWT_VAL(CMAC_IMAGE_SINGLE) + memset(&_binary_cmac_ram_bin_start, 0xaa, cmac_ram_size); + memcpy(&_binary_cmac_ram_bin_start, &_binary_cmac_rom_bin_start, ii.size_rom); +#else + memset(&_binary_cmac_ram_bin_start, 0xaa, cmac_ram_size); + rc = flash_area_read(fa, 0, &_binary_cmac_ram_bin_start, ii.size_rom); + assert(rc == 0); +#endif + + /* Setup CMAC memory addresses */ + MEMCTRL->CMI_CODE_BASE_REG = (uint32_t)&_binary_cmac_ram_bin_start; + MEMCTRL->CMI_DATA_BASE_REG = MEMCTRL->CMI_CODE_BASE_REG + ii.offset_data; + MEMCTRL->CMI_SHARED_BASE_REG = MEMCTRL->CMI_CODE_BASE_REG + ii.offset_shared; + MEMCTRL->CMI_END_REG = MEMCTRL->CMI_CODE_BASE_REG + ii.size_ram - 1; + + /* Initialize shared memory */ + cmac_shared_init(); + + trim = (struct cmac_trim *)&g_cmac_shared_data->trim; + trim->rfcu_len = da1469x_trimv_group_read(6, trim->rfcu, ARRAY_SIZE(trim->rfcu)); + trim->rfcu_mode1_len = da1469x_trimv_group_read(8, trim->rfcu_mode1, ARRAY_SIZE(trim->rfcu_mode1)); + trim->rfcu_mode2_len = da1469x_trimv_group_read(10, trim->rfcu_mode2, ARRAY_SIZE(trim->rfcu_mode2)); + trim->synth_len = da1469x_trimv_group_read(7, trim->synth, ARRAY_SIZE(trim->synth)); + +#if MYNEWT_VAL(CMAC_DEBUG_HOST_PRINT_ENABLE) + cmac_host_print_trim("rfcu", trim->rfcu, trim->rfcu_len); + cmac_host_print_trim("rfcu_mode1", trim->rfcu_mode1, trim->rfcu_mode1_len); + cmac_host_print_trim("rfcu_mode2", trim->rfcu_mode2, trim->rfcu_mode2_len); + cmac_host_print_trim("synth", trim->synth, trim->synth_len); +#endif + + /* Release CMAC from reset and sync */ + CRG_TOP->CLK_RADIO_REG &= ~CRG_TOP_CLK_RADIO_REG_CMAC_SYNCH_RESET_Msk; + cmac_shared_sync(); + + da1469x_lpclk_register_cmac_cb(cmac_host_lpclk_cb); + +#if MYNEWT_VAL(CMAC_DEBUG_HOST_PRINT_ENABLE) && MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) + /* Trim values are calculated on RF init, so are valid after synced with CMAC */ + console_printf("[CMAC] Calculated trim_val1: 1=0x%08x 2=0x%08x\n", + (unsigned)g_cmac_shared_data->debug.trim_val1_tx_1, + (unsigned)g_cmac_shared_data->debug.trim_val1_tx_2); + console_printf("[CMAC] Calculated trim_val2: tx=0x%08x rx=0x%08x\n", + (unsigned)g_cmac_shared_data->debug.trim_val2_tx, + (unsigned)g_cmac_shared_data->debug.trim_val2_rx); +#endif +} diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/src/cmac_mbox.c b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/src/cmac_mbox.c new file mode 100644 index 00000000..9594dbe9 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/src/cmac_mbox.c @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 <assert.h> +#include <cmac_driver/cmac_shared.h> +#include <string.h> +#include <stdbool.h> +#include <stdint.h> +#include "syscfg/syscfg.h" +#include "mcu/mcu.h" +#include "os/os_arch.h" +#include "os/os.h" + +#ifndef min +#define min(_a, _b) ((_a) < (_b) ? (_a) : (_b)) +#endif + +static cmac_mbox_read_cb *g_cmac_mbox_read_cb; +static cmac_mbox_write_notif_cb *g_cmac_mbox_write_notif_cb; + +void +cmac_mbox_set_read_cb(cmac_mbox_read_cb *cb) +{ + g_cmac_mbox_read_cb = cb; +} + +void +cmac_mbox_set_write_notif_cb(cmac_mbox_write_notif_cb *cb) +{ + g_cmac_mbox_write_notif_cb = cb; +} + +int +cmac_mbox_read(void) +{ +#if MYNEWT_VAL(BLE_HOST) + volatile struct cmac_mbox *mbox = &g_cmac_shared_data->mbox_c2s; + uint8_t *mbox_buf = (uint8_t *)&g_cmac_shared_data->mbox_c2s_buf; + const uint16_t mbox_size = MYNEWT_VAL(CMAC_MBOX_SIZE_C2S); +#else + volatile struct cmac_mbox *mbox = &g_cmac_shared_data.mbox_s2c; + uint8_t *mbox_buf = (uint8_t *)&g_cmac_shared_data.mbox_s2c_buf; + const uint16_t mbox_size = MYNEWT_VAL(CMAC_MBOX_SIZE_S2C); +#endif + uint16_t rd_off; + uint16_t wr_off; + uint16_t chunk; + int len = 0; + + if (!g_cmac_mbox_read_cb) { + return 0; + } + + do { + rd_off = mbox->rd_off; + wr_off = mbox->wr_off; + + if (rd_off <= wr_off) { + chunk = wr_off - rd_off; + } else { + chunk = mbox_size - rd_off; + } + + while (chunk) { + len = g_cmac_mbox_read_cb(&mbox_buf[rd_off], chunk); + if (len < 0) { + break; + } + + rd_off += len; + chunk -= len; + } + + mbox->rd_off = rd_off == mbox_size ? 0 : rd_off; + } while ((mbox->rd_off != mbox->wr_off) && (len >= 0)); + + return 0; +} + +int +cmac_mbox_write(const void *data, uint16_t len) +{ +#if MYNEWT_VAL(BLE_HOST) + volatile struct cmac_mbox *mbox = &g_cmac_shared_data->mbox_s2c; + uint8_t *mbox_buf = (uint8_t *)&g_cmac_shared_data->mbox_s2c_buf; + const uint16_t mbox_size = MYNEWT_VAL(CMAC_MBOX_SIZE_S2C); +#else + volatile struct cmac_mbox *mbox = &g_cmac_shared_data.mbox_c2s; + uint8_t *mbox_buf = (uint8_t *)&g_cmac_shared_data.mbox_c2s_buf; + const uint16_t mbox_size = MYNEWT_VAL(CMAC_MBOX_SIZE_C2S); +#endif + uint16_t rd_off; + uint16_t wr_off; + uint16_t max_wr; + uint16_t chunk; + + while (len) { + rd_off = mbox->rd_off; + wr_off = mbox->wr_off; + + /* + * Calculate maximum length to write, i.e. up to end of buffer or stop + * before rd_off to be able to detect full queue. + */ + if (rd_off > wr_off) { + /* + * |0|1|2|3|4|5|6|7| + * | | | |W| | |R| | + * `---^ + */ + max_wr = rd_off - wr_off - 1; + } else if (rd_off == 0) { + /* + * |0|1|2|3|4|5|6|7| + * |R| | |W| | | | | + * `-------^ + */ + max_wr = mbox_size - wr_off - 1; + } else { + /* + * |0|1|2|3|4|5|6|7| + * | |R| |W| | | | | + * `---------^ + */ + max_wr = mbox_size - wr_off; + } + + chunk = min(len, max_wr); + + if (chunk == 0) { + continue; + } + + memcpy(&mbox_buf[wr_off], data, chunk); + + wr_off += chunk; + mbox->wr_off = wr_off == mbox_size ? 0 : wr_off; + + g_cmac_mbox_write_notif_cb(); + + len -= chunk; + data = (uint8_t *)data + chunk; + } + + return 0; +} diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/src/cmac_rand.c b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/src/cmac_rand.c new file mode 100644 index 00000000..67a315f9 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/src/cmac_rand.c @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 <assert.h> +#include <cmac_driver/cmac_shared.h> +#include <string.h> +#include <stdbool.h> +#include "syscfg/syscfg.h" +#include "mcu/mcu.h" +#include "os/os_arch.h" +#include "os/os.h" + +#if MYNEWT_VAL(BLE_HOST) +int +cmac_rand_is_active(void) +{ + return g_cmac_shared_data->rand.cmr_active; +} + +int +cmac_rand_is_full(void) +{ + int next; + bool rc; + + next = cmac_rand_get_next(); + if (next == g_cmac_shared_data->rand.cmr_out) { + rc = 1; + } else { + rc = 0; + } + return rc; +} + +int +cmac_rand_get_next(void) +{ + int next; + + /* If active and not full, put event on queue to get random numbers */ + next = g_cmac_shared_data->rand.cmr_in + 1; + if (next == CMAC_RAND_BUF_ELEMS) { + next = 0; + } + return next; +} + +void +cmac_rand_fill(uint32_t *buf, int num_words) +{ + int next; + + /* XXX: if words is 0, is it possible we could get into a state + where we are waiting for random numbers but M33 does not know it + has to fill any? */ + + /* NOTE: we already know the buffer is not full first time through */ + next = g_cmac_shared_data->rand.cmr_in; + while (num_words) { + g_cmac_shared_data->rand.cmr_buf[next] = buf[0]; + next = cmac_rand_get_next(); + g_cmac_shared_data->rand.cmr_in = next; + next = cmac_rand_get_next(); + if (next == g_cmac_shared_data->rand.cmr_out) { + break; + } + --num_words; + ++buf; + } +} +#endif + +#if MYNEWT_VAL(BLE_CONTROLLER) +static cmac_rand_isr_cb_t g_cmac_rand_isr_cb; + +void +cmac_rand_set_isr_cb(cmac_rand_isr_cb_t cb) +{ + g_cmac_rand_isr_cb = cb; +} + +void +cmac_rand_start(void) +{ + g_cmac_shared_data.rand.cmr_active = 1; +} + +void +cmac_rand_stop(void) +{ + g_cmac_shared_data.rand.cmr_active = 0; +} + +/** + * cmac rnum read + * + * Called during the system to cmac isr to take random numbers + * from shared memory into the BLE stack. + */ +void +cmac_rand_read(void) +{ + uint8_t bytes_left; + uint32_t rnum; + + /* Just leave if no callback. */ + if (g_cmac_rand_isr_cb == NULL) { + return; + } + + bytes_left = 0; + while (g_cmac_shared_data.rand.cmr_active) { + if (bytes_left) { + --bytes_left; + rnum >>= 8; + } else if (g_cmac_shared_data.rand.cmr_out != g_cmac_shared_data.rand.cmr_in) { + bytes_left = 3; + rnum = g_cmac_shared_data.rand.cmr_buf[g_cmac_shared_data.rand.cmr_out]; + ++g_cmac_shared_data.rand.cmr_out; + if (g_cmac_shared_data.rand.cmr_out == CMAC_RAND_BUF_ELEMS) { + g_cmac_shared_data.rand.cmr_out = 0; + } + } else { + break; + } + (*g_cmac_rand_isr_cb)((uint8_t)rnum); + } +} +#endif diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/src/cmac_shared.c b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/src/cmac_shared.c new file mode 100644 index 00000000..24640ca4 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/src/cmac_shared.c @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 "syscfg/syscfg.h" +#if MYNEWT_VAL(BLE_CONTROLLER) && !MYNEWT_VAL(MCU_DEBUG_DSER_CMAC_SHARED) +#define MCU_DIAG_SER_DISABLE +#endif + +#include <assert.h> +#include <string.h> +#include <stdbool.h> +#include "mcu/mcu.h" +#include <cmac_driver/cmac_shared.h> +#include "os/os_arch.h" +#include "os/os.h" + +#ifndef min +#define min(_a, _b) ((_a) < (_b) ? (_a) : (_b)) +#endif + +#if MYNEWT_VAL(BLE_HOST) +volatile struct cmac_shared_data *g_cmac_shared_data; +#include "mcu/da1469x_clock.h" +#define MCU_DIAG_SER(_x) +#elif MYNEWT_VAL(BLE_CONTROLLER) +volatile struct cmac_shared_data g_cmac_shared_data __attribute__((section(".shdata"))); +#endif + +void +cmac_shared_init(void) +{ +#if MYNEWT_VAL(BLE_HOST) + g_cmac_shared_data = (void *)(MCU_MEM_SYSRAM_START_ADDRESS + + MEMCTRL->CMI_SHARED_BASE_REG); + + memset((void *)g_cmac_shared_data, 0, sizeof(*g_cmac_shared_data)); + + g_cmac_shared_data->xtal32m_settle_us = MYNEWT_VAL(MCU_CLOCK_XTAL32M_SETTLE_TIME_US); + + g_cmac_shared_data->dcdc.enabled = DCDC->DCDC_CTRL1_REG & DCDC_DCDC_CTRL1_REG_DCDC_ENABLE_Msk; + if (g_cmac_shared_data->dcdc.enabled) { + g_cmac_shared_data->dcdc.v18 = DCDC->DCDC_V18_REG; + g_cmac_shared_data->dcdc.v18p = DCDC->DCDC_V18P_REG; + g_cmac_shared_data->dcdc.vdd = DCDC->DCDC_VDD_REG; + g_cmac_shared_data->dcdc.v14 = DCDC->DCDC_V14_REG; + g_cmac_shared_data->dcdc.ctrl1 = DCDC->DCDC_CTRL1_REG; + } + +#if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) + g_cmac_shared_data->debug.tx_power_override = INT8_MAX; +#endif +#endif +} + + +void +cmac_shared_sync(void) +{ + /* + * We need to guarantee proper order of initialization here, i.e. SYS has + * to wait until CMAC finished initialization as otherwise host may start + * sending HCI packets which will timeout as there is no one to read them. + */ +#if MYNEWT_VAL(BLE_HOST) + assert(g_cmac_shared_data->magic_sys == 0); + + while (g_cmac_shared_data->magic_cmac != CMAC_SHARED_MAGIC_CMAC); + g_cmac_shared_data->magic_sys = CMAC_SHARED_MAGIC_SYS; + + NVIC_EnableIRQ(CMAC2SYS_IRQn); +#endif + +#if MYNEWT_VAL(BLE_CONTROLLER) + assert(g_cmac_shared_data.magic_cmac == 0); + + g_cmac_shared_data.magic_cmac = CMAC_SHARED_MAGIC_CMAC; + while (g_cmac_shared_data.magic_sys != CMAC_SHARED_MAGIC_SYS); + + NVIC_SetPriority(SYS2CMAC_IRQn, 3); + NVIC_EnableIRQ(SYS2CMAC_IRQn); +#endif +} diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/syscfg.yml b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/syscfg.yml new file mode 100644 index 00000000..a382c424 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/cmac_driver/syscfg.yml @@ -0,0 +1,104 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +syscfg.defs: + CMAC_MBOX_SIZE_S2C: + description: > + Size of mailbox for SYS to CMAC data. The size + value should be power of 2 to allow for better + code optimization. + value: 128 + CMAC_MBOX_SIZE_C2S: + description: > + Size of mailbox for CMAC to SYS data. The size + value should be power of 2 to allow for better + code optimization. + value: 128 + + CMAC_TRIM_SIZE_RFCU: + description: > + Size of trim values for RFCU. This is maximum + number of trim values that can be read from + OTP and applied, all excessive values will be + discarded. + value: 10 + CMAC_TRIM_SIZE_SYNTH: + description: > + Size of trim values for RFCU. This is maximum + number of trim values that can be read from + OTP and applied, all excessive values will be + discarded. + value: 10 + + CMAC_DEBUG_SWD_ENABLE: + description: > + Enable CMAC SWD interface. + value: 0 + CMAC_DEBUG_DIAG_ENABLE: + description: > + Enable CMAC diagnostic lines. + value: 0 + CMAC_DEBUG_DATA_ENABLE: + description: > + Enable extra debugging data in shared segment. + value: 0 + CMAC_DEBUG_COREDUMP_ENABLE: + description: > + Enable dumping CMAC registers to shared segment + on fault. + value: 1 + CMAC_DEBUG_HOST_PRINT_ENABLE: + description: > + Enable some debug printouts to console from host side. + This will dump some settings during startup, useful to + check what is loaded to CMAC via shared data. + value: 0 + + CMAC_IMAGE_SINGLE: + description: > + When enable, CMAC binary is linked with application image + creating a single image build. See CMAC_IMAGE_TARGET_NAME. + When disabled, CMAC binary is built and flashed separately + to flash partition. See CMAC_IMAGE_PARTITION. + value: 1 + CMAC_IMAGE_TARGET_NAME: + description: > + Target name to build for CMAC binary for single image build. + value: "@apache-mynewt-nimble/targets/dialog_cmac" + CMAC_IMAGE_PARTITION: + description: > + Flash partition to load CMAC binary from if single image build + is disabled. + value: FLASH_AREA_IMAGE_1 + CMAC_IMAGE_RAM_SIZE: + description: > + Size of RAM area in bytes reserved for CMAC if single image + build is disabled. Unit suffix (K, M) is allowed. + Note: for single image build this setting is not applicable + since proper RAM area size is automatically calculated from + CMAC binary. + value: 128K + + CMAC_CMAC2SYS_IRQ_PRIORITY: + description: > + The priority of the CMAC2SYS IRQ. Default is 0, or highest + priority. + value: 0 + +syscfg.restrictions.BLE_HOST: + - TRNG diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/pkg.yml new file mode 100644 index 00000000..ef8fc1ee --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/pkg.yml @@ -0,0 +1,36 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +pkg.name: nimble/transport/dialog_cmac +pkg.description: HCI H4 transport for Dialog CMAC +pkg.author: "Apache Mynewt <dev@mynewt.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + +pkg.deps: + - nimble + - nimble/transport/dialog_cmac/cmac_driver + +pkg.apis: + - ble_transport + +pkg.init: + ble_hci_cmac_init: 100 diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_cmac_common.c b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_cmac_common.c new file mode 100644 index 00000000..665b6216 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_cmac_common.c @@ -0,0 +1,194 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 <assert.h> +#include <string.h> + +#include "syscfg/syscfg.h" +#include "os/mynewt.h" +#include "nimble/ble.h" +#include "nimble/ble_hci_trans.h" +#include "nimble/hci_common.h" +#include "ble_hci_cmac_priv.h" + +/* + * If controller-to-host flow control is enabled we need to hold an extra command + * buffer for HCI_Host_Number_Of_Completed_Packets which can be sent at any time. + */ +#if MYNEWT_VAL(BLE_HS_FLOW_CTRL) || MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) +#define HCI_CMD_COUNT 2 +#else +#define HCI_CMD_COUNT 1 +#endif + +#define POOL_ACL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) + \ + BLE_MBUF_MEMBLOCK_OVERHEAD + \ + BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT) + +static uint8_t ble_hci_pool_cmd_mempool_buf[ + OS_MEMPOOL_BYTES(HCI_CMD_COUNT, BLE_HCI_TRANS_CMD_SZ)]; +static struct os_mempool ble_hci_pool_cmd_mempool; + +static uint8_t ble_hci_pool_evt_hi_mempool_buf[ + OS_MEMPOOL_BYTES(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))]; +static struct os_mempool ble_hci_pool_evt_hi_mempool; + +static uint8_t ble_hci_pool_evt_lo_mempool_buf[ + OS_MEMPOOL_BYTES(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))]; +static struct os_mempool ble_hci_pool_evt_lo_mempool; + +static uint8_t ble_hci_pool_acl_mempool_buf[ + OS_MEMPOOL_BYTES(MYNEWT_VAL(BLE_ACL_BUF_COUNT), + POOL_ACL_BLOCK_SIZE)]; +static struct os_mempool_ext ble_hci_pool_acl_mempool; +static struct os_mbuf_pool ble_hci_pool_acl_mbuf_pool; + +__attribute__((weak)) void ble_hci_trans_notify_free(void); + +static os_mempool_put_fn *g_ble_hci_pool_acl_mempool_put_cb; +static void *g_ble_hci_pool_acl_mempool_put_arg; + +int +ble_hci_trans_reset(void) +{ + return 0; +} + +uint8_t * +ble_hci_trans_buf_alloc(int type) +{ + uint8_t *buf; + + switch (type) { + case BLE_HCI_TRANS_BUF_CMD: + buf = os_memblock_get(&ble_hci_pool_cmd_mempool); + break; + case BLE_HCI_TRANS_BUF_EVT_HI: + buf = os_memblock_get(&ble_hci_pool_evt_hi_mempool); + if (buf) { + break; + } + /* no break */ + case BLE_HCI_TRANS_BUF_EVT_LO: + buf = os_memblock_get(&ble_hci_pool_evt_lo_mempool); + break; + default: + assert(0); + buf = NULL; + } + + return buf; +} + +void +ble_hci_trans_buf_free(uint8_t *buf) +{ + int rc; + + if (os_memblock_from(&ble_hci_pool_cmd_mempool, buf)) { + rc = os_memblock_put(&ble_hci_pool_cmd_mempool, buf); + assert(rc == 0); + } else if (os_memblock_from(&ble_hci_pool_evt_hi_mempool, buf)) { + rc = os_memblock_put(&ble_hci_pool_evt_hi_mempool, buf); + assert(rc == 0); + } else { + assert(os_memblock_from(&ble_hci_pool_evt_lo_mempool, buf)); + rc = os_memblock_put(&ble_hci_pool_evt_lo_mempool, buf); + assert(rc == 0); + } + + ble_hci_trans_notify_free(); +} + +struct os_mbuf * +ble_hci_cmac_alloc_acl_mbuf(void) +{ + return os_mbuf_get_pkthdr(&ble_hci_pool_acl_mbuf_pool, + sizeof(struct ble_mbuf_hdr)); +} + +static os_error_t +ble_hci_cmac_free_acl_cb(struct os_mempool_ext *mpe, void *data, void *arg) +{ + int rc; + + if (g_ble_hci_pool_acl_mempool_put_cb) { + rc = g_ble_hci_pool_acl_mempool_put_cb(mpe, data, + g_ble_hci_pool_acl_mempool_put_arg); + } else { + rc = os_memblock_put_from_cb(&mpe->mpe_mp, data); + } + + if (rc != 0) { + return rc; + } + + ble_hci_trans_notify_free(); + + return 0; +} + + +int +ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg) +{ + g_ble_hci_pool_acl_mempool_put_cb = cb; + g_ble_hci_pool_acl_mempool_put_arg = arg; + + return 0; +} + +void +ble_hci_cmac_init(void) +{ + int rc; + + SYSINIT_ASSERT_ACTIVE(); + + rc = os_mempool_init(&ble_hci_pool_cmd_mempool, + HCI_CMD_COUNT, BLE_HCI_TRANS_CMD_SZ, + ble_hci_pool_cmd_mempool_buf, "ble_hci_cmd"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&ble_hci_pool_evt_hi_mempool, + MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), + ble_hci_pool_evt_hi_mempool_buf, "ble_hci_evt_hi"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&ble_hci_pool_evt_lo_mempool, + MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), + ble_hci_pool_evt_lo_mempool_buf, "ble_hci_evt_lo"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_ext_init(&ble_hci_pool_acl_mempool, + MYNEWT_VAL(BLE_ACL_BUF_COUNT), POOL_ACL_BLOCK_SIZE, + ble_hci_pool_acl_mempool_buf, "ble_hci_acl"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mbuf_pool_init(&ble_hci_pool_acl_mbuf_pool, + &ble_hci_pool_acl_mempool.mpe_mp, POOL_ACL_BLOCK_SIZE, + MYNEWT_VAL(BLE_ACL_BUF_COUNT)); + SYSINIT_PANIC_ASSERT(rc == 0); + + ble_hci_pool_acl_mempool.mpe_put_cb = ble_hci_cmac_free_acl_cb; +} diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_cmac_hs.c b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_cmac_hs.c new file mode 100644 index 00000000..1164fe71 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_cmac_hs.c @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 <assert.h> +#include <string.h> +#include "syscfg/syscfg.h" + +#if MYNEWT_VAL(BLE_HOST) + +#include "cmac_driver/cmac_shared.h" +#include "cmac_driver/cmac_host.h" +#include "nimble/ble_hci_trans.h" +#include "os/os_mbuf.h" +#include "ble_hci_trans_h4.h" +#include "ble_hci_cmac_priv.h" + +struct ble_hci_cmac_hs_api { + ble_hci_trans_rx_cmd_fn *evt_cb; + void *evt_arg; + ble_hci_trans_rx_acl_fn *acl_cb; + void *acl_arg; +}; + +static struct ble_hci_cmac_hs_api g_ble_hci_cmac_hs_api; +static struct ble_hci_trans_h4_rx_state g_ble_hci_cmac_hs_rx_state; +static bool g_ble_hci_cmac_hs_read_err; + +static int +ble_hci_cmac_hs_frame_cb(uint8_t pkt_type, void *data) +{ + int rc; + + switch (pkt_type) { + case BLE_HCI_TRANS_H4_PKT_TYPE_ACL: + rc = g_ble_hci_cmac_hs_api.acl_cb(data, g_ble_hci_cmac_hs_api.acl_arg); + break; + case BLE_HCI_TRANS_H4_PKT_TYPE_EVT: + rc = g_ble_hci_cmac_hs_api.evt_cb(data, g_ble_hci_cmac_hs_api.evt_arg); + break; + default: + assert(0); + break; + } + + return rc; +} + +static int +ble_hci_cmac_hs_mbox_read_cb(const void *data, uint16_t len) +{ + int rlen; + os_sr_t sr; + + rlen = ble_hci_trans_h4_rx(&g_ble_hci_cmac_hs_rx_state, data, len, + ble_hci_cmac_hs_frame_cb); + if (rlen < 0) { + /* + * There was oom error, we need to wait for buffer to be freed and + * trigger another read. + */ + OS_ENTER_CRITICAL(sr); + g_ble_hci_cmac_hs_read_err = true; + OS_EXIT_CRITICAL(sr); + } + + return rlen; +} + +static void +ble_hci_cmac_hs_mbox_write_notif_cb(void) +{ + cmac_host_signal2cmac(); +} + +int +ble_hci_trans_hs_cmd_tx(uint8_t *cmd) +{ + uint8_t pkt_type = BLE_HCI_TRANS_H4_PKT_TYPE_CMD; + + cmac_mbox_write(&pkt_type, sizeof(pkt_type)); + cmac_mbox_write(cmd, cmd[2] + 3); + + ble_hci_trans_buf_free(cmd); + + return 0; +} + +int +ble_hci_trans_hs_acl_tx(struct os_mbuf *om) +{ + uint8_t pkt_type = BLE_HCI_TRANS_H4_PKT_TYPE_ACL; + struct os_mbuf *om_next; + + cmac_mbox_write(&pkt_type, sizeof(pkt_type)); + + while (om) { + om_next = SLIST_NEXT(om, om_next); + + cmac_mbox_write(om->om_data, om->om_len); + + os_mbuf_free(om); + om = om_next; + } + + return 0; +} + +void +ble_hci_trans_notify_free(void) +{ + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + if (g_ble_hci_cmac_hs_read_err) { + g_ble_hci_cmac_hs_read_err = false; + /* Just trigger an interrupt, it will trigger read */ + NVIC_SetPendingIRQ(CMAC2SYS_IRQn); + } + OS_EXIT_CRITICAL(sr); +} + +void +ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *evt_cb, void *evt_arg, + ble_hci_trans_rx_acl_fn *acl_cb, void *acl_arg) +{ + g_ble_hci_cmac_hs_api.evt_cb = evt_cb; + g_ble_hci_cmac_hs_api.evt_arg = evt_arg; + g_ble_hci_cmac_hs_api.acl_cb = acl_cb; + g_ble_hci_cmac_hs_api.acl_arg = acl_arg; + + /* We can now handle data from CMAC, initialize it */ + cmac_mbox_set_read_cb(ble_hci_cmac_hs_mbox_read_cb); + cmac_mbox_set_write_notif_cb(ble_hci_cmac_hs_mbox_write_notif_cb); + cmac_host_init(); +} + +#endif diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_cmac_ll.c b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_cmac_ll.c new file mode 100644 index 00000000..3531529c --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_cmac_ll.c @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 "syscfg/syscfg.h" + +#if MYNEWT_VAL(BLE_CONTROLLER) + +#if !MYNEWT_VAL(MCU_DEBUG_DSER_BLE_HCI_CMAC_LL) +#define MCU_DIAG_SER_DISABLE +#endif + +#include <assert.h> +#include <string.h> +#include "mcu/mcu.h" +#include "cmac_driver/cmac_shared.h" +#include "nimble/ble_hci_trans.h" +#include "os/os_mbuf.h" +#include "ble_hci_trans_h4.h" +#include "ble_hci_cmac_priv.h" + +struct ble_hci_cmac_ll_api { + ble_hci_trans_rx_cmd_fn *cmd_cb; + void *cmd_arg; + ble_hci_trans_rx_acl_fn *acl_cb; + void *acl_arg; +}; + +static struct ble_hci_cmac_ll_api g_ble_hci_cmac_ll_api; +static struct ble_hci_trans_h4_rx_state g_ble_hci_cmac_ll_rx_state; + +static int +ble_hci_cmac_ll_frame_cb(uint8_t pkt_type, void *data) +{ + int rc; + + MCU_DIAG_SER('F'); + + switch (pkt_type) { + case BLE_HCI_TRANS_H4_PKT_TYPE_CMD: + rc = g_ble_hci_cmac_ll_api.cmd_cb(data, g_ble_hci_cmac_ll_api.cmd_arg); + break; + case BLE_HCI_TRANS_H4_PKT_TYPE_ACL: + rc = g_ble_hci_cmac_ll_api.acl_cb(data, g_ble_hci_cmac_ll_api.acl_arg); + break; + default: + assert(0); + break; + } + + return rc; +} + +static int +ble_hci_cmac_ll_mbox_read_cb(const void *data, uint16_t len) +{ + int rlen; + + MCU_DIAG_SER('R'); + rlen = ble_hci_trans_h4_rx(&g_ble_hci_cmac_ll_rx_state, data, len, + ble_hci_cmac_ll_frame_cb); + + /* There should be no oom on LL side due to flow control used */ + assert(rlen >= 0); + + return rlen; +} + +static void +ble_hci_cmac_ll_mbox_write_notif_cb(void) +{ + MCU_DIAG_SER('W'); + CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV1C_CMAC2SYS_IRQ_SET_Msk; +} + +int +ble_hci_trans_ll_evt_tx(uint8_t *evt) +{ + uint8_t pkt_type = BLE_HCI_TRANS_H4_PKT_TYPE_EVT; + + cmac_mbox_write(&pkt_type, sizeof(pkt_type)); + cmac_mbox_write(evt, evt[1] + 2); + + ble_hci_trans_buf_free(evt); + + return 0; +} + +int +ble_hci_trans_ll_acl_tx(struct os_mbuf *om) +{ + uint8_t pkt_type = BLE_HCI_TRANS_H4_PKT_TYPE_ACL; + struct os_mbuf *om_next; + + cmac_mbox_write(&pkt_type, sizeof(pkt_type)); + + while (om) { + om_next = SLIST_NEXT(om, om_next); + + cmac_mbox_write(om->om_data, om->om_len); + + os_mbuf_free(om); + om = om_next; + } + + return 0; +} + +void +ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb, void *cmd_arg, + ble_hci_trans_rx_acl_fn *acl_cb, void *acl_arg) +{ + g_ble_hci_cmac_ll_api.cmd_cb = cmd_cb; + g_ble_hci_cmac_ll_api.cmd_arg = cmd_arg; + g_ble_hci_cmac_ll_api.acl_cb = acl_cb; + g_ble_hci_cmac_ll_api.acl_arg = acl_arg; + + /* Setup callbacks for mailboxes */ + cmac_mbox_set_read_cb(ble_hci_cmac_ll_mbox_read_cb); + cmac_mbox_set_write_notif_cb(ble_hci_cmac_ll_mbox_write_notif_cb); + + /* Synchronize with SYS */ + cmac_shared_sync(); +} + +#endif diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_cmac_priv.h b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_cmac_priv.h new file mode 100644 index 00000000..451053c3 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_cmac_priv.h @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 _BLE_HCI_CMAC_PRIV_H_ +#define _BLE_HCI_CMAC_PRIV_H_ + +#include "os/os_mbuf.h" + +struct os_mbuf *ble_hci_cmac_alloc_acl_mbuf(void); + +void ble_hci_trans_notify_free(void); + +#endif /* _BLE_HCI_CMAC_PRIV_H_ */ diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_trans_h4.c b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_trans_h4.c new file mode 100644 index 00000000..74da3912 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_trans_h4.c @@ -0,0 +1,332 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 <assert.h> +#include <stdbool.h> +#include <string.h> +#include "syscfg/syscfg.h" +#include "os/os_mbuf.h" +#include "nimble/ble_hci_trans.h" +#include "nimble/hci_common.h" +#include "ble_hci_trans_h4.h" +#include "ble_hci_cmac_priv.h" + +#define RXS_STATE_W4_PKT_TYPE 0 +#define RXS_STATE_W4_HEADER 1 +#define RXS_STATE_W4_PAYLOAD 2 +#define RXS_STATE_COMPLETED 3 + +struct input_buffer { + const uint8_t *buf; + uint16_t len; +}; + +static int +ble_hci_trans_h4_ib_adjust(struct input_buffer *ib, uint16_t len) +{ + assert(ib->len >= len); + + ib->buf += len; + ib->len -= len; + + return len; +} + +static void +ble_hci_trans_h4_rxs_start(struct ble_hci_trans_h4_rx_state *rxs, uint8_t pkt_type) +{ + rxs->pkt_type = pkt_type; + rxs->len = 0; + rxs->expected_len = 0; + + switch (rxs->pkt_type) { +#if MYNEWT_VAL(BLE_CONTROLLER) + case BLE_HCI_TRANS_H4_PKT_TYPE_CMD: + rxs->min_len = 3; + break; +#endif + case BLE_HCI_TRANS_H4_PKT_TYPE_ACL: + rxs->min_len = 4; + break; +#if MYNEWT_VAL(BLE_HOST) + case BLE_HCI_TRANS_H4_PKT_TYPE_EVT: + rxs->min_len = 2; + break; +#endif + default: + /* XXX sync loss */ + assert(0); + break; + } +} + +static int +ble_hci_trans_h4_pull_min_len(struct ble_hci_trans_h4_rx_state *rxs, + struct input_buffer *ib) +{ + uint16_t len; + + len = min(ib->len, rxs->min_len - rxs->len); + memcpy(&rxs->hdr[rxs->len], ib->buf, len); + + rxs->len += len; + ble_hci_trans_h4_ib_adjust(ib, len); + + return rxs->len != rxs->min_len; +} + +static int +ble_hci_trans_h4_rx_state_w4_header(struct ble_hci_trans_h4_rx_state *rxs, + struct input_buffer *ib) +{ +#if MYNEWT_VAL(BLE_HOST) + int pool; +#endif + int rc; + + rc = ble_hci_trans_h4_pull_min_len(rxs, ib); + if (rc) { + /* need more data */ + return 1; + } + + switch (rxs->pkt_type) { +#if MYNEWT_VAL(BLE_CONTROLLER) + case BLE_HCI_TRANS_H4_PKT_TYPE_CMD: + rxs->buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); + if (!rxs->buf) { + return -1; + } + + memcpy(rxs->buf, rxs->hdr, rxs->len); + rxs->expected_len = rxs->hdr[2] + 3; + break; +#endif + case BLE_HCI_TRANS_H4_PKT_TYPE_ACL: + rxs->om = ble_hci_cmac_alloc_acl_mbuf(); + if (!rxs->om) { + return -1; + } + + os_mbuf_append(rxs->om, rxs->hdr, rxs->len); + rxs->expected_len = get_le16(&rxs->hdr[2]) + 4; + break; +#if MYNEWT_VAL(BLE_HOST) + case BLE_HCI_TRANS_H4_PKT_TYPE_EVT: + pool = BLE_HCI_TRANS_BUF_EVT_HI; + if (rxs->hdr[0] == BLE_HCI_EVCODE_LE_META) { + /* For LE Meta event we need 3 bytes to parse header */ + rxs->min_len = 3; + rc = ble_hci_trans_h4_pull_min_len(rxs, ib); + if (rc) { + /* need more data */ + return 1; + } + + /* Advertising reports shall be allocated from low-prio pool */ + if ((rxs->hdr[2] == BLE_HCI_LE_SUBEV_ADV_RPT) || + (rxs->hdr[2] == BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { + pool = BLE_HCI_TRANS_BUF_EVT_LO; + } + } + + /* + * XXX Events originally allocated from hi-pool can use lo-pool as + * fallback and cannot be dropped. Events allocated from lo-pool + * can be dropped to avoid oom while scanning which means that + * any advertising or extended advertising report can be silently + * discarded by transport. While this is perfectly fine for legacy + * advertising, for extended advertising it means we can drop start + * or end of chain report and host won't be able to reassemble + * chain properly... so just need to make sure pool on host side is + * large enough to catch up with controller. + */ + rxs->buf = ble_hci_trans_buf_alloc(pool); + if (!rxs->buf && pool == BLE_HCI_TRANS_BUF_EVT_HI) { + rxs->buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + if (!rxs->buf) { + return -1; + } + } + + if (rxs->buf) { + memcpy(rxs->buf, rxs->hdr, rxs->len); + } + + rxs->expected_len = rxs->hdr[1] + 2; + break; +#endif + default: + assert(0); + break; + } + + return 0; +} + +static int +ble_hci_trans_h4_rx_state_w4_payload(struct ble_hci_trans_h4_rx_state *rxs, + struct input_buffer *ib) +{ + uint16_t mbuf_len; + uint16_t len; + int rc; + + len = min(ib->len, rxs->expected_len - rxs->len); + + switch (rxs->pkt_type) { +#if MYNEWT_VAL(BLE_CONTROLLER) + case BLE_HCI_TRANS_H4_PKT_TYPE_CMD: +#endif +#if MYNEWT_VAL(BLE_HOST) + case BLE_HCI_TRANS_H4_PKT_TYPE_EVT: +#endif + if (rxs->buf) { + memcpy(&rxs->buf[rxs->len], ib->buf, len); + } + break; + case BLE_HCI_TRANS_H4_PKT_TYPE_ACL: + assert(rxs->om); + + mbuf_len = OS_MBUF_PKTLEN(rxs->om); + rc = os_mbuf_append(rxs->om, ib->buf, len); + if (rc) { + /* + * Some data may already be appended so need to adjust rxs only by + * the size of appended data. + */ + len = OS_MBUF_PKTLEN(rxs->om) - mbuf_len; + rxs->len += len; + ble_hci_trans_h4_ib_adjust(ib, len); + + return -1; + } + break; + default: + assert(0); + break; + } + + rxs->len += len; + ble_hci_trans_h4_ib_adjust(ib, len); + + /* return 1 if need more data */ + return rxs->len != rxs->expected_len; +} + +static void +ble_hci_trans_h4_rx_state_completed(struct ble_hci_trans_h4_rx_state *rxs, + ble_hci_trans_h4_frame_cb *frame_cb) +{ + int rc; + + switch (rxs->pkt_type) { +#if MYNEWT_VAL(BLE_CONTROLLER) + case BLE_HCI_TRANS_H4_PKT_TYPE_CMD: +#endif +#if MYNEWT_VAL(BLE_HOST) + case BLE_HCI_TRANS_H4_PKT_TYPE_EVT: +#endif + if (rxs->buf) { + rc = frame_cb(rxs->pkt_type, rxs->buf); + if (rc != 0) { + ble_hci_trans_buf_free(rxs->buf); + } + rxs->buf = NULL; + } + break; + case BLE_HCI_TRANS_H4_PKT_TYPE_ACL: + if (rxs->om) { + rc = frame_cb(rxs->pkt_type, rxs->om); + if (rc != 0) { + os_mbuf_free_chain(rxs->om); + } + rxs->om = NULL; + } + break; + default: + assert(0); + break; + } +} + +int +ble_hci_trans_h4_rx(struct ble_hci_trans_h4_rx_state *rxs, const uint8_t *buf, + uint16_t len, ble_hci_trans_h4_frame_cb *frame_cb) +{ + struct input_buffer ib = { + .buf = buf, + .len = len, + }; + int rc = 0; + + while (ib.len && (rc >= 0)) { + rc = 0; + switch (rxs->state) { + case RXS_STATE_W4_PKT_TYPE: + ble_hci_trans_h4_rxs_start(rxs, ib.buf[0]); + ble_hci_trans_h4_ib_adjust(&ib, 1); + rxs->state = RXS_STATE_W4_HEADER; + /* no break */ + + case RXS_STATE_W4_HEADER: + rc = ble_hci_trans_h4_rx_state_w4_header(rxs, &ib); + if (rc) { + break; + } + rxs->state = RXS_STATE_W4_PAYLOAD; + /* no break */ + + case RXS_STATE_W4_PAYLOAD: + rc = ble_hci_trans_h4_rx_state_w4_payload(rxs, &ib); + if (rc) { + break; + } + rxs->state = RXS_STATE_COMPLETED; + /* no break */ + + case RXS_STATE_COMPLETED: + ble_hci_trans_h4_rx_state_completed(rxs, frame_cb); + rxs->state = RXS_STATE_W4_PKT_TYPE; + break; + + default: + assert(0); + /* consume all remaining data */ + ble_hci_trans_h4_ib_adjust(&ib, ib.len); + break; + } + } + + /* + * Calculate consumed bytes + * + * Note: we should always consume some bytes unless there is an oom error. + * It's also possible that we have an oom error but already consumed some + * data, in such case just return success and error will be returned on next + * pass. + */ + len = len - ib.len; + if (len == 0) { + assert(rc < 0); + return -1; + } + + return len; +} diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_trans_h4.h b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_trans_h4.h new file mode 100644 index 00000000..5b83f6b0 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/src/ble_hci_trans_h4.h @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 _BLE_HCI_TRANS_H4_H_ +#define _BLE_HCI_TRANS_H4_H_ + +#include <stdint.h> + +#define BLE_HCI_TRANS_H4_PKT_TYPE_NONE 0x00 +#define BLE_HCI_TRANS_H4_PKT_TYPE_CMD 0x01 +#define BLE_HCI_TRANS_H4_PKT_TYPE_ACL 0x02 +#define BLE_HCI_TRANS_H4_PKT_TYPE_EVT 0x04 + +struct ble_hci_trans_h4_rx_state { + uint8_t state; + uint8_t pkt_type; + uint8_t min_len; + uint16_t len; + uint16_t expected_len; + uint8_t hdr[4]; + union { + uint8_t *buf; + struct os_mbuf *om; + }; +}; + +typedef int (ble_hci_trans_h4_frame_cb)(uint8_t pkt_type, void *data); + +int ble_hci_trans_h4_rx(struct ble_hci_trans_h4_rx_state *rxs, + const uint8_t *buf, uint16_t len, + ble_hci_trans_h4_frame_cb *frame_cb); + +#endif /* _BLE_HCI_TRANS_H4_H_ */ diff --git a/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/syscfg.yml b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/syscfg.yml new file mode 100644 index 00000000..c44773ef --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/dialog_cmac/syscfg.yml @@ -0,0 +1,43 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +syscfg.defs: + BLE_HCI_EVT_HI_BUF_COUNT: + description: 'Number of high-priority event buffers.' + value: 2 + + BLE_HCI_EVT_LO_BUF_COUNT: + description: 'Number of low-priority event buffers.' + value: 8 + + BLE_HCI_EVT_BUF_SIZE: + description: 'Size of each event buffer, in bytes.' + value: 70 + + BLE_ACL_BUF_COUNT: + description: 'The number of ACL data buffers' + value: 4 + + BLE_ACL_BUF_SIZE: + description: > + This is the maximum size of the data portion of HCI ACL data + packets. It does not include the HCI data header (of 4 bytes). + value: 255 + +syscfg.vals.'BLE_EXT_ADV || BLE_LL_CFG_FEAT_LL_EXT_ADV': + BLE_HCI_EVT_BUF_SIZE: 257 diff --git a/src/libs/mynewt-nimble/nimble/transport/emspi/src/ble_hci_emspi.c b/src/libs/mynewt-nimble/nimble/transport/emspi/src/ble_hci_emspi.c index 61c0c9cb..61fe96b2 100644 --- a/src/libs/mynewt-nimble/nimble/transport/emspi/src/ble_hci_emspi.c +++ b/src/libs/mynewt-nimble/nimble/transport/emspi/src/ble_hci_emspi.c @@ -295,15 +295,7 @@ done: static struct os_mbuf * ble_hci_trans_acl_buf_alloc(void) { - uint8_t usrhdr_len; - -#if MYNEWT_VAL(BLE_HS_FLOW_CTRL) - usrhdr_len = BLE_MBUF_HS_HDR_LEN; -#else - usrhdr_len = 0; -#endif - - return os_mbuf_get_pkthdr(&ble_hci_emspi_acl_mbuf_pool, usrhdr_len); + return os_mbuf_get_pkthdr(&ble_hci_emspi_acl_mbuf_pool, 0); } /** diff --git a/src/libs/mynewt-nimble/nimble/transport/nrf5340/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/nrf5340/pkg.yml new file mode 100644 index 00000000..4db567c8 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/nrf5340/pkg.yml @@ -0,0 +1,38 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +pkg.name: nimble/transport/nrf5340 +pkg.description: HCI transport for nRF5340 +pkg.author: "Apache Mynewt <dev@mynewt.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + - nrf5340 + +pkg.deps: + - "@apache-mynewt-nimble/nimble" + - "@apache-mynewt-core/kernel/os" + - "@apache-mynewt-core/hw/drivers/ipc_nrf5340" + +pkg.apis: + - ble_transport + +pkg.init: + nrf5340_ble_hci_init: 'MYNEWT_VAL(BLE_TRANS_NRF5340_SYSINIT_STAGE)' diff --git a/src/libs/mynewt-nimble/nimble/transport/nrf5340/src/nrf5340_ble_hci.c b/src/libs/mynewt-nimble/nimble/transport/nrf5340/src/nrf5340_ble_hci.c new file mode 100644 index 00000000..3f113e11 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/nrf5340/src/nrf5340_ble_hci.c @@ -0,0 +1,426 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 <assert.h> +#include <string.h> +#include <os/mynewt.h> +#include <nimble/ble.h> +#include <nimble/ble_hci_trans.h> +#include <nimble/hci_common.h> +#include <ipc_nrf5340/ipc_nrf5340.h> + +#define HCI_PKT_NONE 0x00 +#define HCI_PKT_CMD 0x01 +#define HCI_PKT_ACL 0x02 +#define HCI_PKT_EVT 0x04 + +#define POOL_ACL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) + \ + BLE_MBUF_MEMBLOCK_OVERHEAD + \ + BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT) + +#if MYNEWT_VAL(BLE_CONTROLLER) +#define IPC_TX_CHANNEL 0 +#define IPC_RX_CHANNEL 1 +#endif + +#if MYNEWT_VAL(BLE_HOST) +#define IPC_TX_CHANNEL 1 +#define IPC_RX_CHANNEL 0 +#endif + +struct nrf5340_ble_hci_api { +#if MYNEWT_VAL(BLE_CONTROLLER) + ble_hci_trans_rx_cmd_fn *cmd_cb; + void *cmd_arg; +#endif +#if MYNEWT_VAL(BLE_HOST) + ble_hci_trans_rx_cmd_fn *evt_cb; + void *evt_arg; +#endif + ble_hci_trans_rx_acl_fn *acl_cb; + void *acl_arg; +}; + +struct nrf5340_ble_hci_rx_data { + uint8_t type; + uint8_t hdr[4]; + uint16_t len; + uint16_t expected_len; + union { + uint8_t *buf; + struct os_mbuf *om; + }; +}; + +struct nrf5340_ble_hci_pool_cmd { + uint8_t cmd[BLE_HCI_TRANS_CMD_SZ]; + bool allocated; +}; + +/* (Pseudo)pool for HCI commands */ +static struct nrf5340_ble_hci_pool_cmd nrf5340_ble_hci_pool_cmd; + +/* Pools for HCI events (high and low priority) */ +static uint8_t nrf5340_ble_hci_pool_evt_hi_buf[OS_MEMPOOL_BYTES( + MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))]; +static struct os_mempool nrf5340_ble_hci_pool_evt_hi; +static uint8_t nrf5340_ble_hci_pool_evt_lo_buf[OS_MEMPOOL_BYTES( + MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))]; +static struct os_mempool nrf5340_ble_hci_pool_evt_lo; + +/* Pool for ACL data */ +static uint8_t nrf5340_ble_hci_pool_acl_buf[OS_MEMPOOL_BYTES( + MYNEWT_VAL(BLE_ACL_BUF_COUNT), + POOL_ACL_BLOCK_SIZE)]; +static struct os_mempool nrf5340_ble_hci_pool_acl; +static struct os_mbuf_pool nrf5340_ble_hci_pool_acl_mbuf; + +/* Interface to host/ll */ +static struct nrf5340_ble_hci_api nrf5340_ble_hci_api; + +/* State of RX currently in progress (needs to reassemble frame) */ +static struct nrf5340_ble_hci_rx_data nrf5340_ble_hci_rx_data; + +int +ble_hci_trans_reset(void) +{ + /* XXX Should we do something with RF and/or BLE core? */ + return 0; +} + +static int +ble_hci_trans_acl_tx(struct os_mbuf *om) +{ + uint8_t ind = HCI_PKT_ACL; + struct os_mbuf *x; + int rc; + + rc = ipc_nrf5340_send(IPC_TX_CHANNEL, &ind, 1); + if (rc == 0) { + x = om; + while (x) { + rc = ipc_nrf5340_send(IPC_TX_CHANNEL, x->om_data, x->om_len); + if (rc < 0) { + break; + } + x = SLIST_NEXT(x, om_next); + } + } + + os_mbuf_free_chain(om); + + return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0; +} + +#if MYNEWT_VAL(BLE_CONTROLLER) +void +ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb, void *cmd_arg, + ble_hci_trans_rx_acl_fn *acl_cb, void *acl_arg) +{ + nrf5340_ble_hci_api.cmd_cb = cmd_cb; + nrf5340_ble_hci_api.cmd_arg = cmd_arg; + nrf5340_ble_hci_api.acl_cb = acl_cb; + nrf5340_ble_hci_api.acl_arg = acl_arg; +} + +int +ble_hci_trans_ll_evt_tx(uint8_t *hci_ev) +{ + uint8_t ind = HCI_PKT_EVT; + int len = 2 + hci_ev[1]; + int rc; + + rc = ipc_nrf5340_send(IPC_TX_CHANNEL, &ind, 1); + if (rc == 0) { + rc = ipc_nrf5340_send(IPC_TX_CHANNEL, hci_ev, len); + } + + ble_hci_trans_buf_free(hci_ev); + + return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0; +} + +int +ble_hci_trans_ll_acl_tx(struct os_mbuf *om) +{ + return ble_hci_trans_acl_tx(om); +} +#endif + +#if MYNEWT_VAL(BLE_HOST) +void +ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *evt_cb, void *evt_arg, + ble_hci_trans_rx_acl_fn *acl_cb, void *acl_arg) +{ + nrf5340_ble_hci_api.evt_cb = evt_cb; + nrf5340_ble_hci_api.evt_arg = evt_arg; + nrf5340_ble_hci_api.acl_cb = acl_cb; + nrf5340_ble_hci_api.acl_arg = acl_arg; +} + +int +ble_hci_trans_hs_cmd_tx(uint8_t *cmd) +{ + uint8_t ind = HCI_PKT_CMD; + int len = 3 + cmd[2]; + int rc; + + rc = ipc_nrf5340_send(IPC_TX_CHANNEL, &ind, 1); + if (rc == 0) { + rc = ipc_nrf5340_send(IPC_TX_CHANNEL, cmd, len); + } + + ble_hci_trans_buf_free(cmd); + + return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0; +} + +int +ble_hci_trans_hs_acl_tx(struct os_mbuf *om) +{ + return ble_hci_trans_acl_tx(om); +} +#endif + +uint8_t * +ble_hci_trans_buf_alloc(int type) +{ + uint8_t *buf; + + switch (type) { + case BLE_HCI_TRANS_BUF_CMD: + assert(!nrf5340_ble_hci_pool_cmd.allocated); + nrf5340_ble_hci_pool_cmd.allocated = 1; + buf = nrf5340_ble_hci_pool_cmd.cmd; + break; + case BLE_HCI_TRANS_BUF_EVT_HI: + buf = os_memblock_get(&nrf5340_ble_hci_pool_evt_hi); + if (buf) { + break; + } + /* no break */ + case BLE_HCI_TRANS_BUF_EVT_LO: + buf = os_memblock_get(&nrf5340_ble_hci_pool_evt_lo); + break; + default: + assert(0); + buf = NULL; + } + + return buf; +} + +void +ble_hci_trans_buf_free(uint8_t *buf) +{ + int rc; + + if (buf == nrf5340_ble_hci_pool_cmd.cmd) { + assert(nrf5340_ble_hci_pool_cmd.allocated); + nrf5340_ble_hci_pool_cmd.allocated = 0; + } else if (os_memblock_from(&nrf5340_ble_hci_pool_evt_hi, buf)) { + rc = os_memblock_put(&nrf5340_ble_hci_pool_evt_hi, buf); + assert(rc == 0); + } else { + assert(os_memblock_from(&nrf5340_ble_hci_pool_evt_lo, buf)); + rc = os_memblock_put(&nrf5340_ble_hci_pool_evt_lo, buf); + assert(rc == 0); + } +} + +static void +nrf5340_ble_hci_trans_rx_process(int channel) +{ + struct nrf5340_ble_hci_rx_data *rxd = &nrf5340_ble_hci_rx_data; +#if MYNEWT_VAL(BLE_HOST) + int pool = BLE_HCI_TRANS_BUF_EVT_HI; +#endif + int rc; + + switch (rxd->type) { + case HCI_PKT_NONE: + ipc_nrf5340_read(channel, &rxd->type, 1); + rxd->len = 0; + rxd->expected_len = 0; + +#if MYNEWT_VAL(BLE_CONTROLLER) + assert((rxd->type == HCI_PKT_ACL) || (rxd->type = HCI_PKT_CMD)); +#endif +#if MYNEWT_VAL(BLE_HOST) + assert((rxd->type == HCI_PKT_ACL) || (rxd->type = HCI_PKT_EVT)); +#endif + break; +#if MYNEWT_VAL(BLE_CONTROLLER) + case HCI_PKT_CMD: + /* commands are sent complete over IPC */ + rxd->len = ipc_nrf5340_read(channel, rxd->hdr, 3); + assert(rxd->len == 3); + + rxd->buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); + memcpy(rxd->buf, rxd->hdr, rxd->len); + + rxd->len += ipc_nrf5340_read(channel, &rxd->buf[rxd->len], rxd->hdr[2]); + assert(rxd->len == 3 + rxd->hdr[2]); + + rc = nrf5340_ble_hci_api.cmd_cb(rxd->buf, nrf5340_ble_hci_api.cmd_arg); + if (rc != 0) { + ble_hci_trans_buf_free(rxd->buf); + } + + rxd->type = HCI_PKT_NONE; + break; +#endif +#if MYNEWT_VAL(BLE_HOST) + case HCI_PKT_EVT: + /* events are sent complete over IPC */ + rxd->len = ipc_nrf5340_read(channel, rxd->hdr, 2); + assert(rxd->len == 2); + + if (rxd->hdr[0] == BLE_HCI_EVCODE_LE_META) { + /* For LE Meta event we need 3 bytes to parse header */ + rxd->len += ipc_nrf5340_read(channel, rxd->hdr + 2, 1); + assert(rxd->len == 3); + + /* Advertising reports shall be allocated from low-prio pool */ + if ((rxd->hdr[2] == BLE_HCI_LE_SUBEV_ADV_RPT) || + (rxd->hdr[2] == BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { + pool = BLE_HCI_TRANS_BUF_EVT_LO; + } + } + + rxd->buf = ble_hci_trans_buf_alloc(pool); + if (!rxd->buf) { + /* + * Only care about valid buffer when shall be allocated from + * high-prio pool, otherwise NULL is fine and we'll just skip + * this event. + */ + if (pool != BLE_HCI_TRANS_BUF_EVT_LO) { + rxd->buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + } + } + + rxd->expected_len = 2 + rxd->hdr[1]; + + if (rxd->buf) { + memcpy(rxd->buf, rxd->hdr, rxd->len); + + rxd->len += ipc_nrf5340_read(channel, &rxd->buf[rxd->len], + rxd->expected_len - rxd->len); + assert(rxd->expected_len == rxd->len); + + rc = nrf5340_ble_hci_api.evt_cb(rxd->buf, + nrf5340_ble_hci_api.evt_arg); + if (rc != 0) { + ble_hci_trans_buf_free(rxd->buf); + } + } else { + rxd->len += ipc_nrf5340_consume(channel, + rxd->expected_len - rxd->len); + assert(rxd->expected_len == rxd->len); + } + + rxd->type = HCI_PKT_NONE; + break; +#endif + case HCI_PKT_ACL: + if (rxd->len < 4) { + rxd->len += ipc_nrf5340_read(channel, rxd->hdr, 4 - rxd->len); + + if (rxd->len < 4) { + break; + } + } + + /* Parse header and allocate proper buffer if not done yet */ + if (rxd->expected_len == 0) { + rxd->om = os_mbuf_get_pkthdr(&nrf5340_ble_hci_pool_acl_mbuf, + sizeof(struct ble_mbuf_hdr)); + if (!rxd->om) { + /* not much we can do here... */ + assert(0); + } + + os_mbuf_append(rxd->om, rxd->hdr, rxd->len); + rxd->expected_len = get_le16(&rxd->hdr[2]) + 4; + } + + if (rxd->len != rxd->expected_len) { + rxd->len += ipc_nrf5340_read_om(channel, rxd->om, + rxd->expected_len - rxd->len); + } + + if (rxd->len == rxd->expected_len) { + rc = nrf5340_ble_hci_api.acl_cb(rxd->om, + nrf5340_ble_hci_api.acl_arg); + if (rc != 0) { + os_mbuf_free_chain(rxd->om); + } + rxd->type = HCI_PKT_NONE; + } + break; + default: + assert(0); + break; + } +} + +static void +nrf5340_ble_hci_trans_rx(int channel, void *user_data) +{ + while (ipc_nrf5340_available(channel) > 0) { + nrf5340_ble_hci_trans_rx_process(channel); + } +} + +void +nrf5340_ble_hci_init(void) +{ + int rc; + + SYSINIT_ASSERT_ACTIVE(); + + rc = os_mempool_init(&nrf5340_ble_hci_pool_acl, MYNEWT_VAL(BLE_ACL_BUF_COUNT), + POOL_ACL_BLOCK_SIZE, nrf5340_ble_hci_pool_acl_buf, + "nrf5340_ble_hci_pool_acl"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mbuf_pool_init(&nrf5340_ble_hci_pool_acl_mbuf, + &nrf5340_ble_hci_pool_acl, POOL_ACL_BLOCK_SIZE, + MYNEWT_VAL(BLE_ACL_BUF_COUNT)); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&nrf5340_ble_hci_pool_evt_hi, + MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), + nrf5340_ble_hci_pool_evt_hi_buf, + "nrf5340_ble_hci_pool_evt_hi"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&nrf5340_ble_hci_pool_evt_lo, + MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), + nrf5340_ble_hci_pool_evt_lo_buf, + "nrf5340_ble_hci_pool_evt_lo"); + SYSINIT_PANIC_ASSERT(rc == 0); + + ipc_nrf5340_recv(IPC_RX_CHANNEL, nrf5340_ble_hci_trans_rx, NULL); +} diff --git a/src/libs/mynewt-nimble/nimble/transport/nrf5340/syscfg.yml b/src/libs/mynewt-nimble/nimble/transport/nrf5340/syscfg.yml new file mode 100644 index 00000000..1417bbc0 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/nrf5340/syscfg.yml @@ -0,0 +1,51 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +syscfg.defs: + BLE_HCI_EVT_HI_BUF_COUNT: + description: 'Number of high-priority event buffers.' + value: 2 + + BLE_HCI_EVT_LO_BUF_COUNT: + description: 'Number of low-priority event buffers.' + value: 8 + + BLE_HCI_EVT_BUF_SIZE: + description: 'Size of each event buffer, in bytes.' + value: 70 + + BLE_ACL_BUF_COUNT: + description: 'The number of ACL data buffers' + value: 4 + + BLE_ACL_BUF_SIZE: + description: > + This is the maximum size of the data portion of HCI ACL data + packets. It does not include the HCI data header (of 4 bytes). + value: 255 + + BLE_TRANS_NRF5340_SYSINIT_STAGE: + description: > + Sysinit stage for the RAM BLE transport. + value: 100 + +syscfg.vals.BLE_EXT_ADV: + BLE_HCI_EVT_BUF_SIZE: 257 + +syscfg.restrictions: + - '!(BLE_HOST && BLE_CONTROLLER)' diff --git a/src/libs/mynewt-nimble/nimble/transport/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/pkg.yml index 2bc4ac29..8174286d 100644 --- a/src/libs/mynewt-nimble/nimble/transport/pkg.yml +++ b/src/libs/mynewt-nimble/nimble/transport/pkg.yml @@ -43,3 +43,12 @@ pkg.deps.'BLE_HCI_TRANSPORT == "uart"': pkg.deps.'BLE_HCI_TRANSPORT == "da1469x"': - nimble/transport/da1469x + +pkg.deps.'BLE_HCI_TRANSPORT == "dialog_cmac"': + - nimble/transport/dialog_cmac + +pkg.deps.'BLE_HCI_TRANSPORT == "usb"': + - nimble/transport/usb + +pkg.deps.'BLE_HCI_TRANSPORT == "nrf5340"': + - nimble/transport/nrf5340 diff --git a/src/libs/mynewt-nimble/nimble/transport/socket/src/ble_hci_socket.c b/src/libs/mynewt-nimble/nimble/transport/socket/src/ble_hci_socket.c index 863d0fbb..44de8fed 100644 --- a/src/libs/mynewt-nimble/nimble/transport/socket/src/ble_hci_socket.c +++ b/src/libs/mynewt-nimble/nimble/transport/socket/src/ble_hci_socket.c @@ -53,19 +53,22 @@ #if MYNEWT_VAL(BLE_SOCK_USE_LINUX_BLUE) #include <sys/errno.h> -#define BTPROTO_HCI 1 -#define HCI_CHANNEL_RAW 0 -#define HCI_CHANNEL_USER 1 -#define HCIDEVUP _IOW('H', 201, int) -#define HCIDEVDOWN _IOW('H', 202, int) -#define HCIDEVRESET _IOW('H', 203, int) -#define HCIGETDEVLIST _IOR('H', 210, int) +#define BTPROTO_HCI 1 +#define HCI_CHANNEL_RAW 0 +#define HCI_CHANNEL_USER 1 +#define HCIDEVUP _IOW('H', 201, int) +#define HCIDEVDOWN _IOW('H', 202, int) +#define HCIDEVRESET _IOW('H', 203, int) +#define HCIGETDEVLIST _IOR('H', 210, int) struct sockaddr_hci { - sa_family_t hci_family; - unsigned short hci_dev; - unsigned short hci_channel; + sa_family_t hci_family; + unsigned short hci_dev; + unsigned short hci_channel; }; +#elif MYNEWT_VAL(BLE_SOCK_USE_NUTTX) +#include <errno.h> +#include <netpacket/bluetooth.h> #endif #include <fcntl.h> @@ -205,6 +208,8 @@ static struct ble_hci_sock_state { static int s_ble_hci_device = MYNEWT_VAL(BLE_SOCK_TCP_PORT); #elif MYNEWT_VAL(BLE_SOCK_USE_LINUX_BLUE) static int s_ble_hci_device = MYNEWT_VAL(BLE_SOCK_LINUX_DEV); +#elif MYNEWT_VAL(BLE_SOCK_USE_NUTTX) +static int s_ble_hci_device = 0; #endif /** @@ -227,6 +232,7 @@ ble_hci_trans_acl_buf_alloc(void) return m; } +#if MYNEWT_VAL(BLE_SOCK_USE_LINUX_BLUE) static int ble_hci_sock_acl_tx(struct os_mbuf *om) { @@ -268,10 +274,66 @@ ble_hci_sock_acl_tx(struct os_mbuf *om) } return 0; } +#elif MYNEWT_VAL(BLE_SOCK_USE_NUTTX) +static int +ble_hci_sock_acl_tx(struct os_mbuf *om) +{ + size_t len; + uint8_t *buf; + int i; + struct os_mbuf *m; + struct sockaddr_hci addr; + + addr.hci_family = AF_BLUETOOTH; + addr.hci_channel = HCI_CHANNEL_RAW; + addr.hci_dev = 0; + + memcpy(&addr, &addr, sizeof(struct sockaddr_hci)); + + len = 1; + + for (m = om; m; m = SLIST_NEXT(m, om_next)) { + len += m->om_len; + } + + buf = (uint8_t *)malloc(len); + + buf[0] = BLE_HCI_UART_H4_ACL; + i = 1; + for (m = om; m; m = SLIST_NEXT(m, om_next)) { + memcpy(&buf[i], m->om_data, m->om_len); + i += m->om_len; + } + + STATS_INC(hci_sock_stats, omsg); + STATS_INC(hci_sock_stats, oacl); + STATS_INCN(hci_sock_stats, obytes, OS_MBUF_PKTLEN(om) + 1); + + i = sendto(ble_hci_sock_state.sock, buf, len, 0, + (struct sockaddr *)&addr, sizeof(struct sockaddr_hci)); + + free(buf); + + os_mbuf_free_chain(om); + if (i != OS_MBUF_PKTLEN(om) + 1) { + if (i < 0) { + dprintf(1, "sendto() failed : %d\n", errno); + } else { + dprintf(1, "sendto() partial write: %d\n", i); + } + STATS_INC(hci_sock_stats, oerr); + return BLE_ERR_MEM_CAPACITY; + } + return 0; +} +#endif + +#if MYNEWT_VAL(BLE_SOCK_USE_LINUX_BLUE) static int ble_hci_sock_cmdevt_tx(uint8_t *hci_ev, uint8_t h4_type) { + uint8_t btaddr[6]; struct msghdr msg; struct iovec iov[8]; int len; @@ -316,6 +378,57 @@ ble_hci_sock_cmdevt_tx(uint8_t *hci_ev, uint8_t h4_type) return 0; } +#elif MYNEWT_VAL(BLE_SOCK_USE_NUTTX) +static int +ble_hci_sock_cmdevt_tx(uint8_t *hci_ev, uint8_t h4_type) +{ + uint8_t *buf; + size_t len; + struct sockaddr_hci addr; + int i; + + addr.hci_family = AF_BLUETOOTH; + addr.hci_channel = HCI_CHANNEL_RAW; + addr.hci_dev = 0; + + memcpy(&addr, &addr, sizeof(struct sockaddr_hci)); + + if (h4_type == BLE_HCI_UART_H4_CMD) { + len = sizeof(struct ble_hci_cmd) + hci_ev[2]; + STATS_INC(hci_sock_stats, ocmd); + } else if (h4_type == BLE_HCI_UART_H4_EVT) { + len = sizeof(struct ble_hci_ev) + hci_ev[1]; + STATS_INC(hci_sock_stats, oevt); + } else { + assert(0); + } + + STATS_INC(hci_sock_stats, omsg); + STATS_INCN(hci_sock_stats, obytes, len + 1); + + buf = (uint8_t *)malloc(len + 1); + + buf[0] = h4_type; + memcpy(&buf[1], hci_ev, len); + + i = sendto(ble_hci_sock_state.sock, buf, len + 1, 0, + (struct sockaddr *)&addr, sizeof(struct sockaddr_hci)); + + free(buf); + ble_hci_trans_buf_free(hci_ev); + if (i != len + 1) { + if (i < 0) { + dprintf(1, "sendto() failed : %d\n", errno); + } else { + dprintf(1, "sendto() partial write: %d\n", i); + } + STATS_INC(hci_sock_stats, oerr); + return BLE_ERR_MEM_CAPACITY; + } + + return 0; +} +#endif static int ble_hci_sock_rx_msg(void) @@ -427,6 +540,7 @@ ble_hci_sock_rx_msg(void) STATS_INC(hci_sock_stats, ierr); break; } + memmove(bhss->rx_data, &bhss->rx_data[len], bhss->rx_off - len); bhss->rx_off -= len; } @@ -540,7 +654,7 @@ ble_hci_sock_config(void) rc = bind(s, (struct sockaddr *)&shci, sizeof(shci)); if (rc) { - dprintf(1, "bind() failed %d\n", errno); + dprintf(1, "bind() failed %d hci%d\n", errno, shci.hci_dev); goto err; } @@ -565,7 +679,54 @@ err: } return BLE_ERR_HW_FAIL; } +#elif MYNEWT_VAL(BLE_SOCK_USE_NUTTX) +static int +ble_hci_sock_config(void) +{ + struct sockaddr_hci shci; + int s; + int rc; + ble_npl_time_t timeout; + + memset(&shci, 0, sizeof(shci)); + shci.hci_family = AF_BLUETOOTH; + shci.hci_dev = 0; + shci.hci_channel = HCI_CHANNEL_RAW; + + if (ble_hci_sock_state.sock >= 0) { + close(ble_hci_sock_state.sock); + ble_hci_sock_state.sock = -1; + } + + s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); + if (s < 0) { + dprintf(1, "socket() failed %d\n", errno); + goto err; + } + + rc = bind(s, (struct sockaddr *)&shci, sizeof(shci)); + if (rc) { + dprintf(1, "bind() failed %d hci%d\n", errno, shci.hci_dev); + goto err; + } + + ble_hci_sock_state.sock = s; + + rc = ble_npl_time_ms_to_ticks(10, &timeout); + if (rc) { + goto err; + } + ble_npl_callout_reset(&ble_hci_sock_state.timer, timeout); + + return 0; +err: + if (s >= 0) { + close(s); + } + return BLE_ERR_HW_FAIL; +} #endif + /** * Sends an HCI event from the controller to the host. * diff --git a/src/libs/mynewt-nimble/nimble/transport/syscfg.yml b/src/libs/mynewt-nimble/nimble/transport/syscfg.yml index 137d6e94..5bec6adf 100644 --- a/src/libs/mynewt-nimble/nimble/transport/syscfg.yml +++ b/src/libs/mynewt-nimble/nimble/transport/syscfg.yml @@ -26,13 +26,16 @@ syscfg.defs: value: builtin restrictions: $notnull choices: - - builtin # Built-in NimBLE controller and RAM transport - - custom # Custom transport, has to be included manually by user - - ram # RAM transport - - uart # UART HCI H4 transport - - socket # Socket transport (for native builds) - - emspi # SPI transport for EM Microelectionic controllers - - da1469x # Dialog DA1469x integrated controller + - builtin # Built-in NimBLE controller and RAM transport + - custom # Custom transport, has to be included manually by user + - ram # RAM transport + - uart # UART HCI H4 transport + - socket # Socket transport (for native builds) + - emspi # SPI transport for EM Microelectionic controllers + - da1469x # Dialog DA1469x integrated controller + - dialog_cmac # Dialog CMAC via shared memory + - usb # USB + - nrf5340 # nRF5340 # Deprecated settings BLE_HCI_TRANSPORT_NIMBLE_BUILTIN: diff --git a/src/libs/mynewt-nimble/nimble/transport/uart/src/ble_hci_uart.c b/src/libs/mynewt-nimble/nimble/transport/uart/src/ble_hci_uart.c index ac6af28e..cbb6dd42 100644 --- a/src/libs/mynewt-nimble/nimble/transport/uart/src/ble_hci_uart.c +++ b/src/libs/mynewt-nimble/nimble/transport/uart/src/ble_hci_uart.c @@ -195,8 +195,6 @@ ble_hci_trans_acl_buf_alloc(void) #if MYNEWT_VAL(BLE_CONTROLLER) usrhdr_len = sizeof(struct ble_mbuf_hdr); -#elif MYNEWT_VAL(BLE_HS_FLOW_CTRL) - usrhdr_len = BLE_MBUF_HS_HDR_LEN; #else usrhdr_len = 0; #endif diff --git a/src/libs/mynewt-nimble/nimble/transport/usb/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/usb/pkg.yml new file mode 100644 index 00000000..49317c97 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/usb/pkg.yml @@ -0,0 +1,39 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +pkg.name: nimble/transport/usb +pkg.description: Provides HCI transport over USB interface +pkg.author: "Apache Mynewt <dev@mynewt.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + - usb + +pkg.deps: + - "@apache-mynewt-core/hw/hal" + - "@apache-mynewt-core/kernel/os" + - "@apache-mynewt-core/util/mem" + - nimble + +pkg.apis: + - ble_transport + +pkg.init: + ble_hci_usb_init: 'MYNEWT_VAL(BLE_TRANS_USB_SYSINIT_STAGE)' diff --git a/src/libs/mynewt-nimble/nimble/transport/usb/src/ble_hci_usb.c b/src/libs/mynewt-nimble/nimble/transport/usb/src/ble_hci_usb.c new file mode 100644 index 00000000..55c91f22 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/usb/src/ble_hci_usb.c @@ -0,0 +1,410 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 <assert.h> +#include <stddef.h> +#include "syscfg/syscfg.h" +#include "sysinit/sysinit.h" +#include "os/os.h" +#include "mem/mem.h" + +#include "nimble/ble.h" +#include "nimble/ble_hci_trans.h" +#include "nimble/hci_common.h" + +#include <class/bth/bth_device.h> + +/* + * The MBUF payload size must accommodate the HCI data header size plus the + * maximum ACL data packet length. The ACL block size is the size of the + * mbufs we will allocate. + */ +#define ACL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) \ + + BLE_MBUF_MEMBLOCK_OVERHEAD \ + + BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT) + +struct usb_ble_hci_pool_cmd { + uint8_t cmd[BLE_HCI_TRANS_CMD_SZ]; + bool allocated; +}; + +/* (Pseudo)pool for HCI commands */ +static struct usb_ble_hci_pool_cmd usb_ble_hci_pool_cmd; + +static ble_hci_trans_rx_cmd_fn *ble_hci_usb_rx_cmd_ll_cb; +static void *ble_hci_usb_rx_cmd_ll_arg; + +static ble_hci_trans_rx_acl_fn *ble_hci_usb_rx_acl_ll_cb; +static void *ble_hci_usb_rx_acl_ll_arg; + +static struct os_mempool ble_hci_usb_evt_hi_pool; +static os_membuf_t ble_hci_usb_evt_hi_buf[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) +]; + +static struct os_mempool ble_hci_usb_evt_lo_pool; +static os_membuf_t ble_hci_usb_evt_lo_buf[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) +]; + +static uint8_t ble_hci_pool_acl_mempool_buf[ + OS_MEMPOOL_BYTES(MYNEWT_VAL(BLE_ACL_BUF_COUNT), + ACL_BLOCK_SIZE)]; +static struct os_mempool ble_hci_pool_acl_mempool; +static struct os_mbuf_pool ble_hci_pool_acl_mbuf_pool; + +static struct os_mbuf *incoming_acl_data; + +static struct os_mbuf * +ble_hci_trans_acl_buf_alloc(void) +{ + struct os_mbuf *m; + + m = os_mbuf_get_pkthdr(&ble_hci_pool_acl_mbuf_pool, + sizeof(struct ble_mbuf_hdr)); + return m; +} + +void +ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb, + void *cmd_arg, + ble_hci_trans_rx_acl_fn *acl_cb, + void *acl_arg) +{ + ble_hci_usb_rx_cmd_ll_cb = cmd_cb; + ble_hci_usb_rx_cmd_ll_arg = cmd_arg; + ble_hci_usb_rx_acl_ll_cb = acl_cb; + ble_hci_usb_rx_acl_ll_arg = acl_arg; +} + +#define BLE_HCI_USB_EVT_COUNT \ + (MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT) + MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT)) + +/** + * A packet to be sent over the USB. This can be a command, an event, or ACL + * data. + */ +struct ble_hci_pkt { + STAILQ_ENTRY(ble_hci_pkt) next; + void *data; +}; + +static struct os_mempool ble_hci_pkt_pool; +static os_membuf_t ble_hci_pkt_buf[ + OS_MEMPOOL_SIZE(BLE_HCI_USB_EVT_COUNT + 1 + + MYNEWT_VAL(BLE_HCI_ACL_OUT_COUNT), + sizeof(struct ble_hci_pkt))]; + +struct tx_queue { + STAILQ_HEAD(, ble_hci_pkt) queue; +}; + +static struct tx_queue ble_hci_tx_acl_queue = {STAILQ_HEAD_INITIALIZER(ble_hci_tx_acl_queue.queue)}; +static struct tx_queue ble_hci_tx_evt_queue = { STAILQ_HEAD_INITIALIZER(ble_hci_tx_evt_queue.queue) }; + +/* + * TinyUSB callbacks. + */ +void +tud_bt_acl_data_sent_cb(uint16_t sent_bytes) +{ + struct os_mbuf *om; + struct ble_hci_pkt *curr_acl; + struct ble_hci_pkt *next_acl; + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + curr_acl = STAILQ_FIRST(&ble_hci_tx_acl_queue.queue); + OS_EXIT_CRITICAL(sr); + + assert(curr_acl != NULL); + om = curr_acl->data; + assert(om != NULL && om->om_len >= sent_bytes); + os_mbuf_adj(om, sent_bytes); + + while (om != NULL && om->om_len == 0) { + curr_acl->data = SLIST_NEXT(om, om_next); + os_mbuf_free(om); + om = curr_acl->data; + } + + if (om == NULL) { + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE_HEAD(&ble_hci_tx_acl_queue.queue, next); + next_acl = STAILQ_FIRST(&ble_hci_tx_acl_queue.queue); + OS_EXIT_CRITICAL(sr); + os_memblock_put(&ble_hci_pkt_pool, curr_acl); + if (next_acl != NULL) { + om = next_acl->data; + } + } + + if (om != NULL) { + tud_bt_acl_data_send(om->om_data, om->om_len); + } +} + +void +tud_bt_event_sent_cb(uint16_t sent_bytes) +{ + struct ble_hci_pkt *curr_evt; + struct ble_hci_pkt *next_evt; + uint8_t *hci_ev; + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + curr_evt = STAILQ_FIRST(&ble_hci_tx_evt_queue.queue); + OS_EXIT_CRITICAL(sr); + assert(curr_evt != NULL); + hci_ev = curr_evt->data; + + assert(hci_ev != NULL && hci_ev[1] + sizeof(struct ble_hci_ev) == sent_bytes); + + ble_hci_trans_buf_free(hci_ev); + + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE_HEAD(&ble_hci_tx_evt_queue.queue, next); + next_evt = STAILQ_FIRST(&ble_hci_tx_evt_queue.queue); + OS_EXIT_CRITICAL(sr); + os_memblock_put(&ble_hci_pkt_pool, curr_evt); + + if (next_evt != NULL) { + hci_ev = next_evt->data; + tud_bt_event_send(hci_ev, hci_ev[1] + sizeof(struct ble_hci_ev)); + } +} + +void +tud_bt_acl_data_received_cb(void *acl_data, uint16_t data_len) +{ + uint8_t *data; + uint32_t len; + struct os_mbuf *om = incoming_acl_data; + int rc; + + if (om == NULL) { + om = ble_hci_trans_acl_buf_alloc(); + assert(om != NULL); + } + assert(om->om_len + data_len <= MYNEWT_VAL(BLE_ACL_BUF_SIZE) + BLE_HCI_DATA_HDR_SZ); + + os_mbuf_append(om, acl_data, data_len); + incoming_acl_data = om; + if (om->om_len > BLE_HCI_DATA_HDR_SZ) { + data = incoming_acl_data->om_data; + len = data[2] + (data[3] << 8) + BLE_HCI_DATA_HDR_SZ; + if (len >= incoming_acl_data->om_len) { + incoming_acl_data = NULL; + rc = ble_hci_usb_rx_acl_ll_cb(om, ble_hci_usb_rx_acl_ll_arg); + (void)rc; + } + } +} + +void +tud_bt_hci_cmd_cb(void *hci_cmd, size_t cmd_len) +{ + uint8_t *buf; + int rc = -1; + + assert(ble_hci_usb_rx_cmd_ll_cb); + if (ble_hci_usb_rx_cmd_ll_cb) { + buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); + assert(buf != NULL); + memcpy(buf, hci_cmd, cmd_len); + + rc = ble_hci_usb_rx_cmd_ll_cb(buf, ble_hci_usb_rx_cmd_ll_arg); + } + + if (rc != 0) { + ble_hci_trans_buf_free(buf); + } +} + +static int +ble_hci_trans_ll_tx(struct tx_queue *queue, struct os_mbuf *om) +{ + struct ble_hci_pkt *pkt; + os_sr_t sr; + bool first; + + /* If this packet is zero length, just free it */ + if (OS_MBUF_PKTLEN(om) == 0) { + os_mbuf_free_chain(om); + return 0; + } + + pkt = os_memblock_get(&ble_hci_pkt_pool); + if (pkt == NULL) { + os_mbuf_free_chain(om); + return BLE_ERR_MEM_CAPACITY; + } + + pkt->data = om; + OS_ENTER_CRITICAL(sr); + first = STAILQ_EMPTY(&queue->queue); + STAILQ_INSERT_TAIL(&queue->queue, pkt, next); + OS_EXIT_CRITICAL(sr); + if (first) { + tud_bt_acl_data_send(om->om_data, om->om_len); + } + + return 0; +} + +int +ble_hci_trans_ll_acl_tx(struct os_mbuf *om) +{ + return ble_hci_trans_ll_tx(&ble_hci_tx_acl_queue, om); +} + +int +ble_hci_trans_ll_evt_tx(uint8_t *hci_ev) +{ + struct ble_hci_pkt *pkt; + os_sr_t sr; + bool first; + + assert(hci_ev != NULL); + + pkt = os_memblock_get(&ble_hci_pkt_pool); + if (pkt == NULL) { + ble_hci_trans_buf_free(hci_ev); + return BLE_ERR_MEM_CAPACITY; + } + + pkt->data = hci_ev; + OS_ENTER_CRITICAL(sr); + first = STAILQ_EMPTY(&ble_hci_tx_evt_queue.queue); + STAILQ_INSERT_TAIL(&ble_hci_tx_evt_queue.queue, pkt, next); + OS_EXIT_CRITICAL(sr); + if (first) { + tud_bt_event_send(hci_ev, hci_ev[1] + sizeof(struct ble_hci_ev)); + } + + return 0; +} + +uint8_t * +ble_hci_trans_buf_alloc(int type) +{ + uint8_t *buf; + + switch (type) { + case BLE_HCI_TRANS_BUF_CMD: + assert(!usb_ble_hci_pool_cmd.allocated); + usb_ble_hci_pool_cmd.allocated = 1; + buf = usb_ble_hci_pool_cmd.cmd; + break; + + case BLE_HCI_TRANS_BUF_EVT_HI: + buf = os_memblock_get(&ble_hci_usb_evt_hi_pool); + if (buf == NULL) { + /* If no high-priority event buffers remain, try to grab a + * low-priority one. + */ + buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + } + break; + + case BLE_HCI_TRANS_BUF_EVT_LO: + buf = os_memblock_get(&ble_hci_usb_evt_lo_pool); + break; + + default: + assert(0); + buf = NULL; + } + + return buf; +} + +void +ble_hci_trans_buf_free(uint8_t *buf) +{ + int rc; + + /* XXX: this may look a bit odd, but the controller uses the command + * buffer to send back the command complete/status as an immediate + * response to the command. This was done to insure that the controller + * could always send back one of these events when a command was received. + * Thus, we check to see which pool the buffer came from so we can free + * it to the appropriate pool + */ + if (os_memblock_from(&ble_hci_usb_evt_hi_pool, buf)) { + rc = os_memblock_put(&ble_hci_usb_evt_hi_pool, buf); + assert(rc == 0); + } else if (os_memblock_from(&ble_hci_usb_evt_lo_pool, buf)) { + rc = os_memblock_put(&ble_hci_usb_evt_lo_pool, buf); + assert(rc == 0); + } else { + assert(usb_ble_hci_pool_cmd.allocated); + usb_ble_hci_pool_cmd.allocated = 0; + } + (void)rc; +} + +int +ble_hci_trans_reset(void) +{ + return 0; +} + +void +ble_hci_usb_init(void) +{ + int rc; + + /* Ensure this function only gets called by sysinit. */ + SYSINIT_ASSERT_ACTIVE(); + + rc = mem_init_mbuf_pool(ble_hci_pool_acl_mempool_buf, &ble_hci_pool_acl_mempool, &ble_hci_pool_acl_mbuf_pool, + MYNEWT_VAL(BLE_ACL_BUF_COUNT), ACL_BLOCK_SIZE, "ble_hci_acl"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&ble_hci_usb_evt_hi_pool, + MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), + ble_hci_usb_evt_hi_buf, + "ble_hci_usb_evt_hi_pool"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&ble_hci_usb_evt_lo_pool, + MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), + ble_hci_usb_evt_lo_buf, + "ble_hci_usb_evt_lo_pool"); + SYSINIT_PANIC_ASSERT(rc == 0); + + /* + * Create memory pool of packet list nodes. NOTE: the number of these + * buffers should be, at least, the total number of event buffers (hi + * and lo), the number of command buffers (currently 1) and the total + * number of buffers that the controller could possibly hand to the host. + */ + rc = os_mempool_init(&ble_hci_pkt_pool, + BLE_HCI_USB_EVT_COUNT + 1 + + MYNEWT_VAL(BLE_HCI_ACL_OUT_COUNT), + sizeof (struct ble_hci_pkt), + ble_hci_pkt_buf, + "ble_hci_usb_pkt_pool"); + SYSINIT_PANIC_ASSERT(rc == 0); +} diff --git a/src/libs/mynewt-nimble/nimble/transport/usb/syscfg.yml b/src/libs/mynewt-nimble/nimble/transport/usb/syscfg.yml new file mode 100644 index 00000000..ebc261a2 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/usb/syscfg.yml @@ -0,0 +1,57 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +syscfg.defs: + BLE_HCI_EVT_BUF_SIZE: + description: 'The size of the allocated event buffers' + value: 70 + BLE_HCI_EVT_HI_BUF_COUNT: + description: 'The number of high priority event buffers' + value: 8 + BLE_HCI_EVT_LO_BUF_COUNT: + description: 'The number of low priority event buffers' + value: 8 + BLE_ACL_BUF_COUNT: + description: 'The number of ACL data buffers' + value: 12 + BLE_ACL_BUF_SIZE: + description: > + This is the maximum size of the data portion of HCI ACL data + packets. It does not include the HCI data header (of 4 bytes). + value: 255 + + BLE_HCI_ACL_OUT_COUNT: + description: > + This count is used in creating a pool of elements used by the + code to enqueue various elements. In the case of the controller + only HCI, this number should be equal to the number of mbufs in + the msys pool. For host only, it is really dependent on the + number of ACL buffers that the controller tells the host it + has. + value: 12 + + BLE_TRANS_USB_SYSINIT_STAGE: + description: > + Sysinit stage for the USB BLE transport. + value: 500 + +syscfg.vals.BLE_EXT_ADV: + BLE_HCI_EVT_BUF_SIZE: 257 + +syscfg.restrictions: + - '!BLE_HOST' |