Search Here

Sunday, February 1, 2015

Forgin Function Interface with Perl

Dear Readers,

Very Happy New year 2015. Opps!! I didn't realize that already a month over after the new year is started. Its Feb 2015 now. Hmmm.. Time pass by so fast.

After the Christmas and new year vacation, @work + @home keeps me busy and did not get enough time to do experiments.

@Work, we are working on a LPC micro controller based board to control another electronics board which has a digital radio IC (DAB | DRM | HD) on it. LPC micro controller board has a USB connectivity and it will be connected to Computer to take batch commands.

Batch commands the will get processed further inside the LPC micro controller board and the send to connected digital radio IC. This complex setup was made because we cant not afford PC to USB latency So we have a LPC board in middle. (Hey, I am not an embeeded enginner, So no more questions :) ).

We have also decided to use WinUSB based minimal driver in PC side to communicate with LPC micro controller. So there will be a .dll (Say liblpccommunicate.dll) which is wrapper over WinUSB provides communication functions.

In C world, its awesome. Just load the dll (and corresponding header file) and start communicating with LPC board (atleast in windows its easy).

How do we communicate with LPC board from scripting languages like Perl / Python?

My experiment is started here.

Earlier projects, we use to expose a virtual COM / Serial port from the USB drivers so all the scripting languages can just use the well defined COM / Serial interface to communicate from computer to device.

I have used Win32::SerialPort (for windows) perl module to communicate to devices (mostly electronic boards which has a specific SoC to test).

There is also a Device::SerialPort for Linux for the same purpose.

Now, I can not use the above super reliable modules from my perl scripts because of lack of COM port interface.

I was experimenting with multiple options to import the function from DLL / Shared Lib to perl's space and call it.

Some time back I was experimenting the very limited and windows only modules called Win32::API. The main limitation is that we can not call a function that returns a structure.

In my case, almost all the USB function would return a structure. So Win32::API is ruled out.

Then I came across a open source project (actively maintained since 1998!!) called libffi. libffi provides easy mechanism to call the functions exported in the DLL / Shared Lib at run time.

Awesome, I was looking for this !!. Next, I was looking options to use the libffi in perl. I dont want to re-invent the wheel again. So I search in metacpan , This is a beauty of perl. If you think you have a problem, some one would have already solved in CPAN so you can concentrate on your application work.

I found a module called FFI::Raw , I did few experiments and its seems to be working for me.

Then from the perl news letter, I got to know the new perl + FFI work by



HERE you can find some more advantages of FFI::Platypus.

Thanks to











 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#!perl
#Description: Get linux system uptime using GNOME libgtop library and FFI::Platypus
#Refer: https://developer.gnome.org/libgtop/stable/libgtop-Uptime.html
#Author: Bakkiaraj M
use strict;
use warnings;
use FFI::Platypus;
use FFI::CheckLib;
use Convert::Binary::C;
use Time::Seconds;
use Data::Dumper;

#Globals
my $ffiObj = "";
my $libPath = "";
my $cStructObj = "";
my $glibtopUptimeSize = 0;
my $glibtopUptimeStruct = undef;
my $packedglibtopUptimeStruct = undef;
my $timeObj = "";

#Find the lib
$libPath = find_lib(lib=>'gtop-2.0',libpath=>'/usr/lib64');


print "\n Found libgtop in :", $libPath;

#Create FFI::Platypus object
$ffiObj = FFI::Platypus->new();
$ffiObj->lib($libPath);

#Create Convert::Binary::C object to import the structures 
$cStructObj = Convert::Binary::C->new();
$cStructObj->configure( 'Alignment' => 0 );

#import glibtop_uptime struct using Convert::Binary::C
#Note: guint64 is unsigned long as per 
#http://www.freedesktop.org/software/gstreamer-sdk/data/docs/latest/glib/glib-Basic-Types.html#guint64

$cStructObj->parse(<<ENDC);
struct glibtop_uptime {
    unsigned long flags;
    double uptime;      /* GLIBTOP_UPTIME_UPTIME */
    double idletime; /* GLIBTOP_UPTIME_IDLETIME */
    unsigned long boot_time;
};
ENDC

$glibtopUptimeStruct = {};
$packedglibtopUptimeStruct = $cStructObj->pack('glibtop_uptime',$glibtopUptimeStruct);

#Get size of the glibtop_uptime
$glibtopUptimeSize = $cStructObj->sizeof('glibtop_uptime');

#typecast the glibtop_uptime as a FFI::Platypus record
$ffiObj->type("record($glibtopUptimeSize)"=>'glibtop_uptime');
#import glibtop_get_uptime function from libgtop to perl
$ffiObj->attach('glibtop_get_uptime',['glibtop_uptime'],'void');

#Call glibtop_get_uptime
glibtop_get_uptime ($packedglibtopUptimeStruct);

#unpack the structure
$glibtopUptimeStruct = $cStructObj->unpack('glibtop_uptime',$packedglibtopUptimeStruct);
#print "\n", Dumper($glibtopUptimeStruct);
print "\n System is upfor: ", $glibtopUptimeStruct->{'uptime'}," Sec";

$timeObj = Time::Seconds->new($glibtopUptimeStruct->{'uptime'});
print "\n System is upfor: ",$timeObj->pretty;

#using uptime command
print "\n\n System is upfor:";
system('uptime -p');

exit (0);
Get System time from windows OS using GetLocalTime API


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#!perl
# Author : Bakkiaraj M
# Script: Get System time from windows OS using GetLocalTime API.
use strict;
use warnings;
use FFI::CheckLib;
use FFI::Platypus;
use Convert::Binary::C;

#Get the system time using Kernel32.dll

#find the Kernel32.dll 
my $libPath = find_lib(lib=>'Kernel32');
#Create FFI Object
my $ffiObj = FFI::Platypus->new();
$ffiObj->lib($libPath);

#Import the GetLocalTime function
$ffiObj->attach('GetLocalTime',['record(16)'],'void');

#Define SYSTEMTIME Struct as per https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
#As per, C:\MinGW\include\windef.h, WORD id unsigned short
my $c = Convert::Binary::C->new->parse(<<ENDC);
  
struct SYSTEMTIME {
  unsigned short wYear;
  unsigned short wMonth;
  unsigned short wDayOfWeek;
  unsigned short wDay;
  unsigned short wHour;
  unsigned short wMinute;
  unsigned short wSecond;
  unsigned short wMilliseconds;
  };
  
ENDC


my $dateStruct = {
  wYear=>0,
  wMonth=>0,
  wDayOfWeek=>0,
  wDay=>0,
  wHour=>0,
  wMinute=>0,
  wSecond=>0,
  wMilliseconds=>0,
};

my $packed = $c->pack('SYSTEMTIME', $dateStruct);

#Call the function by passing the structure reference
GetLocalTime($packed);

if (defined ($packed))
{
 #Unpack the structure 
 my $sysDate = $c->unpack('SYSTEMTIME', $packed);
 print "\n WINDOWS SYSTEM TIME: ",$$sysDate{'wHour'},':',$$sysDate{'wMinute'},':',$$sysDate{'wSecond'},'.',$$sysDate{'wMilliseconds'},' ',$$sysDate{'wDay'},'/',$$sysDate{'wMonth'},'/',$$sysDate{'wYear'}, "\n";
}
else
{
 print "\n Something is wrong\n";
}

exit 0;


For more examples go to HERE.

I hope, with libffi we can open up the scripting interface from our WinUSB based driver.

I will share the details in future..