新增 cc_cycle_service 与拷机 UI,支持插线自动循环:满电放电(Hi-Z+电池供电)至 10% 后按温控充电;拷机放电阶段修正 SOC 显示并关闭热路径调试日志。
Co-authored-by: Cursor <cursoragent@cursor.com>
// VIEW_MAIN_PHONE, // 主电话Slice
VIEW_DIALING_METHOD, // 拨号方式
VIEW_TEST, // 测试
+ VIEW_CC_CYCLE_BURN, // 充放电拷机亮屏
VIEW_CALCULATOR, // 计算器
// VIEW_SCHEDULE, // 日程
VIEW_SLEEPMODE, // sleep mode
"blemoder",
"transspecard",
"factorytest_service",
+ "cc_cycle_service",
# "hid_service",
"producttest",
"ppg_hal",
${CMAKE_CURRENT_SOURCE_DIR}/src/testhrsenson.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/testgsenson.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/testold.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/testCcCycle.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ccCycleBurnView.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ccCycleBurnPresenter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/testbt.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/testSEChipTest.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/testModel.cpp
${ROOT_DIR}/open_source/openharmony/third_party/qrcodegen/cpp
${ROOT_DIR}/zhihui/services/factorytest_service
+ ${ROOT_DIR}/zhihui/services/cc_cycle_service
${ROOT_DIR}/zhihui/drivers/
${ROOT_DIR}/zhihui/drivers/charge/hp4570
${ROOT_DIR}/zhihui/4g/cat1Service/include
${ROOT_DIR}/application/wearable/fd272/nativeapp/nativeui/alarmclocktimerconfig/include
${ROOT_DIR}/application/wearable/fd272/nativeapp/nativeui/player/include
${ROOT_DIR}/zhihui/services/factorytest_service
+ ${ROOT_DIR}/zhihui/services/cc_cycle_service
)
elseif( BOARD_N9 IN_LIST DEFINES )
set(PRIVATE_HEADER
--- /dev/null
+#ifndef CC_CYCLE_BURN_PRESENTER_H
+#define CC_CYCLE_BURN_PRESENTER_H
+
+#include "Presenter.h"
+#include "ccCycleBurnView.h"
+namespace OHOS
+{
+ class ccCycleBurnPresenter : public Presenter<ccCycleBurnView>,
+ public UIView::OnDragListener
+ {
+ public:
+ ccCycleBurnPresenter();
+ ~ccCycleBurnPresenter() override;
+ static ccCycleBurnPresenter *GetInstance(void);
+
+ void OnStart() override;
+ void OnResume() override;
+ void OnPause() override;
+ void OnStop() override;
+
+ private:
+ bool OnDrag(UIView &view, const DragEvent &event) override;
+ bool OnDragEnd(UIView &view, const DragEvent &event) override;
+ static bool IsSwipeBackToExit(const DragEvent &event);
+ };
+}
+
+#endif
--- /dev/null
+#ifndef CC_CYCLE_BURN_VIEW_H
+#define CC_CYCLE_BURN_VIEW_H
+
+#include "View.h"
+#include "components/ui_view_group.h"
+#include "components/ui_label.h"
+
+#ifdef ENABLE_HP4570
+#include "cc_cycle_service.h"
+#endif
+
+namespace OHOS
+{
+ class ccCycleBurnPresenter;
+
+ class ccCycleBurnView : public View<ccCycleBurnPresenter>
+ {
+ public:
+ ccCycleBurnView();
+ ~ccCycleBurnView() override;
+ static ccCycleBurnView *GetInstance(void);
+
+ void OnStart() override;
+ void OnStop() override;
+ void RefreshStatus(void);
+ void ApplyScreenAlwaysOn(void);
+
+ private:
+ void DestroyBurnWidgets(void);
+ bool CreateBurnView(void);
+
+ UIViewGroup *burnGroup_{nullptr};
+ UILabel *phaseLabel_{nullptr};
+ UILabel *statusLabel_{nullptr};
+ bool viewInit_{false};
+ void UpdatePhaseBackground(cc_cycle_phase_e phase);
+ };
+}
+
+#endif
--- /dev/null
+#ifndef TEST_CC_CYCLE_VIEW_H
+#define TEST_CC_CYCLE_VIEW_H
+
+#include "components/ui_scroll_view.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button_ext.h"
+
+namespace OHOS
+{
+ class testCcCycleView
+ {
+ public:
+ testCcCycleView();
+ virtual ~testCcCycleView();
+ static testCcCycleView *GetInstance(void);
+
+ UIScrollView *testCcCycleInitIView(uint8_t id);
+ void ClearAll(void);
+ void RefreshCcCycleButtons(void);
+ void RefreshStatusLabel(void);
+
+ private:
+ static void StatusTimerCallback(void *arg);
+ bool testCcCycleScrollViewInit(uint8_t id);
+ UIScrollView *testCcCycleScrollView_{nullptr};
+ UILabel *title_{nullptr};
+ UILabel *statusLabel_{nullptr};
+ UILabel *hintLabel_{nullptr};
+ UILabelButtonExt *labelButton_cc_sw_{nullptr};
+ UILabelButtonExt *labelButton_cc_enter_{nullptr};
+ UILabelButtonExt *labelButton_next_{nullptr};
+ };
+}
+
+#endif
#endif\r
LUMINANCE,\r
CHARG,\r
+#ifdef ENABLE_HP4570\r
+ CCCYCLE,\r
+#endif\r
SPEAK,\r
MOTOR,\r
#ifdef SUPPORT_CAT1_SERVICE\r
#include "producttest/include/testhrsenson.h"\r
#include "producttest/include/testgsenson.h"\r
#include "producttest/include/testold.h"\r
+#ifdef ENABLE_HP4570\r
+#include "producttest/include/testCcCycle.h"\r
+#endif\r
#include "producttest/include/testbt.h"\r
#include "producttest/include/testSEChipTest.h"\r
#include "producttest/include/testPing.h"\r
bool ChangeTPTESTView(int16_t thisView);\r
bool ChangLUMTESTView(int16_t thisView);\r
bool ChangchargingTESTView(int16_t thisView);\r
+#ifdef ENABLE_HP4570\r
+ bool ChangeCcCycleTESTView(int16_t thisView);\r
+#endif\r
bool ChangspeakTESTView(int16_t thisView);\r
bool ChangmotorTESTView(int16_t thisView);\r
bool ChangKEYTESTView(int16_t thisView);\r
testTPView *test_TP_view{nullptr};\r
testLUMView *test_lum_view{nullptr};\r
testCHANINGView *test_charging_view{nullptr};\r
+#ifdef ENABLE_HP4570\r
+ testCcCycleView *test_cc_cycle_view{nullptr};\r
+#endif\r
testSPEAKView *test_speak_view{nullptr};\r
testMOTORView *test_motor_view{nullptr};\r
testcat1View *test_cat1_view{nullptr};\r
--- /dev/null
+#include "AppViewIDs.h"
+#include "NativeAbility.h"
+#include "NativeRegisterManager.h"
+#include "producttest/include/ccCycleBurnPresenter.h"
+#include "producttest/include/ccCycleBurnView.h"
+#include "producttest/include/testPresenter.h"
+#include "producttest/include/testView.h"
+#include "producttest/include/testCcCycle.h"
+#include "wearable_log.h"
+#include "common/screen.h"
+#include "cmsis_os2.h"
+#include <cstdlib>
+#include <cstring>
+
+#ifdef ENABLE_HP4570
+#include "cc_cycle_service.h"
+#endif
+
+static osTimerId_t g_ccBurnRefreshTimer = nullptr;
+static osTimerId_t g_ccBurnShowUiTimer = nullptr;
+static volatile uint8_t g_burnUiValid = 0;
+
+static void cc_burn_refresh_timer_cb(void *arg)
+{
+ (void)arg;
+ if (!g_burnUiValid) {
+ return;
+ }
+#ifdef ENABLE_HP4570
+ if (!cc_cycle_is_running()) {
+ return;
+ }
+#endif
+ OHOS::ccCycleBurnView *v = OHOS::ccCycleBurnView::GetInstance();
+ if (v != nullptr) {
+ v->RefreshStatus();
+ }
+}
+
+static void cc_burn_show_ui_timer_cb(void *arg)
+{
+ (void)arg;
+#ifdef ENABLE_HP4570
+ if (!cc_cycle_is_running()) {
+ return;
+ }
+#endif
+ OHOS::NativeAbility::GetInstance().ChangeSlice(VIEW_CC_CYCLE_BURN);
+}
+
+namespace OHOS
+{
+ REGIST_SLICE(VIEW_CC_CYCLE_BURN, ccCycleBurnView, ccCycleBurnPresenter);
+
+ static ccCycleBurnPresenter *g_burnPresenter = nullptr;
+
+ ccCycleBurnPresenter::ccCycleBurnPresenter()
+ {
+ g_burnPresenter = this;
+ }
+
+ ccCycleBurnPresenter::~ccCycleBurnPresenter()
+ {
+ if (g_ccBurnRefreshTimer != nullptr) {
+ (void)osTimerStop(g_ccBurnRefreshTimer);
+ (void)osTimerDelete(g_ccBurnRefreshTimer);
+ g_ccBurnRefreshTimer = nullptr;
+ }
+ g_burnPresenter = nullptr;
+ }
+
+ ccCycleBurnPresenter *ccCycleBurnPresenter::GetInstance(void)
+ {
+ return g_burnPresenter;
+ }
+
+ bool ccCycleBurnPresenter::IsSwipeBackToExit(const DragEvent &event)
+ {
+ if (event.GetDragDirection() != DragEvent::DIRECTION_LEFT_TO_RIGHT) {
+ return false;
+ }
+ Point startPoint = event.GetStartPoint();
+ Point endPoint = event.GetLastPoint();
+ int dragDistance = endPoint.x - startPoint.x;
+ int dragHeight = abs(endPoint.y - startPoint.y);
+ int screenWidth = Screen::GetInstance().GetWidth();
+
+ return (dragDistance > 80 && dragHeight < 80 &&
+ startPoint.x < screenWidth / 2 && dragDistance > dragHeight * 2);
+ }
+
+ bool ccCycleBurnPresenter::OnDrag(UIView &view, const DragEvent &event)
+ {
+ (void)view;
+ (void)event;
+ return true;
+ }
+
+ bool ccCycleBurnPresenter::OnDragEnd(UIView &view, const DragEvent &event)
+ {
+ (void)view;
+ if (IsSwipeBackToExit(event)) {
+ cc_cycle_hide_burn_ui();
+ return true;
+ }
+ return false;
+ }
+
+ void ccCycleBurnPresenter::OnStart()
+ {
+ Presenter<ccCycleBurnView>::OnStart();
+ g_burnUiValid = 1;
+ if (g_ccBurnRefreshTimer == nullptr) {
+ g_ccBurnRefreshTimer = osTimerNew(cc_burn_refresh_timer_cb, osTimerPeriodic, nullptr, nullptr);
+ }
+ if (g_ccBurnRefreshTimer != nullptr) {
+ (void)osTimerStart(g_ccBurnRefreshTimer, 1000);
+ }
+ }
+
+ void ccCycleBurnPresenter::OnResume(void)
+ {
+ if (view_ != nullptr) {
+ view_->ApplyScreenAlwaysOn();
+ view_->RefreshStatus();
+ }
+ }
+
+ void ccCycleBurnPresenter::OnPause(void)
+ {
+ Presenter<ccCycleBurnView>::OnPause();
+ }
+
+ void ccCycleBurnPresenter::OnStop(void)
+ {
+ g_burnUiValid = 0;
+ if (g_ccBurnRefreshTimer != nullptr) {
+ (void)osTimerStop(g_ccBurnRefreshTimer);
+ }
+ Presenter<ccCycleBurnView>::OnStop();
+ }
+}
+
+void cc_cycle_show_burn_ui(void)
+{
+ if (g_ccBurnShowUiTimer == nullptr) {
+ g_ccBurnShowUiTimer = osTimerNew(cc_burn_show_ui_timer_cb, osTimerOnce, nullptr, nullptr);
+ }
+ if (g_ccBurnShowUiTimer != nullptr) {
+ (void)osTimerStop(g_ccBurnShowUiTimer);
+ (void)osTimerStart(g_ccBurnShowUiTimer, 500);
+ }
+}
+
+void cc_cycle_hide_burn_ui(void)
+{
+ OHOS::NativeAbility::GetInstance().ChangeSlice(VIEW_TEST);
+ if (OHOS::testView::GetInstance() != nullptr) {
+#ifdef ENABLE_HP4570
+ OHOS::testView::GetInstance()->ChangeView(OHOS::TESTVIEW, OHOS::CCCYCLE);
+#else
+ OHOS::testView::GetInstance()->ChangeView(OHOS::TESTVIEW, OHOS::TESTVIEW);
+#endif
+ }
+ if (OHOS::testCcCycleView::GetInstance() != nullptr) {
+ OHOS::testCcCycleView::GetInstance()->RefreshCcCycleButtons();
+ }
+}
--- /dev/null
+#include "producttest/include/ccCycleBurnView.h"
+#include "producttest/include/ccCycleBurnPresenter.h"
+#include "wearable_log.h"
+#include "common/screen.h"
+#include "gfx_utils/color.h"
+#include "power_display_service.h"
+#include "custom_utils.h"
+#include <cstdio>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "pm_definition.h"
+#include "pm_veto.h"
+#include "pm.h"
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef ENABLE_HP4570
+#include "cc_cycle_service.h"
+#endif
+
+namespace OHOS
+{
+ static ccCycleBurnView *g_burnView = nullptr;
+
+ ccCycleBurnView::ccCycleBurnView()
+ {
+ g_burnView = this;
+ }
+
+ ccCycleBurnView::~ccCycleBurnView()
+ {
+ DestroyBurnWidgets();
+ g_burnView = nullptr;
+ }
+
+ ccCycleBurnView *ccCycleBurnView::GetInstance(void)
+ {
+ return g_burnView;
+ }
+
+ void ccCycleBurnView::UpdatePhaseBackground(cc_cycle_phase_e phase)
+ {
+ if (burnGroup_ == nullptr) {
+ return;
+ }
+ if (phase == CC_PHASE_CHARGING) {
+ burnGroup_->SetStyle(STYLE_BACKGROUND_COLOR, 0xFFC8E6C9); /* 浅绿=充电 */
+ if (phaseLabel_ != nullptr) {
+ phaseLabel_->SetStyle(STYLE_TEXT_COLOR, 0xFF1B5E20);
+ phaseLabel_->SetText("【充电中】");
+ }
+ } else if (phase == CC_PHASE_DISCHARGE) {
+ burnGroup_->SetStyle(STYLE_BACKGROUND_COLOR, Color::White().full);
+ if (phaseLabel_ != nullptr) {
+ phaseLabel_->SetStyle(STYLE_TEXT_COLOR, Color::Black().full);
+ phaseLabel_->SetText("【放电中】");
+ }
+ } else {
+ burnGroup_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Gray().full);
+ if (phaseLabel_ != nullptr) {
+ phaseLabel_->SetText("【空闲】");
+ }
+ }
+ }
+
+ void ccCycleBurnView::ApplyScreenAlwaysOn(void)
+ {
+ const power_display_svr_api_t *display_api = power_display_svr_get_api();
+ if (display_api == nullptr) {
+ return;
+ }
+ if (display_api->get_screen_state() != SCREEN_ON) {
+ display_api->turn_on_screen();
+ }
+ display_api->set_auto_timeout_function(false);
+ uapi_setScreenBrightness(255);
+ }
+
+ void ccCycleBurnView::RefreshStatus(void)
+ {
+#ifdef ENABLE_HP4570
+ cc_cycle_phase_e p = cc_cycle_get_phase();
+ UpdatePhaseBackground(p);
+
+ if (statusLabel_ != nullptr) {
+ char buf[96];
+ (void)cc_cycle_format_status_line(buf, sizeof(buf));
+ statusLabel_->SetText(buf);
+ }
+ // RootView::GetInstance()->Invalidate();
+#else
+ if (statusLabel_ != nullptr) {
+ statusLabel_->SetText("拷机");
+ }
+#endif
+ ApplyScreenAlwaysOn();
+ }
+
+ void ccCycleBurnView::DestroyBurnWidgets(void)
+ {
+ if (burnGroup_ == nullptr) {
+ return;
+ }
+ UIViewGroup *root = GetRootContainer();
+ if (root != nullptr) {
+ root->Remove(burnGroup_);
+ }
+ burnGroup_->RemoveAll();
+ delete phaseLabel_;
+ delete statusLabel_;
+ delete burnGroup_;
+ phaseLabel_ = nullptr;
+ statusLabel_ = nullptr;
+ burnGroup_ = nullptr;
+ viewInit_ = false;
+ }
+
+ bool ccCycleBurnView::CreateBurnView(void)
+ {
+ int w = Screen::GetInstance().GetWidth();
+ int h = Screen::GetInstance().GetHeight();
+
+ burnGroup_ = new UIViewGroup();
+ if (burnGroup_ == nullptr) {
+ return false;
+ }
+ burnGroup_->SetPosition(0, 0, w, h);
+ burnGroup_->SetStyle(STYLE_BACKGROUND_OPA, 0xff);
+ burnGroup_->SetStyle(STYLE_BACKGROUND_COLOR, Color::White().full);
+ burnGroup_->SetTouchable(true);
+
+ phaseLabel_ = new UILabel();
+ if (phaseLabel_ == nullptr) {
+ return false;
+ }
+ phaseLabel_->SetPosition(0, h / 2 - 80, w, 64);
+ phaseLabel_->SetStyle(STYLE_TEXT_FONT, 40);
+ phaseLabel_->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+ phaseLabel_->SetText("【拷机】");
+ burnGroup_->Add(phaseLabel_);
+
+ statusLabel_ = new UILabel();
+ if (statusLabel_ == nullptr) {
+ return false;
+ }
+ statusLabel_->SetPosition(20, h / 2, w - 40, 72);
+ statusLabel_->SetStyle(STYLE_TEXT_COLOR, Color::Black().full);
+ statusLabel_->SetStyle(STYLE_TEXT_FONT, 24);
+ statusLabel_->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_TOP);
+ statusLabel_->SetText("左滑返回");
+ burnGroup_->Add(statusLabel_);
+
+ burnGroup_->SetDraggable(true);
+ UIView::OnDragListener *dragListener =
+ static_cast<UIView::OnDragListener *>(ccCycleBurnPresenter::GetInstance());
+ if (dragListener != nullptr) {
+ burnGroup_->SetOnDragListener(dragListener);
+ }
+
+ AddViewToRootContainer(burnGroup_);
+ return true;
+ }
+
+ void ccCycleBurnView::OnStart()
+ {
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ccCycleBurnView::OnStart");
+ if (!viewInit_) {
+ if (!CreateBurnView()) {
+ return;
+ }
+ viewInit_ = true;
+ }
+ ApplyScreenAlwaysOn();
+ uint8_t cnt = pm_veto_get_id_cnt(PM_ID_P_TEST);
+ if (cnt == 0) {
+ uapi_pm_add_sleep_veto(PM_ID_P_TEST);
+ }
+ RefreshStatus();
+ }
+
+ void ccCycleBurnView::OnStop()
+ {
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ccCycleBurnView::OnStop");
+ const power_display_svr_api_t *display_api = power_display_svr_get_api();
+ if (display_api != nullptr) {
+ display_api->set_auto_timeout_function(true);
+ }
+ uint8_t cnt = pm_veto_get_id_cnt(PM_ID_P_TEST);
+ if (cnt == 1) {
+ uapi_pm_remove_sleep_veto(PM_ID_P_TEST);
+ }
+ }
+}
--- /dev/null
+#include "wearable_log.h"
+#include "custom_utils.h"
+#include "producttest/include/testPresenter.h"
+#include "producttest/include/testCcCycle.h"
+#include "producttest/include/testView.h"
+#include "producttest/include/testabout.h"
+#include "common/screen.h"
+#include "gfx_utils/color.h"
+#include "cmsis_os2.h"
+#include <cstdio>
+
+#ifdef ENABLE_HP4570
+#include "cc_cycle_service.h"
+
+namespace OHOS
+{
+ static testCcCycleView *g_testCcCycleView = nullptr;
+ static osTimerId_t g_ccCycleStatusTimer = nullptr;
+
+ testCcCycleView::testCcCycleView()
+ {
+ g_testCcCycleView = this;
+ }
+
+ testCcCycleView::~testCcCycleView()
+ {
+ if (g_ccCycleStatusTimer != nullptr) {
+ (void)osTimerStop(g_ccCycleStatusTimer);
+ (void)osTimerDelete(g_ccCycleStatusTimer);
+ g_ccCycleStatusTimer = nullptr;
+ }
+ ClearAll();
+ g_testCcCycleView = nullptr;
+ }
+
+ void testCcCycleView::StatusTimerCallback(void *arg)
+ {
+ (void)arg;
+ testCcCycleView *v = testCcCycleView::GetInstance();
+ if (v != nullptr) {
+ v->RefreshCcCycleButtons();
+ }
+ }
+
+ void testCcCycleView::RefreshStatusLabel(void)
+ {
+ if (statusLabel_ == nullptr) {
+ return;
+ }
+ char buf[96];
+ (void)cc_cycle_format_status_line(buf, sizeof(buf));
+ statusLabel_->SetText(buf);
+ }
+
+ testCcCycleView *testCcCycleView::GetInstance(void)
+ {
+ return g_testCcCycleView;
+ }
+
+ void testCcCycleView::RefreshCcCycleButtons(void)
+ {
+ if (labelButton_cc_sw_ != nullptr) {
+ if (cc_cycle_get_enabled()) {
+ labelButton_cc_sw_->SetText("拷机开关:开");
+ } else {
+ labelButton_cc_sw_->SetText("拷机开关:关");
+ }
+ }
+ if (labelButton_cc_enter_ != nullptr) {
+ if (cc_cycle_is_running()) {
+ labelButton_cc_enter_->SetText("停止自动拷机");
+ } else {
+ labelButton_cc_enter_->SetText("开始自动拷机(需插线)");
+ }
+ }
+ RefreshStatusLabel();
+ }
+
+ void testCcCycleView::ClearAll(void)
+ {
+ if (testCcCycleScrollView_ == nullptr) {
+ return;
+ }
+ testCcCycleScrollView_->RemoveAll();
+ if (labelButton_cc_sw_ != nullptr) {
+ delete labelButton_cc_sw_;
+ labelButton_cc_sw_ = nullptr;
+ }
+ if (labelButton_cc_enter_ != nullptr) {
+ delete labelButton_cc_enter_;
+ labelButton_cc_enter_ = nullptr;
+ }
+ if (labelButton_next_ != nullptr) {
+ delete labelButton_next_;
+ labelButton_next_ = nullptr;
+ }
+ if (hintLabel_ != nullptr) {
+ delete hintLabel_;
+ hintLabel_ = nullptr;
+ }
+ if (statusLabel_ != nullptr) {
+ delete statusLabel_;
+ statusLabel_ = nullptr;
+ }
+ if (title_ != nullptr) {
+ delete title_;
+ title_ = nullptr;
+ }
+ delete testCcCycleScrollView_;
+ testCcCycleScrollView_ = nullptr;
+ }
+
+ bool testCcCycleView::testCcCycleScrollViewInit(uint8_t id)
+ {
+ int w = Screen::GetInstance().GetWidth();
+ int h = Screen::GetInstance().GetHeight();
+
+ testCcCycleScrollView_ = new UIScrollView();
+ if (testCcCycleScrollView_ == nullptr) {
+ return false;
+ }
+ testCcCycleScrollView_->SetPosition(0, 0, w, h);
+ testCcCycleScrollView_->SetStyle(STYLE_BACKGROUND_OPA, 0xff);
+ testCcCycleScrollView_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Black().full);
+
+ title_ = testAboutView::GetInstance()->init_title(165, 45, "充放电拷机");
+ if (title_ == nullptr) {
+ return false;
+ }
+ testCcCycleScrollView_->Add(title_);
+
+ statusLabel_ = new UILabel();
+ if (statusLabel_ == nullptr) {
+ return false;
+ }
+ statusLabel_->SetPosition(30, 90, w - 60, 56);
+ statusLabel_->SetStyle(STYLE_TEXT_COLOR, Color::Yellow().full);
+ statusLabel_->SetStyle(STYLE_TEXT_FONT, 26);
+ statusLabel_->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+ statusLabel_->SetText("状态:未运行");
+ testCcCycleScrollView_->Add(statusLabel_);
+
+ hintLabel_ = new UILabel();
+ if (hintLabel_ == nullptr) {
+ return false;
+ }
+ hintLabel_->SetPosition(40, 120, w - 80, 80);
+ hintLabel_->SetStyle(STYLE_TEXT_COLOR, Color::White().full);
+ hintLabel_->SetStyle(STYLE_TEXT_FONT, 24);
+ hintLabel_->SetText("插线后开开关再开始;亮屏页左滑返回;本页左滑退出");
+ hintLabel_->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_TOP);
+ testCcCycleScrollView_->Add(hintLabel_);
+
+ (void)cc_cycle_init();
+ labelButton_cc_sw_ = testAboutView::GetInstance()->init_button_next(
+ 300, 280, Test_ViewMapper_t[id].viewid_str_next);
+ UIView::OnClickListener *clickListener =
+ static_cast<UIView::OnClickListener *>(testPresenter::GetInstance());
+
+ labelButton_cc_sw_->SetViewId("cc_cycle_sw");
+ labelButton_cc_sw_->SetText("拷机开关:关");
+ labelButton_cc_sw_->SetOnClickListener(clickListener);
+ testCcCycleScrollView_->Add(labelButton_cc_sw_);
+
+ labelButton_cc_enter_ = testAboutView::GetInstance()->init_button_next(
+ 300, 380, Test_ViewMapper_t[id].viewid_str_next);
+ labelButton_cc_enter_->SetViewId("cc_cycle_enter");
+ labelButton_cc_enter_->SetText("开始自动拷机(需插线)");
+ labelButton_cc_enter_->SetOnClickListener(clickListener);
+ testCcCycleScrollView_->Add(labelButton_cc_enter_);
+
+ labelButton_next_ = testAboutView::GetInstance()->init_button_next(
+ 267, 480, Test_ViewMapper_t[id].viewid_str_next);
+ labelButton_next_->SetOnClickListener(clickListener);
+ testCcCycleScrollView_->Add(labelButton_next_);
+
+ RefreshCcCycleButtons();
+ if (g_ccCycleStatusTimer == nullptr) {
+ g_ccCycleStatusTimer = osTimerNew(StatusTimerCallback, osTimerPeriodic, nullptr, nullptr);
+ }
+ if (g_ccCycleStatusTimer != nullptr) {
+ (void)osTimerStart(g_ccCycleStatusTimer, 1000);
+ }
+ testCcCycleScrollView_->SetTouchable(true);
+ testCcCycleScrollView_->SetDraggable(true);
+ UIView::OnDragListener *dragListener =
+ static_cast<UIView::OnDragListener *>(testPresenter::GetInstance());
+ if (dragListener != nullptr) {
+ testCcCycleScrollView_->SetOnDragListener(dragListener);
+ }
+ return true;
+ }
+
+ UIScrollView *testCcCycleView::testCcCycleInitIView(uint8_t id)
+ {
+ if (!testCcCycleScrollViewInit(id)) {
+ return nullptr;
+ }
+ return testCcCycleScrollView_;
+ }
+}
+
+#endif /* ENABLE_HP4570 */
#ifdef CUSTOM_ZHIHUI
#include "factorytest_protocol.h"
#endif
+#ifdef ENABLE_HP4570
+#include "cc_cycle_service.h"
+#include "producttest/include/testCcCycle.h"
+#endif
return true;
}
+#ifdef ENABLE_HP4570
+ if (strcmp(view.GetViewId(), "cc_cycle_sw") == 0) {
+ cc_cycle_set_enabled(cc_cycle_get_enabled() ? 0 : 1);
+ if (testCcCycleView::GetInstance() != nullptr) {
+ testCcCycleView::GetInstance()->RefreshCcCycleButtons();
+ }
+ return true;
+ }
+ if (strcmp(view.GetViewId(), "cc_cycle_enter") == 0) {
+ if (!cc_cycle_get_enabled()) {
+ return true;
+ }
+ if (cc_cycle_is_running()) {
+ cc_cycle_stop_automation();
+ } else if (cc_cycle_enter_test_ui() != ERRCODE_SUCC) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "cc_cycle: need charger plugged");
+ }
+ if (testCcCycleView::GetInstance() != nullptr) {
+ testCcCycleView::GetInstance()->RefreshCcCycleButtons();
+ }
+ return true;
+ }
+#endif
+
for(int i=0;i<len;i++)
{
if(strcmp(view.GetViewId(),Test_ViewMapper_t[i].viewid_str) == 0)
#endif
{LUMINANCE, "luminanceButton", "亮度", "luminanceButton_next", &testView::ChangLUMTESTView, true},
{CHARG, "chargingButton", "电池充电", "chargingButton_next", &testView::ChangchargingTESTView, true},
+#ifdef ENABLE_HP4570
+ {CCCYCLE, "ccCycleButton", "充放电拷机", "ccCycleButton_next", &testView::ChangeCcCycleTESTView, true},
+#endif
{SPEAK, "speakButton", "喇叭", "speakButton_next", &testView::ChangspeakTESTView, true},
{MOTOR, "motorButton", "马达", "motorButton_next", &testView::ChangmotorTESTView, true},
#ifdef SUPPORT_CAT1_SERVICE
return true;
}
+#ifdef ENABLE_HP4570
+ bool testView::ChangeCcCycleTESTView(int16_t thisView)
+ {
+ if (SystemScrollView[thisView] == nullptr) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SystemView::ChangeCcCycleTESTView");
+ test_cc_cycle_view = new testCcCycleView();
+ if (test_cc_cycle_view == nullptr) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SystemView:: new scrollView[%d] fail", thisView);
+ return false;
+ }
+ SystemScrollView[thisView] = test_cc_cycle_view->testCcCycleInitIView((uint8_t)thisView);
+ group->Add(SystemScrollView[thisView]);
+ }
+ return true;
+ }
+#endif
+
bool testView::ChangspeakTESTView(int16_t thisView)
{
if (SystemScrollView[thisView] == nullptr)
test_G_view = nullptr;
SystemScrollView[hideView] = nullptr;
break;
+#ifdef ENABLE_HP4570
+ case CCCYCLE:
+ if (SystemScrollView[hideView] != nullptr)
+ group->Remove(SystemScrollView[hideView]);
+ delete test_cc_cycle_view;
+ test_cc_cycle_view = nullptr;
+ SystemScrollView[hideView] = nullptr;
+ break;
+#endif
case OLDTEST:
if (SystemScrollView[hideView] != nullptr)
group->Remove(SystemScrollView[hideView]);
endif()
add_subdirectory_if_exist(ble_service)
add_subdirectory_if_exist(factorytest_service)
+add_subdirectory_if_exist(cc_cycle_service)
add_subdirectory_if_exist(hid_service)
return batteryservice_get_voltage(voltage);
}
+void battery_set_force_discharge_soc(uint8_t on)
+{
+ batteryservice_set_force_discharge_soc(on);
+}
+
void battery_percent_init(uint8_t percent);
+/* 拷机放电:仍插线但禁充时,按未插线曲线/缓降规则算 SOC(避免 99% 锁死) */
+void battery_set_force_discharge_soc(uint8_t on);
+
#ifdef __cplusplus
#if __cplusplus
}
#include "debug_print.h"
// #include "cat1_utils.h"
#include <math.h>
+
+/* 电量热路径调试:拷机每秒多次算 SOC + printf 易堵串口/耗 CPU,默认关 */
+#ifndef BATTERY_SOC_VERBOSE_LOG
+#define BATTERY_SOC_VERBOSE_LOG 0
+#endif
+#if BATTERY_SOC_VERBOSE_LOG
+#define BAT_SOC_LOG(...) printf(__VA_ARGS__)
+#define BAT_SOC_PRINT(...) PRINT(__VA_ARGS__)
+#else
+#define BAT_SOC_LOG(...) ((void)0)
+#define BAT_SOC_PRINT(...) ((void)0)
+#endif
// #include "custom_save_runtime.h"
#include "charge_ic.h"
static BAT_VOL_T bat_vol;
static int history_percent = 0;
+static uint8_t cur_percent = 0;
+static uint8_t g_force_discharge_soc_mode = 0;
+/* 拷机放电阶段 SOC 峰值,禁止显示电量回升 */
+static int s_cc_burn_discharge_soc_peak = -1;
+void batteryservice_set_force_discharge_soc(uint8_t on)
+{
+ g_force_discharge_soc_mode = on ? 1 : 0;
+ if (on) {
+ if (s_cc_burn_discharge_soc_peak < 0) {
+ int seed = history_percent > 0 ? history_percent :
+ (cur_percent > 0 ? (int)cur_percent : -1);
+ s_cc_burn_discharge_soc_peak = seed;
+ }
+ } else {
+ s_cc_burn_discharge_soc_peak = -1;
+ }
+}
+
// static float sum_vol = 0;
// static int vol_num=0;
static battery_info_t current_battery_info={0};
-static uint8_t cur_percent = 0;
-
static uint8_t percernt_installized = 0;
static float test_temp = 0;
if (s_chg_done_flat_cnt >= CHG_DONE_FLAT_STREAK && history_percent < 100) {
history_percent++;
*percent = history_percent;
- printf("[电池计算] CHG_DONE+>=%.1fV 连续电压不升 cnt=%u(>=%u) -> 累加 %% hist=%d\n",
- CHG_DONE_MIN_VOLTAGE_V,
- (unsigned int)s_chg_done_flat_cnt, (unsigned int)CHG_DONE_FLAT_STREAK, history_percent);
+ BAT_SOC_LOG("[电池计算] HP4570 CHG_DONE+>=%.1fV 连续电压不升 cnt=%u(>=%u) -> 累加 %% hist=%d\n",
+ HP4570_CHG_DONE_MIN_VOLTAGE_V,
+ (unsigned int)s_hp4570_chg_done_flat_cnt, (unsigned int)HP4570_CHG_DONE_FLAT_STREAK, history_percent);
if (history_percent >= 100) {
s_chg_done_flat_cnt = 0;
s_chg_done_last_v = -1.0f;
{
uint32_t current_time = 0;
int percent = 0;
- // ===================== 最小修改:根据充电状态选择MAP =====================
- const float (*battery_map)[2] = get_charge_stat() ? battery_charge_percent_map : battery_percent_map;
+ /* 插线拷机禁充放电:仍检测到 plug,但按未插线 MAP/缓降算电量 */
+ uint8_t treat_as_charging = (get_charge_stat() != 0) && (g_force_discharge_soc_mode == 0);
+ const float (*battery_map)[2] = treat_as_charging ? battery_charge_percent_map : battery_percent_map;
int map_len = sizeof(battery_charge_percent_map)/sizeof(battery_charge_percent_map[0]); // 两个map长度一样
// ======================================================================
float temp_value = 0.0f;
// // ===================== 只打印当前使用的数组 =====================
static bool print_flag = false;
- if(!print_flag)
- {
+ if (!print_flag) {
print_flag = true;
+#if BATTERY_SOC_VERBOSE_LOG
printf("==== 当前使用的电池电压映射表 ====\n");
- if(get_charge_stat())
- {
+ if (treat_as_charging) {
printf("==== 充电模式 battery_charge_percent_map ====\n");
- }
- else
- {
+ } else if (g_force_discharge_soc_mode) {
+ printf("==== 拷机放电(插线禁充) battery_percent_map ====\n");
+ } else {
printf("==== 非充电模式 battery_percent_map ====\n");
}
- for(int i=0; i<map_len; i++)
- {
+ for (int i = 0; i < map_len; i++) {
printf("[%2d] 电压: %.3f V → 电量: %d %%\n",
- i,
- battery_map[i][0],
- (int)battery_map[i][1]);
+ i, battery_map[i][0], (int)battery_map[i][1]);
}
printf("=======================================\n");
+#endif
}
// ===============================================================
+ if (voltage > battery_map[0][0]) {
+ percent = (int)battery_map[0][1];
+ }
+
for (int i =0;i<map_len -1;i++)
{
//电压在前后两个之间
percent = (int)(temp_value + 0.5);
- // ===================== 打印关键计算变量 =====================
- printf("[电池计算] 当前电压=%.3fV | 区间[%d]%.3fV ~ [%d]%.3fV | r_div=%.3f | 计算电量=%.1f%% | 取整=%d%%\n",
- voltage,
- i, battery_map[i][0],
- i+1, battery_map[i+1][0],
- r_div,
- temp_value,
- percent);
- // ============================================================
-
- if(get_charge_stat())
+ BAT_SOC_LOG("[电池计算] 当前电压=%.3fV | 区间[%d]%.3fV ~ [%d]%.3fV | r_div=%.3f | 计算电量=%.1f%% | 取整=%d%%\n",
+ voltage, i, battery_map[i][0], i + 1, battery_map[i + 1][0], r_div, temp_value, percent);
+
+ if (treat_as_charging)
{
// if(history_percent > percent && abs(history_percent - percent) < 10)
if(history_percent > percent)
}
- printf("000 history_percent:%d ,percent : %d ,voltage:%.3f \n",history_percent,percent,voltage);
+ BAT_SOC_LOG("000 history_percent:%d ,percent : %d ,voltage:%.3f \n", history_percent, percent, voltage);
if (voltage <= batteryservice_VOLTAGE_MIN)
percent = 0;
if (voltage >= batteryservice_VOLTAGE_MAX)
{
- if(get_charge_stat() && history_percent < 100 && history_percent)
+ if (g_force_discharge_soc_mode) {
+ /* 拷机放电:不逐格累加;满电区仍需给出合理 SOC,避免 percent 仍为 0 */
+ if (percent <= 0) {
+ percent = history_percent > 0 ? history_percent : (int)battery_map[0][1];
+ }
+ } else if (treat_as_charging && history_percent < 100 && history_percent)
{
- printf("111 history_percent:%d ,percent : %d ,voltage:%.3f \n",history_percent,percent,voltage);
+ BAT_SOC_LOG("111 history_percent:%d ,percent : %d ,voltage:%.3f \n", history_percent, percent, voltage);
history_percent++;
percent = history_percent;
}
- else if(!get_charge_stat() && history_percent)
+ else if (!treat_as_charging && history_percent)
{
- printf("222 history_percent:%d ,percent : %d ,voltage:%.3f \n",history_percent,percent,voltage);
+ BAT_SOC_LOG("222 history_percent:%d ,percent : %d ,voltage:%.3f \n", history_percent, percent, voltage);
percent = history_percent;
}
else
{
- printf("333 history_percent:%d ,percent : %d ,voltage:%.3f \n",history_percent,percent,voltage);
+ BAT_SOC_LOG("333 history_percent:%d ,percent : %d ,voltage:%.3f \n", history_percent, percent, voltage);
percent = 100;
history_percent = 100;
}
}
- if (battery_check_charge_done(voltage, &percent)) {
+ if (!g_force_discharge_soc_mode && battery_check_charge_done(voltage, &percent)) {
return percent;
}
+ if (g_force_discharge_soc_mode) {
+ if (s_cc_burn_discharge_soc_peak < 0) {
+ int seed = history_percent > 0 ? history_percent :
+ (cur_percent > 0 ? (int)cur_percent : percent);
+ if (seed <= 0 && voltage >= battery_map[0][0] - 0.08f) {
+ seed = (int)battery_map[0][1];
+ }
+ s_cc_burn_discharge_soc_peak = seed;
+ }
+ if (s_cc_burn_discharge_soc_peak < 0) {
+ s_cc_burn_discharge_soc_peak = percent > 0 ? percent : 0;
+ }
+ if (percent > s_cc_burn_discharge_soc_peak) {
+ percent = s_cc_burn_discharge_soc_peak;
+ } else if (percent < s_cc_burn_discharge_soc_peak) {
+ /* 拒绝单次异常 0% 把满电峰值打穿;真放空时电压会进低压区 */
+ if (percent > 0 || voltage <= batteryservice_VOLTAGE_MIN + 0.05f) {
+ s_cc_burn_discharge_soc_peak = percent;
+ } else {
+ percent = s_cc_burn_discharge_soc_peak;
+ }
+ }
+ history_percent = percent;
+ }
+
return percent;
}
else {
bat_vol.avg_vol = bat_vol.sum_vol / bat_vol.vol_num;
}
- printf("avg_vol : %.3f\n",bat_vol.avg_vol);
+ BAT_SOC_LOG("avg_vol : %.3f\n", bat_vol.avg_vol);
}
}
int DecimalPart_1 = (int)(DecimalPart / 100);
int DecimalPart_2 = (int)((DecimalPart % 100) / 10);
int DecimalPart_3 = (int)(DecimalPart % 10);
- PRINT("222*voltage : %.3f \n",*voltage);
+ BAT_SOC_PRINT("222*voltage : %.3f \n", *voltage);
// PRINT("DecimalPart_1 : %d , DecimalPart_2 : %d DecimalPart_3 : %d \n",DecimalPart_1,DecimalPart_2,DecimalPart_3);
uint16_t value = DecimalPart_1 << 8 | DecimalPart_2 << 4 | DecimalPart_3 << 0;
uint8_t percent = 0;
battery_info_t *current_battery_info = get_current_battery_info();
- percent = battery_get_power_percentage();
*voltage = current_battery_info->battery_voltage;
+ if (g_force_discharge_soc_mode) {
+ percent = (uint8_t)battery_get_percent_by_voltage(current_battery_info->battery_voltage);
+ cur_percent = percent;
+ } else {
+ percent = battery_get_power_percentage();
+ }
return percent;
}
#include "debug_print.h"
-// #ifdef ENABLE_HP4570
-// #include "hp4570.h"
-// #elif defined ENABLE_SGM41562
-// #include "sgm41562.h"
-// #endif
+#ifdef ENABLE_HP4570
+#include "hp4570.h"
+extern uint8_t cc_cycle_is_discharge_phase(void);
+#elif defined ENABLE_SGM41562
+#include "sgm41562.h"
+#endif
#include "charge_ic.h"
// #include "cat1_utils.h"
{
float voltage;
float bat_temp;
+#ifdef ENABLE_HP4570
+ /* 拷机放电:Hi-Z/禁充由 cc_cycle 管;拷机充电:走正常温控与 ICHG 档位 */
+ if (cc_cycle_is_discharge_phase()) {
+ return;
+ }
+#endif
//获取电量
uint8_t percent = batteryservice_get_voltage(&voltage);
uint8_t batteryservice_set_test_bat_temp(float temp);
void battery_save_vol(void);
void battery_restore_vol(void);
+void batteryservice_set_force_discharge_soc(uint8_t on);
#ifdef __cplusplus
#if __cplusplus
--- /dev/null
+set(COMPONENT_NAME "cc_cycle_service")
+
+set(PUBLIC_HEADER
+ ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+set(SOURCES
+ ${CMAKE_CURRENT_SOURCE_DIR}/cc_cycle_service.c
+)
+
+set(PRIVATE_HEADER
+ ${ROOT_DIR}/zhihui/utils
+ ${ROOT_DIR}/zhihui/services/battery/hal
+ ${ROOT_DIR}/zhihui/services/battery/service
+ ${ROOT_DIR}/zhihui/drivers/charge/hp4570
+ ${ROOT_DIR}/zhihui/services/gnss/inc
+ ${ROOT_DIR}/application/brandy/brandy_standard
+)
+
+set(COMPONENT_CCFLAGS
+ -Wno-error
+ -Wno-unused-parameter
+)
+
+set(WHOLE_LINK true)
+set(MAIN_COMPONENT false)
+
+build_component()
--- /dev/null
+#include "cc_cycle_service.h"
+#include "custom_utils.h"
+#include "errcode.h"
+#include "battery_hal.h"
+#include "cmsis_os2.h"
+#include "securec.h"
+#include <stdio.h>
+#include <string.h>
+
+#ifdef ENABLE_HP4570
+#include "hp4570.h"
+#include "battery_service.h"
+#endif
+
+#if defined(SUPPORT_GNSS)
+#include "gnss_ctl.h"
+#endif
+
+#define CC_CYCLE_MAGIC 0x43434643u /* "CCFC" */
+#define CC_CYCLE_VERSION 2
+#define CC_CYCLE_SOC_FULL 99
+#define CC_CYCLE_SOC_LOW 10
+
+typedef struct {
+ uint32_t magic;
+ uint16_t version;
+ uint8_t test_enabled;
+ uint8_t phase;
+ uint8_t auto_running;
+ uint8_t reserved;
+ uint32_t charge_start_ts;
+ uint32_t charge_end_ts;
+ uint16_t round_count;
+} cc_cycle_store_t;
+
+static cc_cycle_store_t g_store;
+static uint8_t g_task_running;
+static uint8_t g_lcd_on;
+static uint8_t g_gps_on;
+static uint8_t g_pending_hide_burn_ui;
+static osMutexId_t g_mutex;
+
+static void cc_lock(void)
+{
+ if (g_mutex != NULL) {
+ (void)osMutexAcquire(g_mutex, osWaitForever);
+ }
+}
+
+static void cc_unlock(void)
+{
+ if (g_mutex != NULL) {
+ (void)osMutexRelease(g_mutex);
+ }
+}
+
+static void cc_ensure_userdata_dir(void)
+{
+ static uint8_t s_dir_ready;
+
+ if (s_dir_ready) {
+ return;
+ }
+ uapi_create_folder((char *)"user");
+ uapi_create_folder((char *)"user/userdata");
+ s_dir_ready = 1;
+}
+
+static void cc_store_load(void)
+{
+ uint16_t len = sizeof(g_store);
+ memset(&g_store, 0, sizeof(g_store));
+ uapi_get_file_data((char *)CC_CYCLE_STORE_PATH, (uint8_t *)&g_store, &len);
+ if (g_store.magic != CC_CYCLE_MAGIC) {
+ memset(&g_store, 0, sizeof(g_store));
+ g_store.magic = CC_CYCLE_MAGIC;
+ g_store.version = CC_CYCLE_VERSION;
+ g_store.phase = (uint8_t)CC_PHASE_IDLE;
+ }
+}
+
+static void cc_store_save(void)
+{
+ g_store.magic = CC_CYCLE_MAGIC;
+ g_store.version = CC_CYCLE_VERSION;
+ uapi_save_file_data((char *)CC_CYCLE_STORE_PATH, (uint8_t *)&g_store,
+ (uint16_t)sizeof(g_store), "wb");
+}
+
+static void cc_sync_discharge_soc_mode(void)
+{
+#ifdef SUPPORT_BATTERY_SERVICE
+ if (g_store.auto_running && g_store.phase == (uint8_t)CC_PHASE_DISCHARGE) {
+ battery_set_force_discharge_soc(1);
+ } else {
+ battery_set_force_discharge_soc(0);
+ }
+#else
+ (void)0;
+#endif
+}
+
+static uint8_t cc_read_soc(float *voltage)
+{
+ float v = 0.0f;
+ uint8_t soc = 0;
+#ifdef SUPPORT_BATTERY_SERVICE
+ soc = battery_get_voltage(&v);
+#else
+ (void)voltage;
+ return 0;
+#endif
+ if (voltage != NULL) {
+ *voltage = v;
+ }
+ return soc;
+}
+
+static uint8_t cc_is_plugged(void)
+{
+ return get_charge_stat() ? 1 : 0;
+}
+
+/*
+ * 充电:恢复 VBUS 路径 + 允充。
+ * 放电:禁充 + VBUS Hi-Z,负载由电池承担(线仍插着用于检测/拷机循环)。
+ */
+static void cc_set_charge_enable(uint8_t on)
+{
+#ifdef ENABLE_HP4570
+ if (on) {
+ /* 恢复 VBUS 路径、允充;ICHG 由 battery_service 按温度/SOC 配置(非固定死 260mA) */
+ hp4570n_set_hiz_en(false);
+ hp4570n_set_ceb_en(true);
+ disable_02c();
+ } else {
+ hp4570n_set_ceb_en(false);
+ hp4570n_set_hiz_en(true);
+ }
+#else
+ (void)on;
+#endif
+}
+
+static void cc_set_white_screen(uint8_t on)
+{
+ /* 白屏与常亮由 VIEW_CC_CYCLE_BURN 界面负责 */
+ if (on) {
+ g_lcd_on = 1;
+ } else if (g_lcd_on) {
+ g_lcd_on = 0;
+ }
+}
+
+static void cc_set_gps(uint8_t on)
+{
+#if defined(SUPPORT_GNSS)
+ if (on && !g_gps_on) {
+ gnss_start();
+ g_gps_on = 1;
+ } else if (!on && g_gps_on) {
+ gnss_stop();
+ g_gps_on = 0;
+ }
+#else
+ (void)on;
+#endif
+}
+
+static void cc_append_charge_log(uint32_t t_start, uint32_t t_end, uint8_t soc_end)
+{
+ FILE *fp;
+ char line[96];
+ cc_ensure_userdata_dir();
+ (void)snprintf_s(line, sizeof(line), sizeof(line) - 1,
+ "start=%u end=%u soc_end=%u round=%u\n",
+ (unsigned int)t_start, (unsigned int)t_end, (unsigned int)soc_end,
+ (unsigned int)g_store.round_count);
+ fp = fopen(CC_CYCLE_CHARGE_LOG_PATH, "a");
+ if (fp == NULL) {
+ return;
+ }
+ (void)fwrite(line, 1, strlen(line), fp);
+ (void)fclose(fp);
+}
+
+static void cc_enter_discharge_phase(void)
+{
+ g_store.phase = (uint8_t)CC_PHASE_DISCHARGE;
+ g_store.charge_start_ts = 0;
+ g_store.charge_end_ts = 0;
+ cc_set_charge_enable(0);
+ cc_sync_discharge_soc_mode();
+ if (g_store.auto_running) {
+ cc_set_white_screen(1);
+ cc_set_gps(1);
+ }
+}
+
+static void cc_enter_charging_phase(void)
+{
+ uint32_t now = 0;
+ (void)uapi_get_timestampe_ss(&now);
+ g_store.phase = (uint8_t)CC_PHASE_CHARGING;
+ g_store.charge_start_ts = now;
+ g_store.charge_end_ts = 0;
+ cc_set_white_screen(0);
+ cc_set_charge_enable(1);
+ cc_sync_discharge_soc_mode();
+ if (g_store.auto_running) {
+ cc_set_gps(1);
+ }
+}
+
+static void cc_finish_charging_phase(uint8_t soc)
+{
+ uint32_t now = 0;
+ (void)uapi_get_timestampe_ss(&now);
+ g_store.charge_end_ts = now;
+ g_store.round_count++;
+ cc_append_charge_log(g_store.charge_start_ts, g_store.charge_end_ts, soc);
+ cc_enter_discharge_phase();
+}
+
+static void cc_finish_discharge_phase(uint8_t soc)
+{
+ (void)soc;
+ if (!cc_is_plugged()) {
+ return;
+ }
+ cc_enter_charging_phase();
+}
+
+static void cc_pick_initial_phase(uint8_t soc)
+{
+#ifdef ENABLE_HP4570
+ if (soc >= CC_CYCLE_SOC_FULL || hp4570n_read_chrg_stat_chrg_done()) {
+ cc_enter_discharge_phase();
+ } else if (soc <= CC_CYCLE_SOC_LOW) {
+ cc_enter_charging_phase();
+ } else if (g_store.phase == (uint8_t)CC_PHASE_CHARGING) {
+ cc_enter_charging_phase();
+ } else {
+ cc_enter_discharge_phase();
+ }
+#else
+ if (soc >= CC_CYCLE_SOC_FULL) {
+ cc_enter_discharge_phase();
+ } else {
+ cc_enter_charging_phase();
+ }
+#endif
+}
+
+static void cc_tick(void)
+{
+ uint8_t soc;
+ uint32_t now = 0;
+
+ if (!g_store.test_enabled || !g_store.auto_running) {
+ return;
+ }
+ if (!cc_is_plugged()) {
+ /* 插线拷机:掉线则暂停自动循环,恢复充电 IC 默认 */
+ cc_set_white_screen(0);
+ cc_set_gps(0);
+ cc_set_charge_enable(1);
+ g_store.phase = (uint8_t)CC_PHASE_IDLE;
+ g_store.auto_running = 0;
+ battery_set_force_discharge_soc(0);
+ g_pending_hide_burn_ui = 1;
+ return;
+ }
+
+ (void)uapi_get_timestampe_ss(&now);
+ soc = cc_read_soc(NULL);
+
+ if (g_store.phase == (uint8_t)CC_PHASE_DISCHARGE) {
+ cc_set_charge_enable(0);
+ cc_set_white_screen(1);
+ cc_set_gps(1);
+ if (soc <= CC_CYCLE_SOC_LOW) {
+ cc_finish_discharge_phase(soc);
+ }
+ return;
+ }
+
+ if (g_store.phase == (uint8_t)CC_PHASE_CHARGING) {
+ cc_set_white_screen(0);
+ cc_set_gps(1);
+ cc_set_charge_enable(1);
+ if (g_store.charge_start_ts == 0) {
+ g_store.charge_start_ts = now;
+ }
+#ifdef ENABLE_HP4570
+ if (soc >= CC_CYCLE_SOC_FULL || hp4570n_read_chrg_stat_chrg_done()) {
+ cc_finish_charging_phase(soc);
+ }
+#else
+ if (soc >= CC_CYCLE_SOC_FULL) {
+ cc_finish_charging_phase(soc);
+ }
+#endif
+ }
+}
+
+static void cc_cycle_task(void *arg)
+{
+ (void)arg;
+ g_task_running = 1;
+ while (g_task_running) {
+ uint8_t hide_ui = 0;
+ cc_lock();
+ cc_tick();
+ cc_store_save();
+ hide_ui = g_pending_hide_burn_ui;
+ g_pending_hide_burn_ui = 0;
+ cc_unlock();
+ if (hide_ui) {
+ cc_cycle_hide_burn_ui();
+ }
+ osDelay(1000);
+ }
+}
+
+static void cc_start_task(void)
+{
+ static uint8_t started;
+ app_task_definition_t taskcfg = {0};
+ if (started) {
+ return;
+ }
+ if (g_mutex == NULL) {
+ g_mutex = osMutexNew(NULL);
+ }
+ taskcfg.create_queue_handle = NULL;
+ taskcfg.attr.name = "cc_cycle_svc";
+ taskcfg.attr.priority = osPriorityNormal;
+ taskcfg.attr.stack_size = 1024 * 6;
+ taskcfg.func = cc_cycle_task;
+ taskcfg.use_mem = USE_EXTEND_MEM;
+ if (uapi_create_osThread_custom(&taskcfg) != ERRCODE_SUCC) {
+ return;
+ }
+ started = 1;
+}
+
+void cc_cycle_init(void)
+{
+ cc_ensure_userdata_dir();
+ cc_start_task();
+ cc_lock();
+ cc_store_load();
+ cc_unlock();
+}
+
+void cc_cycle_on_boot(void)
+{
+ cc_cycle_init();
+ cc_lock();
+ if (!g_store.test_enabled || !g_store.auto_running) {
+ cc_unlock();
+ return;
+ }
+ if (!cc_is_plugged()) {
+ g_store.auto_running = 0;
+ g_store.phase = (uint8_t)CC_PHASE_IDLE;
+ cc_store_save();
+ cc_unlock();
+ return;
+ }
+ cc_set_gps(1);
+ if (g_store.phase == (uint8_t)CC_PHASE_CHARGING) {
+ cc_enter_charging_phase();
+ } else if (g_store.phase == (uint8_t)CC_PHASE_DISCHARGE) {
+ cc_enter_discharge_phase();
+ } else {
+ cc_pick_initial_phase(cc_read_soc(NULL));
+ }
+ cc_store_save();
+ cc_unlock();
+ cc_cycle_show_burn_ui();
+}
+
+uint8_t cc_cycle_get_enabled(void)
+{
+ return g_store.test_enabled;
+}
+
+void cc_cycle_set_enabled(uint8_t on)
+{
+ uint8_t hide_ui = 0;
+ cc_lock();
+ if (!on && g_store.auto_running) {
+ g_store.auto_running = 0;
+ g_store.phase = (uint8_t)CC_PHASE_IDLE;
+ cc_set_white_screen(0);
+ cc_set_gps(0);
+ cc_set_charge_enable(1);
+ battery_set_force_discharge_soc(0);
+ hide_ui = 1;
+ }
+ g_store.test_enabled = on ? 1 : 0;
+ cc_store_save();
+ cc_unlock();
+ if (hide_ui) {
+ cc_cycle_hide_burn_ui();
+ }
+}
+
+cc_cycle_phase_e cc_cycle_get_phase(void)
+{
+ return (cc_cycle_phase_e)g_store.phase;
+}
+
+uint16_t cc_cycle_get_round_count(void)
+{
+ return g_store.round_count;
+}
+
+uint8_t cc_cycle_get_soc(void)
+{
+ uint8_t soc;
+ cc_lock();
+ soc = cc_read_soc(NULL);
+ cc_unlock();
+ return soc;
+}
+
+uint8_t cc_cycle_get_charge_enable_intent(void)
+{
+ uint8_t on = 0;
+ cc_lock();
+ if (g_store.auto_running && g_store.phase == (uint8_t)CC_PHASE_CHARGING) {
+ on = 1;
+ }
+ cc_unlock();
+ return on;
+}
+
+uint8_t cc_cycle_get_hw_is_charging(void)
+{
+#ifdef ENABLE_HP4570
+ if (hp4570n_read_chrg_stat_fast_chrg() || hp4570n_read_chrg_stat_pre_chrg() ||
+ hp4570n_read_chrg_stat_dead_chrg()) {
+ return 1;
+ }
+ if (hp4570n_read_chrg_stat_chrg_done()) {
+ return 0;
+ }
+#endif
+ return 0;
+}
+
+int cc_cycle_format_status_line(char *buf, unsigned int buf_size)
+{
+ cc_cycle_phase_e phase;
+ uint8_t soc;
+ uint8_t intent;
+ uint8_t hw_chg;
+ uint16_t round;
+ uint8_t running;
+
+ if (buf == NULL || buf_size == 0) {
+ return 0;
+ }
+ cc_lock();
+ phase = (cc_cycle_phase_e)g_store.phase;
+ soc = cc_read_soc(NULL);
+ round = g_store.round_count;
+ running = g_store.auto_running;
+ cc_unlock();
+
+ intent = cc_cycle_get_charge_enable_intent();
+ hw_chg = cc_cycle_get_hw_is_charging();
+
+ if (!running || phase == CC_PHASE_IDLE) {
+ return snprintf_s(buf, buf_size, buf_size - 1,
+ "状态:未运行 SOC:%u%%", (unsigned int)soc);
+ }
+ if (phase == CC_PHASE_DISCHARGE) {
+ if (hw_chg) {
+ return snprintf_s(buf, buf_size, buf_size - 1,
+ "【放电中】电池供电 SOC:%u%% 轮次:%u HiZ:开 HW:充!",
+ (unsigned int)soc, (unsigned int)round);
+ }
+ return snprintf_s(buf, buf_size, buf_size - 1,
+ "【放电中】电池供电 SOC:%u%% 轮次:%u HiZ:开",
+ (unsigned int)soc, (unsigned int)round);
+ }
+ if (hw_chg) {
+ return snprintf_s(buf, buf_size, buf_size - 1,
+ "【充电中】SOC:%u%% 轮次:%u IC:开 HW:充",
+ (unsigned int)soc, (unsigned int)round);
+ }
+ return snprintf_s(buf, buf_size, buf_size - 1,
+ "【充电中】SOC:%u%% 轮次:%u IC:%s HW:未充",
+ (unsigned int)soc, (unsigned int)round, intent ? "开" : "关");
+}
+
+uint8_t cc_cycle_is_active(void)
+{
+ return (g_store.test_enabled && g_store.auto_running &&
+ g_store.phase != (uint8_t)CC_PHASE_IDLE) ? 1 : 0;
+}
+
+uint8_t cc_cycle_is_discharge_phase(void)
+{
+ return (g_store.test_enabled && g_store.auto_running &&
+ g_store.phase == (uint8_t)CC_PHASE_DISCHARGE) ? 1 : 0;
+}
+
+uint8_t cc_cycle_is_running(void)
+{
+ return g_store.auto_running;
+}
+
+void cc_cycle_stop_automation(void)
+{
+ cc_lock();
+ g_store.auto_running = 0;
+ g_store.phase = (uint8_t)CC_PHASE_IDLE;
+ cc_set_white_screen(0);
+ cc_set_gps(0);
+ cc_set_charge_enable(1);
+ battery_set_force_discharge_soc(0);
+ cc_store_save();
+ cc_unlock();
+ cc_cycle_hide_burn_ui();
+}
+
+errcode_t cc_cycle_enter_test_ui(void)
+{
+ uint8_t soc;
+ cc_lock();
+ if (!g_store.test_enabled) {
+ cc_unlock();
+ return ERRCODE_FAIL;
+ }
+ if (!cc_is_plugged()) {
+ cc_unlock();
+ return ERRCODE_FAIL;
+ }
+ g_store.auto_running = 1;
+ soc = cc_read_soc(NULL);
+ cc_pick_initial_phase(soc);
+ cc_store_save();
+ cc_unlock();
+ cc_cycle_show_burn_ui();
+ return ERRCODE_SUCC;
+}
--- /dev/null
+#ifndef CC_CYCLE_SERVICE_H
+#define CC_CYCLE_SERVICE_H
+
+#include <stdint.h>
+#include "errcode.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CC_CYCLE_STORE_PATH "user/userdata/cc_cycle.bin"
+#define CC_CYCLE_CHARGE_LOG_PATH "user/userdata/cc_charge_log.txt"
+
+typedef enum {
+ CC_PHASE_IDLE = 0,
+ CC_PHASE_DISCHARGE = 1, /* 插线拷机:VBUS Hi-Z+禁充,电池放电;白屏+GPS */
+ CC_PHASE_CHARGING = 2, /* 插线拷机:允许充电,记录起止时间 */
+} cc_cycle_phase_e;
+
+void cc_cycle_init(void);
+void cc_cycle_on_boot(void);
+
+uint8_t cc_cycle_get_enabled(void);
+void cc_cycle_set_enabled(uint8_t on);
+
+cc_cycle_phase_e cc_cycle_get_phase(void);
+uint16_t cc_cycle_get_round_count(void);
+uint8_t cc_cycle_get_soc(void);
+/* 软件意图:放电阶段为0(禁充),充电阶段为1(允充) */
+uint8_t cc_cycle_get_charge_enable_intent(void);
+/* HP4570 硬件充电状态:1=预充/快充中 */
+uint8_t cc_cycle_get_hw_is_charging(void);
+uint8_t cc_cycle_is_active(void);
+/* 仅放电阶段:拷机需接管 Hi-Z/禁充;充电阶段交还 battery_service 管电流 */
+uint8_t cc_cycle_is_discharge_phase(void);
+uint8_t cc_cycle_is_running(void);
+
+/* 写入状态文案,buf 建议>=96 字节,返回 snprintf 结果 */
+int cc_cycle_format_status_line(char *buf, unsigned int buf_size);
+
+/* 需已插充电线;启动后自动循环充放电 */
+errcode_t cc_cycle_enter_test_ui(void);
+void cc_cycle_stop_automation(void);
+
+/* 全屏白底拷机界面(producttest 实现) */
+void cc_cycle_show_burn_ui(void);
+void cc_cycle_hide_burn_ui(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
${ROOT_DIR}/middleware/services/gui/uikit/ui/frameworks/dock/
${ROOT_DIR}/zhihui/UI/producttest/include
${ROOT_DIR}/zhihui/UI
+ ${ROOT_DIR}/zhihui/services/cc_cycle_service
${ROOT_DIR}/zhihui/AI/AImain
)
#include "custom_utils.h"
#include "custom_save_runtime.h"
+#ifdef ENABLE_HP4570
+#include "cc_cycle_service.h"
+#endif
/* Forward declarations for functions used in this file */
extern void save_time(void);
if(factory_test_flag == 2)
{
custom_aging_test_init();
- }
+ }
#endif
+
+#ifdef ENABLE_HP4570
+ if (custom_get_factory_test_flag() != 0) {
+ cc_cycle_on_boot();
+ }
+#endif
}
void startup_post_init(void)