[REF] How Infrared is (not) working on LePro3 - some infos for IR devs

Search This thread

darkobas

Senior Member
Jan 11, 2011
4,762
9,223
plus.google.com
Another (failed) try:
Instead of writing our own infrared HAL implementation, I thought it might be easier to just look at the implementation of other devices.

I came across the Xiaomi Mi 5 ("gemini") which also has an infrared device, the same ro.product.board (msm8996) and the same architecture.

I just replaced the HAL implementation file on the LePro3 (/system/lib64/hw/consumerir.default.so) with the one from the latest Cyanogenmod nigthly build (the file there is named: /system/lib64/hw/consumerir.msm8996.so).

First success: The .so file was loaded successfully, but the Consumer IR Service failed to start, as the Xiaomi HAL implementation uses LIRC to communicate with the infrared blaster (using the device file /dev/lirc0) which is not provided by the default kernel of the LePro 3.

As the Consumer IR Service failed to start, the device stuck in a bootloop, logging regularly this error:
Code:
11-24 16:24:02.459 I/SystemServer( 1570): Consumer IR Service
11-24 16:24:02.460 E/ConsumerIrLirc( 1570): fail to open /dev/lirc0 error -1
11-24 16:24:02.460 E/ConsumerIrService( 1570): Can't open consumer IR transmitter, error: -1
11-24 16:24:02.460 E/System  ( 1570): ******************************************
11-24 16:24:02.461 E/System  ( 1570): ************ Failure starting core service
11-24 16:24:02.461 E/System  ( 1570): java.lang.RuntimeException: FEATURE_CONSUMER_IR present, but no IR HAL loaded!
11-24 16:24:02.461 E/System  ( 1570):   at com.android.server.ConsumerIrService.<init>(ConsumerIrService.java:51)
11-24 16:24:02.461 E/System  ( 1570):   at com.android.server.SystemServer.startOtherServices(SystemServer.java:508)
11-24 16:24:02.461 E/System  ( 1570):   at com.android.server.SystemServer.run(SystemServer.java:282)
11-24 16:24:02.461 E/System  ( 1570):   at com.android.server.SystemServer.main(SystemServer.java:180)
11-24 16:24:02.461 E/System  ( 1570):   at java.lang.reflect.Method.invoke(Native Method)
11-24 16:24:02.461 E/System  ( 1570):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
11-24 16:24:02.461 E/System  ( 1570):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

So, if somebody could compile a kernel which provides a lirc interface (/dev/lirc0), we could just use the HAL from Xiaomi and the problem also would be solved.
I had a quick look qt this. But i think they have modified the lirc driver in kernel to work with their hardware. also their dts is different.

Sent from my LEX720 using Tapatalk
 
  • Like
Reactions: mobiusm

androcheck

Senior Member
Dec 7, 2009
236
413
john.zweng.at
I had a quick look qt this. But i think they have modified the lirc driver in kernel to work with their hardware. also their dts is different.
Hi @darkobas! Thanks for looking into this. :)

I also realized that lirc is very probably not an option for the IR chip used in the LEX720 device. The lirc kernel driver would need to implement the proprietary serial protocol which is currently done by the QuickSetSDK in userspace (altough it would be a beautiful and clean solution to have a working lirc driver).

Btw, I recently also switched to your OmniROM 7.1.2 build for my daily used phone. Thanks for your work! :good:
 

darkobas

Senior Member
Jan 11, 2011
4,762
9,223
plus.google.com
Hi @darkobas! Thanks for looking into this. :)

I also realized that lirc is very probably not an option for the IR chip used in the LEX720 device. The lirc kernel driver would need to implement the proprietary serial protocol which is currently done by the QuickSetSDK in userspace (altough it would be a beautiful and clean solution to have a working lirc driver).

Btw, I recently also switched to your OmniROM 7.1.2 build for my daily used phone. Thanks for your work! :good:

trying to make atleast the stock app work.
stuck at this at the moment
05-09 12:26:19.217 6581 6581 I UEI.SmartControl.LeTV: ### init IR Blaster...
05-09 12:26:19.220 6581 6581 E UEI.SmartControl.LeTV: no permission on read/write serial port!
05-09 12:26:19.221 6581 6581 E UEI.SmartControl.LeTV: java.io.IOException: no permission on read/write serial port!
05-09 12:26:19.221 6581 6581 E UEI.SmartControl.LeTV: at com.uei.driver.SerialDataComm.f(Unknown Source)
05-09 12:26:19.221 6581 6581 E UEI.SmartControl.LeTV: at com.uei.driver.SerialDataComm.<init>(Unknown Source)
 
  • Like
Reactions: GalaticStryder

androcheck

Senior Member
Dec 7, 2009
236
413
john.zweng.at
trying to make atleast the stock app work.
stuck at this at the moment
05-09 12:26:19.217 6581 6581 I UEI.SmartControl.LeTV: ### init IR Blaster...
05-09 12:26:19.220 6581 6581 E UEI.SmartControl.LeTV: no permission on read/write serial port!
05-09 12:26:19.221 6581 6581 E UEI.SmartControl.LeTV: java.io.IOException: no permission on read/write serial port!
05-09 12:26:19.221 6581 6581 E UEI.SmartControl.LeTV: at com.uei.driver.SerialDataComm.f(Unknown Source)
05-09 12:26:19.221 6581 6581 E UEI.SmartControl.LeTV: at com.uei.driver.SerialDataComm.<init>(Unknown Source)

Hi,
I've decompiled the QuickSet SDK and this log message only appears in this context (where "file" is the serial device file under /dev which is used to send commands to the IR system):

Code:
if (file != null && file.canRead() && file.canWrite()) {
    ... does some stuff here
    return;  // and RETURNS
}
this.logger.logError("no permission on read/write serial port!", new Object[0]);
throw new IOException("no permission on read/write serial port!");

So this means it cannot find the tty file or has not the permissions to read/write to it (also take care of SE linux context!).
On the original stock ROM the device file /dev/ttyHSL1 is used.

Additional info:
The information which device file should be used, normally comes from the client application (which binds the QuickSet SDK service). The QuickSet service itself only defines a fallback default within its strings.xml (<string name="SerialPort_LeTV">/dev/ttyMT3</string>).

The serial device file path to use is added to the intent sent to the service (see "Port" below):

Code:
...
intent.putExtra("Port", this.platformParams.getSerialName());  // <--- HERE the client app specifies the full path to the tty device file
intent.putExtra("Baudrate", this.platformParams.getSerialPort());
boolean result = bindService(intent, this.mSetupServiceConnection, 1);
 

trizex

Senior Member
Oct 21, 2006
233
141
I wrote a bit about it couple of months ago. Screenshots of 6.0 working IR logcat grabs are in this post
https://xdaforums.com/showpost.php?p=71677801&postcount=117

So I've spent a few hours digging around, and here's what I have so far. The serial port to which the app is trying to bind should be /dev/ttyHSL1, but it's missing in nougat.

Furthermore following @androcheck great writeup on the matter I saw that sys/remote/enable wasnt being toggled at all.( on remote control app startup it should change its value to 1, thus powering up the IR chip). I tried toggling it manually, but nothing changed.

I restored my 6.0.1 to grab some logs, and saw some processes that werent present in nougat. Mainly "ss", " ss_ir", "ss_UEI_IRbiz", who, among other things, toggle the sys/remote/enable switch, and bind quicksetsdk to /dev/ttyHSL1.

So after returning to Nougat, I was offered to update the remote control app, and I did. Now it crashes on startup, but guess what? The processes I've mentioned that I saw on Marshmallow were now present :) the app toggles the switch to activate IR now as it should, but the serial port itself is still missing (if I presume correctly it's missing from the kernel?)

Hope I was of some use to you with this info, I'll post the grabbed logs in a min.
 

androcheck

Senior Member
Dec 7, 2009
236
413
john.zweng.at
I wrote a bit about it couple of months ago. Screenshots of 6.0 working IR logcat grabs are in this post
https://xdaforums.com/showpost.php?p=71677801&postcount=117
@trizex Thanks for your reply. :)

@darkobas: which kernel did you test with? Did you test with your EAS kernel?

I did a quick grep over the source and the only occurrences of "ttyHSL" I found were in:
  • Documentation/devicetree/bindings/tty/serial/msm_serial.txt
  • drivers/tty/serial/msm_serial_hs_lite.c

I've checked the config in "arch/arm64/configs/zl1_defconfig" and it seems that CONFIG_SERIAL_MSM_HSL is not enabled.
Could you try again with this config enabled?

P.S.: I didn't build the kernel or ROM myself until now. Is it possible that you could provide me a local manifest to work with? :)
 
Last edited:
  • Like
Reactions: trizex

GalaticStryder

Senior Member
Nov 20, 2014
1,325
4,753
Porto Alegre
@trizex Thanks for your reply. :)

@darkobas: which kernel did you test with? Did you test with your EAS kernel?

I did a quick grep over the source and the only occurrences of "ttyHSL" I found where in:
  • Documentation/devicetree/bindings/tty/serial/msm_serial.txt
  • drivers/tty/serial/msm_serial_hs_lite.c

I've checked the config in "arch/arm64/configs/zl1_defconfig" and it seems that CONFIG_SERIAL_MSM_HSL is not enabled.
Could you try again with this config enabled?

P.S.: I didn't build the kernel or ROM myself until now. Is it possible that you could provide me a local manifest to work with? :)

Legacy HSL needs to be enabled not only for IR but for other OEM components.

The stock Kernel has introduced SERIAL_MSM_HSL_DYNAMIC_CONSOLE for that purpose.

Code:
config SERIAL_MSM_HSL
	tristate "MSM UART High Speed: Legacy mode Serial Driver"
	depends on (ARM || ARM64) && ARCH_MSM
	select SERIAL_CORE
	default n
	help
	  Select this module to enable MSM high speed UART driver in
	  legacy mode.

config SERIAL_MSM_HSL_CONSOLE
	bool "MSM High speed serial legacy mode console support"
	depends on SERIAL_MSM_HSL=y
	select SERIAL_CORE_CONSOLE
	select SERIAL_EARLYCON
	default n

config SERIAL_MSM_HSL_DYNAMIC_CONSOLE
	bool "Dynamic command line support for the HSL console"
	depends on SERIAL_MSM_HSL_CONSOLE
	default n

To build the Kernel only, just use the minimal repo, I updated it to 7.1.2: https://github.com/GalaticStryder/omniscience
 
Last edited:

darkobas

Senior Member
Jan 11, 2011
4,762
9,223
plus.google.com
@trizex Thanks for your reply. :)

@darkobas: which kernel did you test with? Did you test with your EAS kernel?

I did a quick grep over the source and the only occurrences of "ttyHSL" I found were in:
  • Documentation/devicetree/bindings/tty/serial/msm_serial.txt
  • drivers/tty/serial/msm_serial_hs_lite.c

I've checked the config in "arch/arm64/configs/zl1_defconfig" and it seems that CONFIG_SERIAL_MSM_HSL is not enabled.
Could you try again with this config enabled?

P.S.: I didn't build the kernel or ROM myself until now. Is it possible that you could provide me a local manifest to work with? :)
Yeah i have enabled hsl. just chmoding it didnt help.
also quickset doesnt seem to try enable the ir.... ill continue 2morrow.

Sent from my LEX720 using Tapatalk
 
  • Like
Reactions: CaptainHook8

darkobas

Senior Member
Jan 11, 2011
4,762
9,223
plus.google.com

ok startup is almost identical for me
it fails though
05-09 18:33:51.424 10652 10652 D MainControlActivity: Send IRFunction --0
05-09 18:33:51.432 10652 10790 E IRActionManager: -- Send IR: Id = 0
05-09 18:33:51.434 7276 7288 I UEI.SmartControl.LeTV: ------ IControl API: 1
05-09 18:33:51.434 7276 7288 I UEI.SmartControl.LeTV: Control.sendIR. 64028
05-09 18:33:51.434 7276 7288 E UEI.SmartControl.LeTV: Function is not found: 0
05-09 18:33:51.434 7276 7288 I UEI.SmartControl.LeTV: Control.sendIR: 2
05-09 18:33:51.435 10652 10790 E IRActionManager: Result = 2 ŔžúÚçŐ: Not found
05-09 18:33:51.501 10652 10652 D TVPanelFragment: panel--action:up
05-09 18:33:51.507 10652 10790 E IRActionManager: -- testStopIrFunction
05-09 18:33:51.508 7276 7300 I UEI.SmartControl.LeTV: ------ IControl API: 4
05-09 18:33:51.508 7276 7300 I UEI.SmartControl.LeTV: Control.stopIR.
05-09 18:33:51.508 7276 7300 I UEI.SmartControl.LeTV: stopIR...
05-09 18:33:51.508 7276 7300 I UEI.SmartControl.LeTV: stopIR done
05-09 18:33:51.508 7276 7300 I UEI.SmartControl.LeTV: Control.stopIR: 1
05-09 18:33:51.509 10652 10790 E IRActionManager: Result = 1 ŔžúÚçŐ: Error
 

androcheck

Senior Member
Dec 7, 2009
236
413
john.zweng.at
Regarding your logcat: I'm not totally sure, but it looks for me like this means the client (IR remote app) tries to use a deviceId/functionId combination (64028/0), which the QuickSet SDK doesn't know of. Are you testing with the original LeEco Remote app / QuickSet SDK service combination or are you using a different app or quickset sdk?

I'm also not sure yet where the configuration for QuickSet (remote devices and functions) actually is coming from (where it's loaded from). Maybe your versions are totally fine, but somehow the configuration is messed up (it's really hard to tell, the code is obfuscated and hard to follow).

And regarding this:
also quickset doesnt seem to try enable the ir....
The write to "/sys/remote/enable" is done by the LeEco Remote app (package: com.letv.android.remotecontrol) not the QuickSet SDK. On the stock ROM this file had a special SELinux type assigned (sysfs_ir_enable) and it was taken care of that the LeEco remote app was allowed to write it:
Code:
u:object_r:sysfs_ir_enable:s0
 

darkobas

Senior Member
Jan 11, 2011
4,762
9,223
plus.google.com
Regarding your logcat: I'm not totally sure, but it looks for me like this means the client (IR remote app) tries to use a deviceId/functionId combination (64028/0), which the QuickSet SDK doesn't know of. Are you testing with the original LeEco Remote app / QuickSet SDK service combination or are you using a different app or quickset sdk?

I'm also not sure yet where the configuration for QuickSet (remote devices and functions) actually is coming from (where it's loaded from). Maybe your versions are totally fine, but somehow the configuration is messed up (it's really hard to tell, the code is obfuscated and hard to follow).

And regarding this:

The write to "/sys/remote/enable" is done by the LeEco Remote app (package: com.letv.android.remotecontrol) not the QuickSet SDK. On the stock ROM this file had a special SELinux type assigned (sysfs_ir_enable) and it was taken care of that the LeEco remote app was allowed to write it:
Code:
u:object_r:sysfs_ir_enable:s0
Yeah original.

Ill try change the context name for remote/enable

Sent from my LEX720 using Tapatalk
 
  • Like
Reactions: CaptainHook8

Top Liked Posts

  • There are no posts matching your filters.
  • 16
    So, I was also interested why 3rd party infrared apps are not working on the LePro 3, and did some debugging. This thread somehow documents my findings step by step...

    Edit - Dec 1, 2016:
    As the postings below got a little bit technical, I'll try to give a short overview and some background infos about the situation with Infrared apps on the LePro 3 (and others, like some LG or Honor phones)

    Situation with LePro 3 Stock ROM (EUI):
    • Since Kitkat, the official Android API has included functions for controlling Infrared emitting devices (IR blaster). (see ConsumerIrManager in Android API Doc)
    • The LePro 3 (at least in Version 5.8.018S) includes this official API, so all standard Infrared apps from Play Store seem to install and work fine on a first look (the apps don't complain and don't crash)
    • But actually the infrared HAL (HAL=hardware abstraction layer) implementation which is responsible to actually DO the stuff on hardware seems to be a dummy implementation: It takes the command (e.g. transmit IR pattern XXXYYZZZYY), and then simply does nothing. So the Infrared apps think everything is working fine, but in reality the IR blaster is not sending anything. (You can easily check with a second phone if the IR blaster is working by looking with the camera of the second phone on the IR blaster, as most cameras can see Infrared light.)
    • The included system app "Remote Control" from LeEco works fine, so it must use other mechanisms to control the IR hardware.

    Background:
    • Official Android API has support for only sending Infrared patterns over an Infrared emitting device (IR led). No receiving supported.
    • An Infrared app has to give the raw pattern it wants to send, and the IR emitter simply sends this raw led on/led off pattern (see the method transmit(..)) . Such a pattern could look like: "use carrier frequency 38 kHz; then turn the LED on for 169ms, turn it off for 168ms, turn on for 21ms, turn off for 263ms, etc.... So it's really a low-level way to tell the IR blaster what to do. That is the official Android API way to send Infrared. (See also this short YouTube video for more details on how infrared remotes are working in general: How It Works - Infrared Remote Control.)
    • On the other side the hardware included in LePro 3 supports both: sending and receiving of infrared. So it can "learn" infrared patterns from other remote controls (something what the official Android API doesn't support at the moment).
    • Also the hardware is not just a "dumb" infrared LED, but instead they included a fully independent System-on-chip from a company named "Universal Electronics" (UEI). They seem to be specialized on making infrared remote controllers and also sell physical universal remote controls.
    • So, LeEco (and LG and others) decided to not just put a simple infrared LED into their devices, but instead include an advanced product from a company which has more experience on the field of infrared remotes (Universal Electronics).
    • Or in other words: Imagine Le Eco crammed one of these universal remote controls, which Universal Electronics is selling, into your phone and the included app doesn't send directly infrared, but instead just presses the buttons on this built-in universal remote control.

    How is the Universal Electronics chip working?
    • As you may imagine a full blown universal remote control in hardware is more complex than a simple LED. In fact the infrared chip (on the LePro 3 it seems to be the MAXQ616) is a separate system-on-chip, running its own firmware on a 12 MHz processor with its own 80KB flash memory and its own RAM (2KB) which communicates over a serial line with the Snapdragon main system where Android is running (using the serial device /dev/ttyHSL1 with a baudrate of 230400). (According to the short spec-sheet it seems to support other protocols for communication as well, but at least in the Le Pro 3 it is wired to the Snapdragon over a serial line.)
    • Power-on/power-off: The LeEco kernel source contains a small driver (ir_maxq616.c) which provides a sys-file (/sys/remote/enable). This driver only seems to set a GPIO pin if a 1 or a 0 is written into this sys-file. I guess this GPIO pin is used as kind of a "power-switch" for the MAXQ616 chip (or maybe to trigger some kind of power-save mode). This file is protected by SELinux policies (so not all apps are allowed to toggle this "switch"). If a 0 is written into this sys-file the IR blaster no longer emits IR.
    • The commands sent between the infrared chip system and Android kernel seem to be more high-level than the IR patterns which are used in the official Android Infrared API (which are just simple LED-on/LED-off patterns as described above). Probably this will make it much harder to implement a HAL for the standard Android API.
    • To make it easier for manufacturers like LeEco and LG to include this sophisticated infrared devices into their phones, Universal Electronics provides an SDK (software development kit) which is called QuickSet SDK (btw, when you search for it on XDA you see that a also some other phones are using this SDK).
    • This SDK is running as a bound service (on the LePro 3 it'c called "UEI Android Services SDK(LeTV)") and offers high level APIs for app developers which can build infrared apps. This was used to build the pre-installed infrared remote app. The SDK converts the commands of the app to low-level serial signals which are sent to the infrared chip, which then performs the actions.
    • LeEco did some customizations to this SDK package (e.g. changed the packagename to "com.uei.quicksetsdk.letv"). So we cannot assume this a generic package also to be found on other OEM's phones.
    • The high-level protocol between the Android App and the QuickSet SDK looks something like: "start sending Samsung TV power button signal", "stop sending infrared". QuickSet SDK and the Infrared chip understand this high level commands and decide on their own which pattern and frequencies need to be used to send a "power button" signal for samsung TVs.
    • So not the app is in control what is actually sent over infrared, but instead the QuickSet SDK (or the infrared chip-system)
    • This is a totally different approach than what we have in the official Android Infrared API. So now I can imagine a little bit better, why LeEco/LG/Universal Electronics decided not to support the official API (but it's still unclear for me why they included the dummy implementation - maybe by mistake?).
    • On the other hand the Android API is much less complex, and allows much more freedom in what to send over IR (just give it a pattern and the hardware emits it).

    What are possible future steps?
    1. On EUI: We could try live with the original remote application (but the LeEco remote control app is very bloated and claims a lot of permissions not related to infrared - see this posting here).
    2. On EUI: We could try to port preinstalled remote applications from other phones which also are built with QickSet SDK (for example LG's QuickRemote app), but this might be difficult if the other phone used a different version of QuickSet SDK.
    3. On cyanogenmod or AOSP: Out of the box the standard infrared API will not work (as described above) but we could try to port QuickSet SDK and the LeEco remote app to cyanogenmod (this is the way other devs did it on LG phones). But the LeEco Remote control app seems to have some dependencies to other LeEco services, so this might be difficult.
    4. On all ROMs: If it is possible to reverse the protocol which QuickSet SDK and the infrared chip-system are using then we might be able to implement the standard Android infrared API (writing our own consumer_ir.c HAL which does the same as the QuickSet SDK). But this would also mean, that we degrade this high-level full-blown general remote control system to a dumb simple IR emitter. Also receiving of IR (learning mode) would not work, as standard Android has no API for this. This approach is much more difficult than the others and maybe might never be possible at all.
    5. Update, Dec 2, 2016: On EUI: There is another option: infrared apps could try to use the QuickSet SDK directly, like the LeEco remote control app does. This seems to work in principle (every app can bind the QuickSet SDK service without special permissions) but has some disadvantages:
      • I don't know if the API is somewhere publicly available. I don't see any docs online, maybe an account is needed at developer.quicksetcloud.com. I didn't try this.
      • At least LeEco did some customizations on the QuickSet service on the LePro 3 (changing the package name), so this solution is very targeted for specific devices and not generic
      • There is still the "master switch" (the kernel sys-file: /sys/remote/enable) which is used to turn on or off the MAXQ616 infrared controller. On the EUI stock kernel this file is protected be SELinux (context u:eek:bject_r:sysfs_ir_enable:s0), so other apps would need root to enable the IR chip at first
      Nevertheless I tried this in a proof-of-concept app (using root for enabling the master-switch) and it seems to work in principle. See this posting for details.
    6. 2nd Update - SUCCESS!!, Dec 2, 2016: On EUI: And I found another, more generic solution! :D Instead of binding the QuickSet SDK directly from an app (which would need customizations for every IR app), I wrote an Xposed module which does the same but within the standard Android ConsumerIrService (which provides the default Android IR API). So the standard Android API receives IR patterns from apps and simply forwards them to the QuickSet SDK API. (This only is possible because the QuickSet SDK - besides all of its high-level API methods - fortunately also contains a single very important low-level API method which allows sending of raw IR patterns: transmit(int carrierFrequency, int[] pattern)). So this Xposed module can act as a simple "bridge" between the 2 APIs. I've published this Xposed module in the XPosed repo, see this thread for details: [MOD][Xposed] Make Infrared Blaster working with all 3rd party apps (on EUI)


    ---------------------------------------------------------------------------
    ---------------------------------------------------------------------------
    ---------------------------------------------------------------------------
    Original posting below:

    As other IR apps seem to work (i.e. they don't crash or throw Exceptions) it seems that the basic Infrared services are installed on the system. And indeed the ConsumerIrService class is available. This system service provides the API that user-installed apps can use to send IR commands (that's what all the standard Infrared apps from playstore are doing).

    This (Java) class uses a native implementation (i.e. written in C or C++) to perform the actual commands. In Android hardware stuff gets abstracted using so-called HALs (=hardware abstraction layer). So when the ConsumerIrService class gets instantiated it calls the native method halOpen() which is implemented here in com_android_server_ConsumerIrService.cpp.

    This C++ function uses hw_get_module to load the consumerir HAL (hardware abstraction layer) implementation. In the first logcat I made on my LEX720 after buying I found the error message from this very method:
    Code:
    E/ConsumerIrService(10728): Can't open consumer IR HW Module, error: -2
    -2 means ENOENT in C, which stands for "file not found".

    Since updating to EUI 5.8.018S this error does not appear anymore, which means the loading of the HAL now is working just fine. And indeed, (after finding out how hw_get_module is locating the modules) I could verify that the HAL implementation file exists on the system and gets loaded without problems. You can find it here: /system/lib64/hw/consumerir.default.so

    So what is the implementation in consumerir.default.so actually doing?

    When using a 3rd party app and trying to send IR commands, you will find in the logcat messages like this:
    Code:
     D/ConsumerIrHal( 3445): transmit for 2272 uS at 37647 Hz
    This log messages looks exactly like log message from the Android Open Source example implementation of the consumer IR HAL in the file consumerir.c in line 46. If we look in the same C module at the end, where the HAL module info is declared, you will see the strings:
    Code:
    consumerir_module_t HAL_MODULE_INFO_SYM = {
        .common = {
            .tag                = HARDWARE_MODULE_TAG,
            .module_api_version = CONSUMERIR_MODULE_API_VERSION_1_0,
            .hal_api_version    = HARDWARE_HAL_API_VERSION,
            .id                 = CONSUMERIR_HARDWARE_MODULE_ID,
            .name               = "Demo IR HAL",
            .author             = "The Android Open Source Project",
            .methods            = &consumerir_module_methods,
        },
    };
    You can find this here at the end of the file.

    I did a quick "strings" (this command just displays readable text parts contained in binary files) on the LEX720 device on the /system/lib64/hw/consumerir.default.so file and indeed I found the same strings in there:
    Code:
    # strings /system/lib64/hw/consumerir.default.so
    ...
    Demo IR HAL
    The Android Open Source Project
    ...
    This is not a proof but might be a strong indication that this is the same file as the one from the Android Open Source project (especially as it also contains the string "Demo IR HAL").

    Ok, how is the AOSP implementation actually sending IR codes?
    It turns out, it doesn't at all. It's just meant as a tamplate for OEM manufacturers to include their own hardware-specific implementation. If you look at the relevant function "consumerir_transmit" you see that it's just simulating and does nothing else but sleeping:
    Code:
     static int consumerir_transmit(struct consumerir_device *dev __unused,
       int carrier_freq, const int pattern[], int pattern_len)
    {
        int total_time = 0;
        long i;
        for (i = 0; i < pattern_len; i++)
            total_time += pattern[i];
        /* simulate the time spent transmitting by sleeping */
        ALOGD("transmit for %d uS at %d Hz", total_time, carrier_freq);
        usleep(total_time);  //  <<------- IT IS JUST SLEEPING, DOING NOTHING!
        return 0;
    }

    Ok. So it seems the reason why we the official android Infrared API is not working, is because the actual implementation in "consumerir.c" is missing.
    While the LePro does include a consumerir HAL implementation, it is just a dummy, it does nothing on the hardware.


    Ok, so how is then the LeEco Remote Control (package "com.letv.android.remotecontrol" in /system/app/LetvRemoteControl_preinstall/) doing it?

    As far as I could see, the Java part of the application is communicating with a service ("com.uei.control.Service") which seems to perform the actual sending of infrared commands. Unfortunately this seems to be implemented native (in C code) so I have no idea how to find out what it's doing.

    I can see that in the Intent which binds the service two parameters (using "putExtra()") are given, which sound very interesting:
    • intent.putExtra("Port", this.platformParams.getSerialName()); // which is /dev/ttyHSL1 at this point
    • intent.putExtra("Baudrate", this.platformParams.getSerialPort()); // which is 230400 at this point
    Also before binding the service, the application writes a "1" into the sys-file:
    /sys/remote/enable (which is world writable, permissions: 0666 - UPDATE: not world-writable, protected by SELinux: -rw-rw-rw- u:eek:bject_r:sysfs_ir_enable:s0 /sys/remote/enable)
    (Btw, this sys file is provided by the driver file "kernel/drivers/misc/ir_maxq616.c" in the kernel source and just seems to set a specific GPIO pin to 0 or 1. So I guess this GPIO PIN is wired to the IR chip to turn it on and off).


    Summary:
    • LeEco Remote uses own proprietary and unknown C implementation (only logs the command and sleeps)
    • The Android ConsumerIR HAL is installed, but is just a dummy implementation
    • The physical infrared device seems to be a serial device, accessible under /dev/ttyHSL1 (also world-writable)
    • Baudrate seems to be 230400
    • Infrared chip needs to be enabled by: echo 1 > /sys/remote/enable (needs to be allowed by SE policy or maybe as root)

    So I see this options here:
    1. Some of the infrared apps in PlayStore directly use the serial device file (apps must be modified)
    2. Somebody is able to implement the "Consumer IR HAL" driver so that it really sends the the actual command over the serial device (i.e. compile a new "consumerir.default.so" file and replace it in the /system/lib64/hw/ directory with a root file explorer or maybe using a magisk module). This way all standard infrared apps should work without modification.

    Unfortunately my own knowledge about serial device communication as well as Infrared transmitter devices is not existing.. Also my latest experiences in C are from several years ago.

    But maybe the findings in this posting might help somebody else to implement this (app developers as well as platform developers).
    So if you know somebody, feel free to spread the link to this thread.

    John :)
    6
    got the stock app to work on omni! (with sepolicy enforcing ofcourse)
    5
    It was less work than expected. Now it seems to work for me perfectly. I cleaned up the code, published it on Github and made a new thread for the Xposed module (I think this thread should stay more focused on the technical backgrounds while the new thread will be dedicated to the Xposed module).

    Head over here:
    [MOD][Xposed] Make Infrared Blaster working with all 3rd party apps :)
    5
    Ok, I found another possible way to use the Infrared blaster (for sending):
    Instead of directly communicating over the serial line, I tried to bind to the QuickSet SDK service from within my own test-app. As the QuickSet SDK service is not protected with a permission this should be possible and indeed, binding the service worked flawlessly.

    Unfortunately I forgot that there is still the "masterswitch" to turn on or off the MAXQ616 IR controller chip.
    This is done by writing a "1" or a "0" into the file /sys/remote/enable which normally is done by the LeEco remote app:
    Code:
    # power on IR controller:
    echo 1 > /sys/remote/enable
    
    # power-off IR controller:
    echo 0 > /sys/remote/enable

    This file is provided by the "ir_maxq616" driver in the kernel and just sets a GPIO to 1 or 0 (which I guess is connected to the IR controller chip to power it down or a least go to a power-save mode):
    Code:
    // snippet from: kernel/drivers/misc/ir_maxq616.c
    
    	if (enable == 0) {
    		if (irdata->power_on) {
    			gpio_set_value(irdata->en_gpio, 0);
    			irdata->power_on = 0;
    		}
    	} else {
    		if (irdata->power_on == 0) {
    			gpio_set_value(irdata->en_gpio, 1);
    			msleep(1500);
    			irdata->power_on = 1;
    		}
    	}

    The SELinux policy only allows the original LeEco remote app to write into this kernel sys-file. So if we want to write this file from other apps (for turning the IR chip on), unfortunately we will need to be root (or globally set SE policy to "permissive").

    Nevertheless, taking all this into account I made a small test-app, and voila, I was able to trabsmit my own custom IR pattern from my own test app. :)
    I guess, that's a first step in the right direction. :D

    Here is a short video demonstrating that the IR blaster really is emitting infrared signals: Short demo video

    (I published my proof-of-concept app on Github as reference for interested developers: https://github.com/johnzweng/QuickSetSDKProofOfConcept)
    4
    First breakthrough:
    I've created a (still very, very alpha) Xposed module which hooks the ConsumerIrService class and tries to bind the QuickSet SDK service to send the Infrared commands which it has received over the standard Android Infrared API using the QuickSet SDK API (so it acts like a bridge between the two APIs).

    And it works!! :victory: (in principle)
    There are still a lot of edges, but if want to try it out yourself, I've attached an alpha-version of the Xposed module to this posting so you could try yourself with your favorite remote control app.

    It does NOT YET WORK OUT OF THE BOX! You have to follow these steps before it will work:
    1. Install the Xposed module, enable it in Xposed app, reboot
    2. After reboot, open the original LeEco remote app one time and press some buttons (we still need this step here, to turn on the IR blaster. The LeEco remote app just does this here: "echo 1 > /sys/remote/enable"). You could also do this yourself in a terminal (as root). Should only be necessary once after every reboot.
    3. Then open the system settings -> go to "Apps" -> search for "UEI Android Services SDK(LeTV)" -> click "Force Stop" (I am still not sure why this step is necessary, somehow the SDK service needs to be restarted once after every reboot..)
    4. Open any app which uses standard Infrared API and SUCESSS! :) Check with a digital camera (or another phone's camera) if the IR blaster really is emitting infrared.
    If I find some time over the weekend, I will try to get these things fixed.

    Here a short demonstration video.


    As you can see in the video I tested this with three different apps and it worked with my Samsung TV. I just randomly chose these apps from Play Store: ZaZa Remote-Universal Remote, ASmart Remote IR and IR Universal Remote

    Also, I have just tested this only on EUI 5.8.018S (WAXCNFN5801811012S)!
    So if you are running a different (newer) version of EUI, please give feedback if it's working or not! Thanks! :good:

    [edit]removed attachement, as there is now a working 1.0 version[/edit]