diff --git a/boards/sim/sim/sim/src/sim_bringup.c b/boards/sim/sim/sim/src/sim_bringup.c index 643cbafd4da..79ebca96244 100644 --- a/boards/sim/sim/sim/src/sim_bringup.c +++ b/boards/sim/sim/sim/src/sim_bringup.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -354,6 +355,17 @@ int sim_bringup(void) } #endif +#ifdef CONFIG_BLUETOOTH_UART_BRIDGE + /* Register the Bluetooth BT/BLE dual mode bridge driver */ + + ret = bt_uart_bridge_register("/dev/ttyHCI0", + "/dev/ttyBT", "/dev/ttyBLE"); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: bt_uart_bridge_register() failed: %d\n", ret); + } +#endif + #ifdef CONFIG_SIM_I2CBUS /* Initialize the i2c master bus device */ diff --git a/drivers/wireless/bluetooth/Kconfig b/drivers/wireless/bluetooth/Kconfig index 039980ecc6d..5c0d29f5417 100644 --- a/drivers/wireless/bluetooth/Kconfig +++ b/drivers/wireless/bluetooth/Kconfig @@ -57,6 +57,13 @@ config BLUETOOTH_UART_DUMP endif # BLUETOOTH_UART +config BLUETOOTH_UART_BRIDGE + bool "Bluetooth BT/BLE Dual Mode UART Bridge Driver" + select MM_CIRCBUF + default n + ---help--- + Enable Bluetooth BT/BLE Dual Mode UART Bridge Driver. + config BLUETOOTH_NULL bool "NULL Bluetooth device" default n diff --git a/drivers/wireless/bluetooth/Make.defs b/drivers/wireless/bluetooth/Make.defs index 4eb538e9c8e..8548d7903c9 100644 --- a/drivers/wireless/bluetooth/Make.defs +++ b/drivers/wireless/bluetooth/Make.defs @@ -55,6 +55,11 @@ CSRCS += bt_uart_bcm4343x.c endif endif +ifeq ($(CONFIG_BLUETOOTH_UART_BRIDGE),y) +CSRCS += bt_uart_bridge.c +CSRCS += bt_uart_filter.c +endif + ifeq ($(CONFIG_BLUETOOTH_NULL),y) CSRCS += bt_null.c endif diff --git a/drivers/wireless/bluetooth/bt_uart_bridge.c b/drivers/wireless/bluetooth/bt_uart_bridge.c new file mode 100644 index 00000000000..6b91e4eaef3 --- /dev/null +++ b/drivers/wireless/bluetooth/bt_uart_bridge.c @@ -0,0 +1,433 @@ +/**************************************************************************** + * drivers/wireless/bluetooth/bt_uart_bridge.c + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "bt_uart_filter.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define HCI_RECVBUF_SIZE 2048 +#define HCI_SENDBUF_SIZE 1024 +#define HCI_NPOLLWAITERS 2 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +union bt_hci_hdr_u +{ + struct bt_hci_cmd_hdr_s cmd; + struct bt_hci_acl_hdr_s acl; + struct bt_hci_iso_hdr_s iso; + struct bt_hci_evt_hdr_s evt; +}; + +struct bt_uart_bridge_device_s +{ + FAR struct bt_uart_bridge_s *bridge; + + struct bt_uart_filter_s filter; + + struct circbuf_s recvbuf; + sem_t recvlock; + uint8_t sendbuf[HCI_SENDBUF_SIZE]; + size_t sendlen; +}; + +struct bt_uart_bridge_s +{ + struct bt_uart_bridge_device_s device[BT_UART_FILTER_TYPE_COUNT]; + + sem_t recvlock; + sem_t sendlock; + + struct file filep; + uint8_t tmpbuf[HCI_RECVBUF_SIZE]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int bt_uart_bridge_open (FAR struct file *filep); +static int bt_uart_bridge_close (FAR struct file *filep); +static ssize_t bt_uart_bridge_read (FAR struct file *filep, + FAR char *buffer, size_t buflen); +static ssize_t bt_uart_bridge_write (FAR struct file *filep, + FAR const char *buffer, size_t buflen); +static int bt_uart_bridge_ioctl (FAR struct file *filep, + int cmd, unsigned long arg); +static int bt_uart_bridge_poll (FAR struct file *filep, + FAR struct pollfd *fds, bool setup); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_hcibridge_ops = +{ + .open = bt_uart_bridge_open, + .close = bt_uart_bridge_close, + .read = bt_uart_bridge_read, + .write = bt_uart_bridge_write, + .ioctl = bt_uart_bridge_ioctl, + .poll = bt_uart_bridge_poll +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static ssize_t +bt_uart_circbuf_read(FAR struct bt_uart_bridge_device_s *device, + FAR char *buffer, size_t buflen) +{ + int ret; + + ret = nxsem_wait_uninterruptible(&device->recvlock); + if (ret < 0) + { + return ret; + } + + ret = circbuf_read(&device->recvbuf, buffer, buflen); + + nxsem_post(&device->recvlock); + + return ret; +} + +static ssize_t +bt_uart_circbuf_write(FAR struct bt_uart_bridge_device_s *device, + FAR char *buffer, size_t buflen) +{ + int ret; + + ret = nxsem_wait_uninterruptible(&device->recvlock); + if (ret < 0) + { + return ret; + } + + if (circbuf_space(&device->recvbuf) >= buflen) + { + ret = circbuf_write(&device->recvbuf, buffer, buflen); + } + + nxsem_post(&device->recvlock); + + return ret; +} + +static int bt_uart_bridge_open(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct bt_uart_bridge_device_s *device = inode->i_private; + + if (filep->f_inode->i_crefs == 0) + { + device->sendlen = 0; + circbuf_reset(&device->recvbuf); + } + + return OK; +} + +static int bt_uart_bridge_close(FAR struct file *filep) +{ + return OK; +} + +static ssize_t bt_uart_bridge_read(FAR struct file *filep, + FAR char *buffer, size_t buflen) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct bt_uart_bridge_device_s *device = inode->i_private; + FAR struct bt_uart_bridge_s *bridge = device->bridge; + FAR struct bt_uart_bridge_device_s *iterator; + int recvlen; + int ret; + int i; + + ret = bt_uart_circbuf_read(device, buffer, buflen); + if (ret != 0) + { + return ret; + } + + ret = nxsem_wait_uninterruptible(&bridge->recvlock); + if (ret < 0) + { + return ret; + } + + while (circbuf_is_empty(&device->recvbuf)) + { + recvlen = file_read(&bridge->filep, + bridge->tmpbuf, HCI_RECVBUF_SIZE); + if (recvlen < 0) + { + nxsem_post(&bridge->recvlock); + return recvlen; + } + + for (i = 0; i < BT_UART_FILTER_TYPE_COUNT; i++) + { + iterator = &bridge->device[i]; + if (bt_uart_filter_forward_recv(&iterator->filter, + bridge->tmpbuf, recvlen)) + { + bt_uart_circbuf_write(iterator, bridge->tmpbuf, recvlen); + } + } + } + + nxsem_post(&bridge->recvlock); + + return bt_uart_circbuf_read(device, buffer, buflen); +} + +static ssize_t bt_uart_bridge_write(FAR struct file *filep, + FAR const char *buffer, size_t buflen) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct bt_uart_bridge_device_s *device = inode->i_private; + FAR struct bt_uart_bridge_s *bridge = device->bridge; + FAR union bt_hci_hdr_u *hdr; + size_t pktlen; + size_t hdrlen; + int ret; + int i; + + ret = nxsem_wait_uninterruptible(&bridge->sendlock); + if (ret < 0) + { + return ret; + } + + if (device->sendlen + buflen > HCI_SENDBUF_SIZE) + { + ret = -EINVAL; + goto err; + } + + memcpy(device->sendbuf + device->sendlen, buffer, buflen); + device->sendlen += buflen; + + hdr = (FAR union bt_hci_hdr_u *)(device->sendbuf + 1); + + while (1) + { + switch (device->sendbuf[0]) + { + case H4_CMD: + hdrlen = sizeof(struct bt_hci_cmd_hdr_s); + pktlen = hdr->cmd.param_len; + break; + case H4_ACL: + hdrlen = sizeof(struct bt_hci_acl_hdr_s); + pktlen = hdr->acl.len; + break; + case H4_ISO: + hdrlen = sizeof(struct bt_hci_iso_hdr_s); + pktlen = hdr->iso.len; + break; + default: + ret = -EINVAL; + goto err; + } + + /* Reassembly is incomplete ? */ + + hdrlen += H4_HEADER_SIZE; + + if (device->sendlen < hdrlen) + { + goto out; + } + + pktlen += hdrlen; + if (device->sendlen < pktlen) + { + goto out; + } + + /* Got the full packet, check and send out */ + + if (bt_uart_filter_forward_send(&device->filter, + device->sendbuf, pktlen)) + { + ret = file_write(&bridge->filep, device->sendbuf, pktlen); + if (ret < 0) + { + goto err; + } + } + + device->sendlen -= pktlen; + if (device->sendlen == 0) + { + goto out; + } + + memmove(device->sendbuf, device->sendbuf + pktlen, device->sendlen); + } + +err: + device->sendlen = 0; +out: + nxsem_post(&bridge->sendlock); + return ret < 0 ? ret : buflen; +} + +static int bt_uart_bridge_ioctl(FAR struct file *filep, + int cmd, unsigned long arg) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct bt_uart_bridge_device_s *device = inode->i_private; + FAR struct bt_uart_bridge_s *bridge = device->bridge; + + return file_ioctl(&bridge->filep, cmd, arg); +} + +static int bt_uart_bridge_poll(FAR struct file *filep, + FAR struct pollfd *fds, bool setup) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct bt_uart_bridge_device_s *device = inode->i_private; + FAR struct bt_uart_bridge_s *bridge = device->bridge; + int ret; + + ret = file_poll(&bridge->filep, fds, setup); + if (setup && ret >= 0 && !circbuf_is_empty(&device->recvbuf)) + { + fds->revents |= POLLIN; + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int bt_uart_bridge_register(const char *hciname, + const char *btname, const char *blename) +{ + FAR struct bt_uart_bridge_device_s *device; + FAR struct bt_uart_bridge_s *bridge; + int i = 0; + int ret; + FAR const char *bridges[] = + { + btname, + blename + }; + + if (!hciname || (!btname && !blename)) + { + return -EINVAL; + } + + bridge = (FAR struct bt_uart_bridge_s *) + kmm_zalloc(sizeof(struct bt_uart_bridge_s)); + if (bridge == NULL) + { + return -ENOMEM; + } + + nxsem_init(&bridge->recvlock, 0, 1); + nxsem_init(&bridge->sendlock, 0, 1); + + ret = file_open(&bridge->filep, hciname, O_RDWR); + if (ret < 0) + { + goto err_file; + } + + for (i = 0; i < BT_UART_FILTER_TYPE_COUNT; i++) + { + if (!bridges[i]) + { + continue; + } + + device = &bridge->device[i]; + + device->bridge = bridge; + bt_uart_filter_init(&device->filter, i); + nxsem_init(&device->recvlock, 0, 1); + + ret = circbuf_init(&device->recvbuf, NULL, HCI_RECVBUF_SIZE); + if (ret < 0) + { + goto err_circbuf; + } + + ret = register_driver(bridges[i], &g_hcibridge_ops, 0666, device); + if (ret < 0) + { + goto err_device; + } + } + + return OK; + + for (; i >= 0; i--) + { + if (!bridges[i]) + { + continue; + } + + device = &bridge->device[i]; + unregister_driver(bridges[i]); +err_device: + circbuf_uninit(&device->recvbuf); +err_circbuf: + nxsem_destroy(&device->recvlock); + } + + file_close(&bridge->filep); + +err_file: + nxsem_destroy(&bridge->recvlock); + nxsem_destroy(&bridge->sendlock); + + kmm_free(bridge); + + return ret; +} diff --git a/drivers/wireless/bluetooth/bt_uart_filter.c b/drivers/wireless/bluetooth/bt_uart_filter.c new file mode 100644 index 00000000000..33c536d30ac --- /dev/null +++ b/drivers/wireless/bluetooth/bt_uart_filter.c @@ -0,0 +1,265 @@ +/**************************************************************************** + * drivers/wireless/bluetooth/bt_uart_filter.c + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "bt_uart_filter.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const uint8_t g_bt_uart_filter_bt_evt_table[] = +{ + BT_HCI_EVT_INQUIRY_COMPLETE, + BT_HCI_EVT_CONN_COMPLETE, + BT_HCI_EVT_CONN_REQUEST, + BT_HCI_EVT_AUTH_COMPLETE, + BT_HCI_EVT_REMOTE_NAME_REQ_COMPLETE, + BT_HCI_EVT_REMOTE_FEATURES, + BT_HCI_EVT_ROLE_CHANGE, + BT_HCI_EVT_PIN_CODE_REQ, + BT_HCI_EVT_LINK_KEY_NOTIFY, + BT_HCI_EVT_LINK_KEY_REQ, + BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI, + BT_HCI_EVT_REMOTE_EXT_FEATURES, + BT_HCI_EVT_SYNC_CONN_COMPLETE, + BT_HCI_EVT_EXTENDED_INQUIRY_RESULT, + BT_HCI_EVT_IO_CAPA_RESP, + BT_HCI_EVT_IO_CAPA_REQ, + BT_HCI_EVT_SSP_COMPLETE, + BT_HCI_EVT_USER_CONFIRM_REQ, + BT_HCI_EVT_USER_PASSKEY_REQ, + BT_HCI_EVT_USER_PASSKEY_NOTIFY, + BT_HCI_EVT_PAGE_SCAN_REP_MODE_CHNG, + BT_HCI_EVT_CONN_PKT_TYPE_CHANGE, + BT_HCI_EVT_READ_CLOCK_OFF_COMP, + BT_HCI_EVT_MAX_SLOTS_CHANGED, + BT_HCI_EVT_MODE_CHANGE, + BT_HCI_EVT_QOS_SETUP_COMP, + BT_HCI_EVT_LINK_SUPER_TOUT_CHANGED, +}; + +static const uint8_t g_bt_uart_filter_ble_evt_table[] = +{ + BT_HCI_EVT_LE_META_EVENT, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static bool bt_uart_filter_set_handle(FAR struct bt_uart_filter_s *filter, + int old, int new) +{ + int i; + + for (i = 0; i < BT_UART_FILTER_CONN_COUNT; i++) + { + if (filter->handle[i] == old) + { + filter->handle[i] = new & 0xfff; + return true; + } + } + + return false; +} + +static bool bt_uart_filter_alloc_handle(FAR struct bt_uart_filter_s *filter, + int handle) +{ + return bt_uart_filter_set_handle(filter, 0, handle); +} + +static bool bt_uart_filter_free_handle(FAR struct bt_uart_filter_s *filter, + int handle) +{ + return bt_uart_filter_set_handle(filter, handle, 0); +} + +static bool bt_uart_filter_has_handle(FAR struct bt_uart_filter_s *filter, + int handle) +{ + return bt_uart_filter_set_handle(filter, handle, handle); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +bool bt_uart_filter_forward_recv(FAR struct bt_uart_filter_s *filter, + FAR char *buffer, size_t buflen) +{ + FAR const uint8_t *evt_table; + int size; + int i; + + if (buffer[0] == H4_EVT) + { + if (filter->type == BT_UART_FILTER_TYPE_BLE) + { + evt_table = g_bt_uart_filter_bt_evt_table; + size = sizeof(g_bt_uart_filter_bt_evt_table); + } + else + { + evt_table = g_bt_uart_filter_ble_evt_table; + size = sizeof(g_bt_uart_filter_ble_evt_table); + } + + for (i = 0; i < size; i++) + { + if (buffer[1] == evt_table[i]) + { + return false; + } + } + + switch (buffer[1]) + { + case BT_HCI_EVT_LE_META_EVENT: + if (buffer[3] == BT_HCI_EVT_LE_CONN_COMPLETE) + { + FAR struct bt_hci_evt_le_conn_complete_s *evt; + + evt = (FAR void *)&buffer[4]; + if (evt->status == 0) + { + return bt_uart_filter_alloc_handle(filter, evt->handle); + } + } + else if (buffer[3] == BT_HCI_EVT_LE_ENH_CONN_COMPLETE) + { + FAR struct bt_hci_evt_le_enh_conn_complete_s *evt; + + evt = (FAR void *)&buffer[4]; + if (evt->status == 0) + { + return bt_uart_filter_alloc_handle(filter, evt->handle); + } + } + break; + case BT_HCI_EVT_CONN_COMPLETE: + { + FAR struct bt_hci_evt_conn_complete_s *evt; + + evt = (FAR void *)&buffer[3]; + if (evt->status == 0) + { + return bt_uart_filter_alloc_handle(filter, evt->handle); + } + } + break; + case BT_HCI_EVT_NUM_COMPLETED_PACKETS: + { + FAR struct bt_hci_evt_num_completed_packets_s *evt; + + evt = (FAR void *)&buffer[3]; + return bt_uart_filter_has_handle(filter, evt->h[0].handle); + } + break; + case BT_HCI_EVT_REMOTE_VERSION_INFO: + { + FAR struct bt_hci_evt_remote_version_info_s *evt; + + evt = (FAR void *)&buffer[3]; + return bt_uart_filter_has_handle(filter, evt->handle); + } + break; + case BT_HCI_EVT_ENCRYPT_CHANGE: + { + FAR struct bt_hci_evt_encrypt_change_s *evt; + + evt = (FAR void *)&buffer[3]; + return bt_uart_filter_has_handle(filter, evt->handle); + } + break; + case BT_HCI_EVT_ENCRYPT_KEY_REFRESH_COMPLETE: + { + FAR struct bt_hci_evt_encrypt_key_refresh_complete_s *evt; + + evt = (FAR void *)&buffer[3]; + return bt_uart_filter_has_handle(filter, evt->handle); + } + break; + case BT_HCI_EVT_DISCONN_COMPLETE: + { + FAR struct bt_hci_evt_disconn_complete_s *evt; + + evt = (FAR void *)&buffer[3]; + return bt_uart_filter_free_handle(filter, evt->handle); + } + break; + default: + break; + } + } + else if (buffer[0] == H4_ACL) + { + FAR struct bt_hci_acl_hdr_s *acl = (FAR void *)&buffer[1]; + + return bt_uart_filter_has_handle(filter, acl->handle); + } + + return true; +} + +bool bt_uart_filter_forward_send(FAR struct bt_uart_filter_s *filter, + FAR char *buffer, size_t buflen) +{ + uint16_t opcode; + + if (buffer[0] == H4_CMD) + { + opcode = buffer[2] << 8 | buffer[1]; + + switch (opcode) + { + case BT_HCI_OP_SET_EVENT_MASK: + { + /* Override the all event bits roughly to avoid the + * bt/ble host specific mask deliver to controller. + */ + + memset(&buffer[4], 0xff, 7); + buffer[11] = 0x3f; + } + break; + + default: + break; + } + } + + return true; +} + +void bt_uart_filter_init(FAR struct bt_uart_filter_s *filter, int type) +{ + memset(filter->handle, 0, sizeof(filter->handle)); + filter->type = type; +} diff --git a/drivers/wireless/bluetooth/bt_uart_filter.h b/drivers/wireless/bluetooth/bt_uart_filter.h new file mode 100644 index 00000000000..e6e9ceba72a --- /dev/null +++ b/drivers/wireless/bluetooth/bt_uart_filter.h @@ -0,0 +1,60 @@ +/**************************************************************************** + * drivers/wireless/bluetooth/bt_uart_filter.h + * + * 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 __DRIVER_WIRELESS_BLUETOOTH_BT_UART_FILTER_H +#define __DRIVER_WIRELESS_BLUETOOTH_BT_UART_FILTER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BT_UART_FILTER_CONN_COUNT 4 + +#define BT_UART_FILTER_TYPE_BT 0 +#define BT_UART_FILTER_TYPE_BLE 1 +#define BT_UART_FILTER_TYPE_COUNT 2 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct bt_uart_filter_s +{ + int type; + uint16_t handle[BT_UART_FILTER_CONN_COUNT]; +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +void bt_uart_filter_init(FAR struct bt_uart_filter_s *filter, int type); +bool bt_uart_filter_forward_send(FAR struct bt_uart_filter_s *filter, + FAR char *buffer, size_t buflen); +bool bt_uart_filter_forward_recv(FAR struct bt_uart_filter_s *filter, + FAR char *buffer, size_t buflen); + +#endif /* __DRIVER_WIRELESS_BLUETOOTH_BT_UART_FILTER_H */ diff --git a/include/nuttx/wireless/bluetooth/bt_uart_bridge.h b/include/nuttx/wireless/bluetooth/bt_uart_bridge.h new file mode 100644 index 00000000000..b7c0c27a25a --- /dev/null +++ b/include/nuttx/wireless/bluetooth/bt_uart_bridge.h @@ -0,0 +1,39 @@ +/**************************************************************************** + * include/nuttx/wireless/bluetooth/bt_uart_bridge.h + * + * 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 __INCLUDE_NUTTX_WIRELESS_BLUETOOTH_BT_UART_BRIDGE_H +#define __INCLUDE_NUTTX_WIRELESS_BLUETOOTH_BT_UART_BRIDGE_H + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: bt_uart_bridge_register + * + * Description: + * Register the Bluetooth BT/BLE dual mode UART bridge driver + * + ****************************************************************************/ + +int bt_uart_bridge_register(FAR const char *hciname, + FAR const char *btname, FAR const char *blename); + +#endif /* __INCLUDE_NUTTX_WIRELESS_BLUETOOTH_BT_UART_BRIDGE_H */