Experimental basic support for Sanyo AC 152 bit protocol. (#1828)

* LSBF order determined by sequencing a temperature range.
* add `sendSanyoAc152()` & `decodeSanyoAc152()` routines
* Fix some comments.
* Unit test coverage added for new protocol.
* Update supported devices info.

For #1826
This commit is contained in:
David Conran
2022-06-24 17:00:24 +10:00
committed by GitHub
parent f706f99fd9
commit ea5d911027
11 changed files with 188 additions and 6 deletions

View File

@@ -1132,6 +1132,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
DPRINTLN("Attempting TCL AC 96-bit decode");
if (decodeTcl96Ac(results, offset)) return true;
#endif // DECODE_TCL96AC
#if DECODE_SANYO_AC152
DPRINTLN("Attempting Sanyo AC 152-bit decode");
if (decodeSanyoAc152(results, offset)) return true;
#endif // DECODE_SANYO_AC152
// Typically new protocols are added above this line.
}
#if DECODE_HASH

View File

@@ -325,6 +325,12 @@ class IRrecv {
const uint16_t nbits = kSanyoAc88Bits,
const bool strict = true);
#endif // DECODE_SANYO_AC88
#if DECODE_SANYO_AC152
bool decodeSanyoAc152(decode_results *results,
uint16_t offset = kStartOffset,
const uint16_t nbits = kSanyoAc152Bits,
const bool strict = true);
#endif // DECODE_SANYO_AC152
#if DECODE_MITSUBISHI
bool decodeMitsubishi(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kMitsubishiBits,

View File

@@ -238,6 +238,13 @@
#define SEND_SANYO_AC88 _IR_ENABLE_DEFAULT_
#endif // SEND_SANYO_AC88
#ifndef DECODE_SANYO_AC152
#define DECODE_SANYO_AC152 _IR_ENABLE_DEFAULT_
#endif // DECODE_SANYO_AC152
#ifndef SEND_SANYO_AC152
#define SEND_SANYO_AC152 _IR_ENABLE_DEFAULT_
#endif // SEND_SANYO_AC152
#ifndef DECODE_MITSUBISHI
#define DECODE_MITSUBISHI _IR_ENABLE_DEFAULT_
#endif // DECODE_MITSUBISHI
@@ -927,7 +934,7 @@
DECODE_SANYO_AC88 || DECODE_RHOSS || DECODE_HITACHI_AC264 || \
DECODE_KELON168 || DECODE_HITACHI_AC296 || DECODE_CARRIER_AC128 || \
DECODE_DAIKIN200 || DECODE_HAIER_AC160 || DECODE_TCL96AC || \
DECODE_BOSCH144 || \
DECODE_BOSCH144 || DECODE_SANYO_AC152 || \
false)
// Add any DECODE to the above if it uses result->state (see kStateSizeMax)
// you might also want to add the protocol to hasACState function
@@ -1088,8 +1095,9 @@ enum decode_type_t {
CLIMABUTLER,
TCL96AC,
BOSCH144, // 120
SANYO_AC152,
// Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = BOSCH144,
kLastDecodeType = SANYO_AC152,
};
// Message lengths & required repeat values
@@ -1299,6 +1307,9 @@ const uint16_t kSanyoAcBits = kSanyoAcStateLength * 8;
const uint16_t kSanyoAc88StateLength = 11;
const uint16_t kSanyoAc88Bits = kSanyoAc88StateLength * 8;
const uint16_t kSanyoAc88MinRepeat = 2;
const uint16_t kSanyoAc152StateLength = 19;
const uint16_t kSanyoAc152Bits = kSanyoAc152StateLength * 8;
const uint16_t kSanyoAc152MinRepeat = kNoRepeat;
const uint16_t kSanyoSA8650BBits = 12;
const uint16_t kSanyoLC7461AddressBits = 13;
const uint16_t kSanyoLC7461CommandBits = 8;

View File

@@ -768,6 +768,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
return kSanyoAcBits;
case SANYO_AC88:
return kSanyoAc88Bits;
case SANYO_AC152:
return kSanyoAc152Bits;
case SHARP_AC:
return kSharpAcBits;
case TCL96AC:
@@ -1353,6 +1355,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state,
sendSanyoAc88(state, nbytes);
break;
#endif // SEND_SANYO_AC88
#if SEND_SANYO_AC152
case SANYO_AC152:
sendSanyoAc152(state, nbytes);
break;
#endif // SEND_SANYO_AC152
#if SEND_SHARP_AC
case SHARP_AC:
sendSharpAc(state, nbytes);

View File

@@ -346,6 +346,11 @@ class IRsend {
const uint16_t nbytes = kSanyoAc88StateLength,
const uint16_t repeat = kSanyoAc88MinRepeat);
#endif // SEND_SANYO_AC88
#if SEND_SANYO_AC152
void sendSanyoAc152(const uint8_t *data,
const uint16_t nbytes = kSanyoAc152StateLength,
const uint16_t repeat = kSanyoAc152MinRepeat);
#endif // SEND_SANYO_AC152
#if SEND_DISH
// sendDISH() should typically be called with repeat=3 as DISH devices
// expect the code to be sent at least 4 times. (code + 3 repeats = 4 codes)

View File

@@ -404,6 +404,7 @@ IRTEXT_CONST_BLOB_DECL(kAllProtocolNamesStr) {
D_STR_CLIMABUTLER "\x0"
D_STR_TCL96AC "\x0"
D_STR_BOSCH144 "\x0"
D_STR_SANYO_AC152 "\x0"
///< New protocol strings should be added just above this line.
"\x0" ///< This string requires double null termination.
};

View File

@@ -213,6 +213,7 @@ bool hasACState(const decode_type_t protocol) {
case SAMSUNG_AC:
case SANYO_AC:
case SANYO_AC88:
case SANYO_AC152:
case SHARP_AC:
case TCL96AC:
case TCL112AC:

View File

@@ -77,6 +77,14 @@ const uint32_t kSanyoAc88Gap = 3675; ///< uSeconds
const uint16_t kSanyoAc88Freq = 38000; ///< Hz. (Guess only)
const uint8_t kSanyoAc88ExtraTolerance = 5; /// (%) Extra tolerance to use.
const uint16_t kSanyoAc152HdrMark = 3300; ///< uSeconds
const uint16_t kSanyoAc152BitMark = 440; ///< uSeconds
const uint16_t kSanyoAc152HdrSpace = 1725; ///< uSeconds
const uint16_t kSanyoAc152OneSpace = 1290; ///< uSeconds
const uint16_t kSanyoAc152ZeroSpace = 405; ///< uSeconds
const uint16_t kSanyoAc152Freq = 38000; ///< Hz. (Guess only)
const uint8_t kSanyoAc152ExtraTolerance = 13; /// (%) Extra tolerance to use.
#if SEND_SANYO
/// Construct a Sanyo LC7461 message.
/// @param[in] address The 13 bit value of the address(Custom) portion of the
@@ -687,7 +695,7 @@ void IRsend::sendSanyoAc88(const uint8_t data[], const uint16_t nbytes,
#endif // SEND_SANYO_AC88
#if DECODE_SANYO_AC88
/// Decode the supplied SanyoAc message.
/// Decode the supplied SanyoAc88 message.
/// Status: ALPHA / Untested.
/// @param[in,out] results Ptr to the data to decode & where to store the decode
/// @warning data's bit order may change. It is not yet confirmed.
@@ -976,3 +984,61 @@ String IRSanyoAc88::toString(void) const {
result += addLabeledString(minsToString(getClock()), kClockStr);
return result;
}
#if SEND_SANYO_AC152
/// Send a SanyoAc152 formatted message.
/// Status: BETA / Probably works.
/// @param[in] data An array of bytes containing the IR command.
/// @warning data's bit order may change. It is not yet confirmed.
/// @param[in] nbytes Nr. of bytes of data in the array.
/// @param[in] repeat Nr. of times the message is to be repeated.
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1826
void IRsend::sendSanyoAc152(const uint8_t data[], const uint16_t nbytes,
const uint16_t repeat) {
// (Header + Data + Footer) per repeat
sendGeneric(kSanyoAc152HdrMark, kSanyoAc152HdrSpace,
kSanyoAc152BitMark, kSanyoAc152OneSpace,
kSanyoAc152BitMark, kSanyoAc152ZeroSpace,
kSanyoAc152BitMark, kDefaultMessageGap,
data, nbytes, kSanyoAc152Freq, false, repeat, kDutyDefault);
space(kDefaultMessageGap); // Make a guess at a post message gap.
}
#endif // SEND_SANYO_AC152
#if DECODE_SANYO_AC152
/// Decode the supplied SanyoAc152 message.
/// Status: BETA / Probably works.
/// @param[in,out] results Ptr to the data to decode & where to store the decode
/// @warning data's bit order may change. It is not yet confirmed.
/// @param[in] offset The starting index to use when attempting to decode the
/// raw data. Typically/Defaults to kStartOffset.
/// @param[in] nbits The number of data bits to expect.
/// @param[in] strict Flag indicating if we should perform strict matching.
/// @return A boolean. True if it can decode it, false if it can't.
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1503
bool IRrecv::decodeSanyoAc152(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
if (strict && nbits != kSanyoAc152Bits)
return false;
// Header + Data + Footer
if (!matchGeneric(results->rawbuf + offset, results->state,
results->rawlen - offset, nbits,
kSanyoAc152HdrMark, kSanyoAc152HdrSpace,
kSanyoAc152BitMark, kSanyoAc152OneSpace,
kSanyoAc152BitMark, kSanyoAc152ZeroSpace,
kSanyoAc152BitMark,
kDefaultMessageGap, // Just a guess.
false, _tolerance + kSanyoAc152ExtraTolerance,
kMarkExcess, false))
return false; // No match!
// Success
results->decode_type = decode_type_t::SANYO_AC152;
results->bits = nbits;
// No need to record the state as we stored it as we decoded it.
// As we use result->state, we don't record value, address, or command as it
// is a union data type.
return true;
}
#endif // DECODE_SANYO_AC152

View File

@@ -13,6 +13,7 @@
/// @see https://docs.google.com/spreadsheets/d/1dYfLsnYvpjV-SgO8pdinpfuBIpSzm8Q1R5SabrLeskw/edit?usp=sharing
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1503
/// @see https://docs.google.com/spreadsheets/d/1weUmGAsEpfX38gg5rlDN69Uchnbr6gQl9FqHffLBIRk/edit#gid=0
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1826
// Supports:
// Brand: Sanyo, Model: SA 8650B - disabled
@@ -21,6 +22,8 @@
// Brand: Sanyo, Model: RCS-2HS4E remote (SANYO_AC)
// Brand: Sanyo, Model: SAP-K242AH A/C (SANYO_AC)
// Brand: Sanyo, Model: RCS-2S4E remote (SANYO_AC)
// Brand: Sanyo, Model: RCS-4MHVPIS4EE remote (SANYO_AC152)
// Brand: Sanyo, Model: SAP-KMRV124EHE A/C (SANYO_AC152)
#ifndef IR_SANYO_H_
#define IR_SANYO_H_

View File

@@ -980,13 +980,16 @@ D_STR_INDIRECT " " D_STR_MODE
#define D_STR_SANYO "SANYO"
#endif // D_STR_SANYO
#ifndef D_STR_SANYO_AC
#define D_STR_SANYO_AC "SANYO_AC"
#define D_STR_SANYO_AC D_STR_SANYO "_AC"
#endif // D_STR_SANYO_AC
#ifndef D_STR_SANYO_AC88
#define D_STR_SANYO_AC88 "SANYO_AC88"
#define D_STR_SANYO_AC88 D_STR_SANYO_AC "88"
#endif // D_STR_SANYO_AC88
#ifndef D_STR_SANYO_AC152
#define D_STR_SANYO_AC152 D_STR_SANYO_AC "152"
#endif // D_STR_SANYO_AC152
#ifndef D_STR_SANYO_LC7461
#define D_STR_SANYO_LC7461 "SANYO_LC7461"
#define D_STR_SANYO_LC7461 D_STR_SANYO "_LC7461"
#endif // D_STR_SANYO_LC7461
#ifndef D_STR_SHARP
#define D_STR_SHARP "SHARP"

View File

@@ -284,6 +284,14 @@ TEST(TestUtils, Housekeeping) {
ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::SANYO_AC88));
ASSERT_EQ(kSanyoAc88Bits, IRsend::defaultBits(decode_type_t::SANYO_AC88));
ASSERT_EQ(kSanyoAc88MinRepeat, IRsend::minRepeats(decode_type_t::SANYO_AC88));
// Sanyo A/C 152 Bit.
ASSERT_EQ("SANYO_AC152", typeToString(decode_type_t::SANYO_AC152));
ASSERT_EQ(decode_type_t::SANYO_AC152, strToDecodeType("SANYO_AC152"));
ASSERT_TRUE(hasACState(decode_type_t::SANYO_AC152));
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::SANYO_AC152));
ASSERT_EQ(kSanyoAc152Bits, IRsend::defaultBits(decode_type_t::SANYO_AC152));
ASSERT_EQ(kSanyoAc152MinRepeat,
IRsend::minRepeats(decode_type_t::SANYO_AC152));
}
TEST(TestDecodeSanyoAc, DecodeRealExamples) {
@@ -820,3 +828,70 @@ TEST(TestSanyoAc88Class, Clock) {
ac.setClock(25 * 60 + 61);
EXPECT_EQ(23 * 60 + 59, ac.getClock());
}
TEST(TestDecodeSanyoAc152, DecodeRealExamples) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
// Ref: "16c" from https://github.com/crankyoldgit/IRremoteESP8266/issues/1826#issuecomment-1160708653
const uint16_t rawData[307] = {
3294, 1726, 420, 330, 458, 462, 382, 452, 438, 330, 456, 458, 384, 454,
384, 1312, 422, 324, 512, 336, 454, 458, 384, 450, 438, 358, 436, 464,
424, 326, 458, 476, 372, 458, 430, 328, 458, 464, 382, 1308, 424, 326,
510, 1264, 424, 268, 520, 460, 380, 460, 436, 324, 462, 400, 436, 474,
372, 456, 430, 342, 452, 450, 388, 446, 442, 1262, 422, 266, 520, 1314,
372, 1306, 424, 1258, 370, 390, 448, 1314, 372, 1310, 426, 308, 522, 338,
454, 470, 370, 454, 438, 330, 456, 468, 370, 456, 384, 464, 384, 1306,
422, 328, 460, 472, 374, 448, 442, 1258, 426, 1256, 426, 268, 520, 464,
382, 460, 430, 328, 508, 1264, 426, 262, 572, 1262, 424, 228, 604, 1262,
372, 1312, 372, 1310, 426, 1256, 422, 1258, 424, 262, 524, 418, 428, 456,
382, 1308, 372, 456, 386, 456, 382, 464, 378, 1308, 424, 360, 436, 454,
430, 344, 450, 1306, 372, 1310, 424, 326, 510, 338, 452, 456, 384, 456,
436, 328, 510, 1258, 372, 1310, 422, 338, 454, 466, 424, 328, 460, 1310,
372, 1312, 424, 1258, 450, 262, 496, 1310, 372, 1310, 426, 1260, 424, 260,
526, 442, 442, 1264, 426, 268, 520, 458, 380, 450, 386, 462, 436, 320,
518, 1256, 372, 394, 446, 398, 494, 334, 506, 326, 510, 276, 518, 460,
430, 332, 508, 326, 510, 356, 440, 448, 444, 264, 572, 336, 456, 408, 434,
454, 438, 332, 506, 336, 454, 460, 384, 448, 444, 326, 510, 332, 456, 442,
400, 456, 384, 456, 386, 452, 388, 454, 440, 326, 512, 272, 518, 450, 440,
334, 454, 458, 440, 320, 516, 268, 570, 340, 452, 468, 424, 260, 574, 336,
456, 394, 444, 458, 438, 328, 508, 1258, 370, 1312, 372, 1312, 424, 314,
468, 1312, 450, 1232, 370, 1314, 420, 324, 514}; // UNKNOWN 584FBE80
const uint8_t expectedState[kSanyoAc152StateLength] = {
0x40, 0x00, 0x14, 0x80, 0x6E, 0x80, 0x18, 0xEA, 0x23, 0x62,
0x30, 0xEE, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77};
irsend.begin();
irsend.reset();
irsend.sendRaw(rawData, 307, 38000);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
ASSERT_EQ(SANYO_AC152, irsend.capture.decode_type);
EXPECT_EQ(kSanyoAc152Bits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
EXPECT_FALSE(irsend.capture.repeat);
EXPECT_EQ(
"",
IRAcUtils::resultAcToString(&irsend.capture));
}
TEST(TestDecodeSanyoAc152, SyntheticSelfDecode) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
const uint8_t expectedState[kSanyoAc152StateLength] = {
0x40, 0x00, 0x14, 0x80, 0x6E, 0x80, 0x18, 0xEA, 0x23, 0x62,
0x30, 0xEE, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77};
irsend.begin();
irsend.reset();
irsend.sendSanyoAc152(expectedState);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(SANYO_AC152, irsend.capture.decode_type);
EXPECT_EQ(kSanyoAc152Bits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
EXPECT_FALSE(irsend.capture.repeat);
EXPECT_EQ(
"",
IRAcUtils::resultAcToString(&irsend.capture));
}