diff --git a/class/wireless/usbh_bluetooth.c b/class/wireless/usbh_bluetooth.c index 638dfd4a..47a4cbac 100644 --- a/class/wireless/usbh_bluetooth.c +++ b/class/wireless/usbh_bluetooth.c @@ -126,14 +126,11 @@ static int usbh_bluetooth_disconnect(struct usbh_hubport *hport, uint8_t intf) return ret; } -int usbh_bluetooth_hci_cmd(struct usbh_bluetooth *bluetooth_class, uint8_t *buffer, uint32_t buflen) +int usbh_bluetooth_hci_cmd(uint8_t *buffer, uint32_t buflen) { + struct usbh_bluetooth *bluetooth_class = &g_bluetooth_class; struct usb_setup_packet *setup = bluetooth_class->hport->setup; - uint16_t opcode = (((uint16_t)buffer[1] << 8) | (uint16_t)buffer[0]); - - USB_LOG_DBG("opcode:%04x, param len:%d\r\n", opcode, buffer[2]); - setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE; setup->bRequest = 0x00; setup->wValue = 0; @@ -144,10 +141,11 @@ int usbh_bluetooth_hci_cmd(struct usbh_bluetooth *bluetooth_class, uint8_t *buff return usbh_control_transfer(bluetooth_class->hport, setup, g_bluetooth_cmd_buf); } -int usbh_bluetooth_hci_acl_out(struct usbh_bluetooth *bluetooth_class, uint8_t *buffer, uint32_t buflen) +int usbh_bluetooth_hci_acl_out(uint8_t *buffer, uint32_t buflen) { - int ret; + struct usbh_bluetooth *bluetooth_class = &g_bluetooth_class; struct usbh_urb *urb = &bluetooth_class->bulkout_urb; + int ret; usbh_bulk_urb_fill(urb, bluetooth_class->hport, bluetooth_class->bulkout, buffer, buflen, USB_OSAL_WAITING_FOREVER, NULL, NULL); ret = usbh_submit_urb(urb); @@ -163,12 +161,14 @@ void usbh_bluetooth_hci_event_rx_thread(void *argument) uint32_t ep_mps; uint32_t interval; uint8_t retry = 0; + uint16_t actual_len = 0; ep_mps = USB_GET_MAXPACKETSIZE(g_bluetooth_class.intin->wMaxPacketSize); interval = g_bluetooth_class.intin->bInterval; + USB_LOG_INFO("Create hc event rx thread\r\n"); while (1) { - usbh_int_urb_fill(&g_bluetooth_class.intin_urb, g_bluetooth_class.hport, g_bluetooth_class.intin, g_bluetooth_event_buf, ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL); + usbh_int_urb_fill(&g_bluetooth_class.intin_urb, g_bluetooth_class.hport, g_bluetooth_class.intin, &g_bluetooth_event_buf[actual_len], ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL); ret = usbh_submit_urb(&g_bluetooth_class.intin_urb); if (ret < 0) { if (ret == -USB_ERR_SHUTDOWN) { @@ -186,13 +186,20 @@ void usbh_bluetooth_hci_event_rx_thread(void *argument) continue; } } - usbh_bluetooth_hci_rx_callback(USB_BLUETOOTH_HCI_EVT, g_bluetooth_event_buf, g_bluetooth_class.intin_urb.actual_length); + actual_len += g_bluetooth_class.intin_urb.actual_length; + if (g_bluetooth_class.intin_urb.actual_length != ep_mps) { + usbh_bluetooth_hci_rx_callback(USB_BLUETOOTH_HCI_EVT, g_bluetooth_event_buf, actual_len); + actual_len = 0; + } else { + /* read continue util read short packet */ + } usb_osal_msleep(interval); } // clang-format off -delete : USB_LOG_INFO("Delete hc event rx thread\r\n"); +delete : + USB_LOG_INFO("Delete hc event rx thread\r\n"); usb_osal_thread_delete(NULL); - // clang-format om + // clang-format on } void usbh_bluetooth_hci_acl_rx_thread(void *argument) @@ -200,11 +207,13 @@ void usbh_bluetooth_hci_acl_rx_thread(void *argument) int ret; uint32_t ep_mps; uint8_t retry = 0; + uint16_t actual_len = 0; ep_mps = USB_GET_MAXPACKETSIZE(g_bluetooth_class.bulkin->wMaxPacketSize); + USB_LOG_INFO("Create hc acl rx thread\r\n"); while (1) { - usbh_bulk_urb_fill(&g_bluetooth_class.bulkin_urb, g_bluetooth_class.hport, g_bluetooth_class.bulkin, g_bluetooth_acl_buf, ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL); + usbh_bulk_urb_fill(&g_bluetooth_class.bulkin_urb, g_bluetooth_class.hport, g_bluetooth_class.bulkin, &g_bluetooth_acl_buf[actual_len], ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL); ret = usbh_submit_urb(&g_bluetooth_class.bulkin_urb); if (ret < 0) { if (ret == -USB_ERR_SHUTDOWN) { @@ -218,12 +227,19 @@ void usbh_bluetooth_hci_acl_rx_thread(void *argument) continue; } } - usbh_bluetooth_hci_rx_callback(USB_BLUETOOTH_HCI_ACL, g_bluetooth_acl_buf, g_bluetooth_class.bulkin_urb.actual_length); + actual_len += g_bluetooth_class.bulkin_urb.actual_length; + if (g_bluetooth_class.bulkin_urb.actual_length != ep_mps) { + actual_len = 0; + usbh_bluetooth_hci_rx_callback(USB_BLUETOOTH_HCI_ACL_IN, g_bluetooth_acl_buf, actual_len); + } else { + /* read continue util read short packet */ + } } // clang-format off -delete : USB_LOG_INFO("Delete hc acl rx thread\r\n"); +delete : + USB_LOG_INFO("Delete hc acl rx thread\r\n"); usb_osal_thread_delete(NULL); - // clang-format om + // clang-format on } __WEAK void usbh_bluetooth_hci_rx_callback(uint8_t hci_type, uint8_t *data, uint32_t len) diff --git a/class/wireless/usbh_bluetooth.h b/class/wireless/usbh_bluetooth.h index 03613d9d..11e8e15e 100644 --- a/class/wireless/usbh_bluetooth.h +++ b/class/wireless/usbh_bluetooth.h @@ -6,10 +6,12 @@ #ifndef USBH_BLUETOOTH_H #define USBH_BLUETOOTH_H -#define USB_BLUETOOTH_HCI_CMD 1 -#define USB_BLUETOOTH_HCI_EVT 2 -#define USB_BLUETOOTH_HCI_ACL 4 -#define USB_BLUETOOTH_HCI_ISO 5 +#define USB_BLUETOOTH_HCI_CMD 0 +#define USB_BLUETOOTH_HCI_EVT 1 +#define USB_BLUETOOTH_HCI_ACL_OUT 2 +#define USB_BLUETOOTH_HCI_ACL_IN 3 +#define USB_BLUETOOTH_HCI_ISO_OUT 4 +#define USB_BLUETOOTH_HCI_ISO_IN 5 struct usbh_bluetooth { struct usbh_hubport *hport; @@ -35,9 +37,9 @@ void usbh_bluetooth_run(struct usbh_bluetooth *bluetooth_class); void usbh_bluetooth_stop(struct usbh_bluetooth *bluetooth_class); /* OpCode(OCF+OGF:2bytes) + ParamLength + Paramas */ -int usbh_bluetooth_hci_cmd(struct usbh_bluetooth *bluetooth_class, uint8_t *buffer, uint32_t buflen); +int usbh_bluetooth_hci_cmd(uint8_t *buffer, uint32_t buflen); /* Handle (12bits) + Packet_Boundary_Flag(2bits) + BC_flag(2bits) + data_len(2bytes) + data */ -int usbh_bluetooth_hci_acl_out(struct usbh_bluetooth *bluetooth_class, uint8_t *buffer, uint32_t buflen); +int usbh_bluetooth_hci_acl_out(uint8_t *buffer, uint32_t buflen); void usbh_bluetooth_hci_event_rx_thread(void *argument); void usbh_bluetooth_hci_acl_rx_thread(void *argument); diff --git a/third_party/nimble-latest/ble_hci_usbh.c b/third_party/nimble-latest/ble_hci_usbh.c index 5a70f1bc..f8c3e0cd 100644 --- a/third_party/nimble-latest/ble_hci_usbh.c +++ b/third_party/nimble-latest/ble_hci_usbh.c @@ -4,6 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "usbh_core.h" +#include "usbh_bluetooth.h" + #include #include #include "os/os_mbuf.h" @@ -11,13 +14,8 @@ #include "nimble/transport.h" #include "nimble/transport/hci_h4.h" -#include -#include - struct hci_h4_sm g_hci_h4sm; -struct usbh_bluetooth *active_bluetooth_class; - static void hci_dump(uint8_t hci_type, uint8_t *data, uint32_t len) { uint32_t i = 0; @@ -59,20 +57,31 @@ void usbh_bluetooth_hci_rx_callback(uint8_t hci_type, uint8_t *data, uint32_t le { uint8_t pkt_type = 0; - if (hci_type == USB_BLUETOOTH_HCI_EVT) { - pkt_type = HCI_H4_EVT; - } else { - pkt_type = HCI_H4_ACL; + switch (hci_type) { + case USB_BLUETOOTH_HCI_EVT: + pkt_type = HCI_H4_EVT; + break; + + case USB_BLUETOOTH_HCI_ACL_IN: + pkt_type = HCI_H4_ACL; + break; + + // case USB_BLUETOOTH_HCI_ISO_IN: + // break; + + default: + USB_LOG_ERR("Unknown HCI type %u\r\n", hci_type); + return; } hci_dump(pkt_type, data, len); + hci_h4_sm_rx(&g_hci_h4sm, &pkt_type, 1); hci_h4_sm_rx(&g_hci_h4sm, data, len); } void usbh_bluetooth_run(struct usbh_bluetooth *bluetooth_class) { - active_bluetooth_class = bluetooth_class; ble_usb_transport_init(); usb_osal_thread_create("ble_event", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_bluetooth_hci_event_rx_thread, NULL); @@ -91,7 +100,7 @@ int ble_transport_to_ll_cmd_impl(void *buf) hci_dump(HCI_H4_CMD, buf, pkt_len); - ret = usbh_bluetooth_hci_cmd(active_bluetooth_class, buf, pkt_len); + ret = usbh_bluetooth_hci_cmd(buf, pkt_len); if (ret < 0) { ret = BLE_ERR_MEM_CAPACITY; } else { @@ -110,7 +119,7 @@ int ble_transport_to_ll_acl_impl(struct os_mbuf *om) while (x != NULL) { hci_dump(HCI_H4_ACL, x->om_data, x->om_len); - ret = usbh_bluetooth_hci_acl_out(active_bluetooth_class, x->om_data, x->om_len); + ret = usbh_bluetooth_hci_acl_out(x->om_data, x->om_len); if (ret < 0) { ret = BLE_ERR_MEM_CAPACITY; break; diff --git a/third_party/zephyr_bluetooth-3.x.x/ble_hci_usbh.c b/third_party/zephyr_bluetooth-3.x.x/ble_hci_usbh.c new file mode 100644 index 00000000..fa8864dc --- /dev/null +++ b/third_party/zephyr_bluetooth-3.x.x/ble_hci_usbh.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2024, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "usbh_core.h" +#include "usbh_bluetooth.h" + +#include "byteorder.h" +#include "hci_host.h" +#include "hci_driver.h" + +static void hci_dump(uint8_t hci_type, uint8_t *data, uint32_t len) +{ + uint32_t i = 0; + + USB_LOG_DBG("hci type:%u\r\n", hci_type); + + for (i = 0; i < len; i++) { + if (i % 16 == 0) { + USB_LOG_DBG("\r\n"); + } + + USB_LOG_DBG("%02x ", data[i]); + } + + USB_LOG_DBG("\r\n"); +} + +static bool is_hci_event_discardable(const uint8_t *evt_data) +{ + uint8_t evt_type = evt_data[0]; + + switch (evt_type) { +#if defined(CONFIG_BT_BREDR) + case BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI: + case BT_HCI_EVT_EXTENDED_INQUIRY_RESULT: + return true; +#endif + case BT_HCI_EVT_LE_META_EVENT: { + uint8_t subevt_type = evt_data[sizeof(struct bt_hci_evt_hdr)]; + + switch (subevt_type) { + case BT_HCI_EVT_LE_ADVERTISING_REPORT: + return true; + default: + return false; + } + } + default: + return false; + } +} + +static struct net_buf *usbh_bt_evt_recv(uint8_t *data, size_t remaining) +{ + bool discardable = false; + struct bt_hci_evt_hdr hdr; + struct net_buf *buf; + size_t buf_tailroom; + + if (remaining < sizeof(hdr)) { + USB_LOG_ERR("Not enough data for event header\r\n"); + return NULL; + } + + discardable = is_hci_event_discardable(data); + + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + remaining -= sizeof(hdr); + + if (remaining != hdr.len) { + USB_LOG_ERR("Event payload length is not correct\r\n"); + return NULL; + } + + buf = bt_buf_get_evt(hdr.evt, discardable, K_NO_WAIT); + if (!buf) { + if (discardable) { + USB_LOG_DBG("Discardable buffer pool full, ignoring event\r\n"); + } else { + USB_LOG_ERR("No available event buffers!\r\n"); + } + return buf; + } + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < remaining) { + USB_LOG_ERR("Not enough space in buffer %zu/%zu\r\n", remaining, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + net_buf_add_mem(buf, data, remaining); + + return buf; +} + +static struct net_buf *usbh_bt_acl_recv(uint8_t *data, size_t remaining) +{ + struct bt_hci_acl_hdr hdr; + struct net_buf *buf; + size_t buf_tailroom; + + if (remaining < sizeof(hdr)) { + USB_LOG_ERR("Not enough data for ACL header\r\n"); + return NULL; + } + + buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT); + if (buf) { + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + remaining -= sizeof(hdr); + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + } else { + USB_LOG_ERR("No available ACL buffers!\r\n"); + return NULL; + } + + if (remaining != sys_le16_to_cpu(hdr.len)) { + USB_LOG_ERR("ACL payload length is not correct\r\n"); + net_buf_unref(buf); + return NULL; + } + + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < remaining) { + USB_LOG_ERR("Not enough space in buffer %zu/%zu\r\n", remaining, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + USB_LOG_DBG("len %u", remaining); + net_buf_add_mem(buf, data, remaining); + + return buf; +} + +static struct net_buf *usbh_bt_iso_recv(uint8_t *data, size_t remaining) +{ + struct bt_hci_iso_hdr hdr; + struct net_buf *buf; + size_t buf_tailroom; + + if (remaining < sizeof(hdr)) { + USB_LOG_ERR("Not enough data for ISO header\r\n"); + return NULL; + } + + buf = bt_buf_get_rx(BT_BUF_ISO_IN, K_NO_WAIT); + if (buf) { + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + remaining -= sizeof(hdr); + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + } else { + USB_LOG_ERR("No available ISO buffers!\r\n"); + return NULL; + } + + // if (remaining != bt_iso_hdr_len(sys_le16_to_cpu(hdr.len))) { + // USB_LOG_ERR("ISO payload length is not correct\r\n"); + // net_buf_unref(buf); + // return NULL; + // } + + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < remaining) { + USB_LOG_ERR("Not enough space in buffer %zu/%zu\r\n", remaining, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + USB_LOG_DBG("len %zu", remaining); + net_buf_add_mem(buf, data, remaining); + + return buf; +} + +static int usbh_hci_host_rcv_pkt(uint8_t pkt_indicator, uint8_t *data, uint16_t len) +{ + struct net_buf *buf = NULL; + size_t remaining = len; + bool prio = true; + + switch (pkt_indicator) { + case USB_BLUETOOTH_HCI_EVT: + buf = usbh_bt_evt_recv(data, remaining); + break; + + case USB_BLUETOOTH_HCI_ACL_IN: + buf = usbh_bt_acl_recv(data, remaining); + prio = false; + break; + + case USB_BLUETOOTH_HCI_ISO_IN: + buf = usbh_bt_iso_recv(data, remaining); + break; + + default: + USB_LOG_ERR("Unknown HCI type %u\r\n", pkt_indicator); + return -1; + } + + hci_dump(pkt_indicator, buf->data, buf->len); + + if (buf) { + bt_recv(buf); + } + + return 0; +} + +static int bt_usbh_open(void) +{ + return 0; +} + +static int bt_usbh_send(struct net_buf *buf) +{ + int err = 0; + uint8_t pkt_indicator = bt_buf_get_type(buf); + + hci_dump(pkt_indicator, buf->data, buf->len); + + switch (pkt_indicator) { + case BT_BUF_ACL_OUT: + usbh_bluetooth_hci_acl_out(buf->data, buf->len); + break; + case BT_BUF_CMD: + usbh_bluetooth_hci_cmd(buf->data, buf->len); + break; + case BT_BUF_ISO_OUT: + break; + default: + USB_LOG_ERR("Unknown type %u\r\n", pkt_indicator); + goto done; + } +done: + net_buf_unref(buf); + + return err; +} + +static const struct bt_hci_driver usbh_drv = { + .name = "usbhost btble", + .open = bt_usbh_open, + .send = bt_usbh_send, + .bus = BT_HCI_DRIVER_BUS_USB, +#if defined(CONFIG_BT_DRIVER_QUIRK_NO_AUTO_DLE) + .quirks = BT_QUIRK_NO_AUTO_DLE, +#endif +}; + +__WEAK void usbh_bluetooth_run_callback(void) +{ + /* bt_enable() */ +} + +__WEAK void usbh_bluetooth_stop_callback(void) +{ + /* bt_disable() */ +} + +void usbh_bluetooth_run(struct usbh_bluetooth *bluetooth_class) +{ + bt_hci_driver_register(&usbh_drv); + + usb_osal_thread_create("ble_event", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_bluetooth_hci_event_rx_thread, NULL); + usb_osal_thread_create("ble_acl", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_bluetooth_hci_acl_rx_thread, NULL); + + usbh_bluetooth_run_callback(); +} + +void usbh_bluetooth_stop(struct usbh_bluetooth *bluetooth_class) +{ + usbh_bluetooth_stop_callback(); +} + +void usbh_bluetooth_hci_rx_callback(uint8_t hci_type, uint8_t *data, uint32_t len) +{ + usbh_hci_host_rcv_pkt(hci_type, data, len); +} \ No newline at end of file