From bdc10744fb338ae197692713a0b48a7ccc36f566 Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 26 Apr 2020 10:25:59 +0200 Subject: Add Nimble in libs directory --- .../nimble/transport/da1469x/.gitignore | 2 + .../mynewt-nimble/nimble/transport/da1469x/README | 13 + .../cmac_driver/include/cmac_driver/cmac_host.h | 37 +++ .../nimble/transport/da1469x/cmac_driver/pkg.yml | 27 ++ .../da1469x/cmac_driver/scripts/build_libcmac.sh | 51 +++ .../transport/da1469x/cmac_driver/src/cmac_host.c | 326 ++++++++++++++++++ .../transport/da1469x/cmac_driver/syscfg.yml | 23 ++ .../mynewt-nimble/nimble/transport/da1469x/pkg.yml | 38 +++ .../nimble/transport/da1469x/src/da1469x_ble_hci.c | 368 +++++++++++++++++++++ .../nimble/transport/da1469x/syscfg.yml | 43 +++ 10 files changed, 928 insertions(+) create mode 100644 src/libs/mynewt-nimble/nimble/transport/da1469x/.gitignore create mode 100644 src/libs/mynewt-nimble/nimble/transport/da1469x/README create mode 100644 src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/include/cmac_driver/cmac_host.h create mode 100644 src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/pkg.yml create mode 100755 src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/scripts/build_libcmac.sh create mode 100644 src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/src/cmac_host.c create mode 100644 src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/syscfg.yml create mode 100644 src/libs/mynewt-nimble/nimble/transport/da1469x/pkg.yml create mode 100644 src/libs/mynewt-nimble/nimble/transport/da1469x/src/da1469x_ble_hci.c create mode 100644 src/libs/mynewt-nimble/nimble/transport/da1469x/syscfg.yml (limited to 'src/libs/mynewt-nimble/nimble/transport/da1469x') diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/.gitignore b/src/libs/mynewt-nimble/nimble/transport/da1469x/.gitignore new file mode 100644 index 00000000..bba9f995 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/.gitignore @@ -0,0 +1,2 @@ +/src/libble_stack_da1469x.a + diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/README b/src/libs/mynewt-nimble/nimble/transport/da1469x/README new file mode 100644 index 00000000..b30a01c4 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/README @@ -0,0 +1,13 @@ +Integrated BLE Controller (CMAC) requires a binary firmware to be loaded. Such +firmware is distributed by Dialog Semiconductor in SDK package which has to be +obtained separately, see: +https://www.dialog-semiconductor.com/products/da1469x-product-family + +Firmware is available as part of following library in SDK package: +sdk/interfaces/ble/binaries/DA1469x-Release/libble_stack_da1469x.a + +By default, CMAC driver will look for this file in its package root directory +(i.e. nimble/transport/da1469x/cmac_driver) but this can be changed using +CMAC_IMAGE_FILE_NAME syscfg variable. + +Current version of CMAC driver was tested with SDK version 10.0.4.66. diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/include/cmac_driver/cmac_host.h b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/include/cmac_driver/cmac_host.h new file mode 100644 index 00000000..f623a48a --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/include/cmac_driver/cmac_host.h @@ -0,0 +1,37 @@ +/* + * 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 __CMAC_HOST_H_ +#define __CMAC_HOST_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (* cmac_mbox_read_cb)(const uint8_t *, uint16_t len); + +void cmac_host_init(void); +void cmac_mbox_write(const uint8_t *buf, size_t len); +void cmac_mbox_set_read_cb(cmac_mbox_read_cb cb); + +#ifdef __cplusplus +} +#endif + +#endif /* __CMAC_HOST_H_ */ diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/pkg.yml new file mode 100644 index 00000000..90a89318 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/pkg.yml @@ -0,0 +1,27 @@ +# +# 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/da1469x/cmac_driver +pkg.description: Driver for Dialog's BLE controller +pkg.author: +pkg.homepage: +pkg.keywords: + +pkg.pre_link_cmds.BLE_HOST: + scripts/build_libcmac.sh: 100 diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/scripts/build_libcmac.sh b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/scripts/build_libcmac.sh new file mode 100755 index 00000000..659c2b9f --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/scripts/build_libcmac.sh @@ -0,0 +1,51 @@ +#!/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. + +if [ ! -f ${MYNEWT_VAL_CMAC_IMAGE_FILE_NAME} ]; then + >&2 echo ERROR: BLE stack library not found. Please check nimble/transport/da1469x/README for details. + exit 1 +fi + +OBJCOPY=${MYNEWT_OBJCOPY_PATH} +AR=${MYNEWT_AR_PATH} +LIBBLE_A=$(readlink -e ${MYNEWT_VAL_CMAC_IMAGE_FILE_NAME}) +LIBCMAC_A=${MYNEWT_USER_SRC_DIR}/libcmac.a + +BASENAME_ROM=cmac.rom +BASENAME_RAM=cmac.ram + +cd ${MYNEWT_USER_WORK_DIR} + +# Extract firmware binary from .a since we do not need to link all other +# objects with our image. +${AR} x ${LIBBLE_A} cmac_fw.c.obj +${OBJCOPY} -O binary --only-section=.cmi_fw_area cmac_fw.c.obj cmac.bin + +# We need separate copies for RAM and ROM image since section names are derived +# from file names. For now files are the same, but it would be possible to +# link ROM image without data and shared sections which contains zeroes anyway. +cp cmac.bin ${BASENAME_ROM}.bin +cp cmac.bin ${BASENAME_RAM}.bin + +# 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/da1469x/cmac_driver/src/cmac_host.c b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/src/cmac_host.c new file mode 100644 index 00000000..0bfb715e --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/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 +#include +#include +#include +#include "os/os.h" +#include "mcu/cmsis_nvic.h" +#include "mcu/da1469x_lpclk.h" +#include "mcu/da1469x_hal.h" +#include "mcu/da1469x_pdc.h" +#include "mcu/mcu.h" +#include "cmac_driver/cmac_host.h" + +#define CMAC_SYM_CONFIG ((void *)(0x00818f20 + MEMCTRL->CMI_CODE_BASE_REG)) +#define CMAC_SYM_CONFIG_DYN ((void *)(0x00821af8 + MEMCTRL->CMI_CODE_BASE_REG)) +#define CMAC_SYM_MBOX_RX ((void *)(0x008216b0 + MEMCTRL->CMI_CODE_BASE_REG)) +#define CMAC_SYM_MBOX_TX ((void *)(0x008218b0 + MEMCTRL->CMI_CODE_BASE_REG)) + +#define CMAC_MBOX_SIZE 504 +#define CMAC_MBOX_F_RESET 0x0008 +#define CMAC_MBOX_F_WRITEPENDING 0x0010 + +struct cmac_config { + uint8_t bdaddr[6]; /* Device address */ + + uint8_t rf_calibration_delay; + + uint8_t lp_clock_freq; /* Sleep clock frequency (0 = 32768Hz, 1 = 32000Hz) */ + uint16_t lp_clock_sca; /* Sleep clock accuracy [ppm] */ + + uint16_t rx_buf_len; /* RX buffer size */ + uint16_t tx_buf_len; /* TX buffer size */ + bool initial_length_req; + + /* Channel assessment algorithm settings */ + uint16_t chan_assess_itvl; + uint8_t chan_assess_itvl_mult; + int8_t chan_assess_min_rssi; + uint16_t chan_assess_pkt_num; + uint16_t chan_assess_bad_pkt_num; + + /* Calibration settings */ + uint8_t system_tcs_length; + uint8_t synth_tcs_length; + uint8_t rfcu_tcs_length; + + uint8_t default_tx_power; /* Default TX power for connection/advertising */ + bool filter_dup_ov_discard; /* Discard unknown devices when filter buffer is full */ + bool use_hp_1m; + bool use_hp_2m; +}; + +struct cmac_config_dynamic { + bool enable_sleep; /* Enable sleep */ + + /* More options here, don't care now */ +}; + +struct cmac_mbox { + volatile uint16_t magic; + volatile uint16_t flags; + volatile uint16_t wr_off; + volatile uint16_t rd_off; + uint8_t data[CMAC_MBOX_SIZE]; +}; + +/* 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 _dummy1; + uint32_t size_rom; + uint32_t _dummy2; + uint32_t magic; + uint32_t _dummy3[5]; +}; + +/* Mailboxes for SYS<->CMAC communication */ +static struct cmac_mbox *cmac_mbox_rx; +static struct cmac_mbox *cmac_mbox_tx; + +/* 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; +/* Callback for data ready from CMAC */ +static cmac_mbox_read_cb g_cmac_mbox_read_cb; + +static inline void +cmac_host_signal2cmac(void) +{ + da1469x_pdc_set(g_cmac_host_pdc_sys2cmac); +} + +static void +cmac2sys_isr(void) +{ + uint16_t wr_off; + uint16_t rd_off; + uint16_t chunk; + uint16_t len; + + os_trace_isr_enter(); + + /* Clear CMAC2SYS interrupt */ + *(volatile uint32_t *)0x40002000 = 2; + + if (*(volatile uint32_t *)0x40002000 & 0x1c00) { + /* XXX CMAC is in error state, need to recover */ + assert(0); + } + + if (cmac_mbox_rx->flags & CMAC_MBOX_F_RESET) { + cmac_mbox_rx->flags &= ~CMAC_MBOX_F_RESET; + goto done; + } + + if (!g_cmac_mbox_read_cb) { + cmac_mbox_rx->rd_off = cmac_mbox_rx->wr_off; + goto done; + } + + do { + rd_off = cmac_mbox_rx->rd_off; + wr_off = cmac_mbox_rx->wr_off; + + if (rd_off <= wr_off) { + chunk = wr_off - rd_off; + } else { + chunk = CMAC_MBOX_SIZE - rd_off; + } + + while (chunk) { + len = g_cmac_mbox_read_cb(&cmac_mbox_rx->data[rd_off], chunk); + + rd_off += len; + chunk -= len; + }; + + cmac_mbox_rx->rd_off = rd_off % CMAC_MBOX_SIZE; + } while (cmac_mbox_rx->rd_off != cmac_mbox_rx->wr_off); + +done: + + if (cmac_mbox_rx->flags & CMAC_MBOX_F_WRITEPENDING) { + cmac_host_signal2cmac(); + } + + os_trace_isr_exit(); +} + +static void +cmac_host_lpclk_cb(uint32_t freq) +{ + struct cmac_config_dynamic *cmac_config_dyn; + + cmac_config_dyn = CMAC_SYM_CONFIG_DYN; + cmac_config_dyn->enable_sleep = freq == 32768; +} + +void +cmac_mbox_write(const uint8_t *buf, size_t len) +{ + uint16_t wr_off; + uint16_t rd_off; + uint16_t chunk; + uint32_t primask; + + __HAL_DISABLE_INTERRUPTS(primask); + + while (len) { + rd_off = cmac_mbox_tx->rd_off; + wr_off = cmac_mbox_tx->wr_off; + + if (rd_off > wr_off) { + chunk = min(len, rd_off - wr_off); + } else { + chunk = min(len, CMAC_MBOX_SIZE - wr_off); + } + + if (chunk == 0) { + continue; + } + + memcpy(&cmac_mbox_tx->data[wr_off], buf, chunk); + + wr_off += chunk; + cmac_mbox_tx->wr_off = wr_off % CMAC_MBOX_SIZE; + + cmac_host_signal2cmac(); + + len -= chunk; + buf += chunk; + } + + __HAL_ENABLE_INTERRUPTS(primask); +} + +void +cmac_mbox_set_read_cb(cmac_mbox_read_cb cb) +{ + g_cmac_mbox_read_cb = cb; +} + +void +cmac_host_init(void) +{ + struct cmac_image_info ii; + uint32_t cmac_rom_size; + uint32_t cmac_ram_size; + struct cmac_config *cmac_config; + struct cmac_config_dynamic *cmac_config_dyn; + + /* Add PDC entry to wake up CMAC from M33 */ + 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); + } + + /* 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 (for now they should be the same) */ + 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]; + assert(cmac_rom_size == cmac_ram_size); + + /* Load image header and check if image can be loaded */ + memcpy(&ii, &_binary_cmac_rom_bin_start, sizeof(ii)); + assert(ii.magic == 0x43414d43); /* "CMAC" */ + + /* Copy CMAC image to RAM */ + memset(&_binary_cmac_ram_bin_start, 0, cmac_ram_size); + memcpy(&_binary_cmac_ram_bin_start, &_binary_cmac_rom_bin_start[sizeof(ii)], + ii.size_rom); + + /* + * Setup memory controller for CMAC + * Code and data are set to the same address initially since CMAC will + * update data address on init. Also shared address is updated on init. + */ + MEMCTRL->CMI_CODE_BASE_REG = (uint32_t)&_binary_cmac_ram_bin_start; + MEMCTRL->CMI_DATA_BASE_REG = MEMCTRL->CMI_CODE_BASE_REG; + MEMCTRL->CMI_SHARED_BASE_REG = 0; + MEMCTRL->CMI_END_REG = (uint32_t)&_binary_cmac_ram_bin_end; + + /* Symbols below are in shared memory, can update them now */ + cmac_config = CMAC_SYM_CONFIG; + cmac_config_dyn = CMAC_SYM_CONFIG_DYN; + cmac_mbox_rx = CMAC_SYM_MBOX_RX; + cmac_mbox_tx = CMAC_SYM_MBOX_TX; + + /* Update CMAC configuration */ + cmac_config->lp_clock_freq = 0; + cmac_config->lp_clock_sca = 50; + cmac_config->rx_buf_len = 251 + 11; + cmac_config->tx_buf_len = 251 + 11; + cmac_config->initial_length_req = 0; + cmac_config->system_tcs_length = 0; + cmac_config->synth_tcs_length = 0; + cmac_config->rfcu_tcs_length = 0; + cmac_config->default_tx_power = 4; + cmac_config_dyn->enable_sleep = false; + + /* Release CMAC from reset */ + CRG_TOP->CLK_RADIO_REG &= ~CRG_TOP_CLK_RADIO_REG_CMAC_SYNCH_RESET_Msk; + + /* Wait for CMAC to update registers */ + while (MEMCTRL->CMI_DATA_BASE_REG == MEMCTRL->CMI_CODE_BASE_REG); + while (MEMCTRL->CMI_SHARED_BASE_REG != (MEMCTRL->CMI_END_REG & 0xfffffc00)); + + /* Initialize mailboxes and sync with CMAC */ + cmac_mbox_tx->flags = CMAC_MBOX_F_RESET; + cmac_mbox_tx->wr_off = 0; + cmac_mbox_tx->rd_off = 0; + cmac_mbox_tx->magic = 0xa55a; + while (cmac_mbox_rx->magic != 0xa55a); + + NVIC_SetVector(CMAC2SYS_IRQn, (uint32_t)cmac2sys_isr); + NVIC_SetPriority(CMAC2SYS_IRQn, 0); + NVIC_EnableIRQ(CMAC2SYS_IRQn); + + cmac_host_signal2cmac(); + + da1469x_lpclk_register_cmac_cb(cmac_host_lpclk_cb); +} diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/syscfg.yml b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/syscfg.yml new file mode 100644 index 00000000..be2e62d9 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/syscfg.yml @@ -0,0 +1,23 @@ +# 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_IMAGE_FILE_NAME: + description: > + Path to library with CMAC firmware. See README for details. + value: "libble_stack_da1469x.a" diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/da1469x/pkg.yml new file mode 100644 index 00000000..5d9b533c --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/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/da1469x +pkg.description: HCI transport for DA1469x +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + +pkg.deps: + - "@apache-mynewt-nimble/nimble" + - "@apache-mynewt-nimble/nimble/transport/da1469x/cmac_driver" + - "@apache-mynewt-core/kernel/os" + +pkg.apis: + - ble_transport + +pkg.init: + da1469x_ble_hci_init: 100 + da1469x_ble_hci_cmac_init: 201 diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/src/da1469x_ble_hci.c b/src/libs/mynewt-nimble/nimble/transport/da1469x/src/da1469x_ble_hci.c new file mode 100644 index 00000000..971d0cd0 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/src/da1469x_ble_hci.c @@ -0,0 +1,368 @@ +/* + * 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 +#include +#include "os/mynewt.h" +#include "nimble/ble.h" +#include "nimble/ble_hci_trans.h" +#include "nimble/hci_common.h" +#include "cmac_driver/cmac_host.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) + +struct da1469x_ble_hci_host_api { + ble_hci_trans_rx_cmd_fn *evt_cb; + void *evt_arg; + ble_hci_trans_rx_acl_fn *acl_cb; + void *acl_arg; +}; + +struct da1469x_ble_hci_rx_data { + uint8_t type; + uint8_t hdr[4]; + uint8_t min_len; + uint16_t len; + uint16_t expected_len; + union { + uint8_t *buf; + struct os_mbuf *om; + }; +}; + +struct da1469x_ble_hci_pool_cmd { + uint8_t cmd[BLE_HCI_TRANS_CMD_SZ]; + bool allocated; +}; + +/* (Pseudo)pool for HCI commands */ +static struct da1469x_ble_hci_pool_cmd da1469x_ble_hci_pool_cmd; + +/* Pools for HCI events (high and low priority) */ +static uint8_t da1469x_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 da1469x_ble_hci_pool_evt_hi; +static uint8_t da1469x_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 da1469x_ble_hci_pool_evt_lo; + +/* Pool for ACL data */ +static uint8_t da1469x_ble_hci_pool_acl_buf[ OS_MEMPOOL_BYTES( + MYNEWT_VAL(BLE_ACL_BUF_COUNT), + POOL_ACL_BLOCK_SIZE) ]; +static struct os_mempool da1469x_ble_hci_pool_acl; +static struct os_mbuf_pool da1469x_ble_hci_pool_acl_mbuf; + +/* Interface to host */ +static struct da1469x_ble_hci_host_api da1469x_ble_hci_host_api; + +/* State of RX currently in progress (needs to reassemble frame) */ +static struct da1469x_ble_hci_rx_data da1469x_ble_hci_rx_data; + +int +ble_hci_trans_reset(void) +{ + /* XXX Should we do something with RF and/or BLE core? */ + return 0; +} + +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) +{ + da1469x_ble_hci_host_api.evt_cb = evt_cb; + da1469x_ble_hci_host_api.evt_arg = evt_arg; + da1469x_ble_hci_host_api.acl_cb = acl_cb; + da1469x_ble_hci_host_api.acl_arg = acl_arg; +} + +uint8_t * +ble_hci_trans_buf_alloc(int type) +{ + uint8_t *buf; + + switch (type) { + case BLE_HCI_TRANS_BUF_CMD: + assert(!da1469x_ble_hci_pool_cmd.allocated); + da1469x_ble_hci_pool_cmd.allocated = 1; + buf = da1469x_ble_hci_pool_cmd.cmd; + break; + case BLE_HCI_TRANS_BUF_EVT_HI: + buf = os_memblock_get(&da1469x_ble_hci_pool_evt_hi); + if (buf) { + break; + } + /* no break */ + case BLE_HCI_TRANS_BUF_EVT_LO: + buf = os_memblock_get(&da1469x_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 == da1469x_ble_hci_pool_cmd.cmd) { + assert(da1469x_ble_hci_pool_cmd.allocated); + da1469x_ble_hci_pool_cmd.allocated = 0; + } else if (os_memblock_from(&da1469x_ble_hci_pool_evt_hi, buf)) { + rc = os_memblock_put(&da1469x_ble_hci_pool_evt_hi, buf); + assert(rc == 0); + } else { + assert(os_memblock_from(&da1469x_ble_hci_pool_evt_lo, buf)); + rc = os_memblock_put(&da1469x_ble_hci_pool_evt_lo, buf); + assert(rc == 0); + } +} + +int +ble_hci_trans_hs_cmd_tx(uint8_t *cmd) +{ + uint8_t ind = HCI_PKT_CMD; + int len = 3 + cmd[2]; + + cmac_mbox_write(&ind, 1); + cmac_mbox_write(cmd, len); + + ble_hci_trans_buf_free(cmd); + + return 0; +} + +int +ble_hci_trans_hs_acl_tx(struct os_mbuf *om) +{ + uint8_t ind = HCI_PKT_ACL; + struct os_mbuf *x; + + cmac_mbox_write(&ind, 1); + + x = om; + while (x) { + cmac_mbox_write(x->om_data, x->om_len); + x = SLIST_NEXT(x, om_next); + } + + os_mbuf_free_chain(om); + + return 0; +} + +static int +da1469x_ble_hci_trans_ll_rx(const uint8_t *buf, uint16_t len) +{ + struct da1469x_ble_hci_rx_data *rxd = &da1469x_ble_hci_rx_data; + void *data; + int pool = BLE_HCI_TRANS_BUF_EVT_HI; + int rc; + + assert(len); + + if (rxd->type == HCI_PKT_NONE) { + rxd->type = buf[0]; + rxd->len = 0; + rxd->expected_len = 0; + + switch (rxd->type) { + case HCI_PKT_ACL: + rxd->min_len = 4; + break; + case HCI_PKT_EVT: + rxd->min_len = 2; + break; + default: + assert(0); + break; + } + + return 1; + } + + /* Ensure we have minimum length of bytes required to process header */ + if (rxd->len < rxd->min_len) { + len = min(len, rxd->min_len - rxd->len); + memcpy(&rxd->hdr[rxd->len], buf, len); + rxd->len += len; + return len; + } + + /* Parse header and allocate proper buffer if not done yet */ + if (rxd->expected_len == 0) { + switch (rxd->type) { + case HCI_PKT_ACL: + data = os_mbuf_get_pkthdr(&da1469x_ble_hci_pool_acl_mbuf, + sizeof(struct ble_mbuf_hdr)); + if (!data) { + return 0; + } + + rxd->om = data; + os_mbuf_append(rxd->om, rxd->hdr, rxd->len); + rxd->expected_len = get_le16(&rxd->hdr[2]) + 4; + break; + case HCI_PKT_EVT: + if (rxd->hdr[0] == BLE_HCI_EVCODE_LE_META) { + /* For LE Meta event we need 3 bytes to parse header */ + if (rxd->min_len < 3) { + rxd->min_len = 3; + return 0; + } + + /* 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; + } + } + + data = ble_hci_trans_buf_alloc(pool); + if (!data) { + /* + * 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) { + data = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + if (!data) { + return 0; + } + } + } + + rxd->buf = data; + memcpy(rxd->buf, rxd->hdr, rxd->len); + rxd->expected_len = rxd->hdr[1] + 2; + break; + default: + assert(0); + return len; + } + } + + len = min(len, rxd->expected_len - rxd->len); + + switch (rxd->type) { + case HCI_PKT_ACL: + os_mbuf_append(rxd->om, buf, len); + rxd->len += len; + + if (rxd->len == rxd->expected_len) { + rc = da1469x_ble_hci_host_api.acl_cb(rxd->om, + da1469x_ble_hci_host_api.acl_arg); + if (rc != 0) { + os_mbuf_free_chain(rxd->om); + } + rxd->type = HCI_PKT_NONE; + } + break; + case HCI_PKT_EVT: + if (rxd->buf) { + memcpy(&rxd->buf[rxd->len], buf, len); + } + rxd->len += len; + + if (rxd->len == rxd->expected_len) { + /* + * XXX for unknown reason at startup controller sends command + * complete for a vendor specific command which we never sent + * and this messes up with our ack code - just discard this + * event + */ + if ((rxd->buf[0] == 0x0E) && (get_le16(&rxd->buf[3]) == 0xfc11)) { + ble_hci_trans_buf_free(rxd->buf); + } else if (rxd->buf) { + rc = da1469x_ble_hci_host_api.evt_cb(rxd->buf, + da1469x_ble_hci_host_api.evt_arg); + if (rc != 0) { + ble_hci_trans_buf_free(rxd->buf); + } + } + rxd->type = HCI_PKT_NONE; + } + break; + default: + assert(0); + break; + } + + return len; +} + +static int +da1469x_ble_hci_read_cb(const uint8_t *buf, uint16_t len) +{ + return da1469x_ble_hci_trans_ll_rx(buf, len); +} + +void +da1469x_ble_hci_init(void) +{ + int rc; + + SYSINIT_ASSERT_ACTIVE(); + + rc = os_mempool_init(&da1469x_ble_hci_pool_acl, MYNEWT_VAL(BLE_ACL_BUF_COUNT), + POOL_ACL_BLOCK_SIZE, da1469x_ble_hci_pool_acl_buf, + "da1469x_ble_hci_pool_acl"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mbuf_pool_init(&da1469x_ble_hci_pool_acl_mbuf, + &da1469x_ble_hci_pool_acl, POOL_ACL_BLOCK_SIZE, + MYNEWT_VAL(BLE_ACL_BUF_COUNT)); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&da1469x_ble_hci_pool_evt_hi, + MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), + da1469x_ble_hci_pool_evt_hi_buf, + "da1469x_ble_hci_pool_evt_hi"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&da1469x_ble_hci_pool_evt_lo, + MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), + da1469x_ble_hci_pool_evt_lo_buf, + "da1469x_ble_hci_pool_evt_lo"); + SYSINIT_PANIC_ASSERT(rc == 0); +} + +void +da1469x_ble_hci_cmac_init(void) +{ + cmac_mbox_set_read_cb(da1469x_ble_hci_read_cb); + cmac_host_init(); +} diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/syscfg.yml b/src/libs/mynewt-nimble/nimble/transport/da1469x/syscfg.yml new file mode 100644 index 00000000..4ea9da9b --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/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_HCI_EVT_BUF_SIZE: 274 -- cgit v1.2.3