/* 0.1.17:CH224A 运行期轮询(pdmon.h)。 守四件事: 1. 读到的就是芯片此刻的值,换了档下一拍就跟着变(这个模块存在的理由); 2. 读不到时 `ok` 落下、旧值留着,恢复后自己回来; 3. 换档事件:连续两拍一致才记、同一个档位只记一次、和启动时那条不重复; 4. 主干不应答就去 mux 通道 5 找(设计与实物不一致,bringup.c `pd_up()`)。 */ #include "pdmon.h" #include "board_pins.h" #include "ch224a.h" #include "evlog.h" #include "hal_i2c.h" #include "hal_lock.h" #include "i2cbus.h" #include "sim_hal.h" #include "tca9548a.h" #include "unity.h" static int count_pd_ev(evlog_rec_t *last) { (void)evlog_flush(0); evlog_stats_t st; evlog_stats(&st); int n = 0; evlog_rec_t rec; for (uint32_t seq = st.oldest_seq; seq < st.next_seq; seq++) { if (evlog_read(seq, &rec, 1) == 1 && rec.type == (uint8_t)LOG_EV_PD_LIMIT) { n++; if (last != NULL) { *last = rec; } } } return n; } static void charger(uint32_t ma) { sim_i2c_set_reg(CH224A_ADDR_DEFAULT, CH224A_REG_STATUS, 0x08); sim_i2c_set_reg(CH224A_ADDR_DEFAULT, CH224A_REG_CURRENT, (uint16_t)(ma / 50u)); } void setUp(void) { sim_hal_reset(); TEST_ASSERT_EQUAL_INT(HAL_OK, hal_i2c_init(NULL)); TEST_ASSERT_EQUAL_INT(HAL_OK, hal_lock_init()); sim_i2c_add_mux(TCA9548A_ADDR, BOARD_PIN_MUX_RST_N); TEST_ASSERT_EQUAL_INT(HAL_OK, i2cbus_init()); TEST_ASSERT_EQUAL_INT(HAL_OK, evlog_init_ex(0)); } void tearDown(void) {} static void test_reports_what_the_chip_says_now(void) { sim_i2c_add(CH224A_ADDR_DEFAULT, 1); charger(3000); pdmon_init(3000); pdmon_snap_t s; pdmon_get(&s); TEST_ASSERT_FALSE(s.ok); /* 还没读过第一拍 */ pdmon_poll(); pdmon_get(&s); TEST_ASSERT_TRUE(s.ok); TEST_ASSERT_EQUAL_UINT8(0x08, s.status); TEST_ASSERT_EQUAL_UINT32(3000, s.ma); charger(5000); pdmon_poll(); pdmon_get(&s); TEST_ASSERT_EQUAL_UINT32(5000, s.ma); /* 下一拍就是新值,不等去抖 */ } static void test_read_failure_keeps_the_old_value_and_recovers(void) { sim_i2c_add(CH224A_ADDR_DEFAULT, 1); charger(3250); pdmon_init(3250); pdmon_poll(); sim_i2c_set_present(CH224A_ADDR_DEFAULT, false); pdmon_poll(); pdmon_snap_t s; pdmon_get(&s); TEST_ASSERT_FALSE(s.ok); TEST_ASSERT_EQUAL_UINT32(3250, s.ma); TEST_ASSERT_EQUAL_UINT32(1, s.errors); sim_i2c_set_present(CH224A_ADDR_DEFAULT, true); pdmon_poll(); pdmon_get(&s); TEST_ASSERT_TRUE(s.ok); TEST_ASSERT_EQUAL_INT(0, count_pd_ev(NULL)); /* 掉线再回来、档位没变:不记 */ } static void test_change_is_logged_once_after_two_matching_reads(void) { sim_i2c_add(CH224A_ADDR_DEFAULT, 1); charger(5000); pdmon_init(5000); /* 启动时 bringup 已经记过 5 A 那条 */ pdmon_poll(); pdmon_poll(); TEST_ASSERT_EQUAL_INT(0, count_pd_ev(NULL)); charger(0); /* 重新协商的中途 */ pdmon_poll(); pdmon_poll(); TEST_ASSERT_EQUAL_INT(0, count_pd_ev(NULL)); charger(3000); pdmon_poll(); TEST_ASSERT_EQUAL_INT(0, count_pd_ev(NULL)); /* 只见过一拍 */ pdmon_poll(); evlog_rec_t rec; TEST_ASSERT_EQUAL_INT(1, count_pd_ev(&rec)); TEST_ASSERT_EQUAL_UINT8(PDMON_EV_ARG_CHANGED, rec.arg); TEST_ASSERT_EQUAL_INT32(600, rec.bus_mv); /* 60 W,单位 mW/100 */ TEST_ASSERT_EQUAL_INT32(3000, rec.current_ua); for (int i = 0; i < 5; i++) { pdmon_poll(); } TEST_ASSERT_EQUAL_INT(1, count_pd_ev(NULL)); } static void test_boot_missed_it_but_runtime_reads_it(void) { sim_i2c_add(CH224A_ADDR_DEFAULT, 1); charger(3000); pdmon_init(0); /* 启动时没读到,日志里是「按保守值」那条 */ pdmon_poll(); pdmon_poll(); evlog_rec_t rec; TEST_ASSERT_EQUAL_INT(1, count_pd_ev(&rec)); TEST_ASSERT_EQUAL_INT32(3000, rec.current_ua); } static void test_found_behind_channel_5(void) { sim_i2c_add_ch(TCA9548A_CH_PD, CH224A_ADDR_DEFAULT, 1); sim_i2c_set_reg_ch(TCA9548A_CH_PD, CH224A_ADDR_DEFAULT, CH224A_REG_STATUS, 0x08); sim_i2c_set_reg_ch(TCA9548A_CH_PD, CH224A_ADDR_DEFAULT, CH224A_REG_CURRENT, 5000 / 50); pdmon_init(5000); pdmon_poll(); pdmon_snap_t s; pdmon_get(&s); TEST_ASSERT_TRUE(s.ok); TEST_ASSERT_EQUAL_UINT32(5000, s.ma); TEST_ASSERT_EQUAL_UINT32(0, s.errors); } static void test_absent_chip_is_just_not_ok(void) { pdmon_init(0); pdmon_poll(); pdmon_snap_t s; pdmon_get(&s); TEST_ASSERT_FALSE(s.ok); TEST_ASSERT_EQUAL_UINT32(1, s.polls); TEST_ASSERT_EQUAL_UINT32(1, s.errors); TEST_ASSERT_EQUAL_INT(0, count_pd_ev(NULL)); } int main(void) { UNITY_BEGIN(); RUN_TEST(test_reports_what_the_chip_says_now); RUN_TEST(test_read_failure_keeps_the_old_value_and_recovers); RUN_TEST(test_change_is_logged_once_after_two_matching_reads); RUN_TEST(test_boot_missed_it_but_runtime_reads_it); RUN_TEST(test_found_behind_channel_5); RUN_TEST(test_absent_chip_is_just_not_ok); return UNITY_END(); }