客户端通讯协议

nanjing-yancao-wuliuzhongxin
yiming 4 years ago
parent 5d988e092d
commit 62bcc185b0

@ -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<String, Set<String>> shelveEmptyMap = new HashMap<>();
public void startEmptyCheck(String SRMNumber){
shelveEmptyMap.put(SRMNumber,new HashSet<>());
}
public Set<String> 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;
// }
}

@ -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<Camera> cameras = cameraMapper.selectByMap(new HashMap<>(0));
cameras.forEach(camera -> {

@ -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];
}
}
}

@ -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<String, Channel> channelMap = new HashMap<>();
public static void connect(String key,Channel channel){
public static void connect(String key, Channel channel){
channelMap.put(key,channel);
}

@ -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();
}
}
}

@ -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;
}
}

@ -0,0 +1,12 @@
package com.zhehekeji.web.service.client;
import lombok.Data;
@Data
/**
*
*/
public class EmptyTrayCheckTransmission {
}

@ -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<String> {
@Override
protected void encode(ChannelHandlerContext channelHandlerContext, String data, ByteBuf byteBuf) throws Exception {
data = data + ";";
byteBuf.writeBytes(data.getBytes(StandardCharsets.UTF_8));
}
}

@ -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];
}
}
}

@ -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<SocketChannel>() {
@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();
}
}

@ -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];
}
}
}
}

Loading…
Cancel
Save