Re: Forward LIRC from one machine to another via UDP over the network?
Paul Fox <[email protected]> Sat, 31 May 2025 18:51:00 -0400
| Newsgroups | gmane.comp.hardware.lirc |
|---|---|
| Message-ID | <[email protected]> |
------- =_aaaaaaaaaa0
Content-Type: text/plain; charset="us-ascii"
Content-ID: <181635.1748731860.1-xLQi51zkbdE9bcD+F6QJUYSwOGtdHRLOnKs2IOyhHvI@public.gmane.org>
patrick wrote:
> I cobbled together this command on the RPi, hoping it would send the IR
> signals to the MythTV computer in the same way the HDHR did but it doesn't
> seem to be working. I'm running irw on the 192.168.1.2 computer but it's
> not receiving any signals.
>
> /usr/bin/mode2 -d /dev/lirc0 | irtext2udp | socat -
> udp-datagram:[1]192.168.1.2:5000,broadcast
>
> I'm hoping someone else has done this or has experience with it and could
> offer me some assistance please.
Unless something has changed recently (and I doubt it), irtext2udp
is broken, because it matches the documentation of the UDP protocol, which
is also broken. I submitted patches for these issues in March 2022:
https://sourceforge.net/p/lirc/tickets/370/
I also sent mail to the (this) list about it at the same time -- I'm sure
it's in the archives. So that's probably at least part of your problem.
For various reasons (mostly historical, but also having to do with my
network topology), I don't do lircd processing on the raspberry pi boxes
that are scattered around the house, each with an IR receiver. Instead,
I forward the IR to a central server, where there's an instance of
lircd running for every client. Since UDP can't make it through
my firewall, I send it over tcp, through an ssh tunnel, and convert
back to UDP at the destination.
For all of those reasons, I don't use irtext2udp. I use my own script
(attached), which takes mode2 format and converts it to the UDP
format, and sends it to a tcp port. You'll see that it sends to a port
on "localhost" -- that's because it's actually being forwarded across
an ssh tunnel.
On the receiving end, I have a listener that gets data from the other end
of the ssh tunnel. The meat of it is this line:
socat -u tcp4-listen:88${octet},reuseaddr,fork UDP:localhost:87${destoctet}
The 88xx address is what the ssh server delivers to, and the 87xx
address is the appropriate lircd daemon.
Hope some part of this helps.
paul
=----------------------
paul fox, [email protected] (arlington, ma, where it's 59.2 degrees)
------- =_aaaaaaaaaa0
Content-Type: text/x-shellscript; charset="utf-8"; name="irmode2-to-udp"
Content-Description: irmode2-to-udp
Content-Disposition: attachment; filename="irmode2-to-udp"
Content-Transfer-Encoding: quoted-printable
#!/bin/bash
# Convert pulse/space microsecond tick data in "mode2" format to the
# UDP driver's binary format.
# "mode2" data looks like:
# pulse 3000
# space 1000
# pulse 2995
# space 1001
# ... etc
# Low values (that fit in 15 bits) are combined with the high-bit
# pulse/space flag, and sent as two little-endian bytes. Larger
# values send two bytes of 0 plus the flag, and then 4 bytes of value,
# again in little-endian format.
#
# The UDP packets consist of a number of little endian 16-bit
# integers. The high bit signifies the state of the received signal;
# set indicates a space, clear a mark. The low 15 bits specify how
# long the signal lasted.
# =
# With the default resolution setting (61) the times are measured in
# 1/16384 second intervals. This was used by old hardware using a
# cheap 32kHz clock crystal, when designing new devices a 1MHz 1=C2=B5s
# clock is recommended.
# =
# To allow long times to be transfered a long UDP input format is
# available, this consists of a zero time as specified by the short
# format followed by a four byte little endian time value. This
# should only be needed occasionally for example the time between
# button presses.
set -e
set -o pipefail
oldudp=3D;
while [ "$1" ]
do
case "$1" in
oldudp) oldudp=3Doldudp ;;
esac
shift
done
ir-ctl --receive --mode2 |
while read state ticks
do
: got: .$state. .$ticks.
timeout=3D; pulse=3D;
case $state in
pulse) pulse=3Dtrue ;;
space) pulse=3D; ;;
timeout) timeout=3Dtrue; ;;
"") continue ;;
*) echo "unknown keyword '$state'" >&2; continue;;
esac
# convert the microsecond timings to the 1/16384 second intervals
# used in the "old days".
test "$oldudp" && (( ticks =3D (ticks + 30) / 61 ))
if [ "$timeout" ]
then
printf "%b" "\x00" "\x80"
printf "%b" "\xff" "\xff" "\xff" "\xff"
elif (( ticks < 32768 ))
then
# add the high-bit flag for spaces
test "$pulse" || (( ticks +=3D 32768 ))
# first create two hex format ascii bytes
printf -v hb0 "%x" $(( ticks & 0xff ))
printf -v hb1 "%x" $(( (ticks >> 8) & 0xff ))
# then print those ascii bytes as binary, in l-e format
printf "%b" "\x$hb0" "\x$hb1"
else
# for a "long" response, there's a two-byte little-endian
# header: zero plus the high-bit space flag ...
if [ $pulse ]
then
printf "%b" "\x00" "\x00"
else
printf "%b" "\x00" "\x80"
fi
# ... followed by a little-endian longword.
# first create four bytes, in ascii format
printf -v hb0 "%x" $(( ticks & 0xff ))
printf -v hb1 "%x" $(( (ticks >> 8) & 0xff ))
printf -v hb2 "%x" $(( (ticks >> 16) & 0xff ))
printf -v hb3 "%x" $(( (ticks >> 24) & 0xff ))
# then print those ascii bytes to binary, in l-e format
printf "%b" "\x$hb0" "\x$hb1" "\x$hb2" "\x$hb3"
fi
done | nc localhost 8700 || echo pipe failed >&2
------- =_aaaaaaaaaa0
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
------- =_aaaaaaaaaa0--