#include "seriallib.h" /* Attempt to open the serial port Return the file descriptor */ int OpenSerial(char *port) { int fdes; if ((fdes = open(port,O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0) { perror("OpenSerial"); } else { fcntl(fdes,F_SETFL,FNDELAY); } return(fdes); } /* Setup the communication options Hopefully POSIX compliant */ int SetupSerial(int fdes,int baud,int databits,int stopbits,int parity) { int n; struct termios options; //,options2; /* Get the current options */ if (tcgetattr(fdes,&options) < 0) { perror("SetupSerial 1"); return(FALSE); } /* fprintf(stderr,"iflag - 0%o; oflag - 0%o; cflag - 0%o; lflag - 0%o\n", (unsigned int)options.c_iflag, (unsigned int)options.c_oflag, (unsigned int)options.c_cflag, (unsigned int)options.c_lflag); */ /* Set the baud rate */ switch (baud) { case 1200: n = cfsetispeed(&options,B1200); n += cfsetospeed(&options,B1200); break; case 2400: n = cfsetispeed(&options,B2400); n += cfsetospeed(&options,B2400); break; case 4800: n = cfsetispeed(&options,B4800); n += cfsetospeed(&options,B4800); break; case 9600: n = cfsetispeed(&options,B9600); n += cfsetospeed(&options,B9600); break; case 19200: n = cfsetispeed(&options,B19200); n += cfsetospeed(&options,B19200); break; case 38400: n = cfsetispeed(&options,B38400); n += cfsetospeed(&options,B38400); break; case 57600: // witilt n = cfsetispeed(&options,B57600); n += cfsetospeed(&options,B57600); break; default: fprintf(stderr,"Unsupported baud rate\n"); return(FALSE); } if (n != 0) { perror("SetupSerial 2"); return(FALSE); } // Set the data size options.c_cflag &= ~CSIZE; // Character size mask switch (databits) { case 7: options.c_cflag |= CS7; break; case 8: options.c_cflag |= CS8; break; default: fprintf(stderr,"Unsupported data size\n"); return(FALSE); } // Set parity switch (parity) { case 'n': case 'N': options.c_cflag &= ~PARENB; // Clear parity enable break; case 'o': case 'O': options.c_cflag |= PARENB; // Parity enable options.c_cflag |= PARODD; // Enable odd parity break; case 'e': case 'E': options.c_cflag |= PARENB; // Parity enable options.c_cflag &= ~PARODD; // Turn off odd parity = even break; default: fprintf(stderr,"Unsupported parity\n"); return(FALSE); } // Set stop bits switch (stopbits) { case 1: options.c_cflag &= ~CSTOPB; // Not 2 stop bits = One stop bit break; case 2: options.c_cflag |= CSTOPB; // Two stop bits break; default: fprintf(stderr,"Unsupported stop bits\n"); return(FALSE); } // Non blocking return immediately with data options.c_cc[VMIN] = 0; options.c_cc[VTIME] = 0; // Local flags options.c_lflag = 0; // No local flags options.c_lflag &= ~ICANON; // Don't canonicalise options.c_lflag &= ~ECHO; // Don't echo options.c_lflag &= ~ECHOK; // Don't echo // Control flags options.c_cflag &= ~CRTSCTS; // Disable RTS/CTS options.c_cflag |= CLOCAL; // Ignore status lines options.c_cflag |= CREAD; // Enable receiver options.c_cflag |= HUPCL; // Drop DTR on close // oflag - output processing options.c_oflag &= ~OPOST; // No output processing options.c_oflag &= ~ONLCR; // Don't convert linefeeds // iflag - input processing options.c_iflag |= IGNPAR; // Ignore parity options.c_iflag &= ~ISTRIP; // Don't strip high order bit options.c_iflag |= IGNBRK; // Ignore break conditions options.c_iflag &= ~INLCR; // Don't Map NL to CR options.c_iflag &= ~ICRNL; // Don't Map CR to NL options.c_iflag |= (IXON | IXOFF | IXANY); // xon/xoff flow control /* fprintf(stderr,"iflag - 0%o; oflag - 0%o; cflag - 0%o; lflag - 0%o\n", (unsigned int)options.c_iflag, (unsigned int)options.c_oflag, (unsigned int)options.c_cflag, (unsigned int)options.c_lflag); */ // Update the options and do it NOW if (tcsetattr(fdes,TCSANOW,&options) < 0) { perror("SetupSerial 3"); return(FALSE); } /* Read the options and check they have "taken" if (tcgetattr(fdes,&options2) < 0) { perror("SetupSerial 4"); return(FALSE); } fprintf(stderr,"iflag - 0%o; oflag - 0%o; cflag - 0%o; lflag - 0%o\n", (unsigned int)options.c_iflag, (unsigned int)options.c_oflag, (unsigned int)options.c_cflag, (unsigned int)options.c_lflag); if (memcmp((void *)&options,(void *)&options2,sizeof(options)) != 0) { perror("SetupSerial 5"); return(FALSE); } */ // Clear the line tcflush(fdes,TCIFLUSH); return(TRUE); } void CheckSerialPort(int fdes) { int input_speed,output_speed; struct termios options; /* Get the current options */ if (tcgetattr(fdes,&options) != 0) { perror("CheckSpeed"); } fprintf(stderr,"iflag - 0%o; oflag - 0%o; cflag - 0%o; lflag - 0%o\n", (unsigned int)options.c_iflag, (unsigned int)options.c_oflag, (unsigned int)options.c_cflag, (unsigned int)options.c_lflag); fprintf(stderr,"c_ispeed - 0%o; c_ospeed - 0%o\n", (unsigned int)options.c_ispeed, (unsigned int)options.c_ospeed); input_speed = cfgetispeed(&options); output_speed = cfgetospeed(&options); fprintf(stderr,"Input speed: %d\n",input_speed); fprintf(stderr,"Output speed: %d\n",output_speed); } /* Write a string to the serial port device */ int SendSerialString(int fdes,char *buffer) { int len; len = strlen(buffer); if (write(fdes,buffer,len) != len) return(FALSE); return(TRUE); } /* Write raw bytes to the serial port device */ int SendSerialRaw(int fdes,unsigned char *buffer,int len) { if (write(fdes,buffer,len) != len) return(FALSE); return(TRUE); } /* Read any characters on the port Note that the maximum number of bytes to read has to inclue the trailing '\0' which is added to make a legal C string. */ int ReadSerialString(int fdes,char *buffer,int maxread) { int len; len = read(fdes,buffer,maxread-1); if (len < 0 && errno != EAGAIN) return(FALSE); buffer[len] = '\0'; return(len); } /* Read a single character from the port */ int ReadSerialChar(int fdes,unsigned int *n) { char c[8]; int len; len = read(fdes,c,1); if (len < 1 && errno != EAGAIN) return(FALSE); *n = c[0]; return(TRUE); } /* Read raw bytes from the serial port Return the number read */ int ReadSerialRaw(int fdes,unsigned char *buffer,int maxread,int timeout) { int len,iptr=0; unsigned char buf; struct timeval tp; double startsecs,secs; gettimeofday(&tp,NULL); startsecs = tp.tv_sec + tp.tv_usec / 1000000.0; for (;;) { len = read(fdes,&buf,1); if (len > 0) { buffer[iptr] = buf; iptr++; if (iptr >= maxread) break; } gettimeofday(&tp,NULL); secs = tp.tv_sec + tp.tv_usec / 1000000.0; if (secs-startsecs > timeout) break; } return(iptr); } /* Clear serial, read until nothing is left */ void ClearSerial(int fdes) { char buf; while (read(fdes,&buf,1) > 0) ; } /* Wait for a particular character The timeout is in seconds */ int SkipSerialUntil(int fdes,char c,double timeout) { char buf; int len; struct timeval tp; double startsecs,secs; gettimeofday(&tp,NULL); startsecs = tp.tv_sec + tp.tv_usec / 1000000.0; for (;;) { len = read(fdes,&buf,1); if (len > 0 && buf == c) break; gettimeofday(&tp,NULL); secs = tp.tv_sec + tp.tv_usec / 1000000.0; if (secs-startsecs > timeout) return(FALSE); } return(TRUE); } /* Read until a particular character is received Return a C string */ int ReadSerialUntil(int fdes,char *buffer,char c,int maxread,double timeout) { int len,iptr=0; char buf; struct timeval tp; double startsecs,secs; gettimeofday(&tp,NULL); startsecs = tp.tv_sec + tp.tv_usec / 1000000.0; buffer[iptr] = '\0'; for (;;) { len = read(fdes,&buf,1); if (len > 0 && buf == c) break; if (len > 0 && iptr < maxread-1) { buffer[iptr] = buf; iptr++; buffer[iptr] = '\0'; } gettimeofday(&tp,NULL); secs = tp.tv_sec + tp.tv_usec / 1000000.0; if (secs-startsecs > timeout) return(FALSE); } return(TRUE); } /* Display a possibly binary string */ void Raw2stderr(unsigned char *buf,int len) { int i; for (i=0;i 126) fprintf(stderr,"<%03d>",buf[i]); else fprintf(stderr,"%c",buf[i]); } } /* Display a string potentially with non printable characters */ void Str2stderr(char *buf) { unsigned int i; for (i=0;i 126) fprintf(stderr,"<%03d>",buf[i]); else fprintf(stderr,"%c",buf[i]); } } /* Given a 3 byte string from the mouse in "s" Return the button and position. */ void DecodeSerialMouse(unsigned char *s,int *button,int *x,int *y) { *button = 'n'; if ((s[0] & 0x20) != 0) *button = 'l'; else if ((s[0] & 0x10) != 0) *button = 'r'; *x = (s[0] & 0x03) * 64 + (s[1] & 0x3F); if (*x > 127) *x = *x - 256; *y = (s[0] & 0x0C) * 16 + (s[2] & 0x3F); if (*y > 127) *y = *y - 256; } /* Set up for the serialversion of the Magellan Spacemosue */ int SerialSpacemouse(char *s) { int fd; struct termios options,options2; if ((fd = open(s,O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0) { fprintf(stderr,"Failed to open serial port\n"); } else { fcntl(fd,F_SETFL,FNDELAY); } // Get the current options if (tcgetattr(fd,&options) < 0) { fprintf(stderr,"First get failed\n"); exit(-1); } // Change things cfsetispeed(&options,B9600); cfsetospeed(&options,B9600); options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; options.c_cflag &= ~PARENB; options.c_cflag |= CSTOPB; options.c_cc[VMIN] = 0; options.c_cc[VTIME] = 0; options.c_lflag = 0; // No local flags options.c_lflag &= ~ICANON; // Don't canonicalise options.c_lflag &= ~ECHO; // Don't echo options.c_lflag &= ~ECHOK; // Don't echo options.c_cflag &= ~CRTSCTS; // Disable RTS/CTS options.c_cflag |= CLOCAL; // Ignore status lines options.c_cflag |= CREAD; // Enable receiver options.c_cflag |= HUPCL; // Drop DTR on close options.c_oflag &= ~OPOST; // No output processing options.c_oflag &= ~ONLCR; // Don't convert linefeeds options.c_iflag |= IGNPAR; // Ignore parity options.c_iflag &= ~ISTRIP; // Don't strip high order bit options.c_iflag |= IGNBRK; // Ignore break conditions options.c_iflag &= ~INLCR; // Don't Map NL to CR options.c_iflag &= ~ICRNL; // Don't Map CR to NL options.c_iflag |= (IXON | IXOFF | IXANY); // xon/xoff flow control // Update the options and do it NOW if (tcsetattr(fd,TCSANOW,&options) < 0) { fprintf(stderr,"Failed to set\n"); exit(-1); } // Read the options again and check they have "taken" if (tcgetattr(fd,&options2) < 0) { fprintf(stderr,"Second get failed\n"); exit(-1); } // Compare if (memcmp((void *)&options,(void *)&options2,sizeof(options)) != 0) { fprintf(stderr,"Did not compare favourably!\n"); exit(-1); } return(fd); }