00001 /************************************************************************************************/ 00002 /*! \file common.c 00003 * \brief Communicate with serial device. 00004 * \author $Author: jayhawk_hokie $ 00005 * \version $Revision: 1.6 $ 00006 * \date $Date: 2007/08/02 23:18:28 $ 00007 ************************************************************************************************/ 00008 /*! 00009 * 00010 ************************************************************************************************/ 00011 00012 00013 #include "satctl.h" 00014 #include "common.h" 00015 00016 /*! \brief Initialize serial port \n 00017 * The presumption was that we'd always be talking 00018 * exclusively to devices in 8N1. Now, to use 2 stop bits, we had to use 00019 * a define to avoid rewriting all the code that uses init_serial as it is 00020 * already written. Any major version change should incorporate an option 00021 * for doing this properly in the code. 00022 * @param *portfn pointer to port file name 00023 * @param brate 00024 * @param *portfd pointer to port file descripter 00025 * @return int 0 if successful 00026 */ 00027 int init_serial(char *portfn, speed_t brate, int *portfd) { 00028 struct termios tty; /* tty termios attrib structure */ 00029 int mcs; /* Modem-control settings flags */ 00030 00031 portfd[0] = open( portfn, O_RDWR | O_NOCTTY ); /* Open the port - a more common call to open port */ 00032 /* portfd[0] = open( portfn, O_RDWR ); */ /* Open the port - orginally set */ 00033 if (portfd[0] == -1) return(-1); 00034 00035 tcgetattr(portfd[0], &tty); /* Get the port attributes */ 00036 cfsetospeed(&tty, brate); /* Put outrate in tty struct */ 00037 cfsetispeed(&tty, brate); /* Put inrate in tty struct */ 00038 /* This was an oversight. The presumption was that we'd always be talking 00039 * exclusively to devices in 8N1. Now, to use 2 stop bits, we had to use 00040 * a define to avoid rewriting all the code that uses init_serial as it is 00041 * already written. Any major version change should incorporate an option 00042 * for doing this properly in the code. 00043 */ 00044 #ifndef TSB 00045 tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; /* Set 8 data bits */ 00046 #else 00047 tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8 | CSTOPB; 00048 /* Set 8 data bits & 2 stop bits */ 00049 #endif 00050 00051 /* Set raw, no echo mode */ 00052 tty.c_iflag = (IGNBRK | IXON | IXOFF | IXANY); /* Set ingore-breaks - added for software flow control 00053 (MIGHT CAUSE PROBLEMS FOR OTHER DEVICES) */ 00054 /* tty.c_iflag = IGNBRK; */ /* Set ingore-breaks */ 00055 tty.c_lflag = 0; /* Clear local modes flag */ 00056 tty.c_oflag = 0; /* Clear output modes flag */ 00057 tty.c_cflag |= CLOCAL | CREAD; /* Ignore modem ctrl/ enable rcvr */ 00058 tcsetattr(portfd[0], TCSANOW, &tty); /* Effect flags, active now */ 00059 00060 /* Set RTS line */ 00061 ioctl(portfd[0], TIOCMGET, &mcs); /* Get modem-control flags */ 00062 mcs |= TIOCM_RTS | TIOCM_DTR; /* Modify modem-control flags */ 00063 ioctl(portfd[0], TIOCMSET, &mcs); /* Put modem-control flags */ 00064 00065 /* Port is ready for use */ 00066 return(0); 00067 } 00068 00069 /*! \brief Send data string to serial port 00070 * @param fd file descriptor for port 00071 * @param *str pointer to return string 00072 * @return int 0 if successful 00073 */ 00074 int say(int fd, char *str) { 00075 static int wrote; /* Number of bytes written */ 00076 static int slen; /* Length of submitted string */ 00077 00078 slen = strlen(str); /* Get # bytes to write */ 00079 /* Debug */ 00080 /*if (debug>4) 00081 fprintf(stderr, "writing \"%s\" (len: %d) to %d\n", str, slen+2, fd);*/ 00082 00083 /*tmp = (char *)malloc(slen+3); * Allocate buffer accordingly */ 00084 /*strcpy(tmp, str); * Copy and add 2 EOL's & a NULL */ 00085 /*tmp[slen++] = eol[0]; 00086 tmp[slen++] = eol[0]; 00087 tmp[slen] = 0; 00088 */ 00089 00090 wrote = write(fd, str, slen); /* Hocus Pocus !!! */ 00091 /* TODO: Here's the first thing that could stand fixing. This writing 00092 * is all but blind. Granted, we return what we wrote, but we don't 00093 * loop to write the rest. At this point, writing commands on the order 00094 * of 10 bytes max, this should suffice. Later on, this routine will 00095 * probably need to be made more robust. 00096 */ 00097 if (!wrote) perror("say():write() failed"); 00098 /* if (debug>4) 00099 fprintf(stderr, "wrote %d bytes\n", wrote); 00100 free(tmp);*/ 00101 return(0); 00102 } 00103 00104 /*! \brief hear function reads data from serial port \n 00105 * @param fd file descriptor for port 00106 * @param *str pointer to return string 00107 * @param maxlen maximum length of return string 00108 * @param minlen minimum length of return string ( 0 = end string at character return, 00109 * !0 = minimum length) 00110 * @param maxbtime maximum blocking time for select function 00111 * (select function looks for ports to read) 00112 * @param term termination character to search for if minlen = 0 00113 * @return int 0 if successful 00114 */ 00115 int hear(int fd, char *str, int maxlen, int minlen, int maxbtime, char term) { 00116 int tbr = 0; /* Total bytes read (cumulative) */ 00117 int i; /* A loop variable */ 00118 struct timeval rtmr; /* Time to block in select() call */ 00119 fd_set rfds; /* fd set containing our port fd */ 00120 char *ptr; 00121 static char *left = NULL; 00122 static int useleft = 0; 00123 char *buffer; 00124 buffer = (char *) malloc(100); 00125 00126 if (!left) 00127 left = (char *)malloc(maxlen+1); 00128 bzero(str, maxlen); /* Zero out the target string (& illicit 00129 * any segfaults now in case someone didn't 00130 * properly initialize this. Sneaky, eh?) */ 00131 FD_ZERO(&rfds); /* Setup the fd set */ 00132 FD_SET(fd, &rfds); 00133 00134 rtmr.tv_sec = maxbtime/1000000; /* Setup the block timer */ 00135 rtmr.tv_usec = maxbtime - (rtmr.tv_sec * 1000000); 00136 /* First, check for leftovers from last time... */ 00137 if (useleft) 00138 { 00139 strcpy(str, left); 00140 tbr = strlen(left); 00141 left[0] = 0; 00142 } 00143 /* This is not too straightforward, but should be sufficiently sophisticated. 00144 * Regardless, it's complicated enough to warrant explanation. 00145 * This loop will run the shortest of: 00146 * 1) 2 un-reset loops (2 loops of maxbtime usec w/o read data) 00147 * 2) IF minlen, then until tbr >= minlen (i.e. minlen bytes get read) 00148 * 3) IF NOT minlen, then until tbr[last]=term (i.e. the term char gets read) 00149 * 4) maxlen characters already read 00150 */ 00151 for ( i = 0; 00152 /* Run while i < 3 (until i reaches 3) and.... */ 00153 (i < 3) && 00154 /*(i < 3) && */ 00155 /* If minlen, then while tbr < minlen, else until we get a term char */ 00156 /*(minlen ? (tbr<minlen) : (str[tbr?(tbr-1):0]!=term) ) &&*/ 00157 /* if minlen is false (i.e. minlen = 0) then if no terminate found then 00158 do maxlen > tbr . */ 00159 (minlen ? (tbr<minlen) : !strchr(str, term)) && 00160 (maxlen > tbr) ; 00161 i++) 00162 { 00163 if (select(fd+1, &rfds, NULL, NULL, &rtmr)) 00164 { /* Data to read? */ 00165 tbr += read(fd, str+tbr, maxlen-tbr); /* Read returned data */ 00166 i = 0; 00167 } 00168 else 00169 { 00170 } 00171 } 00172 if (!minlen) 00173 if ((ptr=strchr(str, term))) { /* Assignment intentional */ 00174 if (ptr != str+tbr-1) { /* The term character is being used, but is NOT the last character read */ 00175 /* strcpy(left, ptr+1); */ /* So copy the rest into the leftover buffer */ 00176 /* useleft = 1; */ /* Mark the marker. */ 00177 /* tbr -= (int)((str+tbr)-ptr);*/ /* and reduce tbr to the right value */ 00178 /* ptr[1] = 0; */ /* Finally, terminate the return string at the right place */ 00179 } 00180 } 00181 if (tbr == 0) { 00182 return(1); 00183 } 00184 return(0); 00185 } 00186 00187 /* Do not change the comments below - they will be added automatically by CVS*/ 00188 /***************************************************************************** 00189 * $Log: common.c,v $ 00190 * Revision 1.6 2007/08/02 23:18:28 jayhawk_hokie 00191 * Fixed Warnings. 00192 * 00193 * Revision 1.5 2006/08/11 20:07:47 bwilliam 00194 * Updated init_serial and hear functions. Modified so magnetometer can function. 00195 * 00196 * 00197 * 00198 ******************************************************************************/ 00199