From 05ba868736725db54db1944ed5cf7a95d14efc37 Mon Sep 17 00:00:00 2001
From: liusuyi <1951119284@qq.com>
Date: Wed, 30 Oct 2024 17:07:51 +0800
Subject: [PATCH] 增加:手动飞行控制

---
 ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandCmd.java                     |   33 +
 ard-work/src/main/java/com/ard/tianyu/netty/command/manual/PointControlReachedReplyCmd.java |   33 +
 ard-work/src/main/java/com/ard/tianyu/netty/handler/MessageProtocolDecoder.java             |   57 ++
 ard-work/src/main/java/com/ard/tianyu/netty/command/manual/FlyControlCmd.java               |   45 ++
 ard-work/src/main/java/com/ard/tianyu/service/impl/TyServiceImpl.java                       |  109 ++++
 ard-work/src/main/java/com/ard/tianyu/model/dto/manual/ReturnHomeDTO.java                   |    1 
 ard-work/src/main/java/com/ard/tianyu/netty/command/manual/ReturnHomeCancelReplyCmd.java    |   33 +
 ard-work/src/main/java/com/ard/tianyu/model/dto/manual/LandCancelDTO.java                   |   20 
 ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandReplyCmd.java                |   33 +
 ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandForcedReplyCmd.java          |   33 +
 ard-work/src/main/java/com/ard/tianyu/controller/UavManualFlyController.java                |   73 +++
 ard-work/src/main/java/com/ard/tianyu/model/dto/manual/LandForcedDTO.java                   |   20 
 ard-work/src/main/java/com/ard/tianyu/websocket/handler/TyMessageHandler.java               |   39 +
 ard-work/src/main/java/com/ard/tianyu/model/dto/manual/FlyPointControlCancelDTO.java        |   20 
 ard-work/src/main/java/com/ard/tianyu/model/dto/manual/EmeragencyBrakeDTO.java              |   23 +
 ard-work/src/main/java/com/ard/tianyu/model/dto/BoxSettingsDTO.java                         |   14 
 ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandCancelReplyCmd.java          |   33 +
 ard-work/src/main/java/com/ard/tianyu/controller/UavGimbalController.java                   |    3 
 ard-work/src/main/java/com/ard/tianyu/model/dto/manual/FlyPointControlDTO.java              |   46 ++
 ard-work/src/main/java/com/ard/tianyu/model/dto/manual/LandDTO.java                         |   20 
 ard-work/src/main/java/com/ard/tianyu/netty/command/manual/EmergencyBrakeReplyCmd.java      |   34 +
 ard-work/src/main/java/com/ard/tianyu/websocket/interceptor/TyHandshakeInterceptor.java     |   35 +
 ard-work/src/main/java/com/ard/tianyu/netty/command/manual/FlyPointControlCmd.java          |   46 ++
 ard-framework/src/main/java/com/ard/framework/config/SecurityConfig.java                    |    2 
 ard-work/src/main/java/com/ard/tianyu/http/TyClient.java                                    |    2 
 ard-work/src/main/java/com/ard/tianyu/service/ITyService.java                               |   45 +
 ard-work/pom.xml                                                                            |    5 
 /dev/null                                                                                   |   30 -
 ard-work/src/main/java/com/ard/tianyu/netty/command/manual/EmergencyBrakeCmd.java           |   35 +
 ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandCancelCmd.java               |   33 +
 ard-work/src/main/java/com/ard/tianyu/model/dto/manual/ReturnHomeCancelDTO.java             |   21 
 ard-work/src/main/java/com/ard/tianyu/websocket/utils/WebSocketUtil.java                    |  141 ++++++
 ard-work/src/main/java/com/ard/tianyu/websocket/config/WebSocketConfig.java                 |   27 +
 ard-work/src/main/java/com/ard/tianyu/model/dto/manual/FlyControlDTO.java                   |   40 +
 ard-work/src/main/java/com/ard/tianyu/netty/command/manual/FlyPointControlCancelCmd.java    |   32 +
 ard-work/src/main/java/com/ard/tianyu/netty/command/manual/ReturnHomeCancelCmd.java         |   33 +
 ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandForcedCmd.java               |   33 +
 37 files changed, 1,229 insertions(+), 53 deletions(-)

diff --git a/ard-framework/src/main/java/com/ard/framework/config/SecurityConfig.java b/ard-framework/src/main/java/com/ard/framework/config/SecurityConfig.java
index 86a2920..61b71ea 100644
--- a/ard-framework/src/main/java/com/ard/framework/config/SecurityConfig.java
+++ b/ard-framework/src/main/java/com/ard/framework/config/SecurityConfig.java
@@ -111,7 +111,7 @@
             .authorizeHttpRequests((requests) -> {
                 permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
                 // 对于登录login 注册register 验证码captchaImage 允许匿名访问
-                requests.antMatchers("/login", "/register", "/captchaImage").permitAll()
+                requests.antMatchers("/login", "/register", "/captchaImage", "/ws/**").permitAll()
                     // 静态资源,可匿名访问
                     .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                     .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
diff --git a/ard-work/pom.xml b/ard-work/pom.xml
index 9dd55b0..2214e30 100644
--- a/ard-work/pom.xml
+++ b/ard-work/pom.xml
@@ -55,6 +55,11 @@
             <artifactId>protobuf-java</artifactId>
             <version>3.20.1</version>
         </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/ard-work/src/main/java/com/ard/tianyu/controller/UavGimbalController.java b/ard-work/src/main/java/com/ard/tianyu/controller/UavGimbalController.java
index 22ff46d..93fc471 100644
--- a/ard-work/src/main/java/com/ard/tianyu/controller/UavGimbalController.java
+++ b/ard-work/src/main/java/com/ard/tianyu/controller/UavGimbalController.java
@@ -41,8 +41,7 @@
     private ITyService tyService;
 
 
-
-    @ApiOperation(value = "云台转动(基于角度)", notes = "actionCode值:0-回中,1-上,2-右上,3-右,4-右下,5-下,6-左下,7-左,8-左上,254-停止")
+    @ApiOperation(value = "云台转动(基于角度)", notes = "actionCode值:0-回中,1-上,2-右上,3-右,4-右下,5-下,6-左下,7-左,8-左上,254-停止 \r\n rotationAngle值:取值范围:0~255【云台实际转动角度= 转动角度/100+2.5 单位:度】")
     @ApiOperationSupport(order = 1)
     @PostMapping("/angleControl")
     public AjaxResult angleControl(@RequestBody AngleControlDTO angleControlDto) {
diff --git a/ard-work/src/main/java/com/ard/tianyu/controller/UavManualFlyController.java b/ard-work/src/main/java/com/ard/tianyu/controller/UavManualFlyController.java
index d90cab3..c77853f 100644
--- a/ard-work/src/main/java/com/ard/tianyu/controller/UavManualFlyController.java
+++ b/ard-work/src/main/java/com/ard/tianyu/controller/UavManualFlyController.java
@@ -1,9 +1,7 @@
 package com.ard.tianyu.controller;
 
 import com.ard.common.core.domain.AjaxResult;
-import com.ard.tianyu.model.dto.manual.ReturnHomeDTO;
-import com.ard.tianyu.model.dto.manual.SwitchUavControlDTO;
-import com.ard.tianyu.model.dto.manual.TakeOffDTO;
+import com.ard.tianyu.model.dto.manual.*;
 import com.ard.tianyu.service.ITyService;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
 import io.swagger.annotations.Api;
@@ -33,6 +31,7 @@
         tyService.switchUavControl(switchUavControlDTO);
         return AjaxResult.success();
     }
+
     @ApiOperation(value = "起飞", notes = "起飞高度height取值范围:1.2~100,误差:+-0.4米")
     @ApiOperationSupport(order = 2)
     @PostMapping("/takeOff")
@@ -48,4 +47,72 @@
         tyService.returnHome(returnHomeDTO);
         return AjaxResult.success();
     }
+
+    @ApiOperation("取消返航")
+    @ApiOperationSupport(order = 4)
+    @PostMapping("/returnHomeCancel")
+    public AjaxResult returnHomeCancel(@RequestBody ReturnHomeCancelDTO returnHomeCancelDTO) {
+        tyService.returnHomeCancel(returnHomeCancelDTO);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation("降落")
+    @ApiOperationSupport(order = 5)
+    @PostMapping("/land")
+    public AjaxResult land(@RequestBody LandDTO landDTO) {
+        tyService.land(landDTO);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation("取消降落")
+    @ApiOperationSupport(order = 6)
+    @PostMapping("/landCancel")
+    public AjaxResult landCancel(@RequestBody LandCancelDTO landCancelDTO) {
+        tyService.landCancel(landCancelDTO);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation("强制降落")
+    @ApiOperationSupport(order = 7)
+    @PostMapping("/landForced")
+    public AjaxResult landForced(@RequestBody LandForcedDTO landForcedDTO) {
+        tyService.landForced(landForcedDTO);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation(value = "方向控制", notes = "前后速度frSpeed:【前0至30 后0至-30】单位m/s " +
+            "左右速度lrSpeed:【右0至30 左0至-30】单位m/s  " +
+            "上下速度udSpeed:【上0至5 后0至-5 】单位m/s 偏航角yaw:-150~150 deg/s")
+    @ApiOperationSupport(order = 8)
+    @PostMapping("/flyControl")
+    public AjaxResult flyControl(@RequestBody FlyControlDTO flyControlDTO) {
+        tyService.flyControl(flyControlDTO);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation(value = "开始指点飞行", notes = "速度speed:0~20 单位m/s " +
+            "飞行模式flyMode:0-节能模式【飞机直线飞到目标点,需飞机在空中】," +
+            "1-安全模式【飞机飞行至目标点高度再平飞到目标点,飞机可以在地面或空中】 默认为节能模式")
+    @ApiOperationSupport(order = 9)
+    @PostMapping("/flyPointControl")
+    public AjaxResult flyPointControl(@RequestBody FlyPointControlDTO flyPointControlDTO) {
+        tyService.flyPointControl(flyPointControlDTO);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation("停止指点飞行")
+    @ApiOperationSupport(order = 10)
+    @PostMapping("/flyPointControlCancel")
+    public AjaxResult flyPointControlCancel(@RequestBody FlyPointControlCancelDTO flyPointControlCancelDTO) {
+        tyService.flyPointControlCancel(flyPointControlCancelDTO);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation(value = "紧急制动", notes = "动作参数actionParam: 0-解除紧急制动 1-紧急制动")
+    @ApiOperationSupport(order = 11)
+    @PostMapping("/emeragencyBrake")
+    public AjaxResult emeragencyBrake(@RequestBody EmeragencyBrakeDTO emeragencyBrakeDTO) {
+        tyService.emeragencyBrake(emeragencyBrakeDTO);
+        return AjaxResult.success();
+    }
 }
\ No newline at end of file
diff --git a/ard-work/src/main/java/com/ard/tianyu/http/TyClient.java b/ard-work/src/main/java/com/ard/tianyu/http/TyClient.java
index 303fa79..b67b86f 100644
--- a/ard-work/src/main/java/com/ard/tianyu/http/TyClient.java
+++ b/ard-work/src/main/java/com/ard/tianyu/http/TyClient.java
@@ -54,5 +54,5 @@
      * 修改云盒设置
      */
     @Post(TyConst.POST_BOX_UPDATE)
-    TyHttpCommonReceiver updateBoxSettings(@JSONBody BoxSettingsDTO boxSettingsDTO, @Header Map<String, String> headers);
+    TyHttpCommonReceiver<?> updateBoxSettings(@JSONBody BoxSettingsDTO boxSettingsDTO, @Header Map<String, String> headers);
 }
\ No newline at end of file
diff --git a/ard-work/src/main/java/com/ard/tianyu/model/dto/BoxSettingsDTO.java b/ard-work/src/main/java/com/ard/tianyu/model/dto/BoxSettingsDTO.java
index 5e607d5..bd6be4e 100644
--- a/ard-work/src/main/java/com/ard/tianyu/model/dto/BoxSettingsDTO.java
+++ b/ard-work/src/main/java/com/ard/tianyu/model/dto/BoxSettingsDTO.java
@@ -34,41 +34,41 @@
      * 照片实时回传开关,0-关闭,1-开启
      */
     @JsonProperty("openImgRtp")
-    private String openImgRtp;
+    private Integer openImgRtp;
 
     /**
      * 视频包排序开关,0-关闭,1-开启(排序会增加视频延时)
      */
     @JsonProperty("openVideoSort")
-    private String openVideoSort;
+    private Integer openVideoSort;
 
     /**
      * 云端视频存储开关,0-关闭,1-开启
      */
     @JsonProperty("openVideoStorage")
-    private String openVideoStorage;
+    private Integer openVideoStorage;
 
     /**
      * 视频自动推流开关,0-关闭,1-开启
      */
     @JsonProperty("videoAutoPush")
-    private String videoAutoPush;
+    private Integer videoAutoPush;
 
     /**
      * 云盒固件自动升级开关,0-关闭,1-开启
      */
     @JsonProperty("autoUpdate")
-    private String autoUpdate;
+    private Integer autoUpdate;
 
     /**
      * 云盒与平台失联xx秒后自动返航
      */
     @JsonProperty("lostTime")
-    private String lostTime;
+    private Integer lostTime;
 
     /**
      * 低电量自动返航开关:0-关闭,1-智能计算,xx-指定的返航电量
      */
     @JsonProperty("minHomeBattery")
-    private String minHomeBattery;
+    private Integer minHomeBattery;
 }
diff --git a/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/EmeragencyBrakeDTO.java b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/EmeragencyBrakeDTO.java
new file mode 100644
index 0000000..bb2af4c
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/EmeragencyBrakeDTO.java
@@ -0,0 +1,23 @@
+package com.ard.tianyu.model.dto.manual;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 紧急制动实体对象
+ *
+ * @author liusuyi
+ * @date 2024年10月26日9:02
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class EmeragencyBrakeDTO {
+    private String boxSn;
+
+    //0x00-解除紧急制动 0x01-紧急制动
+    private byte actionParam;
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/FlyControlDTO.java b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/FlyControlDTO.java
new file mode 100644
index 0000000..6f616af
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/FlyControlDTO.java
@@ -0,0 +1,40 @@
+package com.ard.tianyu.model.dto.manual;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 方向控制实体对象
+ *
+ * @author liusuyi
+ * @date 2024年10月26日9:02
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class FlyControlDTO {
+
+    private String boxSn;
+
+    /**
+     * 前后速度
+     */
+    private Float frSpeed;
+    /**
+     * 左右速度
+     */
+    private Float lrSpeed;
+    /**
+     * 上下速度
+     */
+    private Float udSpeed;
+
+    /**
+     * 偏航角
+     */
+    private Float yaw;
+
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/FlyPointControlCancelDTO.java b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/FlyPointControlCancelDTO.java
new file mode 100644
index 0000000..1d2af00
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/FlyPointControlCancelDTO.java
@@ -0,0 +1,20 @@
+package com.ard.tianyu.model.dto.manual;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 停止指点飞行实体对象
+ *
+ * @author liusuyi
+ * @date 2024年10月26日9:02
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class FlyPointControlCancelDTO {
+    private String boxSn;
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/FlyPointControlDTO.java b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/FlyPointControlDTO.java
new file mode 100644
index 0000000..40ac18d
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/FlyPointControlDTO.java
@@ -0,0 +1,46 @@
+package com.ard.tianyu.model.dto.manual;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 指点飞行控制实体对象
+ *
+ * @author liusuyi
+ * @date 2024年10月26日9:02
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class FlyPointControlDTO {
+
+    private String boxSn;
+
+    /**
+     * 经度
+     */
+    private Double longitude;
+    /**
+     * 纬度
+     */
+    private Double latitude;
+    /**
+     * 高度
+     */
+    private Float altitude;
+
+    /**
+     * 速度
+     */
+    private Float speed;
+
+    /**
+     * 飞行模式
+     */
+    @Builder.Default
+    private byte flyMode = 0;
+
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/LandCancelDTO.java b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/LandCancelDTO.java
new file mode 100644
index 0000000..bb50469
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/LandCancelDTO.java
@@ -0,0 +1,20 @@
+package com.ard.tianyu.model.dto.manual;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 取消降落实体对象
+ *
+ * @author liusuyi
+ * @date 2024年10月26日9:02
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class LandCancelDTO {
+    private String boxSn;
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/LandDTO.java b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/LandDTO.java
new file mode 100644
index 0000000..a81d15e
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/LandDTO.java
@@ -0,0 +1,20 @@
+package com.ard.tianyu.model.dto.manual;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 降落实体对象
+ *
+ * @author liusuyi
+ * @date 2024年10月26日9:02
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class LandDTO {
+    private String boxSn;
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/LandForcedDTO.java b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/LandForcedDTO.java
new file mode 100644
index 0000000..6a5a519
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/LandForcedDTO.java
@@ -0,0 +1,20 @@
+package com.ard.tianyu.model.dto.manual;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 取消降落实体对象
+ *
+ * @author liusuyi
+ * @date 2024年10月26日9:02
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class LandForcedDTO {
+    private String boxSn;
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/ReturnHomeCancelDTO.java b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/ReturnHomeCancelDTO.java
new file mode 100644
index 0000000..af885c3
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/ReturnHomeCancelDTO.java
@@ -0,0 +1,21 @@
+package com.ard.tianyu.model.dto.manual;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+
+/**
+ * 取消返航实体对象
+ *
+ * @author liusuyi
+ * @date 2024年10月26日9:02
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class ReturnHomeCancelDTO {
+    private String boxSn;
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/ReturnHomeDTO.java b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/ReturnHomeDTO.java
index fa22f5a..2fd48fb 100644
--- a/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/ReturnHomeDTO.java
+++ b/ard-work/src/main/java/com/ard/tianyu/model/dto/manual/ReturnHomeDTO.java
@@ -19,7 +19,6 @@
 @Builder
 @AllArgsConstructor
 @NoArgsConstructor
-@Validated
 public class ReturnHomeDTO {
     private String boxSn;
 }
diff --git a/ard-work/src/main/java/com/ard/tianyu/netty/command/PointFlyCmd.java b/ard-work/src/main/java/com/ard/tianyu/netty/command/PointFlyCmd.java
deleted file mode 100644
index 46be995..0000000
--- a/ard-work/src/main/java/com/ard/tianyu/netty/command/PointFlyCmd.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.ard.tianyu.netty.command;// PointFlyCommand.java
-import io.netty.buffer.ByteBuf;
-
-public class PointFlyCmd extends BaseCmd {
-    private double longitude;
-    private double latitude;
-    private float height;
-    private float speed;
-
-    public PointFlyCmd(double longitude, double latitude, float height, float speed) {
-        this.longitude = longitude;
-        this.latitude = latitude;
-        this.height = height;
-        this.speed = speed;
-        setDataHeader((short) 0x7479);
-        setCmdCode((byte) 0xD1);
-        setDataLength((short) 17); // 数据长度计算
-    }
-
-    @Override
-    public void encode(ByteBuf out) {
-        out.writeShort(getDataHeader());    // 写入数据头
-        out.writeShort(getDataLength());    // 写入数据长度
-        out.writeByte(getCmdCode());        // 写入命令码
-        out.writeDouble(longitude);         // 写入经度
-        out.writeDouble(latitude);          // 写入纬度
-        out.writeFloat(height);             // 写入高度
-        out.writeFloat(speed);              // 写入速度
-    }
-}
diff --git a/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/EmergencyBrakeCmd.java b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/EmergencyBrakeCmd.java
new file mode 100644
index 0000000..761ee74
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/EmergencyBrakeCmd.java
@@ -0,0 +1,35 @@
+package com.ard.tianyu.netty.command.manual;
+
+import com.ard.tianyu.model.dto.manual.EmeragencyBrakeDTO;
+import com.ard.tianyu.netty.command.BaseCmd;
+import io.netty.buffer.ByteBuf;
+
+/**
+ * 紧急制动指令
+ *
+ * @author liusuyi
+ * @date 2024年10月30日16:20
+ **/
+public class EmergencyBrakeCmd extends BaseCmd {
+
+    private final byte actionParam;         //动作参数
+
+    public EmergencyBrakeCmd(EmeragencyBrakeDTO emeragencyBrakeDTO) {
+        setDataHeader((short) 0x7479);
+        setDataLength((short) 19);
+        setBoxSn(emeragencyBrakeDTO.getBoxSn().getBytes());
+        setCmdCode((byte) 0xD1);
+        this.actionParam = emeragencyBrakeDTO.getActionParam();
+    }
+
+
+    public void encode(ByteBuf out) {
+        out.writeShort(getDataHeader());    // 写入数据头
+        out.writeShort(getDataLength());    // 写入数据长度
+        out.writeBytes(getBoxSn());         // 写入盒子SN
+        out.writeByte(getCmdCode());        // 写入命令码
+        out.writeByte(0x00);          // 写入加密标志
+        out.writeByte(0x32);          // 写入动作编号
+        out.writeByte(this.actionParam);    // 写入动作参数
+    }
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/EmergencyBrakeReplyCmd.java b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/EmergencyBrakeReplyCmd.java
new file mode 100644
index 0000000..3ed5bf3
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/EmergencyBrakeReplyCmd.java
@@ -0,0 +1,34 @@
+package com.ard.tianyu.netty.command.manual;
+
+import com.ard.tianyu.model.dto.manual.EmeragencyBrakeDTO;
+import com.ard.tianyu.netty.command.BaseCmd;
+import io.netty.buffer.ByteBuf;
+import lombok.Data;
+
+/**
+ * 紧急制动回复指令
+ *
+ * @author liusuyi
+ * @date 2024年10月30日16:20
+ **/
+@Data
+public class EmergencyBrakeReplyCmd extends BaseCmd {
+
+    private final byte encryptFlag = 0x00; // 加密标志
+    private final byte actionCode = 0x32;  // 动作编号
+    private final byte result;             // 执行结果
+    private final Integer errorCode;       // 错误码
+
+    public EmergencyBrakeReplyCmd(String boxSn, Byte result, Integer errorCode) {
+        setDataHeader((short) 0x6A77);
+        setDataLength((short) 23);
+        setBoxSn(boxSn.getBytes());
+        setCmdCode((byte) 0xD1);
+        this.result = result;
+        this.errorCode = errorCode;
+    }
+
+    public void encode(ByteBuf out) {
+
+    }
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/FlyControlCmd.java b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/FlyControlCmd.java
new file mode 100644
index 0000000..e0f4811
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/FlyControlCmd.java
@@ -0,0 +1,45 @@
+package com.ard.tianyu.netty.command.manual;
+
+import com.ard.tianyu.model.dto.manual.FlyControlDTO;
+import com.ard.tianyu.netty.command.BaseCmd;
+import io.netty.buffer.ByteBuf;
+
+/**
+ * 方向控制指令
+ *
+ * @author liusuyi
+ * @date 2024年10月26日15:43
+ **/
+public class FlyControlCmd extends BaseCmd {
+    private final float frSpeed;                    // 前后速度
+    private final float lrSpeed;                    // 左右速度
+    private final float udSpeed;                    // 上下速度
+    private final float yaw;                        // 偏航角
+    private final short execTime = 200;             // 执行时间
+
+    public FlyControlCmd(FlyControlDTO flyControlDTO) {
+        setDataHeader((short) 0x7479);
+        setDataLength((short) 36);
+        setBoxSn(flyControlDTO.getBoxSn().getBytes());
+        setCmdCode((byte) 0xD1);
+        this.frSpeed = flyControlDTO.getFrSpeed();
+        this.lrSpeed = flyControlDTO.getLrSpeed();
+        this.udSpeed = flyControlDTO.getUdSpeed();
+        this.yaw = flyControlDTO.getYaw();
+    }
+
+
+    public void encode(ByteBuf out) {
+        out.writeShort(getDataHeader());    // 写入数据头
+        out.writeShort(getDataLength());    // 写入数据长度
+        out.writeBytes(getBoxSn());         // 写入盒子SN
+        out.writeByte(getCmdCode());        // 写入命令码
+        out.writeByte(0x00);          // 写入加密标志
+        out.writeByte(0x28);          // 写入动作编号
+        out.writeFloat(frSpeed);            // 写入前后速度
+        out.writeFloat(lrSpeed);            // 写入左右速度
+        out.writeFloat(udSpeed);            // 写入上下速度
+        out.writeFloat(yaw);                // 写入偏航角
+        out.writeShort(execTime);           // 写入执行时间
+    }
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/FlyPointControlCancelCmd.java b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/FlyPointControlCancelCmd.java
new file mode 100644
index 0000000..3c345f7
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/FlyPointControlCancelCmd.java
@@ -0,0 +1,32 @@
+package com.ard.tianyu.netty.command.manual;
+
+import com.ard.tianyu.model.dto.manual.FlyPointControlCancelDTO;
+import com.ard.tianyu.netty.command.BaseCmd;
+import io.netty.buffer.ByteBuf;
+
+/**
+ * 停止指点飞行指令
+ *
+ * @author liusuyi
+ * @date 2024年10月26日15:43
+ **/
+public class FlyPointControlCancelCmd extends BaseCmd {
+
+
+    public FlyPointControlCancelCmd(FlyPointControlCancelDTO flyPointControlCancelDTO) {
+        setDataHeader((short) 0x7479);
+        setDataLength((short) 18);
+        setBoxSn(flyPointControlCancelDTO.getBoxSn().getBytes());
+        setCmdCode((byte) 0xD1);
+    }
+
+
+    public void encode(ByteBuf out) {
+        out.writeShort(getDataHeader());    // 写入数据头
+        out.writeShort(getDataLength());    // 写入数据长度
+        out.writeBytes(getBoxSn());         // 写入盒子SN
+        out.writeByte(getCmdCode());        // 写入命令码
+        out.writeByte(0x00);          // 写入加密标志
+        out.writeByte(0x3A);          // 写入动作编号
+    }
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/FlyPointControlCmd.java b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/FlyPointControlCmd.java
new file mode 100644
index 0000000..5838ea7
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/FlyPointControlCmd.java
@@ -0,0 +1,46 @@
+package com.ard.tianyu.netty.command.manual;
+
+import com.ard.tianyu.model.dto.manual.FlyPointControlDTO;
+import com.ard.tianyu.netty.command.BaseCmd;
+import io.netty.buffer.ByteBuf;
+
+/**
+ * 指点飞行控制指令
+ *
+ * @author liusuyi
+ * @date 2024年10月26日15:43
+ **/
+public class FlyPointControlCmd extends BaseCmd {
+    private final double longitude;                  // 经度
+    private final double latitude;                   // 纬度
+    private final float altitude;                    // 高度
+    private final float speed;                       // 速度
+    private final byte flyMode;                      // 飞行模式
+
+    public FlyPointControlCmd(FlyPointControlDTO flyPointControlDTO) {
+        setDataHeader((short) 0x7479);
+        setDataLength((short) 36);
+        setBoxSn(flyPointControlDTO.getBoxSn().getBytes());
+        setCmdCode((byte) 0xD1);
+        this.longitude = flyPointControlDTO.getLongitude();
+        this.latitude = flyPointControlDTO.getLatitude();
+        this.altitude = flyPointControlDTO.getAltitude();
+        this.speed = flyPointControlDTO.getSpeed();
+        this.flyMode = flyPointControlDTO.getFlyMode();
+    }
+
+
+    public void encode(ByteBuf out) {
+        out.writeShort(getDataHeader());    // 写入数据头
+        out.writeShort(getDataLength());    // 写入数据长度
+        out.writeBytes(getBoxSn());         // 写入盒子SN
+        out.writeByte(getCmdCode());        // 写入命令码
+        out.writeByte(0x00);          // 写入加密标志
+        out.writeByte(0x39);          // 写入动作编号
+        out.writeDouble(longitude);         // 写入经度
+        out.writeDouble(latitude);          // 写入纬度
+        out.writeFloat(altitude);           // 写入高度
+        out.writeFloat(speed);              // 写入速度
+        out.writeByte(flyMode);             // 写入飞行模式
+    }
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandCancelCmd.java b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandCancelCmd.java
new file mode 100644
index 0000000..b791898
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandCancelCmd.java
@@ -0,0 +1,33 @@
+package com.ard.tianyu.netty.command.manual;
+
+import com.ard.tianyu.model.dto.manual.LandCancelDTO;
+import com.ard.tianyu.model.dto.manual.LandDTO;
+import com.ard.tianyu.netty.command.BaseCmd;
+import io.netty.buffer.ByteBuf;
+
+/**
+ * 取消降落指令
+ *
+ * @author liusuyi
+ * @date 2024年10月26日15:43
+ **/
+public class LandCancelCmd extends BaseCmd {
+
+
+    public LandCancelCmd(LandCancelDTO landCancleDTO) {
+        setDataHeader((short) 0x7479);
+        setDataLength((short) 18);
+        setBoxSn(landCancleDTO.getBoxSn().getBytes());
+        setCmdCode((byte) 0xD1);
+    }
+
+
+    public void encode(ByteBuf out) {
+        out.writeShort(getDataHeader());    // 写入数据头
+        out.writeShort(getDataLength());    // 写入数据长度
+        out.writeBytes(getBoxSn());         // 写入盒子SN
+        out.writeByte(getCmdCode());        // 写入命令码
+        out.writeByte(0x00);          // 写入加密标志
+        out.writeByte(0x15);          // 写入动作编号
+    }
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandCancelReplyCmd.java b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandCancelReplyCmd.java
new file mode 100644
index 0000000..3de41ce
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandCancelReplyCmd.java
@@ -0,0 +1,33 @@
+package com.ard.tianyu.netty.command.manual;
+
+import com.ard.tianyu.netty.command.BaseCmd;
+import io.netty.buffer.ByteBuf;
+import lombok.Data;
+
+/**
+ * 取消降落回复指令
+ *
+ * @author liusuyi
+ * @date 2024年10月26日15:43
+ **/
+@Data
+public class LandCancelReplyCmd extends BaseCmd {
+
+    private final byte encryptFlag = 0x00; // 加密标志
+    private final byte actionCode = 0x15;  // 动作编号
+    private final byte result;             // 执行结果
+    private final Integer errorCode;       // 错误码
+
+    public LandCancelReplyCmd(String boxSn, Byte result, Integer errorCode) {
+        setDataHeader((short) 0x6A77);
+        setDataLength((short) 23);
+        setBoxSn(boxSn.getBytes());
+        setCmdCode((byte) 0xD1);
+        this.result = result;
+        this.errorCode = errorCode;
+    }
+
+    public void encode(ByteBuf out) {
+
+    }
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandCmd.java b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandCmd.java
new file mode 100644
index 0000000..384ce0a
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandCmd.java
@@ -0,0 +1,33 @@
+package com.ard.tianyu.netty.command.manual;
+
+import com.ard.tianyu.model.dto.manual.LandDTO;
+import com.ard.tianyu.model.dto.manual.ReturnHomeCancelDTO;
+import com.ard.tianyu.netty.command.BaseCmd;
+import io.netty.buffer.ByteBuf;
+
+/**
+ * 降落指令
+ *
+ * @author liusuyi
+ * @date 2024年10月26日15:43
+ **/
+public class LandCmd extends BaseCmd {
+
+
+    public LandCmd(LandDTO landDTO) {
+        setDataHeader((short) 0x7479);
+        setDataLength((short) 18);
+        setBoxSn(landDTO.getBoxSn().getBytes());
+        setCmdCode((byte) 0xD1);
+    }
+
+
+    public void encode(ByteBuf out) {
+        out.writeShort(getDataHeader());    // 写入数据头
+        out.writeShort(getDataLength());    // 写入数据长度
+        out.writeBytes(getBoxSn());         // 写入盒子SN
+        out.writeByte(getCmdCode());        // 写入命令码
+        out.writeByte(0x00);          // 写入加密标志
+        out.writeByte(0x14);          // 写入动作编号
+    }
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandForcedCmd.java b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandForcedCmd.java
new file mode 100644
index 0000000..758380c
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandForcedCmd.java
@@ -0,0 +1,33 @@
+package com.ard.tianyu.netty.command.manual;
+
+import com.ard.tianyu.model.dto.manual.LandCancelDTO;
+import com.ard.tianyu.model.dto.manual.LandForcedDTO;
+import com.ard.tianyu.netty.command.BaseCmd;
+import io.netty.buffer.ByteBuf;
+
+/**
+ * 强制降落指令
+ *
+ * @author liusuyi
+ * @date 2024年10月26日15:43
+ **/
+public class LandForcedCmd extends BaseCmd {
+
+
+    public LandForcedCmd(LandForcedDTO landForcedDTO) {
+        setDataHeader((short) 0x7479);
+        setDataLength((short) 18);
+        setBoxSn(landForcedDTO.getBoxSn().getBytes());
+        setCmdCode((byte) 0xD1);
+    }
+
+
+    public void encode(ByteBuf out) {
+        out.writeShort(getDataHeader());    // 写入数据头
+        out.writeShort(getDataLength());    // 写入数据长度
+        out.writeBytes(getBoxSn());         // 写入盒子SN
+        out.writeByte(getCmdCode());        // 写入命令码
+        out.writeByte(0x00);          // 写入加密标志
+        out.writeByte(0x29);          // 写入动作编号
+    }
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandForcedReplyCmd.java b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandForcedReplyCmd.java
new file mode 100644
index 0000000..ee7cb16
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandForcedReplyCmd.java
@@ -0,0 +1,33 @@
+package com.ard.tianyu.netty.command.manual;
+
+import com.ard.tianyu.netty.command.BaseCmd;
+import io.netty.buffer.ByteBuf;
+import lombok.Data;
+
+/**
+ * 强制降落回复指令
+ *
+ * @author liusuyi
+ * @date 2024年10月26日15:43
+ **/
+@Data
+public class LandForcedReplyCmd extends BaseCmd {
+
+    private final byte encryptFlag = 0x00; // 加密标志
+    private final byte actionCode = 0x29;  // 动作编号
+    private final byte result;             // 执行结果
+    private final Integer errorCode;       // 错误码
+
+    public LandForcedReplyCmd(String boxSn, Byte result, Integer errorCode) {
+        setDataHeader((short) 0x6A77);
+        setDataLength((short) 23);
+        setBoxSn(boxSn.getBytes());
+        setCmdCode((byte) 0xD1);
+        this.result = result;
+        this.errorCode = errorCode;
+    }
+
+    public void encode(ByteBuf out) {
+
+    }
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandReplyCmd.java b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandReplyCmd.java
new file mode 100644
index 0000000..311d554
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/LandReplyCmd.java
@@ -0,0 +1,33 @@
+package com.ard.tianyu.netty.command.manual;
+
+import com.ard.tianyu.netty.command.BaseCmd;
+import io.netty.buffer.ByteBuf;
+import lombok.Data;
+
+/**
+ * 降落回复指令
+ *
+ * @author liusuyi
+ * @date 2024年10月26日15:43
+ **/
+@Data
+public class LandReplyCmd extends BaseCmd {
+
+    private final byte encryptFlag = 0x00; // 加密标志
+    private final byte actionCode = 0x14;  // 动作编号
+    private final byte result;             // 执行结果
+    private final Integer errorCode;       // 错误码
+
+    public LandReplyCmd(String boxSn, Byte result, Integer errorCode) {
+        setDataHeader((short) 0x6A77);
+        setDataLength((short) 23);
+        setBoxSn(boxSn.getBytes());
+        setCmdCode((byte) 0xD1);
+        this.result = result;
+        this.errorCode = errorCode;
+    }
+
+    public void encode(ByteBuf out) {
+
+    }
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/PointControlReachedReplyCmd.java b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/PointControlReachedReplyCmd.java
new file mode 100644
index 0000000..001ff9b
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/PointControlReachedReplyCmd.java
@@ -0,0 +1,33 @@
+package com.ard.tianyu.netty.command.manual;
+
+import com.ard.tianyu.netty.command.BaseCmd;
+import io.netty.buffer.ByteBuf;
+import lombok.Data;
+
+/**
+ * 到达指点飞行位置回复指令
+ *
+ * @author liusuyi
+ * @date 2024年10月26日15:43
+ **/
+@Data
+public class PointControlReachedReplyCmd extends BaseCmd {
+
+    private final byte encryptFlag = 0x00; // 加密标志
+    private final byte actionCode = 0x39;  // 动作编号
+    private final byte result;             // 执行结果
+    private final Integer errorCode;       // 错误码
+
+    public PointControlReachedReplyCmd(String boxSn, Byte result, Integer errorCode) {
+        setDataHeader((short) 0x6A77);
+        setDataLength((short) 19);
+        setBoxSn(boxSn.getBytes());
+        setCmdCode((byte) 0xD1);
+        this.result = result;
+        this.errorCode = errorCode;
+    }
+
+    public void encode(ByteBuf out) {
+
+    }
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/ReturnHomeCancelCmd.java b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/ReturnHomeCancelCmd.java
new file mode 100644
index 0000000..be109fc
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/ReturnHomeCancelCmd.java
@@ -0,0 +1,33 @@
+package com.ard.tianyu.netty.command.manual;
+
+import com.ard.tianyu.model.dto.manual.ReturnHomeCancelDTO;
+import com.ard.tianyu.model.dto.manual.ReturnHomeDTO;
+import com.ard.tianyu.netty.command.BaseCmd;
+import io.netty.buffer.ByteBuf;
+
+/**
+ * 取消返航指令
+ *
+ * @author liusuyi
+ * @date 2024年10月26日15:43
+ **/
+public class ReturnHomeCancelCmd extends BaseCmd {
+
+
+    public ReturnHomeCancelCmd(ReturnHomeCancelDTO returnHomeCancelDTO) {
+        setDataHeader((short) 0x7479);
+        setDataLength((short) 18);
+        setBoxSn(returnHomeCancelDTO.getBoxSn().getBytes());
+        setCmdCode((byte) 0xD1);
+    }
+
+
+    public void encode(ByteBuf out) {
+        out.writeShort(getDataHeader());    // 写入数据头
+        out.writeShort(getDataLength());    // 写入数据长度
+        out.writeBytes(getBoxSn());         // 写入盒子SN
+        out.writeByte(getCmdCode());        // 写入命令码
+        out.writeByte(0x00);          // 写入加密标志
+        out.writeByte(0x13);          // 写入动作编号
+    }
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/ReturnHomeCancelReplyCmd.java b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/ReturnHomeCancelReplyCmd.java
new file mode 100644
index 0000000..52e356a
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/netty/command/manual/ReturnHomeCancelReplyCmd.java
@@ -0,0 +1,33 @@
+package com.ard.tianyu.netty.command.manual;
+
+import com.ard.tianyu.netty.command.BaseCmd;
+import io.netty.buffer.ByteBuf;
+import lombok.Data;
+
+/**
+ * 取消返航回复指令
+ *
+ * @author liusuyi
+ * @date 2024年10月26日15:43
+ **/
+@Data
+public class ReturnHomeCancelReplyCmd extends BaseCmd {
+
+    private final byte encryptFlag = 0x00; // 加密标志
+    private final byte actionCode = 0x13;  // 动作编号
+    private final byte result;             // 执行结果
+    private final Integer errorCode;       // 错误码
+
+    public ReturnHomeCancelReplyCmd(String boxSn, Byte result, Integer errorCode) {
+        setDataHeader((short) 0x6A77);
+        setDataLength((short) 23);
+        setBoxSn(boxSn.getBytes());
+        setCmdCode((byte) 0xD1);
+        this.result = result;
+        this.errorCode = errorCode;
+    }
+
+    public void encode(ByteBuf out) {
+
+    }
+}
diff --git a/ard-work/src/main/java/com/ard/tianyu/netty/handler/MessageProtocolDecoder.java b/ard-work/src/main/java/com/ard/tianyu/netty/handler/MessageProtocolDecoder.java
index 10b9d63..27fe205 100644
--- a/ard-work/src/main/java/com/ard/tianyu/netty/handler/MessageProtocolDecoder.java
+++ b/ard-work/src/main/java/com/ard/tianyu/netty/handler/MessageProtocolDecoder.java
@@ -5,8 +5,7 @@
 import com.ard.tianyu.netty.command.camera.CapturePicReplyCmd;
 import com.ard.tianyu.netty.command.camera.RecordStartReplyCmd;
 import com.ard.tianyu.netty.command.camera.RecordStopReplyCmd;
-import com.ard.tianyu.netty.command.manual.ReturnHomeReplyCmd;
-import com.ard.tianyu.netty.command.manual.TakeOffReplyCmd;
+import com.ard.tianyu.netty.command.manual.*;
 import com.ard.tianyu.netty.command.notice.BoxPowerStatusReplyCmd;
 import com.ard.tianyu.netty.command.notice.FlyWayEndReplyCmd;
 import com.ard.tianyu.netty.command.notice.UavReadyReplyCmd;
@@ -112,6 +111,60 @@
                         baseCmd = new ReturnHomeReplyCmd(boxSn, result, errorCode);
                         log.debug("返航回复: {}", boxSn);
                         break;
+                    case 0x13:
+                        result = in.readByte();
+                        errorCode = in.readInt();
+                        uavData = new byte[15];
+                        in.readBytes(uavData);
+                        boxSn = new String(uavData);
+                        baseCmd = new ReturnHomeCancelReplyCmd(boxSn, result, errorCode);
+                        log.debug("取消返航回复: {}", boxSn);
+                        break;
+                    case 0x14:
+                        result = in.readByte();
+                        errorCode = in.readInt();
+                        uavData = new byte[15];
+                        in.readBytes(uavData);
+                        boxSn = new String(uavData);
+                        baseCmd = new LandReplyCmd(boxSn, result, errorCode);
+                        log.debug("降落回复: {}", boxSn);
+                        break;
+                    case 0x15:
+                        result = in.readByte();
+                        errorCode = in.readInt();
+                        uavData = new byte[15];
+                        in.readBytes(uavData);
+                        boxSn = new String(uavData);
+                        baseCmd = new LandCancelReplyCmd(boxSn, result, errorCode);
+                        log.debug("取消降落回复: {}", boxSn);
+                        break;
+                    case 0x29:
+                        result = in.readByte();
+                        errorCode = in.readInt();
+                        uavData = new byte[15];
+                        in.readBytes(uavData);
+                        boxSn = new String(uavData);
+                        baseCmd = new LandForcedReplyCmd(boxSn, result, errorCode);
+                        log.debug("强制降落回复: {}", boxSn);
+                        break;
+                    case 0x32:
+                        result = in.readByte();
+                        errorCode = in.readInt();
+                        uavData = new byte[15];
+                        in.readBytes(uavData);
+                        boxSn = new String(uavData);
+                        baseCmd = new EmergencyBrakeReplyCmd(boxSn, result, errorCode);
+                        log.debug("紧急制动回复: {}", boxSn);
+                        break;
+                    case 0x39:
+                        result = in.readByte();
+                        errorCode = in.readInt();
+                        uavData = new byte[15];
+                        in.readBytes(uavData);
+                        boxSn = new String(uavData);
+                        baseCmd = new PointControlReachedReplyCmd(boxSn, result, errorCode);
+                        log.debug("到达指点飞行位置回复: {}", boxSn);
+                        break;
                     case 0x22:
                         result = in.readByte();
                         errorCode = in.readInt();
diff --git a/ard-work/src/main/java/com/ard/tianyu/service/ITyService.java b/ard-work/src/main/java/com/ard/tianyu/service/ITyService.java
index 2308965..612fcb2 100644
--- a/ard-work/src/main/java/com/ard/tianyu/service/ITyService.java
+++ b/ard-work/src/main/java/com/ard/tianyu/service/ITyService.java
@@ -7,9 +7,7 @@
 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.manual.ReturnHomeDTO;
-import com.ard.tianyu.model.dto.manual.SwitchUavControlDTO;
-import com.ard.tianyu.model.dto.manual.TakeOffDTO;
+import com.ard.tianyu.model.dto.manual.*;
 import com.ard.tianyu.model.dto.signal.SignalInfo;
 import com.ard.tianyu.model.dto.state.UavState;
 import com.ard.tianyu.model.dto.telemetry.TelemetryData;
@@ -138,6 +136,47 @@
      * 返航
      */
     void returnHome(ReturnHomeDTO returnHomeDTO);
+
+    /**
+     * 取消返航
+     */
+    void returnHomeCancel(ReturnHomeCancelDTO returnHomeCancelDTO);
+
+    /**
+     * 降落
+     */
+    void land(LandDTO landDTO);
+
+    /**
+     * 取消降落
+     */
+    void landCancel(LandCancelDTO landCancelDTO);
+
+    /**
+     * 强制降落
+     */
+    void landForced(LandForcedDTO landForcedDTO);
+
+    /**
+     * 方向控制
+     */
+    void flyControl(FlyControlDTO flyControlDTO);
+
+    /**
+     * 指点飞行控制
+     */
+    void flyPointControl(FlyPointControlDTO flyPointControlDTO);
+
+    /**
+     * 停止指点飞行控制
+     */
+    void flyPointControlCancel(FlyPointControlCancelDTO flyPointControlCancelDTO);
+
+    /**
+     * 紧急制动
+     */
+    void emeragencyBrake(EmeragencyBrakeDTO emeragencyBrakeDTO);
+
     /**
      * 获取无人机状态
      */
diff --git a/ard-work/src/main/java/com/ard/tianyu/service/impl/TyServiceImpl.java b/ard-work/src/main/java/com/ard/tianyu/service/impl/TyServiceImpl.java
index f995b0f..88d749c 100644
--- a/ard-work/src/main/java/com/ard/tianyu/service/impl/TyServiceImpl.java
+++ b/ard-work/src/main/java/com/ard/tianyu/service/impl/TyServiceImpl.java
@@ -15,9 +15,7 @@
 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.manual.ReturnHomeDTO;
-import com.ard.tianyu.model.dto.manual.SwitchUavControlDTO;
-import com.ard.tianyu.model.dto.manual.TakeOffDTO;
+import com.ard.tianyu.model.dto.manual.*;
 import com.ard.tianyu.model.dto.signal.SignalInfo;
 import com.ard.tianyu.model.dto.state.UavState;
 import com.ard.tianyu.model.dto.telemetry.TelemetryData;
@@ -38,6 +36,7 @@
 import com.ard.tianyu.netty.command.register.*;
 import com.ard.tianyu.netty.handler.ErrorCodeEnum;
 import com.ard.tianyu.service.ITyService;
+import com.ard.tianyu.websocket.utils.WebSocketUtil;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
 import lombok.extern.slf4j.Slf4j;
@@ -300,6 +299,78 @@
     }
 
     /**
+     * 取消返航
+     */
+    @Override
+    public void returnHomeCancel(ReturnHomeCancelDTO returnHomeCancelDTO) {
+        ReturnHomeCancelCmd returnHomeCancelCmd = new ReturnHomeCancelCmd(returnHomeCancelDTO);
+        this.sendMessage(tyConfiguration.getIpPort(), returnHomeCancelCmd);
+    }
+
+    /**
+     * 降落
+     */
+    @Override
+    public void land(LandDTO landDTO) {
+        LandCmd landCmd = new LandCmd(landDTO);
+        this.sendMessage(tyConfiguration.getIpPort(), landCmd);
+    }
+
+    /**
+     * 取消降落
+     */
+    @Override
+    public void landCancel(LandCancelDTO landCancelDTO) {
+        LandCancelCmd landCancelCmd = new LandCancelCmd(landCancelDTO);
+        this.sendMessage(tyConfiguration.getIpPort(), landCancelCmd);
+    }
+
+    /**
+     * 强制降落
+     */
+    @Override
+    public void landForced(LandForcedDTO landForcedDTO) {
+        LandForcedCmd landForcedCmd = new LandForcedCmd(landForcedDTO);
+        this.sendMessage(tyConfiguration.getIpPort(), landForcedCmd);
+    }
+
+    /**
+     * 方向控制
+     */
+    @Override
+    public void flyControl(FlyControlDTO flyControlDTO) {
+        FlyControlCmd flyControlCmd = new FlyControlCmd(flyControlDTO);
+        this.sendMessage(tyConfiguration.getIpPort(), flyControlCmd);
+    }
+
+    /**
+     * 指点飞行控制
+     */
+    @Override
+    public void flyPointControl(FlyPointControlDTO flyPointControlDTO) {
+        FlyPointControlCmd flyPointControlCmd = new FlyPointControlCmd(flyPointControlDTO);
+        this.sendMessage(tyConfiguration.getIpPort(), flyPointControlCmd);
+    }
+
+    /**
+     * 停止指点飞行控制
+     */
+    @Override
+    public void flyPointControlCancel(FlyPointControlCancelDTO flyPointControlCancelDTO) {
+        FlyPointControlCancelCmd flyPointControlCancelCmd = new FlyPointControlCancelCmd(flyPointControlCancelDTO);
+        this.sendMessage(tyConfiguration.getIpPort(), flyPointControlCancelCmd);
+    }
+
+    /**
+     * 紧急制动
+     */
+    @Override
+    public void emeragencyBrake(EmeragencyBrakeDTO emeragencyBrakeDTO) {
+        EmergencyBrakeCmd emergencyBrakeCmd=new EmergencyBrakeCmd(emeragencyBrakeDTO);
+        this.sendMessage(tyConfiguration.getIpPort(), emergencyBrakeCmd);
+    }
+
+    /**
      * 获取无人机状态
      */
     @Override
@@ -362,6 +433,7 @@
                 UavState uavState = UavStateConverter.convertProtoToEntity(uavStateCmd.getUavState());
                 UavStateCache.putUavState(uavState);
                 logPrint("无人机状态", uavState.getBoxSn());
+                WebSocketUtil.sendMessageAll(uavState);
                 break;
             case (byte) 0xA9:
                 // 处理无人机遥测消息
@@ -419,6 +491,36 @@
                     ReturnHomeReplyCmd returnHomeReplyCmd = (ReturnHomeReplyCmd) tyCommand;
                     logPrint("无人机返航", returnHomeReplyCmd.getResult(), returnHomeReplyCmd.getErrorCode());
                 }
+                //取消返航回复
+                if (tyCommand instanceof ReturnHomeCancelReplyCmd) {
+                    ReturnHomeCancelReplyCmd returnHomeCancelReplyCmd = (ReturnHomeCancelReplyCmd) tyCommand;
+                    logPrint("取消无人机返航", returnHomeCancelReplyCmd.getResult(), returnHomeCancelReplyCmd.getErrorCode());
+                }
+                //降落回复
+                if (tyCommand instanceof LandReplyCmd) {
+                    LandReplyCmd landReplyCmd = (LandReplyCmd) tyCommand;
+                    logPrint("降落", landReplyCmd.getResult(), landReplyCmd.getErrorCode());
+                }
+                //取消降落回复
+                if (tyCommand instanceof LandCancelReplyCmd) {
+                    LandCancelReplyCmd landCancelReplyCmd = (LandCancelReplyCmd) tyCommand;
+                    logPrint("取消降落", landCancelReplyCmd.getResult(), landCancelReplyCmd.getErrorCode());
+                }
+                //强制降落回复
+                if (tyCommand instanceof LandForcedReplyCmd) {
+                    LandForcedReplyCmd landForcedReplyCmd = (LandForcedReplyCmd) tyCommand;
+                    logPrint("强制降落", landForcedReplyCmd.getResult(), landForcedReplyCmd.getErrorCode());
+                }
+                //到达指点飞行位置回复
+                if (tyCommand instanceof PointControlReachedReplyCmd) {
+                    PointControlReachedReplyCmd pointControlReachedReplyCmd = (PointControlReachedReplyCmd) tyCommand;
+                    logPrint("到达指点飞行位置", pointControlReachedReplyCmd.getResult(), pointControlReachedReplyCmd.getErrorCode());
+                }
+                //紧急制动回复
+                if (tyCommand instanceof EmergencyBrakeReplyCmd) {
+                    EmergencyBrakeReplyCmd emergencyBrakeReplyCmd = (EmergencyBrakeReplyCmd) tyCommand;
+                    logPrint("紧急制动回复", emergencyBrakeReplyCmd.getResult(), emergencyBrakeReplyCmd.getErrorCode());
+                }
                 break;
             default:
                 // 处理其他消息
@@ -430,6 +532,7 @@
     private void logPrint(String message, Object obj) {
         log.debug("收到{}回复{}", message, obj);
     }
+
     //公共日志打印
     private void logPrint(String message, byte result, Integer errorCode) {
         log.info("收到{}回复:{} 错误码:{}【{}】",
diff --git a/ard-work/src/main/java/com/ard/tianyu/websocket/config/WebSocketConfig.java b/ard-work/src/main/java/com/ard/tianyu/websocket/config/WebSocketConfig.java
new file mode 100644
index 0000000..e43f086
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/websocket/config/WebSocketConfig.java
@@ -0,0 +1,27 @@
+package com.ard.tianyu.websocket.config;
+
+import com.ard.tianyu.websocket.handler.TyMessageHandler;
+import com.ard.tianyu.websocket.interceptor.TyHandshakeInterceptor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.config.annotation.EnableWebSocket;
+import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
+import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
+import javax.annotation.Resource;
+
+@Configuration
+@EnableWebSocket
+public class WebSocketConfig implements WebSocketConfigurer {
+
+    @Resource
+    private TyMessageHandler tyMessageHandler;
+
+    @Override
+    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
+        //添加myWebSocketHandler消息处理对象以及websocket连接地址
+        registry.addHandler(tyMessageHandler, "/ws/**")
+                //设置允许跨域访问
+                .setAllowedOrigins("*")
+                //添加拦截器可实现用户链接前进行权限校验等操作
+                .addInterceptors(new TyHandshakeInterceptor());
+    }
+}
\ No newline at end of file
diff --git a/ard-work/src/main/java/com/ard/tianyu/websocket/handler/TyMessageHandler.java b/ard-work/src/main/java/com/ard/tianyu/websocket/handler/TyMessageHandler.java
new file mode 100644
index 0000000..58b5969
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/websocket/handler/TyMessageHandler.java
@@ -0,0 +1,39 @@
+package com.ard.tianyu.websocket.handler;
+
+import com.ard.tianyu.websocket.utils.WebSocketUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.CloseStatus;
+import org.springframework.web.socket.TextMessage;
+import org.springframework.web.socket.WebSocketSession;
+import org.springframework.web.socket.handler.TextWebSocketHandler;
+
+@Component
+@Slf4j
+public class TyMessageHandler extends TextWebSocketHandler {
+
+    @Override
+    public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
+        // 处理接收到的消息
+        String payload = message.getPayload();
+        log.info("【websocket】Received message: " + payload);
+        log.info("【websocket】size: " + WebSocketUtil.ONLINE_USER_SESSIONS.size());
+    }
+
+    @Override
+    public void afterConnectionEstablished(WebSocketSession session) {
+        log.info("【websocket】Connected: " + session.getId());
+        String userId = (String) session.getAttributes().get("userId");
+        WebSocketUtil.ONLINE_USER_SESSIONS.put(userId, session);
+        log.info("【websocket】size: " + WebSocketUtil.ONLINE_USER_SESSIONS.size());
+
+    }
+
+    @Override
+    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
+        log.info("【websocket】Disconnected: " + session.getId());
+        String userId = (String) session.getAttributes().get("userId");
+        WebSocketUtil.ONLINE_USER_SESSIONS.remove(userId);
+        log.info("【websocket】size: " + WebSocketUtil.ONLINE_USER_SESSIONS.size());
+    }
+}
\ No newline at end of file
diff --git a/ard-work/src/main/java/com/ard/tianyu/websocket/interceptor/TyHandshakeInterceptor.java b/ard-work/src/main/java/com/ard/tianyu/websocket/interceptor/TyHandshakeInterceptor.java
new file mode 100644
index 0000000..b324841
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/websocket/interceptor/TyHandshakeInterceptor.java
@@ -0,0 +1,35 @@
+package com.ard.tianyu.websocket.interceptor;
+
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.web.socket.WebSocketHandler;
+import org.springframework.web.socket.server.HandshakeInterceptor;
+
+import java.util.Map;
+
+public class TyHandshakeInterceptor implements HandshakeInterceptor {
+
+    @Override
+    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
+                                   WebSocketHandler wsHandler, Map<String, Object> attributes){
+        //从路径中获取userId
+        String path = request.getURI().getPath();
+        String[] segments = path.split("/");
+        if (segments.length > 2) {
+            String userId = segments[segments.length - 1];
+            attributes.put("userId", userId);
+        }
+        //从header中获取userId
+//        String userId = request.getHeaders().getFirst("userId");
+//        if (userId != null)
+//        {
+//            attributes.put("userId", userId);
+//        }
+        return true;
+    }
+
+    @Override
+    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
+                               WebSocketHandler wsHandler, Exception ex) {
+    }
+}
\ No newline at end of file
diff --git a/ard-work/src/main/java/com/ard/tianyu/websocket/utils/WebSocketUtil.java b/ard-work/src/main/java/com/ard/tianyu/websocket/utils/WebSocketUtil.java
new file mode 100644
index 0000000..dc78204
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/tianyu/websocket/utils/WebSocketUtil.java
@@ -0,0 +1,141 @@
+package com.ard.tianyu.websocket.utils;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.socket.TextMessage;
+import org.springframework.web.socket.WebSocketSession;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @ClassName WebSocketUtils
+ * @Description: websocket工具类
+ * @Author 刘苏义
+ * @Date 2023/1/27 7:46
+ * @Version 1.0
+ */
+@Slf4j
+public final class WebSocketUtil {
+
+    // 存储 websocket session
+    public static final ConcurrentMap<String, WebSocketSession> ONLINE_USER_SESSIONS = new ConcurrentHashMap<>();
+
+    /**
+     * @param session 用户 session
+     * @param message 发送内容
+     */
+    public static void sendMessage(WebSocketSession session, String message) {
+        if (session == null) {
+            return;
+        }
+        final InetSocketAddress remoteAddress = session.getRemoteAddress();
+        if (remoteAddress == null) {
+            return;
+        }
+        synchronized (session) {
+            try {
+                log.debug("发送消息:" + message);
+                session.sendMessage(new TextMessage(String.join(", ", message)));
+            } catch (IOException e) {
+                log.error("sendMessage IOException ", e);
+            }
+        }
+    }
+
+    /**
+     * @param session 用户 session
+     * @param message 发送内容
+     */
+    public static void sendMessage(WebSocketSession session, Map message) {
+        if (session == null) {
+            return;
+        }
+       final InetSocketAddress remoteAddress = session.getRemoteAddress();
+        if (remoteAddress == null) {
+            return;
+        }
+        synchronized (session) {
+            try {
+                session.sendMessage(new TextMessage(JSONObject.toJSONString(message)));
+            } catch (IOException e) {
+                log.error("sendMessage IOException ", e);
+            }
+        }
+    }
+
+    public static void sendMessage(WebSocketSession session, List message) {
+        if (session == null) {
+            return;
+        }
+        final InetSocketAddress remoteAddress = session.getRemoteAddress();
+        if (remoteAddress == null) {
+            return;
+        }
+        synchronized (session) {
+            try {
+                session.sendMessage(new TextMessage(JSONObject.toJSONString(message)));
+            } catch (IOException e) {
+                log.error("sendMessage IOException ", e);
+            }
+        }
+    }
+
+    /**
+     * 推送消息到其他客户端
+     *
+     * @param message
+     */
+    public static void sendMessageAll(String message) {
+        ONLINE_USER_SESSIONS.forEach((sessionId, session) -> sendMessage(session, message));
+    }
+
+    /**
+     * 推送消息到其他客户端
+     *
+     * @param message
+     */
+    public static void sendMessageAll(Map message) {
+        JSONObject jsonObject = new JSONObject(message);
+        ONLINE_USER_SESSIONS.forEach((sessionId, session) -> sendMessage(session, jsonObject.toString()));
+    }
+    /**
+     * 推送消息到其他客户端
+     *
+     * @param message
+     */
+    public static void sendMessageAll(Object message) {
+        String jsonMessage = JSONObject.toJSONString(message);  // 确保对象转换为 JSON 字符串
+        ONLINE_USER_SESSIONS.forEach((sessionId, session) -> sendMessage(session, jsonMessage));
+    }
+    /**
+     * 推送消息到其他客户端
+     *
+     * @param message
+     */
+    public static void sendMessageAll(List message) {
+        ONLINE_USER_SESSIONS.forEach((sessionId, session) -> sendMessage(session, JSON.toJSONString(message)));
+    }
+    /**
+     * @Author 刘苏义
+     * @Description  发送消息给userId_前缀的人
+     * @Date   2024/7/16 10:24
+     * @Param
+     * @return
+     */
+    public static void sendMessagePrefix(String targetId, String message) {
+        String regex = "^" + Pattern.quote(targetId) + "_\\d+$";
+        Pattern pattern = Pattern.compile(regex);
+        ONLINE_USER_SESSIONS.entrySet().stream().filter(entry -> {
+            Matcher matcher = pattern.matcher(entry.getKey());
+            return matcher.matches();
+        }).map(Map.Entry::getValue).forEach(session -> WebSocketUtil.sendMessage(session, message));
+    }
+}
\ No newline at end of file

--
Gitblit v1.9.3