c++ - tcsetattr() blocking time with TCSADRAIN flag is weird -
i coding serial port in linux.
and requirement of communication 5ms inter-byte time.
and requires me change parity mode(even , odd) each byte before write() call, according byte's value is.
so code below(i describe code simply)
void setwakeupmode(int fd, bool mode) { struct termios tio; bzero(&tio, sizeof(tio)); tcgetattr(fd, &tio); if (mode == false) { tio.c_cflag &= ~parodd; } else if (mode == true) { tio.c_cflag |= parodd; } if(tcsetattr(fd, tcsadrain, &tio) < 0){ perror("tcsetattr error"); } } int main(){ unsigned char a[2] = {0x01, 0x0f}; write(fd, a, 1); setwakeupmode(fd, true); write(fd, a+1, 1); } but code doesn't satisfy inter-byte time resulting in 20ms.
so tried print exact time between each system call below.
int main(){ unsigned char a[2] = {0x01, 0x0f}; printf("write1 start : %s", /*time*/); write(fd, a, 1); printf("write1 end : %s", /*time*/); setwakeupmode(fd, true); printf("write2 start : %s", /*time*/); write(fd, a+1, 1); printf("write2 end : %s, /*time*/); } and result
write1 start : 34.755201 write1 end : 34.756046 write2 start : 34.756587 write2 end : 34.757349 this result satisfy 5ms inter-byte time, resulting in 1ms inter-byte time.
so tried several ways.
and recognize when print right before tcsetattr(), inter-byte time satisfied.
for example, if remove printf("write1 end : %s, /*time*/); below
int main(){ unsigned char a[2] = {0x01, 0x0f}; printf("write1 start : %s", /*time*/); write(fd, a, 1); // printf("write1 end : %s", /*time*/); //remove setwakeupmode(fd, true); printf("write2 start : %s", /*time*/); write(fd, a+1, 1); printf("write2 end : %s", /*time*/); } the result surprisingly different, see interval between write1 start , write2 start, 18ms.
write1 start : 40.210111 write2 start : 40.228332 write2 end : 40.229187 if use std::cout instead of printf, result same.
why weird situration happen?
-------------------------------edit--------------------------------
since see answers, misunderstanding problem.
i not worrying printf() overhead.
simply saying.
- i want call
write()s 1byte interval betweenwrite()s must within 5ms - and before calling
write(), have change parity mode usingtcsetattr() - but interval result
18ms, being blocked @tcsetattr()time. - but if call
printf()orstd::coutright beforetcsetattr(), interval reduce1~2ms.
that is, somehow, calling printf before tcsetattr() make tcsetattr() return blocking faster.
--------------------------update----------------------------
i have progress on problem.
i said had put printf() or std::cout make blocking time short on tcsetattr().
but not printing affect problem.
it needed delay, is, if put usleep(500) before calling tcsetattr(), make affect on inter-byte-time reducing 1~2ms, returning tcsetattr() faster.
i assume, if call tcsetattr() tcsadrain flag, wait until data in serial buffer transmitted, , change setting want.
and make delay.
but if calling delay, before call tcsetattr(), buffer state empty(because during delay time, data in serial buffer transmitted), there no blocking.
this scenario assume, possible?
this scenario assume, possible?
you must quite right. sawdust wrote:
uart_wait_until_sent() in
drivers/tty/serial/serial_core.cexplains why interval between characters quantized when "drain" involved: serial port driver polled tiocser_temp (transmitter empty) status using delay millisecond resolution.
that's right, except polling cycle resolution not milliseconds, jiffies:
while (!port->ops->tx_empty(port)) { msleep_interruptible(jiffies_to_msecs(char_time)); … so if hz 100 , char_time 1 (the minimum), status checked every 10 ms. wrote:
but if calling delay, before call
tcsetattr(), buffer state empty(because during delay time, data in serial buffer transmitted), there no blocking.
in other words, if delay process long enough time gets transmitter empty test !port->ops->tx_empty(port) transmitter empty, no sleep occurs; otherwise sleeps @ least 1 jiffy.
Comments
Post a Comment