#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; }