-
-
Notifications
You must be signed in to change notification settings - Fork 82
virtualhub: Implement BTStack bluetooth. #435
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
jaguilar
wants to merge
3
commits into
pybricks:master
Choose a base branch
from
jaguilar:virtualhub-bluetooth
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,24 +30,51 @@ | |
| #include "pybricks_service_server.h" | ||
| #endif // PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE | ||
|
|
||
| #if PBDRV_CONFIG_BLUETOOTH_BTSTACK_POSIX | ||
|
|
||
| #include <errno.h> | ||
| #include <poll.h> | ||
|
|
||
| #endif | ||
|
|
||
| #ifdef PBDRV_CONFIG_BLUETOOTH_BTSTACK_HUB_KIND | ||
| #define HUB_KIND PBDRV_CONFIG_BLUETOOTH_BTSTACK_HUB_KIND | ||
| #else | ||
| #error "PBDRV_CONFIG_BLUETOOTH_BTSTACK_HUB_KIND is required" | ||
| #endif | ||
|
|
||
| #ifndef PBDRV_CONFIG_BLUETOOTH_BTSTACK_POSIX | ||
| #define PBDRV_CONFIG_BLUETOOTH_BTSTACK_POSIX 0 | ||
| #endif | ||
|
|
||
| // location of product variant in bootloader flash memory of Technic Large hubs | ||
| #if PBDRV_CONFIG_BLUETOOTH_BTSTACK_HUB_VARIANT_ADDR | ||
| #define HUB_VARIANT (*(const uint16_t *)PBDRV_CONFIG_BLUETOOTH_BTSTACK_HUB_VARIANT_ADDR) | ||
| #else | ||
| #define HUB_VARIANT 0x0000 | ||
| #endif | ||
|
|
||
| #define DEBUG 0 | ||
| #define DEBUG 1 | ||
|
|
||
| #if DEBUG | ||
| #include <pbdrv/../../drv/uart/uart_debug_first_port.h> | ||
| #define DEBUG_PRINT pbdrv_uart_debug_printf | ||
| #include <pbdrv/../../drv/uart/uart_debug_first_port.h> | ||
| #define DEBUG_PRINT pbdrv_uart_debug_printf | ||
| static void pbdrv_hci_dump_reset(void) { | ||
| } | ||
| static void pbdrv_hci_dump_log_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) { | ||
| pbdrv_uart_debug_printf("HCI %s packet type: %02x, len: %u\n", in ? "in" : "out", packet_type, len); | ||
| } | ||
| static void pbdrv_hci_dump_log_message(int log_level, const char *format, va_list argptr) { | ||
| pbdrv_uart_debug_vprintf(format, argptr); | ||
| pbdrv_uart_debug_printf("\n"); | ||
| } | ||
| static const hci_dump_t bluetooth_btstack_classic_hci_dump = { | ||
| .reset = pbdrv_hci_dump_reset, | ||
| .log_packet = pbdrv_hci_dump_log_packet, | ||
| .log_message = pbdrv_hci_dump_log_message, | ||
| }; | ||
| #else | ||
| #define DEBUG_PRINT(...) | ||
| #endif | ||
|
|
@@ -223,23 +250,39 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe | |
| pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton; | ||
| #endif // PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE | ||
|
|
||
| static pbdrv_bluetooth_btstack_device_discriminator device_info; | ||
|
|
||
| switch (hci_event_packet_get_type(packet)) { | ||
| case HCI_EVENT_TRANSPORT_USB_INFO: { | ||
| // Store USB vendor and product IDs for later use | ||
| device_info.usb_vendor_id = hci_event_transport_usb_info_get_vendor_id(packet); | ||
| device_info.usb_product_id = hci_event_transport_usb_info_get_product_id(packet); | ||
| break; | ||
| } | ||
| case HCI_EVENT_COMMAND_COMPLETE: { | ||
| const uint8_t *rp = hci_event_command_complete_get_return_parameters(packet); | ||
| switch (hci_event_command_complete_get_command_opcode(packet)) { | ||
| case HCI_OPCODE_HCI_READ_LOCAL_VERSION_INFORMATION: { | ||
| uint16_t lmp_pal_subversion = pbio_get_uint16_le(&rp[7]); | ||
| pbdrv_bluetooth_btstack_set_chipset(lmp_pal_subversion); | ||
| device_info.hci_version = rp[0]; | ||
| device_info.hci_revision = pbio_get_uint16_le(&rp[1]); | ||
| device_info.lmp_pal_version = rp[3]; | ||
| device_info.manufacturer = pbio_get_uint16_le(&rp[4]); | ||
| device_info.lmp_pal_subversion = pbio_get_uint16_le(&rp[6]); | ||
| pbdrv_bluetooth_btstack_set_chipset(&device_info); | ||
|
|
||
| #if DEBUG | ||
| // Show version in ev3dev format. | ||
| uint16_t lmp_pal_subversion = device_info.lmp_pal_subversion; | ||
| uint16_t chip = (lmp_pal_subversion & 0x7C00) >> 10; | ||
| uint16_t min_ver = (lmp_pal_subversion & 0x007F); | ||
| uint16_t maj_ver = (lmp_pal_subversion & 0x0380) >> 7; | ||
| if (lmp_pal_subversion & 0x8000) { | ||
| maj_ver |= 0x0008; | ||
| } | ||
| DEBUG_PRINT("LMP %04x: TIInit_%d.%d.%d.bts\n", lmp_pal_subversion, chip, maj_ver, min_ver); | ||
| (void)maj_ver; // In lib/pbio/test, this variable appears unused even though it's not. | ||
| (void)min_ver; | ||
| (void)chip; | ||
| #endif | ||
| break; | ||
| } | ||
|
|
@@ -999,6 +1042,13 @@ static void bluetooth_btstack_run_loop_execute(void) { | |
| // not used | ||
| } | ||
|
|
||
| static bool do_poll_handler; | ||
|
|
||
| void pbdrv_bluetooth_btstack_run_loop_trigger(void) { | ||
| do_poll_handler = true; | ||
| pbio_os_request_poll(); | ||
| } | ||
|
|
||
| static const btstack_run_loop_t bluetooth_btstack_run_loop = { | ||
| .init = btstack_run_loop_base_init, | ||
| .add_data_source = btstack_run_loop_base_add_data_source, | ||
|
|
@@ -1011,14 +1061,10 @@ static const btstack_run_loop_t bluetooth_btstack_run_loop = { | |
| .execute = bluetooth_btstack_run_loop_execute, | ||
| .dump_timer = btstack_run_loop_base_dump_timer, | ||
| .get_time_ms = pbdrv_clock_get_ms, | ||
| .poll_data_sources_from_irq = pbdrv_bluetooth_btstack_run_loop_trigger, | ||
| }; | ||
|
|
||
| static bool do_poll_handler; | ||
|
|
||
| void pbdrv_bluetooth_btstack_run_loop_trigger(void) { | ||
| do_poll_handler = true; | ||
| pbio_os_request_poll(); | ||
| } | ||
|
|
||
| static pbio_os_process_t pbdrv_bluetooth_hci_process; | ||
|
|
||
|
|
@@ -1028,9 +1074,57 @@ static pbio_os_process_t pbdrv_bluetooth_hci_process; | |
| */ | ||
| static pbio_error_t pbdrv_bluetooth_hci_process_thread(pbio_os_state_t *state, void *context) { | ||
|
|
||
| if (do_poll_handler) { | ||
| #if PBDRV_CONFIG_BLUETOOTH_BTSTACK_POSIX | ||
| int nfds = btstack_linked_list_count(&btstack_run_loop_base_data_sources); | ||
| struct pollfd fds[nfds]; | ||
| #endif | ||
|
|
||
| if (do_poll_handler || PBDRV_CONFIG_BLUETOOTH_BTSTACK_POSIX) { | ||
| do_poll_handler = false; | ||
| btstack_run_loop_base_poll_data_sources(); | ||
|
|
||
| #if PBDRV_CONFIG_BLUETOOTH_BTSTACK_POSIX | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we could have a |
||
| btstack_linked_list_iterator_t it; | ||
| int i; | ||
| for (i = 0, btstack_linked_list_iterator_init(&it, &btstack_run_loop_base_data_sources); | ||
| btstack_linked_list_iterator_has_next(&it); ++i) { | ||
| // cache pointer to next data_source to allow data source to remove itself | ||
| btstack_data_source_t *ds = (void *)btstack_linked_list_iterator_next(&it); | ||
|
|
||
| // In POSIX mode we must additionally identify data source FDs that | ||
| // are ready for reading or writing. | ||
| struct pollfd *pfd = &fds[i]; | ||
| pfd->fd = ds->source.fd; | ||
| pfd->events = 0; | ||
| if (ds->flags & DATA_SOURCE_CALLBACK_READ) { | ||
| pfd->events |= POLLIN; | ||
| } | ||
| if (ds->flags & DATA_SOURCE_CALLBACK_WRITE) { | ||
| pfd->events |= POLLOUT; | ||
| } | ||
|
|
||
| } | ||
|
|
||
| int err = poll(fds, nfds, 0); | ||
| if (err < 0) { | ||
| DEBUG_PRINT("btstack: poll() returned %d, ignoring\n", errno); | ||
| } else if (err > 0) { | ||
| // Some fd was ready. | ||
| for (i = 0, btstack_linked_list_iterator_init(&it, &btstack_run_loop_base_data_sources); | ||
| btstack_linked_list_iterator_has_next(&it); ++i) { | ||
| btstack_data_source_t *ds = (void *)btstack_linked_list_iterator_next(&it); | ||
| struct pollfd *pfd = &fds[i]; | ||
| if (pfd->revents & POLLIN) { | ||
| ds->process(ds, DATA_SOURCE_CALLBACK_READ); | ||
| } else if (pfd->revents & POLLOUT) { | ||
| ds->process(ds, DATA_SOURCE_CALLBACK_WRITE); | ||
| } else if (pfd->revents & POLLERR) { | ||
| DEBUG_PRINT("btstack: poll() error on fd %d\n", pfd->fd); | ||
| } | ||
| } | ||
|
|
||
| } | ||
| #endif | ||
| } | ||
|
|
||
| static pbio_os_timer_t btstack_timer = { | ||
|
|
@@ -1065,9 +1159,21 @@ void pbdrv_bluetooth_init_hci(void) { | |
| btstack_run_loop_init(&bluetooth_btstack_run_loop); | ||
|
|
||
| hci_init(pdata->transport_instance(), pdata->transport_config()); | ||
| hci_set_chipset(pdata->chipset_instance()); | ||
|
|
||
| #if DEBUG | ||
| hci_dump_init(&bluetooth_btstack_classic_hci_dump); | ||
| hci_dump_enable_log_level(HCI_DUMP_LOG_LEVEL_INFO, true); | ||
| hci_dump_enable_log_level(HCI_DUMP_LOG_LEVEL_ERROR, true); | ||
| hci_dump_enable_log_level(HCI_DUMP_LOG_LEVEL_DEBUG, true); | ||
| hci_dump_enable_packet_log(true); | ||
| #endif | ||
|
|
||
| if (pdata->chipset_instance != NULL) { | ||
| hci_set_chipset(pdata->chipset_instance()); | ||
| } | ||
| hci_set_control(pdata->control_instance()); | ||
|
|
||
|
|
||
| // REVISIT: do we need to call btstack_chipset_cc256x_set_power() or btstack_chipset_cc256x_set_power_vector()? | ||
|
|
||
| hci_event_callback_registration.callback = &packet_handler; | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -23,13 +23,29 @@ typedef struct { | |||||
|
|
||||||
| void pbdrv_bluetooth_btstack_run_loop_trigger(void); | ||||||
|
|
||||||
| typedef struct { | ||||||
| // Only set on POSIX -- these data come from the USB device descriptor. | ||||||
| uint16_t usb_vendor_id; | ||||||
| uint16_t usb_product_id; | ||||||
|
|
||||||
| // Set on all platforms -- these data come from the | ||||||
| // HCI_OPCODE_HCI_READ_LOCAL_VERSION_INFORMATION response. | ||||||
| uint8_t hci_version; | ||||||
| uint16_t hci_revision; | ||||||
| uint8_t lmp_pal_version; | ||||||
| uint16_t manufacturer; | ||||||
| uint16_t lmp_pal_subversion; | ||||||
|
|
||||||
| } pbdrv_bluetooth_btstack_device_discriminator; | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| /** | ||||||
| * Hook called when BTstack reads the local version information. | ||||||
| * | ||||||
| * This is called _after_ hci_set_chipset but _before_ the init script is sent | ||||||
| * over the wire, so this can be used to dynamically select the init script. | ||||||
| */ | ||||||
| void pbdrv_bluetooth_btstack_set_chipset(uint16_t lmp_pal_subversion); | ||||||
| void pbdrv_bluetooth_btstack_set_chipset( | ||||||
| pbdrv_bluetooth_btstack_device_discriminator *device_info); | ||||||
|
|
||||||
| typedef struct { | ||||||
| const hci_transport_t *(*transport_instance)(void); | ||||||
|
|
||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.