feat: add AS status feedback for both HMI sizes with verified v2.7 release

This commit is contained in:
shenlefengnai-rgb
2026-10-07 16:32:42 +08:00
parent dba8aa5ea9
commit e6556fc218
245 changed files with 21470 additions and 159 deletions
+41 -22
View File
@@ -38,18 +38,22 @@ static volatile AmiDisplayState display_state;
static volatile uint32_t display_dirty;
static volatile uint32_t dash_last_rx_ms;
static volatile uint32_t debug_last_rx_ms;
static volatile uint32_t wheel_speed_last_rx_ms;
static volatile bool wheel_speed_received;
static volatile uint32_t adc_last_rx_ms;
static volatile uint32_t bms_status_last_rx_ms;
static volatile uint32_t bms_temperature_last_rx_ms;
static volatile uint32_t drivetrain_last_rx_ms;
static volatile uint32_t vcu_status_last_rx_ms;
/* Task 7 = unknown; lock/EBS 0 = unknown, 1 = green, 2 = red. */
static volatile uint8_t vcu_display_state[3] = {7U, 0U, 0U};
/* AS 0..5 = OFF/Ready/Driving/Finished/Emergency/Manual; 6 = unknown. */
static volatile uint8_t vcu_display_state[4] = {7U, 0U, 0U, 6U};
static volatile uint8_t vcu_display_dirty;
static volatile bool vcu_status_received;
/* Preserve the exact source units even where the HMI has integer controls. */
static volatile uint16_t sdc_adc_mv;
static volatile uint16_t sdc_frequency_hz[4];
/* SDC 7bc2d9f: left-front PA0 and right-front PA6, already calibrated mm/s. */
static volatile uint16_t sdc_wheel_speed_mm_s[2];
static volatile uint16_t sdc_gpio_state;
static volatile uint16_t sdc_gpio_changed;
static volatile uint32_t sdc_gpio_timestamp_ms;
@@ -281,18 +285,20 @@ static bool DecodeCan(uint32_t identifier, uint32_t id_type,
if (identifier == AMI_CAN_ID_VCU_STATUS)
{
/* Custom VCU feedback; requests never update these actual states. */
if ((length != 8U) || (data[7] != 1U) || (data[0] > 6U) ||
(data[1] > 1U) || (data[2] > 1U) || ((data[3] & 0xF8U) != 0U) ||
(data[5] != 0U) || (data[6] != 0U))
if ((length != 8U) || (data[0] > 6U) ||
(data[1] > 1U) || (data[2] > 1U) || (data[6] != 0U) ||
!(((data[7] == 1U) && ((data[3] & 0xF8U) == 0U) && (data[5] == 0U)) ||
((data[7] == 2U) && ((data[3] & 0xF0U) == 0U) && (data[5] <= 5U))))
{
return false;
}
uint8_t states[3] = {
uint8_t states[4] = {
(data[3] & 1U) ? data[0] : 7U,
(data[3] & 2U) ? (data[1] ? 1U : 2U) : 0U,
(data[3] & 4U) ? (data[2] ? 1U : 2U) : 0U
(data[3] & 4U) ? (data[2] ? 1U : 2U) : 0U,
((data[7] == 2U) && (data[3] & 8U)) ? data[5] : 6U
};
for (uint32_t i = 0U; i < 3U; ++i)
for (uint32_t i = 0U; i < 4U; ++i)
{
if (vcu_display_state[i] != states[i])
{
@@ -340,13 +346,19 @@ static bool DecodeCan(uint32_t identifier, uint32_t id_type,
debug_last_rx_ms = now;
return true;
}
if ((identifier == AMI_CAN_ID_SDC_FREQUENCY) && (length == 8U))
if ((identifier == AMI_CAN_ID_SDC_WHEEL_SPEED) && (length == 4U))
{
for (uint32_t i = 0U; i < 4U; ++i)
{
sdc_frequency_hz[i] = (uint16_t)ReadLeU16(&data[i * 2U]);
}
/* Hz is not km/h; wheel circumference and pulses/rev are undefined. */
uint32_t left = ReadLeU16(data);
uint32_t right = ReadLeU16(&data[2]);
sdc_wheel_speed_mm_s[0] = (uint16_t)left;
sdc_wheel_speed_mm_s[1] = (uint16_t)right;
/* Mean front-wheel mm/s * 0.0036 -> whole km/h, rounded once.
SDC already applies 49 pulses/rev and 1414 mm circumference.
Zero and 0xFFFF are valid values; the source defines no sentinel. */
SetDashValue(0U, (int32_t)(((left + right) * 9U + 2500U) / 5000U));
wheel_speed_last_rx_ms = now;
wheel_speed_received = true;
dash_last_rx_ms = now;
return true;
}
if ((identifier == AMI_CAN_ID_SDC_GPIO) && (length == 8U))
@@ -602,13 +614,20 @@ static void UpdateTimeoutsAndLeds(void)
__disable_irq();
/* Sample time after excluding RX IRQs: a newer timestamp must not underflow. */
now = HAL_GetTick();
if (wheel_speed_received &&
((now - wheel_speed_last_rx_ms) > AMI_WHEEL_SPEED_TIMEOUT_MS))
{
SetDashValid(0U, false);
wheel_speed_received = false;
}
if (vcu_status_received &&
((now - vcu_status_last_rx_ms) > AMI_VCU_STATUS_TIMEOUT_MS))
{
vcu_display_state[0] = 7U;
vcu_display_state[1] = 0U;
vcu_display_state[2] = 0U;
vcu_display_dirty |= 7U;
vcu_display_state[3] = 6U;
vcu_display_dirty |= 15U;
vcu_status_received = false;
}
if ((adc_last_rx_ms == 0U) || ((now - adc_last_rx_ms) > AMI_ADC_TIMEOUT_MS))
@@ -654,8 +673,8 @@ static void UpdateTimeoutsAndLeds(void)
static void SendNextDirtyValue(void)
{
static const char *const vcu_prefix[3] = {
"current_task=", "lock_state=", "ebs_state="
static const char *const vcu_prefix[4] = {
"current_task=", "lock_state=", "ebs_state=", "as_state="
};
static const char *const dash_prefix[8] = {
"dash.speed.val=", "dash.ts.val=", "dash.mct.val=", "dash.dl.val=",
@@ -689,14 +708,14 @@ static void SendNextDirtyValue(void)
}
/* Fair rotation prevents rapid source updates from starving other fields. */
for (uint32_t offset = 0U; offset < 35U; ++offset)
for (uint32_t offset = 0U; offset < 36U; ++offset)
{
index = (cursor + offset) % 35U;
index = (cursor + offset) % 36U;
if ((index < 32U) ? ((dirty & (1UL << index)) != 0U)
: ((vcu_dirty & (1U << (index - 32U))) != 0U)) { break; }
}
bit = 1UL << ((index < 32U) ? index : index - 32U);
cursor = (index + 1U) % 35U;
cursor = (index + 1U) % 36U;
__disable_irq();
if (index >= 32U)
@@ -750,7 +769,7 @@ void AMI_App_Init(void)
HAL_GPIO_WritePin(STATUS_LED1_GPIO_Port, STATUS_LED1_Pin, LedInactiveLevel());
HAL_GPIO_WritePin(STATUS_LED2_GPIO_Port, STATUS_LED2_Pin, AMI_LED_ACTIVE_LEVEL);
display_dirty = DIRTY_DASH_ALL | DIRTY_DEBUG_ALL | DIRTY_COLOR_ALL;
vcu_display_dirty = 7U;
vcu_display_dirty = 15U;
ConfigureCan();
RestartScreenRx();
}
@@ -768,7 +787,7 @@ void AMI_App_Service(void)
{
__disable_irq();
display_dirty |= DIRTY_DASH_ALL | DIRTY_DEBUG_ALL | DIRTY_COLOR_ALL;
vcu_display_dirty |= 7U;
vcu_display_dirty |= 15U;
__enable_irq();
last_screen_sync_ms = now;
}