From 643175bb6f061e880596fee5beb54350cc693438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LAPTOP-S9HJSOEB=5C=E6=98=8A=E5=A4=A9?= Date: Fri, 29 Mar 2024 09:55:51 +0800 Subject: [PATCH 1/3] =?UTF-8?q?1.=E5=A2=9E=E5=8A=A0=E8=A7=86=E8=A7=89?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=AB=AF=E7=AB=AF=E5=8F=A3=EF=BC=88=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=8D=97=E4=BA=AC=E7=83=9F=E8=8D=89=E8=A7=86=E8=A7=89?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=EF=BC=89=202.=E6=8F=90=E4=BA=A4=E7=9B=98?= =?UTF-8?q?=E7=82=B9=E5=8E=86=E5=8F=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/config/ConfigProperties.java | 4 + .../web/controller/CheckLogController.java | 9 + .../java/com/zhehekeji/web/pojo/LocReq.java | 16 ++ .../zhehekeji/web/service/InitService.java | 6 + .../com/zhehekeji/web/service/PlcCmdInfo.java | 6 + .../com/zhehekeji/web/service/PlcService.java | 51 ++++- .../web/service/client/CETransmission.java | 32 ++++ .../web/service/client/ClientChanel.java | 111 +++++++++++ .../web/service/client/ClientCodeMap.java | 24 +++ .../zhehekeji/web/service/client/Decoder.java | 145 ++++++++++++++ .../web/service/client/ECResultMessage.java | 51 +++++ .../web/service/client/ECTransmission.java | 125 ++++++++++++ .../service/client/EmptyCheckCodeInfo.java | 41 ++++ .../zhehekeji/web/service/client/Encoder.java | 24 +++ .../web/service/client/HBTransmission.java | 36 ++++ .../web/service/client/ISTransmission.java | 44 +++++ .../web/service/client/LCTransmission.java | 34 ++++ .../web/service/client/MessageConverter.java | 13 ++ .../service/client/NettyConnectHandler.java | 44 +++++ .../web/service/client/NettyServer.java | 60 ++++++ .../web/service/client/RealtimeCheckMap.java | 87 +++++++++ .../web/service/client/SCTransmission.java | 181 ++++++++++++++++++ .../web/service/ksec/KsecDataInfo.java | 7 + .../web/service/ksec/KsecDecoder.java | 19 +- web/src/main/resources/application-prod.yml | 12 +- 25 files changed, 1165 insertions(+), 17 deletions(-) create mode 100644 web/src/main/java/com/zhehekeji/web/pojo/LocReq.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/CETransmission.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/ClientChanel.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/ClientCodeMap.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/Decoder.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/ECResultMessage.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/ECTransmission.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/EmptyCheckCodeInfo.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/Encoder.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/HBTransmission.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/ISTransmission.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/LCTransmission.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/MessageConverter.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/NettyConnectHandler.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/NettyServer.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/RealtimeCheckMap.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/SCTransmission.java diff --git a/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java b/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java index bc4cc8a..1993ede 100644 --- a/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java +++ b/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java @@ -39,6 +39,10 @@ public class ConfigProperties { private Rfid rfid; + /** + * TCP服务端端口 + */ + private Integer serverPort; @Data public static class CameraConfig{ diff --git a/web/src/main/java/com/zhehekeji/web/controller/CheckLogController.java b/web/src/main/java/com/zhehekeji/web/controller/CheckLogController.java index 4c22b24..79bbb29 100644 --- a/web/src/main/java/com/zhehekeji/web/controller/CheckLogController.java +++ b/web/src/main/java/com/zhehekeji/web/controller/CheckLogController.java @@ -5,6 +5,7 @@ import com.zhehekeji.common.util.ValidatorUtil; import com.zhehekeji.core.pojo.Result; import com.zhehekeji.web.entity.CheckLog; import com.zhehekeji.web.entity.StockLog; +import com.zhehekeji.web.pojo.LocReq; import com.zhehekeji.web.pojo.stock.CheckLogSearch; import com.zhehekeji.web.pojo.stock.StockLogSearch; import com.zhehekeji.web.service.CheckLogService; @@ -17,6 +18,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; +import java.util.List; +import java.util.Map; @Api(tags = "盘点历史") @RequestMapping("/checkLog") @@ -34,5 +37,11 @@ public class CheckLogController { return Result.success(checkLogService.list(checkLogSearch)); } + @ApiOperation("盘点历史") + @PostMapping("/getOne") + public Map getOne(@RequestBody Result> checkLogSearch){ + + return null; + } } diff --git a/web/src/main/java/com/zhehekeji/web/pojo/LocReq.java b/web/src/main/java/com/zhehekeji/web/pojo/LocReq.java new file mode 100644 index 0000000..8a069e1 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/pojo/LocReq.java @@ -0,0 +1,16 @@ +package com.zhehekeji.web.pojo; + +import lombok.Data; + +@Data +public class LocReq { + Integer streetId; + //货位编码 + private String loc; + //时间 + private String date; + //托盘标签 + private String tagid; + //taskId + private String jobnum; +} diff --git a/web/src/main/java/com/zhehekeji/web/service/InitService.java b/web/src/main/java/com/zhehekeji/web/service/InitService.java index 307609d..dd03da0 100644 --- a/web/src/main/java/com/zhehekeji/web/service/InitService.java +++ b/web/src/main/java/com/zhehekeji/web/service/InitService.java @@ -13,6 +13,7 @@ import com.zhehekeji.web.lib.joyware.NetSDKLib; import com.zhehekeji.web.mapper.CameraMapper; import com.zhehekeji.web.mapper.SensorGunMapper; import com.zhehekeji.web.mapper.StreetMapper; +import com.zhehekeji.web.service.client.NettyServer; import com.zhehekeji.web.service.ksec.KsecNettyClient; import com.zhehekeji.web.service.robotic.NettyClient; import com.zhehekeji.web.service.sick.SickNettyClient; @@ -52,6 +53,9 @@ public class InitService implements ApplicationRunner { @Resource private CameraService cameraService; + @Resource + private NettyServer nettyServer; + @Bean public CameraControlLoginModule cameraControlLoginModule(){ CameraControlLoginModule cameraControlLoginModule = null; @@ -79,6 +83,8 @@ public class InitService implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { + nettyServer.CreateNettyServer(configProperties.getServerPort()); + //球机登录 List cameras = cameraMapper.selectByMap(new HashMap<>(0)); cameras.forEach(camera -> { diff --git a/web/src/main/java/com/zhehekeji/web/service/PlcCmdInfo.java b/web/src/main/java/com/zhehekeji/web/service/PlcCmdInfo.java index 74375a1..85f1e37 100644 --- a/web/src/main/java/com/zhehekeji/web/service/PlcCmdInfo.java +++ b/web/src/main/java/com/zhehekeji/web/service/PlcCmdInfo.java @@ -73,6 +73,12 @@ public class PlcCmdInfo { private Integer streetId; + private String typeNum; + + private Integer quantity; + + private Integer checkRlt; + public PlcCmdInfo(String plcId, String taskId, Integer side1, Integer leftRight1, Integer column1, Integer row1, Integer separation1, Integer side2, Integer leftRight2, Integer column2, Integer row2, Integer separation2,String lotnum) { this.taskId = taskId; this.side1 = side1; diff --git a/web/src/main/java/com/zhehekeji/web/service/PlcService.java b/web/src/main/java/com/zhehekeji/web/service/PlcService.java index 176e08b..186af94 100644 --- a/web/src/main/java/com/zhehekeji/web/service/PlcService.java +++ b/web/src/main/java/com/zhehekeji/web/service/PlcService.java @@ -14,6 +14,8 @@ import com.zhehekeji.web.pojo.OrderVO; import com.zhehekeji.web.service.RFID.RFIDMap; import com.zhehekeji.web.service.RFID.RFIDSocket; import com.zhehekeji.web.service.RFID.RFIDSocketFactory; +import com.zhehekeji.web.service.client.ClientChanel; +import com.zhehekeji.web.service.client.SCTransmission; import com.zhehekeji.web.service.damLightSource.JYDAMEquip; import com.zhehekeji.web.service.damLightSource.JYDamHelper; import com.zhehekeji.web.service.hikLightSource.HikControlSocket; @@ -37,6 +39,8 @@ import java.util.concurrent.BlockingDeque; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import static org.aspectj.weaver.tools.cache.SimpleCacheFactory.path; + /** * @Description plc信号指令处理类 * 对plcId做同步处理,防止内存中保存的正在运行的订单信息错乱 @@ -743,6 +747,7 @@ public class PlcService { } Boolean trayGoodCheck = Boolean.TRUE; + OrderInfo orderInfo = new OrderInfo(street, plcCmdInfo, 1, cmdCode); //扫货物 if(configProperties.getScanCodeMode().getGoods() == 2) { log.info("扫码类型:" + configProperties.getScanCodeMode().getTray()); @@ -800,10 +805,26 @@ public class PlcService { log.warn("rfid error:{}", trayCode); } + }else if (configProperties.getScanCodeMode().getGoods() == 4){ + //开始盘点 + String goodLocation = orderInfo.getStreetId().toString()+"_"+ plcCmdInfo.getLeftRight1().toString()+"_"+ orderInfo.getSeparation().toString()+"_"+ orderInfo.getRow().toString()+"_"+ orderInfo.getColumn(); + SCTransmission scTransmission = new SCTransmission(street.getPlcId(),plcCmdInfo.getTaskId(),goodLocation,plcCmdInfo.getTypeNum(), plcCmdInfo.getQuantity(), "N"); + + String scTransmissionStr = scTransmission.toString(); + ClientChanel.write(scTransmissionStr,street.getPlcId()); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + //滁州开始盘点即取货到位 + + SCTransmission scTransmission2 = new SCTransmission(street.getPlcId(),plcCmdInfo.getTaskId()); + String scTransmissionStr2 = scTransmission2.toSC02String(); + ClientChanel.write(scTransmissionStr2,street.getPlcId()); } - OrderInfo orderInfo = new OrderInfo(street, plcCmdInfo, 1, cmdCode); Stock stock = stockMapper.getByStreetAndDirectionAndSideAndRowColumn(orderInfo.getStreetId(), plcCmdInfo.getLeftRight1(), orderInfo.getSeparation(), orderInfo.getRow(), orderInfo.getColumn()); String scanCode = null; @@ -845,7 +866,6 @@ public class PlcService { stock.setWmsCode(wmsCode); stockMapper.updateById(stock); } - checkLog(stock); // StockCheckRunnable stockCheckRunnable = new StockCheckRunnable(street,plcCmdInfo,cmdCode,stockMapper,path,checkLogMapper,configProperties.getScanCodeMode().getGoods(),wmsCode,wmsTrayCode,trayCode,trayCheck,configProperties,sensorGun); // threadPoolExecutor.execute(stockCheckRunnable); //还原相机 @@ -935,4 +955,31 @@ public class PlcService { return configProperties; } + public void visualInventory(SCTransmission scTransmission) { + String[] location = scTransmission.getGoodsLocation().split("_"); + Stock stock = stockMapper.getByStreetAndDirectionAndSideAndRowColumn( + Integer.parseInt(location[0]),//巷道id + Integer.parseInt(location[1]),//左右 + Integer.parseInt(location[2]),//内外 + Integer.parseInt(location[3]),//行 + Integer.parseInt(location[4]));//列 + + //收到盘点结果 + if (stock == null) { + stock = Stock.builder() + .category(scTransmission.getRstCategory()) + .count(scTransmission.getRstCount()) + .status(scTransmission.getCheckRst().equals("1")?2:1) + .exportTime(LocalDateTime.now()).build(); + stockMapper.insert(stock); + } else { + stock.setCategory(scTransmission.getRstCategory()); + stock.setCount(scTransmission.getRstCount()); + if(stock.getStatus() != 1) + stock.setStatus(scTransmission.getCheckRst().equals("1")?2:1); + stock.setExportTime(LocalDateTime.now()); + stockMapper.updateById(stock); + } + checkLog(stock); + } } diff --git a/web/src/main/java/com/zhehekeji/web/service/client/CETransmission.java b/web/src/main/java/com/zhehekeji/web/service/client/CETransmission.java new file mode 100644 index 0000000..d06acf3 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/CETransmission.java @@ -0,0 +1,32 @@ +package com.zhehekeji.web.service.client; + +import lombok.Data; + +@Data +/** + * 与客户端建立连接的传输体 + */ +public class CETransmission { + + private static String HEADER = "CE"; + private static String Split = "&"; + + private String SRMNumber; + + public String toString(){ + return HEADER + Split + SRMNumber; + } + + public static String getHEADER(){ + return HEADER; + } + + public CETransmission(String body){ + String [] strings = body.split(Split); + if(strings != null && strings.length == 2 && HEADER.equals(strings[0])){ + SRMNumber = strings[1]; + } + + } + +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/ClientChanel.java b/web/src/main/java/com/zhehekeji/web/service/client/ClientChanel.java new file mode 100644 index 0000000..4231f2d --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/ClientChanel.java @@ -0,0 +1,111 @@ +package com.zhehekeji.web.service.client; + + +import io.netty.channel.Channel; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.InetSocketAddress; +import java.time.LocalDateTime; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 所有的客户端的chanel + */ +@Slf4j +public class ClientChanel { + + + static final Logger tcpLogger = LoggerFactory.getLogger("tcp"); + + /** + * key : 巷道标识符 + */ + static Map channelMap = new ConcurrentHashMap<>(); + + + /** + * key : 巷道标识符 + */ + static Map channelStringTime = new ConcurrentHashMap<>(); + + + /** + * key :IP + * value: 巷道标识符 + */ + static Map IP_SRMNumberMap = new ConcurrentHashMap<>(); + + /** + * key :巷道标识符 + * value: IP + */ + static Map SRMNumber_IPMap = new ConcurrentHashMap<>(); + + public static void putIp(String ip,String ID){ + IP_SRMNumberMap.put(ip,ID); + } + + public static void putSRMNUmber_Ip(String ID,String ip){ + SRMNumber_IPMap.put(ID,ip); + IP_SRMNumberMap.put(ip,ID); + } + + public static String getIpFromId(String ID){ + return SRMNumber_IPMap.get(ID); + } + + public static void deleteIp(String ip){ + IP_SRMNumberMap.remove(ip); + } + + public static String getIDFromIp(String ip){ + return IP_SRMNumberMap.get(ip); + } + + public static void connect(String SRMNumber, Channel channel){ + channelMap.put(SRMNumber,channel); + InetSocketAddress socketAddress = (InetSocketAddress) channel.remoteAddress(); + String clientIp = socketAddress.getAddress().getHostAddress(); + putSRMNUmber_Ip(SRMNumber, clientIp); + channelStringTime.put(SRMNumber,LocalDateTime.now()); + log.info("connect:{}巷道 ", SRMNumber); + } +// static { +// Timer timer = new Timer(); +// timer.scheduleAtFixedRate(new TimerTask() { +// @Override +// public void run() { +// for (String key :channelStringTime.keySet()){ +// if(LocalDateTime.now().equals(channelStringTime.get(key).plusMinutes(5))) { +// channelStringTime.remove(key); +// disConnect(key); +// } +// } +// } +// },0,60000); +// } + public static void disConnect(String key){ + channelMap.remove(key); + } + + public static Set keys(){ + return channelMap.keySet(); + } + + public static Channel get(String key){ + return channelMap.get(key); + } + + public static void write(String data,String key){ + if(channelMap.get(key) != null){ + channelMap.get(key).writeAndFlush(data); + }else { + tcpLogger.info("no connect client:{}",key); + } + } + +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/ClientCodeMap.java b/web/src/main/java/com/zhehekeji/web/service/client/ClientCodeMap.java new file mode 100644 index 0000000..bb3a427 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/ClientCodeMap.java @@ -0,0 +1,24 @@ +package com.zhehekeji.web.service.client; + +import java.util.Hashtable; +import java.util.Map; + +public class ClientCodeMap { + + /** + * 线程安全的map + */ + protected static Map codeMap = new Hashtable<>(); + + public static void putCode(String SRMNumber,String code){ + codeMap.put(SRMNumber,code); + } + + public static String getCode(String SRMNumber){ + return codeMap.get(SRMNumber); + } + + public static void removeCode(String SRMNumber){ + codeMap.remove(SRMNumber); + } +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java b/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java new file mode 100644 index 0000000..7b1e478 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java @@ -0,0 +1,145 @@ +package com.zhehekeji.web.service.client; + +import com.zhehekeji.web.entity.Stock; +import com.zhehekeji.web.service.PlcService; +import com.zhehekeji.web.service.ksec.*; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.DelimiterBasedFrameDecoder; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.charset.Charset; +import java.time.LocalDateTime; +import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import static com.zhehekeji.web.service.ksec.KsecDecoder.ksecInfoMap; +import static org.aspectj.weaver.tools.cache.SimpleCacheFactory.path; + +/** + * 客户端解码器 连接用 + */ +@Slf4j +public class Decoder extends DelimiterBasedFrameDecoder { + + private static final Logger tcpLogger = LoggerFactory.getLogger("tcp"); + + public static String PT_CLIENT = "PT"; + private static String WCS_CLIENT = "WCS"; + private static String EMPTY_CLIENT = "EMPTY"; + private static String END_STRING = "$"; + + private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,15,30, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(20000)); + + private PlcService plcService; + + public Decoder(PlcService plcService) { + + super(20000,true,false, Unpooled.copiedBuffer(">".getBytes()), + Unpooled.copiedBuffer("$".getBytes())); + this.plcService = plcService; + } + + @Override + protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + + in = (ByteBuf) super.decode(ctx, in); + if(in == null){ + log.debug("no data"); + return null; + } + ClientRunnable clientRunnable = new ClientRunnable(in,ctx,plcService); + threadPoolExecutor.execute(clientRunnable); + return null; + } + + public static class ClientRunnable implements Runnable { + + private ByteBuf in; + + private ChannelHandlerContext ctx; + + private PlcService plcService; + + + public ClientRunnable(ByteBuf in,ChannelHandlerContext ctx,PlcService plcService){ + this.ctx = ctx; + this.in = in; + this.plcService = plcService; + } + + @Override + public void run() { + String body = in.toString(Charset.forName("UTF-8")); + tcpLogger.info("receive client:{}, data length:{}",body, body.length()); + //视觉服务 + { + if(body.startsWith(HBTransmission.getHEADER())) { + //心跳 + HBTransmission hbTransmission = new HBTransmission(body); + //回复客户端心跳 + ctx.channel().writeAndFlush(hbTransmission.toString()); + ClientChanel.connect(hbTransmission.getSRMNumber(), ctx.channel()); + //tcpLogger.info("client:{} heart", hbTransmission.getSRMNumber()); + in.release(); + } else if(body.startsWith(SCTransmission.getHeader())){ + //盘点指令 + SCTransmission scTransmission = new SCTransmission(body); + if(scTransmission.isCollectOver()){ + //给普天发送数据采集完毕指令 + KsecDataInfo ksecDataInfo = ksecInfoMap.get(scTransmission.getTaskNo()); + ksecDataInfo.setCmdName("E2"); + KsecInfo ksecInfo = new KsecInfo("KC","E",ksecDataInfo); + KsecNettyClient.write(ksecInfo); + }else { + plcService.visualInventory(scTransmission); + + KsecDataInfo ksecDataInfo = ksecInfoMap.get(scTransmission.getTaskNo()); + ksecDataInfo.setCmdName("E3"); + ksecDataInfo.setQuantity(scTransmission.getRstCount()); + ksecDataInfo.setTypeNum(scTransmission.getRstCategory()); + ksecDataInfo.setCheckRlt(Integer.parseInt(scTransmission.getCheckRst())); + KsecInfo ksecInfo = new KsecInfo("KC","E",ksecDataInfo); + KsecNettyClient.write(ksecInfo); + ksecInfoMap.remove(scTransmission.getTaskNo()); + //添加到实时信息里 + //RealtimeCheckMap.put(scTransmission.getSRMNumber(),scTransmission.checkInfo()); + //更新盤點統計 +// emptyCheckService.updateCheckLastTime(tmTransmission.getTaskNo(),tmTransmission.getSRMNumber(),stock.getCode()); + } + in.release(); + }else if(body.startsWith(CETransmission.getHEADER())){ + //客户端建立连接 + CETransmission ceTransmission = new CETransmission(body); + //回复客户端,建立连接完成 + + ctx.channel().writeAndFlush(ceTransmission.toString()); + ClientChanel.connect(ceTransmission.getSRMNumber(), ctx.channel()); + tcpLogger.info("client:{} connect", ceTransmission.getSRMNumber()); + in.release(); + } + else if(body.startsWith("DC")){ + //客户端断开连接 + String [] strings = body.split("&"); + if(strings != null && strings.length == 2){ + tcpLogger.info("client:{} disConnect", strings[1]); + ClientChanel.disConnect(strings[1]); + } + in.release(); + } + +// else if (body.contains("EMPTY_CLIENT")){ +// ClientChanel.connect(EMPTY_CLIENT_NAME, ctx.channel()); +// tcpLogger.info("client:{} connect", EMPTY_CLIENT_NAME); +// in.release(); +// } + } + } + } + +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/ECResultMessage.java b/web/src/main/java/com/zhehekeji/web/service/client/ECResultMessage.java new file mode 100644 index 0000000..68eaae9 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/ECResultMessage.java @@ -0,0 +1,51 @@ +package com.zhehekeji.web.service.client; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.List; + +@Slf4j + +@Data +/** + * 空货位盘点 + * + * EC&6&17455&UL061001050111,1;UL061002050111,0;UL061003050111,1;>(算法客户端发送) + * UL061001050111,1 货位号,是否有货(0:无货,1:有货) + */ + +public class ECResultMessage { + private static String HEADER = "EC"; + private static String SPLIT = "&"; + private static String SPLIT_EMP = ";"; + private String SRMNumber; + private String taskId; + private String emptyCheckMsg; + private List ecTransMissionList; + + public ECResultMessage(String body){ + ecTransMissionList = new ArrayList<>(); + log.info("body: {}", body); + String [] strings = body.split(SPLIT); + if(strings != null && strings.length == 4 && HEADER.equals(strings[0])){ + SRMNumber = strings[1]; + taskId = strings[2]; + emptyCheckMsg = strings[3]; + log.info("srmNumber:{}, taskId:{},emptyCheckMsg:{}", SRMNumber, taskId, emptyCheckMsg); + String[] checkMsgStrs = emptyCheckMsg.split(SPLIT_EMP); + for (String checkMsgStr : checkMsgStrs) { + if (!checkMsgStr.isEmpty() && checkMsgStr.contains(",")){ + log.info("checkMsgStr: {}", checkMsgStr); + String[] msgStrs = checkMsgStr.split(","); + String goodsLocation = msgStrs[0]; + String empty = msgStrs[1]; + ECTransmission ecTransmission = new ECTransmission(SRMNumber, taskId, goodsLocation, empty); + ecTransMissionList.add(ecTransmission); + } + } + } + } + +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/ECTransmission.java b/web/src/main/java/com/zhehekeji/web/service/client/ECTransmission.java new file mode 100644 index 0000000..7b0b07d --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/ECTransmission.java @@ -0,0 +1,125 @@ +package com.zhehekeji.web.service.client; + +import lombok.Data; + +@Data +/** + * 空货位盘点 + * + * ■ EC,SRM001,BY201710250940368150001,START;(服务端发送) + * ■ EC,SRM001,BY201710250940368150001,R010002001(货位号), Y/N;(客户端对每个货位回复有无,对于双伸的货位需要回复两次(浅深货位)) + * ■ EC,SRM001,BY201710250940368150001,END ;(服务端发送)。 + * + */ +public class ECTransmission { + + private static String HEADER = "EC"; + private static String Split = "&"; + +// private static String Split = ","; + + private String SRMNumber; + + private String taskId; + + private String type; + + private String goodsLocation; + + private String isEmpty; + + private String emptyMsg; + + /** + * 左右 1:左 2:右 + */ + private Integer direction; + + /** + * 深浅 1:浅 2:深 + */ + private Integer side; + + private Integer row; + + private Integer column; + + private Integer startColumn; + + private Integer endColumn; + + /** + * 货位条码 + */ + private String originCode; + +// public String toString(){ +// return HEADER + Split + SRMNumber; +// } + + public static String getHEADER(){ + return HEADER; + } + + public ECTransmission(String body){ + String [] strings = body.split(Split); + if(strings != null && strings.length == 4 && HEADER.equals(strings[0])){ + SRMNumber = strings[1]; + taskId = strings[2]; +// goodsLocation = strings[3]; +// isEmpty = strings[4]; + emptyMsg = strings[3]; +// direction = goodsLocation.substring(0).equals("L") ? 1:2; +// side = Integer.valueOf(goodsLocation.substring(2,3)); +// row = Integer.valueOf(goodsLocation.substring(3,6)); +// column = Integer.valueOf(goodsLocation.substring(6,9)); + }else if(strings != null && strings.length == 8 && HEADER.equals(strings[0])){ + //todo length == 9 + SRMNumber = strings[1]; + taskId = strings[2]; + startColumn = Integer.valueOf(strings[4]); + endColumn = Integer.valueOf(strings[5]); + goodsLocation = strings[6]; + direction = goodsLocation.substring(0).equals("L") ? 1:2; + side = Integer.valueOf(goodsLocation.substring(2,3)); + row = Integer.valueOf(goodsLocation.substring(3,6)); + column = Integer.valueOf(goodsLocation.substring(6,9)); + //todo 7 8 + originCode = "ddddd"; + isEmpty = strings[7]; + } + } + + public ECTransmission(String srmNumber, String id, String location, String empty){ + SRMNumber = srmNumber; + taskId = id; + goodsLocation = location; + isEmpty = empty; + + // UL061001050111 + row = Integer.valueOf(goodsLocation.substring(8,10)); + column = Integer.valueOf(goodsLocation.substring(5,8)); + direction = Integer.valueOf(goodsLocation.substring(4,5)); + side = Integer.valueOf(goodsLocation.substring(11,12)); + } + + /** + * 空托盘检测开始信息 + * @return + */ + public static String toEmptyCheckStartString(String SRMNumber, String taskId){ + StringBuffer sb = new StringBuffer(HEADER); + sb.append(Split).append(SRMNumber).append(Split).append(taskId).append(Split).append("START"); + return sb.toString(); + } + + /** + * 空托盘检测 结束信号 + * @return + */ + public static String toEmptyCheckEndString(String SRMNumber, String taskId){ + StringBuffer sb = new StringBuffer(HEADER); + sb.append(Split).append(SRMNumber).append(Split).append(taskId).append(Split).append("END"); + return sb.toString(); + } +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/EmptyCheckCodeInfo.java b/web/src/main/java/com/zhehekeji/web/service/client/EmptyCheckCodeInfo.java new file mode 100644 index 0000000..69dcebf --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/EmptyCheckCodeInfo.java @@ -0,0 +1,41 @@ +package com.zhehekeji.web.service.client; + +import lombok.Data; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * 空货位扫描到的全部条码 + */ +@Data +public class EmptyCheckCodeInfo { + + private static Map> allCode = new HashMap<>(); + + public static void start(String SRMNumber, String taskNo){ + String key = String.format("{}-{}",SRMNumber, taskNo); + allCode.remove(key); + } + + public static void addCode(String SRMNumber,Integer row,Integer startColumn,Integer endColumn,String code){ + String key = String.format("{}-{}-{}-{}",SRMNumber,row,startColumn,endColumn); + Set codes = allCode.get(key); + if(codes == null){ + codes = new HashSet<>(); + } + codes.add(code); + } + + public static Set getAllCode(String SRMNumber, String taskNo){ + String key = String.format("{}-{}",SRMNumber, taskNo); + return allCode.get(key); + } + + public static void stop(String SRMNumber,Integer row,Integer startColumn,Integer endColumn){ + String key = String.format("{}-{}-{}-{}",SRMNumber,row,startColumn,endColumn); + allCode.remove(key); + } +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/Encoder.java b/web/src/main/java/com/zhehekeji/web/service/client/Encoder.java new file mode 100644 index 0000000..a523252 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/Encoder.java @@ -0,0 +1,24 @@ +package com.zhehekeji.web.service.client; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.charset.StandardCharsets; + +/** + * 客户端传输协议 以;结尾 + */ +public class Encoder extends MessageToByteEncoder { + private static String END_STRING = ">"; + + private static final Logger tcpLogger = LoggerFactory.getLogger("tcp"); + @Override + protected void encode(ChannelHandlerContext channelHandlerContext, String data, ByteBuf byteBuf) throws Exception { + data = data + END_STRING; + tcpLogger.info("send to client:{}, length:{}",data, data.length()); + byteBuf.writeBytes(data.getBytes(StandardCharsets.UTF_8)); + } +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/HBTransmission.java b/web/src/main/java/com/zhehekeji/web/service/client/HBTransmission.java new file mode 100644 index 0000000..779812b --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/HBTransmission.java @@ -0,0 +1,36 @@ +package com.zhehekeji.web.service.client; + +import lombok.Data; + +@Data +/** + * 与客户端的心跳 + */ +public class HBTransmission { + + private static String HEADER = "HB"; + private static String Split = "&"; + + private String SRMNumber; + + public String toString(){ + return HEADER + Split + SRMNumber; + } + + public static String getHEADER(){ + return HEADER; + } + + public HBTransmission(String body){ + String [] strings = body.split(Split); + if(strings != null && strings.length == 2 && HEADER.equals(strings[0])){ + SRMNumber = strings[1]; + } + + } + + public static void main(String[] args) { + HBTransmission ceTransmission= new HBTransmission("HB&1"); + System.out.println(ceTransmission); + } +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/ISTransmission.java b/web/src/main/java/com/zhehekeji/web/service/client/ISTransmission.java new file mode 100644 index 0000000..26d0e93 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/ISTransmission.java @@ -0,0 +1,44 @@ +package com.zhehekeji.web.service.client; + +import lombok.Data; + +@Data +public class ISTransmission { + + private static String HEADER = "IS"; + + private static String Split = ","; + + private String SRMNumber; + + private String taskId; + + private String goodsLocation; + + private String code; + + public String toString(){ + StringBuffer sb = new StringBuffer(); + sb.append(HEADER).append(Split).append(SRMNumber).append(Split).append(taskId).append(Split).append(goodsLocation); + if(code != null){ + sb.append(Split).append(code); + } + return sb.toString(); + } + + public ISTransmission(String SRMNumber,String taskId,String goodsLocation){ + this.SRMNumber = SRMNumber; + this.goodsLocation = goodsLocation; + this.taskId = taskId; + } + + public ISTransmission(String msg){ + String [] strings = msg.split(Split); + HEADER = strings[0]; + SRMNumber = strings[1]; + goodsLocation = strings[2]; + if(strings.length == 4){ + code = strings[3]; + } + } +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/LCTransmission.java b/web/src/main/java/com/zhehekeji/web/service/client/LCTransmission.java new file mode 100644 index 0000000..d2329c9 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/LCTransmission.java @@ -0,0 +1,34 @@ +package com.zhehekeji.web.service.client; + + +import lombok.Data; + +@Data +/** + * 开关灯 + */ +public class LCTransmission { + + private static String HEADER = "LC"; + + private String SRMNumber; + + /** + * 1:开 0:关 + */ + private Integer status; + + public String toString(){ + return HEADER + "&" + SRMNumber+"&"+status; + } + + public static String getHEADER(){ + return HEADER; + } + + public LCTransmission(String SRMNumber,Integer status){ + this.SRMNumber = SRMNumber; + this.status = status; + } + +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/MessageConverter.java b/web/src/main/java/com/zhehekeji/web/service/client/MessageConverter.java new file mode 100644 index 0000000..5f767f0 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/MessageConverter.java @@ -0,0 +1,13 @@ +package com.zhehekeji.web.service.client; + +import org.springframework.stereotype.Component; + +/** + * 普天的消息 转给盘点客户端 + */ +@Component +public class MessageConverter { + + + +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/NettyConnectHandler.java b/web/src/main/java/com/zhehekeji/web/service/client/NettyConnectHandler.java new file mode 100644 index 0000000..fe55324 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/NettyConnectHandler.java @@ -0,0 +1,44 @@ +package com.zhehekeji.web.service.client; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import lombok.extern.slf4j.Slf4j; + +import java.net.InetSocketAddress; + +/** + * 客户端的上下线 + * + * @author Administrator + * + */ +@Slf4j +public class NettyConnectHandler extends ChannelInboundHandlerAdapter { + + /** + * 建立连接时 + */ + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress(); + String clientIp = socketAddress.getAddress().getHostAddress(); + int clientPort = socketAddress.getPort(); + log.info("ip:{} port:{} connected",clientIp, clientPort); + ctx.fireChannelActive(); + } + + /** + * 关闭连接时 + */ + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress(); + String clientIp = socketAddress.getAddress().getHostAddress(); + int clientPort = socketAddress.getPort(); + log.info("ip:{} port:{} disconnected",clientIp, clientPort); + String ID = ClientChanel.getIDFromIp(clientIp); + //设置客户端下线 + ClientChanel.disConnect(ID); + } + +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/NettyServer.java b/web/src/main/java/com/zhehekeji/web/service/client/NettyServer.java new file mode 100644 index 0000000..6ea7758 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/NettyServer.java @@ -0,0 +1,60 @@ +package com.zhehekeji.web.service.client; + +import com.zhehekeji.web.service.PlcService; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import lombok.SneakyThrows; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +@Component +public class NettyServer { + + @Resource + private PlcService plcService; + + + public void CreateNettyServer(int port) throws InterruptedException { + Thread thread = new Thread(new Runnable() { + @SneakyThrows + @Override + public void run() { + EventLoopGroup bossGroup = new NioEventLoopGroup(); + // 从线程组, 老板线程组会把任务丢给他,让手下线程组去做任务 + EventLoopGroup workerGroup = new NioEventLoopGroup(); + + try { + // netty服务器的创建, 辅助工具类,用于服务器通道的一系列配置 + ServerBootstrap serverBootstrap = new ServerBootstrap(); + serverBootstrap.group(bossGroup, workerGroup) //绑定两个线程组 + .channel(NioServerSocketChannel.class) //指定NIO的模式 + + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) { + ch.pipeline().addLast(new NettyConnectHandler()); + ch.pipeline().addLast(new Decoder(plcService)); + ch.pipeline().addLast(new Encoder()); + }}); // 子处理器,用于处理workerGroup + + // 启动server,并且设置8088为启动的端口号,同时启动方式为同步 + ChannelFuture channelFuture = serverBootstrap.bind(port).sync(); + + // 监听关闭的channel,设置位同步方式 + channelFuture.channel().closeFuture().sync(); + } finally { + //退出线程组 + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); + } + } + }); + thread.start(); + } +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/RealtimeCheckMap.java b/web/src/main/java/com/zhehekeji/web/service/client/RealtimeCheckMap.java new file mode 100644 index 0000000..59289ab --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/RealtimeCheckMap.java @@ -0,0 +1,87 @@ +package com.zhehekeji.web.service.client; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +@Data +public class RealtimeCheckMap { + + private static Map map = new HashMap<>(); + + public static void put(String SRMNumber,CheckInfo checkInfo){ + checkInfo.setTime(LocalDateTime.now()); + String ip ="http://"+ClientChanel.getIpFromId(SRMNumber)+":9009/pic/"+checkInfo.getCheckCode()+"/"+checkInfo.getTaskNo()+"/"; + checkInfo.setIP(ip); + checkInfo.setSidePic1(String.format("%s1.png",ip)); + checkInfo.setSidePic2(String.format("%s2.png",ip)); + checkInfo.setSidePic3(String.format("%s3.png",ip)); + checkInfo.setSidePic4(String.format("%s4.png",ip)); + checkInfo.setTopPic1(String.format("%s5.png",ip)); + checkInfo.setTopPic2(String.format("%s6.png",ip)); + map.put(SRMNumber,checkInfo); + } + + public static CheckInfo getRealtimeCheck(String SRMNumber){ + return map.get(SRMNumber); + } + + @Data + public static class CheckInfo{ + + private Integer row; + + private Integer column; + + private Integer side; + + private Integer direction; + + private String WMSCode; + + private String WMSCategory; + + private Integer WMSCount; + + private String checkCode; + + private String checkCategory; + + private Integer checkCount; + + private Integer status; + + private String topPic1; + + private String topPic2; + + private String sidePic1; + + private String sidePic2; + + private String sidePic3; + + private String sidePic4; + + private String IP; + + private String taskNo; + + @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") + private LocalDateTime time; + + public Integer getStatus(){ + if(WMSCode.equals(checkCount) && checkCount.equals(WMSCount)){ + return 1; + } + return 0; + } + + + + + } +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/SCTransmission.java b/web/src/main/java/com/zhehekeji/web/service/client/SCTransmission.java new file mode 100644 index 0000000..591cad1 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/SCTransmission.java @@ -0,0 +1,181 @@ +package com.zhehekeji.web.service.client; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +/** + * 盘点指令 + * 与客户端的传输内容 + * + */ +@Data +public class SCTransmission { + + private static String header = "SC"; + + private String SRMNumber; + + /** + * 搬运任务号 + */ + private String taskNo; + + /** + * 货位号 + */ + private String goodsLocation; + + /** + * 托盘号 + */ + private String trayNo; + + + private String code; + /** + * 上位机下发品规 + */ + private String category; + private Integer count; + + /** + * 盘点结果 + */ + private String rstCategory; + private Integer rstCount; + + private String visualTest; + + private String isDisConnect; + + /** + * 盘点结果是否正确 + */ + private String checkRst; + + /** + * 左右 1:左 2:右 + */ + private Integer direction; + + /** + * 深浅 1:浅 2:深 + */ + private Integer side; + + private static String Split = "&"; + + private boolean collectOver; + + public String toString(){ + StringBuffer sb = new StringBuffer(header); + sb.append(Split).append(SRMNumber).append(Split).append(goodsLocation).append(Split) + .append(taskNo).append(Split).append(code) + .append(Split).append(count).append(Split).append(visualTest); + return sb.toString(); + } + + public String toSC02String(){ + return header+Split+SRMNumber+Split+taskNo; + } + + public static String getHeader(){ + return header; + } + + // public SCTransmission(String body){ +// String [] strings = body.split(Split); +// if(strings != null && strings.length >= 9 && strings[0].equals(header)){ +// if(strings.length == 9){ +// SRMNumber = strings[1]; +// taskNo = strings[2]; +// goodsLocation = strings[3]; +// trayNo = strings[4]; +// code = strings[5]; +// count = Integer.valueOf(strings[6]); +// visualTest = strings[7]; +// isDisConnect = strings[8]; +// direction = goodsLocation.substring(0).equals("L") ? 1:2; +// side = Integer.valueOf(goodsLocation.substring(2,3)); +// //checkType = strings[7]; +// collectOver = false; +// if("Y".equals(isDisConnect)){ +// //需要拆分之前的 +// } +// } +// +// }else if(strings.length == 3){ +// //是盘点数据采集完成的信号 +// collectOver = true; +// SRMNumber = strings[1]; +// taskNo = strings[2]; +// //goodsLocation = strings[3]; +// } +// } +//TM&6&UL062009050111&2121&11010019&30&NULL&NULL + public SCTransmission(String body){ + log.info("tmtrans body: {}", body); + String [] strings = body.split(Split); + if(strings != null && strings.length >= 9 && strings[0].equals(header)){ + if(strings.length == 9){ + SRMNumber = strings[1]; + goodsLocation = strings[2]; + taskNo = strings[3]; + category = strings[4]; + count = Integer.valueOf(strings[5]); + rstCategory = strings[6]; + rstCount = Integer.valueOf(strings[7]); + checkRst = strings[8]; + collectOver = false; + log.info("taskNo:{}, srmNumber:{}, goodsLocation:{}", taskNo, SRMNumber, goodsLocation); +// if("Y".equals(isDisConnect)){ +// //需要拆分之前的 +// } + } + + }else if(strings.length == 3){ + //是盘点数据采集完成的信号 + collectOver = true; + SRMNumber = strings[1]; + taskNo = strings[2]; + //goodsLocation = strings[3]; + } + } + + public SCTransmission(String SRMNumber,String taskId,String goodsLocation,String code,Integer count,String visual){ + this.SRMNumber = SRMNumber; + this.taskNo = taskId; + this.goodsLocation = goodsLocation; + this.code = code; + this.count = count; + this.trayNo = "Unknown"; + this.visualTest = visual; + } + + public SCTransmission(String SRMNumber,String taskId){ + this.SRMNumber = SRMNumber; + this.taskNo = taskId; + } + + public RealtimeCheckMap.CheckInfo checkInfo(){ + log.info("cheinfo start"); + RealtimeCheckMap.CheckInfo checkInfo = new RealtimeCheckMap.CheckInfo(); + Integer row = Integer.valueOf(goodsLocation.substring(8,10)); + Integer column = Integer.valueOf(goodsLocation.substring(5,8)); + Integer leftRight = Integer.valueOf(goodsLocation.substring(4,5)); + Integer inout = Integer.valueOf(goodsLocation.substring(11,12)); + checkInfo.setDirection(leftRight); + checkInfo.setColumn(column); + checkInfo.setRow(row); + checkInfo.setSide(inout); + checkInfo.setTaskNo(this.taskNo); +// checkInfo.setWMSCategory(category); +// checkInfo.setWMSCount(count); +// checkInfo.setWMSCode(code); + checkInfo.setCheckCode(goodsLocation); + checkInfo.setCheckCount(rstCount); + //checkInfo.setCheckCategory(); + return checkInfo; + } +} diff --git a/web/src/main/java/com/zhehekeji/web/service/ksec/KsecDataInfo.java b/web/src/main/java/com/zhehekeji/web/service/ksec/KsecDataInfo.java index 90ac787..0737b83 100644 --- a/web/src/main/java/com/zhehekeji/web/service/ksec/KsecDataInfo.java +++ b/web/src/main/java/com/zhehekeji/web/service/ksec/KsecDataInfo.java @@ -1,5 +1,6 @@ package com.zhehekeji.web.service.ksec; +import io.swagger.models.auth.In; import lombok.Data; @Data @@ -39,6 +40,12 @@ public class KsecDataInfo { private String trayCode; + private String typeNum; + + private Integer quantity; + + private Integer checkRlt; + /** * 盘点批次号 */ diff --git a/web/src/main/java/com/zhehekeji/web/service/ksec/KsecDecoder.java b/web/src/main/java/com/zhehekeji/web/service/ksec/KsecDecoder.java index d40c757..dba44aa 100644 --- a/web/src/main/java/com/zhehekeji/web/service/ksec/KsecDecoder.java +++ b/web/src/main/java/com/zhehekeji/web/service/ksec/KsecDecoder.java @@ -16,6 +16,8 @@ import org.springframework.util.StringUtils; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -34,6 +36,8 @@ public class KsecDecoder extends DelimiterBasedFrameDecoder { private static String lastLotnum; + public static Map ksecInfoMap = new HashMap<>(); + private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(7,21,30, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(20000)); private PlcService plcService; @@ -95,7 +99,8 @@ public class KsecDecoder extends DelimiterBasedFrameDecoder { if(dataInfo != null){ plcCmdInfo = new PlcCmdInfo(dataInfo.getSRMNumber(), dataInfo.getTaskId(), dataInfo.getFromSide(), dataInfo.getFromDirection(), dataInfo.getFromColumn(), dataInfo.getFromRow(), dataInfo.getFromSeparation(),dataInfo.getToSide(), dataInfo.getToDirection(), dataInfo.getToColumn(), dataInfo.getToRow(),dataInfo.getToSeparation(),lotnum); - + plcCmdInfo.setTypeNum(dataInfo.getTypeNum()); + plcCmdInfo.setQuantity(dataInfo.getQuantity()); srmNumber = dataInfo.getSRMNumber(); cmdName = dataInfo.getCmdName(); } @@ -182,18 +187,12 @@ public class KsecDecoder extends DelimiterBasedFrameDecoder { // log.info("other D code :{}",code); // } } else if (Cmd.E.name().equals(ksecInfo.getType())) { - //成都蜜雪冰城 没有盘点批次号,把这一块注释 lotnum -// if(!StringUtils.isEmpty(lotnum) && !lotnum.equals(lastLotnum)){ -// //需要把stock表truncate -// FileUtil.save(lotnum,"lastLotnum"); -// tcpLogger.info("truncate table ,last lotnum:{},new lotnum:{}",lastLotnum,lotnum); -// plcService.truncateStock(); -// lastLotnum = lotnum; -// } + //盘点 //转球机到盘点位 然后拍照 plcCmdInfo.setTimes(1); - //成都蜜雪冰城 将lotnum当成托盘条码描述 + ksecInfoMap.put(dataInfo.getTaskId(),dataInfo); + Boolean ok = plcService.check(plcCmdInfo,ksecInfo.getData().getCmdName(), dataInfo.getCode(), dataInfo.getTrayCode(), dataInfo.getLotnum()); // Boolean ok = true; if(ok){ diff --git a/web/src/main/resources/application-prod.yml b/web/src/main/resources/application-prod.yml index 0cc6d0e..9f60935 100644 --- a/web/src/main/resources/application-prod.yml +++ b/web/src/main/resources/application-prod.yml @@ -65,7 +65,7 @@ savePath: # ------------服务端类型 0:TCP(罗伯泰克) 1:KSEC(JSON)(昆船) serverMode: 1 ksec: - ip: 192.168.168.11 + ip: 127.0.0.1 port: 8001 #断点重连的次数:-1->不断重连 reconnectNum: -1 @@ -85,10 +85,10 @@ lightSource: index: 1 # -----tray 托盘 # -----goods 货物 -# 扫码模式 0:此处不盘点 1:球机扫码 2:sick扫码枪 3:南北达RFID +# 扫码模式 0:此处不盘点 1:球机扫码 2:sick扫码枪 3:南北达RFID 4.南京视觉客户端(只支持货物盘点) scanCodeMode: - tray: 1 - goods: 0 + tray: 3 + goods: 4 goodsCodeTypes: - 14 trayCodeTypes: @@ -98,4 +98,6 @@ deleteFileDays: 365 rfid: codeType: ISO18000_6C - scanTime: 2 \ No newline at end of file + scanTime: 2 +#视觉服务接收端口 +serverPort: 5554 \ No newline at end of file From 18245aaf00eaeb8b1192159d91411d9f06d5eb6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LAPTOP-S9HJSOEB=5C=E6=98=8A=E5=A4=A9?= Date: Tue, 9 Jul 2024 16:50:52 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E8=A7=86=E8=A7=89=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=EF=BC=8C=E6=9C=AA=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zhehekeji/web/lib/CameraDelayTask.java | 4 + .../com/zhehekeji/web/service/PlcService.java | 64 +++++- .../zhehekeji/web/service/client/Decoder.java | 142 ++++++------ .../service/client/GetPhotoDelayExecutor.java | 207 ++++++++++++++++++ .../web/service/client/NettyServer.java | 5 +- .../web/service/client/TransmissionPojo.java | 164 ++++++++++++++ .../web/service/client/TransmissionType.java | 14 ++ 7 files changed, 524 insertions(+), 76 deletions(-) create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/GetPhotoDelayExecutor.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/TransmissionPojo.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/TransmissionType.java diff --git a/web/src/main/java/com/zhehekeji/web/lib/CameraDelayTask.java b/web/src/main/java/com/zhehekeji/web/lib/CameraDelayTask.java index 3552de4..acbd293 100644 --- a/web/src/main/java/com/zhehekeji/web/lib/CameraDelayTask.java +++ b/web/src/main/java/com/zhehekeji/web/lib/CameraDelayTask.java @@ -1,5 +1,6 @@ package com.zhehekeji.web.lib; +import com.zhehekeji.web.service.client.TransmissionPojo; import lombok.AllArgsConstructor; import lombok.Data; @@ -15,9 +16,12 @@ public class CameraDelayTask implements Delayed { private LocalDateTime startTime; + + private TransmissionPojo transmissionPojo; private LocalDateTime endTime; private String path; + private String command; /** * 0 : mp4 1:jpeg diff --git a/web/src/main/java/com/zhehekeji/web/service/PlcService.java b/web/src/main/java/com/zhehekeji/web/service/PlcService.java index 186af94..521f0aa 100644 --- a/web/src/main/java/com/zhehekeji/web/service/PlcService.java +++ b/web/src/main/java/com/zhehekeji/web/service/PlcService.java @@ -14,11 +14,12 @@ import com.zhehekeji.web.pojo.OrderVO; import com.zhehekeji.web.service.RFID.RFIDMap; import com.zhehekeji.web.service.RFID.RFIDSocket; import com.zhehekeji.web.service.RFID.RFIDSocketFactory; -import com.zhehekeji.web.service.client.ClientChanel; -import com.zhehekeji.web.service.client.SCTransmission; +import com.zhehekeji.web.service.client.*; import com.zhehekeji.web.service.damLightSource.JYDAMEquip; import com.zhehekeji.web.service.damLightSource.JYDamHelper; import com.zhehekeji.web.service.hikLightSource.HikControlSocket; +import com.zhehekeji.web.service.ksec.KsecDataInfo; +import com.zhehekeji.web.service.ksec.KsecInfo; import com.zhehekeji.web.service.ksec.KsecNettyClient; import com.zhehekeji.web.service.sick.SickSocket; import lombok.extern.slf4j.Slf4j; @@ -38,6 +39,8 @@ import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingDeque; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import static org.aspectj.weaver.tools.cache.SimpleCacheFactory.path; @@ -642,6 +645,7 @@ public class PlcService { } + Lock lock = new ReentrantLock(); @Resource private LightSourceMapper lightSourceMapper; @@ -873,9 +877,65 @@ public class PlcService { long end = System.currentTimeMillis(); long s = end - startTime; log.info("time:{}millisecond", s); + TransmissionPojo transmissionPojo = new TransmissionPojo(checkLog, street); + if (ClientChanel.get(dataInfo.getSRMNumber()) != null) { + ClientChanel.get(dataInfo.getSRMNumber()).writeAndFlush(transmissionPojo.toString(TransmissionType.ST)); + } else { + log.error("未找到对应plc" + transmissionPojo.toString()); + } + //取货完成进行拍照 + try { + Thread.sleep(50L); + //不为其他状态进入队列 + if (lock.tryLock()) { + //队列中没有任务,发送取图指令 + //只采用队列,队列中有数据则自动发送 + //模拟随行 + if (configProperties.isInventorySimulationFollow() ) { + TransmissionPojo transmissionPojoFollow = new TransmissionPojo(street, transmissionPojo.getRow(),transmissionPojo.getColumn(),transmissionPojo.getDirection(), ""); + String s = (transmissionPojoFollow).toString(TransmissionType.GPS); + + //放置到队列中,等待取图返回后删除 + GetPhotoDelayExecutor.addCameraDelayTask(street.getPlcId(), s, configProperties.getQueueSpanTime(),transmissionPojoFollow); + + } + //放置到队列中,等待取图返回后删除 + GetPhotoDelayExecutor.addCameraDelayTask(street.getPlcId(), transmissionPojo.toString(TransmissionType.GPS), configProperties.getQueueSpanTime(),transmissionPojo); + } + + } catch (InterruptedException e) { + log.error("取图命令 error", e); + } finally { + lock.unlock(); + log.info("盘点完成"); + } return true; } + + public KsecInfo getKsecDataInfo(TransmissionPojo transmissionPojo, String type) { + KsecDataInfo ksecDataInfo = new KsecDataInfo(); + CheckLog checkLog = checkLogMapper.selectById(transmissionPojo.getCheckId()); + if(checkLog!=null) { + ksecDataInfo.setLotnum(checkLog.getLotnum()); + ksecDataInfo.setSRMNumber(transmissionPojo.getStreetNumber()); + ksecDataInfo.setCmdName(type); + ksecDataInfo.setTaskId(checkLog.getTaskId().toString()); + ksecDataInfo.setFromDirection(checkLog.getDirection()); + ksecDataInfo.setFromColumn(checkLog.getColumn()); + ksecDataInfo.setFromRow(checkLog.getRow()); + ksecDataInfo.setFromSide(checkLog.getSide()); + ksecDataInfo.setCode(checkLog.getCode()); + ksecDataInfo.setTrayCode(checkLog.getTrayCode()); + ksecDataInfo.setLotnum(checkLog.getLotnum()); + + + + } + + KsecInfo ksecInfo = new KsecInfo("KC", "E", ksecDataInfo); + return ksecInfo; + } public void checkLog(Stock stock){ CheckLog checkLog = new CheckLog(); checkLog.setCheckNum(stock.getCheckNum()); diff --git a/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java b/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java index 7b1e478..6b81e32 100644 --- a/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java +++ b/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java @@ -1,8 +1,11 @@ package com.zhehekeji.web.service.client; -import com.zhehekeji.web.entity.Stock; +import com.zhehekeji.web.lib.CameraDelayTask; +import com.zhehekeji.web.service.EmptyCheckService; import com.zhehekeji.web.service.PlcService; -import com.zhehekeji.web.service.ksec.*; +import com.zhehekeji.web.service.ksec.KsecInfo; +import com.zhehekeji.web.service.ksec.KsecNettyClient; +import com.zhehekeji.web.service.putian.*; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; @@ -12,15 +15,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.charset.Charset; -import java.time.LocalDateTime; -import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import static com.zhehekeji.web.service.ksec.KsecDecoder.ksecInfoMap; -import static org.aspectj.weaver.tools.cache.SimpleCacheFactory.path; - /** * 客户端解码器 连接用 */ @@ -29,20 +27,32 @@ public class Decoder extends DelimiterBasedFrameDecoder { private static final Logger tcpLogger = LoggerFactory.getLogger("tcp"); - public static String PT_CLIENT = "PT"; - private static String WCS_CLIENT = "WCS"; - private static String EMPTY_CLIENT = "EMPTY"; + public static String START_CHECK = "ST"; + private static String GET_PHOTO = "GP"; + private static String GET_PHOTO_END = "GPE"; + private static String RETURN_CHECK = "RTE"; + private static String FOLLOW_GET_PHOTO_END = "SGPE"; + private static String END_CHECK = "EN"; + private static String HEART_BEAT = "HB"; + private static String CONNECT_START = "CE"; + + + + private static String END_STRING = "$"; private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,15,30, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(20000)); + private EmptyCheckService emptyCheckService; + private PlcService plcService; - public Decoder(PlcService plcService) { + public Decoder(PlcService plcService,EmptyCheckService emptyCheckService) { super(20000,true,false, Unpooled.copiedBuffer(">".getBytes()), Unpooled.copiedBuffer("$".getBytes())); this.plcService = plcService; + this.emptyCheckService = emptyCheckService; } @Override @@ -53,7 +63,7 @@ public class Decoder extends DelimiterBasedFrameDecoder { log.debug("no data"); return null; } - ClientRunnable clientRunnable = new ClientRunnable(in,ctx,plcService); + ClientRunnable clientRunnable = new ClientRunnable(in,ctx,plcService,emptyCheckService); threadPoolExecutor.execute(clientRunnable); return null; } @@ -66,80 +76,66 @@ public class Decoder extends DelimiterBasedFrameDecoder { private PlcService plcService; + private EmptyCheckService emptyCheckService; - public ClientRunnable(ByteBuf in,ChannelHandlerContext ctx,PlcService plcService){ + public ClientRunnable(ByteBuf in,ChannelHandlerContext ctx,PlcService plcService,EmptyCheckService emptyCheckService){ this.ctx = ctx; this.in = in; this.plcService = plcService; + this.emptyCheckService = emptyCheckService; } @Override public void run() { String body = in.toString(Charset.forName("UTF-8")); - tcpLogger.info("receive client:{}, data length:{}",body, body.length()); - //视觉服务 - { - if(body.startsWith(HBTransmission.getHEADER())) { - //心跳 - HBTransmission hbTransmission = new HBTransmission(body); - //回复客户端心跳 - ctx.channel().writeAndFlush(hbTransmission.toString()); - ClientChanel.connect(hbTransmission.getSRMNumber(), ctx.channel()); - //tcpLogger.info("client:{} heart", hbTransmission.getSRMNumber()); - in.release(); - } else if(body.startsWith(SCTransmission.getHeader())){ - //盘点指令 - SCTransmission scTransmission = new SCTransmission(body); - if(scTransmission.isCollectOver()){ - //给普天发送数据采集完毕指令 - KsecDataInfo ksecDataInfo = ksecInfoMap.get(scTransmission.getTaskNo()); - ksecDataInfo.setCmdName("E2"); - KsecInfo ksecInfo = new KsecInfo("KC","E",ksecDataInfo); - KsecNettyClient.write(ksecInfo); - }else { - plcService.visualInventory(scTransmission); - - KsecDataInfo ksecDataInfo = ksecInfoMap.get(scTransmission.getTaskNo()); - ksecDataInfo.setCmdName("E3"); - ksecDataInfo.setQuantity(scTransmission.getRstCount()); - ksecDataInfo.setTypeNum(scTransmission.getRstCategory()); - ksecDataInfo.setCheckRlt(Integer.parseInt(scTransmission.getCheckRst())); - KsecInfo ksecInfo = new KsecInfo("KC","E",ksecDataInfo); - KsecNettyClient.write(ksecInfo); - ksecInfoMap.remove(scTransmission.getTaskNo()); - //添加到实时信息里 - //RealtimeCheckMap.put(scTransmission.getSRMNumber(),scTransmission.checkInfo()); - //更新盤點統計 -// emptyCheckService.updateCheckLastTime(tmTransmission.getTaskNo(),tmTransmission.getSRMNumber(),stock.getCode()); - } - in.release(); - }else if(body.startsWith(CETransmission.getHEADER())){ - //客户端建立连接 - CETransmission ceTransmission = new CETransmission(body); - //回复客户端,建立连接完成 - - ctx.channel().writeAndFlush(ceTransmission.toString()); - ClientChanel.connect(ceTransmission.getSRMNumber(), ctx.channel()); - tcpLogger.info("client:{} connect", ceTransmission.getSRMNumber()); - in.release(); + tcpLogger.info("receive client:{}, data length:{}", body, body.length()); + TransmissionPojo transmissionPojo = new TransmissionPojo(body); + //心跳进行连接 + if(HEART_BEAT.equals(transmissionPojo.getHeader()) || CONNECT_START.equals(transmissionPojo.getHeader())){ + ClientChanel.connect(transmissionPojo.getStreetNumber(),ctx.channel()); + } + //获取照片后发送进行计算逻辑,并在拍照队列中取出拍照发送 + else if(GET_PHOTO_END.equals(transmissionPojo.getHeader())){ + if(transmissionPojo.getTaskId() != null && !"0".equals(transmissionPojo.getTaskId())) { + ClientChanel.get(transmissionPojo.getStreetNumber()).writeAndFlush(transmissionPojo.toString(TransmissionType.RTS)); + + // GetPhotoDelayExecutor.addCameraDelayTask(transmissionPojo.getStreetNumber(), transmissionPojo.toString(TransmissionType.RTS), 3000); } - else if(body.startsWith("DC")){ - //客户端断开连接 - String [] strings = body.split("&"); - if(strings != null && strings.length == 2){ - tcpLogger.info("client:{} disConnect", strings[1]); - ClientChanel.disConnect(strings[1]); - } - in.release(); + try { + Thread.sleep(50L); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + //删除队列的拍照数据 + GetPhotoDelayExecutor.remove(transmissionPojo.getStreetNumber(),transmissionPojo); + //读取下一个发送 + CameraDelayTask cameraDelayTask = GetPhotoDelayExecutor.nextOne(transmissionPojo.getStreetNumber(),transmissionPojo.toString(TransmissionType.GPS)); + if (cameraDelayTask != null) { + TransmissionPojo pojo = new TransmissionPojo(cameraDelayTask.getCommand()); + ClientChanel.get(pojo.getStreetNumber()).writeAndFlush(pojo.toString(TransmissionType.GPS)); } -// else if (body.contains("EMPTY_CLIENT")){ -// ClientChanel.connect(EMPTY_CLIENT_NAME, ctx.channel()); -// tcpLogger.info("client:{} connect", EMPTY_CLIENT_NAME); -// in.release(); -// } + } + //照片和结果保存,并发送给上位机 + else if(RETURN_CHECK.equals(transmissionPojo.getHeader())){ + //保存数据 + plcService.visualCalculationResults(transmissionPojo); + //发送给上位机 + KsecInfo ksecInfo = plcService.getKsecDataInfo(transmissionPojo,"E"); + ksecInfo.getData().setTypeNum(transmissionPojo.getCategory()); + ksecInfo.getData().setQuantity(transmissionPojo.getCount()); + ksecInfo.getData().setCheckRlt(transmissionPojo.getResult()); + KsecNettyClient.write(ksecInfo); + GetPhotoDelayExecutor.removeTask(transmissionPojo.getStreetNumber(), transmissionPojo); + + + + } + //照片和结果保存,并发送给上位机 + else if(FOLLOW_GET_PHOTO_END.equals(transmissionPojo.getHeader())){ + //保存数据 + plcService.saveFollowPhoto(transmissionPojo); } } } - } diff --git a/web/src/main/java/com/zhehekeji/web/service/client/GetPhotoDelayExecutor.java b/web/src/main/java/com/zhehekeji/web/service/client/GetPhotoDelayExecutor.java new file mode 100644 index 0000000..c5a8e6a --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/GetPhotoDelayExecutor.java @@ -0,0 +1,207 @@ +package com.zhehekeji.web.service.client; + +import com.zhehekeji.common.util.SpringContextUtil; +import com.zhehekeji.web.entity.Street; +import com.zhehekeji.web.lib.CameraDelayTask; +import com.zhehekeji.web.service.PlcService; +import com.zhehekeji.web.service.ksec.KsecInfo; +import com.zhehekeji.web.service.ksec.KsecNettyClient; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +/** + * GetPhotoDelayExecutor类用于管理照片获取的延时任务。 + */ +@Slf4j +public class GetPhotoDelayExecutor { + // 延时队列,存放CameraDelayTask任务 + public static Map> cameraDelayTaskMap = new ConcurrentHashMap<>(); + // 线程池,用于执行延时任务 + public static DelayQueue delayTasks = new DelayQueue<>(); + private static ExecutorService exec = Executors.newFixedThreadPool(15); + + /** + * 向延时队列中添加一个拍照延时任务。 + * + * @param plcId 相机的PLC编号 + * @param getPhotoCommand 获取照片的命令 + * @param time 任务延时时间 + */ + public static void addCameraDelayTask(String plcId, String getPhotoCommand, long time,TransmissionPojo transmissionPojo) { + // 如果队列为空,则直接发送命令 + if(cameraDelayTaskMap.get(plcId)==null || cameraDelayTaskMap.get(plcId).size() == 0) { + if( ClientChanel.get(plcId) != null){ + log.info("队列中无数据,输出"+getPhotoCommand); + ClientChanel.get(plcId).writeAndFlush(getPhotoCommand); + }else { + + log.info("队列中无数据,未找到通信"+plcId); + } + } + // 创建一个CameraDelayTask对象,并将其添加到队列中 + CameraDelayTask cameraDelayTask = new CameraDelayTask(plcId, getPhotoCommand, time,transmissionPojo); + if(cameraDelayTaskMap.get(plcId)!=null){ + + cameraDelayTaskMap.get(plcId).add(cameraDelayTask); + }else { + cameraDelayTaskMap.put(plcId,new DelayQueue<>()); + cameraDelayTaskMap.get(plcId).add(cameraDelayTask); + } + delayTasks.add(cameraDelayTask); + } + + /** + * 根据命令和相机PLC编号从延时队列中移除任务。 + * + * @param plcId 命令行 + */ + public static CameraDelayTask remove(String plcId, TransmissionPojo transmissionPojo) { + synchronized (plcId) { + // 将延时队列中的任务转换为数组,便于遍历和移除 + Object[] objects = cameraDelayTaskMap.get(plcId).toArray(); + if(objects.length > 0) { + for(Object object : objects){ + + CameraDelayTask cameraDelayTask = (CameraDelayTask)object; + if (cameraDelayTask != null + && cameraDelayTask.getTransmissionPojo().getTaskId().equals(transmissionPojo.getTaskId()) + && cameraDelayTask.getTransmissionPojo().getCheckId().equals(transmissionPojo.getCheckId()) + && cameraDelayTask.getTransmissionPojo().getDirection().equals(transmissionPojo.getDirection())) { + cameraDelayTaskMap.get(plcId).remove(cameraDelayTask); + return cameraDelayTask; + + } + } + + + } + } + return null; + } + public static CameraDelayTask removeTask(String plcId, TransmissionPojo transmissionPojo) { + synchronized (plcId){ + // 将延时队列中的任务转换为数组,便于遍历和移除 + Object[] objects = delayTasks.toArray(); + if(objects.length > 0) { + for(Object object : objects){ + + CameraDelayTask cameraDelayTask = (CameraDelayTask)object; + if (cameraDelayTask != null + && cameraDelayTask.getTransmissionPojo().getTaskId().equals(transmissionPojo.getTaskId()) + && cameraDelayTask.getTransmissionPojo().getCheckId().equals(transmissionPojo.getCheckId()) + && cameraDelayTask.getTransmissionPojo().getDirection().equals(transmissionPojo.getDirection())) { + delayTasks.remove(cameraDelayTask); + return cameraDelayTask; + + } + } + + + } + } + return null; + } + + public static CameraDelayTask nextOne(String plcId, String getPhotoCommand) { + plcId = plcId.intern(); + synchronized (plcId) { + // 将延时队列中的任务转换为数组,便于遍历和移除 + Object[] objects = cameraDelayTaskMap.get(plcId).toArray(); + if(objects.length > 0) { + CameraDelayTask cameraDelayTask = (CameraDelayTask)objects[0]; + if (cameraDelayTask != null) { + return cameraDelayTask; + + } + } + } + return null; + } + /** + * 启动延时任务的执行器。 + */ + public static void runExecutor(List streets ) { + for (Street street: streets){ + + exec.execute(new Consumer(street)); + } + exec.execute(new TaskConsumer()); + } + + /** + * Consumer内部类,实现Runnable接口,用于消费延时队列中的任务。 + */ + private static class Consumer implements Runnable { + private Street street; + Consumer(Street street){ + this.street = street; + } + /** + * 无限循环,不断从延时队列中取出任务并执行。 + */ + @Override + public void run() { + while (true) { + try { + // 从Spring上下文中获取PlcService实例 + PlcService plcService = SpringContextUtil.getBean(PlcService.class); + // 从延时队列中获取并移除一个任务 + if (cameraDelayTaskMap.get(street.getPlcId())!=null) { + CameraDelayTask cameraDelayTask = cameraDelayTaskMap.get(street.getPlcId()).take(); +// if (cameraDelayTask != null) { +// // 构造传输对象,并将任务命令等信息设置进去 +// TransmissionPojo transmissionPojo = new TransmissionPojo(cameraDelayTask.getCommand()); +// // 调用PLC服务,模拟发送数据到上位机 +// KsecInfo ksecInfo = plcService.getKsecDataInfo(transmissionPojo, "E"); +// ksecInfo.getData().setTypeNum(transmissionPojo.getCategory()); +// ksecInfo.getData().setQuantity(transmissionPojo.getCount()); +// ksecInfo.getData().setCheckRlt(0); +// // 将信息发送给上位机 +// if (!transmissionPojo.getTaskId().equals("0")) +// KsecNettyClient.write(ksecInfo); +// } + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + private static class TaskConsumer implements Runnable { + + /** + * 无限循环,不断从延时队列中取出任务并执行。 + */ + @Override + public void run() { + while (true) { + try { + // 从Spring上下文中获取PlcService实例 + PlcService plcService = SpringContextUtil.getBean(PlcService.class); + // 从延时队列中获取并移除一个任务 + CameraDelayTask cameraDelayTask = delayTasks.take(); + if (cameraDelayTask != null) { + // 构造传输对象,并将任务命令等信息设置进去 + TransmissionPojo transmissionPojo = new TransmissionPojo(cameraDelayTask.getCommand()); + // 调用PLC服务,模拟发送数据到上位机 + KsecInfo ksecInfo = plcService.getKsecDataInfo(transmissionPojo, "E"); + ksecInfo.getData().setTypeNum(transmissionPojo.getCategory()); + ksecInfo.getData().setQuantity(transmissionPojo.getCount()); + ksecInfo.getData().setCheckRlt(0); + // 将信息发送给上位机 + if (!transmissionPojo.getTaskId().equals("0")) + KsecNettyClient.write(ksecInfo); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/NettyServer.java b/web/src/main/java/com/zhehekeji/web/service/client/NettyServer.java index 6ea7758..a52bb4e 100644 --- a/web/src/main/java/com/zhehekeji/web/service/client/NettyServer.java +++ b/web/src/main/java/com/zhehekeji/web/service/client/NettyServer.java @@ -1,5 +1,6 @@ package com.zhehekeji.web.service.client; +import com.zhehekeji.web.service.EmptyCheckService; import com.zhehekeji.web.service.PlcService; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; @@ -19,6 +20,8 @@ public class NettyServer { @Resource private PlcService plcService; + @Resource + private EmptyCheckService emptyCheckService; public void CreateNettyServer(int port) throws InterruptedException { Thread thread = new Thread(new Runnable() { @@ -39,7 +42,7 @@ public class NettyServer { @Override public void initChannel(SocketChannel ch) { ch.pipeline().addLast(new NettyConnectHandler()); - ch.pipeline().addLast(new Decoder(plcService)); + ch.pipeline().addLast(new Decoder(plcService,emptyCheckService)); ch.pipeline().addLast(new Encoder()); }}); // 子处理器,用于处理workerGroup diff --git a/web/src/main/java/com/zhehekeji/web/service/client/TransmissionPojo.java b/web/src/main/java/com/zhehekeji/web/service/client/TransmissionPojo.java new file mode 100644 index 0000000..77d7148 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/TransmissionPojo.java @@ -0,0 +1,164 @@ +package com.zhehekeji.web.service.client; + +import com.zhehekeji.web.entity.CheckLog; +import com.zhehekeji.web.entity.Street; +import lombok.Data; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +@Data +public class TransmissionPojo { + private String data; + private String[] dataArray; + private String header; + private String streetNumber;//巷道标识符 + + private Integer row;//行 + private Integer column;//列 + + private String pcd;//点位文件路径 + private String taskId; + private String checkId; + private Integer direction;//左右 + private Integer count = 0; //数量 + private String category = ""; //品规 + private Set picsPath; //照片 + + + private Integer result; + public TransmissionPojo(CheckLog checkLog , Street street){ + this.checkId = checkLog.getId().toString(); + this.streetNumber = street.getPlcId(); + this.taskId = checkLog.getLotnum(); + this.row = checkLog.getRow(); + this.column = checkLog.getColumn(); + this.direction = checkLog.getDirection(); + this.count = checkLog.getCount(); + if(checkLog.getCategory() != null && checkLog.getCategory().contains("/")) { + this.category = checkLog.getCategory().split("/")[0]; + }else { + this.category = checkLog.getCategory(); + } + + } + + /** + * 将给定数字转换为指定长度(默认3位)的字符,不足部分用“0”补全。 + * + * @param number 需要转换的数字 + * @param length 目标字符长度(默认3) + * @return 符合要求的字符串 + */ + public static String convertNumberToFixedLengthChars(int number, int length) { + if (length < 1) { + throw new IllegalArgumentException("Length must be a positive integer."); + } + + String numStr = Integer.toString(number); + while (numStr.length() < length) { + numStr = "0" + numStr; + } + return numStr; + } + public TransmissionPojo( Street street,Integer row , Integer column,Integer direction,String orderId){ + this.streetNumber = street.getPlcId(); + this.row = row; + + this.taskId = "0"; + this.direction = direction; + this.column = column; + this.checkId = convertNumberToFixedLengthChars(row, 3) + convertNumberToFixedLengthChars(column, 3); + + } + public String toString(TransmissionType type) { + this.header = type.toString(); + if (type == TransmissionType.ST) { + return "ST&" + streetNumber + "&" + checkId + "&" + taskId + "&" + direction ; + }else if (type == TransmissionType.GPS) { + return "GPS&" + streetNumber +"/"+row +"/"+column+ "&" + checkId + "&" + taskId + "&" + direction+ "&" + category + "&" + count; + }else if (type == TransmissionType.RTS) { + return "RTS&" + streetNumber +"/"+row +"/"+column+ "&" + checkId + "&" + taskId + "&" + direction + "&" + category + "&" + count; + } + return ""; + } + + public TransmissionPojo(String data) { + this.data = data; + data = data.replace(">", ""); + this.dataArray = data.split("&"); + this.header = dataArray[0]; + if(dataArray[1].contains("/")) { + String[] dataArr = dataArray[1].split("/"); + this.streetNumber = dataArr[0]; + this.row = Integer.valueOf(dataArr[1]); + if(dataArr.length > 2) { + this.column = Integer.valueOf(dataArr[2]); + } + }else { + this.streetNumber = dataArray[1]; + } + if (dataArray.length > 2) { + this.checkId = dataArray[2]; + this.taskId = (dataArray[3]); + if(dataArray[4] != null && !"".equals(dataArray[4]) && !"null".equals(dataArray[4])) { + this.direction = Integer.valueOf(dataArray[4]); + } + } + + if (dataArray.length > 5) { + if(dataArray[5] != null &&!"".equals(dataArray[5]) && !"null".equals(dataArray[5]) ) { + + this.category = dataArray[5]; + } + if( dataArray.length > 6 && dataArray[6] != null && !"".equals(dataArray[6]) && ! "null".equals(dataArray[5])) { + this.count = Integer.valueOf(dataArray[6]); + } + } + if (dataArray.length > 7) { + this.result = Integer.parseInt(dataArray[7])==0 ?0:1; + //不记录2d图像 + //String path2D = "/fileData/"+this.taskId+"/"+this.checkId+"/"+this.direction+".jpg"; + + String path3D ; + if((this.taskId!=null) && !"".equals(this.taskId)){ + path3D = "/fileData/"+this.taskId+"/"+this.checkId+"/"+(this.direction+2)+".PNG"; + }else { + path3D = "/fileData/"+this.checkId+"/"+(this.direction+2)+".PNG"; + } + Set strings = new HashSet<>(); + //strings.add(path2D); + strings.add(path3D); + + // 将数组中的元素添加到 Set 集合中 + if(dataArray.length > 8 && dataArray[8].split(";").length>0) { + String[] s = dataArray[8].split(";"); + for (int i = 0; i < s.length; i++) { + s[i] = s[i].replace("\\\\","/"); + s[i] = s[i].replace("\\","/"); + if(s[i].startsWith(".")) { + s[i] = s[i].replaceFirst(".", ""); // 移除单个字符 + } + + // 或者 + // stringArray[i] = stringArray[i].replaceAll(regexToRemove, ""); // 使用正则表达式移除字符类别 + } + Collections.addAll(strings,s); + strings.remove(""); + } + this.picsPath = strings; + + } + if(this.taskId != null && !"".equals(this.taskId) && this.checkId != null && !"".equals(this.checkId)) + this.pcd = "/fileData/"+this.taskId+"/"+this.checkId+"/"+(this.direction+2)+".pcd"; + + } + + public static void main(String[] args) { + //2024-05-31 17:52:07,909 INFO (Decoder.java:96)- receive client:RTE&001/1/9&2812&&2&0341&30&1&.\fileData\\2812\4.PNG;\fileData\\2812\2_0341_rlt.jpg&.\fileData\\2812\4.pcd, data length:106 + TransmissionPojo transmissionPojo = new TransmissionPojo("RTE&001/1/9&2812&&2&0341&30&1&.\\fileData\\\\2812\\4.PNG;\\fileData\\\\2812\\2_0341_rlt.jpg&.\\fileData\\\\2812\\4.pcd>"); + System.out.println(transmissionPojo); + } + +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/TransmissionType.java b/web/src/main/java/com/zhehekeji/web/service/client/TransmissionType.java new file mode 100644 index 0000000..40d82f6 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/TransmissionType.java @@ -0,0 +1,14 @@ +package com.zhehekeji.web.service.client; + +public enum TransmissionType { + ST , + GPS , + GPE , + SGPS , + SGPE , + RTS , + RTE , + EN , + ZHB ; + +} From d6df183a0c2207a5165c402df8fc6c0fb599b9e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LAPTOP-S9HJSOEB=5C=E6=98=8A=E5=A4=A9?= Date: Fri, 19 Jul 2024 15:45:54 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=A7=86=E8=A7=89?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/config/ConfigProperties.java | 4 + .../com/zhehekeji/web/entity/CheckLog.java | 16 +- .../java/com/zhehekeji/web/entity/Stock.java | 2 + .../zhehekeji/web/lib/CameraDelayTask.java | 9 + .../web/lib/hik/HikExceptionCallBack.java | 19 +- .../zhehekeji/web/service/InitService.java | 5 +- .../com/zhehekeji/web/service/PlcCmdInfo.java | 2 + .../com/zhehekeji/web/service/PlcService.java | 299 ++++++++++++------ .../zhehekeji/web/service/client/Decoder.java | 13 +- .../service/client/GetPhotoDelayExecutor.java | 1 + .../web/service/client/NettyServer.java | 5 +- .../web/service/client/TransmissionPojo.java | 4 +- .../web/service/ksec/KsecDecoder.java | 8 +- web/src/main/resources/application-prod.yml | 3 +- 14 files changed, 258 insertions(+), 132 deletions(-) diff --git a/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java b/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java index 1993ede..49e57c3 100644 --- a/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java +++ b/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java @@ -44,6 +44,10 @@ public class ConfigProperties { */ private Integer serverPort; + private boolean inventorySimulationFollow = false; + + private Long queueSpanTime = 5000L; + @Data public static class CameraConfig{ diff --git a/web/src/main/java/com/zhehekeji/web/entity/CheckLog.java b/web/src/main/java/com/zhehekeji/web/entity/CheckLog.java index 2d412c2..c1fac85 100644 --- a/web/src/main/java/com/zhehekeji/web/entity/CheckLog.java +++ b/web/src/main/java/com/zhehekeji/web/entity/CheckLog.java @@ -12,6 +12,8 @@ import java.time.LocalDateTime; @Data public class CheckLog { + @TableId(type = IdType.AUTO) + private Integer id; private Integer streetId; @@ -33,8 +35,13 @@ public class CheckLog { private String wmsCode; private String category; + private String taskId; private Integer count; + private Integer wmsCount; + private String wmsCategory; + + private int statusVision = 0; private String checkNum; @@ -44,10 +51,6 @@ public class CheckLog { @ApiModelProperty("扫描出的托盘码") private String trayCode; - private Integer status; - - - private String pic; private String lotnum; @@ -56,5 +59,10 @@ public class CheckLog { @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime; + private Integer status; + + private String pic; + @TableField(exist=false) + private String[] pics; } diff --git a/web/src/main/java/com/zhehekeji/web/entity/Stock.java b/web/src/main/java/com/zhehekeji/web/entity/Stock.java index 85994e8..6efd327 100644 --- a/web/src/main/java/com/zhehekeji/web/entity/Stock.java +++ b/web/src/main/java/com/zhehekeji/web/entity/Stock.java @@ -25,6 +25,7 @@ public class Stock { @ApiModelProperty("随行任务号") private String orderNum; + private int statusVision =0; @ApiModelProperty("盘点任务号") private String checkNum; @@ -91,4 +92,5 @@ public class Stock { private String streetName; + private String pcd;//点位文件路径 } diff --git a/web/src/main/java/com/zhehekeji/web/lib/CameraDelayTask.java b/web/src/main/java/com/zhehekeji/web/lib/CameraDelayTask.java index acbd293..6ea672d 100644 --- a/web/src/main/java/com/zhehekeji/web/lib/CameraDelayTask.java +++ b/web/src/main/java/com/zhehekeji/web/lib/CameraDelayTask.java @@ -30,10 +30,19 @@ public class CameraDelayTask implements Delayed { private long executeTime; + private String cameraPlcId; private long delayTime; private Integer ptzId; + public CameraDelayTask(String cameraPlcId, String command, long delayTime,TransmissionPojo transmissionPojo) { + this.cameraPlcId = cameraPlcId; + this.command = command; + this.executeTime = System.currentTimeMillis()+delayTime; + this.delayTime = delayTime; + + this.transmissionPojo = transmissionPojo; + } public CameraDelayTask(Integer cameraId, LocalDateTime startTime, LocalDateTime endTime, String path, Integer type, long delayTime) { this.cameraId = cameraId; this.startTime = startTime; diff --git a/web/src/main/java/com/zhehekeji/web/lib/hik/HikExceptionCallBack.java b/web/src/main/java/com/zhehekeji/web/lib/hik/HikExceptionCallBack.java index aec408c..2020cab 100644 --- a/web/src/main/java/com/zhehekeji/web/lib/hik/HikExceptionCallBack.java +++ b/web/src/main/java/com/zhehekeji/web/lib/hik/HikExceptionCallBack.java @@ -10,15 +10,22 @@ public class HikExceptionCallBack implements HCNetSDK.FExceptionCallBack { @Override public void invoke(int dwType, int lUserID, int lHandle, Pointer pUser) { - Integer cameraId =CameraConnMap.getCameraIdByLoginId(new NetSDKLib.LLong(lUserID)); - if(dwType == 32768){ + NetSDKLib.LLong lLong = new NetSDKLib.LLong(lUserID); + Integer cameraId =CameraConnMap.getCameraIdByLoginId(lLong); + if(dwType == 0x8000){ + if(cameraId != null) { + log.error("hik disconnect,cameraId:{}", cameraId); - log.error("hik disconnect,cameraId:{}", cameraId); - }else if(dwType == 32791){ + } + }else if(dwType == 0x8017){ - log.info("hik reconnect,cameraId:{}", CameraConnMap.getCameraIdByLoginId(new NetSDKLib.LLong(lUserID))); - } + log.info("hik reconnect,cameraId:{}", cameraId); + if(!lLong.equals(CameraConnMap.getConnId(cameraId))) { + log.error("hik reconnect,cameraId:{},lUserId:{}", cameraId,lLong); + CameraConnMap.conn(cameraId, new NetSDKLib.LLong(lUserID)); + } + } } } diff --git a/web/src/main/java/com/zhehekeji/web/service/InitService.java b/web/src/main/java/com/zhehekeji/web/service/InitService.java index dd03da0..6f2142e 100644 --- a/web/src/main/java/com/zhehekeji/web/service/InitService.java +++ b/web/src/main/java/com/zhehekeji/web/service/InitService.java @@ -13,6 +13,7 @@ import com.zhehekeji.web.lib.joyware.NetSDKLib; import com.zhehekeji.web.mapper.CameraMapper; import com.zhehekeji.web.mapper.SensorGunMapper; import com.zhehekeji.web.mapper.StreetMapper; +import com.zhehekeji.web.service.client.GetPhotoDelayExecutor; import com.zhehekeji.web.service.client.NettyServer; import com.zhehekeji.web.service.ksec.KsecNettyClient; import com.zhehekeji.web.service.robotic.NettyClient; @@ -87,6 +88,8 @@ public class InitService implements ApplicationRunner { //球机登录 List cameras = cameraMapper.selectByMap(new HashMap<>(0)); + + List streets = streetMapper.selectByMap(new HashMap<>()); cameras.forEach(camera -> { LoginThread loginThread = new LoginThread(camera); loginThread.start(); @@ -96,7 +99,6 @@ public class InitService implements ApplicationRunner { if(configProperties.getServerMode() == 0){ log.info("PLC TCP MODE"); //plc 连接状态初始化 - List streets = streetMapper.selectByMap(new HashMap<>(0)); streets.forEach(street -> { StreetConn.init(street.getId(),street.getPlcId()); @@ -123,6 +125,7 @@ public class InitService implements ApplicationRunner { } } TaskDelayExecutor.runMp4DownloadExecutor(); + GetPhotoDelayExecutor.runExecutor(streets); } class LoginThread extends Thread{ diff --git a/web/src/main/java/com/zhehekeji/web/service/PlcCmdInfo.java b/web/src/main/java/com/zhehekeji/web/service/PlcCmdInfo.java index 85f1e37..c6edd13 100644 --- a/web/src/main/java/com/zhehekeji/web/service/PlcCmdInfo.java +++ b/web/src/main/java/com/zhehekeji/web/service/PlcCmdInfo.java @@ -69,6 +69,8 @@ public class PlcCmdInfo { private Integer times; + private String code; + private String lotnum; private Integer streetId; diff --git a/web/src/main/java/com/zhehekeji/web/service/PlcService.java b/web/src/main/java/com/zhehekeji/web/service/PlcService.java index 521f0aa..6486f27 100644 --- a/web/src/main/java/com/zhehekeji/web/service/PlcService.java +++ b/web/src/main/java/com/zhehekeji/web/service/PlcService.java @@ -11,6 +11,7 @@ import com.zhehekeji.web.lib.*; import com.zhehekeji.web.mapper.*; import com.zhehekeji.web.pojo.CameraPtzPojo; import com.zhehekeji.web.pojo.OrderVO; +import com.zhehekeji.web.pojo.stock.StockStatus; import com.zhehekeji.web.service.RFID.RFIDMap; import com.zhehekeji.web.service.RFID.RFIDSocket; import com.zhehekeji.web.service.RFID.RFIDSocketFactory; @@ -41,6 +42,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; import static org.aspectj.weaver.tools.cache.SimpleCacheFactory.path; @@ -652,7 +654,26 @@ public class PlcService { public Boolean check(PlcCmdInfo plcCmdInfo,String cmdCode,String wmsCode,String wmsTrayCode,String wmsCatagary){ long startTime = System.currentTimeMillis(); + Street street = streetService.getStreetByPlcId(plcCmdInfo.getPlcId()); + + //开始盘点具体货位 + CheckLog checkLog = new CheckLog(); + checkLog.setStreetId(street.getId()); + checkLog.setLotnum(plcCmdInfo.getLotnum()); + checkLog.setDirection(plcCmdInfo.getLeftRight1()); + checkLog.setSide(plcCmdInfo.getSide1()); + checkLog.setRow(plcCmdInfo.getRow1()); + checkLog.setColumn(plcCmdInfo.getColumn1()); + checkLog.setWmsCode(plcCmdInfo.getCode()); + + checkLog.setTaskId((plcCmdInfo.getTaskId())); + //默认未盘点 + checkLog.setStatus(StockStatus.PENDING.getStatus()); + checkLog.setCreateTime(LocalDateTime.now()); + checkLog.setWmsCategory(plcCmdInfo.getTypeNum()); + checkLog.setWmsCount(plcCmdInfo.getQuantity()); + CronTab.putTime(street.getId()); List lightSources = lightSourceMapper.selectList(new QueryWrapper().eq("street_id",street.getId())); lightSources.forEach(lightSource -> { @@ -680,76 +701,26 @@ public class PlcService { String path = PathUtil.createFileNameByRowColumn("jpg", cameraId, plcCmdInfo.getRow1(), plcCmdInfo.getColumn1()); + try { cameraCapture(cameraId, false, null, path); } catch (NullPointerException e) { log.error("相机{}未连接无法拍照", cameraId); } + + checkLog.setPic(path); + checkLogMapper.insert(checkLog); //托盘码 String trayCode = null; Boolean trayCheck = Boolean.TRUE; //扫托盘码 - if(configProperties.getScanCodeMode().getTray() == 2) { - log.info("扫码类型:" + configProperties.getScanCodeMode().getTray()); - //托盘使用sick扫码枪 - SensorGun sensorGun = sensorService.getSensorByPlc(street.getId(), plcCmdInfo.getLeftRight1()); - if (sensorGun == null) { - trayCode = "扫码枪未配置"; - trayCheck = Boolean.FALSE; - log.error("no sensor gun config in database ,street id:{},direction:{}", street.getId(), plcCmdInfo.getLeftRight1()); - } else { - trayCode = SickSocket.readOCR(sensorGun.getIp(), sensorGun.getPort()); - log.info("sensor tray code:{}", trayCode); - if ("".equals(wmsTrayCode)) { - //托盘码为空,无货物 - //只要扫码枪未识别出条码,即认为盘点正确 - if (StringUtils.isEmpty(trayCode) || trayCode.equals("NoRead")) { - trayCode = "无货物"; - trayCheck = Boolean.TRUE; - } else { - trayCode = "扫码枪识别异常"; - trayCheck = Boolean.FALSE; - log.warn("sick ocr error:{}", trayCode); - } - } else { - if (StringUtils.isEmpty(trayCode) || trayCode.equals("NoRead")) { - trayCode = "扫码枪识别异常"; - trayCheck = Boolean.FALSE; - log.warn("sick ocr error:{}", trayCode); - } else { - //扫到就认为正常 - trayCheck = Boolean.TRUE; - } - } - } - }else if(configProperties.getScanCodeMode().getTray() == 3){ - //扫到的码 - Set tags = new HashSet<>(); - try { - RFIDCheck(plcCmdInfo, true); - Thread.sleep(1000 * configProperties.getRfid().getScanTime()); - } catch (Exception e) { - e.printStackTrace(); - } finally { - tags = RFIDStop(plcCmdInfo); - log.info("盘点rfid扫描结果:" + tags); - } - if (tags !=null && tags.contains(wmsTrayCode)) { - //托盘码为空,无货物 - //只要扫码枪未识别出条码,即认为盘点正确 - trayCode = wmsTrayCode; - trayCheck = Boolean.TRUE; + trayCheck = scan(configProperties.getScanCodeMode().getTray(),street,plcCmdInfo,checkLog,trayCode); - } else { - trayCode = trayCode+ "扫码枪识别异常"; - trayCheck = Boolean.FALSE; - log.warn("rfid error:{}", trayCode); - } - } - Boolean trayGoodCheck = Boolean.TRUE; + String trayGoodCode = null; + Boolean trayGoodCheck = scan(configProperties.getScanCodeMode().getGoods(),street,plcCmdInfo,checkLog,trayGoodCode); OrderInfo orderInfo = new OrderInfo(street, plcCmdInfo, 1, cmdCode); //扫货物 @@ -786,7 +757,8 @@ public class PlcService { } } } - }else if(configProperties.getScanCodeMode().getGoods() == 3){ + }else + if(configProperties.getScanCodeMode().getGoods() == 3){ Set tags = new HashSet<>(); try { RFIDCheck(plcCmdInfo, true); @@ -809,31 +781,49 @@ public class PlcService { log.warn("rfid error:{}", trayCode); } - }else if (configProperties.getScanCodeMode().getGoods() == 4){ - //开始盘点 - String goodLocation = orderInfo.getStreetId().toString()+"_"+ plcCmdInfo.getLeftRight1().toString()+"_"+ orderInfo.getSeparation().toString()+"_"+ orderInfo.getRow().toString()+"_"+ orderInfo.getColumn(); - SCTransmission scTransmission = new SCTransmission(street.getPlcId(),plcCmdInfo.getTaskId(),goodLocation,plcCmdInfo.getTypeNum(), plcCmdInfo.getQuantity(), "N"); - - String scTransmissionStr = scTransmission.toString(); - ClientChanel.write(scTransmissionStr,street.getPlcId()); + }else + if (configProperties.getScanCodeMode().getGoods() == 4){ + TransmissionPojo transmissionPojo = new TransmissionPojo(checkLog, street); + if (ClientChanel.get(plcCmdInfo.getPlcId()) != null) { + ClientChanel.get(plcCmdInfo.getPlcId()).writeAndFlush(transmissionPojo.toString(TransmissionType.ST)); + } else { + log.error("未找到对应plc" + transmissionPojo.toString()); + } + //取货完成进行拍照 try { - Thread.sleep(500); + Thread.sleep(50L); + //不为其他状态进入队列 + if (lock.tryLock()) { + //队列中没有任务,发送取图指令 + //只采用队列,队列中有数据则自动发送 + //模拟随行 + if (configProperties.isInventorySimulationFollow() ) { + TransmissionPojo transmissionPojoFollow = new TransmissionPojo(street, transmissionPojo.getRow(),transmissionPojo.getColumn(),transmissionPojo.getDirection(), ""); + String s = (transmissionPojoFollow).toString(TransmissionType.GPS); + + //放置到队列中,等待取图返回后删除 + GetPhotoDelayExecutor.addCameraDelayTask(street.getPlcId(), s, configProperties.getQueueSpanTime(),transmissionPojoFollow); + + + } + //放置到队列中,等待取图返回后删除 + GetPhotoDelayExecutor.addCameraDelayTask(street.getPlcId(), transmissionPojo.toString(TransmissionType.GPS), configProperties.getQueueSpanTime(),transmissionPojo); + } + } catch (InterruptedException e) { - throw new RuntimeException(e); + log.error("取图命令 error", e); + } finally { + lock.unlock(); + log.info("盘点完成"); } - //滁州开始盘点即取货到位 - - SCTransmission scTransmission2 = new SCTransmission(street.getPlcId(),plcCmdInfo.getTaskId()); - String scTransmissionStr2 = scTransmission2.toSC02String(); - ClientChanel.write(scTransmissionStr2,street.getPlcId()); } - Stock stock = stockMapper.getByStreetAndDirectionAndSideAndRowColumn(orderInfo.getStreetId(), plcCmdInfo.getLeftRight1(), orderInfo.getSeparation(), orderInfo.getRow(), orderInfo.getColumn()); String scanCode = null; //货物使用球机扫码 + checkLog.setTrayCode(trayCode); log.info("code:{}", scanCode); //核对异常 Integer status = 1; @@ -841,6 +831,8 @@ public class PlcService { if (trayCheck && trayGoodCheck ) { status = 2; } + checkLog.setStatus(status); + checkLogMapper.updateById(checkLog); if (stock == null) { stock = Stock.builder() .checkNum(plcCmdInfo.getOrderNum()) @@ -872,47 +864,115 @@ public class PlcService { } // StockCheckRunnable stockCheckRunnable = new StockCheckRunnable(street,plcCmdInfo,cmdCode,stockMapper,path,checkLogMapper,configProperties.getScanCodeMode().getGoods(),wmsCode,wmsTrayCode,trayCode,trayCheck,configProperties,sensorGun); // threadPoolExecutor.execute(stockCheckRunnable); + //还原相机 gyrateCameraByCode(cameraId, "C5"); long end = System.currentTimeMillis(); - long s = end - startTime; - log.info("time:{}millisecond", s); - TransmissionPojo transmissionPojo = new TransmissionPojo(checkLog, street); - if (ClientChanel.get(dataInfo.getSRMNumber()) != null) { - ClientChanel.get(dataInfo.getSRMNumber()).writeAndFlush(transmissionPojo.toString(TransmissionType.ST)); - } else { - log.error("未找到对应plc" + transmissionPojo.toString()); - } - //取货完成进行拍照 - try { - Thread.sleep(50L); - //不为其他状态进入队列 - if (lock.tryLock()) { - //队列中没有任务,发送取图指令 - //只采用队列,队列中有数据则自动发送 - //模拟随行 - if (configProperties.isInventorySimulationFollow() ) { - TransmissionPojo transmissionPojoFollow = new TransmissionPojo(street, transmissionPojo.getRow(),transmissionPojo.getColumn(),transmissionPojo.getDirection(), ""); - String s = (transmissionPojoFollow).toString(TransmissionType.GPS); + long timeLong = end - startTime; + log.info("time:{}millisecond", timeLong); - //放置到队列中,等待取图返回后删除 - GetPhotoDelayExecutor.addCameraDelayTask(street.getPlcId(), s, configProperties.getQueueSpanTime(),transmissionPojoFollow); + return true; + } + Boolean scan(int type ,Street street, PlcCmdInfo plcCmdInfo,CheckLog checkLog ,String trayCode){ + Boolean checkBoolean = true; + if(type == 2) { + checkBoolean = Boolean.FALSE; + log.info("扫码类型:" + configProperties.getScanCodeMode().getTray()); + //托盘使用sick扫码枪 + SensorGun sensorGun = sensorService.getSensorByPlc(street.getId(), plcCmdInfo.getLeftRight1()); + if (sensorGun == null) { + trayCode = "扫码枪识别异常"; + log.error("no sensor gun config in database ,street id:{},direction:{}", street.getId(), plcCmdInfo.getLeftRight1()); + } else { + trayCode = SickSocket.readOCR(sensorGun.getIp(), sensorGun.getPort()); + log.info("sensor tray code:{}", trayCode); + if ("".equals(plcCmdInfo.getCode())) { + //托盘码为空,无货物 + //只要扫码枪未识别出条码,即认为盘点正确 + if (StringUtils.isEmpty(trayCode) || trayCode.equals("NoRead")) { + trayCode = ""; + checkBoolean = Boolean.TRUE; + } else { + trayCode = "扫码枪识别异常"; + checkBoolean = Boolean.FALSE; + log.warn("sick ocr error:{}", trayCode); + } + } else { + if (StringUtils.isEmpty(trayCode) || trayCode.equals("NoRead")) { + trayCode = "扫码枪识别异常"; + checkBoolean = Boolean.FALSE; + log.warn("sick ocr error:{}", trayCode); + } else { + //扫到就认为正常 + checkBoolean = Boolean.TRUE; + } } - //放置到队列中,等待取图返回后删除 - GetPhotoDelayExecutor.addCameraDelayTask(street.getPlcId(), transmissionPojo.toString(TransmissionType.GPS), configProperties.getQueueSpanTime(),transmissionPojo); } + }else + if(type == 3){ + Set tags = new HashSet<>(); + try { + RFIDCheck(plcCmdInfo, true); + Thread.sleep(1000 * configProperties.getRfid().getScanTime()); + } catch (Exception e) { + e.printStackTrace(); + } finally { + tags = RFIDStop(plcCmdInfo); + log.info("盘点rfid扫描结果:" + tags); + } + if (tags !=null && tags.contains(plcCmdInfo.getCode())) { + //托盘码为空,无货物 + //只要扫码枪未识别出条码,即认为盘点正确 + trayCode = plcCmdInfo.getCode(); + checkBoolean = Boolean.TRUE; + + } else { + trayCode = trayCode+ "扫码枪识别异常"; + checkBoolean = Boolean.FALSE; + log.warn("rfid error:{}", trayCode); + + } + }else + if (type == 4){ + TransmissionPojo transmissionPojo = new TransmissionPojo(checkLog, street); + if (ClientChanel.get(plcCmdInfo.getPlcId()) != null) { + ClientChanel.get(plcCmdInfo.getPlcId()).writeAndFlush(transmissionPojo.toString(TransmissionType.ST)); + } else { + log.error("未找到对应plc" + transmissionPojo.toString()); + } + //取货完成进行拍照 + try { + Thread.sleep(50L); + //不为其他状态进入队列 + if (lock.tryLock()) { + //队列中没有任务,发送取图指令 + //只采用队列,队列中有数据则自动发送 + //模拟随行 + if (configProperties.isInventorySimulationFollow() ) { + TransmissionPojo transmissionPojoFollow = new TransmissionPojo(street, transmissionPojo.getRow(),transmissionPojo.getColumn(),transmissionPojo.getDirection(), ""); + String s = (transmissionPojoFollow).toString(TransmissionType.GPS); - } catch (InterruptedException e) { - log.error("取图命令 error", e); - } finally { - lock.unlock(); - log.info("盘点完成"); + //放置到队列中,等待取图返回后删除 + GetPhotoDelayExecutor.addCameraDelayTask(street.getPlcId(), s, configProperties.getQueueSpanTime(),transmissionPojoFollow); + + + } + //放置到队列中,等待取图返回后删除 + GetPhotoDelayExecutor.addCameraDelayTask(street.getPlcId(), transmissionPojo.toString(TransmissionType.GPS), configProperties.getQueueSpanTime(),transmissionPojo); + } + + } catch (InterruptedException e) { + log.error("取图命令 error", e); + } finally { + lock.unlock(); + log.info("盘点完成"); + } } - return true; - } + return checkBoolean; + } public KsecInfo getKsecDataInfo(TransmissionPojo transmissionPojo, String type) { KsecDataInfo ksecDataInfo = new KsecDataInfo(); CheckLog checkLog = checkLogMapper.selectById(transmissionPojo.getCheckId()); @@ -1042,4 +1102,37 @@ public class PlcService { } checkLog(stock); } + + + public void visualCalculationResults(TransmissionPojo transmissionPojo) { + CheckLog checkLog = checkLogMapper.selectById(transmissionPojo.getCheckId()); + Stock stock = stockMapper.selectOne(new QueryWrapper().eq("check_Num", checkLog.getId())); + Street street = streetService.getStreetByPlcId(transmissionPojo.getStreetNumber()); + if (transmissionPojo.getResult() != null && transmissionPojo.getResult() == 1) { + checkLog.setStatusVision(StockStatus.SUCCESS.getStatus()); + stock.setStatusVision(StockStatus.SUCCESS.getStatus()); + } else { + checkLog.setStatusVision(StockStatus.ERROR.getStatus()); + stock.setStatusVision(StockStatus.ERROR.getStatus()); + stock.setCount(transmissionPojo.getCount()); + stock.setCategory(transmissionPojo.getCategory()); + } + + if (transmissionPojo.getPcd() != null && !"".equals(transmissionPojo.getPcd())) { + stock.setPcd("http://" + street.getPlcIp() + ":8007" + transmissionPojo.getPcd()); + } + if (transmissionPojo.getPicsPath() != null && transmissionPojo.getPicsPath().size() > 0) { + + String pics = transmissionPojo.getPicsPath().stream().map(v -> { + return "http://" + street.getPlcIp() + ":8007" + v; + }).collect(Collectors.joining(";")); + checkLog.setPic(pics); + stock.setCheckPic(pics); + } + checkLogMapper.updateById(checkLog); + stockMapper.updateById(stock); + } + + public void saveFollowPhoto(TransmissionPojo transmissionPojo) { + } } diff --git a/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java b/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java index 6b81e32..11024ef 100644 --- a/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java +++ b/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java @@ -1,11 +1,9 @@ package com.zhehekeji.web.service.client; import com.zhehekeji.web.lib.CameraDelayTask; -import com.zhehekeji.web.service.EmptyCheckService; import com.zhehekeji.web.service.PlcService; import com.zhehekeji.web.service.ksec.KsecInfo; import com.zhehekeji.web.service.ksec.KsecNettyClient; -import com.zhehekeji.web.service.putian.*; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; @@ -43,16 +41,15 @@ public class Decoder extends DelimiterBasedFrameDecoder { private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,15,30, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(20000)); - private EmptyCheckService emptyCheckService; + private PlcService plcService; - public Decoder(PlcService plcService,EmptyCheckService emptyCheckService) { + public Decoder(PlcService plcService) { super(20000,true,false, Unpooled.copiedBuffer(">".getBytes()), Unpooled.copiedBuffer("$".getBytes())); this.plcService = plcService; - this.emptyCheckService = emptyCheckService; } @Override @@ -63,7 +60,7 @@ public class Decoder extends DelimiterBasedFrameDecoder { log.debug("no data"); return null; } - ClientRunnable clientRunnable = new ClientRunnable(in,ctx,plcService,emptyCheckService); + ClientRunnable clientRunnable = new ClientRunnable(in,ctx,plcService); threadPoolExecutor.execute(clientRunnable); return null; } @@ -76,13 +73,11 @@ public class Decoder extends DelimiterBasedFrameDecoder { private PlcService plcService; - private EmptyCheckService emptyCheckService; - public ClientRunnable(ByteBuf in,ChannelHandlerContext ctx,PlcService plcService,EmptyCheckService emptyCheckService){ + public ClientRunnable(ByteBuf in,ChannelHandlerContext ctx,PlcService plcService){ this.ctx = ctx; this.in = in; this.plcService = plcService; - this.emptyCheckService = emptyCheckService; } @Override diff --git a/web/src/main/java/com/zhehekeji/web/service/client/GetPhotoDelayExecutor.java b/web/src/main/java/com/zhehekeji/web/service/client/GetPhotoDelayExecutor.java index c5a8e6a..db5e4d1 100644 --- a/web/src/main/java/com/zhehekeji/web/service/client/GetPhotoDelayExecutor.java +++ b/web/src/main/java/com/zhehekeji/web/service/client/GetPhotoDelayExecutor.java @@ -52,6 +52,7 @@ public class GetPhotoDelayExecutor { cameraDelayTaskMap.put(plcId,new DelayQueue<>()); cameraDelayTaskMap.get(plcId).add(cameraDelayTask); } + delayTasks.add(cameraDelayTask); } diff --git a/web/src/main/java/com/zhehekeji/web/service/client/NettyServer.java b/web/src/main/java/com/zhehekeji/web/service/client/NettyServer.java index a52bb4e..6ea7758 100644 --- a/web/src/main/java/com/zhehekeji/web/service/client/NettyServer.java +++ b/web/src/main/java/com/zhehekeji/web/service/client/NettyServer.java @@ -1,6 +1,5 @@ package com.zhehekeji.web.service.client; -import com.zhehekeji.web.service.EmptyCheckService; import com.zhehekeji.web.service.PlcService; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; @@ -20,8 +19,6 @@ public class NettyServer { @Resource private PlcService plcService; - @Resource - private EmptyCheckService emptyCheckService; public void CreateNettyServer(int port) throws InterruptedException { Thread thread = new Thread(new Runnable() { @@ -42,7 +39,7 @@ public class NettyServer { @Override public void initChannel(SocketChannel ch) { ch.pipeline().addLast(new NettyConnectHandler()); - ch.pipeline().addLast(new Decoder(plcService,emptyCheckService)); + ch.pipeline().addLast(new Decoder(plcService)); ch.pipeline().addLast(new Encoder()); }}); // 子处理器,用于处理workerGroup diff --git a/web/src/main/java/com/zhehekeji/web/service/client/TransmissionPojo.java b/web/src/main/java/com/zhehekeji/web/service/client/TransmissionPojo.java index 77d7148..19766bc 100644 --- a/web/src/main/java/com/zhehekeji/web/service/client/TransmissionPojo.java +++ b/web/src/main/java/com/zhehekeji/web/service/client/TransmissionPojo.java @@ -35,9 +35,9 @@ public class TransmissionPojo { this.row = checkLog.getRow(); this.column = checkLog.getColumn(); this.direction = checkLog.getDirection(); - this.count = checkLog.getCount(); + this.count = checkLog.getWmsCount(); if(checkLog.getCategory() != null && checkLog.getCategory().contains("/")) { - this.category = checkLog.getCategory().split("/")[0]; + this.category = checkLog.getWmsCategory().split("/")[0]; }else { this.category = checkLog.getCategory(); } diff --git a/web/src/main/java/com/zhehekeji/web/service/ksec/KsecDecoder.java b/web/src/main/java/com/zhehekeji/web/service/ksec/KsecDecoder.java index dba44aa..935591b 100644 --- a/web/src/main/java/com/zhehekeji/web/service/ksec/KsecDecoder.java +++ b/web/src/main/java/com/zhehekeji/web/service/ksec/KsecDecoder.java @@ -103,6 +103,12 @@ public class KsecDecoder extends DelimiterBasedFrameDecoder { plcCmdInfo.setQuantity(dataInfo.getQuantity()); srmNumber = dataInfo.getSRMNumber(); cmdName = dataInfo.getCmdName(); + if(dataInfo.getCode()!=null && !"".equals(dataInfo.getCode())){ + plcCmdInfo.setCode(dataInfo.getCode()); + }else if(dataInfo.getTrayCode()!=null && !"".equals(dataInfo.getTrayCode())){ + plcCmdInfo.setCode(dataInfo.getTrayCode()); + } + } if (Cmd.A.name().equals(ksecInfo.getType())) { //心跳 @@ -193,7 +199,7 @@ public class KsecDecoder extends DelimiterBasedFrameDecoder { plcCmdInfo.setTimes(1); ksecInfoMap.put(dataInfo.getTaskId(),dataInfo); - Boolean ok = plcService.check(plcCmdInfo,ksecInfo.getData().getCmdName(), dataInfo.getCode(), dataInfo.getTrayCode(), dataInfo.getLotnum()); + Boolean ok = plcService.check(plcCmdInfo,ksecInfo.getData().getCmdName(), plcCmdInfo.getCode(), plcCmdInfo.getCode(), dataInfo.getLotnum()); // Boolean ok = true; if(ok){ ksecInfo.getData().setAckStatus(1); diff --git a/web/src/main/resources/application-prod.yml b/web/src/main/resources/application-prod.yml index 9f60935..5cbf4a9 100644 --- a/web/src/main/resources/application-prod.yml +++ b/web/src/main/resources/application-prod.yml @@ -31,7 +31,6 @@ cameraConfig: cameraPassword: a1234567 cameraUser: admin cameraPort: 8000 - videoServer: 127.0.0.1:8083 #相机抓图延迟 毫秒,这个延迟是等待球机球机转动到位,然后拍照的 delayCaptureTime: 3500 #随行模式下的相机抓图延迟 毫秒,这个延迟是等待球机球机转动到位,然后拍照的 @@ -87,7 +86,7 @@ lightSource: # -----goods 货物 # 扫码模式 0:此处不盘点 1:球机扫码 2:sick扫码枪 3:南北达RFID 4.南京视觉客户端(只支持货物盘点) scanCodeMode: - tray: 3 + tray: 2 goods: 4 goodsCodeTypes: - 14