1094 lines
34 KiB
C
1094 lines
34 KiB
C
//
|
||
// Created by cfif on 16.09.22.
|
||
//
|
||
#include <SystemDelayInterface.h>
|
||
#include "SerialPortArtery.h"
|
||
#include "string.h"
|
||
|
||
void vSerialPortInit(
|
||
tSerialPortArtery *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
|
||
) {
|
||
usart_reset(uart);
|
||
|
||
crm_periph_clock_enable(uartClock, TRUE);
|
||
|
||
usart_init(uart, BoundRate, USART_DATA_8BITS, USART_STOP_1_BIT);
|
||
|
||
usart_transmitter_enable(uart, TRUE);
|
||
usart_receiver_enable(uart, TRUE);
|
||
|
||
if (swap) {
|
||
usart_transmit_receive_pin_swap(uart, TRUE);
|
||
}
|
||
|
||
usart_enable(uart, TRUE);
|
||
|
||
usart_interrupt_enable(uart, USART_RDBF_INT, TRUE);
|
||
|
||
NVIC_EnableIRQ(irq);
|
||
NVIC_SetPriority(irq, irqPriority);
|
||
|
||
env->rxDataQueue = osMessageQueueNew(rxBufferLength, 1, NULL);
|
||
|
||
if (rxSnifferLength) {
|
||
env->rxDataSnifferQueue = osMessageQueueNew(rxSnifferLength, 1, NULL);
|
||
} else {
|
||
env->rxDataSnifferQueue = 0;
|
||
}
|
||
|
||
env->uart = uart;
|
||
}
|
||
|
||
void vSerialPortLinInit(
|
||
tSerialPortArtery *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, 12, NULL);
|
||
|
||
if (rxSnifferLength) {
|
||
env->rxDataSnifferQueue = osMessageQueueNew(rxSnifferLength, sizeof(lin_frame_t), NULL);
|
||
} else {
|
||
env->rxDataSnifferQueue = 0;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
void vSerialPortInitExt(
|
||
tSerialPortArtery *env,
|
||
usart_type *uart,
|
||
bool swap,
|
||
usart_hardware_flow_control_type flow_control_type,
|
||
uint32_t BoundRate,
|
||
IRQn_Type irq,
|
||
crm_periph_clock_type uartClock,
|
||
uint8_t irqPriority,
|
||
uint32_t rxBufferLength,
|
||
uint32_t rxSnifferLength
|
||
) {
|
||
usart_reset(uart);
|
||
|
||
crm_periph_clock_enable(uartClock, TRUE);
|
||
|
||
usart_init(uart, BoundRate, USART_DATA_8BITS, USART_STOP_1_BIT);
|
||
usart_hardware_flow_control_set(uart, flow_control_type);
|
||
|
||
usart_transmitter_enable(uart, TRUE);
|
||
usart_receiver_enable(uart, TRUE);
|
||
|
||
if (swap) {
|
||
usart_transmit_receive_pin_swap(uart, TRUE);
|
||
}
|
||
|
||
usart_enable(uart, TRUE);
|
||
|
||
usart_interrupt_enable(uart, USART_RDBF_INT, TRUE);
|
||
|
||
NVIC_EnableIRQ(irq);
|
||
NVIC_SetPriority(irq, irqPriority);
|
||
|
||
env->rxDataQueue = osMessageQueueNew(rxBufferLength, 1, NULL);
|
||
|
||
if (rxSnifferLength) {
|
||
env->rxDataSnifferQueue = osMessageQueueNew(rxSnifferLength, 1, NULL);
|
||
} else {
|
||
env->rxDataSnifferQueue = 0;
|
||
}
|
||
|
||
env->uart = uart;
|
||
}
|
||
|
||
void vSerialPortInitDMA(
|
||
tSerialPortArtery *env,
|
||
usart_type *uart,
|
||
|
||
dma_type *DMA_RX,
|
||
dma_type *DMA_TX,
|
||
|
||
dma_channel_type *RX_DMA_CHANNEL,
|
||
dmamux_channel_type *RX_DMA_CHANNEL_MUX,
|
||
dmamux_requst_id_sel_type RX_DMAMUX_DMAREQ_ID,
|
||
IRQn_Type RX_DMA_Channel_IRQ,
|
||
uint32_t RX_DMA_FDT_FLAG,
|
||
|
||
uint8_t *DMA_BUF,
|
||
uint16_t DMA_BUF_LEN,
|
||
|
||
|
||
dma_channel_type *TX_DMA_CHANNEL,
|
||
dmamux_channel_type *TX_DMA_CHANNEL_MUX,
|
||
dmamux_requst_id_sel_type TX_DMAMUX_DMAREQ_ID,
|
||
IRQn_Type TX_DMA_Channel_IRQ,
|
||
uint32_t TX_DMA_FDT_FLAG,
|
||
|
||
bool swap,
|
||
uint32_t BoundRate,
|
||
IRQn_Type irq,
|
||
crm_periph_clock_type uartClock,
|
||
uint8_t irqPriority,
|
||
uint32_t rxBufferLength,
|
||
uint32_t rxSnifferLength
|
||
) {
|
||
|
||
{
|
||
if (DMA_RX)NVIC_DisableIRQ(RX_DMA_Channel_IRQ);
|
||
if (DMA_TX)NVIC_DisableIRQ(TX_DMA_Channel_IRQ);
|
||
NVIC_DisableIRQ(irq);
|
||
}
|
||
|
||
/*включаем тактирование uart и нужных DMA */{
|
||
crm_periph_clock_enable(uartClock, TRUE);
|
||
|
||
if (DMA_RX == DMA1 || DMA_TX == DMA1) {
|
||
crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
|
||
}
|
||
if (DMA_RX == DMA2 || DMA_TX == DMA2) {
|
||
crm_periph_clock_enable(CRM_DMA2_PERIPH_CLOCK, TRUE);
|
||
}
|
||
}
|
||
|
||
/*заполняем параметры и создаем все очереди до начала работы порта (иначе при раннем сробатывании прервывания все упадет)*/{
|
||
env->txAccessQueue = osMessageQueueNew(1, 1, NULL);
|
||
|
||
env->rxDataQueue = osMessageQueueNew(rxBufferLength, 1, NULL);
|
||
|
||
if (rxSnifferLength) {
|
||
env->rxDataSnifferQueue = osMessageQueueNew(rxSnifferLength, 1, NULL);
|
||
} else {
|
||
env->rxDataSnifferQueue = 0;
|
||
}
|
||
|
||
|
||
env->rxDmaFdtFlag = RX_DMA_FDT_FLAG;
|
||
env->txDmaFdtFlag = TX_DMA_FDT_FLAG;
|
||
|
||
env->txDmaChannel = TX_DMA_CHANNEL;
|
||
env->rxDmaChannel = RX_DMA_CHANNEL;
|
||
|
||
env->rxDmaBuf = DMA_BUF;
|
||
env->rxDmaOffset = 0;
|
||
}
|
||
|
||
|
||
/*инициализируем uart */{
|
||
env->uart = uart;
|
||
|
||
usart_reset(uart);
|
||
|
||
usart_init(uart, BoundRate, USART_DATA_8BITS, USART_STOP_1_BIT);
|
||
|
||
usart_transmitter_enable(uart, TRUE);
|
||
usart_receiver_enable(uart, TRUE);
|
||
|
||
usart_dma_receiver_enable(uart, TRUE);
|
||
usart_dma_transmitter_enable(uart, TRUE);
|
||
|
||
|
||
if (swap) {
|
||
usart_transmit_receive_pin_swap(uart, TRUE);
|
||
}
|
||
}
|
||
|
||
|
||
/*инициализируем RX DMA в циклическом режиме*/if (DMA_RX) {
|
||
dmamux_enable(DMA_RX, TRUE);
|
||
|
||
// dma channel for usart rx configuration
|
||
dma_reset(RX_DMA_CHANNEL);
|
||
dma_default_para_init(&env->dma_rx_init_struct);
|
||
env->dma_rx_init_struct.buffer_size = DMA_BUF_LEN;
|
||
env->dma_rx_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
|
||
env->dma_rx_init_struct.memory_base_addr = (uint32_t) DMA_BUF;
|
||
env->dma_rx_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
|
||
env->dma_rx_init_struct.memory_inc_enable = TRUE;
|
||
env->dma_rx_init_struct.peripheral_base_addr = (uint32_t) &uart->dt;
|
||
env->dma_rx_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
|
||
env->dma_rx_init_struct.peripheral_inc_enable = FALSE;
|
||
env->dma_rx_init_struct.priority = DMA_PRIORITY_HIGH;
|
||
env->dma_rx_init_struct.loop_mode_enable = TRUE;
|
||
dma_init(RX_DMA_CHANNEL, &env->dma_rx_init_struct);
|
||
|
||
|
||
// config flexible dma for usart7 rx
|
||
dmamux_init(RX_DMA_CHANNEL_MUX, RX_DMAMUX_DMAREQ_ID);
|
||
}
|
||
|
||
|
||
/*инициализируем TX DMA*/if (DMA_TX) {
|
||
dmamux_enable(DMA_TX, TRUE);
|
||
|
||
// dma channel for usart tx configuration
|
||
dma_reset(TX_DMA_CHANNEL);
|
||
dma_default_para_init(&env->dma_tx_init_struct);
|
||
env->dma_tx_init_struct.buffer_size = 0;
|
||
env->dma_tx_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
|
||
env->dma_tx_init_struct.memory_base_addr = 0;
|
||
env->dma_tx_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
|
||
env->dma_tx_init_struct.memory_inc_enable = TRUE;
|
||
env->dma_tx_init_struct.peripheral_base_addr = (uint32_t) &uart->dt;
|
||
env->dma_tx_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
|
||
env->dma_tx_init_struct.peripheral_inc_enable = FALSE;
|
||
env->dma_tx_init_struct.priority = DMA_PRIORITY_HIGH;
|
||
env->dma_tx_init_struct.loop_mode_enable = FALSE;
|
||
dma_init(TX_DMA_CHANNEL, &env->dma_tx_init_struct);
|
||
|
||
// config flexible dma for usart7 tx
|
||
dmamux_init(TX_DMA_CHANNEL_MUX, TX_DMAMUX_DMAREQ_ID);
|
||
}
|
||
|
||
|
||
/*включаем rx dma и прерывания на нем*/if (DMA_RX) {
|
||
dma_interrupt_enable(RX_DMA_CHANNEL, DMA_FDT_INT, TRUE);
|
||
|
||
NVIC_EnableIRQ(RX_DMA_Channel_IRQ);
|
||
NVIC_SetPriority(RX_DMA_Channel_IRQ, irqPriority);
|
||
|
||
dma_channel_enable(RX_DMA_CHANNEL, TRUE); // uart7 rx begin dma receiving
|
||
}
|
||
|
||
/*включаем прерывания на tx dma*/if (DMA_TX) {
|
||
dma_interrupt_enable(TX_DMA_CHANNEL, DMA_FDT_INT, TRUE);
|
||
|
||
NVIC_EnableIRQ(TX_DMA_Channel_IRQ);
|
||
NVIC_SetPriority(TX_DMA_Channel_IRQ, irqPriority);
|
||
|
||
}
|
||
|
||
/*включаем uart и прерывания на нем*/{
|
||
usart_interrupt_enable(uart, USART_IDLE_INT, TRUE);
|
||
// usart_interrupt_enable(uart, USART_RDBF_INT, FALSE);
|
||
|
||
NVIC_EnableIRQ(irq);
|
||
NVIC_SetPriority(irq, irqPriority);
|
||
|
||
usart_enable(uart, TRUE);
|
||
}
|
||
}
|
||
|
||
void vSerialPortInitDMAExt(
|
||
tSerialPortArtery *env,
|
||
usart_type *uart,
|
||
|
||
dma_type *DMA_RX,
|
||
dma_type *DMA_TX,
|
||
|
||
dma_channel_type *RX_DMA_CHANNEL,
|
||
dmamux_channel_type *RX_DMA_CHANNEL_MUX,
|
||
dmamux_requst_id_sel_type RX_DMAMUX_DMAREQ_ID,
|
||
IRQn_Type RX_DMA_Channel_IRQ,
|
||
uint32_t RX_DMA_FDT_FLAG,
|
||
|
||
uint8_t *DMA_BUF,
|
||
uint16_t DMA_BUF_LEN,
|
||
|
||
|
||
dma_channel_type *TX_DMA_CHANNEL,
|
||
dmamux_channel_type *TX_DMA_CHANNEL_MUX,
|
||
dmamux_requst_id_sel_type TX_DMAMUX_DMAREQ_ID,
|
||
IRQn_Type TX_DMA_Channel_IRQ,
|
||
uint32_t TX_DMA_FDT_FLAG,
|
||
|
||
bool swap,
|
||
usart_hardware_flow_control_type flow_control_type,
|
||
uint32_t BoundRate,
|
||
IRQn_Type irq,
|
||
crm_periph_clock_type uartClock,
|
||
uint8_t irqPriority,
|
||
uint32_t rxBufferLength,
|
||
uint32_t rxSnifferLength
|
||
) {
|
||
|
||
/*включаем тактирование uart и нужных DMA */{
|
||
crm_periph_clock_enable(uartClock, TRUE);
|
||
|
||
if (DMA_RX == DMA1 || DMA_TX == DMA1) {
|
||
crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
|
||
}
|
||
if (DMA_RX == DMA2 || DMA_TX == DMA2) {
|
||
crm_periph_clock_enable(CRM_DMA2_PERIPH_CLOCK, TRUE);
|
||
}
|
||
}
|
||
|
||
/*заполняем параметры и создаем все очереди до начала работы порта (иначе при раннем сробатывании прервывания все упадет)*/{
|
||
env->txAccessQueue = osMessageQueueNew(1, 1, NULL);
|
||
|
||
env->rxDataQueue = osMessageQueueNew(rxBufferLength, 1, NULL);
|
||
|
||
if (rxSnifferLength) {
|
||
env->rxDataSnifferQueue = osMessageQueueNew(rxSnifferLength, 1, NULL);
|
||
} else {
|
||
env->rxDataSnifferQueue = 0;
|
||
}
|
||
|
||
|
||
env->rxDmaFdtFlag = RX_DMA_FDT_FLAG;
|
||
env->txDmaFdtFlag = TX_DMA_FDT_FLAG;
|
||
|
||
env->txDmaChannel = TX_DMA_CHANNEL;
|
||
env->rxDmaChannel = RX_DMA_CHANNEL;
|
||
|
||
env->rxDmaBuf = DMA_BUF;
|
||
env->rxDmaOffset = 0;
|
||
}
|
||
|
||
|
||
/*инициализируем uart */{
|
||
env->uart = uart;
|
||
|
||
usart_reset(uart);
|
||
|
||
usart_init(uart, BoundRate, USART_DATA_8BITS, USART_STOP_1_BIT);
|
||
usart_hardware_flow_control_set(uart, flow_control_type);
|
||
|
||
usart_transmitter_enable(uart, TRUE);
|
||
usart_receiver_enable(uart, TRUE);
|
||
|
||
usart_dma_receiver_enable(uart, TRUE);
|
||
usart_dma_transmitter_enable(uart, TRUE);
|
||
|
||
|
||
if (swap) {
|
||
usart_transmit_receive_pin_swap(uart, TRUE);
|
||
}
|
||
}
|
||
|
||
|
||
/*инициализируем RX DMA в циклическом режиме*/if (DMA_RX) {
|
||
dmamux_enable(DMA_RX, TRUE);
|
||
|
||
// dma channel for usart rx configuration
|
||
dma_reset(RX_DMA_CHANNEL);
|
||
dma_default_para_init(&env->dma_rx_init_struct);
|
||
env->dma_rx_init_struct.buffer_size = DMA_BUF_LEN;
|
||
env->dma_rx_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
|
||
env->dma_rx_init_struct.memory_base_addr = (uint32_t) DMA_BUF;
|
||
env->dma_rx_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
|
||
env->dma_rx_init_struct.memory_inc_enable = TRUE;
|
||
env->dma_rx_init_struct.peripheral_base_addr = (uint32_t) &uart->dt;
|
||
env->dma_rx_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
|
||
env->dma_rx_init_struct.peripheral_inc_enable = FALSE;
|
||
env->dma_rx_init_struct.priority = DMA_PRIORITY_HIGH;
|
||
env->dma_rx_init_struct.loop_mode_enable = TRUE;
|
||
dma_init(RX_DMA_CHANNEL, &env->dma_rx_init_struct);
|
||
|
||
|
||
// config flexible dma for usart7 rx
|
||
dmamux_init(RX_DMA_CHANNEL_MUX, RX_DMAMUX_DMAREQ_ID);
|
||
}
|
||
|
||
|
||
/*инициализируем TX DMA*/if (DMA_TX) {
|
||
dmamux_enable(DMA_TX, TRUE);
|
||
|
||
// dma channel for usart tx configuration
|
||
dma_reset(TX_DMA_CHANNEL);
|
||
dma_default_para_init(&env->dma_tx_init_struct);
|
||
env->dma_tx_init_struct.buffer_size = 0;
|
||
env->dma_tx_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
|
||
env->dma_tx_init_struct.memory_base_addr = 0;
|
||
env->dma_tx_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
|
||
env->dma_tx_init_struct.memory_inc_enable = TRUE;
|
||
env->dma_tx_init_struct.peripheral_base_addr = (uint32_t) &uart->dt;
|
||
env->dma_tx_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
|
||
env->dma_tx_init_struct.peripheral_inc_enable = FALSE;
|
||
env->dma_tx_init_struct.priority = DMA_PRIORITY_HIGH;
|
||
env->dma_tx_init_struct.loop_mode_enable = FALSE;
|
||
dma_init(TX_DMA_CHANNEL, &env->dma_tx_init_struct);
|
||
|
||
// config flexible dma for usart7 tx
|
||
dmamux_init(TX_DMA_CHANNEL_MUX, TX_DMAMUX_DMAREQ_ID);
|
||
}
|
||
|
||
|
||
/*включаем rx dma и прерывания на нем*/if (DMA_RX) {
|
||
dma_interrupt_enable(RX_DMA_CHANNEL, DMA_FDT_INT, TRUE);
|
||
|
||
NVIC_EnableIRQ(RX_DMA_Channel_IRQ);
|
||
NVIC_SetPriority(RX_DMA_Channel_IRQ, irqPriority);
|
||
|
||
dma_channel_enable(RX_DMA_CHANNEL, TRUE); // uart7 rx begin dma receiving
|
||
}
|
||
|
||
/*включаем прерывания на tx dma*/if (DMA_TX) {
|
||
dma_interrupt_enable(TX_DMA_CHANNEL, DMA_FDT_INT, TRUE);
|
||
|
||
NVIC_EnableIRQ(TX_DMA_Channel_IRQ);
|
||
NVIC_SetPriority(TX_DMA_Channel_IRQ, irqPriority);
|
||
|
||
}
|
||
|
||
/*включаем uart и прерывания на нем*/{
|
||
usart_interrupt_enable(uart, USART_IDLE_INT, TRUE);
|
||
// usart_interrupt_enable(uart, USART_RDBF_INT, FALSE);
|
||
|
||
NVIC_EnableIRQ(irq);
|
||
NVIC_SetPriority(irq, irqPriority);
|
||
|
||
usart_enable(uart, TRUE);
|
||
}
|
||
}
|
||
|
||
|
||
void vSerialPortSendDMA(
|
||
tSerialPortArtery *env,
|
||
usart_type *uart,
|
||
|
||
dma_type *DMA,
|
||
dma_channel_type *DMA_CHANNEL,
|
||
dmamux_channel_type *DMA_CHANNEL_MUX,
|
||
dmamux_requst_id_sel_type DMAMUX_DMAREQ_ID,
|
||
uint8_t *DMA_BUF,
|
||
uint16_t DMA_BUF_LEN
|
||
|
||
) {
|
||
dma_channel_enable(DMA_CHANNEL, FALSE);
|
||
|
||
// dma channel for usart tx configuration
|
||
dma_reset(DMA_CHANNEL);
|
||
dma_default_para_init(&env->dma_tx_init_struct);
|
||
env->dma_tx_init_struct.buffer_size = DMA_BUF_LEN;
|
||
env->dma_tx_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
|
||
env->dma_tx_init_struct.memory_base_addr = (uint32_t) DMA_BUF;
|
||
env->dma_tx_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
|
||
env->dma_tx_init_struct.memory_inc_enable = TRUE;
|
||
env->dma_tx_init_struct.peripheral_base_addr = (uint32_t) &uart->dt;
|
||
env->dma_tx_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
|
||
env->dma_tx_init_struct.peripheral_inc_enable = FALSE;
|
||
env->dma_tx_init_struct.priority = DMA_PRIORITY_MEDIUM;
|
||
env->dma_tx_init_struct.loop_mode_enable = FALSE;
|
||
dma_init(DMA_CHANNEL, &env->dma_tx_init_struct);
|
||
|
||
// config flexible dma for usart7 tx
|
||
dmamux_init(DMA_CHANNEL_MUX, DMAMUX_DMAREQ_ID);
|
||
|
||
dma_channel_enable(DMA_CHANNEL, TRUE);
|
||
|
||
}
|
||
|
||
|
||
/*
|
||
void vSerialPortIrqProcessingDMA(tSerialPortArtery *env) {
|
||
|
||
dma_channel_enable(env->dma_channel, FALSE);
|
||
|
||
uint32_t len = env->dma_init_struct.buffer_size - env->dma_channel->dtcnt;
|
||
env->offset = len;
|
||
|
||
for (uint32_t i = 0; i < len; ++i) {
|
||
osMessageQueuePut(env->rxDataQueue, &env->dma_buf[i], 0x0, 0U);
|
||
if (env->rxDataSnifferQueue) {
|
||
osMessageQueuePut(env->rxDataSnifferQueue, &env->dma_buf[i], 0x0, 0U);
|
||
}
|
||
}
|
||
|
||
dma_init(env->dma_channel, &env->dma_init_struct);
|
||
dma_channel_enable(env->dma_channel, TRUE);
|
||
}
|
||
*/
|
||
|
||
|
||
void SerialPortFilter_RxDmaBufToQueue(tSerialPortArtery *env, uint32_t bufEnd,
|
||
tSerialPortIO *virtualPort,
|
||
uint16_t *counterBufFilterStr, uint8_t *bufStrFilter, uint16_t maxBufStrFilter,
|
||
const char *FilterStr[], uint8_t countFiler) {
|
||
|
||
for (uint32_t i = env->rxDmaOffset; i < bufEnd; ++i) {
|
||
osMessageQueuePut(env->rxDataQueue, &env->rxDmaBuf[i], 0x0, 0U);
|
||
if (env->rxDataSnifferQueue) {
|
||
|
||
if (*counterBufFilterStr < maxBufStrFilter) {
|
||
bufStrFilter[*counterBufFilterStr] = env->rxDmaBuf[i];
|
||
++*counterBufFilterStr;
|
||
} else {
|
||
*counterBufFilterStr = 0;
|
||
}
|
||
|
||
bool isFilterFind = false;
|
||
if (env->rxDmaBuf[i] == '\n') {
|
||
|
||
for (uint8_t j = 0; j < countFiler; ++j) {
|
||
if (memcmp(bufStrFilter, FilterStr[j], strlen(FilterStr[j])) == 0) {
|
||
|
||
SerialPortTransmit(virtualPort, bufStrFilter, *counterBufFilterStr, 0);
|
||
|
||
isFilterFind = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (isFilterFind == false) {
|
||
for (uint16_t j = 0; j < *counterBufFilterStr; ++j)
|
||
osMessageQueuePut(env->rxDataSnifferQueue, &bufStrFilter[j], 0x0, 0U);
|
||
}
|
||
|
||
*counterBufFilterStr = 0;
|
||
memset(bufStrFilter, 0, maxBufStrFilter);
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
void SerialPort_RxDmaBufToQueue(tSerialPortArtery *env, uint32_t bufEnd) {
|
||
osStatus_t res;
|
||
for (uint32_t i = env->rxDmaOffset; i < bufEnd; ++i) {
|
||
osMessageQueuePut(env->rxDataQueue, &env->rxDmaBuf[i], 0x0, 0U);
|
||
if (env->rxDataSnifferQueue) {
|
||
osMessageQueuePut(env->rxDataSnifferQueue, &env->rxDmaBuf[i], 0x0, 0U);
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
void SerialPort_IrqProcessing_UartIdle(tSerialPortArtery *env) {
|
||
// Смотрим idle прерывание
|
||
if (usart_flag_get(env->uart, USART_IDLEF_FLAG)) {
|
||
// Сброс прерывания
|
||
usart_data_receive(env->uart);
|
||
usart_flag_clear(env->uart, USART_IDLEF_FLAG);
|
||
size_t bufEnd = env->dma_rx_init_struct.buffer_size - env->rxDmaChannel->dtcnt;
|
||
SerialPort_RxDmaBufToQueue(env, bufEnd);
|
||
env->rxDmaOffset = bufEnd;
|
||
}
|
||
}
|
||
|
||
void SerialPort_IrqProcessing_DmaRxLoop(tSerialPortArtery *env) {
|
||
if (dma_flag_get(env->rxDmaFdtFlag)) {
|
||
SerialPort_RxDmaBufToQueue(env, env->dma_rx_init_struct.buffer_size);
|
||
env->rxDmaOffset = 0;
|
||
dma_flag_clear(env->rxDmaFdtFlag);
|
||
}
|
||
}
|
||
|
||
|
||
void
|
||
SerialPort_IrqProcessingFilter_UartIdle(tSerialPortArtery *env,
|
||
tSerialPortIO *virtualPort,
|
||
uint16_t *counterBufFilterStr, uint8_t *bufStrFilter, uint16_t maxBufStrFilter,
|
||
const char *FilterStr[], uint8_t countFiler) {
|
||
// Смотрим idle прерывание
|
||
if (usart_flag_get(env->uart, USART_IDLEF_FLAG)) {
|
||
// Сброс прерывания
|
||
usart_data_receive(env->uart);
|
||
usart_flag_clear(env->uart, USART_IDLEF_FLAG);
|
||
size_t bufEnd = env->dma_rx_init_struct.buffer_size - env->rxDmaChannel->dtcnt;
|
||
SerialPortFilter_RxDmaBufToQueue(env, bufEnd, virtualPort, counterBufFilterStr, bufStrFilter, maxBufStrFilter,
|
||
FilterStr,
|
||
countFiler);
|
||
env->rxDmaOffset = bufEnd;
|
||
}
|
||
}
|
||
|
||
void
|
||
SerialPort_IrqProcessingFilter_DmaRxLoop(tSerialPortArtery *env,
|
||
tSerialPortIO *virtualPort,
|
||
uint16_t *counterBufFilterStr, uint8_t *bufStrFilter, uint16_t maxBufStrFilter,
|
||
const char *FilterStr[], uint8_t countFiler) {
|
||
if (dma_flag_get(env->rxDmaFdtFlag)) {
|
||
SerialPortFilter_RxDmaBufToQueue(env, env->dma_rx_init_struct.buffer_size,
|
||
virtualPort,
|
||
counterBufFilterStr, bufStrFilter, maxBufStrFilter,
|
||
FilterStr, countFiler);
|
||
env->rxDmaOffset = 0;
|
||
dma_flag_clear(env->rxDmaFdtFlag);
|
||
}
|
||
}
|
||
|
||
|
||
static const uint8_t DUMMY_BYTE = 0xFF;
|
||
|
||
void SerialPort_IrqProcessing_DmaTx(tSerialPortArtery *env) {
|
||
if (dma_flag_get(env->txDmaFdtFlag)) {
|
||
dma_flag_clear(env->txDmaFdtFlag);
|
||
osMessageQueuePut(env->txAccessQueue, &DUMMY_BYTE, 0, 0);
|
||
}
|
||
}
|
||
|
||
void SerialPort_IrqProcessing_DmaTxBlind(tSerialPortArtery *env) {
|
||
if (dma_flag_get(env->txDmaFdtFlag)) {
|
||
dma_flag_clear(env->txDmaFdtFlag);
|
||
// osMessageQueuePut(env->txAccessQueue, &DUMMY_BYTE, 0, 0);
|
||
}
|
||
}
|
||
|
||
|
||
void vSerialPortIrqProcessing(tSerialPortArtery *env) {
|
||
|
||
uint8_t data;
|
||
while (usart_flag_get(env->uart, USART_RDBF_FLAG)) {
|
||
data = usart_data_receive(env->uart);
|
||
osMessageQueuePut(env->rxDataQueue, &data, 0x0, 0U);
|
||
if (env->rxDataSnifferQueue) {
|
||
osMessageQueuePut(env->rxDataSnifferQueue, &data, 0x0, 0U);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
static uint16_t vSerialPortReceiveQueue(tSerialPortArtery *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 uint16_t vSerialPortReceive(tSerialPortArtery *env, uint8_t *data, uint16_t size, uint32_t timeout) {
|
||
return vSerialPortReceiveQueue(env, data, size, timeout, env->rxDataQueue);
|
||
}
|
||
|
||
static uint16_t vSerialPortReceiveSniffer(tSerialPortArtery *env, uint8_t *data, uint16_t size, uint32_t timeout) {
|
||
|
||
return env->rxDataSnifferQueue
|
||
? vSerialPortReceiveQueue(env, data, size, timeout, env->rxDataSnifferQueue)
|
||
: 0;
|
||
}
|
||
|
||
static uint16_t vSerialPortReceiveSnifferSecond(tSerialPortArtery *env, uint8_t *data, uint16_t size, uint32_t timeout) {
|
||
|
||
return env->rxDataSnifferSecondQueue
|
||
? vSerialPortReceiveQueue(env, data, size, timeout, env->rxDataSnifferSecondQueue)
|
||
: 0;
|
||
}
|
||
|
||
static uint16_t vSerialPortTransmitOverDma(tSerialPortArtery *env, uint8_t *data, uint16_t size, uint32_t timeout) {
|
||
uint16_t sent = 0;
|
||
uint32_t endMs = SystemGetMs() + timeout;
|
||
|
||
dma_channel_enable(env->txDmaChannel, FALSE);
|
||
env->dma_tx_init_struct.buffer_size = size;
|
||
env->dma_tx_init_struct.memory_base_addr = (uint32_t) data;
|
||
dma_init(env->txDmaChannel, &env->dma_tx_init_struct);
|
||
dma_channel_enable(env->txDmaChannel, TRUE);
|
||
|
||
uint8_t res;
|
||
|
||
sent = (osMessageQueueGet(env->txAccessQueue, &res, 0, timeout) == osOK) ? size : 0;
|
||
|
||
// SystemDelayMs(10);
|
||
//
|
||
// while ((timeout == SystemWaitForever) || (endMs > SystemGetMs())) {
|
||
// if (dma_flag_get(env->txDmaFdtFlag) != RESET)
|
||
// break;
|
||
// SystemDelayMs(5);
|
||
// }
|
||
|
||
while ((timeout == SystemWaitForever) || (endMs > SystemGetMs())) {
|
||
if (usart_flag_get(env->uart, USART_TDC_FLAG))
|
||
break;
|
||
}
|
||
|
||
dma_channel_enable(env->txDmaChannel, FALSE);
|
||
|
||
// sent = size;
|
||
return sent;
|
||
}
|
||
|
||
static uint16_t
|
||
vSerialPortTransmitOverCore(tSerialPortArtery *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;
|
||
}
|
||
|
||
|
||
uint16_t vSerialPortBlindTransmit(tSerialPortArtery *env, uint8_t *data, uint16_t size, uint32_t timeout) {
|
||
|
||
uint16_t sent = 0;
|
||
uint32_t endMs = SystemGetMs() + timeout;
|
||
|
||
|
||
while ((timeout == SystemWaitForever) || (endMs > SystemGetMs())) {
|
||
if (usart_flag_get(env->uart, USART_TDC_FLAG))
|
||
break;
|
||
else {
|
||
asm("nop");
|
||
}
|
||
}
|
||
|
||
// dma_channel_enable(env->txDmaChannel, FALSE);
|
||
|
||
dma_channel_enable(env->txDmaChannel, FALSE);
|
||
env->dma_tx_init_struct.buffer_size = size;
|
||
env->dma_tx_init_struct.memory_base_addr = (uint32_t) data;
|
||
dma_init(env->txDmaChannel, &env->dma_tx_init_struct);
|
||
dma_channel_enable(env->txDmaChannel, TRUE);
|
||
|
||
// uint8_t res;
|
||
// int32_t s = SystemGetMs();
|
||
// sent = (osMessageQueueGet(env->txAccessQueue, &res, 0, timeout) == osOK) ? size : 0;
|
||
// int32_t s1 = SystemGetMs();
|
||
// int32_t s3 = s1 - s;
|
||
|
||
|
||
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(tSerialPortArtery *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(tSerialPortArtery *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(tSerialPortArtery *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(tSerialPortArtery *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 = vSerialPortTransmitOverCore(env, txBuffer, idx, timeout);
|
||
|
||
return (sent == idx); // Успех, если все байты отправлены
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
static SerialPortIOTransaction vSerialPortTransmitterGet(tSerialPortArtery *env) {
|
||
|
||
#ifdef UART_DMA_SEND
|
||
if (env->txDmaChannel)
|
||
return (SerialPortIOTransaction) vSerialPortTransmitOverDma;
|
||
else
|
||
return (SerialPortIOTransaction) vSerialPortTransmitOverCore;
|
||
#else
|
||
return (SerialPortIOTransaction) vSerialPortTransmitOverCore;
|
||
#endif
|
||
}
|
||
|
||
tSerialPortIO vSerialPortGetIo(tSerialPortArtery *env) {
|
||
tSerialPortIO io = {
|
||
.env = env,
|
||
.receive = (SerialPortIOTransaction) vSerialPortReceive,
|
||
.transmit = vSerialPortTransmitterGet(env)
|
||
};
|
||
return io;
|
||
}
|
||
|
||
tSerialPortIO vSerialPortGetSnifferIo(tSerialPortArtery *env) {
|
||
tSerialPortIO io = {
|
||
.env = env,
|
||
.receive = (SerialPortIOTransaction) vSerialPortReceiveSniffer,
|
||
.transmit = vSerialPortTransmitterGet(env)
|
||
};
|
||
return io;
|
||
}
|
||
|
||
tSerialPortIO SerialPort_GetSnifferSecondIo(tSerialPortArtery *env) {
|
||
tSerialPortIO io = {
|
||
.env = env,
|
||
.receive = (SerialPortIOTransaction) vSerialPortReceiveSnifferSecond,
|
||
.transmit = vSerialPortTransmitterGet(env)
|
||
};
|
||
return io;
|
||
} |