[Gambas-user] Working with .so library

Admin admin at allunix.ru
Mon Jun 24 15:13:22 CEST 2019


Greetings, people of Gambas!

So, this thread is couple of years old now, and yet I want to thank 
everyone again, who helped me with that issue. Everything worked out 
just fine, I was able to create a working cash register software which 
lived through at least thirty versions, was cloned on github by a few 
people to create similar programs for their businesses, and the emails I 
got from them are very satisfying. It works, and many good people saved 
a lot of money dodging the bullet of mandatory Windows installations to 
support those devices that we use nationwide.

So now there's another challenge. Recently linux driver for those 
devices was updated to a new major version, and it is basically a whole 
new .so library. In previous versions, as I've mentioned here, we needed 
to create an interface with the driver from our program using 
CreateFptrInterface function. This function returned a pointer to a 
driver, and thanks to you kind people I was able to understand that we 
needed such a structure in gambas to work with it:

Extern CreateFptrInterface(ver as integer) as Pointer

Public drv as Pointer

Public Sub Form_Load()
     drv = CreateFptrInterface(12)
End sub

and now we basically have drv as a pointer to a Driver, wich can then be 
passed to any library function, so, for example, Beep(drv) will make a 
device to create a sound (that is if we declare Extern Beep(p as 
pointer) ofcourse).

That structure worked until new Driver was created very differently. The 
new .so library is also documented, but, as always, only for those who 
write their applications in C++, and now it says that we need to 
initialize the Driver like this:

libfptr_handle fptr;
libfptr_create (&fptr);

Well, I tried to apply the same knowledge that I've gained with the 
previous version and it did not help.
libfptr_handle does not seem to be a library function at all, yet it is 
described in a header file (which is also available here: 
http://gazizova.net/pub/install/_Devices/atol-30f/10.2.0/ios/fptr10.framework/Headers/libfptr10.h) 

libfptr_create IS a library function, but I could not figure out how to 
corretly call it.

At first I thought that logic is the same: we call a function that 
creates an interface and it gives us back a pointer to a Driver, so in 
Gambas it should look something like:

Extern libfptr_create() as Pointer

Public drv as Pointer

Public Sub Form_Load()
    drv = libfptr_create()
End sub

but ofcourse that is kind of strange, because function libfptr_create as 
it seems to be still wants some argument. And it sure looks like this 
argument is the pointer. And yes, if I call a function like this, I get 
drv = 0. So, then, should I call this function like this:

Public Sub Form_Load()
    libfptr_create(drv)
End sub

putting (p as Pointer) in Extern description ofcourse.

But no, that does not work either. In that case Gambas just segfaults, 
wich, as I now know, just indicates that parameters passed to an 
external function are of wrong type or just there should be more or less 
of them. Looking inside the log file of a Driver I can also see another 
interesting fact: If I, just out of curiosity, call a function 
libfptr_create and pass some random number to it declaring it as integer 
(just like it was in a previous version of a driver where it required to 
have a driver version as integer passed with CreateFptrInterface) - it 
definitly initializes to a, say, much further point then if I pass a 
pointer to it or nothing at all, and fptr becomes equal FFFFFFF. If I 
pass not an Integer, but a random string, the driver initializes to that 
same point, but ftpr stays equal 0. I mean a structure like fptr = 
libfptr_create(12345) or fptr = libfptr_create("test")
I've tried a lot of different combos but still had not figured it out, 
how do I initialize in Gambas what initializes in C++ like this:

libfptr_handle fptr;
libfptr_create(&fptr);

So, as always, any advice will be much appriciated!

Best regards,
Dmitry.


15.06.2017 19:13, ML пишет:
> On 15/06/17 08:48, Admin wrote:
>> 15.06.2017 17:54, Admin пишет:
>>> 15.06.2017 16:19, Tobias Boege пишет:
>>>>> All your help was very important for me, I now have completed my cash
>>>>> register software to the point where it does everything my company
>>>>> needs. I
>>>>> must say Gambas is a great language, it's very easy to learn from
>>>>> scratch,
>>>>> I'm surprised how obvious everything is. But there is a lot of work
>>>>> for me
>>>>> left to do mostly in terms of managing wrong human actions. My
>>>>> software
>>>>> works good if the employee doesn't do any mistakes, but that's
>>>>> unrealistic,
>>>>> so there's a lot of things I want to control and check. And that's
>>>>> where I'm
>>>>> stuck.
>>>>> This library (which still calls itself a driver) theoretically is
>>>>> able to
>>>>> return a lot of values that I need, but I can't understand basic
>>>>> rules of
>>>>> how do we take output from a C-lib in Gambas.
>>>>>  From http://gambaswiki.org/wiki/howto/extern I understood that I
>>>>> need to
>>>>> locate a space in memory and pass a pointer to a library so that it
>>>>> can
>>>>> write data into that place in ram, which I would then read and set
>>>>> free.
>>>>> So I have to declare a pointer, then Alloc(8) it, then pass it to
>>>>> my library
>>>>> and then read from it like it is a stream. Does this principle
>>>>> still work in
>>>>> current version of Gambas?
>>>> If you do Alloc(8), then you get 8 bytes of memory. You most likely
>>>> *don't*
>>>> want to read that like a stream, but use Integer@() or similar
>>>> functions.
>>>>> What I don't understand is how I construct the code in my
>>>>> particular case.
>>>>> To make an interface to the library I declare external pointer like
>>>>> this:
>>>>>       Extern CreateFptrInterface(ver As Integer) As Pointer
>>>>> Then I declare some pointers that I'll use with help of the
>>>>> interface I
>>>>> created:
>>>>>       Extern put_DeviceEnable(p as Pointer, mode as Integer)
>>>>>       Extern GetStatus(p as Pointer, StatRequest as String)
>>>>> Then I declare the pointer which will be that interface:
>>>>>       Public kkmDrv as Pointer
>>>>> So then in sub I can do
>>>>> kkmDrv = CreateFptrInterface(12) ' this establishes the interface
>>>>> put_DeviceEnabled(kkmDrv, 1) ' this transfers the comand to the
>>>>> library
>>>>> through the interface.
>>>>> And it works great.
>>>>> But then If I want to get some data from the library, as I
>>>>> understand, I
>>>>> have to declare another pointer, allocate ram for it and pass my
>>>>> request.
>>>>> I don't understand how should I pass that pointer to GetStatus()
>>>>> while also
>>>>> passing my interface pointer to it, let alone reading data back.
>>>>> Totally
>>>>> confused.
>>>>>
>>>> This entirely depends on how the C functions in your library are
>>>> declared.
>>>> I don't know about your specific library but commonly the occurence
>>>> of an
>>>> error is indicated by an integer return code, e.g. this might be the
>>>> signature of one of the functions in your library:
>>>>     int myfunction(void *interface, int argument)
>>>> If the documentation says that the return value (int) of this function
>>>> indicates an error, then you just need to get that return value back
>>>> into
>>>> your Gambas program, which you accomplish by declaring the function in
>>>> Gambas as
>>>>     Extern myfunction(interface As Pointer, argument As Integer) As
>>>> Integer
>>>> (notice the trailing "As Integer"). Then you can use "myfunction" in
>>>> your
>>>> Gambas code like any other function and get and interpret its return
>>>> value.
>>>> So, if this convention for error reporting is used, it is much
>>>> simpler to
>>>> get information about errors, without using Alloc() and co. Your
>>>> library
>>>> may use a different convention which actually involves pointers, but
>>>> I wouldn't know.
>>>> Regards,
>>>> Tobi
>>>>
>>> I should've said it in the beginning. Ofcourse any function returns
>>> integer value of 0 as success or -1 as error, but that only indicates
>>> that function was successfully executed or not. So GetStatus() will
>>> always return 0 because it shurely ran, nothing can go wrong here.
>>> But that's not the result I want. GetStatus() actually gives back a
>>> string with the status I asked for. Not that I fully understand how
>>> it does that. I already gave links to the libfptr.so library itself
>>> (http://allunix.ru/back/atol.tar.gz) and it's header files
>>> (http://allunix.ru/back/atol-header.tar.gz) so that it's clearer,
>>> what I'm talking about, unfortunately I am absolute zero in C to
>>> figure things out myself.
>>> For example I can see that to get serial number of the device driven
>>> by that library i can use a function described like this:
>>> get_SerialNumber(void *ptr, wchar_t *bfr, int bfrSize);
>>> As far as I can tell what it does is it gets data needed and puts it
>>> into some buffer. The result of executing this function through
>>> put_SerialNumber(kkmDrv) will always be returned to me as 0.
>>> So to see what's in that buffer, I have to then invoke
>>> GetStatus(kkmDrv) describe in .h file like GetStatus(void *ptr); and
>>> the integer result of this operation will also always be 0, which
>>> means that GetStatus itself ran successfully, but I don't care about
>>> that, I want to see what it actually told me, not that if it told me
>>> it successfully or not. So that's the main confusion. If all this is
>>> too complicated and lamely explained then nevermind, I expect it to
>>> be so and I'm sorry, that's the best I can do. I'm just really
>>> confused that I recieve two answers, one boolean telling if function
>>> successfully invoked and one string, carrying the actual data I want.
>>> Best Regards,
>>> Dmitry.
>> UPD: you know, I can be fundamentally wrong about all this library's
>> functionality. Maybe it does not give me any data afterall, I'm
>> beginning to think that this integer (or rather boolean) value is all
>> it gives me back, and the "real" data is just written into it's log
>> file. Which is sufficient to me, so, I guess, nevermind. Sorry about
>> wasting your time.
>> Best regards,
>> Dmitry.
> Dmitry,
> With a desription such as get_SerialNumber(void *ptr, wchar_t *bfr, int
> bfrSize); and having reviewed your communications, I would guess that:
>    *ptr is a pointer to the interface (an input parameter),
>    *buf is a pointer to a -possibly predefined- buffer that the function
> will fill with data (the serial number in this case, could call this an
> output parameter), and
>    bfrSize can be sort of an input/output parameter. bfrSize can hold the
> size in wchar_t units in input and the function may alter it to reflect
> the actual string size returned in *buf.
> All this is just guesswork of course, nothing solid; the actual proper
> usage of the function should be not in the header files, but in the
> documentation.
> The way I would use this call is as follows:
> 1- Get an interface pointer, let's call it ptrItf. You know how.
> 2- Get an int or boolean for the function return value, let's call it
> retVal.
> 3- Get a Gambas string filled with CHR(0), and a pointer to its data
> (make the string big enough so that a serial number would fit, even in
> non-ANSI strings such as UTF-8, and add some slack just to be sure),
> let's call that pointer ptrBuf.
> 4- Get the lenght of the above buffer string, let's call that bufLen.
> 5- Call the function:
>    retVal = get_SerialNumber(ptrItf, ptrBuf, bufLen - 1)
> 6- If retVal <> 0, increment (double) the string size and retry from 3.
> Not in a forever-loop, just once.
> 7- If retVal = 0 then the serial number should somehow be in the string.
> Maybe you have to convert between ANSI/UTF-8/etc., but it should be there.
> Please note that the above is, again, guesswork. Not sure of anything.
> HTH,
> zxMarce.
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> Gambas-user mailing list
> Gambas-user at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/gambas-user
>
>
>



More information about the User mailing list