.idea/.name
New file @@ -0,0 +1 @@ AGVController app/src/main/java/com/example/agvcontroller/MainActivity.java
@@ -15,6 +15,8 @@ import android.view.View; import android.widget.Button; import com.example.agvcontroller.protocol.AgvAction; import com.example.agvcontroller.protocol.ForceSwitchAction; import com.example.agvcontroller.protocol2.AgvPackage; import com.example.agvcontroller.protocol2.PackagePart; import com.example.agvcontroller.socket.NettyServerHandler; @@ -43,11 +45,21 @@ private Handler handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { AgvAction agvAction = new AgvAction<>(ForceSwitchAction.class) .setAgvNo("1") .setSerialNo("asdsadsadsad") .setVal(1) .bodySync((action) -> action.setPwd((short) 21)); // 在这里进行打印输出 System.out.println("打印输出"); if (isDowm) { byte[] message2 = new byte[]{0x01, 0x02, 0x03, 0x06}; // 示例消息 nettyServerHandler.sendMessageToClient(clientId, message2); // 发送消息到客户端 System.out.println(agvAction); // byte[] message2 = new byte[]{0x01, 0x02, 0x03, 0x06}; // 示例消息 nettyServerHandler.sendMessageToClient(clientId, agvAction); // 发送消息到客户端 handler.sendEmptyMessageDelayed(0, 100); } return false; app/src/main/java/com/example/agvcontroller/StartActivity.java
@@ -52,7 +52,7 @@ } }); socketManager = new SocketManager(); socketManager.startServer(8024); socketManager.startServer(8022); } @Subscribe(threadMode = ThreadMode.MAIN) app/src/main/java/com/example/agvcontroller/protocol/AGV_02_DOWN.java
@@ -42,4 +42,35 @@ // 动作参数 private ICommandBody commandBody; public String getSerialNo() { return serialNo; } public void setSerialNo(String serialNo) { this.serialNo = serialNo; } public int getCmdCode() { return cmdCode; } public void setCmdCode(int cmdCode) { this.cmdCode = cmdCode; } public int getVal() { return val; } public void setVal(int val) { this.val = val; } public ICommandBody getCommandBody() { return commandBody; } public void setCommandBody(ICommandBody commandBody) { this.commandBody = commandBody; } } app/src/main/java/com/example/agvcontroller/protocol/AgvAction.java
New file @@ -0,0 +1,124 @@ package com.example.agvcontroller.protocol; import com.example.agvcontroller.socket.NettyServerHandler; import com.example.agvcontroller.socket.RadixTools; import org.json.JSONObject; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * Created by vincent on 2023/3/14 */ @SuppressWarnings("all") public class AgvAction<T extends IActionBody> implements Serializable { private static final long serialVersionUID = -1701520567284510548L; private String agvNo; private String serialNo; private int val; private T actionBody; private HandleCmdType handleCmdType; public byte[] writeToBytes() { // byte[] bytes = new String serialNo = Utils.zeroFill(this.serialNo, 16); byte[] serialNoBytes = Utils.reverse(serialNo.getBytes()); // 流水号 byte cmdCode = (byte) handleCmdType.cmdCode; // 命令码 byte valByte = (byte) val; // 属性值 byte[] bytes = actionBody.writeToBytes(); // 命令参数 return new byte[12]; } void readFromBytes(byte[] messageBodyBytes) { } public AgvAction(Class<T> clazz) { try { actionBody = clazz.newInstance(); } catch (Exception e) { e.printStackTrace(); } this.handleCmdType = HandleCmdType.find(actionBody.getClass()); if (null == handleCmdType) { throw new RuntimeException(clazz.getName() + "检索 HandleCmdType 枚举失败"); } } public AgvAction<T> setAgvNo(String agvNo) { this.agvNo = agvNo; return this; } public AgvAction<T> setSerialNo(String serialNo) { this.serialNo = serialNo; return this; } public AgvAction<T> bodySync(DataSupport<T> dataSupport) { dataSupport.sync(this.actionBody); return this; } public static void main(String[] args) { AgvAction agvAction = new AgvAction<>(ForceSwitchAction.class) .setAgvNo("1") .setSerialNo("asdsadsadsad") .setVal(1) .bodySync((action) -> action.setPwd((short) 21)); NettyServerHandler.sendMessageToClient("123213", agvAction); } public String getAgvNo() { return agvNo; } public String getSerialNo() { return serialNo; } public T getActionBody() { return actionBody; } public void setActionBody(T actionBody) { this.actionBody = actionBody; } public HandleCmdType getHandleCmdType() { return handleCmdType; } public void setHandleCmdType(HandleCmdType handleCmdType) { this.handleCmdType = handleCmdType; } public int getVal() { return val; } public AgvAction<T> setVal(int val) { this.val = val; return this; } } app/src/main/java/com/example/agvcontroller/protocol/AgvActionItem.java
New file @@ -0,0 +1,63 @@ package com.example.agvcontroller.protocol; import java.io.Serializable; /** * 路径包 - 路径点 * Created by vincent on 2023/3/14 */ //@Data public class AgvActionItem<T extends IActionBody> implements Serializable { private static final long serialVersionUID = -6988765550778795176L; // 地面码 private String qrCode; // 动作码 // private AgvActionCmdType actionCmdType; // 属性值 private int val; // 动作参数 private T actionBody; public AgvActionItem() { } // public AgvActionItem(Class<T> clazz) { // try { // actionBody = clazz.newInstance(); // } catch (Exception e) { // e.printStackTrace(); // } // this.actionCmdType = AgvActionCmdType.find(actionBody.getClass()); // if (null == actionCmdType) { // throw new CoolException(clazz.getName() + "检索 AgvActionCmdType 枚举失败"); // } // } public AgvActionItem<T> setQrCode(String qrCode) { this.qrCode = qrCode; return this; } // public AgvActionItem<T> setActionCmdType(AgvActionCmdType actionCmdType) { // this.actionCmdType = actionCmdType; // return this; // } public AgvActionItem<T> setVal(int val) { this.val = val; return this; } public AgvActionItem<T> bodySync(DataSupport<T> dataSupport) { dataSupport.sync(this.actionBody); return this; } } app/src/main/java/com/example/agvcontroller/protocol/DataSupport.java
New file @@ -0,0 +1,7 @@ package com.example.agvcontroller.protocol; public interface DataSupport<T> { void sync(T t); } app/src/main/java/com/example/agvcontroller/protocol/ForceSwitchAction.java
New file @@ -0,0 +1,28 @@ package com.example.agvcontroller.protocol; import java.io.Serializable; public class ForceSwitchAction implements IActionBody, Serializable { private static final long serialVersionUID = -3250235107705010316L; private Short pwd; @Override public byte[] writeToBytes() { return new byte[0]; } @Override public void readFromBytes(byte[] messageBodyBytes) { } public Short getPwd() { return pwd; } public void setPwd(Short pwd) { this.pwd = pwd; } } app/src/main/java/com/example/agvcontroller/protocol/HandleCmdType.java
New file @@ -0,0 +1,29 @@ package com.example.agvcontroller.protocol; public enum HandleCmdType { FORCE_SWITCH(0x80, "开启/关闭强制", ForceSwitchAction.class), ; public int cmdCode; public String desc; public Class<? extends IActionBody> cls; HandleCmdType(int cmdCode, String desc, Class<? extends IActionBody> cls) { this.cmdCode = cmdCode; this.desc = desc; this.cls = cls; } public static HandleCmdType find(Class<? extends IActionBody> cls) { for (HandleCmdType value : HandleCmdType.values()) { if (value.cls.equals(cls)) { return value; } } return null; } } app/src/main/java/com/example/agvcontroller/protocol/IActionBody.java
New file @@ -0,0 +1,12 @@ package com.example.agvcontroller.protocol; /** * 动作参数 */ public interface IActionBody { byte[] writeToBytes(); void readFromBytes(byte[] messageBodyBytes); } app/src/main/java/com/example/agvcontroller/protocol/ProtocolEncoder.java
@@ -1,5 +1,7 @@ package com.example.agvcontroller.protocol; import com.example.agvcontroller.socket.RadixTools; import java.util.logging.Logger; import io.netty.buffer.ByteBuf; @@ -32,6 +34,39 @@ } else if (obj instanceof byte[]){ out.writeBytes((byte[]) obj); } else if (obj instanceof AgvAction<?>){ AgvAction action = (AgvAction)obj; String uniqueNo = action.getAgvNo(); byte[] uniqueNoBytes = RadixTools.intToBytes(Integer.parseInt(uniqueNo)); // uniqueno byte[] bodyBytes = action.writeToBytes(); int len = PackagePart.UNIQUENO.getLen() // len + PackagePart.TIMESTAMP.getLen() + PackagePart.COMMAND_MARK.getLen() + bodyBytes.length; out.writeByte((byte)0xEE) // symbol .writeShortLE(len) .writeBytes(Utils.reverse(uniqueNoBytes)) // uniqueno .writeIntLE((int) (System.currentTimeMillis() / 1000)) // timestamp .writeByte(ProtocolPojoType.ACTION_COMMAND.protocolType.getCode()) // type .writeBytes(bodyBytes) // body .writeShort((short)0) // valid ; int validCode = ValidUtil.calculateValidByteFromBuff(out); out.resetReaderIndex(); out.writerIndex(out.readableBytes() - 2); out.writeShortLE(validCode); } else if (obj instanceof AgvPackage){ AgvPackage pac = (AgvPackage)obj; app/src/main/java/com/example/agvcontroller/socket/NettyServer.java
@@ -1,5 +1,7 @@ package com.example.agvcontroller.socket; import com.example.agvcontroller.protocol.ProtocolEncoder; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; @@ -32,9 +34,16 @@ .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new NettyServerHandler()); ch.pipeline().addLast(new NettyServerHandler()).addLast(new ProtocolEncoder()); } }) // .childHandler(new ChannelInitializer<Channel>(){ // // @Override // protected void initChannel(Channel ch) throws Exception { // ch.pipeline().addLast(new ProtocolEncoder()); // } // }) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); app/src/main/java/com/example/agvcontroller/socket/NettyServerHandler.java
@@ -11,6 +11,7 @@ import android.util.Log; import com.example.agvcontroller.Item; import com.example.agvcontroller.protocol.AgvAction; import org.greenrobot.eventbus.EventBus; @@ -89,6 +90,19 @@ } } public static void sendMessageToClient(String clientId, AgvAction<?> action) { Channel channel = channelMap.get(clientId); if (channel != null && channel.isActive()) { channel.writeAndFlush(action); } else { Log.d(TAG, "Client " + clientId + " is not connected"); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); app/src/main/java/com/example/agvcontroller/socket/RadixTools.java
New file @@ -0,0 +1,163 @@ package com.example.agvcontroller.socket; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; /** * radix tools * Created by vincent on 2018/10/6 */ public class RadixTools { public static void main(String[] args) { String s = RadixTools.toBinaryString((byte) 1); System.out.println(s); for(int i=s.length()-1;i>=0;i--){ char c=s.charAt(i); if (i == 7 && c =='1'){ System.out.println("==="); } } } /************************************** BinaryString **********************************************/ public static String toBinaryString(byte b){ return Long.toBinaryString((b & 0xFF) + 0x100).substring(1); } public static String toBinaryString(byte[] bytes){ StringBuilder sb = new StringBuilder(); for (byte aByte : bytes) { sb.append(Long.toBinaryString((aByte & 0xFF) + 0x100).substring(1)); } return sb.toString(); } /************************************** HexString **********************************************/ public static byte[] hexStringToBytes(String hexString) { if (hexString == null || hexString.equals("")) { return null; } hexString = hexString.toUpperCase(); int length = hexString.length() / 2; char[] hexChars = hexString.toCharArray(); byte[] d = new byte[length]; for (int i = 0; i < length; i++) { int pos = i * 2; d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])); } return d; } public static String bytesToHexStr(byte[] bytes){ StringBuilder buf = new StringBuilder(bytes.length * 2); for(byte b : bytes) { buf.append(String.format("%02x", b & 0xff)); } return buf.toString(); } private static byte charToByte(char c) { return (byte) "0123456789ABCDEF".indexOf(c); } /************************************** String **********************************************/ public static String bytesToStr(byte[] bytes){ return bytesToStr(bytes, Charset.forName("gbk")); } public static String bytesToStr(byte[] bytes, Charset charset){ return new String(bytes, charset).trim().toUpperCase(); } public static byte[] strToBytes(String str) throws UnsupportedEncodingException { return str.getBytes("gbk"); } /************************************** long **********************************************/ public static byte[] longToBytes(long number) { long temp = number; byte[] b = new byte[8]; for (int i = 0; i < b.length; i++) { b[i] = new Long(temp & 0xff).byteValue();// 将最低位保存在最低位 temp = temp >> 8; // 向右移8位 } return b; } public static long bytesToLong(byte[] bytes) { long s = 0; long s0 = bytes[0] & 0xff;// 最低位 long s1 = bytes[1] & 0xff; long s2 = bytes[2] & 0xff; long s3 = bytes[3] & 0xff; long s4 = bytes[4] & 0xff;// 最低位 long s5 = bytes[5] & 0xff; long s6 = bytes[6] & 0xff; long s7 = bytes[7] & 0xff; // s0不变 s1 <<= 8; s2 <<= 16; s3 <<= 24; s4 <<= 8 * 4; s5 <<= 8 * 5; s6 <<= 8 * 6; s7 <<= 8 * 7; s = s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7; return s; } /************************************** int **********************************************/ public static byte[] intToBytes(int n) { byte[] b = new byte[4]; b[3] = (byte) (n & 0xff); b[2] = (byte) (n >> 8 & 0xff); b[1] = (byte) (n >> 16 & 0xff); b[0] = (byte) (n >> 24 & 0xff); return b; } public static int bytesToInt(byte[] b) { int s = 0; int s0 = b[0] & 0xff;// 最低位 int s1 = b[1] & 0xff; int s2 = b[2] & 0xff; int s3 = b[3] & 0xff; s0 <<= 24; s1 <<= 16; s2 <<= 8; s = s0 | s1 | s2 | s3; return s; } /************************************** short **********************************************/ public static short byteToShort(byte[] b) { short s = 0; short s0 = (short) (b[1] & 0xff);// 最低位 short s1 = (short) (b[0] & 0xff); s1 <<= 8; s = (short) (s0 | s1); return s; } public static byte[] shortToByte(short s){ byte[] b = new byte[2]; for(int i = 0; i < 2; i++){ int offset = 16 - (i+1)*8; //因为byte占4个字节,所以要计算偏移量 b[i] = (byte)((s >> offset)&0xff); //把16位分为2个8位进行分别存储 } return b; } }