Lolo
Lolo

Reputation: 7

Corrupted data over serial

I have a problem. I have 2 pieces of hardware (similar to pi) and I'm trying to test communication over serial cable between them. Both are linux based but have limited tools. I have wrote a script to send and receive files. When I send a txt file with some text on it, everything works fine. When i try to send a binary file, the data it's not the same, sometimes i get bigger file, sometimes smaller and sometimes just some bytes are changed. I'm wondering for hours why this happens, I set the devices to raw mode (for binary file)...

Here's the scrpit I wrote:

#!/bin/bash

    FILE=$2

    send()
    {
            if [ ! -f $FILE ]; then
                    echo "File $2 doesn not exist, please introduce a valid file"
            fi
            content=`cat "$FILE"` #Dump the file content into variable
            echo -E  "$content" > /dev/ttyO5 #send the whole content to the other device



    }
    receive()
    {

            if [ -f $FILE ]; then
                    echo "The file already exists. Do you want to overwrite it? (y/n
                    read opc
                    if [ "$opc" == "n" ]; then
                            exit 1
                    fi
                    rm "$FILE"
            fi

            while read -t 5 -r -n 1 c; do  # read char by char -r to avoid backslashes to be scaped
                    echo -E -n  "$c" >> $FILE # append char on file -n(to avoid creation of new lines and -E to avoid interpretation of backslashes.

            done < /dev/ttyO5

    }
    case $1 in

            's')
                    send
                    ;;
            'r')
                    receive
                    ;;
            *)
                    echo "Usage $0 [s | r] [FILE]"
                    ;;

    esac

To put the devices on raw mode, I use stty -F /dev/ttyO5 raw and this are the options of the device:

speed 9600 baud;stty: /dev/ttyO5
 line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts
-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

My mind tells me that there's a problem when interpretating some chars and that it might be fixed changing some of the options above. I try several, but i cant make it work. If somebody sees something I dont, i would highly appreciate it.

Regards

EDIT: Problem found but not solved. Read and cat dont like the characters NULL and \n. How could i read those 2 chars?

Upvotes: 0

Views: 596

Answers (1)

Nahuel Fouilleul
Nahuel Fouilleul

Reputation: 19315

Add IFS= before read to allow to read space, tab characters

 while IFS= read -t 5 -r -n 1 c; do

EDIT: '\n' and '\0' still can't be read.

Compare the two following outputs

for i in {{0..9},a,b,c,d,e,f}{{0..9},a,b,c,d,e,f};do printf '\x'"$i"; done | od -c

for i in {{0..9},a,b,c,d,e,f}{{0..9},a,b,c,d,e,f};do printf '\x'"$i"; done | { while IFS= read -r -n1 c; do echo -E -n "$c";done;} | od -c

EDIT: to read a newline add the option -d ''

 while IFS= read -t 5 -r -n 1 -d '' c; do

If [[ $c = '' ]]; so it's the '\0' character in this case, use printf '\0' for example to write it

Following command proves that all character can be copied

for i in {{0..9},a,b,c,d,e,f}{{0..9},a,b,c,d,e,f};do printf '\x'"$i"; done | { while IFS= read -r -n1 -d '' c; do if [[ $c = '' ]]; then printf '\0'; else echo -E -n "$c";fi;done;} | od -c

EDIT: considering performance read is slow, consider using another unix tool : perl

perl -e '
    # $/ end of line of input, special variable
    # read one byte at time
    $/=\1;

    my $outfilename=shift;
    open $outfile,">>",$outfilename or die $!;

    while (<>) {
        # do something on output (for example print ascii number)
        print ord($_),"\n";

        # write to out file
        print $outfile "$_";
    }
' "$FILE" < /dev/ttyO5

Upvotes: 1

Related Questions