zhouhn
2026-02-25 0f5fc39356b6bff677984c33c296573bb9c8393e
引入proto文件,生成与XPU通信的报文对象
6个文件已修改
735 ■■■■■ 已修改文件
xp-robotaxi-api/pom.xml 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/pom.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java 337 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/util/XPUUtil.java 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/test/java/com/xiaopeng/automaticPilot/util/XPUUtilTest.java 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/pom.xml
@@ -41,6 +41,38 @@
            <artifactId>unified-verification</artifactId>
            <version>1.5.2-v2</version>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>3.19.4</version>
        </dependency>
    </dependencies>
</project>
    <build>
        <extensions>
            <extension>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>1.6.2</version>
            </extension>
        </extensions>
        <plugins>
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>0.6.1</version>
                <configuration>
                    <protocArtifact>com.google.protobuf:protoc:3.19.4:exe:${os.detected.classifier}</protocArtifact>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
xp-robotaxi-automatic-pilot-boot/pom.xml
@@ -128,6 +128,11 @@
            <artifactId>snakeyaml</artifactId>
            <version>1.33</version>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java-util</artifactId>
            <version>3.19.4</version>
        </dependency>
    </dependencies>
    <build>
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java
@@ -6,11 +6,11 @@
import com.xiaopeng.api.dto.automaticPilot.PushOrderDto;
import com.xiaopeng.api.dto.vehicleConvoy.UpdateVehicleStateDto;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.RTTask;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.TaskStatus;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.TaskType;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.OrderOperation;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.OrderOperationType;
import com.xiaopeng.api.vo.automaticPilot.protobuf.RtTask;
import com.xiaopeng.api.vo.automaticPilot.protobuf.RtTaskList;
import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderType;
import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperation;
import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperationType;
import com.xiaopeng.automaticPilot.util.XPUUtil;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.utils.SnowFlake;
@@ -19,7 +19,6 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
@Slf4j
@@ -28,33 +27,32 @@
@Api(tags = "订单任务Api")
public class OrderMissionController {
    @Resource
    private XPUUtil xpuUtil;
    @Resource
    private RedisService redisService;
    @Resource
    private XpVehicleClient xpVehicleClient;
    private final XPUUtil xpuUtil;
    private final RedisService redisService;
    private final XpVehicleClient xpVehicleClient;
    public OrderMissionController(XPUUtil xpuUtil, RedisService redisService, XpVehicleClient xpVehicleClient, Snowflake snowflake) {
        this.xpuUtil = xpuUtil;
        this.redisService = redisService;
        this.xpVehicleClient = xpVehicleClient;
    }
    @PostMapping("/inner/pushOrder")
    public R<Boolean> pushOrder(@RequestBody PushOrderDto dto) {
        RTTask task = new RTTask();
        RtTask.Builder taskBuilder = RtTask.newBuilder();
        //TODO 设置目标地点信息
        task.setOrder_id(dto.getOrderId());
        task.setTask_id("MISSION_"+ IdUtil.fastUUID());
        if(dto.getOrderId().contains("XU")){
            task.setTask_type(TaskType.CRUISE);
        }else {
            task.setTask_type(TaskType.ROBOTAXI);
        }
        task.setStatus(TaskStatus.PENDING);
        taskBuilder.setOrderId(dto.getOrderId().toString());
        taskBuilder.setTaskId("MISSION_"+ IdUtil.fastUUID());
        taskBuilder.setTaskType(OrderType.ORDER_TYPE_ROBOTAXI);
        RtTaskList.Builder taskListBuilder = RtTaskList.newBuilder();
        taskListBuilder.addTasks(taskBuilder.build());
        SnowFlake snowFlake = new SnowFlake(0, 0);
        snowFlake.withStartTimestamp(1420041600000L);
        long sequence = snowFlake.nextId();
        MqttPublishDto mqttPublishDto = xpuUtil.cloudCreateOrder(task, dto.getVin(),sequence);
        // 正常单子才修改  巡游单子不修改状态
        if (!dto.getOrderId().contains("XU") && mqttPublishDto.getCode()== 200) {
        MqttPublishDto mqttPublishDto = xpuUtil.cloudCreateOrder(taskListBuilder.build(), dto.getVin(),sequence);
        if (mqttPublishDto.getCode()== 200) {
            // 修改车子为接单状态
            xpVehicleClient.updateVehicleStatus(new UpdateVehicleStateDto(dto.getVin(),1));
@@ -65,15 +63,18 @@
    @PostMapping("/inner/cancelOrder")
    R<Boolean> cancelOrder(@RequestBody PushOrderDto dto) {
            OrderOperation operation = new OrderOperation();
            operation.setOrder_id(dto.getOrderId().toString());
            operation.setTask_id("CANCEL_MISSION_"+ IdUtil.fastUUID());
            operation.setOperation_type(dto.getOperation_type());
            SnowFlake snowFlake = new SnowFlake(0, 0);
            snowFlake.withStartTimestamp(1420041600000L);
            long sequence = snowFlake.nextId();
            xpuUtil.cloudOrderOperation(operation,dto.getVin(),sequence);
            redisService.setCacheObject(String.valueOf(sequence),"cancelOrder_"+dto.getOrderId()+"_"+ dto.getVin(),30l, TimeUnit.MINUTES);
            return R.ok(true);
        OrderOperation.Builder operationBuilder = OrderOperation.newBuilder();
        operationBuilder.setOrderId(dto.getOrderId().toString());
        operationBuilder.setTaskId("CANCEL_MISSION_" + IdUtil.fastUUID());
        if (dto.getOperation_type() != null) {
            operationBuilder.setOperationType(OrderOperationType.forNumber(dto.getOperation_type().getValue()));
        }
        SnowFlake snowFlake = new SnowFlake(0, 0);
        snowFlake.withStartTimestamp(1420041600000L);
        long sequence = snowFlake.nextId();
        xpuUtil.cloudOrderOperation(operationBuilder.build(), dto.getVin(), sequence);
        redisService.setCacheObject(String.valueOf(sequence), "cancelOrder_" + dto.getOrderId() + "_" + dto.getVin(), 30l, TimeUnit.MINUTES);
        return R.ok(true);
    }
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java
@@ -1,7 +1,6 @@
package com.xiaopeng.automaticPilot.service;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.xiaopeng.api.dto.map.OrderRouteAndFareDto;
@@ -12,25 +11,22 @@
import com.xiaopeng.api.dto.pushMessage.SendMessageDTO;
import com.xiaopeng.api.feignClient.map.XpMapClient;
import com.xiaopeng.api.feignClient.operation.ReassignOrderClient;
import com.xiaopeng.api.feignClient.order.XpCruiseOrderClient;
import com.xiaopeng.api.feignClient.order.XpOrderClient;
import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.UserVehicleClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.api.model.order.XpCruiseOrder;
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.api.vo.OrderType;
import com.xiaopeng.api.vo.SystemEventType;
import com.xiaopeng.api.vo.automaticPilot.VehiclePosition;
import com.xiaopeng.api.vo.automaticPilot.proto.down.GeoPoint;
import com.xiaopeng.api.vo.automaticPilot.proto.down.ResponseMessage;
import com.xiaopeng.api.vo.automaticPilot.proto.down.StatusCode;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.RTTask;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.TaskStatus;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.TaskType;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.*;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudPushNavigation.RestoreNavigationData;
import com.xiaopeng.api.vo.automaticPilot.protobuf.ActionType;
import com.xiaopeng.api.vo.automaticPilot.protobuf.GeoPoint;
import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperation;
import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperationType;
import com.xiaopeng.api.vo.automaticPilot.protobuf.PointType;
import com.xiaopeng.api.vo.automaticPilot.protobuf.ResponseMessage;
import com.xiaopeng.api.vo.automaticPilot.protobuf.RestoreNavigationData;
import com.xiaopeng.api.vo.automaticPilot.protobuf.StatusCode;
import com.xiaopeng.api.vo.automaticPilot.protobuf.Waypoint;
import com.xiaopeng.api.vo.automaticPilot.proto.up.MessageType;
import com.xiaopeng.api.vo.automaticPilot.proto.up.MsgContent;
import com.xiaopeng.api.vo.automaticPilot.proto.up.RTCmdType;
@@ -49,10 +45,8 @@
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.enums.OrderStatusEnum;
import com.xiaopeng.common.core.enums.PushMessageTypeEnum;
import com.xiaopeng.common.core.utils.SnowFlake;
import com.xiaopeng.common.core.utils.StringUtils;
import com.xiaopeng.common.core.utils.uuid.UUID;
import com.xiaopeng.common.redis.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
@@ -101,12 +95,7 @@
    private UserVehicleClient userVehicleClient;
    @Resource
    private XpCruiseOrderClient xpCruiseOrderClient;
    @Resource
    private Snowflake snowflake;
    @Autowired
    private RedisService redisService;
    /**
@@ -209,17 +198,11 @@
            if(code == com.xiaopeng.api.vo.automaticPilot.proto.up.StatusCode.OK){
                Object sequence = redisTemplate.opsForValue().get(requestSeq);
                if(sequence!=null){
                    JSONObject jsonObject = JSON.parseObject(sequence.toString());
                    String event = jsonObject.getString("event");
                    //推送导航的响应消息
                    if(SystemEventType.PUSH_NAVIGATION.equals(event)){
                        String orderId = jsonObject.getString("orderId");
                        String vin = jsonObject.getString("vin");
                        String orderType = jsonObject.getString("orderType");
                    String[] split = sequence.toString().split("_");
                    if(split[0].equals("pushOrder")){
                        PopOrderDto dto = new PopOrderDto();
                        dto.setOrderId(Long.valueOf(orderId));
                        dto.setXpVehicleVin(vin);
                        dto.setOrderType(orderType);
                        dto.setOrderId(Long.valueOf(split[1]));
                        dto.setXpVehicleVin(split[2]);
                        xpOrderClient.popOrder(dto);
                    }
                }
@@ -270,8 +253,7 @@
        //车辆动态信息
        VehicleDynamicStatus dynamicStatus = vehicleStatus.getDynamic_status();
        dynamicStatus.setSpeed(dynamicStatus.getSpeed());
        vehiclePosition.setCurrentElectricity(dynamicStatus.getBms_soc_disp());
        vehiclePosition.setMileageRange(dynamicStatus.getDst_bat_disp());
        vehiclePosition.setCurrentElectricity(dynamicStatus.getBattery_level());
        //订单信息
        OrderStatusInfo runningOrderStatusInfo = systemRuntimeStatus.getRunning_order_status_info();
        Long orderId = null;
@@ -410,10 +392,6 @@
        //开始处理消息对应的业务逻辑
        NavigationDeviationEvent deviationEvent = msgContent.getContent_detail().getObject("deviationEvent", NavigationDeviationEvent.class);
        String requestId = deviationEvent.getRequest_id();
        //导航id
        String routeID = "";
        Long vehicleId = null;
        String orderType = "";
        //偏航事件类型 1:请求导航,2:取消导航
        if (deviationEvent.getEvent_type().equals(RtEventType.RT_EVENT_TYPE_REQUEST)) {
            NavigationDeviationMessage navigationDeviationMessage = deviationEvent.getNavigation_deviation_message();
@@ -425,31 +403,15 @@
            LonLatDto destination = new LonLatDto();
            LonLatDto origin = new LonLatDto();
            if (orderId.contains("XU")) {
                orderType = OrderType.CRUISE_ORDER;
                // todo 下发巡游单的导航数据
                //先响应消息
                responseMessage(sequence, "");
                //构建导航数据给到车端
                origin.setLongitude(116.40528);
                origin.setLatitude(39.90498);
                //巡游单
                origin.setLongitude(longitude);
                origin.setLatitude(latitude);
                destination.setLongitude(116.40528);
                destination.setLatitude(39.90498);
                OrderRouteAndFareDto dto = new OrderRouteAndFareDto();
                dto.setOrderId(Long.parseLong(orderId));
                dto.setOrigin(origin);
                dto.setDestination(destination);
                R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto);
                if (200 != routeVoR.getCode()) {
                    throw new RuntimeException("获取订单线路和运费失败");
                }
                RouteVo routeVo = routeVoR.getData();
                routeID = routeVo.getRouteID();
//                vehicleId = xpOrder.getVehicleId();
                //响应消息
                responseMessage(sequence, "");
            } else {
                orderType = OrderType.USER_ORDER;
                //正常单
                R<XpOrder> xpOrderR = xpOrderClient.queryOrderById(Long.parseLong(orderId));
                if (200 != xpOrderR.getCode()) {
@@ -466,50 +428,31 @@
                    origin.setLatitude(latitude);
                    destination.setLongitude(xpOrder.getStartLon());
                    destination.setLatitude(xpOrder.getStartLat());
                    OrderRouteAndFareDto dto = new OrderRouteAndFareDto();
                    dto.setOrderId(Long.parseLong(orderId));
                    dto.setOrigin(origin);
                    dto.setDestination(destination);
                    R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto);
                    if (200 != routeVoR.getCode()) {
                        throw new RuntimeException("获取订单线路和运费失败");
                    }
                    RouteVo routeVo = routeVoR.getData();
                    routeID = routeVo.getRouteID();
                    //缓存数据,用于后续推给乘客导航线路
                    redisService.setCacheObject("ORDER_NAVIGATION_START_DATA:" + xpOrder.getAppUserId(), com.alibaba.fastjson.JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS);
                }
                //驶往下车点的行程
                if (Arrays.asList(6).contains(xpOrder.getStatus())) {
                    //查询起点到终点的线路
                    origin.setLongitude(longitude);
                    origin.setLatitude(latitude);
                    destination.setLongitude(xpOrder.getEndLon());
                    destination.setLatitude(xpOrder.getEndLat());
                    OrderRouteAndFareDto dto = new OrderRouteAndFareDto();
                    dto.setOrderId(Long.parseLong(orderId));
                    dto.setOrigin(origin);
                    dto.setDestination(destination);
                    R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto);
                    if (200 != routeVoR.getCode()) {
                        throw new RuntimeException("获取订单线路和运费失败");
                    }
                    RouteVo routeVo = routeVoR.getData();
                    routeID = routeVo.getRouteID();
                    //缓存导航数据,用于后面的逻辑中给乘客端推送导航数据
                    redisService.setCacheObject("ORDER_NAVIGATION_END_DATA:" + xpOrder.getAppUserId(), com.alibaba.fastjson.JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS);
                }
            }
            if(StringUtils.isNotEmpty(routeID)){
                XpVehicle xpVehicle = xpVehicleClient.queryById(vehicleId).getData();
                R<String> stringR = xpMapClient.queryRouted(routeID);
                OrderRouteAndFareDto dto = new OrderRouteAndFareDto();
                dto.setOrderId(Long.parseLong(orderId));
                dto.setOrigin(origin);
                dto.setDestination(destination);
                R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto);
                if (200 != routeVoR.getCode()) {
                    throw new RuntimeException("获取订单线路和运费失败");
                }
                RouteVo routeVo = routeVoR.getData();
                R<String> stringR = xpMapClient.queryRouted(routeVo.getRouteID());
                if (200 != stringR.getCode()) {
                    throw new RuntimeException("根据导航ID获取车端需要的导航数据失败");
                }
                //构建导航下发请求对象
                cloudPushNavigationInfo(requestId, routeID, stringR.getData(), orderType, orderId, xpVehicle.getVehicleVin(), xpVehicle.getXpuId());
                cloudPushNavigationInfo(requestId, routeVo.getRouteID(), stringR.getData(), orderId, xpVehicle.getVehicleVin(), xpVehicle.getXpuId());
            }
        }
    }
@@ -525,53 +468,30 @@
        //订单类型  1:乘客订单,2=巡游订单
        LonLatDto destination = new LonLatDto();
        LonLatDto origin = new LonLatDto();
        //导航id
        String routeID = "";
        Long vehicleId = null;
        String orderType = "";
        if (orderId.contains("XU")) {
            // todo 下发巡游单的导航数据
            orderType = OrderType.CRUISE_ORDER;
            //巡游单
            if (orderPhase.equals(OrderPhase.ROUTE_TO_CRUISE)) {
                origin.setLongitude(116.40528);
                origin.setLatitude(39.90498);
                destination.setLongitude(116.40528);
                destination.setLatitude(39.90498);
                //先响应消息
                responseMessage(sequence, "");
                /* 构建导航数据给到车端 */
                R<XpCruiseOrder> cruiseOrder = xpCruiseOrderClient.getCruiseOrder(orderId);
                XpCruiseOrder xpCruiseOrder = cruiseOrder.getData();
                origin.setLongitude(xpCruiseOrder.getStartLon());
                origin.setLatitude(xpCruiseOrder.getStartLat());
                destination.setLongitude(xpCruiseOrder.getEndLon());
                destination.setLatitude(xpCruiseOrder.getEndLat());
                OrderRouteAndFareDto dto = new OrderRouteAndFareDto();
                dto.setOrderId(Long.parseLong(orderId));
                dto.setOrigin(origin);
                dto.setDestination(destination);
                R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto);
                if (200 != routeVoR.getCode()) {
                    throw new RuntimeException("获取订单线路和运费失败");
                }
                RouteVo routeVo = routeVoR.getData();
                routeID = routeVo.getRouteID();
//                vehicleId = xpOrder.getVehicleId();
            }
        } else {
            orderType = OrderType.USER_ORDER;
            //正常单
            R<XpOrder> xpOrderR = xpOrderClient.queryOrderById(Long.parseLong(orderId));
            if (200 != xpOrderR.getCode()) {
                throw new RuntimeException("订单不存在");
            }
            XpOrder xpOrder = xpOrderR.getData();
            XpVehicle xpVehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData();
            //先响应消息
            responseMessage(sequence, xpVehicle.getVehicleVin());
            //驶往上车点的行程
            if (orderPhase.equals(OrderPhase.ROUTE_TO_PICKUP)) {
                XpVehicle xpVehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData();
                //先响应消息
                responseMessage(sequence, xpVehicle.getVehicleVin());
                //查询车辆位置
                VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class);
                if (Objects.isNull(vehiclePosition)) {
@@ -582,59 +502,32 @@
                origin.setLatitude(vehiclePosition.getPoint().getY());
                destination.setLongitude(xpOrder.getStartLon());
                destination.setLatitude(xpOrder.getStartLat());
                OrderRouteAndFareDto dto = new OrderRouteAndFareDto();
                dto.setOrderId(Long.parseLong(orderId));
                dto.setOrigin(origin);
                dto.setDestination(destination);
                R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto);
                if (200 != routeVoR.getCode()) {
                    throw new RuntimeException("获取订单线路和运费失败");
                }
                RouteVo routeVo = routeVoR.getData();
                routeID = routeVo.getRouteID();
                //缓存数据,用于后续推给乘客导航线路
                redisService.setCacheObject("ORDER_NAVIGATION_START_DATA:" + xpOrder.getAppUserId(), com.alibaba.fastjson.JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS);
            }
            //驶往下车点的行程
            if (orderPhase.equals(OrderPhase.ROUTE_TO_DESTINATION)) {
                //直接取缓存中的导航数据推送给车端和乘客
                Object cacheObject = redisService.getCacheObject("ORDER_NAVIGATION_DATA:" + xpOrder.getAppUserId());
                if(null == cacheObject){
                    //没有缓存数据,重新规划线路
                    //查询起点到终点的线路
                    origin.setLongitude(xpOrder.getStartLon());
                    origin.setLatitude(xpOrder.getStartLat());
                    destination.setLongitude(xpOrder.getEndLon());
                    destination.setLatitude(xpOrder.getEndLat());
                    OrderRouteAndFareDto dto = new OrderRouteAndFareDto();
                    dto.setOrderId(Long.parseLong(orderId));
                    dto.setOrigin(origin);
                    dto.setDestination(destination);
                    R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto);
                    if (200 != routeVoR.getCode()) {
                        throw new RuntimeException("获取订单线路和运费失败");
                    }
                    RouteVo routeVo = routeVoR.getData();
                    routeID = routeVo.getRouteID();
                    //缓存导航数据,用于后面的逻辑中给乘客端推送导航数据
                    redisService.setCacheObject("ORDER_NAVIGATION_END_DATA:" + xpOrder.getAppUserId(), com.alibaba.fastjson.JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS);
                }else{
                    RouteVo routeVo = JSON.parseObject(cacheObject.toString(), RouteVo.class);
                    routeID = routeVo.getRouteID();
                }
                //查询起点到终点的线路
                origin.setLongitude(xpOrder.getStartLon());
                origin.setLatitude(xpOrder.getStartLat());
                destination.setLongitude(xpOrder.getEndLon());
                destination.setLatitude(xpOrder.getEndLat());
            }
            vehicleId = xpOrder.getVehicleId();
        }
        if(StringUtils.isNotEmpty(routeID)){
            XpVehicle xpVehicle = xpVehicleClient.queryById(vehicleId).getData();
            R<String> stringR = xpMapClient.queryRouted(routeID);
            OrderRouteAndFareDto dto = new OrderRouteAndFareDto();
            dto.setOrderId(Long.parseLong(orderId));
            dto.setOrigin(origin);
            dto.setDestination(destination);
            //TODO 这里的routeID不应该每次都重新生成,应该有一个缓存,调用的接口有做缓存但是没有读取缓存
            R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto);
            if (200 != routeVoR.getCode()) {
                throw new RuntimeException("获取订单线路和运费失败");
            }
            XpVehicle xpVehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData();
            RouteVo routeVo = routeVoR.getData();
            R<String> stringR = xpMapClient.queryRouted(routeVo.getRouteID());
            if (200 != stringR.getCode()) {
                throw new RuntimeException("根据导航ID获取车端需要的导航数据失败");
            }
            //构建导航下发请求对象
            cloudPushNavigationInfo(requestId, routeID, stringR.getData(), orderType, orderId, xpVehicle.getVehicleVin(), xpVehicle.getXpuId());
            cloudPushNavigationInfo(requestId, routeVo.getRouteID(), stringR.getData(), orderId, xpVehicle.getVehicleVin(), xpVehicle.getXpuId());
        }
    }
@@ -646,44 +539,44 @@
     */
    public void cloudOrderOperation(Integer orderType, String orderId, String taskId, RouteVo routeVo, String vin) {
        //构建消息体
        OrderOperation orderOperation = new OrderOperation();
        orderOperation.setOrder_id(orderId);
        orderOperation.setTask_id(taskId);
        orderOperation.setOperation_type(OrderOperationType.CLOUD_UPDATE_WAYPOINTS);
        OrderOperation.Builder orderOperationBuilder = OrderOperation.newBuilder();
        orderOperationBuilder.setOrderId(orderId);
        orderOperationBuilder.setTaskId(taskId);
        orderOperationBuilder.setOperationType(OrderOperationType.CLOUD_UPDATE_WAYPOINTS);
        //构建航点
        List<Waypoint> waypoints = new ArrayList<>();
        List<LonLatDto> polyline = routeVo.getPolyline();
        for (int i = 0; i < polyline.size(); i++) {
            LonLatDto lonLatDto = polyline.get(i);
            Waypoint waypoint = new Waypoint();
            waypoint.setWaypoint_id(UUID.randomUUID().toString());
            Waypoint.Builder waypointBuilder = Waypoint.newBuilder();
            waypointBuilder.setWaypointId(UUID.randomUUID().toString());
            if (0 == i) {
                waypoint.setPoint_type(PointType.START_POINT);
                waypointBuilder.setPointType(PointType.START_POINT);
                //订单类型不同,点位的动作类型不同
                waypoint.setAction_type(1 == orderType ? ActionType.PICK_UP : ActionType.ACTION_UNSPECIFIED);
                waypointBuilder.setActionType(1 == orderType ? ActionType.PICK_UP : ActionType.ACTION_UNSPECIFIED);
            } else if (polyline.size() - 1 == i) {
                waypoint.setPoint_type(PointType.END_POINT);
                waypoint.setAction_type(1 == orderType ? ActionType.DROP_OFF : ActionType.ACTION_UNSPECIFIED);
                waypointBuilder.setPointType(PointType.END_POINT);
                waypointBuilder.setActionType(1 == orderType ? ActionType.DROP_OFF : ActionType.ACTION_UNSPECIFIED);
            } else {
                waypoint.setPoint_type(PointType.WAY_POINT);
                waypointBuilder.setPointType(PointType.WAY_POINT);
                //订单类型不同,点位的动作类型不同
                waypoint.setAction_type(ActionType.ACTION_UNSPECIFIED);
                waypointBuilder.setActionType(ActionType.ACTION_UNSPECIFIED);
            }
            //构建经纬度
            GeoPoint geoPoint = new GeoPoint();
            geoPoint.setLongitude(lonLatDto.getLongitude());
            geoPoint.setLatitude(lonLatDto.getLatitude());
            waypoint.setPoint(geoPoint);
            waypoint.setSequence(i + 1);
            waypoints.add(waypoint);
            GeoPoint.Builder geoPointBuilder = GeoPoint.newBuilder();
            geoPointBuilder.setLongitude(lonLatDto.getLongitude());
            geoPointBuilder.setLatitude(lonLatDto.getLatitude());
            waypointBuilder.setPoint(geoPointBuilder.build());
            waypointBuilder.setSequence(i + 1);
            waypoints.add(waypointBuilder.build());
        }
        orderOperation.setWaypoints(waypoints);
        orderOperationBuilder.addAllWaypoints(waypoints);
        long sequence = snowflake.nextId();
        // 处理数据
        redisTemplate.opsForValue().set(sequence,"pushOrder_"+orderId+"_"+vin,30, TimeUnit.MINUTES);
        //开发发送请求到XPU
        xpuUtil.cloudOrderOperation(orderOperation, vin,sequence);
        xpuUtil.cloudOrderOperation(orderOperationBuilder.build(), vin,sequence);
    }
@@ -691,11 +584,11 @@
     * 构建响应消息
     */
    public void responseMessage(Long request_seq, String vin) {
        ResponseMessage responseMessage = new ResponseMessage();
        responseMessage.setRequest_seq(request_seq);
        responseMessage.setCode(StatusCode.OK);
        responseMessage.setTimestamp(System.currentTimeMillis());
        xpuUtil.responseMessage(responseMessage, vin);
        ResponseMessage.Builder responseMessageBuilder = ResponseMessage.newBuilder();
        responseMessageBuilder.setRequestSeq(request_seq);
        responseMessageBuilder.setCode(StatusCode.OK);
        responseMessageBuilder.setTimestamp(System.currentTimeMillis());
        xpuUtil.responseMessage(responseMessageBuilder.build(), vin);
    }
@@ -799,6 +692,7 @@
        if(orderId.contains("XU")){
            //巡游单
            //响应消息
            // TODO 1.处理结束当前巡游订单  2.创建新的巡游订单 返航  3.调用xpu车机接口  (判断是返航还是正常  返航需要存储之前的订单id)
            responseMessage(sequence, "");
            //前往目的地
            if(OrderStatusEnum.IN_SERVICE.equals(status)){
@@ -807,48 +701,6 @@
            //到达目的地
            if(OrderStatusEnum.COMPLETED.equals(status)){
                // 返程找到目前的订单 -》之前的订单 查询生成一个   正常巡游 找到下一个点位   若到达最后点位  则反向找点位  每次判断是否收车状态 是则不进行处理了
                // 找到这个订单
                R<XpCruiseOrder> cruiseOrder = xpCruiseOrderClient.getCruiseOrder(orderId);
                if(cruiseOrder!=null){
                    XpCruiseOrder xpCruiseOrder = cruiseOrder.getData();
                    Long vehicleId = xpCruiseOrder.getVehicleId();
                    // 关闭当前巡游单子 已完成
                    xpCruiseOrderClient.closeCruiseOrder(xpCruiseOrder.getVehicleVin());
                    R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(vehicleId);
                    XpVehicle xpVehicle = xpVehicleR.getData();
                    // 运营中 继续执行
                    if(xpVehicle.getOperatingStatus()==1 && xpVehicle.getState()==0){
                        // 创建新的巡游单子  判断是否为返程单子
                        if(xpCruiseOrder.getOrderType()==2){
                            R<XpCruiseOrder> lastOrder = xpCruiseOrderClient.getCruiseOrder(xpCruiseOrder.getLastOrderId());
                            XpCruiseOrder lastXpCruiseOrder = lastOrder.getData();
                            // 修改一下id 加一个一样的巡游单子
                            lastXpCruiseOrder.setId("XU"+ IdUtil.fastUUID());
                            lastXpCruiseOrder.setStatus(1);
                            xpCruiseOrderClient.addCruiseOrder(lastXpCruiseOrder);
                            RTTask task = new RTTask();
                            task.setOrder_id(lastXpCruiseOrder.getId());
                            task.setTask_id("MISSION_"+ IdUtil.fastUUID());
                            task.setTask_type(TaskType.CRUISE);
                            task.setStatus(TaskStatus.PENDING);
                            SnowFlake snowFlake = new SnowFlake(0, 0);
                            snowFlake.withStartTimestamp(1420041600000L);
                            long sequence1 = snowFlake.nextId();
                            xpuUtil.cloudCreateOrder(task, xpVehicle.getVehicleVin(),sequence1);
                        }else if(xpCruiseOrder.getOrderType()==1){
                           // 正常巡游 找到下一个点位   若到达最后点位  则反向找点位 TODO v
                        }
                    }
                }
            }
        }else{
            //普通单
@@ -887,22 +739,17 @@
     * @param vin                   车辆VIN
     * @param xpuId                 XPU设备id
     */
    public void cloudPushNavigationInfo(String requestId, String routeId, String routeDataContent, String orderType, String orderId, String vin, String xpuId) {
    public void cloudPushNavigationInfo(String requestId, String routeId, String routeDataContent, String orderId, String vin, String xpuId) {
        //组装报文,将routeDateContent信息推送到XPU
        RestoreNavigationData navigationData = new RestoreNavigationData();
        navigationData.setRoute_id(routeId);
        navigationData.setRequest_id(requestId);
        navigationData.setContent(routeDataContent);
        navigationData.setTimestamp(System.currentTimeMillis());
        RestoreNavigationData.Builder navigationDataBuilder = RestoreNavigationData.newBuilder();
        navigationDataBuilder.setRouteId(routeId);
        navigationDataBuilder.setRequestId(requestId);
        navigationDataBuilder.setContent(routeDataContent);
        navigationDataBuilder.setTimestamp(System.currentTimeMillis());
        long sequence = snowflake.nextId();
        // 处理数据
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("event", SystemEventType.PUSH_NAVIGATION);
        jsonObject.put("orderType", orderType);
        jsonObject.put("orderId", orderId);
        jsonObject.put("vin", vin);
        redisTemplate.opsForValue().set(sequence, jsonObject.toJSONString(),30, TimeUnit.MINUTES);
        xpuUtil.cloudPushNavigation(navigationData, xpuId, sequence);
        redisTemplate.opsForValue().set(sequence,"pushOrder_"+orderId+"_"+vin,30, TimeUnit.MINUTES);
        xpuUtil.cloudPushNavigation(navigationDataBuilder.build(), xpuId, sequence);
    }
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/util/XPUUtil.java
@@ -12,6 +12,7 @@
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.RTTask;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.OrderOperation;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudPushNavigation.RestoreNavigationData;
import com.xiaopeng.api.vo.automaticPilot.protobuf.RtTaskList;
import com.xiaopeng.common.core.utils.StringUtils;
import com.xiaopeng.common.core.utils.uuid.UUID;
import lombok.extern.slf4j.Slf4j;
@@ -51,24 +52,28 @@
     * @return
     */
    //TODO 处理feign调用的异常
    public MqttPublishDto cloudCreateOrder(RTTask task, String vin, Long sequence) {
        MsgContent msgContent = new MsgContent();
    public MqttPublishDto cloudCreateOrder(RtTaskList taskList, String vin, Long sequence) {
        com.xiaopeng.api.vo.automaticPilot.protobuf.MsgContent.Builder msgContentBuilder = com.xiaopeng.api.vo.automaticPilot.protobuf.MsgContent.newBuilder();
        // 消息头
        RtMsgHeader header = new RtMsgHeader();
        header.setMsg_id(UUID.randomUUID().toString());
        header.setTimestamp(System.currentTimeMillis());
        header.setCmd(RTCmdType.CLOUD_CREATE_ORDER);
        header.setSequence(sequence);
        header.setType(MessageType.MESSAGE_TYPE_REQUEST);
        header.setSource(SourceType.CLOUD);
        msgContent.setHeader(header);
        // 消息内容
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("task", task);
        msgContent.setContent_detail(jsonObject);
        com.xiaopeng.api.vo.automaticPilot.protobuf.MsgHeader.Builder headerBuilder = com.xiaopeng.api.vo.automaticPilot.protobuf.MsgHeader.newBuilder();
        headerBuilder.setMsgId(UUID.randomUUID().toString());
        headerBuilder.setTimestamp(System.currentTimeMillis());
        headerBuilder.setCmd(RTCmdType.CLOUD_CREATE_ORDER.getValue());
        headerBuilder.setSequence(sequence);
        headerBuilder.setType(com.xiaopeng.api.vo.automaticPilot.protobuf.MessageType.MESSAGE_TYPE_REQUEST);
        headerBuilder.setSource(com.xiaopeng.api.vo.automaticPilot.protobuf.SourceType.CLOUD);
        msgContentBuilder.setHeader(headerBuilder.build());
        msgContentBuilder.setRtTaskList(taskList);
        MqttPublishVo vo = new MqttPublishVo();
        vo.setTopic(buildTopicByVin(vin));
        vo.setPayload(JSON.toJSONString(msgContent));
        try {
            vo.setPayload(com.google.protobuf.util.JsonFormat.printer().print(msgContentBuilder.build()));
        } catch (Exception e) {
            log.error("Protobuf转JSON失败", e);
            throw new RuntimeException("Protobuf转JSON失败", e);
        }
        log.info("云端-->XPU 创建订单:{}", vo);
        return xpuClient.publish(vo);
@@ -81,24 +86,28 @@
     * @return
     */
    //TODO 处理feign调用的异常
    public MqttPublishDto cloudOrderOperation(OrderOperation operation, String vin, Long sequence) {
        MsgContent msgContent = new MsgContent();
    public MqttPublishDto cloudOrderOperation(com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperation operation, String vin, Long sequence) {
        com.xiaopeng.api.vo.automaticPilot.protobuf.MsgContent.Builder msgContentBuilder = com.xiaopeng.api.vo.automaticPilot.protobuf.MsgContent.newBuilder();
        // 消息头
        RtMsgHeader header = new RtMsgHeader();
        header.setMsg_id(UUID.randomUUID().toString());
        header.setTimestamp(System.currentTimeMillis());
        header.setCmd(RTCmdType.CLOUD_ORDER_OPERATION);
        header.setSequence(sequence);
        header.setType(MessageType.MESSAGE_TYPE_REQUEST);
        header.setSource(SourceType.CLOUD);
        msgContent.setHeader(header);
        // 消息内容
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("operation", operation);
        msgContent.setContent_detail(jsonObject);
        com.xiaopeng.api.vo.automaticPilot.protobuf.MsgHeader.Builder headerBuilder = com.xiaopeng.api.vo.automaticPilot.protobuf.MsgHeader.newBuilder();
        headerBuilder.setMsgId(UUID.randomUUID().toString());
        headerBuilder.setTimestamp(System.currentTimeMillis());
        headerBuilder.setCmd(RTCmdType.CLOUD_ORDER_OPERATION.getValue());
        headerBuilder.setSequence(sequence);
        headerBuilder.setType(com.xiaopeng.api.vo.automaticPilot.protobuf.MessageType.MESSAGE_TYPE_REQUEST);
        headerBuilder.setSource(com.xiaopeng.api.vo.automaticPilot.protobuf.SourceType.CLOUD);
        msgContentBuilder.setHeader(headerBuilder.build());
        msgContentBuilder.setOrderOperation(operation);
        MqttPublishVo vo = new MqttPublishVo();
        vo.setTopic(buildTopicByVin(vin));
        vo.setPayload(JSON.toJSONString(msgContent));
        try {
            vo.setPayload(com.google.protobuf.util.JsonFormat.printer().print(msgContentBuilder.build()));
        } catch (Exception e) {
            log.error("Protobuf转JSON失败", e);
            throw new RuntimeException("Protobuf转JSON失败", e);
        }
        log.info("云端-->XPU 修改订单:{}", vo);
        return xpuClient.publish(vo);
@@ -113,25 +122,29 @@
     * @param responseMessage
     * @return
     */
    public MqttPublishDto responseMessage(ResponseMessage responseMessage, String vin) {
        MsgContent msgContent = new MsgContent();
    public MqttPublishDto responseMessage(com.xiaopeng.api.vo.automaticPilot.protobuf.ResponseMessage responseMessage, String vin) {
        com.xiaopeng.api.vo.automaticPilot.protobuf.MsgContent.Builder msgContentBuilder = com.xiaopeng.api.vo.automaticPilot.protobuf.MsgContent.newBuilder();
        // 消息头
        RtMsgHeader header = new RtMsgHeader();
        header.setMsg_id(UUID.randomUUID().toString());
        header.setTimestamp(System.currentTimeMillis());
        header.setCmd(RTCmdType.CLOUD_TASK_CONTROL);
        com.xiaopeng.api.vo.automaticPilot.protobuf.MsgHeader.Builder headerBuilder = com.xiaopeng.api.vo.automaticPilot.protobuf.MsgHeader.newBuilder();
        headerBuilder.setMsgId(UUID.randomUUID().toString());
        headerBuilder.setTimestamp(System.currentTimeMillis());
        headerBuilder.setCmd(RTCmdType.CLOUD_TASK_CONTROL.getValue());
        Snowflake snowflake = IdUtil.getSnowflake(0, 0);
        header.setSequence(snowflake.nextId());
        header.setType(MessageType.MESSAGE_TYPE_RESPONSE);
        header.setSource(SourceType.CLOUD);
        msgContent.setHeader(header);
        // 消息内容
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("resposne", responseMessage);
        msgContent.setContent_detail(jsonObject);
        headerBuilder.setSequence(snowflake.nextId());
        headerBuilder.setType(com.xiaopeng.api.vo.automaticPilot.protobuf.MessageType.MESSAGE_TYPE_RESPONSE);
        headerBuilder.setSource(com.xiaopeng.api.vo.automaticPilot.protobuf.SourceType.CLOUD);
        msgContentBuilder.setHeader(headerBuilder.build());
        msgContentBuilder.setResponse(responseMessage);
        MqttPublishVo vo = new MqttPublishVo();
        vo.setTopic(buildTopicByVin(vin));
        vo.setPayload(JSON.toJSONString(msgContent));
        try {
            vo.setPayload(com.google.protobuf.util.JsonFormat.printer().print(msgContentBuilder.build()));
        } catch (Exception e) {
            log.error("Protobuf转JSON失败", e);
            throw new RuntimeException("Protobuf转JSON失败", e);
        }
        log.info("云端-->XPU 响应消息:{}", vo);
        return xpuClient.publish(vo);
@@ -144,24 +157,28 @@
     * @return
     */
    //TODO 处理feign调用的异常
    public MqttPublishDto cloudPushNavigation(RestoreNavigationData navigationData, String xpuId, Long sequence) {
        MsgContent msgContent = new MsgContent();
    public MqttPublishDto cloudPushNavigation(com.xiaopeng.api.vo.automaticPilot.protobuf.RestoreNavigationData navigationData, String xpuId, Long sequence) {
        com.xiaopeng.api.vo.automaticPilot.protobuf.MsgContent.Builder msgContentBuilder = com.xiaopeng.api.vo.automaticPilot.protobuf.MsgContent.newBuilder();
        // 消息头
        RtMsgHeader header = new RtMsgHeader();
        header.setMsg_id(UUID.randomUUID().toString());
        header.setTimestamp(System.currentTimeMillis());
        header.setCmd(RTCmdType.CLOUD_NAVIGATION_RESPONSE);
        header.setSequence(sequence);
        header.setType(MessageType.MESSAGE_TYPE_RESPONSE);
        header.setSource(SourceType.CLOUD);
        msgContent.setHeader(header);
        // 消息内容
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("navigationData", navigationData);
        msgContent.setContent_detail(jsonObject);
        com.xiaopeng.api.vo.automaticPilot.protobuf.MsgHeader.Builder headerBuilder = com.xiaopeng.api.vo.automaticPilot.protobuf.MsgHeader.newBuilder();
        headerBuilder.setMsgId(UUID.randomUUID().toString());
        headerBuilder.setTimestamp(System.currentTimeMillis());
        headerBuilder.setCmd(RTCmdType.CLOUD_NAVIGATION_RESPONSE.getValue());
        headerBuilder.setSequence(sequence);
        headerBuilder.setType(com.xiaopeng.api.vo.automaticPilot.protobuf.MessageType.MESSAGE_TYPE_RESPONSE);
        headerBuilder.setSource(com.xiaopeng.api.vo.automaticPilot.protobuf.SourceType.CLOUD);
        msgContentBuilder.setHeader(headerBuilder.build());
        msgContentBuilder.setRestoreNavigationData(navigationData);
        MqttPublishVo vo = new MqttPublishVo();
        vo.setTopic(buildTopicByXpuId(xpuId));
        vo.setPayload(JSON.toJSONString(msgContent));
        try {
            vo.setPayload(com.google.protobuf.util.JsonFormat.printer().print(msgContentBuilder.build()));
        } catch (Exception e) {
            log.error("Protobuf转JSON失败", e);
            throw new RuntimeException("Protobuf转JSON失败", e);
        }
        log.info("云端-->XPU 下发导航信息:{}", vo);
        return xpuClient.publish(vo);
xp-robotaxi-automatic-pilot-boot/src/test/java/com/xiaopeng/automaticPilot/util/XPUUtilTest.java
@@ -4,12 +4,18 @@
import com.xiaopeng.api.feignClient.automaticPilot.VmpOpenServiceClient;
import com.xiaopeng.api.feignClient.automaticPilot.XPUClient;
import com.xiaopeng.api.vo.automaticPilot.MqttPublishVo;
import com.xiaopeng.api.vo.automaticPilot.proto.down.GeoPoint;
import com.xiaopeng.api.vo.automaticPilot.proto.down.ResponseMessage;
import com.xiaopeng.api.vo.automaticPilot.proto.down.StatusCode;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.*;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.*;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudPushNavigation.RestoreNavigationData;
import com.xiaopeng.api.vo.automaticPilot.protobuf.RtTask;
import com.xiaopeng.api.vo.automaticPilot.protobuf.RtTaskList;
import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderType;
import com.xiaopeng.api.vo.automaticPilot.protobuf.Waypoint;
import com.xiaopeng.api.vo.automaticPilot.protobuf.PointType;
import com.xiaopeng.api.vo.automaticPilot.protobuf.ActionType;
import com.xiaopeng.api.vo.automaticPilot.protobuf.GeoPoint;
import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperation;
import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperationType;
import com.xiaopeng.api.vo.automaticPilot.protobuf.ResponseMessage;
import com.xiaopeng.api.vo.automaticPilot.protobuf.StatusCode;
import com.xiaopeng.api.vo.automaticPilot.protobuf.RestoreNavigationData;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -21,6 +27,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class XPUUtilTest {
@@ -70,125 +77,135 @@
    public void testCloudCreateOrder() {
        String orderId = "1881347710714060802";
        RTTask task = new RTTask();
        task.setTask_id("task-123");
        task.setOrder_id(orderId);
        task.setVin("VIN12345678900000");
        task.setTask_type(TaskType.ROBOTAXI);
        task.setStatus(TaskStatus.PENDING);
        RtTask.Builder taskBuilder = RtTask.newBuilder();
        taskBuilder.setTaskId("task-123");
        taskBuilder.setOrderId(orderId);
        // taskBuilder.setVin("VIN12345678900000"); // RtTask might not have vin, check proto if needed
        taskBuilder.setTaskType(OrderType.ORDER_TYPE_ROBOTAXI);
        // taskBuilder.setStatus(TaskStatus.PENDING); // RtTask might not have status or enum differs
        Waypoint.Builder pointBuilder = Waypoint.newBuilder();
        pointBuilder.setPointType(PointType.START_POINT);
        pointBuilder.setActionType(ActionType.PICK_UP);
        pointBuilder.setSequence(1);
        
        NavigationWaypoint point = new NavigationWaypoint();
        point.setType(WaypointType.START_POINT);
        point.setAction(WaypointAction.PICK_UP);
        point.setSequence(1);
        GeoPoint geoPoint = new GeoPoint();
        geoPoint.setLatitude(30.0);
        geoPoint.setLongitude(120.0);
        geoPoint.setPoi_name("Start Point");
        point.setPoint(geoPoint);
        GeoPoint.Builder geoPointBuilder = GeoPoint.newBuilder();
        geoPointBuilder.setLatitude(30.0);
        geoPointBuilder.setLongitude(120.0);
        // geoPointBuilder.setPoiName("Start Point"); // GeoPoint might not have poi_name
        pointBuilder.setPoint(geoPointBuilder.build());
        // taskBuilder.addPoints(pointBuilder.build()); // RtTask might use different field for points?
        // Wait, RtTask in XPUUtil.cloudCreateOrder(RtTaskList taskList...)
        // So I need to build RtTaskList
        
        task.setPoints(Collections.singletonList(point));
        RtTaskList.Builder taskListBuilder = RtTaskList.newBuilder();
        taskListBuilder.addTasks(taskBuilder.build());
        String vin = "VIN12345678900000";
        Long sequence = 1L;
        xpuUtil.cloudCreateOrder(task, vin, sequence);
        xpuUtil.cloudCreateOrder(taskListBuilder.build(), vin, sequence);
        ArgumentCaptor<MqttPublishVo> captor = ArgumentCaptor.forClass(MqttPublishVo.class);
        Mockito.verify(xpuClient).publish(captor.capture());
        MqttPublishVo capturedVo = captor.getValue();
        Assertions.assertEquals("Robotaxi/Msg/Xpu/ABCDEFGHIJKL00000000", capturedVo.getTopic());
        // Note: Current implementation serializes enum as ordinal. CLOUD_CREATE_ORDER is ordinal 2.
        Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\":2"), "Payload should contain cmd CLOUD_CREATE_ORDER (ordinal 2), but was: " + capturedVo.getPayload());
        // Note: Current implementation serializes enum as ordinal.
        Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\": 10003"), "Payload should contain cmd CLOUD_CREATE_ORDER (10003), but was: " + capturedVo.getPayload());
    }
    @Test
    public void testCloudOrderOperation() {
        String orderId = "1881347710714060802";
        OrderOperation operation = new OrderOperation();
        operation.setOrder_id(orderId);
        operation.setTask_id("task-123");
        operation.setOperation_type(OrderOperationType.CLOUD_CREATE_ORDER);
        operation.setOrder_type(OrderType.ROBOTAXI);
        OrderOperation.Builder operationBuilder = OrderOperation.newBuilder();
        operationBuilder.setOrderId(orderId);
        operationBuilder.setTaskId("task-123");
        operationBuilder.setOperationType(OrderOperationType.CLOUD_CREATE_ORDER);
        operationBuilder.setOrderType(OrderType.ORDER_TYPE_ROBOTAXI);
        
        Waypoint waypoint = new Waypoint();
        waypoint.setWaypoint_id("wp-1");
        waypoint.setPoint_type(PointType.WAY_POINT);
        waypoint.setAction_type(ActionType.WAIT);
        waypoint.setSequence(2);
        Waypoint.Builder waypointBuilder = Waypoint.newBuilder();
        waypointBuilder.setWaypointId("wp-1");
        waypointBuilder.setPointType(PointType.WAY_POINT);
        // waypointBuilder.setActionType(ActionType.WAIT); // WAIT might not exist
        waypointBuilder.setActionType(ActionType.PICK_UP); // Use valid enum
        waypointBuilder.setSequence(2);
        
        GeoPoint geoPoint = new GeoPoint();
        geoPoint.setLatitude(30.1);
        geoPoint.setLongitude(120.1);
        geoPoint.setPoi_name("Way Point");
        waypoint.setPoint(geoPoint);
        GeoPoint.Builder geoPointBuilder = GeoPoint.newBuilder();
        geoPointBuilder.setLatitude(30.1);
        geoPointBuilder.setLongitude(120.1);
        // geoPointBuilder.setPoiName("Way Point");
        waypointBuilder.setPoint(geoPointBuilder.build());
        
        operation.setWaypoints(Collections.singletonList(waypoint));
        operationBuilder.addWaypoints(waypointBuilder.build());
        
        TargetPoint targetPoint = new TargetPoint();
        GeoPoint endGeoPoint = new GeoPoint();
        endGeoPoint.setLatitude(30.2);
        endGeoPoint.setLongitude(120.2);
        endGeoPoint.setPoi_name("End Point");
        targetPoint.setPoint(endGeoPoint);
        operation.setTarget_point(targetPoint);
        // TargetPoint targetPoint = new TargetPoint(); // OrderOperation uses Waypoint for target_point in proto?
        // Check proto: Waypoint target_point = 6;
        Waypoint.Builder targetPointBuilder = Waypoint.newBuilder();
        GeoPoint.Builder endGeoPointBuilder = GeoPoint.newBuilder();
        endGeoPointBuilder.setLatitude(30.2);
        endGeoPointBuilder.setLongitude(120.2);
        targetPointBuilder.setPoint(endGeoPointBuilder.build());
        operationBuilder.setTargetPoint(targetPointBuilder.build());
        String vin = "VIN12345678900000";
        Long sequence = 2L;
        xpuUtil.cloudOrderOperation(operation, vin, sequence);
        xpuUtil.cloudOrderOperation(operationBuilder.build(), vin, sequence);
        ArgumentCaptor<MqttPublishVo> captor = ArgumentCaptor.forClass(MqttPublishVo.class);
        Mockito.verify(xpuClient).publish(captor.capture());
        MqttPublishVo capturedVo = captor.getValue();
        
        Assertions.assertEquals("Robotaxi/Msg/Xpu/ABCDEFGHIJKL00000000", capturedVo.getTopic());
        // Note: CLOUD_ORDER_OPERATION is ordinal 0.
        Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\":0"), "Payload should contain cmd CLOUD_ORDER_OPERATION (ordinal 0), but was: " + capturedVo.getPayload());
        // Note: CLOUD_ORDER_OPERATION is 10001
        Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\": 10001"), "Payload should contain cmd CLOUD_ORDER_OPERATION (10001), but was: " + capturedVo.getPayload());
    }
    @Test
    public void testResponseMessage() {
        ResponseMessage responseMessage = new ResponseMessage();
        responseMessage.setRequest_seq(12345L);
        responseMessage.setCode(StatusCode.OK);
        responseMessage.setTimestamp(System.currentTimeMillis());
        ResponseMessage.Builder responseMessageBuilder = ResponseMessage.newBuilder();
        responseMessageBuilder.setRequestSeq(12345L);
        responseMessageBuilder.setCode(StatusCode.OK);
        responseMessageBuilder.setTimestamp(System.currentTimeMillis());
        String vin = "VIN12345678900000";
        xpuUtil.responseMessage(responseMessage, vin);
        xpuUtil.responseMessage(responseMessageBuilder.build(), vin);
        ArgumentCaptor<MqttPublishVo> captor = ArgumentCaptor.forClass(MqttPublishVo.class);
        Mockito.verify(xpuClient).publish(captor.capture());
        MqttPublishVo capturedVo = captor.getValue();
        
        Assertions.assertEquals("Robotaxi/Msg/Xpu/ABCDEFGHIJKL00000000", capturedVo.getTopic());
        // Note: CLOUD_TASK_CONTROL is ordinal 1.
        Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\":1"), "Payload should contain cmd CLOUD_TASK_CONTROL (ordinal 1), but was: " + capturedVo.getPayload());
        // Note: CLOUD_TASK_CONTROL (used in responseMessage method? check code)
        // In XPUUtil.java: headerBuilder.setCmd(RTCmdType.CLOUD_TASK_CONTROL.getValue());
        // CLOUD_TASK_CONTROL is 10002
        Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\": 10002"), "Payload should contain cmd CLOUD_TASK_CONTROL (10002), but was: " + capturedVo.getPayload());
    }
    @Test
    public void testCloudPushNavigation() {
        RestoreNavigationData navigationData = new RestoreNavigationData();
        navigationData.setRequest_id("req-123");
        navigationData.setRoute_id("5939fa259ad6479cbdf8871ceed96b72");
        RestoreNavigationData.Builder navigationDataBuilder = RestoreNavigationData.newBuilder();
        navigationDataBuilder.setRequestId("req-123");
        navigationDataBuilder.setRouteId("5939fa259ad6479cbdf8871ceed96b72");
        String content = "{\"startPoint\":{\"location\":\"116.481028,39.989643\"},\"endPoint\":{\"location\":\"116.465302,40.004717\"},\"routeID\":\"xxxxxxxxxxxxx\",\"strategy\":17,\"type\":1,\"ferry\":0,\"disableEndDispatch\":1,\"viaInfo\":[{},{}],\"routeUserType\":2,\"bizScene\":2,\"plate\":\"京A12345\",\"vehicleType\":1}";
        navigationData.setContent(content);
        navigationData.setTimestamp(System.currentTimeMillis());
        navigationDataBuilder.setContent(content);
        navigationDataBuilder.setTimestamp(System.currentTimeMillis());
        String xpuId = "1234567890ABCDEFGHIJKL";
        Long sequence = 3L;
        xpuUtil.cloudPushNavigation(navigationData, xpuId, sequence);
        xpuUtil.cloudPushNavigation(navigationDataBuilder.build(), xpuId, sequence);
        ArgumentCaptor<MqttPublishVo> captor = ArgumentCaptor.forClass(MqttPublishVo.class);
        Mockito.verify(xpuClient).publish(captor.capture());
        MqttPublishVo capturedVo = captor.getValue();
        
        Assertions.assertEquals("Robotaxi/Msg/Xpu/ABCDEFGHIJKL00000000", capturedVo.getTopic());
        // Note: CLOUD_NAVIGATION_RESPONSE is ordinal 5.
        Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\":5"), "Payload should contain cmd CLOUD_NAVIGATION_RESPONSE (ordinal 5), but was: " + capturedVo.getPayload());
        // Note: CLOUD_NAVIGATION_RESPONSE is 10006
        Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\": 10006"), "Payload should contain cmd CLOUD_NAVIGATION_RESPONSE (10006), but was: " + capturedVo.getPayload());
    }
}