diff --git a/README.md b/README.md index 427a11c..fe440ff 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,8 @@ For a safer, portable native interface, see cereal: ## USAGE -/serctl/ is the interface to the native system C libraries and follows -the system C interface. See tcgetattr(3), tcsetattr(3), cfsetispeed(3) -and cfsetospeed(3) for details. +_serctl_ is the interface to the native system C libraries and follows +the system C interface. serctl:open(Path) -> {ok, FD} | {error, posix()} @@ -57,7 +56,16 @@ and cfsetospeed(3) for details. Write data to the serial device. -The low level interface to the C library: +The low level interface follows the C library (see tcgetattr(3), +tcsetattr(3), cfsetispeed(3) and cfsetospeed(3) for details). For +convenience, atoms may be used in places where C has defined macros for +integers and Erlang records can be used as arguments instead of binaries. + +To use Erlang records to represent the C struct termios (e.g., when +converting binaries using serctl:termios/1) include their definition: + + -include("serctl.hrl"). + serctl:tcgetattr(FD) -> {ok, Termios} | {error, posix()} @@ -67,22 +75,25 @@ The low level interface to the C library: Get the terminal attributes of the serial device. Returns the contents of the system struct termios as a binary. - serctl:tcsetattr(FD, Termios) -> ok | {error, posix()} + serctl:tcsetattr(FD, Action, Termios) -> ok | {error, posix()} Types FD = resource() - Termios = binary() + Action = integer() | Option | Options + Options = [Option] + Option = tcsanow | tcsadrain | tcsaflush + Termios = binary() | #termios{} Sets the terminal attributes of the serial device. - /Warning: the contents of Termios are passed directly to + _Warning: the contents of Termios are passed directly to tcsettr(3). If the system tcsettr(3) does not check if the structure is valid, it may cause the library to crash, causing - the Erlang VM to crash./ + the Erlang VM to crash._ serctl:cfsetispeed(Termios, Speed) -> {ok, Termios1} | {error, posix()} - Types Termios = binary() - Speed = integer() + Types Termios = binary() | #termios{} + Speed = integer() | atom() Termios1 = binary() Set the input speed of the serial device. See the warning for @@ -90,8 +101,8 @@ The low level interface to the C library: serctl:cfsetospeed(Termios, Speed) -> {ok, Termios1} | {error, posix()} - Types Termios = binary() - Speed = integer() + Types Termios = binary() | #termios{} + Speed = integer() | atom() Termios1 = binary() Set the input speed of the serial device. See the warning for @@ -107,7 +118,7 @@ The low level interface to the C library: serctl:constant() -> Constants serctl:constant(Attr) -> integer() - Types Constants = [{Attr, integer()}|...] + Types Constants = [{Attr, integer()}] Attr = tcsaflush | tcsadrain | tcsanow | tcioflush | tcoflush | tciflush | tcion | tcioff | tcoon | tcooff | iexten | tostop | noflsh | echonl | echoke | echok | echoe | echo | icanon | isig | crtscts | b1152000 | @@ -128,8 +139,6 @@ The low level interface to the C library: serctl has a higher level interface that takes care of portability and represents the C data structures as Erlang records: - -include("serctl.hrl"). - serctl:speed(FD, Speed) -> ok | {error, posix()} diff --git a/c_src/serctl.c b/c_src/serctl.c index e562dc4..49583ee 100644 --- a/c_src/serctl.c +++ b/c_src/serctl.c @@ -340,9 +340,9 @@ static ErlNifFunc nif_funcs[] = { {"read", 2, nif_read}, {"write", 2, nif_write}, {"tcgetattr", 1, nif_tcgetattr}, - {"tcsetattr", 3, nif_tcsetattr}, - {"cfsetispeed", 2, nif_cfsetispeed}, - {"cfsetospeed", 2, nif_cfsetospeed}, + {"tcsetattr_nif", 3, nif_tcsetattr}, + {"cfsetispeed_nif", 2, nif_cfsetispeed}, + {"cfsetospeed_nif", 2, nif_cfsetospeed}, {"getfd", 1, nif_getfd}, {"constant", 0, nif_constants}, diff --git a/src/serctl.erl b/src/serctl.erl index a464f3a..7536a29 100644 --- a/src/serctl.erl +++ b/src/serctl.erl @@ -94,13 +94,37 @@ write(_,_) -> tcgetattr(_) -> erlang:error(not_implemented). -tcsetattr(_,_,_) -> +tcsetattr(FD, Action, Termios) when is_list(Action) -> + Option = lists:foldl(fun(X,N) -> constant(X) bxor N end, 0, Action), + tcsetattr(FD, Option, Termios); +tcsetattr(FD, Action, Termios) when is_atom(Action) -> + tcsetattr(FD, constant(Action), Termios); +tcsetattr(FD, Action, #termios{} = Termios) -> + tcsetattr(FD, Action, termios(Termios)); +tcsetattr(FD, Action, Termios) -> + tcsetattr_nif(FD, Action, Termios). + +tcsetattr_nif(_,_,_) -> erlang:error(not_implemented). -cfsetispeed(_,_) -> +cfsetispeed(#termios{} = Termios, Speed) -> + cfsetispeed(termios(Termios), Speed); +cfsetispeed(Termios, Speed) when is_atom(Speed) -> + cfsetispeed(termios(Termios), constant(Speed)); +cfsetispeed(Termios, Speed) -> + cfsetispeed_nif(Termios, Speed). + +cfsetispeed_nif(_,_) -> erlang:error(not_implemented). -cfsetospeed(_,_) -> +cfsetospeed(#termios{} = Termios, Speed) -> + cfsetospeed(termios(Termios), Speed); +cfsetospeed(Termios, Speed) when is_atom(Speed) -> + cfsetospeed(termios(Termios), constant(Speed)); +cfsetospeed(Termios, Speed) -> + cfsetospeed_nif(Termios, Speed). + +cfsetospeed_nif(_,_) -> erlang:error(not_implemented). constant() ->