IR remote receiver for Linux - Page 1
Forum section: electronics / general

author: RoGeorge
author_rank: Super Contributor
timestamp: December 29, 2022, 06:08:13 pm
content: I'm looking for a Linux infrared receiver that can learn the codes from a domestic remote control, and use the IR remote's buttons to control a Linux media player. I was expecting this would be a standard and trivial setup, but apparently it is not.Search engines return the first 1-2 pages full with LIRC (Linux Infrared Remote Control). That used to work some years ago, then part of LIRC was integrated in the Linux kernel, though with less functionality than the original, and now LIRC doesn't work any longer with the current Ubuntu 22.04 LTS. I've found a workaround by installing the much older LIRC from Ubuntu 16.04 (from about 5-10 years ago) but that doesn't create configuration files.Meanwhile some players dropped the LIRC support expecting any IR control to be done through other Linux mechanisms.I need a DIY IR receiver. Already haveTSOP1738IR receiver IC, and CH340 or FT232R serial to USB bridges. Also have ATmega8 or Arduino UNO/nano/DUE to connect the TSOP1738 to the desktop's USB. I don't have any madia center installed, all I need is play/pause and volume for casual media players.This is the second afternoon trying to get IR receiver functionality and nothing works when it comes to install LIRC. Maybe LIRC is a thing of the past but I'm in a bubble search that only shows LIRC based solutions.Anybody knows a tested and working setup for an easy to set IR receiver, please?LATER EDIT:==========Solved (almost) by using a version of LIRC from many years ago, v0.9.0, like this:https://www.eevblog.com/forum/networking/ir-remote-receiver-for-linux/msg4612618/#msg4612618More setting for executing shell commands from an IR remote (with LIRC and irexec), and other settings to control the 'mpv' player with the help of 'socat':https://www.eevblog.com/forum/networking/ir-remote-receiver-for-linux/msg4615912/#msg4615912Even more settings and reconfigure the irexec service to control the last active player through MPRIShttps://www.eevblog.com/forum/networking/ir-remote-receiver-for-linux/msg4624810/#msg4624810

author: Twoflower
author_rank: Frequent Contributor
timestamp: December 29, 2022, 06:33:36 pm
content: That's a painful topic you're facing. Had painful time of learning there (and probably it is till not perfect). Some things I don't understand 100% and I still see an error message that a file is not found, but it works for me. Eventually you can use that stuff as starting-point. The things I did to get it up and running on an RasPi is:Enable the gpio-ir overlay (not sure how this will be done for UEFI boot procedures), and don't load the lirc-rpi overlay:Code:dtoverlay=gpio-ir,gpio_pin=23,rc-map-name=apple_remoteThe string apple_remote can freely chosen filename and the number is the IO-Pin I used (not all can be used!). After reboot this provides a new device under /dev/input/event0 (eventually the number might be different in your system). You can try cat /dev/input/event0 to see if the remote is recognized already.In /etc/rc_keymaps/ you create a file with the name you used above. There are many pre-defined keymaps you can try as well (here for the simplistic white Apple remote):Code:# table apple_remote, type: NEC0x87eec30b KEY_UP0x87eec30d KEY_DOWN0x87eec308 KEY_LEFT0x87eec307 KEY_RIGHT0x87eec304 KEY_ENTER0x87eec302 KEY_ESCNow the file needs to be announced in the /etc/rc_maps.cfg by adding that at the end of the file:Code:* * apple_remoteThis should already create the keystrokes mentioned in the /etc/rc_keymaps/* file.(Probably you'll find that somewhere in the web with some ranting in a blog with some additional information)

author: Nominal Animal
author_rank: Super Contributor
timestamp: December 29, 2022, 10:27:35 pm
content: Quote from: RoGeorge on December 29, 2022, 06:08:13 pmSerial to USB bridges? Oh noooooooo....If you had used a microcontroller with native USB, you could have done everything within the microcontroller, and simply send the events as HID keypresses (multimedia keys). The result is an USB IR receiver that works in all OSes without any drivers, because it is an USB HID keyboard device.Personally, I would have used a Teensy LC because I have one, they're cheap (difficult to obtain right now due to chipageddon, though), and because Teensyduino includes theIRremote library(but see Ken Shirriff's latest version atgithub:/Arduino-IRremote/Arduino-IRremote).I'd first use the Receive example on the Teensyduino page to map out all the remotes I want to use and the codes they send.Then, I'd write the couple of dozen lines needed to implement aTeensy USB HID Keyboardto emit the multimedia keypresses (KEY_MEDIA_PLAY, KEY_MEDIA_PAUSE, KEY_MEDIA_STOP, KEY_MEDIA_VOLUME_INC, KEY_MEDIA_VOLUME_DEC, etc.).You do not actually need a Teensy one for this, of course.You can buy one of the ATmega32u4 based Arduino clones (Pro Micro clones, look for Pro Micro silkscreened on the board) off eBay from European sellers for under 15€ shipped. I've used the ones with USB Micro B connector, and they work just fine; they're clones off the SparkFun Pro Micro or Arduino Pro Micro ATmega32u4 board.They use the Arduino Leonardo bootloader, so within the Arduino environment, you treat them as Arduino Leonardos. For the pinout, but use the Arduino Pro Micro pinout. In Arduino, make sure you have both the Keyboard and IRremote libraries installed, and the same code shown at the Teensy pages above should work.(In theory, it should be possible to use an ATtiny85 DigiSpark clone for this, but I haven't actually tried this myself. These bit-bang the USB connection (low-speed USB HID), calibrating the internal clock to 16.5 MHz. The latest versions of the IRremote and DigiSpark cores do have an interrupt conflict as well, so it definitely isn't as straightforward. This is why I recommend using an Arduino-programmable MCU with hardware USB support instead.)

author: RoGeorge
author_rank: Super Contributor
timestamp: December 30, 2022, 12:45:29 pm
content: Made some progress with LIRC, got a FTDI based receiver working, but with the ancient version of LIRC v0.9.0 from ~6 years ago (LIRC from the Ubuntu 16.04 Xenial repositories, but installed in current Ubuntu 22.04 Jammy). It was tedious, and still don't know how to add a random remote.FTDIFT232R, which is a USB to serial converter, can be used to receive IR with the help of an IR demodulator likeTSOP1738. The FTDI chips are using a special ftdi USB driver. That allows FTDI chips to work with interrupts if needed, they have some parallel bits, too, apart from the standard RS232 signals, they can bitbang with timing and on any pin (this last mode I suppose is used by LIRC), etc.I am using one, and the Out pin from TSOP is connected to the RxD pin of the FTDI (default in LIRC, the pin can be wired on other FTDI pins, too, then configured in LIRC accordingly). Something like this:Schematic fromhttps://www.huitsing.nl/irftdi/There is another hardware dongle with theTSOP Outpin wired to the RxD of an RS232 COM port (port with 16550 UART chip, not USB COM). That is whyCH340G(USB to TTL serial) might not work.The Arduino based are implementing a small GIRS (General InfraRed Server) which can only work with very few remotes, and GIRS is yet another layer, and apart from lirc it will require some firmware to compile/maintain over years.About 10 years ago, some guy Igor wrote a bitbang USB1.1 firmware for AVR chips, like ATmega or even ATtiny. That firmware allows 2 casual GPIO pins of the MCU to become D+ and D- data lines for USB. Many projects used Igor's AVRUSB to connect a casual AVR chip to a PC through USB and control MCU GPIO from PC, log MCU ADC data, etc. It was a total surprise back than, first time when an MCU was able to connect to USB without FTDI or alike USB to TTL bridges. I think this is the current page, and a link with some demo projs:https://www.obdev.at/products/vusb/index.htmlhttps://www.obdev.at/products/vusb/projects.htmlBased on this AVRUSB firmware there is also an IR receiver suported by LIRC (Igor's plug USB LIRC). Again, yet another FW to take care in time.I would prefer LIRC because many media players like Rhythmbox, VLC, etc. have LIRC support.Also happens to have an unused FT232RL and aTFM(S)1380, which are now wired together and could close Rhythmbox from some leftover IR remote from a former Leadtek WinFast FM+TVtuner.There are many config settings to match:- proper driver (here ftdi)- proper lircd (daemon config)- proper IR remote model config- proper LIRC plugins config (specific to each media player that supports LIRC)- proper scripts for each IR remote's button and each media player- proper scripts for other normal application (not media players, LIRC can send events to X, sned keystrokes, emulate mouse move, etc. huge pile of features and config details)Now that the hardware+drivers+configs are known as working, next would be to try to redo the LIRC setup using the current LIRC from the Ubuntu 20.04 Jammy repositories, then to write down simple steps and commands to get LIRC working in Ubuntu with a FTDI receiver.

author: Nominal Animal
author_rank: Super Contributor
timestamp: December 30, 2022, 11:16:39 pm
content: Quote from: RoGeorge on December 30, 2022, 12:45:29 pmAll GUI players I've tested support multimedia keys out of the box. It is because the Logitech et. al keyboards with such physical keys are quite common.(Although, volume up and down is actually wired to the global volume control, not to the application volume.)If this is a non-GUI installation, you do need a helper daemon to switch between applications, for example by switching between TTYs (with each appliance running on their own TTY, possibly on raw framebuffer/DRI). If you use X, you can always use a keyboard mapping in X to eg. change applications (specific remote buttons switching to a specific application).I really do not see why you're so invested in LIRC, when the HID approach is so much more common and actively used.

author: RoGeorge
author_rank: Super Contributor
timestamp: December 31, 2022, 07:52:43 am
content: For why LIRC, at this point the sunk-cost fallacy alone would be a strong enough reason.The goal is to have dedicated physical buttons for volume and play/pause when playing music, movies or YouTube.- Has to work on a Kubuntu desktop (with KDE Plasma)- Has to work headless, without pointing or clicking a GUI, and without having to bring the player into focus- Has to be an IR remote, a keyboard with media buttons is too big to carry in a nearby seat (for example when soldering)- Has to be maintenance free on long term, that's why I'm avoiding brewing my own software- No buying, already have all the parts (USB IR receiver with FT232R and TSOP1738, plenty of IR remotes left from long gone appliances)Could install something else other than LIRC, just that when searching for alternatives couldn't find any.The pitch from the LIRC devs is this:QuoteSource:https://www.lirc.org/html/configuration-guide.html

author: Nominal Animal
author_rank: Super Contributor
timestamp: December 31, 2022, 10:18:10 am
content: Quote from: RoGeorge on December 31, 2022, 07:52:43 amOk, sure. I'm just telling you that that approach has waned to basically nothing, because the Linux input subsystem provides the same functionality in an easier to manage form, and is always built-in in Linux.The userspace API is describedhere, although the binary interface is much stabler than the linked-to library there. It is a trivial interface to use from C,ifyou need more precise control than using multimedia keys on an attached keyboard would be.To repeat, the small USB microcontroller would receive the IR codes from the remote, and map them to USB HID multimedia keys or longer macros. These are provided to the currently active terminal (typically X) just like normally attached keyboard keypresses are.If you need additional control, for example map the keypresses to specific events to specific applications running under X, you can use a simple X application that grabs that particular input event device, consumes the events (so they're no longer forwarded to X), and sends the X events to the target applications as needed. You can write this in C, C++, or even Python. The only "trick" is to add an udev rule to allow the user this application is run as full access to the input event device, and create a symlink so that it does not need to look the event device name up.Quote from: RoGeorge on December 31, 2022, 07:52:43 amYou do realize that web page was last modified on 2017-06-09?I am basically saying that LIRC is rarely used anymore, because everyone just uses the Linux Input Subsystem instead. Even when one needs to translate the keypresses to X events and direct them to specific applications, the code is easier than dealing with LIRC, and utterly stable: your only dependency in C is the X11 library (libX11).If you want, I can write you a simple C program that maps serial port inputs into Linux input events, using theuinputdevice. (Linux allows one to programmatically create USB HID devices that behave exactly like the physical device would.) I'm just saying that with a MCU with a native USB interface, like on ATmega32u4, you don't need such daemons or drivers at all, just program it to support whatever IR remotes you like, and off you go.Also, once you go this route, and find out howeasyit is to make all sorts of USB-connected widgets using MCUs with native USB support, you'll never go back to USB-serial bridges and the like. That's what happened to me, you see.A local store does have TSOP1738 in stock (for under 2€ apiece), but I do not currently have any IR remotes at all. Otherwise, I could have posted an actual example of how to do this.Would it help if I create an uinput example program? For example, one that reads single-character "commands" from a serial port, and injects them into the Linux input subsystem just like a hardware USB HID device would? This would allow you to use your current hardware without buying anything, but leverage the input subsystem instead of relying on LIRC.Note that both the serial and Linux input subsystems are part of the stable linux ABI: such C code written today will run in the future, because this part has not changed in well over a decade at all, and is something Torvalds et. al. insists should not be broken unless absolutely necessary. (There are some silly people, including a couple of kernel devs, who do push libevdev, which I recommend one doesnotuse. The same ones pushed the interface from read()/write() to ioctl()s, and really, the changes should be reverted...)You don't even need to use any external libraries, and can compile the binary statically, if you want.Even though this is "homebrew" code, it is stabler and much easier to maintain than anything you'll use that uses libraries or services, because it only interfaces to stable kernel interfaces.

author: Karel
author_rank: Super Contributor
timestamp: December 31, 2022, 12:34:32 pm
content: I'm using a TSOP38238 connected to a gpio pin of an RPI3b with Libreelec (Kodi) and it's working fine for years.

author: RoGeorge
author_rank: Super Contributor
timestamp: January 01, 2023, 11:37:35 am
content: I've tried one more day to configure the current LIRC v0.10.1 (the one from the Ubuntu 22.04/Jammy repositories) and couldn't make it run, so I've purged it all then installed/configured again the old LIRC v0.9.0 (from Ubuntu 16.04/Xenial).Meanwhile managed to add a new/unknown IR remote (in LIRC v0.9.0), then made the general volume to respond to this:That's a strange IR remote apparently never seen beforehttps://www.eevblog.com/forum/repair/what-is-this-remote-for-(ir-big-round-blue-with-4-big-buttons)/msg4603183/#msg4603183Not only the shape is unusual at that remote, its IR pulses looks different than those from other IR remotes. The IC near it is only a banana for scale.That's how I've installed and configured LIRC v0.9.0 tin Kubuntu 22.04/Jammy to work with a FTDI IR receiver like the one from the schematic posted a couple of messages above:Code:# add xenial repo to the sources.list (temporary, will delete it after install)echo 'deb [trusted=yes] http://ca.archive.ubuntu.com/ubuntu/ xenial universe' | sudo tee -a /etc/apt/sources.list > /dev/nullsudo apt update# install good old LIRC and lock it against further upgradessudo apt install lirc/xenialsudo apt-mark hold lirc# at install time, a configure text wizard should appear, if that didn't happen dosudo dpkg-reconfigure lirc# choose the FTDI driver, that will create proper config files in /etc/lirc/# remove the temporary added xenial repo from /etc/apt/sources.listsudo truncate -s -"$(tail -n1 /etc/apt/sources.list | wc -c)" /etc/apt/sources.listsudo apt update# to configure lirc# download a config file for your IR remote (mine is Leadtek from a former WinFast tuner)# download the remote from https://sourceforge.net/p/lirc-remotes/code/ci/master/tree/remotes/leadtek/Y04G0033.lircd.confwget https://sourceforge.net/p/lirc-remotes/code/ci/master/tree/remotes/leadtek/Y04G0033.lircd.conf?format=raw# add the downloaded remote as remote(s) config filesudo mv /etc/lirc/lircd.conf /etc/lirc/lircd.conf.originalsudo cp ./Y04G0033.lircd.conf /etc/lirc/lircd.conf# restart the lirc service (or reboot the PC) for changes to take effectsudo /etc/init.d/lirc restart# if all OK, irw should tell the received button pressed in the IR remoteirw00000000c03f30cf 00 KEY_UP Leadtek_Cool_Command_Y04G003300000000c03f08f7 00 KEY_DOWN Leadtek_Cool_Command_Y04G003300000000c03f08f7 01 KEY_DOWN Leadtek_Cool_Command_Y04G003300000000c03fc837 00 KEY_ENTER Leadtek_Cool_Command_Y04G003300000000c03f6a95 00 KEY_TV Leadtek_Cool_Command_Y04G003300000000c03fea15 00 KEY_RADIO Leadtek_Cool_Command_Y04G003300000000c03fea15 01 KEY_RADIO Leadtek_Cool_Command_Y04G003300000000c03f1ae5 00 KEY_DVD Leadtek_Cool_Command_Y04G003300000000c03f1ae5 01 KEY_DVD Leadtek_Cool_Command_Y04G0033To make the Pulse Audio general volume to respond to the IR remote buttons- create ~/.lircrc text file to map remote buttons to programs- install the Pulse Audio LIRC plugin- add a line in the Pulse Audio config so the plugin will start each time- restartContent of '~/.lircrc' fileCode:# note KEY_LEFT denotes a button from the IR remote, not the arrow key button from the PC keyboardbeginremote = Leadtek_Cool_Command_Y04G0033prog = pulseaudioconfig = volume-downbutton = KEY_LEFTrepeat = 0endbeginremote = Leadtek_Cool_Command_Y04G0033prog = pulseaudioconfig = volume-upbutton = KEY_RIGHTrepeat = 0endbeginremote = Leadtek_Cool_Command_Y04G0033prog = pulseaudioconfig = mute-togglebutton = KEY_DOWNend# this last one is to toggle pause/play in Rhythmbox# (you must also go to settings in the Rhythmbox GUI and enable its LIRC plugin)beginprog = Rhythmboxbutton = KEY_ENTERconfig = playpauseendThe line to add in PulseAudio config file '/etc/pulse/default.pa'Code:load-module module-lirc# if you have multiple PulseAudio sinks, to specify which one will listen to IR buttons# load-module module-lirc sink=[your sink name]Now reboot the computer to make sure all the changes will take effect.If all went OK and I didn't forget to write down any step, after reboot the general volume should respond to the IR remote buttons. Open Rhythmbox and play some music. Music should pause/play from the IR remote button.To make LIRC "learn" a new/unknown IR remote, use 'irrecord'Code:irrecord -Hftdi some_new_remote# then follow the text wizard# and at the end irrecord will produce a text file 'some_new_remote' in the local directory# open file 'some_new_remote' in a text editor and copy/add its content inside the file /etc/lirc/lircd.conf# save edited /etc/lirc/lircd.conf (you'll need admin rights)## open ~/.lircrc file and add inside new buttons from the new remote## then restart the lirc daemon or reboot the PCIn case anything goes wrong, read the the manual. This is the architecture, then the signal path. Might help when debugging:---------- --------------- ----------| | | Linux input | | || |---->----| layer |---------->----------| Appli- || | | | /dev/input/eventX | cation || | --------------- | |--->---| | | ----------remote | kernel | devinput v| | || | | ----------| | --------------- | Appli- || |---->----| lirc |---------->----------| cation |--| | | | /var/run/lirc/lircd | | |---------- --------------- ---------- |--| | |---------- || |---------------------------------------------------------------------------------------------------| remote |------------(air gap)------------! capture !! device !------------|v|------------! kernel ! Sometimes needs! driver ! modprobe(1) configuration.------------|v IR pulse data Device like /dev/lirc0, /dev/ttyACM0.| or /dev/ttyS0.------------| lirc | Configure lirc_options.conf| driver | with driver and usually also device.------------|v IR pulse data Use mode2(1) to debug|----------------| lirc pass 1 | lircd.conf config file.----------------|v Key symbols Output socket e. g.,| /var/run/lirc/lircd. Use irw(1) to debug.|----------------| lirc pass 2 | lircrc config file.----------------|v Application strings Use ircat(1) to debug.|ApplicationsThe above text diagrams and more info fromhttps://www.lirc.org/html/configuration-guide.htmlReferences: Make LIRC work in Ubuntu 18.04, 20.04, or 22.04https://twosortoftechguys.wordpress.com/2018/07/24/make-lirc-work-in-ubuntu-18-04/ PulseAudio and lirc https://possiblelossofprecision.net/?p=791 Rhythmbox: LIRC plugin does not work pluginhttps://ubuntuforums.org/showthread.php?t=1066766&p=6728540#post6728540 LIRC Manualhttps://www.lirc.org/html/index.html

author: RoGeorge
author_rank: Super Contributor
timestamp: January 01, 2023, 12:29:16 pm
content: Quote from: Nominal Animal on December 31, 2022, 10:18:10 amBut how?!?I have 17 of them if I include the blue round one and a DIY one for Nikon, placed inside a lighter:Picture from projhttps://hackaday.io/project/1293-turn-a-cigarette-lighter-into-an-ir-nikon-remoteQuote from: Nominal Animal on December 31, 2022, 10:18:10 amAn example would help a lot as a generic way to interface MCUs with a PC.If that's not too much to ask, yes, thank you, an example would be great!Maybe reading bytes from a serial port would not be applicable to receiving IR signals from my current hardware. Saying this because I suspect the FT232R USB to serial chip (in LIRC) is in fact used as a 1 bit GPIO, and not as a serial port. If a 'cat /dev/ttyUSB0' is issued then start pressing remote buttons, nothing is displayed. I guess a normal COM will give a timing error, because the protocol of an IR remote is different from an RS232 serial. Another MCU could translate the IR protocol, but that would mean to write MCU code and reflash the firmware in order to add a new remote.Another way would be to poll the signaling pins of a COM port instead of Rx/Tx data pins. That's how LIRC is reading a TSOP sensor attached to the RTS pin of a COM port, i.e.https://www.lirc.org/receivers.htmlI'm not sure if casual USB to TTL serial adapters (non FTDI, like the ones based on CH340) have the RTS pin and can be polled with a precise enough timing to make sense of the IR signals.

author: RoGeorge
author_rank: Super Contributor
timestamp: January 03, 2023, 06:49:34 am
content: Quick note (more settings, specific for LIRC v0.9.0 for Ubuntu16.04/Xenial when installed into current Ubuntu 20.04/Jammy):Settings needed to execute a shell command at the press of an IR remote button(with an example of how to control a program that is not aware of LIRC, here the 'mpv' player)'irexec' will listen to LIRC for pressed IR buttons, and will lookup inside '~./lircrc' file for IR buttons to shell command associations. 'irexec' can be started as a command from a terminal, as a daemon (irexec -d) or as a service with systemd. This last method is preferred, and can be set to start at each boot.Code:- to send shell commands from the IR remote, start irexechttps://linuxaudiofoundation.org/category/irexec/to start irexec automatically at each bootcreate a unit file for systemd, '/lib/systemd/system/irexec.service',so systemd will start irexec at boot, as a service# sudo nano /lib/systemd/system/irexec.serviceDocumentation=man:irexec(1)Documentation=http://lirc.org/html/configure.htmlDocumentation=http://lirc.org/html/configure.html#lircrc_formatDescription=Handle events from IR remotes decoded by lircd(8)After=network.target# note the 'Wants=' for lirc 0.9.0 is called 'lirc', while in 0.10.1 'lircd'Wants=lirc.serviceType=simple# when not specified, the default lircrc is expected to be in /home/<your_username>/.lircrc# use hardcoded path to avoid variable substitutions and shell expansion uncertainty# ExecStart=/usr/bin/irexec /etc/lirc/irexec.lircrcExecStart=/usr/bin/irexec /home/<your_username>/.lircrcExecStart=/usr/bin/irexecRestart=on-failureSuccessExitStatus=3 4RestartForceExitStatus=3 4WantedBy=multi-user.target- to enable loading irexec at bootsudo systemctl daemon-reloadsudo systemctl enable irexecrebootThe mapping of IR buttons to shell commands to be executed is specified inside the '/home/<your_username>/.lircrc' file, i.e.Code:- when 'irexec' is running (either from a terminal, as a daemon or as a service)'irexec' will listen to LIRC and will emitthe commands specified inside the LIRC button mapings file, '~/.lircrc', e.g.beginremote = EBODA_DVD_blackprog = irexecbutton = KEY_PAUSE# use hardcoded path, system variables mught not work# config = echo cycle pause | socat - "$HOME/.config/mpv/socket"config = echo cycle pause | socat - "/home/<your_username>/.config/mpv/socket"endFor this to work, the mpv player needs to be instructed to create that socket and listen to it (by adding the following inside file '~/.config/mpv/mpv.conf' then restart mpv)Code:# add the following line(s) inside file ~/.config/mpv/mpv.conf (create the file if it's missing)# for mpv to receive inputs from a command-line (while mpv is running)# (LIRC irexec daemon will use this socket to control mpv from an IR remote)input-ipc-server=/home/<your_username>/.config/mpv/socketAny changes in the '.lircrc' file will only take effect after lirc and irexec services are restarted. Any consumers of the events has to be restarted, too, for example the running player(s), pulseaudio, lircd, etc. Something like this:Code:sudo systemctl restart lirc && sudo systemctl restart irexec && pulseaudio -kA reboot might be easier, to be sure no components to be restarted were forgotten.To preserve the LIRC settings:Code:- customised files to backup for lirc v0.9.0/etc/lirc/hardware.conf/etc/lirc/lircd.conf/home/<your_username>/.lircrc/lib/systemd/system/irexec.service/home/<your_username>/.config/mpv/mpv.confany other files you created with irrecord for unknown IR remotes

author: DiTBho
author_rank: Super Contributor
timestamp: January 03, 2023, 03:34:42 pm
content: RoGeorge, why do you want to over-complicate simple stuff?

author: DiTBho
author_rank: Super Contributor
timestamp: January 03, 2023, 04:09:12 pm
content: Quote from: Nominal Animal on December 31, 2022, 10:18:10 amYes, please.I have to add some IR remote capabilities to my training setup.Nothing special, just using a small a Creative HiFi stick for two things1: controlling VLC { volume up, down, play, pause, stop, next song/video, ...)2: controlling the street load { more sports warm-up before performance, increase, decrease }Your example will cover 2, but also 1it's a kind of training machine, a computer-controlled mechanism attached to the rear wheel of a bicycle frame to simulate a real road load. The IR stick is attached to the bicycle handlebar, the remote computer is 5 meters in front of the frame, so it's somehow like pointing a TV screen from the sofa.The weather condition is usually too bad for training outdoors, so… let's train indoors

author: RoGeorge
author_rank: Super Contributor
timestamp: January 03, 2023, 04:10:42 pm
content: Quote from: DiTBho on January 03, 2023, 03:34:42 pmWhat else to use then?LIRC is working now, only laying down the settings. For example, fiddled today with the controls for the mpv player. MPV doesn't have a LIRC plugin, yet mpv knows to open a socket and listen to text commands from that socket.LIRC has a tool 'irexec' that can run bash commands. Thus, with the help of 'socat' it is possible to echo commands to the mpv player while mpv is running. To map buttons from the IR remote to various actions in mpv player, all LIRC needs is to insert the following into the '`/.lircrc' file:IR remotes buttons mapping to MPVCode:### mpv IR keys binding (mpv has no LIRC plugin)## https://stackoverflow.com/questions/19536799/lirc-how-to-use-as-keyboard-command# https://alexherbo2.github.io/config/mpv/control-mpv-from-the-command-line/# echo cycle pause | socat - "$XDG_CONFIG_HOME/mpv/socket"# $XDG_CONFIG_HOME might not be defined, use "$HOME/.config" instead## # better use a hardcoded already expanded path# echo cycle pause | socat - "/home/aaa/.config/mpv/socket"# echo playlist-next | socat - "$XDG_CONFIG_HOME/mpv/socket"# echo playlist-prev | socat - "$XDG_CONFIG_HOME/mpv/socket"## !!! DO NOT USE SYSTEM VARIABLES or ~, use hardcoded paths instead !!!## mpv commands format# echo '{ "command": ["set_property", "pause", true] }' | socat - /tmp/mpvsocket# for example# {"command": ["cycle", "pause"]}## see also e.g. 'mpv --list-properties | grep fullscreen'# mpv --list-options | less# # note this will stop the currently running mpv to respond to MPC (socat) commands, restart the mpv to recover### mpv cycle pause KEY_PAUSEbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_PAUSEconfig = echo cycle pause | socat - "home/aaa/.config/mpv/socket"end# mpv cycle pause KEY_PLAYbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_PLAYconfig = echo cycle pause | socat - "home/aaa/.config/mpv/socket"end# mpv playlist-next KEY_RIGHTbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_RIGHTconfig = echo playlist-next | socat - "home/aaa/.config/mpv/socket"end# mpv playlist-prev KEY_LEFTbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_LEFTconfig = echo playlist-prev | socat - "home/aaa/.config/mpv/socket"end# mpv cycle fullscreen KEY_ENTERbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_ENTERconfig = echo cycle fullscreen | socat - "/home/aaa/.config/mpv/socket"end# mpv cycle fullscreen KEY_ZOOMbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_ZOOMconfig = echo cycle fullscreen | socat - "/home/aaa/.config/mpv/socket"end# mpv show subtitles KEY_SUBTITLEbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_SUBTITLEconfig = echo cycle sub-visibility | socat - "/home/aaa/.config/mpv/socket"end# mpv cycle subtitles KEY_OPEN_CLOSEbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_OPEN_CLOSEconfig = echo cycle sid | socat - "/home/aaa/.config/mpv/socket"end# mpv cycle audio KEY_LANGUAGEbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_LANGUAGEconfig = echo cycle aid | socat - "/home/aaa/.config/mpv/socket"end# mpv cycle audio KEY_PROGRAMbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_PROGRAMconfig = echo cycle vid | socat - "/home/aaa/.config/mpv/socket"end# mpv cycle aspect ratio KEY_ANGLEbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_ANGLEconfig = echo cycle aspect | socat - "/home/aaa/.config/mpv/socket"end# mpv cycle osd time KEY_OSDbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_OSDconfig = echo cycle osd-level | socat - "/home/aaa/.config/mpv/socket"end# mpv cycle osd time KEY_TIMEbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_TIMEconfig = echo cycle osd-level | socat - "/home/aaa/.config/mpv/socket"end# mpv seek back -3s KEY_REWINDbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_REWINDconfig = echo seek -3 | socat - "/home/aaa/.config/mpv/socket"end# mpv seek forward +1s KEY_FORWARDbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_FORWARDconfig = echo seek +1 | socat - "/home/aaa/.config/mpv/socket"end# mpv play faster KEY_NEXTbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_NEXTconfig = echo add speed +0.1 | socat - "/home/aaa/.config/mpv/socket"end# mpv play slower KEY_PREVIOUSbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_PREVIOUSconfig = echo add speed -0.1 | socat - "/home/aaa/.config/mpv/socket"end# mpv volume up KEY_VOL_PLUSbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_VOL_PLUSconfig = echo add volume +5 | socat - "/home/aaa/.config/mpv/socket"end# mpv volume down KEY_VOL_MINUSbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_VOL_MINUSconfig = echo add volume -5 | socat - "/home/aaa/.config/mpv/socket"end

author: DiTBho
author_rank: Super Contributor
timestamp: January 03, 2023, 04:15:07 pm
content: Quote from: RoGeorge on January 03, 2023, 04:10:42 pmMPU + USB-HID

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 04, 2023, 07:25:57 am
content: Here is a quick single-file example. Note that it needs access to both the TTY and the /dev/uinput devices, so for testing purposes, I recommend running it as root.Whenever it reads '+', it will generate a Volume Up keypress; whenever it reads '-', it will generate a Volume Down keypress.Specify a serial port or a TTY device, and the vendor:product/name for the synthetic keyboard device, on the command line. For example, if you runsudo ./binary $(tty) 1234:5678/Examplethen you can press + and - on the terminal to change the volume.While the daemon is running, you can observe it in the input event device list. For example,ls -laF /dev/input/andsudo evtest.Typesudo killall -TERM binaryto exit the daemon. (The daemon sets the serial port or TTY to raw mode, so when reading from the same terminal, Ctrl+C no longer generates an INT signal; that's why you cannot exit it by simply pressing Ctrl+C when running the above command. If you run it in a terminal using some other tty or serial port, then Ctrl+C will work just fine.)Code:// SPDX-License-Identifier: CC0-1.0//// Compile using for example// gcc -Wall -O2 thisfile.c -o binary#define _POSIX_C_SOURCE 200809L#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <termios.h>#include <linux/uinput.h>#include <string.h>#include <signal.h>#include <stdio.h>#include <errno.h>// Signal handling for graceful restartstatic volatile sig_atomic_t restart = 0;void handle_restart(int signum){(void)signum;restart = 1;}int install_restart(int signum){struct sigaction act;memset(&act, 0, sizeof act);sigemptyset(&act.sa_mask);act.sa_handler = handle_restart;act.sa_flags = 0; // No SA_RESTART flag!return sigaction(signum, &act, NULL);}// Signal handling for graceful exitstatic volatile sig_atomic_t done = 0;void handle_done(int signum){(void)signum;done = 1;}int install_done(int signum){struct sigaction act;memset(&act, 0, sizeof act);sigemptyset(&act.sa_mask);act.sa_handler = handle_done;act.sa_flags = 0; // No SA_RESTART flag!return sigaction(signum, &act, NULL);}// Helper function, since signal delivery can cause an EINTR "error". Async-signal safe, too.int writeall(int fd, const void *buf, size_t len){const int saved_errno = errno;int err = 0;const unsigned char *const end = (const unsigned char *)buf + len;const unsigned char *src = (const unsigned char *)buf;while (src < end) {ssize_t n = write(fd, src, (size_t)(end - src));if (n > 0) {src += n;} elseif (n != -1) {err = EIO;break;} elseif (errno != EINTR) {err = errno;break;}}errno = saved_errno;return err;}// Emit a keypress and releasevoid keypress(int fd, int code){struct input_event ev;// Timestamp is ignoredev.time.tv_sec = 0;ev.time.tv_usec = 0;ev.time = ev.time;// Keypressev.type = EV_KEY;ev.code = code;ev.value = 1; // Keypressev.type = EV_SYN;ev.code = SYN_REPORT;ev.value = 0;writeall(fd, ev, sizeof ev);// Key releaseev.value = 0; // Releasewriteall(fd, ev, sizeof ev);}int parse_usbid(const char *src, struct uinput_setup *to){unsigned long val;const char *end;if (!src || !*src || !to)return -1;memset(to, 0, sizeof *to);to->id.bustype = 0;to->id.vendor = 0;to->id.product = 0;to->id.version = 0;// Vendorend = src;errno = 0;val = strtoul(src, (char **)&end, 16);if (errno || end == src || *end != ':' || val > 0xFFFF)return -1;to->id.vendor = val;// Productsrc = ++end;errno = 0;val = strtoul(src, (char **)&end, 16);if (errno || end == src || val > 0xFFFF)return -1;to->id.product = val;// Version (optional)if (*end == ':') {src = ++end;errno = 0;val = strtoul(src, (char **)&end, 0);if (errno || end == src || val > 0xFFFF)return -1;to->id.version = val;}// Name (optional)if (*end == '/') {src = ++end;end = src + strlen(src);if ((size_t)(end - src) >= UINPUT_MAX_NAME_SIZE)return -1;strncpy(to->name, src, UINPUT_MAX_NAME_SIZE - 1);}if (*end)return -1;return 0;}int main(int argc, char *argv[]){const char *arg0 = (argc > 0 && argv && argv && argv) ? argv : "(this)";struct uinput_setup setup;struct termios oldsettings, settings;int uinputfd, devfd = -1;// Check command-line argumentsif (argc != 3 || !strcmp(argv, "-h") || !strcmp(argv, "--help")) {fprintf(stderr, "\n");fprintf(stderr, "Usage: %s [ -h | --help ]\n", arg0);fprintf(stderr, " %s DEVICE-PATH VENDOR:PRODUCT[:VERSION]\n", arg0);fprintf(stderr, "\n");return EXIT_FAILURE;}if (parse_usbid(argv, &setup)) {fprintf(stderr, "%s: Invalid synthetic USB HID device identifier.\n", argv);return EXIT_FAILURE;}// Install signal handlersif (install_done(SIGINT) ||install_done(SIGTERM) ||install_restart(SIGHUP) ||install_restart(SIGUSR1)) {fprintf(stderr, "Cannot install signal handlers: %s.\n", strerror(errno));return EXIT_FAILURE;}// Construct new input event deviceuinputfd = open("/dev/uinput", O_RDWR | O_CLOEXEC);if (uinputfd == -1) {fprintf(stderr, "/dev/uinput: %s.\n", strerror(errno));return EXIT_FAILURE;}// List event types and events this can produceioctl(uinputfd, UI_SET_EVBIT, EV_KEY);ioctl(uinputfd, UI_SET_KEYBIT, KEY_VOLUMEDOWN);ioctl(uinputfd, UI_SET_KEYBIT, KEY_VOLUMEUP);// Create the new synthetic input deviceioctl(uinputfd, UI_DEV_SETUP, &setup);ioctl(uinputfd, UI_DEV_CREATE);while (1) {// Close already open serial portif (devfd != -1) {tcflush(devfd, TCIOFLUSH);tcsetattr(devfd, TCSANOW, &oldsettings);close(devfd);}if (done)break;// Open serial port or TTY device,devfd = open(argv, O_RDWR | O_CLOEXEC);if (devfd == -1) {fprintf(stderr, "%s: Cannot open: %s.\n", argv, strerror(errno));close(uinputfd);return EXIT_FAILURE;}// obtain its current configuration,if (tcgetattr(devfd, &oldsettings) == -1) {fprintf(stderr, "%s: Not a TTY or serial port: %s.\n", argv, strerror(errno));close(devfd);close(uinputfd);return EXIT_FAILURE;}// and configure it.settings = oldsettings;settings.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);settings.c_oflag &= ~(OPOST | OCRNL | ONOCR | ONLRET);settings.c_cflag &= ~(CSIZE | PARENB);settings.c_cflag |= CS8 | CREAD;settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | TOSTOP | IEXTEN);settings.c_cc = 1;settings.c_cc = 0;if (tcsetattr(devfd, TCSANOW, &settings) == -1) {fprintf(stderr, "%s: Cannot configure: %s.\n", argv, strerror(errno));tcflush(devfd, TCIOFLUSH);tcsetattr(devfd, TCSANOW, &oldsettings);close(devfd);close(uinputfd);return EXIT_FAILURE;}// We have now restarted.restart = 0;while (!done && !restart) {unsigned char buf;ssize_t n = read(devfd, buf, sizeof buf);if (n > 0) {unsigned char *const end = buf + n;unsigned char *src = buf;while (src < end) {switch (*(src++)) {case '+':keypress(uinputfd, KEY_VOLUMEUP);break;case '-':keypress(uinputfd, KEY_VOLUMEDOWN);break;}}} elseif (n != -1) {// End of input from serial device; reopen.break;} elseif (errno != EINTR) {// Other error from serial device; reopen.break;}}}close(uinputfd);return EXIT_SUCCESS;}Majority of the code is signal handling (TERM and INT will gracefully exit, HUP and USR1 causes it to reopen the serial device), and serial device handling.Note that because all signal handlers have been installed without the SA_RESTART flag, signal delivery to the userspace handler will interrupt any blocking I/O calls (read()andwrite()in particular) witherrno==EINTR. The way the inner loop is written, this program mostly sits quietly waiting (blocking) on aread()from the serial port, with a signal delivery interrupting that. However, the signal could also arrive at a later time; particularly duringwriteall()(writing events to the uinput device), and we want to complete those.This does have a short race window wrt. signals and the blocking read: a signal could be delivered after the flag has been checked but just before the blockingread(). We could avoid that by having the signal handler calltcsetattr()to make the serial device non-blocking (by setting.c_cc=0,.c_cc=0,tcsetattr()being async-signal safe), but generally, standard POSIX signals are not queued and do not have any guarantees, so such short race windows are generally considered acceptable. (Correspondingly, service management daemons are expected to send at least two TERM signals with a delay in between to tell a service to exit, before KILLing the service forcefully. The only downside of killing this program abruptly is that the serial port termios settings are not restored to originals.)Theuinputstuff is quite trivial:Open/dev/uinput(write-only suffices, I recommend close-on-exec so you don't accidentally leak the open descriptor)For each event type it can produce, callioctl(fd, UI_SET_EVBIT, EV_type);For each event it can produce, callioctl(fd, UI_SET_KEYBIT,type_event);Construct astruct uinput_setup, withstruct input_idas theidmember defining the bus (BUS_USB),vendor:product, optionalversion, and thenamemember defining the device name (as if detected internally by the linux kernel) –– the name is NOT the device node name, but describes the device as if obtained from the USB descriptor or parsed by the Linux kernel.Then, callioctl(fd, UI_DEV_SETUP, &setup);Create the device node usingioctl(fd, UI_DEV_CREATE);Note that this is asynchronous: the device node may not exist yet when the call returns, because theudevdaemon takes a fraction of a second to create the device node, assign its properties, and so on. You can apply udev rules to this synthetic device exactly like it was a physical USB HID device.From this point forwards, you emit USB HID events by writing one or morestruct input_eventstructures tofd(the uinput device descriptor above).When you closefd(the uinput device descriptor), the synthetic device is disconnected and removed (byudev) automatically.If you generate multiple devices, you need to openuinputseparately (dup()won't suffice) for each generated device.It really is this simple. The Linux Kerneluinput moduledocumentation describes the interface in even more detail, as well as theLinux Input Subsystem userspace API; you'll also want to check theinclude/linux/input.h,include/linux/input-event-codes.h, andinclude/linux/uinput.hheader files exported from the Linux kernel and available as<linux/input.h>(which auto-includes<linux/input-event-codes.h>) and<input/uinput.h>for userspace programs in C.There are two ways of starting such daemons. One is to haveudevstart and stop them whenever the corresponding device (serial port device) is connected. The other is to have the daemon run always; when the device node does not exist, useinotifyto wait forIN_CREATE,IN_ATTRIB,IN_MOVED_TOevents in/dev/., attempting to open the device whenever such events occur for the entry with the same name. When the device has been successfully opened, the inotify descriptor (and its watch) can be closed. This consumes minimum resources, and very, very little CPU time, because such events in/dev/.occur only when new devices are attached.Sure, you could use theudevAPI instead, and become dependent on systemd-udevd; I don't want to, as I want the same to work with for example eudevd, and therefore use the inotify way.If you do an X-less appliance, withmpvorvlcrunning on raw accelerated framebuffer (DRI+VA_API or whatever), put each one on a separate console (/dev/ttyN). For example, in most Ubuntu variants, X runs on /dev/tty7, and a login (via agetty) on /dev/tty1. Thechvtutility changes the foreground terminal, very similar to how LeftAlt+FNor Ctrl+LeftAlt+FNchanges to /dev/ttyN.You can then have all of the appliance applications running at the same time, and switch between them: both physical USB HID and uinput keypresses above will switch the foreground terminal.If you use X and fullscreen applications, use a minimal window manager with multiple desktops, and start each application on a separate desktop. Depending on the window manager, there will be some keypresses to switch to a specific desktop. So, for multimedia controls, if you want to target a specific fullscreen X application, send first the desktop key shortcut, wait for the X server to start to act on the event (50ms should be plenty), and then send the multimedia keypress.Whatever way you generate events, and regardless of whether they are X or Linux Input subsystem events, do remember that each keystroke is actually a pair of events: a keypress, and a key release. For the Linux Input subsystem events, events are grouped, with ALWAYS aEV_SYN,SYN_REPORTas the last event in a group. So, to generate say Shift+F1, you generate KEY_LEFTSHIFT:1, SYN_REPORT, KEY_F1:1, SYN_REPORT, KEY_F1:0, KEY_LEFTSHIFT:0, SYN_REPORT sequence. (For keypresses, there are three.values: 0=release, 1=press, 2=autorepeat. The Linux kernel and X servers will handle autorepeat for you, though.)

author: RoGeorge
author_rank: Super Contributor
timestamp: January 04, 2023, 09:41:20 am
content: Wow, thank you!It compiles (Kubuntu 20.04/Jammy). Now I have so many questions...Will first search online for the trivial ones, then ask here what still couldn't figure.

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 04, 2023, 10:32:53 am
content: Quote from: RoGeorge on January 04, 2023, 09:41:20 amPlease, ask away!Full disclosure: for the last ten years or so, I've been quite a proponent for using the Linux Input subsystem. In fact, ever since I got my first Teensy 2.0++ (AT90USB1286), and made my first microcontroller project, a Linux keyboard arcade board (Arcade cabinet digital joystick and microcontroller buttons on a sturdy 50cm by 20cm baltic birch stick-laminated board, to play online Flash puzzle and platform games in a browser window, I'velovedUSB Human Interface Device specification. It Just Works.The Linux Input subsystemis modelled somewhat after the USB HID specification, but so that the same subsystem can support all known non-USB human interface devices as well. Vojtek Pavlik, the primary developer (working for SuSE then), really did a good job here. The subsystem is over twenty years old right now, and it still works perfectly well for new devices, with full backwards compatibility with code written two decades ago.For us developers, all we need to know is that each human interface device generates an input event device (/sys/class/input/eventNsymlinks), and udev creates the symlinks and device nodes in/dev/input/. Linux consoles (/dev/ttyN) and X by default read from all keyboard and mouse-like devices, but one can also use theEVIOCGRABioctl() to "grab" the device so that the events it generates are only provided to the grabbing process, and no others. There are a few ioctls to control e.g. keyboard repeat rates and such, but mostly we just read()struct input_eventstructures from the device stream. (Each read will return one or more structures, but only a full number of structures, never partial structures.)The/dev/uinputinterface can be used as I showed earlier to synthesize any such device, under software control.We do need to be aware of the security implications, however: anyone able to inject keystrokes while somebody else is logged in using the local keyboard, can inject commands as well. Similarly, an application that can read input event devices, can monitor keystrokes and mouse movement.When using microcontrollers with native USB, and creating an USB HID widget, theUSB HID Usage Tablesare indispensable, especially the Keyboard/Keypad page, because it includes both the codes related to each keypress (which all happen to fit in one byte, and each keyboard USB event listing up to six simultaneously pressed keys, plus Shift/Ctrl/Alt/etc. key states; but also when it is supported (which kind of keyboard should the USB HID device export itself as).I can warmly recommend any Teensy boards (Teensy LC in particular for their low price), as well as all Pro Micro clones based on ATmega32u4 (using the Arduino Leonardo bootloader) for HID device development in the Arduino environment. With Teensys, after you select one of the Teensy boards (Tools > Board menu), the Teensyduino add-on adds USB Type: to your Tools menu, so you can trivially do e.g. a Serial+Keyboard+Mouse+Joystic HID device (with Serial used for e.g. debug output), stickKeyboard.begin()in setup(), and you can do e.g.Keyboard.press(KEY_MEDIA_VOLUME_INC);Keyboard.release(KEY_MEDIA_VOLUME_INC);in loop() to generate a keystroke event pair (press and release). Literally just a few lines of code to make an USB keyboard! And it is a true keyboard/mouse/joystick device, too: no special drivers are needed in any OS. Just plug it in, wait for a second for USB enumeration etc., and it works.(Also, in Teensyduino,if (Serial) Serial.println("Stuff");will only format and send the string when an application has the USB serial port (tty) open. When no application has the serial port open,(Serial)evaluates tofalse.)EDIT: As of 2023-01-04,exp-tech.declaims to have Teensy LC's in stock; a bit higher price than what they normally go for, though (15€ + VAT + shipping). For anyone interested in experimenting with USB HID devices, I can warmly recommend it; the board itself is okay, but the Teensyduino support in the Arduino environment for such development is superb.

author: DiTBho
author_rank: Super Contributor
timestamp: January 04, 2023, 11:38:35 am
content: Quote from: Nominal Animal on January 04, 2023, 07:25:57 amabout security, ... many years ago, before Arduino was invented, someone put an MPU inside a ps/2 keyboard in a university computer room, MPU able to look at what you are typing and log everything follow the words { "root", "admin", "toor", ... }someone just typed "root", oh see, the next word will probably be the password, let's log into a EEpromI was there at the time (2001), when the head of the computer room found the hw Trojan horse. I remember he laughed out loud and made a joke to make fun of the shocking discovery. He said that paranoia is never enough, so to be more paranoid you should always carry your personal keyboard with you, always unplug it and take it with you to the bathroom, to the bar, NEVER leave the keyboard alone, never type on other keyboards and always put your personal keyboard in the safe when you're not using it.Even better, periodically disassemble and inspect, just in case ...p.s.thanks for the code!

author: Karel
author_rank: Super Contributor
timestamp: January 04, 2023, 12:23:43 pm
content: There'll be no security at all if people have physical access. Period.

author: Ian.M
author_rank: Super Contributor
timestamp: January 04, 2023, 02:43:56 pm
content: Physical access == Game Over, you have been pwn3dAnyone sufficiently determined and skilled could acquire an identical keyboard to that of the target machine, and design a new controller board for it, which could appear identical to the genuine one, but with the USB MCU of their choice, black-topped and remarked to look genuine. As long as the package is the same, the differences in pinout could be handled with a multi-layer via in pad PCB, or if its got a cheap and nasty COB, you don't even have to do that - just goop potting compound over a slim QFN and do your routing within the blob perimeter. Probably the biggest difficulty would be matching the appearance of the typical single sided phenolic keyboard controller PCB!Then its simply a matter of swapping the keyboard controller PCB, so asset tracking, and serial no. stickers are unchanged, and it isn't suspiciously cleaner than before. If necessary swap the keyboards, take the original to the dunny to install the trojan board, then swap them back. The trojan keyboard would be able to pass any scrutiny short of inspection of its PCB under a microscope or by XRAY.The trojan can log to FLASH or internal EEPROM - if it logs lets say the first 32 keystrokes after a significant period of inactivity, it will get most people's passwords, and spit them back out when a highly obscure sequence of key combinations is pressed, either as lightly encrypted text into any convenient text area, or over a one way optical link using one of the keyboard LEDs.The worrying thing is that fancier keyboards may not even need this effort - if the controller MCU is reflashable over USB without needing pins jumpered on its PCB, installing the trojan may be as simple as briefly plugging it into a malicious personal device with an OTG port and a DFU flasher utility!

author: RoGeorge
author_rank: Super Contributor
timestamp: January 07, 2023, 11:57:44 am
content: Quote from: Nominal Animal on January 04, 2023, 10:32:53 amMost of the questions are about something else, related with but not exactly about the example code. I don't have yet a clean view of how the signals travel in general. There are too many new things at once (for me). Was expecting any standards to be more generic, but the kernel org docs show some very narrow standardisation. I was expecting something like the RFC specs for networking, yet the kernel input system refers to very specific items like i.e. joystick or a multi-touch.Even more confusing, there is LIRC documentation in the kernel.orghttps://www.kernel.org/doc/html/latest/userspace-api/media/rc/lirc-dev.htmlhttps://www.kernel.org/doc/html/latest/userspace-api/media/rc/remote_controllers.htmlhttps://www.kernel.org/doc/html/latest/userspace-api/media/Only found that this morning, will have to read the LIRC kernel docs, too.For now, the biggest inconvenient in using the Linux kernel media keys is that the controls (play/pause) are sent to the active window. Often the player is in the background or minimized, and in the foreground is some other window open and active.How do I map the media keys (for example the play/pause) to always go to the media player?Is there any Linux mechanism to tell which player was last playing (in case there are more players open and paused)?

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 07, 2023, 01:17:38 pm
content: Quote from: RoGeorge on January 07, 2023, 11:57:44 amThe logic is rather simple: all human input device drivers map their inputs to the Linux Input subsystem. Kernel-internal stuff, like SysRq, console switching, and so on is on top of that. The userspace input event devices expose the features. X11 reads (but does not grab) by default all available devices (which is why you can just plug in a second or third keyboard and mouse, and they'll all work the same by default), and directs the events to the currently focused application.Quote from: RoGeorge on January 07, 2023, 11:57:44 amThat's because that is exactly how the USB Human Interface Device specification does it.Quote from: RoGeorge on January 07, 2023, 11:57:44 amLike I said earlier, I'd put each player on their own virtual desktop (AKA workspace), maximized.Use your Keyboard Shortcuts to assign a hotkey to select a specific desktop, which automatically focuses the (only) application on that desktop.Quote from: RoGeorge on January 07, 2023, 11:57:44 amDepends on the window manager. Cinnamon (fork from Gnome 2) even has a toolbar widget for that.In general, you can usewmctrlutility to control windows (size, fullscreen, modality, stacking order), focus (wmctrl -awindow-spec), and stuff like list desktops/workspaces (wmctrl -d) and applications (wmctrl -l). Using Keyboard Shortcuts, you can map any keypress to a script (to be executed), and that script can usewmctrlto manipulate the windows. (xpropandxwininfoutilities are very useful when writing such scripts.)

author: RoGeorge
author_rank: Super Contributor
timestamp: January 07, 2023, 01:40:51 pm
content: Makes more sense now, thank you. Though, I still can't understand the mindset of having dedicated media buttons on a desktop keyboard, yet those buttons won't work if I click on another window than the player.I have a commercial A4Tech WiFi combo, keyb+mouse, where the keyboard has 10 extra keys, sideways, like this:Photo from:https://www.a4tech.com/product.aspx?id=160One button is for Play/Pause. It only works when the player window is in focus.Is my Plasma KDE set wrong? Why making a Linux kernel specification in such a lousy way that a click into another window will render useless any input controller with physical media buttons on it, like this play/pause button on a PC keyboard?Shouldn't such a standard specify to play/pause the last player in focus?- specify in the standard to send the multimedia events to the last player that was in focus- specify a switch current player mechanism (like the Alt+TAB for windows, but for players only), in case more players are already open

author: RoGeorge
author_rank: Super Contributor
timestamp: January 07, 2023, 03:05:57 pm
content: Quote from: Nominal Animal on January 07, 2023, 01:17:38 pmThat would work well with a dedicated media center setup, but I'm using a normal desktop.My typical usage is this, from a workstation with Plasma KDE:- start some media that doesn't need 100% attention (a podcast, a music playlist, a light movie, etc.)- meanwhile open and work with other programs, while the media started earlier keeps running, either as audio only or in a 1/4 screen window (not in focus)- at some point I want to pause the media, or to skip a song, and I want to do that without digging through all the open windows, and without pointing the mouse to specific icons- often I need to control the player while sitting in a nearby chair and working at an electronics projectI expect a physical IR remote to interact with whatever it is playing now in the desktop, no mater the player. This works as expected for system volume and system mute (because LIRC was set to control the pulseaudio mute/volume), but not for play/pause/next/previous.Meanwhile looked for alternative ways to get the last active player. Found this:https://unix.stackexchange.com/questions/477823/use-dbus-to-get-name-of-mediaplayer-currently-playingNo idea if that's the right way. There are two methods there, one by looking at the pulse audio stream names, the other by looking at dbus. There seems to be a D-Bus standard,MPRIS (Media Player Remote Interfacing Specification). MPRIS looks very close to what I need, just that it doesn't work with any random media player. Arch wiki has a list of known working playershttps://wiki.archlinux.org/title/MPRISMPV, which is my default video player, doesn't show in dbus (tried withqdbus | grep -i mpv)Later edit:There's an MPV plugin available in most linux repos,https://github.com/hoyon/mpv-mprisInstalled it withsudo apt install mpv-mpris, and the mpv player now shows up inqdbus | grep -i mpv.

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 07, 2023, 03:07:05 pm
content: Quote from: RoGeorge on January 07, 2023, 01:40:51 pmNothing to do with Linux, and everything to do with X Windows.Quote from: RoGeorge on January 07, 2023, 01:40:51 pmThat would be the task of the Window Manager, or the application itself. Any application can passively grab a specific keypress (including modifier state, so you can grab say Alt+Shift+K without affecting how K or Shift+K or Alt+K or Ctrl+K is handled) so that unless someone already focused has it also grabbed, it will be delivered to the application (seeXGrabKey()).One could argue that it is silly that media player applications do not do this for Play/Pause/Stop/Forward/Back.(Then again, certain folks insist that instead of using X11, we should use D-Bus for these, and in e.g. Cinnamon desktop, register for such events provided by the csd-media-keys daemon. Because.. you know. I'd like to rant, but I'll try not to.)Alternatively, you can bind the keypress to a script that determines which window the direct the event to, and synthesize a suitable X11 event directed to that window using e.g.xdotool.Or, followingUnix philosophy, you could use a small X11 application that manages such applications you call "players", by grabbing the keypresses. It can obtain the list of X applications usingXQueryTree(similar toxwininfo -tree -root), and send synthesized events like multimedia keypresses to specific applications usingXSendEvent(). It can even monitor focus change events usingXSelectInput(display, window, FocusChangeMask). This is low-level X11 stuff, too; very lightweight.It seems to me that your needs would be best addressed using a small X11 application that reads codes/sequences/commands directly from your serial port (connected to a microcontroller via USB-Serial bridge, or to a microcontroller with native USB, and that microcontroller having at least one IR receiver already discussed). It would of course also grab the multimedia keys, so that stuff would Just Work. It would need to know how to tell which windows are "Players" (either by window title, or by executable name), and it might be useful to have it have OSD capability (backgroundless frameless windows at fixed position) to display applied actions, but it would be quite straightforward application.This has the benefit that it would adapt to the desktop user, quietly staying on the background, and only consuming very little memory and CPU time whenever window focus changes (if you want it to track focus among player applications) –– or it could also use PulseAudio services to track applications that generate sound, associating them with their respective windows (if any) ––, so that the serial-IR-controller would Do What You Mean, by monitoring which players are active or capable of generating sounds, associating them with the windows, and using X11 to send them the events.In fact, the absolute majority of such an application written in C would be in how to manage the underlying mappings. And the UI for that if you want an UI for it instead of configuring it fully using only flat text config files. Because only X11 (libX11) would be the requirement (plus possibly some PulseAudio crap), it would be very stable and easy to maintain.

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 07, 2023, 03:39:21 pm
content: Quote from: RoGeorge on January 07, 2023, 03:05:57 pmI wonder if simply replicating the multimedia key events to all active windows (via a simple x11 application –– not much configuration) would suffice.(I seriously dislike dbus stuff, you see.)It does sound likeplayerctlmight work for you out of the box. No need to download and compile it, it should be available in the repositories (asplayerctl). You shouldn't even need to install the daemon (the 2.0.2-1 I installed doesn't even have it).Use your Keyboard Shortcuts to bind:- Play and pause to/usr/bin/playerctl play-pause- Forward to/usr/bin/playerctl position +5(to skip 5 seconds forwards)- Backward to/usr/bin/playerctl position -5(to skip 5 seconds backwards)- Next (track) to/usr/bin/playerctl next- Previous (track) to/usr/bin/playerctl previousAs I am writing this, this works for at least Firefox in Linux Mint 20.3, Cinnamon desktop. I have a hidden window with a Youtube video playing, andplayerctl play-pausewill correctly play and pause it.

author: RoGeorge
author_rank: Super Contributor
timestamp: January 07, 2023, 03:53:40 pm
content: Indeed,playerctldoes the expected jobnope, when the player is not specified, plyerctl sends the commands to the first player seen (in alphabetical order). Well, at least it can be easily scripted to interface with whatever IR remote solution.(Not very sure about this, but it seems mplayer is to control MPRIS compliant players through dbus- though my Kubuntu has systemd anyways, not a problem for my current setup)

author: DiTBho
author_rank: Super Contributor
timestamp: January 07, 2023, 05:06:18 pm
content: Quote from: Nominal Animal on January 07, 2023, 03:39:21 pm(me tooif entropy plays a roledbus is a chaos agent)

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 07, 2023, 05:44:36 pm
content: Quote from: RoGeorge on January 07, 2023, 03:53:40 pmCare to try later versions that have theplayerctlddaemon?In your X session, you start the daemon using 'playerctld daemon', and it should monitor the active players as you describe, so thatplayerctldirects the commands to the "proper" application. Or that's what theGitHub page says. It does havequite a few issues, so one might wish to check the issue tracker first whether it is worth pursuing further.My own solution approach would differ: I'd use the X11 approach, mapping windows to audio sources, and use X11 events rather than dbus events to control the players. But that's just me.

author: RoGeorge
author_rank: Super Contributor
timestamp: January 07, 2023, 06:45:45 pm
content: Meanwhile found out it needs the daemonplayerctld, indeed, to keep track of the last player, just that I wanted to test it before posting it works OK when the daemon is started, and been delayed because I didn't know how to properly enable the service to start automatically.Followed the Arch wikihttps://wiki.archlinux.org/title/MPRIS"In order to start playerctld when you log in, you may create the following systemd/User service:" then enabled the service withsystemctl --user enable playerctld.service.Great,playerctldbehaves just as expected, thank you.

author: DiTBho
author_rank: Super Contributor
timestamp: January 07, 2023, 07:09:56 pm
content: Quote from: Nominal Animal on January 07, 2023, 05:44:36 pmI have completely removed dbus from the last stage4's PowerPC GNU/Linux profile.So none of the libraries and applications are compiled with dbus support.Can you tell more about your approach? It's *exactly* what I'd like to do

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 07, 2023, 07:48:07 pm
content: Quote from: DiTBho on January 07, 2023, 07:09:56 pmA simple X11 application as I outlined in#25, usingXGrabKey()to grab the multimedia keys (and optionally read remote commands from a serial port and/or socket), and redirect/synthesize them to specific windows usingXSendEvent()(mapping to whatever keypresses one might want, althoughmpvandvlcat least do support the multimedia keys by default).It does need to be tied in to the audio system also, to track which applications are generating sound. Exactly how to do that, depends on what audio subsystem you're using. Just monitoring which window has had focus last, is probably not going to cut it, you see. X11 itself has no audio support at all.Which one are you using?Simply put, the X11 application needs to map windows to process ID's (PIDs), and processes or windows to audio streams. Many non-player applications can produce sounds, like various alarms and dings, so I'd also use both executable name and window title (via POSIX regular expressions, regcomp() and regexec()) to determine which ones are "players". I'm pretty sure I'd write it in two parts, so that one part is the UI that only runs when one configures it, and the other part is the "daemon" part (that really only needs to run in your X session; see your Autostart session configuration).Unless the audio daemon already provides an interface to list currently active clients (and their PIDs or X11 window IDs), one way is to monitor which processes connect to it via local sockets (/proc/PID/fd/Nin Linux). I do know PulseAudio does (see e.g.pactl list clients), I do believe GStreamer and others do as well. Even applications directly using the OSS device nodes can be tracked.For those using various phone apps, it might be useful to add support to auto-pause current player if a specific application generates audio –– say, Skype ringing would auto-pause your media playback, and so on.

author: RoGeorge
author_rank: Super Contributor
timestamp: January 08, 2023, 08:06:43 am
content: To add MPRIS (Media Player Remote Interfacing Specification) for MPV and playerctl:Code:sudo apt install mpv-mprissudo apt install playerctlCreate a unit file to start the playerctld service. Without playerctld daemon the MPRIS doesn't know what was the last active player to send further commands to.Code:mkdir -p ~/.config/systemd/user && touch ~/.config/systemd/user/playerctld.servicenano ~/.config/systemd/user/playerctld.serviceAdd this content to it and save the playerctld.service fileCode:Description=Keep track of media player activityType=oneshotExecStart=/usr/bin/playerctld daemonWantedBy=default.targetStart and enable the playerctld.service to auto reloadCode:systemctl --user daemon-reloadsystemctl --user start playerctld.servicesystemctl --user enable playerctld.serviceTo enable MPRIS for Firefox check this checkbox in Firefox's Settings -> General -> Browser -> Control media via keyboard, headset, or virtual interfaceLearn more (Mozilla Firefox pages)Quick note about the setup with LIRC v0.9.0/Xenial, irexec, MPRIS and playerctl. Won't work with irexec service started as root. irexec has to be started as --user service, or else playerctl won't see the DBUS session of the current user, and won't be able to talk with MPRIS player.To fix this I had to- disable the root irexec.serviceCode:sudo systemctl stop irexecsudo systemctl disable irexec- create a new unit to start irexec as --user service,nano ~/.config/systemd/user/irexec.servicewith the following contentCode:Documentation=man:irexec(1)Documentation=http://lirc.org/html/configure.htmlDocumentation=http://lirc.org/html/configure.html#lircrc_formatDescription=Handle events from IR remotes decoded by lircd(8)After=network.targetWants=lirc.serviceRequires=dbus.serviceType=simpleExecStart=/usr/bin/irexecRestart=on-failureSuccessExitStatus=3 4RestartForceExitStatus=3 4WantedBy=default.target- start irexec with --user and enable it to start automatically (without sudo):Code:systemctl --user daemon-reloadsystemctl --user start irexecsystemctl --user enable irexec- add IR remote buttons associations with playerctl commandsnano ~/.lircrc(append the following text to it):Code:### playerctl LIRC key bindings# send play/pause/next/prev to the last active player# require playerctl installed and running playerctld daemon### last active player cycle pause KEY_PAUSEbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_PAUSEconfig = playerctl play-pauseend# last active player cycle pause KEY_PLAYbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_PLAYconfig = playerctl play-pauseend# last active player playlist-next KEY_RIGHTbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_RIGHTconfig = playerctl nextend# last active player playlist-prev KEY_RIGHTbeginremote = EBODA_DVD_blackprog = irexecbutton = KEY_LEFTconfig = playerctl previousendTo restart all, either reboot orCode:sudo systemctl daemon-reload && sudo systemctl restart lirc && systemctl --user daemon-reload && systemctl --user restart irexec && systemctl --user restart playerctld && pulseaudio -kBeen 10+ days since keep configuring LIRC and halfway there already, easy-peasy!

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 08, 2023, 09:31:32 am
content: Quote from: RoGeorge on January 08, 2023, 08:06:43 amReminds me of how I accidentally found out how toeasilyconfigure OpenWRT as a WiFi-Ethernet bridge with dedicated management interface on one local Ethernet interface and an isolated LAN on the rest of the local Ethernet connectors, but forgot to write it up, so afterwards, trying to do it twice, I've just managed to lock myself completely out...(The WiFi-Ethernet bridge itself being transparent to the traffic, without an IP address OpenWRT userspace can react to. The use scenario is such that I have a dedicated 4G/5G/LTE modem and firewall between the router (Asus RT-AC51U running OpenWRT) and the internet, this being a guest/untrusted network segment, for stuff like tablets and browsing and media streamers, relying on just WPA2/WPA3 security for local devices. The firewall does some fancy IP filtering, based on incoming connection attempts. The order of creating the management interface and bringing up its IP address, moving the services to that IP address, and then configuring the bridging of the WAN and WiFI is the key, obviously. But I always seem to get it wrong: I need to type the sequence up first, before I try it the next time...)

author: RoGeorge
author_rank: Super Contributor
timestamp: January 08, 2023, 10:16:42 am
content: That's why I keep posting here my settings, so I won't have to discover all that again at the next install.Though, now that LIRC v0.9.0 kind of works as expected, I'm tempted to remove it and try to install one more time the current version of LIRC v0.10+, the one with that uses the kernel LIRC features.

author: DiTBho
author_rank: Super Contributor
timestamp: January 08, 2023, 11:12:48 pm
content: Quote from: Nominal Animal on January 07, 2023, 07:48:07 pmvlc compiled with OSS on SBC#1, and with ALSA support on SBC#2(PowerPC boards)OSS is simpler for me to be implemented/hacked/fixed, at kernel side.

author: DiTBho
author_rank: Super Contributor
timestamp: January 08, 2023, 11:15:58 pm
content: I don't have an audio daemon running; OSS/ALSA at the kernel side, and nothing else in userspace, except mpg123 and VLC.

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 09, 2023, 01:07:31 pm
content: Quote from: DiTBhoWe'll want to monitor processes having the/dev/dsp(OSS) or/dev/snd/pcm*(ALSA) devices open. Since we are only interested in a few applications, we can do that by checking their/proc/PID/fd/(usingreadlink()/readlinkat()), to determine which one is potentially playing audio.This will fail for PulseAudio, because it will be the PulseAudio daemon that has the device open.Could you please check whatlsof /dev/dsp /dev/snd/pcm*outputs when you have bothvlcandmpg123running, with a combination of one playing and one paused or stopped?If only the active one is shown, then the X11 redirector will be very straightforward to implement.(If you don't havelsof, you can do the same by finding out the PIDs of the two processes, and usingls -l /proc/PID/fd/orstat -c '%N' /proc/PID/fd/*)Also, please compare the output towmctrl -l -p, especially the PIDs in the third column. I am assuming the PIDs should match.If you want the same without X, then feeding them the events is a bit more complicated. The issue is that while we can easily determine the controlling terminal for them, we'd need to find a way to feed additional input to themasterside of the terminal –– we can only easily determine theslaveside. If they only used terminal consoles (/dev/ttyN), we could usechvt, but for things likessh'ing in and playing audio via mpg123, it gets tricky.I suspect that it would then be easiest to configure the players to accept control from a local socket or named pipe also.