diff --git a/doc/宁福迦南HTTP通信协议文档12.2.doc b/doc/宁福迦南HTTP通信协议文档12.2.doc new file mode 100644 index 0000000..4500064 Binary files /dev/null and b/doc/宁福迦南HTTP通信协议文档12.2.doc differ diff --git a/readme.md b/readme.md index 6eb2356..6dc7673 100644 --- a/readme.md +++ b/readme.md @@ -8,6 +8,10 @@ *** * 罗伯泰克协议编解码在com.leaper.web.service.robotic下面 * 罗伯泰克协议见doc文件夹下两张图片(罗伯泰克plc通讯协议1——2.jpg) +*** +* HTTP通讯协议在com.leaper.web.controller.MonitorController类 + * 目前是宁福多氟多项目上使用,不推荐使用http,因为http协议的时延比tcp要高 + * 文档见doc文件夹下 宁福迦南HTTP通信协议文档12.2.doc *** ## SDK: ### 1.调用sdk的代码在 com.leaper.web.lib下面 diff --git a/web/src/main/java/com/leaper/web/controller/MonitorController.java b/web/src/main/java/com/leaper/web/controller/MonitorController.java new file mode 100644 index 0000000..7883909 --- /dev/null +++ b/web/src/main/java/com/leaper/web/controller/MonitorController.java @@ -0,0 +1,25 @@ +package com.leaper.web.controller; + +import com.leaper.web.service.CommandHandler; +import com.leaper.web.service.ksec.KsecInfo; +import com.zhehekeji.core.pojo.Result; +import io.swagger.annotations.Api; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Api(value = "monitor",tags = "监控接口 HTTP协议") +@RestController +@RequestMapping("/monitor") +@Slf4j +public class MonitorController { + + @PostMapping("/task") + public Result monitorTask(@RequestBody KsecInfo ksecInfo){ + CommandHandler.exec(ksecInfo); + return Result.success(); + } + +} diff --git a/web/src/main/java/com/leaper/web/service/CommandHandler.java b/web/src/main/java/com/leaper/web/service/CommandHandler.java new file mode 100644 index 0000000..dec7ec5 --- /dev/null +++ b/web/src/main/java/com/leaper/web/service/CommandHandler.java @@ -0,0 +1,36 @@ +package com.leaper.web.service; + +import com.leaper.common.util.FileUtil; +import com.leaper.web.service.ksec.KsecDecoder; +import com.leaper.web.service.ksec.KsecInfo; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +@Slf4j +public class CommandHandler { + + private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(7,21,30, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(20000)); + + static { + String lotnum = FileUtil.getText("lastLotnum"); + if(lotnum != null){ + CommandRunnable.setLastLotnum(lotnum); + } + log.info("read lastLotnum:{}",lotnum); + } + + public static void exec(ChannelHandlerContext ctx, ByteBuf in){ + CommandRunnable commandRunnable = new CommandRunnable(in,ctx); + threadPoolExecutor.execute(commandRunnable); + } + + public static void exec(KsecInfo ksecInfo){ + CommandRunnable commandRunnable = new CommandRunnable(ksecInfo); + threadPoolExecutor.execute(commandRunnable); + } +} diff --git a/web/src/main/java/com/leaper/web/service/CommandRunnable.java b/web/src/main/java/com/leaper/web/service/CommandRunnable.java new file mode 100644 index 0000000..e2fff80 --- /dev/null +++ b/web/src/main/java/com/leaper/web/service/CommandRunnable.java @@ -0,0 +1,190 @@ +package com.leaper.web.service; + +import com.alibaba.fastjson.JSONObject; +import com.leaper.common.util.FileUtil; +import com.leaper.common.util.SpringContextUtil; +import com.leaper.web.pojo.Cmd; +import com.leaper.web.service.ksec.KsecDataInfo; +import com.leaper.web.service.ksec.KsecInfo; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +import java.nio.charset.Charset; + +@Slf4j +public class CommandRunnable implements Runnable{ + + private static final Logger tcpLogger = LoggerFactory.getLogger("tcp"); + + public static void setLastLotnum(String lotnum){ + lastLotnum = lotnum; + } + + private static String lastLotnum; + + private PlcService plcService; + + private ByteBuf in; + + private ChannelHandlerContext ctx; + + private KsecInfo ksecInfo; + + private String content; + + /** + * TCP协议的 + * @param body + * @param ctx + */ + public CommandRunnable(ByteBuf body, ChannelHandlerContext ctx){ + this.in = body; + this.ctx = ctx; + this.plcService = SpringContextUtil.getBean(PlcService.class); + content = body.toString(Charset.forName("UTF-8")); + if(content.startsWith("<")){ + content = content.substring(1, content.length()); + ksecInfo = JSONObject.parseObject(content, KsecInfo.class); + } + tcpLogger.info("{}",content); + } + + /** + * HTTP协议的 + * @param ksecInfo + */ + public CommandRunnable(KsecInfo ksecInfo){ + this.ksecInfo = ksecInfo; + this.plcService = SpringContextUtil.getBean(PlcService.class); + tcpLogger.info("{}",JSONObject.toJSONString(ksecInfo)); + } + + @Override + public void run() { + 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){ + + 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); + } + if(ctx != null){ + ctx.channel().writeAndFlush(ksecInfo); + } + } + if(in != null){ + in.release(); + } + } + + +} diff --git a/web/src/main/java/com/leaper/web/service/ksec/KescFilter.java b/web/src/main/java/com/leaper/web/service/ksec/KescFilter.java index 8008921..e8550ff 100644 --- a/web/src/main/java/com/leaper/web/service/ksec/KescFilter.java +++ b/web/src/main/java/com/leaper/web/service/ksec/KescFilter.java @@ -21,13 +21,10 @@ public class KescFilter extends ChannelInitializer { private KsecInfo ksecInfo; - private PlcService plcService; - private KsecNettyClient nettyClient; - public KescFilter(KsecInfo ksecInfo, PlcService plcService, KsecNettyClient nettyClient){ + public KescFilter(KsecInfo ksecInfo, KsecNettyClient nettyClient){ this.ksecInfo = ksecInfo; - this.plcService = plcService; this.nettyClient = nettyClient; } @@ -38,7 +35,7 @@ public class KescFilter extends ChannelInitializer { //4秒发一次心跳 ph.addLast(new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS)); ByteBuf byteBuf = Unpooled.copiedBuffer(">".getBytes()); - ph.addLast(new KsecDecoder(10000,byteBuf,plcService)); + ph.addLast(new KsecDecoder(10000,byteBuf)); ph.addLast(new KescEncoder()); ph.addLast(new KescNettyHandler(ksecInfo,nettyClient)); } diff --git a/web/src/main/java/com/leaper/web/service/ksec/KsecDecoder.java b/web/src/main/java/com/leaper/web/service/ksec/KsecDecoder.java index 74dc65f..26c3da8 100644 --- a/web/src/main/java/com/leaper/web/service/ksec/KsecDecoder.java +++ b/web/src/main/java/com/leaper/web/service/ksec/KsecDecoder.java @@ -2,6 +2,7 @@ package com.leaper.web.service.ksec; import com.alibaba.fastjson.JSONObject; import com.leaper.web.pojo.Cmd; +import com.leaper.web.service.CommandHandler; import com.leaper.web.service.PlcService; import com.leaper.common.util.FileUtil; import com.leaper.web.service.GoodsActionTimes; @@ -25,21 +26,8 @@ import java.util.concurrent.TimeUnit; @Slf4j public class KsecDecoder extends DelimiterBasedFrameDecoder { - private static final Logger tcpLogger = LoggerFactory.getLogger("tcp"); - - public static void setLastLotnum(String lotnum){ - lastLotnum = lotnum; - } - - private static String lastLotnum; - - private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(7,21,30, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(20000)); - - private PlcService plcService; - - public KsecDecoder(int maxFrameLength, ByteBuf delimiter, PlcService plcService) { + public KsecDecoder(int maxFrameLength, ByteBuf delimiter) { super(maxFrameLength, delimiter); - this.plcService = plcService; } @Override @@ -49,153 +37,7 @@ public class KsecDecoder extends DelimiterBasedFrameDecoder { log.debug("no data"); return null; } - KescRunnable kescRunnable = new KescRunnable(in,ctx,plcService); - threadPoolExecutor.execute(kescRunnable); + CommandHandler.exec(ctx, in); return null; } - - public static class KescRunnable implements Runnable{ - - private ByteBuf in; - - private ChannelHandlerContext ctx; - - private PlcService plcService; - - public KescRunnable(ByteBuf body,ChannelHandlerContext ctx,PlcService plcService){ - this.in = body; - this.ctx = ctx; - this.plcService = plcService; - } - - @Override - public void run() { - String body = in.toString(Charset.forName("UTF-8")); - tcpLogger.info(body); - if (body.startsWith("<")){ - // 去掉首尾标识符 - 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){ - - 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); - - - } - //找到该货位的最后一张照片与现在的照片比照 - //plcService.recordStock(plcCmdInfo, dataInfo.getCode(), 0, 0); - } - in.release(); - } - } } diff --git a/web/src/main/java/com/leaper/web/service/ksec/KsecNettyClient.java b/web/src/main/java/com/leaper/web/service/ksec/KsecNettyClient.java index b635757..57cb5a2 100644 --- a/web/src/main/java/com/leaper/web/service/ksec/KsecNettyClient.java +++ b/web/src/main/java/com/leaper/web/service/ksec/KsecNettyClient.java @@ -33,10 +33,7 @@ public class KsecNettyClient { private static Channel channel; public void createClient(ConfigProperties.KSEC ksec) throws InterruptedException { - String lotnum = FileUtil.getText("lastLotnum"); - if(lotnum != null){ - KsecDecoder.setLastLotnum(lotnum); - } + if (StringUtils.isEmpty(ksec.getIp()) || ksec.getPort() == null) { return; } @@ -44,7 +41,7 @@ public class KsecNettyClient { client.group(group); client.channel(NioSocketChannel.class); KsecInfo heart = KsecInfo.heart(); - client.handler(new KescFilter(heart, plcService,this)); + client.handler(new KescFilter(heart,this)); // 连接服务端 channel = client.connect(ksec.getIp(), ksec.getPort()).sync().channel(); } diff --git a/web/src/main/resources/application-dev.yml b/web/src/main/resources/application-dev.yml index b9a1135..172a097 100644 --- a/web/src/main/resources/application-dev.yml +++ b/web/src/main/resources/application-dev.yml @@ -17,18 +17,16 @@ spring: url: jdbc:mysql://115.236.65.98:12004/lia_duoji_test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8 username: root validationQuery: SELECT 1 FROM DUAL -# --------本服务端口号 -server: - port: 8099 + #-------------- # ----------- # ----默认摄像头的连接信息 cameraConfig: # ------------球機選擇--- 0:利珀 1:海康 - cameraType: 0 + cameraType: 1 cameraPassword: a1234567 cameraUser: admin - cameraPort: 37777 + cameraPort: 8000 videoServer: 127.0.0.1:8083 #相机抓图延迟 毫秒,这个延迟是等待球机球机转动到位,然后拍照的 delayCaptureTime: 3500 diff --git a/web/src/main/resources/application-prod.yml b/web/src/main/resources/application-prod.yml index 1b99eaa..3cbfe3e 100644 --- a/web/src/main/resources/application-prod.yml +++ b/web/src/main/resources/application-prod.yml @@ -17,9 +17,6 @@ spring: url: jdbc:mysql://127.0.0.1:3306/lia_duoji?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8 username: root validationQuery: SELECT 1 FROM DUAL -# --------本服务端口号 -server: - port: 8099 #-------------- # ----------- # ----默认摄像头的连接信息 diff --git a/web/src/main/resources/application-test.yml b/web/src/main/resources/application-test.yml index d4ec534..cf2e001 100644 --- a/web/src/main/resources/application-test.yml +++ b/web/src/main/resources/application-test.yml @@ -17,9 +17,6 @@ spring: url: jdbc:mysql://127.0.0.1:3306/lia_duoji?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8 username: root validationQuery: SELECT 1 FROM DUAL -# --------本服务端口号 -server: - port: 8099 #-------------- # ----------- # ----默认摄像头的连接信息 diff --git a/web/src/main/resources/application.yml b/web/src/main/resources/application.yml index 35ee836..58bad61 100644 --- a/web/src/main/resources/application.yml +++ b/web/src/main/resources/application.yml @@ -1,3 +1,6 @@ +server: + # --------本服务端口号 + port: 8099 spring: profiles: active: @profileActive@