Skip to content

Commit

Permalink
Merge pull request #265 from ToddLa/mame-error-warning
Browse files Browse the repository at this point in the history
MAME WARNING and ERROR

Capture MAME WARNING and ERROR output
show it to the user if the game fails to run.
add option to in-game menu to display warning/error text.
Issue #264
 @ToddLa
* Capture MAME WARNING and ERROR output  …
ce0a8d9
  • Loading branch information
mrjschulte authored Oct 31, 2020
2 parents 9a536f5 + ce0a8d9 commit dbb3842
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 41 deletions.
90 changes: 75 additions & 15 deletions iOS/EmulatorController.m
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ -(GCControllerButtonInput*)buttonHome;
#endif

#define DebugLog 0
#if DebugLog == 0
#if DebugLog == 0 || DEBUG == 0
#define NSLog(...) (void)0
#endif

Expand Down Expand Up @@ -199,6 +199,8 @@ -(GCControllerButtonInput*)buttonHome;
static BOOL g_mame_reset = FALSE; // do a full reset (delete cfg files) before running MAME
static char g_mame_game[MAX_GAME_NAME]; // game MAME should run (or empty is menu)
static char g_mame_game_error[MAX_GAME_NAME];
static char g_mame_output_text[4096];
static BOOL g_mame_warning = FALSE;
static BOOL g_no_roms_found = FALSE;

static NSInteger g_settings_roms_count;
Expand Down Expand Up @@ -277,6 +279,25 @@ int iphone_DrawScreen(myosd_render_primitive* prim_list) {
}
}

// called by the OSD layer with MAME output
// **NOTE** this is called on the MAME background thread, dont do anything stupid.
// ...not doing something stupid includes not leaking autoreleased objects! use a autorelease pool if you need to!
void myosd_output(int channel, const char* text)
{
#if DEBUG
// output to stderr/stdout just like normal, in a DEBUG build.
if (channel == MYOSD_OUTPUT_ERROR || channel == MYOSD_OUTPUT_WARNING)
fputs(text, stderr);
else
fputs(text, stdout);
#endif
// capture any error/warning output for later use.
if (channel == MYOSD_OUTPUT_ERROR || channel == MYOSD_OUTPUT_WARNING) {
strncpy(g_mame_output_text + strlen(g_mame_output_text), text, sizeof(g_mame_output_text) - strlen(g_mame_output_text) - 1);
g_video_reset = TRUE; // force UI reset if we get a error or warning message.
}
}

// run MAME (or pass NULL for main menu)
int run_mame(char* game)
{
Expand All @@ -297,6 +318,7 @@ int run_mame(char* game)
while (g_emulation_initiated) {
prev_myosd_mouse = myosd_mouse = 0;
prev_myosd_light_gun = myosd_light_gun = 0;
g_mame_warning = 0;

// reset MAME by deleteing CFG file cfg/default.cfg
if (g_mame_reset) @autoreleasepool {
Expand All @@ -312,6 +334,10 @@ int run_mame(char* game)
if (g_mame_game[0] != 0 && g_mame_game[0] != ' ')
strcpy(myosd_selected_game, g_mame_game);

// reset g_mame_output_text if we are running a game, but not if we are just running menu.
if (g_mame_game[0] != 0)
g_mame_output_text[0] = 0;

if (run_mame(g_mame_game) != 0 && g_mame_game[0]) {
strncpy(g_mame_game_error, g_mame_game, sizeof(g_mame_game_error));
g_mame_game[0] = 0;
Expand Down Expand Up @@ -640,8 +666,6 @@ - (void)runMenu:(int)player from:(UIView*)view

[self startMenu];

int enable_menu_exit_option = TRUE; // (myosd_inGame && myosd_in_menu==0) || !myosd_inGame;

NSString* title = nil;
NSInteger controller_count = controllers.count;
#if TARGET_OS_TV
Expand Down Expand Up @@ -686,17 +710,37 @@ - (void)runMenu:(int)player from:(UIView*)view
myosd_configure = 1;
[self endMenu];
}]];
// show any MAME output, usually a WARNING message, we catch errors in an other place.
if (g_mame_output_text[0]) {
NSString* title = @"MAME Output";
NSString* symbol = @"info.circle";
NSString* message = [[NSString stringWithUTF8String:g_mame_output_text] stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];

if ([message rangeOfString:@"WARNING"].location != NSNotFound) {
title = @"MAME Warning";
symbol = @"exclamationmark.triangle";
}

if ([message rangeOfString:@"ERROR"].location != NSNotFound) {
title = @"MAME Error";
symbol = @"xmark.octagon";
}

[menu addAction:[UIAlertAction actionWithTitle:title style:UIAlertActionStyleDefault image:[UIImage systemImageNamed:symbol withPointSize:size] handler:^(UIAlertAction* action) {
[self showAlertWithTitle:@PRODUCT_NAME message:message buttons:@[@"Continue"] handler:^(NSUInteger button) {
[self endMenu];
}];
}]];
}
}
[menu addAction:[UIAlertAction actionWithTitle:@"Settings" style:UIAlertActionStyleDefault image:[UIImage systemImageNamed:@"gear" withPointSize:size] handler:^(UIAlertAction* action) {
[self runSettings];
}]];

if(enable_menu_exit_option) {
[menu addAction:[UIAlertAction actionWithTitle:((myosd_inGame && myosd_in_menu==0) ? @"Exit Game" : @"Exit") style:UIAlertActionStyleDestructive image:[UIImage systemImageNamed:@"arrow.uturn.left.circle" withPointSize:size] handler:^(UIAlertAction* action) {
[self endMenu];
[self runExit:NO]; // the user just selected "Exit Game" from a menu, dont ask again
}]];
}
[menu addAction:[UIAlertAction actionWithTitle:((myosd_inGame && myosd_in_menu==0) ? @"Exit Game" : @"Exit") style:UIAlertActionStyleDestructive image:[UIImage systemImageNamed:@"arrow.uturn.left.circle" withPointSize:size] handler:^(UIAlertAction* action) {
[self endMenu];
[self runExit:NO]; // the user just selected "Exit Game" from a menu, dont ask again
}]];

[menu addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction* action) {
[self endMenu];
Expand Down Expand Up @@ -1313,9 +1357,10 @@ -(void)viewDidLoad{
[self performSelectorOnMainThread:@selector(setupMFIControllers) withObject:nil waitUntilDone:NO];
}

toastStyle = [[CSToastStyle alloc] initWithDefaultStyle];
toastStyle = [CSToastManager sharedStyle];
toastStyle.backgroundColor = [UIColor colorWithWhite:0.333 alpha:0.50];
toastStyle.messageColor = [UIColor whiteColor];
toastStyle.imageSize = CGSizeMake(toastStyle.messageFont.lineHeight, toastStyle.messageFont.lineHeight);

mouseInitialLocation = CGPointMake(9111, 9111);
mouseTouchStartLocation = mouseInitialLocation;
Expand Down Expand Up @@ -1978,15 +2023,23 @@ - (void)changeUI { @autoreleasepool {
[UIApplication sharedApplication].idleTimerDisabled = (myosd_inGame || g_joy_used) ? YES : NO;//so atract mode dont sleep

if ( prev_myosd_light_gun == 0 && myosd_light_gun == 1 && g_pref_lightgun_enabled ) {
[self.view makeToast:@"Touch Lightgun Mode Enabled!" duration:2.0 position:CSToastPositionCenter style:toastStyle];
[self.view makeToast:@"Touch Lightgun Mode Enabled!" duration:2.0 position:CSToastPositionCenter
title:nil image:[UIImage systemImageNamed:@"target"] style:toastStyle completion:nil];
}
prev_myosd_light_gun = myosd_light_gun;

if ( prev_myosd_mouse == 0 && myosd_mouse == 1 && g_pref_touch_analog_enabled ) {
[self.view makeToast:@"Touch Mouse Mode Enabled!" duration:2.0 position:CSToastPositionCenter style:toastStyle];
[self.view makeToast:@"Touch Mouse Mode Enabled!" duration:2.0 position:CSToastPositionCenter
title:nil image:[UIImage systemImageNamed:@"cursorarrow.motionlines"] style:toastStyle completion:nil];
}
prev_myosd_mouse = myosd_mouse;

// Show a WARNING toast, but only once, and only if MAME did not show it already
if (myosd_showinfo == 0 && g_mame_warning == 0 && g_mame_output_text[0] && strstr(g_mame_output_text, "WARNING") != NULL) {
[self.view makeToast:@"⚠️Game might not run correctly." duration:3.0 position:CSToastPositionBottom style:toastStyle];
g_mame_warning = 1;
}

areControlsHidden = NO;

memset(cyclesAfterButtonPressed, 0, sizeof(cyclesAfterButtonPressed));
Expand Down Expand Up @@ -2464,6 +2517,9 @@ - (void)buildScreenView {
myosd_display_width = (r.size.width * scale);
myosd_display_height = (r.size.height * scale);
}

// set the rect to use for Toast
toastStyle.toastRect = r;

// make room for a border
UIImage* border_image = nil;
Expand Down Expand Up @@ -4488,7 +4544,8 @@ -(void)MFIControllerConnected:(NSNotification*)notif{
[self setupMFIControllers];
#if TARGET_OS_IOS
if ([controllers containsObject:controller]) {
[self.view makeToast:[NSString stringWithFormat:@"%@ connected", controller.vendorName] duration:4.0 position:CSToastPositionTop style:toastStyle];
[self.view makeToast:[NSString stringWithFormat:@"%@ connected", controller.vendorName] duration:4.0 position:CSToastPositionTop
title:nil image:[UIImage systemImageNamed:@"gamecontroller"] style:toastStyle completion:nil];
}
#endif
}
Expand All @@ -4502,7 +4559,8 @@ -(void)MFIControllerDisconnected:(NSNotification*)notif{
NSLog(@"Goodbye %@", controller.vendorName);
[self setupMFIControllers];
#if TARGET_OS_IOS
[self.view makeToast:[NSString stringWithFormat:@"%@ disconnected", controller.vendorName] duration:4.0 position:CSToastPositionTop style:toastStyle];
[self.view makeToast:[NSString stringWithFormat:@"%@ disconnected", controller.vendorName] duration:4.0 position:CSToastPositionTop
title:nil image:[UIImage systemImageNamed:@"gamecontroller"] style:toastStyle completion:nil];
#endif
}

Expand Down Expand Up @@ -4703,7 +4761,9 @@ -(void)chooseGame:(NSArray*)games {
if (g_mame_game_error[0] != 0) {
NSLog(@"ERROR RUNNING GAME %s", g_mame_game_error);

NSString* msg = [NSString stringWithFormat:@"ERROR RUNNING GAME %s", g_mame_game_error];
NSString* msg = [[NSString stringWithUTF8String:g_mame_output_text] stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
if ([msg length] == 0)
msg = [NSString stringWithFormat:@"ERROR RUNNING GAME %s", g_mame_game_error];
g_mame_game_error[0] = 0;
g_mame_game[0] = 0;
g_mame_game_info = nil;
Expand Down
2 changes: 1 addition & 1 deletion src/emu/video.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ INLINE int original_speed_setting(void)

old_speed = myosd_speed;

printf("Emulated speed %d\n",res);
mame_printf_debug("Emulated speed %d\n",res);
return res;
}

Expand Down
18 changes: 18 additions & 0 deletions src/osd/droid-ios/myosd.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,24 @@ extern const char *myosd_array_years[];
extern const char *myosd_array_main_driver_source[];
extern const char *myosd_array_categories[];

// myosd output
enum myosd_output_channel
{
MYOSD_OUTPUT_ERROR,
MYOSD_OUTPUT_WARNING,
MYOSD_OUTPUT_INFO,
MYOSD_OUTPUT_DEBUG,
MYOSD_OUTPUT_VERBOSE,
};
extern void myosd_output(int channel, const char* text);
#ifdef __MACHINE_H__
_Static_assert(MYOSD_OUTPUT_ERROR == OUTPUT_CHANNEL_ERROR);
_Static_assert(MYOSD_OUTPUT_WARNING == OUTPUT_CHANNEL_WARNING);
_Static_assert(MYOSD_OUTPUT_INFO == OUTPUT_CHANNEL_INFO);
_Static_assert(MYOSD_OUTPUT_DEBUG == OUTPUT_CHANNEL_DEBUG);
_Static_assert(MYOSD_OUTPUT_VERBOSE == OUTPUT_CHANNEL_VERBOSE);
#endif

// subset of a internal game_driver structure we pass up to the UI/OSD layer
typedef struct
{
Expand Down
34 changes: 22 additions & 12 deletions src/osd/droid-ios/osd-ios.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//
//============================================================


#include "emu.h"
#include "myosd.h"

#include "bt_joy.h"
Expand Down Expand Up @@ -101,8 +101,6 @@ int myosd_speed = 100;

char myosd_selected_game[MAX_GAME_NAME] = {'\0'};

extern "C" unsigned long read_mfi_controller(unsigned long res);

/*extern */float joy_analog_x[NUM_JOY][4];
/*extern */float joy_analog_y[NUM_JOY][2];

Expand Down Expand Up @@ -178,7 +176,7 @@ void myosd_video_flip(void)

void myosd_set_video_mode(int width,int height,int vis_width,int vis_height)
{
printf("myosd_set_video_mode: %dx%d [%dx%d]\n",width,height,vis_width,vis_height);
mame_printf_debug("myosd_set_video_mode: %dx%d [%dx%d]\n",width,height,vis_width,vis_height);

myosd_video_width = width;
myosd_video_height = height;
Expand Down Expand Up @@ -259,18 +257,30 @@ float myosd_joystick_read_analog(int n, char axis)
return res;
}

// output channel callback, send output "up" to the app via myosd_output
static void mame_output(void *param, const char *format, va_list argptr)
{
char buffer[1204];
vsnprintf(buffer, sizeof(buffer)-1, format, argptr);
myosd_output((int)(intptr_t)param, buffer);
}

void myosd_init(void)
{
int res = 0;
struct sched_param param;

// capture all MAME output so we can send it to the app.
for (int n=0; n<OUTPUT_CHANNEL_COUNT; n++)
mame_set_output_channel((output_channel)n, mame_output, (void*)n, NULL, NULL);

if (!lib_inited )
{
printf("myosd_init\n");
mame_printf_debug("myosd_init\n");

//myosd_set_video_mode(320,240,320,240);

printf("myosd_dbl_buffer %d\n",myosd_dbl_buffer);
mame_printf_debug("myosd_dbl_buffer %d\n",myosd_dbl_buffer);
myosd_curr_screen = myosd_screen;
myosd_prev_screen = myosd_screen;

Expand All @@ -284,7 +294,7 @@ void myosd_init(void)
//param.sched_priority = 46;
//param.sched_priority = 100;

printf("video priority %d\n",video_thread_priority);
mame_printf_debug("video priority %d\n",video_thread_priority);
param.sched_priority = video_thread_priority;
int policy;
if(video_thread_priority_type == 1)
Expand All @@ -295,7 +305,7 @@ void myosd_init(void)
policy = SCHED_FIFO;

if(pthread_setschedparam(main_tid, policy, &param) != 0)
printf("Error setting pthread priority\n");
mame_printf_debug("Error setting pthread priority\n");
videot_running = 1;
}

Expand All @@ -307,7 +317,7 @@ void myosd_deinit(void)
{
if (lib_inited )
{
printf("myosd_deinit\n");
mame_printf_debug("myosd_deinit\n");

lib_inited = 0;
}
Expand All @@ -316,7 +326,7 @@ void myosd_deinit(void)
void myosd_closeSound(void) {
if( soundInit == 1 )
{
printf("myosd_closeSound\n");
mame_printf_debug("myosd_closeSound\n");


if(global_low_latency_sound)
Expand All @@ -333,12 +343,12 @@ void myosd_openSound(int rate,int stereo) {
{
if(global_low_latency_sound)
{
printf("myosd_openSound LOW LATENCY rate:%d stereo:%d \n",rate,stereo);
mame_printf_debug("myosd_openSound LOW LATENCY rate:%d stereo:%d \n",rate,stereo);
sound_open_AudioUnit(rate, 16, stereo);
}
else
{
printf("myosd_openSound NORMAL rate:%d stereo:%d \n",rate,stereo);
mame_printf_debug("myosd_openSound NORMAL rate:%d stereo:%d \n",rate,stereo);
sound_open_AudioQueue(rate, 16, stereo);
}

Expand Down
10 changes: 5 additions & 5 deletions src/osd/droid-ios/osdinput.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,11 +278,11 @@ void my_poll_ports(running_machine *machine)
else
myosd_num_ways = 2;
}
printf("Num Buttons %d\n",myosd_num_buttons);
printf("Num WAYS %d\n",myosd_num_ways);
printf("Num PLAYERS %d\n",myosd_num_players);
printf("Num COINS %d\n",myosd_num_coins);
printf("Num INPUTS %d\n",myosd_num_inputs);
mame_printf_debug("Num Buttons %d\n",myosd_num_buttons);
mame_printf_debug("Num WAYS %d\n",myosd_num_ways);
mame_printf_debug("Num PLAYERS %d\n",myosd_num_players);
mame_printf_debug("Num COINS %d\n",myosd_num_coins);
mame_printf_debug("Num INPUTS %d\n",myosd_num_inputs);
}

}
Expand Down
5 changes: 5 additions & 0 deletions xcode/MAME4iOS/UIView+Toast.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,11 @@ extern const NSString * CSToastPositionBottom;
*/
@property (assign, nonatomic) NSTimeInterval fadeDuration;

/**
The rect to place toast. Default is view.bounds - safeArea.
*/
@property (assign, nonatomic) CGRect toastRect;

/**
Creates a new instance of `CSToastStyle` with all the default values set.
*/
Expand Down
Loading

0 comments on commit dbb3842

Please sign in to comment.