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;
}





