The NEW Build Your Own Arcade Controls
Front End Support => MaLa Frontend => Topic started by: arzoo on December 18, 2007, 10:05:08 am
-
Hey all - I'm hoping someone might be able to shed some light on a problem I'm having with mame output messages and MaLa - this is a software development issue. Here's the story...
I recently added support for headkaze's MameInteropSDK (mame.dll) to the MaLa LEDBlinky plugin. This allows the plugin to respond when mame is paused and also to light LEDs based on mame output messages - similar to the ledutil app. For development testing I use my MaLa stub app run the plugin and launch mame. Swindus has provided me with the code he uses to launch mame, so I think (hope) that my stub app and MaLa both do the same thing.
Ok, back when I was coding the output message features into LEDBlinky, I was mostly focused on the pause message which I fully tested with both my test stub and MaLa on my mame cab. For the other output messages (LED0, LED1, LAMP0, LAMP1, etc) I only qa'd with my test stub - mistake, DOH!
So, it turns out that something is not quite right when I run LEDBlinky from MaLa - there's some sort of timing problem with the output messages coming from mame. This is what happens; for testing purposes, I was using Asteroids which like many games flashes the start buttons when credits are available using the LED0 and LED1 messages. When running from my test stub, LED0 will blink on/off/on/off about every second - with approximately a 250ms delay between messages.
LED0 on
250ms delay
LED0 off
250ms delay
LED0 on
250ms delay
LED0 off
250ms delay
repeat
But, when running the same code from MaLa, LED0 will blink on/off/on/off about every 10ms and then there's a 1 second delay until the next message burst.
LED0 on
10ms delay
LED0 off
10ms delay
LED0 on
10ms delay
LED0 off
1000ms delay
repeat
With a 10ms delay between messages, the LED code can't keep up and the LEDs end up blinking very sporadically. So that's the problem. I've done some additional testing using ledutil and headkazes's output message test app - as long as the code is launched external to MaLa, it works fine.
I'm wondering if this is some sort of threading issue, but I don't think MaLa uses multiple threads. If anyone has thoughts on how to resolve this - the help would be greatly appreciated!!!
Thanks,
arzoo
-
Hi,
Did you do that test :
run Mala but don't run game. keep it in background.
run your test with your own app while mala is in the background. How does it work?
-
Hi,
Did you do that test :
run Mala but don't run game. keep it in background.
run your test with your own app while mala is in the background. How does it work?
I did try my test code with MaLa running, but I still let MaLa launch mame. I'll try your suggestion and let my code launch mame with MaLa just running in the background. Thanks youki :)
On a side note, I also created a test plugin which does nothing more than log/timestamp the mame output messages – that ruled out any of my LED code causing the problem.
-
I did some additional testing per youki's suggestion - it seems that the MameInterop will only receive messages for the first program to load the dll. So if MaLa loads my plugin and my plugin loads the MameInterop, and I then run my stub program (which also loads the plugin and MameInterop) and launch mame - it doesn't receive any messages. So that doesn't really help with the timing issue.
-
I did some additional testing per youki's suggestion - it seems that the MameInterop will only receive messages for the first program to load the dll. So if MaLa loads my plugin and my plugin loads the MameInterop, and I then run my stub program (which also loads the plugin and MameInterop) and launch mame - it doesn't receive any messages. So that doesn't really help with the timing issue.
If you want multiple programs to use Mame.dll you have to give them each a unique id and name when calling init_mame().
ie.
uniqueId := 1234;
uniqueName := 'Test1';
init_mame(uniqueId, uniqueName, mame_start_ptr, mame_stop_ptr, mame_copydata_ptr, mame_updatestate_ptr);
-
I'm not sure if this helps but ..... :dizzy:
I was unsing MaLa Messages (that comes with the plug-in SDK) to flash LEDS for the Speech v20 Flash N speak. I noticed quite some lag
-
Are Messages from Mala are Sent or Posted?
-
Are Messages from Mala are Sent or Posted?
pass :dunno
-
headkaze - thanks for the init_mame tip. I should have figured that one out on my own!
Loadman - not sure how the MaLa messages could help here, but thanks.
Youki - as far as I can tell, messages can only be posted to MaLa (not posted or sent from MaLa).
I'm really bummed about this because I recently added some Ultralux buttons to my cp for the start and coin buttons and I was hoping to flash them using the mame output messages - that was the point of adding the feature to LEDBlinky. I think the only way to get this resolved would be if swindus gets involved. He's responded to one of my pm's, but I'm sure like many of us, he's busy this time of the year. I also pm'd Aaron, but no response yet.
-
Yet another update on this problem...
I recompiled my output test app so that it uses a different ID for the MameInterop - now both the plugin and test code are receiving output messages.
I started both MaLa and my test app, then let MaLa launch mame. With that scenario, the plugin (running under MaLa) receives the messages with the wrong timing (every 10ms), but the test app receives the messages with the correct timing (every 250ms).
I then launched mame manually - external to MaLa - with this scenario, both my plugin and test app receive the messages correctly!
So without a doubt - the problem only occurs when MaLa launches mame and only effects the MameInterop code running within MaLa's thread.
Here's another interesting note - in the first scenario both the plugin and test app receive the same number of messages - even thought the plugin has 10ms delays and the test app 250ms delays. That's because after the plugin receives 4 message, there is a 1 second delay before the next 4 messages - always 4 messages per second. This does not seem like a random behavior and in fact seems intentional. So why would mame send the messages with this different timing behavior. :dunno
-
Hi,
I'm not familiar with Mala Plugins and i never use MameInterop sdk.
But may be the problem comes from the way your plugin's method is called by Mala.
Your plug'ins method are triggered by Mala.
In one of your method you manage the MameInterop Message. I don't know how, but somewhere you should pull the message from a message queue and process it accordinly.
In your test APP, you call your plug'ins method regulary (may be in a loop , or on a timer event i don't know). So you check almost all time the message queues and process message when they come. and it works as you want.
May be, Mala , call your plug'ins method less often. I guess mala does lot of more than your test app and consume more cpu (he has at least to manage display) , so it could be possible that the call to your plugin method occurs regulary but less often when expected. As message coming from mame are not process instantly they are queuedwaiting the plugin pickup them. When the plugin method becomes active, all the message in the queue are processed quickly .
It is just a guess , i don't if it can help you. I have the feeling it is something more a less like that that occurs.
-
Hi,
I'm not familiar with Mala Plugins and i never use MameInterop sdk.
But may be the problem comes from the way your plugin's method is called by Mala.
Your plug'ins method are triggered by Mala.
In one of your method you manage the MameInterop Message. I don't know how, but somewhere you should pull the message from a message queue and process it accordinly.
In your test APP, you call your plug'ins method regulary (may be in a loop , or on a timer event i don't know). So you check almost all time the message queues and process message when they come. and it works as you want.
May be, Mala , call your plug'ins method less often. I guess mala does lot of more than your test app and consume more cpu (he has at least to manage display) , so it could be possible that the call to your plugin method occurs regulary but less often when expected. As message coming from mame are not process instantly they are queuedwaiting the plugin pickup them. When the plugin method becomes active, all the message in the queue are processed quickly .
It is just a guess , i don't if it can help you. I have the feeling it is something more a less like that that occurs.
Mame.dll has a callback in it that sends the messages to the host application. So there is no timer for receiving messages in the plugin. The plugin would respond to the messages received by the Mame.dll independantly of the Mala process. I had a quick look at the Mala plugin example app and it's just a bunch of values that Mala sends over. Mame messages from Mame.dll should not be effected by the communication between it and the plugin AFAIK. When arzoo's plugin recieves a message like led0 it will process it without talking to Mala. I don't see how that could cause a 1 seconds delay unless Mala is causing the plugin dll to halt for some reason.
There is one thing I can suggest trying arzoo but it probably won't solve the problem if Mala is the cause of it. You can manually create your own window in Delphi without the use of Mame.dll. Register the custom Window's messages and receive them in your own WinProc callback. At least this way we could rule out the Mame.dll <-> plugin communication as being the cause of the problem. You will of course have to port the C++ code to Delphi. That being said I'm pretty sure you already deducted that Mala is the cause of the problem not Mame.dll.
-
When arzoo's plugin recieves a message like led0 it will process it without talking to Mala. I don't see how that could cause a 1 seconds delay unless Mala is causing the plugin dll to halt for some reason.
I think the plugin is running inside the same Thread than Mala. If Mala is too busy , the callback function call could be differed.
Arzoo are you on XP or Win98?
-
When arzoo's plugin recieves a message like led0 it will process it without talking to Mala. I don't see how that could cause a 1 seconds delay unless Mala is causing the plugin dll to halt for some reason.
I think the plugin is running inside the same Thread than Mala. If Mala is too busy , the callback function call could be differed.
Arzoo are you on XP or Win98?
Here is the basic code to communicate with Mame.dll. If the code in the TSDIAppForm.FormShow() procedure is called from Mala then it will run in the same thread. Like if it's in some sort of "Initialize" routine. So maybe he should try putting that code into it's own thread?
unit SDIMAIN;
interface
uses Windows, Classes, Graphics, Forms, Controls, Menus,
Dialogs, StdCtrls, Buttons, ExtCtrls, ComCtrls, ImgList, StdActns,
ActnList, ToolWin, SysUtils, IniFiles;
type
TSDIAppForm = class(TForm)
Memo1: TMemo;
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
SDIAppForm: TSDIAppForm;
type
TMAME_START = Function(): Integer; stdcall;
TMAME_STOP = Function(): Integer; stdcall;
TMAME_COPYDATA = Function(id: Integer; name: PChar): Integer; stdcall;
TMAME_UPDATESTATE = Function(id: Integer; state: Integer): Integer; stdcall;
var
output_hash: THashedStringList;
mame_start_ptr: TMAME_START;
mame_stop_ptr: TMAME_STOP;
mame_copydata_ptr: TMAME_COPYDATA;
mame_updatestate_ptr: TMAME_UPDATESTATE;
Function init_mame(clientid: Integer; name: String; start: TMAME_START; stop: TMAME_STOP; copydata: TMAME_COPYDATA; updatestate: TMAME_UPDATESTATE): Integer; stdcall; external 'Mame.dll';
Function close_mame(): Integer; stdcall; external 'Mame.dll';
Function map_id_to_outname(id: Integer): PChar; stdcall; external 'Mame.dll';
Function mame_start(): Integer; stdcall;
Function mame_stop(): Integer; stdcall;
Function mame_copydata(id: Integer; name: PChar): Integer; stdcall;
Function mame_updatestate(id: Integer; state: Integer): Integer; stdcall;
Function get_name_from_id(id: Integer): String;
implementation
{$R *.dfm}
Function mame_start(): Integer; stdcall;
Begin
output_hash.Clear;
SDIAppForm.Memo1.Lines.Add('mame_start');
mame_start := 1;
End;
Function mame_stop(): Integer; stdcall;
Begin
SDIAppForm.Memo1.Lines.Add('mame_stop');
mame_stop := 1;
End;
Function mame_copydata(id: Integer; name: PChar): Integer; stdcall;
Begin
SDIAppForm.Memo1.Lines.Add('id '+ IntToStr(id) + ' = '''+ name+ '''');
mame_copydata := 1;
End;
Function mame_updatestate(id: Integer; state: Integer): Integer; stdcall;
var
name: String;
Begin
name := get_name_from_id(id);
SDIAppForm.Memo1.Lines.Add('update_state: id='+ IntToStr(id) + ' ('+ name+ ') state=' + IntToStr(state));
mame_updatestate := 1;
End;
Function get_name_from_id(id: Integer): String;
var
name: String;
index: Integer;
Begin
index := output_hash.IndexOfObject(TObject(id));
if index = -1 then
begin
name := map_id_to_outname(id);
output_hash.AddObject(name, TObject(id));
end
else begin
name := String(output_hash[index]);
end;
get_name_from_id := name;
End;
procedure TSDIAppForm.FormShow(Sender: TObject);
begin
output_hash := THashedStringList.Create;
mame_start_ptr := @mame_start;
mame_stop_ptr := @mame_stop;
mame_copydata_ptr := @mame_copydata;
mame_updatestate_ptr := @mame_updatestate;
init_mame(1, 'test', mame_start_ptr, mame_stop_ptr, mame_copydata_ptr, mame_updatestate_ptr);
end;
end.
-
Another thing, i was think seing your code.
Callback function are reintrant.
So may be the behavoir what Arzoo have is a side effect of that.
Arzoo, could you try to just the code of your callback function between Critical Section?
Something like :
Function mame_copydata(id: Integer; name: PChar): Integer; stdcall;
Begin
EnterCriticalSection(CritSect);
SDIAppForm.Memo1.Lines.Add('id '+ IntToStr(id) + ' = '''+ name+ '''');
mame_copydata := 1;
LeaveCriticalSection(CritSect);
End;
Here an article that explain detail on Critical section with delphi :
http://www.delphicorner.f9.co.uk/articles/op4.htm
So maybe he should try putting that code into it's own thread?
It could be difficult to make run just the plugin in another thread. I don't see right now how to do that.
May be the more simple would be that the plugin runs an external exe that only handle the callback.
Or May be, but not sure at all, as you said, just put the call of init_mame(1, 'test', mame_start_ptr, mame_stop_ptr, mame_copydata_ptr, mame_updatestate_ptr); in another thread. But i don't know really how the callback will be handle in that case.
-
Hey guys, thanks for all your help on this. :)
Youki - I think headkaze pretty much answered your questions about how mame.dll works. I'll test the CriticalSection threading code - not sure if it will help but it's definitely worth a try. As for running my plugin in a separate thread - it seems like a good idea, but that would have to be coded in MaLa.
hk - I've considered you're suggestion to create a separate exe which would handle all the output messages external to MaLa. There's also another option - I could buffer all the messages with timestamps and then (using a separate timer) process them asynchronously. With a bit of analysis, I could determine if the timing is wrong and correct it. Both these solutions seem like a ton of effort to work around an issue which should be easy to resolve - but is unfortunately out of my control. If swindus or aaron giles don't get involved these may be my only options.
-
Hey guys, thanks for all your help on this. :)
hk - I've considered you're suggestion to create a separate exe which would handle all the output messages external to MaLa. There's also another option - I could buffer all the messages with timestamps and then (using a separate timer) process them asynchronously. With a bit of analysis, I could determine if the timing is wrong and correct it. Both these solutions seem like a ton of effort to work around an issue which should be easy to resolve - but is unfortunately out of my control. If swindus or aaron giles don't get involved these may be my only options.
Or you know, you could use mamehooker, which already does that. :)
-
Hi Arzoo, i'm curious, didyou progress on that topic?
-
Hi Arzoo, i'm curious, didyou progress on that topic?
Unfortunately not. I've been busy with my family doing holiday stuff - so no time for mame. I'm hoping to try the CriticalSection code tonight - I'll let you know how it goes.
-
No luck with the CriticalSection code :(
-
:(
-
So it turns out that more than just the mame outputs are affected when my plugin runs in the MaLa thread. A few days ago my son had a LAN party and my mame system got a good testing. One thing I noticed was that the LED animation that starts when a mame game is paused was running really slow - like each frame was taking a second. The same animation runs fine when the MaLa screen saver mode is active - so again it seems to have something to do with mame and MaLa. I ran some quick tests and determined that the game pause animation runs fine when my plugin code is executing outside the MaLa thread.
It looks like the only way I can solve these problems would be to modify LEDBlinky so that it runs externally to MaLa. This would require that the plugin sends messages to the external app based on the MaLa events. One additional advantage to doing it this way would be that LEDBlinky could run from any FE. I've never coded any applications that use windows messages to communicate - does anyone have any sample code they could provide or other help? Thanks!
-
yeah sounds like your thinking is correct.
Not that it is a problem for me but my LCD 2x20 display (unsing MaLa hardware) runs very slow during gameplay but fine when a game is quit.
-
arzoo: I don't see the difference between running a separate program to running your plugin code on a separate thread. Have you looked at threading in Delphi? There would be no difference to doing that to running an external exe. The plugin dll is "locked" when called from Mala until it returns so you must place any tasks that don't return immediately in their own thread. Also you have to remember that when Mame is running it doesn't have focus therefore it doesn't have priority. Placing code in threads will improve the response of the program running in the background. In my plugin I wrote an "Event Manager" which allows events to be added to a queue and they are played on a separate thread. When the thread completes the next event in the queue is executed.
Windows messages are easy to use in applications. Ledutil is actually a good example of how to do it.
1. Create a hidden window in client and server apps
2. Use FindWindow() to find the window in the external app
3. Use RegisterWindowMessage() to register custom messages
4. In the WinProc() function check for these custom messages
-
arzoo: I don't see the difference between running a separate program to running your plugin code on a separate thread. Have you looked at threading in Delphi? There would be no difference to doing that to running an external exe. The plugin dll is "locked" when called from Mala until it returns so you must place any tasks that don't return immediately in their own thread. Also you have to remember that when Mame is running it doesn't have focus therefore it doesn't have priority. Placing code in threads will improve the response of the program running in the background. In my plugin I wrote an "Event Manager" which allows events to be added to a queue and they are played on a separate thread. When the thread completes the next event in the queue is executed.
Windows messages are easy to use in applications. Ledutil is actually a good example of how to do it.
1. Create a hidden window in client and server apps
2. Use FindWindow() to find the window in the external app
3. Use RegisterWindowMessage() to register custom messages
4. In the WinProc() function check for these custom messages
hk - thanks for the help. I agree, using multiple threads would most likely also solve the problem. The only advantage I see to using a separate app is the ability to launch LEDBlinky from any FE. Not sure which solution I'll try - hmmmm.