mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-22 16:20:54 +00:00
implemented minimal outgoing-only L2CAP state machine, BT HID connection in test.c working
This commit is contained in:
parent
0b6464c774
commit
87ea0ea477
24
TODO.txt
24
TODO.txt
@ -1,20 +1,20 @@
|
||||
/* new todo file for BTstack */
|
||||
|
||||
UNTIL 13. August 2009 : Google Open Source Jam
|
||||
- implement L2CAP state machine
|
||||
- decide on naming conventions for various layers
|
||||
- provide demos:
|
||||
- BT Scanner: module info, inquiry, remote name
|
||||
- Terminal app with L2CAP support - Python or Java PC demo
|
||||
- evtl. SDP browser
|
||||
- evtl. RFCOMM to BT GPS
|
||||
|
||||
NEXT:
|
||||
- implement client BT API in btstack.h: prefix all functions by bt_$PROTOCOL_*
|
||||
- client/server part using unix domain sockets (portable and fast)
|
||||
- generalize run_loop_add/remove into linked_list_add/remove
|
||||
- client/server part using unix domain sockets (portable and fast)
|
||||
- implement RFCOMM
|
||||
- implement
|
||||
- use linked_list for:
|
||||
- run loop
|
||||
- event handler
|
||||
- data handler
|
||||
- keep track of HCI state (links, inquiries, acl flow control) in linked list
|
||||
- implement L2CAP state machine
|
||||
- implement PAN
|
||||
|
||||
IMPROVE
|
||||
- make data_source_t opaque: data_source_set_fd, data_source_set_cb
|
||||
- implement TimerSource
|
||||
- implement some kind of noitfy mechanism between multiple units
|
||||
- support better handling of multiple parallel socket connections?
|
||||
- callback to announce new connection, allow to store local context pointer
|
||||
|
35
aclocal.m4
vendored
35
aclocal.m4
vendored
@ -1,4 +1,4 @@
|
||||
# generated automatically by aclocal 1.10.2 -*- Autoconf -*-
|
||||
# generated automatically by aclocal 1.10.1 -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
# 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
m4_ifndef([AC_AUTOCONF_VERSION],
|
||||
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
|
||||
m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.63],,
|
||||
m4_if(AC_AUTOCONF_VERSION, [2.63],,
|
||||
[m4_warning([this file was generated for autoconf 2.63.
|
||||
You have another version of autoconf. It may work, but is not guaranteed to.
|
||||
If you have problems, you may need to regenerate the build system entirely.
|
||||
@ -175,7 +175,7 @@ else
|
||||
fi[]dnl
|
||||
])# PKG_CHECK_MODULES
|
||||
|
||||
# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
@ -190,7 +190,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION],
|
||||
[am__api_version='1.10'
|
||||
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
|
||||
dnl require some minimum version. Point them to the right macro.
|
||||
m4_if([$1], [1.10.2], [],
|
||||
m4_if([$1], [1.10.1], [],
|
||||
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
|
||||
])
|
||||
|
||||
@ -204,12 +204,12 @@ m4_define([_AM_AUTOCONF_VERSION], [])
|
||||
# AM_SET_CURRENT_AUTOMAKE_VERSION
|
||||
# -------------------------------
|
||||
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
|
||||
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
|
||||
# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
|
||||
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
|
||||
[AM_AUTOMAKE_VERSION([1.10.2])dnl
|
||||
[AM_AUTOMAKE_VERSION([1.10.1])dnl
|
||||
m4_ifndef([AC_AUTOCONF_VERSION],
|
||||
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
|
||||
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
|
||||
_AM_AUTOCONF_VERSION(AC_AUTOCONF_VERSION)])
|
||||
|
||||
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
|
||||
|
||||
@ -459,28 +459,19 @@ _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
|
||||
|
||||
# Generate code to set up dependency tracking. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008
|
||||
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
#serial 4
|
||||
#serial 3
|
||||
|
||||
# _AM_OUTPUT_DEPENDENCY_COMMANDS
|
||||
# ------------------------------
|
||||
AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
|
||||
[# Autoconf 2.62 quotes --file arguments for eval, but not when files
|
||||
# are listed without --file. Let's play safe and only enable the eval
|
||||
# if we detect the quoting.
|
||||
case $CONFIG_FILES in
|
||||
*\'*) eval set x "$CONFIG_FILES" ;;
|
||||
*) set x $CONFIG_FILES ;;
|
||||
esac
|
||||
shift
|
||||
for mf
|
||||
do
|
||||
[for mf in $CONFIG_FILES; do
|
||||
# Strip MF so we end up with the name of the file.
|
||||
mf=`echo "$mf" | sed -e 's/:.*$//'`
|
||||
# Check whether this is an Automake generated Makefile or not.
|
||||
@ -812,13 +803,13 @@ esac
|
||||
|
||||
# Helper functions for option handling. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 4
|
||||
# serial 3
|
||||
|
||||
# _AM_MANGLE_OPTION(NAME)
|
||||
# -----------------------
|
||||
@ -835,7 +826,7 @@ AC_DEFUN([_AM_SET_OPTION],
|
||||
# ----------------------------------
|
||||
# OPTIONS is a space-separated list of Automake options.
|
||||
AC_DEFUN([_AM_SET_OPTIONS],
|
||||
[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
|
||||
[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
|
||||
|
||||
# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
|
||||
# -------------------------------------------
|
||||
|
184
example/test.c
184
example/test.c
@ -10,199 +10,59 @@
|
||||
#include <strings.h>
|
||||
|
||||
#include "../src/btstack.h"
|
||||
#include "../src/linked_list.h"
|
||||
#include "../src/run_loop.h"
|
||||
#include "../src/socket_connection.h"
|
||||
#include "../src/hci.h"
|
||||
#include "../src/l2cap.h"
|
||||
|
||||
hci_con_handle_t con_handle_out = 0;
|
||||
hci_con_handle_t con_handle_in = 0;
|
||||
uint16_t dest_cid;
|
||||
uint16_t local_cid;
|
||||
|
||||
#define BT_HID
|
||||
// #define POWER_CYCLE_TEST
|
||||
// #define MITM
|
||||
void acl_handler(uint8_t *packet, uint16_t size){
|
||||
// just dump data
|
||||
hexdump( packet, size );
|
||||
}
|
||||
|
||||
|
||||
void event_handler(uint8_t *packet, int size){
|
||||
void event_handler(uint8_t *packet, uint16_t size){
|
||||
// printf("Event type: %x, opcode: %x, other %x\n", packet[0], packet[3] | packet[4] << 8);
|
||||
|
||||
#if defined(BT_HID) || defined(MITM)
|
||||
bd_addr_t addr = {0x00, 0x03, 0xc9, 0x3d, 0x77, 0x43 }; // Think Outside Keyboard
|
||||
|
||||
// bt stack activated, get started
|
||||
if (packet[0] == HCI_EVENT_BTSTACK_WORKING ||
|
||||
(packet[0] == HCI_EVENT_BTSTACK_STATE && packet[2] == HCI_STATE_WORKING)) {
|
||||
bt_send_cmd(&hci_write_class_of_device, 0x7A020C); // used on iPhone
|
||||
}
|
||||
|
||||
if ( COMMAND_COMPLETE_EVENT(packet, hci_write_class_of_device) ) {
|
||||
bt_send_cmd(&hci_write_local_name, "BT in the Middle");
|
||||
bt_send_cmd(&hci_write_local_name, "BTstack-Test");
|
||||
}
|
||||
|
||||
// set local name
|
||||
if ( COMMAND_COMPLETE_EVENT(packet, hci_write_local_name) ) {
|
||||
#if 1
|
||||
bt_send_cmd(&hci_write_authentication_enable, 1);
|
||||
}
|
||||
|
||||
// use pairing
|
||||
if ( COMMAND_COMPLETE_EVENT(packet, hci_write_authentication_enable) ) {
|
||||
#endif
|
||||
#if 0
|
||||
bt_send_cmd(&hci_write_inquiry_mode, 2);
|
||||
}
|
||||
|
||||
// inform about pin code request
|
||||
if (packet[0] == HCI_EVENT_PIN_CODE_REQUEST){
|
||||
printf("Please enter PIN 1234 on remote device\n");
|
||||
}
|
||||
|
||||
// connect to device at addr
|
||||
if ( COMMAND_COMPLETE_EVENT(packet, hci_write_inquiry_mode) ) {
|
||||
#endif
|
||||
#if 0
|
||||
bt_send_cmd(&hci_set_event_mask, 0xffffffff, 0x1fffffff);
|
||||
}
|
||||
|
||||
uint8_t eir[] = {
|
||||
0x0d, 0x09, 0x4d, 0x69, 0x6c, 0x61, 0x73, 0x20, 0x69, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x0f, 0x02,
|
||||
0x00, 0x12, 0x1f, 0x11, 0x07, 0x11, 0x2f, 0x11, 0x0a, 0x11, 0x16, 0x11, 0x15, 0x11, 0x27, 0xff,
|
||||
0x00, 0x4c, 0x02, 0x24, 0x02, 0x86, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
if ( COMMAND_COMPLETE_EVENT(packet, hci_set_event_mask) ) {
|
||||
#endif
|
||||
#if 0
|
||||
bt_send_cmd(&hci_write_extended_inquiry_response, 0, eir);
|
||||
}
|
||||
if ( COMMAND_COMPLETE_EVENT(packet, hci_write_extended_inquiry_response) ) {
|
||||
#endif
|
||||
#if 0
|
||||
bt_send_cmd(&hci_write_simple_pairing_mode, 1);
|
||||
}
|
||||
if ( COMMAND_COMPLETE_EVENT(packet, hci_write_simple_pairing_mode) ) {
|
||||
#endif
|
||||
#if 0
|
||||
bt_send_cmd(&hci_inquiry, HCI_INQUIRY_LAP, 15, 0);
|
||||
}
|
||||
if (packet[0] == HCI_EVENT_INQUIRY_COMPLETE)
|
||||
#endif
|
||||
#if 1
|
||||
bt_send_cmd(&hci_create_connection, &addr, 0x18, 0, 0, 0, 0);
|
||||
#endif
|
||||
}
|
||||
if (packet[0] == HCI_EVENT_CONNECTION_REQUEST){
|
||||
bt_flip_addr(addr, &packet[2]);
|
||||
bt_send_cmd(&hci_accept_connection_request, &addr, 1);
|
||||
l2cap_create_channel(addr, 0x13, event_handler, acl_handler);
|
||||
}
|
||||
|
||||
if (packet[0] == HCI_EVENT_L2CAP_CHANNEL_OPENED){
|
||||
printf("Channel successfully opened, handle 0x%02x, local cid 0x%02x\n", READ_BT_16(packet, 2), READ_BT_16(packet, 4));;
|
||||
}
|
||||
}
|
||||
|
||||
if (packet[0] == HCI_EVENT_PIN_CODE_REQUEST){
|
||||
printf("Please enter PIN 1234 on remote device\n");
|
||||
}
|
||||
|
||||
// connection established -> start L2CAP conection
|
||||
if (packet[0] == HCI_EVENT_CONNECTION_COMPLETE){
|
||||
if (packet[2] == 0){
|
||||
// get new connection handle
|
||||
if (! con_handle_out) {
|
||||
con_handle_out = READ_BT_16(packet, 3);
|
||||
} else {
|
||||
con_handle_in = READ_BT_16(packet, 3);
|
||||
}
|
||||
#ifndef MITM
|
||||
// request l2cap connection
|
||||
printf("> CONNECTION REQUEST\n");
|
||||
local_cid = l2cap_next_local_cid();
|
||||
bt_send_l2cap_signaling_packet(con_handle_out, CONNECTION_REQUEST, l2cap_next_sig_id(), 0x13, local_cid);
|
||||
#else
|
||||
printf("Connected to target device, please start!\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef POWER_CYCLE_TEST
|
||||
if (packet[0] == HCI_EVENT_BTSTACK_WORKING) {
|
||||
bt_send_cmd(&hci_inquiry, HCI_INQUIRY_LAP, 10, 0);
|
||||
}
|
||||
if (packet[0] == HCI_EVENT_INQUIRY_COMPLETE){
|
||||
// power cycle
|
||||
hci_power_control( HCI_POWER_OFF );
|
||||
//
|
||||
printf ("Power off!\n");
|
||||
sleep(10);
|
||||
printf ("Restart!\n");
|
||||
hci_power_control( HCI_POWER_ON );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void acl_handler(uint8_t *packet, int size){
|
||||
|
||||
#ifdef MITM
|
||||
// forward packet on "other" connection
|
||||
hci_con_handle_t incoming_hdl = READ_BT_16(packet, 0) & 0xfff;
|
||||
hci_con_handle_t outgoing_hdl = 0;
|
||||
#if 0
|
||||
if (incoming_hdl == con_handle_in){
|
||||
outgoing_hdl = con_handle_out;
|
||||
} else if (incoming_hdl == con_handle_out){
|
||||
outgoing_hdl = con_handle_in;
|
||||
} else {
|
||||
printf("Incoming acl packet on handle %u\n!", incoming_hdl);
|
||||
}
|
||||
#else
|
||||
outgoing_hdl = incoming_hdl;
|
||||
#endif
|
||||
if (outgoing_hdl){
|
||||
bt_store_16( packet, 0, (READ_BT_16(packet, 0) & 0xf000) | outgoing_hdl);
|
||||
bt_send_acl_packet(packet, size);
|
||||
}
|
||||
|
||||
#else
|
||||
uint16_t source_cid;
|
||||
uint16_t result;
|
||||
uint8_t config_options[] = { 1, 2, 150, 0}; // mtu = 48
|
||||
// connection response
|
||||
if (packet[8] == CONNECTION_RESPONSE){
|
||||
dest_cid = READ_BT_16(packet, 12);
|
||||
source_cid = READ_BT_16(packet, 14);
|
||||
result = READ_BT_16(packet, 16);
|
||||
uint16_t status = READ_BT_16(packet, 18);
|
||||
printf("< CONNECTION_RESPONSE: id %u, dest cid %u, src cid %u, result %u, status %u\n", packet[9], dest_cid, source_cid, result, status);
|
||||
if (result == 0){
|
||||
// printf("> CONFIGURE_REQUEST: id %u\n", sig_seq_nr);
|
||||
bt_send_l2cap_signaling_packet(con_handle_out, CONFIGURE_REQUEST, l2cap_next_sig_id(), dest_cid, 0, 4, &config_options);
|
||||
}
|
||||
}
|
||||
else if (packet[8] == CONFIGURE_RESPONSE){
|
||||
source_cid = READ_BT_16(packet, 12);
|
||||
uint16_t flags = READ_BT_16(packet, 14);
|
||||
result = READ_BT_16(packet, 16);
|
||||
printf("< CONFIGURE_RESPONSE: id %u, src cid %u, flags %u, result %u!!!\n", packet[9], source_cid, flags, result);
|
||||
hexdump(&packet[18], size-18);
|
||||
}
|
||||
else if (packet[8] == CONFIGURE_REQUEST){
|
||||
printf("< CONFIGURE_REQUEST: id %u\n", packet[9]);
|
||||
hexdump(&packet[16], size-16);
|
||||
printf("> CONFIGURE_RESPONSE: id %u\n", packet[9]);
|
||||
bt_send_l2cap_signaling_packet(con_handle_out, CONFIGURE_RESPONSE, packet[9], local_cid, 0, 0, size - 16, &packet[16]);
|
||||
}
|
||||
else {
|
||||
printf("Unknown ACL ^^^ \n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int main (int argc, const char * argv[]){
|
||||
bt_open();
|
||||
bt_register_event_packet_handler(event_handler);
|
||||
bt_register_acl_packet_handler (acl_handler);
|
||||
bt_send_cmd(&hci_set_power_mode, HCI_POWER_ON );
|
||||
run_loop_execute();
|
||||
bt_close();
|
||||
|
@ -14,9 +14,9 @@
|
||||
9C00F86510191097008DAB17 /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C00F86210191097008DAB17 /* utils.c */; };
|
||||
9C00F87310191130008DAB17 /* l2cap_signaling.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C00F87210191130008DAB17 /* l2cap_signaling.c */; };
|
||||
9C00F87410191130008DAB17 /* l2cap_signaling.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C00F87210191130008DAB17 /* l2cap_signaling.c */; };
|
||||
9C05FC971020D3F300255261 /* socket_connection.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C00F7301017ACC3008DAB17 /* socket_connection.c */; };
|
||||
9C1F0E9A0FDAE023008F472F /* run_loop.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C1F0E980FDAE023008F472F /* run_loop.c */; };
|
||||
9C2071F310014D3200A07EA4 /* hci_transport_usb.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C2071F210014D3200A07EA4 /* hci_transport_usb.c */; };
|
||||
9C20720F10025E0500A07EA4 /* libusb-1.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 9C20720E10025E0500A07EA4 /* libusb-1.0.dylib */; };
|
||||
9C46FC390FA906F700ABEF05 /* hci.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C46FC340FA906F700ABEF05 /* hci.c */; };
|
||||
9C46FC3A0FA906F700ABEF05 /* hci_transport_h4.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C46FC360FA906F700ABEF05 /* hci_transport_h4.c */; };
|
||||
9C7B5AC0100BD3340065D87E /* linked_list.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C7B5ABF100BD3340065D87E /* linked_list.c */; };
|
||||
@ -60,7 +60,6 @@
|
||||
9C1F0E980FDAE023008F472F /* run_loop.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = run_loop.c; path = src/run_loop.c; sourceTree = "<group>"; };
|
||||
9C1F0E990FDAE023008F472F /* run_loop.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = run_loop.h; path = src/run_loop.h; sourceTree = "<group>"; };
|
||||
9C2071F210014D3200A07EA4 /* hci_transport_usb.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = hci_transport_usb.c; path = src/hci_transport_usb.c; sourceTree = "<group>"; };
|
||||
9C20720E10025E0500A07EA4 /* libusb-1.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libusb-1.0.dylib"; path = "/usr/local/lib/libusb-1.0.dylib"; sourceTree = "<absolute>"; };
|
||||
9C46FC340FA906F700ABEF05 /* hci.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = hci.c; path = src/hci.c; sourceTree = "<group>"; };
|
||||
9C46FC350FA906F700ABEF05 /* hci.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = hci.h; path = src/hci.h; sourceTree = "<group>"; };
|
||||
9C46FC360FA906F700ABEF05 /* hci_transport_h4.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = hci_transport_h4.c; path = src/hci_transport_h4.c; sourceTree = "<group>"; };
|
||||
@ -90,7 +89,6 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9C20720F10025E0500A07EA4 /* libusb-1.0.dylib in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -113,7 +111,6 @@
|
||||
1AB674ADFE9D54B511CA2CBB /* Products */,
|
||||
9CC152C61009052100223347 /* config.h */,
|
||||
9CA3C0900FB8B3C4005F48DE /* TODO.txt */,
|
||||
9C20720E10025E0500A07EA4 /* libusb-1.0.dylib */,
|
||||
);
|
||||
name = project;
|
||||
sourceTree = "<group>";
|
||||
@ -271,6 +268,7 @@
|
||||
9C00F7D81019082F008DAB17 /* hci_cmds.c in Sources */,
|
||||
9C00F86410191097008DAB17 /* utils.c in Sources */,
|
||||
9C00F87310191130008DAB17 /* l2cap_signaling.c in Sources */,
|
||||
9C05FC971020D3F300255261 /* socket_connection.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
117
src/btstack.c
117
src/btstack.c
@ -26,12 +26,12 @@ static connection_t *btstack_connection = NULL;
|
||||
static linked_list_t l2cap_channels = NULL;
|
||||
|
||||
/** prototypes */
|
||||
static void dummy_handler(uint8_t *packet, int size);
|
||||
static void dummy_handler(uint8_t *packet, uint16_t size);
|
||||
int btstack_packet_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t size);
|
||||
|
||||
/* callback to L2CAP layer */
|
||||
static void (*event_packet_handler)(uint8_t *packet, int size) = dummy_handler;
|
||||
static void (*acl_packet_handler) (uint8_t *packet, int size) = dummy_handler;
|
||||
static void (*event_packet_handler)(uint8_t *packet, uint16_t size) = dummy_handler;
|
||||
static void (*acl_packet_handler) (uint8_t *packet, uint16_t size) = dummy_handler;
|
||||
|
||||
// init BTstack library
|
||||
int bt_open(){
|
||||
@ -52,18 +52,21 @@ int bt_close(){
|
||||
void l2cap_event_handler( uint8_t *packet, uint16_t size ){
|
||||
// handle connection complete events
|
||||
if (packet[0] == HCI_EVENT_CONNECTION_COMPLETE && packet[2] == 0){
|
||||
linked_item_t *it;
|
||||
bd_addr_t address;
|
||||
bt_flip_addr(address, &packet[5]);
|
||||
|
||||
linked_item_t *it;
|
||||
for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
|
||||
l2cap_channel_t * chan = (l2cap_channel_t *) it;
|
||||
if ( ! BD_ADDR_CMP( chan->address, address) ){
|
||||
if (chan->state == L2CAP_STATE_CLOSED) {
|
||||
chan->state = L2CAP_STATE_CONNECTED;
|
||||
chan->handle = READ_BT_16(packet, 3);
|
||||
chan->sig_id = l2cap_next_sig_id();
|
||||
chan->local_cid = l2cap_next_local_cid();
|
||||
|
||||
bt_send_l2cap_signaling_packet( chan->handle, CONNECTION_REQUEST, chan->sig_id, chan->psm, chan->local_cid);
|
||||
|
||||
chan->state = L2CAP_STATE_WAIT_CONNECT_RSP;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -71,20 +74,94 @@ void l2cap_event_handler( uint8_t *packet, uint16_t size ){
|
||||
// handle disconnection complete events
|
||||
// TODO ...
|
||||
}
|
||||
void l2cap_data_handler( uint8_t *packet, uint16_t size ){
|
||||
// Get Channel ID
|
||||
|
||||
void l2cap_signaling_handler(l2cap_channel_t *channel, uint8_t *packet, uint16_t size){
|
||||
|
||||
static uint8_t config_options[] = { 1, 2, 150, 0}; // mtu = 48
|
||||
|
||||
uint8_t code = READ_L2CAP_SIGNALING_CODE( packet );
|
||||
uint8_t identifier = READ_L2CAP_SIGNALING_IDENTIFIER( packet );
|
||||
|
||||
switch (channel->state) {
|
||||
|
||||
case L2CAP_STATE_WAIT_CONNECT_RSP:
|
||||
switch (code){
|
||||
case CONNECTION_RESPONSE:
|
||||
if ( READ_BT_16 (packet, L2CAP_SIGNALING_DATA_OFFSET+3) == 0){
|
||||
// successfull connection
|
||||
channel->dest_cid = READ_BT_16(packet, L2CAP_SIGNALING_DATA_OFFSET + 0);
|
||||
channel->sig_id = l2cap_next_sig_id();
|
||||
bt_send_l2cap_signaling_packet(channel->handle, CONFIGURE_REQUEST, channel->sig_id, channel->dest_cid, 0, 4, &config_options);
|
||||
channel->state = L2CAP_STATE_WAIT_CONFIG_REQ_RSP;
|
||||
} else {
|
||||
// TODO implement failed
|
||||
}
|
||||
break;
|
||||
// TODO implement other signaling packets
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_STATE_WAIT_CONFIG_REQ_RSP:
|
||||
switch (code) {
|
||||
case CONFIGURE_RESPONSE:
|
||||
channel->state = L2CAP_STATE_WAIT_CONFIG_REQ;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_STATE_WAIT_CONFIG_REQ:
|
||||
switch (code) {
|
||||
case CONFIGURE_REQUEST:
|
||||
|
||||
// accept the other's configuration options
|
||||
bt_send_l2cap_signaling_packet(channel->handle, CONFIGURE_RESPONSE, identifier, channel->dest_cid, 0, 0, size - 16, &packet[16]);
|
||||
|
||||
channel->state = L2CAP_STATE_OPEN;
|
||||
|
||||
// notify client
|
||||
uint8_t event[6];
|
||||
event[0] = HCI_EVENT_L2CAP_CHANNEL_OPENED;
|
||||
event[1] = 4;
|
||||
bt_store_16(event, 2, channel->handle);
|
||||
bt_store_16(event, 4, channel->local_cid);
|
||||
(*channel->event_callback)(event, sizeof(event));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void l2cap_data_handler( uint8_t *packet, uint16_t size ){
|
||||
|
||||
// Get Channel ID
|
||||
uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet);
|
||||
|
||||
// Get Connection
|
||||
hci_con_handle_t handle = READ_ACL_CONNECTION_HANDLE(packet);
|
||||
|
||||
// Signaling Packet?
|
||||
if (channel_id == 1) {
|
||||
// Get Signaling Identifier
|
||||
uint8_t sig_id = READ_L2CAP_SIGNALING_IDENTIFIER(packet);
|
||||
|
||||
// Find channel for this sig_id and connection handle
|
||||
linked_item_t *it;
|
||||
for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
|
||||
l2cap_channel_t * chan = (l2cap_channel_t *) it;
|
||||
if ( chan->sig_id == sig_id && chan->handle == handle) {
|
||||
l2cap_signaling_handler( chan, packet, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get Signaling Identifier
|
||||
|
||||
// Find channel for this sig_id
|
||||
|
||||
// Handle CONNECTION_RESPONSE
|
||||
|
||||
// Handle CONFIGURE_RESPONSE
|
||||
|
||||
// Handle CONFIGURE_REQUEST
|
||||
// Find channel for this channel_id and connection handle
|
||||
linked_item_t *it;
|
||||
for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
|
||||
l2cap_channel_t * channel = (l2cap_channel_t *) it;
|
||||
if ( channel->local_cid == channel_id && channel->handle == handle) {
|
||||
(*channel->data_callback)(packet, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int btstack_packet_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t size){
|
||||
@ -128,15 +205,15 @@ int bt_send_l2cap_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMM
|
||||
return bt_send_acl_packet(l2cap_sig_buffer, len);
|
||||
}
|
||||
|
||||
static void dummy_handler(uint8_t *packet, int size){
|
||||
static void dummy_handler(uint8_t *packet, uint16_t size){
|
||||
}
|
||||
|
||||
// register packet and event handler
|
||||
void bt_register_event_packet_handler(void (*handler)(uint8_t *packet, int size)){
|
||||
void bt_register_event_packet_handler(void (*handler)(uint8_t *packet, uint16_t size)){
|
||||
event_packet_handler = handler;
|
||||
}
|
||||
|
||||
void bt_register_acl_packet_handler (void (*handler)(uint8_t *packet, int size)){
|
||||
void bt_register_acl_packet_handler (void (*handler)(uint8_t *packet, uint16_t size)){
|
||||
acl_packet_handler = handler;
|
||||
}
|
||||
|
||||
@ -163,7 +240,7 @@ l2cap_channel_t * l2cap_create_channel(bd_addr_t address, uint16_t psm, void (*e
|
||||
|
||||
// send connection request
|
||||
// BD_ADDR, Packet_Type, Page_Scan_Repetition_Mode, Reserved, Clock_Offset, Allow_Role_Switch
|
||||
bt_send_cmd(&hci_create_connection, &address, 0x18, 0, 0, 0, 0);
|
||||
bt_send_cmd(&hci_create_connection, address, 0x18, 0, 0, 0, 0);
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
@ -27,8 +27,8 @@ int bt_send_cmd(hci_cmd_t *cmd, ...);
|
||||
int bt_send_acl_packet(uint8_t *packet, int size);
|
||||
|
||||
// register packet and event handler
|
||||
void bt_register_event_packet_handler(void (*handler)(uint8_t *packet, int size));
|
||||
void bt_register_acl_packet_handler (void (*handler)(uint8_t *packet, int size));
|
||||
void bt_register_event_packet_handler(void (*handler)(uint8_t *packet, uint16_t size));
|
||||
void bt_register_acl_packet_handler (void (*handler)(uint8_t *packet, uint16_t size));
|
||||
|
||||
// TODO: temp
|
||||
int bt_send_l2cap_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...);
|
||||
|
@ -48,7 +48,7 @@ static int daemon_packet_handler(connection_t *connection, uint8_t packet_type,
|
||||
// printf("ACL from client: ");
|
||||
break;
|
||||
}
|
||||
hexdump(data, length);
|
||||
// hexdump(data, length);
|
||||
// printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -74,6 +74,9 @@
|
||||
#define HCI_EVENT_BTSTACK_WORKING 0x80
|
||||
#define HCI_EVENT_BTSTACK_STATE 0x81
|
||||
|
||||
// data: event (8), len(8), handle(16), channel(16)
|
||||
#define HCI_EVENT_L2CAP_CHANNEL_OPENED 0x82
|
||||
|
||||
#define COMMAND_COMPLETE_EVENT(event,cmd) ( event[0] == HCI_EVENT_COMMAND_COMPLETE && READ_BT_16(event,3) == cmd.opcode)
|
||||
|
||||
/**
|
||||
|
@ -17,6 +17,8 @@
|
||||
// ACL Data 0 0 0x82 Bulk (IN) 32/64
|
||||
// ACL Data 0 0 0x02 Bulk (OUT) 32/64
|
||||
|
||||
#ifdef HAVE_TRANSPORT_USB
|
||||
|
||||
#include <stdio.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h> /* UNIX standard function definitions */
|
||||
@ -338,3 +340,5 @@ hci_transport_t * hci_transport_usb_instance() {
|
||||
}
|
||||
return hci_transport_usb;
|
||||
}
|
||||
|
||||
#endif
|
17
src/l2cap.h
17
src/l2cap.h
@ -15,20 +15,23 @@
|
||||
#define L2CAP_SIG_ID_INVALID 0
|
||||
|
||||
typedef enum {
|
||||
L2CAP_STATE_CLOSED, // no baseband
|
||||
L2CAP_STATE_CONNECTED, // baseband connection
|
||||
L2CAP_STATE_W4_L2CA_CONNECTION_RSP, // from application
|
||||
L2CAP_STATE_W4_L2CAP_CONNECTION_RSP, // from peer
|
||||
L2CAP_STATE_CONFIG,
|
||||
L2CAP_STATE_CLOSED, // no baseband
|
||||
L2CAP_STATE_WAIT_CONNECT, // from application
|
||||
L2CAP_STATE_WAIT_CONNECT_RSP, // from peer
|
||||
L2CAP_STATE_WAIT_CONFIG_REQ_RSP,
|
||||
L2CAP_STATE_WAIT_CONFIG_REQ,
|
||||
L2CAP_STATE_OPEN,
|
||||
L2CAP_STATE_W4_L2CA_DISCON_RSP, // from application
|
||||
L2CAP_STATE_W4_L2CAP_DISCON_RSP, // from peer
|
||||
L2CAP_STATE_WAIT_DISCONNECT, // from application
|
||||
} L2CAP_STATE;
|
||||
|
||||
typedef struct {
|
||||
// linked list - assert: first field
|
||||
linked_item_t item;
|
||||
|
||||
L2CAP_STATE state;
|
||||
uint8_t sig_id;
|
||||
uint16_t local_cid;
|
||||
uint16_t dest_cid;
|
||||
bd_addr_t address;
|
||||
uint16_t psm;
|
||||
hci_con_handle_t handle;
|
||||
|
18
src/utils.h
18
src/utils.h
@ -32,6 +32,22 @@ typedef uint8_t link_key_t[LINK_KEY_LEN];
|
||||
#define READ_BT_24( buffer, pos) ( ((uint32_t) buffer[pos]) | (((uint32_t)buffer[pos+1]) << 8) | (((uint32_t)buffer[pos+2]) << 16))
|
||||
#define READ_BT_32( buffer, pos) ( ((uint32_t) buffer[pos]) | (((uint32_t)buffer[pos+1]) << 8) | (((uint32_t)buffer[pos+2]) << 16) | (((uint32_t) buffer[pos+3])) << 24)
|
||||
|
||||
// ACL Packet
|
||||
#define READ_ACL_CONNECTION_HANDLE( buffer ) ( READ_BT_16(buffer,0) & 0x0fff)
|
||||
#define READ_ACL_FLAGS( buffer ) ( buffer[1] >> 4 )
|
||||
#define READ_ACL_LENGTH( buffer ) (READ_BT_16(buffer, 2)
|
||||
|
||||
// L2CAP Packet
|
||||
#define READ_L2CAP_LENGTH(buffer) ( READ_BT_16(buffer, 4))
|
||||
#define READ_L2CAP_CHANNEL_ID(buffer) ( READ_BT_16(buffer, 6))
|
||||
|
||||
// L2CAP Signaling Packet
|
||||
#define READ_L2CAP_SIGNALING_CODE( buffer ) (buffer[ 8])
|
||||
#define READ_L2CAP_SIGNALING_IDENTIFIER( buffer ) (buffer[ 9])
|
||||
#define READ_L2CAP_SIGNALING_LENGTH( buffer ) (buffer[10])
|
||||
|
||||
#define L2CAP_SIGNALING_DATA_OFFSET 12
|
||||
|
||||
void bt_store_16(uint8_t *buffer, uint16_t pos, uint16_t value);
|
||||
void bt_store_32(uint8_t *buffer, uint16_t pos, uint32_t value);
|
||||
void bt_flip_addr(bd_addr_t dest, bd_addr_t src);
|
||||
@ -40,4 +56,4 @@ void hexdump(void *data, int size);
|
||||
void print_bd_addr( bd_addr_t addr);
|
||||
|
||||
#define BD_ADDR_CMP(a,b) memcmp(a,b, BD_ADDR_LEN)
|
||||
#define BD_ADDR_COPY(dest,src) memcpy(dest,src,BD_ADDR_LEN)
|
||||
#define BD_ADDR_COPY(dest,src) memcpy(dest,src,BD_ADDR_LEN)
|
||||
|
Loading…
x
Reference in New Issue
Block a user