mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-04-16 08:42:28 +00:00
manage RFCOMM channel services by name for iOS platform, rework RFCOMM service registration
This commit is contained in:
parent
84aa122ee4
commit
933d8a8084
@ -97,12 +97,12 @@ void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
|
case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
|
||||||
// data: event(8), len(8), status (8), address (48), server channel(8), rfcomm_cid(16), max frame size(16)
|
// data: event(8), len(8), status (8), address (48), handle(16), server channel(8), rfcomm_cid(16), max frame size(16)
|
||||||
if (packet[2]) {
|
if (packet[2]) {
|
||||||
printf("RFCOMM channel open failed, status %u\n", packet[2]);
|
printf("RFCOMM channel open failed, status %u\n", packet[2]);
|
||||||
} else {
|
} else {
|
||||||
rfcomm_channel_id = READ_BT_16(packet, 10);
|
rfcomm_channel_id = READ_BT_16(packet, 12);
|
||||||
mtu = READ_BT_16(packet, 12);
|
mtu = READ_BT_16(packet, 14);
|
||||||
printf("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n", rfcomm_channel_id, mtu);
|
printf("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n", rfcomm_channel_id, mtu);
|
||||||
uint8_t message[] = "Hello World from BTstack!\n";
|
uint8_t message[] = "Hello World from BTstack!\n";
|
||||||
// bt_send_rfcomm(rfcomm_channel_id, message, sizeof(message));
|
// bt_send_rfcomm(rfcomm_channel_id, message, sizeof(message));
|
||||||
|
@ -125,8 +125,8 @@ void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint
|
|||||||
bd_addr_t event_addr;
|
bd_addr_t event_addr;
|
||||||
uint16_t mtu;
|
uint16_t mtu;
|
||||||
uint16_t psm;
|
uint16_t psm;
|
||||||
|
uint8_t rfcomm_channel_nr;
|
||||||
uint16_t rfcomm_channel_id;
|
uint16_t rfcomm_channel_id;
|
||||||
uint16_t rfcomm_channel_nr;
|
|
||||||
uint8_t credits;
|
uint8_t credits;
|
||||||
static uint32_t packet_counter = 0;
|
static uint32_t packet_counter = 0;
|
||||||
static char packet_info[30]; // "packets: 1234567890"
|
static char packet_info[30]; // "packets: 1234567890"
|
||||||
@ -151,21 +151,31 @@ void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint
|
|||||||
case BTSTACK_EVENT_STATE:
|
case BTSTACK_EVENT_STATE:
|
||||||
// bt stack activated, get started
|
// bt stack activated, get started
|
||||||
if (packet[2] == HCI_STATE_WORKING) {
|
if (packet[2] == HCI_STATE_WORKING) {
|
||||||
// register RFCOMM channel
|
// get persistent RFCOMM channel
|
||||||
bt_send_cmd(&rfcomm_register_service, 0x4711, 100); // random registration ID
|
printf("HCI_STATE_WORKING\n");
|
||||||
}
|
bt_send_cmd(&rfcomm_persistent_channel_for_service, "ch.ringwald.btstack.rfcomm-echo2");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RFCOMM_EVENT_SERVICE_REGISTERED:
|
case RFCOMM_EVENT_PERSISTENT_CHANNEL:
|
||||||
rfcomm_channel_nr = packet[5];
|
rfcomm_channel_nr = packet[3];
|
||||||
printf("RFCOMM channel %u was assigned by BTdaemon\n", rfcomm_channel_nr);
|
printf("RFCOMM channel %u was assigned by BTdaemon\n", rfcomm_channel_nr);
|
||||||
|
bt_send_cmd(&rfcomm_register_service, rfcomm_channel_nr, 100); // reserved channel, mtu=100
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RFCOMM_EVENT_SERVICE_REGISTERED:
|
||||||
|
printf("RFCOMM_EVENT_SERVICE_REGISTERED\n");
|
||||||
|
rfcomm_channel_nr = packet[3];
|
||||||
// register SDP for our SPP
|
// register SDP for our SPP
|
||||||
create_spp_service(service_buffer, rfcomm_channel_nr);
|
create_spp_service(service_buffer, rfcomm_channel_nr);
|
||||||
bt_send_cmd(&sdp_register_service_record, service_buffer);
|
bt_send_cmd(&sdp_register_service_record, service_buffer);
|
||||||
|
bt_send_cmd(&btstack_set_discoverable, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDP_SERVICE_REGISTERED:
|
case SDP_SERVICE_REGISTERED:
|
||||||
bt_send_cmd(&btstack_set_discoverable, 1);
|
// event not sent yet
|
||||||
|
// printf("SDP_SERVICE_REGISTERED\n");
|
||||||
|
// bt_send_cmd(&btstack_set_discoverable, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCI_EVENT_PIN_CODE_REQUEST:
|
case HCI_EVENT_PIN_CODE_REQUEST:
|
||||||
|
@ -168,9 +168,11 @@ extern "C" {
|
|||||||
// data: event(8), len(8), local_cid(16), credits(8)
|
// data: event(8), len(8), local_cid(16), credits(8)
|
||||||
#define RFCOMM_EVENT_CREDITS 0x84
|
#define RFCOMM_EVENT_CREDITS 0x84
|
||||||
|
|
||||||
// data: event(8), len(8), status (8), registration id(16), rfcomm server channel id (8)
|
// data: event(8), len(8), status (8), rfcomm server channel id (8)
|
||||||
#define RFCOMM_EVENT_SERVICE_REGISTERED 0x85
|
#define RFCOMM_EVENT_SERVICE_REGISTERED 0x85
|
||||||
|
|
||||||
|
// data: event(8), len(8), status (8), rfcomm server channel id (8)
|
||||||
|
#define RFCOMM_EVENT_PERSISTENT_CHANNEL 0x86
|
||||||
|
|
||||||
// data: event(8), len(8), service_record_handle(32)
|
// data: event(8), len(8), service_record_handle(32)
|
||||||
#define SDP_SERVICE_REGISTERED 0x90
|
#define SDP_SERVICE_REGISTERED 0x90
|
||||||
@ -203,6 +205,7 @@ extern "C" {
|
|||||||
#define L2CAP_CONFIG_RESPONSE_RESULT_UNKNOWN_OPTIONS 0x69
|
#define L2CAP_CONFIG_RESPONSE_RESULT_UNKNOWN_OPTIONS 0x69
|
||||||
|
|
||||||
#define RFCOMM_MULTIPLEXER_STOPPED 0x70
|
#define RFCOMM_MULTIPLEXER_STOPPED 0x70
|
||||||
|
#define RFCOMM_CHANNEL_ALREADY_REGISTERED 0x71
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default INQ Mode
|
* Default INQ Mode
|
||||||
@ -296,13 +299,21 @@ extern const hci_cmd_t l2cap_unregister_service;
|
|||||||
extern const hci_cmd_t sdp_register_service_record;
|
extern const hci_cmd_t sdp_register_service_record;
|
||||||
extern const hci_cmd_t sdp_unregister_service_record;
|
extern const hci_cmd_t sdp_unregister_service_record;
|
||||||
|
|
||||||
|
// accept connection @param bd_addr(48), rfcomm_cid (16)
|
||||||
extern const hci_cmd_t rfcomm_accept_connection;
|
extern const hci_cmd_t rfcomm_accept_connection;
|
||||||
|
// create rfcomm channel: @param bd_addr(48), channel (8)
|
||||||
extern const hci_cmd_t rfcomm_create_channel;
|
extern const hci_cmd_t rfcomm_create_channel;
|
||||||
|
// decline rfcomm disconnect,@param bd_addr(48), rfcomm cid (16), reason(8)
|
||||||
extern const hci_cmd_t rfcomm_decline_connection;
|
extern const hci_cmd_t rfcomm_decline_connection;
|
||||||
|
// disconnect rfcomm disconnect, @param rfcomm_cid(8), reason(8)
|
||||||
extern const hci_cmd_t rfcomm_disconnect;
|
extern const hci_cmd_t rfcomm_disconnect;
|
||||||
|
// register rfcomm service: @param channel(8), mtu (16)
|
||||||
extern const hci_cmd_t rfcomm_register_service;
|
extern const hci_cmd_t rfcomm_register_service;
|
||||||
|
// unregister rfcomm service, @param service_channel(16)
|
||||||
extern const hci_cmd_t rfcomm_unregister_service;
|
extern const hci_cmd_t rfcomm_unregister_service;
|
||||||
|
// request persisten rfcomm channel for service name: serive name (char*)
|
||||||
|
extern const hci_cmd_t rfcomm_persistent_channel_for_service;
|
||||||
|
|
||||||
#if defined __cplusplus
|
#if defined __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
28
src/daemon.c
28
src/daemon.c
@ -111,6 +111,9 @@ static void (*bluetooth_status_handler)(BLUETOOTH_STATE state) = dummy_bluetooth
|
|||||||
|
|
||||||
static int global_enable = 0;
|
static int global_enable = 0;
|
||||||
|
|
||||||
|
static remote_device_db_t * remote_device_db = NULL;
|
||||||
|
static rfcomm_channel_generator = 1;
|
||||||
|
|
||||||
static void dummy_bluetooth_status_handler(BLUETOOTH_STATE state){
|
static void dummy_bluetooth_status_handler(BLUETOOTH_STATE state){
|
||||||
printf("Bluetooth status: %u\n", state);
|
printf("Bluetooth status: %u\n", state);
|
||||||
};
|
};
|
||||||
@ -239,9 +242,9 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
|
|||||||
rfcomm_disconnect_internal(cid);
|
rfcomm_disconnect_internal(cid);
|
||||||
break;
|
break;
|
||||||
case RFCOMM_REGISTER_SERVICE:
|
case RFCOMM_REGISTER_SERVICE:
|
||||||
registration_id = READ_BT_16(packet, 3);
|
rfcomm_channel = packet[3];
|
||||||
mtu = READ_BT_16(packet, 5);
|
mtu = READ_BT_16(packet, 4);
|
||||||
rfcomm_register_service_internal(connection, registration_id, mtu);
|
rfcomm_register_service_internal(connection, rfcomm_channel, mtu);
|
||||||
break;
|
break;
|
||||||
case RFCOMM_UNREGISTER_SERVICE:
|
case RFCOMM_UNREGISTER_SERVICE:
|
||||||
service_channel = READ_BT_16(packet, 3);
|
service_channel = READ_BT_16(packet, 3);
|
||||||
@ -256,6 +259,24 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
|
|||||||
reason = packet[7];
|
reason = packet[7];
|
||||||
rfcomm_decline_connection_internal(cid);
|
rfcomm_decline_connection_internal(cid);
|
||||||
break;
|
break;
|
||||||
|
case RFCOMM_PERSISTENT_CHANNEL: {
|
||||||
|
if (remote_device_db) {
|
||||||
|
// enforce \0
|
||||||
|
packet[3+248] = 0;
|
||||||
|
rfcomm_channel = remote_device_db->persistent_rfcomm_channel(&packet[3]);
|
||||||
|
} else {
|
||||||
|
// NOTE: hack for non-iOS platforms
|
||||||
|
rfcomm_channel = rfcomm_channel_generator++;
|
||||||
|
}
|
||||||
|
uint8_t event[4];
|
||||||
|
event[0] = RFCOMM_EVENT_PERSISTENT_CHANNEL;
|
||||||
|
event[1] = sizeof(event) - 2;
|
||||||
|
event[2] = 0;
|
||||||
|
event[3] = rfcomm_channel;
|
||||||
|
hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||||
|
socket_connection_send_packet(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SDP_REGISTER_SERVICE_RECORD:
|
case SDP_REGISTER_SERVICE_RECORD:
|
||||||
printf("SDP_REGISTER_SERVICE_RECORD size %u\n", size);
|
printf("SDP_REGISTER_SERVICE_RECORD size %u\n", size);
|
||||||
@ -493,7 +514,6 @@ int main (int argc, char * const * argv){
|
|||||||
|
|
||||||
|
|
||||||
bt_control_t * control = NULL;
|
bt_control_t * control = NULL;
|
||||||
remote_device_db_t * remote_device_db = NULL;
|
|
||||||
|
|
||||||
#ifdef HAVE_TRANSPORT_H4
|
#ifdef HAVE_TRANSPORT_H4
|
||||||
transport = hci_transport_h4_instance();
|
transport = hci_transport_h4_instance();
|
||||||
|
@ -129,7 +129,8 @@ extern "C" {
|
|||||||
#define RFCOMM_UNREGISTER_SERVICE 0x43
|
#define RFCOMM_UNREGISTER_SERVICE 0x43
|
||||||
#define RFCOMM_ACCEPT_CONNECTION 0x44
|
#define RFCOMM_ACCEPT_CONNECTION 0x44
|
||||||
#define RFCOMM_DECLINE_CONNECTION 0x45
|
#define RFCOMM_DECLINE_CONNECTION 0x45
|
||||||
|
#define RFCOMM_PERSISTENT_CHANNEL 0x46
|
||||||
|
|
||||||
//
|
//
|
||||||
#define IS_COMMAND(packet, command) (READ_BT_16(packet,0) == command.opcode)
|
#define IS_COMMAND(packet, command) (READ_BT_16(packet,0) == command.opcode)
|
||||||
|
|
||||||
|
@ -404,21 +404,24 @@ const hci_cmd_t rfcomm_create_channel = {
|
|||||||
const hci_cmd_t rfcomm_disconnect = {
|
const hci_cmd_t rfcomm_disconnect = {
|
||||||
OPCODE(OGF_BTSTACK, RFCOMM_DISCONNECT), "21"
|
OPCODE(OGF_BTSTACK, RFCOMM_DISCONNECT), "21"
|
||||||
};
|
};
|
||||||
// register rfcomm service: @param registration id(16), mtu (16)
|
|
||||||
|
// register rfcomm service: @param channel(8), mtu (16)
|
||||||
const hci_cmd_t rfcomm_register_service = {
|
const hci_cmd_t rfcomm_register_service = {
|
||||||
OPCODE(OGF_BTSTACK, RFCOMM_REGISTER_SERVICE), "22"
|
OPCODE(OGF_BTSTACK, RFCOMM_REGISTER_SERVICE), "12"
|
||||||
};
|
};
|
||||||
// unregister rfcomm service, @param service_channel(16)
|
// unregister rfcomm service, @param service_channel(16)
|
||||||
const hci_cmd_t rfcomm_unregister_service = {
|
const hci_cmd_t rfcomm_unregister_service = {
|
||||||
OPCODE(OGF_BTSTACK, RFCOMM_UNREGISTER_SERVICE), "2"
|
OPCODE(OGF_BTSTACK, RFCOMM_UNREGISTER_SERVICE), "2"
|
||||||
};
|
};
|
||||||
// accept connection @param bd_addr(48), rfcomm_cid (16)
|
// accept connection @param source cid (16)
|
||||||
const hci_cmd_t rfcomm_accept_connection = {
|
const hci_cmd_t rfcomm_accept_connection = {
|
||||||
OPCODE(OGF_BTSTACK, RFCOMM_ACCEPT_CONNECTION), "2"
|
OPCODE(OGF_BTSTACK, RFCOMM_ACCEPT_CONNECTION), "2"
|
||||||
// @param source cid (16)
|
|
||||||
};
|
};
|
||||||
// decline rfcomm disconnect,@param bd_addr(48), rfcomm cid (16), reason(8)
|
// decline connection @param source cid (16)
|
||||||
const hci_cmd_t rfcomm_decline_connection = {
|
const hci_cmd_t rfcomm_decline_connection = {
|
||||||
OPCODE(OGF_BTSTACK, RFCOMM_DECLINE_CONNECTION), "21"
|
OPCODE(OGF_BTSTACK, RFCOMM_DECLINE_CONNECTION), "21"
|
||||||
// @param source cid (16), reason(8)
|
};
|
||||||
|
// request persisten rfcomm channel number for named service
|
||||||
|
const hci_cmd_t rfcomm_persistent_channel_for_service = {
|
||||||
|
OPCODE(OGF_BTSTACK, RFCOMM_PERSISTENT_CHANNEL), "N"
|
||||||
};
|
};
|
||||||
|
@ -46,10 +46,14 @@ typedef struct {
|
|||||||
void (*put_link_key)(bd_addr_t *bd_addr, link_key_t *key);
|
void (*put_link_key)(bd_addr_t *bd_addr, link_key_t *key);
|
||||||
void (*delete_link_key)(bd_addr_t *bd_addr);
|
void (*delete_link_key)(bd_addr_t *bd_addr);
|
||||||
|
|
||||||
// remove name
|
// remote name
|
||||||
int (*get_name)(bd_addr_t *bd_addr, device_name_t *device_name);
|
int (*get_name)(bd_addr_t *bd_addr, device_name_t *device_name);
|
||||||
void (*put_name)(bd_addr_t *bd_addr, device_name_t *device_name);
|
void (*put_name)(bd_addr_t *bd_addr, device_name_t *device_name);
|
||||||
void (*delete_name)(bd_addr_t *bd_addr);
|
void (*delete_name)(bd_addr_t *bd_addr);
|
||||||
|
|
||||||
|
// persistent rfcomm channel
|
||||||
|
uint8_t (*persistent_rfcomm_channel)(char *servicename);
|
||||||
|
|
||||||
} remote_device_db_t;
|
} remote_device_db_t;
|
||||||
|
|
||||||
extern remote_device_db_t remote_device_db_iphone;
|
extern remote_device_db_t remote_device_db_iphone;
|
||||||
|
@ -35,13 +35,21 @@
|
|||||||
|
|
||||||
#define BTdaemonID "ch.ringwald.btdaemon"
|
#define BTdaemonID "ch.ringwald.btdaemon"
|
||||||
#define BTDaemonPrefsPath "Library/Preferences/ch.ringwald.btdaemon.plist"
|
#define BTDaemonPrefsPath "Library/Preferences/ch.ringwald.btdaemon.plist"
|
||||||
|
|
||||||
#define DEVICES_KEY "devices"
|
#define DEVICES_KEY "devices"
|
||||||
#define PREFS_REMOTE_NAME @"RemoteName"
|
#define PREFS_REMOTE_NAME @"RemoteName"
|
||||||
#define PREFS_LINK_KEY @"LinkKey"
|
#define PREFS_LINK_KEY @"LinkKey"
|
||||||
|
|
||||||
|
#define MAX_RFCOMM_CHANNEL_NR 30
|
||||||
|
|
||||||
|
#define RFCOMM_SERVICES_KEY "rfcommServices"
|
||||||
|
#define PREFS_CHANNEL @"channel"
|
||||||
|
#define PREFS_LAST_USED @"lastUsed"
|
||||||
|
|
||||||
static void put_name(bd_addr_t *bd_addr, device_name_t *device_name);
|
static void put_name(bd_addr_t *bd_addr, device_name_t *device_name);
|
||||||
|
|
||||||
static NSMutableDictionary *remote_devices = nil;
|
static NSMutableDictionary *remote_devices = nil;
|
||||||
|
static NSMutableDictionary *rfcomm_services = nil;
|
||||||
|
|
||||||
// Device info
|
// Device info
|
||||||
static void db_open(){
|
static void db_open(){
|
||||||
@ -53,7 +61,8 @@ static void db_open(){
|
|||||||
// NSDictionary * dict = [defaults persistentDomainForName:BTdaemonID];
|
// NSDictionary * dict = [defaults persistentDomainForName:BTdaemonID];
|
||||||
|
|
||||||
// NSDictionary * dict = (NSDictionary*) CFPreferencesCopyAppValue(CFSTR(DEVICES_KEY), CFSTR(BTdaemonID));
|
// NSDictionary * dict = (NSDictionary*) CFPreferencesCopyAppValue(CFSTR(DEVICES_KEY), CFSTR(BTdaemonID));
|
||||||
NSDictionary * dict = (NSDictionary*) CFPreferencesCopyAppValue(CFSTR(DEVICES_KEY), CFSTR(BTdaemonID));
|
NSDictionary * dict;
|
||||||
|
dict = (NSDictionary*) CFPreferencesCopyAppValue(CFSTR(DEVICES_KEY), CFSTR(BTdaemonID));
|
||||||
remote_devices = [[NSMutableDictionary alloc] initWithCapacity:([dict count]+5)];
|
remote_devices = [[NSMutableDictionary alloc] initWithCapacity:([dict count]+5)];
|
||||||
|
|
||||||
// copy entries
|
// copy entries
|
||||||
@ -64,6 +73,17 @@ static void db_open(){
|
|||||||
[remote_devices setObject:deviceEntry forKey:key];
|
[remote_devices setObject:deviceEntry forKey:key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dict = (NSDictionary*) CFPreferencesCopyAppValue(CFSTR(RFCOMM_SERVICES_KEY), CFSTR(BTdaemonID));
|
||||||
|
rfcomm_services = [[NSMutableDictionary alloc] initWithCapacity:([dict count]+5)];
|
||||||
|
|
||||||
|
// copy entries
|
||||||
|
for (id key in dict) {
|
||||||
|
NSDictionary *value = [dict objectForKey:key];
|
||||||
|
NSMutableDictionary *serviceEntry = [NSMutableDictionary dictionaryWithCapacity:[value count]];
|
||||||
|
[serviceEntry addEntriesFromDictionary:value];
|
||||||
|
[rfcomm_services setObject:serviceEntry forKey:key];
|
||||||
|
}
|
||||||
|
|
||||||
log_dbg("read prefs for %u devices\n", [dict count]);
|
log_dbg("read prefs for %u devices\n", [dict count]);
|
||||||
|
|
||||||
[pool release];
|
[pool release];
|
||||||
@ -76,6 +96,7 @@ static void db_synchronize(){
|
|||||||
|
|
||||||
// Core Foundation
|
// Core Foundation
|
||||||
CFPreferencesSetValue(CFSTR(DEVICES_KEY), (CFPropertyListRef) remote_devices, CFSTR(BTdaemonID), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
|
CFPreferencesSetValue(CFSTR(DEVICES_KEY), (CFPropertyListRef) remote_devices, CFSTR(BTdaemonID), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
|
||||||
|
CFPreferencesSetValue(CFSTR(RFCOMM_SERVICES_KEY), (CFPropertyListRef) rfcomm_services, CFSTR(BTdaemonID), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
|
||||||
CFPreferencesSynchronize(CFSTR(BTdaemonID), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
|
CFPreferencesSynchronize(CFSTR(BTdaemonID), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
|
||||||
|
|
||||||
// NSUserDefaults didn't work
|
// NSUserDefaults didn't work
|
||||||
@ -174,6 +195,76 @@ static int get_name(bd_addr_t *bd_addr, device_name_t *device_name) {
|
|||||||
return (remoteName != nil);
|
return (remoteName != nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark PERSISTENT RFCOMM CHANNEL ALLOCATION
|
||||||
|
|
||||||
|
static int firstFreeChannelNr(){
|
||||||
|
BOOL channelUsed[MAX_RFCOMM_CHANNEL_NR+1];
|
||||||
|
int i;
|
||||||
|
for (i=0; i<=MAX_RFCOMM_CHANNEL_NR ; i++) channelUsed[i] = NO;
|
||||||
|
channelUsed[0] = YES;
|
||||||
|
channelUsed[1] = YES; // preserve channel #1 for testing
|
||||||
|
for (NSDictionary * serviceEntry in [rfcomm_services allValues]){
|
||||||
|
int channel = [(NSNumber *) [serviceEntry objectForKey:PREFS_CHANNEL] intValue];
|
||||||
|
channelUsed[channel] = YES;
|
||||||
|
}
|
||||||
|
for (i=0;i<=MAX_RFCOMM_CHANNEL_NR;i++) {
|
||||||
|
if (channelUsed[i] == NO) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deleteLeastUsed(){
|
||||||
|
NSString * leastUsedName = nil;
|
||||||
|
NSDate * leastUsedDate = nil;
|
||||||
|
for (NSString * serviceName in [rfcomm_services allKeys]){
|
||||||
|
NSDictionary *service = [rfcomm_services objectForKey:serviceName];
|
||||||
|
NSDate *serviceDate = [service objectForKey:PREFS_LAST_USED];
|
||||||
|
if (leastUsedName == nil || [leastUsedDate compare:serviceDate] == NSOrderedDescending) {
|
||||||
|
leastUsedName = serviceName;
|
||||||
|
leastUsedDate = serviceDate;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (leastUsedName){
|
||||||
|
// NSLog(@"removing %@", leastUsedName);
|
||||||
|
[rfcomm_services removeObjectForKey:leastUsedName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void addService(NSString * serviceName, int channel){
|
||||||
|
NSMutableDictionary * serviceEntry = [NSMutableDictionary dictionaryWithCapacity:2];
|
||||||
|
[serviceEntry setObject:[NSNumber numberWithInt:channel] forKey:PREFS_CHANNEL];
|
||||||
|
[serviceEntry setObject:[NSDate date] forKey:PREFS_LAST_USED];
|
||||||
|
[rfcomm_services setObject:serviceEntry forKey:serviceName];
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t persistent_rfcomm_channel(char *serviceName){
|
||||||
|
// find existing entry
|
||||||
|
NSString *serviceString = [NSString stringWithUTF8String:serviceName];
|
||||||
|
NSMutableDictionary *serviceEntry = [rfcomm_services objectForKey:serviceString];
|
||||||
|
if (serviceEntry){
|
||||||
|
// update timestamp
|
||||||
|
[serviceEntry setObject:[NSDate date] forKey:PREFS_LAST_USED];
|
||||||
|
|
||||||
|
db_synchronize();
|
||||||
|
|
||||||
|
return [(NSNumber *) [serviceEntry objectForKey:PREFS_CHANNEL] intValue];
|
||||||
|
}
|
||||||
|
// free channel exist?
|
||||||
|
int channel = firstFreeChannelNr();
|
||||||
|
if (channel < 0){
|
||||||
|
// free channel
|
||||||
|
deleteLeastUsed();
|
||||||
|
channel = firstFreeChannelNr();
|
||||||
|
}
|
||||||
|
addService(serviceString, channel);
|
||||||
|
|
||||||
|
db_synchronize();
|
||||||
|
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
remote_device_db_t remote_device_db_iphone = {
|
remote_device_db_t remote_device_db_iphone = {
|
||||||
db_open,
|
db_open,
|
||||||
db_close,
|
db_close,
|
||||||
@ -182,6 +273,7 @@ remote_device_db_t remote_device_db_iphone = {
|
|||||||
delete_link_key,
|
delete_link_key,
|
||||||
get_name,
|
get_name,
|
||||||
put_name,
|
put_name,
|
||||||
delete_name
|
delete_name,
|
||||||
|
persistent_rfcomm_channel
|
||||||
};
|
};
|
||||||
|
|
||||||
|
36
src/rfcomm.c
36
src/rfcomm.c
@ -119,7 +119,7 @@ typedef struct {
|
|||||||
linked_item_t item;
|
linked_item_t item;
|
||||||
|
|
||||||
// server channel
|
// server channel
|
||||||
uint16_t server_channel;
|
uint8_t server_channel;
|
||||||
|
|
||||||
// incoming max frame size
|
// incoming max frame size
|
||||||
uint16_t max_frame_size;
|
uint16_t max_frame_size;
|
||||||
@ -195,7 +195,6 @@ typedef struct {
|
|||||||
|
|
||||||
// global rfcomm data
|
// global rfcomm data
|
||||||
static uint16_t rfcomm_client_cid_generator; // used for client channel IDs
|
static uint16_t rfcomm_client_cid_generator; // used for client channel IDs
|
||||||
static uint8_t rfcomm_server_cid_generator; // used for service registration
|
|
||||||
|
|
||||||
// linked lists for all
|
// linked lists for all
|
||||||
static linked_list_t rfcomm_multiplexers = NULL;
|
static linked_list_t rfcomm_multiplexers = NULL;
|
||||||
@ -274,7 +273,7 @@ static void rfcomm_dump_channels(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void rfcomm_channel_initialize(rfcomm_channel_t *channel, rfcomm_multiplexer_t *multiplexer,
|
static void rfcomm_channel_initialize(rfcomm_channel_t *channel, rfcomm_multiplexer_t *multiplexer,
|
||||||
rfcomm_service_t *service, uint16_t server_channel){
|
rfcomm_service_t *service, uint8_t server_channel){
|
||||||
|
|
||||||
// don't use 0 as channel id
|
// don't use 0 as channel id
|
||||||
if (rfcomm_client_cid_generator == 0) ++rfcomm_client_cid_generator;
|
if (rfcomm_client_cid_generator == 0) ++rfcomm_client_cid_generator;
|
||||||
@ -301,7 +300,7 @@ static void rfcomm_channel_initialize(rfcomm_channel_t *channel, rfcomm_multiple
|
|||||||
|
|
||||||
// service == NULL -> outgoing channel
|
// service == NULL -> outgoing channel
|
||||||
static rfcomm_channel_t * rfcomm_channel_create(rfcomm_multiplexer_t * multiplexer,
|
static rfcomm_channel_t * rfcomm_channel_create(rfcomm_multiplexer_t * multiplexer,
|
||||||
rfcomm_service_t * service, uint16_t server_channel){
|
rfcomm_service_t * service, uint8_t server_channel){
|
||||||
|
|
||||||
log_dbg("rfcomm_channel_create for service %p, channel %u --- begin\n", service, server_channel);
|
log_dbg("rfcomm_channel_create for service %p, channel %u --- begin\n", service, server_channel);
|
||||||
rfcomm_dump_channels();
|
rfcomm_dump_channels();
|
||||||
@ -341,7 +340,7 @@ static rfcomm_channel_t * rfcomm_channel_for_multiplexer_and_dlci(rfcomm_multipl
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rfcomm_service_t * rfcomm_service_for_channel(uint16_t server_channel){
|
static rfcomm_service_t * rfcomm_service_for_channel(uint8_t server_channel){
|
||||||
linked_item_t *it;
|
linked_item_t *it;
|
||||||
for (it = (linked_item_t *) rfcomm_services; it ; it = it->next){
|
for (it = (linked_item_t *) rfcomm_services; it ; it = it->next){
|
||||||
rfcomm_service_t * service = ((rfcomm_service_t *) it);
|
rfcomm_service_t * service = ((rfcomm_service_t *) it);
|
||||||
@ -507,7 +506,7 @@ static void rfcomm_emit_channel_opened(rfcomm_channel_t *channel, uint8_t status
|
|||||||
event[pos++] = sizeof(event) - 2;
|
event[pos++] = sizeof(event) - 2;
|
||||||
event[pos++] = status;
|
event[pos++] = status;
|
||||||
bt_flip_addr(&event[pos], channel->multiplexer->remote_addr); pos += 6;
|
bt_flip_addr(&event[pos], channel->multiplexer->remote_addr); pos += 6;
|
||||||
// bt_store_16(event, pos, channel->multiplexer->con_handle); pos += 2;
|
bt_store_16(event, pos, channel->multiplexer->con_handle); pos += 2;
|
||||||
event[pos++] = channel->dlci >> 1;
|
event[pos++] = channel->dlci >> 1;
|
||||||
bt_store_16(event, pos, channel->rfcomm_cid); pos += 2; // channel ID
|
bt_store_16(event, pos, channel->rfcomm_cid); pos += 2; // channel ID
|
||||||
bt_store_16(event, pos, channel->max_frame_size); pos += 2; // max frame size
|
bt_store_16(event, pos, channel->max_frame_size); pos += 2; // max frame size
|
||||||
@ -537,13 +536,12 @@ static void rfcomm_emit_credits(rfcomm_channel_t * channel, uint8_t credits) {
|
|||||||
(*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
|
(*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rfcomm_emit_service_registered(void *connection, uint8_t status, uint16_t registration_id, uint16_t rfcomm_channel_id){
|
static void rfcomm_emit_service_registered(void *connection, uint8_t status, uint8_t channel){
|
||||||
uint8_t event[6];
|
uint8_t event[4];
|
||||||
event[0] = RFCOMM_EVENT_SERVICE_REGISTERED;
|
event[0] = RFCOMM_EVENT_SERVICE_REGISTERED;
|
||||||
event[1] = sizeof(event) - 2;
|
event[1] = sizeof(event) - 2;
|
||||||
event[2] = status;
|
event[2] = status;
|
||||||
bt_store_16(event, 3, registration_id);
|
event[3] = channel;
|
||||||
event[5] = rfcomm_channel_id;
|
|
||||||
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
|
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||||
(*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
|
(*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
|
||||||
}
|
}
|
||||||
@ -1217,7 +1215,6 @@ void rfcomm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
|
|||||||
|
|
||||||
void rfcomm_init(){
|
void rfcomm_init(){
|
||||||
rfcomm_client_cid_generator = 0;
|
rfcomm_client_cid_generator = 0;
|
||||||
rfcomm_server_cid_generator = 0;
|
|
||||||
rfcomm_multiplexers = NULL;
|
rfcomm_multiplexers = NULL;
|
||||||
rfcomm_services = NULL;
|
rfcomm_services = NULL;
|
||||||
rfcomm_channels = NULL;
|
rfcomm_channels = NULL;
|
||||||
@ -1320,12 +1317,19 @@ void rfcomm_disconnect_internal(uint16_t rfcomm_cid){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rfcomm_register_service_internal(void * connection, uint16_t registration_id, uint16_t max_frame_size){
|
void rfcomm_register_service_internal(void * connection, uint8_t channel, uint16_t max_frame_size){
|
||||||
|
|
||||||
|
// check if already registered
|
||||||
|
rfcomm_service_t * service = rfcomm_service_for_channel(channel);
|
||||||
|
if (service){
|
||||||
|
rfcomm_emit_service_registered(service->connection, RFCOMM_CHANNEL_ALREADY_REGISTERED, channel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// alloc structure
|
// alloc structure
|
||||||
rfcomm_service_t * service = malloc(sizeof(rfcomm_service_t));
|
service = malloc(sizeof(rfcomm_service_t));
|
||||||
if (!service) {
|
if (!service) {
|
||||||
rfcomm_emit_service_registered(service->connection, BTSTACK_MEMORY_ALLOC_FAILED, registration_id, 0);
|
rfcomm_emit_service_registered(service->connection, BTSTACK_MEMORY_ALLOC_FAILED, channel);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1336,14 +1340,14 @@ void rfcomm_register_service_internal(void * connection, uint16_t registration_i
|
|||||||
|
|
||||||
// fill in
|
// fill in
|
||||||
service->connection = connection;
|
service->connection = connection;
|
||||||
service->server_channel = ++rfcomm_server_cid_generator;
|
service->server_channel = channel;
|
||||||
service->max_frame_size = max_frame_size;
|
service->max_frame_size = max_frame_size;
|
||||||
|
|
||||||
// add to services list
|
// add to services list
|
||||||
linked_list_add(&rfcomm_services, (linked_item_t *) service);
|
linked_list_add(&rfcomm_services, (linked_item_t *) service);
|
||||||
|
|
||||||
// done
|
// done
|
||||||
rfcomm_emit_service_registered(service->connection, 0, registration_id, service->server_channel);
|
rfcomm_emit_service_registered(service->connection, 0, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rfcomm_unregister_service_internal(uint8_t service_channel){
|
void rfcomm_unregister_service_internal(uint8_t service_channel){
|
||||||
|
@ -48,7 +48,7 @@ void rfcomm_register_packet_handler(void (*handler)(void * connection, uint8_t p
|
|||||||
// BTstack Internal RFCOMM API
|
// BTstack Internal RFCOMM API
|
||||||
void rfcomm_create_channel_internal(void * connectio, bd_addr_t *addr, uint8_t channel);
|
void rfcomm_create_channel_internal(void * connectio, bd_addr_t *addr, uint8_t channel);
|
||||||
void rfcomm_disconnect_internal(uint16_t rfcomm_cid);
|
void rfcomm_disconnect_internal(uint16_t rfcomm_cid);
|
||||||
void rfcomm_register_service_internal(void * connection, uint16_t registration_id, uint16_t max_frame_size);
|
void rfcomm_register_service_internal(void * connection, uint8_t channel, uint16_t max_frame_size);
|
||||||
void rfcomm_unregister_service_internal(uint8_t service_channel);
|
void rfcomm_unregister_service_internal(uint8_t service_channel);
|
||||||
void rfcomm_accept_connection_internal(uint16_t rfcomm_cid);
|
void rfcomm_accept_connection_internal(uint16_t rfcomm_cid);
|
||||||
void rfcomm_decline_connection_internal(uint16_t rfcomm_cid);
|
void rfcomm_decline_connection_internal(uint16_t rfcomm_cid);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user