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

Add tool to convert protocol & code to raw timing info. #1708

Merged
merged 3 commits into from
Dec 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ tools/*.o
tools/*.a
tools/gc_decode
tools/mode2_decode
tools/code_to_raw

.pioenvs
.piolibdeps
Expand Down
12 changes: 9 additions & 3 deletions tools/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,20 @@ CPPFLAGS += -DUNIT_TEST -D_IR_LOCALE_=en-AU
# Flags passed to the C++ compiler.
CXXFLAGS += -g -Wall -Wextra -pthread -std=gnu++11

all : gc_decode mode2_decode
objects = $(patsubst %.cpp,%,$(wildcard *.cpp))

all : $(objects)

run_tests : all
failed=""; \
for py_unittest in *_test.py; do \
echo "RUNNING: $${py_unittest}"; \
python3 ./$${py_unittest} || failed="$${failed} $${py_unittest}"; \
done; \
for shell_unittest in *_test.sh; do \
echo "RUNNING: $${shell_unittest}"; \
bash ./$${shell_unittest} || failed="$${failed} $${shell_unittest}"; \
done; \
if [ -n "$${failed}" ]; then \
echo "FAIL: :-( :-( Unit test(s)$${failed} failed! :-( :-("; exit 1; \
else \
Expand All @@ -46,7 +52,7 @@ run-% : all
python3 ./$*.py;

clean :
rm -f *.o *.pyc gc_decode mode2_decode
rm -f *.o *.pyc $(objects)


# Keep all intermediate files.
Expand Down Expand Up @@ -80,7 +86,7 @@ IRrecv.o : $(USER_DIR)/IRrecv.cpp $(USER_DIR)/IRrecv.h $(USER_DIR)/IRremoteESP82

# new specific targets goes above this line

%_decode : $(COMMON_OBJ) %_decode.o
$(objects) : %: $(COMMON_OBJ) %.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@

ir_%.o : $(USER_DIR)/ir_%.h $(USER_DIR)/ir_%.cpp $(COMMON_DEPS) $(GTEST_HEADERS)
Expand Down
148 changes: 148 additions & 0 deletions tools/code_to_raw.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// Quick and dirty tool to convert a protocol's (hex) codes to raw timings.
// Copyright 2021 David Conran

#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include "IRac.h"
#include "IRsend.h"
#include "IRsend_test.h"
#include "IRutils.h"


void usage_error(char *name) {
std::cerr << "Usage: " << name
<< " --protocol PROTOCOL_NAME"
<< " --code <hexidecimal>"
<< " [--bits 1-" << kStateSizeMax * 8 << "]"
<< " [--timinginfo]"
<< std::endl;
}

int main(int argc, char *argv[]) {
int argv_offset = 1;
int repeats = 0;
uint64_t code = 0;
uint8_t state[kStateSizeMax] = {0}; // All array elements are set to 0.
decode_type_t input_type = decode_type_t::UNKNOWN;
bool timinginfo = false;

// Check the invocation/calling usage.
if (argc < 5 || argc > 8) {
usage_error(argv[0]);
return 1;
}

if (strncmp("--protocol", argv[argv_offset], 11) == 0) {
argv_offset++;
input_type = strToDecodeType(argv[argv_offset]);
switch (input_type) {
// Unsupported types
case decode_type_t::UNUSED:
case decode_type_t::UNKNOWN:
case decode_type_t::GLOBALCACHE:
case decode_type_t::PRONTO:
case decode_type_t::RAW:
std::cerr << "The protocol specified is not supported by this program."
<< std::endl;
return 1;
default:
break;
}
argv_offset++;
}

uint16_t nbits = IRsend::defaultBits(input_type);
uint16_t stateSize = nbits / 8;
if (strncmp("--code", argv[argv_offset], 7) == 0) {
argv_offset++;
String hexstr = String(argv[argv_offset]);
uint64_t strOffset = 0;
if (hexstr.rfind("0x", 0) || hexstr.rfind("0X", 0)) strOffset = 2;

// Calculate how many hexadecimal characters there are.
uint64_t hexstrlength = hexstr.length() - strOffset;

// Ptr to the least significant byte of the resulting state for this
// protocol.
uint8_t *statePtr = &state[stateSize - 1];

// Convert the string into a state array of the correct length.
for (uint16_t i = 0; i < hexstrlength; i++) {
// Grab the next least sigificant hexadecimal digit from the string.
uint8_t c = tolower(hexstr[hexstrlength + strOffset - i - 1]);
if (isxdigit(c)) {
if (isdigit(c))
c -= '0';
else
c = c - 'a' + 10;
} else {
std::cerr << "Code " << argv[argv_offset]
<< " contains non-hexidecimal characters." << std::endl;
return 3;
}
if (i % 2 == 1) { // Odd: Upper half of the byte.
*statePtr += (c << 4);
statePtr--; // Advance up to the next least significant byte of state.
} else { // Even: Lower half of the byte.
*statePtr = c;
}
}
if (!hasACState(input_type))
code = std::stoull(argv[argv_offset], nullptr, 16);
argv_offset++;
}

if (argc - argv_offset > 0 && strncmp("--bits", argv[argv_offset], 7) == 0) {
argv_offset++;
nbits = std::stoul(argv[argv_offset], nullptr, 10);
if (nbits == 0 && (nbits <= kStateSizeMax * 8)) {
std::cerr << "Nr. of bits " << argv[argv_offset]
<< " is invalid." << std::endl;
return 1;
}
stateSize = nbits / 8;
argv_offset++;
}

if (argc - argv_offset > 0 &&
strncmp("--timinginfo", argv[argv_offset], 13) == 0) {
argv_offset++;
timinginfo = true;
}

if (argc - argv_offset != 0) {
usage_error(argv[0]);
return 1;
}

IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
irsend.reset();

if (hasACState(input_type)) // Is it larger than 64 bits?
irsend.send(input_type, state, stateSize);
else
irsend.send(input_type, code, nbits, repeats);

irsend.makeDecodeResult();
irrecv.decode(&irsend.capture);

std::cout << "Code type: " << irsend.capture.decode_type << " ("
<< typeToString(irsend.capture.decode_type) << ")" << std::endl
<< "Code bits: " << irsend.capture.bits << std::endl;
if (hasACState(irsend.capture.decode_type)) {
String description = IRAcUtils::resultAcToString(&irsend.capture);
if (description.length()) {
std::cout << "Description: " << description.c_str() << std::endl;
}
}

std::cout << std::endl << resultToSourceCode(&irsend.capture) << std::endl;
if (timinginfo) std::cout << resultToTimingInfo(&irsend.capture);

return 0;
}
65 changes: 65 additions & 0 deletions tools/code_to_raw_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#! /bin/bash
CODE_TO_RAW=./code_to_raw
if [[ ! -x ${CODE_TO_RAW} ]]; then
echo "'raw_to_code' failed to compile and produce an executable."
exit 1
fi

function unittest_success()
{
COMMAND=$1
EXPECTED="$2"
echo -n "Testing: \"${COMMAND}\" ..."
OUTPUT="$(${COMMAND})"
STATUS=$?
FAILURE=""
if [[ ${STATUS} -ne 0 ]]; then
FAILURE="Non-Zero Exit status: ${STATUS}. "
fi
if [[ "${OUTPUT}" != "${EXPECTED}" ]]; then
FAILURE="${FAILURE} Unexpected Output: \"${OUTPUT}\" != \"${EXPECTED}\""
fi
if [[ -z ${FAILURE} ]]; then
echo " ok!"
return 0
else
echo
echo "FAILED: ${FAILURE}"
return 1
fi
}

read -r -d '' OUT << EOM
Code type: 4 (SONY)
Code bits: 12

uint16_t rawData[78] = {2400, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 600, 600, 600, 600, 600, 24600, 2400, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 600, 600, 600, 600, 600, 24600, 2400, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 600, 600, 600, 600, 600, 24600 }; // SONY F50
uint32_t address = 0x1;
uint32_t command = 0x2F;
uint64_t data = 0xF50;
EOM

unittest_success "${CODE_TO_RAW} --protocol Sony --code 0xf50 --bits 12" "${OUT}"

read -r -d '' OUT << EOM
Code type: 7 (SAMSUNG)
Code bits: 32

uint16_t rawData[68] = {4480, 4480, 560, 1680, 560, 1680, 560, 1680, 560, 560, 560, 560, 560, 560, 560, 560, 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, 560, 560, 560, 560, 1680, 560, 560, 560, 1680, 560, 1680, 560, 560, 560, 560, 560, 1680, 560, 1680, 560, 560, 560, 47040 }; // SAMSUNG E0E09966
uint32_t address = 0x7;
uint32_t command = 0x99;
uint64_t data = 0xE0E09966;
EOM

unittest_success "${CODE_TO_RAW} --protocol SAMSUNG --code 0xE0E09966" "${OUT}"

read -r -d '' OUT << xEOMx
Code type: 18 (KELVINATOR)
Code bits: 128
Description: Power: On, Mode: 1 (Cool), Temp: 27C, Fan: 1 (Low), Turbo: Off, Quiet: Off, XFan: On, Ion: Off, Light: Off, Swing(H): Off, Swing(V): Off

uint16_t rawData[280] = {9010, 4504, 680, 1530, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 19974, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 1530, 680, 39950, 9010, 4504, 680, 1530, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 1530, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 19974, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 1530, 680, 1530, 680, 39950 }; // KELVINATOR
uint8_t state[16] = {0x19, 0x0B, 0x80, 0x50, 0x00, 0x00, 0x00, 0xE0, 0x19, 0x0B, 0x80, 0x70, 0x00, 0x00, 0x10, 0xF0};
xEOMx

unittest_success "${CODE_TO_RAW} --protocol KELVINATOR --code 0x190B8050000000E0190B8070000010F0" "${OUT}"