#
whycq
2024-08-17 20245e35da8a9d809b2de91f4ec29dd39127f9d5
#
12个文件已修改
3个文件已添加
373 ■■■■■ 已修改文件
app/src/main/java/com/example/agvcontroller/MainActivity.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/StartActivity.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/AGV_01_DOWN.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/AGV_02_DOWN.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/AGV_02_UP.java 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/AGV_03_DOWN.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/AGV_80_DOWN.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/AGV_A1_DOWN.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/AGV_F0_DOWN.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/IMessageBody.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/MessageBodyHandler.java 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/PackagePart.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/socket/NettyServer.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/socket/NettyServerHandler.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/utils/DialogUtil.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/MainActivity.java
@@ -20,14 +20,13 @@
import com.example.agvcontroller.action.HandOutAction;
import com.example.agvcontroller.socket.NettyServerHandler;
import com.example.agvcontroller.socket.SocketManager;
import com.example.agvcontroller.utils.DialogUtil;
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 {
@@ -44,6 +43,7 @@
    private Button rotatopnLeftBtn;  // 左旋转
    private Button goForwardBtn;  // 前进
    private Button goBackwardBtn;  // 后退
    private Button modelSwitchBtn;  // 进入、退出 手动
    private Socket socket;
    SocketManager socketManager;
@@ -68,25 +68,7 @@
                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) {
@@ -117,12 +99,13 @@
        forceSwitchBtn = findViewById(R.id.btn_force_switch);
        goForwardBtn = findViewById(R.id.btn_go_forward);
        goBackwardBtn = findViewById(R.id.btn_go_backward);
        modelSwitchBtn = findViewById(R.id.btn_model_switch);
        Intent intent = getIntent();
        clientId = intent.getStringExtra("message");
        Log.i("message1",clientId);
        // 进出手动模式
        // 强制模式开关
        forceSwitchBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
@@ -138,6 +121,47 @@
                nettyServerHandler.sendMessageToClient(clientId, agvAction); // 发送消息到客户端
            }
        });
        // 强制模式开关
        modelSwitchBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                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)
                        .setVal(1)
                        .bodySync((action) -> action.setPwd((short) 21));
                nettyServerHandler.sendMessageToClient(clientId, agvAction); // 发送消息到客户端
                boolean result = false;
                long timestamp = System.currentTimeMillis();
                Log.i("substring",substring);
                while (System.currentTimeMillis() - timestamp < 20000) {
                    Object o = map.get(substring);
                    if (null != o) {
                        result = true;
                        map.remove(o);
                        break;
                    }
                }
                if (result) {
                    // alert ok  修改按钮样式 名称
                    modelSwitchBtn.setText("自动模式");
                } else {
//                    throw new TimeoutException("超时");
                    DialogUtil.showAlertDialog(MainActivity.this, "提示", "请求应答超时!");
                }
            }
        });
        stopBtn.setOnTouchListener(new CarTouchButton());
        goForwardBtn.setOnTouchListener(new CarTouchButton());
        goBackwardBtn.setOnTouchListener(new CarTouchButton());
app/src/main/java/com/example/agvcontroller/StartActivity.java
@@ -52,7 +52,7 @@
            }
        });
        socketManager = new SocketManager();
        socketManager.startServer(8080);
        socketManager.startServer(8081);
    }
    @Subscribe(threadMode = ThreadMode.MAIN)
app/src/main/java/com/example/agvcontroller/protocol/AGV_01_DOWN.java
@@ -38,6 +38,9 @@
    }
    public String getSerialNo() {
        return serialNo;
    }
    // 流水号 - 16
    private String serialNo;
app/src/main/java/com/example/agvcontroller/protocol/AGV_02_DOWN.java
@@ -1,6 +1,10 @@
package com.example.agvcontroller.protocol;
import com.example.agvcontroller.action.AgvCompleteType;
import com.example.agvcontroller.action.CommonConstant;
import com.example.agvcontroller.socket.RadixTools;
import java.io.Serializable;
/**
@@ -27,7 +31,13 @@
    @Override
    public void readFromBytes(byte[] messageBodyBytes) {
        try {
            this.serialNo = new String(Utils.sliceWithReverse(messageBodyBytes, 0, 16));
            this.cmdCode = Utils.slice(messageBodyBytes, 16, 1)[0];
        } catch (Exception e) {
        }
    }
    // 流水号 - 16
app/src/main/java/com/example/agvcontroller/protocol/AGV_02_UP.java
New file
@@ -0,0 +1,115 @@
package com.example.agvcontroller.protocol;
import com.example.agvcontroller.action.AgvCompleteType;
import com.example.agvcontroller.action.CommonConstant;
import com.example.agvcontroller.socket.RadixTools;
import java.io.Serializable;
/**
 * 动作完成数据包
 *
 * Created by vincent on 2023/3/21
 */
public class AGV_02_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;
}
app/src/main/java/com/example/agvcontroller/protocol/AGV_03_DOWN.java
@@ -20,4 +20,8 @@
    }
    public String getSerialNo() {
        return "";
    }
}
app/src/main/java/com/example/agvcontroller/protocol/AGV_80_DOWN.java
@@ -21,4 +21,8 @@
    }
    public String getSerialNo() {
        return "";
    }
}
app/src/main/java/com/example/agvcontroller/protocol/AGV_A1_DOWN.java
@@ -41,4 +41,8 @@
    private byte[] temp = new byte[4];
    public String getSerialNo() {
        return "";
    }
}
app/src/main/java/com/example/agvcontroller/protocol/AGV_F0_DOWN.java
@@ -28,5 +28,9 @@
    private byte[] temp = new byte[4];
    public String getSerialNo() {
        return "";
    }
}
app/src/main/java/com/example/agvcontroller/protocol/IMessageBody.java
@@ -8,4 +8,6 @@
    void readFromBytes(byte[] messageBodyBytes);
    String getSerialNo();
}
app/src/main/java/com/example/agvcontroller/protocol/MessageBodyHandler.java
New file
@@ -0,0 +1,115 @@
package com.example.agvcontroller.protocol;
import com.example.agvcontroller.met.AbstractInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
/**
 * 报文主体handler
 * Created by vincent on 2023-03-15
 */
//@Component("messageBodyHandler")
@ChannelHandler.Sharable
public class MessageBodyHandler extends AbstractInboundHandler<AgvPackage> {
    private static final Logger log = LoggerFactory.getLogger(MessageBodyHandler.class);
    @Override
    @SuppressWarnings("all")
    protected boolean channelRead0(ChannelHandlerContext ctx, AgvPackage pac) {
        String namespace = IMessageBody.class.getPackage().getName();
        ProtocolType protocolType = pac.getHeader().getProtocolType();
        if (null == protocolType) {
            // 未知包
            return Boolean.FALSE;
        }
        String className =  namespace +  ".AGV_" + Utils.zeroFill(Integer.toHexString(protocolType.getCode()).toUpperCase(), 2)
                +"_"
                +  pac.getHeader().getProtocolType().getDirection().toString().toUpperCase();
        Class<?> cls = null;
        try {
            cls  =   Class.forName(className);;
        } catch (ClassNotFoundException e) {
            log.error("MessageBodyHandler ClassNotFoundException", e);log.error("找不到指定类:{}", className);
            return Boolean.FALSE;
        }
        Object obj = null;
        if (null != cls) {
            try {
                obj = cls.newInstance();
            } catch (ReflectiveOperationException reflectiveOperationException) {
                log.error("MessageBodyHandler ReflectiveOperationException", reflectiveOperationException);
                log.error("java反射创建实例失败:{}", className);
                // 。。。
                return Boolean.FALSE;
            }
        }
        ByteBuf contentBuf = pac.getBody().getContent();           contentBuf.markReaderIndex();   // sign
        // body.buf 属于切片获取, slice 与 channel中的缓冲区 为同一 refenec
            contentBuf.resetReaderIndex();
        int len= contentBuf.readableBytes();
        byte[] bytes = new byte[len];
        pac.getBody().getContent().readBytes(bytes);
        // 读取字节数组 ===>>     实际报文类型
        IMessageBody iMessageBody = null;
        if (null != obj) {
            if ( obj  instanceof IMessageBody) {
                iMessageBody = (IMessageBody) obj;
                    iMessageBody.readFromBytes(bytes);
            }
        }
        pac.getBody().setMessageBody(iMessageBody);     contentBuf.resetReaderIndex();
        return true;
    }
}
app/src/main/java/com/example/agvcontroller/protocol/PackagePart.java
@@ -36,6 +36,11 @@
    COMMAND_MARK(11, 1, "命令标识"),
    /**
     * 流水号
     */
    SERIAL_NUM(13, 16, "流水号"),
    /**
     * 数据单元
     */
    CONTENT(12, -1, "数据单元"),
app/src/main/java/com/example/agvcontroller/socket/NettyServer.java
@@ -1,5 +1,6 @@
package com.example.agvcontroller.socket;
import com.example.agvcontroller.protocol.MessageBodyHandler;
import com.example.agvcontroller.protocol.ProtocolDecoder;
import com.example.agvcontroller.protocol.ProtocolEncoder;
@@ -35,7 +36,10 @@
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new ProtocolEncoder()).addLast(new ProtocolDecoder(4096)).addLast(new NettyServerHandler());
                            ch.pipeline().addLast(new ProtocolEncoder())
                                    .addLast(new ProtocolDecoder(4096))
                                    .addLast(new MessageBodyHandler())
                                    .addLast(new NettyServerHandler());
                        }
                    })
//                    .addLast(new NettyServerHandler())
app/src/main/java/com/example/agvcontroller/socket/NettyServerHandler.java
@@ -67,7 +67,9 @@
    @Override
    protected boolean channelRead0(ChannelHandlerContext ctx, AgvPackage pac) throws Exception {
        String serialNum = pac.getHeader().getSerialNum();
        String serialNum = pac.getBody().getMessageBody().getSerialNo();
        Log.i("substring",serialNum);
        MainActivity.map.put(serialNum, Boolean.TRUE);
        // ack
        ProtocolType ackType = isNeedAck(pac);
        final String uniqueNo = pac.getHeader().getUniqueNo();
@@ -88,7 +90,7 @@
                    ctx.writeAndFlush(ackPac);
                }
                MainActivity.map.put(serialNum, Boolean.TRUE);
                break label;
        }
app/src/main/java/com/example/agvcontroller/utils/DialogUtil.java
New file
@@ -0,0 +1,27 @@
package com.example.agvcontroller.utils;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
public class DialogUtil {
    public static void showAlertDialog(Context context, String title, String message) {
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle(title)
                .setMessage(message)
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                })
                .show();
    }
}