GPIOInputEvent data argument

General discussion about anything related to Ultibo.
Poi
Posts: 36
Joined: Mon Jan 07, 2019 11:57 pm

GPIOInputEvent data argument

Postby Poi » Sat Jul 06, 2019 8:17 pm

I am trying and failing to use the GPIOInputEvent data argument. I got the events working properly across multiple push buttons, but getting a unique id on each event is proving to be difficult.

I am using this procedure to set up the event

Code: Select all

procedure GPIOPinSetup(Pin:LongWord; Button:String);
begin
   GPIOPullSelect(Pin, GPIO_PULL_UP);
   GPIOFunctionSelect(Pin, GPIO_FUNCTION_IN);

   GPIOInputEvent(Pin, GPIO_TRIGGER_LOW, INFINITE, @GPIOPinEventLow, @Button);
end;


Then I use it like this

Code: Select all

GPIOPinSetup(GPIO_PIN_11, 'BUTTON_1');


I have two functions for the trigger low and trigger high events which look like this

Code: Select all

procedure GPIOPinEventHigh(Data:Pointer; Pin:LongWord; Trigger:LongWord);
begin
   Sleep(100);

   GPIOInputEvent(Pin, GPIO_TRIGGER_LOW, INFINITE, @GPIOPinEventLow, Data);
end;

procedure GPIOPinEventLow(Data:Pointer; Pin:LongWord; Trigger:LongWord);
begin
   Sleep(100);

   GPIOInputEvent(Pin, GPIO_TRIGGER_HIGH, INFINITE, @GPIOPinEventHigh, Data);
end;


My problem is that when I try to access the value of Data to print it to console, it seems to be empty. I'm trying to get the value doing this, which according to the compiler is ok and it doesn't complain at runtime either, it just returns an empty string :?

Code: Select all

   PString(Data)^


I tried the referencing and casting + dereferencing logic in a small synchronous snippet, just to be sure I wasn't messing that up, and it looks like it works just fine.

Any ideas?
User avatar
Ultibo
Site Admin
Posts: 2257
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: GPIOInputEvent data argument

Postby Ultibo » Sun Jul 07, 2019 10:07 am

Poi wrote:My problem is that when I try to access the value of Data to print it to console, it seems to be empty. I'm trying to get the value doing this, which according to the compiler is ok and it doesn't complain at runtime either, it just returns an empty string :?

There are two issues I can see here:

1. A string is really a pointer already so @Button will give the address of the pointer to the string not the address of the string itself, when passing 'BUTTON_1' as a string literal then @Button will return an address from the stack of the calling thread which might be invalid by the time the GPIO event occurs.

2. Strings are reference counted in Free Pascal, when you call GPIOPinSetup and pass 'BUTTON_1' that string will be allocated and given a reference count of 1, when the function that called GPIOPinSetup exits the reference count will be decremented and (if it reaches zero) the string will be freed. Obtaining a pointer to the string (like @Button) doesn't increase the reference count so by the time the GPIO event occurs the string will have been freed and the memory reused for something else.

To resolve each of those is quite simple:

For issue 1. Pass the string to GPIOInputEvent as PChar(Button) instead of @Button, then you can simply cast the Data parameter as PChar(Data) in GPIOPinEventHigh and GPIOPinEventLow in order to access the string value.

And for issue 2. Use a global constant or a global variable for the 'BUTTON_1' value, if the values are always predefined then a global constant will work nicely, on the other hand a global variable will work but is not a very good solution. A better option would be to explicitly allocate a string to be passed as the Data parameter like this:

Code: Select all

procedure GPIOPinSetup(Pin:LongWord; Button:String);
var
   Data:PChar;
begin
   GPIOPullSelect(Pin, GPIO_PULL_UP);
   GPIOFunctionSelect(Pin, GPIO_FUNCTION_IN);

   Data:=StrAlloc(Length(Button) + 1); //Length of string plus null terminator
   StrPCopy(Data,Button);
   
   GPIOInputEvent(Pin, GPIO_TRIGGER_LOW, INFINITE, @GPIOPinEventLow, Data);
end;

The value of the Data param will then point to the allocated string, of course if you finish with the value and don't need it again you should call StrDispose to release it.
Ultibo.org | Make something amazing
https://ultibo.org
Poi
Posts: 36
Joined: Mon Jan 07, 2019 11:57 pm

Re: GPIOInputEvent data argument

Postby Poi » Sun Jul 07, 2019 12:49 pm

That did the trick, thanks!

Of course I forgot that a string is actually a pointer to the first character of the chain! I blame modern languages for perpetuating the illusion that strings are primitive data types, what a scam :P

Return to “Discussion”

Who is online

Users browsing this forum: dieselnutjob and 0 guests