From f21aa52cd18dea8bd8087472e1a5181bbd3dca5f Mon Sep 17 00:00:00 2001 From: Caisking Date: Tue, 1 Jul 2025 17:36:48 +0800 Subject: [PATCH] =?utf8?q?=E5=A2=9E=E5=8A=A0GPS=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../nativeui/traing/include/TraingModel.h | 23 +- .../nativeui/traing/src/TraingModel.cpp | 287 +++++++++++++----- 2 files changed, 230 insertions(+), 80 deletions(-) diff --git a/code/sdk/application/wearable/fd230app/nativeui/traing/include/TraingModel.h b/code/sdk/application/wearable/fd230app/nativeui/traing/include/TraingModel.h index 83673f370..14de24648 100644 --- a/code/sdk/application/wearable/fd230app/nativeui/traing/include/TraingModel.h +++ b/code/sdk/application/wearable/fd230app/nativeui/traing/include/TraingModel.h @@ -250,10 +250,7 @@ struct GPSData { double longitude; // 经度 }; //画布点位结构体 -struct CanvasPoint { - int x; - int y; -}; + class TraingModel { public: TraingModel(); @@ -368,11 +365,23 @@ public: //映射经纬度数据集映射画布绘制轨迹坐标集 void GetPointData(); //添加经纬度数据集 - void AddGPSData(double latitude, double longitude); + void AddGPSData(uint32_t timestamp, double latitude, double longitude); + bool SaveCanvasData(); + void ClearCanvasData(); + std::string GetGPSDataPath(uint32_t timestamp); //获取轨迹点集 - std::vector GetCanvasData()const; + std::vector GetCanvasData()const; bool GetGPSConnectState(); void SetGPSConnectState(bool state); + void OpenGPS(); + void CloseGPS(); + //运动心率、gps开启准备 + void start_heart_gps(); + //运动心率、gps关闭 + void stop_heart_gps(); + /////////////////////////////////////////////// + void Traing_StartTimer(uint32_t interval = 1 * 1000); // 1s定时器 + void Traing_StopTimer(void); private: TraingModel(const TraingModel &) = delete; @@ -422,7 +431,7 @@ private: ////////////////////GPS数据集配置///////////////// double latitude{0}; double longitude{0}; - std::vector canvasData; // 轨迹点集 + std::vector canvasData; // 轨迹点集 std::vector gpsData; // GPS数据集 bool gpsconnect{false}; }; diff --git a/code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingModel.cpp b/code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingModel.cpp index 0196798e4..83bd9dfba 100644 --- a/code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingModel.cpp +++ b/code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingModel.cpp @@ -50,11 +50,17 @@ #include "bleService.h" #include "chip_system_time.h" -#include #include "cmath" +#include "system/include/SystemLogModel.h" +#include -extern "C" errcode_t uapi_get_timestampe_ms(uint32_t *tm); -extern "C" errcode_t uapi_get_timestampe_ss(uint32_t *tm); +#if defined(SUPPORT_GNSS) +#include "NMEA0183.h" +#include "gnss_ctl.h" +#include "gnss_sample.h" +#include "graphic_service.h" +gps_data_t send_gps_data = {0}; +#endif #ifdef __cplusplus extern "C" { @@ -138,7 +144,8 @@ static void Training_Notify(void *args, const Topic topic, Request *request) { delete traingbleInfo; } //增加训练runtime控制 - if (uapi_dev_runtime_get_train_status() == 0 || TraingModel::GetInstance()->GetSportState() == ExerciseState::End) { + if (uapi_dev_runtime_get_train_status() == 0 || + TraingModel::GetInstance()->GetSportState() == ExerciseState::End) { return; } //训练基本信息更新 @@ -181,6 +188,22 @@ static void Training_Notify(void *args, const Topic topic, Request *request) { uint8_t heart = *((u_int8_t *)(request->data)); // 进行类型转换 TraingModel::GetInstance()->AnalysisHeartData(heart); } + //训练GPS + gps_data_t *gps_data = getGPSGlobaldata(); + if (gps_data == NULL) { + PRINT("gps_data == NULL \n"); + return; + } + //判断是否为第一次定位 + if (gps_data->last_gps_time_ms > 0) { + memcpy_s(&send_gps_data, sizeof(gps_data_t), gps_data, sizeof(gps_data_t)); + } + //判断是否定位成功 + if (send_gps_data.status > 1) { + //添加经纬度 时间戳? + TraingModel::GetInstance()->AddGPSData(send_gps_data.location.lat, + send_gps_data.location.lng); + } } #ifdef __cplusplus } @@ -562,7 +585,7 @@ void TraingModel::AnalysisExtraData( } //最快配速 if (cyweeInfo->max_pace != 0) { - sportdata->fpc =cyweeInfo->max_pace; + sportdata->fpc = cyweeInfo->max_pace; } //平均步频 if (cyweeInfo->avg_step_freq != 0) { @@ -621,7 +644,7 @@ void TraingModel::SetSportdata(SportData *data) { sportdata->spc = data->spc; sportdata->std = data->std; sportdata->cdc = data->cdc; - printf_data(data);//打印该运动数据 + printf_data(data); //打印该运动数据 IsSpecialSport(sportdata->sportId); // 配置训练特殊性 } } @@ -658,8 +681,8 @@ void TraingModel::ResetSharedTrainingData() { shock_count = 0; //重置震动计数 - gpsData.clear();// 清空gps数据 - canvasData.clear();// 清空画布数据 + gpsData.clear(); // 清空gps数据 + canvasData.clear(); // 清空画布数据 } uint32_t TraingModel::get_current_time() { @@ -754,6 +777,9 @@ void TraingModel::SetTimestamp() { //配置最后的训练强度(平均心率为标准) SetIntensity(sportdata->avgheart); + //更新gps点位 + GetPointData(); + do_custom_fileoperate_service_check_msg( CUSTOM_FILEOPERATE_MSG_TYPE_SPORTDATA_SAVE, nullptr, 0); @@ -2352,7 +2378,7 @@ bool TraingModel::LoadDataFormJson(std::vector &sportDataVector) { /* Latitude(纬度):范围:-90° 至 +90°(或南纬 90° 至北纬 90°); Longitude(经度):范围:-180° 至 +180°(或西经 180° 至东经 180°); - + -画布数据集最多是100个定位坐标,超过按比例进行拿取100个点位; -通过映射关系,将经纬度转换为400*400画布上的坐标; -但是不能靠近400,以免显示不全等问题,350*350; @@ -2360,86 +2386,201 @@ bool TraingModel::LoadDataFormJson(std::vector &sportDataVector) { -如果有正数又有负数,应该怎么处理? */ -static double getmin(double a, double b) -{ - return a < b ? a : b; -} +static double getmin(double a, double b) { return a < b ? a : b; } -static double getmax(double a, double b) -{ - return a > b ? a : b; -} +static double getmax(double a, double b) { return a > b ? a : b; } // 通过经纬度数据集映射画布绘制轨迹坐标集 -void TraingModel::GetPointData() -{ - // 1. 按比例采样最多100个点位 - std::vector sampledData; - if (gpsData.size() > 100) { - double step = static_cast(gpsData.size() - 1) / 99; - for (int i = 0; i < 100; i++) { - int index = static_cast(i * step); - sampledData.push_back(gpsData[index]); - } - } else { - sampledData = gpsData; +void TraingModel::GetPointData() { + // 1. 按比例采样最多100个点位 + std::vector sampledData; + if (gpsData.size() > 100) { + double step = static_cast(gpsData.size() - 1) / 99; + for (int i = 0; i < 100; i++) { + int index = static_cast(i * step); + sampledData.push_back(gpsData[index]); } + } else { + sampledData = gpsData; + } - // 2. 计算经纬度的最小值和最大值 - double minLat = 90.0, maxLat = -90.0; - double minLon = 180.0, maxLon = -180.0; - for (const auto& point : sampledData) { - minLat = getmin(minLat, point.latitude); - maxLat = getmax(maxLat, point.latitude); - minLon = getmin(minLon, point.longitude); - maxLon = getmax(maxLon, point.longitude); - } + // 2. 计算经纬度的最小值和最大值 + double minLat = 90.0, maxLat = -90.0; + double minLon = 180.0, maxLon = -180.0; + for (const auto &point : sampledData) { + minLat = getmin(minLat, point.latitude); + maxLat = getmax(maxLat, point.latitude); + minLon = getmin(minLon, point.longitude); + maxLon = getmax(maxLon, point.longitude); + } - // 3. 将经纬度映射到350×350画布区域(居中在400×400画布) - canvasData.clear(); - const double canvasSize = 350.0; - const double offset = 25.0; // 400 - 350 = 50,两边各留25的边距 - - for (const auto& point : sampledData) { - // 归一化处理(0-1范围) - double normLat = (point.latitude - minLat) / (maxLat - minLat); - double normLon = (point.longitude - minLon) / (maxLon - minLon); - - // 映射到画布坐标(考虑偏移) - double x = normLon * canvasSize + offset; - double y = (1.0 - normLat) * canvasSize + offset; // 注意:y轴需要反转(屏幕坐标系向下为正) - - canvasData.push_back({x, y}); - } + // 3. 将经纬度映射到350×350画布区域(居中在400×400画布) + canvasData.clear(); + const double canvasSize = 300.0; + const double offset = 50.0; // 400 - 300 = 100,两边各留50的边距 + + for (const auto &point : sampledData) { + // 归一化处理(0-1范围) + double normLat = (point.latitude - minLat) / (maxLat - minLat); + double normLon = (point.longitude - minLon) / (maxLon - minLon); + + // 映射到画布坐标(考虑偏移) + double x = normLon * canvasSize + offset; + double y = (1.0 - normLat) * canvasSize + + offset; // 注意:y轴需要反转(屏幕坐标系向下为正) + + canvasData.push_back({x, y}); + } + + //修改起点与终点 } // 添加经纬度数据集 -void TraingModel::AddGPSData(double latitude, double longitude) -{ - // 判断数据是否合理 - if (latitude < -90 || latitude > 90 || longitude < -180 || longitude > 180) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid GPS data"); - return; - } - // 添加数据 - gpsData.push_back({latitude, longitude}); +void TraingModel::AddGPSData(uint32_t timestamp, double latitude, + double longitude) { + // 判断数据是否合理 + if (latitude < -90 || latitude > 90 || longitude < -180 || longitude > 180) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid GPS data"); + return; + } + // 添加数据 + gpsData.push_back({latitude, longitude}); } +// //保存 +// bool SaveCanvasData() +// { + +// } + +// void ClearCanvasData() + +// std::string GetGPSDataPath(uint32_t timestamp) + // 获取轨迹点集 -std::vector TraingModel::GetCanvasData() const -{ - return canvasData; -} +std::vector TraingModel::GetCanvasData() const { return canvasData; } //获取GPS连接状态 -bool TraingModel::GetGPSConnectState() -{ - return gpsconnect; -} +bool TraingModel::GetGPSConnectState() { return gpsconnect; } //设置GPS连接状态 -void TraingModel::SetGPSConnectState(bool state) -{ +void TraingModel::SetGPSConnectState(bool state) { + if (gpsconnect != state) { gpsconnect = state; + //状态改变记录 + SystemLogModel::GetInstance()->save_gps_status_log_type(gpsconnect); + } +} +//开启gps +void TraingModel::OpenGPS() { + // 开启GPS的代码逻辑 + gnss_start(); +} +//关闭gps +void TraingModel::CloseGPS() { + // 关闭GPS的代码逻辑 + gnss_stop(); +} +//运动心率、gps开启准备 +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) { + // 倒计时 + Time--; + // 到时的处理 + if (Time < 0) { + // TraingModel::GetInstance()->Traing_timer_callback_out(); + // return; + } + gps_data_t *gps_data = getGPSGlobaldata(); + if (gps_data == NULL) { + PRINT("gps_data == NULL \n"); + return; + } + //判断是否为第一次定位 + if (gps_data->last_gps_time_ms > 0) { + memcpy_s(&send_gps_data, sizeof(gps_data_t), gps_data, sizeof(gps_data_t)); + } + //判断是否定位成功 + if (send_gps_data.status > 1) { + //定位成功 + TraingModel::GetInstance()->SetGPSConnectState(true); + } else { + TraingModel::GetInstance()->SetGPSConnectState(false); + } +} +/* + * @brief 回调函数 + */ +static void Traing_TimerCallback(int data) { + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Traing_TimerCallback %d", data); + GraphicService::GetInstance()->PostGraphicEvent( + std::bind(Traing_TimerCallbackProc, data)); +} + +/* + * @brief 开启定时器函数 + * @param interval 时间间隔,单位ms + */ +void TraingModel::Traing_StartTimer(uint32_t interval) { + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "TraingModel::Traing_StartTimer"); + /* -------------------------- 1.检查定时器是否已经存在,如果存在则返回 + * ------------------------- */ + if (g_timer != nullptr) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timer already exists!!"); + return; + } + + /* --------------------------------- 2.创建定时器 + * -------------------------------- */ + g_timer = osTimerNew((osTimerFunc_t)Traing_TimerCallback, osTimerPeriodic, + nullptr, nullptr); + // 检查定时器创建是否成功 + if (g_timer == nullptr) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timer create failed!!"); + return; + } + + /* ----------------------------- 3.将毫秒转换为系统时钟节拍数 + * ---------------------------- */ + int tick = osMs2Tick(interval); + + /* --------------------------------- 4.启动定时器 + * -------------------------------- */ + osStatus_t ret = osTimerStart(g_timer, tick); + /* -------------------- 5.检查定时器启动是否成功,如果启动失败,删除定时器并置为 + * nullptr -------------------- */ + if (ret != osOK) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "osTimerDelete failed, ret = %lx!!", + ret); + if (g_timer != nullptr) { + ret = osTimerDelete(g_timer); + } + g_timer = nullptr; + return; + } +} +/* + * @brief 停止定时器 + */ +void TraingModel::Traing_StopTimer(void) { + // 检查定时器是否存在 + if (g_timer != nullptr) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "TraingModel::Traing_StopTimer"); + osTimerStop(g_timer); + // 删除定时器并置为 nullptr + osStatus_t ret = osTimerDelete(g_timer); + if (ret != osOK) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "osTimerDelete failed, ret = %lx!!", ret); + } + g_timer = nullptr; + } } } // namespace OHOS -- 2.17.1