package com.mes.prod; import com.mes.core.StationConfig; import com.mes.core.StationContext; import com.mes.device.IDeviceDriver; import com.mes.util.DateLocalUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** * 拉铆过程参数采集器 * 在WaitCompleteStep轮询中,检测finishedCount变化时从PLC读取过程参数 * 采集的数据暂存在内存队列中,由ProdDataUploader定时上传 */ public class ProdDataCollector { private static final Logger log = LoggerFactory.getLogger(ProdDataCollector.class); // 待上传的过程参数队列 private final List pendingRecords = new CopyOnWriteArrayList<>(); // 上一次的已打数量,用于检测变化 private volatile int lastFinishedCount = 0; private final StationConfig.ProdParamsConfig paramsConfig; public ProdDataCollector(StationConfig.ProdParamsConfig paramsConfig) { this.paramsConfig = paramsConfig; } /** * 在轮询中调用,检测finishedCount变化并采集过程参数 * @param context 工位上下文 * @param driver 设备驱动 * @param currentFinishedCount 当前已打数量 */ public void onPoll(StationContext context, IDeviceDriver driver, int currentFinishedCount) { if (paramsConfig == null || !paramsConfig.isEnabled()) { return; } // 检测已打数量是否增加 if (currentFinishedCount > lastFinishedCount) { lastFinishedCount = currentFinishedCount; String productSn = context.getProcessedProductSn(); if (productSn == null || productSn.trim().isEmpty()) { log.warn("[{}] 工件码为空,跳过过程参数采集", context.getStationCode()); return; } try { // 从PLC读取过程参数(Int32,除以1000得到实际值) String fout = driver.readInt32(paramsConfig.getFoutAddress()) / 1000 + ""; String sout = (float) driver.readInt32(paramsConfig.getSoutAddress()) / 1000 + ""; String fmin = driver.readInt32(paramsConfig.getFminAddress()) / 1000 + ""; String smin = (float) driver.readInt32(paramsConfig.getSminAddress()) / 1000 + ""; String fmax = driver.readInt32(paramsConfig.getFmaxAddress()) / 1000 + ""; String smax = (float) driver.readInt32(paramsConfig.getSmaxAddress()) / 1000 + ""; String qty = String.valueOf(driver.readRegister(paramsConfig.getQtyAddress())); // 构建记录 ProdRecord record = new ProdRecord(); record.setGw(context.getStationCode()); record.setLineSn(context.getLineSn()); record.setType("A"); record.setSn(productSn); record.setFout(fout); record.setSout(sout); record.setFmin(fmin); record.setSmin(smin); record.setFmax(fmax); record.setSmax(smax); record.setQty(qty); record.setSerialNumber(String.valueOf(currentFinishedCount)); record.setUcode(context.getUser()); record.setRecordTime(DateLocalUtils.getCurrentDateTime()); pendingRecords.add(record); log.info("[{}] 采集过程参数: 第{}钉, fout={}, sout={}, fmin={}, smin={}, fmax={}, smax={}", context.getStationCode(), currentFinishedCount, fout, sout, fmin, smin, fmax, smax); } catch (Exception e) { log.error("[{}] 采集过程参数失败: {}", context.getStationCode(), e.getMessage()); } } } /** * 获取并清空待上传的记录 */ public List drainRecords() { List records = new java.util.ArrayList<>(pendingRecords); pendingRecords.removeAll(records); return records; } /** * 将上传失败的记录放回队列 */ public void requeue(List records) { pendingRecords.addAll(0, records); } /** * 获取待上传记录数量 */ public int getPendingCount() { return pendingRecords.size(); } /** * 重置(新工件开始时调用) */ public void reset() { lastFinishedCount = 0; } }