(iOS) BTstack fixups; start multiplayer support

This commit is contained in:
meancoot 2013-06-19 18:31:40 -04:00
parent c63074d04d
commit 8ea92fb004
3 changed files with 162 additions and 100 deletions

View File

@ -26,55 +26,84 @@
#include "btpad_queue.h"
#include "wiimote.h"
static btpad_connection_t btpad_connection;
#define MAX_SLOTS 4
static btpad_connection_t btpad_connection[MAX_SLOTS];
static struct btpad_interface* btpad_iface[MAX_SLOTS];
static void* btpad_device[MAX_SLOTS];
static bool btpad_connection_test(uint16_t handle, bd_addr_t address)
static int32_t btpad_find_slot_for(uint16_t handle, bd_addr_t address)
{
if (handle && btpad_connection.handle && handle != btpad_connection.handle)
return false;
btpad_connection.handle = handle ? handle : btpad_connection.handle;
if (address && btpad_connection.has_address && (BD_ADDR_CMP(address, btpad_connection.address)))
return false;
if (address)
for (int i = 0; i < MAX_SLOTS; i ++)
{
btpad_connection.has_address = true;
memcpy(btpad_connection.address, address, sizeof(bd_addr_t));
if (!btpad_connection[i].handle && !btpad_connection[i].has_address)
continue;
if (handle && btpad_connection[i].handle && handle != btpad_connection[i].handle)
continue;
if (address && btpad_connection[i].has_address && (BD_ADDR_CMP(address, btpad_connection[i].address)))
continue;
return i;
}
return true;
return -1;
}
static struct btpad_interface* btpad_iface;
static void* btpad_device;
static int32_t btpad_find_slot_with_state(enum btpad_state state)
{
for (int i = 0; i < MAX_SLOTS; i ++)
if (btpad_connection[i].state == state)
return i;
return -1;
}
// MAIN THREAD ONLY
uint32_t btpad_get_buttons()
uint32_t btpad_get_buttons(/*uint32_t slot*/)
{
return (btpad_device && btpad_iface) ? btpad_iface->get_buttons(btpad_device) : 0;
uint32_t slot = 0;
if (slot < MAX_SLOTS && btpad_device[slot] && btpad_iface[slot])
return btpad_iface[slot]->get_buttons(btpad_device[slot]);
return 0;
}
int16_t btpad_get_axis(unsigned axis)
int16_t btpad_get_axis(/*uint32_t slot,*/ unsigned axis)
{
return (btpad_device && btpad_iface) ? btpad_iface->get_axis(btpad_device, axis) : 0;
uint32_t slot = 0;
if (slot < MAX_SLOTS && btpad_device[slot] && btpad_iface[slot])
return btpad_iface[slot]->get_axis(btpad_device[slot], axis);
return 0;
}
static void btpad_disconnect_pad()
static void btpad_disconnect_pad(uint32_t slot)
{
if (btpad_iface && btpad_device)
if (slot > MAX_SLOTS)
return;
if (btpad_iface[slot] && btpad_device[slot])
{
ios_add_log_message("BTpad: Disconnecting");
ios_add_log_message("BTpad: Disconnecting slot %d", slot);
btpad_iface->disconnect(btpad_device);
btpad_device = 0;
btpad_iface = 0;
btpad_iface[slot]->disconnect(btpad_device[slot]);
btpad_device[slot] = 0;
btpad_iface[slot] = 0;
}
if (btpad_connection.handle)
btpad_queue_hci_disconnect(btpad_connection.handle, 0x15);
if (btpad_connection[slot].handle)
btpad_queue_hci_disconnect(btpad_connection[slot].handle, 0x15);
memset(&btpad_connection, 0, sizeof(btpad_connection_t));
memset(&btpad_connection[slot], 0, sizeof(btpad_connection_t));
}
static void btpad_disconnect_all_pads()
{
for (int i = 0; i < MAX_SLOTS; i ++)
btpad_disconnect_pad(i);
}
void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
@ -85,7 +114,8 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
{
switch (packet[0])
{
case BTSTACK_EVENT_STATE:
case BTSTACK_EVENT_STATE:
{
if (packet[2] == HCI_STATE_WORKING)
{
btpad_queue_reset();
@ -94,32 +124,34 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
btpad_queue_l2cap_register_service(PSM_HID_CONTROL, 672); // TODO: Where did I get 672 for mtu?
btpad_queue_l2cap_register_service(PSM_HID_INTERRUPT, 672);
btpad_queue_hci_inquiry(HCI_INQUIRY_LAP, 3, 1);
btpad_queue_run(1);
}
else if(packet[2] > HCI_STATE_WORKING && btpad_iface && btpad_device)
{
btpad_disconnect_pad();
btpad_queue_reset();
btpad_disconnect_all_pads();
}
break;
}
break;
case HCI_EVENT_COMMAND_STATUS:
{
btpad_queue_run(packet[3]);
break;
}
break;
case HCI_EVENT_COMMAND_COMPLETE:
{
btpad_queue_run(packet[2]);
if (COMMAND_COMPLETE_EVENT(packet, (*hci_read_bd_addr_ptr)))
{
if (!packet[5])
{
bt_flip_addr_ptr(event_addr, &packet[6]);
ios_add_log_message("BTpad: Local address is %s", bd_addr_to_str_ptr(event_addr));
}
else
ios_add_log_message("BTpad: Failed to get local address (Status: %02X)", packet[5]);
bt_flip_addr_ptr(event_addr, &packet[6]);
if (!packet[5]) ios_add_log_message("BTpad: Local address is %s", bd_addr_to_str_ptr(event_addr));
else ios_add_log_message("BTpad: Failed to get local address (Status: %02X)", packet[5]);
}
break;
}
break;
case L2CAP_EVENT_SERVICE_REGISTERED:
{
@ -141,15 +173,23 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
if (packet[2])
{
bt_flip_addr_ptr(event_addr, &packet[3]);
if (btpad_connection_test(0, event_addr))
const int32_t slot = btpad_find_slot_with_state(BTPAD_EMPTY);
if (slot >= 0)
{
btpad_connection.state = BTPAD_WANT_INQ_COMPLETE;
ios_add_log_message("BTpad: Inquiry found device (Slot %d)", slot);
btpad_connection.page_scan_repetition_mode = packet [3 + packet[2] * (6)];
btpad_connection.class = READ_BT_24(packet, 3 + packet[2] * (6+1+1+1));
btpad_connection.clock_offset = READ_BT_16(packet, 3 + packet[2] * (6+1+1+1+3)) & 0x7fff;
memcpy(btpad_connection[slot].address, event_addr, sizeof(bd_addr_t));
ios_add_log_message("BTpad: Inquiry found device");
btpad_connection[slot].has_address = true;
btpad_connection[slot].state = BTPAD_CONNECTING;
btpad_connection[slot].page_scan_repetition_mode = packet [3 + packet[2] * (6)];
btpad_connection[slot].class = READ_BT_24(packet, 3 + packet[2] * (6+1+1+1));
btpad_connection[slot].clock_offset = READ_BT_16(packet, 3 + packet[2] * (6+1+1+1+3)) & 0x7fff;
btpad_queue_l2cap_create_channel(btpad_connection[slot].address, PSM_HID_CONTROL);
btpad_queue_l2cap_create_channel(btpad_connection[slot].address, PSM_HID_INTERRUPT);
}
}
}
@ -157,13 +197,7 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
case HCI_EVENT_INQUIRY_COMPLETE:
{
if (btpad_connection.state == BTPAD_WANT_INQ_COMPLETE)
{
ios_add_log_message("BTpad: Got inquiry complete; connecting\n");
btpad_queue_l2cap_create_channel(btpad_connection.address, PSM_HID_CONTROL);
btpad_queue_l2cap_create_channel(btpad_connection.address, PSM_HID_INTERRUPT);
}
// TODO: Check performance and batter effect of this
btpad_queue_hci_inquiry(HCI_INQUIRY_LAP, 3, 1);
}
break;
@ -175,32 +209,34 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
const uint16_t psm = READ_BT_16(packet, 11);
const uint16_t channel_id = READ_BT_16(packet, 13);
if (!btpad_connection_test(handle, event_addr))
{
ios_add_log_message("BTpad: Incoming L2CAP connection not recognized; ignoring");
break;
}
const int32_t slot = btpad_find_slot_for(handle, event_addr);
if (!packet[2])
{
ios_add_log_message("BTpad: L2CAP channel opened for psm: %02X", psm);
if (slot < 0)
{
ios_add_log_message("BTpad: Got L2CAP 'Channel Opened' event for unrecognized device");
break;
}
ios_add_log_message("BTpad: L2CAP channel opened: (Slot: %d, PSM: %02X)", slot, psm);
if (psm == PSM_HID_CONTROL)
btpad_connection.channels[0] = channel_id;
btpad_connection[slot].channels[0] = channel_id;
else if (psm == PSM_HID_INTERRUPT)
btpad_connection.channels[1] = channel_id;
btpad_connection[slot].channels[1] = channel_id;
else
ios_add_log_message("BTpad: Got unknown L2CAP PSM, ignoring (PSM: %02X)", psm);
ios_add_log_message("BTpad: Got unknown L2CAP PSM, ignoring (Slot: %d, PSM: %02X)", slot, psm);
if (btpad_connection.channels[0] && btpad_connection.channels[1])
if (btpad_connection[slot].channels[0] && btpad_connection[slot].channels[1])
{
ios_add_log_message("BTpad: Got both L2CAP channels, requesting name");
btpad_queue_hci_remote_name_request(btpad_connection.address, btpad_connection.page_scan_repetition_mode,
0, btpad_connection.clock_offset | 0x8000);
ios_add_log_message("BTpad: Got both L2CAP channels, requesting name (Slot: %d)", slot);
btpad_queue_hci_remote_name_request(btpad_connection[slot].address, btpad_connection[slot].page_scan_repetition_mode,
0, btpad_connection[slot].clock_offset | 0x8000);
}
}
else
ios_add_log_message("BTpad: Failed to open L2CAP channel (PSM: %02X, Status: %02X)", psm, packet[2]);
ios_add_log_message("BTpad: Got failed L2CAP 'Channel Opened' event (Slot %d, PSM: %02X, Status: %02X)", -1, psm, packet[2]);
}
break;
@ -213,26 +249,26 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
const unsigned interrupt = (psm == PSM_HID_INTERRUPT) ? 1 : 0;
ios_add_log_message("BTpad: Incoming L2CAP connection for PSM: %02X", psm);
if (!btpad_connection_test(handle, event_addr))
int32_t slot = btpad_find_slot_for(handle, event_addr);
if (slot < 0)
{
ios_add_log_message("BTpad: Connection is for unregnized handle or address, denying");
slot = btpad_find_slot_with_state(BTPAD_EMPTY);
// TODO: Check error code
btpad_queue_l2cap_decline_connection(channel_id, 0x15);
if (slot >= 0)
{
ios_add_log_message("BTpad: Got new incoming connection (Slot: %d)", slot);
break;
memcpy(btpad_connection[slot].address, event_addr, sizeof(bd_addr_t));
btpad_connection[slot].has_address = true;
btpad_connection[slot].handle = handle;
btpad_connection[slot].state = BTPAD_CONNECTING;
}
else break;
}
btpad_connection.channels[interrupt] = channel_id;
ios_add_log_message("BTpad: Incoming L2CAP connection (Slot: %d, PSM: %02X)", slot, psm);
btpad_queue_l2cap_accept_connection(channel_id);
if (btpad_connection.channels[0] && btpad_connection.channels[1])
{
ios_add_log_message("BTpad: Got both L2CAP channels, requesting name");
btpad_queue_hci_remote_name_request(btpad_connection.address, 0, 0, 0);
}
}
break;
@ -240,30 +276,30 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
{
bt_flip_addr_ptr(event_addr, &packet[3]);
if (!btpad_connection_test(0, event_addr))
const int32_t slot = btpad_find_slot_for(0, event_addr);
if (slot < 0)
{
ios_add_log_message("BTpad: Got unexpected remote name, ignoring");
break;
}
ios_add_log_message("BTpad: Got %200s", (char*)&packet[9]);
ios_add_log_message("BTpad: Got %.200s (Slot: %d)", (char*)&packet[9], slot);
if (strncmp((char*)&packet[9], "PLAYSTATION(R)3 Controller", 26) == 0)
btpad_iface = &btpad_ps3;
btpad_iface[slot] = &btpad_ps3;
else if (strncmp((char*)&packet[9], "Nintendo RVL-CNT-01", 19) == 0)
btpad_iface = &btpad_wii;
btpad_iface[slot] = &btpad_wii;
if (btpad_iface)
if (btpad_iface[slot])
{
btpad_device = btpad_iface->connect(&btpad_connection);
btpad_connection.state = BTPAD_CONNECTED;
btpad_device[slot] = btpad_iface[slot]->connect(&btpad_connection[slot]);
btpad_connection[slot].state = BTPAD_CONNECTED;
}
}
break;
case HCI_EVENT_PIN_CODE_REQUEST:
{
ios_add_log_message("BTpad: Sending PIN");
ios_add_log_message("BTpad: Sending WiiMote PIN");
bt_flip_addr_ptr(event_addr, &packet[2]);
btpad_queue_hci_pin_code_request_reply(event_addr, &packet[2]);
@ -272,6 +308,7 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
}
}
if (btpad_device && btpad_iface)
btpad_iface->packet_handler(btpad_device, packet_type, channel, packet, size);
for (int i = 0; i < MAX_SLOTS; i ++)
if (btpad_device[i] && btpad_iface[i] && (btpad_connection[i].channels[0] == channel || btpad_connection[i].channels[1] == channel))
btpad_iface[i]->packet_handler(btpad_device[i], packet_type, channel, packet, size);
}

View File

@ -22,7 +22,7 @@ uint32_t btpad_get_buttons();
int16_t btpad_get_axis(unsigned axis);
// Private interface
enum btpad_state { BTPAD_EMPTY, BTPAD_WANT_INQ_COMPLETE, BTPAD_CONNECTED };
enum btpad_state { BTPAD_EMPTY, BTPAD_CONNECTING, BTPAD_CONNECTED };
typedef struct
{

View File

@ -17,6 +17,9 @@
#include "btpad.h"
#include "btpad_queue.h"
// NOTE: It seems that it is not needed to wait for the l2cap commands; TODO: Confirm
// #define WAIT_FOR_L2CAP
struct btpad_queue_command
{
const hci_cmd_t* command;
@ -55,6 +58,7 @@ struct btpad_queue_command
bd_addr_t pin;
} hci_pin_code_request_reply;
#ifdef WAIT_FOR_L2CAP
struct
{
uint16_t psm;
@ -77,6 +81,7 @@ struct btpad_queue_command
uint16_t cid;
uint8_t reason;
} l2cap_decline_connection;
#endif
};
};
@ -91,6 +96,7 @@ void btpad_queue_reset()
{
insert_position = 0;
read_position = 0;
can_run = 1;
}
void btpad_queue_run(uint32_t count)
@ -104,12 +110,6 @@ void btpad_queue_process()
{
for (; can_run && (insert_position != read_position); can_run --)
{
if (insert_position == read_position)
{
can_run ++;
return;
}
struct btpad_queue_command* cmd = &commands[read_position];
if (cmd->command == btstack_set_power_mode_ptr)
@ -125,6 +125,7 @@ void btpad_queue_process()
cmd->hci_remote_name_request.reserved, cmd->hci_remote_name_request.clock_offset);
else if (cmd->command == hci_pin_code_request_reply_ptr)
bt_send_cmd_ptr(cmd->command, cmd->hci_pin_code_request_reply.bd_addr, 6, cmd->hci_pin_code_request_reply.pin);
#ifdef WAIT_FOR_L2CAP
else if (cmd->command == l2cap_register_service_ptr)
bt_send_cmd_ptr(cmd->command, cmd->l2cap_register_service.psm, cmd->l2cap_register_service.mtu);
else if (cmd->command == l2cap_create_channel_ptr)
@ -133,6 +134,7 @@ void btpad_queue_process()
bt_send_cmd_ptr(cmd->command, cmd->l2cap_accept_connection.cid);
else if (cmd->command == l2cap_decline_connection_ptr)
bt_send_cmd_ptr(cmd->command, cmd->l2cap_decline_connection.cid, cmd->l2cap_decline_connection.reason);
#endif
INCPOS(read);
}
@ -210,6 +212,8 @@ void btpad_queue_hci_pin_code_request_reply(bd_addr_t bd_addr, bd_addr_t pin)
btpad_queue_process();
}
// NOTE: It seems the l2cap commands don't need to wait
#ifdef WAIT_FOR_L2CAP
void btpad_queue_l2cap_register_service(uint16_t psm, uint16_t mtu)
{
struct btpad_queue_command* cmd = &commands[insert_position];
@ -256,3 +260,24 @@ void btpad_queue_l2cap_decline_connection(uint16_t cid, uint8_t reason)
INCPOS(insert);
btpad_queue_process();
}
#else
void btpad_queue_l2cap_register_service(uint16_t psm, uint16_t mtu)
{
bt_send_cmd_ptr(l2cap_register_service_ptr, psm, mtu);
}
void btpad_queue_l2cap_create_channel(bd_addr_t bd_addr, uint16_t psm)
{
bt_send_cmd_ptr(l2cap_create_channel_ptr, bd_addr, psm);
}
void btpad_queue_l2cap_accept_connection(uint16_t cid)
{
bt_send_cmd_ptr(l2cap_accept_connection_ptr, cid);
}
void btpad_queue_l2cap_decline_connection(uint16_t cid, uint8_t reason)
{
bt_send_cmd_ptr(l2cap_decline_connection_ptr, cid, reason);
}
#endif