diff --git a/README.md b/README.md index d72fbc481..d66a17084 100644 --- a/README.md +++ b/README.md @@ -35,12 +35,14 @@ GATT, SM of the Bluetooth 4.2 LE Central and Peripheral roles (QD ID 25340). ## Supported Protocols and Profiles -Protocols: L2CAP, RFCOMM, SDP, BNEP, ATT, SM +Protocols: L2CAP, RFCOMM, SDP, BNEP, ATT, SM (incl. LE Secure Connections). -Profiles: GAP, IOP, HFP, HSP, SPP, PAN, GATT +Profiles: GAP, IOP, HFP, HSP, SPP, PAN, GATT. Coming next: A2DP, AVRCP, HID, HOGP, BLE, and more. +For information on MFi/iAP2 support, please contact us. + ## Evaluation Platforms #### Embedded Platforms: diff --git a/chipset/README.md b/chipset/README.md index df7152b97..a23c4a323 100644 --- a/chipset/README.md +++ b/chipset/README.md @@ -31,9 +31,9 @@ Broadcom, whose Bluetooth + Wifi division has been acquired by the Cypress Semic CSR, which has been acquired by Qualcomm, provides all relevant information on their Support website after signing an NDA. -Chipset | Type | HCI Transport | BD_ADDR (1) | SCO over HCI (2) | LE DLE | Multiple LE Roles (3)| BTstack folder | Comment +Chipset | Type | HCI Transport | BD_ADDR (1) | SCO over HCI (2) | LE DLE | Multiple LE Roles | BTstack folder | Comment -------------------- |-----------| ---------------|--------------|------------------|--------|----------------------|----------------|--------- -Broadcom UART | Dual mode | H4, H5 | rarely | No (didn't work) | No | Maybe | bcm | Max UART baudrate 3 mbps +Broadcom UART | Dual mode | H4, H5 | rarely | No (didn't work) | No | Maybe (3) | bcm | Max UART baudrate 3 mbps Broadcom USB Dongles | Dual mode | USB | Yes | No (didn't work) | No | No | bcm | CSR UART | Dual mode | H4, H5 | rarely | No (didn't work) | No | No | csr | CSR USB Dongles | Dual mode | USB | Mostly | Yes | No | No | csr | @@ -43,13 +43,13 @@ EM 9304 | LE | SPI, H4 | ? | n.a. Nordic nRF | LE | H4 | fixed random | n.a. | Yes | Yes | | Requires custom HCI firmware STM STLC2500D | Classic | H4 | No | No (didn't try) | n.a | n.a. | stlc2500d | Custom deep sleep management not supported Toshiba TC35661 | Dual mode | H4 | No | No (didn't try) | No | No | tc3566 | HCI version not tested. See below -TI CC256x, WL183x | Dual mode | H4, H5, eHCILL | Yes | Yes | No | No | cc256x | Also WL185x, WL187x, and WL189x +TI CC256x, WL183x | Dual mode | H4, H5, eHCILL | Yes | Yes | No | Yes for CC256XC | cc256x | Also WL185x, WL187x, and WL189x **Notes**: 1. BD_ADDR: Not all Bluetooth chipset come with a fixed valid MAC Address. Better Broadcom and CSR dongles come with a MAC address from the dongle manufacturer, but cheaper ones might come with identical addresses. 2. SCO over HCI: All Bluetooth Classic chipsets support SCO over HCI, for those that are marked with No, we either didn't try or didn't found enough information to configure it correctly. - 2. Multiple LE Roles: Apple uses Broadcom Bluetooth+Wifi in their iOS devices and newer iOS versions support multipe concurrent LE roles, + 3. Multiple LE Roles: Apple uses Broadcom Bluetooth+Wifi in their iOS devices and newer iOS versions support multipe concurrent LE roles, so at least some Broadcom models support multiple concurrent LE roles. ## Broadcom @@ -178,39 +178,39 @@ STMicroelectronics offers the Bluetooth V2.1 + EDR chipset STLC2500D that suppor ## Texas Instruments CC256x series -The Texas Instruments CC256x series is currently in its third iteration and provides a Classic-only (CC2560), a Dual-mode (CC2564), and a Classic + ANT model (CC2567). A variant of the Dual-mode chipset is also integrated into TI's WiLink 8 Wifi+Bluetooth combo modules of the WL183x, WL185x, WL187x, and WL189x series. +The Texas Instruments CC256x series is currently in its fourth iteration and provides a Classic-only (CC2560), a Dual-mode (CC2564), and a Classic + ANT (CC2567) model. A variant of the Dual-mode chipset is also integrated into TI's WiLink 8 Wifi+Bluetooth combo modules of the WL183x, WL185x, WL187x, and WL189x series. The CC256x chipset is connected via an UART connection and supports the H4, H5 (since third iteration), and eHCILL. +The latest generation CC256xC chipsets support multiple LE roles in parallel. + +The different CC256x chipset can be identified by the LMP Subversion returned by the *hci_read_local_version_information* command. TI also uses a numeric way (AKA) to identify their chipsets. The table shows the LMP Subversion and AKA number for the main CC256x series. + +Chipset | LMP Subversion | AKA +--------|----------------|------- +CC2560 | 0x191f | 6.2.31 +CC2560A, CC2564 | 0x1B0F | 6.6.15 +CC256xB | 0x1B90 | 6.7.16 +CC256xC | 0x9a1a | 6.12.26 + **SCO data** is routed to the I2S/PCM interface but can be configured with the [HCI_VS_Write_SCO_Configuration](http://processors.wiki.ti.com/index.php/CC256x_VS_HCI_Commands#HCI_VS_Write_SCO_Configuration_.280xFE10.29) command. **Baud rate** can be set with [HCI_VS_Update_UART_HCI_Baudrate](http://processors.wiki.ti.com/index.php/CC256x_VS_HCI_Commands#HCI_VS_Update_UART_HCI_Baudrate_.280xFF36.29). The chipset confirms the change with a command complete event after which the local UART is set to the new speed. Oddly enough, the CC256x chipsets ignore the incoming CTS line during this particular command complete response. If the MCU gets UART overrun errors in this situation, a work around could be to set a timer for 100 ms and ignore all incoming data (i.e. the command complete event) during that period. Then, after the timeout, the UART can be set to the new speed safely. **BD Addr** can be set with [HCI_VS_Write_BD_Addr](2.2.1 HCI_VS_Write_BD_Addr (0xFC06)) although all chipsets have an official address stored. -**Init Scripts.** In order to use the CC256x chipset an initialization script must be obtained and converted into a C file for use with BTstack. +**Init Scripts.** In order to use the CC256x chipset an initialization script must be obtained and converted into a C file for use with BTstack. For newer revisions, TI provides a main.bts and a ble_add_on.bts that need to be combined. -The Makefile at *chipset/cc256x/Makefile* is able to automatically download and convert the requested file. It does this by: +The Makefile at *chipset/cc256x/Makefile.inc* is able to automatically download and convert the requested file. It does this by: - Downloading one or more [BTS files](http://processors.wiki.ti.com/index.php/CC256x_Downloads) for your chipset. - Running the Python script: - ./convert_bts_init_scripts.py + ./convert_bts_init_scripts.py main.bts [ble_add_on.bts] output_file.c -**Update:** For the latest revision of the CC256x chipsets, the CC2560B -and CC2564B, TI decided to split the init script into a main part and -the BLE part. The conversion script has been updated to detect -*bluetooth_init_cc256x_1.2.bts* and adds *BLE_init_cc256x_1.2.bts* -if present and merges them into a single .c file. - -**Update 2:** In May 2015, TI renamed the init scripts to match -the naming scheme previously used on Linux systems. The conversion -script has been updated to also detect *initscripts_TIInit_6.7.16_bt_spec_4.1.bts* -and integrates *initscripts_TIInit_6.7.16_ble_add-on.bts* if present. - -**BTstack integration**: The common code for all CC256x chipsets is provided by *btstack_chipset_cc256x.c*. During the setup, *btstack_chipset_cc256x_instance* function is used to get a *btstack_chiopset_t* instance and passed to *hci_init* function. +**BTstack integration**: The common code for all CC256x chipsets is provided by *btstack_chipset_cc256x.c*. During the setup, *btstack_chipset_cc256x_instance* function is used to get a *btstack_chipset_t* instance and passed to *hci_init* function. *btstack_chipset_cc256x_lmp_subversion* provides the LMP Subversion for the selected init script. SCO Data can be routed over HCI, so HFP Wide-Band Speech is supported. diff --git a/chipset/cc256x/Makefile.inc b/chipset/cc256x/Makefile.inc index 732804df8..55526f046 100644 --- a/chipset/cc256x/Makefile.inc +++ b/chipset/cc256x/Makefile.inc @@ -1,114 +1,190 @@ # -# Makefile to download and convert .bts files from +# Makefile to download and convert TI's CC256x Service Pack .bts files from # http://processors.wiki.ti.com/index.php/CC256x_Downloads # -BASE_URL = https://git.ti.com/ti-bt/service-packs/blobs/raw/a027ae390d8790e56e1c78136c78fe6537470e91 +# Service Packs for CC256xB v1.5 and CC256xC v1.0 downloaded from BlueKitchen company website +# https://e2e.ti.com/support/wireless_connectivity/bluetooth_cc256x/f/660/p/560523/2056007#2056007 + +TI_GIT_REPO_URL = https://git.ti.com/ti-bt/service-packs/blobs/raw/a027ae390d8790e56e1c78136c78fe6537470e91 +BLUEKITCHEN_URL = https://bluekitchen-gmbh.com/files/ CONVERSION_SCRIPT=$(BTSTACK_ROOT)/chipset/cc256x/convert_bts_init_scripts.py -# first generation CC2560 - TIInit_6.2.31.bts part of .zip archive + +# First generation CC2560 - AKA TIInit_6.2.31.bts + +# v2.44 - file part of .zip archive CC2560_BT_SP_BTS.zip: - curl -O http://processors.wiki.ti.com/images/d/da/CC2560_BT_SP_BTS.zip + @echo "Downloading $@" + @curl -sS -O http://processors.wiki.ti.com/images/d/da/CC2560_BT_SP_BTS.zip bluetooth_init_cc2560_2.44.bts: CC2560_BT_SP_BTS.zip - unzip CC2560_BT_SP_BTS.zip - mv CC2560_BT_SP_BTS/bluetooth_init_cc2560_2.44.bts . - rm -rf CC2560_BT_SP_BTS + @echo "Extracting $@" + @unzip -q -j -o CC2560_BT_SP_BTS.zip CC2560_BT_SP_BTS/bluetooth_init_cc2560_2.44.bts +# Second generation CC2560A and CC2564 - AKA TIInit_6.6.15.bts -# second generation CC2560A and CC2564 - TIInit_6.6.15.bts part of .zip archive +# v2.14 - files part of .zip archive CC2560A_BT_SP_BTS.zip: - curl -O http://processors.wiki.ti.com/images/e/e7/CC2560A_BT_SP_BTS.zip + @echo "Downloading $@" + @curl -sS -O http://processors.wiki.ti.com/images/e/e7/CC2560A_BT_SP_BTS.zip CC2564_BT_BLE_SP_BTS.zip: - curl -O http://processors.wiki.ti.com/images/1/1e/CC2564_BT_BLE_SP_BTS.zip + @echo "Downloading $@" + @curl -sS -O http://processors.wiki.ti.com/images/1/1e/CC2564_BT_BLE_SP_BTS.zip bluetooth_init_cc2560A_2.14.bts: CC2560A_BT_SP_BTS.zip - unzip CC2560A_BT_SP_BTS.zip - mv CC2560A_BT_SP_BTS/bluetooth_init_cc2560a_2.14.bts . - rm -rf CC2560A_BT_SP_BTS + @echo "Extracting $@" + @unzip -q -j -o CC2560A_BT_SP_BTS.zip CC2560A_BT_SP_BTS/bluetooth_init_cc2560A_2.14.bts bluetooth_init_cc2564_2.14.bts: CC2564_BT_BLE_SP_BTS.zip - unzip CC2564_BT_BLE_SP_BTS.zip - mv CC2564_BT_BLE_SP_BTS/bluetooth_init_cc2564_2.14.bts . - rm -rf CC2564_BT_BLE_SP_BTS + @echo "Extracting $@" + @unzip -q -j -o CC2564_BT_BLE_SP_BTS.zip CC2564_BT_BLE_SP_BTS/bluetooth_init_cc2564_2.14.bts +# Third generation CC256xB - AKA TIInit_6.6.16.bts -# third generation - -# versioned files for v1.2 +# v1.2 - versioned files TI Git Repo bluetooth_init_cc2560B_1.2_BT_Spec_4.1.bts: - curl -O $(BASE_URL)/bluetooth_init_cc2560B_1.2_BT_Spec_4.1.bts + @echo "Downloading $@" + @curl -sS -O $(TI_GIT_REPO_URL)/bluetooth_init_cc2560B_1.2_BT_Spec_4.1.bts bluetooth_init_cc2564B_1.2_BT_Spec_4.1.bts: - curl -O $(BASE_URL)/bluetooth_init_cc2564B_1.2_BT_Spec_4.1.bts + @echo "Downloading $@" + @curl -sS -O $(TI_GIT_REPO_URL)/bluetooth_init_cc2564B_1.2_BT_Spec_4.1.bts BLE_init_cc2564B_1.2.bts: - curl -O $(BASE_URL)/BLE_init_cc2564B_1.2.bts + @echo "Downloading $@" + @curl -sS -O $(TI_GIT_REPO_URL)/BLE_init_cc2564B_1.2.bts -# unversioned files for v1.4 +# v1.4 - versioned files TI Git Repo TIInit_6.7.16_bt_spec_4.1.bts: - curl -O https://git.ti.com/ti-bt/service-packs/blobs/raw/54f5c151dacc608b19ab2ce4c30e27a3983048b2/initscripts/TIInit_6.7.16_bt_spec_4.1.bts + @echo "Downloading $@" + @curl -sS -O https://git.ti.com/ti-bt/service-packs/blobs/raw/54f5c151dacc608b19ab2ce4c30e27a3983048b2/initscripts/TIInit_6.7.16_bt_spec_4.1.bts -TIInit_6.7.16_ble_add-on.bts: - curl -O https://git.ti.com/ti-bt/service-packs/blobs/raw/89c8db14929f10d75627b132690432cd71f5f54f/initscripts/TIInit_6.7.16_ble_add-on.bts +TIInit_6.7.16_ble_add-on.bts: + @echo "Downloading $@" + @curl -sS -O https://git.ti.com/ti-bt/service-packs/blobs/raw/89c8db14929f10d75627b132690432cd71f5f54f/initscripts/TIInit_6.7.16_ble_add-on.bts + +# v1.5 - unversioned files from BlueKitchen website, original: http://www.ti.com/tool/cc256xb-bt-sp +cc256x_bt_sp_v1.5.zip: + echo "Downloading $@" + @curl -sS -O $(BLUEKITCHEN_URL)/cc256x_bt_sp_v1.5.zip + +initscripts-TIInit_6.7.16_bt_spec_4.1.bts: cc256x_bt_sp_v1.5.zip + @echo "Extracting $@" + @unzip -q -j -o cc256x_bt_sp_v1.5.zip CC256X_BT_SP/v1.5/initscripts-TIInit_6.7.16_bt_spec_4.1.bts + +initscripts-TIInit_6.7.16_ble_add-on.bts: cc256x_bt_sp_v1.5.zip + @echo "Extracting $@" + @unzip -q -j -o cc256x_bt_sp_v1.5.zip CC256X_BT_SP/v1.5/initscripts-TIInit_6.7.16_ble_add-on.bts + + +# Fourth generation CC256xC - TIInit_6.12.26.bts + +# v1.0 - unversioned files from BlueKitchen website, original: http://www.ti.com/tool/cc256xc-bt-sp +cc256xc_bt_sp_v1.0.zip: + @echo "Downloading $@" + @curl -sS -O $(BLUEKITCHEN_URL)/cc256xc_bt_sp_v1.0.zip + +initscripts-TIInit_6.12.26.bts: cc256xc_bt_sp_v1.0.zip + @echo "Extracting $@" + @unzip -q -j -o cc256xc_bt_sp_v1.0.zip CC256XC_BT_SP/v1.0/initscripts-TIInit_6.12.26.bts + +initscripts-TIInit_6.12.26_ble_add-on.bts: cc256xc_bt_sp_v1.0.zip + @echo "Extracting $@" + @unzip -q -j -o cc256xc_bt_sp_v1.0.zip CC256XC_BT_SP/v1.0/initscripts-TIInit_6.12.26_ble_add-on.bts + + +# Various scripts for WL chipsets -# WL chipset TIInit_11.8.32.bts: - curl -O $(BASE_URL)/TIInit_11.8.32.bts + @echo "Downloading $@" + @curl -sS -O $(TI_GIT_REPO_URL)/TIInit_11.8.32.bts TIInit_12.10.28.bts: - curl -O $(BASE_URL)/TIInit_12.10.28.bts + @echo "Downloading $@" + @curl -sS -O $(TI_GIT_REPO_URL)/TIInit_12.10.28.bts TIInit_12.8.32.bts: - curl -O $(BASE_URL)/TIInit_12.8.32.bts + @echo "Downloading $@" + @curl -sS -O $(TI_GIT_REPO_URL)/TIInit_12.8.32.bts + + + +# convert to .c files based on main file and option add-on -# convert to .c files bluetooth_init_cc2560_2.44.c: bluetooth_init_cc2560_2.44.bts - $(CONVERSION_SCRIPT) - + @echo "Creating $@" + @$(CONVERSION_SCRIPT) $^ $@ bluetooth_init_cc2560A_2.14.c: bluetooth_init_cc2560A_2.14.bts - $(CONVERSION_SCRIPT) + @echo "Creating $@" + @$(CONVERSION_SCRIPT) $^ $@ bluetooth_init_cc2564_2.14.c: bluetooth_init_cc2564_2.14.bts - $(CONVERSION_SCRIPT) - - -bluetooth_init_cc2560B_1.2_BT_Spec_4.0.c: bluetooth_init_cc2560B_1.2_BT_Spec_4.0.bts - $(CONVERSION_SCRIPT) - -bluetooth_init_cc2564B_1.2_BT_Spec_4.0.c: bluetooth_init_cc2564B_1.2_BT_Spec_4.0.bts BLE_init_cc2564B_1.2.bts - $(CONVERSION_SCRIPT) + @echo "Creating $@" + @$(CONVERSION_SCRIPT) $^ $@ bluetooth_init_cc2560B_1.2_BT_Spec_4.1.c: bluetooth_init_cc2560B_1.2_BT_Spec_4.1.bts - $(CONVERSION_SCRIPT) + @echo "Creating $@" + @$(CONVERSION_SCRIPT) $^ $@ bluetooth_init_cc2564B_1.2_BT_Spec_4.1.c: bluetooth_init_cc2564B_1.2_BT_Spec_4.1.bts BLE_init_cc2564B_1.2.bts - $(CONVERSION_SCRIPT) + @echo "Creating $@" + @$(CONVERSION_SCRIPT) $^ $@ bluetooth_init_cc2560B_1.4_BT_Spec_4.1.c: TIInit_6.7.16_bt_spec_4.1.bts - cp TIInit_6.7.16_bt_spec_4.1.bts bluetooth_init_cc2560B_1.4_BT_Spec_4.1.bts - $(CONVERSION_SCRIPT) + @echo "Creating $@" + @$(CONVERSION_SCRIPT) $^ $@ bluetooth_init_cc2564B_1.4_BT_Spec_4.1.c: TIInit_6.7.16_bt_spec_4.1.bts TIInit_6.7.16_ble_add-on.bts - cp TIInit_6.7.16_bt_spec_4.1.bts bluetooth_init_cc2564B_1.4_BT_Spec_4.1.bts - cp TIInit_6.7.16_ble_add-on.bts BLE_init_cc2564B_1.4.bts - $(CONVERSION_SCRIPT) + @echo "Creating $@" + @$(CONVERSION_SCRIPT) $^ $@ + +bluetooth_init_cc2560B_1.5_BT_Spec_4.1.c: initscripts-TIInit_6.7.16_bt_spec_4.1.bts + @echo "Creating $@" + @$(CONVERSION_SCRIPT) $^ $@ + +bluetooth_init_cc2564B_1.5_BT_Spec_4.1.c: initscripts-TIInit_6.7.16_bt_spec_4.1.bts initscripts-TIInit_6.7.16_ble_add-on.bts + @echo "Creating $@" + @$(CONVERSION_SCRIPT) $^ $@ + +bluetooth_init_cc2560C_1.0.c: initscripts-TIInit_6.12.26.bts + @echo "Creating $@" + @$(CONVERSION_SCRIPT) $^ $@ + +bluetooth_init_cc2564C_1.0.c: initscripts-TIInit_6.12.26.bts initscripts-TIInit_6.12.26_ble_add-on.bts + @echo "Creating $@" + @$(CONVERSION_SCRIPT) $^ $@ TIInit_11.8.32.c: TIInit_11.8.32.bts - $(CONVERSION_SCRIPT) + @echo "Creating $@" + @$(CONVERSION_SCRIPT) $^ $@ TIInit_12.10.28.c: TIInit_12.10.28.bts - $(CONVERSION_SCRIPT) + @echo "Creating $@" + @$(CONVERSION_SCRIPT) $^ $@ TIInit_12.8.32.c: TIInit_12.8.32.bts - $(CONVERSION_SCRIPT) + @echo "Creating $@" + @$(CONVERSION_SCRIPT) $^ $@ -all-scripts: bluetooth_init_cc2560_2.44.c bluetooth_init_cc2560A_2.14.c bluetooth_init_cc2564_2.14.bts bluetooth_init_cc2560B_1.2_BT_Spec_4.0.c bluetooth_init_cc2564B_1.2_BT_Spec_4.0.c bluetooth_init_cc2560B_1.2_BT_Spec_4.1.c bluetooth_init_cc2564B_1.2_BT_Spec_4.1.c TIInit_11.8.32.c TIInit_12.10.28.c TIInit_12.8.32.c +all-scripts: \ + bluetooth_init_cc2560_2.44.c \ + bluetooth_init_cc2560A_2.14.c \ + bluetooth_init_cc2564_2.14.bts \ + bluetooth_init_cc2560B_1.4_BT_Spec_4.1.c \ + bluetooth_init_cc2564B_1.4_BT_Spec_4.1.c \ + bluetooth_init_cc2560B_1.5_BT_Spec_4.1.c \ + bluetooth_init_cc2564B_1.5_BT_Spec_4.1.c \ + bluetooth_init_cc2560C_1.0.c \ + bluetooth_init_cc2564C_1.0.c \ + TIInit_11.8.32.c \ + TIInit_12.10.28.c \ + TIInit_12.8.32.c \ clean-scripts: - rm -fr CC256*.zip bluetooth_init_cc256*.bts bluetooth_init_cc256*.c TIInit_*.bts TIInit_*.c BLE_init_cc256*.bts BLE_init_cc256*.c + rm -fr cc256x*.zip CC256*.zip bluetooth_init_cc256*.c TIInit*.c *.bts BLE_init_cc256*.c diff --git a/chipset/cc256x/btstack_chipset_cc256x.c b/chipset/cc256x/btstack_chipset_cc256x.c index ffb7ba23b..c2ce6f5a5 100644 --- a/chipset/cc256x/btstack_chipset_cc256x.c +++ b/chipset/cc256x/btstack_chipset_cc256x.c @@ -88,10 +88,60 @@ static int16_t init_power_in_dB = 13; // 13 dBm // support for SCO over HCI #ifdef ENABLE_SCO_OVER_HCI static int init_send_route_sco_over_hci = 0; -// Follow recommendation from https://e2e.ti.com/support/wireless_connectivity/bluetooth_cc256x/f/660/t/397004 -// route SCO over HCI (connection type=1, tx buffer size = 120, tx buffer max latency= 720, accept packets with CRC Error static const uint8_t hci_route_sco_over_hci[] = { +#if 1 + // Follow recommendation from https://e2e.ti.com/support/wireless_connectivity/bluetooth_cc256x/f/660/t/397004 + // route SCO over HCI (connection type=1, tx buffer size = 120, tx buffer max latency= 720, accept packets with CRC Error 0x10, 0xfe, 0x05, 0x01, 0x78, 0xd0, 0x02, 0x01, +#else + // Configure SCO via I2S interface - 256 kbps + // Send_HCI_VS_Write_CODEC_Config 0xFD06, + 0x06, 0xfd, + // len + 34, + //3072, - clock rate 3072000 hz + 0x00, 0x01, + // 0x00 - clock direction: output = master + 0x00, + // 8000, framesync frequency in hz + 0x40, 0x1f, 0x00, 0x00, + // 0x0001, framesync duty cycle + 0x01, 0x00, + // 1, framesync edge + 1, + // 0x00, framesync polarity + 0x00, + // 0x00, RESERVED + 0x00, + // 16, channel 1 out size + 8, 0, + // 0x0001, channel 1 out offset + 0x01, 0x00, + // 1, channel 1 out edge + 1, + // 16, channel 1 in size + 8, 0, + // 0x0001, channel 1 in offset + 0x01, 0x00, + // 0, channel 1 in edge + 0, + // 0x00, RESERVED + 0x00, + // 16, channel 2 out size + 8, 0, + // 17, channel 2 out offset + 9, 0, + // 0x01, channel 2 out edge + 0x01, + // 16, channel 2 in size + 8, 0, + // 17, channel 2 in offset + 9, 0, + // 0x00, channel 2 in edge + 0x00, + // 0x0001, RESERVED + 0x00 +#endif }; #endif diff --git a/chipset/cc256x/btstack_chipset_cc256x.h b/chipset/cc256x/btstack_chipset_cc256x.h index ec2433fa3..dac84cb65 100644 --- a/chipset/cc256x/btstack_chipset_cc256x.h +++ b/chipset/cc256x/btstack_chipset_cc256x.h @@ -50,9 +50,21 @@ extern "C" { #include #include "btstack_chipset.h" +/** + * Configure output power before HCI POWER_ON + */ void btstack_chipset_cc256x_set_power(int16_t power_in_dB); + +/** + * Get chipset instance for CC256x series + */ const btstack_chipset_t * btstack_chipset_cc256x_instance(void); +/** + * Get LMP Subversion of compile-time init script + */ +uint16_t btstack_chipset_cc256x_lmp_subversion(void); + #if defined __cplusplus } #endif diff --git a/chipset/cc256x/convert_bts_init_scripts.py b/chipset/cc256x/convert_bts_init_scripts.py index 6b340aebf..5718d4115 100755 --- a/chipset/cc256x/convert_bts_init_scripts.py +++ b/chipset/cc256x/convert_bts_init_scripts.py @@ -9,16 +9,19 @@ import re import sys import os -print(''' -CC256x init script conversion tool for use with BTstack, v0.1 +usage = ''' +CC256x init script conversion tool for use with BTstack, v0.2 Copyright 2012-2014 BlueKitchen GmbH -''') -usage = '''This script prepares init scripts for TI's -CC256x chipsets for use with BTstack . +Usage: +$ ./convert_bts_init_scripts.py main.bts [ble-add-on.bts] output.c -Please download the Service Pack for your module from http://processors.wiki.ti.com/index.php/CC256x_Downloads -Then, unzip it and copy the *.bts file into this folder and start the script again. +Please specify the main .bts script and optionally the BLE Add-on to generate the init script .c file. + +The Makefile include chipset/cc256x/Makefile.inc automates the process of downloading and converting .bts files. + +If this is not an option, you can download the Service Packs for your module from http://processors.wiki.ti.com/index.php/CC256x_Downloads +Then, unzip it and copy the *.bts file into this folder before start the script again. ''' fartext = ''' @@ -30,6 +33,14 @@ __attribute__((__progmem__)) #endif ''' +get_lmp_subversion = ''' +const uint16_t {prefix}_init_script_lmp_subversion = {lmp_subversion}; + +uint16_t btstack_chipset_cc256x_lmp_subversion(void){{ + return {prefix}_init_script_lmp_subversion; +}} +''' + data_indent = ' ' def read_little_endian_16(f): @@ -96,15 +107,15 @@ def append_calibration_sequence(additions, str_list, data_indent): str_list.append("0x01, 0x80, 0xfd, 0x06, 0x3c, 0xf0, 0x5f, 0x00, 0x00, 0x00,\n\n") return 20 -def convert_bts(main_bts_file, bts_add_on): + +def convert_bts(output_file, main_bts_file, bts_add_on, aka, lmp_subversion): array_name = 'cc256x' - c_file = main_bts_file.replace('bts', 'c') input_files = [ main_bts_file ] if bts_add_on != "": input_files.append(bts_add_on) - with open(c_file, 'w') as fout: + with open(output_file, 'w') as fout: # assert script contains templates for configuration by BTstack have_eHCILL = False @@ -113,7 +124,7 @@ def convert_bts(main_bts_file, bts_add_on): have_power_vector_edr3 = False; have_class2_single_power = False; - print("Creating {0}".format(c_file)) + print("Creating {0}".format(output_file)) part_size = 0 @@ -223,18 +234,24 @@ def convert_bts(main_bts_file, bts_add_on): fout.write( '// init script created from\n') fout.write( '// - {0}\n'.format(main_bts_file)) + if aka != "": + fout.write( '// - AKA TIInit_{0}.bts\n'.format(aka)) if bts_add_on != "": fout.write( '// - {0}\n'.format(bts_add_on)) fout.write( '#include \n') - + fout.write( '\n') + # if aka != "": + # fout.write( 'const char * {0}_init_script_aka = "{1}";\n'.format(array_name, aka)) + if lmp_subversion != 0: + fout.write( get_lmp_subversion.format(prefix = array_name, lmp_subversion = "0x%04x" % lmp_subversion)) part = 0 size = 0 for part_size in part_sizes: part += 1 size += part_size - print("- part", part, "size", part_size) + print("- part %u, size %u" % (part,part_size)) - print('- total size', size) + print('- total size %u' % size) print("\n".join(additions)) @@ -266,61 +283,61 @@ def convert_bts(main_bts_file, bts_add_on): fout.write('const uint32_t {0}_init_script_size = {1};\n\n'.format(array_name,size)); # fout.write('void main() {0} printf("size {1}\\n", {2}_init_script_size); {3}'.format('{', '%u', array_name,'}')); -# get list of *.bts files -files = glob.glob('*.bts') -if not files: +# check usage: 2-3 param +if len(sys.argv) < 3 or len(sys.argv) > 4: print(usage) - sys.exit(1) + sys.exit(1) -# convert each of them -for name in files: - name_lower = name.lower() - # skip BLE and AVRP add-ons - if name_lower.startswith('ble_init_cc'): - print("Skipping BLE add-on", name) - continue - if name_lower.startswith('avpr_init_cc'): - print("Skipping AVPR add-on", name) - continue - if re.match("tiinit_.*_ble_add-on.bts", name_lower): - print("Skipping BLE add-on", name) - continue - if re.match("initscripts_tiinit_.*_ble_add-on.bts", name_lower): - print("Skipping BLE add-on", name) - continue - if re.match("initscripts_tiinit_.*_avpr_add-on.bts", name_lower): - print("Skipping AVPR add-on", name) - continue +main_bts = sys.argv[1] +add_on = "" +if len(sys.argv) == 4: + add_on = sys.argv[2] +output_file = sys.argv[-1] - print "check", name - - # check for BLE add-on - add_on = "" - name_parts = re.match('bluetooth_init_(.....+_...)_.*.bts', name) - if name_parts: - potential_add_on = 'BLE_init_%s.bts' % name_parts.group(1) - if os.path.isfile(potential_add_on): - add_on = potential_add_on - print("Found", add_on, "add-on for", name) +# get AKA from file names that include model name +aka = "" +lmp_subversion = 0 +name_lower = main_bts.lower() +if 'cc2560_' in name_lower: + aka = "6.2.31" +if 'cc2560a_' in name_lower or 'cc2564_' in name_lower: + aka = "6.6.15" +if 'cc2560b_' in name_lower or 'cc2564b_' in name_lower: + aka = "6.7.16" +if 'cc2564c_' in name_lower: + aka = "6.12.26" - name_parts = re.match('TIInit_(\d*\.\d*\.\d*)_.*.bts', name) - if name_parts: - potential_add_on = 'TIInit_%s_ble_add-on.bts' % name_parts.group(1) - if os.path.isfile(potential_add_on): - add_on = potential_add_on - print("Found", add_on, "add-on for", name) +# use AKA from .bts file that it +name_parts = re.match('.*TIInit_(\d*\.\d*\.\d*).*.bts', main_bts) +if name_parts: + aka = name_parts.group(1) - name_parts = re.match('initscripts_TIInit_(\d*\.\d*\.\d*)_.*.bts', name) - if name_parts: - potential_add_on = 'initscripts_TIInit_%s_ble_add-on.bts' % name_parts.group(1) - if os.path.isfile(potential_add_on): - add_on = potential_add_on - print("Found", add_on, "add-on for", name) +# get lmp subversion from AKA +lmp_subversion_for_aka = { + '6.2.31' : 0x191f, + '6.6.15' : 0x1B0F, + '6.7.16' : 0x1B90, + '6.12.26' : 0x9a1a +} - convert_bts(name, add_on) +if aka in lmp_subversion_for_aka: + lmp_subversion = lmp_subversion_for_aka[aka] + +# print summary + +print ("Main file: %s"% main_bts) +if add_on != "": + print ("Add-on file: %s" % add_on) +if aka != "": + print ("- AKA TIInit_%s.bts" % aka) + +if lmp_subversion: + print ("- LMP Subversion: 0x%04x" % lmp_subversion) +else: + print ("- LMP Subversion: Unknown") + +convert_bts(output_file, main_bts, add_on, aka, lmp_subversion) +print -# done -print('\nConversion(s) successful!\n') - diff --git a/doc/manual/update_apis.py b/doc/manual/update_apis.py index 6c134e1c4..6b8862918 100755 --- a/doc/manual/update_apis.py +++ b/doc/manual/update_apis.py @@ -160,15 +160,19 @@ def createIndex(btstackfolder, apis, githubfolder): functions[ref_function.group(1)] = codeReference(ref_function.group(1), githubfolder, api_tuple[0], linenr) continue - function = re.match('.*?\s+\*?\s*(.*?)\(.*\(*.*;\n', line) + function = re.match('(.*?)\(.*\(*.*;\n', line) if function: - functions[function.group(1)] = codeReference(function.group(1), githubfolder, api_tuple[0], linenr) + parts = function.group(1).split(" "); + name = parts[len(parts)-1] + functions[name] = codeReference( name, githubfolder, api_tuple[0], linenr) continue - function = re.match('.*?\s+\*?\s*(.*?)\(.*\(*.*', line) + function = re.match('.(.*?)\(.*\(*.*', line) if function: + parts = function.group(1).split(" "); + name = parts[len(parts)-1] multiline_function_def = 1 - functions[function.group(1)] = codeReference(function.group(1), githubfolder, api_tuple[0], linenr) + functions[name] = codeReference(name, githubfolder, api_tuple[0], linenr) def main(argv): @@ -207,6 +211,11 @@ def main(argv): writeAPI(apifile, btstackfolder, apis, mk_codeidentation) createIndex(btstackfolder, apis, githubfolder) + for function in functions: + parts = function.split(' ') + if (len(parts) > 1): + print (parts) + references = functions.copy() references.update(typedefs) diff --git a/example/hfp_ag_demo.c b/example/hfp_ag_demo.c index 902cc7ce0..bf24a0455 100644 --- a/example/hfp_ag_demo.c +++ b/example/hfp_ag_demo.c @@ -65,14 +65,8 @@ uint8_t hfp_service_buffer[150]; const uint8_t rfcomm_channel_nr = 1; const char hfp_ag_service_name[] = "BTstack HFP AG Test"; -// PTS -// static bd_addr_t device_addr = {0x00,0x15,0x83,0x5F,0x9D,0x46}; -// BT-201 -// static bd_addr_t device_addr = {0x00, 0x07, 0xB0, 0x83, 0x02, 0x5E}; -// CC256x -// bd_addr_t device_addr = { 0xD0, 0x39, 0x72, 0xCD, 0x83, 0x45}; -// Mini Jambox -bd_addr_t device_addr = { 0x00, 0x15, 0x83, 0x5F, 0x9D, 0x46}; +static bd_addr_t device_addr; +static const char * device_addr_string = "00:15:83:5F:9D:46"; // static uint8_t codecs[] = {HFP_CODEC_CVSD, HFP_CODEC_MSBC}; static uint8_t codecs[] = {HFP_CODEC_CVSD}; @@ -729,6 +723,9 @@ int btstack_main(int argc, const char * argv[]){ printf("SDP service record size: %u\n", de_get_len( hfp_service_buffer)); sdp_register_service(hfp_service_buffer); + // parse humand readable Bluetooth address + sscanf_bd_addr(device_addr_string, device_addr); + #ifdef HAVE_POSIX_STDIN btstack_stdin_setup(stdin_process); #endif diff --git a/example/sco_demo_util.c b/example/sco_demo_util.c index 4f51715e1..1d3b61dd2 100644 --- a/example/sco_demo_util.c +++ b/example/sco_demo_util.c @@ -57,6 +57,8 @@ #define SCO_DEMO_MODE_SINE 0 #define SCO_DEMO_MODE_ASCII 1 #define SCO_DEMO_MODE_COUNTER 2 +#define SCO_DEMO_MODE_55 3 +#define SCO_DEMO_MODE_00 4 // SCO demo configuration @@ -76,6 +78,7 @@ #define USE_PORTAUDIO #endif + #ifdef USE_PORTAUDIO #include #include "btstack_ring_buffer.h" @@ -105,12 +108,13 @@ static uint8_t ring_buffer_storage[2*MSBC_PREBUFFER_BYTES]; static btstack_ring_buffer_t ring_buffer; #endif - static int dump_data = 1; static int count_sent = 0; static int count_received = 0; static uint8_t negotiated_codec = 0; -static int num_audio_frames = 0; +#if SCO_DEMO_MODE != SCO_DEMO_MODE_55 +static int phase = 0; +#endif FILE * msbc_file_in; FILE * msbc_file_out; @@ -141,7 +145,6 @@ static const int16_t sine_int16[] = { -19260, -17557, -15786, -13952, -12062, -10126, -8149, -6140, -4107, -2057, }; -static int phase = 0; static void sco_demo_sine_wave_int8(int num_samples, int8_t * data){ int i; for (i=0; i 'z') phase = 'a'; -#else +#endif +#if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER int j; for (j=0;j 100000){ + printf("Summary: data %07u, packets %04u, packet with crc errors %0u, byte errors %04u\n", data_received, packets, crc_errors, byte_errors); + crc_errors = 0; + byte_errors = 0; + data_received = 0; + packets = 0; + } #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE #ifdef SCO_WAV_FILENAME @@ -538,23 +581,59 @@ void sco_demo_receive(uint8_t * packet, uint16_t size){ #endif if (packet[1] & 0x30){ - printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); - log_info("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); - printf_hexdump(&packet[3], size-3); - + crc_errors++; + // printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); + // printf_hexdump(&packet[3], size-3); return; } if (dump_data){ - printf("data: "); #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII + printf("data: "); int i; for (i=3;iendpoint, transfer->status, transfer->actual_length ); @@ -317,6 +335,7 @@ static int usb_send_sco_packet(uint8_t *packet, int size){ sco_ring_write = 0; } sco_ring_transfers_active++; + sco_ring_transfers_in_flight[tranfer_index] = 1; // log_info("H2: queued packet at index %u, num active %u", tranfer_index, sco_ring_transfers_active); @@ -407,11 +426,19 @@ static void handle_completed_transfer(struct libusb_transfer *transfer){ } resubmit = 1; } else if (transfer->endpoint == sco_out_addr){ - log_info("sco out done, {{ %u/%u (%x)}, { %u/%u (%x)}, { %u/%u (%x)}}", - transfer->iso_packet_desc[0].actual_length, transfer->iso_packet_desc[0].length, transfer->iso_packet_desc[0].status, - transfer->iso_packet_desc[1].actual_length, transfer->iso_packet_desc[1].length, transfer->iso_packet_desc[1].status, - transfer->iso_packet_desc[2].actual_length, transfer->iso_packet_desc[2].length, transfer->iso_packet_desc[2].status); + int i; + for (i = 0; i < transfer->num_iso_packets; i++) { + struct libusb_iso_packet_descriptor *pack = &transfer->iso_packet_desc[i]; + if (pack->status != LIBUSB_TRANSFER_COMPLETED) { + log_error("Error: pack %u status %d\n", i, pack->status); + } + } + // log_info("sco out done, {{ %u/%u (%x)}, { %u/%u (%x)}, { %u/%u (%x)}}", + // transfer->iso_packet_desc[0].actual_length, transfer->iso_packet_desc[0].length, transfer->iso_packet_desc[0].status, + // transfer->iso_packet_desc[1].actual_length, transfer->iso_packet_desc[1].length, transfer->iso_packet_desc[1].status, + // transfer->iso_packet_desc[2].actual_length, transfer->iso_packet_desc[2].length, transfer->iso_packet_desc[2].status); // notify upper layer if there's space for new SCO packets + if (sco_ring_have_space()) { uint8_t event[] = { HCI_EVENT_SCO_CAN_SEND_NOW, 0}; packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event)); @@ -879,6 +906,7 @@ static int usb_open(void){ // outgoing for (c=0; c < SCO_RING_BUFFER_COUNT ; c++){ sco_ring_transfers[c] = libusb_alloc_transfer(NUM_ISO_PACKETS); // 1 isochronous transfers SCO out - up to 3 parts + sco_ring_transfers_in_flight[c] = 0; } #endif @@ -980,6 +1008,18 @@ static int usb_close(void){ #ifdef ENABLE_SCO_OVER_HCI for (c = 0 ; c < ISOC_BUFFERS ; c++) { libusb_cancel_transfer(sco_in_transfer[c]); + log_info("libusb_cancel_transfer sco_in_transfer[%d]", c); + } + + for (c = 0; c < SCO_RING_BUFFER_COUNT ; c++){ + if (sco_ring_transfers_in_flight[c]) { + log_info("libusb_cancel_transfer sco_ring_transfers[%d]", c); + libusb_cancel_transfer(sco_ring_transfers[c]); + } else { + log_info("libusb_free_transfer sco_ring_transfers[%d]", c); + libusb_free_transfer(sco_ring_transfers[c]); + sco_ring_transfers[c] = 0; + } } #endif libusb_set_debug(NULL, LIBUSB_LOG_LEVEL_WARNING); @@ -1008,6 +1048,15 @@ static int usb_close(void){ break; } } + + if (!completed) continue; + + for (c=0; c < SCO_RING_BUFFER_COUNT ; c++){ + if (sco_ring_transfers[c]){ + completed = 0; + break; + } + } #endif } @@ -1016,6 +1065,7 @@ static int usb_close(void){ #ifdef ENABLE_SCO_OVER_HCI libusb_release_interface(handle, 1); #endif + log_info("Libusb shutdown complete"); case LIB_USB_DEVICE_OPENDED: libusb_close(handle); diff --git a/port/ez430-rf2560/src/main.c b/port/ez430-rf2560/src/main.c index a46d2dff8..880964d74 100644 --- a/port/ez430-rf2560/src/main.c +++ b/port/ez430-rf2560/src/main.c @@ -77,9 +77,32 @@ static btstack_packet_callback_registration_t hci_event_callback_registration; static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ if (packet_type != HCI_EVENT_PACKET) return; - if (hci_event_packet_get_type(packet) != BTSTACK_EVENT_STATE) return; - if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return; - printf("BTstack up and running.\n"); + switch(hci_event_packet_get_type(packet)){ + case BTSTACK_EVENT_STATE: + if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return; + printf("BTstack up and running.\n"); + break; + case HCI_EVENT_COMMAND_COMPLETE: + if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_read_local_version_information)){ + uint16_t manufacturer = little_endian_read_16(packet, 10); + uint16_t lmp_subversion = little_endian_read_16(packet, 12); + // assert manufacturer is TI + if (manufacturer != COMPANY_ID_TEXAS_INSTRUMENTS_INC){ + printf("ERROR: Expected Bluetooth Chipset from TI but got manufacturer 0x%04x\n", manufacturer); + break; + } + // assert correct init script is used based on expected lmp_subversion + if (lmp_subversion != btstack_chipset_cc256x_lmp_subversion()){ + printf("Error: LMP Subversion does not match initscript! "); + printf("Your initscripts is for %s chipset\n", btstack_chipset_cc256x_lmp_subversion() < lmp_subversion ? "an older" : "a newer"); + printf("Please update Makefile to include the appropriate bluetooth_init_cc256???.c file\n"); + break; + } + } + break; + default: + break; + } } // main diff --git a/port/msp-exp430f5438-cc2564b/src/main.c b/port/msp-exp430f5438-cc2564b/src/main.c index 2c31fc5c9..0495f909f 100644 --- a/port/msp-exp430f5438-cc2564b/src/main.c +++ b/port/msp-exp430f5438-cc2564b/src/main.c @@ -96,9 +96,32 @@ static btstack_packet_callback_registration_t hci_event_callback_registration; static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ if (packet_type != HCI_EVENT_PACKET) return; - if (hci_event_packet_get_type(packet) != BTSTACK_EVENT_STATE) return; - if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return; - printf("BTstack up and running.\n"); + switch(hci_event_packet_get_type(packet)){ + case BTSTACK_EVENT_STATE: + if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return; + printf("BTstack up and running.\n"); + break; + case HCI_EVENT_COMMAND_COMPLETE: + if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_read_local_version_information)){ + uint16_t manufacturer = little_endian_read_16(packet, 10); + uint16_t lmp_subversion = little_endian_read_16(packet, 12); + // assert manufacturer is TI + if (manufacturer != COMPANY_ID_TEXAS_INSTRUMENTS_INC){ + printf("ERROR: Expected Bluetooth Chipset from TI but got manufacturer 0x%04x\n", manufacturer); + break; + } + // assert correct init script is used based on expected lmp_subversion + if (lmp_subversion != btstack_chipset_cc256x_lmp_subversion()){ + printf("Error: LMP Subversion does not match initscript! "); + printf("Your initscripts is for %s chipset\n", btstack_chipset_cc256x_lmp_subversion() < lmp_subversion ? "an older" : "a newer"); + printf("Please update Makefile to include the appropriate bluetooth_init_cc256???.c file\n"); + break; + } + } + break; + default: + break; + } } static void btstack_setup(void){ diff --git a/port/msp430f5229lp-cc2564b/Makefile b/port/msp430f5229lp-cc2564b/Makefile index 0351a349f..dcb107b1d 100644 --- a/port/msp430f5229lp-cc2564b/Makefile +++ b/port/msp430f5229lp-cc2564b/Makefile @@ -97,7 +97,8 @@ BLE_OBJ = $(BLE:.c=.o) # create firmware image from common objects and example source file all: led_counter.hex spp_counter.hex gap_inquiry.hex spp_flowcontrol.hex \ - sdp_rfcomm_query.hex sdp_general_query.hex ble_server.hex + sdp_rfcomm_query.hex sdp_general_query.hex +# ble_server.hex # fetch and convert init scripts include ${BTSTACK_ROOT}/chipset/cc256x/Makefile.inc diff --git a/port/msp430f5229lp-cc2564b/src/main.c b/port/msp430f5229lp-cc2564b/src/main.c index 837995d03..1fcc3b087 100644 --- a/port/msp430f5229lp-cc2564b/src/main.c +++ b/port/msp430f5229lp-cc2564b/src/main.c @@ -100,9 +100,32 @@ static btstack_packet_callback_registration_t hci_event_callback_registration; static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ if (packet_type != HCI_EVENT_PACKET) return; - if (hci_event_packet_get_type(packet) != BTSTACK_EVENT_STATE) return; - if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return; - printf("BTstack up and running.\n"); + switch(hci_event_packet_get_type(packet)){ + case BTSTACK_EVENT_STATE: + if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return; + printf("BTstack up and running.\n"); + break; + case HCI_EVENT_COMMAND_COMPLETE: + if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_read_local_version_information)){ + uint16_t manufacturer = little_endian_read_16(packet, 10); + uint16_t lmp_subversion = little_endian_read_16(packet, 12); + // assert manufacturer is TI + if (manufacturer != COMPANY_ID_TEXAS_INSTRUMENTS_INC){ + printf("ERROR: Expected Bluetooth Chipset from TI but got manufacturer 0x%04x\n", manufacturer); + break; + } + // assert correct init script is used based on expected lmp_subversion + if (lmp_subversion != btstack_chipset_cc256x_lmp_subversion()){ + printf("Error: LMP Subversion does not match initscript! "); + printf("Your initscripts is for %s chipset\n", btstack_chipset_cc256x_lmp_subversion() < lmp_subversion ? "an older" : "a newer"); + printf("Please update Makefile to include the appropriate bluetooth_init_cc256???.c file\n"); + break; + } + } + break; + default: + break; + } } static void btstack_setup(void){ diff --git a/port/nrf5-zephyr/hci_uart.patch b/port/nrf5-zephyr/hci_uart.patch deleted file mode 100644 index 16699f322..000000000 --- a/port/nrf5-zephyr/hci_uart.patch +++ /dev/null @@ -1,46 +0,0 @@ -diff --git a/samples/bluetooth/hci_uart/src/main.c b/samples/bluetooth/hci_uart/src/main.c -index b103f05..80a82d3 100644 ---- a/samples/bluetooth/hci_uart/src/main.c -+++ b/samples/bluetooth/hci_uart/src/main.c -@@ -36,6 +36,9 @@ - #include - #include - -+#include "ll.h" -+#include "nrf.h" -+ - static struct device *hci_uart_dev; - - #define STACK_SIZE 1024 -@@ -301,6 +304,18 @@ static int hci_uart_init(struct device *unused) - DEVICE_INIT(hci_uart, "hci_uart", &hci_uart_init, NULL, NULL, - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); - -+void little_endian_store_16(uint8_t *buffer, uint16_t pos, uint16_t value){ -+ buffer[pos++] = value; -+ buffer[pos++] = value >> 8; -+} -+ -+void little_endian_store_32(uint8_t *buffer, uint16_t pos, uint32_t value){ -+ buffer[pos++] = value; -+ buffer[pos++] = value >> 8; -+ buffer[pos++] = value >> 16; -+ buffer[pos++] = value >> 24; -+} -+ - void main(void) - { - /* incoming events and data from the controller */ -@@ -320,6 +335,12 @@ void main(void) - (nano_fiber_entry_t)tx_fiber, 0, 0, 7, 0); - - bt_enable_raw(&rx_queue); -+ -+ // make Random Static Address available via HCI Read BD ADDR as fake public address -+ uint8_t addr[6]; -+ little_endian_store_16(addr, 4, NRF_FICR->DEVICEADDR[1] | 0xc000); -+ little_endian_store_32(addr, 0, NRF_FICR->DEVICEADDR[0]); -+ ll_address_set(0, addr); - - while (1) { - struct net_buf *buf; diff --git a/port/nrf5-zephyr/integrate_btstack.sh b/port/nrf5-zephyr/integrate_btstack.sh index 255190e6f..65ffb0505 100755 --- a/port/nrf5-zephyr/integrate_btstack.sh +++ b/port/nrf5-zephyr/integrate_btstack.sh @@ -2,23 +2,28 @@ ZEPHYR_BASE=../../.. -echo "Adding BTstack sources as subsys/btstack" +echo "Integrating BTstack into Zephyr" +if grep -q -F "NRF_FICR->DEVICEADDR" ${ZEPHYR_BASE}/samples/bluetooth/hci_uart/src/main.c; then + echo "HCI Firmware patch already installed" +else + # assert files don't exist since patch would get irritated + echo "Applying HCI Firmware patch" + rm -f ${ZEPHYR_BASE}/samples/bluetooth/hci_uart/flash* + cat hci_firmware.patch | patch -d ${ZEPHYR_BASE} -p1 +fi + +echo "Adding subsys/btstack" # add btstack folder to subsys/Makefile MAKEFILE_ADD_ON='obj-$(CONFIG_BTSTACK) += btstack/' NET_MAKEFILE=${ZEPHYR_BASE}/subsys/Makefile grep -q -F btstack ${NET_MAKEFILE} || echo ${MAKEFILE_ADD_ON} >> ${NET_MAKEFILE} -# add BTstack KConfig to net/Kconfig +# add BTstack KConfig to subsys/Kconfig SUBSYS_KCONFIG=${ZEPHYR_BASE}/subsys/Kconfig grep -q -F btstack ${SUBSYS_KCONFIG} || echo 'source "subsys/btstack/Kconfig"' >> ${SUBSYS_KCONFIG} -# set Nordic Semiconductor as manufacturer -CTRL_H=${ZEPHYR_BASE}/subsys/bluetooth/controller/ll/ctrl.h -sed -i "s|#define RADIO_BLE_COMPANY_ID.*0xFFFF.|#define RADIO_BLE_COMPANY_ID (0x0059) // Nordic Semiconductor ASA|g" ${CTRL_H} - - # create subsys/btstack mkdir -p ${ZEPHYR_BASE}/subsys/btstack @@ -52,17 +57,3 @@ rsync -a Makefile.bluedroid-decoder ${ZEPHYR_BASE}/subsys/btstack/bluedroid/deco # create samples/btstack ./create_examples.py - - -## Additonal changes for HCI Controller firmware in samples/bluetooth/hci-uart -HCI_UART=${ZEPHYR_BASE}/samples/bluetooth/hci_uart - -# add flash scripts to hci-uart -rsync -a flash_nrf51_pca10028.sh ${HCI_UART}/flash_nrf51_pca10028.sh -rsync -a flash_nrf52_pca10040.sh ${HCI_UART}/flash_nrf52_pca10040.sh - -# use 115200 baud -sed -i 's|CONFIG_UART_NRF5_BAUD_RATE=1000000|CONFIG_UART_NRF5_BAUD_RATE=115200|g' ${HCI_UART}/nrf5.conf - -# provide static random address to host via hci read bd addr -grep -q -F ll_address_set ${HCI_UART}/src/main.c || cat hci_uart.patch | patch -d ${ZEPHYR_BASE} -p1 diff --git a/port/nrf5-zephyr/nrf5.conf b/port/nrf5-zephyr/nrf5.conf index 8bbaba96d..1e63b2990 100644 --- a/port/nrf5-zephyr/nrf5.conf +++ b/port/nrf5-zephyr/nrf5.conf @@ -9,7 +9,7 @@ CONFIG_SERIAL=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_BLUETOOTH=y -CONFIG_BLUETOOTH_STACK_HCI_RAW=y +CONFIG_BLUETOOTH_HCI_RAW=y CONFIG_BLUETOOTH_MAX_CONN=16 CONFIG_BLUETOOTH_CONTROLLER_RX_BUFFERS=4 CONFIG_BLUETOOTH_CONTROLLER_TX_BUFFERS=4 diff --git a/port/posix-h4/main.c b/port/posix-h4/main.c index 26fc2664b..3e9c0c2b1 100644 --- a/port/posix-h4/main.c +++ b/port/posix-h4/main.c @@ -69,6 +69,7 @@ int is_bcm; int btstack_main(int argc, const char * argv[]); +static void local_version_information_handler(uint8_t * packet); static hci_transport_config_uart_t config = { HCI_TRANSPORT_CONFIG_UART, @@ -89,6 +90,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack break; case HCI_EVENT_COMMAND_COMPLETE: if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_read_local_name)){ + if (hci_event_command_complete_get_return_parameters(packet)[0]) break; // terminate, name 248 chars packet[6+248] = 0; printf("Local name: %s\n", &packet[6]); @@ -96,6 +98,9 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack btstack_chipset_bcm_set_device_name((const char *)&packet[6]); } } + if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_read_local_version_information)){ + local_version_information_handler(packet); + } break; default: break; @@ -134,17 +139,17 @@ static void use_fast_uart(void){ #endif } -static void local_version_information_callback(uint8_t * packet){ +static void local_version_information_handler(uint8_t * packet){ printf("Local version information:\n"); uint16_t hci_version = little_endian_read_16(packet, 4); uint16_t hci_revision = little_endian_read_16(packet, 6); uint16_t lmp_version = little_endian_read_16(packet, 8); uint16_t manufacturer = little_endian_read_16(packet, 10); uint16_t lmp_subversion = little_endian_read_16(packet, 12); - printf("- HCI Version 0x%04x\n", hci_version); - printf("- HCI Revision 0x%04x\n", hci_revision); - printf("- LMP Version 0x%04x\n", lmp_version); - printf("- LMP Revision 0x%04x\n", lmp_subversion); + printf("- HCI Version 0x%04x\n", hci_version); + printf("- HCI Revision 0x%04x\n", hci_revision); + printf("- LMP Version 0x%04x\n", lmp_version); + printf("- LMP Subversion 0x%04x\n", lmp_subversion); printf("- Manufacturer 0x%04x\n", manufacturer); switch (manufacturer){ case COMPANY_ID_CAMBRIDGE_SILICON_RADIO: @@ -154,6 +159,12 @@ static void local_version_information_callback(uint8_t * packet){ break; case COMPANY_ID_TEXAS_INSTRUMENTS_INC: printf("Texas Instruments - CC256x compatible chipset.\n"); + if (lmp_subversion != btstack_chipset_cc256x_lmp_subversion()){ + printf("Error: LMP Subversion does not match initscript! "); + printf("Your initscripts is for %s chipset\n", btstack_chipset_cc256x_lmp_subversion() < lmp_subversion ? "an older" : "a newer"); + printf("Please update Makefile to include the appropriate bluetooth_init_cc256???.c file\n"); + exit(10); + } use_fast_uart(); hci_set_chipset(btstack_chipset_cc256x_instance()); #ifdef ENABLE_EHCILL @@ -161,6 +172,7 @@ static void local_version_information_callback(uint8_t * packet){ #else printf("eHCILL disable.\n"); #endif + break; case COMPANY_ID_BROADCOM_CORPORATION: printf("Broadcom - using BCM driver.\n"); @@ -197,7 +209,8 @@ int main(int argc, const char * argv[]){ hci_dump_open("/tmp/hci_dump.pklg", HCI_DUMP_PACKETLOGGER); // pick serial port - config.device_name = "/dev/tty.usbserial-A9OVNX5P"; + config.device_name = "/dev/tty.usbserial-A900K2WS"; // DFROBOT + // config.device_name = "/dev/tty.usbserial-A50285BI"; // BOOST-CC2564MODA New // init HCI const btstack_uart_block_t * uart_driver = btstack_uart_block_posix_instance(); @@ -210,9 +223,6 @@ int main(int argc, const char * argv[]){ hci_event_callback_registration.callback = &packet_handler; hci_add_event_handler(&hci_event_callback_registration); - // setup dynamic chipset driver setup - hci_set_local_version_information_callback(&local_version_information_callback); - // handle CTRL-c signal(SIGINT, sigint_handler); diff --git a/port/stm32-f103rb-nucleo/main.c b/port/stm32-f103rb-nucleo/main.c index c07828bd1..3beaf7873 100644 --- a/port/stm32-f103rb-nucleo/main.c +++ b/port/stm32-f103rb-nucleo/main.c @@ -416,9 +416,32 @@ static const hci_transport_config_uart_t config = { static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ if (packet_type != HCI_EVENT_PACKET) return; - if (hci_event_packet_get_type(packet) != BTSTACK_EVENT_STATE) return; - if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return; - printf("BTstack up and running.\n"); + switch(hci_event_packet_get_type(packet)){ + case BTSTACK_EVENT_STATE: + if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return; + printf("BTstack up and running.\n"); + break; + case HCI_EVENT_COMMAND_COMPLETE: + if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_read_local_version_information)){ + uint16_t manufacturer = little_endian_read_16(packet, 10); + uint16_t lmp_subversion = little_endian_read_16(packet, 12); + // assert manufacturer is TI + if (manufacturer != COMPANY_ID_TEXAS_INSTRUMENTS_INC){ + printf("ERROR: Expected Bluetooth Chipset from TI but got manufacturer 0x%04x\n", manufacturer); + break; + } + // assert correct init script is used based on expected lmp_subversion + if (lmp_subversion != btstack_chipset_cc256x_lmp_subversion()){ + printf("Error: LMP Subversion does not match initscript! "); + printf("Your initscripts is for %s chipset\n", btstack_chipset_cc256x_lmp_subversion() < lmp_subversion ? "an older" : "a newer"); + printf("Please update Makefile to include the appropriate bluetooth_init_cc256???.c file\n"); + break; + } + } + break; + default: + break; + } } int main(void) diff --git a/src/btstack_linked_list.h b/src/btstack_linked_list.h index 0183ff4f8..8ba9cb68e 100644 --- a/src/btstack_linked_list.h +++ b/src/btstack_linked_list.h @@ -45,6 +45,8 @@ #if defined __cplusplus extern "C" { #endif + +/* API_START */ typedef struct btstack_linked_item { struct btstack_linked_item *next; // <-- next element in list, or NULL @@ -89,8 +91,11 @@ int btstack_linked_list_iterator_has_next(btstack_linked_list_iterat btstack_linked_item_t * btstack_linked_list_iterator_next(btstack_linked_list_iterator_t * it); void btstack_linked_list_iterator_remove(btstack_linked_list_iterator_t * it); +/* API_END */ + void test_linked_list(void); + #if defined __cplusplus } #endif diff --git a/src/btstack_util.h b/src/btstack_util.h index 7ab067cc8..011e2d29e 100644 --- a/src/btstack_util.h +++ b/src/btstack_util.h @@ -65,12 +65,14 @@ extern "C" { // will be moved to daemon/btstack_device_name_db.h + /** * @brief The device name type */ #define DEVICE_NAME_LEN 248 typedef uint8_t device_name_t[DEVICE_NAME_LEN+1]; +/* API_START */ /** * @brief Minimum function for uint32_t @@ -223,6 +225,7 @@ int uuid_has_bluetooth_prefix(uint8_t * uuid128); */ uint32_t btstack_atoi(const char *str); +/* API_END */ #if defined __cplusplus } diff --git a/src/hci.c b/src/hci.c index 5d8b6d27d..ee1767215 100644 --- a/src/hci.c +++ b/src/hci.c @@ -1445,9 +1445,8 @@ static void event_handler(uint8_t *packet, int size){ switch (hci_event_packet_get_type(packet)) { case HCI_EVENT_COMMAND_COMPLETE: - // get num cmd packets - // log_info("HCI_EVENT_COMMAND_COMPLETE cmds old %u - new %u", hci_stack->num_cmd_packets, packet[2]); - hci_stack->num_cmd_packets = packet[2]; + // get num cmd packets - limit to 1 to reduce complexity + hci_stack->num_cmd_packets = packet[2] ? 1 : 0; if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_read_local_name)){ // terminate, name 248 chars @@ -1524,10 +1523,6 @@ static void event_handler(uint8_t *packet, int size){ hci_stack->manufacturer = little_endian_read_16(packet, 10); // hci_stack->lmp_subversion = little_endian_read_16(packet, 12); log_info("Manufacturer: 0x%04x", hci_stack->manufacturer); - // notify app - if (hci_stack->local_version_information_callback){ - hci_stack->local_version_information_callback(packet); - } } if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_read_local_supported_commands)){ hci_stack->local_supported_commands[0] = @@ -1545,9 +1540,8 @@ static void event_handler(uint8_t *packet, int size){ break; case HCI_EVENT_COMMAND_STATUS: - // get num cmd packets - // log_info("HCI_EVENT_COMMAND_STATUS cmds - old %u - new %u", hci_stack->num_cmd_packets, packet[3]); - hci_stack->num_cmd_packets = packet[3]; + // get num cmd packets - limit to 1 to reduce complexity + hci_stack->num_cmd_packets = packet[3] ? 1 : 0; break; case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:{ @@ -3069,11 +3063,8 @@ void gap_ssp_set_auto_accept(int auto_accept){ } #endif -/** - * pre: numcmds >= 0 - it's allowed to send a command to the controller - */ -int hci_send_cmd(const hci_cmd_t *cmd, ...){ - +// va_list part of hci_send_cmd +int hci_send_cmd_va_arg(const hci_cmd_t *cmd, va_list argptr){ if (!hci_can_send_command_packet_now()){ log_error("hci_send_cmd called but cannot send packet now"); return 0; @@ -3085,13 +3076,19 @@ int hci_send_cmd(const hci_cmd_t *cmd, ...){ hci_reserve_packet_buffer(); uint8_t * packet = hci_stack->hci_packet_buffer; + uint16_t size = hci_cmd_create_from_template(packet, cmd, argptr); + return hci_send_cmd_packet(packet, size); +} +/** + * pre: numcmds >= 0 - it's allowed to send a command to the controller + */ +int hci_send_cmd(const hci_cmd_t *cmd, ...){ va_list argptr; va_start(argptr, cmd); - uint16_t size = hci_cmd_create_from_template(packet, cmd, argptr); + int res = hci_send_cmd_va_arg(cmd, argptr); va_end(argptr); - - return hci_send_cmd_packet(packet, size); + return res; } // Create various non-HCI events. @@ -3773,14 +3770,6 @@ void hci_set_hardware_error_callback(void (*fn)(uint8_t error)){ hci_stack->hardware_error_callback = fn; } -/** - * @brief Set callback for local information from Bluetooth controller right after HCI Reset - * @note Can be used to select chipset driver dynamically during startup - */ -void hci_set_local_version_information_callback(void (*fn)(uint8_t * local_version_information)){ - hci_stack->local_version_information_callback = fn; -} - void hci_disconnect_all(void){ btstack_linked_list_iterator_t it; btstack_linked_list_iterator_init(&it, &hci_stack->connections); diff --git a/src/hci.h b/src/hci.h index d59c962d5..b7ef7f472 100644 --- a/src/hci.h +++ b/src/hci.h @@ -620,9 +620,6 @@ typedef struct { /* callbacks for events */ btstack_linked_list_t event_handlers; - // local version information callback - void (*local_version_information_callback)(uint8_t * local_version_information); - // hardware error callback void (*hardware_error_callback)(uint8_t error); @@ -774,12 +771,6 @@ void hci_set_link_key_db(btstack_link_key_db_t const * link_key_db); */ void hci_set_hardware_error_callback(void (*fn)(uint8_t error)); -/** - * @brief Set callback for local information from Bluetooth controller right after HCI Reset - * @note Can be used to select chipset driver dynamically during startup - */ -void hci_set_local_version_information_callback(void (*fn)(uint8_t * local_version_information)); - /** * @brief Set Public BD ADDR - passed on to Bluetooth chipset during init if supported in bt_control_h */ @@ -900,6 +891,10 @@ void hci_release_packet_buffer(void); /* API_END */ +/** + * va_list version of hci_send_cmd + */ +int hci_send_cmd_va_arg(const hci_cmd_t *cmd, va_list argtr); /** * Get connection iterator. Only used by l2cap.c and sm.c diff --git a/src/hci_dump.c b/src/hci_dump.c index db6e52c64..90c18a5ff 100644 --- a/src/hci_dump.c +++ b/src/hci_dump.c @@ -62,7 +62,6 @@ #include #include // for timestamps #include // for mode flags -#include // for va_list #endif // BLUEZ hcidump - struct not used directly, but left here as documentation @@ -265,19 +264,24 @@ static int hci_dump_log_level_active(int log_level){ return log_level_enabled[log_level]; } +void hci_dump_log_va_arg(int log_level, const char * format, va_list argptr){ + if (hci_dump_log_level_active(log_level)) { +#ifdef HAVE_POSIX_FILE_IO + int len = vsnprintf(log_message_buffer, sizeof(log_message_buffer), format, argptr); + hci_dump_packet(LOG_MESSAGE_PACKET, 0, (uint8_t*) log_message_buffer, len); +#else + printf_timestamp(); + printf("LOG -- "); + vprintf(format, argptr); + printf("\n"); +#endif + } +} + void hci_dump_log(int log_level, const char * format, ...){ - if (!hci_dump_log_level_active(log_level)) return; va_list argptr; va_start(argptr, format); -#ifdef HAVE_POSIX_FILE_IO - int len = vsnprintf(log_message_buffer, sizeof(log_message_buffer), format, argptr); - hci_dump_packet(LOG_MESSAGE_PACKET, 0, (uint8_t*) log_message_buffer, len); -#else - printf_timestamp(); - printf("LOG -- "); - vprintf(format, argptr); - printf("\n"); -#endif + hci_dump_log_va_arg(log_level, format, argptr); va_end(argptr); } diff --git a/src/hci_dump.h b/src/hci_dump.h index c5a58d966..c7deb7abc 100644 --- a/src/hci_dump.h +++ b/src/hci_dump.h @@ -47,6 +47,7 @@ #define __HCI_DUMP_H #include +#include // for va_list #ifdef __AVR__ #include @@ -104,6 +105,8 @@ void hci_dump_close(void); /* API_END */ +void hci_dump_log_va_arg(int log_level, const char * format, va_list argtr); + #ifdef __AVR__ void hci_dump_log_P(int log_level, PGM_P format, ...); #endif diff --git a/src/l2cap.c b/src/l2cap.c index 9d4beae8b..9a542b26c 100644 --- a/src/l2cap.c +++ b/src/l2cap.c @@ -219,11 +219,9 @@ void l2cap_release_packet_buffer(void){ hci_release_packet_buffer(); } -static void l2cap_setup_header(uint8_t * acl_buffer, hci_con_handle_t con_handle, uint16_t remote_cid, uint16_t len){ - int pb = hci_non_flushable_packet_boundary_flag_supported() ? 0x00 : 0x02; - +static void l2cap_setup_header(uint8_t * acl_buffer, hci_con_handle_t con_handle, uint8_t packet_boundary, uint16_t remote_cid, uint16_t len){ // 0 - Connection handle : PB=pb : BC=00 - little_endian_store_16(acl_buffer, 0, con_handle | (pb << 12) | (0 << 14)); + little_endian_store_16(acl_buffer, 0, con_handle | (packet_boundary << 12) | (0 << 14)); // 2 - ACL length little_endian_store_16(acl_buffer, 2, len + 4); // 4 - L2CAP packet length @@ -232,6 +230,7 @@ static void l2cap_setup_header(uint8_t * acl_buffer, hci_con_handle_t con_handle little_endian_store_16(acl_buffer, 6, remote_cid); } +// assumption - only on LE connections int l2cap_send_prepared_connectionless(hci_con_handle_t con_handle, uint16_t cid, uint16_t len){ if (!hci_is_packet_buffer_reserved()){ @@ -247,11 +246,12 @@ int l2cap_send_prepared_connectionless(hci_con_handle_t con_handle, uint16_t cid log_debug("l2cap_send_prepared_connectionless handle %u, cid 0x%02x", con_handle, cid); uint8_t *acl_buffer = hci_get_outgoing_packet_buffer(); - l2cap_setup_header(acl_buffer, con_handle, cid, len); + l2cap_setup_header(acl_buffer, con_handle, 0, cid, len); // send return hci_send_acl_packet_buffer(len+8); } +// assumption - only on LE connections int l2cap_send_connectionless(hci_con_handle_t con_handle, uint16_t cid, uint8_t *data, uint16_t len){ if (!hci_can_send_acl_packet_now(con_handle)){ @@ -449,6 +449,7 @@ static int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_ return hci_send_acl_packet_buffer(len); } +// assumption - only on Classic connections int l2cap_send_prepared(uint16_t local_cid, uint16_t len){ if (!hci_is_packet_buffer_reserved()){ @@ -469,12 +470,15 @@ int l2cap_send_prepared(uint16_t local_cid, uint16_t len){ log_debug("l2cap_send_prepared cid 0x%02x, handle %u, 1 credit used", local_cid, channel->con_handle); + // set non-flushable packet boundary flag if supported on Controller uint8_t *acl_buffer = hci_get_outgoing_packet_buffer(); - l2cap_setup_header(acl_buffer, channel->con_handle, channel->remote_cid, len); + uint8_t packet_boundary_flag = hci_non_flushable_packet_boundary_flag_supported() ? 0x00 : 0x02; + l2cap_setup_header(acl_buffer, channel->con_handle, packet_boundary_flag, channel->remote_cid, len); // send return hci_send_acl_packet_buffer(len+8); } +// assumption - only on Classic connections int l2cap_send(uint16_t local_cid, uint8_t *data, uint16_t len){ l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid); @@ -812,7 +816,7 @@ static void l2cap_run(void){ memcpy(&l2cap_payload[pos], &channel->send_sdu_buffer[channel->send_sdu_pos-2], payload_size); // -2 for virtual SDU len pos += payload_size; channel->send_sdu_pos += payload_size; - l2cap_setup_header(acl_buffer, channel->con_handle, channel->remote_cid, pos); + l2cap_setup_header(acl_buffer, channel->con_handle, 0, channel->remote_cid, pos); // done channel->credits_outgoing--; diff --git a/tool/btstack_rtos_generator.py b/tool/btstack_rtos_generator.py new file mode 100755 index 000000000..6c85acced --- /dev/null +++ b/tool/btstack_rtos_generator.py @@ -0,0 +1,421 @@ +#!/usr/bin/env python +import os, sys, getopt, re, pickle + +copyright = """/* + * Copyright (C) 2016 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ +""" + +single_hfile_header_begin = """ + +/* + * btstack_rtos.h + * + * @brief BTstack Wrapper for use with Real-Time OS + * Wraps each public BTstack function into a thread-safe version + * + * @note Don't edit - generated by tool/btstack_rtos_generator.py + * + */ + +#ifndef __BTSTACK_RTOS_H +#define __BTSTACK_RTOS_H + +#if defined __cplusplus +extern "C" { +#endif + +#include "btstack_config.h" + +#ifndef BTSTACK_RTOS_ENTER +#error Please define BTSTACK_RTOS_ENTER that locks a recursive mutex when using the RTOS wrapper btstack_rtos.h +#endif + +#ifndef BTSTACK_RTOS_EXIT +#error Please define BTSTACK_RTOS_EXIT that releases a recursive mutex when using the RTOS wrapper btstack_rtos.h +#endif + +/* API_START */ + + +""" + +single_hfile_api_header = """ +#include "API_NAME" +""" + +single_hfile_header_end = """ + +/* API_END */ + +#if defined __cplusplus +} +#endif + +#endif // __BTSTACK_RTOS_H +""" + +multiple_header_begin = """ + +/* + * FILENAME + * + * @brief BTstack Wrapper for use with Real-Time OS + * Wraps each public BTstack function into a thread-safe version + * + * @note Don't edit - generated by tool/btstack_rtos_generator.py + * + */ + +#ifndef GUARD +#define GUARD + +#if defined __cplusplus +extern "C" { +#endif + +#include "btstack_config.h" +#include "HEADER" + +#ifndef BTSTACK_RTOS_ENTER +#error Please define BTSTACK_RTOS_ENTER that locks a recursive mutex when using the RTOS wrapper btstack_rtos.h +#endif + +#ifndef BTSTACK_RTOS_EXIT +#error Please define BTSTACK_RTOS_EXIT that releases a recursive mutex when using the RTOS wrapper btstack_rtos.h +#endif + +/* API_START */ + + +""" + +multiple_header_end = """ + +/* API_END */ + +#if defined __cplusplus +} +#endif + +#endif // GUARD +""" + +class State: + SearchStartAPI = 0 + SearchEndAPI = 1 + DoneAPI = 2 + + +num_functions = 0 + +# [file_name, api_title, api_label] +apis = [ + ["src/ble/ancs_client.h", "BLE ANCS Client", "ancsClient", True], + ["src/ble/att_db_util.h", "BLE ATT Database", "attDb", True], + ["src/ble/att_server.h", "BLE ATT Server", "attServer", True], + ["src/ble/gatt_client.h", "BLE GATT Client", "gattClient", True], + ["src/ble/le_device_db.h", "BLE Device Database", "leDeviceDb", True], + ["src/ble/sm.h", "BLE Security Manager", "sm", True], + + ["src/classic/bnep.h", "BNEP", "bnep", True], + ["src/classic/btstack_link_key_db.h","Link Key DB","lkDb", True], + ["src/classic/hsp_hs.h","HSP Headset","hspHS", True], + ["src/classic/hsp_ag.h","HSP Audio Gateway","hspAG", True], + ["src/classic/hfp_hf.h","HFP Hands-Free","hfpHF", True], + ["src/classic/hfp_ag.h","HFP Audio Gateway","hfpAG", True], + ["src/classic/pan.h", "PAN", "pan", True], + ["src/classic/rfcomm.h", "RFCOMM", "rfcomm", True], + ["src/classic/sdp_client.h", "SDP Client", "sdpClient", True], + ["src/classic/sdp_client_rfcomm.h", "SDP RFCOMM Query", "sdpQueries", True], + ["src/classic/sdp_server.h", "SDP Server", "sdpSrv", True], + ["src/classic/sdp_util.h","SDP Utils", "sdpUtil", True], + + ["src/ad_parser.h", "BLE Advertisements Parser", "advParser", False], + # ["src/btstack_chipset.h","BTstack Chipset","btMemory", True], + # ["src/btstack_control.h","BTstack Hardware Control","btControl", True], + ["src/btstack_event.h","HCI Event Getter","btEvent", False], + # ["src/btstack_memory.h","BTstack Memory Management","btMemory", True], + ["src/btstack_linked_list.h","BTstack Linked List","btList", False], + ["src/btstack_run_loop.h", "Run Loop", "runLoop", True], + ["src/btstack_util.h", "Common Utils", "btUtil", False], + ["src/gap.h", "GAP", "gap", True], + ["src/hci.h", "HCI", "hci", True], + ["src/hci_dump.h","HCI Logging","hciTrace", True], + # ["src/hci_transport.h","HCI Transport","hciTransport", True], + ["src/l2cap.h", "L2CAP", "l2cap", True], +] + +def split_arguments(args_string): + args = [] + brace_level = 0 + arg = '' + for c in args_string: + if c == '(': + brace_level += 1 + if c == ')': + brace_level -= 1 + if c == ',' and brace_level == 0: + args.append(arg) + arg = '' + continue + arg = arg + c + if len(arg): + args.append(arg) + return args + +def argument_name(parameter): + function_pointer = re.match('[\w\s\*]*\(\s*\*(\w*)\s*\)\(.*\)', parameter) + if function_pointer: + return function_pointer.group(1) + parts = parameter.split(' ') + filtered_parts = [part for part in parts if part not in ['']] + arg = filtered_parts[len(filtered_parts)-1].replace('*','').replace('[]','') + # le_device_db_encryption_set(index, ediv, rand[8], ltk, key_size, authenticated, authorized); + if arg == 'rand[8]': + arg = 'rand' + return arg + +def create_wrapper(fout, type_and_name, arg_string, need_lock): + global num_functions + + parts = type_and_name.split(' ') + filtered_parts = [part for part in parts if part not in ['static','inline','']] + name = filtered_parts[len(filtered_parts)-1] + return_type = ' '.join(filtered_parts[:-1]) + # handle *function_name + if name.startswith('*'): + name = name[1:] + return_type = return_type + ' *' + rtos_name = "rtos_" + name + is_void_function = len(filtered_parts) == 2 and filtered_parts[0] == "void" + args = split_arguments(arg_string) + call = [] + is_ellipse_function = False + if len(args)!= 1 or args[0] != 'void': + for arg in args: + call_arg = argument_name(arg) + if call_arg == '...': + is_ellipse_function = True + call.append('argptr') + name += '_va_arg' + else: + call.append(argument_name(arg)) + call_args = ', '.join(call) + fout.write('static inline ' + return_type + ' ' + rtos_name + '(' + ", ".join(args) + '){\n') + orig_call = name + '(' + call_args + ')' + if need_lock: + fout.write(' BTSTACK_RTOS_ENTER();\n') + if is_ellipse_function: + fout.write(' va_list argptr;\n') + fout.write(' va_start(argptr, %s);\n' % call[-2]) + if is_void_function: + fout.write(' ' + orig_call+';\n') + else: + fout.write(' ' + return_type + ' res = ' + orig_call + ';\n') + if is_ellipse_function: + fout.write(' va_end(argptr);\n') + fout.write(' BTSTACK_RTOS_EXIT();\n') + if not is_void_function: + fout.write(' return res;\n') + else: + if is_void_function: + fout.write(' ' + orig_call+';\n') + else: + fout.write(' return ' + orig_call + ';\n') + fout.write('}\n') + fout.write('\n') + num_functions += 1 + +def write_wrappers_for_file(fout, file, header_name, need_lock): + with open(file, 'rb') as fin: + typedefFound = 0 + multiline_function_def = 0 + multiline = '' + multiline_comment = 0 + inline_function = 0 + state = State.SearchStartAPI + + for line in fin: + if state == State.DoneAPI: + continue + + if state == State.SearchStartAPI: + parts = re.match('.*API_START.*',line) + if parts: + state = State.SearchEndAPI + continue + + if state == State.SearchEndAPI: + parts = re.match('.*API_END.*',line) + if parts: + state = State.DoneAPI + continue + + if inline_function: + function_end = re.match('.*}.*', line) + if function_end: + inline_function = 0 + continue + + if multiline_function_def: + multiline += line + function_end = re.match('.*\)', line) + if function_end: + multiline_function_def = 0 + function = re.match('([\w\s\*]*)\(([\w\s,\*]*)\).*', multiline) + if function: + type_and_name = function.group(1) + arg_string = function.group(2) + create_wrapper(fout, type_and_name, arg_string, need_lock) + continue + + if multiline_comment: + comment_end = re.match('.*\*/.*', line) + if comment_end: + multiline_comment = 0 + fout.write(line) + continue + + # search typedef struct end + if typedefFound: + typedef = re.match('}\s*(.*);\n', line) + if typedef: + typedefFound = 0 + continue + + # search comment line + comment = re.match(".*/\*.*\*/.*", line) + if comment: + fout.write(line) + continue + + # search start of multi line comment + comment = re.match(".*/\*", line) + if comment: + fout.write(line) + multiline_comment = 1 + continue + + # ignore __attribute__ for hci_dump_log in src/hci_dump.h + param = re.match(".*__attribute__", line) + if param: + continue + + # search typedef struct begin + typedef = re.match('.*typedef\s+struct.*', line) + if typedef: + typedefFound = 1 + + # complete function declaration + function = re.match('([\w\s\*]*)\((.*)\).*', line) + if function: + if "return" in line: + continue + type_and_name = function.group(1) + arg_string = function.group(2) + create_wrapper(fout, type_and_name, arg_string, need_lock) + inline_function = 'inline' in line; + continue + + # multi-line function declaration + function = re.match('([\w\s\*]*)\((.*).*', line) + if function: + multiline = line + multiline_function_def = 1 + continue + + # fout.write(single_hfile_header_begin) + + +def create_wrapper_file(btstack_root, apis, wrapper_file): + with open(wrapper_file, 'w') as fout: + fout.write(copyright) + fout.write(single_hfile_header_begin) + + for api_tuple in apis: + api_filename = btstack_root + "/" + api_tuple[0] + need_lock = api_tuple[3] + header_file = api_tuple[0].replace('src/','') + fout.write(single_hfile_api_header.replace("API_NAME", header_file)) + write_wrappers_for_file(fout, api_filename, header_file, need_lock) + # fout.write(single_hfile_header_begin) + fout.write(single_hfile_header_end) + +def create_wrapper_files(btstack_root, rtos_folder, apis): + for api_tuple in apis: + api_filename = btstack_root + "/" + api_tuple[0] + need_lock = api_tuple[3] + header_file = api_tuple[0].replace('src/','') + path_parts = header_file.split('/') + path_parts[-1] = 'rtos_' + path_parts[-1] + rtos_file = '/'.join(path_parts) + wrapper_file = rtos_folder + '/' + rtos_file + # print('- %s' % wrapper_file) + with open(wrapper_file, 'w') as fout: + guard = '__' + rtos_file.replace('.','_').upper() + fout.write(copyright) + fout.write(multiple_header_begin.replace('FILENAME',rtos_file).replace('GUARD',guard).replace('HEADER',header_file)) + write_wrappers_for_file(fout, api_filename, header_file, need_lock) + fout.write(multiple_header_end.replace('GUARD',guard)) + +def assert_dir_exists(path): + if not os.path.exists(path): + os.makedirs(path) + +def main(argv): + btstack_root = os.path.abspath(os.path.dirname(sys.argv[0]) + '/..') + print ('BTstack folder is: %s' % btstack_root) + + # single file + # gen_path = btstack_root + '/src/btstack_rtos.h' + # print ('Generating RTOS wrapper %s' % gen_path) + # create_wrapper_file(btstack_root, apis, gen_path) + + # individual files in platform/rtos + print ('Generating RTOS wrappers...') + rtos_folder = btstack_root + '/platform/rtos' + assert_dir_exists(rtos_folder) + assert_dir_exists(rtos_folder+'/ble') + assert_dir_exists(rtos_folder+'/classic') + create_wrapper_files(btstack_root, rtos_folder, apis) + + # summary + print ('Number wrapped headers: %u' % len(apis)) + print ('Number wrapped functions: %u' % num_functions) + +if __name__ == "__main__": + main(sys.argv[1:])