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

Generate raw data from hex code #1703

Closed
Nakul93 opened this issue Dec 15, 2021 · 7 comments
Closed

Generate raw data from hex code #1703

Nakul93 opened this issue Dec 15, 2021 · 7 comments
Assignees
Labels

Comments

@Nakul93
Copy link

Nakul93 commented Dec 15, 2021

I am trying to use rmt module from esp-idf and was able to receive raw data(raw timings) from it, in order for matching the protocols I have the hex codes for each control(which is unique).
Is there a way where we can generate the raw data (raw timings) from hex (hash) code so that I can send data.

eg: for GREE

convert:
code: 0x09072050002000C0

to:
uint16_t rawData[139] = {9048, 4422, 706, 1616, 674, 474, 726, 524, 650, 1642, 676, 514, 684, 496, 702, 524, 652, 550, 672, 1616, 674, 1620, 650, 1644, 652, 522, 676, 520, 702, 516, 682, 524, 676, 522, 652, 518, 702, 498, 678, 548, 652, 546, 676, 524, 676, 1620, 674, 476, 700, 520, 704, 524, 674, 524, 652, 548, 678, 522, 652, 1616, 676, 548, 676, 1620, 676, 522, 676, 524, 652, 1642, 676, 498, 700, 19896, 706, 526, 676, 522, 678, 520, 678, 520, 680, 522, 676, 494, 706, 520, 678, 520, 678, 520, 680, 518, 680, 520, 682, 516, 684, 516, 682, 1582, 712, 512, 684, 516, 686, 512, 684, 514, 684, 514, 684, 514, 684, 514, 686, 514, 684, 514, 684, 514, 684, 516, 682, 516, 684, 516, 682, 518, 682, 516, 680, 494, 704, 1586, 708, 1588, 706}; // GREE

@crankyoldgit
Copy link
Owner

crankyoldgit commented Dec 16, 2021

See resultToSourceCode()

TEST(TestResultToSourceCode, SimpleProtocols) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
// Generate a code which has address & command values.
irsend.reset();
irsend.sendNEC(irsend.encodeNEC(0x10, 0x20));
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
ASSERT_EQ(NEC, irsend.capture.decode_type);
ASSERT_EQ(kNECBits, irsend.capture.bits);
EXPECT_EQ(
"uint16_t rawData[68] = {8960, 4480, 560, 560, 560, 560, 560, 560, "
"560, 560, 560, 1680, 560, 560, 560, 560, 560, 560, 560, 1680, "
"560, 1680, 560, 1680, 560, 1680, 560, 560, 560, 1680, 560, 1680, "
"560, 1680, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, "
"560, 1680, 560, 560, 560, 560, 560, 1680, 560, 1680, 560, 1680, "
"560, 1680, 560, 1680, 560, 560, 560, 1680, 560, 1680, 560, 40320 "
"}; // NEC 8F704FB\n"
"uint32_t address = 0x10;\n"
"uint32_t command = 0x20;\n"
"uint64_t data = 0x8F704FB;\n",
resultToSourceCode(&irsend.capture));
// Generate a code which DOESN'T have address & command values.
irsend.reset();
irsend.sendNikai(0xD0F2F);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
ASSERT_EQ(NIKAI, irsend.capture.decode_type);
ASSERT_EQ(kNikaiBits, irsend.capture.bits);
EXPECT_EQ(
"uint16_t rawData[52] = {4000, 4000, 500, 2000, 500, 2000, "
"500, 2000, 500, 2000, 500, 1000, 500, 1000, 500, 2000, 500, 1000, "
"500, 2000, 500, 2000, 500, 2000, 500, 2000, 500, 1000, 500, 1000, "
"500, 1000, 500, 1000, 500, 2000, 500, 2000, 500, 1000, 500, 2000, "
"500, 1000, 500, 1000, 500, 1000, 500, 1000, 500, 8500 };"
" // NIKAI D0F2F\n"
"uint64_t data = 0xD0F2F;\n",
resultToSourceCode(&irsend.capture));
}

@Nakul93
Copy link
Author

Nakul93 commented Dec 16, 2021

From the resultToSourceCode() function, I understood that the rawData is not the rawbuf in decode_results structure.
How can I get rawbuf data and how does it vary from rawData? since in the lib I can see rawbuf is used for decoding

@crankyoldgit
Copy link
Owner

From the resultToSourceCode() function, I understood that the rawData is not the rawbuf in decode_results structure.

Yes, No, kind of.
"rawData" (used by sendRaw()) is derived from the rawbuf, it needs to be massaged/processed a bit to convert from rawbuf to rawData. That resultToSourceCode() routine handles all of it.

How can I get rawbuf data and how does it vary from rawData? since in the lib I can see rawbuf is used for decoding

rawbuf is located in the irparams_t structure.
See also:

volatile irparams_t params;

rawbuf differs from rawData in that rawbuf[] starts at index 1, verses index 0 for rawData[]. i.e. rawData[0] is derived from rawbuf[1]. rawbuf is also stored in "ticks", where as rawData is in uSeconds.
See:

const uint16_t kRawTick = 2; // Capture tick to uSec factor.

There is some other "magic" done to massage the rawbuf data to rawData's format, namely because you can't fit values > 65535 (usecs) into a rawData (uint16_t) array. This can happen when a rawbuf entry contains a value of >= 32768 ticks.
e.g. 32768 * kRawTick > MAXUINT16 (65535)
In short, without modification, a tick is 2 usecs. So, if result->rawbuf[2] holds the value of 250 (ticks), the corresponding/equivalent rawData[1] would contain 500 (uSeconds).

The conversion/compensation is done in the code as follows: (The code is the best explanation if you can follow it)

// Dump data
for (uint16_t i = 1; i < results->rawlen; i++) {
uint32_t usecs;
for (usecs = results->rawbuf[i] * kRawTick; usecs > UINT16_MAX;
usecs -= UINT16_MAX) {
output += uint64ToString(UINT16_MAX);
if (i % 2)
output += F(", 0, ");
else
output += F(", 0, ");
}
output += uint64ToString(usecs, 10);
if (i < results->rawlen - 1)
output += kCommaSpaceStr; // ',' not needed on the last one
if (i % 2 == 0) output += ' '; // Extra if it was even.
}

or
// Convert the decode data.
uint16_t pos = 0;
for (uint16_t i = 1; i < decode->rawlen; i++) {
uint32_t usecs = decode->rawbuf[i] * kRawTick;
while (usecs > UINT16_MAX) { // Keep truncating till it fits.
result[pos++] = UINT16_MAX;
result[pos++] = 0; // A 0 in a sendRaw() array basically means skip.
usecs -= UINT16_MAX;
}
result[pos++] = usecs;
}

or
void dumpRawResult() {
std::cout << std::dec;
if (capture.rawlen == 0) return;
std::cout << "uint16_t rawbuf[" << capture.rawlen - 1 << "] = {";
for (uint16_t i = 1; i < capture.rawlen; i++) {
if (i % 8 == 1) std::cout << std::endl << " ";
std::cout << (capture.rawbuf[i] * kRawTick);
// std::cout << "(" << capture.rawbuf[i] << ")";
if (i < capture.rawlen - 1) std::cout << ", ";
}
std::cout << "};" << std::endl;
}

Yes, rawbuf is used in capture & decoding. The test code I linked to earlier demonstrates how to it can be used to recover (convert) the raw timings produced by a sendBlah(0x1234BEEF); message, as you requested.
The Unit Test code is simulating the sending of the IR message, and simulating the capture of the IR message via the IRsendTest class. There is no other way at present to make irsend.sendBlah() etc produce a rawData structure without going through that (or a similar) process.

@Nakul93
Copy link
Author

Nakul93 commented Dec 16, 2021

Thanks for the detailed explanation, couple of more questions:

  1. If I make some changes and use one of the above solutions will I be able to get the raw ticks, because the approach which I use using esp-idf I get the raw timings(rawData) directly so I need to go back a step and get the raw ticks(rawbuf) if I need to decode
    eg:
 void dumpRawResult() { 
   std::cout << std::dec; 
   if (capture.rawlen == 0) return; 
   std::cout << "uint16_t rawbuf[" << capture.rawlen - 1 << "] = {"; 
   for (uint16_t i = 1; i < capture.rawlen; i++) { 
     if (i % 8 == 1) std::cout << std::endl << "    "; 
     std::cout << (capture.rawbuf[i] /kRawTick);   // Here
     // std::cout << "(" << capture.rawbuf[i] << ")"; 
     if (i < capture.rawlen - 1) std::cout << ", "; 
   } 
   std::cout << "};" << std::endl; 
 } 
  1. Why do we use krawtick as 2, is there a specific reason

@crankyoldgit
Copy link
Owner

  1. If I make some changes and use one of the above solutions will I be able to get the raw ticks, because the approach which I use using esp-idf I get the raw timings(rawData) directly so I need to go back a step and get the raw ticks(rawbuf) if I need to decode

If you're getting usecs from rmt natively, then you probably want to set kRawTick to 1 to use those routines as is, or just remove the kRawTick multiplications.

  1. Why do we use krawtick as 2, is there a specific reason

Yes. For some protocols we need to be able to capture/record marks/spaces that are longer than 66ms (66000us).
rawbuf is a uint16_t array, so the max value is 65535. So to get a value long enough to cover 66+ms and still fit into a uint16_t, we need to lose resolution, hence the 2. Which allows us to record up to 131,072 usecs (with a resolution of 2usecs) i.e. 17 bits. This large a value covers pretty much all known marks/spaces in all protocols. (One of the protocols requires detecting a gap of 90ms IIRC). So 2 is the smallest tick to usec ratio/resolution loss that fits us into 16 bits.

We don't use uint32_t arrays for rawbuf to store the usec timings because it literally cost twice as much memory for the capture array. The hack of storing it as ticks, rather than raw uSeconds saves memory at the very small price of a tiny bit of integer math. Plus multiplying/dividing by 2 is a simple single bit shift, so it is very fast integer math.

crankyoldgit added a commit that referenced this issue Dec 22, 2021
Usage: tools/code_to_raw --protocol PROTOCOL_NAME --code <hexidecimal> [--bits 1-424] [--timinginfo]

e.g.
```
# Convert an A/C code to rawData[] & Timinginfo
tool/code_to_raw --protocol KELVINATOR --code 0x190B8050000000E0190B8070000010F0 --timinginfo

# Convert a Samsung TV code to rawData[].
tools/code_to_raw --protocol SAMSUNG --code 0xE0E09966
# Convert a Sony 12 bit message to rawData[].
tools/code_to_raw --protocol Sony --code 0xf50 --bits 12
```

For #1707
For #1703
crankyoldgit added a commit that referenced this issue Dec 23, 2021
* Add tool to convert protocol & code to raw timing info.

Usage: tools/code_to_raw --protocol PROTOCOL_NAME --code <hexidecimal> [--bits 1-424] [--timinginfo]

e.g.
```
# Convert an A/C code to rawData[] & Timinginfo
tool/code_to_raw --protocol KELVINATOR --code 0x190B8050000000E0190B8070000010F0 --timinginfo

# Convert a Samsung TV code to rawData[].
tools/code_to_raw --protocol SAMSUNG --code 0xE0E09966
# Convert a Sony 12 bit message to rawData[].
tools/code_to_raw --protocol Sony --code 0xf50 --bits 12
```

* Add some tests for `code_to_raw`.
* Update tools Makefile to be more dynamic

For #1707
For #1703

Co-authored-by: Christian Nilsson <[email protected]>
@crankyoldgit
Copy link
Owner

@Nakul93 How are you going with this? Can we mark this issue resolved now?

crankyoldgit added a commit that referenced this issue Dec 31, 2021
_v2.8.1 (20220101)_

**[Bug Fixes]**
- Arduino ESP32 Core v2.0.2+ crashes due to our timer hack. (#1715 #1715)
- SONY: Fix old Sony CD-Player Remote (12 Bit) (#1714)

**[Features]**
- Add tool to convert protocol & code to raw timing info. (#1708 #1707 #1703)
- Add basic support for COOLIX48 protocol. (#1697 #1694)
- MITSUBISHI_AC: Added support for i-SAVE mode. (#1666)
- TOSHIBA_AC: Add Filter setting support. aka. Pure. (#1693 #1692)
- Airton: Add detailed A/C support. (#1688 #1670)

**[Misc]**
- Add a structured library version number. (#1717)
- Workflows Split UnitTests (#1712)
- Reduce time for workflow/Build (#1709)
- Fix some compiler & linter warnings (#1699 #1700)
- Fujitsu: Update supported A/C models (#1690 #1689 #1702 #1701)
- Remove extra `const` qualifier for char pointer (#1704)
- TCL: Update supported devices. (#1698)
- ESP32-C3: Work around for some C3 specific compiler issues. (#1696 #1695)
crankyoldgit added a commit that referenced this issue Jan 1, 2022
## _v2.8.1 (20220101)_

**[Bug Fixes]**
- Arduino ESP32 Core v2.0.2+ crashes due to our timer hack. (#1715 #1713 )
- SONY: Fix old Sony CD-Player Remote (12 Bit) (#1714)

**[Features]**
- Add tool to convert protocol & code to raw timing info. (#1708 #1707 #1703)
- Add basic support for COOLIX48 protocol. (#1697 #1694)
- MITSUBISHI_AC: Added support for i-SAVE mode. (#1666)
- TOSHIBA_AC: Add Filter setting support. aka. Pure. (#1693 #1692)
- Airton: Add detailed A/C support. (#1688 #1670)

**[Misc]**
- Add a structured library version number. (#1717)
- Workflows Split UnitTests (#1712)
- Reduce time for workflow/Build (#1709)
- Fix some compiler & linter warnings (#1699 #1700)
- Fujitsu: Update supported A/C models (#1690 #1689 #1702 #1701)
- Remove extra `const` qualifier for char pointer (#1704)
- TCL: Update supported devices. (#1698)
- ESP32-C3: Work around for some C3 specific compiler issues. (#1696 #1695)
@crankyoldgit
Copy link
Owner

Marking closed due to no response in approx 1 month.

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

No branches or pull requests

2 participants