(iOS, BTstack) More refactoring; Now have to choose the type of pad to connect (annoying, but there's no other way the code gets stable)

This commit is contained in:
meancoot 2013-03-25 18:25:21 -04:00
parent b4721106f6
commit bb4b254be7
8 changed files with 104 additions and 397 deletions

View File

@ -247,6 +247,8 @@ INPUT
#include "../ios/RetroArch/input/BTStack/btdynamic.c"
#include "../ios/RetroArch/input/BTStack/wiimote.c"
#include "../ios/RetroArch/input/BTStack/btpad.c"
#include "../ios/RetroArch/input/BTStack/btpad_ps3.c"
#include "../ios/RetroArch/input/BTStack/btpad_wii.c"
#elif defined(__BLACKBERRY_QNX__)
#include "../playbook/qnx_input.c"
#endif

View File

@ -44,6 +44,8 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
960356BC1700652C008F55DA /* btpad_ps3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = btpad_ps3.c; sourceTree = "<group>"; };
960356BD1700652C008F55DA /* btpad_wii.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = btpad_wii.c; sourceTree = "<group>"; };
96096DD716D1ABAF00BF4499 /* RAModuleInfoList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RAModuleInfoList.m; sourceTree = "<group>"; };
9614C71F16DDC018000B36EF /* RetroArch copy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "RetroArch copy-Info.plist"; path = "/Users/jason/Documents/Projects/ios/RetroArch/ios/RetroArch copy-Info.plist"; sourceTree = "<absolute>"; };
962979F416C43B9500E6DCE0 /* ic_dir.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ic_dir.png; path = "../../android/phoenix/res/drawable-xhdpi/ic_dir.png"; sourceTree = "<group>"; };
@ -156,6 +158,8 @@
children = (
966B9C9416E418B7005B61E1 /* btstack */,
966B9CA116E418B7005B61E1 /* btpad.c */,
960356BC1700652C008F55DA /* btpad_ps3.c */,
960356BD1700652C008F55DA /* btpad_wii.c */,
96F9C27B16FF66BC002455B3 /* btpad.h */,
96F9C27516FF5E97002455B3 /* btdynamic.c */,
96F9C27616FF5E97002455B3 /* btdynamic.h */,

View File

@ -15,7 +15,7 @@
#import <UIKit/UIKit.h>
@interface RetroArch_iOS : UINavigationController<UIApplicationDelegate, UINavigationControllerDelegate>
@interface RetroArch_iOS : UINavigationController<UIApplicationDelegate, UINavigationControllerDelegate, UIAlertViewDelegate>
+ (void)displayErrorMessage:(NSString*)message;

View File

@ -19,7 +19,8 @@
#import "browser/browser.h"
#import "settings/settings.h"
#include "input/BTstack/btdynamic.h"
#include "input/BTStack/btdynamic.h"
#include "input/BTStack/btpad.h"
#define kDOCSFOLDER [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]
@ -291,6 +292,21 @@
{
if (btstack_is_loaded())
{
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"RetroArch"
message:@"Choose Pad Type"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:@"Wii", @"PS3", nil];
[alert show];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (btstack_is_loaded())
{
btpad_set_pad_type(buttonIndex == 0);
btstack_start();
[self.topViewController.navigationItem setRightBarButtonItem:[self createBluetoothButton] animated:YES];
}

View File

@ -41,6 +41,7 @@ static struct
GRAB(btstack_set_power_mode),
GRAB(btstack_set_system_bluetooth_enabled),
GRAB(hci_delete_stored_link_key),
GRAB(hci_disconnect),
GRAB(hci_inquiry),
GRAB(hci_inquiry_cancel),
GRAB(hci_pin_code_request_reply),
@ -56,7 +57,7 @@ static struct
{0, 0}
};
extern void btstack_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
extern void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static pthread_t btstack_thread;
static bool btstack_tested;
@ -70,7 +71,7 @@ static void* btstack_thread_function(void* data)
ios_add_log_message("BTstack: Thread Initializing");
run_loop_init_ptr(RUN_LOOP_COCOA);
bt_register_packet_handler_ptr(btstack_packet_handler);
bt_register_packet_handler_ptr(btpad_packet_handler);
if (bt_open_ptr())
{
@ -140,6 +141,9 @@ bool btstack_load()
void btstack_start()
{
if (!btstack_load())
return;
static bool thread_started = false;
if (!thread_started)
{
@ -157,6 +161,9 @@ void btstack_start()
void btstack_stop()
{
if (!btstack_load())
return;
if (btstack_poweron)
{
ios_add_log_message("BTstack: Clearing poweron flag");

View File

@ -44,6 +44,7 @@ BTDIMPORT const hci_cmd_t* btstack_get_system_bluetooth_enabled_ptr;
BTDIMPORT const hci_cmd_t* btstack_set_power_mode_ptr;
BTDIMPORT const hci_cmd_t* btstack_set_system_bluetooth_enabled_ptr;
BTDIMPORT const hci_cmd_t* hci_delete_stored_link_key_ptr;
BTDIMPORT const hci_cmd_t* hci_disconnect_ptr;
BTDIMPORT const hci_cmd_t* hci_inquiry_ptr;
BTDIMPORT const hci_cmd_t* hci_inquiry_cancel_ptr;
BTDIMPORT const hci_cmd_t* hci_pin_code_request_reply_ptr;

View File

@ -1,31 +1,16 @@
/*
* This file is part of MAME4iOS.
/* RetroArch - A frontend for libretro.
* Copyright (C) 2013 - Jason Fetters
*
* Copyright (C) 2012 David Valdeita (Seleuco)
* 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.
*
* This program 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 Foundation; either version 2 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* In addition, as a special exception, Seleuco
* gives permission to link the code of this program with
* the MAME library (or with modified versions of MAME that use the
* same license as MAME), and distribute linked combinations including
* the two. You must obey the GNU General Public License in all
* respects for all of the code used other than MAME. If you modify
* this file, you may extend this exception to your version of the
* file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <sys/types.h>
@ -38,392 +23,71 @@
#include "btpad.h"
#include "wiimote.h"
enum btpad_state_t { BTPAD_NOT_INITIALIZED, BTPAD_NO_CONNECTION, BTPAD_INQUIRY_CONNECTION, BTPAD_CONNECTION, BTPAD_WANT_NAME, BTPAD_CONNECTED };
static enum btpad_state_t btpad_state = BTPAD_NOT_INITIALIZED;
static enum btpad_device_type_t device_type;
static bd_addr_t device_address;
static char device_name[256];
// Connection data
static uint32_t device_handle[2];
static uint32_t device_remote_cid[2];
static uint32_t device_local_cid[2];
// Inquiry data
static uint32_t device_page_scan_repetition_mode;
static uint32_t device_class;
static uint32_t device_clock_offset;
// Buffers
static struct wiimote_t wiimote_buffer;
static uint8_t psdata_buffer[512];
static struct btpad_interface* btpad_iface;
static void* btpad_device;
static bool btpad_want_wiimote;
static pthread_mutex_t btpad_lock = PTHREAD_MUTEX_INITIALIZER;
// MAIN THREAD ONLY
enum btpad_device_type_t btpad_get_connected_type()
{
return device_type;
}
uint32_t btpad_get_buttons()
{
switch (device_type)
{
case BTPAD_WIIMOTE:
return wiimote_buffer.btns | (wiimote_buffer.exp.classic.btns << 16);
case BTPAD_PS3:
return psdata_buffer[3] | (psdata_buffer[4] << 8);
default:
return 0;
}
pthread_mutex_lock(&btpad_lock);
uint32_t result = (btpad_device && btpad_iface) ? btpad_iface->get_buttons(btpad_device) : 0;
pthread_mutex_unlock(&btpad_lock);
return result;
}
void btpad_set_pad_type(bool wiimote)
{
pthread_mutex_lock(&btpad_lock);
btpad_want_wiimote = wiimote;
pthread_mutex_unlock(&btpad_lock);
}
// BT THREAD ONLY
static void set_ps3_data(unsigned leds)
static void btpad_connect_pad(bool wiimote)
{
// TODO: LEDS
pthread_mutex_lock(&btpad_lock);
static uint8_t report_buffer[] = {
0x52, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
ios_add_log_message("BTpad: Connecting to %s", wiimote ? "WiiMote" : "PS3");
bt_send_l2cap_ptr(device_local_cid[0], report_buffer, sizeof(report_buffer));
btpad_iface = (wiimote) ? &btpad_wii : &btpad_ps3;
btpad_device = btpad_iface->connect();
pthread_mutex_unlock(&btpad_lock);
}
static bool btstack_read_incoming_connection_packet(uint8_t* packet, uint16_t size)
static void btpad_disconnect_pad()
{
const uint32_t psm = READ_BT_16(packet, 10);
const unsigned interrupt = (psm == PSM_HID_INTERRUPT) ? 1 : 0;
pthread_mutex_lock(&btpad_lock);
bt_flip_addr_ptr(device_address, &packet[2]);
device_handle[interrupt] = READ_BT_16(packet, 8);
device_local_cid[interrupt] = READ_BT_16(packet, 12);
device_remote_cid[interrupt] = READ_BT_16(packet, 14);
return interrupt;
}
static void btstack_not_initialized_handler(uint8_t* packet, uint16_t size)
{
switch (packet[0])
if (btpad_iface && btpad_device)
{
case BTSTACK_EVENT_STATE:
ios_add_log_message("BTpad: Disconnecting");
btpad_iface->disconnect(btpad_device);
btpad_device = 0;
btpad_iface = 0;
}
pthread_mutex_unlock(&btpad_lock);
}
void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
if (packet_type == HCI_EVENT_PACKET && packet[0] == BTSTACK_EVENT_STATE)
{
if (packet[2] == HCI_STATE_WORKING)
{
ios_add_log_message("BTstack: Power state now HCI_STATE_WORKING");
ios_add_log_message("BTstack: Registering HID INTERRUPT service");
bt_send_cmd_ptr(l2cap_register_service_ptr, PSM_HID_INTERRUPT, 672);
}
else
ios_add_log_message("BTstack: State is now %d", packet[2]);
break;
btpad_connect_pad(btpad_want_wiimote);
else if(packet[2] > HCI_STATE_WORKING && btpad_iface && btpad_device)
btpad_disconnect_pad();
}
case L2CAP_EVENT_SERVICE_REGISTERED:
if (btpad_device && btpad_iface)
{
if (READ_BT_16(packet, 3) == PSM_HID_INTERRUPT)
{
ios_add_log_message("BTstack: HID INTERRUPT service registered");
ios_add_log_message("BTstack: Registering HID CONTROL service");
bt_send_cmd_ptr(l2cap_register_service_ptr, PSM_HID_CONTROL, 672);
}
else if(READ_BT_16(packet, 3) == PSM_HID_CONTROL)
{
ios_add_log_message("BTstack: HID CONTROL service registered");
ios_add_log_message("BTstack: Waiting for connection");
bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, 3, 0);
btpad_state = BTPAD_NO_CONNECTION;
}
break;
}
}
}
static void btstack_no_connection_handler(uint8_t* packet, uint16_t size)
{
switch (packet[0])
{
// Device is connecting to iOS
case L2CAP_EVENT_INCOMING_CONNECTION:
{
ios_add_log_message("BTstack: Incoming L2CAP connection (PS3 Pad?)");
btpad_state = BTPAD_CONNECTION;
bool ch = btstack_read_incoming_connection_packet(packet, size);
bt_send_cmd_ptr(l2cap_accept_connection_ptr, device_local_cid[ch ? 1 : 0]);
break;
}
// iOS is connecting to device
// Here we just copy the details of the first device found
case HCI_EVENT_INQUIRY_RESULT:
{
ios_add_log_message("BTstack: Inquiry found device (WiiMote?)");
if (packet[2])
{
btpad_state = BTPAD_INQUIRY_CONNECTION;
bt_flip_addr_ptr(device_address, &packet[3]);
device_page_scan_repetition_mode = packet [3 + packet[2] * (6)];
device_class = READ_BT_24(packet, 3 + packet[2] * (6+1+1+1));
device_clock_offset = READ_BT_16(packet, 3 + packet[2] * (6+1+1+1+3)) & 0x7fff;
}
break;
}
case HCI_EVENT_INQUIRY_COMPLETE:
{
bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, 3, 0);
break;
}
}
}
static void btstack_connection_handler(uint8_t* packet, uint16_t size)
{
switch (packet[0])
{
case L2CAP_EVENT_INCOMING_CONNECTION:
{
ios_add_log_message("BTstack: Got other half L2CAP connection; requesting name\n");
btpad_state = BTPAD_WANT_NAME;
bool ch = btstack_read_incoming_connection_packet(packet, size);
bt_send_cmd_ptr(l2cap_accept_connection_ptr, device_local_cid[ch ? 1 : 0]);
bt_send_cmd_ptr(hci_remote_name_request_ptr, device_address, 0, 0, 0);
break;
}
}
}
static void btstack_inquiry_connection_handler(uint8_t* packet, uint16_t size)
{
switch (packet[0])
{
case HCI_EVENT_INQUIRY_COMPLETE:
{
ios_add_log_message("BTstack: Got inquiry complete; requesting name\n");
btpad_state = BTPAD_WANT_NAME;
bt_send_cmd_ptr(hci_remote_name_request_ptr, device_address, device_page_scan_repetition_mode,
0, device_clock_offset | 0x8000);
break;
}
}
}
static void btstack_want_name_handler(uint8_t* packet, uint16_t size)
{
bd_addr_t event_addr;
switch (packet[0])
{
case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
{
bt_flip_addr_ptr(event_addr, &packet[3]);
if (BD_ADDR_CMP(event_addr, device_address) == 0)
{
strncpy(device_name, (const char*)&packet[9], 248);
device_name[248] = 0;
ios_add_log_message("BTstack: Got device name: %s\n", device_name);
if (strncmp(device_name, "Nintendo RVL-CNT-01", 19) == 0)
{
ios_add_log_message("BTstack: Got WiiMote\n");
btpad_state = BTPAD_CONNECTED;
device_type = BTPAD_WIIMOTE;
bt_send_cmd_ptr(l2cap_create_channel_ptr, device_address, PSM_HID_CONTROL);
}
else if(strncmp(device_name, "PLAYSTATION(R)3 Controller", 26) == 0)
{
ios_add_log_message("BTstack: Got PS3 Pad; Sending startup packets\n");
btpad_state = BTPAD_CONNECTED;
device_type = BTPAD_PS3;
// Special packet to tell PS3 controller to send reports
uint8_t data[] = {0x53, 0xF4, 0x42, 0x03, 0x00, 0x00};
bt_send_l2cap_ptr(device_local_cid[0], data, 6);
set_ps3_data(0);
}
else
{
ios_add_log_message("BTstack: Unrecognized device; Will keep looking");
btpad_state = BTPAD_NO_CONNECTION;
}
}
break;
}
}
}
static void btstack_ps3_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
if (packet_type == L2CAP_DATA_PACKET && packet[0] == 0xA1)
{
static bool tag = false;
if(!tag) ios_add_log_message("BTstack: Got PS3 Data Packet (Will only show once)\n");
tag = true;
memcpy(psdata_buffer, packet, size);
}
}
static void btstack_wiimote_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
bd_addr_t event_addr;
if (packet_type == HCI_EVENT_PACKET && packet[0] == L2CAP_EVENT_CHANNEL_OPENED)
{
bt_flip_addr_ptr(event_addr, &packet[3]);
const uint16_t psm = READ_BT_16(packet, 11);
if (packet[2] == 0 && BD_ADDR_CMP(event_addr, device_address) == 0)
{
ios_add_log_message("BTstack: WiiMote L2CAP channel openend: %02X\n", psm);
const unsigned interrupt = (psm == PSM_HID_INTERRUPT) ? 1 : 0;
device_local_cid[interrupt] = READ_BT_16(packet, 13);
device_remote_cid[interrupt] = READ_BT_16(packet, 15);
device_handle[interrupt] = READ_BT_16(packet, 9);
if (psm == PSM_HID_CONTROL)
{
bt_send_cmd_ptr(l2cap_create_channel_ptr, device_address, PSM_HID_INTERRUPT);
memset(&wiimote_buffer, 0, sizeof(struct wiimote_t));
wiimote_buffer.unid = 0;
wiimote_buffer.c_source_cid = device_local_cid[0];
wiimote_buffer.exp.type = EXP_NONE;
wiimote_buffer.wiiMoteConHandle = device_handle[0];
memcpy(&wiimote_buffer.addr, &device_address, BD_ADDR_LEN);
}
else if (psm == PSM_HID_INTERRUPT)
{
wiimote_buffer.i_source_cid = device_local_cid[1];
wiimote_buffer.state = WIIMOTE_STATE_CONNECTED;
wiimote_handshake(&wiimote_buffer, -1, NULL, -1);
}
}
else
{
ios_add_log_message("BTstack: Failed to open WiiMote L2CAP channel: %d", psm);
ios_add_log_message("BTstack: Won't recover, please exit RetroArch from the task switcher");
}
}
else if(packet_type == L2CAP_DATA_PACKET)
{
static bool tag = false;
if(!tag) ios_add_log_message("BTstack: Got Wii Data Packet (Will only show once)\n");
tag = true;
byte* msg = packet + 2;
switch (packet[1])
{
case WM_RPT_BTN:
{
wiimote_pressed_buttons(&wiimote_buffer, msg);
break;
}
case WM_RPT_READ:
{
wiimote_pressed_buttons(&wiimote_buffer, msg);
byte len = ((msg[2] & 0xF0) >> 4) + 1;
byte *data = (msg + 5);
wiimote_handshake(&wiimote_buffer, WM_RPT_READ, data, len);
return;
}
case WM_RPT_CTRL_STATUS:
{
wiimote_pressed_buttons(&wiimote_buffer, msg);
wiimote_handshake(&wiimote_buffer,WM_RPT_CTRL_STATUS,msg,-1);
return;
}
case WM_RPT_BTN_EXP:
{
wiimote_pressed_buttons(&wiimote_buffer, msg);
wiimote_handle_expansion(&wiimote_buffer, msg+2);
break;
}
}
}
}
void btstack_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
typedef void (*handler_t)(uint8_t*, uint16_t);
static handler_t const handlers[] =
{
&btstack_not_initialized_handler,
&btstack_no_connection_handler,
&btstack_inquiry_connection_handler,
&btstack_connection_handler,
&btstack_want_name_handler
};
if (packet_type == HCI_EVENT_PACKET && btpad_state <= BTPAD_WANT_NAME)
{
handlers[(unsigned)btpad_state](packet, size);
}
else if (btpad_state == BTPAD_CONNECTED)
{
if (device_type == BTPAD_PS3)
btstack_ps3_handler(packet_type, channel, packet, size);
else if(device_type == BTPAD_WIIMOTE)
btstack_wiimote_handler(packet_type, channel, packet, size);
}
if (packet_type == HCI_EVENT_PACKET)
{
bd_addr_t event_addr;
switch (packet[0])
{
// This PIN will work for Wiimotes, other devices with PINs aren't supported
case HCI_EVENT_PIN_CODE_REQUEST:
ios_add_log_message("BTstack: Sending PIN (will fail if device isn't WiiMote");
bt_flip_addr_ptr(event_addr, &packet[2]);
bt_send_cmd_ptr(hci_pin_code_request_reply_ptr, device_address, 6, &packet[2]);
break;
case L2CAP_EVENT_CHANNEL_CLOSED:
ios_add_log_message("BTstack: Lost L2CAP connection; will start searching for new device");
btpad_state = BTPAD_NO_CONNECTION;
device_type = BTPAD_NONE;
bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, 3, 0);
break;
}
pthread_mutex_lock(&btpad_lock);
btpad_iface->packet_handler(btpad_device, packet_type, channel, packet, size);
pthread_mutex_unlock(&btpad_lock);
}
}

View File

@ -16,9 +16,22 @@
#ifndef __IOS_RARCH_BTPAD_H__
#define __IOS_RARCH_BTPAD_H__
enum btpad_device_type_t { BTPAD_NONE, BTPAD_PENDING, BTPAD_WIIMOTE, BTPAD_PS3 };
enum btpad_device_type_t btpad_get_connected_type();
uint32_t btpad_get_buttons();
void btpad_set_pad_type(bool wiimote);
// Private interface
struct btpad_interface
{
void* (*connect)();
void (*disconnect)(void* device);
void (*set_leds)(void* device, unsigned leds);
uint32_t (*get_buttons)(void* device);
void (*packet_handler)(void* device, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
};
extern struct btpad_interface btpad_ps3;
extern struct btpad_interface btpad_wii;
#endif