Membalikkan protokol transceiver USB IR Cina


Saya menemukan transceiver IR MicroUSB Cina, dan ada keinginan untuk menghubungkannya ke komputer dengan Windows. Transceiver adalah perangkat yang sangat kompak dengan konektor Micro USB. Satu-satunya opsi "resmi" untuk bekerja dengannya adalah melalui aplikasi Android yang disebut ZaZaRemote.

Ketika terhubung ke komputer melalui adaptor, perangkat didefinisikan sebagai perangkat USB yang kompatibel dengan HID \ VID_10C4 & PID_8468. Googling dengan ID ini tidak memberikan hasil apa pun, dan saya harus melakukan pembalikan protokol.

HID tidak valid


Kelas perangkat didefinisikan sebagai USB \ Class_03 & SubClass_FF & Prot_FF. Class_03 - Perangkat HID, SubClass_FF - khusus vendor. Driver hidusb.sys diinstal secara otomatis oleh sistem. Anda dapat bekerja dengan driver ini melalui API HID .

Setelah membuat sketsa program kecil yang sederhana, saya bisa mendapatkan berbagai info di perangkat:

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

Ternyata pertukaran dilakukan dalam blok maksimum 61 byte, ada 2 antarmuka InputValue dan 2 OutputValue. Fungsi HidP_GetValueCaps mengembalikan informasi lebih rinci tentang mereka:

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

Dari data ini, yang paling menarik adalah ReportID - ID laporan (pada kenyataannya, paket data) dan ReportCount - ukurannya. Data dapat dikirim dan diterima masing-masing menggunakan fungsi HidD_SetOutputReport dan HidD_GetInputReport. Setelah bereksperimen dengan fungsi-fungsi ini, dengan ReportID dan ukuran data yang berbeda, saya tidak dapat mencapai pertukaran yang sukses. Setelah lalu lintas melalui USB menggunakan USBPcap , saya menemukan bahwa data bahkan tidak mencoba untuk dikirim. Ada kecurigaan bahwa ini semacam HID yang salah.


SET_REPORT Permintaan tidak dijawab

Membalik Aplikasi ZaZaRemote


Dalam file APK aplikasi ini, saya menemukan perpustakaan libtiqiaa_dev_usb.so. Ini mengekspor fungsi-fungsi berikut:

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

Dilihat dari namanya, mereka menyadari pertukaran dengan perangkat itu. Fragmen yang mirip dengan memanggil fungsi virtual sering ditemukan dalam kode mereka:

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

Daftar R0 adalah argumen pertama untuk fungsi ini. Fungsi-fungsi ini dipanggil hanya dari kode Java tables.dex. Dengan mendekompilasi file ini, kita mendapatkan tipenya:

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[]);

Kode Java dikaburkan, tetapi beberapa nama masih bertahan. Sehubungan dengan perpustakaan ini, obfuscator hanya merusak nama fungsi terakhir, namun, hampir semua nama dalam kode Java utama rusak.

Setelah mempelajari kode dekompilasi Java sedikit, saya menemukan baris berikut:

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 log adalah teman baik seorang insinyur terbalik.

Untuk memanggil metode asli dari kode Java, mekanisme Java Native Interface digunakan . Fungsi yang diekspor harus seperti:

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

Sekarang Anda dapat mengatur jenis fungsi di 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);

Sekarang dekompiler HexRays mengenali panggilan JNI dan kode menjadi lebih dimengerti, misalnya, panggilan di atas didekompilasi sebagai:

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

Hasil dekompilasi fungsi UsbSendCmd
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;
}

Kodenya dasar, format pesannya jelas: dimulai dengan tanda tangan β€œST”, kemudian muncul byte tipe perintah - salah satu karakter {'L', 'R', 'H', 'O', 'C', 'V', 'S '}, kemudian byte cmdId (hanya pengidentifikasi tambahan yang cocok dengan perintah dan responsnya) dan diakhiri dengan tanda tangan "EN". Pesan yang dihasilkan dikirim oleh sub_3528.

Kode Fungsi 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;
}


Fitur ini sedikit lebih rumit. Dapat dilihat bahwa panjang maksimum pesan yang dikirim dibatasi hingga 1024 byte. Pesan ini dibagi menjadi beberapa bagian. Fragmen terdiri dari 5 byte header dan maksimum 56 byte data - total 61 byte. Struktur header:

  • buf [0] = 2 adalah konstanta. Ingat ReportID 2? Sepertinya ini dia. Dan ReportCount 60 - ukuran data yang tersisa - juga sama.
  • buf [1] = fragmSize + 3 - ukuran data fragmen + 3, yaitu ukurannya dihitung dari byte yang mengikuti variabel ini.
  • buf [2] = UsbPackCounter hanyalah sebuah penghitung, 1..15.
  • Nilai buf [3] yang dihitung oleh ekspresi mewah hanyalah jumlah fragmen, Anda dapat menulis ulang sebagai:

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

Fragmen yang terbentuk dikirim melalui panggilan ke CallIntMethod. Ini memiliki jenis berikut:

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

Dapat dilihat bahwa HexRays tidak mengatur waktu ini - hanya dalam argumen v6 = JNIEnv * env. Namun, dalam kode assembler semuanya ada di tempat:

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

methodID disimpan dalam variabel dword_B2A4. Mari kita lihat dari mana asalnya:



Perekaman dilakukan di fungsi usbOpen dan usbClose. Jelas, kami tertarik dengan usbOpen.

Fragmen yang diinginkan:

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

Jadi ini adalah metode UsbEndpoint :: bulkTransfer. Dan tidak ada - terkait dengan HID!

Sekarang mari kita lihat bagaimana kode IR dikirimkan - fungsi usbSendIR.

Ini cukup besar, tetapi area yang membentuk pesan dengan tim dapat dimengerti.

Fragmen fungsi usbSendIR
  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';

Seperti dengan perintah lain, semuanya dimulai dengan "ST", kemudian cmdId dan kode perintah 'D' diikuti, diikuti oleh byte yang menentukan frekuensi - jika argumennya adalah freq> 255 - itu akan dicari di tabel frekuensi IrFreqTable, jika tidak disalin secara langsung. Kemudian data masuk dan semuanya berakhir dengan "EN".

Fungsi dengan nama "d" yang dikaburkan ternyata menjadi pengurai data yang diterima.

Mengubah driver dan bekerja melalui bulkTransfer


Setelah mempelajari HID API, saya menemukan bahwa itu pada dasarnya tidak menyediakan kemampuan untuk menggunakan bulkTransfer - jadi Anda harus mengubah driver. Driver WinUsb cocok untuk bekerja dengan perangkat ini .
Setelah menulis file inf, saya mengubah driver ke WinUsb dan mencoba mengirim perintah. Semuanya berfungsi dan reaksi diterima dari perangkat - sebagai respons terhadap pengiriman perintah (melalui WinUsb_WritePipe), respons dengan format yang sama datang.

Pertukaran Dump dengan ZaZaRemote


Meskipun sukses sebelumnya, sejauh ini saya belum dapat mencapai hal utama - memaksa perangkat untuk mengirimkan perintah IR. Aplikasi itu terlalu besar dan membingungkan dan hanya ingin membuang lalu lintas USB. Namun, bagaimana melakukan ini dalam kasus aplikasi Android? Entri tersebut ditemukan sebagai Android-x86 di VirtualBox-e. Terlepas dari kenyataan bahwa x86 tidak pernah ARM, namun demikian memungkinkan Anda untuk menjalankan binari ARM asli melalui mekanisme NativeBridge. Dengan menginstal dan mengkonfigurasi perangkat lunak yang diperlukan, saya dapat membuat aplikasi ini berfungsi di VirtualBox.

Izin yang diminta pasti menginspirasi kepercayaan dalam perangkat lunak ini.


Dengan meluncurkan aplikasi dan mengatur penerusan USB, saya dapat mengendus lalu lintas USB. Jadi saya mendapat urutan perintah untuk menginisialisasi penerimaan dan pengiriman perintah IR, serta data sampel paket IR.

Ternyata perangkat tidak hanya mampu mentransmisikan, tetapi juga menerima perintah IR, tetapi penerimaan bekerja sangat-begitu - dari jarak 10 cm, dan kemudian setiap waktu.

Pertukaran Contoh
- :

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..............

Ternyata perangkat memiliki masalah dengan ukuran data yang akan dikirim - selain jawabannya, setiap sampah dituangkan - biasanya apa yang tersisa dari paket sebelumnya.

Mempelajari dump dan percobaan selanjutnya memungkinkan untuk mengetahui fungsi semua tim:

  • 'V' - Versi - permintaan untuk versi - perangkat saya menghasilkan GUID nol;
  • 'L' - IdleMode - mode siaga - dalam mode ini, perangkat berada setelah daya disuplai, atau dijalankan dengan perintah ini;
  • 'S' β€” SendMode β€” β€” ;
  • 'R' β€” RecvMode β€” β€” ;
  • 'D' β€” Data β€” β€” , β€” ;
  • 'O' β€” Output β€” β€” , β€” / ;
  • 'C' β€” Cancel β€” β€” , 'O';
  • 'H' β€” Unknown β€” .


Setelah menerima dump perintah kontrol dan paket IR, saya dapat menerapkan kontrol perangkat lengkap - menerima dan mentransmisikan sinyal IR. Namun, untuk mensintesis sinyal IR sewenang-wenang, perlu untuk menentukan format di mana itu dikodekan. Untuk melakukan ini, saya menghubungkan photodetektor IR ke osiloskop dan mulai memeriksa sinyal yang dikirim. Melalui eksperimen, saya menemukan format penyandian: bit tinggi setiap byte menentukan apakah pemancar aktif atau tidak, dan 7 bit yang lebih rendah menentukan waktu. Satuan waktu adalah 16 mikrodetik. Sebagai contoh: 8A - pemancar dihidupkan selama 160 mikrodetik; 8A 05 FF 83 - 160 ΞΌs aktif, jeda 80 ΞΌs, 2.08 ms aktif.

Ketika pemancar dihidupkan, LED berdenyut pada frekuensi ~ 36,64 kHz. Secara teoritis, frekuensi ini harus ditentukan oleh argumen freq dari perintah usbSendIR, tetapi percobaan menunjukkan bahwa perangkat sama sekali tidak menanggapi argumen ini. Namun demikian, peralatan rumah saya biasanya menerima sinyal dari transceiver ini.
Format data yang direkam oleh perangkat dalam mode terima ternyata serupa.

Kelas TiqiaaUsbIr dan Kontrol IR


Saya menerapkan kontrol transceiver dalam bentuk kelas C ++ TiqiaaUsbIr dan menulis program QT CaptureIR sederhana. Selain fungsi menerima dan mentransmisikan sinyal IR, saya menerapkan sintesis dan decoding sinyal menggunakan protokol NEC. Protokol ini digunakan, misalnya, dalam remote TV LG. Saya juga menerapkan penyimpanan dan pemuatan sinyal IR dalam format asli dan format LIRC. Ada ide untuk membuat modul untuk WinLirc, tapi ternyata itu API yang bengkok dan tidak sepenuhnya diimplementasikan, jadi saya telah menunda ide ini untuk saat ini.

Sumber dan program yang dikompilasi dapat diunduh di sini .

Contoh menggunakan kelas TiqiaaUsbIr:

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

Sinyal power-on yang diambil:



Disintesis:



Selama penangkapan, ada yang salah:



Ringkasan


Dalam proses penelitian, protokol USB dari transceiver Tiqiaa Tview IR sepenuhnya dipulihkan, file inf driver dan perangkat lunak untuk bekerja dengannya ditulis.

Transceiver IR yang dipertimbangkan adalah perangkat yang sangat murah, terjangkau dan ringkas ($ 5 untuk Ali, dimensi 15 x 10 x 5 mm) untuk mengendalikan peralatan rumah tangga dan mempelajari protokol IR-nya. Sayangnya, mengendalikan frekuensi pemancar ternyata tidak beroperasi, yang dalam kasus saya tidak menyebabkan masalah, tetapi ada kemungkinan bahwa ada teknik dengan penerima yang lebih rewel.

Mode penerimaan, karena radius yang kecil dan keandalan tangkapan yang rendah, tidak cocok untuk digunakan sebagai penerima IR penuh - catatan jarak tangkapan yang sukses ~ 30 cm, sedangkan kendali jarak jauh diarahkan tepat ke penerima, dan bahkan semua sinyal fokus biasanya tidak ditangkap. Namun, ini berguna untuk menangkap sinyal dan mempelajari protokol untuk remote IR.

Bonus


Kode IR menarik untuk TV LG: PS Saya mencari informasi tentang LG AccessUSB, lebih detail di sini .

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



All Articles