| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- package com.mes.plc;
- import com.github.xingshuangs.iot.protocol.melsec.model.McDeviceAddress;
- import com.github.xingshuangs.iot.protocol.melsec.model.McDeviceContent;
- import com.github.xingshuangs.iot.protocol.melsec.service.McNetwork;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import java.util.Collections;
- /**
- * 三菱 MC 3E 协议封装:读写位软元件、读 D 区字符串
- * 地址写法:M205、D5000
- */
- public class McPlcClient {
- private static final Logger log = LoggerFactory.getLogger(McPlcClient.class);
- private final String ip;
- private final int port;
- private McNetwork mc;
- private volatile boolean connected = false;
- public McPlcClient(String ip, int port) {
- this.ip = ip;
- this.port = port;
- }
- public synchronized void connect() {
- if (connected) {
- return;
- }
- try {
- mc = new McNetwork(ip, port);
- mc.setPersistence(true);
- mc.setEnableReconnect(false);
- mc.setConnectTimeout(3000);
- mc.setReceiveTimeout(3000);
- mc.connect();
- connected = true;
- log.info("PLC 连接成功 " + ip + ":" + port);
- } catch (Exception e) {
- closeQuietly();
- connected = false;
- mc = null;
- log.info("PLC 连接失败 " + ip + ":" + port + " " + e.getMessage());
- }
- }
- public synchronized void disconnect() {
- closeQuietly();
- connected = false;
- mc = null;
- }
- public boolean isConnected() {
- return connected;
- }
- /** 读单个位,失败返回 false 并标记断开 */
- public synchronized boolean readBit(String address) {
- try {
- checkMc();
- McDeviceContent content = mc.readDeviceBatchInBit(McDeviceAddress.createBy(address, 1));
- return mc.getBooleansBy(content.getData()).get(0);
- } catch (Exception e) {
- onError("读 " + address, e);
- return false;
- }
- }
- /** 写单个位 */
- public synchronized boolean writeBit(String address, boolean value) {
- try {
- checkMc();
- McDeviceAddress addr = McDeviceAddress.createBy(address, 1);
- byte[] data = mc.getBytesBy(Collections.singletonList(value));
- mc.writeDeviceBatchInBit(new McDeviceContent(addr.getDeviceCode(), addr.getHeadDeviceNumber(), 1, data));
- return true;
- } catch (Exception e) {
- onError("写 " + address, e);
- return false;
- }
- }
- /**
- * 读 D 区字符串(ASCII/GBK),charCount 为字符数
- * 三菱 D 区每个字存 2 个字符且字节序相反,这里做高低字节交换
- */
- public synchronized String readString(String address, int charCount) {
- try {
- checkMc();
- int words = (charCount + 1) / 2;
- McDeviceContent content = mc.readDeviceBatchInWord(McDeviceAddress.createBy(address, words));
- byte[] raw = content.getData();
- byte[] swapped = new byte[raw.length];
- for (int i = 0; i + 1 < raw.length; i += 2) {
- swapped[i] = raw[i + 1];
- swapped[i + 1] = raw[i];
- }
- String s = new String(swapped, "GBK");
- int end = s.indexOf('\0');
- if (end >= 0) {
- s = s.substring(0, end);
- }
- return s.trim();
- } catch (Exception e) {
- onError("读 " + address, e);
- return "";
- }
- }
- private void checkMc() {
- if (!connected || mc == null) {
- throw new IllegalStateException("PLC 未连接");
- }
- }
- private void onError(String action, Exception e) {
- log.info("PLC " + action + " 失败: " + e.getMessage());
- // 通信异常后关闭旧连接,由外层重连
- closeQuietly();
- connected = false;
- mc = null;
- }
- private void closeQuietly() {
- try {
- if (mc != null) {
- mc.close();
- }
- } catch (Exception ignored) {
- }
- }
- }
|