1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
%%%-------------------------------------------------------------------
%%% @author Joe Zhao
%%% @copyright (C) 2014, <COMPANY>
%%% @doc
%%% This modules monitors different devices which includes registering devices when linked and monitoring their states.
%%% Registering devices and deregister them are done automatically when device are on/off line.
%%% Other than that the changing states of different devices is recorded, and boardcast / return when queried.
%%% @end
%%% Created : 29. 四月 2014 15:35
%%%-------------------------------------------------------------------
-module(devicemon).
-author("Joe Zhao").
-compile([debug_info,export_all]).
-include("devicemon.hrl").
%% API
%% -export([]).
%% @todo This module is not fault-safe, abrupt death will halt all operations
-define(QTOUT,100).
-define(STNULL,[0,255,0,0,0]).
cleanloop() ->
%% Cleanup the message queue -> Don't call it
receive
_ -> cleanloop()
after 0 ->
ok
end.
deviceloop(Devices) ->
receive
%% Basic Ops within server
{Pid,shutdown} -> ok;
{Pid,reg,Addr,Type} ->
%% Register -> auto replace
deviceloop(orddict:store(Addr,#device{type=Type},Devices));
{Pid,reg,Addr,Type,State} ->
deviceloop(orddict:store(Addr,#device{type=Type,state = State},Devices));
{Pid,dereg,Addr} ->
%% Register -> auto remove
case orddict:find(Addr,Devices) of
error -> deviceloop(Devices);
_Else -> deviceloop(orddict:erase(Addr,Devices))
end;
{Pid,stat,Addr} ->
case orddict:find(Addr,Devices) of
error -> Pid ! {self(),Addr,error};
{ok,Value} -> Pid ! {self(),Addr,Value}
end,
deviceloop(Devices);
%% Query about device list & status
%% Next step: remembering states
{Pid,comm,[0]} -> % General query
Pid ! {self(),comm,orddict:fold(fun(Key,Val,Acc) -> [Key,Val#device.type]++Val#device.state++Acc end, [],Devices)},
deviceloop(Devices);
{Pid,comm,[0,Addr]} -> % Specific query, this also shouldn't happen.
case orddict:find(Addr,Devices) of
error -> Pid ! {self(),comm,[Addr]++?STNULL};
{ok,Value} -> Pid ! {self(),comm,[Addr,Value#device.type]++Value#device.state}
end,
deviceloop(Devices);
%% Messages received from rsbus
{Pid,device,Addr,{error,Cause}} ->
io:format("[Device Err]Device address: ~p Error: ~p \n",[Addr,Cause]),
self() ! {self(),dereg,Addr},
deviceloop(Devices);
{Pid,device,Addr,{stat,Type,Msg}} ->
tcpserv ! {self(),comm,[Addr,Type|Msg]},
deviceloop(orddict:store(Addr,#device{type=Type,state = Msg},Devices));
%% Messages received from some other server -> redirect to rsbus
{Pid,comm,[Addr|Msg]} ->
rsbusserv ! {self(),comm,Addr,Msg},
deviceloop(Devices);
%% General ops
{Pid,clean} -> % Clean message queue -> use it when garbage might be cloting the server
cleanloop(),
deviceloop(Devices);
{Pid,heartbeat,Addr} -> % Specific heartbeat !!! Good stuff
self() ! {self(),comm,[Addr]},
deviceloop(Devices);
{Pid,heartbeat} -> % This type of heartbeat will cause congestion, use with caution
[self() ! {self(),comm,[Addr]}|| Addr <- lists:seq(1,?ADDRANGE)],
deviceloop(Devices)
end.
devmon() ->
register(?MODULE,self()),
deviceloop(orddict:new()).
getStat(Addr) ->
devicemon ! {self(),stat,Addr},
receive
{_Pid,Addr,error} -> error;
{_Pid,Addr,Val} -> Val
after ?QTOUT ->
error
end.
getStatus(Addr) ->
case getStat(Addr) of
error -> error;
Val -> ready
%% device status multiplexer
%% ready | busy
end.
start() ->
spawn(?MODULE,devmon,[]).
|