// // ac_serialio.c - serial port functions // // Copyright (C) 2006 Nathan (Acorn) Pooley // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // version 2 as published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License (gpl.txt) for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // You can contact the author, Nathan (Acorn) Pooley, by writing // to Nathan (Acorn) Pooley, 949 Buckeye Drive, Sunnyvale, CA 94086, USA // or through the form at http://www.rawbw.com/~acorn/wand/feedback.html // // // Thanks to Gary Frerking for writing the Serial Programming HOWTO at // http://www.tldp.org/HOWTO/Serial-Programming-HOWTO // Much of this is based on his descriptions and examples. // //#@DOC@ serial port functions //########################################################################### //############################### INCLUDES ################################## //########################################################################### #include "ac_serialio.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> //########################################################################### //############################### TYPEDEFS ################################## //########################################################################### //=========================================================================== // AcSerial //=========================================================================== struct AcSerialRec { char *device; int baudrate; int baudenum; int fd; struct termios oldtio; struct termios newtio; }; //########################################################################### //############################### GLOBALS ################################### //########################################################################### //########################################################################### //############################### CODE ###################################### //########################################################################### //=========================================================================== // acSerialDestroy() //=========================================================================== void acSerialDestroy(AcSerial *sio) { acSerialClose(sio); if (sio->device) { free(sio->device); } free(sio); } //=========================================================================== // acSerialCreate() //=========================================================================== AcSerial *acSerialCreate(const char *device, int baudrate) { AcSerial *sio = calloc(1,sizeof(AcSerial)); if (!sio) return 0; sio->device = strdup(device); sio->fd = -1; sio->baudrate = 9600; acSerialSetBaud(sio,baudrate); sio->newtio.c_cflag = 0 | CS8 // 8N1 (b8 bit, no parity, 1 stop | CLOCAL // local (not modem) | CREAD // enable rx | CSTOPB // 2 stop bits //| CRTSCTS // HW flow control ; sio->newtio.c_iflag = 0 | IGNPAR // ignore parity errors | ICRNL // map CR to NL ; sio->newtio.c_oflag = 0; // Raw output //sio->newtio.c_oflag |= CSTOPB; // 2 stop bits on output sio->newtio.c_lflag = ICANON; // canonical output sio->newtio.c_cc[VINTR] = 0; /* Ctrl-c */ sio->newtio.c_cc[VQUIT] = 0; /* Ctrl-\ */ sio->newtio.c_cc[VERASE] = 0; /* del */ sio->newtio.c_cc[VKILL] = 0; /* @ */ sio->newtio.c_cc[VEOF] = 4; /* Ctrl-d */ sio->newtio.c_cc[VTIME] = 0; /* inter-character timer unused */ sio->newtio.c_cc[VMIN] = 1; /* blocking read until 1 char arrives */ sio->newtio.c_cc[VSWTC] = 0; /* '\0' */ sio->newtio.c_cc[VSTART] = 0; /* Ctrl-q */ sio->newtio.c_cc[VSTOP] = 0; /* Ctrl-s */ sio->newtio.c_cc[VSUSP] = 0; /* Ctrl-z */ sio->newtio.c_cc[VEOL] = 0; /* '\0' */ sio->newtio.c_cc[VREPRINT] = 0; /* Ctrl-r */ sio->newtio.c_cc[VDISCARD] = 0; /* Ctrl-u */ sio->newtio.c_cc[VWERASE] = 0; /* Ctrl-w */ sio->newtio.c_cc[VLNEXT] = 0; /* Ctrl-v */ sio->newtio.c_cc[VEOL2] = 0; /* '\0' */ return sio; } //=========================================================================== // acSerialSetNonCanonical() //=========================================================================== // // By default, read entire line before returning it. // After calling acSerialSetMode() wait as follows: // // vtime vmin description // ----- ---- ----------- // 0 0 return immediately // >0 0 wait until 1 char received, or until timeout // 0 >0 wait until vmin chars received // >0 >0 wait until vmin chars received, or until vtime elapsed // since last char // vtime is in 1/10 second. // // int acSerialSetNonCanonical(AcSerial *sio, int vtime, int vmin) { sio->newtio.c_lflag = 0; sio->newtio.c_cc[VTIME] = vtime; sio->newtio.c_cc[VMIN] = vmin; if (vtime == 0 && vmin == 0) { fprintf(stderr, "WARNING: Non-Canonical mode with vtime==vmin==0 is broken!\n"); } return 0; } //=========================================================================== // acSerialSetBaud() //=========================================================================== int acSerialSetBaud(AcSerial *sio, int baudrate) { switch(baudrate) { case 50: sio->baudenum = B50; break; case 75: sio->baudenum = B75; break; case 110: sio->baudenum = B110; break; case 134: sio->baudenum = B134; break; case 150: sio->baudenum = B150; break; case 200: sio->baudenum = B200; break; case 300: sio->baudenum = B300; break; case 600: sio->baudenum = B600; break; case 1200: sio->baudenum = B1200; break; case 1800: sio->baudenum = B1800; break; case 2400: sio->baudenum = B2400; break; case 4800: sio->baudenum = B4800; break; case 9600: sio->baudenum = B9600; break; case 19200: sio->baudenum = B19200; break; case 38400: sio->baudenum = B38400; break; case 57600: sio->baudenum = B57600; break; case 115200: sio->baudenum = B115200; break; case 230400: sio->baudenum = B230400; break; default: fprintf(stderr,"Error: bad baud rate: %d. \n", baudrate); if (baudrate != sio->baudrate) { fprintf(stderr,"Using %d.\n",sio->baudrate); acSerialSetBaud(sio,sio->baudrate); } else if (baudrate != 9600) { fprintf(stderr,"Using %d.\n",9600); acSerialSetBaud(sio,9600); } return -1; } cfsetispeed(&sio->newtio, sio->baudenum); cfsetospeed(&sio->newtio, sio->baudenum); sio->baudrate = baudrate; return 0; } //=========================================================================== // acSerialGetFD() //=========================================================================== int acSerialGetFD(AcSerial *sio) { return sio->fd; } //=========================================================================== // acSerialOpen() //=========================================================================== int acSerialOpen(AcSerial *sio) { sio->fd = open(sio->device, O_RDWR | O_NOCTTY); if (sio->fd < 0) { return -1; } // // save old settings // tcgetattr(sio->fd,&sio->oldtio); // // clear the line and activate settings // tcflush(sio->fd, TCIFLUSH); tcsetattr(sio->fd,TCSANOW, &sio->newtio); return 0; } //=========================================================================== // acSerialClose() //=========================================================================== void acSerialClose(AcSerial *sio) { if (sio->fd >= 0) { tcsetattr(sio->fd,TCSANOW,&sio->oldtio); close(sio->fd); } sio->fd = -1; } |
This file Copyright (C) 2006 by Nathan (Acorn) Pooley
Go to TOP Wand page
Go to Acorn's personal webpage
Go to Hogwarts website: www.gotohogwarts.com
Snout: www.snout.org/game
Gadgets of Justice Unlimited
Snout GC (Wiki)
Snout Wiki
File created by do_doc at Wed May 30 03:25:03 PDT 2007