[erlang-questions] Generating skeleton linked-in driver code using an IDL?

Jani Hakala jahakala@REDACTED
Thu Mar 5 20:34:57 CET 2009


I have written a small linked-in driver that fortunately has only a
few different kind of messages passing between erlang code and driver
(driver_entry outputv, ready_input+driver_output_binary). It also
handles several operations issued by port_control() (decoding of data
using ei_decode_*). A big portion of the code is related to decoding
and encoding of the data although the messages are quite simple.

I have looked at some of the code generation tools that are supposed
to help developing linked-in drivers. They (ETDK, DryvErl and the
proposed Foreign Function Interface) seem to focus on how to call
C-functions. I would be more interested about a tool that could be
used to define message structures and operations supported by a
linked-in driver. Those operations would call C/C++ functions in a way
that would not be visible outside the driver (facade pattern).

An IDL compiler is included in OTP so I wrote a CORBA IDL file that
could be a starting point for a new version of my linked-in driver (or
C node perhaps) if it was possible to generate 
  1) C/C++ code that could be used to (de)serialize the messages,
  2) C/C++ skeleton files for the driver,
  3) Erlang code that would (de)serialize messages using CDR encoding or
     erlang external format (or other solution), and
  4) Erlang skeleton files for the process that owns the port.

1) could be implemented using ei_decode/ei_encode functions.
In the case of port_command (3) might be just call to term_to_binary
after some sanity checks for the parameters. Most of the checking
could be delayed until the C-code deserializes the data.

ic - the erlang IDL compiler - generates several files that might be
useful if a tool supporting this kind of scheme was developed or if ic
was modified: 
  - The output files include type codes that describe the data
    structures (:tc/0) and operations (:oe_get_interface/0). 
  - Record definitions are also available for each defined structure
    and exception.
  - The names, in/inout/out information of the parameters are
    unfortunately not readily available (not without changing ic?). 
  - No oneway-information for operations either.

Here is the IDL file (which is nowhere close to being complete) 
I wrote
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: CAN.idl
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20090305/2102b345/attachment.ksh>
-------------- next part --------------

and some sort of use cases:
-------------- next part --------------
- PortOwner is a C++ class in the following use cases.

- In the case of C:
  can->port_owner->xxx(can, ...) instead of this->port_owner->xxx(...)

- oneway calls: handled by erl_drv_entry->output()
   (sort of gen_server:cast)
- twoway calls: handled by erl_drv_entry->control()
   (sort of gen_server:call)

- 'magic' is here something that the programmer should not need to care
   about 

erlang -> driver
 Port = can_driver:init(...) 
  - CAN and PortOwner instances created on C/C++ side
    CAN::init(...) 
    {
       /* Start a thread for incoming messages */
       /* call driver_select to register */
    }

 {ok, {CAN_Ref}} = can_driver:open(Port, "CAN0") 
 -> some erlang code and 'magic' in erl_drv_entry->control()
 -> CAN::open(const char * ifc, CAN_Ref_out ifc_ref)
     {
      CAN_Interface * interface = new CAN_Interface(ifc);
      CAN_Ref ifc_ref_(ifc);
      this->register(ifc_ref_, interface);
      ifc_ref = ifc_ref_;
     }
      /* Raising exception: port_owner->error() or throw */
 -> 'magic'
 -> {ok, {CAN_Ref}}

 ok = can_driver:send_message(Port, CAN_Ref, 1, false, [1, 2, 3])
 -> 'magic'
 -> CAN::send_message(CAN_Ref ifc_ref,
                      uint32_t arbitration_id,
		      bool remote,
		      const OctetSeq & bytes)
    {?/* C++ code */ }
 -> 'magic'
 -> ok		(if no errors)

driver -> erlang
  void ready_input(ErlDrvData drv_data, ErlDrvEvent event)
  {
    CAN_ptr can(CAN_OBJECT(drv_data));
     /* obtain CAN_Ref_out ifc_ref and Message_out msg somehow 
      * (e.g. from a queue) 
      */
    can->port_owner->on_message(ifc_ref, msg);
  }
  -> 'magic'
  -> can_driver:on_message(MyData, {CAN_Ref, Message})
       ... user defined erlang code
-------------- next part --------------

Jani Hakala


More information about the erlang-questions mailing list