[From nobody Mon Mar 25 16:13:24 2013
Return-Path: &lt;voudheus@imec.be&gt;
Received: from imec.be ([146.103.12.193]) by trinidad.imec.be
 (Netscape Messaging Server 3.6)  with ESMTP id AAA73D2
 for &lt;voudheus@imec.be&gt;; Wed, 27 Jun 2001 22:13:48 +0200
Sender: voudheus@imec.be
Message-ID: &lt;3B3A3E7E.35DF4CF8@imec.be&gt;
Date: Wed, 27 Jun 2001 22:13:50 +0200
From: Van Oudheusden &lt;voudheus@imec.be&gt;
X-Mailer: Mozilla 4.75 [en] (X11; U; Linux 2.2.16-22smp i686)
X-Accept-Language: en
MIME-Version: 1.0
To: voudheus@imec.be
Subject: (no subject)
Content-Type: multipart/mixed; boundary=&quot;------------23A8298C4DE93C4D8808C8A3&quot;

This is a multi-part message in MIME format.
--------------23A8298C4DE93C4D8808C8A3
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit



--------------23A8298C4DE93C4D8808C8A3
Content-Type: text/plain; charset=us-ascii;
 name=&quot;easiest_drv.c&quot;
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename=&quot;easiest_drv.c&quot;

#include &lt;stdio.h&gt;
#include &quot;erl_driver.h&quot;

/*-------------------------------------------------------------------------------------*/
/* Global variable (not accessible from outside this file: */
/*-------------------------------------------------------------------------------------*/
static ErlDrvPort  erlang_port;

/*-------------------------------------------------------------------------------------*/
/* Interface routines. These are the CALLBACK routines for the Erlang run-time system. */
/*-------------------------------------------------------------------------------------*/

static int        easy_init(void);
static ErlDrvData easy_start(ErlDrvPort port, char *buff);
static void       easy_stop(ErlDrvData handle);
static void       easy_command(ErlDrvData handle, char *buff, int bufflen);
// static void       easy_input(ErlDrvData handle, ErlDrvEvent event);
// static void       easy_output(ErlDrvData handle, ErlDrvEvent event);
// static void       easy_finish(void);
// static int        easy_control(ErlDrvData handle, unsigned int command, 
//			       char* buf, int count, char** res, int res_size);


/*------------------*/
/* The Driver entry */
/*------------------*/

static ErlDrvEntry easy_driver_entry = {
  NULL,                      /* init, called at system start-up for statically linked drivers or after 
			        loading (by invoking 'erl_ddll: load_driver') for dynamically loaded
			        drivers. */
  easy_start,                /* start,  called when port is opened. This routine should set up
			        internal data structures and return an opaque data entity of the
			        type 'ErlDrvData'. The pointer returned by this routine is the
			        first argument used in all other callbacks (concerning this particular
			        port). Usually this pointer refers to a structure holding information
			        about the particular port: it is a port handle. */ 
  easy_stop,                 /* stop,   called when port is closed. This is either accomplished by
			        an Erlang process or by this driver calling one of the 
				'driver_failure_XXX' routines. This routine should clean up everything
			        that is connected to the associated port (of this driver). */
  easy_command,              /* output, called when Erlang process sends data to the port.
			        The data arrives as a buffer of bytes, the interpretation is not defined
			        and is up to the implementor. This callback returns nothing to the caller,
			        answers are sent to the caller as messages (using the 'driver_output'
				routine) */
  NULL,    
  /*  easy_input, */         /* ready_input, called when the emulator detects input on a file descriptor
				which the driver has marked for monitoring (by using the interface
				'driver_select'). The typical scenario is that 'driver_select' is called
				when an Erlang process orders a read operation, and that this routine
				sends the answer when data is available on the file descriptor. */
  NULL,
  /* easy_output, */         /* ready_output, called when the emulator detects output on a file descriptor.
				The typical scenario is that Erlang orders writing on a file descriptor
				and that the driver calls 'driver_select'. When the descriptor is ready
				for output, this callback is called and the driver can try to send the
				output. */
  &quot;easiest_drv&quot;,                /* char *driver_name, the argument that is used to open the port. */
  NULL,
  /*  easy_finish, */        /* finish, called when the whole driver is unloaded. Every RESOURCE allocated
				by the driver should be freed. (Thus also allocated memory!) */
  NULL,                      /* void * that is not used (backwards compatibility) */
  NULL,
  /*  easy_control, */       /* control, invoked when an Erlang process calls 'erlang:driver_control/2' 
				which is a synchronous interface to drivers. The control interface is used
				to set driver options, change states of ports etc. */
  NULL,                      /* timeout, invoked when a timer expires. The driver can set timers with the
				function 'driver_set_timer'. When such a timer expires, a specific 
				callback function is called. */
  NULL                       /* outputv, vector output interface */
};


/* ---------------------------------------------------------------------*/
/* Called by 'erl_ddll' when loading this driver.
/* ---------------------------------------------------------------------*/
DRIVER_INIT(easiest_drv)
{
  return &amp;easy_driver_entry;
}

/* ---------------------------------------------------------------------*/
/* This is called when an Erlang process opens the port: 
   'open_port({spawn, &quot;easy_drv&quot;}, [])' 
pre:
port:  The port ID number that is used for communication between the
       Erlang run-time system and this C file.
buff:  A null terminated string which consists of the additional 
       args (arguments) that can be passed to this driver.
post:
The handle to the port of this driver is returned. A handle has to be
a pointer to some kind of data structure! (ErlDrvData is a pointer
to a structure: see 'erl_driver.h')
*/
/* ---------------------------------------------------------------------*/
static ErlDrvData easy_start(ErlDrvPort port, char *buff)
{
if (erlang_port != (ErlDrvPort) -1)
  return((ErlDrvData) -1);

fprintf(stderr,&quot;Easy driver started with args %s\n&quot;,buff);
erlang_port = port;
return((ErlDrvData)port);
}


/* --------------------------------------------------------------------- */
/* This is called when Erlang wants to send output to the port (of this driver).
pre:
handle:   The handle of the port of this linked in driver.
buff:     A null terminated string containing the output data.
bufflen:  The length of buff.
post:
Send the data back to where it came from.
*/
/* ---------------------------------------------------------------------*/
static void easy_command(ErlDrvData handle, char *buff, int bufflen)
// long port;
// char *buf;
// int count;
{
  /* Send the data back to where it came from: */
  driver_output((ErlDrvPort)handle, buff, bufflen);
  /* Remark:  'driver_output_binary' exists as well! */
}

/* ---------------------------------------------------------------------*/
/* This is called when Erlang wants to close the port and when the system
shuts down.
pre: _
post:
Set the Erlang port to -1.
*/
/* ---------------------------------------------------------------------*/
static void easy_stop(ErlDrvData handle)
{
  erlang_port = (ErlDrvPort) -1;
}
     







/* ---------------------------------------------------------------------*/
/* ---------------------------------------------------------------------*/
/* ---------------------------------------------------------------------*/
/* The following command is needed (in the console) to compile this file:
gcc -fPIC -c -I/mnt/hda2/kvo7B-1/otp_src_R7B-1/erts/emulator/beam easiest_drv.c ld -G -t easiest_drv.o -o easiest_drv.so
*/
/* 'static' means the associated function is only useable inside the file
   in which it is defined. 'external' (used in a header file) 
   makes a function globally accessible but this is only possible if it 
   is not made 'static'. */
/* ---------------------------------------------------------------------*/

--------------23A8298C4DE93C4D8808C8A3
Content-Type: text/plain; charset=us-ascii;
 name=&quot;erlToeasiest.erl&quot;
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename=&quot;erlToeasiest.erl&quot;

-module(erlToeasiest).
-export([start/0, communicate/2]).

%% ---------------------------------------------------
%% This is an example of communicating (via a port) with a linked in driver
%% which is written in C.  The C file is called 'easiest_drv.c'.
%% ---------------------------------------------------


start() -&gt;
	erl_ddll:load_driver(&quot;.&quot;, &quot;easiest_drv&quot;),
	% erl_ddll:load_driver(&quot;./&quot;, &quot;easiest_drv&quot;),
	io:format('------ ~n'),
	Port = open_port({spawn, &quot;./easiest_drv.so&quot;}, []),	
	% Port = open_port({spawn, &quot;./easiest_drv&quot;}, []),
	communicate(Port, &quot;kvoBoe&quot;).
	%communicate(Port, [2,3,1]).

communicate(Port, Key) -&gt;
	send(Port, Key),
	get_response(Port).

%% --------------------------------------------------------------------------

send(Port, Data) -&gt;
	Port ! {self(), {command, Data}}.
	

get_response(Port) -&gt;
	receive
		{Port, {data,[$l|Data]}} -&gt; 
			io:format('1 erlang received data: ~w~n', [Data]);
		{Port, {data,[$m|Data]}} -&gt;
			io:format('2 erlang received data: ~w~n', [Data]);
		{Port, {data, Data}} -&gt;
			io:format('3 erlang received data: ~w~n', [Data]),
			get_response(Port);
		{Port, Any} -&gt;
			io:format('4 erlang received Any data: ~w~n', [Any]),
			get_response(Port);
		{'EXIT', Port, Reason} -&gt;
			exit({'erlToeasiest.erl: ddll_drv port died', Reason})
	after 2000 -&gt;
		stop(Port),
		io:format('erlToeasiest.erl: Ending linked in driver communication. ~n')
	end.


stop(Port) -&gt;
	Port ! {self(), close},
	receive
		{Port, closed} -&gt; true
	end.

--------------23A8298C4DE93C4D8808C8A3--

]