At least 5 years ago the CF acquired the
When calling this the caller has to provide a string for display on the HDR and also a 4-character version, prefixed by
The HD-Fox T2 has a display comprising 2 pairs of 7-segment displays separated by a double dot display (:). The segments are identified by the 7 least significant bits of a byte as below:
The upper dot of the double dot is the top bit (0x80) of the 2nd segment byte; the lower dot is the top bit of the 4th segment byte.
Presumably a genius instrumented the HD
reveals that each message begins with a byte of value 5 and concludes with a checksum byte equal to the modulo 256 sum of the bytes between. There are 2 further magic bytes after the first, with values 5 and 15; then each of 4 characters is sent as a segment bitmap (which may be 0 for no character) according to the layout shown above.
For the HDR, slightly different formats (eg it can display actual characters, which it does with code value 18) are used between the first and last bytes, but they all fall into this structure:
The HD will also accept strings of less than 4 characters using an appropriate count value; segments are updated from the left without changing the remaining segments.
Based on this, here is a shell script that sends an arbitrary string (subject to the limits of the 7-segment display) to the front panel, using scrolling.
In case anyone wonders what the point is ... First, the shell script saves 3k over the binary even allowing for some extra work for HDR support; second, I have a back burner HD fix-disk project that might benefit.
/sbin/display
binary. This is used in various scripts to display text to display text on the HDR-Fox T2, but has a fall-back interface for HD-Fox T2, as in /bin/tmenu
and /etc/init.d/S89maintenance
:
Code:
...
feedback()
{
[ "$model" = HDR ] && display "$1" || display "\$$2"
}
...
$
, for use on the HD.The HD-Fox T2 has a display comprising 2 pairs of 7-segment displays separated by a double dot display (:). The segments are identified by the 7 least significant bits of a byte as below:
Code:
0x1
0x20 0x2
0x40
0x10 0x4
0x8
Presumably a genius instrumented the HD
humaxtv
binary to identify the strange protocol used on the serial interface /dev/ttyS2
to the Micom front panel device. Doing the same to /sbin/display
, like so
Code:
# strace -x /sbin/display '$abcd' 2>&1 | grep -E '^writ'
write(3, "\x05\x05\x0f\x77\x7c\x39\x5e\x9e", 8) = 8
#
For the HDR, slightly different formats (eg it can display actual characters, which it does with code value 18) are used between the first and last bytes, but they all fall into this structure:
byte | 1 | 2 | 3 | ... | N |
---|---|---|---|---|---|
value | 5 | N-2 | code | ... | checksum |
Based on this, here is a shell script that sends an arbitrary string (subject to the limits of the 7-segment display) to the front panel, using scrolling.
Code:
#!/bin/sh
# args [--loop] [--delay SEC] [--] [STRING...]
# functions
# if sleep only does integers (busybox /bin/sleep)
# would use command builtin, but CF /bin/sh is missing it
if ! sleep 0.1 2>/dev/null; then
# round fractional time to nearest integer
my_sleep() {
sleep "$(printf "%.0f" "$1")"
}
else
my_sleep() {
sleep "$@"
}
fi
usage() { # progname
printf "Usage: $1 [--loop|-l] [--delay|-d SEC] [--] [STRING...]\n"
printf "Display STRING on the HD-Fox T2 front panel, scrolling left once\n"
printf "per SEC (default %s) seconds. If --loop, scroll until cancelled.\n" "$char_delay"
}
# represent a number as a printf octal escape sequence
octal_esc() { # number
printf "\\%#o" "$1"
}
# get the checksum byte to send to the HD Micom
hd_cksum() { # n1 [n2 .. n4]
# include bytes 2 (0x05) and 3 (0x0f) plus the 4 display bytes
printf "%d" $(( (20 + $1 + $2 + $3 + $4) % 256 ))
}
# send segments to Micom front panel serial device, blanking the rest
hd_out() { # ch1 [ch2 .. ch4]
# any trailing null params -> 0
set -- "${1:-0}" "${2:-0}" "${3:-0}" "${4:-0}"
# 3 magic bytes, the 4 display bytes, checksum
>/dev/ttyS2 printf "\x05\x05\x0f%b%b%b%b%b" \
$(octal_esc $1) $(octal_esc $2) $(octal_esc $3) $(octal_esc $4) \
$(octal_esc $(hd_cksum $1 $2 $3 $4))
}
# get the segment byte corresponding to a character as a decimal number
char2ch() { # char
local ch
# provide a few more char mappings than /sbin/display
case $1 in
[Aa]) ch=119 ;;
[Bb]) ch=124 ;;
C) ch=57 ;;
c) ch=88 ;;
[Dd]) ch=94 ;;
[Ee]) ch=121 ;;
[Ff]) ch=113 ;;
[Gg]) ch=61 ;;
H) ch=118 ;;
h) ch=116 ;;
[1I]) ch=6 ;;
i) ch=16 ;;
[Jj]) ch=13 ;;
[Kk]) ch=112 ;;
[Ll]) ch=56 ;;
# hard-to-map chars as 3 horizontal segments
[MWX]) ch=73 ;;
# or centre and bottom for lower case
[mwx]) ch=72;;
[Nn]) ch=84 ;;
[O0]) ch=63 ;;
o) ch=92 ;;
[Pp]) ch=115 ;;
[Qq]) ch=103 ;;
[Rr]) ch=80 ;;
[Ss5]) ch=109 ;;
T) ch=7 ;;
t) ch=120 ;;
[UV]) ch=62 ;;
[uv]) ch=28 ;;
[Yy]) ch=110 ;;
[Zz2]) ch=91 ;;
3) ch=79 ;;
4) ch=102 ;;
6) ch=125 ;;
7) ch=39 ;;
8) ch=127 ;;
9) ch=111 ;;
[_.\;:,]) ch=8 ;;
'|') ch=48 ;;
[{[\(]) ch=35 ;;
[}\)]]) ch=15 ;;
-) ch=64 ;;
=) ch=65 ;;
/) ch=82 ;;
@) ch=95 ;;
'`') ch=96 ;;
[\'\"]) ch=2 ;;
[\]) ch=100 ;;
' ') ch=0 ;;
!) ch=10 ;;
# undefined chars show as top and bottom segments
*) ch=9 ;;
esac
printf "%d" "$ch"
}
valid_secs() { # maybe_secs
# if the entire param matches, return 0; else 1
echo "$1" | sed -rn 's/^[0-9]+(\.[0-9]+)?$//;t;q 1'
}
# defaults
# display speed/s
char_delay=0.5
# only display once
noloop=1
[ HD = "$(cat /etc/model)" ] ||
{ printf "This works on HD-Fox only\n"; usage "${0##*/}"; exit 1; } >&2
# parse args
while [ -n "$1" ]; do
case "$1" in
--loop|-l)
noloop=
shift
;;
--delay|-d)
if valid_secs "$2"; then
char_delay="$2"
shift
else
>&2 printf "\"%s\" is not a valid number of seconds, ignoring.\n" "$2"
fi
shift
;;
-d[0-9]*)
valid_secs "${1#-d}" &&
char_delay="${1#-d}"
shift
;;
--help|-h)
usage "${0##*/}"
exit
;;
--) shift
break
;;
*) break ;;
esac
done
c1=
c2=
c3=
c4=
while true; do
# space between loops
str="$*${noloop:- }"
while [ -n "$str" ]; do
ch="${str}"
str="${ch#?}"
c4="$(char2ch "${ch%"$str"}")"
if [ -n "$c4" ]; then
hd_out "$c1" "$c2" "$c3" "$c4"
c1="$c2"
c2="$c3"
c3="$c4"
c4=
my_sleep "$char_delay"
fi
done
[ -n "$noloop" ] && break
done
while [ -z "$c1" -a -n "$c4" ]; do
c1="$c2"
c2="$c3"
c3="$c4"
c4=
hd_out "$c1" "$c2" "$c3" "$c4"
my_sleep "$char_delay"
done
Last edited: