|
|
@@ -2,6 +2,7 @@ package com.mes.util;
|
|
|
|
|
|
import com.alibaba.fastjson2.JSONArray;
|
|
|
import com.alibaba.fastjson2.JSONObject;
|
|
|
+import com.github.xingshuangs.iot.protocol.melsec.enums.EMcFrameType;
|
|
|
import com.github.xingshuangs.iot.protocol.melsec.enums.EMcSeries;
|
|
|
import com.github.xingshuangs.iot.protocol.melsec.service.McPLC;
|
|
|
import org.slf4j.Logger;
|
|
|
@@ -11,14 +12,21 @@ import java.text.SimpleDateFormat;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Collections;
|
|
|
import java.util.Date;
|
|
|
+import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
import java.util.Locale;
|
|
|
+import java.util.Map;
|
|
|
|
|
|
public class PLCUtils {
|
|
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(PLCUtils.class);
|
|
|
private static final int CONNECT_TIMEOUT_MS = 2000;
|
|
|
private static final int RECEIVE_TIMEOUT_MS = 3000;
|
|
|
+ private static final long PLC_FAILURE_WARN_INTERVAL_MS = 30000L;
|
|
|
+ private static final long WELDING_SAMPLE_INTERVAL_MS = 500L;
|
|
|
+ private static final Map<String, Object> PLC_LOCKS = new HashMap<>();
|
|
|
+ private static final Map<String, McPLC> PLC_CACHE = new HashMap<>();
|
|
|
+ private static final Map<String, Long> PLC_FAILURE_LOG_TIMES = new HashMap<>();
|
|
|
|
|
|
private static McPLC defaultPlc = new McPLC(EMcSeries.QnA, "192.168.0.35", 8000);
|
|
|
|
|
|
@@ -108,16 +116,19 @@ public class PLCUtils {
|
|
|
}
|
|
|
|
|
|
public static StationStatus readStationStatus(StationConfig config) {
|
|
|
- McPLC plc = createPlc(config);
|
|
|
- try {
|
|
|
- return new StationStatus(
|
|
|
- readBoolean(plc, config, config.getAllowStart()),
|
|
|
- readBoolean(plc, config, config.getAllowDown()),
|
|
|
- readBoolean(plc, config, config.getStartMethod()),
|
|
|
- readBoolean(plc, config, config.getStopMethod()),
|
|
|
- readBoolean(plc, config, config.getFault()));
|
|
|
- } finally {
|
|
|
- plc.close();
|
|
|
+ synchronized (getPlcLock(config)) {
|
|
|
+ McPLC plc = getCachedPlc(config);
|
|
|
+ try {
|
|
|
+ return new StationStatus(
|
|
|
+ readBoolean(plc, config, config.getAllowStart()),
|
|
|
+ readBoolean(plc, config, config.getAllowDown()),
|
|
|
+ readBoolean(plc, config, config.getStartMethod()),
|
|
|
+ readBoolean(plc, config, config.getStopMethod()),
|
|
|
+ readBoolean(plc, config, config.getFault()));
|
|
|
+ } catch (RuntimeException e) {
|
|
|
+ discardCachedPlc(config, plc);
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -193,21 +204,160 @@ public class PLCUtils {
|
|
|
return "";
|
|
|
}
|
|
|
|
|
|
- McPLC plc = createPlc(config);
|
|
|
- try {
|
|
|
+ synchronized (getPlcLock(config)) {
|
|
|
+ McPLC plc = getCachedPlc(config);
|
|
|
+ try {
|
|
|
+ synchronized (getPlcLock(config)) {
|
|
|
if ("arc".equalsIgnoreCase(config.getWeldType())) {
|
|
|
return buildArcWeldContent(plc, config).toJSONString();
|
|
|
}
|
|
|
if ("spot".equalsIgnoreCase(config.getWeldType())) {
|
|
|
return buildSpotWeldContent(plc, config).toJSONString();
|
|
|
}
|
|
|
+ }
|
|
|
log.info("未配置该工位的PLC参数点位,工位={}", config.getGw());
|
|
|
return "";
|
|
|
} catch (Exception e) {
|
|
|
log.error("读取PLC参数失败,工位=" + config.getGw(), e);
|
|
|
return "";
|
|
|
- } finally {
|
|
|
- plc.close();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public static WeldingParamSampler startWeldingParamSampler(StationConfig config) {
|
|
|
+ WeldingParamSampler sampler = new WeldingParamSampler(config, WELDING_SAMPLE_INTERVAL_MS);
|
|
|
+ sampler.start();
|
|
|
+ return sampler;
|
|
|
+ }
|
|
|
+ public static boolean writeStartfalseMethod(StationConfig config) {
|
|
|
+ writeBoolean(config, config.getAllowStart(), false);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ public static class WeldingParamSampler {
|
|
|
+ private final StationConfig config;
|
|
|
+ private final long sampleIntervalMs;
|
|
|
+ private final List<JSONObject> samples = new ArrayList<>();
|
|
|
+ private volatile boolean running = false;
|
|
|
+ private Thread thread;
|
|
|
+ private long startTimeMillis;
|
|
|
+ private long stopTimeMillis;
|
|
|
+
|
|
|
+ private WeldingParamSampler(StationConfig config, long sampleIntervalMs) {
|
|
|
+ this.config = config;
|
|
|
+ this.sampleIntervalMs = sampleIntervalMs;
|
|
|
+ }
|
|
|
+
|
|
|
+ public synchronized void start() {
|
|
|
+ if (running || config == null || isEmpty(config.getWeldType())) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ running = true;
|
|
|
+ startTimeMillis = System.currentTimeMillis();
|
|
|
+ thread = new Thread(new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ sampleLoop();
|
|
|
+ }
|
|
|
+ }, "welding-param-sampler-" + config.getGw());
|
|
|
+ thread.setDaemon(true);
|
|
|
+ thread.start();
|
|
|
+ }
|
|
|
+
|
|
|
+ public String stopAndGetContent() {
|
|
|
+ running = false;
|
|
|
+ stopTimeMillis = System.currentTimeMillis();
|
|
|
+ Thread localThread = thread;
|
|
|
+ if (localThread != null) {
|
|
|
+ localThread.interrupt();
|
|
|
+ try {
|
|
|
+ localThread.join(3000L);
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ensureAtLeastOneSample();
|
|
|
+ return buildSampledContent();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void sampleLoop() {
|
|
|
+ while (running) {
|
|
|
+ try {
|
|
|
+ synchronized (getPlcLock(config)) {
|
|
|
+ McPLC plc = getCachedPlc(config);
|
|
|
+ try {
|
|
|
+ addSample(readWeldingSample(plc, config));
|
|
|
+ } catch (RuntimeException e) {
|
|
|
+ discardCachedPlc(config, plc);
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("read welding sample failed, gw={}", config.getGw(), e);
|
|
|
+ }
|
|
|
+ sleepQuietly(sampleIntervalMs);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addSample(JSONObject sample) {
|
|
|
+ if (sample == null || sample.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ synchronized (samples) {
|
|
|
+ samples.add(sample);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ensureAtLeastOneSample() {
|
|
|
+ synchronized (samples) {
|
|
|
+ if (!samples.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ synchronized (getPlcLock(config)) {
|
|
|
+ McPLC plc = getCachedPlc(config);
|
|
|
+ try {
|
|
|
+ addSample(readWeldingSample(plc, config));
|
|
|
+ } catch (RuntimeException e) {
|
|
|
+ discardCachedPlc(config, plc);
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("read final welding sample failed, gw={}", config == null ? "" : config.getGw(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private String buildSampledContent() {
|
|
|
+ if (config == null || isEmpty(config.getWeldType())) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ JSONArray sampleArray = new JSONArray();
|
|
|
+ synchronized (samples) {
|
|
|
+ sampleArray.addAll(samples);
|
|
|
+ }
|
|
|
+ if (sampleArray.isEmpty()) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ JSONObject content = baseContent(config, config.getWeldType());
|
|
|
+ content.put("startTime", formatTime(startTimeMillis));
|
|
|
+ content.put("stopTime", formatTime(stopTimeMillis == 0L ? System.currentTimeMillis() : stopTimeMillis));
|
|
|
+ content.put("sampleIntervalMs", sampleIntervalMs);
|
|
|
+ content.put("sampleCount", sampleArray.size());
|
|
|
+ content.put("samples", sampleArray);
|
|
|
+ addSpotSummary(content, sampleArray);
|
|
|
+ return content.toJSONString();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void sleepQuietly(long millis) {
|
|
|
+ try {
|
|
|
+ Thread.sleep(millis);
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -218,22 +368,29 @@ public class PLCUtils {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- McPLC plc = createPlc(config);
|
|
|
- try {
|
|
|
+ synchronized (getPlcLock(config)) {
|
|
|
+ McPLC plc = getCachedPlc(config);
|
|
|
+ try {
|
|
|
// 现场验证:192.168.0.10 的SLMP端口支持单点写,不适合连续位写。
|
|
|
- plc.writeBoolean(address, value);
|
|
|
- } finally {
|
|
|
- plc.close();
|
|
|
+ plc.writeBoolean(address, value);
|
|
|
+ } catch (RuntimeException e) {
|
|
|
+ discardCachedPlc(config, plc);
|
|
|
+ logPlcFailure("writeBoolean", config, address, plc, e);
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 读取单个 M 点状态,例如开始加工、加工结束。
|
|
|
private static boolean readBoolean(StationConfig config, String address) {
|
|
|
- McPLC plc = createPlc(config);
|
|
|
- try {
|
|
|
- return readBoolean(plc, config, address);
|
|
|
- } finally {
|
|
|
- plc.close();
|
|
|
+ synchronized (getPlcLock(config)) {
|
|
|
+ McPLC plc = getCachedPlc(config);
|
|
|
+ try {
|
|
|
+ return readBoolean(plc, config, address);
|
|
|
+ } catch (RuntimeException e) {
|
|
|
+ discardCachedPlc(config, plc);
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -243,61 +400,115 @@ public class PLCUtils {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- return plc.readBoolean(address);
|
|
|
+ try {
|
|
|
+ return plc.readBoolean(address);
|
|
|
+ } catch (RuntimeException e) {
|
|
|
+ logPlcFailure("readBoolean", config, address, plc, e);
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private static JSONObject buildArcWeldContent(McPLC plc, StationConfig config) {
|
|
|
JSONObject content = baseContent(config, "arc");
|
|
|
+
|
|
|
+ JSONArray samples = new JSONArray();
|
|
|
+ samples.add(buildArcWeldSample(plc, config));
|
|
|
+ content.put("samples", samples);
|
|
|
+ return content;
|
|
|
+ }
|
|
|
+ private static JSONObject buildSpotWeldContent(McPLC plc, StationConfig config) {
|
|
|
+ JSONObject content = baseContent(config, "spot");
|
|
|
+ JSONObject sample = buildSpotWeldSample(plc, config);
|
|
|
+
|
|
|
+ JSONArray samples = new JSONArray();
|
|
|
+ samples.add(sample);
|
|
|
+ content.put("samples", samples);
|
|
|
+ addSpotSummary(content, samples);
|
|
|
+ return content;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static JSONObject readWeldingSample(McPLC plc, StationConfig config) {
|
|
|
+ if ("arc".equalsIgnoreCase(config.getWeldType())) {
|
|
|
+ return buildArcWeldSample(plc, config);
|
|
|
+ }
|
|
|
+ if ("spot".equalsIgnoreCase(config.getWeldType())) {
|
|
|
+ return buildSpotWeldSample(plc, config);
|
|
|
+ }
|
|
|
+ return new JSONObject();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static JSONObject buildArcWeldSample(McPLC plc, StationConfig config) {
|
|
|
JSONObject sample = new JSONObject();
|
|
|
sample.put("time", currentTime());
|
|
|
addScaledNumber(plc, sample, "robot1Current", config.getRobot1Current(), 1, false);
|
|
|
addScaledNumber(plc, sample, "robot1Voltage", config.getRobot1Voltage(), 10, false);
|
|
|
+ addScaledNumber(plc, sample, "robot1WeldTime", config.getRobot1Time(), 20, true);
|
|
|
addScaledNumber(plc, sample, "robot2Current", config.getRobot2Current(), 1, false);
|
|
|
addScaledNumber(plc, sample, "robot2Voltage", config.getRobot2Voltage(), 10, false);
|
|
|
-
|
|
|
- JSONArray samples = new JSONArray();
|
|
|
- samples.add(sample);
|
|
|
- content.put("samples", samples);
|
|
|
- return content;
|
|
|
+ addScaledNumber(plc, sample, "robot2WeldTime", config.getRobot2Time(), 20, true);
|
|
|
+ return sample;
|
|
|
}
|
|
|
- private static JSONObject buildSpotWeldContent(McPLC plc, StationConfig config) {
|
|
|
- List<Boolean> robot1Start = plc.readBoolean(config.getRobot1Start(), 50);
|
|
|
- List<Boolean> robot1Done = plc.readBoolean(config.getRobot1Done(), 50);
|
|
|
- List<Boolean> robot2Start = plc.readBoolean(config.getRobot2Start(), 50);
|
|
|
- List<Boolean> robot2Done = plc.readBoolean(config.getRobot2Done(), 50);
|
|
|
|
|
|
- JSONObject content = baseContent(config, "spot");
|
|
|
+ private static JSONObject buildSpotWeldSample(McPLC plc, StationConfig config) {
|
|
|
JSONObject sample = new JSONObject();
|
|
|
sample.put("time", currentTime());
|
|
|
addIntNumber(plc, sample, "robot1Pressure", config.getRobot1Pressure());
|
|
|
addIntNumber(plc, sample, "robot2Pressure", config.getRobot2Pressure());
|
|
|
addScaledNumber(plc, sample, "robot1Current", config.getRobot1Current(), 100, false);
|
|
|
- addScaledNumber(plc, sample, "robot2Current", config.getRobot2Current(), 100, false);
|
|
|
+ addScaledNumber(plc, sample, "robot1Voltage", config.getRobot1Voltage(), 10, false);
|
|
|
addScaledNumber(plc, sample, "robot1WeldTime", config.getRobot1Time(), 20, true);
|
|
|
+ addScaledNumber(plc, sample, "robot2Current", config.getRobot2Current(), 100, false);
|
|
|
+ addScaledNumber(plc, sample, "robot2Voltage", config.getRobot2Voltage(), 10, false);
|
|
|
addScaledNumber(plc, sample, "robot2WeldTime", config.getRobot2Time(), 20, true);
|
|
|
|
|
|
JSONObject spot = new JSONObject();
|
|
|
JSONObject robot1 = new JSONObject();
|
|
|
- robot1.put("startPoints", toPointNumbers(robot1Start));
|
|
|
- robot1.put("finishPoints", toPointNumbers(robot1Done));
|
|
|
+ robot1.put("startPoints", readPointNumbers(plc, config.getRobot1Start(), 50));
|
|
|
+ robot1.put("finishPoints", readPointNumbers(plc, config.getRobot1Done(), 50));
|
|
|
JSONObject robot2 = new JSONObject();
|
|
|
- robot2.put("startPoints", toPointNumbers(robot2Start));
|
|
|
- robot2.put("finishPoints", toPointNumbers(robot2Done));
|
|
|
+ robot2.put("startPoints", readPointNumbers(plc, config.getRobot2Start(), 50));
|
|
|
+ robot2.put("finishPoints", readPointNumbers(plc, config.getRobot2Done(), 50));
|
|
|
spot.put("robot1", robot1);
|
|
|
spot.put("robot2", robot2);
|
|
|
sample.put("spot", spot);
|
|
|
+ return sample;
|
|
|
+ }
|
|
|
|
|
|
- JSONArray samples = new JSONArray();
|
|
|
- samples.add(sample);
|
|
|
- content.put("samples", samples);
|
|
|
+ private static JSONArray readPointNumbers(McPLC plc, String address, int count) {
|
|
|
+ if (isEmpty(address)) {
|
|
|
+ return new JSONArray();
|
|
|
+ }
|
|
|
+ return toPointNumbers(plc.readBoolean(address, count));
|
|
|
+ }
|
|
|
|
|
|
+ private static void addSpotSummary(JSONObject content, JSONArray samples) {
|
|
|
+ if (samples == null || samples.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ JSONObject lastSample = samples.getJSONObject(samples.size() - 1);
|
|
|
+ if (lastSample == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ JSONObject spot = lastSample.getJSONObject("spot");
|
|
|
+ if (spot == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ JSONObject robot1 = spot.getJSONObject("robot1");
|
|
|
+ JSONObject robot2 = spot.getJSONObject("robot2");
|
|
|
JSONObject summary = new JSONObject();
|
|
|
- summary.put("robot1StartCount", countTrue(robot1Start));
|
|
|
- summary.put("robot1FinishCount", countTrue(robot1Done));
|
|
|
- summary.put("robot2StartCount", countTrue(robot2Start));
|
|
|
- summary.put("robot2FinishCount", countTrue(robot2Done));
|
|
|
+ summary.put("robot1StartCount", pointCount(robot1, "startPoints"));
|
|
|
+ summary.put("robot1FinishCount", pointCount(robot1, "finishPoints"));
|
|
|
+ summary.put("robot2StartCount", pointCount(robot2, "startPoints"));
|
|
|
+ summary.put("robot2FinishCount", pointCount(robot2, "finishPoints"));
|
|
|
content.put("summary", summary);
|
|
|
- return content;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static int pointCount(JSONObject robot, String key) {
|
|
|
+ if (robot == null) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ JSONArray points = robot.getJSONArray(key);
|
|
|
+ return points == null ? 0 : points.size();
|
|
|
}
|
|
|
|
|
|
private static JSONObject baseContent(StationConfig config, String weldingType) {
|
|
|
@@ -363,6 +574,13 @@ public class PLCUtils {
|
|
|
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
|
|
|
}
|
|
|
|
|
|
+ private static String formatTime(long timeMillis) {
|
|
|
+ if (timeMillis <= 0L) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(timeMillis));
|
|
|
+ }
|
|
|
+
|
|
|
// 按 StationConfig 创建 PLC 连接;不同工位可配置不同 PLC、端口和系列。
|
|
|
private static McPLC createPlc(StationConfig config) {
|
|
|
if (config == null || isEmpty(config.getPlcIp())) {
|
|
|
@@ -372,7 +590,9 @@ public class PLCUtils {
|
|
|
return plc;
|
|
|
}
|
|
|
|
|
|
- McPLC plc = new McPLC(parseSeries(config.getPlcSeries()), config.getPlcIp(), config.getPlcPort());
|
|
|
+ EMcSeries series = parseSeries(config.getPlcSeries());
|
|
|
+ EMcFrameType frameType = parseFrameType(config.getPlcFrame(), series.getFrameType());
|
|
|
+ McPLC plc = new McPLC(series, frameType, config.getPlcIp(), config.getPlcPort());
|
|
|
plc.setConnectTimeout(CONNECT_TIMEOUT_MS);
|
|
|
plc.setReceiveTimeout(RECEIVE_TIMEOUT_MS);
|
|
|
return plc;
|
|
|
@@ -388,6 +608,85 @@ public class PLCUtils {
|
|
|
return EMcSeries.QnA;
|
|
|
}
|
|
|
|
|
|
+ private static EMcFrameType parseFrameType(String frameType, EMcFrameType defaultValue) {
|
|
|
+ if (isEmpty(frameType)) {
|
|
|
+ return defaultValue;
|
|
|
+ }
|
|
|
+ String normalized = frameType.trim().toUpperCase(Locale.ROOT);
|
|
|
+ if (!normalized.startsWith("FRAME_")) {
|
|
|
+ normalized = "FRAME_" + normalized;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ return EMcFrameType.valueOf(normalized);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("invalid PLC frame type {}, use default {}", frameType, defaultValue);
|
|
|
+ return defaultValue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void logPlcFailure(String action, StationConfig config, String address, McPLC plc, Exception e) {
|
|
|
+ String logKey = action + "|" + plcKey(config) + "|" + address;
|
|
|
+ long now = System.currentTimeMillis();
|
|
|
+ synchronized (PLC_FAILURE_LOG_TIMES) {
|
|
|
+ Long lastLogTime = PLC_FAILURE_LOG_TIMES.get(logKey);
|
|
|
+ if (lastLogTime != null && now - lastLogTime < PLC_FAILURE_WARN_INTERVAL_MS) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ PLC_FAILURE_LOG_TIMES.put(logKey, now);
|
|
|
+ }
|
|
|
+ log.warn("{} failed, gw={}, address={}, ip={}, port={}, series={}, frame={}, connectTimeout={}ms, receiveTimeout={}ms",
|
|
|
+ action,
|
|
|
+ config == null ? "" : config.getGw(),
|
|
|
+ address,
|
|
|
+ config == null ? "" : config.getPlcIp(),
|
|
|
+ config == null ? "" : config.getPlcPort(),
|
|
|
+ plc == null ? "" : plc.getSeries(),
|
|
|
+ plc == null ? "" : plc.getFrameType(),
|
|
|
+ CONNECT_TIMEOUT_MS,
|
|
|
+ RECEIVE_TIMEOUT_MS,
|
|
|
+ e);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static Object getPlcLock(StationConfig config) {
|
|
|
+ String key = plcKey(config);
|
|
|
+ synchronized (PLC_LOCKS) {
|
|
|
+ Object lock = PLC_LOCKS.get(key);
|
|
|
+ if (lock == null) {
|
|
|
+ lock = new Object();
|
|
|
+ PLC_LOCKS.put(key, lock);
|
|
|
+ }
|
|
|
+ return lock;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static McPLC getCachedPlc(StationConfig config) {
|
|
|
+ String key = plcKey(config);
|
|
|
+ McPLC plc = PLC_CACHE.get(key);
|
|
|
+ if (plc == null) {
|
|
|
+ plc = createPlc(config);
|
|
|
+ PLC_CACHE.put(key, plc);
|
|
|
+ }
|
|
|
+ return plc;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void discardCachedPlc(StationConfig config, McPLC plc) {
|
|
|
+ String key = plcKey(config);
|
|
|
+ McPLC cached = PLC_CACHE.get(key);
|
|
|
+ if (cached == plc) {
|
|
|
+ PLC_CACHE.remove(key);
|
|
|
+ }
|
|
|
+ if (plc != null) {
|
|
|
+ plc.close();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String plcKey(StationConfig config) {
|
|
|
+ if (config == null || isEmpty(config.getPlcIp())) {
|
|
|
+ return "192.168.0.35:8000";
|
|
|
+ }
|
|
|
+ return config.getPlcIp() + ":" + config.getPlcPort();
|
|
|
+ }
|
|
|
+
|
|
|
private static int countTrue(List<Boolean> values) {
|
|
|
int count = 0;
|
|
|
for (Boolean value : values) {
|