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

Increase Panasonic A/C message tolerances. #542

Merged
merged 1 commit into from
Oct 3, 2018
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
30 changes: 21 additions & 9 deletions src/ir_Panasonic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
// CS-YW9MKD (confirmed)
// A/C Remotes:
// A75C3747 (confirmed)
// A75C3704

// Constants
// Ref:
Expand Down Expand Up @@ -218,6 +219,7 @@ bool IRrecv::decodePanasonic(decode_results *results, uint16_t nbits,
// CS-YW9MKD
// A/C Remotes:
// A75C3747
// A75C3704
//
void IRsend::sendPanasonicAC(uint8_t data[], uint16_t nbytes, uint16_t repeat) {
if (nbytes < kPanasonicAcStateLength) return;
Expand Down Expand Up @@ -623,6 +625,7 @@ std::string IRPanasonicAc::toString() {
// CS-YW9MKD
// A/C Remotes:
// A75C3747 (Confirmed)
// A75C3704
bool IRrecv::decodePanasonicAC(decode_results *results, uint16_t nbits,
bool strict) {
if (nbits % 8 != 0) // nbits has to be a multiple of nr. of bits in a byte.
Expand All @@ -643,11 +646,15 @@ bool IRrecv::decodePanasonicAC(decode_results *results, uint16_t nbits,
match_result_t data_result;

// Header
if (!matchMark(results->rawbuf[offset], kPanasonicHdrMark)) return false;
if (!matchMark(results->rawbuf[offset], kPanasonicHdrMark,
kPanasonicAcTolerance, kPanasonicAcExcess))
return false;
// Calculate how long the common tick time is based on the header mark.
uint32_t m_tick = results->rawbuf[offset++] * kRawTick /
kPanasonicHdrMarkTicks;
if (!matchSpace(results->rawbuf[offset], kPanasonicHdrSpace)) return false;
if (!matchSpace(results->rawbuf[offset], kPanasonicHdrSpace,
kPanasonicAcTolerance, kPanasonicAcExcess))
return false;
// Calculate how long the common tick time is based on the header space.
uint32_t s_tick = results->rawbuf[offset++] * kRawTick /
kPanasonicHdrSpaceTicks;
Expand All @@ -662,7 +669,7 @@ bool IRrecv::decodePanasonicAC(decode_results *results, uint16_t nbits,
kPanasonicOneSpaceTicks * s_tick,
kPanasonicBitMarkTicks * m_tick,
kPanasonicZeroSpaceTicks * s_tick,
kTolerance, 0, false);
kPanasonicAcTolerance, kPanasonicAcExcess, false);
if (data_result.success == false) {
DPRINT("DEBUG: offset = ");
DPRINTLN(offset + data_result.used);
Expand All @@ -671,14 +678,18 @@ bool IRrecv::decodePanasonicAC(decode_results *results, uint16_t nbits,
results->state[i] = data_result.data;
}
// Section footer.
if (!matchMark(results->rawbuf[offset++], kPanasonicBitMarkTicks * m_tick))
if (!matchMark(results->rawbuf[offset++], kPanasonicBitMarkTicks * m_tick,
kPanasonicAcTolerance, kPanasonicAcExcess))
return false;
if (!matchSpace(results->rawbuf[offset++], kPanasonicAcSectionGap))
if (!matchSpace(results->rawbuf[offset++], kPanasonicAcSectionGap,
kPanasonicAcTolerance, kPanasonicAcExcess))
return false;
// Header.
if (!matchMark(results->rawbuf[offset++], kPanasonicHdrMarkTicks * m_tick))
if (!matchMark(results->rawbuf[offset++], kPanasonicHdrMarkTicks * m_tick,
kPanasonicAcTolerance, kPanasonicAcExcess))
return false;
if (!matchSpace(results->rawbuf[offset++], kPanasonicHdrSpaceTicks * s_tick))
if (!matchSpace(results->rawbuf[offset++], kPanasonicHdrSpaceTicks * s_tick,
kPanasonicAcTolerance, kPanasonicAcExcess))
return false;
// Data (Section #2)
// Keep reading bytes until we either run out of data.
Expand All @@ -689,7 +700,7 @@ bool IRrecv::decodePanasonicAC(decode_results *results, uint16_t nbits,
kPanasonicOneSpaceTicks * s_tick,
kPanasonicBitMarkTicks * m_tick,
kPanasonicZeroSpaceTicks * s_tick,
kTolerance, 0, false);
kPanasonicAcTolerance, kPanasonicAcExcess, false);
if (data_result.success == false) {
DPRINT("DEBUG: offset = ");
DPRINTLN(offset + data_result.used);
Expand All @@ -698,7 +709,8 @@ bool IRrecv::decodePanasonicAC(decode_results *results, uint16_t nbits,
results->state[i] = data_result.data;
}
// Message Footer.
if (!matchMark(results->rawbuf[offset++], kPanasonicBitMarkTicks * m_tick))
if (!matchMark(results->rawbuf[offset++], kPanasonicBitMarkTicks * m_tick,
kPanasonicAcTolerance, kPanasonicAcExcess))
return false;
if (offset <= results->rawlen &&
!matchAtLeast(results->rawbuf[offset++], kPanasonicAcMessageGap))
Expand Down
3 changes: 3 additions & 0 deletions src/ir_Panasonic.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@

// Constants
const uint16_t kPanasonicFreq = 36700;
const uint16_t kPanasonicAcExcess = 0;
// Much higher than usual. See issue #540.
const uint16_t kPanasonicAcTolerance = 40;

const uint8_t kPanasonicAcAuto = 0; // 0b0000
const uint8_t kPanasonicAcDry = 2; // 0b0010
Expand Down
60 changes: 60 additions & 0 deletions test/ir_Panasonic_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -827,3 +827,63 @@ TEST(TestGeneralPanasonic, typeToString) {
EXPECT_EQ("PANASONIC_AC", typeToString(PANASONIC_AC));
EXPECT_EQ("PANASONIC", typeToString(PANASONIC));
}

// Decode a problematic Panasonic AC message
TEST(TestDecodePanasonicAC, Issue540) {
IRsendTest irsend(0);
IRrecv irrecv(0);
irsend.begin();

// Data from Issue #540
uint16_t rawData[439] = {3512, 1714, 466, 408, 466, 1280, 470, 408, 466, 412,
466, 408, 466, 412, 462, 412, 466, 414, 466, 408, 466, 412, 462, 412, 466,
412, 466, 408, 466, 1280, 466, 412, 462, 416, 462, 412, 466, 408, 466,
412, 462, 416, 462, 412, 462, 1282, 462, 1284, 462, 1288, 466, 412, 462,
412, 462, 1284, 462, 416, 440, 438, 462, 412, 462, 412, 462, 416, 466,
412, 462, 412, 462, 412, 440, 442, 462, 412, 462, 412, 460, 418, 462, 416,
462, 412, 462, 418, 462, 412, 462, 416, 462, 412, 436, 442, 462, 412, 460,
418, 462, 416, 462, 412, 460, 412, 462, 420, 436, 438, 462, 412, 462, 416,
432, 448, 436, 438, 436, 1310, 436, 1310, 462, 420, 432, 442, 436, 438,
462, 416, 432, 444, 432, 10008, 3480, 1744, 492, 382, 492, 1254, 492, 386,
488, 390, 492, 382, 492, 386, 488, 386, 492, 386, 492, 386, 488, 386, 488,
386, 492, 386, 492, 382, 492, 1258, 488, 386, 488, 390, 492, 386, 488,
386, 488, 386, 492, 390, 488, 386, 488, 1256, 488, 1258, 488, 1262, 488,
390, 488, 386, 488, 1258, 488, 390, 488, 392, 488, 386, 488, 386, 488,
394, 488, 386, 488, 386, 488, 390, 488, 390, 488, 386, 488, 390, 462, 412,
488, 390, 462, 1282, 488, 390, 456, 416, 458, 1292, 456, 1288, 488, 1258,
488, 392, 456, 422, 488, 390, 484, 392, 484, 1262, 458, 420, 484, 1262,
482, 1262, 488, 392, 484, 394, 484, 416, 436, 442, 458, 416, 458, 422,
430, 448, 432, 442, 458, 416, 458, 1296, 432, 1314, 458, 1288, 432, 1312,
432, 1322, 428, 446, 428, 1318, 432, 442, 432, 1318, 432, 1318, 428, 446,
428, 1318, 428, 1322, 430, 448, 426, 448, 428, 452, 426, 452, 426, 448,
428, 472, 400, 478, 402, 478, 402, 472, 402, 476, 402, 472, 402, 478, 402,
472, 402, 1348, 398, 1348, 398, 1352, 398, 508, 370, 478, 398, 476, 398,
512, 366, 508, 370, 502, 372, 508, 340, 538, 372, 504, 344, 1400, 344,
1400, 346, 1434, 314, 560, 316, 588, 290, 560, 314, 564, 396, 400, 474,
400, 480, 394, 480, 404, 474, 400, 454, 446, 454, 426, 448, 430, 424, 450,
428, 452, 448, 426, 426, 452, 424, 1322, 454, 426, 450, 424, 426, 452,
428, 452, 450, 424, 428, 446, 426, 1322, 454, 426, 422, 450, 454, 426,
448, 430, 454, 426, 448, 426, 428, 446, 454, 430, 454, 422, 452, 424, 424,
452, 452, 430, 424, 452, 452, 426, 448, 426, 426, 456, 448, 426, 448,
1296, 424, 1322, 426, 1326, 450, 1270, 478, 422, 454, 424, 424, 450, 454};
uint8_t expectedState[kPanasonicAcStateLength] = {
0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06,
0x02, 0x20, 0xE0, 0x04, 0x00, 0x39, 0x34, 0x80, 0xAF, 0x0D,
0x00, 0x0E, 0xE0, 0x00, 0x00, 0x81, 0x00, 0x00, 0x1E};

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

ASSERT_TRUE(irrecv.decode(&irsend.capture));
ASSERT_EQ(PANASONIC_AC, irsend.capture.decode_type);
EXPECT_EQ(kPanasonicAcBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
EXPECT_FALSE(irsend.capture.repeat);
IRPanasonicAc pana(0);
pana.setRaw(irsend.capture.state);
// TODO(crankyoldgit): Try to figure out what model this should be.
EXPECT_EQ("Model: 0 (UNKNOWN), Power: On, Mode: 3 (COOL), Temp: 26C, "
"Fan: 7 (AUTO), Swing (Vertical): 15 (AUTO), "
"Swing (Horizontal): 13 (AUTO), Quiet: Off, Powerful: Off",
pana.toString());
}