isolation support

This commit is contained in:
2026-03-11 16:29:13 +03:00
parent 7893e7aa0c
commit 0e9b352db7
16 changed files with 25253 additions and 25068 deletions

View File

@@ -8,6 +8,9 @@
#define USE_WEB_INTERFACE
// Команды от ПК к устройству
// Пакет статуса изоляции от отдельного блока по одностороннему UART
#define CMD_ISOLATION_STATUS 0x01
#define CMD_GET_STATUS 0x40
#define CMD_GET_LOG 0x50
@@ -56,6 +59,19 @@ typedef struct {
void* argument;
} ReceivedCommand_t;
typedef enum {
SC_SOURCE_UART2 = 0,
SC_SOURCE_UART5 = 1,
} SC_Source_t;
typedef struct __attribute__((packed)) {
uint8_t isolationStatus;
uint16_t isolationResistance;
int16_t voltageHigh;
int16_t voltageLow;
int16_t voltageComm;
} IsolationStatusPacket_t;
typedef struct __attribute__((packed)) {
CONN_State_t connState;
@@ -160,5 +176,7 @@ extern void SC_CommandHandler(ReceivedCommand_t* cmd);
extern SerialControl_t serial_control;
extern StatusPacket_t statusPacket;
extern InfoPacket_t infoPacket;
extern IsolationStatusPacket_t ISO;
extern volatile SC_Source_t g_sc_command_source;
#endif // SERIALCONTROL_H

View File

@@ -59,6 +59,7 @@ void CAN1_RX0_IRQHandler(void);
void USART1_IRQHandler(void);
void USART2_IRQHandler(void);
void USART3_IRQHandler(void);
void UART5_IRQHandler(void);
void CAN2_TX_IRQHandler(void);
void CAN2_RX1_IRQHandler(void);
/* USER CODE BEGIN EFP */

View File

@@ -246,6 +246,17 @@ void GBT_ChargerTask(){
if(GBT_StateTick()>5000){
GBT_SwitchState(GBT_S4_WAIT_PSU_OFF);
}
if(ISO.isolationResistance < (ISO.voltageComm/2)){ // *100/1000
CONN.chargingError = CONN_ERR_INSULATION;
log_printf(LOG_WARN, "Isolation warning\n");
} // 500 Ohm/V
if(ISO.isolationResistance < (ISO.voltageComm/10)){ // *100/1000
CONN.chargingError = CONN_ERR_INSULATION;
log_printf(LOG_WARN, "Current leakage, insulation error, stopping...\n");
GBT_StopEVSE(GBT_CST_OTHERFALUT);
} // 100 Ohm/V
break;
case GBT_S4_WAIT_PSU_OFF:
@@ -401,9 +412,14 @@ void GBT_ChargerTask(){
log_printf(LOG_WARN, "Connector overheat %d %d, stopping...\n", GBT_ReadTemp(0), GBT_ReadTemp(1));
break;
}
if(ISO.isolationResistance < (ISO.voltageComm/10)){ // *100/1000
CONN.chargingError = CONN_ERR_INSULATION;
log_printf(LOG_WARN, "Current leakage, insulation error, stopping...\n");
} // 100 Ohm/V
if(CONN.chargingError != CONN_NO_ERROR){ // --> Suspend EVSE
GBT_StopEVSE(GBT_CST_OTHERFALUT);
// log_printf(LOG_WARN, "Isolation error\n");
}
//GBT_ChargerCurrentStatus.chargingPermissible = 0b1111111111111100;//NOT PERMITTED

View File

@@ -1,18 +1,19 @@
#include "serial_control.h"
#include "crc.h"
#include "usart.h"
#include "board.h"
// Приватные функции
uint32_t revbit(uint32_t uData);
uint32_t CRC32_ForBytes(uint8_t *pData, uint32_t uLen);
uint32_t calculate_crc32(const uint8_t* data, uint16_t length);
uint16_t encode_packet(const uint8_t* payload, uint16_t payload_len, uint8_t* output, uint8_t response_code);
uint8_t process_received_packet(const uint8_t* packet_data, uint16_t packet_len);
static uint32_t calculate_crc32(const uint8_t* data, uint16_t length);
static uint16_t encode_packet(const uint8_t* payload, uint16_t payload_len, uint8_t* output, uint8_t response_code);
static uint8_t parse_packet(const uint8_t* packet_data, uint16_t packet_len, ReceivedCommand_t* out_cmd);
static uint8_t process_received_packet(SerialControl_t *ctx, const uint8_t* packet_data, uint16_t packet_len);
uint8_t test_crc_invalid = 0;
SerialControl_t serial_control;
// Контекст для приема пакетов по UART5 (однонаправленный UART)
static SerialControl_t serial_iso;
volatile SC_Source_t g_sc_command_source = SC_SOURCE_UART2;
StatusPacket_t statusPacket = {
.SOC = 0,
@@ -69,12 +70,14 @@ extern void SC_CommandHandler(ReceivedCommand_t* cmd);
void SC_Init() {
// Обнуляем структуру
memset(&serial_control, 0, sizeof(SerialControl_t));
memset(&serial_iso, 0, sizeof(serial_iso));
}
void SC_Task() {
// Запуск приема в режиме прерывания с ожиданием idle
if((huart2.RxState == HAL_UART_STATE_READY) && (serial_control.command_ready == 0)) HAL_UARTEx_ReceiveToIdle_IT(&huart2, serial_control.rx_buffer, MAX_RX_BUFFER_SIZE - 1);
if((huart5.RxState == HAL_UART_STATE_READY)) HAL_UARTEx_ReceiveToIdle_IT(&huart5, serial_iso.rx_buffer, MAX_RX_BUFFER_SIZE - 1);
// Проверка таймаута отправки пакета (больше 100 мс)
if (huart2.gState == HAL_UART_STATE_BUSY_TX && serial_control.tx_tick != 0) {
if ((HAL_GetTick() - serial_control.tx_tick) > 100) {
@@ -97,9 +100,17 @@ void SC_Task() {
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {
if (huart->Instance == huart2.Instance) {
if(!process_received_packet(serial_control.rx_buffer, Size)){
if(!process_received_packet(&serial_control, serial_control.rx_buffer, Size)){
SC_SendPacket(NULL, 0, RESP_INVALID);
}
g_sc_command_source = SC_SOURCE_UART2;
HAL_UARTEx_ReceiveToIdle_IT(&huart2, serial_control.rx_buffer, MAX_RX_BUFFER_SIZE - 1);
} else if (huart->Instance == huart5.Instance) {
if (process_received_packet(&serial_iso, serial_iso.rx_buffer, Size)) {
g_sc_command_source = SC_SOURCE_UART5;
SC_CommandHandler((ReceivedCommand_t*)&serial_iso.received_command);
}
HAL_UARTEx_ReceiveToIdle_IT(&huart5, serial_iso.rx_buffer, MAX_RX_BUFFER_SIZE - 1);
}
}
@@ -111,54 +122,26 @@ void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
}
// Приватные функции реализации
uint32_t revbit(uint32_t uData) {
uint32_t uRevData = 0, uIndex = 0;
uRevData |= ((uData >> uIndex) & 0x01);
for(uIndex = 1; uIndex < 32; uIndex++) {
uRevData <<= 1;
uRevData |= ((uData >> uIndex) & 0x01);
}
return uRevData;
}
uint32_t CRC32_ForBytes(uint8_t *pData, uint32_t uLen) {
uint32_t uIndex = 0, uData = 0, i;
uIndex = uLen >> 2;
// Полностью программная реализация CRC-32 (полином CRC32_POLYNOMIAL, порядок little-endian)
static uint32_t calculate_crc32(const uint8_t* data, uint16_t length) {
uint32_t crc = 0xFFFFFFFFu;
SERIAL_PROTOCOL_CRC_CLK_ENABLE();
__HAL_CRC_DR_RESET(&hcrc);
while(uIndex--) {
((uint8_t *) & uData)[0] = pData[0];
((uint8_t *) & uData)[1] = pData[1];
((uint8_t *) & uData)[2] = pData[2];
((uint8_t *) & uData)[3] = pData[3];
pData += 4;
uData = revbit(uData);
hcrc.Instance->DR = uData;
}
uData = revbit(hcrc.Instance->DR);
uIndex = uLen & 0x03;
while(uIndex--) {
uData ^= (uint32_t) * pData++;
for(i = 0; i < 8; i++)
if (uData & 0x1)
uData = (uData >> 1) ^ CRC32_POLYNOMIAL;
else
uData >>= 1;
for (uint16_t i = 0; i < length; i++) {
crc ^= data[i];
for (uint8_t bit = 0; bit < 8; bit++) {
if (crc & 0x1u) {
crc = (crc >> 1) ^ CRC32_POLYNOMIAL;
} else {
crc >>= 1;
}
}
}
SERIAL_PROTOCOL_CRC_CLK_DISABLE();
return uData ^ 0xFFFFFFFF;
return crc ^ 0xFFFFFFFFu;
}
uint32_t calculate_crc32(const uint8_t* data, uint16_t length) {
return CRC32_ForBytes((uint8_t*)data, (uint32_t)length);
}
uint16_t encode_packet(const uint8_t* payload, uint16_t payload_len, uint8_t* output, uint8_t response_code) {
static uint16_t encode_packet(const uint8_t* payload, uint16_t payload_len, uint8_t* output, uint8_t response_code) {
uint16_t out_index = 0;
output[out_index++] = response_code;
@@ -208,7 +191,7 @@ void SC_SendPacket(const uint8_t* payload, uint16_t payload_len, uint8_t respons
}
}
uint8_t process_received_packet(const uint8_t* packet_data, uint16_t packet_len) {
static uint8_t parse_packet(const uint8_t* packet_data, uint16_t packet_len, ReceivedCommand_t* out_cmd) {
// if (test_crc_invalid && (packet_data[1] != CMD_GET_STATUS)) {
// test_crc_invalid--;
// return 0;
@@ -221,23 +204,32 @@ uint8_t process_received_packet(const uint8_t* packet_data, uint16_t packet_len)
if (packet_len > MAX_RX_BUFFER_SIZE) return 0;
uint16_t payload_length = packet_len - 4;
// Извлекаем принятую CRC (последние 4 байта, little-endian)
uint32_t received_checksum =
((uint32_t)packet_data[payload_length] << 0) |
((uint32_t)packet_data[payload_length + 1] << 8) |
((uint32_t)packet_data[payload_length + 2] << 16) |
((uint32_t)packet_data[payload_length + 3] << 24);
// Вычисляем CRC для полезной нагрузки
uint32_t calculated_checksum = calculate_crc32(packet_data, payload_length);
if (received_checksum != calculated_checksum) return 0; // CRC не совпадает
serial_control.received_command.argument = &packet_data[1];
serial_control.received_command.command = packet_data[0];
serial_control.received_command.argument_length = payload_length - 1;
serial_control.command_ready = 1;
out_cmd->argument = (void *)&packet_data[1];
out_cmd->command = packet_data[0];
out_cmd->argument_length = (uint8_t)(payload_length - 1);
return 1;
}
static uint8_t process_received_packet(SerialControl_t *ctx, const uint8_t* packet_data, uint16_t packet_len) {
if (!parse_packet(packet_data, packet_len, (ReceivedCommand_t *)&ctx->received_command)) {
return 0;
}
ctx->command_ready = 1;
return 1;
}

View File

@@ -1,6 +1,5 @@
#include "serial_control.h"
#include "charger_gbt.h"
#include "crc.h"
#include "usart.h"
#include "charger_control.h"
#include "charger_gbt.h"
@@ -11,6 +10,12 @@
#ifdef USE_WEB_INTERFACE
extern uint8_t GBT_BAT_STAT_recv;
extern volatile SC_Source_t g_sc_command_source;
IsolationStatusPacket_t ISO = {
.isolationResistance = 0xFFFF
};
uint8_t config_initialized = 0;
ConfigBlock_t config = {
@@ -94,7 +99,20 @@ void SC_CommandHandler(ReceivedCommand_t* cmd) {
// 3. Выполняем программный сброс
NVIC_SystemReset();
return; // Сюда код уже не дойдет, но для компилятора нужно
case CMD_ISOLATION_STATUS:
if (cmd->argument_length == sizeof(IsolationStatusPacket_t)) {
memcpy(&ISO, cmd->argument, sizeof(IsolationStatusPacket_t));
// Для однонаправленного UART5 ответ не нужен
if (g_sc_command_source == SC_SOURCE_UART5) {
return;
}
response_code = RESP_SUCCESS;
break;
}
response_code = RESP_FAILED;
break;
default:
// Неизвестная команда
response_code = RESP_FAILED;

View File

@@ -57,6 +57,7 @@
/* External variables --------------------------------------------------------*/
extern CAN_HandleTypeDef hcan1;
extern CAN_HandleTypeDef hcan2;
extern UART_HandleTypeDef huart5;
extern UART_HandleTypeDef huart1;
extern UART_HandleTypeDef huart2;
extern UART_HandleTypeDef huart3;
@@ -258,6 +259,20 @@ void USART3_IRQHandler(void)
/* USER CODE END USART3_IRQn 1 */
}
/**
* @brief This function handles UART5 global interrupt.
*/
void UART5_IRQHandler(void)
{
/* USER CODE BEGIN UART5_IRQn 0 */
/* USER CODE END UART5_IRQn 0 */
HAL_UART_IRQHandler(&huart5);
/* USER CODE BEGIN UART5_IRQn 1 */
/* USER CODE END UART5_IRQn 1 */
}
/**
* @brief This function handles CAN2 TX interrupt.
*/

View File

@@ -41,7 +41,7 @@ void MX_UART5_Init(void)
/* USER CODE END UART5_Init 1 */
huart5.Instance = UART5;
huart5.Init.BaudRate = 115200;
huart5.Init.BaudRate = 9600;
huart5.Init.WordLength = UART_WORDLENGTH_8B;
huart5.Init.StopBits = UART_STOPBITS_1;
huart5.Init.Parity = UART_PARITY_NONE;
@@ -173,6 +173,9 @@ void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* UART5 interrupt Init */
HAL_NVIC_SetPriority(UART5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(UART5_IRQn);
/* USER CODE BEGIN UART5_MspInit 1 */
/* USER CODE END UART5_MspInit 1 */
@@ -292,6 +295,8 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
HAL_GPIO_DeInit(GPIOD, GPIO_PIN_2);
/* UART5 interrupt Deinit */
HAL_NVIC_DisableIRQ(UART5_IRQn);
/* USER CODE BEGIN UART5_MspDeInit 1 */
/* USER CODE END UART5_MspDeInit 1 */