|
|
Subscribe / Log in / New account

IR decoding with BPF

July 9, 2018

This article was contributed by Sean Young

In the 4.18 kernel, a new feature was merged to allow infrared (IR) decoding to be done using BPF. Infrared remotes use many different encodings; if a decoder were to be written for each, we would end up with hundreds of decoders in the kernel. So, currently, the kernel only supports the most widely used protocols. Alternatively, the lirc daemon can be run to decode IR. Decoding IR can usually be expressed in a few lines of code, so a more lightweight solution without many kernel-to-userspace context switches would be preferable. This article will explain how IR messages are encoded, the structure of a BPF program, and how a BPF program can maintain state between invocations. It concludes with a look at the steps that are taken to end up with a button event, such as a volume-up key event.

Infrared remote controls emit IR light using a simple LED. The LED is turned on and off for shorter or longer periods, which is interpreted somewhat akin to morse code. When infrared light has been detected for a period, the result is called a "pulse". The time between pulses when no infrared light is detected is called a "space".

Whenever a pulse or space is detected by an IR receiver, a BPF program will be executed (if one is attached). This program consists of a single function entry point that takes a pointer to a context. For IR decoders, this context is an unsigned int value. For a packet filter, the context would instead be a packet. In our case, the lower 24 bits of the int value contain the duration of the pulse or space, in microseconds. The top eight bits define the type of the event, which can either be LIRC_MODE2_PULSE, LIRC_MODE2_SPACE, or LIRC_MODE2_TIMEOUT. The return value of the BPF program is ignored.

If a space between two pulses gets excessively long, it could delay the decoding of a button press. For example, we might want to know that the IR message has really ended by measuring the space after the last pulse has occurred. Since a space is a time between two pulses, we would have to wait for the next pulse from the next IR message to occur before we would get this value. So, for this reason, there is a timeout. If a space lasts longer than the timeout, it is reported as LIRC_MODE2_TIMEOUT. This is typically set at 125ms.

A BPF program can be written in a number of different ways, but the easiest way is to use clang with the target BPF. This allows the BPF program to be written in a sort of restricted C that does not allow the use of C-library functions or loops, for example.

To create an IR decoder in BPF, we start with:

    static int eq_margin(int duration, int expected, int margin)
    {
	return (duration >= (expected - margin)) 
     	    && (duration <= (expected + margin));
    }

    int bpf_decoder(unsigned int *sample)
    {
	int duration = *sample & LIRC_VALUE_MASK;
	bool pulse = (*sample & LIRC_MODE2_MASK) == LIRC_MODE2_PULSE;

	if (pulse && eq_margin(duration, 300, 100) {
		// seen short pulse of about 300 microseconds
	}
    }

Typically, IR receivers have a precision of 50µs at most. I would recommend checking for durations of at least 100µs around the value you expect.

Now we can parse a single pulse or space, but every IR message consists of several pulses and spaces in quick succession. In a regular C program, we would use a static variable, a global variable, or some heap memory to maintain our state while waiting for the next event. Unfortunately none of those options are available in BPF. Instead, we use BPF maps, which are a generic key-value store where the key is always an unsigned int and the value is a generic blob; we can store whatever we want. This is how we declare a BPF map to hold the IR-decoding state:

    struct decoder_state {
	unsigned int bits;
	unsigned int count;	
    };

    struct bpf_map_def SEC("maps") decoder_state_map = {
	.type = BPF_MAP_TYPE_ARRAY,
	.key_size = sizeof(unsigned int),
	.value_size = sizeof(struct decoder_state),
	.max_entries = 1,
    };

There are a few different types of BPF maps, the main ones being "array" and "hash". Since we are only looking to store one structure, an array is more than sufficient; we thus specify max_entries as one. The key_size has to be the size of an unsigned int, no other key size is supported. The value_size is the size of our blob of data. We've declared a struct for this purpose, and we use sizeof() to ensure we have the right storage for it.

There are a number functions available to use BPF maps from our BPF code. For example, to get an our entry in decoder_state_map BPF map, we can call:

    int key = 0;
    struct decoder_state *s = bpf_map_lookup_elem(&decoder_state_map, &key);

Unfortunately, if we try to use the pointer to the map, we will get an error when we load our BPF program: "R6 invalid mem access 'map_value_or_null'". This is the kernel's BPF verifier complaining; it checks to ensure that a BPF program does not do anything it should not, like try to access out-of-bounds memory. It also checks for other conditions, like relying on undefined behavior or loops.

The problem here is that bpf_map_lookup_elem(), the function used to obtain a value from a BPF map, might return NULL if the key is beyond the last element. The elements of an array are pre-allocated, and we are looking for element zero out of a total of one, so this lookup should never fail. However, the BPF verifier is not aware of this so, in order to keep the verifier happy, we have to add:

    if (!s)
	return 0;

The pointer we get from bpf_map_lookup_elem() is a direct pointer to the array, so we do not have to call bpf_map_update_elem() after making changes. The BPF verifier will check that we only use our pointer with the right offsets within our array entry; otherwise our program will not load.

Now that we have memory to store state, we can implement decoding. When we have decoded the IR to a button event, we can submit that event to the input subsystem using the BPF function bpf_rc_keydown(). It takes four arguments, being the BPF context, the protocol, the scancode, and the toggle bit:

  • The context for BPF is the pointer that was passed to the main BPF function; so we simply pass sample here.
  • The IR protocol can be used by user space to determine which protocol produced any given scancode; at the moment, nothing uses it.
  • The scancode is the value that was decoded. IR protocols generally encode some sort of value, and that value does not necessarily represent a key or a button. A particular remote might assign particular values with buttons; so, we need a mapping from scancode to key code. This is done using remote-control keymaps, which usually live in /lib/udev/rc_keymaps/ if the v4l-utils package is installed (or the ir-keytable package on Ubuntu or Debian).
  • Some IR protocols include a toggle bit. Since the IR message is repeated every 90ms or so, it is impossible to distinguish a key being held from a key released and pressed again (toggled). In the latter case, the toggle bit will change value, so rc-core knows to generate both key-up and key-down events.

So those are the four arguments to bpf_rc_keydown(). Now, we can show a complete example of a fictional IR decoder.

    #include <linux/lirc.h>
    #include <linux/bpf.h>

    #include "bpf_helpers.h"

    enum state {
	STATE_INACTIVE,
	STATE_FIRST_PULSE,
	STATE_SECOND_PULSE
    };

    struct decoder_state {
       enum state state;
       unsigned int space;
    };

    struct bpf_map_def SEC("maps") decoder_state_map = {
	.type = BPF_MAP_TYPE_ARRAY,
	.key_size = sizeof(unsigned int),
	.value_size = sizeof(struct decoder_state),
	.max_entries = 1,
    };

    SEC("fictional_ir")
    int decode(unsigned int *sample)
    {
	int key = 0;
	struct decoder_state *s = bpf_map_lookup_elem(&decoder_state_map, &key);

	if (!s)
	    return 0;

	int duration = LIRC_VALUE(*sample);

	switch (s->state) {
	case STATE_INACTIVE:
	    if (LIRC_IS_PULSE(*sample) && duration == 500) {
		s->state = STATE_FIRST_PULSE;
	    }
	    break;
	case STATE_FIRST_PULSE:
	    if (LIRC_IS_SPACE(*sample)) {
		s->space = duration;
		s->state = STATE_SECOND_PULSE;
	    } else {
		s->state = STATE_INACTIVE;
	    }
	    break;
	case STATE_SECOND_PULSE:
	    if (LIRC_IS_PULSE(*sample) && duration == 500) {
	 	bpf_rc_keydown(sample, 64, s->space / 100, 0);
	    }
	    s->state = STATE_INACTIVE;
	    break;
	}

	return 0;
    }

    char _license[] SEC("license") = "GPL";

Several operations are multiplexed through the bpf() system call for managing BPF programs and BPF maps, and for attaching them to devices. To create a BPF program, the BPF_PROG_LOAD is used. We have to provide a pointer to the BPF instructions, the instruction count, and a program name. If the system call is successful, we will get a file descriptor.

We can create BPF maps with the BPF_MAP_CREATE command, which also returns a file descriptor on success. Once we have the program and maps created, we can attach the program to a LIRC device (e.g. /dev/lirc0) using the BPF_PROG_ATTACH command. We have to provide a file descriptor for the LIRC device and the BPF program file descriptor. Once the file descriptor is attached, we can safely exit our process and the BPF program won't be freed when its file descriptor is closed.

Currently there is a hard-coded limit of 64 BPF programs that may be attached to one LIRC device. Any more, and BPF_PROG_ATTACH will return E2BIG. Every time a new pulse or space occurs, all the BPF programs will be executed. This makes it possible to load multiple BPF decoders, so that different remotes can be used at the same time.

As you might expect there are also commands for querying and detaching BPF programs.

The BPF example above can be compiled it with:

    clang --target=bpf -O2 -c foobar.c

You'll need to compile it with kernel headers from 4.18 (or later), and the bpf_helpers.h from the same tree. This produces foobar.o, an ELF object file.

Using ir-keytable, you can load this BPF program. You'll need the BPF patches, which have not been merged yet at the time of writing. In order to simulate this, the rc-loopback pseudo-receiver can be used, so no IR hardware is needed. Here are the steps to make this work:

    modprobe rc-loopback
    ir-keytable -p ./foobar.o

In order to test this setup, create a file test with the following contents:

    pulse 500
    space 1500
    pulse 500

Now, run:

    ir-keytable -k 15:KEY_VOLUMEUP -t

in one terminal, and:

    ir-ctl -s test

in another. You should get this output:

    855.168999: lirc protocol(64): scancode = 0xf
    855.169009: event type EV_MSC(0x04): scancode = 0x0f
    855.169009: event type EV_KEY(0x01): key_down: KEY_VOLUMEUP
    855.169009: event type EV_SYN(0x00).

The ir-keytable patches above also include a Python script that converts lircd remote configuration so that it can be used with ir-keytable. This should make it possible to do without the lirc daemon. However, some protocol decoders require very basic loops, which currently the BPF verifier does not allow at all.

Even with all lircd remote configurations supported, that would still not cover all possible remote controls. A possible solution can be found in IRP notation, a general form of description for IR protocols; it would be nice to generate BPF from that, and have support for a very broad array of remotes, without having to open-code each one. Lastly, other things than button presses are encoded in IR, for example target temperatures in air conditioning remote controls, or some remote controls include a directional pad. Supporting such devices with BPF decoders will require some further work.

Index entries for this article
KernelBPF/Device drivers
KernelDevice drivers/Support APIs
GuestArticlesYoung, Sean


to post comments

IR decoding with BPF

Posted Jul 9, 2018 16:09 UTC (Mon) by linuxjacques (subscriber, #45768) [Link] (6 responses)

Well now I know what BPF is, but not from reading this article.

IR decoding with BPF

Posted Jul 9, 2018 18:01 UTC (Mon) by jake (editor, #205) [Link] (5 responses)

> Well now I know what BPF is, but not from reading this article.

I just added a link to hopefully help others who are not up on BPF.

thanks!

jake

IR decoding with BPF

Posted Jul 9, 2018 23:34 UTC (Mon) by atai (subscriber, #10977) [Link] (4 responses)

BPF: the new Javascript?

IR decoding with BPF

Posted Jul 10, 2018 9:06 UTC (Tue) by k3ninho (subscriber, #50375) [Link] (1 responses)

>BPF: the new Javascript?
I'll get onto it once I've finished the Common Lisp interpreter -- unless we can fold in an incomplete and buggy implementation thereof within the eBPF-js engine?

K3n.

IR decoding with BPF

Posted Jul 10, 2018 16:51 UTC (Tue) by Cyberax (✭ supporter ✭, #52523) [Link]

Get on with the time. Nobody cares about LISP anymore, it's JavaScript this century.

IR decoding with BPF

Posted Jul 19, 2018 19:02 UTC (Thu) by miquels (guest, #59247) [Link]

You have it backwards. We should replace BFP in the kernel with WASM.

IR decoding with BPF

Posted Jul 20, 2018 8:06 UTC (Fri) by rurban (guest, #96594) [Link]

Probably, but with the added functionality to remove all things security in your kernel. So they desperately find new ways to keep your favorite toy, and persuade everyone else to ditch dtrace and only write BPF probes. Next time: BPF in userspace, i.e. almost dtrace.

With arrays in BPF and spectre/meltdown it is not possible to be on the safe side anymore.

IR decoding with BPF

Posted Jul 9, 2018 20:45 UTC (Mon) by meyert (subscriber, #32097) [Link] (6 responses)

"Alternatively, the lirc daemon can be run to decode IR"

So why is any of this actually done in kernel code?

Why not rip out all in kernel IR decoding and why adding more like this bpf support?

IR decoding with BPF

Posted Jul 9, 2018 22:45 UTC (Mon) by roc (subscriber, #30627) [Link]

Yes. The article complains about user/kernel context switches but it does not explain why that is actually a problem. Frequent user/kernel transitions are common in Linux, they're called "system calls".

IR decoding with BPF

Posted Jul 9, 2018 23:08 UTC (Mon) by rahvin (guest, #16953) [Link] (3 responses)

There isn't any in kernel IR decoding other than device support. The point of the article is to point out that though BPF was developed for networking it's being found to be a very flexible tool to do lots of things. Will lirc move to using BPF? who knows but the article does show it's possible to use BPF rather creatively for things it was never really intended for.

I don't know about you but that's pretty cool that it was designed and implemented generically enough that it's got uses beyond the direct use for which it was developed. I think that's actually a pretty good example of the Linux way in designing these kernel interfaces so they are flexible.

IR decoding with BPF

Posted Jul 9, 2018 23:35 UTC (Mon) by atai (subscriber, #10977) [Link] (1 responses)

security hole, anyone?

IR decoding with BPF

Posted Jul 10, 2018 0:11 UTC (Tue) by daney (guest, #24551) [Link]

No more of a security hole than the N other uses of eBPF in the kernel.

It seems the main type of device that would use this is probably embedded consumer platforms. Are we going to start seeing evil IR blasters designed to hack into these things via the (now) in-kernel IR decoders? I don't know.

IR decoding with BPF

Posted Jul 10, 2018 0:57 UTC (Tue) by wahern (subscriber, #37304) [Link]

> I don't know about you but that's pretty cool that it was designed and implemented generically enough that it's got uses beyond the direct use for which it was developed.

This would be noteworthy if this were using original BPF, which was explicitly written for stateless filtering of network packets using a very minimal virtual stack machine. The BPF engine in Linux was extended to support more generic constructs as well as loading and storing of state, and has more in common with Google's NaCL project than original BPF. The only remaining limitation in Linux's BPF is, IIUC, the inability to loop--in classic BPF only forward jumps are allowed, whereas in Linux BPF backwards jumps are allowed if the verifier is convinced the program doesn't actually loop.

It's not surprising at all that it can do this.

IR decoding with BPF

Posted Jul 16, 2018 16:53 UTC (Mon) by mchehab (subscriber, #41156) [Link]

> So why is any of this actually done in kernel code?

The answer is the same to this question: "why an USB HID scancode is translated to key inside the Kernel?"

Because on an embedded device, the IR may be the only input device. Think for example on a Set Top Box or a TV set: usually, all the user has is the remote controller. It needs to be able to handle key presses since when the Kernel starts.

IR decoding with BPF

Posted Jul 10, 2018 0:16 UTC (Tue) by quotemstr (subscriber, #45331) [Link] (12 responses)

IR decoding should be done in userspace. It's really hard to imagine a scenario in which the transition latency would matter. This kind of thing is _exactly_ the moral hazard that adding a general-purpose scripting system to the kernel introduces.

IR decoding with BPF

Posted Jul 10, 2018 7:45 UTC (Tue) by shiftee (subscriber, #110711) [Link] (7 responses)

My employer makes an embedded device which supports modbus over serial.
For the embedded C version we customised the driver to watch for a gap like above in order to separate the packets.
We then put the data in a struct with an int telling us the number of bytes.
For the Linux version we have not found a way to do this. We can read the bytes sequentially but the timing information is lost.
This means that if we receive a malformed or unsupported packet the only recovery is to flush the buffers and try reading again.

While not a disaster it is preferable to throw out only that packet and try reading the next one.
To do so under Linux it seems we need to modify the driver, but BPF looks like a nice solution if it were possible

IR decoding with BPF

Posted Jul 10, 2018 8:40 UTC (Tue) by dgm (subscriber, #49227) [Link] (5 responses)

The problem with the modbus over serial protocol is that it relies on detecting silence lengths to mark frame boundaries.

But I thought that libmodbus (http://libmodbus.org/) had this already implemented. Is it not the case?

IR decoding with BPF

Posted Jul 10, 2018 8:58 UTC (Tue) by chris.sykes (subscriber, #54374) [Link] (4 responses)

> But I thought that libmodbus (http://libmodbus.org/) had this already implemented. Is it not the case?

Nope, libmodbus tries to parse the RTU frames as bytes are received in order to figure out how many are still outstanding; the trouble is, it has to do this before it can check the CRC...

IR decoding with BPF

Posted Jul 10, 2018 14:00 UTC (Tue) by dgm (subscriber, #49227) [Link] (3 responses)

Any idea of why it does this instead of reading byte for byte and timing out?

IR decoding with BPF

Posted Jul 10, 2018 15:39 UTC (Tue) by chris.sykes (subscriber, #54374) [Link] (2 responses)

I suspect support for Modbus TCP, which uses length prefixed framing, was added first, with RTU coming later, and they kept the "how many bytes am I still waiting for" code in the common layer.

It's difficult to do RTU frame timing properly from user-space, without RT scheduling; and you really want control over the RX FIFO interrupt thresholds in the UART as well.

I've often thought making Modbus RTU serial line discipline, that exposed a socket API (like socketCAN), would make an interesting project, but so far, haven't found the time...

IR decoding with BPF

Posted Jul 11, 2018 7:22 UTC (Wed) by shiftee (subscriber, #110711) [Link] (1 responses)

So do you think BPF could be modified (in theory at least) to read Modbus RTU packets and somehow provide them to user space as length prefixed frames?

IR decoding with BPF

Posted Jul 11, 2018 9:44 UTC (Wed) by Darkmere (subscriber, #53695) [Link]

Probably. One of the interesting use cases for that is a system where you have multiple speeds on the same physical network.

With rs485 you then want to decode traffic in multiple speeds at once to find out which traffic is modbus RTU and which is some other traffic.
(It’s common enough to have Mbus at 2400 bps and modbus at 9600 and 19200. And no. It ain’t pretty)

IR decoding with BPF

Posted Jul 12, 2018 9:35 UTC (Thu) by seanyoung (subscriber, #28711) [Link]

For the modbus case there is a BPF function bpf_ktime_get_ns() available which can be used for processing timeouts correctly.

This is an interesting idea. I have a device which produces packets on usb-serial; the process wakes up for nearly every byte that arrives, which causes load on the underpowered arm device it is attached to. It would be nice if the process could be woken up only when a complete packet arrives, and invalid packets get dropped.

This seems similar to the original purpose of BPF. The BPF program would need access to the serial buffer and control read readiness reporting.

IR decoding with BPF

Posted Jul 16, 2018 17:10 UTC (Mon) by mchehab (subscriber, #41156) [Link] (3 responses)

> IR decoding should be done in userspace. It's really hard to imagine a scenario in which the transition latency would matter

Handling input events in Kernel has noting to do with latency. It is all about allowing to control the system when it boots. It doesn't really matter if the keyboard is an old PS/2 keyboard, an USB keyboard or a Infrared remote: once keys are pressed, user expects actions to be taken.

The remote controller subsystem was designed to allow:
- disabling it completely;
- enable hardware decoders but require userspace to prepare it;
- do decoding in software (via LIRC);
- support devices with a micro-controller that reports scan codes to the Kernel (instead of PULSE/SPACE timings);
- and now, via BPF decoding (for newer Kernels).

On systems that have keyboard/mice, all the above options could be used, but there are embedded devices where the only input device is an infrared (like a TV set of a Set Top Box). For those, doing Kernel decoding provide ways to allow passing keycodes very early at boot time, with would help, for example, to start userspace with a different run level, just like if the device had any other type of keyboard.

IR decoding with BPF

Posted Jul 17, 2018 9:20 UTC (Tue) by seanyoung (subscriber, #28711) [Link]

Exactly. Another point to consider (if that was not already clear) is that there are two types of IR devices:

1. IR receivers that report pulse/space information "raw IR" or "mode 2"
2. IR receivers that report decoded scancodes

By having pulse/space decoding in kernel space, both types of devices can be used in LIRC_MODE_SCANCODE, which means that decoded scancodes are reported. Userspace does not need to care if the IR decoding happens in the IR receiver or in the kernel; the same interface is exposed to userspace.
Also both types of devices report input events to the input layer in exactly the same way, so again it looks the same from userspace.

Some IR devices (like the winbond-cir SuperI/O) can do both decoding in hardware circuit or report pulse-space to the kernel. We choose to set up the device in the later mode since we can then support many more protocols than the few the hardware supports.

IR decoding with BPF

Posted Jul 30, 2022 0:47 UTC (Sat) by comex (subscriber, #71521) [Link] (1 responses)

I'm pretty sure it's not even possible to load a BPF program without a userspace program, though...

IR decoding with BPF

Posted Jul 30, 2022 21:20 UTC (Sat) by flussence (guest, #85566) [Link]

There's technically nothing stopping someone doing that at kernel build time and then including the BPF bytecode in the kernel/initrd like a firmware blob. It'd be slightly silly as you could just as easily use plain C; on the other hand one could also make the argument *more* of the kernel should be runtime-replaceable like this...

IR decoding with BPF

Posted Jul 11, 2018 15:37 UTC (Wed) by gebi (guest, #59940) [Link] (9 responses)

That should work for the usbtouchscreen driver too...

https://github.com/torvalds/linux/blob/master/drivers/inp...

IR decoding with BPF

Posted Jul 12, 2018 5:19 UTC (Thu) by paulj (subscriber, #341) [Link] (8 responses)

I'm wondering in what scenario user-kernel space transitions are a performance issue for low-speed IR-remote comms?

IR decoding with BPF

Posted Jul 12, 2018 9:25 UTC (Thu) by seanyoung (subscriber, #28711) [Link] (6 responses)

After JIT, an IR decoder is about ~400 instructions on x86-64 (without loops). That's less work than a single context switch, and with user space decoding there will be many more transitions and much more memory used.

IR decoding with BPF

Posted Jul 13, 2018 0:52 UTC (Fri) by k8to (guest, #15413) [Link] (5 responses)

This implies that it's more efficient to have it in-kernel, but does't really explain that doing it in userspace is a performance concern for low-bandwidth links such as the one this is designed for.

In other words if doing it in user space costs 0.00000000001% of a core and doing it in kernel costs 0.000000000001%, then it's not really a performance concern.

IR decoding with BPF

Posted Jul 16, 2018 6:43 UTC (Mon) by cpitrat (subscriber, #116459) [Link] (4 responses)

Say people who do not use hundreds of billions of IR devices on their computer ...

IR decoding with BPF

Posted Jul 16, 2018 8:47 UTC (Mon) by paulj (subscriber, #341) [Link] (3 responses)

Interesting setup. How do you get billions of IR devices attached on a computer?

IR decoding with BPF

Posted Jul 16, 2018 8:59 UTC (Mon) by cpitrat (subscriber, #116459) [Link] (2 responses)

Billions is easy, I'm talking hundreds of billions.
First you have to buy them. That's where you discover that few sellers support int64 through their whole toolchain.
Then you have to get them deliver. Even with small packages (20 cm^3) we're talking about 20,000 trucks coming to your home.
Then you need longer cables because even if the receptor is only 1cm^3 you need a 32m radius sphere to fit them all (ignoring the cable).

So a bunch of challenges, but I as you see, no major obstacle.

IR decoding with BPF

Posted Jul 16, 2018 16:50 UTC (Mon) by excors (subscriber, #95769) [Link]

Why would you want a solid sphere of IR devices? You'd only be able to communicate with the ones on the outside surface, the others would all be in shadow. Surely you'd want to arrange them in a single layer as a spherical shell about 900m in radius, with your IR receiver in the middle. Then you might start to worry about decoding taking a noticeable percentage of your CPU cycles.

IR decoding with BPF

Posted Jul 19, 2018 8:56 UTC (Thu) by johnny (guest, #10110) [Link]

Is that really a productive use of your time, though? Wiring up the first hundred billion devices is probably a fun time, but I suspect the novelty would start wearing off soon thereafter.

IR decoding with BPF

Posted Jul 15, 2018 14:51 UTC (Sun) by rossmohax (guest, #71829) [Link]

I read it more more like a "look ma, no hands!" case :) Curious engineer had an itch to scratch and published result. It might have some battery-saving benefits though.

IR decoding with BPF

Posted Jul 28, 2018 14:27 UTC (Sat) by HybridAU (guest, #85157) [Link] (1 responses)

I know this is slightly off-topic for this article, but does anyone know of a good USB IR Blaster / Receiver? I bought an Irdroid USB IR Transceiver a few years ago and I don't know if it was damaged during postage or something but I could never get it to work. I tried Lirc / irrecord and never got anything.

Essentially what I want to do is set up a Raspberry Pi, record the signals from my air conditioner's remote and then use a cron job to playback and switch on / off my air conditioner at certain times.

IR decoding with BPF

Posted Oct 11, 2018 11:54 UTC (Thu) by seanyoung (subscriber, #28711) [Link]

For USB, I would recommend any mceusb device. Not all have transmitters attached.

The raspberrypi this device is very well supported: https://energenie4u.co.uk/catalogue/product/ENER314-IR


Copyright © 2018, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds