09-08-2017 09:32 AM
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
Solved! Go to Solution.
09-10-2017 07:51 AM
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
09-11-2017 09:21 AM
Set output queue size to -1.
That will probably fix it. The reason is explained in the OpenComConfig function help.
09-11-2017 09:31 AM
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
09-11-2017 09:32 AM
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
09-11-2017 09:55 AM
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,
09-12-2017 03:14 AM
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
09-18-2017 03:42 AM
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); }
09-29-2017 09:12 AM
Did you experiment by changing the UART FIFO size(s)?
Your dialog box may be different, depending from the specific serial interface you have (i.e. physical UART, USB Serial port etc.)