/* A4 之二:`rail_set_mv()` —— 三个验收主项(固件开发计划 §5 A4 那一行): ① 4020 mV 被拒(SR-13) ② **写更大的码值,输出更低**(反向关系) ③ 3900 mV ↔ Vd 0.548 V 都在下面打了 ⭐。 */ #include "dac63204.h" #include "phonerail.h" #include "rail.h" #include "sim_hal.h" #include "unity.h" void setUp(void) { sim_hal_reset(); } void tearDown(void) {} /* 两片假 DAC 都挂上,并预置 DEVICE-ID 与 COMMON-CONFIG 的复位值。 */ static void mount_both(void) { for (int i = 0; i < DAC63204_COUNT; i++) { uint8_t a = dac63204_all_addr[i]; sim_i2c_add(a, 2); sim_i2c_set_reg(a, DAC63204_REG_GENERAL_STATUS, (uint16_t)(DAC63204_DEVICE_ID << 2)); sim_i2c_set_reg(a, DAC63204_REG_COMMON_CONFIG, 0x0FFF); } TEST_ASSERT_EQUAL_INT(HAL_OK, hal_i2c_init(NULL)); } /* 直接从假器件的寄存器里把某一路的码抠出来(绕开被测代码自己的读路径)。 */ static uint16_t raw_code(int rail) { uint16_t reg = sim_i2c_get_reg(dac63204_rail_addr(rail), DAC63204_REG_DATA(dac63204_rail_ch(rail))); return DAC63204_REG_TO_CODE(reg); } /* ---- ① 越界即拒(SR-13) --------------------------------------------------- */ /* ⭐ 验收主项一:4020 mV 必须被拒,而且**一个字节都不许发出去**。 这是第四道限制,前三道在硬件里(设计文档 §4.1)—— 它的作用是让操作者早点 知道自己写错了,不是靠它保安全。 */ static void test_4020_mv_is_rejected(void) { mount_both(); TEST_ASSERT_EQUAL_INT(HAL_OK, rail_volt_init()); for (int rail = 1; rail <= PHONERAIL_RAIL_COUNT; rail++) { uint16_t before = raw_code(rail); TEST_ASSERT_EQUAL_INT_MESSAGE(HAL_ERR_ARG, rail_set_mv(rail, 4020), "4020 mV 必须被拒"); TEST_ASSERT_EQUAL_UINT16_MESSAGE(before, raw_code(rail), "被拒的请求不许改到 DAC"); } TEST_ASSERT_FALSE(rail_mv_in_range(4011)); TEST_ASSERT_TRUE(rail_mv_in_range(RAIL_MV_MAX)); } /* 下限同样拒:DAC 满码也到不了 3523 mV,悄悄夹到 3524 就成了「设了但没设到」。 */ static void test_below_range_is_rejected(void) { mount_both(); TEST_ASSERT_EQUAL_INT(HAL_OK, rail_volt_init()); TEST_ASSERT_EQUAL_INT(HAL_ERR_ARG, rail_set_mv(1, RAIL_MV_MIN - 1)); TEST_ASSERT_EQUAL_INT(HAL_ERR_ARG, rail_set_mv(1, 0)); TEST_ASSERT_FALSE(rail_mv_in_range(3523)); TEST_ASSERT_TRUE(rail_mv_in_range(RAIL_MV_MIN)); } static void test_rail_index_is_one_based(void) { mount_both(); TEST_ASSERT_EQUAL_INT(HAL_ERR_ARG, rail_set_mv(0, RAIL_MV_SAFE)); TEST_ASSERT_EQUAL_INT(HAL_ERR_ARG, rail_set_mv(6, RAIL_MV_SAFE)); int mv = 0; TEST_ASSERT_EQUAL_INT(HAL_ERR_ARG, rail_get_mv(0, &mv)); TEST_ASSERT_EQUAL_INT(HAL_ERR_ARG, rail_get_mv(1, NULL)); } /* ---- ② 反向关系 ---------------------------------------------------------- */ /* ⭐ 验收主项二:**码越大,输出越低。** 写反了不报错 —— 「调高电压」的命令把手机调到 3.52 V,手机照样开机, 要跑一阵子才在负载尖峰下掉电。所以这里既查换算,也查真写进 DAC 的那个数。 */ static void test_higher_code_means_lower_voltage(void) { /* 换算层:单调**递减**,端点钉死。 */ TEST_ASSERT_EQUAL_UINT16(0, rail_mv_to_code(RAIL_MV_MAX)); TEST_ASSERT_TRUE(rail_mv_to_code(RAIL_MV_MIN) > rail_mv_to_code(RAIL_MV_MAX)); TEST_ASSERT_TRUE(rail_mv_to_code(3600) > rail_mv_to_code(4000)); uint16_t prev = rail_mv_to_code(RAIL_MV_MIN); for (int mv = RAIL_MV_MIN + 1; mv <= RAIL_MV_MAX; mv++) { uint16_t code = rail_mv_to_code(mv); TEST_ASSERT_TRUE_MESSAGE(code <= prev, "mv 变大,码必须变小或持平"); prev = code; } /* 总线层:同一路先设高再设低,DAC 里的数必须变大。 */ mount_both(); TEST_ASSERT_EQUAL_INT(HAL_OK, rail_volt_init()); TEST_ASSERT_EQUAL_INT(HAL_OK, rail_set_mv(1, 4000)); uint16_t at_4000 = raw_code(1); TEST_ASSERT_EQUAL_INT(HAL_OK, rail_set_mv(1, 3600)); uint16_t at_3600 = raw_code(1); TEST_ASSERT_TRUE_MESSAGE(at_3600 > at_4000, "3.60 V 的码必须比 4.00 V 的大"); } /* ---- ③ 3900 mV ↔ Vd 0.548 V --------------------------------------------- */ /* ⭐ 验收主项三:NVM 出厂默认那一点(设计文档 §4.3 / §10.5 的表)。 */ static void test_3900_mv_is_vd_548_mv(void) { uint16_t code = rail_mv_to_code(3900); TEST_ASSERT_EQUAL_UINT16(926, code); /* Vd = 926 / 4096 × 2.424 V = 548.0 mV */ TEST_ASSERT_INT32_WITHIN_MESSAGE(500, 548000, rail_code_to_vd_uv(code), "3900 mV 对应的 Vd 必须是 0.548 V"); TEST_ASSERT_EQUAL_INT(3900, rail_code_to_mv(code)); } /* 设计文档 §4.3 那三个角点,一个不落。 */ static void test_transfer_curve_endpoints(void) { TEST_ASSERT_EQUAL_INT(RAIL_MV_MAX, rail_code_to_mv(0)); /* Vd 0 V -> 4.010 V */ TEST_ASSERT_EQUAL_INT(3900, rail_code_to_mv(926)); /* Vd 0.548 -> 3.900 V */ TEST_ASSERT_EQUAL_INT(3524, rail_code_to_mv(DAC63204_CODE_MAX)); /* 满码 -> 3.524 V */ /* 上下限都必须落在 12 位码里 —— 越界说明 RAIL_MV_MIN/MAX 和电阻值对不上了。 */ TEST_ASSERT_TRUE(rail_mv_to_code(RAIL_MV_MIN) <= DAC63204_CODE_MAX); TEST_ASSERT_TRUE(rail_mv_to_code(RAIL_MV_MAX) <= DAC63204_CODE_MAX); } /* 全量程往返:设进去再读回来,误差不超过 1 mV(一个码在输出端 0.119 mV)。 */ static void test_set_get_round_trip(void) { mount_both(); TEST_ASSERT_EQUAL_INT(HAL_OK, rail_volt_init()); for (int rail = 1; rail <= PHONERAIL_RAIL_COUNT; rail++) { for (int mv = RAIL_MV_MIN; mv <= RAIL_MV_MAX; mv += 7) { int back = 0; TEST_ASSERT_EQUAL_INT(HAL_OK, rail_set_mv(rail, mv)); TEST_ASSERT_EQUAL_INT(HAL_OK, rail_get_mv(rail, &back)); TEST_ASSERT_INT_WITHIN(1, mv, back); } } } /* ---- 五路互不串扰 --------------------------------------------------------- */ /* 改一路不许动到别的四路。CH1 与 CH2 在同一片(U6)上,是最容易串的一对。 */ static void test_setting_one_rail_leaves_the_others_alone(void) { mount_both(); TEST_ASSERT_EQUAL_INT(HAL_OK, rail_volt_init()); uint16_t before[PHONERAIL_RAIL_COUNT + 1]; for (int r = 1; r <= PHONERAIL_RAIL_COUNT; r++) { before[r] = raw_code(r); } TEST_ASSERT_EQUAL_INT(HAL_OK, rail_set_mv(1, 3600)); for (int r = 2; r <= PHONERAIL_RAIL_COUNT; r++) { TEST_ASSERT_EQUAL_UINT16_MESSAGE(before[r], raw_code(r), "只该动 CH1"); } TEST_ASSERT_TRUE(raw_code(1) != before[1]); } /* 五路各写一个不同的值,逐路读回来必须各是各的 —— 映射表串了这条就红。 */ static void test_each_rail_keeps_its_own_value(void) { static const int want[PHONERAIL_RAIL_COUNT] = { 3600, 3700, 3800, 3900, 4000 }; mount_both(); TEST_ASSERT_EQUAL_INT(HAL_OK, rail_volt_init()); for (int r = 1; r <= PHONERAIL_RAIL_COUNT; r++) { TEST_ASSERT_EQUAL_INT(HAL_OK, rail_set_mv(r, want[r - 1])); } for (int r = 1; r <= PHONERAIL_RAIL_COUNT; r++) { int back = 0; TEST_ASSERT_EQUAL_INT(HAL_OK, rail_get_mv(r, &back)); TEST_ASSERT_INT_WITHIN(1, want[r - 1], back); } } /* ---- 初始化 -------------------------------------------------------------- */ /* 上电即安全值:init 完五路都应该在 3.90 V 上,不依赖后续有人来设。 */ static void test_init_leaves_every_rail_at_the_safe_value(void) { mount_both(); TEST_ASSERT_EQUAL_INT(HAL_OK, rail_volt_init()); for (int r = 1; r <= PHONERAIL_RAIL_COUNT; r++) { int mv = 0; TEST_ASSERT_EQUAL_INT(HAL_OK, rail_get_mv(r, &mv)); TEST_ASSERT_EQUAL_INT_MESSAGE(RAIL_MV_SAFE, mv, "上电安全值必须是 3900 mV"); } } /* 少一片 DAC:init 必须如实失败(降级留给 A15,这里不许悄悄当成功)。 */ static void test_init_fails_when_a_chip_is_missing(void) { sim_i2c_add(DAC63204_ADDR_U6, 2); sim_i2c_set_reg(DAC63204_ADDR_U6, DAC63204_REG_GENERAL_STATUS, (uint16_t)(DAC63204_DEVICE_ID << 2)); TEST_ASSERT_EQUAL_INT(HAL_OK, hal_i2c_init(NULL)); TEST_ASSERT_EQUAL_INT(HAL_ERR_NAK, rail_volt_init()); /* U7 没挂 */ } static void test_set_propagates_bus_errors(void) { mount_both(); TEST_ASSERT_EQUAL_INT(HAL_OK, rail_volt_init()); sim_i2c_set_present(dac63204_rail_addr(3), false); TEST_ASSERT_EQUAL_INT(HAL_ERR_NAK, rail_set_mv(3, 3800)); int mv = 0; TEST_ASSERT_EQUAL_INT(HAL_ERR_NAK, rail_get_mv(3, &mv)); } int main(void) { UNITY_BEGIN(); RUN_TEST(test_4020_mv_is_rejected); RUN_TEST(test_below_range_is_rejected); RUN_TEST(test_rail_index_is_one_based); RUN_TEST(test_higher_code_means_lower_voltage); RUN_TEST(test_3900_mv_is_vd_548_mv); RUN_TEST(test_transfer_curve_endpoints); RUN_TEST(test_set_get_round_trip); RUN_TEST(test_setting_one_rail_leaves_the_others_alone); RUN_TEST(test_each_rail_keeps_its_own_value); RUN_TEST(test_init_leaves_every_rail_at_the_safe_value); RUN_TEST(test_init_fails_when_a_chip_is_missing); RUN_TEST(test_set_propagates_bus_errors); return UNITY_END(); }