LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 09-17-2014, 05:09 AM   #1
Mechi
LQ Newbie
 
Registered: Aug 2014
Posts: 8

Rep: Reputation: Disabled
Blocking USB read + select and VMIN doesn't seem to work


Hello,
I have a device attached using a COM-to-USB connection to the PC. I'm running Ubuntu Linux, though on Fedora I've had similar results. A simple program that prints out all data received from the serial port proves that the data is being received correctly.

The function that I'm writing will be part of a bigger program with many threads. I want to save CPU time by waiting until a certain BLOCK_SIZE of data is received on the serial port before processing it.
I tried setting VMIN to 17 (minimal block size), 51 or 102 or 255 (all multiples of 17) but with no noticeable difference.

Here's a snippet of the code and below is the current output.
Code:
#define BAUDRATE        B230400
#define RS485_DEV	"/dev/ttyUSB0"
#define _POSIX_SOURCE   1
#define SET_UART 1

#define INPUTBUFFERSIZE 0x40000

typedef struct tagCOMMSTRUCT
{
    int      ipid                   //if(ipid > -1)Comm read ==> IP write
    	   , fd			    //handle to comport
	   , signal_close
           , thread_started;
    pthread_t hReadThread;
    DWORD    rx_queue_size          //size of rx circular buffer
           , rx_head_ptr            //ptr to start position to get more rx data
           , rx_queue_count         //number of bytes as yet unread
           , rx_write_ptr           //ptr to position to put more rx data
           , rx_tail_ptr            //ptr to end of rx data
           , cbTXQueued;
    pthread_mutex_t		cs_mutex;
    pthread_cond_t		cs_cond_fill, cs_cond_empty;
} COMMSTRUCT;


COMMSTRUCT    cs[1];

/*-------------------------------------*\
	Uart_Open
\*-------------------------------------*/
int Uart_Open(char *dev_name)
{
	int fd;
	//int c=0, res;

    struct termios  oldtio, newtio;

    printf("Start...\n");
    fd = open(dev_name, O_RDWR|O_NOCTTY);

    if (fd < 0) {
        perror(dev_name);
        return -1;
    }

    printf("Open...\n");
	
    tcgetattr(fd, &oldtio);
    bzero(&newtio, sizeof(newtio));
	
	newtio = oldtio;

        /* 
          BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
          CRTSCTS : output hardware flow control (only used if the cable has
                    all necessary lines. See sect. 7 of Serial-HOWTO)
          CS8     : 8n1 (8bit,no parity,1 stopbit)
          CLOCAL  : local connection, no modem contol
          CREAD   : enable receiving characters
        */
	newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;

       /*
          IGNPAR  : ignore bytes with parity errors
          ICRNL   : map CR to NL (otherwise a CR input on the other computer
                    will not terminate input)
          otherwise make device raw (no other input processing)
        */
	newtio.c_iflag = IGNPAR;
	newtio.c_oflag = 0;  // Raw output

	/* set input mode (non-canonical, no echo,...) */
	newtio.c_lflag = 0;
	 
	newtio.c_cc[VTIME]    = 0;   /* inter-character timer unused */
	newtio.c_cc[VMIN]     = 51;   /* blocking read until 17*3 chars received */

	cfsetispeed(&newtio, BAUDRATE);  // 230400
	cfsetospeed(&newtio, BAUDRATE);  // 230400
	cfmakeraw(&newtio);

        /* 
          now clean the modem line and activate the settings for the port
        */
	tcflush(fd, TCIFLUSH);
	tcsetattr(fd,TCSANOW,&newtio);


	return fd;

}

/*-------------------------------------*\
	mOpenComm
\*-------------------------------------*/
int mOpenComm(char *szCom, int cb_read)
{
    int           cid, status;
    static int	  do_once = 1;

    g_cid = cid = 0;
	

    //open comport
    cs[cid].fd = Uart_Open(szCom);

    // Create the Read thread.
    cs[cid].thread_started = 0;
    status = pthread_create(&cs[cid].hReadThread, NULL, StartReadThreadProc, NULL);
        
    if(status != 0) //OSA_SOK)
    {
        printf("Unable to create Read thread");
        close(cs[cid].fd);
        return -1;
    }
    
    // Everything was created ok.  Ready to go!
    cs[cid].rx_queue_size = INPUTBUFFERSIZE;  // 0x40000
    cs[cid].rx_head_ptr = 0;
    cs[cid].rx_queue_count = 0;
    cs[cid].rx_write_ptr = 0;
    cs[cid].rx_tail_ptr = 0;
    pthread_mutex_init(&cs[cid].cs_mutex, NULL);
    pthread_cond_init(&cs[cid].cs_cond_fill, NULL);
    pthread_cond_init(&cs[cid].cs_cond_empty, NULL);

    while(!cs[cid].thread_started)
	{
		//wait for thread to start...
        usleep(10);
	}

    return cid;
}


/*-------------------------------------*\
	StartReadThreadProc
\*-------------------------------------*/
static void *StartReadThreadProc(void *lpvParam)
{
    DWORD nNumberOfBytesRead;
    fd_set              fds;
    struct timeval      timeout = {25, 0};  //25 sec
    int 		rc, cid = (int)lpvParam;

    printf("StartReadThreadProc: cid = %d", cid);
    FD_ZERO(&fds);
    FD_SET(cs[cid].fd, &fds);

    cs[cid].thread_started = 1;

    while(!cs[cid].signal_close)
    {
    	// set each time in case timeout corrupted
		timeout.tv_sec = 25;
		timeout.tv_usec = 0;
	    FD_SET(cs[cid].fd, &fds);

		rc = select(cs[cid].fd + 1, &fds, NULL, NULL, &timeout);
//		ioctl(cs[cid].fd, FIONREAD, &rc);

		if (rc == -1)
			perror("select()");
	    else if (!rc)
		{
			printf("^"); //No data within 25 seconds.\n");
		}
		else // if (rc >= 51)
		{
    		pthread_mutex_lock(&cs[cid].cs_mutex);

		//while (cs[cid].rx_queue_count == INPUTBUFFERSIZE)  // no more room in buffer
		//	pthread_cond_wait(&cs[cid].cs_cond_empty, &cs[cid].cs_mutex);

			nNumberOfBytesRead = read(cs[cid].fd, szInputBuffer, INPUTBUFFERSIZE);
			if (nNumberOfBytesRead)
			{
				cs[cid].rx_queue_count += nNumberOfBytesRead;
		    	cs[cid].rx_head_ptr = 0;
		    	cs[cid].rx_tail_ptr = nNumberOfBytesRead;
				printf("\nSerialNumRead %u - 0x%X\n", nNumberOfBytesRead, szInputBuffer[0]);
			}
			pthread_cond_signal(&cs[cid].cs_cond_fill);
			pthread_mutex_unlock(&cs[cid].cs_mutex);
		}
    }

    cs[cid].signal_close = 0;
    return NULL;
}

main()
{
	int cid;
	unsigned char buf[50];

// starts thread "producer"
	cid = mOpenComm(RS485_DEV, 0x40000);
	printf("\nRS485 Open COM+thread:\n");

// now the "consumer"
	for(;;)
	{
		pthread_mutex_lock(&cs[cid].cs_mutex);
		while (mBytesAvail(cid) < 17)
			pthread_cond_wait(&cs[cid].cs_cond_fill, &cs[cid].cs_mutex);
	//	printf("\navail %d\n", mBytesAvail(cid));
		while (mBytesAvail(cid) >= 17)
		{
			mReadComm(g_cid, buf, 17);
	//		printf("\nbufRead 17  0x%X\n", buf[0]);
		}
			//GetRecord(buf);
		//pthread_cond_signal(&cs[cid].cs_cond_empty);
		pthread_mutex_unlock(&cs[cid].cs_mutex);
	}

	//mCloseComm(cid);
}
Here's the output:

Quote:
SerialNumRead 17 - 0x7F

SerialNumRead 27 - 0x7F

SerialNumRead 8 - 0x55

SerialNumRead 17 - 0x7E

SerialNumRead 43 - 0x7E

SerialNumRead 51 - 0x55

SerialNumRead 68 - 0x55

SerialNumRead 9 - 0x55

SerialNumRead 42 - 0x7E

SerialNumRead 68 - 0x55
I also tried polling using
Code:
ioctl(cs[cid].fd, FIONREAD, &rc);
and checking for the returned value to be more that 51 - but similar results - never consistent - and the CPU was not freed enough.

I'd appreciate any help/ideas in this issue.
Thanks,
Mechi

Last edited by Mechi; 09-23-2014 at 05:41 AM. Reason: to make more understandable
 
Old 10-01-2014, 04:35 AM   #2
Mechi
LQ Newbie
 
Registered: Aug 2014
Posts: 8

Original Poster
Rep: Reputation: Disabled
USB "UART" is not standard

Well, since no one answered, I figured out the hard way that even though I treat the ttyUSB as a UART port, it's different and not every thing works like a standard COM.

I finally used mutexes, and only released the "producer" mutex when enough data was accumulated so that the "consumer" could do its calculations.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] case in a select doesn't work!!! massy Programming 1 03-01-2014 03:53 AM
MySQL the syntax to SELECT doesn't work for DELETE Melsync Programming 2 03-31-2007 05:59 AM
DVD menu - doesn't work/can't select anything pingu Linux - Software 3 10-31-2005 09:33 AM
Using Select to make a simple directory menu why doesn't it work ctrimble Programming 5 06-07-2004 01:21 AM
Cut(Select) and Paste doesn't work! andykerouac Linux - General 0 02-11-2004 02:32 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 01:09 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration