I have a similar task, read/write to a MODBUS fieldbus (RS485).
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
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
Hope this may help.