Click here to Skip to main content
15,890,741 members
Please Sign up or sign in to vote.
1.00/5 (4 votes)
See more:
Problem : OUTPUT OF THE RECEIVED DATA AT THE PORT THROWS REPEAT CHARACTERS

CORRECT TX DATA : The Quick Brown Fox Jumps Over The Lazy Dogs Tail And Back Again 1234567890
There are no errors in the rx data if the comm. is between only one UART,but as soon as interrupts come into picture (to comm. with 6 UARTs) ,following error appear and cause failure. Its the repeat characters that should be avoided.


The Quick Brown Fox J Jumps Over The Lazy Dogs Tail And Back Again 1234567890
The Quick Brownwn Fox Jumps Over The Lazy Dogs Tail And Back Again 1234567890
The Quick Brown Fox Jumps Over Thehe Lazy Dogs Tail And Back Again 1234567890
The Quick Brown n Fox Jumps Over The Lazy Dogs Tail And Back Again 1234567890
The Quick Brown Fox Jumps Over The Lazy Dogs Tail And Back Again 1 1234567890

C++
#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;
}


What I have tried:

1.Disabled the keAquireSpinlock and keReleasespinlock - which reduced the frequency of errors but the underlying problem of repeat characters persists.
Posted
Updated 12-Jan-20 20:43pm
v3
Comments
Richard MacCutchan 9-Jan-20 9:40am    
Please edit your question and remove all that unformatted code dump. If you have a specific question then please post it. But do not just dump all your code and expect someone to debug it for you.
[no name] 9-Jan-20 9:52am    
Sounds like a buffer pointer problem.
Rick York 9-Jan-20 10:58am    
"Better an enum than preprocessor macros or global constant."

How is the enumeration better than a global constant? They are effectively the same thing. One difference is you could easily run into variable type issues using an enumerated value instead of a constant with the specific type it is used for. In my opinion, it is better to have those as constants in a namespace so all the types are correct. FWIW, a class with all static members and methods is effectively the same thing as a namespace.

Also - those function macros could and should be inline functions. Macros should be avoided unless no viable alternative exists.

One last thing - for resource locking I really dislike explicit lock and unlock calls. I prefer to use an excursion class which is a form of RAII. The class would perform the lock at construction and do the unlock at destruction. The end result is the resource is locked for the lifetime of the object. Then it becomes a matter of providing the appropriate scoping to define the correct lifetime for the object.

1 solution

I won't bother analyzing that much code, that's your task. I suspect that one of your functions copies the wrong part of your buffer. I suggest one of two approaches:

1. Follow the flow in your program from receiving the data to the output, and every time something is done to the output, print a short label indicating where in the program you are, and the current state of the output. That should give you an idea where the unwanted chars are added.

2. Better yet, use the debugger, break at the function that receives the data, and then check the state of the output at each step of the process. Same as 1, except you don't need to pollute your code with unrelated printouts.

No matter which path you go, check the code immediately before the unwanted change occurs to find the error. If you can't spot it, you can come back here, point at the suspicious code, and tell us what output you're seeing after that particular step, and what you are expecting.

P.S.:
Since your data arrives asynchronously, variant 2 could be tricky, as debugging is bound to affect the order of events. Maybe you could try a third variant, based on the first, by writing event records into a thread-local buffer instead of printing them to cout: just store the string you would otherwise print, and a time stamp along with it. Then, at the end of the program, gather all event buffers, sort them by time stamp, and print events in order of occurence.
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900