zsh-users
 help / Atom feed
* Shell io from and to serial device
@ 2019-02-14  0:00 Dominik Vogt
  2019-02-14  0:56 ` Ben Klein
  2019-02-15  1:02 ` Bart Schaefer
  0 siblings, 2 replies; 3+ messages in thread
From: Dominik Vogt @ 2019-02-14  0:00 UTC (permalink / raw)
  To: Zsh Users

Hi Folks,

I'm really stuck with this problem.  We need a fast, and reliable
way to send a string to a serial device and grep for a certain
reply, and failed to make that work with "expect" - because its
documentation is awful.  Anyway, it should be not too difficult to
do with zsh.  The task is:

  1. configure serial line, e.g. with

    $ stty -F /dev/ttyUSB0 speed 115200 cs8 -cstopb -parenb -echo

  2. Send some string to the serial line

    $ echo foo > /dev/ttyUSB0

  3. Grep for a certain reply with configurable, sub second timeout.

    $ ??????

  4. In case of a timeout, all input from the serial line is stored
     in a file or shell variable.

There should be no noticeable delay if the expected reply shows
up immediately.

Something like this should do it:

-- snip --
#!/usr/bin/zsh

set -u
set -C

SEND="$1"
EXPECT="$2"
TIMEOUT="$3"
DEV="$4"
LOGFILE="$5"
shift 5

trap "exit 1" TERM

# serial setup
stty -F "$DEV" speed 115200 cs8 -cstopb -parenb -echo > /dev/null
# watchdog process
{ sleep "$TIMEOUT"; echo "timeout" 1>&2; kill 0 2> /dev/null; } &
# child sends string with delay
{ sleep 0.01; echo "$SEND" > "$DEV" } &
rm -f "$LOGFILE"
# parent waits for reply
tee "$LOGFILE" < "$DEV" |
while read LINE; do
	if { cat <<EOF
$LINE
EOF
} | grep -q "$EXPECT"
	then
		trap : TERM
		kill 0 2> /dev/null
		exit 0
	fi
done
exit 1
-- snip --

But this looks really complicated and the "sleep 0.01" is
annoying.  There must be an easier way.

Also, I'm not convinced that "tee" won't buffer serial input and
cause a timeout, although on the test machine it doesn't.

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Shell io from and to serial device
  2019-02-14  0:00 Shell io from and to serial device Dominik Vogt
@ 2019-02-14  0:56 ` Ben Klein
  2019-02-15  1:02 ` Bart Schaefer
  1 sibling, 0 replies; 3+ messages in thread
From: Ben Klein @ 2019-02-14  0:56 UTC (permalink / raw)
  To: dominik.vogt, Zsh Users

[-- Attachment #1: Type: text/plain, Size: 2579 bytes --]

I don't know if you have this available, but `timeout` is a common utility
program: https://manpages.ubuntu.com/manpages/cosmic/en/man1/timeout.1.html
(It's
GNU)

So you could start the whole grep pipeline with that command in a new
shell, or if you wanted you could do a callback to a parent ZSH process
like the zsh-async does with SIGWINCH, catch that and kill a job. (You
could enable job control then kill %0 or similar when you get the
interrupting signal back.)

On Wed, Feb 13, 2019 at 7:01 PM Dominik Vogt <dominik.vogt@gmx.de> wrote:

> Hi Folks,
>
> I'm really stuck with this problem.  We need a fast, and reliable
> way to send a string to a serial device and grep for a certain
> reply, and failed to make that work with "expect" - because its
> documentation is awful.  Anyway, it should be not too difficult to
> do with zsh.  The task is:
>
>   1. configure serial line, e.g. with
>
>     $ stty -F /dev/ttyUSB0 speed 115200 cs8 -cstopb -parenb -echo
>
>   2. Send some string to the serial line
>
>     $ echo foo > /dev/ttyUSB0
>
>   3. Grep for a certain reply with configurable, sub second timeout.
>
>     $ ??????
>
>   4. In case of a timeout, all input from the serial line is stored
>      in a file or shell variable.
>
> There should be no noticeable delay if the expected reply shows
> up immediately.
>
> Something like this should do it:
>
> -- snip --
> #!/usr/bin/zsh
>
> set -u
> set -C
>
> SEND="$1"
> EXPECT="$2"
> TIMEOUT="$3"
> DEV="$4"
> LOGFILE="$5"
> shift 5
>
> trap "exit 1" TERM
>
> # serial setup
> stty -F "$DEV" speed 115200 cs8 -cstopb -parenb -echo > /dev/null
> # watchdog process
> { sleep "$TIMEOUT"; echo "timeout" 1>&2; kill 0 2> /dev/null; } &
> # child sends string with delay
> { sleep 0.01; echo "$SEND" > "$DEV" } &
> rm -f "$LOGFILE"
> # parent waits for reply
> tee "$LOGFILE" < "$DEV" |
> while read LINE; do
>         if { cat <<EOF
> $LINE
> EOF
> } | grep -q "$EXPECT"
>         then
>                 trap : TERM
>                 kill 0 2> /dev/null
>                 exit 0
>         fi
> done
> exit 1
> -- snip --
>
> But this looks really complicated and the "sleep 0.01" is
> annoying.  There must be an easier way.
>
> Also, I'm not convinced that "tee" won't buffer serial input and
> cause a timeout, although on the test machine it doesn't.
>
> Ciao
>
> Dominik ^_^  ^_^
>
> --
>
> Dominik Vogt
>
-- 
*\Ben Klein*
Founder and Owner of Robosane, robobenklein@robosane.net
You can find me elsewhere online as 'robobenklein'.
If you need to contact me securely, I am also reachable via GPG, or on
Keybase.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Shell io from and to serial device
  2019-02-14  0:00 Shell io from and to serial device Dominik Vogt
  2019-02-14  0:56 ` Ben Klein
@ 2019-02-15  1:02 ` Bart Schaefer
  1 sibling, 0 replies; 3+ messages in thread
From: Bart Schaefer @ 2019-02-15  1:02 UTC (permalink / raw)
  To: dominik.vogt, Zsh Users

On Wed, Feb 13, 2019 at 4:01 PM Dominik Vogt <dominik.vogt@gmx.de> wrote:
>
>   1. configure serial line, e.g. with
>
>     $ stty -F /dev/ttyUSB0 speed 115200 cs8 -cstopb -parenb -echo
>
>   2. Send some string to the serial line
>
>     $ echo foo > /dev/ttyUSB0

You might get better results using "printf" rather than "echo",
depending on how precise you need to be about what is sent to the
device (where newlines appear, etc.).

>   3. Grep for a certain reply with configurable, sub second timeout.

I think what you want to do here is use "read -E" combined with
"zselect -t" (assuming you have a recent zsh where zselect accepts
hundredths of a second timeouts).

I have a bit of trouble following your example script (what the heck
is that "cat <<EOF" doing in there?), and you haven't said anything
about the "protocol" used on the serial device (is every write by
either side supposed to end with a newline, for example?) so it's hard
to be specific, but something like:

trap "kill 0 2>/dev/null" EXIT
stty -F "$DEV" speed 115200 cs8 -cstopb -parenb -echo > /dev/null
{ zselect -t 1 -w 1 && printf "%s\n" "$SEND" > "$DEV" } &
# $TIMEOUT has to be adjusted to be 100ths before doing this;
# adjusted $TIMEOUT better be > 1 or this will always fail
coproc { zselect -t $TIMEOUT -r 0 || kill 0 2>/dev/null }
# This assumes the "other end" always sends full lines
while read -E LINE >> "$LOGFILE"; do
  print -r -- "$LINE"
done | grep --max-lines=1 --quiet "$EXPECT"
# If not exiting here, "print -p $?" to end the coproc
exit $?

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, back to index

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-14  0:00 Shell io from and to serial device Dominik Vogt
2019-02-14  0:56 ` Ben Klein
2019-02-15  1:02 ` Bart Schaefer

zsh-users

Archives are clonable: git clone --mirror http://inbox.vuxu.org/zsh-users

Newsgroup available over NNTP:
	nntp://inbox.vuxu.org/vuxu.archive.zsh.users


AGPL code for this site: git clone https://public-inbox.org/ public-inbox