summaryrefslogtreecommitdiff
path: root/rsbusserv.erl
diff options
context:
space:
mode:
authorJoe Zhao <ztuowen@gmail.com>2014-05-16 20:16:33 +0800
committerJoe Zhao <ztuowen@gmail.com>2014-05-16 20:16:33 +0800
commit859179718904a1824082fdbbf77192bd1ce762e7 (patch)
tree2869db33b8c21416676d6fc01eb65a079c318f83 /rsbusserv.erl
downloadlocal-859179718904a1824082fdbbf77192bd1ce762e7.tar.gz
local-859179718904a1824082fdbbf77192bd1ce762e7.tar.bz2
local-859179718904a1824082fdbbf77192bd1ce762e7.zip
First commit
Diffstat (limited to 'rsbusserv.erl')
-rw-r--r--rsbusserv.erl119
1 files changed, 119 insertions, 0 deletions
diff --git a/rsbusserv.erl b/rsbusserv.erl
new file mode 100644
index 0000000..997e590
--- /dev/null
+++ b/rsbusserv.erl
@@ -0,0 +1,119 @@
+%%%-------------------------------------------------------------------
+%%% @author Joe Zhao
+%%% @copyright (C) 2014, <COMPANY>
+%%% @doc
+%%% This server monitors behaviors on the serial bus.
+%%% Whose duty includes serialize queries, message encoding,
+%%% and response handling(only when slave request repitition of the previous command)
+%%% The returns of the command are sent back to its origins(first parameter of the tuple, can also be someone else).
+%%% @end
+%%% Created : 27. 四月 2014 16:52
+%%%-------------------------------------------------------------------
+-module(rsbusserv).
+-author("Joe Zhao").
+
+-compile([debug_info,export_all]).
+
+%% API
+%% -export([start/0]).
+
+-define(DEVICE,"/dev/ttyUSB0").
+-define(SPEED,19200).
+-define(TIMEOUT,40). % Timeout in milisec
+-define(REQTIMEOUT,200).
+
+-define(STARTBIT,[16#5B,16#AD]).
+-define(STOPBIT,[16#A4,16#52]).
+-define(REP,16#FF).
+
+rsbuslistener(Pid) ->
+ SerialPort = serial:start([{speed,?SPEED},{open,?DEVICE}]),
+ register(?MODULE,self()),
+ rsbus_listner(Pid,SerialPort).
+
+rsbus_parity(Msg) ->
+ lists:foldl(fun (X,P) -> X bxor P end,0,Msg).
+
+rsbus_rec([],ok,Msg,[]) ->
+ {stat,lists:reverse(tl(Msg)),hd(Msg)};
+rsbus_rec([H1,H2|Tail],read,Msg,[H1,H2]) ->
+ rsbus_rec([],ok,Msg,[]);
+rsbus_rec([H1,H2,H3|Tail],read,Msg,Cmp) ->
+ rsbus_rec([H2,H3|Tail],read,[H1|Msg],Cmp);
+rsbus_rec([H1,H2,H3,H4|Tail1],wait,[],[H1,H2,H3,H4]) ->
+ rsbus_rec(Tail1,read,[],?STOPBIT);
+rsbus_rec([H|Tail],wait,[],Cmp) ->
+ rsbus_rec(Tail,wait,[],Cmp);
+rsbus_rec(Rec,State,Msg,Cmp) ->
+ receive
+ {data, Bytes} ->
+ erlang:display(binary_to_list(Bytes)),
+ rsbus_rec(Rec++binary_to_list(Bytes),State,Msg,Cmp)
+ after ?TIMEOUT ->
+ {error,timeout}
+ end.
+
+rsbus_send(SerialPort,Addr,Msg) ->
+ %% Return {stat,Type,Stat} upon success
+ %% else return {error,timeout|parse}
+ SerialPort ! {send,?STARTBIT},
+ SerialPort ! {send,[Addr]},
+ SerialPort ! {send,Msg},
+ P=rsbus_parity(Msg) bxor Addr,
+ SerialPort ! {send,[P]},
+ SerialPort ! {send,?STOPBIT},
+ io:format("Send Complete!\n"),
+ case rsbus_rec([],wait,[],?STARTBIT++[0,Addr]) of
+ {stat,[?REP],RP} -> rsbus_send(SerialPort,Addr,Msg); % Will resend no matter what
+ {stat,Stat,RP} ->
+ erlang:display(RP),
+ TestP =rsbus_parity([RP|Stat]),
+ if
+ TestP /= Addr -> {err,parse};
+ true -> {stat,hd(Stat),tl(Stat)}
+ end;
+ {error,timeout} -> {error,timeout}
+ end.
+
+
+%% This function can effectively serialize access
+rsbus_listner(Pid,SerialPort) ->
+ erlang:display(self()),
+ receive
+ {data, _Bytes} ->
+ %% This shouldn't happen, no process should initiate comm
+ %% Discard everything
+ rsbus_listner(Pid,SerialPort);
+ {PPid,comm,Addr,Msg} ->
+ io:format("RSBus sending..."),
+ PPid ! {self(),device,Addr,rsbus_send(SerialPort,Addr,Msg)}, % Process and return
+ rsbus_listner(Pid,SerialPort);
+ {Pid,shutdown} ->
+ SerialPort ! stop,
+ ok
+ end.
+
+rsbusloop(Pid) ->
+ receive
+ {'EXIT',Pid,Cond} when Cond == normal; Cond==shutdown -> rsbusloop(spawn_link(?MODULE,rsbuslistener,[self()]));
+ {PPid,shutdown} -> Pid ! {self(),shutdown}
+ end.
+
+rsbusmon() ->
+ process_flag(trap_exit,true),
+ Pid = spawn_link(?MODULE,rsbuslistener,[self()]),
+ rsbusloop(Pid).
+
+rsbusreq(Addr,Msg) ->
+ rsbusserv ! {self(),comm,Addr,Msg},
+ receive
+ {PPid,device,Addr,{error,Reason}} ->
+ {error,Reason};
+ {PPid,device,Addr,{stat,Type,Msg}} ->
+ {stat,Type,Msg}
+ after ?REQTIMEOUT ->
+ {error,timeout}
+ end.
+
+start() ->
+ spawn(?MODULE,rsbusmon,[]). \ No newline at end of file