Linux串口设备的Canonical and noncanonical mode

Canonical and noncanonical mode

可能翻译为规范/非规范模式?

通过termios结构体的c_lflag成员来设置Canonical or noncanonical mode.

这两种模式是串口输入相关的配置。

Canonical模式中:

  • 串口读取的单位是行,行定义为包含行结束符:NL, EOL, EOL2; or EOF at the start of line。read()收到结束符后即返回,其中除了EOF之外(回车符等)与普通字符一样会被read()函数读到缓冲区中。
  • 如何read在没有读到结束符之前意外终止,缓存的数据将被保留。下次read调用将包含这些数据。

noncanonical模式中:

  • 串口读取的单位是字节,不需要等待任何的结束符,而是由MIN (c_cc[VMIN])和TIME (c_cc[VTIME])的设置来决定read何时返回。


VMIN和VTIME

给出定义:

  • VMIN:noncanonical mode中规定read()返回的的最小字节数。
  • VTIME:noncanonical mode中规定read()返回的超时时间(100ms为单位)。

比如说,存在以下几种情况:

MIN == 0, TIME == 0 (polling read)

有数据就返回,返回值是min{当前可用数据长度, 请求数据长度},若没有数据则返回0,不等待。

请求数据长度:count in ssize_t read(int fd, void *buf, size_t count);


MIN > 0, TIME == 0 (blocking read)

直到接受MIN个字节时,read才返回。

但是若请求数据长度<MIN,read会在读到请求数据长度时提前返回。


MIN == 0, TIME > 0 (read with timeout)

调用read()时开始计时,在TIME时间内,若收到数据就返回。


MIN > 0, TIME > 0 (read with interbyte timeout)

在收到字节的数据后开始计时。read()返回的原因包括:

  1. TIME时间内,MIN长度的数据已到达。
  2. TIME计时时间到。
  3. TIME时间内,请求数据长度的数据已到达。(POSIX未规定此情况,所以有可能其他系统未实现!)

所以此类情况下,造成read()返回的返回值必然>0,否则计时器不会开启,read()阻塞在那。


补充:Linux中标准输入/输出的行缓存

在linux中有时调用printf()打印却不显示,可能是因为没有加换行符(\n)导致的,这就是Linux中关于标准输入/输出默认是启用行缓存的。其实是与我们上面提到的Canonical mode同样的原理。

解决的方案有三个:

  1. 手动添加换行符(\n);这种方式具有局限性,因为有的时候换行符会对原始数据造成干扰。

  2. 刷新标准输出缓冲区;

    执行fflush(stdout)将目前缓冲区中的数据发送给输出设备,来刷新缓冲区。

  3. 关闭行缓存;

    setvbuf(stdout,NULL,_IONBF,0);
    

    暴力的关闭输出缓冲区,这样接受到的数据就会直接发送给输出设备了。

posted @ 2021-10-17 12:31  cnwanglu  阅读(454)  评论(0编辑  收藏  举报