This commit is contained in:
cfif 2026-06-02 16:58:27 +03:00
parent 1ee101a5c9
commit d8261599fe
2 changed files with 214 additions and 77 deletions

View File

@ -29,6 +29,7 @@ typedef struct {
lin_frame_t rxFrame;
osMessageQueueId_t rxDataQueue;
osMessageQueueId_t rxDataSnifferQueue;
bool linTxInProgress; // Флаг передачи
} tSerialPortLinArtery;

View File

@ -19,8 +19,8 @@ void vSerialPortLinInit(
) {
env->uart = uart;
env->linLastByteTime = 10;
env->linFrameTimeoutMs = 10;
env->linLastByteTime = 2;
env->linFrameTimeoutMs = 2;
usart_reset(uart);
@ -45,7 +45,7 @@ void vSerialPortLinInit(
// Включаем прерывание по break frame
usart_interrupt_enable(uart, USART_BF_INT, TRUE);
usart_interrupt_enable(uart, USART_RDBF_INT, TRUE);
// usart_interrupt_enable(uart, USART_IDLE_INT, TRUE);
usart_interrupt_enable(uart, USART_IDLE_INT, TRUE);
NVIC_EnableIRQ(irq);
NVIC_SetPriority(irq, irqPriority);
@ -122,68 +122,11 @@ static uint8_t LIN_CalcParity(uint8_t id) {
return (p1 << 7) | (p0 << 6);
}
// Измененный обработчик прерываний (без IDLE):
void SerialPort_IrqProcessing_UartLin(tSerialPortLinArtery *env) {
// 1. Break frame detection
if (usart_flag_get(env->uart, USART_BFF_FLAG)) {
usart_flag_clear(env->uart, USART_BFF_FLAG);
usart_data_receive(env->uart);
env->linFrameStarted = true;
env->linByteCount = 0;
env->linLastByteTime = SystemGetMs(); // Запоминаем время
env->rxFrame.event = LIN_RECV_BREAK_FIELD_OK;
return;
}
// 2. Receive data (без IDLE)
if (usart_flag_get(env->uart, USART_RDBF_FLAG)) {
uint8_t data = usart_data_receive(env->uart);
if (env->linFrameStarted && (env->linByteCount < sizeof(env->linBuffer))) {
env->linBuffer[env->linByteCount] = data;
env->linByteCount++;
env->linLastByteTime = SystemGetMs(); // Обновляем время
} else {
if (env->linFrameStarted) {
env->rxFrame.event = LIN_RX_OVERRUN;
osMessageQueuePut(env->rxDataQueue, &env->rxFrame, 0, 0);
env->linFrameStarted = false;
}
}
}
// 3. Error handling
if (usart_flag_get(env->uart, USART_FERR_FLAG)) {
usart_flag_clear(env->uart, USART_FERR_FLAG);
usart_data_receive(env->uart);
if (env->linFrameStarted) {
env->rxFrame.event = LIN_FRAME_ERROR;
osMessageQueuePut(env->rxDataQueue, &env->rxFrame, 0, 0);
env->linFrameStarted = false;
}
}
if (usart_flag_get(env->uart, USART_ROERR_FLAG)) {
usart_flag_clear(env->uart, USART_ROERR_FLAG);
usart_data_receive(env->uart);
if (env->linFrameStarted) {
env->rxFrame.event = LIN_RX_OVERRUN;
osMessageQueuePut(env->rxDataQueue, &env->rxFrame, 0, 0);
env->linFrameStarted = false;
}
}
}
extern const uint8_t DRS_SENSON_ADR_Stat[8];
// Выделенная функция обработки кадра
static void LIN_ProcessReceivedFrame(tSerialPortLinArtery *env) {
static void LIN_ProcessReceivedFrame(tSerialPortLinArtery *env, bool isHeader) {
// Проверка sync field
if (env->linBuffer[0] != 0x55) {
env->rxFrame.event = LIN_SYNC_ERROR;
@ -202,6 +145,14 @@ static void LIN_ProcessReceivedFrame(tSerialPortLinArtery *env) {
return;
}
if (isHeader) {
env->rxFrame.id = id;
env->rxFrame.dataLen = 0;
env->rxFrame.event = LIN_RX_COMPLETED;
osMessageQueuePut(env->rxDataQueue, &env->rxFrame, 0, 0);
}
env->rxFrame.id = id;
env->rxFrame.dataLen = env->linByteCount - 3;
@ -233,10 +184,121 @@ static void LIN_ProcessReceivedFrame(tSerialPortLinArtery *env) {
osMessageQueuePut(env->rxDataQueue, &env->rxFrame, 0, 0);
}
// Измененный обработчик прерываний (без IDLE):
void SerialPort_IrqProcessing_UartLin(tSerialPortLinArtery *env) {
// ИГНОРИРУЕМ ВСЕ ПРЕРЫВАНИЯ ВО ВРЕМЯ ПЕРЕДАЧИ
if (env->linTxInProgress) {
// Просто очищаем флаги, но не обрабатываем
if (usart_flag_get(env->uart, USART_BFF_FLAG)) {
usart_flag_clear(env->uart, USART_BFF_FLAG);
usart_data_receive(env->uart);
}
if (usart_flag_get(env->uart, USART_RDBF_FLAG)) {
usart_data_receive(env->uart);
}
return;
}
// 1. Break frame detection
if (usart_flag_get(env->uart, USART_BFF_FLAG)) {
usart_flag_clear(env->uart, USART_BFF_FLAG);
usart_data_receive(env->uart);
env->linFrameStarted = true;
env->linByteCount = 0;
env->linLastByteTime = SystemGetMs(); // Запоминаем время
env->rxFrame.event = LIN_RECV_BREAK_FIELD_OK;
return;
}
if (usart_flag_get(env->uart, USART_IDLEF_FLAG)) {
usart_flag_clear(env->uart, USART_IDLEF_FLAG);
uint8_t data = usart_data_receive(env->uart);
if (!env->linFrameStarted) {
return;
}
// Таймаут - кадр должен быть завершен
if (env->linByteCount >= 2) {
if (env->linBuffer[1] == 0x97) {
return;
}
// Пытаемся обработать полученные данные
if (env->linByteCount == 2) {
LIN_ProcessReceivedFrame(env, true);
} else {
LIN_ProcessReceivedFrame(env, false);
}
} else {
// Недостаточно данных
env->rxFrame.event = LIN_TIMEOUT;
osMessageQueuePut(env->rxDataQueue, &env->rxFrame, 0, 0);
}
env->linFrameStarted = false;
}
// 2. Receive data (без IDLE)
if (usart_flag_get(env->uart, USART_RDBF_FLAG)) {
uint8_t data = usart_data_receive(env->uart);
if (env->linFrameStarted && (env->linByteCount < sizeof(env->linBuffer))) {
env->linBuffer[env->linByteCount] = data;
env->linByteCount++;
env->linLastByteTime = SystemGetMs(); // Обновляем время
} else {
if (env->linFrameStarted) {
env->rxFrame.event = LIN_RX_OVERRUN;
osMessageQueuePut(env->rxDataQueue, &env->rxFrame, 0, 0);
env->linFrameStarted = false;
}
}
}
// 3. Error handling
if (usart_flag_get(env->uart, USART_FERR_FLAG)) {
usart_flag_clear(env->uart, USART_FERR_FLAG);
usart_data_receive(env->uart);
if (env->linFrameStarted) {
env->rxFrame.event = LIN_FRAME_ERROR;
osMessageQueuePut(env->rxDataQueue, &env->rxFrame, 0, 0);
env->linFrameStarted = false;
}
}
if (usart_flag_get(env->uart, USART_ROERR_FLAG)) {
usart_flag_clear(env->uart, USART_ROERR_FLAG);
usart_data_receive(env->uart);
if (env->linFrameStarted) {
env->rxFrame.event = LIN_RX_OVERRUN;
osMessageQueuePut(env->rxDataQueue, &env->rxFrame, 0, 0);
env->linFrameStarted = false;
}
}
}
// Функция проверки таймаута (вызывать из таймера, например, каждые 1-5 мс)
void LIN_CheckTimeout(tSerialPortLinArtery *env) {
return;
if (!env->linFrameStarted) {
return;
}
@ -246,9 +308,20 @@ void LIN_CheckTimeout(tSerialPortLinArtery *env) {
if (elapsed >= env->linFrameTimeoutMs) {
// Таймаут - кадр должен быть завершен
if (env->linByteCount >= 3) {
if (env->linByteCount >= 2) {
if (env->linBuffer[1] == 0x97) {
return;
}
// Пытаемся обработать полученные данные
LIN_ProcessReceivedFrame(env);
if (env->linByteCount == 2) {
LIN_ProcessReceivedFrame(env, true);
} else {
LIN_ProcessReceivedFrame(env, false);
}
} else {
// Недостаточно данных
env->rxFrame.event = LIN_TIMEOUT;
@ -259,7 +332,7 @@ void LIN_CheckTimeout(tSerialPortLinArtery *env) {
}
}
/*
static bool vSerialPortSendLinFrame(tSerialPortLinArtery *env, const lin_frame_t *pFrame, uint32_t timeout) {
uint8_t txBuffer[11]; // Максимальный размер LIN кадра (без break)
uint8_t idx = 0;
@ -289,23 +362,73 @@ static bool vSerialPortSendLinFrame(tSerialPortLinArtery *env, const lin_frame_t
// Checksum
txBuffer[idx++] = pFrame->checksum;
// 2. Отправка break field
env->linTxInProgress = true;
// 1. Отправка break field
usart_break_send(env->uart);
// Ожидание завершения отправки break
uint32_t breakTimeout = SystemGetMs() + 10; // 10мс максимум на break
// Ожидаем завершения break (но не через TDC!)
uint32_t breakTimeout = SystemGetMs() + 2; // 2мс достаточно для break
while (usart_flag_get(env->uart, USART_TDBE_FLAG) == RESET) {
if (SystemGetMs() > breakTimeout) {
env->linTxInProgress = false;
return false;
}
}
// 3. Отправка данных (возвращает количество отправленных байт)
uint16_t sent = vSerialPortLinTransmitOverCore(env, txBuffer, idx, timeout);
// 2. Отправка данных (используем TDBE, не TDC!)
for (uint8_t i = 0; i < idx; i++) {
// Ждем пока буфер передачи освободится
while (usart_flag_get(env->uart, USART_TDBE_FLAG) == RESET);
return (sent == idx); // Успех, если все байты отправлены
// Отправляем байт
usart_data_transmit(env->uart, txBuffer[i]);
// НЕ ждем TDC! Сразу переходим к следующему байту
}
// 3. Ждем завершения передачи последнего байта
while (usart_flag_get(env->uart, USART_TDC_FLAG) == RESET);
env->linTxInProgress = false;
// 4. Очищаем эхо (важно!)
while (usart_flag_get(env->uart, USART_RDBF_FLAG)) {
(void)usart_data_receive(env->uart);
}
return true;
}
*/
// Функция отправки RESPONSE от Slave (после получения HEADER)
static bool vSerialPortSendLinResponse(tSerialPortLinArtery *env, const lin_frame_t *pFrame, uint32_t timeout) {
uint8_t txBuffer[10]; // Только данные + checksum (без break и sync!)
uint8_t idx = 0;
if (!pFrame || pFrame->dataLen > 8) return false;
// Формируем ТОЛЬКО RESPONSE (без Header!)
for (uint8_t i = 0; i < pFrame->dataLen; i++) {
txBuffer[idx++] = pFrame->data[i];
}
txBuffer[idx++] = pFrame->checksum;
env->linTxInProgress = true;
// Отправка response (без break и sync!)
for (uint8_t i = 0; i < idx; i++) {
while (usart_flag_get(env->uart, USART_TDBE_FLAG) == RESET);
usart_data_transmit(env->uart, txBuffer[i]);
}
// Ждем завершения
while (usart_flag_get(env->uart, USART_TDC_FLAG) == RESET);
env->linTxInProgress = false;
return true;
}
static uint16_t vSerialPortLinReceiveQueue(tSerialPortLinArtery *env, uint8_t *data, uint16_t size, uint32_t timeout,
osMessageQueueId_t queueId) {
@ -350,10 +473,21 @@ static uint8_t vLinTransmitCommand(tSerialPortLinArtery *env, tLinData *linData,
txFrame.data[i] = linData->g_aTxBuffer[i];
}
bool result = vSerialPortSendLinFrame(env, &txFrame, timeout);
uint8_t receivedPid = linData->g_aRxBuffer[0];
uint8_t id = receivedPid & 0x3F;
uint8_t expectedPid = id | LIN_CalcParity(id);
txFrame.id = expectedPid;
txFrame.checksum = LIN_DrvMakeCheckSum(
txFrame.data,
txFrame.dataLen,
txFrame.id
);
bool result = vSerialPortSendLinResponse(env, &txFrame, timeout);
if (result) {
return LIN_RX_COMPLETED;
return LIN_TX_COMPLETED;
}
return LIN_TIMEOUT;
@ -368,11 +502,13 @@ static uint8_t vLinReceivedCommand(tSerialPortLinArtery *env, tLinData *linData,
memset(linData->g_aRxBuffer, 0, sizeof(linData->g_aRxBuffer));
if (rxFrame.event == LIN_RX_COMPLETED) {
linData->g_aRxBufferLen = rxFrame.dataLen + 1;
linData->g_aRxBuffer[0] = rxFrame.id;
for (uint8_t i = 0; i < rxFrame.dataLen; ++i) {
linData->g_aRxBuffer[i + 1] = rxFrame.data[i];
}
}
return rxFrame.event;
}