nishiwei
5 days ago 3f43e40ed1a1e9f66b3ad2862da9dbc4b710c712
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
/*
 * 【机场1】从 dock2 原类 com.ard.sample.manage.service.impl.DeviceOSDServiceImpl 复制/独立适配(DJI Dock 1 / M30)。
 * 与 dock2 原类同服务共存;本文件内的适配差异以「// 机场1:」内联注释标出。
 */
package com.ard.sample.dock1.manage.service.impl;
 
import com.ard.common.core.redis.RedisConst;
import com.ard.common.core.redis.RedisOpsUtils;
import com.ard.sample.component.mqtt.model.CommonTopicReceiver;
 
import com.ard.sample.component.websocket.config.ConcurrentWebSocketSession;
import com.ard.sample.component.websocket.enums.MessageType;
import com.ard.sample.component.websocket.handler.DockWebSocketHandler;
import com.ard.sample.component.websocket.model.BizCodeEnum;
import com.ard.sample.component.websocket.model.CustomWebSocketMessage;
import com.ard.sample.manage.model.dto.DeviceDTO;
import com.ard.sample.manage.model.dto.TelemetryDTO;
import com.ard.sample.manage.model.dto.TelemetryDeviceDTO;
import com.ard.sample.manage.model.enums.DeviceDomainEnum;
import com.ard.sample.manage.model.receiver.OsdSubDeviceReceiver;
// 机场1:使用带 M30 专属字段的子类解析飞行器 OSD(仍兼容共享层类型)。
import com.ard.sample.dock1.manage.model.receiver.Dock1OsdSubDeviceReceiver;
import com.ard.sample.manage.service.IDeviceService;
// 机场1:轨迹缓存必须与共享任务进度(FlightTaskServiceImpl 的 type="1" 写入)使用同一个服务实例,
// 否则 type="0" 的轨迹点写进 dock1 独立缓存、而 type="1" 的任务状态写在共享缓存,两处永远无法配对。
// 这里复用共享层 IWaylineTrajectoryService,不修改共享层实现。
import com.ard.sample.manage.service.IWaylineTrajectoryService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
 
import java.util.Collection;
import com.ard.sample.manage.service.impl.AbstractTSAService;
import com.ard.sample.manage.service.impl.DeviceOSDServiceImpl;
 
/**
 * @author sean
 * @version 0.3
 * @date 2022/2/21
 */
@Service
@Slf4j
public class Dock1DeviceOSDServiceImpl extends AbstractTSAService {
 
    @Autowired
    private IDeviceService _deviceService;
 
    @Autowired
    private IWaylineTrajectoryService _waylineTrajectoryService;
 
    @Autowired
    private DockWebSocketHandler _dockWebSocketHandler;
 
    protected Dock1DeviceOSDServiceImpl(@Autowired @Qualifier("dock1DockOSDServiceImpl") AbstractTSAService tsaService) {
        super(tsaService);
    }
 
    @Override
    public void pushTelemetryData(Collection<ConcurrentWebSocketSession> sessions,
                                  CustomWebSocketMessage<TelemetryDTO> message, Object osdData) {
        if (osdData instanceof OsdSubDeviceReceiver) {
            OsdSubDeviceReceiver data = (OsdSubDeviceReceiver) osdData;
            TelemetryDTO telemetry = message.getData();
            telemetry.setHost(TelemetryDeviceDTO.builder()
                    .latitude(data.getLatitude())
                    .longitude(data.getLongitude())
                    .altitude(data.getElevation())
                    .attitudeHead(data.getAttitudeHead())
                    .elevation(data.getElevation())
                    .horizontalSpeed(data.getHorizontalSpeed())
                    .verticalSpeed(data.getVerticalSpeed())
                    .build());
 
            this.sendMessageService.sendBatch(sessions, message);
        }
    }
    @Override
    public void handleOSD(CommonTopicReceiver receiver, DeviceDTO device,
                          Collection<ConcurrentWebSocketSession> webSessions,
                          CustomWebSocketMessage<TelemetryDTO> wsMessage) {
        if (DeviceDomainEnum.SUB_DEVICE.getVal() == device.getDomain()) {
            wsMessage.setBizCode(BizCodeEnum.DEVICE_OSD.getCode());
 
            // 机场1:M30/M30T 的 OSD 比共享类多 9 个字段,用 dock1 子类承接。
            // 机场1:Dock1 的飞行器 OSD 中 payloads 本身就是数组,convertValue 已经完成解析;
            // 共享层按 device.payloadsList(扁平 key)二次覆盖的逻辑不适用于 dock1,
            // 且该列表当前恒为 null,会在每条 OSD 上触发 NPE 并打印误导性告警,故 dock1 链直接跳过。
            // 容错:单个字段类型异常(如固件把 rid_state 上报成布尔)不应丢弃整帧 OSD,
            // 解析失败时降级为共享接收器,保证状态、遥测、轨迹链路继续工作。
            OsdSubDeviceReceiver data;
            try {
                data = mapper.convertValue(receiver.getData(), Dock1OsdSubDeviceReceiver.class);
            } catch (IllegalArgumentException e) {
                log.warn("机场1 飞行器 OSD 解析失败,降级为共享接收器:{}", e.getMessage());
                data = mapper.convertValue(receiver.getData(), OsdSubDeviceReceiver.class);
            }
            //data.setChildDeviceSn(device.getDeviceSn());
            String dockOsd = "";
            receiver.setType(MessageType.STATUS.getType()+"-aircraft");
//            receiver.setData(data);
            try {
                dockOsd=mapper.writeValueAsString(receiver);
                JsonNode jsonNode = mapper.readTree(dockOsd);
                //在JSON的data下插入childDeviceSn,飞行器的sn
                if(jsonNode.get("data") instanceof ObjectNode){
                    ObjectNode objectNode = (ObjectNode) jsonNode.get("data");
                    objectNode.put("childDeviceSn", device.getDeviceSn());
                }
                if(jsonNode.has("data")){
 
                    if(jsonNode.get("data").has("mode_code")) {
                        Long code = jsonNode.get("data").get("mode_code").asLong();
                        if ("0,1,2,3,4,5,8,9,10,11,13,14".contains(code.toString())) {
                            _deviceService.updateWorkType(device.getDeviceSn(), code);
                            RedisOpsUtils.set(RedisConst.OSD_STATUS_PREFIX + device.getDeviceSn(), code);
                        }
                    }
                }
                dockOsd=mapper.writeValueAsString(jsonNode);
            } catch (NullPointerException | JsonProcessingException e) {
                log.warn("Please remount the payload, or restart the drone. Otherwise the data of the payload will not be received.");
            }
 
            RedisOpsUtils.setWithExpire(RedisConst.OSD_PREFIX + device.getDeviceSn(), data, RedisConst.DEVICE_ALIVE_SECOND);
            wsMessage.getData().setHost(data);
 
            // 发送给websocket客户端
            _dockWebSocketHandler.sendMessageToSubscribers(device.getDeviceSn(), MessageType.STATUS.getType(), dockOsd, "");
 
            // 将飞行器的OSD数据dockOsd入库;device.getDeviceSn()为飞行器sn,这里要机场的sn,试试receiver.getGateway();
            _waylineTrajectoryService.setList(receiver.getGateway(),"0", dockOsd);
 
            sendMessageService.sendBatch(webSessions, wsMessage);
            this.pushTelemetryData(data, device.getDeviceSn());
        }
        tsaService.handleOSD(receiver, device, webSessions, wsMessage);
    }
}