For pre-R15 versions of Erlang you should typedef both the ErlDrvSizeT and ErlDrvSSizeT types to int, rather than the size_t and ssize_t typedefs you currently have.<div><br></div><div>Another problem with your code is that the return value of the control function should be the size of the binary you're returning. If you want port_call to throw a badarg, just return a value less than 0. For success your final return value should be index+1, which is the length of the encoded binary, not index.</div>
<div><br></div><div>--steve</div><div><br></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Nov 26, 2012 at 12:25 PM, Brisa Jiménez <span dir="ltr"><<a href="mailto:brisa.jimenez.f@gmail.com" target="_blank">brisa.jimenez.f@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi everyone!<div><br></div><div>I have doubts about port_call and driver_init structure in a port driver.</div><div><br>
</div><div>This way I open the port:</div><div>Port = open_port({spawn, ?C_LIBRARY}, [binary]),</div><div>
<br></div><div>Erlang function:</div><div><div>foz(Arg)-></div><div>    call_port({1, Arg}).</div></div><div><br></div><div>C function:</div><div><div>double foz(double x) {</div><div><span style="white-space:pre-wrap">        </span>return x/1.0;</div>

<div>}</div></div><div><br></div><div>I use next BIF to port calls:</div><div>erlang:port_call(Port, Command, encode(Data)),</div><div>where Command is an integer and Data is a float for example...</div><div><br></div><div>

And for encode:</div><div><div>encode(Msg)-></div><div>    term_to_binary(Msg).</div></div><div><br></div><div>This is my driver structure:</div><div><div>ErlDrvEntry driver_entry = {</div><div>    NULL,<span style="white-space:pre-wrap">               </span>// called at system start up for statically</div>

<div>                // linked drivers, and after loading for</div><div>                // dynamically loaded drivers</div><div>    start,</div><div>    stop,<span style="white-space:pre-wrap">             </span>// called when port is closed, and when the emulator is halted.</div>

<div>    NULL,<span style="white-space:pre-wrap">         </span>//called when we have output from erlang to the port</div><div>    NULL,<span style="white-space:pre-wrap">            </span>//ready_input - called when we have input from one of the driver's handles</div>

<div>    NULL,<span style="white-space:pre-wrap">         </span>//ready_output - called when output is possible to one of the driver's handles</div><div>    "library",<span style="white-space:pre-wrap">               </span>//driver_name - name supplied as command in open_port XXX ?</div>

<div>    NULL,<span style="white-space:pre-wrap">         </span>// finish - called before unloading the driver -</div><div>                // DYNAMIC DRIVERS ONLY</div><div>    NULL,<span style="white-space:pre-wrap">          </span>//handle - Reserved -- Used by emulator internally</div>

<div>    NULL,<span style="white-space:pre-wrap">         </span>// control - "ioctl" for drivers - invoked by port_control/3</div><div>    NULL,<span style="white-space:pre-wrap">          </span>//timeout - Handling of timeout in driver</div>

<div>    NULL,<span style="white-space:pre-wrap">         </span>//outputv - called when we have output from erlang to the port</div><div>    NULL,<span style="white-space:pre-wrap">          </span>// ready_async - called when the port is about to be </div>

<div>                // closed, and there is data in the </div><div>                // driver queue that needs to be flushed</div><div>                // before 'stop' can be called</div><div>    call, // call - Works mostly like 'control', a synchronous call into the driver.</div>

<div>    NULL,<span style="white-space:pre-wrap">         </span>// event - Called when an event selected by driver_event() has occurred</div><div><span style="white-space:pre-wrap">  </span>.extended_marker = ERL_DRV_EXTENDED_MARKER,</div>

<div><span style="white-space:pre-wrap">  </span>.major_version = ERL_DRV_EXTENDED_MAJOR_VERSION,</div><div><span style="white-space:pre-wrap"> </span>.minor_version = ERL_DRV_EXTENDED_MINOR_VERSION,    </div>
<div>    0,<span style="white-space:pre-wrap">            </span>// ERL_DRV_FLAGs</div><div>    NULL,<span style="white-space:pre-wrap">                </span>// handle2 - Reserved -- Used by emulator internally</div>
<div>    NULL,<span style="white-space:pre-wrap">         </span>// process_exit - Called when a process monitor fires</div><div>    NULL,<span style="white-space:pre-wrap">           </span>// stop_select - Called to close an event object</div>

<div> };</div></div><div><br></div><div>And my call function:</div><div><div>ErlDrvSSizeT call(ErlDrvData handle, unsigned int command,</div><div>char *buf, ErlDrvSizeT len,</div><div>char **rbuf, ErlDrvSizeT rlen, unsigned int *flags)</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)) return (ErlDrvSSizeT)1;</div>

<div>    if (ei_decode_double(buf, &index, &arg)) return (ErlDrvSSizeT)2;</div><div>    </div><div>    switch (command) {</div><div>        case 1:</div><div>            res = foz(arg);</div><div>            break;</div>

<div>        case 2:</div><div>            res = baz(arg);</div><div>            break;</div><div>        default:</div><div>            return (ErlDrvSSizeT)3;</div><div>    }</div><div>    index = 0;</div><div>    if (ei_encode_version(*rbuf, &index) ||</div>

<div>    ei_encode_double(*rbuf, &index, res)) return (ErlDrvSSizeT)4;</div><div>    return (ErlDrvSSizeT)index;</div><div><br></div><div>}</div></div><div><br></div><div>My erlang version is:</div><div>Erlang R14B03 (erts-5.8.4)</div>

<div><br></div><div>My erts version doesn't have ErlDrvSizeT and ErlDrvSSizeT types, so, I include these types in my port_driver.c file:</div><div><div>typedef size_t ErlDrvSizeT;</div><div>typedef ssize_t ErlDrvSSizeT;</div>

</div><div><br></div><div>When I compile code the next warning is showed:</div><div><div>c_src/port_driver.c:78:5: warning: initialization from incompatible pointer type [enabled by default]</div><div>c_src/port_driver.c:78:5: warning: (near initialization for ‘driver_entry.flush’) [enabled by default]</div>

</div><div><br></div><div>78 line refers to call in driver_entry structure.</div><div><br></div><div>If I ignore the warning happens the next:</div><div><div>1> erl_drv:start().</div><div><0.34.0></div><div>2> erl_drv:foz(4.0).</div>

<div><br></div><div>=ERROR REPORT==== 26-Nov-2012::11:13:45 ===</div><div>Error in process <0.34.0> with exit value: {badarg,[{erlang,port_call,[erl_port,1,<<33 bytes>>]},{erl_drv,loop,1}]}</div></div><div>

<br></div><div>I couldn't change the erlang version, and I read that terms send to c call function are decoded and encoded with ei library.</div><div><br></div><div>Does anybody give me an advice?</div><div><br></div>

<div>Thank you very much.</div>
<br>_______________________________________________<br>
erlang-questions mailing list<br>
<a href="mailto:erlang-questions@erlang.org">erlang-questions@erlang.org</a><br>
<a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
<br></blockquote></div><br></div>