Recent

Author Topic: Am I being stupid? Passing procedures  (Read 5340 times)

richard_rtech

  • New Member
  • *
  • Posts: 35
Am I being stupid? Passing procedures
« on: July 04, 2015, 02:54:30 pm »
I have a procedure....
Code: [Select]
function AS3935init(device:string; target:cint; irq:integer; irqproc:tirqready; var fhandle):boolean;
It lives in a unit and is very happy there. From a button I call :
Code: [Select]
if as3935init ('/dev/i2c-1', $03, 17,@as3935tripped, as3935_handle) then memo1.lines.add('AS3935 Ready');
All is well, it compiles and runs. The routing as3935tripped contains:
Code: [Select]
procedure tform1.as3935tripped (irqnr:integer;edge:boolean);
begin
     if edge then memo1.lines.add (timetostr(time)+': AS3935 Leading IRQ! '+gpios[irqnr].name)
     else  memo1.lines.add (timetostr(time)+': AS3935 Falling IRQ! '+gpios[irqnr].name)
end;

So far so good.

as3935tripped needs to go in the unit though, the end user has no need to monkey with it. So moved the procedure over. Its called with *exactly* the same parameters and now fails to compile with:

Code: [Select]
unit1.pas(316,50) Error: Incompatible type for arg no. 4: Got "<address of procedure(LongInt,Boolean);StdCall>", expected "<procedure variable type of procedure(LongInt,Boolean) of object;StdCall>"

I'm guessing the 'object' is the key here but I'm stumped. Is it because its not longer part of the applications form?




richard_rtech

  • New Member
  • *
  • Posts: 35
Re: Am I being stupid? Passing procedures
« Reply #1 on: July 04, 2015, 03:31:06 pm »
Memo1 reference is a red herring. And empty procedure does the same and there is a compiler warning for that which i was aware of. Thanks tho

typo

  • Hero Member
  • *****
  • Posts: 3051
Re: Am I being stupid? Passing procedures
« Reply #2 on: July 04, 2015, 03:33:01 pm »
Sorry, I have misunderstood your question.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Am I being stupid? Passing procedures
« Reply #3 on: July 04, 2015, 03:40:48 pm »
apparently you're using as3935tripped  a callback parameter in as3935init .

Originally it was a method (procedure .. of object), but now you made it a procedure that's why compiler is complaining.

Check the type of the callback (TIRQReady type), you might need to change it ..or do a trick :)

I bet it's declared as:
Code: [Select]
type
  TIRQReady = procedure(irqnr:integer; edge: Boolean) of object; stdcall;
« Last Edit: July 04, 2015, 03:44:46 pm by skalogryz »

richard_rtech

  • New Member
  • *
  • Posts: 35
Re: Am I being stupid? Passing procedures
« Reply #4 on: July 04, 2015, 03:47:03 pm »
Thats kinda the line I was following. Any trick in particular? :D Having had suspicions confirmed I think I can see a way out by making it part of a dummy class but this seems messy. Had to do this before and it feels "wrong"

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Am I being stupid? Passing procedures
« Reply #5 on: July 04, 2015, 03:52:14 pm »
Thats kinda the line I was following. Any trick in particular? :D Having had suspicions confirmed I think I can see a way out by making it part of a dummy class but this seems messy. Had to do this before and it feels "wrong"
lol. yes. A dummy class is your answer.
Code: [Select]
unit nottheuserinterfaceunit;

type
  TIRQHandler = class 
    class procedure as3935tripped (irqnr:integer;edge:boolean)
  end;

class procedure as3935tripped (irqnr:integer;edge:boolean)
begin
 ... do the callback...
end;

...
unit whereInitisCalled

if as3935init ('/dev/i2c-1', $03, 17,@TIRQHandler.as3935tripped, as3935_handle) then memo1.lines.add('AS3935 Ready');


jc99

  • Hero Member
  • *****
  • Posts: 553
    • My private Site
Re: Am I being stupid? Passing procedures
« Reply #6 on: July 04, 2015, 03:53:25 pm »
Thats kinda the line I was following. Any trick in particular? :D Having had suspicions confirmed I think I can see a way out by making it part of a dummy class but this seems messy. Had to do this before and it feels "wrong"
or just remove the 'of object' in the declaration line and look if it's working now.
OS: Win XP x64, Win 7, Win 7 x64, Win 10, Win 10 x64, Suse Linux 13.2
Laz: 1.4 - 1.8.4, 2.0
https://github.com/joecare99/public
'~|    /''
,_|oe \_,are
If you want to do something for the environment: Twitter: #reduceCO2 or
https://www.betterplace.me/klimawandel-stoppen-co-ueber-preis-reduzieren

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Am I being stupid? Passing procedures
« Reply #7 on: July 04, 2015, 04:03:55 pm »
or just remove the 'of object' in the declaration line and look if it's working now.
eventually adding  "data" pointer in the end? so a method call could be implemented?

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: Am I being stupid? Passing procedures
« Reply #8 on: July 04, 2015, 04:12:52 pm »
Or like this, if your form is in same unit (or uses that unit in the implementation section) as public variable form1. The problem with this is that if you have multiple instances of this form it won't work. You may have to also pass the form as parameter, or do as above and use "of object".

Code: [Select]
type
  TIRQReady = procedure(irqnr:integer; edge: Boolean);

Code: [Select]
procedure as3935tripped (irqnr:integer;edge:boolean);
begin
     if edge then form1.memo1.lines.add (timetostr(time)+': AS3935 Leading IRQ! '+gpios[irqnr].name)
     else form1.memo1.lines.add (timetostr(time)+': AS3935 Falling IRQ! '+gpios[irqnr].name)
end;
« Last Edit: July 04, 2015, 04:15:09 pm by User137 »

jc99

  • Hero Member
  • *****
  • Posts: 553
    • My private Site
Re: Am I being stupid? Passing procedures
« Reply #9 on: July 04, 2015, 04:24:37 pm »
Or like this, if your form is in same unit (or uses that unit in the implementation section) as public variable form1. The problem with this is that if you have multiple instances of this form it won't work. You may have to also pass the form as parameter, or do as above and use "of object".

Code: [Select]
type
  TIRQReady = procedure(irqnr:integer; edge: Boolean);

Code: [Select]
procedure as3935tripped (irqnr:integer;edge:boolean);
begin
     if edge then form1.memo1.lines.add (timetostr(time)+': AS3935 Leading IRQ! '+gpios[irqnr].name)
     else form1.memo1.lines.add (timetostr(time)+': AS3935 Falling IRQ! '+gpios[irqnr].name)
end;
I go with skalogryz, a data pointer ee: TStrings at the end would do it
Code: [Select]
type
  TIRQReady = procedure(irqnr:integer; edge: Boolean;const sList:TStrings);

Code: [Select]
procedure as3935tripped (irqnr:integer;edge:boolean;const sList:TStrings);
begin
     assert(assigned(sList),'Stringlist not prepared');
     if edge then sList.add (timetostr(time)+': AS3935 Leading IRQ! '+gpios[irqnr].name)
     else sList.add (timetostr(time)+': AS3935 Falling IRQ! '+gpios[irqnr].name)
end;
Also gpios must be in the scope of the Procedure.
OS: Win XP x64, Win 7, Win 7 x64, Win 10, Win 10 x64, Suse Linux 13.2
Laz: 1.4 - 1.8.4, 2.0
https://github.com/joecare99/public
'~|    /''
,_|oe \_,are
If you want to do something for the environment: Twitter: #reduceCO2 or
https://www.betterplace.me/klimawandel-stoppen-co-ueber-preis-reduzieren

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Am I being stupid? Passing procedures
« Reply #10 on: July 04, 2015, 04:43:14 pm »
imho, as3935tripped should remain where it is now :D
declaration of TIRQReady and AS3935init should change.

I presume as3935xxx functions are low level API.
and what richard_rtech is trying to do, is hide their low-levelness.

But instead of changing APIs themselves, he could introduce TAS3935 class or something...

richard_rtech

  • New Member
  • *
  • Posts: 35
Re: Am I being stupid? Passing procedures
« Reply #11 on: July 04, 2015, 05:04:25 pm »
Thank you guys. A class could kind of work out a better option anyway. I will have a look now I'm back at my desk.

Turns out a Slugway and decent coffee were needed.

In short I'm tying myself in knots here. The unit is a low level IRQ handling routine to give Laz/FPC access to the pin IRQs on the Raspberry Pi.
Initially I fired off a callback for the user to catch with the IRQ pin and the edge. This worked well and eerything was good.

Adding sensors to this library there is processing to be done with some when an IRQ arrives, one IRQ fits all now doesnt work. Tirqready did live in the thread and was the catch all. The GPIO class now hosts this on a per IRQ basis so the end user (and I) can assign arbitary routines on a per pin basis. This means I can now assign and 'lock' pins out of reach and fire my handlers, then fire a new callback for THAT sensor (an AS3935 lightning detector in this case)

In this case tonirqready isnt needed in the thread at all now and is better off being part of the GPIO class. I was being lazy/had forgotten to move it there. On top of this that code fragment setting up the IRQ was also wrong, it shouldnt be setting up an IRQ callback but a new (as yet nonexistant) callback to deliver the results.

A lot of this is way out of my comfort zone so learning as I go along, especially realising how much Win32 handholds the programmer vs Linux. Most code this low level I've done in STM32/PIC/MC68K Assembler


 

TinyPortal © 2005-2018