mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-14 01:27:41 +00:00
freebsd-netgraph: FreeBSD port that accesses ng_hci node
This commit is contained in:
parent
33c74df1cc
commit
22029648db
206
port/freebsd-netgraph/CMakeLists.txt
Normal file
206
port/freebsd-netgraph/CMakeLists.txt
Normal file
@ -0,0 +1,206 @@
|
||||
cmake_minimum_required (VERSION 3.18)
|
||||
|
||||
project(BTstack-posix-h4)
|
||||
|
||||
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/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}/chipset/bcm)
|
||||
include_directories(${BTSTACK_ROOT}/chipset/csr)
|
||||
include_directories(${BTSTACK_ROOT}/chipset/cc256x)
|
||||
include_directories(${BTSTACK_ROOT}/chipset/em9301)
|
||||
include_directories(${BTSTACK_ROOT}/chipset/realtek)
|
||||
include_directories(${BTSTACK_ROOT}/chipset/tc3566x)
|
||||
include_directories(${BTSTACK_ROOT}/chipset/stlc2500d)
|
||||
include_directories(${BTSTACK_ROOT}/chipset/zephyr)
|
||||
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/sco_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_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_BCM "${BTSTACK_ROOT}/chipset/bcm/*.c")
|
||||
file(GLOB SOURCES_CSR "${BTSTACK_ROOT}/chipset/csr/*.c")
|
||||
file(GLOB SOURCES_EM9301 "${BTSTACK_ROOT}/chipset/em9301/*.c")
|
||||
file(GLOB SOURCES_STLC2500D "${BTSTACK_ROOT}/chipset/stlc2500d/*.c")
|
||||
file(GLOB SOURCES_TC2566X "${BTSTACK_ROOT}/chipset/tc3566x/*.c")
|
||||
file(GLOB SOURCES_REALTEK "${BTSTACK_ROOT}/chipset/realtek/*.c")
|
||||
file(GLOB SOURCES_ZEPHYR "${BTSTACK_ROOT}/chipset/zephyr/*.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_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})
|
||||
|
||||
# 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})
|
||||
link_directories(${PORTAUDIO_LIBRARY_DIRS})
|
||||
link_libraries(${PORTAUDIO_LIBRARIES})
|
||||
add_compile_definitions(HAVE_PORTAUDIO)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# pthread
|
||||
find_package(Threads)
|
||||
link_libraries(${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
# Add CC256x Support and specify init script
|
||||
# set (CC256X_INIT_SCRIPT bluetooth_init_cc2564C_1.5.c)
|
||||
# include(${BTSTACK_ROOT}/chipset/cc256x/cc256x.cmake)
|
||||
|
||||
# Add BCM Support and download PatchRAM files
|
||||
# include(${BTSTACK_ROOT}/chipset/bcm/bcm.cmake)
|
||||
|
||||
# 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 pthread netgraph)
|
||||
endforeach(EXAMPLE)
|
44
port/freebsd-netgraph/README.md
Normal file
44
port/freebsd-netgraph/README.md
Normal file
@ -0,0 +1,44 @@
|
||||
# BTstack Port for FreeBSD Systems
|
||||
|
||||
## Overview
|
||||
This port assumes that FreeBSD provides an ng_hci netgraph node for a connected Bluetooth Controller.
|
||||
In most cases, these are Bluetooth USB dongles or built-in Bluetooth Controller connected via USB.
|
||||
|
||||
For Bluetooth Controllers connected via UART, the POSX-H4 port might be a better option als
|
||||
|
||||
## Implementation details
|
||||
In FreeBSD 13.2, the hci node is connected to a l2cap node and a btsock_hci_raw node. In order to take control, this
|
||||
port create a custom netgraph ng_socket node and connect to the 'acl' and 'raw' hooks of the hci node. The OS Bluetooth
|
||||
functionality will be interrupted.
|
||||
|
||||
## Compilation
|
||||
|
||||
BTstack's FeeeBSD port does not have additional dependencies. To compile the cmake project with make
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
|
||||
or using Ninja:
|
||||
|
||||
mkdir ninja
|
||||
cd ninja
|
||||
cmake ..
|
||||
ninja
|
||||
|
||||
## Running the examples
|
||||
|
||||
As the port needs to reconfigure the Bluetooth netgraph node, it needs to run with root privileges.
|
||||
It tries to connect to 'ubt0hci' by default. If your Bluetooth Controller is different, you can select it with '-u node'
|
||||
On start, BTstack prints the path to the packet log and prints the information on the detected Buetooth Controller.
|
||||
|
||||
$ sudo gatt_counter
|
||||
Packet Log: /tmp/hci_dump.pklg
|
||||
BTstack counter 0001
|
||||
BTstack up and running on 00:1A:7D:DA:71:13.
|
||||
|
||||
## ToDO
|
||||
- drop privileges after startup
|
||||
- auto-detect ng_hci node
|
||||
- support for profiles that require SCO: HFP & HSP
|
67
port/freebsd-netgraph/btstack_config.h
Normal file
67
port/freebsd-netgraph/btstack_config.h
Normal file
@ -0,0 +1,67 @@
|
||||
//
|
||||
// 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_EM9304_PATCH_CONTAINER
|
||||
#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_DATA_LENGTH_EXTENSION
|
||||
#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
|
||||
|
||||
// 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)
|
||||
|
||||
#define HCI_RESET_RESEND_TIMEOUT_MS 1000
|
||||
|
||||
#endif
|
||||
|
350
port/freebsd-netgraph/hci_transport_netgraph.c
Normal file
350
port/freebsd-netgraph/hci_transport_netgraph.c
Normal file
@ -0,0 +1,350 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#define BTSTACK_FILE__ "hci_transport_netgraph.c"
|
||||
|
||||
#include "hci_transport_netgraph.h"
|
||||
|
||||
#include "btstack_bool.h"
|
||||
#include "btstack_config.h"
|
||||
#include "btstack_debug.h"
|
||||
#include "btstack_event.h"
|
||||
#include "btstack_run_loop.h"
|
||||
#include "hci_transport.h"
|
||||
#include "hci.h"
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/bitstring.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
// avoid warning by /usr/include/netgraph/bluetooth/include/ng_btsocket.h
|
||||
#define L2CAP_SOCKET_CHECKED
|
||||
#include <bluetooth.h>
|
||||
#include <netgraph.h>
|
||||
#include <netgraph/bluetooth/include/ng_hci.h>
|
||||
#include <netgraph/bluetooth/include/ng_l2cap.h>
|
||||
#include <netgraph/bluetooth/include/ng_btsocket.h>
|
||||
|
||||
// hci packet handler
|
||||
static void (*hci_transport_netgraph_packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size);
|
||||
|
||||
// data source for integration with BTstack Runloop
|
||||
static btstack_data_source_t hci_transport_netgraph_data_source_hci_raw;
|
||||
|
||||
// block write
|
||||
static uint8_t hci_transport_netgraph_write_packet_type;
|
||||
static int hci_transport_netgraph_write_bytes_len;
|
||||
static const uint8_t * hci_transport_netgraph_write_bytes_data;
|
||||
|
||||
// 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
|
||||
|
||||
typedef enum {
|
||||
TX_OFF,
|
||||
TX_IDLE,
|
||||
TX_W4_PACKET_SENT,
|
||||
} TX_STATE;
|
||||
|
||||
// write state
|
||||
static TX_STATE hci_transport_netgraph_tx_state;
|
||||
|
||||
// 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];
|
||||
|
||||
// Netgraph node
|
||||
const char * hci_node_name = "ubt0hci";
|
||||
|
||||
// Control and Data socket for BTstack Netgraph node
|
||||
static int hci_transport_netgraph_hci_raw_control_socket;
|
||||
static int hci_transport_netgraph_hci_raw_data_socket;
|
||||
|
||||
// Track HCI Netgraph Initialization
|
||||
#define HCI_TODO_READ_BD_ADDR 1
|
||||
#define HCI_TODO_READ_LOCAL_SUPPORTED_FEATURES 2
|
||||
#define HCI_TODO_READ_BUFFER_SIZE 4
|
||||
|
||||
static uint8_t hci_transport_netgraph_hci_todo_init;
|
||||
|
||||
static void hci_transport_netgraph_process_write(btstack_data_source_t *ds) {
|
||||
|
||||
if (hci_transport_netgraph_write_bytes_len == 0) return;
|
||||
|
||||
const char * hook = NULL;
|
||||
switch (hci_transport_netgraph_write_packet_type){
|
||||
case HCI_COMMAND_DATA_PACKET:
|
||||
hook = "raw";
|
||||
break;
|
||||
case HCI_ACL_DATA_PACKET:
|
||||
hook = "acl";
|
||||
break;
|
||||
default:
|
||||
btstack_unreachable();
|
||||
break;
|
||||
}
|
||||
|
||||
int res = NgSendData(ds->source.fd, hook, hci_transport_netgraph_write_bytes_data, hci_transport_netgraph_write_bytes_len);
|
||||
|
||||
if (res < 0){
|
||||
log_error("send data via hook %s returned error %d", hook, errno);
|
||||
btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
|
||||
return;
|
||||
}
|
||||
|
||||
btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
|
||||
|
||||
hci_transport_netgraph_tx_state = TX_IDLE;
|
||||
hci_transport_netgraph_write_bytes_len = 0;
|
||||
hci_transport_netgraph_write_bytes_data = NULL;
|
||||
|
||||
// notify upper stack that it can send again
|
||||
static const uint8_t packet_sent_event[] = { HCI_EVENT_TRANSPORT_PACKET_SENT, 0};
|
||||
hci_transport_netgraph_packet_handler(HCI_EVENT_PACKET, (uint8_t *) &packet_sent_event[0], sizeof(packet_sent_event));
|
||||
}
|
||||
|
||||
static void hci_transport_netgraph_process_read(btstack_data_source_t * ds) {
|
||||
// read complete HCI packet
|
||||
char hook[NG_NODESIZ];
|
||||
int bytes_read = NgRecvData(ds->source.fd, (u_char *) hci_packet, HCI_INCOMING_PACKET_BUFFER_SIZE + 1, hook);
|
||||
|
||||
if (bytes_read < 0){
|
||||
log_error("Read failed %d", (int) bytes_read);
|
||||
} else {
|
||||
|
||||
// ignore 'echo' - only accept hci events from 'raw' hook and acl packet from 'acl' hook
|
||||
// - HCI CMDs that are received over 'raw' hook are sent back via 'raw' hook
|
||||
if (strcmp(hook, "raw") == 0){
|
||||
if (hci_packet[0] != HCI_EVENT_PACKET){
|
||||
return;
|
||||
}
|
||||
}
|
||||
// - ACL Packets that are received from driver are also sent via 'raw' hook
|
||||
if (strcmp(hook, "acl") == 0){
|
||||
if (hci_packet[0] != HCI_ACL_DATA_PACKET){
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// track HCI Event Complete for init commands
|
||||
if (hci_packet[0] == HCI_EVENT_PACKET){
|
||||
if (hci_event_packet_get_type(&hci_packet[1]) == HCI_EVENT_COMMAND_COMPLETE){
|
||||
uint8_t todos_before = hci_transport_netgraph_hci_todo_init;
|
||||
switch (hci_event_command_complete_get_command_opcode(&hci_packet[1])){
|
||||
case HCI_OPCODE_HCI_RESET:
|
||||
hci_transport_netgraph_hci_todo_init = HCI_TODO_READ_BD_ADDR | HCI_TODO_READ_LOCAL_SUPPORTED_FEATURES | HCI_TODO_READ_BUFFER_SIZE;
|
||||
break;
|
||||
case HCI_OPCODE_HCI_READ_BD_ADDR:
|
||||
hci_transport_netgraph_hci_todo_init &= ~HCI_TODO_READ_BD_ADDR;
|
||||
break;
|
||||
case HCI_OPCODE_HCI_READ_LOCAL_SUPPORTED_FEATURES:
|
||||
hci_transport_netgraph_hci_todo_init &= ~HCI_TODO_READ_LOCAL_SUPPORTED_FEATURES;
|
||||
break;
|
||||
case HCI_OPCODE_HCI_READ_BUFFER_SIZE:
|
||||
hci_transport_netgraph_hci_todo_init &= ~HCI_TODO_READ_BUFFER_SIZE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if ((todos_before != 0) && (hci_transport_netgraph_hci_todo_init == 0)){
|
||||
// tell ubt0hci to disconnect acl hook to ubt0l2cap
|
||||
char path[NG_NODESIZ];
|
||||
snprintf(path, sizeof(path), "%s:", hci_node_name);
|
||||
if (NgSendAsciiMsg(hci_transport_netgraph_hci_raw_control_socket, path, "%s", "init") < 0) {
|
||||
log_error("Failed to send init to %s", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t packet_len = bytes_read-1u;
|
||||
hci_transport_netgraph_packet_handler(hci_packet[0], &hci_packet[1], packet_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_transport_netgraph_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
|
||||
if (ds->source.fd < 0) return;
|
||||
switch (callback_type){
|
||||
case DATA_SOURCE_CALLBACK_READ:
|
||||
hci_transport_netgraph_process_read(ds);
|
||||
break;
|
||||
case DATA_SOURCE_CALLBACK_WRITE:
|
||||
hci_transport_netgraph_process_write(ds);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: could pass device name
|
||||
static void hci_transport_netgraph_init (const void *transport_config){
|
||||
log_info("init");
|
||||
|
||||
btstack_assert(transport_config != NULL);
|
||||
|
||||
// extract netgraph device name
|
||||
hci_transport_config_netgraph_t * hci_transport_config_netgraph = (hci_transport_config_netgraph_t*) transport_config;
|
||||
hci_node_name = hci_transport_config_netgraph->device_name;
|
||||
|
||||
// set state to off
|
||||
hci_transport_netgraph_tx_state = TX_OFF;
|
||||
}
|
||||
|
||||
static int hci_transport_netgraph_open(void) {
|
||||
|
||||
log_info("open(%s)", hci_node_name);
|
||||
|
||||
int res;
|
||||
struct ngm_rmhook rmh;
|
||||
struct ngm_connect con;
|
||||
char path[NG_NODESIZ];
|
||||
char btstack_node_hci_raw_name[NG_NODESIZ];
|
||||
|
||||
// create hci_raw netgraph node
|
||||
snprintf(btstack_node_hci_raw_name, sizeof(btstack_node_hci_raw_name), "btstack");
|
||||
if (NgMkSockNode(btstack_node_hci_raw_name, &hci_transport_netgraph_hci_raw_control_socket, &hci_transport_netgraph_hci_raw_data_socket) < 0){
|
||||
log_error("Cannot create netgraph node '%s'", btstack_node_hci_raw_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// tell hci node to disconnect raw hook to btsock_hci_raw (ignore result)
|
||||
snprintf(path, sizeof(path), "%s:", hci_node_name);
|
||||
strncpy(rmh.ourhook, "raw", sizeof(rmh.ourhook));
|
||||
res = NgSendMsg(hci_transport_netgraph_hci_raw_control_socket, path, NGM_GENERIC_COOKIE,
|
||||
NGM_RMHOOK, &rmh, sizeof(rmh));
|
||||
log_info("Remove HCI RAW Hook: %d", res);
|
||||
|
||||
// tell hci node to disconnect acl hook to ubt0l2cap (ignore result)
|
||||
snprintf(path, sizeof(path), "%s:", hci_node_name);
|
||||
strncpy(rmh.ourhook, "acl", sizeof(rmh.ourhook));
|
||||
res = NgSendMsg(hci_transport_netgraph_hci_raw_control_socket, path, NGM_GENERIC_COOKIE,
|
||||
NGM_RMHOOK, &rmh, sizeof(rmh));
|
||||
log_info("Remove ACL Hook: %d", res);
|
||||
|
||||
// connect ubth0hci/raw hook
|
||||
snprintf(path, sizeof(path), "%s:", btstack_node_hci_raw_name);
|
||||
snprintf(con.path, sizeof(con.path), "%s:", hci_node_name);
|
||||
strncpy(con.ourhook, "raw", sizeof(con.ourhook));
|
||||
strncpy(con.peerhook, "raw", sizeof(con.peerhook));
|
||||
if (NgSendMsg(hci_transport_netgraph_hci_raw_control_socket, path, NGM_GENERIC_COOKIE,
|
||||
NGM_CONNECT, &con, sizeof(con)) < 0) {
|
||||
log_error("Cannot connect %s%s to %s%s", path, con.ourhook, con.path, con.peerhook);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// connect ubth0hci/acl hook
|
||||
snprintf(path, sizeof(path), "%s:", btstack_node_hci_raw_name);
|
||||
snprintf(con.path, sizeof(con.path), "%s:", hci_node_name);
|
||||
strncpy(con.ourhook, "acl", sizeof(con.ourhook));
|
||||
strncpy(con.peerhook, "acl", sizeof(con.peerhook));
|
||||
if (NgSendMsg(hci_transport_netgraph_hci_raw_control_socket, path, NGM_GENERIC_COOKIE,
|
||||
NGM_CONNECT, &con, sizeof(con)) < 0) {
|
||||
log_error("Cannot connect %s%s to %s%s", path, con.ourhook, con.path, con.peerhook);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// set up HCI RAW data_source
|
||||
btstack_run_loop_set_data_source_fd(&hci_transport_netgraph_data_source_hci_raw, hci_transport_netgraph_hci_raw_data_socket);
|
||||
btstack_run_loop_set_data_source_handler(&hci_transport_netgraph_data_source_hci_raw, &hci_transport_netgraph_process);
|
||||
btstack_run_loop_add_data_source(&hci_transport_netgraph_data_source_hci_raw);
|
||||
btstack_run_loop_enable_data_source_callbacks(&hci_transport_netgraph_data_source_hci_raw, DATA_SOURCE_CALLBACK_READ);
|
||||
|
||||
// init tx state machines
|
||||
hci_transport_netgraph_tx_state = TX_IDLE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hci_transport_netgraph_close(void){
|
||||
// first remove run loop handler
|
||||
btstack_run_loop_remove_data_source(&hci_transport_netgraph_data_source_hci_raw);
|
||||
|
||||
// then close device
|
||||
close(hci_transport_netgraph_data_source_hci_raw.source.fd);
|
||||
hci_transport_netgraph_data_source_hci_raw.source.fd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hci_transport_netgraph_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
|
||||
hci_transport_netgraph_packet_handler = handler;
|
||||
}
|
||||
|
||||
static int hci_transport_netgraph_can_send_now(uint8_t packet_type){
|
||||
UNUSED(packet_type);
|
||||
return hci_transport_netgraph_tx_state == TX_IDLE;
|
||||
}
|
||||
|
||||
static int hci_transport_netgraph_send_packet(uint8_t packet_type, uint8_t * packet, int size) {
|
||||
btstack_assert(hci_transport_netgraph_write_bytes_len == 0);
|
||||
|
||||
// store packet type before actual data and increase size
|
||||
uint8_t * buffer = &packet[-1];
|
||||
uint32_t buffer_size = size + 1;
|
||||
buffer[0] = packet_type;
|
||||
|
||||
// setup async write
|
||||
hci_transport_netgraph_write_bytes_data = buffer;
|
||||
hci_transport_netgraph_write_bytes_len = buffer_size;
|
||||
hci_transport_netgraph_write_packet_type = packet_type;
|
||||
hci_transport_netgraph_tx_state = TX_W4_PACKET_SENT;
|
||||
|
||||
btstack_run_loop_enable_data_source_callbacks(&hci_transport_netgraph_data_source_hci_raw, DATA_SOURCE_CALLBACK_WRITE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const hci_transport_t hci_transport_netgraph = {
|
||||
.name = "Netgraph",
|
||||
.init = &hci_transport_netgraph_init,
|
||||
.open = &hci_transport_netgraph_open,
|
||||
.close = &hci_transport_netgraph_close,
|
||||
.register_packet_handler = &hci_transport_netgraph_register_packet_handler,
|
||||
.can_send_packet_now = &hci_transport_netgraph_can_send_now,
|
||||
.send_packet = &hci_transport_netgraph_send_packet
|
||||
};
|
||||
|
||||
const hci_transport_t * hci_transport_netgraph_instance(void) {
|
||||
return &hci_transport_netgraph;
|
||||
}
|
61
port/freebsd-netgraph/hci_transport_netgraph.h
Normal file
61
port/freebsd-netgraph/hci_transport_netgraph.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
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief TODO
|
||||
*/
|
||||
|
||||
#ifndef HCI_TRANSPORT_NETGRAPH_H
|
||||
#define HCI_TRANSPORT_NETGRAPH_H
|
||||
|
||||
#include "hci_transport.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
hci_transport_config_type_t type;
|
||||
const char *device_name;
|
||||
} hci_transport_config_netgraph_t;
|
||||
|
||||
const hci_transport_t * hci_transport_netgraph_instance(void);
|
||||
|
||||
#if defined __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // HCI_TRANSPORT_NETGRAPH_H
|
275
port/freebsd-netgraph/main.c
Normal file
275
port/freebsd-netgraph/main.c
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* 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 "btstack_config.h"
|
||||
|
||||
#include "ble/le_device_db_tlv.h"
|
||||
#include "bluetooth_company_id.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 "btstack_uart.h"
|
||||
#include "classic/btstack_link_key_db_tlv.h"
|
||||
#include "hci.h"
|
||||
#include "hci_dump.h"
|
||||
#include "hci_dump_posix_fs.h"
|
||||
#include "hci_dump_posix_stdout.h"
|
||||
#include "hci_transport_netgraph.h"
|
||||
|
||||
|
||||
#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 bd_addr_t local_addr;
|
||||
static hci_transport_config_netgraph_t config;
|
||||
|
||||
// shutdown
|
||||
static bool shutdown_triggered;
|
||||
|
||||
int btstack_main(int argc, const char * argv[]);
|
||||
static void local_version_information_handler(uint8_t * packet);
|
||||
|
||||
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;
|
||||
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:
|
||||
if (hci_event_command_complete_get_command_opcode(packet) == HCI_OPCODE_HCI_READ_LOCAL_VERSION_INFORMATION){
|
||||
local_version_information_handler(packet);
|
||||
}
|
||||
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[] = "hu:l:r";
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"logfile", required_argument, NULL, 'l'},
|
||||
{"reset-tlv", no_argument, NULL, 'r'},
|
||||
{"node", required_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 name of netgraph HCI node. Default: ubt0hci",
|
||||
};
|
||||
|
||||
static char *option_arg_name[] = {
|
||||
"",
|
||||
"LOGFILE",
|
||||
"",
|
||||
"NODE",
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
// set default device path
|
||||
config.device_name = "ubt0hci";
|
||||
|
||||
// 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':
|
||||
config.device_name = 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());
|
||||
|
||||
// log into file using HCI_DUMP_PACKETLOGGER format
|
||||
if (log_file_path == NULL){
|
||||
log_file_path = "/tmp/hci_dump.pklg";
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// init HCI
|
||||
const hci_transport_t * transport = hci_transport_netgraph_instance();
|
||||
config.type = HCI_TRANSPORT_CONFIG_USB;
|
||||
hci_init(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