Skip to content

Commit

Permalink
Add support for short format messages.
Browse files Browse the repository at this point in the history
e.g. swing, quiet, & powerful.

For #1307
  • Loading branch information
crankyoldgit committed Oct 30, 2020
1 parent 27a07e2 commit 40c93eb
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 19 deletions.
7 changes: 5 additions & 2 deletions src/IRrecv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -885,8 +885,11 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
if (decodeElitescreens(results, offset)) return true;
#endif // DECODE_ELITESCREENS
#if DECODE_PANASONIC_AC64
DPRINTLN("Attempting Panasonic AC (64bit) decode");
if (decodePanasonicAC64(results, offset)) return true;
DPRINTLN("Attempting Panasonic AC (64bit) long decode");
if (decodePanasonicAC64(results, offset, kPanasonicAc64Bits)) return true;
DPRINTLN("Attempting Panasonic AC (64bit) short decode");
if (decodePanasonicAC64(results, offset, kPanasonicAc64Bits / 2))
return true;
#endif // DECODE_PANASONIC_AC64
// Typically new protocols are added above this line.
}
Expand Down
64 changes: 47 additions & 17 deletions src/ir_Panasonic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -932,20 +932,32 @@ bool IRrecv::decodePanasonicAC(decode_results *results, uint16_t offset,
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1307
void IRsend::sendPanasonicAC64(const uint64_t data, const uint16_t nbits,
const uint16_t repeat) {
const uint16_t kSectionBits = nbits / kPanasonicAc64Sections;
uint16_t section_bits;
uint16_t sections;
uint16_t blocks;
// Calculate the section, block, and bit sizes based on the requested bit size
if (nbits > kPanasonicAc64Bits / 2) { // A long message
section_bits = nbits / kPanasonicAc64Sections;
sections = kPanasonicAc64Sections;
blocks = kPanasonicAc64BlocksPerSection;
} else { // A short message
section_bits = nbits;
sections = kPanasonicAc64Sections - 1;
blocks = kPanasonicAc64BlocksPerSection + 1;
}
for (uint16_t r = 0; r <= repeat; r++) {
for (uint8_t section = 0; section < kPanasonicAc64Sections; section++) {
for (uint8_t section = 0; section < sections; section++) {
// Two data blocks per section (i.e. 1 + a repeat)
sendGeneric(kPanasonicAc64HdrMark, kPanasonicAc64HdrSpace, // Header
kPanasonicAc64BitMark, kPanasonicAc64OneSpace, // Data
kPanasonicAc64BitMark, kPanasonicAc64ZeroSpace,
0, 0, // No Footer
GETBITS64(
data,
kSectionBits * (kPanasonicAc64Sections - section - 1),
kSectionBits),
kSectionBits, kPanasonicFreq, false,
kPanasonicAc64BlocksPerSection - 1, // Repeat
section_bits * (sections - section - 1),
section_bits),
section_bits, kPanasonicFreq, false,
blocks - 1, // Repeat
50);
// Section Footer
sendGeneric(kPanasonicAc64HdrMark, kPanasonicAc64HdrSpace, // Header
Expand All @@ -971,22 +983,40 @@ void IRsend::sendPanasonicAC64(const uint64_t data, const uint16_t nbits,
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1307
bool IRrecv::decodePanasonicAC64(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
if (results->rawlen < 2 * (2 * (nbits + kHeader) + kFooter) - 1 + offset)
if (strict && (nbits != kPanasonicAc64Bits &&
nbits != kPanasonicAc64Bits / 2))
return false; // Not strictly a valid bit size.

const bool is_long = (nbits > kPanasonicAc64Bits / 2);
const uint16_t min_length = is_long ?
kPanasonicAc64Sections * (2 * (nbits + kHeader) + kFooter) - 1 + offset :
(kPanasonicAc64BlocksPerSection + 1) * ((2 * nbits) + kHeader) +
kFooter - 1 + offset;

if (results->rawlen < min_length)
return false; // Can't possibly be a valid message.
if (strict && nbits != kPanasonicAc64Bits)
return false; // Not strictly a message.

const uint16_t kSectionBits = nbits / kPanasonicAc64Sections;
uint16_t sections;
uint16_t blocks_per_section;
if (is_long) {
sections = kPanasonicAc64Sections;
blocks_per_section = kPanasonicAc64BlocksPerSection;
} else {
sections = kPanasonicAc64Sections - 1;
blocks_per_section = kPanasonicAc64BlocksPerSection + 1;
}
const uint16_t bits_per_block = nbits / sections;

uint64_t data = 0;
uint64_t section_data = 0;
uint32_t prev_section_data;

for (uint16_t block = 0;
block < kPanasonicAc64Sections * kPanasonicAc64BlocksPerSection;
block < sections * blocks_per_section;
block++) {
prev_section_data = section_data;
uint16_t used = matchGeneric(results->rawbuf + offset, &section_data,
results->rawlen - offset, kSectionBits,
results->rawlen - offset, bits_per_block,
kPanasonicAc64HdrMark, kPanasonicAc64HdrSpace,
kPanasonicAc64BitMark, kPanasonicAc64OneSpace,
kPanasonicAc64BitMark, kPanasonicAc64ZeroSpace,
Expand All @@ -995,16 +1025,16 @@ bool IRrecv::decodePanasonicAC64(decode_results *results, uint16_t offset,
if (!used) return false;
offset += used;
// Is it the first block of the section?
if (block % kPanasonicAc64BlocksPerSection == 0) {
if (block % blocks_per_section == 0) {
// Keep the data from the first of the block pairs.
data = (data << kSectionBits) | section_data;
data = (data << bits_per_block) | section_data;
} else { // Not the first block in a section.
// Compliance
if (strict)
// Compare the data from the blocks in pairs.
if (section_data != prev_section_data) return false;
// Look for the section footer at the end of the blocks.
if ((block + 1) % kPanasonicAc64BlocksPerSection == 0) {
if ((block + 1) % blocks_per_section == 0) {
uint64_t junk;
used = matchGeneric(results->rawbuf + offset, &junk,
results->rawlen - offset, 0,
Expand All @@ -1026,8 +1056,8 @@ bool IRrecv::decodePanasonicAC64(decode_results *results, uint16_t offset,
results->value = data;
results->decode_type = decode_type_t::PANASONIC_AC64;
results->bits = nbits;
results->address = GETBITS64(data, kSectionBits, kSectionBits);
results->command = GETBITS64(data, 0, kSectionBits);;
results->address = GETBITS64(data, bits_per_block, bits_per_block);
results->command = GETBITS64(data, 0, bits_per_block);
return true;
}
#endif // DECODE_PANASONIC_AC64
80 changes: 80 additions & 0 deletions test/ir_Panasonic_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1391,3 +1391,83 @@ TEST(TestDecodePanasonicAC64, SyntheticMessage) {
"m920s13946",
irsend.outputStr());
}

// Decode a real *short* Panasonic AC 64 bit message
TEST(TestDecodePanasonicAC64, RealShortMessage) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
// https://github.com/crankyoldgit/IRremoteESP8266/issues/1307#issuecomment-719038870
// https://github.com/crankyoldgit/IRremoteESP8266/files/5461382/quiet-powerful.txt
const uint16_t rawData[201] = {
3548, 3448, 922, 826, 922, 2576, 922, 2574, 918, 832, 916, 830, 918, 830,
918, 830, 918, 2574, 924, 824, 922, 2576, 922, 2574, 922, 826, 922, 826,
922, 826, 922, 826, 922, 2574, 922, 2574, 918, 830, 918, 2574, 922, 832,
916, 2574, 922, 2574, 922, 830, 918, 830, 918, 2574, 922, 826, 922, 2576,
922, 826, 922, 2574, 922, 2574, 922, 826, 922, 826, 3542, 3452, 918, 830,
918, 2574, 922, 2574, 922, 830, 916, 830, 918, 830, 918, 830, 918, 2574,
922, 832, 916, 2574, 922, 2574, 922, 830, 918, 830, 916, 830, 918, 830,
918, 2576, 922, 2574, 922, 826, 922, 2574, 922, 826, 922, 2574, 922, 2574,
918, 830, 916, 830, 918, 2580, 918, 830, 918, 2578, 918, 830, 918, 2580,
918, 2574, 922, 830, 918, 830, 3544, 3446, 922, 832, 916, 2574, 922, 2574,
922, 826, 922, 826, 922, 826, 922, 826, 922, 2574, 918, 830, 918, 2580,
916, 2580, 918, 830, 918, 830, 918, 830, 916, 830, 918, 2580, 918, 2574,
922, 830, 918, 2574, 922, 830, 916, 2576, 922, 2574, 922, 830, 918, 830,
918, 2574, 922, 830, 916, 2576, 922, 830, 918, 2574, 922, 2576, 922, 830,
918, 830, 3538, 3450, 922}; // UNKNOWN A9E430DB

irsend.sendRaw(rawData, 201, kPanasonicFreq);
irsend.makeDecodeResult();

ASSERT_TRUE(irrecv.decode(&irsend.capture));
ASSERT_EQ(PANASONIC_AC64, irsend.capture.decode_type);
EXPECT_EQ(kPanasonicAc64Bits / 2, irsend.capture.bits);
EXPECT_EQ(0x35358686, irsend.capture.value);
EXPECT_EQ(0, irsend.capture.address);
EXPECT_EQ(0x35358686, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);

EXPECT_EQ(
"", IRAcUtils::resultAcToString(&irsend.capture));
stdAc::state_t r, p;
ASSERT_FALSE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}

// Decode a synthetic *short Panasonic AC 64 bit message
TEST(TestDecodePanasonicAC64, SyntheticShortMessage) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();

irsend.sendPanasonicAC64(0x35358686, kPanasonicAc64Bits / 2);
irsend.makeDecodeResult();

ASSERT_TRUE(irrecv.decode(&irsend.capture));
ASSERT_EQ(PANASONIC_AC64, irsend.capture.decode_type);
EXPECT_EQ(kPanasonicAc64Bits / 2, irsend.capture.bits);
EXPECT_EQ(0x35358686, irsend.capture.value);
EXPECT_EQ(0, irsend.capture.address);
EXPECT_EQ(0x35358686, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);

EXPECT_EQ(
"f36700d50"
"m3543s3450"
"m920s828m920s2575m920s2575m920s828m920s828m920s828m920s828m920s2575"
"m920s828m920s2575m920s2575m920s828m920s828m920s828m920s828m920s2575"
"m920s2575m920s828m920s2575m920s828m920s2575m920s2575m920s828m920s828"
"m920s2575m920s828m920s2575m920s828m920s2575m920s2575m920s828m920s828"
"m3543s3450"
"m920s828m920s2575m920s2575m920s828m920s828m920s828m920s828m920s2575"
"m920s828m920s2575m920s2575m920s828m920s828m920s828m920s828m920s2575"
"m920s2575m920s828m920s2575m920s828m920s2575m920s2575m920s828m920s828"
"m920s2575m920s828m920s2575m920s828m920s2575m920s2575m920s828m920s828"
"m3543s3450"
"m920s828m920s2575m920s2575m920s828m920s828m920s828m920s828m920s2575"
"m920s828m920s2575m920s2575m920s828m920s828m920s828m920s828m920s2575"
"m920s2575m920s828m920s2575m920s828m920s2575m920s2575m920s828m920s828"
"m920s2575m920s828m920s2575m920s828m920s2575m920s2575m920s828m920s828"
"m3543s3450"
"m920s13946",
irsend.outputStr());
}

0 comments on commit 40c93eb

Please sign in to comment.