El command cat in shell no finaliza al recetar EOT a través del serial port

Tengo una secuencia de commands shell / perl que inicia commands cat para recibir datos seriales entrantes desde un dispositivo externo.

El dispositivo externo está diseñado para enviar y enviar un carácter EOT cuando está listo para transmitir. Pero el command cat nunca termina al recibir EOT, de hecho imprime todos los datos de serie, seguidos de la pequeña caja con (0004) que es el valor hexadecimal para EOT.

Cuando canalizo todos estos datos en un file y lo abro en VIM, veo el EOT char representado por ^ D.

Me gustaría ¿por qué el command cat en la terminal no detectaría el EOT?

EDITAR: stty –all –file = (serial_port) yeilds

velocidad 115200 baudios; filas 0; columnas 0; línea = 0; intr = ^ C; quit = ^ \; borrar = ^ ?; matar = ^ U; eof = ^ D; eol =; eol2 =; swtch =; start = ^ Q; detener = ^ S; susp = ^ Z; rprnt = ^ R; werase = ^ W; lnext = ^ V; flush = ^ O; min = 1; time = 0; -parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts -cdtrdsr -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8 -opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 -isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke

CTRL + D no tiene sentido aquí, es solo otro byte. Esto se debe a que su terminal serie no está configurado para manejarlo. Específicamente, está efectivamente en modo raw o modo de input no canónico . ¿Ves el indicador -icanon en tu stty -a salida? Eso lo cincha. Así es cómo POSIX describe un terminal debe considerar un carácter EOF:

  • EOF
    • Carácter especial en la input, que se reconoce si se establece el indicador ICANON . Cuando se reciben, todos los bytes que esperan ser leídos se pasan inmediatamente al process sin esperar una nueva línea, y el EOF se descarta. Por lo tanto, si no hay bytes esperando (es decir, el EOF ocurrió al comienzo de una línea) , se devolverá un recuento de bytes de la read() , que representa una indicación de fin de file. Si se establece ICANON , el carácter EOF se descartará cuando se procese.

Pero no está trabajando con un terminal canónico: está trabajando con un terminal que enviará todos los datos a cualquier lector si se lo solicita, siempre que haya al less un byte para enviar. El terminal no almacena la input por línea, por lo que no puede replace el byte EOF con una lectura vacía, sino que simplemente empuja el byte, lo cual, para cat solo lo alienta a seguir leyendo.

  • Si se establece ICANON , se habilitará el procesamiento canónico. Esto permite borrar y eliminar funciones de edición, y el ensamblaje de caracteres de input en líneas delimitadas por NL , EOF y EOL , como se describe en Procesamiento de input en modo canónico .

  • Si ICANON no está configurado, las requestes de lectura se satisfarán directamente desde la queue de input. Una lectura no se cumplirá hasta que se hayan recibido al less MIN bytes o el valor de time de espera TIME haya expirado entre bytes. El valor del time representa décimas de segundo. Consulte Procesamiento de input en modo no canónico para get más detalles.

El carácter EOT no marca el final de un file. Un file puede contener bytes arbitrarios.

Al presionar Ctrl + D en un terminal, la aplicación piensa que ha llegado el final del file. La aplicación no lee un carácter Ctrl + D (EOT), ve una indicación de fin de file. La interpretación de Ctrl + D como carácter de fin de input la realiza el controller de terminal en el kernel; se puede personalizar con el command stty (por ejemplo, stty eof ^E para cambiar el caracter o stty eof ^- para deshabilitar la caracteristica). Esto es específico para los terminales, no se aplica a files regulares, a tuberías, a dispositivos que no son terminales, etc. En particular, no se aplica a puertos serie.

No hay una utilidad de shell estándar que deje de leer en EOT o en un carácter configurable y acepte inputs binarias arbitrarias. Si no hay bytes nulos en su input, puede usar el command de head o el shell de read incorporado para leer una línea después de intercambiar EOT con EOL:

 data=$(tr '\004\012' '\012\004` | head -n 1 | tr '\004\012' '\012\004`; echo a) data=${data#a} 

(La ventaja adicional es garantizar que se preservan las nuevas líneas al final de los datos).