Reverse engineering of Chinese USB IR transceiver protocol


I came across a Chinese MicroUSB IR transceiver, and there was a desire to connect it to a computer with Windows. The transceiver is a very compact device with a Micro USB connector. The only "official" option to work with it is through an Android application called ZaZaRemote.

When connected to a computer through an adapter, the device was defined as a HID-compatible USB device \ VID_10C4 & PID_8468. Googling by this ID did not give any results, and I had to do protocol reversal.

Invalid HID


The device class was defined as USB \ Class_03 & SubClass_FF & Prot_FF. Class_03 - HID device, SubClass_FF - vendor specific. The hidusb.sys driver was automatically installed by the system. You can work with this driver through the HID API .

Having sketched a simple little program, I was able to get various info on the device:

HidD_GetManufacturerString: "Tiqiaa"
HidD_GetProductString: "Tview"

HidP_GetCaps:
  Usage 1
  UsagePage ff00
  InputReportByteLength 61
  OutputReportByteLength 61
  FeatureReportByteLength 0
  NumberLinkCollectionNodes 1
  NumberInputButtonCaps 0
  NumberInputValueCaps 2
  NumberInputDataIndices 2
  NumberOutputButtonCaps 0
  NumberOutputValueCaps 2
  NumberOutputDataIndices 2
  NumberFeatureButtonCaps 0
  NumberFeatureValueCaps 0
  NumberFeatureDataIndices 0

It turns out that the exchange is carried out in blocks of 61 bytes maximum, there are 2 InputValue and 2 OutputValue interfaces. The HidP_GetValueCaps function returns more detailed information on them:

HidP_GetValueCaps(HidP_Input):
    UsagePage ff00
    ReportID fe
    LinkUsage 1
    LinkUsagePage ff00
    BitSize 8
    ReportCount 8

    UsagePage ff00
    ReportID 1
    LinkUsage 1
    LinkUsagePage ff00
    BitSize 8
    ReportCount 60

HidP_GetValueCaps(HidP_Output):
    UsagePage ff00
    ReportID fd
    LinkUsage 1
    LinkUsagePage ff00
    BitSize 8
    ReportCount 8

    UsagePage ff00
    ReportID 2
    LinkUsage 1
    LinkUsagePage ff00
    BitSize 8
    ReportCount 60

Of this data, the most interesting are ReportID - the ID of the report (in fact, the data packet) and ReportCount - its size. Data can be sent and received using the HidD_SetOutputReport and HidD_GetInputReport functions, respectively. Having experimented with these functions, with different ReportID and data size, I was not able to achieve a successful exchange. After traffic over USB using USBPcap , I found that the data did not even try to be transmitted. There was a suspicion that this is some kind of incorrect HID.


SET_REPORT Request went unanswered

Reversing the ZaZaRemote Application


In the APK file of this application, I found the library libtiqiaa_dev_usb.so. It exports the following functions:

Java_com_icontrol_dev_TiqiaaUsbController_usbOpen
Java_com_icontrol_dev_TiqiaaUsbController_usbClose
Java_com_icontrol_dev_TiqiaaUsbController_usbSendCmd
Java_com_icontrol_dev_TiqiaaUsbController_usbSendIR
Java_com_icontrol_dev_TiqiaaUsbController_d

Judging by the name, they realize the exchange with the device. Fragments similar to calling virtual functions are often found in their code:

LDR     R3, [R0]
LDR     R3, [R3,#0x18]
BLX     R3

Register R0 is the first argument to this function. These functions are called only from the Java classes.dex code. By decompiling this file, we get their type:

private native boolean usbOpen(Context context);
private native void usbClose();
private native boolean usbSendCmd(UsbDeviceConnection usbdeviceconnection, UsbEndpoint usbendpoint, int j, int k);
private native boolean usbSendIR(Context context, UsbDeviceConnection usbdeviceconnection, UsbEndpoint usbendpoint, int j, byte abyte0[], int k);
private native IControlIRData d(byte abyte0[]);

Java code was obfuscated, but some names still survive. In relation to this library, the obfuscator spoiled only the name of the last function, however, almost all the names in the main Java code were corrupted.

Having studied Java decompiled code a bit, I found the following lines:

com.tiqiaa.icontrol.e.i.a("DeviceHolder", (new StringBuilder("send......cmdType=")).append(i1).append(",cmdId=").append(j1).toString());
boolean flag1 = a.b(i1, j1);

com.tiqiaa.icontrol.e.i.d("DeviceHolder", (new StringBuilder("send....................freq=")).append(i1).append(",cmdId=").append(j1).append(",buffer.length=").append(abyte0.length).append(" , device = ").append(a).toString());
boolean flag1 = a.a(i1, abyte0, j1);

Debug logs are a good friend of a reverse engineer.

To call native methods from Java code, the Java Native Interface mechanism is used . The exported function should look like:

extern "C" JNIEXPORT void JNICALL Java_ClassName_MethodName(JNIEnv *env, jobject obj, <java arguments>)

Now you can set the type of functions in the IDA:

bool __cdecl Java_com_icontrol_dev_TiqiaaUsbController_usbOpen(JNIEnv *env, jobject obj, struct Context *context);
void __cdecl Java_com_icontrol_dev_TiqiaaUsbController_usbClose(JNIEnv *env, jobject obj);
bool __cdecl Java_com_icontrol_dev_TiqiaaUsbController_usbSendCmd(JNIEnv *env, jobject obj, struct UsbDeviceConnection *usbdeviceconnection, struct UsbEndpoint *usbendpoint, int cmdType, int cmdId);
bool __cdecl Java_com_icontrol_dev_TiqiaaUsbController_usbSendIR(JNIEnv *env, jobject obj, struct Context *context, struct UsbDeviceConnection *usbdeviceconnection, struct UsbEndpoint *usbendpoint, int freq, jbyte buffer, int cmdId);
struct IControlIRData *__cdecl Java_com_icontrol_dev_TiqiaaUsbController_d(JNIEnv *env, jobject obj, jbyteArray buffer);

Now the HexRays decompiler recognizes JNI calls and the code becomes much more understandable, for example, the above call is decompiled as:

v5 = ((int (*)(void))(*env)->FindClass)();

UsbSendCmd function decompilation result
bool __cdecl Java_com_icontrol_dev_TiqiaaUsbController_usbSendCmd(JNIEnv *env, jobject obj, struct UsbDeviceConnection *usbdeviceconnection, struct UsbEndpoint *usbendpoint, int cmdType, int cmdId)
{
  char v6; // r5@5
  bool result; // r0@12
  char data[24]; // [sp+8h] [bp-18h]@12

  dword_B57C = 0;
  if ( UsbEndpoint_bulkTransfer )
  {
    if ( usbdeviceconnection )
    {
      if ( usbendpoint )
      {
        switch ( cmdType )
        {
          case 0:
            v6 = 'L';
            goto LABEL_12;
          case 2:
            v6 = 'R';
            goto LABEL_12;
          case 3:
            v6 = 'H';
            goto LABEL_12;
          case 4:
            v6 = 'O';
            goto LABEL_12;
          case 6:
            v6 = 'C';
            goto LABEL_12;
          case 7:
            v6 = 'V';
            goto LABEL_12;
          case 1:
            v6 = 'S';
LABEL_12:
            data[0] = 'S';
            data[1] = 'T';
            data[3] = v6;
            data[2] = cmdId;
            data[4] = 'E';
            data[5] = 'N';
            result = sub_3528(env, usbdeviceconnection, usbendpoint, data, 6);
            break;
          default:
            result = 0;
            break;
        }
      }
      else
      {
        result = 0;
      }
    }
    else
    {
      result = 0;
    }
  }
  else
  {
    result = UsbEndpoint_bulkTransfer;
  }
  return result;
}

The code is elementary, the message format is obvious: it starts with the signature "ST", then comes the byte of the command type - one of the characters {'L', 'R', 'H', 'O', 'C', 'V', 'S '}, then the cmdId byte (just an incremental identifier to match the command and the response to it) and ends with the signature "EN". The generated message is sent by sub_3528.

Function Code sub_3528
int __cdecl sub_3528(JNIEnv *env, struct UsbDeviceConnection *usbdeviceconnection, struct UsbEndpoint *usbendpoint, void *data, int size)
{
  JNIEnv v5; // r1@1
  JNIEnv *v6; // r4@1
  int result; // r0@2
  int v8; // r2@3
  int tsize; // r7@5
  size_t fragmSize; // r5@9
  int v11; // r0@11
  JNIEnv v12; // r3@11
  int v13; // r6@11
  int rdOffs; // [sp+10h] [bp-80h]@7
  int v15; // [sp+14h] [bp-7Ch]@15
  int jbyteArray; // [sp+18h] [bp-78h]@1
  int fragmCnt; // [sp+1Ch] [bp-74h]@7
  char *_data; // [sp+28h] [bp-68h]@1
  char buf[64]; // [sp+34h] [bp-5Ch]@7
  int _stack_chk_guard; // [sp+74h] [bp-1Ch]@1

  _data = (char *)data;
  v5 = *env;
  v6 = env;
  _stack_chk_guard = ::_stack_chk_guard;
  jbyteArray = ((int (*)(void))v5->NewByteArray)();
  if ( jbyteArray )
  {
    v8 = UsbPackCounter + 1;
    if ( UsbPackCounter + 1 > 15 )
      v8 = 1;
    tsize = size;
    UsbPackCounter = v8;
    if ( size > 1024 )
      tsize = 1024;
    j_j_memset(buf, 0, 0x40u);
    buf[0] = 2;
    buf[3] = (tsize / 56 & 0x7F)
           + ((((tsize + -56 * (tsize / 56 & 0x7F)) >> 31) - (tsize + -56 * (tsize / 56 & 0x7Fu))) >> 31);
    rdOffs = 0;
    fragmCnt = 0;
    buf[2] = UsbPackCounter;
    while ( 1 )
    {
      if ( rdOffs >= tsize )
        goto LABEL_25;
      fragmCnt = (fragmCnt + 1) & 0xFF;
      fragmSize = tsize - rdOffs;
      if ( tsize - rdOffs > 56 )
        fragmSize = 56;
      buf[1] = fragmSize + 3;
      buf[4] = fragmCnt;
      j_j_memcpy(&buf[5], &_data[rdOffs], fragmSize);
      ((void (__fastcall *)(JNIEnv *, int, _DWORD, signed int))(*v6)->SetByteArrayRegion)(v6, jbyteArray, 0, 61);
      v11 = ((int (__fastcall *)(JNIEnv *))(*v6)->ExceptionCheck)(v6);
      v12 = *v6;
      v13 = v11;
      if ( v11 )
      {
        ((void (__fastcall *)(JNIEnv *))v12->ExceptionClear)(v6);
        v13 = 0;
        goto return_r6_del;
      }
      if ( !dword_B2A4 )
      {
LABEL_25:
        v13 = 1;
        goto return_r6_del;
      }
      v15 = ((int (__fastcall *)(JNIEnv *))v12->CallIntMethod)(v6);
      if ( ((int (__fastcall *)(JNIEnv *))(*v6)->ExceptionCheck)(v6) )
      {
        ((void (__fastcall *)(JNIEnv *))(*v6)->ExceptionClear)(v6);
        goto return_r6_del;
      }
      if ( v15 < 0 )
        break;
      rdOffs += fragmSize;
    }
    v13 = 0;
return_r6_del:
    ((void (__fastcall *)(JNIEnv *, int))(*v6)->DeleteLocalRef)(v6, jbyteArray);
    result = v13;
  }
  else
  {
    ((void (__fastcall *)(JNIEnv *))(*v6)->ExceptionClear)(v6);
    result = 0;
  }
  if ( _stack_chk_guard != ::_stack_chk_guard )
    j_j___stack_chk_fail(result);
  return result;
}


This feature is a bit more complicated. It can be seen that the maximum length of the sent message is limited to 1024 bytes. The message is divided into fragments. The fragment consists of 5 bytes of the header and a maximum of 56 bytes of data - a total of 61 bytes. Header structure:

  • buf [0] = 2 is a constant. Remember ReportID 2? It seems that this is it. And ReportCount 60 - the size of the remaining data - is also the same.
  • buf [1] = fragmSize + 3 - fragment data size + 3, ie the size is calculated from the byte following this variable.
  • buf [2] = UsbPackCounter is just a counter, 1..15.
  • The value of buf [3] calculated by the fancy expression is just the number of fragments, you can rewrite it as:

    buf[3] = tsize / 56;
    if (tsize % 56) buf[3]++;
  • buf [4] = fragmCnt - fragment number, 1..buf [3].

Formed fragments are sent through a call to CallIntMethod. It has the following type:

jint (JNICALL *CallIntMethod)(JNIEnv *env, jobject obj, jmethodID methodID, ...);

It can be seen that HexRays did not manage this time - only v6 = JNIEnv * env in the arguments. However, in the assembler code everything is in place:

LDR     R2, [R2,#(dword_B2A4 - 0xB284)] ; jmethodID methodID

methodID is stored in the dword_B2A4 variable. Let's see where it came from:



Recording is done in the usbOpen and usbClose functions. Obviously, we are interested in usbOpen.

The desired fragment:

v27 = ((int (__fastcall *)(JNIEnv *, int, const char *, const char *))(*v4)->GetMethodID)(
        v4,
        v26,
        "bulkTransfer",
        "(Landroid/hardware/usb/UsbEndpoint;[BII)I");
dword_B2A4 = v27;

So this is the UsbEndpoint :: bulkTransfer method. And nothing - related to HID!

Now let's see how IR codes are transmitted - usbSendIR function.

It is quite large, but the area that forms the message with the team is understandable.

Fragment of usbSendIR function
  buf[0] = 'S';
  buf[1] = 'T';
  buf[2] = cmdId;
  buf[3] = 'D';
  if ( freq > 255 )
  {
    LOBYTE(v36) = 0;
    v37 = -1;
    v38 = 0;
    while ( 1 )
    {
      v39 = (freq - IrFreqTable[v38] + ((freq - IrFreqTable[v38]) >> 31)) ^ ((freq - IrFreqTable[v38]) >> 31);
      if ( v37 != -1 && v39 >= v37 )
      {
        v39 = v37;
      }
      else
      {
        LOBYTE(v36) = v38;
        if ( !v39 )
          break;
      }
      if ( ++v38 == 30 )
        break;
      v37 = v39;
    }
  }
  else
  {
    v36 = (unsigned int)(freq - 1) <= 0x1C ? freq : 0;
  }
  buf[4] = v36;
  v40 = &buf[v22];
  v40[5] = 'E';
  v40[6] = 'N';

As with other commands, everything starts with "ST", then cmdId and the command code 'D' follow, followed by a byte that determines the frequency - if the argument is freq> 255 - it is looked up in the frequency table IrFreqTable, otherwise it is copied directly. Then the data goes and everything ends with "EN".

The function with the obfuscated name β€œd” turned out to be a parser of received data.

Changing the driver and working through bulkTransfer


Having studied the HID API, I found out that it basically does not provide the ability to use bulkTransfer - so you have to change the driver. The WinUsb driver is suitable for working with this device .
Having written the inf file, I changed the driver to WinUsb and tried to send commands. Everything worked and a reaction was received from the device - in response to sending commands (via WinUsb_WritePipe) a response of a similar format came.

Dump exchange with ZaZaRemote


Despite previous successes, so far I have not been able to achieve the main thing - to force the device to transmit IR commands. The application was too big and confusing and just wanted to dump USB traffic. However, how to do this in the case of an Android application? The entry was found as Android-x86 on VirtualBox-e. Despite the fact that x86 is never ARM, it nevertheless allows you to run native ARM binaries through the NativeBridge mechanism. By installing and configuring the necessary software, I was able to get this application to work in VirtualBox.

The requested permissions definitely inspire confidence in this software.


By launching the application and setting up USB forwarding, I was able to sniff USB traffic. So I got a sequence of commands for initializing the reception and transmission of IR commands, as well as sample data of IR packets.

It turned out that the device is capable of not only transmitting, but also receiving IR commands, but the reception worked quite so-so - from a distance of 10 cm, and then every other time.

Exchange Example
- :

OUT:
0040 02 09 01 01 01 53 54 12 56 45 4e .....ST.VEN

IN:
0040 01 30 07 01 01 53 54 12 56 30 01 30 30 30 30 30 .0...ST.V0.00000
0050 30 30 30 2d 30 30 30 30 2d 30 30 30 30 2d 30 30 000-0000-0000-00
0060 30 30 2d 30 30 30 30 30 30 30 30 30 30 30 31 09 00-000000000001.
0070 45 4e ff ff ff df ff f9 ef ff df ff bf fb ff EN.............

OUT:
0040 02 09 02 01 01 53 54 13 53 45 4e .....ST.SEN

IN:
0040 01 0a 08 01 01 53 54 13 53 09 45 4e 30 30 30 30 .....ST.S.EN0000
0050 30 30 30 2d 30 30 30 30 2d 30 30 30 30 2d 30 30 000-0000-0000-00
0060 30 30 2d 30 30 30 30 30 30 30 30 30 30 30 31 09 00-000000000001.
0070 45 4e ff ff ff df ff f9 ef ff df ff bf fb ff EN.............

OUT:
0040 02 3b 03 02 01 53 54 14 44 00 ff ff ff ff b7 7f .;...ST.D.......
0050 7f 1b a3 23 a3 23 a3 69 a3 23 a3 23 a3 23 a3 23 ...#.#.i.#.#.#.#
0060 a3 23 a3 69 a3 69 a3 23 a3 69 a3 69 a3 69 a3 69 .#.i.i.#.i.i.i.i
0070 a3 69 a3 69 a3 23 a3 23 a3 23 a3 69 a3 .i.i.#.#.#.i.

OUT:
0040 02 2f 03 02 02 23 a3 23 a3 23 a3 23 a3 69 a3 69 ./...#.#.#.#.i.i
0050 a3 69 a3 23 a3 69 a3 69 a3 69 a3 7f 7f 7f 7f 7f .i.#.i.i.i......
0060 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 57 45 ..............WE
0070 4e N

IN:
0040 01 0a 09 01 01 53 54 14 4f 09 45 4e 30 30 30 30 .....ST.O.EN0000
0050 30 30 30 2d 30 30 30 30 2d 30 30 30 30 2d 30 30 000-0000-0000-00
0060 30 30 2d 30 30 30 30 30 30 30 30 30 30 30 31 09 00-000000000001.
0070 45 4e ff ff ff df ff f9 ef ff df ff bf fb ff EN.............

- :

OUT:
0040 02 09 01 01 01 53 54 17 56 45 4e .....ST.VEN

IN:
0040 01 30 0c 01 01 53 54 17 56 30 01 30 30 30 30 30 .0...ST.V0.00000
0050 30 30 30 2d 30 30 30 30 2d 30 30 30 30 2d 30 30 000-0000-0000-00
0060 30 30 2d 30 30 30 30 30 30 30 30 30 30 30 31 09 00-000000000001.
0070 45 4e ff ff ff df ff f9 ef ff df ff bf fb ff EN.............

OUT:
0040 02 09 02 01 01 53 54 18 53 45 4e .....ST.SEN

0040 01 0a 0d 01 01 53 54 18 53 09 45 4e 30 30 30 30 .....ST.S.EN0000
0050 30 30 30 2d 30 30 30 30 2d 30 30 30 30 2d 30 30 000-0000-0000-00
0060 30 30 2d 30 30 30 30 30 30 30 30 30 30 30 31 09 00-000000000001.
0070 45 4e ff ff ff df ff f9 ef ff df ff bf fb ff EN.............

OUT:
0040 02 09 03 01 01 53 54 19 52 45 4e .....ST.REN

0040 01 0a 0e 01 01 53 54 19 52 13 45 4e 30 30 30 30 .....ST.R.EN0000
0050 30 30 30 2d 30 30 30 30 2d 30 30 30 30 2d 30 30 000-0000-0000-00
0060 30 30 2d 30 30 30 30 30 30 30 30 30 30 30 31 09 00-000000000001.
0070 45 4e ff ff ff df ff f9 ef ff df ff bf fb ff EN.............

OUT:
0040 02 09 04 01 01 53 54 1a 43 45 4e .....ST.CEN

IN:
0040 01 0a 0f 01 01 53 54 1a 43 13 45 4e 30 30 30 30 .....ST.C.EN0000
0050 30 30 30 2d 30 30 30 30 2d 30 30 30 30 2d 30 30 000-0000-0000-00
0060 30 30 2d 30 30 30 30 30 30 30 30 30 30 30 31 09 00-000000000001.
0070 45 4e ff ff ff df ff f9 ef ff df ff bf fb ff EN.............

OUT:
0040 02 09 05 01 01 53 54 1b 4f 45 4e .....ST.OEN

IN:
0040 01 3b 01 0e 01 53 54 00 44 ff ff ff ff ba 7f 7f .;...ST.D.......
0050 19 a4 21 a4 21 a4 68 a4 22 a4 21 a4 22 a4 22 a4 ..!.!.h.".!.".".
0060 22 a4 68 a4 68 a4 21 a4 68 a4 68 a4 68 a4 68 a4 ".h.h.!.h.h.h.h.
0070 68 a4 68 a4 22 a4 22 a4 22 a4 68 a4 22 fb ff h.h.".".".h."..
.....
0040 01 2f 01 0e 0e 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f ./..............
0050 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f ................
0060 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 3e 13 45 .............>.E
0070 4e 82 02 82 02 82 7f 7f 7f 7f 7f 7f 7f fb ff N..............

It turned out that the device has problems with the size of the data to send - in addition to the answer, any garbage is poured - usually what is left of the previous package.

Studying the dump and subsequent experiments made it possible to find out the functions of all the teams:

  • 'V' - Version - request for a version - my device produces a zero GUID;
  • 'L' - IdleMode - standby mode - in this mode, the device is located after power is supplied, or goes by this command;
  • 'S' β€” SendMode β€” β€” ;
  • 'R' β€” RecvMode β€” β€” ;
  • 'D' β€” Data β€” β€” , β€” ;
  • 'O' β€” Output β€” β€” , β€” / ;
  • 'C' β€” Cancel β€” β€” , 'O';
  • 'H' β€” Unknown β€” .


Having received a dump of control commands and IR parcels, I was able to implement full-fledged device control - receiving and transmitting an IR signal. However, in order to synthesize an arbitrary IR signal, it was necessary to determine the format in which it is encoded. To do this, I connected an IR photodetector to an oscilloscope and began to examine the signals sent. Through experimentation, I found out the encoding format: the high bit of each byte determines whether the transmitter is on or off, and the lower 7 bits determine the time. The unit of time was 16 microseconds. For example: 8A - the transmitter is turned on for 160 microseconds; 8A 05 FF 83 - 160 ΞΌs on, pause 80 ΞΌs, 2.08 ms on.

When the transmitter is turned on, the LED pulsates at a frequency of ~ 36.64 kHz. Theoretically, this frequency should be determined by the freq argument of the usbSendIR command, but experiments have shown that the device does not respond to this argument at all. Nevertheless, my home appliances normally accepted the signals of this transceiver.
The format of the data recorded by the device in the receive mode turned out to be similar.

TiqiaaUsbIr Class and IR Control


I implemented the transceiver control in the form of a C ++ TiqiaaUsbIr class and wrote a simple CaptureIR QT program. In addition to the functions of receiving and transmitting IR signals, I implemented the synthesis and decoding of signals using the NEC protocol. This protocol is used, for example, in remotes of LG TVs. I also implemented saving and loading IR signals in the original format and the LIRC format. There was an idea to make a module for WinLirc, but it turned out to be a crooked and not fully implemented API, so I have postponed this idea for now.

Sources and compiled program can be downloaded here .

An example of using the TiqiaaUsbIr class:

std::vector<std::string> IrDev;
TiqiaaUsbIr::EnumDevices(IrDev); //  
TiqiaaUsbIr Ir;
Ir.Open(IrDev[0].c_str()); //  
Ir.SendNecSignal(0x0408); //   (LG POWER)
Ir.Close();

Captured power-on signal:



It is synthesized:



During the capture, something went wrong:



Summary


In the process of research, the USB protocol of the Tiqiaa Tview IR transceiver was completely restored, the inf file of the driver and software for working with it were written.

The considered IR transceiver is a very cheap, affordable and compact ($ 5 on Ali, dimensions 15 x 10 x 5 mm) device for controlling household appliances and studying its IR protocols. Unfortunately, controlling the frequency of the transmitter turned out to be inoperative, which in my case did not cause problems, but it is possible that there is a technique with more finicky receivers.

The reception mode, due to the meager radius and low capture reliability, is unsuitable for use as a full-fledged IR receiver - a record of successful capture distances of ~ 30 cm, while the remote control is aimed exactly at the receiver, and even all focus signals are not normally captured. However, it is useful for capturing signals and studying protocols for IR remotes.

Bonus


Interesting IR codes for LG TVs: PS I am looking for information about LG AccessUSB, more details here .

POWER 0408
POWERON 04C4
POWEROFF 04C5
IN_STOP 04FA
IN_START 04FB
POWERONLY 04FE
EZ_ADJUST 04FF



All Articles