summaryrefslogtreecommitdiff
path: root/devicemon.erl
blob: 703dca5cc8124f8248de99fa74a51893ceb73309 (plain)
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
%%%-------------------------------------------------------------------
%%% @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([]).

-define(QTOUT,100).

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.
      Dev=orddict:fetch(Addr,Devices),
      Pid ! {self(),comm,[Dev#device.type]++Dev#device.state},
      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,[]).