Skip to content

Instantly share code, notes, and snippets.

@msantos
Created September 22, 2011 15:28
Show Gist options
  • Save msantos/1235063 to your computer and use it in GitHub Desktop.
Save msantos/1235063 to your computer and use it in GitHub Desktop.
"Low level" Erlang serial interface
%% Copyright (c) 2011, Michael Santos <[email protected]>
%% All rights reserved.
%%
%% Redistribution and use in source and binary forms, with or without
%% modification, are permitted provided that the following conditions
%% are met:
%%
%% Redistributions of source code must retain the above copyright
%% notice, this list of conditions and the following disclaimer.
%%
%% Redistributions in binary form must reproduce the above copyright
%% notice, this list of conditions and the following disclaimer in the
%% documentation and/or other materials provided with the distribution.
%%
%% Neither the name of the author nor the names of its contributors
%% may be used to endorse or promote products derived from this software
%% without specific prior written permission.
%%
%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
%% "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
%% LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
%% FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
%% COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
%% INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
%% BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
%% LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
%% CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
%% LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
%% ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
%% POSSIBILITY OF SUCH DAMAGE.
-module(serctl).
-include("serctl.hrl").
-export([
open/1,
close/1,
read/2,
write/2,
tcgetattr/1,
tcsetattr/3,
cfsetispeed/2,
cfsetospeed/2,
termios/1, termios/2
]).
-export([
init/0
]).
-on_load(on_load/0).
%%--------------------------------------------------------------------
%%% NIF Stubs
%%--------------------------------------------------------------------
init() ->
on_load().
on_load() ->
erlang:load_nif(progname(), []).
open(_) ->
erlang:error(not_implemented).
close(_) ->
erlang:error(not_implemented).
read(_,_) ->
erlang:error(not_implemented).
write(_,_) ->
erlang:error(not_implemented).
tcgetattr(_) ->
erlang:error(not_implemented).
tcsetattr(_,_,_) ->
erlang:error(not_implemented).
cfsetispeed(_,_) ->
erlang:error(not_implemented).
cfsetospeed(_,_) ->
erlang:error(not_implemented).
%%--------------------------------------------------------------------
%%% API
%%--------------------------------------------------------------------
termios(Attr) ->
termios(os(), Attr).
termios(linux, <<
Iflag:?UINT32, % input mode flags
Oflag:?UINT32, % output mode flags
Cflag:?UINT32, % control mode flags
Lflag:?UINT32, % local mode flags
Line:8, % line discipline
Cc:?NCCS_LINUX/bytes, % control characters
Rest/binary>>) ->
Pad = pad(1+byte_size(Cc)),
<<
_:Pad,
Ispeed:?UINT32, % input speed
Ospeed:?UINT32 % output speed
>> = Rest,
#termios{
iflag = Iflag,
oflag = Oflag,
cflag = Cflag,
lflag = Lflag,
line = Line,
cc = Cc,
ispeed = Ispeed,
ospeed = Ospeed
};
termios(bsd, <<
Iflag:?UINT32, % input mode flags
Oflag:?UINT32, % output mode flags
Cflag:?UINT32, % control mode flags
Lflag:?UINT32, % local mode flags
Line:8, % line discipline
Cc:?NCCS_BSD/bytes, % control characters
Rest/binary
>>) ->
Pad = pad(1+byte_size(Cc)),
<<
_:Pad,
Ispeed:?UINT32, % input speed
Ospeed:?UINT32 % output speed
>> = Rest,
#termios{
iflag = Iflag,
oflag = Oflag,
cflag = Cflag,
lflag = Lflag,
line = Line,
cc = Cc,
ispeed = Ispeed,
ospeed = Ospeed
};
termios(linux, #termios{
iflag = Iflag,
oflag = Oflag,
cflag = Cflag,
lflag = Lflag,
line = Line,
cc = Cc,
ispeed = Ispeed,
ospeed = Ospeed
}) when byte_size(Cc) == ?NCCS_LINUX ->
Pad = pad(1+?NCCS_LINUX),
<<
Iflag:?UINT32BE,
Oflag:?UINT32BE,
Cflag:?UINT32BE,
Lflag:?UINT32BE,
Line:8,
Cc/bytes,
0:Pad,
Ispeed:?UINT32BE,
Ospeed:?UINT32BE
>>;
termios(bsd, #termios{
iflag = Iflag,
oflag = Oflag,
cflag = Cflag,
lflag = Lflag,
line = Line,
cc = Cc,
ispeed = Ispeed,
ospeed = Ospeed
}) when byte_size(Cc) == ?NCCS_BSD ->
Pad = pad(1+?NCCS_BSD),
<<
Iflag:?UINT32BE,
Oflag:?UINT32BE,
Cflag:?UINT32BE,
Lflag:?UINT32BE,
Line:8,
Cc/bytes,
0:Pad,
Ispeed:?UINT32BE,
Ospeed:?UINT32BE
>>.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
progname() ->
filename:join([
filename:dirname(code:which(?MODULE)),
"..",
"priv",
?MODULE
]).
os() ->
case os:type() of
{unix, linux} -> linux;
{unix, darwin} -> bsd;
{unix, freebsd} -> bsd;
{unix, netbsd} -> bsd;
{unix, openbsd} -> bsd
end.
% Returns pad size in *bits*
pad(N) ->
Size = erlang:system_info({wordsize, internal}),
(Size - (N rem Size)) * 8.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment