// 当前Presenter属性实例化的内存指针
static testPresenter *g_pSystemPresenter = nullptr;
+ static int16_t g_pendingJumpSubView = -1; // TEST_VIEW enum value, -1 means none
testPresenter::testPresenter()
{
}
void testPresenter::OnResume()
{
+ // 如果有待跳转的子界面(来自 AT / 协议),在 slice resume 后再执行,避免 testView 尚未创建导致跳转丢失
+ if (g_pendingJumpSubView >= 0 && testView::GetInstance()) {
+ testView::GetInstance()->ChangeView(TESTVIEW, g_pendingJumpSubView);
+ g_pendingJumpSubView = -1;
+ }
+
if(view_->GetSystemScrollView(BUTTON) != nullptr)
{
RootView::GetInstance()->SetOnKeyActListener(this);
#endif /* __cplusplus */
#endif /* __cplusplus */
+ void factorytest_jump_to_subview_id(int16_t target);
+
void factorytest_enter_test_tp_view(void)
{
if(testView::GetInstance())
testView::GetInstance()->ChangeView(TESTVIEW,BUTTON);
}
+ void factorytest_enter_test_luminance_view(void)
+ {
+ if (testView::GetInstance()) {
+ testView::GetInstance()->ChangeView(TESTVIEW, LUMINANCE);
+ }
+ }
+
+ void factorytest_enter_test_charging_view(void)
+ {
+ if (testView::GetInstance()) {
+ testView::GetInstance()->ChangeView(TESTVIEW, CHARG);
+ }
+ }
+
+ void factorytest_enter_test_motor_view(void)
+ {
+ if (testView::GetInstance()) {
+ testView::GetInstance()->ChangeView(TESTVIEW, MOTOR);
+ }
+ }
+
+ void factorytest_enter_test_hr_view(void)
+ {
+ if (testView::GetInstance()) {
+ testView::GetInstance()->ChangeView(TESTVIEW, HRSENSON);
+ }
+ }
+
+ void factorytest_enter_test_gsensor_view(void)
+ {
+ if (testView::GetInstance()) {
+ testView::GetInstance()->ChangeView(TESTVIEW, GSENSON);
+ }
+ }
+
+ void factorytest_enter_test_bt_view(void)
+ {
+ if (testView::GetInstance()) {
+ testView::GetInstance()->ChangeView(TESTVIEW, BTTEST);
+ }
+ }
+
+ void factorytest_enter_test_sechip_view(void)
+ {
+ if (testView::GetInstance()) {
+ testView::GetInstance()->ChangeView(TESTVIEW, SEChipTest);
+ }
+ }
+
+ void factorytest_enter_test_gps_view(void)
+ {
+ if (testView::GetInstance()) {
+ testView::GetInstance()->ChangeView(TESTVIEW, GPSTEST);
+ }
+ }
+
+ void factorytest_jump_to_subview(const char *item)
+ {
+ if (item == nullptr) {
+ return;
+ }
+
+ int16_t target = -1;
+ if (strcasecmp(item, "TP") == 0) {
+ target = TP;
+ } else if (strcasecmp(item, "BRIGHT") == 0) {
+ target = LUMINANCE;
+ } else if (strcasecmp(item, "CHARGE") == 0) {
+ target = CHARG;
+ } else if (strcasecmp(item, "MOTOR") == 0) {
+ target = MOTOR;
+ } else if (strcasecmp(item, "KEY") == 0) {
+ target = BUTTON;
+ } else if (strcasecmp(item, "BUTTON") == 0) {
+ target = BUTTON;
+ } else if (strcasecmp(item, "LCD") == 0) {
+ target = LCD;
+ } else if (strcasecmp(item, "LEAKLIGHT") == 0) {
+ target = HRSENSON;
+ } else if (strcasecmp(item, "GSENSOR") == 0) {
+ target = GSENSON;
+ } else if (strcasecmp(item, "BT") == 0) {
+ target = BTTEST;
+ } else if (strcasecmp(item, "SE") == 0) {
+ target = SEChipTest;
+ } else if (strcasecmp(item, "GPS") == 0) {
+ target = GPSTEST;
+ }
+
+ if (target < 0) {
+ return;
+ }
+
+ factorytest_jump_to_subview_id(target);
+ }
+
+ void factorytest_jump_to_subview_id(int16_t target)
+ {
+ if (target < 0) {
+ return;
+ }
+ if (testView::GetInstance()) {
+ testView::GetInstance()->ChangeView(TESTVIEW, target);
+ } else {
+ g_pendingJumpSubView = target;
+ }
+ }
+
+ void factorytest_set_gps_button_state(int on)
+ {
+#if defined(SUPPORT_GNSS)
+ testGPSView *gpsView = testGPSView::GetInstance();
+ if (gpsView != nullptr) {
+ gpsView->SetGPSState(on ? true : false);
+ }
+#else
+ (void)on;
+#endif
+ }
+
+ void factorytest_trigger_leaklight_ui(void)
+ {
+#if defined(SUPPORT_PPG_SERVICE)
+ testhrsenson1View *hrView = testhrsenson1View::GetInstance();
+ if (hrView != nullptr) {
+ // 等价于界面“light”按钮的行为:获取漏光并刷新文本
+ hrView->setlightvalue();
+ }
+#endif
+ }
+
+ void factorytest_set_bt_discovery_active(int active)
+ {
+ testBTView *btView = testBTView::GetInstance();
+ if (btView != nullptr) {
+ btView->SetDiscoveryActive(active ? true : false);
+ }
+ }
+
#ifdef __cplusplus
#if __cplusplus
}
#endif
#ifdef SUPPORT_PPG_SERVICE
+#include "ppg_service.h"
#include "ppg_hal.h"
#endif
+/* 马达振动测试所需结构体/接口 */
+#include "vibrator_service.h"
+
/* Include custom_utilscpp.h for SPI1 receive functions */
#include "custom_utilscpp.h"
/* Include spi_protocol_test.h for protocol test functions */
#include "custom_save_runtime.h"
#include "gnss_http_server.h"
+#ifdef SUPPORT_GNSS
+#include "gnss_ctl.h"
+#include "NMEA0183.h"
+#include "pgnss_sample.h"
+#endif
+
static int ConvertCmdToParam(uint8_t *para, uint32_t paraLen,
uint8_t argv[CUSTOM_UTILS_MAX_ARGC][CUSTOM_UTILS_MAX_ARGV_LEN], uint32_t* argc)
{
return ERRCODE_SUCC;
}
+/* 获取设备固件版本(buildversion) */
+static uint32_t custom_get_fw_version(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+ UNUSED(para);
+ UNUSED(paraLen);
+ UNUSED(strCommonCmd);
+
+ char version_buf[128] = {0};
+ uint32_t version_len = sizeof(version_buf) - 1; // 预留结束符
+ errcode_t ret = uapi_get_buildversion((uint8_t *)version_buf, version_len);
+ if (ret == ERRCODE_SUCC) {
+ wstp_print("fw_version:%s\r\n", version_buf);
+ } else {
+ wstp_print("fw_version:ERR ret=%d\r\n", (int)ret);
+ }
+ return ERRCODE_SUCC;
+}
+
+/* 进入指定产测子界面(会先进入产测Slice) */
+static uint32_t custom_producttest_jump(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+ UNUSED(strCommonCmd);
+ uint8_t argv[CUSTOM_UTILS_MAX_ARGC][CUSTOM_UTILS_MAX_ARGV_LEN] = { 0 };
+ uint32_t argc = 0;
+
+ int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+ if (ret != CUSTOM_UTILS_SUCCESS) {
+ wstp_print("TESTJUMP ATCMD Convert Command Failed\r\n");
+ return ERRCODE_FAIL;
+ }
+
+ if (argc != 1 || strcmp((char*)argv[0], "?") == 0) {
+ wstp_print("Usage: AT^TESTJUMP=<item>\r\n");
+ wstp_print(" item: TP|LCD|BRIGHT|CHARGE|MOTOR|KEY|BUTTON|LEAKLIGHT|GSENSOR|BT|SE|GPS\r\n");
+ return ERRCODE_SUCC;
+ }
+
+ const char *item = (const char*)argv[0];
+ uint8_t code = 0xFF;
+ if (strcasecmp(item, "TP") == 0) {
+ code = 1;
+ } else if (strcasecmp(item, "BRIGHT") == 0) {
+ code = 2;
+ } else if (strcasecmp(item, "CHARGE") == 0) {
+ code = 3;
+ } else if (strcasecmp(item, "MOTOR") == 0) {
+ code = 4;
+ } else if (strcasecmp(item, "KEY") == 0) {
+ code = 5;
+ } else if (strcasecmp(item, "BUTTON") == 0) {
+ code = 5;
+ } else if (strcasecmp(item, "LCD") == 0) {
+ code = 11;
+ } else if (strcasecmp(item, "LEAKLIGHT") == 0) {
+ code = 6;
+ } else if (strcasecmp(item, "GSENSOR") == 0) {
+ code = 7;
+ } else if (strcasecmp(item, "BT") == 0) {
+ code = 8;
+ } else if (strcasecmp(item, "SE") == 0) {
+ code = 9;
+ } else if (strcasecmp(item, "GPS") == 0) {
+ code = 10;
+ } else {
+ wstp_print("TESTJUMP: unknown item=%s\r\n", item);
+ wstp_print("Usage: AT^TESTJUMP=<item>\r\n");
+ wstp_print(" item: TP|LCD|BRIGHT|CHARGE|MOTOR|KEY|BUTTON|LEAKLIGHT|GSENSOR|BT|SE|GPS\r\n");
+ return ERRCODE_FAIL;
+ }
+
+ // 参考 AT^LCDTEST=1 的实现:通过 custom_cmd_service 异步执行跳转,避免切 slice 时机问题
+ do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_TYPE_PRODUCTTEST_JUMP, &code, sizeof(code));
+ wstp_print("TESTJUMP: %s\r\n", item);
+ return ERRCODE_SUCC;
+}
+
+#ifdef SUPPORT_GNSS
+/* AT^GPSVIEW - jump to GPS test subview (need AT^ENTERTESTVIEW first) */
+static uint32_t custom_gps_view(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+ UNUSED(strCommonCmd);
+ UNUSED(para);
+ UNUSED(paraLen);
+ uint8_t code = 10; // GPS (CUSTOM_CMD_MSG_TYPE_PRODUCTTEST_JUMP code)
+ do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_TYPE_PRODUCTTEST_JUMP, &code, sizeof(code));
+ wstp_print("GPSVIEW\r\n");
+ return ERRCODE_SUCC;
+}
+
+/* AT^GPS=1/0 - start/stop GNSS and sync GPS button state if view exists */
+static uint32_t custom_gps_switch(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+ UNUSED(strCommonCmd);
+ uint8_t argv[CUSTOM_UTILS_MAX_ARGC][CUSTOM_UTILS_MAX_ARGV_LEN] = { 0 };
+ uint32_t argc = 0;
+
+ int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+ if (ret != CUSTOM_UTILS_SUCCESS) {
+ wstp_print("GPS ATCMD Convert Command Failed\r\n");
+ return ERRCODE_FAIL;
+ }
+ if (argc != 1 || strcmp((char*)argv[0], "?") == 0) {
+ wstp_print("Usage: AT^GPS=1/0\r\n");
+ return ERRCODE_SUCC;
+ }
+
+ int on = atoi((char*)argv[0]) ? 1 : 0;
+ if (on) {
+ if (getPGnssServerStat() == 1) {
+ wstp_print("GPS: already on\r\n");
+ } else {
+ errcode_t r = gnss_start();
+ wstp_print("GPS: on ret=%d\r\n", (int)r);
+ }
+ } else {
+ if (getPGnssServerStat() == 0) {
+ wstp_print("GPS: already off\r\n");
+ } else {
+ errcode_t r = gnss_stop();
+ wstp_print("GPS: off ret=%d\r\n", (int)r);
+ }
+ }
+
+ // sync button UI state (if GPS test view is shown)
+ uapi_factorytest_set_gps_button_state(on);
+ return ERRCODE_SUCC;
+}
+
+/* AT^GPSINFO - print satellite/CN0 info and basic fields */
+static uint32_t custom_gps_info(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+ UNUSED(strCommonCmd);
+ UNUSED(para);
+ UNUSED(paraLen);
+
+ gps_data_t *gpsdata = getPGPSGlobaldata();
+ if (gpsdata == NULL) {
+ wstp_print("GPSINFO: gpsdata=null\r\n");
+ return ERRCODE_FAIL;
+ }
+ gps_data_t gpsd = {0};
+ if (gpsdata->last_gps_time_ms > 0) {
+ memcpy(&gpsd, gpsdata, sizeof(gps_data_t));
+ } else {
+ memcpy(&gpsd, gpsdata, sizeof(gps_data_t));
+ }
+
+ char buf[1024] = {0};
+ dump_location_data_to_buf(&gpsd, buf, (int)sizeof(buf));
+
+ // 统计当前已解析到的最大CN0/SNR(用于产测快速判断信号强度)
+ int max_cn0 = 0;
+ const start_stat_t *groups[] = { gpsd.startsP, gpsd.startsB, gpsd.startsN, gpsd.startsL, gpsd.startsQ, gpsd.startsA };
+ for (unsigned gi = 0; gi < (unsigned)(sizeof(groups) / sizeof(groups[0])); ++gi) {
+ for (int i = 0; i < 5; ++i) {
+ if (groups[gi][i].starID > 0 && groups[gi][i].snr > max_cn0) {
+ max_cn0 = groups[gi][i].snr;
+ }
+ }
+ }
+
+ /* 首行汇总:sats=GGA 参与定位卫星数;trace/valid_eph/err 来自 $PNTH001(模组 PNT 跟踪星、有效星历、失败码) */
+ wstp_print("GPSINFO: stat=%d, sats=%d, trace=%d, valid_ephemeris=%d, err=%d, vga=%d, quality=%d.%02d, max_cn0=%d, last_ms=%u\r\n",
+ (int)getPGnssServerStat(),
+ (int)gpsd.num_sats,
+ (int)gpsd.th001_trace_star_count,
+ (int)gpsd.th001_valid_star_count,
+ (int)gpsd.th001_errorcode,
+ (int)gpsd.th000_signal_vga,
+ (int)gpsd.th001_quality,
+ (int)((gpsd.th001_quality - (int)gpsd.th001_quality) * 100),
+ (int)max_cn0,
+ (unsigned int)gpsd.last_gps_time_ms);
+ wstp_print("%s\r\n", buf);
+ return ERRCODE_SUCC;
+}
+#endif
+
+/* 马达振动(等价于界面 start 按钮的一次振动参数) */
+static uint32_t custom_motor_vibrate_once(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+ UNUSED(para);
+ UNUSED(paraLen);
+ UNUSED(strCommonCmd);
+
+ vibrator_cmd_t mail = {0};
+ mail.cycle_time_ms = 235;
+ mail.duty = 60;
+ mail.duration_time_ms = 100;
+ do_vibrator_cmd(mail);
+ wstp_print("MOTOR: vibrate_once\r\n");
+ return ERRCODE_SUCC;
+}
+
+/* 心率漏光测试按钮(Light / leaklight) */
+static uint32_t custom_leaklight_test(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+ UNUSED(para);
+ UNUSED(paraLen);
+ UNUSED(strCommonCmd);
+
+ // 进入心率漏光界面
+ uapi_factorytest_enter_test_view(1);
+ uapi_factorytest_enter_test_hr_view();
+
+#ifdef SUPPORT_PPG_SERVICE
+ send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_LEAKLIGHT_TEST);
+ LOS_Msleep(1000);
+ uint32_t ch0 = 0, ch1 = 0, ch2 = 0;
+ ppg_get_factory_data(&ch0, &ch1, &ch2, NULL);
+ send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_STOP_PPG_TEST);
+ wstp_print(">>>leaklight:green=%u,red=%u,ir=%u\r\n", (unsigned int)ch0, (unsigned int)ch1, (unsigned int)ch2);
+ // 同步UI(若当前正在显示心率漏光界面)
+ uapi_factorytest_trigger_leaklight_ui();
+#else
+ wstp_print("LEAKLIGHT: not supported (SUPPORT_PPG_SERVICE disabled)\r\n");
+#endif
+ return ERRCODE_SUCC;
+}
+
+/* 亮度渐变:0-100% 约 3 秒内完成,用于产测 */
+#define BRIGHTRAMP_STEPS 30
+#define BRIGHTRAMP_DURATION_MS 3000
+#define BRIGHTRAMP_MIN 51
+#define BRIGHTRAMP_MAX 255
+
+static osTimerId_t g_brightramp_timer = NULL;
+static uint8_t g_brightramp_step = 0;
+
+static void brightramp_timer_cb(void *arg)
+{
+ (void)arg;
+ if (g_brightramp_step >= BRIGHTRAMP_STEPS) {
+ if (g_brightramp_timer) {
+ osTimerStop(g_brightramp_timer);
+ osTimerDelete(g_brightramp_timer);
+ g_brightramp_timer = NULL;
+ }
+ uapi_setScreenBrightness(BRIGHTRAMP_MAX);
+ wstp_print("BRIGHTRAMP: done (100%%)\r\n");
+ return;
+ }
+ /* 0-100 线性映射到 BRIGHTRAMP_MIN(51)-BRIGHTRAMP_MAX(255) */
+ uint8_t percent = (g_brightramp_step * 100) / BRIGHTRAMP_STEPS;
+ int value = BRIGHTRAMP_MIN + ((BRIGHTRAMP_MAX - BRIGHTRAMP_MIN) * percent) / 100;
+ if (value > BRIGHTRAMP_MAX) {
+ value = BRIGHTRAMP_MAX;
+ }
+ uapi_setScreenBrightness(value);
+ g_brightramp_step++;
+}
+
+static uint32_t custom_brightramp(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+ UNUSED(para);
+ UNUSED(paraLen);
+ UNUSED(strCommonCmd);
+
+ if (g_brightramp_timer) {
+ osTimerStop(g_brightramp_timer);
+ osTimerDelete(g_brightramp_timer);
+ g_brightramp_timer = NULL;
+ }
+
+ g_brightramp_step = 0;
+ uapi_setScreenBrightness(BRIGHTRAMP_MIN);
+
+ g_brightramp_timer = osTimerNew(brightramp_timer_cb, osTimerPeriodic, NULL, NULL);
+ if (g_brightramp_timer == NULL) {
+ wstp_print("BRIGHTRAMP: timer create failed\r\n");
+ return ERRCODE_FAIL;
+ }
+ osTimerStart(g_brightramp_timer, BRIGHTRAMP_DURATION_MS / BRIGHTRAMP_STEPS);
+ wstp_print("BRIGHTRAMP: 0%% -> 100%% in %d s\r\n", BRIGHTRAMP_DURATION_MS / 1000);
+ return ERRCODE_SUCC;
+}
+
+/* GSENSOR 每秒打印 XYZ,不切换 UI */
+static osTimerId_t g_gsensor_at_timer = NULL;
+static void gsensor_at_timer_cb(void *arg)
+{
+ (void)arg;
+#ifdef SUPPORT_CYWEE_SERVICE
+ gsenson_t t;
+ cywee_get_gsensor_data(1, &t);
+ printf(">>>XYZ: X=%.2f,Y=%.2f,Z=%.2f\r\n", t.x, t.y, t.z);
+#endif
+}
+
+static uint32_t custom_gsensor_test(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+ UNUSED(strCommonCmd);
+ uint8_t argv[CUSTOM_UTILS_MAX_ARGC][CUSTOM_UTILS_MAX_ARGV_LEN] = { 0 };
+ uint32_t argc = 0;
+
+ int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+ if (ret != CUSTOM_UTILS_SUCCESS) {
+ wstp_print("GSENSORTEST ATCMD Convert Command Failed\r\n");
+ return ERRCODE_FAIL;
+ }
+
+ if (argc != 1 || strcmp((char*)argv[0], "?") == 0) {
+ wstp_print("Usage: AT^GSENSORTEST=1/0\r\n");
+ return ERRCODE_SUCC;
+ }
+
+ uint8_t cmd = (uint8_t)atoi((char*)argv[0]);
+ if (cmd == 1) {
+#ifdef SUPPORT_CYWEE_SERVICE
+ if (g_gsensor_at_timer == NULL) {
+ g_gsensor_at_timer = osTimerNew(gsensor_at_timer_cb, osTimerPeriodic, NULL, NULL);
+ }
+ if (g_gsensor_at_timer) {
+ osTimerStart(g_gsensor_at_timer, 1000);
+ wstp_print("GSENSORTEST: start (print xyz every 1s)\r\n");
+ } else {
+ wstp_print("GSENSORTEST: start failed (timer null)\r\n");
+ }
+#else
+ wstp_print("GSENSORTEST: not supported (SUPPORT_CYWEE_SERVICE disabled)\r\n");
+#endif
+ } else {
+ if (g_gsensor_at_timer) {
+ osTimerStop(g_gsensor_at_timer);
+ osTimerDelete(g_gsensor_at_timer);
+ g_gsensor_at_timer = NULL;
+ }
+ wstp_print("GSENSORTEST: stop\r\n");
+ }
+
+ return ERRCODE_SUCC;
+}
+
+/* 蓝牙测试界面:启用/禁用蓝牙栈并跳转界面(注意:系统已有 AT^BTENABLE/BTDISABLE) */
+static uint32_t custom_bt_enable_view(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+ UNUSED(para);
+ UNUSED(paraLen);
+ UNUSED(strCommonCmd);
+
+ // 启用蓝牙栈
+ errcode_t res = enable_bt_stack();
+ wstp_print("BTENABLEVIEW: enable_bt_stack ret=%d\r\n", (int)res);
+ uapi_factorytest_enter_test_view(1);
+ uapi_factorytest_enter_test_bt_view();
+ // 同步UI:默认处于未扫描(discovery)状态
+ uapi_factorytest_set_bt_discovery_active(0);
+ return ERRCODE_SUCC;
+}
+
+static uint32_t custom_bt_disable_view(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+ UNUSED(para);
+ UNUSED(paraLen);
+ UNUSED(strCommonCmd);
+
+ // 先停扫描(若正在扫)
+ extern int custom_bt_scan_test_stop(void);
+ (void)custom_bt_scan_test_stop();
+
+ errcode_t res = disable_bt_stack();
+ wstp_print("BTDISABLEVIEW: disable_bt_stack ret=%d\r\n", (int)res);
+ // 同步UI:退出扫描态
+ uapi_factorytest_set_bt_discovery_active(0);
+ return ERRCODE_SUCC;
+}
+
+/* 直接进入/退出产测界面(不重启) */
+static uint32_t custom_enter_producttest_view(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+ UNUSED(strCommonCmd);
+ uint8_t argv[CUSTOM_UTILS_MAX_ARGC][CUSTOM_UTILS_MAX_ARGV_LEN] = { 0 };
+ uint32_t argc = 0;
+
+ int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+ if (ret != CUSTOM_UTILS_SUCCESS) {
+ wstp_print("ENTERTESTVIEW ATCMD Convert Command Failed\r\n");
+ return ERRCODE_FAIL;
+ }
+
+ /* 默认进入:AT^ENTERTESTVIEW 或 AT^ENTERTESTVIEW=1 */
+ uint8_t cmd = 1;
+ if (argc == 0) {
+ cmd = 1;
+ } else if (argc == 1) {
+ if (strcmp((char*)argv[0], "?") == 0) {
+ wstp_print("Usage: AT^ENTERTESTVIEW[=1|0]\r\n");
+ wstp_print(" 1: enter producttest UI\r\n");
+ wstp_print(" 0: exit producttest UI\r\n");
+ return ERRCODE_SUCC;
+ }
+ cmd = (uint8_t)atoi((char*)argv[0]);
+ } else {
+ wstp_print("ENTERTESTVIEW ATCMD Set Parameter Failed argc %d\r\n", argc);
+ wstp_print("Usage: AT^ENTERTESTVIEW[=1|0]\r\n");
+ return ERRCODE_FAIL;
+ }
+
+ if (cmd != 0 && cmd != 1) {
+ wstp_print("ENTERTESTVIEW invalid cmd=%d (must be 0 or 1)\r\n", cmd);
+ return ERRCODE_FAIL;
+ }
+
+ uapi_factorytest_enter_test_view(cmd);
+ wstp_print("ENTERTESTVIEW: %s\r\n", (cmd == 1) ? "enter" : "exit");
+ return ERRCODE_SUCC;
+}
+
extern void lsfd(void);
static uint32_t custom_lsfd(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
{
{ (char *)"AT^CUSTOM_SN", custom_utils_setsn, (char *)"123456789ABCDEF2345678" },
{ (char *)"AT^CUSTOM_SN_REQ", custom_utils_getsn, (char *)" " },
{ (char *)"AT^STARTOTA", custom_start_ota, (char *)" " },
+ { (char *)"AT^GETFWVER", custom_get_fw_version, (char *)"get firmware version (buildversion)" },
+ { (char *)"AT^ENTERTESTVIEW", custom_enter_producttest_view, (char *)"enter/exit producttest UI: AT^ENTERTESTVIEW[=1|0]" },
+ { (char *)"AT^TESTJUMP", custom_producttest_jump, (char *)"jump producttest subview: AT^TESTJUMP=TP|LCD|BRIGHT|CHARGE|MOTOR|KEY|BUTTON|LEAKLIGHT|GSENSOR|BT|SE|GPS" },
+#ifdef SUPPORT_GNSS
+ { (char *)"AT^GPSVIEW", custom_gps_view, (char *)"enter gps test subview (need AT^ENTERTESTVIEW first)" },
+ { (char *)"AT^GPS", custom_gps_switch, (char *)"gps switch (sync UI button): AT^GPS=1/0" },
+ { (char *)"AT^GPSINFO", custom_gps_info, (char *)"GPS summary + GSV(svid,snr) + PNT trace/valid_eph/err" },
+#endif
+ { (char *)"AT^MOTOR", custom_motor_vibrate_once, (char *)"motor vibrate once (same as UI start)" },
+ { (char *)"AT^LEAKLIGHT", custom_leaklight_test, (char *)"hr leaklight button (Light): AT^LEAKLIGHT" },
+ { (char *)"AT^GSENSORTEST", custom_gsensor_test, (char *)"gsensor test print xyz every 1s: AT^GSENSORTEST=1/0" },
+ { (char *)"AT^BRIGHTRAMP", custom_brightramp, (char *)"auto ramp brightness 0->100%% in ~3s: AT^BRIGHTRAMP" },
+ { (char *)"AT^BTENABLEVIEW", custom_bt_enable_view, (char *)"enable bt stack and enter BT test view" },
+ { (char *)"AT^BTDISABLEVIEW", custom_bt_disable_view, (char *)"stop scan and disable bt stack" },
{ (char *)"AT^LCDID", custom_lcd_getid, (char *)" " },
{ (char *)"AT^TOUCHID", custom_touch_getid, (char *)" " },
}
MediaMutexUnLock(g_bt_scan_ctx.mutex);
- if (is_new) {
- PRINT("[BtScan] New device discovered: %02X:%02X:%02X:%02X:%02X:%02X\r\n",
- bd_addr->addr[5], bd_addr->addr[4], bd_addr->addr[3],
- bd_addr->addr[2], bd_addr->addr[1], bd_addr->addr[0]);
- }
+ // 这里只做“新设备发现”标记,等拿到 RSSI 后再按产测格式打印
// 添加设备(暂时没有名称和RSSI)
- BtScanAddOrUpdateDevice(bd_addr, 0, NULL, false);
+ if (is_new) {
+ // 先加一条空记录,让 device_count 统计包含它
+ BtScanAddOrUpdateDevice(bd_addr, 0, NULL, false);
+ // 标记为新设备(用于在第一次拿到RSSI时打印“新蓝牙设备”)
+ MediaMutexLock(g_bt_scan_ctx.mutex);
+ for (uint32_t i = 0; i < g_bt_scan_ctx.device_count; i++) {
+ if (memcmp(g_bt_scan_ctx.devices[i].addr, bd_addr->addr, BD_ADDR_LEN) == 0) {
+ g_bt_scan_ctx.devices[i].is_new_device = true;
+ break;
+ }
+ }
+ MediaMutexUnLock(g_bt_scan_ctx.mutex);
+ } else {
+ BtScanAddOrUpdateDevice(bd_addr, 0, NULL, false);
+ }
// 尝试获取设备名称(只在设备没有名称时才获取和打印)
if (!has_name_already) {
}
if (status == 0) {
+ // 产测格式打印:每次检测到RSSI都打印一行;新设备首次拿到RSSI时额外打印“新蓝牙设备...已检测到X个不同设备”
+ bool is_new_device = false;
+ uint32_t unique_count = 0;
+ MediaMutexLock(g_bt_scan_ctx.mutex);
+ unique_count = g_bt_scan_ctx.device_count;
+ for (uint32_t i = 0; i < g_bt_scan_ctx.device_count; i++) {
+ if (memcmp(g_bt_scan_ctx.devices[i].addr, bd_addr->addr, BD_ADDR_LEN) == 0) {
+ if (g_bt_scan_ctx.devices[i].is_new_device) {
+ is_new_device = true;
+ g_bt_scan_ctx.devices[i].is_new_device = false; // 只打印一次
+ }
+ break;
+ }
+ }
+ MediaMutexUnLock(g_bt_scan_ctx.mutex);
+
+ printf(">>>检测到蓝牙设备:MAC=%02X:%02X:%02X:%02X:%02X:%02X,RSSI=%ddBm\r\n",
+ bd_addr->addr[5], bd_addr->addr[4], bd_addr->addr[3],
+ bd_addr->addr[2], bd_addr->addr[1], bd_addr->addr[0],
+ rssi);
+
+ if (is_new_device) {
+ printf(">>>新蓝牙设备:MAC=%02X:%02X:%02X:%02X:%02X:%02X,RSSI=%ddBm(已检测到%u个不同设备)\r\n",
+ bd_addr->addr[5], bd_addr->addr[4], bd_addr->addr[3],
+ bd_addr->addr[2], bd_addr->addr[1], bd_addr->addr[0],
+ rssi, (unsigned int)unique_count);
+ }
+
+ // 保留原逻辑:RSSI变化超过阈值时也可额外打印(现在不再需要,避免重复)
// 检查RSSI是否有显著变化(只在新设备或RSSI变化超过5dBm时打印)
MediaMutexLock(g_bt_scan_ctx.mutex);
bool should_print = false;
}
MediaMutexUnLock(g_bt_scan_ctx.mutex);
- if (should_print) {
- printf("fac:[BtScan] Device: %02X:%02X:%02X:%02X:%02X:%02X, RSSI=%d dBm\r\n",
- bd_addr->addr[5], bd_addr->addr[4], bd_addr->addr[3],
- bd_addr->addr[2], bd_addr->addr[1], bd_addr->addr[0],
- rssi);
- }
+ (void)should_print;
// 更新设备RSSI
BtScanAddOrUpdateDevice(bd_addr, rssi, NULL, false);