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

Search This thread

androcheck

Senior Member
Dec 7, 2009
236
413
john.zweng.at
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 :)
 
Last edited:

androcheck

Senior Member
Dec 7, 2009
236
413
john.zweng.at
Update: Forget my proposed option 1:
The device /dev/ttyHSL1 can not be accessed by everybody as access is protected by SELinux policy.
Also the file /sys/remote/enable simply is not visible if I navigate into the directory as non-root user.
 
  • Like
Reactions: umOuch

umOuch

Member
Apr 26, 2012
32
2
Athens
I'm not a mobile phone dev. That said, THABK YOU for this thread and the efforts. I will be a very happy man when this issue is figured out. ???
 

androcheck

Senior Member
Dec 7, 2009
236
413
john.zweng.at
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.
 

Joms_US

Senior Member
Mar 25, 2016
485
142
Tremendous effort my friend but I am just wondering why can't you use LeEco's default IR app? You can add a predefined remote controls (like thousand brands?) and define your own. I created mine that will control my cable box, Samsung TV and Sound bar all in one remote control.
 

umOuch

Member
Apr 26, 2012
32
2
Athens
Tremendous effort my friend but I am just wondering why can't you use LeEco's default IR app? You can add a predefined remote controls (like thousand brands?) and define your own. I created mine that will control my cable box, Samsung TV and Sound bar all in one remote control.

1) it doesn't have all of my devices.

2) the interface is clunky

3) features not as rich as Anymote, for example.

4) i, for example, am using it to control a minimal amount of my stuff... But would rather be using one of my third party apps.

That's just some reasons I think it's a worthwhile venture.
 

androcheck

Senior Member
Dec 7, 2009
236
413
john.zweng.at
Tremendous effort my friend but I am just wondering why can't you use LeEco's default IR app? You can add a predefined remote controls (like thousand brands?) and define your own. I created mine that will control my cable box, Samsung TV and Sound bar all in one remote control.

Hi @Joms_US, thank you for leaving your feedback. Maybe you should try to see this more from a developer's perspective: Yes, of course I can (and I already do) use the default IR app. But I will try to point out some reasons why somebody still might want to work on getting the official Android API working:
  • programmability: of course, the original Remote App can do a lot, but there might be other usages for an infrared emitter besides remote controlling media devices. As a developer you have the freedom to do whatever you want with the capabilities of your hardware by writing your own application. In my personal opinion this is the main feature which makes today's mobile platforms so powerful: external developers might bring new features (in form of apps) to your device which the original manufacturer never might have even thought of. But without an API you cannot do this.
  • standard APIs: Since API level 19 (Android 4.4 - Kitkat) the official Android API includes the ConsumerIrManager class, which offers a generic way to transmit infrared patterns over an infrared emitter. Interestingly LeEco fully included the ConsumerIrManager API into EUI (so apps can use it), but their implementation simply does nothing (it's just a dummy). That's an interesting choice. They could have just ommited this API at all, but they didn't. On the other hand this might make it easier to implement the missing features (and is one more reason to try it).
  • building ground for other developers: like with all open development projects, if a single programmer finds a solution to a problem others might build on this knowledge. In this concrete case: if someone finds out how the infrared hardware can be controlled others can use this, for example to make the IR blaster also work in other ROMs, like cyanogenmod.
  • curiosity: finally, as a developer I'm just curious how things are working, and often it's a lot of fun to find out. Also besides that you gain a lot of knowledge for free on the way by doing so. :)

Don't forget, if people would have never been curious and started playing around we wouldn't have great projects like cyanogenmod or even Linux (and as a result also no Android).
And where would be the best place to discuss development, if not on xda developers. ;)
 
Last edited:

androcheck

Senior Member
Dec 7, 2009
236
413
john.zweng.at
Update:
I haven't done much over the weekend, but here is what I know until now:

  • The LePro 3 doesn't simply contain a "dumb" infrared LED, but instead a fully programmable microcontroller (i.e. a separate small computer) with 80KB flash memory, 2KB SRAM, running its own firmware, etc. which provides the IR functionality (emitting and receiving): MAXQ616 - Infrared Remote Control System-on-Chip
  • The original LeEco IR App is binding the Service: "com.uei.control.Service" (using the action strings: "com.uei.control.ISetup" and "com.uei.control.IControl")
  • This service is provided by the package "com.uei.quicksetsdk.letv" (/system/app/UEIQuicksetSDKLeTV/UEIQuicksetSDKLeTV.apk)
  • This package is proguard obfuscated, but it looks like all the relevant infrared sending is done by the classes in the package: com.uei.driver
  • The service contains a Logging class which is called from everywhere but apparently logging is disabled in the release build
  • As an easy workaround I used Xposed to hook the log methods (they are easy to identify) and log all logging output into Xposed log (see log output below)
  • both, receiving and transmitting IR (and a lot more) is done by communicating with the serial device /dev/ttyHSL1 with a baudrate of 230400
  • For serial communication the native "libserial_port.so" library is used (and is included in 2 versions in the "asset" folder: arm64-v8a and armeabi-v7a)
  • There is a second native library in use: "libqs_jni.so", which I don't know yet what it's used for (see list of provided JNI methods below)

Part of the log (all the typos are like this in the code):
Code:
11-28 19:40:01.828 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Quickset Services start...
11-28 19:40:01.829 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Manufacture = LeMobile
11-28 19:40:01.832 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Id = LeTV
11-28 19:40:01.832 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Extracting JNI libs...
11-28 19:40:01.832 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> --- java.library.path =/vendor/lib64:/system/lib64
11-28 19:40:01.899 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> --- Build.SUPPORTED_ABIS:->arm64-v8a<-
11-28 19:40:01.913 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ------ Quikcset getAppLaunchState: Activated=true
11-28 19:40:01.913 I/Xposed  (30574): Registered=false
11-28 19:40:01.913 I/Xposed  (30574): Region=8
11-28 19:40:01.913 I/Xposed  (30574): Port=/dev/ttyHSL1
11-28 19:40:01.913 I/Xposed  (30574): Baudrate=230400
11-28 19:40:01.913 I/Xposed  (30574): ACEXP=0
11-28 19:40:01.914 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ------- SETTIGN ITEM: Activated=true
11-28 19:40:01.914 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ------- SETTIGN ITEM: Activated
11-28 19:40:01.914 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ------- SETTIGN ITEM: Registered=false
11-28 19:40:01.914 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ------- SETTIGN ITEM: Registered
11-28 19:40:01.914 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ------- SETTIGN ITEM: Region=8
11-28 19:40:01.914 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ------- SETTIGN ITEM: Region
11-28 19:40:01.914 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Quikcset region code =  8
11-28 19:40:01.914 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ------- SETTIGN ITEM: Port=/dev/ttyHSL1
11-28 19:40:01.914 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ------- SETTIGN ITEM: Port
11-28 19:40:01.914 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ---- UART Port read from Settings: /dev/ttyHSL1
11-28 19:40:01.914 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ------- SETTIGN ITEM: Baudrate=230400
11-28 19:40:01.914 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ------- SETTIGN ITEM: Baudrate
11-28 19:40:01.914 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ---- UART baud rate read from Settings: 230400
11-28 19:40:01.914 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ------- SETTIGN ITEM: ACEXP=0
11-28 19:40:01.914 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ------- SETTIGN ITEM: ACEXP
11-28 19:40:01.915 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ----SETTING  Is MAXQ616: true = 0
11-28 19:40:01.915 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> ++++++ pv = D397374D-314B-4405-9689-C6C30E81A922
11-28 19:40:01.915 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> ++++++ pb = 39A68E11-5927-49F0-A155-C2644D73EC90
11-28 19:40:01.915 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> QS Service created
11-28 19:40:01.917 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> AirCon Key: Mode#EC.FN.MD
11-28 19:40:01.917 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Intron - Label: 1 = Mode - EC.FN.MD
11-28 19:40:01.917 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> AirCon Key: Temperature Up#EC.FN.TP.+
11-28 19:40:01.917 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Intron - Label: 2 = Temperature Up - EC.FN.TP.+
11-28 19:40:01.917 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> AirCon Key: Temperature Down#EC.FN.TP.-
11-28 19:40:01.917 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Intron - Label: 3 = Temperature Down - EC.FN.TP.-
....
....
11-28 19:40:01.919 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Service initServices...
11-28 19:40:01.920 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> QS start get config
11-28 19:40:01.926 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ---- DB Folder: /data/user/0/com.uei.quicksetsdk.letv/app_DB
11-28 19:40:01.926 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Config data =  dbroot:=/data/user/0/com.uei.quicksetsdk.letv/app_DB
11-28 19:40:01.926 I/Xposed  (30574): oemid:=LeTV
11-28 19:40:01.926 I/Xposed  (30574): language:=En
11-28 19:40:01.926 I/Xposed  (30574): region:=8
11-28 19:40:01.926 I/Xposed  (30574): userid:=
11-28 19:40:01.926 I/Xposed  (30574): dual_mode:=0
11-28 19:40:01.926 I/Xposed  (30574): auto_lookup:=0
11-28 19:40:01.926 I/Xposed  (30574): wsurl:=""
11-28 19:40:01.926 I/Xposed  (30574): cacert:=""
11-28 19:40:01.926 I/Xposed  (30574): devmap:={"TV":"T","Cable,IPTV":"C","Video Accessory":"N","Satellite/DSS":"S","VCR":"V","DVD":"Y","Receiver, Misc Audio":"R,M","Amplifier":"A","CD":"D","Home Control":"H"}
11-28 19:40:01.927 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> DB File: dac1a
11-28 19:40:01.927 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> DB File: dac2
11-28 19:40:01.927 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> DB File: dac8
11-28 19:40:01.927 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> DB File: dac9a
11-28 19:40:01.927 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> DB File: translation.txt
11-28 19:40:01.927 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> #### Remove old DB files... 
11-28 19:40:01.927 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> deleting : dac1a
11-28 19:40:01.928 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> deleting : dac2
11-28 19:40:01.928 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> deleting : dac8
11-28 19:40:01.928 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> deleting : dac9a
11-28 19:40:01.929 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> #### Unzip DB Files...
11-28 19:40:02.092 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> #### Unzip DB Files: /data/user/0/com.uei.quicksetsdk.letv/app_DB/dac1a
11-28 19:40:02.167 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> #### Unzip DB Files: /data/user/0/com.uei.quicksetsdk.letv/app_DB/dac2
11-28 19:40:02.190 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> #### Unzip DB Files: /data/user/0/com.uei.quicksetsdk.letv/app_DB/dac8
11-28 19:40:02.191 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> #### Unzip DB Files: /data/user/0/com.uei.quicksetsdk.letv/app_DB/dac9a
11-28 19:40:02.191 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> #### Unzip DB Files: /data/user/0/com.uei.quicksetsdk.letv/app_DB/translation.txt
11-28 19:40:02.192 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> #### Unzip DB Files DONE
11-28 19:40:02.193 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Supports setup maps: true
11-28 19:40:02.194 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> QS start statue = true Error code = 0
11-28 19:40:02.194 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> QS version = v2.7.7.1_RC1
11-28 19:40:02.194 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> DB version = APAC_LeTV_Mobile_2015_i-Three_database_v3.0_letv
11-28 19:40:02.194 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> ### init IR Blaster...
11-28 19:40:02.194 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  ---- Is MAXQ616: true
11-28 19:40:02.195 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> open serial port: /dev/ttyHSL1 - 230400
11-28 19:40:02.197 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> UEIBLaster setting for 616
11-28 19:40:02.197 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Setting serial record hearder size = 2
11-28 19:40:02.197 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> configuring settings for MAXQ616
11-28 19:40:02.197 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Get version...
11-28 19:40:02.197 I/Xposed  (30574): DEBUG_INFRARED:  LOGJZ serialWrite byte[] >> 00
11-28 19:40:02.197 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Serial write: 1
11-28 19:40:02.197 I/Xposed  (30574): DEBUG_INFRARED:  LOGJZ serialWrite result >> true
11-28 19:40:02.207 I/Xposed  (30574): DEBUG_INFRARED:  LOGJZ serialWrite byte[] >> 4041424300010B
11-28 19:40:02.207 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Serial write: 7
11-28 19:40:02.208 I/Xposed  (30574): DEBUG_INFRARED:  LOGJZ serialWrite result >> true
11-28 19:40:02.208 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> waitForReply check queue size:  0
11-28 19:40:02.213 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> serial port data available: 21 - 1
11-28 19:40:02.213 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  Blaster return status: 0
11-28 19:40:02.238 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  +++ Serial ailve
11-28 19:40:02.239 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  Blaster return status: 0
11-28 19:40:02.239 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> version : 00 13 00 32 35 36 37 30 32 32 35 36 37 30 34 33 30 30 30 30 32 
11-28 19:40:02.239 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  +++ Serial alive thread START
11-28 19:40:02.239 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> i-One Blaster versions: Library:256702 Software:256704 Bootloader:300002
11-28 19:40:02.239 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> IR Blaster version: 256702256704300002
11-28 19:40:02.239 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> QS saving settings...
11-28 19:40:02.240 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> IR Blaster version: 256702256704300002
11-28 19:40:02.240 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> listAllUpgradeCodes start 
11-28 19:40:02.240 I/Xposed  (30574): DEBUG_INFRARED:  LOGJZ serialWrite byte[] >> 00
11-28 19:40:02.240 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Serial write: 1
11-28 19:40:02.240 I/Xposed  (30574): DEBUG_INFRARED:  LOGJZ serialWrite result >> true
11-28 19:40:02.250 I/Xposed  (30574): DEBUG_INFRARED:  LOGJZ serialWrite byte[] >> 40414243000111
11-28 19:40:02.250 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Serial write: 7
11-28 19:40:02.250 I/Xposed  (30574): DEBUG_INFRARED:  LOGJZ serialWrite result >> true
11-28 19:40:02.250 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> waitForReply check queue size:  0
11-28 19:40:02.255 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> serial port data available: 10 - 1
11-28 19:40:02.256 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  Blaster return status: 0
11-28 19:40:02.281 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  Blaster return status: 0
11-28 19:40:02.281 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  Upgrade Code: 1029
11-28 19:40:02.281 I/Xposed  (30574): DEBUG_INFRARED:  LOG >>  Upgrade Code: 803
11-28 19:40:02.281 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> listAllUpgradeCodes received: 2
11-28 19:40:02.282 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> listAllUpgradeCodes done... 
11-28 19:40:02.283 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Device manager: loading config....
11-28 19:40:02.283 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> ----------- loading internal config...
11-28 19:40:02.283 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Services init done
11-28 19:40:02.284 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> QS Service init finished
11-28 19:40:02.285 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> QS Service version name: 1.0.008
11-28 19:40:02.285 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> QS Service version code: 8
11-28 19:40:02.285 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> QS SDK AIRCON version: v1
11-28 19:40:02.285 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Service requested: Setup
11-28 19:40:02.286 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> --- setting serial info...
11-28 19:40:02.286 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Setting serial port name: /dev/ttyHSL1
11-28 19:40:02.286 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Setting baud rate: 230400
11-28 19:40:02.286 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> Old Blaster settings: true - 230400 - /dev/ttyHSL1
11-28 19:40:02.286 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> New Blaster settings: true - 230400 - /dev/ttyHSL1
11-28 19:40:02.286 I/Xposed  (30574): DEBUG_INFRARED:  LOG >> QS saving settings...
....

Code:
JNI methods libqs_jni.so:
Java_com_uei_quickset_QSNativeLib_QSlogStart
Java_com_uei_quickset_QSNativeLib_QSstart
Java_com_uei_quickset_QSNativeLib_QSstop
Java_com_uei_quickset_QSNativeLib_QSonlineStart
Java_com_uei_quickset_QSNativeLib_QSgetRev
Java_com_uei_quickset_QSNativeLib_QSgetLocalDBVersionString
Java_com_uei_quickset_QSNativeLib_QSretrieveDeviceTypes
Java_com_uei_quickset_QSNativeLib_QSgetDeviceTypeName
Java_com_uei_quickset_QSNativeLib_QSretrieveBrands
Java_com_uei_quickset_QSNativeLib_QSretrieveBrandsArray
Java_com_uei_quickset_QSNativeLib_QSonlineRetrieveBrands
Java_com_uei_quickset_QSNativeLib_QSretrieveModels
Java_com_uei_quickset_QSNativeLib_QSonlineRetrieveModels
Java_com_uei_quickset_QSNativeLib_QSretrieveCodesets
Java_com_uei_quickset_QSNativeLib_QSonlineRetrieveCodesets
Java_com_uei_quickset_QSNativeLib_QSretrieveCodesetsByBrand
Java_com_uei_quickset_QSNativeLib_QSonlineRetrieveCodesetsByBrand
Java_com_uei_quickset_QSNativeLib_QSonlineGetLastErrorCode
Java_com_uei_quickset_QSNativeLib_QSonlineGetLastErrorName
Java_com_uei_quickset_QSNativeLib_QSgetCodesetName
Java_com_uei_quickset_QSNativeLib_QSgetBrandName
Java_com_uei_quickset_QSNativeLib_QSgetModelName
Java_com_uei_quickset_QSNativeLib_QSsendCodeset
Java_com_uei_quickset_QSNativeLib_QSgetBrandsTotal
Java_com_uei_quickset_QSNativeLib_QSgetModelsTotal
Java_com_uei_quickset_QSNativeLib_QSgetCodesetTotal
Java_com_uei_quickset_QSNativeLib_QS_fuzzy_threshold_set
Java_com_uei_quickset_QSNativeLib_QS_fuzzy_threshold_get
Java_com_uei_quickset_QSNativeLib_QSgetModelMode
Java_com_uei_quickset_QSNativeLib_QS_query_mode_get
Java_com_uei_quickset_QSNativeLib_QSqueryModeGet
Java_com_uei_quickset_QSNativeLib_QS_query_mode_reset
Java_com_uei_quickset_QSNativeLib_QS_get_model_fuzzy_value
Java_com_uei_quickset_QSNativeLib_utilsfn
Java_com_uei_quickset_QSNativeLib_QSstartStream
Java_com_uei_quickset_QSNativeLib_QSFuzzyThresholdSet
Java_com_uei_quickset_QSNativeLib_QSFuzzyThresholdGet
Java_com_uei_quickset_QSNativeLib_QSgetCodesetBinary
Java_com_uei_quickset_QSNativeLib_QSEDIDretrieveCodesets
Java_com_uei_quickset_QSNativeLib_QSCECretrieveCodesets
Java_com_uei_quickset_QSNativeLib_QSIPretrieveCodesets
Java_com_uei_quickset_QSNativeLib_QScecgetVendorID
Java_com_uei_quickset_QSNativeLib_QSInfoframeRetrieveCodesets
Java_com_uei_quickset_QSNativeLib_QSinfoframeGetManufacturerName
Java_com_uei_quickset_QSNativeLib_QSautoDiscoveryCodesetRegion
Java_com_uei_quickset_QSNativeLib_QSgetProvidersTotal
Java_com_uei_quickset_QSNativeLib_QSEDIDCECgetBrandName
Java_com_uei_quickset_QSNativeLib_QSgetLastError
Java_com_uei_quickset_QSNativeLib_QSgetLastErrorName
Java_com_uei_quickset_QSNativeLib_QSqueryModeReset
Java_com_uei_quickset_QSNativeLib_QSgetModelFuzzyValue
Java_com_uei_quickset_QSNativeLib_QSsendCodesetByName
Java_com_uei_quickset_QSNativeLib_QSonlineCancelRequest
Java_com_uei_quickset_QSNativeLib_QSreadSetupMapDataDirect
Java_com_uei_quickset_QSNativeLib_QSgetKeyMapZipIR
Java_com_uei_quickset_QSNativeLib_QSisCodesetExistZipIR
Java_com_uei_quickset_QSNativeLib_QSdeleteCodesetZipIR
Java_com_uei_quickset_QSNativeLib_QSlistCodesetsZipIR
Java_com_uei_quickset_QSNativeLib_QSsendCodesetZipIRB64
Java_com_uei_quickset_QSNativeLib_QSsendZipIRBytestream
Java_com_uei_quickset_QSNativeLib_QSgetZipIRFunc
Java_com_uei_quickset_QSNativeLib_QSsendCodesetZipIR
Java_com_uei_quickset_QSNativeLib_QSsendCodesetByNameZipIR
Java_com_uei_quickset_QSNativeLib_QSosmReportTestResult
Java_com_uei_quickset_QSNativeLib_QSosmGetTestKeysTotal
Java_com_uei_quickset_QSNativeLib_QSosmGetFirstTestKey
Java_com_uei_quickset_QSNativeLib_QSosmGetNextTestKey
Java_com_uei_quickset_QSNativeLib_QSosmGetCurrentCodesetName
Java_com_uei_quickset_QSNativeLib_QSosmGetCodesetsTotal
Java_com_uei_quickset_QSNativeLib_QSosmGetCodesetsTested
Java_com_uei_quickset_QSNativeLib_QSRegionRetrieveTypeCount
Java_com_uei_quickset_QSNativeLib_QSRegionRetrieveTypeName
Java_com_uei_quickset_QSNativeLib_QSRegionRetrieveProviderCountByZipcode
Java_com_uei_quickset_QSNativeLib_QSRegionRetrieveBrandCountByRegion
Java_com_uei_quickset_QSNativeLib_QSRegionRetrieveBrandName
Java_com_uei_quickset_QSNativeLib_QSRegionRetrieveProviderName
Java_com_uei_quickset_QSNativeLib_QSRegionGetCodesetsTotal
Java_com_uei_quickset_QSNativeLib_QSRegionGetCodesetsName
Java_com_uei_quickset_QSNativeLib_QSGetAirconCodesetBinary
Java_com_uei_quickset_QSNativeLib_QSOnlineEDIDRetrieveCodesets
Java_com_uei_quickset_QSNativeLib_QSprovinceGetCountryCount
Java_com_uei_quickset_QSNativeLib_QSprovinceGetCountryName
Java_com_uei_quickset_QSNativeLib_QSprovinceGetProvinceCount
Java_com_uei_quickset_QSNativeLib_QSprovinceGetProvinceName
Java_com_uei_quickset_QSNativeLib_QSprovinceGetCityCount
Java_com_uei_quickset_QSNativeLib_QSprovinceGetCityName
Java_com_uei_quickset_QSNativeLib_QSprovinceGetCityProviderCount
Java_com_uei_quickset_QSNativeLib_QSprovinceGetCityProviderName
Java_com_uei_quickset_QSNativeLib_QSprovinceGetCityProviderCodesetCount
Java_com_uei_quickset_QSNativeLib_QSprovinceGetCityProviderCodesetName
Java_com_uei_quickset_QSNativeLib_QSprovinceGetProvinceProviderCount
Java_com_uei_quickset_QSNativeLib_QSprovinceGetProvinceProviderName
Java_com_uei_quickset_QSNativeLib_QSprovinceGetProvinceProviderCodesetCount
Java_com_uei_quickset_QSNativeLib_QSprovinceGetProvinceProviderCodesetName

And down it goes the rabbit hole.. :) I thought this is about writing a simple byte array on a serial line. Seems a little bit more complex. Now I understand why LeEco didn't choose the Android HAL implementation (which basically offers only 3 entrypoints: open, transmit IR and close). Also official Android API doesn't offer support for receiving infrared signals.

[edit]
Just stumbled upon this PDF: Smart Device Solutions. Looks like all this "Quickset" stuff is part of this UEI product. Unfrotunately I haven't found any datasheet yet (which might explain us how to talk to this chip).
[/edit]
 
Last edited:

androcheck

Senior Member
Dec 7, 2009
236
413
john.zweng.at
Okay, if anybody else wants to try to debug the serial communication with the infrared blaster chip, I attached the Xposed module I've written for this purpose.

I've used it on my LEX720 running 5.8.018S. If you are running a newer EUI version it might work or not (depends if they have recompiled the "com.uei.quicksetsdk.letv" package in "/system/app/UEIQuicksetSDKLeTV/UEIQuicksetSDKLeTV.apk" as it is obfuscated and on recompile the hooked mehod names might change).

If it's working this Xposed module does two things:
  1. enable all logging in the QuickSetSDK
  2. log the actual data which is sent or received over the serial device /dev/ttyHSL1

All output is written to the Xposed logfile:
/data/data/de.robv.android.xposed.installer/log/error.log (can also be viewed in the Xposed app).

If you connect to the phone via adb, open a shell session and then follow the logfile for changes via "tail" you can see in realtime what's happening while using the remote app.
Code:
adb shell
su
tail -F /data/data/de.robv.android.xposed.installer/log/error.log | grep "DEBUG_INFRARED"
# or if you only want to see the serial data which is sent and received to the IR blaster chip:
tail -F /data/data/de.robv.android.xposed.installer/log/error.log | grep "SERIAL_"

The output should look something like this:
Code:
11-30 11:52:35.450 I/Xposed  ( 9018): DEBUG_INFRARED:  SERIAL_WRITE >>> 00
11-30 11:52:35.461 I/Xposed  ( 9018): DEBUG_INFRARED:  SERIAL_WRITE >>> 4041424300080100080304000000
11-30 11:52:36.226 I/Xposed  ( 9018): DEBUG_INFRARED:  SERIAL_WRITE >>> 00
11-30 11:52:36.289 I/Xposed  ( 9018): DEBUG_INFRARED:  SERIAL_READ  <<< 000100
11-30 11:52:37.708 I/Xposed  ( 9018): DEBUG_INFRARED:  SERIAL_WRITE >>> 00
11-30 11:52:37.718 I/Xposed  ( 9018): DEBUG_INFRARED:  SERIAL_WRITE >>> 4041424300080100080304000000
11-30 11:52:39.409 I/Xposed  ( 9018): DEBUG_INFRARED:  SERIAL_WRITE >>> 00
11-30 11:52:39.419 I/Xposed  ( 9018): DEBUG_INFRARED:  SERIAL_READ  <<< 000100

Overall, it looks like the QuickSet SDK just sends "high-level" commands to the IR blaster chip (like: "start now blasting the PLAY key for samsung-remote", then blaster emits IR until a new command is sent "stop blasting now").
It seems that also learning new codes is done this way, so that the SDK just sends commands like "start learning now for key CUSTOM KEY1 on remote CUSTOM REMOTE". Then the blaster is listening for infrared and returns a status if it is finished. Later then the Remote App simply requests "now start blasting the learned custom key1 on custom remote", but it seems like it does not actually send the IR pattern which should be emitted.

In the normal Android Infrared API the App says: "now emit this pattern: 000 111 000 ..." and gives a concrete pattern. Which means the app is responsible for holding all the IR patterns for the remote keys. The QuickSet SDK seems to go the opposite way: The remote app doesn't know anything about low-level IR patterns, it just tells the (intelligent) IR chip, "please emit now the Home button of samsung remote" and all the low-level stuff is done by the controller chip in the IR blaster.

So it might be difficult or impossible to get the IR blaster working with apps that use the default Android Infrared API.

Btw, this QuickSetSDK for infrared is used by other phones too (some LG and others). Just search on XDA for QuickSetSDK. When searching other device forums for this (and to see if they got Infrared working on Cyanogen or AOSP) most of them got Infrared working on custom ROMs by simply porting the original remote app to the custom ROM (and not by implementing the standard Android Infrared API).

I am not sure if the QuickSetSDK would support sending of raw IR patterns. If this is possible, then there is a slight chance to get standard Infrared API working, if not we can just use the original remote app (or maybe other remote apps which use the QuickSetSDK, so maybe we can port other Infrared apps , like from LG or so).

That's all for now.. No idea, if or when I will continue on this.
 

Attachments

  • xposed-module-lepro3-debug-ir-blaster-v0.7.apk
    40.1 KB · Views: 119
  • Like
Reactions: Duchman

serc

Senior Member
Sep 2, 2010
168
48
Hi i am very very happy, that people like androcheck are working on this problem.
i have the le max2 and the same problem 3party IR apps dont running with lemax2.
i have the siswoo r8 monster and the same problem

i want to use rCoid app from playstore in future i hope

thankyou androcheck for your work

Tremendous effort my friend but I am just wondering why can't you use LeEco's default IR app? You can add a predefined remote controls (like thousand brands?) and define your own. I created mine that will control my cable box, Samsung TV and Sound bar all in one remote control.

hi joms
Leecos IR remote wants to know my contacts and phonecalls why ????
without permission it is not running why ???
i have paid for IR hardware but it is not running free !!!
 
Last edited:

Joms_US

Senior Member
Mar 25, 2016
485
142
Hi i am very very happy, that people like androcheck are working on this problem.
i have the le max2 and the same problem 3party IR apps dont running with lemax2.
i have the siswoo r8 monster and the same problem

i want to use rCoid app from playstore in future i hope

thankyou androcheck for your work



hi joms
Leecos IR remote wants to know my contacts and phonecalls why ????
without permission it is not running why ???
i have paid for IR hardware but it is not running free !!!

Well it's not like it will steal your contact information. The LeEco remote can do voice activated control I think hence it is asking for call access (which uses microphone).
 

androcheck

Senior Member
Dec 7, 2009
236
413
john.zweng.at
Well it's not like it will steal your contact information. The LeEco remote can do voice activated control I think hence it is asking for call access (which uses microphone).

I don't think that LeEco is doing something bad here, but to be honest I also find it a little bit frightening what permissions the remote app is claiming. It seems like a lot of these permissions aren't used, but I didn't really look into this.

Also for voice control you don't need the CALL_PHONE permission. The RECORD_AUDIO permission would be sufficient for that.

Here is the full list of permissions the LeEco remote app is claiming in its Manifest:
Code:
android.permission.ACCESS_COARSE_LOCATION
android.permission.ACCESS_FINE_LOCATION
android.permission.ACCESS_MOCK_LOCATION
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_WIFI_STATE
android.permission.AUTHENTICATE_ACCOUNTS
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.CALL_PHONE
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.GET_ACCOUNTS
android.permission.INTERNET
android.permission.MANAGE_ACCOUNTS
android.permission.MOUNT_UNMOUNT_FILESYSTEMS
android.permission.READ_CONTACTS
android.permission.READ_EXTERNAL_STORAGE
android.permission.READ_PHONE_STATE
android.permission.READ_PHONE_STATE
android.permission.RECORD_AUDIO
android.permission.SEND_SMS
android.permission.SYSTEM_ALERT_WINDOW
android.permission.SYSTEM_OVERLAY_WINDOW
android.permission.USE_CREDENTIALS
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE_EXTERNAL_STORAGE
android.permission.WRITE_SETTINGS
com.android.alarm.permission.SET_ALARM
com.letv.android.account.permission.ACCOUNT_RELEVANT
com.letv.android.remotecontrol.permission.PUSH_RECEIVER
com.letv.android.remotecontrol.permission.SEND_CONTROL
 
  • Like
Reactions: serc

androcheck

Senior Member
Dec 7, 2009
236
413
john.zweng.at
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)
 
Last edited:

androcheck

Senior Member
Dec 7, 2009
236
413
john.zweng.at
Should I be concerned that LeEco requires my location in order to use my REMOTE app
I don't know. I could imagine that you might want to access coarse location so that the app can offer you remotes for cable providers in your region? Also, I could imagine internet access might be needed for downloading new remotes and speech recognition.

But I didn't really look what exactly is going on there. The app is pretty huge and includes some 3rd party libraries and packages. Maybe some of these are requiring some of the permissions.
 
  • Like
Reactions: serc

androcheck

Senior Member
Dec 7, 2009
236
413
john.zweng.at
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]
 
Last edited:

androcheck

Senior Member
Dec 7, 2009
236
413
john.zweng.at
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 :)
 

quasarswastik

Senior Member
Dec 30, 2015
126
20
Asus Zenfone Max Pro M2
I have a question about LeEco built in remote control app. The question is that why is that app having feature such as 'Mock Location'. Is there any possible reason for that as per your knowledge.
 

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]