List Info

Thread: How to deal with a reference to a function in an extension.




How to deal with a reference to a function in an extension.
user name
2007-10-23 09:21:37
Hi. 

I'd like to ask for your help on the following problem:

I have a C shared object called libtrmc.so. I do not have
access to it's source code.

The Trmc.h has 11 functions. I succeeded in writing an
extension for 10 of them, using h2xs and the tutorial called
perlxstut.

The problem that remains is how to send a reference to a
conversion function written in Perl to the C library.
Important pieces of code are shown below, with my failed
attempt to solve the problem:


>From Trmc.h:
------------------------------------------------------------
------------------------------------------------------------


  typedef struct 
  { 
        ...
	int	(*Etalon)(double *); // transform the argument in Ohm
in Kelvinand return 0 if ok
  } CHANNELPARAMETER; 

  int SetChannelTRMC(CHANNELPARAMETER *channel);

>From an example program given by the programmer:
------------------------------------------------------------
--

  static int conversion(double *data)
  {
      char *formula;

      formula = get_text(channels, "Etalon");
      if (strcmp(formula, "x") == 0) return
_RETURN_OK;  /* f(x) = x */
      *data = evaluate_function(formula, *data);
      return _RETURN_OK;
  }

  void on_SetChannelTRMC_clicked(GtkButton *button, gpointer
user_data)
  {
      CHANNELPARAMETER channel;
      int error;

      ...

      channel.Etalon = conversion;

      /* Call the library. */
      error = SetChannelTRMC(&channel);

  }

This is my failed attempt to solve the problem:

void
SetChannelTRMC(name, value_range_i, value_range_v,
board_address, sub_address, board_type, index, mode,
pre_averaging, scrutation_time, priority_flag, fifo_size,
etalon);

    const char * name;
    double  value_range_i;
    double  value_range_v;
    int	    board_address;
    int	    sub_address;
    int	    board_type;
    int	    index;
    int	    mode;
    int	    pre_averaging;
    int	    scrutation_time;
    int	    priority_flag;
    int	    fifo_size;
    void   * etalon;

  PPCODE:
    CHANNELPARAMETER channel;
    int call_error;

    strcpy(channel.name, name);
    channel.ValueRangeI = value_range_i;
    channel.ValueRangeV = value_range_v;
    channel.BoardAddress = board_address;
    channel.SubAddress = sub_address;
    channel.BoardType = board_type;
    channel.Index = index;
    channel.Mode = mode;
    channel.PreAveraging = pre_averaging;
    channel.ScrutationTime = scrutation_time;
    channel.PriorityFlag = priority_flag;
    channel.FifoSize = fifo_size;
    channel.Etalon = etalon;

    call_error = SetChannelTRMC(&channel);

    XPUSHs(sv_2mortal(newSVnv(call_error)));
    XPUSHs(sv_2mortal(newSVpv(channel.name,0)));
    XPUSHs(sv_2mortal(newSVnv(channel.ValueRangeI)));
    XPUSHs(sv_2mortal(newSVnv(channel.ValueRangeV)));
    XPUSHs(sv_2mortal(newSVnv(channel.BoardAddress)));
    XPUSHs(sv_2mortal(newSVnv(channel.SubAddress)));
    XPUSHs(sv_2mortal(newSVnv(channel.BoardType)));
    XPUSHs(sv_2mortal(newSVnv(channel.Index)));
    XPUSHs(sv_2mortal(newSVnv(channel.Mode)));
    XPUSHs(sv_2mortal(newSVnv(channel.PreAveraging)));
    XPUSHs(sv_2mortal(newSVnv(channel.ScrutationTime)));
    XPUSHs(sv_2mortal(newSVnv(channel.PriorityFlag)));
    XPUSHs(sv_2mortal(newSVnv(channel.FifoSize)));
    XPUSHs(sv_2mortal(newSViv((void *)channel.Etalon)));

But it did not work. Can you, please, help me solving this
problem? 

Thanks in advance,

Eduardo.




-------------------------------------
Eduardo Novaes Hering, DSc.
  enheringgabuleu.com

  



Re: How to deal with a reference to a function in an extension.
user name
2007-10-23 10:39:20
Quoth enheringgabuleu.com ("=?ISO-8859-1?Q?Eduardo
N. Hering?="):
> 
> I'd like to ask for your help on the following
problem:
> 
> I have a C shared object called libtrmc.so. I do not
have access to it's
> source code.
> 
> The Trmc.h has 11 functions. I succeeded in writing an
extension for 10
> of them, using h2xs and the tutorial called perlxstut.
> 
> The problem that remains is how to send a reference to
a conversion
> function written in Perl to the C library. Important
pieces of code are
> shown below, with my failed attempt to solve the
problem:
> 
> From Trmc.h:
> 
>   typedef struct 
>   { 
>         ...
> 	int	(*Etalon)(double *); 
>   } CHANNELPARAMETER; 
> 
>   int SetChannelTRMC(CHANNELPARAMETER *channel);
<snip>
> 
> This is my failed attempt to solve the problem:
>
> void
> SetChannelTRMC(name, value_range_i, value_range_v,
board_address,
> sub_address, board_type, index, mode, pre_averaging,
scrutation_time,
> priority_flag, fifo_size, etalon);
<snip>
>     void   * etalon;
> 
>   PPCODE:
<snip>
>     channel.Etalon = etalon;
> 
>     call_error = SetChannelTRMC(&channel);

You have not said how you are calling this function from
Perl .
If you
were able to call it with the address of a C function, it
would have
worked; but you can't do that. What you need to do is write
a function
in C in the top section of your XS file that takes two
double*
arguments, converts them into Perl scalars, and then calls a
Perl
function. See perlcall for details on how to do this. You
can then pass
this C function into the library.

The difficult part in this case will be finding a way to
pass the Perl
sub to call into the C function, as the callback API doesn't
appear to
include any sort of 'user data' parameter (tut, bad API
design  ).
There is a discussion of this issue, and some possible
solutions, at the
end of perlcall.

Ben


[1-2]

about | contact  Other archives ( Real Estate discussion Medical topics )