Logo Search packages:      
Sourcecode: picp version File versions

serial.c

//-----------------------------------------------------------------------------
//
//    PICSTART Plus programming interface
//
//-----------------------------------------------------------------------------
//
//    Cosmodog, Ltd.
//    415 West Huron Street
//    Chicago, IL   60610
//    http://www.cosmodog.com
//
//-----------------------------------------------------------------------------

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

#include    <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <fcntl.h>
#include <unistd.h>
#include    <strings.h>

#include    "serial.h"

#define MIN_CHARS       0           // DEBUG something is amiss with this, if VTIME is non-zero we get EAGAIN returned instead of zero (and no delay)
#define CHAR_TIMEOUT    0           // character timeout (read fails and returns if this much time passes without a character) in 1/10's sec

extern FILE *comm_debug;
extern int  comm_debug_count;
extern bool sendCommand;

// 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
bool ByteWaiting(int theDevice, unsigned int timeOut)
{
      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);
}

// 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 ReadBytes(int theDevice, unsigned char *theBytes, unsigned int maxBytes, unsigned int timeOut)
{
      unsigned int      i, numRead;

      if (ByteWaiting(theDevice, timeOut))
      {
            if ((numRead = read(theDevice, theBytes, maxBytes)) > 0)          // get waiting bytes
            {
                  if (comm_debug)
                  {
                        for (i=0; i<numRead; i++)
                        {
                              fprintf(comm_debug, " I-0x%02x", theBytes[i]);

                              if (sendCommand)
                              {
                                    fprintf(comm_debug, "\n");
                                    sendCommand = false;
                                    comm_debug_count = 0;
                              }
                              else
                                    comm_debug_count++;

                              if (comm_debug_count >= 8)
                              {
                                    comm_debug_count = 0;
                                    fprintf(comm_debug, "\n");
                              }
                        }
                  }

                  return(numRead);
            }
      }
      return(0);
}

/*
// WriteBytes is currently unused

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

      write(theDevice, theBytes, numBytes);

      if (comm_debug)
      {
            for (i=0; i<numBytes; i++)
            {
                  fprintf(comm_debug, " O-0x%02x", theBytes[i]);
                  comm_debug_count++;

                  if (comm_debug_count >= 8)
                  {
                        comm_debug_count = 0;
                        fprintf(comm_debug, "\n");
                  }
            }

            if (comm_debug_count)
            {
                  comm_debug_count = 0;
                  fprintf(comm_debug, "\n");
            }
      }
}

*/

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

// 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
bool ConfigureDevice(int theDevice, unsigned int baudRate, unsigned char dataBits, unsigned char stopBits, unsigned char parity, bool cooked)
{
      struct termios    terminalParams;
      speed_t                 theSpeed;

      tcflush(theDevice, TCIOFLUSH);                              // flush any unwritten, unread data

      if (tcgetattr(theDevice, &terminalParams) != -1)      // read the old value
      {
            switch (baudRate)
            {
                  case 5:
                        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;
                  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;
                        terminalParams.c_iflag |= ISTRIP;
                        break;
                  case 8:
                  default:
                        terminalParams.c_cflag |= CS8;
                        terminalParams.c_iflag &= ~ISTRIP;
                        break;
            }

            switch (stopBits)
            {
                  case 2:
                        terminalParams.c_cflag |= CSTOPB;
                        break;
                  case 1:
                  default:
                        terminalParams.c_cflag &= ~CSTOPB;
                        break;
            }

            switch (parity)
            {
                  case 0:
                        terminalParams.c_cflag &= ~(PARENB | PARODD);   // no parity
                        terminalParams.c_iflag &= ~INPCK;
                        break;
                  case 1:
                        terminalParams.c_cflag |= (PARENB | PARODD);          // odd parity
                        terminalParams.c_iflag |= INPCK;
                        break;
                  case 2:
                        terminalParams.c_cflag |= PARENB;                           // even parity
                        terminalParams.c_cflag &= ~PARODD;
                        terminalParams.c_iflag |= INPCK;
                        break;
                  default:
                        break;
            }

            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
            {
                  // *** Input flag settings. ***
                  terminalParams.c_iflag &= ~(IGNCR | INLCR | ICRNL | IXOFF | IXON);

                  // *** Output flag settings. ***
                  terminalParams.c_oflag &= ~OPOST;

                  // *** Control flag settings. ***
                  terminalParams.c_cflag &= ~HUPCL;
                  terminalParams.c_cflag |= (CLOCAL | CREAD);

                  // *** Local flag settings. ***
                  terminalParams.c_lflag &= ~(ICANON|ECHO|ECHONL|ISIG|IEXTEN|TOSTOP);

                  terminalParams.c_cc[VINTR]  = _POSIX_VDISABLE;
                  terminalParams.c_cc[VQUIT]  = _POSIX_VDISABLE;
                  terminalParams.c_cc[VSUSP]  = _POSIX_VDISABLE;
                  terminalParams.c_cc[VSTART] = _POSIX_VDISABLE;
                  terminalParams.c_cc[VSTOP]  = _POSIX_VDISABLE;
            }

            terminalParams.c_cc[VMIN] = MIN_CHARS;                // wait until at least one character or until timeout
            terminalParams.c_cc[VTIME] = CHAR_TIMEOUT;      // wait this long, then fail

            if (tcsetattr(theDevice, TCSANOW, &terminalParams) != -1) 
                  return(true);
      }

      return(false);
}

// 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
void GetDeviceConfiguration(int theDevice, unsigned int *baudRate, unsigned char *dataBits, unsigned char *stopBits, unsigned char *parity)
{
      struct termios    terminalParams;

      if (tcgetattr(theDevice, &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;
                  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;
            }
      }
}

// 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
bool ConfigureFlowControl(int theDevice, bool wantControl)
{
      struct termios    terminalParams;

      if (tcgetattr(theDevice, &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] = MIN_CHARS;          // read returns immediately if no characters
            terminalParams.c_cc[VTIME] = CHAR_TIMEOUT;

            if (tcsetattr(theDevice, TCSANOW, &terminalParams) != -1) 
                  return(true);
      }

      return(false);
}

// 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
void GetDeviceStatus(int theDevice, bool *CTS, bool *DCD)
{
      int   status;

      *CTS = *DCD = false;

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

            if(status & TIOCM_CAR)
                  *DCD = true;
      }
}

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

      control = TIOCM_DTR;

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

static struct termios oldTerminalParams;

// 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
bool OpenDevice(char *theName, int *theDevice)
{
      // NOTE: the NOCTTY will prevent us from grabbing this terminal as our
      // controlling terminal (when run from init, we have no controlling
      // terminal, and we do not want this device to become one!)
      if ((*theDevice = open(theName, O_NDELAY | O_RDWR | O_NOCTTY)) != -1)
      {
            // attempt to read configuration, to verify this is a serial device
            // and to save settings
            if (tcgetattr(*theDevice, &oldTerminalParams) != -1)
                  return(true);

            close(*theDevice);
      }

      return(false);
}

// Close theDevice
void CloseDevice(int theDevice)
{
      // try to set the parameters back as they were, don't care if we fail
      tcsetattr(theDevice, TCSANOW, &oldTerminalParams);
      close(theDevice);
}


Generated by  Doxygen 1.6.0   Back to index