prefect
Home Engineering Publications
DACS: Serial Communications Code, serial.c
 
  next up previous contents
Next: TCP/IP Client Library Header, Up: MIDI Controller Previous: Serial Communications Header, serial.h   Contents

Serial Communications Code, serial.c

This code implements the protocol described in the firmware protocols section of this design document.
/*****************************************************************************
 * DACS : Distributed Audio Control System
 *============================================================================
 *         File: serial.c
 *  Description: routines to handle serial communications with DACS components
 *       Author: Stephen S. Richardson
 * Date Created: 07.12.97
 *  Environment: GNU C Compiler (GCC) v2.7.1, Linux i486 v2.0.28
 *        Build: library
 *============================================================================
 * The code, executables, documentation, firmware images, and all related
 * material of DACS are  
 * Copyright (C) 1997 Stephen S. Richardson - ALL RIGHTS RESERVED
 *****************************************************************************
 * Source code control:
 *
 * $Id: serial.c,v 1.1 1997/07/13 14:18:00 prefect Exp prefect $
 *
 *****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/types.h>
#include <time.h>
#include <sys/time.h>
#include "serial.h"

void ser_init_frame (struct raw_frame *f)
{
  f->len=0;
  f->cur=0;
  f->done=0;
  f->dleflag=0;
  f->stxflag=0;

  memset (f->data, 0, MAXPAYLOAD);
}

void ser_init_serbuf (struct serbuf *b)
{
  b->len=0;
  b->len=0;
  memset (b->data, 0, SERBUFLEN);
}

int ser_write_buf (struct raw_frame *fr, struct serbuf *ob)
{
  int i, j=0;

  /* return 0 if the whole frame can't be put in the buffer. */
  if (ob->len + fr->len >= SERBUFLEN) return 0;
  
  /* start of frame */
  ob->data[j++]=DLE;
  ob->data[j++]=STX;

  /* data of frame */
  for (i=0;i<fr->len;i++) {
    if (fr->data[i]==DLE) {
      ob->data[j++]=DLE;
      ob->data[j++]=DLE;       /* character stuffing */
    } else {
      ob->data[j++]=fr->data[i];
    }
  }

  /* end of frame */
  ob->data[j++]=DLE;
  ob->data[j++]=ETX;

  ob->len+=j;
  
  return (1);
}

int ser_service (struct serbuf *ib, struct serbuf *ob,
		 struct raw_frame *of, int serfd)
{
  int r, i, j;

  /* outgoing serial data? */

  if (ob->len) {
    r=write (serfd, ob->data, ob->len);

    if (r<0) {
      /* error writing. */

      fprintf (stderr, "error writing to serial device.\n");
      exit (1);
    } else {
      /* data were written */
      
      if (r==ob->len) {
	/* all data were written */
	
	ob->len=0;
      } else {
	/* only some of the data were written.. shift buffer left by r */
	
	memmove (ob->data, ob->data+r, ob->len-r);
	ob->len -= r;
      }
    }
  }
  

  /* incoming serial data and enough space to store some of it? */

  if ((ser_datawaiting (serfd)) && (ib->len < SERBUFLEN)) {
    
    r=read (serfd, ib->data+ib->len, SERBUFLEN - ib->len);

    if (r<0) {
      fprintf (stderr, "error reading from serial device.\n");
      exit (1);
    } else {
      /* data were read */
      
      ib->len += r;

      /* process into a frame */

      for (i=0;i<ib->len;i++) {
	if (ib->data[i] == DLE) {
	  /* found a DLE */
	  if (of->dleflag) {
	    /* last char was a DLE */
	    
	    of->dleflag=0;

	    if (of->stxflag) {
	      of->data[of->cur++]=DLE;    /* it was a character stuffed DLE */
	    }

	  } else {
	    /* last char was not a DLE */
	    of->dleflag=1;
	  }
	} else {
	  /* found something other than a DLE */
	  if (of->dleflag) {
	    /* last char was a DLE */

	    of->dleflag=0;

	    if (ib->data[i] == STX) {
	      /* found start of packet */
	      of->stxflag=1;
	      of->done=0;
	      of->len=0;
	      of->cur=0;
	    } else if (ib->data[i] == ETX) {
	      /* found end of packet */
	      of->stxflag=0;
	      of->len=of->cur;
	      of->done=1;
	    }
	  } else {
	    /* last character was not DLE */
	    if (of->stxflag) {
	      of->data[of->cur++]=ib->data[i];   /* put the data into frame */
	    }
	  }
	}
      }

      /* reset input buffer position */
      ib->cur=0;
      ib->len=0;
    }
  }
}


int ser_datawaiting (int serfd)
{
  fd_set fds;
  struct timeval tv;

  bzero (&tv, sizeof (struct timeval));
  tv.tv_usec = 1;

  FD_ZERO (&fds);
  FD_SET (serfd, &fds);
  while ((select (serfd+1, &fds, NULL, NULL, &tv))==-1); /* make sure select */
                                                       /* works            */

  if (FD_ISSET (serfd, &fds)) return (1);
  else return (0);
}


/*****************************************************************************
 * ser_open
 *
 * opens a serial port at a baud rate for NON-BLOCKING read/write
 *****************************************************************************/
int ser_open (char *devnam, int bd)
{
  struct termios t;
  int fd;
  
  /* open device */
  fd=open(devnam, O_RDWR|O_NONBLOCK);
  
  if (fd<1) {
    fprintf (stderr, "Error opening serial device %s.\n", devnam);
    exit (1);
  }
  
  tcgetattr (fd, &t);
  
  /* set the port discipline */
  t.c_iflag=BRKINT|IGNPAR;
  t.c_oflag=OPOST;
  t.c_cflag=CS8|CREAD|CLOCAL;
  t.c_lflag=0;
  
  cfsetospeed (&t, (speed_t) bd);
  cfsetispeed (&t, (speed_t) bd);
  tcsetattr (fd, TCSANOW, &t);
  
  return (fd);
}


Steve Richardson 2000-07-06
Table of Contents

[PDF] [Whole document in PDF 1.9MB]

[more photos and information]

 
Page last modified:
Copyright © 1993-2000 prefect - All Rights Reserved.