From 250857190f66f06a306fb9e1faa01033266e5738 Mon Sep 17 00:00:00 2001 From: meancoot Date: Sun, 24 Mar 2013 18:23:46 -0400 Subject: [PATCH] (iOS) Add diagnostic view and logging for BTstack; access it from the settings menu. --- ios/RetroArch.xcodeproj/project.pbxproj | 4 + ios/RetroArch/RALogView.m | 80 +++++++++++++++++ ios/RetroArch/input/BTStack/btdynamic.c | 36 +++++++- ios/RetroArch/input/BTStack/btpad.c | 112 +++++++++++++----------- ios/RetroArch/rarch_wrapper.h | 2 + ios/RetroArch/settings/RASettingsList.m | 3 + ios/RetroArch/views.h | 3 + 7 files changed, 186 insertions(+), 54 deletions(-) create mode 100644 ios/RetroArch/RALogView.m diff --git a/ios/RetroArch.xcodeproj/project.pbxproj b/ios/RetroArch.xcodeproj/project.pbxproj index cb4d132f7f..6288e261ad 100644 --- a/ios/RetroArch.xcodeproj/project.pbxproj +++ b/ios/RetroArch.xcodeproj/project.pbxproj @@ -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 = ""; }; 96F9C27E16FF6892002455B3 /* ios_input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ios_input.c; sourceTree = ""; }; 96F9C27F16FF6892002455B3 /* keycode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keycode.h; sourceTree = ""; }; + 96F9C28216FFA55F002455B3 /* RALogView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RALogView.m; sourceTree = ""; }; D48581DD16F823F9004BEB17 /* griffin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = griffin.c; path = ../griffin/griffin.c; sourceTree = ""; }; /* 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; }; diff --git a/ios/RetroArch/RALogView.m b/ios/RetroArch/RALogView.m new file mode 100644 index 0000000000..41597272ca --- /dev/null +++ b/ios/RetroArch/RALogView.m @@ -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 . + */ + +#include +#include +#include + +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 diff --git a/ios/RetroArch/input/BTStack/btdynamic.c b/ios/RetroArch/input/BTStack/btdynamic.c index 0db2fa2a73..7a7d1365ff 100644 --- a/ios/RetroArch/input/BTStack/btdynamic.c +++ b/ios/RetroArch/input/BTStack/btdynamic.c @@ -18,6 +18,8 @@ #include #include +#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() diff --git a/ios/RetroArch/input/BTStack/btpad.c b/ios/RetroArch/input/BTStack/btpad.c index 75024538f2..96370daa69 100644 --- a/ios/RetroArch/input/BTStack/btpad.c +++ b/ios/RetroArch/input/BTStack/btpad.c @@ -33,6 +33,7 @@ #include #include +#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; } } diff --git a/ios/RetroArch/rarch_wrapper.h b/ios/RetroArch/rarch_wrapper.h index b53bb0a340..bde784b4ca 100644 --- a/ios/RetroArch/rarch_wrapper.h +++ b/ios/RetroArch/rarch_wrapper.h @@ -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 diff --git a/ios/RetroArch/settings/RASettingsList.m b/ios/RetroArch/settings/RASettingsList.m index 2a7620641c..bb54acd334 100644 --- a/ios/RetroArch/settings/RASettingsList.m +++ b/ios/RetroArch/settings/RASettingsList.m @@ -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 diff --git a/ios/RetroArch/views.h b/ios/RetroArch/views.h index f41833969e..2ed07b7fab 100644 --- a/ios/RetroArch/views.h +++ b/ios/RetroArch/views.h @@ -24,6 +24,9 @@ - (void)closePauseMenu; @end +@interface RALogView : UITableViewController +@end + @interface RAModuleInfo : NSObject @property (strong) NSString* displayName; @property (strong) NSString* path;