Merge branch 'develop' into windows-h4

This commit is contained in:
Matthias Ringwald 2016-12-19 15:28:16 +01:00
commit 5c7fd12999
27 changed files with 1080 additions and 316 deletions

View File

@ -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 <a href="mailto:contact@bluekitchen-gmbh.com">contact us</a>.
## Evaluation Platforms
#### Embedded Platforms:

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -50,9 +50,21 @@ extern "C" {
#include <stdint.h>
#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

View File

@ -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 <stdint.h>\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')

View File

@ -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)

View File

@ -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

View File

@ -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 <portaudio.h>
#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<num_samples; i++){
@ -160,6 +163,7 @@ static void sco_demo_sine_wave_int16(int num_samples, int16_t * data){
}
}
}
static int num_audio_frames = 0;
static void sco_demo_fill_audio_frame(void){
if (!hfp_msbc_can_encode_audio_frame_now()) return;
@ -169,7 +173,6 @@ static void sco_demo_fill_audio_frame(void){
hfp_msbc_encode_audio_frame(sample_buffer);
num_audio_frames++;
}
#ifdef SCO_WAV_FILENAME
static btstack_sbc_decoder_state_t decoder_state;
static btstack_cvsd_plc_state_t cvsd_plc_state;
@ -343,6 +346,7 @@ static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
// memcpy(audio_frame_out, (int8_t*)(packet+3), 24);
btstack_cvsd_plc_process_data(&cvsd_plc_state, (int8_t *)(packet+3), num_samples, audio_frame_out);
// int8_t * audio_frame_out = (int8_t*)&packet[3];
wav_writer_write_int8(samples_to_write, audio_frame_out);
num_samples_to_write -= samples_to_write;
@ -459,7 +463,8 @@ void sco_demo_init(void){
#endif
}
static void sco_report(void){
void sco_report(void);
void sco_report(void){
printf("SCO: sent %u, received %u\n", count_sent, count_received);
}
@ -494,16 +499,32 @@ void sco_demo_send(hci_con_handle_t sco_handle){
} else {
sco_demo_sine_wave_int8(audio_samples_per_packet, (int8_t *) (sco_packet+3));
}
#else
#endif
#if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
memset(&sco_packet[3], phase++, audio_samples_per_packet);
if (phase > 'z') phase = 'a';
#else
#endif
#if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
int j;
for (j=0;j<audio_samples_per_packet;j++){
sco_packet[3+j] = phase++;
}
#endif
#if SCO_DEMO_MODE == SCO_DEMO_MODE_55
int j;
for (j=0;j<audio_samples_per_packet;j++){
// sco_packet[3+j] = j & 1 ? 0x35 : 0x53;
sco_packet[3+j] = 0x55;
}
#endif
#if SCO_DEMO_MODE == SCO_DEMO_MODE_00
int j;
for (j=0;j<audio_samples_per_packet;j++){
sco_packet[3+j] = 0x00;
}
// additional hack
// big_endian_store_16(sco_packet, 5, phase++);
(void) phase;
#endif
hci_send_sco_packet_buffer(sco_packet_length);
@ -512,19 +533,41 @@ void sco_demo_send(hci_con_handle_t sco_handle){
hci_request_sco_can_send_now_event();
count_sent++;
#if SCO_DEMO_MODE != SCO_DEMO_MODE_55
if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
#endif
}
/**
* @brief Process received data
*/
#define ANSI_COLOR_RED "\x1b[31m"
#define ANSI_COLOR_GREEN "\x1b[32m"
#define ANSI_COLOR_YELLOW "\x1b[33m"
#define ANSI_COLOR_BLUE "\x1b[34m"
#define ANSI_COLOR_MAGENTA "\x1b[35m"
#define ANSI_COLOR_CYAN "\x1b[36m"
#define ANSI_COLOR_RESET "\x1b[0m"
void sco_demo_receive(uint8_t * packet, uint16_t size){
dump_data = 1;
count_received++;
// if ((count_received % SCO_REPORT_PERIOD) == 0) sco_report();
static uint32_t packets = 0;
static uint32_t crc_errors = 0;
static uint32_t data_received = 0;
static uint32_t byte_errors = 0;
data_received += size - 3;
packets++;
if (data_received > 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;i<size;i++){
printf("%c", packet[i]);
}
printf("\n");
dump_data = 0;
#else
printf_hexdump(&packet[3], size-3);
#endif
#if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
// colored hexdump with expected
static uint8_t expected_byte = 0;
int i;
printf("data: ");
for (i=3;i<size;i++){
if (packet[i] != expected_byte){
printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
} else {
printf("%02x ", packet[i]);
}
expected_byte = packet[i]+1;
}
printf("\n");
#endif
#if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE_00
int i;
int contains_error = 0;
for (i=3;i<size;i++){
if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
contains_error = 1;
byte_errors++;
}
}
if (contains_error){
printf("data: ");
for (i=0;i<3;i++){
printf("%02x ", packet[i]);
}
for (i=3;i<size;i++){
if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
} else {
printf("%02x ", packet[i]);
}
}
printf("\n");
}
#endif
}
}

View File

@ -160,6 +160,7 @@ static uint8_t sco_ring_buffer[SCO_RING_BUFFER_SIZE];
static int sco_ring_write; // packet idx
static int sco_ring_transfers_active;
static struct libusb_transfer *sco_ring_transfers[SCO_RING_BUFFER_COUNT];
static int sco_ring_transfers_in_flight[SCO_RING_BUFFER_COUNT];
#endif
// outgoing buffer for HCI Command packets
@ -235,8 +236,8 @@ static void queue_transfer(struct libusb_transfer *transfer){
LIBUSB_CALL static void async_callback(struct libusb_transfer *transfer){
// identify and free transfers as part of shutdown
int c;
if (libusb_state != LIB_USB_TRANSFERS_ALLOCATED) {
int c;
for (c=0;c<ASYNC_BUFFERS;c++){
if (transfer == event_in_transfer[c]){
libusb_free_transfer(transfer);
@ -257,10 +258,27 @@ LIBUSB_CALL static void async_callback(struct libusb_transfer *transfer){
return;
}
}
for (c=0;c<SCO_RING_BUFFER_COUNT;c++){
if (transfer == sco_ring_transfers[c]){
sco_ring_transfers_in_flight[c] = 0;
libusb_free_transfer(transfer);
sco_ring_transfers[c] = 0;
return;
}
}
#endif
return;
}
for (c=0;c<SCO_RING_BUFFER_COUNT;c++){
if (transfer == sco_ring_transfers[c]){
sco_ring_transfers_in_flight[c] = 0;
}
}
int r;
// log_info("begin async_callback endpoint %x, status %x, actual length %u", transfer->endpoint, 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);

View File

@ -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

View File

@ -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){

View File

@ -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

View File

@ -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){

View File

@ -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 <bluetooth/buf.h>
#include <bluetooth/hci_raw.h>
+#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;

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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
}

View File

@ -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);

View File

@ -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

View File

@ -62,7 +62,6 @@
#include <time.h>
#include <sys/time.h> // for timestamps
#include <sys/stat.h> // for mode flags
#include <stdarg.h> // 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);
}

View File

@ -47,6 +47,7 @@
#define __HCI_DUMP_H
#include <stdint.h>
#include <stdarg.h> // for va_list
#ifdef __AVR__
#include <avr/pgmspace.h>
@ -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

View File

@ -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--;

421
tool/btstack_rtos_generator.py Executable file
View File

@ -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:])