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::cout
right 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.c
explains 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