/***********************************
 ** Aleksander Adamowski (s1869)  **
 ** sob wrz 18 19:00:58 CEST 2004 **
 ***********************************/

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h> /* File control definitions */
#include <errno.h>
#include <termios.h> /* POSIX terminal control definitions */
#include <sys/ioctl.h>

/*#define DEBUG*/
/*#undef DEBUG*/
/*#define HWFLOW*/
/*#define DEBUGTOKENRING
#define DEBUGTOKEN
#define DEBUGQUEUE*/
/**/

#define BUFSIZE 261
#define TOKENTIMEOUT 4

/* Urzadzenie odbiorcze */
char* indevname;
/* Urzadzenie nadawcze */
char* outdevname;
/* Adres stacji */
unsigned char myaddr;

int uchwytpin; /* Deskryptor pliku dla portu wejsciowego */
int uchwytpout; /* Deskryptor pliku dla portu wyjsciowego */

/* Chwilowy adres stacji docelowej, ustawiony na zero jesli nie ma oczekujacych transferow (1-szy wiersz odczytany ze standardowego wyjscia): */
unsigned char dest = 0;
/* Znacznik danych gotowych do wyslania (2-gi wiersz odczytany ze standardowego wyjscia): */
unsigned char dataready = 0;

size_t bufsize = BUFSIZE;
/* Bufor odczytu z linii szeregowej */
char rbuf[BUFSIZE];
ssize_t rbufcount = 0;
/* Bufor zapisu do linii szeregowej */
char wbuf[BUFSIZE];
/* Bufor odczytu ze standardowego wejscia */
char inbuf[BUFSIZE];
/* Czy mamy token, wartosc 1 - token mamy, wartosc 2 - token mamy i czekamy na powrto wyslanej ramki: */
unsigned char haveToken = 0;
/* Kiedy dostalismy token (aby go zwolnic po timeout-cie jesli jakis pakiet do nas nie wrocil) */
time_t whenGotToken;
/* Kiedy wyslalismy token (aby go samodzielnie wygenerowac po timeout-cie jesli nikt go nie otrzymal) */
time_t whenSentToken;

struct termios stareustawienia_in;
struct termios stareustawienia_out;
/* int baud = B57600;*/
int baud = B9600;

typedef struct _tokenframe tokenframe;
struct _tokenframe {
  /* jak w IEEE 802.5, tylko pierwszy bit to bit tokenu: */
  unsigned char access;
  /* Adres stacji zrodlowej: */
  unsigned char src;
  /* Adres stacji docelowej: */
  unsigned char dest;
  /* Dlugosc danych (oczywiscie max 255) */
  unsigned char length;
  /* Dane */
  char* data;
  /* Suma kontrolna */
  unsigned char checksum;
};

/* Ogniwo listy dowiazaniowej stanowiacej kolejke ramek do wyslania */
typedef struct _tokenlink tokenlink;
struct _tokenlink {
  tokenlink* prev;
  tokenlink* next;
  tokenframe* frame;
};

/* Kolejka pakietow do wyslania: */
tokenlink* tokenQueue = NULL;
unsigned int queueLength = 0;

ssize_t sendFrame(tokenframe* tframe);
void sendToken();
unsigned char isToken(tokenframe* tframe);
unsigned char checksum(tokenframe* tframeptr);
tokenframe decodeFrame(char *framedata, ssize_t datalen);
void queueFrame(tokenframe* tframe);
tokenframe* deQueueFrame();
void obsluzKolejke(void);

int otworzporty(void) {
  uchwytpin = open(indevname, O_RDONLY | O_NOCTTY | O_NDELAY);
  if (uchwytpin  == -1) {
    fprintf(stderr, "Blad numer %d przy otwieraniu portu wejsciowego: %s\n", errno, strerror(errno));
    return 0;
  }
  uchwytpout = open(indevname, O_WRONLY | O_NOCTTY | O_NDELAY);
  if (uchwytpout  == -1) {
    fprintf(stderr, "Blad numer %d przy otwieraniu portu wyjsciowego: %s\n", errno, strerror(errno));
    return 0;
  }
  return 1;
}

int skonfigurujporty() {
  struct termios noweustawienia;
  int databits = CS8;

  /* Wylaczyc blokujace Wejscie/wyjscie: */
  fcntl(uchwytpin, F_SETFL, FNDELAY);
  /* fcntl(uchwytp, F_SETFL, FASYNC);*/

  tcgetattr(uchwytpin, &stareustawienia_in); 
  tcgetattr(uchwytpout, &stareustawienia_out); 

  memset(&noweustawienia, 0, sizeof(noweustawienia));
  /*
   * bit CRTSCTS - sprzetowa kontrola przeplywu (flow control),
   * nie dziala jesli przewod nie posiada potrzebnego polaczenia,
   * dlatego steruje sie odpowiednim DEFINE-m:
   */
#ifdef HWFLOW
  noweustawienia.c_cflag = baud | databits | CRTSCTS | CLOCAL | CREAD ;
#else
  noweustawienia.c_cflag = baud | databits | CLOCAL | CREAD ;
#endif
  noweustawienia.c_iflag = IGNPAR;
  /* Brak przetwarzania wyjscia: */
  noweustawienia.c_oflag = 0;
  noweustawienia.c_lflag = 0;

  tcflush(uchwytpin, TCIFLUSH);
  tcflush(uchwytpout, TCIFLUSH);
  tcsetattr(uchwytpin, TCSANOW, &noweustawienia);
  tcsetattr(uchwytpout, TCSANOW, &noweustawienia);

}

int zdekonfigurujport() {
  tcflush(uchwytpin, TCIFLUSH);
  tcflush(uchwytpout, TCIFLUSH);
  tcsetattr(uchwytpin, TCSANOW, &stareustawienia_in);
  tcsetattr(uchwytpout, TCSANOW, &stareustawienia_out);
}

/* Obsluz odczyt z portu */
ssize_t obsluzOdczyt(void) {
  ssize_t readcount = 0;
  ssize_t writtencount;
  int iloscRBuf;
  tokenframe tframe;
  /* Dlugosc nadmiarowej koncowki danych z bufora: */
  unsigned char excesslength = 0;
  /* Wstepnie ustawiamy bajt 3-ci pola "access" ("Zbyt malo danych dla zdekodowania ramki") */
  tframe.access = 4;

  ioctl(uchwytpin, FIONREAD, &iloscRBuf);
  if (iloscRBuf > 0) {
    readcount = read(uchwytpin, rbuf + rbufcount, bufsize);
    rbufcount += readcount;
    if (readcount > 0) {
#ifdef DEBUG
      fprintf(stderr, "Odczytano z portu: %d\n", readcount);
#endif
      tframe = decodeFrame(rbuf, rbufcount);
      /* 3-ci bit pola "access": ramka niepelna, czekamy na dane */
      if (tframe.access & 4) {
#ifdef DEBUGTOKENRING
        fprintf(stderr, "Ramka niepelna, trzeba odczytac wiecej danych.\n");
#endif
        return readcount;
      } else {
        /* Jesli za koncem ramki byly jakies dane, to stanowia one poczatek
         * nastepnej ramki do dekodowania i trzeba je skopiowac na poczatek bufora
         * oraz odpowiednio zmienic rbufcount: */
        excesslength = rbufcount - tframe.length - 5;
        if (excesslength > 0) {
          memmove(rbuf, rbuf + tframe.length + 5, excesslength);
          rbufcount = excesslength;
        }

        /* *****************   TOKEN   ***************** */
        if (isToken(&tframe)) {
          /* Zlapalismy token */
          if (haveToken) {
            /* Blad! ktos wypuszcza token SAMOWOLNIE! */
#ifdef DEBUGTOKEN
            fprintf(stderr, "Token wyemitowany samowolnie spod adresu: %d\n", tframe.src);
#endif
          } else {
#ifdef DEBUGTOKEN
            fprintf(stderr, "Zlapalismy token od stacji %d.\n", tframe.src);
#endif
            haveToken = 1;
            /*whenGotToken = time(NULL);*/
            return 0;
          }
        }

        /* *****************   DO NAS   ***************** */
        if (tframe.dest == myaddr) {
          /* Ramka jest adresowana do nas, wypisujemy dane */
          fprintf(stderr, "Przyszly dane z adresu %d o dlugosci %d\n", tframe.src, tframe.length);
          writtencount = write(1, tframe.data, tframe.length);
          /* Ustawiamy bit 2-gi ("ramka odczytana") w bajcie "access" */
          tframe.access = tframe.access | 2;
        }

        /* *****************   BROADCAST   ***************** */
        if (tframe.dest == 255) {
          /* Ramka jest adresowana rozgloszeniowo, wypisujemy dane */
          fprintf(stderr, "Przyszly dane z adresu %d o dlugosci %d\n", tframe.src, tframe.length);
          writtencount = write(1, tframe.data, tframe.length);
        }

        /* *****************   OD NAS   ***************** */
        /* Zwrocmy uwage na to, ze mozemy byc odbiorca nadanej przez siebie ramki! */
        /* Sprawdzmy, czy to my nadalismy ramke */
        if (tframe.src == myaddr) {
          /* Jesli tak, to  koniec operacji */
          if (tframe.access & 2) {
            /* Komunikat odpowiedni do tego, czy ramka zostala odebrana czy nie */
            fprintf(stderr, "Ramka zakonczyla podroz i zostala przeczytana przez odbiorce.\n");
          } else if (tframe.dest == 255){
            fprintf(stderr, "Ramka rozgloszeniowa zakonczyla podroz po pierscieniu i zostala przez wszystkich odczytana.\n");
          } else {
            fprintf(stderr, "Ramka zakonczyla podroz i NIE zostala przeczytana przez odbiorce.\n");
          }
          /* Obslugiwane w obsluzKolejke() jesli haveToken nie jest == 2: sendToken(); */
          /* Ramka do nas wrocila, wiec opuszczamy znacznik haveToken z 2 do 1: */
          if (haveToken == 2) {
            haveToken = 1;
          } else {
            fprintf(stderr, "BLAD: wrocila do nas wyslana przez nas ramka, a nie mamy tokena na poziomie 2!.\n");
          }
        } else {
          sendFrame(&tframe);
        }
#ifdef DEBUG
        fprintf(stderr, "Zapisano na std wyjscie: %d\n", writtencount);
#endif
      }
    }
  }
  return readcount;
}

tokenframe decodeFrame(char *framedata, ssize_t datalen) {
  tokenframe tframe;
  if (datalen < 5) {
    /* Ramki o dlugosci ponizej 5 bajtow sa bez sensu: */
#ifdef DEBUGTOKENRING
    fprintf(stderr, "Odebrano zbyt krotkie dane (%d bajtow) dla stworzenia ramki\n", datalen);
#endif
    tframe.access = 4;
    return tframe;
  }
  tframe.access = *framedata;
  tframe.src =  *(framedata + 1);
  tframe.dest = *(framedata + 2);
  tframe.length = *(framedata + 3);
  if (datalen < tframe.length + 5) {
    /* Zbyt malo danych dla zadeklarowanej dlugosci: */
#ifdef DEBUGTOKENRING
    fprintf(stderr, "Odebrano zbyt krotkie dane (%d bajtow) dla stworzenia ramki (potrzebne: 5 + %d = %d)\n", datalen, tframe.length, tframe.length + 5);
#endif
    tframe.access = 4;
    return tframe;
  }
  /* TODO: wykrywanie nadmiaru danych */

  /* Zerowanie bitu 3-ciego w "access" (ramka jest juz dekodowalna): */
#ifdef DEBUGTOKENRING
  if (! isToken(&tframe)) {
    fprintf(stderr, "Dane (%d bajtow) wystarczajace dla stworzenia ramki, dekodujemy...\n", datalen);
  }
#endif
  tframe.access = tframe.access & (~ 4);
  if (tframe.access & 1) {
    /* Token nie moze zawierac danych */
    tframe.length = 0;
  }
  if (tframe.length > 0) {
    tframe.data = (char*)malloc(tframe.length);
  } else {
    tframe.data = NULL;
  }
  tframe.data = memcpy(tframe.data, framedata + 4, tframe.length);
  tframe.checksum = *(framedata + 4 + tframe.length);
#ifdef DEBUGTOKENRING
  if (! isToken(&tframe)) {
    fprintf(stderr, "\n{=== Zdekodowana ramka: ===\n");
    fprintf(stderr, "access: %d\n", tframe.access);
    fprintf(stderr, "src: %d\n", tframe.src);
    fprintf(stderr, "dest: %d\n", tframe.dest);
    fprintf(stderr, "length: %d\n", tframe.length);
    fprintf(stderr, "data: %s\n", tframe.data);
    fprintf(stderr, "checksum: %d\n", tframe.checksum);
    fprintf(stderr, " ======= Koniec ramki =====}\n\n");
  }
#endif
  return tframe;
}

/* Obsluz zapis do kolejki */
void obsluzZapis(void) {
  ssize_t readcount;
  ssize_t writtencount;
  char *ptr;
  tokenframe tframe;
  tokenframe* tframeptr;

  /* Czytanie z STDIN do inbuf: */
  readcount = read(0, &inbuf, bufsize);
  /* Prewencyjne ustawienie ostatniego bajtu bufora "inbuf" na 0 aby scanf na pewno sie zatrzymal: */
  ptr = inbuf;
  ptr += bufsize + 10;
  memset(ptr, 0, 1);
  if (readcount > 0) {
#ifdef DEBUG
    fprintf(stderr, "Odczytano z std wejscia: %d\n", readcount);
#endif
    /* Pojawil sie wiersz danych na STDIN */
    if (dest == 0) {
      /* oczekujemy podania adresu stacji docelowej - probujemy parsowac ten wiersz jako liczbe (adres celu) */
      if (sscanf(inbuf, "%hu", &dest) != 1 || dest < 1 )  {
        fprintf(stderr, "Nieprawidlowy adres docelowy (wymagana liczba 1-255)! Podano:\n%s", inbuf);
        dest = 0;
      } else {
        fprintf(stderr, "Adres docelowy: %d\n", dest);
      }
    } else {
#ifdef DEBUGTOKENRING
      fprintf(stderr, "Adres docelowy: %d\n", dest);
#endif
      /* adres stacji docelowej zostal juz podany, odczytany wiersz wysylamy do niej: */
      /* zapisywanie ramki token ring do interfejsu szeregowego: */
      memset(&tframe, 0, sizeof(tokenframe));
      tframe.src = myaddr;
      tframe.dest = dest;
      tframe.length = strnlen(inbuf, readcount);
#ifdef DEBUGTOKENRING
      fprintf(stderr, "Ilosc danych w wysylanej ramce: %d\n", tframe.length);
#endif
      if (tframe.length > 0) {
        tframe.data = (char*)malloc(tframe.length);
      } else {
        tframe.data = NULL;
      }
      tframe.data = memcpy(tframe.data, inbuf, tframe.length);
  
      tframeptr = (tokenframe*)malloc(sizeof(tokenframe));
      memcpy(tframeptr, &tframe, sizeof(tokenframe));
      queueFrame(tframeptr);
      dest = 0;
#ifdef DEBUG
      fprintf(stderr, "Zapisano do portu: %d\n", writtencount);
#endif
    }
  } 
}

void obsluzKolejke(void) {
  tokenframe* tframeptr;
  int iloscWBuf;

  ioctl(uchwytpout, TIOCOUTQ, &iloscWBuf);
  /* Zaczynamy pisac dalsze dane tylko jesli bufor wyjscia juz jest pusty: */
  if (iloscWBuf <= 0) {
    if (haveToken == 1) {
#ifdef DEBUGTOKEN
      /* fprintf(stderr, "Got token at %d, now it is %d.\n", whenGotToken, time(NULL)); */
#endif
      /*if (time(NULL) < (whenGotToken + TOKENTIMEOUT)) {*/
      tframeptr = deQueueFrame();
      if (tframeptr != NULL) {
#ifdef DEBUGTOKENRING
        fprintf(stderr, "Po odebraniu z  deQueue takie jest src: %d\n", tframeptr->src);
#endif
        sendFrame(tframeptr);
        free(tframeptr); tframeptr = NULL;
        /* Wlaczamy oczekiwanie na powrot wyslanej ramki: */
        haveToken = 2;
      } else {
        if (haveToken == 1) {
          /* Nie mamy nic do wyslania, nie czekamy na powrot ramki, wiec nie potrzebujemy tokena: */
          sendToken();
        }
      }
      /*} else { */
      /* Mamy token juz zbyt dlugo (TOKENTIMEOUT), zwalniamy go */
      /*sendToken();
        }*/
    }
  }
}

void waitForWBufEmpty() {
  int iloscWBuf;
  ioctl(uchwytpout, TIOCOUTQ, &iloscWBuf);
  while (iloscWBuf > 0) {
    usleep(20000);
    ioctl(uchwytpout, TIOCOUTQ, &iloscWBuf);
  }
}

void queueFrame(tokenframe* tframe) {
  tokenlink* tlinkptr = (tokenlink*)malloc(sizeof(tokenlink));
  tlinkptr->frame = tframe;

  if (tokenQueue == NULL) {
#ifdef DEBUGQUEUE
    fprintf(stderr, "Kolejka pusta, inicjalizacja: %d\n", queueLength);
#endif
    tlinkptr->prev = tlinkptr;
    tlinkptr->next = tlinkptr;
    tokenQueue = tlinkptr;
  } else {
    /* Element poprzedzajacy glowe kolejki to jej ogon - lista jest cykliczna. */
    /* Dlatego biezacemu ogonowi ustawiamy nowe ogniwo (tlink) jako element nastepny... */
    tokenQueue->prev->next = tlinkptr;
    tlinkptr->prev = tokenQueue->prev;
    /* ... a nastepnie biezacej glowie ustawiamy nowe ogniwo jako element poprzedni (czyli nowy ogon): */
    tokenQueue->prev = tlinkptr;
    tlinkptr->next = tokenQueue;
  }
  queueLength++;
#ifdef DEBUGQUEUE
  fprintf(stderr, "Kolejka sie powiekszyla, rozmiar: %d\n", queueLength);
#endif
}

tokenframe* deQueueFrame() {
  tokenframe* tframeptr;

  /* Lista o dlugosci 0: */
  if (tokenQueue == NULL) {
    return NULL;
  }
  tframeptr = tokenQueue->prev->frame;
  /* Przypadek listy o dlugosci 1: pojedyncze ogniwo wskazujace samo na siebie: */
  if ((tokenQueue->prev) == (tokenQueue)) {
    tokenQueue = NULL;
  } else {
    /* Lista ma dlugosc > 1: */
    /* Poprzednik ogona (moze byc nim tokenQueue - dla listy o dlugosci 2!): */
    tokenlink* tailprev = tokenQueue->prev->prev;
    /* Zwalniamy pamiec po tym ogniwie: */
    /* TODO: poprawne zwalnianie pamieci po ramkach */
    free(tokenQueue->prev);
    /* Latamy dziure po usunietym ogniwie: */
#ifdef DEBUGQUEUE
    fprintf(stderr, "Dlugosc kolejki:%d\n", queueLength);
#endif
    tailprev->next = tokenQueue;
    tokenQueue->prev = tailprev;
  }
  queueLength--;
#ifdef DEBUGQUEUE
    fprintf(stderr, "Odbieramy z kolejki ramke o src: %d\n", tframeptr->src);
#endif

  return tframeptr;
}

ssize_t sendFrame(tokenframe* tframeptr) {
  ssize_t writtencount;
  char dataout[BUFSIZE + 5];
  char *ptr = dataout;
  /* Ustawiamy pole "access": */
  *ptr = tframeptr->access;
  ptr++;
  /* Ustawiamy pole "src": */
  /* TODO */
  *ptr = tframeptr->src;
  ptr++;
  /* Ustawiamy pole "dest": */
  *ptr = tframeptr->dest;
  ptr++;
  /* Ustawiamy pole "length": */
  *ptr = tframeptr->length;
  ptr++;
  /* Ustawiamy pole-wskaznik "data": */
#ifdef DEBUGTOKENRING
  /* nie ma sensu wyswietlac danych debugujacych dla obslugi tokena
   * - on krazy po sieci z duza szybkoscia, komunikaty zalalyby terminal: */
  if (! isToken(tframeptr)) {
    fprintf(stderr, "Kopiowanie do bufora ramki danych o dlugosci:%d\n", tframeptr->length);
    fprintf(stderr, "Dane te:%s\n", tframeptr->data);
  }
#endif
  memcpy(ptr, (*tframeptr).data, (*tframeptr).length);
  /* strncpy(ptr, (*tframe).data, (*tframe).length); */
  ptr+= (*tframeptr).length;
  /* Ustawiamy pole "checksum": */
  *ptr = tframeptr->checksum;
  ptr++;
  /* Wysylamy ramke */
  writtencount = zapiszDoPortu(&dataout, ptr - dataout);
#ifdef DEBUGTOKENRING
  if (! isToken(tframeptr)) {
    fprintf(stderr, "Wyslano ramke o rozmiarze:%d bajtow\n", ptr - dataout);
    fprintf(stderr, "Przeslane zostalo bajtow :%d\n", writtencount);
  }
#endif
  /* TODO: poprawne zwalnianie pamieci po ramkach */
  /*free(tframeptr->data);
  tframeptr->data = NULL;*/
  /* free(tframeptr); */
  return writtencount;
}

void sendToken() {
  tokenframe token;
  if (haveToken) {
    haveToken = 0;
    token.access = 1;
    token.src = myaddr;
    token.dest = 0;
    token.length = 0;
    token.data = NULL;
    checksum(&token);
    sendFrame(&token);
  }
}

unsigned char isToken(tokenframe* tframe) {
  if ((tframe->access) & 1) {
    return 1;
  } else {
    return 0;
  }
}

/* Oblicza sume kontrolna dla ramki i umieszcza w odpowiednim polu */
unsigned char checksum(tokenframe* tframeptr) {
  /* TODO */
  tframeptr->checksum = 16;
  return tframeptr->checksum;
}


ssize_t zapiszDoPortu(char* wbuf, ssize_t bufcount) {
  ssize_t checkcount = 0;
  ssize_t writtencount;
  /* Czekamy na oproznienie bufora zapisu: */
  waitForWBufEmpty();
  /* Zapisuj do portu az oprozni sie bufor */
  while (checkcount < bufcount) {
    writtencount = write(uchwytpout, wbuf + checkcount, bufcount - checkcount);
    checkcount += writtencount;
  }
  return checkcount;
}

int main(int argc, char* argv[]) {
  char* baudname;

  if (argc < 4) {
    fprintf(stderr, "Uzycie: %s urzadzenie_wejsciowe urzadzenie_wyjsciowe adres_stacji_lokalnej [szybkosc w bodach]\n", argv[0]);
    fprintf(stderr, "na przyklad: %s /dev/ttyS0 /dev/ttyS0 1 38400\n", argv[0]);
    exit(1);
  } else {
    indevname = argv[1];
    outdevname = argv[2];
    if (sscanf(argv[3], "%hu", &myaddr) != 1) {
      fprintf(stderr, "Nieprawidlowy adres stacji: %s \nAdres musi byc liczba od 1 do 255\n", argv[3]);
    }
  }
#ifdef DEBUG
  fprintf(stderr, "Nazwa urzadzenia: %s\n", devname);
#endif
  if (argc > 4) {
    baudname = argv[4];
#ifdef DEBUG
    fprintf(stderr, "baudname: %s\n", baudname);
#endif
    if (strncmp(baudname, "300", 8) == 0) {
      baud = B300;
    } else if (strncmp(baudname, "600", 8) == 0) {
      baud = B600;
    } else if (strncmp(baudname, "1200", 8) == 0) {
      baud = B1200;
    } else if (strncmp(baudname, "2400", 8) == 0) {
      baud = B2400;
    } else if (strncmp(baudname, "4800", 8) == 0) {
      baud = B4800;
    } else if (strncmp(baudname, "9600", 8) == 0) {
      baud = B9600;
#ifdef DEBUG
      fprintf(stderr, "ustawiam B9600: %d\n", baud);
#endif
    } else if (strncmp(baudname, "19200", 8) == 0) {
      baud = B19200;
#ifdef DEBU1
      fprintf(stderr, "ustawiam B19200: %d\n", baud);
#endif
    } else if (strncmp(baudname, "38400", 8) == 0) {
      baud = B38400;
    } else if (strncmp(baudname, "57600", 8) == 0) {
      baud = B57600;
    } else if (strncmp(baudname, "115200", 8) == 0) {
      baud = B115200;
    } else {
      fprintf(stderr, "nieznana szybkosc portu: %s\n", baudname);
    }
  }
  if (!otworzporty()) {
    fprintf(stderr, "Blad przy otwieraniu portow, koniec pracy.\n");
  }
  skonfigurujporty();
  fcntl(0, F_SETFL, FNDELAY);
  /* Stacja o adresie 1 ma na starcie token: */
  if (myaddr == 1) {
    haveToken = 1;
  }

  while (1) {
    obsluzOdczyt();
    obsluzZapis();
    obsluzKolejke();
    /* Uspienie na 1/10 sek. */
    /*usleep(100000);*/
    /* Uspienie na 1/50 sek. */
    usleep(20000);
    /* Uspienie na 1/100 sek. */
    /*usleep(10000);*/
  }
  /* printf("%s\n", rbuf); */
  /* Tu reszta... */
  zdekonfigurujport();
  close(uchwytpin);
  close(uchwytpout);
  return 0;
}

