mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-02-22 06:41:17 +00:00
use socket_connection also for client, drop duplicate code in BTstack.c
This commit is contained in:
parent
70f86d379d
commit
dc369792cb
154
src/btstack.c
154
src/btstack.c
@ -9,45 +9,23 @@
|
||||
#include "btstack.h"
|
||||
|
||||
#include "l2cap.h"
|
||||
#include "socket_connection.h"
|
||||
#include "run_loop.h"
|
||||
#include <netdb.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct packet_header {
|
||||
uint16_t length;
|
||||
uint8_t type;
|
||||
uint8_t data[0];
|
||||
} packet_header_t;
|
||||
|
||||
typedef enum {
|
||||
SOCKET_W4_HEADER,
|
||||
SOCKET_W4_DATA,
|
||||
} SOCKET_STATE;
|
||||
|
||||
typedef struct connection {
|
||||
data_source_t ds; // used for run loop
|
||||
linked_item_t item; // used for connection list
|
||||
SOCKET_STATE state;
|
||||
uint16_t bytes_read;
|
||||
uint16_t bytes_to_read;
|
||||
uint8_t buffer[3+3+255]; // max HCI CMD + packet_header
|
||||
} connection_t;
|
||||
|
||||
uint8_t hci_cmd_buffer[3+255];
|
||||
|
||||
uint8_t l2cap_sig_buffer[48];
|
||||
|
||||
|
||||
static void dummy_handler(uint8_t *packet, int size);
|
||||
static int btstack_socket_process(struct data_source *ds, int ready);
|
||||
|
||||
static int btstack_socket = -1;
|
||||
static connection_t *btstack_connection = NULL;
|
||||
static const int btstack_port = 1919;
|
||||
|
||||
/** prototypes */
|
||||
static void dummy_handler(uint8_t *packet, int 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;
|
||||
@ -56,126 +34,44 @@ static void (*acl_packet_handler) (uint8_t *packet, int size) = dummy_handler;
|
||||
|
||||
// init BTstack library
|
||||
int bt_open(){
|
||||
// TCP
|
||||
struct protoent* tcp = getprotobyname("tcp");
|
||||
|
||||
btstack_socket = socket(PF_INET, SOCK_STREAM, tcp->p_proto);
|
||||
if(btstack_socket == -1){
|
||||
return -1;
|
||||
}
|
||||
// localhost
|
||||
struct sockaddr_in btdaemon_address;
|
||||
btdaemon_address.sin_family = AF_INET;
|
||||
btdaemon_address.sin_port = htons(btstack_port);
|
||||
struct hostent* localhost = gethostbyname("localhost");
|
||||
if(!localhost){
|
||||
return -1;
|
||||
}
|
||||
// connect
|
||||
char* addr = localhost->h_addr_list[0];
|
||||
memcpy(&btdaemon_address.sin_addr.s_addr, addr, sizeof addr);
|
||||
if(connect(btstack_socket, (struct sockaddr*)&btdaemon_address, sizeof btdaemon_address) == -1){
|
||||
return -1;
|
||||
}
|
||||
|
||||
// register with run loop
|
||||
btstack_connection = malloc( sizeof(connection_t));
|
||||
if (btstack_connection == NULL) return -1;
|
||||
btstack_connection->ds.fd = btstack_socket;
|
||||
btstack_connection->ds.process = btstack_socket_process;
|
||||
run_loop_add(&btstack_connection->ds);
|
||||
|
||||
// init state machine
|
||||
btstack_connection->state = SOCKET_W4_HEADER;
|
||||
btstack_connection->bytes_read = 0;
|
||||
btstack_connection->bytes_to_read = sizeof(packet_header_t);
|
||||
|
||||
socket_connection_register_packet_callback(btstack_packet_handler);
|
||||
btstack_connection = socket_connection_open_tcp();
|
||||
if (!btstack_connection) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// stop using BTstack library
|
||||
int bt_close(){
|
||||
if (btstack_socket < 0) return 0;
|
||||
shutdown(btstack_socket, SHUT_RDWR);
|
||||
if (btstack_connection) {
|
||||
run_loop_remove(&btstack_connection->ds);
|
||||
free( btstack_connection );
|
||||
btstack_connection = NULL;
|
||||
return socket_connection_close_tcp(btstack_connection);
|
||||
}
|
||||
|
||||
int btstack_packet_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t size){
|
||||
switch (packet_type){
|
||||
case HCI_EVENT_PACKET:
|
||||
(*event_packet_handler)(data, size);
|
||||
break;
|
||||
case HCI_ACL_DATA_PACKET:
|
||||
(*acl_packet_handler)(data, size);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// run_loop based data handling
|
||||
int btstack_socket_process(struct data_source *ds, int ready) {
|
||||
connection_t *conn = (connection_t *) ds;
|
||||
int bytes_read = read(ds->fd, &conn->buffer[conn->bytes_read], conn->bytes_to_read);
|
||||
if (bytes_read <= 0){
|
||||
// free
|
||||
run_loop_remove(&conn->ds);
|
||||
free(conn);
|
||||
// TODO notify client of cailed daemon connection!
|
||||
return 0;
|
||||
}
|
||||
conn->bytes_read += bytes_read;
|
||||
conn->bytes_to_read -= bytes_read;
|
||||
hexdump( conn->buffer, conn->bytes_read);
|
||||
if (conn->bytes_to_read > 0) {
|
||||
return 0;
|
||||
}
|
||||
switch (conn->state){
|
||||
case SOCKET_W4_HEADER:
|
||||
conn->state = SOCKET_W4_DATA;
|
||||
conn->bytes_to_read = READ_BT_16( conn->buffer, 0);
|
||||
break;
|
||||
case SOCKET_W4_DATA:
|
||||
// process packet !!!
|
||||
switch (conn->buffer[2]){
|
||||
case HCI_EVENT_PACKET:
|
||||
(*event_packet_handler)(&conn->buffer[sizeof(packet_header_t)], READ_BT_16( conn->buffer, 0));
|
||||
break;
|
||||
case HCI_ACL_DATA_PACKET:
|
||||
(*acl_packet_handler)(&conn->buffer[sizeof(packet_header_t)], READ_BT_16( conn->buffer, 0));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// wait for next packet
|
||||
conn->state = SOCKET_W4_HEADER;
|
||||
conn->bytes_read = 0;
|
||||
conn->bytes_to_read = sizeof(packet_header_t);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// send hci cmd packet
|
||||
int bt_send_cmd(hci_cmd_t *cmd, ...){
|
||||
va_list argptr;
|
||||
va_start(argptr, cmd);
|
||||
uint16_t len = hci_create_cmd_internal(hci_cmd_buffer, cmd, argptr);
|
||||
va_end(argptr);
|
||||
packet_header_t header;
|
||||
bt_store_16( (uint8_t*) &header.length, 0, len);
|
||||
header.type = HCI_COMMAND_DATA_PACKET;
|
||||
hexdump( (uint8_t*)&header, sizeof(header));
|
||||
write(btstack_socket, (uint8_t*)&header, sizeof(header));
|
||||
hexdump( hci_cmd_buffer, len);
|
||||
write(btstack_socket, hci_cmd_buffer, len);
|
||||
return len;
|
||||
socket_connection_send_packet(btstack_connection, HCI_COMMAND_DATA_PACKET, hci_cmd_buffer, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// send hci acl packet
|
||||
int bt_send_acl_packet(uint8_t *packet, int size){
|
||||
packet_header_t header;
|
||||
bt_store_16( (uint8_t*) &header.length, 0, size);
|
||||
header.type = HCI_ACL_DATA_PACKET;
|
||||
hexdump( (uint8_t*)&header, sizeof(header));
|
||||
write(btstack_socket, (uint8_t*)&header, sizeof(header));
|
||||
hexdump( hci_cmd_buffer, size);
|
||||
write(btstack_socket, packet, size);
|
||||
socket_connection_send_packet(btstack_connection, HCI_ACL_DATA_PACKET, hci_cmd_buffer, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ int main (int argc, const char * argv[]){
|
||||
// @TODO make port and/or socket configurable per config.h
|
||||
|
||||
// create server
|
||||
socket_connection_create_tcp(1919);
|
||||
socket_connection_create_tcp(BTSTACK_PORT);
|
||||
socket_connection_register_packet_callback(daemon_packet_handler);
|
||||
|
||||
// go!
|
||||
|
@ -9,22 +9,27 @@
|
||||
|
||||
#include "socket_connection.h"
|
||||
|
||||
#include "hci.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/select.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "hci.h"
|
||||
#include <unistd.h>
|
||||
|
||||
#define MAX_PENDING_CONNECTIONS 10
|
||||
#define DATA_BUF_SIZE 80
|
||||
|
||||
/** prototypes */
|
||||
static int socket_connection_hci_process(struct data_source *ds, int ready);
|
||||
static int socket_connection_dummy_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t length);
|
||||
|
||||
/** globals */
|
||||
|
||||
/** packet header used over socket connections, in front of the HCI packet */
|
||||
typedef struct packet_header {
|
||||
uint16_t length;
|
||||
@ -51,9 +56,10 @@ static linked_list_t connections = NULL;
|
||||
|
||||
|
||||
/** client packet handler */
|
||||
static int socket_connection_dummy_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t length);
|
||||
|
||||
static int (*socket_connection_packet_callback)(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t length) = socket_connection_dummy_handler;
|
||||
|
||||
|
||||
static int socket_connection_dummy_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t length){
|
||||
return 0;
|
||||
}
|
||||
@ -80,20 +86,48 @@ void socket_connection_free_connection(connection_t *conn){
|
||||
free(conn);
|
||||
}
|
||||
|
||||
void socket_connection_init_statemachine(connection_t *connection){
|
||||
// wait for next packet
|
||||
connection->state = SOCKET_W4_HEADER;
|
||||
connection->bytes_read = 0;
|
||||
connection->bytes_to_read = sizeof(packet_header_t);
|
||||
}
|
||||
|
||||
connection_t * socket_connection_register_new_connection(int fd){
|
||||
// create connection objec
|
||||
connection_t * conn = malloc( sizeof(connection_t));
|
||||
if (conn == NULL) return 0;
|
||||
linked_item_set_user( &conn->ds.item, conn);
|
||||
linked_item_set_user( &conn->item, conn);
|
||||
conn->ds.fd = fd;
|
||||
conn->ds.process = socket_connection_hci_process;
|
||||
|
||||
// prepare state machine and
|
||||
socket_connection_init_statemachine(conn);
|
||||
|
||||
// add this socket to the run_loop
|
||||
run_loop_add( &conn->ds );
|
||||
|
||||
// and the connection list
|
||||
linked_list_add( &connections, &conn->item);
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
int socket_connection_hci_process(struct data_source *ds, int ready) {
|
||||
connection_t *conn = (connection_t *) ds;
|
||||
int bytes_read = read(ds->fd, &conn->buffer[conn->bytes_read], conn->bytes_to_read);
|
||||
|
||||
printf("socket_connection_connection_process: state %u, new %u, read %u, toRead %u\n", conn->state,
|
||||
bytes_read, conn->bytes_read, conn->bytes_to_read);
|
||||
// printf("socket_connection_connection_process: state %u, new %u, read %u, toRead %u\n", conn->state,
|
||||
// bytes_read, conn->bytes_read, conn->bytes_to_read);
|
||||
if (bytes_read <= 0){
|
||||
// free
|
||||
socket_connection_free_connection( linked_item_get_user(&ds->item));
|
||||
socket_connection_free_connection(linked_item_get_user(&ds->item));
|
||||
return 0;
|
||||
}
|
||||
conn->bytes_read += bytes_read;
|
||||
conn->bytes_to_read -= bytes_read;
|
||||
hexdump( conn->buffer, conn->bytes_read);
|
||||
// hexdump( conn->buffer, conn->bytes_read);
|
||||
if (conn->bytes_to_read > 0) {
|
||||
return 0;
|
||||
}
|
||||
@ -106,50 +140,27 @@ int socket_connection_hci_process(struct data_source *ds, int ready) {
|
||||
// dispatch packet !!!
|
||||
(*socket_connection_packet_callback)(conn, conn->buffer[2], &conn->buffer[sizeof(packet_header_t)],
|
||||
READ_BT_16( conn->buffer, 0));
|
||||
|
||||
// wait for next packet
|
||||
conn->state = SOCKET_W4_HEADER;
|
||||
conn->bytes_read = 0;
|
||||
conn->bytes_to_read = sizeof(packet_header_t);
|
||||
// reset state machine
|
||||
socket_connection_init_statemachine(conn);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int socket_connection_accept(struct data_source *socket_ds, int ready) {
|
||||
|
||||
// create data_source_t
|
||||
connection_t * conn = malloc( sizeof(connection_t));
|
||||
if (conn == NULL) return 0;
|
||||
conn->ds.fd = 0;
|
||||
conn->ds.process = socket_connection_hci_process;
|
||||
|
||||
// init state machine
|
||||
conn->state = SOCKET_W4_HEADER;
|
||||
conn->bytes_read = 0;
|
||||
conn->bytes_to_read = sizeof(packet_header_t);
|
||||
|
||||
/* New connection coming in! */
|
||||
conn->ds.fd = accept(socket_ds->fd, NULL, NULL);
|
||||
if (conn->ds.fd < 0) {
|
||||
int fd = accept(socket_ds->fd, NULL, NULL);
|
||||
if (fd < 0) {
|
||||
perror("accept");
|
||||
free(conn);
|
||||
return 0;
|
||||
}
|
||||
// non-blocking ?
|
||||
// socket_connection_set_non_blocking(ds->fd);
|
||||
|
||||
printf("socket_connection_accept new connection %u\n", conn->ds.fd);
|
||||
printf("socket_connection_accept new connection %u\n", fd);
|
||||
|
||||
// add this socket to the run_loop
|
||||
linked_item_set_user( &conn->ds.item, conn);
|
||||
run_loop_add( &conn->ds );
|
||||
|
||||
// and the connection list
|
||||
linked_item_set_user( &conn->item, conn);
|
||||
linked_list_add( &connections, &conn->item);
|
||||
socket_connection_register_new_connection(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -258,3 +269,44 @@ void socket_connection_send_event_all(uint8_t *packet, uint16_t size){
|
||||
socket_connection_send_packet_all( HCI_EVENT_PACKET, packet, size);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* create socket connection to BTdaemon
|
||||
*/
|
||||
connection_t * socket_connection_open_tcp(){
|
||||
// TCP
|
||||
struct protoent* tcp = getprotobyname("tcp");
|
||||
|
||||
int btsocket = socket(PF_INET, SOCK_STREAM, tcp->p_proto);
|
||||
if(btsocket == -1){
|
||||
return NULL;
|
||||
}
|
||||
// localhost
|
||||
struct sockaddr_in btdaemon_address;
|
||||
btdaemon_address.sin_family = AF_INET;
|
||||
btdaemon_address.sin_port = htons(BTSTACK_PORT);
|
||||
struct hostent* localhost = gethostbyname("localhost");
|
||||
if(!localhost){
|
||||
return NULL;
|
||||
}
|
||||
// connect
|
||||
char* addr = localhost->h_addr_list[0];
|
||||
memcpy(&btdaemon_address.sin_addr.s_addr, addr, sizeof addr);
|
||||
if(connect(btsocket, (struct sockaddr*)&btdaemon_address, sizeof btdaemon_address) == -1){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return socket_connection_register_new_connection(btsocket);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* close socket connection to BTdaemon
|
||||
*/
|
||||
int socket_connection_close_tcp(connection_t * connection){
|
||||
if (!connection) return -1;
|
||||
shutdown(connection->ds.fd, SHUT_RDWR);
|
||||
run_loop_remove(&connection->ds);
|
||||
free( connection );
|
||||
return 0;
|
||||
}
|
@ -7,21 +7,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "run_loop.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** TCP port for BTstack */
|
||||
#define BTSTACK_PORT 13333
|
||||
|
||||
/** opaque connection type */
|
||||
typedef struct connection connection_t;
|
||||
|
||||
/**
|
||||
* create socket data_source for tcp socket
|
||||
* create socket for incoming tcp connections
|
||||
*/
|
||||
int socket_connection_create_tcp(int port);
|
||||
|
||||
/**
|
||||
* create socket data_source for unix domain socket
|
||||
* create socket for incoming for unix domain connections
|
||||
*/
|
||||
int socket_connection_create_unix(char *path);
|
||||
|
||||
/**
|
||||
* create socket connection to BTdaemon
|
||||
*/
|
||||
connection_t * socket_connection_open_tcp();
|
||||
|
||||
/**
|
||||
* close socket connection to BTdaemon
|
||||
*/
|
||||
int socket_connection_close_tcp(connection_t *connection);
|
||||
|
||||
/**
|
||||
* set packet handler for all auto-accepted connections
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user