From 62bcc185b02e8db345274542ade9cd3c661789a2 Mon Sep 17 00:00:00 2001 From: yiming Date: Fri, 26 Aug 2022 14:38:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E9=80=9A=E8=AE=AF?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zhehekeji/web/service/GoodsEmptyMap.java | 46 ++++ .../zhehekeji/web/service/InitService.java | 2 + .../web/service/client/CETransmission.java | 18 ++ .../web/service/client/ClientChanel.java | 3 +- .../web/service/client/ClientDecoder.java | 215 ------------------ .../zhehekeji/web/service/client/Decoder.java | 71 ++++++ .../client/EmptyTrayCheckTransmission.java | 12 + .../zhehekeji/web/service/client/Encoder.java | 22 ++ .../web/service/client/HBTransmission.java | 30 +++ .../web/service/client/NettyServer.java | 50 ++++ .../web/service/client/TMTransmission.java | 56 +++++ 11 files changed, 309 insertions(+), 216 deletions(-) create mode 100644 web/src/main/java/com/zhehekeji/web/service/GoodsEmptyMap.java delete mode 100644 web/src/main/java/com/zhehekeji/web/service/client/ClientDecoder.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/EmptyTrayCheckTransmission.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/NettyServer.java diff --git a/web/src/main/java/com/zhehekeji/web/service/GoodsEmptyMap.java b/web/src/main/java/com/zhehekeji/web/service/GoodsEmptyMap.java new file mode 100644 index 0000000..583565c --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/GoodsEmptyMap.java @@ -0,0 +1,46 @@ +package com.zhehekeji.web.service; + +import lombok.Data; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * 空货位检测的存储map + */ +public class GoodsEmptyMap { + + private static Map> shelveEmptyMap = new HashMap<>(); + + public void startEmptyCheck(String SRMNumber){ + shelveEmptyMap.put(SRMNumber,new HashSet<>()); + } + + public Set getEmptyCheck(String SRMNumber){ + return shelveEmptyMap.get(SRMNumber); + } + + /** + * + */ + public void Position(){ + + } + +// @Data +// public static class ShelveEmptyMap{ +// +// /** +// * {左右}{深浅}{行}{列} +// * L 01 0001 0002 +// */ +// private String position; +// /** +// * true: 空 +// * false: 非空 +// */ +// private Boolean isEmpty; +// } +} 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 31a61d3..afffa22 100644 --- a/web/src/main/java/com/zhehekeji/web/service/InitService.java +++ b/web/src/main/java/com/zhehekeji/web/service/InitService.java @@ -12,6 +12,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; @@ -78,6 +79,7 @@ public class InitService implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { + NettyServer.CreateNettyServer(3001); //球机登录 List cameras = cameraMapper.selectByMap(new HashMap<>(0)); cameras.forEach(camera -> { 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 index 34a597b..6e4c652 100644 --- a/web/src/main/java/com/zhehekeji/web/service/client/CETransmission.java +++ b/web/src/main/java/com/zhehekeji/web/service/client/CETransmission.java @@ -8,5 +8,23 @@ import lombok.Data; */ public class CETransmission { + private static String HEADER = "CE"; + private String SRMNumber; + + public String toString(){ + return HEADER + "," + SRMNumber; + } + + public static String getHEADER(){ + return HEADER; + } + + public CETransmission(String body){ + String [] strings = body.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 index cb99b11..5a2224b 100644 --- a/web/src/main/java/com/zhehekeji/web/service/client/ClientChanel.java +++ b/web/src/main/java/com/zhehekeji/web/service/client/ClientChanel.java @@ -2,6 +2,7 @@ package com.zhehekeji.web.service.client; import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; import java.util.HashMap; import java.util.Map; @@ -17,7 +18,7 @@ public class ClientChanel { private static Map channelMap = new HashMap<>(); - public static void connect(String key,Channel channel){ + public static void connect(String key, Channel channel){ channelMap.put(key,channel); } diff --git a/web/src/main/java/com/zhehekeji/web/service/client/ClientDecoder.java b/web/src/main/java/com/zhehekeji/web/service/client/ClientDecoder.java deleted file mode 100644 index cb07e4e..0000000 --- a/web/src/main/java/com/zhehekeji/web/service/client/ClientDecoder.java +++ /dev/null @@ -1,215 +0,0 @@ -package com.zhehekeji.web.service.client; - -import com.alibaba.fastjson.JSONObject; -import com.zhehekeji.web.pojo.Cmd; -import com.zhehekeji.web.service.GoodsActionTimes; -import com.zhehekeji.web.service.PlcCmdInfo; -import com.zhehekeji.web.service.PlcService; -import com.zhehekeji.web.service.ksec.KsecDataInfo; -import com.zhehekeji.web.service.ksec.KsecInfo; -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 org.springframework.util.StringUtils; - -import java.nio.charset.Charset; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -/** - * 客户端解码器 - */ -@Slf4j -public class ClientDecoder extends DelimiterBasedFrameDecoder { - - private static final Logger tcpLogger = LoggerFactory.getLogger("client_tcp"); - - - private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(7,21,30, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(20000)); - - - public ClientDecoder(ByteBuf byteBuf) { - super(1000, byteBuf); - //ByteBuf byteBuf = Unpooled.copiedBuffer("AM".getBytes()); - - } - - @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 kescRunnable = new ClientRunnable(in,ctx); - threadPoolExecutor.execute(kescRunnable); - return null; - } - - /** - * 要找到对应的客户端 - */ - public static class ClientRunnable implements Runnable{ - - private ByteBuf in; - - private ChannelHandlerContext ctx; - - - public ClientRunnable(ByteBuf body,ChannelHandlerContext ctx){ - this.in = body; - this.ctx = ctx; - } - - @Override - public void run() { - String body = in.toString(Charset.forName("UTF-8")); - tcpLogger.info(body); - if (body.startsWith("AM")){ - // 去掉首尾标识符 - body = body.substring(1, body.length()); - KsecInfo ksecInfo = JSONObject.parseObject(body, KsecInfo.class); - if (Cmd.A.name().equals(ksecInfo.getType())) { - in.release(); - return ; - } - KsecDataInfo dataInfo = ksecInfo.getData(); - String lotnum = dataInfo.getLotnum(); - PlcCmdInfo plcCmdInfo = null; - String srmNumber = null; - String cmdName = null; - if(dataInfo != null){ - //左右换过来 - if(dataInfo.getFromDirection() == 1){ - dataInfo.setFromDirection(2); - }else { - dataInfo.setFromDirection(1); - } - if(dataInfo.getToDirection() != null && dataInfo.getToDirection() == 1){ - dataInfo.setToDirection(2); - }else { - dataInfo.setToDirection(1); - } - 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); - - srmNumber = dataInfo.getSRMNumber(); - cmdName = dataInfo.getCmdName(); - } - if (Cmd.A.name().equals(ksecInfo.getType())) { - //心跳 - log.debug("receieve heart "); - } else if (Cmd.B.name().equals(ksecInfo.getType())) { - - //任务 - if (Cmd.B1.name().equals(cmdName)) { - //昆船盘点模式下也会发B1 ,但是不会发送B2 - //这里判断下,是否存在盘点批次号 若存在,既是盘点的B1,无需处理;若不存在lotnum,则是随行的B1 - if(StringUtils.isEmpty(dataInfo.getLotnum())){ - //任务开始 旋转到原点位 - plcService.gyrateCamera(plcCmdInfo,Cmd.C5.name()); - plcService.orderStart(plcCmdInfo); - }else { - log.info("check move"); - } - - } else if (Cmd.B2.name().equals(cmdName)) { - //B2 C4 一起发的,需要停止等B2 - - //这里判断是不是双伸 - if(plcCmdInfo.getSeparation2() == 2){ - //深测货架延迟 - try { - Thread.sleep(plcService.getConfigProperties().getCameraConfig().getB2OutDelayTime()); - } catch (InterruptedException e) { - e.printStackTrace(); - } - }else { - //浅侧延迟 - try { - Thread.sleep(plcService.getConfigProperties().getCameraConfig().getB2DelayTime()); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - plcService.gyrateCamera(plcCmdInfo,Cmd.C5.name()); - plcService.orderStop(plcCmdInfo); - } - } else if (Cmd.C.name().equals(ksecInfo.getType())) { - - //动作 - String code = dataInfo.getCmdName(); - log.info("action code,{},orderInfo:{}", code, plcCmdInfo.toString()); - if (Cmd.isBaseAction(code)) { - //执行动作,需要保存执行到第几步了 - Integer times = GoodsActionTimes.put(plcCmdInfo.getOrderNum()); - plcCmdInfo.setTimes(times); - code = code + "-" + plcCmdInfo.getLeftRightStr(times) + plcCmdInfo.getInOutStr(times); - //执行动作 - try { - plcService.action(plcCmdInfo, times, code); - } catch (InterruptedException e) { - e.printStackTrace(); - } - }else { - log.info("other C code :{}",code); - } - } else if (Cmd.D.name().equals(ksecInfo.getType())) { - - //柳州去掉告警 -// String code = dataInfo.getCmdName(); -// if(code.equals(Cmd.D1.name())){ -// log.info("plcId:{},warn start",plcCmdInfo.getPlcId()); -// //根据告警code转动camera -// String warnCode = dataInfo.getWarnCode(); -// if(!StringUtils.isEmpty(warnCode)){ -// String warnCode0 = Cmd.D1.name()+"-"+warnCode.split(",")[0]; -// plcService.warnAction(plcCmdInfo,warnCode0); -// } -// plcService.warnStart(plcCmdInfo.getPlcId(),dataInfo.getWarnCode()); -// }else if(code.equals(Cmd.D2.name())){ -// log.info("plcId:{},warn stop",plcCmdInfo.getPlcId()); -// plcService.warnStop(plcCmdInfo.getPlcId()); -// }else { -// log.info("other D code :{}",code); -// } - } else if (Cmd.E.name().equals(ksecInfo.getType())) { - - //盘点 - //转球机到盘点位 然后拍照 - -// 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); -// Boolean ok = plcService.check(plcCmdInfo,ksecInfo.getData().getCmdName(), dataInfo.getCode(), dataInfo.getTrayCode()); -// if(ok){ -// ksecInfo.getData().setAckStatus(1); -// }else { -// ksecInfo.getData().setAckStatus(0); -// } -// ctx.channel().writeAndFlush(ksecInfo); - //rfid的逻辑 - String code = dataInfo.getCmdName(); - if("E1".equals(code)){ - plcService.RFIDCheck(plcCmdInfo); - }else { - plcService.RFIDStop(plcCmdInfo); - } - - } - //找到该货位的最后一张照片与现在的照片比照 - //plcService.recordStock(plcCmdInfo, dataInfo.getCode(), 0, 0); - } - in.release(); - } - } -} 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..4eb15c8 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java @@ -0,0 +1,71 @@ +package com.zhehekeji.web.service.client; + +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; + +/** + * 客户端解码器 连接用 + */ +@Slf4j +public class Decoder extends DelimiterBasedFrameDecoder { + + private static final Logger tcpLogger = LoggerFactory.getLogger("client_tcp"); + + + public Decoder() { + super(200,true,false, Unpooled.copiedBuffer(";".getBytes())); + } + + @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; + } + String body = in.toString(Charset.forName("UTF-8")); + if(body.startsWith(HBTransmission.getHEADER())) { + //心跳 + HBTransmission hbTransmission = new HBTransmission(body); + //回复客户端心跳 + + ctx.channel().writeAndFlush(hbTransmission.toString()); + tcpLogger.info("client:{} heart", hbTransmission.getSRMNumber()); + in.release(); + } else if(body.startsWith(TMTransmission.getHeader())){ + //盘点与空货位扫描相关的指令 + TMTransmission tmTransmission = new TMTransmission(body); + if(tmTransmission.getType() == 1){ + //空货位扫描 + + }else { + //盘点 + } + 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]); + } + } + return null; + } + +} diff --git a/web/src/main/java/com/zhehekeji/web/service/client/EmptyTrayCheckTransmission.java b/web/src/main/java/com/zhehekeji/web/service/client/EmptyTrayCheckTransmission.java new file mode 100644 index 0000000..9e68c8c --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/EmptyTrayCheckTransmission.java @@ -0,0 +1,12 @@ +package com.zhehekeji.web.service.client; + +import lombok.Data; + +@Data +/** + * 空托盘检测 + */ +public class EmptyTrayCheckTransmission { + + +} 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..a5903a7 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/Encoder.java @@ -0,0 +1,22 @@ +package com.zhehekeji.web.service.client; + +import com.alibaba.fastjson.JSONObject; +import com.zhehekeji.web.service.ksec.KsecInfo; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; + +import java.nio.charset.StandardCharsets; + +/** + * 客户端传输协议 以;结尾 + */ +public class Encoder extends MessageToByteEncoder { + + + @Override + protected void encode(ChannelHandlerContext channelHandlerContext, String data, ByteBuf byteBuf) throws Exception { + data = data + ";"; + 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..717f042 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/HBTransmission.java @@ -0,0 +1,30 @@ +package com.zhehekeji.web.service.client; + +import lombok.Data; + +@Data +/** + * 与客户端的心跳 + */ +public class HBTransmission { + + private static String HEADER = "HB"; + + private String SRMNumber; + + public String toString(){ + return HEADER + "," + SRMNumber; + } + + public static String getHEADER(){ + return HEADER; + } + + public HBTransmission(String body){ + String [] strings = body.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/NettyServer.java b/web/src/main/java/com/zhehekeji/web/service/client/NettyServer.java new file mode 100644 index 0000000..507cf86 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/NettyServer.java @@ -0,0 +1,50 @@ +package com.zhehekeji.web.service.client; + +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; + +public class NettyServer { + + public static 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 Decoder()); + 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/TMTransmission.java b/web/src/main/java/com/zhehekeji/web/service/client/TMTransmission.java index cc2b944..9fd4e81 100644 --- a/web/src/main/java/com/zhehekeji/web/service/client/TMTransmission.java +++ b/web/src/main/java/com/zhehekeji/web/service/client/TMTransmission.java @@ -40,6 +40,14 @@ public class TMTransmission { */ private String checkType; + /** + * 1: 空托盘检测 + * 0: 正常盘点 + */ + private Integer type; + + private String isEmpty; + private static String Split = ","; public String toString(){ @@ -49,4 +57,52 @@ public class TMTransmission { .append(Split).append(count).append(Split).append(count).append(Split).append(checkType); return sb.toString(); } + + /** + * 空托盘检测开始信息 + * @return + */ + public String toEmptyCheckStartString(){ + StringBuffer sb = new StringBuffer(header); + sb.append(Split).append(SRMNumber).append(Split).append("START"); + return sb.toString(); + } + + /** + * 空托盘检测 结束信号 + * @return + */ + public String toEmptyCheckEndString(){ + StringBuffer sb = new StringBuffer(header); + sb.append(Split).append(SRMNumber).append(Split).append("END"); + return sb.toString(); + } + + public static String getHeader(){ + return header; + } + + public TMTransmission(String body){ + String [] strings = body.split(Split); + if(strings != null && strings.length >0 && strings[0].equals(header)){ + if(strings.length == 8){ + type = 0; + SRMNumber = strings[1]; + taskNo = strings[2]; + goodsLocation = strings[3]; + trayNo = strings[4]; + code = strings[5]; + count = Integer.valueOf(strings[6]); + checkType = strings[7]; + + }else if(strings.length == 4){ + type = 1; + SRMNumber = strings[1]; + goodsLocation = strings[2]; + isEmpty = strings[3]; + + } + + } + } }