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