12

I am trying to send some hex values to a tty port /dev/ttyS2. When I use echo or printf \x0A it will print an extra \x0D before the \x0A.

i=1 
a=$(printf "\xAA\xEE\x0A\x%02x" $i)
echo -ne   "$a"  > /dev/ttyS2

I get this on the terminal/serial port -- note the extra 0D. How can I remove that?

enter image description here

12

You need to disable newline conversion:

stty -F /dev/ttyS2 -onlcr

or, for strict POSIX stty:

stty -onlcr < /dev/ttyS2
| improve this answer | |
  • a=$(printf "\xB2\x00\x01" $i) echo -ne "$a" > /dev/ttyS2 now the \x00 is not printed using echo – dmSherazi Aug 24 at 11:08
  • 3
    @dmSherazi, bash's printf builtin understands those \xXX sequences and expand them to the corresponding bytes. bash variables cannot contain NUL bytes (zsh is the only shell that can). Here, you'd need a=$(printf '\\xB2\\x00\\x%02x' "$i") and printf %b "$a" > /dev/ttyS2 (or preferably switch to octal if you want to be portable). – Stéphane Chazelas Aug 24 at 11:28
  • stty does not have an option -F, it operates on stdin. – schily Aug 24 at 13:04
  • 1
    @schily, not the POSIX specification of the stty command, but several implementations support -F, including GNU, busybox or ast-open. Added so that the device could be opened in non-blocking mode which shells can't do with redirections. – Stéphane Chazelas Aug 24 at 14:07
  • @StéphaneChazelas The only known constraint where a normal open for a tty blocks is when you try to open the dial in variant of the tty. If you however set the tty modes before the carrier detect line is set active, there is no grant that the tty modes survive that status change. BTW: the stty built into ksh93 does not support -F if you only check versions that have been published by David Korn. – schily Aug 24 at 14:30
13

If you want bytes to be transmitted as-is across a serial connection both ways, you need to tell the system it's not to be used as a terminal device, either by detaching the tty line discipline from it or by issuing:

stty raw -echo < /dev/ttyS2

In your case, it was the onlcr attribute which is enabled by default on tty device that was causing the LF to CRLF conversion on output. You can disable all output processing including ocrnl with stty -opost, but that leaves all the input processing for data transmitted in the other direction.

You're not indicating which shell, echo or printf implementation you're using but note that the -n, -e options are not standard, and the behaviour of printf or echo when an argument contains \x is unspecified.

Several implementations of printf in their format argument expand \xHH to the byte of value 0xHH.

In those

printf "\xAA\xEE\x0A\x%02x" $i

Would expand \xAA to the byte 0xAA and for \x would either expand that to byte 0 or to \x literally or complain that hex digits are missing. So you'd end up with <0xaa><0xee><LF>\x01 in $a for instance.

Some echo implementations do also interpret \xHH sequences (some only when passed a -e option).

Here, if you wanted to be portable, you'd do:

a=$(printf '\\252\\356\\012\\%03o' "$i")
printf "$a" > /dev/ttyS2

Or:

a=$(printf '\\0252\\0356\\0012\\0%03o' "$i")
printf %b "$a" > /dev/ttyS2

(standard printf supports \ooo octal sequences in the format, and a %b format which is meant to emulate the kind of expansions some echo implementations do with or without -e, and where the octal sequences are expressed as \0ooo).

You also want to make sure the first printf doesn't output a NUL byte, as except for zsh, shells cannot store NUL bytes in their variable (don't do a=$(printf '\0 or \x00 or \u0000') for instance).

With zsh:

bytes=(0xaa 0xee 0x0a $i)
set +o multibyte
printf %s ${(#)bytes} > /dev/ttyS2

That data could be stored in a variable with either:

printf -v data %s ${(#)bytes}

or

data=${(#j[])bytes}

But more generally, if you want to manipulate data with arbitrary byte values, you may want to use a proper programming language, even if it's an interpreted one like perl or python.

Another approach would be to use tools like xxd that can convert back and forth between a binary form and a text hex dump.

printf aaee0a%02d "$i" | xxd -p -r > /dev/ttyS1
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.