caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Unix library and serial port
@ 2014-08-13  7:23 Edouard Evangelisti
  2014-08-13 10:39 ` Paolo Donadeo
  2014-08-13 11:22 ` Anders Fugmann
  0 siblings, 2 replies; 3+ messages in thread
From: Edouard Evangelisti @ 2014-08-13  7:23 UTC (permalink / raw)
  To: caml-list

Dear all,

I encountered a problem while trying to exchange informations with a ZStepper
Motor connected to the computer through a serial/USB adapter. I can send
commands and move the motor, but I cannot retrieve the informations which are
sent by the motor directly after completion. For this I am using the Unix
library as follows.

First of all, I get a read/write file descriptor :

let usb0 = "/dev/ttyUSB0"
let flags = Unix.([O_RDWR; O_NOCTTY; O_NONBLOCK])
let perm = 0o666
let fd = Unix.openfile usb0 flags perm

I then set the parameters using Unix.tcgetattr/Unix.tcsetattr (for instance
baud and parity check). Most of the default values are fine. Then I am able to
send commands :

let write_serial () =
 let cmd = "/2P1000R\r\n" in (* one command as  an example. *)
 let len = String.length cmd in
 let ret = Unix.write fd cmd 0 len in
 assert (ret = len); (* not the real code here for error management *)
 Unix.tcdrain fd

The call to write_serial triggers ZStepper motion as expected. Then, the motor
send back some data. I have tried to read them using :

let read_serial () =
   let len = 10 in
   let buf = Buffer.create len in
   let str = String.create len in
   let rec loop () =
   let n = Unix.read fd str 0 len in
   if n > 0 then (
     Buffer.add_substring buf str 0 n;
     loop ()
   ) else Buffer.output_buffer stdout buf in
   try loop () with Unix.Unix_error (Unix.EAGAIN, _, _) -> ()

I always got EAGAIN error and no data available. When using
Unix.in_channel_of_descr, I can retrieve some data but asynchronously.

I have tried to launch simultaneously my program and GtkTerm configured with
the same settings and GtkTerm is able to retrieve the informations sent by the
motor after completion. The source code of GtkTerm looks very similar to mine.
I probably do something wrong but I cannot see where is the problem.

Would you have an idea ?

Many thanks in advance for your precious help.









^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Caml-list] Unix library and serial port
  2014-08-13  7:23 [Caml-list] Unix library and serial port Edouard Evangelisti
@ 2014-08-13 10:39 ` Paolo Donadeo
  2014-08-13 11:22 ` Anders Fugmann
  1 sibling, 0 replies; 3+ messages in thread
From: Paolo Donadeo @ 2014-08-13 10:39 UTC (permalink / raw)
  To: Edouard Evangelisti; +Cc: OCaml mailing list

[-- Attachment #1: Type: text/plain, Size: 2617 bytes --]

I have a similar task, read/write to a MODBUS fieldbus (RS485).

I can successfully read with this function:

*let rec really_read ?(timeout = 0.5) fd buffer start length =*
*  let open Unix in*
*  if length <= 0 then () else begin*
*    match Unix.select [ fd ] [] [] timeout with*
*    | [], [], [] -> raise (Timeout timeout)*
*    | fdl, _, _ -> begin*
*        match read fd buffer start length with*
*        | 0 -> raise End_of_file*
*        | r -> really_read fd buffer (start + r) (length - r)*
*      end*
*  end*

The code in which I use *really_read* looks like this:

*  Unix.write ctx.descriptor packet 0 packet_len |> ignore;*
*  let buffer = String.make 2048 (Char.chr 0) in*
*  let timeout = 1.0 in*
*  let expected_bytes = 13 in*
*  really_read ~timeout ctx.descriptor buffer 0 expected_bytes;*

Before reading/writing I set a bunch of terminal variables:

*let modbus_connect device_name baud csize parity cstopb =*
*  let open Unix in*
*  let descriptor = openfile device_name [ O_RDWR; O_NOCTTY; O_NONBLOCK;
O_EXCL; O_CLOEXEC; ] 0o660 in*
*  let old_terminal_settings = tcgetattr descriptor in*
*  let slave_id = None in*
*  let ctx = { device_name; baud; parity; csize; cstopb; descriptor;
old_terminal_settings; slave_id; } in*

*  let term_settings = tcgetattr descriptor in*
*  term_settings.c_obaud <- baud;*
*  term_settings.c_ibaud <- baud;*
*  term_settings.c_cread <- true;*
*  term_settings.c_clocal <- true;*
*  term_settings.c_csize <- csize;*
*  term_settings.c_cstopb <- cstopb;*
*  let () = match parity with*
*    | Parity_None -> begin*
*        term_settings.c_inpck <- false;*
*        term_settings.c_parenb <- false;*
*        term_settings.c_parodd <- false;*
*      end*
*    | Parity_Even -> begin*
*        term_settings.c_inpck <- true;*
*        term_settings.c_parenb <- true;*
*        term_settings.c_parodd <- false;*
*      end*
*    | Parity_Odd -> begin*
*        term_settings.c_inpck <- true;*
*        term_settings.c_parenb <- true;*
*        term_settings.c_parodd <- true;*
*      end in*
*  term_settings.c_icanon <- false;*
*  term_settings.c_echo   <- false;*
*  term_settings.c_echoe  <- false;*
*  term_settings.c_echok  <- false;*
*  term_settings.c_echonl <- false;*
*  term_settings.c_isig   <- false;*
*  term_settings.c_ixon   <- false;*
*  term_settings.c_ixoff  <- false;*
*  term_settings.c_opost  <- false;*
*  term_settings.c_vmin   <- 0;*
*  term_settings.c_vtime  <- 0;*

*  let () = tcsetattr descriptor TCSANOW term_settings in*
*  ctx*

*ctx* is a type in which I keep the context for the connection.

Hope this may help.


-- 
*Paolo*

[-- Attachment #2: Type: text/html, Size: 6843 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Caml-list] Unix library and serial port
  2014-08-13  7:23 [Caml-list] Unix library and serial port Edouard Evangelisti
  2014-08-13 10:39 ` Paolo Donadeo
@ 2014-08-13 11:22 ` Anders Fugmann
  1 sibling, 0 replies; 3+ messages in thread
From: Anders Fugmann @ 2014-08-13 11:22 UTC (permalink / raw)
  To: Edouard Evangelisti, caml-list

Hi Edouard,

Setting the nonblock flag on the socket specifies exactly that calls 
will never wait but raise EGAGIN when no data is available. That is - no 
operations on the socket will ever block.

I would advice you to not open using the O_NONBLOCK flag, and instead
read exactly the amount of bytes you expect. If, for example, the motor 
returns data ending with newlines, I would read one char at a time until 
the terminating char is encountered and then parse the message received.

Another solution is to poll for data and then sleep a bit when EAGAIN is 
raised. Or even use select.

/Anders

On 08/13/2014 09:23 AM, Edouard Evangelisti wrote:
> Dear all,
>
> I encountered a problem while trying to exchange informations with a ZStepper
> Motor connected to the computer through a serial/USB adapter. I can send
> commands and move the motor, but I cannot retrieve the informations which are
> sent by the motor directly after completion. For this I am using the Unix
> library as follows.
>
> First of all, I get a read/write file descriptor :
>
> let usb0 = "/dev/ttyUSB0"
> let flags = Unix.([O_RDWR; O_NOCTTY; O_NONBLOCK])
> let perm = 0o666
> let fd = Unix.openfile usb0 flags perm
>
> I then set the parameters using Unix.tcgetattr/Unix.tcsetattr (for instance
> baud and parity check). Most of the default values are fine. Then I am able to
> send commands :
>
> let write_serial () =
>   let cmd = "/2P1000R\r\n" in (* one command as  an example. *)
>   let len = String.length cmd in
>   let ret = Unix.write fd cmd 0 len in
>   assert (ret = len); (* not the real code here for error management *)
>   Unix.tcdrain fd
>
> The call to write_serial triggers ZStepper motion as expected. Then, the motor
> send back some data. I have tried to read them using :
>
> let read_serial () =
>     let len = 10 in
>     let buf = Buffer.create len in
>     let str = String.create len in
>     let rec loop () =
>     let n = Unix.read fd str 0 len in
>     if n > 0 then (
>       Buffer.add_substring buf str 0 n;
>       loop ()
>     ) else Buffer.output_buffer stdout buf in
>     try loop () with Unix.Unix_error (Unix.EAGAIN, _, _) -> ()

>
> I always got EAGAIN error and no data available. When using
> Unix.in_channel_of_descr, I can retrieve some data but asynchronously.
>
> I have tried to launch simultaneously my program and GtkTerm configured with
> the same settings and GtkTerm is able to retrieve the informations sent by the
> motor after completion. The source code of GtkTerm looks very similar to mine.
> I probably do something wrong but I cannot see where is the problem.
>
> Would you have an idea ?
>
> Many thanks in advance for your precious help.
>
>
>
>
>
>
>
>
>


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2014-08-13 11:22 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-13  7:23 [Caml-list] Unix library and serial port Edouard Evangelisti
2014-08-13 10:39 ` Paolo Donadeo
2014-08-13 11:22 ` Anders Fugmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).