Improve latency of IR decoding
Subsystems (5)
Sean Young
maintainercover Improve latency of IR decoding
The current IR decoding is much too slow. Many IR protocols rely on a trailing space for decoding (e.g. rc-6 needs to know when the bits end). The trailing space is generated by the IR timeout, and if this is longer than required, keys can be perceived as sticky and slugish.
The other issue the keyup timer. IR has no concept of a keyup message, this is implied by the absence of IR. So, minimising the timeout for this further improves the handling.
With these patches in place, using IR with the builtin decoders is much improved and feels very snappy.
Sean Young (3):
media: rc: set timeout to smallest value required by enabled protocols
media: rc: add ioctl to get the current timeout
media: rc: per-protocol repeat period and minimum keyup timer
Documentation/media/uapi/rc/lirc-func.rst | 1 + .../media/uapi/rc/lirc-set-rec-timeout.rst | 14 +++-- drivers/media/cec/cec-core.c | 2 +- drivers/media/rc/ir-imon-decoder.c | 1 + drivers/media/rc/ir-jvc-decoder.c | 1 + drivers/media/rc/ir-mce_kbd-decoder.c | 1 + drivers/media/rc/ir-nec-decoder.c | 1 + drivers/media/rc/ir-rc5-decoder.c | 1 + drivers/media/rc/ir-rc6-decoder.c | 1 + drivers/media/rc/ir-sanyo-decoder.c | 1 + drivers/media/rc/ir-sharp-decoder.c | 1 + drivers/media/rc/ir-sony-decoder.c | 1 + drivers/media/rc/ir-xmp-decoder.c | 1 + drivers/media/rc/lirc_dev.c | 9 ++- drivers/media/rc/rc-core-priv.h | 1 + drivers/media/rc/rc-ir-raw.c | 31 +++++++++- drivers/media/rc/rc-main.c | 68 +++++++++++----------- include/uapi/linux/lirc.h | 6 ++ 18 files changed, 101 insertions(+), 41 deletions(-)
Signature · 1 line
2.14.3
Sean Young
maintainerPATCH 1/3 media: rc: set timeout to smallest value required by enabled protocols
The longer the IR timeout, the longer we wait until delivering each scancode. By reducing this timeout, we reduce the time it take for the last scancode to be delivered.
Note that the lirc daemon disables all protocols, in case we revert back to the default value.
--- drivers/media/rc/ir-imon-decoder.c | 1 + drivers/media/rc/ir-jvc-decoder.c | 1 + drivers/media/rc/ir-mce_kbd-decoder.c | 1 + drivers/media/rc/ir-nec-decoder.c | 1 + drivers/media/rc/ir-rc5-decoder.c | 1 + drivers/media/rc/ir-rc6-decoder.c | 1 + drivers/media/rc/ir-sanyo-decoder.c | 1 + drivers/media/rc/ir-sharp-decoder.c | 1 + drivers/media/rc/ir-sony-decoder.c | 1 + drivers/media/rc/ir-xmp-decoder.c | 1 + drivers/media/rc/rc-core-priv.h | 1 + drivers/media/rc/rc-ir-raw.c | 31 ++++++++++++++++++++++++++++++- drivers/media/rc/rc-main.c | 12 ++++++------ 13 files changed, 47 insertions(+), 7 deletions(-)
drivers/media/rc/ir-imon-decoder.c +1 -0
@@ -170,6 +170,7 @@ static struct ir_raw_handler imon_handler = { .decode = ir_imon_decode, .encode = ir_imon_encode, .carrier = 38000, + .max_space = IMON_UNIT * IMON_BITS * 2, };static int __init ir_imon_decode_init (void )
drivers/media/rc/ir-jvc-decoder.c +1 -0
@@ -213,6 +213,7 @@ static struct ir_raw_handler jvc_handler = { .decode = ir_jvc_decode, .encode = ir_jvc_encode, .carrier = 38000, + .max_space = JVC_TRAILER_SPACE, };static int __init ir_jvc_decode_init (void )
drivers/media/rc/ir-mce_kbd-decoder.c +1 -0
@@ -475,6 +475,7 @@ static struct ir_raw_handler mce_kbd_handler = { .raw_register = ir_mce_kbd_register, .raw_unregister = ir_mce_kbd_unregister, .carrier = 36000, + .max_space = MCIR2_MAX_LEN, };static int __init ir_mce_kbd_decode_init (void )
drivers/media/rc/ir-nec-decoder.c +1 -0
@@ -253,6 +253,7 @@ static struct ir_raw_handler nec_handler = { .decode = ir_nec_decode, .encode = ir_nec_encode, .carrier = 38000, + .max_space = NEC_TRAILER_SPACE, };static int __init ir_nec_decode_init (void )
drivers/media/rc/ir-rc5-decoder.c +1 -0
@@ -274,6 +274,7 @@ static struct ir_raw_handler rc5_handler = { .decode = ir_rc5_decode, .encode = ir_rc5_encode, .carrier = 36000, + .max_space = RC5_TRAILER, };static int __init ir_rc5_decode_init (void )
drivers/media/rc/ir-rc6-decoder.c +1 -0
@@ -394,6 +394,7 @@ static struct ir_raw_handler rc6_handler = { .decode = ir_rc6_decode, .encode = ir_rc6_encode, .carrier = 36000, + .max_space = RC6_SUFFIX_SPACE, };static int __init ir_rc6_decode_init (void )
drivers/media/rc/ir-sanyo-decoder.c +1 -0
@@ -210,6 +210,7 @@ static struct ir_raw_handler sanyo_handler = { .decode = ir_sanyo_decode, .encode = ir_sanyo_encode, .carrier = 38000, + .max_space = SANYO_TRAILER_SPACE, };static int __init ir_sanyo_decode_init (void )
drivers/media/rc/ir-sharp-decoder.c +1 -0
@@ -226,6 +226,7 @@ static struct ir_raw_handler sharp_handler = { .decode = ir_sharp_decode, .encode = ir_sharp_encode, .carrier = 38000, + .max_space = SHARP_TRAILER_SPACE, };static int __init ir_sharp_decode_init (void )
drivers/media/rc/ir-sony-decoder.c +1 -0
@@ -224,6 +224,7 @@ static struct ir_raw_handler sony_handler = { .decode = ir_sony_decode, .encode = ir_sony_encode, .carrier = 40000, + .max_space = SONY_TRAILER_SPACE, };static int __init ir_sony_decode_init (void )
drivers/media/rc/ir-xmp-decoder.c +1 -0
@@ -199,6 +199,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)static struct ir_raw_handler xmp_handler = { .protocols =RC_PROTO_BIT_XMP , .decode = ir_xmp_decode, + .max_space =XMP_TRAILER_SPACE , };static int __init ir_xmp_decode_init (void )
drivers/media/rc/rc-core-priv.h +1 -0
@@ -37,6 +37,7 @@ struct ir_raw_handler {int (*encode)(enum rc_proto protocol,u32 scancode,struct ir_raw_event *events,unsigned int max);u32 carrier; +u32 max_space;/* These two should only be used by the mce kbd decoder */ int (*raw_register)(struct rc_dev *dev);
drivers/media/rc/rc-ir-raw.c +30 -1
@@ -233,7 +233,36 @@ ir_raw_get_allowed_protocols(void)static int change_protocol (struct rc_dev *dev,u64 *rc_proto) { -/* the caller will update dev->enabled_protocols */ +struct ir_raw_handler *handler; +u32 timeout =0 ; + +if (!dev->max_timeout) +return 0 ; + +mutex_lock (&ir_raw_handler_lock); +list_for_each_entry (handler, &ir_raw_handler_list, list) { +if (handler->protocols & *rc_proto) { +if (timeout < handler->max_space) + timeout = handler->max_space; + } + } +mutex_unlock (&ir_raw_handler_lock); + +if (timeout ==0 ) + timeout =IR_DEFAULT_TIMEOUT ; +else + timeout +=MS_TO_NS (10 ); + +if (timeout < dev->min_timeout) + timeout = dev->min_timeout; +else if (timeout > dev->max_timeout) + timeout = dev->max_timeout; + +if (dev->s_timeout) + dev->s_timeout (dev, timeout); +else + dev->timeout = timeout; +return 0 ; }
drivers/media/rc/rc-main.c +6 -6
@@ -1241,6 +1241,9 @@ static ssize_t store_protocols(struct device *device,if (rc <0 ) goto out; +if (dev->driver_type ==RC_DRIVER_IR_RAW ) +ir_raw_load_modules (&new_protocols); + rc = dev->change_protocol (dev, &new_protocols);if (rc <0 ) { dev_dbg(&dev->dev, "Error setting protocols to 0x%llx\n",
@@ -1248,9 +1251,6 @@ static ssize_t store_protocols(struct device *device, goto out; } -if (dev->driver_type ==RC_DRIVER_IR_RAW ) -ir_raw_load_modules (&new_protocols); -if (new_protocols != old_protocols) { *current_protocols = new_protocols; dev_dbg(&dev->dev, "Protocols changed to 0x%llx\n",
@@ -1735,6 +1735,9 @@ static int rc_prepare_rx_device(struct rc_dev *dev)if (dev->driver_type ==RC_DRIVER_SCANCODE && !dev->change_protocol) dev->enabled_protocols = dev->allowed_protocols; +if (dev->driver_type ==RC_DRIVER_IR_RAW ) +ir_raw_load_modules (&rc_proto); +if (dev->change_protocol) { rc = dev->change_protocol (dev, &rc_proto);if (rc <0 )
@@ -1742,9 +1745,6 @@ static int rc_prepare_rx_device(struct rc_dev *dev) dev->enabled_protocols = rc_proto; } -if (dev->driver_type ==RC_DRIVER_IR_RAW ) -ir_raw_load_modules (&rc_proto); -set_bit (EV_KEY , dev->input_dev->evbit);set_bit (EV_REP , dev->input_dev->evbit);set_bit (EV_MSC , dev->input_dev->evbit);
Signature · 1 line
2.14.3
Sean Young
maintainerPATCH 2/3 media: rc: add ioctl to get the current timeout
In reply to Sean YoungSince the kernel now modifies the timeout, make it possible to retrieve the current value.
--- Documentation/media/uapi/rc/lirc-func.rst | 1 + Documentation/media/uapi/rc/lirc-set-rec-timeout.rst | 14 +++++++++----- drivers/media/rc/lirc_dev.c | 7 +++++++ include/uapi/linux/lirc.h | 6 ++++++ 4 files changed, 23 insertions(+), 5 deletions(-)
Documentation/media/uapi/rc/lirc-func.rst +1 -0
@@ -17,6 +17,7 @@ LIRC Function Reference lirc-get-rec-resolution lirc-set-send-duty-cycle lirc-get-timeout + lirc-get-rec-timeout lirc-set-rec-timeout lirc-set-rec-carrier lirc-set-rec-carrier-range
Documentation/media/uapi/rc/lirc-set-rec-timeout.rst +9 -5
@@ -1,19 +1,23 @@ .. -*- coding: utf-8; mode: rst -*- .. _lirc_set_rec_timeout: +.. _lirc_get_rec_timeout: -************************** -ioctl LIRC_SET_REC_TIMEOUT -************************** +*************************************************** +ioctl LIRC_GET_REC_TIMEOUT and LIRC_SET_REC_TIMEOUT +*************************************************** Name ==== -LIRC_SET_REC_TIMEOUT - sets the integer value for IR inactivity timeout. +LIRC_GET_REC_TIMEOUT/LIRC_SET_REC_TIMEOUT - Get/set the integer value for IR inactivity timeout. Synopsis ======== +.. c:function:: int ioctl( int fd, LIRC_GET_REC_TIMEOUT, __u32 *timeout ) + :name: LIRC_GET_REC_TIMEOUT + .. c:function:: int ioctl( int fd, LIRC_SET_REC_TIMEOUT, __u32 *timeout ) :name: LIRC_SET_REC_TIMEOUT
@@ -30,7 +34,7 @@ Arguments Description =========== -Sets the integer value for IR inactivity timeout. +Get and set the integer value for IR inactivity timeout. If supported by the hardware, setting it to 0 disables all hardware timeouts and data should be reported as soon as possible. If the exact value
drivers/media/rc/lirc_dev.c +7 -0
@@ -575,6 +575,13 @@ static long ir_lirc_ioctl(struct file *file, unsigned int cmd, }break ; +case LIRC_GET_REC_TIMEOUT : +if (!dev->timeout) + ret = -ENOTTY ; +else + val =DIV_ROUND_UP (dev->timeout,1000 ); +break ; +case LIRC_SET_REC_TIMEOUT_REPORTS :if (!dev->timeout) ret = -ENOTTY ;
include/uapi/linux/lirc.h +6 -0
@@ -134,6 +134,12 @@#define LIRC_SET_WIDEBAND_RECEIVER _IOW('i', 0x00000023, __u32) +/* +* Return the recording timeout, which is either set by +* the ioctl LIRC_SET_REC_TIMEOUT or by the kernel after setting the protocols. +*/ +#define LIRC_GET_REC_TIMEOUT _IOR('i', 0x00000024, __u32) +/* * struct lirc_scancode - decoded scancode with protocol for use with * LIRC_MODE_SCANCODE
Signature · 1 line
2.14.3
Sean Young
maintainerPATCH 3/3 media: rc: per-protocol repeat period and minimum keyup timer
In reply to Sean YoungEach IR protocol has its own repeat period. We can minimise the keyup timer to be the protocol period + IR timeout. This makes keys less "sticky" and makes IR more reactive and nicer to use.
This feature was previously attempted in commit d57ea877af38 ("media: rc:
per-protocol repeat period"), but that did not take the IR timeout into account, and had to be reverted.
--- drivers/media/cec/cec-core.c | 2 +- drivers/media/rc/lirc_dev.c | 2 +- drivers/media/rc/rc-main.c | 56 +++++++++++++++++++++++--------------------- 3 files changed, 31 insertions(+), 29 deletions(-)
drivers/media/cec/cec-core.c +1 -1
@@ -322,7 +322,7 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, adap->rc->allowed_protocols =RC_PROTO_BIT_CEC ; adap->rc->priv = adap; adap->rc->map_name =RC_MAP_CEC ; - adap->rc->timeout =MS_TO_NS (100 ); + adap->rc->timeout =MS_TO_NS (550 );#endif return adap; }
drivers/media/rc/lirc_dev.c +1 -1
@@ -583,7 +583,7 @@ static long ir_lirc_ioctl(struct file *file, unsigned int cmd,break ;case LIRC_SET_REC_TIMEOUT_REPORTS : -if (!dev->timeout) +if (dev->driver_type !=RC_DRIVER_IR_RAW ) ret = -ENOTTY ;else fh->send_timeout_reports = !!val;
drivers/media/rc/rc-main.c +29 -27
106 lines not on this page · raw message
Signature · 1 line
2.14.3
cover Improve latency of IR decoding
In reply to Sean YoungHi Sean,
Quoted 11 lines · Sean Young
The current IR decoding is much too slow. Many IR protocols rely on a trailing space for decoding (e.g. rc-6 needs to know when the bits end). The trailing space is generated by the IR timeout, and if this is longer than required, keys can be perceived as sticky and slugish.
The other issue the keyup timer. IR has no concept of a keyup message, this is implied by the absence of IR. So, minimising the timeout for this further improves the handling.
With these patches in place, using IR with the builtin decoders is much improved and feels very snappy.
thanks a lot for the patches!
I didn't have much time to test yet, but quick checks on Amlogic/meson-ir (kernel 4.16-rc7 + media tree + your patches) and Raspberry Pi (RPi foundation kernel 4.14 + my backport of your patches) look really promising.
I found one issue, though, in ir-sharp-decoder.c max_space must be set to SHARP_ECHO_SPACE - otherwise we get a timeout between the normal and inverted message part and decoding fails.
One thing I'm wondering is if the keyup timer marging might be too tight now. Basically we have just the fixed 10ms marging from idle timeout. The repeat periods of the protocols are rather accurate/strict, so (programmable) remotes not sticking to the official timing might cause repeated keyup/down events if they are repeating a tad to slow.
I'm not sure if this could be an issue, but maybe we should add a safety margin to the repeat periods as well? For example 10 or 20 percent of the specced repeat periods. What do you think?
To get some more test coverage I've asked my colleague to include my backport patch in the LibreELEC testbuilds for x86 and RPi. We've got some 500 regular users of these so if something's not working we should find out soon. I just hope I didn't mess up the backport... Here's the link to my 4.14 patch:
so long & thanks,
Hias
Quoted 29 lines
Sean Young (3):
media: rc: set timeout to smallest value required by enabled protocols
media: rc: add ioctl to get the current timeout
media: rc: per-protocol repeat period and minimum keyup timerDocumentation/media/uapi/rc/lirc-func.rst | 1 + .../media/uapi/rc/lirc-set-rec-timeout.rst | 14 +++-- drivers/media/cec/cec-core.c | 2 +- drivers/media/rc/ir-imon-decoder.c | 1 + drivers/media/rc/ir-jvc-decoder.c | 1 + drivers/media/rc/ir-mce_kbd-decoder.c | 1 + drivers/media/rc/ir-nec-decoder.c | 1 + drivers/media/rc/ir-rc5-decoder.c | 1 + drivers/media/rc/ir-rc6-decoder.c | 1 + drivers/media/rc/ir-sanyo-decoder.c | 1 + drivers/media/rc/ir-sharp-decoder.c | 1 + drivers/media/rc/ir-sony-decoder.c | 1 + drivers/media/rc/ir-xmp-decoder.c | 1 + drivers/media/rc/lirc_dev.c | 9 ++- drivers/media/rc/rc-core-priv.h | 1 + drivers/media/rc/rc-ir-raw.c | 31 +++++++++- drivers/media/rc/rc-main.c | 68 +++++++++++----------- include/uapi/linux/lirc.h | 6 ++ 18 files changed, 101 insertions(+), 41 deletions(-)Signature · 1 line
2.14.3
cover Improve latency of IR decoding
Hi Sean,
Quoted 33 lines · Matthias Reichl
Hi Sean,
Quoted 11 lines · Sean Young
The current IR decoding is much too slow. Many IR protocols rely on a trailing space for decoding (e.g. rc-6 needs to know when the bits end). The trailing space is generated by the IR timeout, and if this is longer than required, keys can be perceived as sticky and slugish.
The other issue the keyup timer. IR has no concept of a keyup message, this is implied by the absence of IR. So, minimising the timeout for this further improves the handling.
With these patches in place, using IR with the builtin decoders is much improved and feels very snappy.
thanks a lot for the patches!
I didn't have much time to test yet, but quick checks on Amlogic/meson-ir (kernel 4.16-rc7 + media tree + your patches) and Raspberry Pi (RPi foundation kernel 4.14 + my backport of your patches) look really promising.
I found one issue, though, in
ir-sharp-decoder.cmax_spacemust be set toSHARP_ECHO_SPACE- otherwise we get a timeout between the normal and inverted message part and decoding fails.One thing I'm wondering is if the keyup timer marging might be too tight now. Basically we have just the fixed 10ms marging from idle timeout. The repeat periods of the protocols are rather accurate/strict, so (programmable) remotes not sticking to the official timing might cause repeated keyup/down events if they are repeating a tad to slow.
Quoted 8 lines
I'm not sure if this could be an issue, but maybe we should add a safety margin to the repeat periods as well? For example 10 or 20 percent of the specced repeat periods. What do you think?
To get some more test coverage I've asked my colleague to include my backport patch in the LibreELEC testbuilds for x86 and RPi. We've got some 500 regular users of these so if something's not working we should find out soon.
Quick update: testing so far went really smooth, no issues reported since we included the backport patch in LibreELEC testbuilds.
Quote from https://github.com/LibreELEC/LibreELEC.tv/pull/2623#issuecomment-377897518
Quoted 3 lines
This is in my nightly test builds since 28 March, and no problems reported so far.
On my NUC with Harmony One/RC6 remote these commits are working just fine.
I've been using LibreELEC on RPi with the patch (using a gpio ir receiver and a Hauppauge RC-5 remote) since then and everything was fine as well.
so long,
Hias
Quoted 38 lines
I just hope I
didn't mess up the backport... Here's the link to my 4.14 patch:so long & thanks,
Hias
Quoted 29 lines
Sean Young (3):
media: rc: set timeout to smallest value required by enabled protocols
media: rc: add ioctl to get the current timeout
media: rc: per-protocol repeat period and minimum keyup timerDocumentation/media/uapi/rc/lirc-func.rst | 1 + .../media/uapi/rc/lirc-set-rec-timeout.rst | 14 +++-- drivers/media/cec/cec-core.c | 2 +- drivers/media/rc/ir-imon-decoder.c | 1 + drivers/media/rc/ir-jvc-decoder.c | 1 + drivers/media/rc/ir-mce_kbd-decoder.c | 1 + drivers/media/rc/ir-nec-decoder.c | 1 + drivers/media/rc/ir-rc5-decoder.c | 1 + drivers/media/rc/ir-rc6-decoder.c | 1 + drivers/media/rc/ir-sanyo-decoder.c | 1 + drivers/media/rc/ir-sharp-decoder.c | 1 + drivers/media/rc/ir-sony-decoder.c | 1 + drivers/media/rc/ir-xmp-decoder.c | 1 + drivers/media/rc/lirc_dev.c | 9 ++- drivers/media/rc/rc-core-priv.h | 1 + drivers/media/rc/rc-ir-raw.c | 31 +++++++++- drivers/media/rc/rc-main.c | 68 +++++++++++----------- include/uapi/linux/lirc.h | 6 ++ 18 files changed, 101 insertions(+), 41 deletions(-)Signature · 1 line
2.14.3
Sean Young
maintainercover Improve latency of IR decoding
Hi Matthias,
Quoted 18 lines · Matthias Reichl
Quoted 17 lines · Matthias Reichl
Hi Sean,
Quoted 11 lines · Sean Young
The current IR decoding is much too slow. Many IR protocols rely on a trailing space for decoding (e.g. rc-6 needs to know when the bits end). The trailing space is generated by the IR timeout, and if this is longer than required, keys can be perceived as sticky and slugish.
The other issue the keyup timer. IR has no concept of a keyup message, this is implied by the absence of IR. So, minimising the timeout for this further improves the handling.
With these patches in place, using IR with the builtin decoders is much improved and feels very snappy.
thanks a lot for the patches!
Quoted 8 lines
Quoted 8 lines
I didn't have much time to test yet, but quick checks on Amlogic/meson-ir (kernel 4.16-rc7 + media tree + your patches) and Raspberry Pi (RPi foundation kernel 4.14 + my backport of your patches) look really promising.
I found one issue, though, in
ir-sharp-decoder.cmax_spacemust be set toSHARP_ECHO_SPACE- otherwise we get a timeout between the normal and inverted message part and decoding fails.
Thanks for spotting that -- you're right!
Quoted 6 lines
Quoted 6 lines
One thing I'm wondering is if the keyup timer marging might be too tight now. Basically we have just the fixed 10ms marging from idle timeout. The repeat periods of the protocols are rather accurate/strict, so (programmable) remotes not sticking to the official timing might cause repeated keyup/down events if they are repeating a tad to slow.
This does need some further thought. There might be delays in the scheduling of the rc decoding thread or the IR hardware might be slow delivering new IR pulse data (e.g. fifo like hardware, e.g. winbond-cir).
Quoted 9 lines
Quoted 8 lines
I'm not sure if this could be an issue, but maybe we should add a safety margin to the repeat periods as well? For example 10 or 20 percent of the specced repeat periods. What do you think?
To get some more test coverage I've asked my colleague to include my backport patch in the LibreELEC testbuilds for x86 and RPi. We've got some 500 regular users of these so if something's not working we should find out soon.
Quoted 4 lines
Quick update: testing so far went really smooth, no issues reported since we included the backport patch in LibreELEC testbuilds.
Quote from https://github.com/LibreELEC/LibreELEC.tv/pull/2623#issuecomment-377897518
Thank you so much for including the patches in the LibreELEC test builds, that really is a great test!
Quoted 7 lines
Quoted 3 lines
This is in my nightly test builds since 28 March, and no problems reported so far.
On my NUC with Harmony One/RC6 remote these commits are working just fine.
I've been using LibreELEC on RPi with the patch (using a gpio ir receiver and a Hauppauge RC-5 remote) since then and everything was fine as well.
That's great. I'd like to do some more testing with various bits of hardware and test all the protocols.
Thanks,
Sean