forked from achamaikin/CCSModuleSW30Web
Overwrite repository contents with fork state.
Replace outdated files with the latest working tree from fork/CCSModuleSW30Web to align source and generated artifacts. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+283
-120
@@ -3,10 +3,12 @@
|
||||
#include "connector.h"
|
||||
#include "board.h"
|
||||
#include "debug.h"
|
||||
#include "isr_opt.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "charger_config.h"
|
||||
#include "psu_control.h"
|
||||
#include "serial_control.h"
|
||||
|
||||
extern UART_HandleTypeDef huart3;
|
||||
extern uint8_t config_initialized;
|
||||
@@ -28,14 +30,19 @@ uint8_t ev_enable_output = 0;
|
||||
#define CMD_INTERVAL 10
|
||||
#define MAX_TX_BUFFER_SIZE 256
|
||||
#define MAX_RX_BUFFER_SIZE 256
|
||||
|
||||
/* Everest requests 500 V → БП реально 300 V / 1 A, в STATE отдаём 500 V. */
|
||||
#define EVEREST_TIMEOUT_WARN_MS 5000u
|
||||
#define EVEREST_TIMEOUT_STOP_MS 10000u
|
||||
#define UART3_REINIT_TIMEOUT_MS 1500u
|
||||
/* Everest requests 500 V -> PSU really gets 300 V / 1 A, state still reports 500 V. */
|
||||
#define FAKE_EVREQ_VOLTAGE_V 500u
|
||||
#define FAKE_PSU_VOLTAGE_V 300u
|
||||
#define FAKE_PSU_CURRENT_0P1A 10u
|
||||
|
||||
static uint8_t rx_buffer[MAX_RX_BUFFER_SIZE];
|
||||
static uint8_t tx_buffer[MAX_TX_BUFFER_SIZE];
|
||||
static uint8_t tx_pending_buffer[MAX_TX_BUFFER_SIZE];
|
||||
static uint16_t tx_pending_len = 0;
|
||||
static uint8_t uart3_tx_busy = 0;
|
||||
|
||||
uint8_t ESTOP = 0;
|
||||
uint8_t REPLUG = 0;
|
||||
@@ -45,31 +52,121 @@ static uint8_t pwm_duty_percent = 100;
|
||||
uint8_t isolation_enable = 0;
|
||||
static uint32_t last_host_seen = 0;
|
||||
static uint8_t fake_500_voltage_mode = 0;
|
||||
static CP_State_t cp_state_buffer = EV_STATE_ACQUIRING;
|
||||
static uint8_t everest_timed_out = 0;
|
||||
static uint8_t everest_timeout_warn_latched = 0;
|
||||
static uint8_t everest_timeout_stop_latched = 0;
|
||||
static uint32_t uart3_last_packet_tick = 0;
|
||||
static uint32_t uart3_last_reinit_tick = 0;
|
||||
|
||||
CCS_State_t CCS_State;
|
||||
CCS_EvInfo_t CCS_EvInfo;
|
||||
CONN_State_t CCS_EvseState;
|
||||
CCS_ConnectorState_t CCS_ConnectorState = CCS_UNKNOWN;
|
||||
|
||||
static uint8_t process_received_packet(const uint8_t* packet, uint16_t packet_len);
|
||||
ISR_FAST static uint8_t process_received_packet(const uint8_t* packet, uint16_t packet_len);
|
||||
static void CCS_UART3_Watchdog(void);
|
||||
static void CCS_LogUart3Error(const char *tag);
|
||||
|
||||
void CCS_RxEventCallback(UART_HandleTypeDef *huart, uint16_t size) {
|
||||
if (huart != &huart3) {
|
||||
ISR_FAST static void uart3_log_hal_error(uint8_t uart_num, uint32_t err) {
|
||||
if (err == HAL_UART_ERROR_NONE) {
|
||||
log_printf(LOG_ERR, "UART%u HAL error decode: NONE\n", uart_num);
|
||||
return;
|
||||
}
|
||||
if (size > 0 && size <= sizeof(rx_buffer)) {
|
||||
process_received_packet(rx_buffer, size);
|
||||
log_printf(LOG_ERR, "UART%u HAL error decode: %s%s%s%s%s%s raw=0x%08lx\n",
|
||||
uart_num,
|
||||
(err & HAL_UART_ERROR_PE) ? "PE " : "",
|
||||
(err & HAL_UART_ERROR_NE) ? "NE " : "",
|
||||
(err & HAL_UART_ERROR_FE) ? "FE " : "",
|
||||
(err & HAL_UART_ERROR_ORE) ? "ORE " : "",
|
||||
(err & HAL_UART_ERROR_DMA) ? "DMA " : "",
|
||||
#ifdef HAL_UART_ERROR_INVALID_CALLBACK
|
||||
(err & HAL_UART_ERROR_INVALID_CALLBACK) ? "INV_CB " : "",
|
||||
#else
|
||||
"",
|
||||
#endif
|
||||
(unsigned long)err);
|
||||
}
|
||||
|
||||
ISR_FAST static void uart3_arm_rx_or_log(const char *where) {
|
||||
HAL_StatusTypeDef st = HAL_UARTEx_ReceiveToIdle_DMA(&huart3, rx_buffer, sizeof(rx_buffer));
|
||||
if (st == HAL_OK) {
|
||||
return;
|
||||
}
|
||||
uint32_t err_after = HAL_UART_GetError(&huart3);
|
||||
log_printf(LOG_ERR,
|
||||
"UART3 RX arm failed (%s): HAL_Status=%d err_after=0x%08lx\n",
|
||||
where, (int)st, (unsigned long)err_after);
|
||||
uart3_log_hal_error(3u, err_after);
|
||||
CCS_LogUart3Error("UART3 RX arm failed details");
|
||||
if (err_after != HAL_UART_ERROR_NONE) {
|
||||
(void)HAL_UART_AbortReceive(&huart3);
|
||||
}
|
||||
}
|
||||
|
||||
void CCS_RxArm(void) {
|
||||
if ((&huart3)->RxState == HAL_UART_STATE_READY) {
|
||||
(void)HAL_UARTEx_ReceiveToIdle_IT(&huart3, rx_buffer, sizeof(rx_buffer));
|
||||
ISR_FAST void CCS_RxEventCallback(UART_HandleTypeDef *huart, uint16_t size) {
|
||||
if (huart != &huart3) {
|
||||
log_printf(LOG_WARN, "UART3 RX drop: wrong huart in RxEventCallback (size=%u)\n",
|
||||
(unsigned)size);
|
||||
return;
|
||||
}
|
||||
if (size == 0u) {
|
||||
log_printf(LOG_WARN, "UART3 RX drop: RxEvent size=0 (idle, no payload)\n");
|
||||
uart3_arm_rx_or_log("RxEventCallback");
|
||||
return;
|
||||
}
|
||||
if (size > sizeof(rx_buffer)) {
|
||||
log_printf(LOG_ERR, "UART3 RX drop: size=%u > rx_buffer %u (overflow, not parsed)\n",
|
||||
(unsigned)size, (unsigned)sizeof(rx_buffer));
|
||||
uart3_arm_rx_or_log("RxEventCallback");
|
||||
return;
|
||||
}
|
||||
uart3_last_packet_tick = HAL_GetTick();
|
||||
uart3_last_reinit_tick = uart3_last_packet_tick;
|
||||
process_received_packet(rx_buffer, size);
|
||||
uart3_arm_rx_or_log("RxEventCallback");
|
||||
}
|
||||
|
||||
ISR_FAST void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) {
|
||||
uint32_t error = HAL_UART_GetError(huart);
|
||||
uint8_t uart_num =
|
||||
(huart == &huart2) ? 2 :
|
||||
(huart == &huart3) ? 3 :
|
||||
(huart == &huart5) ? 5 : 0;
|
||||
log_printf(LOG_ERR,
|
||||
"UART%u HAL error (ISR): raw=0x%08lx — RX may be corrupted until re-arm\n",
|
||||
uart_num, (unsigned long)error);
|
||||
uart3_log_hal_error(uart_num, error);
|
||||
(void)HAL_UART_AbortReceive(huart);
|
||||
(void)HAL_UART_AbortTransmit(huart);
|
||||
if (huart == &huart3) {
|
||||
uart3_tx_busy = 0;
|
||||
uart3_arm_rx_or_log("ErrorCallback");
|
||||
} else {
|
||||
SC_RecoverUartDma(huart);
|
||||
}
|
||||
}
|
||||
|
||||
void CCS_TxCpltCallback(UART_HandleTypeDef *huart) {
|
||||
if (huart != &huart3) {
|
||||
return;
|
||||
}
|
||||
uart3_tx_busy = 0;
|
||||
if (tx_pending_len > 0) {
|
||||
memcpy(tx_buffer, tx_pending_buffer, tx_pending_len);
|
||||
uart3_tx_busy = 1;
|
||||
if (HAL_UART_Transmit_DMA(&huart3, tx_buffer, tx_pending_len) != HAL_OK) {
|
||||
uart3_tx_busy = 0;
|
||||
CCS_LogUart3Error("UART3 TX DMA resend failed");
|
||||
}
|
||||
tx_pending_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CCS_SerialLoop(void) {
|
||||
static uint32_t tick;
|
||||
if ((int32_t)(HAL_GetTick() - tick) < 1) return;
|
||||
tick = HAL_GetTick();
|
||||
|
||||
static uint32_t replug_tick = 0;
|
||||
static uint32_t replug_watchdog_tick = 0;
|
||||
static uint32_t replug_watchdog1_tick = 0;
|
||||
@@ -77,15 +174,16 @@ void CCS_SerialLoop(void) {
|
||||
static uint32_t force_unlock_tick = 0;
|
||||
static uint32_t stop_tick = 0;
|
||||
|
||||
CCS_RxArm();
|
||||
CCS_UART3_Watchdog();
|
||||
|
||||
/* Read CP once per loop and use buffered value below. */
|
||||
cp_state_buffer = CP_GetState();
|
||||
if (CONN.connControl != CMD_NONE) {
|
||||
last_cmd = CONN.connControl;
|
||||
}
|
||||
|
||||
if (CONN.connControl == CMD_FORCE_UNLOCK) {
|
||||
if (force_unlock_tick == 0) {
|
||||
force_unlock_tick = HAL_GetTick();
|
||||
} else if ((HAL_GetTick() - force_unlock_tick) >= 10000) {
|
||||
} else if ((int32_t)(HAL_GetTick() - force_unlock_tick) >= 10000) {
|
||||
CONN.connControl = CMD_NONE;
|
||||
force_unlock_tick = 0;
|
||||
}
|
||||
@@ -96,7 +194,7 @@ void CCS_SerialLoop(void) {
|
||||
if (CONN.connControl == CMD_STOP) {
|
||||
if (stop_tick == 0) {
|
||||
stop_tick = HAL_GetTick();
|
||||
} else if ((HAL_GetTick() - stop_tick) >= 1000) {
|
||||
} else if ((int32_t)(HAL_GetTick() - stop_tick) >= 1000) {
|
||||
CONN.connControl = CMD_NONE;
|
||||
stop_tick = 0;
|
||||
}
|
||||
@@ -104,12 +202,8 @@ void CCS_SerialLoop(void) {
|
||||
stop_tick = 0;
|
||||
}
|
||||
|
||||
if (CONN.connControl != CMD_NONE) {
|
||||
last_cmd = CONN.connControl;
|
||||
}
|
||||
|
||||
if((HAL_GetTick() - last_cmd_sent) > CMD_INTERVAL){
|
||||
if ((HAL_GetTick() - last_state_sent) >= 200) {
|
||||
if((int32_t)(HAL_GetTick() - last_cmd_sent) > (int32_t)CMD_INTERVAL){
|
||||
if ((int32_t)(HAL_GetTick() - last_state_sent) >= 200) {
|
||||
send_state();
|
||||
last_state_sent = HAL_GetTick();
|
||||
}
|
||||
@@ -123,7 +217,7 @@ void CCS_SerialLoop(void) {
|
||||
if (((CONN.connControl == CMD_STOP) ||
|
||||
(CONN.connControl == CMD_FORCE_UNLOCK) ||
|
||||
(CONN.chargingError != CONN_NO_ERROR)) &&
|
||||
((HAL_GetTick() - last_stop_sent) > 1000)) {
|
||||
((int32_t)(HAL_GetTick() - last_stop_sent) > 1000)) {
|
||||
last_stop_sent = HAL_GetTick();
|
||||
log_printf(LOG_WARN, "Stopping charging...\n");
|
||||
if (CONN.connControl == CMD_FORCE_UNLOCK) {
|
||||
@@ -133,7 +227,7 @@ void CCS_SerialLoop(void) {
|
||||
}
|
||||
|
||||
if (((CCS_EvseState == FinishedEV) || (CCS_EvseState == FinishedEVSE)) &&
|
||||
((HAL_GetTick() - last_stop_sent) > 1000)) {
|
||||
((int32_t)(HAL_GetTick() - last_stop_sent) > 1000)) {
|
||||
last_stop_sent = HAL_GetTick();
|
||||
log_printf(LOG_WARN, "FinishedEV, stopping...\n");
|
||||
CCS_SendEmergencyStop();
|
||||
@@ -143,99 +237,109 @@ void CCS_SerialLoop(void) {
|
||||
(void)replug_watchdog_tick;
|
||||
(void)replug_watchdog1_tick;
|
||||
|
||||
uint8_t host_timed_out = (last_host_seen > 0 && (HAL_GetTick() - last_host_seen) > 5000u);
|
||||
uint8_t has_charging_error = 0;//(CONN.chargingError != CONN_NO_ERROR);
|
||||
uint8_t host_timeout_warn = (last_host_seen > 0u) && ((int32_t)(HAL_GetTick() - last_host_seen) > (int32_t)EVEREST_TIMEOUT_WARN_MS);
|
||||
uint8_t host_timeout_stop = (last_host_seen > 0u) && ((int32_t)(HAL_GetTick() - last_host_seen) > (int32_t)EVEREST_TIMEOUT_STOP_MS);
|
||||
uint8_t host_timed_out = host_timeout_stop;
|
||||
|
||||
if (host_timeout_warn && !everest_timeout_warn_latched) {
|
||||
log_printf(LOG_ERR, "Everest timeout\n");
|
||||
everest_timeout_warn_latched = 1;
|
||||
}
|
||||
|
||||
if (host_timeout_stop && !everest_timeout_stop_latched) {
|
||||
log_printf(LOG_ERR, "Everest timeout, stopping charging...\n");
|
||||
everest_timeout_stop_latched = 1;
|
||||
}
|
||||
|
||||
if (!host_timeout_warn) {
|
||||
everest_timeout_warn_latched = 0;
|
||||
everest_timeout_stop_latched = 0;
|
||||
}
|
||||
|
||||
everest_timed_out = host_timeout_stop;
|
||||
switch(CCS_ConnectorState){
|
||||
case CCS_UNKNOWN:
|
||||
RELAY_Write(RELAY_CP, 0);
|
||||
CONN_SetState(Unknown);
|
||||
if (config_initialized && !host_timed_out) {
|
||||
CCS_ConnectorState = CCS_UNPLUGGED;
|
||||
}
|
||||
break;
|
||||
case CCS_DISABLED:
|
||||
RELAY_Write(RELAY_CP, 0);
|
||||
CONN_SetState(Disabled);
|
||||
if ((CONN.chargingError == CONN_NO_ERROR) && !host_timed_out){
|
||||
CCS_ConnectorState = CCS_UNPLUGGED;
|
||||
}
|
||||
break;
|
||||
case CCS_UNPLUGGED:
|
||||
RELAY_Write(RELAY_CP, 1);
|
||||
CONN_SetState(Unplugged);
|
||||
if ((cp_state_buffer == EV_STATE_B_CONN_PREP) || (cp_state_buffer == EV_STATE_C_CONN_ACTIVE)){
|
||||
CCS_ConnectorState = CCS_AUTH_REQUIRED;
|
||||
}
|
||||
if (CONN.chargingError != CONN_NO_ERROR){
|
||||
log_printf(LOG_ERR, "Charging error %d, state -> disabled\n", CONN.chargingError);
|
||||
CCS_ConnectorState = CCS_DISABLED;
|
||||
}
|
||||
|
||||
break;
|
||||
case CCS_AUTH_REQUIRED:
|
||||
RELAY_Write(RELAY_CP, 1);
|
||||
CONN_SetState(AuthRequired);
|
||||
if(CONN.connControl == CMD_START){
|
||||
log_printf(LOG_INFO, "Charging permitted, start charging\n");
|
||||
CCS_ConnectorState = CCS_CONNECTED;
|
||||
}
|
||||
if (cp_state_buffer == EV_STATE_A_IDLE){
|
||||
log_printf(LOG_INFO, "Car unplugged\n");
|
||||
CCS_ConnectorState = CCS_UNPLUGGED;
|
||||
}
|
||||
break;
|
||||
case CCS_CONNECTED:
|
||||
RELAY_Write(RELAY_CP, 1);
|
||||
if(CCS_EvseState < Preparing) {
|
||||
CONN_SetState(Preparing);
|
||||
} else {
|
||||
CONN_SetState(CCS_EvseState);
|
||||
}
|
||||
if (cp_state_buffer == EV_STATE_A_IDLE){
|
||||
log_printf(LOG_INFO, "Car unplugged\n");
|
||||
CCS_ConnectorState = CCS_UNPLUGGED;
|
||||
}
|
||||
if(REPLUG > 0){
|
||||
log_printf(LOG_INFO, "Replugging...\n");
|
||||
CCS_ConnectorState = CCS_REPLUGGING;
|
||||
}
|
||||
break;
|
||||
case CCS_REPLUGGING:
|
||||
RELAY_Write(RELAY_CP, 0);
|
||||
CONN_SetState(Replugging);
|
||||
if((HAL_GetTick() - replug_tick) > 1000){
|
||||
replug_tick = HAL_GetTick();
|
||||
if(REPLUG > 0){
|
||||
if (REPLUG != 0xFF) REPLUG--;
|
||||
} else {
|
||||
log_printf(LOG_INFO, "Replugging finished, but car unplugged\n");
|
||||
case CCS_UNKNOWN:
|
||||
RELAY_Write(RELAY_CP, 0);
|
||||
CONN_SetState(Unknown);
|
||||
if (config_initialized && !host_timed_out) {
|
||||
CCS_ConnectorState = CCS_UNPLUGGED;
|
||||
}
|
||||
}
|
||||
|
||||
if(REPLUG == 0){
|
||||
if(cp_state_buffer == EV_STATE_B_CONN_PREP){
|
||||
log_printf(LOG_INFO, "Replugging finished, car plugged, state -> auth required\n");
|
||||
break;
|
||||
case CCS_DISABLED:
|
||||
RELAY_Write(RELAY_CP, 0);
|
||||
CONN_SetState(Disabled);
|
||||
if ((CONN.chargingError == CONN_NO_ERROR) && !host_timed_out){
|
||||
CCS_ConnectorState = CCS_UNPLUGGED;
|
||||
}
|
||||
break;
|
||||
case CCS_UNPLUGGED:
|
||||
RELAY_Write(RELAY_CP, 1);
|
||||
CONN_SetState(Unplugged);
|
||||
if ((cp_state_buffer == EV_STATE_B_CONN_PREP) || (cp_state_buffer == EV_STATE_C_CONN_ACTIVE)){
|
||||
CCS_ConnectorState = CCS_AUTH_REQUIRED;
|
||||
}
|
||||
}
|
||||
break;
|
||||
if (CONN.chargingError != CONN_NO_ERROR){
|
||||
log_printf(LOG_ERR, "Charging error %d, state -> disabled\n", CONN.chargingError);
|
||||
CCS_ConnectorState = CCS_DISABLED;
|
||||
}
|
||||
|
||||
break;
|
||||
case CCS_AUTH_REQUIRED:
|
||||
RELAY_Write(RELAY_CP, 1);
|
||||
CONN_SetState(AuthRequired);
|
||||
if(CONN.connControl == CMD_START){
|
||||
log_printf(LOG_INFO, "Charging permitted, start charging\n");
|
||||
CCS_ConnectorState = CCS_CONNECTED;
|
||||
}
|
||||
if (cp_state_buffer == EV_STATE_A_IDLE){
|
||||
log_printf(LOG_INFO, "Car unplugged\n");
|
||||
CCS_ConnectorState = CCS_UNPLUGGED;
|
||||
}
|
||||
break;
|
||||
case CCS_CONNECTED:
|
||||
RELAY_Write(RELAY_CP, 1);
|
||||
if((CCS_EvseState < Preparing) || (CCS_EvseState == AuthRequired)) {
|
||||
CONN_SetState(Preparing);
|
||||
} else {
|
||||
CONN_SetState(CCS_EvseState);
|
||||
}
|
||||
if (cp_state_buffer == EV_STATE_A_IDLE){
|
||||
log_printf(LOG_INFO, "Car unplugged\n");
|
||||
CCS_ConnectorState = CCS_UNPLUGGED;
|
||||
}
|
||||
if(REPLUG > 0){
|
||||
log_printf(LOG_INFO, "Replugging...\n");
|
||||
CCS_ConnectorState = CCS_REPLUGGING;
|
||||
}
|
||||
break;
|
||||
case CCS_REPLUGGING:
|
||||
RELAY_Write(RELAY_CP, 0);
|
||||
CONN_SetState(Replugging);
|
||||
if((int32_t)(HAL_GetTick() - replug_tick) > 1000){
|
||||
replug_tick = HAL_GetTick();
|
||||
if(REPLUG > 0){
|
||||
if (REPLUG != 0xFF) REPLUG--;
|
||||
} else {
|
||||
log_printf(LOG_INFO, "Replugging finished, but car unplugged\n");
|
||||
CCS_ConnectorState = CCS_UNPLUGGED;
|
||||
}
|
||||
}
|
||||
|
||||
if(REPLUG == 0){
|
||||
if(cp_state_buffer == EV_STATE_B_CONN_PREP){
|
||||
log_printf(LOG_INFO, "Replugging finished, car plugged, state -> auth required\n");
|
||||
CCS_ConnectorState = CCS_AUTH_REQUIRED;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (has_charging_error &&
|
||||
CCS_ConnectorState != CCS_DISABLED &&
|
||||
CCS_ConnectorState != CCS_UNKNOWN) {
|
||||
log_printf(LOG_ERR, "Charging error %d, state -> disabled\n", CONN.chargingError);
|
||||
CCS_ConnectorState = CCS_DISABLED;
|
||||
}
|
||||
|
||||
if (host_timed_out) {
|
||||
// 10s timeout: enforce safe-state until host communication recovers.
|
||||
if (host_timeout_stop) {
|
||||
CONN.EnableOutput = 0;
|
||||
CCS_EvseState = Unknown;
|
||||
CP_SetDuty(100);
|
||||
if (CCS_ConnectorState != CCS_DISABLED && CCS_ConnectorState != CCS_UNKNOWN) {
|
||||
log_printf(LOG_ERR, "Everest timeout\n");
|
||||
CCS_ConnectorState = CCS_DISABLED;
|
||||
}
|
||||
} else {
|
||||
@@ -266,11 +370,14 @@ void CCS_Init(void){
|
||||
CCS_MaxLoad.maxCurrent = PSU_MAX_CURRENT*10; //100A
|
||||
CCS_MaxLoad.minCurrent = PSU_MIN_CURRENT*10; //1A
|
||||
CCS_MaxLoad.maxPower = PSU_MAX_POWER; //30000W
|
||||
uart3_last_packet_tick = HAL_GetTick();
|
||||
uart3_last_reinit_tick = uart3_last_packet_tick;
|
||||
uart3_arm_rx_or_log("Init");
|
||||
CCS_SendResetReason();
|
||||
log_printf(LOG_INFO, "CCS init\n");
|
||||
}
|
||||
|
||||
static uint16_t crc16_ibm(const uint8_t* data, uint16_t length) {
|
||||
ISR_FAST static uint16_t crc16_ibm(const uint8_t* data, uint16_t length) {
|
||||
uint16_t crc = 0xFFFFu;
|
||||
for (uint16_t i = 0; i < length; i++) {
|
||||
crc ^= data[i];
|
||||
@@ -304,7 +411,16 @@ static uint16_t CCS_BuildPacket(uint8_t cmd, const void* payload, uint16_t paylo
|
||||
static void CCS_SendPacket(uint8_t cmd, const void* payload, uint16_t payload_len) {
|
||||
uint16_t len = CCS_BuildPacket(cmd, payload, payload_len, tx_buffer, sizeof(tx_buffer));
|
||||
if (len > 0) {
|
||||
HAL_UART_Transmit(&huart3, tx_buffer, len, 1000);
|
||||
if (uart3_tx_busy) {
|
||||
memcpy(tx_pending_buffer, tx_buffer, len);
|
||||
tx_pending_len = len;
|
||||
} else {
|
||||
uart3_tx_busy = 1;
|
||||
if (HAL_UART_Transmit_DMA(&huart3, tx_buffer, len) != HAL_OK) {
|
||||
uart3_tx_busy = 0;
|
||||
CCS_LogUart3Error("UART3 TX DMA start failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
last_cmd_sent = HAL_GetTick();
|
||||
}
|
||||
@@ -366,7 +482,7 @@ static void send_state(void) {
|
||||
CCS_SendPacket(CMD_M2E_STATE, &CCS_State, sizeof(CCS_State));
|
||||
}
|
||||
|
||||
static uint16_t expected_payload_len(uint8_t cmd) {
|
||||
ISR_FAST static uint16_t expected_payload_len(uint8_t cmd) {
|
||||
switch (cmd) {
|
||||
case CMD_E2M_PWM_DUTY: return sizeof(e2m_pwm_duty_t);
|
||||
case CMD_E2M_ENABLE_OUTPUT: return sizeof(e2m_enable_output_t);
|
||||
@@ -382,9 +498,12 @@ static uint16_t expected_payload_len(uint8_t cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
static void apply_command(uint8_t cmd, const uint8_t* payload, uint16_t payload_len) {
|
||||
ISR_FAST static void apply_command(uint8_t cmd, const uint8_t* payload, uint16_t payload_len) {
|
||||
(void)payload_len;
|
||||
last_host_seen = HAL_GetTick();
|
||||
everest_timed_out = 0;
|
||||
everest_timeout_warn_latched = 0;
|
||||
everest_timeout_stop_latched = 0;
|
||||
switch (cmd) {
|
||||
case CMD_E2M_PWM_DUTY: {
|
||||
const e2m_pwm_duty_t* p = (const e2m_pwm_duty_t*)payload;
|
||||
@@ -405,9 +524,9 @@ static void apply_command(uint8_t cmd, const uint8_t* payload, uint16_t payload_
|
||||
const e2m_reset_t* p = (const e2m_reset_t*)payload;
|
||||
if (p->reset) {
|
||||
log_printf(LOG_WARN, "Everest reset command\n");
|
||||
CCS_SendResetReason();
|
||||
HAL_Delay(10);
|
||||
NVIC_SystemReset();
|
||||
// CCS_SendResetReason();
|
||||
// HAL_Delay(10);
|
||||
// NVIC_SystemReset();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -454,32 +573,54 @@ static void apply_command(uint8_t cmd, const uint8_t* payload, uint16_t payload_
|
||||
break;
|
||||
}
|
||||
default:
|
||||
log_printf(LOG_WARN,
|
||||
"UART3 RX warn: cmd 0x%02x CRC/len OK but no switch case (expected_payload vs apply_command)\n",
|
||||
cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t process_received_packet(const uint8_t* packet, uint16_t packet_len) {
|
||||
if (packet_len < 3) return 0;
|
||||
ISR_FAST static uint8_t process_received_packet(const uint8_t* packet, uint16_t packet_len) {
|
||||
if (packet_len < 3u) {
|
||||
if (packet_len == 0u) {
|
||||
log_printf(LOG_WARN, "UART3 RX drop: too_short len=0 (empty chunk)\n");
|
||||
} else if (packet_len == 1u) {
|
||||
log_printf(LOG_WARN, "UART3 RX drop: too_short len=1 b0=0x%02x\n", packet[0]);
|
||||
} else {
|
||||
log_printf(LOG_WARN, "UART3 RX drop: too_short len=2 b0=0x%02x b1=0x%02x\n",
|
||||
packet[0], packet[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t cmd = packet[0];
|
||||
uint16_t payload_len = (uint16_t)(packet_len - 3);
|
||||
uint16_t payload_len = (uint16_t)(packet_len - 3u);
|
||||
|
||||
uint16_t received_crc = (uint16_t)packet[packet_len - 2u] |
|
||||
(uint16_t)packet[packet_len - 1u] << 8;
|
||||
|
||||
uint16_t calculated_crc = crc16_ibm(packet, (uint16_t)(1 + payload_len));
|
||||
uint16_t calculated_crc = crc16_ibm(packet, (uint16_t)(1u + payload_len));
|
||||
if (received_crc != calculated_crc) {
|
||||
log_printf(LOG_ERR, "Packet CRC error\n");
|
||||
log_printf(LOG_ERR,
|
||||
"UART3 RX drop: crc_mismatch cmd=0x%02x total_len=%u payload_len=%u "
|
||||
"crc_rx=0x%04x crc_calc=0x%04x\n",
|
||||
cmd, (unsigned)packet_len, (unsigned)payload_len,
|
||||
(unsigned)received_crc, (unsigned)calculated_crc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t expected_len = expected_payload_len(cmd);
|
||||
if (expected_len == 0xFFFF) {
|
||||
log_printf(LOG_WARN, "Unknown cmd 0x%02x\n", cmd);
|
||||
if (expected_len == 0xFFFFu) {
|
||||
log_printf(LOG_WARN,
|
||||
"UART3 RX drop: unknown_cmd cmd=0x%02x total_len=%u payload_len=%u\n",
|
||||
cmd, (unsigned)packet_len, (unsigned)payload_len);
|
||||
return 0;
|
||||
}
|
||||
if (expected_len != payload_len) {
|
||||
log_printf(LOG_ERR, "Packet len mismatch cmd=0x%02x\n", cmd);
|
||||
log_printf(LOG_ERR,
|
||||
"UART3 RX drop: len_mismatch cmd=0x%02x expected_payload=%u got_payload=%u "
|
||||
"total_len=%u\n",
|
||||
cmd, (unsigned)expected_len, (unsigned)payload_len, (unsigned)packet_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -492,3 +633,25 @@ static uint8_t process_received_packet(const uint8_t* packet, uint16_t packet_le
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void CCS_UART3_Watchdog(void) {
|
||||
const int32_t since_last_packet = (int32_t)(HAL_GetTick() - uart3_last_packet_tick);
|
||||
const int32_t since_last_reinit = (int32_t)(HAL_GetTick() - uart3_last_reinit_tick);
|
||||
|
||||
if ((since_last_packet >= (int32_t)UART3_REINIT_TIMEOUT_MS) &&
|
||||
(since_last_reinit >= (int32_t)UART3_REINIT_TIMEOUT_MS) &&
|
||||
(huart3.RxState == HAL_UART_STATE_READY)) {
|
||||
uart3_arm_rx_or_log("Watchdog");
|
||||
CCS_LogUart3Error("UART3 watchdog rearm");
|
||||
uart3_last_reinit_tick = HAL_GetTick();
|
||||
}
|
||||
}
|
||||
|
||||
static void CCS_LogUart3Error(const char *tag) {
|
||||
log_printf(LOG_ERR, "%s: err=0x%08lx g=%lu rx=%lu tx_busy=%u\n",
|
||||
tag,
|
||||
(unsigned long)HAL_UART_GetError(&huart3),
|
||||
(unsigned long)huart3.gState,
|
||||
(unsigned long)huart3.RxState,
|
||||
(unsigned)uart3_tx_busy);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user