2026-4-30添加更新

This commit is contained in:
朱春声99
2026-04-30 15:27:06 +08:00
parent 7f5211c703
commit 2e9928725b
74 changed files with 6207 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
package com.rczn.rcznautoplc.cache;
import java.util.HashMap;
import java.util.Map;
/**
* 1-功能岛>plc地址
* 2-动作单元>plc地址
* 3-参数名字>plc地址
* 三个映射关系Map表
*/
public class IsLandActionParamToPlc {
// 1-功能岛>plc地址:key-功能岛idvalue-功能岛plc地址
public static final Map<Integer, Integer> islandToPlc = new HashMap<>();
// 2-动作单元>plc地址:key-动作单元idvalue-动作单元plc地址
public static final Map<Integer, Integer> actionToPlc = new HashMap<>();
// 3-参数名字>plc地址:key-参数名字value-参数plc地址
public static final Map<String, Integer> paramToPlc = new HashMap<>();
//4-参数id>plc地址:key-参数idvalue-参数plc地址
public static final Map<Integer,Integer> paramIdToPlc = new HashMap<>();
//更新三种数据的方法
//获取spring里面bean
//1-功能岛>plc地址
}

View File

@@ -0,0 +1,110 @@
package com.rczn.rcznautoplc.cache;
//样品准备状态
public class PlcRunStatus {
//定容岛:状态属性:
public static int goodsScanStatus = 0; //货物扫描:0-准备1-扫描完毕
//plc系统运行状态
public static int systemPlcRunStatus = 0; //系统准备:0-未准备1-空闲2-忙4异常
public static int goodsCount = 0;//样品处理数量
public static int goodsCurrentIndex = 0;//当前样品处理索引
//404内照射项目默认样品尿液液体
public static String defaultGoodsName = "尿液";
public static String defaultGoodsType = "液体";
//目标监测物
public static String defaultGoalDetect = "总氮";
public static class PlcRunStatusResponse{
private int goodsScanStatus = 0; //货物扫描:0-准备1-扫描完毕
private int systemPlcRunStatus = 0; //系统准备:0-未准备1-空闲2-忙4异常
private int goodsCount = 0;//样品处理数量
private int goodsCurrentIndex = 0;//当前样品处理索引
private String defaultGoodsName = "尿液";//默认样品名称
private String defaultGoodsType = "液体";//默认样品类型
private String defaultGoalDetect = "总氮";//默认目标监测物
public PlcRunStatusResponse() {
}
public PlcRunStatusResponse(int goodsScanStatus, int systemPlcRunStatus, int goodsCount, int goodsCurrentIndex, String defaultGoodsName, String defaultGoodsType, String defaultGoalDetect) {
this.goodsScanStatus = goodsScanStatus;
this.systemPlcRunStatus = systemPlcRunStatus;
this.goodsCount = goodsCount;
this.goodsCurrentIndex = goodsCurrentIndex;
this.defaultGoodsName = defaultGoodsName;
this.defaultGoodsType = defaultGoodsType;
this.defaultGoalDetect = defaultGoalDetect;
}
public int getGoodsScanStatus() {
return goodsScanStatus;
}
public void setGoodsScanStatus(int goodsScanStatus) {
this.goodsScanStatus = goodsScanStatus;
}
public int getSystemPlcRunStatus() {
return systemPlcRunStatus;
}
public void setSystemPlcRunStatus(int systemPlcRunStatus) {
this.systemPlcRunStatus = systemPlcRunStatus;
}
public int getGoodsCount() {
return goodsCount;
}
public void setGoodsCount(int goodsCount) {
this.goodsCount = goodsCount;
}
public int getGoodsCurrentIndex() {
return goodsCurrentIndex;
}
public void setGoodsCurrentIndex(int goodsCurrentIndex) {
this.goodsCurrentIndex = goodsCurrentIndex;
}
public String getDefaultGoodsName() {
return defaultGoodsName;
}
public void setDefaultGoodsName(String defaultGoodsName) {
this.defaultGoodsName = defaultGoodsName;
}
public String getDefaultGoodsType() {
return defaultGoodsType;
}
public void setDefaultGoodsType(String defaultGoodsType) {
this.defaultGoodsType = defaultGoodsType;
}
public String getDefaultGoalDetect() {
return defaultGoalDetect;
}
public void setDefaultGoalDetect(String defaultGoalDetect) {
this.defaultGoalDetect = defaultGoalDetect;
}
}
}

View File

@@ -0,0 +1,17 @@
package com.rczn.rcznautoplc.cache;
public class RegisterAddrDic {
//主PLC寄存器地址
public final static int goodsScanRegisterArr = 5000;//样品扫描状态寄存器地址:
//整体运转状态:
public final static int wholeRunStatusRegisterArr = 1100;//整体运转状态寄存器地址:
//协议存储地址:
//1-下发plc样品sop指令协议寄存器地址
public final static int downProtcolRegisterArr = 2000;//协议存储寄存器地址:
//2-接收plc处理样品状态数据协议寄存器地址
public final static int upProtcolRegisterArr = 3000;//协议存储寄存器地址:
}

View File

@@ -0,0 +1,120 @@
package com.rczn.rcznautoplc.controller;
import com.rczn.domain.PageBean;
import com.rczn.domain.Result;
import com.rczn.rcznautoplc.domain.ManageLog;
import com.rczn.rcznautoplc.service.ManageLogService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
@RestController
@RequestMapping("/manage-log")
@Tag(name = "操作日志管理", description = "操作日志增删改查+分页查询接口")
public class ManageLogController {
@Autowired
private ManageLogService manageLogService;
/**
* 分页查询日志
*/
@GetMapping(value = "/listPage", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "分页查询操作日志", description = "支持多条件筛选,空条件自动忽略")
@Parameters({
@Parameter(name = "pageNum", description = "页码(必填)", required = true, example = "1", in = ParameterIn.QUERY),
@Parameter(name = "pageSize", description = "每页条数(必填)", required = true, example = "10", in = ParameterIn.QUERY),
@Parameter(name = "logName", description = "日志名称(可选,模糊查询)", required = false, example = "登录操作", in = ParameterIn.QUERY),
@Parameter(name = "logType", description = "日志类型(可选,精准查询)", required = false, example = "LOGIN", in = ParameterIn.QUERY),
@Parameter(name = "createId", description = "创建人ID可选", required = false, example = "1", in = ParameterIn.QUERY),
@Parameter(name = "logWritetimeStart", description = "日志开始时间可选格式yyyy-MM-dd HH:mm:ss", required = false, example = "2025-01-01 00:00:00", in = ParameterIn.QUERY),
@Parameter(name = "logWritetimeEnd", description = "日志结束时间可选格式yyyy-MM-dd HH:mm:ss", required = false, example = "2025-12-31 23:59:59", in = ParameterIn.QUERY)
})
public Result<PageBean<ManageLog>> getLogPage(
@RequestParam Integer pageNum,
@RequestParam Integer pageSize,
@RequestParam(required = false) String logName,
@RequestParam(required = false) String logType,
@RequestParam(required = false) Long createId,
@RequestParam(required = false)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
LocalDateTime logWritetimeStart,
@RequestParam(required = false)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
LocalDateTime logWritetimeEnd) {
// 构建查询条件(空字段自动忽略)
ManageLog query = new ManageLog();
query.setLogName(logName);
query.setLogType(logType);
query.setCreateId(createId);
// 扩展字段用于时间范围查询实体类无需新增字段MyBatis 支持直接取参)
query.setStartTime(logWritetimeStart); // 实际用 logWritetimeStart这里仅为传递参数
query.setEndTime(logWritetimeEnd);
PageBean<ManageLog> pageBean = manageLogService.selectPage(pageNum, pageSize, query);
return Result.success(pageBean);
}
/**
* 按 ID 查询日志
*/
@GetMapping(value = "/getById/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "查询单个操作日志", description = "按日志ID查询详情")
public Result getLogById(@PathVariable Long id) {
ManageLog log = manageLogService.selectById(id);
return log != null ? Result.success(log) : Result.error("日志不存在或已删除");
}
/**
* 新增操作日志
*/
@PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "新增操作日志", description = "日志名称、类型为必填项,其他字段可选")
public Result addLog(@RequestBody ManageLog manageLog) {
try {
Long logId = manageLogService.insert(manageLog);
return Result.success("日志新增成功");
} catch (IllegalArgumentException e) {
return Result.error(e.getMessage());
}
}
/**
* 更新操作日志
*/
@PutMapping(value = "/update", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "更新操作日志", description = "需传入日志ID其他字段非空则更新")
public Result updateLog(@RequestBody ManageLog manageLog) {
try {
Boolean success = manageLogService.update(manageLog);
return success ? Result.success( "日志更新成功") : Result.error("更新失败(日志不存在或已删除)");
} catch (IllegalArgumentException e) {
return Result.error(e.getMessage());
}
}
/**
* 逻辑删除操作日志
*/
@DeleteMapping(value = "/del/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "删除操作日志", description = "逻辑删除设置delSign=1不物理删除")
public Result deleteLog(
@PathVariable Long id,
@RequestParam(required = false) Long updateId) {
try {
Boolean success = manageLogService.deleteById(id, updateId);
return success ? Result.success("日志删除成功") : Result.error("删除失败(日志不存在或已删除)");
} catch (IllegalArgumentException e) {
return Result.error(e.getMessage());
}
}
}

View File

@@ -0,0 +1,337 @@
package com.rczn.rcznautoplc.controller;
import com.rczn.domain.Result;
import com.rczn.modbus.Modbus4jWriteUtils;
import com.rczn.rcznautoplc.cache.PlcRunStatus;
import com.rczn.rcznautoplc.domain.*;
import com.rczn.rcznautoplc.domain.query.StepInfoQuery;
import com.rczn.rcznautoplc.service.*;
import com.rczn.rcznautoplc.utils.PlcConnectMap;
import com.rczn.utils.ThreadLocalUtil;
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 io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 设备信息 ControllerRESTful API
*/
@RestController
@RequestMapping("/plc")
@Tag(name = "plc设备控制类", description = "plc设备初始化查询控制方法集合")
public class PlcController {
@Autowired
private PlcService plcService;
/**
* 设备连接
*/
@PostMapping(value = "/connect", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "连接设备", description = "连接设备...")
public Result plcConnect(
@ParameterObject
@Schema(description = "plc设备参数")
ModbusConnectObj connectObj) {
ModbusMaster connectorInit;
if(PlcConnectMap.modbusConnectorMap.containsKey(connectObj.getIpAddr())){
return Result.error("设备连接已经存在!");
}
try {
connectorInit = plcService.connectModbus(connectObj);
if(connectorInit != null){
return Result.success(true);
}else {
return Result.error("设备连接失败!");
}
} catch (Exception e) {
return Result.error("设备连接失败!");
}
}
/**
* 向plc寄存器写数据
*/
@PostMapping(value = "/plcWrite", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "连接设备", description = "连接设备...")
public Result plcWrite(
@ParameterObject
@Schema(description = "plc设备参数")
ModbusConnectObj connectObj,
@Parameter
@Schema(description = "寄存器地址", required = true, example = "10000")
@RequestParam int registerAddress,
@Parameter
@Schema(description = "寄存器值", required = true, example = "12345")
@RequestParam int registerValue) {
ModbusMaster connectorInit;
if(PlcConnectMap.modbusConnectorMap.containsKey(connectObj.getIpAddr())){
connectorInit = PlcConnectMap.modbusConnectorMap.get(connectObj.getIpAddr());
try {
Modbus4jWriteUtils.writeHoldingRegister(connectorInit,1,registerAddress,registerValue, DataType.TWO_BYTE_INT_UNSIGNED);
} catch (ModbusTransportException e) {
throw new RuntimeException(e);
} catch (ErrorResponseException e) {
throw new RuntimeException(e);
} catch (ModbusInitException e) {
throw new RuntimeException(e);
}
return Result.error("设备连接已经存在!");
}
try {
connectorInit = plcService.connectModbus(connectObj);
if(connectorInit != null){
//往地址1000里面写入数据
Modbus4jWriteUtils.writeHoldingRegister(connectorInit,1,registerAddress,registerValue, DataType.TWO_BYTE_INT_UNSIGNED);
return Result.success(true);
}else {
return Result.error("设备连接失败!");
}
} catch (Exception e) {
return Result.error("设备连接失败!");
}
}
/**
* 根据ID删除设备逻辑删除
*/
@PostMapping(value = "/run")
@Operation(summary = "运行plc", description = "plc设备运行停止")
public Result runPlc(
@Parameter(name = "ipAddr", description = "设备ip地址", required = true, example = "192.168.1.123")
@RequestParam String ipAddr) {
try {
Boolean success = plcService.startPlc(ipAddr);
return Result.success(success);
} catch (Exception e) {
return Result.error("停止失败!");
}
}
/**
* 根据ID删除设备逻辑删除
*/
@PostMapping(value = "/pause")
@Operation(summary = "暂停运行plc", description = "暂停运行plc")
public Result pausePlc(
@Parameter(name = "ipAddr", description = "设备ip地址", required = true, example = "192.168.1.123")
@RequestParam String ipAddr) {
try {
Boolean success = plcService.pausePlc(ipAddr);
return Result.success(success);
} catch (Exception e) {
return Result.error("停止失败!");
}
}
/**
* 根据设备ip地址停止执行
*/
@PostMapping(value = "/stop")
@Operation(summary = "停止plc", description = "plc设备运行停止")
public Result stop(
@Parameter(name = "ipAddr", description = "设备ip地址", required = true, example = "192.168.1.123")
@RequestParam String ipAddr) {
try {
Boolean success = plcService.stopPlc(ipAddr);
return Result.success(success);
} catch (Exception e) {
return Result.error("停止失败!");
}
}
/**
* 根据plc ip地址故障复位
*/
@PostMapping(value = "/resetError")
@Operation(summary = "plc设备复位故障", description = "plc设备复位故障")
public Result resetError(
@Parameter(name = "ipAddr", description = "设备ip地址", required = true, example = "192.168.1.123")
@RequestParam String ipAddr) {
try {
Boolean success = plcService.resetErrorPlc(ipAddr);
return Result.success(success);
} catch (Exception e) {
return Result.error("停止失败!");
}
}
/**
* 根据plc ip地址获取plc设备状态
*/
@GetMapping(value = "/plcStatus")
@Operation(summary = "plc设备获取状态值", description = "状态值10-就绪11-执行中12-暂停中19已停止20-故障中")
public Result plcStatus(
@Parameter(name = "ipAddr", description = "设备ip地址", required = true, example = "192.168.1.123")
@RequestParam String ipAddr) {
try {
Integer resultValue = plcService.getPlcStatus(ipAddr);
return Result.success(resultValue);
} catch (Exception e) {
return Result.error("停止失败!");
}
}
/**
* 根据plc ip地址获取plc设备状态
*/
@GetMapping(value = "/mastertPlcStatus")
@Operation(summary = "获取主plc状态对象", description = "goodsScanStatus = 0; //货物扫描:0-准备1-扫描完毕;//系统准备:0-未准备1-空闲2-忙4异常")
public Result mastertPlcStatus() {
try {
PlcRunStatus.PlcRunStatusResponse response = new PlcRunStatus.PlcRunStatusResponse();
response.setGoodsScanStatus(PlcRunStatus.goodsScanStatus);
response.setSystemPlcRunStatus(PlcRunStatus.systemPlcRunStatus);
response.setGoodsCount(PlcRunStatus.goodsCount);
response.setGoodsCurrentIndex(PlcRunStatus.goodsCurrentIndex);
response.setDefaultGoodsName(PlcRunStatus.defaultGoodsName);
response.setDefaultGoodsType(PlcRunStatus.defaultGoodsType);
response.setDefaultGoalDetect(PlcRunStatus.defaultGoalDetect);
return Result.success(response);
} catch (Exception e) {
return Result.error("停止失败!");
}
}
/**
* 根据plc ip地址设置plc设备模式
* 0-手动模式1-自动模式
*/
@PostMapping(value = "/setModel")
@Operation(summary = "plc设备设置模式", description = "模式值0-手动模式1-自动模式")
public Result setModel(
@Parameter(name = "ipAddr", description = "设备ip地址", required = true, example = "192.168.1.123", in = ParameterIn.QUERY)
@RequestParam String ipAddr,
@Parameter(name = "model", description = "设备模式值", required = true, example = "0-1", in = ParameterIn.QUERY)
@RequestParam Integer model) {
try {
Boolean resultValue = plcService.setPlcModel(ipAddr,model);
return Result.success(resultValue);
} catch (Exception e) {
return Result.error("停止失败!");
}
}
/**
* 根据plc ip地址获取plc设备模式
* 0-手动模式1-自动模式
*/
@GetMapping(value = "/getModel")
@Operation(summary = "plc设备获取模式值", description = "模式值0-手动模式1-自动模式")
public Result getModel(
@Parameter(name = "ipAddr", description = "设备ip地址", required = true, example = "192.168.1.123")
@RequestParam String ipAddr) {
try {
Integer resultValue = plcService.getPlcModel(ipAddr);
return Result.success(resultValue);
} catch (Exception e) {
return Result.error("停止失败!");
}
}
/**
* 更新设备
*/
@GetMapping(value = "/getAll", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "获取全部plc连接对象", description = "获取全部plc连接对象")
public Result getPlcAll() {
Map<String,ModbusMaster> connectorMap = plcService.modbusALlMap();
return Result.success(connectorMap);
}
/**
* 根据ID查询设备
*/
@GetMapping(value = "/getPlcByIp", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "更加ip地址查询plc连接对象", description = "更加ip地址查询plc连接对象")
public Result getConnectByIpaddr(
@Parameter(name = "ipAddr", description = "设备IP", required = true, example = "192.168.1.123")
@RequestParam String ipAddr) {
ModbusMaster connector = plcService.getModbusConnect(ipAddr);
return Result.success(connector);
}
/**
* 查询所有设备(不分页)
*/
@PostMapping(value = "/doAction", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "调用plc设备执行动作", description = "根据plc设备ip执行动作")
public Result doAction(
@RequestParam String ip,
@RequestParam String action
) {
Boolean aBoolean = plcService.doAction(ip, action);
return Result.success(aBoolean);
}
@Autowired
StepInfoService stepInfoService;
@Autowired
GoodsInfoService goodsInfoService;
@Autowired
ManageLogService manageLogService;
@PostMapping(value = "/runFlow")
@Operation(summary = "为样品执行国标" ,description = "为样品执行国标")
public Result doStandGoods(
@RequestParam String plcIp,
@RequestParam Integer flowId,
@RequestParam List<Integer> goodsIds
){
//根据flowId获取步骤信息表
StepInfoQuery stepInfo = new StepInfoQuery();
stepInfo.setFlowId(flowId);
List<StepInfo> stepInfoList = stepInfoService.selectList(stepInfo);
//stepInfoList根据StepInfo里面的stepOrderint排序
stepInfoList.sort(Comparator.comparing(StepInfo::getStepOrder));
//根据goodsIds获取样品信息的 bar_code编码列表
List<GoodsInfo> goodsInfoList = goodsInfoService.selectByIdList(goodsIds);
List<String> barCodeList = goodsInfoList.stream().map(GoodsInfo::getBarCode).collect(Collectors.toList());
Boolean aBoolean = plcService.runSopInfoForGoodsList(plcIp,flowId, barCodeList, stepInfoList);
//记录操作样品执行SOP操作日志
LocalDateTime loginTime = LocalDateTime.now();
ManageLog info = new ManageLog();
// ========== 修复开始 ==========
Map<String, Object> mapClaims = ThreadLocalUtil.get();
UserBusy userBusy = new UserBusy();
userBusy.setId(Long.valueOf( mapClaims.get("id").toString()));
userBusy.setUserName((String) mapClaims.get("username"));
// ========== 修复结束 ==========
info.setCreateId(userBusy.getId());
info.setLogName("SOP操作日志");
info.setLogType("SOP操作日志");//1登录日志、2SOP操作日志、3基础数据操作日志
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("用户名:").append(userBusy.getUserName()).append("SOP执行操作时间").append(loginTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
info.setLogContent(stringBuilder.toString());
info.setCreateTime(loginTime);
manageLogService.insert(info);
return Result.success(aBoolean);
}
}

View File

@@ -0,0 +1,23 @@
package com.rczn.rcznautoplc.controller;
import com.rczn.websocket.WebSocketServer;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/websocket")
@Tag(name = "websocket", description = "websocket接口")
public class WebSocketController {
@Autowired
private WebSocketServer webSocketServer;
@RequestMapping("/send/{message}")
public String send(@PathVariable("message") String message){
webSocketServer.onMessage(message,null);
return "success";
}
}

View File

@@ -0,0 +1,65 @@
package com.rczn.rcznautoplc.domain;
import com.rczn.domain.BaseBean;
import java.time.LocalDateTime;
public class ManageLog extends BaseBean {
private String logName;
private String logType;
private LocalDateTime logWritetime;
private String logContent;
public ManageLog() {
}
public ManageLog(Long id, Long createId, LocalDateTime createTime, Long updateId, LocalDateTime updateTime, boolean delSign, String remark) {
super(id, createId, createTime, updateId, updateTime, delSign, remark);
}
@Override
public String toString() {
return "ManageLog{" +
"logName='" + logName + '\'' +
", logType='" + logType + '\'' +
", logWritetime=" + logWritetime +
", logContent='" + logContent + '\'' +
'}';
}
public String getLogName() {
return logName;
}
public void setLogName(String logName) {
this.logName = logName;
}
public String getLogType() {
return logType;
}
public void setLogType(String logType) {
this.logType = logType;
}
public LocalDateTime getLogWritetime() {
return logWritetime;
}
public void setLogWritetime(LocalDateTime logWritetime) {
this.logWritetime = logWritetime;
}
public String getLogContent() {
return logContent;
}
public void setLogContent(String logContent) {
this.logContent = logContent;
}
}

View File

@@ -0,0 +1,85 @@
package com.rczn.rcznautoplc.domain;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.github.s7connector.api.S7Connector;
import com.serotonin.modbus4j.ModbusMaster;
public class ModbusConnectObj {
/**
* ip地址
*/
private String ipAddr;
/**
* 端口号
*/
private Integer port;
/**
* 机架号
*/
private Integer rack;
/**
* 插槽
*/
private Integer slot;
/**
* 是否是主机
*/
private Boolean host;
public ModbusConnectObj(String ipAddr, Integer port, Integer rack, Integer slot,Boolean host) {
this.ipAddr = ipAddr;
this.port = port;
this.rack = rack;
this.slot = slot;
this.host = host;
}
public ModbusConnectObj() {
}
public String getIpAddr() {
return ipAddr;
}
public void setIpAddr(String ipAddr) {
this.ipAddr = ipAddr;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
public Integer getRack() {
return rack;
}
public void setRack(Integer rack) {
this.rack = rack;
}
public Integer getSlot() {
return slot;
}
public void setSlot(Integer slot) {
this.slot = slot;
}
public Boolean getHost() {
return host;
}
public void setHost(Boolean host) {
this.host = host;
}
}

View File

@@ -0,0 +1,84 @@
package com.rczn.rcznautoplc.domain;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.github.s7connector.api.S7Connector;
public class PlcConnectObj {
/**
* ip地址
*/
private String ipAddr;
/**
* 端口号
*/
private Integer port;
/**
* 机架号
*/
private Integer rack;
/**
* 插槽
*/
private Integer slot;
/**
* 连接对象
*/
@JsonBackReference
private S7Connector connector;
public PlcConnectObj(String ipAddr, Integer port, Integer rack, Integer slot, S7Connector connector) {
this.ipAddr = ipAddr;
this.port = port;
this.rack = rack;
this.slot = slot;
this.connector = connector;
}
public PlcConnectObj() {
}
public String getIpAddr() {
return ipAddr;
}
public void setIpAddr(String ipAddr) {
this.ipAddr = ipAddr;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
public Integer getRack() {
return rack;
}
public void setRack(Integer rack) {
this.rack = rack;
}
public Integer getSlot() {
return slot;
}
public void setSlot(Integer slot) {
this.slot = slot;
}
public S7Connector getConnector() {
return connector;
}
public void setConnector(S7Connector connector) {
this.connector = connector;
}
}

View File

@@ -0,0 +1,111 @@
package com.rczn.rcznautoplc.domain;
import com.rczn.domain.BaseBean;
import java.time.LocalDateTime;
public class UserBusy extends BaseBean {
private Long id;
private String userName;
private String password;
private String salt;
private String nicke;
private Boolean sex; // 0-女, 1-男
private String emailAddr;
private String address;
public UserBusy() {
}
public UserBusy(Long id, Long createId, LocalDateTime createTime, Long updateId, LocalDateTime updateTime, boolean delSign, String remark) {
super(id, createId, createTime, updateId, updateTime, delSign, remark);
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", password='" + password + '\'' +
", salt='" + salt + '\'' +
", nicke='" + nicke + '\'' +
", sex=" + sex +
", emailAddr='" + emailAddr + '\'' +
", address='" + address + '\'' +
'}';
}
@Override
public Long getId() {
return id;
}
@Override
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
public String getNicke() {
return nicke;
}
public void setNicke(String nicke) {
this.nicke = nicke;
}
public Boolean getSex() {
return sex;
}
public void setSex(Boolean sex) {
this.sex = sex;
}
public String getEmailAddr() {
return emailAddr;
}
public void setEmailAddr(String emailAddr) {
this.emailAddr = emailAddr;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}

View File

@@ -0,0 +1,122 @@
package com.rczn.rcznautoplc.domain.query;
public class DevInfoQuery {
//功能岛外键
private Integer islandId;
//设备名称
private String devName;
//设备型号
private String devModel;
//plc映射地址
private Integer plcAddr;
//设备IP地址
private String ipAddr;
private Integer port;
private String protocolType;
private String company;
private Integer status; // 0-空闲1-运行4-故障
private Integer runModel;//0-手动模式1-自动模式
private String devDesc;
public DevInfoQuery() {
}
public Integer getIslandId() {
return islandId;
}
public void setIslandId(Integer islandId) {
this.islandId = islandId;
}
public String getDevName() {
return devName;
}
public void setDevName(String devName) {
this.devName = devName;
}
public String getDevModel() {
return devModel;
}
public void setDevModel(String devModel) {
this.devModel = devModel;
}
public Integer getPlcAddr() {
return plcAddr;
}
public void setPlcAddr(Integer plcAddr) {
this.plcAddr = plcAddr;
}
public String getIpAddr() {
return ipAddr;
}
public void setIpAddr(String ipAddr) {
this.ipAddr = ipAddr;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
public String getProtocolType() {
return protocolType;
}
public void setProtocolType(String protocolType) {
this.protocolType = protocolType;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Integer getRunModel() {
return runModel;
}
public void setRunModel(Integer runModel) {
this.runModel = runModel;
}
public String getDevDesc() {
return devDesc;
}
public void setDevDesc(String devDesc) {
this.devDesc = devDesc;
}
}

View File

@@ -0,0 +1,87 @@
package com.rczn.rcznautoplc.domain.query;
public class DevParamQuery {
private String devIds;
private Integer devId;
private String paramName;
private String paramValue;
private String paramTypeData;
private String paramUnit;
private String formType;
private String paramDesc;
public DevParamQuery() {
}
public Integer getDevId() {
return devId;
}
public void setDevId(Integer devId) {
this.devId = devId;
}
public String getDevIds() {
return devIds;
}
public void setDevIds(String devIds) {
this.devIds = devIds;
}
public String getParamName() {
return paramName;
}
public void setParamName(String paramName) {
this.paramName = paramName;
}
public String getParamValue() {
return paramValue;
}
public void setParamValue(String paramValue) {
this.paramValue = paramValue;
}
public String getParamTypeData() {
return paramTypeData;
}
public void setParamTypeData(String paramTypeData) {
this.paramTypeData = paramTypeData;
}
public String getParamUnit() {
return paramUnit;
}
public void setParamUnit(String paramUnit) {
this.paramUnit = paramUnit;
}
public String getFormType() {
return formType;
}
public void setFormType(String formType) {
this.formType = formType;
}
public String getParamDesc() {
return paramDesc;
}
public void setParamDesc(String paramDesc) {
this.paramDesc = paramDesc;
}
}

View File

@@ -0,0 +1,75 @@
package com.rczn.rcznautoplc.domain.query;
import com.rczn.domain.BaseBean;
import com.rczn.rcznautoplc.domain.FlowInfo;
import com.rczn.rcznautoplc.domain.IslandInfo;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDateTime;
public class GoodsFlowStatusQuery {
private Integer goodsId;
private Integer flowId;
private Integer islandId;
private Integer devId;
private Integer flowSort;
private Integer status; // 0-未执行1-执行10-通过11-失败
public GoodsFlowStatusQuery() {
}
public Integer getGoodsId() {
return goodsId;
}
public void setGoodsId(Integer goodsId) {
this.goodsId = goodsId;
}
public Integer getFlowId() {
return flowId;
}
public void setFlowId(Integer flowId) {
this.flowId = flowId;
}
public Integer getIslandId() {
return islandId;
}
public void setIslandId(Integer islandId) {
this.islandId = islandId;
}
public Integer getFlowSort() {
return flowSort;
}
public void setFlowSort(Integer flowSort) {
this.flowSort = flowSort;
}
public Integer getDevId() {
return devId;
}
public void setDevId(Integer devId) {
this.devId = devId;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
}

View File

@@ -0,0 +1,125 @@
package com.rczn.rcznautoplc.domain.query;
import com.rczn.domain.BaseBean;
import java.time.LocalDateTime;
public class GoodsInfoQuery extends BaseBean{
private String goodsName;
private String goodsType;
private LocalDateTime incomeTime;
private String goodFrom;
private Integer goodBatch;
private Integer pointNum;
//目标监测物
private String goalDetect;
//条码
private String barCode;
//国标id
private Integer flowId;
private Integer goodsStatus;
private String desc;
public GoodsInfoQuery() {
}
public String getGoodsName() {
return goodsName;
}
public void setGoodsName(String goodsName) {
this.goodsName = goodsName;
}
public String getGoodsType() {
return goodsType;
}
public void setGoodsType(String goodsType) {
this.goodsType = goodsType;
}
public LocalDateTime getIncomeTime() {
return incomeTime;
}
public void setIncomeTime(LocalDateTime incomeTime) {
this.incomeTime = incomeTime;
}
public String getGoodFrom() {
return goodFrom;
}
public void setGoodFrom(String goodFrom) {
this.goodFrom = goodFrom;
}
public Integer getGoodBatch() {
return goodBatch;
}
public void setGoodBatch(Integer goodBatch) {
this.goodBatch = goodBatch;
}
public Integer getPointNum() {
return pointNum;
}
public void setPointNum(Integer pointNum) {
this.pointNum = pointNum;
}
public String getGoalDetect() {
return goalDetect;
}
public void setGoalDetect(String goalDetect) {
this.goalDetect = goalDetect;
}
public String getBarCode() {
return barCode;
}
public void setBarCode(String barCode) {
this.barCode = barCode;
}
public Integer getFlowId() {
return flowId;
}
public void setFlowId(Integer flowId) {
this.flowId = flowId;
}
public Integer getGoodsStatus() {
return goodsStatus;
}
public void setGoodsStatus(Integer goodsStatus) {
this.goodsStatus = goodsStatus;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}

View File

@@ -0,0 +1,60 @@
package com.rczn.rcznautoplc.domain.query;
import com.rczn.domain.BaseBean;
public class IslandInfoQuery {
private String islandName;
private String islandCode;
//plc映射地址
private Integer plcAddr;
private String islandLogo;
private String desc;
public IslandInfoQuery() {
}
public String getIslandName() {
return islandName;
}
public void setIslandName(String islandName) {
this.islandName = islandName;
}
public String getIslandCode() {
return islandCode;
}
public void setIslandCode(String islandCode) {
this.islandCode = islandCode;
}
public Integer getPlcAddr() {
return plcAddr;
}
public void setPlcAddr(Integer plcAddr) {
this.plcAddr = plcAddr;
}
public String getIslandLogo() {
return islandLogo;
}
public void setIslandLogo(String islandLogo) {
this.islandLogo = islandLogo;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}

View File

@@ -0,0 +1,84 @@
package com.rczn.rcznautoplc.domain.query;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.rczn.domain.BaseBean;
import com.rczn.rcznautoplc.domain.IslandInfo;
import java.time.LocalDateTime;
public class IslandParamQuery {
private Integer islandId;
private Integer stepId;
private String paramName;
private String paramType;
private String paramUnit;
private String paramValue;
private String formType;
public IslandParamQuery() {
}
public Integer getIslandId() {
return islandId;
}
public void setIslandId(Integer islandId) {
this.islandId = islandId;
}
public Integer getStepId() {
return stepId;
}
public void setStepId(Integer stepId) {
this.stepId = stepId;
}
public String getParamName() {
return paramName;
}
public void setParamName(String paramName) {
this.paramName = paramName;
}
public String getParamType() {
return paramType;
}
public void setParamType(String paramType) {
this.paramType = paramType;
}
public String getParamUnit() {
return paramUnit;
}
public void setParamUnit(String paramUnit) {
this.paramUnit = paramUnit;
}
public String getParamValue() {
return paramValue;
}
public void setParamValue(String paramValue) {
this.paramValue = paramValue;
}
public String getFormType() {
return formType;
}
public void setFormType(String formType) {
this.formType = formType;
}
}

View File

@@ -0,0 +1,118 @@
package com.rczn.rcznautoplc.domain.query;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.rczn.domain.BaseBean;
import com.rczn.rcznautoplc.domain.IslandInfo;
import java.time.LocalDateTime;
public class StepInfoQuery {
private Integer islandId;
//设备id
private Integer devId;
private Integer flowId;
private String paramName;
private String paramType;
private String paramUnit;
private String paramValue;
private String formType;
private Integer stepOrder;
private String stepName;
private String stepDesc;
public StepInfoQuery() {
}
public Integer getFlowId() {
return flowId;
}
public void setFlowId(Integer flowId) {
this.flowId = flowId;
}
public Integer getDevId() {
return devId;
}
public void setDevId(Integer devId) {
this.devId = devId;
}
public String getParamName() {
return paramName;
}
public void setParamName(String paramName) {
this.paramName = paramName;
}
public String getParamType() {
return paramType;
}
public void setParamType(String paramType) {
this.paramType = paramType;
}
public String getParamUnit() {
return paramUnit;
}
public void setParamUnit(String paramUnit) {
this.paramUnit = paramUnit;
}
public String getParamValue() {
return paramValue;
}
public void setParamValue(String paramValue) {
this.paramValue = paramValue;
}
public String getFormType() {
return formType;
}
public void setFormType(String formType) {
this.formType = formType;
}
public Integer getIslandId() {
return islandId;
}
public void setIslandId(Integer islandId) {
this.islandId = islandId;
}
public Integer getStepOrder() {
return stepOrder;
}
public void setStepOrder(Integer stepOrder) {
this.stepOrder = stepOrder;
}
public String getStepName() {
return stepName;
}
public void setStepName(String stepName) {
this.stepName = stepName;
}
public String getStepDesc() {
return stepDesc;
}
public void setStepDesc(String stepDesc) {
this.stepDesc = stepDesc;
}
}

View File

@@ -0,0 +1,27 @@
package com.rczn.rcznautoplc.mapper;
import com.rczn.rcznautoplc.domain.ManageLog;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper // 标记为 MyBatis Mapper 接口,确保被 Spring 扫描
public interface ManageLogMapper {
// 新增日志(支持空字段,空字段用数据库默认值)
int insert(ManageLog manageLog);
// 逻辑删除日志(按 ID设置 delSign=1
int deleteById(Long id);
// 更新日志(仅更新非空字段,空字段不更新)
int update(ManageLog manageLog);
// 按 ID 查询日志(仅查未删除数据)
ManageLog selectById(Long id);
// 分页查询日志(支持按字段筛选,空字段忽略条件)
List<ManageLog> selectPage(ManageLog manageLog);
// 查询分页总数(与分页查询条件一致)
Long selectTotal(ManageLog manageLog);
}

View File

@@ -0,0 +1,21 @@
package com.rczn.rcznautoplc.service;
import com.rczn.domain.PageBean;
import com.rczn.rcznautoplc.domain.ManageLog;
public interface ManageLogService {
// 新增日志
Long insert(ManageLog manageLog);
// 逻辑删除日志
Boolean deleteById(Long id, Long updateId);
// 更新日志(仅更新非空字段)
Boolean update(ManageLog manageLog);
// 按 ID 查询日志
ManageLog selectById(Long id);
// 分页查询日志(支持多条件筛选)
PageBean<ManageLog> selectPage(Integer pageNum, Integer pageSize, ManageLog manageLog);
}

View File

@@ -0,0 +1,125 @@
package com.rczn.rcznautoplc.service;
import com.github.s7connector.api.S7Connector;
import com.rczn.rcznautoplc.domain.ModbusConnectObj;
import com.rczn.rcznautoplc.domain.PlcConnectObj;
import com.rczn.rcznautoplc.domain.StepInfo;
import com.rczn.rcznautoplc.utils.PlcConnectMap;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import java.util.List;
import java.util.Map;
public interface PlcService {
/**
* 连接plc设备
* @param connectObj-
* @return
*/
PlcConnectObj connect(PlcConnectObj connectObj);
/**
* 连接modbus设备
* @param connectObj-
* @return
*/
ModbusMaster connectModbus(ModbusConnectObj connectObj) throws ModbusInitException, ModbusTransportException;
/**
* 启动plc设备
* @param ipAddr-
* @return
*/
Boolean startPlc(String ipAddr);
/**
* plc设备暂停运行
* @param ipAddr-
* @return
*/
Boolean pausePlc(String ipAddr);
/**
* plc设备故障复位
* @param ipAddr-
* @return
*/
Boolean resetErrorPlc(String ipAddr);
/**
* 根据ip地址获取plc设备状态值
* 0-未连接1-连接11-执行12-暂停19暂停20-故障复位
* @param ipAddr
* @return
*/
Integer getPlcStatus(String ipAddr);
/**
* 根据ip地址设置plc设备模式
* 0-手动1-自动
* @param ipAddr
* @return
*/
Boolean setPlcModel(String ipAddr,Integer modelValue);
/**
* 根据ip地址获取plc设备模式值
* 0-手动1-自动
* @param ipAddr
* @return
*/
Integer getPlcModel(String ipAddr);
/**
* 根据ip地址获取modbus连接设备
*
* @param ipAddr
* @return
*/
public ModbusMaster getModbusConnect(String ipAddr);
/**
* 根据ip地址获取plc设备
* @param ipAddr
* @return
*/
S7Connector getPlc(String ipAddr);
/**
* 获取全部plc连接对象
* @return
*/
Map<String,S7Connector> plcALlMap();
/**
* 获取全部plc连接对象
*
* @return
*/
public Map<String, ModbusMaster> modbusALlMap();
/**
* 执行plc动作
* @param ipAddr
* @param action
* @return
*/
Boolean doAction(String ipAddr,String action);
/**
* 停止plc运行
* @param ipAddr
* @return
*/
Boolean stopPlc(String ipAddr);
/**
* 执行sop信息
* @param sopId
* @param barCodeList
* @param stepInfoList
* @return
*/
Boolean runSopInfoForGoodsList(String plcIp, Integer sopId, List<String> barCodeList,List<StepInfo> stepInfoList);
}

View File

@@ -0,0 +1,85 @@
package com.rczn.rcznautoplc.service.impl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.rczn.domain.PageBean;
import com.rczn.rcznautoplc.domain.ManageLog;
import com.rczn.rcznautoplc.mapper.ManageLogMapper;
import com.rczn.rcznautoplc.service.ManageLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class ManageLogServiceImpl implements ManageLogService {
@Autowired
private ManageLogMapper manageLogMapper;
@Override
public Long insert(ManageLog manageLog) {
// 校验必填字段(日志名称和类型为必填)
Assert.notNull(manageLog.getLogName(), "日志名称不能为空");
Assert.notNull(manageLog.getLogType(), "日志类型不能为空");
//补充日志时间
if (manageLog.getLogWritetime() == null) {
manageLog.setLogWritetime(LocalDateTime.now());
}
// TODO 补充日志创建人信息
// manageLog.setCreateId(null);
manageLog.setCreateTime(LocalDateTime.now());
int rows = manageLogMapper.insert(manageLog);
return rows > 0 ? manageLog.getId() : null;
}
@Override
public Boolean deleteById(Long id, Long updateId) {
Assert.notNull(id, "日志ID不能为空");
int rows = manageLogMapper.deleteById(id);
return rows > 0;
}
@Override
public Boolean update(ManageLog manageLog) {
Assert.notNull(manageLog.getId(), "日志ID不能为空");
//如果更新时间为空,则自动更新
if (manageLog.getUpdateTime() == null) {
manageLog.setUpdateTime(LocalDateTime.now());
}
// TODO 补充日志更新人信息
// manageLog.setUpdateId(null);
int rows = manageLogMapper.update(manageLog);
return rows > 0;
}
@Override
public ManageLog selectById(Long id) {
Assert.notNull(id, "日志ID不能为空");
return manageLogMapper.selectById(id);
}
@Override
public PageBean<ManageLog> selectPage(Integer pageNum, Integer pageSize, ManageLog manageLog) {
// 校验分页参数
Assert.notNull(pageNum, "页码不能为空");
Assert.notNull(pageSize, "每页条数不能为空");
Assert.isTrue(pageNum > 0, "页码必须大于0");
Assert.isTrue(pageSize > 0 && pageSize <= 100000, "每页条数必须在1-10000之间");
// PageHelper 分页(自动拦截查询,添加 LIMIT 条件)
PageHelper.startPage(pageNum, pageSize);
List<ManageLog> logList = manageLogMapper.selectPage(manageLog);
Page<ManageLog> page = (Page<ManageLog>) logList;
PageBean<ManageLog> pageBean = new PageBean<>();
pageBean.setTotal(page.getTotal());
pageBean.setItems(page.getResult());
// 封装PageBean返回
return pageBean;
}
}

View File

@@ -0,0 +1,499 @@
package com.rczn.rcznautoplc.service.impl;
import com.github.s7connector.api.S7Connector;
import com.github.s7connector.api.factory.S7ConnectorFactory;
import com.rczn.ModbusCmdConst;
import com.rczn.modbus.Modbus4jUtils;
import com.rczn.modbus.Modbus4jWriteUtils;
import com.rczn.plc_common.S7ConnectorPLC;
import com.rczn.rcznautoplc.cache.IsLandActionParamToPlc;
import com.rczn.rcznautoplc.cache.PlcRunStatus;
import com.rczn.rcznautoplc.cache.RegisterAddrDic;
import com.rczn.rcznautoplc.domain.*;
import com.rczn.rcznautoplc.domain.query.DevInfoQuery;
import com.rczn.rcznautoplc.domain.query.DevParamQuery;
import com.rczn.rcznautoplc.domain.query.IslandInfoQuery;
import com.rczn.rcznautoplc.service.DevInfoService;
import com.rczn.rcznautoplc.service.DevParamService;
import com.rczn.rcznautoplc.service.IslandInfoService;
import com.rczn.rcznautoplc.service.PlcService;
import com.rczn.rcznautoplc.utils.PlcCommonProtcolUtil;
import com.rczn.rcznautoplc.utils.PlcConnectMap;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import java.util.*;
@Service
public class PlcServiceImpl implements PlcService {
// 核心创建log对象private static final名称固定为log
private static final Logger log = LoggerFactory.getLogger(PlcServiceImpl.class);
// Log log = LogFactory.getLog(PlcServiceImpl.class);
/**
* 连接plc设备
*
* @param connectObj -
* @return
*/
@Override
public PlcConnectObj connect(PlcConnectObj connectObj) {
S7ConnectorPLC plc = new S7ConnectorPLC();
// S7Connector connector = plc.initConnect(connectObj.getIpAddr(), connectObj.getPort(), connectObj.getRack(), connectObj.getSlot());
S7Connector connector = S7ConnectorFactory.buildTCPConnector().build();
connectObj.setConnector(connector);
PlcConnectMap.plcConnectorMap.put(connectObj.getIpAddr(),connector);
return connectObj;
}
/**
* 连接modbus设备
*
* @param connectObj -
* @return
*/
@Override
public ModbusMaster connectModbus(ModbusConnectObj connectObj) throws ModbusInitException, ModbusTransportException {
//初始化modbus连接对象
ModbusMaster modbusMaster = Modbus4jUtils.getAndTestMaster(connectObj.getIpAddr(), connectObj.getPort());
//以ip地址为键值保存连接对象modbusMaster
PlcConnectMap.modbusConnectorMap.put(connectObj.getIpAddr(),modbusMaster);
if(connectObj.getHost()){
PlcConnectMap.masterModbusConnector = modbusMaster;
}
return modbusMaster;
}
/**
* 启动plc设备
*
* @param ipAddr -
* @return
*/
@Override
public Boolean startPlc(String ipAddr) {
// S7Connector connector = PlcConnectMap.plcConnectorMap.get(ipAddr);
// byte[] cmdByte = new byte[4];
// connector.write(DaveArea.DB,1,1,cmdByte);
// S7Connector connector = PlcConnectMap.plcConnectorMap.get(ipAddr);
// byte[] cmdBytes = {(byte)(ModbusCmdConst.plc_run>>8),(byte)ModbusCmdConst.plc_run};
// if(connector != null){
// connector.write(DaveArea.DB,1,0,cmdBytes);
// }
ModbusMaster modbusMaster = PlcConnectMap.modbusConnectorMap.get(ipAddr);
if(modbusMaster!=null){
try {
Modbus4jWriteUtils.writeRegister(modbusMaster,1,1,(short) ModbusCmdConst.plc_run);
return true;
} catch (ModbusTransportException e) {
throw new RuntimeException(e);
} catch (ModbusInitException e) {
throw new RuntimeException(e);
}
}
return false;
}
/**
* plc设备暂停运行
*
* @param ipAddr -
* @return
*/
@Override
public Boolean pausePlc(String ipAddr) {
// S7Connector connector = PlcConnectMap.plcConnectorMap.get(ipAddr);
// byte[] cmdByte = new byte[4];
// connector.write(DaveArea.DB,1,1,cmdByte);
// S7Connector connector = PlcConnectMap.plcConnectorMap.get(ipAddr);
// byte[] cmdBytes = {(byte)(ModbusCmdConst.plc_run>>8),(byte)ModbusCmdConst.plc_run};
// if(connector != null){
// connector.write(DaveArea.DB,1,0,cmdBytes);
// }
ModbusMaster modbusMaster = PlcConnectMap.modbusConnectorMap.get(ipAddr);
if(modbusMaster!=null){
try {
Modbus4jWriteUtils.writeRegister(modbusMaster,1,1,(short) ModbusCmdConst.plc_pause);
return true;
} catch (ModbusTransportException e) {
throw new RuntimeException(e);
} catch (ModbusInitException e) {
throw new RuntimeException(e);
}
}
return false;
}
/**
* plc设备故障复位
*
* @param ipAddr -
* @return
*/
@Override
public Boolean resetErrorPlc(String ipAddr) {
// S7Connector connector = PlcConnectMap.plcConnectorMap.get(ipAddr);
// byte[] cmdByte = new byte[4];
// connector.write(DaveArea.DB,1,1,cmdByte);
// S7Connector connector = PlcConnectMap.plcConnectorMap.get(ipAddr);
// byte[] cmdBytes = {(byte)(ModbusCmdConst.plc_run>>8),(byte)ModbusCmdConst.plc_run};
// if(connector != null){
// connector.write(DaveArea.DB,1,0,cmdBytes);
// }
ModbusMaster modbusMaster = PlcConnectMap.modbusConnectorMap.get(ipAddr);
if(modbusMaster!=null){
try {
Modbus4jWriteUtils.writeRegister(modbusMaster,1,1,(short) ModbusCmdConst.plc_ready);
return true;
} catch (ModbusTransportException e) {
throw new RuntimeException(e);
} catch (ModbusInitException e) {
throw new RuntimeException(e);
}
}
return false;
}
/**
* 根据ip地址获取plc设备状态值
* 0-未连接1-连接10-就绪11-执行12-暂停19暂停20-故障复位
*
* @param ipAddr
* @return
*/
@Override
public Integer getPlcStatus(String ipAddr) {
// S7Connector connector = PlcConnectMap.plcConnectorMap.get(ipAddr);
// byte[] cmdBytes = {(byte)(ModbusCmdConst.plc_run>>8),(byte)ModbusCmdConst.plc_run};
// if(connector != null){
// connector.write(DaveArea.DB,1,0,cmdBytes);
// }
ModbusMaster modbusMaster = PlcConnectMap.modbusConnectorMap.get(ipAddr);
if(modbusMaster!=null){
try {
Number number = Modbus4jUtils.readHoldingRegister(modbusMaster, 1, 1, DataType.TWO_BYTE_INT_UNSIGNED);
return number.intValue();
} catch (ModbusTransportException e) {
throw new RuntimeException(e);
} catch (ErrorResponseException e) {
throw new RuntimeException(e);
} catch (ModbusInitException e) {
throw new RuntimeException(e);
}
}
return -1;
}
/**
* 根据ip地址设置plc设备模式
* 0-手动1-自动
*
* @param ipAddr
* @param modelValue
* @return
*/
@Override
public Boolean setPlcModel(String ipAddr, Integer modelValue) {
// S7Connector connector = PlcConnectMap.plcConnectorMap.get(ipAddr);
// byte[] cmdBytes = {(byte)(ModbusCmdConst.plc_run>>8),(byte)ModbusCmdConst.plc_run};
// if(connector != null){
// connector.write(DaveArea.DB,1,0,cmdBytes);
// }
ModbusMaster modbusMaster = PlcConnectMap.modbusConnectorMap.get(ipAddr);
if(modbusMaster!=null){
try {
Modbus4jWriteUtils.writeRegister(modbusMaster,1,0,(short) modelValue.intValue());
return true;
} catch (ModbusTransportException e) {
throw new RuntimeException(e);
} catch (ModbusInitException e) {
throw new RuntimeException(e);
}
}
return false;
}
/**
* 根据ip地址获取plc设备模式值
* 0-手动1-自动
*
* @param ipAddr
* @return
*/
@Override
public Integer getPlcModel(String ipAddr) {
// S7Connector connector = PlcConnectMap.plcConnectorMap.get(ipAddr);
// byte[] cmdBytes = {(byte)(ModbusCmdConst.plc_run>>8),(byte)ModbusCmdConst.plc_run};
// if(connector != null){
// connector.write(DaveArea.DB,1,0,cmdBytes);
// }
ModbusMaster modbusMaster = PlcConnectMap.modbusConnectorMap.get(ipAddr);
if(modbusMaster!=null){
try {
Number number = Modbus4jUtils.readHoldingRegister(modbusMaster, 1, 0, DataType.TWO_BYTE_INT_UNSIGNED);
if(number.intValue() != 0 && number.intValue()!=1){
number = 0;
}
return number.intValue();
} catch (ModbusTransportException e) {
throw new RuntimeException(e);
} catch (ErrorResponseException e) {
throw new RuntimeException(e);
} catch (ModbusInitException e) {
throw new RuntimeException(e);
}
}
return -1;
}
/**
* 根据ip地址获取plc设备
*
* @param ipAddr
* @return
*/
@Override
public S7Connector getPlc(String ipAddr) {
return PlcConnectMap.plcConnectorMap.get(ipAddr);
}
/**
* 根据ip地址获取modbus连接设备
*
* @param ipAddr
* @return
*/
@Override
public ModbusMaster getModbusConnect(String ipAddr) {
return PlcConnectMap.modbusConnectorMap.get(ipAddr);
}
/**
* 获取全部plc连接对象
*
* @return
*/
@Override
public Map<String, S7Connector> plcALlMap() {
return PlcConnectMap.plcConnectorMap;
}
/**
* 获取全部plc连接对象
*
* @return
*/
@Override
public Map<String, ModbusMaster> modbusALlMap() {
return PlcConnectMap.modbusConnectorMap;
}
/**
* 执行plc动作
*
* @param ipAddr
* @param action
* @return
*/
@Override
public Boolean doAction(String ipAddr, String action) {
// S7Connector connector = PlcConnectMap.plcConnectorMap.get(ipAddr);
// byte[] cmdBytes = new byte[5];
// connector.write(DaveArea.DB,1,1,cmdBytes);
// S7Connector connector = PlcConnectMap.plcConnectorMap.get(ipAddr);
// byte[] cmdBytes = {(byte)(ModbusCmdConst.plc_run>>8),(byte)ModbusCmdConst.plc_run};
// if(connector != null){
// connector.write(DaveArea.DB,1,0,cmdBytes);
// }
ModbusMaster modbusMaster = PlcConnectMap.modbusConnectorMap.get(ipAddr);
if(modbusMaster!=null){
try {
Modbus4jWriteUtils.writeRegister(modbusMaster,1,1,(short) ModbusCmdConst.plc_run);
return true;
} catch (ModbusTransportException e) {
throw new RuntimeException(e);
} catch (ModbusInitException e) {
throw new RuntimeException(e);
}
}
return false;
}
/**
* 停止plc运行
*
* @param ipAddr
* @return
*/
@Override
public Boolean stopPlc(String ipAddr) {
// S7Connector connector = PlcConnectMap.plcConnectorMap.get(ipAddr);
// byte[] cmdBytes = new byte[5];
// connector.write(DaveArea.DB,1,1,cmdBytes);
// S7Connector connector = PlcConnectMap.plcConnectorMap.get(ipAddr);
// byte[] cmdBytes = {(byte)(ModbusCmdConst.plc_run>>8),(byte)ModbusCmdConst.plc_run};
// if(connector != null){
// connector.write(DaveArea.DB,1,0,cmdBytes);
// }
ModbusMaster modbusMaster = PlcConnectMap.modbusConnectorMap.get(ipAddr);
if(modbusMaster!=null){
try {
Modbus4jWriteUtils.writeRegister(modbusMaster,1,1,(short) ModbusCmdConst.plc_stop);
return true;
} catch (ModbusTransportException e) {
throw new RuntimeException(e);
} catch (ModbusInitException e) {
throw new RuntimeException(e);
}
}
return false;
}
@Autowired
IslandInfoService islandInfoService;
@Autowired
DevInfoService devInfoService;
@Autowired
DevParamService devParamService;
/**
* 执行sop信息
*
* @param sopId
* @param barCodeList
* @param stepInfoList
* @return
*/
@Override
public Boolean runSopInfoForGoodsList(String plcIp,Integer sopId, List<String> barCodeList, List<StepInfo> stepInfoList) {
// 1. 空值校验提前拦截null避免线程内空指针
if (barCodeList == null || barCodeList.isEmpty() || stepInfoList == null || stepInfoList.isEmpty()) {
log.warn("样品编码列表或步骤信息列表为空无需执行PLC动作");
return false;
}
//更新一次功能岛、动作单元、参数对应plc映射地址缓存
List<IslandInfo> islandInfos = islandInfoService.selectList(new IslandInfoQuery());
IsLandActionParamToPlc.islandToPlc.clear();
for (int i = 0; i < islandInfos.size(); i++) {
IslandInfo islandInfo = islandInfos.get(i);
IsLandActionParamToPlc.islandToPlc.put(islandInfo.getId().intValue(),islandInfo.getPlcAddr());
}
List<DevInfo> devInfos = devInfoService.getDevInfoList(new DevInfoQuery());
IsLandActionParamToPlc.actionToPlc.clear();
for (int i = 0; i < devInfos.size(); i++) {
DevInfo devInfo = devInfos.get(i);
IsLandActionParamToPlc.actionToPlc.put(devInfo.getId().intValue(),devInfo.getPlcAddr());
}
List<DevParam> devParams = devParamService.selectList(new DevParamQuery());
IsLandActionParamToPlc.paramToPlc.clear();
IsLandActionParamToPlc.paramIdToPlc.clear();
for (int i = 0; i < devParams.size(); i++) {
DevParam devParam = devParams.get(i);
IsLandActionParamToPlc.paramToPlc.put(devParam.getParamName(),devParam.getPlcAddr());
IsLandActionParamToPlc.paramIdToPlc.put(devParam.getId().intValue(),devParam.getPlcAddr());
}
//为stepInfoList排序根据StepInfo的step_order(int)字段
stepInfoList.sort(Comparator.comparingInt(StepInfo::getStepOrder));
// 2. 深拷贝集合:避免线程共享导致的并发修改问题
List<String> barCodeListCopy = new ArrayList<>(barCodeList);
List<StepInfo> stepInfoListCopy = new ArrayList<>(stepInfoList);
// 若StepInfo是自定义对象需保证深拷贝如果是浅拷贝对象属性仍会共享
// stepInfoListCopy = stepInfoList.stream().map(step -> 深拷贝StepInfo).collect(Collectors.toList());
// 3. 启动线程执行分组逻辑
new Thread(() -> {
try {
runSopInfoForGroup(plcIp,sopId,barCodeListCopy, stepInfoListCopy);
} catch (Exception e) {
// 4. 捕获线程内异常:避免线程静默失败
log.error("执行PLC分组任务失败", e);
}
}, "Sop-PLC-Thread-" + sopId).start(); // 给线程命名,便于日志排查
return true;
}
private void runSopInfoForGroup(String plcIp,Integer sopId,List<String> barCodeList, List<StepInfo> stepInfoList) throws InterruptedException {
//更新plc状态中的当前处理样品数量
PlcRunStatus.goodsCount = barCodeList.size();
PlcRunStatus.goodsCurrentIndex = 0;
// 5. 实现8个一组的分组逻辑核心业务补充
int groupSize = 8;
for (int i = 0; i < barCodeList.size(); i += groupSize) {
// 截取8个一组的子列表最后一组可能不足8个
int end = Math.min(i + groupSize, barCodeList.size());
List<String> subBarCodeList = barCodeList.subList(i, end);
//先判断PLC状态
while (true){
if(PlcRunStatus.systemPlcRunStatus == 1){
// 按分组执行PLC动作核心业务逻辑
executePlcActionByGroup(plcIp,sopId,subBarCodeList, stepInfoList);
//更新样品处理数量索引:
PlcRunStatus.goodsCurrentIndex += subBarCodeList.size();
break;
}
}
//暂停2.2秒,获取状态
Thread.sleep(2200);
//获取PLC整体状态
while (true){
if(PlcRunStatus.systemPlcRunStatus == 1){
//如果空闲
break;
}
}
}
}
// 补充按分组执行PLC动作的核心方法
private void executePlcActionByGroup(String plcIp,Integer sopId,List<String> subBarCodeList, List<StepInfo> stepInfoList) {
// 根据样品编码获取PLC设备
// 根据步骤信息执行PLC动作
log.info("执行PLC分组任务当前分组样品编码{}", subBarCodeList);
ModbusMaster modbusMaster = PlcConnectMap.modbusConnectorMap.get(plcIp);
if(modbusMaster!=null){
int startAddr = RegisterAddrDic.downProtcolRegisterArr;
//获取样品+sop序列协议
List<Byte> sopProtcol = PlcCommonProtcolUtil.getSopProtcol(sopId, subBarCodeList, stepInfoList);
//将协议写入PLC
ByteBuffer sopBuff = ByteBuffer.allocate(sopProtcol.size());
for (byte b1:
sopProtcol) {
sopBuff.put(b1);
}
ShortBuffer sopBuffShort = sopBuff.asShortBuffer();
try {
Modbus4jWriteUtils.writeRegisters(modbusMaster,1,startAddr, sopBuffShort.array());
} catch (ModbusTransportException e) {
throw new RuntimeException(e);
} catch (ModbusInitException e) {
throw new RuntimeException(e);
}
}else {
throw new RuntimeException("未找到对应的modbusMaster");
}
}
}

View File

@@ -0,0 +1,159 @@
package com.rczn.rcznautoplc.task;
import com.rczn.modbus.Modbus4jUtils;
import com.rczn.modbus.Modbus4jWriteUtils;
import com.rczn.rcznautoplc.cache.RegisterAddrDic;
import com.rczn.rcznautoplc.domain.GoodsFlowStatus;
import com.rczn.rcznautoplc.domain.GoodsInfo;
import com.rczn.rcznautoplc.service.GoodsFlowStatusService;
import com.rczn.rcznautoplc.service.GoodsInfoService;
import com.rczn.rcznautoplc.cache.PlcRunStatus;
import com.rczn.rcznautoplc.utils.PlcCommonProtcolUtil;
import com.rczn.rcznautoplc.utils.PlcConnectMap;
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 org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Component
public class PlcTask {
Log log = LogFactory.getLog(PlcTask.class);
//样品状态service
@Autowired
GoodsFlowStatusService goodsFlowStatusService;
//定时任务每2秒执行一次Cron 表达式支持 6 位(秒 分 时 日 月 周)或 7 位(秒 分 时 日 月 周 年)
@Scheduled(cron = "0/2 * * * * ?")
public void statusMonitor() throws ModbusInitException, ModbusTransportException, ErrorResponseException {
log.info("plc 设备状态监控.");
//判断是否有plc连接设备,
if(PlcConnectMap.masterModbusConnector != null ){
log.info("plc 主设备状态监控开始...");
//遍历连接对象
ModbusMaster connector = PlcConnectMap.masterModbusConnector;
//1-读取功能岛状态:
//1-1sop中第一个功能岛定容岛>10000(十进制):样品是否扫描完毕-0-10-未扫描完毕1-扫描完毕
Number scanReadyStatusNum = Modbus4jUtils.readHoldingRegister(connector, 1, 5000, DataType.TWO_BYTE_INT_UNSIGNED);
PlcRunStatus.goodsScanStatus = scanReadyStatusNum.intValue();
//判断如果扫描完成获取样品编码数据保存数据库修改plc寄存器状态值和修改索引状态
if(PlcRunStatus.goodsScanStatus == 1){
getGoodsInfoFromPlc( connector, PlcRunStatus.goodsScanStatus);
}
//查看plc的状态返回寄存器开头cc cc-有返回状态数据)
Number goodsStatusStart = Modbus4jUtils.readHoldingRegister(connector, 1, RegisterAddrDic.upProtcolRegisterArr, DataType.TWO_BYTE_INT_UNSIGNED);
if(goodsStatusStart.intValue() == 0xcccc){
//2-读取状态数据长度值
Number goodsStatusLength = Modbus4jUtils.readHoldingRegister(connector, 1, RegisterAddrDic.upProtcolRegisterArr+1, DataType.TWO_BYTE_INT_UNSIGNED);
//3-读取状态数据
Number[] goodsStatusArr = Modbus4jUtils.readHoldingRegisters(connector, 1, RegisterAddrDic.upProtcolRegisterArr, goodsStatusLength.intValue()/2+4, DataType.TWO_BYTE_INT_UNSIGNED);
//4-解析样品状态数据:把number数组数据转正List<byte>
List<Byte> goodsStatusByteList = new ArrayList<>();
for (Number goodsStatusNum:goodsStatusArr
) {
goodsStatusByteList.add((byte) (goodsStatusNum.intValue()>>8));
goodsStatusByteList.add((byte) (goodsStatusNum.intValue()&0xff));
}
List<GoodsFlowStatus> list = PlcCommonProtcolUtil.pareseProtcolStatus(goodsStatusByteList);
//5-插入数据库样品状态:
for (GoodsFlowStatus goodsFlowStatus:list
) {
goodsFlowStatusService.insert(goodsFlowStatus);
}
//6-清空寄存器数据:
Modbus4jWriteUtils.writeRegisters(connector,1,RegisterAddrDic.upProtcolRegisterArr, new short[goodsStatusLength.intValue()/2+4]);
}
//2-读取整个系统sop执行后状态0-未准备1-空闲2-忙4-异常
Number sopRunStatus = Modbus4jUtils.readHoldingRegister(connector, 1, 5500, DataType.TWO_BYTE_INT_UNSIGNED);
PlcRunStatus.systemPlcRunStatus = sopRunStatus.intValue();
}else {
log.info("plc 主设备未连接.");
}
}
@Autowired
GoodsInfoService goodsInfoService;
//任务:样品编码扫描完毕,读取
/**
* 异步执行样品信息读取(单独线程)
* @Async("plcAsyncExecutor") 指定使用自定义的PLC专用线程池
*/
@Async("plcAsyncExecutor")
public void getGoodsInfoFromPlc(ModbusMaster connector,int goodsScanStatus) {
try {
log.info("异步读取样品信息开始,线程名:" + Thread.currentThread().getName());
//10001-10032:32个槽位放置样品
//一个寄存器返回两个字节:是两个样品索引地址:
Number[] goodsIndexStatus = Modbus4jUtils.readHoldingRegisters(connector,1, 5001,16,DataType.TWO_BYTE_INT_UNSIGNED);
List<Integer> goodsIndexNumList = new ArrayList<>();
for (Number goodsIndexNum:goodsIndexStatus
) {
//一个寄存器返回值分成两个样品状态值:
int registerStatus = goodsIndexNum.intValue();
goodsIndexNumList.add(registerStatus>>8);
goodsIndexNumList.add(registerStatus&0xff);
}
// List<GoodsInfo> goodsInfoList = new ArrayList<>();
//当前时间:
LocalDateTime localDateTime = LocalDateTime.now();
//样品编码地址10033-1004810049-10063
for (int i = 0; i < goodsIndexNumList.size(); i++) {
int goodsIndexNum = goodsIndexNumList.get(i);
if (goodsIndexNum == 1) {
Number[] goodsCodeNumTemp = Modbus4jUtils.readHoldingRegisters(connector, 1, 10018 + i * 16,16, DataType.TWO_BYTE_INT_UNSIGNED);
StringBuilder goodCodeNumStr = new StringBuilder();
for (Number goodsIndexNumTemp:goodsCodeNumTemp){
goodCodeNumStr.append(goodsIndexNumTemp.intValue()>>8);
goodCodeNumStr.append(goodsIndexNumTemp.intValue()&0xff);
}
GoodsInfo goodsInfo = new GoodsInfo();
goodsInfo.setBarCode(goodCodeNumStr.toString());
goodsInfo.setPointNum(i+1);
goodsInfo.setGoodsName(PlcRunStatus.defaultGoodsName);
goodsInfo.setGoodsType(PlcRunStatus.defaultGoodsType);
goodsInfo.setGoalDetect(PlcRunStatus.defaultGoalDetect);
goodsInfo.setIncomeTime(localDateTime);
goodsInfo.setCreateTime(LocalDateTime.now());
// goodsInfoList.add(goodsInfo);
//获取的样品对象,保存到数据库,
goodsInfoService.insert(goodsInfo);
log.info("样品编码:" + goodCodeNumStr.toString() + ",样品索引:" + goodsIndexNum);
}
}
//修改寄存器样品索引值:
//10001-10032:16个寄存器每个寄存器两个样品状态值,修改样品索引值为0
short[] goodsRegisterValues = new short[16];
Modbus4jWriteUtils.writeRegisters(connector,1, 10001,goodsRegisterValues);
//修改10000寄存器的值为0
Modbus4jWriteUtils.writeHoldingRegister(connector,1, 10000,0,DataType.TWO_BYTE_INT_UNSIGNED);
// 此处可添加:保存数据到数据库、修改寄存器状态等业务逻辑
log.info("异步读取样品信息完成");
} catch (ModbusInitException | ModbusTransportException | ErrorResponseException e) {
// 捕获异步线程中的异常并记录日志(异步方法异常不会自动抛出到主线程)
log.error("异步读取样品信息失败", e);
}
}
}

View File

@@ -0,0 +1,282 @@
package com.rczn.rcznautoplc.utils;
import com.rczn.rcznautoplc.cache.IsLandActionParamToPlc;
import com.rczn.rcznautoplc.domain.GoodsFlowStatus;
import com.rczn.rcznautoplc.domain.GoodsInfo;
import com.rczn.rcznautoplc.domain.StepInfo;
import com.rczn.rcznautoplc.domain.query.GoodsInfoQuery;
import com.rczn.rcznautoplc.service.GoodsInfoService;
import com.rczn.utils.BeanFactoryUtils;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.*;
public class PlcCommonProtcolUtil {
// 样品SOP执行指令 开始字节(2) 总字节长度(2) SOP id号4 样品数量(1) 样品地址(16) 样品地址(16) 样品地址(16) ... 功能岛PLC(2) 动作PLC地址(2) 参数PLC地址(2) 参数值(2) ... 结束码
// CC CC 0011 11223344 16 0 1 2 AA+01 BB+01 CC+01 0011 EEEE
public static List<Byte> getSopProtcol(Integer sopId,List<String> subBarCodeList, List<StepInfo> stepInfoList) {
List<Byte> protcolByteList = new ArrayList<>();
Byte[] startByte = {(byte) 0xcc,(byte) 0xcc};
for (int i = 0; i < startByte.length; i++) {
protcolByteList.add(startByte[i]);
}
//后面修正数据
byte[] dataLength = new byte[2];
for (int i = 0; i < dataLength.length; i++) {
protcolByteList.add(dataLength[i]);
}
// sop id
byte[] sopIdByte = new byte[4];
sopIdByte[0] = (byte) (sopId >> 24);
sopIdByte[1] = (byte) (sopId >> 16);
sopIdByte[2] = (byte) (sopId >> 8);
sopIdByte[3] = (byte) sopId.intValue();
for (int i = 0; i < sopIdByte.length; i++) {
protcolByteList.add(sopIdByte[i]);
}
//样品数量
byte sampleNum = (byte) subBarCodeList.size();
protcolByteList.add(sampleNum);
//把样品地址写入协议字符串列表
for (int i = 0; i < subBarCodeList.size(); i++) {
String subBarCode = subBarCodeList.get(i);
//subBarCode是一系列数字字符串转成16个10进制数字需要兼容subBarCode长度超过或少于16的情况
byte[] sampleAddress = new byte[16];
for (int j = 0; j < subBarCode.length() && j < sampleAddress.length; j++) {
sampleAddress[j] = (byte) Integer.parseInt(subBarCode.substring(j, j + 1));
}
for (int j = 0; j < sampleAddress.length; j++) {
protcolByteList.add(sampleAddress[j]);
}
}
//stepInfoList列表按照StepInfo对象里面的Integer islandId属性
// 属性里面有stepOrder计算出有多少个连续的不同islandId属性值
//第一个stepInfo的islandId
StepInfo stepInfo_0 = stepInfoList.get(0);
// 1-第一个功能岛plc
Integer islandPlcIntV = IsLandActionParamToPlc.islandToPlc.get(stepInfo_0.getIslandId());
byte[] islandPlc_0 = new byte[2];
islandPlc_0[0] = (byte) 0xaa;
islandPlc_0[1] = (byte) islandPlcIntV.intValue();
for (int i = 0; i < islandPlc_0.length; i++) {
protcolByteList.add(islandPlc_0[i]);
}
//第一个动作单元plc
Integer actionPlcIntV = IsLandActionParamToPlc.actionToPlc.get(stepInfo_0.getDevId());
byte[] actionPlc_0 = new byte[2];
actionPlc_0[0] = (byte) 0xbb;
actionPlc_0[1] = (byte) actionPlcIntV.intValue();
for (int i = 0; i < actionPlc_0.length; i++) {
protcolByteList.add(actionPlc_0[i]);
}
//第一个参数单元plc
Integer paramPlcIntV = IsLandActionParamToPlc.paramToPlc.get(stepInfo_0.getParamName());
byte[] paramPlc_0 = new byte[2];
paramPlc_0[0] = (byte) 0xcc;
paramPlc_0[1] = (byte) paramPlcIntV.intValue();
for (int i = 0; i < paramPlc_0.length; i++) {
protcolByteList.add(paramPlc_0[i]);
}
//第一个参数值
int paramValueInt = Integer.parseInt(stepInfo_0.getParamValue());
byte[] paramValue_0 = new byte[2];
paramValue_0[0] = (byte) (paramValueInt>>8);
paramValue_0[1] = (byte) paramValueInt;
for (int i = 0; i < paramValue_0.length; i++) {
protcolByteList.add(paramValue_0[i]);
}
for (int i = 1; i < stepInfoList.size(); i++) {
// isLandId:1 order:1 => isLandId:1 order:2 => isLandId:2 order:3 => isLandId:2 order:4 => isLandId:3 order:5
StepInfo stepInfo = stepInfoList.get(i);
//判断是否更换功能岛
if (stepInfo.getIslandId() != stepInfo_0.getIslandId()) {
// 1-第一个功能岛plc
Integer islandPlcIntV_1 = IsLandActionParamToPlc.islandToPlc.get(stepInfo_0.getIslandId());
byte[] islandPlc_1 = new byte[2];
islandPlc_1[0] = (byte) 0xaa;
islandPlc_1[1] = (byte) islandPlcIntV_1.intValue();
for (int j = 0; j < islandPlc_1.length; j++) {
protcolByteList.add(islandPlc_1[j]);
}
//第一个动作单元plc
Integer actionPlcIntV_1 = IsLandActionParamToPlc.actionToPlc.get(stepInfo_0.getDevId());
byte[] actionPlc_1 = new byte[2];
actionPlc_1[0] = (byte) 0xbb;
actionPlc_1[1] = (byte) actionPlcIntV_1.intValue();
for (int j = 0; j < actionPlc_1.length; j++) {
protcolByteList.add(actionPlc_1[j]);
}
//第一个参数单元plc
Integer paramPlcIntV_1 = IsLandActionParamToPlc.paramToPlc.get(stepInfo_0.getParamName());
byte[] paramPlc_1 = new byte[2];
paramPlc_1[0] = (byte) 0xcc;
paramPlc_1[1] = (byte) paramPlcIntV.intValue();
for (int j = 0; j < paramPlc_1.length; j++) {
protcolByteList.add(paramPlc_1[j]);
}
//第一个参数值
int paramValueInt_1 = Integer.parseInt(stepInfo_0.getParamValue());
byte[] paramValue_1 = new byte[2];
paramValue_1[0] = (byte) (paramValueInt_1>>8);
paramValue_1[1] = (byte) paramValueInt_1;
for (int j = 0; j < paramValue_1.length; j++) {
protcolByteList.add(paramValue_1[j]);
}
}else if(stepInfo.getDevId()!= stepInfo_0.getDevId()){
//判断是否更换动作单元
//第一个动作单元plc
Integer actionPlcIntV_1 = IsLandActionParamToPlc.actionToPlc.get(stepInfo_0.getDevId());
byte[] actionPlc_1 = new byte[2];
actionPlc_1[0] = (byte) 0xbb;
actionPlc_1[1] = (byte) actionPlcIntV_1.intValue();
for (int j = 0; j < actionPlc_1.length; j++) {
protcolByteList.add(actionPlc_1[j]);
}
//第一个参数单元plc
Integer paramPlcIntV_1 = IsLandActionParamToPlc.paramToPlc.get(stepInfo_0.getParamName());
byte[] paramPlc_1 = new byte[2];
paramPlc_1[0] = (byte) 0xcc;
paramPlc_1[1] = (byte) paramPlcIntV.intValue();
for (int j = 0; j < paramPlc_1.length; j++) {
protcolByteList.add(paramPlc_1[j]);
}
//第一个参数值
int paramValueInt_1 = Integer.parseInt(stepInfo_0.getParamValue());
byte[] paramValue_1 = new byte[2];
paramValue_1[0] = (byte) (paramValueInt_1>>8);
paramValue_1[1] = (byte) paramValueInt_1;
for (int j = 0; j < paramValue_1.length; j++) {
protcolByteList.add(paramValue_1[j]);
}
}else {
//第一个参数单元plc
Integer paramPlcIntV_1 = IsLandActionParamToPlc.paramToPlc.get(stepInfo_0.getParamName());
byte[] paramPlc_1 = new byte[2];
paramPlc_1[0] = (byte) 0xcc;
paramPlc_1[1] = (byte) paramPlcIntV.intValue();
for (int j = 0; j < paramPlc_1.length; j++) {
protcolByteList.add(paramPlc_1[j]);
}
//第一个参数值
int paramValueInt_1 = Integer.parseInt(stepInfo_0.getParamValue());
byte[] paramValue_1 = new byte[2];
paramValue_1[0] = (byte) (paramValueInt_1>>8);
paramValue_1[1] = (byte) paramValueInt_1;
for (int j = 0; j < paramValue_1.length; j++) {
protcolByteList.add(paramValue_1[j]);
}
}
stepInfo_0 = stepInfo;
}
int dataLengthInt = protcolByteList.size();
protcolByteList.set(2, (byte) (dataLengthInt>>8));
protcolByteList.set(3, (byte) dataLengthInt);
byte[] endByte = {(byte) 0xee, (byte) 0xee};
protcolByteList.add(endByte[0]);
protcolByteList.add(endByte[1]);
return protcolByteList;
}
// 样品处理状态返回指令 开始字节(2) 总字节长度(2) SOP id号4 样品数量(4) 样品地址(4) 功能岛PLC(1) 动作PLC地址(1) 参数PLC地址(1) 检测值(2) 样品地址(4) 功能岛PLC(1) 动作PLC地址(1) 参数PLC地址(1) 检测值(2) ... crc校验 结束码
// CCCC 0011 11223344 16 0 1 1 1 0011 1 1 1 1 0011 XX EEEE
public static List<GoodsFlowStatus> pareseProtcolStatus(List<Byte> protcolByteList) {
//获取样品数据整理处理Map对象keybar_codevaluegoodsId
GoodsInfoService goodsInfoService = BeanFactoryUtils.getBean(GoodsInfoService.class);
List<GoodsInfo> goodsInfoList = goodsInfoService.selectList(new GoodsInfoQuery());
Map<String, Long> goodsInfoCodeIDMap = new HashMap<>();
for (GoodsInfo goodsInfo : goodsInfoList) {
goodsInfoCodeIDMap.put(goodsInfo.getBarCode(), goodsInfo.getId());
}
List<GoodsFlowStatus> goodsFlowStatusList = new ArrayList<>();
//sop id值
StringBuilder sopIdSb = new StringBuilder();
for (int i = 0; i < 4; i++) {
Byte sopByte = protcolByteList.get(3 + i);
sopIdSb.append(sopByte.intValue());
}
Integer sopId = Integer.parseInt(sopIdSb.toString());
byte goodsCount = protcolByteList.get(7);
for (int i = 0; i < goodsCount; i++) {
//样品扫描编码地址
StringBuilder goodsAddressSb = new StringBuilder();
for (int j = 0; j < 16; j++){
Byte addByte = protcolByteList.get(8 + i * 16 + j);
goodsAddressSb.append(addByte.intValue());
}
//功能岛PLC地址
byte isLandPlc = protcolByteList.get(8 + (i+1) * 16);
//动作单元plc地址
byte actionPlc = protcolByteList.get(8 + (i+1) * 16 + 1);
//参数plc地址
byte paramPlc = protcolByteList.get(8 + (i+1) * 16 + 2);
//检测值
byte[] checkValue = new byte[2];
for (int j = 0; j < checkValue.length; j++) {
checkValue[j] = protcolByteList.get(8 + (i+1) * 16 + 3 + j);
}
int checkValueInt = ByteBuffer.wrap(checkValue).order(ByteOrder.LITTLE_ENDIAN).getShort();
GoodsFlowStatus flowStatus = new GoodsFlowStatus();
Long goodsId = goodsInfoCodeIDMap.get(goodsAddressSb.toString());
flowStatus.setGoodsId(goodsId.intValue());
flowStatus.setFlowId(sopId);
for (Integer isLandId :
IsLandActionParamToPlc.islandToPlc.keySet()) {
Integer plcValue = IsLandActionParamToPlc.islandToPlc.get(isLandId);
if (plcValue == isLandPlc) {
flowStatus.setIslandId(isLandId);
break;
}
}
for (Integer actionId :
IsLandActionParamToPlc.actionToPlc.keySet()) {
Integer plcValue = IsLandActionParamToPlc.actionToPlc.get(actionId);
if (plcValue == actionPlc) {
flowStatus.setDevId(actionId);
break;
}
}
for (Integer paramId:
IsLandActionParamToPlc.paramIdToPlc.keySet()) {
Integer plcValue = IsLandActionParamToPlc.paramIdToPlc.get(paramId);
if (plcValue == paramPlc) {
flowStatus.setFlowSort(paramId);
break;
}
}
flowStatus.setStatus(checkValueInt);
//保存样品状态数据:
goodsFlowStatusList.add(flowStatus);
}
return goodsFlowStatusList;
}
}

View File

@@ -0,0 +1,24 @@
package com.rczn.rcznautoplc.utils;
import com.github.s7connector.api.S7Connector;
import com.rczn.rcznautoplc.domain.DevInfo;
import com.serotonin.modbus4j.ModbusMaster;
import java.util.HashMap;
import java.util.Map;
public class PlcConnectMap {
//PLC设备map对象keyipvalue设备
public static Map<String, DevInfo> plcDevMap = new HashMap<>();
//plc连接对象缓存
public static Map<String , S7Connector> plcConnectorMap = new HashMap<>();
//Modbus连接对象缓存
public static Map<String , ModbusMaster> modbusConnectorMap = new HashMap<>();
//主plc modbus连接对象:
public static ModbusMaster masterModbusConnector = null;
}

View File

@@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.rczn.rcznautoplc.mapper.ManageLogMapper">
<!-- 公共字段BaseBean 继承的字段) -->
<sql id="baseColumn">
id, create_id, create_time, update_id, update_time, del_sign, remark
</sql>
<!-- ManageLog 专属字段 -->
<sql id="logColumn">
log_name, log_type, log_writetime, log_content
</sql>
<!-- 结果集映射(关联数据库列与实体类字段) -->
<resultMap id="LogResultMap" type="com.rczn.rcznautoplc.domain.ManageLog">
<!-- 公共字段映射 -->
<id column="id" property="id"/>
<result column="create_id" property="createId"/>
<result column="create_time" property="createTime"/>
<result column="update_id" property="updateId"/>
<result column="update_time" property="updateTime"/>
<result column="del_sign" property="delSign"/>
<result column="remark" property="remark"/>
<!-- 专属字段映射 -->
<result column="log_name" property="logName"/>
<result column="log_type" property="logType"/>
<result column="log_writetime" property="logWritetime"/>
<result column="log_content" property="logContent"/>
</resultMap>
<!-- 1. 新增日志(空字段忽略,用数据库默认值) -->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO sys_manage_log (
<trim suffixOverrides=",">
<!-- 专属字段 -->
<if test="logName != null and logName != ''"> log_name,</if>
<if test="logType != null and logType != ''"> log_type,</if>
<if test="logWritetime != null"> log_writetime,</if>
<if test="logContent != null and logContent != ''"> log_content,</if>
<!-- 公共字段 -->
<if test="createId != null"> create_id,</if>
<if test="createTime != null"> create_time,</if>
<if test="updateId != null"> update_id,</if>
<if test="updateTime != null"> update_time,</if>
<if test="delSign != null"> del_sign,</if>
<if test="remark != null and remark != ''"> remark,</if>
</trim>
) VALUES (
<trim suffixOverrides=",">
<!-- 专属字段:空字段传递 null数据库设默认值 -->
<if test="logName != null and logName != ''">#{logName},</if>
<if test="logType != null and logType != ''">#{logType},</if>
<if test="logWritetime != null">#{logWritetime},</if>
<if test="logContent != null and logContent != ''">#{logContent},</if>
<!-- 公共字段:空字段传递 null数据库设默认值 -->
<if test="createId != null">#{createId},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateId != null">#{updateId},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="delSign != null">#{delSign},</if>
<if test="remark != null and remark != ''">#{remark},</if>
</trim>
)
</insert>
<!-- 2. 更新日志(仅更新非空字段) -->
<update id="update">
UPDATE sys_manage_log
<set>
<!-- 专属字段:非空才更新 -->
<if test="logName != null and logName != ''">log_name = #{logName},</if>
<if test="logType != null and logType != ''">log_type = #{logType},</if>
<if test="logWritetime != null">log_writetime = #{logWritetime},</if>
<if test="logContent != null and logContent != ''">log_content = #{logContent},</if>
<!-- 公共字段:非空才更新 -->
<if test="updateId != null">update_id = #{updateId},</if>
<if test="remark != null and remark != ''">remark = #{remark},</if>
<if test="delSign != null">del_sign = #{delSign},</if>
<!-- 强制更新时间为当前时间 -->
update_time = NOW()
</set>
WHERE id = #{id}
AND del_sign = 0 <!-- 仅更新未删除的数据 -->
</update>
<!-- 3. 逻辑删除日志 -->
<delete id="deleteById">
UPDATE sys_manage_log
SET
del_sign = 1,
update_time = NOW(),
<if test="updateId != null">update_id = #{updateId}</if>
WHERE id = #{id}
AND del_sign = 0 <!-- 避免重复删除 -->
</delete>
<!-- 4. 按 ID 查询日志 -->
<select id="selectById" resultMap="LogResultMap">
SELECT
<include refid="baseColumn"/>,
<include refid="logColumn"/>
FROM sys_manage_log
WHERE id = #{id}
AND del_sign = 0 <!-- 仅查未删除数据 -->
</select>
<!-- 5. 分页查询日志(空字段忽略条件) -->
<select id="selectPage" resultMap="LogResultMap" parameterType="com.rczn.rcznautoplc.domain.ManageLog">
SELECT
<include refid="baseColumn"/>,
<include refid="logColumn"/>
FROM sys_manage_log
<where>
<!-- 默认查未删除数据,传 delSign=1 可查已删除 -->
<if test="delSign == null">
AND del_sign = 0
</if>
<if test="delSign != null">
AND del_sign = #{delSign}
</if>
<!-- 日志名称:模糊查询,空字段忽略 -->
<if test="logName != null and logName != ''">
AND log_name LIKE CONCAT('%', #{logName}, '%')
</if>
<!-- 日志类型:精准查询,空字段忽略 -->
<if test="logType != null and logType != ''">
AND log_type = #{logType}
</if>
<!-- 日志写入时间:范围查询(可选,空字段忽略) -->
<if test="startTime != null">
AND log_writetime >= #{startTime}
</if>
<if test="endTime != null">
AND log_writetime &lt;= #{endTime}
</if>
<!-- 创建人ID精准查询空字段忽略 -->
<if test="createId != null">
AND create_id = #{createId}
</if>
</where>
ORDER BY log_writetime DESC <!-- 按日志写入时间倒序 -->
</select>
<!-- 6. 查询分页总数(与分页查询条件一致) -->
<select id="selectTotal" resultType="java.lang.Long" parameterType="com.rczn.rcznautoplc.domain.ManageLog">
SELECT COUNT(*)
FROM sys_manage_log
<where>
<if test="delSign == null">
AND del_sign = 0
</if>
<if test="delSign != null">
AND del_sign = #{delSign}
</if>
<if test="logName != null and logName != ''">
AND log_name LIKE CONCAT('%', #{logName}, '%')
</if>
<if test="logType != null and logType != ''">
AND log_type = #{logType}
</if>
<if test="logWritetimeStart != null">
AND log_writetime >= #{logWritetimeStart}
</if>
<if test="logWritetimeEnd != null">
AND log_writetime &lt;= #{logWritetimeEnd}
</if>
<if test="createId != null">
AND create_id = #{createId}
</if>
</where>
</select>
</mapper>

View File

@@ -0,0 +1,13 @@
package com.rczn.rcznautoplc;
import org.testng.annotations.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class RcznAutoplcApplicationTests {
// @Test
void contextLoads() {
}
}