#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/serial.h>

int fd = 0;

int serwait(int fd, int *dcd, int *rng, int *dsr, int *cts)
  {
  /* Die Funktion wartet (schlaeft), bis sich eine oder mehrere der vier 
     Steuerleitungen aendern. Der Parameter fd ist das Handle einer
     bereits geoeffneten Schnittstelle. 
     Welche Leitungen zu ueberwachen sind, wird in den Parametern 
     dcd, rng, dsr und cts festgelegt:

     * Parameter == NULL: die entsprechende Leitung wird ignoriert.
     * Parameter != NULL: die entsprechende Leitung wird ueberwacht.

     Im zweiten Fall zeigt der Parameter auf eine Variable.

     Der Rueckgabewert der Funktion ist 0 fuer "OK" und -1 im Fehlerfall.
     Die Pegel-Aenderungen auf den Statusleitungen wird in der entsprechenden 
     Variablen zurueckgegeben (0: keine Aenderung, 1: Aenderung). 
  */

  /* struct serial_icounter_struct aus linux/serial.h */
  struct serial_icounter_struct beforec;  
  struct serial_icounter_struct afterc;
  int icstatus, flags;

  flags = 0;
  if(dcd != NULL) { *dcd = 0; flags |= TIOCM_CD; } 
  if(rng != NULL) { *rng = 0; flags |= TIOCM_RNG; } 
  if(dsr != NULL) { *dsr = 0; flags |= TIOCM_DSR; } 
  if(cts != NULL) { *cts = 0; flags |= TIOCM_CTS; } 

  if(flags == 0) return(-1); /* Nothing to do ! */

  memset(&beforec, 0, sizeof(struct serial_icounter_struct));
  memset(&afterc, 0, sizeof(struct serial_icounter_struct));

  icstatus = ioctl(fd, TIOCGICOUNT, &beforec);
  if(icstatus == -1) 
    {
    printf("TIOCGICOUNT failed: %s\n", strerror(errno));
    return(-1);
    }

  /* Wait on the selected flags here */
  icstatus = ioctl(fd, TIOCMIWAIT, flags);
  if(icstatus == -1) 
    {
    printf("TIOCMIWAIT failed: %s\n", strerror(errno));
    return(-1);
    }

  icstatus = ioctl(fd, TIOCGICOUNT, &afterc);
  if(icstatus == -1) 
    {
    printf("TIOCGICOUNT failed: %s\n", strerror(errno));
    return(-1);
    }

  if(dcd != NULL) { *dcd = (beforec.dcd != afterc.dcd); }
  if(cts != NULL) { *cts = (beforec.cts != afterc.cts); }
  if(rng != NULL) { *rng = (beforec.rng != afterc.rng); }
  if(dsr != NULL) { *dsr = (beforec.dsr != afterc.dsr); }

  return(icstatus);
  }


 int open_port(void)
    {
    /* Einfachst-Version; reicht fuer den Test */
    int fd;
    fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd == -1)
      { perror("open_port: Unable to open /dev/ttyS0"); }
    return (fd);
    }


int main(void)
  {
  int res, fd, dcd, rng, dsr, cts;

  fd = open_port();

  /* Alle Leitungen zweimal hintereinander abfragen */
  res = serwait(fd, &dcd, &rng, &dsr, &cts);
  printf("Res: %d, DCD: %d, RNG: %d, DSR: %d, CTS: %d\n",res, dcd, rng, dsr, cts);

  res = serwait(fd, &dcd, &rng, &dsr, &cts);
  printf("Res: %d, DCD: %d, RNG: %d, DSR: %d, CTS: %d\n",res, dcd, rng, dsr, cts);

  /* Nur die CTS-Leitung abfragen */
  res = serwait(fd, NULL, NULL, NULL, &cts);
  printf("Res: %d, CTS: %d\n",res, cts);

  close(fd);
  return(0);
  }

