(iOS) Add diagnostic view and logging for BTstack; access it from the settings menu.

This commit is contained in:
meancoot 2013-03-24 18:23:46 -04:00
parent 4e973d8e27
commit 250857190f
7 changed files with 186 additions and 54 deletions

View File

@ -39,6 +39,7 @@
96AFAE3016C1D4EA009DE44C /* GLKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96AFAE2F16C1D4EA009DE44C /* GLKit.framework */; };
96AFAE3216C1D4EA009DE44C /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96AFAE3116C1D4EA009DE44C /* OpenGLES.framework */; };
96AFAE3816C1D4EA009DE44C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 96AFAE3616C1D4EA009DE44C /* InfoPlist.strings */; };
96F9C28316FFA55F002455B3 /* RALogView.m in Sources */ = {isa = PBXBuildFile; fileRef = 96F9C28216FFA55F002455B3 /* RALogView.m */; };
D48581DE16F823F9004BEB17 /* griffin.c in Sources */ = {isa = PBXBuildFile; fileRef = D48581DD16F823F9004BEB17 /* griffin.c */; };
/* End PBXBuildFile section */
@ -104,6 +105,7 @@
96F9C27D16FF6892002455B3 /* ios_input.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ios_input.h; sourceTree = "<group>"; };
96F9C27E16FF6892002455B3 /* ios_input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ios_input.c; sourceTree = "<group>"; };
96F9C27F16FF6892002455B3 /* keycode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keycode.h; sourceTree = "<group>"; };
96F9C28216FFA55F002455B3 /* RALogView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RALogView.m; sourceTree = "<group>"; };
D48581DD16F823F9004BEB17 /* griffin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = griffin.c; path = ../griffin/griffin.c; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -249,6 +251,7 @@
96366C6F16CAF62200D64A22 /* settings */,
96297A0E16C5AEA100E6DCE0 /* main.m */,
963F5AC516CC523B009BBD19 /* RAGameView.m */,
96F9C28216FFA55F002455B3 /* RALogView.m */,
96096DD716D1ABAF00BF4499 /* RAModuleInfoList.m */,
96C19C2616D455BE00FE8D5A /* rarch_wrapper.h */,
96297A0A16C5AD8D00E6DCE0 /* RetroArch_iOS.h */,
@ -403,6 +406,7 @@
966B9CB216E41C07005B61E1 /* RADirectoryList.m in Sources */,
966B9CB416E41C07005B61E1 /* RAModuleList.m in Sources */,
D48581DE16F823F9004BEB17 /* griffin.c in Sources */,
96F9C28316FFA55F002455B3 /* RALogView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

80
ios/RetroArch/RALogView.m Normal file
View File

@ -0,0 +1,80 @@
/* 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 <stdarg.h>
#include <stdio.h>
#include <pthread.h>
static NSMutableArray* g_messages;
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
void ios_add_log_message(const char* format, ...)
{
pthread_mutex_lock(&g_lock);
g_messages = g_messages ? g_messages : [NSMutableArray array];
char buffer[512];
va_list args;
va_start(args, format);
vsnprintf(buffer, 512, format, args);
va_end(args);
[g_messages addObject:[NSString stringWithUTF8String: buffer]];
pthread_mutex_unlock(&g_lock);
}
@implementation RALogView
- (RALogView*)init
{
self = [super initWithStyle:UITableViewStyleGrouped];
[self setTitle:@"RetroArch Diagnostic Log"];
return self;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView
{
return 1;
}
- (NSString*)tableView:(UITableView*)tableView titleForHeaderInSection:(NSInteger)section
{
return @"Messages";
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
pthread_mutex_lock(&g_lock);
NSInteger count = g_messages ? g_messages.count : 0;
pthread_mutex_unlock(&g_lock);
return count;
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:@"message"];
cell = cell ? cell : [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"message"];
pthread_mutex_lock(&g_lock);
cell.textLabel.text = g_messages[indexPath.row];
pthread_mutex_unlock(&g_lock);
return cell;
}
@end

View File

@ -18,6 +18,8 @@
#include <pthread.h>
#include <CoreFoundation/CFRunLoop.h>
#include "../../rarch_wrapper.h"
#define BUILDING_BTDYNAMIC
#include "btdynamic.h"
@ -65,11 +67,16 @@ static volatile bool btstack_poweron;
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);
if (bt_open_ptr())
{
ios_add_log_message("BTstack: Failed to open, exiting thread.");
return 0;
}
while (1)
{
@ -81,6 +88,8 @@ static void* btstack_thread_function(void* data)
{
poweron = btstack_poweron;
bt_send_cmd_ptr(btstack_set_power_mode_ptr, poweron ? HCI_POWER_ON : HCI_POWER_OFF);
ios_add_log_message("BTstack: Responding to power switch (now %s)", poweron ? "ON" : "OFF");
}
}
@ -94,6 +103,8 @@ bool btstack_load()
if (btstack_tested)
return btstack_loaded;
ios_add_log_message("BTstack: Attempting to load");
btstack_tested = true;
btstack_loaded = false;
@ -101,7 +112,11 @@ bool btstack_load()
void* btstack = dlopen("/usr/lib/libBTstack.dylib", RTLD_LAZY);
if (!btstack)
{
ios_add_log_message("BTstack: /usr/lib/libBTstack.dylib not loadable");
ios_add_log_message("BTstack: Not loaded");
return false;
}
for (int i = 0; grabbers[i].name; i ++)
{
@ -109,11 +124,15 @@ bool btstack_load()
if (!*grabbers[i].target)
{
ios_add_log_message("BTstack: Symbol %s not found in /usr/lib/libBTstack.dylib", grabbers[i].name);
ios_add_log_message("BTstack: Not loaded");
dlclose(btstack);
return false;
}
}
ios_add_log_message("BTstack: Loaded");
btstack_loaded = true;
return true;
@ -123,15 +142,26 @@ void btstack_start()
{
static bool thread_started = false;
if (!thread_started)
{
ios_add_log_message("BTstack: Starting thread");
pthread_create(&btstack_thread, NULL, btstack_thread_function, 0);
thread_started = true;
thread_started = true;
}
btstack_poweron = true;
if (!btstack_poweron)
{
ios_add_log_message("BTstack: Setting poweron flag");
btstack_poweron = true;
}
}
void btstack_stop()
{
btstack_poweron = false;
if (btstack_poweron)
{
ios_add_log_message("BTstack: Clearing poweron flag");
btstack_poweron = false;
}
}
bool btstack_is_loaded()

View File

@ -33,6 +33,7 @@
#include <stdio.h>
#include <string.h>
#include "../../rarch_wrapper.h"
#include "btdynamic.h"
#include "btpad.h"
#include "wiimote.h"
@ -118,9 +119,12 @@ static void btstack_not_initialized_handler(uint8_t* packet, uint16_t size)
{
if (packet[2] == HCI_STATE_WORKING)
{
RARCH_LOG("BTstack started\n");
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;
}
@ -128,14 +132,15 @@ static void btstack_not_initialized_handler(uint8_t* packet, uint16_t size)
{
if (READ_BT_16(packet, 3) == PSM_HID_INTERRUPT)
{
RARCH_LOG("BTstack HID control service registered\n");
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)
{
RARCH_LOG("BTstack HID interrupt service registered\n");
RARCH_LOG("BTstack waiting for connection.\n");
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;
}
@ -151,7 +156,7 @@ static void btstack_no_connection_handler(uint8_t* packet, uint16_t size)
// Device is connecting to iOS
case L2CAP_EVENT_INCOMING_CONNECTION:
{
RARCH_LOG("BTstack incoming L2CAP connection (PS3 Pad?)\n");
ios_add_log_message("BTstack: Incoming L2CAP connection (PS3 Pad?)");
btpad_state = BTPAD_CONNECTION;
@ -165,7 +170,7 @@ static void btstack_no_connection_handler(uint8_t* packet, uint16_t size)
// Here we just copy the details of the first device found
case HCI_EVENT_INQUIRY_RESULT:
{
RARCH_LOG("BTstack inquiry found device (WiiMote?)\n");
ios_add_log_message("BTstack: Inquiry found device (WiiMote?)");
if (packet[2])
{
@ -194,7 +199,7 @@ static void btstack_connection_handler(uint8_t* packet, uint16_t size)
{
case L2CAP_EVENT_INCOMING_CONNECTION:
{
RARCH_LOG("BTstack got other half of connection; requesting name\n");
ios_add_log_message("BTstack: Got other half L2CAP connection; requesting name\n");
btpad_state = BTPAD_WANT_NAME;
@ -213,7 +218,7 @@ static void btstack_inquiry_connection_handler(uint8_t* packet, uint16_t size)
{
case HCI_EVENT_INQUIRY_COMPLETE:
{
RARCH_LOG("BTstack got inquiry complete; requesting name\n");
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,
@ -238,18 +243,18 @@ static void btstack_want_name_handler(uint8_t* packet, uint16_t size)
strncpy(device_name, (const char*)&packet[9], 248);
device_name[248] = 0;
RARCH_LOG("BTstack got name: %s\n", device_name);
ios_add_log_message("BTstack: Got device name: %s\n", device_name);
if (strncmp(device_name, "Nintendo RVL-CNT-01", 19) == 0)
{
RARCH_LOG("Btstack got WiiMote\n");
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)
{
RARCH_LOG("Btstack got PS3 Pad; Sending startup packets\n");
ios_add_log_message("BTstack: Got PS3 Pad; Sending startup packets\n");
btpad_state = BTPAD_CONNECTED;
device_type = BTPAD_PS3;
@ -260,7 +265,10 @@ static void btstack_want_name_handler(uint8_t* packet, uint16_t size)
set_ps3_data(0);
}
else
{
ios_add_log_message("BTstack: Unrecognized device; Will keep looking");
btpad_state = BTPAD_NO_CONNECTION;
}
}
break;
@ -272,9 +280,9 @@ static void btstack_ps3_handler(uint8_t packet_type, uint16_t channel, uint8_t *
{
if (packet_type == L2CAP_DATA_PACKET && packet[0] == 0xA1)
{
static bool poop = false;
if(!poop) RARCH_LOG("GOT DATA PACKET\n");
poop = true;
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);
}
@ -284,51 +292,50 @@ static void btstack_wiimote_handler(uint8_t packet_type, uint16_t channel, uint8
{
bd_addr_t event_addr;
if (packet_type == HCI_EVENT_PACKET)
if (packet_type == HCI_EVENT_PACKET && packet[0] == L2CAP_EVENT_CHANNEL_OPENED)
{
switch (packet[0])
{
case L2CAP_EVENT_CHANNEL_OPENED:
{
bt_flip_addr_ptr(event_addr, &packet[3]);
const uint16_t psm = READ_BT_16(packet, 11);
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)
{
RARCH_LOG("Btstack WiiMote channel openend: %d\n", psm);
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;
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);
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);
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);
}
}
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 poop = false;
if(!poop) RARCH_LOG("GOT DATA PACKET\n");
poop = true;
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;
@ -402,17 +409,20 @@ void btstack_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *pack
{
// This PIN will work for Wiimotes, other devices with PINs aren't supported
case HCI_EVENT_PIN_CODE_REQUEST:
RARCH_LOG("Btstack sending PIN\n");
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:
RARCH_LOG("Btstack lost connection\n");
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;
}
}

View File

@ -25,4 +25,6 @@ void ios_set_game_view_sync(bool on);
void ios_get_game_view_size(unsigned *width, unsigned *height);
void ios_bind_game_view_fbo();
// Thread safe
void ios_add_log_message(const char* format, ...);
#endif

View File

@ -142,6 +142,7 @@ static RASettingData* custom_action(NSString* action)
NSArray* settings = [NSArray arrayWithObjects:
[NSArray arrayWithObjects:@"Frontend",
custom_action(@"Module Info"),
custom_action(@"Diagnostic Log"),
boolean_setting(config, @"ios_auto_bluetooth", @"Auto Enable Bluetooth", @"false"),
nil],
@ -234,6 +235,8 @@ static RASettingData* custom_action(NSString* action)
{
if ([@"Module Info" isEqualToString:action])
[[RetroArch_iOS get] pushViewController:[[RAModuleInfoList alloc] initWithModuleInfo:[RetroArch_iOS get].moduleInfo] animated:YES];
else if ([@"Diagnostic Log" isEqualToString:action])
[[RetroArch_iOS get] pushViewController:[RALogView new] animated:YES];
}
@end

View File

@ -24,6 +24,9 @@
- (void)closePauseMenu;
@end
@interface RALogView : UITableViewController
@end
@interface RAModuleInfo : NSObject
@property (strong) NSString* displayName;
@property (strong) NSString* path;