4

I was trying to log data from RS232 into a file with cat:

cat /dev/ttyS0 > rs232.log

The result was that I had everything in my file except for the last line.

By printing to stdout, I was able to discover, that cat only writes the output if it gets a newline character ('\n'). I discovered the same with:

dd bs=1 if=/dev/ttyS0 of=rs232.log

After reading How can I print text immediately without waiting for a newline in Perl? I was starting to think, if this could be a buffering problem of either the Linux-Kernel or the coreutils package.

According to TJD's comment, I wrote my own program in C but still had the same problems:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* args[])
{
    char buffer;
    FILE* serial;
    serial = fopen(args[1],"r");
    while(1)
    {
        buffer = fgetc(serial);
        printf("%c",buffer);
    }
}

As of the results of my own C-Code this seems to be a Linux-Kernel related issue.

Community
  • 1
  • 1
FSMaxB
  • 2,280
  • 3
  • 22
  • 41
  • Maybe this will help, "[Perl, disable buffering input][1]": use `sysread`. [1]: http://stackoverflow.com/questions/12351500/perl-disable-buffering-input – aqn Oct 03 '12 at 14:22
  • @aqn: I have to admit, that I don't fully understand the use of perl and how it could help me with this. I didn't really understand the subject of the Post in your link, so I tried the given commands in that post and it didn't work. Besides I don't know if every system on which I have to use this command has an installed perl-interpreter. – FSMaxB Oct 03 '12 at 14:34
  • You could definitely write your own 5 line program in C or python to read the port and print with immediate flushing. – TJD Oct 03 '12 at 14:44
  • Arg! No formatting allowed in comments! I'm gonna put my answer in a reply... – aqn Oct 03 '12 at 14:47
  • In your C program, use open() and read() and write() instead of fopen() and fgetc() and printf() which buffers input and output and will not work w/o a newline in the input. – aqn Oct 03 '12 at 15:21
  • @aqn: The buffering in question isn't done in the C stdio library, but inside the kernel tty driver. – Ben Voigt Oct 03 '12 at 15:37

2 Answers2

6

You're opening a TTY. When that TTY is in cooked (aka canonical) mode, it performs line processing (e.g. backspace removes the previous character from the buffer). You'll want to put the TTY into raw mode in order to get every single byte when it arrives instead of waiting for the end of line.

From the man page:

Canonical and noncanonical mode

The setting of the ICANON canon flag in c_lflag determines whether the terminal is operating in canonical mode (ICANON set) or noncanonical mode (ICANON unset). By default, ICANON set.

In canonical mode:

  • Input is made available line by line. An input line is available when one of the line delimiters is typed (NL, EOL, EOL2; or EOF at the start of line). Except in the case of EOF, the line delimiter is included in the buffer returned by read(2).

  • Line editing is enabled (ERASE, KILL; and if the IEXTEN flag is set: WERASE, REPRINT, LNEXT). A read(2) returns at most one line of input; if the read(2) requested fewer bytes than are available in the current line of input, then only as many bytes as requested are read, and the remaining characters will be available for a future read(2).

In noncanonical mode input is available immediately (without the user having to type a line-delimiter character), and line editing is disabled.

The simplest thing to do is just to call cfmakeraw.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
0

Does this work?

perl -e 'open(IN, "/dev/ttyS0") || die; while (sysread(IN, $c, 1)) { print "$c" }'

This DOES work:

$ echo -n ccc|perl -e 'while (sysread(STDIN, $c, 1)) { print "$c" } '
ccc$
aqn
  • 2,542
  • 1
  • 16
  • 12
  • The first one has the same problem as cat and dd, the second one ends without having done anything visible. – FSMaxB Oct 03 '12 at 15:03
  • I have to correct myself, the second command does work, but I didn't see the ccc in front of my prompt line at first. Using echo for the serial port does work, but it seems to send '\n' automatically. – FSMaxB Oct 03 '12 at 15:11
  • If the second one ends without having done anything (it should have printed out "ccc", without a trailing newline, as illustrated) then perhaps "echo -n" on your system does something different. When you do "echo -n ccc" do you get "ccc", without a trailing newline? Also, it's possible that the display of your shell command prompt clobbers the "ccc" output. What do you see when you do the same command but pipe it through "od -c"? – aqn Oct 03 '12 at 15:20