LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

RS232 : timing of ComRd function

Solved!
Go to solution

Hello,

In below, you can find my code. I would like to receive, on RS232 port, byte per byte and transmit at the same time this received byte. But there is a big time between the first byte received and the transmited byte. I try several things but I find the same result.

int    RT_StartRxTxThread(int iComPort, int iBaudRate, int iMonitorFrameLength, double g_msDelay, int iDoWeDisplay)
{
    int        iStatus = 0;
    int        iParity,
            iDataBits,
            iStopBits,
            iInputQueueSize,
            iOutputQueueSize;
    double    dComTimeOut;

    double    dInitialTimerValue;
    int                iToRead;
    int                iCount,iCounter=0;
    unsigned char    ucRxBuffer[512]={0};
    unsigned char    ucTxBuffer[512]={0};
    unsigned char    ucTempBuffer[2];
    unsigned int    uiCRC=0;   
        iComPortNumberNormal    =iComPort;
        iParity                    =2;                // even parity
        iDataBits                =8;
        iStopBits                =1;
        iInputQueueSize            =1;
        iOutputQueueSize        =1;
        dComTimeOut             =0,001;
        iMonitoringFrameLength     = iMonitorFrameLength;
        // setup ComPort
        iStatus = OpenComConfig (    iComPortNumberNormal,
                                    NULL,
                                    (long)iBaudRate,
                                    iParity,
                                    iDataBits,
                                    iStopBits,
                                    iInputQueueSize,
                                    iOutputQueueSize);
        iStatus = OpenComConfig (    2,
                                    NULL,
                                    (long)iBaudRate,
                                    iParity,
                                    iDataBits,
                                    iStopBits,
                                    iInputQueueSize,
                                    iOutputQueueSize);       
        //Set timeout limit
        iStatus = SetComTime (iComPortNumberNormal, dComTimeOut);
        iStatus = SetComTime (2, dComTimeOut);
        iStatus = FlushInQ (iComPortNumberNormal);
        iStatus = FlushInQ (2);
        dInitialTimerValue = Timer();
        while(Timer()-dInitialTimerValue < 10.00)
        {       
            iToRead=ComRd (2, (char*)ucRxBuffer, 1);
            iStatus = ComWrt(iComPortNumberNormal, (char*)ucRxBuffer, 1);
        }
    return 0; 
}

Then, you can find in attached file the scope screenshot. I don't understand why the transmited data wait the end of 2 received bytes. Because I read byte per byte with function ComRd.

 

Thanks

Best Regards

0 Kudos
Message 1 of 9
(5,190 Views)
Solution
Accepted by topic author NicolasDelabie

What you are trying to do in CVI cannot be done in CVI. There are low level features used in the implementation of the serial library that waits for a certain amount of data to appear in the input buffer before the information is being processed. I learned this the hard way so number of years ago trying to build my own virtual serial ports before they became commercially available.

 

You will have to use Windows sdk serial port functions and write your own serial drivers to achieve what you are looking for. 

 

A CVI workaround is to create a com callback and use the most appropriate trigger features like number of bytes or termination strings to trigger the callback and get the desired behaviour you are looking for, but there will always be a delay. If you want close to real-time responses your only option is sdk. 

 

I can dig out the project in the week if you need further pointers. Drop me an email. 

 

Best regards 

Jattie van der Linde
Engineering Manager, Software & Automation
TEL Magnetic Solutions Ltd
0 Kudos
Message 2 of 9
(5,165 Views)

Set output queue size to -1.

That will probably fix it. The reason is explained in the OpenComConfig function help.

S. Eren BALCI
IMESTEK
0 Kudos
Message 3 of 9
(5,151 Views)

Hello Jattie,

Thanks for your explanations. I also tried a com callback but there always was a delay of 1,32ms. So I think I need to use, as you said, the option of Windows sdk. Can you help me to do this?

Thanks again

Best Regards

Nicolas Delabie

0 Kudos
Message 4 of 9
(5,147 Views)

Hello Eren,

Ii just tried to set the output queue size to -1, but I always have a delay of 1,32ms.

Thanks

Best Regards

0 Kudos
Message 5 of 9
(5,144 Views)

OK, I did not look at the attached trace first, but I was almost sure that -1 queue size would solve it.
Point-1: Setting positive output queue size generally delays the actual data transmission.

If output queue size is not -1 than Windows does not send the data immediately to the port, but instead puts it in a queue which is emptied whenever Windows decides to do so. So keep it at -1.

Point-2: I dont know if 1ms is a valid value for COM timeout. But you do not need it. It is irrelevant to your application.
I would not set it to anything to avoid side effects.
The problem is; if your incoming byte has not already arrived before ComRd executed, ComRd waits for 1ms (somewhat inaccurately) and reads the byte in the next turn of the loop and transmits it. That may be the reason for your 1ms delay.

Just leave timeout setting as default and try to code it like below:

while (testing) {
   while (GetInQLen (rxPort) == 0) {
      //do nothing
   }
   ComWrtByte (txPort, ComRdByte(rxPort));
}

 

Hope this helps,

S. Eren BALCI
IMESTEK
0 Kudos
Message 6 of 9
(5,137 Views)

Hello Eren,

I tried your code. However, I always have a delay of 1.32ms between the received data and transmit data. I think the issue is the delay created by ComRd and ComWrt function.

Thanks again

Best Regards

Nicolas Delabie

0 Kudos
Message 7 of 9
(5,123 Views)

Here is the SDK implementation code as discussed.

#include <windows.h>      
/**********************************************************************************************************************
Author: Barry O'Flynn
Date: 21 November 2002
Functionality: To act as a bridge between two comm ports. In the process of data crossing the bridge, it may be relayed
or simply modified.
**********************************************************************************************************************/

#include <utility.h>
#include <ansi_c.h>
#include <input_sdk.h>
#include <cvirte.h>


int intermediate(double* sp, double* ramp, double add_corell[10][2])
{

char *pcCommPort1 = "COM5";
char *pcCommPort2 = "COM1";
char buff[100],mess[30],buffr[400],char1,c;
int i1=1,i2=1,j,no_read_in[260];
int crc1,crc2,x,q,no_read_out[260];
char no_read1,no_read2,k,h,p,l,y;

DCB dcb1,dcb2;
HANDLE hCom1,hCom2;
COMMTIMEOUTS commtimeouts1,*lpCommTimeouts1;
COMMTIMEOUTS commtimeouts2,*lpCommTimeouts2;
BOOL fSuccess1,fSuccess2;
LPDWORD dwLength1=&i1;
LPDWORD dwLength2=&i2;
WORD char_ini;
LPDWORD lpEvtMask;
DWORD dwEvtMask;
/*----------------------------------------------------------------------------------------------------
Set up the handles to both the physical and virtual port.
------------------------------------------------------------------------------------------------------*/
hCom1 = CreateFile( pcCommPort1,
GENERIC_READ | GENERIC_WRITE,
0, // comm devices must be opened w/exclusive-access
NULL, // no security attributes
OPEN_EXISTING, // comm devices must use OPEN_EXISTING
0, // not overlapped I/O
NULL // hTemplate must be NULL for comm devices
);

hCom2 = CreateFile( pcCommPort2,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);

if ((hCom1 == INVALID_HANDLE_VALUE)||(hCom2 == INVALID_HANDLE_VALUE)) {
// Handle the error.
printf ("CreateFile failed with error %d.\n", GetLastError());
Delay(4);
return (1);
}
// We will build on the current configuration, and skip setting the size
// of the input and output buffers with SetupComm.
fSuccess1 = GetCommState(hCom1, &dcb1);
fSuccess2 = GetCommState(hCom2, &dcb2);

if ((!fSuccess1)||(!fSuccess2)) {
// Handle the error.
printf ("GetCommState failed with error %d.\n", GetLastError());
Delay(4);
return (2);
}

/*----------------------------------------------------------------------------------------------------
Configure both the ports using the DCB structure. Set the timeouts on each port to return immediatley.
Allowable badu rates:
CBR_110 CBR_19200 CBR_300 CBR_38400 CBR_600 CBR_56000
CBR_1200 CBR_57600 CBR_2400 CBR_115200 
CBR_4800 CBR_128000 CBR_9600 CBR_256000 CBR_14400
------------------------------------------------------------------------------------------------------*/
																									 
dcb1.BaudRate = CBR_9600; // set the baud rate
dcb1.ByteSize = 8; // data size, xmit, and rcv
dcb1.Parity = NOPARITY; // no parity bit
dcb1.StopBits = ONESTOPBIT; // one stop bit
dcb1.EvtChar = '\10'|'\6';
fSuccess1 = SetCommState(hCom1, &dcb1);

dcb2.BaudRate = CBR_9600; // set the baud rate
dcb2.ByteSize = 8; // data size, xmit, and rcv
dcb2.Parity = NOPARITY; // no parity bit
dcb2.StopBits = ONESTOPBIT; // one stop bit
fSuccess2 = SetCommState(hCom2, &dcb2);

commtimeouts1.ReadIntervalTimeout=MAXDWORD;
commtimeouts1.ReadTotalTimeoutMultiplier=0;
commtimeouts1.ReadTotalTimeoutConstant=0;
commtimeouts1.WriteTotalTimeoutMultiplier=0;
commtimeouts1.WriteTotalTimeoutConstant=0;

commtimeouts2.ReadIntervalTimeout=MAXDWORD;
commtimeouts2.ReadTotalTimeoutMultiplier=0;
commtimeouts2.ReadTotalTimeoutConstant=0;
commtimeouts2.WriteTotalTimeoutMultiplier=0;
commtimeouts2.WriteTotalTimeoutConstant=0;

if ((!fSuccess1)||(!fSuccess2)) {
// Handle the error.
printf ("SetCommState failed with error %d.\n", GetLastError());
Delay(4);
return (3);
}

lpCommTimeouts1=&commtimeouts1;
SetCommTimeouts(hCom1,lpCommTimeouts1);

lpCommTimeouts2=&commtimeouts2;
SetCommTimeouts(hCom2,lpCommTimeouts2);


/*----------------------------------------------------------------------------------------------------
Flush both buffers of contents.
------------------------------------------------------------------------------------------------------*/
PurgeComm(hCom1,PURGE_TXCLEAR);
PurgeComm(hCom1,PURGE_RXCLEAR);
PurgeComm(hCom2,PURGE_TXCLEAR);
PurgeComm(hCom2,PURGE_RXCLEAR);

/*for(k=0;k<260;k++)
{no_read_in[k]=0;
no_read_out[k]=0;
}
for(j=0;j<100;j++){buff[j]=0;}
for(l=0;l<400;l++){buffr[l]=0;}*/


/*----------------------------------------------------------------------------------------------------
Loop continously, relaying data all the time between the two ports.
------------------------------------------------------------------------------------------------------*/

while(1){
//Capture the contents of the input buffer for 100 characters
ReadFile(hCom1,buff,100,dwLength1,NULL);//Maximum nmuber of characters to be read 100
no_read1=*dwLength1;//Number of characters succesfully read

 for(y=0;y<no_read1;y++) //if(WaitCommEvent(hCom1,lpEvtMask,NULL)>0)
 {
	if(buff[y]=='\1')//Catch the number 1
	{ ;
	//Multiple write
	if(buff[y+1]=='\20')//Catch the number 16
	{ //Paste first eleven elements of buff into mess
	  for(q=0;q<11;q++){mess[q]=buff[q+y];}
	  //c=crc(mess,9);
	  crc1 = mess[7]+1;
	  crc2 = mess[8]+1;
	  x=0;//Continue until crcs match or the wrtie string is too long. 
	  while(mess[x+7]!=crc1)//||(mess[x+8]!=crc2))
	  {	if(x<8)//write string has to less than 15
	    {
	  	 mess[x+7]=buff[x+7+y];
	 	 mess[x+8]=buff[x+8+y];
	  	 mess[x+9]=buff[x+9+y];
	 	 mess[x+10]=buff[x+10+y];
	 	 crc1=mess[x+9];//record crc for high and low byte
	 	 crc2=mess[x+10];
	 	 c=crc(mess,9+x);
		 mess[x+9] =  c & 0x00FF;
		 mess[x+10] = (c & 0xFF00) >> 8;
	 	 x+=2;
	    }
	    else {goto no_crc;}//no crc match found thus far 
	  }//while
	    //printf("\nFound multilpe write\n");Delay(10);
	    
	    no_crc://no crc match.
	    ; 
	} //Single write
	else if(buff[y+1]=='\6')//Catch the number 6
	{ 
		crc1=buff[y+6];
		crc2=buff[y+7];
		for(q=0;q<6;q++){mess[q]=buff[q+y];} 
		c=crc(mess,6); 
		mess[6] =  c & 0x00FF;
		mess[7] = (c & 0xFF00) >> 8;
		if(mess[6]!=crc1)
		{printf("\nFound single write\n");
		Delay(10);
		
		}
		//Assign back if only data was found*/
	}
	else{;}		  
	}//if 		 
 }//for y

//if(no_read1!=0){no_read_in[p]=no_read1;p++;};
//Write to physical port and relay the data.
WriteFile( hCom2,buff,no_read1, dwLength1, NULL );	
//Read from the physical port. Maximum characters that can be read 400.
ReadFile(hCom2,buffr,400,dwLength2,NULL);
no_read2=*dwLength2;
//if(no_read2!=0){no_read_out[h]=no_read2;h++;};
//Write back to VP port with recieved data.
WriteFile( hCom1,buffr,no_read2, dwLength2, NULL );	
}





/*----------------------------------------------------------------------------------------------------
Set the event mask to catch the numbers 6 and 16.
------------------------------------------------------------------------------------------------------
dwEvtMask=EV_RXFLAG;
SetCommMask(hCom1,dwEvtMask);

p=0;h=0;
lpEvtMask=&dwEvtMask;
*/



return (0);
}







Jattie van der Linde
Engineering Manager, Software & Automation
TEL Magnetic Solutions Ltd
0 Kudos
Message 8 of 9
(5,032 Views)

Did you experiment by changing the UART FIFO size(s)?

 

Risultati immagini per com port advanced settings

Your dialog box may be different, depending from the specific serial interface you have (i.e. physical UART, USB Serial port etc.)

 

 

Carlo A.
Megaris




0 Kudos
Message 9 of 9
(4,954 Views)