isolation support
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user