delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2006/09/05/07:47:17

X-Spam-Check-By: sourceware.org
Subject: Re: read() blocking and TIOCINQ
Message-ID: <44FD61EB.1090002@esrf.fr>
Date: Tue, 05 Sep 2006 13:39:23 +0200
From: Ernesto Paiser <paiser AT esrf DOT fr>
Reply-To: paiser AT esrf DOT fr
User-Agent: Thunderbird 1.5.0.5 (Windows/20060719)
MIME-Version: 1.0
To: cygwin AT cygwin DOT com
References: <44EABC07 DOT 3010305 AT esrf DOT fr> <Pine DOT GSO DOT 4 DOT 63 DOT 0608220936070 DOT 14509 AT access1 DOT cims DOT nyu DOT edu>
In-Reply-To: <Pine.GSO.4.63.0608220936070.14509@access1.cims.nyu.edu>
X-Virus-Status: Clean
Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sourceware.org/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
Sender: cygwin-owner AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
Delivered-To: mailing list cygwin AT cygwin DOT com

--------------040609070706000004070603
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Hello Igor,
Sorry for my incomplete question.
I attach to you the following file that could be compiled with gcc in
CYGWIN.
Accepted commands start by '?' character, and when the device is not
connected on the serial line the function read(...) blocks:


    DEVICE test program
    -------------------

Type your commands ('.' to quit):
 >> Enter command: ?ver


Then, blocked....:-((


Note that in our computers the serial line name is COMn not /dev/ttySn.

I tried before with /dev/ttySn and I receive file not found as answer.

Thank you for your help,

  Ernesto.

PS.: more details about CYGWIN

PAISER AT tenerife ~
$ uname -a
CYGWIN_NT-5.1 tenerife 1.5.21(0.156/4/2) 2006-07-30 14:21 i686 Cygwin


Igor Peshansky wrote:
> On Tue, 22 Aug 2006, Ernesto Paiser wrote:
> 
>> Hello Corinna,
> 
> FYI, this is a mailing list, and unless you're replying to a specific
> message, you're actually talking to many people.
> 
>> I have problems with read() function blocking and
>> waiting for characters on serial line with cygwin:
>>
>> Here are some code fragments:
>> ========================================================
>> fd = open(sl, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY)
>>
>> newpio.c_cflag = brate | CS8 | CLOCAL | CREAD;
>> newpio.c_iflag = IGNPAR | ICRNL;
>> newpio.c_oflag = 0;
>> newpio.c_lflag = 0;
>> newpio.c_cc[VTIME]    = 1;
>> newpio.c_cc[VMIN]     = 0;
>> ...
>>
>> n = ioctl(fd, TIOCINQ, &n); //It gives me an error (return -1) why??!!!
>>
>> and
>>
>> n = read(fd, buffer, 1);  <<< HERE IS BLOCKING!!!
>> ========================================================
>>
>> TIOCINQ is working on CYGWIN,
>>
>> Is there another way to solve this problem???
> 
> Please post a complete compilable test case that reproduces the problem.
> For example, in the above code, it's unclear what the variable sl contains
> (and I suspect it contains "COM1", which is a no-no -- you should be using
> "/dev/ttyS0").
> 	Igor


-- 
Ernesto PAISER ____________________ paiser AT esrf DOT fr
E.S.R.F. - European Synchrotron Radiation Facility
6 rue Jules Horowitz  BP 220 Grenoble CEDEX France
phone +33 4 76 88 23 48      fax +33 4 76 88 23 25

--------------040609070706000004070603
Content-Type: text/plain;
 name="serial_tiocinq.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="serial_tiocinq.c"

#include <stdio.h>			/* Standard input/output definitions */
#include <string.h>			/* String function definitions */
#include <unistd.h>			/* UNIX standard function definitions */
#include <fcntl.h>			/* File control definitions */
#include <errno.h>			/* Error number definitions */
#include <termios.h>		/* POSIX terminal control definitions */
#include <ctype.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/time.h>



// ............................................................................
// function declarations
int  serial_init (int portn, long baudrate);
int  serial_getchar(int fd, char *buffer);
int  serial_putnchar(int fd, char *data, int n);
void serial_flush(int fd);
void serial_close(int fd);
char *device_get(int fd);
char *device_comm(int fd, char *comm);
int device_getchar(int fd, char *buffer);
char *device_getline(int fd);
size_t check_rxbuffer(void);
int is_a_query(char *comm);

// ............................................................................
# ifndef TEMP_FAILURE_RETRY

#  define TEMP_FAILURE_RETRY(expression) \
(__extension__ \
      ({ long int __result; \
            do __result = (long int) (expression); \
              while (__result == -1L && errno == EINTR); \
              __result; }))

# endif /* TEMP_FAILURE_RETRY */

# define TFR TEMP_FAILURE_RETRY


//#define SLNAME_FORMAT "/dev/ttyS%d" // It doesn't work on Windows XP
#define SLNAME_FORMAT "COM%d"		// I'm using CYGWIN on Windows XP

#define INBUFF_SZ 1024
#define NO_ANSWER       ((char *)-1)
#define COMM_PREFIX   "COM"
#define BAUDRATE_CHAR '@'

#define DEF_BAUDRATE 9600
#define CR_STR         "\r"
#define CR_CHAR        '\r'
#define NL_CHAR        '\n'
#define ACKN_CHAR      '#'
#define QUERY_CHAR     '?'
#define MIN_RXBUFSIZE   1024
#define MAX_RXBUFSIZE   (128 * 1024)
#define COM1	1
#define COM2	2
#define COM3	3
#define COM4	4

struct termios oldpio;    // placeholder for original port settings

size_t   rxbuffsize;
char    *rxbuff;
char    *rxbuffend;
int      rxlines;

// ............................................................................

int main(void) {
   char    inbuff[INBUFF_SZ];
   char   *comm;
   char   *answ;
   int    fd;

	 fd = serial_init(COM1, 9600L);
   if (fd < 0) {
		printf("ERROR: %s\n", "serial_init()");
		exit(EXIT_FAILURE);
	 }


   printf("   DEVICE test program\n");
   printf("   -------------------\n\n");
   printf("Type your commands ('.' to quit):\n");
   while(1) {
      printf(">> Enter command: ");
      comm = fgets(inbuff, INBUFF_SZ, stdin);
      while(isspace(*comm))
         comm++;
      if (!*comm)
         continue;
      if (*comm == '.')
         break;
			
      answ = device_comm(fd, comm);

      if (answ == NO_ANSWER)
         ;
      else if (answ)
         printf("Answer: [%s]\n", answ);
      else
         printf("ERROR: %s\n", "device_comm()");
   }
   return(EXIT_SUCCESS);
}



int serial_init(int portn, long baudrate) {
   struct termios newpio;    // placeholder for new port settings
   long   brate;             // baudrate value
   int    fd;
   char   sl[sizeof(SLNAME_FORMAT)];

   if (portn < 0  || portn > 99) {
      fprintf(stderr, "serial_init(): Bad port number\n");
      return (-1);
   }
   sprintf(sl, SLNAME_FORMAT, portn);

   if ((fd = open(sl, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY)) < 0) {
      perror("serial_init()");
      return (-1);
   } 
   tcgetattr(fd, &oldpio);         // save current port settings        
   bzero(&newpio, sizeof(newpio)); // clear struct for new port settings

   switch (baudrate) {
      case 38400:
    	 brate = B38400;
         break;
      case 19200:
         brate = B19200;
         break;
      case 9600:
         brate = B9600;
         break;
      case 4800:
         brate = B4800;
         break;
      case 2400:
         brate = B2400;
         break;
   }

   // in a more general case one could select 
   // newpio.c_cflag = brate | DATABITS | STOPBITS | PARITY | CLOCAL | CREAD;
   newpio.c_cflag = brate | CS8 | CLOCAL | CREAD;   
   newpio.c_iflag = IGNPAR | ICRNL;
   newpio.c_oflag = 0;
   newpio.c_lflag = 0;//ICANON;    
   newpio.c_cc[VTIME]    = 1;     // inter-character timer unused
   newpio.c_cc[VMIN]     = 0;     // blocking read until 1 character arrives 
     
   tcflush(fd, TCIOFLUSH);  // flush data in internal buffers
   tcsetattr(fd, TCSANOW, &newpio);
   rxbuff     = NULL;
   rxbuffsize = 0;


   return fd;     	
}

int input_timeout (int fd)
{
  fd_set set;
  struct timeval timeout;

  /* Initialize the file descriptor set. */
  FD_ZERO (&set);
  FD_SET (fd, &set);

  /* Initialize the timeout data structure. */
  timeout.tv_sec = 0;
  timeout.tv_usec = 0;

	// select should return 0 if timeout, 1 if input available, -1 if error.
  return TFR(select(fd + 1, &set, NULL, NULL, &timeout));  
}


int serial_getchar(int fd, char *buffer) {
   ssize_t n;
   
   n = input_timeout (fd);   						// it doesn't work...

//	 n = ioctl(fd, FIONBIO , &optval);		// 
//	 n = ioctl(fd, FIONREAD, &optval);	  // FIONREAD not defined on CYGWIN!!!! 
   n = ioctl(fd, TIOCINQ, &n);					// It gives me an error (return -1)	 

      
   if (n)
   	n = read(fd, buffer, 1);
   	
   if (n == EINTR || n == EAGAIN || n == 0) { // read interrupted or not data available
      n = 0;
   } else if (n != 1) {
      perror("serial_getchar()");
      return(-1);
   }
   return(n);
}

int serial_putnchar(int fd, char *data, int n) {

   n = write (fd, data, (ssize_t)n);	
   if (n < 0) {
      perror("serial_putnchar()");
      return(-1);
   }
   return(n);
}

void serial_flush(int fd) {
   tcflush(fd, TCIOFLUSH);  // flush data in internal buffers
}

void serial_close(int fd) {
   close(fd);
   tcsetattr(fd, TCSANOW, &oldpio);
}

char *device_comm(int fd, char *comm)
{
   char *answer;

	 serial_flush(fd);

   if (serial_putnchar(fd, comm, strlen(comm)) < 0) {
      return(NULL);
   } else if (serial_putnchar(fd, CR_STR, sizeof(CR_STR) - 1) < 0) {
      return(NULL);
   }

	 if (is_a_query(comm))
      answer = device_get(fd);
   else 
      answer = NO_ANSWER;

   return(answer);
}

char *device_get(int fd)
{
   char    *line;
   int      nlines;

   rxbuffend = rxbuff;
   line = device_getline(fd);
   if (!line) {
      nlines = -1;
   } else
      nlines = 1;

	 rxlines = nlines;
   return (nlines < 0 ? NULL : rxbuff);
}

char *device_getline(int fd)
{
   int     remsize;
   time_t  tout;
   int     nloffset;

   if (!(remsize = check_rxbuffer())) {
      return(NULL);
   }
   nloffset = rxbuffend - rxbuff;
   tout = time(NULL) + 2; // crappy 2 sec timeout
   while(time(NULL) < tout) {
   	  int c;
   	  
      c = device_getchar(fd, rxbuffend);
      if (c) {
         if (c < 0) {
            return(NULL);
         } else {
            rxbuffend++;
            remsize--;
            if (c == NL_CHAR)
               return(rxbuff + nloffset);             
            else if (!remsize) {
               if (!(remsize = check_rxbuffer()))
                  return(NULL);
            }
         }
      }
   }
   printf("ERROR: %s\n", "device_getline()");
   return(NULL);
}

size_t check_rxbuffer(void) 
{
   size_t  buffsize;
   size_t  newsize;
   char   *newbuff;

   buffsize = rxbuffend - rxbuff;
   if (!rxbuffsize) {
      newsize = MIN_RXBUFSIZE;
   } else if (rxbuffsize == buffsize) {
      if (rxbuffsize < MAX_RXBUFSIZE)
         newsize = 2 * rxbuffsize;
      else
         return(0);
   } else {
      return(rxbuffsize - buffsize);
   }
   if (!(newbuff = realloc(rxbuff, newsize)))
      return(0);

   rxbuffsize = newsize;
   rxbuff = newbuff;
   rxbuffend = newbuff + buffsize;
   return(newsize - buffsize);
}

int device_getchar(int fd, char *buffer)
{
   int  nchar;
   int  c;

   nchar = serial_getchar(fd, buffer);

	 if (nchar == 0) {
      return(0);
   } else if (nchar < 0) {
      printf("ERROR: %s\n", "device_getchar()");
      return(-1);
   }
   c = *buffer;
   if (c == NL_CHAR) {
      *buffer = 0;
      return(NL_CHAR);
   } else if (c < ' ')
      return(0);
   else
      return(c);
}

int is_a_query(char *comm)
{
   char  firstc;

   // skip whitespaces
   while((firstc = *comm) != 0 && isspace(firstc))
      comm++;
   if (isdigit(firstc)) {
      comm++;
      while((firstc = *comm) != ':')
         comm++;
      return(is_a_query(++comm));
   } else if (firstc == '>')
      return(is_a_query(++comm));
   else if (firstc == ACKN_CHAR || firstc == QUERY_CHAR)
      return(1);
   else
      return(0);
}


--------------040609070706000004070603
Content-Type: text/plain; charset=us-ascii

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/
--------------040609070706000004070603--

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019