Skip to content
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
4 changes: 4 additions & 0 deletions src/IRrecv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1102,6 +1102,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
DPRINTLN("Attempting Coolix 48-bit decode");
if (decodeCoolix48(results, offset)) return true;
#endif // DECODE_COOLIX48
#if DECODE_DAIKIN200
DPRINTLN("Attempting Daikin 200-bit decode");
if (decodeDaikin200(results, offset)) return true;
#endif // DECODE_DAIKIN200
// Typically new protocols are added above this line.
}
#if DECODE_HASH
Expand Down
5 changes: 5 additions & 0 deletions src/IRrecv.h
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,11 @@ class IRrecv {
const uint16_t nbits = kDaikin2Bits,
const bool strict = true);
#endif
#if DECODE_DAIKIN200
bool decodeDaikin200(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kDaikin200Bits,
const bool strict = true);
#endif // DECODE_DAIKIN200
#if DECODE_DAIKIN216
bool decodeDaikin216(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kDaikin216Bits,
Expand Down
14 changes: 13 additions & 1 deletion src/IRremoteESP8266.h
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,13 @@
#define SEND_KELON168 _IR_ENABLE_DEFAULT_
#endif // SEND_KELON168

#ifndef DECODE_DAIKIN200
#define DECODE_DAIKIN200 _IR_ENABLE_DEFAULT_
#endif // DECODE_DAIKIN200
#ifndef SEND_DAIKIN200
#define SEND_DAIKIN200 _IR_ENABLE_DEFAULT_
#endif // SEND_DAIKIN200

#if (DECODE_ARGO || DECODE_DAIKIN || DECODE_FUJITSU_AC || DECODE_GREE || \
DECODE_KELVINATOR || DECODE_MITSUBISHI_AC || DECODE_TOSHIBA_AC || \
DECODE_TROTEC || DECODE_HAIER_AC || DECODE_HITACHI_AC || \
Expand All @@ -877,6 +884,7 @@
DECODE_TEKNOPOINT || DECODE_KELON || DECODE_TROTEC_3550 || \
DECODE_SANYO_AC88 || DECODE_RHOSS || DECODE_HITACHI_AC264 || \
DECODE_KELON168 || DECODE_HITACHI_AC296 || \
DECODE_DAIKIN200 || \
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
Expand Down Expand Up @@ -1030,8 +1038,9 @@ enum decode_type_t {
HITACHI_AC264,
KELON168,
HITACHI_AC296,
DAIKIN200,
// Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = HITACHI_AC296,
kLastDecodeType = DAIKIN200,
};

// Message lengths & required repeat values
Expand Down Expand Up @@ -1087,6 +1096,9 @@ const uint16_t kDaikin152DefaultRepeat = kNoRepeat;
const uint16_t kDaikin176StateLength = 22;
const uint16_t kDaikin176Bits = kDaikin176StateLength * 8;
const uint16_t kDaikin176DefaultRepeat = kNoRepeat;
const uint16_t kDaikin200StateLength = 25;
const uint16_t kDaikin200Bits = kDaikin200StateLength * 8;
const uint16_t kDaikin200DefaultRepeat = kNoRepeat;
const uint16_t kDaikin216StateLength = 27;
const uint16_t kDaikin216Bits = kDaikin216StateLength * 8;
const uint16_t kDaikin216DefaultRepeat = kNoRepeat;
Expand Down
7 changes: 7 additions & 0 deletions src/IRsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
return kDaikin176Bits;
case DAIKIN2:
return kDaikin2Bits;
case DAIKIN200:
return kDaikin200Bits;
case DAIKIN216:
return kDaikin216Bits;
case DAIKIN64:
Expand Down Expand Up @@ -1161,6 +1163,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state,
sendDaikin2(state, nbytes);
break;
#endif // SEND_DAIKIN2
#if SEND_DAIKIN200
case DAIKIN200:
sendDaikin200(state, nbytes);
break;
#endif // SEND_DAIKIN200
#if SEND_DAIKIN216
case DAIKIN216:
sendDaikin216(state, nbytes);
Expand Down
5 changes: 5 additions & 0 deletions src/IRsend.h
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,11 @@ class IRsend {
const uint16_t nbytes = kDaikin2StateLength,
const uint16_t repeat = kDaikin2DefaultRepeat);
#endif
#if SEND_DAIKIN200
void sendDaikin200(const unsigned char data[],
const uint16_t nbytes = kDaikin200StateLength,
const uint16_t repeat = kDaikin200DefaultRepeat);
#endif // SEND_DAIKIN200
#if SEND_DAIKIN216
void sendDaikin216(const unsigned char data[],
const uint16_t nbytes = kDaikin216StateLength,
Expand Down
1 change: 1 addition & 0 deletions src/IRtext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ IRTEXT_CONST_BLOB_DECL(kAllProtocolNamesStr) {
D_STR_HITACHI_AC264 "\x0"
D_STR_KELON168 "\x0"
D_STR_HITACHI_AC296 "\x0"
D_STR_DAIKIN200 "\x0"
///< New protocol strings should be added just above this line.
"\x0" ///< This string requires double null termination.
};
Expand Down
1 change: 1 addition & 0 deletions src/IRutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ bool hasACState(const decode_type_t protocol) {
case DAIKIN160:
case DAIKIN176:
case DAIKIN2:
case DAIKIN200:
case DAIKIN216:
case ELECTRA_AC:
case FUJITSU_AC:
Expand Down
88 changes: 87 additions & 1 deletion src/ir_Daikin.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2016 sillyfrog
// Copyright 2017 sillyfrog, crankyoldgit
// Copyright 2018-2021 crankyoldgit
// Copyright 2018-2022 crankyoldgit
// Copyright 2019 pasna (IRDaikin160 class / Daikin176 class)

/// @file
Expand All @@ -21,6 +21,7 @@
/// @see Daikin216 https://github.com/crankyoldgit/IRremoteESP8266/issues/689
/// @see Daikin216 https://github.com/danny-source/Arduino_DY_IRDaikin
/// @see Daikin64 https://github.com/crankyoldgit/IRremoteESP8266/issues/1064
/// @see Daikin200 https://github.com/crankyoldgit/IRremoteESP8266/issues/1802

#include "ir_Daikin.h"
#include <algorithm>
Expand Down Expand Up @@ -3733,3 +3734,88 @@ stdAc::state_t IRDaikin64::toCommon(const stdAc::state_t *prev) const {
result.light = false;
return result;
}

#if SEND_DAIKIN200
/// Send a Daikin200 (200-bit) A/C formatted message.
/// Status: BETA / Untested on a real device.
/// @param[in] data The message to be sent.
/// @param[in] nbytes The number of bytes of message to be sent.
/// @param[in] repeat The number of times the command is to be repeated.
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1802
void IRsend::sendDaikin200(const unsigned char data[], const uint16_t nbytes,
const uint16_t repeat) {
if (nbytes < kDaikin200Section1Length)
return; // Not enough bytes to send a partial message.

for (uint16_t r = 0; r <= repeat; r++) {
// Section #1
sendGeneric(kDaikin200HdrMark, kDaikin200HdrSpace, kDaikin200BitMark,
kDaikin200OneSpace, kDaikin200BitMark, kDaikin200ZeroSpace,
kDaikin200BitMark, kDaikin200Gap, data,
kDaikin200Section1Length,
kDaikin200Freq, false, 0, kDutyDefault);
// Section #2
sendGeneric(kDaikin200HdrMark, kDaikin200HdrSpace, kDaikin200BitMark,
kDaikin200OneSpace, kDaikin200BitMark, kDaikin200ZeroSpace,
kDaikin200BitMark, kDaikin200Gap,
data + kDaikin200Section1Length,
nbytes - kDaikin200Section1Length,
kDaikin200Freq, false, 0, kDutyDefault);
}
}
#endif // SEND_DAIKIN200

#if DECODE_DAIKIN200
/// Decode the supplied Daikin 200-bit message. (DAIKIN200)
/// Status: STABLE / Known to be working.
/// @param[in,out] results Ptr to the data to decode & where to store the decode
/// result.
/// @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/1802
bool IRrecv::decodeDaikin200(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
if (results->rawlen < 2 * (nbits + kHeader + kFooter) - 1 + offset)
return false;

// Compliance
if (strict && nbits != kDaikin200Bits) return false;

const uint8_t ksectionSize[kDaikin200Sections] = {kDaikin200Section1Length,
kDaikin200Section2Length};
// Sections
uint16_t pos = 0;
for (uint8_t section = 0; section < kDaikin200Sections; section++) {
uint16_t used;
// Section Header + Section Data + Section Footer
used = matchGeneric(results->rawbuf + offset, results->state + pos,
results->rawlen - offset, ksectionSize[section] * 8,
kDaikin200HdrMark, kDaikin200HdrSpace,
kDaikin200BitMark, kDaikin200OneSpace,
kDaikin200BitMark, kDaikin200ZeroSpace,
kDaikin200BitMark, kDaikin200Gap,
section >= kDaikin200Sections - 1,
kDaikinTolerance, 0, false);
if (used == 0) return false;
offset += used;
pos += ksectionSize[section];
}
// Compliance
if (strict) {
if (pos * 8 != kDaikin200Bits) return false;
// Validate the checksum.
if (!IRDaikin176::validChecksum(results->state, pos)) return false;
}

// Success
results->decode_type = decode_type_t::DAIKIN200;
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_DAIKIN200
14 changes: 14 additions & 0 deletions src/ir_Daikin.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
/// @see Daikin216 https://github.com/crankyoldgit/IRremoteESP8266/issues/689
/// @see Daikin216 https://github.com/danny-source/Arduino_DY_IRDaikin
/// @see Daikin64 https://github.com/crankyoldgit/IRremoteESP8266/issues/1064
/// @see Daikin200 https://github.com/crankyoldgit/IRremoteESP8266/issues/1802

// Supports:
// Brand: Daikin, Model: ARC433** remote (DAIKIN)
Expand All @@ -47,6 +48,7 @@
// Brand: Daikin, Model: FTWX35AXV1 A/C (DAIKIN64)
// Brand: Daikin, Model: ARC484A4 remote (DAIKIN216)
// Brand: Daikin, Model: FTQ60TV16U2 A/C (DAIKIN216)
// Brand: Daikin, Model: BRC4M150W16 remote (DAIKIN200)

#ifndef IR_DAIKIN_H_
#define IR_DAIKIN_H_
Expand Down Expand Up @@ -676,6 +678,18 @@ const uint8_t kDaikin64MaxTemp = 30; // Celsius
const uint8_t kDaikin64ChecksumOffset = 60;
const uint8_t kDaikin64ChecksumSize = 4; // Mask 0b1111 << 59

const uint16_t kDaikin200Freq = 38000; // Modulation Frequency in Hz.
const uint16_t kDaikin200HdrMark = 4920;
const uint16_t kDaikin200HdrSpace = 2230;
const uint16_t kDaikin200BitMark = 290;
const uint16_t kDaikin200OneSpace = 1850;
const uint16_t kDaikin200ZeroSpace = 780;
const uint16_t kDaikin200Gap = 29400;
const uint16_t kDaikin200Sections = 2;
const uint16_t kDaikin200Section1Length = 7;
const uint16_t kDaikin200Section2Length = kDaikin200StateLength -
kDaikin200Section1Length;

// Legacy defines.
#define DAIKIN_COOL kDaikinCool
#define DAIKIN_HEAT kDaikinHeat
Expand Down
17 changes: 10 additions & 7 deletions src/locale/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -731,25 +731,28 @@ D_STR_INDIRECT " " D_STR_MODE
#define D_STR_DAIKIN "DAIKIN"
#endif // D_STR_DAIKIN
#ifndef D_STR_DAIKIN128
#define D_STR_DAIKIN128 "DAIKIN128"
#define D_STR_DAIKIN128 D_STR_DAIKIN "128"
#endif // D_STR_DAIKIN128
#ifndef D_STR_DAIKIN152
#define D_STR_DAIKIN152 "DAIKIN152"
#define D_STR_DAIKIN152 D_STR_DAIKIN "152"
#endif // D_STR_DAIKIN152
#ifndef D_STR_DAIKIN160
#define D_STR_DAIKIN160 "DAIKIN160"
#define D_STR_DAIKIN160 D_STR_DAIKIN "160"
#endif // D_STR_DAIKIN160
#ifndef D_STR_DAIKIN176
#define D_STR_DAIKIN176 "DAIKIN176"
#define D_STR_DAIKIN176 D_STR_DAIKIN "176"
#endif // D_STR_DAIKIN176
#ifndef D_STR_DAIKIN2
#define D_STR_DAIKIN2 "DAIKIN2"
#define D_STR_DAIKIN2 D_STR_DAIKIN "2"
#endif // D_STR_DAIKIN2
#ifndef D_STR_DAIKIN200
#define D_STR_DAIKIN200 D_STR_DAIKIN "200"
#endif // D_STR_DAIKIN200
#ifndef D_STR_DAIKIN216
#define D_STR_DAIKIN216 "DAIKIN216"
#define D_STR_DAIKIN216 D_STR_DAIKIN "216"
#endif // D_STR_DAIKIN216
#ifndef D_STR_DAIKIN64
#define D_STR_DAIKIN64 "DAIKIN64"
#define D_STR_DAIKIN64 D_STR_DAIKIN "64"
#endif // D_STR_DAIKIN64
#ifndef D_STR_DELONGHI_AC
#define D_STR_DELONGHI_AC "DELONGHI_AC"
Expand Down
87 changes: 87 additions & 0 deletions test/ir_Daikin_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1552,6 +1552,13 @@ TEST(TestUtils, Housekeeping) {
ASSERT_EQ(decode_type_t::DAIKIN64, strToDecodeType("DAIKIN64"));
ASSERT_FALSE(hasACState(decode_type_t::DAIKIN64));
ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::DAIKIN64));

ASSERT_EQ("DAIKIN200", typeToString(decode_type_t::DAIKIN200));
ASSERT_EQ(decode_type_t::DAIKIN200, strToDecodeType("DAIKIN200"));
ASSERT_TRUE(hasACState(decode_type_t::DAIKIN200));
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::DAIKIN200));
ASSERT_EQ(kDaikin200Bits, IRsend::defaultBits(decode_type_t::DAIKIN200));
ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::DAIKIN200));
}

// https://github.com/crankyoldgit/IRremoteESP8266/issues/582#issuecomment-453863879
Expand Down Expand Up @@ -3919,3 +3926,83 @@ TEST(TestDaikin128Class, Issue1754_HeatMode) {
// Compare the synthetic state to the captured one.
EXPECT_STATE_EQ(heatmode, ac.getRaw(), kDaikin128Bits);
}

// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1802
TEST(TestDecodeDaikin200, RealExample) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
const uint16_t rawData[407] = {
4852, 2298,
202, 1942, 202, 870, 200, 870, 202, 868, 202, 1942, 202, 870, 202, 870,
202, 870, 202, 870, 202, 1942, 202, 870, 202, 1942, 202, 1942, 202, 868,
202, 1942, 202, 1942, 202, 1912, 232, 1942, 202, 1942, 202, 868, 202,
1942, 202, 870, 202, 870, 202, 868, 202, 868, 204, 868, 202, 870, 202,
1942, 202, 868, 204, 868, 202, 1942, 202, 870, 202, 870, 200, 870, 202,
1942, 202, 868, 202, 870, 202, 870, 202, 870, 202, 870, 202, 870, 202,
870, 202, 870, 202, 868, 202, 868, 204, 868, 202, 870, 202, 870, 202, 870,
202, 1942, 202, 1942, 202, 1942, 202, 868, 202, 868, 204, 1942, 202, 870,
202, 29468,
4880, 2266,
256, 1888, 230, 844, 202, 868, 202, 870, 256, 1888, 230, 842, 228, 842,
230, 842, 256, 814, 232, 1914, 254, 816, 230, 1916, 256, 1888, 256, 814,
256, 1890, 254, 1888, 256, 1888, 256, 1888, 256, 1888, 256, 816, 230,
1912, 258, 814, 256, 816, 256, 816, 282, 790, 280, 790, 282, 790, 282,
1862, 258, 814, 280, 790, 282, 1862, 280, 792, 280, 790, 282, 788, 282,
790, 282, 790, 282, 790, 282, 790, 282, 788, 282, 790, 282, 1862, 282,
1862, 282, 790, 282, 788, 282, 1862, 282, 1864, 280, 1862, 282, 790, 280,
790, 282, 790, 282, 790, 282, 788, 284, 790, 282, 760, 310, 790, 282, 788,
282, 1862, 282, 788, 282, 790, 282, 788, 282, 788, 282, 1862, 284, 788,
282, 788, 284, 788, 282, 790, 282, 788, 284, 788, 282, 790, 282, 788, 284,
758, 312, 788, 284, 788, 282, 788, 284, 788, 282, 788, 284, 788, 282, 788,
284, 788, 284, 758, 314, 786, 284, 788, 284, 1860, 282, 790, 282, 790,
282, 1862, 282, 758, 312, 762, 310, 788, 284, 788, 282, 758, 314, 758,
314, 1862, 282, 760, 312, 1860, 284, 760, 310, 788, 282, 760, 312, 788,
284, 760, 312, 788, 282, 790, 282, 788, 284, 788, 282, 790, 282, 788, 282,
758, 314, 788, 282, 758, 314, 1862, 282, 758, 312, 788, 284, 758, 312,
758, 314, 788, 282, 758, 314, 758, 312, 788, 284, 788, 284, 758, 312, 760,
312, 762, 310, 790, 284, 788, 282, 758, 314, 758, 312, 788, 282, 760, 312,
760, 312, 760, 312, 788, 282, 758, 314, 788, 284, 788, 284, 758, 312, 788,
282, 790, 282, 1832, 310, 758, 316, 788, 284, 1862, 282, 1862, 282, 1832,
310, 788, 284}; // UNKNOWN 3BFB2888

const uint8_t expectedState[kDaikin200StateLength] = {
0x11, 0xDA, 0x17, 0x48, 0x04, 0x00, 0x4E, // Section 1
0x11, 0xDA, 0x17, 0x48, 0x00, 0x73, 0x00, 0x21, 0x00, // Section 2
0x00, 0x24, 0x50, 0x00, 0x20, 0x00, 0x00, 0x00, 0x72};
irsend.begin();
irsend.reset();
irsend.sendRaw(rawData, 407, kDaikin64Freq);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
ASSERT_EQ(decode_type_t::DAIKIN200, irsend.capture.decode_type);
ASSERT_EQ(kDaikin200Bits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
EXPECT_EQ(
"",
IRAcUtils::resultAcToString(&irsend.capture));
stdAc::state_t result, prev;
ASSERT_FALSE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev));
}

// Decoding a message we entirely constructed based solely on a given state.
TEST(TestDecodeDaikin200, SyntheticExample) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();

const uint8_t expectedState[kDaikin200StateLength] = {
0x11, 0xDA, 0x17, 0x48, 0x04, 0x00, 0x4E, // Section 1
0x11, 0xDA, 0x17, 0x48, 0x00, 0x73, 0x00, 0x21, 0x00, // Section 2
0x00, 0x24, 0x50, 0x00, 0x20, 0x00, 0x00, 0x00, 0x72};

irsend.reset();
irsend.sendDaikin200(expectedState);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
ASSERT_EQ(DAIKIN200, irsend.capture.decode_type);
ASSERT_EQ(kDaikin200Bits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
EXPECT_EQ(
"",
IRAcUtils::resultAcToString(&irsend.capture));
}