Logo Search packages:      
Sourcecode: picp version File versions  Download package

serial.c

// serial.c
// Handle opening and conditioning of the serial port
// These functions isolate all communications with the
// serial device

#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <termio.h>
#include <sys/time.h>


bool ByteWaiting(int theDevice,unsigned int timeOut)
// See if there is unread data waiting on theDevice.
// This is used to poll theDevice without reading any characters
// from it.
// As soon as there is data, or timeOut expires, return.
// NOTE: timeOut is measured in microseconds
// if timeOut is 0, this will return the status immediately
{
      fd_set
            readSet;
      struct timeval
            timeVal;

      FD_ZERO(&readSet);                        // clear the set
      FD_SET(theDevice,&readSet);         // add this descriptor to the set
      timeVal.tv_sec=timeOut/1000000;     // set up the timeout waiting for one to come ready
      timeVal.tv_usec=timeOut%1000000;
      if(select(FD_SETSIZE,&readSet,NULL,NULL,&timeVal)==1) // if our descriptor is ready, then report it
      {
            return(true);
      }
      return(false);
}

unsigned int ReadBytes(int theDevice,unsigned char *theBytes,unsigned int maxBytes,unsigned int timeOut)
// Attempt to read at least one byte from theDevice before timeOut.
// once any byte is seen, attempt to get any more which are pending
// up to maxBytes
// If timeOut occurs, return 0
{
      unsigned int
            numRead;

      if(ByteWaiting(theDevice,timeOut))
      {
            if((numRead=read(theDevice,theBytes,maxBytes))>0)           // get waiting bytes
            {
                  return(numRead);
            }
      }
      return(0);
}

void WriteBytes(int theDevice,unsigned char *theBytes,unsigned int numBytes)
// Write theBytes to theDevice.
{
      write(theDevice,theBytes,numBytes);
}

void FlushBytes(int theDevice)
// Flush any bytes that may be waiting at theDevice
{
      ioctl(theDevice,TCFLSH,0);          // flush the input stream
}

bool ConfigureDevice(int theDevice,unsigned int baudRate,unsigned char dataBits,unsigned char stopBits,unsigned char parity,bool cooked)
// set up data transmission configuration of theDevice
// NOTE: if any of the passed parameters is invalid, it will be set
// to an arbitrary valid value
// baudRate is: 50,75,110,134,150,200,300,600,1200,1800,2400,4800,9600,19200,38400,57600,115200
// dataBits is 7 or 8
// stopBits is 1 or 2
// parity is 0=none,
//           1=odd,
//           2=even
// if there is a problem, return false
{
      struct termios
            terminalParams;
      speed_t
            theSpeed;

      if(ioctl(theDevice,TCGETS,&terminalParams)!=-1) // read the old value
      {
            switch(baudRate)
            {
                  case 50:
                        theSpeed=B50;
                        break;
                  case 75:
                        theSpeed=B75;
                        break;
                  case 110:
                        theSpeed=B110;
                        break;
                  case 134:
                        theSpeed=B134;
                        break;
                  case 150:
                        theSpeed=B150;
                        break;
                  case 200:
                        theSpeed=B200;
                        break;
                  case 300:
                        theSpeed=B300;
                        break;
                  case 600:
                        theSpeed=B600;
                        break;
                  case 1200:
                        theSpeed=B1200;
                        break;
                  case 1800:
                        theSpeed=B1800;
                        break;
                  case 2400:
                        theSpeed=B2400;
                        break;
                  case 4800:
                        theSpeed=B4800;
                        break;
                  case 9600:
                        theSpeed=B9600;
                        break;
                  case 19200:
                        theSpeed=B19200;
                        break;
                  case 38400:
                        theSpeed=B38400;
                        break;
                  case 57600:
                        theSpeed=B57600;
                        break;
                  case 115200:
                        theSpeed=B115200;
                        break;
                  case 230400:
                        theSpeed=B230400;
                        break;
                  case 460800:
                        theSpeed=B460800;
                        break;
                  default:
                        theSpeed=B9600;
                        break;
            }
            cfsetospeed(&terminalParams,theSpeed);
            cfsetispeed(&terminalParams,theSpeed);

            terminalParams.c_cflag&=~CSIZE;           // mask off the data bits
            switch(dataBits)
            {
                  case 7:
                        terminalParams.c_cflag|=CS7;
                        break;
                  case 8:
                  default:
                        terminalParams.c_cflag|=CS8;
                        break;
            }

            terminalParams.c_cflag&=~CSTOPB;    // mask off the stop bits
            switch(stopBits)
            {
                  case 1:
                        break;
                  case 2:
                        terminalParams.c_cflag|=CSTOPB;
                        break;
                  default:
                        break;
            }

            terminalParams.c_cflag&=~(PARENB|PARODD); // mask off the parity bits
            switch(parity)
            {
                  case 0:
                        break;
                  case 1:
                        terminalParams.c_cflag|=(PARENB|PARODD);  // odd parity
                        break;
                  case 2:
                        terminalParams.c_cflag|=PARENB;           // even parity
                        break;
                  default:
                        break;
            }

            terminalParams.c_cflag|=CREAD;            // allow reading

            if(cooked)                                      // use this when setting up the serial port to be used as a terminal
            {
                  terminalParams.c_iflag=ICRNL;
                  terminalParams.c_oflag=OPOST|ONLCR;
                  terminalParams.c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHONL;
            }
            else
            {
                  terminalParams.c_iflag=0;
                  terminalParams.c_oflag=0;
                  terminalParams.c_lflag=0;
            }
            terminalParams.c_cc[VMIN]=0;        // read returns immediately if no characters
            terminalParams.c_cc[VTIME]=0;

            if(ioctl(theDevice,TCSETS,&terminalParams)!=-1)
            {
                  return(true);
            }
      }
      return(false);
}

void GetDeviceConfiguration(int theDevice,unsigned int *baudRate,unsigned char *dataBits,unsigned char *stopBits,unsigned char *parity)
// return the configuration of theDevice
// baudRate is: 50,75,110,134,150,200,300,600,1200,1800,2400,4800,9600,19200,38400,57600,115200,230400,460800
// dataBits is 7 or 8
// stopBits is 1 or 2
// parity is 0=none,
//           1=odd,
//           2=even
{
      struct termios
            terminalParams;

      if(ioctl(theDevice,TCGETS,&terminalParams)!=-1) // read the old value
      {
            switch(cfgetospeed(&terminalParams))
            {
                  case B50:
                        *baudRate=50;
                        break;
                  case B75:
                        *baudRate=75;
                        break;
                  case B110:
                        *baudRate=110;
                        break;
                  case B134:
                        *baudRate=134;
                        break;
                  case B150:
                        *baudRate=150;
                        break;
                  case B200:
                        *baudRate=200;
                        break;
                  case B300:
                        *baudRate=300;
                        break;
                  case B600:
                        *baudRate=600;
                        break;
                  case B1200:
                        *baudRate=1200;
                        break;
                  case B1800:
                        *baudRate=1800;
                        break;
                  case B2400:
                        *baudRate=2400;
                        break;
                  case B4800:
                        *baudRate=4800;
                        break;
                  case B9600:
                        *baudRate=9600;
                        break;
                  case B19200:
                        *baudRate=19200;
                        break;
                  case B38400:
                        *baudRate=38400;
                        break;
                  case B57600:
                        *baudRate=57600;
                        break;
                  case B115200:
                        *baudRate=115200;
                        break;
                  case B230400:
                        *baudRate=230400;
                        break;
                  case B460800:
                        *baudRate=460800;
                        break;
                  default:
                        *baudRate=0;
                        break;
            }

            switch(terminalParams.c_cflag&CSIZE)
            {
                  case CS7:
                        *dataBits=7;
                        break;
                  case CS8:
                        *dataBits=8;
                        break;
                  default:
                        *dataBits=0;
                        break;
            }

            *stopBits=1;
            if(terminalParams.c_cflag&CSTOPB)
            {
                  *stopBits=2;
            }

            *parity=0;
            if(terminalParams.c_cflag&PARENB)
            {
                  if(terminalParams.c_cflag&PARODD)
                  {
                        *parity=1;
                  }
                  else
                  {
                        *parity=2;
                  }
            }
      }
}

bool ConfigureFlowControl(int theDevice,bool wantControl)
// if wantControl is true, configure theDevice to use CTS/RTS hardware
// flow control, if false, turn off flow control
// NOTE: when flow control is off, we must drive our RTS line to the
// modem active at all times
// if there is a problem, return false
{
      struct termios
            terminalParams;

      if(ioctl(theDevice,TCGETS,&terminalParams)!=-1) // read the old value
      {
            if(wantControl)
            {
                  terminalParams.c_cflag|=CRTSCTS;          // set flow control
            }
            else
            {
                  terminalParams.c_cflag&=~CRTSCTS;         // clear flow control
            }
            terminalParams.c_cc[VMIN]=0;                    // read returns immediately if no characters
            terminalParams.c_cc[VTIME]=0;
            if(ioctl(theDevice,TCSETS,&terminalParams)!=-1)
            {
                  return(true);
            }
      }
      return(false);
}

void GetDeviceStatus(int theDevice,bool *CTS,bool *DCD)
// return the status of the two control lines we are interested in:
// CTS is true when the modem has raised CTS (letting us know it is ok to send)
// DCD is true when the carrier detect line is active
{
      int
            status;

      *CTS=*DCD=false;
      if(ioctl(theDevice,TIOCMGET,&status)!=-1)
      {
            if(status&TIOCM_CTS)
            {
                  *CTS=true;
            }
            if(status&TIOCM_CAR)
            {
                  *DCD=true;
            }
      }
}

void SetDTR(int theDevice,bool DTR)
// Set the state of the DTR handshake line
{
      int
            control;

      control=TIOCM_DTR;
      if(DTR)
      {
            ioctl(theDevice,TIOCMBIS,&control);
      }
      else
      {
            ioctl(theDevice,TIOCMBIC,&control);
      }
}

bool OpenDevice(char *theName,int *theDevice)
// Open theName immediately for both read/write
// (do not block under any circumstances)
// return a device handle.
// NOTE: since the device can be opened BEFORE it is locked,
// this function MUST NOT modify the parameters of the device
// or in any way mess with it!!
// if there is a problem, set the error, and return false
{
      struct termios
            terminalParams;

      if((*theDevice=open(theName,O_NDELAY|O_RDWR|O_NOCTTY))!=-1) // NOTE: the NOCTTY will prevent us from grabbing this terminal as our controlling terminal (when run from init, we have no controlling terminal, an we do not want this device to become one!)
      {
            if(ioctl(*theDevice,TCGETS,&terminalParams)!=-1)            // attempt to read configuration, just to verify this is a serial device
            {
                  return(true);
            }
            close(*theDevice);
      }
      return(false);
}

void CloseDevice(int theDevice)
// Close theDevice
{
      close(theDevice);
}

Generated by  Doxygen 1.6.0   Back to index