liusuyi
2024-10-25 1157c58dc74805cbb7db57ab121bbb521f4c216b
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
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
package com.ard.tianyu.service.impl;
 
import com.ard.tianyu.config.TyConfiguration;
import com.ard.tianyu.http.TyClient;
import com.ard.tianyu.model.cache.UavSignalInfoCache;
import com.ard.tianyu.model.cache.UavStateCache;
import com.ard.tianyu.model.cache.UavTelemetryDataCache;
import com.ard.tianyu.model.dto.BoxHistoryDTO;
import com.ard.tianyu.model.dto.BoxPhotosDTO;
import com.ard.tianyu.model.dto.BoxSettingsDTO;
import com.ard.tianyu.model.dto.camera.CameraModeDTO;
import com.ard.tianyu.model.dto.camera.CapturePicDTO;
import com.ard.tianyu.model.dto.camera.RecordDTO;
import com.ard.tianyu.model.dto.control.AbsAngleControlDTO;
import com.ard.tianyu.model.dto.control.AngleControlDTO;
import com.ard.tianyu.model.dto.control.SpeedControlDTO;
import com.ard.tianyu.model.dto.converter.UavSignalInfoConverter;
import com.ard.tianyu.model.dto.converter.UavStateConverter;
import com.ard.tianyu.model.dto.converter.UavTelemetryDataConverter;
import com.ard.tianyu.model.dto.signal.SignalInfo;
import com.ard.tianyu.model.dto.state.UavState;
import com.ard.tianyu.model.dto.telemetry.TelemetryData;
import com.ard.tianyu.model.receiver.*;
import com.ard.tianyu.netty.command.*;
import com.ard.tianyu.netty.TyNettyTcpClient;
import com.ard.tianyu.netty.command.camera.*;
import com.ard.tianyu.netty.command.control.AbsAngleControlCommand;
import com.ard.tianyu.netty.command.control.AngleControlCommand;
import com.ard.tianyu.netty.command.control.SpeedControlCommand;
import com.ard.tianyu.netty.command.real.SignalInfoCommand;
import com.ard.tianyu.netty.command.real.UavStateCommand;
import com.ard.tianyu.netty.command.real.UavTelemetryDataCommand;
import com.ard.tianyu.netty.command.register.*;
import com.ard.tianyu.service.ITyService;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
 
import javax.annotation.Resource;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
 
/**
 * TyServiceImpl
 *
 * @author liusuyi
 * @date 2024年10月22日8:37
 **/
@Slf4j
@Service
public class TyServiceImpl implements ITyService {
 
    @Resource
    private TyClient tyClient;
 
    @Resource
    private TyConfiguration tyConfiguration;
 
    /**
     * 获取天宇token信息
     *
     * @return AccessTokenReceiver
     */
    @Override
    public AccessTokenReceiver getAccessToken() {
        return tyConfiguration.getAccessToken();
    }
 
    /**
     * 获取云盒列表
     *
     * @return List<BoxInfoReceiver>
     */
    @Override
    public List<BoxInfoReceiver> getBoxList() {
        //请求云盒列表
        try {
            TyHttpCommonReceiver<List<BoxInfoReceiver>> boxListReveiver = tyClient.getBoxList(tyConfiguration.getAccessToken().convertFromDTO());
            return boxListReveiver.getContent();
        } catch (Exception e) {
            log.error("获取云盒列表失败:{}", e.getMessage());
            return new ArrayList<>();
        }
    }
 
    /**
     * 获取直播地址
     *
     * @return BoxStreamUrlReceiver
     */
    @Override
    public BoxStreamUrlReceiver getBoxLiveUrl(String boxSn) {
 
        TyHttpCommonReceiver<BoxStreamUrlReceiver> boxLiveUrl = tyClient.getBoxLiveUrl(boxSn, tyConfiguration.getAccessToken().convertFromDTO());
        return boxLiveUrl.getContent();
    }
 
    /**
     * 获取飞行历史
     *
     * @return List<BoxHistoryReceiver>
     */
    @Override
    public List<BoxHistoryReceiver> getBoxHistory(BoxHistoryDTO boxHistoryDTO) {
        TyHttpCommonReceiver<List<BoxHistoryReceiver>> boxHistory = tyClient.getBoxHistory(boxHistoryDTO, tyConfiguration.getAccessToken().convertFromDTO());
        return boxHistory.getContent();
    }
 
    /**
     * 获取盒子图片
     *
     * @return List<BoxPhotosReceiver>
     */
    @Override
    public List<BoxPhotosReceiver> getBoxPhotos(BoxPhotosDTO boxPhotosDTO) {
        TyHttpCommonReceiver<List<BoxPhotosReceiver>> boxPhotos = tyClient.getBoxPhotos(boxPhotosDTO, tyConfiguration.getAccessToken().convertFromDTO());
        return boxPhotos.getContent();
    }
 
    /**
     * 修改云盒设置
     */
    @Override
    public Boolean updateBoxSettings(BoxSettingsDTO boxSettingsDTO) {
        TyHttpCommonReceiver<?> result = tyClient.updateBoxSettings(boxSettingsDTO, tyConfiguration.getAccessToken().convertFromDTO());
        return result.getState() == 1;
    }
 
    /**
     * 注册天宇平台
     */
    @Override
    public void registerMessage() {
        AccessTokenReceiver tyToken = tyConfiguration.getAccessToken();
        RegisterCommand registerMessage = new RegisterCommand(tyToken.getCompanyId(), tyToken.getAccessToken().getBytes());
        this.sendMessage(tyConfiguration.getIpPort(), registerMessage);
    }
 
 
    /**
     * 发送消息
     */
    public void sendMessage(String key, BaseCommand msg) {
        try {
            ChannelFuture future = TyNettyTcpClient.channels.get(key).getChannelFuture();
            Channel channel = future.channel();
            if (channel.isActive()) {
                InetSocketAddress ipSocket = (InetSocketAddress) channel.remoteAddress();
                String host = ipSocket.getHostString();
                int port = ipSocket.getPort();
                channel.writeAndFlush(msg); // 发送编码后的数据
                log.debug("向天宇服务器【{}:{}】发送数据,命令码:{}", host, port, String.format("0x%02X", msg.getCmdCode() & 0xFF));
            } else {
                log.error("与天宇服务器链接断开,无法发送数据!");
            }
        } catch (Exception e) {
            log.error("发送消息异常:{}", e.getMessage());
        }
    }
 
    /**
     * 云台控制基于角度
     */
    @Override
    public void angleControl(AngleControlDTO angleControlDto) {
        AngleControlCommand controlAngleCommand = new AngleControlCommand(angleControlDto);
        this.sendMessage(tyConfiguration.getIpPort(), controlAngleCommand);
    }
 
    /**
     * 云台绝对值控制(基于角度)
     */
    @Override
    public void absAngleControl(AbsAngleControlDTO absAngleControlDto) {
        AbsAngleControlCommand absAngleControlCommand = new AbsAngleControlCommand(absAngleControlDto);
        this.sendMessage(tyConfiguration.getIpPort(), absAngleControlCommand);
    }
 
    /**
     * 云台转动(基于速度)
     */
    @Override
    public void speedControl(SpeedControlDTO speedControlDto) {
        SpeedControlCommand speedControlCommand = new SpeedControlCommand(speedControlDto);
        this.sendMessage(tyConfiguration.getIpPort(), speedControlCommand);
    }
 
    /**
     * 设置相机模式
     */
    @Override
    public void updateCameraMode(CameraModeDTO cameraModeDTO) {
        CameraModeCommand cameraModeCommand = new CameraModeCommand(cameraModeDTO);
        this.sendMessage(tyConfiguration.getIpPort(), cameraModeCommand);
    }
 
    /**
     * 拍照
     */
    @Override
    public void capturePic(CapturePicDTO capturePicDto) {
        updateCameraMode(CameraModeDTO.builder().boxSn(capturePicDto.getBoxSn()).actionParam((byte)0x01).build());
        CapturePicCommand capturePicCommand = new CapturePicCommand(capturePicDto);
        this.sendMessage(tyConfiguration.getIpPort(), capturePicCommand);
    }
 
    /**
     * 录像
     */
    @Override
    public void record(RecordDTO recordDto) {
        BaseCommand baseCommand;
        if (recordDto.getIsRecord()) {
            updateCameraMode(CameraModeDTO.builder().boxSn(recordDto.getBoxSn()).actionParam((byte)0x02).build());
            baseCommand = new RecordStartCommand(recordDto);
        } else {
            baseCommand = new RecordStopCommand(recordDto);
        }
        this.sendMessage(tyConfiguration.getIpPort(), baseCommand);
    }
 
    /**
     * 获取无人机状态
     */
    @Override
    public UavState getUavState(String boxSn) {
        return UavStateCache.getUavState(boxSn);
    }
 
    /**
     * 获取无人机遥测数据
     */
    @Override
    public TelemetryData getUavTelemetryData(String boxSn) {
        return UavTelemetryDataCache.getUavTelemetryData(boxSn);
    }
 
    /**
     * 获取无人机遥测数据
     */
    @Override
    public SignalInfo getSignalInfo(String boxSn) {
        return UavSignalInfoCache.getUavSignalInfo(boxSn);
    }
 
    @Override
    public void processMessage(String key, BaseCommand tyCommand) {
        byte cmdCode = tyCommand.getCmdCode();
        switch (cmdCode) {
            case 0x01:
                // 处理心跳消息
                RegisterReplyCommand registerReplyCommand = (RegisterReplyCommand) tyCommand;
                log.info("收到注册消息-->处理注册消息{}", registerReplyCommand.getSuccess());
                if (registerReplyCommand.getSuccess() != 1) {
                    // 注册失败,重新注册
                    log.info("注册失败,重新注册");
                    registerMessage();
                }
                break;
            case 0x02:
                // 处理注册消息
                HeartbeatReplyCommand heartbeatReplyCommand = (HeartbeatReplyCommand) tyCommand;
                log.debug("收到心跳消息-->处理心跳消息{}", heartbeatReplyCommand.getTimestamp());
                break;
            case 0x03:
                // 处理订阅消息
                break;
            case 0x04:
                // 处理取消订阅消息
                break;
            case (byte) 0xA8:
                // 处理无人机状态消息
                log.debug("收到无人机状态消息-->无人机状态消息");
                UavStateCommand uavStateCommand = (UavStateCommand) tyCommand;
                UavState uavState = UavStateConverter.convertProtoToEntity(uavStateCommand.getUavState());
                UavStateCache.putUavState(uavState);
                break;
            case (byte) 0xA9:
                // 处理无人机遥测消息
                log.debug("收到无人机遥测消息-->无人机遥测消息");
                UavTelemetryDataCommand uavTelemetryDataCommand = (UavTelemetryDataCommand) tyCommand;
                TelemetryData telemetryData = UavTelemetryDataConverter.convertProtoToEntity(uavTelemetryDataCommand.getTelemetryData());
                UavTelemetryDataCache.putUavTelemetryData(telemetryData);
                break;
            case (byte) 0x0C:
                // 处理无人机信道质量数据
                log.debug("收到无人机信道质量数据消息-->无人机信道质量数据消息");
                SignalInfoCommand signalInfoCommand = (SignalInfoCommand) tyCommand;
                SignalInfo signalInfo = UavSignalInfoConverter.convertProtoToEntity(signalInfoCommand.getSignalInfo());
                UavSignalInfoCache.putUavSignalInfoCache(signalInfo);
                break;
            case (byte) 0xD1:
                // 处理无人机
                if (tyCommand instanceof UavReadyNotificationCommand) {
                    UavReadyNotificationCommand droneReadyNotificationCommand = (UavReadyNotificationCommand) tyCommand;
                    if (droneReadyNotificationCommand.getActionCode() == (byte) 0x42) {
                        UavInitInfoCommand uavInitCommand = new UavInitInfoCommand(droneReadyNotificationCommand.getBoxSn());
                        this.sendMessage(tyConfiguration.getIpPort(), uavInitCommand);
                        log.info("收到无人机初始化详情-回复防止再次发送");
                    }
                }
                if (tyCommand instanceof CameraModeReplyCommand) {
                    CameraModeReplyCommand cameraModeReplyCommand = (CameraModeReplyCommand) tyCommand;
                    if (cameraModeReplyCommand.getActionCode() == (byte) 0x22) {
                        log.info("收到无人机设置相机模式回复:{} 错误码:{}", String.format("0x%02X", cameraModeReplyCommand.getResult() & 0xFF), cameraModeReplyCommand.getErrorCode());
                    }
                }
 
                if (tyCommand instanceof CapturePicReplyCommand) {
                    CapturePicReplyCommand capturePicReplyCommand = (CapturePicReplyCommand) tyCommand;
                    if (capturePicReplyCommand.getActionCode() == (byte) 0x23) {
                        log.info("收到无人机拍照回复:{} 错误码:{}", String.format("0x%02X", capturePicReplyCommand.getResult() & 0xFF), capturePicReplyCommand.getErrorCode());
                    }
                }
 
                if (tyCommand instanceof RecordStartReplyCommand) {
                    RecordStartReplyCommand recordStartReplyCommand = (RecordStartReplyCommand) tyCommand;
                    if (recordStartReplyCommand.getActionCode() == (byte) 0x24) {
                        log.info("收到无人机开始录像回复:{} 错误码:{}", String.format("0x%02X", recordStartReplyCommand.getResult() & 0xFF), recordStartReplyCommand.getErrorCode());
                    }
                }
                if (tyCommand instanceof RecordStopReplyCommand) {
                    RecordStopReplyCommand recordStopReplyCommand = (RecordStopReplyCommand) tyCommand;
                    if (recordStopReplyCommand.getActionCode() == (byte) 0x25) {
                        log.info("收到无人机停止录像回复:{} 错误码:{}", String.format("0x%02X", recordStopReplyCommand.getResult() & 0xFF), recordStopReplyCommand.getErrorCode());
                    }
                }
                break;
            default:
                // 处理其他消息
                log.debug("收到其他消息-->其他消息");
        }
    }
 
    @Scheduled(fixedRate = 3000)
    public void sendHeartBeat() {
        long timestamp = System.currentTimeMillis();
        log.debug("定时向天宇发送⼼跳,时间戳{}", timestamp);
        HeartbeatCommand heartbeatMessage = new HeartbeatCommand(timestamp);
        this.sendMessage(tyConfiguration.getIpPort(), heartbeatMessage);
    }
}