Files
CCSModuleSW30Web/Core/Src/serial_control.c

244 lines
8.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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);
uint8_t test_crc_invalid = 0;
SerialControl_t serial_control;
StatusPacket_t statusPacket = {
.SOC = 0,
.Energy = 0,
.RequestedVoltage = 0,
.RequestedCurrent = 0,
.MeasuredVoltage = 0,
.MeasuredCurrent = 0,
.outputEnabled = 0,
.chargingError = 0,
.connState = 0,
.chargingElapsedTimeMin = 0,
.chargingElapsedTimeSec = 0,
.estimatedRemainingChargingTime = 0,
.relayAC = 0,
.relayDC = 0,
.relayAUX = 0,
.lockState = 0,
.evInfoAvailable = 0,
.psuOnline = 0,
.tempConnector0 = 0,
.tempConnector1 = 0,
.tempAmbient = 0,
.tempBatteryMax = 0,
.tempBatteryMin = 0,
.highestVoltageOfBatteryCell = 0,
.batteryStatus = 0,
.phaseVoltageAB = 0,
.phaseVoltageBC = 0,
.phaseVoltageCA = 0,
};
InfoPacket_t infoPacket = {
.serialNumber = 0,
.boardVersion = 0,
.stationType = 0,
.fw_version_major = 0,
.fw_version_minor = 0,
.fw_version_patch = 0,
};
void ReadVersion(){
infoPacket.serialNumber = InfoBlock->serialNumber;
infoPacket.boardVersion = InfoBlock->boardVersion;
infoPacket.stationType = InfoBlock->stationType;
infoPacket.fw_version_major = FW_VERSION_MAJOR;
infoPacket.fw_version_minor = FW_VERSION_MINOR;
infoPacket.fw_version_patch = FW_VERSION_PATCH;
}
// Внешняя функция обработки команд (определена в serial_handler.c)
extern void SC_CommandHandler(ReceivedCommand_t* cmd);
void SC_Init() {
// Обнуляем структуру
memset(&serial_control, 0, sizeof(SerialControl_t));
}
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);
// Проверка таймаута отправки пакета (больше 100 мс)
if (huart2.gState == HAL_UART_STATE_BUSY_TX && serial_control.tx_tick != 0) {
if ((HAL_GetTick() - serial_control.tx_tick) > 100) {
// Таймаут: принудительно сбрасываем передачу
HAL_UART_Abort_IT(&huart2);
// Выключаем DIR при сбросе передачи
HAL_GPIO_WritePin(USART2_DIR_GPIO_Port, USART2_DIR_Pin, GPIO_PIN_RESET);
serial_control.tx_tick = 0; // Сбрасываем tick
}
}
// Проверка наличия принятой команды для обработки
if (serial_control.command_ready && (huart2.gState != HAL_UART_STATE_BUSY_TX)) {
// HAL_Delay(2);
SC_CommandHandler(&serial_control.received_command);
HAL_UARTEx_ReceiveToIdle_IT(&huart2, serial_control.rx_buffer, MAX_RX_BUFFER_SIZE - 1);
serial_control.command_ready = 0; // Сбрасываем флаг
}
}
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {
if (huart->Instance == huart2.Instance) {
if(!process_received_packet(serial_control.rx_buffer, Size)){
SC_SendPacket(NULL, 0, RESP_INVALID);
}
}
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == huart2.Instance) {
HAL_GPIO_WritePin(USART2_DIR_GPIO_Port, USART2_DIR_Pin, GPIO_PIN_RESET);
serial_control.tx_tick = 0;
}
}
// Приватные функции реализации
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;
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;
}
SERIAL_PROTOCOL_CRC_CLK_DISABLE();
return uData ^ 0xFFFFFFFF;
}
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) {
uint16_t out_index = 0;
output[out_index++] = response_code;
if (payload != NULL) {
// Просто копируем полезную нагрузку без какого‑либо экранирования
for (uint16_t i = 0; i < payload_len; i++) {
output[out_index++] = payload[i];
// Проверка переполнения
if (out_index >= MAX_TX_BUFFER_SIZE - 5) { // 4 байта CRC + END_BYTE
return 0;
}
}
}
// Вычисляем CRC для всего содержимого (код ответа + полезная нагрузка)
uint32_t crc = calculate_crc32(output, out_index);
uint8_t* crc_bytes = (uint8_t*)&crc;
// Добавляем CRC без экранирования
for (int i = 0; i < 4; i++) {
output[out_index++] = crc_bytes[i];
if (out_index >= MAX_TX_BUFFER_SIZE - 1) { // место для END_BYTE
return 0;
}
}
return out_index;
}
void SC_SendPacket(const uint8_t* payload, uint16_t payload_len, uint8_t response_code) {
uint16_t packet_len = encode_packet(payload, payload_len, serial_control.tx_buffer, response_code);
if (packet_len > 0) {
if (huart2.gState == HAL_UART_STATE_BUSY_TX) {
HAL_UART_Abort_IT(&huart2);
HAL_GPIO_WritePin(USART2_DIR_GPIO_Port, USART2_DIR_Pin, GPIO_PIN_RESET);
}
HAL_GPIO_WritePin(USART2_DIR_GPIO_Port, USART2_DIR_Pin, GPIO_PIN_SET);
HAL_UART_Transmit_IT(&huart2, serial_control.tx_buffer, packet_len);
serial_control.tx_tick = HAL_GetTick();
}
}
uint8_t process_received_packet(const uint8_t* packet_data, uint16_t packet_len) {
// if (test_crc_invalid && (packet_data[1] != CMD_GET_STATUS)) {
// test_crc_invalid--;
// return 0;
// }else{
// test_crc_invalid = 5;
// }
// Минимальный размер: 1 байт команды + 4 байта CRC
if (packet_len < 5) return 0;
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;
return 1;
}