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;
}
w3cw3c
automatyka przemysłowa