| | |
| | | import android.os.Bundle; |
| | | import android.os.Vibrator; |
| | | import android.util.Log; |
| | | import android.view.KeyEvent; |
| | | import android.view.MotionEvent; |
| | | import android.view.View; |
| | | import android.widget.Button; |
| | | |
| | |
| | | private Button vibrateButton; |
| | | private Socket socket; |
| | | SocketManager socketManager; |
| | | |
| | | String clientId; |
| | | NettyServerHandler nettyServerHandler; |
| | | @Override |
| | | protected void onCreate(Bundle savedInstanceState) { |
| | | super.onCreate(savedInstanceState); |
| | | setContentView(R.layout.activity_main); |
| | | |
| | | // 作为客户端连接 |
| | | //SocketManager.getInstance().setHostAndPort("192.168.4.188", 802); |
| | | //SocketManager.getInstance().connect(); |
| | | |
| | | //SocketManager.getInstance().setPort(8080); |
| | | //SocketManager.getInstance().startServer(); |
| | | |
| | | // 设置端口号并启动服务端 |
| | | //SocketManager.getInstance().setPort(8080); |
| | | //socketManager = new SocketManager(); |
| | | //socketManager.startServer(8080); |
| | | |
| | | // 启动服务端 |
| | | //new Thread(() -> { |
| | | // SocketManager.getInstance().startServer(); |
| | | //}).start(); |
| | | |
| | | vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); |
| | | vibrateButton = findViewById(R.id.btn_stop); |
| | | |
| | | Intent intent = getIntent(); |
| | | String clientId = intent.getStringExtra("message"); |
| | | //String clientId = intent.getStringExtra("message"); |
| | | clientId = intent.getStringExtra("message"); |
| | | Log.i("message1",clientId); |
| | | // 初始化单轴使能 |
| | | byte[] message2 = new byte[]{0x01, 0x02, 0x03, 0x06}; // 示例消息 |
| | | nettyServerHandler.sendMessageToClient(clientId, message2); // 发送消息到客户端 |
| | | |
| | | vibrateButton.setOnClickListener(new View.OnClickListener() { |
| | | @Override |
| | | public void onClick(View v) { |
| | | if (vibrator != null && vibrator.hasVibrator()) { |
| | | //vibrator.vibrate(500); |
| | | } |
| | | |
| | | //String clientId = "/192.168.4.188:63160"; |
| | | byte[] message1 = new byte[]{0x01, 0x02, 0x03, 0x04}; // 示例消息 |
| | | Log.i("message2",clientId); |
| | | Log.i("message3", Arrays.toString(message1)); |
| | | |
| | | nettyServerHandler.sendMessageToClient(clientId, message1); // 发送消息到客户端 |
| | | } |
| | | }); |
| | | //vibrateButton.setOnClickListener(new View.OnClickListener() { |
| | | // @Override |
| | | // public void onClick(View v) { |
| | | // if (vibrator != null && vibrator.hasVibrator()) { |
| | | // //vibrator.vibrate(500); |
| | | // } |
| | | // |
| | | // //String clientId = "/192.168.4.188:63160"; |
| | | // byte[] message1 = new byte[]{0x01, 0x02, 0x03, 0x04}; // 示例消息 |
| | | // Log.i("message2",clientId); |
| | | // Log.i("message3", Arrays.toString(message1)); |
| | | // |
| | | // nettyServerHandler.sendMessageToClient(clientId, message1); // 发送消息到客户端 |
| | | // } |
| | | //}); |
| | | vibrateButton.setOnTouchListener(new CarTouchButton()); |
| | | |
| | | } |
| | | |
| | | private class CarTouchButton implements View.OnTouchListener { |
| | | |
| | | @Override |
| | | public boolean onTouch(View view, MotionEvent motionEvent) { |
| | | if (motionEvent.getAction() == KeyEvent.ACTION_DOWN) { |
| | | byte[] message2 = new byte[]{0x01, 0x02, 0x03, 0x06}; // 示例消息 |
| | | nettyServerHandler.sendMessageToClient(clientId, message2); // 发送消息到客户端 |
| | | } else if (motionEvent.getAction() == KeyEvent.ACTION_UP) { |
| | | byte[] message2 = new byte[]{0x01, 0x02, 0x03, 0x07}; // 示例消息 |
| | | nettyServerHandler.sendMessageToClient(clientId, message2); // 发送消息到客户端 |
| | | } |
| | | return false; |
| | | } |
| | | } |
| | | @Override |
| | | protected void onDestroy() { |
| | | super.onDestroy(); |
| | |
| | | } |
| | | }); |
| | | socketManager = new SocketManager(); |
| | | socketManager.startServer(8022); |
| | | socketManager.startServer(8024); |
| | | } |
| | | |
| | | @Subscribe(threadMode = ThreadMode.MAIN) |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | |
| | | import java.io.Serializable; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 路径数据包 |
| | | * Created by vincent on 2023/3/16 |
| | | */ |
| | | public class AGV_01_DOWN implements IMessageBody, Serializable { |
| | | |
| | | private static final long serialVersionUID = -2786382674008041014L; |
| | | |
| | | @Override |
| | | public byte[] writeToBytes() { |
| | | String serialNo = Utils.zeroFill(this.serialNo, 16); |
| | | byte[] serialNoBytes = Utils.reverse(serialNo.getBytes()); |
| | | //byte pathLen = (byte) actionItems.size(); |
| | | |
| | | byte[] pathBytes = new byte[0]; |
| | | //for (AgvActionItem<? extends IActionBody> item : actionItems) { |
| | | // //byte[] bytes = RadixTools.intToBytes(Integer.parseInt(item.getQrCode())); |
| | | // //byte[] qrCodeBytes = Utils.reverse(bytes); |
| | | // //byte actionCodeByte = (byte) item.getActionCmdType().actionCode; |
| | | // //byte valByte = (byte) item.getVal(); |
| | | // //byte[] actionBodyBytes = item.getActionBody().writeToBytes(); |
| | | // //byte[] merge = Utils.merge(qrCodeBytes, actionCodeByte, valByte, actionBodyBytes); |
| | | // pathBytes = Utils.merge(pathBytes, merge); |
| | | //} |
| | | |
| | | return Utils.merge(serialNoBytes, pathLen, pathBytes); |
| | | } |
| | | |
| | | @Override |
| | | public void readFromBytes(byte[] messageBodyBytes) { |
| | | |
| | | } |
| | | |
| | | // 流水号 - 16 |
| | | private String serialNo; |
| | | |
| | | // 路径长度 |
| | | private int pathLen; |
| | | |
| | | // 路径列表 |
| | | //private List<AgvActionItem<? extends IActionBody>> actionItems = new ArrayList<>(); |
| | | |
| | | } |
| | |
| | | package com.zy.acs.common.domain.protocol; |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | import com.zy.acs.common.utils.Utils; |
| | | import lombok.Data; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | |
| | | * 动作命令包 |
| | | * Created by vincent on 2023/3/21 |
| | | */ |
| | | @Data |
| | | public class AGV_02_DOWN implements IMessageBody, Serializable { |
| | | |
| | | private static final long serialVersionUID = 1664188062202647371L; |
| | |
| | | public byte[] writeToBytes() { |
| | | String serialNo = Utils.zeroFill(this.serialNo, 16); |
| | | byte[] serialNoBytes = Utils.reverse(serialNo.getBytes()); |
| | | byte cmdCodeByte = (byte) this.getCmdCode(); |
| | | byte valByte = (byte) this.getVal(); |
| | | //byte cmdCodeByte = (byte) this.getCmdCode(); |
| | | byte cmdCodeByte = (byte) 1; |
| | | //byte valByte = (byte) this.getVal(); |
| | | byte valByte = (byte) 1; |
| | | |
| | | byte[] cmdBodyBytes = commandBody.writeToBytes(); |
| | | |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * 心跳 |
| | | * Created by vincent on 2023/3/16 |
| | | */ |
| | | public class AGV_03_DOWN implements IMessageBody, Serializable { |
| | | |
| | | private static final long serialVersionUID = 6922520599887812372L; |
| | | |
| | | @Override |
| | | public byte[] writeToBytes() { |
| | | return new byte[0]; |
| | | } |
| | | |
| | | @Override |
| | | public void readFromBytes(byte[] messageBodyBytes) { |
| | | |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * 激活包 |
| | | * Created by vincent on 2023/3/16 |
| | | */ |
| | | public class AGV_80_DOWN implements IMessageBody, Serializable { |
| | | |
| | | private static final long serialVersionUID = -8289774377582991418L; |
| | | |
| | | @Override |
| | | public byte[] writeToBytes() { |
| | | return new byte[0]; |
| | | } |
| | | |
| | | @Override |
| | | public void readFromBytes(byte[] messageBodyBytes) { |
| | | |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * 应答正常包 |
| | | * Created by vincent on 2023/3/16 |
| | | */ |
| | | public class AGV_A1_DOWN implements IMessageBody, Serializable { |
| | | |
| | | private static final long serialVersionUID = -1744072958515341165L; |
| | | |
| | | @Override |
| | | public byte[] writeToBytes() { |
| | | return Utils.merge(ackSign, Utils.reverse(temp)); |
| | | } |
| | | |
| | | @Override |
| | | public void readFromBytes(byte[] messageBodyBytes) { |
| | | |
| | | } |
| | | |
| | | private byte ackSign = 0x11; |
| | | |
| | | private byte[] temp = new byte[4]; |
| | | |
| | | } |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * Created by vincent on 2023/3/15 |
| | | */ |
| | | public class AGV_F0_DOWN implements IMessageBody, Serializable { |
| | | |
| | | private static final long serialVersionUID = 5769100530170067014L; |
| | | |
| | | @Override |
| | | public byte[] writeToBytes() { |
| | | Utils.reverse(sysMark); |
| | | Utils.reverse(sysVersion); |
| | | Utils.reverse(temp); |
| | | return Utils.merge(sysMark, sysVersion, temp); |
| | | } |
| | | |
| | | @Override |
| | | public void readFromBytes(byte[] bytes) { |
| | | } |
| | | |
| | | private byte[] sysMark = new byte[] {0x00, 0x01}; |
| | | |
| | | private byte[] sysVersion = new byte[] {0x01, 0x01}; |
| | | |
| | | private byte[] temp = new byte[4]; |
| | | |
| | | } |
| | | |
| | |
| | | package com.zy.acs.gateway.domain; |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | import com.core.common.Cools; |
| | | import com.zy.acs.gateway.constant.AgvConstant; |
| | | import com.zy.acs.gateway.constant.PacErrorType; |
| | | import io.netty.buffer.ByteBuf; |
| | | import io.netty.buffer.ByteBufUtil; |
| | | |
| | |
| | | * AGV报文模型 |
| | | * Created by vincent on 2023/3/10 |
| | | */ |
| | | public class AgvPackage implements PackageSupport { |
| | | public class AgvPackage { |
| | | |
| | | /** |
| | | * 源数据包缓冲区(引用) |
| | |
| | | return agvPackage; |
| | | } |
| | | |
| | | public String toLogString() { |
| | | StringBuilder pacSb = new StringBuilder(); |
| | | pacSb.append("AGV(").append(getHeader().getUniqueNo()).append(")") |
| | | .append("上传") |
| | | .append("[").append(getHeader().getProtocolType().getDes()).append("]消息.") |
| | | .append("原始消息[").append(getSourceHexStr()).append("]"); |
| | | return pacSb.toString(); |
| | | } |
| | | //public String toLogString() { |
| | | // StringBuilder pacSb = new StringBuilder(); |
| | | // pacSb.append("AGV(").append(getHeader().getUniqueNo()).append(")") |
| | | // .append("上传") |
| | | // .append("[").append(getHeader().getProtocolType().getDes()).append("]消息.") |
| | | // .append("原始消息[").append(getSourceHexStr()).append("]"); |
| | | // return pacSb.toString(); |
| | | //} |
| | | |
| | | public ByteBuf getSourceBuff() { |
| | | // 因为处理buffer时,总是希望拿到一个重置了readerIndex的buf |
| | |
| | | return this; |
| | | } |
| | | |
| | | public ByteBuf convert(ByteBuf byteBuf){ |
| | | byteBuf.writeByte(this.getHeader().getStartSymbol()) |
| | | .writeShort(this.getHeader().getContentLength()) |
| | | .writeByte(this.getHeader().getProtocolType().getCode()) |
| | | .writeBytes(this.getHeader().getUniqueNo().getBytes(AgvConstant.CHARSET_GBK)) |
| | | .writeByte(this.getHeader().getEncryptType().getCode()) |
| | | .writeBytes(this.getBody().getContent()) |
| | | .writeByte(this.getValidCode()); |
| | | // 计算并设置校验码 |
| | | // this.setValidCode(ValidUtil.caculateValidByteFromBuff(byteBuf)); |
| | | byteBuf.resetReaderIndex(); |
| | | byteBuf.writerIndex(byteBuf.readableBytes() - 1).writeByte(this.getValidCode()); |
| | | return byteBuf; |
| | | } |
| | | // public ByteBuf convert(ByteBuf byteBuf){ |
| | | // byteBuf.writeByte(this.getHeader().getStartSymbol()) |
| | | // .writeShort(this.getHeader().getContentLength()) |
| | | // .writeByte(this.getHeader().getProtocolType().getCode()) |
| | | // .writeBytes(this.getHeader().getUniqueNo().getBytes(AgvConstant.CHARSET_GBK)) |
| | | // .writeByte(this.getHeader().getEncryptType().getCode()) |
| | | // .writeBytes(this.getBody().getContent()) |
| | | // .writeByte(this.getValidCode()); |
| | | // // 计算并设置校验码 |
| | | //// this.setValidCode(ValidUtil.caculateValidByteFromBuff(byteBuf)); |
| | | // byteBuf.resetReaderIndex(); |
| | | // byteBuf.writerIndex(byteBuf.readableBytes() - 1).writeByte(this.getValidCode()); |
| | | // return byteBuf; |
| | | // } |
| | | |
| | | } |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * Created by vincent on 2023/3/23 |
| | | */ |
| | | //@Data |
| | | public class AgvProtocol implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 8858385758421567504L; |
| | | |
| | | private String agvNo; |
| | | |
| | | private int timestamp; |
| | | |
| | | private IMessageBody messageBody; |
| | | |
| | | public static AgvProtocol build(String agvNo) { |
| | | AgvProtocol protocol = new AgvProtocol(); |
| | | protocol.setAgvNo(agvNo); |
| | | //protocol.setTimestamp((int) (System.currentTimeMillis()/1000)); |
| | | return protocol; |
| | | } |
| | | |
| | | public AgvProtocol setAgvNo(String agvNo) { |
| | | this.agvNo = agvNo; |
| | | return this; |
| | | } |
| | | |
| | | public AgvProtocol setMessageBody(IMessageBody messageBody) { |
| | | this.messageBody = messageBody; |
| | | return this; |
| | | } |
| | | |
| | | } |
| | |
| | | package com.zy.acs.gateway.utils; |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | /** |
| | | * CRC16循环冗余校验码 |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | |
| | | import java.lang.reflect.*; |
| | | import java.nio.charset.StandardCharsets; |
| | | import java.security.MessageDigest; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | |
| | | /** |
| | | * Created by vincent on 2019-06-09 |
| | | */ |
| | | public class Cools { |
| | | |
| | | public static boolean isEmpty(Object... objects) { |
| | | for (Object obj : objects){ |
| | | if (isEmpty(obj)){ |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | @SuppressWarnings("rawtypes") |
| | | public static boolean isEmpty(Object o) { |
| | | if (o == null) { |
| | | return true; |
| | | } |
| | | if (o instanceof String) { |
| | | if (o.toString().trim().equals("")) { |
| | | return true; |
| | | } |
| | | } else if (o instanceof List) { |
| | | if (((List) o).size() == 0) { |
| | | return true; |
| | | } |
| | | } else if (o instanceof Map) { |
| | | if (((Map) o).size() == 0) { |
| | | return true; |
| | | } |
| | | } else if (o instanceof Set) { |
| | | if (((Set) o).size() == 0) { |
| | | return true; |
| | | } |
| | | } else if (o instanceof Object[]) { |
| | | if (((Object[]) o).length == 0) { |
| | | return true; |
| | | } |
| | | } else if (o instanceof int[]) { |
| | | if (((int[]) o).length == 0) { |
| | | return true; |
| | | } |
| | | } else if (o instanceof long[]) { |
| | | if (((long[]) o).length == 0) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | public static int sqlLimitIndex(Integer pageIndex, Integer pageSize){ |
| | | return (pageIndex - 1) * pageSize; |
| | | } |
| | | |
| | | //public static String enToken(String username, String password){ |
| | | // return AesUtils.encrypt(username, zerofill(password, 16)); |
| | | //} |
| | | |
| | | //public static String deTokn(String token, String password){ |
| | | // //return AesUtils.decrypt(token, zerofill(password, 16)); |
| | | //} |
| | | |
| | | public static String zerofill(String msg, Integer count){ |
| | | if (msg.length() == count){ |
| | | return msg; |
| | | } else if (msg.length() > count){ |
| | | return msg.substring(0, 16); |
| | | } else { |
| | | StringBuilder msgBuilder = new StringBuilder(msg); |
| | | for (int i = 0; i<count-msg.length(); i++){ |
| | | msgBuilder.append("0"); |
| | | } |
| | | return msgBuilder.toString(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 截取字符串(默认end=true) |
| | | * @param str 被截字符串 |
| | | * @param end true:最后一个字符 / false:第一个字符 |
| | | */ |
| | | public static String deleteChar(String str, boolean end){ |
| | | if (isEmpty(str)){ |
| | | return ""; |
| | | } |
| | | if (end){ |
| | | return str.substring(0, str.length()-1); |
| | | } else { |
| | | return str.substring(1); |
| | | } |
| | | } |
| | | |
| | | public static String deleteChar(String str){ |
| | | return deleteChar(str, true); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * map 转 对象 |
| | | */ |
| | | public static <T> T conver(Map<? extends String, ?> map, Class<T> cls){ |
| | | T instance = null; |
| | | try { |
| | | Constructor<T> constructor = cls.getDeclaredConstructor(); |
| | | boolean constructorAccessible = constructor.isAccessible(); |
| | | constructor.setAccessible(true); |
| | | instance = constructor.newInstance(); |
| | | constructor.setAccessible(constructorAccessible); |
| | | } catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | Class<?> prototype = cls; |
| | | do { |
| | | for (Field field : prototype.getDeclaredFields()){ |
| | | if (Modifier.isFinal(field.getModifiers()) |
| | | || Modifier.isStatic(field.getModifiers()) |
| | | || Modifier.isTransient(field.getModifiers())){ |
| | | continue; |
| | | } |
| | | String fieldName = field.getName(); |
| | | Object val = null; |
| | | if (map.containsKey(fieldName)){ |
| | | val = map.get(fieldName); |
| | | } |
| | | if (val != null){ |
| | | boolean fieldAccessible = field.isAccessible(); |
| | | field.setAccessible(true); |
| | | Class<?> type = field.getType(); |
| | | try { |
| | | Constructor<?> constructor = type.getDeclaredConstructor(String.class); |
| | | boolean constructorAccessible = constructor.isAccessible(); |
| | | constructor.setAccessible(true); |
| | | field.set(instance, constructor.newInstance(String.valueOf(val))); |
| | | constructor.setAccessible(constructorAccessible); |
| | | } catch (IllegalAccessException |
| | | | InstantiationException |
| | | | InvocationTargetException |
| | | | NoSuchMethodException e) { |
| | | System.err.println("convert error ===> Class["+prototype+"],Field:["+fieldName+"],Type:["+type+"],Value:["+val+"]"); |
| | | } |
| | | field.setAccessible(fieldAccessible); |
| | | } |
| | | } |
| | | prototype = prototype.getSuperclass(); |
| | | } while (!Object.class.equals(prototype)); |
| | | return instance; |
| | | } |
| | | |
| | | /** |
| | | * 对象 转 map |
| | | */ |
| | | public static Map<String, Object> conver(Object obj){ |
| | | Class<?> cls = obj.getClass(); |
| | | Field[] fields = getAllFields(cls); |
| | | Map<String, Object> map = new HashMap<>(); |
| | | for (Field field : fields) { |
| | | if (Modifier.isFinal(field.getModifiers()) |
| | | || Modifier.isStatic(field.getModifiers()) |
| | | || Modifier.isTransient(field.getModifiers())){ |
| | | continue; |
| | | } |
| | | String key = field.getName(); |
| | | boolean flag = field.isAccessible(); |
| | | field.setAccessible(true); |
| | | Object val = null; |
| | | try { |
| | | val = field.get(obj); |
| | | } catch (IllegalAccessException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | field.setAccessible(flag); |
| | | if (val != null){ |
| | | map.put(key, val); |
| | | } |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | /** |
| | | * 获取指定Class(及其SuperClass)的成员变量 |
| | | */ |
| | | public static Field[] getAllFields(Class<?> cls){ |
| | | return getAllFields(cls, null); |
| | | } |
| | | |
| | | /** |
| | | * 递归合并基类Field |
| | | */ |
| | | private static Field[] getAllFields(Class<?> cls, Field[] params){ |
| | | Field[] fields = (params == null) ? cls.getDeclaredFields() : params; |
| | | Class<?> superCls = cls.getSuperclass(); |
| | | if (superCls == null || superCls == Object.class){ |
| | | return fields; |
| | | } |
| | | Field[] superClsFields = superCls.getDeclaredFields(); |
| | | fields = addAll(fields, superClsFields); |
| | | return getAllFields(superCls, fields); |
| | | } |
| | | |
| | | /** |
| | | * 根据fieldName获取Field对象 |
| | | */ |
| | | public static Field getField(Class<?> cls, String fieldName) { |
| | | Field[] allFields = getAllFields(cls); |
| | | for (Field field : allFields) { |
| | | if (field.getName().equals(fieldName)) { |
| | | return field; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 获取对象中某个Field的值 |
| | | */ |
| | | public static Object getFieldValue(Object obj, Field field) { |
| | | if (null == field) { |
| | | return null; |
| | | } else { |
| | | if (obj instanceof Class) { |
| | | obj = null; |
| | | } |
| | | if (!field.isAccessible()) { |
| | | field.setAccessible(true); |
| | | } |
| | | try { |
| | | return field.get(obj); |
| | | } catch (IllegalAccessException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 数组叠加 |
| | | */ |
| | | @SuppressWarnings("unchecked") |
| | | public static <T> T[] addAll(T[] array1, T... array2) { |
| | | if (array1 == null) { |
| | | return clone(array2); |
| | | } else if (array2 == null) { |
| | | return clone(array1); |
| | | } else { |
| | | Class<?> cls = array1.getClass().getComponentType(); |
| | | T[] joinedArray = (T[]) Array.newInstance(cls, array1.length + array2.length); |
| | | System.arraycopy(array1, 0, joinedArray, 0, array1.length); |
| | | |
| | | try { |
| | | System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); |
| | | return joinedArray; |
| | | } catch (ArrayStoreException e) { |
| | | Class<?> type2 = array2.getClass().getComponentType(); |
| | | if (!cls.isAssignableFrom(type2)) { |
| | | throw new RuntimeException("Cannot store " + type2.getName() + " in an array of " + cls.getName(), e); |
| | | } else { |
| | | throw e; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 克隆 |
| | | */ |
| | | private static <T> T[] clone(T[] array) { |
| | | return array == null ? null : array.clone(); |
| | | } |
| | | |
| | | /** |
| | | * map操作 |
| | | */ |
| | | public static CoolMap add(String key,Object value){ |
| | | CoolMap map = new CoolMap(); |
| | | map.put(key, value); |
| | | return map; |
| | | } |
| | | |
| | | public static class CoolMap extends HashMap<String, Object>{ |
| | | |
| | | public CoolMap add(String key,Object value){ |
| | | this.put(key, value); |
| | | return this; |
| | | } |
| | | |
| | | public CoolMap $(String key,Object value){ |
| | | this.put(key, value); |
| | | return this; |
| | | } |
| | | |
| | | } |
| | | |
| | | public static String md5(String string){ |
| | | try{ |
| | | MessageDigest md5 = MessageDigest.getInstance("MD5"); |
| | | byte[] bytes = md5.digest(string.getBytes(StandardCharsets.UTF_8)); |
| | | char[] chars = new char[bytes.length * 2]; |
| | | for (int i = 0; i < bytes.length; i++) { |
| | | int b = bytes[i]; |
| | | chars[i * 2] = hexDigits[(b & 0xF0) >> 4]; |
| | | chars[i * 2 + 1] = hexDigits[b & 0x0F]; |
| | | } |
| | | return new String(chars).toLowerCase(); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | throw new RuntimeException("md5加密失败,str=".concat(string)); |
| | | } |
| | | } |
| | | |
| | | private static char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; |
| | | |
| | | //public static Map<String, Object> translate(Object obj){ |
| | | // Class<?> cls = obj.getClass(); |
| | | // Field[] fields = getAllFields(cls); |
| | | // Map<String, Object> map = new HashMap<>(); |
| | | // for (Field field : fields) { |
| | | // String key = field.getName(); |
| | | // if (field.isAnnotationPresent(CoolTranslate.class)){ |
| | | // CoolTranslate annotation = field.getAnnotation(CoolTranslate.class); |
| | | // if (!isEmpty(annotation.value())) { |
| | | // key = annotation.value(); |
| | | // } |
| | | // } |
| | | // boolean flag = field.isAccessible(); |
| | | // field.setAccessible(true); |
| | | // Object val = null; |
| | | // try { |
| | | // val = field.get(obj); |
| | | // } catch (IllegalAccessException e) { |
| | | // e.printStackTrace(); |
| | | // } |
| | | // field.setAccessible(flag); |
| | | // if (val != null){ |
| | | // map.put(key, val); |
| | | // } |
| | | // } |
| | | // return map; |
| | | //} |
| | | |
| | | public static boolean eq(String str, String str0) { |
| | | if (Cools.isEmpty(str) && Cools.isEmpty(str0)) { |
| | | return true; |
| | | } |
| | | if (Cools.isEmpty(str) && !Cools.isEmpty(str0)) { |
| | | return false; |
| | | } |
| | | if (Cools.isEmpty(str0) && !Cools.isEmpty(str)) { |
| | | return false; |
| | | } |
| | | if (str.equals(str0)) { |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | public enum DirectionType { |
| | | |
| | | DOWN, |
| | | UP, |
| | | ; |
| | | |
| | | } |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | /** |
| | | * 加密标识枚举 |
| | | * Created by vincent on 2019-04-02 |
| | | */ |
| | | public enum EncryType implements ICodedStatus { |
| | | |
| | | /** |
| | | * 数据不加密 |
| | | */ |
| | | ENCRY_EMPTY(0x01), |
| | | /** |
| | | * RSA算法加密 |
| | | */ |
| | | ENCRY_RSA(0x02), |
| | | /** |
| | | * AES128位算法加密 |
| | | */ |
| | | ENCRY_AES128(0x03), |
| | | /** |
| | | * 异常 |
| | | */ |
| | | ENCRY_EXCEPTION(0xFE), |
| | | /** |
| | | * 无效 |
| | | */ |
| | | ENCRY_INVALID(0xFF); |
| | | |
| | | /** |
| | | * 其他数值为预留 |
| | | */ |
| | | |
| | | private int code; |
| | | EncryType(int code) { |
| | | this.code = code; |
| | | } |
| | | |
| | | |
| | | public static EncryType getByCode(int code) { |
| | | for (EncryType e : |
| | | EncryType.values()) { |
| | | if (e.getCode() == code) { |
| | | return e; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public int getCode() { |
| | | return code; |
| | | } |
| | | |
| | | // 预期的期望值,逗号分隔 |
| | | public static String expectedVals() { |
| | | StringBuilder valSb = new StringBuilder(); |
| | | for (EncryType c : |
| | | EncryType.values()) { |
| | | valSb.append(c.getCode()).append(","); |
| | | } |
| | | // 删除最后一个逗号 |
| | | valSb.deleteCharAt(valSb.length() - 1); |
| | | return valSb.toString(); |
| | | } |
| | | } |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | /** |
| | | * 预留接口,反射时调用 |
| | | * Created by vincent on 2019-04-03 |
| | | */ |
| | | public interface ICodedStatus { |
| | | int getCode(); |
| | | } |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | /** |
| | | * 命令参数 |
| | | */ |
| | | public interface ICommandBody { |
| | | |
| | | byte[] writeToBytes(); |
| | | |
| | | void readFromBytes(byte[] messageBodyBytes); |
| | | |
| | | } |
| | |
| | | package com.zy.acs.common.domain.protocol; |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | import java.io.Serializable; |
| | | |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | import io.netty.buffer.ByteBuf; |
| | | import io.netty.buffer.ByteBufUtil; |
| | | |
| | | /** |
| | | * 协议体 |
| | | * Created by vincent on 2019-04-03 |
| | | */ |
| | | public class PacBody { |
| | | |
| | | private ByteBuf content; |
| | | |
| | | private IMessageBody messageBody; |
| | | |
| | | public ByteBuf getContent() { |
| | | return content; |
| | | } |
| | | |
| | | public PacBody setContent(ByteBuf content) { |
| | | this.content = content.duplicate(); |
| | | return this; |
| | | } |
| | | |
| | | public IMessageBody getMessageBody() { |
| | | return messageBody; |
| | | } |
| | | |
| | | public void setMessageBody(IMessageBody messageBody) { |
| | | this.messageBody = messageBody; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return ByteBufUtil.hexDump(content); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | |
| | | public enum PacErrorType implements ICodedStatus { |
| | | |
| | | /** |
| | | * 解析异常 |
| | | */ |
| | | PAC_ANALYZE_ERROR(0x01, "报文解析异常"), |
| | | |
| | | /** |
| | | * 报文长度验证异常 |
| | | */ |
| | | PAC_LENGTH_ERROR(0x02, "报文长度验证异常"), |
| | | |
| | | /** |
| | | * 报文校验异常 |
| | | */ |
| | | PAC_VALID_ERROR(0x023, "报文长度验证异常"), |
| | | |
| | | ; |
| | | |
| | | private int code; // 编码 |
| | | private String des; // 描述 |
| | | |
| | | PacErrorType(int code, String des) { |
| | | this.code = code; |
| | | this.des = des; |
| | | } |
| | | |
| | | public int getCode() { |
| | | return code; |
| | | } |
| | | |
| | | public String getDes() { |
| | | return des; |
| | | } |
| | | |
| | | public static PacErrorType getByCode(int code) { |
| | | for (PacErrorType c : |
| | | PacErrorType.values()) { |
| | | if (c.getCode() == code) { |
| | | return c; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | |
| | | package com.zy.acs.gateway.domain; |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | import com.zy.acs.gateway.constant.EncryType; |
| | | import com.zy.acs.gateway.constant.ProtocolType; |
| | | import lombok.Data; |
| | | import org.apache.commons.lang.builder.ToStringBuilder; |
| | | |
| | | /** |
| | | * 协议头 |
| | | * Created by vincent on 2019-04-03 |
| | | */ |
| | | @Data |
| | | public class PacHeader { |
| | | |
| | | /** |
| | |
| | | return this; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return new ToStringBuilder(this) |
| | | .append("startSymbol", startSymbol) |
| | | .append("contentLength", contentLength) |
| | | .append("uniqueNo", uniqueNo) |
| | | .append("timestamp", timestamp) |
| | | .append("protocolType", protocolType.getDes()) |
| | | .append("serialNum", serialNum) |
| | | .toString(); |
| | | } |
| | | //@Override |
| | | //public String toString() { |
| | | // return new ToStringBuilder(this) |
| | | // .append("startSymbol", startSymbol) |
| | | // .append("contentLength", contentLength) |
| | | // .append("uniqueNo", uniqueNo) |
| | | // .append("timestamp", timestamp) |
| | | // .append("protocolType", protocolType.getDes()) |
| | | // .append("serialNum", serialNum) |
| | | // .toString(); |
| | | //} |
| | | } |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | /** |
| | | * 报文标识枚举 |
| | | * 下标1: 起始索引 |
| | | * 下标2: 长度 |
| | | * 下标3: 描述 |
| | | * Created by vincent on 2019-04-03 |
| | | */ |
| | | public enum PackagePart { |
| | | |
| | | /** |
| | | * 起始符 |
| | | */ |
| | | START_SYMBOL(0, 1, "起始符"), |
| | | |
| | | /** |
| | | * 数据单元长度 |
| | | */ |
| | | CONTENT_LENGTH(1, 2, "数据单元长度"), |
| | | |
| | | |
| | | /** |
| | | * 唯一标识码 |
| | | */ |
| | | UNIQUENO(3, 4, "唯一标识码"), |
| | | |
| | | /** |
| | | * 时间戳 |
| | | */ |
| | | TIMESTAMP(7, 4, "时间戳"), |
| | | |
| | | /** |
| | | * 命令标识 |
| | | */ |
| | | COMMAND_MARK(11, 1, "命令标识"), |
| | | |
| | | /** |
| | | * 数据单元 |
| | | */ |
| | | CONTENT(12, -1, "数据单元"), |
| | | |
| | | /** |
| | | * 校验码 |
| | | */ |
| | | VALIDE_CODE( -1, 2, "校验码"), |
| | | |
| | | /** |
| | | * 应答标志 |
| | | */ |
| | | ACK_MARK(3, 1, "应答标志"), |
| | | |
| | | /** |
| | | * 数据单元加密方式 |
| | | */ |
| | | ENCRYPT_TYPE(21, 1, "数据单元加密方式"), |
| | | |
| | | ; |
| | | |
| | | // 字节段开始索引 |
| | | private Integer startIndex; |
| | | |
| | | // 字节段总字节数 |
| | | private Integer len; |
| | | |
| | | // 描述 |
| | | private String des; |
| | | |
| | | PackagePart(int startIndex, int len, String des) { |
| | | this.startIndex = startIndex; |
| | | this.len = len; |
| | | this.des = des; |
| | | } |
| | | |
| | | public Integer getStartIndex() { |
| | | return startIndex; |
| | | } |
| | | |
| | | public Integer getLen() { |
| | | return len; |
| | | } |
| | | |
| | | public String getDes() { |
| | | return des; |
| | | } |
| | | |
| | | } |
| | |
| | | package com.zy.acs.gateway.handler.coder; |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | import com.core.common.RadixTools; |
| | | import com.zy.acs.common.utils.Utils; |
| | | import com.zy.acs.gateway.config.SystemProperties; |
| | | import com.zy.acs.gateway.constant.PackagePart; |
| | | import com.zy.acs.gateway.domain.AgvPackage; |
| | | import com.zy.acs.gateway.utils.ValidUtil; |
| | | import java.util.logging.Logger; |
| | | |
| | | import io.netty.buffer.ByteBuf; |
| | | import io.netty.buffer.ByteBufUtil; |
| | | import io.netty.channel.ChannelHandler; |
| | | import io.netty.channel.ChannelHandlerContext; |
| | | import io.netty.handler.codec.MessageToByteEncoder; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * 编码器 |
| | |
| | | * 处理方式: 异或和 |
| | | * Created by vincent on 2019-04-02 |
| | | */ |
| | | @Component |
| | | //@Component |
| | | @ChannelHandler.Sharable |
| | | public class ProtocolEncoder extends MessageToByteEncoder<Object> { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(ProtocolEncoder.class); |
| | | //private static final Logger log = LoggerFactory.getLogger(ProtocolEncoder.class); |
| | | |
| | | @Autowired |
| | | //@Autowired |
| | | private SystemProperties systemProperties; |
| | | |
| | | @Override |
| | |
| | | |
| | | byte[] bodyBytes = pac.getBody().getMessageBody().writeToBytes(); // body |
| | | |
| | | String uniqueNo = pac.getHeader().getUniqueNo(); |
| | | //String uniqueNo = pac.getHeader().getUniqueNo(); |
| | | |
| | | byte[] uniquenoBytes = RadixTools.intToBytes(Integer.parseInt(pac.getHeader().getUniqueNo())); // uniqueno |
| | | //byte[] uniquenoBytes = RadixTools.intToBytes(Integer.parseInt(pac.getHeader().getUniqueNo())); // uniqueno |
| | | |
| | | |
| | | int len = PackagePart.UNIQUENO.getLen() // len |
| | |
| | | + PackagePart.COMMAND_MARK.getLen() |
| | | + bodyBytes.length; |
| | | |
| | | out.writeByte(pac.getHeader().getStartSymbol()) // symbol |
| | | .writeShortLE(len) |
| | | .writeBytes(Utils.reverse(uniquenoBytes)) // uniqueno |
| | | .writeIntLE((int) (System.currentTimeMillis() / 1000)) // timestamp |
| | | .writeByte(pac.getHeader().getProtocolType().getCode()) // type |
| | | .writeBytes(bodyBytes) // body |
| | | .writeShort(pac.getValidCode()) // valid |
| | | ; |
| | | //out.writeByte(pac.getHeader().getStartSymbol()) // symbol |
| | | // .writeShortLE(len) |
| | | // .writeBytes(Utils.reverse(uniquenoBytes)) // uniqueno |
| | | // .writeIntLE((int) (System.currentTimeMillis() / 1000)) // timestamp |
| | | // .writeByte(pac.getHeader().getProtocolType().getCode()) // type |
| | | // .writeBytes(bodyBytes) // body |
| | | // .writeShort(pac.getValidCode()) // valid |
| | | //; |
| | | |
| | | pac.setValidCode(ValidUtil.calculateValidByteFromBuff(out)); |
| | | out.resetReaderIndex(); |
| | |
| | | |
| | | |
| | | if (systemProperties.isPrintPacLog()){ |
| | | log.info("Agv [{}] 下行 [{}] >>> {}", uniqueNo, pac.getHeader().getProtocolType().getDes(), ByteBufUtil.hexDump(out).toUpperCase()); |
| | | //log.info("Agv [{}] 下行 [{}] >>> {}", uniqueNo, pac.getHeader().getProtocolType().getDes(), ByteBufUtil.hexDump(out).toUpperCase()); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | |
| | | /** |
| | | * 应答实体枚举 |
| | | * Created by vincent on 2019-04-02 |
| | | */ |
| | | public enum ProtocolPojoType { |
| | | |
| | | PATH_COMMAND(ProtocolType.PATH_COMMAND, AGV_01_DOWN.class), |
| | | |
| | | ACTION_COMMAND(ProtocolType.ACTION_COMMAND, AGV_02_DOWN.class), |
| | | |
| | | LOGIN_ACK(ProtocolType.LOGIN_ACK, AGV_F0_DOWN.class), |
| | | |
| | | ACTION_SUCCESS_ACK(ProtocolType.ACTION_SUCCESS_ACK, AGV_A1_DOWN.class), |
| | | |
| | | ACTIVATION_COMMAND(ProtocolType.ACTIVATION_COMMAND, AGV_80_DOWN.class), |
| | | |
| | | HEARTBEAT_COMMAND(ProtocolType.HEARTBEAT_COMMAND, AGV_03_DOWN.class), |
| | | |
| | | ; |
| | | |
| | | |
| | | public final ProtocolType protocolType; |
| | | |
| | | |
| | | public final Class<? extends IMessageBody> clazz; |
| | | |
| | | ProtocolPojoType(ProtocolType protocolType, Class<? extends IMessageBody> clazz) { |
| | | this.protocolType = protocolType; |
| | | this.clazz = clazz; |
| | | } |
| | | |
| | | |
| | | public static ProtocolPojoType query(ProtocolType protocolType) { |
| | | for (ProtocolPojoType type : ProtocolPojoType.values()) { |
| | | if (protocolType.equals(type.protocolType)) { |
| | | return type; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | public static ProtocolPojoType query(Class<? extends IMessageBody> clazz) { |
| | | for (ProtocolPojoType type : ProtocolPojoType.values()) { |
| | | if (clazz.equals(type.clazz)) { |
| | | return type; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | /** |
| | | * 标识枚举 |
| | | * Created by vincent on 2019-04-02 |
| | | */ |
| | | public enum ProtocolType implements ICodedStatus { |
| | | |
| | | // 下行 ------------------------------------------------------------------- |
| | | |
| | | PATH_COMMAND(0x01, "路径数据包", DirectionType.DOWN), |
| | | |
| | | ACTION_COMMAND(0x02, "动作命令包", DirectionType.DOWN), |
| | | |
| | | HEARTBEAT_COMMAND(0x03, "心跳包", DirectionType.DOWN), |
| | | |
| | | FAULT_CLEAR_COMMAND(0x04, "故障命令包", DirectionType.DOWN), |
| | | |
| | | ACTIVATION_COMMAND(0x80, "激活包", DirectionType.DOWN), |
| | | |
| | | LOGIN_ACK(0xF0, "登录应答包", DirectionType.DOWN), |
| | | |
| | | ACTION_SUCCESS_ACK(0xA1, "动作完成成功应答", DirectionType.DOWN), |
| | | |
| | | ACTION_FAIL_ACK(0xA0, "动作完成失败应答", DirectionType.DOWN), |
| | | |
| | | // 上行 ------------------------------------------------------------------- |
| | | |
| | | PATH_ACK(0x01, "路径应答包", DirectionType.UP), |
| | | |
| | | COMMAND_ACK(0x02, "命令应答包", DirectionType.UP), |
| | | |
| | | ACTION_COMPLETE(0x11, "动作完成包", DirectionType.UP), |
| | | |
| | | DATA_CODE_REPORT(0x12, "有码实时数据包", DirectionType.UP), |
| | | |
| | | DATA_WITHOUT_CODE_REPORT(0x13, "无码实时数据包", DirectionType.UP), |
| | | |
| | | HEARTBEAT_REPORT(0x03, "心跳包", DirectionType.UP), |
| | | |
| | | FAULT_REPORT(0x04, "故障数据包", DirectionType.UP), |
| | | |
| | | HANDLE_FALUT_ACK(0x14, "故障清除应答包", DirectionType.UP), |
| | | |
| | | SILO_REPORT(0x70, "料仓信息包", DirectionType.UP), |
| | | |
| | | LOGIN_REPORT(0xF0, "机器人登陆数据包", DirectionType.UP), |
| | | |
| | | ; |
| | | |
| | | private final int code; // 编码 |
| | | private final String des; // 描述 |
| | | private final DirectionType direction; |
| | | |
| | | ProtocolType(int code, String des, DirectionType direction) { |
| | | this.code = code; |
| | | this.des = des; |
| | | this.direction = direction; |
| | | } |
| | | |
| | | public int getCode() { |
| | | return code; |
| | | } |
| | | |
| | | public String getDes() { |
| | | return des; |
| | | } |
| | | |
| | | public DirectionType getDirection() { |
| | | return direction; |
| | | } |
| | | |
| | | public static ProtocolType getByCode(int code, DirectionType direction) { |
| | | for (ProtocolType type : ProtocolType.values()) { |
| | | if (type.getCode() == code && type.getDirection() == direction) { |
| | | return type; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | } |
| | |
| | | package com.zy.acs.gateway.utils; |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | import com.zy.acs.common.domain.AgvProtocol; |
| | | import com.zy.acs.common.domain.protocol.IMessageBody; |
| | | import com.zy.acs.gateway.constant.ProtocolPojoType; |
| | | import com.zy.acs.gateway.constant.ProtocolType; |
| | | import com.zy.acs.gateway.domain.AgvPackage; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import java.util.logging.Logger; |
| | | |
| | | /** |
| | | * Created by vincent on 2019-04-03 |
| | | */ |
| | | public class ProtocolUtils { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(ProtocolUtils.class); |
| | | //private static final Logger log = LoggerFactory.getLogger(ProtocolUtils.class); |
| | | |
| | | // 下行协议报文组装 |
| | | public static AgvPackage installDownProtocol(AgvProtocol protocol){ |
| | | |
| | | |
| | | ProtocolPojoType protocolPojo = ProtocolPojoType.query(protocol.getMessageBody().getClass()); |
| | | //ProtocolPojoType protocolPojo = ProtocolPojoType.query(protocol.getMessageBody().getClass()); |
| | | |
| | | assert protocolPojo != null; |
| | | //assert protocolPojo != null; |
| | | |
| | | AgvPackage ackPackage = AgvPackage.valueOfEmpty(); |
| | | ackPackage.getHeader() |
| | | .setStartSymbol((byte)0xEE) |
| | | .setContentLength(0) |
| | | .setUniqueNo(protocol.getAgvNo()) |
| | | .setTimestamp(protocol.getTimestamp()) |
| | | .setProtocolType(protocolPojo.protocolType) |
| | | //.setUniqueNo(protocol.getAgvNo()) |
| | | //.setTimestamp(protocol.getTimestamp()) |
| | | //.setProtocolType(protocolPojo.protocolType) |
| | | ; |
| | | |
| | | ackPackage.getBody().setMessageBody(protocol.getMessageBody()); |
| | | //ackPackage.getBody().setMessageBody(protocol.getMessageBody()); |
| | | |
| | | return ackPackage; |
| | | |
| | |
| | | } catch (ReflectiveOperationException reflectiveOperationException) { |
| | | |
| | | |
| | | log.error("MessageBodyHandler ReflectiveOperationException", reflectiveOperationException); |
| | | //log.error("MessageBodyHandler ReflectiveOperationException", reflectiveOperationException); |
| | | |
| | | log.error("java反射创建实例失败:{}", protocolPojo.clazz.getName()); |
| | | //log.error("java反射创建实例失败:{}", protocolPojo.clazz.getName()); |
| | | |
| | | return null; |
| | | } |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | |
| | | import java.net.InetAddress; |
| | | import java.net.UnknownHostException; |
| | | |
| | | /** |
| | | * vc系统配置 |
| | | * Created by luxiaotao on 2018/10/15 |
| | | */ |
| | | //@Configuration |
| | | //@ConfigurationProperties(prefix = "agv-tcp") |
| | | public class SystemProperties { |
| | | |
| | | public static String HOST_NAME; |
| | | |
| | | static { |
| | | try { |
| | | HOST_NAME = InetAddress.getLocalHost().getHostName(); |
| | | } catch (UnknownHostException e) { |
| | | System.err.println("find hostname err"); |
| | | } |
| | | } |
| | | |
| | | private int port; |
| | | |
| | | private int heartSeconds; |
| | | |
| | | private int backlog; |
| | | |
| | | private boolean keepAlive; |
| | | |
| | | private int sndbuf; |
| | | |
| | | private int rcvbuf; |
| | | |
| | | private boolean printPacLog; |
| | | |
| | | public int getPort() { |
| | | return port; |
| | | } |
| | | |
| | | public void setPort(int port) { |
| | | this.port = port; |
| | | } |
| | | |
| | | public int getHeartSeconds() { |
| | | return heartSeconds; |
| | | } |
| | | |
| | | public void setHeartSeconds(int heartSeconds) { |
| | | this.heartSeconds = heartSeconds; |
| | | } |
| | | |
| | | public int getBacklog() { |
| | | return backlog; |
| | | } |
| | | |
| | | public void setBacklog(int backlog) { |
| | | this.backlog = backlog; |
| | | } |
| | | |
| | | public boolean isKeepAlive() { |
| | | return keepAlive; |
| | | } |
| | | |
| | | public void setKeepAlive(boolean keepAlive) { |
| | | this.keepAlive = keepAlive; |
| | | } |
| | | |
| | | public int getSndbuf() { |
| | | return sndbuf; |
| | | } |
| | | |
| | | public void setSndbuf(int sndbuf) { |
| | | this.sndbuf = sndbuf; |
| | | } |
| | | |
| | | public int getRcvbuf() { |
| | | return rcvbuf; |
| | | } |
| | | |
| | | public void setRcvbuf(int rcvbuf) { |
| | | this.rcvbuf = rcvbuf; |
| | | } |
| | | |
| | | public boolean isPrintPacLog() { |
| | | return printPacLog; |
| | | } |
| | | |
| | | public void setPrintPacLog(final boolean printPacLog) { |
| | | this.printPacLog = printPacLog; |
| | | } |
| | | } |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | | |
| | | /** |
| | | * Created by vincent on 2023/3/14 |
| | | */ |
| | | public class Utils { |
| | | |
| | | /** |
| | | * 数组倒序 |
| | | * @param bytes |
| | | * @param <T> |
| | | */ |
| | | public static <T> byte[] reverse(byte[] bytes) { |
| | | if (bytes == null) return null; |
| | | for (int start = 0, end = bytes.length - 1; start < end; start++, end--) { |
| | | byte temp = bytes[end]; |
| | | bytes[end] = bytes[start]; |
| | | bytes[start] = temp; |
| | | } |
| | | return bytes; |
| | | } |
| | | |
| | | /** |
| | | * 截取数组 |
| | | * @param bytes 原数组 |
| | | * @param pos 定位(截取后包含定位点数据) |
| | | * @param len 长度 |
| | | * @return new arr |
| | | */ |
| | | public static byte[] slice(byte[] bytes, int pos, int len) { |
| | | if (bytes == null || bytes.length == 0 || len == 0) { |
| | | return new byte[0]; |
| | | } |
| | | if (pos + len > bytes.length) { |
| | | throw new RuntimeException("com.zy.acs.common.utils ArrayIndexOutOfBoundsException\n" + |
| | | "原数组 bytes 长度为 " + bytes.length + ",截取长度超过原数组!"); |
| | | } |
| | | byte[] arr = new byte[len]; |
| | | System.arraycopy(bytes, pos, arr, 0, len); |
| | | return arr; |
| | | } |
| | | |
| | | public static byte[] sliceWithReverse(byte[] bytes, int pos, int len) { |
| | | byte[] slice = slice(bytes, pos, len); |
| | | reverse(slice); |
| | | return slice; |
| | | } |
| | | |
| | | public static byte[] merge(Object... objects) { |
| | | int len = 0; |
| | | for (Object object : objects) { |
| | | if (object instanceof byte[]) { |
| | | byte[] bytes = (byte[]) object; |
| | | len += bytes.length; |
| | | } |
| | | if (object instanceof Byte) { |
| | | len++; |
| | | } |
| | | } |
| | | byte[] arr = new byte[len]; |
| | | int idx = 0; |
| | | for (Object object : objects) { |
| | | if (object instanceof byte[]) { |
| | | byte[] bytes = (byte[]) object; |
| | | System.arraycopy(bytes, 0, arr, idx, bytes.length); |
| | | idx += bytes.length; |
| | | } |
| | | if (object instanceof Byte) { |
| | | byte[] bytes = new byte[] {(Byte) object}; |
| | | System.arraycopy(bytes, 0, arr, idx, bytes.length); |
| | | idx += bytes.length; |
| | | } |
| | | } |
| | | return arr; |
| | | } |
| | | |
| | | public static <T> String join(T[] array, String seq) { |
| | | StringBuilder sb = new StringBuilder(); |
| | | if (array != null) { |
| | | for (int i = 0; i < array.length; i++) { |
| | | sb.append(array[i]); |
| | | if (i < array.length - 1) { |
| | | sb.append(seq); |
| | | } |
| | | } |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | public static String zeroFill(String msg, Integer len) { |
| | | len = Optional.ofNullable(len).orElse(16); |
| | | if (msg.length() == len){ |
| | | return msg; |
| | | } else if (msg.length() > len){ |
| | | return msg.substring(0, 16); |
| | | } else { |
| | | StringBuilder msgBuilder = new StringBuilder(msg); |
| | | for (int i = 0; i<len-msg.length(); i++){ |
| | | msgBuilder.insert(0,"0"); |
| | | } |
| | | return msgBuilder.toString(); |
| | | } |
| | | } |
| | | |
| | | public static String removePrefix(String str, String prefix) { |
| | | if (!Cools.isEmpty(str) && !Cools.isEmpty(prefix)) { |
| | | if (str.startsWith(prefix)) { |
| | | return str.substring(prefix.length()); |
| | | } else { |
| | | return str; |
| | | } |
| | | } else { |
| | | return str; |
| | | } |
| | | } |
| | | |
| | | public static String removeSuffix(String str, String suffix) { |
| | | if (!Cools.isEmpty(str) && !Cools.isEmpty(suffix)) { |
| | | if (str.endsWith(suffix)) { |
| | | return str.substring(0, str.indexOf(suffix)); |
| | | } else { |
| | | return str; |
| | | } |
| | | } else { |
| | | return str; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 大驼峰 转 symbol小驼峰 |
| | | */ |
| | | public static String toSymbolCase(String str, char symbol) { |
| | | if (str == null) { |
| | | return null; |
| | | } else { |
| | | int length = str.length(); |
| | | StringBuilder sb = new StringBuilder(); |
| | | |
| | | for(int i = 0; i < length; ++i) { |
| | | char c = str.charAt(i); |
| | | if (Character.isUpperCase(c)) { |
| | | Character preChar = i > 0 ? str.charAt(i - 1) : null; |
| | | Character nextChar = i < str.length() - 1 ? str.charAt(i + 1) : null; |
| | | if (null != preChar) { |
| | | if (symbol == preChar) { |
| | | if (null == nextChar || Character.isLowerCase(nextChar)) { |
| | | c = Character.toLowerCase(c); |
| | | } |
| | | } else if (Character.isLowerCase(preChar)) { |
| | | sb.append(symbol); |
| | | if (null == nextChar || Character.isLowerCase(nextChar)) { |
| | | c = Character.toLowerCase(c); |
| | | } |
| | | } else if (null == nextChar || Character.isLowerCase(nextChar)) { |
| | | sb.append(symbol); |
| | | c = Character.toLowerCase(c); |
| | | } |
| | | } else if (null == nextChar || Character.isLowerCase(nextChar)) { |
| | | c = Character.toLowerCase(c); |
| | | } |
| | | } |
| | | |
| | | sb.append(c); |
| | | } |
| | | |
| | | return sb.toString(); |
| | | } |
| | | } |
| | | |
| | | public static String toCamelCase(CharSequence name) { |
| | | if (null == name) { |
| | | return null; |
| | | } else { |
| | | String name2 = name.toString(); |
| | | if (name2.contains("_")) { |
| | | int length = name2.length(); |
| | | StringBuilder sb = new StringBuilder(length); |
| | | boolean upperCase = false; |
| | | |
| | | for(int i = 0; i < length; ++i) { |
| | | char c = name2.charAt(i); |
| | | if (c == '_') { |
| | | upperCase = true; |
| | | } else if (upperCase) { |
| | | sb.append(Character.toUpperCase(c)); |
| | | upperCase = false; |
| | | } else { |
| | | sb.append(Character.toLowerCase(c)); |
| | | } |
| | | } |
| | | |
| | | return sb.toString(); |
| | | } else { |
| | | return name2; |
| | | } |
| | | } |
| | | } |
| | | |
| | | public static String sub(String str, Integer maxLen) { |
| | | if (str.length() > maxLen) { |
| | | return str.substring(0, maxLen); |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | public static String generateSeqNum(String lastSeqNum) { |
| | | if (Cools.isEmpty(lastSeqNum)) { |
| | | return zeroFill("1", 4); |
| | | } else { |
| | | int i = Integer.parseInt(lastSeqNum); |
| | | if (i >= 9999) { |
| | | return zeroFill("1", 4); |
| | | } else { |
| | | return zeroFill(String.valueOf(i+1), 4); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // pos start in 0 |
| | | public static boolean getBit(byte b, int position) { |
| | | if (position < 0 || position > 7) { |
| | | throw new IllegalArgumentException("Bit position must be between 0 and 7"); |
| | | } |
| | | int mask = 1 << position; |
| | | return (b & mask) != 0; |
| | | } |
| | | |
| | | public static <T> List<T> singletonList(T o) { |
| | | List<T> list = new ArrayList<>(); |
| | | list.add(o); |
| | | return list; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.example.agvcontroller.protocol; |
| | | |
| | | import io.netty.buffer.ByteBuf; |
| | | |
| | | /** |
| | | * 校验工具类 |
| | | * Created by vincent on 2019-04-03 |
| | | */ |
| | | public class ValidUtil { |
| | | |
| | | public static final Integer MAX_DEFAULT = 65531; |
| | | |
| | | /** |
| | | * 校验消息中数值是否在对应允许的范围内 |
| | | * @param item 被校验数据值 |
| | | * @param min 允许的最小值 |
| | | * @param max 允许的最大值 |
| | | */ |
| | | public static boolean rangeValid(int item, int min, int max) { |
| | | return !(item < min || item > max); |
| | | } |
| | | |
| | | /** |
| | | * 异或校验包完整 |
| | | * 从命令单元(第三个字节)开始,一次与后一个字节异或,直至倒数第二个字节。 |
| | | * 将异或的结果与报文中最后一个字节比较。 |
| | | * -相等:报文完整 |
| | | * -不相等:报文不完整 |
| | | */ |
| | | public static boolean validPac(AgvPackage pac) { |
| | | ByteBuf buf = pac.getSourceBuff(); |
| | | return getValdByteInMsg(pac) == calculateValidByteFromBuff(buf); |
| | | } |
| | | |
| | | /** |
| | | * 从当前数据包计算校验码 |
| | | */ |
| | | public static int calculateValidByteFromBuff(ByteBuf buf) { |
| | | buf.resetReaderIndex(); |
| | | byte[] bytes = new byte[buf.readableBytes() - PackagePart.VALIDE_CODE.getLen()]; |
| | | buf.readBytes(bytes); |
| | | int currValidByte = CRCUtils.crc16(bytes); |
| | | // 重置读指针 |
| | | buf.resetReaderIndex(); |
| | | return currValidByte; |
| | | } |
| | | |
| | | /** |
| | | * 获取当前数据包中的校验码(最后一位字节) |
| | | */ |
| | | public static int getValdByteInMsg(AgvPackage pac) { |
| | | return pac.getValidCode(); |
| | | } |
| | | |
| | | } |