(Apple) Rework gamepad connection management; fix BTstack support when building with the iOS 7 SDK.

This commit is contained in:
meancoot 2013-10-03 17:43:41 -04:00
parent fe8b6c3c0f
commit fae300aaaf
10 changed files with 215 additions and 238 deletions

View File

@ -15,32 +15,25 @@
#include <IOKit/hid/IOHIDManager.h> #include <IOKit/hid/IOHIDManager.h>
#include "apple/common/apple_input.h" #include "apple/common/apple_input.h"
#include "apple/common/hidpad/hidpad.h"
struct hidpad_connection struct apple_pad_connection
{ {
uint32_t slot; uint32_t slot;
struct hidpad_interface* interface;
void* hidpad;
IOHIDDeviceRef device; IOHIDDeviceRef device;
uint8_t data[2048]; uint8_t data[2048];
}; };
static IOHIDManagerRef g_hid_manager; static IOHIDManagerRef g_hid_manager;
static struct hidpad_connection g_connected_pads[MAX_PADS];
void hidpad_send_control(struct hidpad_connection* connection, uint8_t* data, size_t size) void apple_pad_send_control(struct apple_pad_connection* connection, uint8_t* data, size_t size)
{ {
IOHIDDeviceSetReport(connection->device, kIOHIDReportTypeOutput, 0x01, data, size); IOHIDDeviceSetReport(connection->device, kIOHIDReportTypeOutput, 0x01, data + 1, size - 1);
} }
// NOTE: I pieced this together through trial and error, any corrections are welcome // NOTE: I pieced this together through trial and error, any corrections are welcome
static void hid_device_input_callback(void* context, IOReturn result, void* sender, IOHIDValueRef value) static void hid_device_input_callback(void* context, IOReturn result, void* sender, IOHIDValueRef value)
{ {
struct hidpad_connection* connection = context; struct apple_pad_connection* connection = context;
IOHIDElementRef element = IOHIDValueGetElement(value); IOHIDElementRef element = IOHIDValueGetElement(value);
uint32_t type = IOHIDElementGetType(element); uint32_t type = IOHIDElementGetType(element);
@ -97,16 +90,15 @@ static void hid_device_input_callback(void* context, IOReturn result, void* send
static void hid_device_removed(void* context, IOReturn result, void* sender) static void hid_device_removed(void* context, IOReturn result, void* sender)
{ {
struct hidpad_connection* connection = (struct hidpad_connection*)context; struct apple_pad_connection* connection = (struct apple_pad_connection*)context;
if (connection && connection->slot < MAX_PADS) if (connection && connection->slot < MAX_PLAYERS)
{ {
g_current_input_data.pad_buttons[connection->slot] = 0; g_current_input_data.pad_buttons[connection->slot] = 0;
memset(g_current_input_data.pad_axis[connection->slot], 0, sizeof(g_current_input_data.pad_axis)); memset(g_current_input_data.pad_axis[connection->slot], 0, sizeof(g_current_input_data.pad_axis));
if (connection->interface) apple_joypad_disconnect(connection->slot);
connection->interface->disconnect(connection->hidpad); free(connection);
memset(connection, 0, sizeof(*connection));
} }
IOHIDDeviceClose(sender, kIOHIDOptionsTypeNone); IOHIDDeviceClose(sender, kIOHIDOptionsTypeNone);
@ -114,8 +106,8 @@ static void hid_device_removed(void* context, IOReturn result, void* sender)
static void hid_device_report(void* context, IOReturn result, void *sender, IOHIDReportType type, uint32_t reportID, uint8_t *report, CFIndex reportLength) static void hid_device_report(void* context, IOReturn result, void *sender, IOHIDReportType type, uint32_t reportID, uint8_t *report, CFIndex reportLength)
{ {
struct hidpad_connection* connection = (struct hidpad_connection*)context; struct apple_pad_connection* connection = (struct apple_pad_connection*)context;
connection->interface->packet_handler(connection->hidpad, report, reportLength); apple_joypad_packet(connection->slot, connection->data, reportLength + 1);
} }
static void hid_manager_device_attached(void* context, IOReturn result, void* sender, IOHIDDeviceRef device) static void hid_manager_device_attached(void* context, IOReturn result, void* sender, IOHIDDeviceRef device)
@ -123,24 +115,9 @@ static void hid_manager_device_attached(void* context, IOReturn result, void* se
bool is_pad = (IOHIDDeviceConformsTo(device, kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick) || bool is_pad = (IOHIDDeviceConformsTo(device, kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick) ||
IOHIDDeviceConformsTo(device, kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad)); IOHIDDeviceConformsTo(device, kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad));
struct hidpad_connection* connection = 0; struct apple_pad_connection* connection = calloc(1, sizeof(struct apple_pad_connection));
if (is_pad)
{
for (int i = 0; i != MAX_PADS; i ++)
{
if (!g_connected_pads[i].device)
{
connection = &g_connected_pads[i];
connection->device = device; connection->device = device;
connection->slot = i; connection->slot = MAX_PLAYERS;
break;
}
}
if (!connection)
return;
}
IOHIDDeviceOpen(device, kIOHIDOptionsTypeNone); IOHIDDeviceOpen(device, kIOHIDOptionsTypeNone);
IOHIDDeviceScheduleWithRunLoop(device, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); IOHIDDeviceScheduleWithRunLoop(device, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
@ -149,26 +126,13 @@ static void hid_manager_device_attached(void* context, IOReturn result, void* se
CFStringRef device_name = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); CFStringRef device_name = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
if (is_pad && device_name) if (is_pad && device_name)
{ {
static const struct { const char* name; struct hidpad_interface* iface; } hidpad_map[] = {
{ "Nintendo RVL-CNT-01", &hidpad_wii },
{ "PLAYSTATION(R)3 Controller", &hidpad_ps3 },
{ 0, 0} };
char buffer[1024]; char buffer[1024];
CFStringGetCString(device_name, buffer, 1024, kCFStringEncodingUTF8); CFStringGetCString(device_name, buffer, 1024, kCFStringEncodingUTF8);
for (int i = 0; hidpad_map[i].name; i ++) connection->slot = apple_joypad_connect(buffer, connection);
{ IOHIDDeviceRegisterInputReportCallback(device, connection->data + 1, sizeof(connection->data) - 1, hid_device_report, connection);
if (strstr(buffer, hidpad_map[i].name))
{
connection->interface = hidpad_map[i].iface;
IOHIDDeviceRegisterInputReportCallback(device, connection->data, 2048, hid_device_report, connection);
connection->hidpad = connection->interface->connect(connection, connection->slot);
return;
} }
} else
}
IOHIDDeviceRegisterInputValueCallback(device, hid_device_input_callback, connection); IOHIDDeviceRegisterInputValueCallback(device, hid_device_input_callback, connection);
} }

View File

@ -16,10 +16,11 @@
#ifndef __APPLE_RARCH_INPUT_H__ #ifndef __APPLE_RARCH_INPUT_H__
#define __APPLE_RARCH_INPUT_H__ #define __APPLE_RARCH_INPUT_H__
#include "general.h"
// Input responder // Input responder
#define MAX_TOUCHES 16 #define MAX_TOUCHES 16
#define MAX_KEYS 256 #define MAX_KEYS 256
#define MAX_PADS 4
typedef struct typedef struct
{ {
@ -38,10 +39,28 @@ typedef struct
uint32_t keys[MAX_KEYS]; uint32_t keys[MAX_KEYS];
uint32_t pad_buttons[MAX_PADS]; uint32_t pad_buttons[MAX_PLAYERS];
int16_t pad_axis[MAX_PADS][4]; int16_t pad_axis[MAX_PLAYERS][4];
} apple_input_data_t; } apple_input_data_t;
struct apple_pad_connection;
struct apple_pad_interface
{
void* (*connect)(struct apple_pad_connection* connection, uint32_t slot);
void (*disconnect)(void* device);
void (*packet_handler)(void* device, uint8_t *packet, uint16_t size);
};
// Joypad data
int32_t apple_joypad_connect(const char* name, struct apple_pad_connection* connection);
void apple_joypad_disconnect(uint32_t slot);
void apple_joypad_packet(uint32_t slot, uint8_t* data, uint32_t length);
// This is implemented in the platform specific portions of the input code
void apple_joypad_send_hid_control(struct apple_pad_connection* connection, uint8_t* data, size_t size);
// Input data for the main thread and the game thread
extern apple_input_data_t g_current_input_data; //< Main thread data extern apple_input_data_t g_current_input_data; //< Main thread data
extern apple_input_data_t g_polled_input_data; //< Game thread data extern apple_input_data_t g_polled_input_data; //< Game thread data
@ -51,7 +70,6 @@ uint32_t apple_input_get_icade_buttons();
void apple_input_reset_icade_buttons(); void apple_input_reset_icade_buttons();
void apple_input_handle_key_event(unsigned keycode, bool down); void apple_input_handle_key_event(unsigned keycode, bool down);
extern int32_t apple_input_find_any_key(); extern int32_t apple_input_find_any_key();
extern int32_t apple_input_find_any_button(uint32_t port); extern int32_t apple_input_find_any_button(uint32_t port);
extern int32_t apple_input_find_any_axis(uint32_t port); extern int32_t apple_input_find_any_axis(uint32_t port);

View File

@ -25,10 +25,77 @@
#endif #endif
#include "apple/common/hidpad/wiimote.c" #include "apple/common/hidpad/wiimote.c"
#include "apple/common/hidpad/hidpad_ps3.c" #include "apple/common/hidpad/apple_ps3_pad.c"
#include "apple/common/hidpad/hidpad_wii.c" #include "apple/common/hidpad/apple_wii_pad.c"
typedef struct
{
bool used;
struct apple_pad_interface* iface;
void* data;
} joypad_slot_t;
static joypad_slot_t slots[MAX_PLAYERS];
static int32_t find_empty_slot()
{
for (int i = 0; i != MAX_PLAYERS; i ++)
if (!slots[i].used)
return i;
return -1;
}
int32_t apple_joypad_connect(const char* name, struct apple_pad_connection* connection)
{
int32_t slot = find_empty_slot();
if (slot >= 0 && slot < MAX_PLAYERS)
{
joypad_slot_t* s = &slots[slot];
s->used = true;
static const struct { const char* name; struct apple_pad_interface* iface; } pad_map[] = {
{ "Nintendo RVL-CNT-01", &apple_pad_wii },
{ "PLAYSTATION(R)3 Controller", &apple_pad_ps3 },
{ 0, 0} };
for (int i = 0; name && pad_map[i].name; i ++)
if (strstr(name, pad_map[i].name))
{
s->iface = pad_map[i].iface;
s->data = s->iface->connect(connection, slot);
}
}
return slot;
}
void apple_joypad_disconnect(uint32_t slot)
{
if (slot < MAX_PLAYERS && slots[slot].used)
{
joypad_slot_t* s = &slots[slot];
if (s->iface && s->data)
s->iface->disconnect(s->data);
s->used = false;
}
}
void apple_joypad_packet(uint32_t slot, uint8_t* data, uint32_t length)
{
if (slot < MAX_PLAYERS && slots[slot].used)
{
joypad_slot_t* s = &slots[slot];
if (s->iface && s->data)
s->iface->packet_handler(s->data, data, length);
}
}
// RetroArch joypad driver:
static bool apple_joypad_init(void) static bool apple_joypad_init(void)
{ {
return true; return true;
@ -52,7 +119,7 @@ static bool apple_joypad_button(unsigned port, uint16_t joykey)
if (GET_HAT_DIR(joykey)) if (GET_HAT_DIR(joykey))
return false; return false;
else // Check the button else // Check the button
return (port < MAX_PADS && joykey < 32) ? (g_polled_input_data.pad_buttons[port] & (1 << joykey)) != 0 : false; return (port < MAX_PLAYERS && joykey < 32) ? (g_polled_input_data.pad_buttons[port] & (1 << joykey)) != 0 : false;
} }
static int16_t apple_joypad_axis(unsigned port, uint32_t joyaxis) static int16_t apple_joypad_axis(unsigned port, uint32_t joyaxis)

View File

@ -18,13 +18,11 @@
#include <stdlib.h> #include <stdlib.h>
#include "boolean.h" #include "boolean.h"
#include "apple/common/rarch_wrapper.h" #include "apple/common/apple_input.h"
#include "hidpad.h"
struct hidpad_ps3_data struct hidpad_ps3_data
{ {
struct hidpad_connection* connection; struct apple_pad_connection* connection;
uint8_t data[512]; uint8_t data[512];
@ -49,24 +47,19 @@ static void hidpad_ps3_send_control(struct hidpad_ps3_data* device)
}; };
report_buffer[11] = 1 << ((device->slot % 4) + 1); report_buffer[11] = 1 << ((device->slot % 4) + 1);
#ifdef IOS apple_pad_send_control(device->connection, report_buffer, sizeof(report_buffer));
hidpad_send_control(device->connection, report_buffer, sizeof(report_buffer));
#else
hidpad_send_control(device->connection, report_buffer + 1, sizeof(report_buffer) - 1);
#endif
} }
static void* hidpad_ps3_connect(struct hidpad_connection* connection, uint32_t slot) static void* hidpad_ps3_connect(struct apple_pad_connection* connection, uint32_t slot)
{ {
struct hidpad_ps3_data* device = malloc(sizeof(struct hidpad_ps3_data)); struct hidpad_ps3_data* device = calloc(1, sizeof(struct hidpad_ps3_data));
memset(device, 0, sizeof(*device));
device->connection = connection; device->connection = connection;
device->slot = slot; device->slot = slot;
// Magic packet to start reports // Magic packet to start reports
#ifdef IOS #ifdef IOS
static uint8_t data[] = {0x53, 0xF4, 0x42, 0x03, 0x00, 0x00}; static uint8_t data[] = {0x53, 0xF4, 0x42, 0x03, 0x00, 0x00};
hidpad_send_control(device->connection, data, 6); apple_pad_send_control(device->connection, data, 6);
#endif #endif
// Without this the digital buttons won't be reported // Without this the digital buttons won't be reported
@ -122,18 +115,14 @@ static void hidpad_ps3_packet_handler(struct hidpad_ps3_data* device, uint8_t *p
device->have_led = true; device->have_led = true;
} }
#ifdef IOS
memcpy(device->data, packet, size); memcpy(device->data, packet, size);
#else
memcpy(device->data + 1, packet, size);
#endif
g_current_input_data.pad_buttons[device->slot] = hidpad_ps3_get_buttons(device); g_current_input_data.pad_buttons[device->slot] = hidpad_ps3_get_buttons(device);
for (int i = 0; i < 4; i ++) for (int i = 0; i < 4; i ++)
g_current_input_data.pad_axis[device->slot][i] = hidpad_ps3_get_axis(device, i); g_current_input_data.pad_axis[device->slot][i] = hidpad_ps3_get_axis(device, i);
} }
struct hidpad_interface hidpad_ps3 = struct apple_pad_interface apple_pad_ps3 =
{ {
(void*)&hidpad_ps3_connect, (void*)&hidpad_ps3_connect,
(void*)&hidpad_ps3_disconnect, (void*)&hidpad_ps3_disconnect,

View File

@ -21,12 +21,10 @@
#include "apple/common/rarch_wrapper.h" #include "apple/common/rarch_wrapper.h"
#include "wiimote.h" #include "wiimote.h"
#include "hidpad.h"
static void* hidpad_wii_connect(struct hidpad_connection* connection, uint32_t slot) static void* hidpad_wii_connect(struct apple_pad_connection* connection, uint32_t slot)
{ {
struct wiimote_t* device = malloc(sizeof(struct wiimote_t)); struct wiimote_t* device = calloc(1, sizeof(struct wiimote_t));
memset(device, 0, sizeof(struct wiimote_t));
device->connection = connection; device->connection = connection;
device->unid = slot; device->unid = slot;
@ -64,13 +62,8 @@ static int16_t hidpad_wii_get_axis(struct wiimote_t* device, unsigned axis)
static void hidpad_wii_packet_handler(struct wiimote_t* device, uint8_t *packet, uint16_t size) static void hidpad_wii_packet_handler(struct wiimote_t* device, uint8_t *packet, uint16_t size)
{ {
#ifdef IOS
byte* msg = packet + 2; byte* msg = packet + 2;
switch (packet[1]) switch (packet[1])
#else
byte* msg = packet + 1;
switch (packet[0])
#endif
{ {
case WM_RPT_BTN: case WM_RPT_BTN:
{ {
@ -105,7 +98,7 @@ static void hidpad_wii_packet_handler(struct wiimote_t* device, uint8_t *packet,
g_current_input_data.pad_axis[device->unid][i] = hidpad_wii_get_axis(device, i); g_current_input_data.pad_axis[device->unid][i] = hidpad_wii_get_axis(device, i);
} }
struct hidpad_interface hidpad_wii = struct apple_pad_interface apple_pad_wii =
{ {
(void*)&hidpad_wii_connect, (void*)&hidpad_wii_connect,
(void*)&hidpad_wii_disconnect, (void*)&hidpad_wii_disconnect,

View File

@ -1,32 +0,0 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2013 - Jason Fetters
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __IOS_RARCH_HIDPAD_H__
#define __IOS_RARCH_HIDPAD_H__
struct hidpad_connection;
void hidpad_send_control(struct hidpad_connection* connection, uint8_t* data, size_t size);
struct hidpad_interface
{
void* (*connect)(struct hidpad_connection* connection, uint32_t slot);
void (*disconnect)(void* device);
void (*packet_handler)(void* device, uint8_t *packet, uint16_t size);
};
extern struct hidpad_interface hidpad_wii;
extern struct hidpad_interface hidpad_ps3;
#endif

View File

@ -358,11 +358,7 @@ int wiimote_send(struct wiimote_t* wm, byte report_type, byte* msg, int len)
printf("\n"); printf("\n");
#endif #endif
#ifdef IOS apple_pad_send_control(wm->connection, buf, len + 2);
hidpad_send_control(wm->connection, buf, len + 2);
#else
hidpad_send_control(wm->connection, buf + 1, len + 1);
#endif
return 1; return 1;
} }

View File

@ -41,8 +41,6 @@
#ifndef __WIIMOTE_H__ #ifndef __WIIMOTE_H__
#define __WIIMOTE_H__ #define __WIIMOTE_H__
#include "hidpad.h"
#if defined(__cplusplus) #if defined(__cplusplus)
extern "C" { extern "C" {
#endif #endif
@ -232,7 +230,7 @@ extern "C" {
typedef struct wiimote_t { typedef struct wiimote_t {
int unid; /**< user specified id */ int unid; /**< user specified id */
struct hidpad_connection* connection; struct apple_pad_connection* connection;
int state; /**< various state flags */ int state; /**< various state flags */
byte leds; /**< currently lit leds */ byte leds; /**< currently lit leds */
float battery_level; /**< battery level */ float battery_level; /**< battery level */

View File

@ -21,7 +21,6 @@
#include <string.h> #include <string.h>
#include "apple/common/rarch_wrapper.h" #include "apple/common/rarch_wrapper.h"
#include "apple/common/hidpad/hidpad.h"
#include "btdynamic.h" #include "btdynamic.h"
#include "btpad.h" #include "btpad.h"
#include "btpad_queue.h" #include "btpad_queue.h"
@ -29,13 +28,10 @@
// Private interface // Private interface
enum btpad_state { BTPAD_EMPTY, BTPAD_CONNECTING, BTPAD_CONNECTED }; enum btpad_state { BTPAD_EMPTY, BTPAD_CONNECTING, BTPAD_CONNECTED };
struct hidpad_connection struct apple_pad_connection
{ {
uint32_t slot; uint32_t slot;
struct hidpad_interface* interface;
void* hidpad;
enum btpad_state state; enum btpad_state state;
bool has_address; bool has_address;
@ -45,9 +41,9 @@ struct hidpad_connection
uint16_t channels[2]; //0: Control, 1: Interrupt uint16_t channels[2]; //0: Control, 1: Interrupt
}; };
static struct hidpad_connection g_connected_pads[MAX_PADS]; static struct apple_pad_connection g_connections[MAX_PLAYERS];
void hidpad_send_control(struct hidpad_connection* connection, uint8_t* data, size_t size) void apple_pad_send_control(struct apple_pad_connection* connection, uint8_t* data, size_t size)
{ {
bt_send_l2cap_ptr(connection->channels[0], data, size); bt_send_l2cap_ptr(connection->channels[0], data, size);
} }
@ -66,55 +62,46 @@ void btpad_set_inquiry_state(bool on)
} }
// Internal interface: // Internal interface:
static int32_t btpad_find_slot_for(uint16_t handle, bd_addr_t address) static struct apple_pad_connection* btpad_find_empty_connection()
{ {
for (int i = 0; i < MAX_PADS; i ++) for (int i = 0; i != MAX_PLAYERS; i ++)
if (g_connections[i].state == BTPAD_EMPTY)
return &g_connections[i];
return 0;
}
static struct apple_pad_connection* btpad_find_connection_for(uint16_t handle, bd_addr_t address)
{ {
if (!g_connected_pads[i].handle && !g_connected_pads[i].has_address) for (int i = 0; i < MAX_PLAYERS; i ++)
{
if (!g_connections[i].handle && !g_connections[i].has_address)
continue; continue;
if (handle && g_connected_pads[i].handle && handle != g_connected_pads[i].handle) if (handle && g_connections[i].handle && handle != g_connections[i].handle)
continue; continue;
if (address && g_connected_pads[i].has_address && (BD_ADDR_CMP(address, g_connected_pads[i].address))) if (address && g_connections[i].has_address && (BD_ADDR_CMP(address, g_connections[i].address)))
continue; continue;
return i; return &g_connections[i];
} }
return -1; return 0;
} }
static int32_t btpad_find_slot_with_state(enum btpad_state state) static void btpad_close_connection(struct apple_pad_connection* connection)
{ {
for (int i = 0; i < MAX_PADS; i ++) if (connection->handle)
if (g_connected_pads[i].state == state) btpad_queue_hci_disconnect(connection->handle, 0x15);
return i;
return -1; memset(connection, 0, sizeof(struct apple_pad_connection));
} }
static void btpad_disconnect_pad(uint32_t slot) static void btpad_close_all_connections()
{ {
if (slot > MAX_PADS) for (int i = 0; i < MAX_PLAYERS; i ++)
return; btpad_close_connection(&g_connections[i]);
if (g_connected_pads[slot].interface && g_connected_pads[slot].hidpad)
{
ios_add_log_message("BTpad: Disconnecting slot %d", slot);
g_connected_pads[slot].interface->disconnect(g_connected_pads[slot].hidpad);
}
if (g_connected_pads[slot].handle)
btpad_queue_hci_disconnect(g_connected_pads[slot].handle, 0x15);
memset(&g_connected_pads[slot], 0, sizeof(struct hidpad_connection));
}
static void btpad_disconnect_all_pads()
{
for (int i = 0; i < MAX_PADS; i ++)
btpad_disconnect_pad(i);
} }
void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
@ -140,7 +127,7 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
} }
else if(packet[2] > HCI_STATE_WORKING) else if(packet[2] > HCI_STATE_WORKING)
{ {
btpad_disconnect_all_pads(); btpad_close_all_connections();
} }
} }
break; break;
@ -170,19 +157,18 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
{ {
bt_flip_addr_ptr(event_addr, &packet[3]); bt_flip_addr_ptr(event_addr, &packet[3]);
const int32_t slot = btpad_find_slot_with_state(BTPAD_EMPTY); struct apple_pad_connection* connection = btpad_find_empty_connection();
if (slot >= 0) if (connection)
{ {
ios_add_log_message("BTpad: Inquiry found device (Slot %d)", slot); ios_add_log_message("BTpad: Inquiry found device");
memset(connection, 0, sizeof(struct apple_pad_connection));
memcpy(g_connected_pads[slot].address, event_addr, sizeof(bd_addr_t)); memcpy(connection->address, event_addr, sizeof(bd_addr_t));
connection->has_address = true;
connection->state = BTPAD_CONNECTING;
g_connected_pads[slot].has_address = true; bt_send_cmd_ptr(l2cap_create_channel_ptr, connection->address, PSM_HID_CONTROL);
g_connected_pads[slot].state = BTPAD_CONNECTING; bt_send_cmd_ptr(l2cap_create_channel_ptr, connection->address, PSM_HID_INTERRUPT);
g_connected_pads[slot].slot = slot;
bt_send_cmd_ptr(l2cap_create_channel_ptr, g_connected_pads[slot].address, PSM_HID_CONTROL);
bt_send_cmd_ptr(l2cap_create_channel_ptr, g_connected_pads[slot].address, PSM_HID_INTERRUPT);
} }
} }
} }
@ -190,8 +176,7 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
case HCI_EVENT_INQUIRY_COMPLETE: case HCI_EVENT_INQUIRY_COMPLETE:
{ {
// TODO: Check performance and battery effect of this // This must be turned off during gameplay as it causes a ton of lag
inquiry_running = !inquiry_off; inquiry_running = !inquiry_off;
if (inquiry_running) if (inquiry_running)
@ -206,34 +191,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 psm = READ_BT_16(packet, 11);
const uint16_t channel_id = READ_BT_16(packet, 13); const uint16_t channel_id = READ_BT_16(packet, 13);
const int32_t slot = btpad_find_slot_for(handle, event_addr); struct apple_pad_connection* connection = btpad_find_connection_for(handle, event_addr);
if (!packet[2]) if (!packet[2])
{ {
if (slot < 0) if (!connection)
{ {
ios_add_log_message("BTpad: Got L2CAP 'Channel Opened' event for unrecognized device"); ios_add_log_message("BTpad: Got L2CAP 'Channel Opened' event for unrecognized device");
break; break;
} }
ios_add_log_message("BTpad: L2CAP channel opened: (Slot: %d, PSM: %02X)", slot, psm); ios_add_log_message("BTpad: L2CAP channel opened: (PSM: %02X)", psm);
g_connected_pads[slot].handle = handle; connection->handle = handle;
if (psm == PSM_HID_CONTROL) if (psm == PSM_HID_CONTROL)
g_connected_pads[slot].channels[0] = channel_id; connection->channels[0] = channel_id;
else if (psm == PSM_HID_INTERRUPT) else if (psm == PSM_HID_INTERRUPT)
g_connected_pads[slot].channels[1] = channel_id; connection->channels[1] = channel_id;
else else
ios_add_log_message("BTpad: Got unknown L2CAP PSM, ignoring (Slot: %d, PSM: %02X)", slot, psm); ios_add_log_message("BTpad: Got unknown L2CAP PSM, ignoring (PSM: %02X)", psm);
if (g_connected_pads[slot].channels[0] && g_connected_pads[slot].channels[1]) if (connection->channels[0] && connection->channels[1])
{ {
ios_add_log_message("BTpad: Got both L2CAP channels, requesting name (Slot: %d)", slot); ios_add_log_message("BTpad: Got both L2CAP channels, requesting name");
btpad_queue_hci_remote_name_request(g_connected_pads[slot].address, 0, 0, 0); btpad_queue_hci_remote_name_request(connection->address, 0, 0, 0);
} }
} }
else else
ios_add_log_message("BTpad: Got failed L2CAP 'Channel Opened' event (Slot %d, PSM: %02X, Status: %02X)", -1, psm, packet[2]); ios_add_log_message("BTpad: Got failed L2CAP 'Channel Opened' event (PSM: %02X, Status: %02X)", psm, packet[2]);
} }
break; break;
@ -244,26 +229,26 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
const uint32_t psm = READ_BT_16(packet, 10); const uint32_t psm = READ_BT_16(packet, 10);
const uint32_t channel_id = READ_BT_16(packet, 12); const uint32_t channel_id = READ_BT_16(packet, 12);
int32_t slot = btpad_find_slot_for(handle, event_addr); struct apple_pad_connection* connection = btpad_find_connection_for(handle, event_addr);
if (slot < 0)
if (!connection)
{ {
slot = btpad_find_slot_with_state(BTPAD_EMPTY); connection = btpad_find_empty_connection();
if (connection)
if (slot >= 0)
{ {
ios_add_log_message("BTpad: Got new incoming connection (Slot: %d)", slot); ios_add_log_message("BTpad: Got new incoming connection");
memcpy(g_connected_pads[slot].address, event_addr, sizeof(bd_addr_t)); memset(connection, 0, sizeof(struct apple_pad_connection));
g_connected_pads[slot].has_address = true; memcpy(connection->address, event_addr, sizeof(bd_addr_t));
g_connected_pads[slot].handle = handle; connection->has_address = true;
g_connected_pads[slot].state = BTPAD_CONNECTING; connection->handle = handle;
g_connected_pads[slot].slot = slot; connection->state = BTPAD_CONNECTING;
} }
else break; else break;
} }
ios_add_log_message("BTpad: Incoming L2CAP connection (Slot: %d, PSM: %02X)", slot, psm); ios_add_log_message("BTpad: Incoming L2CAP connection (PSM: %02X)", psm);
bt_send_cmd_ptr(l2cap_accept_connection_ptr, channel_id); bt_send_cmd_ptr(l2cap_accept_connection_ptr, channel_id);
} }
break; break;
@ -272,24 +257,18 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
{ {
bt_flip_addr_ptr(event_addr, &packet[3]); bt_flip_addr_ptr(event_addr, &packet[3]);
const int32_t slot = btpad_find_slot_for(0, event_addr); struct apple_pad_connection* connection = btpad_find_connection_for(0, event_addr);
if (slot < 0)
if (!connection)
{ {
ios_add_log_message("BTpad: Got unexpected remote name, ignoring"); ios_add_log_message("BTpad: Got unexpected remote name, ignoring");
break; break;
} }
ios_add_log_message("BTpad: Got %.200s (Slot: %d)", (char*)&packet[9], slot); ios_add_log_message("BTpad: Got %.200s", (char*)&packet[9]);
if (strncmp((char*)&packet[9], "PLAYSTATION(R)3 Controller", 26) == 0)
g_connected_pads[slot].interface = &hidpad_ps3;
else if (strncmp((char*)&packet[9], "Nintendo RVL-CNT-01", 19) == 0)
g_connected_pads[slot].interface = &hidpad_wii;
if (g_connected_pads[slot].interface) connection->slot = apple_joypad_connect((char*)packet + 9, connection);
{ connection->state = BTPAD_CONNECTED;
g_connected_pads[slot].hidpad = g_connected_pads[slot].interface->connect(&g_connected_pads[slot], slot);
g_connected_pads[slot].state = BTPAD_CONNECTED;
}
} }
break; break;
@ -308,13 +287,13 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
if (!packet[2]) if (!packet[2])
{ {
const int32_t slot = btpad_find_slot_for(handle, 0); struct apple_pad_connection* connection = btpad_find_connection_for(handle, 0);
if (slot >= 0) if (connection)
{ {
g_connected_pads[slot].handle = 0; connection->handle = 0;
btpad_disconnect_pad(slot);
ios_add_log_message("BTpad: Device disconnected (Slot: %d)", slot); apple_joypad_disconnect(connection->slot);
btpad_close_connection(connection);
} }
} }
else else
@ -332,12 +311,12 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
} }
else if (packet_type == L2CAP_DATA_PACKET) else if (packet_type == L2CAP_DATA_PACKET)
{ {
for (int i = 0; i < MAX_PADS; i ++) for (int i = 0; i < MAX_PLAYERS; i ++)
{ {
struct hidpad_connection* connection = &g_connected_pads[i]; struct apple_pad_connection* connection = &g_connections[i];
if (connection->hidpad && connection->interface && (connection->channels[0] == channel || connection->channels[1] == channel)) if (connection->state == BTPAD_CONNECTED && (connection->channels[0] == channel || connection->channels[1] == channel))
connection->interface->packet_handler(connection->hidpad, packet, size); apple_joypad_packet(connection->slot, packet, size);
} }
} }
} }

View File

@ -29,23 +29,28 @@
#include "file.h" #include "file.h"
//#define HAVE_DEBUG_FILELOG //#define HAVE_DEBUG_FILELOG
void ios_set_bluetooth_mode(NSString* mode)
{
#ifndef __IPHONE_7_0 // iOS7 iCade Support
apple_input_enable_icade([mode isEqualToString:@"icade"]);
btstack_set_poweron([mode isEqualToString:@"btstack"]);
#else
bool enabled = [mode isEqualToString:@"icade"];
apple_input_enable_icade(enabled);
[[RAGameView get] iOS7SetiCadeMode:enabled];
#endif
}
bool is_ios_7() bool is_ios_7()
{ {
return [[UIDevice currentDevice].systemVersion compare:@"7.0" options:NSNumericSearch] != NSOrderedAscending; return [[UIDevice currentDevice].systemVersion compare:@"7.0" options:NSNumericSearch] != NSOrderedAscending;
} }
void ios_set_bluetooth_mode(NSString* mode)
{
if (!is_ios_7())
{
apple_input_enable_icade([mode isEqualToString:@"icade"]);
btstack_set_poweron([mode isEqualToString:@"btstack"]);
}
#ifdef __IPHONE_7_0 // iOS7 iCade Support
else
{
bool enabled = [mode isEqualToString:@"icade"];
apple_input_enable_icade(enabled);
[[RAGameView get] iOS7SetiCadeMode:enabled];
}
#endif
}
// Input helpers: This is kept here because it needs objective-c // Input helpers: This is kept here because it needs objective-c
static void handle_touch_event(NSArray* touches) static void handle_touch_event(NSArray* touches)
{ {