From ab1eac113363934904e35de592bc9a69d3819ff1 Mon Sep 17 00:00:00 2001 From: Mateusz Bronk Date: Fri, 30 Aug 2024 15:30:32 +0200 Subject: [PATCH] Argo WREM2 - changed proto msg size: 96->90 bits Includes `matchBytes()` change to be able to work with non-byte-aligned bit lengths. Signed-off-by: Mateusz Bronk --- src/IRac.cpp | 2 +- src/IRrecv.cpp | 34 ++++++++++++++++++++------------ src/IRremoteESP8266.h | 2 +- test/IRrecv_test.cpp | 8 ++++++-- test/ir_Argo_test.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 74 insertions(+), 18 deletions(-) diff --git a/src/IRac.cpp b/src/IRac.cpp index b500303d9..dd5598a2a 100644 --- a/src/IRac.cpp +++ b/src/IRac.cpp @@ -4563,7 +4563,7 @@ namespace IRAcUtils { #endif // DECODE_AMCOR #if DECODE_ARGO case decode_type_t::ARGO: { - const uint16_t length = decode->bits / 8; + const uint16_t length = static_cast(ceil(static_cast(decode->bits) / 8.0)); if (IRArgoAC_WREM3::isValidWrem3Message(decode->state, decode->bits, true)) { IRArgoAC_WREM3 ac(kGpioUnused); diff --git a/src/IRrecv.cpp b/src/IRrecv.cpp index 316dfc149..4ba52fb4d 100644 --- a/src/IRrecv.cpp +++ b/src/IRrecv.cpp @@ -1583,8 +1583,6 @@ uint16_t IRrecv::_matchGeneric(volatile uint16_t *data_ptr, const uint8_t tolerance, const int16_t excess, const bool MSBfirst) { - // If we are expecting byte sizes, check it's a factor of 8 or fail. - if (!use_bits && nbits % 8 != 0) return 0; // Calculate if we expect a trailing space in the data section. const bool kexpectspace = footermark || (onespace != zerospace); // Calculate how much remaining buffer is required. @@ -1607,23 +1605,33 @@ uint16_t IRrecv::_matchGeneric(volatile uint16_t *data_ptr, return 0; // Data - if (use_bits) { // Bits. - match_result_t result = IRrecv::matchData(data_ptr + offset, nbits, + if (!use_bits) { // Bytes. + uint16_t data_used = IRrecv::matchBytes(data_ptr + offset, result_bytes_ptr, + remaining - offset, nbits / 8, + onemark, onespace, + zeromark, zerospace, tolerance, + excess, MSBfirst, kexpectspace); + if (!data_used) return 0; + offset += data_used; + } + + //Only using bits, or using *bytes*, but number of bits was not a multiple of 8 + if (use_bits || nbits % 8 != 0) { + uint16_t target_bit_count = (use_bits)? nbits : nbits % 8; + match_result_t result = IRrecv::matchData(data_ptr + offset, target_bit_count, onemark, onespace, zeromark, zerospace, tolerance, excess, MSBfirst, kexpectspace); if (!result.success) return 0; - *result_bits_ptr = result.data; + if (use_bits) { + *result_bits_ptr = result.data; + } else { + //Fill in last (non-full) byte + result_bytes_ptr[nbits / 8] = static_cast(result.data); + } offset += result.used; - } else { // bytes - uint16_t data_used = IRrecv::matchBytes(data_ptr + offset, result_bytes_ptr, - remaining - offset, nbits / 8, - onemark, onespace, - zeromark, zerospace, tolerance, - excess, MSBfirst, kexpectspace); - if (!data_used) return 0; - offset += data_used; } + // Footer if (footermark && !matchMark(*(data_ptr + offset++), footermark, tolerance, excess)) diff --git a/src/IRremoteESP8266.h b/src/IRremoteESP8266.h index b5daffaf8..5378a928e 100644 --- a/src/IRremoteESP8266.h +++ b/src/IRremoteESP8266.h @@ -1165,7 +1165,7 @@ const uint16_t kAmcorBits = kAmcorStateLength * 8; const uint16_t kAmcorDefaultRepeat = kSingleRepeat; const uint16_t kArgoStateLength = 12; const uint16_t kArgoShortStateLength = 4; -const uint16_t kArgoBits = kArgoStateLength * 8; +const uint16_t kArgoBits = 90; // The protocol bit length is NOT full byte aligned const uint16_t kArgoShortBits = kArgoShortStateLength * 8; const uint16_t kArgo3AcControlStateLength = 6; // Bytes const uint16_t kArgo3iFeelReportStateLength = 2; // Bytes diff --git a/test/IRrecv_test.cpp b/test/IRrecv_test.cpp index 2d32847d3..fb246eaba 100644 --- a/test/IRrecv_test.cpp +++ b/test/IRrecv_test.cpp @@ -1289,7 +1289,7 @@ TEST(TestMatchGeneric, UsingBytes) { EXPECT_GT(irsend.capture.rawlen - kStartOffset, entries_used); EXPECT_EQ(16, entries_used); - // Asking for non mod-8 size should fail. + // Asking for non mod-8 size should SUCCEED and fill-in next byte. entries_used = irrecv.matchGeneric( irsend.capture.rawbuf + offset, result_data, irsend.capture.rawlen - offset, @@ -1302,7 +1302,11 @@ TEST(TestMatchGeneric, UsingBytes) { 1, // 1% Tolerance 0, // No excess margin true); // MSB first. - ASSERT_EQ(0, entries_used); + ASSERT_NE(0, entries_used); + EXPECT_EQ(0b10101010, result_data[0]); + EXPECT_EQ(0b1, result_data[1]); + EXPECT_GT(irsend.capture.rawlen - kStartOffset, entries_used); + EXPECT_EQ(18, entries_used); // Expecting different timings should fail. entries_used = irrecv.matchGeneric( diff --git a/test/ir_Argo_test.cpp b/test/ir_Argo_test.cpp index 817272a17..66b0712c6 100644 --- a/test/ir_Argo_test.cpp +++ b/test/ir_Argo_test.cpp @@ -104,7 +104,7 @@ TEST(TestArgoACClass, MessageConstructon) { auto expected = std::vector({ 0xAC, 0xF5, 0x00, 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0xAC, 0xD6, 0x01}); auto actual = ac.getRaw(); - EXPECT_THAT(std::vector(actual, actual + kArgoBits / 8), + EXPECT_THAT(std::vector(actual, actual + static_cast(ceil(static_cast(kArgoBits) / 8.0))), ::testing::ElementsAreArray(expected)); EXPECT_EQ( "Model: 1 (WREM2), Power: On, Mode: 0 (Cool), Fan: 0 (Auto), Temp: 20C, " @@ -1461,6 +1461,50 @@ TEST(TestDecodeArgo, RealShortDecode) { EXPECT_EQ(28, r.sensorTemperature); } +TEST(TestDecodeArgo, Issue2133_90bit_message) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + // Full Argo command message (90 bits) + const uint16_t command_90bit[193] = { + 6422, 3190, 408, 872, 428, 848, 428, 2126, 402, 2150, 408, 872, 404, 2152, 402, 874, 402, + 2152, 402, 2154, 406, 872, 428, 2126, 404, 876, 404, 2150, 430, 2124, 432, 2122, 432, 2124, + 404, 874, 404, 874, 426, 852, 428, 850, 412, 864, 406, 872, 404, 874, 400, 2154, 428, 2128, + 402, 876, 402, 874, 400, 2154, 404, 2150, 406, 2150, 400, 878, 400, 876, 402, 874, 416, 2136, + 404, 2152, 402, 876, 402, 874, 402, 874, 428, 852, 402, 874, 404, 872, 400, 876, 402, 876, + 404, 872, 430, 846, 402, 2152, 406, 2150, 406, 2150, 404, 874, 432, 846, 426, 850, 428, 850, + 400, 878, 398, 876, 404, 874, 404, 874, 400, 2152, 432, 2124, 428, 2128, 432, 846, 426, 852, + 400, 2154, 404, 874, 426, 2128, 428, 2128, 404, 872, 430, 848, 426, 2128, 404, 872, 414, 2140, + 432, 848, 400, 876, 426, 850, 404, 872, 402, 876, 400, 876, 430, 848, 404, 872, 404, 874, 402, + 2154, 402, 876, 428, 2126, 406, 872, 426, 2128, 426, 852, 404, 872, 430, 2124, 404, 874, 430, + 846, 426, 2128, 400 + }; // ARGO WREM2 (off command) + + irsend.reset(); + uint8_t expectedState[kArgoStateLength] = { + 0xAC, 0xF5, 0x80, 0x39, 0x06, 0xE0, 0x00, 0xA7, 0x29, 0x80, 0x4A, 0x02 }; + irsend.sendRaw(command_90bit, sizeof(command_90bit) / sizeof(command_90bit[0]), 38); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(decode_type_t::ARGO, irsend.capture.decode_type); + EXPECT_EQ(kArgoBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "Model: 1 (WREM2), Power: Off, Mode: 0 (Cool), Fan: 3 (Max), Temp: 10C, Sensor Temp: 21C, Max: Off, IFeel: On, Night: Off", + IRAcUtils::resultAcToString(&irsend.capture)); + stdAc::state_t r, p; + EXPECT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); + EXPECT_EQ(stdAc::ac_command_t::kControlCommand, r.command); + + EXPECT_EQ(21, r.sensorTemperature); // Note: This may be off by 1 per the report in #2133 + EXPECT_TRUE(r.iFeel); + EXPECT_FALSE(r.power); + EXPECT_EQ(10, r.degrees); + EXPECT_EQ(stdAc::opmode_t::kCool, r.mode); +} + + /// /// @brief Test Fixture for recorded tests ///