LaserControllerDual.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. package com.mes.controller;
  2. import com.alibaba.fastjson2.JSON;
  3. import com.mes.device.LaserDevice;
  4. import com.mes.ui.MesClient;
  5. import com.mes.util.DateLocalUtils;
  6. import com.mes.util.JdbcUtils;
  7. import org.slf4j.Logger;
  8. import org.slf4j.LoggerFactory;
  9. import java.util.ArrayList;
  10. import java.util.List;
  11. /**
  12. * 激光切割双面控制器
  13. * 参考OP60双面逻辑
  14. */
  15. public class LaserControllerDual {
  16. private static final Logger log = LoggerFactory.getLogger(LaserControllerDual.class);
  17. private LaserDevice device;
  18. // A面状态机 0=未开始 1=已扫码等待启动 2=设备运行中 3=设备运行结束
  19. public static Integer tjFlaga = 0;
  20. public static String curSna = "";
  21. public static List<String> hjparamsA = new ArrayList<>();
  22. public static Integer tjStatusa = 0; // 1=提交失败
  23. public static Boolean mesQualityFlagA = false; // true=MES质检通过可工作
  24. // B面状态机
  25. public static Integer tjFlagb = 0;
  26. public static String curSnb = "";
  27. public static List<String> hjparamsB = new ArrayList<>();
  28. public static Integer tjStatusb = 0;
  29. public static Boolean mesQualityFlagB = false;
  30. public LaserControllerDual(LaserDevice device) {
  31. this.device = device;
  32. }
  33. /**
  34. * 状态检测(1秒调用1次,参考OP60的getPlcParam)
  35. */
  36. public void checkStatus() {
  37. try {
  38. if(!device.isConnected()) {
  39. return;
  40. }
  41. // A面状态检测
  42. checkStatusA();
  43. // B面状态检测
  44. checkStatusB();
  45. } catch (Exception e) {
  46. log.error("状态检测异常", e);
  47. }
  48. }
  49. /**
  50. * A面状态检测(参考OP60的getStatusA)
  51. * 完成判定只看 #1593==1(持续信号),不要求 working==1
  52. * 因为加工完成瞬间 #1591 会变 0、#1593 变 1,两者互斥
  53. */
  54. private void checkStatusA() {
  55. try {
  56. // 读取A面加工中状态 #1591
  57. int working = device.readWorking("A");
  58. if(tjFlaga == 1 && working == 1) {
  59. // 状态切换:1(等待启动)→ 2(运行中)
  60. tjFlaga = 2;
  61. log.info("A面检测到设备启动,开始采集参数");
  62. MesClient.pxstatus1.setText("A面运行中");
  63. // A面启动不清零#1590,保持允许信号给B面使用
  64. log.info("A面启动,保持#1590=1供B面使用");
  65. } else if(tjFlaga == 2) {
  66. // 运行中,检测是否完成(不看 working,因为完成瞬间 working 会变 0)
  67. int finish = device.readFinish("A");
  68. if(finish == 1) {
  69. // 状态切换:2(运行中)→ 3(完成)
  70. tjFlaga = 3;
  71. log.info("A面检测到设备完成(#1593=1)");
  72. MesClient.pxstatus1.setText("A面完成,提交中");
  73. // 保存剩余参数
  74. if(hjparamsA.size() > 0) {
  75. saveParams("A");
  76. }
  77. // 上传结果到MES
  78. boolean sendret = sendQuality(curSna, "OK", "A");
  79. if(!sendret) {
  80. tjStatusa = 1;
  81. log.error("A面结果上传MES失败");
  82. MesClient.pxstatus1.setText("A面上传失败");
  83. } else {
  84. log.info("A面结果上传成功,复位状态(不清零#1590,供B面使用)");
  85. resetStatusA();
  86. MesClient.pxstatus1.setText("A面提交成功");
  87. }
  88. // A面完成不清零#1590,让B面可以直接启动
  89. }
  90. }
  91. } catch (Exception e) {
  92. log.error("A面状态检测异常", e);
  93. }
  94. }
  95. /**
  96. * B面状态检测(参考OP60的getStatusB)
  97. * B面不需要扫码,利用A面的允许信号直接启动
  98. * B面完成后才清零#1590,为下一轮A面扫码准备
  99. */
  100. private void checkStatusB() {
  101. try {
  102. // 读取B面加工中状态 #1592
  103. int working = device.readWorking("B");
  104. if(tjFlagb == 0 && working == 1) {
  105. // B面直接启动(无需扫码,tjFlagb从0直接到2)
  106. tjFlagb = 2;
  107. log.info("B面检测到设备启动(无需扫码),开始采集参数");
  108. MesClient.pxstatus2.setText("B面运行中");
  109. } else if(tjFlagb == 2) {
  110. // 运行中,检测是否完成
  111. int finish = device.readFinish("B");
  112. if(finish == 1) {
  113. // 状态切换:2(运行中)→ 3(完成)
  114. tjFlagb = 3;
  115. log.info("B面检测到设备完成(#1594=1)");
  116. MesClient.pxstatus2.setText("B面完成,提交中");
  117. // 保存剩余参数
  118. if(hjparamsB.size() > 0) {
  119. saveParams("B");
  120. }
  121. // B面不提交MES结果,只管控A面
  122. log.info("B面完成,清零#1590禁止启动,等待下一轮A面扫码");
  123. device.writeMesEnable(0);
  124. resetStatusB();
  125. MesClient.pxstatus2.setText("B面完成");
  126. }
  127. }
  128. } catch (Exception e) {
  129. log.error("B面状态检测异常", e);
  130. }
  131. }
  132. /**
  133. * 参数采集(1秒调用1次,参考OP60的getPlcParams)
  134. */
  135. public void collectParams() {
  136. try {
  137. if(!device.isConnected()) {
  138. return;
  139. }
  140. // A面采集
  141. if(tjFlaga == 2) {
  142. collectParamsA();
  143. }
  144. // B面采集
  145. if(tjFlagb == 2) {
  146. collectParamsB();
  147. }
  148. } catch (Exception e) {
  149. log.error("参数采集异常", e);
  150. }
  151. }
  152. /**
  153. * A面参数采集
  154. */
  155. private void collectParamsA() {
  156. try {
  157. // 读取参数
  158. double speed = device.readSpeed(); // #33563 进给速度
  159. double time = device.readTime("A"); // #1595 加工时间
  160. int count = device.readCount("A"); // #1597 零件计数
  161. // 拼接参数字符串
  162. String timestamp = DateLocalUtils.getCurrentTime();
  163. String record = speed + "|" + time + "|" + count + "|" + timestamp;
  164. hjparamsA.add(record);
  165. log.debug("A面采集参数: {}", record);
  166. // 更新UI显示
  167. MesClient.param1.setText(String.format("%.1f", speed));
  168. MesClient.param2.setText(String.format("%.0f", time));
  169. MesClient.param3.setText(String.valueOf(count));
  170. // 满60条存储
  171. if(hjparamsA.size() >= 60) {
  172. saveParams("A");
  173. }
  174. } catch (Exception e) {
  175. log.error("A面参数采集异常", e);
  176. }
  177. }
  178. /**
  179. * B面参数采集
  180. */
  181. private void collectParamsB() {
  182. try {
  183. // 读取参数
  184. double speed = device.readSpeed(); // #33563 进给速度
  185. double time = device.readTime("B"); // #1596 加工时间
  186. int count = device.readCount("B"); // #1598 零件计数
  187. // 拼接参数字符串
  188. String timestamp = DateLocalUtils.getCurrentTime();
  189. String record = speed + "|" + time + "|" + count + "|" + timestamp;
  190. hjparamsB.add(record);
  191. log.debug("B面采集参数: {}", record);
  192. // 更新UI显示
  193. MesClient.param21.setText(String.format("%.1f", speed));
  194. MesClient.param22.setText(String.format("%.0f", time));
  195. MesClient.param23.setText(String.valueOf(count));
  196. // 满60条存储
  197. if(hjparamsB.size() >= 60) {
  198. saveParams("B");
  199. }
  200. } catch (Exception e) {
  201. log.error("B面参数采集异常", e);
  202. }
  203. }
  204. /**
  205. * 保存参数到SQLite
  206. */
  207. private void saveParams(String side) {
  208. try {
  209. List<String> params = side.equals("A") ? hjparamsA : hjparamsB;
  210. String sn = side.equals("A") ? curSna : curSnb;
  211. if(params.size() == 0) {
  212. return;
  213. }
  214. if(sn == null || sn.trim().isEmpty()) {
  215. log.warn("{}面工件码为空,跳过保存数据", side);
  216. params.clear();
  217. return;
  218. }
  219. String oprno = MesClient.mes_gw;
  220. String lineSn = MesClient.mes_line_sn;
  221. String paramsJson = JSON.toJSONString(params);
  222. JdbcUtils.insertLaserData(oprno, lineSn, sn, paramsJson);
  223. log.info("{}面保存参数: sn={}, count={}", side, sn, params.size());
  224. params.clear();
  225. } catch (Exception e) {
  226. log.error("{}面保存参数异常", side, e);
  227. }
  228. }
  229. /**
  230. * 上传结果到MES
  231. */
  232. private boolean sendQuality(String sn, String result, String side) {
  233. try {
  234. // 调用MES接口(使用标准的 sendQuality,会发送到MES服务器)
  235. String user = MesClient.user_menu.getText();
  236. String user20 = MesClient.getBarcode(user);
  237. boolean ret = com.mes.ui.DataUtil.sendQuality(
  238. MesClient.nettyClient,
  239. sn,
  240. result,
  241. user20
  242. );
  243. log.info("{}面上传结果: sn={}, result={}, ret={}", side, sn, result, ret);
  244. return ret;
  245. } catch (Exception e) {
  246. log.error("{}面上传结果异常", side, e);
  247. return false;
  248. }
  249. }
  250. /**
  251. * 复位A面状态
  252. */
  253. private void resetStatusA() {
  254. tjFlaga = 0;
  255. curSna = "";
  256. hjparamsA.clear();
  257. tjStatusa = 0;
  258. mesQualityFlagA = false;
  259. MesClient.product_sn.setText("");
  260. MesClient.param1.setText("");
  261. MesClient.param2.setText("");
  262. MesClient.param3.setText("");
  263. MesClient.pxstatus1.setText("A");
  264. log.info("A面状态已复位");
  265. }
  266. /**
  267. * 复位B面状态
  268. */
  269. private void resetStatusB() {
  270. tjFlagb = 0;
  271. curSnb = "";
  272. hjparamsB.clear();
  273. tjStatusb = 0;
  274. mesQualityFlagB = false;
  275. MesClient.product_sn2.setText("");
  276. MesClient.param21.setText("");
  277. MesClient.param22.setText("");
  278. MesClient.param23.setText("");
  279. MesClient.pxstatus2.setText("B");
  280. log.info("B面状态已复位");
  281. }
  282. /**
  283. * 扫码处理(A面)
  284. */
  285. public boolean onScanCodeA(String sn, String user) {
  286. try {
  287. // 检查状态
  288. if(tjFlaga != 0) {
  289. log.warn("A面上一个工件未完成");
  290. return false;
  291. }
  292. log.info("A面扫码: {}", sn);
  293. curSna = sn;
  294. tjFlaga = 1;
  295. // 等待MES质检回复后再写#1590=1
  296. // 这里先标记状态,等DataUtil.checkQuality回调后再写
  297. return true;
  298. } catch (Exception e) {
  299. log.error("A面扫码处理异常", e);
  300. return false;
  301. }
  302. }
  303. /**
  304. * 扫码处理(B面)
  305. */
  306. public boolean onScanCodeB(String sn, String user) {
  307. try {
  308. // 检查状态
  309. if(tjFlagb != 0) {
  310. log.warn("B面上一个工件未完成");
  311. return false;
  312. }
  313. log.info("B面扫码: {}", sn);
  314. curSnb = sn;
  315. tjFlagb = 1;
  316. return true;
  317. } catch (Exception e) {
  318. log.error("B面扫码处理异常", e);
  319. return false;
  320. }
  321. }
  322. /**
  323. * MES质检通过回调(A面)
  324. */
  325. public void onMesQualityPassA() {
  326. try {
  327. mesQualityFlagA = true;
  328. // 写#1590=1(允许启动)
  329. boolean ret = device.writeMesEnable(1);
  330. if(ret) {
  331. log.info("A面MES质检通过,写入#1590=1(允许启动)");
  332. MesClient.pxstatus1.setText("A面等待启动");
  333. } else {
  334. log.error("A面写入#1590=1失败");
  335. MesClient.pxstatus1.setText("A面写信号失败");
  336. }
  337. } catch (Exception e) {
  338. log.error("A面MES质检回调异常", e);
  339. }
  340. }
  341. /**
  342. * MES质检通过回调(B面)
  343. * B面不需要扫码,此方法不再使用
  344. */
  345. public void onMesQualityPassB() {
  346. try {
  347. mesQualityFlagB = true;
  348. log.info("B面质检回调(B面不需要扫码,忽略)");
  349. // B面不写#1590,利用A面的允许信号
  350. } catch (Exception e) {
  351. log.error("B面MES质检回调异常", e);
  352. }
  353. }
  354. /**
  355. * 手动复位A面
  356. */
  357. public void manualResetA() {
  358. log.warn("手动复位A面状态");
  359. resetStatusA();
  360. }
  361. /**
  362. * 手动复位B面
  363. */
  364. public void manualResetB() {
  365. log.warn("手动复位B面状态");
  366. resetStatusB();
  367. }
  368. }