1. wrapping C functions

It's been many a year since I wrapped any libraries for use with euphoria and i've forgotten anything i knew and i'm trying to wrap the raspberry pi wiringPi library and hit two functions that i can't for the life of me remember how to handle. I've done everything else just those two remain

int wiringPiSPIDataRW (int channel, unsigned char *data, int len) ;

&

extern void serialPrintf (int fd, char *message, ...) ;

please can someone put me out of my misery?

new topic     » topic index » view message » categorize

2. Re: wrapping C functions

 
  dll_ptr = open_dll("whatever_your_library_is.dll") 
 
wiringPiSPIDataRaw = link_c_func(dll_ptr, "wiringPiSPIDataRW", {C_INT, C_POINTER, C_INT}, C_INT) 
											 
function euWiringPiSPIDataRaw( integer x, atom yptr, integer z) 
  atom ret 
  ret = c_func(wiringPiSPIDataRaw,{x, yptr, z}) 
  return ret 
end function 
serialPrintf = link_c_proc(dll_ptr, "serialPrintf", {C_INT, C_POINTER, ...}) 
procedure euSerialPrintf(integer fd, atom message_ptr, ...) 
 
  c_proc(serialPrintf, {fd, message_ptr, ...}) 
 
end procedure 
 

You will need to poke and organize the data for the data and message ptrs according to however the pi expects to see it still.

new topic     » goto parent     » topic index » view message » categorize

3. Re: wrapping C functions

ssallen said...
serialPrintf = link_c_proc(dll_ptr, "serialPrintf", {C_INT, C_POINTER, ...}) 
procedure euSerialPrintf(integer fd, atom message_ptr, ...) 
 
  c_proc(serialPrintf, {fd, message_ptr, ...}) 
 
end procedure 
 

That's not exactly right. serialPrintf is a vardic function, which isn't directly supported in Euphoria. Though you could do:

serialPrintStr = link_c_proc(dll_ptr, "serialPrintf", {C_INT, C_POINTER, C_POINTER}) 
procedure euSerialPrintStr(integer fd, sequence message, sequence string) 
 
  atom message_ptr = allocate_string(message) 
  atom string_ptr = allocate_string(string) 
  c_proc(serialPrintStr, {fd, message_ptr, string_ptr}) 
  free(message_ptr) 
  free(string_ptr) 
 
end procedure 
 
serialPrintInt = link_c_proc(dll_ptr, "serialPrintf", {C_INT, C_POINTER, C_INT}) 
procedure euSerialPrintInt(integer fd, sequence message, atom int) 
 
  atom message_ptr = allocate_string(message) 
  c_proc(serialPrintInt, {fd, message_ptr, int}) 
  free(message_ptr) 
 
end procedure 
 

You'd need a new definition for each variation of serialPrintf() that you wanted to handle, though.

new topic     » goto parent     » topic index » view message » categorize

4. Re: wrapping C functions

hahaha, I just thought he didn't want to type all the parameters out. That would have been extremely confusing. Thanks Jim.

new topic     » goto parent     » topic index » view message » categorize

5. Re: wrapping C functions

jimcbrown said...

That's not exactly right. serialPrintf is a vardic function, which isn't directly supported in Euphoria. Though you could do:

You'd need a new definition for each variation of serialPrintf() that you wanted to handle, though.

Ugh. I hate having to deal with variadic functions in Euphoria. Luckily most C libraries also include statically-defined functions that Euphoria can wrap over for variadic purposes. (e.g. just call the static function for each argument in a list)

However, there is hope! I've recently concocted this method for passing a variable number of arguments to C functions by declaring the function on-the-fly and then caching the result. The code below is from memory but should work just fine. This could be simplified for functions that take n-number of a single type by simply calling repeat( C_TYPE, count ), etc.

include "std/dll.e" 
include "std/machine.e" 
include "std/map.e" 
 
map serialPrintf_ids = map:new() 
 
procedure serialPrintf( integer fd, sequence message, object args ) 
     
    -- ensure that 'args' is always a sequence of arguments 
    if atom( args ) then 
        args = {args} 
    end if 
     
    -- declare the base argument types 
    sequence arg_types = {C_INT,C_POINTER} 
     
    -- append the variadic argument types 
    for i = 1 to length( args ) do 
         
        if sequence( args[i] ) then 
            -- replace the argument with a pointer to the string... 
            args[i] = allocate_string( args[i], 1 ) -- (1 = clean up automatically) 
            arg_types = append( arg_types, C_POINTER ) 
             
        elsif integer( args[i] ) then 
            arg_types = append( arg_types, C_INT ) 
             
        else -- atom (float? could be anything depending on your function) 
            arg_types = append( arg_types, C_FLOAT ) 
             
        end if 
         
    end for 
     
    -- lookup this pattern of argument types in the cache 
    integer id = map:get( serialPrintf_ids, arg_types, -1 ) 
     
    if id = -1 then -- not found! 
         
        -- declare this new pattern... 
        id = link_c_proc( dll_ptr, "serialPrintf", arg_types ) 
         
        -- ...and store it in the cache 
        map:put( serialPrintf_ids, arg_types, id ) 
         
    end if 
     
    -- store the message argument in memory 
    atom message_ptr = allocate_string( message, 1 ) 
     
    -- call the function with our arguments 
    c_proc( id, {fd,message_ptr} & args ) 
     
end procedure 

-Greg

new topic     » goto parent     » topic index » view message » categorize

6. Re: wrapping C functions

That's a little risky, you don't know if the integer might actually need to be a double. You should go through the format string instead and determine the types that way.

new topic     » goto parent     » topic index » view message » categorize

7. Re: wrapping C functions

SDPringle said...

That's a little risky

I was thinking that too. Then it dawned on me, there is a far simpler way:

serialPrintf = link_c_proc(dll_ptr, "serialPrintf", {C_INT, C_POINTER}) 
procedure euSerialPrintf(integer fd, sequence fmt, object args) 
 
  c_proc(serialPrintf, {fd, allocate_string(sprintf(fmt,args),1)}) 
 
end procedure 

Pete

new topic     » goto parent     » topic index » view message » categorize

8. Re: wrapping C functions

SDPringle said...

That's a little risky, you don't know if the integer might actually need to be a double. You should go through the format string instead and determine the types that way.

Agreed. I guess I should have pointed that out. My method is really more applicable to functions that take a variable number of the same type, typically pointers to objects. In any case, I would rely on the programmer to make the correct usage and adapt my method as necessary.

Parsing the format string would certainly work, but would also require much more code for a very small gain (one often knows what one is feeding a printf function). Perhaps we could pass the sequence of types directly...

procedure euSerialPrintf(integer fd, sequence fmt, object args = {}, object types = {}) 
 
  if atom( args ) then args = {args} end if 
  if atom( types ) then types = {types} end if 
 
  if length( args ) != length( types ) then 
    crash( "euSerialPrintf: args and types must be the same length! %d != %d\n", {length(args),length(types)} ) 
  end if 
 
  integer serialPrintf = link_c_proc(dll_ptr, "serialPrintf", {C_INT, C_POINTER} & types) 
 
  -- ...perform caching here... 
 
  c_proc(serialPrintf, {fd, allocate_string(fmt,1)} & args) 
 
end procedure 
 
petelomax said...

I was thinking that too. Then it dawned on me, there is a far simpler way:

serialPrintf = link_c_proc(dll_ptr, "serialPrintf", {C_INT, C_POINTER}) 
procedure euSerialPrintf(integer fd, sequence fmt, object args) 
 
  c_proc(serialPrintf, {fd, allocate_string(sprintf(fmt,args),1)}) 
 
end procedure 

While this method certainly works, it is only applicable in this situations. Other variadic functions may not be so convenient. getlost

-Greg

new topic     » goto parent     » topic index » view message » categorize

9. Re: wrapping C functions

petelomax said...
SDPringle said...

That's a little risky

I was thinking that too. Then it dawned on me, there is a far simpler way:

serialPrintf = link_c_proc(dll_ptr, "serialPrintf", {C_INT, C_POINTER}) 
procedure euSerialPrintf(integer fd, sequence fmt, object args) 
 
  c_proc(serialPrintf, {fd, allocate_string(sprintf(fmt,args),1)}) 
 
end procedure 

Pete

thanks, that looks good and will work for this case. i'll "steal" it and make the changes to the includes.

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu