From 575a81b2002d81c0530e1e5e7b485d7d3a5ae6fc Mon Sep 17 00:00:00 2001 From: David Conran Date: Wed, 3 May 2023 22:06:18 +1000 Subject: [PATCH] Add support for a 40bit varient of the standard Panasonic protocol (#1977) This seems to be a shorter version of the normal 48 bit protocol. Different manufacturer code, and slightly different checksum calc. Modified the exist code to support it rather than add a new protocol. Fixes #1976 --- src/IRrecv.cpp | 7 ++- src/IRremoteESP8266.h | 2 + src/ir_Panasonic.cpp | 17 ++++-- test/ir_Panasonic_test.cpp | 114 ++++++++++++++++++++++++++++++------- 4 files changed, 112 insertions(+), 28 deletions(-) diff --git a/src/IRrecv.cpp b/src/IRrecv.cpp index 4a7faaa5..cc00c1d6 100644 --- a/src/IRrecv.cpp +++ b/src/IRrecv.cpp @@ -701,9 +701,12 @@ bool IRrecv::decode(decode_results *results, irparams_t *save, return true; #endif #if DECODE_PANASONIC - DPRINTLN("Attempting Panasonic decode"); + DPRINTLN("Attempting Panasonic (48-bit) decode"); if (decodePanasonic(results, offset)) return true; -#endif + DPRINTLN("Attempting Panasonic (40-bit) decode"); + if (decodePanasonic(results, offset, kPanasonic40Bits, true, + kPanasonic40Manufacturer)) return true; +#endif // DECODE_PANASONIC #if DECODE_LG DPRINTLN("Attempting LG (28-bit) decode"); if (decodeLG(results, offset, kLgBits, true)) return true; diff --git a/src/IRremoteESP8266.h b/src/IRremoteESP8266.h index 07a4d4a5..a3f634c5 100644 --- a/src/IRremoteESP8266.h +++ b/src/IRremoteESP8266.h @@ -1335,6 +1335,8 @@ const uint16_t kNeoclimaBits = kNeoclimaStateLength * 8; const uint16_t kNeoclimaMinRepeat = kNoRepeat; const uint16_t kPanasonicBits = 48; const uint32_t kPanasonicManufacturer = 0x4004; +const uint32_t kPanasonic40Manufacturer = 0x34; +const uint16_t kPanasonic40Bits = 40; const uint16_t kPanasonicAcStateLength = 27; const uint16_t kPanasonicAcStateShortLength = 16; const uint16_t kPanasonicAcBits = kPanasonicAcStateLength * 8; diff --git a/src/ir_Panasonic.cpp b/src/ir_Panasonic.cpp index a0a0b6b2..82acaac7 100644 --- a/src/ir_Panasonic.cpp +++ b/src/ir_Panasonic.cpp @@ -128,8 +128,15 @@ uint64_t IRsend::encodePanasonic(const uint16_t manufacturer, bool IRrecv::decodePanasonic(decode_results *results, uint16_t offset, const uint16_t nbits, const bool strict, const uint32_t manufacturer) { - if (strict && nbits != kPanasonicBits) - return false; // Request is out of spec. + if (strict) { // Compliance checks + switch (nbits) { + case kPanasonic40Bits: + case kPanasonicBits: + break; + default: + return false; // Request is out of spec. + } + } uint64_t data = 0; @@ -147,8 +154,10 @@ bool IRrecv::decodePanasonic(decode_results *results, uint16_t offset, if (address != manufacturer) // Verify the Manufacturer code. return false; // Verify the checksum. - uint8_t checksumOrig = data; - uint8_t checksumCalc = (data >> 24) ^ (data >> 16) ^ (data >> 8); + const uint8_t checksumOrig = data; + uint8_t checksumCalc = (data >> 16) ^ (data >> 8); + if (nbits != kPanasonic40Bits) + checksumCalc ^= (data >> 24); if (checksumOrig != checksumCalc) return false; } diff --git a/test/ir_Panasonic_test.cpp b/test/ir_Panasonic_test.cpp index 3e52cef8..3e3ae4d2 100644 --- a/test/ir_Panasonic_test.cpp +++ b/test/ir_Panasonic_test.cpp @@ -13,7 +13,7 @@ // Tests for encodePanasonic(). TEST(TestEncodePanasonic, General) { - IRsendTest irsend(4); + IRsendTest irsend(kGpioUnused); EXPECT_EQ(0x0, irsend.encodePanasonic(0, 0, 0, 0)); EXPECT_EQ(0x101010101, irsend.encodePanasonic(1, 1, 1, 1)); EXPECT_EQ(0xFFFF, irsend.encodePanasonic(0, 0, 0, 0xFF)); @@ -28,7 +28,7 @@ TEST(TestEncodePanasonic, General) { // Test sending typical data only. TEST(TestSendPanasonic64, SendDataOnly) { - IRsendTest irsend(4); + IRsendTest irsend(kGpioUnused); irsend.begin(); irsend.reset(); @@ -76,7 +76,7 @@ TEST(TestSendPanasonic64, SendDataOnly) { // Test sending with different repeats. TEST(TestSendPanasonic64, SendWithRepeats) { - IRsendTest irsend(4); + IRsendTest irsend(kGpioUnused); irsend.begin(); irsend.reset(); @@ -147,7 +147,7 @@ TEST(TestSendPanasonic64, SendWithRepeats) { // Test sending an atypical data size. TEST(TestSendPanasonic64, SendUnusualSize) { - IRsendTest irsend(4); + IRsendTest irsend(kGpioUnused); irsend.begin(); irsend.reset(); @@ -213,8 +213,8 @@ TEST(TestSendPanasonic, CompareToSendPanasonic64) { // Decode normal Panasonic messages. TEST(TestDecodePanasonic, NormalDecodeWithStrict) { - IRsendTest irsend(4); - IRrecv irrecv(4); + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); irsend.begin(); // Normal Panasonic 48-bit message. @@ -259,8 +259,8 @@ TEST(TestDecodePanasonic, NormalDecodeWithStrict) { // Decode normal repeated Panasonic messages. TEST(TestDecodePanasonic, NormalDecodeWithRepeatAndStrict) { - IRsendTest irsend(4); - IRrecv irrecv(4); + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); irsend.begin(); // Normal Panasonic 48-bit message with 2 repeats. @@ -293,8 +293,8 @@ TEST(TestDecodePanasonic, NormalDecodeWithRepeatAndStrict) { // Decode Panasonic messages with unsupported values. TEST(TestDecodePanasonic, DecodeWithNonStrictValues) { - IRsendTest irsend(4); - IRrecv irrecv(4); + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); irsend.begin(); irsend.reset(); @@ -331,8 +331,8 @@ TEST(TestDecodePanasonic, DecodeWithNonStrictValues) { // Decode Panasonic messages with unsupported size/lengths. TEST(TestDecodePanasonic, DecodeWithNonStrictSize) { - IRsendTest irsend(4); - IRrecv irrecv(4); + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); irsend.begin(); irsend.reset(); @@ -375,8 +375,8 @@ TEST(TestDecodePanasonic, DecodeWithNonStrictSize) { // Decode (non-standard) 64-bit messages. TEST(TestDecodePanasonic, Decode64BitMessages) { - IRsendTest irsend(4); - IRrecv irrecv(4); + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); irsend.begin(); irsend.reset(); @@ -395,8 +395,8 @@ TEST(TestDecodePanasonic, Decode64BitMessages) { // Decode a 'real' example via GlobalCache TEST(TestDecodePanasonic, DecodeGlobalCacheExample) { - IRsendTest irsend(4); - IRrecv irrecv(4); + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); irsend.begin(); irsend.reset(); @@ -432,8 +432,8 @@ TEST(TestDecodePanasonic, DecodeGlobalCacheExample) { // Fail to decode a non-Panasonic example via GlobalCache TEST(TestDecodePanasonic, FailToDecodeNonPanasonicExample) { - IRsendTest irsend(4); - IRrecv irrecv(4); + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); irsend.begin(); irsend.reset(); @@ -452,8 +452,8 @@ TEST(TestDecodePanasonic, FailToDecodeNonPanasonicExample) { // Failing to decode Panasonic in Issue #245 TEST(TestDecodePanasonic, DecodeIssue245) { - IRsendTest irsend(4); - IRrecv irrecv(4); + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); irsend.begin(); irsend.reset(); @@ -813,8 +813,8 @@ TEST(TestIRPanasonicAcClass, HumanReadable) { // Decode normal Panasonic AC messages. TEST(TestDecodePanasonicAC, RealExample) { - IRsendTest irsend(4); - IRrecv irrecv(4); + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); irsend.begin(); // Data from Issue #525 @@ -1586,3 +1586,73 @@ TEST(TestIRPanasonicAc32Class, HumanReadable) { "Swing(H): Off, Swing(V): 5 (Lowest)", ac.toString()); } + +// Decode a 'real' example of a captured 40 bit panasonic message +TEST(TestDecodePanasonic, RealPanasonic40BitMesg) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + irsend.reset(); + // Panasonic 40 bit code https://github.com/crankyoldgit/IRremoteESP8266/issues/1976#issue-1660147581 + const uint16_t rawData1[83] = { + 3486, 1742, + 432, 456, 406, 456, 406, 1336, 406, 1312, 430, 456, 406, 1334, 408, 456, + 406, 456, 408, 456, 406, 1334, 408, 456, 408, 454, 408, 1334, 408, 456, + 406, 1336, 406, 456, 408, 1334, 408, 456, 406, 456, 408, 1336, 406, 456, + 408, 454, 406, 456, 406, 454, 408, 1332, 410, 1332, 408, 1334, 408, 1336, + 406, 1334, 410, 1332, 410, 454, 406, 456, 406, 456, 406, 1332, 410, 1334, + 408, 454, 406, 1336, 406, 1336, 406, 454, 410, 454, 408}; // UKN 1D41D404 + + irsend.sendRaw(rawData1, 83, 38); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(PANASONIC, irsend.capture.decode_type); + EXPECT_EQ(kPanasonic40Bits, irsend.capture.bits); + EXPECT_EQ(0x344A90FC6C, irsend.capture.value); + EXPECT_EQ(0x34, irsend.capture.address); + EXPECT_EQ(0x4A90FC6C, irsend.capture.command); + EXPECT_FALSE(irsend.capture.repeat); + + // night ch3 from https://github.com/crankyoldgit/IRremoteESP8266/issues/1976#issuecomment-1501736104 + const uint16_t rawData2[83] = { + 3490, 1734, + 440, 426, 460, 400, 438, 1304, 438, 1302, 440, 426, 436, 1302, 464, 400, + 462, 400, 462, 402, 462, 1278, 438, 426, 438, 426, 460, 1282, 434, 428, + 434, 1308, 460, 402, 460, 1280, 440, 422, 438, 426, 436, 1306, 438, 424, + 462, 402, 436, 426, 462, 400, 438, 426, 436, 1304, 434, 1308, 438, 1304, + 464, 1278, 436, 1306, 466, 398, 464, 398, 466, 1276, 466, 1274, 464, 1280, + 462, 402, 436, 1304, 466, 1276, 440, 422, 440, 424, 460}; // UKN DAE32FFC + irsend.reset(); + + irsend.sendRaw(rawData2, 83, 38); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(PANASONIC, irsend.capture.decode_type); + EXPECT_EQ(kPanasonic40Bits, irsend.capture.bits); + EXPECT_EQ(0x344A907CEC, irsend.capture.value); + EXPECT_EQ(0x34, irsend.capture.address); + EXPECT_EQ(0x4A907CEC, irsend.capture.command); + EXPECT_FALSE(irsend.capture.repeat); +} + +// recreate the above real message, synthetically. +TEST(TestDecodePanasonic, SynthticPanasonic40BitMesg) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + irsend.reset(); + + irsend.sendPanasonic64(0x344A90FC6C, kPanasonic40Bits); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(PANASONIC, irsend.capture.decode_type); + EXPECT_EQ(kPanasonic40Bits, irsend.capture.bits); + EXPECT_EQ(0x344A90FC6C, irsend.capture.value); + EXPECT_EQ(0x34, irsend.capture.address); + EXPECT_EQ(0x4A90FC6C, irsend.capture.command); + EXPECT_FALSE(irsend.capture.repeat); +}