#
whycq
2025-02-07 dd170bf880918ce00a1df68e8a3c621ada9b5820
#
7个文件已添加
4个文件已修改
491 ■■■■ 已修改文件
app/src/main/java/com/example/agvcontroller/AGVApplication.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/LogActivity.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/MainActivity.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/action/LoginReset.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/AGV_03_UP.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/HandleCmdType.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/socket/NettyServerHandler.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/utils/ToDBC.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable/new_logo.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/activity_log.xml 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/activity_main.xml 218 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/AGVApplication.java
New file
@@ -0,0 +1,33 @@
package com.example.agvcontroller;
import android.app.Application;
import android.os.Handler;
import android.os.Looper;
import java.util.ArrayList;
import java.util.List;
public class AGVApplication extends Application {
    private static List<String> logList = new ArrayList<>();
    @Override
    public void onCreate() {
        super.onCreate();
    }
    @Override
    public void onTerminate() {
        super.onTerminate();
        // 清空日志列表
        logList.clear();
    }
    public static List<String> getLogList() {
        return logList;
    }
    public static void addLog(String log) {
        logList.add(log);
    }
}
app/src/main/java/com/example/agvcontroller/LogActivity.java
New file
@@ -0,0 +1,39 @@
package com.example.agvcontroller;
import static com.example.agvcontroller.utils.ToDBC.toDBC;
import android.os.Bundle;
import android.widget.TextView;
import java.util.List;
import androidx.appcompat.app.AppCompatActivity;
public class LogActivity extends AppCompatActivity {
    private TextView logTextView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_log);
        logTextView = findViewById(R.id.log_text_view);
        // 获取传递的日志数据
        List<String> logList = getIntent().getStringArrayListExtra("log_list");
        // 更新日志显示
        updateLogTextView(logList);
    }
    private void updateLogTextView(List<String> logList) {
        StringBuilder logBuilder = new StringBuilder();
        for (String log : logList) {
            logBuilder.append(log).append("\n");
        }
        logTextView.setText(toDBC(logBuilder.toString()));
    }
}
app/src/main/java/com/example/agvcontroller/MainActivity.java
@@ -36,6 +36,7 @@
import com.example.agvcontroller.action.HandLift;
import com.example.agvcontroller.action.LiftResetAction;
import com.example.agvcontroller.action.LoadResetAction;
import com.example.agvcontroller.action.LoginReset;
import com.example.agvcontroller.action.RotatopnLeftRight;
import com.example.agvcontroller.action.SingleSwitchAction;
import com.example.agvcontroller.action.SingleSwitchRunAction;
@@ -68,6 +69,7 @@
    private static final int MAX_RECENT_LOGS = 10; // 最多显示 10 条最新日志
    private static TextView agvBattery;
    private static TextView agvSocket;
    private static TextView agvNo;
    private static TextView agvStatus;
    private static TextView agvPositionId;
@@ -77,6 +79,7 @@
    private static TextView agvForkExtend;
    private static TextView agvForkAngle;
    private static TextView agvError;
    private Button reLogin;
@@ -406,6 +409,7 @@
        setContentView(R.layout.activity_main);
        agvBattery = findViewById(R.id.agv_battery);
        agvSocket = findViewById(R.id.socket);
        agvNo = findViewById(R.id.agv_no);
        agvStatus = findViewById(R.id.agv_status);
        agvPositionId = findViewById(R.id.agv_position_id);
@@ -415,6 +419,8 @@
        agvForkExtend = findViewById(R.id.agv_ford);
        agvForkAngle = findViewById(R.id.agv_ratio);
        agvError = findViewById(R.id.agv_error);
        reLogin = findViewById(R.id.relogin_button);
@@ -524,6 +530,18 @@
        Log.i("message1",clientId);
        reLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String substring = String.valueOf(new SnowflakeIdWorker().nextId()).substring(0,16);
                AgvAction agvAction = new AgvAction<>(LoginReset.class)
                        .setAgvNo(AgvNo)
                        .setSerialNo(substring)
                        .setVal(1)
                        .bodySync((action) -> action.setPwd((short) 1));
                nettyServerHandler.sendMessageToClient(clientId, agvAction); // 发送消息到客户端
            }
        });
        // 前拨杆伸出
        frontPaddleExtendBtn.setOnClickListener(new View.OnClickListener() {
            @Override
@@ -1460,6 +1478,7 @@
        AgvNo = agvCar.getAgvNo();
        agvNo.setText("AGV编号:" + AgvNo);
        agvBattery.setText("电量:" + agvCar.getBattery() + "%");
        agvSocket.setText(agvCar.getStatus() == 1 ? "已连接" : "未连接");
        agvStatus.setText("AGV状态:" + agvCar.getStatus());
        agvPositionId.setText("ID:" + agvCar.getPositionID());
        agvPositionX.setText("(X):" + agvCar.getPositionX());
app/src/main/java/com/example/agvcontroller/action/LoginReset.java
New file
@@ -0,0 +1,31 @@
package com.example.agvcontroller.action;
import com.example.agvcontroller.protocol.IActionBody;
import com.example.agvcontroller.socket.RadixTools;
import java.io.Serializable;
public class LoginReset implements IActionBody, Serializable {
    private static final long serialVersionUID = -3250235107705010315L;
    private Short pwd;
    @Override
    public byte[] writeToBytes() {
        byte[] bytes = RadixTools.shortToByte(pwd);
        return bytes;
    }
    @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/AGV_03_UP.java
New file
@@ -0,0 +1,42 @@
package com.example.agvcontroller.protocol;
import com.example.agvcontroller.socket.RadixTools;
import java.io.Serializable;
public class AGV_03_UP implements IMessageBody, Serializable {
    private static final long serialVersionUID = -5588066188890649095L;
    @Override
    public byte[] writeToBytes() {
        return new byte[0];
    }
    @Override
    public void readFromBytes(byte[] bytes) {
        this.battery = Utils.sliceWithReverse(bytes, 2, 1)[0];
        this.error = Utils.sliceWithReverse(bytes, 26, 4)[0];
    }
    @Override
    public String getSerialNo() {
        return "";
    }
    private int battery;
    private int error;
    public int getBattery() {
        return battery;
    }
    public int getError() {
        return error;
    }
}
app/src/main/java/com/example/agvcontroller/protocol/HandleCmdType.java
@@ -16,6 +16,7 @@
import com.example.agvcontroller.action.HandOutAction;
import com.example.agvcontroller.action.LiftResetAction;
import com.example.agvcontroller.action.LoadResetAction;
import com.example.agvcontroller.action.LoginReset;
import com.example.agvcontroller.action.RotatopnLeftRight;
import com.example.agvcontroller.action.SingleSwitchAction;
import com.example.agvcontroller.action.SingleSwitchRunAction;
@@ -60,6 +61,8 @@
    BACK_PADDLE(0x8A, "手动控制后拨杆", BackPaddle.class),
    LOGIN_RESET(0x80, "重新登录", LoginReset.class),
    ;
app/src/main/java/com/example/agvcontroller/socket/NettyServerHandler.java
@@ -46,6 +46,7 @@
    private static final String TAG = "NettyServerHandler";
    private static ConcurrentHashMap<String, Channel> channelMap = new ConcurrentHashMap<>();
    private Map<String, Runnable> pendingRemovals = new HashMap<>();
    AGVCar agvCar;
    int battery = 0;
    int status = 0;
    int agvStatus = 0;
@@ -58,6 +59,8 @@
    int forkExtend = 0;
    int forkAngle = 0;
    int agvError = 0;
    String agvNo = "--";
    String log;
    private Handler handler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
@@ -75,14 +78,19 @@
        String ip = remoteAddress.getAddress().getHostAddress();
        int port = remoteAddress.getPort();
        channelMap.put(clientId, ctx.channel());
        EventBus.getDefault().post(new AGVCar(clientId,ip,port,"--",0));
        Log.d(TAG, "Client connected: " + clientId);
        agvCar = new AGVCar(clientId, ip, port, agvNo, 1, battery,agvStatus,positionID,positionX,positionY,agvAngle,gyroAngle,forkHeight,forkExtend,forkAngle,agvError);
        // 取消延迟删除操作
        if (pendingRemovals.containsKey(clientId)) {
            handler.removeCallbacks(pendingRemovals.get(clientId));
            pendingRemovals.remove(clientId);
        }
        EventBus.getDefault().post(agvCar);
//        Log.d(TAG, "Client connected: " + clientId);
        log = formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.SSS") + " 上行: " + ip + "[tcp]>>>已连接";
        Log.d("updown", log);
        AGVApplication.addLog(log);
//        // 取消延迟删除操作
//        if (pendingRemovals.containsKey(clientId)) {
//            handler.removeCallbacks(pendingRemovals.get(clientId));
//            pendingRemovals.remove(clientId);
//        }
    }
@@ -92,24 +100,38 @@
        InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
        String ip = remoteAddress.getAddress().getHostAddress();
        int port = remoteAddress.getPort();
        channelMap.remove(clientId);
//        channelMap.remove(clientId);
        EventBus.getDefault().post(clientId);
        Log.d(TAG, "Client disconnected: " + clientId);
//        Log.d(TAG, "Client disconnected: " + clientId);
        agvCar = new AGVCar(clientId, ip, port, agvNo, 0, battery,agvStatus,positionID,positionX,positionY,agvAngle,gyroAngle,forkHeight,forkExtend,forkAngle,agvError);
        // 启动延迟删除操作
        Runnable removalRunnable = new Runnable() {
            @Override
            public void run() {
                removeItem(clientId);
            }
        };
        pendingRemovals.put(clientId, removalRunnable);
        handler.postDelayed(removalRunnable, 20000); // 20秒后执行删除操作
        EventBus.getDefault().post(agvCar);
//        Log.d(TAG, "Client connected: " + clientId);
        log = formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.SSS") + " 上行: " + ip + "[tcp]>>>断开连接";
        Log.d("updown", log);
        AGVApplication.addLog(log);
//        // 启动延迟删除操作
//        Runnable removalRunnable = new Runnable() {
//            @Override
//            public void run() {
//                removeItem(clientId);
//            }
//        };
//        pendingRemovals.put(clientId, removalRunnable);
//        handler.postDelayed(removalRunnable, 20000); // 20秒后执行删除操作
    }
    private void removeItem(String clientId) {
//        原先是要删除后续为了能动态自动连接需要更新
//        if (channelMap.remove(clientId) != null) {
//            Log.d(TAG, "Client removed after 20 seconds: " + clientId);
//            EventBus.getDefault().post(clientId);
//        } else {
//            Log.d(TAG, "Client already reconnected or not found: " + clientId);
//        }
        if (channelMap.remove(clientId) != null) {
            Log.d(TAG, "Client removed after 20 seconds: " + clientId);
            EventBus.getDefault().post(clientId);
@@ -150,11 +172,6 @@
        // ack
        ProtocolType ackType = isNeedAck(pac);
        final String uniqueNo = pac.getHeader().getUniqueNo();
        String agvNo;
        AGVCar agvCar;
        String log;
        label : switch (pac.getHeader().getProtocolType()){
            case ACTION_COMPLETE:   // 动作完成数据包
                AGV_11_UP agv_11_up = (AGV_11_UP) pac.getBody().getMessageBody();
app/src/main/java/com/example/agvcontroller/utils/ToDBC.java
New file
@@ -0,0 +1,16 @@
package com.example.agvcontroller.utils;
public class ToDBC {
    public static String toDBC(String input) {
        char[] chars = input.toCharArray();
        for (int i=0;i< chars.length; i++){
            if(chars[i]== 12288){
                chars[i]=(char)32;
                continue;
            }
            if(chars[i]> 65280 && chars[i]< 65375)
                chars[i]=(char)(chars[i]- 65248);
        }
        return new String(chars);
    }
}
app/src/main/res/drawable/new_logo.png
app/src/main/res/layout/activity_log.xml
New file
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".LogActivity">
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true">
        <TextView
            android:id="@+id/log_text_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="12sp"
            android:textColor="#FFFFFF"
            android:background="#000000"
            android:focusable="true"
            android:singleLine="false"
            android:focusableInTouchMode="true"
            android:breakStrategy="high_quality"
            android:hyphenationFrequency="normal"
            android:scrollbars="vertical" />
    </ScrollView>
</LinearLayout>
app/src/main/res/layout/activity_main.xml
@@ -14,116 +14,157 @@
        android:orientation="vertical"
        android:padding="10dp"
        android:layout_weight="4">
        <LinearLayout
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="2"
            android:orientation="vertical">
            >
            <TextView
                android:id="@+id/agv_battery"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity=""
                android:textSize="14sp"
                android:text="电量:100%"
                android:textColor="#FFFFFF" />
            <TextView
                android:id="@+id/agv_no"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity=""
                android:textSize="14sp"
                android:text="AGV编号:1"
                android:textColor="#FFFFFF" />
            <TextView
                android:id="@+id/agv_status"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity=""
                android:textSize="14sp"
                android:text="AGV状态:空闲"
                android:textColor="#FFFFFF" />
            android:layout_weight="2">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content" >
                android:layout_height="match_parent"
                android:orientation="vertical">
                >
                <TextView
                    android:layout_width="wrap_content"
                    android:id="@+id/agv_battery"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity=""
                    android:textSize="12sp"
                    android:layout_marginRight="10dp"
                    android:text="当前位置"
                    android:textSize="14sp"
                    android:text="电量:100%"
                    android:textColor="#FFFFFF" />
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    >
                    <TextView
                        android:id="@+id/agv_no"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity=""
                        android:textSize="14sp"
                        android:text="AGV编号:1"
                        android:textColor="#FFFFFF" />
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity=""
                        android:textSize="14sp"
                        android:text="  "
                        android:textColor="#FFFFFF" />
                    <TextView
                        android:id="@+id/socket"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity=""
                        android:textSize="14sp"
                        android:text="--"
                        android:textColor="#FFFFFF" />
                </LinearLayout>
                <TextView
                    android:id="@+id/agv_position_id"
                    android:layout_width="wrap_content"
                    android:id="@+id/agv_status"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity=""
                    android:textSize="12sp"
                    android:layout_marginRight="10dp"
                    android:text="ID:9987"
                    android:textSize="14sp"
                    android:text="AGV状态:空闲"
                    android:textColor="#FFFFFF" />
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" >
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity=""
                        android:textSize="12sp"
                        android:layout_marginRight="10dp"
                        android:text="当前位置"
                        android:textColor="#FFFFFF" />
                    <TextView
                        android:id="@+id/agv_position_id"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity=""
                        android:textSize="12sp"
                        android:layout_marginRight="10dp"
                        android:text="ID:9987"
                        android:textColor="#FFFFFF" />
                    <TextView
                        android:id="@+id/agv_position_x"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity=""
                        android:textSize="12sp"
                        android:layout_marginRight="10dp"
                        android:text="(X):123087"
                        android:textColor="#FFFFFF" />
                    <TextView
                        android:id="@+id/agv_position_y"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity=""
                        android:textSize="12sp"
                        android:layout_marginRight="10dp"
                        android:text="(Y):432311"
                        android:textColor="#FFFFFF" />
                </LinearLayout>
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" >
                    <TextView
                        android:id="@+id/agv_position_height"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity=""
                        android:textSize="12sp"
                        android:layout_marginRight="10dp"
                        android:text="当前高度:100mm"
                        android:textColor="#FFFFFF" />
                    <TextView
                        android:id="@+id/agv_ford"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity=""
                        android:textSize="12sp"
                        android:layout_marginRight="10dp"
                        android:text="货叉伸出距离:30mm"
                        android:textColor="#FFFFFF" />
                    <TextView
                        android:id="@+id/agv_ratio"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity=""
                        android:textSize="12sp"
                        android:layout_marginRight="10dp"
                        android:text="货叉旋转角度:90°"
                        android:textColor="#FFFFFF" />
                </LinearLayout>
                <TextView
                    android:id="@+id/agv_position_x"
                    android:id="@+id/agv_error"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:gravity=""
                    android:textSize="12sp"
                    android:layout_marginRight="10dp"
                    android:text="(X):123087"
                    android:textColor="#FFFFFF" />
                <TextView
                    android:id="@+id/agv_position_y"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:gravity=""
                    android:textSize="12sp"
                    android:layout_marginRight="10dp"
                    android:text="(Y):432311"
                    android:text="AGV故障:导航故障 > 待机状态下丢码"
                    android:textColor="#FFFFFF" />
            </LinearLayout>
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content" >
                <TextView
                    android:id="@+id/agv_position_height"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:gravity=""
                    android:textSize="12sp"
                    android:layout_marginRight="10dp"
                    android:text="当前高度:100mm"
                    android:textColor="#FFFFFF" />
                <TextView
                    android:id="@+id/agv_ford"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:gravity=""
                    android:textSize="12sp"
                    android:layout_marginRight="10dp"
                    android:text="货叉伸出距离:30mm"
                    android:textColor="#FFFFFF" />
                <TextView
                    android:id="@+id/agv_ratio"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:gravity=""
                    android:textSize="12sp"
                    android:layout_marginRight="10dp"
                    android:text="货叉旋转角度:90°"
                    android:textColor="#FFFFFF" />
            </LinearLayout>
            <TextView
                android:id="@+id/agv_error"
            <com.google.android.material.button.MaterialButton
                android:id="@+id/relogin_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity=""
                android:textSize="12sp"
                android:layout_marginRight="10dp"
                android:text="AGV故障:导航故障 > 待机状态下丢码"
                android:textColor="#FFFFFF" />
        </LinearLayout>
                android:layout_alignParentEnd="true"
                android:layout_alignParentTop="true"
                android:layout_marginLeft="20sp"
                android:layout_centerVertical="true"
                android:layout_marginRight="10sp"
                android:backgroundTint="#2196F3"
                android:minWidth="10dp"
                android:paddingLeft="10dp"
                android:paddingRight="10dp"
                android:text="重新登录"
                app:cornerRadius="5dp" />
        </RelativeLayout>
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
@@ -136,6 +177,7 @@
                android:id="@+id/recent_log_text_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scrollbars="vertical"
                />
            <com.google.android.material.button.MaterialButton
                android:id="@+id/view_all_logs_button"