[Gambas-user] Working with .so library
Admin
admin at ...3661...
Wed May 31 06:48:53 CEST 2017
So, I am writing a programm for my business that would basically be a
cash register. Don't know for other countries but here in Russia the tax
law works like this: you have to form a check for a customer in a
spicific way spicified by the law, so some hardware manufacturers are
making certified cash registers/check printers that simply form the
check needed and automatically send tax info to authorities, very simple
and easy to integrate with ERP systems. The only problem is that most of
accounting software that is compatible with those registers is written
for Windows. Now that Windows becomes more and more monstrous, many
businesses turn to Linux, at least on those computers that are only a
cashier's workstation that does not need to do much in terms of
performance power. But the problem is, there's only one or two cashier's
programms for linux exist for now, that are compatible with that
certified hardware, and it's not open source or free.
First of all I want to make my own for myself, and second - I want to
share it. Gambas is a great language in this case because of many
aspects. In small buisnesses usually there are not a lot of qualified
programmers to make some apps in C or C++, but instead there usually is
just a single sysadmin, who is servicing the IT stuff wich usually is
just one or two PCs and a router/switch. So, Gambas is much more
accessible to those people as I see it. Programs written on it are easy
to understand and modify to the needs of a small business.
And what is great - the manufacturers of that certified hardware are
willing to help: ofcourse they mostly do business with Windows stuff,
they only work directly with big businesses and they don't produce
accounting software themselves, but they are kind enough to provide at
least a binary libraries (they call those - drivers, but i'm not shure
if it's technically correct) for their hardware even for Linux as a x86
and x64 .so files. What those binary libraries do is simple conversion
of easy commands to hex codes that are then passed to a hardware via USB
or RS232 or Ethernet. It is MUCH easier to work with those commands then
implement the whole communication protocol from scratch. Ofcourse I am
not the only one who is interested in those devices to work under linux,
and as I can tell from different forums in the internet - programmers
successfully use this libraries and thank the developers. There's not a
lot of documentation out there, but yeah, on paper it seems to be simple
enough... if you write your code in C or C++.
Things get much different when you try to use the library in Gambas.
What I was able to understand from the documentation is that you need to
"initialize the interface" with the library, which will create a
"virtual class" and than you can pass your data to it. So, in C (using
QT) that would look something like this:
typedef IFptr * (*_CreateFptrInterface)(int ver);
bool init() {
QLibrary *lib = new QLibrary("fptr");
lib->load();
if(lib->isLoaded()) {
_CreateFptrInterface CreateFptrInterface =
(_CreateFptrInterface)lib->resolve("CreateFptrInterface");
if(CreateFptrInterface) {
IFptr * iface = CreateFptrInterface(12);
iface->put_DeviceEnabled(true);
int result = 0;
iface->get_ResultCode(&result);
qDebug() << result;
wchar_t bfr[1000];
int length = iface->get_ResultDescription(bfr,1000);
qDebug() << QString::fromWCharArray(bfr,length);
}
}
}
So, as I understand we create a pointer called IFptr by calling
CreateFptrInterface() and then we pass any other pointer through this
one. Pardon my terminology, I am new to this stuff.
I wrote some simple code that basically initializes this driver just so
I can see some output in the driver logs which are kindly created in
~/.atol. It also sends some data to driver which must change just one
setting:
-----
Library "~/ATOL/linux-x64/libfptr"
Extern CreateFptrInterface(ver As Integer) As Pointer
Extern put_DeviceSingleSettingAsInt(p As Pointer, s1 As String, s2 As
Integer) As Integer
Extern ApplySingleSettings(p As Pointer) As Pointer
[...]
Public Sub Button1_Click()
Dim IFptr As Pointer
IFptr = CreateFptrInterface(12)
put_DeviceSingleSettingAsInt(IFptr, "Model", 63)
ApplySingleSettings(IFptr)
End
-----
When I click Button1, the driver surely initializes, I see in logs that
IFptr object is created. If I provide the wrong version in
CreateFptrInterface it fails, saying in logs that there's missmatch in
interface version, so no doubt the argument is passed correctly. I also
can see that put_DeviceSingleSetting is being called, but the
configuration does not actually change. The commercial software that
uses this very same driver and works fine - leaves mostly the same trace
in driver's log except that I see what arguments are passed to
DeviceSingleSetting. And in my case I only see that the procedure is
envoked but with no arguments. I was trying to use many other procedures
(or methods, or pointers, or what are they?) with the same effect - they
surely are called and executed, but I can't pass any arguments to them.
I was experimenting with variable types I send them, and if I, for
example, send an integer as an argument when the library expects a
string - it crashes. If I do not use IFptr pointer - it crashes. So I
think I figured out the syntax correctly, but I still can't get the
desired result.
My question is basically this: Should I continue experimenting, or is it
simply impossible to work with this kind of library from Gambas?
Here is the link to the library and some other libraries it uses itself:
http://allunix.ru/back/atol.tar.gz - there's also a binary executable
that is a test program, unfortunately it's in Russian, but it still
shows what logs must look like when everything is correct, just for a
comparison.
There's simple experiment you can make: it has a pointer
ShowProperties() which must show a window with driver's settings using
it's own library libgui_engine.so. When I call ShowProperties(IFptr) it
prints to log that it can't find this lib, which is expectable, because
first I must provide the path to it using
put_DeviceSingleSettingAsBuff(IFptr, "SearchDir",
"/home/bocha/ATOL/linux-x64/") and AplySingleSettings(IFptr), but when I
pass this setting, I, as always, see that it passes no arguments, so the
result stays the same.
I do understand that I ask a lot of invovement, there's no simple way to
understand what's needed to be done to make this whole thing work so not
many people would even read this message to the end, but I still hope
for some answers, they would be much appriciated. Thank you!
Best Regards.
Dmitry Bachilo.
More information about the User
mailing list