// // Created by cfif on 16.09.22. // #include #include "SerialPortLinArtery.h" #include "string.h" void vSerialPortLinInit( tSerialPortLinArtery *env, usart_type *uart, bool swap, uint32_t BoundRate, IRQn_Type irq, crm_periph_clock_type uartClock, uint8_t irqPriority, uint32_t rxBufferLength, uint32_t rxSnifferLength ) { env->uart = uart; env->linLastByteTime = 2; env->linFrameTimeoutMs = 2; usart_reset(uart); crm_periph_clock_enable(uartClock, TRUE); usart_init(uart, BoundRate, USART_DATA_8BITS, USART_STOP_1_BIT); // ВКЛЮЧАЕМ LIN РЕЖИМ!!! usart_lin_mode_enable(uart, TRUE); // Настраиваем длину break field (LIN требует 13 бит, выбираем 11) usart_break_bit_num_set(uart, USART_BREAK_11BITS); usart_transmitter_enable(uart, TRUE); usart_receiver_enable(uart, TRUE); if (swap) { usart_transmit_receive_pin_swap(uart, TRUE); } usart_enable(uart, TRUE); // Включаем прерывание по 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); NVIC_EnableIRQ(irq); NVIC_SetPriority(irq, irqPriority); env->rxDataQueue = osMessageQueueNew(rxBufferLength, sizeof(lin_frame_t), NULL); if (rxSnifferLength) { env->rxDataSnifferQueue = osMessageQueueNew(rxSnifferLength, sizeof(lin_frame_t), NULL); } else { env->rxDataSnifferQueue = 0; } } static uint16_t vSerialPortLinTransmitOverCore(tSerialPortLinArtery *env, uint8_t *data, uint16_t size, uint32_t timeout) { uint16_t sent = 0; uint32_t endMs = SystemGetMs() + timeout; while (size && ((timeout == SystemWaitForever) || (endMs > SystemGetMs()))) { if (usart_flag_get(env->uart, USART_TDBE_FLAG)) { usart_data_transmit(env->uart, *data); --size; ++data; ++sent; } } while ((timeout == SystemWaitForever) || (endMs > SystemGetMs())) { if (usart_flag_get(env->uart, USART_TDC_FLAG)) break; } return sent; } static uint8_t LIN_DrvMakeCheckSum(uint8_t *pBuf, uint8_t u8Size, uint8_t u8Pid) { uint16_t u16Checksum = 0U; uint8_t u8Length = 0U; // For PID is 0x3C (ID 0x3C) or 0x7D (ID 0x3D) or 0xFE (ID 0x3E) or 0xBF (ID 0x3F) if ((0x3CU == u8Pid) || (0x7DU == u8Pid) || (0xFEU == u8Pid) || (0xBFU == u8Pid)) { u8Pid = 0U; } u16Checksum += u8Pid; for (u8Length = 0U; u8Length < u8Size; u8Length++) { u16Checksum += *pBuf; pBuf++; if (u16Checksum > 0xFFU) { u16Checksum -= 0xFFU; } } return ~(uint8_t) (u16Checksum); } static uint8_t LIN_CalcParity(uint8_t id) { uint8_t p0 = 0; uint8_t p1 = 0; // P0 = ID0 ^ ID1 ^ ID2 ^ ID4 p0 = ((id >> 0) & 0x01) ^ ((id >> 1) & 0x01) ^ ((id >> 2) & 0x01) ^ ((id >> 4) & 0x01); // P1 = ^(ID1 ^ ID3 ^ ID4 ^ ID5) p1 = 1 ^ ((id >> 1) & 0x01) ^ ((id >> 3) & 0x01) ^ ((id >> 4) & 0x01) ^ ((id >> 5) & 0x01); return (p1 << 7) | (p0 << 6); } extern const uint8_t DRS_SENSON_ADR_Stat[8]; // Выделенная функция обработки кадра static void LIN_ProcessReceivedFrame(tSerialPortLinArtery *env, bool isHeader) { // Проверка sync field if (env->linBuffer[0] != 0x55) { env->rxFrame.event = LIN_SYNC_ERROR; osMessageQueuePut(env->rxDataQueue, &env->rxFrame, 0, 0); return; } // Проверка PID uint8_t receivedPid = env->linBuffer[1]; uint8_t id = receivedPid & 0x3F; uint8_t expectedPid = id | LIN_CalcParity(id); if (receivedPid != expectedPid) { env->rxFrame.event = LIN_PID_ERROR; osMessageQueuePut(env->rxDataQueue, &env->rxFrame, 0, 0); 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; if (env->rxFrame.dataLen > 8) { env->rxFrame.event = LIN_FRAME_ERROR; osMessageQueuePut(env->rxDataQueue, &env->rxFrame, 0, 0); return; } // Копируем данные for (uint8_t i = 0; i < env->rxFrame.dataLen; i++) { env->rxFrame.data[i] = env->linBuffer[2 + i]; } // Проверка checksum env->rxFrame.checksum = env->linBuffer[env->linByteCount - 1]; uint8_t calculatedChecksum = LIN_DrvMakeCheckSum( env->rxFrame.data, env->rxFrame.dataLen, receivedPid ); if (env->rxFrame.checksum != calculatedChecksum) { env->rxFrame.event = LIN_CHECKSUM_ERROR; } else { env->rxFrame.event = LIN_RX_COMPLETED; } 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; } uint32_t now = SystemGetMs(); uint32_t elapsed = now - env->linLastByteTime; if (elapsed >= env->linFrameTimeoutMs) { // Таймаут - кадр должен быть завершен 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; } } /* static bool vSerialPortSendLinFrame(tSerialPortLinArtery *env, const lin_frame_t *pFrame, uint32_t timeout) { uint8_t txBuffer[11]; // Максимальный размер LIN кадра (без break) uint8_t idx = 0; if (!pFrame) { return false; } // Проверка валидности данных if (pFrame->dataLen > 8) { return false; } // 1. Формирование LIN кадра // Sync field txBuffer[idx++] = 0x55; // PID (ID + parity) uint8_t pid = pFrame->id | LIN_CalcParity(pFrame->id); txBuffer[idx++] = pid; // Data bytes for (uint8_t i = 0; i < pFrame->dataLen; i++) { txBuffer[idx++] = pFrame->data[i]; } // Checksum txBuffer[idx++] = pFrame->checksum; env->linTxInProgress = true; // 1. Отправка break field usart_break_send(env->uart); // Ожидаем завершения 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; } } // 2. Отправка данных (используем TDBE, не TDC!) 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]); // НЕ ждем 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) { uint16_t received = 0; if (timeout) { uint32_t endMs = SystemGetMs() + timeout; uint32_t leftMs; while (size && ((timeout == SystemWaitForever) || (endMs > SystemGetMs()))) { leftMs = endMs - SystemGetMs(); if (osMessageQueueGet(queueId, data, NULL, leftMs) == osOK) { --size; ++received; ++data; } } } else { while (size) { if (osMessageQueueGet(queueId, data, NULL, 0) == osOK) { --size; ++received; ++data; } else { return received; } } } return received; } static uint8_t vLinTransmitCommand(tSerialPortLinArtery *env, tLinData *linData, uint8_t ADR_COM, uint32_t timeout) { lin_frame_t txFrame; txFrame.dataLen = linData->g_aTxBufferLen; for (uint8_t i = 0; i < linData->g_aTxBufferLen; ++i) { txFrame.data[i] = linData->g_aTxBuffer[i]; } uint8_t receivedPid = ADR_COM; 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_TX_COMPLETED; } return LIN_TIMEOUT; } static uint8_t vLinReceivedCommand(tSerialPortLinArtery *env, tLinData *linData, uint8_t *ADR_COM, uint32_t timeout) { lin_frame_t rxFrame; // uint16_t len = vSerialPortLinReceiveQueue(env, (void *) &rxFrame, sizeof(lin_frame_t), osWaitForever, env->rxDataQueue); osStatus_t result = osMessageQueueGet(env->rxDataQueue, (void *) &rxFrame, NULL, osWaitForever); if (result == osOK) { memset(linData->g_aRxBuffer, 0, sizeof(linData->g_aRxBuffer)); if (rxFrame.event == LIN_RX_COMPLETED) { linData->g_aRxBufferLen = rxFrame.dataLen + 1; *ADR_COM = rxFrame.id & 0x3F; for (uint8_t i = 0; i < rxFrame.dataLen; ++i) { linData->g_aRxBuffer[i] = rxFrame.data[i]; } } return rxFrame.event; } return LIN_NO_EVENT; } tSerialPortLinIO vSerialPorLinGetIo(tSerialPortLinArtery *env) { tSerialPortLinIO io = { .env = env, .transmitCommand = (LinIOTransactionTransmit) vLinTransmitCommand, .receivedCommand = (LinIOTransactionReceived) vLinReceivedCommand }; return io; }