<div>Hi everyone!</div><div>I want to send and receive binary data through Erlang port, and use ei to encode and decode data, but when I try to test code below the next error occurs:</div><div><br><div>
<div>Erlang R14B03 (erts-5.8.4) [source] [rq:1] [async-threads:0] [kernel-poll:false]</div><div><br></div><div>Eshell V5.8.4 (abort with ^G)</div><div>1> erl_drv:start().</div><div>** exception exit: {error,"undefined symbol: ei_decode_version"}</div>
<div> in function erl_drv:start/0</div></div><div><br></div><div>Can anybody give me an example of how do it what I'm want?</div><div>I appreciate any advice.</div><div>Thanks.</div><div><br></div><div>===</div>
<div><br></div><div><div>-module(erl_drv).</div><div>-export([start/0, stop/0, init/1]).</div><div>-export([foz/1, baz/1]).</div><div>-define(C_LIBRARY, "library").</div>
<div><br></div><div>start() -></div><div> case erl_ddll:load_driver("priv", ?C_LIBRARY) of</div><div><span style="white-space:pre-wrap"> </span>ok -> ok;</div><div><span style="white-space:pre-wrap"> </span>{error, already_loaded} -> ok;</div>
<div><span style="white-space:pre-wrap"> </span>{error, Reason}-> exit({error, erl_ddll:format_error(Reason)})</div><div> end,</div><div> spawn(?MODULE, init, [?C_LIBRARY]).</div><div><br></div>
<div>init(?C_LIBRARY) -></div><div> register(erl_drv, self()),</div><div> Port = open_port({spawn, ?C_LIBRARY}, [binary]),</div><div> loop(Port).</div><div><br></div><div>stop() -></div><div> erl_drv ! stop.</div>
<div><br></div><div>foz(Arg)-></div><div> call_port({foz, Arg}).</div><div><br></div><div>baz(Arg)-></div><div> call_port({baz, Arg}).</div><div><br></div><div>call_port(Msg) -></div><div> erl_drv ! {call, self(), Msg},</div>
<div> receive</div><div> {erl_drv, Res} -></div><div><span style="white-space:pre-wrap"> </span> Res</div><div> end.</div><div><br></div><div>loop(Port) -></div><div> receive</div>
<div><span style="white-space:pre-wrap"> </span>{call, Caller, {Command, Data}}-></div><div><span style="white-space:pre-wrap"> </span> case Command of</div><div><span style="white-space:pre-wrap"> </span>foz-> port_control(Port, 3, encode(Data));</div>
<div><span style="white-space:pre-wrap"> </span>baz-> port_control(Port, 4, encode(Data))</div><div><span style="white-space:pre-wrap"> </span> end,</div><div><span style="white-space:pre-wrap"> </span> </div>
<div><span style="white-space:pre-wrap"> </span> receive</div><div><span style="white-space:pre-wrap"> </span> {Port, {data, Data}} -></div><div><span style="white-space:pre-wrap"> </span> Caller ! {erl_drv, decode(Data)}</div>
<div> <span style="white-space:pre-wrap"> </span> end,</div><div><span style="white-space:pre-wrap"> </span> loop(Port);</div><div> <span style="white-space:pre-wrap"> </span>stop -></div>
<div><span style="white-space:pre-wrap"> </span> Port ! {self(), close},</div><div><span style="white-space:pre-wrap"> </span> receive </div><div><span style="white-space:pre-wrap"> </span>{Port, closed} -></div>
<div><span style="white-space:pre-wrap"> </span> exit(normal)</div><div><span style="white-space:pre-wrap"> </span> end;</div><div> <span style="white-space:pre-wrap"> </span>{'EXIT', Port, Reason} -></div>
<div><span style="white-space:pre-wrap"> </span> io:format("~p ~n", [Reason]),</div><div><span style="white-space:pre-wrap"> </span> exit(port_terminated)</div><div> end.</div>
<div><br></div><div>encode(Msg)-></div><div> term_to_binary(Msg).</div><div><br></div><div>decode(RetVal)-></div><div> binary_to_term(RetVal).</div><div><br></div><div>===</div><div><br></div><div><div>/* port_driver.c*/</div>
</div><div><br></div><div><div>#include <stdio.h></div><div>#include "erl_driver.h"</div><div>#include "ei.h"</div><div>#include "erl_interface.h"</div><div><br></div><div>double foz(double);</div>
<div>double baz(double);</div><div><br></div><div>typedef size_t ErlDrvSizeT;</div><div>typedef ssize_t ErlDrvSSizeT;</div><div><br></div><div>typedef struct {</div><div> ErlDrvPort port;</div><div>} ptr_port;</div><div>
<br></div><div>static ErlDrvData start(ErlDrvPort port, char *buff)</div><div>{</div><div> ptr_port* ptr_port1 = (ptr_port*)driver_alloc(sizeof(ptr_port));</div><div> set_port_control_flags(port , PORT_CONTROL_FLAG_BINARY);</div>
<div> ptr_port1->port = port;</div><div> return (ErlDrvData)ptr_port1;</div><div>}</div><div><br></div><div>static void stop(ErlDrvData handle)</div><div>{</div><div> driver_free((char*)handle);</div><div>}</div>
<div><br></div><div>static ErlDrvSSizeT control(ErlDrvData handle, unsigned int command,</div><div> char *buf, ErlDrvSizeT len,</div><div><span style="white-space:pre-wrap"> </span>char **rbuf, ErlDrvSizeT rlen)</div>
<div>{</div><div><span style="white-space:pre-wrap"> </span>ptr_port *ptr_port1 = (ptr_port*)handle;</div><div> double arg, res;</div><div> int version, index = 0;</div><div><br></div><div> if (ei_decode_version(buf, &index, &version))</div>
<div> return((ErlDrvSSizeT) ERL_DRV_ERROR_GENERAL);</div><div> if (ei_decode_double(buf, &index, &arg))</div><div> return((ErlDrvSSizeT) ERL_DRV_ERROR_BADARG);</div><div> switch (command) {</div>
<div> case 3:</div><div> res = foz(arg);</div><div> break;</div><div> case 4:</div><div> res = baz(arg);</div><div> break;</div><div> default:</div><div> return((ErlDrvSSizeT) ERL_DRV_ERROR_BADARG);</div>
<div> }</div><div> index = 0;</div><div> if (ei_encode_version(*rbuf, &index)</div><div> || ei_encode_double(*rbuf, &index, res))</div><div> return((ErlDrvSSizeT) ERL_DRV_ERROR_ERRNO);</div>
<div> else</div><div> return((ErlDrvSSizeT) index);</div><div>}</div><div><br></div><div>ErlDrvEntry driver_entry = {</div><div> NULL,<span style="white-space:pre-wrap"> </span>//* F_PTR init, N/A </div>
<div> start,<span style="white-space:pre-wrap"> </span>//* L_PTR start, called when port is opened </div><div> stop,<span style="white-space:pre-wrap"> </span>//* F_PTR stop, called when port is closed </div>
<div><span style="white-space:pre-wrap"> </span>NULL,<span style="white-space:pre-wrap"> </span>//* F_PTR output, called when erlang has sent </div><div> NULL,<span style="white-space:pre-wrap"> </span>//* F_PTR ready_input, called when input descriptor ready </div>
<div> NULL,<span style="white-space:pre-wrap"> </span>//* F_PTR ready_output, called when output descriptor ready </div><div> "library",<span style="white-space:pre-wrap"> </span>//* char *driver_name, the argument to open_port </div>
<div> NULL,<span style="white-space:pre-wrap"> </span>//* F_PTR finish, called when unloaded </div><div> control,<span style="white-space:pre-wrap"> </span>//* F_PTR control, port_command callback </div>
<div> NULL,<span style="white-space:pre-wrap"> </span>//* F_PTR timeout, reserved </div><div> NULL<span style="white-space:pre-wrap"> </span>//* F_PTR outputv, reserved </div>
<div>};</div><div> </div><div>DRIVER_INIT(library) /* must match name in driver_entry */</div><div>{</div><div><span style="white-space:pre-wrap"> </span>return &driver_entry;</div><div>}</div></div>
<div><br></div><div>===</div><div><br></div><div><div>/*library.c*/</div><div><br></div><div>double foz(double x) {</div><div><span style="white-space:pre-wrap"> </span>return x/1.0;</div><div>}</div><div>
<br></div><div>double baz(double y) {</div><div><span style="white-space:pre-wrap"> </span>return y/2.0;</div><div>}</div></div><div><br></div><div>===</div><div><br></div><div><div># Makefile</div><div>
<br></div><div>ERL_ROOT=/usr/local/lib/erlang</div><div><br></div><div>all: compile_c compile</div><div><br></div><div>compile_c:</div><div><span style="white-space:pre-wrap"> </span>@mkdir -p priv</div>
<div><span style="white-space:pre-wrap"> </span>gcc -o priv/library.so -I$(ERL_ROOT)/usr/include/ -I$(ERL_ROOT)/lib/erl_interface-3.7.4/include/ -fpic -shared c_src/*.c </div><div><br></div><div>compile:</div>
<div><span style="white-space:pre-wrap"> </span>@mkdir -p ebin</div><div><span style="white-space:pre-wrap"> </span>erlc -o ebin/ src/erl_drv.erl</div><div><br></div><div>clean:</div><div>
<span style="white-space:pre-wrap"> </span>@rm -rf ebin priv</div><div><br></div><div>test:</div><div><span style="white-space:pre-wrap"> </span>erl -pa ebin/</div><div><span style="white-space:pre-wrap"> </span></div>
<div>.PHONY: c_src</div></div><div><br></div><div><br></div></div></div>