From 5bdad72f5d5077ca875dd03cfdaafb3d7aba93da Mon Sep 17 00:00:00 2001 From: whycq <913841844@qq.com> Date: 星期五, 16 八月 2024 14:36:58 +0800 Subject: [PATCH] # --- app/src/main/java/com/example/agvcontroller/action/RedisConstant.java | 38 ++++ app/src/main/java/com/example/agvcontroller/action/AckMsgBuilder.java | 44 +++++ app/src/main/java/com/example/agvcontroller/protocol/AGV_A1_DOWN.java | 16 ++ app/src/main/java/com/example/agvcontroller/action/CommonConstant.java | 10 + app/src/main/java/com/example/agvcontroller/MainActivity.java | 34 ++++ app/src/main/java/com/example/agvcontroller/action/AGV_11_UP.java | 115 ++++++++++++++ app/src/main/java/com/example/agvcontroller/met/AbstractInboundHandler.java | 36 ++++ app/src/main/java/com/example/agvcontroller/socket/NettyServerHandler.java | 89 ++++++++-- app/src/main/java/com/example/agvcontroller/action/AgvCompleteType.java | 53 ++++++ app/src/main/java/com/example/agvcontroller/socket/NettyServer.java | 2 app/build.gradle | 1 11 files changed, 415 insertions(+), 23 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index ef29b47..7dcae09 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -37,6 +37,7 @@ androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' implementation 'org.greenrobot:eventbus:3.2.0' + implementation 'redis.clients:jedis:3.0.1' implementation 'androidx.recyclerview:recyclerview:1.3.0' implementation 'io.netty:netty-all:4.1.68.Final' diff --git a/app/src/main/java/com/example/agvcontroller/MainActivity.java b/app/src/main/java/com/example/agvcontroller/MainActivity.java index 72f66e2..b08e87c 100644 --- a/app/src/main/java/com/example/agvcontroller/MainActivity.java +++ b/app/src/main/java/com/example/agvcontroller/MainActivity.java @@ -23,10 +23,16 @@ import com.example.agvcontroller.utils.SnowflakeIdWorker; import java.net.Socket; +import java.sql.Time; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeoutException; public class MainActivity extends AppCompatActivity { + + public static final Map<String, Object> map = new ConcurrentHashMap(); private RecyclerView recyclerView; private ItemAdapter itemAdapter; @@ -45,22 +51,46 @@ private boolean isDowm = false; private boolean isOpen = false; - String substring = String.valueOf(new SnowflakeIdWorker().nextId()).substring(0,16); + private Handler handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { if (isDowm) { + String substring = String.valueOf(new SnowflakeIdWorker().nextId()).substring(0,16); AgvAction agvAction = new AgvAction<>(ForceSwitchAction.class) .setAgvNo("1") .setSerialNo(substring) .setVal(1) .bodySync((action) -> action.setPwd((short) 21)); + nettyServerHandler.sendMessageToClient(clientId, agvAction); // 鍙戦�佹秷鎭埌瀹㈡埛绔� handler.sendEmptyMessageDelayed(0, 100); + + boolean result = false; + long timestamp = System.currentTimeMillis(); + + while (System.currentTimeMillis() - timestamp < 5000) { + + Object o = map.get(substring); + + if (null != o) { + result = true; + map.remove(o); + break; + } + } + + if (result) { + // alert ok + } else { + throw new TimeoutException("瓒呮椂"); + } + } if (isOpen) { + String substring = String.valueOf(new SnowflakeIdWorker().nextId()).substring(0,16); AgvAction agvAction = new AgvAction<>(ForceSwitchAction.class) .setAgvNo("12") .setSerialNo(substring) @@ -99,7 +129,7 @@ if (vibrator != null && vibrator.hasVibrator()) { vibrator.vibrate(500); } - + String substring = String.valueOf(new SnowflakeIdWorker().nextId()).substring(0,16); AgvAction agvAction = new AgvAction<>(HandOutAction.class) .setAgvNo("12") .setSerialNo(substring) diff --git a/app/src/main/java/com/example/agvcontroller/action/AGV_11_UP.java b/app/src/main/java/com/example/agvcontroller/action/AGV_11_UP.java new file mode 100644 index 0000000..67fb01b --- /dev/null +++ b/app/src/main/java/com/example/agvcontroller/action/AGV_11_UP.java @@ -0,0 +1,115 @@ +package com.example.agvcontroller.action; + +import com.example.agvcontroller.protocol.IMessageBody; +import com.example.agvcontroller.protocol.Utils; +import com.example.agvcontroller.socket.RadixTools; + +import java.io.Serializable; + +/** + * 鍔ㄤ綔瀹屾垚鏁版嵁鍖� + * + * Created by vincent on 2023/3/21 + */ +public class AGV_11_UP implements IMessageBody, Serializable { + + private static final long serialVersionUID = 8403019742104020004L; + + @Override + public byte[] writeToBytes() { + return new byte[0]; + } + + @Override + public void readFromBytes(byte[] bytes) { +// try { + this.serialNo = new String(Utils.sliceWithReverse(bytes, 0, 16)); +// } catch (UnsupportedEncodingException e) { +// e.printStackTrace(); +// } + this.completeCode = Utils.slice(bytes, 16, 1)[0]; + this.completeType = AgvCompleteType.query(this.completeCode); + this.qrCode = Utils.zeroFill(String.valueOf(RadixTools.bytesToInt(Utils.sliceWithReverse(bytes, 17, 4))), CommonConstant.QR_CODE_LEN); + this.direction = RadixTools.byteToShort(Utils.sliceWithReverse(bytes, 21,2)); +// this.locCode = new String(Utils.sliceWithReverse(bytes, 23, 16)).replaceAll("\\u0000", ""); +// this.boxCode = new String(Utils.sliceWithReverse(bytes, 39, 16)).replaceAll("\\u0000", ""); + this.locCode = Utils.zeroFill(String.valueOf(RadixTools.bytesToInt(Utils.sliceWithReverse(bytes, 23, 4))), CommonConstant.QR_CODE_LEN); + this.boxCode = Utils.zeroFill(String.valueOf(RadixTools.bytesToInt(Utils.sliceWithReverse(bytes, 39, 4))), CommonConstant.QR_CODE_LEN); + } + + private String serialNo; + + // 瀹屾垚鍔ㄤ綔鐮� + private int completeCode; + + private AgvCompleteType completeType; + + // 鍦伴潰鐮� - 8浣� + private String qrCode; + + // 杞﹀ご鏈濆悜 + private short direction; + + // 璐т綅浜岀淮鐮� + private String locCode; + + public String getSerialNo() { + return serialNo; + } + + public void setSerialNo(String serialNo) { + this.serialNo = serialNo; + } + + public int getCompleteCode() { + return completeCode; + } + + public void setCompleteCode(int completeCode) { + this.completeCode = completeCode; + } + + public AgvCompleteType getCompleteType() { + return completeType; + } + + public void setCompleteType(AgvCompleteType completeType) { + this.completeType = completeType; + } + + public String getQrCode() { + return qrCode; + } + + public void setQrCode(String qrCode) { + this.qrCode = qrCode; + } + + public short getDirection() { + return direction; + } + + public void setDirection(short direction) { + this.direction = direction; + } + + public String getLocCode() { + return locCode; + } + + public void setLocCode(String locCode) { + this.locCode = locCode; + } + + public String getBoxCode() { + return boxCode; + } + + public void setBoxCode(String boxCode) { + this.boxCode = boxCode; + } + + // 鏂欑浜岀淮鐮� + private String boxCode; + +} diff --git a/app/src/main/java/com/example/agvcontroller/action/AckMsgBuilder.java b/app/src/main/java/com/example/agvcontroller/action/AckMsgBuilder.java new file mode 100644 index 0000000..e86e3c0 --- /dev/null +++ b/app/src/main/java/com/example/agvcontroller/action/AckMsgBuilder.java @@ -0,0 +1,44 @@ +package com.example.agvcontroller.action; + +import com.example.agvcontroller.protocol.AgvPackage; +import com.example.agvcontroller.protocol.ProtocolType; +import com.example.agvcontroller.protocol.ProtocolUtils; + +import java.util.logging.Logger; + +import io.netty.buffer.ByteBuf; + +/** + * 搴旂瓟鎶ユ枃寤洪�犺�� + * Created by vincent on 2019-04-04 + */ +public class AckMsgBuilder { + +// private static final Logger log = LoggerFactory.getLogger(AckMsgBuilder.class); + + /** + * 鎴愬姛搴旂瓟 + * @return ByteBuf + */ + public static AgvPackage ofSuccess(AgvPackage original, ProtocolType ackType) { + + + return ProtocolUtils.installDownProtocol( + + original.getHeader().getUniqueNo() + + , ackType + ); + + } + + /** + * 澶辫触搴旂瓟 + * @return ByteBuf + */ + public static ByteBuf ofFail(ByteBuf sourceBuff) { + return sourceBuff; + } + + +} diff --git a/app/src/main/java/com/example/agvcontroller/action/AgvCompleteType.java b/app/src/main/java/com/example/agvcontroller/action/AgvCompleteType.java new file mode 100644 index 0000000..f274222 --- /dev/null +++ b/app/src/main/java/com/example/agvcontroller/action/AgvCompleteType.java @@ -0,0 +1,53 @@ +package com.example.agvcontroller.action; + +/** + * Agv鍔ㄤ綔瀹屾垚绫诲瀷 + */ +public enum AgvCompleteType { + + COMMON_COMPLETE(0x01, "鍒濆鍖栬嚜妫�鎴栬鍔ㄦ煡璇㈠畬鎴�"), + + STRAIGHT_COMPLETE(0x02, "鐩磋璺緞瀹屾垚"), + + TURN_CORNER_COMPLETE(0x03, "杞集瀹屾垚"), + + RETURN_ZERO_OF_ROTATE_TELESCOPIC_COMPLETE(0x04, "鏃嬭浆浼哥缉褰掗浂瀹屾垚"), + + TAKE_FROM_STORAGE_COMPLETE(0x05, "浠庢枡浠撳彇璐у畬鎴�"), + + RELEASE_FROM_STORAGE_COMPLETE(0x06, "寰�鏂欎粨鏀捐揣瀹屾垚"), + + TAKE_FROM_SHELVES_COMPLETE(0x07, "浠庤揣鏋跺彇璐у畬鎴�"), + + RELEASE_FROM_SHELVES_COMPLETE(0x08, "寰�璐ф灦鏀捐揣瀹屾垚"), + + SCAN_COMPLETE(0x09, "鎵弿璐ф灦鍜屾枡绠卞畬鎴�"), + + DOCKING_CHARGE_COMPLETE(0x0C, "鍏呯數瀵规帴瀹屾垚"), + + FULL_CHARGE_COMPLETE(0x0D, "鍏呮弧鐢�"), + + STOP_RECENT_CODE_COMPLETE(0x0E, "鍋滃埌鏈�杩戜簩缁寸爜瀹屾垚"), + + ENTIRE_PATH_COMPLETE(0x0F, "鏁翠釜璺緞鎵ц瀹屾垚"), + + ; + + private int code; + private String desc; + + AgvCompleteType(int code, String desc) { + this.code = code; + this.desc = desc; + } + + public static AgvCompleteType query(int completeCode) { + for (AgvCompleteType type : AgvCompleteType.values()) { + if (completeCode == type.code) { + return type; + } + } + return null; + } + +} diff --git a/app/src/main/java/com/example/agvcontroller/action/CommonConstant.java b/app/src/main/java/com/example/agvcontroller/action/CommonConstant.java new file mode 100644 index 0000000..048ea67 --- /dev/null +++ b/app/src/main/java/com/example/agvcontroller/action/CommonConstant.java @@ -0,0 +1,10 @@ +package com.example.agvcontroller.action; + +/** + * Created by vincent on 2023/3/29 + */ +public class CommonConstant { + + public static final int QR_CODE_LEN = 8; + +} diff --git a/app/src/main/java/com/example/agvcontroller/action/RedisConstant.java b/app/src/main/java/com/example/agvcontroller/action/RedisConstant.java new file mode 100644 index 0000000..e84b232 --- /dev/null +++ b/app/src/main/java/com/example/agvcontroller/action/RedisConstant.java @@ -0,0 +1,38 @@ +package com.example.agvcontroller.action; + +/** + * Created by vincent on 2023/3/14 + */ +public class RedisConstant { + + public static final String AGV_CMD_DOWN_FLAG = "AGV_CMD_DOWN_FLAG"; + + public static final String AGV_CMD_UP_FLAG = "AGV_CMD_UP_FLAG"; + + public static final String AGV_ONLINE_FLAG = "AGV_ONLINE_FLAG"; + + public static final String AGV_COMPLETE_FLAG = "AGV_COMPLETE_FLAG"; + + public static final String AGV_DATA_FLAG = "AGV_DATA_FLAG"; + + public static final String AGV_FAULT_REPORT_FLAG = "AGV_FAULT_REPORT_FLAG"; + + public static final String DIGITAL_AGV_FLAG = "DIGITAL_AGV_FLAG"; + + public static final int CMD_TIMEOUT_LIMIT = 5000; + + public static final String AGV_MAP_ASTAR_FLAG = "AGV_MAP_ASTAR_FLAG"; + + public static final String AGV_MAP_ASTAR_CODE_FLAG = "AGV_MAP_ASTAR_CODE_FLAG"; + + public static final String AGV_MAP_ASTAR_TURN_FLAG = "AGV_MAP_ASTAR_TURN_FLAG"; + + public static final String AGV_MAP_ASTAR_CDA_FLAG = "AGV_MAP_ASTAR_CDA_FLAG"; + + public static final String AGV_MAP_ASTAR_DYNAMIC_FLAG = "AGV_MAP_ASTAR_DYNAMIC_FLAG"; + + public static final String AGV_MAP_ASTAR_WAVE_FLAG = "AGV_MAP_ASTAR_WAVE_FLAG"; + + public static final String AGV_TRAFFIC_JAM_FLAG = "AGV_TRAFFIC_JAM_FLAG"; + +} diff --git a/app/src/main/java/com/example/agvcontroller/met/AbstractInboundHandler.java b/app/src/main/java/com/example/agvcontroller/met/AbstractInboundHandler.java new file mode 100644 index 0000000..7fd263e --- /dev/null +++ b/app/src/main/java/com/example/agvcontroller/met/AbstractInboundHandler.java @@ -0,0 +1,36 @@ +package com.example.agvcontroller.met; + +import com.example.agvcontroller.protocol.AgvPackage; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.util.ReferenceCountUtil; + +/** + * netty handler澧炲己鍣� + * 璁捐妯″紡: 閫傞厤鍣ㄦā寮� + * Created by vincent on 2019-04-06 + */ +public abstract class AbstractInboundHandler<T> extends ChannelInboundHandlerAdapter { + + @Override + public void channelRead(ChannelHandlerContext ctx, Object obj) throws Exception { + @SuppressWarnings("unchecked") + T t = (T) obj; + if (channelRead0(ctx, t)) { + ctx.fireChannelRead(t); + } else { + // 绠¢亾涓柇锛宖ireChannelRead鏈墽琛岋紝闇�瑕佹墜鍔ㄩ噴鏀惧爢澶栧唴瀛� + if (obj instanceof AgvPackage){ + AgvPackage pac = (AgvPackage) obj; + if (pac.getSourceBuff().refCnt() > 0) { + pac.getSourceBuff().skipBytes(pac.getSourceBuff().readableBytes()); + ReferenceCountUtil.release(pac.getSourceBuff()); + } + } + } + } + + protected abstract boolean channelRead0(ChannelHandlerContext ctx, T t) throws Exception; + +} diff --git a/app/src/main/java/com/example/agvcontroller/protocol/AGV_A1_DOWN.java b/app/src/main/java/com/example/agvcontroller/protocol/AGV_A1_DOWN.java index 7cdfe5d..b51952f 100644 --- a/app/src/main/java/com/example/agvcontroller/protocol/AGV_A1_DOWN.java +++ b/app/src/main/java/com/example/agvcontroller/protocol/AGV_A1_DOWN.java @@ -21,6 +21,22 @@ } + public byte getAckSign() { + return ackSign; + } + + public void setAckSign(byte ackSign) { + this.ackSign = ackSign; + } + + public byte[] getTemp() { + return temp; + } + + public void setTemp(byte[] temp) { + this.temp = temp; + } + private byte ackSign = 0x11; private byte[] temp = new byte[4]; diff --git a/app/src/main/java/com/example/agvcontroller/socket/NettyServer.java b/app/src/main/java/com/example/agvcontroller/socket/NettyServer.java index 1f91141..278bac0 100644 --- a/app/src/main/java/com/example/agvcontroller/socket/NettyServer.java +++ b/app/src/main/java/com/example/agvcontroller/socket/NettyServer.java @@ -35,7 +35,7 @@ .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { - ch.pipeline().addLast(new NettyServerHandler()).addLast(new ProtocolEncoder()); + ch.pipeline().addLast(new ProtocolEncoder()).addLast(new ProtocolDecoder(4096)).addLast(new NettyServerHandler()); } }) // .addLast(new NettyServerHandler()) diff --git a/app/src/main/java/com/example/agvcontroller/socket/NettyServerHandler.java b/app/src/main/java/com/example/agvcontroller/socket/NettyServerHandler.java index 1bcb965..f27d329 100644 --- a/app/src/main/java/com/example/agvcontroller/socket/NettyServerHandler.java +++ b/app/src/main/java/com/example/agvcontroller/socket/NettyServerHandler.java @@ -1,30 +1,34 @@ package com.example.agvcontroller.socket; -import java.nio.charset.StandardCharsets; + import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; import android.util.Log; import com.example.agvcontroller.Item; +import com.example.agvcontroller.MainActivity; +import com.example.agvcontroller.action.AGV_11_UP; +import com.example.agvcontroller.action.AckMsgBuilder; +import com.example.agvcontroller.met.AbstractInboundHandler; +import com.example.agvcontroller.protocol.AGV_A1_DOWN; import com.example.agvcontroller.protocol.AgvAction; +import com.example.agvcontroller.protocol.AgvPackage; +import com.example.agvcontroller.protocol.ProtocolType; import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; -import java.util.Arrays; import java.util.concurrent.ConcurrentHashMap; -public class NettyServerHandler extends ChannelInboundHandlerAdapter { +public class NettyServerHandler extends AbstractInboundHandler<AgvPackage> { private static final String TAG = "NettyServerHandler"; private static ConcurrentHashMap<String, Channel> channelMap = new ConcurrentHashMap<>(); + @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { @@ -42,22 +46,53 @@ Log.d(TAG, "Client disconnected: " + clientId); } +// @Override +// public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { +// // 澶勭悊鎺ユ敹鍒扮殑娑堟伅 +// ByteBuf byteBuf = (ByteBuf) msg; +// try { +// while (byteBuf.isReadable()) { +// byte[] bytes = new byte[byteBuf.readableBytes()]; +// byteBuf.readBytes(bytes); +// String hexString = bytesToHex(bytes); +// // 鑾峰彇agv淇℃伅 娣诲姞鍒發ist涓� +// Log.d(TAG, "ctx: " + ctx.channel().remoteAddress().toString() ); +// Log.d(TAG, "Received: " + hexString); +// } +// } finally { +// byteBuf.release(); +// } +// } + @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - // 澶勭悊鎺ユ敹鍒扮殑娑堟伅 - ByteBuf byteBuf = (ByteBuf) msg; - try { - while (byteBuf.isReadable()) { - byte[] bytes = new byte[byteBuf.readableBytes()]; - byteBuf.readBytes(bytes); - String hexString = bytesToHex(bytes); - // 鑾峰彇agv淇℃伅 娣诲姞鍒發ist涓� - Log.d(TAG, "ctx: " + ctx.channel().remoteAddress().toString() ); - Log.d(TAG, "Received: " + hexString); - } - } finally { - byteBuf.release(); + protected boolean channelRead0(ChannelHandlerContext ctx, AgvPackage pac) throws Exception { + + String serialNum = pac.getHeader().getSerialNum(); + // ack + ProtocolType ackType = isNeedAck(pac); + final String uniqueNo = pac.getHeader().getUniqueNo(); + label : switch (pac.getHeader().getProtocolType()){ + case ACTION_COMPLETE: // 鍔ㄤ綔瀹屾垚鏁版嵁鍖� + + + AGV_11_UP agv_11_up = (AGV_11_UP) pac.getBody().getMessageBody(); +// redis.push(RedisConstant.AGV_COMPLETE_FLAG, AgvProtocol.build(uniqueNo).setMessageBody(agv_11_up)); + + // 鍔ㄤ綔瀹屾垚搴旂瓟 + if (null != ackType) { + AgvPackage ackPac = AckMsgBuilder.ofSuccess(pac, ackType); + + AGV_A1_DOWN agv_a1_down = (AGV_A1_DOWN) ackPac.getBody().getMessageBody(); + agv_a1_down.setAckSign((byte) agv_11_up.getCompleteCode()); + + ctx.writeAndFlush(ackPac); + } + + MainActivity.map.put(serialNum, Boolean.TRUE); + + break label; } + return false; } private String bytesToHex(byte[] bytes) { @@ -109,4 +144,18 @@ ctx.close(); } + /** + * 鏈嶅姟鍣ㄦ槸鍚﹂渶瑕佸簲绛� + */ + public static ProtocolType isNeedAck(AgvPackage pac) { + switch (pac.getHeader().getProtocolType()) { + case ACTION_COMPLETE: + return ProtocolType.ACTION_SUCCESS_ACK; + case LOGIN_REPORT: + return ProtocolType.LOGIN_ACK; + default: + return null; + } + } + } -- Gitblit v1.9.1