动作参数取值范围+角色配置权限
This commit is contained in:
@@ -14,47 +14,6 @@
|
||||
<description>rczn-common(公共模块:实体类、工具类、统一响应)</description>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<!-- 若想引用modbus4j需要引入下列repository id:ias-snapshots id:ias-releases 两个 ,使用默认仓库下载,不要使用阿里云仓库-->
|
||||
<repositories>
|
||||
<repository>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
<id>ias-snapshots</id>
|
||||
<name>Infinite Automation Snapshot Repository</name>
|
||||
<url>https://maven.mangoautomation.net/repository/ias-snapshot/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>ias-releases</id>
|
||||
<name>Infinite Automation Release Repository</name>
|
||||
<url>https://maven.mangoautomation.net/repository/ias-release/</url>
|
||||
</repository>
|
||||
<!-- ====================== 新增:Spring AI 必须的仓库 ====================== -->
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-releases</id>
|
||||
<name>Spring Releases</name>
|
||||
<url>https://repo.spring.io/release</url>
|
||||
</repository>
|
||||
<!-- ===================================================================== -->
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- 核心依赖 -->
|
||||
<dependency>
|
||||
@@ -85,6 +44,11 @@
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>java-jwt</artifactId>
|
||||
<version>${jwt.version}</version>
|
||||
</dependency>
|
||||
<!-- 如果需要 Web 相关类(拦截器等) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
@@ -92,41 +56,13 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- springAI框架 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.ai</groupId>-->
|
||||
<!-- <artifactId>spring-ai-starter-model-openai</artifactId>-->
|
||||
<!-- <version>1.0.0</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- Servlet API -->
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- S7connector 依赖 -->
|
||||
<dependency>
|
||||
<groupId>com.github.s7connector</groupId>
|
||||
<artifactId>s7connector</artifactId>
|
||||
<version>2.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- modbus4j -->
|
||||
<dependency>
|
||||
<groupId>com.infiniteautomation</groupId>
|
||||
<artifactId>modbus4j</artifactId>
|
||||
<version>3.0.3</version> <!-- 或其他稳定版本 -->
|
||||
</dependency>
|
||||
<!-- 连接池(工业场景必加,优化多设备连接) -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
<version>2.12.0</version>
|
||||
</dependency>
|
||||
<!-- Spring Context(如果需要 @Component 等注解) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
@@ -134,9 +70,8 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>java-jwt</artifactId>
|
||||
<version>${jwt.version}</version>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
@@ -154,12 +89,6 @@
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- websocket 核心依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.rczn;
|
||||
|
||||
/**
|
||||
* modbus 指令常量enum
|
||||
*/
|
||||
public class ModbusCmdConst {
|
||||
//下面是指令值:
|
||||
//就绪
|
||||
public static final int plc_ready = 10;
|
||||
//运行
|
||||
public static final int plc_run = 11;
|
||||
//暂停
|
||||
public static final int plc_pause = 12;
|
||||
//停止
|
||||
public static final int plc_stop = 10;
|
||||
//故障复位
|
||||
public static final int plc_reset_error = 20;
|
||||
//修改模式
|
||||
public static final int plc_set_model = 0;
|
||||
//参数读取:
|
||||
public static final int plc_read_param = 18;
|
||||
//
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.rczn.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* 异步线程池配置(用于PLC数据读取的异步执行)
|
||||
*/
|
||||
@Configuration
|
||||
@EnableAsync //开启异步任务
|
||||
public class AsyncThreadPoolConfig {
|
||||
|
||||
/**
|
||||
* 定义PLC专用线程池
|
||||
*/
|
||||
@Bean(name = "plcAsyncExecutor")
|
||||
public Executor plcAsyncExecutor(){
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
// 核心线程数(根据业务调整)
|
||||
executor.setCorePoolSize(5);
|
||||
// 最大线程数
|
||||
executor.setMaxPoolSize(10);
|
||||
// 队列容量
|
||||
executor.setQueueCapacity(20);
|
||||
// 线程名前缀(便于日志排查)
|
||||
executor.setThreadNamePrefix("PLC-Async-");
|
||||
// 线程空闲超时时间
|
||||
executor.setKeepAliveSeconds(60);
|
||||
// 拒绝策略:队列满时由调用线程处理(避免任务丢失)
|
||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
// 初始化线程池
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.rczn.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||
|
||||
@Configuration
|
||||
public class WebSocketConfig {
|
||||
|
||||
@Bean
|
||||
public ServerEndpointExporter serverEndpointExporter(){
|
||||
return new ServerEndpointExporter();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.rczn.domain;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class BaseBean {
|
||||
@@ -17,7 +15,6 @@ public class BaseBean {
|
||||
private String remark;
|
||||
|
||||
private LocalDateTime startTime;
|
||||
|
||||
private LocalDateTime endTime;
|
||||
|
||||
// 无参构造器、全参构造器(同步修改 delSign 类型)
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.rczn.exception;
|
||||
|
||||
import com.rczn.domain.Result;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class GlobalException {
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public Result handleException(Exception e){
|
||||
e.printStackTrace();
|
||||
return Result.error(StringUtils.hasLength(e.getMessage())? e.getMessage() : "系统异常");
|
||||
}
|
||||
}
|
||||
@@ -9,29 +9,13 @@ import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
//@Component
|
||||
public class LoginInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
// 1. 放行OPTIONS预检请求,直接返回200 OK,不做任何校验
|
||||
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
// 手动添加跨域响应头(兜底)
|
||||
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
|
||||
response.setHeader("Access-Control-Allow-Credentials", "true");
|
||||
response.setHeader("Access-Control-Allow-Methods", "GET,POST,PATCH,PUT,DELETE,OPTIONS");
|
||||
response.setHeader("Access-Control-Allow-Headers", "*");
|
||||
response.setHeader("Access-Control-Max-Age", "3600");
|
||||
return true; // 直接放行,不执行后续拦截逻辑
|
||||
}
|
||||
|
||||
try {
|
||||
String token = request.getHeader("Authorization");
|
||||
String[] tokens = token.split(" ");
|
||||
if(tokens.length>1){
|
||||
token = tokens[1];
|
||||
}
|
||||
Map<String, Object> claims = JwtUtil.parseToken(token);
|
||||
//保存用户数据到ThreadLocalUtil
|
||||
ThreadLocalUtil.set(claims);
|
||||
|
||||
@@ -1,380 +0,0 @@
|
||||
package com.rczn.modbus;
|
||||
|
||||
import com.serotonin.modbus4j.BatchRead;
|
||||
import com.serotonin.modbus4j.BatchResults;
|
||||
import com.serotonin.modbus4j.ModbusFactory;
|
||||
import com.serotonin.modbus4j.ModbusMaster;
|
||||
import com.serotonin.modbus4j.code.DataType;
|
||||
import com.serotonin.modbus4j.exception.ErrorResponseException;
|
||||
import com.serotonin.modbus4j.exception.ModbusInitException;
|
||||
import com.serotonin.modbus4j.exception.ModbusTransportException;
|
||||
import com.serotonin.modbus4j.ip.IpParameters;
|
||||
import com.serotonin.modbus4j.locator.BaseLocator;
|
||||
import com.serotonin.modbus4j.msg.ReadInputRegistersResponse;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* modbus通讯工具类,采用modbus4j实现
|
||||
*
|
||||
* @author lxq
|
||||
* @dependencies modbus4j-3.0.3.jar
|
||||
* @website https://github.com/infiniteautomation/modbus4j
|
||||
*/
|
||||
public class Modbus4jUtils {
|
||||
/**
|
||||
* 工厂。
|
||||
*/
|
||||
static ModbusFactory modbusFactory;
|
||||
static {
|
||||
if (modbusFactory == null) {
|
||||
modbusFactory = new ModbusFactory();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取master
|
||||
*
|
||||
* @return
|
||||
* @throws ModbusInitException
|
||||
*/
|
||||
public static ModbusMaster getMaster() throws ModbusInitException {
|
||||
IpParameters params = new IpParameters();
|
||||
params.setHost("localhost");
|
||||
params.setPort(502);
|
||||
|
||||
//
|
||||
// modbusFactory.createRtuMaster(params); //RTU 协议
|
||||
// modbusFactory.createUdpMaster(params);//UDP 协议
|
||||
// modbusFactory.createAsciiMaster(params);//ASCII 协议
|
||||
|
||||
// 采用 Modbus RTU over TCP/IP,第二个参数为 true,即 modbusFactory.createTcpMaster(params, true)
|
||||
ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 协议
|
||||
master.setTimeout(3000);
|
||||
master.setRetries(1);
|
||||
master.init();
|
||||
|
||||
return master;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取master
|
||||
*
|
||||
* @return
|
||||
* @throws ModbusInitException
|
||||
*/
|
||||
public static ModbusMaster getMaster(String ipAddr,Integer port) throws ModbusInitException {
|
||||
IpParameters params = new IpParameters();
|
||||
// params.setHost("localhost");
|
||||
params.setHost(ipAddr);
|
||||
// params.setPort(502);
|
||||
params.setPort(port);
|
||||
//
|
||||
// modbusFactory.createRtuMaster(params); //RTU 协议
|
||||
// modbusFactory.createUdpMaster(params);//UDP 协议
|
||||
// modbusFactory.createAsciiMaster(params);//ASCII 协议
|
||||
|
||||
// 采用 Modbus RTU over TCP/IP,第二个参数为 true,即 modbusFactory.createTcpMaster(params, true)
|
||||
ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 协议
|
||||
master.setTimeout(3000);
|
||||
master.setRetries(1);
|
||||
master.init();
|
||||
|
||||
return master;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取和测试Master对象
|
||||
* @param ip
|
||||
* @param port
|
||||
* @return
|
||||
* @throws ModbusInitException
|
||||
*/
|
||||
public static ModbusMaster getAndTestMaster(String ip, Integer port)
|
||||
throws ModbusInitException {
|
||||
|
||||
ModbusMaster master = getMaster(ip, port);
|
||||
|
||||
try {
|
||||
// 随便读一个确定存在的寄存器
|
||||
BaseLocator<Number> locator =
|
||||
BaseLocator.holdingRegister(1, 0, DataType.TWO_BYTE_INT_SIGNED);
|
||||
|
||||
Number value = master.getValue(locator);// ⭐ 真正触发 TCP 连接
|
||||
System.out.println("value:"+value);
|
||||
} catch (Exception e) {
|
||||
master.destroy();
|
||||
throw new RuntimeException("PLC 连接失败:" + ip + ":" + port, e);
|
||||
}
|
||||
|
||||
return master;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取[01 Coil Status 0x]类型 开关数据
|
||||
*
|
||||
* @param slaveId
|
||||
* slaveId
|
||||
* @param offset
|
||||
* 位置
|
||||
* @return 读取值
|
||||
* @throws ModbusTransportException
|
||||
* 异常
|
||||
* @throws ErrorResponseException
|
||||
* 异常
|
||||
* @throws ModbusInitException
|
||||
* 异常
|
||||
*/
|
||||
public static Boolean readCoilStatus(ModbusMaster modbusMaster,int slaveId, int offset)
|
||||
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
|
||||
// 01 Coil Status
|
||||
BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset);
|
||||
Boolean value = modbusMaster.getValue(loc);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取[02 Input Status 1x]类型 开关数据
|
||||
*
|
||||
* @param slaveId
|
||||
* @param offset
|
||||
* @return
|
||||
* @throws ModbusTransportException
|
||||
* @throws ErrorResponseException
|
||||
* @throws ModbusInitException
|
||||
*/
|
||||
public static Boolean readInputStatus(ModbusMaster modbusMaster,int slaveId, int offset)
|
||||
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
|
||||
// 02 Input Status
|
||||
BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, offset);
|
||||
Boolean value = modbusMaster.getValue(loc);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取[03 Holding Register类型 2x]模拟量数据
|
||||
*
|
||||
* @param slaveId
|
||||
* slave Id
|
||||
* @param offset
|
||||
* 位置
|
||||
* @param dataType
|
||||
* 数据类型,来自com.serotonin.modbus4j.code.DataType
|
||||
* @return
|
||||
* @throws ModbusTransportException
|
||||
* 异常
|
||||
* @throws ErrorResponseException
|
||||
* 异常
|
||||
* @throws ModbusInitException
|
||||
* 异常
|
||||
*/
|
||||
public static Number readHoldingRegister(ModbusMaster modbusMaster,int slaveId, int offset, int dataType)
|
||||
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
|
||||
// 03 Holding Register类型数据读取
|
||||
BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
|
||||
Number value = modbusMaster.getValue(loc);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取[04 Input Registers 3x]类型 模拟量数据
|
||||
*
|
||||
* @param modbusMaster
|
||||
* modbusMaster modbus连接对象
|
||||
* @param slaveId
|
||||
* slaveId 设备号
|
||||
* @param offset
|
||||
* 位置
|
||||
* @param dataType
|
||||
* 数据类型,来自com.serotonin.modbus4j.code.DataType
|
||||
* @return 返回结果
|
||||
* @throws ModbusTransportException
|
||||
* 异常
|
||||
* @throws ErrorResponseException
|
||||
* 异常
|
||||
* @throws ModbusInitException
|
||||
* 异常
|
||||
*/
|
||||
public static Number readInputRegisters(ModbusMaster modbusMaster,int slaveId, int offset, int dataType)
|
||||
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
|
||||
// 04 Input Registers类型数据读取
|
||||
BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, dataType);
|
||||
Number value = modbusMaster.getValue(loc);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量读取使用方法
|
||||
*
|
||||
* @throws ModbusTransportException
|
||||
* @throws ErrorResponseException
|
||||
* @throws ModbusInitException
|
||||
*/
|
||||
public static BatchResults<Integer> batchRead(ModbusMaster modbusMaster,int slaveId, int offset, int dataType) throws ModbusTransportException, ErrorResponseException, ModbusInitException {
|
||||
|
||||
BatchRead<Integer> batch = new BatchRead<Integer>();
|
||||
|
||||
batch.addLocator(0, BaseLocator.holdingRegister(1, 1, DataType.FOUR_BYTE_FLOAT));
|
||||
batch.addLocator(1, BaseLocator.inputStatus(1, 0));
|
||||
|
||||
batch.setContiguousRequests(false);
|
||||
BatchResults<Integer> results = modbusMaster.send(batch);
|
||||
System.out.println(results.getValue(0));
|
||||
System.out.println(results.getValue(1));
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 连续读取多个 Holding Register
|
||||
*/
|
||||
public static Number[] readHoldingRegisters(
|
||||
ModbusMaster master,
|
||||
int slaveId,
|
||||
int startOffset,
|
||||
int count,
|
||||
int dataType)
|
||||
throws ModbusTransportException, ErrorResponseException {
|
||||
|
||||
Number[] values = new Number[count];
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
BaseLocator<Number> locator =
|
||||
BaseLocator.holdingRegister(slaveId, startOffset + i, dataType);
|
||||
|
||||
values[i] = master.getValue(locator);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* 连续读取多个 Input Register
|
||||
*/
|
||||
public static Number[] readInputRegistersBatch(
|
||||
ModbusMaster master,
|
||||
int slaveId,
|
||||
int startOffset,
|
||||
int count,
|
||||
int dataType)
|
||||
throws ModbusTransportException, ErrorResponseException {
|
||||
|
||||
Number[] values = new Number[count];
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
BaseLocator<Number> locator =
|
||||
BaseLocator.inputRegister(slaveId, startOffset + i, dataType);
|
||||
|
||||
values[i] = master.getValue(locator);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量读取多个 Holding Register(高性能)
|
||||
*/
|
||||
public static BatchResults<Integer> batchReadHoldingRegisters(
|
||||
ModbusMaster master,
|
||||
int slaveId,
|
||||
int[] offsets,
|
||||
int dataType)
|
||||
throws ModbusTransportException, ErrorResponseException {
|
||||
|
||||
BatchRead<Integer> batch = new BatchRead<>();
|
||||
|
||||
for (int i = 0; i < offsets.length; i++) {
|
||||
batch.addLocator(i,
|
||||
BaseLocator.holdingRegister(slaveId, offsets[i], dataType));
|
||||
}
|
||||
|
||||
batch.setContiguousRequests(true); // 连续优化
|
||||
return master.send(batch);
|
||||
}
|
||||
|
||||
/**
|
||||
* 混合批量读取
|
||||
*/
|
||||
public static BatchResults<Integer> batchReadMixed(
|
||||
ModbusMaster master,
|
||||
int slaveId)
|
||||
throws ModbusTransportException, ErrorResponseException {
|
||||
|
||||
BatchRead<Integer> batch = new BatchRead<>();
|
||||
|
||||
batch.addLocator(0,
|
||||
BaseLocator.holdingRegister(slaveId, 0, DataType.FOUR_BYTE_FLOAT));
|
||||
|
||||
batch.addLocator(1,
|
||||
BaseLocator.holdingRegister(slaveId, 2, DataType.TWO_BYTE_INT_SIGNED));
|
||||
|
||||
batch.addLocator(2,
|
||||
BaseLocator.coilStatus(slaveId, 0));
|
||||
|
||||
batch.setContiguousRequests(false);
|
||||
|
||||
return master.send(batch);
|
||||
}
|
||||
|
||||
|
||||
public static void close(ModbusMaster master) {
|
||||
if (master != null) {
|
||||
master.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
ModbusMaster master = getMaster("192.178.111.123", 501);
|
||||
|
||||
} catch (ModbusInitException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 测试
|
||||
*
|
||||
* @param args
|
||||
*/
|
||||
public static void main1(String[] args) {
|
||||
try {
|
||||
ModbusMaster modbusMaster = getMaster();
|
||||
// 01测试
|
||||
// Boolean v011 = readCoilStatus(modbusMaster,1, 0);
|
||||
// Boolean v012 = readCoilStatus(modbusMaster,1, 1);
|
||||
// Boolean v013 = readCoilStatus(modbusMaster,1, 6);
|
||||
// System.out.println("v011:" + v011);
|
||||
// System.out.println("v012:" + v012);
|
||||
// System.out.println("v013:" + v013);
|
||||
// // 02测试
|
||||
// Boolean v021 = readInputStatus(modbusMaster,1, 0);
|
||||
// Boolean v022 = readInputStatus(modbusMaster,1, 1);
|
||||
// Boolean v023 = readInputStatus(modbusMaster,1, 2);
|
||||
// System.out.println("v021:" + v021);
|
||||
// System.out.println("v022:" + v022);
|
||||
// System.out.println("v023:" + v023);
|
||||
//
|
||||
// // 03测试
|
||||
// Number v031 = readHoldingRegister(modbusMaster,1, 1, DataType.FOUR_BYTE_FLOAT);// 注意,float
|
||||
// Number v032 = readHoldingRegister(modbusMaster,1, 3, DataType.FOUR_BYTE_FLOAT);// 同上
|
||||
// System.out.println("v031:" + v031);
|
||||
// System.out.println("v032:" + v032);
|
||||
|
||||
// 04测试
|
||||
// Number v041 = readInputRegisters(modbusMaster,1, 0, DataType.FOUR_BYTE_FLOAT);//
|
||||
Number v041 = readInputRegisters(modbusMaster,1, 0, DataType.FOUR_BYTE_INT_UNSIGNED);//
|
||||
Number v042 = readInputRegisters(modbusMaster,1, 2, DataType.FOUR_BYTE_FLOAT);//
|
||||
System.out.println("v041:" + v041);
|
||||
System.out.println("v042:" + v042);
|
||||
|
||||
Number vff = readHoldingRegister(modbusMaster,1,0,DataType.TWO_BYTE_INT_SIGNED);
|
||||
System.out.println("vff:" + vff);
|
||||
Number vff2 = readHoldingRegister(modbusMaster,1,2,DataType.TWO_BYTE_INT_SIGNED);
|
||||
System.out.println("vff2:" + vff2);
|
||||
// 批量读取
|
||||
// batchRead();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,247 +0,0 @@
|
||||
package com.rczn.modbus;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.serotonin.modbus4j.ModbusFactory;
|
||||
import com.serotonin.modbus4j.ModbusMaster;
|
||||
import com.serotonin.modbus4j.code.DataType;
|
||||
import com.serotonin.modbus4j.exception.ErrorResponseException;
|
||||
import com.serotonin.modbus4j.exception.ModbusInitException;
|
||||
import com.serotonin.modbus4j.exception.ModbusTransportException;
|
||||
import com.serotonin.modbus4j.ip.IpParameters;
|
||||
import com.serotonin.modbus4j.locator.BaseLocator;
|
||||
import com.serotonin.modbus4j.msg.ModbusResponse;
|
||||
import com.serotonin.modbus4j.msg.WriteCoilRequest;
|
||||
import com.serotonin.modbus4j.msg.WriteCoilResponse;
|
||||
import com.serotonin.modbus4j.msg.WriteCoilsRequest;
|
||||
import com.serotonin.modbus4j.msg.WriteCoilsResponse;
|
||||
import com.serotonin.modbus4j.msg.WriteRegisterRequest;
|
||||
import com.serotonin.modbus4j.msg.WriteRegisterResponse;
|
||||
import com.serotonin.modbus4j.msg.WriteRegistersRequest;
|
||||
|
||||
/**
|
||||
* modbus4j写入数据
|
||||
*
|
||||
* @author xq
|
||||
*
|
||||
*/
|
||||
public class Modbus4jWriteUtils {
|
||||
static Log log = LogFactory.getLog(Modbus4jWriteUtils.class);
|
||||
/**
|
||||
* 工厂。
|
||||
*/
|
||||
static ModbusFactory modbusFactory;
|
||||
static {
|
||||
if (modbusFactory == null) {
|
||||
modbusFactory = new ModbusFactory();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取tcpMaster
|
||||
*
|
||||
* @return
|
||||
* @throws ModbusInitException
|
||||
*/
|
||||
public static ModbusMaster getMaster() throws ModbusInitException {
|
||||
IpParameters params = new IpParameters();
|
||||
params.setHost("localhost");
|
||||
params.setPort(502);
|
||||
|
||||
ModbusMaster tcpMaster = modbusFactory.createTcpMaster(params, false);
|
||||
tcpMaster.init();
|
||||
|
||||
return tcpMaster;
|
||||
}
|
||||
/**
|
||||
* 获取master
|
||||
*
|
||||
* @return
|
||||
* @throws ModbusInitException
|
||||
*/
|
||||
public static ModbusMaster getMaster(String ipAddr,Integer port) throws ModbusInitException {
|
||||
IpParameters params = new IpParameters();
|
||||
// params.setHost("localhost");
|
||||
params.setHost(ipAddr);
|
||||
// params.setPort(502);
|
||||
params.setPort(port);
|
||||
//
|
||||
// modbusFactory.createRtuMaster(params); //RTU 协议
|
||||
// modbusFactory.createUdpMaster(params);//UDP 协议
|
||||
// modbusFactory.createAsciiMaster(params);//ASCII 协议
|
||||
|
||||
// 采用 Modbus RTU over TCP/IP,第二个参数为 true,即 modbusFactory.createTcpMaster(params, true)
|
||||
ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 协议
|
||||
master.init();
|
||||
|
||||
return master;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写 [01 Coil Status(0x)]写一个 function ID = 5
|
||||
*
|
||||
* @param slaveId
|
||||
* slave的ID
|
||||
* @param writeOffset
|
||||
* 位置
|
||||
* @param writeValue
|
||||
* 值
|
||||
* @return 是否写入成功
|
||||
* @throws ModbusTransportException
|
||||
* @throws ModbusInitException
|
||||
*/
|
||||
public static boolean writeCoil(ModbusMaster tcpMaster,int slaveId, int writeOffset, boolean writeValue)
|
||||
throws ModbusTransportException, ModbusInitException {
|
||||
// 获取master
|
||||
// ModbusMaster tcpMaster = getMaster();
|
||||
// 创建请求
|
||||
WriteCoilRequest request = new WriteCoilRequest(slaveId, writeOffset, writeValue);
|
||||
// 发送请求并获取响应对象
|
||||
WriteCoilResponse response = (WriteCoilResponse) tcpMaster.send(request);
|
||||
if (response.isException()) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 写[01 Coil Status(0x)] 写多个 function ID = 15
|
||||
*
|
||||
* @param slaveId
|
||||
* slaveId
|
||||
* @param startOffset
|
||||
* 开始位置
|
||||
* @param bdata
|
||||
* 写入的数据
|
||||
* @return 是否写入成功
|
||||
* @throws ModbusTransportException
|
||||
* @throws ModbusInitException
|
||||
*/
|
||||
public static boolean writeCoils(ModbusMaster tcpMaster,int slaveId, int startOffset, boolean[] bdata)
|
||||
throws ModbusTransportException, ModbusInitException {
|
||||
// 获取master
|
||||
// ModbusMaster tcpMaster = getMaster();
|
||||
// 创建请求
|
||||
WriteCoilsRequest request = new WriteCoilsRequest(slaveId, startOffset, bdata);
|
||||
// 发送请求并获取响应对象
|
||||
WriteCoilsResponse response = (WriteCoilsResponse) tcpMaster.send(request);
|
||||
if (response.isException()) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/***
|
||||
* 写[03 Holding Register(4x)] 写一个 function ID = 6
|
||||
*
|
||||
* @param slaveId
|
||||
* @param writeOffset
|
||||
* @param writeValue
|
||||
* @return
|
||||
* @throws ModbusTransportException
|
||||
* @throws ModbusInitException
|
||||
*/
|
||||
public static boolean writeRegister(ModbusMaster tcpMaster,int slaveId, int writeOffset, short writeValue)
|
||||
throws ModbusTransportException, ModbusInitException {
|
||||
// 获取master
|
||||
// ModbusMaster tcpMaster = getMaster();
|
||||
// 创建请求对象
|
||||
WriteRegisterRequest request = new WriteRegisterRequest(slaveId, writeOffset, writeValue);
|
||||
WriteRegisterResponse response = (WriteRegisterResponse) tcpMaster.send(request);
|
||||
if (response.isException()) {
|
||||
log.error(response.getExceptionMessage());
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 写入[03 Holding Register(4x)]写多个 function ID=16
|
||||
*
|
||||
* @param slaveId
|
||||
* modbus的slaveID
|
||||
* @param startOffset
|
||||
* 起始位置偏移量值
|
||||
* @param sdata
|
||||
* 写入的数据
|
||||
* @return 返回是否写入成功
|
||||
* @throws ModbusTransportException
|
||||
* @throws ModbusInitException
|
||||
*/
|
||||
public static boolean writeRegisters(ModbusMaster tcpMaster,int slaveId, int startOffset, short[] sdata)
|
||||
throws ModbusTransportException, ModbusInitException {
|
||||
// 获取master
|
||||
// ModbusMaster tcpMaster = getMaster();
|
||||
// 创建请求对象
|
||||
WriteRegistersRequest request = new WriteRegistersRequest(slaveId, startOffset, sdata);
|
||||
// 发送请求并获取响应对象
|
||||
ModbusResponse response = tcpMaster.send(request);
|
||||
if (response.isException()) {
|
||||
log.error(response.getExceptionMessage());
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入数字类型的模拟量(如:写入Float类型的模拟量、Double类型模拟量、整数类型Short、Integer、Long)
|
||||
*
|
||||
* @param slaveId
|
||||
* @param offset
|
||||
* @param value
|
||||
* 写入值,Number的子类,例如写入Float浮点类型,Double双精度类型,以及整型short,int,long
|
||||
* @param dataType
|
||||
* ,com.serotonin.modbus4j.code.DataType
|
||||
* @throws ModbusTransportException
|
||||
* @throws ErrorResponseException
|
||||
* @throws ModbusInitException
|
||||
*/
|
||||
public static void writeHoldingRegister(ModbusMaster tcpMaster,int slaveId, int offset, Number value, int dataType)
|
||||
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
|
||||
// 获取master
|
||||
// ModbusMaster tcpMaster = getMaster();
|
||||
// 类型
|
||||
BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, offset, dataType);
|
||||
tcpMaster.setValue(locator, value);
|
||||
}
|
||||
|
||||
public static void main1(String[] args) {
|
||||
try {
|
||||
ModbusMaster modbusMaster = getMaster();
|
||||
//@formatter:off
|
||||
// 测试01
|
||||
// boolean t01 = writeCoil(1, 0, true);
|
||||
// System.out.println("T01:" + t01);
|
||||
|
||||
// 测试02
|
||||
// boolean t02 = writeCoils(1, 0, new boolean[] { true, false, true });
|
||||
// System.out.println("T02:" + t02);
|
||||
|
||||
// 测试03
|
||||
// short v = -3;
|
||||
// boolean t03 = writeRegister(1, 0, v);
|
||||
// System.out.println("T03:" + t03);
|
||||
// 测试04
|
||||
// boolean t04 = writeRegisters(1, 0, new short[] { -3, 3, 9 });
|
||||
// System.out.println("t04:" + t04);
|
||||
|
||||
writeRegister(modbusMaster,1,2,(short) 3);
|
||||
//写模拟量
|
||||
writeHoldingRegister(modbusMaster,1,0, 999, DataType.TWO_BYTE_INT_SIGNED);
|
||||
|
||||
//@formatter:on
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.rczn.plc;
|
||||
|
||||
|
||||
import com.github.s7connector.api.annotation.S7Variable;
|
||||
import com.github.s7connector.impl.utils.S7Type;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PLCData {
|
||||
|
||||
/**
|
||||
* type是这个点位在PLC中设置的类型,源码会解析其长度;
|
||||
* byteOffset对应PLC偏移量中的整数部分;
|
||||
* bitOffset指偏移量的小数部分,bitOffset指第几个bit.
|
||||
* byteOffset和bitOffset 也可理解为返回的byte[]中第byteOffset到bitOffset
|
||||
*/
|
||||
@S7Variable(type= S7Type.BOOL,byteOffset = 0,bitOffset = 0)
|
||||
public Boolean data10;//bool型的值不要用private
|
||||
|
||||
@S7Variable(type=S7Type.BOOL,byteOffset = 0,bitOffset = 1)
|
||||
public Boolean data11;
|
||||
|
||||
@S7Variable(type=S7Type.BOOL,byteOffset = 0,bitOffset = 2)
|
||||
public Boolean data12;
|
||||
|
||||
@S7Variable(type=S7Type.BOOL,byteOffset = 0,bitOffset = 3)
|
||||
public Boolean data13;
|
||||
|
||||
@S7Variable(type=S7Type.BOOL,byteOffset = 0,bitOffset = 4)
|
||||
public Boolean data14;
|
||||
|
||||
@S7Variable(type=S7Type.BOOL,byteOffset = 0,bitOffset = 5)
|
||||
public Boolean data15;
|
||||
|
||||
@S7Variable(type=S7Type.BOOL,byteOffset = 0,bitOffset = 6)
|
||||
public Boolean data16;
|
||||
|
||||
@S7Variable(type=S7Type.BOOL,byteOffset = 0,bitOffset = 7)
|
||||
public Boolean data17;
|
||||
|
||||
@S7Variable(type=S7Type.BYTE,byteOffset = 1,bitOffset = 0)
|
||||
public Byte dataB1;
|
||||
|
||||
@S7Variable(type=S7Type.STRING,byteOffset = 2,bitOffset = 0)
|
||||
public String dataS1;
|
||||
|
||||
@S7Variable(type=S7Type.STRING,byteOffset = 258,bitOffset = 40)
|
||||
public String dataS2;
|
||||
|
||||
@S7Variable(type=S7Type.STRING,byteOffset = 514,bitOffset = 40)
|
||||
public String dataS3;
|
||||
|
||||
@S7Variable(type=S7Type.STRING,byteOffset = 770)
|
||||
public String dataS4;
|
||||
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package com.rczn.plc;
|
||||
|
||||
import com.github.s7connector.api.DaveArea;
|
||||
import com.github.s7connector.api.S7Connector;
|
||||
import com.github.s7connector.api.factory.S7ConnectorFactory;
|
||||
import com.github.s7connector.impl.serializer.converter.StringConverter;
|
||||
|
||||
import java.util.Scanner;
|
||||
|
||||
|
||||
/**
|
||||
* @author 木春
|
||||
* @className S7PlcClient.java
|
||||
* @Form no
|
||||
* @Description ToDo
|
||||
* @createTime 2022 年 11 月 18 日 21 21:40:49
|
||||
**/
|
||||
public class S7PlcClient {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
|
||||
//初始化 创建一个链接对象
|
||||
S7Connector connector =
|
||||
S7ConnectorFactory
|
||||
.buildTCPConnector()
|
||||
.withHost("192.168.0.105") //
|
||||
.withRack(0) //架机号 可选
|
||||
.withSlot(1) //插槽号 可选
|
||||
.build();
|
||||
|
||||
// 写数据线程
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
java_write_plc(connector);//写数据
|
||||
}
|
||||
}).start();
|
||||
|
||||
// 读数据线程
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
java_read_plc(connector);//调用读取数据方法
|
||||
}
|
||||
}).start();
|
||||
|
||||
}
|
||||
|
||||
//读取数据
|
||||
public static void java_read_plc(S7Connector connector) {
|
||||
/* 读取数据方法*/
|
||||
byte[] PlcData = null;
|
||||
String str = null;
|
||||
String str1 = null;
|
||||
StringConverter converter = null;
|
||||
String extract1 = null;
|
||||
//循环读取
|
||||
while (true) {
|
||||
PlcData = connector.read(
|
||||
DaveArea.DB, //选择区块
|
||||
1, // 区块编号
|
||||
255, //长度
|
||||
260); //偏移地址
|
||||
|
||||
converter = new StringConverter();//字符串转换
|
||||
|
||||
//将读取到的数据转换成字符串类型 读取到的数据转换后
|
||||
extract1 = converter.extract(String.class, PlcData, 0, 0);
|
||||
//比对两次数据是否一样 不一样就打印
|
||||
if (!(extract1.equals(str1))) {
|
||||
System.out.println(" ");
|
||||
System.out.println("接收plc的数据为 = " + extract1);
|
||||
str1 = extract1;
|
||||
//plc发送 qu 就结束退出程序
|
||||
if (extract1.equals("qu")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//发送数据
|
||||
public static void java_write_plc(S7Connector connector) {
|
||||
while (true) {
|
||||
/*发送数据*/
|
||||
String data = null;
|
||||
// byte[] bytes = null;
|
||||
String input = null;
|
||||
Scanner sc = new Scanner(System.in);
|
||||
System.out.print("请输入要发送的数据: ");
|
||||
input = sc.nextLine();
|
||||
|
||||
String data_Baotou = " ";//数据包头 两个空格
|
||||
String data_tail = " ";//包尾 六个空格
|
||||
data = data_Baotou + input + data_tail;//发送的数据
|
||||
byte[] bytes = new byte[input.length()];
|
||||
bytes = data.getBytes();//转字节
|
||||
System.out.println("发送的字节长度 = " + bytes.length);//发送的字节长度
|
||||
connector.write(DaveArea.DB, 1, 4, bytes);//写入到 DB1 偏移量为4的变量
|
||||
System.out.println("发送的数据为 = " + data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
package com.rczn.plc;
|
||||
|
||||
import com.github.s7connector.api.DaveArea;
|
||||
import com.github.s7connector.api.S7Connector;
|
||||
import com.github.s7connector.api.S7Serializer;
|
||||
import com.github.s7connector.api.factory.S7ConnectorFactory;
|
||||
import com.github.s7connector.api.factory.S7SerializerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class S7PlcCommun {
|
||||
|
||||
|
||||
/**
|
||||
* 初始化PLC连接
|
||||
*/
|
||||
public S7Connector initConnect(){
|
||||
//PLC地址
|
||||
String ipAddress = "192.168.1.2";
|
||||
//默认端口
|
||||
Integer port = 102;
|
||||
S7Connector s7Connector = S7ConnectorFactory
|
||||
.buildTCPConnector()
|
||||
.withHost(ipAddress)
|
||||
.withPort(port)
|
||||
.withTimeout(10000) //连接超时时间
|
||||
.withRack(0)
|
||||
.withSlot(1)
|
||||
.build();
|
||||
S7Serializer s7Serializer2L = S7SerializerFactory.buildSerializer(s7Connector);
|
||||
return s7Connector;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取PLC中的数据
|
||||
*
|
||||
**/
|
||||
public void readPlcData() {
|
||||
|
||||
S7Connector s7Connector = initConnect();
|
||||
//第一个参数:DaveArea.DB 表示读取PLC的地址区域为DB
|
||||
//第二个参数:DB地址,若plc中是DB1000,则填1000
|
||||
//第三个参数:数据长度, <=plc中两个偏移量的间隔,当前偏移量为1000,下一个地址偏移量为1100,则长度可填 0-1000;
|
||||
//第四个参数:偏移量
|
||||
byte[] barcodeByte = s7Connector.read(DaveArea.DB, 1000, 2, 0);
|
||||
//由于当前PLC地址中保存的数据类型是字符串类型,所以直接将byte[] 转成string即可;
|
||||
String barcode =byteToHex(barcodeByte);
|
||||
System.out.println(barcode);
|
||||
try {
|
||||
s7Connector.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* byte数组转hex
|
||||
* @param bytes
|
||||
* @return
|
||||
*/
|
||||
public static String byteToHex(byte[] bytes){
|
||||
String strHex = "";
|
||||
StringBuilder sb = new StringBuilder("");
|
||||
for (int n = 0; n < bytes.length; n++) {
|
||||
strHex = Integer.toHexString(bytes[n] & 0xFF);
|
||||
sb.append((strHex.length() == 1) ? "0" + strHex : strHex); // 每个字节由两个字符表示,位数不够,高位补0
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* 向PLC中写数据
|
||||
*
|
||||
**/
|
||||
public void writePlcData() {
|
||||
|
||||
S7Connector s7Connector = initConnect();
|
||||
//第一个参数:DaveArea.DB 表示读取PLC的地址区域为DB
|
||||
//第二个参数:DB地址,若plc中是DB1000,则填1000
|
||||
//第三个参数:偏移量
|
||||
//第四个参数:写入的数据 二进制数组byte[],由于plc中地址的数据类型是word,所以写入的数据必须是4位的16进制数据
|
||||
s7Connector.write(DaveArea.DB,1000, 4,hexStringToBytes("0001"));
|
||||
|
||||
try {
|
||||
s7Connector.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将16进制字符串转成二进制数组
|
||||
* @param hexString
|
||||
* @return
|
||||
*/
|
||||
public static byte[] hexStringToBytes(String hexString) {
|
||||
if (hexString == null || hexString.equals("")) {
|
||||
return null;
|
||||
}
|
||||
hexString = hexString.toUpperCase();
|
||||
int length = hexString.length() / 2;
|
||||
char[] hexChars = hexString.toCharArray();
|
||||
byte[] d = new byte[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
int pos = i * 2;
|
||||
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将单个16进制字符转换为对应的字节值(核心补充方法)
|
||||
* @param c 16进制字符(0-9、A-F)
|
||||
* @return 对应的字节值(0-15)
|
||||
*/
|
||||
private static byte charToByte(char c) {
|
||||
// 0-9 对应 48-57
|
||||
if (c >= '0' && c <= '9') {
|
||||
return (byte) (c - '0');
|
||||
}
|
||||
// A-F 对应 65-70
|
||||
else if (c >= 'A' && c <= 'F') {
|
||||
return (byte) (c - 'A' + 10);
|
||||
}
|
||||
// 非法字符抛出异常(避免静默错误)
|
||||
else {
|
||||
throw new IllegalArgumentException("非法的16进制字符:" + c);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,220 +0,0 @@
|
||||
package com.rczn.plc_common;
|
||||
|
||||
import com.github.s7connector.api.DaveArea;
|
||||
import com.github.s7connector.api.S7Connector;
|
||||
import com.github.s7connector.api.factory.S7ConnectorFactory;
|
||||
import com.github.s7connector.impl.serializer.converter.BitConverter;
|
||||
import com.github.s7connector.impl.serializer.converter.IntegerConverter;
|
||||
import com.github.s7connector.impl.serializer.converter.RealConverter;
|
||||
import com.github.s7connector.impl.serializer.converter.StringConverter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class S7ConnectorPLC {
|
||||
public S7Connector initConnect(String ipAddress,int port,int rack,int slot) {
|
||||
//默认端口
|
||||
// 创建与PLC的链接
|
||||
S7Connector connector = S7ConnectorFactory.buildTCPConnector()
|
||||
.withHost(ipAddress)
|
||||
.withPort(port)
|
||||
.withRack(0) // 架机号 可选,建议选择,可能会报错
|
||||
.withSlot(2) // 插槽号 可选,建议选择,可能会报错
|
||||
.build();
|
||||
return connector;
|
||||
}
|
||||
|
||||
public static void main1(String[] args) {
|
||||
S7ConnectorPLC s7ConnectorPLC = new S7ConnectorPLC();
|
||||
S7Connector connector = s7ConnectorPLC.initConnect("192.168.110.123", 102, 0, 2);
|
||||
// s7ConnectorPLC.Java_To_write(connector);
|
||||
s7ConnectorPLC.Cyclic_readT(connector);
|
||||
}
|
||||
|
||||
//Int类型的封装类 用来转义
|
||||
private static IntegerConverter intCon = new IntegerConverter();
|
||||
//String...
|
||||
private static StringConverter strCon = new StringConverter();
|
||||
//Boolean...
|
||||
private static BitConverter boolCon = new BitConverter();
|
||||
//real实数浮点...
|
||||
private static RealConverter realCon = new RealConverter();
|
||||
|
||||
//获取到的数据存储
|
||||
public boolean in_bool = false;//bool
|
||||
public Integer in_int = null;//int
|
||||
public String in_String = "";//string
|
||||
public double in_real = 0.0;//real
|
||||
|
||||
public void Cyclic_read(S7Connector connector) {
|
||||
|
||||
byte[] PlcData = null;
|
||||
//读取bool型
|
||||
PlcData = connector.read(DaveArea.DB, // 选择数据区块
|
||||
5, // 区块编号
|
||||
1, // 数据值长度 boolean长度1
|
||||
0); // 开始位置偏移量
|
||||
Boolean extract_bool = boolCon.extract(Boolean.class, PlcData, 0, 0);//接收转换的数值
|
||||
in_bool = extract_bool;//赋值给全局变量
|
||||
|
||||
// 读取整型
|
||||
PlcData = connector.read(DaveArea.DB, // 选择数据区块
|
||||
5, // 区块编号
|
||||
2, // 数据值长度 int长度2
|
||||
2); // 开始位置 偏移量
|
||||
Integer extract_int = intCon.extract(Integer.class, PlcData, 0, 0);
|
||||
in_int = extract_int;
|
||||
|
||||
// 读取字符串型
|
||||
PlcData = connector.read(DaveArea.DB, // 选择数据区块
|
||||
5, // 区块编号
|
||||
16, // 数据值长度 String最小3 随值长度增加
|
||||
4); // 开始位置偏移量
|
||||
String extract_string = strCon.extract(String.class, PlcData, 0, 0);
|
||||
in_String = extract_string;
|
||||
|
||||
// 读取小数型
|
||||
PlcData = connector.read(DaveArea.DB, // 选择数据区块
|
||||
5, // 区块编号
|
||||
4, // 数据值长度 double长度4
|
||||
260); //偏移量
|
||||
Double num1 = realCon.extract(Double.class, PlcData, 0, 0);
|
||||
/* BigDecimal bd1 = new BigDecimal(num1);
|
||||
System.out.println("转换real浮点= " + bd1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());*/
|
||||
in_real = num1;
|
||||
|
||||
try {
|
||||
connector.close();//关闭链接
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
public void Cyclic_readT(S7Connector connector) {
|
||||
|
||||
byte[] PlcData = null;
|
||||
//读取bool型
|
||||
PlcData = connector.read(DaveArea.DB, // 选择数据区块
|
||||
5, // 区块编号
|
||||
1, // 数据值长度 boolean长度1
|
||||
0); // 开始位置偏移量
|
||||
Boolean extract_bool = boolCon.extract(Boolean.class, PlcData, 0, 0);//接收转换的数值
|
||||
in_bool = extract_bool;//赋值给全局变量
|
||||
|
||||
// 读取整型
|
||||
PlcData = connector.read(DaveArea.DB, // 选择数据区块
|
||||
5, // 区块编号
|
||||
2, // 数据值长度 int长度2
|
||||
2); // 开始位置 偏移量
|
||||
Integer extract_int = intCon.extract(Integer.class, PlcData, 0, 0);
|
||||
in_int = extract_int;
|
||||
|
||||
// 读取字符串型
|
||||
PlcData = connector.read(DaveArea.DB, // 选择数据区块
|
||||
5, // 区块编号
|
||||
16, // 数据值长度 String最小3 随值长度增加
|
||||
4); // 开始位置偏移量
|
||||
String extract_string = strCon.extract(String.class, PlcData, 0, 0);
|
||||
in_String = extract_string;
|
||||
|
||||
// 读取小数型
|
||||
PlcData = connector.read(DaveArea.DB, // 选择数据区块
|
||||
5, // 区块编号
|
||||
4, // 数据值长度 double长度4
|
||||
260); //偏移量
|
||||
Double num1 = realCon.extract(Double.class, PlcData, 0, 0);
|
||||
/* BigDecimal bd1 = new BigDecimal(num1);
|
||||
System.out.println("转换real浮点= " + bd1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());*/
|
||||
in_real = num1;
|
||||
|
||||
try {
|
||||
connector.close();//关闭链接
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
public void Java_To_write(S7Connector connector) {
|
||||
byte[] bytes = null;
|
||||
|
||||
boolean out_boolen = true;
|
||||
// bytes = S7Type.BOOL;
|
||||
// connector.write(DaveArea.DB, 5, 264, bytes);
|
||||
|
||||
// 向plc中写int整型数据
|
||||
// 向PLC中写短整型(2字节,对应PLC INT类型)数据
|
||||
//第一个参数:DaveArea.DB 表示读取PLC的地址区域为DB
|
||||
//第二个参数:DB块地址,若plc中是DB1000,则填1000
|
||||
//第三个参数:偏移量
|
||||
//第四个参数:写入的数据 二进制数组byte[]
|
||||
short out_int = 15;
|
||||
bytes = ByteBuffer.allocate(2).putShort(out_int).array();
|
||||
connector.write(DaveArea.DB, 5, 266, bytes);
|
||||
|
||||
// 向PLC中写整型(4字节,对应PLC DINT类型)数据
|
||||
int data=15;
|
||||
bytes = ByteBuffer.allocate(4).putInt(data).array();
|
||||
connector.write(DaveArea.DB,5, 528,bytes);
|
||||
|
||||
|
||||
// 写入字符串
|
||||
//第一个参数:DaveArea.DB 表示读取PLC的地址区域为DB
|
||||
//第二个参数:DB块地址,若plc中是DB1000,则填1000
|
||||
//第三个参数:偏移量
|
||||
//第四个参数:写入的数据 二进制数组byte[] ,总长度为10的话,有效数据只能是10-8,第一位代表总长,第二位,代表有效数据字节
|
||||
String out_string = "helloPlc";
|
||||
int writeStrLength = 10;//地址块大小
|
||||
byte[] writeBytes = new byte[writeStrLength];
|
||||
writeBytes[0] = (byte) writeStrLength;//写入本字符串块总宽度
|
||||
out_string = out_string.trim();//清除掉两边的空串
|
||||
int availableEffectCharLength = 0;//有效字符数控制
|
||||
if (out_string.length() > writeStrLength - 2) {//>writeStrLength-2 截断到最大有效数据位
|
||||
availableEffectCharLength = writeStrLength - 2;
|
||||
|
||||
} else {//<=writeStrLength-2
|
||||
availableEffectCharLength = out_string.length();
|
||||
}
|
||||
writeBytes[1] = (byte) availableEffectCharLength;//写入有效字节数
|
||||
byte[] strBytes = out_string.getBytes(StandardCharsets.US_ASCII);
|
||||
for (int i = 0; i < availableEffectCharLength; i++) {
|
||||
writeBytes[i + 2] = strBytes[i];
|
||||
}
|
||||
connector.write(DaveArea.DB, 5, 268, writeBytes);
|
||||
|
||||
|
||||
/**
|
||||
* 写入PLC中的浮点型数据
|
||||
* java float : plc Real 4 字节
|
||||
* java double : plc LReal 8 字节
|
||||
**/
|
||||
//第一个参数:DaveArea.DB 表示读取PLC的地址区域为DB
|
||||
//第二个参数:DB块地址,若plc中是DB1000,则填1000
|
||||
//第三个参数:偏移量
|
||||
//第四个参数:写入的数据 二进制数组byte[]
|
||||
float out_real= 5.54F;
|
||||
bytes = ByteBuffer.allocate(4).putFloat(out_real).array();
|
||||
connector.write(DaveArea.DB,5, 524,bytes);
|
||||
|
||||
/**
|
||||
* 写入PLC中的浮点型LREAL(java中是double)数据
|
||||
* java float : plc Real 4 字节
|
||||
* java double : plc LReal 8 字节
|
||||
**/
|
||||
//第一个参数:DaveArea.DB 表示读取PLC的地址区域为DB
|
||||
//第二个参数:DB块地址,若plc中是DB1000,则填1000
|
||||
//第三个参数:偏移量
|
||||
//第四个参数:写入的数据 二进制数组byte[]
|
||||
float out_Lreal= 15.56F;
|
||||
bytes = ByteBuffer.allocate(8).putDouble(out_Lreal).array();
|
||||
connector.write(DaveArea.DB,5, 532,bytes);
|
||||
|
||||
|
||||
try {
|
||||
connector.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.rczn.task;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class TestCrc {
|
||||
public static void main(String[] args) throws CloneNotSupportedException {
|
||||
LocalDateTime localDateTime = LocalDateTime.now();
|
||||
Video v1 = new Video("123", localDateTime);
|
||||
Video v2 = (Video) v1.clone();
|
||||
|
||||
System.out.println(v1);
|
||||
System.out.println(v2);
|
||||
System.out.println("===================================");
|
||||
|
||||
localDateTime.minusDays(10);
|
||||
v1.setName("vvvvvv");
|
||||
|
||||
System.out.println(v1);
|
||||
System.out.println(v2);
|
||||
System.out.println("===============12312312312====================");
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.rczn.task;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class TestTask {
|
||||
Log log = LogFactory.getLog(TestTask.class);
|
||||
|
||||
@Scheduled(cron = "0 0/30 * * * ?")
|
||||
public void test() {
|
||||
System.out.println("This is a test task.");
|
||||
log.info("This is a test task.");
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.rczn.task;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class Video implements Cloneable{
|
||||
private String name;
|
||||
private LocalDateTime createTime;
|
||||
|
||||
public Video() {
|
||||
|
||||
}
|
||||
|
||||
public Video(String name, LocalDateTime createTime) {
|
||||
this.name = name;
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object clone() throws CloneNotSupportedException {
|
||||
return super.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Video{" +
|
||||
"name='" + name + '\'' +
|
||||
", createTime=" + createTime +
|
||||
'}';
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.rczn.utils;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class BeanFactoryUtils implements BeanFactoryPostProcessor {
|
||||
|
||||
private static ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
|
||||
BeanFactoryUtils.beanFactory = factory;
|
||||
}
|
||||
|
||||
// 获取Bean
|
||||
public static <T> T getBean(Class<T> clazz) {
|
||||
return beanFactory.getBean(clazz);
|
||||
}
|
||||
}
|
||||
@@ -27,11 +27,4 @@ public class JwtUtil {
|
||||
.asMap();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGFpbXMiOnsicGVybWlzc2lvbnMiOlsiMTExMSIsIjIyMiIsIjU1NSJdLCJpZCI6MywidXNlcm5hbWUiOiJzdHJpbmcifSwiZXhwIjoxNzc2NzE2NzAyfQ.ynjs9Ys0CxoZjRstjz3mjr3c6NYMFiV3MmTGQYpJmKQ";//genToken(null);
|
||||
System.out.println(token);
|
||||
Map<String, Object> claims = parseToken(token);
|
||||
System.out.println(claims);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
package com.rczn.websocket;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.websocket.*;
|
||||
import jakarta.websocket.server.PathParam;
|
||||
import jakarta.websocket.server.ServerEndpoint;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
@Component
|
||||
@ServerEndpoint("/websocket/{userId}")
|
||||
public class WebSocketServer {
|
||||
Log log = LogFactory.getLog(WebSocketServer.class);
|
||||
|
||||
//springboot自带json转换器
|
||||
private static ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
//存放每个连接对象
|
||||
private static CopyOnWriteArraySet<WebSocketServer> webSockets = new CopyOnWriteArraySet<>();
|
||||
private Session session;
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 连接建立成功调用的方法
|
||||
* @param session
|
||||
* @param userId
|
||||
*/
|
||||
@OnOpen
|
||||
public void onOpen(Session session, @PathParam("userId") Long userId) {
|
||||
this.session = session;
|
||||
this.userId = userId;
|
||||
webSockets.add(this);
|
||||
log.info("有新连接加入!当前在线人数为" + webSockets.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接关闭调用的方法
|
||||
*/
|
||||
@OnClose
|
||||
public void onClose(){
|
||||
webSockets.remove(this);
|
||||
log.info("有连接关闭!当前在线人数为" + webSockets.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* 收到客户端消息后调用的方法
|
||||
* @OnMessage
|
||||
* @param message 客户端发送过来的消息
|
||||
* @param session
|
||||
*/
|
||||
@OnMessage
|
||||
public void onMessage(String message,Session session){
|
||||
log.info("收到来自客户端的消息:" + message);
|
||||
}
|
||||
|
||||
@OnError
|
||||
public void onError(Session session, Throwable error) {
|
||||
log.error("发生错误:"+error.getStackTrace());
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
* @param message
|
||||
* @throws IOException
|
||||
*/
|
||||
public void sendMessage(String message) throws IOException {
|
||||
this.session.getBasicRemote().sendText(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1 @@
|
||||
##spring.application.name=rczn-common
|
||||
#spring:
|
||||
# ai:
|
||||
# openai:
|
||||
# api-key: "sk-b2b55f0bc7e140668e0326c0cc7a86df" #sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
# base-url: "https://api.deepseek.com"
|
||||
# chat:
|
||||
# options:
|
||||
# model: "deepseek-chat"
|
||||
# # 关键:给语音模型也配置上,就不报错了
|
||||
# speech:
|
||||
# api-key: "sk-b2b55f0bc7e140668e0326c0cc7a86df"
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.rczn.rczncommon;
|
||||
|
||||
//import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class RcznCommonApplicationTests {
|
||||
|
||||
// @Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user