#
whycq
2025-02-06 318bd727e2fe02e4f541dfe943f77606af41d509
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
package com.example.agvcontroller.socket;
 
 
 
import static com.example.agvcontroller.utils.DateUtils.formatDate;
 
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 android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
 
import com.example.agvcontroller.AGVApplication;
import com.example.agvcontroller.AGVCar;
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_03_UP;
import com.example.agvcontroller.protocol.AGV_12_UP;
import com.example.agvcontroller.protocol.AGV_13_UP;
import com.example.agvcontroller.protocol.AGV_A1_DOWN;
import com.example.agvcontroller.protocol.AGV_F0_DOWN;
import com.example.agvcontroller.protocol.AGV_F0_UP;
import com.example.agvcontroller.protocol.AgvAction;
import com.example.agvcontroller.protocol.AgvPackage;
import com.example.agvcontroller.protocol.ProtocolType;
import com.example.agvcontroller.utils.DateUtils;
 
 
import org.greenrobot.eventbus.EventBus;
 
import java.net.InetSocketAddress;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
 
public class NettyServerHandler  extends AbstractInboundHandler<AgvPackage> {
 
    private static final String TAG = "NettyServerHandler";
    private static ConcurrentHashMap<String, Channel> channelMap = new ConcurrentHashMap<>();
    private Map<String, Runnable> pendingRemovals = new HashMap<>();
    int battery = 0;
    int status = 0;
    int agvStatus = 0;
    String positionID = "--";
    int positionX = 0;
    int positionY = 0;
    float agvAngle = 0;
    float gyroAngle = 0;
    int forkHeight = 0;
    int forkExtend = 0;
    int forkAngle = 0;
    int agvError = 0;
    private Handler handler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            String clientId = (String) msg.obj;
            removeItem(clientId);
        }
    };
 
 
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        String clientId = ctx.channel().remoteAddress().toString();
        InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
        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);
 
        // 取消延迟删除操作
        if (pendingRemovals.containsKey(clientId)) {
            handler.removeCallbacks(pendingRemovals.get(clientId));
            pendingRemovals.remove(clientId);
        }
 
    }
 
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        String clientId = ctx.channel().remoteAddress().toString();
        InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
        String ip = remoteAddress.getAddress().getHostAddress();
        int port = remoteAddress.getPort();
        channelMap.remove(clientId);
        EventBus.getDefault().post(clientId);
        Log.d(TAG, "Client disconnected: " + clientId);
 
        // 启动延迟删除操作
        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);
        }
    }
 
//    @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信息 添加到list中
//                Log.d(TAG, "ctx: " + ctx.channel().remoteAddress().toString() );
//                Log.d(TAG, "Received: " + hexString);
//            }
//        } finally {
//            byteBuf.release();
//        }
//    }
 
    @Override
    protected boolean channelRead0(ChannelHandlerContext ctx, AgvPackage pac) throws Exception {
        String clientId = ctx.channel().remoteAddress().toString();
        InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
        String ip = remoteAddress.getAddress().getHostAddress();
        int port = remoteAddress.getPort();
        Log.i("clientId--->",clientId);
        Log.i("substring",pac.toString());
        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();
        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();
//                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);
                }
                break label;
            case DATA_CODE_REPORT:
                AGV_12_UP agv_12_up = (AGV_12_UP) pac.getBody().getMessageBody();
                agvNo = pac.getHeader().getUniqueNo();
                channelMap.put(clientId, ctx.channel());
                agvStatus = agv_12_up.getStatus();
                positionID = agv_12_up.getQrCode();
                positionX = agv_12_up.getOffsetX();
                positionY = agv_12_up.getOffsetY();
                agvAngle = agv_12_up.getAGVCurrentAngle();
                gyroAngle = agv_12_up.getGyroAngle();
                forkHeight = agv_12_up.getCurrentAltitude();
                forkExtend = agv_12_up.getForkLength();
                forkAngle = agv_12_up.getLoaderTheta();
                agvCar = new AGVCar(clientId, ip, port, agvNo, 1, battery,agvStatus,positionID,positionX,positionY,agvAngle,gyroAngle,forkHeight,forkExtend,forkAngle,agvError);
                EventBus.getDefault().post(agvCar);
                log = formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.SSS") + " 上行: " + ip + "[有码实时数据包]>>>" + pac.getSourceHexStr();
                Log.d("updown", log);
                AGVApplication.addLog(log);
                break label;
            case DATA_WITHOUT_CODE_REPORT:
                AGV_13_UP agv_13_up = (AGV_13_UP) pac.getBody().getMessageBody();
                agvNo = pac.getHeader().getUniqueNo();
                channelMap.put(clientId, ctx.channel());
                agvCar = new AGVCar(clientId, ip, port, agvNo, 1, battery,agvStatus,positionID,positionX,positionY,agvAngle,gyroAngle,forkHeight,forkExtend,forkAngle,agvError);
                EventBus.getDefault().post(agvCar);
                log = formatDate(new Date(), "yyyy-MM-dd HH:mm:ss:SSS") + " 上行: " + ip + "[无码实时数据包]>>>" + pac.getSourceHexStr();
                Log.d("updown", log);
                AGVApplication.addLog(log);
                break label;
            case HEARTBEAT_REPORT:
                AGV_03_UP agv_03_up = (AGV_03_UP) pac.getBody().getMessageBody();
                battery = agv_03_up.getBattery();
                agvError = agv_03_up.getError();
//                pac.getBody().getMessageBody()
                agvNo = pac.getHeader().getUniqueNo();
                channelMap.put(clientId, ctx.channel());
                agvCar = new AGVCar(clientId, ip, port, agvNo, 1, battery,agvStatus,positionID,positionX,positionY,agvAngle,gyroAngle,forkHeight,forkExtend,forkAngle,agvError);
                EventBus.getDefault().post(agvCar);
                log = formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.SSS") + " 上行: " + ip + "[心跳包]>>>" + pac.getSourceHexStr();
                Log.d("updown", log);
                AGVApplication.addLog(log);
                break label;
            case LOGIN_REPORT:
                AGV_F0_UP agv_f0_up = (AGV_F0_UP) pac.getBody().getMessageBody();
                if (null != ackType) {
                    AgvPackage ackPac = AckMsgBuilder.ofSuccess(pac, ackType);
                    AGV_F0_DOWN agv_f0_down = (AGV_F0_DOWN) ackPac.getBody().getMessageBody();
                    log = formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.SSS") + " 上行: " + ip + "[登录包]>>>" + pac.getSourceHexStr();
                    Log.d("updown", log);
                    AGVApplication.addLog(log);
 
//                    EventBus.getDefault().post(log);
 
                    ctx.writeAndFlush(ackPac);
                }
                battery = agv_f0_up.getBattery();
//                pac.getBody().getMessageBody()
                agvNo = pac.getHeader().getUniqueNo();
                channelMap.put(clientId, ctx.channel());
                agvCar = new AGVCar(clientId, ip, port, agvNo, 1, battery,agvStatus,positionID,positionX,positionY,agvAngle,gyroAngle,forkHeight,forkExtend,forkAngle,agvError);
                EventBus.getDefault().post(agvCar);
                break label;
 
        }
        return false;
    }
 
    private String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
 
    // 将十六进制字符串转换为字节数组
    private byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }
 
    public static void sendMessageToClient(String clientId, byte[] message) {
        Channel channel = channelMap.get(clientId);
        if (channel != null && channel.isActive()) {
            ByteBuf buf = Unpooled.wrappedBuffer(message);
            String upperCase = ByteBufUtil.hexDump(buf).toUpperCase();
            Log.d(TAG, "upperCase " + upperCase);
            channel.writeAndFlush(buf);
        } else {
            Log.d(TAG, "Client " + clientId + " is not connected");
        }
    }
 
    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();
        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;
        }
    }
 
}