port/qt-usb: port of libusb as qt console application

This commit is contained in:
Matthias Ringwald 2020-02-21 18:04:23 +01:00
parent 656e09c914
commit 1b464e99af
7 changed files with 913 additions and 0 deletions

View File

@ -0,0 +1,210 @@
/*
* Copyright (C) 2019 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
*
*/
#define BTSTACK_FILE__ "btstack_run_loop_qt.c"
/*
* btstack_run_loop_qt.c
*/
// enable POSIX functions (needed for -std=c99)
#define _POSIX_C_SOURCE 200809
#include "btstack_run_loop_qt.h"
#include "btstack_run_loop.h"
#include "btstack_run_loop_base.h"
#include "btstack_util.h"
#include "btstack_linked_list.h"
#include "btstack_debug.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
static void btstack_run_loop_qt_dump_timer(void);
// start time. tv_usec/tv_nsec = 0
#ifdef _POSIX_MONOTONIC_CLOCK
// use monotonic clock if available
static struct timespec init_ts;
#else
// fallback to gettimeofday
static struct timeval init_tv;
#endif
static BTstackRunLoopQt * btstack_run_loop_object;
#ifdef _POSIX_MONOTONIC_CLOCK
/**
* @brief Returns the timespec which represents the time(stop - start). It might be negative
*/
static void timespec_diff(struct timespec *start, struct timespec *stop, struct timespec *result){
result->tv_sec = stop->tv_sec - start->tv_sec;
if ((stop->tv_nsec - start->tv_nsec) < 0) {
result->tv_sec = stop->tv_sec - start->tv_sec - 1;
result->tv_nsec = stop->tv_nsec - start->tv_nsec + 1000000000;
} else {
result->tv_sec = stop->tv_sec - start->tv_sec;
result->tv_nsec = stop->tv_nsec - start->tv_nsec;
}
}
/**
* @brief Convert timespec to miliseconds, might overflow
*/
static uint64_t timespec_to_milliseconds(struct timespec *a){
uint64_t ret = 0;
uint64_t sec_val = (uint64_t)(a->tv_sec);
uint64_t nsec_val = (uint64_t)(a->tv_nsec);
ret = (sec_val*1000) + (nsec_val/1000000);
return ret;
}
/**
* @brief Returns the milisecond value of (stop - start). Might overflow
*/
static uint64_t timespec_diff_milis(struct timespec* start, struct timespec* stop){
struct timespec diff_ts;
timespec_diff(start, stop, &diff_ts);
return timespec_to_milliseconds(&diff_ts);
}
#endif
/**
* @brief Queries the current time in ms since start
*/
static uint32_t btstack_run_loop_qt_get_time_ms(void){
uint32_t time_ms;
#ifdef _POSIX_MONOTONIC_CLOCK
struct timespec now_ts;
clock_gettime(CLOCK_MONOTONIC, &now_ts);
time_ms = (uint32_t) timespec_diff_milis(&init_ts, &now_ts);
#else
struct timeval tv;
gettimeofday(&tv, NULL);
time_ms = (uint32_t) ((tv.tv_sec - init_tv.tv_sec) * 1000) + (tv.tv_usec / 1000);
#endif
return time_ms;
}
/**
* Execute run_loop
*/
static void btstack_run_loop_qt_execute(void) {
}
// set timer
static void btstack_run_loop_qt_set_timer(btstack_timer_source_t *a, uint32_t timeout_in_ms){
uint32_t time_ms = btstack_run_loop_qt_get_time_ms();
a->timeout = time_ms + timeout_in_ms;
log_debug("btstack_run_loop_qt_set_timer to %u ms (now %u, timeout %u)", a->timeout, time_ms, timeout_in_ms);
}
/**
* Add timer to run_loop (keep list sorted)
*/
static void btstack_run_loop_qt_add_timer(btstack_timer_source_t *ts){
uint32_t now = btstack_run_loop_qt_get_time_ms();
int32_t next_timeout_before = btstack_run_loop_base_get_time_until_timeout(now);
btstack_run_loop_base_add_timer(ts);
int32_t next_timeout_after = btstack_run_loop_base_get_time_until_timeout(now);
if (next_timeout_after >= 0 && (next_timeout_after != next_timeout_before)){
QTimer::singleShot((uint32_t)next_timeout_after, btstack_run_loop_object, SLOT(processTimers()));
}
}
// BTstackRunLoopQt class implementation
void BTstackRunLoopQt::processTimers(){
uint32_t now = btstack_run_loop_qt_get_time_ms();
int32_t next_timeout_before = btstack_run_loop_base_get_time_until_timeout(now);
btstack_run_loop_base_process_timers(btstack_run_loop_qt_get_time_ms());
int32_t next_timeout_after = btstack_run_loop_base_get_time_until_timeout(now);
if (next_timeout_after >= 0 && (next_timeout_after != next_timeout_before)){
QTimer::singleShot((uint32_t)next_timeout_after, this, SLOT(processTimers()));
}
}
static void btstack_run_loop_qt_init(void){
btstack_run_loop_base_init();
btstack_run_loop_object = new BTstackRunLoopQt();
#ifdef _POSIX_MONOTONIC_CLOCK
clock_gettime(CLOCK_MONOTONIC, &init_ts);
init_ts.tv_nsec = 0;
#else
// just assume that we started at tv_usec == 0
gettimeofday(&init_tv, NULL);
init_tv.tv_usec = 0;
#endif
}
static void btstack_run_loop_qt_dump_timer(void){
btstack_linked_item_t *it;
int i = 0;
for (it = (btstack_linked_item_t *) btstack_run_loop_base_timers; it ; it = it->next){
btstack_timer_source_t *ts = (btstack_timer_source_t*) it;
log_info("timer %u (%p): timeout %u\n", i, ts, ts->timeout);
}
}
static const btstack_run_loop_t btstack_run_loop_qt = {
&btstack_run_loop_qt_init,
&btstack_run_loop_base_add_data_source,
&btstack_run_loop_base_remove_data_source,
&btstack_run_loop_base_enable_data_source_callbacks,
&btstack_run_loop_base_disable_data_source_callbacks,
&btstack_run_loop_qt_set_timer,
&btstack_run_loop_qt_add_timer,
&btstack_run_loop_base_remove_timer,
&btstack_run_loop_qt_execute,
&btstack_run_loop_qt_dump_timer,
&btstack_run_loop_qt_get_time_ms,
};
/**
* Provide btstack_run_loop_posix instance
*/
const btstack_run_loop_t * btstack_run_loop_qt_get_instance(void){
return &btstack_run_loop_qt;
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (C) 2019 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
*
*/
/*
* btstack_run_loop_qt.h
* Functionality special to the Qt event loop
*/
#ifndef btstack_run_loop_QT_H
#define btstack_run_loop_QT_H
#include "btstack_run_loop.h"
// BTstack Run Loop Object for Qt integration
#if defined __cplusplus
#include <QObject>
#include <QTimer>
class BTstackRunLoopQt : public QObject {
Q_OBJECT
public slots:
void processTimers(void);
};
#endif
#if defined __cplusplus
extern "C" {
#endif
/**
* Provide btstack_run_loop_qt instance
*/
const btstack_run_loop_t * btstack_run_loop_qt_get_instance(void);
/* API_END */
#if defined __cplusplus
}
#endif
#endif // btstack_run_loop_QT_H

74
port/qt-usb/.gitignore vendored Normal file
View File

@ -0,0 +1,74 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe
CMakeLists.txt.user

186
port/qt-usb/CMakeLists.txt Normal file
View File

@ -0,0 +1,186 @@
cmake_minimum_required(VERSION 3.5)
project(qt-usb LANGUAGES C CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
message("${Qt5_DIR}")
find_package(Qt5Core)
# BTstack Root
set(BTSTACK_ROOT "../..")
message("BTSTACK_ROOT: ${BTSTACK_ROOT}")
# add libusb
find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h PATH_SUFFIXES "include" "libusb" "libusb-1.0")
find_library(LIBUSB_LIBRARY NAMES usb-1.0 PATH_SUFFIXES "lib" "lib32" "lib64" "dylib")
get_filename_component(LIBUSB_LIBRARY_PATH ${LIBUSB_LIBRARY} DIRECTORY)
include_directories( ${LIBUSB_INCLUDE_DIR} )
link_directories( ${LIBUSB_LIBRARY_PATH} )
link_libraries( usb-1.0 )
# BTstack include
include_directories(${BTSTACK_ROOT}/3rd-party/micro-ecc)
include_directories(${BTSTACK_ROOT}/3rd-party/bluedroid/decoder/include)
include_directories(${BTSTACK_ROOT}/3rd-party/bluedroid/encoder/include)
include_directories(${BTSTACK_ROOT}/3rd-party/md5)
include_directories(${BTSTACK_ROOT}/3rd-party/hxcmod-player)
include_directories(${BTSTACK_ROOT}/3rd-party/hxcmod-player/mod)
include_directories(${BTSTACK_ROOT}/3rd-party/lwip/core/src/include)
include_directories(${BTSTACK_ROOT}/3rd-party/lwip/dhcp-server)
include_directories(${BTSTACK_ROOT}/3rd-party/rijndael)
include_directories(${BTSTACK_ROOT}/3rd-party/yxml)
include_directories(${BTSTACK_ROOT}/3rd-party/tinydir)
include_directories(${BTSTACK_ROOT}/src)
include_directories(${BTSTACK_ROOT}/platform/posix)
include_directories(${BTSTACK_ROOT}/platform/embedded)
include_directories(${BTSTACK_ROOT}/platform/lwip)
include_directories(${BTSTACK_ROOT}/platform/lwip/port)
include_directories(${BTSTACK_ROOT}/platform/qt)
include_directories(.)
# BTstack sources
file(GLOB SOURCES_SRC "${BTSTACK_ROOT}/src/*.c" "${BTSTACK_ROOT}/example/sco_demo_util.c")
file(GLOB SOURCES_BLE "${BTSTACK_ROOT}/src/ble/*.c")
file(GLOB SOURCES_GATT "${BTSTACK_ROOT}/src/ble/gatt-service/*.c")
file(GLOB SOURCES_CLASSIC "${BTSTACK_ROOT}/src/classic/*.c")
file(GLOB SOURCES_MESH "${BTSTACK_ROOT}/src/mesh/*.c")
file(GLOB SOURCES_BLUEDROID "${BTSTACK_ROOT}/3rd-party/bluedroid/encoder/srce/*.c" "${BTSTACK_ROOT}/3rd-party/bluedroid/decoder/srce/*.c")
file(GLOB SOURCES_MD5 "${BTSTACK_ROOT}/3rd-party/md5/md5.c")
file(GLOB SOURCES_UECC "${BTSTACK_ROOT}/3rd-party/micro-ecc/uECC.c")
file(GLOB SOURCES_YXML "${BTSTACK_ROOT}/3rd-party/yxml/yxml.c")
file(GLOB SOURCES_HXCMOD "${BTSTACK_ROOT}/3rd-party/hxcmod-player/*.c" "${BTSTACK_ROOT}/3rd-party/hxcmod-player/mods/*.c")
file(GLOB SOURCES_RIJNDAEL "${BTSTACK_ROOT}/3rd-party/rijndael/rijndael.c")
set(SOURCES_POSIX
# Adding btstac_uart_block.c causes weird link error, skip for now. QSerialPort might be used in btstack_uart_block_qt.cpp
# ${BTSTACK_ROOT}/platform/posix/btstack_uart_block.c
${BTSTACK_ROOT}/platform/posix/btstack_audio_portaudio.c
${BTSTACK_ROOT}/platform/posix/btstack_network_posix.c
${BTSTACK_ROOT}/platform/posix/btstack_stdin_posix.c
${BTSTACK_ROOT}/platform/posix/btstack_tlv_posix.c
${BTSTACK_ROOT}/platform/posix/wav_util.c
)
set(SOURCES_LIBUSB
${BTSTACK_ROOT}/platform/libusb/hci_transport_h2_libusb.c
)
set(LWIP_CORE_SRC
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/def.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/inet_chksum.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/init.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/ip.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/mem.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/memp.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/netif.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/pbuf.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/tcp.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/tcp_in.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/tcp_out.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/timeouts.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/udp.c
)
set (LWIP_IPV4_SRC
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/ipv4/acd.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/ipv4/dhcp.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/ipv4/etharp.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/ipv4/icmp.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/ipv4/ip4.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/ipv4/ip4_addr.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/core/ipv4/ip4_frag.c
)
set (LWIP_NETIF_SRC
${BTSTACK_ROOT}/3rd-party/lwip/core/src/netif/ethernet.c
)
set (LWIP_HTTPD
${BTSTACK_ROOT}/3rd-party/lwip/core/src/apps/http/altcp_proxyconnect.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/apps/http/fs.c
${BTSTACK_ROOT}/3rd-party/lwip/core/src/apps/http/httpd.c
)
set (LWIP_DHCPD
${BTSTACK_ROOT}/3rd-party/lwip/dhcp-server/dhserver.c
)
set (LWIP_PORT
${BTSTACK_ROOT}/platform/lwip/port/sys_arch.c
${BTSTACK_ROOT}/platform/lwip/bnep_lwip.c
)
set (SOURCES_LWIP ${LWIP_CORE_SRC} ${LWIP_IPV4_SRC} ${LWIP_NETIF_SRC} ${LWIP_HTTPD} ${LWIP_DHCPD} ${LWIP_PORT})
file(GLOB SOURCES_BLE_OFF "${BTSTACK_ROOT}/src/ble/le_device_db_memory.c")
list(REMOVE_ITEM SOURCES_BLE ${SOURCES_BLE_OFF})
set(SOURCES
${SOURCES_MD5}
${SOURCES_YXML}
${SOURCES_BLUEDROID}
${SOURCES_POSIX}
${SOURCES_RIJNDAEL}
${SOURCES_LIBUSB}
${SOURCES_SRC}
${SOURCES_BLE}
${SOURCES_GATT}
${SOURCES_MESH}
${SOURCES_CLASSIC}
${SOURCES_UECC}
${SOURCES_HXCMOD}
)
list(SORT SOURCES)
# create static lib
add_library(btstack-lib STATIC ${SOURCES})
# create targets for all examples
file(GLOB EXAMPLES_C "${BTSTACK_ROOT}/example/*.c")
list(SORT EXAMPLES_C)
file(GLOB EXAMPLES_GATT "${BTSTACK_ROOT}/example/*.gatt")
# remove some
file(GLOB EXAMPLES_OFF "${BTSTACK_ROOT}/example/sco_demo_util.c" "${BTSTACK_ROOT}/example/ant_test.c" "${BTSTACK_ROOT}/example/avrcp_browsing_client.c")
list(REMOVE_ITEM EXAMPLES_C ${EXAMPLES_OFF})
# on Mac 10.14, adding lwip to libstack results in a yet not understood link error
# workaround: add lwip sources only to lwip_examples
set (LWIP_EXAMPLES pan_lwip_http_server)
# create targets
foreach(EXAMPLE_FILE ${EXAMPLES_C})
get_filename_component(EXAMPLE ${EXAMPLE_FILE} NAME_WE)
set (SOURCE_FILES ${EXAMPLE_FILE})
# add qt main.cpp and run loop
list(APPEND SOURCE_FILES ${BTSTACK_ROOT}/platform/qt/btstack_run_loop_qt.cpp main.cpp)
# add lwip sources for lwip examples
if ( "${LWIP_EXAMPLES}" MATCHES ${EXAMPLE} )
list(APPEND SOURCE_FILES ${SOURCES_LWIP})
endif()
# add GATT DB creation
if ( "${EXAMPLES_GATT}" MATCHES ${EXAMPLE} )
message("example ${EXAMPLE} -- with GATT DB")
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${EXAMPLE}.h
COMMAND ${BTSTACK_ROOT}/tool/compile_gatt.py
ARGS ${BTSTACK_ROOT}/example/${EXAMPLE}.gatt ${CMAKE_CURRENT_BINARY_DIR}/${EXAMPLE}.h
)
list(APPEND SOURCE_FILES ${CMAKE_CURRENT_BINARY_DIR}/${EXAMPLE}.h)
# generated file does not need AUTOMOC and AUOUIC processing
set_property(SOURCE {CMAKE_CURRENT_BINARY_DIR}/${EXAMPLE}.h PROPERTY SKIP_AUTOGEN ON)
else()
message("example ${EXAMPLE}")
endif()
add_executable(${EXAMPLE} ${SOURCE_FILES} )
target_link_libraries(${EXAMPLE} btstack-lib Qt5::Core)
endforeach(EXAMPLE_FILE)

83
port/qt-usb/README.md Normal file
View File

@ -0,0 +1,83 @@
# BTstack Port for QT with libusb Library (Mac/Linux)
Windows or Embedded (bare metal) platforms not supported yet.
## Compilation
You'll need Qt and [libusb-1.0](http://libusb.info) or higher to be
installed.
When everything is ready, you can open the provided CMakelists.txt project in Qt Creator and run any of the provided examples.
See Qt documentation on how to compile on the command line or with other IDEs
## Environment Setup
### Linux
On Linux, the USB Bluetooth dongle is usually not accessible to a regular user. You can either:
- run the examples as root
- add a udev rule for your dongle to extend access rights to user processes
To add an udev rule, please create `/etc/udev/rules.d/btstack.rules` and add this
# Match all devices from CSR
SUBSYSTEM=="usb", ATTRS{idVendor}=="0a12", MODE="0666"
# Match DeLOCK Bluetooth 4.0 dongle
SUBSYSTEM=="usb", ATTRS{idVendor}=="0a5c", ATTRS{device}=="21e8", MODE="0666"
# Match Asus BT400
SUBSYSTEM=="usb", ATTRS{idVendor}=="0b05", ATTRS{device}=="17cb", MODE="0666"
# Match Laird BT860 / Cypress Semiconductor CYW20704A2
SUBSYSTEM=="usb", ATTRS{idVendor}=="04b4", ATTRS{device}=="f901", MODE="0666"
### macOS
On macOS, the OS will try to use a plugged-in Bluetooth Controller if one is available.
It's best to to tell the OS to always use the internal Bluetooth Contoller.
For this, execute:
sudo nvram bluetoothHostControllerSwitchBehavior=never
and then reboot to activate the change.
Note: if you get this error,
libusb: warning [darwin_open] USBDeviceOpen: another process has device opened for exclusive access
libusb: error [darwin_reset_device] ResetDevice: device not opened for exclusive access
and you didn't start another instance and you didn't assign the USB Controller to a virtual machine,
macOS uses the plugged-in Bluetooth Controller. Please configure NVRAM as explained and try again after a reboot.
## Running the examples
BTstack's HCI USB transport will try to find a suitable Bluetooth module and use it.
On start, BTstack will try to find a suitable Bluetooth module. It will also print the path to the packet log as well as the USB path.
$ ./le_counter
Packet Log: /tmp/hci_dump.pklg
BTstack counter 0001
USB Path: 06
BTstack up and running on 00:1A:7D:DA:71:13.
If you want to run multiple examples at the same time, it helps to fix the path to the used Bluetooth module by passing -u usb-path to the executable.
Example running le_streamer and le_streamer_client in two processes, using Bluetooth dongles at USB path 6 and 4:
./le_streamer -u 6
Specified USB Path: 06
Packet Log: /tmp/hci_dump_6.pklg
USB Path: 06
BTstack up and running on 00:1A:7D:DA:71:13.
To start the streaming, please run the le_streamer_client example on other device, or use some GATT Explorer, e.g. LightBlue, BLExplr.
$ ./le_streamer_client -u 4
Specified USB Path: 04
Packet Log: /tmp/hci_dump_4.pklg
USB Path: 04
BTstack up and running on 00:1A:7D:DA:71:13.
Start scanning!

View File

@ -0,0 +1,55 @@
//
// btstack_config.h for libusb port
//
#ifndef __BTSTACK_CONFIG
#define __BTSTACK_CONFIG
// Port related features
#define HAVE_MALLOC
#define HAVE_POSIX_FILE_IO
#define HAVE_BTSTACK_STDIN
#define HAVE_POSIX_TIME
// BTstack features that can be enabled
#define ENABLE_BLE
#define ENABLE_CLASSIC
#define ENABLE_HFP_WIDE_BAND_SPEECH
#define ENABLE_LE_CENTRAL
#define ENABLE_LE_PERIPHERAL
#define ENABLE_LE_SECURE_CONNECTIONS
#define ENABLE_LE_DATA_CHANNELS
#define ENABLE_MICRO_ECC_FOR_LE_SECURE_CONNECTIONS
#define ENABLE_LE_DATA_LENGTH_EXTENSION
#define ENABLE_ATT_DELAYED_RESPONSE
#define ENABLE_LOG_ERROR
#define ENABLE_LOG_INFO
#define ENABLE_SCO_OVER_HCI
#define ENABLE_SDP_DES_DUMP
#define ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
#define ENABLE_SOFTWARE_AES128
// BTstack configuration. buffers, sizes, ...
#define HCI_ACL_PAYLOAD_SIZE (1691 + 4)
#define HCI_INCOMING_PRE_BUFFER_SIZE 14 // sizeof BNEP header, avoid memcpy
#define NVM_NUM_DEVICE_DB_ENTRIES 20
// Mesh Configuration
#define ENABLE_MESH
#define ENABLE_MESH_ADV_BEARER
#define ENABLE_MESH_GATT_BEARER
#define ENABLE_MESH_PB_ADV
#define ENABLE_MESH_PB_GATT
#define ENABLE_MESH_PROXY_SERVER
#define ENABLE_MESH_PROVISIONER
#define MAX_NR_MESH_TRANSPORT_KEYS 16
#define MAX_NR_MESH_VIRTUAL_ADDRESSES 16
#define MAX_NR_MESH_SUBNETS 2
// allow for one NetKey update
#define MAX_NR_MESH_NETWORK_KEYS (MAX_NR_MESH_SUBNETS+1)
#endif

231
port/qt-usb/main.cpp Normal file
View File

@ -0,0 +1,231 @@
/*
* Copyright (C) 2019 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
*
*/
#define __BTSTACK_FILE__ "main.c"
// *****************************************************************************
//
// minimal setup for HCI code
//
// *****************************************************************************
#include <QCoreApplication>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include "btstack_config.h"
#include "bluetooth_company_id.h"
#include "btstack_debug.h"
#include "btstack_event.h"
#include "ble/le_device_db_tlv.h"
#include "classic/btstack_link_key_db_tlv.h"
#include "btstack_memory.h"
#include "btstack_run_loop.h"
#include "btstack_run_loop_qt.h"
#include "hal_led.h"
#include "hci.h"
#include "hci_dump.h"
#include "btstack_stdin.h"
#include "btstack_audio.h"
#include "btstack_tlv_posix.h"
#define TLV_DB_PATH_PREFIX "/tmp/btstack_"
#define TLV_DB_PATH_POSTFIX ".tlv"
static char tlv_db_path[100];
static const btstack_tlv_t * tlv_impl;
static btstack_tlv_posix_t tlv_context;
static bd_addr_t local_addr;
extern "C" int btstack_main(int argc, const char * argv[]);
static const uint8_t read_static_address_command_complete_prefix[] = { 0x0e, 0x1b, 0x01, 0x09, 0xfc };
static bd_addr_t static_address;
static int using_static_address;
static btstack_packet_callback_registration_t hci_event_callback_registration;
static void local_version_information_handler(uint8_t * packet){
printf("Local version information:\n");
uint16_t hci_version = packet[6];
uint16_t hci_revision = little_endian_read_16(packet, 7);
uint16_t lmp_version = packet[9];
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 Subversion 0x%04x\n", lmp_subversion);
printf("- Manufacturer 0x%04x\n", manufacturer);
}
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
UNUSED(channel);
UNUSED(size);
if (packet_type != HCI_EVENT_PACKET) return;
switch (hci_event_packet_get_type(packet)){
case BTSTACK_EVENT_STATE:
if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return;
gap_local_bd_addr(local_addr);
if (using_static_address){
memcpy(local_addr, static_address, 6);
}
printf("BTstack up and running on %s.\n", bd_addr_to_str(local_addr));
strcpy(tlv_db_path, TLV_DB_PATH_PREFIX);
strcat(tlv_db_path, bd_addr_to_str(local_addr));
strcat(tlv_db_path, TLV_DB_PATH_POSTFIX);
tlv_impl = btstack_tlv_posix_init_instance(&tlv_context, tlv_db_path);
btstack_tlv_set_instance(tlv_impl, &tlv_context);
#ifdef ENABLE_CLASSIC
hci_set_link_key_db(btstack_link_key_db_tlv_get_instance(tlv_impl, &tlv_context));
#endif
#ifdef ENABLE_BLE
le_device_db_tlv_configure(tlv_impl, &tlv_context);
#endif
break;
case HCI_EVENT_COMMAND_COMPLETE:
if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_read_local_version_information)){
local_version_information_handler(packet);
}
if (memcmp(packet, read_static_address_command_complete_prefix, sizeof(read_static_address_command_complete_prefix)) == 0){
reverse_48(&packet[7], static_address);
gap_random_address_set(static_address);
using_static_address = 1;
}
break;
default:
break;
}
}
static void sigint_handler(int param){
UNUSED(param);
printf("CTRL-C - SIGINT received, shutting down..\n");
log_info("sigint_handler: shutting down");
// reset anyway
btstack_stdin_reset();
// power down
hci_power_control(HCI_POWER_OFF);
hci_close();
log_info("Good bye, see you.\n");
exit(0);
}
static int led_state = 0;
void hal_led_toggle(void){
led_state = 1 - led_state;
printf("LED State %u\n", led_state);
}
#define USB_MAX_PATH_LEN 7
int btstack_main(int argc, const char * argv[]);
int main(int argc, char * argv[]){
uint8_t usb_path[USB_MAX_PATH_LEN];
int usb_path_len = 0;
const char * usb_path_string = NULL;
if (argc >= 3 && strcmp(argv[1], "-u") == 0){
// parse command line options for "-u 11:22:33"
usb_path_string = argv[2];
printf("Specified USB Path: ");
while (1){
char * delimiter;
int port = strtol(usb_path_string, &delimiter, 16);
usb_path[usb_path_len] = port;
usb_path_len++;
printf("%02x ", port);
if (!delimiter) break;
if (*delimiter != ':' && *delimiter != '-') break;
usb_path_string = delimiter+1;
}
printf("\n");
argc -= 2;
memmove(&argv[1], &argv[3], (argc-1) * sizeof(char *));
}
QCoreApplication a(argc, argv);
/// GET STARTED with BTstack ///
btstack_memory_init();
btstack_run_loop_init(btstack_run_loop_qt_get_instance());
if (usb_path_len){
hci_transport_usb_set_path(usb_path_len, usb_path);
}
// use logger: format HCI_DUMP_PACKETLOGGER, HCI_DUMP_BLUEZ or HCI_DUMP_STDOUT
char pklg_path[100];
strcpy(pklg_path, "/tmp/hci_dump");
if (usb_path_len){
strcat(pklg_path, "_");
strcat(pklg_path, usb_path_string);
}
strcat(pklg_path, ".pklg");
printf("Packet Log: %s\n", pklg_path);
hci_dump_open(pklg_path, HCI_DUMP_PACKETLOGGER);
// init HCI
hci_init(hci_transport_usb_instance(), NULL);
#ifdef HAVE_PORTAUDIO
btstack_audio_sink_set_instance(btstack_audio_portaudio_sink_get_instance());
btstack_audio_source_set_instance(btstack_audio_portaudio_source_get_instance());
#endif
// inform about BTstack state
hci_event_callback_registration.callback = &packet_handler;
hci_add_event_handler(&hci_event_callback_registration);
// handle CTRL-c
signal(SIGINT, sigint_handler);
// setup app
btstack_main(argc, (const char **) argv);
// enter Qt run loop
return a.exec();
}