普天协议对接

nanjing-yancao-wuliuzhongxin
yiming 4 years ago
parent 4f0fc140a7
commit 699ad94a9f

@ -0,0 +1,55 @@
package com.zhehekeji.web.controller;
import com.github.pagehelper.PageInfo;
import com.zhehekeji.core.pojo.Result;
import com.zhehekeji.web.entity.CheckLog;
import com.zhehekeji.web.pojo.stock.CheckLogSearch;
import com.zhehekeji.web.service.EmptyCheckService;
import com.zhehekeji.web.service.client.ClientChanel;
import com.zhehekeji.web.service.client.ECTransmission;
import com.zhehekeji.web.service.client.TMTransmission;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@Api(tags = "客户端通讯测试")
@RequestMapping("/clientTest")
@RestController
public class ClientTestController {
@Resource
private EmptyCheckService emptyCheckService;
@ApiOperation("空货位盘点【发起】")
@GetMapping("/emptyCheck/start")
public Result<Boolean> startEmptyCheck(@ApiParam("巷道标识") String SRMNumber,@ApiParam("盘点批次ID") String taskId, @ApiParam("检测第几行") Integer row){
ClientChanel.write(ECTransmission.toEmptyCheckStartString(SRMNumber),SRMNumber);
return Result.success();
}
@ApiOperation("空货位盘点 【结束】")
@GetMapping("/emptyCheck/stop")
public Result<Boolean> stopEmptyCheck(@ApiParam("巷道标识") String SRMNumber,@ApiParam("盘点批次ID") String taskId, @ApiParam("检测第几行") Integer row){
emptyCheckService.emptyCheckStart(SRMNumber,taskId,row);
ClientChanel.write(ECTransmission.toEmptyCheckEndString(SRMNumber),SRMNumber);
return Result.success();
}
@ApiOperation("盘点具体货位 第一步 【开始】")
@GetMapping("/stockCheck/start")
public Result<Boolean> startStockCheck(@ApiParam("巷道标识") String SRMNumber,@ApiParam("盘点批次ID") String taskId,
@ApiParam("货位号,如L0100010002 ,R/L表示左右,01是浅货位02深,0001是X,0002是Y") String goodsLocation,
@ApiParam("是否是虚拟检测 Y:是 N:不是")String V){
TMTransmission tmTransmission = new TMTransmission();
ClientChanel.write(ECTransmission.toEmptyCheckEndString(SRMNumber),SRMNumber);
return Result.success();
}
}

@ -21,6 +21,7 @@ import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@Slf4j
@ -106,26 +107,59 @@ public class EmptyCheckService {
}
/**
*
* @param ecTransmission
*
* @param
*/
public void emptyCheckStart(ECTransmission ecTransmission){
Street street = streetService.getStreetByPlcId(ecTransmission.getSRMNumber());
public void emptyCheckStart(String SRMNUmber,String taskId,Integer row){
log.info("空托盘检测 按行开始SRMNUmber:{},taskNo:{},row:{}",SRMNUmber,taskId,row);
Street street = streetService.getStreetByPlcId(SRMNUmber);
if(street == null){
log.error(" no SRMNumer:{}",ecTransmission.getSRMNumber());
log.error(" no SRMNumer:{}",SRMNUmber);
return;
}
Map<String,Object> map = new HashMap<>();
map.put("street_id",street.getId());
// map.put("direction",leftRight);
// map.put("side",side);
map.put("row",row);
stockMapper.deleteByMap(map);
//新增空的盘点统计
List<CheckStreetSummary> checkStreetSummaries = checkStreetSummaryMapper.selectList(new QueryWrapper<CheckStreetSummary>().eq("street_id",street.getId()).eq("task_id",taskId));
if(checkStreetSummaries.size() == 0){
log.info("新增盘点统计SRMNUmber:{},taskNo:{},row:{}",SRMNUmber,taskId,row);
CheckStreetSummary checkStreetSummary = new CheckStreetSummary();
checkStreetSummary.setTaskId(ecTransmission.getTaskId());
checkStreetSummary.setTaskId(taskId);
checkStreetSummary.setStartTime(LocalDateTime.now());
checkStreetSummary.setStreetId(street.getId());
checkStreetSummaryMapper.insert(checkStreetSummary);
}
}
public String getEmptyStatus(String SRMNUmber,String taskId,Integer side,Integer leftRight,Integer row){
Street street = streetService.getStreetByPlcId(SRMNUmber);
if(street == null){
log.error(" no SRMNumer:{}",SRMNUmber);
return null;
}
List<Stock> stockList = stockMapper.selectList(new QueryWrapper<Stock>().eq("`row`",row).eq("street_id",street.getId()).eq("direction",leftRight).eq("side",side));
Map<Integer,Stock> stockMap = new HashMap<>(stockList.size()*2);
stockList.forEach(stock -> {
stockMap.put(stock.getColumn(),stock);
});
int columns = side == 1?street.getLeftColumn():street.getRightColumn();
StringBuffer sb = new StringBuffer();
for(int i = 1;i<=columns;i++){
if(stockMap.get(i) != null && stockMap.get(i).getEmptyStatus() == 1){
sb.append(1);
}else {
sb.append(0);
}
}
return sb.toString();
}
public void emptyCheckLog(ECTransmission ecTransmission){
Street street = streetService.getStreetByPlcId(ecTransmission.getSRMNumber());
if(street == null){
@ -138,6 +172,8 @@ public class EmptyCheckService {
stock.setDirection(ecTransmission.getDirection());
if(ecTransmission.getIsEmpty().equals("N")){
stock.setEmptyStatus(3);
}else {
stock.setEmptyStatus(1);
}
stock.setRow(ecTransmission.getRow());
stock.setColumn(ecTransmission.getColumn());

@ -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.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
@ -19,6 +20,8 @@ public class Decoder extends DelimiterBasedFrameDecoder {
private static final Logger tcpLogger = LoggerFactory.getLogger("tcp");
private EmptyCheckService emptyCheckService;
private PlcService plcService;
public Decoder(PlcService plcService) {
super(200,true,false, Unpooled.copiedBuffer(";".getBytes()));
@ -33,6 +36,7 @@ public class Decoder extends DelimiterBasedFrameDecoder {
return null;
}
String body = in.toString(Charset.forName("UTF-8"));
tcpLogger.info("client rece:{}",body);
if(body.startsWith(HBTransmission.getHEADER())) {
//心跳
HBTransmission hbTransmission = new HBTransmission(body);
@ -56,6 +60,8 @@ public class Decoder extends DelimiterBasedFrameDecoder {
}else if(body.startsWith(ECTransmission.getHEADER())){
//空货位盘点
ECTransmission ecTransmission = new ECTransmission(body);
//保存空货位信息
emptyCheckService.emptyCheckLog(ecTransmission);
}else if(body.startsWith("DC")){
//客户端断开连接

@ -67,7 +67,7 @@ public class ECTransmission {
*
* @return
*/
public String toEmptyCheckStartString(){
public static String toEmptyCheckStartString(String SRMNumber){
StringBuffer sb = new StringBuffer(HEADER);
sb.append(Split).append(SRMNumber).append(Split).append("START");
return sb.toString();
@ -77,7 +77,7 @@ public class ECTransmission {
*
* @return
*/
public String toEmptyCheckEndString(){
public static String toEmptyCheckEndString(String SRMNumber){
StringBuffer sb = new StringBuffer(HEADER);
sb.append(Split).append(SRMNumber).append(Split).append("END");
return sb.toString();

@ -36,7 +36,6 @@ public class TMTransmission {
private Integer count;
private String visualTest;
private String isDisConnect;
@ -61,8 +60,6 @@ public class TMTransmission {
return sb.toString();
}
public static String getHeader(){
return header;
}

@ -0,0 +1,70 @@
package com.zhehekeji.web.service.putian;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class PTData {
protected static String SPLIT = "#";
private static String END_STRING = "\n";
public static String HEART_TYPE = "HB";
/**
* 1.EmptyCheck01 EC01
* 2.EmptyCheck02: EC02
* 3.(EmptyCheck03) EC03
* 4.StockCheck01 SC01
* 5.StockCheck02 SC02
* 6. StockCheck03: SC03
* 7.StockCheck04: SC04
* 8. IntoStock01 : IS01
* 9. IntoStock02 IS02
* 10. IntoStock03 IS03
* 11. IntoStock04 IS04
* 12.HeartBeat : HB
*/
public static String EMPTY_CHECK_01 = "EC01";
public static String EMPTY_CHECK_02 = "EC02";
public static String EMPTY_CHECK_03 = "EC03";
public static String STOCK_CHECK_01 = "SC01";
public static String STOCK_CHECK_02 = "SC02";
public static String STOCK_CHECK_03 = "SC03";
public static String STOCK_CHECK_04 = "SC04";
public static String Into_Stock_01 = "IS01";
public static String Into_Stock_02 = "IS02";
public static String Into_Stock_03 = "IS03";
public static String Into_Stock_04 = "IS04";
private String FlowControl;
private String Type;
private String Content;
public String toString(){
return FlowControl + SPLIT + Type + SPLIT + Content + END_STRING;
}
public PTData(String data){
String[] strings = data.split(SPLIT);
FlowControl = strings[0];
Type = strings[1];
Content = strings[2];
}
public static PTData HeartBeat(){
PTData ptData = new PTData();
ptData.setFlowControl(".");
ptData.setType(HEART_TYPE);
ptData.setContent("HeartBeat");
return ptData;
}
}

@ -0,0 +1,78 @@
package com.zhehekeji.web.service.putian;
import com.zhehekeji.web.service.EmptyCheckService;
import com.zhehekeji.web.service.client.ClientChanel;
import com.zhehekeji.web.service.client.ECTransmission;
import com.zhehekeji.web.service.ksec.KsecDecoder;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LineBasedFrameDecoder;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.Charset;
@Slf4j
public class PTDecoder extends LineBasedFrameDecoder {
private static final Logger tcpLogger = LoggerFactory.getLogger("tcp");
private EmptyCheckService emptyCheckService;
/**
* failFast maxLength 使 failFast TooLongFrameException
* Netty failFast=true maxLength TooLongFrameException
* failFast=false TooLongFrameException
* @param maxLength
* @param stripDelimiter true
* @param failFast
*/
public PTDecoder(int maxLength, boolean stripDelimiter, boolean failFast) {
super(maxLength, stripDelimiter, failFast);
}
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
in = (ByteBuf) super.decode(ctx, in);
if(in != null){
String body = in.toString(Charset.forName("UTF-8"));
tcpLogger.info(body);
PTData ptData = new PTData(body);
if(ptData.getType().equals(PTData.HEART_TYPE)){
//心跳 什么都不处理,因为netty长链接断开会感知
}else if(ptData.getType().equals(PTData.EMPTY_CHECK_01)){
log.info("空货位检测开始");
PTEmptyCheckContent checkContent = PTEmptyCheckContent.EmptyCheck(body);
emptyCheckService.emptyCheckStart(checkContent.getSRMNUmber(), checkContent.getTaskNo(), checkContent.getRow());
String startEmptyCheckStr = ECTransmission.toEmptyCheckStartString(checkContent.getSRMNUmber());
//通知客户端开始检测
ClientChanel.write(startEmptyCheckStr,checkContent.getSRMNUmber());
}else if(ptData.getType().equals(PTData.EMPTY_CHECK_02)){
log.info("空货位检测结束");
PTEmptyCheckContent checkContent = PTEmptyCheckContent.EmptyCheck(body);
String endEmptyCheckStr = ECTransmission.toEmptyCheckEndString(checkContent.getSRMNUmber());
//通知客户端结束检测
ClientChanel.write(endEmptyCheckStr,checkContent.getSRMNUmber());
//等待3s把空货位盘点的结果发给普天
//todo
emptyCheckService.getEmptyStatus(checkContent.getSRMNUmber(),checkContent.getTaskNo(),1,1,checkContent.getRow());
}else if(ptData.getType().equals(PTData.STOCK_CHECK_01)){
log.info("盘点具体货位");
}else if(ptData.getType().equals(PTData.STOCK_CHECK_02)){
log.info("盘点具体货位 ,货物已取到载货台");
}else {
log.info("未知的盘点指令:{}",ptData.getType());
}
}
return null;
}
}

@ -0,0 +1,52 @@
package com.zhehekeji.web.service.putian;
import lombok.Data;
/**
* EC01
* ,,,,,START
* SRM001,202209081122,1,1,5,START
* (EC02)
* ,,,,,END
* SRM001,202209081122,1,1,5,END
* (EC03)
* ,,,,,,1:,0:
* {}{} L01R02
* SRM001,202209081122,1,1,5,L01,10111
* @return
*/
@Data
public class PTEmptyCheckContent {
private String SRMNUmber;
private String goodsLocation;
private String taskNo;
private Integer num;
private Integer row;
private Integer startColumn;
private Integer endColumn;
/**
* Start OR END
*/
private String type;
public static PTEmptyCheckContent EmptyCheck(String data){
PTEmptyCheckContent ptContent = new PTEmptyCheckContent();
String [] strings = data.split(",");
ptContent.setSRMNUmber(strings[0]);
ptContent.setTaskNo(strings[1]);
ptContent.setRow(Integer.valueOf(strings[2]));
ptContent.setStartColumn(Integer.valueOf(strings[3]));
ptContent.setEndColumn(Integer.valueOf(strings[4]));
ptContent.setType(strings[5]);
return ptContent;
}
}

@ -0,0 +1,41 @@
package com.zhehekeji.web.service.putian;
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.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import java.util.concurrent.TimeUnit;
/**
*
*
* @author Administrator
*
*/
public class PTFilter extends ChannelInitializer<SocketChannel> {
private PlcService plcService;
private PuTianNettyClient nettyClient;
public PTFilter(PlcService plcService, PuTianNettyClient nettyClient){
this.plcService = plcService;
this.nettyClient = nettyClient;
}
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline ph = ch.pipeline();
//30秒发一次心跳
ph.addLast(new IdleStateHandler(0, 30, 0, TimeUnit.SECONDS));
ByteBuf byteBuf = Unpooled.copiedBuffer(">".getBytes());
ph.addLast(new PTDecoder(1000,false,true));
ph.addLast(new PtEncoder());
ph.addLast(new PTNettyHandler(nettyClient));
}
}

@ -0,0 +1,65 @@
package com.zhehekeji.web.service.putian;
import com.zhehekeji.web.service.StreetConn;
import com.zhehekeji.web.service.ksec.KsecInfo;
import com.zhehekeji.web.service.ksec.KsecNettyClient;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
/**
* PLC
*
* @author Administrator
*
*/
@Slf4j
public class PTNettyHandler extends ChannelInboundHandlerAdapter {
/** 客户端请求的心跳命令 */
private PTData heart;
private PuTianNettyClient nettyClient;
public PTNettyHandler(PuTianNettyClient nettyClient){
this.nettyClient = nettyClient;
// this.heart = new PTData();
// this.heart.setContent("");
}
/**
*
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
log.info("upPc connected ");
StreetConn.conn(1);
ctx.fireChannelActive();
}
/**
*
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
log.info("upPc closed");
StreetConn.disConn(1);
log.info(" streetId reconnect......");
nettyClient.reconnect(1);
}
/**
* 4;
*
*/
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception {
if (obj instanceof IdleStateEvent) {
log.debug("upPc send heart");
ctx.channel().writeAndFlush(heart);
}
}
}

@ -0,0 +1,19 @@
package com.zhehekeji.web.service.putian;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import java.nio.charset.StandardCharsets;
/**
* TCP
*/
public class PtEncoder extends MessageToByteEncoder<PTData> {
@Override
protected void encode(ChannelHandlerContext channelHandlerContext, PTData data, ByteBuf byteBuf) throws Exception {
String body = data.toString();
byteBuf.writeBytes(body.getBytes(StandardCharsets.UTF_8));
}
}

@ -0,0 +1,95 @@
package com.zhehekeji.web.service.putian;
import com.zhehekeji.web.config.ConfigProperties;
import com.zhehekeji.web.service.PlcService;
import com.zhehekeji.web.service.client.Decoder;
import com.zhehekeji.web.service.client.Encoder;
import com.zhehekeji.web.service.ksec.KescFilter;
import com.zhehekeji.web.service.ksec.KsecInfo;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
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.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
@Slf4j
@Component
public class PuTianNettyClient {
private static EventLoopGroup group = new NioEventLoopGroup();
@Resource
private PlcService plcService;
@Resource
private ConfigProperties configProperties;
/**
*
*/
private static int RECONNECT_NUM = 10;
private static Channel channel;
public void createClient(ConfigProperties.KSEC ksec) throws InterruptedException {
if (StringUtils.isEmpty(ksec.getIp()) || ksec.getPort() == null) {
return;
}
Bootstrap client = new Bootstrap();
client.group(group);
client.channel(NioSocketChannel.class);
client.handler(new PTNettyHandler(this));
// 连接服务端
channel = client.connect(ksec.getIp(), ksec.getPort()).sync().channel();
}
/**
* 线 RECONNECT_NUM
*
* @param upId
*/
public void reconnect(Integer upId) {
Boolean isConnected = false;
int num = 0;
ConfigProperties.KSEC ksec = configProperties.getKsec();
if (ksec == null) {
log.error("reconnect ,upPc is null ,id:{}", upId);
return;
}
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (num < RECONNECT_NUM && !isConnected) {
try {
createClient(ksec);
} catch (Exception e) {
//没连上 继续
log.error("reconnect error num:{}", num);
num++;
continue;
}
isConnected = true;
}
if (isConnected) {
log.info("plc reconnect success");
} else {
log.error("plc reconnect error .upPcId:{},reconnect num:{},ip:{},port:{}", upId, num, ksec.getIp(), ksec.getPort());
}
}
public static void write(KsecInfo ksecInfo){
if(channel != null){
channel.writeAndFlush(ksecInfo);
}else {
log.error(" no connected upPc");
}
}
}
Loading…
Cancel
Save