RISC-V/V203/usb/usart/test/usart.cpp
2024-10-16 15:46:34 +02:00

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