diff --git a/nimble/transport/pkg.yml b/nimble/transport/pkg.yml index 5070c72883..30237f75bd 100644 --- a/nimble/transport/pkg.yml +++ b/nimble/transport/pkg.yml @@ -48,6 +48,8 @@ pkg.deps.'BLE_TRANSPORT_HS == "cdc"': - nimble/transport/cdc pkg.deps.'BLE_TRANSPORT_LL == "apollo3"': - nimble/transport/apollo3 +pkg.deps.'BLE_TRANSPORT_LL == "uart_ll"': + - nimble/transport/uart_ll pkg.deps.BLE_MONITOR_RTT: - "@apache-mynewt-core/hw/drivers/rtt" diff --git a/nimble/transport/syscfg.yml b/nimble/transport/syscfg.yml index 7f02f6cc8f..febe09d401 100644 --- a/nimble/transport/syscfg.yml +++ b/nimble/transport/syscfg.yml @@ -46,6 +46,7 @@ syscfg.defs: - nrf5340 - socket - apollo3 + - uart_ll - custom BLE_TRANSPORT_ACL_COUNT: diff --git a/nimble/transport/uart_ll/pkg.yml b/nimble/transport/uart_ll/pkg.yml new file mode 100644 index 0000000000..efc97d5456 --- /dev/null +++ b/nimble/transport/uart_ll/pkg.yml @@ -0,0 +1,32 @@ +# +# 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/uart_ll +pkg.description: HCI H4 transport over UART to external controller +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" + +pkg.deps: + - "@apache-mynewt-core/hw/hal" + - "@apache-mynewt-core/kernel/os" + - nimble + - nimble/transport/common/hci_h4 + +pkg.apis: + - ble_transport diff --git a/nimble/transport/uart_ll/src/hci_uart.c b/nimble/transport/uart_ll/src/hci_uart.c new file mode 100644 index 0000000000..95eae3f4b3 --- /dev/null +++ b/nimble/transport/uart_ll/src/hci_uart.c @@ -0,0 +1,245 @@ +/* + * 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 +#include +#include "os/os_mbuf.h" +#include "os/os_mempool.h" +#include "hal/hal_uart.h" +#include "nimble/transport.h" +#include "nimble/transport/hci_h4.h" + +#define TX_Q_SIZE (MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_HS_COUNT) + 1) + +struct hci_uart_tx { + uint8_t type; + uint8_t sent_type; + uint16_t len; + uint16_t idx; + + struct os_mbuf *om; + uint8_t *buf; + + STAILQ_ENTRY(hci_uart_tx) tx_q_next; +}; + +static STAILQ_HEAD(, hci_uart_tx) tx_q; + +static struct os_mempool pool_tx_q; +static uint8_t pool_tx_q_buf[ OS_MEMPOOL_BYTES(TX_Q_SIZE, + sizeof(struct hci_uart_tx)) ]; + +struct hci_h4_sm hci_uart_h4sm; + +static int +hci_uart_frame_cb(uint8_t pkt_type, void *data) +{ + switch (pkt_type) { + case HCI_H4_EVT: + return ble_transport_to_hs_evt(data); + case HCI_H4_ACL: + return ble_transport_to_hs_acl(data); + default: + assert(0); + break; + } + + return -1; +} + +static int +hci_uart_rx_char(void *arg, uint8_t data) +{ + hci_h4_sm_rx(&hci_uart_h4sm, &data, 1); + + return 0; +} + +static int +hci_uart_tx_char(void *arg) +{ + struct hci_uart_tx *tx; + uint8_t ch; + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + tx = STAILQ_FIRST(&tx_q); + OS_EXIT_CRITICAL(sr); + if (!tx) { + return -1; + } + + if (!tx->sent_type) { + tx->sent_type = 1; + return tx->type; + } + + switch (tx->type) { + case HCI_H4_CMD: + ch = tx->buf[tx->idx]; + tx->idx++; + if (tx->idx == tx->len) { + ble_transport_free(tx->buf); + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE_HEAD(&tx_q, tx_q_next); + OS_EXIT_CRITICAL(sr); + os_memblock_put(&pool_tx_q, tx); + } + break; + case HCI_H4_ACL: + os_mbuf_copydata(tx->om, 0, 1, &ch); + os_mbuf_adj(tx->om, 1); + tx->len--; + if (tx->len == 0) { + os_mbuf_free_chain(tx->om); + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE_HEAD(&tx_q, tx_q_next); + OS_EXIT_CRITICAL(sr); + os_memblock_put(&pool_tx_q, tx); + } + break; + default: + assert(0); + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE_HEAD(&tx_q, tx_q_next); + OS_EXIT_CRITICAL(sr); + os_memblock_put(&pool_tx_q, tx); + } + + return ch; +} + +static int +hci_uart_configure(void) +{ + enum hal_uart_parity parity; + enum hal_uart_flow_ctl flowctl; + int rc; + + rc = hal_uart_init_cbs(MYNEWT_VAL(BLE_TRANSPORT_UART_PORT), + hci_uart_tx_char, NULL, + hci_uart_rx_char, NULL); + if (rc != 0) { + return -1; + } + + if (MYNEWT_VAL_CHOICE(BLE_TRANSPORT_UART_PARITY, odd)) { + parity = HAL_UART_PARITY_ODD; + } else if (MYNEWT_VAL_CHOICE(BLE_TRANSPORT_UART_PARITY, even)) { + parity = HAL_UART_PARITY_EVEN; + } else { + parity = HAL_UART_PARITY_NONE; + } + + if (MYNEWT_VAL_CHOICE(BLE_TRANSPORT_UART_FLOW_CONTROL, rtscts)) { + flowctl = HAL_UART_FLOW_CTL_RTS_CTS; + } else { + flowctl = HAL_UART_FLOW_CTL_NONE; + } + + rc = hal_uart_config(MYNEWT_VAL(BLE_TRANSPORT_UART_PORT), + MYNEWT_VAL(BLE_TRANSPORT_UART_BAUDRATE), + MYNEWT_VAL(BLE_TRANSPORT_UART_DATA_BITS), + MYNEWT_VAL(BLE_TRANSPORT_UART_STOP_BITS), + parity, flowctl); + if (rc != 0) { + return -1; + } + + return 0; +} + +int +ble_transport_to_ll_cmd_impl(void *buf) +{ + struct hci_uart_tx *txe; + os_sr_t sr; + + txe = os_memblock_get(&pool_tx_q); + if (!txe) { + assert(0); + return -ENOMEM; + } + + txe->type = HCI_H4_CMD; + txe->sent_type = 0; + txe->len = 3 + ((uint8_t *)buf)[2]; + txe->buf = buf; + txe->idx = 0; + txe->om = NULL; + + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&tx_q, txe, tx_q_next); + OS_EXIT_CRITICAL(sr); + + hal_uart_start_tx(MYNEWT_VAL(BLE_TRANSPORT_UART_PORT)); + + return 0; +} + +int +ble_transport_to_ll_acl_impl(struct os_mbuf *om) +{ + struct hci_uart_tx *txe; + os_sr_t sr; + + txe = os_memblock_get(&pool_tx_q); + if (!txe) { + assert(0); + return -ENOMEM; + } + + txe->type = HCI_H4_ACL; + txe->sent_type = 0; + txe->len = OS_MBUF_PKTLEN(om); + txe->idx = 0; + txe->buf = NULL; + txe->om = om; + + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&tx_q, txe, tx_q_next); + OS_EXIT_CRITICAL(sr); + + hal_uart_start_tx(MYNEWT_VAL(BLE_TRANSPORT_UART_PORT)); + + return 0; +} + +void +ble_transport_ll_init(void) +{ + int rc; + + SYSINIT_ASSERT_ACTIVE(); + + rc = hci_uart_configure(); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&pool_tx_q, TX_Q_SIZE, sizeof(struct hci_uart_tx), + pool_tx_q_buf, "hci_uart_tx_q"); + SYSINIT_PANIC_ASSERT(rc == 0); + + hci_h4_sm_init(&hci_uart_h4sm, &hci_h4_allocs_from_ll, hci_uart_frame_cb); + + STAILQ_INIT(&tx_q); +} diff --git a/nimble/transport/uart_ll/syscfg.yml b/nimble/transport/uart_ll/syscfg.yml new file mode 100644 index 0000000000..ccf38b61a5 --- /dev/null +++ b/nimble/transport/uart_ll/syscfg.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. +# + +syscfg.defs: + BLE_TRANSPORT_UART_LL_PORT: + description: UART index to use for HCI interface + value: 0 + BLE_TRANSPORT_UART_LL_BAUDRATE: + description: Baudrate on UART + value: 1000000 + BLE_TRANSPORT_UART_LL_DATA_BITS: + description: Number of data bits on UART + value: 8 + BLE_TRANSPORT_UART_LL_STOP_BITS: + description: Number of stop bits on UART + value: 1 + BLE_TRANSPORT_UART_LL_PARITY: + description: Parity on UART + value: none + choices: none,even,odd + BLE_TRANSPORT_UART_LL_FLOW_CONTROL: + description: Flow control on UART + choices: off,rtscts + value: rtscts