package com.mes.plc; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Properties; /** * 涂胶 PLC 配置:一台 PLC,a1/b1 为两把胶枪地址。 */ public class TjPlcConfig { public final boolean enabled; public final String machine; public String host; public final int rack; public final int slot; public final int db; public final GunAddr a1; public final GunAddr b1; public static class GunAddr { public final String name; public final int frameCodeOffset; public final int frameCodeLen; public final int scanFeedbackByte; public final int scanFeedbackBit; public final int allowEntryByte; public final int allowEntryBit; public final int pathDoneByte; public final int pathDoneBit; public final int allDoneByte; public final int allDoneBit; public final int seqOffset; public final int glueSpeedOffset; public final int glueLengthOffset; public GunAddr(String name, Properties pro, String prefix) { boolean a1 = "a1".equals(name); this.name = name; this.frameCodeOffset = parseInt(pro.getProperty(prefix + "frameCodeOffset"), a1 ? 0 : 32); this.frameCodeLen = parseInt(pro.getProperty(prefix + "frameCodeLen"), 30); this.scanFeedbackByte = parseInt(pro.getProperty(prefix + "scanFeedbackByte"), 64); this.scanFeedbackBit = parseInt(pro.getProperty(prefix + "scanFeedbackBit"), a1 ? 0 : 1); this.allowEntryByte = parseInt(pro.getProperty(prefix + "allowEntryByte"), 64); this.allowEntryBit = parseInt(pro.getProperty(prefix + "allowEntryBit"), a1 ? 2 : 3); this.pathDoneByte = parseInt(pro.getProperty(prefix + "pathDoneByte"), a1 ? 64 : 74); this.pathDoneBit = parseInt(pro.getProperty(prefix + "pathDoneBit"), a1 ? 4 : 0); this.allDoneByte = parseInt(firstNonBlank(pro.getProperty(prefix + "allDoneByte"), pro.getProperty(prefix + "glueDoneByte")), a1 ? 64 : 74); this.allDoneBit = parseInt(firstNonBlank(pro.getProperty(prefix + "allDoneBit"), pro.getProperty(prefix + "glueDoneBit")), a1 ? 5 : 1); this.seqOffset = parseInt(pro.getProperty(prefix + "seqOffset"), a1 ? 66 : 76); this.glueSpeedOffset = parseInt(pro.getProperty(prefix + "glueSpeedOffset"), a1 ? 68 : 78); // 涂胶长度:博途为 Word(非 Real) this.glueLengthOffset = parseInt(pro.getProperty(prefix + "glueLengthOffset"), a1 ? 72 : 82); } public String frameCodeAddr(int db) { return String.format("DB%d.DBB%d String[%d]", db, frameCodeOffset, frameCodeLen); } public String scanFeedbackAddr(int db) { return String.format("DB%d.DBX%d.%d", db, scanFeedbackByte, scanFeedbackBit); } public String allowEntryAddr(int db) { return String.format("DB%d.DBX%d.%d", db, allowEntryByte, allowEntryBit); } public String pathDoneAddr(int db) { return String.format("DB%d.DBX%d.%d", db, pathDoneByte, pathDoneBit); } public String allDoneAddr(int db) { return String.format("DB%d.DBX%d.%d", db, allDoneByte, allDoneBit); } public String seqAddr(int db) { return String.format("DB%d.DBW%d", db, seqOffset); } public String glueSpeedAddr(int db) { return String.format("DB%d.DBD%d", db, glueSpeedOffset); } public String glueLengthAddr(int db) { return String.format("DB%d.DBW%d", db, glueLengthOffset); } } private TjPlcConfig(Properties pro) { this.enabled = "true".equalsIgnoreCase(trim(pro.getProperty("mes.tj.plc.enabled"))); this.machine = trim(pro.getProperty("mes.machine", "a1")); this.host = trim(pro.getProperty("mes.tj.plc.host")); this.rack = parseInt(pro.getProperty("mes.tj.plc.rack"), 0); this.slot = parseInt(pro.getProperty("mes.tj.plc.slot"), 1); this.db = parseInt(pro.getProperty("mes.tj.plc.db"), 1300); this.a1 = new GunAddr("a1", pro, "mes.tj.a1."); this.b1 = new GunAddr("b1", pro, "mes.tj.b1."); } public GunAddr activeGun() { return "b1".equalsIgnoreCase(machine) ? b1 : a1; } public GunAddr gun(String name) { return "b1".equalsIgnoreCase(name) ? b1 : a1; } public static TjPlcConfig load() { try { Properties pro = loadProperties(); return new TjPlcConfig(pro); } catch (Exception e) { e.printStackTrace(); return new TjPlcConfig(new Properties()); } } public static Properties loadProperties() throws Exception { Properties pro = new Properties(); File file = resolveConfigFile(); if (file != null && file.exists()) { try (InputStream is = new FileInputStream(file); BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { pro.load(br); } return pro; } InputStream is = ClassLoader.getSystemResourceAsStream("config/config.properties"); if (is != null) { try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { pro.load(br); } } return pro; } /** * 保存 PLC IP,并尽量写回可写的 config.properties。 */ public static synchronized boolean saveHost(String newHost) { try { File file = resolveConfigFile(); if (file == null) { return false; } if (!file.exists()) { File parent = file.getParentFile(); if (parent != null && !parent.exists()) { parent.mkdirs(); } } String content; if (file.exists()) { try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) { StringBuilder sb = new StringBuilder(); String line; boolean replaced = false; while ((line = br.readLine()) != null) { if (line.startsWith("mes.tj.plc.host=")) { sb.append("mes.tj.plc.host=").append(newHost.trim()).append("\n"); replaced = true; } else { sb.append(line).append("\n"); } } if (!replaced) { sb.append("mes.tj.plc.host=").append(newHost.trim()).append("\n"); } content = sb.toString(); } } else { content = "mes.tj.plc.host=" + newHost.trim() + "\n"; } try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8))) { bw.write(content); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } public static File resolveConfigFile() { try { URL url = ClassLoader.getSystemResource("config/config.properties"); if (url != null && "file".equalsIgnoreCase(url.getProtocol())) { return new File(url.toURI()); } } catch (Exception ignored) { } File[] candidates = new File[]{ new File("src/resources/config/config.properties"), new File("config/config.properties"), new File("bin/config/config.properties") }; for (File f : candidates) { if (f.exists()) { return f; } } // 开发目录默认写入 File dev = new File("src/resources/config/config.properties"); if (dev.getParentFile() != null && (dev.getParentFile().exists() || dev.getParentFile().mkdirs())) { return dev; } return new File("config/config.properties"); } private static String firstNonBlank(String a, String b) { if (a != null && !a.trim().isEmpty()) { return a; } return b; } private static String trim(String v) { return v == null ? "" : v.trim(); } private static int parseInt(String v, int def) { try { if (v == null || v.trim().isEmpty()) { return def; } return Integer.parseInt(v.trim()); } catch (Exception e) { return def; } } }