madeeasy85 Ответов: 1

Как я могу исправить пользовательскую ошибку многопортовой последовательной связи? (Драйвер режима ядра Windows)


Проблема : вывод полученных данных на порт выбрасывает повторяющиеся символы

Правильные данные TX : быстрая бурая лиса перепрыгивает через хвост ленивой собаки и обратно 1234567890
Нет никаких ошибок в данных rx, если комм. находится между только одним UART,но как только прерывания вступают в картину (комм. с 6 UARTs) ,появляются следующие ошибки и вызывают сбой. Это повторяющиеся символы, которых следует избегать.


Быстрая Коричневая Лиса Прыгает Через Ленивую Дж Собакам Хвост И Снова 1234567890
Быстрая Коричневая Лиса Перепрыгивает Через Хвост Ленивой Собаки И Обратно 1234567890
Быстрая Бурая Лиса Перепрыгивает Через Хвост Ленивой Собаки И Обратно 1234567890
Быстрая коричневая Лиса прыгает через ленивую Н собак хвост и снова 1234567890
Быстрая Бурая Лиса Перепрыгивает Через Хвост Ленивой Собаки И Обратно 1 1234567890

#include "SerialPort.h"
#include "SuppFunc.h"

/*
 * Some handy constants. Better an enum than preprocessor macros or global constant.
 */
enum SerialPortConstants
{
	SerialDefXON = 0x11,
	SerialDefXOFF = 0x13,

	MaximumBaudRate = 38400, 		

	BaseMode1Value = 0x00,
	BaseMode2Value = 0x00,
	
	InitialQueueSize = 8192,
	BlockAReceiveInterrupt = 0x02,
	BlockBReceiveInterrupt = 0x20,
	BlockATransmitInterrupt = 0x01,
	BlockBTransmitInterrupt = 0x10,
	FIFOErrorFlags          = 0x70,
	FrameStatusError		= 0x40,
	ParityStatusError		= 0x20,	
	OverrunStatusError		= 0x10,
	RxRDYStatus 			= 0x01,
	FFULLStatus				= 0x02,
	TxRDYStatus 			= 0x04,

	BreakOnCommand			= 0x60,
	BreakOffCommand			= 0x70,
	DisableRxCommand		= 0x02,
	EnableRxCommand			= 0x01,
	MillisecondsTo100Nanoseconds = 10000,
};

/*
 * Private SerialPort function declarations.
 */
 
/*
 * Validates the provided flags against all the valid flags.
 *
 * @param providedFlags, the flags to test.
 * @param allValidFlags, the set of valid flags.
 * @returns 0 if the flags are invalid, anyother value indicates that the flags are valid.
 */
unsigned char SerialPortValidateFlags( ULONG providedFlags, ULONG allValidFlags ); 

/*
 * Resets the serial port connection settings to the default values.
 *
 * @param [in] serialport the serial port to initialise the attributes of.
 */
void SerialPortResetConnectionSettings( SerialPort* serialPort );

/*
 * Increases the size of the suppied queue to the required size. If the queue is
 * already big enough no action is taken.
 *
 * @param [in/out] queue the queue to update.
 * @param [in] newSize the new size of the queue.
 */
void UpdateQueue( Queue* queue, unsigned int newSize );

/*
 * Transmits the next byte from the transmit queue to the Tx register of the supplied serial port.
 *
 * @param [in/out] serialPort the serial port to transmit data to.
 */
void SerialPortTransmitByte( SerialPort* serialPort );

/*
 * Receives a byte from the serial port and adds it to the receive queue.
 *
 * @param [in/out] serialPort the serial port to receive data from.
 */
void SerialPortReceiveByte( SerialPort* serialPort );

/*
 * This function will cancel a read request for the suppiled serial port if one is pending.
 *
 * @param [in] serialPort the serial port to cancel any pending reads on.
 */
void TryCancellingRead( SerialPort* serialPort );

/*
 * Provides access to the read transfer data and then resets those values in the serial port.
 *
 * @param [in] serialPort the serial port to get the read transfer data from.
 * @param [in/out] bufferLength the length of the client supplied buffer in the IRP.
 * @returns a pointer to the IRP for the read.
 */
PIRP GetAndResetPendingRead( SerialPort* serialPort, unsigned int* bufferLength );

/*
 * This function will cancel a write request for the suppiled serial port if one is pending.
 *
 * @param [in] serialPort the serial port to cancel any pending write on.
 */
void TryCancellingWrite( SerialPort* serialPort );

/*
 * Provides access to the write transfer data and then resets those values in the serial port.
 *
 * @param [in] serialPort the serial port to get the write transfer data from.
 * @param [in/out] bufferLength the length of the client supplied buffer in the IRP.
 * @returns a pointer to the IRP for the write.
 */
PIRP GetAndResetPendingWrite( SerialPort* serialPort, unsigned int* bufferLength );

/*
 * Processes the interrupts of a UART.
 *
 * @param [in] serialPort the serial port to process.
 * @param [in] interruptStatusValue the value of the interrupt status register for the DUART that the serial port is part of.
 * @param [in] transmitInterruptMask the tranmit interrupt mask for this type of serial port.
 * @param [in] receiveInterruptMask the receive interrupt mask for this type of serial port.
 */
void ProcessUARTInterrupts( SerialPort* serialPort, UARTRegisterValue interruptStatusValue, UARTRegisterValue transmitInterruptMask, UARTRegisterValue receiveInterruptMask );

/*++

Routine Description:

    This routine is used to cancel the current read.

Arguments:

    Device - Wdf device handle

    Request - Pointer to the WDFREQUEST to be canceled.

Return Value:

    None.

--*/
DRIVER_CANCEL SerialCancelCurrentRead;
void SerialCancelCurrentRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );

/*
 * Reads from the receive buffer until either the supplied numberOfBytes is read or the buffer is empty.
 *
 * @param [in] serialPort the serial port buffer to read from.
 * @param [in] numberOfBytes the number of bytes in the supplied buffer.
 * @param [out] buffer the buffer to put the received data into.
 * @param [out] numberOfBytesRead gets set to the number of bytes actually read.
 */
#define SerialPortCopyFromReceiveBuffer( serialPort, numberOfBytes, buffer, numberOfBytesRead ) ( *numberOfBytesRead = FillBufferFromQueue( &serialPort->receiveQueue, buffer, numberOfBytes ) )

/*
 * Writes to the transmit queue until either the supplied numberOfBytes is written or the queue is full.
 *
 * @param [in] serialPort the serial port buffer to write to.
 * @param [in] numberOfBytes the number of bytes in the supplied buffer.
 * @param [out] buffer the buffer to get the data to transmit from.
 * @param [out] numberOfBytesWritten gets set to the number of bytes actually written.
 */
#define SerialPortCopyToWriteBuffer( serialPort, numberOfBytes, buffer, numberOfBytesWritten ) ( *numberOfBytesWritten = FillQueueFromBuffer( &serialPort->transmitQueue, buffer, numberOfBytes ) )

/*
 * Resets the mode register pointer of the supplied UART.
 *
 * @param [in] _serialPort the serial port to write to.
 * @returns 1 if successful or 0 if an error occured.
 */
#define ResetSerialPortModeRegisterPointer( _serialPort ) ResetUARTModeRegisterPointer( _serialPort->baseAddress, _serialPort->uartType )

/*
 * Reset the receiver, this resets the FIFO pointer to the begginning and disables the receiver.
 *
 * @param [in] _serialPort the serial port to reset.
 * @returns 1 if successful or 0 if an error occured.
 */
#define SerialPortResetReceiver( _serialPort ) ResetReceiver( _serialPort->baseAddress, _serialPort->uartType )

/*
 * Write to a serial port register.
 *
 * @param [in] _serialPort the serial port to write to.
 * @param [in] _uartRegister the register to write to.
 * @param [in] _value the value to write to the register.
 * @returns 1 if successful or 0 if an error occured.
 */
#define WriteSerialPortRegister( _serialPort, _uartRegister, _value ) WriteUARTRegister( _serialPort->baseAddress, _uartRegister, _serialPort->uartType, _value )

/*
 * Read from a serial port register.
 *
 * @param [in] _serialPort the serial port to read from.
 * @param [in] _uartRegister the register to read from.
 * @param [in] _value the address of the value to write the register value to.
 * @returns 1 if successful or 0 if an error occured.
 */
#define ReadSerialPortRegister( _serialPort, _uartRegister, _value ) ReadUARTRegister( _serialPort->baseAddress, _uartRegister, _serialPort->uartType, _value )


NTSTATUS SerialPortInitialise( SerialPort* serialPort, unsigned char deviceNumber )
{
	NTSTATUS status = STATUS_SUCCESS;
	unsigned long baseAddress = 0;
	UARTType uartType = UARTDummyUnit;
	unsigned char uartId = 255;
	
	if ( serialPort == NULL )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		if ( deviceNumber != 0 )
		{
			baseAddress = ( ( deviceNumber - 1 ) / 2 ) * UARTPairRegistersSize;
		
			if ( ( ( deviceNumber - 1 ) % 2 ) == 0 )
			{
				uartType = UARTUnitA;
			}
			else
			{
				uartType = UARTUnitB;
			}
			
			uartId = deviceNumber - 1;
		}

		DebugPrintf((	"SerialPortInitialise: device id: %u, base address: %u, UART type: %s\n",
						deviceNumber, baseAddress,
						( ( uartType == UARTUnitA ) ? "UARTUnitA" :
						( ( uartType == UARTUnitB ) ? "UARTUnitB" : "UARTDummyUnit" ) ) ));

		serialPort->uartId = uartId;		
		serialPort->baseAddress = baseAddress;
		serialPort->uartType = uartType;
		
		serialPort->open = 0;
		serialPort->waitMask.currentWaitMask = 0;
		serialPort->waitMask.waitOnMaskPending = 0;
		serialPort->waitMask.pIrp = NULL;
		serialPort->waitMask.waitEvents = NULL;
		
		serialPort->pendingRead.pIrp = NULL;
		serialPort->pendingRead.bufferLength = 0;
		
		KeInitializeSpinLock( &serialPort->pendingRead.lock );

		SerialPortResetConnectionSettings( serialPort );
	
		InitialiseQueueLock( &serialPort->receiveQueue );
		InitialiseQueueLock( &serialPort->transmitQueue );
		
		InitializeListHead( &serialPort->readCompletionWorkerList );
		KeInitializeSpinLock( &serialPort->readCompletionWorkerListLock );
		serialPort->readCompletionWorkerActive = 0;
		
		SerialPortClearStats( serialPort );
		
		serialPort->numberOfQueuedWriteBytes = 0;
		
		// initialise the queue, it is important that the buffer pointer is initialised to NULL before the first call.
		LockQueue( &serialPort->receiveQueue );

		// as the queues of this port are not yet in operation it's safe to initialise the buffer without locking.
		serialPort->receiveQueue.buffer = NULL;
		
		InitialiseQueue( &serialPort->receiveQueue, InitialQueueSize );
		
		UnlockQueue( &serialPort->receiveQueue );
		
		LockQueue( &serialPort->transmitQueue );

		serialPort->transmitQueue.buffer = NULL;
			
		InitialiseQueue( &serialPort->transmitQueue, InitialQueueSize );
			
		UnlockQueue( &serialPort->transmitQueue );
	}
	
	return status;
}

NTSTATUS SerialPortOpen( SerialPort* serialPort )
{
	NTSTATUS status = STATUS_SUCCESS;
	UARTRegisterValue dataElement;

	if ( serialPort == NULL )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		if ( serialPort->open == 1 )
		{
			status = STATUS_ACCESS_DENIED;
		}
		else
		{
		    // set the open flag.
			serialPort->open = 1;
			
			// initialise the queue
			LockQueue( &serialPort->receiveQueue );

			InitialiseQueue( &serialPort->receiveQueue, InitialQueueSize );
			
			UnlockQueue( &serialPort->receiveQueue );
			
			LockQueue( &serialPort->transmitQueue );

			InitialiseQueue( &serialPort->transmitQueue, InitialQueueSize );
				
			UnlockQueue( &serialPort->transmitQueue );
		
			serialPort->numberOfQueuedWriteBytes = 0;
	
			SerialPortClearStats( serialPort );
			
			if ( OpenUART( serialPort->baseAddress, serialPort->uartType ) == 0 )
			{
				DebugPrintf(( "Failed to Open the UART.\n" ));
			}
		}
	}

	return status;
}

NTSTATUS SerialPortClose( SerialPort* serialPort )
{
	NTSTATUS status = STATUS_SUCCESS;
	unsigned int debugStat = 0;

	if ( serialPort == NULL )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		if ( serialPort->waitMask.pIrp != NULL )
		{
			PlxCompleteIrpWithInformation( serialPort->waitMask.pIrp, STATUS_SUCCESS, 0 );
			serialPort->waitMask.pIrp = NULL;
		}
		
		serialPort->open = 0;
	
		serialPort->waitMask.currentWaitMask = 0;
		serialPort->waitMask.waitOnMaskPending = 0;
		serialPort->waitMask.waitEvents = NULL;
		
		TryCancellingRead( serialPort );
		TryCancellingWrite( serialPort ); // TODO: get this to cancel all pending write requests.

		SerialPortResetConnectionSettings( serialPort );
		
		// ensure that the queue is freed.
		LockQueue( &serialPort->receiveQueue );
		FreeQueue( &serialPort->receiveQueue );
		UnlockQueue( &serialPort->receiveQueue );
		
		LockQueue( &serialPort->transmitQueue );
		FreeQueue( &serialPort->transmitQueue );
		UnlockQueue( &serialPort->transmitQueue );
		
		if ( CloseUART( serialPort->baseAddress, serialPort->uartType ) == 0 )
		{
			DebugPrintf(( "Failed to Close the UART.\n" ));
		}
	}

	return status;
}

NTSTATUS SerialPortSetQueueSize( SerialPort* serialPort, PSERIAL_QUEUE_SIZE serialQueueSize )
{
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( ( serialQueueSize == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		DebugPrintf(( "SerialPortSetQueueSize InSize %d, OutSize %d\n", serialQueueSize->InSize, serialQueueSize->OutSize ));
		
		UpdateQueue( &serialPort->receiveQueue, serialQueueSize->InSize );
		UpdateQueue( &serialPort->transmitQueue, serialQueueSize->OutSize );
	}
	
	return status;
}

NTSTATUS SerialPortConfigSize( SerialPort* serialPort, PULONG configSize )
{
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( ( configSize == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		*configSize = 0; // According to MSDN this IO control code is obsolete, so we set the size to 0.
		
		DebugPrintf(( "SerialPortConfigSize %d\n", *configSize ));
	}
	
	return status;
}

NTSTATUS SerialPortGetBaudRate( SerialPort* serialPort, PSERIAL_BAUD_RATE baudRate )
{			
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( ( baudRate == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		baudRate->BaudRate = serialPort->baudRate;
		
		DebugPrintf(( "SerialPortGetBaudRate %d\n", baudRate->BaudRate ));
	}
	
	return status;
}

NTSTATUS SerialPortSetBaudRate( SerialPort* serialPort, PSERIAL_BAUD_RATE baudRate )
{
	NTSTATUS status = STATUS_SUCCESS;
		
	UARTRegisterValue csrData;
	
	if ( ( baudRate == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		DebugPrintf(( "SerialPortSetBaudRate %u\n", baudRate->BaudRate ));
		
		if ( GetBAUDRate( baudRate->BaudRate, &csrData ) == 0 )
		{
			// The baud rate is not valid.
			status = STATUS_INVALID_PARAMETER;
			DebugPrintf(( "Invalid baud rate %u\n", baudRate->BaudRate ));
		}
		else
		{
			serialPort->baudRate = baudRate->BaudRate;
			
			WriteSerialPortRegister( serialPort, StatusAndClockSelect, csrData );
		}
	}
	
	return status;
}

NTSTATUS SerialPortGetLineControl( SerialPort* serialPort, PSERIAL_LINE_CONTROL lineControl )
{			
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( ( lineControl == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		lineControl->WordLength = serialPort->lineControl.WordLength;
		lineControl->Parity = serialPort->lineControl.Parity;
		lineControl->StopBits = serialPort->lineControl.StopBits;
		
		DebugPrintf(( "SerialPortGetLineControl -> WordLength: %d, Parity: %d, StopBits: %d\n", lineControl->WordLength, lineControl->Parity, lineControl->StopBits ));
	}
	
	return status;
}

NTSTATUS SerialPortSetLineControl( SerialPort* serialPort, PSERIAL_LINE_CONTROL lineControl )
{
	NTSTATUS status = STATUS_SUCCESS;
	UARTRegisterValue dataBits;
	UARTRegisterValue parity;
	UARTRegisterValue stopBits;
	unsigned char fiveStopBits = 0;
	
	if ( ( lineControl == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		if ( ResetSerialPortModeRegisterPointer( serialPort ) == 0 )
		{
			status = STATUS_INVALID_PARAMETER;
			DebugPrintf(( "SerialPortSetLineControl -> FAILED to Reset the Mode register pointer\n" ));
		}
		else
		{
			if ( GetDataBits( lineControl->WordLength, &dataBits ) == 0 )
			{
				status = STATUS_INVALID_PARAMETER;
				DebugPrintf(( "SerialPortSetLineControl -> FAILED to GetDataBits WordLength: %d\n", lineControl->WordLength ));
			}
			else
			{
				if ( GetParity( lineControl->Parity, &parity ) == 0 )
				{
					status = STATUS_INVALID_PARAMETER;
					DebugPrintf(( "SerialPortSetLineControl -> FAILED to GetParity Parity: %d\n", lineControl->Parity ));
				}
				else
				{
					if ( lineControl->WordLength == 5 )
					{
						fiveStopBits = 1;
					}
					
					if ( GetStopBits( lineControl->StopBits, &stopBits, fiveStopBits ) == 0 )
					{
						status = STATUS_INVALID_PARAMETER;
						DebugPrintf(( "SerialPortSetLineControl -> FAILED to GetStopBits StopBits: %d\n", lineControl->StopBits ));
					}
					else
					{
						if ( WriteSerialPortRegister( serialPort, Mode, parity | dataBits ) == 0 )
						{
							status = STATUS_INVALID_PARAMETER;
							DebugPrintf(( "SerialPortSetLineControl -> FAILED to Write Mode 1 register\n" ));
						}
						else
						{
							serialPort->lineControl.WordLength = lineControl->WordLength;
							serialPort->lineControl.Parity = lineControl->Parity;
								
							if ( WriteSerialPortRegister( serialPort, Mode, stopBits ) == 0 )
							{
								status = STATUS_INVALID_PARAMETER;
								DebugPrintf(( "SerialPortSetLineControl -> FAILED to Write Mode 2 register\n" ));
							}
							else
							{
								serialPort->lineControl.StopBits = lineControl->StopBits;
							}
						}
					}
				}
			}
		}
		
		DebugPrintf(( "SerialPortSetLineControl -> WordLength: %d, Parity: %d, StopBits: %d\n", lineControl->WordLength, lineControl->Parity, lineControl->StopBits ));
	}
	
	return status;
}

NTSTATUS SerialPortGetChars( SerialPort* serialPort, PSERIAL_CHARS chars )
{			
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( ( chars == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		chars->EofChar = serialPort->serialChars.EofChar;
		chars->ErrorChar = serialPort->serialChars.ErrorChar;
		chars->BreakChar = serialPort->serialChars.BreakChar;
		chars->EventChar = serialPort->serialChars.EventChar;
		chars->XonChar = serialPort->serialChars.XonChar;
		chars->XoffChar = serialPort->serialChars.XoffChar;
		
		DebugPrintf(( "SerialPortGetChars -> EofChar: %d, ErrorChar: %d, BreakChar: %d, EventChar: %d, XonChar: %d, XoffChar: %d\n",
					  chars->EofChar, chars->ErrorChar, chars->BreakChar, chars->EventChar, chars->XonChar, chars->XoffChar ));
	}
	
	return status;
}

NTSTATUS SerialPortSetChars( SerialPort* serialPort, PSERIAL_CHARS chars )
{			
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( ( chars == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		serialPort->serialChars.EofChar = chars->EofChar;
		serialPort->serialChars.ErrorChar = chars->ErrorChar;
		serialPort->serialChars.BreakChar = chars->BreakChar;
		serialPort->serialChars.EventChar = chars->EventChar;
		serialPort->serialChars.XonChar = chars->XonChar;
		serialPort->serialChars.XoffChar = chars->XoffChar;
		
		DebugPrintf(( "SerialPortSetChars -> EofChar: %d, ErrorChar: %d, BreakChar: %d, EventChar: %d, XonChar: %d, XoffChar: %d\n",
					  chars->EofChar, chars->ErrorChar, chars->BreakChar, chars->EventChar, chars->XonChar, chars->XoffChar ));
	}
	
	return status;
}

NTSTATUS SerialPortGetHandflow( SerialPort* serialPort, PSERIAL_HANDFLOW handflow )
{
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( ( handflow == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		handflow->ControlHandShake = serialPort->handflow.ControlHandShake;
		handflow->FlowReplace = serialPort->handflow.FlowReplace;
		handflow->XonLimit = serialPort->handflow.XonLimit;
		handflow->XoffLimit = serialPort->handflow.XoffLimit;

		DebugPrintf(( "SerialPortGetHandflow -> ControlHandShake: %X, FlowReplace: %X, XonLimit: %d, XoffLimit: %d\n",
					  handflow->ControlHandShake, handflow->FlowReplace, handflow->XonLimit, handflow->XoffLimit ));
	}
	
	return status;
}

NTSTATUS SerialPortSetHandflow( SerialPort* serialPort, PSERIAL_HANDFLOW handflow )
{
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( ( handflow == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		serialPort->handflow.ControlHandShake = handflow->ControlHandShake;
		serialPort->handflow.FlowReplace = handflow->FlowReplace;
		serialPort->handflow.XonLimit = handflow->XonLimit;
		serialPort->handflow.XoffLimit = handflow->XoffLimit;

		DebugPrintf(( "SerialPortSetHandflow -> ControlHandShake: %X, FlowReplace: %X, XonLimit: %d, XoffLimit: %d\n",
					  handflow->ControlHandShake, handflow->FlowReplace, handflow->XonLimit, handflow->XoffLimit ));
	}
	
	return status;
}

NTSTATUS SerialPortSetRTS( SerialPort* serialPort )
{			
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( serialPort == NULL )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	
	// A status of STATUS_INVALID_PARAMETER indicates that the handshake flow control of the device is set to automatically use RTS.
	//status = STATUS_INVALID_PARAMETER;
	
	DebugPrintf(( "SerialPortSetRTS\n" ));
	
	return status;
}

NTSTATUS SerialPortClearRTS( SerialPort* serialPort )
{			
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( serialPort == NULL )
	{
		status = STATUS_INVALID_PARAMETER;
	}
		
	// A status of STATUS_INVALID_PARAMETER indicates that the handshake flow control of the device is set to automatically use RTS.
	//status = STATUS_INVALID_PARAMETER;
	
	DebugPrintf(( "SerialPortClearRTS\n" ));
	
	return status;
}

NTSTATUS SerialPortSetDTR( SerialPort* serialPort )
{			
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( serialPort == NULL ) 
	{
		status = STATUS_INVALID_PARAMETER;
	}
	
	// A status of STATUS_INVALID_PARAMETER indicates that the handshake flow control of the device is set to automatically use DTR.
	//status = STATUS_INVALID_PARAMETER;
	
	DebugPrintf(( "SerialPortSetDTR\n" ));
	
	return status;
}

NTSTATUS SerialPortClearDTR( SerialPort* serialPort )
{			
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( serialPort == NULL ) 
	{
		status = STATUS_INVALID_PARAMETER;
	}
	
	// A status of STATUS_INVALID_PARAMETER indicates that the handshake flow control of the device is set to automatically use DTR.
	//status = STATUS_INVALID_PARAMETER;
	
	DebugPrintf(( "SerialPortClearDTR\n" ));
	
	return status;
}

NTSTATUS SerialPortSetTimeouts( SerialPort* serialPort, PSERIAL_TIMEOUTS timeouts )
{			
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( ( timeouts == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		// this condition is invalid as specified by the MSDN documentation.
		if ( ( timeouts->ReadIntervalTimeout == MAXULONG ) &&
			 ( timeouts->ReadTotalTimeoutConstant == MAXULONG ) )
		{
			status = STATUS_INVALID_PARAMETER;
		}
		else
		{
			serialPort->timeouts.ReadIntervalTimeout = timeouts->ReadIntervalTimeout;
			serialPort->timeouts.ReadTotalTimeoutMultiplier = timeouts->ReadTotalTimeoutMultiplier;
			serialPort->timeouts.ReadTotalTimeoutConstant = timeouts->ReadTotalTimeoutConstant;
			serialPort->timeouts.WriteTotalTimeoutMultiplier = timeouts->WriteTotalTimeoutMultiplier;
			serialPort->timeouts.WriteTotalTimeoutConstant = timeouts->WriteTotalTimeoutConstant;
		}
		
		DebugPrintf(( "SerialPortSetTimeouts -> ReadIntervalTimeout: %u, ReadTotalTimeoutMultiplier: %u, ReadTotalTimeoutConstant: %u, WriteTotalTimeoutMultiplier: %u, WriteTotalTimeoutConstant: %u\n",
					  timeouts->ReadIntervalTimeout, timeouts->ReadTotalTimeoutMultiplier, timeouts->ReadTotalTimeoutConstant, timeouts->WriteTotalTimeoutMultiplier, timeouts->WriteTotalTimeoutConstant ));
	}
	
	return status;
}

NTSTATUS SerialPortGetTimeouts( SerialPort* serialPort, PSERIAL_TIMEOUTS timeouts )
{			
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( ( timeouts == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		timeouts->ReadIntervalTimeout = serialPort->timeouts.ReadIntervalTimeout;
		timeouts->ReadTotalTimeoutMultiplier = serialPort->timeouts.ReadTotalTimeoutMultiplier;
		timeouts->ReadTotalTimeoutConstant = serialPort->timeouts.ReadTotalTimeoutConstant;
		timeouts->WriteTotalTimeoutMultiplier = serialPort->timeouts.WriteTotalTimeoutMultiplier;
		timeouts->WriteTotalTimeoutConstant = serialPort->timeouts.WriteTotalTimeoutConstant;
		
		DebugPrintf(( "SerialPortGetTimeouts -> ReadIntervalTimeout: %u, ReadTotalTimeoutMultiplier: %u, ReadTotalTimeoutConstant: %u, WriteTotalTimeoutMultiplier: %u, WriteTotalTimeoutConstant: %u\n",
					  timeouts->ReadIntervalTimeout, timeouts->ReadTotalTimeoutMultiplier, timeouts->ReadTotalTimeoutConstant, timeouts->WriteTotalTimeoutMultiplier, timeouts->WriteTotalTimeoutConstant ));
	}
	
	return status;
}

NTSTATUS SerialPortWaitOnMask( SerialPort* serialPort, PULONG waitEvents, PIRP pIrp )
{			
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( ( waitEvents == NULL ) || ( pIrp == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		// A client can wait for the wait events represented by flag bits SERIAL_EV_RXCHAR through SERIAL_EV_EVENT2. For more information about these event flags, see SERIAL_EV_XXX. 
		// A client sends an IOCTL_SERIAL_WAIT_ON_MASK request to wait for the occurrence of an event that was specified in the wait mask supplied by the most recent IOCTL_SERIAL_SET_WAIT_MASK request.
		// If one or more events in the current wait mask occur before the IOCTL_SERIAL_WAIT_ON_MASK request is sent, this request is immediately completed with a status of STATUS_SUCCESS and an output
		// mask value that identifies the events. If no event in the wait mask occurs before the IOCTL_SERIAL_WAIT_ON_MASK request is sent, this request is marked as pending, and it waits in the serial
		// controller queue for the next occurrence of an event in the current wait mask. 
		// After a client's IOCTL_SERIAL_WAIT_ON_MASK request is completed with a status of STATUS_SUCCESS and a nonzero output mask value, the client can send a new IOCTL_SERIAL_WAIT_ON_MASK request to
		// wait for another event in the current wait mask. Only a new event that occurs after the previous IOCTL_SERIAL_WAIT_ON_MASK request was completed will cause the new IOCTL_SERIAL_WAIT_ON_MASK
		// request to be completed with a status of STATUS_SUCCESS and a nonzero output mask value.
		
		// A status of STATUS_INVALID_PARAMETER indicates that no wait events are set, or a wait-on-mask request is already pending.
		if ( ( serialPort->waitMask.currentWaitMask == 0 ) || ( serialPort->waitMask.waitOnMaskPending == 1 ) )
		{
			status = STATUS_INVALID_PARAMETER;
			*waitEvents = 0;
		}
		else
		{
			serialPort->waitMask.waitOnMaskPending = 1;
			status = STATUS_PENDING;
			serialPort->waitMask.pIrp = pIrp;
			serialPort->waitMask.waitEvents = waitEvents;
			*waitEvents = 0;
		}
		
		DebugPrintf(( "SerialPortWaitOnMask 0x%X\n", *waitEvents ));
	}
	
	return status;
}

NTSTATUS SerialPortSetWaitMask( SerialPort* serialPort, PULONG newWaitMask )
{
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( ( newWaitMask == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		// Logically or together all the valid flags, invert that so that we have all the invalid flags set and
		// 'and' this with the provided flags to see if any of the invalid flags are set in the provided flags...
		if ( SerialPortValidateFlags(	*newWaitMask, 
										SERIAL_EV_RXCHAR | SERIAL_EV_RXFLAG |
										SERIAL_EV_TXEMPTY | SERIAL_EV_CTS |
										SERIAL_EV_DSR | SERIAL_EV_RLSD |
										SERIAL_EV_BREAK | SERIAL_EV_ERR |
										SERIAL_EV_RING | SERIAL_EV_PERR |
										SERIAL_EV_RX80FULL | SERIAL_EV_EVENT1 |
										SERIAL_EV_EVENT2 ) == 0 )
		{
			status = STATUS_INVALID_PARAMETER;
		}
		
		if ( status == STATUS_SUCCESS )
		{
			// TODO: If a wait-on-mask request is already pending when a set-wait-mask request is processed,
			//       the pending wait-on-event request is completed with a status of STATUS_SUCCESS and the
			//       output wait event mask is set to zero.
			if ( serialPort->waitMask.waitOnMaskPending == 1 )
			{
				PlxCompleteIrpWithInformation( serialPort->waitMask.pIrp, STATUS_SUCCESS, 0 );
				serialPort->waitMask.waitOnMaskPending = 0;
				serialPort->waitMask.pIrp = NULL;
			}

			// save the wait mask.
			serialPort->waitMask.currentWaitMask = *newWaitMask;
		}
		
		DebugPrintf(( "SerialPortSetWaitMask 0x%X\n", serialPort->waitMask.currentWaitMask ));
	}
	
	return status;
}		

NTSTATUS SerialPortGetWaitMask( SerialPort* serialPort, PULONG waitMask )
{
	NTSTATUS status = STATUS_SUCCESS;

	if ( ( waitMask == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		// get the wait mask.
		*waitMask = serialPort->waitMask.currentWaitMask;

		DebugPrintf(( "SerialPortGetWaitMask 0x%X\n", serialPort->waitMask.currentWaitMask ));
	}
	
	return status;
}

NTSTATUS SerialPortPurge( SerialPort* serialPort, PULONG purgeMask )
{			
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( ( purgeMask == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		// A status of STATUS_INVALID_PARAMETER indicates that the purge mask is not valid.
		if ( SerialPortValidateFlags(	*purgeMask,
										SERIAL_PURGE_RXABORT |
										SERIAL_PURGE_RXCLEAR |
										SERIAL_PURGE_TXABORT |
										SERIAL_PURGE_TXCLEAR ) == 0 )
		{
			status = STATUS_INVALID_PARAMETER;
			DebugPrintf(( "SerialPortPurge invalid flag set %d\n", *purgeMask ));
		}
		else
		{
			if ( *purgeMask & SERIAL_PURGE_RXABORT )
			{
				TryCancellingRead( serialPort );
			}
			
			if ( *purgeMask & SERIAL_PURGE_RXCLEAR )
			{
				TryCancellingRead( serialPort );			
				LockQueue( &serialPort->receiveQueue );				
				InitialiseQueue( &serialPort->receiveQueue, serialPort->receiveQueue.size );
				UnlockQueue( &serialPort->receiveQueue );
			}
			
			if ( *purgeMask & ( SERIAL_PURGE_TXABORT | SERIAL_PURGE_TXCLEAR ) )
			{
				TryCancellingWrite( serialPort );
			}
			
			DebugPrintf(( "SerialPortPurge 0x%.1X\n", *purgeMask ));
		}
	}
	
	return status;
}

NTSTATUS SerialPortGetCommStatus( SerialPort* serialPort, PSERIAL_STATUS serialStatus )
{			
	NTSTATUS status = STATUS_SUCCESS;
	ULONG currentTxQueueUsed = 0;
	ULONG currentRxQueueUsed = 0;	
	
	if ( ( serialStatus == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		LockQueue( &serialPort->receiveQueue );
		currentRxQueueUsed = serialPort->receiveQueue.used;
		UnlockQueue( &serialPort->receiveQueue );

		LockQueue( &serialPort->transmitQueue );
		currentTxQueueUsed = serialPort->transmitQueue.used;
		UnlockQueue( &serialPort->transmitQueue );
		
		serialStatus->Errors = 0;
		serialStatus->HoldReasons = 0;
		serialStatus->AmountInInQueue = currentRxQueueUsed;
		serialStatus->AmountInOutQueue = currentTxQueueUsed;
		serialStatus->EofReceived = 0;
		serialStatus->WaitForImmediate = 0;
				
		DebugPrintf(( "SerialPortGetCommStatus\n"));
		//DebugPrintf(( "SerialGetCommStatus -> Errors: %d, HoldReasons: %d, AmountInInQueue: %d, AmountInOutQueue: %d, EofReceived: %d, WaitForImmediate: %d\n",
		//			  serialStatus->Errors, serialStatus->HoldReasons, serialStatus->AmountInInQueue, serialStatus->AmountInOutQueue, serialStatus->EofReceived, serialStatus->WaitForImmediate ));
	}
	
	return status;
}

NTSTATUS SerialPortGetProperties( SerialPort* serialPort, PSERIAL_COMMPROP commProperties )
{
	NTSTATUS status = STATUS_SUCCESS;
	ULONG currentTxQueueSize = 0;
	ULONG currentRxQueueSize = 0;
	
	if ( ( commProperties == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		commProperties->PacketLength = sizeof( SERIAL_COMMPROP );
		commProperties->PacketVersion = 2;
		commProperties->ServiceMask = SERIAL_SP_SERIALCOMM;
		commProperties->MaxTxQueue = 0;
		commProperties->MaxRxQueue = 0;
		commProperties->MaxBaud = SERIAL_BAUD_38400;
		commProperties->ProvSubType = SERIAL_SP_RS232;
		commProperties->ProvCapabilities =	//SERIAL_PCF_DTRDSR | // DTR data terminal ready) and DSR (data set ready) are supported.
								//SERIAL_PCF_RTSCTS | // RTS (request to send) and CTS (clear to send) are supported.
								//SERIAL_PCF_CD | // CD (carrier detect) is supported.
								SERIAL_PCF_PARITY_CHECK | // Parity checking is supported.
								//SERIAL_PCF_XONXOFF | // XON (transmit on) and XOFF (transmit off) flow control are supported.
								SERIAL_PCF_SETXCHAR | // The XON and XOFF characters are settable.
								SERIAL_PCF_TOTALTIMEOUTS | // Total-elapsed-time time-outs are supported.
								SERIAL_PCF_INTTIMEOUTS | // Interval time-outs are supported.
								SERIAL_PCF_SPECIALCHARS; // Special characters are supported.

		commProperties->SettableParams =	SERIAL_SP_PARITY | // Parity type (even or odd)
								SERIAL_SP_BAUD | // Baud rate
								SERIAL_SP_DATABITS | // Data bits
								SERIAL_SP_STOPBITS | // Stop bits
								//SERIAL_SP_HANDSHAKING; // Handshaking (flow control) NO FLOW CONTROL!!! This is hardwired on the T48 DMX cards.
								SERIAL_SP_PARITY_CHECK;

		// other supported baud rates are: 50, 200, 1050, 2000.
		commProperties->SettableBaud =	SERIAL_BAUD_075 | // 75 bps
							SERIAL_BAUD_110 | // 110 bps
							SERIAL_BAUD_150 | // 150 bps
							SERIAL_BAUD_300 | // 300 bps
							SERIAL_BAUD_600 | // 600 bps
							SERIAL_BAUD_1200 | // 1,200 bps
							SERIAL_BAUD_1800 |
							SERIAL_BAUD_2400 | // 2,400 bps
							SERIAL_BAUD_4800 | // 4,800 bps
							SERIAL_BAUD_9600 | // 9,600 bps
							SERIAL_BAUD_19200 | // 19,200 bps
							SERIAL_BAUD_38400; // 38,400 bps

		commProperties->SettableData =	SERIAL_DATABITS_5 | //5 data bits
							SERIAL_DATABITS_6 | //6 data bits
							SERIAL_DATABITS_7 | //7 data bits
							SERIAL_DATABITS_8;

		commProperties->SettableStopParity =	SERIAL_STOPBITS_10 | // One stop bit.
									SERIAL_STOPBITS_15 | // One and a half stop bits.
									SERIAL_STOPBITS_20 | // Two stop bits.
									SERIAL_PARITY_NONE | // No parity bit is used.
									SERIAL_PARITY_ODD | // Odd parity. The parity bit is 1 if the number of 1s in the character value is even. Otherwise, the parity bit is 0.
									SERIAL_PARITY_EVEN | // Even parity. The parity bit is 1 if the number of 1s in the character value is odd. Otherwise, the parity bit is 0.
									SERIAL_PARITY_MARK | // The parity bit is always set to 1.
									SERIAL_PARITY_SPACE;

		LockQueue( &serialPort->receiveQueue );
		currentRxQueueSize = serialPort->receiveQueue.size;
		UnlockQueue( &serialPort->receiveQueue );

		commProperties->CurrentTxQueue = currentTxQueueSize;
		commProperties->CurrentRxQueue = currentRxQueueSize;
		commProperties->ProvSpec1 = 0;
		commProperties->ProvSpec2 = 0;
		commProperties->ProvChar[0] = 0;

		DebugPrintf(( "SerialPortGetProperties\n" ));
	}
	
	return status;
}

NTSTATUS SerialPortWrite( SerialPort* serialPort, unsigned int numberOfBytes, void* buffer, unsigned int* numberOfBytesWritten, PIRP pIrp )
{
	NTSTATUS status = STATUS_SUCCESS;
	LARGE_INTEGER dueTime = { 0 };

	//DebugPrintf_Cont(( "(Length: %u) ...", numberOfBytes ));
	
	if ( ( numberOfBytesWritten == NULL ) || ( buffer == NULL ) || ( serialPort == NULL ) )
	{
		if ( numberOfBytesWritten != NULL )
		{
			*numberOfBytesWritten = 0;
		}
		
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		if ( numberOfBytes == 0 )
		{
			*numberOfBytesWritten = 0;
		}
		else
		{
			SerialPortCopyToWriteBuffer( serialPort, numberOfBytes, buffer, numberOfBytesWritten );
			
			dueTime.QuadPart = -((LONGLONG)( ( serialPort->timeouts.WriteTotalTimeoutMultiplier * numberOfBytes ) + serialPort->timeouts.WriteTotalTimeoutConstant ) * MillisecondsTo100Nanoseconds );

			if ( dueTime.QuadPart != 0 )
			{
				KeSetTimer( &serialPort->writeTimeout.timer, dueTime, &serialPort->writeTimeout.timeoutDpc );
			}
			
			//if ( serialPort->transmitQueue.used > 0 )
			{
				SetWriteInterrupt( serialPort->baseAddress, serialPort->uartType );
			}
		}
	}
	
	return status;
}

NTSTATUS SerialPortRead( SerialPort* serialPort, unsigned int numberOfBytes, void* buffer, unsigned int* numberOfBytesRead, PIRP pIrp )
{
	KIRQL cancelIRQL;
	NTSTATUS status = STATUS_SUCCESS;

	unsigned char pendRequest = 0;
	LARGE_INTEGER dueTime = { 0 };
	unsigned int receiveQueueUsed = 0;

	if ( numberOfBytesRead != NULL )
	{
		*numberOfBytesRead = 0;
	}	
	
	if ( ( numberOfBytesRead == NULL ) || ( buffer == NULL ) || ( serialPort == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		if ( ( serialPort->timeouts.ReadIntervalTimeout == MAXULONG ) &&
			 ( serialPort->timeouts.ReadTotalTimeoutConstant == 0 ) && 
			 ( serialPort->timeouts.ReadTotalTimeoutMultiplier == 0 ) )
		{
			
		}
		else
		{
			LockQueue( &serialPort->receiveQueue );
			receiveQueueUsed = serialPort->receiveQueue.used;
			UnlockQueue( &serialPort->receiveQueue );
		
			if ( ( serialPort->timeouts.ReadIntervalTimeout == MAXULONG ) &&
				 ( serialPort->timeouts.ReadTotalTimeoutMultiplier == MAXULONG ) &&
				 ( serialPort->timeouts.ReadTotalTimeoutConstant < MAXULONG ) )
			{
				
				if ( receiveQueueUsed == 0 )
				{
					pendRequest = 1;
					numberOfBytes = 1;
				}
			}
			else if ( receiveQueueUsed < numberOfBytes ) 
			{
				pendRequest = 1;
			}
		}
		
		if ( pendRequest == 1 )
		{
			status = STATUS_PENDING;
			
			KeAcquireSpinLock( &serialPort->pendingRead.lock, &serialPort->pendingRead.irqlOriginal );
			
			serialPort->pendingRead.pIrp = pIrp;
			serialPort->pendingRead.bufferLength = numberOfBytes;
			
			IoAcquireCancelSpinLock( &cancelIRQL );
			IoSetCancelRoutine( pIrp, SerialCancelCurrentRead );
			IoReleaseCancelSpinLock( cancelIRQL );
			
			KeReleaseSpinLock( &serialPort->pendingRead.lock, serialPort->pendingRead.irqlOriginal );
			
			IoMarkIrpPending( pIrp );
			
			dueTime.QuadPart = -((LONGLONG)( ( serialPort->timeouts.ReadTotalTimeoutMultiplier * numberOfBytes ) + serialPort->timeouts.ReadTotalTimeoutConstant ) * MillisecondsTo100Nanoseconds );
			
			if ( dueTime.QuadPart != 0 )
			{
				KeSetTimer( &serialPort->readTimeout.timer, dueTime, &serialPort->readTimeout.timeoutDpc );
			}
		}
		else
		{
			SerialPortCopyFromReceiveBuffer( serialPort, numberOfBytes, buffer, numberOfBytesRead );
		}
	}

	return status;
}

NTSTATUS SerialPortClearStats( SerialPort* serialPort )
{
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( serialPort == NULL )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		serialPort->performanceStats.ReceivedCount = 0;
		serialPort->performanceStats.TransmittedCount = 0;
		serialPort->performanceStats.FrameErrorCount = 0;
		serialPort->performanceStats.SerialOverrunErrorCount = 0;
		serialPort->performanceStats.BufferOverrunErrorCount = 0;
		serialPort->performanceStats.ParityErrorCount = 0;
		
		DebugPrintf(( "SerialClearStats\n" ));
	}
	
	return status;
}

NTSTATUS SerialPortGetStats( SerialPort* serialPort, SERIALPERF_STATS* performanceStats )
{
	NTSTATUS status = STATUS_SUCCESS;
		
	if ( ( serialPort == NULL ) || ( performanceStats == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		performanceStats->ReceivedCount = serialPort->performanceStats.ReceivedCount;
		performanceStats->TransmittedCount = serialPort->performanceStats.TransmittedCount;
		performanceStats->FrameErrorCount = serialPort->performanceStats.FrameErrorCount;
		performanceStats->SerialOverrunErrorCount = serialPort->performanceStats.SerialOverrunErrorCount;
		performanceStats->BufferOverrunErrorCount = serialPort->performanceStats.BufferOverrunErrorCount;
		performanceStats->ParityErrorCount = serialPort->performanceStats.ParityErrorCount;
		
		DebugPrintf(( "SerialGetStats: ReceivedCount %d, TransmittedCount %d, FrameErrorCount %d, SerialOverrunErrorCount %d, BufferOverrunErrorCount %d, ParityErrorCount %d\n",
						serialPort->performanceStats.ReceivedCount,
						serialPort->performanceStats.TransmittedCount,
						serialPort->performanceStats.FrameErrorCount,
						serialPort->performanceStats.SerialOverrunErrorCount,
						serialPort->performanceStats.BufferOverrunErrorCount,
						serialPort->performanceStats.ParityErrorCount ));
	}
	
	return status;
}

NTSTATUS SerialPortGetDTRRTS( SerialPort* serialPort, PULONG dtrRts )
{
	//SERIAL_DTR_STATE | SERIAL_RTS_STATE
	NTSTATUS status = STATUS_SUCCESS;
	
	if ( ( serialPort == NULL ) || ( dtrRts == NULL ) )
	{
		status = STATUS_INVALID_PARAMETER;
	}
	else
	{
		*dtrRts = 0;
		
		DebugPrintf(( "SerialPortGetDTRRTS\n" ));
	}
	
	return status;
}


Что я уже пробовал:

1.отключил keAquireSpinlock и keReleasespinlock - что снизило частоту ошибок, но основная проблема повторения символов сохраняется.

Richard MacCutchan

Пожалуйста, отредактируйте свой вопрос и удалите весь этот неформатированный дамп кода. Если у вас есть конкретный вопрос, пожалуйста, напишите его. Но не стоит просто сбрасывать весь свой код и ожидать, что кто-то отладит его для вас.

Gerry Schmitz

Похоже на проблему с указателем буфера.

Rick York

- Лучше перечисление, чем макросы препроцессора или глобальная константа."

Чем перечисление лучше глобальной константы? По сути, это одно и то же. Одно из отличий заключается в том, что вы можете легко столкнуться с проблемами типа переменной, используя перечисляемое значение вместо константы с конкретным типом, для которого оно используется. На мой взгляд, лучше иметь их в качестве констант в пространстве имен, чтобы все типы были правильными. FWIW, класс со всеми статическими членами и методами фактически является тем же самым, что и пространство имен.

Кроме того, эти макросы функций могут и должны быть встроенными функциями. Макросов следует избегать, если только не существует жизнеспособной альтернативы.

И последнее - для блокировки ресурсов мне очень не нравятся явные вызовы блокировки и разблокировки. Я предпочитаю использовать экскурсионный класс, который является формой RAII. Класс выполнял бы блокировку при строительстве и разблокировку при разрушении. Конечным результатом является блокировка ресурса на время существования объекта. Затем возникает вопрос о предоставлении соответствующей области видимости для определения правильного времени жизни объекта.

1 Ответов

Рейтинг:
0

Stefan_Lang

Я не буду утруждать себя анализом такого количества кода, это ваша задача. Я подозреваю, что одна из ваших функций копирует неправильную часть вашего буфера. Я предлагаю один из двух подходов:

1. проследите за потоком в вашей программе от получения данных до вывода, и каждый раз, когда что-то делается с выводом, печатайте короткую метку, указывающую, где в программе вы находитесь, и текущее состояние вывода. Это должно дать вам представление о том, где добавляются нежелательные символы.

2. еще лучше, используйте отладчик, остановитесь на функции, которая получает данные, а затем проверьте состояние выходных данных на каждом шаге процесса. То же самое, что и 1, за исключением того, что вам не нужно загрязнять свой код несвязанными распечатками.

Независимо от того, по какому пути вы идете, проверьте код непосредственно перед тем, как произойдет нежелательное изменение, чтобы найти ошибку. Если вы не можете обнаружить его, вы можете вернуться сюда, указать на подозрительный код и сказать нам, какой результат вы видите после этого конкретного шага и чего вы ожидаете.

С. П.:
Поскольку ваши данные поступают асинхронно, вариант 2 может быть сложным, поскольку отладка неизбежно влияет на порядок событий. Может быть, вы могли бы попробовать третий вариант, основанный на первом, записав записи событий в локальный буфер потока вместо того, чтобы печатать их в cout: просто сохраните строку, которую вы иначе напечатали бы, и отметку времени вместе с ней. Затем, в конце программы, соберите все буферы событий, отсортируйте их по отметке времени и распечатайте события в порядке их появления.