Link to home
Start Free TrialLog in
Avatar of diver999
diver999

asked on

Best way to call code after interrupt

Hi,
I have a hardware interrupt which executes some code (in Delphi) and sets a flag.  
The flag is to be used to update displays and databases.
What is the best way to ensure that the code called by the flag is executed as quickly as possible after the end of the interrupt routine ?
Examples would be appreciated
Thanks
Avatar of Geert G
Geert G
Flag of Belgium image

use the observer pattern and put the flag in an observable
all the observers get called instantly when the flag changes

https://www.experts-exchange.com/questions/23365012/MVC-and-Delphi.html
Avatar of diver999
diver999

ASKER

Hi Geert
Thanks for that.  I think that the use of observers (I didn't know about them) sounds very interesting - and a big subject - which I need to research.  At present I feel out of my depth with this.
This question is connected with https://www.experts-exchange.com/questions/24334423/Fast-computer-causes-image-copy-to-crash.html
I have a fairly old and (until now) stable application for image analysis which is triggered by hardware and makes an interrupt.    Within the interrupt routine I had a lot of stuff including display of images and results.  I think that the faster computer is generating interrupts at a higher priority than my hardware, which is causing my application to crash (I know that you should always keep interrupt routines small, but this has seemed to work for a long time....)
I have re-written it so that the interrupt routine just gets the image data into a bitmap object and sets a boolean global variable "inspect_flag".  I then have a timer :
>>>>>>>>>>>>>>>>>>>>>>
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if inspect_flag then
  begin
    UpdateEverythingElse;      
    inspect_flag := false;
  end;
end;
<<<<<<<<<<<<<<<<<<<<<<
which now works fine, but of course I have the timer delay. (I am getting about 300 images per minute)
So I just want something that monitors "inspect_flag" and executes the UpdateEverythingElse as soon as it exits the interrupt routine.
Sorry if I sound a bit dumb - I know I should go and read up about observers etc but I just need to get this going rather quickly
Thanks for your help.
you used a timer to decouple the setting of the flag so your app doesn't need to wait on the update ?
you can use a windows message just the same, without needing a timer
and it should work faster ... if nothing changes, nothing needs an update and no timer running

you'll need to change the setting of the boolean flag to calling a procedure

procedure SetFlagChanded;
begin
  if Assigned(Form1) then
    Form1.FlagChanged := True;
end;
const
  WM_FlagChanged = WM_USER +1;
 
type
  TForm1 = class(TForm)
  private
    procedure SetInspectFlag(const Value: Boolean);
    procedure WMFlagChanged(var Msg: TMessage); message WM_FlagChanged;
  public
    property inspect_flag: boolean read fInspectFlag write SetInspectFlag;
  end;
 
procedure TForm1.SetInspectFlag(const Value: Boolean);
begin
  if fInspectFlag <> Value then 
  begin
    fInspectFlag := Value;
    if fInspectFlag then // only send message when true
      PostMessage(Handle, WM_FlagChanged, 0, 0);
  end;
end;
 
procedure TForm1.WMFlagChanged(var Msg: TMessage); 
begin
  UpdateEverythingElse;  
  fInspectFlag := False;
end;

Open in new window

oops, typo:

procedure SetFlagChanded;
begin
  if Assigned(Form1) then
    Form1.inspect_flag := True;
end;
It looks the right sort of thing but I am not sure where fInspectFlag is declared
It doesn't compile and I can't see what to do
Thanks
Richard
sorry, i usually just type this in the firefox editor, don't use delphi all the time to test

Shift-Ctrl C would have solved that ...
(class completion, just type a procedure in the header and Shift-Ctrl C makes the implementation for you)

  TForm1 = class(TForm)
  private
    fInspectFlag: Boolean;
    procedure SetInspectFlag(const Value: Boolean);
    procedure WMFlagChanged(var Msg: TMessage); message WM_FlagChanged;
  public
    property inspect_flag: boolean read fInspectFlag write SetInspectFlag;
  end;
Thanks Geert
This is what I have...
I am using RapidDriver Pci to get the hardware interrupt (stable solution - been working several years)
What happens is that the UpdateEverythingElse code is not called on every occasion that the Inspect_flag is set.
Am I setting it in the right place ?  I tried before ClearInterrupt also.
I will do some more research.
  TForm1 = class(TForm);
  private
    fInspectFlag : boolean;
    procedure SetInspectFlag(const Value: Boolean);
    procedure WMFlagChanged(var Msg: TMessage); message WM_FlagChanged;
  public
    property inspect_flag: boolean read fInspectFlag write SetInspectFlag;
  end;
 
 
procedure TForm1.SetInspectFlag(const Value: Boolean);
begin
  if fInspectFlag <> Value then
  begin
    fInspectFlag := Value;
    if fInspectFlag then // only send message when true
      PostMessage(Handle, WM_FlagChanged, 0, 0);
  end;
end;
 
procedure TForm1.WMFlagChanged(var Msg: TMessage);
begin
  UpdateEverythingElse;
  fInspectFlag := False;
end;
 
 
procedure UpdateEverythingElse;
begin
   ...
   ...
   ...
end;
 
procedure OnHardwareInterrupt(TimStampLo: Longword; TimeSampHi: Longword); stdcall;
begin
    DisableInterrupt;  //set pci register
    get_image;
    ...
    ...
    ...
    ClearInterrupt;  //reset interrupt flag latch in hardware
    EnableInterrupt; //set pci register 
    Form1.Inspect_flag := true;
end;

Open in new window

Using the code above you will only post a message each time the fInspectFlag is changed from False into True.

If you receive interrupts faster than you are able to process the image and clear the flag, the windows message will not be sent once for every interrupt. One simple change may be able to solve this, swap the lines

  UpdateEverythingElse;
  fInspectFlag := False;

for

  fInspectFlag := False;
  UpdateEverythingElse;

But this is probably not the optimal solution. Do you need to process each and every image or would it be sufficient to process the most recently received image? A better solution may be to store all images in a temporary list/queue and then dequeue them for processing.

Given that this is a hardware interrupt the callback may not be using regular windows messages, in which case the code must also be thread safe to make sure that the interrupt is not copying a new image onto the previous image while you are still processing it. Do you know if this is the case?
ASKER CERTIFIED SOLUTION
Avatar of JonasMalmsten
JonasMalmsten
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Real problem was not solved - it was down to dual core procressor.  Reverted to signle core processr to make the problem go away