الهندسة العكسية لبروتوكول الإرسال والاستقبال الصينية USB IR


لقد صادفت جهاز الإرسال والاستقبال الصيني MicroUSB IR ، وكانت هناك رغبة في توصيله بجهاز كمبيوتر يعمل بنظام Windows. جهاز الإرسال والاستقبال هو جهاز مضغوط للغاية مع موصل Micro USB. الخيار "الرسمي" الوحيد للعمل معه هو من خلال تطبيق Android يسمى ZaZaRemote.

عند توصيله بجهاز كمبيوتر من خلال محول ، تم تعريف الجهاز على أنه جهاز USB متوافق مع HID \ VID_10C4 و PID_8468. لم تقدم Google من خلال هذا المعرّف أي نتائج ، وكان عليّ إجراء عكس للبروتوكول.

HID غير صالح


تم تعريف فئة الجهاز على أنها USB \ Class_03 و SubClass_FF & Prot_FF. Class_03 - جهاز HID ، SubClass_FF - خاص بالمورد. تم تثبيت برنامج التشغيل hidusb.sys تلقائيًا بواسطة النظام. يمكنك العمل مع برنامج التشغيل هذا من خلال HID API .

بعد أن قمت برسم برنامج صغير بسيط ، تمكنت من الحصول على معلومات مختلفة على الجهاز:

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

اتضح أن التبادل يتم في كتل تبلغ 61 بايت كحد أقصى ، وهناك واجهتان InputValue و 2 OutputValue. تعرض الدالة HidP_GetValueCaps معلومات أكثر تفصيلاً عنها:

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

من بين هذه البيانات ، الأكثر إثارة للاهتمام هي ReportID - معرف التقرير (في الواقع ، حزمة البيانات) و ReportCount - حجمه. يمكن إرسال البيانات واستلامها باستخدام الدالتين HidD_SetOutputReport و HidD_GetInputReport ، على التوالي. بعد أن جربت هذه الوظائف ، مع معرف تقرير مختلف وحجم البيانات ، لم أتمكن من تحقيق تبادل ناجح. بعد حركة المرور عبر USB باستخدام USBPcap ، اكتشفت أن البيانات لم تحاول حتى إرسالها. كان هناك شك في أن هذا نوع من HID غير صحيح.


SET_REPORT ذهب الطلب بلا إجابة

عكس تطبيق ZaZaRemote


في ملف APK لهذا التطبيق ، وجدت مكتبة libtiqiaa_dev_usb.so. تقوم بتصدير الوظائف التالية:

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

إذا حكمنا من خلال الاسم ، فإنهم يدركون التبادل مع الجهاز. غالبًا ما توجد أجزاء شبيهة باستدعاء الوظائف الافتراضية في الكود الخاص بها:

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

تسجيل R0 هو الحجة الأولى لهذه الوظيفة. يتم استدعاء هذه الوظائف فقط من كود Java classes.dex. من خلال فك هذا الملف ، نحصل على نوعه:

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 الرئيسي.

بعد أن درست كود Java المترجم قليلاً ، وجدت الأسطر التالية:

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

سجلات التصحيح هي صديق جيد للمهندس العكسي.

لاستدعاء طرق أصلية من كود Java ، يتم استخدام آلية Java Native Interface . يجب أن تبدو الوظيفة المُصدرة كما يلي:

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

الآن يمكنك تعيين نوع الوظائف في المؤسسة الدولية للتنمية:

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

الآن يتعرف برنامج فك شفرة HexRays على مكالمات JNI ويصبح الرمز أكثر قابلية للفهم ، على سبيل المثال ، يتم إلغاء ترجمة المكالمة أعلاه على النحو التالي:

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

نتيجة فك الدالة 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;
}

الرمز أساسي ، تنسيق الرسالة واضح: يبدأ بالتوقيع "ST" ، ثم يأتي بايت من نوع الأمر - أحد الأحرف {'L' ، 'R' ، 'H' ، 'O' ، 'C' ، 'V' ، 'S '} ، ثم بايت cmdId (مجرد معرف تزايدي لمطابقة الأمر والاستجابة له) وينتهي بالتوقيع "EN". يتم إرسال الرسالة التي تم إنشاؤها بواسطة sub_3528.

كود الوظيفة 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;
}


هذه الميزة أكثر تعقيدًا بعض الشيء. يمكن ملاحظة أن الحد الأقصى لطول الرسالة المرسلة يقتصر على 1024 بايت. تنقسم الرسالة إلى أجزاء. يتكون الجزء من 5 بايت من الرأس وحد أقصى 56 بايت من البيانات - ما مجموعه 61 بايت. هيكل الرأس:

  • buf [0] = 2 ثابت. تذكر ReportID 2؟ يبدو أن هذا هو. و ReportCount 60 - حجم البيانات المتبقية - هو نفسه أيضًا.
  • buf [1] = fragmSize + 3 - حجم البيانات المجزأة + 3 ، أي يتم حساب الحجم من البايت الذي يلي هذا المتغير.
  • buf [2] = UsbPackCounter مجرد عداد ، 1..15.
  • قيمة buf [3] المحسوبة بواسطة التعبير الهوى ليست سوى عدد الأجزاء ، يمكنك إعادة كتابتها على النحو التالي:

    buf[3] = tsize / 56;
    if (tsize % 56) buf[3]++;
  • buf [4] = fragmCnt - رقم القطعة ، 1..buf [3].

يتم إرسال الأجزاء التي تم تكوينها من خلال استدعاء CallIntMethod. لها النوع التالي:

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

يمكن ملاحظة أن HexRays لم يدير هذه المرة - في الحجج فقط v6 = JNIEnv * env. ومع ذلك ، كل شيء في كود المجمع في مكانه:

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

يتم تخزين methodID في المتغير dword_B2A4. دعونا نرى من أين جاء:



يتم التسجيل في وظيفتي usbOpen و usbClose. من الواضح أننا مهتمون بـ usbOpen.

الجزء المطلوب:

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

إذن هذه هي طريقة UsbEndpoint :: bulkTransfer. ولا شيء - يتعلق HID!

الآن دعونا نرى كيف يتم إرسال رموز الأشعة تحت الحمراء - وظيفة usbSendIR.

إنها كبيرة جدًا ، لكن المنطقة التي تشكل الرسالة مع الفريق مفهومة.

جزء من وظيفة 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';

كما هو الحال مع الأوامر الأخرى ، يبدأ كل شيء بـ "ST" ، ثم يتبع cmdId ويتبع رمز الأمر 'D' ، متبوعًا ببايت يحدد التردد - إذا كانت الوسيطة freq> 255 - يتم البحث عنه في جدول التردد IrFreqTable ، وإلا فسيتم نسخه مباشرة. ثم تذهب البيانات وينتهي كل شيء بـ "EN".

وتبين أن الوظيفة التي تحمل الاسم "d" المظلمة هي محلل للبيانات المستلمة.

تغيير السائق والعمل من خلال النقل بالجملة


بعد دراسة HID API ، اكتشفت أنها لا توفر في الأساس القدرة على استخدام النقل الأكبر - لذا يجب عليك تغيير برنامج التشغيل. برنامج تشغيل WinUsb مناسب للعمل مع هذا الجهاز .
بعد كتابة ملف inf ، قمت بتغيير برنامج التشغيل إلى WinUsb وحاولت إرسال الأوامر. كل شيء يعمل وتم تلقي رد فعل من الجهاز - استجابةً لإرسال الأوامر (عبر WinUsb_WritePipe) جاءت استجابة لتنسيق مماثل.

تبادل القمامة مع ZaZaRemote


على الرغم من النجاحات السابقة ، لم أتمكن حتى الآن من تحقيق الشيء الرئيسي - لإجبار الجهاز على إرسال أوامر الأشعة تحت الحمراء. كان التطبيق كبيرًا ومربكًا وأراد فقط التخلص من حركة مرور USB. ومع ذلك ، كيف تفعل ذلك في حالة تطبيق Android؟ تم العثور على الإدخال كـ Android-x86 في VirtualBox-e. على الرغم من حقيقة أن x86 ليس ARM مطلقًا ، إلا أنه يسمح لك بتشغيل ثنائيات ARM الأصلية من خلال آلية NativeBridge. من خلال تثبيت وتكوين البرامج الضرورية ، تمكنت من تشغيل هذا التطبيق في VirtualBox.

الأذونات المطلوبة تلهم بالتأكيد الثقة في هذا البرنامج.


من خلال تشغيل التطبيق وإعداد إعادة توجيه USB ، تمكنت من التعرف على حركة مرور USB. لذلك حصلت على سلسلة من الأوامر لتهيئة استقبال وإرسال أوامر الأشعة تحت الحمراء ، وكذلك عينة من بيانات حزم الأشعة تحت الحمراء.

اتضح أن الجهاز قادر على ليس فقط الإرسال ، ولكن أيضًا تلقي أوامر الأشعة تحت الحمراء ، ولكن الاستقبال يعمل بشكل جيد - من مسافة 10 سم ، ثم كل مرة.

مثال التبادل
- :

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

اتضح أن الجهاز لديه مشاكل في حجم البيانات لإرسالها - بالإضافة إلى الإجابة ، يتم سكب أي القمامة - عادة ما تبقى من الحزمة السابقة.

جعلت دراسة التفريغ والتجارب اللاحقة من الممكن معرفة وظائف جميع الفرق:

  • 'V' - الإصدار - طلب إصدار - ينتج جهازي صفر GUID ؛
  • 'L' - IdleMode - وضع الاستعداد - في هذا الوضع ، يقع الجهاز بعد توفير الطاقة ، أو يمر بهذا الأمر ؛
  • 'S' — SendMode — — ;
  • 'R' — RecvMode — — ;
  • 'D' — Data — — , — ;
  • 'O' — Output — — , — / ;
  • 'C' — Cancel — — , 'O';
  • 'H' — Unknown — .


بعد أن تلقيت تفريغًا لأوامر التحكم وطرود الأشعة تحت الحمراء ، تمكنت من تنفيذ التحكم الكامل في الجهاز - استقبال وإرسال إشارة الأشعة تحت الحمراء. ومع ذلك ، من أجل تجميع إشارة IR تعسفية ، كان من الضروري تحديد التنسيق الذي تم ترميزه. للقيام بذلك ، قمت بتوصيل كاشف ضوئي IR إلى راسم الذبذبات وبدأت في فحص الإشارات المرسلة. من خلال التجريب ، اكتشفت تنسيق الترميز: يحدد البت العالي لكل بايت ما إذا كان جهاز الإرسال قيد التشغيل أو إيقاف التشغيل ، وتحدد البتات السفلية السبعة الوقت. كانت وحدة الوقت 16 ميكروثانية. على سبيل المثال: 8 أ - يتم تشغيل جهاز الإرسال لمدة 160 ميكروثانية ؛ 8A 05 FF 83 - 160 ons قيد التشغيل ، إيقاف مؤقت 80 ،s ، 2.08 مللي ثانية على.

عند تشغيل جهاز الإرسال ، ينبض LED بتردد ~ 36.64 كيلو هرتز. من الناحية النظرية ، يجب تحديد هذا التردد من خلال الوسيطة freq للأمر usbSendIR ، لكن التجارب أظهرت أن الجهاز لا يستجيب لهذه الحجة على الإطلاق. ومع ذلك ، قبلت أجهزتي المنزلية عادةً إشارات جهاز الإرسال والاستقبال.
تبين أن تنسيق البيانات المسجلة بواسطة الجهاز في وضع الاستلام متشابه.

فئة TiqiaaUsbIr و IR


قمت بتطبيق التحكم في جهاز الإرسال والاستقبال في شكل فئة C ++ TiqiaaUsbIr وكتبت برنامج CaptureIR QT بسيط. بالإضافة إلى وظائف استقبال وإرسال إشارات الأشعة تحت الحمراء ، قمت بتنفيذ توليف الإشارات وفك تشفيرها باستخدام بروتوكول NEC. يستخدم هذا البروتوكول ، على سبيل المثال ، في أجهزة التحكم عن بعد لأجهزة تلفزيون LG. قمت أيضًا بتنفيذ حفظ إشارات IR وتحميلها بالتنسيق الأصلي وتنسيق LIRC. كانت هناك فكرة لإنشاء وحدة نمطية لـ WinLirc ، ولكن تبين أنها واجهة برمجة تطبيقات ملتوية وغير منفذة بالكامل ، لذا فقد أجلت هذه الفكرة الآن.

يمكن تنزيل المصادر والبرامج المترجمة هنا .

مثال على استخدام فئة TiqiaaUsbIr:

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

تم التقاط إشارة تشغيل الطاقة:



تم توليفها:



أثناء الالتقاط ، حدث خطأ ما:



ملخص


في عملية البحث ، تمت استعادة بروتوكول USB الخاص بجهاز الإرسال والاستقبال Tiqiaa Tview IR بالكامل ، وتم كتابة ملف inf لبرنامج التشغيل والبرامج للعمل معه.

يعتبر جهاز الإرسال والاستقبال IR المعتبر جهازًا رخيصًا جدًا وبأسعار معقولة وصغير الحجم (5 دولارات على Ali ، أبعاد 15 × 10 × 5 مم) للتحكم في الأجهزة المنزلية ودراسة بروتوكولات الأشعة تحت الحمراء الخاصة به. لسوء الحظ ، تبين أن التحكم في تردد جهاز الإرسال غير صالح للعمل ، وهو ما لم يسبب مشاكل في حالتي ، ولكن من الممكن أن تكون هناك تقنية مع أجهزة استقبال أكثر دقة.

وضع الاستقبال ، بسبب نصف القطر الهزيل وموثوقية الالتقاط المنخفضة ، غير مناسب للاستخدام كمستقبل IR كامل - سجل لمسافات الالتقاط الناجحة ~ 30 سم ، في حين أن جهاز التحكم عن بعد موجه بالضبط إلى جهاز الاستقبال ، وحتى جميع إشارات التركيز لا يتم التقاطها بشكل طبيعي. ومع ذلك ، فهي مفيدة لالتقاط الإشارات ودراسة البروتوكولات للتحكم عن بعد بالأشعة تحت الحمراء.

علاوة


رموز IR مثيرة للاهتمام لأجهزة تلفزيون LG: PS أنا أبحث عن معلومات حول LG AccessUSB ، لمزيد من التفاصيل هنا .

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



All Articles