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*