mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-24 22:43:35 +00:00
Add native linux port
This commit is contained in:
parent
97f64e028b
commit
d761bfb000
191
port/linux/CMakeLists.txt
Normal file
191
port/linux/CMakeLists.txt
Normal file
@ -0,0 +1,191 @@
|
||||
cmake_minimum_required (VERSION 3.18)
|
||||
|
||||
project(BTstack-linux-bluez)
|
||||
|
||||
SET(BTSTACK_ROOT ${CMAKE_SOURCE_DIR}/../..)
|
||||
|
||||
# extra compiler warnings
|
||||
if ("${CMAKE_C_COMPILER_ID}" MATCHES ".*Clang.*")
|
||||
# using Clang
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused-variable -Wswitch-default -Werror")
|
||||
elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
|
||||
# using GCC
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused-but-set-variable -Wunused-variable -Wswitch-default -Werror")
|
||||
elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "Intel")
|
||||
# using Intel C++
|
||||
elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# using Visual Studio C++
|
||||
endif()
|
||||
|
||||
|
||||
# to generate .h from .gatt files
|
||||
find_package (Python REQUIRED COMPONENTS Interpreter)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# local dir for btstack_config.h after build dir to avoid using .h from Makefile
|
||||
include_directories(.)
|
||||
|
||||
|
||||
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/lc3-google/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/lc3-google/include)
|
||||
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/embedded)
|
||||
include_directories(${BTSTACK_ROOT}/platform/lwip)
|
||||
include_directories(${BTSTACK_ROOT}/platform/lwip/port)
|
||||
include_directories(${BTSTACK_ROOT}/platform/posix)
|
||||
|
||||
file(GLOB SOURCES_SRC "${BTSTACK_ROOT}/src/*.c" "${BTSTACK_ROOT}/example/*demo_util*.c")
|
||||
file(GLOB SOURCES_BLE "${BTSTACK_ROOT}/src/ble/*.c")
|
||||
file(GLOB SOURCES_BLUEDROID "${BTSTACK_ROOT}/3rd-party/bluedroid/encoder/srce/*.c" "${BTSTACK_ROOT}/3rd-party/bluedroid/decoder/srce/*.c")
|
||||
file(GLOB SOURCES_CLASSIC "${BTSTACK_ROOT}/src/classic/*.c")
|
||||
file(GLOB SOURCES_MESH "${BTSTACK_ROOT}/src/mesh/*.c")
|
||||
file(GLOB SOURCES_GATT "${BTSTACK_ROOT}/src/ble/gatt-service/*.c")
|
||||
file(GLOB SOURCES_UECC "${BTSTACK_ROOT}/3rd-party/micro-ecc/uECC.c")
|
||||
file(GLOB SOURCES_HXCMOD "${BTSTACK_ROOT}/3rd-party/hxcmod-player/*.c" "${BTSTACK_ROOT}/3rd-party/hxcmod-player/mods/*.c")
|
||||
file(GLOB SOURCES_LE_AUDIO "${BTSTACK_ROOT}/src/le-audio/*.c" "${BTSTACK_ROOT}/src/le-audio/gatt-service/*.c")
|
||||
file(GLOB SOURCES_MD5 "${BTSTACK_ROOT}/3rd-party/md5/md5.c")
|
||||
file(GLOB SOURCES_RIJNDAEL "${BTSTACK_ROOT}/3rd-party/rijndael/rijndael.c")
|
||||
file(GLOB SOURCES_YXML "${BTSTACK_ROOT}/3rd-party/yxml/yxml.c")
|
||||
file(GLOB SOURCES_POSIX "${BTSTACK_ROOT}/platform/posix/*.c")
|
||||
file(GLOB SOURCES_LC3_GOOGLE "${BTSTACK_ROOT}/3rd-party/lc3-google/src/*.c")
|
||||
file(GLOB SOURCES_PORT "*.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})
|
||||
|
||||
file(GLOB SOURCES_POSIX_OFF "${BTSTACK_ROOT}/platform/posix/le_device_db_fs.c")
|
||||
list(REMOVE_ITEM SOURCES_POSIX ${SOURCES_POSIX_OFF})
|
||||
|
||||
set(SOURCES
|
||||
${SOURCES_BLE}
|
||||
${SOURCES_BCM}
|
||||
${SOURCES_BLUEDROID}
|
||||
${SOURCES_CLASSIC}
|
||||
${SOURCES_CSR}
|
||||
${SOURCES_EM9301}
|
||||
${SOURCES_GATT}
|
||||
${SOURCES_HXCMOD}
|
||||
${SOURCES_HXCMOD}
|
||||
${SOURCES_LC3_GOOGLE}
|
||||
${SOURCES_LE_AUDIO}
|
||||
${SOURCES_LIBUSB}
|
||||
${SOURCES_MD5}
|
||||
${SOURCES_MESH}
|
||||
${SOURCES_PORT}
|
||||
${SOURCES_REALTEK}
|
||||
${SOURCES_RIJNDAEL}
|
||||
${SOURCES_SRC}
|
||||
${SOURCES_CSR}
|
||||
${SOURCES_STLC2500D}
|
||||
${SOURCES_TC2566X}
|
||||
${SOURCES_UECC}
|
||||
${SOURCES_POSIX}
|
||||
${SOURCES_YXML}
|
||||
${SOURCES_ZEPHYR}
|
||||
)
|
||||
list(SORT SOURCES)
|
||||
|
||||
# create static lib
|
||||
add_library(btstack STATIC ${SOURCES})
|
||||
|
||||
# Collect libraries for executables
|
||||
set (BTSTACK_LIBRARIES btstack)
|
||||
|
||||
# pkgconfig
|
||||
find_package(PkgConfig)
|
||||
|
||||
# portaudio
|
||||
if (PkgConfig_FOUND)
|
||||
pkg_check_modules(PORTAUDIO portaudio-2.0)
|
||||
if(PORTAUDIO_FOUND)
|
||||
message("HAVE_PORTAUDIO")
|
||||
include_directories(${PORTAUDIO_INCLUDE_DIRS})
|
||||
set(BTSTACK_LIBRARIES ${BTSTACK_LIBRARIES} ${PORTAUDIO_LIBRARIES})
|
||||
link_directories(${PORTAUDIO_LIBRARY_DIRS})
|
||||
add_compile_definitions(HAVE_PORTAUDIO)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# pthread
|
||||
find_package(Threads)
|
||||
set(BTSTACK_LIBRARIES ${BTSTACK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} pthread m bluetooth)
|
||||
|
||||
# get list of examples, skipping mesh_node_demo
|
||||
include(../../example/CMakeLists.txt)
|
||||
set (EXAMPLES ${EXAMPLES_GENERAL} ${EXAMPLES_CLASSIC_ONLY} ${EXAMPLES_LE_ONLY} ${EXAMPLES_DUAL_MODE})
|
||||
list(REMOVE_DUPLICATES EXAMPLES)
|
||||
list(REMOVE_ITEM EXAMPLES "mesh_node_demo")
|
||||
|
||||
# create targets
|
||||
foreach(EXAMPLE ${EXAMPLES})
|
||||
# get c file
|
||||
set (SOURCES_EXAMPLE ${BTSTACK_ROOT}/example/${EXAMPLE}.c)
|
||||
|
||||
# add GATT DB creation
|
||||
if ( "${EXAMPLES_GATT_FILES}" MATCHES ${EXAMPLE} )
|
||||
message("example ${EXAMPLE} -- with GATT DB")
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${EXAMPLE}.h
|
||||
DEPENDS ${BTSTACK_ROOT}/example/${EXAMPLE}.gatt
|
||||
COMMAND ${Python_EXECUTABLE}
|
||||
ARGS ${BTSTACK_ROOT}/tool/compile_gatt.py ${BTSTACK_ROOT}/example/${EXAMPLE}.gatt ${CMAKE_CURRENT_BINARY_DIR}/${EXAMPLE}.h
|
||||
)
|
||||
list(APPEND SOURCES_EXAMPLE ${CMAKE_CURRENT_BINARY_DIR}/${EXAMPLE}.h)
|
||||
else()
|
||||
message("example ${EXAMPLE}")
|
||||
endif()
|
||||
add_executable(${EXAMPLE} ${SOURCES_EXAMPLE})
|
||||
target_link_libraries(${EXAMPLE} ${BTSTACK_LIBRARIES})
|
||||
endforeach(EXAMPLE)
|
47
port/linux/README.md
Normal file
47
port/linux/README.md
Normal file
@ -0,0 +1,47 @@
|
||||
# BTstack Port for Linux Systems
|
||||
|
||||
While BTstack can directly work on Linux with most Bluetooth Controllers that are connected via UART (port/posix-h4) or USB (port/libusb), it might be convenient to use the Linux Bluetooth Subsystem in some cases, e.g. if the Bluetooth Controller uses other transports (such as SDIO) or the Controller is already fully configured by the distributions.
|
||||
|
||||
|
||||
## Compilation
|
||||
|
||||
In addition to regular C build tools, you also need the Bluetooth development package installed.
|
||||
|
||||
sudo apt install libbluetooth-dev
|
||||
|
||||
Now you can compile it as usual with CMake
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
|
||||
|
||||
## Running the examples
|
||||
|
||||
Please make sure that BlueZ is not installed or at least disabled
|
||||
|
||||
sudo systemctl stop bluetooth
|
||||
sudo systemctl disable bluetooth
|
||||
sudo systemctl mask bluetooth
|
||||
|
||||
Also make sure that the chosen device (here, hci0) is down
|
||||
|
||||
sudo hciconfig hci0 down
|
||||
|
||||
To access the Bluetooth Controller, you can either run the examples as root, or, set the necessary permissions for a compiled example, e.g.
|
||||
|
||||
sudo setcap 'cap_net_raw,cap_net_admin+eip' gatt_counter
|
||||
|
||||
|
||||
Now, you can run any of the examples
|
||||
|
||||
$ ./gatt_counter
|
||||
Packet Log: /tmp/hci_dump.pklg
|
||||
BTstack counter 0001
|
||||
BTstack up and running on 00:1A:7D:DA:71:13.
|
||||
|
||||
|
||||
## Status
|
||||
|
||||
When running gatt_counter, a basic LE Peripheral with a GATT Service, the first two connections fail, while the third and later work as expected. There's no difference when looking at the HCI Trace with btmon, just that no ACL packets are received in the failing attempts.
|
72
port/linux/btstack_config.h
Normal file
72
port/linux/btstack_config.h
Normal file
@ -0,0 +1,72 @@
|
||||
//
|
||||
// btstack_config.h for generic POSIX H4 port
|
||||
//
|
||||
// Documentation: https://bluekitchen-gmbh.com/btstack/#how_to/
|
||||
//
|
||||
|
||||
#ifndef BTSTACK_CONFIG_H
|
||||
#define BTSTACK_CONFIG_H
|
||||
|
||||
// Port related features
|
||||
#define HAVE_ASSERT
|
||||
#define HAVE_BTSTACK_STDIN
|
||||
#define HAVE_MALLOC
|
||||
#define HAVE_POSIX_FILE_IO
|
||||
#define HAVE_POSIX_TIME
|
||||
|
||||
// BTstack features that can be enabled
|
||||
#define ENABLE_ATT_DELAYED_RESPONSE
|
||||
#define ENABLE_AVRCP_COVER_ART
|
||||
#define ENABLE_BLE
|
||||
#define ENABLE_CLASSIC
|
||||
#define ENABLE_CROSS_TRANSPORT_KEY_DERIVATION
|
||||
#define ENABLE_GOEP_L2CAP
|
||||
#define ENABLE_HFP_WIDE_BAND_SPEECH
|
||||
#define ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
|
||||
#define ENABLE_L2CAP_LE_CREDIT_BASED_FLOW_CONTROL_MODE
|
||||
#define ENABLE_LE_CENTRAL
|
||||
#define ENABLE_LE_CENTRAL
|
||||
#define ENABLE_LE_DATA_LENGTH_EXTENSION
|
||||
#define ENABLE_LE_EXTENDED_ADVERTISING
|
||||
#define ENABLE_LE_ISOCHRONOUS_STREAMS
|
||||
#define ENABLE_LE_PERIODIC_ADVERTISING
|
||||
#define ENABLE_LE_PERIPHERAL
|
||||
#define ENABLE_LE_PRIVACY_ADDRESS_RESOLUTION
|
||||
#define ENABLE_LE_SECURE_CONNECTIONS
|
||||
#define ENABLE_LOG_ERROR
|
||||
#define ENABLE_LOG_INFO
|
||||
#define ENABLE_MICRO_ECC_FOR_LE_SECURE_CONNECTIONS
|
||||
#define ENABLE_PRINTF_HEXDUMP
|
||||
#define ENABLE_SCO_OVER_HCI
|
||||
#define ENABLE_SDP_DES_DUMP
|
||||
#define ENABLE_SOFTWARE_AES128
|
||||
|
||||
// BTstack configuration. buffers, sizes, ...
|
||||
#define HCI_ACL_PAYLOAD_SIZE (1691 + 4)
|
||||
#define HCI_INCOMING_PRE_BUFFER_SIZE 14 // sizeof benep heade, avoid memcpy
|
||||
|
||||
#define NVM_NUM_DEVICE_DB_ENTRIES 16
|
||||
#define NVM_NUM_LINK_KEYS 16
|
||||
|
||||
#define MAX_NR_AUDIO_CHANNELS 5
|
||||
#define MAX_NR_BIS 5
|
||||
#define MAX_NR_CIS 5
|
||||
|
||||
// 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_PROVISIONER
|
||||
#define ENABLE_MESH_PROXY_SERVER
|
||||
|
||||
#define MAX_NR_MESH_SUBNETS 2
|
||||
#define MAX_NR_MESH_TRANSPORT_KEYS 16
|
||||
#define MAX_NR_MESH_VIRTUAL_ADDRESSES 16
|
||||
|
||||
// allow for one NetKey update
|
||||
#define MAX_NR_MESH_NETWORK_KEYS (MAX_NR_MESH_SUBNETS+1)
|
||||
|
||||
#endif
|
||||
|
209
port/linux/hci_transport_linux.c
Normal file
209
port/linux/hci_transport_linux.c
Normal file
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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 BLUEKITCHEN
|
||||
* GMBH 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__ "hci_transport_linux.c"
|
||||
|
||||
#include "hci_transport_linux.h"
|
||||
|
||||
#include "btstack_bool.h"
|
||||
#include "btstack_config.h"
|
||||
#include "btstack_debug.h"
|
||||
#include "btstack_run_loop.h"
|
||||
#include "hci_transport.h"
|
||||
#include "hci.h"
|
||||
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/hci.h>
|
||||
|
||||
// we cannot include hci_lib.h directly as it clashes with some of our hci functions
|
||||
// prefix all clashing functions with linux_
|
||||
#define hci_send_cmd linux_hci_send_cmd
|
||||
#define hci_create_connection linux_hci_create_connection
|
||||
#define hci_disconnect linux_hci_disconnect
|
||||
#define hci_inquiry linux_hci_inquiry
|
||||
#define hci_read_local_name linux_hci_read_local_name
|
||||
#define hci_write_local_name linux_hci_write_local_name
|
||||
#define hci_read_clock_offset linux_hci_read_clock_offset
|
||||
#define hci_read_bd_addr linux_hci_read_bd_addr
|
||||
#define hci_delete_stored_link_key linux_hci_delete_stored_link_key
|
||||
#define hci_write_inquiry_scan_type linux_hci_write_inquiry_scan_type
|
||||
#define hci_write_inquiry_mode linux_hci_write_inquiry_mode
|
||||
#define hci_write_simple_pairing_mode linux_hci_write_simple_pairing_mode
|
||||
#define hci_read_local_oob_data linux_hci_read_local_oob_data
|
||||
#define hci_write_inquiry_transmit_power_level linux_hci_write_inquiry_transmit_power_level
|
||||
#define hci_read_transmit_power_level linux_hci_read_transmit_power_level
|
||||
#define hci_read_link_supervision_timeout linux_hci_read_link_supervision_timeout
|
||||
#define hci_write_link_supervision_timeout linux_hci_write_link_supervision_timeout
|
||||
#define hci_read_link_quality linux_hci_read_link_quality
|
||||
#define hci_read_rssi linux_hci_read_rssi
|
||||
#define hci_read_clock linux_hci_read_clock
|
||||
#define hci_le_set_scan_enable linux_hci_le_set_scan_enable
|
||||
#define hci_le_set_scan_parameters linux_hci_le_set_scan_parameters
|
||||
#define hci_le_set_advertise_enable linux_hci_le_set_advertise_enable
|
||||
#define hci_le_read_white_list_size linux_hci_le_read_white_list_size
|
||||
#define hci_le_clear_white_list linux_hci_le_clear_white_list
|
||||
#define hci_le_clear_resolving_list linux_hci_le_clear_resolving_list
|
||||
#define hci_le_read_resolving_list_size linux_hci_le_read_resolving_list_size
|
||||
#include <bluetooth/hci_lib.h>
|
||||
|
||||
// assert pre-buffer for packet type is available
|
||||
#if !defined(HCI_OUTGOING_PRE_BUFFER_SIZE) || (HCI_OUTGOING_PRE_BUFFER_SIZE == 0)
|
||||
#error HCI_OUTGOING_PRE_BUFFER_SIZE not defined. Please update hci.h
|
||||
#endif
|
||||
|
||||
|
||||
// hci packet handler
|
||||
static void (*hci_transport_linux_packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size) = NULL;
|
||||
|
||||
// data source for integration with BTstack Runloop
|
||||
static btstack_data_source_t hci_transport_linux_data_source;
|
||||
|
||||
// incoming packet buffer
|
||||
static uint8_t hci_packet_with_pre_buffer[HCI_INCOMING_PRE_BUFFER_SIZE + HCI_INCOMING_PACKET_BUFFER_SIZE + 1]; // packet type + max(acl header + acl payload, event header + event data)
|
||||
static uint8_t * hci_packet = &hci_packet_with_pre_buffer[HCI_INCOMING_PRE_BUFFER_SIZE];
|
||||
|
||||
// linux hci socket
|
||||
static int hci_socket = -1;
|
||||
|
||||
static const hci_transport_config_linux_t * hci_transport_config_linux;
|
||||
|
||||
static void hci_transport_linux_process_read(btstack_data_source_t * ds) {
|
||||
UNUSED(ds);
|
||||
|
||||
int bytes_read = read(hci_socket, hci_packet, HCI_INCOMING_PACKET_BUFFER_SIZE);
|
||||
if (bytes_read < 0) {
|
||||
perror("Failed to read HCI packet");
|
||||
return;
|
||||
}
|
||||
|
||||
hci_transport_linux_packet_handler(hci_packet[0], &hci_packet[1], bytes_read-1);
|
||||
}
|
||||
|
||||
static void hci_transport_linux_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
|
||||
switch (callback_type){
|
||||
case DATA_SOURCE_CALLBACK_READ:
|
||||
hci_transport_linux_process_read(ds);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_transport_linux_init (const void *transport_config){
|
||||
btstack_assert(transport_config != NULL);
|
||||
hci_transport_config_linux = (const hci_transport_config_linux_t *) transport_config;
|
||||
btstack_assert(hci_transport_config_linux->type == HCI_TRANSPORT_CONFIG_LINUX);
|
||||
log_info("Using device id %u", hci_transport_config_linux->device_id);
|
||||
}
|
||||
|
||||
static int hci_transport_linux_open(void) {
|
||||
struct sockaddr_hci addr;
|
||||
|
||||
hci_socket = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, BTPROTO_HCI);
|
||||
if (hci_socket < 0) {
|
||||
perror("Failed to create HCI socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.hci_family = AF_BLUETOOTH;
|
||||
addr.hci_dev = hci_transport_config_linux->device_id;
|
||||
addr.hci_channel = HCI_CHANNEL_USER;
|
||||
if (bind(hci_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("Failed to bind HCI socket");
|
||||
close(hci_socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// set up data_source
|
||||
btstack_run_loop_set_data_source_fd(&hci_transport_linux_data_source, hci_socket);
|
||||
btstack_run_loop_set_data_source_handler(&hci_transport_linux_data_source, &hci_transport_linux_process);
|
||||
btstack_run_loop_add_data_source(&hci_transport_linux_data_source);
|
||||
btstack_run_loop_enable_data_source_callbacks(&hci_transport_linux_data_source, DATA_SOURCE_CALLBACK_READ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hci_transport_linux_close(void){
|
||||
btstack_run_loop_remove_data_source(&hci_transport_linux_data_source);
|
||||
if (hci_socket >= 0) {
|
||||
close(hci_socket);
|
||||
hci_socket = -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hci_transport_linux_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
|
||||
hci_transport_linux_packet_handler = handler;
|
||||
}
|
||||
|
||||
static int hci_transport_linux_send_packet(uint8_t packet_type, uint8_t * packet, int size) {
|
||||
// store packet type before actual data and increase size
|
||||
uint8_t * buffer = &packet[-1];
|
||||
uint32_t buffer_size = size + 1;
|
||||
buffer[0] = packet_type;
|
||||
|
||||
if (write(hci_socket, buffer, buffer_size) < 0) {
|
||||
perror("Failed to send HCI packet");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const hci_transport_t hci_transport_linux = {
|
||||
.name = "Linux BlueZ",
|
||||
.init = &hci_transport_linux_init,
|
||||
.open = &hci_transport_linux_open,
|
||||
.close = &hci_transport_linux_close,
|
||||
.register_packet_handler = &hci_transport_linux_register_packet_handler,
|
||||
.send_packet = &hci_transport_linux_send_packet
|
||||
};
|
||||
|
||||
const hci_transport_t * hci_transport_linux_instance(void) {
|
||||
return &hci_transport_linux;
|
||||
}
|
61
port/linux/hci_transport_linux.h
Normal file
61
port/linux/hci_transport_linux.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 BLUEKITCHEN
|
||||
* GMBH 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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* hci_transport_linux
|
||||
*
|
||||
* HCI Transport API implementation that connects to native Linux Bluetooth device via the User Channel
|
||||
* This allows BTstack to use Bluetooth Controller supported by the Linux kernel after the it was fully initialized
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HCI_TRANSPORT_LINUX_H
|
||||
#define HCI_TRANSPORT_LINUX_H
|
||||
|
||||
#include "hci_transport.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const hci_transport_t * hci_transport_linux_instance(void);
|
||||
|
||||
#if defined __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // HCI_TRANSPORT_LINUX_H
|
290
port/linux/main.c
Normal file
290
port/linux/main.c
Normal file
@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 BLUEKITCHEN
|
||||
* GMBH 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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "btstack_config.h"
|
||||
|
||||
#include "ble/le_device_db_tlv.h"
|
||||
#include "btstack_audio.h"
|
||||
#include "btstack_debug.h"
|
||||
#include "btstack_event.h"
|
||||
#include "btstack_memory.h"
|
||||
#include "btstack_run_loop.h"
|
||||
#include "btstack_run_loop_posix.h"
|
||||
#include "btstack_signal.h"
|
||||
#include "btstack_stdin.h"
|
||||
#include "btstack_tlv_posix.h"
|
||||
#include "classic/btstack_link_key_db_tlv.h"
|
||||
#include "hci.h"
|
||||
#include "hci_dump.h"
|
||||
#include "hci_dump_posix_fs.h"
|
||||
#include "hci_transport.h"
|
||||
#include "hci_transport_linux.h"
|
||||
|
||||
|
||||
static hci_transport_config_linux_t transport_config = {
|
||||
.type = HCI_TRANSPORT_CONFIG_LINUX,
|
||||
.device_id = 0,
|
||||
};
|
||||
|
||||
#define TLV_DB_PATH_PREFIX "/tmp/btstack_"
|
||||
#define TLV_DB_PATH_POSTFIX ".tlv"
|
||||
static char tlv_db_path[100];
|
||||
static bool tlv_reset;
|
||||
static const btstack_tlv_t * tlv_impl;
|
||||
static btstack_tlv_posix_t tlv_context;
|
||||
|
||||
static btstack_packet_callback_registration_t hci_event_callback_registration;
|
||||
|
||||
// shutdown
|
||||
static bool shutdown_triggered;
|
||||
|
||||
// prototypes
|
||||
int btstack_main(int argc, const char * argv[]);
|
||||
static void local_version_information_handler(uint8_t * packet);
|
||||
|
||||
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
static bd_addr_t local_addr;
|
||||
if (packet_type != HCI_EVENT_PACKET) return;
|
||||
switch (hci_event_packet_get_type(packet)){
|
||||
case BTSTACK_EVENT_STATE:
|
||||
switch(btstack_event_state_get_state(packet)){
|
||||
case HCI_STATE_WORKING:
|
||||
gap_local_bd_addr(local_addr);
|
||||
printf("BTstack up and running on %s.\n", bd_addr_to_str(local_addr));
|
||||
btstack_strcpy(tlv_db_path, sizeof(tlv_db_path), TLV_DB_PATH_PREFIX);
|
||||
btstack_strcat(tlv_db_path, sizeof(tlv_db_path), bd_addr_to_str_with_delimiter(local_addr, '-'));
|
||||
btstack_strcat(tlv_db_path, sizeof(tlv_db_path), TLV_DB_PATH_POSTFIX);
|
||||
printf("TLV path: %s", tlv_db_path);
|
||||
if (tlv_reset){
|
||||
int rc = unlink(tlv_db_path);
|
||||
if (rc == 0) {
|
||||
printf(", reset ok");
|
||||
} else {
|
||||
printf(", reset failed with result = %d", rc);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
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_STATE_OFF:
|
||||
btstack_tlv_posix_deinit(&tlv_context);
|
||||
if (!shutdown_triggered) break;
|
||||
// reset stdin
|
||||
btstack_stdin_reset();
|
||||
log_info("Good bye, see you.\n");
|
||||
exit(0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HCI_EVENT_COMMAND_COMPLETE:
|
||||
switch (hci_event_command_complete_get_command_opcode(packet)){
|
||||
case HCI_OPCODE_HCI_READ_LOCAL_VERSION_INFORMATION:
|
||||
local_version_information_handler(packet);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void trigger_shutdown(void){
|
||||
printf("CTRL-C - SIGINT received, shutting down..\n");
|
||||
log_info("sigint_handler: shutting down");
|
||||
shutdown_triggered = true;
|
||||
hci_power_control(HCI_POWER_OFF);
|
||||
}
|
||||
|
||||
static int led_state = 0;
|
||||
void hal_led_toggle(void){
|
||||
led_state = 1 - led_state;
|
||||
printf("LED State %u\n", led_state);
|
||||
}
|
||||
|
||||
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 char short_options[] = "hl:ru:";
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"logfile", required_argument, NULL, 'l'},
|
||||
{"reset-tlv", no_argument, NULL, 'r'},
|
||||
{"device_id", no_argument, NULL, 'u'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static char *help_options[] = {
|
||||
"print (this) help.",
|
||||
"set file to store debug output and HCI trace.",
|
||||
"reset bonding information stored in TLV.",
|
||||
"set device id, e.g. 0 for HCI0",
|
||||
};
|
||||
|
||||
static char *option_arg_name[] = {
|
||||
"",
|
||||
"LOGFILE",
|
||||
"",
|
||||
"DEVICE_ID",
|
||||
};
|
||||
|
||||
static void usage(const char *name){
|
||||
unsigned int i;
|
||||
printf( "usage:\n\t%s [options]\n", name );
|
||||
printf("valid options:\n");
|
||||
for( i=0; long_options[i].name != 0; i++) {
|
||||
printf("--%-10s| -%c %-10s\t\t%s\n", long_options[i].name, long_options[i].val, option_arg_name[i], help_options[i] );
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char * argv[]){
|
||||
|
||||
const char * log_file_path = NULL;
|
||||
|
||||
// parse command line parameters
|
||||
while(true){
|
||||
int c = getopt_long( argc, (char* const *)argv, short_options, long_options, NULL );
|
||||
if (c < 0) {
|
||||
break;
|
||||
}
|
||||
if (c == '?'){
|
||||
break;
|
||||
}
|
||||
switch (c) {
|
||||
case 'l':
|
||||
log_file_path = optarg;
|
||||
break;
|
||||
case 'u':
|
||||
transport_config.device_id = btstack_atoi(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
tlv_reset = true;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
usage(argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
/// GET STARTED with BTstack ///
|
||||
btstack_memory_init();
|
||||
btstack_run_loop_init(btstack_run_loop_posix_get_instance());
|
||||
|
||||
char pklg_path[PATH_MAX] = "/tmp/hci_dump_";
|
||||
// log into file using HCI_DUMP_PACKETLOGGER format
|
||||
if (log_file_path == NULL){
|
||||
char *app_name = strndup( argv[0], PATH_MAX );
|
||||
char *base_name = basename( app_name );
|
||||
const char *pklg_postfix = ".pklg";
|
||||
|
||||
btstack_strcat( pklg_path, sizeof(pklg_path), base_name );
|
||||
btstack_strcat( pklg_path, sizeof(pklg_path), pklg_postfix );
|
||||
free( app_name );
|
||||
|
||||
log_file_path = pklg_path;
|
||||
}
|
||||
hci_dump_posix_fs_open(log_file_path, HCI_DUMP_PACKETLOGGER);
|
||||
const hci_dump_t * hci_dump_impl = hci_dump_posix_fs_get_instance();
|
||||
hci_dump_init(hci_dump_impl);
|
||||
printf("Packet Log: %s\n", log_file_path);
|
||||
printf("Bluetooth device: hci%u\n", transport_config.device_id);
|
||||
|
||||
// init HCI
|
||||
const hci_transport_t * transport = hci_transport_linux_instance();
|
||||
hci_init(transport, (void*) &transport_config);
|
||||
|
||||
#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);
|
||||
|
||||
// register callback for CTRL-c
|
||||
btstack_signal_register_callback(SIGINT, &trigger_shutdown);
|
||||
|
||||
// setup app
|
||||
btstack_main(argc, argv);
|
||||
|
||||
// go
|
||||
btstack_run_loop_execute();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user