<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>