All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.xingshuangs.iot.protocol.melsec.service.McPLC Maven / Gradle / Ivy

/*
 * MIT License
 *
 * Copyright (c) 2021-2099 Oscura (xingshuang) 
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.github.xingshuangs.iot.protocol.melsec.service;


import com.github.xingshuangs.iot.common.buff.ByteReadBuff;
import com.github.xingshuangs.iot.common.buff.ByteWriteBuff;
import com.github.xingshuangs.iot.common.buff.EByteBuffFormat;
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.model.McDeviceAddress;
import com.github.xingshuangs.iot.protocol.melsec.model.McDeviceContent;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import static com.github.xingshuangs.iot.common.constant.GeneralConst.LOCALHOST;
import static com.github.xingshuangs.iot.common.constant.GeneralConst.MELSEC_PORT;

/**
 * 三菱的PLC
 * 通信帧命名规格
* 通信帧命名格式如下:
* xxx 兼容 n m 帧(示例: QnA 兼容 3C 帧、QnA 兼容 3E 帧)
* 1、xxx 用于表示与以前产品模块的指令兼容性的对象可编程控制器 CPU
* A : A 系列可编程控制器 CPU
* QnA : QnA 系列可编程控制器 CPU
* 2、n对应的以前产品模块的帧
* 1 : 兼容 A 系列的计算机链接模块、以太网接口模块支持的指令的通信帧
* 2 : 兼容 QnA 系列串行通信模块支持的 QnA 简易帧
* 3 : QnA 系列串行通信模块支持的 QnA 帧及兼容 QnA 系列以太网接口模块支持的通信帧
* 4 : 兼容 QnA 系列串行通信模块支持的 QnA 扩展帧
* 3、m是指相应帧进行数据通信的对象模块
* C : C24
* E : E71
*

* 通信方式
* 一般我们使用比较多的是以太网通信,
* 对于FX5U系列/Q系列/Qna系列/L系列的PLC,通常会使用QnA兼容3E帧,
* 对于FX3U系列,我们需要加以太网模块,采用A兼容1E帧。
* 对于串口设备,一般会使用QnA兼容2C帧和QnA兼容4C帧。
* * @author xingshuang */ public class McPLC extends McNetwork { public McPLC() { this(EMcSeries.QnA, EMcSeries.QnA.getFrameType(), LOCALHOST, MELSEC_PORT); } public McPLC(String host, int port) { this(EMcSeries.QnA, EMcSeries.QnA.getFrameType(), host, port); } public McPLC(EMcSeries series, String host, int port) { this(series, series.getFrameType(), host, port); } public McPLC(EMcSeries series, EMcFrameType frameType, String host, int port) { super(host, port); this.tag = "Melsec"; this.series = series; this.frameType = frameType; } //region 软元件读取 /** * 读多地址 * * @param multiAddressRead 多地址 * @return 数据列表 */ public List readMultiAddress(McMultiAddressRead multiAddressRead) { return this.readDeviceRandomInWord(multiAddressRead.getWords(), multiAddressRead.getDwords()); } /** * 读取booleans数据 * * @param address 地址 * @param count boolean个数 * @return boolean列表 */ public List readBoolean(String address, int count) { // 三菱1个字节对应两个boolean McDeviceAddress deviceAddress = McDeviceAddress.createBy(address, count); McDeviceContent deviceContent = this.readDeviceBatchInBit(deviceAddress); List res = this.getBooleansBy(deviceContent.getData()); return res.subList(0, count); } /** * 读取字节数组数据 * * @param address 地址 * @param count 字节个数 * @return 字节数组 */ public byte[] readBytes(String address, int count) { // 三菱1个字占2个字节 int newCount = count % 2 == 0 ? (count / 2) : ((count + 1) / 2); McDeviceAddress deviceAddress = McDeviceAddress.createBy(address, newCount); McDeviceContent deviceContent = this.readDeviceBatchInWord(deviceAddress); return ByteReadBuff.newInstance(deviceContent.getData()).getBytes(count); } /** * 读取1个boolean数据 * * @param address 地址 * @return boolean */ public boolean readBoolean(String address) { List booleans = this.readBoolean(address, 1); return booleans.get(0); } /** * 读取1个字节数据 * * @param address 地址 * @return 字节 */ public byte readByte(String address) { byte[] bytes = this.readBytes(address, 1); return bytes[0]; } /** * 读取1个Int16数据 * * @param address 地址 * @return short数据 */ public short readInt16(String address) { byte[] bytes = this.readBytes(address, 2); return ByteReadBuff.newInstance(bytes, true).getInt16(); } /** * 读取多个Int16数据 * * @param addresses 多地址 * @return short列表 */ public List readInt16(String... addresses) { return this.readInt16(Arrays.asList(addresses)); } /** * 读取多个Int16数据 * * @param addresses 多地址 * @return short列表 */ public List readInt16(List addresses) { List deviceAddresses = addresses.stream().map(McDeviceAddress::createBy) .collect(Collectors.toList()); List deviceContents = this.readDeviceRandomInWord(deviceAddresses, new ArrayList<>()); return deviceContents.stream() .map(x -> ByteReadBuff.newInstance(x.getData(), true).getInt16()) .collect(Collectors.toList()); } /** * 读取1个UInt16数据 * * @param address 地址 * @return int数据 */ public int readUInt16(String address) { byte[] bytes = this.readBytes(address, 2); return ByteReadBuff.newInstance(bytes, true).getUInt16(); } /** * 读取多个UInt16数据 * * @param addresses 多地址 * @return integer列表 */ public List readUInt16(String... addresses) { return this.readUInt16(Arrays.asList(addresses)); } /** * 读取多个UInt16数据 * * @param addresses 多地址 * @return integer列表 */ public List readUInt16(List addresses) { List deviceAddresses = addresses.stream().map(McDeviceAddress::createBy) .collect(Collectors.toList()); List deviceContents = this.readDeviceRandomInWord(deviceAddresses, new ArrayList<>()); return deviceContents.stream() .map(x -> ByteReadBuff.newInstance(x.getData(), true).getUInt16()) .collect(Collectors.toList()); } /** * 读取1个Int32数据 * * @param address 地址 * @return int数据 */ public int readInt32(String address) { byte[] bytes = this.readBytes(address, 4); return ByteReadBuff.newInstance(bytes, EByteBuffFormat.AB_CD).getInt32(); } /** * 读取多个Int32数据 * * @param addresses 多地址 * @return integer列表 */ public List readInt32(String... addresses) { return this.readInt32(Arrays.asList(addresses)); } /** * 读取多个Int32数据 * * @param addresses 多地址 * @return integer列表 */ public List readInt32(List addresses) { List deviceAddresses = addresses.stream().map(McDeviceAddress::createBy) .collect(Collectors.toList()); List deviceContents = this.readDeviceRandomInWord(new ArrayList<>(), deviceAddresses); return deviceContents.stream() .map(x -> ByteReadBuff.newInstance(x.getData(), EByteBuffFormat.AB_CD).getInt32()) .collect(Collectors.toList()); } /** * 读取1个UInt32数据 * * @param address 地址 * @return long数据 */ public long readUInt32(String address) { byte[] bytes = this.readBytes(address, 4); return ByteReadBuff.newInstance(bytes, EByteBuffFormat.AB_CD).getUInt32(); } /** * 读取多个UInt32数据 * * @param addresses 多地址 * @return long列表 */ public List readUInt32(String... addresses) { return this.readUInt32(Arrays.asList(addresses)); } /** * 读取多个UInt32数据 * * @param addresses 多地址 * @return long列表 */ public List readUInt32(List addresses) { List deviceAddresses = addresses.stream().map(McDeviceAddress::createBy) .collect(Collectors.toList()); List deviceContents = this.readDeviceRandomInWord(new ArrayList<>(), deviceAddresses); return deviceContents.stream() .map(x -> ByteReadBuff.newInstance(x.getData(), EByteBuffFormat.AB_CD).getUInt32()) .collect(Collectors.toList()); } /** * 读取1个Float32数据 * * @param address 地址 * @return float数据 */ public float readFloat32(String address) { byte[] bytes = this.readBytes(address, 4); return ByteReadBuff.newInstance(bytes, EByteBuffFormat.AB_CD).getFloat32(); } /** * 读取多个Float32数据 * * @param addresses 多地址 * @return Float列表 */ public List readFloat32(String... addresses) { return this.readFloat32(Arrays.asList(addresses)); } /** * 读取多个Float32数据 * * @param addresses 多地址 * @return Float列表 */ public List readFloat32(List addresses) { List deviceAddresses = addresses.stream().map(McDeviceAddress::createBy) .collect(Collectors.toList()); List deviceContents = this.readDeviceRandomInWord(new ArrayList<>(), deviceAddresses); return deviceContents.stream() .map(x -> ByteReadBuff.newInstance(x.getData(), EByteBuffFormat.AB_CD).getFloat32()) .collect(Collectors.toList()); } /** * 读取1个Float64数据 * * @param address 地址 * @return double数据 */ public double readFloat64(String address) { byte[] bytes = this.readBytes(address, 8); return ByteReadBuff.newInstance(bytes, EByteBuffFormat.AB_CD).getFloat64(); } // /** // * 读取多个Float64数据 // * // * @param addresses 多地址 // * @return Double列表 // */ // public List readFloat64(String... addresses) { // return this.readFloat64(Arrays.asList(addresses)); // } // // /** // * 读取多个Float64数据 // * // * @param addresses 多地址 // * @return Double列表 // */ // public List readFloat64(List addresses) { // List deviceAddresses = addresses.stream().map(x -> McDeviceAddress.createBy(x, 4)) // .collect(Collectors.toList()); // // List deviceContents = this.readDeviceBatchMultiBlocks(deviceAddresses, new ArrayList<>()); // // return deviceContents.stream() // .map(x -> ByteReadBuff.newInstance(x.getData(), EByteBuffFormat.AB_CD).getFloat64()) // .collect(Collectors.toList()); // } /** * 读取字符串数据 * * @param address 地址 * @param length 字符串长度 * @return 字符串 */ public String readString(String address, int length) { byte[] bytes = this.readBytes(address, length); return ByteReadBuff.newInstance(bytes, true).getString(length); } //endregion //region 软元件写入 /** * 写多地址 * * @param multiAddressWrite 多地址 */ public void writeMultiAddress(McMultiAddressWrite multiAddressWrite) { this.writeDeviceRandomInWord(multiAddressWrite.getWords(), multiAddressWrite.getDwords()); } /** * 写入多个boolean * * @param address 地址 * @param booleans boolean值 */ public void writeBoolean(String address, Boolean... booleans) { this.writeBoolean(address, Arrays.asList(booleans)); } /** * 写入boolean数据列表 * * @param address 地址 * @param booleans boolean列表 */ public void writeBoolean(String address, List booleans) { byte[] bytes = this.getBytesBy(booleans); McDeviceContent deviceContent = McDeviceContent.createBy(address, booleans.size(), bytes); this.writeDeviceBatchInBit(deviceContent); } /** * 写入字节数组 * * @param address 地址 * @param data 字节数组 */ public void writeBytes(String address, byte[] data) { // 三菱1个字占2个字节 byte[] newData = data; if (data.length % 2 != 0) { newData = ByteWriteBuff.newInstance(data.length + 1, true).putBytes(data).getData(); } // 软元件按字批量读取,是字的个数,而不是字节个数 McDeviceContent deviceContent = McDeviceContent.createBy(address, newData.length / 2, newData); this.writeDeviceBatchInWord(deviceContent); } /** * 写入1个boolean数据 * * @param address 地址 * @param data boolean数据 */ public void writeBoolean(String address, boolean data) { this.writeBoolean(address, Collections.singletonList(data)); } /** * 写入1个字节数据 * * @param address 地址 * @param data 字节数据 */ public void writeByte(String address, byte data) { this.writeBytes(address, new byte[]{data}); } /** * 写入1个Int16数据 * * @param address 地址 * @param data short数据 */ public void writeInt16(String address, short data) { byte[] bytes = ByteWriteBuff.newInstance(2, true).putShort(data).getData(); this.writeBytes(address, bytes); } /** * 写入多个Int16数据 * * @param address 地址 * @param data 数据 */ public void writeInt16(String address, Short... data) { this.writeInt16(address, Arrays.asList(data)); } /** * 写入多个Int16数据 * * @param address 地址 * @param data 数据 */ public void writeInt16(String address, List data) { if (data.isEmpty()) { throw new IllegalArgumentException("列表为空"); } ByteWriteBuff buff = ByteWriteBuff.newInstance(data.size() * 2, true); data.forEach(buff::putShort); this.writeBytes(address, buff.getData()); } /** * 写入1个UInt16数据 * * @param address 地址 * @param data int数据 */ public void writeUInt16(String address, int data) { byte[] bytes = ByteWriteBuff.newInstance(2, true).putShort(data).getData(); this.writeBytes(address, bytes); } /** * 写入多个UInt16数据 * * @param address 地址 * @param data 数据 */ public void writeUInt16(String address, Integer... data) { this.writeUInt16(address, Arrays.asList(data)); } /** * 写入多个UInt16数据 * * @param address 地址 * @param data 数据 */ public void writeUInt16(String address, List data) { if (data.isEmpty()) { throw new IllegalArgumentException("列表为空"); } ByteWriteBuff buff = ByteWriteBuff.newInstance(data.size() * 2, true); data.forEach(buff::putShort); this.writeBytes(address, buff.getData()); } /** * 写入1个Int32数据 * * @param address 地址 * @param data int数据 */ public void writeInt32(String address, int data) { byte[] bytes = ByteWriteBuff.newInstance(4, EByteBuffFormat.AB_CD).putInteger(data).getData(); this.writeBytes(address, bytes); } /** * 写入多个Int32数据 * * @param address 地址 * @param data 数据 */ public void writeInt32(String address, Integer... data) { this.writeInt32(address, Arrays.asList(data)); } /** * 写入多个Int32数据 * * @param address 地址 * @param data 数据 */ public void writeInt32(String address, List data) { if (data.isEmpty()) { throw new IllegalArgumentException("列表为空"); } ByteWriteBuff buff = ByteWriteBuff.newInstance(data.size() * 4, EByteBuffFormat.AB_CD); data.forEach(buff::putInteger); this.writeBytes(address, buff.getData()); } /** * 写入1个UInt32数据 * * @param address 地址 * @param data long数据 */ public void writeUInt32(String address, long data) { byte[] bytes = ByteWriteBuff.newInstance(4, EByteBuffFormat.AB_CD).putInteger(data).getData(); this.writeBytes(address, bytes); } /** * 写入多个UInt32数据 * * @param address 地址 * @param data 数据 */ public void writeUInt32(String address, Long... data) { this.writeUInt32(address, Arrays.asList(data)); } /** * 写入多个UInt32数据 * * @param address 地址 * @param data 数据 */ public void writeUInt32(String address, List data) { if (data.isEmpty()) { throw new IllegalArgumentException("data list is empty"); } ByteWriteBuff buff = ByteWriteBuff.newInstance(data.size() * 4, EByteBuffFormat.AB_CD); data.forEach(buff::putInteger); this.writeBytes(address, buff.getData()); } /** * 写入1个Float32数据 * * @param address 地址 * @param data float数据 */ public void writeFloat32(String address, float data) { byte[] bytes = ByteWriteBuff.newInstance(4, EByteBuffFormat.AB_CD).putFloat(data).getData(); this.writeBytes(address, bytes); } /** * 写入多个Float32数据 * * @param address 地址 * @param data 数据 */ public void writeFloat32(String address, Float... data) { this.writeFloat32(address, Arrays.asList(data)); } /** * 写入多个Float32数据 * * @param address 地址 * @param data 数据 */ public void writeFloat32(String address, List data) { if (data.isEmpty()) { throw new IllegalArgumentException("data list is empty"); } ByteWriteBuff buff = ByteWriteBuff.newInstance(data.size() * 4, EByteBuffFormat.AB_CD); data.forEach(buff::putFloat); this.writeBytes(address, buff.getData()); } /** * 写入1个Float64数据 * * @param address 地址 * @param data double数据 */ public void writeFloat64(String address, double data) { byte[] bytes = ByteWriteBuff.newInstance(8, EByteBuffFormat.AB_CD).putDouble(data).getData(); this.writeBytes(address, bytes); } /** * 写入多个Float64数据 * * @param address 地址 * @param data 数据 */ public void writeFloat64(String address, Double... data) { this.writeFloat64(address, Arrays.asList(data)); } /** * 写入多个Float64数据 * * @param address 地址 * @param data 数据 */ public void writeFloat64(String address, List data) { if (data.isEmpty()) { throw new IllegalArgumentException("data list is empty"); } ByteWriteBuff buff = ByteWriteBuff.newInstance(data.size() * 8, EByteBuffFormat.AB_CD); data.forEach(buff::putDouble); this.writeBytes(address, buff.getData()); } /** * 写入字符串数据 * * @param address 地址 * @param data 字符串数据 */ public void writeString(String address, String data) { byte[] bytes = ByteWriteBuff.newInstance(data.length(), true).putString(data).getData(); this.writeBytes(address, bytes); } //endregion }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy