Wysyłanie danych przez port szeregowy
-- Sebastian Pawlak, 2005.
Przedstawiony program umożliwia wysyłanie danych z pliku przez port szeregowy. Użytkownik może ustawić parametry transmisji.
Kod źródłowy pliku "nadajnik.c":
/* Nadajnik * Program wysyla plik na odpowiedni tty z odpowiednia predkoscia, liczba * bitow znaku, parzystoscia. * * Sebastian Pawlak, 2005. */ #include <stdio.h> #include <fcntl.h> /* dla creat(), flag typu O_RDONLY, O_NOCTTY */ #include <unistd.h> /* dla read(), write(), close(), usleep(), alarm() */ #include <stdlib.h> /* dla strtol() i exit() */ #include <termios.h> #include <string.h> /* dla bzero() */ #include <signal.h> #define PORT "/dev/ttyS1" /* port szeregowy - wysylanie danych */ #define FILE_NAME "pl" /* domyslna nazwa pliku do wyslania */ enum { DEFAULT_SPEED = 9600, /* domyslna predkosc transmisji */ BUF_SIZE = 255, /* rozmiar bufora na dane */ OPEN_TIMEOUT = 10, /* max. czas oczekiwania na otwarcie portu */ DEFAULT_PARITY = 0, DEFAULT_CHARSIZE = 8, DEFAULT_STOPBITS = 1 }; int speed = DEFAULT_SPEED; int parity = DEFAULT_PARITY; int charsize = DEFAULT_CHARSIZE; int stopbits = DEFAULT_STOPBITS; int fdS; /* deskryptor pliku */ struct termios oldS, newS; /* konfiguracja portu */ char portName[256]; char fileName[256]; int openPort(const char *dev, int flag); int confPort(int, struct termios *old, struct termios *new); void catchSignal(int); int main(int argc, char *argv[]) { int n = 0, i, k = 0; unsigned char buf[BUF_SIZE]; /* bufor na dane wejsciowe */ static struct sigaction act; int f; void info(void); fprintf(stdout, "NADAJNIK\n\n"); /* analiza parametrow wywolania */ if (argc >= 2) { /* ... jesli podano przynajmniej jeden parametr */ /* szybkosc */ n = strtol(argv[1], NULL, 10); if ((n != 1200) && (n != 1800) && (n != 2400) && (n != 4800) && (n != 9600) && (n != 19200) && (n != 38400) && (n != 57600)) { fprintf(stderr, "Bledna szybkosc transmisji (dostepne: 1200, 1800, " "2400, 4800, 9600, 19200, 38400, 57600)!\n\n"); info(); exit(-1); } speed = n; } if (argc >= 3) { /* liczba bitow */ charsize = strtol(argv[2], NULL, 10); if (charsize < 5) charsize = 8; else if (charsize > 8) charsize = 8; } if (argc >= 4) { /* parzystosc */ parity = strtol(argv[3], NULL, 10); if (parity < 0) parity = 0; else if (parity > 2) parity = 2; } if (argc >= 5) /* nazwa portu */ sprintf(portName, "%s", argv[4]); else sprintf(portName, "%s", PORT); if (argc >= 6) /* plik */ sprintf(fileName, "%s", argv[5]); else sprintf(fileName, "%s", FILE_NAME); if (argc < 2) { info(); return 0; } /* obsluga sygnalow - m.in. opuszczanie programu po nacisnieciu CTRL+C */ act.sa_handler = catchSignal; sigfillset(&(act.sa_mask)); sigaction(SIGQUIT, &act, NULL); sigaction(SIGKILL, &act, NULL); sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); /* otwarcie pliku z danymi */ if ((f = open(fileName, O_RDONLY, 0)) == -1) { fprintf(stderr, "Problem z otwarciem pliku \"%s\"!\n", fileName); exit(-1); } /* otwieranie i konfiguracja portu */ fdS = openPort(portName, O_WRONLY); /* ttySx, tylko do zapisu */ confPort(fdS, &oldS, &newS); fprintf(stdout, "Rozpoczynam nadawanie (speed: %d, port: %s, file: %s)\n", speed, portName, fileName); /* glowna petla: nadawanie danych */ while ((n = read(f, buf, BUF_SIZE)) > 0) { /* z pliku */ if ((i = write(fdS, buf, n)) != n) /* do portu */ fprintf(stderr, "Problem z write(): %d, %d\n", n, i); k += n; printf("dotychczas wyslano do FIFO znakow: %d\n", k); } close(f); close(fdS); return 0; } /* info: wypisuje menu z dostepnymi opcjami uruchamiania programu */ void info(void) { fprintf(stdout, "uzycie: ./nadajnik szybkosc charsize parity port plik\n" " gdzie: szybkosc - szybkosc odbioru w bps;\n" " dostepne: 1200, 1800, " "2400, 4800, 9600, 19200, 38400, 57600)\n\n" " domyslna szybkosc: %d\n\n", speed); fprintf(stdout, " charsize - 8, 7, ...\n\n"); fprintf(stdout, " parity - 0 (N), 1 (O), 2 (E)\n\n"); fprintf(stdout, " port - /dev/ttyS0, /dev/ttyS1, ...\n\n"); fprintf(stdout, " plik - plik do wyslania.\n\n"); } /* catchSignal: funkcja obslugi sygnalow - przywraca pierwotne ustawienia * portow, zamyka pliki, konczy dzialanie programu */ void catchSignal(int n) { /* oproznianie kolejki */ tcflush(fdS, TCIOFLUSH); /* odtwarzanie pierwotnych ustawien portu */ tcsetattr(fdS, TCSANOW, &oldS); /* zamykanie pliku */ close(fdS); fprintf(stdout, "Koniec.\n"); exit(0); } /* setTimeout: obsluguje sytuacje, w ktorej funkcja "open" zbyt dlugo * nie zwraca sterowania */ static void setTimeout(int n) { fprintf(stderr, "Przekroczony limit czasu oczekiwania na otwarcie " "portu \"%s\"!\n", portName); exit(-1); } /* openPort: otwiera wskazany port szeregowy i zwraca uchwyt do niego */ int openPort(const char *dev, int flag) { int fd; static struct sigaction act, oact; /* ustawienia dla SIGALRM - zabezpieczenie na wypadek zbyt dlugiego * czasu powrotu z funkcji "open" */ act.sa_handler = setTimeout; sigfillset(&(act.sa_mask)); sigaction(SIGALRM, &act, &oact); alarm(OPEN_TIMEOUT); /* otwarcie portu */ if ((fd = open(dev, flag | O_NOCTTY)) == -1) { char s[256]; sprintf(s, "Blad otwarcia \"%s\"", dev); perror(s); exit(-1); } /* przywracanie poprzedniego stanu dla "alarm" */ alarm(0); sigaction(SIGALRM, &oact, &act); return fd; } /* confPort: ustawia odpowiednie parametry dla portu szeregowego */ int confPort(int f, struct termios *old, struct termios *new) { enum { SPD_SIZE = 8 }; const struct { int speed; speed_t def; } spd[SPD_SIZE] = { { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, { 4800, B4800 }, { 9600, B9600 }, { 19200, B19200 }, { 38400, B38400 }, { 57600, B57600 } }; /* dopuszczalne szybkosci */ int i; tcgetattr(f, old); /* zachowanie aktualnych ustawien portu */ bzero(new, sizeof (new)); /* czyszczenie struktury */ /*fcntl(f, F_SETFL, FNDELAY);*/ /* tryb blokujacy, gdy zakomentowane */ /* CRTSCTS: sprzetowa kontrola przeplywu, * CLOCAL : polaczenie lokalne, * CREAD : zezwolenie na odbior znakow. */ new->c_cflag = CRTSCTS | CLOCAL | CREAD; /* IGNPAR : ignoruje bledne dane */ new->c_iflag = IGNPAR; /* parzystosc: brak, parzysta, nieparzysta */ switch (parity) { case 0: default: /* brak kontroli parzystosci */ break; case 1: /* parzystosc nieparzysta */ new->c_iflag |= INPCK; new->c_cflag |= PARENB | PARODD; printf("parity: odd\n"); break; case 2: new->c_iflag |= INPCK; new->c_cflag |= PARENB; /* parzystosc parzysta */ printf("parity: even\n"); break; } /* liczba bitow znaku: CS5, CS6, CS7, CS8 */ switch (charsize) { case 8: default: new->c_cflag |= CS8; printf("char: 8\n"); break; case 7: new->c_cflag |= CS7; printf("char: 7\n"); break; case 6: new->c_cflag |= CS6; printf("char: 6\n"); break; case 5: new->c_cflag |= CS5; printf("char: 5\n"); break; } /* liczba bitow stopu: 1, 2 */ switch (stopbits) { case 1: default: /* 1 bit stopu, domyslnie w termios */ break; case 2: /* 2 bity stopu */ new->c_cflag |= CSTOPB; break; } /* surowe wyjscie i wejscie */ new->c_oflag = 0; new->c_lflag = 0; /* parametry MIN i TIME */ new->c_cc[VMIN] = 1; /* oczekiwanie na chociaz jeden znak */ new->c_cc[VTIME] = 0; /* oczekiwanie nieskonczone */ /* szybkosci transmisji */ for (i = 0; (i < SPD_SIZE) && (spd[i].speed != speed); i++) ; if (i == SPD_SIZE) /* nie znaleziono szybkosci na liscie */ return -1; cfsetispeed(new, spd[i].def); /* ustawienie szybkosci transmisji */ cfsetospeed(new, spd[i].def); tcflush(f, TCIOFLUSH); /* oproznianie kolejek we. i wy. */ tcsetattr(f, TCSANOW, new); /* aktywacja nowych ustawien portu */ return 0; }