// // 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 = 20; env->linFrameTimeoutMs = 20; 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); } // Измененный обработчик прерываний (без 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)) { if (env->linFrameStarted && (env->linByteCount < sizeof(env->linBuffer))) { uint8_t data = usart_data_receive(env->uart); env->linBuffer[env->linByteCount] = data; env->linByteCount++; env->linLastByteTime = SystemGetMs(); // Обновляем время } else { usart_data_receive(env->uart); 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; } } } // Выделенная функция обработки кадра static void LIN_ProcessReceivedFrame(tSerialPortLinArtery *env) { // Проверка 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; } 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); } // Функция проверки таймаута (вызывать из таймера, например, каждые 1-5 мс) void LIN_CheckTimeout(tSerialPortLinArtery *env) { if (!env->linFrameStarted) { return; } uint32_t now = SystemGetMs(); uint32_t elapsed = now - env->linLastByteTime; if (elapsed >= env->linFrameTimeoutMs) { // Таймаут - кадр должен быть завершен if (env->linByteCount >= 3) { // Пытаемся обработать полученные данные LIN_ProcessReceivedFrame(env); } else { // Недостаточно данных env->rxFrame.event = LIN_TIMEOUT; osMessageQueuePut(env->rxDataQueue, &env->rxFrame, 0, 0); } env->linFrameStarted = false; } } bool vSerialPortSendLinFrame(tSerialPortLinArtery *env, const lin_frame_t *pFrame, uint32_t timeout) { uint8_t txBuffer[11]; // Максимальный размер LIN кадра (без break) uint8_t idx = 0; if ((!env) || (!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; // 2. Отправка break field usart_break_send(env->uart); // Ожидание завершения отправки break uint32_t breakTimeout = SystemGetMs() + 10; // 10мс максимум на break while (usart_flag_get(env->uart, USART_TDBE_FLAG) == RESET) { if (SystemGetMs() > breakTimeout) { return false; } } // 3. Отправка данных (возвращает количество отправленных байт) uint16_t sent = vSerialPortLinTransmitOverCore(env, txBuffer, idx, timeout); return (sent == idx); // Успех, если все байты отправлены }