manage RFCOMM channel services by name for iOS platform, rework RFCOMM service registration

This commit is contained in:
matthias.ringwald 2011-05-03 21:14:41 +00:00
parent 84aa122ee4
commit 933d8a8084
10 changed files with 189 additions and 44 deletions

View File

@ -97,12 +97,12 @@ void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint
break;
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]) {
printf("RFCOMM channel open failed, status %u\n", packet[2]);
} else {
rfcomm_channel_id = READ_BT_16(packet, 10);
mtu = READ_BT_16(packet, 12);
rfcomm_channel_id = 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);
uint8_t message[] = "Hello World from BTstack!\n";
// bt_send_rfcomm(rfcomm_channel_id, message, sizeof(message));

View File

@ -125,8 +125,8 @@ void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint
bd_addr_t event_addr;
uint16_t mtu;
uint16_t psm;
uint8_t rfcomm_channel_nr;
uint16_t rfcomm_channel_id;
uint16_t rfcomm_channel_nr;
uint8_t credits;
static uint32_t packet_counter = 0;
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:
// bt stack activated, get started
if (packet[2] == HCI_STATE_WORKING) {
// register RFCOMM channel
bt_send_cmd(&rfcomm_register_service, 0x4711, 100); // random registration ID
}
// get persistent RFCOMM channel
printf("HCI_STATE_WORKING\n");
bt_send_cmd(&rfcomm_persistent_channel_for_service, "ch.ringwald.btstack.rfcomm-echo2");
}
break;
case RFCOMM_EVENT_SERVICE_REGISTERED:
rfcomm_channel_nr = packet[5];
case RFCOMM_EVENT_PERSISTENT_CHANNEL:
rfcomm_channel_nr = packet[3];
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
create_spp_service(service_buffer, rfcomm_channel_nr);
bt_send_cmd(&sdp_register_service_record, service_buffer);
bt_send_cmd(&btstack_set_discoverable, 1);
break;
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;
case HCI_EVENT_PIN_CODE_REQUEST:

View File

@ -168,9 +168,11 @@ extern "C" {
// data: event(8), len(8), local_cid(16), credits(8)
#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
// 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)
#define SDP_SERVICE_REGISTERED 0x90
@ -203,6 +205,7 @@ extern "C" {
#define L2CAP_CONFIG_RESPONSE_RESULT_UNKNOWN_OPTIONS 0x69
#define RFCOMM_MULTIPLEXER_STOPPED 0x70
#define RFCOMM_CHANNEL_ALREADY_REGISTERED 0x71
/**
* 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_unregister_service_record;
// accept connection @param bd_addr(48), rfcomm_cid (16)
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;
// decline rfcomm disconnect,@param bd_addr(48), rfcomm cid (16), reason(8)
extern const hci_cmd_t rfcomm_decline_connection;
// disconnect rfcomm disconnect, @param rfcomm_cid(8), reason(8)
extern const hci_cmd_t rfcomm_disconnect;
// register rfcomm service: @param channel(8), mtu (16)
extern const hci_cmd_t rfcomm_register_service;
// unregister rfcomm service, @param service_channel(16)
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
}
#endif

View File

@ -111,6 +111,9 @@ static void (*bluetooth_status_handler)(BLUETOOTH_STATE state) = dummy_bluetooth
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){
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);
break;
case RFCOMM_REGISTER_SERVICE:
registration_id = READ_BT_16(packet, 3);
mtu = READ_BT_16(packet, 5);
rfcomm_register_service_internal(connection, registration_id, mtu);
rfcomm_channel = packet[3];
mtu = READ_BT_16(packet, 4);
rfcomm_register_service_internal(connection, rfcomm_channel, mtu);
break;
case RFCOMM_UNREGISTER_SERVICE:
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];
rfcomm_decline_connection_internal(cid);
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:
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;
remote_device_db_t * remote_device_db = NULL;
#ifdef HAVE_TRANSPORT_H4
transport = hci_transport_h4_instance();

View File

@ -129,7 +129,8 @@ extern "C" {
#define RFCOMM_UNREGISTER_SERVICE 0x43
#define RFCOMM_ACCEPT_CONNECTION 0x44
#define RFCOMM_DECLINE_CONNECTION 0x45
#define RFCOMM_PERSISTENT_CHANNEL 0x46
//
#define IS_COMMAND(packet, command) (READ_BT_16(packet,0) == command.opcode)

View File

@ -404,21 +404,24 @@ const hci_cmd_t rfcomm_create_channel = {
const hci_cmd_t rfcomm_disconnect = {
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 = {
OPCODE(OGF_BTSTACK, RFCOMM_REGISTER_SERVICE), "22"
OPCODE(OGF_BTSTACK, RFCOMM_REGISTER_SERVICE), "12"
};
// unregister rfcomm service, @param service_channel(16)
const hci_cmd_t rfcomm_unregister_service = {
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 = {
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 = {
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"
};

View File

@ -46,10 +46,14 @@ typedef struct {
void (*put_link_key)(bd_addr_t *bd_addr, link_key_t *key);
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);
void (*put_name)(bd_addr_t *bd_addr, device_name_t *device_name);
void (*delete_name)(bd_addr_t *bd_addr);
// persistent rfcomm channel
uint8_t (*persistent_rfcomm_channel)(char *servicename);
} remote_device_db_t;
extern remote_device_db_t remote_device_db_iphone;

View File

@ -35,13 +35,21 @@
#define BTdaemonID "ch.ringwald.btdaemon"
#define BTDaemonPrefsPath "Library/Preferences/ch.ringwald.btdaemon.plist"
#define DEVICES_KEY "devices"
#define PREFS_REMOTE_NAME @"RemoteName"
#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 NSMutableDictionary *remote_devices = nil;
static NSMutableDictionary *remote_devices = nil;
static NSMutableDictionary *rfcomm_services = nil;
// Device info
static void db_open(){
@ -53,7 +61,8 @@ static void db_open(){
// 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;
dict = (NSDictionary*) CFPreferencesCopyAppValue(CFSTR(DEVICES_KEY), CFSTR(BTdaemonID));
remote_devices = [[NSMutableDictionary alloc] initWithCapacity:([dict count]+5)];
// copy entries
@ -64,6 +73,17 @@ static void db_open(){
[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]);
[pool release];
@ -76,6 +96,7 @@ static void db_synchronize(){
// Core Foundation
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);
// 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);
}
#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 = {
db_open,
db_close,
@ -182,6 +273,7 @@ remote_device_db_t remote_device_db_iphone = {
delete_link_key,
get_name,
put_name,
delete_name
delete_name,
persistent_rfcomm_channel
};

View File

@ -119,7 +119,7 @@ typedef struct {
linked_item_t item;
// server channel
uint16_t server_channel;
uint8_t server_channel;
// incoming max frame size
uint16_t max_frame_size;
@ -195,7 +195,6 @@ typedef struct {
// global rfcomm data
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
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,
rfcomm_service_t *service, uint16_t server_channel){
rfcomm_service_t *service, uint8_t server_channel){
// don't use 0 as channel id
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
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);
rfcomm_dump_channels();
@ -341,7 +340,7 @@ static rfcomm_channel_t * rfcomm_channel_for_multiplexer_and_dlci(rfcomm_multipl
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;
for (it = (linked_item_t *) rfcomm_services; it ; it = it->next){
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++] = status;
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;
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
@ -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));
}
static void rfcomm_emit_service_registered(void *connection, uint8_t status, uint16_t registration_id, uint16_t rfcomm_channel_id){
uint8_t event[6];
static void rfcomm_emit_service_registered(void *connection, uint8_t status, uint8_t channel){
uint8_t event[4];
event[0] = RFCOMM_EVENT_SERVICE_REGISTERED;
event[1] = sizeof(event) - 2;
event[2] = status;
bt_store_16(event, 3, registration_id);
event[5] = rfcomm_channel_id;
event[3] = channel;
hci_dump_packet( HCI_EVENT_PACKET, 0, 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(){
rfcomm_client_cid_generator = 0;
rfcomm_server_cid_generator = 0;
rfcomm_multiplexers = NULL;
rfcomm_services = 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
rfcomm_service_t * service = malloc(sizeof(rfcomm_service_t));
service = malloc(sizeof(rfcomm_service_t));
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;
}
@ -1336,14 +1340,14 @@ void rfcomm_register_service_internal(void * connection, uint16_t registration_i
// fill in
service->connection = connection;
service->server_channel = ++rfcomm_server_cid_generator;
service->server_channel = channel;
service->max_frame_size = max_frame_size;
// add to services list
linked_list_add(&rfcomm_services, (linked_item_t *) service);
// 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){

View File

@ -48,7 +48,7 @@ void rfcomm_register_packet_handler(void (*handler)(void * connection, uint8_t p
// BTstack Internal RFCOMM API
void rfcomm_create_channel_internal(void * connectio, bd_addr_t *addr, uint8_t channel);
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_accept_connection_internal(uint16_t rfcomm_cid);
void rfcomm_decline_connection_internal(uint16_t rfcomm_cid);