diff --git a/apps/modbus/src/modbus_device.erl b/apps/modbus/src/modbus_device.erl index a290ade..4b1d42d 100644 --- a/apps/modbus/src/modbus_device.erl +++ b/apps/modbus/src/modbus_device.erl @@ -100,7 +100,7 @@ handle_info({timeout, _, {poll_ticker, Name}}, State = #state{parent_pid = Paren %% 读取采集项目 ReceiverPid = self(), Ref = make_ref(), - ParentPid ! {request, ReceiverPid, Ref, SlaveId, Address}, + ParentPid ! {request, ReceiverPid, Ref, SlaveId, Address, 1}, {noreply, State#state{inflight = maps:put(Ref, Name, Inflight)}}; diff --git a/apps/modbus/src/modbus_service.erl b/apps/modbus/src/modbus_service.erl index c8fd2e5..dd3d5dd 100644 --- a/apps/modbus/src/modbus_service.erl +++ b/apps/modbus/src/modbus_service.erl @@ -20,8 +20,7 @@ -export([init/1, handle_event/4, terminate/3, code_change/4, callback_mode/0]). %% rtu指令 --define(MODBUS_CONNECT, 16#01). --define(MODBUS_READ, 16#02). +-define(MODBUS_READ, 16#01). %% 当前的状态 -define(DISCONNECTED, disconnected). @@ -33,7 +32,9 @@ -record(rtu_mode, { port :: erlang:port(), - delay_ms = 0 :: integer() + delay_ms = 0 :: integer(), + %% 信道是否在忙 + is_busy = false }). -record(state, { @@ -122,25 +123,27 @@ callback_mode() -> %% process message, this function is called. %% 请求的时候必须先加入队列,modbus需要控制请求的频率 -handle_event(info, {request, ReceiverPid, Ref, SlaveId, Address}, StateName, State = #state{mode = #rtu_mode{}, packet_id = PacketId, queue = Q}) -> +handle_event(info, {request, ReceiverPid, Ref, SlaveId, Address, Cnt}, StateName, State = #state{mode = #rtu_mode{}, packet_id = PacketId, queue = Q}) -> case StateName of ?CONNECTED -> %% 基于队列处理, modbus不是全双工的模式 - NQ = queue:in({PacketId, ReceiverPid, Ref, SlaveId, Address}, Q), + NQ = queue:in({PacketId, ReceiverPid, Ref, SlaveId, Address, Cnt}, Q), {keep_state, State#state{queue = NQ, packet_id = PacketId + 1}, [{next_event, info, read_next}]}; _ -> {keep_state, State} end; %% rtu 模式下读取下一个任务 -handle_event(info, read_next, ?CONNECTED, State = #state{mode = #rtu_mode{port = Port}, queue = Q, inflight = Inflight}) -> +handle_event(info, read_next, ?CONNECTED, State = #state{mode = #rtu_mode{is_busy = true}}) -> + {keep_state, State}; +handle_event(info, read_next, ?CONNECTED, State = #state{mode = Mode = #rtu_mode{port = Port}, queue = Q, inflight = Inflight}) -> lager:debug("[modbus_service] read next, q: ~p, port is: ~p", [queue:to_list(Q), Port]), case queue:out(Q) of - {{value, {PacketId, ReceiverPid, Ref, SlaveId, Address}}, Q2} -> - ReadCmd = <>, + {{value, {PacketId, ReceiverPid, Ref, SlaveId, Address, Cnt}}, Q2} -> + ReadCmd = <>, Port ! {self(), {command, ReadCmd}}, - {keep_state, State#state{queue = Q2, inflight = maps:put(PacketId, {ReceiverPid, Ref}, Inflight)}}; + {keep_state, State#state{queue = Q2, mode = Mode#rtu_mode{is_busy = true}, inflight = maps:put(PacketId, {ReceiverPid, Ref}, Inflight)}}; {empty, Q1} -> {keep_state, State#state{queue = Q1}} end; @@ -148,7 +151,8 @@ handle_event(info, read_next, ?DISCONNECTED, State = #state{mode = #rtu_mode{}}) {keep_state, State}; %% 从port读取数据, todo 获取到的数据表示为32位整数 -handle_event(info, {Port, {data, <>}}, ?CONNECTED, State = #state{mode = #rtu_mode{port = Port, delay_ms = DelayMs}, inflight = Inflight}) -> +handle_event(info, {Port, {data, <>}}, ?CONNECTED, State = #state{mode = Mode = #rtu_mode{port = Port, delay_ms = DelayMs}, inflight = Inflight}) -> + lager:debug("[device_service] read port data packet_id: ~p, val: ~p", [PacketId, Val]), NInflight = case maps:take(PacketId, Inflight) of error -> Inflight; @@ -157,11 +161,16 @@ handle_event(info, {Port, {data, <>}}, ?CON Inflight0 end, lager:debug("[modbus_service] port data is: ~p", [{PacketId, Val}]), - %% 读取下一条 - erlang:start_timer(DelayMs, self(), read_next), + + %% 通讯的过程需要一个空闲时间 + erlang:start_timer(DelayMs, self(), delay_locking), {keep_state, State#state{inflight = NInflight}}; +%% 锁定一个空闲时间, 把状态标记为空闲 +handle_event(info, {timeout, _, delay_locking}, ?CONNECTED, State = #state{mode = Mode = #rtu_mode{}}) -> + {keep_state, State#state{mode = Mode#rtu_mode{is_busy = false}}, [{next_event, info, read_next}]}; + %% 广播消息 handle_event(info, {broadcast, Key, Val}, ?CONNECTED, State = #state{alarm_pids = AlarmPids}) -> %% 推送告警信息