delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2001/02/08/12:40:52

Mailing-List: contact cygwin-help AT sourceware DOT cygnus DOT com; run by ezmlm
List-Subscribe: <mailto:cygwin-subscribe AT sources DOT redhat DOT com>
List-Archive: <http://sources.redhat.com/ml/cygwin/>
List-Post: <mailto:cygwin AT sources DOT redhat DOT com>
List-Help: <mailto:cygwin-help AT sources DOT redhat DOT com>, <http://sources.redhat.com/ml/#faqs>
Sender: cygwin-owner AT sources DOT redhat DOT com
Delivered-To: mailing list cygwin AT sources DOT redhat DOT com
Message-ID: <3A82DA1C.E9DB390F@beamreachnetworks.com>
Date: Thu, 08 Feb 2001 09:40:44 -0800
From: "Eric M. Monsler" <emonsler AT beamreachnetworks DOT com>
X-Mailer: Mozilla 4.76 [en] (WinNT; U)
X-Accept-Language: en
MIME-Version: 1.0
To: "sylvain DOT gommier AT m4x DOT org" <sylvain DOT gommier AT nomade DOT fr>
CC: cygwin AT sources DOT redhat DOT com
Subject: Re: Serial read
References: <G8FSSX$IesNb_qTD6uoBMGRGqLQ8Fr5_sDZ0c3ZL4HVjSqjngMiyFizLk AT nomade DOT fr>

Sylvain,

See my setup code below.  As you will see, I don't use a wide variety of
settings, but it seems to function properly.

After the initiallization, in another function I do :
   while(blah blah)
     {
      FD_ZERO(&rset);

      /* Set up fd_set and call select. */
      FD_SET(udp_socket_fd,&rset);
      FD_SET(serial_fd,&rset);
      maxfdp = MAX(udp_socket_fd,serial_fd) +1;

      /* Now pend on our input file descriptors, until data is
	 available or unti we timeout. */
      sel_ret = select(maxfdp, &rset, NULL, NULL, &sel_timeout);
      /* Check if we timed out.  If so, increment a counter; if not,
	 try to read data */
      if(sel_ret == 0)
	{
	  /* We timed out! */
	  /* Do some metrics, or something */
	}
      else
	{
	  /* Check if we have Serial data to get */
	  if( FD_ISSET(serial_fd,&rset) )
	    {
	      /* Try to receive a message!
		 
		 Note that 'data' available in the serial interface
		 does not mean that the whole message is available! */
	      msg_hndlr->buffer = receive_serial_data(serial_fd,
						      &msg_length);
	/* Other stuff */
	    }
        /* Other stuff */
 	}
      } /* End while */


All before I read, because I don't want to block on read (I have other
things to do).  If you are OK blocking, great, but you might try
changing to select'ing first just to see what happens.  If that works, I
think there's some bug in either your port setup or in cygwin.

Inside receive_serial_data() is a bunch of stuff for message
syncronization, but all my reads are like:

read_bytes = 
  read(sfd, 
       &(av_ser_if_rx_state.tmp_len.tmp_bytes[4 - need_bytes]),
       need_bytes);
or :

read_bytes = read(sfd,
	          av_ser_if_rx_state.write_ptr,
  	          need_bytes);

after which I check if I got all the bytes I need, twiddle state, retry
reading in the new state, until completiong or a block.  At block,
(read_bytes == 0), I jump out back to the while(loop) that does
select().

Below is the full function that I use to initialize the serial port. 
You'll see I had some confusion on whether I needed to fctnl() or not to
get non-blocking behavior.  It seems to never block as is.

HTH,

Eric Monsler




int init_serial_if(int port, char *parity, long baudrate)
{

  int 	fd;	/* The file descriptor returned from opening port */
  byte	*b_ptr;	/* Byte addressing pointer for placing magic bytes
                   into structure */
  int 	ii;
  
  char * serialdevice;
  long int	baud_enum = B0;

  /* 
     Set up serial device text based on port number
  */

#ifdef __CYGWIN__
  if(port == 2)
    {
      serialdevice = "/dev/com2";
    }
  else if(port == 1)
    {
      serialdevice = "/dev/com1";
    }  
  else
    {
      printf("Invalid port specified, trying port 1\n");
      serialdevice = "/dev/com1";
    }  
#else
  if(port == 2)
    {
      serialdevice = "/dev/ttyb";
    }
  else if(port == 1)
    {
      serialdevice = "/dev/ttya";
    }    
  else
    {
      printf("Invalid port specified, trying port 1\n");
      serialdevice = "/dev/ttya";
    }  
#endif


  /*
    Handle baud rate enumeration
  */
  switch(baudrate)
    {      
    case 300:
      baud_enum =  B300    ;
      break;
    case 1200:
      baud_enum =  B1200   ;
      break;
    case 2400:
      baud_enum =  B2400   ;
      break;
    case 9600:
      baud_enum =  B9600   ;
      break;
    case 19200:
      baud_enum =  B19200  ;
      break;
    case 38400:
      baud_enum =  B38400  ;
      break;
    case 57600:
      baud_enum =  B57600  ;
      break;
    case 115200:
      baud_enum =  B115200 ;
      break;
    default:
      printf("Specified baudrate not recognized, using 9600!\n");
      baud_enum = B9600;
    }

  /* 
     Now we know we have the correct parameters to use, proceed to
     open port and write 
  */

  fd = open(serialdevice, O_RDWR | O_NOCTTY | O_NDELAY);
  if (fd <0) {perror(serialdevice); exit(-1); }

#if DEBUG
  printf("Opening serial port %s returned: %d\n",serialdevice,fd);
#endif
  
  tcgetattr(fd,&oldtio); /* save current port settings */
  
  /* Start with old settings, then we'll modify */
  newtio = oldtio;
  
  /* 
     Now do the port setup to match what the EPLD is expecting 
  */

  /* Set baudrate */
  cfsetispeed(&newtio,baud_enum);
  cfsetospeed(&newtio,baud_enum);

  /* Enable the receiver and set local. */
  newtio.c_cflag |= (CLOCAL | CREAD);

  if(strcmp(parity,"8N1") == 0)
    {
      /* Set 8 bit characters, no parity, 1 stop (8N1) */
      newtio.c_cflag &= ~PARENB;	/* Clear previous parity bits values */
      newtio.c_cflag &= ~CSTOPB;	/* Clear previous stop bits values */
      newtio.c_cflag &= ~CSIZE;	/* Clear previous charsize bits values
*/
      newtio.c_cflag |= CS8;	/* Set for 8 bits. */
    }
  else
    {
      printf("Unsupported parity selection, using 8N1.\n");
      /* FIXME */
      printf("Actually, only 8N1 supported at this time \n");
      /* Set 8 bit characters, no parity, 1 stop (8N1) */
      newtio.c_cflag &= ~PARENB;	/* Clear previous parity bits values */
      newtio.c_cflag &= ~CSTOPB;	/* Clear previous stop bits values */
      newtio.c_cflag &= ~CSIZE;	/* Clear previous charsize bits values
*/
      newtio.c_cflag |= CS8;	/* Set for 8 bits. */
    }

  /* I think we want to disable hardware flow control.  FIXME  */
  newtio.c_cflag &= ~CRTSCTS;

  /* When we read, we want completely raw access  */
  newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

  /* I think we want to disable software flow control.  FIXME  */
  newtio.c_iflag &= ~(IXON | IXOFF | IXANY);
   
  /* Set output filtering to raw. */
  newtio.c_oflag &= ~OPOST;

  /* Set readsize and timeout to some reasonable values, just to be safe
*/
  newtio.c_cc[VTIME]    = 0;   /* inter-character timer unused */
  newtio.c_cc[VMIN]     = 0;   /* nonblocking read */
  

  /* 
     Now we can flush, and then make the control changes!
  */
  tcflush(fd, TCIFLUSH);
  tcsetattr(fd,TCSANOW,&newtio);
  
  /* Finally, on read, we want to NOT block, so we set this such that
     reads return a 0 number of bytes read rather than blocking. */
#if 0
  /*  Should be reduntant with above controls */
  if( fcntl(fd, F_SETFL, FNDELAY) == -1)
    {
      perror("Failed to set non-blocking read");
    }
#endif
  
  /* 
     Port all set up, ready to read and write data
  */


  /* 
     Initialize our state control structures and internal constructs
  */

  /* Snipped this from example */

  return fd;
}


/* 

   For completeness, provide a function to close and restore the port

*/

void close_serial_if(int sfd)
{
  /* Restore previous terminal settings */
  tcflush(sfd, TCIFLUSH);
  tcsetattr(sfd,TCSANOW,&oldtio);

  /* Close file descriptor for port */
  close(sfd);
}

--
Want to unsubscribe from this list?
Check out: http://cygwin.com/ml/#unsubscribe-simple

- Raw text -


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