Merge pull request #234 from Themaister/ios_btstack

Ios btstack
This commit is contained in:
Squarepusher 2013-06-22 20:23:13 -07:00
commit 7985de4eb8
23 changed files with 922 additions and 747 deletions

View File

@ -92,10 +92,9 @@ void* rarch_main_ios(void* args)
#ifdef HAVE_RGUI
char* system_directory = ios_get_rarch_system_directory();
strlcpy(g_extern.savestate_dir, system_directory,
sizeof(g_extern.savestate_dir));
strlcpy(g_extern.savefile_dir, system_directory,
sizeof(g_extern.savefile_dir));
strlcpy(g_extern.savestate_dir, system_directory, sizeof(g_extern.savestate_dir));
strlcpy(g_extern.savefile_dir, system_directory, sizeof(g_extern.savefile_dir));
free(system_directory);
menu_init();
g_extern.lifecycle_mode_state |= 1ULL << MODE_GAME;
@ -168,8 +167,6 @@ void* rarch_main_ios(void* args)
if (g_extern.main_is_init)
rarch_main_deinit();
free(system_directory);
#else
while ((g_extern.is_paused && !g_extern.is_oneshot) ? rarch_main_idle_iterate() : rarch_main_iterate());
rarch_main_deinit();

View File

@ -260,6 +260,7 @@ INPUT
#include "../ios/RetroArch/input/BTStack/btpad.c"
#include "../ios/RetroArch/input/BTStack/btpad_ps3.c"
#include "../ios/RetroArch/input/BTStack/btpad_wii.c"
#include "../ios/RetroArch/input/BTStack/btpad_queue.c"
#elif defined(__BLACKBERRY_QNX__)
#include "../blackberry-qnx/qnx_input.c"
#endif

View File

@ -41,8 +41,11 @@
<int key="NSvFlags">292</int>
<string key="NSFrame">{{160, 237}, {120, 44}}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
<int key="IBUITag">4</int>
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
<int key="IBUIContentHorizontalAlignment">0</int>
<int key="IBUIContentVerticalAlignment">0</int>
@ -75,6 +78,7 @@
<int key="NSvFlags">292</int>
<string key="NSFrame">{{20, 20}, {120, 44}}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="344367644"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
@ -97,6 +101,7 @@
<int key="NSvFlags">292</int>
<string key="NSFrame">{{160, 20}, {120, 44}}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="1033465661"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
@ -119,9 +124,11 @@
<int key="NSvFlags">292</int>
<string key="NSFrame">{{20, 237}, {120, 44}}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="61755535"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
<int key="IBUITag">1</int>
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
<int key="IBUIContentHorizontalAlignment">0</int>
<int key="IBUIContentVerticalAlignment">0</int>
@ -141,9 +148,11 @@
<int key="NSvFlags">292</int>
<string key="NSFrame">{{20, 186}, {120, 44}}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="58186559"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
<int key="IBUITag">3</int>
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
<int key="IBUIContentHorizontalAlignment">0</int>
<int key="IBUIContentVerticalAlignment">0</int>
@ -163,9 +172,11 @@
<int key="NSvFlags">292</int>
<string key="NSFrame">{{160, 186}, {120, 44}}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="721040644"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
<int key="IBUITag">2</int>
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
<int key="IBUIContentHorizontalAlignment">0</int>
<int key="IBUIContentVerticalAlignment">0</int>
@ -185,14 +196,16 @@
<int key="NSvFlags">292</int>
<string key="NSFrame">{{20, 135}, {260, 44}}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="694263183"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
<int key="IBUITag">1</int>
<int key="IBUITag">10</int>
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
<int key="IBNumberOfSegments">10</int>
<int key="IBSelectedSegmentIndex">0</int>
<array key="IBSegmentTitles">
<string>0</string>
<string>1</string>
<string>2</string>
<string>3</string>
@ -202,7 +215,6 @@
<string>7</string>
<string>8</string>
<string>9</string>
<string>10</string>
</array>
<array class="NSMutableArray" key="IBSegmentWidths">
<real value="0.0"/>
@ -258,6 +270,7 @@
<int key="NSvFlags">292</int>
<string key="NSFrame">{{20, 71}, {120, 44}}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="374409903"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
@ -280,6 +293,7 @@
<int key="NSvFlags">292</int>
<string key="NSFrame">{{160, 71}, {120, 44}}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="562513162"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
@ -300,6 +314,7 @@
</array>
<string key="NSFrame">{{0, 20}, {300, 300}}</string>
<reference key="NSSuperview"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="38801877"/>
<object class="NSColor" key="IBUIBackgroundColor">
<int key="NSColorSpace">3</int>
@ -324,12 +339,12 @@
<array class="NSMutableArray" key="connectionRecords">
<object class="IBConnectionRecord">
<object class="IBCocoaTouchEventConnection" key="connection">
<string key="label">closeGamePressed:</string>
<string key="label">basicEvent:</string>
<reference key="source" ref="61755535"/>
<reference key="destination" ref="372490531"/>
<int key="IBEventType">7</int>
</object>
<int key="connectionID">23</int>
<int key="connectionID">215</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchEventConnection" key="connection">
@ -342,30 +357,30 @@
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchEventConnection" key="connection">
<string key="label">resetGame:</string>
<string key="label">basicEvent:</string>
<reference key="source" ref="721040644"/>
<reference key="destination" ref="372490531"/>
<int key="IBEventType">7</int>
</object>
<int key="connectionID">138</int>
<int key="connectionID">214</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchEventConnection" key="connection">
<string key="label">saveState:</string>
<string key="label">basicEvent:</string>
<reference key="source" ref="694263183"/>
<reference key="destination" ref="372490531"/>
<int key="IBEventType">7</int>
</object>
<int key="connectionID">137</int>
<int key="connectionID">212</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchEventConnection" key="connection">
<string key="label">loadState:</string>
<string key="label">basicEvent:</string>
<reference key="source" ref="58186559"/>
<reference key="destination" ref="372490531"/>
<int key="IBEventType">7</int>
</object>
<int key="connectionID">136</int>
<int key="connectionID">213</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchEventConnection" key="connection">
@ -418,13 +433,13 @@
<array class="NSMutableArray" key="children">
<reference ref="694263183"/>
<reference ref="38801877"/>
<reference ref="721040644"/>
<reference ref="58186559"/>
<reference ref="562513162"/>
<reference ref="61755535"/>
<reference ref="374409903"/>
<reference ref="1033465661"/>
<reference ref="344367644"/>
<reference ref="721040644"/>
</array>
<reference key="parent" ref="0"/>
</object>
@ -515,9 +530,20 @@
<nil key="activeLocalization"/>
<dictionary class="NSMutableDictionary" key="localizations"/>
<nil key="sourceID"/>
<int key="maxID">210</int>
<int key="maxID">215</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<array class="NSMutableArray" key="referencedPartialClassDescriptions">
<object class="IBPartialClassDescription">
<string key="className">RetroArch_iOS</string>
<string key="superclassName">UINavigationController</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">./Classes/RetroArch_iOS.h</string>
</object>
</object>
</array>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes"/>
<int key="IBDocument.localizationMode">0</int>
<string key="IBDocument.TargetRuntimeIdentifier">IBIPadFramework</string>
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>

View File

@ -81,21 +81,21 @@ static UIView* g_pause_indicator_view;
- (void)openPauseMenu
{
// Setup save state selector
UISegmentedControl* stateSelect = (UISegmentedControl*)[g_pause_view viewWithTag:1];
UISegmentedControl* stateSelect = (UISegmentedControl*)[g_pause_view viewWithTag:10];
stateSelect.selectedSegmentIndex = (g_extern.state_slot < 10) ? g_extern.state_slot : -1;
g_extern.is_paused = true;
//
[UIView animateWithDuration:0.2
animations:^ { g_pause_view.alpha = 1.0f; }
completion:^(BOOL finished){}];
animations:^{ g_pause_view.alpha = 1.0f; }
completion:^(BOOL finished) { }];
}
- (void)closePauseMenu
{
[UIView animateWithDuration:0.2
animations:^ { g_pause_view.alpha = 0.0f; }
animations:^{ g_pause_view.alpha = 0.0f; }
completion:^(BOOL finished) { }
];
@ -105,9 +105,9 @@ static UIView* g_pause_indicator_view;
- (void)hidePauseButton
{
[UIView animateWithDuration:0.2
animations:^ { g_pause_indicator_view.alpha = ALMOST_INVISIBLE; }
completion:^(BOOL finished) { }
];
animations:^{ g_pause_indicator_view.alpha = ALMOST_INVISIBLE; }
completion:^(BOOL finished) { }
];
}
- (void)suspend
@ -170,9 +170,6 @@ void ios_flip_game_view()
{
dispatch_sync(dispatch_get_main_queue(), ^{
[g_view display];
// HACK: While here, copy input structures
ios_copy_input(&g_ios_input_data);
});
g_fast_forward_skips = g_is_syncing ? 0 : 3;
}

View File

@ -22,7 +22,6 @@
static NSMutableArray* g_messages;
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
#ifndef HAVE_DEBUG_DIAGLOG
void ios_add_log_message(const char* format, ...)
{
pthread_mutex_lock(&g_lock);
@ -39,54 +38,6 @@ void ios_add_log_message(const char* format, ...)
pthread_mutex_unlock(&g_lock);
}
#else
static FILE* old_stdout;
static FILE* old_stderr;
static FILE* log_stream;
static int stdout_write(void* mem_buffer, const char* data, int len)
{
pthread_mutex_lock(&g_lock);
g_messages = g_messages ? g_messages : [NSMutableArray array];
char buffer[len + 10];
strncpy(buffer, data, len);
buffer[len] = 0;
[g_messages addObject:[NSString stringWithFormat:@"%s", buffer]];
pthread_mutex_unlock(&g_lock);
return len;
}
void ios_log_init()
{
if (!log_stream)
{
old_stdout = stdout;
old_stderr = stderr;
log_stream = fwopen(0, stdout_write);
setvbuf(log_stream, 0, _IOLBF, 0);
stdout = log_stream;
stderr = log_stream;
}
}
void ios_log_quit()
{
if (log_stream)
{
stdout = old_stdout;
stderr = old_stderr;
fclose(log_stream);
log_stream = 0;
}
}
#endif
@implementation RALogView

View File

@ -165,7 +165,7 @@ static NSString* build_string_pair(NSString* stringA, NSString* stringB)
if (indexPath.section == _firmwareSectionIndex)
{
NSString* item = (NSString*)[self itemForIndexPath:indexPath];
[RetroArch_iOS displayErrorMessage:objc_getAssociatedObject(item, "OTHER") withTitle:item];
ios_display_alert(objc_getAssociatedObject(item, "OTHER"), item);
}
}

View File

@ -17,18 +17,12 @@
@interface RetroArch_iOS : UINavigationController<UIApplicationDelegate, UINavigationControllerDelegate>
+ (void)displayErrorMessage:(NSString*)message;
+ (void)displayErrorMessage:(NSString*)message withTitle:(NSString*)title;
+ (RetroArch_iOS*)get;
- (void)runGame:(NSString*)path withModule:(RAModuleInfo*)module;
- (void)refreshConfig;
- (void)refreshSystemConfig;
- (IBAction)startBluetooth;
- (IBAction)stopBluetooth;
@property (strong, nonatomic) NSString* documentsDirectory; // e.g. /var/mobile/Documents
@property (strong, nonatomic) NSString* systemDirectory; // e.g. /var/mobile/Documents/.RetroArch
@property (strong, nonatomic) NSString* systemConfigPath; // e.g. /var/mobile/Documents/.RetroArch/frontend.cfg
@ -36,4 +30,7 @@
@end
// utility.m
extern void ios_display_alert(NSString* message, NSString* title);
extern void ios_clear_config_hack();
extern bool path_make_and_check_directory(const char* path, mode_t mode, int amode);
extern NSString* ios_get_value_from_config(config_file_t* config, NSString* name, NSString* defaultValue);

View File

@ -115,7 +115,7 @@
}
}
else
[RetroArch_iOS displayErrorMessage:[NSString stringWithFormat:@"Browsed path is not a directory: %@", _path]];
ios_display_alert([NSString stringWithFormat:@"Browsed path is not a directory: %@", _path], 0);
[self.tableView reloadData];
}
@ -129,8 +129,8 @@
else
{
if (access(_path.UTF8String, R_OK | W_OK | X_OK))
[RetroArch_iOS displayErrorMessage:@"The directory containing the selected file has limited permissions. This may "
"prevent zipped games from loading, and will cause some cores to not function."];
ios_display_alert(@"The directory containing the selected file has limited permissions. This may "
"prevent zipped games from loading, and will cause some cores to not function.", 0);
[[RetroArch_iOS get] pushViewController:[[RAModuleList alloc] initWithGame:path.path] animated:YES];
}
@ -199,7 +199,7 @@
if (info && info.data)
[RetroArch_iOS.get pushViewController:[[RAModuleInfoList alloc] initWithModuleInfo:info] animated:YES];
else
[RetroArch_iOS displayErrorMessage:@"No information available."];
ios_display_alert(@"No information available.", 0);
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

View File

@ -37,9 +37,8 @@ static struct
GRAB(bt_send_l2cap),
GRAB(run_loop_init),
GRAB(run_loop_execute),
GRAB(btstack_get_system_bluetooth_enabled),
GRAB(btstack_set_power_mode),
GRAB(btstack_set_system_bluetooth_enabled),
GRAB(hci_delete_stored_link_key),
GRAB(hci_disconnect),
GRAB(hci_read_bd_addr),
@ -65,7 +64,7 @@ static bool btstack_loaded;
static bool btstack_open;
static bool btstack_poweron;
bool btstack_load()
bool btstack_try_load()
{
assert(sizeof(void**) == sizeof(void(*)()));
@ -109,47 +108,28 @@ bool btstack_load()
return true;
}
void btstack_start()
void btstack_set_poweron(bool on)
{
if (!btstack_load())
if (!btstack_try_load())
return;
if (!btstack_open)
if (!btstack_open && bt_open_ptr())
{
if (bt_open_ptr())
{
ios_add_log_message("BTstack: bt_open failed");
btstack_loaded = false;
return;
}
ios_add_log_message("BTstack: bt_open failed");
btstack_loaded = false;
return;
}
btstack_open = true;
if (!btstack_poweron)
if (on != btstack_poweron)
{
ios_add_log_message("BTstack: Turning on");
bt_send_cmd_ptr(btstack_set_power_mode_ptr, HCI_POWER_ON);
btstack_poweron = true;
}
}
void btstack_stop()
{
if (btstack_load() && btstack_open && btstack_poweron)
{
ios_add_log_message("BTstack: Turning off");
bt_send_cmd_ptr(btstack_set_power_mode_ptr, HCI_POWER_OFF);
btstack_poweron = false;
}
}
bool btstack_is_loaded()
{
return btstack_load();
btstack_poweron = on;
ios_add_log_message("BTstack: Turning %s", on ? "on" : "off");
bt_send_cmd_ptr(btstack_set_power_mode_ptr, on ? HCI_POWER_ON : HCI_POWER_OFF);
}
}
bool btstack_is_running()
{
return btstack_poweron;
}

View File

@ -20,10 +20,8 @@
#include "btstack/utils.h"
#include "btstack/btstack.h"
bool btstack_load();
void btstack_start();
void btstack_stop();
bool btstack_is_loaded();
bool btstack_try_load();
void btstack_set_poweron(bool on);
bool btstack_is_running();
#ifndef BUILDING_BTDYNAMIC
@ -41,9 +39,7 @@ BTDIMPORT void (*bt_send_l2cap_ptr)(uint16_t local_cid, uint8_t *data, uint16_t
BTDIMPORT void (*run_loop_init_ptr)(RUN_LOOP_TYPE type);
BTDIMPORT void (*run_loop_execute_ptr)();
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_read_bd_addr_ptr;

View File

@ -23,67 +23,94 @@
#include "../../rarch_wrapper.h"
#include "btdynamic.h"
#include "btpad.h"
#include "btpad_queue.h"
#include "wiimote.h"
static btpad_connection_t btpad_connection;
static btpad_connection_t btpad_connection[MAX_PADS];
static struct btpad_interface* btpad_iface[MAX_PADS];
static void* btpad_device[MAX_PADS];
static bool inquiry_off;
static bool inquiry_running;
static bool btpad_connection_test(uint16_t handle, bd_addr_t address)
// External interface (MAIN THREAD ONLY)
void btpad_set_inquiry_state(bool on)
{
if (handle && btpad_connection.handle && handle != btpad_connection.handle)
return false;
btpad_connection.handle = handle ? handle : btpad_connection.handle;
inquiry_off = !on;
if (address && btpad_connection.has_address && (BD_ADDR_CMP(address, btpad_connection.address)))
return false;
if (address)
{
btpad_connection.has_address = true;
memcpy(btpad_connection.address, address, sizeof(bd_addr_t));
}
return true;
if (!inquiry_off && !inquiry_running)
btpad_queue_hci_inquiry(HCI_INQUIRY_LAP, 3, 1);
}
static struct btpad_interface* btpad_iface;
static void* btpad_device;
// 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;
if (slot < MAX_PADS && 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;
if (slot < MAX_PADS && btpad_device[slot] && btpad_iface[slot])
return btpad_iface[slot]->get_axis(btpad_device[slot], axis);
return 0;
}
static void btpad_disconnect_pad()
// Internal interface:
static int32_t btpad_find_slot_for(uint16_t handle, bd_addr_t address)
{
if (btpad_iface && btpad_device)
for (int i = 0; i < MAX_PADS; i ++)
{
ios_add_log_message("BTpad: Disconnecting");
btpad_iface->disconnect(btpad_device);
btpad_device = 0;
btpad_iface = 0;
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;
}
if (btpad_connection.handle)
bt_send_cmd_ptr(hci_disconnect_ptr, btpad_connection.handle, 0x15);
memset(&btpad_connection, 0, sizeof(btpad_connection_t));
return -1;
}
static void btpad_connect_pad()
static int32_t btpad_find_slot_with_state(enum btpad_state state)
{
if (btpad_connection.state == BTPAD_CONNECTED)
btpad_disconnect_pad();
memset(&btpad_connection, 0, sizeof(btpad_connection_t));
for (int i = 0; i < MAX_PADS; i ++)
if (btpad_connection[i].state == state)
return i;
ios_add_log_message("BTpad: Requesting local address");
bt_send_cmd_ptr(hci_read_bd_addr_ptr);
return -1;
}
static void btpad_disconnect_pad(uint32_t slot)
{
if (slot > MAX_PADS)
return;
if (btpad_iface[slot] && btpad_device[slot])
{
ios_add_log_message("BTpad: Disconnecting slot %d", slot);
btpad_iface[slot]->disconnect(btpad_device[slot]);
btpad_device[slot] = 0;
btpad_iface[slot] = 0;
}
if (btpad_connection[slot].handle)
btpad_queue_hci_disconnect(btpad_connection[slot].handle, 0x15);
memset(&btpad_connection[slot], 0, sizeof(btpad_connection_t));
}
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)
@ -94,45 +121,41 @@ 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_connect_pad();
{
btpad_queue_reset();
btpad_queue_hci_read_bd_addr();
bt_send_cmd_ptr(l2cap_register_service_ptr, PSM_HID_CONTROL, 672); // TODO: Where did I get 672 for mtu?
bt_send_cmd_ptr(l2cap_register_service_ptr, 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();
break;
{
btpad_disconnect_all_pads();
}
}
break;
case HCI_EVENT_COMMAND_STATUS:
{
btpad_queue_run(packet[3]);
}
break;
case HCI_EVENT_COMMAND_COMPLETE:
{
btpad_queue_run(packet[2]);
if (COMMAND_COMPLETE_EVENT(packet, (*hci_read_bd_addr_ptr)))
{
if (packet[5])
ios_add_log_message("BTpad: Failed to get local address (E: %02X)", packet[5]);
else
{
bt_flip_addr_ptr(event_addr, &packet[6]);
ios_add_log_message("BTpad: Local address is %s", bd_addr_to_str_ptr(event_addr));
}
ios_add_log_message("BTpad: Registering HID INTERRUPT service");
bt_send_cmd_ptr(l2cap_register_service_ptr, PSM_HID_INTERRUPT, 672);
}
break;
case L2CAP_EVENT_SERVICE_REGISTERED:
{
uint32_t psm = READ_BT_16(packet, 3);
if (packet[2])
ios_add_log_message("BTpad: Failed to register HID service (PSM: %02X, E: %02X)", psm, packet[2]);
else if (psm == PSM_HID_INTERRUPT)
{
ios_add_log_message("BTpad: HID INTERRUPT service registered");
ios_add_log_message("BTpad: Registering HID CONTROL service");
bt_send_cmd_ptr(l2cap_register_service_ptr, PSM_HID_CONTROL, 672);
}
else if(psm == PSM_HID_CONTROL)
{
ios_add_log_message("BTpad: HID CONTROL service registered");
ios_add_log_message("BTpad: Starting inquiry");
bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, 3, 1);
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;
@ -142,15 +165,20 @@ 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].slot = slot;
bt_send_cmd_ptr(l2cap_create_channel_ptr, btpad_connection[slot].address, PSM_HID_CONTROL);
bt_send_cmd_ptr(l2cap_create_channel_ptr, btpad_connection[slot].address, PSM_HID_INTERRUPT);
}
}
}
@ -158,62 +186,50 @@ 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");
bt_send_cmd_ptr(l2cap_create_channel_ptr, btpad_connection.address, PSM_HID_CONTROL);
}
else if(btpad_connection.state == BTPAD_EMPTY)
{
if (btpad_connection.laps < 40)
{
btpad_connection.laps ++;
bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, 3, 1);
}
else
ios_add_log_message("BTpad: Did not find wiimote, will stop searching");
}
// TODO: Check performance and battery effect of this
inquiry_running = !inquiry_off;
if (inquiry_running)
btpad_queue_hci_inquiry(HCI_INQUIRY_LAP, 3, 1);
}
break;
case L2CAP_EVENT_CHANNEL_OPENED:
{
const uint8_t status = packet[2];
bt_flip_addr_ptr(event_addr, &packet[3]);
const uint16_t handle = READ_BT_16(packet, 9);
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 (status == 0)
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);
btpad_connection[slot].handle = handle;
if (psm == PSM_HID_CONTROL)
{
btpad_connection.channels[0] = channel_id;
ios_add_log_message("BTpad: Got HID CONTROL channel; Opening INTERRUPT");
bt_send_cmd_ptr(l2cap_create_channel_ptr, btpad_connection.address, PSM_HID_INTERRUPT);
}
btpad_connection[slot].channels[0] = channel_id;
else if (psm == PSM_HID_INTERRUPT)
{
btpad_connection.channels[1] = channel_id;
ios_add_log_message("BTpad: Got HID INTERRUPT channel; Requesting name");
bt_send_cmd_ptr(hci_remote_name_request_ptr, btpad_connection.address, btpad_connection.page_scan_repetition_mode,
0, btpad_connection.clock_offset | 0x8000);
}
btpad_connection[slot].channels[1] = channel_id;
else
ios_add_log_message("BTpad: Got unknown L2CAP channel, ignoring");
ios_add_log_message("BTpad: Got unknown L2CAP PSM, ignoring (Slot: %d, PSM: %02X)", slot, psm);
if (btpad_connection[slot].channels[0] && btpad_connection[slot].channels[1])
{
ios_add_log_message("BTpad: Got both L2CAP channels, requesting name (Slot: %d)", slot);
btpad_queue_hci_remote_name_request(btpad_connection[slot].address, 0, 0, 0);
}
}
else
ios_add_log_message("BTpad: Failed to open WiiMote L2CAP channel (PSM: %02X, E: %02X)", psm, status);
ios_add_log_message("BTpad: Got failed L2CAP 'Channel Opened' event (Slot %d, PSM: %02X, Status: %02X)", -1, psm, packet[2]);
}
break;
@ -223,31 +239,28 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
const uint16_t handle = READ_BT_16(packet, 8);
const uint32_t psm = READ_BT_16(packet, 10);
const uint32_t channel_id = READ_BT_16(packet, 12);
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
bt_send_cmd_ptr(l2cap_decline_connection_ptr, 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;
btpad_connection[slot].slot = slot;
}
else break;
}
btpad_connection.channels[interrupt] = channel_id;
bt_send_cmd_ptr(l2cap_accept_connection_ptr, btpad_connection.channels[interrupt]);
ios_add_log_message("BTpad: L2CAP Connection accepted");
if (btpad_connection.channels[0] && btpad_connection.channels[1])
{
ios_add_log_message("BTpad: Got both L2CAP channels, requesting name");
bt_send_cmd_ptr(hci_remote_name_request_ptr, btpad_connection.address, 0, 0, 0);
}
ios_add_log_message("BTpad: Incoming L2CAP connection (Slot: %d, PSM: %02X)", slot, psm);
bt_send_cmd_ptr(l2cap_accept_connection_ptr, channel_id);
}
break;
@ -255,38 +268,66 @@ 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]);
bt_send_cmd_ptr(hci_pin_code_request_reply_ptr, event_addr, 6, &packet[2]);
btpad_queue_hci_pin_code_request_reply(event_addr, &packet[2]);
}
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
{
const uint32_t handle = READ_BT_16(packet, 3);
if (!packet[2])
{
const int32_t slot = btpad_find_slot_for(handle, 0);
if (slot >= 0)
{
btpad_connection[slot].handle = 0;
btpad_disconnect_pad(slot);
ios_add_log_message("BTpad: Device disconnected (Slot: %d)", slot);
}
}
else
ios_add_log_message("BTpad: Got failed 'Disconnection Complete' event (Status: %02X)", packet[2]);
}
break;
case L2CAP_EVENT_SERVICE_REGISTERED:
{
if (!packet[2])
ios_add_log_message("BTpad: Got failed 'Service Registered' event (PSM: %02X, Status: %02X)", READ_BT_16(packet, 3), packet[2]);
}
break;
}
}
if (btpad_device && btpad_iface)
btpad_iface->packet_handler(btpad_device, packet_type, channel, packet, size);
for (int i = 0; i < MAX_PADS; 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

@ -18,26 +18,24 @@
#include "btstack/btstack.h"
uint32_t btpad_get_buttons();
int16_t btpad_get_axis(unsigned axis);
void btpad_set_inquiry_state(bool on);
uint32_t btpad_get_buttons(uint32_t slot);
int16_t btpad_get_axis(uint32_t slot, 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
{
enum btpad_state state;
uint32_t slot;
uint16_t handle;
bool has_address;
bd_addr_t address;
uint32_t laps;
uint32_t page_scan_repetition_mode;
uint32_t class;
uint32_t clock_offset;
uint16_t channels[2]; //0: Control, 1: Interrupt
bool connected;
@ -47,7 +45,6 @@ struct btpad_interface
{
void* (*connect)(const btpad_connection_t* connection);
void (*disconnect)(void* device);
void (*set_leds)(void* device, unsigned leds);
uint32_t (*get_buttons)(void* device);
int16_t (*get_axis)(void* device, unsigned axis);

View File

@ -31,39 +31,16 @@ struct btpad_ps3_data
uint32_t handle;
uint32_t channels[2];
uint32_t slot;
bool have_led;
};
static void btpad_ps3_setleds(struct btpad_ps3_data* device, unsigned leds);
static void* btpad_ps3_connect(const btpad_connection_t* connection)
{
struct btpad_ps3_data* device = malloc(sizeof(struct btpad_ps3_data));
memset(device, 0, sizeof(*device));
memcpy(device->address, connection->address, BD_ADDR_LEN);
device->handle = connection->handle;
device->channels[0] = connection->channels[0];
device->channels[1] = connection->channels[1];
// Magic packet to start reports
static uint8_t data[] = {0x53, 0xF4, 0x42, 0x03, 0x00, 0x00};
bt_send_l2cap_ptr(device->channels[0], data, 6);
// Without this the digital buttons won't be reported
btpad_ps3_setleds(device, 1);
return device;
}
static void btpad_ps3_disconnect(struct btpad_ps3_data* device)
{
}
static void btpad_ps3_setleds(struct btpad_ps3_data* device, unsigned leds)
static void btpad_ps3_send_control(struct btpad_ps3_data* device)
{
// TODO: Can this be modified to turn of motion tracking?
static uint8_t report_buffer[] = {
0x52, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x52, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
@ -74,13 +51,55 @@ static void btpad_ps3_setleds(struct btpad_ps3_data* device, unsigned leds)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
report_buffer[11] = (leds & 0xF) << 1;
report_buffer[11] = 1 << ((device->slot % 4) + 1);
bt_send_l2cap_ptr(device->channels[0], report_buffer, sizeof(report_buffer));
}
static void* btpad_ps3_connect(const btpad_connection_t* connection)
{
struct btpad_ps3_data* device = malloc(sizeof(struct btpad_ps3_data));
memset(device, 0, sizeof(*device));
memcpy(device->address, connection->address, BD_ADDR_LEN);
device->handle = connection->handle;
device->channels[0] = connection->channels[0];
device->channels[1] = connection->channels[1];
device->slot = connection->slot;
// Magic packet to start reports
static uint8_t data[] = {0x53, 0xF4, 0x42, 0x03, 0x00, 0x00};
bt_send_l2cap_ptr(device->channels[0], data, 6);
// Without this the digital buttons won't be reported
btpad_ps3_send_control(device);
return device;
}
static void btpad_ps3_disconnect(struct btpad_ps3_data* device)
{
}
static uint32_t btpad_ps3_get_buttons(struct btpad_ps3_data* device)
{
return device->data[3] | (device->data[4] << 8) | ((device->data[5] & 1) << 16);
#define KEY(X) RETRO_DEVICE_ID_JOYPAD_##X
static const uint32_t button_mapping[17] =
{
KEY(SELECT), KEY(L3), KEY(R3), KEY(START),
KEY(UP), KEY(RIGHT), KEY(DOWN), KEY(LEFT),
KEY(L2), KEY(R2), KEY(L), KEY(R),
KEY(X), KEY(A), KEY(B), KEY(Y),
16 //< PS Button
};
#undef KEY
const uint32_t pressed_keys = device->data[3] | (device->data[4] << 8) | ((device->data[5] & 1) << 16);
uint32_t result = 0;
for (int i = 0; i < 17; i ++)
result |= (pressed_keys & (1 << i)) ? (1 << button_mapping[i]) : 0;
return result;
}
static int16_t btpad_ps3_get_axis(struct btpad_ps3_data* device, unsigned axis)
@ -101,11 +120,14 @@ static void btpad_ps3_packet_handler(struct btpad_ps3_data* device, uint8_t pack
{
if (!device->have_led)
{
btpad_ps3_setleds(device, 1);
btpad_ps3_send_control(device);
device->have_led = true;
}
memcpy(device->data, packet, size);
g_current_input_data.pad_buttons[device->slot] = btpad_ps3_get_buttons(device);
for (int i = 0; i < 4; i ++)
g_current_input_data.pad_axis[device->slot][i] = btpad_ps3_get_axis(device, i);
}
}
@ -113,7 +135,6 @@ struct btpad_interface btpad_ps3 =
{
(void*)&btpad_ps3_connect,
(void*)&btpad_ps3_disconnect,
(void*)&btpad_ps3_setleds,
(void*)&btpad_ps3_get_buttons,
(void*)&btpad_ps3_get_axis,
(void*)&btpad_ps3_packet_handler

View File

@ -0,0 +1,176 @@
/* 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/>.
*/
#include "btdynamic.h"
#include "btpad.h"
#include "btpad_queue.h"
struct btpad_queue_command
{
const hci_cmd_t* command;
union
{
struct
{
uint8_t on;
} btstack_set_power_mode;
struct
{
uint16_t handle;
uint8_t reason;
} hci_disconnect;
struct
{
uint32_t lap;
uint8_t length;
uint8_t num_responses;
} hci_inquiry;
struct
{
bd_addr_t bd_addr;
uint8_t page_scan_repetition_mode;
uint8_t reserved;
uint16_t clock_offset;
} hci_remote_name_request;
struct // For wiimote only
{
bd_addr_t bd_addr;
bd_addr_t pin;
} hci_pin_code_request_reply;
};
};
struct btpad_queue_command commands[64];
static uint32_t insert_position;
static uint32_t read_position;
static uint32_t can_run;
#define INCPOS(POS) { POS##_position = (POS##_position + 1) % 64; }
void btpad_queue_reset()
{
insert_position = 0;
read_position = 0;
can_run = 1;
}
void btpad_queue_run(uint32_t count)
{
can_run = count;
btpad_queue_process();
}
void btpad_queue_process()
{
for (; can_run && (insert_position != read_position); can_run --)
{
struct btpad_queue_command* cmd = &commands[read_position];
if (cmd->command == btstack_set_power_mode_ptr)
bt_send_cmd_ptr(cmd->command, cmd->btstack_set_power_mode.on);
else if (cmd->command == hci_read_bd_addr_ptr)
bt_send_cmd_ptr(cmd->command);
else if (cmd->command == hci_disconnect_ptr)
bt_send_cmd_ptr(cmd->command, cmd->hci_disconnect.handle, cmd->hci_disconnect.reason);
else if (cmd->command == hci_inquiry_ptr)
bt_send_cmd_ptr(cmd->command, cmd->hci_inquiry.lap, cmd->hci_inquiry.length, cmd->hci_inquiry.num_responses);
else if (cmd->command == hci_remote_name_request_ptr)
bt_send_cmd_ptr(cmd->command, cmd->hci_remote_name_request.bd_addr, cmd->hci_remote_name_request.page_scan_repetition_mode,
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);
INCPOS(read);
}
}
void btpad_queue_btstack_set_power_mode(uint8_t on)
{
struct btpad_queue_command* cmd = &commands[insert_position];
cmd->command = btstack_set_power_mode_ptr;
cmd->btstack_set_power_mode.on = on;
INCPOS(insert);
btpad_queue_process();
}
void btpad_queue_hci_read_bd_addr()
{
struct btpad_queue_command* cmd = &commands[insert_position];
cmd->command = hci_read_bd_addr_ptr;
INCPOS(insert);
btpad_queue_process();
}
void btpad_queue_hci_disconnect(uint16_t handle, uint8_t reason)
{
struct btpad_queue_command* cmd = &commands[insert_position];
cmd->command = hci_disconnect_ptr;
cmd->hci_disconnect.handle = handle;
cmd->hci_disconnect.reason = reason;
INCPOS(insert);
btpad_queue_process();
}
void btpad_queue_hci_inquiry(uint32_t lap, uint8_t length, uint8_t num_responses)
{
struct btpad_queue_command* cmd = &commands[insert_position];
cmd->command = hci_inquiry_ptr;
cmd->hci_inquiry.lap = lap;
cmd->hci_inquiry.length = length;
cmd->hci_inquiry.num_responses = num_responses;
INCPOS(insert);
btpad_queue_process();
}
void btpad_queue_hci_remote_name_request(bd_addr_t bd_addr, uint8_t page_scan_repetition_mode, uint8_t reserved, uint16_t clock_offset)
{
struct btpad_queue_command* cmd = &commands[insert_position];
cmd->command = hci_remote_name_request_ptr;
memcpy(cmd->hci_remote_name_request.bd_addr, bd_addr, sizeof(bd_addr_t));
cmd->hci_remote_name_request.page_scan_repetition_mode = page_scan_repetition_mode;
cmd->hci_remote_name_request.reserved = reserved;
cmd->hci_remote_name_request.clock_offset = clock_offset;
INCPOS(insert);
btpad_queue_process();
}
void btpad_queue_hci_pin_code_request_reply(bd_addr_t bd_addr, bd_addr_t pin)
{
struct btpad_queue_command* cmd = &commands[insert_position];
cmd->command = hci_pin_code_request_reply_ptr;
memcpy(cmd->hci_pin_code_request_reply.bd_addr, bd_addr, sizeof(bd_addr_t));
memcpy(cmd->hci_pin_code_request_reply.pin, pin, sizeof(bd_addr_t));
INCPOS(insert);
btpad_queue_process();
}

View File

@ -0,0 +1,30 @@
/* 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_BTPAD_QUEUE_H__
#define __IOS_RARCH_BTPAD_QUEUE_H__
void btpad_queue_reset();
void btpad_queue_run(uint32_t count);
void btpad_queue_process();
void btpad_queue_btstack_set_power_mode(uint8_t on);
void btpad_queue_hci_read_bd_addr();
void btpad_queue_hci_disconnect(uint16_t handle, uint8_t reason);
void btpad_queue_hci_inquiry(uint32_t lap, uint8_t length, uint8_t num_responses);
void btpad_queue_hci_remote_name_request(bd_addr_t bd_addr, uint8_t page_scan_repetition_mode, uint8_t reserved, uint16_t clock_offset);
void btpad_queue_hci_pin_code_request_reply(bd_addr_t bd_addr, bd_addr_t pin);
#endif

View File

@ -31,6 +31,7 @@ static void* btpad_wii_connect(const btpad_connection_t* connection)
memcpy(device->addr, connection->address, BD_ADDR_LEN);
device->unid = connection->slot;
device->wiiMoteConHandle = connection->handle;
device->c_source_cid = connection->channels[0];
device->i_source_cid = connection->channels[1];
@ -46,11 +47,6 @@ static void btpad_wii_disconnect(struct wiimote_t* device)
{
}
static void btpad_wii_setleds(struct wiimote_t* device, unsigned leds)
{
// TODO
}
static uint32_t btpad_wii_get_buttons(struct wiimote_t* device)
{
return device->btns | (device->exp.classic.btns << 16);
@ -86,30 +82,34 @@ static void btpad_wii_packet_handler(struct wiimote_t* device, uint8_t packet_ty
case WM_RPT_BTN:
{
wiimote_pressed_buttons(device, msg);
return;
break;
}
case WM_RPT_READ:
{
wiimote_pressed_buttons(device, msg);
wiimote_handshake(device, WM_RPT_READ, msg + 5, ((msg[2] & 0xF0) >> 4) + 1);
return;
break;
}
case WM_RPT_CTRL_STATUS:
{
wiimote_pressed_buttons(device, msg);
wiimote_handshake(device,WM_RPT_CTRL_STATUS,msg,-1);
return;
break;
}
case WM_RPT_BTN_EXP:
{
wiimote_pressed_buttons(device, msg);
wiimote_handle_expansion(device, msg+2);
return;
break;
}
}
g_current_input_data.pad_buttons[device->unid] = btpad_wii_get_buttons(device);
for (int i = 0; i < 4; i ++)
g_current_input_data.pad_axis[device->unid][i] = btpad_wii_get_axis(device, i);
}
}
@ -117,7 +117,6 @@ struct btpad_interface btpad_wii =
{
(void*)&btpad_wii_connect,
(void*)&btpad_wii_disconnect,
(void*)&btpad_wii_setleds,
(void*)&btpad_wii_get_buttons,
(void*)&btpad_wii_get_axis,
(void*)&btpad_wii_packet_handler

View File

@ -13,7 +13,10 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <unistd.h>
#include <dispatch/dispatch.h>
#include "input/input_common.h"
#include "ios_input.h"
#include "general.h"
@ -22,6 +25,215 @@
extern const rarch_joypad_driver_t ios_joypad;
static const rarch_joypad_driver_t* const g_joydriver = &ios_joypad;
ios_input_data_t g_current_input_data;
ios_input_data_t g_polled_input_data;
static const struct rarch_key_map rarch_key_map_hidusage[];
// Main thread interface
static bool icade_enabled;
static uint32_t icade_buttons;
static void handle_icade_event(unsigned keycode)
{
static const struct
{
bool up;
int button;
} icade_map[0x20] =
{
{ false, -1 }, { false, -1 }, { false, -1 }, { false, -1 }, // 0
{ false, 2 }, { false, -1 }, { true , 3 }, { false, 3 }, // 4
{ true , 0 }, { true, 5 }, { true , 7 }, { false, 8 }, // 8
{ false, 6 }, { false, 9 }, { false, 10 }, { false, 11 }, // C
{ true , 6 }, { true , 9 }, { false, 7 }, { true, 10 }, // 0
{ true , 2 }, { true , 8 }, { false, -1 }, { true , 4 }, // 4
{ false, 5 }, { true , 11 }, { false, 0 }, { false, 1 }, // 8
{ false, 4 }, { true , 1 }, { false, -1 }, { false, -1 } // C
};
if (icade_enabled && (keycode < 0x20) && (icade_map[keycode].button >= 0))
{
const int button = icade_map[keycode].button;
if (icade_map[keycode].up)
icade_buttons &= ~(1 << button);
else
icade_buttons |= (1 << button);
}
}
void ios_input_enable_icade(bool on)
{
icade_enabled = on;
icade_buttons = 0;
}
void ios_input_handle_key_event(unsigned keycode, bool down)
{
if (icade_enabled)
handle_icade_event(keycode);
else if (keycode < MAX_KEYS)
g_current_input_data.keys[keycode] = down;
}
// Game thread interface
static bool ios_key_pressed(enum retro_key key)
{
if ((int)key >= 0 && key < RETROK_LAST)
return g_polled_input_data.keys[input_translate_rk_to_keysym(key)];
return false;
}
static bool ios_is_pressed(unsigned port_num, const struct retro_keybind *binds, unsigned key)
{
return ios_key_pressed(binds[key].key) || input_joypad_pressed(g_joydriver, port_num, binds, key);
}
// Exported input driver
static void *ios_input_init(void)
{
input_init_keyboard_lut(rarch_key_map_hidusage);
memset(&g_polled_input_data, 0, sizeof(g_polled_input_data));
return (void*)-1;
}
static void ios_input_poll(void *data)
{
dispatch_sync(dispatch_get_main_queue(), ^{
memcpy(&g_polled_input_data, &g_current_input_data, sizeof(ios_input_data_t));
for (int i = 0; i != g_polled_input_data.touch_count; i ++)
{
input_translate_coord_viewport(g_polled_input_data.touches[i].screen_x, g_polled_input_data.touches[i].screen_y,
&g_polled_input_data.touches[i].fixed_x, &g_polled_input_data.touches[i].fixed_y,
&g_polled_input_data.touches[i].full_x, &g_polled_input_data.touches[i].full_y);
}
input_joypad_poll(g_joydriver);
});
}
static int16_t ios_input_state(void *data, const struct retro_keybind **binds, unsigned port, unsigned device, unsigned index, unsigned id)
{
switch (device)
{
case RETRO_DEVICE_JOYPAD:
return (id < RARCH_BIND_LIST_END) ? ios_is_pressed(port, binds[port], id) : false;
case RETRO_DEVICE_ANALOG:
return input_joypad_analog(g_joydriver, port, index, id, binds[port]);
case RETRO_DEVICE_KEYBOARD:
return ios_key_pressed(id);
case RETRO_DEVICE_POINTER:
case RARCH_DEVICE_POINTER_SCREEN:
{
const bool want_full = device == RARCH_DEVICE_POINTER_SCREEN;
if (index < g_polled_input_data.touch_count && index < MAX_TOUCHES)
{
const ios_touch_data_t* touch = &g_polled_input_data.touches[index];
switch (id)
{
case RETRO_DEVICE_ID_POINTER_PRESSED: return 1;
case RETRO_DEVICE_ID_POINTER_X: return want_full ? touch->full_x : touch->fixed_x;
case RETRO_DEVICE_ID_POINTER_Y: return want_full ? touch->full_y : touch->fixed_y;
}
}
return 0;
}
default:
return 0;
}
}
static bool ios_bind_button_pressed(void *data, int key)
{
const struct retro_keybind *binds = g_settings.input.binds[0];
return (key >= 0 && key < RARCH_BIND_LIST_END) ? ios_is_pressed(0, binds, key) : false;
}
static void ios_input_free_input(void *data)
{
(void)data;
}
static void ios_input_set_keybinds(void *data, unsigned device, unsigned port,
unsigned id, unsigned keybind_action)
{
(void)device;
if (keybind_action & (1ULL << KEYBINDS_ACTION_SET_DEFAULT_BINDS))
{
switch (device)
{
case DEVICE_NONE:
break;
case DEVICE_WIIMOTE:
strlcpy(g_settings.input.device_names[port], "Wiimote + Classic",
sizeof(g_settings.input.device_names[port]));
g_settings.input.device[port] = device;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_B].joykey = 22;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_Y].joykey = 21;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_SELECT].joykey = 28;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_START].joykey = 26;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_UP].joykey = 16;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_DOWN].joykey = 30;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_LEFT].joykey = 17;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_RIGHT].joykey = 31;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_A].joykey = 20;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_X].joykey = 19;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L].joykey = 29;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R].joykey = 25;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].joykey = 23;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].joykey = 18;
g_settings.input.binds[port][RARCH_MENU_TOGGLE].joykey = 27;
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
break;
case DEVICE_SIXAXIS:
strlcpy(g_settings.input.device_names[port], "SixAxis/DualShock3",
sizeof(g_settings.input.device_names[port]));
g_settings.input.device[port] = device;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_B].joykey = 14;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_Y].joykey = 15;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_SELECT].joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_START].joykey = 3;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_UP].joykey = 4;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_DOWN].joykey = 6;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_LEFT].joykey = 7;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_RIGHT].joykey = 5;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_A].joykey = 13;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_X].joykey = 12;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L].joykey = 10;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R].joykey = 11;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].joykey = 8;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].joykey = 9;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].joykey = 1;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].joykey = 2;
g_settings.input.binds[port][RARCH_MENU_TOGGLE].joykey = 16;
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
break;
}
}
}
const input_driver_t input_ios = {
ios_input_init,
ios_input_poll,
ios_input_state,
ios_bind_button_pressed,
ios_input_free_input,
ios_input_set_keybinds,
"ios_input",
};
// Key table
#include "keycode.h"
static const struct rarch_key_map rarch_key_map_hidusage[] = {
@ -166,158 +378,4 @@ static const struct rarch_key_map rarch_key_map_hidusage[] = {
// RETROK_EURO },
// RETROK_UNDO },
{ 0, RETROK_UNKNOWN }
};
ios_input_data_t g_ios_input_data;
// Non-exported helpers
static bool ios_key_pressed(enum retro_key key)
{
if ((int)key >= 0 && key < RETROK_LAST)
return g_ios_input_data.keys[input_translate_rk_to_keysym(key)];
return false;
}
static bool ios_is_pressed(unsigned port_num, const struct retro_keybind *binds, unsigned key)
{
return ios_key_pressed(binds[key].key) || input_joypad_pressed(g_joydriver, port_num, binds, key);
}
// Exported input driver
static void *ios_input_init(void)
{
input_init_keyboard_lut(rarch_key_map_hidusage);
memset(&g_ios_input_data, 0, sizeof(g_ios_input_data));
return (void*)-1;
}
static void ios_input_poll(void *data)
{
for (int i = 0; i != g_ios_input_data.touch_count; i ++)
{
input_translate_coord_viewport(g_ios_input_data.touches[i].screen_x, g_ios_input_data.touches[i].screen_y,
&g_ios_input_data.touches[i].fixed_x, &g_ios_input_data.touches[i].fixed_y,
&g_ios_input_data.touches[i].full_x, &g_ios_input_data.touches[i].full_y);
}
input_joypad_poll(g_joydriver);
}
static int16_t ios_input_state(void *data, const struct retro_keybind **binds, unsigned port, unsigned device, unsigned index, unsigned id)
{
switch (device)
{
case RETRO_DEVICE_JOYPAD:
return (id < RARCH_BIND_LIST_END) ? ios_is_pressed(port, binds[port], id) : false;
case RETRO_DEVICE_ANALOG:
return input_joypad_analog(g_joydriver, port, index, id, binds[port]);
case RETRO_DEVICE_KEYBOARD:
return ios_key_pressed(id);
case RETRO_DEVICE_POINTER:
case RARCH_DEVICE_POINTER_SCREEN:
{
const bool want_full = device == RARCH_DEVICE_POINTER_SCREEN;
if (index < g_ios_input_data.touch_count && index < MAX_TOUCHES)
{
const ios_touch_data_t* touch = &g_ios_input_data.touches[index];
switch (id)
{
case RETRO_DEVICE_ID_POINTER_PRESSED: return 1;
case RETRO_DEVICE_ID_POINTER_X: return want_full ? touch->full_x : touch->fixed_x;
case RETRO_DEVICE_ID_POINTER_Y: return want_full ? touch->full_y : touch->fixed_y;
}
}
return 0;
}
default:
return 0;
}
}
static bool ios_bind_button_pressed(void *data, int key)
{
const struct retro_keybind *binds = g_settings.input.binds[0];
return (key >= 0 && key < RARCH_BIND_LIST_END) ? ios_is_pressed(0, binds, key) : false;
}
static void ios_input_free_input(void *data)
{
(void)data;
}
static void ios_input_set_keybinds(void *data, unsigned device, unsigned port,
unsigned id, unsigned keybind_action)
{
(void)device;
if (keybind_action & (1ULL << KEYBINDS_ACTION_SET_DEFAULT_BINDS))
{
switch (device)
{
case DEVICE_NONE:
break;
case DEVICE_WIIMOTE:
strlcpy(g_settings.input.device_names[port], "Wiimote + Classic",
sizeof(g_settings.input.device_names[port]));
g_settings.input.device[port] = device;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_B].joykey = 22;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_Y].joykey = 21;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_SELECT].joykey = 28;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_START].joykey = 26;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_UP].joykey = 16;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_DOWN].joykey = 30;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_LEFT].joykey = 17;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_RIGHT].joykey = 31;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_A].joykey = 20;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_X].joykey = 19;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L].joykey = 29;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R].joykey = 25;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].joykey = 23;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].joykey = 18;
g_settings.input.binds[port][RARCH_MENU_TOGGLE].joykey = 27;
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
break;
case DEVICE_SIXAXIS:
strlcpy(g_settings.input.device_names[port], "SixAxis/DualShock3",
sizeof(g_settings.input.device_names[port]));
g_settings.input.device[port] = device;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_B].joykey = 14;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_Y].joykey = 15;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_SELECT].joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_START].joykey = 3;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_UP].joykey = 4;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_DOWN].joykey = 6;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_LEFT].joykey = 7;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_RIGHT].joykey = 5;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_A].joykey = 13;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_X].joykey = 12;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L].joykey = 10;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R].joykey = 11;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].joykey = 8;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].joykey = 9;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].joykey = 1;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].joykey = 2;
g_settings.input.binds[port][RARCH_MENU_TOGGLE].joykey = 16;
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
break;
}
}
}
const input_driver_t input_ios = {
ios_input_init,
ios_input_poll,
ios_input_state,
ios_bind_button_pressed,
ios_input_free_input,
ios_input_set_keybinds,
"ios_input",
};
};

View File

@ -19,6 +19,7 @@
// Input responder
#define MAX_TOUCHES 16
#define MAX_KEYS 256
#define MAX_PADS 4
typedef struct
{
@ -34,16 +35,15 @@ typedef struct
uint32_t keys[MAX_KEYS];
uint32_t pad_buttons;
int16_t pad_axis[4];
uint32_t pad_buttons[MAX_PADS];
int16_t pad_axis[MAX_PADS][4];
} ios_input_data_t;
extern ios_input_data_t g_ios_input_data;
extern ios_input_data_t g_current_input_data; //< Main thread data
extern ios_input_data_t g_polled_input_data; //< Game thread data
// Defined in main.m, must be called on the emu thread in a dispatch_sync block
void ios_copy_input(ios_input_data_t* data);
// Called from main.m, defined in ios_input.c
void ios_add_key_event(bool down, unsigned keycode, uint32_t character, uint16_t keyModifiers);
// Main thread only
void ios_input_enable_icade(bool on);
void ios_input_handle_key_event(unsigned keycode, bool down);
#endif

View File

@ -41,7 +41,7 @@ static bool ios_joypad_button(unsigned port, uint16_t joykey)
if (GET_HAT_DIR(joykey))
return false;
else // Check the button
return (port == 0 && joykey < 32) ? (g_ios_input_data.pad_buttons & (1 << joykey)) != 0 : false;
return (port < MAX_PADS && joykey < 32) ? (g_polled_input_data.pad_buttons[port] & (1 << joykey)) != 0 : false;
}
static int16_t ios_joypad_axis(unsigned port, uint32_t joyaxis)
@ -52,12 +52,12 @@ static int16_t ios_joypad_axis(unsigned port, uint32_t joyaxis)
int16_t val = 0;
if (AXIS_NEG_GET(joyaxis) < 4)
{
val = g_ios_input_data.pad_axis[AXIS_NEG_GET(joyaxis)];
val = g_polled_input_data.pad_axis[AXIS_NEG_GET(joyaxis)];
val = (val < 0) ? val : 0;
}
else if(AXIS_POS_GET(joyaxis) < 4)
{
val = g_ios_input_data.pad_axis[AXIS_POS_GET(joyaxis)];
val = g_polled_input_data.pad_axis[AXIS_POS_GET(joyaxis)];
val = (val > 0) ? val : 0;
}

View File

@ -13,7 +13,6 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <sys/stat.h>
#include <pthread.h>
#include <string.h>
@ -30,82 +29,29 @@
#include "file.h"
//#define HAVE_DEBUG_FILELOG
static bool use_tv_mode;
static ios_input_data_t g_input_data;
static bool enable_btstack;
static bool use_icade;
static uint32_t icade_buttons;
bool path_make_and_check_directory(const char* path, mode_t mode, int amode)
{
if (!path_is_directory(path) && mkdir(path, mode) != 0)
return false;
return access(path, amode) == 0;
}
// Input helpers
void ios_copy_input(ios_input_data_t* data)
{
// Call only from main thread
memcpy(data, &g_input_data, sizeof(g_input_data));
data->pad_buttons = btpad_get_buttons() | (use_icade ? icade_buttons : 0);
for (int i = 0; i < 4; i ++)
data->pad_axis[i] = btpad_get_axis(i);
}
// Input helpers: This is kept here because it needs objective-c
static void handle_touch_event(NSArray* touches)
{
const int numTouches = [touches count];
const float scale = [[UIScreen mainScreen] scale];
g_input_data.touch_count = 0;
g_current_input_data.touch_count = 0;
for(int i = 0; i != numTouches && g_input_data.touch_count < MAX_TOUCHES; i ++)
for(int i = 0; i != numTouches && g_current_input_data.touch_count < MAX_TOUCHES; i ++)
{
UITouch* touch = [touches objectAtIndex:i];
const CGPoint coord = [touch locationInView:touch.view];
if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled)
{
g_input_data.touches[g_input_data.touch_count ].screen_x = coord.x * scale;
g_input_data.touches[g_input_data.touch_count ++].screen_y = coord.y * scale;
g_current_input_data.touches[g_current_input_data.touch_count ].screen_x = coord.x * scale;
g_current_input_data.touches[g_current_input_data.touch_count ++].screen_y = coord.y * scale;
}
}
}
static void handle_icade_event(unsigned keycode)
{
static const struct
{
bool up;
int button;
} icade_map[0x20] =
{
{ false, -1 }, { false, -1 }, { false, -1 }, { false, -1 }, // 0
{ false, 2 }, { false, -1 }, { true , 3 }, { false, 3 }, // 4
{ true , 0 }, { true, 5 }, { true , 7 }, { false, 8 }, // 8
{ false, 6 }, { false, 9 }, { false, 10 }, { false, 11 }, // C
{ true , 6 }, { true , 9 }, { false, 7 }, { true, 10 }, // 0
{ true , 2 }, { true , 8 }, { false, -1 }, { true , 4 }, // 4
{ false, 5 }, { true , 11 }, { false, 0 }, { false, 1 }, // 8
{ false, 4 }, { true , 1 }, { false, -1 }, { false, -1 } // C
};
if ((keycode < 0x20) && (icade_map[keycode].button >= 0))
{
const int button = icade_map[keycode].button;
if (icade_map[keycode].up)
icade_buttons &= ~(1 << button);
else
icade_buttons |= (1 << button);
}
}
@interface RApplication : UIApplication
@end
@ -127,14 +73,7 @@ static void handle_icade_event(unsigned keycode)
int eventType = eventMem ? *(int*)&eventMem[8] : 0;
if (eventType == GSEVENT_TYPE_KEYDOWN || eventType == GSEVENT_TYPE_KEYUP)
{
uint16_t key = *(uint16_t*)&eventMem[0x3C];
if (!use_icade && key < MAX_KEYS)
g_input_data.keys[key] = (eventType == GSEVENT_TYPE_KEYDOWN);
else if (eventType == GSEVENT_TYPE_KEYDOWN)
handle_icade_event(key);
}
ios_input_handle_key_event(*(uint16_t*)&eventMem[0x3C], eventType == GSEVENT_TYPE_KEYDOWN);
CFBridgingRelease(eventMem);
}
@ -160,19 +99,18 @@ int main(int argc, char *argv[])
extern void* rarch_main_ios(void* args);
extern void ios_frontend_post_event(void (*fn)(void*), void* userdata);
static void event_game_reset(void* userdata)
{
rarch_game_reset();
}
static void event_load_state(void* userdata)
// These are based on the tag property of the button used to trigger the event
enum basic_event_t { RESET = 1, LOAD_STATE = 2, SAVE_STATE = 3, QUIT = 4 };
static void event_basic_command(void* userdata)
{
rarch_load_state();
}
static void event_save_state(void* userdata)
{
rarch_save_state();
switch ((enum basic_event_t)userdata)
{
case RESET: rarch_game_reset(); return;
case LOAD_STATE: rarch_load_state(); return;
case SAVE_STATE: rarch_save_state(); return;
case QUIT: g_extern.system.shutdown = true; return;
}
}
static void event_set_state_slot(void* userdata)
@ -182,31 +120,16 @@ static void event_set_state_slot(void* userdata)
static void event_show_rgui(void* userdata)
{
if (g_extern.lifecycle_mode_state & (1ULL << MODE_MENU))
{
g_extern.lifecycle_mode_state &= ~(1ULL << MODE_MENU);
g_extern.lifecycle_mode_state |= (1ULL << MODE_GAME);
}
else
{
g_extern.lifecycle_mode_state &= ~(1ULL << MODE_GAME);
g_extern.lifecycle_mode_state |= (1ULL << MODE_MENU);
}
}
static void event_quit(void* userdata)
{
g_extern.system.shutdown = true;
const bool in_menu = g_extern.lifecycle_mode_state & (1 << MODE_MENU);
g_extern.lifecycle_mode_state &= ~(1ULL << (in_menu ? MODE_MENU : MODE_GAME));
g_extern.lifecycle_mode_state |= (1ULL << (in_menu ? MODE_GAME : MODE_MENU));
}
static void event_reload_config(void* userdata)
{
// Need to clear these otherwise stale versions may be used!
memset(g_settings.input.overlay, 0, sizeof(g_settings.input.overlay));
memset(g_settings.video.shader_path, 0, sizeof(g_settings.video.shader_path));
ios_clear_config_hack();
uninit_drivers();
g_extern.block_config_read = false;
config_load();
init_drivers();
}
@ -226,21 +149,6 @@ static void event_reload_config(void* userdata)
RAModuleInfo* _module;
}
+ (void)displayErrorMessage:(NSString*)message
{
[RetroArch_iOS displayErrorMessage:message withTitle:@"RetroArch"];
}
+ (void)displayErrorMessage:(NSString*)message withTitle:(NSString*)title
{
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:title
message:message
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
+ (RetroArch_iOS*)get
{
return (RetroArch_iOS*)[[UIApplication sharedApplication] delegate];
@ -249,10 +157,6 @@ static void event_reload_config(void* userdata)
// UIApplicationDelegate
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
#ifdef HAVE_DEBUG_DIAGLOG
ios_log_init();
#endif
self.delegate = self;
// Setup window
@ -266,18 +170,21 @@ static void event_reload_config(void* userdata)
self.systemConfigPath = [self.systemDirectory stringByAppendingPathComponent:@"frontend.cfg"];
if (!path_make_and_check_directory(self.documentsDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
[RetroArch_iOS displayErrorMessage:[NSString stringWithFormat:@"Failed to create or access base directory: %@", self.documentsDirectory]];
ios_display_alert([NSString stringWithFormat:@"Failed to create or access base directory: %@", self.documentsDirectory], 0);
else if (!path_make_and_check_directory(self.systemDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
[RetroArch_iOS displayErrorMessage:[NSString stringWithFormat:@"Failed to create or access system directory: %@", self.systemDirectory]];
ios_display_alert([NSString stringWithFormat:@"Failed to create or access system directory: %@", self.systemDirectory], 0);
else
{
[self pushViewController:[RADirectoryList directoryListAtBrowseRoot] animated:YES];
[self refreshSystemConfig];
if (use_tv_mode)
[self runGame:nil withModule:nil];
}
// Warn if there are no cores present
if ([RAModuleInfo getModules].count == 0)
[RetroArch_iOS displayErrorMessage:@"No libretro cores were found. You will not be able to play any games."];
ios_display_alert(@"No libretro cores were found. You will not be able to play any games.", 0);
}
- (void)applicationWillEnterForeground:(UIApplication *)application
@ -351,29 +258,36 @@ static void event_reload_config(void* userdata)
{
if (!_isRunning)
{
_module = module;
[RASettingsList refreshModuleConfig:_module];
[self pushViewController:RAGameView.get animated:NO];
_isRunning = true;
_module = module;
[RASettingsList refreshModuleConfig:_module];
btpad_set_inquiry_state(false);
struct rarch_main_wrap* load_data = malloc(sizeof(struct rarch_main_wrap));
memset(load_data, 0, sizeof(struct rarch_main_wrap));
load_data->libretro_path = strdup(_module.path.UTF8String);
load_data->rom_path = strdup(path.UTF8String);
load_data->sram_path = strdup(self.systemDirectory.UTF8String);
load_data->state_path = strdup(self.systemDirectory.UTF8String);
load_data->config_path = strdup(_module.configPath.UTF8String);
load_data->verbose = false;
if (path && module)
{
load_data->libretro_path = strdup(_module.path.UTF8String);
load_data->rom_path = strdup(path.UTF8String);
load_data->config_path = strdup(_module.configPath.UTF8String);
}
else
load_data->config_path = strdup(RAModuleInfo.globalConfigPath.UTF8String);
if (pthread_create(&_retroThread, 0, rarch_main_ios, load_data))
{
[self rarchExited:NO];
return;
}
pthread_detach(_retroThread);
[self refreshSystemConfig];
}
}
@ -381,7 +295,7 @@ static void event_reload_config(void* userdata)
- (void)rarchExited:(BOOL)successful
{
if (!successful)
[RetroArch_iOS displayErrorMessage:@"Failed to load game."];
ios_display_alert(@"Failed to load game.", 0);
if (_isRunning)
{
@ -390,7 +304,12 @@ static void event_reload_config(void* userdata)
//
[self popToViewController:[RAGameView get] animated:NO];
[self popViewControllerAnimated:NO];
btpad_set_inquiry_state(true);
}
if (use_tv_mode)
[self runGame:nil withModule:nil];
_module = nil;
}
@ -400,11 +319,7 @@ static void event_reload_config(void* userdata)
if (_isRunning)
ios_frontend_post_event(&event_reload_config, 0);
else
{
// Need to clear these otherwise stale versions may be used!
memset(g_settings.input.overlay, 0, sizeof(g_settings.input.overlay));
memset(g_settings.video.shader_path, 0, sizeof(g_settings.video.shader_path));
}
ios_clear_config_hack();
}
- (void)refreshSystemConfig
@ -435,13 +350,10 @@ static void event_reload_config(void* userdata)
}
//
config_get_bool(conf, "ios_use_icade", &use_icade);
config_get_bool(conf, "ios_use_btstack", &enable_btstack);
if (enable_btstack)
[self startBluetooth];
else
[self stopBluetooth];
bool val;
ios_input_enable_icade(config_get_bool(conf, "ios_use_icade", &val) && val);
btstack_set_poweron(config_get_bool(conf, "ios_use_btstack", &val) && val);
use_tv_mode = config_get_bool(conf, "ios_tv_mode", & val) && val;
config_file_free(conf);
}
@ -467,33 +379,19 @@ static void event_reload_config(void* userdata)
{
_isPaused = true;
[[RAGameView get] openPauseMenu];
btpad_set_inquiry_state(true);
}
}
- (IBAction)resetGame:(id)sender
- (IBAction)basicEvent:(id)sender
{
if (_isRunning)
ios_frontend_post_event(&event_game_reset, 0);
ios_frontend_post_event(&event_basic_command, ((UIView*)sender).tag);
[self closePauseMenu:sender];
}
- (IBAction)loadState:(id)sender
{
if (_isRunning)
ios_frontend_post_event(&event_load_state, 0);
[self closePauseMenu:sender];
}
- (IBAction)saveState:(id)sender
{
if (_isRunning)
ios_frontend_post_event(&event_save_state, 0);
[self closePauseMenu:sender];
}
- (IBAction)chooseState:(id)sender
{
if (_isRunning)
@ -512,18 +410,13 @@ static void event_reload_config(void* userdata)
{
[[RAGameView get] closePauseMenu];
_isPaused = false;
}
- (IBAction)closeGamePressed:(id)sender
{
[self closePauseMenu:sender];
ios_frontend_post_event(event_quit, 0);
btpad_set_inquiry_state(false);
}
- (IBAction)showSettings
{
if (_module)
[self pushViewController:[[RASettingsList alloc] initWithModule:_module] animated:YES];
[self pushViewController:[[RASettingsList alloc] initWithModule:_module] animated:YES];
}
- (IBAction)showSystemSettings
@ -531,19 +424,6 @@ static void event_reload_config(void* userdata)
[self pushViewController:[RASystemSettingsList new] animated:YES];
}
#pragma mark Bluetooth Helpers
- (IBAction)startBluetooth
{
if (btstack_is_loaded() && !btstack_is_running())
btstack_start();
}
- (IBAction)stopBluetooth
{
if (btstack_is_loaded())
btstack_stop();
}
@end
void ios_rarch_exited(void* result)

View File

@ -30,13 +30,6 @@ void ios_set_game_view_sync(unsigned interval);
void ios_get_game_view_size(unsigned *width, unsigned *height);
void ios_bind_game_view_fbo();
#ifndef HAVE_DEBUG_DIAGLOG
void ios_add_log_message(const char* format, ...);
#else
void ios_log_init();
void ios_log_quit();
// Thread safe
#define ios_add_log_message(...) do { printf(__VA_ARGS__); printf("\n"); } while(0)
#endif
#endif

View File

@ -41,6 +41,8 @@ enum SettingTypes
@property double rangeMin;
@property double rangeMax;
@property uint32_t player;
@property bool haveNoneOption;
- (id)initWithType:(enum SettingTypes)aType label:(NSString*)aLabel name:(NSString*)aName;
@ -73,14 +75,17 @@ static RASettingData* boolean_setting(config_file_t* config, NSString* name, NSS
return result;
}
static RASettingData* button_setting(config_file_t* config, NSString* name, NSString* label, NSString* defaultValue)
static RASettingData* button_setting(config_file_t* config, uint32_t player, NSString* name, NSString* label, NSString* defaultValue)
{
RASettingData* result = [[RASettingData alloc] initWithType:ButtonSetting label:label name:name];
NSString* realname = player ? [NSString stringWithFormat:@"input_player%d_%@", player, name] : name;
RASettingData* result = [[RASettingData alloc] initWithType:ButtonSetting label:label name:realname];
result.msubValues = [NSMutableArray arrayWithObjects:
ios_get_value_from_config(config, name, defaultValue),
ios_get_value_from_config(config, [name stringByAppendingString:@"_btn"], @"nul"),
ios_get_value_from_config(config, [name stringByAppendingString:@"_axis"], @"nul"),
ios_get_value_from_config(config, realname, defaultValue),
ios_get_value_from_config(config, [realname stringByAppendingString:@"_btn"], @"nul"),
ios_get_value_from_config(config, [realname stringByAppendingString:@"_axis"], @"nul"),
nil];
result.player = player ? player - 1 : 0;
return result;
}
@ -163,6 +168,42 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
return result;
}
static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
{
return [NSArray arrayWithObjects:
[NSArray arrayWithObjects:[NSString stringWithFormat:@"Player %d", player],
button_setting(config, player, @"up", @"Up", @"up"),
button_setting(config, player, @"down", @"Down", @"down"),
button_setting(config, player, @"left", @"Left", @"left"),
button_setting(config, player, @"right", @"Right", @"right"),
button_setting(config, player, @"start", @"Start", @"enter"),
button_setting(config, player, @"select", @"Select", @"rshift"),
button_setting(config, player, @"b", @"B", @"z"),
button_setting(config, player, @"a", @"A", @"x"),
button_setting(config, player, @"x", @"X", @"s"),
button_setting(config, player, @"y", @"Y", @"a"),
button_setting(config, player, @"l", @"L", @"q"),
button_setting(config, player, @"r", @"R", @"w"),
button_setting(config, player, @"l2", @"L2", @"nul"),
button_setting(config, player, @"r2", @"R2", @"nul"),
button_setting(config, player, @"l3", @"L3", @"nul"),
button_setting(config, player, @"r3", @"R3", @"nul"),
button_setting(config, player, @"l_y_minus", @"Left Stick Up", @"nul"),
button_setting(config, player, @"l_y_plus", @"Left Stick Down", @"nul"),
button_setting(config, player, @"l_x_minus", @"Left Stick Left", @"nul"),
button_setting(config, player, @"l_x_plus", @"Left Stick Right", @"nul"),
button_setting(config, player, @"r_y_minus", @"Right Stick Up", @"nul"),
button_setting(config, player, @"r_y_plus", @"Right Stick Down", @"nul"),
button_setting(config, player, @"r_x_minus", @"Right Stick Left", @"nul"),
button_setting(config, player, @"r_x_plus", @"Right Stick Right", @"nul"),
nil],
nil];
}
@implementation RASettingsList
{
RAModuleInfo* _module;
@ -212,57 +253,29 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
[NSArray arrayWithObjects:@"Input",
subpath_setting(config, @"input_overlay", @"Input Overlay", @"", overlay_path, @"cfg"),
range_setting(config, @"input_overlay_opacity", @"Overlay Opacity", @"1.0", 0.0, 1.0),
group_setting(@"Player 1 Keys", [NSArray arrayWithObjects:
[NSArray arrayWithObjects:@"Player 1",
button_setting(config, @"input_player1_up", @"Up", @"up"),
button_setting(config, @"input_player1_down", @"Down", @"down"),
button_setting(config, @"input_player1_left", @"Left", @"left"),
button_setting(config, @"input_player1_right", @"Right", @"right"),
button_setting(config, @"input_player1_start", @"Start", @"enter"),
button_setting(config, @"input_player1_select", @"Select", @"rshift"),
button_setting(config, @"input_player1_b", @"B", @"z"),
button_setting(config, @"input_player1_a", @"A", @"x"),
button_setting(config, @"input_player1_x", @"X", @"s"),
button_setting(config, @"input_player1_y", @"Y", @"a"),
button_setting(config, @"input_player1_l", @"L", @"q"),
button_setting(config, @"input_player1_r", @"R", @"w"),
button_setting(config, @"input_player1_l2", @"L2", @"nul"),
button_setting(config, @"input_player1_r2", @"R2", @"nul"),
button_setting(config, @"input_player1_l3", @"L3", @"nul"),
button_setting(config, @"input_player1_r3", @"R3", @"nul"),
button_setting(config, @"input_player1_l_y_minus", @"Left Stick Up", @"nul"),
button_setting(config, @"input_player1_l_y_plus", @"Left Stick Down", @"nul"),
button_setting(config, @"input_player1_l_x_minus", @"Left Stick Left", @"nul"),
button_setting(config, @"input_player1_l_x_plus", @"Left Stick Right", @"nul"),
button_setting(config, @"input_player1_r_y_minus", @"Right Stick Up", @"nul"),
button_setting(config, @"input_player1_r_y_plus", @"Right Stick Down", @"nul"),
button_setting(config, @"input_player1_r_x_minus", @"Right Stick Left", @"nul"),
button_setting(config, @"input_player1_r_x_plus", @"Right Stick Right", @"nul"),
nil],
nil]),
group_setting(@"System Keys", [NSArray arrayWithObjects:
// TODO: Many of these strings will be cut off on an iPhone
[NSArray arrayWithObjects:@"System Keys",
button_setting(config, @"input_menu_toggle", @"Show RGUI", @"f1"),
button_setting(config, @"input_disk_eject_toggle", @"Insert/Eject Disk", @"nul"),
button_setting(config, @"input_disk_next", @"Cycle Disks", @"nul"),
button_setting(config, @"input_save_state", @"Save State", @"f2"),
button_setting(config, @"input_load_state", @"Load State", @"f4"),
button_setting(config, @"input_state_slot_increase", @"Next State Slot", @"f7"),
button_setting(config, @"input_state_slot_decrease", @"Previous State Slot", @"f6"),
button_setting(config, @"input_toggle_fast_forward", @"Toggle Fast Forward", @"space"),
button_setting(config, @"input_hold_fast_forward", @"Hold Fast Forward", @"l"),
button_setting(config, @"input_rewind", @"Rewind", @"r"),
button_setting(config, @"input_slowmotion", @"Slow Motion", @"e"),
button_setting(config, @"input_reset", @"Reset", @"h"),
button_setting(config, @"input_exit_emulator", @"Close Game", @"escape"),
button_setting(config, @"input_enable_hotkey", @"Hotkey Enable (Always on if not set)", @"nul"),
button_setting(config, 0, @"input_menu_toggle", @"Show RGUI", @"f1"),
button_setting(config, 0, @"input_disk_eject_toggle", @"Insert/Eject Disk", @"nul"),
button_setting(config, 0, @"input_disk_next", @"Cycle Disks", @"nul"),
button_setting(config, 0, @"input_save_state", @"Save State", @"f2"),
button_setting(config, 0, @"input_load_state", @"Load State", @"f4"),
button_setting(config, 0, @"input_state_slot_increase", @"Next State Slot", @"f7"),
button_setting(config, 0, @"input_state_slot_decrease", @"Previous State Slot", @"f6"),
button_setting(config, 0, @"input_toggle_fast_forward", @"Toggle Fast Forward", @"space"),
button_setting(config, 0, @"input_hold_fast_forward", @"Hold Fast Forward", @"l"),
button_setting(config, 0, @"input_rewind", @"Rewind", @"r"),
button_setting(config, 0, @"input_slowmotion", @"Slow Motion", @"e"),
button_setting(config, 0, @"input_reset", @"Reset", @"h"),
button_setting(config, 0, @"input_exit_emulator", @"Close Game", @"escape"),
button_setting(config, 0, @"input_enable_hotkey", @"Hotkey Enable (Always on if not set)", @"nul"),
nil],
nil]),
group_setting(@"Player 1 Keys", build_input_port_group(config, 1)),
group_setting(@"Player 2 Keys", build_input_port_group(config, 2)),
group_setting(@"Player 3 Keys", build_input_port_group(config, 3)),
group_setting(@"Player 4 Keys", build_input_port_group(config, 4)),
nil],
[NSArray arrayWithObjects:@"Save States",
@ -334,11 +347,12 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
NSArray* settings = [NSArray arrayWithObjects:
[NSArray arrayWithObjects:@"Frontend",
custom_action(@"Diagnostic Log", nil, nil),
boolean_setting(config, @"ios_tv_mode", @"TV Mode", @"false"),
nil],
[NSArray arrayWithObjects:@"Bluetooth",
// TODO: Note that with this turned off the native bluetooth is expected to be a real keyboard
boolean_setting(config, @"ios_use_icade", @"Native BT is iCade", @"false"),
btstack_is_loaded() ? boolean_setting(config, @"ios_use_btstack", @"Enable BTstack", @"false") : nil,
btstack_try_load() ? boolean_setting(config, @"ios_use_btstack", @"Enable BTstack", @"false") : nil,
nil],
[NSArray arrayWithObjects:@"Orientations",
boolean_setting(config, @"ios_allow_portrait", @"Portrait", @"true"),
@ -379,16 +393,9 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
if ([@"Diagnostic Log" isEqualToString:setting.label])
[[RetroArch_iOS get] pushViewController:[RALogView new] animated:YES];
else if ([@"Enable BTstack" isEqualToString:setting.label])
{
if ([@"true" isEqualToString:setting.value])
[RetroArch_iOS.get startBluetooth];
else
[RetroArch_iOS.get stopBluetooth];
}
btstack_set_poweron([setting.value isEqualToString:@"true"]);
else if([@"Global Core Config" isEqualToString:setting.label])
{
[RetroArch_iOS.get pushViewController:[[RASettingsList alloc] initWithModule:nil] animated:YES];
}
else
{
RAModuleInfo* data = (RAModuleInfo*)objc_getAssociatedObject(setting, "USERDATA");
@ -741,9 +748,6 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
- (void)checkInput
{
ios_input_data_t data;
ios_copy_input(&data);
// Keyboard
static const struct
{
@ -802,7 +806,7 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
for (int i = 0; ios_key_name_map[i].hid_id; i++)
{
if (data.keys[ios_key_name_map[i].hid_id])
if (g_current_input_data.keys[ios_key_name_map[i].hid_id])
{
_value.msubValues[0] = [NSString stringWithUTF8String:ios_key_name_map[i].keyname];
[self finish];
@ -811,9 +815,9 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
}
// Pad Buttons
for (int i = 0; data.pad_buttons && i < sizeof(data.pad_buttons) * 8; i++)
for (int i = 0; g_current_input_data.pad_buttons[_value.player] && i < sizeof(g_current_input_data.pad_buttons[_value.player]) * 8; i++)
{
if (data.pad_buttons & (1 << i))
if (g_current_input_data.pad_buttons[_value.player] & (1 << i))
{
_value.msubValues[1] = [NSString stringWithFormat:@"%d", i];
[self finish];
@ -824,7 +828,7 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
// Pad Axis
for (int i = 0; i < 4; i++)
{
int16_t value = data.pad_axis[i];
int16_t value = g_current_input_data.pad_axis[_value.player][i];
if (abs(value) > 0x1000)
{

View File

@ -13,8 +13,30 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <sys/stat.h>
#include "general.h"
#include "file.h"
#import "views.h"
void ios_display_alert(NSString* message, NSString* title)
{
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:title ? title : @"RetroArch"
message:message
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
// Little nudge to prevent stale values when reloading the confg file
void ios_clear_config_hack()
{
g_extern.block_config_read = false;
memset(g_settings.input.overlay, 0, sizeof(g_settings.input.overlay));
memset(g_settings.video.shader_path, 0, sizeof(g_settings.video.shader_path));
}
// Fetch a value from a config file, returning defaultValue if the value is not present
NSString* ios_get_value_from_config(config_file_t* config, NSString* name, NSString* defaultValue)
{
@ -27,6 +49,15 @@ NSString* ios_get_value_from_config(config_file_t* config, NSString* name, NSStr
return result;
}
// Ensures a directory exists and has correct permissions
bool path_make_and_check_directory(const char* path, mode_t mode, int amode)
{
if (!path_is_directory(path) && mkdir(path, mode) != 0)
return false;
return access(path, amode) == 0;
}
// Simple class to reduce code duplication for fixed table views
@implementation RATableViewController