85 lines
2.4 KiB
C++
85 lines
2.4 KiB
C++
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <stdint.h>
|
|
#include <termios.h>
|
|
#include <sys/ioctl.h>
|
|
#include "usart.h"
|
|
|
|
UsartClass::UsartClass (const char * name, const int baudrate) : BaseLayer() {
|
|
id = name;
|
|
running = false;
|
|
fd = ::open (id, O_RDWR);
|
|
if (fd < 0) return;
|
|
|
|
timeout = 20'000'000 / baudrate; // cca 2 násobek pro 1 byte
|
|
|
|
struct termios LineFlags;
|
|
int attr = tcgetattr (fd, &LineFlags);
|
|
if (attr) {
|
|
printf ("Nelze zjistit parametry portu %s\r\n", name);
|
|
::close (fd);
|
|
return;
|
|
}
|
|
// nastaveni komunikacnich parametru do struct termios
|
|
LineFlags.c_iflag = IGNPAR /* | IXON | IXOFF*/; // ignoruj chyby parity
|
|
LineFlags.c_oflag = 0; // normalni nastaveni
|
|
LineFlags.c_cflag = CS8 | CREAD | CLOCAL; // 8-bit, povol prijem
|
|
LineFlags.c_lflag = 0; // Raw input bez echa
|
|
LineFlags.c_cc [VMIN] = 1; // minimalni pocet znaku pro cteni
|
|
LineFlags.c_cc [VTIME] = 1; // read timeout 0.1 s
|
|
|
|
tcsetattr (fd, TCSANOW, &LineFlags);
|
|
fcntl (fd, F_SETFL, 0);
|
|
|
|
int flag = TIOCM_DTR;
|
|
ioctl(fd, TIOCMBIS, & flag);
|
|
|
|
setBaud(baudrate);
|
|
|
|
printf ("Port %s opened (%d) at %d Bd\r\n", id, fd, baudrate);
|
|
usleep (10000);
|
|
running = true;
|
|
pthread_create (&rc, NULL, UsartClass::UsartHandler, this);
|
|
}
|
|
|
|
UsartClass::~UsartClass() {
|
|
running = false;
|
|
pthread_cancel (rc);
|
|
|
|
int flag = TIOCM_DTR;
|
|
ioctl(fd, TIOCMBIC, & flag);
|
|
|
|
::close (fd);
|
|
printf ("Port %s closed\r\n", id);
|
|
}
|
|
uint32_t UsartClass::Up (const char * data, uint32_t len) {
|
|
return BaseLayer::Up (data, len);
|
|
}
|
|
|
|
uint32_t UsartClass::Down (const char * data, uint32_t len) {
|
|
if (!running) return 0;
|
|
const unsigned maxchunk = 32; // USB bulk len (64) je moc
|
|
unsigned offset = 0, remain = len;
|
|
while (remain) {
|
|
const unsigned chunk = remain > maxchunk ? maxchunk : remain;
|
|
const unsigned writn = ::write (fd, data + offset, chunk);
|
|
// Počkat je nejjednodušší prevence zahlcení USB (USART má omezenou rychlost)
|
|
usleep (timeout * writn); // závisí na baud rate
|
|
offset += writn;
|
|
remain -= writn;
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
void UsartClass::ReadLoop (void) {
|
|
int n;
|
|
while (running) {
|
|
// Nutno číst po jednom nebo použít timer, jinak to po prvním čtení zdechne.
|
|
n = ::read (fd, rxbuf, 1);
|
|
if (!n) continue;
|
|
Up (rxbuf, n);
|
|
}
|
|
}
|