Need help finding bug using select()

J. Seth Henry jshamlet at comcast.net
Wed Jan 21 13:43:27 PST 2004


Guys,
I am, needless to say, still fairly new to programming under *nix - despite 
months of learning. So far, I have been able to work out a lot of things, but 
this issue with the select statement has me stumped.

I am attempting to listen to a serial port, and perform actions when data is 
received -or- simply wait a fixed amount of time. The waiting a fixed amount 
of time works great, but select doesn't return on serial events.

Would anyone be so kind as to tell me what I'm doing wrong? I know the data is 
being received - as I can read the port periodically (via the timeout) and I 
get what I am expecting. I would rather not wait until the timer expires, 
though.

Here is the code:

(from main.c)

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdarg.h>

/* local includes */
#include <params.h>
#include <io_func.h>
#include <utility_func.h>

int
message_proc(daemon_obj *daemon_info);

int
main(int argc, char **argv)
{
   int  retval, i;

/* Setup the structures */

   daemon_obj       daemon_info;
   thermostat_obj   stat_info[MAX_STATS];
   fd_set           stat_set;
   struct timeval   tick_info;

   init_daemon_info(&daemon_info);
   init_stat_info(stat_info);
   retval = read_conf_file(&daemon_info, stat_info);

/* At least for now, the thermostat is the only device that
     can generate unanticipated data */

   if(open_ioport(&daemon_info, STAT) == SUCCESS) {
      FD_ZERO(&stat_set);
      FD_SET(daemon_info.ioport.stat_fd, &stat_set);
   } else { return IO_ERROR; }

/* They relay board doesn't generate unanticipated data
     so there is no point in selecting on it */

   if(open_ioport(&daemon_info, OVRD) != SUCCESS)
      return IO_ERROR;

   tick_info.tv_sec = daemon_info.params.tick_rate;
   tick_info.tv_usec = 0;

   retval = sync_stat_time(&daemon_info);
   printf("Thermostat time/date updated\n");

   do{
   retval = query_sensors(&daemon_info, stat_info, 0);
   if(retval != SUCCESS)
      return retval;


   retval = query_status(&daemon_info, stat_info, 0);
   for(i = 0; i < MAX_SENSORS; i++)
      if(stat_info[0].sensor_info[i].is_present == TRUE)
         printf("%d: %d%c ", i, stat_info[0].sensor_info[i].value, 
stat_info[0].sensor_info[i].suffix);

   printf("SYS_MODE: %d ",stat_info[0].status_info.sys_status);
   printf("SAMPLE: %e ", stat_info[0].samples);

   retval = select(FD_SETSIZE, &stat_set, NULL, NULL, &tick_info);
   if(retval != 0)
      message_proc(&daemon_info);

   printf("Returned: %d \n", retval);

   } while(1);
   return 0;
}

int
message_proc(daemon_obj *daemon_info)
{
   char tbuffer[MAX_RX_LEN];
   char *bufptr;
   int  nbytes, tries, int_fd;
   int  i;

   i = MAX_RX_LEN;
   while ((nbytes = read(int_fd, bufptr, tbuffer + sizeof(tbuffer) - bufptr - 
1)) > 0)
   {
      bufptr += nbytes;
      i--;
      if (bufptr[-1] == '\n' || bufptr[-1] == '\r')
         break;
      if (i == 0)
         return(OVR_FLOW);
   }
   *bufptr = '\0';
   bufptr = tbuffer;
   printf("%s\n",tbuffer);
   return (SUCCESS);

}

(from io_func.c)

#include <stdio.h>   /* Standard input/output definitions */
#include <stdlib.h>
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <sys/types.h>

/* Local includes */
#include <params.h>

/*
   open_port opens a serial port for I/O

   daemon_info  -> points to the common daemon_info structure
   stat_or_ovrd -> determines which set of io information to use
                   0 = statnet info, 1 = override relay info
*/

int
open_ioport(daemon_obj *daemon_info, int stat_or_ovrd)
{
   char *device, *buffer_to, *buffer_from;
   int int_fd, int_baudrate;
   struct termios options;

   if(stat_or_ovrd == STAT) {
      device = daemon_info->ioport.stat_ioport;
      int_baudrate = daemon_info->ioport.stat_baudrate;
   } else if(stat_or_ovrd == OVRD) {
      if( daemon_info->ioport.port_linked == FALSE) {
         device = daemon_info->ioport.ovrd_ioport;
         int_baudrate = daemon_info->ioport.ovrd_baudrate;
      } else if( daemon_info->ioport.port_linked == TRUE) {
         buffer_from = daemon_info->ioport.stat_ioport;
         buffer_to = daemon_info->ioport.ovrd_ioport;
         strcpy(buffer_to, buffer_from);
         buffer_to[sizeof(buffer_to) - 1] = NULL;
         daemon_info->ioport.ovrd_baudrate = 
daemon_info->ioport.stat_baudrate;
         daemon_info->ioport.ovrd_fd = daemon_info->ioport.stat_fd;
         return SUCCESS;
      }
   } else { return FAILURE; }

   int_fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
   if(stat_or_ovrd == STAT){
      daemon_info->ioport.stat_fd = int_fd;
   } else {
      daemon_info->ioport.ovrd_fd = int_fd;
   }

   if (int_fd == FAILURE) {
      if(stat_or_ovrd == 0){
         printf("Unable to open thermostat port at %s\n", device);
      } else {
         printf("Unable to open override relay at %s\n", device);
      }
      return(IO_ERROR);
   } else {
      fcntl(int_fd, F_SETFL, 0);
   }

   tcgetattr(int_fd, &options);

   if(int_baudrate == 19200) {
         cfsetispeed(&options, B19200);
         cfsetospeed(&options, B19200);
   } else {
      if(int_baudrate == 9600) {
         cfsetispeed(&options, B9600);
         cfsetospeed(&options, B9600);
      } else {
         printf("Invalid port speed selected!\n");
         if(stat_or_ovrd == 0){
            daemon_info->ioport.stat_fd = FAILURE;
         } else {
            daemon_info->ioport.ovrd_fd = FAILURE;
         }
         return(IO_ERROR);
      }
   }

   options.c_cflag |= (CLOCAL | CREAD );
   options.c_cflag &= ~PARENB;
   options.c_cflag &= ~CSTOPB;
   options.c_cflag &= ~CSIZE;
   options.c_cflag |= CS8;
   options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
   options.c_iflag |= (INPCK | ISTRIP);
   options.c_oflag &= ~OPOST;
   options.c_cc[VMIN] = 0;
   options.c_cc[VTIME] = 10;

   tcsetattr(int_fd, TCSANOW, &options);

   return SUCCESS;
}

/*
   stat_comm writes out the contents of an incoming buffer to the
   thermostat, and posts the results in an outgoing buffer.

   daemon_info  -> points to the file descriptors
   stat_or_ovrd -> determines which device to send data to (0 = statnet, else 
= relay)
   wr_buffer -> incoming buffer (text to print)
   rd_buffer -> results of communications

*/

int
stat_comm(daemon_obj *daemon_info, int stat_or_ovrd, char *wr_buffer, char 
*rd_buffer)
{
   char tbuffer[MAX_RX_LEN];
   char *bufptr;
   int  nbytes, tries, int_fd;
   int  i;

   if(stat_or_ovrd == 0){
      int_fd = daemon_info->ioport.stat_fd;
   } else {
      int_fd = daemon_info->ioport.ovrd_fd;
   }

   bufptr = wr_buffer;
   for (tries = 0; tries < 3; tries ++)
   {
      if (write(int_fd, bufptr, strlen(bufptr)) < 3)
         continue;

      bufptr = tbuffer;

      i = MAX_RX_LEN;
      while ((nbytes = read(int_fd, bufptr, tbuffer + sizeof(tbuffer) - bufptr 
- 1)) > 0)
      {
         bufptr += nbytes;
         i--;
         if (bufptr[-1] == '\n' || bufptr[-1] == '\r')
            break;
         if (i == 0)
            return(COMM_ERROR);
      }
      *bufptr = '\0';
      bufptr = tbuffer;
      sprintf(rd_buffer,"%s\n",tbuffer);

      if( strlen(bufptr) > 1 ){
         return (SUCCESS);
      } else {
          sprintf(rd_buffer,"ERROR\n");
          return(CMD_ERROR);
      }
   }
   return (COMM_ERROR);
}



I have verified that the functions do work, and the hardware is being set up 
correctly. BTW - the code in message_proc is temporary. I will add the real 
code once I get past this problem. (don't laugh - I'm learning as I go, and I 
will probably completely rewrite all of this once I understand what to do)

Thanks!
Seth Henry



More information about the freebsd-questions mailing list