|
@ -23,43 +23,39 @@ |
|
|
using namespace iflytop; |
|
|
using namespace iflytop; |
|
|
using namespace iflytop::core; |
|
|
using namespace iflytop::core; |
|
|
|
|
|
|
|
|
int uartStart(struct UartDevice *dev, unsigned char canonic); |
|
|
|
|
|
int uartSend(struct UartDevice *dev, char *data, int size); |
|
|
|
|
|
int uartReceive(struct UartDevice *dev, char *data, int size_max); |
|
|
|
|
|
int uartStop(struct UartDevice *dev); |
|
|
|
|
|
/*
|
|
|
|
|
|
Parameters: |
|
|
|
|
|
struct UartDevice* dev - pointer to the UartDevice struct |
|
|
|
|
|
unsigned char canonic - communication mode |
|
|
|
|
|
1 - canonic communication (chars are only received after \n is detected). |
|
|
|
|
|
0 - non canonic communication (chars are received as they arrive over UART). |
|
|
|
|
|
Return value: |
|
|
|
|
|
UART_FAILURE -1 failure |
|
|
|
|
|
UART_SUCCESS 0 success |
|
|
|
|
|
Description: |
|
|
|
|
|
Initializes the UART device. |
|
|
|
|
|
When calling the function, the device name (usually "/dev/ttyUL1") must be filled in dev->name and the baud rate |
|
|
|
|
|
must be filled in dev->rate. The canonic function parameter indicates communication mode (canonic or not). In the |
|
|
|
|
|
canonic communication mode, the received chars can be retrieved by read only after \n is detected. In the non canonic |
|
|
|
|
|
communication mode, the received chars can be retrieved by read as they are received, as the non canonic mode is |
|
|
|
|
|
configured with no wait. |
|
|
|
|
|
*/ |
|
|
|
|
|
int uartStart(struct UartDevice *dev, unsigned char canonic) { |
|
|
|
|
|
struct termios *tty; |
|
|
|
|
|
int fd; |
|
|
|
|
|
|
|
|
static map<string, uint32_t> s_baundmap = { |
|
|
|
|
|
{"0", 0000000}, {"50", 0000001}, {"75", 0000002}, {"110", 0000003}, //
|
|
|
|
|
|
{"134", 0000004}, {"150", 0000005}, {"200", 0000006}, {"300", 0000007}, //
|
|
|
|
|
|
{"600", 0000010}, {"1200", 0000011}, {"1800", 0000012}, {"2400", 0000013}, //
|
|
|
|
|
|
{"4800", 0000014}, {"9600", 0000015}, {"19200", 0000016}, {"38400", 0000017}, //
|
|
|
|
|
|
{"57600", 0010001}, {"115200", 0010002}, {"230400", 0010003}, {"460800", 0010004}, //
|
|
|
|
|
|
{"500000", 0010005}, {"576000", 0010006}, {"921600", 0010007}, {"1000000", 0010010}, //
|
|
|
|
|
|
{"1152000", 0010011}, {"1500000", 0010012}, {"2000000", 0010013}, {"2500000", 0010014}, //
|
|
|
|
|
|
{"3000000", 0010015}, {"3500000", 0010016}, {"4000000", 0010017}, |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Uart::Uart() {} |
|
|
|
|
|
Uart::~Uart() {} |
|
|
|
|
|
|
|
|
|
|
|
int Uart::open(string path, string ratestr) { |
|
|
int rc; |
|
|
int rc; |
|
|
|
|
|
|
|
|
fd = open(dev->name, O_RDWR | O_NOCTTY); |
|
|
|
|
|
if (fd < 0) { |
|
|
|
|
|
printf("%s: failed to open file descriptor for file %s\r\n", __func__, dev->name); |
|
|
|
|
|
return UART_FAILURE; |
|
|
|
|
|
|
|
|
m_name = path; |
|
|
|
|
|
uint32_t rate = 0; |
|
|
|
|
|
|
|
|
|
|
|
m_fd = ::open(path.c_str(), O_RDWR | O_NOCTTY); |
|
|
|
|
|
if (m_fd < 0) { |
|
|
|
|
|
m_error = fmt::format("open {} failed,{}", path, strerror(errno)); |
|
|
|
|
|
return -1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
tty = (struct termios *)calloc(1, sizeof(*dev->tty)); |
|
|
|
|
|
if (!tty) { |
|
|
|
|
|
printf("%s: failed to allocate tty instance\r\n", __func__); |
|
|
|
|
|
return UART_FAILURE; |
|
|
|
|
|
|
|
|
if (s_baundmap.find(ratestr) == s_baundmap.end()) { |
|
|
|
|
|
m_error = fmt::format("baund {} not support", ratestr); |
|
|
|
|
|
return -1; |
|
|
} |
|
|
} |
|
|
|
|
|
rate = s_baundmap[ratestr]; |
|
|
|
|
|
m_rate = ratestr; |
|
|
|
|
|
memset(&m_tty, 0, sizeof(m_tty)); |
|
|
// memset(tty, 0, sizeof(struct termios));
|
|
|
// memset(tty, 0, sizeof(struct termios));
|
|
|
/*
|
|
|
/*
|
|
|
BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed. |
|
|
BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed. |
|
@ -70,177 +66,66 @@ int uartStart(struct UartDevice *dev, unsigned char canonic) { |
|
|
CREAD : enable receiving characters |
|
|
CREAD : enable receiving characters |
|
|
*/ |
|
|
*/ |
|
|
// tty->c_cflag = dev->rate | CRTSCTS | CS8 | CLOCAL | CREAD;
|
|
|
// tty->c_cflag = dev->rate | CRTSCTS | CS8 | CLOCAL | CREAD;
|
|
|
tty->c_cflag = dev->rate | CS8 | CLOCAL | CREAD; |
|
|
|
|
|
if (canonic) { |
|
|
|
|
|
// canonic
|
|
|
|
|
|
/*
|
|
|
|
|
|
IGNPAR : ignore bytes with parity errors |
|
|
|
|
|
ICRNL : map CR to NL (otherwise a CR input on the other computer |
|
|
|
|
|
will not terminate input) |
|
|
|
|
|
otherwise make device raw (no other input processing) |
|
|
|
|
|
*/ |
|
|
|
|
|
tty->c_iflag = IGNPAR | ICRNL; |
|
|
|
|
|
/*
|
|
|
|
|
|
ICANON : enable canonical input |
|
|
|
|
|
disable all echo functionality, and don't send signals to calling program |
|
|
|
|
|
*/ |
|
|
|
|
|
tty->c_lflag = ICANON; |
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
m_tty.c_cflag = rate | CS8 | CLOCAL | CREAD; |
|
|
|
|
|
|
|
|
// not canonic
|
|
|
// not canonic
|
|
|
/*
|
|
|
/*
|
|
|
IGNPAR : ignore bytes with parity errorsc_cc[VTIME] |
|
|
IGNPAR : ignore bytes with parity errorsc_cc[VTIME] |
|
|
*/ |
|
|
*/ |
|
|
tty->c_iflag = IGNPAR; |
|
|
|
|
|
|
|
|
m_tty.c_iflag = IGNPAR; |
|
|
/* set input mode (non-canonical, no echo,...) */ |
|
|
/* set input mode (non-canonical, no echo,...) */ |
|
|
tty->c_lflag = 0; |
|
|
|
|
|
|
|
|
m_tty.c_lflag = 0; |
|
|
/* Do not wait for data */ |
|
|
/* Do not wait for data */ |
|
|
tty->c_cc[VTIME] = 0; /* inter-character timer unused */ |
|
|
|
|
|
tty->c_cc[VMIN] = 0; /* blocking read until 5 chars received */ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
m_tty.c_cc[VTIME] = 10; /* inter-character timer unused */ |
|
|
|
|
|
m_tty.c_cc[VMIN] = 0; /* blocking read until 5 chars received */ |
|
|
|
|
|
|
|
|
/*
|
|
|
/*
|
|
|
Raw output. |
|
|
Raw output. |
|
|
*/ |
|
|
*/ |
|
|
tty->c_oflag = 0; |
|
|
|
|
|
|
|
|
m_tty.c_oflag = 0; |
|
|
|
|
|
|
|
|
/* Flush port */ |
|
|
/* Flush port */ |
|
|
tcflush(fd, TCIFLUSH); |
|
|
|
|
|
|
|
|
tcflush(m_fd, TCIFLUSH); |
|
|
|
|
|
|
|
|
/* Apply attributes */ |
|
|
/* Apply attributes */ |
|
|
rc = tcsetattr(fd, TCSANOW, tty); |
|
|
|
|
|
|
|
|
rc = tcsetattr(m_fd, TCSANOW, &m_tty); |
|
|
if (rc) { |
|
|
if (rc) { |
|
|
printf("%s: failed to set TCSANOW attr\r\n", __func__); |
|
|
|
|
|
return UART_FAILURE; |
|
|
|
|
|
|
|
|
m_error = fmt::format("tcsetattr {} failed,{}", path, strerror(errno)); |
|
|
|
|
|
return -1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
dev->fd = fd; |
|
|
|
|
|
dev->tty = tty; |
|
|
|
|
|
|
|
|
|
|
|
return UART_SUCCESS; |
|
|
|
|
|
|
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
Parameters: |
|
|
|
|
|
struct UartDevice* dev - pointer to the UartDevice struct |
|
|
|
|
|
char *data - pointer to the array of chars to be sent over UART |
|
|
|
|
|
int size |
|
|
|
|
|
positive value - number of chars to be sent over UART |
|
|
|
|
|
-1 - indicates that all the chars until string terminator \0 will be sent |
|
|
|
|
|
Return value: |
|
|
|
|
|
number of chars sent over UART |
|
|
|
|
|
Description: |
|
|
|
|
|
This function sends a number of chars over UART. |
|
|
|
|
|
If the size function parameter is -1 then all the characters until string terminator \0 will be sent. |
|
|
|
|
|
*/ |
|
|
|
|
|
int uartSend(struct UartDevice *dev, char *data, int size) { |
|
|
|
|
|
|
|
|
int Uart::send(char *data, int size) { |
|
|
|
|
|
if (logger->level() <= level::debug) { |
|
|
|
|
|
logger->debug("{} send: {}", m_name, StringUtils().bytesToString((const uint8_t *)data, size)); |
|
|
|
|
|
} |
|
|
int sent = 0; |
|
|
int sent = 0; |
|
|
if (size == -1) { |
|
|
|
|
|
size = strlen(data); |
|
|
|
|
|
|
|
|
sent = write(m_fd, data, size); |
|
|
|
|
|
if (sent < 0) { |
|
|
|
|
|
m_error = fmt::format("write {} failed,{}", m_name, strerror(errno)); |
|
|
} |
|
|
} |
|
|
sent = write(dev->fd, data, size); |
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
printf("%s: sent %d characters\r\n", __func__, sent); |
|
|
|
|
|
#endif
|
|
|
|
|
|
return sent; |
|
|
return sent; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
Parameters: |
|
|
|
|
|
struct UartDevice* dev - pointer to the UartDevice struct |
|
|
|
|
|
char *data - pointer to the array of chars to hold the cars revceived over UART |
|
|
|
|
|
int size_max - the maximum number of characters to be received |
|
|
|
|
|
Return value: |
|
|
|
|
|
number of chars received over UART |
|
|
|
|
|
Description: |
|
|
|
|
|
This function receives characters over UART. |
|
|
|
|
|
In the canonic communication mode, the received chars will be retrieved by read only after \n is detected. |
|
|
|
|
|
In the non canonic communication mode, the received chars will be retrieved by read as they are received, as the |
|
|
|
|
|
non canonic mode is configured with no wait. |
|
|
|
|
|
*/ |
|
|
|
|
|
int uartReceive(struct UartDevice *dev, char *data, int size_max) { |
|
|
|
|
|
|
|
|
int Uart::receive(char *data, int size_max) { |
|
|
int received = 0; |
|
|
int received = 0; |
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
// printf("%s: receiving characters %d\r\n", __func__, size_max);
|
|
|
|
|
|
#endif
|
|
|
|
|
|
received = read(dev->fd, data, size_max - 1); |
|
|
|
|
|
data[received] = '\0'; |
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
// if(received > 0)
|
|
|
|
|
|
// printf("%s: received %d characters\r\n", __func__, received);
|
|
|
|
|
|
// else
|
|
|
|
|
|
// printf("%s: r%d/%d\r\n", __func__, received, size_max);
|
|
|
|
|
|
#endif
|
|
|
|
|
|
return received; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int uartStop(struct UartDevice *dev) { |
|
|
|
|
|
free(dev->tty); |
|
|
|
|
|
|
|
|
|
|
|
return UART_SUCCESS; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
using namespace iflytop; |
|
|
|
|
|
using namespace core; |
|
|
|
|
|
|
|
|
|
|
|
Uart::Uart(const char *path, int rate) { |
|
|
|
|
|
this->device.name = strdup(path); |
|
|
|
|
|
this->device.rate = rate; |
|
|
|
|
|
} |
|
|
|
|
|
Uart::~Uart() { |
|
|
|
|
|
if (this->device.name) free(this->device.name); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int Uart::start(unsigned char canonic) { return uartStart(&this->device, canonic); } |
|
|
|
|
|
int Uart::send(char *data, int size) { |
|
|
|
|
|
if (logger->level() <= level::debug) { |
|
|
|
|
|
logger->debug("{} send: {}", this->device.name, StringUtils().bytesToString((const uint8_t *)data, size)); |
|
|
|
|
|
|
|
|
received = read(m_fd, data, size_max); |
|
|
|
|
|
if (received < 0) { |
|
|
|
|
|
m_error = fmt::format("read {} failed,{}", m_name, strerror(errno)); |
|
|
} |
|
|
} |
|
|
return uartSend(&this->device, data, size); |
|
|
|
|
|
} |
|
|
|
|
|
int Uart::receive(char *data, int size_max) { |
|
|
|
|
|
int ret = uartReceive(&this->device, data, size_max); |
|
|
|
|
|
if (logger->level() <= level::debug) { |
|
|
if (logger->level() <= level::debug) { |
|
|
if (ret > 0) { |
|
|
|
|
|
logger->debug("{} receive: {}[{}]", this->device.name, StringUtils().bytesToString((const uint8_t *)data, ret)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
logger->debug("{} receive: {}", m_name, StringUtils().bytesToString((const uint8_t *)data, received)); |
|
|
} |
|
|
} |
|
|
return ret; |
|
|
|
|
|
} |
|
|
|
|
|
int Uart::stop() { |
|
|
|
|
|
int rc = uartStop(&this->device); |
|
|
|
|
|
return rc; |
|
|
|
|
|
} |
|
|
|
|
|
bool Uart::flush_rx() { |
|
|
|
|
|
int rc = tcflush(this->device.fd, TCIFLUSH); |
|
|
|
|
|
return rc == 0; |
|
|
|
|
|
} |
|
|
|
|
|
bool Uart::flush_tx() { |
|
|
|
|
|
int rc = tcflush(this->device.fd, TCOFLUSH); |
|
|
|
|
|
return rc == 0; |
|
|
|
|
|
} |
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief Set the rx overtime object |
|
|
|
|
|
* |
|
|
|
|
|
* @param n100ms 设置超时时间,单位100ms,如果为0,则不超时,立即返回 |
|
|
|
|
|
* @return true |
|
|
|
|
|
* @return false |
|
|
|
|
|
*/ |
|
|
|
|
|
bool Uart::set_rx_overtime(int n100ms) { |
|
|
|
|
|
this->device.tty->c_cc[VTIME] = n100ms; |
|
|
|
|
|
int rc = tcsetattr(this->device.fd, TCSANOW, this->device.tty); |
|
|
|
|
|
return rc == 0; |
|
|
|
|
|
|
|
|
return received; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
int Uart::receive(char *data, int size, int overtimems) { |
|
|
int Uart::receive(char *data, int size, int overtimems) { |
|
|
|
|
|
if (m_fd < 0) return -1; |
|
|
|
|
|
|
|
|
tp_steady now = tu_steady().now(); |
|
|
tp_steady now = tu_steady().now(); |
|
|
tp_steady end = now + std::chrono::milliseconds(overtimems); |
|
|
tp_steady end = now + std::chrono::milliseconds(overtimems); |
|
|
int rc = 0; |
|
|
int rc = 0; |
|
|
int total = 0; |
|
|
int total = 0; |
|
|
while (now < end) { |
|
|
while (now < end) { |
|
|
rc = uartReceive(&this->device, data + total, size - total); |
|
|
|
|
|
|
|
|
rc = receive(data + total, size - total); |
|
|
if (rc > 0) { |
|
|
if (rc > 0) { |
|
|
total += rc; |
|
|
total += rc; |
|
|
if (total >= size) break; |
|
|
if (total >= size) break; |
|
@ -250,3 +135,24 @@ int Uart::receive(char *data, int size, int overtimems) { |
|
|
} |
|
|
} |
|
|
return total; |
|
|
return total; |
|
|
} |
|
|
} |
|
|
|
|
|
int Uart::close() { |
|
|
|
|
|
::close(m_fd); |
|
|
|
|
|
m_fd = -1; |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
bool Uart::flush_rx() { |
|
|
|
|
|
if (m_fd < 0) return false; |
|
|
|
|
|
int rc = tcflush(m_fd, TCIFLUSH); |
|
|
|
|
|
return rc == 0; |
|
|
|
|
|
} |
|
|
|
|
|
bool Uart::flush_tx() { |
|
|
|
|
|
if (m_fd < 0) return false; |
|
|
|
|
|
int rc = tcflush(m_fd, TCOFLUSH); |
|
|
|
|
|
return rc == 0; |
|
|
|
|
|
} |
|
|
|
|
|
bool Uart::set_rx_overtime(int n100ms) { |
|
|
|
|
|
if (m_fd < 0) return false; |
|
|
|
|
|
m_tty.c_cc[VTIME] = n100ms; |
|
|
|
|
|
int rc = tcsetattr(this->m_fd, TCSANOW, &m_tty); |
|
|
|
|
|
return rc == 0; |
|
|
|
|
|
} |