移植gps数据到650
authorCaisking <Casiking@zhihuishixun.com>
Thu, 28 Aug 2025 09:44:56 +0000 (17:44 +0800)
committerCaisking <Casiking@zhihuishixun.com>
Thu, 28 Aug 2025 09:44:56 +0000 (17:44 +0800)
code/sdk/application/wearable/fd230/nativeapp/nativeui/traing/include/TraingModel.h
code/sdk/application/wearable/fd230/nativeapp/nativeui/traing/include/TraingNomalPresenter.h
code/sdk/application/wearable/fd230/nativeapp/nativeui/traing/src/TraingModel.cpp
code/sdk/application/wearable/fd230/nativeapp/nativeui/traing/src/TraingNomalPresenter.cpp
code/sdk/application/wearable/fd230/nativeapp/nativeui/traing/training_GPS/src/TraingGPSnotePresenter.cpp
code/sdk/application/wearable/fd230/nativeapp/nativeui/traing/training_card/include/TraingCardPresenter.h
code/sdk/application/wearable/fd230/nativeapp/nativeui/traing/training_card/src/TraingCardPresenter.cpp

index bb848cb..f5d8e0c 100644 (file)
@@ -393,9 +393,9 @@ public:
   //运动心率、gps关闭
   void stop_heart_gps();
   ///////////////////////////////////////////////
-  void Traing_StartTimer(uint32_t interval = 1 * 1000); // 1s定时器
-  void Traing_StopTimer(void);
-  void sport_data_timer(uint32_t interval = 1 * 1000);
+  void gnss_start_timer(uint32_t interval = 1 * 1000); // 1s定时器
+  void gnss_stop_timer(void);
+  void sport_start_data_timer(uint32_t interval = 1 * 1000);
   void sport_stop_data_timer();
 
 private:
index b9c804b..7ad590f 100644 (file)
@@ -35,6 +35,8 @@ namespace OHOS
         bool OnDrag(UIView &view, const DragEvent &event) override;
         bool OnKeyAct(UIView &view, const KeyEvent &event) override; // 增加按键事件
         // bool OnDragEnd(UIView& view, const DragEvent& event) override;
+
+        bool enter_flag{false};
     };
 } // namespace OHOS
 
index 94ade42..fa50c4a 100644 (file)
@@ -24,9 +24,8 @@
 
 #include "ConfigModel.h"
 
-#ifdef BLE_SERVER_ENABLE
+#ifdef SUPPORT_BLE_SERVICE
 #include "bleEvent.h"
-#include "bleInstruct.h"
 #include "bleService.h"
 #endif
 
@@ -156,7 +155,7 @@ static void Training_Notify(void *args, const Topic topic, Request *request) {
                     "memcpy_s act_result_t fail  ret = %d", rets);
       return;
     }
-#ifdef BLE_SERVER_ENABLE
+#ifdef SUPPORT_BLE_SERVICE
     TraingCardPresenter::GetInstance()->send_sport_cmd(traingbleInfo);
 #endif
     delete traingbleInfo;
@@ -472,7 +471,7 @@ void TraingModel::SetSportState(ExerciseState state) {
       if (state == ExerciseState::Start) {
         sportdata->duration = 0;
       }
-#ifdef BLE_SERVER_ENABLE
+#ifdef SUPPORT_BLE_SERVICE
       sendtraningstatedata(static_cast<uint8_t>(state), sportdata->duration);
 #endif
     }
@@ -767,6 +766,9 @@ void TraingModel::SetTimestamp() {
 
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "开始运动");
 
+    sport_start_data_timer(300); //开启数据获取定时器 刷新频率是300ms
+
+#ifdef SYSTEM_LOG_SERVICE
     //日志记录
     if (Openingway) {
       uapi_save_runtime_log(RUNTIME_LOG_APP_SPORT_LAUNCH); // app发起运动
@@ -778,8 +780,11 @@ void TraingModel::SetTimestamp() {
     } else {
       uapi_save_runtime_log(RUNTIME_LOG_SPORT_NORMAL_START); //普通运动
     }
+#endif
 
   } else if (currentState == ExerciseState::End && !Endstate) {
+    sport_stop_data_timer(); //停止数据获取定时器
+
     // 设置训练 runtime 为 0 训练结束
     uapi_dev_runtime_set_train_status(0);
     if (Openingway) {
@@ -1727,7 +1732,7 @@ std::string TraingModel::GetPaceTablePath(uint32_t timestamp) {
 }
 /*发送实时数据*/
 void TraingModel::SendLiveData() {
-  #ifdef SUPPORT_BLE_SERVICE
+#ifdef SUPPORT_BLE_SERVICE
   msg_get_train_data_info_t data;
   memset(&data, 0, sizeof(msg_get_train_data_info_t));
   WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "sportdata->starttime %d \r\n",
@@ -1742,7 +1747,7 @@ void TraingModel::SendLiveData() {
   WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SendLiveData Begin!");
   sendtraningdata(&data); // 发送数据函数
   WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SendLiveData Stop!");
-  #endif
+#endif
 }
 /* -------------------------------- 运动识别发起处理
  * -------------------------------- */
@@ -2997,8 +3002,9 @@ std::string TraingModel::GetGPSDataPath(uint32_t timestamp) {
 
   // 如果未找到,检查时间戳相差1到2秒的文件
   for (int i = -2; i <= 2; ++i) {
-    uint32_t checkTimestamp = timestamp + i; 
-    std::string filePath = TRAINING_GPS_FILE + std::to_string(checkTimestamp) + ".bin";
+    uint32_t checkTimestamp = timestamp + i;
+    std::string filePath =
+        TRAINING_GPS_FILE + std::to_string(checkTimestamp) + ".bin";
     if (IsFileAccessibleAndNotEmpty(filePath)) {
       WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "找到gps表: %s", filePath.c_str());
       return filePath; // 返回找到的文件路径
@@ -3037,80 +3043,85 @@ void TraingModel::start_heart_gps() { OpenGPS(); }
 //运动心率、gps关闭
 void TraingModel::stop_heart_gps() { CloseGPS(); }
 
-/////////////////////////////////////gps定时器/////////////////////////////////////
-static osTimerId_t g_timer = nullptr;
-static int Time = 30;
-/*定时器到期时的处理*/
-/*定时器到期时的处理*/
-static void Traing_TimerCallbackProc(int data) {
+/////////////////////////////////////位置服务定时器/////////////////////////////////////
+/*
+ * 位置服务定时器说明:
+ * - 功能:负责获取GPS定位数据,更新GPS连接状态,添加经纬度数据
+ * - 频率:1秒间隔,保证位置数据的实时性
+ * - 触发条件:仅在训练进行中且训练状态非结束时执行
+ */
+static osTimerId_t g_location_timer = nullptr;
+static int location_timer_interval = 1; // 位置数据获取间隔,单位秒
+
+/*位置服务定时器到期时的处理*/
+static void gnss_timer_callbackProc(int data) {
   /*
-      定时倒计时 后续实现
+      GPS数据获取处理
   */
 #if defined(SUPPORT_GNSS)
-    gps_data_t send_gps_data = {0};
-    gps_data_t *gps_data = getPGPSGlobaldata();
-    
-    if (gps_data == NULL) {
-        PRINT("gps_data == NULL \n");
-        return;
-    }
+  gps_data_t send_gps_data = {0};
+  gps_data_t *gps_data = getPGPSGlobaldata();
 
-    // 判断是否为第一次定位并复制GPS数据
-    if (gps_data->last_gps_time_ms > 0) {
-      memcpy_s(&send_gps_data, sizeof(gps_data_t), gps_data, sizeof(gps_data_t));
-    }
-    else
-    {
-      return;
-    }
+  if (gps_data == NULL) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "gps_data == NULL");
+    return;
+  }
+
+  // 判断是否为第一次定位并复制GPS数据
+  if (gps_data->last_gps_time_ms > 0) {
+    memcpy_s(&send_gps_data, sizeof(gps_data_t), gps_data, sizeof(gps_data_t));
+  } else {
+    return;
+  }
 
-    // 判断是否定位成功并设置连接状态
-    bool isGpsConnected = (send_gps_data.status > 1);
-    TraingModel::GetInstance()->SetGPSConnectState(isGpsConnected);
+  // 判断是否定位成功并设置连接状态
+  bool isGpsConnected = (send_gps_data.status > 1);
+  TraingModel::GetInstance()->SetGPSConnectState(isGpsConnected);
 
-    // 判断是否在运动或训练已结束
-    if (uapi_dev_runtime_get_train_status() == 0 ||
-        TraingModel::GetInstance()->GetSportState() == ExerciseState::End) {
-        return;
-    }
+  // 判断是否在运动或训练已结束
+  if (uapi_dev_runtime_get_train_status() == 0 ||
+      TraingModel::GetInstance()->GetSportState() == ExerciseState::End) {
+    return;
+  }
 
-    // 如果定位成功,添加经纬度数据
-    if (isGpsConnected) {
-        uint32_t time = TraingModel::GetInstance()->get_current_time();
-        TraingModel::GetInstance()->AddGPSData(time, send_gps_data.location.lat,
-                                              send_gps_data.location.lng);
-    }
+  // 如果定位成功,添加经纬度数据
+  if (isGpsConnected) {
+    uint32_t time = TraingModel::GetInstance()->get_current_time();
+    TraingModel::GetInstance()->AddGPSData(time, send_gps_data.location.lat,
+                                           send_gps_data.location.lng);
+  }
 #endif
 }
+
 /*
- * @brief 回调函数
+ * @brief 位置服务定时器回调函数
  */
-static void Traing_TimerCallback(int data) {
-  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Traing_TimerCallback %d", data);
+static void gnss_timer_callback(int data) {
+  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "gnss_timer_callback %d", data);
   GraphicService::GetInstance()->PostGraphicEvent(
-      std::bind(Traing_TimerCallbackProc, data));
+      std::bind(gnss_timer_callbackProc, data));
 }
 
 /*
- *  @brief 开启定时器函数
+ *  @brief 开启位置服务定时器函数
  *  @param interval 时间间隔,单位ms
  */
-void TraingModel::Traing_StartTimer(uint32_t interval) {
-  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "TraingModel::Traing_StartTimer");
-  /* -------------------------- 1.检查定时器是否已经存在,如果存在则返回
+void TraingModel::gnss_start_timer(uint32_t interval) {
+  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "TraingModel::gnss_start_timer");
+  /* -------------------------- 1.检查位置服务定时器是否已经存在,如果存在则返回
    * ------------------------- */
-  if (g_timer != nullptr) {
-    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timer already exists!!");
+  if (g_location_timer != nullptr) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Location Timer already exists!!");
     return;
   }
 
-  /* --------------------------------- 2.创建定时器
+  /* --------------------------------- 2.创建位置服务定时器
    * -------------------------------- */
-  g_timer = osTimerNew((osTimerFunc_t)Traing_TimerCallback, osTimerPeriodic,
+  g_location_timer = osTimerNew((osTimerFunc_t)gnss_timer_callback, osTimerPeriodic,
                        nullptr, nullptr);
   // 检查定时器创建是否成功
-  if (g_timer == nullptr) {
-    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timer create failed!!");
+  if (g_location_timer == nullptr) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Location Timer create failed!!");
     return;
   }
 
@@ -3118,50 +3129,61 @@ void TraingModel::Traing_StartTimer(uint32_t interval) {
    * ---------------------------- */
   int tick = osMs2Tick(interval);
 
-  /* --------------------------------- 4.启动定时器
+  /* --------------------------------- 4.启动位置服务定时器
    * -------------------------------- */
-  osStatus_t ret = osTimerStart(g_timer, tick);
-  /* -------------------- 5.检查定时器启动是否成功,如果启动失败,删除定时器并置为
+  osStatus_t ret = osTimerStart(g_location_timer, tick);
+  /* -------------------- 5.检查位置服务定时器启动是否成功,如果启动失败,删除定时器并置为
    * nullptr -------------------- */
   if (ret != osOK) {
-    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "osTimerDelete failed, ret = %lx!!",
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Location Timer start failed, ret = %lx!!",
                   ret);
-    if (g_timer != nullptr) {
-      ret = osTimerDelete(g_timer);
+    if (g_location_timer != nullptr) {
+      ret = osTimerDelete(g_location_timer);
     }
-    g_timer = nullptr;
+    g_location_timer = nullptr;
     return;
   }
 }
+
 /*
- * @brief 停止定时器
+ * @brief 停止位置服务定时器
  */
-void TraingModel::Traing_StopTimer(void) {
-  // 检查定时器是否存在
-  if (g_timer != nullptr) {
-    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "TraingModel::Traing_StopTimer");
-    osTimerStop(g_timer);
+void TraingModel::gnss_stop_timer(void) {
+  // 检查位置服务定时器是否存在
+  if (g_location_timer != nullptr) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "TraingModel::gnss_stop_timer");
+    osTimerStop(g_location_timer);
     // 删除定时器并置为 nullptr
-    osStatus_t ret = osTimerDelete(g_timer);
+    osStatus_t ret = osTimerDelete(g_location_timer);
     if (ret != osOK) {
       WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
-                    "osTimerDelete failed, ret = %lx!!", ret);
+                    "Location Timer delete failed, ret = %lx!!", ret);
     }
-    g_timer = nullptr;
+    g_location_timer = nullptr;
   }
 }
 
-///////////////////////////////////////datatimer//////////////////////////////////
+///////////////////////////////////////运动数据采集定时器//////////////////////////////////
+/*
+ * 运动数据采集定时器说明:
+ * - 功能:负责获取运动数据(步数、距离、卡路里、心率等),更新训练目标完成度
+ * - 频率:300ms间隔,保证运动数据的实时性和准确性
+ * - 触发条件:仅在训练进行中且训练状态非结束时执行
+ * - 包含服务:CYWEE运动数据、PPG心率数据、训练目标检查、UI更新
+ */
 #if SPORT_TIMER_DATA
-// 声明定时器变量
-static osTimerId_t g_data_timer = nullptr;
-static void sport_data_callbackProc(int data) {
+// 声明运动数据采集定时器变量
+static osTimerId_t g_sport_start_data_timer = nullptr;
+static int sport_start_data_timer_interval = 300; // 运动数据获取间隔,单位毫秒
+
+static void sport_data_time_proc(int data) {
   //增加训练runtime控制
   if (uapi_dev_runtime_get_train_status() == 0 ||
       TraingModel::GetInstance()->GetSportState() == ExerciseState::End) {
     return;
   }
-  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "sport_data_callbackProc");
+  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "sport_data_time_proc");
+  
 #ifdef SUPPORT_CYWEE_SERVICE
   act_result_t cyweeInfo;
   cywee_get_act_data(&cyweeInfo);
@@ -3170,68 +3192,67 @@ static void sport_data_callbackProc(int data) {
   TraingModel::GetInstance()->CheckSportTag();
 
   act_ext_result_t cyweeInfo_ext;
-
   cywee_get_act_ext_data(&cyweeInfo_ext);
   TraingModel::GetInstance()->AnalysisExtraData(&cyweeInfo_ext);
 #endif
+
   //训练心率
   uint8_t hrs = 0;
 #ifdef SUPPORT_PPG_SERVICE
   hrs = ppg_get_hrs();
-  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"heart_data_callbackProc::hrs = %d\n", hrs);
+  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"Training data timer: heart rate = %d", hrs);
 #endif
   TraingModel::GetInstance()->AnalysisHeartData(hrs);
 
-  if(TraingCardPresenter::GetInstance())
-  {
+  if (TraingCardPresenter::GetInstance()) {
     TraingCardPresenter::GetInstance()->updataview();
   }
-
 }
 
-static void sport_data_timer_callback(int data) {
+static void sport_data_time_callback(int data) {
   GraphicService::GetInstance()->PostGraphicEvent(
-      std::bind(sport_data_callbackProc, data));
+      std::bind(sport_data_time_proc, data));
 }
 
-void TraingModel::sport_data_timer(uint32_t interval) {
+void TraingModel::sport_start_data_timer(uint32_t interval) {
   WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
-                "TraingModel::sport_start_screen60s_timer");
-  if (g_data_timer != nullptr) {
-    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timer already exists!!");
+                "TraingModel::sport_start_data_timer - Starting sport data timer");
+  if (g_sport_start_data_timer != nullptr) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Sport Data Timer already exists!!");
     return;
   }
-  g_data_timer = osTimerNew((osTimerFunc_t)sport_data_timer_callback,
+  g_sport_start_data_timer = osTimerNew((osTimerFunc_t)sport_data_time_callback,
                             osTimerPeriodic, nullptr, nullptr);
-  if (g_data_timer == nullptr) {
-    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timer create failed!!");
+  if (g_sport_start_data_timer == nullptr) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Sport Data Timer create failed!!");
     return;
   }
   int tick = osMs2Tick(interval);
-  osStatus_t ret = osTimerStart(g_data_timer, tick);
+  osStatus_t ret = osTimerStart(g_sport_start_data_timer, tick);
   if (ret != osOK) {
-    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "osTimerDelete failed, ret = %lx!!",
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Sport Data Timer start failed, ret = %lx!!",
                   ret);
-    if (g_data_timer != nullptr) {
-      ret = osTimerDelete(g_data_timer);
+    if (g_sport_start_data_timer != nullptr) {
+      ret = osTimerDelete(g_sport_start_data_timer);
     }
-    g_data_timer = nullptr;
+    g_sport_start_data_timer = nullptr;
     return;
   }
 }
+
 void TraingModel::sport_stop_data_timer(void) {
-  // 检查定时器是否存在
-  if (g_data_timer != nullptr) {
+  // 检查运动数据采集定时器是否存在
+  if (g_sport_start_data_timer != nullptr) {
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
-                  "TraingModel::sport_stop_screen60s_timer");
-    osTimerStop(g_data_timer);
+                  "TraingModel::sport_stop_data_timer - Stopping sport data timer");
+    osTimerStop(g_sport_start_data_timer);
     // 删除定时器并置为 nullptr
-    osStatus_t ret = osTimerDelete(g_data_timer);
+    osStatus_t ret = osTimerDelete(g_sport_start_data_timer);
     if (ret != osOK) {
       WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
-                    "osTimerDelete failed, ret = %lx!!", ret);
+                    "Sport Data Timer delete failed, ret = %lx!!", ret);
     }
-    g_data_timer = nullptr;
+    g_sport_start_data_timer = nullptr;
   }
 }
 #endif
@@ -3340,4 +3361,20 @@ void ble_training_init(void) {
 
 #endif
 
+/*
+ * 定时器分工总结:
+ * 
+ * 1. 位置服务定时器 (g_location_timer)
+ *    - 频率:1秒间隔
+ *    - 功能:GPS定位、连接状态更新、轨迹数据采集
+ *    - 特点:中等频率,保证位置数据实时性
+ * 
+ * 2. 运动数据采集定时器 (g_sport_start_data_timer)
+ *    - 频率:300毫秒间隔
+ *    - 功能:运动数据采集、心率监测、目标完成度检查、UI更新
+ *    - 特点:高频率,保证运动数据实时性和准确性
+ * 
+ * 两个定时器独立运行,互不干扰,根据各自功能特点选择合适的执行频率
+ */
+
 } // namespace OHOS
index 09cc2e9..1e2a2a7 100644 (file)
@@ -47,19 +47,16 @@ namespace OHOS
 \r
     void TraingNomalPresenter::OnStart()\r
     {\r
-        TraingModel::GetInstance()->Traing_StartTimer(1000);\r
+        TraingModel::GetInstance()->gnss_start_timer(1000);\r
         Presenter<TraingNomalView>::OnStart();\r
     }\r
 \r
-    void TraingNomalPresenter::OnPause(void)\r
-    {\r
-        TraingModel::GetInstance()->Traing_StopTimer();\r
+    void TraingNomalPresenter::OnPause(void){\r
         Presenter<TraingNomalView>::OnPause();\r
     }\r
 \r
     void TraingNomalPresenter::OnResume(void)\r
     {\r
-\r
         Presenter<TraingNomalView>::OnResume();\r
     }\r
 \r
@@ -79,8 +76,13 @@ namespace OHOS
             4.[设置训练目标]进入 {不返回}\r
         */\r
         NativeAbility::GetInstance().Back(TransitionType::TRANSITION_BACK_TO_HEXAGONS);\r
-        // 关闭gps\r
+        //如果不是进入运动界面\r
+        if(enter_flag == false){\r
+        // 关闭gps与心率\r
         TraingModel::GetInstance()->stop_heart_gps();\r
+        // 关闭gps定时器\r
+        TraingModel::GetInstance()->gnss_start_timer();\r
+        }\r
     }\r
     bool TraingNomalPresenter::OnDrag(UIView &view, const DragEvent &event)\r
     {\r
@@ -120,6 +122,7 @@ namespace OHOS
             TraingCardPresenter::GetInstance()->OpenSensor(type);\r
             // 设置为手表开启运动\r
             TraingModel::GetInstance()->SetSportOpenWay(false);\r
+            enter_flag = true;\r
         }\r
         return true;\r
     }\r
@@ -139,6 +142,5 @@ namespace OHOS
     {\r
         //获取gps定位状态\r
         TraingNomalView::GetInstance()->updateview();\r
-        \r
     }\r
 }\r
index 250bddf..008085a 100644 (file)
@@ -80,11 +80,11 @@ namespace OHOS
         // 根据控件id查找是哪个控件触发了点击回调
         if (strcmp(view.GetViewId(), BUTTONBACK) == 0)
         {
-            // NativeAbility::GetInstance().ChangeSlice(VIEW_TRAININGGPSLACK);
+            NativeAbility::GetInstance().ChangeSlice(VIEW_TRAININGNOMAL);
         }
         if (strcmp(view.GetViewId(), BUTTONGO) == 0)
         {
-            // NativeAbility::GetInstance().ChangeSlice(VIEW_TRAININGGPSLOST);
+            NativeAbility::GetInstance().ChangeSlice(VIEW_TRAININGCRAD);
         }
         return true;
     }
index f5169f9..9dad127 100644 (file)
@@ -427,7 +427,7 @@ bool TraingCardPresenter::OnKeyAct(UIView &view, const KeyEvent &event) {
 }\r
 /* -------------------------------- 协议发起运动处理\r
  * -------------------------------- */\r
-#ifdef BLE_SERVER_ENABLE\r
+#ifdef SUPPORT_BLE_SERVICE\r
 bool TraingCardPresenter::send_sport_cmd(training_ble *cmd) {\r
   if (cmd == nullptr) {\r
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "无效的运动命令 cmd 为空!");\r