Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deciphering the functions. #256

Open
warrenarea opened this issue Apr 18, 2017 · 129 comments
Open

Deciphering the functions. #256

warrenarea opened this issue Apr 18, 2017 · 129 comments

Comments

@warrenarea
Copy link

warrenarea commented Apr 18, 2017

So it occurs to me that trying to locate the get_level and decryption functions, based on where
the rjindael code is... is pretty much a lost cause, because the rjindael is just mixed in with a bunch
of other encryption functions, and they could be doing all sorts of other processes in between
actually utilizing the data acquired.

So I think I'm getting a little closer, by first looking at "Imports" or Symbols, which are basically
the function names.

What I want to focus on at this point, is "sure thing" code and recognizable code segments,
because there is a ton of code, and we don't want to waste our time on false positives and
confusing ourselves.

I think I'll break the code up into sections, to make it easier to edit later.

If you want to comment on an item, reference its function name. (for clarity)

@warrenarea
Copy link
Author

Object Explorer : DataAcqThread

_DWORD *__thiscall sub_14DD040(_DWORD *this, int a2, int a3, int a4, int a5, int a6, char *Source, char a8, char a9)
{
  _DWORD *v9; // edi@1
  void *v10; // ST18_4@1
  int v11; // edx@1
  int v13; // [sp+0h] [bp-1Ch]@0
  int v14; // [sp+4h] [bp-18h]@0
  int v15; // [sp+8h] [bp-14h]@0

  v9 = this;
  v10 = this;
  sub_14E2890(Source, a8, a9);
  *v9 = &off_16AB094;
  v9[94] = Xtime_get_ticks(v13, v14, v15, v10);
  v9[95] = v11;
  v9[96] = *(_DWORD *)a6;
  v9[97] = *(_DWORD *)(a6 + 4);
  v9[98] = a2;
  v9[99] = 0;
  v9[100] = 0;
  v9[99] = sub_138CCC0(v9 + 99);
  v9[101] = a3;
  v9[102] = a4;
  v9[103] = 0;
  v9[104] = 0;
  v9[105] = 0;
  v9[106] = 0;
  v9[107] = a5;
  v9[108] = 0;
  v9[109] = 0;
  v9[108] = sub_138CCC0(v9 + 108);
  v9[111] = 0;
  v9[112] = 0;
  v9[113] = 0;
  v9[112] = sub_14DD940(v9 + 112);
  v9[114] = 0;
  v9[115] = 0;
  v9[114] = sub_14DD940(v9 + 114);
  v9[116] = 0;
  v9[117] = 0;
  v9[116] = sub_14DD940(v9 + 116);
  v9[118] = 0;
  v9[119] = 0;
  v9[118] = sub_14DD940(v9 + 118);
  v9[120] = 0;
  v9[121] = 0;
  v9[120] = sub_140A580(v9 + 120);
  v9[122] = 0;
  v9[123] = 0;
  v9[122] = sub_138CCC0(v9 + 122);
  v9[124] = 0;
  v9[125] = 0;
  v9[124] = sub_138CCC0(v9 + 124);
  v9[126] = 0;
  v9[127] = 0;
  v9[126] = sub_138CCC0(v9 + 126);
  return v9;
}

Comments:
Looks like sensor_bit values we're seeing here.

@minifiredragon
Copy link
Contributor

I would agree, this is what I found as well while running EPOC+

@warrenarea
Copy link
Author

Object Explorer : CognitiveDetectionG2_Clamshell

signed int __thiscall sub_8670310(void *this, int a2, int a3)
{
  void *v3; // ebx@1
  int v4; // edi@23
  int v15; // eax@41
  int v16; // eax@41
  unsigned int v17; // esi@41
  int v18; // ecx@42
  signed int v19; // edi@45
  signed int v20; // ebx@47
  signed int v21; // eax@47
  int v22; // eax@49
  bool v23; // zf@49
  signed int v24; // eax@51
  int v25; // eax@55
  unsigned int v26; // esi@65
  int v27; // ecx@66
  signed int v28; // eax@68
  int v29; // eax@70
  bool v30; // zf@70
  signed int v31; // eax@72
  int v32; // eax@76
  int v33; // esi@76
  int v34; // eax@85
  int v35; // eax@85
  int v36; // esi@85
  int v37; // eax@85
  int v38; // ST3C_4@85
  unsigned int v39; // esi@99
  int v40; // ecx@100
  signed int v41; // eax@102
  int v42; // eax@104
  unsigned int v43; // esi@109
  int v44; // ecx@110
  signed int v45; // eax@112
  int v46; // eax@114
  unsigned int v47; // esi@119
  int v48; // eax@123
  char v52; // [sp+0h] [bp-70h]@0
  void *v53; // [sp+10h] [bp-60h]@1
  unsigned int v55; // [sp+18h] [bp-58h]@55
  int v57; // [sp+28h] [bp-48h]@41
  unsigned int v58; // [sp+2Ch] [bp-44h]@55
  int v59; // [sp+2Ch] [bp-44h]@76
  int v60; // [sp+30h] [bp-40h]@85
  void *Src; // [sp+48h] [bp-28h]@1
  int v62; // [sp+58h] [bp-18h]@1
  unsigned int v63; // [sp+5Ch] [bp-14h]@1
  int v64; // [sp+6Ch] [bp-4h]@1

  v3 = this;
  v53 = this;
  v64 = 0;
  v63 = 15;
  v62 = 0;
  LOBYTE(Src) = 0;
  sub_850C1E0((int)&Src, "34bd287fcda21853efba287688db0c4d", 0x20u);
  LOBYTE(v64) = 1;
  sub_853E2F0(&Src);
  LOBYTE(v64) = 0;
  if ( v63 >= 0x10 )
    operator delete(Src);
  v63 = 15;
  v62 = 0;
  LOBYTE(Src) = 0;
  sub_850C1E0((int)&Src, "1b67a98380453cedca92592b3428a418", 0x20u);
  LOBYTE(v64) = 2;
  sub_853E2F0(&Src);
  LOBYTE(v64) = 0;
  if ( v63 >= 0x10 )
    operator delete(Src);
  v63 = 15;
  v62 = 0;
  LOBYTE(Src) = 0;
  sub_850C1E0((int)&Src, "2f862bcdcbeffd69eb4a6f84c0f1e69b", 0x20u);
  LOBYTE(v64) = 3;
  sub_853E2F0(&Src);
  LOBYTE(v64) = 0;
  if ( v63 >= 0x10 )
    operator delete(Src);
  v63 = 15;
  v62 = 0;
  LOBYTE(Src) = 0;
  sub_850C1E0((int)&Src, "077ad045a661aa9be650f87a291716c3", 0x20u);
  LOBYTE(v64) = 4;
  sub_853E2F0(&Src);
  LOBYTE(v64) = 0;
  if ( v63 >= 0x10 )
    operator delete(Src);
  v63 = 15;
  v62 = 0;
  LOBYTE(Src) = 0;
  sub_850C1E0((int)&Src, "563f77be9797afaed87a515a37302163", 0x20u);
  LOBYTE(v64) = 5;
  sub_853E2F0(&Src);
  LOBYTE(v64) = 0;
  if ( v63 >= 0x10 )
    operator delete(Src);
  v63 = 15;
  v62 = 0;
  LOBYTE(Src) = 0;
  sub_850C1E0((int)&Src, "600e25844e2cd2ac247acef85582a262", 0x20u);
  LOBYTE(v64) = 6;
  sub_853E2F0(&Src);
  LOBYTE(v64) = 0;
  if ( v63 >= 0x10 )
    operator delete(Src);
  v63 = 15;
  v62 = 0;
  LOBYTE(Src) = 0;
  sub_850C1E0((int)&Src, "9de38cf5529d7eb1b4caade47f3c594c", 0x20u);
  LOBYTE(v64) = 7;
  sub_853E2F0(&Src);
  LOBYTE(v64) = 0;
  if ( v63 >= 0x10 )
    operator delete(Src);
  v63 = 15;
  v62 = 0;
  LOBYTE(Src) = 0;
  sub_850C1E0((int)&Src, "1e0fa5d1bedb54db63f18862dcd6538d", 0x20u);
  LOBYTE(v64) = 8;
  sub_853E2F0(&Src);
  LOBYTE(v64) = 0;
  if ( v63 >= 0x10 )
    operator delete(Src);
  v63 = 15;
  v62 = 0;
  LOBYTE(Src) = 0;
  sub_850C1E0((int)&Src, "b07766e96df0e9a01737ab61f60503d5", 0x20u);
  LOBYTE(v64) = 9;
  sub_853E2F0(&Src);
  LOBYTE(v64) = 0;
  if ( v63 >= 0x10 )
    operator delete(Src);
  v63 = 15;
  v62 = 0;
  LOBYTE(Src) = 0;
  sub_850C1E0((int)&Src, "aa07a0cd4f6f544b8bf34c0be604da7f", 0x20u);
  LOBYTE(v64) = 10;
  sub_853E2F0(&Src);
  LOBYTE(v64) = 0;
  if ( v63 >= 0x10 )
    operator delete(Src);
  v63 = 15;
  v62 = 0;
  LOBYTE(Src) = 0;
  sub_850C1E0((int)&Src, "824180e25489bf4935865cc05377f606", 0x20u);
  LOBYTE(v64) = 11;
  sub_853E2F0(&Src);
  LOBYTE(v64) = 0;
  if ( v63 >= 0x10 )
    operator delete(Src);
  v4 = a2;
  if ( !(unsigned __int8)(*(int (__thiscall **)(void *))(*(_DWORD *)v3 + 48))(v3) )
    v3 = v53;
  v15 = (*(int (__thiscall **)(void *))(*(_DWORD *)v3 + 84))(v3);
  v16 = sub_86E7710(v15);
  v17 = *(_DWORD *)(a2 + 16);
  v57 = v16;
  if ( *(_DWORD *)(a2 + 20) < 0x10u )
    v18 = a2;
  else
    v18 = *(_DWORD *)a2;
  v20 = 32;
  v21 = 32;
  if ( v17 < 0x20 )
    v21 = *(_DWORD *)(a2 + 16);
  v22 = sub_8519A70(v18, "2f862bcdcbeffd69eb4a6f84c0f1e69b", v21);
  v23 = v22 == 0;
  if ( !v22 )
  {
    if ( v17 >= 0x20 )
      v24 = v17 != 32;
    else
      v24 = -1;
    v23 = v24 == 0;
  }
  if ( !v23 )
    goto LABEL_138;
  v55 = sub_86E6260(a3);
  v63 = 15;
  v62 = 0;
  LOBYTE(Src) = 0;
  sub_850C1E0((int)&Src, "207990f83c61d088201133343f06b299", 0x20u);
  LOBYTE(v64) = 12;
  v25 = (*(int (__stdcall **)(int *))(*(_DWORD *)v57 + 4))((int *)&Src);
  v58 = sub_86E6260(v25);
  LOBYTE(v64) = 0;
  if ( v63 >= 0x10 )
    operator delete(Src);
  if ( v55 & 0xFFFFC001 )
  {
    if ( dword_8949F54 <= 2 )
      sub_86E5C20(2, "CognitivDetectionG2: parameterSanityCheck failed. Invalid active action(s).", v52);
    return 774;
  }
  if ( ((v55
       + ((v55 - ((v55 >> 1) & 0x77777777) - ((v55 >> 2) & 0x33333333) - ((v55 >> 3) & 0x11111111)) >> 4)
       - ((v55 >> 1) & 0x77777777)
       - ((v55 >> 2) & 0x33333333)
       - ((v55 >> 3) & 0x11111111)) & 0xF0F0F0F)
     % 0xFF > v58 )
  {
    if ( dword_8949F54 <= 2 )
      sub_86E5C20(2, "CognitivDetectionG2: parameterSanityCheck failed. Max active actions reached.", v52);
    v19 = 775;
  }
  else
  {
LABEL_138:
    v26 = *(_DWORD *)(a2 + 16);
    if ( *(_DWORD *)(a2 + 20) < 0x10u )
      v27 = a2;
    else
      v27 = *(_DWORD *)a2;
    v28 = 32;
    if ( v26 < 0x20 )
      v28 = *(_DWORD *)(a2 + 16);
    v29 = sub_8519A70(v27, "1b67a98380453cedca92592b3428a418", v28);
    v30 = v29 == 0;
    if ( !v29 )
    {
      if ( v26 >= 0x20 )
        v31 = v26 != 32;
      else
        v31 = -1;
      v30 = v31 == 0;
    }
    if ( v30 )
    {
      v59 = sub_86E6260(a3);
      v63 = 15;
      v62 = 0;
      LOBYTE(Src) = 0;
      sub_850C1E0((int)&Src, "1b67a98380453cedca92592b3428a418", 0x20u);
      LOBYTE(v64) = 13;
      v32 = (*(int (__stdcall **)(void **))(*(_DWORD *)v57 + 4))(&Src);
      v33 = sub_86E6260(v32);
      LOBYTE(v64) = 0;
      if ( v63 >= 0x10 )
        operator delete(Src);
      switch ( v59 )
      {
        case 0:
          if ( v33 != 1 )
            goto LABEL_99;
          if ( dword_8949F54 > 2 )
            goto LABEL_95;
          sub_86E5C20(
            2,
            "%s %s",
            (unsigned int)"CognitivDetectionG2: parameterSanityCheck failed. Unexpected training control flag:");
          return 773;
        case 1:
          if ( v33 == 1 )
          {
            if ( dword_8949F54 > 2 )
            {
LABEL_95:
              v19 = 773;
            }
            else
            {
              sub_86E5C20(
                2,
                "%s %s",
                (unsigned int)"CognitivDetectionG2: parameterSanityCheck failed. Unexpected training control flag:");
              v19 = 773;
            }
          }
          else
          {
            sub_850B460((int)&Src, "2f862bcdcbeffd69eb4a6f84c0f1e69b");
            LOBYTE(v64) = 14;
            v34 = (*(int (__stdcall **)(void **))(*(_DWORD *)v57 + 4))(&Src);
            v35 = sub_86E6260(v34);
            LOBYTE(v64) = 0;
            v36 = v35 | 1;
            sub_850B5D0(&Src);
            sub_850B460((int)&v60, "34bd287fcda21853efba287688db0c4d");
            LOBYTE(v64) = 15;
            v37 = (*(int (__stdcall **)(int *))(*(_DWORD *)v57 + 4))(&v60);
            v38 = sub_86E6260(v37);
            LOBYTE(v64) = 0;
            sub_850B5D0(&v60);
            if ( v38 & v36 )
              goto LABEL_99;
            if ( dword_8949F54 <= 2 )
              sub_86E5C20(
                2,
                "%s %d",
                (unsigned int)"CognitivDetectionG2: parameterSanityCheck failed. Unexpected training action:");
            v19 = 772;
          }
          break;
        case 2:
        case 3:
          if ( v33 == 1 )
            goto LABEL_99;
          if ( dword_8949F54 > 2 )
            goto LABEL_95;
          sub_86E5C20(
            2,
            "%s %s",
            (unsigned int)"CognitivDetectionG2: parameterSanityCheck failed. Unexpected training control flag:");
          return 773;
        case 4:
          if ( !v33 )
            goto LABEL_99;
          if ( dword_8949F54 <= 2 )
            sub_86E5C20(
              2,
              "%s %s",
              (unsigned int)"CognitivDetectionG2: parameterSanityCheck failed. Unexpected training control flag:");
          goto LABEL_95;
        case 5:
          goto LABEL_99;
        default:
          if ( dword_8949F54 <= 2 )
            sub_86E5C20(2, "CognitivDetectionG2: parameterSanityCheck failed. Unknown training control parameter.", v52);
          return 773;
      }
    }
    else
    {
LABEL_99:
      v39 = *(_DWORD *)(a2 + 16);
      if ( *(_DWORD *)(a2 + 20) < 0x10u )
        v40 = a2;
      else
        v40 = *(_DWORD *)a2;
      v41 = 32;
      if ( v39 < 0x20 )
        v41 = *(_DWORD *)(a2 + 16);
      v42 = sub_8519A70(v40, "98ec7f4c8199a7096deb25f48034a60c", v41);
      if ( v42 || v39 < 0x20 || (LOBYTE(v42) = v39 != 32, v42) || (unsigned int)sub_86E6260(a3) <= 1 )
      {
        v43 = *(_DWORD *)(a2 + 16);
        if ( *(_DWORD *)(a2 + 20) < 0x10u )
          v44 = a2;
        else
          v44 = *(_DWORD *)a2;
        v45 = 32;
        if ( v43 < 0x20 )
          v45 = *(_DWORD *)(a2 + 16);
        v46 = sub_8519A70(v44, "bf67cdf1c3362bbe1846a77ea067483e", v45);
        if ( v46 || v43 < 0x20 || (LOBYTE(v46) = v43 != 32, v46) || sub_86E6260(a3) >= 0 )
        {
          v47 = *(_DWORD *)(a2 + 16);
          if ( *(_DWORD *)(a2 + 20) >= 0x10u )
            v4 = *(_DWORD *)a2;
          if ( v47 < 0x20 )
            v20 = *(_DWORD *)(a2 + 16);
          v48 = sub_8519A70(v4, "824180e25489bf4935865cc05377f606", v20);
          if ( v48 || v47 < 0x20 || (LOBYTE(v48) = v47 != 32, v48) )
          {
            v19 = 0;
          }
          else if ( (*(int (**)(void))(*(_DWORD *)v53 + 20))() )
          {
            v19 = 1;
          }
          else
          {
            v19 = 2304;
          }
        }
        else
        {
          v19 = 769;
        }
      }
      else
      {
        v19 = 770;
      }
    }
  }
  return v19;
}

Comment:
Though I don't think its entirely relevant, it has some interesting features, and shows a
small piece of the core code.

@minifiredragon
Copy link
Contributor

I think that code is what is used to draw the graphs. It repeats in the loop x number of times equal to i think 500ms as it looks like it prints half a second to the display.

@warrenarea
Copy link
Author

its a little more slow going than i thought, still looking for that function that explains it all.
think i'm pretty close though.... seen a few functions that look pretty promising.

double checking them though. I decided I might take another approach, and went back to looking
at the "old" v2.0 Emotiv Control Panel.

Figured it might be easier to pin point it there, and then go back to the new one.

Though I am noticing some key differences, kind of like some of the functions were renamed,
and modularized and the code a bit more organized in the Xavier version. So although I might
be able to pin point the general structure of the old version, the functions will likely be slightly
re-arranged.

@warrenarea
Copy link
Author

Signal Quality

int __thiscall sub_13CA090(void *this)
{
  void *v1; // edi@1
  signed __int32 v2; // edx@1
  QString *v3; // ebx@1
  signed int v4; // esi@1
  int v5; // eax@1
  int v6; // edx@2
  int v7; // edx@2
  int v8; // edx@3
  const struct QString *v9; // eax@12
  const struct QString *v10; // eax@12
  char *v11; // ecx@12
  const struct QString *v12; // eax@13
  const struct QString *v13; // eax@13
  const struct QString *v14; // eax@14
  const struct QString *v15; // eax@14
  const struct QString *v16; // eax@15
  const struct QString *v17; // eax@15
  const struct QString *v18; // eax@16
  const struct QString *v19; // eax@16
  const struct QString *v20; // eax@17
  const struct QString *v21; // eax@17
  const char *v22; // ecx@18
  QString *v23; // ecx@18
  QString *v25; // [sp-4h] [bp-5Ch]@18
  const char *v26; // [sp+0h] [bp-58h]@3
  char v27; // [sp+14h] [bp-44h]@17
  char v28; // [sp+18h] [bp-40h]@17
  char v29; // [sp+1Ch] [bp-3Ch]@16
  char v30; // [sp+20h] [bp-38h]@16
  char v31; // [sp+24h] [bp-34h]@15
  char v32; // [sp+28h] [bp-30h]@15
  char v33; // [sp+2Ch] [bp-2Ch]@14
  char v34; // [sp+30h] [bp-28h]@14
  char v35; // [sp+34h] [bp-24h]@13
  char v36; // [sp+38h] [bp-20h]@13
  char v37; // [sp+3Ch] [bp-1Ch]@12
  char v38; // [sp+40h] [bp-18h]@12
  int v39; // [sp+44h] [bp-14h]@1
  int v40; // [sp+48h] [bp-10h]@1
  int v41; // [sp+54h] [bp-4h]@1

  v1 = this;
  v39 = QString::shared_null;
  v2 = _InterlockedExchangeAdd(QString::shared_null, 1u);
  v41 = 0;
  v40 = QString::shared_null;
  _InterlockedExchangeAdd(QString::shared_null, 1u);
  LOBYTE(v41) = 1;
  v3 = (this + 64);
  v4 = 0;
  v5 = this + 60;
  do
  {
    QString::operator=(v5, v2, "image:url(:/Resources/Sensorsignal/");
    QString::operator=(v3, v6, "image:url(:/Resources/Sensorsignal/");
    switch ( v4 )
    {
      case 0:
        QString::operator=(&v39, v7, "F3");
        v26 = "sF3";
        goto LABEL_8;
      case 1:
        QString::operator=(&v39, v7, "F4");
        v26 = "sF4";
        goto LABEL_8;
      case 2:
        QString::operator=(&v39, v7, "T7");
        v26 = "sT7";
        goto LABEL_8;
      case 3:
        QString::operator=(&v39, v7, "T8");
        v26 = "sT8";
        goto LABEL_8;
      case 4:
        QString::operator=(&v39, v7, "Pz");
        v26 = &off_1624340;
LABEL_8:
        QString::operator=(&v40, v8, v26);
        break;
      default:
        break;
    }
    QString::append((v1 + 60), &v39);
    QString::append(v3, &v40);
    if ( !*(v1 + 28) )
      *(v1 + v4 + 10) = 0;
    switch ( *(v1 + v4 + 10) )
    {
      case 0:
        v9 = QString::fromAscii(&v38, "Black.png);", -1);
        LOBYTE(v41) = 2;
        QString::append((v1 + 60), v9);
        LOBYTE(v41) = 1;
        QString::~QString(&v38);
        v10 = QString::fromAscii(&v37, "Black.png);", -1);
        LOBYTE(v41) = 3;
        QString::append(v3, v10);
        v11 = &v37;
        break;
      case 1:
        v12 = QString::fromAscii(&v36, "Red.png);", -1);
        LOBYTE(v41) = 4;
        QString::append((v1 + 60), v12);
        LOBYTE(v41) = 1;
        QString::~QString(&v36);
        v13 = QString::fromAscii(&v35, "Red.png);", -1);
        LOBYTE(v41) = 5;
        QString::append(v3, v13);
        v11 = &v35;
        break;
      case 2:
        v14 = QString::fromAscii(&v34, "Orange.png);", -1);
        LOBYTE(v41) = 6;
        QString::append((v1 + 60), v14);
        LOBYTE(v41) = 1;
        QString::~QString(&v34);
        v15 = QString::fromAscii(&v33, "Red.png);", -1);
        LOBYTE(v41) = 7;
        QString::append(v3, v15);
        v11 = &v33;
        break;
      case 3:
        v16 = QString::fromAscii(&v32, "Orange.png);", -1);
        LOBYTE(v41) = 8;
        QString::append((v1 + 60), v16);
        LOBYTE(v41) = 1;
        QString::~QString(&v32);
        v17 = QString::fromAscii(&v31, "Orange.png);", -1);
        LOBYTE(v41) = 9;
        QString::append(v3, v17);
        v11 = &v31;
        break;
      case 4:
        v18 = QString::fromAscii(&v30, "Green.png);", -1);
        LOBYTE(v41) = 10;
        QString::append((v1 + 60), v18);
        LOBYTE(v41) = 1;
        QString::~QString(&v30);
        v19 = QString::fromAscii(&v29, "Green.png);", -1);
        LOBYTE(v41) = 11;
        QString::append(v3, v19);
        v11 = &v29;
        break;
      default:
        v20 = QString::fromAscii(&v28, "Black.png);", -1);
        LOBYTE(v41) = 12;
        QString::append((v1 + 60), v20);
        LOBYTE(v41) = 1;
        QString::~QString(&v28);
        v21 = QString::fromAscii(&v27, "Black.png);", -1);
        LOBYTE(v41) = 13;
        QString::append(v3, v21);
        v11 = &v27;
        break;
    }
    LOBYTE(v41) = 1;
    QString::~QString(v11);
    v26 = v22;
    v25 = v3;
    QString::QString(&v26);
    sub_13C9BD0(v4, v25);
    v25 = v23;
    QString::QString(&v25);
    sub_13C9B30(v4++, v25);
    v5 = v1 + 60;
  }
  while ( v4 < 5 );
  LOBYTE(v41) = 0;
  QString::~QString(&v40);
  v41 = -1;
  return QString::~QString(&v39);
}

@warrenarea
Copy link
Author

Some sort of main thread. Could be useful in seeing what order the functions
are initiated. Might look further into the "data acquisition" function.

int __cdecl sub_13E41C0(int a1, int a2, void *a3)
{
  void **v4; // eax@6
  void *v5; // eax@9
  int v6; // ebx@9
  int v7; // ecx@15
  int v8; // eax@17
  int v9; // ecx@19
  int v10; // eax@21
  int v11; // ecx@24
  char *v12; // eax@30
  int v13; // esi@32
  int v14; // eax@35
  int v15; // eax@52
  int v16; // eax@53
  void *v17; // eax@54
  int v18; // ecx@55
  int v19; // eax@58
  void *v20; // eax@62
  int *v21; // esi@63
  int v22; // ecx@66
  int v23; // eax@68
  int v24; // edx@68
  int v25; // eax@68
  int v26; // edx@68
  char v27; // al@68
  int v28; // eax@69
  int v29; // edx@69
  int v30; // eax@71
  int v31; // edx@71
  int v32; // eax@73
  int v33; // edx@73
  int v34; // eax@75
  int v35; // edx@75
  int v36; // eax@76
  int v37; // edx@76
  char v38; // al@76
  int v39; // eax@77
  int v40; // edx@77
  int v41; // eax@79
  int v42; // edx@79
  int v43; // eax@81
  int v44; // edx@81
  int v45; // eax@83
  int v46; // edx@83
  int v47; // eax@87
  int v48; // edx@87
  int v49; // eax@88
  int v50; // edx@88
  void *v51; // eax@88
  int v52; // ecx@89
  char v53; // [sp+14h] [bp-BCh]@19
  __int128 v54; // [sp+18h] [bp-B8h]@19
  int v55; // [sp+28h] [bp-A8h]@19
  char v56; // [sp+2Ch] [bp-A4h]@15
  void *v57; // [sp+30h] [bp-A0h]@15
  int v58; // [sp+34h] [bp-9Ch]@15
  __int128 v59; // [sp+38h] [bp-98h]@15
  int v60; // [sp+48h] [bp-88h]@1
  char v61; // [sp+58h] [bp-78h]@4
  char **v62; // [sp+5Ch] [bp-74h]@30
  char v63; // [sp+64h] [bp-6Ch]@28
  char v64; // [sp+65h] [bp-6Bh]@29
  char v65; // [sp+69h] [bp-67h]@68
  char v66; // [sp+6Ch] [bp-64h]@66
  void *v67; // [sp+90h] [bp-40h]@18
  int v68; // [sp+94h] [bp-3Ch]@7
  void **v69; // [sp+98h] [bp-38h]@6
  void *v70; // [sp+9Ch] [bp-34h]@23
  void *v71[2]; // [sp+A0h] [bp-30h]@1
  int v72; // [sp+B4h] [bp-1Ch]@4
  unsigned int v73; // [sp+B8h] [bp-18h]@4
  int *v74; // [sp+C0h] [bp-10h]@1
  int v75; // [sp+CCh] [bp-4h]@1

  v74 = &v60;
  v71[0] = a3;
  v75 = 0;
  if ( !a1 && !sub_13EED30(a2) )
    return a1 + 2;
  sub_14A8950(&v61);
  LOBYTE(v75) = 1;
  v73 = 15;
  v72 = 0;
  LOBYTE(v71[1]) = 0;
  sub_136C1E0(&v71[1], "edk.cfg", 7u);
  LOBYTE(v75) = 2;
  sub_14A99B0(&v71[1]);
  LOBYTE(v75) = 1;
  if ( v73 >= 0x10 )
    operator delete(v71[1]);
  v4 = operator new(0x10u);
  v69 = v4;
  LOBYTE(v75) = 3;
  if ( v4 )
    v68 = sub_154B840(v4);
  else
    v68 = 0;
  LOBYTE(v75) = 1;
  v5 = operator new(0x28u);
  v6 = v5;
  if ( v5 )
  {
    *(v5 + 8) = xmmword_16BDE30;
    *v5 = &off_16BCEB4;
    *(v5 + 6) = 0;
    *(v5 + 7) = 0;
    *(v5 + 8) = 0;
  }
  else
  {
    v6 = 0;
  }
  if ( a1 != 1 )
  {
    if ( a1 == 2 )
    {
      v70 = operator new(0x300u);
      LOBYTE(v75) = 7;
      if ( v70 )
        v11 = sub_13DF780(2, 0);
      else
        v11 = 0;
      LOBYTE(v75) = 1;
      dword_17D348C = v11;
      if ( v11 )
        (*(*v6 + 72))(v6, v11);
      goto LABEL_62;
    }
    if ( !v63 || !v64 )
    {
      if ( DWORD2(xmmword_17A8708) == 2 )
      {
        if ( (DWORD1(xmmword_17A8708) - 2) > 2 )
        {
          if ( dword_17A9F54 <= 3 )
          {
            DWORD3(v59) = DWORD1(xmmword_17A8708);
            sub_1545C20(3, "%s [%d]", "EE_EngineConnect : unknown board type");
          }
        }
        else if ( xmmword_17A8708 == 2 )
        {
          v70 = operator new(0x88u);
          LOBYTE(v75) = 8;
          if ( v70 )
          {
            v15 = sub_13E03B0(xmmword_16BDE20, *(&xmmword_16BDE20 + 1));
            LOBYTE(v75) = 1;
            (*(*v6 + 72))(v6, v15);
          }
          else
          {
            v16 = *v6;
            LOBYTE(v75) = 1;
            (*(v16 + 72))(v6, 0);
          }
        }
        else
        {
          v17 = operator new(0x40u);
          if ( v17 )
            v18 = sub_13E1610(v17, xmmword_16BDE20, *(&xmmword_16BDE20 + 1));
          else
            v18 = 0;
          (*(*v6 + 72))(v6, v18);
          if ( operator new(0x38u) )
          {
            v19 = sub_13E15B0(xmmword_16BDE20, *(&xmmword_16BDE20 + 1));
            (*(*v6 + 72))(v6, v19);
          }
          else
          {
            (*(*v6 + 72))(v6, 0);
          }
        }
      }
      goto LABEL_62;
    }
    v12 = *v62;
    for ( v71[0] = *v62; ; v12 = v71[0] )
    {
      while ( 1 )
      {
        if ( v12 == v62 )
          goto LABEL_62;
        v13 = (v12 + 40);
        v69 = 0;
        if ( *(v12 + 14) )
          break;
LABEL_47:
        sub_13F7DA0(v71);
        v12 = v71[0];
      }
      if ( dword_17A9F54 <= 0 )
      {
        if ( *(v12 + 15) < 0x10u )
          v14 = (v12 + 40);
        else
          v14 = *v13;
        DWORD3(v59) = v14;
        sub_1545C20(0, "%s [%s] ...", "EE_EngineConnect : Loading file");
      }
      if ( !sub_149C590(v13, v68, &v69) )
      {
        if ( dword_17A9F54 <= 0 )
        {
          if ( *(v13 + 20) >= 0x10u )
            v13 = *v13;
          DWORD3(v59) = v13;
          sub_1545C20(0, "%s [%s]", "EE_EngineConnect : Error loading profile ");
        }
        goto LABEL_47;
      }
      if ( dword_17A9F54 > 0 )
        goto LABEL_47;
      if ( *(v13 + 20) >= 0x10u )
        v13 = *v13;
      *(&v59 + 1) = __PAIR__("has been loaded.", v13);
      sub_1545C20(0, "%s [%s] %s", "EE_EngineConnect : Profile ");
      sub_13F7DA0(v71);
    }
  }
  if ( byte_17A86B8 )
  {
    v69 = operator new(0x3D8u);
    LOBYTE(v75) = 4;
    if ( v69 )
    {
      *(&v59 + 1) = 15i64;
      DWORD1(v59) = 0;
      v56 = 0;
      sub_136C0C0(&v56, v71[0], 0, 0xFFFFFFFF);
      v7 = sub_13DF3A0(
             a2,
             1,
             xmmword_16BDE30,
             *(&xmmword_16BDE30 + 1),
             0,
             *&v56,
             v57,
             v58,
             v59,
             SDWORD1(v59),
             SDWORD2(v59),
             SDWORD3(v59));
    }
    else
    {
      v7 = 0;
    }
    dword_17D3488 = v7;
    v8 = *v6;
    DWORD3(v59) = v7;
    LOBYTE(v75) = 1;
    (*(v8 + 72))(v6, v7);
  }
  else
  {
    v67 = operator new(0x300u);
    LOBYTE(v75) = 5;
    if ( v67 )
    {
      v69 = &v57;
      sub_136B460(&v57, Memory);
      *&v56 = 0;
      LOBYTE(v75) = 6;
      v55 = 15;
      DWORD3(v54) = 0;
      v53 = 0;
      sub_136C0C0(&v53, v71[0], 0, 0xFFFFFFFF);
      LOBYTE(v75) = 5;
      v9 = sub_13DF080(
             a2,
             0,
             1,
             xmmword_16BDE30,
             *(&xmmword_16BDE30 + 1),
             0,
             *&v53,
             v54,
             SDWORD1(v54),
             SDWORD2(v54),
             SDWORD3(v54),
             v55,
             *&v56,
             v57,
             v58,
             v59,
             SDWORD1(v59),
             SDWORD2(v59),
             SDWORD3(v59));
    }
    else
    {
      v9 = 0;
    }
    dword_17D3490 = v9;
    v10 = *v6;
    DWORD3(v59) = v9;
    LOBYTE(v75) = 1;
    (*(v10 + 72))(v6, v9);
  }
LABEL_62:
  sub_149E320();
  v20 = operator new(0x88u);
  v70 = v20;
  LOBYTE(v75) = 9;
  if ( v20 )
    v21 = sub_14ACA30(v20);
  else
    v21 = 0;
  LOBYTE(v75) = 1;
  v70 = operator new(0x28u);
  LOBYTE(v75) = 10;
  if ( v70 )
  {
    v22 = sub_14ABD40(v21, &v66);
    v71[0] = v22;
  }
  else
  {
    v22 = 0;
    v71[0] = 0;
  }
  *(v22 + 25) = v65;
  LOBYTE(v75) = 1;
  v23 = sub_149D5A0("DataAcquisitionDetection");
  v24 = *v21;
  DWORD3(v59) = v23;
  (*(v24 + 100))(v21, v23);
  v25 = sub_149D5A0("FFTDataDetection");
  v26 = *v21;
  DWORD3(v59) = v25;
  (*(v26 + 100))(v21, v25);
  v27 = dword_17A8618;
  if ( dword_17A8618 & 1 )
  {
    v28 = sub_149D5A0("BlinkWinkG3Detection");
    v29 = *v21;
    DWORD3(v59) = v28;
    (*(v29 + 100))(v21, v28);
    v27 = dword_17A8618;
  }
  if ( v27 & 2 )
  {
    v30 = sub_149D5A0("NTExpressivDetection");
    v31 = *v21;
    DWORD3(v59) = v30;
    (*(v31 + 100))(v21, v30);
    v27 = dword_17A8618;
  }
  if ( v27 & 4 )
  {
    v32 = sub_149D5A0("HorizontalEyeDetection");
    v33 = *v21;
    DWORD3(v59) = v32;
    (*(v33 + 100))(v21, v32);
    v27 = dword_17A8618;
  }
  if ( v27 & 8 )
  {
    v34 = sub_149D5A0("ExciteIntegrateDetection");
    v35 = *v21;
    DWORD3(v59) = v34;
    (*(v35 + 100))(v21, v34);
  }
  v36 = sub_149D5A0("SignalQualityDetection");
  v37 = *v21;
  DWORD3(v59) = v36;
  (*(v37 + 100))(v21, v36);
  v38 = dword_17A8618;
  if ( dword_17A8618 & 0x200 )
  {
    v39 = sub_149D5A0("CognitivDetectionG2");
    v40 = *v21;
    DWORD3(v59) = v39;
    (*(v40 + 100))(v21, v39);
    v38 = dword_17A8618;
  }
  if ( v38 & 0x10 )
  {
    v41 = sub_149D5A0("EngagementBoredomDetection");
    v42 = *v21;
    DWORD3(v59) = v41;
    (*(v42 + 100))(v21, v41);
    v38 = dword_17A8618;
  }
  if ( v38 & 0x20 )
  {
    v43 = sub_149D5A0("MeditationDetection");
    v44 = *v21;
    DWORD3(v59) = v43;
    (*(v44 + 100))(v21, v43);
    v38 = dword_17A8618;
  }
  if ( v38 & 0x40 )
  {
    v45 = sub_149D5A0("ValenceDetection");
    v46 = *v21;
    DWORD3(v59) = v45;
    (*(v46 + 100))(v21, v45);
    v38 = dword_17A8618;
  }
  if ( xmmword_17A8708 != 3 && xmmword_17A8708 != 4 && v38 < 0 )
  {
    v47 = sub_149D5A0("FrustrationDetection");
    v48 = *v21;
    DWORD3(v59) = v47;
    (*(v48 + 100))(v21, v47);
  }
  v49 = sub_149D5A0("BatteryDetection");
  v50 = *v21;
  DWORD3(v59) = v49;
  (*(v50 + 100))(v21, v49);
  v51 = operator new(0xE10u);
  v70 = v51;
  LOBYTE(v75) = 11;
  if ( v51 )
    v52 = sub_14A2360(v51, v6, v68, v71[0]);
  else
    v52 = 0;
  LOBYTE(v75) = 1;
  dword_17D3494 = v52;
  if ( dword_17D3488 )
  {
    sub_14A75D0(dword_17D3488);
    v52 = dword_17D3494;
  }
  (*(*v52 + 64))();
  LOBYTE(v75) = 0;
  sub_14A9220(&v61);
  return 0;
}

@warrenarea
Copy link
Author

Signal Quality for Insight.

Not entirely sure how useful this will be. Probably more to this function.

int __thiscall sub_140A460(QWidget **this, QObject *a2)
{
  QWidget **v2; // edi@1
  bool v3; // bl@1
  const struct QString *v4; // eax@2
  const struct QString *v5; // eax@3
  _DWORD *v6; // esi@3
  const struct QString *v7; // eax@6
  QObject *v8; // ecx@6
  QWidget *v9; // ecx@6
  const struct QString *v10; // eax@6
  QWidget *v11; // ecx@6
  int v12; // eax@7
  const struct QString *v13; // eax@9
  QObject *v14; // ecx@9
  QWidget *v15; // ecx@9
  const struct QString *v16; // eax@9
  QWidget *v17; // ecx@9
  int v18; // eax@10
  const struct QString *v19; // eax@12
  QObject *v20; // ecx@12
  QWidget *v21; // ecx@12
  const struct QString *v22; // eax@12
  QWidget *v23; // ecx@12
  int v24; // eax@13
  const struct QString *v25; // eax@15
  QObject *v26; // ecx@15
  QWidget *v27; // ecx@15
  const struct QString *v28; // eax@15
  QWidget *v29; // ecx@15
  int v30; // eax@16
  const struct QString *v31; // eax@18
  QObject *v32; // ecx@18
  QWidget *v33; // ecx@18
  const struct QString *v34; // eax@18
  QWidget *v35; // ecx@18
  int v36; // eax@19
  const struct QString *v37; // eax@21
  QObject *v38; // ecx@21
  QWidget *v39; // ecx@21
  const struct QString *v40; // eax@21
  QWidget *v41; // ecx@21
  int v42; // eax@22
  const struct QString *v43; // eax@24
  QObject *v44; // ecx@24
  QWidget *v45; // ecx@24
  const struct QString *v46; // eax@24
  QWidget *v47; // ecx@24
  int v48; // eax@25
  const struct QString *v49; // eax@27
  QObject *v50; // ecx@27
  QWidget *v51; // ecx@27
  const struct QString *v52; // eax@27
  QWidget *v53; // ecx@27
  int v54; // eax@28
  const struct QString *v55; // eax@30
  QObject *v56; // ecx@30
  QWidget *v57; // ecx@30
  const struct QString *v58; // eax@30
  QWidget *v59; // ecx@30
  int v60; // eax@31
  const struct QString *v61; // eax@33
  QObject *v62; // ecx@33
  QWidget *v63; // ecx@33
  const struct QString *v64; // eax@33
  QWidget *v65; // ecx@33
  int v66; // eax@34
  const struct QString *v67; // eax@36
  QObject *v68; // ecx@36
  QWidget *v69; // ecx@36
  const struct QString *v70; // eax@36
  QWidget *v71; // ecx@36
  int v72; // eax@37
  const struct QString *v73; // eax@39
  QObject *v74; // ecx@39
  QWidget *v75; // ecx@39
  const struct QString *v76; // eax@39
  QWidget *v77; // ecx@39
  int v78; // eax@40
  const struct QString *v79; // eax@42
  QObject *v80; // ecx@42
  QWidget *v81; // ecx@42
  const struct QString *v82; // eax@42
  QWidget *v83; // ecx@42
  char v85; // [sp+10h] [bp-28h]@9
  _DWORD *v86; // [sp+18h] [bp-20h]@3
  __int128 v87; // [sp+1Ch] [bp-1Ch]@1
  int v88; // [sp+34h] [bp-4h]@2

  v2 = this;
  v3 = *(*QObject::objectName(a2, &v87 + 12) + 8) == 0;
  QString::~QString((&v87 + 12));
  if ( v3 )
  {
    v4 = QString::fromUtf8(&v87 + 12, "SignalQualityInsight", -1);
    v88 = 0;
    QObject::setObjectName(a2, v4);
    v88 = -1;
    QString::~QString((&v87 + 12));
  }
  *(&v87 + 1) = 987842478280i64;
  QWidget::resize(a2, (&v87 + 8));
  v5 = QString::fromUtf8(&v87 + 12, "background-image: none;", -1);
  v88 = 1;
  QWidget::setStyleSheet(a2, v5);
  v88 = -1;
  QString::~QString((&v87 + 12));
  v6 = operator new(0x14u);
  v86 = v6;
  v88 = 2;
  if ( v6 )
  {
    QWidget::QWidget(a2, 0);
    *v6 = &off_165CFAC;
    v6[2] = &off_165D078;
  }
  else
  {
    v6 = 0;
  }
  v88 = -1;
  *v2 = v6;
  v7 = QString::fromUtf8(&v87 + 12, "s_sensorCQ", -1);
  v8 = *v2;
  v88 = 3;
  QObject::setObjectName(v8, v7);
  v88 = -1;
  QString::~QString((&v87 + 12));
  v9 = *v2;
  _mm_storeu_si128(&v87, _mm_load_si128(&xmmword_1664640));
  QWidget::setGeometry(v9, &v87);
  v10 = QString::fromUtf8(&v87 + 12, "image:url(:/image/image/Sensorsignal/sheadsignal.png);", -1);
  v11 = *v2;
  v88 = 4;
  QWidget::setStyleSheet(v11, v10);
  v88 = -1;
  QString::~QString((&v87 + 12));
  DWORD3(v87) = operator new(0x14u);
  v88 = 5;
  if ( DWORD3(v87) )
  {
    QLabel::QLabel(*v2, 0);
    v12 = DWORD3(v87);
    *DWORD3(v87) = &off_165919C;
    *(v12 + 8) = &off_1659268;
  }
  else
  {
    v12 = 0;
  }
  v2[1] = v12;
  v88 = -1;
  v13 = QString::fromUtf8(&v87 + 12, "sF3", -1);
  v14 = v2[1];
  v88 = 6;
  QObject::setObjectName(v14, v13);
  v88 = -1;
  QString::~QString((&v87 + 12));
  v15 = v2[1];
  _mm_storeu_si128(&v87, _mm_load_si128(&xmmword_1664600));
  QWidget::setGeometry(v15, &v87);
  QFont::QFont(&v85);
  v88 = 7;
  QFont::setPointSize(&v85, 9);
  QFont::setWeight(&v85, 75);
  QFont::setWeight(&v85, 75);
  QWidget::setFont(v2[1], &v85);
  v16 = QString::fromUtf8(&v87 + 12, "\nbackground-image: url(:/Resources/SetUpWidget/Sensorsignal/sF3Black.png);", -1);
  v17 = v2[1];
  LOBYTE(v88) = 8;
  QWidget::setStyleSheet(v17, v16);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  DWORD3(v87) = operator new(0x14u);
  LOBYTE(v88) = 9;
  if ( DWORD3(v87) )
  {
    QLabel::QLabel(*v2, 0);
    v18 = DWORD3(v87);
    *DWORD3(v87) = &off_165919C;
    *(v18 + 8) = &off_1659268;
  }
  else
  {
    v18 = 0;
  }
  v2[2] = v18;
  LOBYTE(v88) = 7;
  v19 = QString::fromUtf8(&v87 + 12, "sF4", -1);
  v20 = v2[2];
  LOBYTE(v88) = 10;
  QObject::setObjectName(v20, v19);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  v21 = v2[2];
  _mm_storeu_si128(&v87, _mm_load_si128(&xmmword_1664610));
  QWidget::setGeometry(v21, &v87);
  QWidget::setFont(v2[2], &v85);
  v22 = QString::fromUtf8(&v87 + 12, "image: url(:/Resources/SetUpWidget/Sensorsignal/sF4Black.png);", -1);
  v23 = v2[2];
  LOBYTE(v88) = 11;
  QWidget::setStyleSheet(v23, v22);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  DWORD3(v87) = operator new(0x14u);
  LOBYTE(v88) = 12;
  if ( DWORD3(v87) )
  {
    QLabel::QLabel(*v2, 0);
    v24 = DWORD3(v87);
    *DWORD3(v87) = &off_165919C;
    *(v24 + 8) = &off_1659268;
  }
  else
  {
    v24 = 0;
  }
  v2[3] = v24;
  LOBYTE(v88) = 7;
  v25 = QString::fromUtf8(&v87 + 12, "sT7", -1);
  v26 = v2[3];
  LOBYTE(v88) = 13;
  QObject::setObjectName(v26, v25);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  v27 = v2[3];
  _mm_storeu_si128(&v87, _mm_load_si128(&xmmword_1664620));
  QWidget::setGeometry(v27, &v87);
  QWidget::setFont(v2[3], &v85);
  v28 = QString::fromUtf8(&v87 + 12, "image: url(:/Resources/SetUpWidget/Sensorsignal/sT7Black.png);", -1);
  v29 = v2[3];
  LOBYTE(v88) = 14;
  QWidget::setStyleSheet(v29, v28);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  DWORD3(v87) = operator new(0x14u);
  LOBYTE(v88) = 15;
  if ( DWORD3(v87) )
  {
    QLabel::QLabel(*v2, 0);
    v30 = DWORD3(v87);
    *DWORD3(v87) = &off_165919C;
    *(v30 + 8) = &off_1659268;
  }
  else
  {
    v30 = 0;
  }
  v2[4] = v30;
  LOBYTE(v88) = 7;
  v31 = QString::fromUtf8(&v87 + 12, "sT8", -1);
  v32 = v2[4];
  LOBYTE(v88) = 16;
  QObject::setObjectName(v32, v31);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  v33 = v2[4];
  _mm_storeu_si128(&v87, _mm_load_si128(&xmmword_1664630));
  QWidget::setGeometry(v33, &v87);
  QWidget::setFont(v2[4], &v85);
  v34 = QString::fromUtf8(&v87 + 12, "image: url(:/Resources/SetUpWidget/Sensorsignal/sT8Black.png);", -1);
  v35 = v2[4];
  LOBYTE(v88) = 17;
  QWidget::setStyleSheet(v35, v34);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  DWORD3(v87) = operator new(0x14u);
  LOBYTE(v88) = 18;
  if ( DWORD3(v87) )
  {
    QLabel::QLabel(*v2, 0);
    v36 = DWORD3(v87);
    *DWORD3(v87) = &off_165919C;
    *(v36 + 8) = &off_1659268;
  }
  else
  {
    v36 = 0;
  }
  v2[5] = v36;
  LOBYTE(v88) = 7;
  v37 = QString::fromUtf8(&v87 + 12, &off_1664340, -1);
  v38 = v2[5];
  LOBYTE(v88) = 19;
  QObject::setObjectName(v38, v37);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  v39 = v2[5];
  _mm_storeu_si128(&v87, _mm_load_si128(&xmmword_1664650));
  QWidget::setGeometry(v39, &v87);
  QWidget::setFont(v2[5], &v85);
  v40 = QString::fromUtf8(&v87 + 12, "image: url(:/Resources/SetUpWidget/Sensorsignal/sPzBlack.png);", -1);
  v41 = v2[5];
  LOBYTE(v88) = 20;
  QWidget::setStyleSheet(v41, v40);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  DWORD3(v87) = operator new(0x14u);
  LOBYTE(v88) = 21;
  if ( DWORD3(v87) )
  {
    QWidget::QWidget(a2, 0);
    v42 = DWORD3(v87);
    *DWORD3(v87) = &off_165CFAC;
    *(v42 + 8) = &off_165D078;
  }
  else
  {
    v42 = 0;
  }
  v2[6] = v42;
  LOBYTE(v88) = 7;
  v43 = QString::fromUtf8(&v87 + 12, "sensorCQ", -1);
  v44 = v2[6];
  LOBYTE(v88) = 22;
  QObject::setObjectName(v44, v43);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  v45 = v2[6];
  _mm_storeu_si128(&v87, _mm_load_si128(&xmmword_16646C0));
  QWidget::setGeometry(v45, &v87);
  v46 = QString::fromUtf8(&v87 + 12, "image:url(:/Resources/SetUpWidget/Sensorsignal/headsignal.png);", -1);
  v47 = v2[6];
  LOBYTE(v88) = 23;
  QWidget::setStyleSheet(v47, v46);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  DWORD3(v87) = operator new(0x14u);
  LOBYTE(v88) = 24;
  if ( DWORD3(v87) )
  {
    QLabel::QLabel(v2[6], 0);
    v48 = DWORD3(v87);
    *DWORD3(v87) = &off_165919C;
    *(v48 + 8) = &off_1659268;
  }
  else
  {
    v48 = 0;
  }
  v2[7] = v48;
  LOBYTE(v88) = 7;
  v49 = QString::fromUtf8(&v87 + 12, "sensorF3", -1);
  v50 = v2[7];
  LOBYTE(v88) = 25;
  QObject::setObjectName(v50, v49);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  v51 = v2[7];
  _mm_storeu_si128(&v87, _mm_load_si128(&xmmword_1664660));
  QWidget::setGeometry(v51, &v87);
  v52 = QString::fromUtf8(&v87 + 12, "image:url(:/Resources/Sensorsignal/F3Black.png);", -1);
  v53 = v2[7];
  LOBYTE(v88) = 26;
  QWidget::setStyleSheet(v53, v52);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  DWORD3(v87) = operator new(0x14u);
  LOBYTE(v88) = 27;
  if ( DWORD3(v87) )
  {
    QLabel::QLabel(v2[6], 0);
    v54 = DWORD3(v87);
    *DWORD3(v87) = &off_165919C;
    *(v54 + 8) = &off_1659268;
  }
  else
  {
    v54 = 0;
  }
  v2[8] = v54;
  LOBYTE(v88) = 7;
  v55 = QString::fromUtf8(&v87 + 12, "sensorT7", -1);
  v56 = v2[8];
  LOBYTE(v88) = 28;
  QObject::setObjectName(v56, v55);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  v57 = v2[8];
  _mm_storeu_si128(&v87, _mm_load_si128(&xmmword_1664690));
  QWidget::setGeometry(v57, &v87);
  v58 = QString::fromUtf8(&v87 + 12, "image:url(:/Resources/Sensorsignal/T7Black.png);", -1);
  v59 = v2[8];
  LOBYTE(v88) = 29;
  QWidget::setStyleSheet(v59, v58);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  DWORD3(v87) = operator new(0x14u);
  LOBYTE(v88) = 30;
  if ( DWORD3(v87) )
  {
    QLabel::QLabel(v2[6], 0);
    v60 = DWORD3(v87);
    *DWORD3(v87) = &off_165919C;
    *(v60 + 8) = &off_1659268;
  }
  else
  {
    v60 = 0;
  }
  v2[9] = v60;
  LOBYTE(v88) = 7;
  v61 = QString::fromUtf8(&v87 + 12, "sensorT8", -1);
  v62 = v2[9];
  LOBYTE(v88) = 31;
  QObject::setObjectName(v62, v61);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  v63 = v2[9];
  _mm_storeu_si128(&v87, _mm_load_si128(&xmmword_16646A0));
  QWidget::setGeometry(v63, &v87);
  v64 = QString::fromUtf8(&v87 + 12, "image:url(:/Resources/Sensorsignal/T8Black.png);", -1);
  v65 = v2[9];
  LOBYTE(v88) = 32;
  QWidget::setStyleSheet(v65, v64);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  DWORD3(v87) = operator new(0x14u);
  LOBYTE(v88) = 33;
  if ( DWORD3(v87) )
  {
    QLabel::QLabel(v2[6], 0);
    v66 = DWORD3(v87);
    *DWORD3(v87) = &off_165919C;
    *(v66 + 8) = &off_1659268;
  }
  else
  {
    v66 = 0;
  }
  v2[10] = v66;
  LOBYTE(v88) = 7;
  v67 = QString::fromUtf8(&v87 + 12, "sensorF4", -1);
  v68 = v2[10];
  LOBYTE(v88) = 34;
  QObject::setObjectName(v68, v67);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  v69 = v2[10];
  _mm_storeu_si128(&v87, _mm_load_si128(&xmmword_1664670));
  QWidget::setGeometry(v69, &v87);
  v70 = QString::fromUtf8(&v87 + 12, "image:url(:/Resources/Sensorsignal/F4Black.png);", -1);
  v71 = v2[10];
  LOBYTE(v88) = 35;
  QWidget::setStyleSheet(v71, v70);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  DWORD3(v87) = operator new(0x14u);
  LOBYTE(v88) = 36;
  if ( DWORD3(v87) )
  {
    QLabel::QLabel(v2[6], 0);
    v72 = DWORD3(v87);
    *DWORD3(v87) = &off_165919C;
    *(v72 + 8) = &off_1659268;
  }
  else
  {
    v72 = 0;
  }
  v2[11] = v72;
  LOBYTE(v88) = 7;
  v73 = QString::fromUtf8(&v87 + 12, "sensorPz", -1);
  v74 = v2[11];
  LOBYTE(v88) = 37;
  QObject::setObjectName(v74, v73);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  v75 = v2[11];
  _mm_storeu_si128(&v87, _mm_load_si128(&xmmword_16646B0));
  QWidget::setGeometry(v75, &v87);
  v76 = QString::fromUtf8(&v87 + 12, "image:url(:/Resources/Sensorsignal/PzBlack.png);", -1);
  v77 = v2[11];
  LOBYTE(v88) = 38;
  QWidget::setStyleSheet(v77, v76);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  DWORD3(v87) = operator new(0x14u);
  LOBYTE(v88) = 39;
  if ( DWORD3(v87) )
  {
    QLabel::QLabel(v2[6], 0);
    v78 = DWORD3(v87);
    *DWORD3(v87) = &off_165919C;
    *(v78 + 8) = &off_1659268;
  }
  else
  {
    v78 = 0;
  }
  v2[12] = v78;
  LOBYTE(v88) = 7;
  v79 = QString::fromUtf8(&v87 + 12, "sensorCMS", -1);
  v80 = v2[12];
  LOBYTE(v88) = 40;
  QObject::setObjectName(v80, v79);
  LOBYTE(v88) = 7;
  QString::~QString((&v87 + 12));
  v81 = v2[12];
  DWORD2(v87) = &v87;
  _mm_storeu_si128(&v87, _mm_load_si128(&xmmword_1664680));
  QWidget::setGeometry(v81, DWORD2(v87));
  v82 = QString::fromUtf8(&v86, "image:url(:/Resources/Sensorsignal/fr3.png);", -1);
  v83 = v2[12];
  LOBYTE(v88) = 41;
  QWidget::setStyleSheet(v83, v82);
  LOBYTE(v88) = 7;
  QString::~QString(&v86);
  QWidget::raise(v2[7]);
  QWidget::raise(v2[10]);
  QWidget::raise(v2[11]);
  QWidget::raise(v2[8]);
  QWidget::raise(v2[9]);
  QWidget::raise(v2[12]);
  QWidget::raise(v2[6]);
  QWidget::raise(*v2);
  sub_1409E00(a2);
  QMetaObject::connectSlotsByName(a2);
  v88 = -1;
  return QFont::~QFont(&v85);
}

@warrenarea
Copy link
Author


void __thiscall sub_1498E80(int *this, int a2)
{
  int *v2; // ebx@1
  int v3; // ecx@1
  int v4; // ST14_4@1
  int v5; // eax@1
  int v6; // esi@1
  int v7; // edi@1
  signed int v8; // ebx@1
  signed int v9; // esi@2
  int v10; // esi@8
  char v11; // [sp+10h] [bp-2Ch]@1
  void *v12; // [sp+18h] [bp-24h]@9
  char v13; // [sp+1Ch] [bp-20h]@1
  int v14; // [sp+20h] [bp-1Ch]@1
  void *v15; // [sp+24h] [bp-18h]@7
  int v16; // [sp+28h] [bp-14h]@1
  int *v17; // [sp+2Ch] [bp-10h]@1
  int v18; // [sp+38h] [bp-4h]@1
  int v19; // [sp+44h] [bp+8h]@1

  v2 = this;
  v17 = this;
  sub_1304FC0(&v13, a2, 0, 0, 0, *(_DWORD *)(a2 + 4) - 1);
  v3 = *(_DWORD *)a2;
  v4 = *(_DWORD *)(a2 + 4) - 1;
  v18 = 0;
  sub_1304FC0(&v11, a2, 1, v3 - 1, 0, v4);
  v5 = *v2;
  v6 = v14;
  LOBYTE(v18) = 1;
  v16 = v14;
  v19 = (*(int (__thiscall **)(int *))(v5 + 84))(v2);
  v7 = 0;
  v8 = sub_14C7540(v19);
  if ( v6 > 0 )
  {
    do
    {
      v9 = 128;
      sub_14C76A0(v19);
      if ( sub_14C76A0(v19) == 2 )
      {
        if ( v8 == 128 )
        {
          v9 = 127;
        }
        else if ( v8 == 256 )
        {
          v9 = 255;
        }
      }
      sub_1307C40(0, v7);
      if ( (signed int)floor(*((double *)v15 + v7)) != v9 )
      {
        sub_1307C40(0, v7);
        v10 = (signed int)floor(*((double *)v15 + v7)) % (v8 / 2);
        if ( v10 < 14 )
        {
          sub_1307C40(0, v7);
          *(_QWORD *)&v17[2 * v10 + 20] = *((_QWORD *)v12 + v7);
        }
      }
      ++v7;
    }
    while ( v7 < v16 );
  }
  if ( v12 )
    operator delete[](v12);
  if ( v15 )
    operator delete[](v15);
}

This function is interesting, because i noticed it Floor's one of the values (brings it to integer)
and then it performs a % division? the v8 was 128 which divided by 2, would then be 64.

obviously this would be some sort of binary math... this function looked promising because...
when I set up a breakpoint, I got it to display just a segment of the data, before breaking.
so could be getting closer. Though looking at the code alone, might be tough... without seeing
what numbers are actually passing through the variables.... I can hover over some of them while
its running and get results... but it can be a little slow going since some of the results are in hex,
while others are in integers.

@warrenarea
Copy link
Author

Also found the function for when the USB dongle is removed, but that's not entirely helpful here.

Emotiv Dongle Plus function, not helpful either, think that's just more HID functions.

Data Acquisition, really thought there would be something to that one, and it does have some
unique data structures, but nothing really jumping out.... these decompilations are sort of
helpful, but can still be confusing without some context.

@ghost
Copy link

ghost commented Apr 28, 2017

v8 in that function could be the counter.

@ghost
Copy link

ghost commented Apr 29, 2017

def quality(reference_class):
  offset? = (this + 64);
  sensor = 0;
  offset_2? = this + 60;
  for sensor in range(0, 5):
    if ( !*(reference_class.current_sensor_value + 28) )
    # if sensor value not positive after + 28 set lowest level.
     quality_value = reference_class.current_sensor_value + sensor + 10 = 0;
    switch (quality_value) 
         0:  Nothing,
         1: Worst,
         2: Bad,
         3: Better,
         4: Good
  # do_something_with_sensor_maybe_set_the_string(v4, v25);
  # v25 = v23;
  # QString::QString(&v25);
  # increment_current_sensor_and_or_something_else(v4++, v25);

@ghost
Copy link

ghost commented Apr 29, 2017

sub_1307C40 <--- this function is important

@ghost
Copy link

ghost commented Apr 29, 2017

sub_14C76A0 <-- this one too

@ghost
Copy link

ghost commented Apr 29, 2017

void __thiscall sub_1498E80(int *this, int a2/length)
{
  int *v2; // ebx@1
  int v3; // ecx@1
  int v4; // ST14_4@1
  int v5; // eax@1
  int v6; // esi@1
  int v7; // edi@1
  signed int v8; // ebx@1
  signed int max_value; // esi@2
  int v10; // esi@8
  char v11; // [sp+10h] [bp-2Ch]@1
  void *v12; // [sp+18h] [bp-24h]@9 <--- interesting location
  char v13; // [sp+1Ch] [bp-20h]@1 <---
  int v14; // [sp+20h] [bp-1Ch]@1 ? What is this
  void *v15; // [sp+24h] [bp-18h]@7
  int v16; // [sp+28h] [bp-14h]@1
  int *v17; // [sp+2Ch] [bp-10h]@1
  int v18; // [sp+38h] [bp-4h]@1
  int v19; // [sp+44h] [bp+8h]@1
  
   v2 = this;
   v17 = this;
   sub_1304FC0(&v13, a2, 0, 0, 0, *(_DWORD *)(a2 + 4) - 1); <-- get character value at bytes/bits? assign to v13?
   v3_bytes = *(_DWORD *)length; <- length of bytes or initial value?
   v4_bytes = *(_DWORD *)(length + 4) - 1; <- length of bytes or initial value?
   v18 = 0;
   sub_1304FC0(&v11, length, 1, v3_bytes - 1, 0, v4_bytes); <-- get character value at bytes/bits? assign to v11?
    v5 = *v2;
    value_size = v14;
   LOBYTE(v18) = 1; ? Unused?
   max_size = v14; Max Bytes/Bits
    v19 = (*(int (__thiscall **)(int *))(v5 + 84))(v2);  ? call this function with 84 added to the first parameter and length is obviously not length then.
    current_bit/byte = 0;
    v8 = sub_14C7540(v19); # Detect speed/battery/extra precision/counter? headset version/mode?
    if ( value_size > 0 )
   {
        do
       {
       max_value = 128;  Max value
       sub_14C76A0(v19); Detect number of bytes?
       if ( sub_14C76A0(v19) == 2 ) 
       {
             if ( v8 == 128 )
             {
                 max_value = 127; # Max Value
             }
             else if ( v8 == 256 )
            {
                 max_value = 255; #  Max Value
            }
      }
  sub_1307C40(0, current_bit); <-- shift?
  # v15 == current value?
  if ( (signed int)floor(*((double *)v15 + current_bit)) != v9 ) # If current_value != max value or battery?
  {
    sub_1307C40(0, current_bit); <-- shift?
    v10 = (signed int)floor(*((double *)v15 + current_bit)) % --> (v8 / 2); <-- precision? 64 or 128 always maybe?
    if ( v10 < 14 ) # 14 is an interesting number old headset logic? some sensor, gyros? quality?
    {
         sub_1307C40(0, current_bit); <-- shift?
         *(_QWORD *)&v17[2 * v10 + 20] = *((_QWORD *)v12 + current_bit);
          Set some bytes to something plus the current bit?
         
        }
     }
     ++current_bit;
   }
    while ( current_bit < max_size );
  }

@ghost
Copy link

ghost commented Apr 29, 2017

There definitely appears to be some juiciness in this function: sub_149D5A0

would like to see that.

@CaptainSmileyXL
Copy link

Is there anywhere I can see a few lines of raw output from the pure eeg program (even if they are screenshots)? There are references in some of the other threads to it's output and the values, I was just hoping I could see some as I play with the output of the various read functions from the Control Panel. And I apologize ahead of time if I have missed a post where this has already been addressed!!!

@warrenarea
Copy link
Author

Terrific news bill... it looks like i've discovered the function for Epoc Plus, that handles evaluating data quality.

@warrenarea
Copy link
Author

int __thiscall sub_300260(int this, char a2, char a3, int a4)
{
  int v4; // edi@1
  _DWORD *v5; // eax@2
  _DWORD *v6; // eax@2
  int v7; // esi@2
  int v9; // eax@3
  int v10; // ecx@3
  unsigned int v11; // esi@3
  unsigned int v12; // eax@5
  int *v13; // ecx@10
  signed int v14; // esi@11
  _DWORD *v15; // eax@14
  int *v16; // edi@15
  _DWORD *v17; // eax@16
  int v18; // ebx@16
  int v19; // esi@17

  v4 = this;
  if ( *sub_2FD670((this + 504), &a3) )
  {
    v5 = sub_2FD670((v4 + 504), &a3);
    --*v5;
    v6 = sub_2FD670((v4 + 488), &a3);
    v7 = a4;
    *v6 = a4;
    *sub_2FD670((v4 + 496), &a3) = v7;
    return 0;
  }
  v9 = sub_2FD700(&a3);
  v10 = v9;
  v11 = *(v9 + 16);
  if ( *(v9 + 20) >= 0x10u )
  {
    v10 = *v9;
  }
  v12 = 8;
  if ( v11 < 8 )
  {
    v12 = v11;
  }
  if ( sub_159A70(v10, "EPOCPLUS", v12) || v11 < 8 || v11 != 8 )
  {
    v14 = 129;
  }
  else
  {
    v13 = (v4 + 472);
    if ( !a2 )
    {
      sub_2FD820(v13, &a3);
      v15 = sub_2FD820((v4 + 472), &a3);
      v14 = floor(round(
                    COERCE_UNSIGNED_INT64(*(*v15 + 8) * 0.03125),
                    COERCE_UNSIGNED_INT64(*(*v15 + 8) * 0.03125) >> 32) * 32.0);
      goto LABEL_15;
    }
    v14 = 256;
    if ( **sub_2FD820(v13, &a3) <= 128.0 )
    {
      v14 = 128;
    }
  }
  if ( a2 )
  {
    v16 = (v4 + 488);
    goto LABEL_16;
  }
LABEL_15:
  v16 = (v4 + 496);
LABEL_16:
  v17 = sub_2FD670(v16, &a3);
  v18 = a4;
  if ( a4 == *v17 )
  {
    v19 = -1;
  }
  else if ( v18 <= *sub_2FD670(v16, &a3) )
  {
    v19 = v18 + v14 - *sub_2FD670(v16, &a3) - 1;
  }
  else
  {
    v19 = v18 - *sub_2FD670(v16, &a3) - 1;
  }
  *sub_2FD670(v16, &a3) = v18;
  return v19;
}

@warrenarea
Copy link
Author

I found this little nugget nested below some "data ACQ thread" in a double precision float.

its obviously some math dealing with Epoc Plus microvoltage, because its multiplaying by 0.03125 (i.e .031)

which is a little confusing now that i think about it, because they have been saying that the microvoltage
is .13 not .31

@warrenarea
Copy link
Author

there is even more math i believe that you will find useful... in the "data Acq thread"

@warrenarea
Copy link
Author

what would be really helpful.... is if Minifiredragon could put a breakpoint in there... and look for the values being returned.

@warrenarea
Copy link
Author

Data Acquisition Thread:


1. 
2. int *__thiscall sub_2FE5C0(_DWORD **this)
3. {
4.   _DWORD **v1; // ebx@1
5.   __m128d v2; // xmm0@1
6.   void (__stdcall ***v3)(_DWORD); // eax@2
7.   void (__thiscall ***v4)(_DWORD, _DWORD); // esi@2
8.   int v5; // eax@3
9.   int *result; // eax@4
10.   int *v7; // esi@4
11.   int v8; // eax@6
12.   int v9; // edi@19
13.   _DWORD *v10; // esi@19
14.   int v11; // eax@19
15.   _DWORD *v12; // ecx@22
16.   _DWORD *v13; // ecx@23
17.   _DWORD *v14; // ecx@23
18.   _DWORD *v15; // edx@23
19.   int *v16; // esi@23
20.   int v17; // ecx@25
21.   signed int v18; // edi@25
22.   int v19; // edx@27
23.   unsigned int v20; // ecx@28
24.   size_t v21; // ecx@29
25.   int v22; // edx@38
26.   unsigned int v23; // ecx@39
27.   unsigned int v24; // ecx@40
28.   int *v25; // edx@48
29.   int v26; // edi@50
30.   int v27; // edx@52
31.   unsigned int v28; // ecx@53
32.   size_t v29; // ecx@54
33.   int v30; // edx@63
34.   unsigned int v31; // ecx@64
35.   unsigned int v32; // ecx@65
36.   char *v33; // edx@73
37.   int v34; // edi@75
38.   int v35; // edx@77
39.   unsigned int v36; // ecx@78
40.   size_t v37; // ecx@79
41.   int v38; // edx@88
42.   unsigned int v39; // ecx@89
43.   unsigned int v40; // ecx@90
44.   void *v41; // eax@98
45.   char v42; // al@99
46.   _DWORD *v43; // ecx@101
47.   _DWORD *v44; // eax@101
48.   size_t v45; // edi@101
49.   void *v46; // eax@102
50.   void *v47; // esi@102
51.   size_t v48; // esi@106
52.   size_t *v49; // ecx@106
53.   size_t v50; // eax@107
54.   __int64 v51; // rax@115
55.   signed int v52; // eax@115
56.   signed int v53; // edi@115
57.   int v54; // edx@115
58.   int v55; // esi@115
59.   _DWORD **v56; // esi@115
60.   void *v57; // ebx@115
61.   int *v58; // ecx@115
62.   void *v59; // edi@115
63.   int v60; // eax@115
64.   double *v61; // esi@115
65.   _DWORD **v62; // ecx@115
66.   void *v63; // eax@122
67.   char v64; // si@123
68.   void (__stdcall ***v65)(_DWORD); // esi@131
69.   void *v66; // eax@134
70.   void *v67; // edi@134
71.   void *v68; // eax@137
72.   void *v69; // edi@137
73.   size_t v70; // eax@140
74.   int (*v71)(void); // edi@140
75.   __int64 v72; // rax@140
76.   int v73; // edi@142
77.   int v74; // eax@142
78.   void *v75; // eax@143
79.   char v76; // al@144
80.   _DWORD *v77; // ecx@146
81.   _DWORD *v78; // edx@146
82.   int v79; // eax@147
83.   _DWORD *v80; // ecx@148
84.   void *v81; // eax@150
85.   size_t v82; // edi@150
86.   unsigned int v83; // edi@153
87.   void *v85; // eax@164
88.   void *v86; // edi@164
89.   void *v87; // eax@167
90.   void *v88; // edi@167
91.   void *v89; // eax@170
92.   void *v90; // edi@170
93.   _DWORD *v91; // ecx@173
94.   __int64 v92; // rax@173
95.   int v93; // eax@173
96.   int v94; // edx@173
97.   unsigned int v95; // edi@173
98.   signed int v96; // eax@177
99.   _DWORD *v97; // eax@180
100.   __int128 v98; // xmm0@180
101.   double **v100; // eax@182
102.   _DWORD *v101; // eax@182
103.   int v102; // eax@183
104.   int *v103; // ecx@183
105.   double **v104; // eax@185
106.   double **v105; // eax@185
107.   double **v106; // eax@187
108.   _DWORD *v107; // eax@187
109.   int v108; // eax@191
110.   size_t v109; // edi@192
111.   void *v111; // eax@195
112.   double *v112; // edx@203
113.   int v113; // eax@204
114.   int v114; // ecx@204
115.   void *v115; // eax@204
116.   size_t v116; // eax@205
117.   int v117; // edx@207
118.   int v118; // eax@207
119.   _DWORD *v119; // ecx@209
120.   int v120; // eax@211
121.   size_t v121; // edi@213
122.   char *headsetType; // ecx@215
123.   unsigned int v123; // edi@215
124.   unsigned int v124; // edx@217
125.   const char *v125; // edi@220
126.   unsigned int v126; // edx@220
127.   bool v127; // cf@224
128.   unsigned __int8 v128; // al@226
129.   unsigned __int8 v129; // al@228
130.   unsigned __int8 v130; // al@230
131.   int v131; // eax@231
132.   bool v132; // zf@233
133.   signed int v133; // eax@236
134.   void *v134; // eax@240
135.   void *v135; // eax@244
136.   char v136; // al@245
137.   _DWORD *v137; // ecx@247
138.   int v138; // eax@247
139.   int v139; // ecx@247
140.   size_t *v140; // eax@247
141.   void **v141; // edi@247
142.   size_t v142; // ecx@248
143.   void *v143; // eax@248
144.   void *v144; // eax@254
145.   void *v145; // edi@254
146.   std::_Container_base0 *v146; // ecx@268
147.   double **v147; // eax@269
148.   char v148; // al@270
149.   _DWORD *v149; // ecx@272
150.   void (__stdcall **v150)(_DWORD); // eax@278
151.   void (__stdcall **j)(_DWORD); // eax@279
152.   void (__stdcall **i)(_DWORD); // eax@282
153.   int *v153; // eax@286
154.   int v154; // edi@286
155.   void *v155; // eax@290
156.   char v156; // al@291
157.   _DWORD *v157; // ecx@293
158.   int v158; // [sp+0h] [bp-1ECh]@1
159.   char v159; // [sp+10h] [bp-1DCh]@247
160.   void *v160; // [sp+18h] [bp-1D4h]@251
161.   char v161; // [sp+1Ch] [bp-1D0h]@290
162.   int v162; // [sp+20h] [bp-1CCh]@290
163.   int v163; // [sp+28h] [bp-1C4h]@290
164.   int v164; // [sp+30h] [bp-1BCh]@290
165.   char v165; // [sp+34h] [bp-1B8h]@290
166.   int v166; // [sp+38h] [bp-1B4h]@290
167.   char v167; // [sp+3Ch] [bp-1B0h]@19
168.   char v168; // [sp+40h] [bp-1ACh]@290
169.   void *v169; // [sp+44h] [bp-1A8h]@290
170.   int v170; // [sp+48h] [bp-1A4h]@290
171.   void *v171; // [sp+4Ch] [bp-1A0h]@290
172.   int v172; // [sp+50h] [bp-19Ch]@290
173.   _DWORD *v173; // [sp+54h] [bp-198h]@290
174.   _DWORD *v174; // [sp+58h] [bp-194h]@290
175.   _DWORD *v175; // [sp+5Ch] [bp-190h]@290
176.   _DWORD *v176; // [sp+60h] [bp-18Ch]@290
177.   void *v177; // [sp+64h] [bp-188h]@290
178.   int v178; // [sp+68h] [bp-184h]@290
179.   void *v179; // [sp+6Ch] [bp-180h]@290
180.   int v180; // [sp+70h] [bp-17Ch]@290
181.   char v181; // [sp+74h] [bp-178h]@150
182.   void *v182; // [sp+7Ch] [bp-170h]@162
183.   int v183; // [sp+80h] [bp-16Ch]@209
184.   void *v184; // [sp+84h] [bp-168h]@115
185.   int v185; // [sp+88h] [bp-164h]@115
186.   int v186; // [sp+8Ch] [bp-160h]@115
187.   int v187; // [sp+90h] [bp-15Ch]@23
188.   void *v188; // [sp+94h] [bp-158h]@115
189.   int v189; // [sp+98h] [bp-154h]@115
190.   int v190; // [sp+9Ch] [bp-150h]@115
191.   int v191; // [sp+A0h] [bp-14Ch]@173
192.   void *v192; // [sp+A4h] [bp-148h]@115
193.   int v193; // [sp+A8h] [bp-144h]@115
194.   int v194; // [sp+ACh] [bp-140h]@115
195.   int v195; // [sp+B0h] [bp-13Ch]@23
196.   int v196; // [sp+B4h] [bp-138h]@23
197.   int v197; // [sp+B8h] [bp-134h]@23
198.   int v198; // [sp+BCh] [bp-130h]@23
199.   int v199; // [sp+C0h] [bp-12Ch]@23
200.   int v200; // [sp+C4h] [bp-128h]@209
201.   int v201; // [sp+C8h] [bp-124h]@209
202.   int v202; // [sp+CCh] [bp-120h]@209
203.   unsigned int v203; // [sp+D0h] [bp-11Ch]@170
204.   int v204; // [sp+D4h] [bp-118h]@170
205.   void *v205; // [sp+D8h] [bp-114h]@173
206.   void *v206; // [sp+DCh] [bp-110h]@180
207.   int v207; // [sp+E0h] [bp-10Ch]@188
208.   int v208; // [sp+E4h] [bp-108h]@188
209.   int v209; // [sp+E8h] [bp-104h]@141
210.   int v210; // [sp+ECh] [bp-100h]@209
211.   unsigned int v211; // [sp+F0h] [bp-FCh]@164
212.   int v212; // [sp+F4h] [bp-F8h]@164
213.   void *v213; // [sp+F8h] [bp-F4h]@167
214.   int v214; // [sp+FCh] [bp-F0h]@209
215.   unsigned int v215; // [sp+100h] [bp-ECh]@167
216.   int v216; // [sp+104h] [bp-E8h]@167
217.   void *v217; // [sp+108h] [bp-E4h]@170
218.   _DWORD **v218; // [sp+10Ch] [bp-E0h]@1
219.   int v219; // [sp+110h] [bp-DCh]@23
220.   int v220; // [sp+114h] [bp-D8h]@150
221.   int v221; // [sp+118h] [bp-D4h]@150
222.   size_t v222; // [sp+11Ch] [bp-D0h]@153
223.   double v223; // [sp+120h] [bp-CCh]@140
224.   double v224; // [sp+128h] [bp-C4h]@1
225.   int v225; // [sp+130h] [bp-BCh]@48
226.   int v226; // [sp+134h] [bp-B8h]@73
227.   int v227; // [sp+138h] [bp-B4h]@23
228.   double v228; // [sp+13Ch] [bp-B0h]@1
229.   void *v229; // [sp+144h] [bp-A8h]@209
230.   _BYTE *v230; // [sp+148h] [bp-A4h]@209
231.   int v231; // [sp+14Ch] [bp-A0h]@209
232.   _DWORD **v232; // [sp+150h] [bp-9Ch]@1
233.   double v233; // [sp+154h] [bp-98h]@115
234.   unsigned int Dst; // [sp+15Ch] [bp-90h]@137
235.   int v235; // [sp+160h] [bp-8Ch]@137
236.   void *v236; // [sp+164h] [bp-88h]@140
237.   int v237; // [sp+168h] [bp-84h]@164
238.   void (__stdcall ***v238)(_DWORD); // [sp+16Ch] [bp-80h]@2
239.   double *v239; // [sp+170h] [bp-7Ch]@167
240.   unsigned int v240; // [sp+174h] [bp-78h]@134
241.   int v241; // [sp+178h] [bp-74h]@134
242.   void *Src; // [sp+17Ch] [bp-70h]@137
243.   double v243; // [sp+180h] [bp-6Ch]@184
244.   size_t v244; // [sp+184h] [bp-68h]@98
245.   int v245; // [sp+188h] [bp-64h]@21
246.   size_t Size; // [sp+18Ch] [bp-60h]@28
247.   void *v247; // [sp+190h] [bp-5Ch]@22
248.   unsigned int v248; // [sp+194h] [bp-58h]@22
249.   int v249; // [sp+198h] [bp-54h]@22
250.   size_t v250; // [sp+19Ch] [bp-50h]@150
251.   size_t v251; // [sp+1A0h] [bp-4Ch]@150
252.   size_t v252; // [sp+1A4h] [bp-48h]@140
253.   void *v253; // [sp+1A8h] [bp-44h]@125
254.   int v254; // [sp+1B8h] [bp-34h]@125
255.   unsigned int v255; // [sp+1BCh] [bp-30h]@125
256.   void *v256; // [sp+1C0h] [bp-2Ch]@23
257.   int v257; // [sp+1D0h] [bp-1Ch]@23
258.   unsigned int v258; // [sp+1D4h] [bp-18h]@23
259.   int *v259; // [sp+1DCh] [bp-10h]@1
260.   int v260; // [sp+1E8h] [bp-4h]@22
261. 
262.   v259 = &v158;
263.   v1 = this;
264.   v232 = this;
265.   v224 = *&qword_3F9A30;
266.   v2 = 0i64;
267.   v218 = this;
268.   v228 = 0.0;
269. LABEL_2:
270.   while ( 1 )
271.   {
272.     v3 = sub_3023D0((v1 + 79), 0);
273.     v4 = v3;
274.     v238 = v3;
275.     if ( v3 )
276.     {
277.       break;
278.     }
279. LABEL_20:
280.     if ( v1[103] < (*(*v1[98] + 4))() )
281.     {
282.       do
283.       {
284.         (*(*v1[98] + 8))(&v245);
285.         if ( v245 == -1 )
286.         {
287.           break;
288.         }
289.         v247 = 0;
290.         v248 = 0;
291.         v249 = 0;
292.         v12 = v1[98];
293.         v260 = 0;
294.         if ( (*(*v12 + 28))(v245, &v247) )
295.         {
296.           goto LABEL_122;
297.         }
298.         (*(*v1[98] + 20))(v245, &v196);
299.         v258 = 15;
300.         v257 = 0;
301.         LOBYTE(v256) = 0;
302.         v13 = v1[98];
303.         LOBYTE(v260) = 3;
304.         (*(*v13 + 32))(v245, &v256);
305.         v14 = v1[98];
306.         v219 = 0;
307.         (*(*v14 + 60))(v245, &v219);
308.         (*(*v1[98] + 40))(v245, &v198);
309.         (*(*v1[98] + 44))(v245, &v199);
310.         (*(*v1[98] + 48))(v245, &v187);
311.         (*(*v1[98] + 52))(v245, &v195);
312.         (*(*v1[98] + 56))(v245, &v197);
313.         v15 = v248;
314.         v16 = v247;
315.         v227 = 53;
316.         if ( &v227 >= v248 || v247 > &v227 )
317.         {
318.           v17 = v249;
319.           if ( v248 == v249 && ((v249 - v248) >> 2) < 1 )
320.           {
321.             v22 = (v248 - v247) >> 2;
322.             if ( (0x3FFFFFFF - v22) < 1 )
323.             {
324.               goto LABEL_121;
325.             }
326.             v23 = (v249 - v247) >> 2;
327.             if ( 0x3FFFFFFF - (v23 >> 1) >= v23 )
328.             {
329.               v24 = (v23 >> 1) + v23;
330.             }
331.             else
332.             {
333.               v24 = 0;
334.             }
335.             if ( v24 < v22 + 1 )
336.             {
337.               v24 = v22 + 1;
338.             }
339.             sub_277E90(v24);
340.             v17 = v249;
341.             v15 = v248;
342.             v16 = v247;
343.           }
344.           if ( v15 )
345.           {
346.             *v15 = 53;
347.             goto LABEL_47;
348.           }
349.         }
350.         else
351.         {
352.           v17 = v249;
353.           v18 = (&v227 - v247) >> 2;
354.           if ( v248 == v249 && ((v249 - v248) >> 2) < 1 )
355.           {
356.             v19 = (v248 - v247) >> 2;
357.             if ( (0x3FFFFFFF - v19) < 1 )
358.             {
359.               goto LABEL_121;
360.             }
361.             v20 = (v249 - v247) >> 2;
362.             Size = v19 + 1;
363.             if ( 0x3FFFFFFF - (v20 >> 1) >= v20 )
364.             {
365.               v21 = (v20 >> 1) + v20;
366.             }
367.             else
368.             {
369.               v21 = 0;
370.             }
371.             if ( v21 < Size )
372.             {
373.               v21 = Size;
374.             }
375.             sub_277E90(v21);
376.             v17 = v249;
377.             v15 = v248;
378.             v16 = v247;
379.           }
380.           if ( v15 )
381.           {
382.             *v15 = v16[v18];
383. LABEL_47:
384.             v17 = v249;
385.             v16 = v247;
386.             v15 = v248;
387.             goto LABEL_48;
388.           }
389.         }
390. LABEL_48:
391.         v25 = v15 + 1;
392.         v225 = 54;
393.         v248 = v25;
394.         if ( &v225 >= v25 || v16 > &v225 )
395.         {
396.           if ( v25 == v17 && ((v17 - v25) >> 2) < 1 )
397.           {
398.             v30 = v25 - v16;
399.             if ( (0x3FFFFFFF - v30) < 1 )
400.             {
401.               goto LABEL_121;
402.             }
403.             v31 = (v17 - v16) >> 2;
404.             if ( 0x3FFFFFFF - (v31 >> 1) >= v31 )
405.             {
406.               v32 = (v31 >> 1) + v31;
407.             }
408.             else
409.             {
410.               v32 = 0;
411.             }
412.             if ( v32 < v30 + 1 )
413.             {
414.               v32 = v30 + 1;
415.             }
416.             sub_277E90(v32);
417.             v17 = v249;
418.             v25 = v248;
419.             v16 = v247;
420.           }
421.           if ( v25 )
422.           {
423.             *v25 = 54;
424.             goto LABEL_72;
425.           }
426.         }
427.         else
428.         {
429.           v26 = &v225 - v16;
430.           if ( v25 == v17 && ((v17 - v25) >> 2) < 1 )
431.           {
432.             v27 = v25 - v16;
433.             if ( (0x3FFFFFFF - v27) < 1 )
434.             {
435.               goto LABEL_121;
436.             }
437.             v28 = (v17 - v16) >> 2;
438.             Size = v27 + 1;
439.             if ( 0x3FFFFFFF - (v28 >> 1) >= v28 )
440.             {
441.               v29 = (v28 >> 1) + v28;
442.             }
443.             else
444.             {
445.               v29 = 0;
446.             }
447.             if ( v29 < Size )
448.             {
449.               v29 = Size;
450.             }
451.             sub_277E90(v29);
452.             v17 = v249;
453.             v25 = v248;
454.             v16 = v247;
455.           }
456.           if ( v25 )
457.           {
458.             *v25 = v16[v26];
459. LABEL_72:
460.             v17 = v249;
461.             v16 = v247;
462.             v25 = v248;
463.             goto LABEL_73;
464.           }
465.         }
466. LABEL_73:
467.         v33 = (v25 + 1);
468.         v226 = 55;
469.         v248 = v33;
470.         if ( &v226 >= v33 || v16 > &v226 )
471.         {
472.           if ( v33 == v17 && ((v17 - v33) >> 2) < 1 )
473.           {
474.             v38 = (v33 - v16) >> 2;
475.             if ( (0x3FFFFFFF - v38) < 1 )
476.             {
477. LABEL_121:
478.               std::_Xlength_error("vector<T> too long");
479. LABEL_122:
480.               v63 = operator new(0x20u);
481.               v244 = v63;
482.               LOBYTE(v260) = 1;
483.               if ( v63 )
484.               {
485.                 v64 = sub_300670(v63);
486.               }
487.               else
488.               {
489.                 v64 = 0;
490.               }
491.               LOBYTE(v260) = 0;
492.               v255 = 15;
493.               v254 = 0;
494.               LOBYTE(v253) = 0;
495.               sub_14C1E0(&v253, "Invalid input device configuration.", 0x23u);
496.               LOBYTE(v260) = 2;
497.               sub_301530(&v253);
498.               LOBYTE(v260) = 0;
499.               if ( v255 >= 0x10 )
500.               {
501.                 operator delete(v253);
502.               }
503.               sub_302A00(v1[102], v64, 0);
504.               v260 = -1;
505.               if ( v247 )
506.               {
507.                 operator delete(v247);
508.                 v247 = 0;
509.                 v248 = 0;
510.                 v249 = 0;
511.               }
512.               break;
513.             }
514.             v39 = (v17 - v16) >> 2;
515.             if ( 0x3FFFFFFF - (v39 >> 1) >= v39 )
516.             {
517.               v40 = (v39 >> 1) + v39;
518.             }
519.             else
520.             {
521.               v40 = 0;
522.             }
523.             if ( v40 < v38 + 1 )
524.             {
525.               v40 = v38 + 1;
526.             }
527.             sub_277E90(v40);
528.             v33 = v248;
529.           }
530.           if ( v33 )
531.           {
532.             *v33 = 55;
533.             goto LABEL_97;
534.           }
535.         }
536.         else
537.         {
538.           v34 = &v226 - v16;
539.           if ( v33 == v17 && ((v17 - v33) >> 2) < 1 )
540.           {
541.             v35 = (v33 - v16) >> 2;
542.             if ( (0x3FFFFFFF - v35) < 1 )
543.             {
544.               goto LABEL_121;
545.             }
546.             v36 = (v17 - v16) >> 2;
547.             Size = v35 + 1;
548.             if ( 0x3FFFFFFF - (v36 >> 1) >= v36 )
549.             {
550.               v37 = (v36 >> 1) + v36;
551.             }
552.             else
553.             {
554.               v37 = 0;
555.             }
556.             if ( v37 < Size )
557.             {
558.               v37 = Size;
559.             }
560.             sub_277E90(v37);
561.             v33 = v248;
562.             v16 = v247;
563.           }
564.           if ( v33 )
565.           {
566.             *v33 = v16[v34];
567. LABEL_97:
568.             v33 = v248;
569.             goto LABEL_98;
570.           }
571.         }
572. LABEL_98:
573.         v248 = (v33 + 4);
574.         v41 = operator new(0x50u);
575.         v244 = v41;
576.         LOBYTE(v260) = 4;
577.         if ( v41 )
578.         {
579.           v42 = sub_3008D0(v41, v245, v196, &v247, &v256, v219, v198, v199, v187, v195, v197);
580.         }
581.         else
582.         {
583.           v42 = 0;
584.         }
585.         v43 = v1[102];
586.         LOBYTE(v260) = 3;
587.         sub_302A00(v43, v42, 0);
588.         v44 = operator new(0xCu);
589.         v45 = v44;
590.         v244 = v44;
591.         LOBYTE(v260) = 5;
592.         if ( v44 )
593.         {
594.           *v44 = 1;
595.           v44[1] = 1;
596.           Size = 8;
597.           v46 = new_array(8u);
598.           v47 = v46;
599.           if ( v46 )
600.           {
601.             memset(v46, 0, Size);
602.             *(v45 + 8) = v47;
603.           }
604.           else
605.           {
606.             *(v45 + 8) = 0;
607.           }
608.         }
609.         else
610.         {
611.           v45 = 0;
612.         }
613.         v48 = v45;
614.         Size = v45;
615.         LOBYTE(v260) = 6;
616.         v49 = sub_2FD790(&v245);
617.         if ( v49 != &Size )
618.         {
619.           v48 = 0;
620.           Size = *v49;
621.           v50 = Size;
622.           *v49 = v45;
623.           if ( v50 )
624.           {
625.             if ( *(v50 + 8) )
626.             {
627.               operator delete[](*(v50 + 8));
628.               v50 = Size;
629.             }
630.             operator delete(v50);
631.           }
632.         }
633.         LOBYTE(v260) = 3;
634.         if ( v48 )
635.         {
636.           if ( *(v48 + 8) )
637.           {
638.             operator delete[](*(v48 + 8));
639.           }
640.           operator delete(v48);
641.         }
642.         v1[103] = (v1[103] + 1);
643.         LODWORD(v51) = Xtime_get_ticks();
644.         reverse_bits(v51 - v1[96], (v51 - *(v1 + 48)) >> 32);
645.         v233 = v2.m128d_f64[0];
646.         reverse_bits(10000000, 0);
647.         v233 = v233 / v2.m128d_f64[0];
648.         reverse_bits(1000, 0);
649.         v2.m128d_f64[0] = v2.m128d_f64[0] * v233;
650.         sub_3BD63F(v2);
651.         v53 = v52;
652.         v55 = v54;
653.         sub_2FCFF0(&v184, 2);
654.         LOBYTE(v260) = 7;
655.         reverse_bits(v53, v55);
656.         v56 = v232;
657.         v57 = v184;
658.         v58 = (v232 + 112);
659.         *v184 = _mm_unpckl_pd(v2, v2);
660.         sub_2FD820(v58, &v245);
661.         sub_2FD550(&v184);
662.         *sub_2FD670(v56 + 126, &v245) = 0;
663.         sub_2FCFF0(&v188, 2);
664.         v59 = v188;
665.         LOBYTE(v260) = 8;
666.         *v188 = xmmword_4CB160;
667.         sub_2FD820(v56 + 118, &v245);
668.         sub_2FD550(&v188);
669.         *sub_2FD670(v56 + 122, &v245) = 0;
670.         v60 = sub_2FD700(&v245);
671.         sub_14C1E0(v60, "EPOC", 4u);
672.         sub_2FCFF0(&v192, 2);
673.         v61 = v192;
674.         LOBYTE(v260) = 9;
675.         v62 = v232;
676.         *v192 = v224;
677.         v2 = *&v228;
678.         v61[1] = v228;
679.         sub_2FD820(v62 + 114, &v245);
680.         sub_2FD550(&v192);
681.         operator delete(v61);
682.         v192 = 0;
683.         v193 = 0;
684.         v194 = 0;
685.         operator delete(v59);
686.         v188 = 0;
687.         v189 = 0;
688.         v190 = 0;
689.         operator delete(v57);
690.         v184 = 0;
691.         v185 = 0;
692.         v186 = 0;
693.         if ( v258 >= 0x10 )
694.         {
695.           operator delete(v256);
696.         }
697.         v258 = 15;
698.         v257 = 0;
699.         LOBYTE(v256) = 0;
700.         v260 = -1;
701.         if ( v247 )
702.         {
703.           operator delete(v247);
704.           v247 = 0;
705.           v248 = 0;
706.           v249 = 0;
707.         }
708.         v1 = v232;
709.       }
710.       while ( v1[103] < (*(*v232[98] + 4))() );
711.     }
712.     if ( !v1[103] )
713.     {
714.       sub_3262B0(0xAu);
715.       continue;
716.     }
717.     v65 = *v1[99];
718. LABEL_132:
719.     v238 = v65;
720.     while ( 1 )
721.     {
722.       if ( v65 == v1[99] )
723.       {
724.         goto LABEL_2;
725.       }
726.       v240 = 1;
727.       v241 = 1;
728.       Size = 8;
729.       v66 = new_array(8u);
730.       v67 = v66;
731.       if ( v66 )
732.       {
733.         memset(v66, 0, Size);
734.       }
735.       else
736.       {
737.         v67 = 0;
738.       }
739.       Src = v67;
740.       v260 = 10;
741.       Dst = 1;
742.       v235 = 1;
743.       Size = 8;
744.       v68 = new_array(8u);
745.       v69 = v68;
746.       if ( v68 )
747.       {
748.         memset(v68, 0, Size);
749.       }
750.       else
751.       {
752.         v69 = 0;
753.       }
754.       v236 = v69;
755.       v70 = v65[4];
756.       v71 = Xtime_get_ticks;
757.       LOBYTE(v260) = 11;
758.       v252 = v70;
759.       LODWORD(v72) = Xtime_get_ticks();
760.       reverse_bits(v72 - v1[94], (v72 - *(v1 + 47)) >> 32);
761.       v223 = v2.m128d_f64[0];
762.       reverse_bits(10000, 0);
763.       if ( v223 / v2.m128d_f64[0] > 1000.0 )
764.       {
765.         (*(*v1[98] + 24))(v252, &v209);
766.         if ( ((*v1)[10])(v1, v252) )
767.         {
768.           v73 = *v1[107];
769.           v74 = ((*v1)[9])(v1, v252, v209 == 0);
770.           (*(v73 + 28))(v1[107], v74);
771.           v71 = Xtime_get_ticks;
772.         }
773.         v75 = operator new(0x10u);
774.         v244 = v75;
775.         LOBYTE(v260) = 12;
776.         if ( v75 )
777.         {
778.           v76 = sub_300AB0(v75, v252, v209);
779.         }
780.         else
781.         {
782.           v76 = 0;
783.         }
784.         v77 = v1[102];
785.         LOBYTE(v260) = 11;
786.         sub_302A00(v77, v76, 0);
787.         v1[94] = v71();
788.         v1[95] = v78;
789.       }
790.       v79 = (*(*v1[98] + 16))(v252, &v240);
791.       Size = 3;
792.       if ( !v79 )
793.       {
794.         v80 = v1[98];
795.         LOBYTE(v260) = 13;
796.         Size = (*(*v80 + 36))(v252, &Dst, v240);
797.         if ( v241 == 23 || v241 == 27 )
798.         {
799.           sub_1BA1B0(&v181);
800.           LOBYTE(v260) = 14;
801.           v220 = 1;
802.           v221 = 12;
803.           v251 = 96;
804.           v81 = new_array(0x60u);
805.           v82 = v81;
806.           v250 = v81;
807.           if ( v81 )
808.           {
809.             memset(v81, 0, v251);
810.           }
811.           else
812.           {
813.             v82 = 0;
814.             v250 = 0;
815.           }
816.           v222 = v82;
817.           LOBYTE(v260) = 15;
818.           new_list_array(&v220);
819.           v83 = 0;
820.           LOBYTE(v260) = 16;
821.           if ( Dst * v235 != 1 )
822.           {
823.             goto LABEL_299;
824.           }
825.           v2 = *v236;
826.           __asm { lahf }
827.           if ( __SETP__(_AH & 0x44, 0) )
828.           {
829. LABEL_299:
830.             v83 = Dst;
831.             if ( Dst >= v240 )
832.             {
833.               v83 = v240;
834.             }
835.             sub_280180(&Dst, 2);
836.             sub_167C40(&Dst, 0, 0);
837.             v251 = v236;
838.             sub_167C40(&v220, 0, 0);
839.             *v250 = *v251;
840.             sub_167C40(&Dst, 0, 1u);
841.             v251 = v236;
842.             sub_167C40(&v220, 0, 1u);
843.             *(v250 + 8) = *(v251 + 8);
844.             sub_167C40(&Dst, 0, 2u);
845.             v251 = v236;
846.             sub_167C40(&v220, 0, 2u);
847.             *(v250 + 16) = *(v251 + 16);
848.             sub_167C40(&Dst, 0, 3u);
849.             v251 = v236;
850.             sub_167C40(&v220, 0, 3u);
851.             v2 = *(v251 + 24);
852.             *(v250 + 24) = v2.m128d_f64[0];
853.           }
854.           while ( v83 < v240 )
855.           {
856.             sub_280180(&v220, 2);
857.             ++v83;
858.             v250 = v222;
859.           }
860.           concat_items(&v240, &v181, 2);
861.           if ( v250 )
862.           {
863.             operator delete[](v250);
864.           }
865.           LOBYTE(v260) = 13;
866.           if ( v182 )
867.           {
868.             operator delete[](v182);
869.           }
870.         }
871.         v211 = v240;
872.         v212 = 1;
873.         v251 = 8 * v240 | -(v240 >> 29 != 0);
874.         v85 = new_array(v251);
875.         v86 = v85;
876.         v237 = v85;
877.         if ( v85 )
878.         {
879.           memset(v85, 0, v251);
880.         }
881.         else
882.         {
883.           v86 = 0;
884.           v237 = 0;
885.         }
886.         v213 = v86;
887.         LOBYTE(v260) = 17;
888.         new_list_array(&v211);
889.         v215 = v240;
890.         LOBYTE(v260) = 18;
891.         v216 = 1;
892.         v251 = 8 * v240 | -(v240 >> 29 != 0);
893.         v87 = new_array(v251);
894.         v88 = v87;
895.         v239 = v87;
896.         if ( v87 )
897.         {
898.           memset(v87, 0, v251);
899.         }
900.         else
901.         {
902.           v88 = 0;
903.           v239 = 0;
904.         }
905.         v217 = v88;
906.         LOBYTE(v260) = 19;
907.         new_list_array(&v215);
908.         v203 = v240;
909.         LOBYTE(v260) = 20;
910.         v204 = 1;
911.         v250 = 8 * v240 | -(v240 >> 29 != 0);
912.         v89 = new_array(v250);
913.         v90 = v89;
914.         v251 = v89;
915.         if ( v89 )
916.         {
917.           memset(v89, 0, v250);
918.         }
919.         else
920.         {
921.           v90 = 0;
922.           v251 = 0;
923.         }
924.         v205 = v90;
925.         LOBYTE(v260) = 21;
926.         new_list_array(&v203);
927.         v91 = v1[98];
928.         LOBYTE(v260) = 22;
929.         (*(*v91 + 52))(v252, &v191);
930.         LODWORD(v92) = Xtime_get_ticks();
931.         v93 = sub_3BD860(v92 - *(v1 + 48), 0x2710u, 0);
932.         reverse_bits(v93, v94);
933.         v2.m128d_f64[0] = v2.m128d_f64[0] / 1000.0;
934.         v95 = 0;
935.         v233 = v2.m128d_f64[0];
936.         while ( v95 < v240 )
937.         {
938.           sub_167C40(&v240, v95, 5u);
939.           if ( *(Src + v241 * v95 + 5) > v228 )
940.           {
941.             v1[111] = (v1[111] + 1);
942.           }
943.           sub_167C40(&v240, v95, 0x13u);
944.           v96 = floor(*(Src + v241 * v95 + 19));
945.           if ( v191 != 2 || v96 != 32 )
946.           {
947.             v97 = sub_2FD820(v1 + 114, &v252);
948.             sub_22E250(v97);
949.             LOBYTE(v260) = 23;
950.             v98 = *v206;
951.             __asm { lahf }
952.             if ( __SETP__(_AH & 0x44, 0) && v233 - *(v206 + 1) > 0.5 )
953.             {
954.               sub_167C40(&v211, v95, 0);
955.               *(v237 + 8 * v95) = v233;
956.               sub_167C40(&v215, v95, 0);
957.               v239[v95] = v233;
958.               v100 = sub_2FD820(v1 + 112, &v252);
959.               **v100 = v233;
960.               v101 = sub_2FD820(v1 + 112, &v252);
961.               *(*v101 + 8) = v233;
962.               *sub_2FD670(v1 + 126, &v252) = 1;
963.             }
964.             else
965.             {
966.               sub_167C40(&v240, v95, 1u);
967.               v244 = floor(*(Src + v241 * v95 + 1));
968.               v250 = v252;
969.               v223 = **sub_2FD820(v1 + 118, &v250);
970.               v102 = sub_300260(v1, 1, v250, v244);
971.               v103 = (v1 + 112);
972.               if ( v102 == -1 )
973.               {
974.                 v243 = **sub_2FD820(v103, &v250);
975.               }
976.               else
977.               {
978.                 v243 = v102 / v223;
979.                 v104 = sub_2FD820(v103, &v250);
980.                 v243 = v224 / v223 + **v104 + v243;
981.                 v105 = sub_2FD820(v1 + 112, &v250);
982.                 **v105 = v243;
983.               }
984.               sub_167C40(&v211, v95, 0);
985.               *(v237 + 8 * v95) = v243;
986.               v244 = *sub_2FD820(v1 + 112, &v252) + 8;
987.               sub_167C40(&v215, v95, 0);
988.               v239[v95] = *v244;
989.             }
990.             v106 = sub_2FD820(v1 + 114, &v252);
991.             **v106 = v224;
992.             v107 = sub_2FD820(v1 + 114, &v252);
993.             LOBYTE(v260) = 22;
994.             *(*v107 + 8) = v233;
995.             if ( v206 )
996.             {
997.               std::_Container_base0::_Orphan_all(&v206);
998.               operator delete(v206);
999.               v206 = 0;
1000.               v207 = 0;
1001.               v208 = 0;
1002.             }
1003.           }
1004.           else
1005.           {
1006.             sub_167C40(&v240, v95, 1u);
1007.             v250 = v241 * v95;
1008.             v244 = Src;
1009.             sub_167C40(&v215, v95, 0);
1010.             v223 = sub_2FDAE0(v252, floor(*(v244 + 8 * v250 + 8)));
1011.             v239[v95] = v223;
1012.             v244 = *sub_2FD820(v1 + 112, &v252);
1013.             sub_167C40(&v211, v95, 0);
1014.             *(v237 + 8 * v95) = *v244;
1015.           }
1016.           sub_167C40(&v203, v95, 0);
1017.           v2 = *&v233;
1018.           *(v251 + 8 * v95++) = v233;
1019.         }
1020.         concat_items(&v240, &v211, 2);
1021.         concat_items(&v240, &v203, 2);
1022.         concat_items(&v240, &v215, 2);
1023.         if ( ((*v1)[10])(v1, v252) )
1024.         {
1025.           v108 = ((*v1)[9])(v1, v252);
1026.           (*(*v1[107] + 16))(v108, &v240);
1027.         }
1028.         v109 = *sub_2FD790(&v252);
1029.         v250 = v109;
1030.         if ( *(v109 + 4) * *v109 != 1 )
1031.         {
1032.           goto LABEL_300;
1033.         }
1034.         v2 = **(v109 + 8);
1035.         __asm { lahf }
1036.         if ( __SETP__(_AH & 0x44, 0) )
1037.         {
1038. LABEL_300:
1039.           sub_280180(&v240, 2);
1040.         }
1041.         else if ( v109 != &v240 )
1042.         {
1043.           *v109 = v240;
1044.           *(v109 + 4) = v241;
1045.           v244 = 8 * v241 * *v109 | -((v241 * *v109) >> 29 != 0);
1046.           v111 = new_array(v244);
1047.           v251 = v111;
1048.           if ( v111 )
1049.           {
1050.             memset(v111, 0, v244);
1051.           }
1052.           else
1053.           {
1054.             v251 = 0;
1055.           }
1056.           if ( *(v109 + 8) )
1057.           {
1058.             operator delete[](*(v109 + 8));
1059.           }
1060.           *(v109 + 8) = v251;
1061.           memmove(*(v109 + 8), Src, 8 * *(v109 + 4) * *v109 & 0xFFFFFFF8);
1062.         }
1063.         if ( v1[111] >= v1[101] )
1064.         {
1065.           v112 = operator new(0xCu);
1066.           v239 = v112;
1067.           v251 = v112;
1068.           LOBYTE(v260) = 24;
1069.           if ( v112 )
1070.           {
1071.             v113 = *v109;
1072.             *v112 = *v109;
1073.             v114 = *(v109 + 4);
1074.             *(v112 + 1) = v114;
1075.             v244 = 8 * v114 * v113 | -((v114 * v113) >> 29 != 0);
1076.             v115 = new_array(v244);
1077.             v251 = v115;
1078.             if ( v115 )
1079.             {
1080.               memset(v115, 0, v244);
1081.               v116 = v251;
1082.             }
1083.             else
1084.             {
1085.               v116 = 0;
1086.             }
1087.             v117 = v239;
1088.             *(v239 + 2) = v116;
1089.             memmove(*(v117 + 8), *(v109 + 8), 8 * *(v109 + 4) * *v109 & 0xFFFFFFF8);
1090.             v118 = v239;
1091.           }
1092.           else
1093.           {
1094.             v118 = 0;
1095.             v239 = 0;
1096.           }
1097.           LOBYTE(v260) = 22;
1098.           sub_16C010(v118);
1099.           v258 = 15;
1100.           v257 = 0;
1101.           LOBYTE(v256) = 0;
1102.           v119 = v1[98];
1103.           LOBYTE(v260) = 25;
1104.           (*(*v119 + 32))(v252, &v256);
1105.           (*(*v1[98] + 40))(v252, &v214);
1106.           (*(*v1[98] + 44))(v252, &v200);
1107.           (*(*v1[98] + 20))(v252, &v210);
1108.           (*(*v1[98] + 48))(v252, &v201);
1109.           (*(*v1[98] + 52))(v252, &v202);
1110.           (*(*v1[98] + 56))(v252, &v183);
1111.           v229 = 0;
1112.           v230 = 0;
1113.           v231 = 0;
1114.           LOBYTE(v260) = 26;
1115.           v255 = 15;
1116.           v254 = 0;
1117.           LOBYTE(v253) = 0;
1118.           sub_14C1E0(&v253, ":,", 2u);
1119.           LOBYTE(v260) = 27;
1120.           sub_1B9D00(&v256, &v229, &v253);
1121.           LOBYTE(v260) = 26;
1122.           if ( v255 >= 0x10 )
1123.           {
1124.             operator delete(v253);
1125.           }
1126.           v120 = (v230 - v229) / 24;
1127.           if ( v120 && !(v120 & 1) )
1128.           {
1129.             v121 = 0;
1130.             while ( 2 )
1131.             {
1132.               v251 = v121;
1133.               if ( v121 >= (v230 - v229) / 24 )
1134.               {
1135.                 v109 = v250;
1136.                 break;
1137.               }
1138.               v127 = *(v229 + 6 * v121 + 5) < 0x10u;
1139.               headsetType = v229 + 24 * v121;
1140.               v123 = *(headsetType + 4);
1141.               v237 = (headsetType + 24);
1142.               v244 = v123;
1143.               if ( !v127 )
1144.               {
1145.                 headsetType = *headsetType;
1146.               }
1147.               v124 = 11;
1148.               if ( v123 < 0xB )
1149.               {
1150.                 v124 = v123;
1151.               }
1152.               if ( !v124 )
1153.               {
1154.                 goto LABEL_235;
1155.               }
1156.               v125 = "headsetType";
1157.               v127 = v124 < 4;
1158.               v126 = v124 - 4;
1159.               if ( v127 )
1160.               {
1161. LABEL_223:
1162.                 if ( v126 != -4 )
1163.                 {
1164.                   goto LABEL_224;
1165.                 }
1166.               }
1167.               else
1168.               {
1169.                 while ( *headsetType == *v125 )
1170.                 {
1171.                   headsetType += 4;
1172.                   v125 += 4;
1173.                   v127 = v126 < 4;
1174.                   v126 -= 4;
1175.                   if ( v127 )
1176.                   {
1177.                     goto LABEL_223;
1178.                   }
1179.                 }
1180. LABEL_224:
1181.                 v127 = *headsetType < *v125;
1182.                 if ( *headsetType != *v125
1183.                   || v126 != -3
1184.                   && ((v128 = headsetType[1], v127 = v128 < v125[1], v128 != v125[1])
1185.                    || v126 != -2
1186.                    && ((v129 = headsetType[2], v127 = v129 < v125[2], v129 != v125[2])
1187.                     || v126 != -1 && (v130 = headsetType[3], v127 = v130 < v125[3], v130 != v125[3]))) )
1188.                 {
1189.                   v131 = -v127 | 1;
1190.                   goto LABEL_233;
1191.                 }
1192.               }
1193.               v131 = 0;
1194. LABEL_233:
1195.               v132 = v131 == 0;
1196.               if ( v131 )
1197.               {
1198.                 goto LABEL_239;
1199.               }
1200.               v123 = v244;
1201. LABEL_235:
1202.               if ( v123 >= 0xB )
1203.               {
1204.                 v133 = v123 != 11;
1205.               }
1206.               else
1207.               {
1208.                 v133 = -1;
1209.               }
1210.               v132 = v133 == 0;
1211. LABEL_239:
1212.               if ( v132 )
1213.               {
1214.                 v134 = sub_2FD700(&v252);
1215.                 if ( v134 != v237 )
1216.                 {
1217.                   sub_14C0C0(v134, v237, 0, 0xFFFFFFFF);
1218.                 }
1219.               }
1220.               v121 = v251 + 2;
1221.               continue;
1222.             }
1223.           }
1224.           sub_2FDC00(v1, v252, v210, v214);
1225.           v135 = operator new(0x40u);
1226.           v244 = v135;
1227.           LOBYTE(v260) = 28;
1228.           if ( v135 )
1229.           {
1230.             v136 = sub_300820(v135, v252, v239, &v256, v214, v200, v210, v201, v202, v183);
1231.           }
1232.           else
1233.           {
1234.             v136 = 0;
1235.           }
1236.           v137 = v1[102];
1237.           LOBYTE(v260) = 26;
1238.           sub_302A00(v137, v136, 0);
1239.           v138 = sub_1BA1B0(&v159);
1240.           *v109 = *v138;
1241.           v139 = *(v138 + 4);
1242.           v140 = (v138 + 8);
1243.           *(v109 + 4) = v139;
1244.           v141 = (v109 + 8);
1245.           if ( v141 != v140 )
1246.           {
1247.             v142 = *v140;
1248.             *v140 = 0;
1249.             v143 = *v141;
1250.             v244 = v142;
1251.             if ( v143 )
1252.             {
1253.               operator delete[](v143);
1254.               v142 = v244;
1255.             }
1256.             *v141 = v142;
1257.           }
1258.           if ( v160 )
1259.           {
1260.             operator delete[](v160);
1261.           }
1262.           v132 = v229 == 0;
1263.           v1[111] = 0;
1264.           LOBYTE(v260) = 25;
1265.           if ( !v132 )
1266.           {
1267.             std::_Container_base0::_Orphan_all(&v229);
1268.             v144 = v230;
1269.             v145 = v229;
1270.             v244 = v230;
1271.             if ( v229 != v230 )
1272.             {
1273.               do
1274.               {
1275.                 if ( *(v145 + 5) >= 0x10u )
1276.                 {
1277.                   operator delete(*v145);
1278.                   v144 = v244;
1279.                 }
1280.                 *(v145 + 5) = 15;
1281.                 *(v145 + 4) = 0;
1282.                 *v145 = 0;
1283.                 v145 = v145 + 24;
1284.               }
1285.               while ( v145 != v144 );
1286.               v145 = v229;
1287.             }
1288.             operator delete(v145);
1289.             v229 = 0;
1290.             v230 = 0;
1291.             v231 = 0;
1292.           }
1293.           LOBYTE(v260) = 22;
1294.           if ( v258 >= 0x10 )
1295.           {
1296.             operator delete(v256);
1297.           }
1298.         }
1299.         std::_Container_base0::_Orphan_all((v1 + 104));
1300.         v1[105] = v1[104];
1301.         if ( v205 )
1302.         {
1303.           operator delete[](v205);
1304.         }
1305.         if ( v217 )
1306.         {
1307.           operator delete[](v217);
1308.         }
1309.         if ( v213 )
1310.         {
1311.           operator delete[](v213);
1312.         }
1313.         goto LABEL_273;
1314.       }
1315.       v146 = (v1 + 104);
1316.       if ( v79 != 3 )
1317.       {
1318.         break;
1319.       }
1320.       std::_Container_base0::_Orphan_all(v146);
1321.       v1[105] = v1[104];
1322.       v147 = sub_2FD820(v1 + 114, &v252);
1323.       v2 = *&v228;
1324.       **v147 = v228;
1325.       v244 = operator new(0xCu);
1326.       LOBYTE(v260) = 30;
1327.       if ( v244 )
1328.       {
1329.         v148 = sub_300990(v252);
1330.       }
1331.       else
1332.       {
1333.         v148 = 0;
1334.       }
1335.       v149 = v1[102];
1336.       LOBYTE(v260) = 11;
1337.       sub_302A00(v149, v148, 0);
1338. LABEL_273:
1339.       if ( v236 )
1340.       {
1341.         operator delete[](v236);
1342.       }
1343.       v260 = -1;
1344.       if ( Src )
1345.       {
1346.         operator delete[](Src);
1347.       }
1348.       if ( !*(v65 + 13) )
1349.       {
1350.         v150 = v65[2];
1351.         if ( *(v150 + 13) )
1352.         {
1353.           for ( i = v65[1]; !*(i + 13); i = i[1] )
1354.           {
1355.             if ( v65 != i[2] )
1356.             {
1357.               break;
1358.             }
1359.             v65 = i;
1360.           }
1361.           v65 = i;
1362.         }
1363.         else
1364.         {
1365.           v65 = v65[2];
1366.           for ( j = *v150; !*(j + 13); j = *j )
1367.           {
1368.             v65 = j;
1369.           }
1370.         }
1371.         goto LABEL_132;
1372.       }
1373.     }
1374.     std::_Container_base0::_Orphan_all(v146);
1375.     v1[105] = v1[104];
1376.     v153 = sub_2FD790(&v252);
1377.     v154 = *v153;
1378.     *v153 = 0;
1379.     if ( v154 )
1380.     {
1381.       if ( *(v154 + 8) )
1382.       {
1383.         operator delete[](*(v154 + 8));
1384.       }
1385.       operator delete(v154);
1386.     }
1387.     (*(*v1[98] + 12))(v252);
1388.     sub_2FE0B0(&v168, v65);
1389.     v1[103] = (v1[103] - 1);
1390.     sub_2FD9B0(v1 + 112, &v169, &v252);
1391.     sub_15D7E0(v1 + 112, &v166, v169, v170);
1392.     sub_2FD9B0(v1 + 120, &v179, &v252);
1393.     sub_28D010(v1 + 120, &v164, v179, v180);
1394.     sub_2FD9B0(v1 + 122, &v175, &v252);
1395.     sub_291F20(v1 + 122, &v161, v175, v176);
1396.     sub_2FD9B0(v1 + 118, &v171, &v252);
1397.     sub_15D7E0(v1 + 118, &v162, v171, v172);
1398.     sub_2FD9B0(v1 + 114, &v177, &v252);
1399.     sub_15D7E0(v1 + 114, &v163, v177, v178);
1400.     sub_2FD9B0(v1 + 126, &v173, &v252);
1401.     sub_291F20(v1 + 126, &v165, v173, v174);
1402.     ((*v1)[10])(v1, v252);
1403.     ((*v1)[8])(v1, v252);
1404.     v155 = operator new(0xCu);
1405.     v244 = v155;
1406.     LOBYTE(v260) = 31;
1407.     if ( v155 )
1408.     {
1409.       v156 = sub_3009C0(v155, v252);
1410.     }
1411.     else
1412.     {
1413.       v156 = 0;
1414.     }
1415.     v157 = v1[102];
1416.     LOBYTE(v260) = 11;
1417.     sub_302A00(v157, v156, 0);
1418.     if ( v236 )
1419.     {
1420.       operator delete[](v236);
1421.     }
1422.     v260 = -1;
1423.     if ( Src )
1424.     {
1425.       operator delete[](Src);
1426.     }
1427.   }
1428.   v5 = sub_2367D0(v3);
1429.   if ( v5 != 9 )
1430.   {
1431.     if ( v5 == 11 )
1432.     {
1433.       ((*v1)[6])(v1, v4);
1434.     }
1435.     else if ( v5 == 13 )
1436.     {
1437.       v9 = *v1;
1438.       v10 = sub_301270(v4, &v167);
1439.       v11 = sub_291C60(v238);
1440.       (*(v9 + 28))(v1, *v10, v11);
1441.       (**v238)(1);
1442.     }
1443.     goto LABEL_20;
1444.   }
1445.   (**v4)(v4, 1);
1446.   result = v1[99];
1447.   v7 = *result;
1448.   if ( *result != result )
1449.   {
1450.     do
1451.     {
1452.       result = (*(*v1[98] + 12))(v7[4]);
1453.       if ( !*(v7 + 13) )
1454.       {
1455.         v8 = v7[2];
1456.         if ( *(v8 + 13) )
1457.         {
1458.           for ( result = v7[1]; !*(result + 13); result = result[1] )
1459.           {
1460.             if ( v7 != result[2] )
1461.             {
1462.               break;
1463.             }
1464.             v7 = result;
1465.           }
1466.           v7 = result;
1467.         }
1468.         else
1469.         {
1470.           v7 = v7[2];
1471.           for ( result = *v8; !*(result + 13); result = *result )
1472.           {
1473.             v7 = result;
1474.           }
1475.         }
1476.       }
1477.     }
1478.     while ( v7 != v1[99] );
1479.   }
1480.   return result;
1481. }
1482. 
1483. 

@warrenarea
Copy link
Author

again, this is part of the data acquisition thread.
i posted this because... it gets interesting right around line 642

i renamed the function "reverse_bits" because that Sub is linked to a function
that says it reverses the bits.

and then after that, you'll notice there is a negotiation between 64-bit Floating doubles.

and then a little bit below, a function to "floor"

@warrenarea
Copy link
Author

another nearby function . . .

double *__thiscall sub_2FDC00(int this, char a2, signed int a3, signed int a4)
{
  signed int v4; // ebx@1
  int v5; // edi@1
  int v6; // eax@2
  int v7; // ecx@2
  unsigned int v8; // esi@2
  unsigned int v9; // eax@4
  int v10; // eax@6
  int *v11; // edi@9
  double **v12; // eax@9
  double v13; // xmm0_8@9
  double **v14; // eax@14
  double *v15; // esi@15
  double v16; // ST18_8@15
  double *result; // eax@15

  v4 = a3;
  v5 = this;
  if ( a3 == 128 )
  {
    v6 = sub_2FD700(&a2);
    v7 = v6;
    v8 = *(v6 + 16);
    if ( *(v6 + 20) >= 0x10u )
    {
      v7 = *v6;
    }
    v9 = 4;
    if ( v8 < 4 )
    {
      v9 = v8;
    }
    v10 = sub_159A70(v7, "EPOC", v9);
    if ( v10 || v8 < 4 || (LOBYTE(v10) = v8 != 4, v10) )
    {
      v11 = (v5 + 472);
      v12 = sub_2FD820(v11, &a2);
      v13 = *&qword_4CB148;
    }
    else
    {
      v11 = (v5 + 472);
      v12 = sub_2FD820(v11, &a2);
      v13 = *&qword_4CB150;
    }
  }
  else
  {
    v11 = (this + 472);
    v12 = sub_2FD820((this + 472), &a2);
    if ( v4 == 256 )
    {
      v13 = *&qword_4CB158;
    }
    else
    {
      v13 = v4;
    }
  }
  **v12 = v13;
  v14 = sub_2FD820(v11, &a2);
  if ( a4 )
  {
    v15 = *v14;
    v16 = round(COERCE_UNSIGNED_INT64((v4 / a4)), COERCE_UNSIGNED_INT64((v4 / a4)) >> 32);
    result = *sub_2FD820(v11, &a2);
    result[1] = *v15 / v16;
  }
  else
  {
    result = *v14;
    *(result + 1) = 0i64;
  }
  return result;
}

@warrenarea
Copy link
Author

we can also know, that these functions provided, are not sub functions, or some part of other pieces of code, because each one makes reference to "Epoc" or "Epoc Plus".

@warrenarea
Copy link
Author

_mm_unpckl_pd means to unpack and interleave double.
which seems relevant.

also, i think you've probably noticed by now, theres lines like:
"6d467bcbb30e27f94a7b01ee11fd18a5"

I'm pretty sure they are related to profiles, not entirely how that works, but pretty
sure that's what they're related to.

SETP
you may have seen that before as well, i believe its related to retrieving the HID device.

@warrenarea
Copy link
Author

Also, SignalQualitySW... apparently it stands for "Signal Quality Square Wave"

@warrenarea
Copy link
Author

pretty sure that long function is the one we're primarily after, it makes another
reference to sub_2FDAE0 which also makes use of a
qword_4C38C0: dq 3FA0000000000000h

which i believe is a double representation of 0.03125

theres a few other functions that reference it, and they seem to do a right shift 31 places, and then
multiplies by 0.03125

I think at this point though, we're going to need someone who actually has the Epoc+ to
set up a breakpoint, and look at the actual variables.

It might be difficult to read the memory as well in IDA, because we're using a double float, and I had a
hard time deciphering the 0.03125 without the use of hex rays. In some places, I think it rounds off
to integers too, so we should at least be able to see "some" recognizable integers probably in the 4000
range.

@ghost
Copy link

ghost commented Jun 14, 2017

Unless it's concatenating the packets?

@warrenarea
Copy link
Author

warrenarea commented Jun 19, 2017

thought it might be useful to go back to how daeken first started out.

The first byte of each report is a counter that goes from 0-127 then to 233, then cycles back to 0. Once this was determined, I figured out the gyro data. To do that, I broke out pygame and wrote a simple app that drew a rectangle at the X and Y coords coming from two bytes of the records. I pretty quickly figured out that the X coord from the gyro is byte 29 and the Y coord is byte 30. The EPOC has some sort of logic in it to reset the gyro baseline levels, but I'm not sure on the details there; the baseline I'm seeing generally (not perfect) is roughly 102 for X and 204 for Y. This lets you get control from the gyro fairly easy.

That accounts for 3 bytes of the packet, but we have 14 sensors. If you assume that each sensor is represented by 2 bytes of data, that gives us 28 bytes for sensor data. 32 - 28 == 4, so what's the extra byte? Looking at byte 15, it's pretty clear that it's (almost) always zero -- the only time it's non-zero is the very first report from the device. I have absolutely no idea what this is.

@warrenarea
Copy link
Author

In the get_level code we'd been working on, i did see a specific byte that, i have been calling the byte_Counter, because it loops 0-28 so that makes some sense now.

then I also found the 0-127 counter he was speaking of, but i don't remember seeing it hit 233.
i thought i remembered it going to a different number, thought it was 0xF1 (241) will look into that
again.

its obvious that all the code is correct for the regular Epoc mode, but the better I understand how the
regular epoc version works, the easier it will be to go to the Epoc+ and identify how it works.

I thought by going back to the old version of control panel, that it would be easier... and some parts of
it are definitely a ton easier to read... but others just leave me with a lot of questions.

I'm still trying to figure out how they get their byte_names, sometimes I get the feeling like i'm staring
right at them. lol

but i'm also wondering if maybe they aren't using the strings of numbers like we have them set up,
for all we know... they could have boxed them up in a bunch of long hex numbers, and then sequentially
iterate through them. heck, thats probably what i'd do. lol

something i'm curious about though.... is when I was looking at some of daekens old code, that he was
using an entirely different set of sensor_bits... which was likely for the different clamshell versions, but
then got edited out over time.

he also said that... some of the sensors have less noise or something, so that it was relatively easy to
sort them out. likely was just doing trial by error.... so makes me wonder if he even found the code
for that part.

either way... we're on the right track with our get_level

@warrenarea
Copy link
Author

Found this in a Double 0.5128205128205129
in the old control panel version.

Undoubtedly its the double precision version of the 0.51 microvolts.

@kanzure
Copy link
Member

kanzure commented Jun 20, 2017

That accounts for 3 bytes of the packet, but we have 14 sensors. If you assume that each sensor is represented by 2 bytes of data, that gives us 28 bytes for sensor data. 32 - 28 == 4, so what's the extra byte? Looking at byte 15, it's pretty clear that it's (almost) always zero -- the only time it's non-zero is the very first report from the device. I have absolutely no idea what this is.

The order of data in each packet is as follows: 1 interpolation, 1 packet counter, 1 battery level, 16 inputs but sometimes 2 unused (last one might be square wave data), 2 gyro, 1 unused, 3 for anti-debugging clock check.

@warrenarea
Copy link
Author

Thanks kanzure,

Back to the Epoc+
Perhaps I should have read the instruction manual first.... because if you go to the Pure.EEG dashboard,
and click Help, and then look at the user manual.

They actually explain the formatting of all of the data being stored in the files, and are pretty specific.

labels:
COUNTER INTERPOLATED AF3 F7 F3 FC5 T7 P7 O1 O2 P8 T8 FC6 F4 F8 AF4 RAW_CQ 
GYROX  GYROY  MARKER  SYNC  TIME_STAMP_s  TIME_STAMP_ms  CQ_AF3  CQ_F7  CQ_F3 
CQ_FC5   CQ_T7   CQ_P7   CQ_O1   CQ_O2   CQ_P8   CQ_T8   CQ_FC6   CQ_F4 
CQ_F8   CQ_AF4 
CQ_CMS CQ_DRL (Epoc mode)

labels:
COUNTER  INTERPOLATED  AF3  T7  Pz  T8  AF4  RAW_CQ  GYROX  GYROY  MARKER 
SYNC  TIME_STAMP_s  TIME_STAMP_ms  CQ_AF3  CQ_T7  CQ_Pz  CQ_T8  CQ_AF4  (Insight 
mode)
These are the headings for each data column (see below).
chan:39
Count  of  the  total  number  of  information  columns  in  the  remainder  of  the  file  (note 
-
this  includes all columns, not just EEG data).

units:emotiv
Measurement units. One emotiv unit is almost exactly one microvolt

4.3 Column Headings
COUNTER

Packet counter is used as a timebase, The counter runs from 0 to 128 (note there are 129 counter
values. it takes one sample longer than a second to cycle around the full count)

INTERPOLATED
This   is   a   flag   which   shows   if   a   packet   was   dropped   and   the   value   interpolated   from 
surrounding values. FLAG=0 means the sample was good.

AF3..AF4  EEG channels 

RAW_CQ

This is a multiplexed conductivity measurement used to derive the contact quality indicator lights.  It  is  possible  to  demultiplex  this  channel  if  more  accurate  conductivity  measurements  are required. The multiplexer cycles twice through the electrode in each 129 sample cycle.

CQ_AF3..CQ_AF4
These numbers show the colour of the CQ Map indicators, where 0=BLACK, 1 =RED,
2=ORANGE,  3=YELLOW, 4=GREEN  (Epoc  mode)s Or  0=BLACK,  1  =RED,  2=ORANGE,  3= GREEN (Insight mode) 

CQ_CMS, CQ_DRL
The colours for the the reference locations either RED (1) or GREEN (4) 

GYROX, GYROY
Horizontal and vertical difference readings since the previous sample.

MARKER

Timing markers manually or automatically entered in the file. If no marker was detected at the
particular   timing   sample,   a   value   of   zero   is   added   into   the   file,   otherwise   the   number 
associated with  the  marker  button,  or  the  byte  transmitted  to  the  COM  port,  is  entered  in  the  MARKER column for that sample.

4.4 Notes on the Data
DC Offset

EEG data is stored as floating point values directly converted from the unsigned 14
bit ADC output  from  the  headset.  This  means  that  the  (floating)  DC  level  of  the  signal occurs  at approximately  4200  uV,  negative  voltages  are  transmitted  as  positive  values  less  than  the average level,  and  positive  voltages  are  transmitted  as  positive  values  greater  than  the average.  In  order to  remove  the  DC  offset,  especially  before  performing  any  kind  of  analysis  such as Fast Fourier Transform (FFT) it is necessary to apply some kind of DC offset removal.  The simplest method is simply to subtract the average from the entire data channel, although  this  is  the  least  accurate. Ideally  you  should  apply  a  high
-
pass  filter  which  matches  the 
characteristics of the electronics 
-
that is, you should use a 0.16Hz first order high
-
pass filter to 
remove the background signal (this also removes any longer term drift, which is not achieved 
by  the  average
subtraction  method).  Another  method  is  to  use  an  IIR  filter  to  track  the 
background level and subtract it an example is shown below in Matlab pseudocode, assuming 
the first row has been removed from
the array input_data()

INTERPOLATED
This   is   a   flag   which   shows   if   a   packet   was   dropped   an
d   the   value   interpolated   from 
surrounding
values. FLAG=0 means the sample was good.
AF3..AF4
EEG channels
RAW_CQ
This is a multiplexed conductivity measurement used to derive the contact quality indicator
lights.  It  is  possible  to  demultiplex  this 
channel  if  more  accurate  conductivity  measurements 
are
required. The multiplexer cycles twice through the electrode in each 129
-
sample cycle.
CQ_AF3..CQ_AF4
These numbers show the colour of the CQ Map indicators, where 0=BLACK, 1 =RED,
2=ORANGE,  3=YELLOW,
4=GREEN  (Epoc  mode) 
s
Or  0=BLACK,  1  =RED,  2=ORANGE,  3= 
GREEN (Insight mode)
CQ_CMS, CQ_DRL
The colours for the the reference locations
-
either RED (1) or GREEN (4)
GYROX, GYROY
Horizontal and vertical difference readings since the previous sample.
MARKER
Timing markers manually or automatically entered in the file. If no marker was detected at the
particular   timing   sample,   a   value   of   zero   is   added   into   the   file,   otherwise   the   number 
associated
28
with  the  marker  button,  or  the  byte  transmitted  to  the  COM  por
t,  is  entered  in  the  MARKER 
column for that sample.
4.4 Notes on the Data
DC Offset
EEG data is stored as floating point values directly converted from the unsigned 14
-
bit ADC
output  from  the  headset.  This  means  that  the  (floating)  DC  level  of  the  signal
occurs  at 
approximately  4200  uV,  negative  voltages  are  transmitted  as  positive  values  less  than  the 
average
level,  and  positive  voltages  are  transmitted  as  positive  values  greater  than  the 
average.  In  order
to  remove  the  DC  offset,  especially  before  perfo
rming  any  kind  of  analysis 
such as Fast Fourier
Transform (FFT) it is necessary to apply some kind of DC offset removal. 
The simplest method
is simply to subtract the average from the entire data channel, although 
this  is  the  least  accurate.
Ideally  you  sh
ould  apply  a  high
-
pass  filter  which  matches  the 
characteristics of the electronics 
-
that is, you should use a 0.16Hz first order high
-
pass filter to 
remove the background signal (this also removes any longer term drift, which is not achieved 
by  the  average
subtraction  method).  Another  method  is  to  use  an  IIR  filter  to  track  the 
background level and subtract it an example is shown below in Matlab pseudocode, assuming 
the first row has been removed from
the array input_data()

@warrenarea
Copy link
Author

So I'm looking at the data packets for Epoc+ that minifiredragon provided a while back,
and at the end... I see a lot of 0 padding, which I am wondering if its not a hardware version
of contact quality.

I think to test that theory, would be to have him try it again, but this time, wearing the headset.
If i'm right... the 0 padding will all be 3

@warrenarea
Copy link
Author

Bill, check this out...
so I was looking at how the user manual says that the (floating) DC level of the signal occurs at
approximately 4200uV

and then I looked for patterns in the data that minifire gave us, from our decrypted version.
this is what i found...

Counter Interpolate (7 sensors in 2 bytes each) (2 unknown bytes) (7 sensors in 2 bytes each) 32 delimiter

then every couple packets, there is extra data, which i think is obviously gyro data and the last
14 bytes, are contact quality bits, which will be 0 - 3

now.... if you hilight all of the data pieces that have 125 in them, you can see a pattern.

125 125 125 128 125 125 125 115 125 125 126 134 127 149

they are all centralized around that range group...

and i think when we first began, we were looking for -8900 +8900 values.... and trying to make
them fit.... but I think these values, are actually just added to 4200 .... and thats also why, if you
look at the Pure.Eeg output file, you'll see all of the values.... are all centralized around 4200

because its actually being added/subtracted from 4200
if you take off the first digit (4) on all of the samples, almost all of them end up matching that tight
little range of 125.... i think maybe the sensors were wetted, or in that sample, it was on his head, so
the values are slightly higher/lower than 125.

i also found code supporting this theory.... by searching for 4200 i found some code, that also adds
and subtracts by 100 off of 4200, which coincides with why its not 4200+125, but rather 4200-200+125

so i think the first number (before 125), is actually what is used to get the floating point number.

and judging by the gyro data, i should find that it is also being added to 2000

@warrenarea
Copy link
Author

it also coincides that every couple packets that there is gyro data, because there is an option to increase the rate at which the gyro data is provided, to preserve battery life.

@warrenarea
Copy link
Author

signed int __thiscall sub_10FC680(int this)
{
int v1; // eax@1
int v2; // edx@1
signed int result; // eax@4
double v4; // xmm0_8@5

v1 = *(_DWORD )(this + 80);
v2 = 0;
if ( v1 <= 0 )
goto LABEL_9;
while ( !
(_BYTE *)(this + v2 + 84) )
{
if ( ++v2 >= v1 )
return 4200;
}
v4 = *(double )((_DWORD *)(this + 124) + 8 * v2);
result = (signed int)floor(v4);
if ( v4 <= 0.0 )
LABEL_9:
result = 4200;
return result;
}

@warrenarea
Copy link
Author

sub_10fc680 the function above.

  v5 = sub_10FC680(*(_DWORD *)(v3 + 588));
  *(_DWORD *)(*(_DWORD *)(v3 + 588) + 112) = v5 - 100;
  v6 = v5 + 100;
  *(_DWORD *)(*(_DWORD *)(v3 + 588) + 116) = v5 + 100;
  QSpinBox::setValue(*(QSpinBox **)(v3 + 368), v5 - 100);
  QSpinBox::setValue(*(QSpinBox **)(v3 + 364), v6);

@warrenarea
Copy link
Author

i think the hardware is basically just doing the baseline math... which coincides with the sensor_quality
being done on the hardware level as well. which just leaves the int to floating conversion to be done on the
cpu.

@warrenarea
Copy link
Author

i'm not sure if that function i gave is the heart of the data handling for epoc+
but it does look pretty consistent with what is happening.... i think from what i told you,
you should be able to at least get the Epoc+ running with Epoc-like resolution.

@warrenarea
Copy link
Author

Just received the Insight and the Epoc+ and am currently charging them.

I inspected the quality of the headsets, and found a few things to note.

The Insight polymer, as expected, feels like a stiff kind of rubber. I think it may have also came with
a few backup ones... and also came with a hydrator. So I think they eventually do need hydrated again.

The plastic, does seem a bit durable, think it might be the pureness of the polycarbonate that has been
worked on... the arms do seem slightly springy, but if you weren't careful, I could easily see one snapping off. At first I thought I seen a couple hairline fractures, but it appears they were just segments of the
plastic.

The Insight is made in China + Vietnam

I got a universal USB dongle for the Insight, but it appears it may have been unnecessary,
because the USB that comes with the Epoc+ appears to be a universal dongle as well, with no
visible difference.

I inspected the Epoc+ and I thought again I seen hairline fractures in the arms, but from what I can
gather, it might be how they are making it slightly more flexible, is instead of casting single plastic molds,
they are creating smaller segments and then heating them together. It did appear to be flexible, but I
keep in mind.... that the original Epoc took a few months before it actually started to deteriorate.

The Epoc+ is made in the phillipines, the same as the original Epoc, and the USB dongles.

Included with the Insight was a large EmotivInsight t-shirt, and a button that said i<3emotiv. lol

Insight out of box, requires 2 hours charging.
Epoc+ out of box, requires 4 hours charging.

Insight also comes with an alan wrench to remove reference sensors.

@minifiredragon
Copy link
Contributor

Sorry to have seemed to disappear. Got caught up in reading a book for these headsets called Analyzing Neural Time Series Data. Something that will be needed to process the raw data that is saved from these files. That and I had upgraded my web server and just realized a few of my email addresses weren't collecting email. When I fixed it man did I get alot of emokit messages. :)

@warrenarea
Copy link
Author

yeah I got every charged up and ready to go.
I didn't realize there was also a Xavier consumer control panel as well.
So might be helpful to have something else to poke around in IDA.

The Insight has an odd charging cable, its like a audio jack that plugs into USB...
not entirely sure why they went with this alternative method, especially if the voltage
would be about the same as their other cable. The design for the plugin is not good,
because you almost have to yank on the cable to get it to come out. Which could lead
to cable damage in the long-term. Think its more of a cosmetic than anything.

When you plugin the Insight cable (to charge), Pure.EEG detects a headset device, and the USB
product_name (in emotiv.py) shows up as 'Insight' ... I got it to detect the interface.... but it is kind
of a moot point, because it has no sensor data while charging+turned off.

Also, with the universal dongles, bill has it already setup to detect the product_name 'EEG Signals'
and 'Brain Computer Interface USB Receiver/Dongle' which has no data sent.

From the date provided, these were created in March 2016

My insight model # is: (where i X-ed out my unique identifier)
IN2016080500xxxx
This came from when I was plugged into the Insight with USB,
which tells me, the device itself was created in a batch August 2016

@warrenarea
Copy link
Author

So I attached the Epoc+ physically to the USB of the PC, (which is required to establish 2-way
communication, in order to change the mode settings)

The interface it makes is to:
'EPOC+'
and provided a device.serial_number of:
'EP2017010700xxxx'
where the last 'x' is my unique device #
This Epoc+ batch was made in January 2017

@warrenarea
Copy link
Author

I believe I have decoded the settings for the mode change for Epoc+

First, it appears that the Epoc+ will only change settings if the USB data cable is plugged in,
and device is turned on.

If it is just plugged in and turned off, no settings will be changed.
That sounds obvious, but the light indicators kind of confuse matters.

The USB dongles are detected as a 'Composite Device'
where the headset is detected as an 'Input' Device.

The dongles display 2 device interfaces, and the headset only 1

However the headset says it has 2 endpoints, where the dongle only has 1

I will have to read up a bit more on the USB protocol and pywinusb to go further.

Here is the data formatting for changing modes:


-- = 00 padding for a 32 byte packet.

55 AA 20 12 00 --
EPOC 

55 AA 20 12 82 --
82 = 10000010
     1xx00010   

EPOC+
128hz *
16bit
off
16bit


55 AA 20 12 E2 --
E2 = 11100010
     1xx00010 
EPOC+
256hz *
16bit
off
16bit

55 AA 20 12 86 --
86 = 10000110
86 = 1000xx10
EPOC+
128hz
16bit
32hz *
16bit


55 AA 20 12 8A --
8A = 10001010
     1000xx10
EPOC+
128hz
16bit
64hz *
16bit

55 AA 20 12 8E --
8E = 10001110
8E = 1000xx10
EPOC+
128hz
16bit
128hz *
16bit

55 AA 20 12 EA --
EA = 11101010
EPOC+
256hz
16bit
64hz
16bit

55 AA 20 12 EE --
EE = 11101110

EPOC+
256hz
16bit
128hz
16bit

1xx0yy10

xx = sample rate hz
yy = mems hz

Below each 5 bytes, i display the affected character in binary,
to make it easier to see whats being changed.

I already have created a script to try to push these changes into the Epoc+
Pretty certain I have the data right, but can't get it to actually "send" the data through pywinusb.

@warrenarea
Copy link
Author

To get the data values, I found this neat program called "USBlyzer" that lets you packet sniff
the USB/HID communications. Then I just changed each mode, and it became pretty apparent
what was being sent.

Now.... I just have to get pywinusb to communicate it to the right interface...
would have made a lot more sense to have turned this mode changing feature, into a hardware switch!

@warrenarea
Copy link
Author

So I tried a few different things for the Epoc+
Went through all of the 6 different keys inspecting the data.
Then I changed each Epoc-Mode seeing if the keys made a difference to each mode, which they didn't.

I found the only useful data to be model 6 from this listing:
#264

Here is a sample:


51  16  0  128  161  127  183  127  123  127  137  127  126  127  110  127  0  0  
           119  127  169  127  190  127  119  127  185  127   46  129   96  150  
      
52  16  176  127  144  127  130  127  131  127  147  127  136  127  135  127  0  0 
        140  127  172  127  199  127  128  127  177  127  32  129  13  150  
     
53  16  102  127 132  127  106  127  139  127  154  127  138  127  147  127  0  0 
        153  127 161  127  201  127  141  127  178  127   27  129  211  149 

54  16   90  127  133  127  118  127  139  127  156  127  129  127  142  127  0  0 
        146  127  147  127  195  127  151  127  186  127   32  129  218  149  
    
55  16  119  127  141  127  142  127  132  127  153  127  118  127  127  127  0  0 
        133  127  148  127  185  127  155  127  196  127   40  129   12  150 

56   16  143  127  148  127  155  127  123  127  149  127  113  127  117  127  0  0 
         131  127  167  127  177  127  155  127  200  127   42  129   53  150  
         
7  32  

         202  255  53  0  194  255  62  6  102  62  55  244  224  0  82  244  167 254  
         0  0  0  0  0  0  0  0  0  0  0  0  
 
57  16  149  127  156  127  156  127  121  127  143  127  121  127  119  127  0  0 
        137  127  188  127  177  127  150  127  193  127   38  129   57  150  
      
58  16  146  127  166  127  158  127  128  127  137  127  132  127  130  127  0  0 
        140  127  193  127  184  127  144  127  178  127   32  129   37  150  
    
59  16  139  127  170  127  165  127  139  127  130  127  136  127  141  127  0  0 
        139  127  185  127  194  127  145  127  169  127   27  129   19  150 

60  16  128  127  162  127  167  127  146  127  123  127  133  127  144  127  0  0 
        138  127  176  127  198  127  156  127  173  127   27  129   16  150 

61  16  129  127  147  127  158  127  142  127  123  127  130  127  138  127  0  0 
        135  127  168  127  192  127  164  127  187  127   31  129   26  150 

62  16  147  127  141  127  142  127  130  127  130  127  131  127  128  127  0  0 
        131  127  159  127  181  127  161  127  198  127   35  129   37  150  0  0
        
63  16  158  127  147  127  130  127  119  127  138  127  133  127  120  127  0  0 
        135  127  149  127  170  127  155  127  202  127   34  129   34  150 
        
64  16  143  127  158  127  128  127  117  127  141  127  134  127  116  127  0  0 
            147  127  141  127  166  127  156  127  199  127   29  129   14  150  
        
8  32 
         191  255  67  0  182  255  112  6  112  62  87  244  229  0  102  244  175  254  
         0  0  0  0  0  0  0  0  0  0  0  0  
         
65  16  121  127  164  127  136  127  122  127  138  127  134  127  119  127  0  0 
        156  127  138  127  169  127  165  127  194  127   25  129  246  149  
        
66  16  121  127  163  127  149  127  129  127  134  127  135  127  126  127  0  0 
        148  127  138  127  174  127  169  127  190  127   28  129  236  149 

So basically, the same data that minifiredragon collected with his.
[Counter] [16] [14 BYTEs] 0 0 [14BYTES]

and then the second counter is for the MEMS.
[Counter] [32] [18 bytes] [12 '0' bytes]

I tried wearing 1 sensor on a couple different contacts, verified a positive signal, and
I suspected that one of the 0's would light up.... but it appears this is not for signal
quality like I previously thought, and might just be 0 padding.

Checked to see if anything special happens at 255 counter but it just loops back to 0.
Think Epoc just goes to 128, so will have to change that.

While wearing the headset with just a couple contacts, I did notice that it seemed like it
was picking up more "rhythmic" patterns than i noticed with the Epoc, so perhaps the
higher precision is to credit for this. Plus it was in 256hz mode, reading the neural
responses slightly faster. I should try to do a comparison.

Also a little displeased with the Epoc+ sensor contacts, one of the blank contacts kept falling off.
and not sure if it was well connected but another contact fell off as well. I suspect my hot glue
gun will get involved eventually.

Upon further consideration, I don't think my idea about values being subtracted from 4200 was
quite correct, though it may be involved in some matter of fashion. Next i'll have to start diving
into IDA.

so no new news, but we're on track.

@warrenarea
Copy link
Author

Well, i've made some interesting discoveries for the Epoc+.

I managed to setup my CyKit version to stream the data values, I figured it would be easier
for me to visualize the data outside of Python.

First, I displayed the 127 in a line graph, and they were all flat-lined.

Then I just plotted a line graph of the data value after 127, and it looked pretty close to how
Xavier displays it.

So then I went to see if I could figure out which sensor was which... and by tapping on them,
I was able to get a pretty good estimate which was which... but due to sensor proximity, it was
a bit difficult.

Then I went back to displaying all of the 127's again.... and I noticed that with 1 sensor attached,
the 127 changed either slightly higher or slightly lower... I'm thinking this might be something like
positive or negative impedance.... when I pressed firmly on the contact, I think the number went below
127, and when i let go, the number goes above 127... without any felt sensors attached, the number
always equalizes to 127.

Once I discovered that, I was quickly able to discern which sensor was which, by attaching only one
sensor, monitoring which Nth 127 changed, and then monitoring Xavier for that sensor activity.

The order is:

F3 FC5 AF3 F7 T7 P7 O1 O2 P8 T8 F8 AF4 FC6 F4

Which, is the same order of sensors that we already have in Emotiv for the Epoc, so nothing
has changed there.

I first mapped it by tapping the sensors
and then mapped it again by measuring the impedance value.
they both came out the same.

So now we know that... the following 127 for each data value, corresponds to that particular sensor.

If the 2nd byte is 16, then thats for the data... if the 2nd byte is 32, thats for the MEMS,
and I did do a little bit with that.... most the values start with 255 and then if the value is
< 255 and > 128, then it moves the mouse left
< 255 and < 128, then it moves the mouse right

I would attach some screenshots of the line graph, but I was streaming too many packet duplicates
and probably wouldn't do it justice.

@warrenarea
Copy link
Author

note, that the 127's only changed when that sensor was attached to the head, which would lend to the impedance idea.

@warrenarea
Copy link
Author

This is just from the data line after the 127.
Although I do think there is some additional handling involved for the floating point precision
I think this will at least gets us a workable version of Epoc+

What do you think Bill?

@warrenarea
Copy link
Author

@warrenarea
Copy link
Author

It appears the Insight #268
and the Epoc+ in Epoc-mode
uses the same key model=4 from #264

we knew the key already, but now we know that solving one will likely solve for the other as well.

I didn't have a lot of time to go through the values... but I can tell you, that the order of the values
are not as linear as the Epoc+ the sensors are mixed in with the gyro data.

half the sensors seemed like they were giving good results, and half the sensors seemed like they
were giving noisy feedback... I'm thinking its just in a similar format as the regular Epoc and will
have to be filtered as such.

Also, I noted that in Epoc-Mode, Xavier does not report the battery correctly... which is what minifire
had been saying earlier... in Epoc+ mode i think it reports it correctly.

@warrenarea
Copy link
Author

Bill, perhaps you will find this interesting (or you've already seen it)
https://github.com/Emotiv/community-sdk/tree/master/examples_extra_prime

has some examples in Python that could prove useful... at very least, shows some of
the byte names.

@warrenarea
Copy link
Author

I noticed in my graphics of the EPOC+ signals, that it wasn't quite measuring the data peaks,
which I'm thinking is because they may be using that 127 impedance value (signal quality), as
maybe an amplification factor. Because that peak occurred when I let off the sensor.

likely why some peaks or lows seem exaggerated in Xavier and not in my version.

Also... in my version that uses gevent, I noticed that it was triggering the init twice,
i think through a gevent.spawn event, why it was duplicating packets... but then I kind
of ran into a speed issue, where it starts out fast, and then it slows down rapidly...

The odd thing is, I was getting a faster/consistent speed with the Epoc+ which sends data faster
at 256hz... on top of sending duplicate packets.... so something must be configured wrong
somewhere along the line.

I think I remember you said your version doesn't even use greenlets anymore, so I should
probably give that a try.... I was hoping to stick with Py2.7 though, because I never really
noticed an improvement in speed with Py3 anyways.

@warrenarea
Copy link
Author

warrenarea commented Aug 2, 2017

what might interest some of you....

https://www.emotiv.com/emotivpro/

it appears emotiv has produced a new program, this one is specifically for recording.
seems kind of redundant, as the Xavier seems to have almost the same functionality...

plus... they're charging you even more per month.... but this time... you have
"unlimited recordings"

and if i'm reading this correctly.... it looks like they've done away with the $49/month
and are now charging $99/month

its a shame, all of the price gouging will have the opposite effect of making this device
more popular.

@warrenarea
Copy link
Author

@warrenarea
Copy link
Author

https://discordapp.com/invite/gTYNWc7
If anyone would like to assist me in the Epoc+ data
I have a Discord chat server setup here.

You can either download the discord chat messenger,
or just click the link to use the browser interface.

Basically we have the input and the output.... and just need to sort out how
it operates.

I also compiled a list of floating point numbers that correspond to each Decimal value (ie.4200)
and there seems to be a pattern, that I have yet to sort out....

The floating point numbers actually repeat and are not unique at all.... i think if someone with
a bit more knowledge than I about this sort of math could take a look, they could easily tell what
is going on.

also, it seems like if you multiply or add some of them together, they match up, but with a slight
variance.

would appreciate it if you could take a look...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants